summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormsweet <msweet@a1ca3aef-8c08-0410-bb20-df032aa958be>2013-05-10 18:56:23 +0000
committermsweet <msweet@a1ca3aef-8c08-0410-bb20-df032aa958be>2013-05-10 18:56:23 +0000
commit22171cb27d62ec2b6f9b0f99518f003fe9d328b6 (patch)
tree0b2ce20510254e96967994ad9f1c25bdc17deba9
downloadcups-22171cb27d62ec2b6f9b0f99518f003fe9d328b6.tar.gz
Import cups.org releasesrelease-1.1.13
git-svn-id: svn+ssh://src.apple.com/svn/cups/cups.org/tags/release-1.1.13@4306 a1ca3aef-8c08-0410-bb20-df032aa958be
-rw-r--r--.cvsignore9
-rw-r--r--CHANGES.txt2014
-rw-r--r--CREDITS.txt26
-rw-r--r--ENCRYPTION.txt138
-rw-r--r--INSTALL.txt170
-rw-r--r--LICENSE.html895
-rw-r--r--LICENSE.txt812
-rw-r--r--Makedefs.in179
-rw-r--r--Makefile148
-rw-r--r--README.txt283
-rw-r--r--backend/.cvsignore7
-rw-r--r--backend/Makefile141
-rw-r--r--backend/betest.c85
-rw-r--r--backend/ipp.c793
-rw-r--r--backend/lpd.c765
-rw-r--r--backend/parallel.c643
-rw-r--r--backend/serial.c867
-rw-r--r--backend/socket.c347
-rw-r--r--backend/usb.c454
-rw-r--r--berkeley/.cvsignore4
-rw-r--r--berkeley/Makefile105
-rw-r--r--berkeley/lpc.c481
-rw-r--r--berkeley/lpq.c542
-rw-r--r--berkeley/lpr.c425
-rw-r--r--berkeley/lprm.c267
-rw-r--r--cgi-bin/.cvsignore5
-rw-r--r--cgi-bin/Makefile121
-rw-r--r--cgi-bin/admin.c1599
-rw-r--r--cgi-bin/cgi.h96
-rw-r--r--cgi-bin/classes.c360
-rw-r--r--cgi-bin/html.c89
-rw-r--r--cgi-bin/ipp-var.c299
-rw-r--r--cgi-bin/ipp-var.h55
-rw-r--r--cgi-bin/jobs.c139
-rw-r--r--cgi-bin/printers.c360
-rw-r--r--cgi-bin/template.c501
-rw-r--r--cgi-bin/var.c672
-rw-r--r--conf/Makefile72
-rw-r--r--conf/classes.conf89
-rw-r--r--conf/client.conf65
-rw-r--r--conf/cupsd.conf.in720
-rw-r--r--conf/mime.convs87
-rw-r--r--conf/mime.types156
-rw-r--r--conf/printcap2
-rw-r--r--conf/printers.conf96
-rw-r--r--config-scripts/cups-common.m4155
-rw-r--r--config-scripts/cups-compiler.m4187
-rw-r--r--config-scripts/cups-directories.m4238
-rw-r--r--config-scripts/cups-image.m472
-rw-r--r--config-scripts/cups-libtool.m449
-rw-r--r--config-scripts/cups-manpages.m4104
-rw-r--r--config-scripts/cups-network.m438
-rw-r--r--config-scripts/cups-openslp.m447
-rw-r--r--config-scripts/cups-openssl.m469
-rw-r--r--config-scripts/cups-opsys.m490
-rw-r--r--config-scripts/cups-pam.m459
-rw-r--r--config-scripts/cups-sharedlibs.m4150
-rw-r--r--config.h.in214
-rw-r--r--configure.in48
-rwxr-xr-xcups-config.in133
-rw-r--r--cups.dsw29
-rw-r--r--cups.list.in400
-rw-r--r--cups.plist11
-rwxr-xr-xcups.sh.in180
-rw-r--r--cups.spec228
-rw-r--r--cups.strings9
-rw-r--r--cups/.cvsignore4
-rw-r--r--cups/Makefile208
-rw-r--r--cups/cups.dsp188
-rw-r--r--cups/cups.h175
-rw-r--r--cups/cups_C.h133
-rw-r--r--cups/debug.h57
-rw-r--r--cups/dest.c789
-rw-r--r--cups/emit.c425
-rw-r--r--cups/encode.c311
-rw-r--r--cups/http.c2215
-rw-r--r--cups/http.h345
-rw-r--r--cups/ipp.c2028
-rw-r--r--cups/ipp.h432
-rw-r--r--cups/language.c430
-rw-r--r--cups/language.h224
-rw-r--r--cups/mark.c441
-rw-r--r--cups/md5.c392
-rw-r--r--cups/md5.h94
-rw-r--r--cups/md5passwd.c148
-rw-r--r--cups/options.c430
-rw-r--r--cups/page.c189
-rw-r--r--cups/ppd.c2006
-rw-r--r--cups/ppd.h268
-rw-r--r--cups/snprintf.c287
-rw-r--r--cups/string.c125
-rw-r--r--cups/string.h103
-rw-r--r--cups/tempfile.c200
-rw-r--r--cups/testhttp.c124
-rw-r--r--cups/testmime.dsp102
-rw-r--r--cups/testppd.c195
-rw-r--r--cups/testppd.dsp102
-rw-r--r--cups/usersys.c447
-rw-r--r--cups/util.c1741
-rw-r--r--data/HPGLprolog37
-rw-r--r--data/Makefile112
-rw-r--r--data/classified277
-rw-r--r--data/confidential277
-rw-r--r--data/cups.irix3
-rw-r--r--data/cups.pam2
-rw-r--r--data/cups.suse2
-rw-r--r--data/iso-8859-1251
-rw-r--r--data/iso-8859-10251
-rw-r--r--data/iso-8859-13251
-rw-r--r--data/iso-8859-14251
-rw-r--r--data/iso-8859-15251
-rw-r--r--data/iso-8859-2253
-rw-r--r--data/iso-8859-3244
-rw-r--r--data/iso-8859-4251
-rw-r--r--data/iso-8859-5251
-rw-r--r--data/iso-8859-6206
-rw-r--r--data/iso-8859-7246
-rw-r--r--data/iso-8859-8214
-rw-r--r--data/iso-8859-9251
-rw-r--r--data/koi8-r261
-rw-r--r--data/koi8-u259
-rw-r--r--data/psglyphs1051
-rw-r--r--data/secret277
-rw-r--r--data/standard261
-rw-r--r--data/testprint.ps522
-rw-r--r--data/topsecret277
-rw-r--r--data/unclassified277
-rw-r--r--data/utf-839
-rw-r--r--data/windows-1250254
-rw-r--r--data/windows-1251258
-rw-r--r--data/windows-1252254
-rw-r--r--data/windows-1253243
-rw-r--r--data/windows-1254252
-rw-r--r--data/windows-1255236
-rw-r--r--data/windows-1256259
-rw-r--r--data/windows-1257247
-rw-r--r--data/windows-1258250
-rw-r--r--data/windows-874228
-rw-r--r--doc/Makefile236
-rw-r--r--doc/cmp.html677
-rw-r--r--doc/cmp.pdfbin0 -> 55052 bytes
-rw-r--r--doc/cmp.shtml595
-rw-r--r--doc/cups.css4
-rw-r--r--doc/cupsdoc.css9
-rw-r--r--doc/documentation.html81
-rw-r--r--doc/figures.scbin0 -> 75144 bytes
-rw-r--r--doc/glossary.shtml73
-rw-r--r--doc/idd.html1083
-rw-r--r--doc/idd.pdfbin0 -> 66961 bytes
-rw-r--r--doc/idd.shtml1431
-rw-r--r--doc/images/accept-jobs.gifbin0 -> 259 bytes
-rw-r--r--doc/images/add-class.gifbin0 -> 242 bytes
-rw-r--r--doc/images/add-printer.gifbin0 -> 252 bytes
-rw-r--r--doc/images/cancel-job.gifbin0 -> 248 bytes
-rw-r--r--doc/images/cancel-jobs.gifbin0 -> 255 bytes
-rw-r--r--doc/images/cancel.gifbin0 -> 210 bytes
-rw-r--r--doc/images/classes.gifbin0 -> 591 bytes
-rw-r--r--doc/images/config-printer.gifbin0 -> 296 bytes
-rw-r--r--doc/images/continue.gifbin0 -> 224 bytes
-rw-r--r--doc/images/cups-block-diagram.gifbin0 -> 11637 bytes
-rw-r--r--doc/images/cups-large.gifbin0 -> 7457 bytes
-rw-r--r--doc/images/cups-medium.gifbin0 -> 3163 bytes
-rw-r--r--doc/images/cups-small.gifbin0 -> 1266 bytes
-rw-r--r--doc/images/delete-class.gifbin0 -> 259 bytes
-rw-r--r--doc/images/delete-printer.gifbin0 -> 267 bytes
-rw-r--r--doc/images/draft.gifbin0 -> 926 bytes
-rw-r--r--doc/images/hold-job.gifbin0 -> 228 bytes
-rw-r--r--doc/images/left.gifbin0 -> 110 bytes
-rw-r--r--doc/images/logo.gifbin0 -> 1958 bytes
-rw-r--r--doc/images/manage-classes.gifbin0 -> 289 bytes
-rw-r--r--doc/images/manage-jobs.gifbin0 -> 266 bytes
-rw-r--r--doc/images/manage-printers.gifbin0 -> 296 bytes
-rw-r--r--doc/images/modify-class.gifbin0 -> 267 bytes
-rw-r--r--doc/images/modify-printer.gifbin0 -> 277 bytes
-rw-r--r--doc/images/navbar.gifbin0 -> 2869 bytes
-rw-r--r--doc/images/navbar.xcf.gzbin0 -> 4253 bytes
-rw-r--r--doc/images/print-test-page.gifbin0 -> 288 bytes
-rw-r--r--doc/images/printer-idle.gifbin0 -> 706 bytes
-rw-r--r--doc/images/printer-processing.gifbin0 -> 805 bytes
-rw-r--r--doc/images/printer-stopped.gifbin0 -> 794 bytes
-rw-r--r--doc/images/reject-jobs.gifbin0 -> 252 bytes
-rw-r--r--doc/images/release-job.gifbin0 -> 255 bytes
-rw-r--r--doc/images/restart-job.gifbin0 -> 249 bytes
-rw-r--r--doc/images/right.gifbin0 -> 145 bytes
-rw-r--r--doc/images/show-active.gifbin0 -> 303 bytes
-rw-r--r--doc/images/show-completed.gifbin0 -> 337 bytes
-rw-r--r--doc/images/start-class.gifbin0 -> 238 bytes
-rw-r--r--doc/images/start-printer.gifbin0 -> 255 bytes
-rw-r--r--doc/images/stop-class.gifbin0 -> 245 bytes
-rw-r--r--doc/images/stop-printer.gifbin0 -> 252 bytes
-rw-r--r--doc/index.html36
-rw-r--r--doc/ipp.html1442
-rw-r--r--doc/ipp.pdfbin0 -> 103168 bytes
-rw-r--r--doc/ipp.shtml1938
-rw-r--r--doc/overview.html500
-rw-r--r--doc/overview.pdfbin0 -> 37870 bytes
-rw-r--r--doc/printing-overview.shtml125
-rw-r--r--doc/references.shtml42
-rw-r--r--doc/sam.html4887
-rw-r--r--doc/sam.pdfbin0 -> 261903 bytes
-rw-r--r--doc/sam.shtml4611
-rw-r--r--doc/sdd.html591
-rw-r--r--doc/sdd.pdfbin0 -> 73046 bytes
-rw-r--r--doc/sdd.shtml564
-rw-r--r--doc/spm.html7639
-rw-r--r--doc/spm.pdfbin0 -> 595185 bytes
-rw-r--r--doc/spm.shtml8667
-rw-r--r--doc/sps.html297
-rw-r--r--doc/sps.pdfbin0 -> 32999 bytes
-rw-r--r--doc/sps.shtml457
-rw-r--r--doc/ssr.html269
-rw-r--r--doc/ssr.pdfbin0 -> 31773 bytes
-rw-r--r--doc/ssr.shtml167
-rw-r--r--doc/stp.html262
-rw-r--r--doc/stp.pdfbin0 -> 35025 bytes
-rw-r--r--doc/stp.shtml144
-rw-r--r--doc/sum.html1643
-rw-r--r--doc/sum.pdfbin0 -> 104938 bytes
-rw-r--r--doc/sum.shtml887
-rw-r--r--doc/svd.html296
-rw-r--r--doc/svd.pdfbin0 -> 37735 bytes
-rw-r--r--doc/svd.shtml212
-rw-r--r--doc/system-overview.shtml19
-rw-r--r--filter/.cvsignore13
-rw-r--r--filter/Makefile246
-rw-r--r--filter/common.c400
-rw-r--r--filter/common.h71
-rw-r--r--filter/form-main.c60
-rw-r--r--filter/form-ps.c47
-rw-r--r--filter/form-tree.c622
-rw-r--r--filter/form.h175
-rw-r--r--filter/hpgl-attr.c452
-rw-r--r--filter/hpgl-char.c500
-rw-r--r--filter/hpgl-config.c641
-rw-r--r--filter/hpgl-input.c232
-rw-r--r--filter/hpgl-main.c265
-rw-r--r--filter/hpgl-polygon.c380
-rw-r--r--filter/hpgl-prolog.c407
-rw-r--r--filter/hpgl-vector.c731
-rw-r--r--filter/hpgltops.h233
-rw-r--r--filter/image-bmp.c510
-rw-r--r--filter/image-colorspace.c926
-rw-r--r--filter/image-gif.c644
-rw-r--r--filter/image-jpeg.c194
-rw-r--r--filter/image-photocd.c323
-rw-r--r--filter/image-pix.c223
-rw-r--r--filter/image-png.c250
-rw-r--r--filter/image-pnm.c288
-rw-r--r--filter/image-sgi.c267
-rw-r--r--filter/image-sgi.h94
-rw-r--r--filter/image-sgilib.c857
-rw-r--r--filter/image-sun.c377
-rw-r--r--filter/image-tiff.c1707
-rw-r--r--filter/image-zoom.c310
-rw-r--r--filter/image.c773
-rw-r--r--filter/image.h231
-rw-r--r--filter/imagetops.c870
-rw-r--r--filter/imagetoraster.c4452
-rw-r--r--filter/pstops.c1147
-rw-r--r--filter/raster.c252
-rw-r--r--filter/raster.h233
-rw-r--r--filter/rastertodymo.c361
-rw-r--r--filter/rastertoepson.c1131
-rw-r--r--filter/rastertohp.c806
-rw-r--r--filter/textcommon.c1155
-rw-r--r--filter/textcommon.h102
-rw-r--r--filter/texttops.c1316
-rw-r--r--fonts/AvantGarde-Bookbin0 -> 34871 bytes
-rw-r--r--fonts/AvantGarde-BookObliquebin0 -> 35156 bytes
-rw-r--r--fonts/AvantGarde-Demibin0 -> 36354 bytes
-rw-r--r--fonts/AvantGarde-DemiObliquebin0 -> 36128 bytes
-rw-r--r--fonts/Bookman-Demibin0 -> 44768 bytes
-rw-r--r--fonts/Bookman-DemiItalicbin0 -> 44950 bytes
-rw-r--r--fonts/Bookman-Lightbin0 -> 44934 bytes
-rw-r--r--fonts/Bookman-LightItalicbin0 -> 44162 bytes
-rw-r--r--fonts/Charter-Boldbin0 -> 33799 bytes
-rw-r--r--fonts/Charter-BoldItalicbin0 -> 35229 bytes
-rw-r--r--fonts/Charter-Italicbin0 -> 35118 bytes
-rw-r--r--fonts/Charter-Romanbin0 -> 34869 bytes
-rw-r--r--fonts/Courierbin0 -> 45758 bytes
-rw-r--r--fonts/Courier-Boldbin0 -> 50493 bytes
-rw-r--r--fonts/Courier-BoldObliquebin0 -> 51527 bytes
-rw-r--r--fonts/Courier-Obliquebin0 -> 44404 bytes
-rw-r--r--fonts/Helveticabin0 -> 36026 bytes
-rw-r--r--fonts/Helvetica-Boldbin0 -> 35941 bytes
-rw-r--r--fonts/Helvetica-BoldObliquebin0 -> 39013 bytes
-rw-r--r--fonts/Helvetica-Narrowbin0 -> 36615 bytes
-rw-r--r--fonts/Helvetica-Narrow-Boldbin0 -> 37240 bytes
-rw-r--r--fonts/Helvetica-Narrow-BoldObliquebin0 -> 38310 bytes
-rw-r--r--fonts/Helvetica-Narrow-Obliquebin0 -> 37247 bytes
-rw-r--r--fonts/Helvetica-Obliquebin0 -> 38314 bytes
-rw-r--r--fonts/Makefile75
-rw-r--r--fonts/NewCenturySchlbk-Boldbin0 -> 48864 bytes
-rw-r--r--fonts/NewCenturySchlbk-BoldItalicbin0 -> 47083 bytes
-rw-r--r--fonts/NewCenturySchlbk-Italicbin0 -> 45832 bytes
-rw-r--r--fonts/NewCenturySchlbk-Romanbin0 -> 46830 bytes
-rw-r--r--fonts/Palatino-Boldbin0 -> 52406 bytes
-rw-r--r--fonts/Palatino-BoldItalicbin0 -> 51285 bytes
-rw-r--r--fonts/Palatino-Italicbin0 -> 50022 bytes
-rw-r--r--fonts/Palatino-Romanbin0 -> 52665 bytes
-rw-r--r--fonts/Symbolbin0 -> 33709 bytes
-rw-r--r--fonts/Times-Boldbin0 -> 44729 bytes
-rw-r--r--fonts/Times-BoldItalicbin0 -> 44656 bytes
-rw-r--r--fonts/Times-Italicbin0 -> 45458 bytes
-rw-r--r--fonts/Times-Romanbin0 -> 46026 bytes
-rw-r--r--fonts/Utopia-Boldbin0 -> 36580 bytes
-rw-r--r--fonts/Utopia-BoldItalicbin0 -> 37836 bytes
-rw-r--r--fonts/Utopia-Italicbin0 -> 37599 bytes
-rw-r--r--fonts/Utopia-Regularbin0 -> 36350 bytes
-rw-r--r--fonts/ZapfChancery-MediumItalicbin0 -> 49289 bytes
-rw-r--r--fonts/ZapfDingbatsbin0 -> 45955 bytes
-rwxr-xr-xinstall-sh251
-rw-r--r--locale/C/cups_C133
-rw-r--r--locale/Makefile77
-rw-r--r--locale/be/cups_be132
-rw-r--r--locale/cs/cups_cs133
-rw-r--r--locale/de/cups_de134
-rw-r--r--locale/en/cups_en133
-rw-r--r--locale/es/cups_es133
-rw-r--r--locale/fr/cups_fr133
-rw-r--r--locale/he/cups_he133
-rw-r--r--locale/it/cups_it133
-rw-r--r--locale/locale.txt32
-rw-r--r--locale/ru_RU.cp1251/cups_ru_RU.cp1251132
-rw-r--r--locale/ru_RU.koi8r/cups_ru_RU.koi8r132
-rw-r--r--locale/translate.c259
-rw-r--r--locale/uk/cups_uk132
-rw-r--r--locale/uk_UA.cp1251/cups_uk_UA.cp1251132
-rw-r--r--locale/zh_CN/cups_zh_CN133
-rw-r--r--man/.cvsignore6
-rw-r--r--man/Makefile114
-rw-r--r--man/accept.man60
-rw-r--r--man/backend.man109
-rw-r--r--man/classes.conf.man72
-rw-r--r--man/cups-config.man95
-rw-r--r--man/cups-lpd.man92
-rw-r--r--man/cups-polld.man46
-rw-r--r--man/cupsaddsmb.man114
-rw-r--r--man/cupsd.conf.man246
-rw-r--r--man/cupsd.man56
-rw-r--r--man/enable.man67
-rw-r--r--man/filter.man116
-rw-r--r--man/lp.man160
-rw-r--r--man/lpadmin.man155
-rw-r--r--man/lpc.man80
-rw-r--r--man/lpinfo.man60
-rw-r--r--man/lpmove.man53
-rw-r--r--man/lpoptions.man116
-rw-r--r--man/lppasswd.man61
-rw-r--r--man/lpq.man57
-rw-r--r--man/lpr.man101
-rw-r--r--man/lprm.man54
-rw-r--r--man/lpstat.man130
-rw-r--r--man/mime.convs.man54
-rw-r--r--man/mime.types.man98
-rw-r--r--man/printers.conf.man73
-rw-r--r--pdftops/.cvsignore1
-rw-r--r--pdftops/Array.cxx52
-rw-r--r--pdftops/Array.h56
-rw-r--r--pdftops/CNS13CMapInfo.h47771
-rw-r--r--pdftops/COPYING339
-rw-r--r--pdftops/Catalog.cxx308
-rw-r--r--pdftops/Catalog.h76
-rw-r--r--pdftops/CompactFontInfo.h464
-rw-r--r--pdftops/Decrypt.cxx384
-rw-r--r--pdftops/Decrypt.h59
-rw-r--r--pdftops/Dict.cxx89
-rw-r--r--pdftops/Dict.h75
-rw-r--r--pdftops/Error.cxx47
-rw-r--r--pdftops/Error.h26
-rw-r--r--pdftops/FontEncoding.cxx143
-rw-r--r--pdftops/FontEncoding.h64
-rw-r--r--pdftops/FontFile.cxx2530
-rw-r--r--pdftops/FontFile.h170
-rw-r--r--pdftops/FontInfo.h2070
-rw-r--r--pdftops/FormWidget.cxx130
-rw-r--r--pdftops/FormWidget.h67
-rw-r--r--pdftops/Function.cxx1373
-rw-r--r--pdftops/Function.h157
-rw-r--r--pdftops/GB12CMapInfo.h50880
-rw-r--r--pdftops/GString.cxx223
-rw-r--r--pdftops/GString.h95
-rw-r--r--pdftops/Gfx.cxx2508
-rw-r--r--pdftops/Gfx.h242
-rw-r--r--pdftops/GfxFont.cxx1081
-rw-r--r--pdftops/GfxFont.h250
-rw-r--r--pdftops/GfxState.cxx2100
-rw-r--r--pdftops/GfxState.h922
-rw-r--r--pdftops/Japan12CMapInfo.h31362
-rw-r--r--pdftops/Japan12ToRKSJ.h1038
-rw-r--r--pdftops/Lexer.cxx472
-rw-r--r--pdftops/Lexer.h74
-rw-r--r--pdftops/Link.cxx633
-rw-r--r--pdftops/Link.h336
-rw-r--r--pdftops/Makefile132
-rw-r--r--pdftops/Object.cxx220
-rw-r--r--pdftops/Object.h299
-rw-r--r--pdftops/OutputDev.cxx94
-rw-r--r--pdftops/OutputDev.h140
-rw-r--r--pdftops/PDFDoc.cxx251
-rw-r--r--pdftops/PDFDoc.h135
-rw-r--r--pdftops/PSOutputDev.cxx2562
-rw-r--r--pdftops/PSOutputDev.h215
-rw-r--r--pdftops/Page.cxx268
-rw-r--r--pdftops/Page.h125
-rw-r--r--pdftops/Params.cxx90
-rw-r--r--pdftops/Params.h38
-rw-r--r--pdftops/Parser.cxx212
-rw-r--r--pdftops/Parser.h58
-rw-r--r--pdftops/README426
-rw-r--r--pdftops/SFont.h127
-rw-r--r--pdftops/StdFontInfo.h546
-rw-r--r--pdftops/Stream-CCITT.h459
-rw-r--r--pdftops/Stream.cxx3466
-rw-r--r--pdftops/Stream.h723
-rw-r--r--pdftops/T1Font.h102
-rw-r--r--pdftops/TTFont.h104
-rw-r--r--pdftops/XRef.cxx635
-rw-r--r--pdftops/XRef.h110
-rw-r--r--pdftops/config.h140
-rw-r--r--pdftops/gfile.cxx678
-rw-r--r--pdftops/gfile.h132
-rw-r--r--pdftops/gmem.c203
-rw-r--r--pdftops/gmem.h53
-rw-r--r--pdftops/gmempp.cxx31
-rw-r--r--pdftops/gtypes.h31
-rw-r--r--pdftops/parseargs.c190
-rw-r--r--pdftops/parseargs.h71
-rw-r--r--pdftops/pdftops.cxx157
-rw-r--r--ppd/Makefile63
-rw-r--r--ppd/deskjet.ppd198
-rw-r--r--ppd/deskjet2.ppd217
-rw-r--r--ppd/dymo.ppd155
-rw-r--r--ppd/epson24.ppd128
-rw-r--r--ppd/epson9.ppd126
-rw-r--r--ppd/laserjet.ppd200
-rw-r--r--ppd/okidat24.ppd128
-rw-r--r--ppd/okidata9.ppd126
-rw-r--r--ppd/stcolor.ppd132
-rw-r--r--ppd/stcolor2.ppd132
-rw-r--r--ppd/stphoto.ppd132
-rw-r--r--ppd/stphoto2.ppd132
-rw-r--r--pstoraster/.cvsignore3
-rw-r--r--pstoraster/Dependencies2213
-rw-r--r--pstoraster/Fontmap98
-rw-r--r--pstoraster/Makefile454
-rw-r--r--pstoraster/bfont.h76
-rw-r--r--pstoraster/bseq.h66
-rw-r--r--pstoraster/btoken.h41
-rw-r--r--pstoraster/ctype_.h37
-rw-r--r--pstoraster/dirent_.h60
-rw-r--r--pstoraster/dstack.h236
-rw-r--r--pstoraster/errno_.h42
-rw-r--r--pstoraster/errors.h148
-rw-r--r--pstoraster/estack.h139
-rw-r--r--pstoraster/files.h157
-rw-r--r--pstoraster/fname.h54
-rw-r--r--pstoraster/gconf.h43
-rw-r--r--pstoraster/gconfig.c127
-rw-r--r--pstoraster/gconfig.h243
-rw-r--r--pstoraster/gconfig_.h5
-rw-r--r--pstoraster/gconfigv.h4
-rw-r--r--pstoraster/gdebug.h132
-rw-r--r--pstoraster/gdev8bcm.h78
-rw-r--r--pstoraster/gdevabuf.c404
-rw-r--r--pstoraster/gdevbbox.c1069
-rw-r--r--pstoraster/gdevbbox.h100
-rw-r--r--pstoraster/gdevcmap.h74
-rw-r--r--pstoraster/gdevcups.c3058
-rw-r--r--pstoraster/gdevdbit.c708
-rw-r--r--pstoraster/gdevddrw.c643
-rw-r--r--pstoraster/gdevdflt.c270
-rw-r--r--pstoraster/gdevdgbr.c586
-rw-r--r--pstoraster/gdevhit.c98
-rw-r--r--pstoraster/gdevht.h51
-rw-r--r--pstoraster/gdevm1.c759
-rw-r--r--pstoraster/gdevm16.c168
-rw-r--r--pstoraster/gdevm2.c259
-rw-r--r--pstoraster/gdevm24.c526
-rw-r--r--pstoraster/gdevm32.c249
-rw-r--r--pstoraster/gdevm4.c319
-rw-r--r--pstoraster/gdevm8.c247
-rw-r--r--pstoraster/gdevmem.c501
-rw-r--r--pstoraster/gdevmem.h233
-rw-r--r--pstoraster/gdevmgr.h127
-rw-r--r--pstoraster/gdevmpla.c200
-rw-r--r--pstoraster/gdevmrop.h97
-rw-r--r--pstoraster/gdevnfwd.c797
-rw-r--r--pstoraster/gdevpccm.h44
-rw-r--r--pstoraster/gdevpcfb.h209
-rw-r--r--pstoraster/gdevpcl.h52
-rw-r--r--pstoraster/gdevpipe.c72
-rw-r--r--pstoraster/gdevpm.h46
-rw-r--r--pstoraster/gdevprn.c837
-rw-r--r--pstoraster/gdevprn.h560
-rw-r--r--pstoraster/gdevprna.h190
-rw-r--r--pstoraster/gdevps.c1151
-rw-r--r--pstoraster/gdevpsde.c282
-rw-r--r--pstoraster/gdevpsdf.c514
-rw-r--r--pstoraster/gdevpsdf.h292
-rw-r--r--pstoraster/gdevpsdi.c349
-rw-r--r--pstoraster/gdevpsdp.c705
-rw-r--r--pstoraster/gdevpsds.c470
-rw-r--r--pstoraster/gdevpsds.h110
-rw-r--r--pstoraster/gdevpstr.h90
-rw-r--r--pstoraster/gdevpxop.h114
-rw-r--r--pstoraster/gdevvec.c905
-rw-r--r--pstoraster/gdevvec.h349
-rw-r--r--pstoraster/genarch.c163
-rw-r--r--pstoraster/ghost.h34
-rw-r--r--pstoraster/gp.h233
-rw-r--r--pstoraster/gp_getnv.c60
-rw-r--r--pstoraster/gp_nofb.c58
-rw-r--r--pstoraster/gp_nsync.c120
-rw-r--r--pstoraster/gp_unifn.c61
-rw-r--r--pstoraster/gp_unifs.c424
-rw-r--r--pstoraster/gp_unix.c173
-rw-r--r--pstoraster/gpcheck.h65
-rw-r--r--pstoraster/gpgetenv.h50
-rw-r--r--pstoraster/gpsync.h81
-rw-r--r--pstoraster/gs_btokn.ps313
-rw-r--r--pstoraster/gs_ccfnt.ps100
-rw-r--r--pstoraster/gs_cff.ps614
-rw-r--r--pstoraster/gs_cidfn.ps466
-rw-r--r--pstoraster/gs_cmap.ps256
-rw-r--r--pstoraster/gs_cmdl.ps188
-rw-r--r--pstoraster/gs_dbt_e.ps67
-rw-r--r--pstoraster/gs_diskf.ps232
-rw-r--r--pstoraster/gs_dpnxt.ps120
-rw-r--r--pstoraster/gs_dps.ps205
-rw-r--r--pstoraster/gs_dps1.ps147
-rw-r--r--pstoraster/gs_dps2.ps200
-rw-r--r--pstoraster/gs_epsf.ps67
-rw-r--r--pstoraster/gs_fform.ps100
-rw-r--r--pstoraster/gs_fonts.ps934
-rw-r--r--pstoraster/gs_init.ps1521
-rw-r--r--pstoraster/gs_iso_e.ps74
-rw-r--r--pstoraster/gs_kanji.ps166
-rw-r--r--pstoraster/gs_ksb_e.ps72
-rw-r--r--pstoraster/gs_lev2.ps717
-rw-r--r--pstoraster/gs_ll3.ps387
-rw-r--r--pstoraster/gs_mex_e.ps72
-rw-r--r--pstoraster/gs_mro_e.ps65
-rw-r--r--pstoraster/gs_pfile.ps135
-rw-r--r--pstoraster/gs_res.ps726
-rw-r--r--pstoraster/gs_setpd.ps715
-rw-r--r--pstoraster/gs_statd.ps301
-rw-r--r--pstoraster/gs_std_e.ps81
-rw-r--r--pstoraster/gs_sym_e.ps91
-rw-r--r--pstoraster/gs_ttf.ps694
-rw-r--r--pstoraster/gs_typ32.ps134
-rw-r--r--pstoraster/gs_typ42.ps52
-rw-r--r--pstoraster/gs_type1.ps145
-rw-r--r--pstoraster/gs_wan_e.ps52
-rw-r--r--pstoraster/gs_wl1_e.ps74
-rw-r--r--pstoraster/gs_wl2_e.ps74
-rw-r--r--pstoraster/gs_wl5_e.ps74
-rw-r--r--pstoraster/gsalloc.c1621
-rw-r--r--pstoraster/gsalloc.h87
-rw-r--r--pstoraster/gsalpha.c48
-rw-r--r--pstoraster/gsalpha.h41
-rw-r--r--pstoraster/gsalphac.h71
-rw-r--r--pstoraster/gsargs.c225
-rw-r--r--pstoraster/gsargs.h89
-rw-r--r--pstoraster/gsbitmap.h193
-rw-r--r--pstoraster/gsbitops.c674
-rw-r--r--pstoraster/gsbitops.h222
-rw-r--r--pstoraster/gsbittab.c144
-rw-r--r--pstoraster/gsbittab.h83
-rw-r--r--pstoraster/gsccode.h72
-rw-r--r--pstoraster/gsccolor.h58
-rw-r--r--pstoraster/gscdefs.c78
-rw-r--r--pstoraster/gscdefs.h81
-rw-r--r--pstoraster/gscdevn.c184
-rw-r--r--pstoraster/gschar.c1492
-rw-r--r--pstoraster/gschar.h130
-rw-r--r--pstoraster/gschar0.c407
-rw-r--r--pstoraster/gscie.c1357
-rw-r--r--pstoraster/gscie.h688
-rw-r--r--pstoraster/gsclipsr.c45
-rw-r--r--pstoraster/gsclipsr.h34
-rw-r--r--pstoraster/gscolor.c357
-rw-r--r--pstoraster/gscolor.h43
-rw-r--r--pstoraster/gscolor1.c271
-rw-r--r--pstoraster/gscolor1.h47
-rw-r--r--pstoraster/gscolor2.c455
-rw-r--r--pstoraster/gscolor2.h106
-rw-r--r--pstoraster/gscolor3.c70
-rw-r--r--pstoraster/gscolor3.h41
-rw-r--r--pstoraster/gscompt.h59
-rw-r--r--pstoraster/gscoord.c507
-rw-r--r--pstoraster/gscoord.h55
-rw-r--r--pstoraster/gscparam.c480
-rw-r--r--pstoraster/gscpixel.c89
-rw-r--r--pstoraster/gscpixel.h34
-rw-r--r--pstoraster/gscpm.h39
-rw-r--r--pstoraster/gscrd.c350
-rw-r--r--pstoraster/gscrd.h75
-rw-r--r--pstoraster/gscrdp.c632
-rw-r--r--pstoraster/gscrdp.h104
-rw-r--r--pstoraster/gscrypt1.h56
-rw-r--r--pstoraster/gscscie.c374
-rw-r--r--pstoraster/gscsel.h44
-rw-r--r--pstoraster/gscsepnm.h54
-rw-r--r--pstoraster/gscsepr.c352
-rw-r--r--pstoraster/gscsepr.h74
-rw-r--r--pstoraster/gscspace.c237
-rw-r--r--pstoraster/gscspace.h400
-rw-r--r--pstoraster/gsdcolor.h332
-rw-r--r--pstoraster/gsdevice.c570
-rw-r--r--pstoraster/gsdevice.h103
-rw-r--r--pstoraster/gsdevmem.c239
-rw-r--r--pstoraster/gsdll.h145
-rw-r--r--pstoraster/gsdparam.c782
-rw-r--r--pstoraster/gsdpnext.h34
-rw-r--r--pstoraster/gsdps.h40
-rw-r--r--pstoraster/gsdps1.c242
-rw-r--r--pstoraster/gsdsrc.c121
-rw-r--r--pstoraster/gsdsrc.h133
-rw-r--r--pstoraster/gserror.h42
-rw-r--r--pstoraster/gserrors.h56
-rw-r--r--pstoraster/gsexit.h41
-rw-r--r--pstoraster/gsfcmap.c167
-rw-r--r--pstoraster/gsfcmap.h69
-rw-r--r--pstoraster/gsflip.h46
-rw-r--r--pstoraster/gsfont.c558
-rw-r--r--pstoraster/gsfont.h87
-rw-r--r--pstoraster/gsfont0.c136
-rw-r--r--pstoraster/gsfunc.c78
-rw-r--r--pstoraster/gsfunc.h136
-rw-r--r--pstoraster/gsfunc0.c347
-rw-r--r--pstoraster/gsfunc0.h66
-rw-r--r--pstoraster/gsfunc3.c361
-rw-r--r--pstoraster/gsfunc3.h114
-rw-r--r--pstoraster/gsgc.h91
-rw-r--r--pstoraster/gshsb.c171
-rw-r--r--pstoraster/gshsb.h33
-rw-r--r--pstoraster/gsht.c651
-rw-r--r--pstoraster/gsht.h78
-rw-r--r--pstoraster/gsht1.c449
-rw-r--r--pstoraster/gsht1.h60
-rw-r--r--pstoraster/gshtscr.c574
-rw-r--r--pstoraster/gshtx.h158
-rw-r--r--pstoraster/gsimage.c326
-rw-r--r--pstoraster/gsimage.h84
-rw-r--r--pstoraster/gsimpath.c191
-rw-r--r--pstoraster/gsinit.c79
-rw-r--r--pstoraster/gsio.h66
-rw-r--r--pstoraster/gsiodev.c318
-rw-r--r--pstoraster/gsiparam.h289
-rw-r--r--pstoraster/gsiparm2.h63
-rw-r--r--pstoraster/gsiparm3.h67
-rw-r--r--pstoraster/gsiparm4.h59
-rw-r--r--pstoraster/gsjconf.h81
-rw-r--r--pstoraster/gsjmorec.h59
-rw-r--r--pstoraster/gslib.h44
-rw-r--r--pstoraster/gsline.c340
-rw-r--r--pstoraster/gsline.h75
-rw-r--r--pstoraster/gslparam.h52
-rw-r--r--pstoraster/gsmalloc.c398
-rw-r--r--pstoraster/gsmalloc.h78
-rw-r--r--pstoraster/gsmatrix.c455
-rw-r--r--pstoraster/gsmatrix.h80
-rw-r--r--pstoraster/gsmdebug.h54
-rw-r--r--pstoraster/gsmemlok.h64
-rw-r--r--pstoraster/gsmemory.c198
-rw-r--r--pstoraster/gsmemory.h277
-rw-r--r--pstoraster/gsmemraw.h181
-rw-r--r--pstoraster/gsmisc.c942
-rw-r--r--pstoraster/gsnorop.c119
-rw-r--r--pstoraster/gspaint.c356
-rw-r--r--pstoraster/gspaint.h38
-rw-r--r--pstoraster/gsparam.c382
-rw-r--r--pstoraster/gsparam.h505
-rw-r--r--pstoraster/gsparams.c417
-rw-r--r--pstoraster/gsparams.h77
-rw-r--r--pstoraster/gspath.c518
-rw-r--r--pstoraster/gspath.h98
-rw-r--r--pstoraster/gspath1.c480
-rw-r--r--pstoraster/gspath2.h40
-rw-r--r--pstoraster/gspcolor.c958
-rw-r--r--pstoraster/gspcolor.h87
-rw-r--r--pstoraster/gspenum.h40
-rw-r--r--pstoraster/gspmdrv.h40
-rw-r--r--pstoraster/gsptype1.h143
-rw-r--r--pstoraster/gsptype2.h52
-rw-r--r--pstoraster/gsrect.h61
-rw-r--r--pstoraster/gsrefct.h148
-rw-r--r--pstoraster/gsrop.h46
-rw-r--r--pstoraster/gsropc.h60
-rw-r--r--pstoraster/gsropt.h195
-rw-r--r--pstoraster/gsshade.c451
-rw-r--r--pstoraster/gsshade.h255
-rw-r--r--pstoraster/gsstate.c1025
-rw-r--r--pstoraster/gsstate.h81
-rw-r--r--pstoraster/gsstruct.h970
-rw-r--r--pstoraster/gstext.c344
-rw-r--r--pstoraster/gstext.h231
-rw-r--r--pstoraster/gstrap.c190
-rw-r--r--pstoraster/gstrap.h81
-rw-r--r--pstoraster/gstype1.c562
-rw-r--r--pstoraster/gstype1.h265
-rw-r--r--pstoraster/gstype2.c779
-rw-r--r--pstoraster/gstype42.c481
-rw-r--r--pstoraster/gstypes.h86
-rw-r--r--pstoraster/gsuid.h78
-rw-r--r--pstoraster/gsutil.c285
-rw-r--r--pstoraster/gsutil.h67
-rw-r--r--pstoraster/gsxfont.h45
-rw-r--r--pstoraster/gx.h52
-rw-r--r--pstoraster/gxacpath.c479
-rw-r--r--pstoraster/gxalloc.h403
-rw-r--r--pstoraster/gxalpha.h74
-rw-r--r--pstoraster/gxarith.h84
-rw-r--r--pstoraster/gxband.h70
-rw-r--r--pstoraster/gxbcache.c153
-rw-r--r--pstoraster/gxbcache.h130
-rw-r--r--pstoraster/gxbitfmt.h195
-rw-r--r--pstoraster/gxbitmap.h133
-rw-r--r--pstoraster/gxbitops.h142
-rw-r--r--pstoraster/gxccache.c456
-rw-r--r--pstoraster/gxccman.c797
-rw-r--r--pstoraster/gxchar.h190
-rw-r--r--pstoraster/gxcht.c710
-rw-r--r--pstoraster/gxcindex.h91
-rw-r--r--pstoraster/gxclbits.c740
-rw-r--r--pstoraster/gxcldev.h727
-rw-r--r--pstoraster/gxclimag.c1316
-rw-r--r--pstoraster/gxclio.h104
-rw-r--r--pstoraster/gxclip.c582
-rw-r--r--pstoraster/gxclip.h75
-rw-r--r--pstoraster/gxclip2.c306
-rw-r--r--pstoraster/gxclip2.h55
-rw-r--r--pstoraster/gxclipm.c309
-rw-r--r--pstoraster/gxclipm.h35
-rw-r--r--pstoraster/gxclist.c734
-rw-r--r--pstoraster/gxclist.h299
-rw-r--r--pstoraster/gxclmem.c1151
-rw-r--r--pstoraster/gxclmem.h155
-rw-r--r--pstoraster/gxclpage.c127
-rw-r--r--pstoraster/gxclpage.h63
-rw-r--r--pstoraster/gxclpath.c1198
-rw-r--r--pstoraster/gxclpath.h207
-rw-r--r--pstoraster/gxclrast.c2333
-rw-r--r--pstoraster/gxclread.c517
-rw-r--r--pstoraster/gxclrect.c656
-rw-r--r--pstoraster/gxclutil.c616
-rw-r--r--pstoraster/gxclzlib.c76
-rw-r--r--pstoraster/gxcmap.c890
-rw-r--r--pstoraster/gxcmap.h101
-rw-r--r--pstoraster/gxcolor2.h98
-rw-r--r--pstoraster/gxcomp.h113
-rw-r--r--pstoraster/gxcoord.h44
-rw-r--r--pstoraster/gxcpath.c962
-rw-r--r--pstoraster/gxcpath.h134
-rw-r--r--pstoraster/gxcspace.h237
-rw-r--r--pstoraster/gxctable.c146
-rw-r--r--pstoraster/gxctable.h70
-rw-r--r--pstoraster/gxcvalue.h48
-rw-r--r--pstoraster/gxdcconv.c162
-rw-r--r--pstoraster/gxdcconv.h43
-rw-r--r--pstoraster/gxdcolor.c339
-rw-r--r--pstoraster/gxdcolor.h199
-rw-r--r--pstoraster/gxdda.h158
-rw-r--r--pstoraster/gxdevcli.h877
-rw-r--r--pstoraster/gxdevice.h453
-rw-r--r--pstoraster/gxdevmem.h170
-rw-r--r--pstoraster/gxdevrop.h35
-rw-r--r--pstoraster/gxdht.h272
-rw-r--r--pstoraster/gxdither.c502
-rw-r--r--pstoraster/gxdither.h76
-rw-r--r--pstoraster/gxfarith.h144
-rw-r--r--pstoraster/gxfcache.h270
-rw-r--r--pstoraster/gxfcmap.h101
-rw-r--r--pstoraster/gxfill.c1543
-rw-r--r--pstoraster/gxfixed.h248
-rw-r--r--pstoraster/gxfmap.h105
-rw-r--r--pstoraster/gxfont.h224
-rw-r--r--pstoraster/gxfont0.h81
-rw-r--r--pstoraster/gxfont1.h158
-rw-r--r--pstoraster/gxfont42.h72
-rw-r--r--pstoraster/gxfrac.h98
-rw-r--r--pstoraster/gxftype.h57
-rw-r--r--pstoraster/gxfunc.h56
-rw-r--r--pstoraster/gxgetbit.h101
-rw-r--r--pstoraster/gxhint1.c275
-rw-r--r--pstoraster/gxhint2.c397
-rw-r--r--pstoraster/gxhint3.c560
-rw-r--r--pstoraster/gxht.c532
-rw-r--r--pstoraster/gxht.h222
-rw-r--r--pstoraster/gxhttile.h54
-rw-r--r--pstoraster/gxhttype.h45
-rw-r--r--pstoraster/gxi12bit.c300
-rw-r--r--pstoraster/gxicolor.c307
-rw-r--r--pstoraster/gxidata.c255
-rw-r--r--pstoraster/gxifast.c716
-rw-r--r--pstoraster/gxiinit.c921
-rw-r--r--pstoraster/gximage.h283
-rw-r--r--pstoraster/gximage3.c429
-rw-r--r--pstoraster/gximage4.c297
-rw-r--r--pstoraster/gximono.c586
-rw-r--r--pstoraster/gxiodev.h190
-rw-r--r--pstoraster/gxiparam.h172
-rw-r--r--pstoraster/gxiscale.c256
-rw-r--r--pstoraster/gxistate.h251
-rw-r--r--pstoraster/gxline.h81
-rw-r--r--pstoraster/gxlum.h50
-rw-r--r--pstoraster/gxmatrix.h83
-rw-r--r--pstoraster/gxmclip.c116
-rw-r--r--pstoraster/gxmclip.h111
-rw-r--r--pstoraster/gxobj.h230
-rw-r--r--pstoraster/gxop1.h81
-rw-r--r--pstoraster/gxp1fill.c374
-rw-r--r--pstoraster/gxp1fill.h40
-rw-r--r--pstoraster/gxpageq.h192
-rw-r--r--pstoraster/gxpaint.c81
-rw-r--r--pstoraster/gxpaint.h125
-rw-r--r--pstoraster/gxpath.c829
-rw-r--r--pstoraster/gxpath.h317
-rw-r--r--pstoraster/gxpath2.c487
-rw-r--r--pstoraster/gxpcache.h61
-rw-r--r--pstoraster/gxpcmap.c666
-rw-r--r--pstoraster/gxpcolor.h138
-rw-r--r--pstoraster/gxpcopy.c824
-rw-r--r--pstoraster/gxpdash.c189
-rw-r--r--pstoraster/gxpflat.c455
-rw-r--r--pstoraster/gxropc.h53
-rw-r--r--pstoraster/gxsample.c211
-rw-r--r--pstoraster/gxsample.h87
-rw-r--r--pstoraster/gxshade.c348
-rw-r--r--pstoraster/gxshade.h247
-rw-r--r--pstoraster/gxshade1.c527
-rw-r--r--pstoraster/gxshade4.c285
-rw-r--r--pstoraster/gxshade4.h58
-rw-r--r--pstoraster/gxshade6.c566
-rw-r--r--pstoraster/gxstate.h86
-rw-r--r--pstoraster/gxstroke.c1319
-rw-r--r--pstoraster/gxsync.h81
-rw-r--r--pstoraster/gxtext.h121
-rw-r--r--pstoraster/gxtmap.h58
-rw-r--r--pstoraster/gxtype1.c518
-rw-r--r--pstoraster/gxtype1.h346
-rw-r--r--pstoraster/gxxfont.h180
-rw-r--r--pstoraster/gzacpath.h60
-rw-r--r--pstoraster/gzcpath.h106
-rw-r--r--pstoraster/gzht.h203
-rw-r--r--pstoraster/gzline.h41
-rw-r--r--pstoraster/gzpath.h385
-rw-r--r--pstoraster/gzstate.h137
-rw-r--r--pstoraster/ialloc.c314
-rw-r--r--pstoraster/ialloc.h125
-rw-r--r--pstoraster/iastate.h35
-rw-r--r--pstoraster/iastruct.h34
-rw-r--r--pstoraster/ibnum.c222
-rw-r--r--pstoraster/ibnum.h71
-rw-r--r--pstoraster/iccinit0.c31
-rw-r--r--pstoraster/ichar.h72
-rw-r--r--pstoraster/icharout.h59
-rw-r--r--pstoraster/icie.h96
-rw-r--r--pstoraster/icolor.h54
-rw-r--r--pstoraster/iconfig.c74
-rw-r--r--pstoraster/icontext.c275
-rw-r--r--pstoraster/icontext.h59
-rw-r--r--pstoraster/icsmap.h45
-rw-r--r--pstoraster/icstate.h74
-rw-r--r--pstoraster/idebug.c299
-rw-r--r--pstoraster/idebug.h48
-rw-r--r--pstoraster/idict.c780
-rw-r--r--pstoraster/idict.h268
-rw-r--r--pstoraster/idictdef.h128
-rw-r--r--pstoraster/idparam.c371
-rw-r--r--pstoraster/idparam.h90
-rw-r--r--pstoraster/idstack.c249
-rw-r--r--pstoraster/idstack.h125
-rw-r--r--pstoraster/iestack.h56
-rw-r--r--pstoraster/ifilter.h89
-rw-r--r--pstoraster/ifont.h97
-rw-r--r--pstoraster/ifunc.h58
-rw-r--r--pstoraster/igc.c1316
-rw-r--r--pstoraster/igc.h102
-rw-r--r--pstoraster/igcref.c681
-rw-r--r--pstoraster/igcstr.c393
-rw-r--r--pstoraster/igcstr.h41
-rw-r--r--pstoraster/igstate.h181
-rw-r--r--pstoraster/iht.h37
-rw-r--r--pstoraster/iimage.h46
-rw-r--r--pstoraster/iimage2.h50
-rw-r--r--pstoraster/iinit.c511
-rw-r--r--pstoraster/ilevel.h39
-rw-r--r--pstoraster/ilocate.c439
-rw-r--r--pstoraster/imain.c664
-rw-r--r--pstoraster/imain.h276
-rw-r--r--pstoraster/imainarg.c849
-rw-r--r--pstoraster/imainarg.h54
-rw-r--r--pstoraster/imemory.h99
-rw-r--r--pstoraster/iminst.h92
-rw-r--r--pstoraster/iname.c637
-rw-r--r--pstoraster/iname.h105
-rw-r--r--pstoraster/inamedef.h230
-rw-r--r--pstoraster/inames.h114
-rw-r--r--pstoraster/interp.c1554
-rw-r--r--pstoraster/interp.h95
-rw-r--r--pstoraster/iostack.h45
-rw-r--r--pstoraster/ipacked.h159
-rw-r--r--pstoraster/iparam.c1080
-rw-r--r--pstoraster/iparam.h118
-rw-r--r--pstoraster/iparray.h42
-rw-r--r--pstoraster/ireclaim.c163
-rw-r--r--pstoraster/iref.h431
-rw-r--r--pstoraster/isave.c1070
-rw-r--r--pstoraster/isave.h133
-rw-r--r--pstoraster/iscan.c1131
-rw-r--r--pstoraster/iscan.h161
-rw-r--r--pstoraster/iscanbin.c768
-rw-r--r--pstoraster/iscannum.c398
-rw-r--r--pstoraster/iscannum.h36
-rw-r--r--pstoraster/isstate.h46
-rw-r--r--pstoraster/istack.c588
-rw-r--r--pstoraster/istack.h256
-rw-r--r--pstoraster/istream.h43
-rw-r--r--pstoraster/istruct.h98
-rw-r--r--pstoraster/iutil.c676
-rw-r--r--pstoraster/iutil.h121
-rw-r--r--pstoraster/iutil2.c154
-rw-r--r--pstoraster/iutil2.h56
-rw-r--r--pstoraster/ivmspace.h111
-rw-r--r--pstoraster/main.h101
-rw-r--r--pstoraster/malloc_.h59
-rw-r--r--pstoraster/math_.h97
-rw-r--r--pstoraster/memory_.h107
-rw-r--r--pstoraster/opcheck.h86
-rw-r--r--pstoraster/opdef.h164
-rw-r--r--pstoraster/oper.h108
-rw-r--r--pstoraster/opextern.h115
-rw-r--r--pstoraster/ostack.h94
-rw-r--r--pstoraster/pipe_.h42
-rw-r--r--pstoraster/pstoraster.c253
-rw-r--r--pstoraster/sa85x.h51
-rw-r--r--pstoraster/sbcp.c259
-rw-r--r--pstoraster/sbhc.c291
-rw-r--r--pstoraster/sbhc.h98
-rw-r--r--pstoraster/sbtx.h45
-rw-r--r--pstoraster/sbwbs.c535
-rw-r--r--pstoraster/sbwbs.h78
-rw-r--r--pstoraster/scanchar.h75
-rw-r--r--pstoraster/scantab.c112
-rw-r--r--pstoraster/scf.h213
-rw-r--r--pstoraster/scfd.c809
-rw-r--r--pstoraster/scfdtab.c942
-rw-r--r--pstoraster/scfe.c536
-rw-r--r--pstoraster/scfetab.c170
-rw-r--r--pstoraster/scfparam.c99
-rw-r--r--pstoraster/scfx.h132
-rw-r--r--pstoraster/scommon.h173
-rw-r--r--pstoraster/sdcparam.c630
-rw-r--r--pstoraster/sdcparam.h57
-rw-r--r--pstoraster/sdct.h121
-rw-r--r--pstoraster/sdctc.c55
-rw-r--r--pstoraster/sdctd.c303
-rw-r--r--pstoraster/sdcte.c203
-rw-r--r--pstoraster/sddparam.c83
-rw-r--r--pstoraster/sdeparam.c328
-rw-r--r--pstoraster/seexec.c192
-rw-r--r--pstoraster/sfilter.h139
-rw-r--r--pstoraster/sfilter1.c301
-rw-r--r--pstoraster/sfilter2.c339
-rw-r--r--pstoraster/sfxstdio.c269
-rw-r--r--pstoraster/shc.c74
-rw-r--r--pstoraster/shc.h254
-rw-r--r--pstoraster/shcgen.c491
-rw-r--r--pstoraster/shcgen.h60
-rw-r--r--pstoraster/siscale.c498
-rw-r--r--pstoraster/siscale.h148
-rw-r--r--pstoraster/sjpeg.h80
-rw-r--r--pstoraster/sjpegc.c305
-rw-r--r--pstoraster/sjpegd.c100
-rw-r--r--pstoraster/sjpege.c129
-rw-r--r--pstoraster/sjpegerr.c102
-rw-r--r--pstoraster/slzwc.c50
-rw-r--r--pstoraster/slzwce.c167
-rw-r--r--pstoraster/slzwd.c372
-rw-r--r--pstoraster/slzwx.h80
-rw-r--r--pstoraster/smtf.c184
-rw-r--r--pstoraster/smtf.h49
-rw-r--r--pstoraster/spcxd.c75
-rw-r--r--pstoraster/spcxx.h35
-rw-r--r--pstoraster/spdiff.c334
-rw-r--r--pstoraster/spdiffx.h55
-rw-r--r--pstoraster/spngp.c364
-rw-r--r--pstoraster/spngpx.h61
-rw-r--r--pstoraster/srld.c133
-rw-r--r--pstoraster/srle.c203
-rw-r--r--pstoraster/srlx.h77
-rw-r--r--pstoraster/sstring.c464
-rw-r--r--pstoraster/sstring.h79
-rw-r--r--pstoraster/stat_.h62
-rw-r--r--pstoraster/std.h261
-rw-r--r--pstoraster/stdio_.h74
-rw-r--r--pstoraster/stdpre.h422
-rw-r--r--pstoraster/store.h250
-rw-r--r--pstoraster/stream.c911
-rw-r--r--pstoraster/stream.h334
-rw-r--r--pstoraster/strimpl.h154
-rw-r--r--pstoraster/string_.h59
-rw-r--r--pstoraster/szlibc.c151
-rw-r--r--pstoraster/szlibd.c118
-rw-r--r--pstoraster/szlibe.c115
-rw-r--r--pstoraster/szlibx.h74
-rw-r--r--pstoraster/szlibxx.h73
-rw-r--r--pstoraster/time_.h70
-rw-r--r--pstoraster/vmsmath.h49
-rw-r--r--pstoraster/zarith.c373
-rw-r--r--pstoraster/zarray.c131
-rw-r--r--pstoraster/zbseq.c136
-rw-r--r--pstoraster/zcfont.c164
-rw-r--r--pstoraster/zchar.c710
-rw-r--r--pstoraster/zchar1.c763
-rw-r--r--pstoraster/zchar2.c228
-rw-r--r--pstoraster/zchar32.c217
-rw-r--r--pstoraster/zchar42.c184
-rw-r--r--pstoraster/zcharout.c241
-rw-r--r--pstoraster/zcid.c102
-rw-r--r--pstoraster/zcie.c731
-rw-r--r--pstoraster/zcolor.c241
-rw-r--r--pstoraster/zcolor1.c247
-rw-r--r--pstoraster/zcolor2.c191
-rw-r--r--pstoraster/zcontrol.c897
-rw-r--r--pstoraster/zcrd.c438
-rw-r--r--pstoraster/zcsdevn.c119
-rw-r--r--pstoraster/zcsindex.c239
-rw-r--r--pstoraster/zcspixel.c73
-rw-r--r--pstoraster/zcssepr.c186
-rw-r--r--pstoraster/zdevcal.c79
-rw-r--r--pstoraster/zdevice.c445
-rw-r--r--pstoraster/zdevice2.c373
-rw-r--r--pstoraster/zdict.c515
-rw-r--r--pstoraster/zdps1.c459
-rw-r--r--pstoraster/zfbcp.c99
-rw-r--r--pstoraster/zfcmap.c355
-rw-r--r--pstoraster/zfdctd.c110
-rw-r--r--pstoraster/zfdcte.c157
-rw-r--r--pstoraster/zfdecode.c363
-rw-r--r--pstoraster/zfile.c915
-rw-r--r--pstoraster/zfileio.c842
-rw-r--r--pstoraster/zfilter.c418
-rw-r--r--pstoraster/zfilter2.c165
-rw-r--r--pstoraster/zfilterx.c336
-rw-r--r--pstoraster/zfname.c116
-rw-r--r--pstoraster/zfont.c471
-rw-r--r--pstoraster/zfont0.c346
-rw-r--r--pstoraster/zfont1.c291
-rw-r--r--pstoraster/zfont2.c553
-rw-r--r--pstoraster/zfont32.c79
-rw-r--r--pstoraster/zfont42.c189
-rw-r--r--pstoraster/zfproc.c363
-rw-r--r--pstoraster/zfreuse.c206
-rw-r--r--pstoraster/zfunc.c237
-rw-r--r--pstoraster/zfunc0.c113
-rw-r--r--pstoraster/zfunc3.c136
-rw-r--r--pstoraster/zfzlib.c105
-rw-r--r--pstoraster/zgeneric.c528
-rw-r--r--pstoraster/zgstate.c450
-rw-r--r--pstoraster/zhsb.c68
-rw-r--r--pstoraster/zht.c265
-rw-r--r--pstoraster/zht1.c156
-rw-r--r--pstoraster/zht2.c357
-rw-r--r--pstoraster/zimage.c490
-rw-r--r--pstoraster/zimage2.c158
-rw-r--r--pstoraster/zimage3.c139
-rw-r--r--pstoraster/ziodev.c475
-rw-r--r--pstoraster/ziodev2.c148
-rw-r--r--pstoraster/zmath.c277
-rw-r--r--pstoraster/zmatrix.c358
-rw-r--r--pstoraster/zmedia2.c472
-rw-r--r--pstoraster/zmisc.c345
-rw-r--r--pstoraster/zmisc1.c157
-rw-r--r--pstoraster/zmisc2.c322
-rw-r--r--pstoraster/zmisc3.c129
-rw-r--r--pstoraster/zpacked.c258
-rw-r--r--pstoraster/zpaint.c92
-rw-r--r--pstoraster/zpath.c205
-rw-r--r--pstoraster/zpath1.c279
-rw-r--r--pstoraster/zpcolor.c264
-rw-r--r--pstoraster/zrelbit.c342
-rw-r--r--pstoraster/zshade.c599
-rw-r--r--pstoraster/zstack.c295
-rw-r--r--pstoraster/zstring.c172
-rw-r--r--pstoraster/zsysvm.c164
-rw-r--r--pstoraster/ztoken.c241
-rw-r--r--pstoraster/ztrap.c72
-rw-r--r--pstoraster/ztype.c510
-rw-r--r--pstoraster/zupath.c673
-rw-r--r--pstoraster/zusparam.c655
-rw-r--r--pstoraster/zvmem.c404
-rw-r--r--pstoraster/zvmem2.c153
-rw-r--r--scheduler/.cvsignore3
-rw-r--r--scheduler/Makefile145
-rw-r--r--scheduler/auth.c1498
-rw-r--r--scheduler/auth.h136
-rw-r--r--scheduler/banners.c216
-rw-r--r--scheduler/banners.h57
-rw-r--r--scheduler/cert.c275
-rw-r--r--scheduler/cert.h60
-rw-r--r--scheduler/classes.c695
-rw-r--r--scheduler/classes.h43
-rw-r--r--scheduler/client.c2497
-rw-r--r--scheduler/client.h104
-rw-r--r--scheduler/conf.c1868
-rw-r--r--scheduler/conf.h169
-rw-r--r--scheduler/cups-lpd.c1287
-rw-r--r--scheduler/cups-polld.c327
-rw-r--r--scheduler/cups.pam2
-rw-r--r--scheduler/cupsd.dsp173
-rw-r--r--scheduler/cupsd.h176
-rw-r--r--scheduler/devices.c482
-rw-r--r--scheduler/dirsvc.c1729
-rw-r--r--scheduler/dirsvc.h132
-rw-r--r--scheduler/filter.c301
-rw-r--r--scheduler/ipp.c5643
-rw-r--r--scheduler/job.c2997
-rw-r--r--scheduler/job.h107
-rw-r--r--scheduler/listen.c222
-rw-r--r--scheduler/log.c440
-rw-r--r--scheduler/main.c802
-rw-r--r--scheduler/mime.c579
-rw-r--r--scheduler/mime.h139
-rw-r--r--scheduler/ppds.c897
-rw-r--r--scheduler/printers.c2054
-rw-r--r--scheduler/printers.h117
-rw-r--r--scheduler/quotas.c236
-rw-r--r--scheduler/server.c162
-rw-r--r--scheduler/testmime.c228
-rw-r--r--scheduler/testspeed.c126
-rw-r--r--scheduler/type.c1090
-rw-r--r--standards/draft-ietf-ipp-collection-04.txt2262
-rw-r--r--standards/draft-ietf-ipp-finishings-fold-trim-bale-00.txt585
-rw-r--r--standards/draft-ietf-ipp-implementers-guide-v11-02.txt5046
-rw-r--r--standards/draft-ietf-ipp-indp-method-04.txt1768
-rw-r--r--standards/draft-ietf-ipp-install-02.txt1426
-rw-r--r--standards/draft-ietf-ipp-job-printer-set-ops-03.txt3828
-rw-r--r--standards/draft-ietf-ipp-job-prog-02.txt986
-rw-r--r--standards/draft-ietf-ipp-ldap-printer-schema-04.txt1456
-rw-r--r--standards/draft-ietf-ipp-not-05.txt928
-rw-r--r--standards/draft-ietf-ipp-not-over-snmp-04.txt9
-rw-r--r--standards/draft-ietf-ipp-not-spec-06.txt4988
-rw-r--r--standards/draft-ietf-ipp-notify-get-02.txt1711
-rw-r--r--standards/draft-ietf-ipp-notify-mailto-03.txt1740
-rw-r--r--standards/draft-ietf-ipp-notify-poll-02.txt9
-rw-r--r--standards/draft-ietf-ipp-ops-admin-req-00.txt9
-rw-r--r--standards/draft-ietf-ipp-ops-set2-02.txt9
-rw-r--r--standards/draft-ietf-ipp-url-scheme-02.txt899
-rw-r--r--standards/rfc1179.txt787
-rw-r--r--standards/rfc1321.txt1179
-rw-r--r--standards/rfc2246.txt4483
-rw-r--r--standards/rfc2396.txt2243
-rw-r--r--standards/rfc2487.txt451
-rw-r--r--standards/rfc2565.txt2075
-rw-r--r--standards/rfc2566.txt9691
-rw-r--r--standards/rfc2567.txt2411
-rw-r--r--standards/rfc2568.txt563
-rw-r--r--standards/rfc2569.txt1571
-rw-r--r--standards/rfc2595.txt843
-rw-r--r--standards/rfc2616.txt9859
-rw-r--r--standards/rfc2617.txt1907
-rw-r--r--standards/rfc2639.txt3587
-rw-r--r--standards/rfc2712.txt395
-rw-r--r--standards/rfc2817.txt731
-rw-r--r--standards/rfc2818.txt395
-rw-r--r--standards/rfc2821.txt4427
-rw-r--r--standards/rfc2822.txt2859
-rw-r--r--standards/rfc2910.txt2579
-rw-r--r--standards/rfc2911.txt12547
-rw-r--r--systemv/.cvsignore10
-rw-r--r--systemv/Makefile190
-rw-r--r--systemv/accept.c316
-rw-r--r--systemv/cancel.c286
-rw-r--r--systemv/cupsaddsmb.c286
-rw-r--r--systemv/lp.c654
-rw-r--r--systemv/lpadmin.c1856
-rw-r--r--systemv/lpinfo.c457
-rw-r--r--systemv/lpmove.c232
-rw-r--r--systemv/lpoptions.c427
-rw-r--r--systemv/lppasswd.c405
-rw-r--r--systemv/lpstat.c1924
-rw-r--r--templates/Makefile103
-rw-r--r--templates/add-class.tmpl33
-rw-r--r--templates/add-printer.tmpl33
-rw-r--r--templates/admin-op.tmpl1
-rw-r--r--templates/admin.tmpl57
-rw-r--r--templates/choose-device.tmpl32
-rw-r--r--templates/choose-make.tmpl35
-rw-r--r--templates/choose-members.tmpl30
-rw-r--r--templates/choose-model.tmpl35
-rw-r--r--templates/choose-serial.tmpl56
-rw-r--r--templates/choose-uri.tmpl41
-rw-r--r--templates/class-added.tmpl2
-rw-r--r--templates/class-confirm.tmpl6
-rw-r--r--templates/class-deleted.tmpl1
-rw-r--r--templates/class-modified.tmpl2
-rw-r--r--templates/classes.tmpl51
-rw-r--r--templates/config-printer.tmpl6
-rw-r--r--templates/config-printer2.tmpl2
-rw-r--r--templates/error.tmpl3
-rw-r--r--templates/header.tmpl23
-rw-r--r--templates/job-cancel.tmpl1
-rw-r--r--templates/job-hold.tmpl1
-rw-r--r--templates/job-release.tmpl1
-rw-r--r--templates/job-restart.tmpl1
-rw-r--r--templates/jobs.tmpl54
-rw-r--r--templates/modify-class.tmpl34
-rw-r--r--templates/modify-printer.tmpl36
-rw-r--r--templates/option-boolean.tmpl7
-rw-r--r--templates/option-header.tmpl8
-rw-r--r--templates/option-pickmany.tmpl7
-rw-r--r--templates/option-pickone.tmpl7
-rw-r--r--templates/option-trailer.tmpl8
-rw-r--r--templates/printer-accept.tmpl1
-rw-r--r--templates/printer-added.tmpl2
-rw-r--r--templates/printer-configured.tmpl2
-rw-r--r--templates/printer-confirm.tmpl6
-rw-r--r--templates/printer-deleted.tmpl1
-rw-r--r--templates/printer-modified.tmpl2
-rw-r--r--templates/printer-reject.tmpl1
-rw-r--r--templates/printer-start.tmpl2
-rw-r--r--templates/printer-stop.tmpl2
-rw-r--r--templates/printers.tmpl57
-rw-r--r--templates/test-page.tmpl2
-rw-r--r--templates/trailer.tmpl7
-rw-r--r--test/.cvsignore1
-rw-r--r--test/4.1-requests.test140
-rw-r--r--test/4.2-cups-printer-ops.test214
-rw-r--r--test/4.3-job-ops.test297
-rwxr-xr-xtest/5.1-lpadmin.sh64
-rwxr-xr-xtest/5.2-lpc.sh40
-rwxr-xr-xtest/5.3-lpq.sh40
-rwxr-xr-xtest/5.4-lpstat.sh40
-rwxr-xr-xtest/5.5-lp.sh52
-rwxr-xr-xtest/5.6-lpr.sh52
-rwxr-xr-xtest/5.7-lprm.sh52
-rwxr-xr-xtest/5.8-cancel.sh52
-rwxr-xr-xtest/5.9-lpinfo.sh52
-rw-r--r--test/Makefile72
-rw-r--r--test/create-job-format.test56
-rw-r--r--test/create-job-sheets.test55
-rw-r--r--test/create-job-timeout.test55
-rw-r--r--test/create-job.test54
-rw-r--r--test/get-devices.test21
-rw-r--r--test/get-job-attributes.test27
-rw-r--r--test/get-job-attributes2.test28
-rw-r--r--test/get-ppds.test21
-rw-r--r--test/get-printer-attributes.test44
-rw-r--r--test/ipptest.c808
-rw-r--r--test/print-job-hold.test33
-rw-r--r--test/print-job.test32
-rwxr-xr-xtest/run-stp-tests.sh327
-rw-r--r--test/set-attrs-hold.test180
-rw-r--r--test/str-header.html35
-rw-r--r--test/str-trailer.html5
-rw-r--r--test/testfile.jpgbin0 -> 598930 bytes
-rw-r--r--test/testfile.pdfbin0 -> 36613 bytes
-rw-r--r--test/testfile.ps512
-rw-r--r--test/testfile.txt60
-rw-r--r--test/testhp.ppd195
-rw-r--r--test/testps.ppd192
-rw-r--r--visualc/config.h147
-rw-r--r--visualc/jpeg.dsp284
-rw-r--r--visualc/libpng.dsp149
-rw-r--r--visualc/zlib.dsp141
1268 files changed, 592167 insertions, 0 deletions
diff --git a/.cvsignore b/.cvsignore
new file mode 100644
index 000000000..be4550c6f
--- /dev/null
+++ b/.cvsignore
@@ -0,0 +1,9 @@
+config.cache
+config.h
+config.log
+config.status
+configure
+cups-config
+cups.list
+cups.sh
+Makedefs
diff --git a/CHANGES.txt b/CHANGES.txt
new file mode 100644
index 000000000..543a74914
--- /dev/null
+++ b/CHANGES.txt
@@ -0,0 +1,2014 @@
+CHANGES.txt - 01/31/2002
+------------------------
+
+CHANGES IN CUPS V1.1.13
+
+ - The lpstat command did not report jobs submitted to
+ regular printer classes.
+ - The texttops filter didn't use sufficient precision
+ when positioning text with some values of cpi and lpi.
+ This could cause the alignment of text to stray.
+ - cupsGetDests() didn't merge the options from the
+ /etc/cups/lpoptions file with ~/.lpoptions - options
+ in ~/.lpoptions overrode them completely.
+ - Added support for KOI8-R and KOI8-U character sets,
+ and added several Russian message catalogs.
+ - The scheduler put the wrong timezone offset in the log
+ files (e.g. +0500 instead of -0500 for EST...)
+ - The scheduler did not ignore trailing whitespace in
+ *.convs files.
+ - The scheduler now forces all processes to exit (kill
+ -9) when it is stopped. This prevents parallel and
+ USB devices from running in the background after cupsd
+ goes away.
+ - The cupsParseOptions() function didn't skip trailing
+ whitespace after quoted values.
+ - More changes to support CUPS on OS/2.
+ - Added Simplified Chinese message catalog.
+ - Added PAM support for IRIX.
+ - The cupsGetPPD() function didn't remove the @server
+ portion of the printer name, and since it would
+ connect immediately to the remote server instead of
+ the local server, the printer would not be found.
+ - Classification and page labels were not rotated to
+ match the page orientation.
+ - Now set the TCP "no delay" option on network
+ connections to improve performance/response time.
+ - Improved the IRIX printing tools support with patches
+ from Andrea Suatoni.
+ - Added a new PrintcapGUI directive to specify the GUI
+ option panel program to use for the IRIX printing
+ tools support.
+ - The cupsGetDests() function did not check to see if a
+ user-defined default printer (set via lpoptions) still
+ existed.
+ - The pstops filter no longer assumes that the default
+ dictionary is writable when doing N-up processing.
+ - The pstops filter now supports printing N-up with the
+ page-set option.
+ - The imagetoraster filter now supports direct printing
+ of CMYK image data without conversion/correction.
+ - The IPP backend now reports printer state/error
+ conditions when possible (toner low, media empty,
+ etc.)
+ - The lpstat command now supports the (undocumented)
+ IRIX -l option ("-lprintername") for a compact job
+ listing for a printer.
+ - The lpstat command now includes printer date/time
+ information in the output (always Jan 01 00:00) to
+ make third-party tools happy.
+ - The text filter now supports non-integer cpi and lpi
+ values.
+ - The Margins field in the CUPS raster header was not
+ initialized by the pstoraster filter.
+ - Added --with-optim="flags" option to configure script.
+ - Updated the Italian message translations.
+ - Updated the cups.list file to install the correct
+ files.
+ - The pstoraster filter accessed the third element of a
+ 2 element array.
+ - The scheduler did not setup a status pipe for polling
+ processes, so error messages went to whatever file
+ descriptor 2 was pointing to when they were started.
+ - The httpMD5Final() function didn't put a colon between
+ the password and nonce strings.
+ - The pstops filter did not default to Binary data for
+ "%%BeginData:".
+ - The pstops filter did not stop processing when a line
+ containing a CTRL-D is seen.
+ - The scheduler no longer replaces the JobSheets values
+ from the printers.conf and classes.conf files with the
+ classification level, if set. This way the original
+ banner settings are preserved when classification
+ levels are changed or turned off.
+ - The serial backend didn't drain the output queue, nor
+ did it restore the original settings.
+ - Updated the default system group under MacOS X.
+ - If no SystemGroup was defined in cupsd.conf, the
+ system default group was not used.
+ - The cups-lpd mini-daemon now supports LPD clients that
+ send multiple control files.
+ - httpConnectEncrypt() now always uses encryption for
+ connections on port 443, since port 443 is reserved
+ for the "https" scheme.
+ - Group authentication via certificates did not work
+ from the web interface for accounts other than
+ "root".
+ - The serial port backend did not clear the OPOST
+ option, which could cause problems with some printers.
+ - The cups-lpd mini-daemon didn't lookup the client IP
+ address properly.
+ - The parallel backend now identifies the polled and
+ interrupt-driven devices under *BSD.
+ - The scheduler allowed the "always" encryption mode
+ inside a Location, which is not valid.
+ - The CUPS startup script now checks for the timezone
+ information under Linux.
+ - Now also map the sides attribute to the JCLDuplex
+ option (if present) in PPD files.
+ - Updated pdftops to Xpdf 0.93a.
+ - Added support for MD5 passwords under Slackware.
+ - Added new AuthType BasicDigest that does Basic
+ authentication using the MD5 password file managed by
+ the lppasswd command.
+ - The banner page attribute substitution code now
+ retains {name} sequences in banner files when the
+ named attribute is undefined. Use {?name} to
+ conditionally substitute an IPP attribute.
+ - The scheduler now ensures that the ServerRoot
+ directory and configuration files are owned by and
+ writable by the User and Group in cupsd.conf.
+ - The USB backend now lists all USB printer devices
+ regardless of whether a printer is connected or not.
+ This allows new USB printers to be connected without
+ restarting cupsd.
+ - Added some more minor performance tweeks to the IPP
+ protocol code to reduce copying and array indexing.
+ - The cupsaddsmb utility now uses the -c option with
+ smbclient and rpcclient to avoid the read length limit
+ for commands on the standard input.
+ - Added an include file to the CRD handling code in
+ pstoraster so that it would compile properly on 64-bit
+ pointer platforms...
+ - The cups-config script reported the wrong version
+ number.
+ - The cups-config script was installed in $(bindir)
+ instead of $(BINDIR).
+ - The init script did not correctly check for a running
+ cupsd under IRIX 5.x.
+
+
+CHANGES IN CUPS V1.1.12
+
+ - Added "Polish" to the list of known languages for PPD
+ files.
+ - Added missing directory definition to cups-config.
+ - The CUPS-Move-Job operation did not set the
+ destination type for the new destination.
+ - The CUPS-Add-Printer operation did not support the
+ allow=all or deny=none values to clear the per-user
+ printer ACLs.
+ - The SetPrinterAttrs() function did not handle invalid
+ PPD files that were missing the required NickName
+ attribute. It now looks for NickName, ModelName, and
+ then substitutes the string "Bad PPD File" for the
+ printer-make-and-model attribute.
+
+
+CHANGES IN CUPS V1.1.11
+
+ - Added support for embedded TrueType fonts in PDF
+ files.
+ - Added support for PostScript functions in PDF
+ files.
+ - Added new "cupsaddsmb" utility for exporting
+ CUPS printer drivers to SAMBA/Windows clients.
+ - Added preliminary support for Darwin/MacOS X.
+ - The CUPS-Add-Printer operation no longer allows
+ arbitrary scheme names in device URIs to be used - it
+ now restricts the available schemes to those found in
+ the device list (lpinfo -m).
+ - The ippRead() and ipp_read_file() functions could not
+ handle more than IPP_MAX_VALUES (100) values in a
+ 1setOf attribute. These functions have been updated
+ to dynamically allocate more memory as needed, and the
+ IPP_MAX_VALUES constant now represents the allocation
+ increment. [this caused some versions of the
+ GIMP-print drivers to fail since the number of media
+ options exceeded 100...]
+ - The scheduler could crash when BrowseShortNames
+ was set to "No".
+ - The scheduler did not prevent MaxClients from being
+ set to 0, which could cause the scheduler to go in an
+ infinite loop when accepting a request.
+ - Made some performance optimizations in the ippRead()
+ functions to make IPP request/response processing
+ faster.
+ - The accept/reject/enable/disable command did not
+ support properly support the "-h" or default
+ server name.
+ - The scheduler did not save the quota configuration
+ when the job-quota-period attribute was set to 0.
+ - The LPDEST and PRINTER environment variables did not
+ support printer instances.
+ - The text filter now handles more types of boldface and
+ underline formatting.
+ - The cupsTempFd() function did not fail if the
+ temporary directory did not exist; this would cause it
+ to loop indefinitely instead of returning an error
+ (-1).
+ - Stopping (disabling) a printer class did not stop jobs
+ from printing to printers in that class.
+ - The cupsGetDests() function was sending the
+ requested-attributes attribute as a name instead of a
+ keyword; this caused a serious performance problem on
+ slower systems since more information had to be
+ transferred from server to client.
+ - The web interfaces did not always quote < and & in
+ things like the job title. This had the potential for
+ browser-based security violations (on the browser's
+ machine); bug report from SuSE.
+ - The scheduler now treats unauthenticated usernames as
+ case-insensitive when doing quota and allow/deny
+ processing.
+ - The lp command sent the "request ID is ..." message
+ to stderr instead of stdout...
+ - The PostScript filter (pstops) now handles EPS files,
+ adding a showpage command to the files as needed.
+ - The configure script checked for the <stdlib.h> header
+ file before the JPEG libraries; since the JPEG headers
+ can define HAVE_STDLIB_H, the configure check would
+ cause the JPEG check to fail on some systems.
+ - The scheduler now supports localized banner files,
+ using the subdirectory approach, e.g. the "es"
+ subdirectory under /usr/share/cups/banners is used for
+ the Spanish banner files.
+ - Updated the scheduler so it knows the correct
+ language abbreviation to use for all supported
+ PPD LanguageVersion values. The new code also
+ supports country codes as well, so "English-GB"
+ maps to the "en_GB" locale.
+ - The cups-lpd mini-daemon did not support
+ anonymous printing (no username specified).
+ While the username is REQUIRED by RFC-1179,
+ MacOS clients do not send the REQUIRED username
+ information when printing via LPD.
+ - Added many warning and informational messages
+ to cups-lpd where they were missing.
+ - Added Czech message file contributed by SuSE.
+ - The cups-lpd mini-daemon now returns a non-zero
+ status if an invalid destination or job ID is
+ provided.
+ - The scheduler did not honor the KeepAlive setting in
+ cupsd.conf.
+ - Increased the size of the file read/write buffers to
+ 32k.
+ - *BSD static library creation fixes.
+ - Use mkstemps() instead of tmpnam() in pdftops whenever
+ possible.
+ - Added httpGetHostByName() function as a wrapper around
+ gethostbyname() - some implementations of this
+ function do not support IP addresses (e.g. MacOS X.)
+ - Added casts to all printf's of file lengths, since
+ there is currently no standard way of formatting long
+ long values.
+ - The client filename field was not cleared in all
+ instances, resulting in old form data being submitted
+ to CGIs.
+ - The httpConnect*() functions now try all available
+ addresses for a host when connecting for the first
+ time.
+ - The pstoraster filter would "lose" all drawing
+ commands when the PageSize was set but the printer
+ bitmap was not reallocated. This was most noticeable
+ with the output from StarOffice 6 beta and would
+ result in a blank page being output...
+ - The IPP backend was sending a PAGE comment even when
+ printing the output from a filter (it should only send
+ page comments when printing files directly...)
+ - The pdftops filter didn't properly map glyph names of
+ embedded Asian TrueType fonts.
+ - Changed the CUPS startup script to look for a program
+ named "cupsd", not just any program with "cupsd" in
+ the name (this caused the apcupsd UPS monitoring
+ daemon to be stopped/restarted...)
+ - The CUPS-Move-Job operation did not change the
+ internal destination name for held jobs, so moved (but
+ held) jobs would still show up as queued on the
+ original destination.
+ - The cups-polld program didn't send the
+ requested-attributes attribute in the
+ CUPS-Get-Printers and CUPS-Get-Classes requests, which
+ made it use more CPU and bandwidth than required.
+ - The scheduler and CUPS API incorrectly added a
+ job-sheets-default attribute for remote printers. This
+ caused banner pages to be omitted from client system
+ prints.
+
+
+CHANGES IN CUPS V1.1.10-1
+
+ - Minor fixes to the filter, systemv, and template
+ makefiles to install files properly.
+
+
+CHANGES IN CUPS V1.1.10
+
+ - Added a driver for DYMO label printers.
+ - Added new ClassifyOverride directive to allow users
+ to override the classification of individual jobs.
+ - Added new BrowseProtocols directive to control which
+ browse protocols are used (currently CUPS and SLP).
+ - Added SLPv2 support (thanks to Matt Peterson for
+ contributing the initial implementation for CUPS.)
+ - Adding a raw printer on a remote CUPS server now
+ correctly redirects PPD file requests to the remote
+ server.
+ - The serial backend now limits writes to 1/10th
+ second worth of data to avoid buffer overflows
+ with some types of flow control.
+ - The scheduler did not properly process PUT requests,
+ so configuration files could not be uploaded to the
+ server.
+ - The scheduler did not strip trailing whitespace on
+ lines in the configuration files.
+ - The httpWrite() function did not transition the PUT
+ request to the HTTP_STATUS state to get the status
+ from the server.
+ - The scheduler did not properly handle trailing null
+ ("-") filters when testing a driver that sent data
+ to the file: pseudo-backend.
+ - The IPP backend now only sends a document-format of
+ "application/vnd.cups-raw" when printing to another
+ CUPS server using a local printer driver or interface
+ script. Previously the job's document format was
+ used, which was incorrect.
+ - The lpadmin command didn't use the ppd-name attribute
+ with the -m option; this prevented the use of the
+ "raw" model from the command-line.
+ - The pstoraster filter output draft (1-bit) 6-color
+ output in the wrong order; this resulted in yellow
+ being printed instead of black on Stylus Photo
+ printers.
+ - The pdftops filter did not have the Japanese and
+ Chinese text support compiled into it.
+ - The IPP and AppSocket backends did not clear the
+ "waiting for print job to complete" status message,
+ which caused some confusion... :)
+ - The serial backend now opens the port in "no delay"
+ mode to avoid DCD detection problems with some OS's.
+
+
+CHANGES IN CUPS V1.1.9-1
+
+ - The configure script did not substitute the
+ correct user and group names.
+ - The configure script did not use the full path
+ to the install-sh script when it was used.
+ - The pstoraster filter did not correctly support
+ DuplexTumble mode for printers that used flip
+ duplexing.
+ - The cups.list.in file was missing from the
+ distribution.
+ - The New DeskJet series driver did not use the
+ correct OrderDependency for the Duplex option.
+ - Use read() instead of fread() to read piped
+ print files in lpr/lp. This avoids a bug in the
+ HP-UX 10.20 fread() function.
+ - Updated the pstoraster filter to use the MIPS_FIXADE
+ system call under IRIX to fix bus error problems on
+ R12000 processors (Ghostscript is not 64-bit clean...)
+ - Some Xerox PPD files (most notably the Phaser 790)
+ have illegal whitespace in the option keyword in the
+ OpenUI line. This caused the PageRegion option to not
+ be recognized properly for the Phaser 790.
+
+
+CHANGES IN CUPS V1.1.9
+
+ - Revamped the configure script to use a modular
+ approach for the various tests.
+ - Added --with-openssl-* options to properly reference
+ the OpenSSL libraries in DSOs.
+ - Added --with-cups-user and --with-cups-group
+ options to specify the default user and group for
+ CUPS.
+ - Added AIX shared library support.
+ - Added AIX device discovery for the serial and
+ parallel ports.
+ - Now use install program or script to install
+ directories, files, and symlinks.
+ - Updated pstops filter to use strict handling of EPS
+ files embedded in a PostScript document. The %%EOF
+ handling in 1.1.8 caused some dvips files not to
+ print.
+ - Fixed yet another memory allocation bug in pstoraster
+ that would cause it to crash. This fix also ensures
+ that all memory allocations are done on (at least) a
+ 64-bit boundary.
+ - Fixed Digest authentication - httpGetSubField() didn't
+ skip the Digest keyword.
+ - The scheduler did not properly handle Digest
+ authentication with the new multiple-group support.
+ - The scheduler did not allow usernames that were
+ not in the UNIX password file to be used for Digest
+ authentication from passwd.md5.
+ - The scheduler could not scan PPD files that only used
+ a carriage return (i.e. MacOS PPD files); the new code
+ is also about 40% faster, so servers with thousands of
+ PPD files should start much faster now.
+ - The scheduler now stores the PPD file size and
+ modification times in the ppds.dat file, so it can now
+ incrementally update the PPD database from the model
+ directory, resulting in significantly faster startup
+ times.
+ - The lpinfo command did not return a non-zero status
+ code if an error occurred.
+ - Fixed a bug in the scheduler's UpdateJob() function.
+ Basically, all jobs shared the same status buffer, and
+ the "buffer start" pointer could point to 1 byte
+ before the beginning of the buffer. The new
+ implementation uses a separate buffer for each job and
+ eliminates the buffer start bug.
+ - The IPP backend would send N copies of a document if
+ the receiving device didn't support the copies
+ attribute, even if the upstream driver already added
+ the necessary commands to generate the copies. This
+ was most noticeable with HP printers where N * N
+ copies would come out instead of N.
+ - The PostScript filter (pstops) did not properly handle
+ duplex printing on inkjet printers that provide this
+ option. Copies would be put on the front and back
+ sides of the duplexed page, and the filter did not
+ output an even number of pages.
+ - The backends always caught SIGTERM after they
+ connected to the printer. This prevented raw jobs
+ from being cancelled early.
+ - The cupsSetDests() function now removes any printers,
+ instances, and options that are not defined by the
+ user or server. This should prevent old system-wide
+ options from being used in individual user accounts.
+ - Updated the EPSON printer driver and added PPDs for
+ the newer EPSON Stylus printers that only support the
+ "ESC i" graphics command.
+ - The lpadmin command didn't allow you to add remote
+ printers to a local class.
+ - The lpadmin command didn't allow you to set the
+ options (quotas, etc.) for a class.
+ - The scheduler did not load or save the
+ job-sheets-default attribute for classes.
+ - The scheduler did not automatically recreate remote
+ printers that were part of a class.
+ - It was possible for a printer class to list the same
+ printer more than once.
+ - The scheduler now makes a backup copy of classes.conf
+ and printers.conf before writing the new file.
+ - The lppasswd program incorrectly asked for a new
+ password when deleting an existing MD5 password
+ account.
+ - The scheduler did not match "/printers/name.ppd"
+ against a location of "/printers/name".
+ - The client code did not always handle HTTP encryption
+ upgrades properly.
+ - The client code now caches the last Digest password so
+ it can retry using a new resource path or nonce value,
+ which are included in the MD5 sum sent to the server.
+ This should eliminate unnecessary password prompts
+ when using Digest authentication.
+ - The lppasswd command didn't have a man page.
+ - Updated the PJL detection rules to allow the universal
+ escape to occur anywhere in the first 128 bytes of the
+ file.
+ - The cups-polld program would poll servers continuously
+ with no delay if there was an error contacting the
+ server.
+ - The IPP backend would send an empty job-name or
+ requesting-user-name attribute if the corresponding
+ job attribute was an empty string. While this is
+ allowed by the IPP specification, some HP JetDirect
+ implementations return a client-error-bad-request
+ error if an empty name attribute value is received.
+ The new code only sends these attributes if they are
+ not the empty string.
+ - At least some versions of the HP JetDirect firmware
+ do not correctly implement IPP. Added additional
+ checks to the IPP backend to eliminate extra,
+ unsupported attributes which should normally be
+ ignored by a compliant IPP device.
+ - The scheduler did not copy the complete list of
+ supported file types into the
+ document-format-supported attribute. This caused
+ clients to not send the local file type (such as
+ application/vnd.cups-raw for raw print files) and the
+ corresponding bad output in some cases.
+ - The scheduler did not fully copy attributes from a
+ set-job-attributes request - string attributes were
+ only referenced, which could cause cupsd to crash
+ or behave irratically.
+ - The lp command didn't send the right value for the
+ job-hold-until attribute when "-H resume" was
+ specified.
+ - The IPP backend now returns as soon as a job is
+ completed or reported as "pending-held".
+ - Added new ImplicitAnyClasses and HideImplicitMembers
+ directives to the cupsd.conf file to make implicit
+ classes more usable/transparent to the user.
+ - Clients can now (with the appropriate authentication)
+ retrieve and update the server configuration files
+ using HTTP GET and PUT requests.
+ - The web interface didn't allow you to modify the
+ location or description of the printer.
+ - The pdftops filter now uses its own temporary file
+ function to work with PDF files using LZW compression
+ (which use the uncompress program or gunzip)
+ - The SystemGroup directive now supports specification of
+ multiple groups.
+ - Added new Include directive to cupsd.conf, a la
+ Apache.
+ - Added new pseudo-driver/PPD called "raw" that can be
+ used to create/convert a raw queue. This also allows
+ raw queues to be created in the web interface.
+ - The pdftops filter didn't handle image objects that
+ used JPEG and Flate compression together.
+ - The pstops filter counted pages wrong when using the
+ N-up and even/odd printing options. This prevented
+ the page-ranges option from working properly.
+ - Added another fix to pstoraster for a bus error
+ condition caused by a lack of parenthesis in the
+ Ghostscript code.
+ - Added new "natural-scaling" option which scales the
+ natural size of the image (percent of natural image
+ size instead of percent of page size.)
+ - The lppasswd program is now setuid to the CUPS user
+ instead of root.
+ - The PPD functions did not allow for PPD files that
+ defined the page sizes and margins before the page
+ size options.
+ - The mime.types file now checks for the PJL "LANGUAGE =
+ Postscript" command for PostScript files.
+ - The scheduler did not truncate file: output files.
+ - The PPD file reading code did not handle options with
+ raw quotes (") in the human-readable names.
+ - The pdftops filter now remaps the space character when
+ (bad) PDF files contain a .notdef glyph for the space
+ character.
+
+
+CHANGES IN CUPS V1.1.8
+
+ - Updated configure script to check for /etc/pam.d and
+ to only set PAMDIR if it exists.
+ - Updated spec file to generate separate cups-pstoraster
+ package for pstoraster.
+ - The spec file wasn't setting LOGDIR in the install.
+ - The scheduler might restart a stopped printer after
+ stopping a print job. Thanks to Florent
+ Guiliani for finding this bug!
+ - The init script showed run level 0 for the Red Hat
+ chkconfig program. This is incorrect because Red Hat
+ doesn't use run level 0 for shutdown scripts.
+ - The IPP backend did not handle the
+ client-error-not-found error when checking the status
+ of the job that was sent. This caused remote queues
+ to stop on client machines when the server had job
+ history disabled.
+ - Added httpConnectEncrypt() function to avoid
+ performance penalty for setting up encrypted
+ connections initially.
+ - Use httpConnectEncrypt() in all client apps and in the
+ CUPS API to ensure consistent usage of encryption
+ throughout.
+ - Jobs weren't queued to remote classes (fix from
+ Richard Begg.)
+ - AIX changes from Richard Begg.
+ - Fixed the pstops fix for GNOME output - no longer use
+ the page numbers in the %%Page: comment since GNOME
+ puts a filename instead (!?@!#?!). There is still an
+ issue with N-up printing since GNOME defines its fonts
+ in the first page instead of the document setup section
+ (pages must be independent according to the DSC spec)
+ People with GNOME printing problems should consult bug
+ #54489...
+ - The imagetops filter produced PAGE: messages when
+ generating PostScript for a non-PostScript printer
+ (only affects page-label and Classification
+ options.)
+ - The updated pdftops filter was looking for an options
+ file called xpdf.conf instead of pdftops.conf.
+ - The scheduler would not force the default job sheets
+ for printers to the current classification setting.
+ - Added a new ippFindNextAttribute() function to the
+ CUPS API.
+ - ppdEmitJCL() now strips any leading path info from
+ the title string. This is only an issue for non-CUPS
+ clients that don't do this already...
+ - Other pstops fixed from Helge Blischke for printing
+ non-conforming documents.
+ - The MaxJobs parameter was not reset when loading the
+ cupsd.conf file.
+
+
+CHANGES IN CUPS V1.1.7
+
+ - Configuration script changes, including new
+ "--with-docdir=/dir" option to relocate CUPS
+ documentation and web content according to your
+ favorite version of the FHS.
+ - Documentation updates for encryption, SLP, etc.
+ - New Software Test Plan and automated test script to
+ test CUPS prior to installation.
+ - All scheduler configuration files are now case
+ insensitive to match Apache.
+ - Added support for Apache ListenBackLog, LogFormat,
+ Require, UseCanonicalName, Satisfy, <Limit>,
+ <LimitExcept>, LimitRequestSize, and Options
+ directives.
+ - Added support for all Apache log levels...
+ - Added support for "double" HostNameLookups.
+ - Added new "RunAsUser" directive to support non-root
+ configurations on the standard (priviledged) ports.
+ - Added support for non-root invocation of the lpd
+ backend (does no reserve a priviledged port, which
+ might not work with some LPD servers...)
+ - Added new PrintcapFormat directive to control the
+ output format of the printcap file (BSD or Solaris
+ formats are supported at present.)
+ - The CUPS directory service routines now handle
+ ECONNREFUSED errors gracefully rather than shutting
+ all browsing off.
+ - ippErrorString() now returns the recommended error
+ messages from the IPP/1.1 Model and Semantics
+ document.
+ - Fixed a minor IPP compliance issue with responses
+ to requests without the attributes-charset or
+ attributes-natural-language attributes.
+ - Sun fix: need httpFlush() call for chunked IPP
+ requests in cupsDoFileRequest().
+ - httpConnect() now looks up "localhost" by name and
+ by address (127.0.0.1) for users the go to the
+ trouble of removing the required localhost entry
+ in /etc/hosts or on their DNS server...
+ - Added support for Linux 2.4.x devfs parallel port
+ filenames (/dev/parallel/N).
+ - cupsDo[File]Request() and cupsGetPPD() no longer
+ block trying to reconnect to a crashed or inaccessable
+ server.
+ - Added new ppdEmitJCL() function to better handle
+ PJL commands from PPD files.
+ - A bug in UpdateJob() would cause the scheduler to
+ consume 100% CPU until another request was submitted.
+ - The cancel command did not support the "-" option to
+ cancel all jobs on all printers.
+ - The cancel and lprm commands did not support cancelling
+ the next/current job in the queue.
+ - The pdftops and pstoraster filters were using unsafe
+ temporary file functions; while this is not a problem
+ in normal configurations (the CUPS temporary directory
+ is restricted), they now use the cupsTempFd() function.
+ - The mime.types file was missing the recognition rule
+ for Sun Raster images.
+ - The admin CGI was passing a printer make string to
+ ippSetCGIVars() that was being replaced in that
+ function.
+ - "lpoptions -l" would resave the options...
+ - The EPSON drivers now send the "end packet mode"
+ command when printing to USB devices.
+ - The scheduler initialized certificates before loading
+ the cupsd.conf file.
+ - The scheduler used /dev/random to collect random data,
+ which could block if insufficient entropy information
+ had been collected by the kernel. Now use
+ /dev/urandom.
+ - Fixed a bug in the whitespace skipping code in
+ httpGetSubField().
+ - The LPD backend now supports a new "order" option:
+ "lpd://server/queue?order=control,data" (default) and
+ "lpd://server/queue?order=data,control".
+ - The scheduler enforced a 30 second timeout on all
+ clients regardless of the Timeout directive and if a
+ CGI was currently running.
+ - cupsParseOptions() now sets boolean options to
+ option=true or option=false.
+ - The "percent complete" calculations in the LPD backend
+ could overflow on large files, causing the percentage
+ to wrap to 0 every 40MB or so.
+ - Fixed a memory reallocation bug in pstoraster that
+ could cause it to crash.
+ - The LPD backend now sanitizes the job title to avoid
+ potential problems on remote LPD servers.
+ - The lp command did not send the requesting-user-name
+ attribute when altering a job.
+ - The pstops filter did not handle PostScript files with
+ lines longer than 8191 bytes.
+ - The scheduler no longer uses inet_addr() to convert IP
+ addresses in dot format (mmm.nnn.ooo.ppp) to the
+ 32-bit format, since it will not work for IPv6
+ addresses.
+ - New "Classification" directive to force labeling of
+ the current classification on each page.
+ - New "page-label" attribute to add per-page labels
+ ("For Official Use Only", "Draft", etc.)
+ - The scheduler now sets the HTTPS environment variable
+ for CGI programs when a client connects using
+ encryption.
+ - Fixed a recursion bug in the scheduler that could
+ cause cupsd to crash when a printer was removed.
+ - The LPDEST and PRINTER environment variables didn't
+ support instances.
+ - Dropped the "file" backend from the device list that
+ is reported, since it is only available for *testing*
+ and should never be used in a production environment.
+ The file: device can still be used, but it won't show
+ up in the list of devices from lpinfo or the web
+ interface.
+ - Added support for /dev/lpa# parallel ports under *BSD.
+ - Added META variables to the CGI header template to
+ prevent caching of the results.
+ - Fixed an unaligned memory buffer for the pstoraster
+ clist states; this caused bus errors for some
+ combinations of printers, drivers, and options.
+ - Re-added black reduction for colorful colors; this
+ helps to prevent dark colors from getting desaturated.
+ (only used when converting RGB to CMYK)
+ - Added two new directives - MaxJobsPerPrinter and
+ MaxJobsPerUser - to allow an administrator to set
+ the maximum number of pending jobs in a queue or
+ submitted by a user.
+ - The scheduler no longer stops a printer if it can't
+ create the status pipe or run the filters or backend.
+ This will allow heavily loaded servers to service
+ clients or start print jobs as the load allows.
+ - Fixed a bug in the Set-Job-Attributes code that could
+ crash the scheduler (patch from Martin Zielinski)
+ - cupsSetDests() did not quote option values with
+ embedded spaces.
+ - Added support for the Enable-Printer and
+ Disable-Printer extension operations (same as
+ CUPS-Accept-Jobs and CUPS-Reject-Jobs.)
+ - The AppSocket and IPP backends now wait for the print
+ job to be finished before exiting; this should prevent
+ the loss of print jobs with older JetDirect firmware
+ and make consecutive print jobs print faster.
+ - The BMP loading code did not handle resolution values
+ of 0. This is a problem with BMP image files produced
+ by the GIMP.
+ - The HTTP Upgrade code (upgrade to TLS encryption)
+ bypassed the authentication checks.
+ - The HTTP Upgrade code did not send a 426 status code
+ to the client and end the current request. This caused
+ a race condition between the client and server for the
+ upgrade to TLS.
+ - Fixed a bug in the EOF and Trailer detection code in
+ the pstops filter.
+ - The imagetoraster filter did not add the margins to
+ the custom page size in the raster header.
+ - The imagetops filter did not adjust the custom page
+ size to the size of the printed image.
+ - The imagetops filter did not include DSC comments
+ which are required by some printers.
+ - The imagetops filter did not insert newlines in
+ Base85 encoded output, causing files to contain
+ lines longer than 255 characters (violation of the
+ DSC).
+ - Added support for the DeskJet 900 series duplexer
+ and CRET color modes in the HP driver.
+ - Added support for PPD-defined margins in the HP
+ driver.
+ - Fixed the debugging output from pstoraster - the
+ font list was not terminated by a newline.
+ - Some versions of the HP-UX pam_unix authentication
+ module apparently do not pass the appdata_ptr argument
+ to the conversation function, preventing the scheduler
+ from authenticating users using PAM under HP-UX. A
+ workaround using a static variable has been added to
+ address this problem.
+ - Fixed a bug in the scheduler SortPrinters() function
+ that could cause printers to disappear or the
+ scheduler to crash when adding a printer.
+ - Changed the pstops filter to not do per-page filtering
+ if the file does not conform to at least version 3.0
+ of the document structuring conventions. This seems
+ to "fix" printing with broken apps.
+ - The image filters did not handle older TIFF files that
+ lacked the samples-per-pixel and bits-per-pixel tags.
+ - Added new cupsGetJobs() and cupsFreeJobs() functions
+ to manage print jobs.
+ - cupsEncodeOptions() would encode names of 0 length and
+ cupsAddOption() and cupsParseOptions() would add names
+ of 0 length.
+ - The scheduler might block waiting for status messages
+ after starting a new print job. Thanks to Florent
+ Guiliani for finding this bug!
+
+
+CHANGES IN CUPS V1.1.6-3
+
+ - The configure script put the JPEG library before the
+ TIFF library; this caused problems in some
+ configurations since the TIFF library also supports
+ JPEG compression of TIFF images.
+ - Updated the configure script and makefiles to handle
+ admin man pages with the "1m" extension (HP-UX, IRIX,
+ Solaris, Tru64) and in odd directories (IRIX)
+ - The updated cupsTempFile() function did not return
+ the filename when called with a filename buffer of
+ NULL (previously it used a static buffer.)
+ - FreeBSD uses /dev/unlptN, but NetBSD and OpenBSD use
+ /dev/ulptN.
+ - DeletePrinter() didn't remove the printer from any
+ classes it was a member of.
+ - DeletePrinterFromClass() didn't preserve the
+ implicit status of a class.
+ - DeletePrinterFromClasses() didn't remove printers
+ from implicit classes.
+ - StartJob() didn't send the job-sheets, job-priority,
+ and job-hold-until attributes to remote printers.
+ - LoadAllJobs() was looking for job-sheets-completed
+ instead of job-media-sheets-completed. This would
+ prevent accumulation of page data after a restart
+ of the scheduler.
+ - The pstops and imagetops filters now generate copies
+ using the appropriate method for a Level 1, 2, or 3
+ printer since some Level 2/3 printers don't support
+ the /#copies variable anymore.
+ - The man page for cups-lpd did not mention the "-o"
+ option.
+ - The IPP backend didn't handle version-not-supported
+ errors and revert to IPP/1.0 (previously it only checked
+ for a bad-request error)
+ - Caldera fix: lpc now reports unimplemented commands as
+ unimplemented, not invalid.
+ - Caldera fix: lpq didn't recognize BSD lpq "-a" option.
+ - Caldera fix: lpr didn't recognize BSD lpr "-1", "-2",
+ "-3", "-4", "-q", or "-U" options.
+ - RedHat fixes: patches to GNU Ghostscript
+ - SuSE fix: temp file creation patch to GNU Ghostscript
+ (pstoraster).
+ - SuSE fix: remove cgi-bin/abort.c and cgi-bin/email.c,
+ which are not used.
+ - SuSE fix: missing NULL check in cgi_initialize_post().
+ - SuSE fix: potential buffer overflows in
+ cgi_initialize_string().
+ - SuSE fix: potential buffer overflows in
+ ippSetCGIVars()
+ - SuSE fix: more NULL checks in ppdOpen(); also make
+ sure that all memory is freed on error to avoid memory
+ leaks.
+ - SuSE fix: Exit from child if setgid() or setuid()
+ fails.
+ - SuSE fix: Added setgroups() calls after setgid() and
+ setuid() calls.
+ - SuSE fix: potential buffer overflows in httpEncode64()
+ calls.
+ - SuSE fix: potential buffer overflows in httpSeparate()
+ - SuSE fix: potential buffer overflows in ippWrite() for
+ bad input.
+ - SuSE fix: potential nul skip in ppd_decode() for
+ missing hex digits.
+
+
+CHANGES IN CUPS V1.1.6-2
+
+ - Added changes to support NetBSD startup scripts.
+ - Added separate compiler options for pstoraster
+ (Ghostscript) to avoid compiler-induced errors
+ from Ghostscript's twisted code.
+ - The mime.types file contained syntax errors.
+ - Updated the *BSD USB device filenames to use
+ the /dev/unlptN files so that the USB device
+ is not reset prior to printing (causes print
+ corruption on many printers)
+ - Added new cupsTempFd() function to avoid serious
+ security bug in glibc fopen() function. The glibc
+ fopen() function unlinks a file before creating it,
+ which opens up possible symlink attacks.
+ - Now reject 0-length names in add-printer and add-class
+ requests.
+ - Fix for pstoraster when ZLIB is not available.
+ - cupsGetPPD() didn't reconnect when a HTTP connection
+ was lost.
+ - SuSE fix: httpConnect() didn't check that the
+ value from gethostbyname() was a valid IPv4 address.
+ - SuSE fix: httpConnect() didn't allow file descriptor 0
+ to be used for a socket.
+ - SuSE fix: ippRead() didn't confirm that all values in
+ a set were numeric or string types.
+ - SuSE fix: lppasswd race condition fixes.
+ - SuSE fix: directive names could overflow buffer when
+ reading *.conf files.
+ - SuSE fix: HEAD requests for PPD files did not use the
+ same logic as GET requests.
+ - SuSE fix: possible buffer overflow when adding
+ /index.html to requested directory name.
+ - SuSE fix: possible buffer overflow when converting
+ IPP attributes to string options for filters.
+ - SuSE fix: creating file: device output with mode 0666
+ instead of mode 0600.
+ - SuSE fix: creating job info files with mode 0640
+ instead of 0600.
+ - SuSE fix: don't rely on snprintf() for including
+ system name in log filenames.
+ - SuSE fix: add bounds checking when copying quoted
+ and hex strings.
+
+
+CHANGES IN CUPS V1.1.6-1
+
+ - Added configure check for getting the correct
+ strftime() format string; %c is not Y2k safe,
+ and %KC and NULL are not universally supported.
+
+
+CHANGES IN CUPS V1.1.6
+
+ - Fixed another possible DoS attack in httpGets()
+ - Added check for "LANGUAGE = PCL" and "LANGUAGE =
+ POSTSCRIPT" in mime.types.
+ - Resolution options were not being passed into the
+ filter programs properly.
+ - The default compiler options for GCC no longer include
+ "-g3", which apparently is deprecated in newer
+ versions of GCC.
+ - CheckJobs() could cause cupsd to crash if a job is
+ cancelled in StartJob().
+ - The printers.conf and classes.conf files are now
+ written with restricted permissions.
+ - The round-robin algorithm used by FindAvailablePrinter()
+ had problems; fixes contributed by Joel Fredrikson.
+ - If LoadAllJobs() is unable to determine the file type
+ of a print job, assume "application/vnd.cups-raw".
+ - The web interface now provides a job_printer_name
+ value for any corresponding job_printer_uri value.
+ - The cups-lpd mini-daemon now logs the client address
+ and hostname as well as all commands and errors in the
+ syslog file.
+ - The IPP backend now detects the supported file formats
+ and only specifies the document format if it is
+ supported. This makes IPP printing to network print
+ servers and cards more reliable without affecting the
+ capabilities of CUPS servers.
+ - The time_at_xyz attributes are now converted to human-
+ readable dates and times for the web interfaces.
+ - The HP and EPSON sample drivers now correctly catch
+ signals and eject the current page when a job is
+ cancelled.
+ - Fixed bug in CGI code - did not ignore control
+ characters (e.g. newlines) in form data. This caused
+ sporatic web interface problems.
+ - The file type logging code in the scheduler referenced
+ the optional document-format attribute; the new code
+ uses the resolved MIME type instead.
+ - The client.conf parsing code now removes trailing
+ whitespace.
+ - The MaxJobs directive was being treated as a boolean
+ instead of an integer.
+ - The scheduler would not timeout remote printers if
+ BrowseInterval was set to 0.
+ - The lpadmin command now supports setting of options
+ and user-level access control.
+ - Added "-E" option to all printing commands to force
+ encryption.
+ - The client code did not consume the response to the
+ OPTIONS request when switching to secure mode.
+ - The scheduler did not output a Content-Length field
+ when responding to an OPTIONS request.
+ - Added documentation on using cups-lpd with xinetd
+ to the man page.
+ - The socket backend now starts retries at 5 seconds and
+ increases the interval to 30 seconds. This should
+ provide faster printing when multiple jobs/files are
+ queued for a printer.
+ - The filters and backends no longer buffer output to
+ stderr. This should provide much more accurate status
+ reporting.
+
+
+CHANGES IN CUPS V1.1.5-2
+
+ - Fixed configure check for OpenSSL to work with RSA
+ code.
+ - Added configure check for <sys/ioctl.h>, and use this
+ check in backend/serial.c.
+ - Updated configure script handling of data,
+ configuration, and state directories to use datadir,
+ sysconfdir, and localstatedir variables.
+ - NetBSD uses different serial port filenames than
+ FreeBSD and OpenBSD.
+ - The pdftops filter didn't need some X-specific files.
+ - The scheduler makefile doesn't do a chown anymore when
+ installing (cupsd did this automatically on startup
+ anyways)
+
+
+CHANGES IN CUPS V1.1.5-1
+
+ - There was a typo in the top-level Makefile
+ - The top-level Makefile did not install an init script
+ for run level 5.
+ - The configure script did not add the "crypto" library
+ when checking for the OpenSSL library.
+ - The OKIDATA PPD files were missing.
+ - The config.h.in file defined the wrong version number.
+ - The serial backend did not define "funky_hex" under *BSD.
+ - Updated the Visual C++ project files and some of the
+ CUPS API sources to compile under Windows again.
+
+
+CHANGES IN CUPS V1.1.5
+
+ - Security updates - new default configuration does
+ not broadcast printer information and only allows
+ access from the local system.
+ - EXPERIMENTAL encryption support - CUPS now optionally
+ supports TLS/SSL encryption via the OpenSSL library.
+ - Documentation updates.
+ - Makefile/configure script updates.
+ - The RPM spec file didn't work out-of-the-box under
+ RedHat or Mandrake.
+ - Minor code cleanup to remove extraneous compiler
+ warnings.
+ - cupsTempFile() was using %p for the temporary
+ filename; this should have been %08x (just 8 digit
+ hex)
+ - Deleting a printer with active print jobs would still
+ crash the server.
+ - ippWrite() and ipp_write_file() didn't send the
+ correct value length for name-with-language and
+ text-with-language attributes.
+ - Updated IPP code to support copied strings (that
+ should not be freed); this provides slightly more
+ efficient IPP server performance.
+ - Updated PDF filter to Xpdf 0.91.
+ - httpGets() could go into an infinite loop if a line
+ longer than the input buffer size was sent by a
+ client. This could be used in a Denial-of-Service
+ attack.
+ - The lpstat and CUPS API functions now request only the
+ data required when getting the list of printer or
+ class information. This should improve performance
+ with large numbers of printers on slower machines.
+ - The scheduler was always enforcing the FilterLimit,
+ even if FilterLimit was set to 0.
+ - Updated the Linux USB backend to support Mandrake's
+ /dev/usb/usblp# filenames.
+ - The PRINTER and LPDEST environment variables did not
+ override the lpoptions default printer.
+ - The PPD read functions incorrectly included trailing
+ characters (usually whitespace) after quoted string
+ attributes.
+ - The multiple-document-handling attribute handling code
+ did not check for the correct value for collated
+ copies (separate-documents-uncollated-copies).
+ - The EPSON driver did not work with OKIDATA printers in
+ EPSON emulation mode (needed change-emulation command)
+ - The HP-GL/2 filter did not scale the plot properly in
+ scale mode 2.
+ - Added PPD files for 9-pin and 24-pin OKIDATA printers.
+ - The httpSeparate() function didn't handle passwords
+ that started with a number.
+ - ippDelete() could free the character set string
+ multiple times in name-with-language and
+ text-with-language attributes.
+ - The scheduler would access freed memory right after
+ freeing it (for debug messages); these parts of the
+ code have been reordered to avoid this situation
+ which was causing sporatic errors and crashes.
+ - The ppdClose() function didn't free all of the strings
+ in the ppd_file_t structure.
+ - The LoadAllJobs() function in the scheduler did not
+ close the spool directory.
+ - Changed all sprintf's that use string formats to
+ snprintf's, even if the destination buffer is
+ larger than the source string(s); this protects
+ against buffer overflows caused outside of CUPS...
+ - Changed all strcpy's to strncpy's between local and
+ global variables, even if the destination buffer is
+ larger than the source string; this protects
+ against buffer overflows caused outside of CUPS...
+ - The CUPS certificate functions didn't use the
+ CUPS_SERVERROOT environment variable when set.
+ - The directory services code was copying instead of
+ comparing the remote printer info, resulting in
+ unnecessary updates of the printer attributes for
+ remote printers.
+ - Added new mime.types rules to allow automatic raw
+ printing of PCL and ESC/P files; PJL headers are
+ parsed to differentiate between PostScript and
+ PCL job files. This should eliminate a lot of
+ the reports of SAMBA printing problems due to
+ the missing "-oraw" or "-l" options.
+ - The mimeLoadType() function didn't handle the
+ 3-argument contains() function.
+ - The LoadPPDs() function in the scheduler didn't
+ properly set the alloc_ppds variable or handle a PPD
+ database containing 0 printers.
+ - The scheduler FindAvailablePrinter() function didn't
+ use the same queuing logic as the CheckJobs()
+ function. This caused classes to stall if a remote
+ printer was always busy.
+ - Jobs are now assigned to printers in a class
+ round-robin style. This should prevent the first
+ server in the class from bearing the brunt of the
+ jobs.
+ - The scheduler's LoadAllJobs() function didn't always
+ restore remote printers for queued jobs on startup.
+ - The serial backend didn't support the higher baud
+ rates with the old termios interface. It now supports
+ 57600 and 115200 baud.
+ - The serial backend now supports different types of
+ flow control; previously it ignored the flow=XYZ
+ option in the device URI.
+ - The serial backend now supports DTR/DSR flow control,
+ which is popular on dot-matrix printers (access with
+ "flow=dtrdsr" in the device URI)
+ - Added new job-originating-host-name attribute for
+ jobs. The new attribute provides the hostname or
+ IP address of the machine that submitted the job.
+ - The set-job-attributes code no longer allows read-only
+ job attributes to be changed.
+ - Expanded the click area for the navigation bar in the
+ web interface.
+ - Updated the lp and cancel commands to support all of
+ the Solaris print options (some are simply ignored
+ since they do not map)
+ - Updated the scheduler to limit the number of file
+ descriptors to the maximum select() set size. This
+ was causing problems on Solaris systems where the
+ max FD count was increased beyond 1024.
+ - The scheduler's LoadDevices() function was getting
+ interrupted by the SIGCHLD signal handler; now ignore
+ child signals while loading devices.
+ - Added quota and allow/deny user support for printers
+ and classes.
+ - Removed black/CMY adjustment code from the PS and
+ image file RIPs; it was interfering with some CUPS
+ driver dithering code.
+ - The lpc program stopped listing the queue statuses
+ after the first active printer.
+ - The cups-lpd program used an output format that the
+ Solaris printing system did not understand.
+ - Updated the lpq program to use the Solaris format
+ except under Tru64 UNIX.
+ - Some DEC PPD files incorrectly use "Off" for the null
+ value in UI constraints. Added "Off" to the list of
+ accepted null values.
+ - Changed the *BSD define constants to __*BSD__ in all
+ of the backends.
+ - Added support for "lpstat printername", which is an
+ undocumented feature in Solaris.
+ - The HP-GL/2 filter now only sets the plot size if it
+ is set in the plot file.
+ - The lpmove command wasn't sending the requesting
+ user name, causing it to always fail.
+ - Updated the cupsTempFile() code to use GetTempPath()
+ under Windows.
+ - The cups-lpd mini-daemon didn't limit the number of
+ data files accepted, didn't use cupsTempFile(),
+ didn't handle control file job information in any
+ order, and didn't free job options after printing
+ a file.
+ - The scheduler copy_banner() function did not
+ explicitly set the owner and permissions of the banner
+ files, which could prevent the banner pages from
+ printing on some systems.
+ - The lpstat program wasn't listing remote classes.
+ - The scheduler did not verify that the printer-uri
+ attribute was specified in all requests that required
+ it.
+
+
+CHANGES IN CUPS v1.1.4
+
+ - Makefile and configure script fixes.
+ - **** Changed the default Printcap setting **** to
+ /etc/printcap. There are just too many people asking
+ why application XYZ doesn't see their printers!
+ - The web admin interface now displays an error if it
+ can't get the list of printer drivers from cupsd.
+ - The IPP backend was putting the copies option before
+ the other job options were set. This caused the IPP
+ request to contain attribute groups in the wrong
+ order, which prevented remote printing.
+ - Added checks in scheduler to free memory used for
+ IPP requests and language information when closing
+ a client connection.
+ - Fixed the duplex option in the HP LaserJet driver. It
+ should now work with all LaserJet printers (and
+ compatibles)
+ - The add-printer web interface didn't initialize the
+ "old info" data pointer, which caused random crashes
+ on many OS's.
+ - Fixed many page sizes defined in the Level 1
+ compatibility file "gs_statd.ps" to match reality.
+ - Fixed another bug in the setpagedevice "code" in
+ Ghostscript. It should now accept all standard
+ Adobe attributes on all platforms.
+ - Fixed pstoraster so that it reallocates memory for
+ color depth changes as well as size/resolution
+ changes. This removes an ordering constraint on
+ the color, page size, and resolution options in
+ PPD files.
+ - The IPP backend didn't use the job's character set
+ when the destination printer supported it. This
+ caused problems when printing text files to other
+ CUPS servers.
+ - Updated the logic used to determine when to rebuild
+ the PPD file database. The scheduler now checks the
+ dates and the number of PPD files (was just checking
+ the dates.)
+ - Updated the ippSetCGIVars() function (used by the
+ web interfaces) to only filter valid string values.
+ - The PostScript filter was scaling 2-up pages
+ incorrectly. This caused the edges of some pages to
+ be clipped.
+
+
+CHANGES IN CUPS v1.1.3
+
+ - Makefile fixes.
+ - RPM spec file changes.
+ - Documentation updates.
+ - Enabled pstoraster debug messages for everything
+ (only logged when LogLevel set to "debug"...)
+ - Changed the Input/OutputAttributes fix in
+ pstoraster so that it works on all platforms.
+ - The HP-GL/2 filter didn't set the right green
+ color value in encoded polylines or text.
+ - Updated the "fitplot" code to handle plot sizes
+ specified as "PSwidth,length" and "PSlength,width".
+ - Updated the Linux parallel and USB backends to open
+ the device files prior to looking in /proc for
+ autoprobe info. This makes sure that loadable device
+ driver modules are in fact loaded...
+ - Added new FilterLimit directive to limit the number
+ of processing jobs/filters on a system.
+ - set-job-attributes didn't change the job-state to
+ held/pending when the job-hold-until attribute was
+ specified.
+ - set-job-attributes didn't save the new job attributes.
+ - Now change the "requesting-user-name" attribute in
+ requests from remote systems to "remroot" when an
+ unauthenticated "root" user is sent. This can be
+ changed using the new RemoteRoot directive in
+ cupsd.conf.
+ - The cancel-job, hold-job, release-job, and restart-job
+ operations didn't log the authenticated username.
+ - The cups-lpd mini-daemon now checks for a
+ document-format option before forcing raw mode with
+ filter mode 'l'.
+ - The cups-lpd mini-daemon now supports "-o" options
+ on the command-line (passed by inetd) to set global
+ defaults for all print queues.
+ - The pstops filter assumed that a file with a Trailer
+ comment would also have an EOF comment.
+ - Added new cupsSetPasswordCB(), cupsSetServer(),
+ cupsSetUser(), and ippSetPort() functions to better
+ support client applications (especially GUIs...)
+ - The CUPS-add-class and CUPS-add-printer operations
+ didn't reset the printer-name attribute on remote
+ print queues that had to be renamed when a local
+ printer was defined with the same name.
+ - The lpoptions command now supports a "-r" option to
+ remove options for a printer or instance.
+ - The lpadmin and admin.cgi programs no longer allow
+ class and printer names to begin with a number; this
+ caused the command-line utilities to become confused.
+ - The Linux USB backend now looks for both the parallel
+ and usblp driver names in the device list.
+ - Added a new FontPath directive to cupsd.conf, and also
+ a "--with-fontpath" option for the configure script to
+ specify alternate font paths for pstoraster.
+ - The CUPS-move-job operation didn't update the
+ job-printer-uri attribute.
+ - The scheduler only looked up printers and classes by
+ name in IPP requests, instead of using the full URI.
+ This caused problems with KUPS and friends with
+ remote printers.
+ - The scheduler now handles better localization of
+ hostnames (e.g. server is host.foo.com, remote is
+ host.subfoo.foo.com, localized is not host.subfoo...)
+ - The scheduler logging functions now use a common
+ log file checking/rotation function (courtesy of
+ Crutcher Dunnavant at Red Hat)
+ - The scheduler could accept more client connections
+ than it allocated for if more than one Port or Listen
+ line was present in cupsd.conf.
+ - Other minor scheduler performance tweeks.
+ - The lpq and lprm commands didn't support the default
+ printer set using lpoptions.
+ - The lpoptions command now supports a "-l" option to
+ list the printer-specific options and their current
+ settings.
+ - The web printer and class lists now show a link to the
+ default printer or class at the top of the page.
+ - The text filter now supports pretty printing of shell
+ and perl scripts as well as C/C++ source files.
+ - The top and bottom margins were reversed for landscape
+ text printing.
+ - The lpq and lprm commands didn't understand printer
+ instances.
+ - The scheduler only selected on the first 100 file
+ descriptors instead of the maximum file descriptor
+ limit.
+ - The scheduler client, listener, and mainline functions
+ now share code to disable and enable monitoring for
+ new client connections.
+ - The imagetoraster filter didn't support all of the
+ required pagedevice parameters.
+ - The serial backend now checks for 100 serial ports
+ under Linux.
+ - The scheduler used sscanf() to pull out the remote
+ printer location, description, and make/model strings,
+ but if any of these options was empty then sscanf()
+ would stop processing.
+ - Added "debug2" log level to provide a little less
+ verbose debugging information at the "debug" level.
+ - The scheduler would crash if you stopped a printer
+ that was currently printing a job.
+ - The scheduler incorrectly allowed jobs in the cancelled,
+ aborted, or completed state to be cancelled.
+ - The image filters did not load TIFF images properly
+ for bottom-to-top and right-to-left orientations.
+ - Added new cupsEncodeOptions() function to encode
+ CUPS options as IPP job attributes.
+ - The IPP backend, LPD mini-daemon, client commands,
+ and CUPS API did not properly encode multiple
+ option values separated by commas.
+ - Added new scheduler malloc logging in debug mode
+ (provides summary of total arena size, allocated,
+ and free bytes once a minute)
+ - The EPM-based distributions didn't install the
+ correct symlinks for a few man pages.
+ - Fixed a memory leak in the scheduler - wasn't
+ freeing old filters when deleting or renaming
+ printers.
+ - The scheduler now queries the primary IP address
+ for the name of the server and maps any incoming
+ requests from that address to the server name.
+ This fixes web admin mapping problems from
+ server.domain.com to localhost.
+ - The web printer modify interface now remembers
+ the previous device and driver settings (except
+ for serial ports.)
+ - The job-k-octets attribute is now stored as part of
+ the job attributes; this preserves the information
+ after a job is completed when job file history is
+ turned off.
+ - Dropped option sub-group parsing code for the moment,
+ since many Xerox PPD files abuse this feature in PPD
+ files and don't follow the hierarchy rules.
+ - Added new wrapper code around options so that duplex
+ options for some HP printers don't prevent prints.
+ - Added support for Digital UNIX/Tru64 UNIX/OSF/1 format
+ for "lpstat -v" output.
+ - Now show the URI for remote printers instead of
+ /dev/null in "lpstat -v" output.
+ - Creating classes and adding printers to a class with
+ the lpadmin command didn't work.
+ - The banner pages and test page should now format
+ correctly in both portrait and landscape orientations.
+ - Updated banner page substitution so that { can appear
+ by itself without quoting.
+
+
+CHANGES IN CUPS v1.1.2
+
+ - Makefile/configure fixes
+ - RPM spec file and EPM list file fixes
+ - The cupsTempFile() function now uses a different
+ algorithm for generating temp files and "reserves"
+ them to avoid possible security exploitation.
+ - Now use /dev/random (if available) to seed the random
+ number generator for certificates.
+ - The /var/spool/cups and /var/spool/cups/tmp directories
+ were incorrectly owned by root; they are now owned by
+ the filter user, typically "lp".
+ - The scheduler now resets the permissions on the spool
+ and temp directories as needed to match the filter
+ user.
+ - Now expose ppdCollect() as an externally callable
+ function.
+ - The image filters now support filtering from the
+ standard input.
+ - The imagetoraster filter now collects all printer
+ options and job patch files and applies them to the
+ page header as needed.
+ - Added format and banner options to LPD backend.
+ - The send-document operation didn't start a job
+ immediately when last-document was true.
+ - The set-job-attributes operation didn't correctly
+ replace the current job-hold-until value.
+ - Removed the option wrapper code from ppdEmit() and
+ friends since it caused problems with Ghostscript
+ and many PS printers.
+ - Was setting TZ environment variable twice for job
+ filters.
+ - Added syslog logging in cups-lpd to aide in
+ debugging problems.
+ - The HP-UX parallel port backend did not list the
+ available parallel ports on some systems (printf
+ calling problem...)
+ - The lp and lpr commands overrode user options if
+ -d/-P were specified after -o.
+ - The scheduler would crash with a */* filter.
+ - Added support for a "default" filter for unknown file
+ types. The example provided in the mime.types and
+ mime.convs file prints unknown files as if "-oraw" was
+ specified for the job. This functionality is disabled
+ by default.
+ - The "compatibility" mode fix for older backends did not
+ work for smbspool. Added a workaround for it.
+ - The HP-GL/2 filter didn't perform the right pen scaling
+ with some files and the "fitplot" option.
+ - New Software Performance Specification document that
+ describes the memory, disk, and CPU usage of all the
+ CUPS software.
+
+
+CHANGES IN CUPS v1.1.1
+
+ - The pstoraster Makefile still referenced one of the
+ old PDF filter files.
+ - The filter Makefile used INSTALL_DATA instead of
+ INSTALL_LIB to install the CUPS image library.
+ - The administration CGI didn't work properly with
+ network devices.
+ - The BrowseACL variable was not updated after the
+ cupsd.conf file was loaded.
+ - The lpd mini-daemon didn't support printer instances.
+ - Now use a default umask of 077 for child processes.
+ - Now put temp files in /var/spool/cups/tmp for child
+ processes and the root user, unless TMPDIR or TempDir
+ is defined otherwise.
+ - cupsGetPPD() no longer uses easy-to-guess filenames.
+ - The CUPS-Delete-Class and CUPS-Delete-Printer
+ operations now save classes.conf file as needed.
+ - The lppasswd command wouldn't add a user.
+ - The ppdOpen() function could cause a segfault if a
+ 0-length PPD file was read.
+ - The image filters were not handling images with
+ different X and Y resolutions properly.
+ - The imagetoraster filter defaulted to RGB output
+ instead of black output like pstoraster.
+ - The pstops filter didn't handle binary data properly.
+ - The pstops filter didn't handle copies properly for
+ PS files lacking DSC comments.
+ - The pstops filter now appends %%EOF to the end of
+ documents if they don't have it.
+ - The cupsGetPPD() function didn't work with remote
+ printers lacking the @server in the name.
+ - The configure script didn't work right when only
+ --prefix was specified.
+ - The ppdEmit() code now wraps all printer commands so
+ that buggy PostScript printers will still print a file
+ after receiving an option that isn't available.
+ - Fixed the DeskJet margin bug, and disabled 600dpi
+ color mode until it can be fixed.
+ - The cupsAddDest() function didn't sort instances
+ correctly in all cases.
+ - The time-at-xyz attributes now expand to the date and
+ time in banner files.
+
+
+CHANGES IN CUPS v1.1
+
+ - Documentation updates.
+ - Configuration script updates.
+ - Didn't map charset and language value strings to lowercase
+ and _ to - as required by SLP and IPP.
+ - ppdLoadXYZ() didn't add the list of available fonts to the
+ ppd_file_t structure.
+ - The text filter common code was freeing the PPD file data
+ before it was used.
+ - The text filter now embeds missing fonts.
+ - The CGI interface now maps local access to the server to
+ the localhost address.
+ - The HP-GL/2 filter didn't use the specified (or default)
+ color ranges, resulting in strange colors.
+ - The HP-GL/2 filter didn't default to no input window, which
+ caused unnecessary clipping of plots.
+ - Integrated Xpdf's pdftops filter into CUPS, which is a
+ lightweight and reliable replacement for Ghostscript's
+ PDF support.
+ - Removed all PDF support from Ghostscript.
+ - Updated HP driver to set top margin; this seems to fix
+ the offset problem seen on HP DeskJet printers.
+ - Fixed dependencies on the ZLIB and JPEG libraries in
+ pstoraster.
+ - The lpr command wasn't using the lpoptions defined by
+ the user.
+ - The lpr command would segfault if the CUPS server was
+ not running.
+ - The top-level makefile was not installing the CUPS
+ initialization script. It now does so if it sees there
+ is an init.d directory in /sbin, /etc/rc.d, or /etc.
+ - "lpstat -v all" didn't work.
+ - pstoraster would crash on some platforms doing the
+ setpagedevice operator.
+ - The web administration interface now allows you to set
+ the default banner pages.
+ - Images can now be positioned on the page using the new
+ "position" option.
+ - The AccessLog, ErrorLog, and PageLog directives now
+ support "%s" to insert the server name.
+ - Added a new BrowseShortNames directive to allow for
+ short remote printer names ("printer" instead of
+ "printer@server") when possible.
+ - The scheduler could crash if given an invalid PPD file
+ with no PageSize attributes.
+ - Updated the serial, parallel, and usb backends to do
+ multiple writes and ignore ioctl() errors as needed;
+ this should fix problems with serial printing on old
+ serial drivers and with the UltraSPARC parallel port
+ driver under Solaris 2.7.
+ - Now propagate LD_LIBRARY_PATH to child processes from
+ cupsd.
+ - New DataDir directive for installing in alternate
+ locations.
+ - New CUPS_SERVERROOT and CUPS_DATADIR environment
+ variables to specify installation directories as
+ needed.
+ - Queued remote jobs recreate remote printers as needed
+ when the scheduler is started.
+ - Deleting a printer also purges all jobs on that
+ printer.
+ - Old job and control files that don't belong to a
+ printer are automatically deleted.
+ - Wasn't updating time-at-processing and
+ time-at-completed attributes in job.
+ - Didn't send required multiple-operation-time-out
+ attribute in response to a get-printer-attributes
+ request.
+ - cups-lpd now supports options set with lpoptions.
+ - The job-hold-until attribute is now provided with all
+ jobs. For jobs that are not currently held the value
+ is "no-hold".
+ - The scheduler was not sending "unknown" values in IPP
+ responses.
+ - The lpoptions command now accumulates options from
+ previous runs rather than replacing all options for a
+ printer.
+ - The IPP backend now switches to IPP/1.0 if a 1.1
+ request fails.
+ - The lpadmin and admin.cgi programs now validate new
+ printer and class names.
+ - The access_log file now includes the number of IPP bytes
+ received in a POST request.
+
+
+CHANGES IN CUPS v1.1b5
+
+ - Documentation updates.
+ - The pstoraster filter didn't compile without the JPEG library.
+ - The cupsd server didn't support the HTTP OPTIONS request
+ method.
+ - Dropped the "CLOSE" method supported by the cupsd server.
+ (not defined in HTTP specification)
+ - Makefile/configure script fixes.
+ - Missing the job-restart template.
+ - Added IPP test suite for testing.
+ - Missing IPP documentation from binary distributions.
+ - Fixed multiple-document handling code when last-document
+ not specified.
+ - Added more checks to IPP requests to prevent bad requests
+ from getting through.
+ - Not all of the Ghostscript error output was being sent to
+ stderr.
+ - The PostScript filter now added PJL commands to set the
+ job name and display string, if supported.
+ - The scheduler would crash if the browse socket could not
+ be bound. Now disables browsing if port 631 (reserved for
+ IPP) is being used by a misbehaving daemon.
+ - The USB backend now looks for the older Linux 2.2.x USB
+ printer device filenames as well as the newer ones.
+ - The IPP backend now uses the UTF-8 charset exclusively,
+ since apparently only CUPS handles more than US-ASCII and
+ UTF-8...
+ - Wasn't quoting ( in PostScript banners...
+ - Send-document requests with no document-format attribute
+ could cause cupsd to crash.
+ - Old jobs in the spool directory might cause cupsd to
+ crash.
+ - CUPS now supports all of the recommended job-hold-until
+ keywords as well as name values of the form "HH:MM" and
+ "HH:MM:SS".
+ - Added placeholder pointer for TLS encryption to the HTTP
+ connection structure.
+ - Fixed the "fast poll" bug reported by DISA - the
+ status pipe wasn't being closed for multi-file jobs.
+ - Revamped put_params code in pstoraster to fix bitmap
+ allocation bug with FrameMaker output.
+ - Ripped out filename, etc. code from pstoraster as it
+ is a potential security hole.
+ - Added support for RIP_CACHE environment variable in the
+ new pstoraster.
+ - Fixed USB device filenames for Linux; now support new
+ pre-2.4 devices (/dev/usb/lp#) and 2.2 devices
+ (/dev/usblp#)
+ - Fixed accept-jobs crash with classes.
+ - Didn't include dot-matrix EPSON drivers in previous
+ release.
+
+
+CHANGES IN CUPS v1.1b4
+
+ - Documentation updates.
+ - Many makefile and configuration script fixes (should
+ now compile better under *BSD.)
+ - The MediaPosition attribute was being mishandled by
+ GhostScript, causing the RIP to fail whenever a paper
+ tray was selected.
+ - The scheduler now logs the final line of log information
+ from a filter, even if it doesn't end with a newline; this
+ primarily affects GhostScript error output.
+ - The scheduler was saving implicit classes, so after a few
+ restarts you'll end up with AnyPrinter, AnyAnyPrinter, etc.
+ - The JPEG autodetection didn't work with some JPEG files that
+ came from digital cameras (JPEG but not JFIF); the new
+ magic types should work with all images that the JPEG library
+ can handle.
+ - Fixed a bug in the new contains() MIME type rule that could
+ cause cupsd to crash.
+ - Switched to using strtol() in the MIME type code so that you
+ can use hex, octal, or decimal constants as desired in the
+ mime.types file.
+ - Banner files are now treated as templates, allowing any type
+ of file to be used as a banner.
+ - Added a 30-second timeout to backend device reports so that a
+ hung backend will not prevent the scheduler from starting.
+ - Backends are once again terminated when jobs are stopped; the
+ CUPS-supplied backends will stay alive until the downstream
+ filters have had a chance to clear out old page data.
+ - The charset lookup in the CUPS localization support was wrong
+ (iso8859-x instead of iso-8859-x)
+ - Changed the "cpNNNN" code page files to "windows-NNNN" to match
+ the IANA registrations.
+ - New PostScript banner pages.
+ - Added Windows BMP and Alias PIX image file support to the image
+ filter.
+ - The PNG reading coded didn't free all of its buffers.
+ - Added Digest authentication support to the client and server
+ code.
+ - Added Solaris options to System V commands.
+ - Now support the output-bin job template attribute.
+ - Now log the job-billing attribute in the page_log file, and
+ keep track of the total number of pages in the
+ job-media-sheets-completed attribute.
+ - The penwidth option is now in micrometers to support more
+ accurate width specification.
+ - The image filters now support interlaced and transparent PNG
+ files.
+ - Didn't handle Keep-Alive for HTTP/1.0 clients.
+ - The BrowsePoll support didn't handle when BrowseInterval
+ was set to 0 (now uses 30 seconds if BrowseInterval is 0)
+ - The DeskJet driver now supports 600 DPI color for printers
+ that support it.
+ - New lpinfo and lpmove commands.
+ - The lpq command now supports the Digital UNIX output format.
+ - The LPD mini-daemon now supports all required LPD operations.
+ - Implemented timeouts for multi-file documents.
+ - New cupsPrintFiles() function in the CUPS API library to
+ print multiple files using create-job and send-document
+ requests (1 job ID for multiple files)
+ - The lp command now sends multiple files as a single job,
+ matching the behavior of the System V command.
+ - The "cancel -a" command now purges job history files.
+
+
+CHANGES IN CUPS v1.1b3
+
+ - Documentation updates.
+ - The startup script redirected stderr before stdout,
+ which caused problems with some versions of Bourne
+ shell and Bash.
+ - Fixed a bug in the scheduler's PPD language reading
+ code.
+ - Fixed a bug in the scheduler's check for the
+ manufacturer in the PPD.
+ - The pstoraster filter didn't allow some input and
+ output attributes to be set.
+ - Added banner page support.
+ - Added missing PAM configuration file.
+ - Configuration script fixes for Linux and *BSD.
+ - The log file code was using the wrong sign for the
+ timezone offset.
+ - The default printcap file is now empty (no printcap
+ file is generated).
+ - The scheduler did not start jobs destined for remote
+ printers when they became available.
+ - The scheduler now sends jobs to remote printers
+ immediately. (when sending jobs to a class, the remote
+ printer is only used when it becomes available)
+ - The scheduler now supports printing of banner pages
+ via the job-sheets attribute (banner files go in
+ /usr/share/cups/banners)
+ - The cupsd process now forks itself into the background
+ (override with -f)
+ - Added several *BSD enhancements.
+ - Added UNSUPPORTED libtool option to configuration
+ script to allow the use of libtool. Note that this is
+ UNSUPPORTED by us, but added by request of the *BSD
+ folks.
+ - The parallel, serial, and usb backends now retry the
+ opening of their ports. This allows multiple print
+ queues to be associated with a single physical port,
+ and will allow CUPS to support several types of
+ parallel port auto-switches in the near future.
+ - Set-Job-Attributes now supports adding, changing, and
+ deleting job template attributes, and no longer allows
+ job-printer-uri to be set (see CUPS-Move-Job)
+ - Added CUPS-Move-Job operation to support moving of jobs.
+ - The CGI template functionality now supports multiple
+ languages (still only have templates for English)
+ - The CUPS-Get-Printers and CUPS-Get-Classes operations
+ now support filtering as defined in the IDD.
+ - The Get-Jobs, CUPS-Get-Printers, and CUPS-Get-Classes
+ operations no longer limit themselves to 1000 jobs,
+ printers, or classes (believe it or not, this is
+ needed for some sites)
+ - The web interfaces now support language-specific
+ templates.
+ - The web admin interface now supports class management.
+ - The web admin interface now shows a list of
+ manufacturers before selecting the PPD/driver for a
+ specific printer.
+ - The web admin interface now supports configuration of
+ the default printer options in the PPD file.
+ - The web interface now uses printer/class
+ authentication for the test page instead of admin
+ authentication.
+ - Updated the RPM spec file for the current release.
+ - Updated language support for Windows code pages.
+ - 8-bit character set files can now use multiple fonts
+ (needed for Arabic, Greek, Hebrew, etc.)
+ - Added basic right-to-left text support in the text
+ filter.
+ - The POSIX locale now uses ISO-8859-1 instead of
+ US-ASCII.
+ - Fixed PDF printing problems.
+ - Fixed PostScript RIP page device dictionary elements
+ that weren't getting passed in cups_get_params().
+ - Added a new "contains" rule for the magic file typing.
+ - The "printable" rule now accepts characters from 128 to 255
+ (needed for Microsoft character sets)
+ - Added support for ~/.cupsrc as well as /etc/cups/client.conf
+ so that the default server can be configured on a per-user
+ basis without environment variables.
+ - Added LPD mini-daemon to support incoming LPD jobs.
+
+
+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 000000000..71bad1486
--- /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/ENCRYPTION.txt b/ENCRYPTION.txt
new file mode 100644
index 000000000..5ec656ea5
--- /dev/null
+++ b/ENCRYPTION.txt
@@ -0,0 +1,138 @@
+ENCRYPTION - CUPS v1.1.7 - 02/21/2001
+-------------------------------------
+
+This file describes the encryption support provided by CUPS.
+
+WARNING: CLIENTS CURRENTLY TRUST ALL CERTIFICATES FROM SERVERS.
+This makes the CUPS client applications vulnerable to "man in
+the middle" attacks, so we don't recommend using this to do
+remote administration over WANs at this time.
+
+Future versions of CUPS will keep track of server certificates
+and provide a callback/confirmation interface for accepting new
+certificates and warning when a certificate has changed.
+
+
+LEGAL STUFF
+
+BEFORE USING THE ENCRYPTION SUPPORT, PLEASE VERIFY THAT IT IS
+LEGAL TO DO SO IN YOUR COUNTRY. CUPS by itself doesn't include
+any encryption code, but it can link against the OpenSSL library
+which does.
+
+
+OVERVIEW OF ENCRYPTION SUPPORT IN CUPS
+
+CUPS supports SSL/2.0, SSL/3.0, and TLS/1.0 encryption using
+keys as large as 128-bits. Encryption support is provided via
+the OpenSSL library and some new hooks in the CUPS code.
+
+CUPS provides support for dedicated (https) and "upgrade" (TLS)
+encryption of sessions. The "HTTP Upgrade" method is described
+in RFC 2817; basically, the client can be secure or unsecure,
+and the client or server initiates an upgrade to a secure
+connection via some new HTTP fields and status codes. The HTTP
+Upgrade method is new and no browsers we know of support it yet.
+Stick with "https" for web browsers.
+
+The current implementation is very basic. The CUPS client
+software (lp, lpr, etc.) uses encryption as requested by the
+user or server.
+
+The user can specify the "-E" option with the printing commands
+to force encryption of the connection. Encryption can also be
+specified using the Encryption directive in the client.conf file
+or in the CUPS_ENCRYPTION environment variable:
+
+ Never
+
+ Never do encryption.
+
+ Always
+
+ Always do SSL/TLS encryption using the https scheme.
+
+ IfRequested
+
+ Upgrade to TLS encryption if the server asks for it.
+ This is the default setting.
+
+ Required
+
+ Always upgrade to TLS encryption as soon as the
+ connection is made. This is different than the "Always"
+ mode above since the connection is initially unsecure
+ and the client initiates the upgrade to TLS encryption.
+ (same as using the "-E" option)
+
+These keywords are also used in the cupsd.conf file to secure
+particular locations. To secure all traffic on the server, listen
+on port 443 (https port) instead of port 631 and change the "ipp"
+service listing (or add it if you don't have one) in /etc/services
+to 443. To provide both secure and normal methods, add a line
+reading:
+
+ SSLPort 443
+
+to /etc/cups/cupsd.conf.
+
+
+BEFORE YOU BEGIN
+
+You'll need the OpenSSL library from:
+
+ http://www.openssl.org
+
+
+CONFIGURING WITH ENCRYPTION SUPPORT
+
+Once you have the OpenSSL library installed, you'll need to
+configure CUPS to use it with the "--enable-ssl" option:
+
+ ./configure --enable-ssl
+
+If the OpenSSL stuff is not in a standard location, make sure to
+define the CFLAGS, CXXFLAGS, and LDFLAGS environment variables
+with the appropriate compiler and linker options first.
+
+
+GENERATING A SERVER CERTIFICATE AND KEY
+
+The following OpenSSL command will generate a server certificate
+and key that you can play with. Since the certificate is not
+properly signed it will generate all kinds of warnings in
+Netscape and MSIE:
+
+ openssl req -new -x509 -keyout /etc/cups/ssl/server.key \
+ -out /etc/cups/ssl/server.crt -days 365 -nodes
+
+ chmod 600 /etc/cups/ssl/server.*
+
+The "-nodes" option prevents the certificate and key from being
+encrypted. The cupsd process runs in the background, detached
+from any input source; if you encrypt these files then cupsd
+will not be able to load them!
+
+Send all rants about non-encrypted certificate and key files to
+/dev/null. It makes sense to encrypt user files, but not for
+files used by system processes/daemons...
+
+
+REPORTING PROBLEMS
+
+If you have problems, READ THE DOCUMENTATION FIRST! If the
+documentation does not solve your 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. The "/var/log/cups/error_log" file should also be sent,
+as it often helps to determine the cause of your problem.
+
+If you are running a version of Linux, be sure to provide the
+Linux distribution you have, too.
+
+Please note that the "cups-support@cups.org" email address goes
+to the CUPS developers; they are busy people, so your email may
+go unanswered for days or weeks. In general, only general build
+or distribution problems will actually get answered - for
+end-user support see the "README.txt" for a summary of the
+resources available.
diff --git a/INSTALL.txt b/INSTALL.txt
new file mode 100644
index 000000000..d5d765aae
--- /dev/null
+++ b/INSTALL.txt
@@ -0,0 +1,170 @@
+INSTALL - CUPS v1.1.13 - 01/31/2002
+-----------------------------------
+
+This file describes how to compile and install CUPS from source
+code. For more information on CUPS see the file called
+"README.txt". A complete change log can be found in
+"CHANGES.txt".
+
+
+BEFORE YOU BEGIN
+
+You'll need ANSI-compliant C and C++ compilers, plus a make
+program and Bourne shell. The GNU compiler tools work well -
+we've tested the current CUPS code against GCC 2.95.x with
+excellent results.
+
+The makefiles used by the project should work with all versions
+of make. We've tested them with GNU make as well as the make
+programs shipped by Compaq, HP, SGI, and Sun. FreeBSD users
+should use GNU make (gmake).
+
+Besides these tools you'll want the following libraries:
+
+ - JPEG 6b or higher
+ - PNG 1.0.6 or higher
+ - TIFF 3.4 or higher
+ - ZLIB 1.1.3 or higher
+
+CUPS will compile and run without these, however you'll miss out on
+many of the features provided by CUPS.
+
+
+CONFIGURATION
+
+CUPS uses GNU autoconf, so you should find the usual "configure"
+script in the main CUPS source directory. To configure CUPS for
+your system, type:
+
+ ./configure ENTER
+
+The default installation will put the CUPS software in the
+"/etc", "/usr", and "/var" directories on your system, which
+will overwrite any existing printing commands on your system.
+Use the "--prefix" option to install the CUPS software in
+another location:
+
+ ./configure --prefix=/some/directory 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, CXXFLAGS, DSOFLAGS,
+and LDFLAGS environment variables prior to running configure:
+
+ setenv CFLAGS "-I/some/directory" ENTER
+ setenv CXXFLAGS "-I/some/directory" ENTER
+ setenv DSOFLAGS "-L/some/directory" ENTER
+ setenv LDFLAGS "-L/some/directory" ENTER
+ ./configure ... ENTER
+
+or:
+
+ CFLAGS="-I/some/directory"; export CFLAGS ENTER
+ CXXFLAGS="-I/some/directory"; export CXXFLAGS ENTER
+ DSOFLAGS="-L/some/directory"; export DSOFLAGS ENTER
+ LDFLAGS="-L/some/directory"; export LDFLAGS ENTER
+ ./configure ... ENTER
+
+To enable support for encryption, you'll also want to add the
+"--enable-ssl" option:
+
+ ./configure --enable-ssl
+
+SSL and TLS support require the OpenSSL library, available at:
+
+ http://www.openssl.org
+
+If the OpenSSL header files and libraries are not in a standard
+location, specify the locations of these files using the
+--with-openssl-includes and --with-openssl-libs directives:
+
+ ./configure --enable-ssl \
+ --with-openssl-includes=/foo/bar/include \
+ --with-openssl-libs=/foo/bar/lib
+
+See the file "ENCRYPTION.txt" for information on using the
+encryption support in CUPS.
+
+Once you have configured things, just type:
+
+ make ENTER
+
+or if you have FreeBSD, NetBSD, or OpenBSD type:
+
+ gmake ENTER
+
+to build the software.
+
+
+INSTALLING THE SOFTWARE
+
+Once you have built the software you need to install it. The
+"install" target provides a quick way to install the software on
+your local system:
+
+ make install ENTER
+
+or for FreeBSD, NetBSD, or OpenBSD:
+
+ gmake install ENTER
+
+You can also build binary packages that can be installed on other
+machines using the RPM spec file ("cups.spec") or EPM list file
+("cups.list"). The latter also supports building of binary RPMs,
+so it may be more convenient to use - we use EPM to build all of
+our binary distributions.
+
+You can find the RPM software at:
+
+ http://www.rpm.org
+
+The RPM software is at:
+
+ http://www.easysw.com/epm
+
+
+CREATING BINARY DISTRIBUTIONS WITH EPM
+
+The top level makefile supports generation of many types of binary
+distributions using EPM. To build a binary distribution type:
+
+ make <format> ENTER
+
+or
+
+ gmake <format> ENTER
+
+for FreeBSD, NetBSD, and OpenBSD. The <format> target is one of
+the following:
+
+ epm - Builds a portable shell script and tar file based
+ distribution. This format will also backup your
+ existing printing system if you decide to remove
+ CUPS at some future time.
+ aix - Builds an AIX binary distribution.
+ bsd - Builds a *BSD binary distribution.
+ deb - Builds a Debian binary distribution.
+ depot - Builds a HP-UX binary distribution.
+ pkg - Builds a Solaris binary distribution.
+ rpm - Builds a RPM binary distribution.
+ tardist - Builds an IRIX binary distribution.
+
+
+REPORTING PROBLEMS
+
+If you have problems, READ THE DOCUMENTATION FIRST! If the
+documentation does not solve your 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. The "/var/log/cups/error_log" file should also be sent,
+as it often helps to determine the cause of your problem.
+
+If you are running a version of Linux, be sure to provide the
+Linux distribution you have, too.
+
+Please note that the "cups-support@cups.org" email address goes
+to the CUPS developers; they are busy people, so your email may
+go unanswered for days or weeks. In general, only general build
+or distribution problems will actually get answered - for
+end-user support see the "README.txt" for a summary of the
+resources available.
diff --git a/LICENSE.html b/LICENSE.html
new file mode 100644
index 000000000..d6c54dd23
--- /dev/null
+++ b/LICENSE.html
@@ -0,0 +1,895 @@
+<HTML>
+<HEAD>
+ <TITLE>Software License Agreement - Common UNIX Printing System</TITLE>
+</HEAD>
+
+<BODY BGCOLOR="#ffffff" TEXT="#000000">
+
+<H2 ALIGN="CENTER">Common UNIX Printing System License Agreement</H2>
+
+<P ALIGN="CENTER">Copyright 1997-2002 by Easy Software Products<BR>
+44141 AIRPORT VIEW DR STE 204<BR>
+HOLLYWOOD, MARYLAND 20636-3111 USA<BR>
+<BR>
+Voice: +1.301.373.9600<BR>
+Email: <A HREF="mailto:cups-info@cups.org">cups-info@cups.org</A><BR>
+WWW: <A HREF="http://www.cups.org">http://www.cups.org</A>
+
+<H3>Introduction</H3>
+
+<P>The Common UNIX Printing System<SUP>TM</SUP>, ("CUPS<SUP>TM</SUP>"),
+is provided under the GNU General Public License ("GPL") and GNU
+Library General Public License ("LGPL"), Version 2. A copy of these
+licenses follow this introduction.
+
+<P>The GNU LGPL applies to the CUPS API library, located in the "cups"
+subdirectory of the CUPS source distribution and in the
+"/usr/include/cups" directory and "libcups.a", "libcups_s.a",
+"libcups.sl", or "libcups.so" files in the binary distributions.
+
+<P>The GNU GPL applies to the remainder of the CUPS distribution,
+including the "pstoraster" filter which is based upon GNU Ghostscript
+5.50 and the "pdftops" filter which is based upon Xpdf 0.93a.
+
+<P>For those not familiar with the GNU GPL, the license basically
+allows you to:
+
+<UL>
+
+ <LI>Use the CUPS software at no charge.
+
+ <LI>Distribute verbatim copies of the software in source or
+ binary form.
+
+ <LI>Sell verbatim copies of the software for a media fee, or
+ sell support for the software.
+
+ <LI>Distribute or sell printer drivers and filters that use
+ CUPS so long as source code is made available under the GPL.
+
+</UL>
+
+<P>What this license <B>does not</B> allow you to do is make changes or
+add features to CUPS and then sell a binary distribution without source
+code. You must provide source for any new drivers, changes, or
+additions to the software, and all code must be provided under the GPL
+or LGPL as appropriate.
+
+<P>The GNU LGPL relaxes the "link-to" restriction, allowing you to
+develop applications that use the CUPS API library under other licenses
+and/or conditions as appropriate for your application.
+
+<H3>Trademarks</H3>
+
+<P>Easy Software Products has trademarked the Common UNIX Printing
+System, CUPS, and CUPS logo. These names and logos may be used freely
+in any direct port or binary distribution of CUPS. To use them in
+derivative products, please contract Easy Software Products for written
+permission. Our intention is to protect the value of these trademarks and
+ensure that any derivative product meets the same high-quality
+standards as the original.
+
+<H3>Binary Distribution Rights</H3>
+
+<P>Easy Software Products also sells rights to the CUPS source code
+under a binary distribution license for vendors that are unable to
+release source code for their drivers, additions, and modifications to
+CUPS under the GNU GPL and LGPL. For information please contact us at
+the address shown above.
+
+<P>The Common UNIX Printing System provides a "pstoraster" filter that
+utilizes the GNU GhostScript 5.50 core to convert PostScript files into
+a stream of raster images. For binary distribution licensing of this
+software, please contact:
+
+<BLOCKQUOTE>
+Miles Jones<BR>
+Director of Marketing<BR>
+Artifex Software Inc.<BR>
+454 Las Gallinas Ave., Suite 108<BR>
+San Rafael, CA 94903 USA<BR>
+Voice: +1.415.492.9861<BR>
+Fax: +1.415.492.9862<BR>
+EMail: <A HREF="mailto:info@arsoft.com">info@arsoft.com</A>
+</BLOCKQUOTE>
+
+<P>The "pdftops" filter is based on the Xpdf 0.93a software. For binary
+distribution licensing of this software, please contact:
+
+<BLOCKQUOTE>
+Derek B. Noonburg<BR>
+Email: <A HREF="mailto:derekn@foolabs.com">derekn@foolabs.com</A><BR>
+WWW: <A HREF="http://www.foolabs.com/xpdf/">http://www.foolabs.com/xpdf/</A>
+</BLOCKQUOTE>
+
+<H3>Support</H3>
+
+<P>Easy Software Products sells software support for CUPS as well as a
+commercial printing product based on CUPS called ESP Print Pro. You can
+find out more at our web site:
+
+<UL><PRE>
+<A HREF="http://www.easysw.com">http://www.easysw.com</A>
+</PRE></UL>
+
+<!-- NEW PAGE -->
+<H2>GNU GENERAL PUBLIC LICENSE</H2>
+
+<P>Version 2, June 1991
+
+<PRE>
+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.
+<PRE>
+
+<H4>Preamble</H4>
+
+<P>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.
+
+<P>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.
+
+<P>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.
+
+<P>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.
+
+<P>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.
+
+<P>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.
+
+<P>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.
+
+<P>The precise terms and conditions for copying, distribution and
+modification follow.
+
+<H4>GNU GENERAL PUBLIC LICENSE<BR>
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION</H4>
+
+<OL START="0">
+
+<LI>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".
+
+<P>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.
+
+<LI>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.
+
+<P>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.
+
+<LI>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:
+
+<OL TYPE="a">
+
+<LI>You must cause the modified files to carry prominent notices
+stating that you changed the files and the date of any change.
+
+<LI>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.
+
+<LI>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.)
+
+</OL>
+
+<P>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.
+
+<P>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.
+
+<P>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.
+
+<LI>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:
+
+<OL TYPE="a">
+
+<LI>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,
+
+<LI>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,
+
+<LI>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.)
+
+</OL>
+
+<P>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.
+
+<P>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.
+
+<LI>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.
+
+<LI>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.
+
+<LI>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.
+
+<LI>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.
+
+<P>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.
+
+<P>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.
+
+<P>This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+<LI>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.
+
+<LI>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.
+
+<P>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.
+
+<LI>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.
+
+</OL>
+
+<H4>NO WARRANTY</H4>
+
+<OL START="11">
+
+<LI>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.
+
+<LI>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.
+
+</OL>
+
+<H4>END OF TERMS AND CONDITIONS</H4>
+
+<!-- NEW PAGE -->
+<H2>GNU LIBRARY GENERAL PUBLIC LICENSE</H2>
+
+<P>Version 2, June 1991
+
+<PRE>
+Copyright (C) 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.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+</PRE>
+
+<H4>Preamble</H4>
+
+<P>The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+<P>This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it. You can use it for
+your libraries, too.
+
+<P>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.
+
+<P>To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+<P>For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+<P>Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+<P>Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library. If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+
+<P>Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software. To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+<P>Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs. This
+license, the GNU Library General Public License, applies to certain
+designated libraries. This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+<P>The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it. Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program. However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+<P>Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries. We
+concluded that weaker conditions might promote sharing better.
+
+<P>However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them. (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.) The hope is that this
+will lead to faster development of free libraries.
+
+<P>The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+<P>Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+
+<H4>TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION</H4>
+
+<P><STRONG>0.</STRONG>
+This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License"). Each licensee is
+addressed as "you".
+
+<P>A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+<P>The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+<P>"Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+<P>Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+<P><STRONG>1.</STRONG>
+You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+<P>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.
+
+<P><STRONG>2.</STRONG>
+You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+<OL TYPE="a">
+
+ <LI>The modified work must itself be a software library.
+
+ <P>
+ <LI>You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ <P>
+ <LI>You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ <P>
+ <LI>If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ <P>(For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+</OL>
+
+<P>These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+<P>Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+<P>In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+<P><STRONG>3.</STRONG>
+You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+<P>Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+<P>This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+<P><STRONG>4.</STRONG>
+You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+<P>If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+<P><STRONG>5.</STRONG>
+A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+<P>However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+<P>When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+<P>If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+<P>Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+<P><STRONG>6.</STRONG>
+As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+<P>You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+<OL TYPE="a">
+
+ <LI>Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ <P>
+ <LI>Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ <P>
+ <LI>If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ <P>
+ <LI>Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+</OL>
+
+<P>For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+<P>It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+<P><STRONG>7.</STRONG>
+You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+<OL TYPE="a">
+
+ <LI>Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ <P>
+ <LI>Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+</OL>
+
+<P><STRONG>8.</STRONG>
+You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+<P><STRONG>9.</STRONG>
+You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+<P><STRONG>10.</STRONG>
+Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+<P><STRONG>11.</STRONG>
+If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+<P>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.
+
+<P>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.
+
+<P>This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+<P><STRONG>12.</STRONG>
+If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+<P><STRONG>13.</STRONG>
+The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+<P>Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+<P><STRONG>14.</STRONG>
+If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+<P><STRONG>NO WARRANTY</STRONG>
+
+<P><STRONG>15.</STRONG>
+BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+<P><STRONG>16.</STRONG>
+IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+<H4>END OF TERMS AND CONDITIONS</H4>
+
+</BODY>
+</HTML>
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 000000000..dcc0a5e53
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,812 @@
+ Common UNIX Printing System License Agreement
+
+ Copyright 1997-2002 by Easy Software Products
+ 44141 AIRPORT VIEW DR STE 204
+ HOLLYWOOD, MARYLAND 20636-3111 USA
+
+ Voice: +1.301.373.9600
+ Email: cups-info@cups.org
+ WWW: http://www.cups.org
+
+
+INTRODUCTION
+
+The Common UNIX Printing SystemTM, ("CUPSTM"), is provided under the GNU
+General Public License ("GPL") and GNU Library General Public License
+("LGPL"), Version 2. A copy of these licenses follow this introduction.
+
+The GNU LGPL applies to the CUPS API library, located in the "cups"
+subdirectory of the CUPS source distribution and in the "/usr/include/cups"
+directory and "libcups.a", "libcups_s.a", "libcups.sl", or "libcups.so"
+files in the binary distributions.
+
+The GNU GPL applies to the remainder of the CUPS distribution, including the
+"pstoraster" filter which is based upon GNU Ghostscript 5.50 and the
+"pdftops" filter which is based upon Xpdf 0.93a.
+
+For those not familiar with the GNU GPL, the license basically allows you
+to:
+
+ - Use the CUPS software at no charge.
+ - Distribute verbatim copies of the software in source or binary form.
+ - Sell verbatim copies of the software for a media fee, or sell support
+ for the software.
+ - Distribute or sell printer drivers and filters that use CUPS so long as
+ source code is made available under the GPL.
+
+What this license does not allow you to do is make changes or add features
+to CUPS and then sell a binary distribution without source code. You must
+provide source for any new drivers, changes, or additions to the software,
+and all code must be provided under the GPL or LGPL as appropriate.
+
+The GNU LGPL relaxes the "link-to" restriction, allowing you to develop
+applications that use the CUPS API library under other licenses and/or
+conditions as appropriate for your application.
+
+
+TRADEMARKS
+
+Easy Software Products has trademarked the Common UNIX Printing System,
+CUPS, and CUPS logo. These names and logos may be used freely in any direct
+port or binary distribution of CUPS. To use them in derivative products,
+please contract Easy Software Products for written permission. Our intention
+is to protect the value of these trademarks and ensure that any derivative
+product meets the same high-quality standards as the original.
+
+
+BINARY DISTRIBUTION RIGHTS
+
+Easy Software Products also sells rights to the CUPS source code under a
+binary distribution license for vendors that are unable to release source
+code for their drivers, additions, and modifications to CUPS under the GNU
+GPL and LGPL. For information please contact us at the address shown above.
+
+The Common UNIX Printing System provides a "pstoraster" filter that utilizes
+the GNU GhostScript 5.50 core to convert PostScript files into a stream of
+raster images. For binary distribution licensing of this software, please
+contact:
+
+ Miles Jones
+ 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
+
+The "pdftops" filter is based on the Xpdf 0.93a software. For binary
+distribution licensing of this software, please contact:
+
+ Derek B. Noonburg
+ Email: derekn@foolabs.com
+ WWW: http://www.foolabs.com/xpdf/
+
+
+SUPPORT
+
+Easy Software Products sells software support for CUPS as well as a
+commercial printing product based on CUPS called ESP Print Pro. You can find
+out more at our web site:
+
+ http://www.easysw.com
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 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
+
+ 0. 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.
+
+ 1. 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.
+
+ 2. 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:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) 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.
+
+ c) 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.
+
+ 3. 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:
+
+ a) 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,
+
+ b) 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,
+
+ c) 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.
+
+ 4. 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.
+
+ 5. 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.
+
+ 6. 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.
+
+ 7. 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.
+
+ 8. 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.
+
+ 9. 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.
+
+ 10. 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
+
+ 11. 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.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 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.
+
+ [This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it. You can use it for
+your libraries, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library. If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software. To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+ Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs. This
+license, the GNU Library General Public License, applies to certain
+designated libraries. This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+ The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it. Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program. However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+ Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries. We
+concluded that weaker conditions might promote sharing better.
+
+ However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them. (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.) The hope is that this
+will lead to faster development of free libraries.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+ Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License"). Each licensee is
+addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ c) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ d) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
diff --git a/Makedefs.in b/Makedefs.in
new file mode 100644
index 000000000..184e301f7
--- /dev/null
+++ b/Makedefs.in
@@ -0,0 +1,179 @@
+#
+# "$Id$"
+#
+# Common makefile definitions for the Common UNIX Printing System (CUPS).
+#
+# Copyright 1997-2002 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 = @LIBTOOL@ @CC@
+CXX = @LIBTOOL@ @CXX@
+DSO = @DSO@
+HTMLDOC = @HTMLDOC@
+INSTALL = @INSTALL@
+LIBTOOL = @LIBTOOL@
+LN = /bin/ln -sf
+MV = @MV@
+NROFF = @NROFF@
+RANLIB = @RANLIB@
+RM = @RM@ -f
+SED = @SED@
+SHELL = /bin/sh
+
+#
+# Installation programs...
+#
+
+INSTALL_BIN = $(LIBTOOL) $(INSTALL) -m 755 -s
+INSTALL_DATA = $(INSTALL) -m 644
+INSTALL_DIR = $(INSTALL) -d
+INSTALL_LIB = $(LIBTOOL) $(INSTALL) -m 755
+INSTALL_MAN = $(INSTALL) -m 644
+INSTALL_SCRIPT = $(INSTALL) -m 755
+
+#
+# Default user and group for the scheduler...
+#
+
+CUPS_USER = @CUPS_USER@
+CUPS_GROUP = @CUPS_GROUP@
+
+#
+# Libraries...
+#
+
+LIBCUPS = @LIBCUPS@
+LIBCUPSIMAGE = @LIBCUPSIMAGE@
+LIBJPEG = @LIBJPEG@
+LIBMALLOC = @LIBMALLOC@
+LIBPNG = @LIBPNG@
+LIBSLP = @LIBSLP@
+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 = @ARFLAGS@
+CFLAGS = @CFLAGS@ -I.. $(OPTIONS)
+CXXFLAGS = @CXXFLAGS@ -I.. $(OPTIONS)
+DSOFLAGS = @DSOFLAGS@
+DSOLIBS = @DSOLIBS@
+IMGLIBS = @IMGLIBS@ -lm
+LDFLAGS = @LDFLAGS@ $(OPTIM)
+LINKCUPS = @LINKCUPS@
+LINKCUPSIMAGE = @LINKCUPSIMAGE@
+LIBS = $(LINKCUPS) $(NETLIBS) @LIBS@
+NETLIBS = @NETLIBS@
+OPTIM = @OPTIM@
+OPTIONS =
+PAMLIBS = @PAMLIBS@
+SSLLIBS = @SSLLIBS@
+
+#
+# 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@
+
+AMANDIR = $(BUILDROOT)@AMANDIR@
+BINDIR = $(BUILDROOT)@bindir@
+DATADIR = $(BUILDROOT)@CUPS_DATADIR@
+DOCDIR = $(BUILDROOT)@CUPS_DOCROOT@
+INCLUDEDIR = $(BUILDROOT)$(includedir)
+INITDIR = @INITDIR@
+INITDDIR = @INITDDIR@
+LIBDIR = $(BUILDROOT)$(libdir)
+LOCALEDIR = $(BUILDROOT)@CUPS_LOCALEDIR@
+LOGDIR = $(BUILDROOT)@CUPS_LOGDIR@
+MANDIR = $(BUILDROOT)@mandir@
+PAMDIR = $(BUILDROOT)@PAMDIR@
+PMANDIR = $(BUILDROOT)@PMANDIR@
+REQUESTS = $(BUILDROOT)@CUPS_REQUESTS@
+SBINDIR = $(BUILDROOT)@sbindir@
+SERVERBIN = $(BUILDROOT)@CUPS_SERVERBIN@
+SERVERROOT = $(BUILDROOT)@CUPS_SERVERROOT@
+
+CAT1EXT = @CAT1EXT@
+CAT3EXT = @CAT3EXT@
+CAT5EXT = @CAT5EXT@
+CAT8EXT = @CAT8EXT@
+MAN8EXT = @MAN8EXT@
+MAN8DIR = @MAN8DIR@
+
+#
+# Rules...
+#
+
+.SILENT:
+.SUFFIXES: .a .c .cxx .h .man .o .0 .1 .1m .3 .5 .8 .z
+.c.o:
+ echo Compiling $<...
+ $(CC) $(OPTIM) $(CFLAGS) -c $<
+.cxx.o:
+ echo Compiling $<...
+ $(CXX) $(OPTIM) $(CXXFLAGS) -c $<
+.man.0 .man.1 .man.1m .man.3 .man.5 .man.8:
+ echo Formatting $<...
+ $(RM) $@
+ $(NROFF) -man $< >$@
+.man.z:
+ echo Formatting $<...
+ $(RM) $@ t.z
+ $(NROFF) -man $< >t
+ pack -f t
+ $(MV) t.z $@
+
+#
+# End of "$Id$"
+#
diff --git a/Makefile b/Makefile
new file mode 100644
index 000000000..a674b3ad0
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,148 @@
+#
+# "$Id$"
+#
+# Top-level Makefile for the Common UNIX Printing System (CUPS).
+#
+# Copyright 1997-2002 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 pdftops pstoraster \
+ scheduler systemv
+
+#
+# Make all targets...
+#
+
+all:
+ chmod +x cups-config
+ for dir in $(DIRS); do\
+ echo Making all in $$dir... ;\
+ (cd $$dir ; $(MAKE) $(MFLAGS)) || exit 1;\
+ done
+
+#
+# Remove object and target files...
+#
+
+clean:
+ for dir in $(DIRS); do\
+ echo Cleaning in $$dir... ;\
+ (cd $$dir; $(MAKE) $(MFLAGS) clean) || exit 1;\
+ done
+
+#
+# Install object and target files...
+#
+
+install:
+ for dir in $(DIRS); do\
+ echo Installing in $$dir... ;\
+ (cd $$dir; $(MAKE) $(MFLAGS) install) || exit 1;\
+ done
+ echo Installing in conf...
+ (cd conf; $(MAKE) $(MFLAGS) install)
+ echo Installing in data...
+ (cd data; $(MAKE) $(MFLAGS) install)
+ echo Installing in doc...
+ (cd doc; $(MAKE) $(MFLAGS) install)
+ echo Installing in fonts...
+ (cd fonts; $(MAKE) $(MFLAGS) install)
+ echo Installing in locale...
+ (cd locale; $(MAKE) $(MFLAGS) install)
+ echo Installing in ppd...
+ (cd ppd; $(MAKE) $(MFLAGS) install)
+ echo Installing in templates...
+ (cd templates; $(MAKE) $(MFLAGS) install)
+ echo Installing cups-config script...
+ $(INSTALL_DIR) $(BINDIR)
+ $(INSTALL_SCRIPT) cups-config $(BINDIR)/cups-config
+ echo Installing startup script...
+ if test "x$(INITDIR)" != "x"; then \
+ $(INSTALL_DIR) $(BUILDROOT)$(INITDIR)/init.d; \
+ $(INSTALL_SCRIPT) cups.sh $(BUILDROOT)$(INITDIR)/init.d/cups; \
+ $(INSTALL_DIR) $(BUILDROOT)$(INITDIR)/rc0.d; \
+ $(INSTALL_SCRIPT) cups.sh $(BUILDROOT)$(INITDIR)/rc0.d/K00cups; \
+ $(INSTALL_DIR) $(BUILDROOT)$(INITDIR)/rc2.d; \
+ $(INSTALL_SCRIPT) cups.sh $(BUILDROOT)$(INITDIR)/rc2.d/S99cups; \
+ $(INSTALL_DIR) $(BUILDROOT)$(INITDIR)/rc3.d; \
+ $(INSTALL_SCRIPT) cups.sh $(BUILDROOT)$(INITDIR)/rc3.d/S99cups; \
+ $(INSTALL_DIR) $(BUILDROOT)$(INITDIR)/rc5.d; \
+ $(INSTALL_SCRIPT) cups.sh $(BUILDROOT)$(INITDIR)/rc5.d/S99cups; \
+ fi
+ if test "x$(INITDIR)" = "x" -a "x$(INITDDIR)" != "x"; then \
+ $(INSTALL_DIR) $(BUILDROOT)$(INITDDIR); \
+ if test "$(INITDDIR)" = "/System/Library/StartupItems/CUPS"; then \
+ $(INSTALL_SCRIPT) cups.sh $(BUILDROOT)$(INITDDIR)/CUPS; \
+ $(INSTALL_DATA) cups.plist $(BUILDROOT)$(INITDDIR)/StartupParameters.plist; \
+ $(INSTALL_DIR) $(BUILDROOT)$(INITDDIR)/Resources/English.lproj; \
+ $(INSTALL_DATA) cups.strings $(BUILDROOT)$(INITDDIR)/Resources/English.lproj/Localizable.strings; \
+ else \
+ $(INSTALL_SCRIPT) cups.sh $(BUILDROOT)$(INITDDIR)/cups; \
+ fi \
+ fi
+
+
+#
+# Run the test suite...
+#
+
+test: all
+ echo Running CUPS test suite...
+ cd test; ./run-stp-tests.sh
+
+
+#
+# Make software distributions using EPM (http://www.easysw.com/epm)...
+#
+
+EPMFLAGS = -v
+
+aix:
+ epm $(EPMFLAGS) -f aix cups
+
+bsd:
+ epm $(EPMFLAGS) -f bsd cups
+
+epm:
+ epm $(EPMFLAGS) cups
+
+rpm:
+ epm $(EPMFLAGS) -f rpm cups
+
+deb:
+ epm $(EPMFLAGS) -f deb cups
+
+depot:
+ epm $(EPMFLAGS) -f depot cups
+
+pkg:
+ epm $(EPMFLAGS) -f pkg cups
+
+tardist:
+ epm $(EPMFLAGS) -f tardist cups
+
+#
+# End of "$Id$".
+#
diff --git a/README.txt b/README.txt
new file mode 100644
index 000000000..719de20f1
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,283 @@
+README - CUPS v1.1.13 - 01/31/2002
+----------------------------------
+
+Looking for compile instructions? Read the file "INSTALL.txt"
+instead...
+
+
+INTRODUCTION
+
+CUPS provides a portable printing layer for UNIX(r)-based
+operating systems. It has been developed by Easy Software
+Products to promote a standard printing solution for all UNIX
+vendors and users. CUPS provides the System V and Berkeley
+command-line interfaces.
+
+CUPS uses the Internet Printing Protocol ("IPP") as the basis
+for managing print jobs and queues. The Line Printer Daemon
+("LPD") Server Message Block ("SMB"), and AppSocket (a.k.a.
+JetDirect) protocols are also supported with reduced
+functionality. CUPS adds network printer browsing and
+PostScript Printer Description ("PPD") based printing options to
+support real-world printing under UNIX.
+
+CUPS also includes a customized version of GNU Ghostscript
+(currently based off GNU Ghostscript 5.50) and an image file RIP
+that are used to support non-PostScript printers. Sample
+drivers for HP and EPSON printers are included that use these
+filters.
+
+Drivers for thousands of printers are provided with our ESP
+Print Pro software, available at:
+
+ http://www.easysw.com/printpro
+
+CUPS is licensed under the GNU General Public License and GNU
+Library General Public License. Please contact Easy Software
+Products for commercial support and "binary distribution"
+rights.
+
+
+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 ANSI-compliant C
+and C++ compilers and optionally one or more image file support
+libraries. Complete source installation instructions can be
+found in the file "INSTALL.txt".
+
+
+SOFTWARE REQUIREMENTS
+
+The following operating system software is required to install
+one of the binary distributions from Easy Software Products:
+
+ - AIX 4.3 or higher
+ - Compaq Tru64 UNIX (aka OSF1 aka Digital UNIX) 4.0 or higher
+ - HP-UX 10.20 or higher
+ - IRIX 5.3 or higher
+ - Linux 2.0 with glibc2 or higher
+ - Solaris 2.5 or higher (SPARC or Intel)
+
+
+INSTALLING "PORTABLE" CUPS DISTRIBUTIONS
+
+We are currently distributing "portable" 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.
+
+
+INSTALLING HOST-SPECIFIC (RPM, DEBIAN, ETC.) DISTRIBUTIONS
+
+The host-specific distributions use the operating system
+software installation tools. To install a host-specific
+distribution please consult the CUPS Software Administrators
+Manual or your operating system documentation.
+
+
+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/doc/cups" directory in the binary
+distributions, and under the "doc" directory in the source
+archives.
+
+Please read the documentation before asking questions.
+
+
+GETTING SUPPORT AND OTHER RESOURCES
+
+If you have problems, READ THE DOCUMENTATION FIRST!
+
+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.
+
+Commercial support (with a guaranteed response time) is
+available from Easy Software Products. For more information
+see:
+
+ http://www.easysw.com/cups
+
+See the CUPS web site at "http://www.cups.org" for other site
+links.
+
+
+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.
+
+DO NOT use the hostname for your machine - it will not work with
+the default CUPS configuration. To enable administration access
+on other addresses, consult the CUPS Software Administrators
+Manual.
+
+
+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
+ ----------------------------- ------------
+ Dymo Label Printers dymo.ppd
+ EPSON Stylus Color Series stcolor.ppd
+ EPSON Stylus Photo Series stphoto.ppd
+ EPSON Stylus New Color Series stcolor2.ppd
+ EPSON Stylus New Photo Series stphoto2.ppd
+ EPSON 9-pin Series epson9.ppd
+ EPSON 24-pin Series epson24.ppd
+ HP DeskJet Series deskjet.ppd
+ HP New DeskJet Series deskjet2.ppd
+ HP LaserJet Series laserjet.ppd
+ OKIDATA 9-Pin Series okidata9.ppd
+ OKIDATA 24-Pin Series okidat24.ppd
+
+These sample drivers provide basic printing capabilities, but
+generally do not exercise the full potential of the printers or
+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 PDF,
+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.
+
+
+LEGAL STUFF
+
+CUPS is Copyright 1993-2002 by Easy Software Products. CUPS,
+the CUPS logo, and the Common UNIX Printing System are the
+trademark property of Easy Software Products.
+
+The MD5 Digest code is Copyright 1999 Aladdin Enterprises.
+
+The PostScript RIP software (pstoraster) is based on the GNU
+Ghostscript 5.50 core, Copyright 1986-1998 by Aladdin
+Enterprises.
+
+The PDF filter (pdftops) is based on the Xpdf 0.92 software,
+Copyright 1996-2002 by Derek B. Noonburg.
+
+This software is based in part on the work of the Independent
+JPEG Group.
+
+CUPS is provided under the terms of the GNU General Public
+License and GNU Library General Public License. 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 "LICENSE.html",
+"LICENSE.txt", or "cups.license" files for more information.
+
+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.9600
+ Email: cups-info@cups.org
+ WWW: http://www.cups.org
+
+Note that commercial licensors may also require a license from
+Artifex Software Inc. which handles commercial licensing of the
+Ghostscript software, and from Derek B. Noonburg who developed
+the Xpdf software used to print PDF files.
diff --git a/backend/.cvsignore b/backend/.cvsignore
new file mode 100644
index 000000000..e78e89c08
--- /dev/null
+++ b/backend/.cvsignore
@@ -0,0 +1,7 @@
+ipp
+lpd
+usb
+parallel
+betest
+serial
+socket
diff --git a/backend/Makefile b/backend/Makefile
new file mode 100644
index 000000000..4d1f23ad9
--- /dev/null
+++ b/backend/Makefile
@@ -0,0 +1,141 @@
+#
+# "$Id$"
+#
+# Backend makefile for the Common UNIX Printing System (CUPS).
+#
+# Copyright 1997-2002 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) http
+
+
+#
+# Install all targets...
+#
+
+install:
+ $(INSTALL_DIR) $(SERVERBIN)/backend
+ for file in $(BACKENDS); do \
+ $(INSTALL_BIN) $$file $(SERVERBIN)/backend; \
+ done
+ $(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 000000000..7d041c966
--- /dev/null
+++ b/backend/betest.c
@@ -0,0 +1,85 @@
+/*
+ * "$Id$"
+ *
+ * Backend test program for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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 <stdio.h>
+#include <stdlib.h>
+#include <cups/string.h>
+#include <unistd.h>
+
+
+/*
+ * '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 000000000..1d3ddf186
--- /dev/null
+++ b/backend/ipp.c
@@ -0,0 +1,793 @@
+/*
+ * "$Id$"
+ *
+ * IPP backend for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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.
+ * password_cb() - Disable the password prompt for
+ * cupsDoFileRequest().
+ * report_printer_state() - Report the printer state.
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <cups/cups.h>
+#include <cups/language.h>
+#include <cups/string.h>
+#include <signal.h>
+
+
+/*
+ * Local functions...
+ */
+
+const char *password_cb(const char *);
+int report_printer_state(ipp_t *ipp);
+
+
+/*
+ * Local globals...
+ */
+
+char *password = NULL;
+
+
+/*
+ * '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 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 uri[HTTP_MAX_URI];/* Updated URI without user/pass */
+ ipp_status_t ipp_status; /* Status of IPP request */
+ http_t *http; /* HTTP connection */
+ ipp_t *request, /* IPP request */
+ *response, /* IPP response */
+ *supported; /* get-printer-attributes response */
+ ipp_attribute_t *job_id_attr; /* job-id attribute */
+ int job_id; /* job-id value */
+ ipp_attribute_t *job_state; /* job-state attribute */
+ ipp_attribute_t *copies_sup; /* copies-supported attribute */
+ ipp_attribute_t *charset_sup; /* charset-supported attribute */
+ ipp_attribute_t *format_sup; /* document-format-supported attribute */
+ const char *charset; /* Character set to use */
+ cups_lang_t *language; /* Default language */
+ int copies; /* Number of copies remaining */
+ const char *content_type; /* CONTENT_TYPE environment variable */
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ struct sigaction action; /* Actions for POSIX signals */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+ int version; /* IPP version */
+ int reasons; /* Number of printer-state-reasons shown */
+
+
+ /*
+ * Make sure status messages are not buffered...
+ */
+
+ setbuf(stderr, NULL);
+
+ /*
+ * Check command-line...
+ */
+
+ if (argc == 1)
+ {
+ char *s;
+
+ if ((s = strrchr(argv[0], '/')) != NULL)
+ s ++;
+ else
+ s = argv[0];
+
+ printf("network %s \"Unknown\" \"Internet Printing Protocol (%s)\"\n", s, 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...
+ */
+
+ int fd; /* Temporary file */
+ char buffer[8192]; /* Buffer for copying */
+ int bytes; /* Number of bytes read */
+
+
+ if ((fd = cupsTempFd(filename, sizeof(filename))) < 0)
+ {
+ perror("ERROR: unable to create temporary file");
+ return (1);
+ }
+
+ while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0)
+ if (write(fd, buffer, bytes) < bytes)
+ {
+ perror("ERROR: unable to write to temporary file");
+ close(fd);
+ unlink(filename);
+ return (1);
+ }
+
+ close(fd);
+ }
+ 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);
+
+ /*
+ * Set the authentication info, if any...
+ */
+
+ cupsSetPasswordCB(password_cb);
+
+ if (username[0])
+ {
+ if ((password = strchr(username, ':')) != NULL)
+ *password++ = '\0';
+
+ cupsSetUser(username);
+ }
+
+ /*
+ * 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();
+ charset_sup = NULL;
+ copies_sup = NULL;
+ format_sup = NULL;
+ version = 1;
+ supported = NULL;
+
+ do
+ {
+ /*
+ * Build the IPP request...
+ */
+
+ request = ippNew();
+ request->request.op.version[1] = version;
+ 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, "utf-8");
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL,
+ language != NULL ? language->language : "en");
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, uri);
+
+ /*
+ * Do the request...
+ */
+
+ if ((supported = cupsDoRequest(http, request, resource)) == NULL)
+ ipp_status = cupsLastError();
+ else
+ ipp_status = supported->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);
+ report_printer_state(supported);
+ sleep(10);
+ }
+ else if ((ipp_status == IPP_BAD_REQUEST ||
+ ipp_status == IPP_VERSION_NOT_SUPPORTED) && version == 1)
+ {
+ /*
+ * Switch to IPP/1.0...
+ */
+
+ fputs("INFO: Printer does not support IPP/1.1, trying IPP/1.0...\n", stderr);
+ version = 0;
+ }
+ else
+ fprintf(stderr, "ERROR: Unable to get printer status (%s)!\n",
+ ippErrorString(ipp_status));
+
+ if (supported)
+ ippDelete(supported);
+
+ continue;
+ }
+ else if ((copies_sup = ippFindAttribute(supported, "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 */
+ }
+
+ charset_sup = ippFindAttribute(supported, "charset-supported",
+ IPP_TAG_CHARSET);
+ format_sup = ippFindAttribute(supported, "document-format-supported",
+ IPP_TAG_MIMETYPE);
+
+ if (format_sup)
+ {
+ fprintf(stderr, "DEBUG: document-format-supported (%d values)\n",
+ format_sup->num_values);
+ for (i = 0; i < format_sup->num_values; i ++)
+ fprintf(stderr, "DEBUG: [%d] = \"%s\"\n", i,
+ format_sup->values[i].string.text);
+ }
+
+ report_printer_state(supported);
+ }
+ while (ipp_status > IPP_OK_CONFLICT);
+
+ /*
+ * Now that we are "connected" to the port, ignore SIGTERM so that we
+ * can finish out any page data the driver sends (e.g. to eject the
+ * current page... Only ignore SIGTERM if we are printing data from
+ * stdin (otherwise you can't cancel raw jobs...)
+ */
+
+ if (argc < 7)
+ {
+#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
+ sigset(SIGTERM, SIG_IGN);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+
+ sigemptyset(&action.sa_mask);
+ action.sa_handler = SIG_IGN;
+ sigaction(SIGTERM, &action, NULL);
+#else
+ signal(SIGTERM, SIG_IGN);
+#endif /* HAVE_SIGSET */
+ }
+
+ /*
+ * See if the printer supports multiple copies...
+ */
+
+ if (copies_sup || argc < 7)
+ copies = 1;
+ else
+ copies = atoi(argv[4]);
+
+ /*
+ * Figure out the character set to use...
+ */
+
+ charset = language ? cupsLangEncoding(language) : "us-ascii";
+
+ if (charset_sup)
+ {
+ /*
+ * See if IPP server supports the requested character set...
+ */
+
+ for (i = 0; i < charset_sup->num_values; i ++)
+ if (strcasecmp(charset, charset_sup->values[i].string.text) == 0)
+ break;
+
+ /*
+ * If not, choose us-ascii or utf-8...
+ */
+
+ if (i >= charset_sup->num_values)
+ {
+ /*
+ * See if us-ascii is supported...
+ */
+
+ for (i = 0; i < charset_sup->num_values; i ++)
+ if (strcasecmp("us-ascii", charset_sup->values[i].string.text) == 0)
+ break;
+
+ if (i < charset_sup->num_values)
+ charset = "us-ascii";
+ else
+ charset = "utf-8";
+ }
+ }
+
+ /*
+ * Then issue the print-job request...
+ */
+
+ reasons = 0;
+
+ while (copies > 0)
+ {
+ /*
+ * Build the IPP request...
+ */
+
+ request = ippNew();
+ request->request.op.version[1] = version;
+ 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, charset);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL,
+ language != NULL ? language->language : "en");
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, uri);
+
+ fprintf(stderr, "DEBUG: printer-uri = \"%s\"\n", uri);
+
+ if (argv[2][0])
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, argv[2]);
+
+ fprintf(stderr, "DEBUG: requesting-user-name = \"%s\"\n", argv[2]);
+
+ if (argv[3][0])
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
+ argv[3]);
+
+ fprintf(stderr, "DEBUG: job-name = \"%s\"\n", argv[3]);
+
+ /*
+ * Handle options on the command-line...
+ */
+
+ options = NULL;
+ num_options = cupsParseOptions(argv[5], 0, &options);
+
+ if (argc > 6)
+ content_type = getenv("CONTENT_TYPE");
+ else
+ content_type = "application/vnd.cups-raw";
+
+ if (content_type != NULL && format_sup != NULL)
+ {
+ for (i = 0; i < format_sup->num_values; i ++)
+ if (strcasecmp(content_type, format_sup->values[i].string.text) == 0)
+ break;
+
+ if (i < format_sup->num_values)
+ num_options = cupsAddOption("document-format", content_type,
+ num_options, &options);
+ }
+
+ if (copies_sup)
+ {
+ /*
+ * Only send options if the destination printer supports the copies
+ * attribute. This is a hack for the HP JetDirect implementation of
+ * IPP, which does not accept extension attributes and incorrectly
+ * reports a client-error-bad-request error instead of the
+ * successful-ok-unsupported-attributes status. In short, at least
+ * some HP implementations of IPP are non-compliant.
+ */
+
+ cupsEncodeOptions(request, num_options, options);
+ ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_INTEGER, "copies",
+ atoi(argv[4]));
+ }
+
+ cupsFreeOptions(num_options, options);
+
+ /*
+ * Do the request...
+ */
+
+ if ((response = cupsDoFileRequest(http, request, resource, filename)) == NULL)
+ ipp_status = cupsLastError();
+ else
+ ipp_status = response->request.status.status_code;
+
+ if (ipp_status > IPP_OK_CONFLICT)
+ {
+ job_id = 0;
+
+ 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 (%s)!\n",
+ ippErrorString(ipp_status));
+ }
+ else if ((job_id_attr = ippFindAttribute(response, "job-id",
+ IPP_TAG_INTEGER)) == NULL)
+ {
+ fputs("INFO: Print file accepted - job ID unknown.\n", stderr);
+ job_id = 0;
+ }
+ else
+ {
+ job_id = job_id_attr->values[0].integer;
+ fprintf(stderr, "INFO: Print file accepted - job ID %d.\n", job_id);
+ }
+
+ if (response)
+ ippDelete(response);
+
+ if (ipp_status <= IPP_OK_CONFLICT && argc > 6)
+ {
+ 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;
+
+ /*
+ * Wait for the job to complete...
+ */
+
+ if (!job_id)
+ continue;
+
+ fputs("INFO: Waiting for job to complete...\n", stderr);
+
+ for (;;)
+ {
+ /*
+ * Build an IPP_GET_JOB_ATTRIBUTES request...
+ */
+
+ request = ippNew();
+ request->request.op.version[1] = version;
+ request->request.op.operation_id = IPP_GET_JOB_ATTRIBUTES;
+ request->request.op.request_id = 1;
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, charset);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL,
+ language != NULL ? language->language : "en");
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, uri);
+
+ ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id",
+ job_id);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes", NULL, "job-state");
+
+ /*
+ * Do the request...
+ */
+
+ if ((response = cupsDoRequest(http, request, resource)) == NULL)
+ ipp_status = cupsLastError();
+ else
+ ipp_status = response->request.status.status_code;
+
+ if (ipp_status == IPP_NOT_FOUND)
+ {
+ /*
+ * Job has gone away and/or the server has no job history...
+ */
+
+ ippDelete(response);
+
+ ipp_status = IPP_OK;
+ break;
+ }
+
+ if (ipp_status > IPP_OK_CONFLICT)
+ {
+ if (ipp_status != IPP_SERVICE_UNAVAILABLE &&
+ ipp_status != IPP_PRINTER_BUSY)
+ {
+ if (response)
+ ippDelete(response);
+
+ fprintf(stderr, "ERROR: Unable to get job %d attributes (%s)!\n",
+ job_id, ippErrorString(ipp_status));
+ break;
+ }
+ }
+ else if ((job_state = ippFindAttribute(response, "job-state", IPP_TAG_ENUM)) != NULL)
+ {
+ /*
+ * Stop polling if the job is finished or pending-held...
+ */
+
+ if (job_state->values[0].integer > IPP_JOB_PROCESSING ||
+ job_state->values[0].integer == IPP_JOB_HELD)
+ {
+ ippDelete(response);
+ break;
+ }
+ }
+
+ if (response)
+ ippDelete(response);
+
+
+ /*
+ * Now check on the printer state...
+ */
+
+ request = ippNew();
+ request->request.op.version[1] = version;
+ 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, charset);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL,
+ language != NULL ? language->language : "en");
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, uri);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes", NULL, "job-state-reasons");
+
+ /*
+ * Do the request...
+ */
+
+ if ((response = cupsDoRequest(http, request, resource)) != NULL)
+ {
+ reasons = report_printer_state(response);
+ ippDelete(response);
+ }
+
+ /*
+ * Wait 10 seconds before polling again...
+ */
+
+ sleep(10);
+ }
+ }
+
+ /*
+ * Free memory...
+ */
+
+ httpClose(http);
+
+ if (supported)
+ ippDelete(supported);
+
+ /*
+ * Close and remove the temporary file if necessary...
+ */
+
+ if (argc < 7)
+ unlink(filename);
+
+ /*
+ * Return the queue status...
+ */
+
+ if (ipp_status <= IPP_OK_CONFLICT && reasons == 0)
+ fputs("INFO: Ready to print.\n", stderr);
+
+ return (ipp_status > IPP_OK_CONFLICT);
+}
+
+
+/*
+ * 'password_cb()' - Disable the password prompt for cupsDoFileRequest().
+ */
+
+const char * /* O - Password */
+password_cb(const char *prompt) /* I - Prompt (not used) */
+{
+ (void)prompt;
+
+ return (password);
+}
+
+
+/*
+ * 'report_printer_state()' - Report the printer state.
+ */
+
+int /* O - Number of reasons shown */
+report_printer_state(ipp_t *ipp) /* I - IPP response */
+{
+ int i; /* Looping var */
+ int count; /* Count of reasons shown... */
+ ipp_attribute_t *reasons; /* printer-state-reasons */
+ const char *message; /* Message to show */
+ char unknown[1024]; /* Unknown message string */
+
+
+ if ((reasons = ippFindAttribute(ipp, "printer-state-reasons",
+ IPP_TAG_KEYWORD)) == NULL)
+ return (0);
+
+ for (i = 0, count = 0; i < reasons->num_values; i ++)
+ {
+ message = NULL;
+
+ if (strncmp(reasons->values[i].string.text, "media-needed", 12) == 0)
+ message = "Media tray needs to be filled.";
+ else if (strncmp(reasons->values[i].string.text, "media-jam", 9) == 0)
+ message = "Media jam!";
+ else if (strncmp(reasons->values[i].string.text, "moving-to-paused", 16) == 0 ||
+ strncmp(reasons->values[i].string.text, "paused", 6) == 0 ||
+ strncmp(reasons->values[i].string.text, "shutdown", 8) == 0)
+ message = "Printer off-line.";
+ else if (strncmp(reasons->values[i].string.text, "toner-low", 9) == 0)
+ message = "Toner low.";
+ else if (strncmp(reasons->values[i].string.text, "toner-empty", 11) == 0)
+ message = "Out of toner!";
+ else if (strncmp(reasons->values[i].string.text, "cover-open", 10) == 0)
+ message = "Cover open.";
+ else if (strncmp(reasons->values[i].string.text, "interlock-open", 14) == 0)
+ message = "Interlock open.";
+ else if (strncmp(reasons->values[i].string.text, "door-open", 9) == 0)
+ message = "Door open.";
+ else if (strncmp(reasons->values[i].string.text, "input-tray-missing", 18) == 0)
+ message = "Media tray missing!";
+ else if (strncmp(reasons->values[i].string.text, "media-low", 9) == 0)
+ message = "Media tray almost empty.";
+ else if (strncmp(reasons->values[i].string.text, "media-empty", 11) == 0)
+ message = "Media tray empty!";
+ else if (strncmp(reasons->values[i].string.text, "output-tray-missing", 19) == 0)
+ message = "Output tray missing!";
+ else if (strncmp(reasons->values[i].string.text, "output-area-almost-full", 23) == 0)
+ message = "Output bin almost full.";
+ else if (strncmp(reasons->values[i].string.text, "output-area-full", 16) == 0)
+ message = "Output bin full!";
+ else if (strncmp(reasons->values[i].string.text, "marker-supply-low", 17) == 0)
+ message = "Ink/toner almost empty.";
+ else if (strncmp(reasons->values[i].string.text, "marker-supply-empty", 19) == 0)
+ message = "Ink/toner empty!";
+ else if (strncmp(reasons->values[i].string.text, "marker-waste-almost-full", 24) == 0)
+ message = "Ink/toner waste bin almost full.";
+ else if (strncmp(reasons->values[i].string.text, "marker-waste-full", 17) == 0)
+ message = "Ink/toner waste bin full!";
+ else if (strncmp(reasons->values[i].string.text, "fuser-over-temp", 15) == 0)
+ message = "Fuser temperature high!";
+ else if (strncmp(reasons->values[i].string.text, "fuser-under-temp", 16) == 0)
+ message = "Fuser temperature low!";
+ else if (strncmp(reasons->values[i].string.text, "opc-near-eol", 12) == 0)
+ message = "OPC almost at end-of-life.";
+ else if (strncmp(reasons->values[i].string.text, "opc-life-over", 13) == 0)
+ message = "OPC at end-of-life!";
+ else if (strncmp(reasons->values[i].string.text, "developer-low", 13) == 0)
+ message = "Developer almost empty.";
+ else if (strncmp(reasons->values[i].string.text, "developer-empty", 15) == 0)
+ message = "Developer empty!";
+ else if (strstr(reasons->values[i].string.text, "error") != NULL)
+ {
+ message = unknown;
+
+ snprintf(unknown, sizeof(unknown), "Unknown printer error (%s)!",
+ reasons->values[i].string.text);
+ }
+
+ if (message)
+ {
+ count ++;
+ if (strstr(reasons->values[i].string.text, "error"))
+ fprintf(stderr, "ERROR: %s\n", message);
+ else if (strstr(reasons->values[i].string.text, "warning"))
+ fprintf(stderr, "WARNING: %s\n", message);
+ else
+ fprintf(stderr, "INFO: %s\n", message);
+ }
+ }
+
+ return (count);
+}
+
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/backend/lpd.c b/backend/lpd.c
new file mode 100644
index 000000000..5c884520c
--- /dev/null
+++ b/backend/lpd.c
@@ -0,0 +1,765 @@
+/*
+ * "$Id$"
+ *
+ * Line Printer Daemon backend for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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.
+ * lpd_write() - Write a buffer of data to an LPD server.
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include <cups/cups.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <cups/string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+
+#ifdef WIN32
+# include <winsock.h>
+#else
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
+# include <netdb.h>
+#endif /* WIN32 */
+
+
+/*
+ * The order for control and data files in LPD requests...
+ */
+
+#define ORDER_CONTROL_DATA 0
+#define ORDER_DATA_CONTROL 1
+
+
+/*
+ * It appears that rresvport() is never declared on most systems...
+ */
+
+extern int rresvport(int *port);
+
+
+/*
+ * Local functions...
+ */
+
+static int lpd_command(int lpd_fd, char *format, ...);
+static int lpd_queue(char *hostname, char *printer, char *filename,
+ int fromstdin, char *user, char *title, int copies,
+ int banner, int format, int order);
+static int lpd_write(int lpd_fd, char *buffer, int length);
+
+
+/*
+ * '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) */
+ *options, /* Pointer to options */
+ name[255], /* Name of option */
+ value[255], /* Value of option */
+ *ptr, /* Pointer into name or value */
+ filename[1024], /* File to print */
+ title[256]; /* Title string */
+ int port; /* Port number (not used) */
+ int status; /* Status of LPD job */
+ int banner; /* Print banner page? */
+ int format; /* Print format */
+ int order; /* Order of control/data files */
+
+
+ /*
+ * Make sure status messages are not buffered...
+ */
+
+ setbuf(stderr, NULL);
+
+ /*
+ * Check command-line...
+ */
+
+ 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...
+ */
+
+ int fd; /* Temporary file */
+ char buffer[8192]; /* Buffer for copying */
+ int bytes; /* Number of bytes read */
+
+
+ if ((fd = cupsTempFd(filename, sizeof(filename))) < 0)
+ {
+ perror("ERROR: unable to create temporary file");
+ return (1);
+ }
+
+ while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0)
+ if (write(fd, buffer, bytes) < bytes)
+ {
+ perror("ERROR: unable to write to temporary file");
+ close(fd);
+ unlink(filename);
+ return (1);
+ }
+
+ close(fd);
+ }
+ 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);
+
+ /*
+ * See if there are any options...
+ */
+
+ banner = 0;
+ format = 'l';
+ order = ORDER_CONTROL_DATA;
+
+ if ((options = strchr(resource, '?')) != NULL)
+ {
+ /*
+ * Yup, terminate the device name string and move to the first
+ * character of the options...
+ */
+
+ *options++ = '\0';
+
+ /*
+ * Parse options...
+ */
+
+ 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, "banner") == 0)
+ {
+ /*
+ * Set the banner...
+ */
+
+ banner = !value[0] ||
+ strcasecmp(value, "on") == 0 ||
+ strcasecmp(value, "yes") == 0 ||
+ strcasecmp(value, "true") == 0;
+ }
+ else if (strcasecmp(name, "format") == 0 && value[0])
+ {
+ /*
+ * Set output format...
+ */
+
+ if (strchr("cdfglnoprtv", value[0]) != NULL)
+ format = value[0];
+ else
+ fprintf(stderr, "ERROR: Unknown format character \"%c\"\n", value[0]);
+ }
+ else if (strcasecmp(name, "order") == 0 && value[0])
+ {
+ /*
+ * Set control/data order...
+ */
+
+ if (strcasecmp(value, "control,data") == 0)
+ order = ORDER_CONTROL_DATA;
+ else if (strcasecmp(value, "data,control") == 0)
+ order = ORDER_DATA_CONTROL;
+ else
+ fprintf(stderr, "ERROR: Unknown file order \"%s\"\n", value);
+ }
+ }
+ }
+
+ /*
+ * Sanitize the document title...
+ */
+
+ strncpy(title, argv[3], sizeof(title) - 1);
+ title[sizeof(title) - 1] = '\0';
+
+ for (ptr = title; *ptr; ptr ++)
+ if (!isalnum(*ptr) && !isspace(*ptr))
+ *ptr = '_';
+
+ /*
+ * Queue the job...
+ */
+
+ if (argc > 6)
+ {
+ status = lpd_queue(hostname, resource + 1, filename, 0,
+ argv[2] /* user */, title, atoi(argv[4]) /* copies */,
+ banner, format, order);
+
+ if (!status)
+ fprintf(stderr, "PAGE: 1 %d\n", atoi(argv[4]));
+ }
+ else
+ status = lpd_queue(hostname, resource + 1, filename, 1,
+ argv[2] /* user */, title, 1, banner, format, order);
+
+ /*
+ * 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 %2.2x %s", buf[0], buf + 1);
+
+ /*
+ * Send the command...
+ */
+
+ fprintf(stderr, "DEBUG: Sending command string (%d bytes)...\n", bytes);
+
+ if (lpd_write(fd, buf, bytes) < bytes)
+ return (-1);
+
+ /*
+ * Read back the status from the command and return it...
+ */
+
+ fprintf(stderr, "DEBUG: Reading command status...\n");
+
+ 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 */
+ int fromstdin, /* I - Printing from stdin? */
+ char *user, /* I - Requesting user */
+ char *title, /* I - Job title */
+ int copies, /* I - Number of copies */
+ int banner, /* I - Print LPD banner? */
+ int format, /* I - Format specifier */
+ int order) /* I - Order of data/control files */
+{
+ 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 */
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ struct sigaction action; /* Actions for POSIX signals */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+
+
+ /*
+ * First try to reserve a port for this connection...
+ */
+
+ if ((hostaddr = httpGetHostByName(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 (getuid())
+ {
+ /*
+ * We're running as a normal user, so just create a regular socket...
+ */
+
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+ {
+ perror("ERROR: Unable to create socket");
+ return (1);
+ }
+ }
+ else
+ {
+ /*
+ * We're running as root, so comply with RFC 1179 and reserve a
+ * priviledged port between 721 and 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;
+ }
+
+ fprintf(stderr, "INFO: Connected from port %d...\n", port);
+
+ /*
+ * Now that we are "connected" to the port, ignore SIGTERM so that we
+ * can finish out any page data the driver sends (e.g. to eject the
+ * current page... Only ignore SIGTERM if we are printing data from
+ * stdin (otherwise you can't cancel raw jobs...)
+ */
+
+ if (fromstdin)
+ {
+#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
+ sigset(SIGTERM, SIG_IGN);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+
+ sigemptyset(&action.sa_mask);
+ action.sa_handler = SIG_IGN;
+ sigaction(SIGTERM, &action, NULL);
+#else
+ signal(SIGTERM, SIG_IGN);
+#endif /* HAVE_SIGSET */
+ }
+
+ /*
+ * 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\nJ%s\n", localhost, user, title);
+ cptr = control + strlen(control);
+
+ if (banner)
+ {
+ snprintf(cptr, sizeof(control) - (cptr - control), "L%s\n", user);
+ cptr += strlen(cptr);
+ }
+
+ while (copies > 0)
+ {
+ snprintf(cptr, sizeof(control) - (cptr - control), "%cdfA%03d%s\n", format,
+ getpid() % 1000, localhost);
+ cptr += strlen(cptr);
+ copies --;
+ }
+
+ snprintf(cptr, sizeof(control) - (cptr - control),
+ "UdfA%03d%s\nNdfA%03d%s\n",
+ getpid() % 1000, localhost,
+ getpid() % 1000, localhost);
+
+ fprintf(stderr, "DEBUG: Control file is:\n%s", control);
+
+ if (order == ORDER_CONTROL_DATA)
+ {
+ 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 (lpd_write(fd, control, strlen(control) + 1) < (strlen(control) + 1))
+ {
+ status = errno;
+ perror("ERROR: Unable to write control file");
+ }
+ else if (read(fd, &status, 1) < 1)
+ status = errno;
+
+ if (status != 0)
+ fprintf(stderr, "ERROR: Remote host did not accept control file (%d)\n",
+ status);
+ else
+ fputs("INFO: Control file sent successfully\n", stderr);
+ }
+ else
+ status = 0;
+
+ if (status == 0)
+ {
+ /*
+ * Send the print file...
+ */
+
+ 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.0f * tbytes / filestats.st_size));
+
+ if (lpd_write(fd, buffer, nbytes) < nbytes)
+ {
+ perror("ERROR: Unable to send print file to printer");
+ break;
+ }
+ else
+ tbytes += nbytes;
+ }
+
+ if (tbytes < filestats.st_size)
+ status = errno;
+ else if (lpd_write(fd, "", 1) < 1)
+ status = errno;
+ else if (recv(fd, &status, 1, 0) < 1)
+ status = errno;
+
+ if (status != 0)
+ fprintf(stderr, "ERROR: Remote host did not accept data file (%d)\n",
+ status);
+ else
+ fputs("INFO: Data file sent successfully\n", stderr);
+ }
+
+ if (status == 0 && order == ORDER_DATA_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 (lpd_write(fd, control, strlen(control) + 1) < (strlen(control) + 1))
+ {
+ status = errno;
+ perror("ERROR: Unable to write control file");
+ }
+ else if (read(fd, &status, 1) < 1)
+ status = errno;
+
+ if (status != 0)
+ fprintf(stderr, "ERROR: Remote host did not accept control file (%d)\n",
+ status);
+ else
+ fputs("INFO: Control file sent successfully\n", stderr);
+ }
+
+ /*
+ * Close the socket connection and input file and return...
+ */
+
+ close(fd);
+ fclose(fp);
+
+ return (status);
+}
+
+
+/*
+ * 'lpd_write()' - Write a buffer of data to an LPD server.
+ */
+
+static int /* O - Number of bytes written or -1 on error */
+lpd_write(int lpd_fd, /* I - LPD socket */
+ char *buffer, /* I - Buffer to write */
+ int length) /* I - Number of bytes to write */
+{
+ int bytes, /* Number of bytes written */
+ total; /* Total number of bytes written */
+
+
+ total = 0;
+ while ((bytes = send(lpd_fd, buffer, length - total, 0)) >= 0)
+ {
+ total += bytes;
+ buffer += bytes;
+
+ if (total == length)
+ break;
+ }
+
+ if (bytes < 0)
+ return (-1);
+ else
+ return (length);
+}
+
+
+#ifndef HAVE_RRESVPORT
+/*
+ * 'rresvport()' - A simple implementation of rresvport().
+ */
+
+int /* O - Socket or -1 on error */
+rresvport(int *port) /* IO - Port number to bind to */
+{
+ struct sockaddr_in addr; /* Socket address */
+ int fd; /* Socket file descriptor */
+
+
+ /*
+ * Try to create an IPv4 socket...
+ */
+
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+ return (-1);
+
+ /*
+ * Initialize the address buffer...
+ */
+
+ memset(&addr, 0, sizeof(addr));
+
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = INADDR_ANY;
+
+ /*
+ * Try to bind the socket to a reserved port; unlike the standard
+ * BSD rresvport(), we limit the port number to 721 through 732
+ * (instead of 512 to 1023) since RFC 1179 defines the local port
+ * number between 721 and 732...
+ */
+
+ while (*port > 720)
+ {
+ /*
+ * Set the port number...
+ */
+
+ addr.sin_port = htons(*port);
+
+ /*
+ * Try binding the port to the socket; return if all is OK...
+ */
+
+ if (!bind(fd, (struct sockaddr *)&addr, sizeof(addr)))
+ return (fd);
+
+ /*
+ * Stop if we have any error other than "address already in use"...
+ */
+
+ if (errno != EADDRINUSE)
+ {
+# ifdef WIN32
+ closesocket(fd);
+# else
+ close(fd);
+# endif /* WIN32 */
+
+ return (-1);
+ }
+
+ /*
+ * Try the next port...
+ */
+
+ (*port)--;
+ }
+
+ /*
+ * Wasn't able to bind to a reserved port, so close the socket and return
+ * -1...
+ */
+
+# ifdef WIN32
+ closesocket(fd);
+# else
+ close(fd);
+# endif /* WIN32 */
+
+ return (-1);
+}
+#endif /* !HAVE_RRESVPORT */
+
+/*
+ * End of "$Id$".
+ */
diff --git a/backend/parallel.c b/backend/parallel.c
new file mode 100644
index 000000000..127f9d7b7
--- /dev/null
+++ b/backend/parallel.c
@@ -0,0 +1,643 @@
+/*
+ * "$Id$"
+ *
+ * Parallel port backend for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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 <cups/cups.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <cups/string.h>
+#include <signal.h>
+
+#ifdef WIN32
+# include <io.h>
+#else
+# include <unistd.h>
+# include <fcntl.h>
+# include <termios.h>
+#endif /* WIN32 */
+
+#ifdef __sgi
+# include <invent.h>
+# 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 */
+ 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 termios opts; /* Parallel port options */
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ struct sigaction action; /* Actions for POSIX signals */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+
+
+ /*
+ * Make sure status messages are not buffered...
+ */
+
+ setbuf(stderr, NULL);
+
+ /*
+ * Check command-line...
+ */
+
+ 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...
+ */
+
+ do
+ {
+ if ((fd = open(resource, O_WRONLY | O_EXCL)) == -1)
+ {
+ if (errno == EBUSY)
+ {
+ fputs("INFO: Parallel port busy; will retry in 30 seconds...\n", stderr);
+ sleep(30);
+ }
+ else
+ {
+ fprintf(stderr, "ERROR: Unable to open parallel port device file \"%s\": %s\n",
+ resource, strerror(errno));
+ return (1);
+ }
+ }
+ }
+ while (fd < 0);
+
+ /*
+ * Set any options provided...
+ */
+
+ tcgetattr(fd, &opts);
+
+ opts.c_lflag &= ~(ICANON | ECHO | ISIG); /* Raw mode */
+
+ /**** No options supported yet ****/
+
+ tcsetattr(fd, TCSANOW, &opts);
+
+ /*
+ * Now that we are "connected" to the port, ignore SIGTERM so that we
+ * can finish out any page data the driver sends (e.g. to eject the
+ * current page... Only ignore SIGTERM if we are printing data from
+ * stdin (otherwise you can't cancel raw jobs...)
+ */
+
+ if (argc < 7)
+ {
+#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
+ sigset(SIGTERM, SIG_IGN);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+
+ sigemptyset(&action.sa_mask);
+ action.sa_handler = SIG_IGN;
+ sigaction(SIGTERM, &action, NULL);
+#else
+ signal(SIGTERM, SIG_IGN);
+#endif /* HAVE_SIGSET */
+ }
+
+ /*
+ * 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...
+ */
+
+ tbytes += nbytes;
+ bufptr = buffer;
+
+ while (nbytes > 0)
+ {
+ if ((wbytes = write(fd, bufptr, nbytes)) < 0)
+ if (errno == ENOTTY)
+ wbytes = write(fd, bufptr, nbytes);
+
+ if (wbytes < 0)
+ {
+ perror("ERROR: Unable to send print file to printer");
+ break;
+ }
+
+ nbytes -= wbytes;
+ bufptr += wbytes;
+ }
+
+ 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)
+{
+#if defined(__hpux) || defined(__sgi) || defined(__sun)
+ static char *funky_hex = "0123456789abcdefghijklmnopqrstuvwxyz";
+ /* Funky hex numbering used for some devices */
+#endif /* __hpux || __sgi || __sun */
+
+#ifdef __linux
+ int i; /* Looping var */
+ int fd; /* File descriptor */
+ char device[255], /* Device filename */
+ probefile[255], /* Probe filename */
+ basedevice[255]; /* Base device filename for ports */
+ 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 ++)
+ {
+ /*
+ * First open the device to make sure the driver module is loaded...
+ */
+
+ if ((fd = open("/dev/parallel/0", O_WRONLY)) >= 0)
+ {
+ close(fd);
+ strcpy(basedevice, "/dev/parallel/");
+ }
+ else
+ {
+ sprintf(device, "/dev/lp%d", i);
+ if ((fd = open(device, O_WRONLY)) >= 0)
+ {
+ close(fd);
+ strcpy(basedevice, "/dev/lp");
+ }
+ else
+ {
+ sprintf(device, "/dev/par%d", i);
+ if ((fd = open(device, O_WRONLY)) >= 0)
+ {
+ close(fd);
+ strcpy(basedevice, "/dev/par");
+ }
+ else
+ strcpy(basedevice, "/dev/unknown-parallel");
+ }
+ }
+
+ /*
+ * Then try looking at the probe file...
+ */
+
+ sprintf(probefile, "/proc/parport/%d/autoprobe", i);
+ if ((probe = fopen(probefile, "r")) == NULL)
+ {
+ /*
+ * Linux 2.4 kernel has different path...
+ */
+
+ sprintf(probefile, "/proc/sys/dev/parport/parport%d/autoprobe", i);
+ probe = fopen(probefile, "r");
+ }
+
+ if (probe != NULL)
+ {
+ /*
+ * Found a probe file!
+ */
+
+ 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:%s%d \"%s %s\" \"Parallel Port #%d\"\n",
+ basedevice, i, make, model, i + 1);
+ else
+ printf("direct parallel:%s%d \"%s\" \"Parallel Port #%d\"\n",
+ basedevice, i, model, i + 1);
+ }
+ else if (fd >= 0)
+ {
+ /*
+ * No probe file, but we know the port is there...
+ */
+
+ 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",
+ device, 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 */
+ int fd; /* File descriptor */
+ 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 (interrupt-driven)\"\n", device, i + 1);
+ }
+
+ sprintf(device, "/dev/lpa%d", i);
+ if ((fd = open(device, O_WRONLY)) >= 0)
+ {
+ close(fd);
+ printf("direct parallel:%s \"Unknown\" \"Parallel Port #%d (polled)\"\n", device, i + 1);
+ }
+ }
+#elif defined(_AIX)
+ int i; /* Looping var */
+ int fd; /* File descriptor */
+ char device[255]; /* Device filename */
+
+
+ for (i = 0; i < 8; i ++)
+ {
+ sprintf(device, "/dev/lp%d", i);
+ if ((fd = open(device, O_WRONLY)) >= 0)
+ {
+ close(fd);
+ printf("direct parallel:%s \"Unknown\" \"Parallel Port #%d\"\n", device, i + 1);
+ }
+ }
+#endif
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/backend/serial.c b/backend/serial.c
new file mode 100644
index 000000000..6e510ae45
--- /dev/null
+++ b/backend/serial.c
@@ -0,0 +1,867 @@
+/*
+ * "$Id$"
+ *
+ * Serial port backend for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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.
+ * list_devices() - List all serial devices.
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include <cups/cups.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <cups/string.h>
+#include <signal.h>
+
+#ifdef __hpux
+# include <sys/modem.h>
+#endif /* __hpux */
+
+#ifdef WIN32
+# include <io.h>
+#else
+# include <unistd.h>
+# include <fcntl.h>
+# include <termios.h>
+# ifdef HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+# endif /* HAVE_SYS_IOCTL_H */
+#endif /* WIN32 */
+
+#ifdef __sgi
+# include <invent.h>
+# 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 */
+
+#ifndef CRTSCTS
+# ifdef CNEW_RTSCTS
+# define CRTSCTS CNEW_RTSCTS
+# else
+# define CRTSCTS 0
+# endif /* CNEW_RTSCTS */
+#endif /* !CRTSCTS */
+
+
+/*
+ * 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 */
+ int wbytes; /* Number of bytes written */
+ size_t nbytes, /* Number of bytes read */
+ tbytes; /* Total number of bytes written */
+ int dtrdsr; /* Do dtr/dsr flow control? */
+ int bufsize; /* Size of output buffer for writes */
+ char buffer[8192], /* Output buffer */
+ *bufptr; /* Pointer into buffer */
+ struct termios opts; /* Serial port options */
+ struct termios origopts; /* Original port options */
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ struct sigaction action; /* Actions for POSIX signals */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+
+
+ /*
+ * Make sure status messages are not buffered...
+ */
+
+ setbuf(stderr, NULL);
+
+ /*
+ * Check command-line...
+ */
+
+ 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...
+ */
+
+ do
+ {
+ if ((fd = open(resource, O_WRONLY | O_NOCTTY | O_EXCL | O_NDELAY)) == -1)
+ {
+ if (errno == EBUSY)
+ {
+ fputs("INFO: Serial port busy; will retry in 30 seconds...\n", stderr);
+ sleep(30);
+ }
+ else
+ {
+ fprintf(stderr, "ERROR: Unable to open serial port device file \"%s\": %s\n",
+ resource, strerror(errno));
+ return (1);
+ }
+ }
+ }
+ while (fd < 0);
+
+ /*
+ * Set any options provided...
+ */
+
+ tcgetattr(fd, &origopts);
+ tcgetattr(fd, &opts);
+
+ opts.c_lflag &= ~(ICANON | ECHO | ISIG); /* Raw mode */
+ opts.c_oflag &= ~OPOST; /* Don't post-process */
+
+ bufsize = 96; /* 9600 baud / 10 bits/char / 10Hz */
+ dtrdsr = 0; /* No dtr/dsr flow control */
+
+ 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...
+ */
+
+ bufsize = atoi(value) / 100;
+
+#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;
+#ifdef B57600
+ case 57600 :
+ cfsetispeed(&opts, B57600);
+ cfsetospeed(&opts, B57600);
+ break;
+#endif /* B57600 */
+#ifdef B115200
+ case 115200 :
+ cfsetispeed(&opts, B115200);
+ cfsetospeed(&opts, B115200);
+ break;
+#endif /* B115200 */
+ 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;
+ }
+ else if (strcasecmp(name, "flow") == 0)
+ {
+ /*
+ * Set flow control...
+ */
+
+ if (strcasecmp(value, "none") == 0)
+ {
+ opts.c_iflag &= ~(IXON | IXOFF | IXANY);
+ opts.c_cflag &= ~CRTSCTS;
+ }
+ else if (strcasecmp(value, "soft") == 0)
+ {
+ opts.c_iflag |= IXON | IXOFF | IXANY;
+ opts.c_cflag &= ~CRTSCTS;
+ }
+ else if (strcasecmp(value, "hard") == 0 ||
+ strcasecmp(value, "rtscts") == 0)
+ {
+ opts.c_iflag &= ~(IXON | IXOFF | IXANY);
+ opts.c_cflag |= CRTSCTS;
+ }
+ else if (strcasecmp(value, "dtrdsr") == 0)
+ {
+ opts.c_iflag &= ~(IXON | IXOFF | IXANY);
+ opts.c_cflag &= ~CRTSCTS;
+
+ dtrdsr = 1;
+ }
+ }
+ }
+
+ tcsetattr(fd, TCSANOW, &opts);
+ fcntl(fd, F_SETFL, 0);
+
+ /*
+ * Now that we are "connected" to the port, ignore SIGTERM so that we
+ * can finish out any page data the driver sends (e.g. to eject the
+ * current page... Only ignore SIGTERM if we are printing data from
+ * stdin (otherwise you can't cancel raw jobs...)
+ */
+
+ if (argc < 7)
+ {
+#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
+ sigset(SIGTERM, SIG_IGN);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+
+ sigemptyset(&action.sa_mask);
+ action.sa_handler = SIG_IGN;
+ sigaction(SIGTERM, &action, NULL);
+#else
+ signal(SIGTERM, SIG_IGN);
+#endif /* HAVE_SIGSET */
+ }
+
+ /*
+ * Finally, send the print file...
+ */
+
+ if (bufsize > sizeof(buffer))
+ bufsize = sizeof(buffer);
+
+ while (copies > 0)
+ {
+ copies --;
+
+ if (fp != stdin)
+ {
+ fputs("PAGE: 1 1\n", stderr);
+ rewind(fp);
+ }
+
+ if (dtrdsr)
+ {
+ /*
+ * Check the port and sleep until DSR is set...
+ */
+
+ int status;
+
+
+ if (!ioctl(fd, TIOCMGET, &status))
+ if (!(status & TIOCM_DSR))
+ {
+ /*
+ * Wait for DSR to go high...
+ */
+
+ fputs("DEBUG: DSR is low; waiting for device...\n", stderr);
+
+ do
+ {
+ sleep(1);
+ if (ioctl(fd, TIOCMGET, &status))
+ break;
+ }
+ while (!(status & TIOCM_DSR));
+
+ fputs("DEBUG: DSR is high; writing to device...\n", stderr);
+ }
+ }
+
+ tbytes = 0;
+ while ((nbytes = fread(buffer, 1, bufsize, fp)) > 0)
+ {
+ /*
+ * Write the print data to the printer...
+ */
+
+ tbytes += nbytes;
+ bufptr = buffer;
+
+ while (nbytes > 0)
+ {
+ if ((wbytes = write(fd, bufptr, nbytes)) < 0)
+ if (errno == ENOTTY)
+ wbytes = write(fd, bufptr, nbytes);
+
+ if (wbytes < 0)
+ {
+ perror("ERROR: Unable to send print file to printer");
+ break;
+ }
+
+ nbytes -= wbytes;
+ bufptr += wbytes;
+ }
+
+ if (argc > 6)
+ fprintf(stderr, "INFO: Sending print file, %u bytes...\n", tbytes);
+ }
+ }
+
+ /*
+ * Close the serial port and input file and return...
+ */
+
+ tcsetattr(fd, TCSADRAIN, &origopts);
+
+ close(fd);
+ if (fp != stdin)
+ fclose(fp);
+
+ return (0);
+}
+
+
+/*
+ * 'list_devices()' - List all serial devices.
+ */
+
+void
+list_devices(void)
+{
+#if defined(__hpux) || defined(__sgi) || defined(__sun) || defined(__FreeBSD__) || defined(__OpenBSD__)
+ static char *funky_hex = "0123456789abcdefghijklmnopqrstuvwxyz";
+ /* Funky hex numbering used for some devices */
+#endif /* __hpux || __sgi || __sun || __FreeBSD__ || __OpenBSD__ */
+
+#ifdef __linux
+ int i; /* Looping var */
+ int fd; /* File descriptor */
+ char device[255]; /* Device filename */
+
+
+ for (i = 0; i < 100; i ++)
+ {
+ sprintf(device, "/dev/ttyS%d", i);
+ if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 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=38400 \"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=38400 \"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=38400 \"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)
+#ifdef B115200
+ printf("serial serial:%s?baud=115200 \"Unknown\" \"Serial Port #%d\"\n",
+ device, i + 1);
+#else
+ printf("serial serial:%s?baud=38400 \"Unknown\" \"Serial Port #%d\"\n",
+ device, i + 1);
+#endif /* B115200 */
+ }
+
+ /*
+ * 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__)
+ 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 | O_NDELAY)) >= 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 | O_NDELAY)) >= 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 | O_NDELAY)) >= 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 | O_NDELAY)) >= 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 | O_NDELAY)) >= 0)
+ {
+ close(fd);
+ printf("serial serial:%s?baud=115200 \"Unknown\" \"SX Serial Port #%d\"\n",
+ device, i + 1);
+ }
+ }
+#elif defined(__NetBSD__)
+ int i, j; /* Looping vars */
+ int fd; /* File descriptor */
+ char device[255]; /* Device filename */
+
+
+ /*
+ * Standard serial ports...
+ */
+
+ for (i = 0; i < 4; i ++)
+ {
+ sprintf(device, "/dev/tty%02d", i);
+ if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0)
+ {
+ close(fd);
+ printf("serial serial:%s?baud=115200 \"Unknown\" \"Serial Port #%d\"\n",
+ device, i + 1);
+ }
+ }
+
+ /*
+ * Cyclades-Z ports...
+ */
+
+ for (i = 0; i < 16; i ++) /* Should be up to 65536 boards... */
+ for (j = 0; j < 64; j ++)
+ {
+ sprintf(device, "/dev/ttyCZ%02d%02d", i, j);
+ if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0)
+ {
+ close(fd);
+ printf("serial serial:%s?baud=115200 \"Unknown\" \"Cyclades #%d Serial Prt #%d\"\n",
+ device, i, j + 1);
+ }
+ }
+
+#endif
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/backend/socket.c b/backend/socket.c
new file mode 100644
index 000000000..403ac6707
--- /dev/null
+++ b/backend/socket.c
@@ -0,0 +1,347 @@
+/*
+ * "$Id$"
+ *
+ * AppSocket backend for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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 <cups/cups.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <cups/string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+
+#ifdef WIN32
+# include <winsock.h>
+#else
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
+# include <netdb.h>
+#endif /* WIN32 */
+
+
+/*
+ * '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 delay; /* Delay for retries... */
+ 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 defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ struct sigaction action; /* Actions for POSIX signals */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+
+
+ /*
+ * Make sure status messages are not buffered...
+ */
+
+ setbuf(stderr, NULL);
+
+ /*
+ * Check command-line...
+ */
+
+ 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 = httpGetHostByName(hostname)) == NULL)
+ {
+ fprintf(stderr, "ERROR: Unable to locate printer \'%s\' - %s\n",
+ 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 (delay = 5;;)
+ {
+ 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 %d seconds...\n",
+ hostname, delay);
+ sleep(delay);
+
+ if (delay < 30)
+ delay += 5;
+ }
+ else
+ {
+ perror("ERROR: Unable to connect to printer (retrying in 30 seconds)");
+ sleep(30);
+ }
+ }
+ else
+ break;
+ }
+
+ /*
+ * Now that we are "connected" to the port, ignore SIGTERM so that we
+ * can finish out any page data the driver sends (e.g. to eject the
+ * current page... Only ignore SIGTERM if we are printing data from
+ * stdin (otherwise you can't cancel raw jobs...)
+ */
+
+ if (argc < 7)
+ {
+#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
+ sigset(SIGTERM, SIG_IGN);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+
+ sigemptyset(&action.sa_mask);
+ action.sa_handler = SIG_IGN;
+ sigaction(SIGTERM, &action, NULL);
+#else
+ signal(SIGTERM, SIG_IGN);
+#endif /* HAVE_SIGSET */
+ }
+
+ /*
+ * 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);
+#ifdef __hpux
+ if (select(fd + 1, (int *)&input, NULL, NULL, &timeout) > 0)
+#else
+ if (select(fd + 1, &input, NULL, NULL, &timeout) > 0)
+#endif /* __hpux */
+ {
+ /*
+ * 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);
+ }
+
+ /*
+ * Shutdown the socket and wait for the other end to finish...
+ */
+
+ fputs("INFO: Print file sent, waiting for printer to finish...\n", stderr);
+
+ shutdown(fd, 1);
+
+ for (;;)
+ {
+ /*
+ * Wait a maximum of 90 seconds for backchannel data or a closed
+ * connection...
+ */
+
+ timeout.tv_sec = 90;
+ timeout.tv_usec = 0;
+
+ FD_ZERO(&input);
+ FD_SET(fd, &input);
+
+#ifdef __hpux
+ if (select(fd + 1, (int *)&input, NULL, NULL, &timeout) > 0)
+#else
+ if (select(fd + 1, &input, NULL, NULL, &timeout) > 0)
+#endif /* __hpux */
+ {
+ /*
+ * 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
+ break;
+ }
+ else
+ break;
+ }
+
+ /*
+ * Close the socket connection...
+ */
+
+ close(fd);
+ }
+
+ /*
+ * Close the input file and return...
+ */
+
+ if (fp != stdin)
+ fclose(fp);
+
+ fputs("INFO: Ready to print.\n", stderr);
+
+ return (0);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/backend/usb.c b/backend/usb.c
new file mode 100644
index 000000000..2950537aa
--- /dev/null
+++ b/backend/usb.c
@@ -0,0 +1,454 @@
+/*
+ * "$Id$"
+ *
+ * USB port backend for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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 <cups/cups.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <cups/string.h>
+#include <signal.h>
+
+#ifdef WIN32
+# include <io.h>
+#else
+# include <unistd.h>
+# include <fcntl.h>
+# include <termios.h>
+#endif /* WIN32 */
+
+
+/*
+ * 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 */
+ 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 termios opts; /* Parallel port options */
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ struct sigaction action; /* Actions for POSIX signals */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+
+
+ /*
+ * Make sure status messages are not buffered...
+ */
+
+ setbuf(stderr, NULL);
+
+ /*
+ * Check command-line...
+ */
+
+ 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...
+ */
+
+ do
+ {
+ if ((fd = open(resource, O_WRONLY | O_EXCL)) == -1)
+ {
+ if (errno == EBUSY)
+ {
+ fputs("INFO: USB port busy; will retry in 30 seconds...\n", stderr);
+ sleep(30);
+ }
+ else
+ {
+ fprintf(stderr, "ERROR: Unable to open USB port device file \"%s\": %s\n",
+ resource, strerror(errno));
+ return (1);
+ }
+ }
+ }
+ while (fd < 0);
+
+ /*
+ * Set any options provided...
+ */
+
+ tcgetattr(fd, &opts);
+
+ opts.c_lflag &= ~(ICANON | ECHO | ISIG); /* Raw mode */
+
+ /**** No options supported yet ****/
+
+ tcsetattr(fd, TCSANOW, &opts);
+
+ /*
+ * Now that we are "connected" to the port, ignore SIGTERM so that we
+ * can finish out any page data the driver sends (e.g. to eject the
+ * current page... Only ignore SIGTERM if we are printing data from
+ * stdin (otherwise you can't cancel raw jobs...)
+ */
+
+ if (argc < 7)
+ {
+#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
+ sigset(SIGTERM, SIG_IGN);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+
+ sigemptyset(&action.sa_mask);
+ action.sa_handler = SIG_IGN;
+ sigaction(SIGTERM, &action, NULL);
+#else
+ signal(SIGTERM, SIG_IGN);
+#endif /* HAVE_SIGSET */
+ }
+
+ /*
+ * 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...
+ */
+
+ tbytes += nbytes;
+ bufptr = buffer;
+
+ while (nbytes > 0)
+ {
+ if ((wbytes = write(fd, bufptr, nbytes)) < 0)
+ if (errno == ENOTTY)
+ wbytes = write(fd, bufptr, nbytes);
+
+ if (wbytes < 0)
+ {
+ perror("ERROR: Unable to send print file to printer");
+ break;
+ }
+
+ nbytes -= wbytes;
+ bufptr += wbytes;
+ }
+
+ 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/bus/usb/devices 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 */
+
+
+ /*
+ * First try opening one of the USB devices to load the driver
+ * module as needed...
+ */
+
+ if ((fd = open("/dev/usb/lp0", O_WRONLY)) >= 0)
+ close(fd); /* 2.3.x and 2.4.x */
+ else if ((fd = open("/dev/usb/usblp0", O_WRONLY)) >= 0)
+ close(fd); /* Mandrake 7.x */
+ else if ((fd = open("/dev/usblp0", O_WRONLY)) >= 0)
+ close(fd); /* 2.2.x */
+
+ /*
+ * Then look at the device list for the USB bus...
+ */
+
+ if ((probe = fopen("/proc/bus/usb/devices", "r")) != NULL)
+ {
+ /*
+ * Scan the device list...
+ */
+
+ 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 ||
+ strstr(line, "Driver=usblp") != NULL) &&
+ make[0] && model[0])
+ {
+ /*
+ * We were processing a printer device; send the info out...
+ */
+
+ sprintf(device, "/dev/usb/lp%d", i);
+ if (access(device, 0))
+ {
+ sprintf(device, "/dev/usb/usblp%d", i);
+
+ if (access(device, 0))
+ sprintf(device, "/dev/usblp%d", i);
+ }
+
+ printf("direct usb:%s \"%s %s\" \"USB Printer #%d\"\n",
+ device, make, model, i + 1);
+
+ i ++;
+
+ memset(make, 0, sizeof(make));
+ memset(model, 0, sizeof(model));
+ }
+ }
+
+ fclose(probe);
+
+ /*
+ * Write empty device listings for unused USB devices...
+ */
+
+ for (; i < 16; i ++)
+ {
+ sprintf(device, "/dev/usb/lp%d", i);
+
+ if (access(device, 0))
+ {
+ sprintf(device, "/dev/usb/usblp%d", i);
+
+ if (access(device, 0))
+ {
+ sprintf(device, "/dev/usblp%d", i);
+
+ if (access(device, 0))
+ continue;
+ }
+ }
+
+ printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1);
+ }
+ }
+ else
+ {
+ /*
+ * Just check manually for USB devices...
+ */
+
+ for (i = 0; i < 16; i ++)
+ {
+ sprintf(device, "/dev/usb/lp%d", i);
+
+ if (access(device, 0))
+ {
+ sprintf(device, "/dev/usb/usblp%d", i);
+
+ if (access(device, 0))
+ {
+ sprintf(device, "/dev/usblp%d", i);
+
+ if (access(device, 0))
+ continue;
+ }
+ }
+
+ printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1);
+ }
+ }
+#elif defined(__sgi)
+#elif defined(__sun)
+#elif defined(__hpux)
+#elif defined(__osf)
+#elif defined(__FreeBSD__)
+ int i; /* Looping var */
+ char device[255]; /* Device filename */
+
+
+ for (i = 0; i < 3; i ++)
+ {
+ sprintf(device, "/dev/unlpt%d", i);
+ if (!access(device, 0))
+ printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1);
+ }
+#elif defined(__NetBSD__) || defined(__OpenBSD__)
+ int i; /* Looping var */
+ char device[255]; /* Device filename */
+
+
+ for (i = 0; i < 3; i ++)
+ {
+ sprintf(device, "/dev/ulpt%d", i);
+ if (!access(device, 0))
+ printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1);
+ }
+#endif
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/berkeley/.cvsignore b/berkeley/.cvsignore
new file mode 100644
index 000000000..3ff70bf38
--- /dev/null
+++ b/berkeley/.cvsignore
@@ -0,0 +1,4 @@
+lpc
+lpq
+lpr
+lprm
diff --git a/berkeley/Makefile b/berkeley/Makefile
new file mode 100644
index 000000000..62508f772
--- /dev/null
+++ b/berkeley/Makefile
@@ -0,0 +1,105 @@
+#
+# "$Id$"
+#
+# Berkeley commands makefile for the Common UNIX Printing System (CUPS).
+#
+# Copyright 1997-2002 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:
+ $(INSTALL_DIR) $(BINDIR)
+ $(INSTALL_BIN) lpq $(BINDIR)
+ $(INSTALL_BIN) lpr $(BINDIR)
+ $(INSTALL_BIN) lprm $(BINDIR)
+ $(INSTALL_DIR) $(SBINDIR)
+ $(INSTALL_BIN) 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 000000000..3904939ff
--- /dev/null
+++ b/berkeley/lpc.c
@@ -0,0 +1,481 @@
+/*
+ * "$Id$"
+ *
+ * "lpc" command for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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 <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <cups/cups.h>
+#include <cups/language.h>
+#include <cups/debug.h>
+
+
+/*
+ * 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 = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
+
+ 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
+ printf("%s is not implemented by the CUPS version of lpc.\n", 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 */
+ *jattr; /* Current job 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 */
+ static const char *requested[] =
+ { /* Requested attributes */
+ "printer-name",
+ "device-uri",
+ "printer-state",
+ "printer-is-accepting-jobs"
+ };
+
+
+ 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();
+
+ 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);
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes", sizeof(requested) / sizeof(requested[0]),
+ NULL, requested);
+
+ /*
+ * 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);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, printer_uri);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes", NULL, "job-id");
+
+ if ((jobs = cupsDoRequest(http, request, "/jobs/")) != NULL)
+ {
+ for (jattr = jobs->attrs; jattr != NULL; jattr = jattr->next)
+ if (jattr->name && strcmp(jattr->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 000000000..0b269e84f
--- /dev/null
+++ b/berkeley/lpq.c
@@ -0,0 +1,542 @@
+/*
+ * "$Id$"
+ *
+ * "lpq" command for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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.
+ * show_printer() - Show printer status.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <config.h>
+#include <cups/cups.h>
+#include <cups/language.h>
+#include <cups/debug.h>
+
+
+/*
+ * 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 */
+ char *instance; /* Printer instance */
+ int id, /* Desired job ID */
+ interval, /* Reporting interval */
+ longstatus; /* Show file details */
+ int num_dests; /* Number of destinations */
+ cups_dest_t *dests; /* Destinations */
+#ifdef HAVE_LIBSSL
+ http_encryption_t encryption; /* Encryption? */
+#endif /* HAVE_LIBSSL */
+
+
+ /*
+ * Connect to the scheduler...
+ */
+
+ if ((http = httpConnectEncrypt(cupsServer(), ippPort(),
+ cupsEncryption())) == NULL)
+ {
+ fputs("lpq: Unable to contact server!\n", stderr);
+ return (1);
+ }
+
+ /*
+ * Check for command-line options...
+ */
+
+ dest = NULL;
+ user = NULL;
+ id = 0;
+ interval = 0;
+ longstatus = 0;
+
+ num_dests = cupsGetDests(&dests);
+
+ for (i = 0; i < num_dests; i ++)
+ if (dests[i].is_default)
+ dest = dests[i].name;
+
+ 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 'E' : /* Encrypt */
+#ifdef HAVE_LIBSSL
+ encryption = HTTP_ENCRYPT_REQUIRED;
+
+ if (http)
+ httpEncryption(http, encryption);
+#else
+ fprintf(stderr, "%s: Sorry, no encryption support compiled in!\n",
+ argv[0]);
+#endif /* HAVE_LIBSSL */
+ break;
+
+ case 'P' : /* Printer */
+ if (argv[i][2])
+ dest = argv[i] + 2;
+ else
+ {
+ i ++;
+ dest = argv[i];
+ }
+
+ if ((instance = strchr(dest, '/')) != NULL)
+ *instance = '\0';
+ break;
+
+ case 'a' : /* All printers */
+ dest = NULL;
+ break;
+
+ case 'l' : /* Long status */
+ longstatus = 1;
+ break;
+
+ default :
+ fputs("Usage: lpq [-P dest] [-l] [+interval]\n", stderr);
+ httpClose(http);
+ cupsFreeDests(num_dests, dests);
+ 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...
+ */
+
+ cupsFreeDests(num_dests, dests);
+ 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, "printer-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, "/")) != 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;
+ }
+
+ if (!longstatus && jobcount == 0)
+#ifdef __osf__
+ puts("Rank Owner Pri Job Files Total Size");
+#else
+ puts("Rank Owner Job File(s) Total Size");
+#endif /* __osf__ */
+
+ jobcount ++;
+
+ /*
+ * Display the job...
+ */
+
+ if (jobstate == IPP_JOB_PROCESSING)
+ strcpy(rankstr, "active");
+ else
+ {
+ snprintf(rankstr, sizeof(rankstr), "%d%s", rank, ranks[rank % 10]);
+ rank ++;
+ }
+
+ if (longstatus)
+ {
+ puts("");
+
+ if (jobcopies > 1)
+ snprintf(namestr, sizeof(namestr), "%d copies of %s", jobcopies,
+ jobname);
+ else
+ {
+ strncpy(namestr, jobname, sizeof(namestr) - 1);
+ namestr[sizeof(namestr) - 1] = '\0';
+ }
+
+ printf("%s: %-34.34s[job %d localhost]\n", jobuser, rankstr, jobid);
+ printf(" %-40.40s%d bytes\n", namestr, jobsize);
+ }
+ else
+#ifdef __osf__
+ printf("%-6s %-10.10s %-4d %-10d %-27.27s %d bytes\n", rankstr, jobuser,
+ jobpriority, jobid, jobname, jobsize);
+#else
+ printf("%-7s %-8.8s%-8d%-32.32s%d bytes\n", rankstr, jobuser,
+ jobid, jobname, jobsize);
+#endif /* __osf */
+
+ 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);
+
+ snprintf(uri, sizeof(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 000000000..aa5ccab9b
--- /dev/null
+++ b/berkeley/lpr.c
@@ -0,0 +1,425 @@
+/*
+ * "$Id$"
+ *
+ * "lpr" command for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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 <stdio.h>
+#include <stdlib.h>
+
+#include <config.h>
+#include <cups/cups.h>
+
+
+#ifndef WIN32
+# include <signal.h>
+
+
+/*
+ * 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, j; /* Looping var */
+ int job_id; /* Job ID */
+ char ch; /* Option character */
+ char *printer, /* Destination printer or class */
+ *instance; /* Instance */
+ const char *title; /* Job title */
+ int num_copies; /* Number of copies per file */
+ int num_files; /* Number of files to print */
+ const char *files[1000]; /* Files to print */
+ int num_dests; /* Number of destinations */
+ cups_dest_t *dests, /* Destinations */
+ *dest; /* Selected destination */
+ int num_options; /* Number of options */
+ cups_option_t *options; /* Options */
+ int deletefile; /* Delete file after print? */
+ char buffer[8192]; /* Copy buffer */
+ int temp; /* Temporary file descriptor */
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ struct sigaction action; /* Signal action */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+
+
+ deletefile = 0;
+ printer = NULL;
+ num_dests = 0;
+ dests = NULL;
+ num_options = 0;
+ options = NULL;
+ num_files = 0;
+ title = NULL;
+
+ for (i = 1; i < argc; i ++)
+ if (argv[i][0] == '-')
+ switch (ch = argv[i][1])
+ {
+ case 'E' : /* Encrypt */
+#ifdef HAVE_LIBSSL
+ cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
+#else
+ fprintf(stderr, "%s: Sorry, no encryption support compiled in!\n",
+ argv[0]);
+#endif /* HAVE_LIBSSL */
+ break;
+
+ case '1' : /* TROFF font set 1 */
+ case '2' : /* TROFF font set 2 */
+ case '3' : /* TROFF font set 3 */
+ case '4' : /* TROFF font set 4 */
+ case 'i' : /* indent */
+ case 'w' : /* width */
+ if (argv[i][2] == '\0')
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ fprintf(stderr, "lpr: Expected value after -%c option!\n", ch);
+ return (1);
+ }
+ }
+
+ 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",
+ ch);
+ break;
+
+ case 'o' : /* Option */
+ if (argv[i][2] != '\0')
+ num_options = cupsParseOptions(argv[i] + 2, num_options, &options);
+ else
+ {
+ i ++;
+ if (i >= argc)
+ {
+ fputs("lpr: Expected option=value after -o option!\n", stderr);
+ return (1);
+ }
+
+ num_options = cupsParseOptions(argv[i], num_options, &options);
+ }
+ break;
+
+ case 'l' : /* Literal/raw */
+ num_options = cupsAddOption("raw", "", num_options, &options);
+ break;
+
+ case 'p' : /* Prettyprint */
+ num_options = cupsAddOption("prettyprint", "", num_options, &options);
+ break;
+
+ case 'h' : /* Suppress burst page */
+ num_options = cupsAddOption("job-sheets", "none", num_options, &options);
+ break;
+
+ case 's' : /* Don't use symlinks */
+ break;
+
+ case 'm' : /* Mail on completion */
+ fputs("Warning: email notification is not supported!\n", stderr);
+ break;
+
+ case 'q' : /* Queue file but don't print */
+ num_options = cupsAddOption("job-hold-until", "indefinite",
+ num_options, &options);
+ break;
+
+ case 'r' : /* Remove file after printing */
+ deletefile = 1;
+ break;
+
+ case 'P' : /* Destination printer or class */
+ if (argv[i][2] != '\0')
+ printer = argv[i] + 2;
+ else
+ {
+ i ++;
+ if (i >= argc)
+ {
+ fputs("lpr: Expected destination after -P option!\n", stderr);
+ return (1);
+ }
+
+ printer = argv[i];
+ }
+
+ if ((instance = strrchr(printer, '/')) != NULL)
+ *instance++ = '\0';
+
+ if (num_dests == 0)
+ num_dests = cupsGetDests(&dests);
+
+ if ((dest = cupsGetDest(printer, instance, num_dests, dests)) != NULL)
+ {
+ for (j = 0; j < dest->num_options; j ++)
+ if (cupsGetOption(dest->options[j].name, num_options, options) == NULL)
+ num_options = cupsAddOption(dest->options[j].name,
+ dest->options[j].value,
+ num_options, &options);
+ }
+ break;
+
+ case '#' : /* Number of copies */
+ if (argv[i][2] != '\0')
+ num_copies = atoi(argv[i] + 2);
+ else
+ {
+ i ++;
+ if (i >= argc)
+ {
+ fputs("lpr: Expected copy count after -# option!\n", stderr);
+ return (1);
+ }
+
+ 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 ++;
+ if (i >= argc)
+ {
+ fprintf(stderr, "lpr: Expected name after -%c option!\n", ch);
+ return (1);
+ }
+
+ title = argv[i];
+ }
+ break;
+
+ case 'U' : /* User */
+ if (argv[i][2] != '\0')
+ cupsSetUser(argv[i] + 2);
+ else
+ {
+ i ++;
+ if (i >= argc)
+ {
+ fputs("lpr: Expected username after -U option!\n", stderr);
+ return (1);
+ }
+
+ cupsSetUser(argv[i]);
+ }
+ break;
+
+ default :
+ fprintf(stderr, "lpr: Unknown option \'%c\'!\n", argv[i][1]);
+ return (1);
+ }
+ else if (num_files < 1000)
+ {
+ /*
+ * Print a file...
+ */
+
+ files[num_files] = argv[i];
+ num_files ++;
+
+ if (title == NULL)
+ {
+ if ((title = strrchr(argv[i], '/')) != NULL)
+ title ++;
+ else
+ title = argv[i];
+ }
+ }
+ else
+ fprintf(stderr, "lpr: Too many files - \"%s\"\n", argv[i]);
+ /*
+ * See if we have any files to print; if not, print from stdin...
+ */
+
+ if (printer == NULL)
+ {
+ if (num_dests == 0)
+ num_dests = cupsGetDests(&dests);
+
+ for (j = 0, dest = dests; j < num_dests; j ++, dest ++)
+ if (dest->is_default)
+ {
+ printer = dests[j].name;
+
+ for (j = 0; j < dest->num_options; j ++)
+ if (cupsGetOption(dest->options[j].name, num_options, options) == NULL)
+ num_options = cupsAddOption(dest->options[j].name,
+ dest->options[j].value,
+ num_options, &options);
+ break;
+ }
+ }
+
+ if (printer == NULL)
+ {
+ fputs("lpr: error - no default destination available.\n", stderr);
+ return (1);
+ }
+
+ if (num_files > 0)
+ {
+ job_id = cupsPrintFiles(printer, num_files, files, title, num_options, options);
+
+ if (deletefile)
+ {
+ /*
+ * Delete print files after printing...
+ */
+
+ for (i = 0; i < num_files; i ++)
+ unlink(files[i]);
+ }
+ }
+ else
+ {
+ num_files = 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 */
+
+ if ((temp = cupsTempFd(tempfile, sizeof(tempfile))) < 0)
+ {
+ fputs("lpr: unable to create temporary file.\n", stderr);
+ return (1);
+ }
+
+ while ((i = read(0, buffer, sizeof(buffer))) > 0)
+ write(temp, buffer, i);
+
+ i = lseek(temp, 0, SEEK_CUR);
+ close(temp);
+
+ if (i == 0)
+ {
+ fputs("lpr: stdin is empty, so no job has been sent.\n", stderr);
+ return (1);
+ }
+
+ if (title)
+ job_id = cupsPrintFile(printer, tempfile, title, num_options, options);
+ else
+ job_id = cupsPrintFile(printer, tempfile, "(stdin)", num_options, options);
+
+ unlink(tempfile);
+ }
+
+ if (job_id < 1)
+ {
+ fprintf(stderr, "lpr: unable to print file: %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 000000000..3aab5771b
--- /dev/null
+++ b/berkeley/lprm.c
@@ -0,0 +1,267 @@
+/*
+ * "$Id$"
+ *
+ * "lprm" command for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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 <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include <cups/cups.h>
+#include <cups/language.h>
+
+
+/*
+ * '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 *instance; /* Pointer to instance name */
+ 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 */
+ int num_dests; /* Number of destinations */
+ cups_dest_t *dests; /* Destinations */
+ http_encryption_t encryption; /* Encryption? */
+
+
+ /*
+ * Setup to cancel individual print jobs...
+ */
+
+ op = IPP_CANCEL_JOB;
+ job_id = 0;
+ dest = NULL;
+ response = NULL;
+ http = NULL;
+ encryption = cupsEncryption();
+
+ num_dests = cupsGetDests(&dests);
+
+ for (i = 0; i < num_dests; i ++)
+ if (dests[i].is_default)
+ dest = dests[i].name;
+
+ /*
+ * Open a connection to the server...
+ */
+
+ if ((http = httpConnectEncrypt(cupsServer(), ippPort(), encryption)) == NULL)
+ {
+ fputs("lprm: Unable to contact server!\n", stderr);
+ cupsFreeDests(num_dests, dests);
+ 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 'E' : /* Encrypt */
+#ifdef HAVE_LIBSSL
+ encryption = HTTP_ENCRYPT_REQUIRED;
+
+ httpEncryption(http, encryption);
+#else
+ fprintf(stderr, "%s: Sorry, no encryption support compiled in!\n",
+ argv[0]);
+#endif /* HAVE_LIBSSL */
+ break;
+
+ case 'P' : /* Cancel jobs on a printer */
+ if (argv[i][2])
+ dest = argv[i] + 2;
+ else
+ {
+ i ++;
+ dest = argv[i];
+ }
+
+ if ((instance = strchr(dest, '/')) != NULL)
+ *instance = '\0';
+ break;
+
+ default :
+ fprintf(stderr, "lprm: Unknown option \'%c\'!\n", argv[i][1]);
+ cupsFreeDests(num_dests, dests);
+ httpClose(http);
+ 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
+ {
+ dest = argv[i];
+ 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;
+ }
+
+ if (response->request.status.status_code > IPP_OK_CONFLICT)
+ {
+ ippDelete(response);
+ cupsFreeDests(num_dests, dests);
+ httpClose(http);
+ return (1);
+ }
+
+ ippDelete(response);
+ }
+ else
+ {
+ fputs("lprm: Unable to cancel job(s)!\n", stderr);
+ cupsFreeDests(num_dests, dests);
+ httpClose(http);
+ 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);
+ cupsFreeDests(num_dests, dests);
+ httpClose(http);
+ return (1);
+ }
+
+ cupsFreeDests(num_dests, dests);
+ httpClose(http);
+
+ return (0);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cgi-bin/.cvsignore b/cgi-bin/.cvsignore
new file mode 100644
index 000000000..77c74e433
--- /dev/null
+++ b/cgi-bin/.cvsignore
@@ -0,0 +1,5 @@
+admin.cgi
+classes.cgi
+jobs.cgi
+libcgi.a
+printers.cgi
diff --git a/cgi-bin/Makefile b/cgi-bin/Makefile
new file mode 100644
index 000000000..41c000741
--- /dev/null
+++ b/cgi-bin/Makefile
@@ -0,0 +1,121 @@
+#
+# "$Id$"
+#
+# CGI makefile for the Common UNIX Printing System (CUPS).
+#
+# Copyright 1997-2002 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
+
+CGIS = admin.cgi classes.cgi jobs.cgi printers.cgi
+TARGETS = libcgi.a $(CGIS)
+LIBOBJS = 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) $(TARGETS)
+
+
+#
+# Install all targets...
+#
+
+install:
+ $(INSTALL_DIR) $(SERVERBIN)/cgi-bin
+ for file in $(CGIS); do \
+ $(INSTALL_BIN) $$file $(SERVERBIN)/cgi-bin; \
+ done
+
+
+#
+# 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 000000000..dbfd0745e
--- /dev/null
+++ b/cgi-bin/admin.c
@@ -0,0 +1,1599 @@
+/*
+ * "$Id$"
+ *
+ * Administration CGI for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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.
+ * do_am_class() - Add or modify a class.
+ * do_am_printer() - Add or modify a printer.
+ * do_config_printer() - Configure the default options for a printer.
+ * do_delete_class() - Delete a class...
+ * do_delete_printer() - Delete a printer...
+ * do_job_op() - Do a job operation.
+ * do_printer_op() - Do a printer operation.
+ * get_line() - Get a line that is terminated by a LF, CR, or CR LF.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "ipp-var.h"
+#include <ctype.h>
+#include <errno.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_config_printer(http_t *http, cups_lang_t *language);
+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 char *get_line(char *buf, int length, FILE *fp);
+
+
+/*
+ * '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");
+ ippSetServerVersion();
+
+ cgiCopyTemplateLang(stdout, TEMPLATES, "header.tmpl", getenv("LANG"));
+
+ /*
+ * See if we have form data...
+ */
+
+ if (!cgiInitialize())
+ {
+ /*
+ * Nope, send the administration menu...
+ */
+
+ cgiCopyTemplateLang(stdout, TEMPLATES, "admin.tmpl", getenv("LANG"));
+ }
+ else if ((op = cgiGetVariable("OP")) != NULL)
+ {
+ /*
+ * Connect to the HTTP server...
+ */
+
+ http = httpConnectEncrypt("localhost", ippPort(), cupsEncryption());
+
+ /*
+ * 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, "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 if (strcmp(op, "config-printer") == 0)
+ do_config_printer(http, language);
+ else
+ {
+ /*
+ * Bad operation code... Display an error...
+ */
+
+ cgiCopyTemplateLang(stdout, TEMPLATES, "admin-op.tmpl", getenv("LANG"));
+ }
+
+ /*
+ * Close the HTTP server connection...
+ */
+
+ httpClose(http);
+ }
+ else
+ {
+ /*
+ * Form data but no operation code... Display an error...
+ */
+
+ cgiCopyTemplateLang(stdout, TEMPLATES, "admin-op.tmpl", getenv("LANG"));
+ }
+
+ /*
+ * Send the standard trailer...
+ */
+
+ cgiCopyTemplateLang(stdout, TEMPLATES, "trailer.tmpl", getenv("LANG"));
+
+ /*
+ * 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? */
+{
+ int i, j; /* Looping vars */
+ int element; /* Element number */
+ int num_printers; /* Number of printers */
+ ipp_t *request, /* IPP request */
+ *response; /* IPP response */
+ ipp_attribute_t *attr; /* member-uris attribute */
+ ipp_status_t status; /* Request status */
+ char uri[HTTP_MAX_URI]; /* Device or printer URI */
+ const char *name, /* Pointer to class name */
+ *ptr; /* Pointer to CGI variable */
+
+
+ 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/classes/%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, NULL, NULL);
+ ippDelete(response);
+ }
+
+ /*
+ * Update the location and description of an existing printer...
+ */
+
+ cgiCopyTemplateLang(stdout, TEMPLATES, "modify-class.tmpl", getenv("LANG"));
+ }
+ else
+ {
+ /*
+ * Get the name, location, and description for a new printer...
+ */
+
+ cgiCopyTemplateLang(stdout, TEMPLATES, "add-class.tmpl", getenv("LANG"));
+ }
+
+ return;
+ }
+
+ name = cgiGetVariable("PRINTER_NAME");
+ if (isdigit(*name))
+ ptr = name;
+ else
+ for (ptr = name; *ptr; ptr ++)
+ if (!isalnum(*ptr) && *ptr != '_')
+ break;
+
+ if (*ptr || ptr == name)
+ {
+ cgiSetVariable("ERROR", "The class name may only contain letters, "
+ "numbers, and the underscore.");
+ cgiCopyTemplateLang(stdout, TEMPLATES, "error.tmpl", getenv("LANG"));
+ return;
+ }
+
+ if (cgiGetVariable("MEMBER_URIS") == NULL)
+ {
+ /*
+ * Build a CUPS_GET_PRINTERS request, which requires the
+ * following attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ */
+
+ request = ippNew();
+
+ request->request.op.operation_id = CUPS_GET_PRINTERS;
+ request->request.op.request_id = 1;
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, cupsLangEncoding(language));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ 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)
+ {
+ /*
+ * Create MEMBER_URIS and MEMBER_NAMES arrays...
+ */
+
+ for (element = 0, attr = response->attrs;
+ attr != NULL;
+ attr = attr->next)
+ if (attr->name && strcmp(attr->name, "printer-uri-supported") == 0)
+ {
+ cgiSetArray("MEMBER_URIS", element, attr->values[0].string.text);
+ element ++;
+ }
+
+ for (element = 0, attr = response->attrs;
+ attr != NULL;
+ attr = attr->next)
+ if (attr->name && strcmp(attr->name, "printer-name") == 0)
+ {
+ cgiSetArray("MEMBER_NAMES", element, attr->values[0].string.text);
+ element ++;
+ }
+
+ num_printers = cgiGetSize("MEMBER_URIS");
+
+ ippDelete(response);
+ }
+ else
+ num_printers = 0;
+
+ /*
+ * 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/classes/%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)
+ {
+ if ((attr = ippFindAttribute(response, "member-uris", IPP_TAG_URI)) != NULL)
+ {
+ /*
+ * Mark any current members in the class...
+ */
+
+ for (j = 0; j < num_printers; j ++)
+ cgiSetArray("MEMBER_SELECTED", j, "");
+
+ for (i = 0; i < attr->num_values; i ++)
+ for (j = 0; j < num_printers; j ++)
+ if (strcmp(attr->values[i].string.text, cgiGetArray("MEMBER_URIS", j)) == 0)
+ {
+ cgiSetArray("MEMBER_SELECTED", j, "SELECTED");
+ break;
+ }
+ }
+
+ ippDelete(response);
+ }
+
+ /*
+ * Let the user choose...
+ */
+
+ cgiCopyTemplateLang(stdout, TEMPLATES, "choose-members.tmpl", getenv("LANG"));
+ }
+ else
+ {
+ /*
+ * Build a CUPS_ADD_CLASS request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * printer-location
+ * printer-info
+ * printer-is-accepting-jobs
+ * printer-state
+ * member-uris
+ */
+
+ request = ippNew();
+
+ request->request.op.operation_id = CUPS_ADD_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);
+
+ snprintf(uri, sizeof(uri), "ipp://localhost/classes/%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"));
+
+ ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1);
+
+ ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state",
+ IPP_PRINTER_IDLE);
+
+ if ((num_printers = cgiGetSize("MEMBER_URIS")) > 0)
+ {
+ attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_URI, "member-uris",
+ num_printers, NULL, NULL);
+ for (i = 0; i < num_printers; i ++)
+ attr->values[i].string.text = strdup(cgiGetArray("MEMBER_URIS", i));
+ }
+
+ /*
+ * 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));
+ cgiCopyTemplateLang(stdout, TEMPLATES, "error.tmpl", getenv("LANG"));
+ }
+ else if (modify)
+ cgiCopyTemplateLang(stdout, TEMPLATES, "class-modified.tmpl", getenv("LANG"));
+ else
+ cgiCopyTemplateLang(stdout, TEMPLATES, "class-added.tmpl", getenv("LANG"));
+ }
+}
+
+
+/*
+ * '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 */
+ int element; /* Element number */
+ ipp_attribute_t *attr, /* Current attribute */
+ *last; /* Last attribute */
+ ipp_t *request, /* IPP request */
+ *response, /* IPP response */
+ *oldinfo; /* Old printer information */
+ 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 */
+ char make[255]; /* Make string */
+ const char *name, /* Pointer to class name */
+ *ptr; /* Pointer to CGI variable */
+ static int baudrates[] = /* Baud rates */
+ {
+ 1200,
+ 2400,
+ 4800,
+ 9600,
+ 19200,
+ 38400,
+ 57600,
+ 115200,
+ 230400,
+ 460800
+ };
+
+
+ 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...
+ */
+
+ oldinfo = cupsDoRequest(http, request, "/");
+ }
+ else
+ oldinfo = NULL;
+
+ if ((name = cgiGetVariable("PRINTER_NAME")) == NULL ||
+ cgiGetVariable("PRINTER_LOCATION") == NULL)
+ {
+ if (modify)
+ {
+ /*
+ * Update the location and description of an existing printer...
+ */
+
+ if (oldinfo)
+ ippSetCGIVars(oldinfo, NULL, NULL);
+
+ cgiCopyTemplateLang(stdout, TEMPLATES, "modify-printer.tmpl", getenv("LANG"));
+ }
+ else
+ {
+ /*
+ * Get the name, location, and description for a new printer...
+ */
+
+ cgiCopyTemplateLang(stdout, TEMPLATES, "add-printer.tmpl", getenv("LANG"));
+ }
+
+ if (oldinfo)
+ ippDelete(oldinfo);
+
+ return;
+ }
+
+ if (isdigit(*name))
+ ptr = name;
+ else
+ for (ptr = name; *ptr; ptr ++)
+ if (!isalnum(*ptr) && *ptr != '_')
+ break;
+
+ if (*ptr || ptr == name)
+ {
+ cgiSetVariable("ERROR", "The printer name may only contain letters, "
+ "numbers, and the underscore.");
+ cgiCopyTemplateLang(stdout, TEMPLATES, "error.tmpl", getenv("LANG"));
+ return;
+ }
+
+ 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, NULL, NULL);
+ ippDelete(response);
+ }
+
+ /*
+ * Let the user choose...
+ */
+
+ if (oldinfo &&
+ (attr = ippFindAttribute(oldinfo, "device-uri", IPP_TAG_URI)) != NULL)
+ {
+ strncpy(uri, attr->values[0].string.text, sizeof(uri) - 1);
+ uri[sizeof(uri) - 1] = '\0';
+ if ((uriptr = strchr(uri, ':')) != NULL && strncmp(uriptr, "://", 3) == 0)
+ *uriptr = '\0';
+
+ cgiSetVariable("CURRENT_DEVICE_URI", uri);
+ }
+
+ cgiCopyTemplateLang(stdout, TEMPLATES, "choose-device.tmpl", getenv("LANG"));
+ }
+ else if (strchr(var, '/') == NULL)
+ {
+ if (oldinfo &&
+ (attr = ippFindAttribute(oldinfo, "device-uri", IPP_TAG_URI)) != NULL)
+ {
+ /*
+ * Set the current device URI for the form to the old one...
+ */
+
+ if (strncmp(attr->values[0].string.text, var, strlen(var)) == 0)
+ cgiSetVariable("DEVICE_URI", attr->values[0].string.text);
+ }
+
+ /*
+ * User needs to set the full URI...
+ */
+
+ cgiCopyTemplateLang(stdout, TEMPLATES, "choose-uri.tmpl", getenv("LANG"));
+ }
+ 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);
+ }
+
+ cgiCopyTemplateLang(stdout, TEMPLATES, "choose-serial.tmpl", getenv("LANG"));
+ }
+ else if ((var = cgiGetVariable("PPD_NAME")) == NULL)
+ {
+ if (modify)
+ {
+ /*
+ * Get the PPD file...
+ */
+
+ int fd; /* PPD file */
+ char filename[1024]; /* PPD filename */
+ ppd_file_t *ppd; /* PPD information */
+ char buffer[1024]; /* Buffer */
+ int bytes; /* Number of bytes */
+
+
+ snprintf(uri, sizeof(uri), "/printers/%s.ppd", name);
+
+ if (httpGet(http, uri))
+ httpGet(http, uri);
+
+ while (httpUpdate(http) == HTTP_CONTINUE);
+
+ if ((fd = cupsTempFd(filename, sizeof(filename))) >= 0)
+ {
+ while ((bytes = httpRead(http, buffer, sizeof(buffer))) > 0)
+ write(fd, buffer, bytes);
+
+ close(fd);
+
+ if ((ppd = ppdOpenFile(filename)) != NULL)
+ {
+ if (ppd->manufacturer)
+ cgiSetVariable("CURRENT_MAKE", ppd->manufacturer);
+ if (ppd->nickname)
+ cgiSetVariable("CURRENT_MAKE_AND_MODEL", ppd->nickname);
+
+ ppdClose(ppd);
+ }
+
+ unlink(filename);
+ }
+ else
+ httpFlush(http);
+ }
+
+ /*
+ * 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)
+ {
+ if ((var = cgiGetVariable("PPD_MAKE")) == NULL)
+ {
+ /*
+ * Let the user choose a make...
+ */
+
+ for (element = 0, attr = response->attrs, last = NULL;
+ attr != NULL;
+ attr = attr->next)
+ if (attr->name && strcmp(attr->name, "ppd-make") == 0)
+ if (last == NULL ||
+ strcasecmp(last->values[0].string.text,
+ attr->values[0].string.text) != 0)
+ {
+ cgiSetArray("PPD_MAKE", element, attr->values[0].string.text);
+ element ++;
+ last = attr;
+ }
+
+ cgiCopyTemplateLang(stdout, TEMPLATES, "choose-make.tmpl",
+ getenv("LANG"));
+ }
+ else
+ {
+ /*
+ * Let the user choose a model...
+ */
+
+ strncpy(make, var, sizeof(make) - 1);
+ make[sizeof(make) - 1] = '\0';
+
+ ippSetCGIVars(response, "ppd-make", make);
+ cgiCopyTemplateLang(stdout, TEMPLATES, "choose-model.tmpl",
+ getenv("LANG"));
+ }
+
+ ippDelete(response);
+ }
+ else
+ {
+ char message[1024];
+
+
+ snprintf(message, sizeof(message), "Unable to get list of printer drivers: %s",
+ ippErrorString(cupsLastError()));
+ cgiSetVariable("ERROR", message);
+ cgiCopyTemplateLang(stdout, TEMPLATES, "error.tmpl", getenv("LANG"));
+ }
+ }
+ 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"));
+
+ strncpy(uri, cgiGetVariable("DEVICE_URI"), sizeof(uri) - 1);
+ uri[sizeof(uri) - 1] = '\0';
+ if (strncmp(uri, "serial:", 7) == 0)
+ {
+ /*
+ * Update serial port URI to include baud rate, etc.
+ */
+
+ if ((uriptr = strchr(uri, '?')) == NULL)
+ uriptr = uri + strlen(uri);
+
+ snprintf(uriptr, sizeof(uri) - (uriptr - uri),
+ "?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));
+ cgiCopyTemplateLang(stdout, TEMPLATES, "error.tmpl", getenv("LANG"));
+ }
+ else if (modify)
+ cgiCopyTemplateLang(stdout, TEMPLATES, "printer-modified.tmpl", getenv("LANG"));
+ else
+ cgiCopyTemplateLang(stdout, TEMPLATES, "printer-added.tmpl", getenv("LANG"));
+ }
+
+ if (oldinfo)
+ ippDelete(oldinfo);
+}
+
+
+/*
+ * 'do_config_printer()' - Configure the default options for a printer.
+ */
+
+static void
+do_config_printer(http_t *http, /* I - HTTP connection */
+ cups_lang_t *language)/* I - Client's language */
+{
+ int i, j, k; /* Looping vars */
+ int have_options; /* Have options? */
+ ipp_t *request, /* IPP request */
+ *response; /* IPP response */
+ ipp_attribute_t *attr; /* IPP attribute */
+ char uri[HTTP_MAX_URI]; /* Job URI */
+ const char *var; /* Variable value */
+ const char *printer; /* Printer printer name */
+ ipp_status_t status; /* Operation status... */
+ const char *filename; /* PPD filename */
+ char tempfile[1024]; /* Temporary filename */
+ FILE *in, /* Input file */
+ *out; /* Output file */
+ int outfd; /* Output file descriptor */
+ char line[1024]; /* Line from PPD file */
+ char keyword[1024], /* Keyword from Default line */
+ *keyptr; /* Pointer into keyword... */
+ ppd_file_t *ppd; /* PPD file */
+ ppd_group_t *group; /* Option group */
+ ppd_option_t *option; /* Option */
+
+
+ /*
+ * Get the printer name...
+ */
+
+ if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL)
+ snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", printer);
+ else
+ {
+ cgiSetVariable("ERROR", ippErrorString(IPP_NOT_FOUND));
+ cgiCopyTemplateLang(stdout, TEMPLATES, "error.tmpl", getenv("LANG"));
+ return;
+ }
+
+ /*
+ * Get the PPD file...
+ */
+
+ if ((filename = cupsGetPPD(printer)) == NULL)
+ {
+ cgiSetVariable("ERROR", ippErrorString(IPP_NOT_FOUND));
+ cgiCopyTemplateLang(stdout, TEMPLATES, "error.tmpl", getenv("LANG"));
+ return;
+ }
+
+ ppd = ppdOpenFile(filename);
+
+ if (cgiGetVariable("job_sheets_start") != NULL ||
+ cgiGetVariable("job_sheets_end") != NULL)
+ have_options = 1;
+ else
+ have_options = 0;
+
+ for (i = ppd->num_groups, group = ppd->groups;
+ i > 0 && !have_options;
+ i --, group ++)
+ for (j = group->num_options, option = group->options;
+ j > 0;
+ j --, option ++)
+ if ((var = cgiGetVariable(option->keyword)) != NULL)
+ {
+ have_options = 1;
+ break;
+ }
+
+ if (!have_options)
+ {
+ /*
+ * Show the options to the user...
+ */
+
+ cgiCopyTemplateLang(stdout, TEMPLATES, "config-printer.tmpl",
+ getenv("LANG"));
+
+ for (i = ppd->num_groups, group = ppd->groups;
+ i > 0;
+ i --, group ++)
+ {
+ cgiSetVariable("GROUP", group->text);
+ cgiCopyTemplateLang(stdout, TEMPLATES, "option-header.tmpl",
+ getenv("LANG"));
+
+ for (j = group->num_options, option = group->options;
+ j > 0;
+ j --, option ++)
+ {
+ if (strcmp(option->keyword, "PageRegion") == 0)
+ continue;
+
+ cgiSetVariable("KEYWORD", option->keyword);
+ cgiSetVariable("KEYTEXT", option->text);
+ cgiSetVariable("DEFCHOICE", option->defchoice);
+
+ cgiSetSize("CHOICES", option->num_choices);
+ cgiSetSize("TEXT", option->num_choices);
+ for (k = 0; k < option->num_choices; k ++)
+ {
+ cgiSetArray("CHOICES", k, option->choices[k].choice);
+ cgiSetArray("TEXT", k, option->choices[k].text);
+ }
+
+ switch (option->ui)
+ {
+ case PPD_UI_BOOLEAN :
+ cgiCopyTemplateLang(stdout, TEMPLATES, "option-boolean.tmpl",
+ getenv("LANG"));
+ break;
+ case PPD_UI_PICKONE :
+ cgiCopyTemplateLang(stdout, TEMPLATES, "option-pickone.tmpl",
+ getenv("LANG"));
+ break;
+ case PPD_UI_PICKMANY :
+ cgiCopyTemplateLang(stdout, TEMPLATES, "option-pickmany.tmpl",
+ getenv("LANG"));
+ break;
+ }
+ }
+
+ cgiCopyTemplateLang(stdout, TEMPLATES, "option-trailer.tmpl",
+ getenv("LANG"));
+ }
+
+ /*
+ * 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)
+ {
+ if ((attr = ippFindAttribute(response, "job-sheets-supported", IPP_TAG_ZERO)) != NULL)
+ {
+ /*
+ * Add the job sheets options...
+ */
+
+ cgiSetVariable("GROUP", "Banners");
+ cgiCopyTemplateLang(stdout, TEMPLATES, "option-header.tmpl",
+ getenv("LANG"));
+
+ cgiSetSize("CHOICES", attr->num_values);
+ cgiSetSize("TEXT", attr->num_values);
+ for (k = 0; k < attr->num_values; k ++)
+ {
+ cgiSetArray("CHOICES", k, attr->values[k].string.text);
+ cgiSetArray("TEXT", k, attr->values[k].string.text);
+ }
+
+ attr = ippFindAttribute(response, "job-sheets-default", IPP_TAG_ZERO);
+
+ cgiSetVariable("KEYWORD", "job_sheets_start");
+ cgiSetVariable("KEYTEXT", "Starting Banner");
+ cgiSetVariable("DEFCHOICE", attr == NULL ?
+ "" : attr->values[0].string.text);
+
+ cgiCopyTemplateLang(stdout, TEMPLATES, "option-pickone.tmpl",
+ getenv("LANG"));
+
+ cgiSetVariable("KEYWORD", "job_sheets_end");
+ cgiSetVariable("KEYTEXT", "Ending Banner");
+ cgiSetVariable("DEFCHOICE", attr == NULL && attr->num_values > 1 ?
+ "" : attr->values[1].string.text);
+
+ cgiCopyTemplateLang(stdout, TEMPLATES, "option-pickone.tmpl",
+ getenv("LANG"));
+
+ cgiCopyTemplateLang(stdout, TEMPLATES, "option-trailer.tmpl",
+ getenv("LANG"));
+ }
+
+ ippDelete(response);
+ }
+
+ cgiCopyTemplateLang(stdout, TEMPLATES, "config-printer2.tmpl",
+ getenv("LANG"));
+ }
+ else
+ {
+ /*
+ * Set default options...
+ */
+
+ outfd = cupsTempFd(tempfile, sizeof(tempfile));
+ in = fopen(filename, "rb");
+ out = fdopen(outfd, "wb");
+
+ if (outfd < 0 || in == NULL || out == NULL)
+ {
+ cgiSetVariable("ERROR", strerror(errno));
+ cgiCopyTemplateLang(stdout, TEMPLATES, "error.tmpl", getenv("LANG"));
+ unlink(filename);
+ return;
+ }
+
+ while (get_line(line, sizeof(line), in) != NULL)
+ {
+ if (strncmp(line, "*Default", 8) != 0)
+ fprintf(out, "%s\n", line);
+ else
+ {
+ /*
+ * Get default option name...
+ */
+
+ strncpy(keyword, line + 8, sizeof(keyword) - 1);
+ keyword[sizeof(keyword) - 1] = '\0';
+
+ for (keyptr = keyword; *keyptr; keyptr ++)
+ if (*keyptr == ':' || isspace(*keyptr))
+ break;
+
+ *keyptr = '\0';
+
+ if (strcmp(keyword, "PageRegion") == 0)
+ var = cgiGetVariable("PageSize");
+ else
+ var = cgiGetVariable(keyword);
+
+ if (var != NULL)
+ fprintf(out, "*Default%s: %s\n", keyword, var);
+ else
+ fprintf(out, "%s\n", line);
+ }
+ }
+
+ fclose(in);
+ fclose(out);
+ close(outfd);
+
+ /*
+ * Build a CUPS_ADD_PRINTER request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * job-sheets-default
+ * [ppd file]
+ */
+
+ 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);
+
+ attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
+ "job-sheets-default", 2, NULL, NULL);
+ attr->values[0].string.text = strdup(cgiGetVariable("job_sheets_start"));
+ attr->values[1].string.text = strdup(cgiGetVariable("job_sheets_end"));
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoFileRequest(http, request, "/admin/", tempfile)) != NULL)
+ {
+ status = response->request.status.status_code;
+ ippDelete(response);
+ }
+ else
+ status = IPP_NOT_AUTHORIZED;
+
+ if (status > IPP_OK_CONFLICT)
+ {
+ cgiSetVariable("ERROR", ippErrorString(status));
+ cgiCopyTemplateLang(stdout, TEMPLATES, "error.tmpl", getenv("LANG"));
+ }
+ else
+ cgiCopyTemplateLang(stdout, TEMPLATES, "printer-configured.tmpl", getenv("LANG"));
+
+ unlink(tempfile);
+ }
+
+ unlink(filename);
+}
+
+
+/*
+ * '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)
+ {
+ cgiCopyTemplateLang(stdout, TEMPLATES, "class-confirm.tmpl", getenv("LANG"));
+ return;
+ }
+
+ if ((pclass = cgiGetVariable("PRINTER_NAME")) != NULL)
+ snprintf(uri, sizeof(uri), "ipp://localhost/classes/%s", pclass);
+ else
+ {
+ cgiSetVariable("ERROR", ippErrorString(IPP_NOT_FOUND));
+ cgiCopyTemplateLang(stdout, TEMPLATES, "error.tmpl", getenv("LANG"));
+ 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));
+ cgiCopyTemplateLang(stdout, TEMPLATES, "error.tmpl", getenv("LANG"));
+ }
+ else
+ cgiCopyTemplateLang(stdout, TEMPLATES, "class-deleted.tmpl", getenv("LANG"));
+}
+
+
+/*
+ * '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)
+ {
+ cgiCopyTemplateLang(stdout, TEMPLATES, "printer-confirm.tmpl", getenv("LANG"));
+ return;
+ }
+
+ if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL)
+ snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", printer);
+ else
+ {
+ cgiSetVariable("ERROR", ippErrorString(IPP_NOT_FOUND));
+ cgiCopyTemplateLang(stdout, TEMPLATES, "error.tmpl", getenv("LANG"));
+ 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));
+ cgiCopyTemplateLang(stdout, TEMPLATES, "error.tmpl", getenv("LANG"));
+ }
+ else
+ cgiCopyTemplateLang(stdout, TEMPLATES, "printer-deleted.tmpl", getenv("LANG"));
+}
+
+
+/*
+ * '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));
+ cgiCopyTemplateLang(stdout, TEMPLATES, "error.tmpl", getenv("LANG"));
+ 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));
+ cgiCopyTemplateLang(stdout, TEMPLATES, "error.tmpl", getenv("LANG"));
+ }
+ else if (op == IPP_CANCEL_JOB)
+ cgiCopyTemplateLang(stdout, TEMPLATES, "job-cancel.tmpl", getenv("LANG"));
+ else if (op == IPP_HOLD_JOB)
+ cgiCopyTemplateLang(stdout, TEMPLATES, "job-hold.tmpl", getenv("LANG"));
+ else if (op == IPP_RELEASE_JOB)
+ cgiCopyTemplateLang(stdout, TEMPLATES, "job-release.tmpl", getenv("LANG"));
+ else if (op == IPP_RESTART_JOB)
+ cgiCopyTemplateLang(stdout, TEMPLATES, "job-restart.tmpl", getenv("LANG"));
+}
+
+
+/*
+ * '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));
+ cgiCopyTemplateLang(stdout, TEMPLATES, "error.tmpl", getenv("LANG"));
+ 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));
+ cgiCopyTemplateLang(stdout, TEMPLATES, "error.tmpl", getenv("LANG"));
+ }
+ else if (op == IPP_PAUSE_PRINTER)
+ cgiCopyTemplateLang(stdout, TEMPLATES, "printer-stop.tmpl", getenv("LANG"));
+ else if (op == IPP_RESUME_PRINTER)
+ cgiCopyTemplateLang(stdout, TEMPLATES, "printer-start.tmpl", getenv("LANG"));
+ else if (op == CUPS_ACCEPT_JOBS)
+ cgiCopyTemplateLang(stdout, TEMPLATES, "printer-accept.tmpl", getenv("LANG"));
+ else if (op == CUPS_REJECT_JOBS)
+ cgiCopyTemplateLang(stdout, TEMPLATES, "printer-reject.tmpl", getenv("LANG"));
+}
+
+
+/*
+ * 'get_line()' - Get a line that is terminated by a LF, CR, or CR LF.
+ */
+
+static char * /* O - Pointer to buf or NULL on EOF */
+get_line(char *buf, /* I - Line buffer */
+ int length, /* I - Length of buffer */
+ FILE *fp) /* I - File to read from */
+{
+ char *bufptr; /* Pointer into buffer */
+ int ch; /* Character from file */
+
+
+ length --;
+ bufptr = buf;
+
+ while ((ch = getc(fp)) != EOF)
+ {
+ if (ch == '\n')
+ break;
+ else if (ch == '\r')
+ {
+ /*
+ * Look for LF...
+ */
+
+ ch = getc(fp);
+ if (ch != '\n' && ch != EOF)
+ ungetc(ch, fp);
+
+ break;
+ }
+
+ *bufptr++ = ch;
+ length --;
+ if (length == 0)
+ break;
+ }
+
+ *bufptr = '\0';
+
+ if (ch == EOF)
+ return (NULL);
+ else
+ return (buf);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cgi-bin/cgi.h b/cgi-bin/cgi.h
new file mode 100644
index 000000000..5c0bac189
--- /dev/null
+++ b/cgi-bin/cgi.h
@@ -0,0 +1,96 @@
+/*
+ * "$Id$"
+ *
+ * CGI support library definitions.
+ *
+ * Copyright 1997-2002 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 <stdio.h>
+# include <stdlib.h>
+# include <string.h>
+# include <ctype.h>
+# include <time.h>
+
+# ifdef WIN32
+# include <direct.h>
+# include <io.h>
+# include <malloc.h>
+# else
+# include <unistd.h>
+# endif /* WIN32 */
+
+
+/*
+ * Stuff for WIN32 and OS/2...
+ */
+
+# if defined(WIN32) || defined(__EMX__)
+# define strcasecmp stricmp
+# define strncasecmp strnicmp
+# endif /* WIN32 || __EMX__ */
+
+
+/*
+ * 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 *tmpl);
+extern void cgiCopyTemplateLang(FILE *out, const char *directory,
+ const char *tmpl, const char *lang);
+
+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);
+
+extern char *cgiGetCookie(const char *name, char *buf, int buflen);
+extern void cgiSetCookie(const char *name, const char *value,
+ const char *path, const char *domain,
+ time_t expires, int secure);
+
+# 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 000000000..16a17b18c
--- /dev/null
+++ b/cgi-bin/classes.c
@@ -0,0 +1,360 @@
+/*
+ * "$Id$"
+ *
+ * Class status CGI for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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 */
+ ipp_attribute_t *attr; /* IPP attribute */
+ ipp_status_t status; /* Operation status... */
+ char uri[HTTP_MAX_URI];
+ /* Printer URI */
+ const char *which_jobs; /* Which jobs to show */
+ const char *op; /* Operation to perform, if any */
+
+
+ /*
+ * Get any form variables...
+ */
+
+ cgiInitialize();
+ op = cgiGetVariable("OP");
+
+ /*
+ * Get the request language...
+ */
+
+ language = cupsLangDefault();
+
+ /*
+ * Connect to the HTTP server...
+ */
+
+ http = httpConnectEncrypt("localhost", ippPort(), cupsEncryption());
+
+ /*
+ * 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...
+ */
+
+ ippSetServerVersion();
+
+ pclass = argv[0];
+ if (strcmp(pclass, "/") == 0 || strcmp(pclass, "classes.cgi") == 0)
+ {
+ pclass = NULL;
+ cgiSetVariable("TITLE", cupsLangString(language, CUPS_MSG_CLASS));
+ }
+ else
+ cgiSetVariable("TITLE", pclass);
+
+ cgiCopyTemplateLang(stdout, TEMPLATES, "header.tmpl", getenv("LANG"));
+
+ if (op == NULL || strcasecmp(op, "print-test-page") != 0)
+ {
+ /*
+ * Get the default destination...
+ */
+
+ request = ippNew();
+ request->request.op.operation_id = CUPS_GET_DEFAULT;
+ 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 ((response = cupsDoRequest(http, request, "/")) != NULL)
+ {
+ if ((attr = ippFindAttribute(response, "printer-name", IPP_TAG_NAME)) != NULL)
+ cgiSetVariable("DEFAULT_NAME", attr->values[0].string.text);
+
+ if ((attr = ippFindAttribute(response, "printer-uri-supported", IPP_TAG_URI)) != NULL)
+ {
+ char method[HTTP_MAX_URI],
+ username[HTTP_MAX_URI],
+ hostname[HTTP_MAX_URI],
+ resource[HTTP_MAX_URI],
+ uri[HTTP_MAX_URI];
+ int port; /* URI data */
+ const char *server; /* Name of server */
+
+
+ /*
+ * Map localhost access to localhost...
+ */
+
+ server = getenv("SERVER_NAME");
+
+ httpSeparate(attr->values[0].string.text, method, username,
+ hostname, &port, resource);
+
+ if (strcasecmp(hostname, server) == 0 &&
+ (strcmp(getenv("REMOTE_HOST"), "127.0.0.1") == 0 ||
+ strcmp(getenv("REMOTE_HOST"), "localhost") == 0 ||
+ strcmp(getenv("REMOTE_HOST"), server) == 0))
+ strcpy(hostname, "localhost");
+
+ /*
+ * Rewrite URI with HTTP address...
+ */
+
+ snprintf(uri, sizeof(uri), "http://%s:%d%s", hostname, port,
+ resource);
+
+ cgiSetVariable("DEFAULT_URI", uri);
+ }
+
+ ippDelete(response);
+ }
+
+ /*
+ * Get the class 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, NULL, NULL);
+ ippDelete(response);
+ }
+
+ /*
+ * Write the report...
+ */
+
+ cgiCopyTemplateLang(stdout, TEMPLATES, "classes.tmpl", getenv("LANG"));
+
+ /*
+ * 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, NULL, NULL);
+ ippDelete(response);
+
+ cgiCopyTemplateLang(stdout, TEMPLATES, "jobs.tmpl", getenv("LANG"));
+ }
+ }
+ }
+ else
+ {
+ /*
+ * Print a test page...
+ */
+
+ snprintf(uri, sizeof(uri), "ipp://localhost/classes/%s", pclass);
+
+ /*
+ * 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, NULL, NULL);
+
+ ippDelete(response);
+ }
+ else
+ status = IPP_GONE;
+
+ cgiSetVariable("PRINTER_NAME", pclass);
+
+ if (status > IPP_OK_CONFLICT)
+ {
+ cgiSetVariable("ERROR", ippErrorString(status));
+ cgiCopyTemplateLang(stdout, TEMPLATES, "error.tmpl", getenv("LANG"));
+ }
+ else
+ cgiCopyTemplateLang(stdout, TEMPLATES, "test-page.tmpl", getenv("LANG"));
+ }
+
+ cgiCopyTemplateLang(stdout, TEMPLATES, "trailer.tmpl", getenv("LANG"));
+
+ /*
+ * 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 000000000..ac2291ee4
--- /dev/null
+++ b/cgi-bin/html.c
@@ -0,0 +1,89 @@
+/*
+ * "$Id$"
+ *
+ * CGI HTML functions.
+ *
+ * Copyright 1997-2002 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 <stdarg.h>
+
+
+/*
+ * '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("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" "
+ "\"http://www.w3.org/TR/REC-html40/loose.dtd\">\n", out);
+ fputs("<HTML>\n", out);
+ fputs("<HEAD>\n", out);
+
+ fputs("\t<TITLE>\n", out);
+ va_start(ap, title);
+ vfprintf(out, title, ap);
+ va_end(ap);
+ fputs("</TITLE>\n", out);
+
+ if (stylesheet)
+ fprintf(out, "\t<LINK REL=\"STYLESHEET\" TYPE=\"text/css\" HREF=\"%s\">\n",
+ stylesheet);
+ if (author)
+ fprintf(out, "\t<META NAME=\"AUTHOR\" CONTENT=\"%s\">\n", author);
+ if (keywords)
+ fprintf(out, "\t<META NAME=\"KEYWORDS\" CONTENT=\"%s\">\n", keywords);
+ if (description)
+ fprintf(out, "\t<META NAME=\"DESCRIPTION\" CONTENT=\"%s\">\n", description);
+
+ fputs("</HEAD>\n", out);
+ fputs("<BODY>\n", out);
+}
+
+
+/*
+ * 'cgiEndHTML()' - End an HTML document stream.
+ */
+
+void
+cgiEndHTML(FILE *out) /* I - Output file to use */
+{
+ fputs("</BODY>\n", out);
+ fputs("</HTML>\n", out);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cgi-bin/ipp-var.c b/cgi-bin/ipp-var.c
new file mode 100644
index 000000000..17ce3eaac
--- /dev/null
+++ b/cgi-bin/ipp-var.c
@@ -0,0 +1,299 @@
+/*
+ * "$Id$"
+ *
+ * IPP variable routines for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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:
+ *
+ * ippGetTemplateDir() - Get the templates directory...
+ * ippSetServerVersion() - Set the server name and CUPS version...
+ * ippSetCGIVars() - Set CGI variables from an IPP response.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "ipp-var.h"
+
+
+/*
+ * 'ippGetTemplateDir()' - Get the templates directory...
+ */
+
+char * /* O - Template directory */
+ippGetTemplateDir(void)
+{
+ const char *datadir; /* CUPS_DATADIR env var */
+ static char templates[1024] = ""; /* Template directory */
+
+
+ if (!templates[0])
+ {
+ /*
+ * Build the template directory pathname...
+ */
+
+ if ((datadir = getenv("CUPS_DATADIR")) == NULL)
+ datadir = CUPS_DATADIR;
+
+ snprintf(templates, sizeof(templates), "%s/templates", datadir);
+ }
+
+ return (templates);
+}
+
+
+/*
+ * 'ippSetServerVersion()' - Set the server name and CUPS version...
+ */
+
+void
+ippSetServerVersion(void)
+{
+ cgiSetVariable("SERVER_NAME", getenv("SERVER_NAME"));
+ cgiSetVariable("REMOTE_USER", getenv("REMOTE_USER"));
+ cgiSetVariable("CUPS_VERSION", CUPS_SVERSION);
+}
+
+
+/*
+ * 'ippSetCGIVars()' - Set CGI variables from an IPP response.
+ */
+
+void
+ippSetCGIVars(ipp_t *response, /* I - Response data to be copied... */
+ const char *filter_name, /* I - Filter name */
+ const char *filter_value) /* I - Filter value */
+{
+ int element; /* Element in CGI array */
+ ipp_attribute_t *attr, /* Attribute in response... */
+ *filter; /* Filtering attribute */
+ 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; /* URI data */
+ int ishttps; /* Using encryption? */
+ const char *server; /* Name of server */
+ struct tm *date; /* Date information */
+
+
+ ippSetServerVersion();
+
+ server = getenv("SERVER_NAME");
+ ishttps = getenv("HTTPS") != NULL;
+
+ 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...
+ */
+
+ if (filter_name)
+ {
+ for (filter = attr;
+ filter != NULL && filter->group_tag != IPP_TAG_ZERO;
+ filter = filter->next)
+ if (filter->name && strcmp(filter->name, filter_name) == 0 &&
+ (filter->value_tag == IPP_TAG_STRING ||
+ (filter->value_tag >= IPP_TAG_TEXTLANG &&
+ filter->value_tag <= IPP_TAG_MIMETYPE)) &&
+ filter->values[0].string.text != NULL &&
+ strcasecmp(filter->values[0].string.text, filter_value) == 0)
+ break;
+
+ if (!filter)
+ return;
+
+ if (filter->group_tag == IPP_TAG_ZERO)
+ {
+ attr = filter;
+ element --;
+ continue;
+ }
+ }
+
+ for (; attr != NULL && attr->group_tag != IPP_TAG_ZERO; attr = attr->next)
+ {
+ /*
+ * Copy the attribute name, substituting "_" for "-"...
+ */
+
+ if (attr->name == NULL)
+ continue;
+
+ for (i = 0; attr->name[i]; i ++)
+ if (attr->name[i] == '-')
+ name[i] = '_';
+ else
+ name[i] = attr->name[i];
+
+ name[i] = '\0';
+
+ /*
+ * Add "job_printer_name" variable if we have a "job_printer_uri"
+ * attribute...
+ */
+
+ if (strcmp(name, "job_printer_uri") == 0)
+ {
+ if ((valptr = strrchr(attr->values[0].string.text, '/')) == NULL)
+ valptr = "unknown";
+ else
+ valptr ++;
+
+ cgiSetArray("job_printer_name", element, valptr);
+ }
+
+ /*
+ * Copy values...
+ */
+
+ value[0] = '\0'; /* Initially an empty string */
+ value[sizeof(value) - 1] = '\0'; /* In case string gets full */
+ valptr = value; /* Start at the beginning */
+
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (i)
+ strncat(valptr, ",", sizeof(value) - (valptr - value) - 1);
+
+ valptr += strlen(valptr);
+
+ switch (attr->value_tag)
+ {
+ case IPP_TAG_INTEGER :
+ case IPP_TAG_ENUM :
+ if (strncmp(name, "time_at_", 8) == 0)
+ {
+ date = localtime((time_t *)&(attr->values[i].integer));
+ strftime(valptr, sizeof(value) - (valptr - value),
+ CUPS_STRFTIME_FORMAT, date);
+ }
+ else
+ snprintf(valptr, sizeof(value) - (valptr - value),
+ "%d", attr->values[i].integer);
+ break;
+
+ case IPP_TAG_BOOLEAN :
+ snprintf(valptr, sizeof(value) - (valptr - value),
+ "%d", attr->values[i].boolean);
+ break;
+
+ case IPP_TAG_NOVALUE :
+ strncat(valptr, "novalue", sizeof(value) - (valptr - value) - 1);
+ break;
+
+ case IPP_TAG_RANGE :
+ snprintf(valptr, sizeof(value) - (valptr - value),
+ "%d-%d", attr->values[i].range.lower,
+ attr->values[i].range.upper);
+ break;
+
+ case IPP_TAG_RESOLUTION :
+ snprintf(valptr, sizeof(value) - (valptr - value),
+ "%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 (strchr(attr->values[i].string.text, ':') != NULL)
+ {
+ httpSeparate(attr->values[i].string.text, method, username,
+ hostname, &port, resource);
+
+ if (strcmp(method, "ipp") == 0 ||
+ strcmp(method, "http") == 0)
+ {
+ /*
+ * Map localhost access to localhost and local port...
+ */
+
+ if (strcasecmp(hostname, server) == 0 &&
+ (strcmp(getenv("REMOTE_HOST"), "127.0.0.1") == 0 ||
+ strcmp(getenv("REMOTE_HOST"), "localhost") == 0 ||
+ strcmp(getenv("REMOTE_HOST"), server) == 0))
+ {
+ strcpy(hostname, "localhost");
+ port = atoi(getenv("SERVER_PORT"));
+ }
+
+ /*
+ * Rewrite URI with HTTP address...
+ */
+
+ if (username[0])
+ snprintf(uri, sizeof(uri), "%s://%s@%s:%d%s",
+ ishttps ? "https" : "http",
+ username, hostname, port, resource);
+ else
+ snprintf(uri, sizeof(uri), "%s://%s:%d%s",
+ ishttps ? "https" : "http",
+ hostname, port, resource);
+
+ strncat(valptr, uri, sizeof(value) - (valptr - value) - 1);
+ 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 :
+ strncat(valptr, attr->values[i].string.text,
+ sizeof(value) - (valptr - value) - 1);
+ break;
+
+ default :
+ break; /* anti-compiler-warning-code */
+ }
+ }
+
+ /*
+ * 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 000000000..0ce4163a9
--- /dev/null
+++ b/cgi-bin/ipp-var.h
@@ -0,0 +1,55 @@
+/*
+ * "$Id$"
+ *
+ * IPP variable definitions for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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 <ctype.h>
+#include <cups/cups.h>
+#include <cups/debug.h>
+#include <cups/language.h>
+#include <cups/string.h>
+#include "cgi.h"
+
+
+/*
+ * Definitions...
+ */
+
+#define TEMPLATES ippGetTemplateDir()
+
+
+/*
+ * Prototype...
+ */
+
+extern char *ippGetTemplateDir(void);
+extern void ippSetServerVersion(void);
+extern void ippSetCGIVars(ipp_t *, const char *, const char *);
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cgi-bin/jobs.c b/cgi-bin/jobs.c
new file mode 100644
index 000000000..571f2f20a
--- /dev/null
+++ b/cgi-bin/jobs.c
@@ -0,0 +1,139 @@
+/*
+ * "$Id$"
+ *
+ * Job status CGI for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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 = httpConnectEncrypt("localhost", ippPort(), cupsEncryption());
+
+ /*
+ * Tell the client to expect HTML...
+ */
+
+ printf("Content-Type: text/html;charset=%s\n\n", cupsLangEncoding(language));
+
+ cgiSetVariable("TITLE", "Jobs");
+
+ ippSetServerVersion();
+
+ cgiCopyTemplateLang(stdout, TEMPLATES, "header.tmpl", getenv("LANG"));
+
+ /*
+ * 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, NULL, NULL);
+ ippDelete(response);
+
+ cgiCopyTemplateLang(stdout, TEMPLATES, "jobs.tmpl", getenv("LANG"));
+ }
+
+ cgiCopyTemplateLang(stdout, TEMPLATES, "trailer.tmpl", getenv("LANG"));
+
+ /*
+ * 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 000000000..91222a628
--- /dev/null
+++ b/cgi-bin/printers.c
@@ -0,0 +1,360 @@
+/*
+ * "$Id$"
+ *
+ * Printer status CGI for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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 */
+ ipp_attribute_t *attr; /* IPP attribute */
+ ipp_status_t status; /* Operation status... */
+ char uri[HTTP_MAX_URI];
+ /* Printer URI */
+ const char *which_jobs; /* Which jobs to show */
+ const char *op; /* Operation to perform, if any */
+
+
+ /*
+ * Get any form variables...
+ */
+
+ cgiInitialize();
+ op = cgiGetVariable("OP");
+
+ /*
+ * Get the request language...
+ */
+
+ language = cupsLangDefault();
+
+ /*
+ * Connect to the HTTP server...
+ */
+
+ http = httpConnectEncrypt("localhost", ippPort(), cupsEncryption());
+
+ /*
+ * 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...
+ */
+
+ ippSetServerVersion();
+
+ printer = argv[0];
+ if (strcmp(printer, "/") == 0 || strcmp(printer, "printers.cgi") == 0)
+ {
+ printer = NULL;
+ cgiSetVariable("TITLE", cupsLangString(language, CUPS_MSG_PRINTER));
+ }
+ else
+ cgiSetVariable("TITLE", printer);
+
+ cgiCopyTemplateLang(stdout, TEMPLATES, "header.tmpl", getenv("LANG"));
+
+ if (op == NULL || strcasecmp(op, "print-test-page") != 0)
+ {
+ /*
+ * Get the default destination...
+ */
+
+ request = ippNew();
+ request->request.op.operation_id = CUPS_GET_DEFAULT;
+ 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 ((response = cupsDoRequest(http, request, "/")) != NULL)
+ {
+ if ((attr = ippFindAttribute(response, "printer-name", IPP_TAG_NAME)) != NULL)
+ cgiSetVariable("DEFAULT_NAME", attr->values[0].string.text);
+
+ if ((attr = ippFindAttribute(response, "printer-uri-supported", IPP_TAG_URI)) != NULL)
+ {
+ char method[HTTP_MAX_URI],
+ username[HTTP_MAX_URI],
+ hostname[HTTP_MAX_URI],
+ resource[HTTP_MAX_URI],
+ uri[HTTP_MAX_URI];
+ int port; /* URI data */
+ const char *server; /* Name of server */
+
+
+ /*
+ * Map localhost access to localhost...
+ */
+
+ server = getenv("SERVER_NAME");
+
+ httpSeparate(attr->values[0].string.text, method, username,
+ hostname, &port, resource);
+
+ if (strcasecmp(hostname, server) == 0 &&
+ (strcmp(getenv("REMOTE_HOST"), "127.0.0.1") == 0 ||
+ strcmp(getenv("REMOTE_HOST"), "localhost") == 0 ||
+ strcmp(getenv("REMOTE_HOST"), server) == 0))
+ strcpy(hostname, "localhost");
+
+ /*
+ * Rewrite URI with HTTP address...
+ */
+
+ snprintf(uri, sizeof(uri), "http://%s:%d%s", hostname, port,
+ resource);
+
+ cgiSetVariable("DEFAULT_URI", uri);
+ }
+
+ ippDelete(response);
+ }
+
+ /*
+ * 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, NULL, NULL);
+ ippDelete(response);
+ }
+
+ /*
+ * Write the report...
+ */
+
+ cgiCopyTemplateLang(stdout, TEMPLATES, "printers.tmpl", getenv("LANG"));
+
+ /*
+ * 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, NULL, NULL);
+ ippDelete(response);
+
+ cgiCopyTemplateLang(stdout, TEMPLATES, "jobs.tmpl", getenv("LANG"));
+ }
+ }
+ }
+ else
+ {
+ /*
+ * Print a test page...
+ */
+
+ snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", printer);
+
+ /*
+ * 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, NULL, NULL);
+
+ ippDelete(response);
+ }
+ else
+ status = IPP_GONE;
+
+ cgiSetVariable("PRINTER_NAME", printer);
+
+ if (status > IPP_OK_CONFLICT)
+ {
+ cgiSetVariable("ERROR", ippErrorString(status));
+ cgiCopyTemplateLang(stdout, TEMPLATES, "error.tmpl", getenv("LANG"));
+ }
+ else
+ cgiCopyTemplateLang(stdout, TEMPLATES, "test-page.tmpl", getenv("LANG"));
+ }
+
+ cgiCopyTemplateLang(stdout, TEMPLATES, "trailer.tmpl", getenv("LANG"));
+
+ /*
+ * 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 000000000..838689c82
--- /dev/null
+++ b/cgi-bin/template.c
@@ -0,0 +1,501 @@
+/*
+ * "$Id$"
+ *
+ * CGI template function.
+ *
+ * Copyright 1997-2002 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.
+ * cgiCopyTemplateLang() - Copy a template file using a language...
+ * 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 *tmpl) /* I - Template file to read */
+{
+ FILE *in; /* Input file */
+
+
+ /*
+ * Open the template file...
+ */
+
+ if ((in = fopen(tmpl, "r")) == NULL)
+ return;
+
+ /*
+ * Parse the file to the end...
+ */
+
+ cgi_copy(out, in, 0, 0);
+
+ /*
+ * Close the template file and return...
+ */
+
+ fclose(in);
+}
+
+
+/*
+ * 'cgiCopyTemplateLang()' - Copy a template file using a language...
+ */
+
+void
+cgiCopyTemplateLang(FILE *out, /* I - Output file */
+ const char *directory, /* I - Directory */
+ const char *tmpl, /* I - Base filename */
+ const char *lang) /* I - Language */
+{
+ int i; /* Looping var */
+ char filename[1024], /* Filename */
+ locale[16]; /* Locale name */
+ FILE *in; /* Input file */
+
+
+ /*
+ * Convert the language to a locale name...
+ */
+
+ if (lang != NULL)
+ {
+ for (i = 0; lang[i] && i < 15; i ++)
+ if (isalnum(lang[i]))
+ locale[i] = tolower(lang[i]);
+ else
+ locale[i] = '_';
+
+ locale[i] = '\0';
+ }
+ else
+ locale[0] = '\0';
+
+ /*
+ * See if we have a template file for this language...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/%s/%s", directory, locale, tmpl);
+ if (access(filename, 0))
+ {
+ locale[2] = '\0';
+
+ snprintf(filename, sizeof(filename), "%s/%s/%s", directory, locale, tmpl);
+ if (access(filename, 0))
+ snprintf(filename, sizeof(filename), "%s/%s", directory, tmpl);
+ }
+
+ /*
+ * Open the template file...
+ */
+
+ if ((in = fopen(filename, "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 */
+ *nameptr, /* Pointer into name */
+ innername[255], /* Inner comparison name */
+ *innerptr, /* Pointer into inner name */
+ *s; /* String pointer */
+ const char *value; /* Value of variable */
+ const char *innerval; /* Inner value */
+ const char *outptr; /* Output string pointer */
+ char outval[1024], /* Formatted 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("}]<>=! \t\n", ch))
+ break;
+ else if (s > name && ch == '?')
+ break;
+ else if (s < (name + sizeof(name) - 1))
+ *s++ = ch;
+
+ *s = '\0';
+
+ if (s == name && isspace(ch))
+ {
+ if (out)
+ {
+ putc('{', out);
+ putc(ch, out);
+ }
+
+ continue;
+ }
+
+ /*
+ * See if it has a value...
+ */
+
+ if (name[0] == '?')
+ {
+ /*
+ * Insert value only if it exists...
+ */
+
+ if ((nameptr = strrchr(name, '-')) != NULL && isdigit(nameptr[1]))
+ {
+ *nameptr++ = '\0';
+
+ if ((value = cgiGetArray(name + 1, atoi(nameptr) - 1)) != NULL)
+ outptr = value;
+ else
+ {
+ outval[0] = '\0';
+ outptr = outval;
+ }
+ }
+ if ((value = cgiGetArray(name + 1, element)) != NULL)
+ outptr = value;
+ else
+ {
+ outval[0] = '\0';
+ outptr = outval;
+ }
+ }
+ else if (name[0] == '#')
+ {
+ /*
+ * Insert count...
+ */
+
+ if (name[1])
+ sprintf(outval, "%d", cgiGetSize(name + 1));
+ else
+ sprintf(outval, "%d", element + 1);
+
+ outptr = outval;
+ }
+ 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 ((nameptr = strrchr(name, '-')) != NULL && isdigit(nameptr[1]))
+ {
+ *nameptr++ = '\0';
+ if ((value = cgiGetArray(name, atoi(nameptr) - 1)) == NULL)
+ {
+ snprintf(outval, sizeof(outval), "{%s}", name);
+ outptr = outval;
+ }
+ else
+ outptr = value;
+ }
+ else if ((value = cgiGetArray(name, element)) == NULL)
+ {
+ snprintf(outval, sizeof(outval), "{%s}", name);
+ outptr = outval;
+ }
+ else
+ outptr = value;
+ }
+
+ /*
+ * See if the terminating character requires another test...
+ */
+
+ if (ch == '}')
+ {
+ /*
+ * End of substitution...
+ */
+
+ if (out)
+ cgi_puts(outptr, out);
+
+ continue;
+ }
+
+ /*
+ * OK, process one of the following checks:
+ *
+ * {name?exist:not-exist} Exists?
+ * {name=value?true:false} Equal
+ * {name<value?true:false} Less than
+ * {name>value?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 (s >= (compare + sizeof(compare) - 1))
+ continue;
+ 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 != '}')
+ if (innerptr < (innername + sizeof(innername) - 1))
+ *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) - 1)) == NULL)
+ *s = '\0';
+ else
+ {
+ strncpy(s, innerval, sizeof(compare) - (s - compare) - 1);
+ compare[sizeof(compare) - 1] = '\0';
+ }
+ }
+ else if (innername[0] == '?')
+ {
+ if ((innerval = cgiGetArray(innername + 1, element)) == NULL)
+ *s = '\0';
+ else
+ {
+ strncpy(s, innerval, sizeof(compare) - (s - compare) - 1);
+ compare[sizeof(compare) - 1] = '\0';
+ }
+ }
+ else if ((innerval = cgiGetArray(innername, element)) == NULL)
+ snprintf(s, sizeof(s), "{%s}", innername);
+ else
+ {
+ strncpy(s, innerval, sizeof(compare) - (s - compare) - 1);
+ compare[sizeof(compare) - 1] = '\0';
+ }
+
+ 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(outptr, compare) < 0;
+ break;
+ case '>' :
+ result = strcasecmp(outptr, compare) > 0;
+ break;
+ case '=' :
+ result = strcasecmp(outptr, compare) == 0;
+ break;
+ case '!' :
+ result = strcasecmp(outptr, compare) != 0;
+ break;
+ default :
+ result = 1;
+ 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);
+
+ /*
+ * Flush any pending output...
+ */
+
+ if (out)
+ fflush(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] == '<')
+ fputs("&lt;", out);
+ else if (s[0] == '>')
+ fputs("&gt;", out);
+ else if (*s == '\"')
+ fputs("&quot;", out);
+ else if (s[0] == '&')
+ fputs("&amp;", 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 000000000..0c291a26e
--- /dev/null
+++ b/cgi-bin/var.c
@@ -0,0 +1,672 @@
+/*
+ * "$Id$"
+ *
+ * CGI form variable and array functions.
+ *
+ * Copyright 1997-2002 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"
+#include <errno.h>
+#include <syslog.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);
+
+ if (data == NULL)
+ return (0);
+
+ /*
+ * Read the data into the buffer...
+ */
+
+ for (tbytes = 0; tbytes < length; tbytes += nbytes)
+ if ((nbytes = read(0, data + tbytes, length - tbytes)) < 0)
+ if (errno != EAGAIN)
+ {
+ 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 ++)
+ if (*data == '=')
+ break;
+ else if (*data >= ' ' && s < (name + sizeof(name) - 1))
+ *s++ = *data;
+
+ *s = '\0';
+ if (*data == '=')
+ data ++;
+ else
+ return (0);
+
+ /*
+ * Read the variable value...
+ */
+
+ for (s = value, done = 0; !done && *data != '\0'; data ++)
+ switch (*data)
+ {
+ case '&' : /* End of data... */
+ done = 1;
+ break;
+
+ case '+' : /* Escaped space character */
+ if (s < (value + sizeof(value) - 1))
+ *s++ = ' ';
+ break;
+
+ case '%' : /* Escaped control character */
+ /*
+ * Read the hex code...
+ */
+
+ if (s < (value + sizeof(value) - 1))
+ {
+ data ++;
+ ch = *data - '0';
+ if (ch > 9)
+ ch -= 7;
+ *s = ch << 4;
+
+ data ++;
+ ch = *data - '0';
+ if (ch > 9)
+ ch -= 7;
+ *s++ |= ch;
+ }
+ else
+ data += 2;
+ break;
+
+ default : /* Other characters come straight through */
+ if (*data >= ' ' && s < (value + sizeof(value) - 1))
+ *s++ = *data;
+ break;
+ }
+
+ *s = '\0'; /* nul terminate the string */
+
+ /*
+ * Remove trailing whitespace...
+ */
+
+ if (s > value)
+ s --;
+
+ while (s >= value && *s == ' ')
+ *s-- = '\0';
+
+ /*
+ * Add the string to the variable "database"...
+ */
+
+ if ((s = strrchr(name, '-')) != NULL && isdigit(s[1]))
+ {
+ *s++ = '\0';
+ if (value[0])
+ cgiSetArray(name, atoi(s) - 1, value);
+ }
+ else if (cgiGetVariable(name) != NULL)
+ cgiSetArray(name, cgiGetSize(name), 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("Sorted variable list is:");
+ for (i = 0; i < form_count; i ++)
+ printf("%d: %s (%d) = \"%s\" ...\n", i, form_vars[i].name,
+ form_vars[i].nvalues, form_vars[i].values[0]);
+#endif /* DEBUG */
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/conf/Makefile b/conf/Makefile
new file mode 100644
index 000000000..6a4891e53
--- /dev/null
+++ b/conf/Makefile
@@ -0,0 +1,72 @@
+#
+# "$Id$"
+#
+# Configuration file makefile for the Common UNIX Printing System (CUPS).
+#
+# Copyright 1993-2002 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:
+ $(INSTALL_DIR) $(SERVERROOT)
+ for file in $(KEEP); do \
+ if test -r $(SERVERROOT)/$$file ; then \
+ $(INSTALL_DATA) $$file $(SERVERROOT)/$$file.N ; \
+ else \
+ $(INSTALL_DATA) $$file $(SERVERROOT) ; \
+ fi ; \
+ done
+ for file in $(REPLACE); do \
+ if test -r $(SERVERROOT)/$$file ; then \
+ $(MV) $(SERVERROOT)/$$file $(SERVERROOT)/$$file.O ; \
+ fi ; \
+ $(INSTALL_DATA) $$file $(SERVERROOT) ; \
+ done
+
+
+#
+# End of "$Id$".
+#
diff --git a/conf/classes.conf b/conf/classes.conf
new file mode 100644
index 000000000..05526a605
--- /dev/null
+++ b/conf/classes.conf
@@ -0,0 +1,89 @@
+#
+# "$Id: classes.conf 2010 2002-01-02 17:59:21Z mike $"
+#
+# Sample class configuration file for the Common UNIX Printing System
+# (CUPS) scheduler.
+#
+# Copyright 1997-2002 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 <Class name> definition. Class names
+# can be up to 128 characters in length and are *not* case sensitive.
+#
+# One <DefaultClass name> entry can appear in this file; if you don't
+# define a default destination, the first printer or class becomes
+# the default.
+#
+
+#<Class sample>
+#
+# Info: the description for the class.
+#
+
+#Info Acme LaserPrint 1000 Printers
+
+#
+# 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
+#</Class>
+
+#
+# End of "$Id: classes.conf 2010 2002-01-02 17:59:21Z mike $".
+#
diff --git a/conf/client.conf b/conf/client.conf
new file mode 100644
index 000000000..244b5e1fe
--- /dev/null
+++ b/conf/client.conf
@@ -0,0 +1,65 @@
+#
+# "$Id: client.conf 2010 2002-01-02 17:59:21Z mike $"
+#
+# Sample client configuration file for the Common UNIX Printing System
+# (CUPS).
+#
+# Copyright 1997-2002 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 encryption settings. #
+# #
+########################################################################
+
+#
+# ServerName: the hostname of your server. By default CUPS will use the
+# hostname of the system or the value of the CUPS_SERVER environment
+# variable.
+#
+
+#ServerName myhost.domain.com
+
+#
+# Encryption: whether or not to use encryption; this depends on having
+# the OpenSSL library linked into the CUPS library.
+#
+# Possible values:
+#
+# Always - Always use encryption (SSL)
+# Never - Never use encryption
+# Required - Use TLS encryption upgrade
+# IfRequested - Use encryption if the server requests it
+#
+# The default value is "IfRequested". This parameter can also be set
+# using the CUPS_ENCRYPTION environment variable.
+#
+
+#Encryption Always
+#Encryption Never
+#Encryption Required
+#Encryption IfRequested
+
+
+#
+# End of "$Id: client.conf 2010 2002-01-02 17:59:21Z mike $".
+#
diff --git a/conf/cupsd.conf.in b/conf/cupsd.conf.in
new file mode 100644
index 000000000..15e3fd25a
--- /dev/null
+++ b/conf/cupsd.conf.in
@@ -0,0 +1,720 @@
+#
+# "$Id$"
+#
+# Sample configuration file for the Common UNIX Printing System (CUPS)
+# scheduler.
+#
+# Copyright 1997-2002 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... #
+# #
+########################################################################
+
+
+########
+######## Server Identity
+########
+
+#
+# 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 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
+
+
+########
+######## Server Options
+########
+
+#
+# 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
+# "@CUPS_LOGDIR@/access_log"
+#
+# You can also use the special name "syslog" to send the output to the
+# syslog file or daemon.
+#
+
+#AccessLog @CUPS_LOGDIR@/access_log
+
+#
+# Classification: the classification level of the server. If set, this
+# classification is displayed on all pages, and raw printing is disabled.
+# The default is the empty string.
+#
+
+#Classification classified
+#Classification confidential
+#Classification secret
+#Classification topsecret
+#Classification unclassified
+
+#
+# ClassifyOverride: whether to allow users to override the classification
+# on printouts. If enabled, users can limit banner pages to before or
+# after the job, and can change the classification of a job, but cannot
+# completely eliminate the classification or banners.
+#
+# The default is off.
+#
+
+#ClassifyOverride off
+
+#
+# DataDir: the root directory for the CUPS data files.
+# By default "@CUPS_DATADIR@".
+#
+
+#DataDir @CUPS_DATADIR@
+
+#
+# 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
+
+#
+# DefaultLanguage: the default language if not specified by the browser.
+# If not specified, the current locale is used.
+#
+
+#DefaultLanguage en
+
+#
+# DocumentRoot: the root directory for HTTP documents that are served.
+# By default "@CUPS_DOCROOT@".
+#
+
+#DocumentRoot @CUPS_DOCROOT@
+
+#
+# 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
+# "@CUPS_LOGDIR@/error_log"
+#
+# You can also use the special name "syslog" to send the output to the
+# syslog file or daemon.
+#
+
+#ErrorLog @CUPS_LOGDIR@/error_log
+
+#
+# FontPath: the path to locate all font files (currently only for pstoraster)
+# By default "@CUPS_FONTPATH@".
+#
+
+#FontPath @CUPS_FONTPATH@
+
+#
+# LogLevel: controls the number of messages logged to the ErrorLog
+# file and can be one of the following:
+#
+# debug2 Log everything.
+# debug Log almost 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
+
+#
+# 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
+# "@CUPS_LOGDIR@/page_log"
+#
+# You can also use the special name "syslog" to send the output to the
+# syslog file or daemon.
+#
+
+#PageLog @CUPS_LOGDIR@/page_log
+
+#
+# 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
+
+#
+# AutoPurgeJobs: automatically purge jobs when not needed for quotas.
+# Default is No.
+#
+
+#AutoPurgeJobs No
+
+#
+# MaxJobs: maximum number of jobs to keep in memory (active and completed.)
+# Default is 500; the value 0 is used for no limit.
+#
+
+#MaxJobs 500
+
+#
+# Printcap: the name of the printcap file. Default is /etc/printcap.
+# Leave blank to disable printcap file generation.
+#
+
+#Printcap /etc/printcap
+
+#
+# PrintcapFormat: the format of the printcap file, currently either
+# BSD or Solaris. The default is "BSD".
+#
+
+#PrintcapFormat BSD
+#PrintcapFormat Solaris
+
+#
+# PrintcapGUI: the name of the GUI options panel program to associate
+# with print queues under IRIX. The default is "/usr/bin/glpoptions"
+# from ESP Print Pro.
+#
+# This option is only used under IRIX; the options panel program
+# must accept the "-d printer" and "-o options" options and write
+# the selected printer options back to stdout on completion.
+#
+
+#PrintcapGUI /usr/bin/glpoptions
+
+#
+# RequestRoot: the directory where request files are stored.
+# By default "@CUPS_REQUESTS@".
+#
+
+#RequestRoot @CUPS_REQUESTS@
+
+#
+# RemoteRoot: the name of the user assigned to unauthenticated accesses
+# from remote systems. By default "remroot".
+#
+
+#RemoteRoot remroot
+
+#
+# ServerBin: the root directory for the scheduler executables.
+# By default "@CUPS_SERVERBIN@".
+#
+
+#ServerBin @CUPS_SERVERBIN@
+
+#
+# ServerRoot: the root directory for the scheduler.
+# By default "@CUPS_SERVERROOT@".
+#
+
+#ServerRoot @CUPS_SERVERROOT@
+
+
+########
+######## Encryption Support
+########
+
+#
+# ServerCertificate: the file to read containing the server's certificate.
+# Defaults to "@CUPS_SERVERROOT@/ssl/server.crt".
+#
+
+#ServerCertificate @CUPS_SERVERROOT@/ssl/server.crt
+
+#
+# ServerKey: the file to read containing the server's key.
+# Defaults to "@CUPS_SERVERROOT@/ssl/server.key".
+#
+
+#ServerKey @CUPS_SERVERROOT@/ssl/server.key
+
+
+########
+######## Filter Options
+########
+
+#
+# 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
+
+#
+# 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 "@CUPS_REQUESTS@/tmp" or
+# the value of the TMPDIR environment variable.
+#
+
+#TempDir @CUPS_REQUESTS@/tmp
+
+#
+# FilterLimit: sets the maximum cost of all job filters that can be run
+# at the same time. A limit of 0 means no limit. A typical job may need
+# a filter limit of at least 200; limits less than the minimum required
+# by a job force a single job to be printed at any time.
+#
+# The default limit is 0 (unlimited).
+#
+
+#FilterLimit 0
+
+########
+######## Network Options
+########
+
+#
+# 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
+#
+# NOTE: Unfortunately, most web browsers don't support TLS or HTTP Upgrades
+# for encryption. If you want to support web-based encryption you'll
+# probably need to listen on port 443 (the "https" port...)
+#
+
+#Port 80
+#Port 443
+Port 631
+
+#
+# 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
+
+#
+# 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
+
+#
+# MaxClients: controls the maximum number of simultaneous clients that
+# will be handled. Defaults to 100.
+#
+
+#MaxClients 100
+
+#
+# MaxRequestSize: controls the maximum size of HTTP requests and print files.
+# Set to 0 to disable this feature (defaults to 0.)
+#
+
+#MaxRequestSize 0
+
+#
+# Timeout: the timeout before requests time out. Default is 300 seconds.
+#
+
+#Timeout 300
+
+
+########
+######## Browsing Options
+########
+
+#
+# Browsing: whether or not to broadcast and/or listen for CUPS printer
+# information on the network. Enabled by default.
+#
+
+#Browsing On
+
+#
+# BrowseProtocols: which protocols to use for browsing. Can be
+# any of the following separated by whitespace and/or commas:
+#
+# all - Use all supported protocols.
+# cups - Use the CUPS browse protocol.
+# slp - Use the SLPv2 protocol.
+#
+# The default is "cups".
+#
+# NOTE: If you choose to use SLPv2, it is *strongly* recommended that
+# you have at least one SLP Directory Agent (DA) on your
+# network. Otherwise, browse updates can take several seconds,
+# during which the scheduler will not response to client
+# requests.
+#
+
+#BrowseProtocols cups
+
+#
+# BrowseAddress: specifies a broadcast address to be used. By
+# default browsing information is not sent!
+#
+# Note: HP-UX does not properly handle broadcast unless you have a
+# Class A, B, C, or D netmask (i.e. no CIDR support).
+#
+# Note: Using the "global" broadcast address (255.255.255.255) will
+# activate a Linux demand-dial link with the default configuration.
+# If you have a LAN as well as the dial-up link, use the LAN's
+# broadcast address.
+#
+
+#BrowseAddress x.y.z.255
+#BrowseAddress x.y.255.255
+#BrowseAddress x.255.255.255
+#BrowseAddress 255.255.255.255
+
+#
+# BrowseShortNames: whether or not to use "short" names for remote printers
+# when possible (e.g. "printer" instead of "printer@host".) Enabled by
+# default.
+#
+
+#BrowseShortNames Yes
+
+#
+# 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
+
+#
+# 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
+
+#
+# BrowseOrder: specifies the order of BrowseAllow/BrowseDeny comparisons.
+#
+
+#BrowseOrder allow,deny
+#BrowseOrder deny,allow
+
+#
+# BrowsePoll: poll the named server(s) for printers
+#
+
+#BrowsePoll address:port
+
+#
+# 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
+
+#
+# BrowseRelay: relay browser packets from one address/network to another.
+#
+
+#BrowseRelay source-address destination-address
+
+#
+# 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
+
+#
+# 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
+
+#
+# ImplicitAnyClasses: whether or not to create "AnyPrinter" implicit
+# classes.
+#
+# When ImplicitAnyClasses is On and a local queue of the same name
+# exists, e.g. "printer", "printer@server1", "printer@server1", then
+# an implicit class called "Anyprinter" is created instead.
+#
+# When ImplicitAnyClasses is Off, implicit classes are not created
+# when there is a local queue of the same name.
+#
+# Disabled by default.
+#
+
+#ImplicitAnyCLasses Off
+
+#
+# HideImplicitMembers: whether or not to show the members of an
+# implicit class.
+#
+# When HideImplicitMembers is On, any remote printers that are
+# part of an implicit class are hidden from the user, who will
+# then only see a single queue even though many queues will be
+# supporting the implicit class.
+#
+# Enabled by default.
+#
+
+#HideImplicitMembers On
+
+
+########
+######## Security Options
+########
+
+#
+# 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
+
+#
+# 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 when connecting to the
+# localhost interface)
+#
+# 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.
+#
+# Encryption: whether or not to use encryption; this depends on having
+# the OpenSSL library linked into the CUPS library and scheduler.
+#
+# Possible values:
+#
+# Always - Always use encryption (SSL)
+# Never - Never use encryption
+# Required - Use TLS encryption upgrade
+# IfRequested - Use encryption if the server requests it
+#
+# The default value is "IfRequested".
+#
+
+<Location />
+Order Deny,Allow
+Deny From All
+Allow From 127.0.0.1
+</Location>
+
+#<Location /classes>
+#
+# You may wish to limit access to printers and classes, either with Allow
+# and Deny lines, or by requiring a username and password.
+#
+#</Location>
+
+#<Location /classes/name>
+#
+# You may wish to limit access to printers and classes, either with Allow
+# and Deny lines, or by requiring a username and password.
+#
+#</Location>
+
+#<Location /printers>
+#
+# You may wish to limit access to printers and classes, either with Allow
+# and Deny lines, or by requiring a username and password.
+#
+#</Location>
+
+#<Location /printers/name>
+#
+# 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
+#</Location>
+
+<Location /admin>
+#
+# You definitely will want to limit access to the administration functions.
+# 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
+
+#Encryption Required
+</Location>
+
+#
+# End of "$Id$".
+#
diff --git a/conf/mime.convs b/conf/mime.convs
new file mode 100644
index 000000000..57c537893
--- /dev/null
+++ b/conf/mime.convs
@@ -0,0 +1,87 @@
+#
+# "$Id: mime.convs 2062 2002-01-23 22:30:42Z mike $"
+#
+# MIME converts file for the Common UNIX Printing System (CUPS).
+#
+# Copyright 1997-2002 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:
+#
+# The "cost" field is used to find the least costly filters to run
+# when converting a job file to a printable format.
+#
+# All filters *must* accept the standard command-line arguments
+# (job-id, user, title, copies, options, [filename or stdin]) to
+# work with CUPS.
+#
+
+########################################################################
+#
+# PostScript filters
+#
+
+application/pdf application/postscript 33 pdftops
+application/postscript application/vnd.cups-postscript 66 pstops
+application/vnd.hp-HPGL application/postscript 66 hpgltops
+image/* application/vnd.cups-postscript 66 imagetops
+application/x-cshell application/postscript 33 texttops
+application/x-perl application/postscript 33 texttops
+application/x-shell application/postscript 33 texttops
+text/plain application/postscript 33 texttops
+text/html application/postscript 33 texttops
+
+########################################################################
+#
+# Form filter...
+#
+# This filter does not currently exist, but the file format is defined
+# in the IDD and registered with the IANA for future use...
+#
+
+#application/vnd.cups-form application/vnd.cups-postscript 33 formtops
+
+########################################################################
+#
+# Raster filters...
+#
+
+image/* application/vnd.cups-raster 100 imagetoraster
+application/vnd.cups-postscript application/vnd.cups-raster 100 pstoraster
+
+########################################################################
+#
+# Raw filter...
+#
+# Uncomment the following filter and the application/octet-stream type
+# in mime.types to allow printing of arbitrary files without the -oraw
+# option.
+#
+
+#application/octet-stream application/vnd.cups-raw 0 -
+
+#
+# End of "$Id: mime.convs 2062 2002-01-23 22:30:42Z mike $".
+#
diff --git a/conf/mime.types b/conf/mime.types
new file mode 100644
index 000000000..23363b2dc
--- /dev/null
+++ b/conf/mime.types
@@ -0,0 +1,156 @@
+#
+# "$Id: mime.types 2010 2002-01-02 17:59:21Z mike $"
+#
+# MIME types file for the Common UNIX Printing System (CUPS).
+#
+# Copyright 1997-2002 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, 128-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
+# contains(offset,range,"string") True if the range contains the 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 128-255.
+#
+# String constants must be surrounded by "" if they contain whitespace.
+# To insert binary data into a string, use the <hex> notation.
+#
+
+########################################################################
+#
+# Application-generated files...
+#
+
+application/msword doc string(0,<D0CF11E0A1B11AE1>)
+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>E<1B>%0B) string(0,<201B>)\
+ string(0,BP;) string(0,IN;) string(0,DF;) \
+ string(0,BPINPS;) \
+ (contains(0,128,<1B>%-12345X) + \
+ (contains(9,512,"LANGUAGE=HPGL") \
+ contains(9,512,"LANGUAGE = HPGL")))
+
+########################################################################
+#
+# Image files...
+#
+
+image/gif gif string(0,GIF87a) string(0,GIF89a)
+image/png png string(0,<89>PNG)
+image/jpeg jpeg jpg jpe string(0,<FFD8FF>) &&\
+ (char(3,0xe0) char(3,0xe1) char(3,0xe2) char(3,0xe3)\
+ char(3,0xe4) char(3,0xe5) char(3,0xe6) char(3,0xe7)\
+ char(3,0xe8) char(3,0xe9) char(3,0xea) char(3,0xeb)\
+ char(3,0xec) char(3,0xed) char(3,0xee) char(3,0xef))
+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 string(0,<59a66a95>)
+
+#image/fpx fpx
+image/x-alias pix short(8,8) short(8,24)
+image/x-bitmap bmp string(0,BM) && !printable(2,14)
+
+########################################################################
+#
+# Text files...
+#
+
+text/html html htm printable(0,1024) +\
+ (string(0,"<HTML>") string(0,"<!DOCTYPE"))
+application/x-cshell csh printable(0,1024) + string(0,#!) +\
+ (contains(2,80,/csh) contains(2,80,/tcsh))
+application/x-perl pl printable(0,1024) + string(0,#!) +\
+ contains(2,80,/perl)
+application/x-shell sh printable(0,1024) + string(0,#!) +\
+ (contains(2,80,/bash) contains(2,80,/ksh)\
+ contains(2,80,/sh) contains(2,80,/zsh))
+text/plain txt printable(0,1024)
+
+########################################################################
+#
+# CUPS-specific types...
+#
+
+application/vnd.cups-form string(0,"<CUPSFORM>")
+application/vnd.cups-postscript contains(0,128,<1B>%-12345X) + \
+ (contains(9,512,"LANGUAGE=POSTSCRIPT") \
+ contains(9,512,"LANGUAGE = Postscript") \
+ contains(9,512,"LANGUAGE = POSTSCRIPT"))
+application/vnd.cups-raster string(0,"RaSt") string(0,"tSaR")
+application/vnd.cups-raw (string(0,<1B>E) + !string(2,<1B>%0B)) \
+ string(0,<1B>@) \
+ (contains(0,128,<1B>%-12345X) + \
+ (contains(9,512,"LANGUAGE=PCL") \
+ contains(9,512,"LANGUAGE = PCL")))
+
+########################################################################
+#
+# Raw print file support...
+#
+# Uncomment the following type and the application/octet-stream
+# filter line in mime.convs to allow raw file printing without the
+# -oraw option.
+#
+
+#application/octet-stream
+
+#
+# End of "$Id: mime.types 2010 2002-01-02 17:59:21Z mike $".
+#
diff --git a/conf/printcap b/conf/printcap
new file mode 100644
index 000000000..230c3017d
--- /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 000000000..c69067569
--- /dev/null
+++ b/conf/printers.conf
@@ -0,0 +1,96 @@
+#
+# "$Id: printers.conf 2010 2002-01-02 17:59:21Z mike $"
+#
+# Sample printer configuration file for the Common UNIX Printing System
+# (CUPS) scheduler.
+#
+# Copyright 1997-2002 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 <Printer name> definition. Printer names
+# can be up to 128 characters in length and are *not* case sensitive.
+#
+# One <DefaultPrinter name> entry can appear in this file; if you don't
+# define a default destination, the first printer or class becomes the
+# default.
+#
+
+#<Printer sample>
+#
+# Info: the description for the printer.
+#
+
+#Info Acme LaserPrint 1000
+
+#
+# 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
+
+#</Printer>
+
+#
+# End of "$Id: printers.conf 2010 2002-01-02 17:59:21Z mike $".
+#
diff --git a/config-scripts/cups-common.m4 b/config-scripts/cups-common.m4
new file mode 100644
index 000000000..5c97a1d6d
--- /dev/null
+++ b/config-scripts/cups-common.m4
@@ -0,0 +1,155 @@
+dnl
+dnl "$Id: cups-common.m4 2035 2002-01-14 20:29:17Z mike $"
+dnl
+dnl Common configuration stuff for the Common UNIX Printing System (CUPS).
+dnl
+dnl Copyright 1997-2002 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
+
+dnl We need at least autoconf 2.13...
+AC_PREREQ(2.13)
+
+dnl Set the name of the config header file...
+AC_CONFIG_HEADER(config.h)
+
+dnl Default compiler flags...
+CFLAGS="${CFLAGS:=}"
+CPPFLAGS="${CPPFLAGS:=}"
+CXXFLAGS="${CXXFLAGS:=}"
+LDFLAGS="${LDFLAGS:=}"
+
+dnl Checks for programs...
+AC_PROG_AWK
+AC_PROG_CC
+AC_PROG_CXX
+AC_PROG_CPP
+AC_PROG_INSTALL
+if test "$INSTALL" = "$ac_install_sh"; then
+ # Use full path to install-sh script...
+ INSTALL="`pwd`/install-sh -c"
+fi
+AC_PROG_RANLIB
+AC_PATH_PROG(AR,ar)
+AC_PATH_PROG(HTMLDOC,htmldoc)
+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(RM,rm)
+AC_PATH_PROG(SED,sed)
+
+dnl Architecture checks...
+AC_C_BIGENDIAN
+
+dnl Check for libraries...
+AC_SEARCH_LIBS(crypt, crypt)
+AC_SEARCH_LIBS(getspent, sec gen)
+
+LIBMALLOC=""
+AC_CHECK_LIB(c,mallinfo,LIBS="$LIBS"; AC_DEFINE(HAVE_MALLINFO),LIBS="$LIBS")
+if test "$ac_cv_lib_c_mallinfo" = "no"; then
+ AC_CHECK_LIB(malloc,mallinfo,
+ LIBS="$LIBS"
+ LIBMALLOC="-lmalloc"
+ AC_DEFINE(HAVE_MALLINFO),
+ LIBS="$LIBS")
+fi
+AC_SUBST(LIBMALLOC)
+
+dnl Checks for header files.
+AC_HEADER_STDC
+AC_HEADER_DIRENT
+AC_CHECK_HEADER(crypt.h,AC_DEFINE(HAVE_CRYPT_H))
+AC_CHECK_HEADER(malloc.h,AC_DEFINE(HAVE_MALLOC_H))
+AC_CHECK_HEADER(shadow.h,AC_DEFINE(HAVE_SHADOW_H))
+AC_CHECK_HEADER(string.h,AC_DEFINE(HAVE_STRING_H))
+AC_CHECK_HEADER(strings.h,AC_DEFINE(HAVE_STRINGS_H))
+AC_CHECK_HEADER(usersec.h,AC_DEFINE(HAVE_USERSEC_H))
+AC_CHECK_HEADER(sys/ioctl.h,AC_DEFINE(HAVE_SYS_IOCTL_H))
+
+dnl Checks for string functions.
+AC_CHECK_FUNCS(strdup strcasecmp strncasecmp)
+if test "$uname" = "HP-UX" -a "$uversion" = "1020"; then
+ echo Forcing snprintf emulation for HP-UX.
+else
+ AC_CHECK_FUNCS(snprintf vsnprintf)
+fi
+
+dnl Check OS version and use appropriate format string for strftime...
+AC_MSG_CHECKING(for correct format string to use with strftime)
+
+case "$uname" in
+ IRIX* | SunOS*)
+ # IRIX and SunOS
+ AC_MSG_RESULT(NULL)
+ AC_DEFINE(CUPS_STRFTIME_FORMAT, NULL)
+ ;;
+ *)
+ # All others
+ AC_MSG_RESULT("%c")
+ AC_DEFINE(CUPS_STRFTIME_FORMAT, "%c")
+ ;;
+esac
+
+dnl Checks for mkstemp and mkstemps functions.
+AC_CHECK_FUNCS(mkstemp mkstemps)
+
+dnl Checks for vsyslog function.
+AC_CHECK_FUNCS(vsyslog)
+
+dnl Checks for signal functions.
+if test "$uname" != "Linux"; then
+ AC_CHECK_FUNCS(sigset)
+fi
+
+AC_CHECK_FUNCS(sigaction)
+
+dnl Checks for wait functions.
+AC_CHECK_FUNCS(waitpid)
+AC_CHECK_FUNCS(wait3)
+
+dnl See if the tm structure has the tm_gmtoff member...
+AC_MSG_CHECKING(for tm_gmtoff member in tm structure)
+AC_TRY_COMPILE([#include <time.h>],[struct tm t;
+ int o = t.tm_gmtoff;],
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_TM_GMTOFF),
+ AC_MSG_RESULT(no))
+
+dnl Flags for "ar" command...
+case $uname in
+ Darwin* | *BSD*)
+ ARFLAGS="-rcv"
+ ;;
+ *)
+ ARFLAGS="crvs"
+ ;;
+esac
+
+AC_SUBST(ARFLAGS)
+
+dnl
+dnl End of "$Id: cups-common.m4 2035 2002-01-14 20:29:17Z mike $".
+dnl
diff --git a/config-scripts/cups-compiler.m4 b/config-scripts/cups-compiler.m4
new file mode 100644
index 000000000..5902867c3
--- /dev/null
+++ b/config-scripts/cups-compiler.m4
@@ -0,0 +1,187 @@
+dnl
+dnl "$Id: cups-compiler.m4 2075 2002-01-26 21:35:09Z mike $"
+dnl
+dnl Common configuration stuff for the Common UNIX Printing System (CUPS).
+dnl
+dnl Copyright 1997-2002 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
+dnl Clear the debugging and non-shared library options unless the user asks
+dnl for them...
+
+OPTIM=""
+AC_SUBST(OPTIM)
+
+AC_ARG_ENABLE(debug, [ --enable-debug turn on debugging [default=no]],
+ [if test x$enable_debug = xyes; then
+ OPTIM="-g"
+ fi])
+
+AC_ARG_WITH(optim, [ --with-optim=\"flags\" set optimization flags ])
+
+dnl Update compiler options...
+if test -n "$GCC"; then
+ # Starting with GCC 3.0, you must link C++ programs against either
+ # libstdc++ (shared by default), or libsupc++ (always static). If
+ # you care about binary portability between Linux distributions,
+ # you need to either 1) build your own GCC with static C++ libraries
+ # or 2) link using gcc and libsupc++. We choose the latter since
+ # CUPS doesn't (currently) use any of the stdc++ library.
+ #
+ # Also, GCC 3.0.x still has problems compiling some code. You may
+ # or may not have success with it. USE 3.0.x WITH EXTREME CAUTION!
+ #
+ # Previous versions of GCC do not have the reliance on the stdc++
+ # or g++ libraries, so the extra supc++ library is not needed.
+
+ AC_MSG_CHECKING(if libsupc++ is required)
+
+ SUPC="`$CXX -print-file-name=libsupc++.a 2>/dev/null`"
+ if test -n "$SUPC" -a "$SUPC" != "libsupc++.a"; then
+ # This is gcc 3.x, and it knows of libsupc++, so we need it
+ LIBS="$LIBS -lsupc++"
+ AC_MSG_RESULT(yes)
+ else
+ AC_MSG_RESULT(no)
+ fi
+
+ CXX="$CC"
+
+ if test -z "$OPTIM"; then
+ if test "x$with_optim" = x; then
+ if test $uname = HP-UX; then
+ # GCC under HP-UX has bugs with -O2
+ OPTIM="-O1"
+ else
+ OPTIM="-O2"
+ fi
+ else
+ OPTIM="$with_optim $OPTIM"
+ fi
+ fi
+
+ if test $PICFLAG = 1 -a $uname != AIX; then
+ OPTIM="-fPIC $OPTIM"
+ fi
+
+ if test "x$with_optim" = x; then
+ OPTIM="-Wall $OPTIM"
+ fi
+else
+ case $uname in
+ AIX*)
+ if test -z "$OPTIM"; then
+ if test "x$with_optim" = x; then
+ OPTIM="-O2 -qmaxmem=6000"
+ else
+ OPTIM="$with_optim $OPTIM"
+ fi
+ fi
+ ;;
+ HP-UX*)
+ if test -z "$OPTIM"; then
+ if test "x$with_optim" = x; then
+ OPTIM="+O2"
+ else
+ OPTIM="$with_optim $OPTIM"
+ fi
+ fi
+
+ CFLAGS="-Ae $CFLAGS"
+
+ if test "x$with_optim" = x; then
+ OPTIM="+DAportable $OPTIM"
+ fi
+
+ if test $PICFLAG = 1; then
+ OPTIM="+z $OPTIM"
+ fi
+ ;;
+ IRIX*)
+ if test -z "$OPTIM"; then
+ if test "x$with_optim" = x; then
+ OPTIM="-O2"
+ else
+ OPTIM="$with_optim $OPTIM"
+ fi
+ fi
+
+ if test $uversion -ge 62 -a "x$with_optim" = x; then
+ OPTIM="$OPTIM -n32 -mips3"
+ fi
+
+ if test "x$with_optim" = x; then
+ OPTIM="-fullwarn $OPTIM"
+ fi
+ ;;
+ SunOS*)
+ # Solaris
+ if test -z "$OPTIM"; then
+ if test "x$with_optim" = x; then
+ OPTIM="-xO4"
+ else
+ OPTIM="$with_optim $OPTIM"
+ fi
+ fi
+
+ if test "x$with_optim" = x; then
+ OPTIM="$OPTIM -xarch=generic"
+ fi
+
+ if test $PICFLAG = 1; then
+ OPTIM="-KPIC $OPTIM"
+ fi
+ ;;
+ UNIX_SVR*)
+ # UnixWare
+ if test -z "$OPTIM"; then
+ if test "x$with_optim" = x; then
+ OPTIM="-O"
+ else
+ OPTIM="$with_optim $OPTIM"
+ fi
+ 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-bugs@cups.org with uname and compiler options needed"
+ echo "for your platform, or set the CFLAGS and CXXFLAGS"
+ echo "environment variable before running configure."
+ ;;
+ esac
+fi
+
+case $uname in
+ Darwin* | *BSD)
+ ARFLAGS="-rcv"
+ ;;
+ *)
+ ARFLAGS="crvs"
+ ;;
+esac
+
+dnl
+dnl End of "$Id: cups-compiler.m4 2075 2002-01-26 21:35:09Z mike $".
+dnl
diff --git a/config-scripts/cups-directories.m4 b/config-scripts/cups-directories.m4
new file mode 100644
index 000000000..9f3be4810
--- /dev/null
+++ b/config-scripts/cups-directories.m4
@@ -0,0 +1,238 @@
+dnl
+dnl "$Id: cups-directories.m4 2064 2002-01-24 18:51:13Z mike $"
+dnl
+dnl Directory stuff for the Common UNIX Printing System (CUPS).
+dnl
+dnl Copyright 1997-2002 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_PREFIX_DEFAULT(/)
+
+AC_ARG_WITH(fontpath, [ --with-fontpath set font path for pstoraster],fontpath="$withval",fontpath="")
+AC_ARG_WITH(docdir, [ --with-docdir set path for documentation],docdir="$withval",docdir="")
+AC_ARG_WITH(logdir, [ --with-logdir set path for log files],logdir="$withval",logdir="")
+AC_ARG_WITH(rcdir, [ --with-rcdir set path for rc scripts],rcdir="$withval",rcdir="")
+
+dnl Fix "prefix" variable if it hasn't been specified...
+if test "$prefix" = "NONE"; then
+ prefix="/"
+fi
+
+dnl Fix "exec_prefix" variable if it hasn't been specified...
+if test "$exec_prefix" = "NONE"; then
+ if test "$prefix" = "/"; then
+ exec_prefix="/usr"
+ else
+ exec_prefix="$prefix"
+ fi
+fi
+
+dnl Fix "sharedstatedir" variable if it hasn't been specified...
+if test "$sharedstatedir" = "\${prefix}/com" -a "$prefix" = "/"; then
+ sharedstatedir="/usr/com"
+fi
+
+dnl Fix "datadir" variable if it hasn't been specified...
+if test "$datadir" = "\${prefix}/share"; then
+ if test "$prefix" = "/"; then
+ datadir="/usr/share"
+ else
+ datadir="$prefix/share"
+ fi
+fi
+
+dnl Fix "includedir" variable if it hasn't been specified...
+if test "$includedir" = "\${prefix}/include" -a "$prefix" = "/"; then
+ includedir="/usr/include"
+fi
+
+dnl Fix "localstatedir" variable if it hasn't been specified...
+if test "$localstatedir" = "\${prefix}/var"; then
+ if test "$prefix" = "/"; then
+ localstatedir="/var"
+ else
+ localstatedir="$prefix/var"
+ fi
+fi
+
+dnl Fix "sysconfdir" variable if it hasn't been specified...
+if test "$sysconfdir" = "\${prefix}/etc"; then
+ if test "$prefix" = "/"; then
+ sysconfdir="/etc"
+ else
+ sysconfdir="$prefix/etc"
+ fi
+fi
+
+dnl Fix "libdir" variable for IRIX 6.x...
+if test "$uname" = "IRIX" -a $uversion -ge 62; then
+ libdir="$exec_prefix/lib32"
+fi
+
+dnl Fix "fontpath" variable...
+if test "x$fontpath" = "x"; then
+ fontpath="$datadir/cups/fonts"
+fi
+
+dnl Setup init.d locations...
+if test x$rcdir = x; then
+ case "$uname" in
+ FreeBSD* | OpenBSD*)
+ # FreeBSD and OpenBSD
+ INITDIR=""
+ INITDDIR=""
+ ;;
+
+ NetBSD*)
+ # NetBSD
+ INITDIR=""
+ INITDDIR="/etc/rc.d"
+ ;;
+
+ Darwin*)
+ # Darwin and MacOS X - this is just strange...
+ INITDIR=""
+ INITDDIR="/System/Library/StartupItems/CUPS"
+ ;;
+
+ Linux*)
+ # Linux seems to choose an init.d directory at random...
+ if test -d /sbin/init.d; then
+ # SuSE
+ INITDIR="/sbin/init.d"
+ INITDDIR=".."
+ else
+ if test -d /etc/rc.d; then
+ # RedHat
+ INITDIR="/etc/rc.d"
+ INITDDIR="../init.d"
+ else
+ # Others
+ INITDIR="/etc"
+ INITDDIR="../init.d"
+ fi
+ fi
+ ;;
+
+ OSF1* | HP-UX*)
+ INITDIR="/sbin"
+ INITDDIR="../init.d"
+ ;;
+
+ AIX*)
+ INITDIR="/etc/rc.d"
+ INITDDIR=".."
+ ;;
+
+ *)
+ INITDIR="/etc"
+ INITDDIR="../init.d"
+ ;;
+
+ esac
+else
+ INITDIR=""
+ INITDDIR="$rcdir"
+fi
+
+AC_SUBST(INITDIR)
+AC_SUBST(INITDDIR)
+
+dnl Setup default locations...
+CUPS_SERVERROOT="$sysconfdir/cups"
+CUPS_REQUESTS="$localstatedir/spool/cups"
+
+AC_DEFINE_UNQUOTED(CUPS_SERVERROOT, "$sysconfdir/cups")
+AC_DEFINE_UNQUOTED(CUPS_REQUESTS, "$localstatedir/spool/cups")
+
+if test x$logdir = x; then
+ CUPS_LOGDIR="$localstatedir/log/cups"
+ AC_DEFINE_UNQUOTED(CUPS_LOGDIR, "$localstatedir/log/cups")
+else
+ CUPS_LOGDIR="$logdir"
+ AC_DEFINE_UNQUOTED(CUPS_LOGDIR, "$logdir")
+fi
+
+dnl See what directory to put server executables...
+case "$uname" in
+ *BSD* | Darwin*)
+ # *BSD and Darwin (MacOS X)
+ INSTALL_SYSV=""
+ CUPS_SERVERBIN="$exec_prefix/libexec/cups"
+ AC_DEFINE_UNQUOTED(CUPS_SERVERBIN, "$exec_prefix/libexec/cups")
+ ;;
+ *)
+ # All others
+ INSTALL_SYSV="install-sysv"
+ CUPS_SERVERBIN="$exec_prefix/lib/cups"
+ AC_DEFINE_UNQUOTED(CUPS_SERVERBIN, "$exec_prefix/lib/cups")
+ ;;
+esac
+
+AC_SUBST(INSTALL_SYSV)
+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* | *BSD* | Darwin*)
+ CUPS_LOCALEDIR="$datadir/locale"
+ AC_DEFINE_UNQUOTED(CUPS_LOCALEDIR, "$datadir/locale")
+ ;;
+
+ OSF1* | AIX*)
+ CUPS_LOCALEDIR="$exec_prefix/lib/nls/msg"
+ AC_DEFINE_UNQUOTED(CUPS_LOCALEDIR, "$exec_prefix/lib/nls/msg")
+ ;;
+
+ *)
+ # This is the standard System V location...
+ CUPS_LOCALEDIR="$exec_prefix/lib/locale"
+ AC_DEFINE_UNQUOTED(CUPS_LOCALEDIR, "$exec_prefix/lib/locale")
+ ;;
+esac
+
+AC_SUBST(CUPS_LOCALEDIR)
+
+dnl Set the CUPS_DATADIR directory...
+CUPS_DATADIR="$datadir/cups"
+AC_DEFINE_UNQUOTED(CUPS_DATADIR, "$datadir/cups")
+AC_SUBST(CUPS_DATADIR)
+
+dnl Set the CUPS_DOCROOT directory...
+if test x$docdir = x; then
+ CUPS_DOCROOT="$datadir/doc/cups"
+ docdir="$datadir/doc/cups"
+else
+ CUPS_DOCROOT="$docdir"
+fi
+
+AC_DEFINE_UNQUOTED(CUPS_DOCROOT, "$docdir")
+AC_SUBST(CUPS_DOCROOT)
+
+dnl Set the CUPS_FONTPATH directory...
+CUPS_FONTPATH="$fontpath"
+AC_SUBST(CUPS_FONTPATH)
+AC_DEFINE_UNQUOTED(CUPS_FONTPATH, "$fontpath")
+
+dnl
+dnl End of "$Id: cups-directories.m4 2064 2002-01-24 18:51:13Z mike $".
+dnl
diff --git a/config-scripts/cups-image.m4 b/config-scripts/cups-image.m4
new file mode 100644
index 000000000..ec232b68c
--- /dev/null
+++ b/config-scripts/cups-image.m4
@@ -0,0 +1,72 @@
+dnl
+dnl "$Id: cups-image.m4 2013 2002-01-02 18:50:43Z mike $"
+dnl
+dnl Image library stuff for the Common UNIX Printing System (CUPS).
+dnl
+dnl Copyright 1997-2002 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
+
+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_HEADER(jpeglib.h,
+ AC_CHECK_LIB(jpeg, jpeg_destroy_decompress,
+ AC_DEFINE(HAVE_LIBJPEG)
+ LIBJPEG="-ljpeg"
+ LIBS="$LIBS -ljpeg"))
+
+AC_CHECK_HEADER(zlib.h,
+ AC_CHECK_LIB(z, gzgets,
+ AC_DEFINE(HAVE_LIBZ)
+ LIBZ="-lz"
+ LIBS="$LIBS -lz"))
+
+dnl PNG library uses math library functions...
+AC_CHECK_LIB(m, pow)
+
+AC_CHECK_HEADER(png.h,
+ AC_CHECK_LIB(png, png_set_tRNS_to_alpha,
+ AC_DEFINE(HAVE_LIBPNG)
+ LIBPNG="-lpng -lm"))
+
+AC_CHECK_HEADER(tiff.h,
+ AC_CHECK_LIB(tiff, TIFFReadScanline,
+ AC_DEFINE(HAVE_LIBTIFF)
+ LIBTIFF="-ltiff"))
+
+dnl Restore original LIBS settings...
+LIBS="$SAVELIBS"
+
+AC_CHECK_HEADER(stdlib.h,AC_DEFINE(HAVE_STDLIB_H))
+
+dnl
+dnl End of "$Id: cups-image.m4 2013 2002-01-02 18:50:43Z mike $".
+dnl
diff --git a/config-scripts/cups-libtool.m4 b/config-scripts/cups-libtool.m4
new file mode 100644
index 000000000..feb6198c7
--- /dev/null
+++ b/config-scripts/cups-libtool.m4
@@ -0,0 +1,49 @@
+dnl
+dnl "$Id: cups-libtool.m4 2013 2002-01-02 18:50:43Z mike $"
+dnl
+dnl Libtool stuff for the Common UNIX Printing System (CUPS).
+dnl
+dnl Copyright 1997-2002 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_ARG_ENABLE(libtool_unsupported, [ --enable-libtool-unsupported=LIBTOOL_PATH
+ turn on building with libtool (UNSUPPORTED!) [default=no]],
+ [if test x$enable_libtool_unsupported != xno; then
+ LIBTOOL="$enable_libtool_unsupported"
+ enable_shared=no
+ echo "WARNING: libtool is not supported or endorsed by Easy Software Products."
+ echo " WE DO NOT PROVIDE TECHNICAL SUPPORT FOR LIBTOOL PROBLEMS."
+ echo " (even if you have a support contract)"
+ else
+ LIBTOOL=""
+ fi])
+
+AC_SUBST(LIBTOOL)
+
+if test x$LIBTOOL != x; then
+ LIBCUPS="libcups.la"
+ LIBCUPSIMAGE="libcupsimage.la"
+ LINKCUPS="../cups/\$(LIBCUPS)"
+ LINKCUPSIMAGE="../filter/\$(LIBCUPSIMAGE)"
+ DSO="\$(CC)"
+fi
+
+dnl
+dnl End of "$Id: cups-libtool.m4 2013 2002-01-02 18:50:43Z mike $".
+dnl
diff --git a/config-scripts/cups-manpages.m4 b/config-scripts/cups-manpages.m4
new file mode 100644
index 000000000..9253d1305
--- /dev/null
+++ b/config-scripts/cups-manpages.m4
@@ -0,0 +1,104 @@
+dnl
+dnl "$Id: cups-manpages.m4 2013 2002-01-02 18:50:43Z mike $"
+dnl
+dnl Manpage stuff for the Common UNIX Printing System (CUPS).
+dnl
+dnl Copyright 1997-2002 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
+
+dnl Fix "mandir" variable...
+if test "$mandir" = "\${prefix}/man" -a "$prefix" = "/"; then
+ case "$uname" in
+ Darwin* | Linux* | *BSD* | AIX*)
+ # Darwin, MacOS X, Linux, *BSD, and AIX
+ mandir="/usr/share/man"
+ AMANDIR="/usr/share/man"
+ PMANDIR="/usr/share/man"
+ ;;
+ IRIX*)
+ # SGI IRIX
+ mandir="/usr/share/catman/u_man"
+ AMANDIR="/usr/share/catman/a_man"
+ PMANDIR="/usr/share/catman/p_man"
+ ;;
+ *)
+ # All others
+ mandir="/usr/man"
+ AMANDIR="/usr/man"
+ PMANDIR="/usr/man"
+ ;;
+ esac
+else
+ AMANDIR="$mandir"
+ PMANDIR="$mandir"
+fi
+
+AC_SUBST(AMANDIR)
+AC_SUBST(PMANDIR)
+
+dnl Setup manpage extensions...
+case "$uname" in
+ *BSD* | Darwin*)
+ # *BSD
+ CAT1EXT=0
+ CAT3EXT=0
+ CAT5EXT=0
+ CAT8EXT=0
+ MAN8EXT=8
+ MAN8DIR=8
+ ;;
+ IRIX*)
+ # SGI IRIX
+ CAT1EXT=z
+ CAT3EXT=z
+ CAT5EXT=z
+ CAT8EXT=z
+ MAN8EXT=1m
+ MAN8DIR=1
+ ;;
+ SunOS* | HP-UX*)
+ # Solaris and HP-UX
+ CAT1EXT=1
+ CAT3EXT=3
+ CAT5EXT=5
+ CAT8EXT=1m
+ MAN8EXT=1m
+ MAN8DIR=1m
+ ;;
+ *)
+ # All others
+ CAT1EXT=1
+ CAT3EXT=3
+ CAT5EXT=5
+ CAT8EXT=8
+ MAN8EXT=8
+ MAN8DIR=8
+ ;;
+esac
+
+AC_SUBST(CAT1EXT)
+AC_SUBST(CAT3EXT)
+AC_SUBST(CAT5EXT)
+AC_SUBST(CAT8EXT)
+AC_SUBST(MAN8EXT)
+AC_SUBST(MAN8DIR)
+
+dnl
+dnl End of "$Id: cups-manpages.m4 2013 2002-01-02 18:50:43Z mike $".
+dnl
diff --git a/config-scripts/cups-network.m4 b/config-scripts/cups-network.m4
new file mode 100644
index 000000000..755f794c6
--- /dev/null
+++ b/config-scripts/cups-network.m4
@@ -0,0 +1,38 @@
+dnl
+dnl "$Id: cups-network.m4 2081 2002-01-27 21:16:14Z mike $"
+dnl
+dnl Networking stuff for the Common UNIX Printing System (CUPS).
+dnl
+dnl Copyright 1997-2002 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
+
+NETLIBS=""
+
+if test "$uname" != "IRIX"; then
+ AC_CHECK_LIB(socket,socket,NETLIBS="-lsocket")
+ AC_CHECK_LIB(nsl,gethostbyaddr,NETLIBS="$NETLIBS -lnsl")
+fi
+
+AC_CHECK_FUNCS(rresvport)
+
+AC_SUBST(NETLIBS)
+
+dnl
+dnl End of "$Id: cups-network.m4 2081 2002-01-27 21:16:14Z mike $".
+dnl
diff --git a/config-scripts/cups-openslp.m4 b/config-scripts/cups-openslp.m4
new file mode 100644
index 000000000..090beafa5
--- /dev/null
+++ b/config-scripts/cups-openslp.m4
@@ -0,0 +1,47 @@
+dnl
+dnl "$Id: cups-openslp.m4 2035 2002-01-14 20:29:17Z mike $"
+dnl
+dnl OpenSLP configuration stuff for the Common UNIX Printing System (CUPS).
+dnl
+dnl Copyright 1997-2002 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_ARG_ENABLE(slp, [ --enable-slp turn on SLP support [default=yes]])
+AC_ARG_WITH(openslp-libs, [ --with-openslp-libs set directory for OpenSLP library],
+ LDFLAGS="-L$withval $LDFLAGS"
+ DSOFLAGS="-L$withval $DSOFLAGS",)
+AC_ARG_WITH(openslp-includes, [ --with-openslp-includes set directory for OpenSLP includes],
+ CFLAGS="-I$withval $CFLAGS"
+ CXXFLAGS="-I$withval $CXXFLAGS",)
+
+LIBSLP=""
+
+if test x$enable_slp != xno; then
+ AC_CHECK_HEADER(slp.h,
+ AC_CHECK_LIB(slp, SLPOpen,
+ AC_DEFINE(HAVE_LIBSLP)
+ LIBSLP="-lslp"))
+fi
+
+AC_SUBST(LIBSLP)
+
+
+dnl
+dnl End of "$Id: cups-openslp.m4 2035 2002-01-14 20:29:17Z mike $".
+dnl
diff --git a/config-scripts/cups-openssl.m4 b/config-scripts/cups-openssl.m4
new file mode 100644
index 000000000..7c21c1c1a
--- /dev/null
+++ b/config-scripts/cups-openssl.m4
@@ -0,0 +1,69 @@
+dnl
+dnl "$Id: cups-openssl.m4 2035 2002-01-14 20:29:17Z mike $"
+dnl
+dnl OpenSSL stuff for the Common UNIX Printing System (CUPS).
+dnl
+dnl Copyright 1997-2002 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_ARG_ENABLE(ssl, [ --enable-ssl turn on SSL/TLS support [default=yes]])
+AC_ARG_WITH(openssl-libs, [ --with-openssl-libs set directory for OpenSSL library],
+ LDFLAGS="-L$withval $LDFLAGS"
+ DSOFLAGS="-L$withval $DSOFLAGS",)
+AC_ARG_WITH(openssl-includes, [ --with-openssl-includes set directory for OpenSSL includes],
+ CFLAGS="-I$withval $CFLAGS"
+ CXXFLAGS="-I$withval $CXXFLAGS",)
+
+SSLLIBS=""
+
+if test x$enable_ssl != xno; then
+ AC_CHECK_HEADER(openssl/ssl.h,
+ dnl Save the current libraries so the crypto stuff isn't always
+ dnl included...
+ SAVELIBS="$LIBS"
+
+ dnl Some ELF systems can't resolve all the symbols in libcrypto
+ dnl if libcrypto was linked against RSAREF, and fail to link the
+ dnl test program correctly, even though a correct installation
+ dnl of OpenSSL exists. So we test the linking three times in
+ dnl case the RSAREF libraries are needed.
+
+ for libcrypto in \
+ "-lcrypto" \
+ "-lcrypto -lrsaref" \
+ "-lcrypto -lRSAglue -lrsaref"
+ do
+ AC_CHECK_LIB(ssl,SSL_new,
+ [SSLLIBS="-lssl $libcrypto"
+ AC_DEFINE(HAVE_LIBSSL)],,
+ $libcrypto)
+
+ if test "x${SSLLIBS}" != "x"; then
+ break
+ fi
+ done
+
+ LIBS="$SAVELIBS")
+fi
+
+AC_SUBST(SSLLIBS)
+
+dnl
+dnl End of "$Id: cups-openssl.m4 2035 2002-01-14 20:29:17Z mike $".
+dnl
diff --git a/config-scripts/cups-opsys.m4 b/config-scripts/cups-opsys.m4
new file mode 100644
index 000000000..943f358e5
--- /dev/null
+++ b/config-scripts/cups-opsys.m4
@@ -0,0 +1,90 @@
+dnl
+dnl "$Id: cups-opsys.m4 2013 2002-01-02 18:50:43Z mike $"
+dnl
+dnl Operating system stuff for the Common UNIX Printing System (CUPS).
+dnl
+dnl Copyright 1997-2002 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
+
+dnl Get the operating system and version number...
+uname=`uname`
+uversion=`uname -r | sed -e '1,$s/[[^0-9]]//g'`
+if test x$uname = xIRIX64; then
+ uname="IRIX"
+fi
+
+dnl Determine the correct username and group for this OS...
+AC_ARG_WITH(cups-user, [ --with-cups-user set default user for CUPS],
+ CUPS_USER="$withval",
+ AC_MSG_CHECKING(for default print user)
+ if test -f /etc/passwd; then
+ CUPS_USER=""
+ for user in lp lpd guest daemon nobody; do
+ if test "`grep \^${user}: /etc/passwd`" != ""; then
+ CUPS_USER="$user"
+ AC_MSG_RESULT($user)
+ break;
+ fi
+ done
+
+ if test x$CUPS_USER = x; then
+ CUPS_USER="${USER:=nobody}"
+ AC_MSG_RESULT(not found, using "$CUPS_USER")
+ fi
+ else
+ CUPS_USER="${USER:=nobody}"
+ AC_MSG_RESULT(no password file, using "$CUPS_USER")
+ fi)
+
+AC_ARG_WITH(cups-group, [ --with-cups-group set default group for CUPS],
+ CUPS_GROUP="$withval",
+ AC_MSG_CHECKING(for default print group)
+ if test x$uname = xDarwin; then
+ CUPS_GROUP="${GROUP:=admin}"
+ AC_MSG_RESULT(Darwin, using "$CUPS_GROUP")
+ else
+ if test -f /etc/group; then
+ CUPS_GROUP=""
+ for group in sys system root; do
+ if test "`grep \^${group}: /etc/group`" != ""; then
+ CUPS_GROUP="$group"
+ AC_MSG_RESULT($group)
+ break;
+ fi
+ done
+
+ if test x$CUPS_GROUP = x; then
+ CUPS_GROUP="${GROUP:=nobody}"
+ AC_MSG_RESULT(not found, using "$CUPS_GROUP")
+ fi
+ else
+ CUPS_GROUP="${GROUP:=nobody}"
+ AC_MSG_RESULT(no group file, using "$CUPS_GROUP")
+ fi
+ fi)
+
+AC_SUBST(CUPS_USER)
+AC_SUBST(CUPS_GROUP)
+
+AC_DEFINE_UNQUOTED(CUPS_DEFAULT_USER, "$CUPS_USER")
+AC_DEFINE_UNQUOTED(CUPS_DEFAULT_GROUP, "$CUPS_GROUP")
+
+dnl
+dnl "$Id: cups-opsys.m4 2013 2002-01-02 18:50:43Z mike $"
+dnl
diff --git a/config-scripts/cups-pam.m4 b/config-scripts/cups-pam.m4
new file mode 100644
index 000000000..3d3f3bf5d
--- /dev/null
+++ b/config-scripts/cups-pam.m4
@@ -0,0 +1,59 @@
+dnl
+dnl "$Id: cups-pam.m4 2013 2002-01-02 18:50:43Z mike $"
+dnl
+dnl PAM stuff for the Common UNIX Printing System (CUPS).
+dnl
+dnl Copyright 1997-2002 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_ARG_ENABLE(pam, [ --enable-pam turn on PAM support [default=yes]])
+
+dnl Don't use PAM with AIX...
+if test $uname = AIX; then
+ enable_pam=no
+fi
+
+PAMDIR=""
+PAMLIBS=""
+
+if test x$enable_pam != xno; then
+ SAVELIBS="$LIBS"
+ AC_CHECK_LIB(dl,dlopen)
+ AC_CHECK_LIB(pam,pam_start)
+
+ if test x$ac_cv_lib_pam_pam_start != xno; then
+ if test x$ac_cv_lib_dl_dlopen != xno; then
+ PAMLIBS="-lpam -ldl"
+ else
+ PAMLIBS="-lpam"
+ fi
+ if test -d /etc/pam.d; then
+ PAMDIR="/etc/pam.d"
+ fi
+ fi
+
+ LIBS="$SAVELIBS"
+fi
+
+AC_SUBST(PAMDIR)
+AC_SUBST(PAMLIBS)
+
+dnl
+dnl End of "$Id: cups-pam.m4 2013 2002-01-02 18:50:43Z mike $".
+dnl
diff --git a/config-scripts/cups-sharedlibs.m4 b/config-scripts/cups-sharedlibs.m4
new file mode 100644
index 000000000..9e5e630eb
--- /dev/null
+++ b/config-scripts/cups-sharedlibs.m4
@@ -0,0 +1,150 @@
+dnl
+dnl "$Id: cups-sharedlibs.m4 2064 2002-01-24 18:51:13Z mike $"
+dnl
+dnl Shared library support for the Common UNIX Printing System (CUPS).
+dnl
+dnl Copyright 1997-2002 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
+
+PICFLAG=1
+DSOFLAGS="${DSOFLAGS:=}"
+
+AC_ARG_ENABLE(shared, [ --enable-shared turn on shared libraries [default=yes]])
+
+if test x$enable_shared != xno; then
+ case "$uname" in
+ SunOS* | UNIX_S*)
+ LIBCUPS="libcups.so.2"
+ LIBCUPSIMAGE="libcupsimage.so.2"
+ DSO="\$(CC)"
+ DSOFLAGS="$DSOFLAGS -Wl,-h,\$@ -G \$(OPTIM)"
+ ;;
+ HP-UX*)
+ LIBCUPS="libcups.sl.2"
+ LIBCUPSIMAGE="libcupsimage.sl.2"
+ DSO="ld"
+ DSOFLAGS="$DSOFLAGS -b -z +h \$@"
+ ;;
+ IRIX*)
+ LIBCUPS="libcups.so.2"
+ LIBCUPSIMAGE="libcupsimage.so.2"
+ DSO="\$(CC)"
+ DSOFLAGS="$DSOFLAGS -Wl,-rpath,\$(libdir),-set_version,sgi2.4,-soname,\$@ -shared \$(OPTIM)"
+ ;;
+ OSF1* | Linux* | NetBSD* | OpenBSD*)
+ LIBCUPS="libcups.so.2"
+ LIBCUPSIMAGE="libcupsimage.so.2"
+ DSO="\$(CC)"
+ DSOFLAGS="$DSOFLAGS -Wl,-soname,\$@ -shared \$(OPTIM)"
+ ;;
+ Darwin* | FreeBSD*)
+ LIBCUPS="libcups.2.dylib"
+ LIBCUPSIMAGE="libcupsimage.2.dylib"
+ DSO="ld"
+ DSOFLAGS="$DSOFLAGS -dylib /usr/lib/dylib1.o -lc"
+ ;;
+ AIX*)
+ LIBCUPS="libcups_s.a"
+ LIBCUPSIMAGE="libcupsimage_s.a"
+ DSO="\$(CC)"
+ DSOFLAGS="$DSOFLAGS -Wl,-bexpall,-bM:SRE,-bnoentry"
+ ;;
+ *)
+ echo "Warning: shared libraries may not be supported. Trying -shared"
+ echo " option with compiler."
+ LIBCUPS="libcups.so.2"
+ LIBCUPSIMAGE="libcupsimage.so.2"
+ DSO="\$(CC)"
+ DSOFLAGS="$DSOFLAGS -Wl,-soname,\$@ -shared \$(OPTIM)"
+ ;;
+ esac
+else
+ PICFLAG=0
+ LIBCUPS="libcups.a"
+ LIBCUPSIMAGE="libcupsimage.a"
+ DSO=":"
+fi
+
+AC_SUBST(DSO)
+AC_SUBST(DSOFLAGS)
+AC_SUBST(LIBCUPS)
+AC_SUBST(LIBCUPSIMAGE)
+
+if test x$enable_shared = xno; then
+ LINKCUPS="-L../cups -lcups"
+ LINKCUPSIMAGE="-L../filter -lcupsimage"
+ LINKCUPS="$LINKCUPS \$(SSLLIBS)"
+else
+ if test $uname = AIX; then
+ LINKCUPS="-L../cups -lcups_s"
+ LINKCUPSIMAGE="-L../filter -lcupsimage_s"
+ else
+ LINKCUPS="-L../cups -lcups"
+ LINKCUPSIMAGE="-L../filter -lcupsimage"
+ fi
+fi
+
+AC_SUBST(LINKCUPS)
+AC_SUBST(LINKCUPSIMAGE)
+
+dnl Update libraries for DSOs...
+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="\$(LIBPNG) \$(LIBTIFF) \$(LIBJPEG) \$(LIBZ)"
+ IMGLIBS=""
+
+ # The *BSD, HP-UX, and Solaris run-time linkers need help when
+ # 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*)
+ # HP-UX
+ DSOFLAGS="+b $libdir +fb $DSOFLAGS"
+ LDFLAGS="$LDFLAGS -Wl,+b,$libdir,+fb"
+ ;;
+ SunOS*)
+ # Solaris
+ DSOFLAGS="-R$libdir $DSOFLAGS"
+ LDFLAGS="$LDFLAGS -R$libdir"
+ ;;
+ *BSD* | Darwin*)
+ # *BSD
+ DSOFLAGS="-Wl,-R$libdir $DSOFLAGS"
+ LDFLAGS="$LDFLAGS -Wl,-R$libdir"
+ ;;
+ Linux*)
+ # Linux
+ DSOFLAGS="-Wl,-rpath,$libdir $DSOFLAGS"
+ LDFLAGS="$LDFLAGS -Wl,-rpath,$libdir"
+ ;;
+ esac
+else
+ DSOLIBS=""
+ IMGLIBS="\$(LIBPNG) \$(LIBTIFF) \$(LIBJPEG) \$(LIBZ)"
+fi
+
+AC_SUBST(DSOLIBS)
+AC_SUBST(IMGLIBS)
+
+dnl
+dnl End of "$Id: cups-sharedlibs.m4 2064 2002-01-24 18:51:13Z mike $".
+dnl
diff --git a/config.h.in b/config.h.in
new file mode 100644
index 000000000..6572d39de
--- /dev/null
+++ b/config.h.in
@@ -0,0 +1,214 @@
+/*
+ * "$Id$"
+ *
+ * Configuration file for the Common UNIX Printing System (CUPS).
+ *
+ * @configure_input@
+ *
+ * Copyright 1997-2002 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-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ */
+
+/*
+ * Version of software...
+ */
+
+#define CUPS_SVERSION "CUPS v1.1.13"
+
+
+/*
+ * Default user and group...
+ */
+
+#define CUPS_DEFAULT_USER "lp"
+#define CUPS_DEFAULT_GROUP "sys"
+
+
+/*
+ * 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"
+#define CUPS_FONTPATH "/usr/share/cups/fonts"
+
+
+/*
+ * What is the format string for strftime?
+ */
+
+#define CUPS_STRFTIME_FORMAT NULL
+
+
+/*
+ * 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 <shadow.h>?
+ */
+
+#undef HAVE_SHADOW_H
+
+
+/*
+ * Do we have <crypt.h>?
+ */
+
+#undef HAVE_CRYPT_H
+
+
+/*
+ * Use <string.h>, <strings.h>, or both?
+ */
+
+#undef HAVE_STRING_H
+#undef HAVE_STRINGS_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
+
+
+/*
+ * Do we have the mallinfo function and malloc.h?
+ */
+
+#undef HAVE_MALLINFO
+#undef HAVE_MALLOC_H
+
+
+/*
+ * Do we have the OpenSSL library?
+ */
+
+#undef HAVE_LIBSSL
+
+
+/*
+ * Do we have the OpenSLP library?
+ */
+
+#undef HAVE_LIBSLP
+
+
+/*
+ * Do we have <sys/ioctl.h>?
+ */
+
+#undef HAVE_SYS_IOCTL_H
+
+
+/*
+ * Do we have mkstemp() and/or mkstemps()?
+ */
+
+#undef HAVE_MKSTEMP
+#undef HAVE_MKSTEMPS
+
+
+/*
+ * Does the "tm" structure contain the "tm_gmtoff" member?
+ */
+
+#undef HAVE_TM_GMTOFF
+
+
+/*
+ * Do we have rresvport()?
+ */
+
+#undef HAVE_RRESVPORT
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/configure.in b/configure.in
new file mode 100644
index 000000000..2049ef4fc
--- /dev/null
+++ b/configure.in
@@ -0,0 +1,48 @@
+dnl
+dnl "$Id$"
+dnl
+dnl Configuration script for the Common UNIX Printing System (CUPS).
+dnl
+dnl Copyright 1997-2002 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)
+
+sinclude(config-scripts/cups-opsys.m4)
+sinclude(config-scripts/cups-common.m4)
+sinclude(config-scripts/cups-directories.m4)
+sinclude(config-scripts/cups-manpages.m4)
+
+sinclude(config-scripts/cups-sharedlibs.m4)
+sinclude(config-scripts/cups-libtool.m4)
+sinclude(config-scripts/cups-compiler.m4)
+
+sinclude(config-scripts/cups-image.m4)
+sinclude(config-scripts/cups-network.m4)
+sinclude(config-scripts/cups-openslp.m4)
+sinclude(config-scripts/cups-openssl.m4)
+sinclude(config-scripts/cups-pam.m4)
+
+AC_OUTPUT(Makedefs cups.list cups.sh cups-config conf/cupsd.conf)
+
+chmod +x cups-config
+
+dnl
+dnl End of "$Id$".
+dnl
diff --git a/cups-config.in b/cups-config.in
new file mode 100755
index 000000000..d52e66e77
--- /dev/null
+++ b/cups-config.in
@@ -0,0 +1,133 @@
+#! /bin/sh
+#
+# "$Id$"
+#
+# CUPS configuration utility.
+#
+# Copyright 2001 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
+#
+
+VERSION="1.1.13"
+APIVERSION="1.1"
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+bindir=@bindir@
+includedir=@includedir@
+libdir=@libdir@
+datadir=@datadir@
+sysconfdir=@sysconfdir@
+cups_datadir=@CUPS_DATADIR@
+cups_serverbin=@CUPS_SERVERBIN@
+cups_serverroot=@CUPS_SERVERROOT@
+
+# flags for C++ compiler:
+CFLAGS="@CFLAGS@"
+LDFLAGS="@LDFLAGS@"
+LIBS="@SSLLIBS@ @NETLIBS@ @LIBS@"
+
+if test $includedir != /usr/include; then
+ CFLAGS="$CFLAGS -I$includedir"
+fi
+
+if test $libdir != /usr/lib -a $libdir != /usr/lib32; then
+ LDFLAGS="$LDFLAGS -L$libdir"
+fi
+
+usage ()
+{
+ echo "Usage: cups-config --api-version"
+ echo " cups-config --cflags"
+ echo " cups-config --datadir"
+ echo " cups-config --help"
+ echo " cups-config --ldflags"
+ echo " cups-config [--image] [--static] --libs"
+ echo " cups-config --serverbin"
+ echo " cups-config --serverroot"
+ echo " cups-config --version"
+
+ exit $1
+}
+
+if test $# -eq 0; then
+ usage 1
+fi
+
+# Parse command line options
+static=no
+image=no
+
+while test $# -gt 0; do
+ case $1 in
+ --api-version)
+ echo $APIVERSION
+ ;;
+ --cflags)
+ echo $CFLAGS
+ ;;
+ --datadir)
+ echo $cups_datadir
+ ;;
+ --help)
+ usage 0
+ ;;
+ --image)
+ image=yes
+ ;;
+ --ldflags)
+ echo $LDFLAGS
+ ;;
+ --libs)
+ if test $static = no; then
+ if test $image = no; then
+ echo -lcups $LIBS
+ else
+ echo -lcupsimage -lcups $LIBS
+ fi
+ else
+ if test $image = no; then
+ echo $libdir/libcups.a $LIBS
+ else
+ echo $libdir/libcupsimage.a $libdir/libcups.a $LIBS
+ fi
+ fi
+ ;;
+ --serverbin)
+ echo $cups_serverbin
+ ;;
+ --serverroot)
+ echo $cups_serverroot
+ ;;
+ --static)
+ static=yes
+ ;;
+ --version)
+ echo $VERSION
+ ;;
+ *)
+ usage 1
+ ;;
+ esac
+
+ shift
+done
+
+#
+# End of "$Id$".
+#
diff --git a/cups.dsw b/cups.dsw
new file mode 100644
index 000000000..28bdbaa89
--- /dev/null
+++ b/cups.dsw
@@ -0,0 +1,29 @@
+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>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/cups.list.in b/cups.list.in
new file mode 100644
index 000000000..aee5a4389
--- /dev/null
+++ b/cups.list.in
@@ -0,0 +1,400 @@
+#
+# "$Id$"
+#
+# ESP Package Manager (EPM) file list for the Common UNIX Printing
+# System (CUPS).
+#
+# Copyright 1997-2002 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 information
+%product Common UNIX Printing System
+%copyright 1993-2002 by Easy Software Products, All Rights Reserved.
+%vendor Easy Software Products
+%license LICENSE.txt
+%readme README.txt
+%version 1.1.13
+%provides cups
+%provides cupsys
+%provides cups-devel
+%provides cupsys-devel
+%provides cups-pstoraster
+%provides libcups1
+%provides libcups.so.2
+
+#
+# GNU variables...
+#
+
+$prefix=@prefix@
+$exec_prefix=@exec_prefix@
+$bindir=@bindir@
+$datadir=@datadir@
+$includedir=@includedir@
+$infodir=@infodir@
+$libdir=@libdir@
+$libexecdir=@libexecdir@
+$localstatedir=@localstatedir@
+$mandir=@mandir@
+$oldincludedir=@oldincludedir@
+$sbindir=@sbindir@
+$sharedstatedir=@sharedstatedir@
+$srcdir=@srcdir@
+$sysconfdir=@sysconfdir@
+$top_srcdir=@top_srcdir@
+
+#
+# ESP variables...
+#
+
+$AMANDIR=@AMANDIR@
+$BINDIR=@bindir@
+$DATADIR=@CUPS_DATADIR@
+$DOCDIR=@CUPS_DOCROOT@
+$INCLUDEDIR=${includedir}
+$INITDIR=@INITDIR@
+$INITDDIR=@INITDDIR@
+$LIBDIR=${libdir}
+$LOCALEDIR=@CUPS_LOCALEDIR@
+$LOGDIR=@CUPS_LOGDIR@
+$MANDIR=@mandir@
+$PAMDIR=@PAMDIR@
+$PMANDIR=@PMANDIR@
+$REQUESTS=@CUPS_REQUESTS@
+$SBINDIR=@sbindir@
+$SERVERBIN=@CUPS_SERVERBIN@
+$SERVERROOT=@CUPS_SERVERROOT@
+
+$CUPS_USER=@CUPS_USER@
+
+$CAT1EXT=@CAT1EXT@
+$CAT3EXT=@CAT3EXT@
+$CAT5EXT=@CAT5EXT@
+$CAT8EXT=@CAT8EXT@
+$MAN8EXT=@MAN8EXT@
+$MAN8DIR=@MAN8DIR@
+
+# Make sure the MD5 password file is now owned by CUPS_USER...
+%postinstall if test -f $SERVERROOT/passwd.md5; then
+%postinstall chown $CUPS_USER $SERVERROOT/passwd.md5
+%postinstall fi
+
+# Make sure the shared libraries are refreshed...
+%system linux
+%postinstall ldconfig
+%system all
+
+# Server programs
+%system all
+# Server files
+f 0555 root sys $SBINDIR/cupsd scheduler/cupsd
+
+d 0555 root sys $SERVERBIN -
+d 0555 root sys $SERVERBIN/backend -
+f 0555 root sys $SERVERBIN/backend/ipp backend/ipp
+l 0555 root sys $SERVERBIN/backend/http ipp
+f 0555 root sys $SERVERBIN/backend/lpd backend/lpd
+f 0555 root sys $SERVERBIN/backend/parallel backend/parallel
+f 0555 root sys $SERVERBIN/backend/serial backend/serial
+f 0555 root sys $SERVERBIN/backend/socket backend/socket
+f 0555 root sys $SERVERBIN/backend/usb backend/usb
+d 0555 root sys $SERVERBIN/cgi-bin -
+f 0555 root sys $SERVERBIN/cgi-bin/admin.cgi cgi-bin/admin.cgi
+f 0555 root sys $SERVERBIN/cgi-bin/classes.cgi cgi-bin/classes.cgi
+f 0555 root sys $SERVERBIN/cgi-bin/jobs.cgi cgi-bin/jobs.cgi
+f 0555 root sys $SERVERBIN/cgi-bin/printers.cgi cgi-bin/printers.cgi
+d 0555 root sys $SERVERBIN/daemon -
+f 0555 root sys $SERVERBIN/daemon/cups-lpd scheduler/cups-lpd
+f 0555 root sys $SERVERBIN/daemon/cups-polld scheduler/cups-polld
+d 0555 root sys $SERVERBIN/filter -
+f 0555 root sys $SERVERBIN/filter/pstoraster pstoraster/pstoraster
+f 0555 root sys $SERVERBIN/filter/pdftops pdftops/pdftops
+f 0555 root sys $SERVERBIN/filter/imagetops filter/imagetops
+f 0555 root sys $SERVERBIN/filter/pstops filter/pstops
+f 0555 root sys $SERVERBIN/filter/texttops filter/texttops
+f 0555 root sys $SERVERBIN/filter/rastertodymo filter/rastertodymo
+f 0555 root sys $SERVERBIN/filter/rastertoepson filter/rastertoepson
+f 0555 root sys $SERVERBIN/filter/rastertohp filter/rastertohp
+f 0555 root sys $SERVERBIN/filter/hpgltops filter/hpgltops
+f 0555 root sys $SERVERBIN/filter/imagetoraster filter/imagetoraster
+
+# Admin commands
+l 0555 root sys $BINDIR/disable $SBINDIR/accept
+l 0555 root sys $BINDIR/enable $SBINDIR/accept
+l 0555 root sys $LIBDIR/accept $SBINDIR/accept
+l 0555 root sys $LIBDIR/lpadmin $SBINDIR/lpadmin
+l 0555 root sys $LIBDIR/reject accept
+f 0555 root sys $SBINDIR/accept systemv/accept
+f 0555 root sys $SBINDIR/cupsaddsmb systemv/cupsaddsmb
+f 0555 root sys $SBINDIR/lpadmin systemv/lpadmin
+f 0555 root sys $SBINDIR/lpc berkeley/lpc
+f 0555 root sys $SBINDIR/lpinfo systemv/lpinfo
+f 0555 root sys $SBINDIR/lpmove systemv/lpmove
+l 0555 root sys $SBINDIR/reject accept
+
+%system irix
+l 0555 root sys /usr/etc/lpc $SBINDIR/lpc
+%system all
+
+# User commands
+f 0555 root sys $BINDIR/cancel systemv/cancel
+f 0555 root sys $BINDIR/lp systemv/lp
+f 0555 root sys $BINDIR/lpoptions systemv/lpoptions
+f 4555 $CUPS_USER sys $BINDIR/lppasswd systemv/lppasswd
+f 0555 root sys $BINDIR/lpq berkeley/lpq
+f 0555 root sys $BINDIR/lpr berkeley/lpr
+f 0555 root sys $BINDIR/lprm berkeley/lprm
+f 0555 root sys $BINDIR/lpstat systemv/lpstat
+
+%system irix
+l 0555 root sys /usr/bsd/lpq $BINDIR/lpq
+l 0555 root sys /usr/bsd/lpr $BINDIR/lpr
+l 0555 root sys /usr/bsd/lprm $BINDIR/lprm
+%system all
+
+# DSOs
+%system hpux
+f 0555 root sys $LIBDIR/libcups.sl.2 cups/libcups.sl.2
+l 0555 root sys $LIBDIR/libcups.sl libcups.sl.2
+f 0555 root sys $LIBDIR/libcupsimage.sl.2 filter/libcupsimage.sl.2
+l 0555 root sys $LIBDIR/libcupsimage.sl libcupsimage.sl.2
+%system aix
+f 0555 root sys $LIBDIR/libcups_s.a cups/libcups_s.a
+f 0555 root sys $LIBDIR/libcupsimage_s.a filter/libcupsimage_s.a
+%system !hpux !aix
+f 0555 root sys $LIBDIR/libcups.so.2 cups/libcups.so.2
+l 0555 root sys $LIBDIR/libcups.so libcups.so.2
+f 0555 root sys $LIBDIR/libcupsimage.so.2 filter/libcupsimage.so.2
+l 0555 root sys $LIBDIR/libcupsimage.so libcupsimage.so.2
+%system all
+
+# Directories
+d 0755 root sys $LOGDIR -
+d 0700 $CUPS_USER sys $REQUESTS -
+d 1700 $CUPS_USER sys $REQUESTS/tmp -
+
+# Data files
+f 0444 root sys $LOCALEDIR/C/cups_C locale/C/cups_C
+f 0444 root sys $LOCALEDIR/be/cups_be locale/be/cups_be
+f 0444 root sys $LOCALEDIR/cs/cups_cs locale/cs/cups_cs
+f 0444 root sys $LOCALEDIR/de/cups_de locale/de/cups_de
+f 0444 root sys $LOCALEDIR/en/cups_en locale/en/cups_en
+f 0444 root sys $LOCALEDIR/es/cups_es locale/es/cups_es
+f 0444 root sys $LOCALEDIR/fr/cups_fr locale/fr/cups_fr
+f 0444 root sys $LOCALEDIR/it/cups_it locale/it/cups_it
+f 0444 root sys $LOCALEDIR/ru_RU.cp1251/cups_ru_RU.cp1251 locale/ru_RU.cp1251/cups_ru_RU.cp1251
+f 0444 root sys $LOCALEDIR/ru_RU.koi8r/cups_ru_RU.koi8r locale/ru_RU.koi8r/cups_ru_RU.koi8r
+f 0444 root sys $LOCALEDIR/uk/cups_uk locale/uk/cups_uk
+f 0444 root sys $LOCALEDIR/uk_UA.cp1251/cups_uk_UA.cp1251 locale/uk_UA.cp1251/cups_uk_UA.cp1251
+f 0444 root sys $LOCALEDIR/zh_CN/cups_zh_CN locale/zh_CN/cups_zh_CN
+
+d 0555 root sys $DATADIR -
+
+d 0555 root sys $DATADIR/banners -
+f 0444 root sys $DATADIR/banners/classified data/classified
+f 0444 root sys $DATADIR/banners/confidential data/confidential
+f 0444 root sys $DATADIR/banners/secret data/secret
+f 0444 root sys $DATADIR/banners/standard data/standard
+f 0444 root sys $DATADIR/banners/topsecret data/topsecret
+f 0444 root sys $DATADIR/banners/unclassified data/unclassified
+
+d 0555 root sys $DATADIR/charsets -
+f 0444 root sys $DATADIR/charsets/windows-874 data/windows-874
+f 0444 root sys $DATADIR/charsets/windows-1250 data/windows-1250
+f 0444 root sys $DATADIR/charsets/windows-1251 data/windows-1251
+f 0444 root sys $DATADIR/charsets/windows-1252 data/windows-1252
+f 0444 root sys $DATADIR/charsets/windows-1253 data/windows-1253
+f 0444 root sys $DATADIR/charsets/windows-1254 data/windows-1254
+f 0444 root sys $DATADIR/charsets/windows-1255 data/windows-1255
+f 0444 root sys $DATADIR/charsets/windows-1256 data/windows-1256
+f 0444 root sys $DATADIR/charsets/windows-1257 data/windows-1257
+f 0444 root sys $DATADIR/charsets/windows-1258 data/windows-1258
+f 0444 root sys $DATADIR/charsets/iso-8859-1 data/iso-8859-1
+f 0444 root sys $DATADIR/charsets/iso-8859-2 data/iso-8859-2
+f 0444 root sys $DATADIR/charsets/iso-8859-3 data/iso-8859-3
+f 0444 root sys $DATADIR/charsets/iso-8859-4 data/iso-8859-4
+f 0444 root sys $DATADIR/charsets/iso-8859-5 data/iso-8859-5
+f 0444 root sys $DATADIR/charsets/iso-8859-6 data/iso-8859-6
+f 0444 root sys $DATADIR/charsets/iso-8859-7 data/iso-8859-7
+f 0444 root sys $DATADIR/charsets/iso-8859-8 data/iso-8859-8
+f 0444 root sys $DATADIR/charsets/iso-8859-9 data/iso-8859-9
+f 0444 root sys $DATADIR/charsets/iso-8859-10 data/iso-8859-10
+f 0444 root sys $DATADIR/charsets/iso-8859-13 data/iso-8859-13
+f 0444 root sys $DATADIR/charsets/iso-8859-14 data/iso-8859-14
+f 0444 root sys $DATADIR/charsets/iso-8859-15 data/iso-8859-15
+f 0444 root sys $DATADIR/charsets/utf-8 data/utf-8
+
+d 0555 root sys $DATADIR/data -
+f 0444 root sys $DATADIR/data/HPGLprolog data/HPGLprolog
+f 0444 root sys $DATADIR/data/psglyphs data/psglyphs
+f 0444 root sys $DATADIR/data/testprint.ps data/testprint.ps
+
+d 0555 root sys $DATADIR/fonts -
+f 0444 root sys $DATADIR/fonts fonts/AvantGarde*
+f 0444 root sys $DATADIR/fonts fonts/Bookman*
+f 0444 root sys $DATADIR/fonts fonts/Charter*
+f 0444 root sys $DATADIR/fonts fonts/Courier*
+f 0444 root sys $DATADIR/fonts fonts/Helvetica*
+f 0444 root sys $DATADIR/fonts fonts/NewCentury*
+f 0444 root sys $DATADIR/fonts fonts/Palatino*
+f 0444 root sys $DATADIR/fonts fonts/Symbol
+f 0444 root sys $DATADIR/fonts fonts/Times*
+f 0444 root sys $DATADIR/fonts fonts/Utopia*
+f 0444 root sys $DATADIR/fonts fonts/Zapf*
+
+d 0555 root sys $DATADIR/pstoraster -
+f 0444 root sys $DATADIR/pstoraster/Fontmap pstoraster/Fontmap
+f 0444 root sys $DATADIR/pstoraster pstoraster/gs*.ps
+
+d 0555 root sys $DATADIR/model -
+f 0444 root sys $DATADIR/model ppd/*.ppd
+
+d 0555 root sys $DATADIR/templates -
+c 0444 root sys $DATADIR/templates templates/*.tmpl
+
+# Config files
+d 0555 root sys $SERVERROOT -
+d 0711 $CUPS_USER $CUPS_GROUP $SERVERROOT/certs -
+d 0755 root sys $SERVERROOT/interfaces -
+d 0755 root sys $SERVERROOT/ppd -
+c 0600 root sys $SERVERROOT conf/*.conf
+c 0600 root sys $SERVERROOT/mime.convs conf/mime.convs
+c 0600 root sys $SERVERROOT/mime.types conf/mime.types
+
+%system linux
+d 0555 root sys $PAMDIR -
+c 0644 root sys $PAMDIR/cups data/cups.pam
+c 0644 root sys $PAMDIR/cups.suse data/cups.suse
+%install if test -f /lib/security/pam_unix.so; then
+%install mv $PAMDIR/cups.suse $PAMDIR/cups
+%install fi
+
+# IRIX doesn't normally support PAM, but the freeware project
+# includes a version of PAM that can be used...
+%system irix
+d 0555 root sys $PAMDIR -
+c 0644 root sys $PAMDIR/cups data/cups.irix
+
+%system all
+
+# Developer files
+f 0555 root sys $BINDIR/cups-config cups-config
+d 0555 root sys $INCLUDEDIR/cups -
+f 0444 root sys $INCLUDEDIR/cups/cups.h cups/cups.h
+f 0444 root sys $INCLUDEDIR/cups/http.h cups/http.h
+f 0444 root sys $INCLUDEDIR/cups/image.h filter/image.h
+f 0444 root sys $INCLUDEDIR/cups/ipp.h cups/ipp.h
+f 0444 root sys $INCLUDEDIR/cups/language.h cups/language.h
+f 0444 root sys $INCLUDEDIR/cups/md5.h cups/md5.h
+f 0444 root sys $INCLUDEDIR/cups/ppd.h cups/ppd.h
+f 0444 root sys $INCLUDEDIR/cups/raster.h filter/raster.h
+
+f 0444 root sys $LIBDIR/libcups.a cups/libcups.a
+
+# Documentation files
+d 0555 root sys $DOCDIR -
+f 0444 root sys $DOCDIR doc/*.css
+f 0444 root sys $DOCDIR doc/*.html
+f 0444 root sys $DOCDIR doc/*.pdf
+d 0555 root sys $DOCDIR/images -
+f 0444 root sys $DOCDIR/images doc/images/*.gif
+
+# Man pages
+d 0555 root sys $AMANDIR -
+d 0555 root sys $AMANDIR/cat$MAN8DIR -
+d 0555 root sys $AMANDIR/man$MAN8DIR -
+d 0555 root sys $MANDIR -
+d 0555 root sys $MANDIR/cat1 -
+d 0555 root sys $PMANDIR/cat3 -
+d 0555 root sys $MANDIR/cat5 -
+d 0555 root sys $MANDIR/man1 -
+d 0555 root sys $PMANDIR/man3 -
+d 0555 root sys $MANDIR/man5 -
+
+f 0444 root sys $MANDIR/cat1/backend.$CAT1EXT man/backend.$CAT1EXT
+f 0444 root sys $MANDIR/cat1/filter.$CAT1EXT man/filter.$CAT1EXT
+f 0444 root sys $MANDIR/cat1/lpoptions.$CAT1EXT man/lpoptions.$CAT1EXT
+f 0444 root sys $MANDIR/cat1/lppasswd.$CAT1EXT man/lppasswd.$CAT1EXT
+f 0444 root sys $MANDIR/cat1/lpq.$CAT1EXT man/lpq.$CAT1EXT
+f 0444 root sys $MANDIR/cat1/lprm.$CAT1EXT man/lprm.$CAT1EXT
+f 0444 root sys $MANDIR/cat1/lpr.$CAT1EXT man/lpr.$CAT1EXT
+f 0444 root sys $MANDIR/cat1/lpstat.$CAT1EXT man/lpstat.$CAT1EXT
+f 0444 root sys $MANDIR/cat1/lp.$CAT1EXT man/lp.$CAT1EXT
+l 0444 root sys $MANDIR/cat1/cancel.$CAT1EXT lp.$CAT1EXT
+
+f 0444 root sys $PMANDIR/cat3/cups-config.$CAT3EXT man/cups-config.$CAT3EXT
+
+f 0444 root sys $MANDIR/cat5/classes.conf.$CAT5EXT man/classes.conf.$CAT5EXT
+f 0444 root sys $MANDIR/cat5/cupsd.conf.$CAT5EXT man/cupsd.conf.$CAT5EXT
+f 0444 root sys $MANDIR/cat5/mime.convs.$CAT5EXT man/mime.convs.$CAT5EXT
+f 0444 root sys $MANDIR/cat5/mime.types.$CAT5EXT man/mime.types.$CAT5EXT
+f 0444 root sys $MANDIR/cat5/printers.conf.$CAT5EXT man/printers.conf.$CAT5EXT
+
+f 0444 root sys $AMANDIR/cat$MAN8DIR/accept.$CAT8EXT man/accept.$CAT8EXT
+l 0444 root sys $AMANDIR/cat$MAN8DIR/reject.$CAT8EXT accept.$CAT8EXT
+f 0444 root sys $AMANDIR/cat$MAN8DIR/cupsaddsmb.$CAT8EXT man/cupsaddsmb.$CAT8EXT
+f 0444 root sys $AMANDIR/cat$MAN8DIR/cups-lpd.$CAT8EXT man/cups-lpd.$CAT8EXT
+f 0444 root sys $AMANDIR/cat$MAN8DIR/cups-polld.$CAT8EXT man/cups-polld.$CAT8EXT
+f 0444 root sys $AMANDIR/cat$MAN8DIR/cupsd.$CAT8EXT man/cupsd.$CAT8EXT
+f 0444 root sys $AMANDIR/cat$MAN8DIR/enable.$CAT8EXT man/enable.$CAT8EXT
+l 0444 root sys $AMANDIR/cat$MAN8DIR/disable.$CAT8EXT enable.$CAT8EXT
+f 0444 root sys $AMANDIR/cat$MAN8DIR/lpadmin.$CAT8EXT man/lpadmin.$CAT8EXT
+f 0444 root sys $AMANDIR/cat$MAN8DIR/lpc.$CAT8EXT man/lpc.$CAT8EXT
+f 0444 root sys $AMANDIR/cat$MAN8DIR/lpinfo.$CAT8EXT man/lpinfo.$CAT8EXT
+f 0444 root sys $AMANDIR/cat$MAN8DIR/lpmove.$CAT8EXT man/lpmove.$CAT8EXT
+
+f 0444 root sys $MANDIR/man1/backend.$MAN1EXT man/backend.man
+f 0444 root sys $MANDIR/man1/filter.$MAN1EXT man/filter.man
+f 0444 root sys $MANDIR/man1/lpoptions.$MAN1EXT man/lpoptions.man
+f 0444 root sys $MANDIR/man1/lppasswd.$MAN1EXT man/lppasswd.man
+f 0444 root sys $MANDIR/man1/lpq.$MAN1EXT man/lpq.man
+f 0444 root sys $MANDIR/man1/lprm.$MAN1EXT man/lprm.man
+f 0444 root sys $MANDIR/man1/lpr.$MAN1EXT man/lpr.man
+f 0444 root sys $MANDIR/man1/lpstat.$MAN1EXT man/lpstat.man
+f 0444 root sys $MANDIR/man1/lp.$MAN1EXT man/lp.man
+l 0444 root sys $MANDIR/man1/cancel.$MAN1EXT lp.man
+
+f 0444 root sys $PMANDIR/man3/cups-config.$MAN3EXT man/cups-config.man
+
+f 0444 root sys $MANDIR/man5/classes.conf.$MAN5EXT man/classes.conf.man
+f 0444 root sys $MANDIR/man5/cupsd.conf.$MAN5EXT man/cupsd.conf.man
+f 0444 root sys $MANDIR/man5/mime.convs.$MAN5EXT man/mime.convs.man
+f 0444 root sys $MANDIR/man5/mime.types.$MAN5EXT man/mime.types.man
+f 0444 root sys $MANDIR/man5/printers.conf.$MAN5EXT man/printers.conf.man
+
+f 0444 root sys $AMANDIR/man$MAN8DIR/accept.$MAN8EXT man/accept.man
+l 0444 root sys $AMANDIR/man$MAN8DIR/reject.$MAN8EXT accept.man
+f 0444 root sys $AMANDIR/man$MAN8DIR/cupsaddsmb.$MAN8EXT man/cupsaddsmb.man
+f 0444 root sys $AMANDIR/man$MAN8DIR/cups-lpd.$MAN8EXT man/cups-lpd.man
+f 0444 root sys $AMANDIR/man$MAN8DIR/cups-polld.$MAN8EXT man/cups-polld.man
+f 0444 root sys $AMANDIR/man$MAN8DIR/cupsd.$MAN8EXT man/cupsd.man
+f 0444 root sys $AMANDIR/man$MAN8DIR/enable.$MAN8EXT man/enable.man
+l 0444 root sys $AMANDIR/man$MAN8DIR/disable.$MAN8EXT enable.man
+f 0444 root sys $AMANDIR/man$MAN8DIR/lpadmin.$MAN8EXT man/lpadmin.man
+f 0444 root sys $AMANDIR/man$MAN8DIR/lpc.$MAN8EXT man/lpc.man
+f 0444 root sys $AMANDIR/man$MAN8DIR/lpinfo.$MAN8EXT man/lpinfo.man
+f 0444 root sys $AMANDIR/man$MAN8DIR/lpmove.$MAN8EXT man/lpmove.man
+
+# Startup script
+%system all
+i 0555 root sys cups cups.sh
+
+#
+# End of "$Id$".
+#
diff --git a/cups.plist b/cups.plist
new file mode 100644
index 000000000..f7c80c61a
--- /dev/null
+++ b/cups.plist
@@ -0,0 +1,11 @@
+{
+ Description = "CUPS Printing";
+ Provides = ("CUPS");
+ Requires = ("Resolver");
+ OrderPreference = "None";
+ Messages =
+ {
+ start = "Starting CUPS";
+ stop = "Stopping CUPS";
+ };
+}
diff --git a/cups.sh.in b/cups.sh.in
new file mode 100755
index 000000000..c25233020
--- /dev/null
+++ b/cups.sh.in
@@ -0,0 +1,180 @@
+#!/bin/sh
+#
+# "$Id$"
+#
+# Startup/shutdown script for the Common UNIX Printing System (CUPS).
+#
+# Copyright 1997-2002 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
+#
+
+#### OS-Dependent Information
+
+#
+# Linux chkconfig stuff:
+#
+# chkconfig: 235 99 00
+# description: Startup/shutdown script for the Common UNIX \
+# Printing System (CUPS).
+#
+
+#
+# NetBSD 1.5+ rcorder script lines. The format of the following two
+# lines is very strict -- please don't add additional spaces!
+#
+# PROVIDE: cups
+# REQUIRE: DAEMON
+#
+
+
+#### OS-Dependent Configuration
+
+case "`uname`" in
+ IRIX*)
+ IS_ON=/sbin/chkconfig
+ ;;
+
+ NetBSD*)
+ IS_ON=:
+ ;;
+
+ Darwin*)
+ . /etc/rc.common
+
+ if test "${CUPS:=-YES-}" = "-NO-"; then
+ exit 0
+ fi
+
+ IS_ON=:
+ ;;
+
+ Linux*)
+ # Set the timezone, if possible...
+ if test -f /etc/TIMEZONE; then
+ . /etc/TIMEZONE
+ else
+ if test -f /etc/sysconfig/clock; then
+ . /etc/sysconfig/clock
+ TZ="$ZONE"
+ export TZ
+ fi
+ fi
+
+ IS_ON=/bin/true
+ ;;
+
+ *)
+ IS_ON=/bin/true
+ ;;
+esac
+
+#### OS-Independent Stuff
+
+#
+# The verbose flag controls the printing of the names of
+# daemons as they are started. Currently always echos for
+# all but IRIX, which can configure verbose bootup messages.
+#
+
+if test "`uname`" = "Darwin"; then
+ ECHO=ConsoleMessage
+else
+ if $IS_ON verbose; then
+ ECHO=echo
+ else
+ ECHO=:
+ fi
+fi
+
+#
+# See if the CUPS server (cupsd) is running...
+#
+
+case "`uname`" in
+ HP-UX* | AIX* | SINIX*)
+ pid=`ps -e | awk '{if (match($4, ".*/cupsd$") || $4 == "cupsd") print $1}'`
+ ;;
+ IRIX* | SunOS*)
+ pid=`ps -e | nawk '{if (match($4, ".*/cupsd$") || $4 == "cupsd") print $1}'`
+ ;;
+ UnixWare*)
+ pid=`ps -e | awk '{if (match($6, ".*/cupsd$") || $6 == "cupsd") print $1}'`
+ . /etc/TIMEZONE
+ ;;
+ OSF1*)
+ pid=`ps -e | awk '{if (match($5, ".*/cupsd$") || $5 == "cupsd") print $1}'`
+ ;;
+ Linux* | *BSD* | Darwin*)
+ pid=`ps ax | awk '{if (match($5, ".*/cupsd$") || $5 == "cupsd") print $1}'`
+ ;;
+ *)
+ pid=""
+ ;;
+esac
+
+#
+# Start or stop the CUPS server based upon the first argument to the script.
+#
+
+case $1 in
+ start | restart | reload)
+ if $IS_ON cups; then
+ if test "$pid" != ""; then
+ kill -HUP $pid
+ else
+ prefix=@prefix@
+ exec_prefix=@exec_prefix@
+ @sbindir@/cupsd
+ fi
+ $ECHO "cups: scheduler ${1}ed."
+ else
+ $ECHO "cups: scheduler stopped."
+ 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 with no errors.
+#
+
+exit 0
+
+
+#
+# End of "$Id$".
+#
diff --git a/cups.spec b/cups.spec
new file mode 100644
index 000000000..2acaa4d73
--- /dev/null
+++ b/cups.spec
@@ -0,0 +1,228 @@
+#
+# "$Id: cups.spec 2010 2002-01-02 17:59:21Z mike $"
+#
+# RPM "spec" file for the Common UNIX Printing System (CUPS).
+#
+# Original version by Jason McMullan <jmcc@ontv.com>.
+#
+# Copyright 1999-2002 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.1.13
+Release: 0
+Copyright: GPL
+Group: System Environment/Daemons
+Source: ftp://ftp.easysw.com/pub/cups/%{version}/cups-%{version}-source.tar.gz
+Url: http://www.cups.org
+Packager: Michael Sweet <mike@easysw.com>
+Vendor: Easy Software Products
+
+# Use buildroot so as not to disturb the version already installed
+BuildRoot: /var/tmp/%{name}-root
+
+# Dependencies...
+Conflicts: lpr, LPRng
+Provides: libcups.so.2
+Provides: libcupsimage.so.2
+Provides: cups
+
+%package devel
+Summary: Common Unix Printing System - development environment
+Group: Development/Libraries
+Provides: libcups1
+
+%package pstoraster
+Summary: Common Unix Printing System - PostScript RIP
+Group: System Environment/Daemons
+Provides: pstoraster
+
+%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.
+
+%description pstoraster
+The Common UNIX Printing System provides a portable printing layer for
+UNIX® operating systems. This is the PostScript RIP package for
+supporting non-PostScript printer drivers.
+
+%prep
+%setup
+
+%build
+CFLAGS="$RPM_OPT_FLAGS" CXXFLAGS="$RPM_OPT_FLAGS" LDFLAGS="$RPM_OPT_FLAGS" ./configure
+
+# If we got this far, all prerequisite libraries must be here.
+make
+
+%install
+# Make sure the RPM_BUILD_ROOT directory exists.
+rm -rf $RPM_BUILD_ROOT
+
+make BUILDROOT=$RPM_BUILD_ROOT install
+
+%post
+ldconfig
+
+if test -x /sbin/chkconfig; then
+ /sbin/chkconfig --add cups
+ /sbin/chkconfig cups on
+fi
+
+# these lines automatically start cupsd after installation; commented out
+# by request...
+#if test -f /sbin/init.d/cups; then
+# /sbin/init.d/cups start
+#fi
+#if test -f /etc/rc.d/init.d/cups; then
+# /etc/rc.d/init.d/cups start
+#fi
+#if test -f /etc/init.d/cups; then
+# /etc/init.d/cups start
+#fi
+
+%preun
+if test -f /sbin/init.d/cups; then
+ /sbin/init.d/cups stop
+fi
+if test -f /etc/rc.d/init.d/cups; then
+ /etc/rc.d/init.d/cups stop
+fi
+if test -f /etc/init.d/cups; then
+ /etc/init.d/cups stop
+fi
+
+if test -x /sbin/chkconfig; then
+ /sbin/chkconfig --del cups
+fi
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%files
+%defattr(-,root,root)
+%dir /etc/cups
+%config(noreplace) /etc/cups/*.conf
+%dir /etc/cups/certs
+%dir /etc/cups/interfaces
+/etc/cups/mime.types
+/etc/cups/mime.convs
+%dir /etc/cups/ppd
+%dir /etc/pam.d
+/etc/pam.d/*
+
+# RC dirs are a pain under Linux... Uncomment the appropriate ones if you
+# don't use Red Hat or Mandrake...
+
+/etc/rc.d/init.d/*
+/etc/rc.d/rc0.d/*
+/etc/rc.d/rc3.d/*
+/etc/rc.d/rc5.d/*
+
+#/etc/init.d/*
+#/etc/rc0.d/*
+#/etc/rc3.d/*
+#/etc/rc5.d/*
+
+#/sbin/rc.d/*
+#/sbin/rc.d/rc0.d/*
+#/sbin/rc.d/rc3.d/*
+#/sbin/rc.d/rc5.d/*
+
+/usr/bin/cancel
+/usr/bin/disable
+/usr/bin/enable
+/usr/bin/lp*
+/usr/lib/*.so*
+%dir /usr/lib/cups
+%dir /usr/lib/cups/backend
+/usr/lib/cups/backend/*
+%dir /usr/lib/cups/cgi-bin
+/usr/lib/cups/cgi-bin/*
+%dir /usr/lib/cups/daemon
+/usr/lib/cups/daemon/*
+%dir /usr/lib/cups/filter
+/usr/lib/cups/filter/hpgltops
+/usr/lib/cups/filter/imagetops
+/usr/lib/cups/filter/imagetoraster
+/usr/lib/cups/filter/pdftops
+/usr/lib/cups/filter/pstops
+/usr/lib/cups/filter/rastertoepson
+/usr/lib/cups/filter/rastertohp
+/usr/lib/cups/filter/texttops
+/usr/sbin/*
+%dir /usr/share/cups
+%dir /usr/share/cups/banners
+/usr/share/cups/banners/*
+%dir /usr/share/cups/charsets
+/usr/share/cups/charsets/*
+%dir /usr/share/cups/data
+/usr/share/cups/data/*
+%dir /usr/share/cups/model
+/usr/share/cups/model/*
+%dir /usr/share/cups/templates
+/usr/share/cups/templates/*
+%dir /usr/share/doc/cups
+/usr/share/doc/cups/*
+%dir /usr/share/locale
+/usr/share/locale/*
+%dir /usr/share/man/cat1
+/usr/share/man/cat1/*
+%dir /usr/share/man/cat5
+/usr/share/man/cat5/*
+%dir /usr/share/man/cat8
+/usr/share/man/cat8/*
+%dir /usr/share/man/man1
+/usr/share/man/man1/*
+%dir /usr/share/man/man5
+/usr/share/man/man5/*
+%dir /usr/share/man/man8
+/usr/share/man/man8/*
+
+%attr(0700,lp,root) %dir /var/spool/cups
+%attr(1700,lp,root) %dir /var/spool/cups/tmp
+
+%files devel
+%dir /usr/include/cups
+/usr/include/cups/*
+/usr/lib/*.a
+%dir /usr/share/man/cat3
+/usr/share/man/cat3/*
+%dir /usr/share/man/man3
+/usr/share/man/man1/*
+
+%files pstoraster
+%dir /usr/lib/cups/filter
+/usr/lib/cups/filter/pstoraster
+%dir /usr/share/cups/fonts
+/usr/share/cups/fonts/*
+%dir /usr/share/cups/pstoraster
+/usr/share/cups/pstoraster/*
+
+#
+# End of "$Id: cups.spec 2010 2002-01-02 17:59:21Z mike $".
+#
diff --git a/cups.strings b/cups.strings
new file mode 100644
index 000000000..0d7535458
--- /dev/null
+++ b/cups.strings
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
+<plist version="0.9">
+<dict>
+ <key>Starting CUPS</key>
+ <string>Starting CUPS</string>
+</dict>
+</plist>
+
diff --git a/cups/.cvsignore b/cups/.cvsignore
new file mode 100644
index 000000000..c707b044b
--- /dev/null
+++ b/cups/.cvsignore
@@ -0,0 +1,4 @@
+libcups.a
+libcups.sl.2
+libcups.so.2
+libcups_s.a
diff --git a/cups/Makefile b/cups/Makefile
new file mode 100644
index 000000000..ad3bb9ad6
--- /dev/null
+++ b/cups/Makefile
@@ -0,0 +1,208 @@
+#
+# "$Id$"
+#
+# Support library Makefile for the Common UNIX Printing System (CUPS).
+#
+# Copyright 1997-2002 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 encode.o http.o ipp.o language.o mark.o md5.o \
+ md5passwd.o options.o page.o ppd.o snprintf.o string.o \
+ tempfile.o usersys.o util.o
+OBJS = $(LIBOBJS) testhttp.o testppd.o ppd-debug.o
+
+
+#
+# Header files to install...
+#
+
+HEADERS = cups.h http.h ipp.h language.h md5.h ppd.h
+
+
+#
+# Targets in this directory...
+#
+
+TARGETS = $(LIBCUPS) libcups.a
+
+
+#
+# Make all targets...
+#
+
+all: $(TARGETS)
+
+
+#
+# Remove object and target files...
+#
+
+clean:
+ $(RM) $(OBJS) $(TARGETS) `basename $(LIBCUPS) .2`
+
+
+#
+# Install object and target files...
+#
+
+install: all
+ $(INSTALL_DIR) $(INCLUDEDIR)/cups
+ for file in $(HEADERS); do \
+ $(INSTALL_DATA) $$file $(INCLUDEDIR)/cups; \
+ done
+ $(INSTALL_DIR) $(LIBDIR)
+ $(INSTALL_LIB) $(LIBCUPS) $(LIBDIR)
+ if test $(LIBCUPS) = "libcups.so.2" -o $(LIBCUPS) = "libcups.sl.2"; then \
+ $(INSTALL_LIB) libcups.a $(LIBDIR); \
+ $(RM) $(LIBDIR)/`basename $(LIBCUPS) .2`; \
+ $(LN) $(LIBCUPS) $(LIBDIR)/`basename $(LIBCUPS) .2`; \
+ fi
+ if test $(LIBCUPS) = "libcups.2.dylib"; then \
+ $(INSTALL_LIB) libcups.a $(LIBDIR); \
+ $(RM) $(LIBDIR)/libcups.dylib; \
+ $(LN) $(LIBCUPS) $(LIBDIR)/libcups.dylib; \
+ fi
+ if test $(LIBCUPS) = "libcups_s.a"; then \
+ $(INSTALL_LIB) libcups.a $(LIBDIR); \
+ fi
+
+
+#
+# libcups.so.2, libcups.sl.2
+#
+
+libcups.so.2 libcups.sl.2: $(LIBOBJS) ../Makedefs
+ echo Linking $@...
+ $(DSO) $(DSOFLAGS) -o $@ $(LIBOBJS) $(SSLLIBS)
+ $(RM) `basename $@ .2`
+ $(LN) $@ `basename $@ .2`
+
+
+#
+# libcups.2.dylib
+#
+
+libcups.2.dylib: $(LIBOBJS) ../Makedefs
+ echo Linking $@...
+ $(DSO) $(DSOFLAGS) -o $@ \
+ -dylib_install_name $(LIBDIR)/libcups.dylib \
+ -dylib_current_version 2.0.4 \
+ -dylib_compatibility_version 2.0.0 \
+ $(LIBOBJS) $(SSLLIBS)
+ $(RM) libcups.dylib
+ $(LN) $@ libcups.dylib
+
+
+#
+# libcups_s.a
+#
+
+libcups_s.a: $(LIBOBJS) ../Makedefs
+ echo Creating $@...
+ $(RM) libcups_s.exp
+ (echo _ipp_add_attr; echo _ipp_free_attr) >libcups_s.exp
+ $(DSO) $(DSOFLAGS) -Wl,-bexport:libcups_s.exp -o libcups_s.o $(LIBOBJS) $(SSLLIBS) -lm
+ $(RM) $@
+ $(AR) $(ARFLAGS) $@ libcups_s.o
+
+
+#
+# libcups.la
+#
+
+libcups.la: $(LIBOBJS) ../Makedefs
+ echo Linking $@...
+ $(DSO) $(DSOFLAGS) -o $@ $(LIBOBJS:.o=.lo) -rpath $(LIBDIR) \
+ -version-info 2:4 $(SSLLIBS)
+
+
+#
+# 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
+encode.o: cups.h ipp.h string.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
+tempfile.o: cups.h 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) $(SSLLIBS)
+
+testhttp.o: http.h
+
+
+#
+# testppd
+#
+
+testppd: testppd.o ppd-debug.o language.o mark.o page.o
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ testppd.o ppd-debug.o language.o mark.o page.o
+
+testppd.o: ppd.h
+ppd-debug.o: ppd.c language.h ppd.h
+ echo Compiling $< with debugging...
+ $(CC) $(OPTIM) $(CFLAGS) -DDEBUG -c -o $@ $<
+
+$(OBJS): ../Makedefs ../config.h
+
+
+#
+# End of "$Id$".
+#
diff --git a/cups/cups.dsp b/cups/cups.dsp
new file mode 100644
index 000000000..8822fdbe0
--- /dev/null
+++ b/cups/cups.dsp
@@ -0,0 +1,188 @@
+# 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=.\dest.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\emit.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=.\md5.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\md5passwd.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=.\snprintf.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\string.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\usersys.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=.\cups_C.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\debug.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=.\md5.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ppd.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\string.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 000000000..3f18ad254
--- /dev/null
+++ b/cups/cups.h
@@ -0,0 +1,175 @@
+/*
+ * "$Id$"
+ *
+ * API definitions for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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 "ipp.h"
+# include "ppd.h"
+
+
+/*
+ * C++ magic...
+ */
+
+# ifdef __cplusplus
+extern "C" {
+# endif /* __cplusplus */
+
+
+/*
+ * Constants...
+ */
+
+# define CUPS_VERSION 1.0113
+# 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_DEFAULT = 0x20000, /* Default printer on network */
+ 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 or NULL */
+ int is_default; /* Is this printer the default? */
+ int num_options; /* Number of options */
+ cups_option_t *options; /* Options */
+} cups_dest_t;
+
+typedef struct /**** Job ****/
+{
+ int id; /* The job ID */
+ char *dest, /* Printer or class name */
+ *title, /* Title/job name */
+ *user, /* User the submitted the job */
+ *format; /* Document format */
+ ipp_jstate_t state; /* Job state */
+ int size, /* Size in kilobytes */
+ priority; /* Priority (1-100) */
+ time_t completed_time, /* Time the job was completed */
+ creation_time, /* Time the job was created */
+ processing_time; /* Time the job was processed */
+} cups_job_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 http_encryption_t cupsEncryption(void);
+extern void cupsFreeJobs(int num_jobs, cups_job_t *jobs);
+extern int cupsGetClasses(char ***classes);
+extern const char *cupsGetDefault(void);
+extern int cupsGetJobs(cups_job_t **jobs, const char *dest,
+ int myjobs, int completed);
+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 int cupsPrintFiles(const char *printer, int num_files,
+ const char **files, const char *title,
+ int num_options, cups_option_t *options);
+extern char *cupsTempFile(char *filename, int len);
+extern int cupsTempFd(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 cupsEncodeOptions(ipp_t *ipp, 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 void cupsSetEncryption(http_encryption_t e);
+extern void cupsSetPasswordCB(const char *(*cb)(const char *));
+extern void cupsSetServer(const char *server);
+extern void cupsSetUser(const char *user);
+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 000000000..e3586c989
--- /dev/null
+++ b/cups/cups_C.h
@@ -0,0 +1,133 @@
+"iso-8859-1",
+"OK",
+"Cancel",
+"Help",
+"Quit",
+"Close",
+"Yes",
+"No",
+"On",
+"Off",
+"Save",
+"Discard",
+"Default",
+"Options",
+"More Info",
+"Black",
+"Color",
+"Cyan",
+"Magenta",
+"Yellow",
+"Copyright 1993-2002 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.",
+"426 An upgrade to a secure connection is required. If you are seeing this message in a web browser then it does not support HTTP encryption upgrades.",
+"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 000000000..1291c1ba9
--- /dev/null
+++ b/cups/debug.h
@@ -0,0 +1,57 @@
+/*
+ * "$Id$"
+ *
+ * Debugging macros for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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 <stdio.h>
+
+/*
+ * 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 000000000..5f47d5a3b
--- /dev/null
+++ b/cups/dest.c
@@ -0,0 +1,789 @@
+/*
+ * "$Id$"
+ *
+ * User-defined destination (and option) support for the Common UNIX
+ * Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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.
+ * cups_get_sdests() - Get destinations from a server.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cups.h"
+#include "language.h"
+#include "string.h"
+#include <stdlib.h>
+#include <ctype.h>
+
+
+/*
+ * Local functions...
+ */
+
+static int cups_get_dests(const char *filename, int num_dests,
+ cups_dest_t **dests);
+static int cups_get_sdests(ipp_op_t op, 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 (strcasecmp(name, dest->name) == 0 &&
+ 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 (num_dests == 0 || dests == NULL)
+ return (NULL);
+
+ if (name == NULL)
+ {
+ /*
+ * NULL name for default printer.
+ */
+
+ while (num_dests > 0)
+ {
+ if (dests->is_default)
+ return (dests);
+
+ num_dests --;
+ dests ++;
+ }
+ }
+ else
+ {
+ /*
+ * Lookup name and optionally the instance...
+ */
+
+ 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 */
+ cups_dest_t *dest; /* Destination pointer */
+ const char *home; /* HOME environment variable */
+ char filename[1024]; /* Local ~/.lpoptions file */
+ const char *defprinter; /* Default printer */
+ char name[1024], /* Copy of printer name */
+ *instance; /* Pointer to instance name */
+ int num_reals; /* Number of real queues */
+ cups_dest_t *reals; /* Real queues */
+
+
+ /*
+ * Initialize destination array...
+ */
+
+ num_dests = 0;
+ *dests = (cups_dest_t *)0;
+
+ /*
+ * Grab the printers and classes...
+ */
+
+ num_dests = cups_get_sdests(CUPS_GET_PRINTERS, num_dests, dests);
+ num_dests = cups_get_sdests(CUPS_GET_CLASSES, num_dests, dests);
+
+ /*
+ * Make a copy of the "real" queues for a later sanity check...
+ */
+
+ if (num_dests > 0)
+ {
+ num_reals = num_dests;
+ reals = calloc(num_reals, sizeof(cups_dest_t));
+
+ if (reals)
+ memcpy(reals, *dests, num_reals * sizeof(cups_dest_t));
+ else
+ num_reals = 0;
+ }
+ else
+ {
+ num_reals = 0;
+ reals = NULL;
+ }
+
+ /*
+ * Grab the default destination...
+ */
+
+ if ((defprinter = cupsGetDefault()) != NULL)
+ {
+ /*
+ * Grab printer and instance name...
+ */
+
+ strncpy(name, defprinter, sizeof(name) - 1);
+ name[sizeof(name) - 1] = '\0';
+
+ if ((instance = strchr(name, '/')) != NULL)
+ *instance++ = '\0';
+
+ /*
+ * Lookup the printer and instance and make it the default...
+ */
+
+ if ((dest = cupsGetDest(name, instance, num_dests, *dests)) != NULL)
+ dest->is_default = 1;
+ }
+ else
+ {
+ /*
+ * This initialization of "instance" is unnecessary, but avoids a
+ * compiler warning...
+ */
+
+ instance = NULL;
+ }
+
+ /*
+ * Load the /etc/cups/lpoptions and ~/.lpoptions files...
+ */
+
+ if ((home = getenv("CUPS_SERVERROOT")) != NULL)
+ {
+ snprintf(filename, sizeof(filename), "%s/lpoptions", home);
+ num_dests = cups_get_dests(filename, num_dests, dests);
+ }
+ else
+ 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);
+ }
+
+ /*
+ * Validate the current default destination - this prevents old
+ * Default lines in /etc/cups/lpoptions and ~/.lpoptions from
+ * pointing to a non-existent printer or class...
+ */
+
+ if (num_reals)
+ {
+ /*
+ * See if we have a default printer...
+ */
+
+ if ((dest = cupsGetDest(NULL, NULL, num_dests, *dests)) != NULL)
+ {
+ /*
+ * Have a default; see if it is real...
+ */
+
+ dest = cupsGetDest(dest->name, NULL, num_reals, reals);
+ }
+
+ /*
+ * If dest is NULL, then no default (that exists) is set, so we
+ * need to set a default if one exists...
+ */
+
+ if (dest == NULL && defprinter != NULL)
+ {
+ for (i = 0; i < num_dests; i ++)
+ (*dests)[i].is_default = 0;
+
+ if ((dest = cupsGetDest(name, instance, num_dests, *dests)) != NULL)
+ dest->is_default = 1;
+ }
+
+ /*
+ * Free memory...
+ */
+
+ free(reals);
+ }
+
+ /*
+ * 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 */
+ int wrote; /* Wrote definition? */
+ 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 */
+ int num_temps; /* Number of temporary destinations */
+ cups_dest_t *temps, /* Temporary destinations */
+ *temp; /* Current temporary dest */
+ const char *val; /* Value of temporary option */
+
+
+ /*
+ * Get the server destinations...
+ */
+
+ num_temps = cups_get_sdests(CUPS_GET_PRINTERS, 0, &temps);
+ num_temps = cups_get_sdests(CUPS_GET_CLASSES, num_temps, &temps);
+
+ /*
+ * Figure out which file to write to...
+ */
+
+ if ((home = getenv("CUPS_SERVERROOT")) != NULL)
+ snprintf(filename, sizeof(filename), "%s/lpoptions", home);
+ else
+ strcpy(filename, CUPS_SERVERROOT "/lpoptions");
+
+#ifndef WIN32
+ if (getuid())
+ {
+ /*
+ * Merge in server defaults...
+ */
+
+ num_temps = cups_get_dests(filename, num_temps, &temps);
+
+ /*
+ * Point to user defaults...
+ */
+
+ if ((home = getenv("HOME")) != NULL)
+ snprintf(filename, sizeof(filename), "%s/.lpoptions", home);
+ }
+#endif /* !WIN32 */
+
+ /*
+ * Try to open the file...
+ */
+
+ if ((fp = fopen(filename, "w")) == NULL)
+ {
+ cupsFreeDests(num_temps, temps);
+ 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)
+ {
+ if (dest->is_default)
+ {
+ fprintf(fp, "Default %s", dest->name);
+ if (dest->instance)
+ fprintf(fp, "/%s", dest->instance);
+
+ wrote = 1;
+ }
+ else
+ wrote = 0;
+
+ if ((temp = cupsGetDest(dest->name, dest->instance, num_temps, temps)) == NULL)
+ temp = cupsGetDest(dest->name, NULL, num_temps, temps);
+
+ for (j = dest->num_options, option = dest->options; j > 0; j --, option ++)
+ {
+ /*
+ * See if the server/global options match these; if so, don't
+ * write 'em.
+ */
+
+ if (temp && (val = cupsGetOption(option->name, temp->num_options,
+ temp->options)) != NULL)
+ {
+ if (strcasecmp(val, option->value) == 0)
+ continue;
+ }
+
+ /*
+ * Options don't match, write to the file...
+ */
+
+ if (!wrote)
+ {
+ fprintf(fp, "Dest %s", dest->name);
+ if (dest->instance)
+ fprintf(fp, "/%s", dest->instance);
+ wrote = 1;
+ }
+
+ if (option->value[0])
+ {
+ if (strchr(option->value, ' ') != NULL)
+ fprintf(fp, " %s=\"%s\"", option->name, option->value);
+ else
+ fprintf(fp, " %s=%s", option->name, option->value);
+ }
+ else
+ fprintf(fp, " %s", option->name);
+ }
+
+ if (wrote)
+ fputs("\n", fp);
+ }
+
+ /*
+ * Free the temporary destinations...
+ */
+
+ cupsFreeDests(num_temps, temps);
+
+ /*
+ * 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 */
+ const char *printer; /* PRINTER or LPDEST */
+
+
+ /*
+ * Check environment variables...
+ */
+
+ if ((printer = getenv("LPDEST")) == NULL)
+ if ((printer = getenv("PRINTER")) != NULL)
+ if (strcmp(printer, "lp") == 0)
+ printer = NULL;
+
+ /*
+ * 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...
+ */
+
+ dest->num_options = cupsParseOptions(lineptr, dest->num_options,
+ &(dest->options));
+
+ /*
+ * Set this as default if needed...
+ */
+
+ if (strncasecmp(line, "default", 7) == 0 && printer == NULL)
+ {
+ 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);
+}
+
+
+/*
+ * 'cups_get_sdests()' - Get destinations from a server.
+ */
+
+static int /* O - Number of destinations */
+cups_get_sdests(ipp_op_t op, /* I - get-printers or get-classes */
+ int num_dests, /* I - Number of destinations */
+ cups_dest_t **dests) /* IO - Destinations */
+{
+ cups_dest_t *dest; /* Current destination */
+ http_t *http; /* HTTP connection */
+ ipp_t *request, /* IPP Request */
+ *response; /* IPP Response */
+ ipp_attribute_t *attr; /* Current attribute */
+ cups_lang_t *language; /* Default language */
+ const char *name; /* printer-name attribute */
+ char job_sheets[1024]; /* job-sheets option */
+ static const char *pattrs[] = /* Attributes we're interested in */
+ {
+ "printer-name",
+ "job-sheets-default"
+ };
+
+
+ /*
+ * Connect to the CUPS server...
+ */
+
+ if ((http = httpConnect(cupsServer(), ippPort())) == NULL)
+ return (num_dests);
+
+ /*
+ * Build a CUPS_GET_PRINTERS or CUPS_GET_CLASSES request, which require
+ * the following attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ */
+
+ 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);
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]),
+ NULL, pattrs);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/")) != NULL)
+ {
+ for (attr = response->attrs; attr != NULL; attr = attr->next)
+ {
+ /*
+ * Skip leading attributes until we hit a printer...
+ */
+
+ while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
+ attr = attr->next;
+
+ if (attr == NULL)
+ break;
+
+ /*
+ * Pull the needed attributes from this job...
+ */
+
+ name = NULL;
+
+ strcpy(job_sheets, "");
+
+ while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
+ {
+ if (strcmp(attr->name, "printer-name") == 0 &&
+ attr->value_tag == IPP_TAG_NAME)
+ name = attr->values[0].string.text;
+
+ if (strcmp(attr->name, "job-sheets-default") == 0 &&
+ (attr->value_tag == IPP_TAG_KEYWORD ||
+ attr->value_tag == IPP_TAG_NAME))
+ {
+ if (attr->num_values == 2)
+ snprintf(job_sheets, sizeof(job_sheets), "%s,%s",
+ attr->values[0].string.text, attr->values[1].string.text);
+ else
+ strcpy(job_sheets, attr->values[0].string.text);
+ }
+
+ attr = attr->next;
+ }
+
+ /*
+ * See if we have everything needed...
+ */
+
+ if (!name)
+ {
+ if (attr == NULL)
+ break;
+ else
+ continue;
+ }
+
+ num_dests = cupsAddDest(name, NULL, num_dests, dests);
+
+ if ((dest = cupsGetDest(name, NULL, num_dests, *dests)) != NULL)
+ if (job_sheets[0])
+ dest->num_options = cupsAddOption("job-sheets", job_sheets, 0,
+ &(dest->options));
+
+ if (attr == NULL)
+ break;
+ }
+
+ ippDelete(response);
+ }
+
+ /*
+ * Close the server connection...
+ */
+
+ httpClose(http);
+
+ /*
+ * Return the count...
+ */
+
+ return (num_dests);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/emit.c b/cups/emit.c
new file mode 100644
index 000000000..add34f140
--- /dev/null
+++ b/cups/emit.c
@@ -0,0 +1,425 @@
+/*
+ * "$Id$"
+ *
+ * PPD code emission routines for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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:
+ *
+ * ppdCollect() - Collect all marked options that reside in the specified
+ * ppdEmit() - Emit code for marked options to a file.
+ * ppdEmitFd() - Emit code for marked options to a file.
+ * ppdEmitJCL() - Emit code for JCL options to a file.
+ * ppd_sort() - Sort options by ordering numbers...
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "ppd.h"
+#include <stdlib.h>
+#include "string.h"
+
+#if defined(WIN32) || defined(__EMX__)
+# include <io.h>
+#else
+# include <unistd.h>
+#endif /* WIN32 || __EMX__ */
+
+
+/*
+ * Local functions...
+ */
+
+static int ppd_sort(ppd_choice_t **c1, ppd_choice_t **c2);
+
+
+/*
+ * 'ppdCollect()' - Collect all marked options that reside in the specified
+ * section.
+ */
+
+int /* O - Number of options marked */
+ppdCollect(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);
+ }
+}
+
+
+/*
+ * '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 = ppdCollect(ppd, section, &choices)) == 0)
+ return (0);
+
+ for (i = 0; i < count; i ++)
+ if (section != PPD_ORDER_EXIT && section != PPD_ORDER_JCL)
+ {
+ /*
+ * Send wrapper commands to prevent printer errors for unsupported
+ * options...
+ */
+
+ if (fputs("[{\n", fp) < 0)
+ {
+ free(choices);
+ return (-1);
+ }
+
+ /*
+ * 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("<</PageSize[5 -2 roll]/ImagingBBox null>>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);
+ }
+
+ if (fputs("} stopped cleartomark\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 = ppdCollect(ppd, section, &choices)) == 0)
+ return (0);
+
+ for (i = 0; i < count; i ++)
+ if (section != PPD_ORDER_EXIT && section != PPD_ORDER_JCL)
+ {
+ /*
+ * Send wrapper commands to prevent printer errors for unsupported
+ * options...
+ */
+
+ if (write(fd, "[{\n", 3) < 1)
+ {
+ free(choices);
+ return (-1);
+ }
+
+ /*
+ * Send DSC comments with option...
+ */
+
+ snprintf(buf, sizeof(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);
+ }
+
+ if (write(fd, "} stopped cleartomark\n", 22) < 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);
+}
+
+
+/*
+ * 'ppdEmitJCL()' - Emit code for JCL options to a file.
+ */
+
+int /* O - 0 on success, -1 on failure */
+ppdEmitJCL(ppd_file_t *ppd, /* I - PPD file record */
+ FILE *fp, /* I - File to write to */
+ int job_id, /* I - Job ID */
+ const char *user, /* I - Username */
+ const char *title) /* I - Title */
+{
+ const char *ptr; /* Pointer into JCL string */
+
+
+ /*
+ * Range check the input...
+ */
+
+ if (ppd == NULL || ppd->jcl_begin == NULL || ppd->jcl_ps == NULL)
+ return (0);
+
+ /*
+ * See if the printer supports HP PJL...
+ */
+
+ if (strncmp(ppd->jcl_begin, "\033%-12345X@", 10) == 0)
+ {
+ /*
+ * This printer uses HP PJL commands for output; filter the output
+ * so that we only have a single "@PJL JOB" command in the header...
+ */
+
+ fputs("\033%-12345X", fp);
+ for (ptr = ppd->jcl_begin + 9; *ptr;)
+ if (strncmp(ptr, "@PJL JOB", 8) == 0)
+ {
+ /*
+ * Skip job command...
+ */
+
+ for (;*ptr; ptr ++)
+ if (*ptr == '\n')
+ break;
+
+ if (*ptr)
+ ptr ++;
+ }
+ else
+ {
+ /*
+ * Copy line...
+ */
+
+ for (;*ptr; ptr ++)
+ {
+ putc(*ptr, fp);
+ if (*ptr == '\n')
+ break;
+ }
+
+ if (*ptr)
+ ptr ++;
+ }
+
+ /*
+ * Eliminate any path info from the job title...
+ */
+
+ if ((ptr = strrchr(title, '/')) != NULL)
+ title = ptr + 1;
+
+ /*
+ * Send PJL JOB command before we enter PostScript mode...
+ */
+
+ fprintf(fp, "@PJL JOB NAME = \"%s\" DISPLAY = \"%d %s %s\"\n", title,
+ job_id, user, title);
+ }
+ else
+ fputs(ppd->jcl_begin, stdout);
+
+ ppdEmit(ppd, stdout, PPD_ORDER_JCL);
+ fputs(ppd->jcl_ps, stdout);
+
+ 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);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/encode.c b/cups/encode.c
new file mode 100644
index 000000000..e529aa2c3
--- /dev/null
+++ b/cups/encode.c
@@ -0,0 +1,311 @@
+/*
+ * "$Id$"
+ *
+ * Option encoding routines for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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:
+ *
+ * cupsEncodeOptions() - Encode printer options into IPP attributes.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cups.h"
+#include <stdlib.h>
+#include <ctype.h>
+#include "string.h"
+#include "debug.h"
+
+
+/*
+ * 'cupsEncodeOptions()' - Encode printer options into IPP attributes.
+ */
+
+void
+cupsEncodeOptions(ipp_t *ipp, /* I - Request to add to */
+ int num_options, /* I - Number of options */
+ cups_option_t *options) /* I - Options */
+{
+ int i, j; /* Looping vars */
+ int count; /* Number of values */
+ int n; /* Attribute value */
+ char *s, /* Pointer into option value */
+ *val, /* Pointer to option value */
+ *copy, /* Copy of option value */
+ *sep; /* Option separator */
+ ipp_attribute_t *attr; /* IPP job-id attribute */
+
+
+ DEBUG_printf(("cupsEncodeOptions(%p, %d, %p)\n", ipp, num_options, options));
+
+ if (ipp == NULL || num_options < 1 || options == NULL)
+ return;
+
+ /*
+ * Handle the document format stuff first...
+ */
+
+ if ((val = (char *)cupsGetOption("document-format", num_options, options)) != NULL)
+ ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format",
+ NULL, val);
+ else if (cupsGetOption("raw", num_options, options))
+ ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format",
+ NULL, "application/vnd.cups-raw");
+ else
+ ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format",
+ NULL, "application/octet-stream");
+
+ /*
+ * Then add all other options...
+ */
+
+ for (i = 0; i < num_options; i ++)
+ {
+ /*
+ * Skip document format options - handled above...
+ */
+
+ if (strcasecmp(options[i].name, "raw") == 0 ||
+ strcasecmp(options[i].name, "document-format") == 0 ||
+ !options[i].name[0])
+ continue;
+
+ /*
+ * Count the number of values...
+ */
+
+ for (count = 1, sep = options[i].value;
+ (sep = strchr(sep + 1, ',')) != NULL;
+ count ++);
+
+ DEBUG_printf(("cupsEncodeOptions: option = \'%s\', count = %d\n",
+ options[i].name, count));
+
+ if ((attr = _ipp_add_attr(ipp, count)) == NULL)
+ {
+ /*
+ * Ran out of memory!
+ */
+
+ DEBUG_puts("cupsEncodeOptions: Ran out of memory for attributes!");
+ return;
+ }
+
+ attr->group_tag = IPP_TAG_JOB;
+
+ if ((attr->name = strdup(options[i].name)) == NULL)
+ {
+ /*
+ * Ran out of memory!
+ */
+
+ DEBUG_puts("cupsEncodeOptions: Ran out of memory for name!");
+ return;
+ }
+
+ if (count > 1)
+ {
+ /*
+ * Make a copy of the value we can fiddle with...
+ */
+
+ if ((copy = strdup(options[i].value)) == NULL)
+ {
+ /*
+ * Ran out of memory!
+ */
+
+ DEBUG_puts("cupsEncodeOptions: Ran out of memory for value copy!");
+ return;
+ }
+
+ val = copy;
+ }
+ else
+ {
+ /*
+ * Since we have a single value, use the value directly...
+ */
+
+ val = options[i].value;
+ copy = NULL;
+ }
+
+ /*
+ * 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, option=MxN, and option=val1,val2,...,valN.
+ */
+
+ if (*val == '\0')
+ {
+ /*
+ * Old-style System V boolean value...
+ */
+
+ attr->value_tag = IPP_TAG_BOOLEAN;
+
+ if (strncasecmp(attr->name, "no", 2) == 0)
+ {
+ DEBUG_puts("cupsEncodeOptions: Added boolean false value...");
+ strcpy(attr->name, attr->name + 2);
+ attr->values[0].boolean = 0;
+ }
+ else
+ {
+ DEBUG_puts("cupsEncodeOptions: Added boolean true value...");
+ attr->values[0].boolean = 1;
+ }
+ }
+ else
+ {
+ /*
+ * Scan the value string for values...
+ */
+
+ for (j = 0; *val != '\0'; val = sep, j ++)
+ {
+ /*
+ * Find the end of this value and mark it if needed...
+ */
+
+ if ((sep = strchr(val, ',')) != NULL)
+ *sep++ = '\0';
+ else
+ sep = val + strlen(val);
+
+ /*
+ * See what kind of value it is...
+ */
+
+ if (strcasecmp(val, "true") == 0 ||
+ strcasecmp(val, "on") == 0 ||
+ strcasecmp(val, "yes") == 0)
+ {
+ /*
+ * Boolean value - true...
+ */
+
+ attr->value_tag = IPP_TAG_BOOLEAN;
+ attr->values[j].boolean = 1;
+
+ DEBUG_puts("cupsEncodeOptions: Added boolean true value...");
+ }
+ else if (strcasecmp(val, "false") == 0 ||
+ strcasecmp(val, "off") == 0 ||
+ strcasecmp(val, "no") == 0)
+ {
+ /*
+ * Boolean value - false...
+ */
+
+ attr->value_tag = IPP_TAG_BOOLEAN;
+ attr->values[j].boolean = 0;
+
+ DEBUG_puts("cupsEncodeOptions: Added boolean false value...");
+ }
+ else
+ {
+ /*
+ * Number, range, resolution, or string...
+ */
+
+ n = strtol(val, &s, 0);
+
+ if (*s != '\0' && *s != '-' && (*s != 'x' || s == val))
+ {
+ /*
+ * String value(s)...
+ */
+
+ if ((attr->values[j].string.text = strdup(val)) == NULL)
+ {
+ /*
+ * Ran out of memory!
+ */
+
+ DEBUG_puts("cupsEncodeOptions: Ran out of memory for string!");
+ return;
+ }
+
+ attr->value_tag = IPP_TAG_NAME;
+
+ DEBUG_printf(("cupsEncodeOptions: Added string value \'%s\'...\n", val));
+ }
+ else if (*s == '-')
+ {
+ attr->value_tag = IPP_TAG_RANGE;
+ attr->values[j].range.lower = n;
+ attr->values[j].range.upper = strtol(s + 1, NULL, 0);
+
+ DEBUG_printf(("cupsEncodeOptions: Added range option value %d-%d...\n",
+ n, attr->values[j].range.upper));
+ }
+ else if (*s == 'x')
+ {
+ attr->value_tag = IPP_TAG_RESOLUTION;
+ attr->values[j].resolution.xres = n;
+ attr->values[j].resolution.yres = strtol(s + 1, &s, 0);
+
+ if (strcasecmp(s, "dpc") == 0)
+ attr->values[j].resolution.units = IPP_RES_PER_CM;
+ else if (strcasecmp(s, "dpi") == 0)
+ attr->values[j].resolution.units = IPP_RES_PER_INCH;
+ else
+ {
+ if ((attr->values[j].string.text = strdup(val)) == NULL)
+ {
+ /*
+ * Ran out of memory!
+ */
+
+ DEBUG_puts("cupsEncodeOptions: Ran out of memory for string!");
+ return;
+ }
+
+ attr->value_tag = IPP_TAG_NAME;
+
+ DEBUG_printf(("cupsEncodeOptions: Added string value \'%s\'...\n", val));
+ continue;
+ }
+
+ DEBUG_printf(("cupsEncodeOptions: Adding resolution option value %s...\n",
+ val));
+ }
+ else
+ {
+ attr->value_tag = IPP_TAG_INTEGER;
+ attr->values[j].integer = n;
+
+ DEBUG_printf(("cupsEncodeOptions: Adding integer option value %d...\n", n));
+ }
+ }
+ }
+ }
+ }
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/http.c b/cups/http.c
new file mode 100644
index 000000000..5bc98c8bf
--- /dev/null
+++ b/cups/http.c
@@ -0,0 +1,2215 @@
+/*
+ * "$Id$"
+ *
+ * HTTP routines for the Common UNIX Printing System (CUPS) scheduler.
+ *
+ * Copyright 1997-2002 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:
+ *
+ * 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.
+ * httpConnectEncrypt() - Connect to a HTTP server using encryption.
+ * httpEncryption() - Set the required encryption on the link.
+ * httpReconnect() - Reconnect to a HTTP server...
+ * httpGetHostByName() - Lookup a hostname or IP address, and return
+ * address records for the specified name.
+ * httpSeparate() - Separate a Universal Resource Identifier into its
+ * components.
+ * httpGetSubField() - Get a sub-field value.
+ * 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.
+ * http_upgrade() - Force upgrade to TLS encryption.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include "string.h"
+#include <fcntl.h>
+#include <errno.h>
+
+#include "http.h"
+#include "ipp.h"
+#include "debug.h"
+
+#ifndef WIN32
+# include <signal.h>
+#endif /* !WIN32 */
+
+#ifdef HAVE_LIBSSL
+# include <openssl/err.h>
+# include <openssl/rand.h>
+# include <openssl/ssl.h>
+#endif /* HAVE_LIBSSL */
+
+
+/*
+ * 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);
+#ifdef HAVE_LIBSSL
+static int http_upgrade(http_t *http);
+#endif /* HAVE_LIBSSL */
+
+
+/*
+ * 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)
+{
+#ifdef HAVE_LIBSSL
+ struct timeval curtime; /* Current time in microseconds */
+ int i; /* Looping var */
+ unsigned char data[1024]; /* Seed data */
+#endif /* HAVE_LIBSSL */
+
+#ifdef WIN32
+ 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 */
+
+#ifdef HAVE_LIBSSL
+ SSL_load_error_strings();
+ SSL_library_init();
+
+ /*
+ * Using the current time is a dubious random seed, but on some systems
+ * it is the best we can do (on others, this seed isn't even used...)
+ */
+
+ gettimeofday(&curtime, NULL);
+ srand(curtime.tv_sec + curtime.tv_usec);
+
+ for (i = 0; i < sizeof(data); i ++)
+ data[i] = rand(); /* Yes, this is a poor source of random data... */
+
+ RAND_seed(&data, sizeof(data));
+#endif /* HAVE_LIBSSL */
+}
+
+
+/*
+ * '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 */
+{
+#ifdef HAVE_LIBSSL
+ SSL_CTX *context; /* Context for encryption */
+ SSL *conn; /* Connection for encryption */
+#endif /* HAVE_LIBSSL */
+
+
+ if (!http)
+ return;
+
+#ifdef HAVE_LIBSSL
+ if (http->tls)
+ {
+ conn = (SSL *)(http->tls);
+ context = SSL_get_SSL_CTX(conn);
+
+ SSL_shutdown(conn);
+ SSL_CTX_free(context);
+ SSL_free(conn);
+
+ http->tls = NULL;
+ }
+#endif /* HAVE_LIBSSL */
+
+#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_encryption_t encrypt;/* Type of encryption to use */
+
+
+ /*
+ * Set the default encryption status...
+ */
+
+ if (port == 443)
+ encrypt = HTTP_ENCRYPT_ALWAYS;
+ else
+ encrypt = HTTP_ENCRYPT_IF_REQUESTED;
+
+ return (httpConnectEncrypt(host, port, encrypt));
+}
+
+
+/*
+ * 'httpConnectEncrypt()' - Connect to a HTTP server using encryption.
+ */
+
+http_t * /* O - New HTTP connection */
+httpConnectEncrypt(const char *host, /* I - Host to connect to */
+ int port, /* I - Port number */
+ http_encryption_t encrypt)
+ /* I - Type of encryption to use */
+{
+ int i; /* Looping var */
+ http_t *http; /* New HTTP connection */
+ struct hostent *hostaddr; /* Host address data */
+
+
+ if (host == NULL)
+ return (NULL);
+
+ httpInitialize();
+
+ /*
+ * Lookup the host...
+ */
+
+ if ((hostaddr = httpGetHostByName(host)) == NULL)
+ {
+ /*
+ * This hack to make users that don't have a localhost entry in
+ * their hosts file or DNS happy...
+ */
+
+ if (strcasecmp(host, "localhost") != 0)
+ return (NULL);
+ else if ((hostaddr = httpGetHostByName("127.0.0.1")) == NULL)
+ return (NULL);
+ }
+
+ /*
+ * Verify that it is an IPv4 address (IPv6 support will come in CUPS 1.2...)
+ */
+
+ if (hostaddr->h_addrtype != AF_INET || hostaddr->h_length != 4)
+ 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);
+ http->fd = -1;
+
+ /*
+ * Copy the hostname and port and then "reconnect"...
+ */
+
+ strncpy(http->hostname, host, sizeof(http->hostname) - 1);
+ 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 */
+
+ /*
+ * Set the encryption status...
+ */
+
+ if (port == 443) /* Always use encryption for https */
+ http->encryption = HTTP_ENCRYPT_ALWAYS;
+ else
+ http->encryption = encrypt;
+
+ /*
+ * Loop through the addresses we have until one of them connects...
+ */
+
+ strncpy(http->hostname, host, sizeof(http->hostname) - 1);
+
+ for (i = 0; hostaddr->h_addr_list[i]; i ++)
+ {
+ /*
+ * Load the address...
+ */
+
+ memcpy((char *)&(http->hostaddr.sin_addr), hostaddr->h_addr_list[i],
+ hostaddr->h_length);
+
+ /*
+ * Connect to the remote system...
+ */
+
+ if (!httpReconnect(http))
+ return (http);
+ }
+
+ /*
+ * Could not connect to any known address - bail out!
+ */
+
+ free(http);
+ return (NULL);
+}
+
+
+/*
+ * 'httpEncryption()' - Set the required encryption on the link.
+ */
+
+int /* O - -1 on error, 0 on success */
+httpEncryption(http_t *http, /* I - HTTP data */
+ http_encryption_t e) /* I - New encryption preference */
+{
+#ifdef HAVE_LIBSSL
+ if (!http)
+ return (0);
+
+ http->encryption = e;
+
+ if ((http->encryption == HTTP_ENCRYPT_ALWAYS && !http->tls) ||
+ (http->encryption == HTTP_ENCRYPT_NEVER && http->tls))
+ return (httpReconnect(http));
+ else if (http->encryption == HTTP_ENCRYPT_REQUIRED && !http->tls)
+ return (http_upgrade(http));
+ else
+ return (0);
+#else
+ if (e == HTTP_ENCRYPT_ALWAYS || e == HTTP_ENCRYPT_REQUIRED)
+ return (-1);
+ else
+ return (0);
+#endif /* HAVE_LIBSSL */
+}
+
+
+/*
+ * '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 */
+#ifdef HAVE_LIBSSL
+ SSL_CTX *context; /* Context for encryption */
+ SSL *conn; /* Connection for encryption */
+
+
+ if (http->tls)
+ {
+ conn = (SSL *)(http->tls);
+ context = SSL_get_SSL_CTX(conn);
+
+ SSL_shutdown(conn);
+ SSL_CTX_free(context);
+ SSL_free(conn);
+
+ http->tls = NULL;
+ }
+#endif /* HAVE_LIBSSL */
+
+ /*
+ * Close any previously open socket...
+ */
+
+ if (http->fd >= 0)
+#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)
+ {
+#ifdef WIN32
+ http->error = WSAGetLastError();
+#else
+ http->error = errno;
+#endif /* WIN32 */
+ 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 */
+
+ /*
+ * Using TCP_NODELAY improves responsiveness, especially on systems
+ * with a slow loopback interface... Since we write large buffers
+ * when sending print files and requests, there shouldn't be any
+ * performance penalty for this...
+ */
+
+ val = 1;
+ setsockopt(http->fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
+
+ /*
+ * Connect to the server...
+ */
+
+ if (connect(http->fd, (struct sockaddr *)&(http->hostaddr),
+ sizeof(http->hostaddr)) < 0)
+ {
+#ifdef WIN32
+ http->error = WSAGetLastError();
+#else
+ http->error = errno;
+#endif /* WIN32 */
+ http->status = HTTP_ERROR;
+
+#ifdef WIN32
+ closesocket(http->fd);
+#else
+ close(http->fd);
+#endif
+
+ http->fd = -1;
+
+ return (-1);
+ }
+
+ http->error = 0;
+ http->status = HTTP_CONTINUE;
+
+#ifdef HAVE_LIBSSL
+ if (http->encryption == HTTP_ENCRYPT_ALWAYS)
+ {
+ /*
+ * Always do encryption via SSL.
+ */
+
+ context = SSL_CTX_new(SSLv23_method());
+ conn = SSL_new(context);
+
+ SSL_set_fd(conn, http->fd);
+ if (SSL_connect(conn) != 1)
+ {
+ SSL_CTX_free(context);
+ SSL_free(conn);
+
+#ifdef WIN32
+ http->error = WSAGetLastError();
+#else
+ http->error = errno;
+#endif /* WIN32 */
+ http->status = HTTP_ERROR;
+
+#ifdef WIN32
+ closesocket(http->fd);
+#else
+ close(http->fd);
+#endif
+
+ return (-1);
+ }
+
+ http->tls = conn;
+ }
+ else if (http->encryption == HTTP_ENCRYPT_REQUIRED)
+ return (http_upgrade(http));
+#endif /* HAVE_LIBSSL */
+
+ return (0);
+}
+
+
+/*
+ * 'httpGetHostByName()' - Lookup a hostname or IP address, and return
+ * address records for the specified name.
+ */
+
+struct hostent * /* O - Host entry */
+httpGetHostByName(const char *name) /* I - Hostname or IP address */
+{
+ unsigned ip[4]; /* IP address components */
+ static unsigned packed_ip; /* Packed IPv4 address */
+ static char *packed_ptr[2]; /* Pointer to packed address */
+ static struct hostent host_ip; /* Host entry for IP address */
+
+
+ /*
+ * This function is needed because some operating systems have a
+ * buggy implementation of httpGetHostByName() that does not support
+ * IP addresses. If the first character of the name string is a
+ * number, then sscanf() is used to extract the IP components.
+ * We then pack the components into an IPv4 address manually,
+ * since the inet_aton() function is deprecated. We use the
+ * htonl() macro to get the right byte order for the address.
+ */
+
+ if (isdigit(name[0]))
+ {
+ /*
+ * We have an IP address; break it up and provide the host entry
+ * to the caller. Currently only supports IPv4 addresses, although
+ * it should be trivial to support IPv6 in CUPS 1.2.
+ */
+
+ if (sscanf(name, "%u.%u.%u.%u", ip, ip + 1, ip + 2, ip + 3) != 4)
+ return (NULL); /* Must have 4 numbers */
+
+ packed_ip = htonl(((((((ip[0] << 8) | ip[1]) << 8) | ip[2]) << 8) | ip[3]));
+
+ /*
+ * Fill in the host entry and return it...
+ */
+
+ host_ip.h_name = (char *)name;
+ host_ip.h_aliases = NULL;
+ host_ip.h_addrtype = AF_INET;
+ host_ip.h_length = 4;
+ host_ip.h_addr_list = packed_ptr;
+ packed_ptr[0] = (char *)(&packed_ip);
+ packed_ptr[1] = NULL;
+
+ return (&host_ip);
+ }
+ else
+ {
+ /*
+ * Use the gethostbyname() function to get the IP address for
+ * the name...
+ */
+
+ return (gethostbyname(name));
+ }
+}
+
+
+/*
+ * '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... */
+ const char *atsign, /* @ sign */
+ *slash; /* Separator */
+ char safeuri[HTTP_MAX_URI]; /* "Safe" local copy of URI */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (uri == NULL || method == NULL || username == NULL || host == NULL ||
+ port == NULL || resource == NULL)
+ return;
+
+ /*
+ * Copy the URL to a local string to make sure we don't have a URL
+ * longer than HTTP_MAX_URI characters long...
+ */
+
+ strncpy(safeuri, uri, sizeof(safeuri));
+ safeuri[sizeof(safeuri) - 1] = '\0';
+
+ uri = safeuri;
+
+ /*
+ * 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...
+ */
+
+ for (ptr = host; *uri != ':' && *uri != '\0'; uri ++)
+ if (ptr < (host + HTTP_MAX_URI - 1))
+ *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);
+ 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);
+ 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 username, if any...
+ */
+
+ while (*uri == '/')
+ uri ++;
+
+ if ((slash = strchr(uri, '/')) == NULL)
+ slash = uri + strlen(uri);
+
+ if ((atsign = strchr(uri, '@')) != NULL && atsign < slash)
+ {
+ /*
+ * Got a username:password combo...
+ */
+
+ for (ptr = username; uri < atsign; uri ++)
+ if (ptr < (username + HTTP_MAX_URI - 1))
+ *ptr++ = *uri;
+
+ *ptr = '\0';
+
+ uri = atsign + 1;
+ }
+ else
+ username[0] = '\0';
+
+ /*
+ * Grab the hostname...
+ */
+
+ for (ptr = host; *uri != ':' && *uri != '/' && *uri != '\0'; uri ++)
+ if (ptr < (host + HTTP_MAX_URI - 1))
+ *ptr++ = *uri;
+
+ *ptr = '\0';
+
+ if (*uri != ':')
+ {
+ if (strcasecmp(method, "http") == 0)
+ *port = 80;
+ else if (strcasecmp(method, "https") == 0)
+ *port = 443;
+ else if (strcasecmp(method, "ipp") == 0)
+ *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);
+ resource[HTTP_MAX_URI - 1] = '\0';
+}
+
+
+/*
+ * 'httpGetSubField()' - Get a sub-field value.
+ */
+
+char * /* O - Value or NULL */
+httpGetSubField(http_t *http, /* I - HTTP data */
+ http_field_t field, /* I - Field index */
+ const char *name, /* I - Name of sub-field */
+ char *value) /* O - Value string */
+{
+ const char *fptr; /* Pointer into field */
+ char temp[HTTP_MAX_VALUE], /* Temporary buffer for name */
+ *ptr; /* Pointer into string buffer */
+
+
+ if (http == NULL ||
+ field < HTTP_FIELD_ACCEPT_LANGUAGE ||
+ field > HTTP_FIELD_WWW_AUTHENTICATE ||
+ name == NULL || value == NULL)
+ return (NULL);
+
+ DEBUG_printf(("httpGetSubField(%p, %d, \"%s\", %p)\n",
+ http, field, name, value));
+
+ for (fptr = http->fields[field]; *fptr;)
+ {
+ /*
+ * Skip leading whitespace...
+ */
+
+ while (isspace(*fptr))
+ fptr ++;
+
+ if (*fptr == ',')
+ {
+ fptr ++;
+ continue;
+ }
+
+ /*
+ * Get the sub-field name...
+ */
+
+ for (ptr = temp;
+ *fptr && *fptr != '=' && !isspace(*fptr) && ptr < (temp + sizeof(temp) - 1);
+ *ptr++ = *fptr++);
+
+ *ptr = '\0';
+
+ DEBUG_printf(("name = \"%s\"\n", temp));
+
+ /*
+ * Skip trailing chars up to the '='...
+ */
+
+ while (isspace(*fptr))
+ fptr ++;
+
+ if (!*fptr)
+ break;
+
+ if (*fptr != '=')
+ continue;
+
+ /*
+ * Skip = and leading whitespace...
+ */
+
+ fptr ++;
+
+ while (isspace(*fptr))
+ fptr ++;
+
+ if (*fptr == '\"')
+ {
+ /*
+ * Read quoted string...
+ */
+
+ for (ptr = value, fptr ++;
+ *fptr && *fptr != '\"' && ptr < (value + HTTP_MAX_VALUE - 1);
+ *ptr++ = *fptr++);
+
+ *ptr = '\0';
+
+ while (*fptr && *fptr != '\"')
+ fptr ++;
+
+ if (*fptr)
+ fptr ++;
+ }
+ else
+ {
+ /*
+ * Read unquoted string...
+ */
+
+ for (ptr = value;
+ *fptr && !isspace(*fptr) && *fptr != ',' && ptr < (value + HTTP_MAX_VALUE - 1);
+ *ptr++ = *fptr++);
+
+ *ptr = '\0';
+
+ while (*fptr && !isspace(*fptr) && *fptr != ',')
+ fptr ++;
+ }
+
+ DEBUG_printf(("value = \"%s\"\n", value));
+
+ /*
+ * See if this is the one...
+ */
+
+ if (strcmp(name, temp) == 0)
+ return (value);
+ }
+
+ value[0] = '\0';
+
+ return (NULL);
+}
+
+
+/*
+ * '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 */
+{
+ if (http == NULL ||
+ field < HTTP_FIELD_ACCEPT_LANGUAGE ||
+ field > HTTP_FIELD_WWW_AUTHENTICATE ||
+ value == NULL)
+ return;
+
+ 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 && length <= 256)
+ {
+ /*
+ * Buffer small reads for better performance...
+ */
+
+ if (http->data_remaining > sizeof(http->buffer))
+ bytes = sizeof(http->buffer);
+ else
+ bytes = http->data_remaining;
+
+#ifdef HAVE_LIBSSL
+ if (http->tls)
+ bytes = SSL_read((SSL *)(http->tls), http->buffer, bytes);
+ else
+#endif /* HAVE_LIBSSL */
+ {
+ DEBUG_printf(("httpRead: reading %d bytes from socket into buffer...\n",
+ bytes));
+
+ bytes = recv(http->fd, http->buffer, bytes, 0);
+
+ DEBUG_printf(("httpRead: read %d bytes from socket into buffer...\n",
+ bytes));
+ }
+
+ if (bytes > 0)
+ http->used = bytes;
+ else if (bytes < 0)
+ {
+#ifdef WIN32
+ http->error = WSAGetLastError();
+#else
+ http->error = errno;
+#endif /* WIN32 */
+ return (-1);
+ }
+ else
+ return (0);
+ }
+
+ 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);
+ }
+#ifdef HAVE_LIBSSL
+ else if (http->tls)
+ bytes = SSL_read((SSL *)(http->tls), buffer, length);
+#endif /* HAVE_LIBSSL */
+ 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)
+#ifdef WIN32
+ http->error = WSAGetLastError();
+#else
+ http->error = errno;
+#endif /* WIN32 */
+
+ 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 if (http->state == HTTP_PUT_RECV)
+ http->state = HTTP_STATUS;
+ else
+ http->state = HTTP_WAITING;
+
+ if (httpPrintf(http, "\r\n") < 0)
+ return (-1);
+
+ return (0);
+ }
+ }
+
+ tbytes = 0;
+
+ while (length > 0)
+ {
+#ifdef HAVE_LIBSSL
+ if (http->tls)
+ bytes = SSL_write((SSL *)(http->tls), buffer, length);
+ else
+#endif /* HAVE_LIBSSL */
+ 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...
+ */
+
+#ifdef WIN32
+ WSASetLastError(0);
+#else
+ errno = 0;
+#endif /* WIN32 */
+
+ do
+ {
+ bufptr = http->buffer;
+ bufend = http->buffer + http->used;
+
+ while (bufptr < bufend)
+ if (*bufptr == 0x0a)
+ break;
+ else
+ bufptr ++;
+
+ if (bufptr >= bufend && http->used < HTTP_MAX_BUFFER)
+ {
+ /*
+ * No newline; see if there is more data to be read...
+ */
+
+#ifdef HAVE_LIBSSL
+ if (http->tls)
+ bytes = SSL_read((SSL *)(http->tls), bufend,
+ HTTP_MAX_BUFFER - http->used);
+ else
+#endif /* HAVE_LIBSSL */
+ bytes = recv(http->fd, bufend, HTTP_MAX_BUFFER - http->used, 0);
+
+ if (bytes < 0)
+ {
+ /*
+ * Nope, can't get a line this time...
+ */
+
+#ifdef WIN32
+ 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 */
+
+ 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->used < HTTP_MAX_BUFFER);
+
+ http->activity = time(NULL);
+
+ /*
+ * Read a line from the buffer...
+ */
+
+ lineptr = line;
+ bufptr = http->buffer;
+ bytes = 0;
+ length --;
+
+ while (bufptr < bufend && bytes < length)
+ {
+ bytes ++;
+
+ if (*bufptr == 0x0a)
+ {
+ bufptr ++;
+ break;
+ }
+ else if (*bufptr == 0x0d)
+ bufptr ++;
+ else
+ *lineptr++ = *bufptr++;
+ }
+
+ if (bytes > 0)
+ {
+ *lineptr = '\0';
+
+ http->used -= bytes;
+ if (http->used > 0)
+ memcpy(http->buffer, bufptr, http->used);
+
+ DEBUG_printf(("httpGets(): Returning \"%s\"\n", line));
+ return (line);
+ }
+
+ 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)
+ {
+#ifdef HAVE_LIBSSL
+ if (http->tls)
+ nbytes = SSL_write((SSL *)(http->tls), bufptr, bytes - tbytes);
+ else
+#endif /* HAVE_LIBSSL */
+ nbytes = send(http->fd, bufptr, bytes - tbytes, 0);
+
+ if (nbytes < 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_CONTINUE :
+ return ("Continue");
+ case HTTP_SWITCHING_PROTOCOLS :
+ return ("Switching Protocols");
+ 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_UPGRADE_REQUIRED :
+ return ("Upgrade Required");
+ 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);
+ snprintf(datetime, sizeof(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 */
+#ifdef HAVE_LIBSSL
+ SSL_CTX *context; /* Context for encryption */
+ SSL *conn; /* Connection for encryption */
+#endif /* HAVE_LIBSSL */
+
+
+ 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);
+
+#ifdef HAVE_LIBSSL
+ if (http->status == HTTP_SWITCHING_PROTOCOLS && !http->tls)
+ {
+ context = SSL_CTX_new(SSLv23_method());
+ conn = SSL_new(context);
+
+ SSL_set_fd(conn, http->fd);
+ if (SSL_connect(conn) != 1)
+ {
+ SSL_CTX_free(context);
+ SSL_free(conn);
+
+#ifdef WIN32
+ http->error = WSAGetLastError();
+#else
+ http->error = errno;
+#endif /* WIN32 */
+ http->status = HTTP_ERROR;
+
+#ifdef WIN32
+ closesocket(http->fd);
+#else
+ close(http->fd);
+#endif
+
+ return (HTTP_ERROR);
+ }
+
+ http->tls = conn;
+
+ return (HTTP_CONTINUE);
+ }
+#endif /* HAVE_LIBSSL */
+
+ 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, (int *)&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' && ptr < (buf + sizeof(buf) - 1); uri ++)
+ if (*uri <= ' ' || *uri >= 127)
+ {
+ if (ptr < (buf + sizeof(buf) - 1))
+ *ptr ++ = '%';
+ if (ptr < (buf + sizeof(buf) - 1))
+ *ptr ++ = hex[(*uri >> 4) & 15];
+ if (ptr < (buf + sizeof(buf) - 1))
+ *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;
+
+#ifdef HAVE_LIBSSL
+ if (http->encryption == HTTP_ENCRYPT_REQUIRED && !http->tls)
+ {
+ httpSetField(http, HTTP_FIELD_CONNECTION, "Upgrade");
+ httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.0,SSL/2.0,SSL/3.0");
+ }
+#endif /* HAVE_LIBSSL */
+
+ 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);
+}
+
+
+#ifdef HAVE_LIBSSL
+/*
+ * 'http_upgrade()' - Force upgrade to TLS encryption.
+ */
+
+static int /* O - Status of connection */
+http_upgrade(http_t *http) /* I - HTTP data */
+{
+ int ret; /* Return value */
+ http_t myhttp; /* Local copy of HTTP data */
+
+
+ DEBUG_printf(("http_upgrade(%p)\n", http));
+
+ /*
+ * Copy the HTTP data to a local variable so we can do the OPTIONS
+ * request without interfering with the existing request data...
+ */
+
+ memcpy(&myhttp, http, sizeof(myhttp));
+
+ /*
+ * Send an OPTIONS request to the server, requiring SSL or TLS
+ * encryption on the link...
+ */
+
+ httpClearFields(&myhttp);
+ httpSetField(&myhttp, HTTP_FIELD_CONNECTION, "upgrade");
+ httpSetField(&myhttp, HTTP_FIELD_UPGRADE, "TLS/1.0, SSL/2.0, SSL/3.0");
+
+ if ((ret = httpOptions(&myhttp, "*")) == 0)
+ {
+ /*
+ * Wait for the secure connection...
+ */
+
+ while (httpUpdate(&myhttp) == HTTP_CONTINUE);
+ }
+
+ httpFlush(&myhttp);
+
+ /*
+ * Copy the HTTP data back over, if any...
+ */
+
+ http->fd = myhttp.fd;
+ http->error = myhttp.error;
+ http->activity = myhttp.activity;
+ http->status = myhttp.status;
+ http->version = myhttp.version;
+ http->keep_alive = myhttp.keep_alive;
+ http->used = myhttp.used;
+
+ if (http->used)
+ memcpy(http->buffer, myhttp.buffer, http->used);
+
+ http->auth_type = myhttp.auth_type;
+ http->nonce_count = myhttp.nonce_count;
+
+ memcpy(http->nonce, myhttp.nonce, sizeof(http->nonce));
+
+ http->tls = myhttp.tls;
+ http->encryption = myhttp.encryption;
+
+ /*
+ * See if we actually went secure...
+ */
+
+ if (!http->tls)
+ {
+ /*
+ * Server does not support HTTP upgrade...
+ */
+
+ DEBUG_puts("Server does not support HTTP upgrade!");
+
+#ifdef WIN32
+ closesocket(http->fd);
+#else
+ close(http->fd);
+#endif
+
+ http->fd = -1;
+
+ return (-1);
+ }
+ else
+ return (ret);
+}
+#endif /* HAVE_LIBSSL */
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/http.h b/cups/http.h
new file mode 100644
index 000000000..d922d6a43
--- /dev/null
+++ b/cups/http.h
@@ -0,0 +1,345 @@
+/*
+ * "$Id$"
+ *
+ * Hyper-Text Transport Protocol definitions for the Common UNIX Printing
+ * System (CUPS).
+ *
+ * Copyright 1997-2002 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 <string.h>
+# include <time.h>
+# ifdef WIN32
+# include <winsock.h>
+# else
+# include <unistd.h>
+# include <sys/time.h>
+# include <sys/types.h>
+# include <sys/socket.h>
+# include <netdb.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
+# include <netinet/in_systm.h>
+# include <netinet/ip.h>
+# include <netinet/tcp.h>
+# endif /* WIN32 */
+
+# 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 encryption values...
+ */
+
+typedef enum
+{
+ HTTP_ENCRYPT_IF_REQUESTED, /* Encrypt if requested (TLS upgrade) */
+ HTTP_ENCRYPT_NEVER, /* Never encrypt */
+ HTTP_ENCRYPT_REQUIRED, /* Encryption is required (TLS upgrade) */
+ HTTP_ENCRYPT_ALWAYS /* Always encrypt (SSL) */
+} http_encryption_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_SWITCHING_PROTOCOLS, /* HTTP upgrade to TLS/SSL */
+
+ 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_UPGRADE_REQUIRED = 426, /* Upgrade to SSL/TLS required */
+
+ 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 */
+ void *tls; /* TLS state information */
+ http_encryption_t encryption; /* Encryption requirements */
+} 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 http_t *httpConnectEncrypt(const char *host, int port,
+ http_encryption_t encrypt);
+extern int httpDelete(http_t *http, const char *uri);
+extern int httpEncryption(http_t *http, http_encryption_t e);
+# 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 struct hostent *httpGetHostByName(const char *name);
+extern char *httpGetSubField(http_t *http, http_field_t field,
+ const char *name, char *value);
+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);
+extern char *httpMD5(const char *, const char *, const char *,
+ char [33]);
+extern char *httpMD5Final(const char *, const char *, const char *,
+ char [33]);
+extern char *httpMD5String(const md5_byte_t *, char [33]);
+
+
+/*
+ * 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 000000000..73fa8df15
--- /dev/null
+++ b/cups/ipp.c
@@ -0,0 +1,2028 @@
+/*
+ * "$Id$"
+ *
+ * Internet Printing Protocol support functions for the Common UNIX
+ * Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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 in seconds.
+ * ippDelete() - Delete an IPP request.
+ * ippErrorString() - Return a textual message for the given error
+ * message.
+ * ippFindAttribute() - Find a named attribute in a request...
+ * ippFindNextAttribute() - Find the next named attribute in a request...
+ * ippLength() - Compute the length of an IPP request.
+ * ippNew() - Allocate a new IPP request.
+ * ippPort() - Return the default IPP port number.
+ * ippRead() - Read data for an IPP request.
+ * ippSetPort() - Set the default port number.
+ * 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_free_attr() - Free an attribute.
+ * ipp_read() - Semi-blocking read on a HTTP connection...
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "string.h"
+#include "language.h"
+
+#include "ipp.h"
+#include "debug.h"
+#include <ctype.h>
+
+
+/*
+ * Local globals...
+ */
+
+static int ipp_port = 0;
+
+
+/*
+ * 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(%p, %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 */
+ ipp_value_t *value; /* Current value */
+
+
+ DEBUG_printf(("ippAddBooleans(%p, %02x, \'%s\', %d, %p)\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, value = attr->values;
+ i < num_values;
+ i ++, value ++)
+ value->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(%p, %02x, \'%s\', %p)\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(%p, %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 */
+ ipp_value_t *value; /* Current value */
+
+
+ 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, value = attr->values;
+ i < num_values;
+ i ++, value ++)
+ value->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 = ((int)type & IPP_TAG_COPY) ? (char *)charset :
+ charset ? strdup(charset) : NULL;
+ attr->values[0].string.text = ((int)type & IPP_TAG_COPY) ? (char *)value :
+ value ? strdup(value) : NULL;
+
+ if ((type == IPP_TAG_LANGUAGE || type == IPP_TAG_CHARSET) &&
+ attr->values[0].string.text)
+ {
+ /*
+ * Convert to lowercase and change _ to - as needed...
+ */
+
+ char *p;
+
+
+ for (p = attr->values[0].string.text; *p; p ++)
+ if (*p == '_')
+ *p = '-';
+ else
+ *p = tolower(*p);
+ }
+
+ 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 */
+ ipp_value_t *value; /* Current value */
+
+
+ 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;
+
+ for (i = 0, value = attr->values;
+ i < num_values;
+ i ++, value ++)
+ {
+ if (i == 0)
+ value->string.charset = ((int)type & IPP_TAG_COPY) ? (char *)charset :
+ charset ? strdup(charset) : NULL;
+ else
+ value->string.charset = attr->values[0].string.charset;
+
+ if (values != NULL)
+ value->string.text = ((int)type & IPP_TAG_COPY) ? (char *)values[i] :
+ 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 */
+ ipp_value_t *value; /* Current value */
+
+
+ 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, value = attr->values;
+ i < num_values;
+ i ++, value ++)
+ {
+ value->range.lower = lower[i];
+ value->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 */
+ ipp_value_t *value; /* Current value */
+
+
+ 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, value = attr->values;
+ i < num_values;
+ i ++, value ++)
+ {
+ value->resolution.xres = xres[i];
+ value->resolution.yres = yres[i];
+ value->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(%p)\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 */
+{
+ ipp_attribute_t *attr, /* Current attribute */
+ *next; /* Next attribute */
+
+
+ DEBUG_printf(("ippDelete(): %p\n", ipp));
+
+ if (ipp == NULL)
+ return;
+
+ for (attr = ipp->attrs; attr != NULL; attr = next)
+ {
+ next = attr->next;
+ _ipp_free_attr(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 char unknown[255]; /* Unknown error statuses */
+ static const char *status_oks[] = /* "OK" status codes */
+ {
+ "successful-ok",
+ "successful-ok-ignored-or-substituted-attributes",
+ "successful-ok-conflicting-attributes",
+ "successful-ok-ignored-subscriptions",
+ "successful-ok-ignored-notifications",
+ "successful-ok-too-many-events",
+ "successful-ok-but-cancel-subscription"
+ },
+ *status_400s[] = /* Client errors */
+ {
+ "client-error-bad-request",
+ "client-error-forbidden",
+ "client-error-not-authenticated",
+ "client-error-not-authorized",
+ "client-error-not-possible",
+ "client-error-timeout",
+ "client-error-not-found",
+ "client-error-gone",
+ "client-error-request-entity-too-large",
+ "client-error-request-value-too-long",
+ "client-error-document-format-not-supported",
+ "client-error-attributes-or-values-not-supported",
+ "client-error-uri-scheme-not-supported",
+ "client-error-charset-not-supported",
+ "client-error-conflicting-attributes",
+ "client-error-compression-not-supported",
+ "client-error-compression-error",
+ "client-error-document-format-error",
+ "client-error-document-access-error",
+ "client-error-attributes-not-settable",
+ "client-error-ignored-all-subscriptions",
+ "client-error-too-many-subscriptions",
+ "client-error-ignored-all-notifications",
+ "client-error-print-support-file-not-found"
+ },
+ *status_500s[] = /* Server errors */
+ {
+ "server-error-internal-error",
+ "server-error-operation-not-supported",
+ "server-error-service-unavailable",
+ "server-error-version-not-supported",
+ "server-error-device-error",
+ "server-error-temporary-error",
+ "server-error-not-accepting-jobs",
+ "server-error-busy",
+ "server-error-job-canceled",
+ "server-error-multiple-document-jobs-not-supported",
+ "server-error-printer-is-deactivated"
+ };
+
+
+ /*
+ * See if the error code is a known value...
+ */
+
+ if (error >= IPP_OK && error <= IPP_OK_BUT_CANCEL_SUBSCRIPTION)
+ return (status_oks[error]);
+ else if (error == IPP_REDIRECTION_OTHER_SITE)
+ return ("redirection-other-site");
+ else if (error >= IPP_BAD_REQUEST && error <= IPP_PRINT_SUPPORT_FILE_NOT_FOUND)
+ return (status_400s[error - IPP_BAD_REQUEST]);
+ else if (error >= IPP_INTERNAL_ERROR && error <= IPP_PRINTER_IS_DEACTIVATED)
+ return (status_500s[error - IPP_INTERNAL_ERROR]);
+
+ /*
+ * No, build an "unknown-xxxx" error string...
+ */
+
+ sprintf(unknown, "unknown-%04x", error);
+
+ return (unknown);
+}
+
+
+/*
+ * '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 */
+{
+ DEBUG_printf(("ippFindAttribute(%p, \'%s\')\n", ipp, name));
+
+ if (ipp == NULL || name == NULL)
+ return (NULL);
+
+ /*
+ * Reset the current pointer...
+ */
+
+ ipp->current = NULL;
+
+ /*
+ * Search for the attribute...
+ */
+
+ return (ippFindNextAttribute(ipp, name, type));
+}
+
+
+/*
+ * 'ippFindNextAttribute()' - Find the next named attribute in a request...
+ */
+
+ipp_attribute_t * /* O - Matching attribute */
+ippFindNextAttribute(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 */
+ ipp_tag_t value_tag; /* Value tag */
+
+
+ DEBUG_printf(("ippFindNextAttribute(%p, \'%s\')\n", ipp, name));
+
+ if (ipp == NULL || name == NULL)
+ return (NULL);
+
+ if (ipp->current)
+ attr = ipp->current->next;
+ else
+ attr = ipp->attrs;
+
+ for (; attr != NULL; attr = attr->next)
+ {
+ DEBUG_printf(("ippFindAttribute: attr = %p, name = \'%s\'\n", attr,
+ attr->name));
+
+ value_tag = (ipp_tag_t)(attr->value_tag & IPP_TAG_MASK);
+
+ if (attr->name != NULL && strcasecmp(attr->name, name) == 0 &&
+ (value_tag == type || type == IPP_TAG_ZERO ||
+ (value_tag == IPP_TAG_TEXTLANG && type == IPP_TAG_TEXT) ||
+ (value_tag == IPP_TAG_NAMELANG && type == IPP_TAG_NAME)))
+ {
+ ipp->current = attr;
+
+ return (attr);
+ }
+ }
+
+ ipp->current = NULL;
+
+ 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 */
+ ipp_value_t *value; /* Current value */
+
+
+ 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 & ~IPP_TAG_COPY)
+ {
+ 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, value = attr->values;
+ i < attr->num_values;
+ i ++, value ++)
+ bytes += strlen(value->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, value = attr->values;
+ i < attr->num_values;
+ i ++, value ++)
+ bytes += strlen(value->string.charset) +
+ strlen(value->string.text);
+ break;
+
+ default :
+ for (i = 0, value = attr->values;
+ i < attr->num_values;
+ i ++, value ++)
+ 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(1, sizeof(ipp_t))) != NULL)
+ {
+ /*
+ * Default to IPP 1.1...
+ */
+
+ temp->request.any.version[0] = 1;
+ temp->request.any.version[1] = 1;
+ }
+
+ DEBUG_printf(("ippNew(): %p\n", temp));
+
+ 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 */
+ ipp_value_t *value; /* Current value */
+
+
+ DEBUG_printf(("ippRead(%p, %p)\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;
+
+ DEBUG_printf(("ippRead: version=%d.%d\n", buffer[0], buffer[1]));
+ DEBUG_printf(("ippRead: op_status=%04x\n", ipp->request.any.op_status));
+ DEBUG_printf(("ippRead: request_id=%d\n", ipp->request.any.request_id));
+
+ /*
+ * 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;
+
+ /*
+ * Make sure we aren't adding a new value of a different
+ * type...
+ */
+
+ if (attr->value_tag == IPP_TAG_STRING ||
+ (attr->value_tag >= IPP_TAG_TEXTLANG &&
+ attr->value_tag <= IPP_TAG_MIMETYPE))
+ {
+ /*
+ * String values can sometimes come across in different
+ * forms; accept sets of differing values...
+ */
+
+ if (tag != IPP_TAG_STRING &&
+ (tag < IPP_TAG_TEXTLANG || tag > IPP_TAG_MIMETYPE))
+ return (IPP_ERROR);
+ }
+ else if (attr->value_tag != tag)
+ return (IPP_ERROR);
+
+ /*
+ * Finally, reallocate the attribute array as needed...
+ */
+
+ if ((attr->num_values % IPP_MAX_VALUES) == 0)
+ {
+ ipp_attribute_t *temp, /* Pointer to new buffer */
+ *ptr; /* Pointer in attribute list */
+
+
+ /*
+ * Reallocate memory...
+ */
+
+ if ((temp = realloc(attr, sizeof(ipp_attribute_t) +
+ (attr->num_values + IPP_MAX_VALUES - 1) *
+ sizeof(ipp_value_t))) == NULL)
+ return (IPP_ERROR);
+
+ /*
+ * Reset pointers in the list...
+ */
+
+ for (ptr = ipp->attrs; ptr && ptr->next != attr; ptr = ptr->next);
+
+ if (ptr)
+ ptr->next = temp;
+ else
+ ipp->attrs = temp;
+
+ attr = ipp->current = ipp->last = temp;
+ }
+ }
+ else
+ {
+ /*
+ * New attribute; read the name and add it...
+ */
+
+ if (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;
+ }
+
+ value = attr->values + attr->num_values;
+
+ 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];
+
+ value->integer = n;
+ break;
+ case IPP_TAG_BOOLEAN :
+ if (ipp_read(http, buffer, 1) < 1)
+ return (IPP_ERROR);
+
+ value->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 :
+ value->string.text = calloc(n + 1, 1);
+
+ if (ipp_read(http, value->string.text, n) < n)
+ return (IPP_ERROR);
+
+ DEBUG_printf(("ippRead: value = \'%s\'\n",
+ value->string.text));
+ break;
+ case IPP_TAG_DATE :
+ if (ipp_read(http, value->date, 11) < 11)
+ return (IPP_ERROR);
+ break;
+ case IPP_TAG_RESOLUTION :
+ if (ipp_read(http, buffer, 9) < 9)
+ return (IPP_ERROR);
+
+ value->resolution.xres =
+ (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
+ buffer[3];
+ value->resolution.yres =
+ (((((buffer[4] << 8) | buffer[5]) << 8) | buffer[6]) << 8) |
+ buffer[7];
+ value->resolution.units =
+ (ipp_res_t)buffer[8];
+ break;
+ case IPP_TAG_RANGE :
+ if (ipp_read(http, buffer, 8) < 8)
+ return (IPP_ERROR);
+
+ value->range.lower =
+ (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
+ buffer[3];
+ value->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];
+
+ value->string.charset = calloc(n + 1, 1);
+
+ memcpy(value->string.charset,
+ bufptr + 2, n);
+
+ bufptr += 2 + n;
+ n = (bufptr[0] << 8) | bufptr[1];
+
+ value->string.text = calloc(n + 1, 1);
+
+ memcpy(value->string.text,
+ bufptr + 2, n);
+ break;
+
+ default : /* Other unsupported values */
+ value->unknown.length = n;
+ if (n > 0)
+ {
+ value->unknown.data = malloc(n);
+ if (ipp_read(http, value->unknown.data, n) < n)
+ return (IPP_ERROR);
+ }
+ else
+ value->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;
+
+ default :
+ break; /* anti-compiler-warning-code */
+ }
+
+ 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 */
+ ipp_value_t *value; /* Current value */
+
+
+ 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;
+
+ DEBUG_printf(("ippWrite: version=%d.%d\n", buffer[0], buffer[1]));
+ DEBUG_printf(("ippWrite: op_status=%04x\n", ipp->request.any.op_status));
+ DEBUG_printf(("ippWrite: request_id=%d\n", ipp->request.any.request_id));
+
+ /*
+ * 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;
+ }
+
+ if ((n = strlen(attr->name)) > (sizeof(buffer) - 3))
+ return (IPP_ERROR);
+
+ 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 & ~IPP_TAG_COPY)
+ {
+ case IPP_TAG_INTEGER :
+ case IPP_TAG_ENUM :
+ for (i = 0, value = attr->values;
+ i < attr->num_values;
+ i ++, value ++)
+ {
+ if ((sizeof(buffer) - (bufptr - buffer)) < 9)
+ {
+ if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0)
+ {
+ DEBUG_puts("ippWrite: Could not write IPP attribute...");
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
+ if (i)
+ {
+ /*
+ * Arrays and sets are done by sending additional
+ * values with a zero-length name...
+ */
+
+ *bufptr++ = attr->value_tag;
+ *bufptr++ = 0;
+ *bufptr++ = 0;
+ }
+
+ *bufptr++ = 0;
+ *bufptr++ = 4;
+ *bufptr++ = value->integer >> 24;
+ *bufptr++ = value->integer >> 16;
+ *bufptr++ = value->integer >> 8;
+ *bufptr++ = value->integer;
+ }
+ break;
+
+ case IPP_TAG_BOOLEAN :
+ for (i = 0, value = attr->values;
+ i < attr->num_values;
+ i ++, value ++)
+ {
+ if ((sizeof(buffer) - (bufptr - buffer)) < 6)
+ {
+ if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0)
+ {
+ DEBUG_puts("ippWrite: Could not write IPP attribute...");
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
+ if (i)
+ {
+ /*
+ * Arrays and sets are done by sending additional
+ * values with a zero-length name...
+ */
+
+ *bufptr++ = attr->value_tag;
+ *bufptr++ = 0;
+ *bufptr++ = 0;
+ }
+
+ *bufptr++ = 0;
+ *bufptr++ = 1;
+ *bufptr++ = value->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, value = attr->values;
+ i < attr->num_values;
+ i ++, value ++)
+ {
+ 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"));
+
+ if ((sizeof(buffer) - (bufptr - buffer)) < 3)
+ {
+ if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0)
+ {
+ DEBUG_puts("ippWrite: Could not write IPP attribute...");
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
+ *bufptr++ = attr->value_tag;
+ *bufptr++ = 0;
+ *bufptr++ = 0;
+ }
+
+ n = strlen(value->string.text);
+
+ if (n > sizeof(buffer))
+ return (IPP_ERROR);
+
+ DEBUG_printf(("ippWrite: writing string = %d, \'%s\'\n", n,
+ value->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, value->string.text, n);
+ bufptr += n;
+ }
+ break;
+
+ case IPP_TAG_DATE :
+ for (i = 0, value = attr->values;
+ i < attr->num_values;
+ i ++, value ++)
+ {
+ if ((sizeof(buffer) - (bufptr - buffer)) < 16)
+ {
+ if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0)
+ {
+ DEBUG_puts("ippWrite: Could not write IPP attribute...");
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
+ if (i)
+ {
+ /*
+ * Arrays and sets are done by sending additional
+ * values with a zero-length name...
+ */
+
+ *bufptr++ = attr->value_tag;
+ *bufptr++ = 0;
+ *bufptr++ = 0;
+ }
+
+ *bufptr++ = 0;
+ *bufptr++ = 11;
+ memcpy(bufptr, value->date, 11);
+ bufptr += 11;
+ }
+ break;
+
+ case IPP_TAG_RESOLUTION :
+ for (i = 0, value = attr->values;
+ i < attr->num_values;
+ i ++, value ++)
+ {
+ if ((sizeof(buffer) - (bufptr - buffer)) < 14)
+ {
+ if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0)
+ {
+ DEBUG_puts("ippWrite: Could not write IPP attribute...");
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
+ if (i)
+ {
+ /*
+ * Arrays and sets are done by sending additional
+ * values with a zero-length name...
+ */
+
+ *bufptr++ = attr->value_tag;
+ *bufptr++ = 0;
+ *bufptr++ = 0;
+ }
+
+ *bufptr++ = 0;
+ *bufptr++ = 9;
+ *bufptr++ = value->resolution.xres >> 24;
+ *bufptr++ = value->resolution.xres >> 16;
+ *bufptr++ = value->resolution.xres >> 8;
+ *bufptr++ = value->resolution.xres;
+ *bufptr++ = value->resolution.yres >> 24;
+ *bufptr++ = value->resolution.yres >> 16;
+ *bufptr++ = value->resolution.yres >> 8;
+ *bufptr++ = value->resolution.yres;
+ *bufptr++ = value->resolution.units;
+ }
+ break;
+
+ case IPP_TAG_RANGE :
+ for (i = 0, value = attr->values;
+ i < attr->num_values;
+ i ++, value ++)
+ {
+ if ((sizeof(buffer) - (bufptr - buffer)) < 13)
+ {
+ if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0)
+ {
+ DEBUG_puts("ippWrite: Could not write IPP attribute...");
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
+ if (i)
+ {
+ /*
+ * Arrays and sets are done by sending additional
+ * values with a zero-length name...
+ */
+
+ *bufptr++ = attr->value_tag;
+ *bufptr++ = 0;
+ *bufptr++ = 0;
+ }
+
+ *bufptr++ = 0;
+ *bufptr++ = 8;
+ *bufptr++ = value->range.lower >> 24;
+ *bufptr++ = value->range.lower >> 16;
+ *bufptr++ = value->range.lower >> 8;
+ *bufptr++ = value->range.lower;
+ *bufptr++ = value->range.upper >> 24;
+ *bufptr++ = value->range.upper >> 16;
+ *bufptr++ = value->range.upper >> 8;
+ *bufptr++ = value->range.upper;
+ }
+ break;
+
+ case IPP_TAG_TEXTLANG :
+ case IPP_TAG_NAMELANG :
+ for (i = 0, value = attr->values;
+ i < attr->num_values;
+ i ++, value ++)
+ {
+ if (i)
+ {
+ /*
+ * Arrays and sets are done by sending additional
+ * values with a zero-length name...
+ */
+
+ if ((sizeof(buffer) - (bufptr - buffer)) < 3)
+ {
+ if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0)
+ {
+ DEBUG_puts("ippWrite: Could not write IPP attribute...");
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
+ *bufptr++ = attr->value_tag;
+ *bufptr++ = 0;
+ *bufptr++ = 0;
+ }
+
+ n = strlen(value->string.charset) +
+ strlen(value->string.text) +
+ 4;
+
+ if (n > sizeof(buffer))
+ return (IPP_ERROR);
+
+ 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(value->string.charset);
+ *bufptr++ = n >> 8;
+ *bufptr++ = n;
+
+ /* Charset */
+ memcpy(bufptr, value->string.charset, n);
+ bufptr += n;
+
+ /* Length of text */
+ n = strlen(value->string.text);
+ *bufptr++ = n >> 8;
+ *bufptr++ = n;
+
+ /* Text */
+ memcpy(bufptr, value->string.text, n);
+ bufptr += n;
+ }
+ break;
+
+ default :
+ for (i = 0, value = attr->values;
+ i < attr->num_values;
+ i ++, value ++)
+ {
+ if (i)
+ {
+ /*
+ * Arrays and sets are done by sending additional
+ * values with a zero-length name...
+ */
+
+ if ((sizeof(buffer) - (bufptr - buffer)) < 3)
+ {
+ if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0)
+ {
+ DEBUG_puts("ippWrite: Could not write IPP attribute...");
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
+ *bufptr++ = attr->value_tag;
+ *bufptr++ = 0;
+ *bufptr++ = 0;
+ }
+
+ n = value->unknown.length;
+
+ if (n > sizeof(buffer))
+ return (IPP_ERROR);
+
+ 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, value->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;
+
+ default :
+ break; /* anti-compiler-warning-code */
+ }
+
+ 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 (ipp_port)
+ return (ipp_port);
+ else if ((server_port = getenv("IPP_PORT")) != NULL)
+ return (ipp_port = atoi(server_port));
+ else if ((port = getservbyname("ipp", NULL)) == NULL)
+ return (ipp_port = IPP_PORT);
+ else
+ return (ipp_port = ntohs(port->s_port));
+}
+
+
+/*
+ * 'ippSetPort()' - Set the default port number.
+ */
+
+void
+ippSetPort(int p) /* I - Port number to use */
+{
+ ipp_port = p;
+}
+
+
+/*
+ * '_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(%p, %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;
+
+ DEBUG_printf(("_ipp_add_attr(): %p\n", attr));
+
+ return (attr);
+}
+
+
+/*
+ * '_ipp_free_attr()' - Free an attribute.
+ */
+
+void
+_ipp_free_attr(ipp_attribute_t *attr) /* I - Attribute to free */
+{
+ int i; /* Looping var */
+ ipp_value_t *value; /* Current value */
+
+
+ DEBUG_printf(("_ipp_free_attr(): %p\n", attr));
+
+ 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, value = attr->values;
+ i < attr->num_values;
+ i ++, value ++)
+ free(value->string.text);
+ break;
+
+ case IPP_TAG_TEXTLANG :
+ case IPP_TAG_NAMELANG :
+ for (i = 0, value = attr->values;
+ i < attr->num_values;
+ i ++, value ++)
+ {
+ if (value->string.charset && i == 0)
+ free(value->string.charset);
+ free(value->string.text);
+ }
+ break;
+
+ default :
+ break; /* anti-compiler-warning-code */
+ }
+
+ if (attr->name != NULL)
+ free(attr->name);
+
+ free(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 */
+ char len[32]; /* Length string */
+
+
+ /*
+ * Loop until all bytes are read...
+ */
+
+ for (tbytes = 0, bytes = 0; tbytes < length; tbytes += bytes, buffer += bytes)
+ {
+ if (http->used > 0)
+ {
+ /*
+ * Do "fast read" from HTTP buffer directly...
+ */
+
+ if (http->used > (length - tbytes))
+ bytes = length - tbytes;
+ else
+ bytes = http->used;
+
+ if (bytes == 1)
+ buffer[0] = http->buffer[0];
+ else
+ memcpy(buffer, http->buffer, bytes);
+
+ http->used -= bytes;
+ http->data_remaining -= bytes;
+
+ if (http->used > 0)
+ memcpy(http->buffer, http->buffer + bytes, http->used);
+
+ 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;
+ }
+ }
+ }
+ else if ((bytes = httpRead(http, (char *)buffer, length - tbytes)) <= 0)
+ break;
+ }
+
+ /*
+ * Return the number of bytes read...
+ */
+
+ if (tbytes == 0 && bytes < 0)
+ return (-1);
+ else
+ return (tbytes);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/ipp.h b/cups/ipp.h
new file mode 100644
index 000000000..382c5b108
--- /dev/null
+++ b/cups/ipp.h
@@ -0,0 +1,432 @@
+/*
+ * "$Id$"
+ *
+ * Internet Printing Protocol definitions for the Common UNIX Printing
+ * System (CUPS).
+ *
+ * Copyright 1997-2002 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 "http.h"
+
+
+/*
+ * 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 10 /* Now just an allocation increment */
+
+
+/*
+ * 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_SUBSCRIPTION,
+ IPP_TAG_EVENT_NOTIFICATION,
+ IPP_TAG_UNSUPPORTED_VALUE = 0x10,
+ IPP_TAG_DEFAULT,
+ IPP_TAG_UNKNOWN,
+ IPP_TAG_NOVALUE,
+ IPP_TAG_NOTSETTABLE = 0x15,
+ IPP_TAG_DELETEATTR,
+ IPP_TAG_ADMINDEFINE,
+ 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_BEGIN_COLLECTION,
+ IPP_TAG_TEXTLANG,
+ IPP_TAG_NAMELANG,
+ IPP_TAG_END_COLLECTION,
+ 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_MEMBERNAME,
+ IPP_TAG_MASK = 0x7fffffff, /* Mask for copied attribute values */
+ IPP_TAG_COPY = -0x7fffffff-1 /* Bitflag for copied attribute values */
+} ipp_tag_t;
+
+typedef enum /**** Resolution units... ****/
+{
+ IPP_RES_PER_INCH = 3,
+ IPP_RES_PER_CM
+} ipp_res_t;
+
+typedef enum /**** Finishings... ****/
+{
+ IPP_FINISHINGS_NONE = 3,
+ IPP_FINISHINGS_STAPLE,
+ IPP_FINISHINGS_PUNCH,
+ IPP_FINISHINGS_COVER,
+ IPP_FINISHINGS_BIND,
+ IPP_FINISHINGS_SADDLE_STITCH,
+ IPP_FINISHINGS_EDGE_STITCH,
+ IPP_FINISHINGS_FOLD,
+ IPP_FINISHINGS_TRIM,
+ IPP_FINISHINGS_BALE,
+ IPP_FINISHINGS_BOOKLET_MAKER,
+ IPP_FINISHINGS_JOB_OFFSET,
+ IPP_FINISHINGS_STAPLE_TOP_LEFT = 20,
+ IPP_FINISHINGS_STAPLE_BOTTOM_LEFT,
+ IPP_FINISHINGS_STAPLE_TOP_RIGHT,
+ IPP_FINISHINGS_STAPLE_BOTTOM_RIGHT,
+ IPP_FINISHINGS_EDGE_STITCH_LEFT,
+ IPP_FINISHINGS_EDGE_STITCH_TOP,
+ IPP_FINISHINGS_EDGE_STITCH_RIGHT,
+ IPP_FINISHINGS_EDGE_STITCH_BOTTOM,
+ IPP_FINISHINGS_STAPLE_DUAL_LEFT,
+ IPP_FINISHINGS_STAPLE_DUAL_TOP,
+ IPP_FINISHINGS_STAPLE_DUAL_RIGHT,
+ IPP_FINISHINGS_STAPLE_DUAL_BOTTOM,
+ IPP_FINISHINGS_BIND_LEFT = 50,
+ IPP_FINISHINGS_BIND_TOP,
+ IPP_FINISHINGS_BIND_RIGHT,
+ IPP_FINISHINGS_BIND_BOTTOM
+} 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_CREATE_PRINTER_SUBSCRIPTION,
+ IPP_CREATE_JOB_SUBSCRIPTION,
+ IPP_GET_SUBSCRIPTION_ATTRIBUTES,
+ IPP_GET_SUBSCRIPTIONS,
+ IPP_RENEW_SUBSCRIPTION,
+ IPP_CANCEL_SUBSCRIPTION,
+ IPP_GET_NOTIFICATIONS,
+ IPP_SEND_NOTIFICATIONS,
+ IPP_GET_PRINT_SUPPORT_FILES = 0x0021,
+ IPP_ENABLE_PRINTER,
+ IPP_DISABLE_PRINTER,
+ IPP_PAUSE_PRINTER_AFTER_CURRENT_JOB,
+ IPP_HOLD_NEW_JOBS,
+ IPP_RELEASE_HELD_NEW_JOBS,
+ IPP_DEACTIVATE_PRINTER,
+ IPP_ACTIVATE_PRINTER,
+ IPP_RESTART_PRINTER,
+ IPP_SHUTDOWN_PRINTER,
+ IPP_STARTUP_PRINTER,
+ IPP_REPROCESS_JOB,
+ IPP_CANCEL_CURRENT_JOB,
+ IPP_SUSPEND_CURRENT_JOB,
+ IPP_RESUME_JOB,
+ IPP_PROMOTE_JOB,
+ IPP_SCHEDULE_JOB_AFTER,
+ 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,
+ CUPS_MOVE_JOB,
+ CUPS_ADD_DEVICE,
+ CUPS_DELETE_DEVICE
+} ipp_op_t;
+
+typedef enum /**** IPP status codes... ****/
+{
+ IPP_OK = 0x0000,
+ IPP_OK_SUBST,
+ IPP_OK_CONFLICT,
+ IPP_OK_IGNORED_SUBSCRIPTIONS,
+ IPP_OK_IGNORED_NOTIFICATIONS,
+ IPP_OK_TOO_MANY_EVENTS,
+ IPP_OK_BUT_CANCEL_SUBSCRIPTION,
+ IPP_REDIRECTION_OTHER_SITE = 0x300,
+ 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_COMPRESSION_NOT_SUPPORTED,
+ IPP_COMPRESSION_ERROR,
+ IPP_DOCUMENT_FORMAT_ERROR,
+ IPP_DOCUMENT_ACCESS_ERROR,
+ IPP_ATTRIBUTES_NOT_SETTABLE,
+ IPP_IGNORED_ALL_SUBSCRIPTIONS,
+ IPP_TOO_MANY_SUBSCRIPTIONS,
+ IPP_IGNORED_ALL_NOTIFICATIONS,
+ IPP_PRINT_SUPPORT_FILE_NOT_FOUND,
+
+ IPP_INTERNAL_ERROR = 0x0500,
+ IPP_OPERATION_NOT_SUPPORTED,
+ IPP_SERVICE_UNAVAILABLE,
+ IPP_VERSION_NOT_SUPPORTED,
+ IPP_DEVICE_ERROR,
+ IPP_TEMPORARY_ERROR,
+ IPP_NOT_ACCEPTING,
+ IPP_PRINTER_BUSY,
+ IPP_ERROR_JOB_CANCELLED,
+ IPP_MULTIPLE_JOBS_NOT_SUPPORTED,
+ IPP_PRINTER_IS_DEACTIVATED
+} 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 attribute 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 ipp_attribute_t *ippFindNextAttribute(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 void ippSetPort(int p);
+
+extern ipp_attribute_t *_ipp_add_attr(ipp_t *, int);
+extern void _ipp_free_attr(ipp_attribute_t *);
+
+
+/*
+ * 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 000000000..ab4dec692
--- /dev/null
+++ b/cups/language.c
@@ -0,0 +1,430 @@
+/*
+ * "$Id$"
+ *
+ * I18N/language support for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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 <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#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",
+ "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",
+ "utf-8",
+ "iso-8859-13",
+ "iso-8859-14",
+ "iso-8859-15",
+ "windows-874",
+ "windows-1250",
+ "windows-1251",
+ "windows-1252",
+ "windows-1253",
+ "windows-1254",
+ "windows-1255",
+ "windows-1256",
+ "windows-1257",
+ "windows-1258",
+ "koi8-r",
+ "koi8-u"
+ };
+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[32], /* Requested language name */
+ real[32], /* Real language name */
+ *realptr, /* Pointer into real language name */
+ filename[1024], /* Filename for language locale file */
+ *localedir; /* Directory for locale files */
+ FILE *fp; /* Language locale file pointer */
+ char line[1024]; /* Line from file */
+ cups_msg_t msg; /* Message number */
+ char *text; /* Message text */
+ cups_lang_t *lang; /* Current language... */
+
+
+ /*
+ * Convert the language string passed in to a locale string. "C" is the
+ * standard POSIX locale and is copied unchanged. Otherwise the
+ * language string is converted from ll-cc (language-country) to ll_cc
+ * to match the file naming convention used by all POSIX-compliant
+ * operating systems.
+ */
+
+ if (language == NULL || language[0] == '\0' ||
+ strcmp(language, "POSIX") == 0)
+ strcpy(langname, "C");
+ else
+ {
+ /*
+ * Copy the locale string over safely...
+ */
+
+ strncpy(langname, language, sizeof(langname) - 1);
+ langname[sizeof(langname) - 1] = '\0';
+ }
+
+ if (strlen(langname) < 2)
+ strcpy(real, "C");
+ else
+ {
+ /*
+ * Convert the language name to a normalized form, e.g.:
+ *
+ * ll[_CC[.charset]]
+ */
+
+ real[0] = tolower(langname[0]);
+ real[1] = tolower(langname[1]);
+
+ count = 2;
+
+ if (langname[count] == '_' || langname[count] == '-')
+ {
+ /*
+ * Add country code...
+ */
+
+ real[count] = '_';
+ real[count + 1] = toupper(langname[count + 1]);
+ real[count + 2] = toupper(langname[count + 2]);
+
+ count += 3;
+ }
+
+ if (langname[count] == '.')
+ {
+ /*
+ * Add charset...
+ */
+
+ strncpy(real + count, langname + count, sizeof(real) - count - 1);
+ langname[count] = '\0';
+ count += strlen(langname + count);
+
+ /*
+ * Make sure count stays within the bounds of langname and real
+ * (both vars are the same size...)
+ */
+
+ if (count >= sizeof(real))
+ count = sizeof(real) - 1;
+ }
+
+ langname[count] = '\0';
+ real[count] = '\0';
+ }
+
+ /*
+ * 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 ++;
+
+ return (lang);
+ }
+
+
+ /*
+ * Next try to open a locale file; we will try the charset-localized
+ * file first, then the country-localized file, and finally look for
+ * a generic language file. If all else fails we will use the POSIX
+ * locale.
+ */
+
+ if ((localedir = getenv("LOCALEDIR")) == NULL)
+ localedir = CUPS_LOCALEDIR;
+
+ do
+ {
+ snprintf(filename, sizeof(filename), "%s/%s/cups_%s", localedir,
+ real, real);
+
+ if ((fp = fopen(filename, "r")) == NULL)
+ {
+ if ((realptr = strchr(real, '.')) != NULL)
+ *realptr = '\0';
+ else if ((realptr = strchr(real, '_')) != NULL)
+ *realptr = '\0';
+ }
+ }
+ while (fp == NULL && strchr(real, '_') != NULL && strchr(real, '.') != NULL);
+
+ /*
+ * 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)
+ {
+ strncpy(line, lang_default[0], sizeof(line) - 1);
+ line[sizeof(line) - 1] = '\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 ++;
+ strncpy(lang->language, langname, sizeof(lang->language) - 1);
+ lang->language[sizeof(lang->language) - 1] = '\0';
+
+ 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;
+
+ strncpy(line, lang_default[count], sizeof(line) - 1);
+ /* Already set last byte to 0 above... */
+ }
+ 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 000000000..4f6714827
--- /dev/null
+++ b/cups/language.h
@@ -0,0 +1,224 @@
+/*
+ * "$Id$"
+ *
+ * Multi-language support for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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 <locale.h>
+
+# 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_ISO8859_13,
+ CUPS_ISO8859_14,
+ CUPS_ISO8859_15,
+ CUPS_WINDOWS_874,
+ CUPS_WINDOWS_1250,
+ CUPS_WINDOWS_1251,
+ CUPS_WINDOWS_1252,
+ CUPS_WINDOWS_1253,
+ CUPS_WINDOWS_1254,
+ CUPS_WINDOWS_1255,
+ CUPS_WINDOWS_1256,
+ CUPS_WINDOWS_1257,
+ CUPS_WINDOWS_1258,
+ CUPS_KOI8_R,
+ CUPS_KOI8_U
+} 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...
+ */
+
+# if defined(WIN32) || defined(__EMX__)
+# define cupsLangDefault() cupsLangGet(setlocale(LC_ALL, ""))
+# else
+# define cupsLangDefault() cupsLangGet(setlocale(LC_MESSAGES, ""))
+# endif /* WIN32 || __EMX__ */
+
+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 000000000..296260d26
--- /dev/null
+++ b/cups/mark.c
@@ -0,0 +1,441 @@
+/*
+ * "$Id$"
+ *
+ * Option marking routines for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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"
+#include "debug.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 ||
+ strcasecmp(c1->choice, "Off") == 0 ||
+ strcasecmp(c1->choice, "False") == 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 ||
+ strcasecmp(c2->choice, "Off") == 0 ||
+ strcasecmp(c2->choice, "False") == 0)
+ c2 = NULL;
+ }
+
+ /*
+ * If both options are marked then there is a conflict...
+ */
+
+ if (c1 != NULL && c1->marked &&
+ c2 != NULL && c2->marked)
+ {
+ DEBUG_printf(("%s->%s conflicts with %s->%s (%s %s %s %s)\n",
+ o1->keyword, c1->choice, o2->keyword, c2->choice,
+ c->option1, c->choice1, c->option2, c->choice2));
+ 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 000000000..5db868858
--- /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
+ <ghost@aladdin.com>. 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 <math.h>
+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 000000000..a2d7b3415
--- /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
+ <ghost@aladdin.com>. 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 <purschke@bnl.gov>.
+ 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/md5passwd.c b/cups/md5passwd.c
new file mode 100644
index 000000000..732eb5b6b
--- /dev/null
+++ b/cups/md5passwd.c
@@ -0,0 +1,148 @@
+/*
+ * "$Id$"
+ *
+ * MD5 password support for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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:
+ *
+ * httpMD5() - Compute the MD5 sum of the username:group:password.
+ * httpMD5Nonce() - Combine the MD5 sum of the username, group, and password
+ * with the server-supplied nonce value.
+ * httpMD5String() - Convert an MD5 sum to a character string.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "http.h"
+#include "string.h"
+
+
+/*
+ * 'httpMD5()' - Compute the MD5 sum of the username:group:password.
+ */
+
+char * /* O - MD5 sum */
+httpMD5(const char *username, /* I - User name */
+ const char *realm, /* I - Realm name */
+ const char *passwd, /* I - Password string */
+ char md5[33]) /* O - MD5 string */
+{
+ md5_state_t state; /* MD5 state info */
+ md5_byte_t sum[16]; /* Sum data */
+ char line[256]; /* Line to sum */
+
+
+ /*
+ * Compute the MD5 sum of the user name, group name, and password.
+ */
+
+ snprintf(line, sizeof(line), "%s:%s:%s", username, realm, passwd);
+ md5_init(&state);
+ md5_append(&state, (md5_byte_t *)line, strlen(line));
+ md5_finish(&state, sum);
+
+ /*
+ * Return the sum...
+ */
+
+ return (httpMD5String(sum, md5));
+}
+
+
+/*
+ * 'httpMD5Final()' - Combine the MD5 sum of the username, group, and password
+ * with the server-supplied nonce value, method, and
+ * request-uri.
+ */
+
+char * /* O - New sum */
+httpMD5Final(const char *nonce, /* I - Server nonce value */
+ const char *method, /* I - METHOD (GET, POST, etc.) */
+ const char *resource, /* I - Resource path */
+ char md5[33]) /* IO - MD5 sum */
+{
+ md5_state_t state; /* MD5 state info */
+ md5_byte_t sum[16]; /* Sum data */
+ char line[1024]; /* Line of data */
+ char a2[33]; /* Hash of method and resource */
+
+
+ /*
+ * First compute the MD5 sum of the method and resource...
+ */
+
+ snprintf(line, sizeof(line), "%s:%s", method, resource);
+ md5_init(&state);
+ md5_append(&state, (md5_byte_t *)line, strlen(line));
+ md5_finish(&state, sum);
+ httpMD5String(sum, a2);
+
+ /*
+ * Then combine A1 (MD5 of username, realm, and password) with the nonce
+ * and A2 (method + resource) values to get the final MD5 sum for the
+ * request...
+ */
+
+ snprintf(line, sizeof(line), "%s:%s:%s", md5, nonce, a2);
+
+ md5_init(&state);
+ md5_append(&state, (md5_byte_t *)line, strlen(line));
+ md5_finish(&state, sum);
+
+ return (httpMD5String(sum, md5));
+}
+
+
+/*
+ * 'httpMD5String()' - Convert an MD5 sum to a character string.
+ */
+
+char * /* O - MD5 sum in hex */
+httpMD5String(const md5_byte_t *sum, /* I - MD5 sum data */
+ char md5[33]) /* O - MD5 sum in hex */
+{
+ int i; /* Looping var */
+ char *md5ptr; /* Pointer into MD5 string */
+ static char *hex = "0123456789abcdef";
+ /* Hex digits */
+
+
+ /*
+ * Convert the MD5 sum to hexadecimal...
+ */
+
+ for (i = 16, md5ptr = md5; i > 0; i --, sum ++)
+ {
+ *md5ptr++ = hex[*sum >> 4];
+ *md5ptr++ = hex[*sum & 15];
+ }
+
+ *md5ptr = '\0';
+
+ return (md5);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/options.c b/cups/options.c
new file mode 100644
index 000000000..985620075
--- /dev/null
+++ b/cups/options.c
@@ -0,0 +1,430 @@
+/*
+ * "$Id$"
+ *
+ * Option routines for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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 <stdlib.h>
+#include <ctype.h>
+#include "string.h"
+#include "debug.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 || !name[0] || value == NULL ||
+ options == NULL || num_options < 0)
+ return (num_options);
+
+ /*
+ * 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 || num_options < 0)
+ return (0);
+
+ /*
+ * Make a copy of the argument string and then divide it up...
+ */
+
+ copyarg = strdup(arg);
+ ptr = copyarg;
+
+ /*
+ * Skip leading spaces...
+ */
+
+ while (isspace(*ptr))
+ ptr ++;
+
+ /*
+ * Loop through the string...
+ */
+
+ while (*ptr != '\0')
+ {
+ /*
+ * Get the name up to a SPACE, =, or end-of-string...
+ */
+
+ name = ptr;
+ while (!isspace(*ptr) && *ptr != '=' && *ptr != '\0')
+ ptr ++;
+
+ /*
+ * Avoid an empty name...
+ */
+
+ if (ptr == name)
+ break;
+
+ /*
+ * Skip trailing spaces...
+ */
+
+ while (isspace(*ptr))
+ *ptr++ = '\0';
+
+ if (*ptr != '=')
+ {
+ /*
+ * Start of another option...
+ */
+
+ if (strncasecmp(name, "no", 2) == 0)
+ num_options = cupsAddOption(name + 2, "false", num_options,
+ options);
+ else
+ num_options = cupsAddOption(name, "true", 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 ++;
+ }
+
+ /*
+ * Skip trailing whitespace...
+ */
+
+ 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 */
+
+
+ /*
+ * Check arguments...
+ */
+
+ if (ppd == NULL || num_options <= 0 || options == NULL)
+ return (0);
+
+ /*
+ * Mark options...
+ */
+
+ 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, "JCLDuplex", "None")) /* Samsung */
+ 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, "JCLDuplex", "DuplexNoTumble")) /* Samsung */
+ 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, "JCLDuplex", "DuplexTumble")) /* Samsung */
+ 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 (strcasecmp(options->name, "output-bin") == 0)
+ {
+ if (ppdMarkOption(ppd, "OutputBin", options->value))
+ 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 000000000..16cc03c15
--- /dev/null
+++ b/cups/page.c
@@ -0,0 +1,189 @@
+/*
+ * "$Id$"
+ *
+ * Page size functions for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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 <ctype.h>
+
+
+/*
+ * '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 000000000..b14c42987
--- /dev/null
+++ b/cups/ppd.c
@@ -0,0 +1,2006 @@
+/*
+ * "$Id$"
+ *
+ * PPD file routines for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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 <stdlib.h>
+#include <ctype.h>
+#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 */
+ char **filter; /* Current filter */
+
+
+ /*
+ * Range check the PPD file record...
+ */
+
+ if (ppd == NULL)
+ return;
+
+ /*
+ * Free all strings at the top level...
+ */
+
+ safe_free(ppd->patches);
+ safe_free(ppd->jcl_begin);
+ safe_free(ppd->jcl_ps);
+ safe_free(ppd->jcl_end);
+ 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 filters...
+ */
+
+ if (ppd->num_filters > 0)
+ {
+ for (i = ppd->num_filters, filter = ppd->filters; i > 0; i --, filter ++)
+ safe_free(*filter);
+
+ safe_free(ppd->filters);
+ }
+
+ /*
+ * 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 */
+
+
+ DEBUG_printf(("ppd_get_group(%p, \"%s\")\n", ppd, name));
+
+ for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
+ if (strcmp(group->text, name) == 0)
+ break;
+
+ if (i == 0)
+ {
+ DEBUG_printf(("Adding group %s...\n", name));
+
+ 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[PPD_MAX_NAME],
+ /* Keyword from file */
+ name[PPD_MAX_NAME],
+ /* Option from file */
+ text[PPD_MAX_TEXT],
+ /* Human-readable text from file */
+ *string, /* Code/text from file */
+ *sptr, /* Pointer into string */
+ *nameptr, /* Pointer into name */
+ *temp, /* Temporary string pointer */
+ **tempfonts; /* Temporary fonts pointer */
+ 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, "CloseUI") != 0 &&
+ strcmp(keyword, "JCLCloseUI") != 0 &&
+ strcmp(keyword, "CloseGroup") != 0 &&
+ strcmp(keyword, "CloseSubGroup") != 0 &&
+ strncmp(keyword, "Default", 7) != 0 &&
+ string == NULL)
+ {
+ /*
+ * Need a string value!
+ */
+
+ ppdClose(ppd);
+ return (NULL);
+ }
+
+ 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, "cupsFlipDuplex") == 0)
+ ppd->flip_duplex = strcmp(string, "True") == 0;
+ 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));
+
+ if (filter == NULL)
+ {
+ safe_free(filter);
+ ppdClose(ppd);
+ return (NULL);
+ }
+
+ 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, "Font") == 0)
+ {
+ /*
+ * Add this font to the list of available fonts...
+ */
+
+ if (ppd->num_fonts == 0)
+ tempfonts = (char **)malloc(sizeof(char *));
+ else
+ tempfonts = (char **)realloc(ppd->fonts,
+ sizeof(char *) * (ppd->num_fonts + 1));
+
+ if (tempfonts == NULL)
+ {
+ safe_free(string);
+ ppdClose(ppd);
+ return (NULL);
+ }
+
+ ppd->fonts = tempfonts;
+ ppd->fonts[ppd->num_fonts] = strdup(name);
+ ppd->num_fonts ++;
+ }
+ 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 ((option = ppdFindOption(ppd, "PageSize")) == NULL)
+ {
+ ppd_group_t *temp;
+
+
+ if ((temp = ppd_get_group(ppd,
+ cupsLangString(language,
+ CUPS_MSG_GENERAL))) == NULL)
+ {
+ ppdClose(ppd);
+ safe_free(string);
+ return (NULL);
+ }
+
+ if ((option = ppd_get_option(temp, "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);
+ 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 ((option = ppdFindOption(ppd, "PageSize")) == NULL)
+ {
+ ppd_group_t *temp;
+
+
+ if ((temp = ppd_get_group(ppd,
+ cupsLangString(language,
+ CUPS_MSG_GENERAL))) == NULL)
+ {
+ DEBUG_puts("Unable to get general group!");
+ ppdClose(ppd);
+ safe_free(string);
+ return (NULL);
+ }
+
+ if ((option = ppd_get_option(temp, "PageSize")) == NULL)
+ {
+ DEBUG_puts("Unable to get PageSize option!");
+ ppdClose(ppd);
+ safe_free(string);
+ return (NULL);
+ }
+ }
+
+ if ((choice = ppd_add_choice(option, "Custom")) == NULL)
+ {
+ DEBUG_puts("Unable to add Custom choice!");
+ ppdClose(ppd);
+ safe_free(string);
+ return (NULL);
+ }
+
+ strncpy(choice->text, cupsLangString(language, CUPS_MSG_VARIABLE),
+ sizeof(choice->text) - 1);
+ option = NULL;
+ }
+
+ if ((option = ppdFindOption(ppd, "PageSize")) == NULL)
+ {
+ DEBUG_puts("Unable to find PageSize option!");
+ ppdClose(ppd);
+ safe_free(string);
+ return (NULL);
+ }
+
+ if ((choice = ppdFindChoice(option, "Custom")) == NULL)
+ {
+ DEBUG_puts("Unable to find Custom choice!");
+ 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 != ' ';
+ sptr ++)
+ if (nameptr < (ppd->emulations[i].name + sizeof(ppd->emulations[i].name) - 1))
+ *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
+ {
+ temp = realloc(ppd->patches, strlen(ppd->patches) +
+ strlen(string) + 1);
+ if (temp == NULL)
+ {
+ safe_free(string);
+ ppdClose(ppd);
+ return (NULL);
+ }
+
+ ppd->patches = temp;
+
+ 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); /* Eliminate leading asterisk */
+
+ for (i = strlen(name) - 1; i > 0 && isspace(name[i]); i --)
+ name[i] = '\0'; /* Eliminate trailing spaces */
+
+ DEBUG_printf(("OpenUI of %s in group %s...\n", name,
+ group ? group->text : "(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);
+ }
+
+ DEBUG_printf(("Adding to group %s...\n", group->text));
+ 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, "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)
+ {
+ ppd_group_t *temp;
+
+
+ /*
+ * Only valid for Non-UI options...
+ */
+
+ for (i = ppd->num_groups, temp = ppd->groups; i > 0; i --, temp ++)
+ if (temp->text[0] == '\0')
+ break;
+
+ if (i > 0)
+ for (i = 0; i < temp->num_options; i ++)
+ if (strcmp(keyword, temp->options[i].keyword) == 0)
+ {
+ temp->options[i].section = section;
+ temp->options[i].order = order;
+ break;
+ }
+ }
+ 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)
+ {
+ ppd_group_t *temp;
+
+
+ /*
+ * Only valid for Non-UI options...
+ */
+
+ for (i = ppd->num_groups, temp = ppd->groups; i > 0; i --, temp ++)
+ if (temp->text[0] == '\0')
+ break;
+
+ if (i > 0)
+ for (i = 0; i < temp->num_options; i ++)
+ if (strcmp(keyword, temp->options[i].keyword) == 0)
+ {
+ strncpy(temp->options[i].defchoice, string,
+ sizeof(temp->options[i].defchoice) - 1);
+ break;
+ }
+ }
+ 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... */
+ /*
+ * The following strcpy's are safe, as optionN and
+ * choiceN are all the same size (size defined by PPD spec...)
+ */
+
+ 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... */
+ /*
+ * The following strcpy's are safe, as optionN and
+ * choiceN are all the same size (size defined by PPD spec...)
+ */
+
+ 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)
+ size = ppd_add_size(ppd, name);
+
+ if (size == NULL)
+ {
+ /*
+ * Unable to add or find size!
+ */
+
+ ppdClose(ppd);
+ safe_free(string);
+ return (NULL);
+ }
+
+ sscanf(string, "%f%f", &(size->width), &(size->length));
+ }
+ else if (strcmp(keyword, "ImageableArea") == 0)
+ {
+ if ((size = ppdPageSize(ppd, name)) == NULL)
+ size = ppd_add_size(ppd, name);
+
+ if (size == NULL)
+ {
+ /*
+ * Unable to add or find size!
+ */
+
+ ppdClose(ppd);
+ safe_free(string);
+ return (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))
+ {
+ DEBUG_printf(("group = %p, subgroup = %p\n", group, subgroup));
+
+ if (strcmp(keyword, "PageSize") == 0)
+ {
+ /*
+ * Add a page size...
+ */
+
+ if (ppdPageSize(ppd, name) == NULL)
+ 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.
+ */
+
+static 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 */
+ colon, /* Colon seen? */
+ 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[65536]; /* Line buffer (64k) */
+
+
+ /*
+ * Range check everything...
+ */
+
+ if (fp == NULL || keyword == NULL || option == NULL || text == NULL ||
+ string == NULL)
+ return (0);
+
+ /*
+ * Now loop until we have a valid line...
+ */
+
+ *string = NULL;
+
+ do
+ {
+ /*
+ * Read the line...
+ */
+
+ lineptr = line;
+ endquote = 0;
+ colon = 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);
+ }
+
+ ch = '\n';
+
+ if (!endquote) /* Continue for multi-line text */
+ break;
+
+ *lineptr++ = '\n';
+ }
+ else
+ {
+ /*
+ * Any other character...
+ */
+
+ *lineptr++ = ch;
+
+ if (ch == ':')
+ colon = 1;
+
+ if (ch == '\"' && colon)
+ {
+ endquote = !endquote;
+
+ if (!endquote)
+ {
+ /*
+ * End of quoted string; ignore trailing characters...
+ */
+
+ while ((ch = getc(fp)) != EOF)
+ if (ch == '\n')
+ break;
+ else if (ch == '\r')
+ {
+ ch = getc(fp);
+ if (ch != '\n')
+ ungetc(ch, fp);
+ break;
+ }
+
+ break;
+ }
+ }
+ }
+ }
+
+ if (endquote)
+ {
+ /*
+ * Didn't finish this quoted string...
+ */
+
+ while ((ch = getc(fp)) != EOF)
+ if (ch == '\"')
+ break;
+ }
+
+ if (ch != '\n')
+ {
+ /*
+ * Didn't finish this line...
+ */
+
+ while ((ch = getc(fp)) != EOF)
+ if (ch == '\r' || ch == '\n')
+ {
+ /*
+ * Line feed or carriage return...
+ */
+
+ if (ch == '\r')
+ {
+ /*
+ * Check for a trailing line feed...
+ */
+
+ if ((ch = getc(fp)) == EOF)
+ break;
+ if (ch != 0x0a)
+ ungetc(ch, fp);
+ }
+
+ break;
+ }
+ }
+
+ if (lineptr > line && lineptr[-1] == '\n')
+ lineptr --;
+
+ *lineptr = '\0';
+
+/* DEBUG_printf(("LINE = \"%s\"\n", line));*/
+
+ 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 (strcmp(line, "*") == 0 || /* (Bad) comment line */
+ 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) < (PPD_MAX_NAME - 1))
+ *keyptr++ = *lineptr++;
+
+ *keyptr = '\0';
+
+ if (strcmp(keyword, "End") == 0)
+ continue;
+
+ mask |= PPD_KEYWORD;
+
+/* DEBUG_printf(("keyword = \"%s\", lineptr = \"%s\"\n", keyword, lineptr));*/
+
+ if (isspace(*lineptr))
+ {
+ /*
+ * Get an option name...
+ */
+
+ while (isspace(*lineptr))
+ lineptr ++;
+
+ optptr = option;
+
+ while (*lineptr != '\0' && *lineptr != '\n' && *lineptr != ':' &&
+ *lineptr != '/' && (optptr - option) < 40)
+ *optptr++ = *lineptr++;
+
+ *optptr = '\0';
+ mask |= PPD_OPTION;
+
+/* DEBUG_printf(("option = \"%s\", lineptr = \"%s\"\n", option, lineptr));*/
+
+ if (*lineptr == '/')
+ {
+ /*
+ * Get human-readable text...
+ */
+
+ lineptr ++;
+
+ textptr = text;
+
+ while (*lineptr != '\0' && *lineptr != '\n' && *lineptr != ':' &&
+ (textptr - text) < (PPD_MAX_TEXT - 1))
+ *textptr++ = *lineptr++;
+
+ *textptr = '\0';
+ ppd_decode(text);
+
+ mask |= PPD_TEXT;
+ }
+
+/* DEBUG_printf(("text = \"%s\", lineptr = \"%s\"\n", text, lineptr));*/
+ }
+
+ 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';
+
+/* DEBUG_printf(("string = \"%s\", lineptr = \"%s\"\n", *string, lineptr));*/
+
+ 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 000000000..dec827878
--- /dev/null
+++ b/cups/ppd.h
@@ -0,0 +1,268 @@
+/*
+ * "$Id$"
+ *
+ * PostScript Printer Description definitions for the Common UNIX Printing
+ * System (CUPS).
+ *
+ * Copyright 1997-2002 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 <stdio.h>
+
+
+/*
+ * C++ magic...
+ */
+
+# ifdef __cplusplus
+extern "C" {
+# endif /* __cplusplus */
+
+
+/*
+ * PPD version...
+ */
+
+# define PPD_VERSION 4.3 /* Kept in sync with Adobe version number */
+
+
+/*
+ * PPD size limits (defined in Adobe spec)
+ */
+
+# define PPD_MAX_NAME 41 /* Maximum size of name + 1 for nul */
+# define PPD_MAX_TEXT 81 /* Maximum size of text + 1 for nul */
+# define PPD_MAX_LINE 256 /* Maximum size of line + 1 for nul */
+
+
+/*
+ * 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[PPD_MAX_NAME],
+ /* Computer-readable option name */
+ text[PPD_MAX_TEXT],
+ /* 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[PPD_MAX_NAME],
+ /* Option keyword name ("PageSize", etc.) */
+ defchoice[PPD_MAX_NAME],
+ /* Default option choice */
+ text[PPD_MAX_TEXT];
+ /* 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[PPD_MAX_TEXT];
+ /* 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[PPD_MAX_NAME],
+ /* First keyword */
+ choice1[PPD_MAX_NAME],
+ /* First option/choice (blank for all) */
+ option2[PPD_MAX_NAME],
+ /* Second keyword */
+ choice2[PPD_MAX_NAME];
+ /* Second option/choice (blank for all) */
+} ppd_const_t;
+
+typedef struct /**** Page Sizes ****/
+{
+ int marked; /* Page size selected? */
+ char name[PPD_MAX_NAME];
+ /* 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[PPD_MAX_NAME],
+ /* 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[PPD_MAX_NAME],
+ /* Resolution or "-" */
+ media_type[PPD_MAX_NAME];
+ /* 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... */
+ int flip_duplex; /* 1 = Flip page for back sides */
+} ppd_file_t;
+
+
+/*
+ * Prototypes...
+ */
+
+extern void ppdClose(ppd_file_t *ppd);
+extern int ppdCollect(ppd_file_t *ppd, ppd_section_t section,
+ ppd_choice_t ***choices);
+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 ppdEmitJCL(ppd_file_t *ppd, FILE *fp, int job_id,
+ const char *user, const char *title);
+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 000000000..32fb6041c
--- /dev/null
+++ b/cups/snprintf.c
@@ -0,0 +1,287 @@
+/*
+ * "$Id$"
+ *
+ * snprintf functions for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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 <stdio.h>
+#include <ctype.h>
+#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 000000000..d3e0dc42f
--- /dev/null
+++ b/cups/string.c
@@ -0,0 +1,125 @@
+/*
+ * "$Id$"
+ *
+ * String functions for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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 000000000..1f29f6874
--- /dev/null
+++ b/cups/string.h
@@ -0,0 +1,103 @@
+/*
+ * "$Id$"
+ *
+ * String definitions for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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 <config.h>
+
+# include <stdio.h>
+# include <stdarg.h>
+# include <ctype.h>
+
+# ifdef HAVE_STRING_H
+# include <string.h>
+# endif /* HAVE_STRING_H */
+
+# ifdef HAVE_STRINGS_H
+# include <strings.h>
+# endif /* HAVE_STRINGS_H */
+
+
+/*
+ * 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/tempfile.c b/cups/tempfile.c
new file mode 100644
index 000000000..ddfca917d
--- /dev/null
+++ b/cups/tempfile.c
@@ -0,0 +1,200 @@
+/*
+ * "$Id$"
+ *
+ * Temp file utilities for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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:
+ *
+ * cupsTempFd() - Create a temporary file.
+ * cupsTempFile() - Generate a temporary filename.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cups.h"
+#include "string.h"
+#include "debug.h"
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#if defined(WIN32) || defined(__EMX__)
+# include <io.h>
+#else
+# include <unistd.h>
+#endif /* WIN32 || __EMX__ */
+
+
+/*
+ * 'cupsTempFd()' - Create a temporary file.
+ */
+
+int /* O - New file descriptor */
+cupsTempFd(char *filename, /* I - Pointer to buffer */
+ int len) /* I - Size of buffer */
+{
+ int fd; /* File descriptor for temp file */
+#ifdef WIN32
+ char tmpdir[1024]; /* Windows temporary directory */
+ DWORD curtime; /* Current time */
+#else
+ char *tmpdir; /* TMPDIR environment var */
+ struct timeval curtime; /* Current time */
+#endif /* WIN32 */
+ 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...
+ */
+
+#ifdef WIN32
+ GetTempPath(sizeof(tmpdir), tmpdir);
+#else
+ if ((tmpdir = getenv("TMPDIR")) == NULL)
+ {
+ /*
+ * Put root temp files in restricted temp directory...
+ */
+
+ if (getuid() == 0)
+ tmpdir = CUPS_REQUESTS "/tmp";
+ else
+ tmpdir = "/var/tmp";
+ }
+#endif /* WIN32 */
+
+ /*
+ * Make the temporary name using the specified directory...
+ */
+
+ do
+ {
+#ifdef WIN32
+ /*
+ * Get the current time of day...
+ */
+
+ curtime = GetTickCount();
+
+ /*
+ * Format a string using the hex time values...
+ */
+
+ snprintf(filename, len - 1, "%s/%08lx", tmpdir, curtime);
+#else
+ /*
+ * Get the current time of day...
+ */
+
+ gettimeofday(&curtime, NULL);
+
+ /*
+ * Format a string using the hex time values...
+ */
+
+ snprintf(filename, len - 1, "%s/%08lx%05lx", tmpdir,
+ curtime.tv_sec, curtime.tv_usec);
+#endif /* WIN32 */
+
+ /*
+ * Open the file in "exclusive" mode, making sure that we don't
+ * stomp on an existing file or someone's symlink crack...
+ */
+
+#ifdef O_NOFOLLOW
+ fd = open(filename, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, 0600);
+#else
+ fd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
+#endif /* O_NOFOLLOW */
+
+ if (fd < 0 && (errno == EPERM || errno == ENOENT))
+ break; /* Stop immediately if permission denied or the dir doesn't exist! */
+ }
+ while (fd < 0);
+
+ /*
+ * Return the file descriptor...
+ */
+
+ return (fd);
+}
+
+
+/*
+ * 'cupsTempFile()' - Generate a temporary filename.
+ */
+
+char * /* O - Filename */
+cupsTempFile(char *filename, /* I - Pointer to buffer */
+ int len) /* I - Size of buffer */
+{
+ int fd; /* File descriptor for temp file */
+ 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);
+ }
+
+ /*
+ * Create the temporary file...
+ */
+
+ if ((fd = cupsTempFd(filename, len)) < 0)
+ return (NULL);
+
+ /*
+ * Close the temp file - it'll be reopened later as needed...
+ */
+
+ close(fd);
+
+ /*
+ * Return the temp filename...
+ */
+
+ return (filename);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/testhttp.c b/cups/testhttp.c
new file mode 100644
index 000000000..1125f43b6
--- /dev/null
+++ b/cups/testhttp.c
@@ -0,0 +1,124 @@
+/*
+ * "$Id$"
+ *
+ * HTTP test program for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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 <stdio.h>
+#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[8192]; /* Input buffer */
+ long bytes; /* Number of bytes read */
+ FILE *out; /* Output file */
+ char host[HTTP_MAX_URI],
+ method[HTTP_MAX_URI],
+ username[HTTP_MAX_URI],
+ resource[HTTP_MAX_URI];
+ int port;
+ long length, total;
+ time_t start, current;
+
+
+
+ http = NULL;
+ out = stdout;
+
+ for (i = 1; i < argc; i ++)
+ {
+ if (strcmp(argv[i], "-o") == 0)
+ {
+ i ++;
+ out = fopen(argv[i], "wb");
+ continue;
+ }
+
+ httpSeparate(argv[i], method, username, host, &port, resource);
+
+ http = httpConnect(host, port);
+ if (http == NULL)
+ {
+ perror(host);
+ continue;
+ }
+ printf("Requesting file \"%s\"...\n", resource);
+ httpClearFields(http);
+ httpSetField(http, HTTP_FIELD_ACCEPT_LANGUAGE, "en");
+ httpGet(http, resource);
+ while ((status = httpUpdate(http)) == HTTP_CONTINUE);
+
+ if (status == HTTP_OK)
+ puts("GET OK:");
+ else
+ printf("GET failed with status %d...\n", status);
+
+
+ start = time(NULL);
+ length = atoi(httpGetField(http, HTTP_FIELD_CONTENT_LENGTH));
+ total = 0;
+
+ while ((bytes = httpRead(http, buffer, sizeof(buffer))) > 0)
+ {
+ total += bytes;
+ fwrite(buffer, bytes, 1, out);
+ if (out != stdout)
+ {
+ current = time(NULL);
+ if (current == start) current ++;
+ printf("\r%ld/%ld bytes (%ld bytes/sec) ", total, length,
+ total / (current - start));
+ fflush(stdout);
+ }
+ }
+ }
+
+ 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 000000000..33fbd301a
--- /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 000000000..ea430a36b
--- /dev/null
+++ b/cups/testppd.c
@@ -0,0 +1,195 @@
+/*
+ * "$Id$"
+ *
+ * PPD test program for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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 */
+ 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" };
+
+
+ setbuf(stdout, NULL);
+
+ /*
+ * 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 ((ppd = ppdOpenFile(argv[i])) == NULL)
+ {
+ fprintf(stderr, "Unable to open \'%s\' as a PPD file!\n", argv[i]);
+ continue;
+ }
+
+ printf("FILE: %s\n", argv[i]);
+ 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 = <unknown>");
+ 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 : (int)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 (%d choices)\n", k,
+ option->keyword, option->text, uis[option->ui],
+ sections[option->section], option->order,
+ option->num_choices);
+
+ 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');
+ }
+ }
+ }
+ }
+
+ printf(" num_profiles = %d\n", ppd->num_profiles);
+ for (j = 0; j < ppd->num_profiles; j ++)
+ printf(" profiles[%d] = %s/%s %.3f %.3f [ %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f ]\n",
+ j, ppd->profiles[j].resolution, ppd->profiles[j].media_type,
+ ppd->profiles[j].gamma, ppd->profiles[j].density,
+ ppd->profiles[j].matrix[0][0], ppd->profiles[j].matrix[0][1],
+ ppd->profiles[j].matrix[0][2], ppd->profiles[j].matrix[1][0],
+ ppd->profiles[j].matrix[1][1], ppd->profiles[j].matrix[1][2],
+ ppd->profiles[j].matrix[2][0], ppd->profiles[j].matrix[2][1],
+ ppd->profiles[j].matrix[2][2]);
+
+ printf(" num_fonts = %d\n", ppd->num_fonts);
+ for (j = 0; j < ppd->num_fonts; j ++)
+ printf(" fonts[%d] = %s\n", j, ppd->fonts[j]);
+
+ ppdClose(ppd);
+ }
+
+ return (0);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/testppd.dsp b/cups/testppd.dsp
new file mode 100644
index 000000000..27d4f035c
--- /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 000000000..f5735f516
--- /dev/null
+++ b/cups/usersys.c
@@ -0,0 +1,447 @@
+/*
+ * "$Id$"
+ *
+ * User, system, and password routines for the Common UNIX Printing
+ * System (CUPS).
+ *
+ * Copyright 1997-2002 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:
+ *
+ * cupsEncryption() - Get the default encryption settings...
+ * cupsGetPassword() - Get a password from the user...
+ * cupsServer() - Return the hostname of the default server...
+ * cupsSetEncryption() - Set the encryption preference.
+ * cupsSetPasswordCB() - Set the password callback for CUPS.
+ * cupsSetServer() - Set the default server name...
+ * cupsSetUser() - Set the default user name...
+ * cupsUser() - Return the current users name.
+ * cups_get_password() - Get a password from the user...
+ * cups_get_line() - Get a line from a file...
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cups.h"
+#include "string.h"
+#include <stdlib.h>
+#include <ctype.h>
+
+
+/*
+ * Local functions...
+ */
+
+static const char *cups_get_password(const char *prompt);
+static char *cups_get_line(char *buf, int buflen, FILE *fp);
+
+
+/*
+ * Local globals...
+ */
+
+static http_encryption_t cups_encryption = (http_encryption_t)-1;
+static char cups_user[65] = "",
+ cups_server[256] = "";
+static const char *(*cups_pwdcb)(const char *) = cups_get_password;
+
+
+/*
+ * 'cupsEncryption()' - Get the default encryption settings...
+ */
+
+http_encryption_t
+cupsEncryption(void)
+{
+ FILE *fp; /* client.conf file */
+ char *encryption; /* CUPS_ENCRYPTION variable */
+ const char *home; /* Home directory of user */
+ static char line[1024]; /* Line from file */
+
+
+ /*
+ * First see if we have already set the encryption stuff...
+ */
+
+ if (cups_encryption == (http_encryption_t)-1)
+ {
+ /*
+ * Then see if the CUPS_ENCRYPTION environment variable is set...
+ */
+
+ if ((encryption = getenv("CUPS_ENCRYPTION")) == NULL)
+ {
+ /*
+ * Next check to see if we have a $HOME/.cupsrc or client.conf file...
+ */
+
+ if ((home = getenv("HOME")) != NULL)
+ {
+ snprintf(line, sizeof(line), "%s/.cupsrc", home);
+ fp = fopen(line, "r");
+ }
+ else
+ fp = NULL;
+
+ if (fp == NULL)
+ {
+ if ((home = getenv("CUPS_SERVERROOT")) != NULL)
+ {
+ snprintf(line, sizeof(line), "%s/client.conf", home);
+ fp = fopen(line, "r");
+ }
+ else
+ fp = fopen(CUPS_SERVERROOT "/client.conf", "r");
+ }
+
+ encryption = "IfRequested";
+
+ if (fp != NULL)
+ {
+ /*
+ * Read the config file and look for a ServerName line...
+ */
+
+ while (cups_get_line(line, sizeof(line), fp) != NULL)
+ if (strncmp(line, "Encryption ", 11) == 0)
+ {
+ /*
+ * Got it! Drop any trailing newline and find the name...
+ */
+
+ encryption = line + strlen(line) - 1;
+ if (*encryption == '\n')
+ *encryption = '\0';
+
+ for (encryption = line + 11; isspace(*encryption); encryption ++);
+ break;
+ }
+
+ fclose(fp);
+ }
+ }
+
+ /*
+ * Set the encryption preference...
+ */
+
+ if (strcasecmp(encryption, "never") == 0)
+ cups_encryption = HTTP_ENCRYPT_NEVER;
+ else if (strcasecmp(encryption, "always") == 0)
+ cups_encryption = HTTP_ENCRYPT_ALWAYS;
+ else if (strcasecmp(encryption, "required") == 0)
+ cups_encryption = HTTP_ENCRYPT_REQUIRED;
+ else
+ cups_encryption = HTTP_ENCRYPT_IF_REQUESTED;
+ }
+
+ return (cups_encryption);
+}
+
+
+/*
+ * 'cupsGetPassword()' - Get a password from the user...
+ */
+
+const char * /* O - Password */
+cupsGetPassword(const char *prompt) /* I - Prompt string */
+{
+ return ((*cups_pwdcb)(prompt));
+}
+
+
+/*
+ * 'cupsSetEncryption()' - Set the encryption preference.
+ */
+
+void
+cupsSetEncryption(http_encryption_t e) /* I - New encryption preference */
+{
+ cups_encryption = e;
+}
+
+
+/*
+ * '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 */
+ const char *home; /* Home directory of user */
+ static char line[1024]; /* Line from file */
+
+
+ /*
+ * First see if we have already set the server name...
+ */
+
+ if (!cups_server[0])
+ {
+ /*
+ * Then see if the CUPS_SERVER environment variable is set...
+ */
+
+ if ((server = getenv("CUPS_SERVER")) == NULL)
+ {
+ /*
+ * Next check to see if we have a $HOME/.cupsrc or client.conf file...
+ */
+
+ if ((home = getenv("HOME")) != NULL)
+ {
+ snprintf(line, sizeof(line), "%s/.cupsrc", home);
+ fp = fopen(line, "r");
+ }
+ else
+ fp = NULL;
+
+ if (fp == NULL)
+ {
+ if ((home = getenv("CUPS_SERVERROOT")) != NULL)
+ {
+ snprintf(line, sizeof(line), "%s/client.conf", home);
+ fp = fopen(line, "r");
+ }
+ else
+ fp = fopen(CUPS_SERVERROOT "/client.conf", "r");
+ }
+
+ server = "localhost";
+
+ if (fp != NULL)
+ {
+ /*
+ * Read the config file and look for a ServerName line...
+ */
+
+ while (cups_get_line(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 ++);
+ break;
+ }
+
+ fclose(fp);
+ }
+ }
+
+ /*
+ * Copy the server name over...
+ */
+
+ strncpy(cups_server, server, sizeof(cups_server) - 1);
+ cups_server[sizeof(cups_server) - 1] = '\0';
+ }
+
+ return (cups_server);
+}
+
+
+/*
+ * 'cupsSetPasswordCB()' - Set the password callback for CUPS.
+ */
+
+void
+cupsSetPasswordCB(const char *(*cb)(const char *)) /* I - Callback function */
+{
+ if (cb == (const char *(*)(const char *))0)
+ cups_pwdcb = cups_get_password;
+ else
+ cups_pwdcb = cb;
+}
+
+
+/*
+ * 'cupsSetServer()' - Set the default server name...
+ */
+
+void
+cupsSetServer(const char *server) /* I - Server name */
+{
+ if (server)
+ {
+ strncpy(cups_server, server, sizeof(cups_server) - 1);
+ cups_server[sizeof(cups_server) - 1] = '\0';
+ }
+ else
+ cups_server[0] = '\0';
+}
+
+
+/*
+ * 'cupsSetUser()' - Set the default user name...
+ */
+
+void
+cupsSetUser(const char *user) /* I - User name */
+{
+ if (user)
+ {
+ strncpy(cups_user, user, sizeof(cups_user) - 1);
+ cups_user[sizeof(cups_user) - 1] = '\0';
+ }
+ else
+ cups_user[0] = '\0';
+}
+
+
+#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)
+{
+ if (!cups_user[0])
+ strcpy(cups_user, "WindowsUser");
+
+ return (cups_user);
+}
+
+
+/*
+ * 'cups_get_password()' - Get a password from the user...
+ */
+
+static const char * /* O - Password */
+cups_get_password(const char *prompt) /* I - Prompt string */
+{
+ return (NULL);
+}
+#else
+/*
+ * UNIX username and password stuff...
+ */
+
+# include <pwd.h>
+
+/*
+ * 'cupsUser()' - Return the current user's name.
+ */
+
+const char * /* O - User name */
+cupsUser(void)
+{
+ struct passwd *pwd; /* User/password entry */
+
+
+ if (!cups_user[0])
+ {
+ /*
+ * Rewind the password file...
+ */
+
+ setpwent();
+
+ /*
+ * Lookup the password entry for the current user.
+ */
+
+ if ((pwd = getpwuid(getuid())) == NULL)
+ strcpy(cups_user, "unknown"); /* Unknown user! */
+ else
+ {
+ /*
+ * Copy the username...
+ */
+
+ setpwent();
+
+ strncpy(cups_user, pwd->pw_name, sizeof(cups_user) - 1);
+ cups_user[sizeof(cups_user) - 1] = '\0';
+ }
+
+ /*
+ * Rewind the password file again...
+ */
+
+ setpwent();
+ }
+
+ return (cups_user);
+}
+
+
+/*
+ * 'cups_get_password()' - Get a password from the user...
+ */
+
+static const char * /* O - Password */
+cups_get_password(const char *prompt) /* I - Prompt string */
+{
+ return (getpass(prompt));
+}
+#endif /* WIN32 || __EMX__ */
+
+
+/*
+ * 'cups_get_line()' - Get a line from a file.
+ */
+
+static char * /* O - Line from file */
+cups_get_line(char *buf, /* I - Line buffer */
+ int buflen, /* I - Size of line buffer */
+ FILE *fp) /* I - File to read from */
+{
+ char *bufptr; /* Pointer to end of buffer */
+
+
+ /*
+ * Get the line from a file...
+ */
+
+ if (fgets(buf, buflen, fp) == NULL)
+ return (NULL);
+
+ /*
+ * Remove all trailing whitespace...
+ */
+
+ bufptr = buf + strlen(buf) - 1;
+ if (bufptr < buf)
+ return (NULL);
+
+ while (isspace(*bufptr) && bufptr >= buf)
+ *bufptr-- = '\0';
+
+ return (buf);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/util.c b/cups/util.c
new file mode 100644
index 000000000..b29ebce5b
--- /dev/null
+++ b/cups/util.c
@@ -0,0 +1,1741 @@
+/*
+ * "$Id$"
+ *
+ * Printing utilities for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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...
+ * cupsFreeJobs() - Free memory used by job data.
+ * cupsGetClasses() - Get a list of printer classes.
+ * cupsGetDefault() - Get the default printer or class.
+ * cupsGetJobs() - Get the jobs from the server.
+ * cupsGetPPD() - Get the PPD file for a printer.
+ * cupsGetPrinters() - Get a list of printers.
+ * cupsLastError() - Return the last IPP error that occurred.
+ * cupsPrintFile() - Print a file to a printer or class.
+ * cupsPrintFiles() - Print one or more files 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 <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#if defined(WIN32) || defined(__EMX__)
+# include <io.h>
+#else
+# include <unistd.h>
+#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[HTTP_MAX_VALUE] = "";
+ /* Authorization string */
+static char pwdstring[33] = ""; /* Last password 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[32768]; /* Output buffer */
+ const char *password; /* Password string */
+ char realm[HTTP_MAX_VALUE], /* realm="xyz" string */
+ nonce[HTTP_MAX_VALUE], /* nonce="xyz" string */
+ plain[255], /* Plaintext username:password */
+ encode[512]; /* Encoded username:password */
+ char prompt[1024]; /* Prompt string */
+ int digest_tries; /* Number of tries with Digest */
+
+
+ if (http == NULL || request == NULL || resource == NULL)
+ {
+ if (request != NULL)
+ ippDelete(request);
+
+ last_error = IPP_INTERNAL_ERROR;
+ return (NULL);
+ }
+
+ DEBUG_printf(("cupsDoFileRequest(%p, %08x, \'%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);
+ }
+ }
+ else
+ file = NULL;
+
+ /*
+ * Loop until we can send the request without authorization problems.
+ */
+
+ response = NULL;
+ status = HTTP_ERROR;
+ digest_tries = 0;
+
+ while (response == NULL)
+ {
+ DEBUG_puts("cupsDoFileRequest: setup...");
+
+ /*
+ * Setup the HTTP variables needed...
+ */
+
+ if (filename != NULL)
+ sprintf(length, "%lu", (unsigned long)(ippLength(request) +
+ (size_t)fileinfo.st_size));
+ else
+ sprintf(length, "%lu", (unsigned long)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))
+ {
+ if (httpReconnect(http))
+ {
+ status = HTTP_ERROR;
+ break;
+ }
+ else
+ 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;
+
+ /*
+ * See if we should retry the current digest password...
+ */
+
+ if (strncmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], "Basic", 5) == 0 ||
+ digest_tries > 1 || !pwdstring[0])
+ {
+ /*
+ * Nope - get a password from the user...
+ */
+
+ snprintf(prompt, sizeof(prompt), "Password for %s on %s? ", cupsUser(),
+ http->hostname);
+
+ if ((password = cupsGetPassword(prompt)) == NULL)
+ break;
+ if (!password[0])
+ break;
+
+ strncpy(pwdstring, password, sizeof(pwdstring) - 1);
+ pwdstring[sizeof(pwdstring) - 1] = '\0';
+
+ digest_tries = 0;
+ }
+ else
+ digest_tries ++;
+
+ /*
+ * Got a password; encode it for the server...
+ */
+
+ if (strncmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], "Basic", 5) == 0)
+ {
+ /*
+ * Basic authentication...
+ */
+
+ snprintf(plain, sizeof(plain), "%s:%s", cupsUser(), pwdstring);
+ httpEncode64(encode, plain);
+ snprintf(authstring, sizeof(authstring), "Basic %s", encode);
+ }
+ else
+ {
+ /*
+ * Digest authentication...
+ */
+
+ httpGetSubField(http, HTTP_FIELD_WWW_AUTHENTICATE, "realm", realm);
+ httpGetSubField(http, HTTP_FIELD_WWW_AUTHENTICATE, "nonce", nonce);
+
+ httpMD5(cupsUser(), realm, pwdstring, encode);
+ httpMD5Final(nonce, "POST", resource, encode);
+ snprintf(authstring, sizeof(authstring),
+ "Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", "
+ "response=\"%s\"", cupsUser(), realm, nonce, encode);
+ }
+
+ continue;
+ }
+ else if (status == HTTP_ERROR)
+ {
+#ifdef WIN32
+ if (http->error != WSAENETDOWN && http->error != WSAENETUNREACH)
+#else
+ if (http->error != ENETDOWN && http->error != ENETUNREACH)
+#endif /* WIN32 */
+ continue;
+ else
+ break;
+ }
+#ifdef HAVE_LIBSSL
+ else if (status == HTTP_UPGRADE_REQUIRED)
+ {
+ /*
+ * Flush any error message...
+ */
+
+ httpFlush(http);
+
+ /*
+ * Upgrade with encryption...
+ */
+
+ httpEncryption(http, HTTP_ENCRYPT_REQUIRED);
+
+ /*
+ * Try again, this time with encryption enabled...
+ */
+
+ continue;
+ }
+#endif /* HAVE_LIBSSL */
+ 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;
+ break;
+ }
+ }
+ }
+
+ /*
+ * Close the file if needed...
+ */
+
+ if (filename != NULL)
+ fclose(file);
+
+ /*
+ * Flush any remaining data...
+ */
+
+ httpFlush(http);
+
+ /*
+ * 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);
+}
+
+
+/*
+ * 'cupsFreeJobs()' - Free memory used by job data.
+ */
+
+void
+cupsFreeJobs(int num_jobs,/* I - Number of jobs */
+ cups_job_t *jobs) /* I - Jobs */
+{
+ int i; /* Looping var */
+
+
+ if (num_jobs <= 0 || jobs == NULL)
+ return;
+
+ for (i = 0; i < num_jobs; i ++)
+ {
+ free(jobs[i].dest);
+ free(jobs[i].user);
+ free(jobs[i].format);
+ free(jobs[i].title);
+ }
+
+ free(jobs);
+}
+
+
+/*
+ * '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 */
+
+
+ if (classes == NULL)
+ {
+ last_error = IPP_INTERNAL_ERROR;
+ return (0);
+ }
+
+ /*
+ * 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
+ * requested-attributes
+ */
+
+ 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);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes", NULL, "printer-name");
+
+ /*
+ * 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)
+{
+ 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);
+
+ /*
+ * 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);
+}
+
+
+/*
+ * 'cupsGetJobs()' - Get the jobs from the server.
+ */
+
+int /* O - Number of jobs */
+cupsGetJobs(cups_job_t **jobs, /* O - Job data */
+ const char *mydest, /* I - Only show jobs for dest? */
+ int myjobs, /* I - Only show my jobs? */
+ int completed) /* I - Only show completed jobs? */
+{
+ int n; /* Number of jobs */
+ ipp_t *request, /* IPP Request */
+ *response; /* IPP Response */
+ ipp_attribute_t *attr; /* Current attribute */
+ cups_lang_t *language; /* Default language */
+ cups_job_t *temp; /* Temporary pointer */
+ int id, /* job-id */
+ priority, /* job-priority */
+ size; /* job-k-octets */
+ ipp_jstate_t state; /* job-state */
+ time_t completed_time, /* time-at-completed */
+ creation_time, /* time-at-creation */
+ processing_time; /* time-at-processing */
+ const char *dest, /* job-printer-uri */
+ *format, /* document-format */
+ *title, /* job-name */
+ *user; /* job-originating-user-name */
+ char uri[HTTP_MAX_URI]; /* URI for jobs */
+ static const char *attrs[] = /* Requested attributes */
+ {
+ "job-id",
+ "job-priority",
+ "job-k-octets",
+ "job-state",
+ "time-at-completed",
+ "time-at-creation",
+ "time-at-processing",
+ "job-printer-uri",
+ "document-format",
+ "job-name",
+ "job-originating-user-name"
+ };
+
+
+ if (jobs == NULL)
+ {
+ last_error = IPP_INTERNAL_ERROR;
+ return (0);
+ }
+
+ /*
+ * Try to connect to the server...
+ */
+
+ if (!cups_connect("default", NULL, NULL))
+ {
+ last_error = IPP_SERVICE_UNAVAILABLE;
+ return (0);
+ }
+
+ /*
+ * Build an IPP_GET_JOBS request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * requesting-user-name
+ * which-jobs
+ * my-jobs
+ * requested-attributes
+ */
+
+ 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);
+
+ if (mydest)
+ snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", mydest);
+ else
+ strcpy(uri, "ipp://localhost/jobs");
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, uri);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requesting-user-name", NULL, cupsUser());
+
+ if (myjobs)
+ ippAddBoolean(request, IPP_TAG_OPERATION, "my-jobs", 1);
+
+ if (completed)
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "which-jobs", NULL, "completed");
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes", sizeof(attrs) / sizeof(attrs[0]),
+ NULL, attrs);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ n = 0;
+ *jobs = NULL;
+
+ if ((response = cupsDoRequest(cups_server, request, "/")) != NULL)
+ {
+ last_error = response->request.status.status_code;
+
+ 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...
+ */
+
+ id = 0;
+ size = 0;
+ priority = 50;
+ state = IPP_JOB_PENDING;
+ user = NULL;
+ dest = NULL;
+ format = NULL;
+ title = NULL;
+ creation_time = 0;
+ completed_time = 0;
+ processing_time = 0;
+
+ while (attr != NULL && attr->group_tag == IPP_TAG_JOB)
+ {
+ if (strcmp(attr->name, "job-id") == 0 &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ id = attr->values[0].integer;
+ else if (strcmp(attr->name, "job-state") == 0 &&
+ attr->value_tag == IPP_TAG_ENUM)
+ state = (ipp_jstate_t)attr->values[0].integer;
+ else if (strcmp(attr->name, "job-priority") == 0 &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ priority = attr->values[0].integer;
+ else if (strcmp(attr->name, "job-k-octets") == 0 &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ size = attr->values[0].integer;
+ else if (strcmp(attr->name, "time-at-completed") == 0 &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ completed_time = attr->values[0].integer;
+ else if (strcmp(attr->name, "time-at-creation") == 0 &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ creation_time = attr->values[0].integer;
+ else if (strcmp(attr->name, "time-at-processing") == 0 &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ processing_time = attr->values[0].integer;
+ else if (strcmp(attr->name, "job-printer-uri") == 0 &&
+ attr->value_tag == IPP_TAG_URI)
+ {
+ if ((dest = strrchr(attr->values[0].string.text, '/')) != NULL)
+ dest ++;
+ }
+ else if (strcmp(attr->name, "job-originating-user-name") == 0 &&
+ attr->value_tag == IPP_TAG_NAME)
+ user = attr->values[0].string.text;
+ else if (strcmp(attr->name, "document-format") == 0 &&
+ attr->value_tag == IPP_TAG_MIMETYPE)
+ format = attr->values[0].string.text;
+ else if (strcmp(attr->name, "job-name") == 0 &&
+ attr->value_tag == IPP_TAG_TEXT)
+ title = attr->values[0].string.text;
+
+ attr = attr->next;
+ }
+
+ /*
+ * See if we have everything needed...
+ */
+
+ if (dest == NULL || format == NULL || title == NULL || user == NULL ||
+ id == 0)
+ {
+ if (attr == NULL)
+ break;
+ else
+ continue;
+ }
+
+ /*
+ * Allocate memory for the job...
+ */
+
+ if (n == 0)
+ temp = malloc(sizeof(cups_job_t));
+ else
+ temp = realloc(*jobs, sizeof(cups_job_t) * (n + 1));
+
+ if (temp == NULL)
+ {
+ /*
+ * Ran out of memory!
+ */
+
+ cupsFreeJobs(n, *jobs);
+ *jobs = NULL;
+
+ ippDelete(response);
+ return (0);
+ }
+
+ *jobs = temp;
+ temp += n;
+ n ++;
+
+ /*
+ * Copy the data over...
+ */
+
+ temp->dest = strdup(dest);
+ temp->user = strdup(user);
+ temp->format = strdup(format);
+ temp->title = strdup(title);
+ temp->id = id;
+ temp->priority = priority;
+ temp->state = state;
+ temp->size = size;
+ temp->completed_time = completed_time;
+ temp->creation_time = creation_time;
+ temp->processing_time = processing_time;
+ }
+
+ ippDelete(response);
+ }
+ else
+ last_error = IPP_BAD_REQUEST;
+
+ return (n);
+}
+
+
+/*
+ * 'cupsGetPPD()' - Get the PPD file for a printer.
+ */
+
+const char * /* O - Filename for PPD file */
+cupsGetPPD(const char *name) /* I - Printer name */
+{
+ int i; /* Looping var */
+ ipp_t *request, /* IPP request */
+ *response; /* IPP response */
+ ipp_attribute_t *attr; /* Current attribute */
+ cups_lang_t *language; /* Local language */
+ int fd; /* PPD file */
+ int bytes; /* Number of bytes read */
+ char buffer[8192]; /* Buffer for file */
+ char printer[HTTP_MAX_URI], /* Printer name */
+ method[HTTP_MAX_URI], /* Method/scheme name */
+ username[HTTP_MAX_URI], /* Username:password */
+ hostname[HTTP_MAX_URI], /* Hostname */
+ resource[HTTP_MAX_URI]; /* Resource name */
+ int port; /* Port number */
+ const char *password; /* Password string */
+ char realm[HTTP_MAX_VALUE], /* realm="xyz" string */
+ nonce[HTTP_MAX_VALUE], /* nonce="xyz" string */
+ plain[255], /* Plaintext username:password */
+ encode[512]; /* Encoded username:password */
+ http_status_t status; /* HTTP status from server */
+ char prompt[1024]; /* Prompt string */
+ int digest_tries; /* Number of tries with Digest */
+ static char filename[HTTP_MAX_URI]; /* Local filename */
+ static const char *requested_attrs[] =/* Requested attributes */
+ {
+ "printer-uri-supported",
+ "printer-type",
+ "member-uris"
+ };
+
+
+ if (name == NULL)
+ {
+ last_error = IPP_INTERNAL_ERROR;
+ return (NULL);
+ }
+
+ /*
+ * See if we can connect to the server...
+ */
+
+ if (!cups_connect(name, printer, hostname))
+ {
+ last_error = IPP_SERVICE_UNAVAILABLE;
+ return (NULL);
+ }
+
+ /*
+ * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * requested-attributes
+ */
+
+ 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);
+
+ snprintf(buffer, sizeof(buffer), "ipp://localhost/printers/%s", printer);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, buffer);
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requested-attributes",
+ sizeof(requested_attrs) / sizeof(requested_attrs[0]),
+ NULL, requested_attrs);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(cups_server, request, "/")) != NULL)
+ {
+ last_error = response->request.status.status_code;
+ printer[0] = '\0';
+ hostname[0] = '\0';
+
+ if ((attr = ippFindAttribute(response, "member-uris", IPP_TAG_URI)) != NULL)
+ {
+ /*
+ * Get the first actual server and printer name in the class...
+ */
+
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ httpSeparate(attr->values[0].string.text, method, username, hostname,
+ &port, resource);
+ if (strncmp(resource, "/printers/", 10) == 0)
+ {
+ /*
+ * Found a printer!
+ */
+
+ strncpy(printer, resource + 10, sizeof(printer) - 1);
+ printer[sizeof(printer) - 1] = '\0';
+ break;
+ }
+ }
+ }
+ else if ((attr = ippFindAttribute(response, "printer-uri-supported",
+ IPP_TAG_URI)) != NULL)
+ {
+ /*
+ * Get the actual server and printer names...
+ */
+
+ httpSeparate(attr->values[0].string.text, method, username, hostname,
+ &port, resource);
+ strncpy(printer, strrchr(resource, '/') + 1, sizeof(printer) - 1);
+ printer[sizeof(printer) - 1] = '\0';
+ }
+
+ ippDelete(response);
+
+ /*
+ * Remap local hostname to localhost...
+ */
+
+ gethostname(buffer, sizeof(buffer));
+
+ if (strcasecmp(buffer, hostname) == 0)
+ strcpy(hostname, "localhost");
+ }
+
+ cupsLangFree(language);
+
+ if (!printer[0])
+ return (NULL);
+
+ /*
+ * Reconnect to the correct server as needed...
+ */
+
+ if (strcasecmp(cups_server->hostname, hostname) != 0)
+ {
+ httpClose(cups_server);
+
+ if ((cups_server = httpConnectEncrypt(hostname, ippPort(),
+ cupsEncryption())) == NULL)
+ {
+ last_error = IPP_SERVICE_UNAVAILABLE;
+ return (NULL);
+ }
+ }
+
+ /*
+ * Get a temp file...
+ */
+
+ if ((fd = cupsTempFd(filename, sizeof(filename))) < 0)
+ {
+ /*
+ * Can't open file; close the server connection and return NULL...
+ */
+
+ httpFlush(cups_server);
+ httpClose(cups_server);
+ cups_server = NULL;
+ return (NULL);
+ }
+
+ /*
+ * And send a request to the HTTP server...
+ */
+
+ snprintf(resource, sizeof(resource), "/printers/%s.ppd", printer);
+
+ digest_tries = 0;
+
+ do
+ {
+ httpClearFields(cups_server);
+ httpSetField(cups_server, HTTP_FIELD_HOST, hostname);
+ httpSetField(cups_server, HTTP_FIELD_AUTHORIZATION, authstring);
+
+ if (httpGet(cups_server, resource))
+ {
+ if (httpReconnect(cups_server))
+ {
+ status = HTTP_ERROR;
+ break;
+ }
+ else
+ {
+ 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;
+
+ /*
+ * See if we should retry the current digest password...
+ */
+
+ if (strncmp(cups_server->fields[HTTP_FIELD_WWW_AUTHENTICATE], "Basic", 5) == 0 ||
+ digest_tries > 1 || !pwdstring[0])
+ {
+ /*
+ * Nope - get a password from the user...
+ */
+
+ snprintf(prompt, sizeof(prompt), "Password for %s on %s? ", cupsUser(),
+ cups_server->hostname);
+
+ if ((password = cupsGetPassword(prompt)) == NULL)
+ break;
+ if (!password[0])
+ break;
+
+ strncpy(pwdstring, password, sizeof(pwdstring) - 1);
+ pwdstring[sizeof(pwdstring) - 1] = '\0';
+
+ digest_tries = 0;
+ }
+ else
+ digest_tries ++;
+
+ /*
+ * Got a password; encode it for the server...
+ */
+
+ if (strncmp(cups_server->fields[HTTP_FIELD_WWW_AUTHENTICATE], "Basic", 5) == 0)
+ {
+ /*
+ * Basic authentication...
+ */
+
+ snprintf(plain, sizeof(plain), "%s:%s", cupsUser(), pwdstring);
+ httpEncode64(encode, plain);
+ snprintf(authstring, sizeof(authstring), "Basic %s", encode);
+ }
+ else
+ {
+ /*
+ * Digest authentication...
+ */
+
+ httpGetSubField(cups_server, HTTP_FIELD_WWW_AUTHENTICATE, "realm", realm);
+ httpGetSubField(cups_server, HTTP_FIELD_WWW_AUTHENTICATE, "nonce", nonce);
+
+ httpMD5(cupsUser(), realm, pwdstring, encode);
+ httpMD5Final(nonce, "GET", resource, encode);
+ snprintf(authstring, sizeof(authstring),
+ "Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", "
+ "response=\"%s\"", cupsUser(), realm, nonce, encode);
+ }
+
+ continue;
+ }
+#ifdef HAVE_LIBSSL
+ else if (status == HTTP_UPGRADE_REQUIRED)
+ {
+ /*
+ * Flush any error message...
+ */
+
+ httpFlush(cups_server);
+
+ /*
+ * Upgrade with encryption...
+ */
+
+ httpEncryption(cups_server, HTTP_ENCRYPT_REQUIRED);
+
+ /*
+ * Try again, this time with encryption enabled...
+ */
+
+ continue;
+ }
+#endif /* HAVE_LIBSSL */
+ }
+ while (status == HTTP_UNAUTHORIZED || status == HTTP_UPGRADE_REQUIRED);
+
+ /*
+ * See if we actually got the file or an error...
+ */
+
+ if (status != HTTP_OK)
+ {
+ unlink(filename);
+ httpFlush(cups_server);
+ httpClose(cups_server);
+ cups_server = NULL;
+ return (NULL);
+ }
+
+ /*
+ * OK, we need to copy the file...
+ */
+
+ while ((bytes = httpRead(cups_server, buffer, sizeof(buffer))) > 0)
+ write(fd, buffer, bytes);
+
+ close(fd);
+
+ 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 */
+
+
+ if (printers == NULL)
+ {
+ last_error = IPP_INTERNAL_ERROR;
+ return (0);
+ }
+
+ /*
+ * 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
+ * requested-attributes
+ */
+
+ 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);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes", NULL, "printer-name");
+
+ /*
+ * 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 */
+{
+ DEBUG_printf(("cupsPrintFile(\'%s\', \'%s\', %d, %p)\n",
+ name, filename, num_options, options));
+
+ return (cupsPrintFiles(name, 1, &filename, title, num_options, options));
+}
+
+
+/*
+ * 'cupsPrintFiles()' - Print one or more files to a printer or class.
+ */
+
+int /* O - Job ID */
+cupsPrintFiles(const char *name, /* I - Printer or class name */
+ int num_files, /* I - Number of files */
+ const char **files, /* I - File(s) 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 */
+ const char *val; /* Pointer to 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(("cupsPrintFiles(\'%s\', %d, %p, %d, %p)\n",
+ name, num_files, files, num_options, options));
+
+ if (name == NULL || num_files < 1 || files == NULL)
+ return (0);
+
+ /*
+ * Setup a connection and request data...
+ */
+
+ if (!cups_connect(name, printer, hostname))
+ {
+ DEBUG_printf(("cupsPrintFile: Unable to open connection - %s.\n",
+ strerror(errno)));
+ last_error = IPP_SERVICE_UNAVAILABLE;
+ return (0);
+ }
+
+ language = cupsLangDefault();
+
+ /*
+ * Build a standard CUPS URI for the printer and fill the standard IPP
+ * attributes...
+ */
+
+ if ((request = ippNew()) == NULL)
+ return (0);
+
+ request->request.op.operation_id = num_files == 1 ? IPP_PRINT_JOB :
+ IPP_CREATE_JOB;
+ request->request.op.request_id = 1;
+
+ snprintf(uri, sizeof(uri), "ipp://%s:%d/printers/%s", hostname, ippPort(), printer);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, cupsLangEncoding(language));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL,
+ language != NULL ? language->language : "C");
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, uri);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, cupsUser());
+
+ if (title)
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL, title);
+
+ /*
+ * Then add all options...
+ */
+
+ cupsEncodeOptions(request, num_options, options);
+
+ /*
+ * Do the request...
+ */
+
+ snprintf(uri, sizeof(uri), "/printers/%s", printer);
+
+ if (num_files == 1)
+ response = cupsDoFileRequest(cups_server, request, uri, *files);
+ else
+ response = cupsDoRequest(cups_server, request, uri);
+
+ if (response == 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);
+
+ /*
+ * Handle multiple file jobs if the create-job operation worked...
+ */
+
+ if (jobid > 0 && num_files > 1)
+ for (i = 0; i < num_files; i ++)
+ {
+ /*
+ * Build a standard CUPS URI for the job and fill the standard IPP
+ * attributes...
+ */
+
+ if ((request = ippNew()) == NULL)
+ return (0);
+
+ request->request.op.operation_id = IPP_SEND_DOCUMENT;
+ request->request.op.request_id = 1;
+
+ snprintf(uri, sizeof(uri), "ipp://%s:%d/jobs/%d", hostname, ippPort(),
+ jobid);
+
+ 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, "job-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 if ((val = cupsGetOption("document-format", num_options, options)) != NULL)
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format",
+ NULL, val);
+ 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());
+
+ /*
+ * Is this the last document?
+ */
+
+ if (i == (num_files - 1))
+ ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", 1);
+
+ /*
+ * Send the file...
+ */
+
+ snprintf(uri, sizeof(uri), "/printers/%s", printer);
+
+ if ((response = cupsDoFileRequest(cups_server, request, uri,
+ files[i])) != NULL)
+ ippDelete(response);
+ }
+
+ return (jobid);
+}
+
+
+/*
+ * '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 */
+
+
+ DEBUG_printf(("cups_connect(\"%s\", %p, %p)\n", name, printer, hostname));
+
+ 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);
+ }
+
+ DEBUG_printf(("connecting to %s on port %d...\n", hostname, ippPort()));
+
+ if ((cups_server = httpConnectEncrypt(hostname, ippPort(),
+ cupsEncryption())) == 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 */
+ const char *root; /* Server root directory */
+
+
+ /*
+ * 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...
+ */
+
+ if ((root = getenv("CUPS_SERVERROOT")) == NULL)
+ root = CUPS_SERVERROOT;
+
+ pid = getpid();
+ snprintf(filename, sizeof(filename), "%s/certs/%d", root, pid);
+ if ((fp = fopen(filename, "r")) == NULL && pid > 0)
+ {
+ snprintf(filename, sizeof(filename), "%s/certs/0", root);
+ fp = fopen(filename, "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...
+ */
+
+ snprintf(authstring, sizeof(authstring), "Local %s", certificate);
+
+ return (1);
+#endif /* WIN32 || __EMX__ */
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/data/HPGLprolog b/data/HPGLprolog
new file mode 100644
index 000000000..830458243
--- /dev/null
+++ b/data/HPGLprolog
@@ -0,0 +1,37 @@
+%%BeginResource: procset hpgltops 1.1 0
+%
+% "$Id: HPGLprolog 2010 2002-01-02 17:59:21Z 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-2002 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 000000000..1f44c4ba7
--- /dev/null
+++ b/data/Makefile
@@ -0,0 +1,112 @@
+#
+# "$Id$"
+#
+# Datafile makefile for the Common UNIX Printing System (CUPS).
+#
+# Copyright 1993-2002 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...
+#
+
+BANNERS = classified \
+ confidential \
+ secret \
+ standard \
+ topsecret \
+ unclassified
+
+CHARSETS = windows-874 \
+ windows-1250 \
+ windows-1251 \
+ windows-1252 \
+ windows-1253 \
+ windows-1254 \
+ windows-1255 \
+ windows-1256 \
+ windows-1257 \
+ windows-1258 \
+ koi8-r \
+ koi8-u \
+ 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 \
+ koi8-r \
+ koi8-u \
+ utf-8
+DATAFILES = HPGLprolog psglyphs testprint.ps
+
+
+#
+# Make everything...
+#
+
+all:
+
+
+#
+# Clean all config and object files...
+#
+
+clean:
+
+
+#
+# Install files...
+#
+
+install:
+ $(INSTALL_DIR) $(DATADIR)/banners
+ for file in $(BANNERS); do \
+ $(INSTALL_DATA) $$file $(DATADIR)/banners; \
+ done
+ $(INSTALL_DIR) $(DATADIR)/charsets
+ for file in $(CHARSETS); do \
+ $(INSTALL_DATA) $$file $(DATADIR)/charsets; \
+ done
+ $(INSTALL_DIR) $(DATADIR)/data
+ for file in $(DATAFILES); do \
+ $(INSTALL_DATA) $$file $(DATADIR)/data; \
+ done
+ -if test x$(PAMDIR) != x$(BUILDROOT); then \
+ $(INSTALL_DIR) $(PAMDIR); \
+ if test -f /lib/security/pam_unix.so; then \
+ $(INSTALL_DATA) cups.suse $(PAMDIR)/cups; \
+ else \
+ $(INSTALL_DATA) cups.pam $(PAMDIR)/cups; \
+ fi \
+ fi
+
+
+#
+# End of "$Id$".
+#
diff --git a/data/classified b/data/classified
new file mode 100644
index 000000000..df921456f
--- /dev/null
+++ b/data/classified
@@ -0,0 +1,277 @@
+%!PS-Adobe-3.0
+%%BoundingBox: 0 0 612 792
+%%Pages: 1
+%%LanguageLevel: 1
+%%DocumentData: Clean7Bit
+%%DocumentSuppliedResources: procset bannerprint/1.0
+%%DocumentNeededResources: font Helvetica Helvetica-Bold Times-Roman
+%%Creator: Michael Sweet, Easy Software Products
+%%CreationDate: May 10, 2000
+%%Title: Test Page
+%%EndComments
+%%BeginProlog
+%%BeginResource procset bannerprint 1.1 0
+%
+% PostScript banner page for the Common UNIX Printing System ("CUPS").
+%
+% Copyright 1993-2002 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
+%
+/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
+
+ /pageWidth pageRight pageLeft sub def % pageWidth = pageRight - pageLeft
+ /pageHeight pageTop pageBottom sub def% pageHeight = pageTop - pageBottom
+
+ /boxWidth % width of text box
+ pageWidth pageHeight lt
+ { pageWidth 54 mul }
+ { pageHeight 42 mul }
+ ifelse def
+
+ newpath % Clear bounding path
+
+ % Create fonts...
+ /bigFont /Helvetica-Bold findfont % bigFont = Helvetica-Bold
+ pageHeight 3 mul scalefont def % size = pageHeight * 3 (nominally 33)
+
+ /mediumFont /Helvetica findfont % mediumFont = Helvetica
+ pageHeight 1.5 mul scalefont def % size = pageHeight * 1.5 (nominally 16.5)
+
+ % Offset page to account for lower-left margin...
+ pageLeft 72 mul
+ pageBottom 72 mul
+ translate
+
+ % Draw the label at the top and bottom...
+ 0 setgray % Color
+
+ pageWidth 36 mul % Center of page
+ pageHeight 72 mul % Top of page
+ pageWidth -7 mul add % - 2 lines
+ moveto % Position text
+ bigFont setfont % Font
+ (Classified) CENTER % Show text centered
+
+ pageWidth 36 mul % Center of page
+ pageHeight 6 mul % Bottom of page
+ moveto % Position text
+ bigFont setfont % Font
+ (Classified) CENTER % Show text centered
+
+ % Job information box...
+ pageWidth 36 mul 9 add % x = pageWidth * 1/2 * 72 + 9
+ boxWidth 0.5 mul sub % x-= 1/2 box width
+ pageHeight 30 mul 9 sub % y = pageHeight * 1/2 * 72 - 9
+ boxWidth % w = box width
+ pageHeight 14 mul % h = pageHeight * 1/2 * 72
+ 0.5 setgray rectfill % Draw a shadow
+
+ pageWidth 36 mul % x = pageWidth * 1/2 * 72
+ boxWidth 0.5 mul sub % x-= 1/2 box width
+ pageHeight 30 mul % y = pageHeight * 1/4 * 72
+ boxWidth % w = box width
+ pageHeight 14 mul % h = pageHeight * 1/2 * 72
+
+ 4 copy 1 setgray rectfill % Clear the box to white
+ 0 setgray rectstroke % Draw a black box around it...
+
+ % Job information text...
+ mediumFont setfont % Medium sized font
+
+ pageWidth 36 mul % x = pageWidth * 1/2 * 72
+ pageHeight 36 mul % y = pageHeight * 1/2 * 72
+ pageHeight 5 mul add % y += 2 lines
+ 2 copy % Copy X & Y
+ moveto
+ (Job ID: ) RIGHT
+ moveto
+ ({printer-name}-{job-id}) show
+
+ pageWidth 36 mul % x = pageWidth * 1/2 * 72
+ pageHeight 36 mul % y = pageHeight * 1/2 * 72
+ pageHeight 2 mul add % y += 1 line
+ 2 copy % Copy X & Y
+ moveto
+ (Title: ) RIGHT
+ moveto
+ ({job-name}) show
+
+ pageWidth 36 mul % x = pageWidth * 1/2 * 72
+ pageHeight 36 mul % y = pageHeight * 1/2 * 72
+ pageHeight -1 mul add % y -= 1 line
+ 2 copy % Copy X & Y
+ moveto
+ (Requesting User: ) RIGHT
+ moveto
+ ({job-originating-user-name}) show
+
+ pageWidth 36 mul % x = pageWidth * 1/2 * 72
+ pageHeight 36 mul % y = pageHeight * 1/2 * 72
+ pageHeight -4 mul add % y -= 2 lines
+ 2 copy % Copy X & Y
+ moveto
+ (Billing Info: ) RIGHT
+ moveto
+ ({?job-billing}) show
+
+ % 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: classified 2122 2002-01-31 14:19:37Z mike $".
+%
+%%EOF
diff --git a/data/confidential b/data/confidential
new file mode 100644
index 000000000..48744d6ef
--- /dev/null
+++ b/data/confidential
@@ -0,0 +1,277 @@
+%!PS-Adobe-3.0
+%%BoundingBox: 0 0 612 792
+%%Pages: 1
+%%LanguageLevel: 1
+%%DocumentData: Clean7Bit
+%%DocumentSuppliedResources: procset bannerprint/1.0
+%%DocumentNeededResources: font Helvetica Helvetica-Bold Times-Roman
+%%Creator: Michael Sweet, Easy Software Products
+%%CreationDate: May 10, 2000
+%%Title: Test Page
+%%EndComments
+%%BeginProlog
+%%BeginResource procset bannerprint 1.1 0
+%
+% PostScript banner page for the Common UNIX Printing System ("CUPS").
+%
+% Copyright 1993-2002 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
+%
+/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
+
+ /pageWidth pageRight pageLeft sub def % pageWidth = pageRight - pageLeft
+ /pageHeight pageTop pageBottom sub def% pageHeight = pageTop - pageBottom
+
+ /boxWidth % width of text box
+ pageWidth pageHeight lt
+ { pageWidth 54 mul }
+ { pageHeight 42 mul }
+ ifelse def
+
+ newpath % Clear bounding path
+
+ % Create fonts...
+ /bigFont /Helvetica-Bold findfont % bigFont = Helvetica-Bold
+ pageHeight 3 mul scalefont def % size = pageHeight * 3 (nominally 33)
+
+ /mediumFont /Helvetica findfont % mediumFont = Helvetica
+ pageHeight 1.5 mul scalefont def % size = pageHeight * 1.5 (nominally 16.5)
+
+ % Offset page to account for lower-left margin...
+ pageLeft 72 mul
+ pageBottom 72 mul
+ translate
+
+ % Draw the label at the top and bottom...
+ 0 setgray % Color
+
+ pageWidth 36 mul % Center of page
+ pageHeight 72 mul % Top of page
+ pageWidth -7 mul add % - 2 lines
+ moveto % Position text
+ bigFont setfont % Font
+ (Confidential) CENTER % Show text centered
+
+ pageWidth 36 mul % Center of page
+ pageHeight 6 mul % Bottom of page
+ moveto % Position text
+ bigFont setfont % Font
+ (Confidential) CENTER % Show text centered
+
+ % Job information box...
+ pageWidth 36 mul 9 add % x = pageWidth * 1/2 * 72 + 9
+ boxWidth 0.5 mul sub % x-= 1/2 box width
+ pageHeight 30 mul 9 sub % y = pageHeight * 1/2 * 72 - 9
+ boxWidth % w = box width
+ pageHeight 14 mul % h = pageHeight * 1/2 * 72
+ 0.5 setgray rectfill % Draw a shadow
+
+ pageWidth 36 mul % x = pageWidth * 1/2 * 72
+ boxWidth 0.5 mul sub % x-= 1/2 box width
+ pageHeight 30 mul % y = pageHeight * 1/4 * 72
+ boxWidth % w = box width
+ pageHeight 14 mul % h = pageHeight * 1/2 * 72
+
+ 4 copy 1 setgray rectfill % Clear the box to white
+ 0 setgray rectstroke % Draw a black box around it...
+
+ % Job information text...
+ mediumFont setfont % Medium sized font
+
+ pageWidth 36 mul % x = pageWidth * 1/2 * 72
+ pageHeight 36 mul % y = pageHeight * 1/2 * 72
+ pageHeight 5 mul add % y += 2 lines
+ 2 copy % Copy X & Y
+ moveto
+ (Job ID: ) RIGHT
+ moveto
+ ({printer-name}-{job-id}) show
+
+ pageWidth 36 mul % x = pageWidth * 1/2 * 72
+ pageHeight 36 mul % y = pageHeight * 1/2 * 72
+ pageHeight 2 mul add % y += 1 line
+ 2 copy % Copy X & Y
+ moveto
+ (Title: ) RIGHT
+ moveto
+ ({job-name}) show
+
+ pageWidth 36 mul % x = pageWidth * 1/2 * 72
+ pageHeight 36 mul % y = pageHeight * 1/2 * 72
+ pageHeight -1 mul add % y -= 1 line
+ 2 copy % Copy X & Y
+ moveto
+ (Requesting User: ) RIGHT
+ moveto
+ ({job-originating-user-name}) show
+
+ pageWidth 36 mul % x = pageWidth * 1/2 * 72
+ pageHeight 36 mul % y = pageHeight * 1/2 * 72
+ pageHeight -4 mul add % y -= 2 lines
+ 2 copy % Copy X & Y
+ moveto
+ (Billing Info: ) RIGHT
+ moveto
+ ({?job-billing}) show
+
+ % 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: confidential 2122 2002-01-31 14:19:37Z mike $".
+%
+%%EOF
diff --git a/data/cups.irix b/data/cups.irix
new file mode 100644
index 000000000..476383acb
--- /dev/null
+++ b/data/cups.irix
@@ -0,0 +1,3 @@
+#%PAM-1.0
+auth required pam_unix.so shadow nodelay nullok
+account required pam_unix.so
diff --git a/data/cups.pam b/data/cups.pam
new file mode 100644
index 000000000..f38e70184
--- /dev/null
+++ b/data/cups.pam
@@ -0,0 +1,2 @@
+auth required /lib/security/pam_pwdb.so nullok shadow
+account required /lib/security/pam_pwdb.so
diff --git a/data/cups.suse b/data/cups.suse
new file mode 100644
index 000000000..0c26fbe0d
--- /dev/null
+++ b/data/cups.suse
@@ -0,0 +1,2 @@
+auth required /lib/security/pam_unix.so nullok shadow
+account required /lib/security/pam_unix.so
diff --git a/data/iso-8859-1 b/data/iso-8859-1
new file mode 100644
index 000000000..057d8aee3
--- /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.
+#
+
+00 ff 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 000000000..31f55552e
--- /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.
+#
+
+00 ff 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 000000000..dcfacca9d
--- /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.
+#
+
+00 ff 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 000000000..ca0097a47
--- /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.
+#
+
+00 ff 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 000000000..334160f4f
--- /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.
+#
+
+00 ff 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 000000000..19b77878d
--- /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.
+#
+
+00 ff 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 000000000..efc4529ed
--- /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.
+#
+
+00 ff 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 000000000..5c93156eb
--- /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.
+#
+
+00 ff 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 000000000..59ee84d57
--- /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.
+#
+
+00 ff 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 000000000..356fe72e3
--- /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.
+#
+
+00 ff 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 000000000..57647841c
--- /dev/null
+++ b/data/iso-8859-7
@@ -0,0 +1,246 @@
+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.
+#
+
+00 9f ltor single Courier Courier-Bold Courier-Italic Courier-BoldItalic
+a0 ff ltor single Symbol
+
+#
+# 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 000000000..660122d6a
--- /dev/null
+++ b/data/iso-8859-8
@@ -0,0 +1,214 @@
+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.
+#
+
+00 7f ltor single Courier Courier-Bold Courier-Italic Courier-BoldItalic
+80 ff rtol single Courier
+
+#
+# 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 000000000..83a661edc
--- /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.
+#
+
+00 ff 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/koi8-r b/data/koi8-r
new file mode 100644
index 000000000..7d6816b07
--- /dev/null
+++ b/data/koi8-r
@@ -0,0 +1,261 @@
+charset 8bit
+
+#
+# This file defines the font and character mappings used for Russian
+# Code Page KOI8-R 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.
+#
+
+00 ff 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 2500
+81 2502
+82 250C
+83 2510
+84 2514
+85 2518
+86 251C
+87 2524
+88 252C
+89 2534
+8A 253C
+8B 2580
+8C 2584
+8D 2588
+8E 258C
+8F 2590
+90 2591
+91 2592
+92 2593
+93 2320
+94 25A0
+95 2219
+96 221A
+97 2248
+98 2264
+99 2265
+9A 00A0
+9B 2321
+9C 00B0
+9D 00B2
+9E 00B7
+9F 00F7
+A0 2550
+A1 2551
+A2 2552
+A3 0451
+A4 2553
+A5 2554
+A6 2555
+A7 2556
+A8 2557
+A9 2558
+AA 2559
+AB 255A
+AC 255B
+AD 255C
+AE 255D
+AF 255E
+B0 255F
+B1 2560
+B2 2561
+B3 0401
+B4 2562
+B5 2563
+B6 2564
+B7 2565
+B8 2566
+B9 2567
+BA 2568
+BB 2569
+BC 256A
+BD 256B
+BE 256C
+BF 00A9
+C0 044E
+C1 0430
+C2 0431
+C3 0446
+C4 0434
+C5 0435
+C6 0444
+C7 0433
+C8 0445
+C9 0438
+CA 0439
+CB 043A
+CC 043B
+CD 043C
+CE 043D
+CF 043E
+D0 043F
+D1 044F
+D2 0440
+D3 0441
+D4 0442
+D5 0443
+D6 0436
+D7 0432
+D8 044C
+D9 044B
+DA 0437
+DB 0448
+DC 044D
+DD 0449
+DE 0447
+DF 044A
+E0 042E
+E1 0410
+E2 0411
+E3 0426
+E4 0414
+E5 0415
+E6 0424
+E7 0413
+E8 0425
+E9 0418
+EA 0419
+EB 041A
+EC 041B
+ED 041C
+EE 041D
+EF 041E
+F0 041F
+F1 042F
+F2 0420
+F3 0421
+F4 0422
+F5 0423
+F6 0416
+F7 0412
+F8 042C
+F9 042B
+FA 0417
+FB 0428
+FC 042D
+FD 0429
+FE 0427
+FF 042A
+
+
diff --git a/data/koi8-u b/data/koi8-u
new file mode 100644
index 000000000..c90c543d9
--- /dev/null
+++ b/data/koi8-u
@@ -0,0 +1,259 @@
+charset 8bit
+
+#
+# This file defines the font and character mappings used for Ukrainian
+# Code Page KOI8-U 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.
+#
+
+00 ff 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 2500
+81 2502
+82 250C
+83 2510
+84 2514
+85 2518
+86 251C
+87 2524
+88 252C
+89 2534
+8A 253C
+8B 2580
+8C 2584
+8D 2588
+8E 258C
+8F 2590
+90 2591
+91 2592
+92 2593
+93 2320
+94 25A0
+95 2219
+96 221A
+97 2248
+98 2264
+99 2265
+9A 00A0
+9B 2321
+9C 00B0
+9D 00B2
+9E 00B7
+9F 00F7
+A0 2550
+A1 2551
+A2 2552
+A3 0451
+A4 0454
+A5 2554
+A6 0456
+A7 0457
+A8 2557
+A9 2558
+AA 2559
+AB 255A
+AC 255B
+AD 0491
+AE 255D
+AF 255E
+B0 255F
+B1 2560
+B2 2561
+B3 0401
+B4 0404
+B5 2563
+B6 0406
+B7 0407
+B8 2566
+B9 2567
+BA 2568
+BB 2569
+BC 256A
+BD 0490
+BE 256C
+BF 00A9
+C0 044E
+C1 0430
+C2 0431
+C3 0446
+C4 0434
+C5 0435
+C6 0444
+C7 0433
+C8 0445
+C9 0438
+CA 0439
+CB 043A
+CC 043B
+CD 043C
+CE 043D
+CF 043E
+D0 043F
+D1 044F
+D2 0440
+D3 0441
+D4 0442
+D5 0443
+D6 0436
+D7 0432
+D8 044C
+D9 044B
+DA 0437
+DB 0448
+DC 044D
+DD 0449
+DE 0447
+DF 044A
+E0 042E
+E1 0410
+E2 0411
+E3 0426
+E4 0414
+E5 0415
+E6 0424
+E7 0413
+E8 0425
+E9 0418
+EA 0419
+EB 041A
+EC 041B
+ED 041C
+EE 041D
+EF 041E
+F0 041F
+F1 042F
+F2 0420
+F3 0421
+F4 0422
+F5 0423
+F6 0416
+F7 0412
+F8 042C
+F9 042B
+FA 0417
+FB 0428
+FC 042D
+FD 0429
+FE 0427
+FF 042A
diff --git a/data/psglyphs b/data/psglyphs
new file mode 100644
index 000000000..c4a902c66
--- /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/secret b/data/secret
new file mode 100644
index 000000000..1f8751430
--- /dev/null
+++ b/data/secret
@@ -0,0 +1,277 @@
+%!PS-Adobe-3.0
+%%BoundingBox: 0 0 612 792
+%%Pages: 1
+%%LanguageLevel: 1
+%%DocumentData: Clean7Bit
+%%DocumentSuppliedResources: procset bannerprint/1.0
+%%DocumentNeededResources: font Helvetica Helvetica-Bold Times-Roman
+%%Creator: Michael Sweet, Easy Software Products
+%%CreationDate: May 10, 2000
+%%Title: Test Page
+%%EndComments
+%%BeginProlog
+%%BeginResource procset bannerprint 1.1 0
+%
+% PostScript banner page for the Common UNIX Printing System ("CUPS").
+%
+% Copyright 1993-2002 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
+%
+/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
+
+ /pageWidth pageRight pageLeft sub def % pageWidth = pageRight - pageLeft
+ /pageHeight pageTop pageBottom sub def% pageHeight = pageTop - pageBottom
+
+ /boxWidth % width of text box
+ pageWidth pageHeight lt
+ { pageWidth 54 mul }
+ { pageHeight 42 mul }
+ ifelse def
+
+ newpath % Clear bounding path
+
+ % Create fonts...
+ /bigFont /Helvetica-Bold findfont % bigFont = Helvetica-Bold
+ pageHeight 3 mul scalefont def % size = pageHeight * 3 (nominally 33)
+
+ /mediumFont /Helvetica findfont % mediumFont = Helvetica
+ pageHeight 1.5 mul scalefont def % size = pageHeight * 1.5 (nominally 16.5)
+
+ % Offset page to account for lower-left margin...
+ pageLeft 72 mul
+ pageBottom 72 mul
+ translate
+
+ % Draw the label at the top and bottom...
+ 0 setgray % Color
+
+ pageWidth 36 mul % Center of page
+ pageHeight 72 mul % Top of page
+ pageWidth -7 mul add % - 2 lines
+ moveto % Position text
+ bigFont setfont % Font
+ (Secret) CENTER % Show text centered
+
+ pageWidth 36 mul % Center of page
+ pageHeight 6 mul % Bottom of page
+ moveto % Position text
+ bigFont setfont % Font
+ (Secret) CENTER % Show text centered
+
+ % Job information box...
+ pageWidth 36 mul 9 add % x = pageWidth * 1/2 * 72 + 9
+ boxWidth 0.5 mul sub % x-= 1/2 box width
+ pageHeight 30 mul 9 sub % y = pageHeight * 1/2 * 72 - 9
+ boxWidth % w = box width
+ pageHeight 14 mul % h = pageHeight * 1/2 * 72
+ 0.5 setgray rectfill % Draw a shadow
+
+ pageWidth 36 mul % x = pageWidth * 1/2 * 72
+ boxWidth 0.5 mul sub % x-= 1/2 box width
+ pageHeight 30 mul % y = pageHeight * 1/4 * 72
+ boxWidth % w = box width
+ pageHeight 14 mul % h = pageHeight * 1/2 * 72
+
+ 4 copy 1 setgray rectfill % Clear the box to white
+ 0 setgray rectstroke % Draw a black box around it...
+
+ % Job information text...
+ mediumFont setfont % Medium sized font
+
+ pageWidth 36 mul % x = pageWidth * 1/2 * 72
+ pageHeight 36 mul % y = pageHeight * 1/2 * 72
+ pageHeight 5 mul add % y += 2 lines
+ 2 copy % Copy X & Y
+ moveto
+ (Job ID: ) RIGHT
+ moveto
+ ({printer-name}-{job-id}) show
+
+ pageWidth 36 mul % x = pageWidth * 1/2 * 72
+ pageHeight 36 mul % y = pageHeight * 1/2 * 72
+ pageHeight 2 mul add % y += 1 line
+ 2 copy % Copy X & Y
+ moveto
+ (Title: ) RIGHT
+ moveto
+ ({job-name}) show
+
+ pageWidth 36 mul % x = pageWidth * 1/2 * 72
+ pageHeight 36 mul % y = pageHeight * 1/2 * 72
+ pageHeight -1 mul add % y -= 1 line
+ 2 copy % Copy X & Y
+ moveto
+ (Requesting User: ) RIGHT
+ moveto
+ ({job-originating-user-name}) show
+
+ pageWidth 36 mul % x = pageWidth * 1/2 * 72
+ pageHeight 36 mul % y = pageHeight * 1/2 * 72
+ pageHeight -4 mul add % y -= 2 lines
+ 2 copy % Copy X & Y
+ moveto
+ (Billing Info: ) RIGHT
+ moveto
+ ({?job-billing}) show
+
+ % 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: secret 2122 2002-01-31 14:19:37Z mike $".
+%
+%%EOF
diff --git a/data/standard b/data/standard
new file mode 100644
index 000000000..ca0edb037
--- /dev/null
+++ b/data/standard
@@ -0,0 +1,261 @@
+%!PS-Adobe-3.0
+%%BoundingBox: 0 0 612 792
+%%Pages: 1
+%%LanguageLevel: 1
+%%DocumentData: Clean7Bit
+%%DocumentSuppliedResources: procset bannerprint/1.0
+%%DocumentNeededResources: font Helvetica Helvetica-Bold Times-Roman
+%%Creator: Michael Sweet, Easy Software Products
+%%CreationDate: May 10, 2000
+%%Title: Test Page
+%%EndComments
+%%BeginProlog
+%%BeginResource procset bannerprint 1.1 0
+%
+% PostScript banner page for the Common UNIX Printing System ("CUPS").
+%
+% Copyright 1993-2002 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
+%
+/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
+
+ /pageWidth pageRight pageLeft sub def % pageWidth = pageRight - pageLeft
+ /pageHeight pageTop pageBottom sub def% pageHeight = pageTop - pageBottom
+
+ /boxWidth % width of text box
+ pageWidth pageHeight lt
+ { pageWidth 54 mul }
+ { pageHeight 42 mul }
+ ifelse def
+
+ newpath % Clear bounding path
+
+ % Create fonts...
+ /bigFont /Helvetica-Bold findfont % bigFont = Helvetica-Bold
+ pageHeight 3 mul scalefont def % size = pageHeight * 3 (nominally 33)
+
+ /mediumFont /Helvetica findfont % mediumFont = Helvetica
+ pageHeight 1.5 mul scalefont def % size = pageHeight * 1.5 (nominally 16.5)
+
+ % Offset page to account for lower-left margin...
+ pageLeft 72 mul
+ pageBottom 72 mul
+ translate
+
+ % Job information box...
+ pageWidth 36 mul 9 add % x = pageWidth * 1/2 * 72 + 9
+ boxWidth 0.5 mul sub % x-= 1/2 box width
+ pageHeight 30 mul 9 sub % y = pageHeight * 1/2 * 72 - 9
+ boxWidth % w = box width
+ pageHeight 14 mul % h = pageHeight * 1/2 * 72
+ 0.5 setgray rectfill % Draw a shadow
+
+ pageWidth 36 mul % x = pageWidth * 1/2 * 72
+ boxWidth 0.5 mul sub % x-= 1/2 box width
+ pageHeight 30 mul % y = pageHeight * 1/4 * 72
+ boxWidth % w = box width
+ pageHeight 14 mul % h = pageHeight * 1/2 * 72
+
+ 4 copy 1 setgray rectfill % Clear the box to white
+ 0 setgray rectstroke % Draw a black box around it...
+
+ % Job information text...
+ mediumFont setfont % Medium sized font
+
+ pageWidth 36 mul % x = pageWidth * 1/2 * 72
+ pageHeight 36 mul % y = pageHeight * 1/2 * 72
+ pageHeight 5 mul add % y += 2 lines
+ 2 copy % Copy X & Y
+ moveto
+ (Job ID: ) RIGHT
+ moveto
+ ({printer-name}-{job-id}) show
+
+ pageWidth 36 mul % x = pageWidth * 1/2 * 72
+ pageHeight 36 mul % y = pageHeight * 1/2 * 72
+ pageHeight 2 mul add % y += 1 line
+ 2 copy % Copy X & Y
+ moveto
+ (Title: ) RIGHT
+ moveto
+ ({job-name}) show
+
+ pageWidth 36 mul % x = pageWidth * 1/2 * 72
+ pageHeight 36 mul % y = pageHeight * 1/2 * 72
+ pageHeight -1 mul add % y -= 1 line
+ 2 copy % Copy X & Y
+ moveto
+ (Requesting User: ) RIGHT
+ moveto
+ ({job-originating-user-name}) show
+
+ pageWidth 36 mul % x = pageWidth * 1/2 * 72
+ pageHeight 36 mul % y = pageHeight * 1/2 * 72
+ pageHeight -4 mul add % y -= 2 lines
+ 2 copy % Copy X & Y
+ moveto
+ (Billing Info: ) RIGHT
+ moveto
+ ({?job-billing}) show
+
+ % 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: standard 2122 2002-01-31 14:19:37Z mike $".
+%
+%%EOF
diff --git a/data/testprint.ps b/data/testprint.ps
new file mode 100644
index 000000000..09683e614
--- /dev/null
+++ b/data/testprint.ps
@@ -0,0 +1,522 @@
+%!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-2002 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
+%
+/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)
+
+ % Figure out the sizes of things...
+ /wheelSize % size of wheels
+ pageWidth pageHeight lt
+ { pageWidth 9 mul }
+ { pageHeight 7 mul }
+ ifelse def
+
+ % Create fonts...
+ /bigFont /Helvetica-Bold findfont % bigFont = Helvetica-Bold
+ pageHeight 3 mul scalefont def % size = pageHeight * 3 (nominally 33)
+
+ /mediumFont /Helvetica findfont % mediumFont = Helvetica
+ pageHeight 1.5 mul scalefont def % size = pageHeight * 1.5 (nominally 16.5)
+
+ /smallFont /Times-Roman findfont % smallFont = Times-Roman
+ pageHeight scalefont def % size = pageHeight (nominally 11)
+
+ % 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...
+ wheelSize
+
+ % 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...
+ wheelSize
+
+ % 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...
+ pageHeight 15 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
+ pageHeight -2 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
+ pageHeight sub % 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
+ pageHeight 2 mul sub % 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
+ pageHeight sub % 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
+ pageHeight 2 mul sub % 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
+ pageHeight sub % 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
+ pageHeight 2 mul sub % 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
+ pageHeight sub % 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...
+ pageHeight 15 mul % Height of interpreter information
+
+ 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
+ pageHeight 2 mul sub % 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
+ pageHeight 2 mul sub % Move down...
+ 2 copy moveto % Move to x & y
+ (Version: ) RIGHT % Label
+ version show % Version
+ ( \() show % " ("
+ 1 revision NUMBER % Revision
+ (\)) show % ")"
+
+ % Product
+ pageHeight 2 mul sub % Move down...
+ 2 copy moveto % Move to x & y
+ (Product: ) RIGHT % Label
+ product show % Product name
+
+ % Serial Number
+ pageHeight 2 mul sub % 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
+ pageHeight 10 mul % Bottom of page
+ 2 copy moveto % Position text
+ (Printed Using CUPS v1.1.x) CENTER % Show text centered
+
+ pageHeight 2 mul sub % Move down...
+ 2 copy moveto % Position text
+ smallFont setfont % Font
+ (Copyright 1993-2002 Easy Software Products, All Rights Reserved.) CENTER
+ pageHeight sub % Move down...
+ 2 copy moveto % Position text
+ (CUPS, and the CUPS logo are the trademark property of) CENTER
+ pageHeight sub % Move down...
+ 2 copy moveto % Position text
+ (Easy Software Products, 44141 Airport View Drive, Suite 204,) CENTER
+ pageHeight sub % Move down...
+ 2 copy moveto % Position text
+ (Hollywood, Maryland, 20636-3111, USA.) CENTER
+
+ % Then the CUPS logo....
+ gsave
+ pageWidth 4 mul
+ pageHeight 4 mul
+ translate
+ pageWidth 9 mul CUPSLOGO
+ grestore
+
+ % And the ESP logo....
+ gsave
+ pageWidth 59 mul
+ pageHeight 4 mul
+ translate
+ pageWidth 6 mul ESPLOGO
+ grestore
+% Show the page...
+grestore
+showpage
+%
+% End of "$Id: testprint.ps 2010 2002-01-02 17:59:21Z mike $".
+%
+%%EOF
diff --git a/data/topsecret b/data/topsecret
new file mode 100644
index 000000000..c5c77c340
--- /dev/null
+++ b/data/topsecret
@@ -0,0 +1,277 @@
+%!PS-Adobe-3.0
+%%BoundingBox: 0 0 612 792
+%%Pages: 1
+%%LanguageLevel: 1
+%%DocumentData: Clean7Bit
+%%DocumentSuppliedResources: procset bannerprint/1.0
+%%DocumentNeededResources: font Helvetica Helvetica-Bold Times-Roman
+%%Creator: Michael Sweet, Easy Software Products
+%%CreationDate: May 10, 2000
+%%Title: Test Page
+%%EndComments
+%%BeginProlog
+%%BeginResource procset bannerprint 1.1 0
+%
+% PostScript banner page for the Common UNIX Printing System ("CUPS").
+%
+% Copyright 1993-2002 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
+%
+/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
+
+ /pageWidth pageRight pageLeft sub def % pageWidth = pageRight - pageLeft
+ /pageHeight pageTop pageBottom sub def% pageHeight = pageTop - pageBottom
+
+ /boxWidth % width of text box
+ pageWidth pageHeight lt
+ { pageWidth 54 mul }
+ { pageHeight 42 mul }
+ ifelse def
+
+ newpath % Clear bounding path
+
+ % Create fonts...
+ /bigFont /Helvetica-Bold findfont % bigFont = Helvetica-Bold
+ pageHeight 3 mul scalefont def % size = pageHeight * 3 (nominally 33)
+
+ /mediumFont /Helvetica findfont % mediumFont = Helvetica
+ pageHeight 1.5 mul scalefont def % size = pageHeight * 1.5 (nominally 16.5)
+
+ % Offset page to account for lower-left margin...
+ pageLeft 72 mul
+ pageBottom 72 mul
+ translate
+
+ % Draw the label at the top and bottom...
+ 0 setgray % Color
+
+ pageWidth 36 mul % Center of page
+ pageHeight 72 mul % Top of page
+ pageWidth -7 mul add % - 2 lines
+ moveto % Position text
+ bigFont setfont % Font
+ (Top Secret) CENTER % Show text centered
+
+ pageWidth 36 mul % Center of page
+ pageHeight 6 mul % Bottom of page
+ moveto % Position text
+ bigFont setfont % Font
+ (Top Secret) CENTER % Show text centered
+
+ % Job information box...
+ pageWidth 36 mul 9 add % x = pageWidth * 1/2 * 72 + 9
+ boxWidth 0.5 mul sub % x-= 1/2 box width
+ pageHeight 30 mul 9 sub % y = pageHeight * 1/2 * 72 - 9
+ boxWidth % w = box width
+ pageHeight 14 mul % h = pageHeight * 1/2 * 72
+ 0.5 setgray rectfill % Draw a shadow
+
+ pageWidth 36 mul % x = pageWidth * 1/2 * 72
+ boxWidth 0.5 mul sub % x-= 1/2 box width
+ pageHeight 30 mul % y = pageHeight * 1/4 * 72
+ boxWidth % w = box width
+ pageHeight 14 mul % h = pageHeight * 1/2 * 72
+
+ 4 copy 1 setgray rectfill % Clear the box to white
+ 0 setgray rectstroke % Draw a black box around it...
+
+ % Job information text...
+ mediumFont setfont % Medium sized font
+
+ pageWidth 36 mul % x = pageWidth * 1/2 * 72
+ pageHeight 36 mul % y = pageHeight * 1/2 * 72
+ pageHeight 5 mul add % y += 2 lines
+ 2 copy % Copy X & Y
+ moveto
+ (Job ID: ) RIGHT
+ moveto
+ ({printer-name}-{job-id}) show
+
+ pageWidth 36 mul % x = pageWidth * 1/2 * 72
+ pageHeight 36 mul % y = pageHeight * 1/2 * 72
+ pageHeight 2 mul add % y += 1 line
+ 2 copy % Copy X & Y
+ moveto
+ (Title: ) RIGHT
+ moveto
+ ({job-name}) show
+
+ pageWidth 36 mul % x = pageWidth * 1/2 * 72
+ pageHeight 36 mul % y = pageHeight * 1/2 * 72
+ pageHeight -1 mul add % y -= 1 line
+ 2 copy % Copy X & Y
+ moveto
+ (Requesting User: ) RIGHT
+ moveto
+ ({job-originating-user-name}) show
+
+ pageWidth 36 mul % x = pageWidth * 1/2 * 72
+ pageHeight 36 mul % y = pageHeight * 1/2 * 72
+ pageHeight -4 mul add % y -= 2 lines
+ 2 copy % Copy X & Y
+ moveto
+ (Billing Info: ) RIGHT
+ moveto
+ ({?job-billing}) show
+
+ % 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: topsecret 2122 2002-01-31 14:19:37Z mike $".
+%
+%%EOF
diff --git a/data/unclassified b/data/unclassified
new file mode 100644
index 000000000..d53190841
--- /dev/null
+++ b/data/unclassified
@@ -0,0 +1,277 @@
+%!PS-Adobe-3.0
+%%BoundingBox: 0 0 612 792
+%%Pages: 1
+%%LanguageLevel: 1
+%%DocumentData: Clean7Bit
+%%DocumentSuppliedResources: procset bannerprint/1.0
+%%DocumentNeededResources: font Helvetica Helvetica-Bold Times-Roman
+%%Creator: Michael Sweet, Easy Software Products
+%%CreationDate: May 10, 2000
+%%Title: Test Page
+%%EndComments
+%%BeginProlog
+%%BeginResource procset bannerprint 1.1 0
+%
+% PostScript banner page for the Common UNIX Printing System ("CUPS").
+%
+% Copyright 1993-2002 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
+%
+/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
+
+ /pageWidth pageRight pageLeft sub def % pageWidth = pageRight - pageLeft
+ /pageHeight pageTop pageBottom sub def% pageHeight = pageTop - pageBottom
+
+ /boxWidth % width of text box
+ pageWidth pageHeight lt
+ { pageWidth 54 mul }
+ { pageHeight 42 mul }
+ ifelse def
+
+ newpath % Clear bounding path
+
+ % Create fonts...
+ /bigFont /Helvetica-Bold findfont % bigFont = Helvetica-Bold
+ pageHeight 3 mul scalefont def % size = pageHeight * 3 (nominally 33)
+
+ /mediumFont /Helvetica findfont % mediumFont = Helvetica
+ pageHeight 1.5 mul scalefont def % size = pageHeight * 1.5 (nominally 16.5)
+
+ % Offset page to account for lower-left margin...
+ pageLeft 72 mul
+ pageBottom 72 mul
+ translate
+
+ % Draw the label at the top and bottom...
+ 0 setgray % Color
+
+ pageWidth 36 mul % Center of page
+ pageHeight 72 mul % Top of page
+ pageWidth -7 mul add % - 2 lines
+ moveto % Position text
+ bigFont setfont % Font
+ (Unclassified) CENTER % Show text centered
+
+ pageWidth 36 mul % Center of page
+ pageHeight 6 mul % Bottom of page
+ moveto % Position text
+ bigFont setfont % Font
+ (Unclassified) CENTER % Show text centered
+
+ % Job information box...
+ pageWidth 36 mul 9 add % x = pageWidth * 1/2 * 72 + 9
+ boxWidth 0.5 mul sub % x-= 1/2 box width
+ pageHeight 30 mul 9 sub % y = pageHeight * 1/2 * 72 - 9
+ boxWidth % w = box width
+ pageHeight 14 mul % h = pageHeight * 1/2 * 72
+ 0.5 setgray rectfill % Draw a shadow
+
+ pageWidth 36 mul % x = pageWidth * 1/2 * 72
+ boxWidth 0.5 mul sub % x-= 1/2 box width
+ pageHeight 30 mul % y = pageHeight * 1/4 * 72
+ boxWidth % w = box width
+ pageHeight 14 mul % h = pageHeight * 1/2 * 72
+
+ 4 copy 1 setgray rectfill % Clear the box to white
+ 0 setgray rectstroke % Draw a black box around it...
+
+ % Job information text...
+ mediumFont setfont % Medium sized font
+
+ pageWidth 36 mul % x = pageWidth * 1/2 * 72
+ pageHeight 36 mul % y = pageHeight * 1/2 * 72
+ pageHeight 5 mul add % y += 2 lines
+ 2 copy % Copy X & Y
+ moveto
+ (Job ID: ) RIGHT
+ moveto
+ ({printer-name}-{job-id}) show
+
+ pageWidth 36 mul % x = pageWidth * 1/2 * 72
+ pageHeight 36 mul % y = pageHeight * 1/2 * 72
+ pageHeight 2 mul add % y += 1 line
+ 2 copy % Copy X & Y
+ moveto
+ (Title: ) RIGHT
+ moveto
+ ({job-name}) show
+
+ pageWidth 36 mul % x = pageWidth * 1/2 * 72
+ pageHeight 36 mul % y = pageHeight * 1/2 * 72
+ pageHeight -1 mul add % y -= 1 line
+ 2 copy % Copy X & Y
+ moveto
+ (Requesting User: ) RIGHT
+ moveto
+ ({job-originating-user-name}) show
+
+ pageWidth 36 mul % x = pageWidth * 1/2 * 72
+ pageHeight 36 mul % y = pageHeight * 1/2 * 72
+ pageHeight -4 mul add % y -= 2 lines
+ 2 copy % Copy X & Y
+ moveto
+ (Billing Info: ) RIGHT
+ moveto
+ ({?job-billing}) show
+
+ % 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: unclassified 2122 2002-01-31 14:19:37Z mike $".
+%
+%%EOF
diff --git a/data/utf-8 b/data/utf-8
new file mode 100644
index 000000000..b73eb9667
--- /dev/null
+++ b/data/utf-8
@@ -0,0 +1,39 @@
+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 within each group, with 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 Courier-Bold Courier-Italic Courier-Bold-Italic
+0500 05FF rtol single Courier
+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/data/windows-1250 b/data/windows-1250
new file mode 100644
index 000000000..afcc62ed5
--- /dev/null
+++ b/data/windows-1250
@@ -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.
+#
+
+00 ff 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/windows-1251 b/data/windows-1251
new file mode 100644
index 000000000..6d31dee09
--- /dev/null
+++ b/data/windows-1251
@@ -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.
+#
+
+00 ff 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/windows-1252 b/data/windows-1252
new file mode 100644
index 000000000..a98595874
--- /dev/null
+++ b/data/windows-1252
@@ -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.
+#
+
+00 ff 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/windows-1253 b/data/windows-1253
new file mode 100644
index 000000000..c736ecd6c
--- /dev/null
+++ b/data/windows-1253
@@ -0,0 +1,243 @@
+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.
+#
+
+00 9f ltor single Courier Courier-Bold Courier-Italic Courier-BoldItalic
+a0 ff ltor single Symbol
+
+#
+# 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/windows-1254 b/data/windows-1254
new file mode 100644
index 000000000..87fff2db7
--- /dev/null
+++ b/data/windows-1254
@@ -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.
+#
+
+00 ff 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/windows-1255 b/data/windows-1255
new file mode 100644
index 000000000..a8b26a85d
--- /dev/null
+++ b/data/windows-1255
@@ -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.
+#
+
+00 ff 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/windows-1256 b/data/windows-1256
new file mode 100644
index 000000000..6908f1eb5
--- /dev/null
+++ b/data/windows-1256
@@ -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.
+#
+
+00 ff 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/windows-1257 b/data/windows-1257
new file mode 100644
index 000000000..ac5f8e0b7
--- /dev/null
+++ b/data/windows-1257
@@ -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.
+#
+
+00 ff 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/windows-1258 b/data/windows-1258
new file mode 100644
index 000000000..f7721c51b
--- /dev/null
+++ b/data/windows-1258
@@ -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.
+#
+
+00 ff 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/windows-874 b/data/windows-874
new file mode 100644
index 000000000..886e46a4b
--- /dev/null
+++ b/data/windows-874
@@ -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.
+#
+
+00 ff 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/doc/Makefile b/doc/Makefile
new file mode 100644
index 000000000..1051ba2db
--- /dev/null
+++ b/doc/Makefile
@@ -0,0 +1,236 @@
+#
+# "$Id$"
+#
+# Documentation makefile for the Common UNIX Printing System (CUPS).
+#
+# Copyright 1993-2002 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-9600
+# 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 sps.shtml ssr.shtml stp.shtml sum.shtml \
+ svd.shtml
+DOCIMAGES = images/cups-block-diagram.gif images/cups-large.gif \
+ images/cups-medium.gif images/cups-small.gif
+WEBPAGES = cups.css cupsdoc.css index.html documentation.html
+WEBIMAGES = images/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/config-printer.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/restart-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
+
+
+#
+# Make PS files...
+#
+
+ps: $(DOCUMENTS:.shtml=.ps) overview.ps
+
+
+#
+# Remove all generated files...
+#
+
+clean:
+ $(RM) $(DOCUMENTS:.shtml=.pdf)
+ $(RM) $(DOCUMENTS:.shtml=.html)
+ $(RM) overview.pdf
+
+
+#
+# Install all documentation files...
+#
+
+install:
+ $(INSTALL_DIR) $(DOCDIR)
+ for file in $(WEBPAGES); do \
+ $(INSTALL_MAN) $$file $(DOCDIR); \
+ done
+ $(INSTALL_MAN) overview.html $(DOCDIR)
+ $(INSTALL_MAN) overview.pdf $(DOCDIR)
+ for file in $(DOCUMENTS:.shtml=.html); do \
+ $(INSTALL_MAN) $$file $(DOCDIR); \
+ done
+ for file in $(DOCUMENTS:.shtml=.pdf); do \
+ $(INSTALL_MAN) $$file $(DOCDIR); \
+ done
+ $(INSTALL_DIR) $(DOCDIR)/images
+ for file in $(WEBIMAGES) $(DOCIMAGES); do \
+ $(INSTALL_MAN) $$file $(DOCDIR)/images; \
+ done
+
+
+#
+# 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
+overview.ps: overview.html
+ echo Formatting $@...
+ htmldoc --duplex --jpeg --webpage -f overview.ps 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 $@ $<
+sam.ps: sam.shtml
+ echo Formatting $@...
+ htmldoc --titleimage images/cups-large.gif --duplex --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 $@ $<
+spm.ps: spm.shtml
+ echo Formatting $@...
+ htmldoc --titleimage images/cups-large.gif --duplex --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 $@ $<
+sum.ps: sum.shtml
+ echo Formatting $@...
+ htmldoc --titleimage images/cups-large.gif --duplex --jpeg -f $@ $<
+
+sam-7x8.pdf: sam.shtml
+ echo Formatting $@...
+ htmldoc --titleimage images/cups-large.gif --duplex --compression=9 \
+ --pagelayout tworight --pagemode document \
+ --jpeg --size 7x8.5in --left 0.5in --right 0.25in \
+ --top 0.25in --bottom 0.25in --fontsize 10 --headfootsize 10 -f $@ sam.shtml
+sam-7x8.ps: sam.shtml
+ echo Formatting $@...
+ htmldoc --titleimage images/cups-large.gif --duplex --jpeg \
+ --size 7x8.5in --left 0.5in --right 0.25in \
+ --top 0.25in --bottom 0.25in --fontsize 10 --headfootsize 10 -f $@ sam.shtml
+spm-7x8.pdf: spm.shtml
+ echo Formatting $@...
+ htmldoc --titleimage images/cups-large.gif --duplex --compression=9 \
+ --pagelayout tworight --pagemode document \
+ --jpeg --size 7x8.5in --left 0.5in --right 0.25in \
+ --top 0.25in --bottom 0.25in --fontsize 10 --headfootsize 10 -f $@ spm.shtml
+spm-7x8.ps: spm.shtml
+ echo Formatting $@...
+ htmldoc --titleimage images/cups-large.gif --duplex --jpeg \
+ --size 7x8.5in --left 0.5in --right 0.25in \
+ --top 0.25in --bottom 0.25in --fontsize 10 --headfootsize 10 -f $@ spm.shtml
+sum-7x8.pdf: sum.shtml
+ echo Formatting $@...
+ htmldoc --titleimage images/cups-large.gif --duplex --compression=9 \
+ --pagelayout tworight --pagemode document \
+ --jpeg --size 7x8.5in --left 0.5in --right 0.25in \
+ --top 0.25in --bottom 0.25in --fontsize 10 --headfootsize 10 -f $@ sum.shtml
+sum-7x8.ps: sum.shtml
+ echo Formatting $@...
+ htmldoc --titleimage images/cups-large.gif --duplex --jpeg \
+ --size 7x8.5in --left 0.5in --right 0.25in \
+ --top 0.25in --bottom 0.25in --fontsize 10 --headfootsize 10 -f $@ sum.shtml
+
+$(DOCUMENTS:.shtml=.html): \
+ glossary.shtml printing-overview.shtml \
+ references.shtml system-overview.shtml \
+ ../LICENSE.html
+
+$(DOCUMENTS:.shtml=.pdf): \
+ glossary.shtml printing-overview.shtml \
+ references.shtml system-overview.shtml \
+ ../LICENSE.html
+
+$(DOCUMENTS:.shtml=.ps): \
+ glossary.shtml printing-overview.shtml \
+ references.shtml system-overview.shtml \
+ ../LICENSE.html
+
+
+#
+# End of Makefile.
+#
diff --git a/doc/cmp.html b/doc/cmp.html
new file mode 100644
index 000000000..e09db9fc3
--- /dev/null
+++ b/doc/cmp.html
@@ -0,0 +1,677 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD>
+<TITLE>CUPS Configuration Management Plan</TITLE>
+<META NAME="author" CONTENT="Easy Software Products">
+<META NAME="copyright" CONTENT="Copyright 1997-2002, All Rights Reserved">
+<META NAME="docnumber" CONTENT="CUPS-CMP-1.1">
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=iso-8859-1">
+<STYLE TYPE="text/css"><!--
+BODY { font-family: serif }
+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 }
+SUB { font-size: smaller }
+SUP { font-size: smaller }
+PRE { font-family: monospace }
+--></STYLE>
+</HEAD>
+<BODY>
+<CENTER><A HREF="#CONTENTS"><IMG SRC="images/cups-large.gif" BORDER="0" WIDTH="431" HEIGHT="511"><BR>
+<H1>CUPS Configuration Management Plan</H1></A><BR>
+CUPS-CMP-1.1<BR>
+Easy Software Products<BR>
+Copyright 1997-2002, All Rights Reserved<BR>
+</CENTER>
+<HR>
+<H1 ALIGN="CENTER"><A NAME="CONTENTS">Table of Contents</A></H1>
+<BR>
+<BR><B><A HREF="#1">1 Scope</A></B>
+<UL>
+<LI><A HREF="#1_1">1.1 Identification</A></LI>
+<LI><A HREF="#1_2">1.2 System Overview</A></LI>
+<LI><A HREF="#1_3">1.3 Document Overview</A></LI>
+</UL>
+<B><A HREF="#2">2 References</A></B>
+<UL>
+<LI><A HREF="#2_1">2.1 CUPS Documentation</A></LI>
+<LI><A HREF="#2_2">2.2 Other Documents</A></LI>
+</UL>
+<B><A HREF="#3">3 File Management</A></B>
+<UL>
+<LI><A HREF="#3_1">3.1 Directory Structure</A></LI>
+<LI><A HREF="#3_2">3.2 Source Files</A></LI>
+<LI><A HREF="#3_3">3.3 Configuration Management</A></LI>
+</UL>
+<B><A HREF="#4">4 Trouble Report Processing</A></B>
+<UL>
+<LI><A HREF="#4_1">4.1 Classification</A></LI>
+<LI><A HREF="#4_2">4.2 Identification</A></LI>
+<LI><A HREF="#4_3">4.3 Correction</A></LI>
+<LI><A HREF="#4_4">4.4 Notification</A></LI>
+</UL>
+<B><A HREF="#5">5 Software Releases</A></B>
+<UL>
+<LI><A HREF="#5_1">5.1 Version Numbering</A></LI>
+<LI><A HREF="#5_2">5.2 Generation</A></LI>
+<LI><A HREF="#5_3">5.3 Testing</A></LI>
+<LI><A HREF="#5_4">5.4 Release</A></LI>
+</UL>
+<B><A HREF="#6">A Glossary</A></B>
+<UL>
+<LI><A HREF="#6_1">A.1 Terms</A></LI>
+<LI><A HREF="#6_2">A.2 Acronyms</A></LI>
+</UL>
+<B><A HREF="#7">B Coding Requirements</A></B>
+<UL>
+<LI><A HREF="#7_1">B.1 Source Files</A></LI>
+<UL>
+<LI><A HREF="#7_1_1">B.1.1 Naming</A></LI>
+<LI><A HREF="#7_1_2">B.1.2 Documentation</A></LI>
+</UL>
+<LI><A HREF="#7_2">B.2 Functions</A></LI>
+<UL>
+<LI><A HREF="#7_2_1">B.2.1 Naming</A></LI>
+<LI><A HREF="#7_2_2">B.2.2 Documentation</A></LI>
+</UL>
+<LI><A HREF="#7_3">B.3 Methods</A></LI>
+<UL>
+<LI><A HREF="#7_3_1">B.3.1 Naming</A></LI>
+<LI><A HREF="#7_3_2">B.3.2 Documentation</A></LI>
+</UL>
+<LI><A HREF="#7_4">B.4 Variables</A></LI>
+<UL>
+<LI><A HREF="#7_4_1">B.4.1 Naming</A></LI>
+<LI><A HREF="#7_4_2">B.4.2 Documentation</A></LI>
+</UL>
+<LI><A HREF="#7_5">B.5 Types</A></LI>
+<UL>
+<LI><A HREF="#7_5_1">B.5.1 Naming</A></LI>
+<LI><A HREF="#7_5_2">B.5.2 Documentation</A></LI>
+</UL>
+<LI><A HREF="#7_6">B.6 Structures</A></LI>
+<UL>
+<LI><A HREF="#7_6_1">B.6.1 Naming</A></LI>
+<LI><A HREF="#7_6_2">B.6.2 Documentation</A></LI>
+</UL>
+<LI><A HREF="#7_7">B.7 Classes</A></LI>
+<UL>
+<LI><A HREF="#7_7_1">B.7.1 Naming</A></LI>
+<LI><A HREF="#7_7_2">B.7.2 Documentation</A></LI>
+</UL>
+<LI><A HREF="#7_8">B.8 Constants</A></LI>
+<UL>
+<LI><A HREF="#7_8_1">B.8.1 Naming</A></LI>
+<LI><A HREF="#7_8_2">B.8.2 Documentation</A></LI>
+</UL>
+<LI><A HREF="#7_9">B.9 Code</A></LI>
+<UL>
+<LI><A HREF="#7_9_1">B.9.1 Documentation</A></LI>
+<LI><A HREF="#7_9_2">B.9.2 Style</A></LI>
+</UL>
+</UL>
+<B><A HREF="#8">C Software Trouble Report Form</A></B><HR>
+<H1><A NAME="1">1 Scope</A></H1>
+<H2><A NAME="1_1">1.1 Identification</A></H2>
+ This configuration management plan document provides the guidelines for
+ development and maintenance of the Common UNIX Printing System (&quot;CUPS&quot;)
+ Version 1.1 software.
+<H2><A NAME="1_2">1.2 System Overview</A></H2>
+<P>CUPS provides a portable printing layer for UNIX&reg;-based operating
+ systems. It has been developed by<A HREF="http://www.easysw.com"> Easy
+ Software Products</A> to promote a standard printing solution for all
+ UNIX vendors and users. CUPS provides the System V and Berkeley
+ command-line interfaces.</P>
+<P>CUPS uses the Internet Printing Protocol (&quot;IPP&quot;) as the basis for
+ managing print jobs and queues. The Line Printer Daemon (&quot;LPD&quot;) Server
+ Message Block (&quot;SMB&quot;), and AppSocket (a.k.a. JetDirect) protocols are
+ also supported with reduced functionality. CUPS adds network printer
+ browsing and PostScript Printer Description (&quot;PPD&quot;) based printing
+ options to support real-world printing under UNIX.</P>
+<P>CUPS also includes a customized version of GNU Ghostscript (currently
+ based off GNU Ghostscript 5.50) and an image file RIP that are used to
+ support non-PostScript printers. Sample drivers for HP and EPSON
+ printers are included that use these filters.</P>
+<H2><A NAME="1_3">1.3 Document Overview</A></H2>
+ This configuration management document is organized into the following
+ sections:
+<UL>
+<LI>1 - Scope</LI>
+<LI>2 - References</LI>
+<LI>3 - File Management</LI>
+<LI>4 - Trouble Report Processing</LI>
+<LI>5 - Software Releases</LI>
+<LI>A - Glossary</LI>
+<LI>B - Coding Requirements</LI>
+</UL>
+<H1><A NAME="2">2 References</A></H1>
+<H2><A NAME="2_1">2.1 CUPS Documentation</A></H2>
+<P>The following CUPS documentation is referenced by this document:</P>
+<UL>
+<LI>CUPS-CMP-1.1: CUPS Configuration Management Plan</LI>
+<LI>CUPS-IDD-1.1: CUPS System Interface Design Description</LI>
+<LI>CUPS-IPP-1.1: CUPS Implementation of IPP</LI>
+<LI>CUPS-SAM-1.1.x: CUPS Software Administrators Manual</LI>
+<LI>CUPS-SDD-1.1: CUPS Software Design Description</LI>
+<LI>CUPS-SPM-1.1.x: CUPS Software Programming Manual</LI>
+<LI>CUPS-SSR-1.1: CUPS Software Security Report</LI>
+<LI>CUPS-STP-1.1: CUPS Software Test Plan</LI>
+<LI>CUPS-SUM-1.1.x: CUPS Software Users Manual</LI>
+<LI>CUPS-SVD-1.1: CUPS Software Version Description</LI>
+</UL>
+<H2><A NAME="2_2">2.2 Other Documents</A></H2>
+<P>The following non-CUPS documents are referenced by this document:</P>
+<UL>
+<LI><A HREF="http://partners.adobe.com/asn/developer/PDFS/TN/5003.PPD_Spec_v4.3.pdf">
+Adobe PostScript Printer Description File Format Specification, Version
+ 4.3.</A></LI>
+<LI><A HREF="http://partners.adobe.com/asn/developer/PDFS/TN/PLRM.pdf">
+Adobe PostScript Language Reference, Third Edition.</A></LI>
+<LI>IPP: Job and Printer Set Operations</LI>
+<LI>IPP/1.1: Encoding and Transport</LI>
+<LI>IPP/1.1: Implementers Guide</LI>
+<LI>IPP/1.1: Model and Semantics</LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc1179.txt">RFC 1179, Line Printer
+ Daemon Protocol</A></LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc2567.txt">RFC 2567, Design Goals
+ for an Internet Printing Protocol</A></LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc2568.txt">RFC 2568, Rationale
+ for the Structure of the Model and Protocol</A> for the Internet
+ Printing Protocol</LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc2569.txt">RFC 2569, Mapping
+ between LPD and IPP Protocols</A></LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616, Hypertext
+ Transfer Protocol -- HTTP/1.1</A></LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc2617.txt">RFC 2617, HTTP
+ Authentication: Basic and Digest Access</A> Authentication</LI>
+</UL>
+<H1><A NAME="3">3 File Management</A></H1>
+<H2><A NAME="3_1">3.1 Directory Structure</A></H2>
+ Each source file shall be placed a sub-directory corresponding to the
+ software sub-system it belongs to (&quot;scheduler&quot;, &quot;cups&quot;, etc.) To remain
+ compatible with older UNIX filesystems, directory names shall not
+ exceed 16 characters in length.
+<H2><A NAME="3_2">3.2 Source Files</A></H2>
+ Source files shall be documented and formatted as described in Appendix
+ B, Coding Requirements.
+<H2><A NAME="3_3">3.3 Configuration Management</A></H2>
+ Source files shall be placed under the control of the Concurrent
+ Versions System (&quot;CVS&quot;) software. Source files shall be &quot;checked in&quot;
+ with each change so that modifications can be tracked.
+<P>Documentation on the CVS software is included with the whitepaper,
+ &quot;CVS II: Parallelizing Software Development&quot;.</P>
+<H1><A NAME="4">4 Trouble Report Processing</A></H1>
+ A Software Trouble Report (&quot;STR&quot;) 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:
+<OL>
+<LI>STR is closed with complete resolution</LI>
+<LI>STR is closed without resolution</LI>
+<LI>STR is active</LI>
+<LI>STR is pending (new STR or additional information available)</LI>
+</OL>
+ Trouble reports shall be processed using the following steps.
+<H2><A NAME="4_1">4.1 Classification</A></H2>
+ When a trouble report is received it must be classified at one of the
+ following levels:
+<OL>
+<LI>Request for enhancement</LI>
+<LI>Documentation error</LI>
+<LI>Unable to print a file</LI>
+<LI>Unable to print to a printer</LI>
+<LI>Unable to print at all</LI>
+</OL>
+ The scope of the problem should also be determined as:
+<OL>
+<LI>Specific to a machine</LI>
+<LI>Specific to an operating system</LI>
+<LI>Applies to all machines and operating systems</LI>
+</OL>
+<H2><A NAME="4_2">4.2 Identification</A></H2>
+ 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.
+<P>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).</P>
+<H2><A NAME="4_3">4.3 Correction</A></H2>
+ 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.
+<H2><A NAME="4_4">4.4 Notification</A></H2>
+ The user or vendor is notified when the fix is available or if the
+ problem was caused by user error.
+<H1><A NAME="5">5 Software Releases</A></H1>
+<H2><A NAME="5_1">5.1 Version Numbering</A></H2>
+ CUPS uses a three-part version number separated by periods to represent
+ the major, minor, and patch release numbers:
+<UL>
+<PRE>
+major.minor.patch
+1.1.0
+</PRE>
+</UL>
+ Beta-test releases are indentified by appending the letter B followed
+ by the build number:
+<UL>
+<PRE>
+major.minor.patchbbuild
+1.1.0b1
+</PRE>
+</UL>
+ A CVS snapshot is generated for every beta and final release and uses
+ the version number preceded by the letter &quot;v&quot; and with the decimal
+ points replaced by underscores:
+<UL>
+<PRE>
+v1_0_0b1
+v1_0_0
+</PRE>
+</UL>
+ 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:
+<UL>
+<PRE>
+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
+</PRE>
+</UL>
+<H2><A NAME="5_2">5.2 Generation</A></H2>
+ 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.
+<H2><A NAME="5_3">5.3 Testing</A></H2>
+ 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.
+<H2><A NAME="5_4">5.4 Release</A></H2>
+ When testing has been completed successfully a new distribution image
+ is created from the current CVS code &quot;snapshot&quot;. No production release
+ shall contain software that has not passed the appropriate software
+ tests.
+<H1 TYPE="A" VALUE="1"><A NAME="6">A Glossary</A></H1>
+<H2><A NAME="6_1">A.1 Terms</A></H2>
+<DL>
+<DT>C</DT>
+<DD>A computer language.</DD>
+<DT>parallel</DT>
+<DD>Sending or receiving data more than 1 bit at a time.</DD>
+<DT>pipe</DT>
+<DD>A one-way communications channel between two programs.</DD>
+<DT>serial</DT>
+<DD>Sending or receiving data 1 bit at a time.</DD>
+<DT>socket</DT>
+<DD>A two-way network communications channel.</DD>
+</DL>
+<H2><A NAME="6_2">A.2 Acronyms</A></H2>
+<DL>
+<DT>ASCII</DT>
+<DD>American Standard Code for Information Interchange</DD>
+<DT>CUPS</DT>
+<DD>Common UNIX Printing System</DD>
+<DT>ESC/P</DT>
+<DD>EPSON Standard Code for Printers</DD>
+<DT>FTP</DT>
+<DD>File Transfer Protocol</DD>
+<DT>HP-GL</DT>
+<DD>Hewlett-Packard Graphics Language</DD>
+<DT>HP-PCL</DT>
+<DD>Hewlett-Packard Page Control Language</DD>
+<DT>HP-PJL</DT>
+<DD>Hewlett-Packard Printer Job Language</DD>
+<DT>IETF</DT>
+<DD>Internet Engineering Task Force</DD>
+<DT>IPP</DT>
+<DD>Internet Printing Protocol</DD>
+<DT>ISO</DT>
+<DD>International Standards Organization</DD>
+<DT>LPD</DT>
+<DD>Line Printer Daemon</DD>
+<DT>MIME</DT>
+<DD>Multimedia Internet Mail Exchange</DD>
+<DT>PPD</DT>
+<DD>PostScript Printer Description</DD>
+<DT>SMB</DT>
+<DD>Server Message Block</DD>
+<DT>TFTP</DT>
+<DD>Trivial File Transfer Protocol</DD>
+</DL>
+<H1><A NAME="7">B Coding Requirements</A></H1>
+ 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.
+<H2><A NAME="7_1">B.1 Source Files</A></H2>
+<H3><A NAME="7_1_1">B.1.1 Naming</A></H3>
+ 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 &quot;.c&quot; for ANSI C and
+ &quot;.cxx&quot; for C++ source files. All other &quot;include&quot; files shall have an
+ extension of &quot;.h&quot;.
+<H3><A NAME="7_1_2">B.1.2 Documentation</A></H3>
+ 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 &quot;$Id$&quot; tag:
+<UL>
+<PRE>
+/*
+ * &quot;$Id$&quot;
+ *
+ * Description of file contents.
+ *
+ * Copyright 1997-2002 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 &quot;LICENSE.txt&quot; 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-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * Contents:
+ *
+ * function1() - Description 1.
+ * function2() - Description 2.
+ * function3() - Description 3.
+ */
+</PRE>
+</UL>
+ The bottom of each source file shall contain a trailer giving the name
+ of the file using the CVS &quot;$Id$&quot; 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:
+<UL>
+<PRE>
+/*
+ * End of &quot;$Id$&quot;.
+ */
+</PRE>
+</UL>
+<H2><A NAME="7_2">B.2 Functions</A></H2>
+<H3><A NAME="7_2_1">B.2.1 Naming</A></H3>
+ Functions with a global scope shall be capitalized (&quot;DoThis&quot;, &quot;DoThat&quot;,
+ &quot;DoSomethingElse&quot;, etc.) The only exception to this rule shall be the
+ CUPS interface library functions which may begin with a prefix word in
+ lowercase (&quot;cupsDoThis&quot;, &quot;cupsDoThat&quot;, etc.)
+<P>Functions with a local scope shall be declared &quot;static&quot; and be
+ lowercase with underscores between words (&quot;do_this&quot;, &quot;do_that&quot;,
+ &quot;do_something_else&quot;, etc.)</P>
+<H3><A NAME="7_2_2">B.2.2 Documentation</A></H3>
+ 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:
+<UL>
+<PRE>
+/*
+ * 'do_this()' - Compute y = this(x).
+ *
+ * Notes: none.
+ */
+
+static float /* O - Inverse power value, 0.0 &lt;= y &lt;= 1.1 */
+do_this(float x) /* I - Power value (0.0 &lt;= x &lt;= 1.1) */
+{
+ ...
+ return (y);
+}
+</PRE>
+</UL>
+<H2><A NAME="7_3">B.3 Methods</A></H2>
+<H3><A NAME="7_3_1">B.3.1 Naming</A></H3>
+ Methods shall be in lowercase with underscores between words
+ (&quot;do_this&quot;, &quot;do_that&quot;, &quot;do_something_else&quot;, etc.)
+<H3><A NAME="7_3_2">B.3.2 Documentation</A></H3>
+ 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:
+<UL>
+<PRE>
+/*
+ * 'class::do_this()' - Compute y = this(x).
+ *
+ * Notes: none.
+ */
+
+float /* O - Inverse power value, 0.0 &lt;= y &lt;= 1.0 */
+class::do_this(float x) /* I - Power value (0.0 &lt;= x &lt;= 1.0) */
+{
+ ...
+ return (y);
+}
+</PRE>
+</UL>
+<H2><A NAME="7_4">B.4 Variables</A></H2>
+<H3><A NAME="7_4_1">B.4.1 Naming</A></H3>
+ Variables with a global scope shall be capitalized (&quot;ThisVariable&quot;,
+ &quot;ThatVariable&quot;, &quot;ThisStateVariable&quot;, etc.) The only exception to this
+ rule shall be the CUPS interface library global variables which must
+ begin with the prefix &quot;cups&quot; (&quot;cupsThisVariable&quot;, &quot;cupsThatVariable&quot;,
+ etc.) Global variables shall be replaced by function arguments whenever
+ possible.
+<P>Variables with a local scope shall be lowercase with underscores
+ between words (&quot;this_variable&quot;, &quot;that_variable&quot;, etc.) Any local
+ variables shared by functions within a source file shall be declared
+ &quot;static&quot;.</P>
+<H3><A NAME="7_4_2">B.4.2 Documentation</A></H3>
+ Each variable shall be declared on a separate line and shall be
+ immediately followed by a comment block describing the variable:
+<UL>
+<PRE>
+int this_variable; /* The current state of this */
+int that_variable; /* The current state of that */
+</PRE>
+</UL>
+<H2><A NAME="7_5">B.5 Types</A></H2>
+<H3><A NAME="7_5_1">B.5.1 Naming</A></H3>
+ All type names shall be lowercase with underscores between words and
+ &quot;_t&quot; appended to the end of the name (&quot;this_type_t&quot;, &quot;that_type_t&quot;,
+ etc.)
+<H3><A NAME="7_5_2">B.5.2 Documentation</A></H3>
+ Each type shall have a comment block immediately before the typedef:
+<UL>
+<PRE>
+/*
+ * This type is for CUPS foobar options.
+ */
+typedef int cups_this_type_t;
+</PRE>
+</UL>
+<H2><A NAME="7_6">B.6 Structures</A></H2>
+<H3><A NAME="7_6_1">B.6.1 Naming</A></H3>
+ All structure names shall be lowercase with underscores between words
+ and &quot;_str&quot; appended to the end of the name (&quot;this_struct_str&quot;,
+ &quot;that_struct_str&quot;, etc.)
+<H3><A NAME="7_6_2">B.6.2 Documentation</A></H3>
+ 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:
+<UL>
+<PRE>
+/*
+ * 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 */
+};
+</PRE>
+</UL>
+<H2><A NAME="7_7">B.7 Classes</A></H2>
+<H3><A NAME="7_7_1">B.7.1 Naming</A></H3>
+ All class names shall be lowercase with underscores between words
+ (&quot;this_class&quot;, &quot;that_class&quot;, etc.)
+<H3><A NAME="7_7_2">B.7.2 Documentation</A></H3>
+ 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:
+<UL>
+<PRE>
+/*
+ * 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 */
+};
+</PRE>
+</UL>
+<H2><A NAME="7_8">B.8 Constants</A></H2>
+<H3><A NAME="7_8_1">B.8.1 Naming</A></H3>
+ All constant names shall be uppercase with underscored between words
+ (&quot;THIS_CONSTANT&quot;, &quot;THAT_CONSTANT&quot;, etc.) Constants defined for the CUPS
+ interface library must begin with an uppercase prefix
+ (&quot;CUPS_THIS_CONSTANT&quot;, &quot;CUPS_THAT_CONSTANT&quot;, etc.)
+<P>Typed enumerations shall be used whenever possible to allow for type
+ checking by the compiler.</P>
+<H3><A NAME="7_8_2">B.8.2 Documentation</A></H3>
+ Comment blocks shall immediately follow each constant:
+<UL>
+<PRE>
+enum
+{
+ CUPS_THIS_TRAY, /* This tray */
+ CUPS_THAT_TRAY /* That tray */
+};
+</PRE>
+</UL>
+<H2><A NAME="7_9">B.9 Code</A></H2>
+<H3><A NAME="7_9_1">B.9.1 Documentation</A></H3>
+ All source code shall utilize block comments within functions to
+ describe the operations being performed by a group of statements:
+<UL>
+<PRE>
+/*
+ * Clear the state array before we begin...
+ */
+
+for (i = 0; i &lt; (sizeof(array) / sizeof(sizeof(array[0])); i ++)
+ array[i] = STATE_IDLE;
+
+/*
+ * Wait for state changes...
+ */
+
+do
+{
+ for (i = 0; i &lt; (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])));
+</PRE>
+</UL>
+<H3><A NAME="7_9_2">B.9.2 Style</A></H3>
+<H4 TYPE="a">B.9.2.a Indentation</H4>
+ 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:
+<UL>
+<PRE>
+{
+ int i; /* Looping var */
+
+ /*
+ * Process foobar values from 0 to 999...
+ */
+
+ for (i = 0; i &lt; 1000; i ++)
+ {
+ do_this(i);
+ do_that(i);
+ }
+}
+</PRE>
+</UL>
+ Single-line statements following &quot;do&quot;, &quot;else&quot;, &quot;for&quot;, &quot;if&quot;, and &quot;while&quot;
+ shall be indented 2 spaces as well. Blocks of code in a &quot;switch&quot; block
+ shall be indented 4 spaces after each &quot;case&quot; and &quot;default&quot; case:
+<UL>
+<PRE>
+switch (array[i])
+{
+ case STATE_IDLE :
+ do_this(i);
+ do_that(i);
+ break;
+ default :
+ do_nothing(i);
+ break;
+}
+</PRE>
+</UL>
+<H4>B.9.2.b Spacing</H4>
+ A space shall follow each reserved word (&quot;if&quot;, &quot;while&quot;, etc.) Spaces
+ shall not be inserted between a function name and the arguments in
+ parenthesis.
+<H4>B.9.2.c Return Values</H4>
+ Parenthesis shall surround values returned from a function using
+ &quot;return&quot;:
+<UL>
+<PRE>
+return (STATE_IDLE);
+</PRE>
+</UL>
+<H4>B.9.2.d Loops</H4>
+ Whenever convenient loops should count downward to zero to improve
+ program performance:
+<UL>
+<PRE>
+for (i = sizeof(array) / sizeof(array[0]) - 1; i &gt;= 0; i --)
+ array[i] = STATE_IDLE;
+</PRE>
+</UL>
+<H1 ALIGN="RIGHT"><A NAME="8">C Software Trouble Report Form</A></H1>
+<CENTER>
+<TABLE WIDTH="80%">
+<TR><TH ALIGN="RIGHT">Summary of Problem:</TH><TD ALIGN="LEFT">
+________________________________________</TD></TR>
+<TR><TH ALIGN="RIGHT">Problem Severity:</TH><TD ALIGN="LEFT">__1=RFE
+<BR> __2=Documentation-Error
+<BR> __3=Unable-to-Print-a-File
+<BR> __4=Unable-to-Print-to-a-Printer
+<BR> __5=Unable-to-Print-at-All</TD></TR>
+<TR><TH ALIGN="RIGHT">Problem Scope:</TH><TD ALIGN="LEFT">__1=Machine
+ __2=Operating-System __3=All</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Detailed Description of Problem:</TH><TD
+ALIGN="LEFT">________________________________________
+<BR> ________________________________________
+<BR> ________________________________________
+<BR> ________________________________________
+<BR> ________________________________________
+<BR> ________________________________________</TD></TR>
+</TABLE>
+</CENTER>
+</BODY>
+</HTML>
diff --git a/doc/cmp.pdf b/doc/cmp.pdf
new file mode 100644
index 000000000..253e0a645
--- /dev/null
+++ b/doc/cmp.pdf
Binary files differ
diff --git a/doc/cmp.shtml b/doc/cmp.shtml
new file mode 100644
index 000000000..1e7d42cff
--- /dev/null
+++ b/doc/cmp.shtml
@@ -0,0 +1,595 @@
+<HTML>
+<HEAD>
+ <META NAME="DOCNUMBER" CONTENT="CUPS-CMP-1.1">
+ <META NAME="COPYRIGHT" CONTENT="Copyright 1997-2002, All Rights Reserved">
+ <META NAME="Author" CONTENT="Easy Software Products">
+ <TITLE>CUPS Configuration Management Plan</TITLE>
+</HEAD>
+<BODY>
+
+<H1>Scope</H1>
+
+<H2>Identification</H2>
+
+This configuration management plan document provides the guidelines for
+development and maintenance of the Common UNIX Printing System ("CUPS")
+Version 1.1 software.
+
+<EMBED SRC="system-overview.shtml">
+
+<H2>Document Overview</H2>
+
+This configuration management document is organized into the following
+sections:
+
+<UL>
+ <LI>1 - Scope</LI>
+ <LI>2 - References</LI>
+ <LI>3 - File Management</LI>
+ <LI>4 - Trouble Report Processing</LI>
+ <LI>5 - Software Releases</LI>
+ <LI>A - Glossary</LI>
+ <LI>B - Coding Requirements</LI>
+</UL>
+
+<EMBED SRC="references.shtml">
+
+<H1>File Management</H1>
+
+<H2>Directory Structure</H2>
+
+Each source file shall be placed a sub-directory corresponding to the software
+sub-system it belongs to ("scheduler", "cups", etc.) To remain compatible
+with older UNIX filesystems, directory names shall not exceed 16 characters
+in length.
+
+<H2>Source Files</H2>
+
+Source files shall be documented and formatted as described in Appendix
+B, Coding Requirements.
+
+<H2>Configuration Management</H2>
+
+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.
+
+<P>Documentation on the CVS software is included with the whitepaper, "CVS
+II: Parallelizing Software Development".
+
+<H1>Trouble Report Processing</H1>
+
+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:
+
+<OL>
+ <LI>STR is closed with complete resolution</LI>
+ <LI>STR is closed without resolution</LI>
+ <LI>STR is active</LI>
+ <LI>STR is pending (new STR or additional information available)</LI>
+</OL>
+
+Trouble reports shall be processed using the following steps.
+
+<H2>Classification</H2>
+
+When a trouble report is received it must be classified at one of the following
+levels:
+
+<OL>
+ <LI>Request for enhancement</LI>
+ <LI>Documentation error</LI>
+ <LI>Unable to print a file</LI>
+ <LI>Unable to print to a printer</LI>
+ <LI>Unable to print at all</LI>
+</OL>
+
+The scope of the problem should also be determined as:
+
+<OL>
+ <LI>Specific to a machine</LI>
+ <LI>Specific to an operating system</LI>
+ <LI>Applies to all machines and operating systems</LI>
+</OL>
+
+<H2>Identification</H2>
+
+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.
+
+<P>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).
+
+<H2>Correction</H2>
+
+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.
+
+<H2>Notification</H2>
+
+The user or vendor is notified when the fix is available or if the problem
+was caused by user error.
+
+<H1>Software Releases</H1>
+
+<H2>Version Numbering</H2>
+
+CUPS uses a three-part version number separated by periods to represent
+the major, minor, and patch release numbers:
+
+<UL>
+<PRE>
+major.minor.patch
+1.1.0
+</PRE>
+</UL>
+
+Beta-test releases are indentified by appending the letter B followed by
+the build number:
+
+<UL>
+<PRE>
+major.minor.patchbbuild
+1.1.0b1
+</PRE>
+</UL>
+
+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:
+
+<UL>
+<PRE>
+v1_0_0b1
+v1_0_0
+</PRE>
+</UL>
+
+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:
+
+<UL>
+<PRE>
+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
+</PRE>
+</UL>
+
+<H2>Generation</H2>
+
+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.
+
+<H2>Testing</H2>
+
+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.
+
+<H2>Release</H2>
+
+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.
+
+<EMBED SRC="glossary.shtml">
+
+<H1>Coding Requirements</H1>
+
+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.
+
+<H2>Source Files</H2>
+
+<H3>Naming</H3>
+
+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".
+
+<H3>Documentation</H3>
+
+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 "&#36;Id$" tag:
+
+<UL>
+<PRE>
+/*
+ * "&#36;Id$"
+ *
+ * Description of file contents.
+ *
+ * Copyright 1997-2002 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-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * Contents:
+ *
+ * function1() - Description 1.
+ * function2() - Description 2.
+ * function3() - Description 3.
+ */
+</PRE>
+</UL>
+
+The bottom of each source file shall contain a trailer giving the name
+of the file using the CVS "&#36;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:
+
+<UL>
+<PRE>
+/*
+ * End of "&#36;Id$".
+ */
+</PRE>
+</UL>
+
+<H2>Functions</H2>
+
+<H3>Naming</H3>
+
+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.)
+
+<P>Functions with a local scope shall be declared "static" and be lowercase
+with underscores between words ("do_this", "do_that", "do_something_else",
+etc.)
+
+<H3>Documentation</H3>
+
+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:
+
+<UL>
+<PRE>
+/*
+ * 'do_this()' - Compute y = this(x).
+ *
+ * Notes: none.
+ */
+
+static float /* O - Inverse power value, 0.0 &lt;= y &lt;= 1.1 */
+do_this(float x) /* I - Power value (0.0 &lt;= x &lt;= 1.1) */
+{
+ ...
+ return (y);
+}
+</PRE>
+</UL>
+
+<H2>Methods</H2>
+
+<H3>Naming</H3>
+
+Methods shall be in lowercase with underscores between words ("do_this",
+"do_that", "do_something_else", etc.)
+
+<H3>Documentation</H3>
+
+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:
+
+<UL>
+<PRE>
+/*
+ * 'class::do_this()' - Compute y = this(x).
+ *
+ * Notes: none.
+ */
+
+float /* O - Inverse power value, 0.0 &lt;= y &lt;= 1.0 */
+class::do_this(float x) /* I - Power value (0.0 &lt;= x &lt;= 1.0) */
+{
+ ...
+ return (y);
+}
+</PRE>
+</UL>
+
+<H2>Variables</H2>
+
+<H3>Naming</H3>
+
+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.
+
+<P>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".
+
+<H3>Documentation</H3>
+
+Each variable shall be declared on a separate line and shall be immediately
+followed by a comment block describing the variable:
+
+<UL><PRE>
+int this_variable; /* The current state of this */
+int that_variable; /* The current state of that */
+</PRE></UL>
+
+<H2>Types</H2>
+
+<H3>Naming</H3>
+
+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.)
+
+<H3>Documentation</H3>
+
+Each type shall have a comment block immediately before the typedef:
+
+<UL>
+<PRE>
+/*
+ * This type is for CUPS foobar options.
+ */
+typedef int cups_this_type_t;
+</PRE>
+</UL>
+
+<H2>Structures</H2>
+
+<H3>Naming</H3>
+
+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.)
+
+<H3>Documentation</H3>
+
+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:
+
+<UL>
+<PRE>
+/*
+ * 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 */
+};
+</PRE>
+</UL>
+
+<H2>Classes</H2>
+
+<H3>Naming</H3>
+
+All class names shall be lowercase with underscores between words
+("this_class", "that_class", etc.)
+
+<H3>Documentation</H3>
+
+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:
+
+<UL>
+<PRE>
+/*
+ * 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 */
+};
+</PRE>
+</UL>
+
+<H2>Constants</H2>
+
+<H3>Naming</H3>
+
+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.)
+
+<P>Typed enumerations shall be used whenever possible to allow for type
+checking by the compiler.
+
+<H3>Documentation</H3>
+
+Comment blocks shall immediately follow each constant:
+
+<UL>
+<PRE>
+enum
+{
+ CUPS_THIS_TRAY, /* This tray */
+ CUPS_THAT_TRAY /* That tray */
+};
+</PRE>
+</UL>
+
+<H2>Code</H2>
+
+<H3>Documentation</H3>
+
+All source code shall utilize block comments within functions to describe
+the operations being performed by a group of statements:
+
+<UL>
+<PRE>
+/*
+ * Clear the state array before we begin...
+ */
+
+for (i = 0; i &lt; (sizeof(array) / sizeof(sizeof(array[0])); i ++)
+ array[i] = STATE_IDLE;
+
+/*
+ * Wait for state changes...
+ */
+
+do
+{
+ for (i = 0; i &lt; (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])));
+</PRE>
+</UL>
+
+<H3>Style</H3>
+
+<H4 TYPE="a">Indentation</H4>
+
+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:
+
+<UL>
+<PRE>
+{
+ int i; /* Looping var */
+
+ /*
+ * Process foobar values from 0 to 999...
+ */
+
+ for (i = 0; i &lt; 1000; i ++)
+ {
+ do_this(i);
+ do_that(i);
+ }
+}
+</PRE>
+</UL>
+
+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:
+
+<UL>
+<PRE>
+switch (array[i])
+{
+ case STATE_IDLE :
+ do_this(i);
+ do_that(i);
+ break;
+ default :
+ do_nothing(i);
+ break;
+}
+</PRE>
+</UL>
+
+<H4>Spacing</H4>
+
+A space shall follow each reserved word ("if", "while", etc.) Spaces shall
+not be inserted between a function name and the arguments in parenthesis.
+
+<H4>Return Values</H4>
+
+Parenthesis shall surround values returned from a function using "return":
+
+<UL>
+<PRE>
+return (STATE_IDLE);
+</PRE>
+</UL>
+
+<H4>Loops</H4>
+
+Whenever convenient loops should count downward to zero to improve program
+performance:
+
+<UL>
+<PRE>
+for (i = sizeof(array) / sizeof(array[0]) - 1; i >= 0; i --)
+ array[i] = STATE_IDLE;
+</PRE>
+</UL>
+
+<H1 ALIGN=RIGHT>Software Trouble Report Form</H1>
+
+<CENTER><TABLE WIDTH="80%">
+<TR>
+ <TH ALIGN=RIGHT>Summary of Problem:</TH>
+ <TD ALIGN=LEFT>________________________________________</TD>
+</TR>
+
+<TR>
+ <TH ALIGN=RIGHT>Problem Severity:</TH>
+ <TD ALIGN=LEFT>__1=RFE
+ <BR>__2=Documentation-Error
+ <BR>__3=Unable-to-Print-a-File
+ <BR>__4=Unable-to-Print-to-a-Printer
+ <BR>__5=Unable-to-Print-at-All</TD>
+</TR>
+
+<TR>
+ <TH ALIGN=RIGHT>Problem Scope:</TH>
+ <TD ALIGN=LEFT>__1=Machine __2=Operating-System __3=All</TD>
+</TR>
+
+<TR>
+ <TH ALIGN=RIGHT VALIGN=TOP>Detailed Description of Problem:</TH>
+ <TD ALIGN=LEFT>________________________________________
+ <BR>________________________________________
+ <BR>________________________________________
+ <BR>________________________________________
+ <BR>________________________________________
+ <BR>________________________________________</TD>
+</TR>
+</TABLE></CENTER>
+
+</BODY>
+</HTML>
diff --git a/doc/cups.css b/doc/cups.css
new file mode 100644
index 000000000..9285a5b5e
--- /dev/null
+++ b/doc/cups.css
@@ -0,0 +1,4 @@
+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 000000000..333f20144
--- /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 000000000..02926cbf1
--- /dev/null
+++ b/doc/documentation.html
@@ -0,0 +1,81 @@
+<HTML>
+<HEAD>
+ <TITLE>Documentation - Common UNIX Printing System</TITLE>
+ <LINK REL=STYLESHEET TYPE="text/css" HREF="cups.css">
+ <MAP NAME="navbar">
+ <AREA SHAPE="RECT" COORDS="12,10,50,20" HREF="http://www.easysw.com" ALT="Easy Software Products Home Page">
+ <AREA SHAPE="RECT" COORDS="82,10,196,20" HREF="/admin" ALT="Do Administration Tasks">
+ <AREA SHAPE="RECT" COORDS="216,10,280,20" HREF="/classes" ALT="Manage Printer Classes Status">
+ <AREA SHAPE="RECT" COORDS="300,10,336,20" HREF="/documentation.html" ALT="On-Line Help">
+ <AREA SHAPE="RECT" COORDS="356,10,394,20" HREF="/jobs" ALT="Manage Jobs">
+ <AREA SHAPE="RECT" COORDS="414,10,476,20" HREF="/printers" ALT="Manage Printers">
+ <AREA SHAPE="RECT" COORDS="496,10,568,20" HREF="http://www.cups.org" ALT="Download the Current CUPS Software">
+ </MAP>
+</HEAD>
+
+<BODY BGCOLOR="#cccc99" TEXT="#000000" LINK="#0000FF" VLINK="#FF00FF">
+<CENTER>
+<IMG SRC="/images/navbar.gif" WIDTH="583" HEIGHT="30" USEMAP="#navbar" BORDER="0" ALT="Common UNIX Printing System">
+</CENTER>
+
+<H1>Documentation</H1>
+
+The following documentation for CUPS is available on this server:
+
+<UL>
+
+ <LI>Whitepaper - An Overview of the Common UNIX Printing System (
+ <A HREF="overview.html">HTML</A> |
+ <A HREF="overview.pdf">PDF</A> )
+
+ <LI>Software Users Manual (
+ <A HREF="sum.html">HTML</A> |
+ <A HREF="sum.pdf">PDF</A> )
+
+ <LI>Software Administrators Manual (
+ <A HREF="sam.html">HTML</A> |
+ <A HREF="sam.pdf">PDF</A> )
+
+ <LI>Software Programmers Manual (
+ <A HREF="spm.html">HTML</A> |
+ <A HREF="spm.pdf">PDF</A> )
+
+ <LI>Configuration Management Plan (
+ <A HREF="cmp.html">HTML</A> |
+ <A HREF="cmp.pdf">PDF</A> )
+
+ <LI>CUPS Implementation of IPP (
+ <A HREF="ipp.html">HTML</A> |
+ <A HREF="ipp.pdf">PDF</A> )
+
+ <LI>Interface Design Description (
+ <A HREF="idd.html">HTML</A> |
+ <A HREF="idd.pdf">PDF</A> )
+
+ <LI>Software Design Description (
+ <A HREF="sdd.html">HTML</A> |
+ <A HREF="sdd.pdf">PDF</A> )
+
+ <LI>Software Performance Specification (
+ <A HREF="sps.html">HTML</A> |
+ <A HREF="sps.pdf">PDF</A> )
+
+ <LI>Software Version Description (
+ <A HREF="svd.html">HTML</A> |
+ <A HREF="svd.pdf">PDF</A> )
+
+ <LI>Software Security Report (
+ <A HREF="ssr.html">HTML</A> |
+ <A HREF="ssr.pdf">PDF</A> )
+
+</UL>
+
+<HR>
+
+<P>The Common UNIX Printing System, CUPS, and the CUPS logo are the
+trademark property of <A HREF="http://www.easysw.com">Easy Software
+Products</A>. CUPS is copyright 1997-2002 by Easy Software Products,
+All Rights Reserved.
+
+</BODY>
+</HTML>
diff --git a/doc/figures.sc b/doc/figures.sc
new file mode 100644
index 000000000..f51e814a6
--- /dev/null
+++ b/doc/figures.sc
Binary files differ
diff --git a/doc/glossary.shtml b/doc/glossary.shtml
new file mode 100644
index 000000000..2cc0c1c89
--- /dev/null
+++ b/doc/glossary.shtml
@@ -0,0 +1,73 @@
+<H1 TYPE="A" VALUE="1">Glossary</H1>
+
+<H2>Terms</H2>
+
+<DL>
+
+ <DT>C
+ <DD>A computer language.
+
+ <DT>parallel
+ <DD>Sending or receiving data more than 1 bit at a time.
+
+ <DT>pipe
+ <DD>A one-way communications channel between two programs.
+
+ <DT>serial
+ <DD>Sending or receiving data 1 bit at a time.
+
+ <DT>socket
+ <DD>A two-way network communications channel.
+
+</DL>
+
+<H2>Acronyms</H2>
+
+<DL>
+
+ <DT>ASCII
+ <DD>American Standard Code for Information Interchange
+
+ <DT>CUPS
+ <DD>Common UNIX Printing System
+
+ <DT>ESC/P
+ <DD>EPSON Standard Code for Printers
+
+ <DT>FTP
+ <DD>File Transfer Protocol
+
+ <DT>HP-GL
+ <DD>Hewlett-Packard Graphics Language
+
+ <DT>HP-PCL
+ <DD>Hewlett-Packard Page Control Language
+
+ <DT>HP-PJL
+ <DD>Hewlett-Packard Printer Job Language
+
+ <DT>IETF
+ <DD>Internet Engineering Task Force
+
+ <DT>IPP
+ <DD>Internet Printing Protocol
+
+ <DT>ISO
+ <DD>International Standards Organization
+
+ <DT>LPD
+ <DD>Line Printer Daemon
+
+ <DT>MIME
+ <DD>Multimedia Internet Mail Exchange
+
+ <DT>PPD
+ <DD>PostScript Printer Description
+
+ <DT>SMB
+ <DD>Server Message Block
+
+ <DT>TFTP
+ <DD>Trivial File Transfer Protocol
+
+</DL>
diff --git a/doc/idd.html b/doc/idd.html
new file mode 100644
index 000000000..12f7e46fb
--- /dev/null
+++ b/doc/idd.html
@@ -0,0 +1,1083 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD>
+<TITLE>CUPS Interface Design Description</TITLE>
+<META NAME="author" CONTENT="Easy Software Products">
+<META NAME="copyright" CONTENT="Copyright 1997-2002, All Rights Reserved">
+<META NAME="docnumber" CONTENT="CUPS-IDD-1.1">
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=iso-8859-1">
+<STYLE TYPE="text/css"><!--
+BODY { font-family: serif }
+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 }
+SUB { font-size: smaller }
+SUP { font-size: smaller }
+PRE { font-family: monospace }
+--></STYLE>
+</HEAD>
+<BODY>
+<CENTER><A HREF="#CONTENTS"><IMG SRC="images/cups-large.gif" BORDER="0" WIDTH="431" HEIGHT="511"><BR>
+<H1>CUPS Interface Design Description</H1></A><BR>
+CUPS-IDD-1.1<BR>
+Easy Software Products<BR>
+Copyright 1997-2002, All Rights Reserved<BR>
+</CENTER>
+<HR>
+<H1 ALIGN="CENTER"><A NAME="CONTENTS">Table of Contents</A></H1>
+<BR>
+<BR><B><A HREF="#1">1 Scope</A></B>
+<UL>
+<LI><A HREF="#1_1">1.1 Identification</A></LI>
+<LI><A HREF="#1_2">1.2 System Overview</A></LI>
+<LI><A HREF="#1_3">1.3 Document Overview</A></LI>
+</UL>
+<B><A HREF="#2">2 References</A></B>
+<UL>
+<LI><A HREF="#2_1">2.1 CUPS Documentation</A></LI>
+<LI><A HREF="#2_2">2.2 Other Documents</A></LI>
+</UL>
+<B><A HREF="#3">3 Internal Interfaces</A></B>
+<UL>
+<LI><A HREF="#3_1">3.1 Character Set Files</A></LI>
+<UL>
+<LI><A HREF="#3_1_1">3.1.1 8-Bit Character Set Files</A></LI>
+<LI><A HREF="#3_1_2">3.1.2 Unicode Character Set Files</A></LI>
+</UL>
+<LI><A HREF="#3_2">3.2 Language Files</A></LI>
+<LI><A HREF="#3_3">3.3 MIME Files</A></LI>
+<UL>
+<LI><A HREF="#3_3_1">3.3.1 mime.types</A></LI>
+<LI><A HREF="#3_3_2">3.3.2 mime.convs</A></LI>
+</UL>
+<LI><A HREF="#3_4">3.4 Option Files</A></LI>
+<LI><A HREF="#3_5">3.5 PostScript Printer Description Files</A></LI>
+<UL>
+<LI><A HREF="#3_5_1">3.5.1 PPD Specification</A></LI>
+<LI><A HREF="#3_5_2">3.5.2 CUPS Extensions to PPD Files</A></LI>
+</UL>
+<LI><A HREF="#3_6">3.6 Scheduler Configuration Files</A></LI>
+<UL>
+<LI><A HREF="#3_6_1">3.6.1 classes.conf</A></LI>
+<LI><A HREF="#3_6_2">3.6.2 cupsd.conf</A></LI>
+<LI><A HREF="#3_6_3">3.6.3 printers.conf</A></LI>
+</UL>
+</UL>
+<B><A HREF="#4">4 External Interfaces</A></B>
+<UL>
+<LI><A HREF="#4_1">4.1 AppSocket Protocol</A></LI>
+<LI><A HREF="#4_2">4.2 CUPS Browsing Protocol</A></LI>
+<LI><A HREF="#4_3">4.3 CUPS Form File</A></LI>
+<UL>
+<LI><A HREF="#4_3_1">4.3.1 CUPS Form DTD</A></LI>
+</UL>
+<LI><A HREF="#4_4">4.4 CUPS PostScript File</A></LI>
+<LI><A HREF="#4_5">4.5 CUPS Raster File</A></LI>
+<LI><A HREF="#4_6">4.6 CUPS Raw Files</A></LI>
+<LI><A HREF="#4_7">4.7 Internet Printing Protocol</A></LI>
+<LI><A HREF="#4_8">4.8 Line Printer Daemon Protocol</A></LI>
+<LI><A HREF="#4_9">4.9 Server Message Block Protocol</A></LI>
+</UL>
+<B><A HREF="#5">5 Directories</A></B>
+<BR>
+<BR><B><A HREF="#6">A Glossary</A></B>
+<UL>
+<LI><A HREF="#6_1">A.1 Terms</A></LI>
+<LI><A HREF="#6_2">A.2 Acronyms</A></LI>
+</UL>
+<HR>
+<H1><A NAME="1">1 Scope</A></H1>
+<H2><A NAME="1_1">1.1 Identification</A></H2>
+<P>This interface design description document provides detailed file
+ formats, message formats, and program conventions for the Common UNIX
+ Printing System (&quot;CUPS&quot;) Version 1.1.</P>
+<H2><A NAME="1_2">1.2 System Overview</A></H2>
+<P>CUPS provides a portable printing layer for UNIX&reg;-based operating
+ systems. It has been developed by<A HREF="http://www.easysw.com"> Easy
+ Software Products</A> to promote a standard printing solution for all
+ UNIX vendors and users. CUPS provides the System V and Berkeley
+ command-line interfaces.</P>
+<P>CUPS uses the Internet Printing Protocol (&quot;IPP&quot;) as the basis for
+ managing print jobs and queues. The Line Printer Daemon (&quot;LPD&quot;) Server
+ Message Block (&quot;SMB&quot;), and AppSocket (a.k.a. JetDirect) protocols are
+ also supported with reduced functionality. CUPS adds network printer
+ browsing and PostScript Printer Description (&quot;PPD&quot;) based printing
+ options to support real-world printing under UNIX.</P>
+<P>CUPS also includes a customized version of GNU Ghostscript (currently
+ based off GNU Ghostscript 5.50) and an image file RIP that are used to
+ support non-PostScript printers. Sample drivers for HP and EPSON
+ printers are included that use these filters.</P>
+<H2><A NAME="1_3">1.3 Document Overview</A></H2>
+<P>This interface design description document is organized into the
+ following sections:</P>
+<UL>
+<LI>1 - Scope</LI>
+<LI>2 - References</LI>
+<LI>3 - Internal Interfaces</LI>
+<LI>4 - External Interfaces</LI>
+<LI>5 - Directories</LI>
+<LI>A - Glossary</LI>
+</UL>
+<H1><A NAME="2">2 References</A></H1>
+<H2><A NAME="2_1">2.1 CUPS Documentation</A></H2>
+<P>The following CUPS documentation is referenced by this document:</P>
+<UL>
+<LI>CUPS-CMP-1.1: CUPS Configuration Management Plan</LI>
+<LI>CUPS-IDD-1.1: CUPS System Interface Design Description</LI>
+<LI>CUPS-IPP-1.1: CUPS Implementation of IPP</LI>
+<LI>CUPS-SAM-1.1.x: CUPS Software Administrators Manual</LI>
+<LI>CUPS-SDD-1.1: CUPS Software Design Description</LI>
+<LI>CUPS-SPM-1.1.x: CUPS Software Programming Manual</LI>
+<LI>CUPS-SSR-1.1: CUPS Software Security Report</LI>
+<LI>CUPS-STP-1.1: CUPS Software Test Plan</LI>
+<LI>CUPS-SUM-1.1.x: CUPS Software Users Manual</LI>
+<LI>CUPS-SVD-1.1: CUPS Software Version Description</LI>
+</UL>
+<H2><A NAME="2_2">2.2 Other Documents</A></H2>
+<P>The following non-CUPS documents are referenced by this document:</P>
+<UL>
+<LI><A HREF="http://partners.adobe.com/asn/developer/PDFS/TN/5003.PPD_Spec_v4.3.pdf">
+Adobe PostScript Printer Description File Format Specification, Version
+ 4.3.</A></LI>
+<LI><A HREF="http://partners.adobe.com/asn/developer/PDFS/TN/PLRM.pdf">
+Adobe PostScript Language Reference, Third Edition.</A></LI>
+<LI>IPP: Job and Printer Set Operations</LI>
+<LI>IPP/1.1: Encoding and Transport</LI>
+<LI>IPP/1.1: Implementers Guide</LI>
+<LI>IPP/1.1: Model and Semantics</LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc1179.txt">RFC 1179, Line Printer
+ Daemon Protocol</A></LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc2567.txt">RFC 2567, Design Goals
+ for an Internet Printing Protocol</A></LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc2568.txt">RFC 2568, Rationale
+ for the Structure of the Model and Protocol</A> for the Internet
+ Printing Protocol</LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc2569.txt">RFC 2569, Mapping
+ between LPD and IPP Protocols</A></LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616, Hypertext
+ Transfer Protocol -- HTTP/1.1</A></LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc2617.txt">RFC 2617, HTTP
+ Authentication: Basic and Digest Access</A> Authentication</LI>
+</UL>
+<H1><A NAME="3">3 Internal Interfaces</A></H1>
+<H2><A NAME="3_1">3.1 Character Set Files</A></H2>
+<P>The character set files define a mapping between 8-bit characters and
+ the Unicode character set, or between Unicode and printer fonts. They
+ are named using the IETF charset names defined in RFCnnnn. These files
+ are ASCII text, the content of which is described below. Comments can
+ be included by using the <TT>#</TT> character in the first column of a
+ line.</P>
+<H3><A NAME="3_1_1">3.1.1 8-Bit Character Set Files</A></H3>
+<P>8-bit character set files start with a line reading:</P>
+<UL>
+<PRE>
+charset 8bit
+</PRE>
+</UL>
+<P>Following this are lines that define the font information:</P>
+<UL>
+<PRE>
+first last direction width normal bold italic bold-italic
+</PRE>
+</UL>
+<P><VAR>First</VAR> and<VAR> last</VAR> are the first and last glyphs in
+ the font mapping that correspond to that font; a maximum of 256
+ characters can be mapped within each group, with a maximum of 256
+ mappings (this is a PostScript limitation.) The glyph values are
+ hexadecimal.</P>
+<P><VAR>Direction</VAR> is the string &quot;ltor&quot;, &quot;rtol&quot;, or &quot;rtola&quot;
+ indicating left-to-right, right-to-left, or right-to-left Arabic text.</P>
+<P><VAR>Width</VAR> is the string &quot;single&quot; or &quot;double&quot;; double means
+ that the glyphs are twice as wide as ASCII characters in the Courier
+ typeface.</P>
+<P><VAR>Normal, bold, italic</VAR>, and<VAR> bold-italic</VAR> 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. &quot;Symbol&quot;.) Each font that is listed will be used (and downloaded
+ if needed) when printing.</P>
+<P>The remaining lines define a character to Unicode glyph mapping for
+ the character set. The character and glyph values are hexadecimal:</P>
+<UL>
+<PRE>
+xx yyyy
+</PRE>
+</UL>
+<H3><A NAME="3_1_2">3.1.2 Unicode Character Set Files</A></H3>
+<P>Unicode character set files start with a line reading:</P>
+<UL>
+<PRE>
+charset encoding
+</PRE>
+</UL>
+<P><VAR>Encoding</VAR> is the encoding to use for the text; currently
+ only the string &quot;utf8&quot; is supported.</P>
+<P>Following this are lines defining the font information:</P>
+<UL>
+<PRE>
+first last direction width normal bold italic bold-italic
+</PRE>
+</UL>
+<P><VAR>First</VAR> and<VAR> last</VAR> are the first and last glyphs in
+ the font mapping that correspond to that font; a maximum of 256
+ characters can be mapped within each group, with a maximum of 256
+ mappings (this is a PostScript limitation.) The glyph values are
+ hexadecimal.</P>
+<P><VAR>Direction</VAR> is the string &quot;ltor&quot;, &quot;rtol&quot;, or &quot;rtola&quot;
+ indicating left-to-right, right-to-left, or right-to-left Arabic text.</P>
+<P><VAR>Width</VAR> is the string &quot;single&quot; or &quot;double&quot;; double means
+ that the glyphs are twice as wide as ASCII characters in the Courier
+ typeface.</P>
+<P><VAR>Normal, bold, italic</VAR>, and<VAR> bold-italic</VAR> 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. &quot;Symbol&quot;.) Each font that is listed will be used (and downloaded
+ if needed) when printing.</P>
+<H2><A NAME="3_2">3.2 Language Files</A></H2>
+<P>The language files define the default character set and a collection
+ of text messages in that language. They are named by prefixing the
+ string &quot;cups_&quot; to the front of the language specifier (e.g. &quot;cups_en&quot;,
+ &quot;cups_fr&quot;, etc.) Each file consists of two or more lines of ASCII text.</P>
+<P>The first line identifies the character set to be used for the
+ messages. The currently recognized values are:</P>
+<UL>
+<LI>iso-8859-1</LI>
+<LI>iso-8859-2</LI>
+<LI>iso-8859-3</LI>
+<LI>iso-8859-4</LI>
+<LI>iso-8859-5</LI>
+<LI>iso-8859-6</LI>
+<LI>iso-8859-7</LI>
+<LI>iso-8859-8</LI>
+<LI>iso-8859-9</LI>
+<LI>iso-8859-10</LI>
+<LI>iso-8859-13</LI>
+<LI>iso-8859-14</LI>
+<LI>iso-8859-15</LI>
+<LI>us-ascii</LI>
+<LI>utf-8</LI>
+<LI>windows-874</LI>
+<LI>windows-1250</LI>
+<LI>windows-1251</LI>
+<LI>windows-1252</LI>
+<LI>windows-1253</LI>
+<LI>windows-1254</LI>
+<LI>windows-1255</LI>
+<LI>windows-1256</LI>
+<LI>windows-1257</LI>
+<LI>windows-1258</LI>
+<LI>koi8-r</LI>
+<LI>koi8-u</LI>
+</UL>
+<P>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.</P>
+<H2><A NAME="3_3">3.3 MIME Files</A></H2>
+<P>CUPS uses two MIME files in its standard configuration.</P>
+<H3><A NAME="3_3_1">3.3.1 mime.types</A></H3>
+<P>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 (&quot;#&quot;)
+ character. The backslash (&quot;\&quot;) character can be used at the end of a
+ line to continue that line to the next.</P>
+<P>Each non-blank line starts with a MIME type identifier (&quot;super/type&quot;)
+ as registered with the IANA. All text following the MIME type is
+ treated as a series of type recognition rules:</P>
+<UL>
+<PRE>
+mime-type := super &quot;/&quot; type { SP rule }*
+super := { &quot;a-z&quot; | &quot;A-Z&quot; }*
+type := { &quot;a-z&quot; | &quot;A-Z&quot; | &quot;-&quot; | &quot;.&quot; | &quot;0-9&quot; }*
+rule := { extension | match | operator | &quot;(&quot; rule &quot;)&quot; }*
+extension := { &quot;a-z&quot; | &quot;A-Z&quot; | &quot;0-9&quot; }*
+match := &quot;match(&quot; regexp &quot;)&quot; |
+ &quot;ascii(&quot; offset &quot;,&quot; length &quot;)&quot; |
+ &quot;printable(&quot; offset &quot;,&quot; length &quot;)&quot; |
+ &quot;string(&quot; offset &quot;,&quot; string &quot;)&quot; |
+ &quot;contains(&quot; offset &quot;,&quot; length &quot;,&quot; string &quot;)&quot; |
+ &quot;char(&quot; offset &quot;,&quot; value &quot;)&quot; |
+ &quot;short(&quot; offset &quot;,&quot; value &quot;)&quot; |
+ &quot;int(&quot; offset &quot;,&quot; value &quot;)&quot; |
+ &quot;locale(&quot; string &quot;)&quot;
+operator := &quot;+&quot; | [ logical AND ]
+ &quot;,&quot; | SP [ logical OR ]
+ &quot;!&quot; [ unary NOT ]
+</PRE>
+</UL>
+<P>The <CODE>int</CODE> and <CODE>short</CODE> rules match look for
+ integers in network byte order (a.k.a. big-endian) with the
+ most-significant byte first.</P>
+<H3><A NAME="3_3_2">3.3.2 mime.convs</A></H3>
+<P>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
+ (&quot;#&quot;) character.</P>
+<P>Each non-blank line starts with two MIME type identifiers
+ (&quot;super/type&quot;) 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:</P>
+<UL>
+<PRE>
+super/type SP super/type2 SP cost SP program
+</PRE>
+</UL>
+<H2><A NAME="3_4">3.4 Option Files</A></H2>
+<P>CUPS maintains user-defined printer and option files for each printer
+ and user on the system. The printers and options defined in the system
+ option file (<CODE>/etc/cups/lpoptions</CODE>) are loaded first,
+ followed by the user option file (<CODE>$HOME/.lpoptions</CODE>).
+ Options in the user file replace those defined in the system file for
+ the same destination. Each line in the files can be one of the
+ following:</P>
+<UL>
+<PRE>
+Dest name option=value option=value ... option=value
+Dest name/instance option=value option=value ... option=value
+Default name option=value option=value ... option=value
+Default name/instance option=value option=value ... option=value
+</PRE>
+</UL>
+<P>The line beginning with &quot;Default&quot; indicates the default destination
+ for print jobs; a default line in the user option file overrides the
+ default defined in the system option file.</P>
+<P><VAR>Name</VAR> is the name of a printer known to the local server.</P>
+<P><VAR>Instance</VAR> can be any string of letters, numbers, and the
+ underscore up to 127 characters in length.</P>
+<P>The remainder of the line contains a list of space-separated options
+ and their values.</P>
+<H2><A NAME="3_5">3.5 PostScript Printer Description Files</A></H2>
+<P>PostScript Printer Description (&quot;PPD&quot;) files describe the
+ capabilities of each printer and are used by CUPS to support
+ printer-specific features and intelligent filtering.</P>
+<H3><A NAME="3_5_1">3.5.1 PPD Specification</A></H3>
+<P>The PPD file format is described in<A HREF="http://partners.adobe.com/asn/developer/PDFS/TN/5003.PPD_Spec_v4.3.pdf">
+ Adobe TechNote #5003: PostScript Printer Description File Format
+ Specification Version 4.3</A>.</P>
+<H3><A NAME="3_5_2">3.5.2 CUPS Extensions to PPD Files</A></H3>
+<P>CUPS adds several new attributes that are described below.</P>
+<H4>3.5.2.1 cupsFilter</H4>
+<P>This string attribute provides a conversion rule of the form:</P>
+<UL>
+<PRE>
+source/type cost program
+</PRE>
+</UL>
+<P>The destination type is assumed to the printer's type. If a printer
+ supports the source type directly the special filter program &quot;-&quot; may be
+ specified.</P>
+<H4>3.5.2.2 cupsManualCopies</H4>
+<P>This boolean attribute notifies the RIP filters that the destination
+ printer does not support copy generation in hardware. The default value
+ is false.</P>
+<H4>3.5.2.3 cupsModelNumber</H4>
+<P>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.</P>
+<H4>3.5.2.4 cupsProfile</H4>
+<P>This string attribute specifies a color profile of the form:</P>
+<UL>
+<PRE>
+resolution/type density gamma m00 m01 m02 m10 m11 m12 m20 m21 m22
+</PRE>
+</UL>
+<P>The<I> resolution</I> and<I> type</I> values may be &quot;-&quot; to act as a
+ wildcard. Otherwise they must match one of the <CODE>Resolution</CODE>
+ or <CODE>MediaType</CODE> attributes defined in the PPD file.</P>
+<P>The<I> density</I> and<I> gamma</I> values define gamma and density
+ adjustment function such that:</P>
+<UL>
+<PRE>
+f(x) = density * x<SUP>gamma</SUP>
+</PRE>
+</UL>
+<P>The<I> m00</I> through<I> m22</I> values define a 3x3 transformation
+ matrix for the CMY color values. The density function is applied<I>
+ after</I> the CMY transformation.</P>
+<H4>3.5.2.5 cupsVersion</H4>
+<P>This required attribute describes which version of the CUPS IDD was
+ used for the PPD file extensions. Currently it must be the string &quot;1.0&quot;
+ or &quot;1.1&quot;.</P>
+<H2><A NAME="3_6">3.6 Scheduler Configuration Files</A></H2>
+<P>The scheduler reads three configuration files that define the
+ available printers, classes, and services:</P>
+<DL>
+<DT>classes.conf</DT>
+<DD>This file defines all of the printer classes known to the system.</DD>
+<DT>cupsd.conf</DT>
+<DD>This file defines the files, directories, passwords, etc. used by
+ the scheduler.</DD>
+<DT>printers.conf</DT>
+<DD>This file defines all of the printers known to the system.</DD>
+</DL>
+<H3><A NAME="3_6_1">3.6.1 classes.conf</A></H3>
+<P>The classes.conf file consists of 1 or more lines of ASCII text.
+ Comment lines start with the pound (&quot;#&quot;) character.</P>
+<P>Each non-blank line starts with the name of a configuration directive
+ followed by its value. The following directives are understood:
+<CENTER>
+<TABLE BORDER="1" WIDTH="90%">
+<TR><TH WIDTH="25%">Directive</TH><TH>Description</TH></TR>
+<TR><TD>&lt;Class name&gt;
+<BR> &lt;/Class&gt;</TD><TD>Surrounds a class definition.</TD></TR>
+<TR><TD>&lt;DefaultClass name&gt;
+<BR> &lt;/Class&gt;</TD><TD>Surrounds a class definition for the default
+ destination.</TD></TR>
+<TR><TD>Accepting</TD><TD>Specifies whether the class is accepting new
+ jobs. May be the names &quot;Yes&quot; or &quot;No&quot;.</TD></TR>
+<TR><TD>AllowUsers</TD><TD>Specifies a list of users that are allowed to
+ access the class.</TD></TR>
+<TR><TD>BannerStart</TD><TD>Specifies the banner that is printed before
+ other files in a job.</TD></TR>
+<TR><TD>BannerEnd</TD><TD>Specifies the banner that is printed after
+ other files in a job.</TD></TR>
+<TR><TD>DenyUsers</TD><TD>Specifies a list of users that are not allowed
+ to access the class.</TD></TR>
+<TR><TD>Info</TD><TD>A textual description of the class.</TD></TR>
+<TR><TD>Location</TD><TD>A textual location of the class.</TD></TR>
+<TR><TD>Printer</TD><TD>Specifies a printer that is a member of the
+ class.</TD></TR>
+<TR><TD>State</TD><TD>Specifies the initial state of the class; can be
+ &quot;Idle&quot; or &quot;Stopped&quot;.</TD></TR>
+<TR><TD>StateMessage</TD><TD>Specifies a textual message for the current
+ class state.</TD></TR>
+</TABLE>
+</CENTER>
+</P>
+<H3><A NAME="3_6_2">3.6.2 cupsd.conf</A></H3>
+<P>The cupsd.conf file consists of 1 or more lines of ASCII text.
+ Comment lines start with the pound (&quot;#&quot;) character.</P>
+<P>Each non-blank line starts with the name of a configuration directive
+ followed by its value. The following directives are understood:
+<CENTER>
+<TABLE BORDER="1" WIDTH="90%">
+<TR><TH WIDTH="25%">Directive</TH><TH>Default</TH><TH>Description</TH></TR>
+<TR><TD>AccessLog</TD><TD>access_log</TD><TD>Specifies the location of
+ the access log file. The special name &quot;syslog&quot; can be used to send
+ access log information to the system log.</TD></TR>
+<TR><TD>Allow</TD><TD>-</TD><TD>Allows connections from the specified
+ host, network, or domain.</TD></TR>
+<TR><TD>AuthClass</TD><TD>-</TD><TD>Specifies what level of
+ authentication is required; may be &quot;User&quot;, &quot;System&quot;, or &quot;Group&quot;.</TD></TR>
+<TR><TD>AuthType</TD><TD>None</TD><TD>Specifies the type of
+ authentication to perform; may be &quot;None&quot;, &quot;Basic&quot;, or &quot;Digest&quot;.</TD></TR>
+<TR><TD>BrowseAddress</TD><TD>255.255.255.255</TD><TD>Specifies a
+ broadcast address to send CUPS browsing packets to.</TD></TR>
+<TR><TD>BrowseAllow</TD><TD>-</TD><TD>Specifies hosts or addresses from
+ which browsing information should be used.</TD></TR>
+<TR><TD>BrowseDeny</TD><TD>-</TD><TD>Specifies hosts or addresses from
+ which browsing information should not be used.</TD></TR>
+<TR><TD>BrowseInterval</TD><TD>30</TD><TD>Specifies the number of
+ seconds between browsing updates. A browse interval of 0 seconds
+ disables outgoing packets.</TD></TR>
+<TR><TD>BrowseOrder</TD><TD>Allow,Deny</TD><TD>Specifies the order of
+ BrowseAllow and BrowseDeny directive processing; can be &quot;Deny,Allow&quot; to
+ implicitly deny hosts unless they are allowed by a BrowseAllow line, or
+ &quot;Allow,Deny&quot; to implicitly allow hosts unless they are denied by a
+ BrowseDeny line.</TD></TR>
+<TR><TD>BrowsePoll</TD><TD>-</TD><TD>Specifies a server to poll for
+ available printers and classes.</TD></TR>
+<TR><TD>BrowsePort</TD><TD>631</TD><TD>Specifies the UDP port number to
+ use for browse packets.</TD></TR>
+<TR><TD>BrowseRelay</TD><TD>-</TD><TD>Specifies a source and destination
+ address for relaying browser information from one subnet to another.</TD>
+</TR>
+<TR><TD>BrowseShortNames</TD><TD>yes</TD><TD>Specifies whether or not to
+ provide short names (without the &quot;@server&quot; part) for remote printers.</TD>
+</TR>
+<TR><TD>BrowseTimeout</TD><TD>300</TD><TD>Specifies the number of
+ seconds to wait until remote destinations are removed from the local
+ destination list.</TD></TR>
+<TR><TD>Browsing</TD><TD>On</TD><TD>Specifies whether or not printer and
+ class browsing is enabled; can be &quot;On&quot; or &quot;Off&quot;.</TD></TR>
+<TR><TD>DataDir</TD><TD>/usr/share/cups</TD><TD>Specifies the directory
+ where CUPS data files are stored.</TD></TR>
+<TR><TD>DefaultCharset</TD><TD>iso-8859-1</TD><TD>Specifies the default
+ character set.</TD></TR>
+<TR><TD>DefaultLanguage</TD><TD>current locale</TD><TD>Specifies the
+ default language.</TD></TR>
+<TR><TD>Deny</TD><TD>-</TD><TD>Refuses connections from the specified
+ host, network, or domain.</TD></TR>
+<TR><TD>DocumentRoot</TD><TD>/usr/share/doc/cups</TD><TD>Specifies the
+ document data root directory.</TD></TR>
+<TR><TD>ErrorLog</TD><TD>error_log</TD><TD>Specifies the error log file
+ location. The special name &quot;syslog&quot; can be used to send error log
+ information to the system log.</TD></TR>
+<TR><TD>Group</TD><TD>root, sys, system</TD><TD>Specifies the group name
+ or ID that is used when running external programs.</TD></TR>
+<TR><TD>HostNameLookups</TD><TD>Off</TD><TD>Specifies whether or not to
+ perform reverse IP address lookups to get the actual hostname; may be
+ &quot;On&quot; or &quot;Off&quot;. Hostname lookups can significantly degrade the
+ performance of the CUPS server if one or more DNS servers is not
+ functioning properly.</TD></TR>
+<TR><TD>ImplicitClasses</TD><TD>On</TD><TD>Specifies whether or not to
+ automatically create printer classes when more than one printer or
+ class of the same name is detected on the network; may be &quot;On&quot; or
+ &quot;Off&quot;.</TD></TR>
+<TR><TD>KeepAlive</TD><TD>On</TD><TD>Specifies whether or not to use the
+ HTTP Keep-Alive feature; may be &quot;On&quot; or &quot;Off&quot;.</TD></TR>
+<TR><TD>KeepAliveTimeout</TD><TD>30</TD><TD>Specifies the amount of time
+ to keep the HTTP connection alive before closing it.</TD></TR>
+<TR><TD>&lt;Location path&gt;
+<BR> &lt;/Location&gt;</TD><TD>-</TD><TD>Specifies a location to restrict
+ access to.</TD></TR>
+<TR><TD>LogLevel</TD><TD>info</TD><TD>Controls the amount of information
+ that is logged in the error log file. Can be one of &quot;debug&quot;, &quot;info&quot;,
+ &quot;warn&quot;, &quot;error&quot;, or &quot;none&quot;, in decreasing order or verbosity.</TD></TR>
+<TR><TD>MaxClients</TD><TD>100</TD><TD>Specifies the maximum number of
+ simultaneous active clients. This value is internally limited to 1/3 of
+ the total number of available file descriptors.</TD></TR>
+<TR><TD>MaxLogSize</TD><TD>0</TD><TD>Specifies the maximum size of the
+ access, error, and page log files in bytes. If set to 0 then no maximum
+ size is set. Log files are rotated automatically when this size is
+ exceeded.</TD></TR>
+<TR><TD>MaxRequestSize</TD><TD>0</TD><TD>Specifies the maximum size of
+ HTTP requests in bytes. If set to 0 then there is no maximum.</TD></TR>
+<TR><TD>Order</TD><TD>Allow,Deny</TD><TD>Specifies the order of Allow
+ and Deny directive processing; can be &quot;Deny,Allow&quot; to implicitly deny
+ hosts unless they are allowed by an Allow line, or &quot;Allow,Deny&quot; to
+ implicitly allow hosts unless they are denied by a Deny line.</TD></TR>
+<TR><TD>PageLog</TD><TD>page_log</TD><TD>Specifies the location of the
+ page log file. The special name &quot;syslog&quot; can be used to send page log
+ information to the system log.</TD></TR>
+<TR><TD>Port</TD><TD>631</TD><TD>Specifies a port number to listen to
+ for HTTP connections.</TD></TR>
+<TR><TD>Printcap</TD><TD>/etc/printcap</TD><TD>Specifies the location of
+ a Berkeley printcap file to update with a list of current printers and
+ classes. If no filename is supplied then this automatic generation is
+ disabled.</TD></TR>
+<TR><TD>RequestRoot</TD><TD>/var/spool/cups</TD><TD>Specifies the
+ location of request files.</TD></TR>
+<TR><TD>RIPCache</TD><TD>8m</TD><TD>Specifies the size of the memory
+ cache in bytes that is used by RIP filters.</TD></TR>
+<TR><TD>ServerAdmin</TD><TD>root@ServerName</TD><TD>Specifies the person
+ to contact with problems.</TD></TR>
+<TR><TD>ServerName</TD><TD>hostname</TD><TD>Specifies the hostname that
+ is supplied to HTTP clients. This is also used to determine the default
+ CUPS server for the CUPS IPP client applications.</TD></TR>
+<TR><TD>ServerRoot</TD><TD>/etc/cups</TD><TD>Specifies the root
+ directory for server configuration files.</TD></TR>
+<TR><TD>SystemGroup</TD><TD>root, sys, system</TD><TD>Specifies the
+ group name used for System class authentication.</TD></TR>
+<TR><TD>TempDir</TD><TD>/var/tmp</TD><TD>Specifies the temporary
+ directory to use.</TD></TR>
+<TR><TD>Timeout</TD><TD>300</TD><TD>The timeout in seconds before client
+ connections are closed in the middle of a request.</TD></TR>
+<TR><TD>User</TD><TD>lp</TD><TD>Specifies the user that is used when
+ running external programs.</TD></TR>
+</TABLE>
+</CENTER>
+</P>
+<H3><A NAME="3_6_3">3.6.3 printers.conf</A></H3>
+<P>The printers.conf file consists of 1 or more lines of ASCII text.
+ Comment lines start with the pound (&quot;#&quot;) character.</P>
+<P>Each non-blank line starts with the name of a configuration directive
+ followed by its value. The following directives are understood:
+<CENTER>
+<TABLE BORDER="1" WIDTH="90%">
+<TR><TH WIDTH="25%">Directive</TH><TH>Description</TH></TR>
+<TR><TD>Accepting</TD><TD>Specifies whether the printer is accepting new
+ jobs. May be the names &quot;Yes&quot; or &quot;No&quot;.</TD></TR>
+<TR><TD>&lt;DefaultPrinter name&gt;
+<BR> &lt;/Printer&gt;</TD><TD>Surrounds the printer definition for a default
+ destination.</TD></TR>
+<TR><TD>AllowUsers</TD><TD>Specifies a list of users that are allowed to
+ access the printer.</TD></TR>
+<TR><TD>BannerStart</TD><TD>Specifies the banner that is printed before
+ other files in a job.</TD></TR>
+<TR><TD>BannerEnd</TD><TD>Specifies the banner that is printed after
+ other files in a job.</TD></TR>
+<TR><TD>DenyUsers</TD><TD>Specifies a list of users that are not allowed
+ to access the printer.</TD></TR>
+<TR><TD>DeviceURI</TD><TD>Specifies the device-uri attribute for the
+ printer.</TD></TR>
+<TR><TD>Info</TD><TD>A textual description of the printer.</TD></TR>
+<TR><TD>Location</TD><TD>A textual location of the printer.</TD></TR>
+<TR><TD>&lt;Printer name&gt;
+<BR> &lt;/Printer&gt;</TD><TD>Surrounds the printer definition.</TD></TR>
+<TR><TD>State</TD><TD>Specifies the initial state of the printer; can be
+ &quot;Idle&quot; or &quot;Stopped&quot;.</TD></TR>
+<TR><TD>StateMessage</TD><TD>Specifies a textual message for the current
+ printer state.</TD></TR>
+</TABLE>
+</CENTER>
+</P>
+<H1><A NAME="4">4 External Interfaces</A></H1>
+<H2><A NAME="4_1">4.1 AppSocket Protocol</A></H2>
+<P>The AppSocket protocol is an 8-bit clean TCP/IP socket connection.
+ The default IP service port is 9100. The URI method name is &quot;socket&quot;.</P>
+<P>The AppSocket protocol is used by the Hewlett Packard JetDirect
+ network interfaces and print servers, as well as many other vendors'
+ products. See the CUPS Software Administrators Manual for a list of
+ supported products.</P>
+<H2><A NAME="4_2">4.2 CUPS Browsing Protocol</A></H2>
+<P>The CUPS Browsing Protocol is a UDP/IP-based broadcast service. By
+ default this service operates on IP service port 631.</P>
+<P>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:</P>
+<UL>
+<PRE>
+type SP state SP uri SP &quot;location&quot; SP &quot;info&quot; SP &quot;make-and-model&quot; NL
+</PRE>
+</UL>
+<P><VAR>State, uri, location, info</VAR>, and<VAR> make-and-model</VAR>,
+ correspond to the IPP <CODE>printer-state</CODE>, <CODE>
+printer-uri-supported</CODE>, <CODE>printer-location</CODE>, <CODE>
+printer-info</CODE>, and <CODE>printer-make-and-model</CODE> attributes.</P>
+<P><VAR>Type</VAR> is a hexadecimal number string representing
+ capability/type bits:
+<CENTER>
+<TABLE BORDER="1" WIDTH="40%">
+<TR><TH WIDTH="8%">Bit</TH><TH>Description</TH></TR>
+<TR><TD>0</TD><TD>0 = printer
+<BR> 1 = class</TD></TR>
+<TR><TD>1</TD><TD>0 = local
+<BR> 1 = remote
+<BR> (always 1)</TD></TR>
+<TR><TD>2</TD><TD>1 = can print B</TD></TR>
+<TR><TD>3</TD><TD>1 = can print color</TD></TR>
+<TR><TD>4</TD><TD>1 = can duplex</TD></TR>
+<TR><TD>5</TD><TD>1 = can staple</TD></TR>
+<TR><TD>6</TD><TD>1 = can do fast copies</TD></TR>
+<TR><TD>7</TD><TD>1 = can do fast collating</TD></TR>
+<TR><TD>8</TD><TD>1 = can punch holes</TD></TR>
+<TR><TD>9</TD><TD>1 = can cover</TD></TR>
+<TR><TD>10</TD><TD>1 = can bind</TD></TR>
+<TR><TD>11</TD><TD>1 = can sort</TD></TR>
+<TR><TD>12</TD><TD>1 = can print up to 9x14 inches</TD></TR>
+<TR><TD>13</TD><TD>1 = can print up to 18x24 inches</TD></TR>
+<TR><TD>14</TD><TD>1 = can print up to 36x48 inches</TD></TR>
+<TR><TD>15</TD><TD>1 = can print variable sizes</TD></TR>
+</TABLE>
+</CENTER>
+</P>
+<H2><A NAME="4_3">4.3 CUPS Form File</A></H2>
+<P>CUPS Form files are XML files used by the CUPS <CODE>formtops</CODE>
+ filter to produce dynamic banner pages and support preprinted forms.</P>
+<P>The MIME type for CUPS Form files is <CODE>application/vnd.cups-form</CODE>
+.</P>
+<H3><A NAME="4_3_1">4.3.1 CUPS Form DTD</A></H3>
+<P>The following DTD describes the available elements and attributes in
+ a CUPS Form file:
+<CENTER>
+<TABLE BORDER>
+<TR><TD>
+<PRE>
+&lt;!ENTITY % Angle &quot;CDATA&quot; -- angle in degrees --&gt;
+
+&lt;!ENTITY % Color &quot;CDATA&quot; -- a color using sRGB: #RRGGBB as Hex values --&gt;
+
+&lt;!ENTITY % Length &quot;CDATA&quot; -- nn for pixels or nn% for percentage length --&gt;
+
+&lt;!ENTITY % Lengths &quot;CDATA&quot; -- comma-separated Length values --&gt;
+
+&lt;!ENTITY % Text &quot;CDATA&quot;&gt;
+
+&lt;!ENTITY % heading &quot;H1|H2|H3|H4|H5|H6&quot;&gt;
+
+&lt;!ENTITY % preformatted &quot;PRE&quot;&gt;
+
+&lt;!ENTITY % i18n
+ &quot;lang %LanguageCode; #IMPLIED -- language code --
+ dir (ltr|rtl) #IMPLIED -- direction for weak/neutral text --&quot;
+ &gt;
+
+&lt;!ENTITY % attrs &quot;%i18n;&quot;&gt;
+
+&lt;!ENTITY % fontstyle
+ &quot;B | FONT | I | TT&quot;&gt;
+
+&lt;!ENTITY % graphics
+ &quot;BOX | RECT | LINE | POLY | ARC | PIE | TEXT&quot;&gt;
+
+&lt;!ENTITY % insert
+ &quot;IMG | VAR&quot;&gt;
+
+&lt;!-- %inline; covers inline or &quot;text-level&quot; elements --&gt;
+&lt;!ENTITY % inline &quot;#PCDATA | %fontstyle; | %graphics; | %insert;&quot;&gt;
+
+&lt;!ELEMENT (%fontstyle;) - - (%inline;)*&gt;
+&lt;!ATTLIST (%fontstyle;)
+ %attrs; -- %i18n --
+ &gt;
+
+&lt;!ELEMENT BR - O EMPTY -- forced line break --&gt;
+&lt;!ATTLIST BR
+ %attrs; -- %i18n --
+ &gt;
+
+&lt;!ENTITY % block
+ &quot;P | %heading; | %preformatted;&quot;&gt;
+
+&lt;!ENTITY % flow &quot;%block; | %inline;&quot;&gt;
+
+&lt;!ELEMENT PAGE O O (%flow;)+ -- document body --&gt;
+&lt;!ATTLIST PAGE
+ %attrs; -- %i18n --
+ align (left|center|right) #IMPLIED -- horizontal alignment --
+ valign (top|middle|center|bottom) #IMPLIED -- vertical alignment --
+ &gt;
+
+&lt;!ELEMENT P - O (%inline;)* -- paragraph --&gt;
+&lt;!ATTLIST P
+ %attrs; -- %i18n --
+ align (left|center|right) #IMPLIED -- horizontal alignment --
+ &gt;
+
+&lt;!ELEMENT (%heading;) - - (%inline;)* -- heading --&gt;
+&lt;!ATTLIST (%heading;)
+ %attrs; -- %i18n --
+ align (left|center|right) #IMPLIED -- horizontal alignment --
+ &gt;
+
+&lt;!ELEMENT PRE - - (%inline;)* -- preformatted text --&gt;
+&lt;!ATTLIST PRE
+ %attrs; -- %i18n --
+ align (left|center|right) #IMPLIED -- horizontal alignment --
+ &gt;
+
+&lt;!ELEMENT BOX - O EMPTY -- unfilled box --&gt;
+&lt;!ATTLIST BOX
+ color %Color; #IMPLIED -- override color --
+ height %Length; #REQUIRED -- height of box --
+ thickness %Length; #IMPLIED -- override line thickness --
+ width %Length; #REQUIRED -- width of box --
+ x %Length; #REQUIRED -- horizontal position --
+ y %Length; #REQUIRED -- vertical position --
+ &gt;
+
+&lt;!ELEMENT RECT - O EMPTY -- filled box --&gt;
+&lt;!ATTLIST RECT
+ color %Color; #IMPLIED -- override color --
+ height %Length; #REQUIRED -- height of box --
+ width %Length; #REQUIRED -- width of box --
+ x %Length; #REQUIRED -- horizontal position --
+ y %Length; #REQUIRED -- vertical position --
+ &gt;
+
+&lt;!ELEMENT LINE - O EMPTY -- polyline --&gt;
+&lt;!ATTLIST LINE
+ color %Color; #IMPLIED -- override color --
+ thickness %Length; #IMPLIED -- override line thickness --
+ x %Lengths; #REQUIRED -- horizontal positions --
+ y %Lengths; #REQUIRED -- vertical positions --
+ &gt;
+
+&lt;!ELEMENT POLY - O EMPTY -- polygon (filled) --&gt;
+&lt;!ATTLIST POLY
+ color %Color; #IMPLIED -- override color --
+ x %Lengths; #REQUIRED -- horizontal positions --
+ y %Lengths; #REQUIRED -- vertical positions --
+ &gt;
+
+&lt;!ELEMENT ARC - O EMPTY -- unfilled arc --&gt;
+&lt;!ATTLIST ARC
+ color %Color; #IMPLIED -- override color --
+ end %Angle; #IMPLIED -- override end angle --
+ height %Length; #REQUIRED -- height of arc --
+ start %Angle; #IMPLIED -- override start angle --
+ thickness %Length; #IMPLIED -- override line thickness --
+ width %Length; #REQUIRED -- width of arc --
+ x %Length; #REQUIRED -- horizontal position --
+ y %Length; #REQUIRED -- vertical position --
+ &gt;
+
+&lt;!ELEMENT PIE - O EMPTY -- filled arc --&gt;
+&lt;!ATTLIST PIE
+ color %Color; #IMPLIED -- override color --
+ end %Angle; #IMPLIED -- override end angle --
+ height %Length; #REQUIRED -- height of arc --
+ start %Angle; #IMPLIED -- override start angle --
+ width %Length; #REQUIRED -- width of arc --
+ x %Length; #REQUIRED -- horizontal position --
+ y %Length; #REQUIRED -- vertical position --
+ &gt;
+
+&lt;!ELEMENT TEXT - - (%flow;)* -- text box --&gt;
+&lt;!ATTLIST RECT
+ align (left|center|right) #IMPLIED -- horizontal alignment --
+ height %Length; #REQUIRED -- height of box --
+ valign (top|middle|center|bottom) #IMPLIED -- vertical alignment --
+ width %Length; #REQUIRED -- width of box --
+ x %Length; #REQUIRED -- horizontal position --
+ y %Length; #REQUIRED -- vertical position --
+ &gt;
+
+
+&lt;!ELEMENT IMG - O EMPTY -- Embedded image --&gt;
+&lt;!ATTLIST IMG
+ %attrs; -- %coreattrs, %i18n, %events --
+ src %URI; #REQUIRED -- URI of image to embed --
+ height %Length; #IMPLIED -- override height --
+ width %Length; #IMPLIED -- override width --
+ &gt;
+
+&lt;!ELEMENT HEAD O O (DEFVAR)* -- document head --&gt;
+&lt;!ATTLIST HEAD
+ %i18n; -- lang, dir --
+ &gt;
+
+&lt;!ELEMENT DEFVAR - O EMPTY -- variable definition --&gt;
+&lt;!ATTLIST DEFVAR
+ name CDATA #REQUIRED -- name
+ value CDATA #REQUIRED -- value
+ &gt;
+
+
+&lt;!ENTITY % html.content &quot;HEAD, PAGE&quot;&gt;
+
+&lt;!ELEMENT CUPSFORM - - (HEAD) (PAGE)+ -- document root element --&gt;
+&lt;!ATTLIST CUPSFORM
+ %i18n; -- lang, dir --
+ &gt;
+</PRE>
+</TD></TR>
+</TABLE>
+</CENTER>
+</P>
+<H2><A NAME="4_4">4.4 CUPS PostScript File</A></H2>
+<P>CUPS PostScript files are device-dependent Adobe PostScript program
+ files. The PostScript language is described in the<A HREF="http://partners.adobe.com/asn/developer/PDFS/TN/PLRM.pdf">
+ Adobe PostScript Language Reference Manual, Third Edition</A>.</P>
+<P>The MIME type for CUPS PostScript files is <CODE>
+application/vnd.cups-postscript</CODE>.</P>
+<H2><A NAME="4_5">4.5 CUPS Raster File</A></H2>
+<P>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.</P>
+<P>A raster file begins with a four byte synchronization word:
+ 0x52615374 (&quot;RaSt&quot;) for big-endian architectures and 0x74536152
+ (&quot;tSaR&quot;) for little-endian architectures. The writer of the raster file
+ will use the native word order, and the reader is responsible for
+ detecting a reversed word order file and swapping bytes as needed. The
+ CUPS Image Library raster functions perform this function
+ automatically.</P>
+<P>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.
+<CENTER>
+<TABLE BORDER="1" WIDTH="80%">
+<TR><TH WIDTH="10%">Bytes</TH><TH WIDTH="20%">Description</TH><TH>Values</TH>
+</TR>
+<TR><TD>0-63</TD><TD>MediaClass</TD><TD>Nul-terminated ASCII string</TD></TR>
+<TR><TD>64-127</TD><TD>MediaColor</TD><TD>Nul-terminated ASCII string</TD>
+</TR>
+<TR><TD>128-191</TD><TD>MediaType</TD><TD>Nul-terminated ASCII string</TD>
+</TR>
+<TR><TD>192-255</TD><TD>OutputType</TD><TD>Nul-terminated ASCII string</TD>
+</TR>
+<TR><TD>256-259</TD><TD>AdvanceDistance</TD><TD>0 to 2<SUP>32</SUP> - 1
+ points</TD></TR>
+<TR><TD>260-263</TD><TD>AdvanceMedia</TD><TD>0 = Never advance roll
+<BR> 1 = Advance roll after file
+<BR> 2 = Advance roll after job
+<BR> 3 = Advance roll after set
+<BR> 4 = Advance roll after page</TD></TR>
+<TR><TD>264-267</TD><TD>Collate</TD><TD>0 = do not collate copies
+<BR> 1 = collate copies</TD></TR>
+<TR><TD>268-271</TD><TD>CutMedia</TD><TD>0 = Never cut media
+<BR> 1 = Cut roll after file
+<BR> 2 = Cut roll after job
+<BR> 3 = Cut roll after set
+<BR> 4 = Cut roll after page</TD></TR>
+<TR><TD>272-275</TD><TD>Duplex</TD><TD>0 = Print single-sided
+<BR> 1 = Print double-sided</TD></TR>
+<TR><TD>276-283</TD><TD>HWResolution</TD><TD>Horizontal and vertical
+ resolution in dots-per-inch.</TD></TR>
+<TR><TD>284-299</TD><TD>ImagingBoundingBox</TD><TD>Four integers giving
+ the left, bottom, right, and top positions of the page bounding box in
+ points</TD></TR>
+<TR><TD>300-303</TD><TD>InsertSheet</TD><TD>0 = Do not insert separator
+ sheets
+<BR> 1 = Insert separator sheets</TD></TR>
+<TR><TD>304-307</TD><TD>Jog</TD><TD>0 = Do no jog pages
+<BR> 1 = Jog pages after file
+<BR> 2 = Jog pages after job
+<BR> 3 = Jog pages after set</TD></TR>
+<TR><TD>308-311</TD><TD>LeadingEdge</TD><TD>0 = Top edge is first
+<BR> 1 = Right edge is first
+<BR> 2 = Bottom edge is first
+<BR> 3 = Left edge is first</TD></TR>
+<TR><TD>312-319</TD><TD>Margins</TD><TD>Left and bottom origin of image
+ in points</TD></TR>
+<TR><TD>320-323</TD><TD>ManualFeed</TD><TD>0 = Do not manually feed
+ media
+<BR> 1 = Manually feed media</TD></TR>
+<TR><TD>324-327</TD><TD>MediaPosition</TD><TD>Input slot position from 0
+ to N</TD></TR>
+<TR><TD>328-331</TD><TD>MediaWeight</TD><TD>Media weight in grams per
+ meter squared</TD></TR>
+<TR><TD>332-335</TD><TD>MirrorPrint</TD><TD>0 = Do not mirror prints
+<BR> 1 = Mirror prints</TD></TR>
+<TR><TD>336-339</TD><TD>NegativePrint</TD><TD>0 = Do not invert prints
+<BR> 1 = Invert prints</TD></TR>
+<TR><TD>340-343</TD><TD>NumCopies</TD><TD>1 to 2<SUP>32</SUP> - 1</TD></TR>
+<TR><TD>344-347</TD><TD>Orientation</TD><TD>0 = Do not rotate page
+<BR> 1 = Rotate page counter-clockwise
+<BR> 2 = Turn page upside down
+<BR> 3 = Rotate page clockwise</TD></TR>
+<TR><TD>348-351</TD><TD>OutputFaceUp</TD><TD>0 = Output face down
+<BR> 1 = Output face up</TD></TR>
+<TR><TD>352-359</TD><TD>PageSize</TD><TD>Width and length in points</TD></TR>
+<TR><TD>360-363</TD><TD>Separations</TD><TD>0 = Print composite image
+<BR> 1 = Print color separations</TD></TR>
+<TR><TD>364-367</TD><TD>TraySwitch</TD><TD>0 = Do not change trays if
+ selected tray is empty
+<BR> 1 = Change trays if selected tray is empty</TD></TR>
+<TR><TD>368-371</TD><TD>Tumble</TD><TD>0 = Do not rotate even pages when
+ duplexing
+<BR> 1 = Rotate even pages when duplexing</TD></TR>
+<TR><TD>372-375</TD><TD>cupsWidth</TD><TD>Width of page image in pixels</TD>
+</TR>
+<TR><TD>376-379</TD><TD>cupsHeight</TD><TD>Height of page image in
+ pixels</TD></TR>
+<TR><TD>380-383</TD><TD>cupsMediaType</TD><TD>Driver-specific 0 to 2<SUP>
+32</SUP> - 1</TD></TR>
+<TR><TD>384-387</TD><TD>cupsBitsPerColor</TD><TD>1, 2, 4, 8 bits</TD></TR>
+<TR><TD>388-391</TD><TD>cupsBitsPerPixel</TD><TD>1 to 32 bits</TD></TR>
+<TR><TD>392-395</TD><TD>cupsBytesPerLine</TD><TD>1 to 2<SUP>32</SUP> - 1
+ bytes</TD></TR>
+<TR><TD>396-399</TD><TD>cupsColorOrder</TD><TD>0 = chunky pixels (CMYK
+ CMYK CMYK)
+<BR> 1 = banded pixels (CCC MMM YYY KKK)
+<BR> 2 = planar pixels (CCC... MMM... YYY... KKK...)</TD></TR>
+<TR><TD>400-403</TD><TD>cupsColorSpace</TD><TD>0 = white
+<BR> 1 = RGB
+<BR> 2 = RGBA
+<BR> 3 = black
+<BR> 4 = CMY
+<BR> 5 = YMC
+<BR> 6 = CMYK
+<BR> 7 = YMCK
+<BR> 8 = KCMY
+<BR> 9 = KCMYcm</TD></TR>
+<TR><TD>404-407</TD><TD>cupsCompression</TD><TD>Driver-specific 0 to 2<SUP>
+32</SUP> - 1</TD></TR>
+<TR><TD>408-411</TD><TD>cupsRowCount</TD><TD>Driver-specific 0 to 2<SUP>
+32</SUP> - 1</TD></TR>
+<TR><TD>412-415</TD><TD>cupsRowFeed</TD><TD>Driver-specific 0 to 2<SUP>
+32</SUP> - 1</TD></TR>
+<TR><TD>416-419</TD><TD>cupsRowStep</TD><TD>Driver-specific 0 to 2<SUP>
+32</SUP> - 1</TD></TR>
+</TABLE>
+</CENTER>
+</P>
+<P>The MIME type for CUPS Raster files is <CODE>
+application/vnd.cups-raster</CODE>.</P>
+<H2><A NAME="4_6">4.6 CUPS Raw Files</A></H2>
+<P>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 <CODE>application/vnd.cups-raw</CODE>.</P>
+<H2><A NAME="4_7">4.7 Internet Printing Protocol</A></H2>
+<P>The Internet Printing Protocol and the CUPS extensions to it are
+ described in the CUPS Implementation of IPP document.</P>
+<H2><A NAME="4_8">4.8 Line Printer Daemon Protocol</A></H2>
+<P>The Line Printer Daemon (LPD) protocol is described by<A HREF="http://www.ietf.org/rfc/rfc1179.txt">
+ RFC 1179: Line Printer Daemon Protocol</A>.</P>
+<P>The URI method name for LPD is &quot;lpd&quot;.</P>
+<H2><A NAME="4_9">4.9 Server Message Block Protocol</A></H2>
+<P>The Server Message Block (SMB) and related Common Internet File
+ System (CIFS) protocols are described at<A HREF="http://anu.samba.org/cifs">
+ http://anu.samba.org/cifs</A>.</P>
+<P>The URI method name for SMB is &quot;smb&quot;. Support for this protocol is
+ provided via the SAMBA <CODE>smbspool(1)</CODE> program provided with
+ SAMBA 2.0.6 and higher.</P>
+<H1><A NAME="5">5 Directories</A></H1>
+<DL>
+<DT>/etc/cups</DT>
+<DD>The scheduler configuration and MIME files reside here.</DD>
+<DT>/etc/cups/certs</DT>
+<DD>The authentication certificates reside here.</DD>
+<DT>/etc/cups/interfaces</DT>
+<DD>System V interface scripts reside here.</DD>
+<DT>/etc/cups/ppd</DT>
+<DD>This directory contains PPD files for each printer.</DD>
+<DT>/usr/bin</DT>
+<DD>The <CODE>cancel</CODE>, <CODE>lp</CODE>, <CODE>lpq</CODE>, <CODE>
+lpr</CODE>, <CODE>lprm</CODE>, and <CODE>lpstat</CODE> commands reside
+ here.</DD>
+<DT>/usr/lib, /usr/lib32</DT>
+<DD>The shared libraries (DSOs) reside here.</DD>
+<DT>/usr/lib/cups/backend</DT>
+<DD>The backend filters reside here.</DD>
+<DT>/usr/lib/cups/cgi-bin</DT>
+<DD>The CGI programs reside here.</DD>
+<DT>/usr/lib/cups/daemon</DT>
+<DD>The polling and LPD daemons reside here.</DD>
+<DT>/usr/lib/cups/filter</DT>
+<DD>The file filters reside here.</DD>
+<DT>/usr/sbin</DT>
+<DD>The <CODE>accept</CODE>, <CODE>cupsd</CODE>, <CODE>lpadmin</CODE>, <CODE>
+lpc</CODE>, and <CODE>reject</CODE> commands reside here.</DD>
+<DT>/usr/share/cups</DT>
+<DD>This is the root directory of the CUPS static data.</DD>
+<DT>/usr/share/cups/charsets</DT>
+<DD>The character set files reside here.</DD>
+<DT>/usr/share/cups/data</DT>
+<DD>The filter data files reside here.</DD>
+<DT>/usr/share/cups/fonts</DT>
+<DD>The <CODE>pstoraster</CODE> font files reside here.</DD>
+<DT>/usr/share/cups/model</DT>
+<DD>The sample PPD files reside here.</DD>
+<DT>/usr/share/cups/pstoraster</DT>
+<DD>The <CODE>pstoraster</CODE> data files reside here.</DD>
+<DT>/usr/share/doc/cups</DT>
+<DD>The scheduler documentation files reside here.</DD>
+<DT>/var/log/cups</DT>
+<DD>The <CODE>access_log</CODE>, <CODE>error_log</CODE>, and <CODE>
+page_log</CODE> files reside here.</DD>
+<DT>/var/spool/cups</DT>
+<DD>This directory contains print job files.</DD>
+</DL>
+<H1 TYPE="A" VALUE="1"><A NAME="6">A Glossary</A></H1>
+<H2><A NAME="6_1">A.1 Terms</A></H2>
+<DL>
+<DT>C</DT>
+<DD>A computer language.</DD>
+<DT>parallel</DT>
+<DD>Sending or receiving data more than 1 bit at a time.</DD>
+<DT>pipe</DT>
+<DD>A one-way communications channel between two programs.</DD>
+<DT>serial</DT>
+<DD>Sending or receiving data 1 bit at a time.</DD>
+<DT>socket</DT>
+<DD>A two-way network communications channel.</DD>
+</DL>
+<H2><A NAME="6_2">A.2 Acronyms</A></H2>
+<DL>
+<DT>ASCII</DT>
+<DD>American Standard Code for Information Interchange</DD>
+<DT>CUPS</DT>
+<DD>Common UNIX Printing System</DD>
+<DT>ESC/P</DT>
+<DD>EPSON Standard Code for Printers</DD>
+<DT>FTP</DT>
+<DD>File Transfer Protocol</DD>
+<DT>HP-GL</DT>
+<DD>Hewlett-Packard Graphics Language</DD>
+<DT>HP-PCL</DT>
+<DD>Hewlett-Packard Page Control Language</DD>
+<DT>HP-PJL</DT>
+<DD>Hewlett-Packard Printer Job Language</DD>
+<DT>IETF</DT>
+<DD>Internet Engineering Task Force</DD>
+<DT>IPP</DT>
+<DD>Internet Printing Protocol</DD>
+<DT>ISO</DT>
+<DD>International Standards Organization</DD>
+<DT>LPD</DT>
+<DD>Line Printer Daemon</DD>
+<DT>MIME</DT>
+<DD>Multimedia Internet Mail Exchange</DD>
+<DT>PPD</DT>
+<DD>PostScript Printer Description</DD>
+<DT>SMB</DT>
+<DD>Server Message Block</DD>
+<DT>TFTP</DT>
+<DD>Trivial File Transfer Protocol</DD>
+</DL>
+</BODY>
+</HTML>
diff --git a/doc/idd.pdf b/doc/idd.pdf
new file mode 100644
index 000000000..9f0e1a9ed
--- /dev/null
+++ b/doc/idd.pdf
Binary files differ
diff --git a/doc/idd.shtml b/doc/idd.shtml
new file mode 100644
index 000000000..d6c4f510a
--- /dev/null
+++ b/doc/idd.shtml
@@ -0,0 +1,1431 @@
+<HTML>
+<HEAD>
+ <META NAME="COPYRIGHT" CONTENT="Copyright 1997-2002, All Rights Reserved">
+ <META NAME="DOCNUMBER" CONTENT="CUPS-IDD-1.1">
+ <META NAME="Author" CONTENT="Easy Software Products">
+ <TITLE>CUPS Interface Design Description</TITLE>
+</HEAD>
+<BODY>
+
+<H1>Scope</H1>
+
+<H2>Identification</H2>
+
+<P>This interface design description document provides detailed file
+formats, message formats, and program conventions for the Common UNIX
+Printing System ("CUPS") Version 1.1.
+
+<EMBED SRC="system-overview.shtml">
+
+<H2>Document Overview</H2>
+
+<P>This interface design description document is organized into the following
+sections:
+
+<UL>
+ <LI>1 - Scope
+ <LI>2 - References
+ <LI>3 - Internal Interfaces
+ <LI>4 - External Interfaces
+ <LI>5 - Directories
+ <LI>A - Glossary
+</UL>
+
+<EMBED SRC="references.shtml">
+
+<H1>Internal Interfaces</H1>
+
+<H2>Character Set Files</H2>
+
+<P>The character set files define a mapping between 8-bit characters
+and the Unicode character set, or between Unicode and printer fonts.
+They are named using the IETF charset names defined in RFCnnnn. These
+files are ASCII text, the content of which is described below. Comments
+can be included by using the <TT>#</TT> character in the first column
+of a line.
+
+<H3>8-Bit Character Set Files</H3>
+
+<P>8-bit character set files start with a line reading:
+
+<UL><PRE>
+charset 8bit
+</PRE></UL>
+
+<P>Following this are lines that define the font information:
+
+<UL><PRE>
+first last direction width normal bold italic bold-italic
+</PRE></UL>
+
+<P><VAR>First</VAR> and <VAR>last</VAR> are the first and last glyphs
+in the font mapping that correspond to that font; a maximum of 256
+characters can be mapped within each group, with a maximum of 256
+mappings (this is a PostScript limitation.) The glyph values are
+hexadecimal.
+
+<P><VAR>Direction</VAR> is the string "ltor", "rtol", or "rtola" indicating
+left-to-right, right-to-left, or right-to-left Arabic text.
+
+<P><VAR>Width</VAR> is the string "single" or "double"; double means that the
+glyphs are twice as wide as ASCII characters in the Courier typeface.
+
+<P><VAR>Normal, bold, italic</VAR>, and <VAR>bold-italic</VAR> 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.
+
+<P>The remaining lines define a character to Unicode glyph mapping for the
+character set. The character and glyph values are hexadecimal:
+
+<UL><PRE>
+xx yyyy
+</PRE></UL>
+
+<H3>Unicode Character Set Files</H3>
+
+<P>Unicode character set files start with a line reading:
+
+<UL><PRE>
+charset encoding
+</PRE></UL>
+
+<P><VAR>Encoding</VAR> is the encoding to use for the text; currently only
+the string "utf8" is supported.
+
+<P>Following this are lines defining the font information:
+
+<UL><PRE>
+first last direction width normal bold italic bold-italic
+</PRE></UL>
+
+<P><VAR>First</VAR> and <VAR>last</VAR> are the first and last glyphs
+in the font mapping that correspond to that font; a maximum of 256
+characters can be mapped within each group, with a maximum of 256
+mappings (this is a PostScript limitation.) The glyph values are
+hexadecimal.
+
+<P><VAR>Direction</VAR> is the string "ltor", "rtol", or "rtola" indicating
+left-to-right, right-to-left, or right-to-left Arabic text.
+
+<P><VAR>Width</VAR> is the string "single" or "double"; double means that the
+glyphs are twice as wide as ASCII characters in the Courier typeface.
+
+<P><VAR>Normal, bold, italic</VAR>, and <VAR>bold-italic</VAR> 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.
+
+<H2>Language Files</H2>
+
+<P>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.
+
+<P>The first line identifies the character set to be used for the messages.
+The currently recognized values are:
+
+<UL>
+ <LI>iso-8859-1
+ <LI>iso-8859-2
+ <LI>iso-8859-3
+ <LI>iso-8859-4
+ <LI>iso-8859-5
+ <LI>iso-8859-6
+ <LI>iso-8859-7
+ <LI>iso-8859-8
+ <LI>iso-8859-9
+ <LI>iso-8859-10
+ <LI>iso-8859-13
+ <LI>iso-8859-14
+ <LI>iso-8859-15
+ <LI>us-ascii
+ <LI>utf-8
+ <LI>windows-874
+ <LI>windows-1250
+ <LI>windows-1251
+ <LI>windows-1252
+ <LI>windows-1253
+ <LI>windows-1254
+ <LI>windows-1255
+ <LI>windows-1256
+ <LI>windows-1257
+ <LI>windows-1258
+ <LI>koi8-r
+ <LI>koi8-u
+</UL>
+
+<P>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.
+
+<H2>MIME Files</H2>
+
+<P>CUPS uses two MIME files in its standard configuration.
+
+<H3>mime.types</H3>
+
+<P>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.
+
+<P>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:
+
+<UL><PRE>
+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 ")" |
+ "contains(" offset "," length "," string ")" |
+ "char(" offset "," value ")" |
+ "short(" offset "," value ")" |
+ "int(" offset "," value ")" |
+ "locale(" string ")"
+operator := "+" | [ logical AND ]
+ "," | SP [ logical OR ]
+ "!" [ unary NOT ]
+</PRE></UL>
+
+<P>The <CODE>int</CODE> and <CODE>short</CODE> rules match look for integers
+in network byte order (a.k.a. big-endian) with the most-significant byte first.
+
+<H3>mime.convs</H3>
+
+<P>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.
+
+<P>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:
+
+<UL><PRE>
+super/type SP super/type2 SP cost SP program
+</PRE></UL>
+
+<H2>Option Files</H2>
+
+<P>CUPS maintains user-defined printer and option files for each
+printer and user on the system. The printers and options defined in the
+system option file (<CODE>/etc/cups/lpoptions</CODE>) are loaded first,
+followed by the user option file (<CODE>$HOME/.lpoptions</CODE>).
+Options in the user file replace those defined in the system file for
+the same destination. Each line in the files can be one of the
+following:
+
+<UL><PRE>
+Dest name option=value option=value ... option=value
+Dest name/instance option=value option=value ... option=value
+Default name option=value option=value ... option=value
+Default name/instance option=value option=value ... option=value
+</PRE></UL>
+
+<P>The line beginning with "Default" indicates the default destination for
+print jobs; a default line in the user option file overrides the default
+defined in the system option file.
+
+<P><VAR>Name</VAR> is the name of a printer known to the local server.
+
+<P><VAR>Instance</VAR> can be any string of letters, numbers, and the underscore
+up to 127 characters in length.
+
+<P>The remainder of the line contains a list of space-separated options
+and their values.
+
+<H2>PostScript Printer Description Files</H2>
+
+<P>PostScript Printer Description ("PPD") files describe the capabilities
+of each printer and are used by CUPS to support printer-specific features
+and intelligent filtering.
+
+<H3>PPD Specification</H3>
+
+<P>The PPD file format is described in
+<A HREF="http://partners.adobe.com/asn/developer/PDFS/TN/5003.PPD_Spec_v4.3.pdf">
+Adobe TechNote #5003: PostScript Printer Description File Format
+Specification Version 4.3</A>.
+
+<H3>CUPS Extensions to PPD Files</H3>
+
+<P>CUPS adds several new attributes that are described below.
+
+<H4>cupsFilter</H4>
+
+<P>This string attribute provides a conversion rule of the form:
+
+<UL><PRE>
+source/type cost program
+</PRE></UL>
+
+<P>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.
+
+<H4>cupsManualCopies</H4>
+
+<P>This boolean attribute notifies the RIP filters that the destination printer
+does not support copy generation in hardware. The default value is false.
+
+<H4>cupsModelNumber</H4>
+
+<P>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.
+
+<H4>cupsProfile</H4>
+
+<P>This string attribute specifies a color profile of the form:
+
+<UL><PRE>
+resolution/type density gamma m00 m01 m02 m10 m11 m12 m20 m21 m22
+</PRE></UL>
+
+<P>The <I>resolution</I> and <I>type</I> values may be "-" to act as a
+wildcard. Otherwise they must match one of the <CODE>Resolution</CODE> or
+<CODE>MediaType</CODE> attributes defined in the PPD file.
+
+<P>The <I>density</I> and <I>gamma</I> values define gamma and density
+adjustment function such that:
+
+<UL><PRE>
+f(x) = density * x<SUP>gamma</SUP>
+</PRE></UL>
+
+<P>The <I>m00</I> through <I>m22</I> values define a 3x3 transformation
+matrix for the CMY color values. The density function is applied <I>after</I>
+the CMY transformation.
+
+<H4>cupsVersion</H4>
+
+<P>This required attribute describes which version of the CUPS IDD was used
+for the PPD file extensions. Currently it must be the string "1.0" or "1.1".
+
+<H2>Scheduler Configuration Files</H2>
+
+<P>The scheduler reads three configuration files that define the available
+printers, classes, and services:
+
+<DL>
+
+ <DT>classes.conf
+ <DD>This file defines all of the printer classes known to the
+ system.
+
+ <DT>cupsd.conf
+ <DD>This file defines the files, directories, passwords, etc.
+ used by the scheduler.
+
+ <DT>printers.conf
+ <DD>This file defines all of the printers known to the system.
+
+</DL>
+
+<H3>classes.conf</H3>
+
+<P>The classes.conf file consists of 1 or more lines of ASCII text.
+Comment lines start with the pound ("#") character.
+
+<P>Each non-blank line starts with the name of a configuration directive
+followed by its value. The following directives are understood:
+
+<CENTER><TABLE WIDTH="90%" BORDER="1">
+<TR>
+ <TH WIDTH="25%">Directive</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>&lt;Class name&gt;<BR>
+ &lt;/Class&gt;</TD>
+ <TD>Surrounds a class definition.</TD>
+</TR>
+<TR>
+ <TD>&lt;DefaultClass name&gt;<BR>
+ &lt;/Class&gt;</TD>
+ <TD>Surrounds a class definition for the default destination.</TD>
+</TR>
+<TR>
+ <TD>Accepting</TD>
+ <TD>Specifies whether the class is accepting new jobs. May be
+ the names "Yes" or "No".</TD>
+</TR>
+<TR>
+ <TD>AllowUsers</TD>
+ <TD>Specifies a list of users that are allowed to access the class.</TD>
+</TR>
+<TR>
+ <TD>BannerStart</TD>
+ <TD>Specifies the banner that is printed before other files in a
+ job.</TD>
+</TR>
+<TR>
+ <TD>BannerEnd</TD>
+ <TD>Specifies the banner that is printed after other files in a
+ job.</TD>
+</TR>
+<TR>
+ <TD>DenyUsers</TD>
+ <TD>Specifies a list of users that are not allowed to access the
+ class.</TD>
+</TR>
+<TR>
+ <TD>Info</TD>
+ <TD>A textual description of the class.</TD>
+</TR>
+<TR>
+ <TD>Location</TD>
+ <TD>A textual location of the class.</TD>
+</TR>
+<TR>
+ <TD>Printer</TD>
+ <TD>Specifies a printer that is a member of the class.</TD>
+</TR>
+<TR>
+ <TD>State</TD>
+ <TD>Specifies the initial state of the class; can be "Idle" or
+ "Stopped".</TD>
+</TR>
+<TR>
+ <TD>StateMessage</TD>
+ <TD>Specifies a textual message for the current class state.</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>cupsd.conf</H3>
+
+<P>The cupsd.conf file consists of 1 or more lines of ASCII text.
+Comment lines start with the pound ("#") character.
+
+<P>Each non-blank line starts with the name of a configuration directive
+followed by its value. The following directives are understood:
+
+<CENTER><TABLE WIDTH="90%" BORDER="1">
+<TR>
+ <TH WIDTH="25%">Directive</TH>
+ <TH>Default</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>AccessLog</TD>
+ <TD>access_log</TD>
+ <TD>Specifies the location of the access log file. The special name
+ "syslog" can be used to send access log information to the system
+ log.</TD>
+</TR>
+<TR>
+ <TD>Allow</TD>
+ <TD>-</TD>
+ <TD>Allows connections from the specified host, network, or
+ domain.</TD>
+</TR>
+<TR>
+ <TD>AuthClass</TD>
+ <TD>-</TD>
+ <TD>Specifies what level of authentication is required; may be
+ "User", "System", or "Group".</TD>
+</TR>
+<TR>
+ <TD>AuthType</TD>
+ <TD>None</TD>
+ <TD>Specifies the type of authentication to perform; may be
+ "None", "Basic", or "Digest".</TD>
+</TR>
+<TR>
+ <TD>BrowseAddress</TD>
+ <TD>255.255.255.255</TD>
+ <TD>Specifies a broadcast address to send CUPS browsing packets to.</TD>
+</TR>
+<TR>
+ <TD>BrowseAllow</TD>
+ <TD>-</TD>
+ <TD>Specifies hosts or addresses from which browsing information
+ should be used.</TD>
+</TR>
+<TR>
+ <TD>BrowseDeny</TD>
+ <TD>-</TD>
+ <TD>Specifies hosts or addresses from which browsing information
+ should not be used.</TD>
+</TR>
+<TR>
+ <TD>BrowseInterval</TD>
+ <TD>30</TD>
+ <TD>Specifies the number of seconds between browsing updates. A
+ browse interval of 0 seconds disables outgoing packets.</TD>
+</TR>
+<TR>
+ <TD>BrowseOrder</TD>
+ <TD>Allow,Deny</TD>
+ <TD>Specifies the order of BrowseAllow and BrowseDeny directive
+ processing; can be "Deny,Allow" to implicitly deny hosts unless
+ they are allowed by a BrowseAllow line, or "Allow,Deny" to
+ implicitly allow hosts unless they are denied by a BrowseDeny
+ line.</TD>
+</TR>
+<TR>
+ <TD>BrowsePoll</TD>
+ <TD>-</TD>
+ <TD>Specifies a server to poll for available printers and classes.</TD>
+</TR>
+<TR>
+ <TD>BrowsePort</TD>
+ <TD>631</TD>
+ <TD>Specifies the UDP port number to use for browse packets.</TD>
+</TR>
+<TR>
+ <TD>BrowseRelay</TD>
+ <TD>-</TD>
+ <TD>Specifies a source and destination address for relaying browser
+ information from one subnet to another.</TD>
+</TR>
+<TR>
+ <TD>BrowseShortNames</TD>
+ <TD>yes</TD>
+ <TD>Specifies whether or not to provide short names (without the
+ "@server" part) for remote printers.</TD>
+</TR>
+<TR>
+ <TD>BrowseTimeout</TD>
+ <TD>300</TD>
+ <TD>Specifies the number of seconds to wait until remote destinations
+ are removed from the local destination list.</TD>
+</TR>
+<TR>
+ <TD>Browsing</TD>
+ <TD>On</TD>
+ <TD>Specifies whether or not printer and class browsing is enabled; can
+ be "On" or "Off".</TD>
+</TR>
+<TR>
+ <TD>DataDir</TD>
+ <TD>/usr/share/cups</TD>
+ <TD>Specifies the directory where CUPS data files are stored.</TD>
+</TR>
+<TR>
+ <TD>DefaultCharset</TD>
+ <TD>iso-8859-1</TD>
+ <TD>Specifies the default character set.</TD>
+</TR>
+<TR>
+ <TD>DefaultLanguage</TD>
+ <TD>current locale</TD>
+ <TD>Specifies the default language.</TD>
+</TR>
+<TR>
+ <TD>Deny</TD>
+ <TD>-</TD>
+ <TD>Refuses connections from the specified host, network, or
+ domain.</TD>
+</TR>
+<TR>
+ <TD>DocumentRoot</TD>
+ <TD>/usr/share/doc/cups</TD>
+ <TD>Specifies the document data root directory.</TD>
+</TR>
+<TR>
+ <TD>ErrorLog</TD>
+ <TD>error_log</TD>
+ <TD>Specifies the error log file location. The special name
+ "syslog" can be used to send error log information to the system
+ log.</TD>
+</TR>
+<TR>
+ <TD>Group</TD>
+ <TD>root, sys, system</TD>
+ <TD>Specifies the group name or ID that is used when running
+ external programs.</TD>
+</TR>
+<TR>
+ <TD>HostNameLookups</TD>
+ <TD>Off</TD>
+ <TD>Specifies whether or not to perform reverse IP address lookups to
+ get the actual hostname; may be "On" or "Off". Hostname lookups can
+ significantly degrade the performance of the CUPS server if one or
+ more DNS servers is not functioning properly.</TD>
+</TR>
+<TR>
+ <TD>ImplicitClasses</TD>
+ <TD>On</TD>
+ <TD>Specifies whether or not to automatically create printer classes
+ when more than one printer or class of the same name is detected on
+ the network; may be "On" or "Off".</TD>
+</TR>
+<TR>
+ <TD>KeepAlive</TD>
+ <TD>On</TD>
+ <TD>Specifies whether or not to use the HTTP Keep-Alive feature; may
+ be "On" or "Off".</TD>
+</TR>
+<TR>
+ <TD>KeepAliveTimeout</TD>
+ <TD>30</TD>
+ <TD>Specifies the amount of time to keep the HTTP connection alive
+ before closing it.</TD>
+</TR>
+<TR>
+ <TD>&lt;Location path&gt;<BR>
+ &lt;/Location&gt;</TD>
+ <TD>-</TD>
+ <TD>Specifies a location to restrict access to.</TD>
+</TR>
+<TR>
+ <TD>LogLevel</TD>
+ <TD>info</TD>
+ <TD>Controls the amount of information that is logged in the
+ error log file. Can be one of "debug", "info", "warn", "error",
+ or "none", in decreasing order or verbosity.</TD>
+</TR>
+<TR>
+ <TD>MaxClients</TD>
+ <TD>100</TD>
+ <TD>Specifies the maximum number of simultaneous active clients.
+ This value is internally limited to 1/3 of the total number of
+ available file descriptors.</TD>
+</TR>
+<TR>
+ <TD>MaxLogSize</TD>
+ <TD>0</TD>
+ <TD>Specifies the maximum size of the access, error, and page
+ log files in bytes. If set to 0 then no maximum size is set.
+ Log files are rotated automatically when this size is
+ exceeded.</TD>
+</TR>
+<TR>
+ <TD>MaxRequestSize</TD>
+ <TD>0</TD>
+ <TD>Specifies the maximum size of HTTP requests in bytes. If set to 0
+ then there is no maximum.</TD>
+</TR>
+<TR>
+ <TD>Order</TD>
+ <TD>Allow,Deny</TD>
+ <TD>Specifies the order of Allow and Deny directive processing; can
+ be "Deny,Allow" to implicitly deny hosts unless they are allowed by
+ an Allow line, or "Allow,Deny" to implicitly allow hosts unless they
+ are denied by a Deny line.</TD>
+</TR>
+<TR>
+ <TD>PageLog</TD>
+ <TD>page_log</TD>
+ <TD>Specifies the location of the page log file. The special name
+ "syslog" can be used to send page log information to the system
+ log.</TD>
+</TR>
+<TR>
+ <TD>Port</TD>
+ <TD>631</TD>
+ <TD>Specifies a port number to listen to for HTTP connections.</TD>
+</TR>
+<TR>
+ <TD>Printcap</TD>
+ <TD>/etc/printcap</TD>
+ <TD>Specifies the location of a Berkeley printcap file to update
+ with a list of current printers and classes. If no filename is
+ supplied then this automatic generation is disabled.</TD>
+</TR>
+<TR>
+ <TD>RequestRoot</TD>
+ <TD>/var/spool/cups</TD>
+ <TD>Specifies the location of request files.</TD>
+</TR>
+<TR>
+ <TD>RIPCache</TD>
+ <TD>8m</TD>
+ <TD>Specifies the size of the memory cache in bytes that is used by
+ RIP filters.</TD>
+</TR>
+<TR>
+ <TD>ServerAdmin</TD>
+ <TD>root@ServerName</TD>
+ <TD>Specifies the person to contact with problems.</TD>
+</TR>
+<TR>
+ <TD>ServerName</TD>
+ <TD>hostname</TD>
+ <TD>Specifies the hostname that is supplied to HTTP clients. This
+ is also used to determine the default CUPS server for the CUPS IPP
+ client applications.</TD>
+</TR>
+<TR>
+ <TD>ServerRoot</TD>
+ <TD>/etc/cups</TD>
+ <TD>Specifies the root directory for server configuration files.</TD>
+</TR>
+<TR>
+ <TD>SystemGroup</TD>
+ <TD>root, sys, system</TD>
+ <TD>Specifies the group name used for System class authentication.</TD>
+</TR>
+<TR>
+ <TD>TempDir</TD>
+ <TD>/var/tmp</TD>
+ <TD>Specifies the temporary directory to use.</TD>
+</TR>
+<TR>
+ <TD>Timeout</TD>
+ <TD>300</TD>
+ <TD>The timeout in seconds before client connections are closed
+ in the middle of a request.</TD>
+</TR>
+<TR>
+ <TD>User</TD>
+ <TD>lp</TD>
+ <TD>Specifies the user that is used when running external programs.</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>printers.conf</H3>
+
+<P>The printers.conf file consists of 1 or more lines of ASCII text.
+Comment lines start with the pound ("#") character.
+
+<P>Each non-blank line starts with the name of a configuration directive
+followed by its value. The following directives are understood:
+
+<CENTER><TABLE WIDTH="90%" BORDER="1">
+<TR>
+ <TH WIDTH="25%">Directive</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>Accepting</TD>
+ <TD>Specifies whether the printer is accepting new jobs. May be
+ the names "Yes" or "No".</TD>
+</TR>
+<TR>
+ <TD>&lt;DefaultPrinter name&gt;<BR>
+ &lt;/Printer&gt;</TD>
+ <TD>Surrounds the printer definition for a default destination.</TD>
+</TR>
+<TR>
+ <TD>AllowUsers</TD>
+ <TD>Specifies a list of users that are allowed to access the printer.</TD>
+</TR>
+<TR>
+ <TD>BannerStart</TD>
+ <TD>Specifies the banner that is printed before other files in a
+ job.</TD>
+</TR>
+<TR>
+ <TD>BannerEnd</TD>
+ <TD>Specifies the banner that is printed after other files in a
+ job.</TD>
+</TR>
+<TR>
+ <TD>DenyUsers</TD>
+ <TD>Specifies a list of users that are not allowed to access the
+ printer.</TD>
+</TR>
+<TR>
+ <TD>DeviceURI</TD>
+ <TD>Specifies the device-uri attribute for the printer.</TD>
+</TR>
+<TR>
+ <TD>Info</TD>
+ <TD>A textual description of the printer.</TD>
+</TR>
+<TR>
+ <TD>Location</TD>
+ <TD>A textual location of the printer.</TD>
+</TR>
+<TR>
+ <TD>&lt;Printer name&gt;<BR>
+ &lt;/Printer&gt;</TD>
+ <TD>Surrounds the printer definition.</TD>
+</TR>
+<TR>
+ <TD>State</TD>
+ <TD>Specifies the initial state of the printer; can be "Idle" or
+ "Stopped".</TD>
+</TR>
+<TR>
+ <TD>StateMessage</TD>
+ <TD>Specifies a textual message for the current printer state.</TD>
+</TR>
+</TABLE></CENTER>
+
+<H1>External Interfaces</H1>
+
+<H2>AppSocket Protocol</H2>
+
+<P>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".
+
+<P>The AppSocket protocol is used by the Hewlett Packard JetDirect
+network interfaces and print servers, as well as many other vendors'
+products. See the CUPS Software Administrators Manual for a list of
+supported products.
+
+<H2>CUPS Browsing Protocol</H2>
+
+<P>The CUPS Browsing Protocol is a UDP/IP-based broadcast service. By default
+this service operates on IP service port 631.
+
+<P>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:
+
+<UL><PRE>
+type SP state SP uri SP "location" SP "info" SP "make-and-model" NL
+</PRE></UL>
+
+<P><VAR>State, uri, location, info</VAR>, and <VAR>make-and-model</VAR>,
+correspond to the IPP <CODE>printer-state</CODE>,
+<CODE>printer-uri-supported</CODE>, <CODE>printer-location</CODE>,
+<CODE>printer-info</CODE>, and <CODE>printer-make-and-model</CODE>
+attributes.
+
+<P><VAR>Type</VAR> is a hexadecimal number string representing
+capability/type bits:
+
+<CENTER><TABLE WIDTH="40%" BORDER="1">
+<TR>
+ <TH WIDTH="8%">Bit</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>0</TD>
+ <TD>0 = printer<BR>
+ 1 = class</TD>
+</TR>
+<TR>
+ <TD>1</TD>
+ <TD>0 = local<BR>
+ 1 = remote<BR>
+ (always 1)</TD>
+</TR>
+<TR>
+ <TD>2</TD>
+ <TD>1 = can print B&W</TD>
+</TR>
+<TR>
+ <TD>3</TD>
+ <TD>1 = can print color</TD>
+</TR>
+<TR>
+ <TD>4</TD>
+ <TD>1 = can duplex</TD>
+</TR>
+<TR>
+ <TD>5</TD>
+ <TD>1 = can staple</TD>
+</TR>
+<TR>
+ <TD>6</TD>
+ <TD>1 = can do fast copies</TD>
+</TR>
+<TR>
+ <TD>7</TD>
+ <TD>1 = can do fast collating</TD>
+</TR>
+<TR>
+ <TD>8</TD>
+ <TD>1 = can punch holes</TD>
+</TR>
+<TR>
+ <TD>9</TD>
+ <TD>1 = can cover</TD>
+</TR>
+<TR>
+ <TD>10</TD>
+ <TD>1 = can bind</TD>
+</TR>
+<TR>
+ <TD>11</TD>
+ <TD>1 = can sort</TD>
+</TR>
+<TR>
+ <TD>12</TD>
+ <TD>1 = can print up to 9x14 inches</TD>
+</TR>
+<TR>
+ <TD>13</TD>
+ <TD>1 = can print up to 18x24 inches</TD>
+</TR>
+<TR>
+ <TD>14</TD>
+ <TD>1 = can print up to 36x48 inches</TD>
+</TR>
+<TR>
+ <TD>15</TD>
+ <TD>1 = can print variable sizes</TD>
+</TR>
+</TABLE></CENTER>
+
+<H2>CUPS Form File</H2>
+
+<P>CUPS Form files are XML files used by the CUPS <CODE>formtops</CODE>
+filter to produce dynamic banner pages and support preprinted forms.
+
+<P>The MIME type for CUPS Form files is
+<CODE>application/vnd.cups-form</CODE>.
+
+<H3>CUPS Form DTD</H3>
+
+<P>The following DTD describes the available elements and attributes in
+a CUPS Form file:
+
+<CENTER><TABLE BORDER>
+<TR>
+<TD><PRE>
+&lt;!ENTITY % Angle "CDATA" -- angle in degrees -->
+
+&lt;!ENTITY % Color "CDATA" -- a color using sRGB: #RRGGBB as Hex values -->
+
+&lt;!ENTITY % Length "CDATA" -- nn for pixels or nn% for percentage length -->
+
+&lt;!ENTITY % Lengths "CDATA" -- comma-separated Length values -->
+
+&lt;!ENTITY % Text "CDATA">
+
+&lt;!ENTITY % heading "H1|H2|H3|H4|H5|H6">
+
+&lt;!ENTITY % preformatted "PRE">
+
+&lt;!ENTITY % i18n
+ "lang %LanguageCode; #IMPLIED -- language code --
+ dir (ltr|rtl) #IMPLIED -- direction for weak/neutral text --"
+ >
+
+&lt;!ENTITY % attrs "%i18n;">
+
+&lt;!ENTITY % fontstyle
+ "B | FONT | I | TT">
+
+&lt;!ENTITY % graphics
+ "BOX | RECT | LINE | POLY | ARC | PIE | TEXT">
+
+&lt;!ENTITY % insert
+ "IMG | VAR">
+
+&lt;!-- %inline; covers inline or "text-level" elements -->
+&lt;!ENTITY % inline "#PCDATA | %fontstyle; | %graphics; | %insert;">
+
+&lt;!ELEMENT (%fontstyle;) - - (%inline;)*>
+&lt;!ATTLIST (%fontstyle;)
+ %attrs; -- %i18n --
+ >
+
+&lt;!ELEMENT BR - O EMPTY -- forced line break -->
+&lt;!ATTLIST BR
+ %attrs; -- %i18n --
+ >
+
+&lt;!ENTITY % block
+ "P | %heading; | %preformatted;">
+
+&lt;!ENTITY % flow "%block; | %inline;">
+
+&lt;!ELEMENT PAGE O O (%flow;)+ -- document body -->
+&lt;!ATTLIST PAGE
+ %attrs; -- %i18n --
+ align (left|center|right) #IMPLIED -- horizontal alignment --
+ valign (top|middle|center|bottom) #IMPLIED -- vertical alignment --
+ >
+
+&lt;!ELEMENT P - O (%inline;)* -- paragraph -->
+&lt;!ATTLIST P
+ %attrs; -- %i18n --
+ align (left|center|right) #IMPLIED -- horizontal alignment --
+ >
+
+&lt;!ELEMENT (%heading;) - - (%inline;)* -- heading -->
+&lt;!ATTLIST (%heading;)
+ %attrs; -- %i18n --
+ align (left|center|right) #IMPLIED -- horizontal alignment --
+ >
+
+&lt;!ELEMENT PRE - - (%inline;)* -- preformatted text -->
+&lt;!ATTLIST PRE
+ %attrs; -- %i18n --
+ align (left|center|right) #IMPLIED -- horizontal alignment --
+ >
+
+&lt;!ELEMENT BOX - O EMPTY -- unfilled box -->
+&lt;!ATTLIST BOX
+ color %Color; #IMPLIED -- override color --
+ height %Length; #REQUIRED -- height of box --
+ thickness %Length; #IMPLIED -- override line thickness --
+ width %Length; #REQUIRED -- width of box --
+ x %Length; #REQUIRED -- horizontal position --
+ y %Length; #REQUIRED -- vertical position --
+ >
+
+&lt;!ELEMENT RECT - O EMPTY -- filled box -->
+&lt;!ATTLIST RECT
+ color %Color; #IMPLIED -- override color --
+ height %Length; #REQUIRED -- height of box --
+ width %Length; #REQUIRED -- width of box --
+ x %Length; #REQUIRED -- horizontal position --
+ y %Length; #REQUIRED -- vertical position --
+ >
+
+&lt;!ELEMENT LINE - O EMPTY -- polyline -->
+&lt;!ATTLIST LINE
+ color %Color; #IMPLIED -- override color --
+ thickness %Length; #IMPLIED -- override line thickness --
+ x %Lengths; #REQUIRED -- horizontal positions --
+ y %Lengths; #REQUIRED -- vertical positions --
+ >
+
+&lt;!ELEMENT POLY - O EMPTY -- polygon (filled) -->
+&lt;!ATTLIST POLY
+ color %Color; #IMPLIED -- override color --
+ x %Lengths; #REQUIRED -- horizontal positions --
+ y %Lengths; #REQUIRED -- vertical positions --
+ >
+
+&lt;!ELEMENT ARC - O EMPTY -- unfilled arc -->
+&lt;!ATTLIST ARC
+ color %Color; #IMPLIED -- override color --
+ end %Angle; #IMPLIED -- override end angle --
+ height %Length; #REQUIRED -- height of arc --
+ start %Angle; #IMPLIED -- override start angle --
+ thickness %Length; #IMPLIED -- override line thickness --
+ width %Length; #REQUIRED -- width of arc --
+ x %Length; #REQUIRED -- horizontal position --
+ y %Length; #REQUIRED -- vertical position --
+ >
+
+&lt;!ELEMENT PIE - O EMPTY -- filled arc -->
+&lt;!ATTLIST PIE
+ color %Color; #IMPLIED -- override color --
+ end %Angle; #IMPLIED -- override end angle --
+ height %Length; #REQUIRED -- height of arc --
+ start %Angle; #IMPLIED -- override start angle --
+ width %Length; #REQUIRED -- width of arc --
+ x %Length; #REQUIRED -- horizontal position --
+ y %Length; #REQUIRED -- vertical position --
+ >
+
+&lt;!ELEMENT TEXT - - (%flow;)* -- text box -->
+&lt;!ATTLIST RECT
+ align (left|center|right) #IMPLIED -- horizontal alignment --
+ height %Length; #REQUIRED -- height of box --
+ valign (top|middle|center|bottom) #IMPLIED -- vertical alignment --
+ width %Length; #REQUIRED -- width of box --
+ x %Length; #REQUIRED -- horizontal position --
+ y %Length; #REQUIRED -- vertical position --
+ >
+
+
+&lt;!ELEMENT IMG - O EMPTY -- Embedded image -->
+&lt;!ATTLIST IMG
+ %attrs; -- %coreattrs, %i18n, %events --
+ src %URI; #REQUIRED -- URI of image to embed --
+ height %Length; #IMPLIED -- override height --
+ width %Length; #IMPLIED -- override width --
+ >
+
+&lt;!ELEMENT HEAD O O (DEFVAR)* -- document head -->
+&lt;!ATTLIST HEAD
+ %i18n; -- lang, dir --
+ >
+
+&lt;!ELEMENT DEFVAR - O EMPTY -- variable definition -->
+&lt;!ATTLIST DEFVAR
+ name CDATA #REQUIRED -- name
+ value CDATA #REQUIRED -- value
+ >
+
+
+&lt;!ENTITY % html.content "HEAD, PAGE">
+
+&lt;!ELEMENT CUPSFORM - - (HEAD) (PAGE)+ -- document root element -->
+&lt;!ATTLIST CUPSFORM
+ %i18n; -- lang, dir --
+ >
+</PRE></TD>
+</TR>
+</TABLE></CENTER>
+
+<H2>CUPS PostScript File</H2>
+
+<P>CUPS PostScript files are device-dependent Adobe PostScript program files.
+The PostScript language is described in the
+<A HREF="http://partners.adobe.com/asn/developer/PDFS/TN/PLRM.pdf">
+Adobe PostScript Language Reference Manual, Third Edition</A>.
+
+<P>The MIME type for CUPS PostScript files is
+<CODE>application/vnd.cups-postscript</CODE>.
+
+<H2>CUPS Raster File</H2>
+
+<P>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.
+
+<P>A raster file begins with a four byte synchronization word: 0x52615374
+("RaSt") for big-endian architectures and 0x74536152 ("tSaR") for little-endian
+architectures. The writer of the raster file will use the native word order,
+and the reader is responsible for detecting a reversed word order file and
+swapping bytes as needed. The CUPS Image Library raster functions perform
+this function automatically.
+
+<P>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.
+
+<CENTER><TABLE WIDTH="80%" BORDER="1">
+<TR>
+ <TH WIDTH="10%">Bytes</TH>
+ <TH WIDTH="20%">Description</TH>
+ <TH>Values</TH>
+</TR>
+<TR>
+ <TD>0-63</TD>
+ <TD>MediaClass</TD>
+ <TD>Nul-terminated ASCII string</TD>
+</TR>
+<TR>
+ <TD>64-127</TD>
+ <TD>MediaColor</TD>
+ <TD>Nul-terminated ASCII string</TD>
+</TR>
+<TR>
+ <TD>128-191</TD>
+ <TD>MediaType</TD>
+ <TD>Nul-terminated ASCII string</TD>
+</TR>
+<TR>
+ <TD>192-255</TD>
+ <TD>OutputType</TD>
+ <TD>Nul-terminated ASCII string</TD>
+</TR>
+<TR>
+ <TD>256-259</TD>
+ <TD>AdvanceDistance</TD>
+ <TD>0 to 2<SUP>32</SUP> - 1 points</TD>
+</TR>
+<TR>
+ <TD>260-263</TD>
+ <TD>AdvanceMedia</TD>
+ <TD>0 = Never advance roll<BR>
+ 1 = Advance roll after file<BR>
+ 2 = Advance roll after job<BR>
+ 3 = Advance roll after set<BR>
+ 4 = Advance roll after page</TD>
+</TR>
+<TR>
+ <TD>264-267</TD>
+ <TD>Collate</TD>
+ <TD>0 = do not collate copies<BR>
+ 1 = collate copies</TD>
+</TR>
+<TR>
+ <TD>268-271</TD>
+ <TD>CutMedia</TD>
+ <TD>0 = Never cut media<BR>
+ 1 = Cut roll after file<BR>
+ 2 = Cut roll after job<BR>
+ 3 = Cut roll after set<BR>
+ 4 = Cut roll after page</TD>
+</TR>
+<TR>
+ <TD>272-275</TD>
+ <TD>Duplex</TD>
+ <TD>0 = Print single-sided<BR>
+ 1 = Print double-sided</TD>
+</TR>
+<TR>
+ <TD>276-283</TD>
+ <TD>HWResolution</TD>
+ <TD>Horizontal and vertical resolution in dots-per-inch.</TD>
+</TR>
+<TR>
+ <TD>284-299</TD>
+ <TD>ImagingBoundingBox</TD>
+ <TD>Four integers giving the left, bottom, right, and top positions
+ of the page bounding box in points</TD>
+</TR>
+<TR>
+ <TD>300-303</TD>
+ <TD>InsertSheet</TD>
+ <TD>0 = Do not insert separator sheets<BR>
+ 1 = Insert separator sheets</TD>
+</TR>
+<TR>
+ <TD>304-307</TD>
+ <TD>Jog</TD>
+ <TD>0 = Do no jog pages<BR>
+ 1 = Jog pages after file<BR>
+ 2 = Jog pages after job<BR>
+ 3 = Jog pages after set</TD>
+</TR>
+<TR>
+ <TD>308-311</TD>
+ <TD>LeadingEdge</TD>
+ <TD>0 = Top edge is first<BR>
+ 1 = Right edge is first<BR>
+ 2 = Bottom edge is first<BR>
+ 3 = Left edge is first</TD>
+</TR>
+<TR>
+ <TD>312-319</TD>
+ <TD>Margins</TD>
+ <TD>Left and bottom origin of image in points</TD>
+</TR>
+<TR>
+ <TD>320-323</TD>
+ <TD>ManualFeed</TD>
+ <TD>0 = Do not manually feed media<BR>
+ 1 = Manually feed media</TD>
+</TR>
+<TR>
+ <TD>324-327</TD>
+ <TD>MediaPosition</TD>
+ <TD>Input slot position from 0 to N</TD>
+</TR>
+<TR>
+ <TD>328-331</TD>
+ <TD>MediaWeight</TD>
+ <TD>Media weight in grams per meter squared</TD>
+</TR>
+<TR>
+ <TD>332-335</TD>
+ <TD>MirrorPrint</TD>
+ <TD>0 = Do not mirror prints<BR>
+ 1 = Mirror prints</TD>
+</TR>
+<TR>
+ <TD>336-339</TD>
+ <TD>NegativePrint</TD>
+ <TD>0 = Do not invert prints<BR>
+ 1 = Invert prints</TD>
+</TR>
+<TR>
+ <TD>340-343</TD>
+ <TD>NumCopies</TD>
+ <TD>1 to 2<SUP>32</SUP> - 1</TD>
+</TR>
+<TR>
+ <TD>344-347</TD>
+ <TD>Orientation</TD>
+ <TD>0 = Do not rotate page<BR>
+ 1 = Rotate page counter-clockwise<BR>
+ 2 = Turn page upside down<BR>
+ 3 = Rotate page clockwise</TD>
+</TR>
+<TR>
+ <TD>348-351</TD>
+ <TD>OutputFaceUp</TD>
+ <TD>0 = Output face down<BR>
+ 1 = Output face up</TD>
+</TR>
+<TR>
+ <TD>352-359</TD>
+ <TD>PageSize</TD>
+ <TD>Width and length in points</TD>
+</TR>
+<TR>
+ <TD>360-363</TD>
+ <TD>Separations</TD>
+ <TD>0 = Print composite image<BR>
+ 1 = Print color separations</TD>
+</TR>
+<TR>
+ <TD>364-367</TD>
+ <TD>TraySwitch</TD>
+ <TD>0 = Do not change trays if selected tray is empty<BR>
+ 1 = Change trays if selected tray is empty</TD>
+</TR>
+<TR>
+ <TD>368-371</TD>
+ <TD>Tumble</TD>
+ <TD>0 = Do not rotate even pages when duplexing<BR>
+ 1 = Rotate even pages when duplexing</TD>
+</TR>
+<TR>
+ <TD>372-375</TD>
+ <TD>cupsWidth</TD>
+ <TD>Width of page image in pixels</TD>
+</TR>
+<TR>
+ <TD>376-379</TD>
+ <TD>cupsHeight</TD>
+ <TD>Height of page image in pixels</TD>
+</TR>
+<TR>
+ <TD>380-383</TD>
+ <TD>cupsMediaType</TD>
+ <TD>Driver-specific 0 to 2<SUP>32</SUP> - 1</TD>
+</TR>
+<TR>
+ <TD>384-387</TD>
+ <TD>cupsBitsPerColor</TD>
+ <TD>1, 2, 4, 8 bits</TD>
+</TR>
+<TR>
+ <TD>388-391</TD>
+ <TD>cupsBitsPerPixel</TD>
+ <TD>1 to 32 bits</TD>
+</TR>
+<TR>
+ <TD>392-395</TD>
+ <TD>cupsBytesPerLine</TD>
+ <TD>1 to 2<SUP>32</SUP> - 1 bytes</TD>
+</TR>
+<TR>
+ <TD>396-399</TD>
+ <TD>cupsColorOrder</TD>
+ <TD>0 = chunky pixels (CMYK CMYK CMYK)<BR>
+ 1 = banded pixels (CCC MMM YYY KKK)<BR>
+ 2 = planar pixels (CCC... MMM... YYY... KKK...)</TD>
+</TR>
+<TR>
+ <TD>400-403</TD>
+ <TD>cupsColorSpace</TD>
+ <TD>0 = white<BR>
+ 1 = RGB<BR>
+ 2 = RGBA<BR>
+ 3 = black<BR>
+ 4 = CMY<BR>
+ 5 = YMC<BR>
+ 6 = CMYK<BR>
+ 7 = YMCK<BR>
+ 8 = KCMY<BR>
+ 9 = KCMYcm</TD>
+</TR>
+<TR>
+ <TD>404-407</TD>
+ <TD>cupsCompression</TD>
+ <TD>Driver-specific 0 to 2<SUP>32</SUP> - 1</TD>
+</TR>
+<TR>
+ <TD>408-411</TD>
+ <TD>cupsRowCount</TD>
+ <TD>Driver-specific 0 to 2<SUP>32</SUP> - 1</TD>
+</TR>
+<TR>
+ <TD>412-415</TD>
+ <TD>cupsRowFeed</TD>
+ <TD>Driver-specific 0 to 2<SUP>32</SUP> - 1</TD>
+</TR>
+<TR>
+ <TD>416-419</TD>
+ <TD>cupsRowStep</TD>
+ <TD>Driver-specific 0 to 2<SUP>32</SUP> - 1</TD>
+</TR>
+</TABLE></CENTER>
+
+<P>The MIME type for CUPS Raster files is
+<CODE>application/vnd.cups-raster</CODE>.
+
+<H2>CUPS Raw Files</H2>
+
+<P>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 <CODE>application/vnd.cups-raw</CODE>.
+
+<H2>Internet Printing Protocol</H2>
+
+<P>The Internet Printing Protocol and the CUPS extensions to it are
+described in the CUPS Implementation of IPP document.
+
+<H2>Line Printer Daemon Protocol</H2>
+
+<P>The Line Printer Daemon (LPD) protocol is described by
+<A HREF="http://www.ietf.org/rfc/rfc1179.txt">RFC 1179: Line Printer Daemon
+Protocol</A>.
+
+<P>The URI method name for LPD is "lpd".
+
+<H2>Server Message Block Protocol</H2>
+
+<P>The Server Message Block (SMB) and related Common Internet File
+System (CIFS) protocols are described at
+<A HREF="http://anu.samba.org/cifs">http://anu.samba.org/cifs</A>.
+
+<P>The URI method name for SMB is "smb". Support for this protocol is
+provided via the SAMBA <CODE>smbspool(1)</CODE> program provided with
+SAMBA 2.0.6 and higher.
+
+<H1>Directories</H1>
+
+<DL>
+
+ <DT>/etc/cups
+ <DD>The scheduler configuration and MIME files reside here.
+
+ <DT>/etc/cups/certs
+ <DD>The authentication certificates reside here.
+
+ <DT>/etc/cups/interfaces
+ <DD>System V interface scripts reside here.
+
+ <DT>/etc/cups/ppd
+ <DD>This directory contains PPD files for each printer.
+
+ <DT>/usr/bin
+ <DD>The <CODE>cancel</CODE>, <CODE>lp</CODE>, <CODE>lpq</CODE>,
+ <CODE>lpr</CODE>, <CODE>lprm</CODE>, and <CODE>lpstat</CODE> commands
+ reside here.
+
+ <DT>/usr/lib, /usr/lib32
+ <DD>The shared libraries (DSOs) reside here.
+
+ <DT>/usr/lib/cups/backend
+ <DD>The backend filters reside here.
+
+ <DT>/usr/lib/cups/cgi-bin
+ <DD>The CGI programs reside here.
+
+ <DT>/usr/lib/cups/daemon
+ <DD>The polling and LPD daemons reside here.
+
+ <DT>/usr/lib/cups/filter
+ <DD>The file filters reside here.
+
+ <DT>/usr/sbin
+ <DD>The <CODE>accept</CODE>, <CODE>cupsd</CODE>,
+ <CODE>lpadmin</CODE>, <CODE>lpc</CODE>, and <CODE>reject</CODE>
+ commands reside here.
+
+ <DT>/usr/share/cups
+ <DD>This is the root directory of the CUPS static data.
+
+ <DT>/usr/share/cups/charsets
+ <DD>The character set files reside here.
+
+ <DT>/usr/share/cups/data
+ <DD>The filter data files reside here.
+
+ <DT>/usr/share/cups/fonts
+ <DD>The <CODE>pstoraster</CODE> font files reside here.
+
+ <DT>/usr/share/cups/model
+ <DD>The sample PPD files reside here.
+
+ <DT>/usr/share/cups/pstoraster
+ <DD>The <CODE>pstoraster</CODE> data files reside here.
+
+ <DT>/usr/share/doc/cups
+ <DD>The scheduler documentation files reside here.
+
+ <DT>/var/log/cups
+ <DD>The <CODE>access_log</CODE>, <CODE>error_log</CODE>, and
+ <CODE>page_log</CODE> files reside here.
+
+ <DT>/var/spool/cups
+ <DD>This directory contains print job files.
+
+</DL>
+
+<EMBED SRC="glossary.shtml">
+
+</BODY>
+</HTML>
diff --git a/doc/images/accept-jobs.gif b/doc/images/accept-jobs.gif
new file mode 100644
index 000000000..9da7a0dce
--- /dev/null
+++ b/doc/images/accept-jobs.gif
Binary files differ
diff --git a/doc/images/add-class.gif b/doc/images/add-class.gif
new file mode 100644
index 000000000..0f43a6fcd
--- /dev/null
+++ b/doc/images/add-class.gif
Binary files differ
diff --git a/doc/images/add-printer.gif b/doc/images/add-printer.gif
new file mode 100644
index 000000000..90d17eb3f
--- /dev/null
+++ b/doc/images/add-printer.gif
Binary files differ
diff --git a/doc/images/cancel-job.gif b/doc/images/cancel-job.gif
new file mode 100644
index 000000000..3cc1e23bc
--- /dev/null
+++ b/doc/images/cancel-job.gif
Binary files differ
diff --git a/doc/images/cancel-jobs.gif b/doc/images/cancel-jobs.gif
new file mode 100644
index 000000000..2384b903c
--- /dev/null
+++ b/doc/images/cancel-jobs.gif
Binary files differ
diff --git a/doc/images/cancel.gif b/doc/images/cancel.gif
new file mode 100644
index 000000000..e99460678
--- /dev/null
+++ b/doc/images/cancel.gif
Binary files differ
diff --git a/doc/images/classes.gif b/doc/images/classes.gif
new file mode 100644
index 000000000..ace15df98
--- /dev/null
+++ b/doc/images/classes.gif
Binary files differ
diff --git a/doc/images/config-printer.gif b/doc/images/config-printer.gif
new file mode 100644
index 000000000..22849db7d
--- /dev/null
+++ b/doc/images/config-printer.gif
Binary files differ
diff --git a/doc/images/continue.gif b/doc/images/continue.gif
new file mode 100644
index 000000000..ff774adb3
--- /dev/null
+++ b/doc/images/continue.gif
Binary files differ
diff --git a/doc/images/cups-block-diagram.gif b/doc/images/cups-block-diagram.gif
new file mode 100644
index 000000000..2fe505e44
--- /dev/null
+++ b/doc/images/cups-block-diagram.gif
Binary files differ
diff --git a/doc/images/cups-large.gif b/doc/images/cups-large.gif
new file mode 100644
index 000000000..fc66ef07c
--- /dev/null
+++ b/doc/images/cups-large.gif
Binary files differ
diff --git a/doc/images/cups-medium.gif b/doc/images/cups-medium.gif
new file mode 100644
index 000000000..c45ed6ab9
--- /dev/null
+++ b/doc/images/cups-medium.gif
Binary files differ
diff --git a/doc/images/cups-small.gif b/doc/images/cups-small.gif
new file mode 100644
index 000000000..6adb4a29f
--- /dev/null
+++ b/doc/images/cups-small.gif
Binary files differ
diff --git a/doc/images/delete-class.gif b/doc/images/delete-class.gif
new file mode 100644
index 000000000..81b1465ac
--- /dev/null
+++ b/doc/images/delete-class.gif
Binary files differ
diff --git a/doc/images/delete-printer.gif b/doc/images/delete-printer.gif
new file mode 100644
index 000000000..41ce85d78
--- /dev/null
+++ b/doc/images/delete-printer.gif
Binary files differ
diff --git a/doc/images/draft.gif b/doc/images/draft.gif
new file mode 100644
index 000000000..77d9716ab
--- /dev/null
+++ b/doc/images/draft.gif
Binary files differ
diff --git a/doc/images/hold-job.gif b/doc/images/hold-job.gif
new file mode 100644
index 000000000..ebd448ae9
--- /dev/null
+++ b/doc/images/hold-job.gif
Binary files differ
diff --git a/doc/images/left.gif b/doc/images/left.gif
new file mode 100644
index 000000000..fd7b04104
--- /dev/null
+++ b/doc/images/left.gif
Binary files differ
diff --git a/doc/images/logo.gif b/doc/images/logo.gif
new file mode 100644
index 000000000..9999795ca
--- /dev/null
+++ b/doc/images/logo.gif
Binary files differ
diff --git a/doc/images/manage-classes.gif b/doc/images/manage-classes.gif
new file mode 100644
index 000000000..69d5b0147
--- /dev/null
+++ b/doc/images/manage-classes.gif
Binary files differ
diff --git a/doc/images/manage-jobs.gif b/doc/images/manage-jobs.gif
new file mode 100644
index 000000000..adaff856f
--- /dev/null
+++ b/doc/images/manage-jobs.gif
Binary files differ
diff --git a/doc/images/manage-printers.gif b/doc/images/manage-printers.gif
new file mode 100644
index 000000000..cd897291d
--- /dev/null
+++ b/doc/images/manage-printers.gif
Binary files differ
diff --git a/doc/images/modify-class.gif b/doc/images/modify-class.gif
new file mode 100644
index 000000000..58a0ead82
--- /dev/null
+++ b/doc/images/modify-class.gif
Binary files differ
diff --git a/doc/images/modify-printer.gif b/doc/images/modify-printer.gif
new file mode 100644
index 000000000..593b5f881
--- /dev/null
+++ b/doc/images/modify-printer.gif
Binary files differ
diff --git a/doc/images/navbar.gif b/doc/images/navbar.gif
new file mode 100644
index 000000000..c19f634c0
--- /dev/null
+++ b/doc/images/navbar.gif
Binary files differ
diff --git a/doc/images/navbar.xcf.gz b/doc/images/navbar.xcf.gz
new file mode 100644
index 000000000..28438a6bb
--- /dev/null
+++ b/doc/images/navbar.xcf.gz
Binary files differ
diff --git a/doc/images/print-test-page.gif b/doc/images/print-test-page.gif
new file mode 100644
index 000000000..807dca10e
--- /dev/null
+++ b/doc/images/print-test-page.gif
Binary files differ
diff --git a/doc/images/printer-idle.gif b/doc/images/printer-idle.gif
new file mode 100644
index 000000000..68d990c62
--- /dev/null
+++ b/doc/images/printer-idle.gif
Binary files differ
diff --git a/doc/images/printer-processing.gif b/doc/images/printer-processing.gif
new file mode 100644
index 000000000..a9a23f795
--- /dev/null
+++ b/doc/images/printer-processing.gif
Binary files differ
diff --git a/doc/images/printer-stopped.gif b/doc/images/printer-stopped.gif
new file mode 100644
index 000000000..76f45649b
--- /dev/null
+++ b/doc/images/printer-stopped.gif
Binary files differ
diff --git a/doc/images/reject-jobs.gif b/doc/images/reject-jobs.gif
new file mode 100644
index 000000000..6d938e308
--- /dev/null
+++ b/doc/images/reject-jobs.gif
Binary files differ
diff --git a/doc/images/release-job.gif b/doc/images/release-job.gif
new file mode 100644
index 000000000..a05cd9cc7
--- /dev/null
+++ b/doc/images/release-job.gif
Binary files differ
diff --git a/doc/images/restart-job.gif b/doc/images/restart-job.gif
new file mode 100644
index 000000000..a007efc5b
--- /dev/null
+++ b/doc/images/restart-job.gif
Binary files differ
diff --git a/doc/images/right.gif b/doc/images/right.gif
new file mode 100644
index 000000000..8ae8213ce
--- /dev/null
+++ b/doc/images/right.gif
Binary files differ
diff --git a/doc/images/show-active.gif b/doc/images/show-active.gif
new file mode 100644
index 000000000..d232ef9f8
--- /dev/null
+++ b/doc/images/show-active.gif
Binary files differ
diff --git a/doc/images/show-completed.gif b/doc/images/show-completed.gif
new file mode 100644
index 000000000..efd206cd5
--- /dev/null
+++ b/doc/images/show-completed.gif
Binary files differ
diff --git a/doc/images/start-class.gif b/doc/images/start-class.gif
new file mode 100644
index 000000000..2b6f43fad
--- /dev/null
+++ b/doc/images/start-class.gif
Binary files differ
diff --git a/doc/images/start-printer.gif b/doc/images/start-printer.gif
new file mode 100644
index 000000000..017bb394a
--- /dev/null
+++ b/doc/images/start-printer.gif
Binary files differ
diff --git a/doc/images/stop-class.gif b/doc/images/stop-class.gif
new file mode 100644
index 000000000..5cb7adfd8
--- /dev/null
+++ b/doc/images/stop-class.gif
Binary files differ
diff --git a/doc/images/stop-printer.gif b/doc/images/stop-printer.gif
new file mode 100644
index 000000000..b3accf3df
--- /dev/null
+++ b/doc/images/stop-printer.gif
Binary files differ
diff --git a/doc/index.html b/doc/index.html
new file mode 100644
index 000000000..051abb5b8
--- /dev/null
+++ b/doc/index.html
@@ -0,0 +1,36 @@
+<HTML>
+<HEAD>
+ <TITLE>Common UNIX Printing System</TITLE>
+ <LINK REL=STYLESHEET TYPE="text/css" HREF="cups.css">
+ <MAP NAME="navbar">
+ <AREA SHAPE="RECT" COORDS="12,10,50,20" HREF="http://www.easysw.com" ALT="Easy Software Products Home Page">
+ <AREA SHAPE="RECT" COORDS="82,10,196,20" HREF="/admin" ALT="Do Administration Tasks">
+ <AREA SHAPE="RECT" COORDS="216,10,280,20" HREF="/classes" ALT="Manage Printer Classes Status">
+ <AREA SHAPE="RECT" COORDS="300,10,336,20" HREF="/documentation.html" ALT="On-Line Help">
+ <AREA SHAPE="RECT" COORDS="356,10,394,20" HREF="/jobs" ALT="Manage Jobs">
+ <AREA SHAPE="RECT" COORDS="414,10,476,20" HREF="/printers" ALT="Manage Printers">
+ <AREA SHAPE="RECT" COORDS="496,10,568,20" HREF="http://www.cups.org" ALT="Download the Current CUPS Software">
+ </MAP>
+</HEAD>
+
+<BODY BGCOLOR="#cccc99" TEXT="#000000" LINK="#0000FF" VLINK="#FF00FF">
+<CENTER>
+<IMG SRC="/images/navbar.gif" WIDTH="583" HEIGHT="30" USEMAP="#navbar" BORDER="0" ALT="Common UNIX Printing System">
+</CENTER>
+
+<H1><A HREF="admin">Do Administration Tasks</A></H1>
+<H1><A HREF="classes">Manage Printer Classes</A></H1>
+<H1><A HREF="documentation.html">On-Line Help</A></H1>
+<H1><A HREF="jobs">Manage Jobs</A></H1>
+<H1><A HREF="printers">Manage Printers</A></H1>
+<H1><A HREF="http://www.cups.org">Download the Current CUPS Software</A></H1>
+
+<HR>
+
+<P>The Common UNIX Printing System, CUPS, and the CUPS logo are the
+trademark property of <A HREF="http://www.easysw.com">Easy Software
+Products</A>. CUPS is copyright 1997-2002 by Easy Software Products,
+All Rights Reserved.
+
+</BODY>
+</HTML>
diff --git a/doc/ipp.html b/doc/ipp.html
new file mode 100644
index 000000000..f130789ee
--- /dev/null
+++ b/doc/ipp.html
@@ -0,0 +1,1442 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD>
+<TITLE>CUPS Implementation of IPP</TITLE>
+<META NAME="author" CONTENT="Easy Software Products">
+<META NAME="copyright" CONTENT="Copyright 1997-2002 All Rights Reserved">
+<META NAME="docnumber" CONTENT="CUPS-IPP-1.1">
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=iso-8859-1">
+<STYLE TYPE="text/css"><!--
+BODY { font-family: serif }
+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 }
+SUB { font-size: smaller }
+SUP { font-size: smaller }
+PRE { font-family: monospace }
+--></STYLE>
+</HEAD>
+<BODY>
+<CENTER><A HREF="#CONTENTS"><IMG SRC="images/cups-large.gif" BORDER="0" WIDTH="431" HEIGHT="511"><BR>
+<H1>CUPS Implementation of IPP</H1></A><BR>
+CUPS-IPP-1.1<BR>
+Easy Software Products<BR>
+Copyright 1997-2002 All Rights Reserved<BR>
+</CENTER>
+<HR>
+<H1 ALIGN="CENTER"><A NAME="CONTENTS">Table of Contents</A></H1>
+<BR>
+<BR><B><A HREF="#1">1 Scope</A></B>
+<UL>
+<LI><A HREF="#1_1">1.1 Identification</A></LI>
+<LI><A HREF="#1_2">1.2 System Overview</A></LI>
+<LI><A HREF="#1_3">1.3 Document Overview</A></LI>
+</UL>
+<B><A HREF="#2">2 References</A></B>
+<UL>
+<LI><A HREF="#2_1">2.1 CUPS Documentation</A></LI>
+<LI><A HREF="#2_2">2.2 Other Documents</A></LI>
+</UL>
+<B><A HREF="#3">3 Overview</A></B>
+<UL>
+<LI><A HREF="#3_1">3.1 IPP URIs</A></LI>
+<LI><A HREF="#3_2">3.2 CUPS IPP Operations</A></LI>
+</UL>
+<B><A HREF="#4">4 Operations</A></B>
+<UL>
+<LI><A HREF="#4_1">4.1 Print-Job Operation</A></LI>
+<UL>
+<LI><A HREF="#4_1_1">4.1.1 Print-Job Request</A></LI>
+<LI><A HREF="#4_1_2">4.1.2 Print-Job Response</A></LI>
+</UL>
+<LI><A HREF="#4_2">4.2 Create-Job Operation</A></LI>
+<UL>
+<LI><A HREF="#4_2_1">4.2.1 Create-Job Request</A></LI>
+<LI><A HREF="#4_2_2">4.2.2 Create-Job Response</A></LI>
+</UL>
+<LI><A HREF="#4_3">4.3 Set-Job-Attributes Operation</A></LI>
+<UL>
+<LI><A HREF="#4_3_1">4.3.1 Set-Job-Attributes Request</A></LI>
+<LI><A HREF="#4_3_2">4.3.2 Set-Job-Attributes Response</A></LI>
+</UL>
+<LI><A HREF="#4_4">4.4 CUPS-Get-Default Operation</A></LI>
+<UL>
+<LI><A HREF="#4_4_1">4.4.1 CUPS-Get-Default Request</A></LI>
+<LI><A HREF="#4_4_2">4.4.2 CUPS-Get-Default Response</A></LI>
+</UL>
+<LI><A HREF="#4_5">4.5 CUPS-Get-Printers Operation</A></LI>
+<UL>
+<LI><A HREF="#4_5_1">4.5.1 CUPS-Get-Printers Request</A></LI>
+<LI><A HREF="#4_5_2">4.5.2 CUPS-Get-Printers Response</A></LI>
+</UL>
+<LI><A HREF="#4_6">4.6 CUPS-Add-Printer Operation</A></LI>
+<UL>
+<LI><A HREF="#4_6_1">4.6.1 CUPS-Add-Printer Request</A></LI>
+<LI><A HREF="#4_6_2">4.6.2 CUPS-Add-Printer Response</A></LI>
+</UL>
+<LI><A HREF="#4_7">4.7 CUPS-Delete-Printer Operation</A></LI>
+<UL>
+<LI><A HREF="#4_7_1">4.7.1 CUPS-Delete-Printer Request</A></LI>
+<LI><A HREF="#4_7_2">4.7.2 CUPS-Delete-Printer Response</A></LI>
+</UL>
+<LI><A HREF="#4_8">4.8 CUPS-Get-Classes Operation</A></LI>
+<UL>
+<LI><A HREF="#4_8_1">4.8.1 CUPS-Get-Classes Request</A></LI>
+<LI><A HREF="#4_8_2">4.8.2 CUPS-Get-Classes Response</A></LI>
+</UL>
+<LI><A HREF="#4_9">4.9 CUPS-Add-Class Operation</A></LI>
+<UL>
+<LI><A HREF="#4_9_1">4.9.1 CUPS-Add-Class Request</A></LI>
+<LI><A HREF="#4_9_2">4.9.2 CUPS-Add-Class Response</A></LI>
+</UL>
+<LI><A HREF="#4_10">4.10 CUPS-Delete-Class Operation</A></LI>
+<UL>
+<LI><A HREF="#4_10_1">4.10.1 CUPS-Delete-Class Request</A></LI>
+<LI><A HREF="#4_10_2">4.10.2 CUPS-Delete-Class Response</A></LI>
+</UL>
+<LI><A HREF="#4_11">4.11 CUPS-Accept-Jobs Operation</A></LI>
+<UL>
+<LI><A HREF="#4_11_1">4.11.1 CUPS-Accept-Jobs Request</A></LI>
+<LI><A HREF="#4_11_2">4.11.2 CUPS-Accept-Jobs Response</A></LI>
+</UL>
+<LI><A HREF="#4_12">4.12 CUPS-Reject-Jobs Operation</A></LI>
+<UL>
+<LI><A HREF="#4_12_1">4.12.1 CUPS-Reject-Jobs Request</A></LI>
+<LI><A HREF="#4_12_2">4.12.2 CUPS-Reject-Jobs Response</A></LI>
+</UL>
+<LI><A HREF="#4_13">4.13 CUPS-Set-Default Operation</A></LI>
+<UL>
+<LI><A HREF="#4_13_1">4.13.1 CUPS-Set-Default Request</A></LI>
+<LI><A HREF="#4_13_2">4.13.2 CUPS-Set-Default Response</A></LI>
+</UL>
+<LI><A HREF="#4_14">4.14 CUPS-Get-Devices Operation</A></LI>
+<UL>
+<LI><A HREF="#4_14_1">4.14.1 CUPS-Get-Devices Request</A></LI>
+<LI><A HREF="#4_14_2">4.14.2 CUPS-Get-Devices Response</A></LI>
+</UL>
+<LI><A HREF="#4_15">4.15 CUPS-Get-PPDs Operation</A></LI>
+<UL>
+<LI><A HREF="#4_15_1">4.15.1 CUPS-Get-PPDs Request</A></LI>
+<LI><A HREF="#4_15_2">4.15.2 CUPS-Get-PPDs Response</A></LI>
+</UL>
+<LI><A HREF="#4_16">4.16 CUPS-Move-Job Operation</A></LI>
+<UL>
+<LI><A HREF="#4_16_1">4.16.1 CUPS-Move-Job Request</A></LI>
+<LI><A HREF="#4_16_2">4.16.2 CUPS-Move-Job Response</A></LI>
+</UL>
+</UL>
+<B><A HREF="#5">5 Attributes</A></B>
+<UL>
+<LI><A HREF="#5_1">5.1 Device Attributes</A></LI>
+<UL>
+<LI><A HREF="#5_1_1">5.1.1 device-class (type2 keyword)</A></LI>
+<LI><A HREF="#5_1_2">5.1.2 device-info (text(127))</A></LI>
+<LI><A HREF="#5_1_3">5.1.3 device-make-and-model (text(127))</A></LI>
+<LI><A HREF="#5_1_4">5.1.4 device-uri (uri)</A></LI>
+</UL>
+<LI><A HREF="#5_2">5.2 Job Template Attributes</A></LI>
+<UL>
+<LI><A HREF="#5_2_1">5.2.1 blackplot (boolean)</A></LI>
+<LI><A HREF="#5_2_2">5.2.2 brightness (integer(0:200))</A></LI>
+<LI><A HREF="#5_2_3">5.2.3 columns (integer(1:4))</A></LI>
+<LI><A HREF="#5_2_4">5.2.4 cpi (type2 enum)</A></LI>
+<LI><A HREF="#5_2_5">5.2.5 fitplot (boolean)</A></LI>
+<LI><A HREF="#5_2_6">5.2.6 gamma (integer(1:10000))</A></LI>
+<LI><A HREF="#5_2_7">5.2.7 hue (integer(-180:180))</A></LI>
+<LI><A HREF="#5_2_8">5.2.8 job-billing (text(MAX))</A></LI>
+<LI><A HREF="#5_2_9">5.2.9 job-hold-until (keyword | name(MAX))</A></LI>
+<LI><A HREF="#5_2_10">5.2.10 job-sheets (1setof type3 keyword |
+ name(MAX))</A></LI>
+<LI><A HREF="#5_2_11">5.2.11 job-originating-host-name (name(MAX))</A></LI>
+<LI><A HREF="#5_2_12">5.2.12 lpi (type2 enum)</A></LI>
+<LI><A HREF="#5_2_13">5.2.13 natural-scaling (integer(1:1000))</A></LI>
+<LI><A HREF="#5_2_14">5.2.14 page-bottom (integer(0:MAX))</A></LI>
+<LI><A HREF="#5_2_15">5.2.15 page-label (text(MAX))</A></LI>
+<LI><A HREF="#5_2_16">5.2.16 page-left (integer(0:MAX))</A></LI>
+<LI><A HREF="#5_2_17">5.2.17 page-right (integer(0:MAX))</A></LI>
+<LI><A HREF="#5_2_18">5.2.18 page-set (type2 keyword)</A></LI>
+<LI><A HREF="#5_2_19">5.2.19 page-top (integer(0:MAX))</A></LI>
+<LI><A HREF="#5_2_20">5.2.20 penwidth (integer(0:MAX))</A></LI>
+<LI><A HREF="#5_2_21">5.2.21 position (type2 keyword)</A></LI>
+<LI><A HREF="#5_2_22">5.2.22 ppi (integer(1:MAX))</A></LI>
+<LI><A HREF="#5_2_23">5.2.23 prettyprint (boolean)</A></LI>
+<LI><A HREF="#5_2_24">5.2.24 saturation (integer(0:200))</A></LI>
+<LI><A HREF="#5_2_25">5.2.25 scaling (integer(1:1000))</A></LI>
+<LI><A HREF="#5_2_26">5.2.26 wrap (boolean)</A></LI>
+</UL>
+<LI><A HREF="#5_3">5.3 PPD Attributes</A></LI>
+<UL>
+<LI><A HREF="#5_3_1">5.3.1 ppd-natural-language (naturalLanguage)</A></LI>
+<LI><A HREF="#5_3_2">5.3.2 ppd-make (text(127))</A></LI>
+<LI><A HREF="#5_3_3">5.3.3 ppd-make-and-model (text(127))</A></LI>
+<LI><A HREF="#5_3_4">5.3.4 ppd-name (name(255))</A></LI>
+</UL>
+<LI><A HREF="#5_4">5.4 Printer Attributes</A></LI>
+<UL>
+<LI><A HREF="#5_4_1">5.4.1 job-k-limit (integer)</A></LI>
+<LI><A HREF="#5_4_2">5.4.2 job-page-limit (integer)</A></LI>
+<LI><A HREF="#5_4_3">5.4.3 job-quota-period (integer)</A></LI>
+<LI><A HREF="#5_4_4">5.4.4 job-sheets-supported (1setof type3 keyword |
+ name(MAX))</A></LI>
+<LI><A HREF="#5_4_5">5.4.5 printer-type (type2 enum)</A></LI>
+<LI><A HREF="#5_4_6">5.4.6 printer-type-mask (type2 enum)</A></LI>
+<LI><A HREF="#5_4_7">5.4.7 requesting-user-name-allowed (1setof
+ name(127))</A></LI>
+<LI><A HREF="#5_4_8">5.4.8 requesting-user-name-denied (1setof
+ name(127))</A></LI>
+</UL>
+<LI><A HREF="#5_5">5.5 Printer Class Attributes</A></LI>
+<UL>
+<LI><A HREF="#5_5_1">5.5.1 member-names (1setof name(127))</A></LI>
+<LI><A HREF="#5_5_2">5.5.2 member-uris (1setof uri)</A></LI>
+</UL>
+</UL>
+<B><A HREF="#6">A Glossary</A></B>
+<UL>
+<LI><A HREF="#6_1">A.1 Terms</A></LI>
+<LI><A HREF="#6_2">A.2 Acronyms</A></LI>
+</UL>
+<HR>
+<H1><A NAME="1">1 Scope</A></H1>
+<H2><A NAME="1_1">1.1 Identification</A></H2>
+<P>This document provides an overview of the Internet Printing Protocol
+ (&quot;IPP&quot;) version 1.1 as implemented in the Common UNIX Printing System
+ (&quot;CUPS&quot;) version 1.1.</P>
+<H2><A NAME="1_2">1.2 System Overview</A></H2>
+<P>CUPS provides a portable printing layer for UNIX&reg;-based operating
+ systems. It has been developed by<A HREF="http://www.easysw.com"> Easy
+ Software Products</A> to promote a standard printing solution for all
+ UNIX vendors and users. CUPS provides the System V and Berkeley
+ command-line interfaces.</P>
+<P>CUPS uses the Internet Printing Protocol (&quot;IPP&quot;) as the basis for
+ managing print jobs and queues. The Line Printer Daemon (&quot;LPD&quot;) Server
+ Message Block (&quot;SMB&quot;), and AppSocket (a.k.a. JetDirect) protocols are
+ also supported with reduced functionality. CUPS adds network printer
+ browsing and PostScript Printer Description (&quot;PPD&quot;) based printing
+ options to support real-world printing under UNIX.</P>
+<P>CUPS also includes a customized version of GNU Ghostscript (currently
+ based off GNU Ghostscript 5.50) and an image file RIP that are used to
+ support non-PostScript printers. Sample drivers for HP and EPSON
+ printers are included that use these filters.</P>
+<H2><A NAME="1_3">1.3 Document Overview</A></H2>
+<P>This document is organized into the following sections:</P>
+<UL>
+<LI><A HREF="#1">1 - Scope</A></LI>
+<LI><A HREF="#2">2 - References</A></LI>
+<LI><A HREF="#3">3 - Overview</A></LI>
+<LI><A HREF="#4">4 - Operations</A></LI>
+<LI><A HREF="#5">5 - Attributes</A></LI>
+<LI><A HREF="#6">A - Glossary</A></LI>
+</UL>
+<H1><A NAME="2">2 References</A></H1>
+<H2><A NAME="2_1">2.1 CUPS Documentation</A></H2>
+<P>The following CUPS documentation is referenced by this document:</P>
+<UL>
+<LI>CUPS-CMP-1.1: CUPS Configuration Management Plan</LI>
+<LI>CUPS-IDD-1.1: CUPS System Interface Design Description</LI>
+<LI>CUPS-IPP-1.1: CUPS Implementation of IPP</LI>
+<LI>CUPS-SAM-1.1.x: CUPS Software Administrators Manual</LI>
+<LI>CUPS-SDD-1.1: CUPS Software Design Description</LI>
+<LI>CUPS-SPM-1.1.x: CUPS Software Programming Manual</LI>
+<LI>CUPS-SSR-1.1: CUPS Software Security Report</LI>
+<LI>CUPS-STP-1.1: CUPS Software Test Plan</LI>
+<LI>CUPS-SUM-1.1.x: CUPS Software Users Manual</LI>
+<LI>CUPS-SVD-1.1: CUPS Software Version Description</LI>
+</UL>
+<H2><A NAME="2_2">2.2 Other Documents</A></H2>
+<P>The following non-CUPS documents are referenced by this document:</P>
+<UL>
+<LI><A HREF="http://partners.adobe.com/asn/developer/PDFS/TN/5003.PPD_Spec_v4.3.pdf">
+Adobe PostScript Printer Description File Format Specification, Version
+ 4.3.</A></LI>
+<LI><A HREF="http://partners.adobe.com/asn/developer/PDFS/TN/PLRM.pdf">
+Adobe PostScript Language Reference, Third Edition.</A></LI>
+<LI>IPP: Job and Printer Set Operations</LI>
+<LI>IPP/1.1: Encoding and Transport</LI>
+<LI>IPP/1.1: Implementers Guide</LI>
+<LI>IPP/1.1: Model and Semantics</LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc1179.txt">RFC 1179, Line Printer
+ Daemon Protocol</A></LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc2567.txt">RFC 2567, Design Goals
+ for an Internet Printing Protocol</A></LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc2568.txt">RFC 2568, Rationale
+ for the Structure of the Model and Protocol</A> for the Internet
+ Printing Protocol</LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc2569.txt">RFC 2569, Mapping
+ between LPD and IPP Protocols</A></LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616, Hypertext
+ Transfer Protocol -- HTTP/1.1</A></LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc2617.txt">RFC 2617, HTTP
+ Authentication: Basic and Digest Access</A> Authentication</LI>
+</UL>
+<H1><A NAME="3">3 Overview</A></H1>
+<P>CUPS 1.1 implements IPP/1.1 and the operations and attributes defined
+ in the &quot;IPP: Job and Printer Set Operations&quot;, &quot;IPP/1.1: Output-bin
+ Attribute Extension&quot;, and &quot;IPP/1.1: finishings 'fold',' trim', and
+ 'bale' attribute values extension&quot; specifications.</P>
+<P>CUPS also provides 13 new operations and many new attributes to
+ support multiple IPP printers and printer classes on a single host.</P>
+<H2><A NAME="3_1">3.1 IPP URIs</A></H2>
+<P>CUPS supports both the &quot;http&quot; and &quot;ipp&quot; methods. The following
+ resource names are used:</P>
+<DL>
+<DT>method://hostname:port/</DT>
+<DD>Can be used for all &quot;get&quot; operations.</DD>
+<DT>method://hostname:port/admin</DT>
+<DD>Used for all administrative operations.</DD>
+<DT>method://hostname:port/classes/name</DT>
+<DD>Specifies a printer class.</DD>
+<DT>method://hostname:port/jobs/id</DT>
+<DD>Specifies a job.</DD>
+<DT>method://hostname:port/printers/name</DT>
+<DD>Specifies a printer.</DD>
+</DL>
+<P>So a typical printer URI would be
+ &quot;ipp://foo.bar.com/printers/LaserJet&quot;.</P>
+<P>In addition, the CUPS server also supports normal browser access to
+ &quot;method://hostname:port/admin/&quot;, &quot;method://hostname:port/classes/&quot;,
+ &quot;method://hostname:port/jobs/&quot;, and &quot;method://hostname:port/printers/&quot;
+ to view and manage resources on the server dynamically.</P>
+<H2><A NAME="3_2">3.2 CUPS IPP Operations</A></H2>
+<P>CUPS provides 13 extension operations in addition to most of the
+ standard IPP and registered extension operations:
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH VALIGN="TOP">Operation Name</TH><TH VALIGN="TOP">CUPS</TH><TH VALIGN="TOP">
+Code</TH><TH VALIGN="TOP">Brief Description</TH></TR>
+<TR><TD VALIGN="TOP">Print-Job</TD><TD VALIGN="TOP">1.0</TD><TD VALIGN="TOP">
+0x0002</TD><TD VALIGN="TOP">Print a file.</TD></TR>
+<TR><TD VALIGN="TOP">Validate-Job</TD><TD VALIGN="TOP">1.0</TD><TD VALIGN="TOP">
+0x0004</TD><TD VALIGN="TOP">Validate job attributes.</TD></TR>
+<TR><TD VALIGN="TOP">Create-Job</TD><TD VALIGN="TOP">1.1</TD><TD VALIGN="TOP">
+0x0005</TD><TD VALIGN="TOP">Create a print job.</TD></TR>
+<TR><TD VALIGN="TOP">Send-Document</TD><TD VALIGN="TOP">1.1</TD><TD VALIGN="TOP">
+0x0006</TD><TD VALIGN="TOP">Send a file for a print job.</TD></TR>
+<TR><TD VALIGN="TOP">Cancel-Job</TD><TD VALIGN="TOP">1.0</TD><TD VALIGN="TOP">
+0x0008</TD><TD VALIGN="TOP">Cancel a print job.</TD></TR>
+<TR><TD VALIGN="TOP">Get-Job-Attributes</TD><TD VALIGN="TOP">1.0</TD><TD VALIGN="TOP">
+0x0009</TD><TD VALIGN="TOP">Get job attributes.</TD></TR>
+<TR><TD VALIGN="TOP">Get-Jobs</TD><TD VALIGN="TOP">1.0</TD><TD VALIGN="TOP">
+0x000A</TD><TD VALIGN="TOP">Get all jobs.</TD></TR>
+<TR><TD VALIGN="TOP">Get-Printer-Attributes</TD><TD VALIGN="TOP">1.0</TD><TD
+VALIGN="TOP">0x000B</TD><TD VALIGN="TOP">Get printer attributes.</TD></TR>
+<TR><TD VALIGN="TOP">Hold-Job</TD><TD VALIGN="TOP">1.1</TD><TD VALIGN="TOP">
+0x000C</TD><TD VALIGN="TOP">Hold a job for printing.</TD></TR>
+<TR><TD VALIGN="TOP">Release-Job</TD><TD VALIGN="TOP">1.1</TD><TD VALIGN="TOP">
+0x000D</TD><TD VALIGN="TOP">Release a job for printing.</TD></TR>
+<TR><TD VALIGN="TOP">Pause-Printer</TD><TD VALIGN="TOP">1.0</TD><TD VALIGN="TOP">
+0x0010</TD><TD VALIGN="TOP">Pause printing on a printer.</TD></TR>
+<TR><TD VALIGN="TOP">Resume-Printer</TD><TD VALIGN="TOP">1.0</TD><TD VALIGN="TOP">
+0x0011</TD><TD VALIGN="TOP">Resume printing on a printer.</TD></TR>
+<TR><TD VALIGN="TOP">Purge-Jobs</TD><TD VALIGN="TOP">1.0</TD><TD VALIGN="TOP">
+0x0012</TD><TD VALIGN="TOP">Purge all jobs.</TD></TR>
+<TR><TD VALIGN="TOP">Set-Job-Attributes</TD><TD VALIGN="TOP">1.1</TD><TD VALIGN="TOP">
+0x0014</TD><TD VALIGN="TOP">Set attributes for a pending or held job.</TD>
+</TR>
+<TR><TD VALIGN="TOP">CUPS-Get-Default</TD><TD VALIGN="TOP">1.0</TD><TD VALIGN="TOP">
+0x4001</TD><TD VALIGN="TOP">Get the default destination.</TD></TR>
+<TR><TD VALIGN="TOP">CUPS-Get-Printers</TD><TD VALIGN="TOP">1.0</TD><TD VALIGN="TOP">
+0x4002</TD><TD VALIGN="TOP">Get all of the available printers.</TD></TR>
+<TR><TD VALIGN="TOP">CUPS-Add-Printer</TD><TD VALIGN="TOP">1.0</TD><TD VALIGN="TOP">
+0x4003</TD><TD VALIGN="TOP">Add or modify a printer.</TD></TR>
+<TR><TD VALIGN="TOP">CUPS-Delete-Printer</TD><TD VALIGN="TOP">1.0</TD><TD
+VALIGN="TOP">0x4004</TD><TD VALIGN="TOP">Delete a printer.</TD></TR>
+<TR><TD VALIGN="TOP">CUPS-Get-Classes</TD><TD VALIGN="TOP">1.0</TD><TD VALIGN="TOP">
+0x4005</TD><TD VALIGN="TOP">Get all of the available printer classes.</TD>
+</TR>
+<TR><TD VALIGN="TOP">CUPS-Add-Class</TD><TD VALIGN="TOP">1.0</TD><TD VALIGN="TOP">
+0x4006</TD><TD VALIGN="TOP">Add or modify a printer class.</TD></TR>
+<TR><TD VALIGN="TOP">CUPS-Delete-Class</TD><TD VALIGN="TOP">1.0</TD><TD VALIGN="TOP">
+0x4007</TD><TD VALIGN="TOP">Delete a printer class.</TD></TR>
+<TR><TD VALIGN="TOP">CUPS-Accept-Jobs</TD><TD VALIGN="TOP">1.0</TD><TD VALIGN="TOP">
+0x4008</TD><TD VALIGN="TOP">Accept jobs on a printer or printer class.</TD>
+</TR>
+<TR><TD VALIGN="TOP">CUPS-Reject-Jobs</TD><TD VALIGN="TOP">1.0</TD><TD VALIGN="TOP">
+0x4009</TD><TD VALIGN="TOP">Reject jobs on a printer or printer class.</TD>
+</TR>
+<TR><TD VALIGN="TOP">CUPS-Set-Default</TD><TD VALIGN="TOP">1.0</TD><TD VALIGN="TOP">
+0x400A</TD><TD VALIGN="TOP">Set the default destination.</TD></TR>
+<TR><TD VALIGN="TOP">CUPS-Get-Devices</TD><TD VALIGN="TOP">1.1</TD><TD VALIGN="TOP">
+0x400B</TD><TD VALIGN="TOP">Get all of the available devices.</TD></TR>
+<TR><TD VALIGN="TOP">CUPS-Get-PPDs</TD><TD VALIGN="TOP">1.1</TD><TD VALIGN="TOP">
+0x400C</TD><TD VALIGN="TOP">Get all of the available PPDs.</TD></TR>
+<TR><TD VALIGN="TOP">CUPS-Move-Job</TD><TD VALIGN="TOP">1.1</TD><TD VALIGN="TOP">
+0x400D</TD><TD VALIGN="TOP">Move a job to a different printer.</TD></TR>
+</TABLE>
+</CENTER>
+</P>
+<H1><A NAME="4">4 Operations</A></H1>
+<P>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.</P>
+<H2><A NAME="4_1">4.1 Print-Job Operation</A></H2>
+<P>The Print-Job operation (0x0002) prints a file.</P>
+<H3><A NAME="4_1_1">4.1.1 Print-Job Request</A></H3>
+<P>The following groups of attributes are supplied as part of the
+ Print-Job request:</P>
+<P>Group 1: Operation Attributes</P>
+<UL>
+<P>Natural Language and Character Set:</P>
+<P>The &quot;attributes-charset&quot; and &quot;attributes-natural-language&quot; attributes
+ as described in section 3.1.4.1 of the IPP Model and Semantics
+ document.</P>
+<P>&quot;printer-uri&quot; (uri):</P>
+<P>The client MUST supply a URI for the specified printer.</P>
+</UL>
+<P>Group 2: Job Template Attributes</P>
+<UL>
+<P>&quot;job-billing&quot; (text(MAX)):</P>
+<P><I>(CUPS 1.1 and higher)</I></P>
+<P>The client OPTIONALLY supplies a billing string that is logged with
+ the page accounting information.</P>
+<P>&quot;job-sheets&quot; (1setof type3 keyword | name(MAX)):</P>
+<P><I>(CUPS 1.1 and higher)</I></P>
+<P>The client OPTIONALLY supplies one or two banner pages that are
+ printed before and after any files in the print job. The name of &quot;none&quot;
+ is reserved to indicate that no banner page should be printed. If the
+ client does not specify this attribute then the value of the
+ &quot;job-sheets-default&quot; printer object attribute is used.</P>
+<P><B>Note:</B> Standard IPP only allows specification of a single
+ job-sheets attribute value.</P>
+<P>&quot;media&quot; (1setof type3 keyword | name(MAX)):</P>
+<P>The client OPTIONALLY supplies one or more media attributes
+ specifying the size, type, source, and color of the output media. If
+ the client does not specify this attribute then the value of the
+ &quot;media-default&quot; printer object attribute is used.</P>
+<P><B>Note:</B> Standard IPP only allows specification of a single media
+ attribute value.</P>
+<P>Other Job Template Attributes</P>
+</UL>
+<P>The Print-Job request is followed by a file to be printed.</P>
+<H3><A NAME="4_1_2">4.1.2 Print-Job Response</A></H3>
+<P>The following groups of attributes are send as part of the Print-Job
+ Response:</P>
+<P>Group 1: Operation Attributes</P>
+<UL>
+<P>Status Message:</P>
+<P>The standard response status message.</P>
+<P>Natural Language and Character Set:</P>
+<P>The &quot;attributes-charset&quot; and &quot;attributes-natural-language&quot; attributes
+ as described in section 3.1.4.2 of the IPP Model and Semantics
+ document.</P>
+</UL>
+<P>Group 2: Job Attributes</P>
+<UL>
+<P>Standard Job Attributes</P>
+</UL>
+<H2><A NAME="4_2">4.2 Create-Job Operation</A></H2>
+<P>The Create-Job operation (0x0005) creates a new, empty print job.</P>
+<H3><A NAME="4_2_1">4.2.1 Create-Job Request</A></H3>
+<P>The following groups of attributes are supplied as part of the
+ Create-Job request:</P>
+<P>Group 1: Operation Attributes</P>
+<UL>
+<P>Natural Language and Character Set:</P>
+<P>The &quot;attributes-charset&quot; and &quot;attributes-natural-language&quot; attributes
+ as described in section 3.1.4.1 of the IPP Model and Semantics
+ document.</P>
+<P>&quot;printer-uri&quot; (uri):</P>
+<P>The client MUST supply a URI for the specified printer.</P>
+</UL>
+<P>Group 2: Job Template Attributes</P>
+<UL>
+<P>&quot;job-billing&quot; (text(MAX)):</P>
+<P><I>(CUPS 1.1 and higher)</I></P>
+<P>The client OPTIONALLY supplies a billing string that is logged with
+ the page accounting information.</P>
+<P>&quot;job-sheets&quot; (1setof type3 keyword | name(MAX)):</P>
+<P><I>(CUPS 1.1 and higher)</I></P>
+<P>The client OPTIONALLY supplies one or two banner pages that are
+ printed before and after any files in the print job. The name of &quot;none&quot;
+ is reserved to indicate that no banner page should be printed. If the
+ client does not specify this attribute then the value of the
+ &quot;job-sheets-default&quot; printer object attribute is used.</P>
+<P><B>Note:</B> Standard IPP only allows specification of a single
+ job-sheets attribute value.</P>
+<P>&quot;media&quot; (1setof type3 keyword | name(MAX)):</P>
+<P>The client OPTIONALLY supplies one or more media attributes
+ specifying the size, type, source, and color of the output media. If
+ the client does not specify this attribute then the value of the
+ &quot;media-default&quot; printer object attribute is used.</P>
+<P><B>Note:</B> Standard IPP only allows specification of a single media
+ attribute value.</P>
+<P>Standard Job Template Attributes</P>
+</UL>
+<H3><A NAME="4_2_2">4.2.2 Create-Job Response</A></H3>
+<P>The following groups of attributes are send as part of the Create-Job
+ Response:</P>
+<P>Group 1: Operation Attributes</P>
+<UL>
+<P>Status Message:</P>
+<P>The standard response status message.</P>
+<P>Natural Language and Character Set:</P>
+<P>The &quot;attributes-charset&quot; and &quot;attributes-natural-language&quot; attributes
+ as described in section 3.1.4.2 of the IPP Model and Semantics
+ document.</P>
+</UL>
+<P>Group 2: Job Attributes</P>
+<UL>
+<P>Standard Job Attributes</P>
+</UL>
+<H2><A NAME="4_3">4.3 Set-Job-Attributes Operation</A></H2>
+<P>The Set-Job-Attributes operation (0x0014) changes the attributes of
+ an active (not completed) job.</P>
+<H3><A NAME="4_3_1">4.3.1 Set-Job-Attributes Request</A></H3>
+<P>The following groups of attributes are supplied as part of the
+ Set-Job-Attributes request:</P>
+<P>Group 1: Operation Attributes</P>
+<UL>
+<P>Natural Language and Character Set:</P>
+<P>The &quot;attributes-charset&quot; and &quot;attributes-natural-language&quot; attributes
+ as described in section 3.1.4.1 of the IPP Model and Semantics
+ document.</P>
+<P>&quot;printer-uri&quot; (uri) and &quot;job-id&quot; (integer)</P>
+<P><I>OR</I></P>
+<P>&quot;job-uri&quot;:</P>
+<P>The client MUST supply a URI for the specified printer and a job ID
+ number, or the job URI.</P>
+</UL>
+<P>Group 2: Job Template Attributes</P>
+<UL>
+<P>&quot;job-sheets&quot; (1setof type3 keyword | name(MAX)):</P>
+<P><I>(CUPS 1.1 and higher)</I></P>
+<P>The client OPTIONALLY supplies one or two banner pages that are
+ printed before and after any files in the print job. The name of &quot;none&quot;
+ is reserved to indicate that no banner page should be printed. If the
+ client does not specify this attribute then the value of the
+ &quot;job-sheets-default&quot; printer object attribute is used.</P>
+<P><B>Note:</B> Standard IPP only allows specification of a single
+ job-sheets attribute value.</P>
+<P>&quot;media&quot; (1setof type3 keyword | name(MAX)):</P>
+<P>The client OPTIONALLY supplies one or more media attributes
+ specifying the size, type, source, and color of the output media. If
+ the client does not specify this attribute then the value of the
+ &quot;media-default&quot; printer object attribute is used.</P>
+<P><B>Note:</B> Standard IPP only allows specification of a single media
+ attribute value.</P>
+<P>Other Job Template Attributes</P>
+</UL>
+<H3><A NAME="4_3_2">4.3.2 Set-Job-Attributes Response</A></H3>
+<P>The following groups of attributes are send as part of the
+ Set-Job-Attributes Response:</P>
+<P>Group 1: Operation Attributes</P>
+<UL>
+<P>Status Message:</P>
+<P>The standard response status message.</P>
+<P>Natural Language and Character Set:</P>
+<P>The &quot;attributes-charset&quot; and &quot;attributes-natural-language&quot; attributes
+ as described in section 3.1.4.2 of the IPP Model and Semantics
+ document.</P>
+</UL>
+<H2><A NAME="4_4">4.4 CUPS-Get-Default Operation</A></H2>
+<P>The CUPS-Get-Default operation (0x4001) returns the default printer
+ URI and attributes.</P>
+<H3><A NAME="4_4_1">4.4.1 CUPS-Get-Default Request</A></H3>
+<P>The following groups of attributes are supplied as part of the
+ CUPS-Get-Default request:</P>
+<P>Group 1: Operation Attributes</P>
+<UL>
+<P>Natural Language and Character Set:</P>
+<P>The &quot;attributes-charset&quot; and &quot;attributes-natural-language&quot; attributes
+ as described in section 3.1.4.1 of the IPP Model and Semantics
+ document.</P>
+<P>&quot;requested-attributes&quot; (1setOf keyword) :</P>
+<P>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'.</P>
+</UL>
+<H3><A NAME="4_4_2">4.4.2 CUPS-Get-Default Response</A></H3>
+<P>The following groups of attributes are send as part of the
+ CUPS-Get-Default Response:</P>
+<P>Group 1: Operation Attributes</P>
+<UL>
+<P>Status Message:</P>
+<P>The standard response status message.</P>
+<P>Natural Language and Character Set:</P>
+<P>The &quot;attributes-charset&quot; and &quot;attributes-natural-language&quot; attributes
+ as described in section 3.1.4.2 of the IPP Model and Semantics
+ document.</P>
+</UL>
+<P>Group 2: Printer Object Attributes</P>
+<UL>
+<P>The set of requested attributes and their current values.</P>
+</UL>
+<H2><A NAME="4_5">4.5 CUPS-Get-Printers Operation</A></H2>
+<P>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.</P>
+<H3><A NAME="4_5_1">4.5.1 CUPS-Get-Printers Request</A></H3>
+<P>The following groups of attributes are supplied as part of the
+ CUPS-Get-Printers request:</P>
+<P>Group 1: Operation Attributes</P>
+<UL>
+<P>Natural Language and Character Set:</P>
+<P>The &quot;attributes-charset&quot; and &quot;attributes-natural-language&quot; attributes
+ as described in section 3.1.4.1 of the IPP Model and Semantics
+ document.</P>
+<P>&quot;limit&quot; (integer (1:MAX)):</P>
+<P>The client OPTIONALLY supplies this attribute limiting the number of
+ printers that are returned.</P>
+<P>&quot;printer-info&quot; (text(127)):</P>
+<P><I>(CUPS 1.1 and higher)</I></P>
+<P>The client OPTIONALLY supplies this attribute to select which
+ printers are returned.</P>
+<P>&quot;printer-location&quot; (text(127)):</P>
+<P><I>(CUPS 1.1 and higher)</I></P>
+<P>The client OPTIONALLY supplies this attribute to select which
+ printers are returned.</P>
+<P>&quot;printer-type&quot; (type2 enum):</P>
+<P><I>(CUPS 1.1 and higher)</I></P>
+<P>The client OPTIONALLY supplies a printer type enumeration to select
+ which printers are returned.</P>
+<P>&quot;printer-type-mask&quot; (type2 enum):</P>
+<P><I>(CUPS 1.1 and higher)</I></P>
+<P>The client OPTIONALLY supplies a printer type mask enumeration to
+ select which bits are used in the &quot;printer-type&quot; attribute.</P>
+<P>&quot;requested-attributes&quot; (1setOf keyword) :</P>
+<P>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'.</P>
+</UL>
+<H3><A NAME="4_5_2">4.5.2 CUPS-Get-Printers Response</A></H3>
+<P>The following groups of attributes are send as part of the
+ CUPS-Get-Printers Response:</P>
+<P>Group 1: Operation Attributes</P>
+<UL>
+<P>Status Message:</P>
+<P>The standard response status message.</P>
+<P>Natural Language and Character Set:</P>
+<P>The &quot;attributes-charset&quot; and &quot;attributes-natural-language&quot; attributes
+ as described in section 3.1.4.2 of the IPP Model and Semantics
+ document.</P>
+</UL>
+<P>Group 2: Printer Object Attributes</P>
+<UL>
+<P>The set of requested attributes and their current values for each
+ printer.</P>
+</UL>
+<H2><A NAME="4_6">4.6 CUPS-Add-Printer Operation</A></H2>
+<P>The CUPS-Add-Printer operation (0x4003) adds a new printer or
+ modifies an existing printer on the system.</P>
+<H3><A NAME="4_6_1">4.6.1 CUPS-Add-Printer Request</A></H3>
+<P>The following groups of attributes are supplied as part of the
+ CUPS-Add-Printer request:</P>
+<P>Group 1: Operation Attributes</P>
+<UL>
+<P>Natural Language and Character Set:</P>
+<P>The &quot;attributes-charset&quot; and &quot;attributes-natural-language&quot; attributes
+ as described in section 3.1.4.1 of the IPP Model and Semantics
+ document.</P>
+<P>&quot;printer-uri&quot; (uri):</P>
+<P>The client MUST supply a URI for the specified printer.</P>
+</UL>
+<P>Group 2: Printer Object Attributes</P>
+<UL>
+<P>&quot;banner-end-default&quot; (name(127)):</P>
+<P><I>(CUPS 1.1 and higher)</I></P>
+<P>The client OPTIONALLY supplies a banner page name that is printed
+ after files in a job. The reserved name &quot;none&quot; is used to specify that
+ no banner page should be printed.</P>
+<P>&quot;banner-start-default&quot; (name(127)):</P>
+<P><I>(CUPS 1.1 and higher)</I></P>
+<P>The client OPTIONALLY supplies a banner page name that is printed
+ before files in a job. The reserved name &quot;none&quot; is used to specify that
+ no banner page should be printed.</P>
+<P>&quot;device-uri&quot; (uri):</P>
+<P>The client OPTIONALLY supplies a device URI for the specified
+ printer.</P>
+<P>&quot;ppd-name&quot; (name(127)):</P>
+<P>The client OPTIONALLY supplies a PPD name for the specified printer.</P>
+<P>&quot;printer-is-accepting-jobs&quot; (boolean):</P>
+<P>The client OPTIONALLY supplies this boolean attribute indicating
+ whether or not the printer object should accept new jobs.</P>
+<P>&quot;printer-info&quot; (text(127)):</P>
+<P>The client OPTIONALLY supplies this attribute indicating the printer
+ information string.</P>
+<P>&quot;printer-location&quot; (text(127)):</P>
+<P>The client OPTIONALLY supplies this attribute indicating a textual
+ location of the printer.</P>
+<P>&quot;printer-more-info&quot; (uri):</P>
+<P>The client OPTIONALLY supplies this attribute indicating a URI for
+ additional printer information.</P>
+<P>&quot;printer-state&quot; (type2 enum):</P>
+<P>The client OPTIONALLY supplies this attribute indicating the
+ initial/current state of the printer. Only the &quot;idle&quot; and &quot;stopped&quot;
+ enumerations are recognized.</P>
+<P>&quot;printer-state-message&quot; (text(MAX)):</P>
+<P>The client OPTIONALLY supplies this attribute indicating a textual
+ reason for the current printer state.</P>
+<P>&quot;requesting-user-name-allowed&quot; (1setof name(127) | delete)</P>
+<P><I>OR</I></P>
+<P>&quot;requesting-user-name-denied&quot; (1setof name(127) | delete):</P>
+<P>The client OPTIONALLY supplies one of these attributes to specify an
+ access control list for incoming print jobs. To allow all users access
+ to a printer, use the delete tag for the attribute value.</P>
+</UL>
+<P>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 &quot;ppd-name&quot;
+ attribute overrides any file that is attached to the end of the request
+ with a local CUPS PPD file.</P>
+<H3><A NAME="4_6_2">4.6.2 CUPS-Add-Printer Response</A></H3>
+<P>The following groups of attributes are send as part of the
+ CUPS-Add-Printer Response:</P>
+<P>Group 1: Operation Attributes</P>
+<UL>
+<P>Status Message:</P>
+<P>The standard response status message.</P>
+<P>Natural Language and Character Set:</P>
+<P>The &quot;attributes-charset&quot; and &quot;attributes-natural-language&quot; attributes
+ as described in section 3.1.4.2 of the IPP Model and Semantics
+ document.</P>
+</UL>
+<H2><A NAME="4_7">4.7 CUPS-Delete-Printer Operation</A></H2>
+<P>The CUPS-Delete-Printer operation (0x4004) removes an existing
+ printer from the system.</P>
+<H3><A NAME="4_7_1">4.7.1 CUPS-Delete-Printer Request</A></H3>
+<P>The following groups of attributes are supplied as part of the
+ CUPS-Delete-Printer request:</P>
+<P>Group 1: Operation Attributes</P>
+<UL>
+<P>Natural Language and Character Set:</P>
+<P>The &quot;attributes-charset&quot; and &quot;attributes-natural-language&quot; attributes
+ as described in section 3.1.4.1 of the IPP Model and Semantics
+ document.</P>
+<P>&quot;printer-uri&quot; (uri):</P>
+<P>The client MUST supply a URI for the specified printer.</P>
+</UL>
+<H3><A NAME="4_7_2">4.7.2 CUPS-Delete-Printer Response</A></H3>
+<P>The following groups of attributes are send as part of the
+ CUPS-Delete-Printer Response:</P>
+<P>Group 1: Operation Attributes</P>
+<UL>
+<P>Status Message:</P>
+<P>The standard response status message.</P>
+<P>Natural Language and Character Set:</P>
+<P>The &quot;attributes-charset&quot; and &quot;attributes-natural-language&quot; attributes
+ as described in section 3.1.4.2 of the IPP Model and Semantics
+ document.</P>
+</UL>
+<H2><A NAME="4_8">4.8 CUPS-Get-Classes Operation</A></H2>
+<P>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.</P>
+<H3><A NAME="4_8_1">4.8.1 CUPS-Get-Classes Request</A></H3>
+<P>The following groups of attributes are supplied as part of the
+ CUPS-Get-Classes request:</P>
+<P>Group 1: Operation Attributes</P>
+<UL>
+<P>Natural Language and Character Set:</P>
+<P>The &quot;attributes-charset&quot; and &quot;attributes-natural-language&quot; attributes
+ as described in section 3.1.4.1 of the IPP Model and Semantics
+ document.</P>
+<P>&quot;limit&quot; (integer (1:MAX)):</P>
+<P>The client OPTIONALLY supplies this attribute limiting the number of
+ printer classes that are returned.</P>
+<P>&quot;printer-info&quot; (text(127)):</P>
+<P><I>(CUPS 1.1 and higher)</I></P>
+<P>The client OPTIONALLY supplies this attribute to select which printer
+ classes are returned.</P>
+<P>&quot;printer-location&quot; (text(127)):</P>
+<P><I>(CUPS 1.1 and higher)</I></P>
+<P>The client OPTIONALLY supplies this attribute to select which printer
+ classes are returned.</P>
+<P>&quot;printer-type&quot; (type2 enum):</P>
+<P><I>(CUPS 1.1 and higher)</I></P>
+<P>The client OPTIONALLY supplies a printer type enumeration to select
+ which printer classes are returned.</P>
+<P>&quot;printer-type-mask&quot; (type2 enum):</P>
+<P><I>(CUPS 1.1 and higher)</I></P>
+<P>The client OPTIONALLY supplies a printer type mask enumeration to
+ select which bits are used in the &quot;printer-type&quot; attribute.</P>
+<P>&quot;requested-attributes&quot; (1setOf keyword) :</P>
+<P>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'.</P>
+</UL>
+<H3><A NAME="4_8_2">4.8.2 CUPS-Get-Classes Response</A></H3>
+<P>The following groups of attributes are send as part of the
+ CUPS-Get-Classes Response:</P>
+<P>Group 1: Operation Attributes</P>
+<UL>
+<P>Status Message:</P>
+<P>The standard response status message.</P>
+<P>Natural Language and Character Set:</P>
+<P>The &quot;attributes-charset&quot; and &quot;attributes-natural-language&quot; attributes
+ as described in section 3.1.4.2 of the IPP Model and Semantics
+ document.</P>
+</UL>
+<P>Group 2: Printer Class Object Attributes</P>
+<UL>
+<P>The set of requested attributes and their current values for each
+ printer class.</P>
+</UL>
+<H2><A NAME="4_9">4.9 CUPS-Add-Class Operation</A></H2>
+<P>The CUPS-Add-Class operation (0x4006) adds a new printer class or
+ modifies and existing printer class on the system.</P>
+<H3><A NAME="4_9_1">4.9.1 CUPS-Add-Class Request</A></H3>
+<P>The following groups of attributes are supplied as part of the
+ CUPS-Add-Class request:</P>
+<P>Group 1: Operation Attributes</P>
+<UL>
+<P>Natural Language and Character Set:</P>
+<P>The &quot;attributes-charset&quot; and &quot;attributes-natural-language&quot; attributes
+ as described in section 3.1.4.1 of the IPP Model and Semantics
+ document.</P>
+<P>&quot;printer-uri&quot; (uri):</P>
+<P>The client MUST supply a URI for the specified printer class.</P>
+</UL>
+<P>Group 2: Printer Object Attributes</P>
+<UL>
+<P>&quot;member-uris&quot; (1setof uri):</P>
+<P>The client OPTIONALLY supplies the &quot;member-uris&quot; set specifying the
+ printers and printer classes that are part of the class.</P>
+<P>&quot;printer-is-accepting-jobs&quot; (boolean):</P>
+<P>The client OPTIONALLY supplies this boolean attribute indicating
+ whether or not the class object should accept new jobs.</P>
+<P>&quot;printer-info&quot; (text(127)):</P>
+<P>The client OPTIONALLY supplies this attribute indicating the printer
+ information string.</P>
+<P>&quot;printer-location&quot; (text(127)):</P>
+<P>The client OPTIONALLY supplies this attribute indicating a textual
+ location of the class.</P>
+<P>&quot;printer-more-info&quot; (uri):</P>
+<P>The client OPTIONALLY supplies this attribute indicating a URI for
+ additional class information.</P>
+<P>&quot;printer-state&quot; (type2 enum):</P>
+<P>The client OPTIONALLY supplies this attribute indicating the
+ initial/current state of the class. Only the &quot;idle&quot; and &quot;stopped&quot;
+ enumerations are recognized.</P>
+<P>&quot;printer-state-message&quot; (text(MAX)):</P>
+<P>The client OPTIONALLY supplies this attribute indicating a textual
+ reason for the current class state.</P>
+<P>&quot;requesting-user-name-allowed&quot; (1setof name(127))</P>
+<P><I>OR</I></P>
+<P>&quot;requesting-user-name-denied&quot; (1setof name(127)):</P>
+<P>The client OPTIONALLY supplies one of these attributes to specify an
+ access control list for incoming print jobs. To allow all users access
+ to a class, use the delete tag for the attribute value.</P>
+</UL>
+<H3><A NAME="4_9_2">4.9.2 CUPS-Add-Class Response</A></H3>
+<P>The following groups of attributes are send as part of the
+ CUPS-Add-Class Response:</P>
+<P>Group 1: Operation Attributes</P>
+<UL>
+<P>Status Message:</P>
+<P>The standard response status message.</P>
+<P>Natural Language and Character Set:</P>
+<P>The &quot;attributes-charset&quot; and &quot;attributes-natural-language&quot; attributes
+ as described in section 3.1.4.2 of the IPP Model and Semantics
+ document.</P>
+</UL>
+<H2><A NAME="4_10">4.10 CUPS-Delete-Class Operation</A></H2>
+<P>The CUPS-Delete-Class operation (0x4007) removes an existing printer
+ class from the system.</P>
+<H3><A NAME="4_10_1">4.10.1 CUPS-Delete-Class Request</A></H3>
+<P>The following groups of attributes are supplied as part of the
+ CUPS-Delete-Class request:</P>
+<P>Group 1: Operation Attributes</P>
+<UL>
+<P>Natural Language and Character Set:</P>
+<P>The &quot;attributes-charset&quot; and &quot;attributes-natural-language&quot; attributes
+ as described in section 3.1.4.1 of the IPP Model and Semantics
+ document.</P>
+<P>&quot;printer-uri&quot; (uri):</P>
+<P>The client MUST supply a URI for the specified printer class.</P>
+</UL>
+<H3><A NAME="4_10_2">4.10.2 CUPS-Delete-Class Response</A></H3>
+<P>The following groups of attributes are send as part of the
+ CUPS-Delete-Class Response:</P>
+<P>Group 1: Operation Attributes</P>
+<UL>
+<P>Status Message:</P>
+<P>The standard response status message.</P>
+<P>Natural Language and Character Set:</P>
+<P>The &quot;attributes-charset&quot; and &quot;attributes-natural-language&quot; attributes
+ as described in section 3.1.4.2 of the IPP Model and Semantics
+ document.</P>
+</UL>
+<H2><A NAME="4_11">4.11 CUPS-Accept-Jobs Operation</A></H2>
+<P>The CUPS-Accept-Jobs operation (0x4008) sets the
+ &quot;printer-is-accepting-jobs&quot; attribute to true for the specified printer
+ or printer class.</P>
+<H3><A NAME="4_11_1">4.11.1 CUPS-Accept-Jobs Request</A></H3>
+<P>The following groups of attributes are supplied as part of the
+ CUPS-Accept-Jobs request:</P>
+<P>Group 1: Operation Attributes</P>
+<UL>
+<P>Natural Language and Character Set:</P>
+<P>The &quot;attributes-charset&quot; and &quot;attributes-natural-language&quot; attributes
+ as described in section 3.1.4.1 of the IPP Model and Semantics
+ document.</P>
+<P>&quot;printer-uri&quot; (uri):</P>
+<P>The client MUST supply a URI for the specified printer or printer
+ class.</P>
+</UL>
+<H3><A NAME="4_11_2">4.11.2 CUPS-Accept-Jobs Response</A></H3>
+<P>The following groups of attributes are send as part of the
+ CUPS-Accept-Jobs Response:</P>
+<P>Group 1: Operation Attributes</P>
+<UL>
+<P>Status Message:</P>
+<P>The standard response status message.</P>
+<P>Natural Language and Character Set:</P>
+<P>The &quot;attributes-charset&quot; and &quot;attributes-natural-language&quot; attributes
+ as described in section 3.1.4.2 of the IPP Model and Semantics
+ document.</P>
+</UL>
+<H2><A NAME="4_12">4.12 CUPS-Reject-Jobs Operation</A></H2>
+<P>The CUPS-Reject-Jobs operation (0x4009) sets
+ the&quot;printer-is-accepting-jobs&quot; attribute to false for the specified
+ printer or printer class.</P>
+<H3><A NAME="4_12_1">4.12.1 CUPS-Reject-Jobs Request</A></H3>
+<P>The following groups of attributes are supplied as part of the
+ CUPS-Reject-Jobs request:</P>
+<P>Group 1: Operation Attributes</P>
+<UL>
+<P>Natural Language and Character Set:</P>
+<P>The &quot;attributes-charset&quot; and &quot;attributes-natural-language&quot; attributes
+ as described in section 3.1.4.1 of the IPP Model and Semantics
+ document.</P>
+<P>&quot;printer-uri&quot; (uri):</P>
+<P>The client MUST supply a URI for the specified printer or printer
+ class.</P>
+</UL>
+<P>Group 2: Printer Object Attributes</P>
+<UL>
+<P>&quot;printer-state-message&quot; (text(MAX)):</P>
+<P>The client OPTIONALLY supplies this attribute indicating a textual
+ reason for the current printer state.</P>
+</UL>
+<H3><A NAME="4_12_2">4.12.2 CUPS-Reject-Jobs Response</A></H3>
+<P>The following groups of attributes are send as part of the
+ CUPS-Reject-Jobs Response:</P>
+<P>Group 1: Operation Attributes</P>
+<UL>
+<P>Status Message:</P>
+<P>The standard response status message.</P>
+<P>Natural Language and Character Set:</P>
+<P>The &quot;attributes-charset&quot; and &quot;attributes-natural-language&quot; attributes
+ as described in section 3.1.4.2 of the IPP Model and Semantics
+ document.</P>
+</UL>
+<H2><A NAME="4_13">4.13 CUPS-Set-Default Operation</A></H2>
+<P>The CUPS-Set-Default operation (0x400A) sets the default printer
+ destination for all clients when a resource name of &quot;/printers&quot; is
+ specified.</P>
+<H3><A NAME="4_13_1">4.13.1 CUPS-Set-Default Request</A></H3>
+<P>The following groups of attributes are supplied as part of the
+ CUPS-Set-Default request:</P>
+<P>Group 1: Operation Attributes</P>
+<UL>
+<P>Natural Language and Character Set:</P>
+<P>The &quot;attributes-charset&quot; and &quot;attributes-natural-language&quot; attributes
+ as described in section 3.1.4.1 of the IPP Model and Semantics
+ document.</P>
+<P>&quot;printer-uri&quot; (uri):</P>
+<P>The client MUST supply a URI for the specified printer or printer
+ class.</P>
+</UL>
+<H3><A NAME="4_13_2">4.13.2 CUPS-Set-Default Response</A></H3>
+<P>The following groups of attributes are send as part of the
+ CUPS-Set-Default Response:</P>
+<P>Group 1: Operation Attributes</P>
+<UL>
+<P>Status Message:</P>
+<P>The standard response status message.</P>
+<P>Natural Language and Character Set:</P>
+<P>The &quot;attributes-charset&quot; and &quot;attributes-natural-language&quot; attributes
+ as described in section 3.1.4.2 of the IPP Model and Semantics
+ document.</P>
+</UL>
+<H2><A NAME="4_14">4.14 CUPS-Get-Devices Operation</A></H2>
+<P>The CUPS-Get-Devices operation (0x400B) returns all of the supported
+ device-uri's for the server (CUPS 1.1 and higher).</P>
+<H3><A NAME="4_14_1">4.14.1 CUPS-Get-Devices Request</A></H3>
+<P>The following groups of attributes are supplied as part of the
+ CUPS-Get-Devices request:</P>
+<P>Group 1: Operation Attributes</P>
+<UL>
+<P>Natural Language and Character Set:</P>
+<P>The &quot;attributes-charset&quot; and &quot;attributes-natural-language&quot; attributes
+ as described in section 3.1.4.1 of the IPP Model and Semantics
+ document.</P>
+<P>&quot;device-class&quot; (type1 keyword):</P>
+<P>The client OPTIONALLY supplies a device class keyword to select which
+ devices are returned.</P>
+<P>&quot;limit&quot; (integer (1:MAX)):</P>
+<P>The client OPTIONALLY supplies this attribute limiting the number of
+ devices that are returned.</P>
+<P>&quot;requested-attributes&quot; (1setOf keyword) :</P>
+<P>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'.</P>
+</UL>
+<H3><A NAME="4_14_2">4.14.2 CUPS-Get-Devices Response</A></H3>
+<P>The following groups of attributes are send as part of the
+ CUPS-Get-Devices Response:</P>
+<P>Group 1: Operation Attributes</P>
+<UL>
+<P>Status Message:</P>
+<P>The standard response status message.</P>
+<P>Natural Language and Character Set:</P>
+<P>The &quot;attributes-charset&quot; and &quot;attributes-natural-language&quot; attributes
+ as described in section 3.1.4.2 of the IPP Model and Semantics
+ document.</P>
+</UL>
+<P>Group 2: Device Object Attributes</P>
+<UL>
+<P>The set of requested attributes and their current values for each
+ device.</P>
+</UL>
+<H2><A NAME="4_15">4.15 CUPS-Get-PPDs Operation</A></H2>
+<P>The CUPS-Get-PPDs operation (0x400C) returns all of the locally
+ available PPD files on the system (CUPS 1.1 and higher).</P>
+<H3><A NAME="4_15_1">4.15.1 CUPS-Get-PPDs Request</A></H3>
+<P>The following groups of attributes are supplied as part of the
+ CUPS-Get-PPDs request:</P>
+<P>Group 1: Operation Attributes</P>
+<UL>
+<P>Natural Language and Character Set:</P>
+<P>The &quot;attributes-charset&quot; and &quot;attributes-natural-language&quot; attributes
+ as described in section 3.1.4.1 of the IPP Model and Semantics
+ document.</P>
+<P>&quot;limit&quot; (integer (1:MAX)):</P>
+<P>The client OPTIONALLY supplies this attribute limiting the number of
+ PPDs that are returned.</P>
+<P>&quot;ppd-make&quot; (text(127)):</P>
+<P>The client OPTIONALLY supplies a printer manufacturer to select which
+ PPDs are returned.</P>
+<P>&quot;requested-attributes&quot; (1setOf keyword) :</P>
+<P>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'.</P>
+</UL>
+<H3><A NAME="4_15_2">4.15.2 CUPS-Get-PPDs Response</A></H3>
+<P>The following groups of attributes are send as part of the
+ CUPS-Get-PPDs Response:</P>
+<P>Group 1: Operation Attributes</P>
+<UL>
+<P>Status Message:</P>
+<P>The standard response status message.</P>
+<P>Natural Language and Character Set:</P>
+<P>The &quot;attributes-charset&quot; and &quot;attributes-natural-language&quot; attributes
+ as described in section 3.1.4.2 of the IPP Model and Semantics
+ document.</P>
+</UL>
+<P>Group 2: PPD Attributes</P>
+<UL>
+<P>The set of requested attributes and their current values for each PPD
+ file.</P>
+</UL>
+<H2><A NAME="4_16">4.16 CUPS-Move-Job Operation</A></H2>
+<P>The CUPS-Move-Job operation (0x400D) moves an active print job to a
+ different printer (CUPS 1.1 and higher).</P>
+<H3><A NAME="4_16_1">4.16.1 CUPS-Move-Job Request</A></H3>
+<P>The following groups of attributes are supplied as part of the
+ CUPS-Move-Job request:</P>
+<P>Group 1: Operation Attributes</P>
+<UL>
+<P>Natural Language and Character Set:</P>
+<P>The &quot;attributes-charset&quot; and &quot;attributes-natural-language&quot; attributes
+ as described in section 3.1.4.1 of the IPP Model and Semantics
+ document.</P>
+<P>&quot;printer-uri&quot; (uri) and &quot;job-id&quot; (integer)</P>
+<P><I>OR</I></P>
+<P>&quot;job-uri&quot;:</P>
+<P>The client MUST supply a URI for the specified printer and a job ID
+ number, or the job URI.</P>
+</UL>
+<P>Group 2: Job Template Attributes</P>
+<UL>
+<P>&quot;job-printer-uri&quot; (uri)</P>
+<P>The client MUST supply a URI for a printer on the same server.</P>
+</UL>
+<H3><A NAME="4_16_2">4.16.2 CUPS-Move-Job Response</A></H3>
+<P>The following groups of attributes are send as part of the
+ CUPS-Move-Job Response:</P>
+<P>Group 1: Operation Attributes</P>
+<UL>
+<P>Status Message:</P>
+<P>The standard response status message.</P>
+<P>Natural Language and Character Set:</P>
+<P>The &quot;attributes-charset&quot; and &quot;attributes-natural-language&quot; attributes
+ as described in section 3.1.4.2 of the IPP Model and Semantics
+ document.</P>
+</UL>
+<H1><A NAME="5">5 Attributes</A></H1>
+<P>CUPS provides many extension attributes to support multiple devices,
+ PPD files, standard job filters, printers, and printer classes.</P>
+<H2><A NAME="5_1">5.1 Device Attributes</A></H2>
+<P>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.</P>
+<H3><A NAME="5_1_1">5.1.1 device-class (type2 keyword)</A></H3>
+<P>The device-class attribute specifies the class of device and can be
+ one of the following:</P>
+<UL>
+<LI>&quot;file&quot; - a disk file.</LI>
+<LI>&quot;direct&quot; - a parallel or fixed-rate serial data port, currently used
+ for Centronics, IEEE-1284, and USB printer ports.</LI>
+<LI>&quot;serial&quot; - a variable-rate serial port.</LI>
+<LI>&quot;network&quot; - a network connection, typically via AppSocket, HTTP,
+ IPP, LPD, or SMB/CIFS protocols.</LI>
+</UL>
+<H3><A NAME="5_1_2">5.1.2 device-info (text(127))</A></H3>
+<P>The device-info attribute specifies a human-readable string
+ describing the device, e.g. &quot;Parallel Port #1&quot;.</P>
+<H3><A NAME="5_1_3">5.1.3 device-make-and-model (text(127))</A></H3>
+<P>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 &quot;unknown&quot;.</P>
+<H3><A NAME="5_1_4">5.1.4 device-uri (uri)</A></H3>
+<P>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:</P>
+<UL>
+<LI>&quot;file&quot; - The device-uri will be of the form
+ &quot;file:/path/to/filename&quot;.</LI>
+<LI>&quot;direct&quot; - The device-uri will be of the form
+ &quot;method:/dev/filename&quot;, where method may be &quot;parallel&quot; or &quot;usb&quot; in the
+ current implementation.</LI>
+<LI>&quot;serial&quot; - The device-uri will be of the form
+ &quot;serial:/dev/filename?baud=value+parity=value+flow=value&quot;. The baud
+ value is the data rate in bits per second; the supported values depend
+ on the underlying hardware. The parity value can be one of &quot;none&quot;,
+ &quot;even&quot;, or &quot;odd&quot;. The flow value can be one of &quot;none&quot;, &quot;soft&quot; (XON/XOFF
+ handshaking), &quot;hard&quot; or &quot;rts/cts&quot; (RTS/CTS handshaking), or &quot;dtrdsr&quot;
+ (DTR/DSR handshaking).</LI>
+<P>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 (&quot;soft&quot; or &quot;hard&quot;).</P>
+<LI>&quot;network&quot; - The device-uri will be of the form
+ &quot;method://[username:password@]hostname[:port]/[resource]&quot;, where method
+ may be &quot;http&quot;, &quot;ipp&quot;, &quot;lpd&quot;, &quot;smb&quot;, or &quot;socket&quot; in the current
+ implementation.</LI>
+<P>The URI returned by CUPS-Get-Devices will only contain the method
+ name followed by two slashes (&quot;method://&quot;). It is up to the client
+ application to add the appropriate host and other information when
+ adding a new printer.</P>
+<P>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.</P>
+</UL>
+<H2><A NAME="5_2">5.2 Job Template Attributes</A></H2>
+<H3><A NAME="5_2_1">5.2.1 blackplot (boolean)</A></H3>
+<P>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.</P>
+<H3><A NAME="5_2_2">5.2.2 brightness (integer(0:200))</A></H3>
+<P>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.</P>
+<P>Brightness is applied to the Cyan, Magenta, Yellow, and Black values
+ using the function &quot;f(x) = brightness / 100 * x&quot;.</P>
+<H3><A NAME="5_2_3">5.2.3 columns (integer(1:4))</A></H3>
+<P>The columns attribute specifies the number of columns to generate
+ when printing text files. The default value is 1.</P>
+<H3><A NAME="5_2_4">5.2.4 cpi (type2 enum)</A></H3>
+<P>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.</P>
+<H3><A NAME="5_2_5">5.2.5 fitplot (boolean)</A></H3>
+<P>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.</P>
+<H3><A NAME="5_2_6">5.2.6 gamma (integer(1:10000))</A></H3>
+<P>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.</P>
+<P>Gamma is applied to the Red, Green, and Blue values (or luminance for
+ grayscale output) using the function &quot;f(x) = x<SUP>(1000/gamma)</SUP>&quot;.</P>
+<H3><A NAME="5_2_7">5.2.7 hue (integer(-180:180))</A></H3>
+<P>The hue attribute specifies a color hue rotation when printing image
+ files. The default value is 0.</P>
+<H3><A NAME="5_2_8">5.2.8 job-billing (text(MAX))</A></H3>
+<P><I>(CUPS 1.1 and higher)</I></P>
+<P>The job-billing attribute provides a text value to associate with a
+ job for billing purposes.</P>
+<H3><A NAME="5_2_9">5.2.9 job-hold-until (keyword | name(MAX))</A></H3>
+<P><I>(CUPS 1.1 and higher)</I></P>
+<P>The job-hold-until attribute specifies a hold time. In addition to
+ the standard IPP/1.1 keyword names, CUPS supports name values of the
+ form &quot;HH:MM&quot; and &quot;HH:MM:SS&quot; that specify a hold time. The hold time is
+ in Greenwich Mean Time (GMT) and<I> not</I> in the local time zone. If
+ the specified time is less than the current time, the job is held until
+ the next day.</P>
+<H3><A NAME="5_2_10">5.2.10 job-sheets (1setof type3 keyword |
+ name(MAX))</A></H3>
+<P><I>(CUPS 1.1 and higher)</I></P>
+<P>The job-sheets attribute specifies one or two banner files that are
+ printed before and after a job. The reserved value of &quot;none&quot; disables
+ banner printing. The default value is stored in the job-sheets-default
+ attribute.</P>
+<P>If only one value is supplied, the banner file is printed before the
+ job. If two values are supplied, the first value is used as the
+ starting banner file and the second as the ending banner file.</P>
+<H3><A NAME="5_2_11">5.2.11 job-originating-host-name (name(MAX))</A></H3>
+<P><I>(CUPS 1.1.5 and higher)</I></P>
+<P>The job-originating-host-name attribute specifies the host from which
+ the job was queued. The value will be the hostname or IP address of the
+ client depending on whether hostname resolution is enabled. The
+ localhost address (127.0.0.1) is<B> always</B> resolved to the name
+ &quot;localhost&quot;.</P>
+<P>This attribute is read-only.</P>
+<H3><A NAME="5_2_12">5.2.12 lpi (type2 enum)</A></H3>
+<P>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.</P>
+<H3><A NAME="5_2_13">5.2.13 natural-scaling (integer(1:1000))</A></H3>
+<P><I>(CUPS 1.1.9 and higher)</I></P>
+<P>The natural-scaling attribute specifies the scaling of image files
+ with respect to the natural image size. A value of 100 specifies that
+ the image file should exactly the natural size, while 50 is half the
+ natural size and 200 is twice the natural size. The default value is
+ 100.</P>
+<P>The ppi option can be used to override the natural resolution of the
+ image, which controls the natural size.</P>
+<H3><A NAME="5_2_14">5.2.14 page-bottom (integer(0:MAX))</A></H3>
+<P>The page-bottom attribute specifies the bottom margin in points (72
+ points equals 1 inch). The default value is the device physical margin.</P>
+<H3><A NAME="5_2_15">5.2.15 page-label (text(MAX))</A></H3>
+<P><I>(CUPS 1.1.7 and higher)</I></P>
+<P>The page-label attribute provides a text value to place in the header
+ and footer on each page. If a classification level is set on the
+ server, then this classification is printed before the page label.</P>
+<H3><A NAME="5_2_16">5.2.16 page-left (integer(0:MAX))</A></H3>
+<P>The page-left attribute specifies the left margin in points (72
+ points equals 1 inch). The default value is the device physical margin.</P>
+<H3><A NAME="5_2_17">5.2.17 page-right (integer(0:MAX))</A></H3>
+<P>The page-right attribute specifies the right margin in points (72
+ points equals 1 inch). The default value is the device physical margin.</P>
+<H3><A NAME="5_2_18">5.2.18 page-set (type2 keyword)</A></H3>
+<P>The page-set attribute specifies which pages to print in a file. The
+ supported keywords are &quot;all&quot;, &quot;even&quot;, and &quot;odd&quot;. The default value is
+ &quot;all&quot;.</P>
+<H3><A NAME="5_2_19">5.2.19 page-top (integer(0:MAX))</A></H3>
+<P>The page-top attribute specifies the top margin in points (72 points
+ equals 1 inch). The default value is the device physical margin.</P>
+<H3><A NAME="5_2_20">5.2.20 penwidth (integer(0:MAX))</A></H3>
+<P>The penwidth attribute specifies the default pen width in micrometers
+ when printing HP-GL/2 plot files. The default value is 1000 (1
+ millimeter).</P>
+<H3><A NAME="5_2_21">5.2.21 position (type2 keyword)</A></H3>
+<P>The position attribute specifies the location of image files on the
+ media. The following keyword values are recognized:</P>
+<UL>
+<LI><CODE>center</CODE> - Center the image on the page (default)</LI>
+<LI><CODE>top</CODE> - Print the image centered at the top of the page</LI>
+<LI><CODE>left</CODE> - Print the image centered on the left of page</LI>
+<LI><CODE>right</CODE> - Print the image centered on the right of the
+ page</LI>
+<LI><CODE>top-left</CODE> - Print the image at the top left corner of
+ the page</LI>
+<LI><CODE>top-right</CODE> - Print the image at the top right corner of
+ the page</LI>
+<LI><CODE>bottom</CODE> - Print the image centered at the bottom of the
+ page</LI>
+<LI><CODE>bottom-left</CODE> - Print the image at the bottom left corner
+ of the page</LI>
+<LI><CODE>bottom-right</CODE> - Print the image at the bottom right
+ corner of the page</LI>
+</UL>
+<H3><A NAME="5_2_22">5.2.22 ppi (integer(1:MAX))</A></H3>
+<P>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.</P>
+<H3><A NAME="5_2_23">5.2.23 prettyprint (boolean)</A></H3>
+<P>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.</P>
+<H3><A NAME="5_2_24">5.2.24 saturation (integer(0:200))</A></H3>
+<P>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.</P>
+<H3><A NAME="5_2_25">5.2.25 scaling (integer(1:1000))</A></H3>
+<P>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.</P>
+<P>The scaling attribute overrides the ppi attribute if specified.</P>
+<H3><A NAME="5_2_26">5.2.26 wrap (boolean)</A></H3>
+<P>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.</P>
+<H2><A NAME="5_3">5.3 PPD Attributes</A></H2>
+<H3><A NAME="5_3_1">5.3.1 ppd-natural-language (naturalLanguage)</A></H3>
+<P>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 &quot;en&quot; (English) is assumed.</P>
+<H3><A NAME="5_3_2">5.3.2 ppd-make (text(127))</A></H3>
+<P>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.</P>
+<H3><A NAME="5_3_3">5.3.3 ppd-make-and-model (text(127))</A></H3>
+<P>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.</P>
+<H3><A NAME="5_3_4">5.3.4 ppd-name (name(255))</A></H3>
+<P>The ppd-name attribute specifies the PPD filename on the server
+ relative to the model directory. The forward slash (/) is used to
+ delineate directories.</P>
+<H2><A NAME="5_4">5.4 Printer Attributes</A></H2>
+<H3><A NAME="5_4_1">5.4.1 job-k-limit (integer)</A></H3>
+<P><I>(CUPS 1.1 and higher)</I></P>
+<P>The job-k-limit attribute specifies the maximum number of kilobytes
+ that may be printed by a user, including banner files. The default
+ value of 0 specifies that there is no limit.</P>
+<H3><A NAME="5_4_2">5.4.2 job-page-limit (integer)</A></H3>
+<P><I>(CUPS 1.1 and higher)</I></P>
+<P>The job-page-limit attribute specifies the maximum number of pages
+ that may be printed by a user, including banner files. The default
+ value of 0 specifies that there is no limit.</P>
+<H3><A NAME="5_4_3">5.4.3 job-quota-period (integer)</A></H3>
+<P><I>(CUPS 1.1 and higher)</I></P>
+<P>The job-quota-period attribute specifies the time period used for
+ quota calculations, in seconds. The default value of 0 specifies that
+ the limits apply to all jobs that have been printed by a user that are
+ still known to the system.</P>
+<H3><A NAME="5_4_4">5.4.4 job-sheets-supported (1setof type3 keyword |
+ name(MAX))</A></H3>
+<P><I>(CUPS 1.1 and higher)</I></P>
+<P>The job-sheets-supported attribute specifies the available banner
+ files. There will always be at least one banner file available called
+ &quot;none&quot;.</P>
+<H3><A NAME="5_4_5">5.4.5 printer-type (type2 enum)</A></H3>
+<P>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:
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Bit</TH><TH>Description</TH></TR>
+<TR><TD VALIGN="TOP">0x00000001</TD><TD VALIGN="TOP">Is a printer class.</TD>
+</TR>
+<TR><TD VALIGN="TOP">0x00000002</TD><TD VALIGN="TOP">Is a remote
+ destination.</TD></TR>
+<TR><TD VALIGN="TOP">0x00000004</TD><TD VALIGN="TOP">Can print in black.</TD>
+</TR>
+<TR><TD VALIGN="TOP">0x00000008</TD><TD VALIGN="TOP">Can print in color.</TD>
+</TR>
+<TR><TD VALIGN="TOP">0x00000010</TD><TD VALIGN="TOP">Can print on both
+ sides of the page in hardware.</TD></TR>
+<TR><TD VALIGN="TOP">0x00000020</TD><TD VALIGN="TOP">Can staple output.</TD>
+</TR>
+<TR><TD VALIGN="TOP">0x00000040</TD><TD VALIGN="TOP">Can do fast copies
+ in hardware.</TD></TR>
+<TR><TD VALIGN="TOP">0x00000080</TD><TD VALIGN="TOP">Can do fast copy
+ collation in hardware.</TD></TR>
+<TR><TD VALIGN="TOP">0x00000100</TD><TD VALIGN="TOP">Can punch output.</TD>
+</TR>
+<TR><TD VALIGN="TOP">0x00000200</TD><TD VALIGN="TOP">Can cover output.</TD>
+</TR>
+<TR><TD VALIGN="TOP">0x00000400</TD><TD VALIGN="TOP">Can bind output.</TD>
+</TR>
+<TR><TD VALIGN="TOP">0x00000800</TD><TD VALIGN="TOP">Can sort output.</TD>
+</TR>
+<TR><TD VALIGN="TOP">0x00001000</TD><TD VALIGN="TOP">Can handle media up
+ to US-Legal/A4.</TD></TR>
+<TR><TD VALIGN="TOP">0x00002000</TD><TD VALIGN="TOP">Can handle media
+ from US-Legal/A4 to ISO-C/A2.</TD></TR>
+<TR><TD VALIGN="TOP">0x00004000</TD><TD VALIGN="TOP">Can handle media
+ larger than ISO-C/A2.</TD></TR>
+<TR><TD VALIGN="TOP">0x00008000</TD><TD VALIGN="TOP">Can handle
+ user-defined media sizes.</TD></TR>
+<TR><TD VALIGN="TOP">0x00010000</TD><TD VALIGN="TOP">Is an implicit
+ (server-generated) class.</TD></TR>
+</TABLE>
+</CENTER>
+</P>
+<H3><A NAME="5_4_6">5.4.6 printer-type-mask (type2 enum)</A></H3>
+<P><I>(CUPS 1.1 and higher)</I></P>
+<P>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.</P>
+<H3><A NAME="5_4_7">5.4.7 requesting-user-name-allowed (1setof
+ name(127))</A></H3>
+<P><I>(CUPS 1.1 and higher)</I></P>
+<P>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.</P>
+<H3><A NAME="5_4_8">5.4.8 requesting-user-name-denied (1setof name(127))</A>
+</H3>
+<P><I>(CUPS 1.1 and higher)</I></P>
+<P>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.</P>
+<H2><A NAME="5_5">5.5 Printer Class Attributes</A></H2>
+<H3><A NAME="5_5_1">5.5.1 member-names (1setof name(127))</A></H3>
+<P>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.</P>
+<H3><A NAME="5_5_2">5.5.2 member-uris (1setof uri)</A></H3>
+<P>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.</P>
+<H1 TYPE="A" VALUE="1"><A NAME="6">A Glossary</A></H1>
+<H2><A NAME="6_1">A.1 Terms</A></H2>
+<DL>
+<DT>C</DT>
+<DD>A computer language.</DD>
+<DT>parallel</DT>
+<DD>Sending or receiving data more than 1 bit at a time.</DD>
+<DT>pipe</DT>
+<DD>A one-way communications channel between two programs.</DD>
+<DT>serial</DT>
+<DD>Sending or receiving data 1 bit at a time.</DD>
+<DT>socket</DT>
+<DD>A two-way network communications channel.</DD>
+</DL>
+<H2><A NAME="6_2">A.2 Acronyms</A></H2>
+<DL>
+<DT>ASCII</DT>
+<DD>American Standard Code for Information Interchange</DD>
+<DT>CUPS</DT>
+<DD>Common UNIX Printing System</DD>
+<DT>ESC/P</DT>
+<DD>EPSON Standard Code for Printers</DD>
+<DT>FTP</DT>
+<DD>File Transfer Protocol</DD>
+<DT>HP-GL</DT>
+<DD>Hewlett-Packard Graphics Language</DD>
+<DT>HP-PCL</DT>
+<DD>Hewlett-Packard Page Control Language</DD>
+<DT>HP-PJL</DT>
+<DD>Hewlett-Packard Printer Job Language</DD>
+<DT>IETF</DT>
+<DD>Internet Engineering Task Force</DD>
+<DT>IPP</DT>
+<DD>Internet Printing Protocol</DD>
+<DT>ISO</DT>
+<DD>International Standards Organization</DD>
+<DT>LPD</DT>
+<DD>Line Printer Daemon</DD>
+<DT>MIME</DT>
+<DD>Multimedia Internet Mail Exchange</DD>
+<DT>PPD</DT>
+<DD>PostScript Printer Description</DD>
+<DT>SMB</DT>
+<DD>Server Message Block</DD>
+<DT>TFTP</DT>
+<DD>Trivial File Transfer Protocol</DD>
+</DL>
+</BODY>
+</HTML>
diff --git a/doc/ipp.pdf b/doc/ipp.pdf
new file mode 100644
index 000000000..0a3fb0160
--- /dev/null
+++ b/doc/ipp.pdf
Binary files differ
diff --git a/doc/ipp.shtml b/doc/ipp.shtml
new file mode 100644
index 000000000..d59d81e10
--- /dev/null
+++ b/doc/ipp.shtml
@@ -0,0 +1,1938 @@
+<HTML>
+<HEAD>
+ <META NAME="COPYRIGHT" CONTENT="Copyright 1997-2002 All Rights Reserved">
+ <META NAME="DOCNUMBER" CONTENT="CUPS-IPP-1.1">
+ <META NAME="Author" CONTENT="Easy Software Products">
+ <TITLE>CUPS Implementation of IPP</TITLE>
+</HEAD>
+<BODY>
+
+<H1>Scope</H1>
+
+<H2>Identification</H2>
+
+<P>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.
+
+<EMBED SRC="system-overview.shtml">
+
+<H2>Document Overview</H2>
+
+<P>This document is organized into the following sections:
+
+<UL>
+ <LI><A HREF="#1">1 - Scope</A>
+ <LI><A HREF="#2">2 - References</A>
+ <LI><A HREF="#3">3 - Overview</A>
+ <LI><A HREF="#4">4 - Operations</A>
+ <LI><A HREF="#5">5 - Attributes</A>
+ <LI><A HREF="#6">A - Glossary</A>
+</UL>
+
+<EMBED SRC="references.shtml">
+
+<H1>Overview</H1>
+
+<P>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.
+
+<P>CUPS also provides 13 new operations and many new attributes to
+support multiple IPP printers and printer classes on a single host.
+
+<H2>IPP URIs</H2>
+
+<P>CUPS supports both the "http" and "ipp" methods. The following
+resource names are used:
+
+<DL>
+
+ <DT>method://hostname:port/
+
+ <DD>Can be used for all "get" operations.
+
+ <DT>method://hostname:port/admin
+
+ <DD>Used for all administrative operations.
+
+ <DT>method://hostname:port/classes/name
+
+ <DD>Specifies a printer class.
+
+ <DT>method://hostname:port/jobs/id
+
+ <DD>Specifies a job.
+
+ <DT>method://hostname:port/printers/name
+
+ <DD>Specifies a printer.
+
+</DL>
+
+<P>So a typical printer URI would be "ipp://foo.bar.com/printers/LaserJet".
+
+<P>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.
+
+<H2>CUPS IPP Operations</H2>
+
+<P>CUPS provides 13 extension operations in addition to most of the
+standard IPP and registered extension operations:
+
+<CENTER><TABLE BORDER WIDTH="80%">
+<TR>
+ <TH VALIGN="TOP">Operation Name</TH>
+ <TH VALIGN="TOP">CUPS</TH>
+ <TH VALIGN="TOP">Code</TH>
+ <TH VALIGN="TOP">Brief Description</TH>
+</TR>
+<TR>
+ <TD VALIGN="TOP">Print-Job</TD>
+ <TD VALIGN="TOP">1.0</TD>
+ <TD VALIGN="TOP">0x0002</TD>
+ <TD VALIGN="TOP">Print a file.</TD>
+</TR>
+<TR>
+ <TD VALIGN="TOP">Validate-Job</TD>
+ <TD VALIGN="TOP">1.0</TD>
+ <TD VALIGN="TOP">0x0004</TD>
+ <TD VALIGN="TOP">Validate job attributes.</TD>
+</TR>
+<TR>
+ <TD VALIGN="TOP">Create-Job</TD>
+ <TD VALIGN="TOP">1.1</TD>
+ <TD VALIGN="TOP">0x0005</TD>
+ <TD VALIGN="TOP">Create a print job.</TD>
+</TR>
+<TR>
+ <TD VALIGN="TOP">Send-Document</TD>
+ <TD VALIGN="TOP">1.1</TD>
+ <TD VALIGN="TOP">0x0006</TD>
+ <TD VALIGN="TOP">Send a file for a print job.</TD>
+</TR>
+<TR>
+ <TD VALIGN="TOP">Cancel-Job</TD>
+ <TD VALIGN="TOP">1.0</TD>
+ <TD VALIGN="TOP">0x0008</TD>
+ <TD VALIGN="TOP">Cancel a print job.</TD>
+</TR>
+<TR>
+ <TD VALIGN="TOP">Get-Job-Attributes</TD>
+ <TD VALIGN="TOP">1.0</TD>
+ <TD VALIGN="TOP">0x0009</TD>
+ <TD VALIGN="TOP">Get job attributes.</TD>
+</TR>
+<TR>
+ <TD VALIGN="TOP">Get-Jobs</TD>
+ <TD VALIGN="TOP">1.0</TD>
+ <TD VALIGN="TOP">0x000A</TD>
+ <TD VALIGN="TOP">Get all jobs.</TD>
+</TR>
+<TR>
+ <TD VALIGN="TOP">Get-Printer-Attributes</TD>
+ <TD VALIGN="TOP">1.0</TD>
+ <TD VALIGN="TOP">0x000B</TD>
+ <TD VALIGN="TOP">Get printer attributes.</TD>
+</TR>
+<TR>
+ <TD VALIGN="TOP">Hold-Job</TD>
+ <TD VALIGN="TOP">1.1</TD>
+ <TD VALIGN="TOP">0x000C</TD>
+ <TD VALIGN="TOP">Hold a job for printing.</TD>
+</TR>
+<TR>
+ <TD VALIGN="TOP">Release-Job</TD>
+ <TD VALIGN="TOP">1.1</TD>
+ <TD VALIGN="TOP">0x000D</TD>
+ <TD VALIGN="TOP">Release a job for printing.</TD>
+</TR>
+<TR>
+ <TD VALIGN="TOP">Pause-Printer</TD>
+ <TD VALIGN="TOP">1.0</TD>
+ <TD VALIGN="TOP">0x0010</TD>
+ <TD VALIGN="TOP">Pause printing on a printer.</TD>
+</TR>
+<TR>
+ <TD VALIGN="TOP">Resume-Printer</TD>
+ <TD VALIGN="TOP">1.0</TD>
+ <TD VALIGN="TOP">0x0011</TD>
+ <TD VALIGN="TOP">Resume printing on a printer.</TD>
+</TR>
+<TR>
+ <TD VALIGN="TOP">Purge-Jobs</TD>
+ <TD VALIGN="TOP">1.0</TD>
+ <TD VALIGN="TOP">0x0012</TD>
+ <TD VALIGN="TOP">Purge all jobs.</TD>
+</TR>
+<TR>
+ <TD VALIGN="TOP">Set-Job-Attributes</TD>
+ <TD VALIGN="TOP">1.1</TD>
+ <TD VALIGN="TOP">0x0014</TD>
+ <TD VALIGN="TOP">Set attributes for a pending or held job.</TD>
+</TR>
+<TR>
+ <TD VALIGN="TOP">CUPS-Get-Default</TD>
+ <TD VALIGN="TOP">1.0</TD>
+ <TD VALIGN="TOP">0x4001</TD>
+ <TD VALIGN="TOP">Get the default destination.</TD>
+</TR>
+<TR>
+ <TD VALIGN="TOP">CUPS-Get-Printers</TD>
+ <TD VALIGN="TOP">1.0</TD>
+ <TD VALIGN="TOP">0x4002</TD>
+ <TD VALIGN="TOP">Get all of the available printers.</TD>
+</TR>
+<TR>
+ <TD VALIGN="TOP">CUPS-Add-Printer</TD>
+ <TD VALIGN="TOP">1.0</TD>
+ <TD VALIGN="TOP">0x4003</TD>
+ <TD VALIGN="TOP">Add or modify a printer.</TD>
+</TR>
+<TR>
+ <TD VALIGN="TOP">CUPS-Delete-Printer</TD>
+ <TD VALIGN="TOP">1.0</TD>
+ <TD VALIGN="TOP">0x4004</TD>
+ <TD VALIGN="TOP">Delete a printer.</TD>
+</TR>
+<TR>
+ <TD VALIGN="TOP">CUPS-Get-Classes</TD>
+ <TD VALIGN="TOP">1.0</TD>
+ <TD VALIGN="TOP">0x4005</TD>
+ <TD VALIGN="TOP">Get all of the available printer classes.</TD>
+</TR>
+<TR>
+ <TD VALIGN="TOP">CUPS-Add-Class</TD>
+ <TD VALIGN="TOP">1.0</TD>
+ <TD VALIGN="TOP">0x4006</TD>
+ <TD VALIGN="TOP">Add or modify a printer class.</TD>
+</TR>
+<TR>
+ <TD VALIGN="TOP">CUPS-Delete-Class</TD>
+ <TD VALIGN="TOP">1.0</TD>
+ <TD VALIGN="TOP">0x4007</TD>
+ <TD VALIGN="TOP">Delete a printer class.</TD>
+</TR>
+<TR>
+ <TD VALIGN="TOP">CUPS-Accept-Jobs</TD>
+ <TD VALIGN="TOP">1.0</TD>
+ <TD VALIGN="TOP">0x4008</TD>
+ <TD VALIGN="TOP">Accept jobs on a printer or printer class.</TD>
+</TR>
+<TR>
+ <TD VALIGN="TOP">CUPS-Reject-Jobs</TD>
+ <TD VALIGN="TOP">1.0</TD>
+ <TD VALIGN="TOP">0x4009</TD>
+ <TD VALIGN="TOP">Reject jobs on a printer or printer class.</TD>
+</TR>
+<TR>
+ <TD VALIGN="TOP">CUPS-Set-Default</TD>
+ <TD VALIGN="TOP">1.0</TD>
+ <TD VALIGN="TOP">0x400A</TD>
+ <TD VALIGN="TOP">Set the default destination.</TD>
+</TR>
+<TR>
+ <TD VALIGN="TOP">CUPS-Get-Devices</TD>
+ <TD VALIGN="TOP">1.1</TD>
+ <TD VALIGN="TOP">0x400B</TD>
+ <TD VALIGN="TOP">Get all of the available devices.</TD>
+</TR>
+<TR>
+ <TD VALIGN="TOP">CUPS-Get-PPDs</TD>
+ <TD VALIGN="TOP">1.1</TD>
+ <TD VALIGN="TOP">0x400C</TD>
+ <TD VALIGN="TOP">Get all of the available PPDs.</TD>
+</TR>
+<TR>
+ <TD VALIGN="TOP">CUPS-Move-Job</TD>
+ <TD VALIGN="TOP">1.1</TD>
+ <TD VALIGN="TOP">0x400D</TD>
+ <TD VALIGN="TOP">Move a job to a different printer.</TD>
+</TR>
+</TABLE>
+</CENTER>
+
+<H1>Operations</H1>
+
+<P>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.
+
+<H2>Print-Job Operation</H2>
+
+<P>The Print-Job operation (0x0002) prints a file.
+
+<H3>Print-Job Request</H3>
+
+<P>The following groups of attributes are supplied as part of the
+Print-Job request:
+
+<P>Group 1: Operation Attributes
+
+<UL>
+
+ <P>Natural Language and Character Set:
+
+ <P>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1 of the IPP Model and
+ Semantics document.
+
+ <P>"printer-uri" (uri):
+
+ <P>The client MUST supply a URI for the specified printer.
+
+</UL>
+
+<P>Group 2: Job Template Attributes
+
+<UL>
+
+ <P>"job-billing" (text(MAX)):
+
+ <P><I>(CUPS 1.1 and higher)</I>
+
+ <P>The client OPTIONALLY supplies a billing string that is logged
+ with the page accounting information.
+
+ <P>"job-sheets" (1setof type3 keyword | name(MAX)):
+
+ <P><I>(CUPS 1.1 and higher)</I>
+
+ <P>The client OPTIONALLY supplies one or two banner pages that
+ are printed before and 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 "job-sheets-default" printer
+ object attribute is used.
+
+ <P><B>Note:</B> Standard IPP only allows specification of a single
+ job-sheets attribute value.
+
+ <P>"media" (1setof type3 keyword | name(MAX)):
+
+ <P>The client OPTIONALLY supplies one or more media attributes
+ specifying the size, type, source, and color of the output
+ media. If the client does not specify this attribute then the
+ value of the "media-default" printer object attribute is used.
+
+ <P><B>Note:</B> Standard IPP only allows specification of a single
+ media attribute value.
+
+ <P>Other Job Template Attributes
+
+</UL>
+
+<P>The Print-Job request is followed by a file to be printed.
+
+<H3>Print-Job Response</H3>
+
+<P>The following groups of attributes are send as part of the Print-Job
+Response:
+
+<P>Group 1: Operation Attributes
+
+<UL>
+
+ <P>Status Message:
+
+ <P>The standard response status message.
+
+ <P>Natural Language and Character Set:
+
+ <P>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2 of the IPP Model and
+ Semantics document.
+
+</UL>
+
+<P>Group 2: Job Attributes
+
+<UL>
+
+ <P>Standard Job Attributes
+
+</UL>
+
+<H2>Create-Job Operation</H2>
+
+<P>The Create-Job operation (0x0005) creates a new, empty print job.
+
+<H3>Create-Job Request</H3>
+
+<P>The following groups of attributes are supplied as part of the
+Create-Job request:
+
+<P>Group 1: Operation Attributes
+
+<UL>
+
+ <P>Natural Language and Character Set:
+
+ <P>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1 of the IPP Model and
+ Semantics document.
+
+ <P>"printer-uri" (uri):
+
+ <P>The client MUST supply a URI for the specified printer.
+
+</UL>
+
+<P>Group 2: Job Template Attributes
+
+<UL>
+
+ <P>"job-billing" (text(MAX)):
+
+ <P><I>(CUPS 1.1 and higher)</I>
+
+ <P>The client OPTIONALLY supplies a billing string that is logged
+ with the page accounting information.
+
+ <P>"job-sheets" (1setof type3 keyword | name(MAX)):
+
+ <P><I>(CUPS 1.1 and higher)</I>
+
+ <P>The client OPTIONALLY supplies one or two banner pages that
+ are printed before and 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 "job-sheets-default" printer
+ object attribute is used.
+
+ <P><B>Note:</B> Standard IPP only allows specification of a single
+ job-sheets attribute value.
+
+ <P>"media" (1setof type3 keyword | name(MAX)):
+
+ <P>The client OPTIONALLY supplies one or more media attributes
+ specifying the size, type, source, and color of the output
+ media. If the client does not specify this attribute then the
+ value of the "media-default" printer object attribute is used.
+
+ <P><B>Note:</B> Standard IPP only allows specification of a single
+ media attribute value.
+
+ <P>Standard Job Template Attributes
+
+</UL>
+
+<H3>Create-Job Response</H3>
+
+<P>The following groups of attributes are send as part of the
+Create-Job Response:
+
+<P>Group 1: Operation Attributes
+
+<UL>
+
+ <P>Status Message:
+
+ <P>The standard response status message.
+
+ <P>Natural Language and Character Set:
+
+ <P>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2 of the IPP Model and
+ Semantics document.
+
+</UL>
+
+<P>Group 2: Job Attributes
+
+<UL>
+
+ <P>Standard Job Attributes
+
+</UL>
+
+<H2>Set-Job-Attributes Operation</H2>
+
+<P>The Set-Job-Attributes operation (0x0014) changes the attributes of
+an active (not completed) job.
+
+<H3>Set-Job-Attributes Request</H3>
+
+<P>The following groups of attributes are supplied as part of the
+Set-Job-Attributes request:
+
+<P>Group 1: Operation Attributes
+
+<UL>
+
+ <P>Natural Language and Character Set:
+
+ <P>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1 of the IPP Model and
+ Semantics document.
+
+ <P>"printer-uri" (uri) and "job-id" (integer)
+ <P><I>OR</I>
+ <P>"job-uri":
+
+ <P>The client MUST supply a URI for the specified printer and
+ a job ID number, or the job URI.
+
+</UL>
+
+<P>Group 2: Job Template Attributes
+
+<UL>
+
+ <P>"job-sheets" (1setof type3 keyword | name(MAX)):
+
+ <P><I>(CUPS 1.1 and higher)</I>
+
+ <P>The client OPTIONALLY supplies one or two banner pages that
+ are printed before and 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 "job-sheets-default" printer
+ object attribute is used.
+
+ <P><B>Note:</B> Standard IPP only allows specification of a single
+ job-sheets attribute value.
+
+ <P>"media" (1setof type3 keyword | name(MAX)):
+
+ <P>The client OPTIONALLY supplies one or more media attributes
+ specifying the size, type, source, and color of the output
+ media. If the client does not specify this attribute then the
+ value of the "media-default" printer object attribute is used.
+
+ <P><B>Note:</B> Standard IPP only allows specification of a single
+ media attribute value.
+
+ <P>Other Job Template Attributes
+
+</UL>
+
+<H3>Set-Job-Attributes Response</H3>
+
+<P>The following groups of attributes are send as part of the Set-Job-Attributes
+Response:
+
+<P>Group 1: Operation Attributes
+
+<UL>
+
+ <P>Status Message:
+
+ <P>The standard response status message.
+
+ <P>Natural Language and Character Set:
+
+ <P>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2 of the IPP Model and
+ Semantics document.
+
+</UL>
+
+<H2>CUPS-Get-Default Operation</H2>
+
+<P>The CUPS-Get-Default operation (0x4001) returns the default printer
+URI and attributes.
+
+<H3>CUPS-Get-Default Request</H3>
+
+<P>The following groups of attributes are supplied as part of the
+CUPS-Get-Default request:
+
+<P>Group 1: Operation Attributes
+
+<UL>
+
+ <P>Natural Language and Character Set:
+
+ <P>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1 of the IPP Model and
+ Semantics document.
+
+ <P>"requested-attributes" (1setOf keyword) :
+
+ <P>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'.
+
+</UL>
+
+<H3>CUPS-Get-Default Response</H3>
+
+<P>The following groups of attributes are send as part of the
+CUPS-Get-Default Response:
+
+<P>Group 1: Operation Attributes
+
+<UL>
+
+ <P>Status Message:
+
+ <P>The standard response status message.
+
+ <P>Natural Language and Character Set:
+
+ <P>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2 of the IPP Model and
+ Semantics document.
+
+</UL>
+
+<P>Group 2: Printer Object Attributes
+
+<UL>
+
+ <P>The set of requested attributes and their current values.
+
+</UL>
+
+<H2>CUPS-Get-Printers Operation</H2>
+
+<P>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.
+
+<H3>CUPS-Get-Printers Request</H3>
+
+<P>The following groups of attributes are supplied as part of the
+CUPS-Get-Printers request:
+
+<P>Group 1: Operation Attributes
+
+<UL>
+
+ <P>Natural Language and Character Set:
+
+ <P>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1 of the IPP Model and
+ Semantics document.
+
+ <P>"limit" (integer (1:MAX)):
+
+ <P>The client OPTIONALLY supplies this attribute limiting the
+ number of printers that are returned.
+
+ <P>"printer-info" (text(127)):
+
+ <P><I>(CUPS 1.1 and higher)</I>
+
+ <P>The client OPTIONALLY supplies this attribute to
+ select which printers are returned.
+
+ <P>"printer-location" (text(127)):
+
+ <P><I>(CUPS 1.1 and higher)</I>
+
+ <P>The client OPTIONALLY supplies this attribute to
+ select which printers are returned.
+
+ <P>"printer-type" (type2 enum):
+
+ <P><I>(CUPS 1.1 and higher)</I>
+
+ <P>The client OPTIONALLY supplies a printer type enumeration to
+ select which printers are returned.
+
+ <P>"printer-type-mask" (type2 enum):
+
+ <P><I>(CUPS 1.1 and higher)</I>
+
+ <P>The client OPTIONALLY supplies a printer type mask
+ enumeration to select which bits are used in the "printer-type"
+ attribute.
+
+ <P>"requested-attributes" (1setOf keyword) :
+
+ <P>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'.
+
+</UL>
+
+<H3>CUPS-Get-Printers Response</H3>
+
+<P>The following groups of attributes are send as part of the
+CUPS-Get-Printers Response:
+
+<P>Group 1: Operation Attributes
+
+<UL>
+
+ <P>Status Message:
+
+ <P>The standard response status message.
+
+ <P>Natural Language and Character Set:
+
+ <P>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2 of the IPP Model and
+ Semantics document.
+
+</UL>
+
+<P>Group 2: Printer Object Attributes
+
+<UL>
+
+ <P>The set of requested attributes and their current values for
+ each printer.
+
+</UL>
+
+<H2>CUPS-Add-Printer Operation</H2>
+
+<P>The CUPS-Add-Printer operation (0x4003) adds a new printer or
+modifies an existing printer on the system.
+
+<H3>CUPS-Add-Printer Request</H3>
+
+<P>The following groups of attributes are supplied as part of the
+CUPS-Add-Printer request:
+
+<P>Group 1: Operation Attributes
+
+<UL>
+
+ <P>Natural Language and Character Set:
+
+ <P>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1 of the IPP Model and
+ Semantics document.
+
+ <P>"printer-uri" (uri):
+
+ <P>The client MUST supply a URI for the specified printer.
+
+</UL>
+
+<P>Group 2: Printer Object Attributes
+
+<UL>
+
+ <P>"banner-end-default" (name(127)):
+
+ <P><I>(CUPS 1.1 and higher)</I>
+
+ <P>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.
+
+ <P>"banner-start-default" (name(127)):
+
+ <P><I>(CUPS 1.1 and higher)</I>
+
+ <P>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.
+
+ <P>"device-uri" (uri):
+
+ <P>The client OPTIONALLY supplies a device URI for the
+ specified printer.
+
+ <P>"ppd-name" (name(127)):
+
+ <P>The client OPTIONALLY supplies a PPD name for the specified
+ printer.
+
+ <P>"printer-is-accepting-jobs" (boolean):
+
+ <P>The client OPTIONALLY supplies this boolean attribute
+ indicating whether or not the printer object should accept new jobs.
+
+ <P>"printer-info" (text(127)):
+
+ <P>The client OPTIONALLY supplies this attribute indicating the
+ printer information string.
+
+ <P>"printer-location" (text(127)):
+
+ <P>The client OPTIONALLY supplies this attribute indicating a
+ textual location of the printer.
+
+ <P>"printer-more-info" (uri):
+
+ <P>The client OPTIONALLY supplies this attribute indicating a
+ URI for additional printer information.
+
+ <P>"printer-state" (type2 enum):
+
+ <P>The client OPTIONALLY supplies this attribute indicating the
+ initial/current state of the printer. Only the "idle" and "stopped"
+ enumerations are recognized.
+
+ <P>"printer-state-message" (text(MAX)):
+
+ <P>The client OPTIONALLY supplies this attribute indicating a
+ textual reason for the current printer state.
+
+ <P>"requesting-user-name-allowed" (1setof name(127) | delete)
+ <P><I>OR</I>
+ <P>"requesting-user-name-denied" (1setof name(127) | delete):
+
+ <P>The client OPTIONALLY supplies one of these attributes to
+ specify an access control list for incoming print jobs. To allow
+ all users access to a printer, use the delete tag for the
+ attribute value.
+
+</UL>
+
+<P>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.
+
+<H3>CUPS-Add-Printer Response</H3>
+
+<P>The following groups of attributes are send as part of the
+CUPS-Add-Printer Response:
+
+<P>Group 1: Operation Attributes
+
+<UL>
+
+ <P>Status Message:
+
+ <P>The standard response status message.
+
+ <P>Natural Language and Character Set:
+
+ <P>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2 of the IPP Model and
+ Semantics document.
+
+</UL>
+
+<H2>CUPS-Delete-Printer Operation</H2>
+
+<P>The CUPS-Delete-Printer operation (0x4004) removes an existing
+printer from the system.
+
+<H3>CUPS-Delete-Printer Request</H3>
+
+<P>The following groups of attributes are supplied as part of the
+CUPS-Delete-Printer request:
+
+<P>Group 1: Operation Attributes
+
+<UL>
+
+ <P>Natural Language and Character Set:
+
+ <P>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1 of the IPP Model and
+ Semantics document.
+
+ <P>"printer-uri" (uri):
+
+ <P>The client MUST supply a URI for the specified printer.
+
+</UL>
+
+<H3>CUPS-Delete-Printer Response</H3>
+
+<P>The following groups of attributes are send as part of the
+CUPS-Delete-Printer Response:
+
+<P>Group 1: Operation Attributes
+
+<UL>
+
+ <P>Status Message:
+
+ <P>The standard response status message.
+
+ <P>Natural Language and Character Set:
+
+ <P>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2 of the IPP Model and
+ Semantics document.
+
+</UL>
+
+<H2>CUPS-Get-Classes Operation</H2>
+
+<P>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.
+
+<H3>CUPS-Get-Classes Request</H3>
+
+<P>The following groups of attributes are supplied as part of the
+CUPS-Get-Classes request:
+
+<P>Group 1: Operation Attributes
+
+<UL>
+
+ <P>Natural Language and Character Set:
+
+ <P>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1 of the IPP Model and
+ Semantics document.
+
+ <P>"limit" (integer (1:MAX)):
+
+ <P>The client OPTIONALLY supplies this attribute limiting the
+ number of printer classes that are returned.
+
+ <P>"printer-info" (text(127)):
+
+ <P><I>(CUPS 1.1 and higher)</I>
+
+ <P>The client OPTIONALLY supplies this attribute to
+ select which printer classes are returned.
+
+ <P>"printer-location" (text(127)):
+
+ <P><I>(CUPS 1.1 and higher)</I>
+
+ <P>The client OPTIONALLY supplies this attribute to
+ select which printer classes are returned.
+
+ <P>"printer-type" (type2 enum):
+
+ <P><I>(CUPS 1.1 and higher)</I>
+
+ <P>The client OPTIONALLY supplies a printer type enumeration to
+ select which printer classes are returned.
+
+ <P>"printer-type-mask" (type2 enum):
+
+ <P><I>(CUPS 1.1 and higher)</I>
+
+ <P>The client OPTIONALLY supplies a printer type mask
+ enumeration to select which bits are used in the "printer-type"
+ attribute.
+
+ <P>"requested-attributes" (1setOf keyword) :
+
+ <P>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'.
+
+</UL>
+
+<H3>CUPS-Get-Classes Response</H3>
+
+<P>The following groups of attributes are send as part of the
+CUPS-Get-Classes Response:
+
+<P>Group 1: Operation Attributes
+
+<UL>
+
+ <P>Status Message:
+
+ <P>The standard response status message.
+
+ <P>Natural Language and Character Set:
+
+ <P>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2 of the IPP Model and
+ Semantics document.
+
+</UL>
+
+<P>Group 2: Printer Class Object Attributes
+
+<UL>
+
+ <P>The set of requested attributes and their current values for
+ each printer class.
+
+</UL>
+
+<H2>CUPS-Add-Class Operation</H2>
+
+<P>The CUPS-Add-Class operation (0x4006) adds a new printer class or
+modifies and existing printer class on the system.
+
+<H3>CUPS-Add-Class Request</H3>
+
+<P>The following groups of attributes are supplied as part of the
+CUPS-Add-Class request:
+
+<P>Group 1: Operation Attributes
+
+<UL>
+
+ <P>Natural Language and Character Set:
+
+ <P>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1 of the IPP Model and
+ Semantics document.
+
+ <P>"printer-uri" (uri):
+
+ <P>The client MUST supply a URI for the specified printer class.
+
+</UL>
+
+<P>Group 2: Printer Object Attributes
+
+<UL>
+
+ <P>"member-uris" (1setof uri):
+
+ <P>The client OPTIONALLY supplies the "member-uris" set
+ specifying the printers and printer classes that are part of the class.
+
+ <P>"printer-is-accepting-jobs" (boolean):
+
+ <P>The client OPTIONALLY supplies this boolean attribute
+ indicating whether or not the class object should accept new jobs.
+
+ <P>"printer-info" (text(127)):
+
+ <P>The client OPTIONALLY supplies this attribute indicating the
+ printer information string.
+
+ <P>"printer-location" (text(127)):
+
+ <P>The client OPTIONALLY supplies this attribute indicating a
+ textual location of the class.
+
+ <P>"printer-more-info" (uri):
+
+ <P>The client OPTIONALLY supplies this attribute indicating a
+ URI for additional class information.
+
+ <P>"printer-state" (type2 enum):
+
+ <P>The client OPTIONALLY supplies this attribute indicating the
+ initial/current state of the class. Only the "idle" and "stopped"
+ enumerations are recognized.
+
+ <P>"printer-state-message" (text(MAX)):
+
+ <P>The client OPTIONALLY supplies this attribute indicating a
+ textual reason for the current class state.
+
+ <P>"requesting-user-name-allowed" (1setof name(127))
+ <P><I>OR</I>
+ <P>"requesting-user-name-denied" (1setof name(127)):
+
+ <P>The client OPTIONALLY supplies one of these attributes to
+ specify an access control list for incoming print jobs. To allow
+ all users access to a class, use the delete tag for the
+ attribute value.
+
+</UL>
+
+<H3>CUPS-Add-Class Response</H3>
+
+<P>The following groups of attributes are send as part of the CUPS-Add-Class Response:
+
+<P>Group 1: Operation Attributes
+
+<UL>
+
+ <P>Status Message:
+
+ <P>The standard response status message.
+
+ <P>Natural Language and Character Set:
+
+ <P>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2 of the IPP Model and
+ Semantics document.
+
+</UL>
+
+<H2>CUPS-Delete-Class Operation</H2>
+
+<P>The CUPS-Delete-Class operation (0x4007) removes an existing printer
+class from the system.
+
+<H3>CUPS-Delete-Class Request</H3>
+
+<P>The following groups of attributes are supplied as part of the
+CUPS-Delete-Class request:
+
+<P>Group 1: Operation Attributes
+
+<UL>
+
+ <P>Natural Language and Character Set:
+
+ <P>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1 of the IPP Model and
+ Semantics document.
+
+ <P>"printer-uri" (uri):
+
+ <P>The client MUST supply a URI for the specified printer class.
+
+</UL>
+
+<H3>CUPS-Delete-Class Response</H3>
+
+<P>The following groups of attributes are send as part of the
+CUPS-Delete-Class Response:
+
+<P>Group 1: Operation Attributes
+
+<UL>
+
+ <P>Status Message:
+
+ <P>The standard response status message.
+
+ <P>Natural Language and Character Set:
+
+ <P>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2 of the IPP Model and
+ Semantics document.
+
+</UL>
+
+<H2>CUPS-Accept-Jobs Operation</H2>
+
+<P>The CUPS-Accept-Jobs operation (0x4008) sets the
+"printer-is-accepting-jobs" attribute to true for the specified printer
+or printer class.
+
+<H3>CUPS-Accept-Jobs Request</H3>
+
+<P>The following groups of attributes are supplied as part of the
+CUPS-Accept-Jobs request:
+
+<P>Group 1: Operation Attributes
+
+<UL>
+
+ <P>Natural Language and Character Set:
+
+ <P>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1 of the IPP Model and
+ Semantics document.
+
+ <P>"printer-uri" (uri):
+
+ <P>The client MUST supply a URI for the specified printer or printer class.
+
+</UL>
+
+<H3>CUPS-Accept-Jobs Response</H3>
+
+<P>The following groups of attributes are send as part of the
+CUPS-Accept-Jobs Response:
+
+<P>Group 1: Operation Attributes
+
+<UL>
+
+ <P>Status Message:
+
+ <P>The standard response status message.
+
+ <P>Natural Language and Character Set:
+
+ <P>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2 of the IPP Model and
+ Semantics document.
+
+</UL>
+
+<H2>CUPS-Reject-Jobs Operation</H2>
+
+<P>The CUPS-Reject-Jobs operation (0x4009) sets
+the"printer-is-accepting-jobs" attribute to false for the specified
+printer or printer class.
+
+<H3>CUPS-Reject-Jobs Request</H3>
+
+<P>The following groups of attributes are supplied as part of the
+CUPS-Reject-Jobs request:
+
+<P>Group 1: Operation Attributes
+
+<UL>
+
+ <P>Natural Language and Character Set:
+
+ <P>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1 of the IPP Model and
+ Semantics document.
+
+ <P>"printer-uri" (uri):
+
+ <P>The client MUST supply a URI for the specified printer or printer class.
+
+</UL>
+
+<P>Group 2: Printer Object Attributes
+
+<UL>
+
+ <P>"printer-state-message" (text(MAX)):
+
+ <P>The client OPTIONALLY supplies this attribute indicating a
+ textual reason for the current printer state.
+
+</UL>
+
+<H3>CUPS-Reject-Jobs Response</H3>
+
+<P>The following groups of attributes are send as part of the
+CUPS-Reject-Jobs Response:
+
+<P>Group 1: Operation Attributes
+
+<UL>
+
+ <P>Status Message:
+
+ <P>The standard response status message.
+
+ <P>Natural Language and Character Set:
+
+ <P>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2 of the IPP Model and
+ Semantics document.
+
+</UL>
+
+<H2>CUPS-Set-Default Operation</H2>
+
+<P>The CUPS-Set-Default operation (0x400A) sets the default printer
+destination for all clients when a resource name of "/printers" is
+specified.
+
+<H3>CUPS-Set-Default Request</H3>
+
+<P>The following groups of attributes are supplied as part of the
+CUPS-Set-Default request:
+
+<P>Group 1: Operation Attributes
+
+<UL>
+
+ <P>Natural Language and Character Set:
+
+ <P>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1 of the IPP Model and
+ Semantics document.
+
+ <P>"printer-uri" (uri):
+
+ <P>The client MUST supply a URI for the specified printer or
+ printer class.
+
+</UL>
+
+<H3>CUPS-Set-Default Response</H3>
+
+<P>The following groups of attributes are send as part of the
+CUPS-Set-Default Response:
+
+<P>Group 1: Operation Attributes
+
+<UL>
+
+ <P>Status Message:
+
+ <P>The standard response status message.
+
+ <P>Natural Language and Character Set:
+
+ <P>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2 of the IPP Model and
+ Semantics document.
+
+</UL>
+
+<H2>CUPS-Get-Devices Operation</H2>
+
+<P>The CUPS-Get-Devices operation (0x400B) returns all of the supported
+device-uri's for the server (CUPS 1.1 and higher).
+
+<H3>CUPS-Get-Devices Request</H3>
+
+<P>The following groups of attributes are supplied as part of the
+CUPS-Get-Devices request:
+
+<P>Group 1: Operation Attributes
+
+<UL>
+
+ <P>Natural Language and Character Set:
+
+ <P>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1 of the IPP Model and
+ Semantics document.
+
+ <P>"device-class" (type1 keyword):
+
+ <P>The client OPTIONALLY supplies a device class keyword to select
+ which devices are returned.
+
+ <P>"limit" (integer (1:MAX)):
+
+ <P>The client OPTIONALLY supplies this attribute limiting the number of
+ devices that are returned.
+
+ <P>"requested-attributes" (1setOf keyword) :
+
+ <P>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'.
+
+</UL>
+
+<H3>CUPS-Get-Devices Response</H3>
+
+<P>The following groups of attributes are send as part of the
+CUPS-Get-Devices Response:
+
+<P>Group 1: Operation Attributes
+
+<UL>
+
+ <P>Status Message:
+
+ <P>The standard response status message.
+
+ <P>Natural Language and Character Set:
+
+ <P>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2 of the IPP Model and
+ Semantics document.
+
+</UL>
+
+<P>Group 2: Device Object Attributes
+
+<UL>
+
+ <P>The set of requested attributes and their current values for
+ each device.
+
+</UL>
+
+<H2>CUPS-Get-PPDs Operation</H2>
+
+<P>The CUPS-Get-PPDs operation (0x400C) returns all of the locally
+available PPD files on the system (CUPS 1.1 and higher).
+
+<H3>CUPS-Get-PPDs Request</H3>
+
+<P>The following groups of attributes are supplied as part of the
+CUPS-Get-PPDs request:
+
+<P>Group 1: Operation Attributes
+
+<UL>
+
+ <P>Natural Language and Character Set:
+
+ <P>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1 of the IPP Model and
+ Semantics document.
+
+ <P>"limit" (integer (1:MAX)):
+
+ <P>The client OPTIONALLY supplies this attribute limiting the number of
+ PPDs that are returned.
+
+ <P>"ppd-make" (text(127)):
+
+ <P>The client OPTIONALLY supplies a printer manufacturer to select
+ which PPDs are returned.
+
+ <P>"requested-attributes" (1setOf keyword) :
+
+ <P>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'.
+
+</UL>
+
+<H3>CUPS-Get-PPDs Response</H3>
+
+<P>The following groups of attributes are send as part of the
+CUPS-Get-PPDs Response:
+
+<P>Group 1: Operation Attributes
+
+<UL>
+
+ <P>Status Message:
+
+ <P>The standard response status message.
+
+ <P>Natural Language and Character Set:
+
+ <P>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2 of the IPP Model and
+ Semantics document.
+
+</UL>
+
+<P>Group 2: PPD Attributes
+
+<UL>
+
+ <P>The set of requested attributes and their current values for each
+ PPD file.
+
+</UL>
+
+<H2>CUPS-Move-Job Operation</H2>
+
+<P>The CUPS-Move-Job operation (0x400D) moves an active print job to a
+different printer (CUPS 1.1 and higher).
+
+<H3>CUPS-Move-Job Request</H3>
+
+<P>The following groups of attributes are supplied as part of the
+CUPS-Move-Job request:
+
+<P>Group 1: Operation Attributes
+
+<UL>
+
+ <P>Natural Language and Character Set:
+
+ <P>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1 of the IPP Model and
+ Semantics document.
+
+ <P>"printer-uri" (uri) and "job-id" (integer)
+ <P><I>OR</I>
+ <P>"job-uri":
+
+ <P>The client MUST supply a URI for the specified printer and
+ a job ID number, or the job URI.
+
+</UL>
+
+<P>Group 2: Job Template Attributes
+
+<UL>
+
+ <P>"job-printer-uri" (uri)
+
+ <P>The client MUST supply a URI for a printer on the same server.
+
+</UL>
+
+<H3>CUPS-Move-Job Response</H3>
+
+<P>The following groups of attributes are send as part of the
+CUPS-Move-Job Response:
+
+<P>Group 1: Operation Attributes
+
+<UL>
+
+ <P>Status Message:
+
+ <P>The standard response status message.
+
+ <P>Natural Language and Character Set:
+
+ <P>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2 of the IPP Model and
+ Semantics document.
+
+</UL>
+
+<H1>Attributes</H1>
+
+<P>CUPS provides many extension attributes to support multiple devices,
+PPD files, standard job filters, printers, and printer classes.
+
+<H2>Device Attributes</H2>
+
+<P>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.
+
+<H3>device-class (type2 keyword)</H3>
+
+<P>The device-class attribute specifies the class of device and can be
+one of the following:
+
+<UL>
+
+ <LI>"file" - a disk file.
+
+ <LI>"direct" - a parallel or fixed-rate serial data port,
+ currently used for Centronics, IEEE-1284, and USB printer
+ ports.
+
+ <LI>"serial" - a variable-rate serial port.
+
+ <LI>"network" - a network connection, typically via AppSocket,
+ HTTP, IPP, LPD, or SMB/CIFS protocols.
+
+</UL>
+
+<H3>device-info (text(127))</H3>
+
+<P>The device-info attribute specifies a human-readable string describing
+the device, e.g. "Parallel Port #1".
+
+<H3>device-make-and-model (text(127))</H3>
+
+<P>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".
+
+<H3>device-uri (uri)</H3>
+
+<P>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:
+
+<UL>
+
+ <LI>"file" - The device-uri will be of the form
+ "file:/path/to/filename".
+
+ <LI>"direct" - The device-uri will be of the form
+ "method:/dev/filename", where method may be "parallel" or "usb"
+ in the current implementation.
+
+ <LI>"serial" - The device-uri will be of the form
+ "serial:/dev/filename?baud=value+parity=value+flow=value".
+ The baud value is the data rate in bits per second; the
+ supported values depend on the underlying hardware.
+ The parity value can be one of "none", "even", or "odd".
+ The flow value can be one of "none", "soft" (XON/XOFF
+ handshaking), "hard" or "rts/cts" (RTS/CTS handshaking),
+ or "dtrdsr" (DTR/DSR handshaking).
+
+ <P>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").
+
+ <LI>"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.
+
+ <P>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.
+
+ <P>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.
+
+</UL>
+
+<H2>Job Template Attributes</H2>
+
+<H3>blackplot (boolean)</H3>
+
+<P>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.
+
+<H3>brightness (integer(0:200))</H3>
+
+<P>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.
+
+<P>Brightness is applied to the Cyan, Magenta, Yellow, and Black values using
+the function "f(x) = brightness / 100 * x".
+
+<H3>columns (integer(1:4))</H3>
+
+<P>The columns attribute specifies the number of columns to generate when
+printing text files. The default value is 1.
+
+<H3>cpi (type2 enum)</H3>
+
+<P>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.
+
+<H3>fitplot (boolean)</H3>
+
+<P>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.
+
+<H3>gamma (integer(1:10000))</H3>
+
+<P>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.
+
+<P>Gamma is applied to the Red, Green, and Blue values (or luminance for
+grayscale output) using the function "f(x) = x<SUP>(1000/gamma)</SUP>".
+
+<H3>hue (integer(-180:180))</H3>
+
+<P>The hue attribute specifies a color hue rotation when printing image
+files. The default value is 0.
+
+<H3>job-billing (text(MAX))</H3>
+
+<P><I>(CUPS 1.1 and higher)</I>
+
+<P>The job-billing attribute provides a text value to associate with a job
+for billing purposes.
+
+<H3>job-hold-until (keyword | name(MAX))</H3>
+
+<P><I>(CUPS 1.1 and higher)</I>
+
+<P>The job-hold-until attribute specifies a hold time. In addition to the
+standard IPP/1.1 keyword names, CUPS supports name values of the form
+"HH:MM" and "HH:MM:SS" that specify a hold time. The hold time is in
+Greenwich Mean Time (GMT) and <I>not</I> in the local time zone. If the
+specified time is less than the current time, the job is held until the
+next day.
+
+<H3>job-sheets (1setof type3 keyword | name(MAX))</H3>
+
+<P><I>(CUPS 1.1 and higher)</I>
+
+<P>The job-sheets attribute specifies one or two banner files that are printed
+before and after a job. The reserved value of "none" disables banner printing.
+The default value is stored in the job-sheets-default attribute.
+
+<P>If only one value is supplied, the banner file is printed before the job.
+If two values are supplied, the first value is used as the starting banner
+file and the second as the ending banner file.
+
+<H3>job-originating-host-name (name(MAX))</H3>
+
+<P><I>(CUPS 1.1.5 and higher)</I>
+
+<P>The job-originating-host-name attribute specifies the host
+from which the job was queued. The value will be the hostname or
+IP address of the client depending on whether hostname
+resolution is enabled. The localhost address (127.0.0.1) is
+<B>always</B> resolved to the name "localhost".
+
+<P>This attribute is read-only.
+
+<H3>lpi (type2 enum)</H3>
+
+<P>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.
+
+<H3>natural-scaling (integer(1:1000))</H3>
+
+<P><I>(CUPS 1.1.9 and higher)</I>
+
+<P>The natural-scaling attribute specifies the scaling of image files with
+respect to the natural image size. A value of 100 specifies that the image
+file should exactly the natural size, while 50 is half the natural size
+and 200 is twice the natural size. The default value is 100.
+
+<P>The ppi option can be used to override the natural resolution of the
+image, which controls the natural size.
+
+<H3>page-bottom (integer(0:MAX))</H3>
+
+<P>The page-bottom attribute specifies the bottom margin in points (72 points
+equals 1 inch). The default value is the device physical margin.
+
+<H3>page-label (text(MAX))</H3>
+
+<P><I>(CUPS 1.1.7 and higher)</I>
+
+<P>The page-label attribute provides a text value to place in
+the header and footer on each page. If a classification level is
+set on the server, then this classification is printed before
+the page label.
+
+<H3>page-left (integer(0:MAX))</H3>
+
+<P>The page-left attribute specifies the left margin in points (72 points
+equals 1 inch). The default value is the device physical margin.
+
+<H3>page-right (integer(0:MAX))</H3>
+
+<P>The page-right attribute specifies the right margin in points (72 points
+equals 1 inch). The default value is the device physical margin.
+
+<H3>page-set (type2 keyword)</H3>
+
+<P>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".
+
+<H3>page-top (integer(0:MAX))</H3>
+
+<P>The page-top attribute specifies the top margin in points (72 points
+equals 1 inch). The default value is the device physical margin.
+
+<H3>penwidth (integer(0:MAX))</H3>
+
+<P>The penwidth attribute specifies the default pen width in micrometers
+when printing HP-GL/2 plot files. The default value is 1000 (1 millimeter).
+
+<H3>position (type2 keyword)</H3>
+
+<P>The position attribute specifies the location of image files on the
+media. The following keyword values are recognized:
+
+<UL>
+
+ <LI><CODE>center</CODE> - Center the image on the page (default)
+
+ <LI><CODE>top</CODE> - Print the image centered at the top of the page
+
+ <LI><CODE>left</CODE> - Print the image centered on the left of page
+
+ <LI><CODE>right</CODE> - Print the image centered on the right of the page
+
+ <LI><CODE>top-left</CODE> - Print the image at the top left corner of
+ the page
+
+ <LI><CODE>top-right</CODE> - Print the image at the top right corner of
+ the page
+
+ <LI><CODE>bottom</CODE> - Print the image centered at the bottom of
+ the page
+
+ <LI><CODE>bottom-left</CODE> - Print the image at the bottom left
+ corner of the page
+
+ <LI><CODE>bottom-right</CODE> - Print the image at the bottom right
+ corner of the page
+
+</UL>
+
+<H3>ppi (integer(1:MAX))</H3>
+
+<P>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.
+
+<H3>prettyprint (boolean)</H3>
+
+<P>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.
+
+<H3>saturation (integer(0:200))</H3>
+
+<P>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.
+
+<H3>scaling (integer(1:1000))</H3>
+
+<P>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.
+
+<P>The scaling attribute overrides the ppi attribute if specified.
+
+<H3>wrap (boolean)</H3>
+
+<P>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.
+
+<H2>PPD Attributes</H2>
+
+<H3>ppd-natural-language (naturalLanguage)</H3>
+
+<P>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.
+
+<H3>ppd-make (text(127))</H3>
+
+<P>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.
+
+<H3>ppd-make-and-model (text(127))</H3>
+
+<P>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.
+
+<H3>ppd-name (name(255))</H3>
+
+<P>The ppd-name attribute specifies the PPD filename on the server
+relative to the model directory. The forward slash (/) is used to
+delineate directories.
+
+<H2>Printer Attributes</H2>
+
+<H3>job-k-limit (integer)</H3>
+
+<P><I>(CUPS 1.1 and higher)</I>
+
+<P>The job-k-limit attribute specifies the maximum number of kilobytes that
+may be printed by a user, including banner files. The default value of 0
+specifies that there is no limit.
+
+<H3>job-page-limit (integer)</H3>
+
+<P><I>(CUPS 1.1 and higher)</I>
+
+<P>The job-page-limit attribute specifies the maximum number of pages that
+may be printed by a user, including banner files. The default value of 0
+specifies that there is no limit.
+
+<H3>job-quota-period (integer)</H3>
+
+<P><I>(CUPS 1.1 and higher)</I>
+
+<P>The job-quota-period attribute specifies the time period used for quota
+calculations, in seconds. The default value of 0 specifies that the limits
+apply to all jobs that have been printed by a user that are still known to
+the system.
+
+<H3>job-sheets-supported (1setof type3 keyword | name(MAX))</H3>
+
+<P><I>(CUPS 1.1 and higher)</I>
+
+<P>The job-sheets-supported attribute specifies the available banner files.
+There will always be at least one banner file available called "none".
+
+<H3>printer-type (type2 enum)</H3>
+
+<P>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:
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Bit</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD VALIGN="TOP">0x00000001</TD>
+ <TD VALIGN="TOP">Is a printer class.</TD>
+</TR>
+<TR>
+ <TD VALIGN="TOP">0x00000002</TD>
+ <TD VALIGN="TOP">Is a remote destination.</TD>
+</TR>
+<TR>
+ <TD VALIGN="TOP">0x00000004</TD>
+ <TD VALIGN="TOP">Can print in black.</TD>
+</TR>
+<TR>
+ <TD VALIGN="TOP">0x00000008</TD>
+ <TD VALIGN="TOP">Can print in color.</TD>
+</TR>
+<TR>
+ <TD VALIGN="TOP">0x00000010</TD>
+ <TD VALIGN="TOP">Can print on both sides of the page in hardware.</TD>
+</TR>
+<TR>
+ <TD VALIGN="TOP">0x00000020</TD>
+ <TD VALIGN="TOP">Can staple output.</TD>
+</TR>
+<TR>
+ <TD VALIGN="TOP">0x00000040</TD>
+ <TD VALIGN="TOP">Can do fast copies in hardware.</TD>
+</TR>
+<TR>
+ <TD VALIGN="TOP">0x00000080</TD>
+ <TD VALIGN="TOP">Can do fast copy collation in hardware.</TD>
+</TR>
+<TR>
+ <TD VALIGN="TOP">0x00000100</TD>
+ <TD VALIGN="TOP">Can punch output.</TD>
+</TR>
+<TR>
+ <TD VALIGN="TOP">0x00000200</TD>
+ <TD VALIGN="TOP">Can cover output.</TD>
+</TR>
+<TR>
+ <TD VALIGN="TOP">0x00000400</TD>
+ <TD VALIGN="TOP">Can bind output.</TD>
+</TR>
+<TR>
+ <TD VALIGN="TOP">0x00000800</TD>
+ <TD VALIGN="TOP">Can sort output.</TD>
+</TR>
+<TR>
+ <TD VALIGN="TOP">0x00001000</TD>
+ <TD VALIGN="TOP">Can handle media up to US-Legal/A4.</TD>
+</TR>
+<TR>
+ <TD VALIGN="TOP">0x00002000</TD>
+ <TD VALIGN="TOP">Can handle media from US-Legal/A4 to ISO-C/A2.</TD>
+</TR>
+<TR>
+ <TD VALIGN="TOP">0x00004000</TD>
+ <TD VALIGN="TOP">Can handle media larger than ISO-C/A2.</TD>
+</TR>
+<TR>
+ <TD VALIGN="TOP">0x00008000</TD>
+ <TD VALIGN="TOP">Can handle user-defined media sizes.</TD>
+</TR>
+<TR>
+ <TD VALIGN="TOP">0x00010000</TD>
+ <TD VALIGN="TOP">Is an implicit (server-generated) class.</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>printer-type-mask (type2 enum)</H3>
+
+<P><I>(CUPS 1.1 and higher)</I>
+
+<P>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.
+
+<H3>requesting-user-name-allowed (1setof name(127))</H3>
+
+<P><I>(CUPS 1.1 and higher)</I>
+
+<P>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.
+
+<H3>requesting-user-name-denied (1setof name(127))</H3>
+
+<P><I>(CUPS 1.1 and higher)</I>
+
+<P>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.
+
+<H2>Printer Class Attributes</H2>
+
+<H3>member-names (1setof name(127))</H3>
+
+<P>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.
+
+<H3>member-uris (1setof uri)</H3>
+
+<P>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.
+
+<EMBED SRC="glossary.shtml">
+
+</BODY>
+</HTML>
diff --git a/doc/overview.html b/doc/overview.html
new file mode 100644
index 000000000..67dc1d8ff
--- /dev/null
+++ b/doc/overview.html
@@ -0,0 +1,500 @@
+<HTML>
+<HEAD>
+ <META NAME="Author" CONTENT="Michael Sweet">
+ <TITLE>An Overview of the Common UNIX Printing System</TITLE>
+ <LINK REL=STYLESHEET TYPE="text/css" HREF="cupsdoc.css">
+</HEAD>
+<BODY>
+<TABLE WIDTH="100%">
+<TR VALIGN=TOP>
+ <TD><IMG SRC="images/cups-large.gif" WIDTH="103" HEIGHT="120"></TD>
+ <TD><H1 ALIGN="RIGHT">An Overview of the<BR>
+ Common UNIX Printing System,<BR>
+ Version 1.1</H1>
+
+ <P ALIGN="RIGHT">July 10, 2000<BR>
+ Michael Sweet, Easy Software Products<BR>
+ Copyright 1998-2002, All Rights Reserved.</P>
+ </TD>
+</TR>
+</TABLE>
+
+<P>This whitepaper describes the Common UNIX Printing
+System<SUP>TM</SUP> ("CUPS<SUP>TM</SUP>"), a portable and extensible
+printing system for UNIX<SUP>&reg;</SUP>. CUPS is being developed by
+<A HREF="http://www.easysw.com">Easy Software Products</A>, a software
+firm located in Hollywood, Maryland that has been selling commercial
+software for UNIX since 1993 through more than 40 distributors serving
+over 80 countries worldwide.
+
+<P>Additional information on CUPS is available on the World Wide Web at
+"<A HREF="http://www.cups.org">http://www.cups.org</A>".
+
+<H2>Background</H2>
+
+<P>Printing within UNIX has historically been done using one of two
+printing systems - the Berkeley Line Printer Daemon ("LPD") [RFC1179]
+and the AT&amp;T Line Printer system. These printing systems were
+designed in the 70's for printing text to line printers; vendors have
+since added varying levels of support for other types of printers.
+
+<P>Replacements for these printing systems have emerged [LPRng,
+Palladin, PLP], however none of the replacements change the fundamental
+capabilities of these systems.
+
+<P>Over the last few years several attempts at developing a standard
+printing interface have been made, including the draft POSIX Printing
+standard developed by the Institute of Electrical and Electronics
+Engineers, Inc. ("IEEE") [IEEE-1387.4] and Internet Printing Protocol
+("IPP") developed by the Internet Engineering Task Force ("IETF")
+through the Printer Working Group ("PWG") [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, but has been
+shelved by the IEEE.
+
+<P>The Internet Printing Protocol defines extensions to the HyperText
+Transport Protocol 1.1 [RFC2616] to provide support for remote printing
+services. IPP/1.0 was accepted by the IETF as an experimental Request
+For Comments [RFC] document in October of 1999. Since then the Printer
+Working Group has developed an updated set of specifications for
+IPP/1.1 which have been accepted by the IETF and are awaiting
+publication as proposed standards. Unlike POSIX Printing, IPP enjoys
+widespread industry support and is poised to become the standard
+network printing solution for all operating systems.
+
+<P>CUPS uses IPP/1.1 to provide a complete, modern printing system for
+UNIX that can be extended to support new printers, devices, and
+protocols while providing compatibility with existing UNIX
+applications. CUPS is free software provided under the terms of the
+GNU General Public License and GNU Library General Public License.
+
+<H2>History</H2>
+
+<P>The first production release of CUPS (based on IPP/1.0) was released
+in October of 1999. Since then, we have released several patch updates
+to the original CUPS 1.0 release that addressed security, portability,
+and bugs found, but no new functionality was added to improve the
+stability of the CUPS code.
+
+<P>CUPS 1.1 is based on IPP/1.1 and adds many of the functional
+enhancements that have been requested by our users. As with 1.0, CUPS
+1.1 will be followed by patch releases that address any problems found
+with the software but add no new features.
+
+<H2>Design Overview</H2>
+
+<P>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.
+
+<CENTER><IMG SRC="images/cups-block-diagram.gif" WIDTH="470" HEIGHT="170"></CENTER>
+<P ALIGN="CENTER">Figure 1 - CUPS Block Diagram</P>
+
+<H3>Scheduler</H3>
+
+<P>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,
+status monitoring, and administration.
+
+<P>The scheduler also manages a list of available printers on the LAN
+and dispatches print jobs as needed using the appropriate filters and
+backends.
+
+<H3>Configuration Files</H3>
+
+The configuration files consist of:
+
+<UL>
+
+ <LI>The HTTP server configuration file.
+
+ <LI>Printer and class definition files.
+
+ <LI>MIME type and conversion rule files.
+
+ <LI>PostScript Printer Description ("PPD") files.
+
+</UL>
+
+<P>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.
+
+<P>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.
+
+<P>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 <I>Content-Type</I> field for <I>GET</I> and <I>HEAD</I>
+requests and by the IPP request handler to determine the file type
+when a <I>Print-Job</I> or <I>Send-File</I> request is received with a
+<I>document-format</I> of <I>application/octet-stream</I>.
+
+<P>The MIME conversion rule files list the available filters. 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".
+
+<P>The PPD files describe the capabilities of all printers, not just
+PostScript printers. There is one PPD file for each printer. PPD files
+for non-PostScript printers define additional filters through
+<I>cupsFilter</I> attributes to support printer drivers.
+
+<H3>CUPS API</H3>
+
+<P>The CUPS API contains CUPS-specific convenience functions for queuing
+print jobs, getting printer information, accessing resources via HTTP
+and IPP, and manipulating PPD files. Unlike the rest of CUPS, the CUPS
+API is provided under the terms of the GNU LGPL so it may be used by
+non-GPL applications.
+
+<H3>Berkeley and System V Commands</H3>
+
+<P>CUPS provides the System V and Berkeley command-line interfaces for
+submitting jobs and checking the printer status. The
+<CODE>lpstat</CODE> and <CODE>lpc status</CODE> commands also show
+network printers ("printer@server") when printer browsing is enabled.
+
+<P>The System V administation commands are supplied for managing
+printers and classes. The Berkeley printer administration tool
+(<CODE>lpc</CODE>) is only supported in a "read-only" mode to check the
+current status of the printer queues and scheduler.
+
+<H3>Filters</H3>
+
+<P>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.
+
+<P>Filters are provided for many file formats and include image file
+and PostScript raster filters that support non-PostScript printers. Multiple
+filters are run in parallel to produce the required output format.
+
+<P>The PostScript raster filter is based on the GNU Ghostscript 5.50
+core. Instead of using the Ghostscript printer drivers and front-end,
+the CUPS filter uses a generic raster printer driver and CUPS-compliant
+front-end to support any kind of raster printer. This allows the same
+printer driver filter to be used for printing raster data from any
+filter.
+
+<H3>CUPS Imaging</H3>
+
+<P>The CUPS Imaging library provides functions for managing large
+images, doing colorspace conversion and color management, scaling
+images for printing, and managing raster page streams. It is used by
+the CUPS image file filters, the PostScript RIP, and all raster
+printers drivers.
+
+<H3>Backends</H3>
+
+<P>A backend program is a special filter that sends print data to a
+device or network connection. Backends for parallel, serial, USB, LPD, IPP,
+and AppSocket (JetDirect) connections are provided in CUPS 1.1.
+
+<P>SAMBA version 2.0.6 and higher includes a SMB backend
+(<CODE>smbspool(1)</CODE>) that can be used with CUPS 1.0 or 1.1 for
+printing to Windows.
+
+<H2>Network Printing</H2>
+
+<P>Traditionally, network printing has been one of the hardest things to
+get working under UNIX. One reason is because each vendor added their
+own extensions to the LPD protocol (the previous standard for network
+printing), making cross-platform printing difficult if not impossible.
+
+<P>Another reason is that you have to administer every network printer
+on every client machine. In some cases you can "clone" the printer
+configuration from a "master" client to each of the others, but even
+that can be time-consuming and error-prone. Something better is needed.
+
+<P>CUPS provides "printer browsing", which allows clients to
+automatically see and use printers from any server on a LAN. This means
+that you only need to configure the server and the clients will
+automatically see the printers and classes on it.
+
+<P>In addition, CUPS can automatically merge multiple identical network
+printers into "implicit classes". This allows clients to send jobs to
+the implicit class and have them print on the first available printer
+or server. In addition, failsafe and load-balancing functions are
+enabled simply by defining the same printer on multiple servers!
+
+<H2>New Features in CUPS 1.1</H2>
+
+<P>CUPS 1.1 includes many new features and capabilities:
+
+<OL>
+
+ <LI><A HREF="#BACKENDS">Backends</A>
+
+ <LI><A HREF="#BANNERS">Banner Page Support</A>
+
+ <LI><A HREF="#DIGEST">Digest Authentication</A>
+
+ <LI><A HREF="#DIRSVC">Directory Services</A>
+
+ <LI><A HREF="#FHS2">Directory Structure Changes</A>
+
+ <LI><A HREF="#DOCOS">Documentation</A>
+
+ <LI><A HREF="#DRIVERS">Drivers</A>
+
+ <LI><A HREF="#FILTERS">Filters</A>
+
+ <LI><A HREF="#IPP">IPP Support</A>
+
+ <LI><A HREF="#PERSISTENCE">Job Persistence</A>
+
+ <LI><A HREF="#LPD">LPD Client Support</A>
+
+ <LI><A HREF="#USEROPTS">User-Defined Printers and Options</A>
+
+ <LI><A HREF="#WEB">Web Administration Interface</A>
+
+</OL>
+
+<H3><A NAME="BACKENDS">1. Backends</A></H3>
+
+<P>CUPS 1.1 implements a new backend interface for retrieving a list of
+available devices for CUPS clients. This allows administration
+interfaces to query the CUPS scheduler for a list of available devices,
+automatically configure printers if the device identification
+information is available, and present the user with a list of available
+devices rather than relying on the user to know what devices are
+configured on the system.
+
+<P>The new release also includes a backend for USB printers under
+*BSD and Linux. Support for USB under Solaris 8 will be provided in
+a subsequent patch release.
+
+<H3><A NAME="BANNERS">2. Banner Page Support</A></H3>
+
+<P>CUPS 1.1 includes support for banner pages at the beginning and end
+of a job. Banner pages may be of any file format and support variable
+substitution for job titles, usernames, etc. Default banner pages are
+associated with each printer and can be overridden with command-line
+options by the user.
+
+<H3><A NAME="DIGEST">3. Digest Authentication</A></H3>
+
+<P>Digest authentication provides a more secure method of authenticating
+access to the printing system. Unlike Basic authentication, Digest
+authentication does not send passwords "in the clear" so it is more
+difficult to gain unauthorized access to your system.
+
+<P>CUPS 1.1 implements Digest authentication using a special MD5
+password file instead of the UNIX password file. This file is managed
+using the new <CODE>lppasswd</CODE> command.
+
+<H3><A NAME="DIRSVC">4. Directory Services</A></H3>
+
+<P>CUPS 1.1 adds new directory service ("printer browsing") features to
+make using CUPS on large LANs and WANs easier. You can now poll a
+remote server for printer information and relay it to the LAN as well
+as restrict what printer information is processed (e.g. to "hide"
+servers, domains, or networks that you don't want to see.)
+
+<H3><A NAME="FHS2">5. Directory Structure Changes</A></H3>
+
+<P>CUPS 1.1 now uses a directory structure that complies with the
+Filesystem Hierarchy Standard ("FHS"), version 2.0. This should make
+integration into existing Linux and *BSD distributions a lot easier.
+
+<H3><A NAME="DOCOS">6. Documentation</A></H3>
+
+<P>The CUPS 1.1 documentation has gone through many revisions,
+including a completely rewritten administrators manual, a new
+programmers manual, and an IPP implementation reference manual.
+
+<H3><A NAME="DRIVERS">7. Drivers</A></H3>
+
+<P>CUPS 1.1 includes drivers for EPSON dot-matrix and inkjet printers.
+As with the HP PCL drivers, the EPSON drivers don't necessarily provide
+the best possible output for each printer but should provide adequate
+printing quality for general day-to-day printing.
+
+<H3><A NAME="FILTERS">8. Filters</A></H3>
+
+<P>CUPS 1.1 includes new image, PostScript, PDF, and text filters. The image
+filters have been upgraded to support Windows BMP and Alias PIX files.
+
+<P>The PostScript filter is now based off GNU Ghostscript 5.50. The new
+filter provides much better performance with higher-resolution printers
+and supports most Level 3 PostScript language features.
+
+<P>The new PDF filter is based off the excellent Xpdf software from
+Derek Noonburg and supports automatic page scaling. The new filter is a
+faster, smaller, more reliable replacement for the GNU Ghostscript PDF
+filtering that was used in CUPS 1.0.
+
+<P>The new text filter now supports bidirectional text and can embed
+fonts as needed.
+
+<H3><A NAME="IPP">9. IPP Support</A></H3>
+
+<P>Probably the least visible portion of CUPS is the IPP support. CUPS
+1.1 implements all of the required IPP/1.1 operations and attributes
+and most of the optional ones. The optional Create-Job and Send-File
+operations are now implemented, allowing for better System V printing
+system compatibility (one job ID per <CODE>lp</CODE> command) and
+support for banner pages.
+
+<H3><A NAME="PERSISTENCE">10. Job Persistence</A></H3>
+
+<P>CUPS 1.1 supports job persistence. This means that jobs are preserved
+even after a reboot, a feature that was sorely missing from CUPS 1.0.
+
+<P>In addition, CUPS 1.1 allows you to keep job information after the
+job has printed. The basic post-job persistence mode provides a job
+history (number of pages printed, time job was printed, etc.) but does
+not preserve the actual job files. This can be changed to discard all
+information after a job is printed or keep the job files after printing
+so you can reprint a job at some later time.
+
+<H3><A NAME="LPD">11. LPD Client Support</A></H3>
+
+<P>By popular request, CUPS 1.1 supports LPD-based clients using a new
+mini-daemon that handles LPD requests and passes them on to the main
+server.
+
+<H3><A NAME="USEROPTS">12. User-Defined Printers and Options</A></H3>
+
+<P>CUPS 1.1 includes support for user-defined printers and options via
+a new <CODE>lpoptions</CODE> command. User-defined printers are special
+instances of the available printers (e.g. "printer/instance" or
+"printer@server/instance") that can have their own default options such
+as media size, resolution, and so forth. The <CODE>lpoptions</CODE>
+command can also be used to set a different default printer queue.
+
+<H3><A NAME="WEB">13. Web Administration Interface</A></H3>
+
+<P>CUPS 1.0 provided a simple class, job, and printer monitoring
+interface for web browsers. CUPS 1.1 replaces this interface with an
+enhanced administration interface that allows you to add, modify,
+delete, configure, and control classes, jobs, and printers.
+
+<H2>Software Using CUPS</H2>
+
+<P>A lot has happened since CUPS 1.0 came out, and many software packages
+are supporting CUPS. We have contributed code to the SAMBA team to support
+CUPS, and parts of that are already available in SAMBA 2.0.6 and 2.0.7.
+With any luck the final pieces that provide a complete integration with
+SAMBA will be available in the next release of SAMBA.
+
+<P>Two graphical interfaces have appeared on the scene that use CUPS as
+well. The KUPS project provides a KDE-based interface for CUPS and can be
+found at:
+
+<UL><PRE>
+<A HREF="http://kups.sourceforge.net">http://kups.sourceforge.net</A>
+</PRE></UL>
+
+<P>The X Printing Panel ("XPP") project provides a graphical printing
+panel for CUPS and can be found at:
+
+<UL><PRE>
+<A HREF="http://www.phy.uni-bayreuth.de/till/xpp">http://www.phy.uni-bayreuth.de/till/xpp/</A>
+</PRE></UL>
+
+<P>Numerous other filters, drivers, tutorials, etc. have been made available
+on the CUPS bazaar, available at:
+
+<UL><PRE>
+<A HREF="http://www.cups.org/bazaar.cgi">http://www.cups.org/bazaar.cgi</A>
+</PRE></UL>
+
+<P>Finally, our own ESP Print Pro software uses CUPS to provide drivers
+for thousands of printers and can be found at:
+
+<UL><PRE>
+<A HREF="http://www.easysw.com/printpro">http://www.easysw.com/printpro</A>
+</PRE></UL>
+
+<H2>Operating Systems Using CUPS</H2>
+
+<P>One of our goals has always been to get as many UNIX/Linux
+distributions using CUPS as possible. Debian is currently providing
+CUPS as part of its stable distribution, and many other distributions
+are considering it in their next releases.
+
+<H2>Summary</H2>
+
+<P>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. CUPS 1.1
+adds many new features that make it an even better choice for printing
+under UNIX.
+
+<H2>Who to Contact</H2>
+
+<P>For more information on CUPS please contact us at:
+
+<UL><PRE>
+Attn: CUPS Information
+Easy Software Products
+44141 Airport View Drive Suite 204
+Hollywood, Maryland 20636-3111 USA
+
++1.301.373.9600
+
+<A HREF="mailto:cups-info@cups.org">cups-info@cups.org</A>
+</PRE></UL>
+
+<H2>References</H2>
+
+<DL>
+
+ <DT>IEEE-1387.4</DT>
+
+ <DD>System Administration - Part 4: Printing Interfaces (draft)</DD>
+
+ <DT><A HREF="http://www.pwg.org/ipp/index.html">IETF-IPP</A></DT>
+
+ <DD>Internet Printing Protocol/1.1</DD>
+
+ <DT><A HREF="http://www.astart.com/lprng.html">LPRng</A></DT>
+
+ <DD>An enhanced, extended, and portable implementation of the
+ Berkeley LPR print spooler functionality</DD>
+
+ <DT>Palladin</DT>
+
+ <DD>A printing system developed at the Massachussetts Institute
+ of Technology</DD>
+
+ <DT><A HREF="http://www-usa.iona.com//hyplan/jmason/plp.html">PLP</A></DT>
+
+ <DD>The Portable Line Printer spooler system</DD>
+
+ <DT><A HREF="http://www.ietf.org/rfc/rfc1179.txt">RFC1179</A></DT>
+
+ <DD>Line Printer Daemon Protocol</DD>
+
+ <DT><A HREF="http://www.ietf.org/rfc/rfc2046.txt">RFC2046</A></DT>
+
+ <DD>Multipurpose Internet Mail Extensions (MIME) Part Two: Media Types</DD>
+
+ <DT><A HREF="http://www.ietf.org/rfc/rfc2616.txt">RFC2616</A></DT>
+
+ <DD>Hypertext Transfer Protocol -- HTTP/1.1</DD>
+
+</DL>
+
+<H2>Trademarks</H2>
+
+<P>The Common UNIX Printing System, CUPS, and the CUPS logo are the
+trademark property of Easy Software Products. All other trademarks are
+the property of their respective owners.
+
+</BODY>
+</HTML>
diff --git a/doc/overview.pdf b/doc/overview.pdf
new file mode 100644
index 000000000..f698e37eb
--- /dev/null
+++ b/doc/overview.pdf
Binary files differ
diff --git a/doc/printing-overview.shtml b/doc/printing-overview.shtml
new file mode 100644
index 000000000..1682dae7f
--- /dev/null
+++ b/doc/printing-overview.shtml
@@ -0,0 +1,125 @@
+<H1 ALIGN="RIGHT"><A NAME="OVERVIEW">1 - Printing System Overview</A></H1>
+
+<P>This chapter provides an overview of how the Common UNIX Printing System
+works.
+
+<H2>The Printing Problem</H2>
+
+<P>For years <I>the printing problem</I> has plagued UNIX. Unlike
+Microsoft&reg; Windows&reg; or Mac OS, UNIX has no standard interface or
+system in place for supporting printers. Among the solutions currently
+available, the Berkeley and System V printing systems are the most
+prevalent.
+
+<P>These printing systems support line printers (text only) or
+PostScript printers (text and graphics), and with some coaxing they can
+be made to support a full range of printers and file formats. However,
+because each varient of the UNIX operating system uses a different
+printing system than the next developing printer drivers for a wide
+range of printers and operating systems is extremely difficult. That
+combined with the limited volume of customers for each UNIX varient has
+forced most printer vendors to give up supporting UNIX entirely.
+
+<P>CUPS is designed to eliminate <I>the printing problem</I>. 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.
+
+<H2>The Technology</H2>
+
+<P>CUPS is based upon an emerging Internet standard called the Internet
+Printing Protocol. IPP has been embraced by dozens of printer and
+printer server manufacturers and is supported by Microsoft Windows
+2000.
+
+<P>IPP defines a standard protocol for printing as well as managing
+print jobs and printer options like media size, resolution, and so
+forth. Like all IP-based protocols, IPP can be used locally or over the
+Internet to printers hundreds or thousands of miles away. Unlike other
+protocols, however, IPP also supports access control, authentication,
+and encryption, making it a much more capable and secure printing
+solution than older ones.
+
+<P>IPP is layered on top of the Hyper-Text Transport Protocol ("HTTP")
+which is the basis of web servers on the Internet. This allows users
+to view documentation, check status information on a printer or server,
+and manage their printers, classes, and jobs using their web browser.
+
+<P>CUPS provides a complete IPP/1.1 based printing system that provides
+Basic, Digest, and local certificate authentication and user, domain,
+or IP-based access control. TLS encryption will be available in future
+versions of CUPS.
+
+<H2>Jobs</H2>
+
+<P>Each file or set of files that is submitted for printing is called a
+<I>job</I>. 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.
+
+<H2>Classes</H2>
+
+<P>CUPS supports collections of printers known as <I>classes</I>. Jobs
+sent to a class are forwarded to the first available printer in the
+class.
+
+<H2>Filters</H2>
+
+<P>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.
+
+<P>CUPS provides filters for printing many types of image files,
+HP-GL/2 files, PDF files, and text files. CUPS also supplies PostScript
+and image file Raster Image Processor ("RIP") filters that convert
+PostScript or image files into bitmaps that can be sent to a raster
+printer.
+
+<H2>Backends</H2>
+
+<P>Backends perform the most important task of all - they send the
+filtered print data to the printer.
+
+<P>CUPS provides backends for printing over parallel, serial, and USB
+ports, and over the network via the IPP, JetDirect (AppSocket), and
+Line Printer Daemon ("LPD") protocols. Additional backends are
+available in network service packages such as the SMB backend
+included with the popular SAMBA software.
+
+<P>Backends are also used to determine the available devices. On
+startup each backend is asked for a list of devices it supports,
+and any information that is available. This allows the parallel
+backend to tell CUPS that an EPSON Stylus Color 600 printer is
+attached to parallel port 1, for example.
+
+<H2>Printer Drivers</H2>
+
+<P>Printer drivers in CUPS consist of one of more filters specific to a
+printer. CUPS includes sample printer drivers for Hewlett-Packard
+LaserJet and DeskJet printers and EPSON 9-pin, 24-pin, Stylus Color,
+and Stylus Photo printers. While these drivers do not generate optimal
+output for the different printer models, they do provide basic printing
+and demonstrate how you can write your own printer drivers and
+incorporate them into CUPS.
+
+<H2>Networking</H2>
+
+<P>Printers and classes on the local system are automatically shared
+with other systems on the network. This allows you to setup one system
+to print to a printer and use this system as a printer server or spool
+host for all of the others. Users may then select a local printer by
+name or a remote printer using "name@server".
+
+<P>CUPS also provides <I>implicit classes</I>, which are collections of
+printers and/or classes with the same name. This allows you to setup
+multiple servers pointing to the same physical network printer, for
+example, so that you aren't relying on a single system for printing.
+Because this also works with printer classes, you can setup multiple
+servers and printers and never worry about a single point of failure
+unless all of the printers and servers go down!
diff --git a/doc/references.shtml b/doc/references.shtml
new file mode 100644
index 000000000..4b4930e57
--- /dev/null
+++ b/doc/references.shtml
@@ -0,0 +1,42 @@
+<H1>References</H1>
+
+<H2>CUPS Documentation</H2>
+
+<P>The following CUPS documentation is referenced by this document:
+
+<UL>
+ <LI>CUPS-CMP-1.1: CUPS Configuration Management Plan
+ <LI>CUPS-IDD-1.1: CUPS System Interface Design Description
+ <LI>CUPS-IPP-1.1: CUPS Implementation of IPP
+ <LI>CUPS-SAM-1.1.x: CUPS Software Administrators Manual
+ <LI>CUPS-SDD-1.1: CUPS Software Design Description
+ <LI>CUPS-SPM-1.1.x: CUPS Software Programming Manual
+ <LI>CUPS-SSR-1.1: CUPS Software Security Report
+ <LI>CUPS-STP-1.1: CUPS Software Test Plan
+ <LI>CUPS-SUM-1.1.x: CUPS Software Users Manual
+ <LI>CUPS-SVD-1.1: CUPS Software Version Description
+</UL>
+
+<H2>Other Documents</H2>
+
+<P>The following non-CUPS documents are referenced by this document:
+
+<UL>
+ <LI><A HREF="http://partners.adobe.com/asn/developer/PDFS/TN/5003.PPD_Spec_v4.3.pdf">Adobe
+ PostScript Printer Description File Format Specification,
+ Version 4.3.</A>
+ <LI><A HREF="http://partners.adobe.com/asn/developer/PDFS/TN/PLRM.pdf">Adobe
+ PostScript Language Reference, Third Edition.</A>
+ <LI>IPP: Job and Printer Set Operations
+ <LI>IPP/1.1: Encoding and Transport
+ <LI>IPP/1.1: Implementers Guide
+ <LI>IPP/1.1: Model and Semantics
+ <LI><A HREF="http://www.ietf.org/rfc/rfc1179.txt">RFC 1179, Line Printer Daemon Protocol</A>
+ <LI><A HREF="http://www.ietf.org/rfc/rfc2567.txt">RFC 2567, Design Goals for an Internet Printing Protocol</A>
+ <LI><A HREF="http://www.ietf.org/rfc/rfc2568.txt">RFC 2568, Rationale for the Structure of the Model and Protocol</A>
+ for the Internet Printing Protocol</A>
+ <LI><A HREF="http://www.ietf.org/rfc/rfc2569.txt">RFC 2569, Mapping between LPD and IPP Protocols</A>
+ <LI><A HREF="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616, Hypertext Transfer Protocol -- HTTP/1.1</A>
+ <LI><A HREF="http://www.ietf.org/rfc/rfc2617.txt">RFC 2617, HTTP Authentication: Basic and Digest Access</A>
+ Authentication
+</UL>
diff --git a/doc/sam.html b/doc/sam.html
new file mode 100644
index 000000000..968ce4104
--- /dev/null
+++ b/doc/sam.html
@@ -0,0 +1,4887 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD>
+<TITLE>CUPS Software Administrators Manual</TITLE>
+<META NAME="author" CONTENT="Easy Software Products">
+<META NAME="copyright" CONTENT="Copyright 1997-2002, All Rights Reserved">
+<META NAME="docnumber" CONTENT="CUPS-SAM-1.1.13">
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=iso-8859-1">
+<STYLE TYPE="text/css"><!--
+BODY { font-family: serif }
+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 }
+SUB { font-size: smaller }
+SUP { font-size: smaller }
+PRE { font-family: monospace }
+--></STYLE>
+</HEAD>
+<BODY BGCOLOR="#ffffff">
+<CENTER><A HREF="#CONTENTS"><IMG SRC="images/cups-large.gif" BORDER="0" WIDTH="431" HEIGHT="511"><BR>
+<H1>CUPS Software Administrators Manual</H1></A><BR>
+CUPS-SAM-1.1.13<BR>
+Easy Software Products<BR>
+Copyright 1997-2002, All Rights Reserved<BR>
+</CENTER>
+<HR>
+<H1 ALIGN="CENTER"><A NAME="CONTENTS">Table of Contents</A></H1>
+<BR>
+<BR><B><A HREF="#1">Preface</A></B>
+<UL>
+<LI><A HREF="#1_1">System Overview</A></LI>
+<LI><A HREF="#1_2">Document Overview</A></LI>
+<LI><A HREF="#1_3">Notation Conventions</A></LI>
+<LI><A HREF="#1_4">Abbreviations</A></LI>
+<LI><A HREF="#1_5">Other References</A></LI>
+</UL>
+<B><A HREF="#OVERVIEW">1 - Printing System Overview</A></B>
+<UL>
+<LI><A HREF="#2_1">The Printing Problem</A></LI>
+<LI><A HREF="#2_2">The Technology</A></LI>
+<LI><A HREF="#2_3">Jobs</A></LI>
+<LI><A HREF="#2_4">Classes</A></LI>
+<LI><A HREF="#2_5">Filters</A></LI>
+<LI><A HREF="#2_6">Backends</A></LI>
+<LI><A HREF="#2_7">Printer Drivers</A></LI>
+<LI><A HREF="#2_8">Networking</A></LI>
+</UL>
+<B><A HREF="#BUILDING_INSTALLING">2 - Building and Installing CUPS</A></B>
+<UL>
+<LI><A HREF="#3_1">Installing a Source Distribution</A></LI>
+<UL>
+<LI><A HREF="#REQUIREMENTS">Requirements</A></LI>
+<LI><A HREF="#COMPILING">Compiling CUPS</A></LI>
+<LI><A HREF="#INSTALLING">Installing the Software</A></LI>
+<LI><A HREF="#RUNNING">Running the Software</A></LI>
+</UL>
+<LI><A HREF="#BINARY">Installing a Binary Distribution</A></LI>
+<UL>
+<LI><A HREF="#PORTABLE-BINARY">Installing a Portable Distribution</A></LI>
+<LI><A HREF="#RPM-BINARY">Installing an RPM Distribution</A></LI>
+<LI><A HREF="#DPKG-BINARY">Installing an Debian Distribution</A></LI>
+</UL>
+</UL>
+<B><A HREF="#MANAGING_PRINTERS">3 - Managing Printers</A></B>
+<UL>
+<LI><A HREF="#4_1">The Basics</A></LI>
+<LI><A HREF="#4_2">Adding Your First Printer</A></LI>
+<UL>
+<LI><A HREF="#4_2_1">Adding Your First Printer from the Command-Line</A></LI>
+<LI><A HREF="#ADD_WEB">Adding Your First Printer from the Web</A></LI>
+</UL>
+<LI><A HREF="#4_3">Managing Printers from the Command-Line</A></LI>
+<UL>
+<LI><A HREF="#4_3_1">Adding and Modifying Printers</A></LI>
+<LI><A HREF="#4_3_2">Deleting Printers</A></LI>
+<LI><A HREF="#4_3_3">Setting the Default Printer</A></LI>
+<LI><A HREF="#4_3_4">Starting and Stopping Printers</A></LI>
+<LI><A HREF="#4_3_5">Accepting and Rejecting Print Jobs</A></LI>
+</UL>
+<LI><A HREF="#4_4">Managing Printers from the Web</A></LI>
+</UL>
+<B><A HREF="#PRINTER_CLASSES">4 - Printer Classes</A></B>
+<UL>
+<LI><A HREF="#5_1">The Basics</A></LI>
+<LI><A HREF="#5_2">Managing Printer Classes from the Command-Line</A></LI>
+<LI><A HREF="#5_3">Managing Printer Classes from the Web Interface</A></LI>
+<LI><A HREF="#5_4">Implicit Classes</A></LI>
+</UL>
+<B><A HREF="#CLIENT_SETUP">5 - Client Setup</A></B>
+<UL>
+<LI><A HREF="#6_1">The Basics</A></LI>
+<UL>
+<LI><A HREF="#CLIENT_MANUAL">Manual Configuration of Print Queues</A></LI>
+<LI><A HREF="#CLIENT_SERVER">Specifying a Single Server for Printing</A></LI>
+<LI><A HREF="#CLIENT_AUTO">Automatic Configuration of Print Queues</A></LI>
+<LI><A HREF="#CLIENT_POLL">Specifying Multiple Servers for Printing</A></LI>
+</UL>
+</UL>
+<B><A HREF="#PRINTING_MANAGEMENT">6 - Printing System Management</A></B>
+<UL>
+<LI><A HREF="#7_1">The Basics</A></LI>
+<LI><A HREF="#RESTARTING">Restarting the CUPS Server</A></LI>
+<LI><A HREF="#7_3">Changing the Server Configuration</A></LI>
+<LI><A HREF="#7_4">Server Directives</A></LI>
+<UL>
+<LI><A HREF="#AccessLog">AccessLog</A></LI>
+<LI><A HREF="#Allow">Allow</A></LI>
+<LI><A HREF="#AuthClass">AuthClass</A></LI>
+<LI><A HREF="#AuthGroupName">AuthGroupName</A></LI>
+<LI><A HREF="#AuthType">AuthType</A></LI>
+<LI><A HREF="#AutoPurgeJobs">AutoPurgeJobs</A></LI>
+<LI><A HREF="#BrowseAddress">BrowseAddress</A></LI>
+<LI><A HREF="#BrowseAllow">BrowseAllow</A></LI>
+<LI><A HREF="#BrowseDeny">BrowseDeny</A></LI>
+<LI><A HREF="#BrowseOrder">BrowseOrder</A></LI>
+<LI><A HREF="#BrowseInterval">BrowseInterval</A></LI>
+<LI><A HREF="#BrowsePoll">BrowsePoll</A></LI>
+<LI><A HREF="#BrowsePort">BrowsePort</A></LI>
+<LI><A HREF="#BrowseProtocols">BrowseProtocols</A></LI>
+<LI><A HREF="#BrowseRelay">BrowseRelay</A></LI>
+<LI><A HREF="#BrowseShortNames">BrowseShortNames</A></LI>
+<LI><A HREF="#BrowseTimeout">BrowseTimeout</A></LI>
+<LI><A HREF="#Browsing">Browsing</A></LI>
+<LI><A HREF="#Classification">Classification</A></LI>
+<LI><A HREF="#ClassifyOverride">ClassifyOverride</A></LI>
+<LI><A HREF="#DataDir">DataDir</A></LI>
+<LI><A HREF="#DefaultCharset">DefaultCharset</A></LI>
+<LI><A HREF="#DefaultLanguage">DefaultLanguage</A></LI>
+<LI><A HREF="#Deny">Deny</A></LI>
+<LI><A HREF="#DocumentRoot">DocumentRoot</A></LI>
+<LI><A HREF="#Encryption">Encryption</A></LI>
+<LI><A HREF="#ErrorLog">ErrorLog</A></LI>
+<LI><A HREF="#FilterLimit">FilterLimit</A></LI>
+<LI><A HREF="#FontPath">FontPath</A></LI>
+<LI><A HREF="#Group">Group</A></LI>
+<LI><A HREF="#HideImplicitMembers">HideImplicitMembers</A></LI>
+<LI><A HREF="#HostNameLookups">HostNameLookups</A></LI>
+<LI><A HREF="#ImplicitClasses">ImplicitClasses</A></LI>
+<LI><A HREF="#ImplicitAnyClasses">ImplicitAnyClasses</A></LI>
+<LI><A HREF="#Include">Include</A></LI>
+<LI><A HREF="#KeepAlive">KeepAlive</A></LI>
+<LI><A HREF="#KeepAliveTimeout">KeepAliveTimeout</A></LI>
+<LI><A HREF="#Limit">Limit</A></LI>
+<LI><A HREF="#LimitExcept">LimitExcept</A></LI>
+<LI><A HREF="#LimitRequestBody">LimitRequestBody</A></LI>
+<LI><A HREF="#Listen">Listen</A></LI>
+<LI><A HREF="#Location">Location</A></LI>
+<LI><A HREF="#LogLevel">LogLevel</A></LI>
+<LI><A HREF="#MaxClients">MaxClients</A></LI>
+<LI><A HREF="#MaxJobs">MaxJobs</A></LI>
+<LI><A HREF="#MaxJobsPerPrinter">MaxJobsPerPrinter</A></LI>
+<LI><A HREF="#MaxJobsPerUser">MaxJobsPerUser</A></LI>
+<LI><A HREF="#MaxLogSize">MaxLogSize</A></LI>
+<LI><A HREF="#MaxRequestSize">MaxRequestSize</A></LI>
+<LI><A HREF="#Order">Order</A></LI>
+<LI><A HREF="#PageLog">PageLog</A></LI>
+<LI><A HREF="#Port">Port</A></LI>
+<LI><A HREF="#PreserveJobHistory">PreserveJobHistory</A></LI>
+<LI><A HREF="#PreserveJobFiles">PreserveJobFiles</A></LI>
+<LI><A HREF="#Printcap">Printcap</A></LI>
+<LI><A HREF="#PrintcapFormat">PrintcapFormat</A></LI>
+<LI><A HREF="#PrintcapGUI">PrintcapGUI</A></LI>
+<LI><A HREF="#RemoteRoot">RemoteRoot</A></LI>
+<LI><A HREF="#RequestRoot">RequestRoot</A></LI>
+<LI><A HREF="#Require">Require</A></LI>
+<LI><A HREF="#RIPCache">RIPCache</A></LI>
+<LI><A HREF="#RunAsUser">RunAsUser</A></LI>
+<LI><A HREF="#Satisfy">Satisfy</A></LI>
+<LI><A HREF="#ServerAdmin">ServerAdmin</A></LI>
+<LI><A HREF="#ServerBin">ServerBin</A></LI>
+<LI><A HREF="#ServerCertificate">ServerCertificate</A></LI>
+<LI><A HREF="#ServerKey">ServerKey</A></LI>
+<LI><A HREF="#ServerName">ServerName</A></LI>
+<LI><A HREF="#ServerRoot">ServerRoot</A></LI>
+<LI><A HREF="#SSLListen">SSLListen</A></LI>
+<LI><A HREF="#SSLPort">SSLPort</A></LI>
+<LI><A HREF="#SystemGroup">SystemGroup</A></LI>
+<LI><A HREF="#TempDir">TempDir</A></LI>
+<LI><A HREF="#Timeout">Timeout</A></LI>
+<LI><A HREF="#User">User</A></LI>
+</UL>
+<LI><A HREF="#PRINTING_SECURITY">Printing System Security</A></LI>
+<UL>
+<LI><A HREF="#CERTIFICATES">Authentication Using Certificates</A></LI>
+<LI><A HREF="#7_5_2">Using Basic Authentication</A></LI>
+<LI><A HREF="#7_5_3">Using Digest Authentication</A></LI>
+<LI><A HREF="#7_5_4">System and Group Authentication</A></LI>
+</UL>
+<LI><A HREF="#PRINTER_ACCOUNTING">Printer Accounting</A></LI>
+<UL>
+<LI><A HREF="#7_6_1">The access_log File</A></LI>
+<LI><A HREF="#7_6_2">The error_log File</A></LI>
+<LI><A HREF="#7_6_3">The page_log File</A></LI>
+</UL>
+<LI><A HREF="#FILE_TYPING_FILTERING">File Typing and Filtering</A></LI>
+<UL>
+<LI><A HREF="#7_7_1">mime.types</A></LI>
+<LI><A HREF="#7_7_2">mime.convs</A></LI>
+<LI><A HREF="#7_7_3">Adding Filetypes and Filters</A></LI>
+<LI><A HREF="#7_7_4">Printer Drivers and PPD Files</A></LI>
+<LI><A HREF="#7_7_5">Writing Your Own Filter or Printer Driver</A></LI>
+</UL>
+</UL>
+<B><A HREF="#PRINTING_OTHER">7 - Printing with Other Systems</A></B>
+<UL>
+<LI><A HREF="#8_1">The Basics</A></LI>
+<LI><A HREF="#8_2">Printing from LPD Clients</A></LI>
+<LI><A HREF="#8_3">Printing to LPD Servers</A></LI>
+<LI><A HREF="#8_4">Printing from Mac OS Clients</A></LI>
+<UL>
+<LI><A HREF="#8_4_1">Columbia Appletalk Package (CAP)</A></LI>
+<LI><A HREF="#8_4_2">XINET KA/Spool</A></LI>
+<LI><A HREF="#8_4_3">NetATalk</A></LI>
+</UL>
+<LI><A HREF="#8_5">Printing to Mac OS Servers</A></LI>
+<LI><A HREF="#8_6">Printing from Windows Clients</A></LI>
+<UL>
+<LI><A HREF="#8_6_1">Exporting Printer Drivers</A></LI>
+</UL>
+<LI><A HREF="#8_7">Printing to Windows Servers</A></LI>
+</UL>
+<B><A HREF="#LICENSE">A - Software License Agreement</A></B>
+<UL>
+<LI><A HREF="#9_1">Common UNIX Printing System License Agreement</A></LI>
+<UL>
+<LI><A HREF="#9_1_1">Introduction</A></LI>
+<LI><A HREF="#9_1_2">Trademarks</A></LI>
+<LI><A HREF="#9_1_3">Binary Distribution Rights</A></LI>
+<LI><A HREF="#9_1_4">Support</A></LI>
+</UL>
+<LI><A HREF="#9_2">GNU GENERAL PUBLIC LICENSE</A></LI>
+<LI><A HREF="#9_3">GNU LIBRARY GENERAL PUBLIC LICENSE</A></LI>
+</UL>
+<B><A HREF="#COMMON_NETWORK">B - Common Network Settings</A></B>
+<UL>
+<LI><A HREF="#10_1">Configuring a Network Interface</A></LI>
+<UL>
+<LI><A HREF="#10_1_1">Configuring the IP Address Using ARP</A></LI>
+<LI><A HREF="#10_1_2">Configuring the IP Address Using RARP</A></LI>
+<LI><A HREF="#10_1_3">Configuring the IP Address Using BOOTP</A></LI>
+</UL>
+<LI><A HREF="#10_2">Verifying the Printer Connection</A></LI>
+<LI><A HREF="#10_3">Common Network Interface Settings</A></LI>
+<LI><A HREF="#AXIS">Configuring Axis Print Servers</A></LI>
+<LI><A HREF="#LINKSYS">Configuring Linksys Print Servers</A></LI>
+</UL>
+<B><A HREF="#PRINTER_DRIVERS">C - Printer Drivers</A></B>
+<UL>
+<LI><A HREF="#11_1">Printer Drivers</A></LI>
+<LI><A HREF="#EPSON9">EPSON 9-pin Dot Matrix</A></LI>
+<LI><A HREF="#EPSON24">EPSON 24-pin Dot Matrix</A></LI>
+<LI><A HREF="#STCOLOR">EPSON Stylus Color</A></LI>
+<LI><A HREF="#STPHOTO">EPSON Stylus Photo</A></LI>
+<LI><A HREF="#DESKJET">HP DeskJet</A></LI>
+<LI><A HREF="#LASERJET">HP LaserJet</A></LI>
+</UL>
+<B><A HREF="#FILES">D - List of Files</A></B>
+<BR>
+<BR><B><A HREF="#FAQ">E - Troubleshooting Common Problems</A></B>
+<UL>
+<LI><A HREF="#13_1">My Applications Don't See the Available Printers</A></LI>
+<LI><A HREF="#13_2">CUPS Doesn't Recognize My Username or Password!</A></LI>
+<LI><A HREF="#ALLOW_REMOTE">I Can't Do Administration Tasks from Another
+ Machine!</A></LI>
+<LI><A HREF="#13_4">I Can't Do Administration Tasks from My Web Browser!</A>
+</LI>
+<LI><A HREF="#13_5">Connection Refused Messages</A></LI>
+<LI><A HREF="#13_6">Write Error Messages</A></LI>
+</UL>
+<HR>
+<H1 ALIGN="RIGHT"><A NAME="1">Preface</A></H1>
+<P>This software administrators manual provides printer administration
+ information for the Common UNIX Printing System<SUP>TM</SUP> (&quot;CUPS<SUP>
+TM</SUP>&quot;), version 1.1.13.</P>
+<H2><A NAME="1_1">System Overview</A></H2>
+<P>CUPS provides a portable printing layer for UNIX&reg;-based operating
+ systems. It has been developed by<A HREF="http://www.easysw.com"> Easy
+ Software Products</A> to promote a standard printing solution for all
+ UNIX vendors and users. CUPS provides the System V and Berkeley
+ command-line interfaces.</P>
+<P>CUPS uses the Internet Printing Protocol (&quot;IPP&quot;) as the basis for
+ managing print jobs and queues. The Line Printer Daemon (&quot;LPD&quot;) Server
+ Message Block (&quot;SMB&quot;), and AppSocket (a.k.a. JetDirect) protocols are
+ also supported with reduced functionality. CUPS adds network printer
+ browsing and PostScript Printer Description (&quot;PPD&quot;) based printing
+ options to support real-world printing under UNIX.</P>
+<P>CUPS also includes a customized version of GNU Ghostscript (currently
+ based off GNU Ghostscript 5.50) and an image file RIP that are used to
+ support non-PostScript printers. Sample drivers for HP and EPSON
+ printers are included that use these filters.</P>
+
+<!-- NEED 3in -->
+<H2><A NAME="1_2">Document Overview</A></H2>
+<P>This software administrators manual is organized into the following
+ sections:</P>
+<UL>
+<LI><A HREF="#OVERVIEW">1 - Printing System Overview</A></LI>
+<LI><A HREF="#BUILDING_INSTALLING">2 - Building and Installing CUPS</A></LI>
+<LI><A HREF="#MANAGING_PRINTERS">3 - Managing Printers</A></LI>
+<LI><A HREF="#PRINTER_CLASSES">4 - Printer Classes</A></LI>
+<LI><A HREF="#CLIENT_SETUP">5 - Client Setup</A></LI>
+<LI><A HREF="#PRINTING_MANAGEMENT">6 - Printing System Management</A></LI>
+<LI><A HREF="#PRINTING_OTHER">7 - Printing with Other Systems</A></LI>
+<LI><A HREF="#LICENSE">A - Software License Agreement</A></LI>
+<LI><A HREF="#COMMON_NETWORK">B - Common Network Settings</A></LI>
+<LI><A HREF="#PRINTER_DRIVERS">C - Printer Drivers</A></LI>
+<LI><A HREF="#FILES">D - List of Files</A></LI>
+<LI><A HREF="#FAQ">E - Troubleshooting Common Problems</A></LI>
+</UL>
+<H2><A NAME="1_3">Notation Conventions</A></H2>
+<P>Various font and syntax conventions are used in this guide. Examples
+ and their meanings and uses are explained below:
+<CENTER>
+<TABLE WIDTH="80%">
+<TR><TH>Example</TH><TD>&nbsp;&nbsp;&nbsp;</TD><TH>Description</TH></TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR VALIGN="TOP"><TD><CODE>lpstat</CODE>
+<BR> <CODE>lpstat(1)</CODE></TD><TD>&nbsp;&nbsp;&nbsp;</TD><TD>The names of commands;
+ the first mention of a command or function in a chapter is followed by
+ a manual page section number.</TD></TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR VALIGN="TOP"><TD><VAR>/var</VAR>
+<BR><VAR> /usr/share/cups/data/testprint.ps</VAR></TD><TD>&nbsp;&nbsp;&nbsp;</TD><TD>
+File and directory names.</TD></TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR VALIGN="TOP"><TD NOWRAP><TT>Request ID is Printer-123</TT></TD><TD>
+&nbsp;&nbsp;&nbsp;</TD><TD>Screen output.</TD></TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR VALIGN="TOP"><TD NOWRAP><KBD>lp -d printer filename ENTER</KBD></TD><TD>
+&nbsp;&nbsp;&nbsp;</TD><TD>Literal user input; special keys like <KBD>ENTER</KBD> are
+ in ALL CAPS.</TD></TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR VALIGN="TOP"><TD>12.3</TD><TD>&nbsp;&nbsp;&nbsp;</TD><TD>Numbers in the text are
+ written using the period (.) to indicate the decimal point.</TD></TR>
+</TABLE>
+</CENTER>
+
+<!-- NEED 3in -->
+</P>
+<H2><A NAME="1_4">Abbreviations</A></H2>
+ The following abbreviations are used throughout this manual:
+<UL>
+<DL>
+<DT>kb</DT>
+<DD>Kilobytes, or 1024 bytes
+<BR>&nbsp;</DD>
+<DT>Mb</DT>
+<DD>Megabytes, or 1048576 bytes
+<BR>&nbsp;</DD>
+<DT>Gb</DT>
+<DD>Gigabytes, or 1073741824 bytes
+<BR>&nbsp;</DD>
+</DL>
+</UL>
+<H2><A NAME="1_5">Other References</A></H2>
+<UL>
+<DL>
+<DT>CUPS Software Programmers Manual</DT>
+<DD>A programmer guide for interfacing with and/or extending the CUPS
+ software.
+<BR>&nbsp;</DD>
+<DT>CUPS Software Users Manual</DT>
+<DD>An end-user guide for using the CUPS software.
+<BR>&nbsp;</DD>
+</DL>
+</UL>
+<H1 ALIGN="RIGHT"><A NAME="OVERVIEW">1 - Printing System Overview</A></H1>
+<P>This chapter provides an overview of how the Common UNIX Printing
+ System works.</P>
+<H2><A NAME="2_1">The Printing Problem</A></H2>
+<P>For years<I> the printing problem</I> has plagued UNIX. Unlike
+ Microsoft&reg; Windows&reg; or Mac OS, UNIX has no standard interface or system
+ in place for supporting printers. Among the solutions currently
+ available, the Berkeley and System V printing systems are the most
+ prevalent.</P>
+<P>These printing systems support line printers (text only) or
+ PostScript printers (text and graphics), and with some coaxing they can
+ be made to support a full range of printers and file formats. However,
+ because each varient of the UNIX operating system uses a different
+ printing system than the next developing printer drivers for a wide
+ range of printers and operating systems is extremely difficult. That
+ combined with the limited volume of customers for each UNIX varient has
+ forced most printer vendors to give up supporting UNIX entirely.</P>
+<P>CUPS is designed to eliminate<I> the printing problem</I>. 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.</P>
+<H2><A NAME="2_2">The Technology</A></H2>
+<P>CUPS is based upon an emerging Internet standard called the Internet
+ Printing Protocol. IPP has been embraced by dozens of printer and
+ printer server manufacturers and is supported by Microsoft Windows
+ 2000.</P>
+<P>IPP defines a standard protocol for printing as well as managing
+ print jobs and printer options like media size, resolution, and so
+ forth. Like all IP-based protocols, IPP can be used locally or over the
+ Internet to printers hundreds or thousands of miles away. Unlike other
+ protocols, however, IPP also supports access control, authentication,
+ and encryption, making it a much more capable and secure printing
+ solution than older ones.</P>
+<P>IPP is layered on top of the Hyper-Text Transport Protocol (&quot;HTTP&quot;)
+ which is the basis of web servers on the Internet. This allows users to
+ view documentation, check status information on a printer or server,
+ and manage their printers, classes, and jobs using their web browser.</P>
+<P>CUPS provides a complete IPP/1.1 based printing system that provides
+ Basic, Digest, and local certificate authentication and user, domain,
+ or IP-based access control. TLS encryption will be available in future
+ versions of CUPS.</P>
+<H2><A NAME="2_3">Jobs</A></H2>
+<P>Each file or set of files that is submitted for printing is called a<I>
+ job</I>. 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.</P>
+<H2><A NAME="2_4">Classes</A></H2>
+<P>CUPS supports collections of printers known as<I> classes</I>. Jobs
+ sent to a class are forwarded to the first available printer in the
+ class.</P>
+<H2><A NAME="2_5">Filters</A></H2>
+<P>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.</P>
+<P>CUPS provides filters for printing many types of image files, HP-GL/2
+ files, PDF files, and text files. CUPS also supplies PostScript and
+ image file Raster Image Processor (&quot;RIP&quot;) filters that convert
+ PostScript or image files into bitmaps that can be sent to a raster
+ printer.</P>
+<H2><A NAME="2_6">Backends</A></H2>
+<P>Backends perform the most important task of all - they send the
+ filtered print data to the printer.</P>
+<P>CUPS provides backends for printing over parallel, serial, and USB
+ ports, and over the network via the IPP, JetDirect (AppSocket), and
+ Line Printer Daemon (&quot;LPD&quot;) protocols. Additional backends are
+ available in network service packages such as the SMB backend included
+ with the popular SAMBA software.</P>
+<P>Backends are also used to determine the available devices. On startup
+ each backend is asked for a list of devices it supports, and any
+ information that is available. This allows the parallel backend to tell
+ CUPS that an EPSON Stylus Color 600 printer is attached to parallel
+ port 1, for example.</P>
+<H2><A NAME="2_7">Printer Drivers</A></H2>
+<P>Printer drivers in CUPS consist of one of more filters specific to a
+ printer. CUPS includes sample printer drivers for Hewlett-Packard
+ LaserJet and DeskJet printers and EPSON 9-pin, 24-pin, Stylus Color,
+ and Stylus Photo printers. While these drivers do not generate optimal
+ output for the different printer models, they do provide basic printing
+ and demonstrate how you can write your own printer drivers and
+ incorporate them into CUPS.</P>
+<H2><A NAME="2_8">Networking</A></H2>
+<P>Printers and classes on the local system are automatically shared
+ with other systems on the network. This allows you to setup one system
+ to print to a printer and use this system as a printer server or spool
+ host for all of the others. Users may then select a local printer by
+ name or a remote printer using &quot;name@server&quot;.</P>
+<P>CUPS also provides<I> implicit classes</I>, which are collections of
+ printers and/or classes with the same name. This allows you to setup
+ multiple servers pointing to the same physical network printer, for
+ example, so that you aren't relying on a single system for printing.
+ Because this also works with printer classes, you can setup multiple
+ servers and printers and never worry about a single point of failure
+ unless all of the printers and servers go down!</P>
+<H1 ALIGN="RIGHT"><A NAME="BUILDING_INSTALLING">2 - Building and
+ Installing CUPS</A></H1>
+<P>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,<A HREF="#BINARY"> Installing a
+ Binary Distribution</A>.</P>
+<H2><A NAME="3_1">Installing a Source Distribution</A></H2>
+<P>This section describes how to compile and install CUPS on your system
+ from the source code.</P>
+<H3><A NAME="REQUIREMENTS">Requirements</A></H3>
+<P>You'll need ANSI-compliant C and C++ compilers 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 compile and run
+ under Microsoft Windows.</P>
+<P>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
+ significantly reduced functionality. Easy Software Products maintains a
+ mirror of the current versions of these libraries at:</P>
+<UL>
+<PRE>
+<A HREF="ftp://ftp.easysw.com/pub/libraries">ftp://ftp.easysw.com/pub/libraries</A>
+</PRE>
+</UL>
+<P>If you make changes to the man pages you'll need GNU groff or another
+ nroff-like package. GNU groff is available from:</P>
+<UL>
+<PRE>
+<A HREF="ftp://ftp.gnu.org/pub/groff">ftp://ftp.gnu.org/pub/groff</A>
+</PRE>
+</UL>
+<P>The documentation is formatted using the HTMLDOC software. If you
+ need to make changes you can get the HTMLDOC software from:</P>
+<UL>
+<PRE>
+<A HREF="http://www.easysw.com/htmldoc">http://www.easysw.com/htmldoc</A>
+</PRE>
+</UL>
+<P>Finally, you'll need a <CODE>make</CODE> program that understands the
+ <CODE>include</CODE> directive - FreeBSD, NetBSD, and OpenBSD
+ developers should use the <CODE>gmake</CODE> program.</P>
+<H3><A NAME="COMPILING">Compiling CUPS</A></H3>
+<P>CUPS uses GNU autoconf to configure the makefiles and source code for
+ your system. Type the following command to configure CUPS for your
+ system:</P>
+<UL>
+<PRE>
+<B>./configure ENTER</B>
+</PRE>
+</UL>
+<P>The default installation will put the CUPS software in the<VAR> /etc</VAR>
+,<VAR> /usr</VAR>, and<VAR> /var</VAR> directories on your system, which
+ will overwrite any existing printing commands on your system. Use the <CODE>
+--prefix</CODE> option to install the CUPS software in another location:</P>
+<UL>
+<PRE>
+<B>./configure --prefix=/some/directory ENTER</B>
+</PRE>
+</UL>
+<P>If the PNG, JPEG, TIFF, and ZLIB libraries are not installed in a
+ system default location (typically<VAR> /usr/include</VAR> and<VAR>
+ /usr/lib</VAR>) you'll need to set the <CODE>CFLAGS</CODE>, <CODE>
+CXXFLAGS</CODE>, and <CODE>LDFLAGS</CODE> environment variables prior to
+ running configure:</P>
+<UL>
+<PRE>
+<B>setenv CFLAGS &quot;-I/some/directory&quot; ENTER</B>
+<B>setenv CXXFLAGS &quot;-I/some/directory&quot; ENTER</B>
+<B>setenv LDFLAGS &quot;-L/some/directory&quot; ENTER</B>
+<B>setenv DSOFLAGS &quot;-L/some/directory&quot; ENTER</B>
+<B>./configure ... ENTER</B>
+</PRE>
+</UL>
+<P>or:</P>
+<UL>
+<PRE>
+<B>CFLAGS=&quot;-I/some/directory&quot;; export CFLAGS ENTER</B>
+<B>CXXFLAGS=&quot;-I/some/directory&quot;; export CXXFLAGS ENTER</B>
+<B>LDFLAGS=&quot;-L/some/directory&quot;; export LDFLAGS ENTER</B>
+<B>DSOFLAGS=&quot;-L/some/directory&quot;; export DSOFLAGS ENTER</B>
+<B>./configure ... ENTER</B>
+</PRE>
+</UL>
+<P>To enable support for encryption, you'll also want to add the
+ &quot;--enable-ssl&quot; option:</P>
+<UL>
+<PRE>
+./configure --enable-ssl
+</PRE>
+</UL>
+<P>SSL and TLS support require the OpenSSL library, available at:</P>
+<UL>
+<PRE>
+<A HREF="http://www.openssl.org">http://www.openssl.org</A>
+</PRE>
+</UL>
+<P>If the OpenSSL headers and libraries are not installed in the
+ standard directories, use the <CODE>--with-openssl-includes</CODE> and <CODE>
+--with-openssl-libs</CODE> options:</P>
+<UL>
+<PRE>
+./configure --enable-ssl \
+ --with-openssl-includes=/foo/bar/include \
+ --with-openssl-libs=/foo/bar/lib
+</PRE>
+</UL>
+<P>Once you have configured things, just type:</P>
+<UL>
+<PRE>
+<B>make ENTER</B>
+</PRE>
+</UL>
+<P>to build the software.
+<!-- NEED 4in -->
+</P>
+<H3><A NAME="INSTALLING">Installing the Software</A></H3>
+<P>Use the &quot;install&quot; target to install the software:</P>
+<UL>
+<PRE>
+<B>make install ENTER</B>
+</PRE>
+</UL>
+<CENTER>
+<TABLE BGCOLOR="#cccccc" BORDER="1" CELLPADDING="5" WIDTH="80%">
+<TR><TD><B> WARNING:</B>
+<P>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 reinstall the old printing
+ system from your operating system CDs.</P>
+</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="RUNNING">Running the Software</A></H3>
+<P>Once you have installed the software you can start the CUPS server by
+ typing:</P>
+<UL>
+<PRE>
+<B>/usr/sbin/cupsd ENTER</B>
+</PRE>
+</UL>
+
+<!-- NEED 4in -->
+<H2><A NAME="BINARY">Installing a Binary Distribution</A></H2>
+<P>CUPS comes in a variety of binary distribution formats. Easy Software
+ Products provides binaries in TAR format with installation and removal
+ scripts (&quot;portable&quot; distributions), and in RPM and DPKG formats for Red
+ Hat and Debian-based distributions. Portable distributions are
+ available for all platforms, while the RPM and DPKG distributions are
+ only available for Linux.
+<CENTER>
+<TABLE BGCOLOR="#cccccc" BORDER="1" CELLPADDING="5" WIDTH="80%">
+<TR><TD><B> WARNING:</B>
+<P>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/or reinstall the old printing system from
+ your operating system CDs.</P>
+</TD></TR>
+</TABLE>
+</CENTER>
+</P>
+<H3><A NAME="PORTABLE-BINARY">Installing a Portable Distribution</A></H3>
+<P>To install the CUPS software from a portable distribution you will
+ need to be logged in as root; doing an <CODE>su</CODE> is good enough.
+ Once you are the root user, run the installation script with:</P>
+<UL>
+<PRE>
+<B>./cups.install ENTER</B>
+</PRE>
+</UL>
+<P>After asking you a few yes/no questions the CUPS software will be
+ installed and the scheduler will be started automatically.
+<!-- NEED 2in -->
+</P>
+<H3><A NAME="RPM-BINARY">Installing an RPM Distribution</A></H3>
+<P>To install the CUPS software from an RPM distribution you will need
+ to be logged in as root; doing an <CODE>su</CODE> is good enough. Once
+ you are the root user, run RPM with:</P>
+<UL>
+<PRE>
+<B>rpm -e lpr</B>
+<B>rpm -i cups-1.1-linux-M.m.n-intel.rpm ENTER</B>
+</PRE>
+</UL>
+<P>After a short delay the CUPS software will be installed and the
+ scheduler will be started automatically.</P>
+<H3><A NAME="DPKG-BINARY">Installing an Debian Distribution</A></H3>
+<P>To install the CUPS software from a Debian distribution you will need
+ to be logged in as root; doing an <CODE>su</CODE> is good enough. Once
+ you are the root user, run dpkg with:</P>
+<UL>
+<PRE>
+<B>dpkg -i cups-1.1-linux-M.m.n-intel.deb ENTER</B>
+</PRE>
+</UL>
+<P>After a short delay the CUPS software will be installed and the
+ scheduler will be started automatically.</P>
+<H1 ALIGN="RIGHT"><A NAME="MANAGING_PRINTERS">3 - Managing Printers</A></H1>
+<P>This chapter describes how to add your first printer and how to
+ manage your printers.</P>
+<H2><A NAME="4_1">The Basics</A></H2>
+<P>Each printer queue has a name associated with it; the printer name
+ must start with a letter and can contain up to 127 letters, numbers,
+ and the underscore (_). Case is not significant, e.g. &quot;PRINTER&quot;,
+ &quot;Printer&quot;, and &quot;printer&quot; are considered to be the same name.</P>
+<P>Printer queues also have a device associated with them. The device
+ can be a parallel port, a network interface, and so forth. Devices
+ within CUPS use Uniform Resource Identifiers (&quot;URIs&quot;) which are a more
+ general form of Uniform Resource Locators (&quot;URLs&quot;) that are used in
+ your web browser. For example, the first parallel port in Linux usually
+ uses a device URI of <CODE>parallel:/dev/lp1</CODE>.
+<!-- NEED 2.5in -->
+</P>
+<P>You can see a complete list of supported devices by running the <CODE>
+lpinfo(8)</CODE> command:</P>
+<UL>
+<PRE>
+<B>lpinfo -v ENTER</B>
+file file
+network socket
+network http
+network ipp
+network lpd
+direct parallel:/dev/lp1
+serial serial:/dev/ttyS1?baud=115200
+serial serial:/dev/ttyS2?baud=115200
+direct usb:/dev/usb/lp0
+network smb
+</PRE>
+</UL>
+<P>The <CODE>-v</CODE> option specifies that you want a list of
+ available devices. The first word in each line is the type of device
+ (direct, file, network, or serial) and is followed by the device URI or
+ method name for that device. File devices have device URIs of the form <CODE>
+file:/directory/filename</CODE> while network devices use the more
+ familiar <CODE>method://server</CODE> or <CODE>method://server/path</CODE>
+ format.</P>
+<P>Finally, printer queues usually have a PostScript Printer Description
+ (&quot;PPD&quot;) file associated with them. PPD files describe the capabilities
+ of each printer, the page sizes supported, etc., and are used for
+ PostScript and non-PostScript printers. CUPS includes PPD files for HP
+ LaserJet, HP DeskJet, EPSON 9-pin, EPSON 24-pin, and EPSON Stylus
+ printers.</P>
+<H2><A NAME="4_2">Adding Your First Printer</A></H2>
+<P>CUPS provides two methods for adding printers: a command-line program
+ called <CODE>lpadmin(8)</CODE> and a Web interface. The <CODE>lpadmin</CODE>
+ command allows you to perform most printer administration tasks from
+ the command-line and is located in<VAR> /usr/sbin</VAR>. The Web
+ interface is located at:</P>
+<UL>
+<PRE>
+<A HREF="http://localhost:631/admin">http://localhost:631/admin</A>
+</PRE>
+</UL>
+<P>and steps you through printer configuration. If you don't like
+ command-line interfaces, try the<A HREF="#ADD_WEB"> Web interface</A>
+ instead.</P>
+<H3><A NAME="4_2_1">Adding Your First Printer from the Command-Line</A></H3>
+<P>Run the <CODE>lpadmin</CODE> command with the <CODE>-p</CODE> option
+ to add a printer to CUPS:</P>
+<UL>
+<PRE>
+<B>/usr/sbin/lpadmin -p <I>printer</I> -E -v <I>device</I> -m <I>ppd</I> ENTER</B>
+</PRE>
+</UL>
+<P>For an HP DeskJet printer connected to the parallel port this would
+ look like:</P>
+<UL>
+<PRE>
+<B>/usr/sbin/lpadmin -p DeskJet -E -v parallel:/dev/lp1 -m deskjet.ppd ENTER</B>
+</PRE>
+</UL>
+<P>Similarly, an HP LaserJet printer using a JetDirect network interface
+ at IP address 11.22.33.44 would be added with the command:</P>
+<UL>
+<PRE>
+<B>/usr/sbin/lpadmin -p LaserJet -E -v socket://11.22.33.44 -m laserjet.ppd ENTER</B>
+</PRE>
+</UL>
+<P>As you can see, <CODE>deskjet.ppd</CODE> and <CODE>laserjet.ppd</CODE>
+ are the PPD files for the HP DeskJet and HP LaserJet drivers included
+ with CUPS. You'll find a complete list of PPD files and the printers
+ they will work with in<A HREF="#PRINTER_DRIVERS"> Appendix C, &quot;Printer
+ Drivers&quot;</A>.</P>
+<P>For a dot matrix printer connected to the serial port this would
+ might look like:</P>
+<UL>
+<PRE>
+<B>/usr/sbin/lpadmin -p DotMatrix -E -v serial:/dev/ttyS0?baud=9600+size=8+parity=none+flow=soft deskjet.ppd ENTER</B>
+</PRE>
+</UL>
+<P>Here you specify the serial port (e.g. S0,S1, d0, d1), baud rate
+ (e.g. 9600, 19200, 38400, 115200, etc.), number of bits, parity, and
+ flow control. If you do not need flow control, delete the &quot;+flow=soft&quot;
+ portion.</P>
+<H3><A NAME="ADD_WEB">Adding Your First Printer from the Web</A></H3>
+<P>The CUPS web server provides a user-friendly &quot;wizard&quot; interface for
+ adding your printers. Rather than figuring out which device URI and PPD
+ file to use, you can instead click on the appropriate listings and fill
+ in some simple information. Enter the following URL in your web browser
+ to begin:</P>
+<UL>
+<PRE>
+<A HREF="http://localhost:631/admin">http://localhost:631/admin</A>
+</PRE>
+</UL>
+<P>Click on the<VAR> Add Printer</VAR> button to add a printer.</P>
+<H2><A NAME="4_3">Managing Printers from the Command-Line</A></H2>
+<P>The <CODE>lpadmin</CODE> command enables you to perform most printer
+ administration tasks from the command-line. You'll find <CODE>lpadmin</CODE>
+ in the<VAR> /usr/sbin</VAR> directory.</P>
+<H3><A NAME="4_3_1">Adding and Modifying Printers</A></H3>
+<P>Run the <CODE>lpadmin</CODE> command with the <CODE>-p</CODE> option
+ to add or modify a printer:</P>
+<UL>
+<PRE>
+<B>/usr/sbin/lpadmin -p <I>printer</I> <I>options</I> ENTER</B>
+</PRE>
+</UL>
+<P>The<I> options</I> arguments can be any of the following:</P>
+<UL>
+<DL>
+<DT>-c<I> class</I></DT>
+<DD>Adds the named printer to printer class<VAR> class</VAR>. If the
+ class does not exist then it is created.</DD>
+<DT>-i<I> interface</I></DT>
+<DD>Copies the named<VAR> interface</VAR> script to the printer.
+ Interface scripts are used by System V printer drivers. Since all
+ filtering is disabled when using an interface script, scripts generally
+ should not be used unless there is no other driver for a printer.</DD>
+<DT>-m<I> model</I></DT>
+<DD>Specifies a standard printer driver which is usually a PPD file. A
+ list of all available models can be displayed using the <CODE>lpinfo</CODE>
+ command with the <CODE>-m</CODE> option. A list of printer drivers
+ included with CUPS can be found in<A HREF="#PRINTER_DRIVERS"> Appendix
+ C, &quot;Printer Drivers&quot;</A>.</DD>
+<DT>-r<I> class</I></DT>
+<DD>Removes the named printer from printer class<VAR> class. If the
+ resulting class becomes empty then it is removed.</VAR></DD>
+<DT>-v<I> device-uri</I></DT>
+<DD>Sets the device for communicating with the printer. If a job is
+ currently printing on the named printer then the job will be restarted
+ and sent to the new device.</DD>
+<DT>-D<I> info</I></DT>
+<DD>Provides a textual description of the printer, e.g. &quot;John's Personal
+ Printer&quot;.</DD>
+<DT>-E</DT>
+<DD>Enables the printer and accepts job. This option is equivalent to
+ running the <CODE>enable(1)</CODE> and <CODE>accept(8)</CODE> commands
+ on the printer.</DD>
+<DT>-L<I> location</I></DT>
+<DD>Provides a textual location for the printer, e.g. &quot;Computer Lab 5&quot;.</DD>
+<DT>-P<I> ppd-file</I></DT>
+<DD>Specifies a local PPD file for the printer driver.</DD>
+</DL>
+</UL>
+<H3><A NAME="4_3_2">Deleting Printers</A></H3>
+<P>Run the <CODE>lpadmin</CODE> command with the <CODE>-x</CODE> option
+ to delete a printer:</P>
+<UL>
+<PRE>
+<B>/usr/sbin/lpadmin -x <I>printer</I> ENTER</B>
+</PRE>
+</UL>
+<H3><A NAME="4_3_3">Setting the Default Printer</A></H3>
+<P>Run the <CODE>lpadmin</CODE> command with the <CODE>-d</CODE> option
+ to set a default printer:</P>
+<UL>
+<PRE>
+<B>/usr/sbin/lpadmin -d <I>printer</I> ENTER</B>
+</PRE>
+</UL>
+<P>The default printer can be overridden by the user using the <CODE>
+lpoptions(1)</CODE> command.</P>
+<H3><A NAME="4_3_4">Starting and Stopping Printers</A></H3>
+<P>The <CODE>enable</CODE> and <CODE>disable</CODE> commands start and
+ stop printer queues, respectively:</P>
+<UL>
+<PRE>
+<B>/usr/bin/enable <I>printer</I> ENTER</B>
+<B>/usr/bin/disable <I>printer</I> ENTER</B>
+</PRE>
+</UL>
+<P>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 queued jobs are printed after the printer is enabled (started).</P>
+<H3><A NAME="4_3_5">Accepting and Rejecting Print Jobs</A></H3>
+<P>The <CODE>accept</CODE> and <CODE>reject</CODE> commands accept and
+ reject print jobs for the named printer, respectively:</P>
+<UL>
+<PRE>
+<B>/usr/sbin/accept <I>printer</I> ENTER</B>
+<B>/usr/sbin/reject <I>printer</I> ENTER</B>
+</PRE>
+</UL>
+<P>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.</P>
+<H2><A NAME="4_4">Managing Printers from the Web</A></H2>
+<P>The Web interface is located at:</P>
+<UL>
+<PRE>
+<A HREF="http://localhost:631/admin">http://localhost:631/admin</A>
+</PRE>
+</UL>
+<P>From there you can perform all printer management tasks with a few
+ simple mouse clicks.</P>
+<H1 ALIGN="RIGHT"><A NAME="PRINTER_CLASSES">4 - Printer Classes</A></H1>
+<P>This chapter describes what printer classes are and how to manage
+ them.</P>
+<H2><A NAME="5_1">The Basics</A></H2>
+<P>CUPS provides collections of printers called<I> printer classes</I>.
+ Jobs sent to a class are forwarded to the first available printer in
+ the class. Classes can themselves be members of other classes, so it is
+ possible for you to define very large, distributed printer classes for
+ high-availability printing.</P>
+<P>CUPS also supports<I> implicit classes</I>. Implicit classes work
+ just like printer classes, but they are created automatically based
+ upon the available printers and classes on the network. This allows you
+ to setup multiple print servers with identical printer configurations
+ and have the client machines send their print jobs to the first
+ available server. If one or more servers go down, the jobs are
+ automatically redirected to the servers that are running, providing
+ fail-safe printing.</P>
+<H2><A NAME="5_2">Managing Printer Classes from the Command-Line</A></H2>
+<P>Run the <CODE>lpadmin</CODE> command with the <CODE>-p</CODE> and <CODE>
+-c</CODE> options to add a printer to a class:</P>
+<UL>
+<PRE>
+<B>/usr/sbin/lpadmin -p <I>printer</I> -c <I>class</I> ENTER</B>
+</PRE>
+</UL>
+<P>The<I> class</I> is created automatically if it doesn't exist. To
+ remove a printer from a class use the <CODE>-r</CODE> option:</P>
+<UL>
+<PRE>
+<B>/usr/sbin/lpadmin -p <I>printer</I> -r <I>class</I> ENTER</B>
+</PRE>
+</UL>
+<P>To remove the entire class just use the <CODE>-x</CODE> option:</P>
+<UL>
+<PRE>
+<B>/usr/sbin/lpadmin -x <I>class</I> ENTER</B>
+</PRE>
+</UL>
+<H2><A NAME="5_3">Managing Printer Classes from the Web Interface</A></H2>
+<P>The Web interface is located at:</P>
+<UL>
+<PRE>
+<A HREF="http://localhost:631/admin">http://localhost:631/admin</A>
+</PRE>
+</UL>
+<P>The<VAR> Add Class</VAR> and<VAR> Modify Class</VAR> interfaces
+ provide a list of available printers; click on the printers of interest
+ to add them to the class.</P>
+<H2><A NAME="5_4">Implicit Classes</A></H2>
+<P>A noted earlier, implicit classes are created automatically from the
+ available network printers and classes. To disable this functionality,
+ set the<A HREF="#ImplicitClasses"> <CODE>ImplicitClasses</CODE></A>
+ directive to <CODE>Off</CODE> in the <CODE>cupsd.conf</CODE> file. You
+ will find more information on doing this in<A HREF="#PRINTING_MANAGEMENT">
+ Chapter 6, &quot;Printing System Management&quot;</A>.</P>
+<H1 ALIGN="RIGHT"><A NAME="CLIENT_SETUP">5 - Client Setup</A></H1>
+<P>This chapter discusses several ways to configure CUPS clients for
+ printing.</P>
+<H2><A NAME="6_1">The Basics</A></H2>
+<P>A client is any machine that sends print jobs to another machine for
+ final printing. Clients can also be servers if they communicate
+ directly with any printers of their own.</P>
+<P>CUPS supports several methods of configuring client machines:</P>
+<UL>
+<LI><A HREF="#CLIENT_MANUAL">Manual configuration of print queues.</A></LI>
+<LI><A HREF="#CLIENT_SERVER">Specifying a single server for printing.</A>
+</LI>
+<LI><A HREF="#CLIENT_AUTO">Automatic configuration of print queues.</A></LI>
+<LI><A HREF="#CLIENT_POLL">Specifying multiple servers for printing.</A></LI>
+</UL>
+<H3><A NAME="CLIENT_MANUAL">Manual Configuration of Print Queues</A></H3>
+<P>The most tedious method of configuring client machines is to
+ configure each remote queue by hand using the <CODE>lpadmin</CODE>
+ command:</P>
+<UL>
+<PRE>
+<B>lpadmin -p <I>printer</I> -E -v ipp://<I>server</I>/printers/<I>printer</I> ENTER</B>
+</PRE>
+</UL>
+<P>The <CODE>printer</CODE> name is the name of the printer on the
+ server machine. The <CODE>server</CODE> name is the hostname or IP
+ address of the server machine. Repeat the <CODE>lpadmin</CODE> command
+ for each remote printer you wish to use.</P>
+<H3><A NAME="CLIENT_SERVER">Specifying a Single Server for Printing</A></H3>
+<P>CUPS can be configured to run without a local spooler and send all
+ jobs to a single server. However, if that server goes down then all
+ printing will be disabled. Use this configuration only as absolutely
+ needed.</P>
+<P>The default server is normally &quot;localhost&quot;. To override the default
+ server create a file named<VAR> /etc/cups/client.conf</VAR> and add a
+ line reading:</P>
+<UL>
+<PRE>
+ServerName <I>server</I>
+</PRE>
+</UL>
+<P>to the file. The<VAR> server</VAR> name can be the hostname or IP
+ address of the default server.</P>
+<P>The default server can also be customized on a per-user basis. To set
+ a user-specific server create a file named<VAR> ~/.cupsrc</VAR> and add
+ a line reading:</P>
+<UL>
+<PRE>
+ServerName <I>server</I>
+</PRE>
+</UL>
+<P>to the file. The<VAR> server</VAR> name can be the hostname or IP
+ address of the default server.</P>
+<H3><A NAME="CLIENT_AUTO">Automatic Configuration of Print Queues</A></H3>
+<P>CUPS supports automatic client configuration of printers on the same
+ subnet. To configure printers on the same subnet,<I> do nothing</I>.
+ Each client should see the available printers within 30 seconds
+ automatically. The printer and class lists are updated automatically as
+ printers and servers are added or removed.</P>
+<P>If you want to see printers on other subnets as well, use the<A HREF="#BrowsePoll">
+ <CODE>BrowsePoll</CODE></A> directive as described next.</P>
+<H3><A NAME="CLIENT_POLL">Specifying Multiple Servers for Printing</A></H3>
+<P>If you have CUPS servers on different subnets, then you should
+ configure CUPS to poll those servers. Polling provides the benefits of
+ automatic configuration without significant configuration on the
+ clients, and multiple clients on the same subnet can share the same
+ configuration information.</P>
+<P>Polling is enabled by specifying one or more<A HREF="#BrowsePoll"> <CODE>
+BrowsePoll</CODE></A> directives in the<VAR> /etc/cups/cupsd.conf</VAR>
+ file. For information on making these changes, see<A HREF="#PRINTING_MANAGEMENT">
+ Chapter 6, &quot;Printing System Management&quot;</A>.</P>
+<H1 ALIGN="RIGHT"><A NAME="PRINTING_MANAGEMENT">6 - Printing System
+ Management</A></H1>
+<P>This chapter shows how you can configure the CUPS server.</P>
+<H2><A NAME="7_1">The Basics</A></H2>
+<P>Several text files are used to configure CUPS. All of the server
+ configuration files are located in the<VAR> /etc/cups</VAR> directory:</P>
+<UL>
+<DL>
+<!-- NEED 1in -->
+
+<DT>classes.conf</DT>
+<DD>This file contains information on each printer class. Normally you
+ manipulate this file using the <CODE>lpadmin</CODE> command or the Web
+ interface.
+<BR>&nbsp;
+<!-- NEED 1in -->
+</DD>
+<DT>client.conf</DT>
+<DD>This file provides the default server name for client machines. See<A
+HREF="#CLIENT_SETUP"> Chapter 5, &quot;Client Setup&quot;</A> for more
+ information.
+<BR>&nbsp;
+<!-- NEED 1in -->
+</DD>
+<DT>cupsd.conf</DT>
+<DD>This file controls how the CUPS server (<VAR>/usr/sbin/cupsd</VAR>)
+ operates and is normally edited by hand.
+<BR>&nbsp;
+<!-- NEED 1in -->
+</DD>
+<DT>mime.convs</DT>
+<DD>This file contains a list of standard file conversion filters and
+ their costs. You normally do not edit this file.
+<BR>&nbsp;
+<!-- NEED 1in -->
+</DD>
+<DT>mime.types</DT>
+<DD>This file contains a list of standard file formats and how to
+ recognize them. You normally do not edit this file.
+<BR>&nbsp;
+<!-- NEED 1in -->
+</DD>
+<DT>printers.conf</DT>
+<DD>This file contains information on each printer. Normally you
+ manipulate this file using the <CODE>lpadmin</CODE> command or the Web
+ Interface.
+<BR>&nbsp;</DD>
+</DL>
+</UL>
+<H2><A NAME="RESTARTING">Restarting the CUPS Server</A></H2>
+<P>Once you have made a change to a configuration file you need to
+ restart the CUPS server by sending it a <CODE>HUP</CODE> signal or
+ using the supplied initialization script. The CUPS distributions
+ install the script in the<VAR> init.d</VAR> directory with the name<VAR>
+ cups</VAR>. The location varies based upon the operating system:</P>
+<UL>
+<PRE>
+<B>/etc/rc.d/init.d/cups restart ENTER</B>
+<B>/etc/init.d/cups restart ENTER</B>
+<B>/sbin/init.d/cups restart ENTER</B>
+</PRE>
+</UL>
+<H2><A NAME="7_3">Changing the Server Configuration</A></H2>
+<P>The<VAR> /etc/cups/cupsd.conf</VAR> file contains configuration<I>
+ directives</I> that control how the server functions. Each directive is
+ listed on a line by itself followed by its value. Comments are
+ introduced using the number sign (&quot;#&quot;) character at the beginning of a
+ line. Since the server configuration file consists of plain text, you
+ can use your favorite text editor to make changes to it.
+<!-- NEED 4in -->
+</P>
+<H2><A NAME="7_4">Server Directives</A></H2>
+<P>The<VAR> cupsd.conf</VAR> file contains many directives that
+ determine how the server operates:</P>
+<UL>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="0">
+<TR><TD VALIGN="TOP">
+<LI><A HREF="#AccessLog"><CODE>AccessLog</CODE></A></LI>
+<LI><A HREF="#Allow"><CODE>Allow</CODE></A></LI>
+<LI><A HREF="#AuthClass"><CODE>AuthClass</CODE></A></LI>
+<LI><A HREF="#AuthGroupName"><CODE>AuthGroupName</CODE></A></LI>
+<LI><A HREF="#AuthType"><CODE>AuthType</CODE></A></LI>
+<LI><A HREF="#AutoPurgeJobs"><CODE>AutoPurgeJobs</CODE></A></LI>
+<LI><A HREF="#BrowseAddress"><CODE>BrowseAddress</CODE></A></LI>
+<LI><A HREF="#BrowseAllow"><CODE>BrowseAllow</CODE></A></LI>
+<LI><A HREF="#BrowseDeny"><CODE>BrowseDeny</CODE></A></LI>
+<LI><A HREF="#BrowseInterval"><CODE>BrowseInterval</CODE></A></LI>
+<LI><A HREF="#BrowseOrder"><CODE>BrowseOrder</CODE></A></LI>
+<LI><A HREF="#BrowsePoll"><CODE>BrowsePoll</CODE></A></LI>
+<LI><A HREF="#BrowsePort"><CODE>BrowsePort</CODE></A></LI>
+<LI><A HREF="#BrowseProtocols"><CODE>BrowseProtocols</CODE></A></LI>
+<LI><A HREF="#BrowseRelay"><CODE>BrowseRelay</CODE></A></LI>
+<LI><A HREF="#BrowseShortNames"><CODE>BrowseShortNames</CODE></A></LI>
+<LI><A HREF="#BrowseTimeout"><CODE>BrowseTimeout</CODE></A></LI>
+<LI><A HREF="#Browsing"><CODE>Browsing</CODE></A></LI>
+<LI><A HREF="#Classification"><CODE>Classification</CODE></A></LI>
+<LI><A HREF="#ClassifyOverride"><CODE>ClassifyOverride</CODE></A></LI>
+<LI><A HREF="#DataDir"><CODE>DataDir</CODE></A></LI>
+<LI><A HREF="#DefaultCharset"><CODE>DefaultCharset</CODE></A></LI>
+<LI><A HREF="#DefaultLanguage"><CODE>DefaultLanguage</CODE></A></LI>
+<LI><A HREF="#Deny"><CODE>Deny</CODE></A></LI>
+<LI><A HREF="#DocumentRoot"><CODE>DocumentRoot</CODE></A></LI>
+</TD><TD VALIGN="TOP"> &nbsp;&nbsp;&nbsp;</TD><TD VALIGN="TOP">
+<LI><A HREF="#Encryption"><CODE>Encryption</CODE></A></LI>
+<LI><A HREF="#ErrorLog"><CODE>ErrorLog</CODE></A></LI>
+<LI><A HREF="#FilterLimit"><CODE>FilterLimit</CODE></A></LI>
+<LI><A HREF="#FontPath"><CODE>FontPath</CODE></A></LI>
+<LI><A HREF="#Group"><CODE>Group</CODE></A></LI>
+<LI><A HREF="#HideImplicitMembers"><CODE>HideImplicitMembers</CODE></A></LI>
+<LI><A HREF="#HostNameLookups"><CODE>HostNameLookups</CODE></A></LI>
+<LI><A HREF="#ImplicitClasses"><CODE>ImplicitClasses</CODE></A></LI>
+<LI><A HREF="#ImplicitAnyClasses"><CODE>ImplicitAnyClasses</CODE></A></LI>
+<LI><A HREF="#Include"><CODE>Include</CODE></A></LI>
+<LI><A HREF="#KeepAliveTimeout"><CODE>KeepAliveTimeout</CODE></A></LI>
+<LI><A HREF="#KeepAlive"><CODE>KeepAlive</CODE></A></LI>
+<LI><A HREF="#Limit"><CODE>Limit</CODE></A></LI>
+<LI><A HREF="#LimitExcept"><CODE>LimitExcept</CODE></A></LI>
+<LI><A HREF="#LimitRequestBody"><CODE>LimitRequestBody</CODE></A></LI>
+<LI><A HREF="#Listen"><CODE>Listen</CODE></A></LI>
+<LI><A HREF="#Location"><CODE>Location</CODE></A></LI>
+<LI><A HREF="#LogLevel"><CODE>LogLevel</CODE></A></LI>
+<LI><A HREF="#MaxClients"><CODE>MaxClients</CODE></A></LI>
+<LI><A HREF="#MaxJobs"><CODE>MaxJobs</CODE></A></LI>
+<LI><A HREF="#MaxJobsPerPrinter"><CODE>MaxJobsPerPrinter</CODE></A></LI>
+<LI><A HREF="#MaxJobsPerUser"><CODE>MaxJobsPerUser</CODE></A></LI>
+<LI><A HREF="#MaxLogSize"><CODE>MaxLogSize</CODE></A></LI>
+<LI><A HREF="#MaxRequestSize"><CODE>MaxRequestSize</CODE></A></LI>
+<LI><A HREF="#Order"><CODE>Order</CODE></A></LI>
+</TD><TD VALIGN="TOP"> &nbsp;&nbsp;&nbsp;</TD><TD VALIGN="TOP">
+<LI><A HREF="#PageLog"><CODE>PageLog</CODE></A></LI>
+<LI><A HREF="#Port"><CODE>Port</CODE></A></LI>
+<LI><A HREF="#PreserveJobFiles"><CODE>PreserveJobFiles</CODE></A></LI>
+<LI><A HREF="#PreserveJobHistory"><CODE>PreserveJobHistory</CODE></A></LI>
+<LI><A HREF="#Printcap"><CODE>Printcap</CODE></A></LI>
+<LI><A HREF="#PrintcapFormat"><CODE>PrintcapFormat</CODE></A></LI>
+<LI><A HREF="#PrintcapGUI"><CODE>PrintcapGUI</CODE></A></LI>
+<LI><A HREF="#RemoteRoot"><CODE>RemoteRoot</CODE></A></LI>
+<LI><A HREF="#RequestRoot"><CODE>RequestRoot</CODE></A></LI>
+<LI><A HREF="#Require"><CODE>Require</CODE></A></LI>
+<LI><A HREF="#RIPCache"><CODE>RIPCache</CODE></A></LI>
+<LI><A HREF="#RunAsUser"><CODE>RunAsUser</CODE></A></LI>
+<LI><A HREF="#Satisfy"><CODE>Satisfy</CODE></A></LI>
+<LI><A HREF="#ServerAdmin"><CODE>ServerAdmin</CODE></A></LI>
+<LI><A HREF="#ServerBin"><CODE>ServerBin</CODE></A></LI>
+<LI><A HREF="#ServerCertificate"><CODE>ServerCertificate</CODE></A></LI>
+<LI><A HREF="#ServerKey"><CODE>ServerKey</CODE></A></LI>
+<LI><A HREF="#ServerName"><CODE>ServerName</CODE></A></LI>
+<LI><A HREF="#ServerRoot"><CODE>ServerRoot</CODE></A></LI>
+<LI><A HREF="#SSLListen"><CODE>SSLListen</CODE></A></LI>
+<LI><A HREF="#SSLPort"><CODE>SSLPort</CODE></A></LI>
+<LI><A HREF="#SystemGroup"><CODE>SystemGroup</CODE></A></LI>
+<LI><A HREF="#TempDir"><CODE>TempDir</CODE></A></LI>
+<LI><A HREF="#Timeout"><CODE>Timeout</CODE></A></LI>
+<LI><A HREF="#User"><CODE>User</CODE></A></LI>
+</TD></TR>
+</TABLE>
+</UL>
+
+<!-- NEED 3in -->
+<H3><A NAME="AccessLog">AccessLog</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+AccessLog /var/log/cups/access_log
+AccessLog /var/log/cups/access_log-%s
+AccessLog syslog
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>AccessLog</CODE> directive sets the name of the access log
+ file. If the filename is not absolute then it is assumed to be relative
+ to the<A HREF="#ServerRoot"> <CODE>ServerRoot</CODE></A> directory. The
+ access log file is stored in &quot;common log format&quot; and can be used by any
+ web access reporting tool to generate a report on CUPS server activity.</P>
+<P>The server name can be included in the filename by using <CODE>%s</CODE>
+ in the name.</P>
+<P>The special name &quot;syslog&quot; can be used to send the access information
+ to the system log instead of a plain file.</P>
+<P>The default access log file is<VAR> /var/log/cups/access_log</VAR>.
+<!-- NEED 6in -->
+</P>
+<H3><A NAME="Allow">Allow</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+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
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>Allow</CODE> directive specifies a hostname, IP address, or
+ network that is allowed access to the server. <CODE>Allow</CODE>
+ directives are cummulative, so multiple <CODE>Allow</CODE> directives
+ can be used to allow access for multiple hosts or networks. The <CODE>
+/mm</CODE> notation specifies a CIDR netmask:
+<CENTER>
+<TABLE BORDER="1">
+<TR><TH WIDTH="10%">mm</TH><TH WIDTH="20%">netmask</TH><TH WIDTH="10%">
+mm</TH><TH WIDTH="20%">netmask</TH></TR>
+<TR><TD ALIGN="CENTER">0</TD><TD ALIGN="CENTER">0.0.0.0</TD><TD ALIGN="CENTER">
+8</TD><TD ALIGN="CENTER">255.0.0.0</TD></TR>
+<TR><TD ALIGN="CENTER">1</TD><TD ALIGN="CENTER">128.0.0.0</TD><TD ALIGN="CENTER">
+16</TD><TD ALIGN="CENTER">255.255.0.0</TD></TR>
+<TR><TD ALIGN="CENTER">2</TD><TD ALIGN="CENTER">192.0.0.0</TD><TD ALIGN="CENTER">
+24</TD><TD ALIGN="CENTER">255.255.255.0</TD></TR>
+<TR><TD ALIGN="CENTER">...</TD><TD ALIGN="CENTER">...</TD><TD ALIGN="CENTER">
+32</TD><TD ALIGN="CENTER">255.255.255.255</TD></TR>
+</TABLE>
+</CENTER>
+</P>
+<P>The <CODE>Allow</CODE> directive must appear inside a<A HREF="#Location">
+ <CODE>Location</CODE></A> directive.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="AuthClass">AuthClass</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+AuthClass Anonymous
+AuthClass User
+AuthClass System
+AuthClass Group
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>AuthClass</CODE> directive defines what level of
+ authentication is required:</P>
+<UL>
+<LI><CODE>Anonymous</CODE> - No authentication should be performed
+ (default.)</LI>
+<LI><CODE>User</CODE> - A valid username and password is required.</LI>
+<LI><CODE>System</CODE> - A valid username and password is required, and
+ the username must belong to the &quot;sys&quot; group; this can be changed using
+ the<A HREF="#SystemGroup"> <CODE>SystemGroup</CODE></A> directive.</LI>
+<LI><CODE>Group</CODE> - A valid username and password is required, and
+ the username must belong to the group named by the <CODE>AuthGroupName</CODE>
+ directive.</LI>
+</UL>
+<P>The <CODE>AuthClass</CODE> directive must appear inside a<A HREF="#Location">
+ <CODE>Location</CODE></A> directive.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="AuthGroupName">AuthGroupName</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+AuthGroupName mygroup
+AuthGroupName lp
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>AuthGroupName</CODE> directive sets the group to use for <CODE>
+Group</CODE> authentication.</P>
+<P>The <CODE>AuthGroupName</CODE> directive must appear inside a<A HREF="#Location">
+ <CODE>Location</CODE></A> directive.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="AuthType">AuthType</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+AuthType None
+AuthType Basic
+AuthType Digest
+AuthType BasicDigest
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>AuthType</CODE> directive defines the type of
+ authentication to perform:</P>
+<UL>
+<LI><CODE>None</CODE> - No authentication should be performed (default.)</LI>
+<LI><CODE>Basic</CODE> - Basic authentication should be performed using
+ the UNIX password and group files.</LI>
+<LI><CODE>Digest</CODE> - Digest authentication should be performed
+ using the<VAR> /etc/cups/passwd.md5</VAR> file.</LI>
+<LI><CODE>BasicDigest</CODE> - Basic authentication should be performed
+ using the<VAR> /etc/cups/passwd.md5</VAR> file.</LI>
+</UL>
+<P>When using <CODE>Basic</CODE>, <CODE>Digest</CODE>, or <CODE>
+BasicDigest</CODE> authentication, clients connecting through the <CODE>
+localhost</CODE> interface can also authenticate using<A HREF="#CERTIFICATES">
+ certificates</A>.</P>
+<P>The <CODE>AuthType</CODE> directive must appear inside a<A HREF="#Location">
+ <CODE>Location</CODE></A> directive.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="AutoPurgeJobs">AutoPurgeJobs</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+AutoPurgeJobs Yes
+AutoPurgeJobs No
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>AutoPurgeJobs</CODE> directive specifies whether or not to
+ purge completed jobs once they are no longer required for quotas. This
+ option has no effect if quotas are not enabled. The default setting is <CODE>
+No</CODE>.
+<!-- NEED 5in -->
+</P>
+<H3><A NAME="BrowseAddress">BrowseAddress</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+BrowseAddress 255.255.255.255:631
+BrowseAddress 192.0.2.255:631
+BrowseAddress host.domain.com:631
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>BrowseAddress</CODE> directive specifies an address to send
+ browsing information to. Multiple <CODE>BrowseAddress</CODE> directives
+ can be specified to send browsing information to different networks or
+ systems.</P>
+<P>The default address is <CODE>255.255.255.255:631</CODE> which will
+ broadcast the information to all networks the server is connected to.
+<CENTER>
+<TABLE BGCOLOR="#cccccc" BORDER="1" CELLPADDING="5" WIDTH="80%">
+<TR><TD><B> NOTE:</B>
+<P>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.</P>
+</TD></TR>
+</TABLE>
+</CENTER>
+
+<!-- NEED 4in -->
+</P>
+<H3><A NAME="BrowseAllow">BrowseAllow</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+BrowseAllow from all
+BrowseAllow from none
+BrowseAllow from 192.0.2
+BrowseAllow from 192.0.2.0/24
+BrowseAllow from 192.0.2.0/255.255.255.0
+BrowseAllow from *.domain.com
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>BrowseAllow</CODE> directive specifies a system or network
+ to accept browse packets from. The default is to accept browse packets
+ from all hosts.</P>
+<P>Host and domain name matching require that you enable the<A HREF="#HostNameLookups">
+ <CODE>HostNameLookups</CODE></A> directive.</P>
+<P>IP address matching supports exact matches, partial addresses that
+ match networks using netmasks of 255.0.0.0, 255.255.0.0, and
+ 255.255.255.0, or network addresses using the specified netmask or bit
+ count.
+<!-- NEED 4in -->
+</P>
+<H3><A NAME="BrowseDeny">BrowseDeny</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+BrowseDeny from all
+BrowseDeny from none
+BrowseDeny from 192.0.2
+BrowseDeny from 192.0.2.0/24
+BrowseDeny from 192.0.2.0/255.255.255.0
+BrowseDeny from *.domain.com
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>BrowseDeny</CODE> directive specifies a system or network
+ to reject browse packets from. The default is to deny browse packets
+ from no hosts.</P>
+<P>Host and domain name matching require that you enable the<A HREF="#HostNameLookups">
+ <CODE>HostNameLookups</CODE></A> directive.</P>
+<P>IP address matching supports exact matches, partial addresses that
+ match networks using netmasks of 255.0.0.0, 255.255.0.0, and
+ 255.255.255.0, or network addresses using the specified netmask or bit
+ count.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="BrowseOrder">BrowseOrder</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+BrowseOrder allow,deny
+BrowseOrder deny,allow
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>BrowseOrder</CODE> directive specifies the order of
+ allow/deny processing. The default order is <CODE>deny,allow</CODE>:</P>
+<UL>
+<LI><CODE>allow,deny</CODE> - Browse packets are accepted unless
+ specifically denied.</LI>
+<LI><CODE>deny,allow</CODE> - Browse packets are rejected unless
+ specifically allowed.</LI>
+</UL>
+
+<!-- NEED 3in -->
+<H3><A NAME="BrowseInterval">BrowseInterval</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+BrowseInterval 0
+BrowseInterval 30
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>BrowseInterval</CODE> directive specifies the maximum
+ amount of time between browsing updates. Specifying a value of 0
+ seconds disables outgoing browse updates but allows a server to receive
+ printer information from other hosts.</P>
+<P>The <CODE>BrowseInterval</CODE> value should always be less than the<A
+HREF="#BrowseTimeout"> <CODE>BrowseTimeout</CODE></A> value. Otherwise
+ printers and classes will disappear from client systems between
+ updates.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="BrowsePoll">BrowsePoll</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+BrowsePoll 192.0.2.2:631
+BrowsePoll host.domain.com:631
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>BrowsePoll</CODE> directive polls a server for available
+ printers once every<A HREF="#BrowseInterval"> <CODE>BrowseInterval</CODE>
+</A> seconds. Multiple <CODE>BrowsePoll</CODE> directives can be
+ specified to poll multiple servers.</P>
+<P>If <CODE>BrowseInterval</CODE> is set to 0 then the server is polled
+ once every 30 seconds.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="BrowsePort">BrowsePort</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+BrowsePort 631
+BrowsePort 9999
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>BrowsePort</CODE> directive specifies the UDP port number
+ used for browse packets. The default port number is 631.
+<CENTER>
+<TABLE BGCOLOR="#cccccc" BORDER="1" CELLPADDING="5" WIDTH="80%">
+<TR><TD><B> NOTE:</B>
+<P>You must set the <CODE>BrowsePort</CODE> to the same value on all of
+ the systems that you want to see.</P>
+</TD></TR>
+</TABLE>
+</CENTER>
+
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="BrowseProtocols">BrowseProtocols</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+BrowseProtocols CUPS
+BrowseProtocols SLP
+BrowseProtocols CUPS SLP
+BrowseProtocols all
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>BrowseProtocols</CODE> directive specifies the protocols to
+ use when collecting and distributing shared printers on the local
+ network. The default protocol is <CODE>CUPS</CODE>, which is a
+ broadcast-based protocol.
+<CENTER>
+<TABLE BGCOLOR="#cccccc" BORDER="1" CELLPADDING="5" WIDTH="80%">
+<TR><TD><B> NOTE:</B>
+<P>When using the <CODE>SLP</CODE> protocol, you must have at least one
+ Directory Agent (DA) server on your network. Otherwise the CUPS
+ scheduler (<CODE>cupsd</CODE>) will not respond to client requests for
+ several seconds while polling the network.</P>
+</TD></TR>
+</TABLE>
+</CENTER>
+
+<!-- NEED 4in -->
+</P>
+<H3><A NAME="BrowseRelay">BrowseRelay</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+BrowseRelay 193.0.2.1 192.0.2.255
+BrowseRelay 193.0.2.0/255.255.255.0 192.0.2.255
+BrowseRelay 193.0.2.0/24 192.0.2.255
+BrowseRelay *.domain.com 192.0.2.255
+BrowseRelay host.domain.com 192.0.2.255
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>BrowseRelay</CODE> directive specifies source and
+ destination addresses for relaying browsing information from one host
+ or network to another. Multiple <CODE>BrowseRelay</CODE> directives can
+ be specified as needed.</P>
+<P><CODE>BrowseRelay</CODE> is typically used on systems that bridge
+ multiple subnets using one or more network interfaces. It can also be
+ used to relay printer information from polled servers with the line:</P>
+<UL>
+<PRE>
+BrowseRelay 127.0.0.1 255.255.255.255
+</PRE>
+</UL>
+<P>This effectively provides access to printers on a WAN for all clients
+ on the LAN(s).
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="BrowseShortNames">BrowseShortNames</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+BrowseShortNames Yes
+BrowseShortNames No
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>BrowseShortNames</CODE> directive specifies whether or not
+ short names are used for remote printers when possible. Short names are
+ just the remote printer name, without the server (&quot;printer&quot;). If more
+ than one remote printer is detected with the same name, the printers
+ will have long names (&quot;printer@server1&quot;, &quot;printer@server2&quot;.)</P>
+<P>The default value for this option is <CODE>Yes</CODE>.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="BrowseTimeout">BrowseTimeout</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+BrowseTimeout 300
+BrowseTimeout 60
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>BrowseTimeout</CODE> directive sets the timeout for printer
+ or class information that is received in browse packets. Once a printer
+ or class times out it is removed from the list of available
+ destinations.</P>
+<P>The <CODE>BrowseTimeout</CODE> value should always be greater than
+ the<A HREF="#BrowseInterval"> <CODE>BrowseInterval</CODE></A> value.
+ Otherwise printers and classes will disappear from client systems
+ between updates.
+<!-- NEED 4in -->
+</P>
+<H3><A NAME="Browsing">Browsing</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+Browsing On
+Browsing Off
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>Browsing</CODE> directive controls whether or not network
+ printer browsing is enabled. The default setting is <CODE>On</CODE>.
+<CENTER>
+<TABLE BGCOLOR="#cccccc" BORDER="1" CELLPADDING="5" WIDTH="80%">
+<TR><TD><B> NOTE:</B>
+<P>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.</P>
+</TD></TR>
+</TABLE>
+</CENTER>
+
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="Classification">Classification</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+Classification
+Classification classified
+Classification confidential
+Classification secret
+Classification topsecret
+Classification unclassified
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>Classification</CODE> directive sets the classification
+ level on the server. When this option is set, at least one of the
+ banner pages is forced to the classification level, and the
+ classification is placed on each page of output. The default is no
+ classification level.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="ClassifyOverride">ClassifyOverride</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+ClassifyOverride Yes
+ClassifyOverride No
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>ClassifyOverride</CODE> directive specifies whether users
+ can override the default classification level on the server. When the
+ server classification is set, users can change the classification using
+ the <CODE>job-sheets</CODE> option and can choose to only print one
+ security banner before or after the job. If the <CODE>job-sheets</CODE>
+ option is set to <CODE>none</CODE> then the server default
+ classification is used.</P>
+<P>The default is to not allow classification overrides.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="DataDir">DataDir</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+DataDir /usr/share/cups
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>DataDir</CODE> directive sets the directory to use for data
+ files.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="DefaultCharset">DefaultCharset</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+DefaultCharset utf-8
+DefaultCharset iso-8859-1
+DefaultCharset windows-1251
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>DefaultCharset</CODE> directive sets the default character
+ set to use for client connections. The default character set is <CODE>
+utf-8</CODE> but is overridden by the character set for the language
+ specified by the client or the <CODE>DefaultLanguage</CODE> directive.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="DefaultLanguage">DefaultLanguage</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+DefaultLanguage de
+DefaultLanguage en
+DefaultLanguage es
+DefaultLanguage fr
+DefaultLanguage it
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>DefaultLanguage</CODE> directive specifies the default
+ language to use for client connections. Setting the default language
+ also sets the default character set if a language localization file
+ exists for it. The default language is &quot;en&quot; for English.
+<!-- NEED 5in -->
+</P>
+<H3><A NAME="Deny">Deny</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+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
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>Deny</CODE> directive specifies a hostname, IP address, or
+ network that is allowed access to the server. <CODE>Deny</CODE>
+ directives are cummulative, so multiple <CODE>Deny</CODE> directives
+ can be used to allow access for multiple hosts or networks. The <CODE>
+/mm</CODE> notation specifies a CIDR netmask:
+<CENTER>
+<TABLE BORDER="1">
+<TR><TH WIDTH="10%">mm</TH><TH WIDTH="20%">netmask</TH><TH WIDTH="10%">
+mm</TH><TH WIDTH="20%">netmask</TH></TR>
+<TR><TD ALIGN="CENTER">0</TD><TD ALIGN="CENTER">0.0.0.0</TD><TD ALIGN="CENTER">
+8</TD><TD ALIGN="CENTER">255.0.0.0</TD></TR>
+<TR><TD ALIGN="CENTER">1</TD><TD ALIGN="CENTER">128.0.0.0</TD><TD ALIGN="CENTER">
+16</TD><TD ALIGN="CENTER">255.255.0.0</TD></TR>
+<TR><TD ALIGN="CENTER">2</TD><TD ALIGN="CENTER">192.0.0.0</TD><TD ALIGN="CENTER">
+24</TD><TD ALIGN="CENTER">255.255.255.0</TD></TR>
+<TR><TD ALIGN="CENTER">...</TD><TD ALIGN="CENTER">...</TD><TD ALIGN="CENTER">
+32</TD><TD ALIGN="CENTER">255.255.255.255</TD></TR>
+</TABLE>
+</CENTER>
+</P>
+<P>The <CODE>Deny</CODE> directive must appear inside a<A HREF="#Location">
+ <CODE>Location</CODE></A> directive.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="DocumentRoot">DocumentRoot</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+DocumentRoot /usr/share/doc/cups
+DocumentRoot /foo/bar/doc/cups
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>DocumentRoot</CODE> directive specifies the location of web
+ content for the HTTP server in CUPS. If an absolute path is not
+ specified then it is assumed to be relative to the<A HREF="#ServerRoot">
+ <CODE>ServerRoot</CODE></A> directory. The default directory is<VAR>
+ /usr/share/doc/cups</VAR>.</P>
+<P>Documents are first looked up in a sub-directory for the primary
+ language requested by the client (e.g.<VAR> /usr/share/doc/cups/fr/...</VAR>
+) and then directly under the <CODE>DocumentRoot</CODE> directory (e.g.<VAR>
+ /usr/share/doc/cups/...</VAR>), so it is possible to localize the web
+ content by providing subdirectories for each language needed.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="Encryption">Encryption</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+Encryption Never
+Encryption IfRequested
+Encryption Required
+Encryption Always
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>Encryption</CODE> directive must appear instead a<A HREF="#Location">
+ <CODE>Location</CODE></A> section and specifies the encryption settings
+ for that location. The default setting is <CODE>IfRequested</CODE> for
+ all locations.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="ErrorLog">ErrorLog</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+ErrorLog /var/log/cups/error_log
+ErrorLog /var/log/cups/error_log-%s
+ErrorLog syslog
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>ErrorLog</CODE> directive sets the name of the error log
+ file. If the filename is not absolute then it is assumed to be relative
+ to the<A HREF="#ServerRoot"> <CODE>ServerRoot</CODE></A> directory. The
+ default error log file is<VAR> /var/log/cups/error_log</VAR>.</P>
+<P>The server name can be included in the filename by using <CODE>%s</CODE>
+ in the name.</P>
+<P>The special name &quot;syslog&quot; can be used to send the error information
+ to the system log instead of a plain file.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="FilterLimit">FilterLimit</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+FilterLimit 0
+FilterLimit 200
+FilterLimit 1000
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>FilterLimit</CODE> directive sets the maximum cost of all
+ running job filters. It can be used to limit the number of filter
+ programs that are run on a server to minimize disk, memory, and CPU
+ resource problems. A limit of 0 disables filter limiting.</P>
+<P>An average print to a non-PostScript printer needs a filter limit of
+ about 200. A PostScript printer needs about half that (100). Setting
+ the limit below these thresholds will effectively limit the scheduler
+ to printing a single job at any time.</P>
+<P>The default limit is 0.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="FontPath">FontPath</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+FontPath /foo/bar/fonts
+FontPath /usr/share/cups/fonts:/foo/bar/fonts
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>FontPath</CODE> directive specifies the font path to use
+ when searching for fonts. The default font path is <CODE>
+/usr/share/cups/fonts</CODE>.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="Group">Group</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+Group sys
+Group system
+Group root
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>Group</CODE> directive specifies the UNIX group that filter
+ and CGI programs run as. The default group is <CODE>sys</CODE>, <CODE>
+system</CODE>, or <CODE>root</CODE> depending on the operating system.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="HideImplicitMembers">HideImplicitMembers</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+HideImplicitMembers Yes
+HideImplicitMembers No
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>HideImplicitMembers</CODE> directive controls whether the
+ individual printers in an implicit class are shown to the user. The
+ default is <CODE>No</CODE>.</P>
+<P><A HREF="#ImplicitClasses"><CODE>ImplicitClasses</CODE></A> must be
+ enabled for this directive to have any effect.</P>
+
+<!-- NEED 3in -->
+<H3><A NAME="HostNameLookups">HostNameLookups</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+HostNameLookups On
+HostNameLookups Off
+HostNameLookups Double
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>HostNameLookups</CODE> directive controls whether or not
+ CUPS looks up the hostname for connecting clients. The <CODE>Double</CODE>
+ setting causes CUPS to verify that the hostname resolved from the
+ address matches one of the addresses returned for that hostname. <CODE>
+Double</CODE> lookups also prevent clients with unregistered addresses
+ from connecting to your server. The default is <CODE>Off</CODE> to
+ avoid the potential server performance problems with hostname lookups.
+ Set this option to <CODE>On</CODE> or <CODE>Double</CODE> only if
+ absolutely required.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="ImplicitClasses">ImplicitClasses</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+ImplicitClasses On
+ImplicitClasses Off
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>ImplicitClasses</CODE> directive controls whether implicit
+ classes are created based upon the available network printers and
+ classes. The default setting is <CODE>On</CODE> but is automatically
+ turned <CODE>Off</CODE> if<A HREF="#Browsing"> <CODE>Browsing</CODE></A>
+ is turned <CODE>Off</CODE>.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="ImplicitAnyClasses">ImplicitAnyClasses</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+ImplicitAnyClasses On
+ImplicitAnyClasses Off
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>ImplicitAnyClasses</CODE> directive controls whether
+ implicit classes for local and remote printers are created with the
+ name <CODE>AnyPrinter</CODE>. The default setting is <CODE>Off</CODE>.</P>
+<P><A HREF="#ImplicitClasses"><CODE>ImplicitClasses</CODE></A> must be
+ enabled for this directive to have any effect.</P>
+
+<!-- NEED 3in -->
+<H3><A NAME="Include">Include</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+Include filename
+Include /foo/bar/filename
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>Include</CODE> directive includes the named file in the <CODE>
+cupsd.conf</CODE> file. If no leading path is provided, the file is
+ assumed to be relative to the<A HREF="#ServerRoot"> <CODE>ServerRoot</CODE>
+</A> directory.</P>
+
+<!-- NEED 3in -->
+<H3><A NAME="KeepAlive">KeepAlive</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+KeepAlive On
+KeepAlive Off
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>KeepAlive</CODE> directive controls whether or not to
+ support persistent HTTP connections. The default is <CODE>On</CODE>.</P>
+<P>HTTP/1.1 clients automatically support persistent connections, while
+ HTTP/1.0 clients must specifically request them using the <CODE>
+Keep-Alive</CODE> attribute in the <CODE>Connection:</CODE> field of
+ each request.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="KeepAliveTimeout">KeepAliveTimeout</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+KeepAliveTimeout 60
+KeepAliveTimeout 30
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>KeepAliveTimeout</CODE> directive controls how long a
+ persistent HTTP connection will remain open after the last request. The
+ default is 60 seconds.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="Limit">Limit</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+&lt;Limit GET POST&gt;
+...
+&lt;/Limit&gt;
+
+&lt;Limit ALL&gt;
+...
+&lt;/Limit&gt;
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>Limit</CODE> directive groups access control directives for
+ specific types of HTTP requests and must appear inside a<A HREF="#Location">
+ <CODE>Location</CODE></A> section. Access can be limited for individual
+ request types (<CODE>DELETE</CODE>, <CODE>GET</CODE>, <CODE>HEAD</CODE>
+, <CODE>OPTIONS</CODE>, <CODE>POST</CODE>, <CODE>PUT</CODE>, and <CODE>
+TRACE</CODE>) or for all request types (<CODE>ALL</CODE>). The request
+ type names are case-sensitive for compatibility with Apache.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="LimitExcept">LimitExcept</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+&lt;LimitExcept GET POST&gt;
+...
+&lt;/LimitExcept&gt;
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>LimitExcept</CODE> directive groups access control
+ directives for specific types of HTTP requests and must appear inside a<A
+HREF="#Location"> <CODE>Location</CODE></A> section. Unlike the<A HREF="#Limit">
+ <CODE>Limit</CODE></A> directive, <CODE>LimitExcept</CODE> restricts
+ access for all requests<I> except</I> those listed on the <CODE>
+LimitExcept</CODE> line.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="LimitRequestBody">LimitRequestBody</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+LimitRequestBody 10485760
+LimitRequestBody 10m
+LimitRequestBody 0
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>LimitRequestBody</CODE> directive controls the maximum size
+ of print files, IPP requests, and HTML form data in HTTP POST requests.
+ The default limit is 0 which disables the limit check.</P>
+<P>Also see the identical<A HREF="#MaxRequestSize"> <CODE>MaxRequestSize</CODE>
+</A> directive.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="Listen">Listen</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+Listen 127.0.0.1:631
+Listen 192.0.2.1:631
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>Listen</CODE> directive specifies a network address and
+ port to listen for connections. Multiple <CODE>Listen</CODE> directives
+ can be provided to listen on multiple addresses.</P>
+<P>The <CODE>Listen</CODE> directive is similar to the<A HREF="#Port"> <CODE>
+Port</CODE></A> directive but allows you to restrict access to specific
+ interfaces or networks.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="Location">Location</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+&lt;Location /&gt;
+...
+&lt;/Location&gt;
+
+&lt;Location /admin&gt;
+...
+&lt;/Location&gt;
+
+&lt;Location /printers/name&gt;
+...
+&lt;/Location&gt;
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>Location</CODE> directive specifies access control and
+ authentication options for the specified HTTP resource or path. More
+ information can be found later in this chapter in<A HREF="#PRINTING_SECURITY">
+ &quot;Printing System Security&quot;</A>.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="LogLevel">LogLevel</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+LogLevel none
+LogLevel emerg
+LogLevel alert
+LogLevel crit
+LogLevel error
+LogLevel warn
+LogLevel notice
+LogLevel info
+LogLevel debug
+LogLevel debug2
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>LogLevel</CODE> directive specifies the level of logging
+ for the<A HREF="#ErrorLog"> <CODE>ErrorLog</CODE></A> file. The
+ following values are recognized (each level logs everything under the
+ preceding levels):</P>
+<UL>
+<LI><CODE>none</CODE> - Log nothing.</LI>
+<LI><CODE>emerg</CODE> - Log emergency conditions that prevent the
+ server from running.</LI>
+<LI><CODE>alert</CODE> - Log alerts that must be handled immediately.</LI>
+<LI><CODE>crit</CODE> - Log critical errors that don't prevent the
+ server from running.</LI>
+<LI><CODE>error</CODE> - Log general errors.</LI>
+<LI><CODE>warn</CODE> - Log errors and warnings.</LI>
+<LI><CODE>notice</CODE> - Log temporary error conditions.</LI>
+<LI><CODE>info</CODE> - Log all requests and state changes (default).</LI>
+<LI><CODE>debug</CODE> - Log basic debugging information.</LI>
+<LI><CODE>debug2</CODE> - Log all debugging information.</LI>
+</UL>
+
+<!-- NEED 3in -->
+<H3><A NAME="MaxClients">MaxClients</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+MaxClients 100
+MaxClients 1024
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>MaxClients</CODE> directive controls the maximum number of
+ simultaneous clients that will be allowed by the server. The default is
+ 100 clients.
+<CENTER>
+<TABLE BGCOLOR="#cccccc" BORDER="1" CELLPADDING="5" WIDTH="80%">
+<TR><TD><B> NOTE:</B>
+<P>Since each print job requires a file descriptor for the status pipe,
+ the CUPS server internally limits the <CODE>MaxClients</CODE> value to
+ 1/3 of the available file descriptors to avoid possible problems when
+ printing large numbers of jobs.</P>
+</TD></TR>
+</TABLE>
+</CENTER>
+
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="MaxJobs">MaxJobs</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+MaxJobs 100
+MaxJobs 9999
+MaxJobs 0
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>MaxJobs</CODE> directive controls the maximum number of
+ jobs that are kept in memory. Once the number of jobs reaches the
+ limit, the oldest completed job is automatically purged from the system
+ to make room for the new one. If all of the known jobs are still
+ pending or active then the new job will be rejected.</P>
+<P>Setting the maximum to 0 disables this functionality. The default
+ setting is 0.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="MaxJobsPerPrinter">MaxJobsPerPrinter</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+MaxJobsPerPrinter 100
+MaxJobsPerPrinter 9999
+MaxJobsPerPrinter 0
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>MaxJobsPerPrinter</CODE> directive controls the maximum
+ number of active jobs that are allowed for each printer or class. Once
+ a printer or class reaches the limit, new jobs will be rejected until
+ one of the active jobs is completed, stopped, aborted, or cancelled.</P>
+<P>Setting the maximum to 0 disables this functionality. The default
+ setting is 0.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="MaxJobsPerUser">MaxJobsPerUser</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+MaxJobsPerUser 100
+MaxJobsPerUser 9999
+MaxJobsPerUser 0
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>MaxJobsPerUser</CODE> directive controls the maximum number
+ of active jobs that are allowed for each user. Once a user reaches the
+ limit, new jobs will be rejected until one of the active jobs is
+ completed, stopped, aborted, or cancelled.</P>
+<P>Setting the maximum to 0 disables this functionality. The default
+ setting is 0.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="MaxLogSize">MaxLogSize</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+MaxLogSize 1048576
+MaxLogSize 1m
+MaxLogSize 0
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>MaxLogSize</CODE> directive controls the maximum size of
+ each log file. Once a log file reaches or exceeds the maximum size it
+ is closed and renamed to<VAR> filename.O</VAR>. This allows you to
+ rotate the logs automatically. The default size is 1048576 bytes (1MB).</P>
+<P>Setting the maximum size to 0 disables log rotation.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="MaxRequestSize">MaxRequestSize</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+MaxRequestSize 10485760
+MaxRequestSize 10m
+MaxRequestSize 0
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>MaxRequestSize</CODE> directive controls the maximum size
+ of print files, IPP requests, and HTML form data in HTTP POST requests.
+ The default limit is 0 which disables the limit check.</P>
+<P>Also see the identical<A HREF="#LimitRequestBody"> <CODE>
+LimitRequestBody</CODE></A> directive.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="Order">Order</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+Order Allow,Deny
+Order Deny,Allow
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>Order</CODE> directive defines the default access control.
+ The following values are supported:</P>
+<UL>
+<LI><CODE>Allow,Deny</CODE> - Allow requests from all systems<I> except</I>
+ for those listed in a <CODE>Deny</CODE> directive.</LI>
+<LI><CODE>Deny,Allow</CODE> - Allow requests only from those listed in
+ an <CODE>Allow</CODE> directive.</LI>
+</UL>
+<P>The <CODE>Order</CODE> directive must appear inside a<A HREF="#Location">
+ <CODE>Location</CODE></A> directive.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="PageLog">PageLog</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+PageLog /var/log/cups/page_log
+PageLog /var/log/cups/page_log-%s
+PageLog syslog
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>PageLog</CODE> directive sets the name of the page log
+ file. If the filename is not absolute then it is assumed to be relative
+ to the<A HREF="#ServerRoot"> <CODE>ServerRoot</CODE></A> directory. The
+ default page log file is<VAR> /var/log/cups/page_log</VAR>.</P>
+<P>The server name can be included in the filename by using <CODE>%s</CODE>
+ in the name.</P>
+<P>The special name &quot;syslog&quot; can be used to send the page information to
+ the system log instead of a plain file.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="Port">Port</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+Port 631
+Port 80
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>Port</CODE> directive specifies a port to listen on.
+ Multiple <CODE>Port</CODE> lines can be specified to listen on multiple
+ ports. The default port is 631.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="PreserveJobHistory">PreserveJobHistory</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+PreserveJobHistory On
+PreserveJobHistory Off
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>PreserveJobHistory</CODE> directive controls whether the
+ history of completed, cancelled, or aborted print jobs is stored on
+ disk.</P>
+<P>A value of <CODE>On</CODE> (the default) preserves job information
+ until the administrator purges it with the <CODE>cancel</CODE> command.</P>
+<P>A value of <CODE>Off</CODE> removes the job information as soon as
+ each job is completed, cancelled, or aborted.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="PreserveJobFiles">PreserveJobFiles</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+PreserveJobFiles On
+PreserveJobFiles Off
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>PreserveJobFiles</CODE> directive controls whether the
+ document files of completed, cancelled, or aborted print jobs are
+ stored on disk.</P>
+<P>A value of <CODE>On</CODE> preserves job files until the
+ administrator purges them with the <CODE>cancel</CODE> command. Jobs
+ can be restarted (and reprinted) as desired until they are purged.</P>
+<P>A value of <CODE>Off</CODE> (the default) removes the job files as
+ soon as each job is completed, cancelled, or aborted.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="Printcap">Printcap</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+Printcap
+Printcap /etc/printcap
+Printcap /etc/printers.conf
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>Printcap</CODE> directive controls whether or not a
+ printcap file is automatically generated and updated with a list of
+ available printers. If specified with no value, then no printcap file
+ will be generated. The default is to generate a file named<VAR>
+ /etc/printcap</VAR>.</P>
+<P>When a filename is specified (e.g.<VAR> /etc/printcap</VAR>), the
+ printcap file is written whenever a printer is added or removed. The
+ printcap file can then be used by applications that are hardcoded to
+ look at the printcap file for the available printers.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="PrintcapFormat">PrintcapFormat</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+PrintcapFormat BSD
+PrintcapFormat Solaris
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>PrintcapFormat</CODE> directive controls the output format
+ of the printcap file. The default is to generate a BSD printcap file.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="PrintcapGUI">PrintcapGUI</A></H3>
+<HR>
+<H4>Example</H4>
+<UL>
+<PRE>
+PrintcapGUI /usr/bin/glpoptions
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>PrintcapGUI</CODE> directive sets the program to use when
+ displaying an option panel from an IRIX application that uses the
+ Impressario print API. The default program is the ESP Print Pro
+ &quot;glpoptions&quot; GUI.</P>
+<P>The program must accept the <CODE>-d</CODE> option to specify a
+ printer and the <CODE>-o</CODE> option to specify one or more options.
+ After allowing the user to select/change options, the program must then
+ write the list of printing options without the <CODE>-o</CODE> to the
+ standard output.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="RemoteRoot">RemoteRoot</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+RemoteRoot remroot
+RemoteRoot root
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>RemoteRoot</CODE> directive sets the username for
+ unauthenticated root requests from remote hosts. The default username
+ is<VAR> remroot</VAR>. Setting <CODE>RemoteRoot</CODE> to<VAR> root</VAR>
+ effectively disables this security mechanism.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="RequestRoot">RequestRoot</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+RequestRoot /var/spool/cups
+RequestRoot /foo/bar/spool/cups
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>RequestRoot</CODE> directive sets the directory for
+ incoming IPP requests and HTML forms. If an absolute path is not
+ provided then it is assumed to be relative to the<A HREF="#ServerRoot">
+ <CODE>ServerRoot</CODE></A> directory. The default request directory is<VAR>
+ /var/spool/cups</VAR>.
+<!-- NEED 4in -->
+</P>
+<H3><A NAME="Require">Require</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+Require group foo bar
+Require user john mary
+Require valid-user
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>Require</CODE> directive specifies that authentication is
+ required for the resource. The <CODE>group</CODE> keyword specifies
+ that the authenticated user must be a member of one or more of the
+ named groups that follow.</P>
+<P>The <CODE>user</CODE> keyboard specifies that the authenticated user
+ must be one of the named users that follow.</P>
+<P>The <CODE>valid-user</CODE> keyword specifies that any authenticated
+ user may access the resource.</P>
+<P>The default is to do no authentication. This directive must appear
+ inside a<A HREF="#Location"> <CODE>Location</CODE></A> directive.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="RIPCache">RIPCache</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+RIPCache 8m
+RIPCache 1g
+RIPCache 2048k
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>RIPCache</CODE> directive sets the size of the memory cache
+ used by Raster Image Processor (&quot;RIP&quot;) filters such as <CODE>
+imagetoraster</CODE> and <CODE>pstoraster</CODE>. The size can be
+ suffixed with a &quot;k&quot; for kilobytes, &quot;m&quot; for megabytes, or &quot;g&quot; for
+ gigabytes. The default cache size is &quot;8m&quot;, or 8 megabytes.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="RunAsUser">RunAsUser</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+RunAsUser Yes
+RunAsUser No
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>RunAsUser</CODE> directive controls whether the scheduler
+ runs as the unpriviledged user account (usually <CODE>lp</CODE>). The
+ default is <CODE>No</CODE> which leaves the scheduler running as the <CODE>
+root</CODE> user.</P>
+<P><B>Note:</B> Running as a non-priviledged user may prevent LPD and
+ locally connected printers from working due to permission problems. The
+ <CODE>lpd</CODE> backend will automatically use a non-priviledged mode
+ that is not 100% compliant with RFC 1179. The <CODE>parallel</CODE>, <CODE>
+serial</CODE>, and <CODE>usb</CODE> backends will need write access to
+ the corresponding device files.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="Satisfy">Satisfy</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+Satisfy all
+Satisfy any
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>Satisfy</CODE> directive specifies whether all conditions
+ must be satisfied to allow access to the resource. If set to <CODE>all</CODE>
+, then all authentication and access control conditions must be satified
+ to allow access.</P>
+<P>Setting <CODE>Satisfy</CODE> to <CODE>any</CODE> allows a user to
+ gain access if the authentication or access control requirements are
+ satisfied. For example, you might require authentication for remote
+ access, but allow local access without authentication.</P>
+<P>The default is <CODE>all</CODE>. This directive must appear inside a<A
+HREF="#Location"> <CODE>Location</CODE></A> directive.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="ServerAdmin">ServerAdmin</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+ServerAdmin user@host
+ServerAdmin root@foo.bar.com
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>ServerAdmin</CODE> directive identifies the email address
+ for the administrator on the system. By default the administrator email
+ address is <CODE>root@server</CODE>, where <CODE>server</CODE> is the
+ server name.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="ServerBin">ServerBin</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+ServerBin /usr/lib/cups
+ServerBin /foo/bar/lib/cups
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>ServerBin</CODE> directive sets the directory for
+ server-run executables. If an absolute path is not provided then it is
+ assumed to be relative to the<A HREF="#ServerRoot"> <CODE>ServerRoot</CODE>
+</A> directory. The default executable directory is<VAR> /usr/lib/cups</VAR>
+.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="ServerCertificate">ServerCertificate</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+ServerCertificate /etc/cups/ssl/server.crt
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>ServerCertificate</CODE> directive specifies the location
+ of the SSL certificate file used by the server when negotiating
+ encrypted connections. The certificate must not be encrypted (password
+ protected) since the scheduler normally runs in the background and will
+ be unable to ask for a password. The default certificate file is<VAR>
+ /etc/cups/ssl/server.crt</VAR>.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="ServerKey">ServerKey</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+ServerKey /etc/cups/ssl/server.key
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>ServerKey</CODE> directive specifies the location of the
+ SSL private key file used by the server when negotiating encrypted
+ connections. The default key file is<VAR> /etc/cups/ssl/server.crt</VAR>
+.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="ServerName"></A>ServerName</H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+ServerName foo.domain.com
+ServerName myserver.domain.com
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>ServerName</CODE> directive specifies the hostname that is
+ reported to clients. By default the server name is the hostname.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="ServerRoot">ServerRoot</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+ServerRoot /etc/cups
+ServerRoot /foo/bar/cups
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>ServerRoot</CODE> directive specifies the absolute path to
+ the server configuration and state files. It is also used to resolve
+ relative paths in the<VAR> cupsd.conf</VAR> file. The default server
+ directory is<VAR> /etc/cups</VAR>.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="SSLListen">SSLListen</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+SSLListen 127.0.0.1:443
+SSLListen 192.0.2.1:443
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>SSLListen</CODE> directive specifies a network address and
+ port to listen for secure connections. Multiple <CODE>SSLListen</CODE>
+ directives can be provided to listen on multiple addresses.</P>
+<P>The <CODE>SSLListen</CODE> directive is similar to the<A HREF="#SSLPort">
+ <CODE>SSLPort</CODE></A> directive but allows you to restrict access to
+ specific interfaces or networks.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="SSLPort">SSLPort</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+SSLPort 443
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>SSLPort</CODE> directive specifies a port to listen on for
+ secure connections. Multiple <CODE>SSLPort</CODE> lines can be
+ specified to listen on multiple ports.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="SystemGroup">SystemGroup</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+SystemGroup sys
+SystemGroup system
+SystemGroup root
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>SystemGroup</CODE> directive specifies the system
+ administration group for <CODE>System</CODE> authentication. More
+ information can be found later in this chapter in<A HREF="#PRINTING_SECURITY">
+ &quot;Printing System Security&quot;</A>.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="TempDir">TempDir</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+TempDir /var/tmp
+TempDir /foo/bar/tmp
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>TempDir</CODE> directive specifies an absolute path for the
+ directory to use for temporary files. The default directory is<VAR>
+ /var/tmp</VAR>.</P>
+<P>Temporary directories must be world-writable and should have the
+ &quot;sticky&quot; permission bit enabled so that other users cannot delete
+ filter temporary files. The following commands will create an
+ appropriate temporary directory called<VAR> /foo/bar/tmp</VAR>:</P>
+<UL>
+<PRE>
+<B>mkdir /foo/bar/tmp ENTER</B>
+<B>chmod a+rwxt /foo/bar/tmp ENTER</B>
+</PRE>
+</UL>
+
+<!-- NEED 3in -->
+<H3><A NAME="Timeout">Timeout</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+Timeout 300
+Timeout 90
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>Timeout</CODE> directive controls the amount of time to
+ wait before an active HTTP or IPP request times out. The default
+ timeout is 300 seconds.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="User">User</A></H3>
+<HR>
+<H4>Examples</H4>
+<UL>
+<PRE>
+User lp
+User guest
+</PRE>
+</UL>
+<H4>Description</H4>
+<P>The <CODE>User</CODE> directive specifies the UNIX user that filter
+ and CGI programs run as. The default user is <CODE>lp</CODE>.
+<!-- NEW PAGE -->
+</P>
+<H2><A NAME="PRINTING_SECURITY">Printing System Security</A></H2>
+<P>CUPS provides support for address, certificate, and password (Basic
+ and Digest) based authentication and access control. Certificate and
+ password authentication provide ways to limit access to individual
+ people or groups.</P>
+<P>Address based access control allows you to limit access to specific
+ systems, networks, or domains. While this does not provide
+ authentication, it does allow you to limit the potential users of your
+ system efficiently.</P>
+<P>CUPS maintains a list of locations that have access control and/or
+ authentication enabled. Locations are specified using the<A HREF="#Location">
+ <CODE>Location</CODE></A> directive:</P>
+<UL>
+<PRE>
+&lt;Location /resource&gt;
+<A HREF="#AuthClass">AuthClass</A> ...
+<A HREF="#AuthGroupName">AuthGroupName</A> ...
+<A HREF="#AuthType">AuthType</A> ...
+
+<A HREF="#Order">Order</A> ...
+<A HREF="#Allow">Allow</A> from ...
+<A HREF="#Deny">Deny</A> from ...
+&lt;/Location&gt;
+</PRE>
+</UL>
+<P>Locations generally follow the directory structure of the<A HREF="#DocumentRoot">
+ <CODE>DocumentRoot</CODE></A> directory, however CUPS does have several
+ virtual locations for administration, classes, jobs, and printers:
+<CENTER>
+<TABLE BORDER="1">
+<TR><TH>Location</TH><TH>Description</TH></TR>
+<TR><TD>/admin</TD><TD>The path for all administration operations.</TD></TR>
+<TR><TD>/classes</TD><TD>The path for all classes.</TD></TR>
+<TR><TD>/classes/name</TD><TD>The resource for class <CODE>name</CODE>.</TD>
+</TR>
+<TR><TD>/jobs</TD><TD>The path for all jobs.</TD></TR>
+<TR><TD>/jobs/id</TD><TD>The resource for job <CODE>id</CODE>.</TD></TR>
+<TR><TD>/printers</TD><TD>The path for all printers.</TD></TR>
+<TR><TD>/printers/name</TD><TD>The path for printer <CODE>name</CODE>.</TD>
+</TR>
+<TR><TD>/printers/name.ppd</TD><TD>The PPD file path for printer <CODE>
+name</CODE>.</TD></TR>
+</TABLE>
+</CENTER>
+</P>
+<H3><A NAME="CERTIFICATES">Authentication Using Certificates</A></H3>
+<P>CUPS supports a local certificate-based authentication scheme that
+ can be used in place of <CODE>Basic</CODE> or <CODE>Digest</CODE>
+ authentication by clients connecting through the <CODE>localhost</CODE>
+ interface. Certificate authentication is not supported or allowed from
+ clients on any other interface.</P>
+<P>Certificates are 128-bit random numbers that refer to an internal
+ authentication record in the server. A client connecting via the <CODE>
+localhost</CODE> interface sends a request with an authorization header
+ of:</P>
+<UL>
+<PRE>
+Authorization: Local 0123456789ABCDEF0123456789ABCDEF
+</PRE>
+</UL>
+<P>The server then looks up the local certificate and authenticates
+ using the username associated with it.</P>
+<P>Certificates are generated by the server automatically and stored in
+ the<VAR> /etc/cups/certs</VAR> directory using the process ID of the
+ CGI program started by the server. Certificate files are only readable
+ by the<A HREF="#User"> <CODE>User</CODE></A> and<A HREF="#Group"> <CODE>
+Group</CODE></A> defined in the<VAR> cupsd.conf</VAR> file. When the CGI
+ program ends the certificate is removed and invalidated automatically.</P>
+<P>The special file<VAR> /etc/cups/certs/0</VAR> defines the<I> root
+ certificate</I> which can be used by any client running as the
+ super-user or another user that is part of the group defined by the<A HREF="#SystemGroup">
+ <CODE>SystemGroup</CODE></A> directive. The root certificate is
+ automatically regenerated every 5 minutes.</P>
+<H3><A NAME="7_5_2">Using Basic Authentication</A></H3>
+<P>Basic authentication uses UNIX users and passwords to authenticate
+ access to resources such as printers and classes, and to limit access
+ to administrative functions.
+<CENTER>
+<TABLE BGCOLOR="#cccccc" BORDER="1" CELLPADDING="5" WIDTH="80%">
+<TR><TD><B> NOTE:</B>
+<P>Basic authentication sends the username and password Base64 encoded
+ from the client to the server, so it offers no protection against
+ eavesdropping. This means that a malicious user can monitor network
+ packets and discover valid users and passwords that could result in a
+ serious compromise in network security. Use Basic authentication with
+ extreme care.</P>
+</TD></TR>
+</TABLE>
+</CENTER>
+</P>
+<P>The CUPS implementation of Basic authentication does not allow access
+ through user accounts without a password. If you try to authenticate
+ using an account without a password, your access will be immediately
+ blocked.</P>
+<P>Once a valid username and password is authenticated by CUPS, any
+ additional group membership requirements are checked.
+<CENTER>
+<TABLE BGCOLOR="#cccccc" BORDER="1" CELLPADDING="5" WIDTH="80%">
+<TR><TD><B> NOTE:</B>
+<P>The root user is considered by CUPS to be a member of every group.</P>
+</TD></TR>
+</TABLE>
+</CENTER>
+
+<!-- NEED 1in -->
+</P>
+<P>Use the <CODE>AuthType</CODE> directive to enable Basic
+ authentication:</P>
+<UL>
+<PRE>
+AuthType Basic
+</PRE>
+</UL>
+
+<!-- NEED 7in -->
+<H3><A NAME="7_5_3">Using Digest Authentication</A></H3>
+<P>Digest authentication uses users and passwords defined in the<VAR>
+ /etc/cups/passwd.md5</VAR> file to authenticate access to resources
+ such as printers and classes, and to limit access to administrative
+ functions.
+<CENTER>
+<TABLE BGCOLOR="#cccccc" BORDER="1" CELLPADDING="5" WIDTH="80%">
+<TR><TD><B> NOTE:</B>
+<P>Unlike Basic authentication, Digest passes the MD5 sum (basically a
+ complicated checksum) of the username and password instead of the
+ strings themselves. Also, Digest authentication does not use the UNIX
+ password file, so if an attacker does discover the original password it
+ is less likely to result in a serious security problem so long as you
+ use a different UNIX password than the corresponding Digest password.</P>
+<P>The current CUPS implementation of Digest authentication uses the
+ client's hostname or IP address for the &quot;nonce&quot; value. The nonce value
+ is an additional string added to the username and password to make
+ guessing the password more difficult. The server checks that the nonce
+ value matches the client's hostname or address and rejects the MD5 sum
+ if it doesn't. Future versions of CUPS will support Digest &quot;session&quot;
+ authentication which adds the request data to the MD5 sum, providing
+ even better authentication and security.</P>
+<P>Digest authentication does not guarantee that an attacker cannot gain
+ unauthorized access, but it is safer than Basic authentication and
+ should be used in place of Basic authentication whenever possible.<B>
+ Support for Digest authentication in web browsers is not yet
+ universally available.</B></P>
+</TD></TR>
+</TABLE>
+</CENTER>
+
+<!-- NEED 2in -->
+</P>
+<P>The <CODE>lppasswd(1)</CODE> command is used to add, change, or
+ remove accounts from the<VAR> passwd.md5</VAR> file. To add a user to
+ the default system group, type:</P>
+<UL>
+<PRE>
+<B>lppasswd -a user ENTER</B>
+Password: <B>(password) ENTER</B> [password is not echoed]
+Password again: <B>(password) ENTER</B> [password is not echoed]
+</PRE>
+</UL>
+
+<!-- NEED 2in -->
+<P>Once added, a user can change his/her password by typing:</P>
+<UL>
+<PRE>
+<B>lppasswd ENTER</B>
+Old password: <B>(password) ENTER</B> [password is not echoed]
+Password: <B>(password) ENTER</B> [password is not echoed]
+Password again: <B>(password) ENTER</B> [password is not echoed]
+</PRE>
+</UL>
+
+<!-- NEED 1in -->
+<P>To remove a user from the password file, type:</P>
+<UL>
+<PRE>
+<B>lppasswd -x user ENTER</B>
+</PRE>
+</UL>
+<P>Once a valid username and password is authenticated by CUPS, any
+ additional group membership requirements are checked.
+<CENTER>
+<TABLE BGCOLOR="#cccccc" BORDER="1" CELLPADDING="5" WIDTH="80%">
+<TR><TD><B> NOTE:</B>
+<P>The root user is considered by CUPS to be a member of every group.</P>
+</TD></TR>
+</TABLE>
+</CENTER>
+</P>
+<P>Use the <CODE>AuthType</CODE> directive to enable Digest
+ authentication:</P>
+<UL>
+<PRE>
+AuthType Digest
+</PRE>
+</UL>
+<H3><A NAME="7_5_4">System and Group Authentication</A></H3>
+<P>The<A HREF="#AuthClass"> <CODE>AuthClass</CODE></A> directive
+ controls the level of authentication to perform. <CODE>System</CODE>
+ and <CODE>Group</CODE> authentication extend the normal user-based
+ authentication to require membership in a UNIX group. For <CODE>System</CODE>
+ authentication each user must belong to the <CODE>sys</CODE>, <CODE>
+system</CODE>, or <CODE>root</CODE> group; the actual group depends on
+ the operating system.</P>
+<P>For <CODE>Group</CODE> authentication each user must belong to the
+ group named by the<A HREF="#AuthGroupName"> <CODE>AuthGroupName</CODE></A>
+ directive:</P>
+<UL>
+<PRE>
+&lt;Location /path&gt;
+AuthType Digest
+AuthClass Group
+AuthGroupName mygroup
+&lt;/Location&gt;
+</PRE>
+</UL>
+<P>The named group must be a valid UNIX user group, usually defined in
+ the<VAR> /etc/group</VAR> or<VAR> /etc/netgroup</VAR> files.
+ Additionally, when using Digest authentication you need to create user
+ accounts with the named group:</P>
+<UL>
+<PRE>
+<B>lppasswd -g mygroup -a user ENTER</B>
+Password: <B>(password) ENTER</B> [password is not echoed]
+Password again: <B>(password) ENTER</B> [password is not echoed]
+</PRE>
+</UL>
+
+<!-- NEW PAGE -->
+<H2><A NAME="PRINTER_ACCOUNTING">Printer Accounting</A></H2>
+<P>ESP Print Pro maintains a log of all accesses, errors, and pages that
+ are printed. The log files are normally stored in the<VAR>
+ /var/log/cups</VAR> directory. You can change this by editing the<VAR>
+ /etc/cups/cupsd.conf</VAR> configuration file.</P>
+<H3><A NAME="7_6_1">The access_log File</A></H3>
+<P>The<VAR> access_log</VAR> file lists each HTTP resource that is
+ accessed by a web browser or CUPS/IPP client. Each line is in the
+ so-called &quot;Common Log Format&quot; used by many web servers and web
+ reporting tools:</P>
+<UL>
+<PRE>
+host group user date-time \&quot;method resource version\&quot; status bytes
+
+127.0.0.1 - - [20/May/1999:19:20:29 +0000] &quot;POST /admin/ HTTP/1.1&quot; 401 0
+127.0.0.1 - mike [20/May/1999:19:20:31 +0000] &quot;POST /admin/ HTTP/1.1&quot; 200 0
+</PRE>
+</UL>
+<P>The<I> host</I> field will normally only be an IP address unless you
+ have enabled the<A HREF="#HostNameLookups"> <CODE>HostNameLookups</CODE>
+</A> directive in the<VAR> cupsd.conf</VAR> file.</P>
+<P>The<I> group</I> field always contains &quot;-&quot; in CUPS.</P>
+<P>The<I> user</I> field is the authenticated username of the requesting
+ user. If no username and password is supplied for the request then this
+ field contains &quot;-&quot;.</P>
+<P>The<I> date-time</I> field is the date and time of the request in
+ local time and is in the format:</P>
+<UL>
+<PRE>
+[DD/MON/YYYY:HH:MM:SS +ZZZZ]
+</PRE>
+</UL>
+<P>where<I> ZZZZ</I> is the timezone offset in hours and minutes from
+ Greenwich Mean Time (a.k.a. GMT a.k.a. ZULU.)</P>
+<P>The<I> method</I> field is the HTTP method used (&quot;GET&quot;, &quot;PUT&quot;,
+ &quot;POST&quot;, etc.)</P>
+<P>The<I> resource</I> field is the filename of the requested resource.</P>
+<P>The<I> version</I> field is the HTTP specification version used by
+ the client. For CUPS clients this will always be &quot;HTTP/1.1&quot;.</P>
+<P>The<I> status</I> field contains the HTTP result status of the
+ request. Usually it is &quot;200&quot;, but other HTTP status codes are possible.
+ For example, 401 is the &quot;unauthorized access&quot; status in the example
+ above.</P>
+<P>The<I> bytes</I> field contains the number of bytes in the request.
+ For POST requests the<I> bytes</I> field contains the number of bytes
+ that was received from the client.</P>
+<H3><A NAME="7_6_2">The error_log File</A></H3>
+<P>The<VAR> error_log</VAR> file lists messages from the scheduler
+ (errors, warnings, etc.):</P>
+<UL>
+<PRE>
+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'.
+</PRE>
+</UL>
+<P>The<I> level</I> field contains the type of message:</P>
+<UL>
+<LI><CODE>E</CODE> - An error occurred.</LI>
+<LI><CODE>W</CODE> - The server was unable to perform some action.</LI>
+<LI><CODE>I</CODE> - Informational message.</LI>
+<LI><CODE>D</CODE> - Debugging message.</LI>
+</UL>
+<P>The<I> date-time</I> field contains the date and time of when the
+ page started printing. The format of this field is identical to the<I>
+ data-time</I> field in the<VAR> access_log</VAR> file.</P>
+<P>The<I> message</I> fields contains a free-form textual message.</P>
+<H3><A NAME="7_6_3">The page_log File</A></H3>
+<P>The<VAR> page_log</VAR> file lists each page that is sent to a
+ printer. Each line contains the following information:</P>
+<UL>
+<PRE>
+printer user job-id date-time page-number num-copies job-billing
+
+DeskJet root 2 [20/May/1999:19:21:05 +0000] 1 0 acme-123
+</PRE>
+</UL>
+<P>The<I> printer</I> 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.</P>
+<P>The<I> user</I> field contains the name of the user (the IPP <CODE>
+requesting-user-name</CODE> attribute) that submitted this file for
+ printing.</P>
+<P>The<I> job-id</I> 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!</P>
+<P>The<I> date-time</I> field contains the date and time of when the
+ page started printing. The format of this field is identical to the<I>
+ data-time</I> field in the<VAR> access_log</VAR> file.</P>
+<P>The<I> page-number</I> and<I> num-pages</I> 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<I> num-pages</I> field
+ will always be 1.</P>
+<P>The<I> job-billing</I> field contains a copy of the <CODE>job-billing</CODE>
+ attribute provided with the IPP <CODE>create-job</CODE> or <CODE>
+print-job</CODE> requests or &quot;-&quot; if none was provided.
+<!-- NEW PAGE -->
+</P>
+<H2><A NAME="FILE_TYPING_FILTERING">File Typing and Filtering</A></H2>
+<P>CUPS provides a MIME-based file typing and filtering mechanism to
+ convert files to a printable format for each printer. On startup the
+ CUPS server reads MIME database files from the<VAR> /etc/cups</VAR>
+ directory (or a directory specified by the<A HREF="#ServerRoot"> <CODE>
+ServerRoot</CODE></A> directive) to build a file type and conversion
+ database in memory. These database files are plain ASCII text and can
+ be edited with your favorite text editor.</P>
+<P>The<VAR> mime.types</VAR> and<VAR> mime.convs</VAR> files define the
+ standard file types and filters that are available on the system.</P>
+<H3><A NAME="7_7_1">mime.types</A></H3>
+<P>The<VAR> mime.types</VAR> file 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 <CODE>text/html</CODE>
+ file type is defined as:</P>
+<UL>
+<PRE>
+text/html html htm \
+ printable(0,1024) + \
+ (string(0,&quot;&lt;HTML&gt;&quot;) string(0,&quot;&lt;!DOCTYPE&quot;))
+</PRE>
+</UL>
+<P>The first two rules say that any file with an extension of<VAR> .html</VAR>
+ or<VAR> .htm</VAR> is a HTML file. The third rule says that any file
+ whose first 1024 characters are printable text and starts with the
+ strings <CODE>&lt;HTML&gt;</CODE> or <CODE>&lt;!DOCTYPE</CODE> is a HTML file as
+ well.</P>
+<P>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 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.</P>
+<P>The available tests are:</P>
+<UL>
+<LI><CODE>( expr )</CODE> - Parenthesis for expression grouping</LI>
+<LI><CODE>+</CODE> - Logical AND</LI>
+<LI><CODE>,</CODE> or whitespace - Logical OR</LI>
+<LI><CODE>!</CODE> - Logical NOT</LI>
+<LI><CODE>match(&quot;pattern&quot;)</CODE> - Pattern match on filename</LI>
+<LI><CODE>extension</CODE> - Pattern match on &quot;*.extension&quot;</LI>
+<LI><CODE>ascii(offset,length)</CODE> - True if bytes are valid
+ printable ASCII (CR, NL, TAB, BS, 32-126)</LI>
+<LI><CODE>printable(offset,length)</CODE> - True if bytes are printable
+ 8-bit chars (CR, NL, TAB, BS, 32-126, 160-254)</LI>
+<LI><CODE>string(offset,&quot;string&quot;)</CODE> - True if bytes are identical
+ to string</LI>
+<LI><CODE>contains(offset,range,&quot;string&quot;)</CODE> - True if the range of
+ bytes contains the string</LI>
+<LI><CODE>char(offset,value)</CODE> - True if byte is identical</LI>
+<LI><CODE>short(offset,value)</CODE> - True if 16-bit integer is
+ identical (network or &quot;big-endian&quot; byte order)</LI>
+<LI><CODE>int(offset,value)</CODE> - True if 32-bit integer is identical
+ (network or &quot;big-endian&quot; byte order)</LI>
+<LI><CODE>locale(&quot;string&quot;)</CODE> - True if current locale matches
+ string</LI>
+</UL>
+<P>All numeric values can be in decimal (123), octal (0123), or
+ hexadecimal (0x123) as desired.
+<!-- NEED 2.5in -->
+</P>
+<P>Strings can be in quotes, all by themselves, as a string of
+ hexadecimal values, or some combination:</P>
+<UL>
+<PRE>
+&quot;string&quot;
+'string'
+string
+&lt;737472696e67&gt;
+&lt;7374&gt;ring
+</PRE>
+</UL>
+<P>As shown in the <CODE>text/html</CODE> example, rules can continue on
+ multiple lines using the backslash (\) character. A more complex
+ example is the <CODE>image/jpeg</CODE> rules:</P>
+<UL>
+<PRE>
+image/jpeg jpeg jpg jpe string(0,&lt;FFD8FF&gt;) &amp;&amp;\
+ (char(3,0xe0) char(3,0xe1) char(3,0xe2) char(3,0xe3)\
+ char(3,0xe4) char(3,0xe5) char(3,0xe6) char(3,0xe7)\
+ char(3,0xe8) char(3,0xe9) char(3,0xea) char(3,0xeb)\
+ char(3,0xec) char(3,0xed) char(3,0xee) char(3,0xef))
+</PRE>
+</UL>
+<P>This rule states that any file with an extension of<VAR> .jpeg</VAR>,<VAR>
+ .jpg</VAR>, or<VAR> .jpe</VAR> is a JPEG file. In addition, any file
+ starting with the hexadecimal string <CODE>&lt;FFD8FF&gt;</CODE> (JPEG
+ Start-Of-Image) followed by a character between and including <CODE>
+0xe0</CODE> and <CODE>0xef</CODE> (JPEG APPn markers) is also a JPEG
+ file.</P>
+<H3><A NAME="7_7_2">mime.convs</A></H3>
+<P>The<VAR> mime.convs</VAR> file defines all of the filter programs
+ that are known to the system. Each line consists of:</P>
+<UL>
+<PRE>
+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
+</PRE>
+</UL>
+<P>The<I> source</I> field is a MIME type, optionally using a wildcard
+ for the super-type or sub-type (e.g. &quot;text/plain&quot;, &quot;image/*&quot;,
+ &quot;*/postscript&quot;).</P>
+<P>The<I> destination</I> field is a MIME type defined in the<VAR>
+ mime.types</VAR> file.</P>
+<P>The<I> cost</I> 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 <CODE>image/jpeg</CODE> to <CODE>
+application/vnd.cups-raster</CODE>, you could use the <CODE>imagetops</CODE>
+ and <CODE>pstoraster</CODE> filters for a total cost of 100, or the <CODE>
+imagetoraster</CODE> filter for a total cost of 50.</P>
+<P>The<I> program</I> field defines the filter program to run; the
+ special program &quot;-&quot; 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 Description and CUPS
+ Software Programmers Manual:</P>
+<UL>
+<PRE>
+program job user title options [filename]
+</PRE>
+</UL>
+<P>If specified, the<I> filename</I> 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.
+<!-- NEED 4in -->
+</P>
+<H3><A NAME="7_7_3">Adding Filetypes and Filters</A></H3>
+<P>Adding a new file type or filter is fairly straight-forward. Rather
+ than adding the new type and filter to the<VAR> mime.types</VAR> and<VAR>
+ mime.convs</VAR> files which are overwritten when you upgrade to a new
+ version of CUPS, you simple need to create new files with<VAR> .types</VAR>
+ and<VAR> .convs</VAR> extensions in the<VAR> /etc/cups</VAR> directory.
+ We recommend that you use the product or format name, e.g.:</P>
+<UL>
+<PRE>
+myproduct.types
+myproduct.convs
+</PRE>
+</UL>
+<P>If you are providing a filter for a common file format or printer,
+ add the company or author name:</P>
+<UL>
+<PRE>
+acme-msword.types
+acme.msword.convs
+</PRE>
+</UL>
+<P>This will help to prevent name collisions if you install many
+ different file types and filters.</P>
+<P>Once you choose the names for these files, create them using your
+ favorite text editor as described earlier in this chapter. Once you
+ have created the files, restart the <CODE>cupsd</CODE> process as
+ described earlier in<A HREF="#RESTARTING"> &quot;Restarting the CUPS Server&quot;</A>
+.</P>
+<H3><A NAME="7_7_4">Printer Drivers and PPD Files</A></H3>
+<P>Most CUPS printer drivers utilize one or more printer-specific
+ filters and a PPD file for each printer model. Printer driver filters
+ are registered via the PPD file using <CODE>cupsFilter</CODE>
+ attributes:</P>
+<UL>
+<PRE>
+*cupsFilter: &quot;application/vnd.cups-raster 0 rastertohp&quot;
+</PRE>
+</UL>
+<P>The filter is specified using the source file type only; the
+ destination file type is assumed to be <CODE>printer/name</CODE> -
+ suitable for sending to the printer.</P>
+<H3><A NAME="7_7_5">Writing Your Own Filter or Printer Driver</A></H3>
+<P>CUPS supports an unlimited number of file formats and filters, and
+ can handle any printer. If you'd like to write a filter or printer
+ driver for your favorite file format or printer, consult the CUPS
+ Software Programmers Manual for step-by-step instructions.</P>
+<H1 ALIGN="RIGHT"><A NAME="PRINTING_OTHER">7 - Printing with Other
+ Systems</A></H1>
+<P>This chapter describes how to print from client systems that use the
+ LPD, Mac OS, or Windows printing protocols.</P>
+<H2><A NAME="8_1">The Basics</A></H2>
+<P>CUPS is based on the IPP protocol, so any system that supports IPP
+ can send jobs to and receive jobs from CUPS automatically. However, not
+ all systems support IPP yet. This chapter will show you how to connect
+ these systems to your CUPS server, either to accept jobs from your
+ server for printing, or to send jobs to your server.</P>
+<H2><A NAME="8_2">Printing from LPD Clients</A></H2>
+<P>CUPS supports limited functionality for LPD-based clients. With LPD
+ you can print files to specific printers, list the queue status, and so
+ forth. However, the automatic client configuration and printer options
+ are not supported by the LPD protocol, so you must manually configure
+ each client for the printers it needs to access.</P>
+<P>The <CODE>cups-lpd(8)</CODE> program provides support for LPD
+ clients. To enable LPD support on your server, edit the<VAR>
+ /etc/inetd.conf</VAR> file and add a line reading:</P>
+<UL>
+<PRE>
+printer stream tcp nowait lp /usr/lib/cups/daemon/cups-lpd cups-lpd
+</PRE>
+</UL>
+<P>The path to the <CODE>cups-lpd</CODE> may vary depending on your
+ installation.</P>
+<P>Once you have added this line, send the <CODE>inetd(8)</CODE> process
+ a <CODE>HUP</CODE> signal or reboot the system:</P>
+<UL>
+<PRE>
+<B>killall -HUP inetd ENTER</B> [IRIX and some versions of Linux]
+<B>kill -HUP <I>pid</I> ENTER [Others]</B>
+<B>reboot ENTER [For all systems if the HUP signal fails]</B>
+</PRE>
+</UL>
+<H2><A NAME="8_3">Printing to LPD Servers</A></H2>
+<P>CUPS provides the <CODE>lpd</CODE> backend for printing to LPD-based
+ servers and printers. Use a device URI of <CODE>lpd://server/name</CODE>
+ to print to a printer on an LPD server, where <CODE>server</CODE> is
+ the hostname or IP address of the server and <CODE>name</CODE> is the
+ queue name.</P>
+<P>Microsoft Windows NT provides an LPD service under the name &quot;TCP/IP
+ Printing Services&quot;. To enable LPD printing on NT, open the &quot;Services&quot;
+ control panel, select the &quot;TCP/IP Printing Services&quot; service, and click
+ on the &quot;Start&quot; button. Any shared printer will then be available via
+ the LPD protocol.</P>
+<H2><A NAME="8_4">Printing from Mac OS Clients</A></H2>
+<P>CUPS does not provide Mac OS support directly. However, there are
+ several free and commercial software packages that do.</P>
+<H3><A NAME="8_4_1">Columbia Appletalk Package (CAP)</A></H3>
+<P>Because the CAP LaserWriter server (<CODE>lwsrv(8)</CODE>) does not
+ support specification of PPD files, we do not recommend that you use
+ CAP with CUPS. However, you can run the <CODE>lpsrv</CODE> program for
+ limited printing with the command:</P>
+<UL>
+<PRE>
+lwsrv -n &quot;<I>Name</I>&quot; -p <I>printer</I> -a /usr/lib/adicts -f /usr/lib/LW+Fonts
+</PRE>
+</UL>
+<P>where <CODE>Name</CODE> is the name you want to use when sharing the
+ printer, and <CODE>printer</CODE> is the name of the CUPS print queue.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="8_4_2">XINET KA/Spool</A></H3>
+<P>To use your system as a print server for Mac OS clients, configure
+ each printer using a <CODE>papserver(8)</CODE> in the<VAR>
+ /usr/adm/appletalk/services</VAR> file, specifying the corresponding
+ PPD file in the<VAR> /etc/cups/ppd</VAR> directory for each printer.
+ For a printer named <CODE>MyPrinter</CODE> the entry would look like:</P>
+<UL>
+<PRE>
+/usr/etc/appletalk/papserver -I -L -P /etc/cups/ppd/MyPrinter.ppd \
+&quot;Printer Description&quot; MyPrinter
+</PRE>
+</UL>
+<CENTER>
+<TABLE BGCOLOR="#cccccc" BORDER="1" CELLPADDING="5" WIDTH="80%">
+<TR><TD><B> NOTE:</B>
+<P>Enter the text above on a single line without the backslash (\)
+ character.</P>
+</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="8_4_3">NetATalk</A></H3>
+<P>To use your system as a print server for Mac OS clients, configure
+ each printer in the<VAR> papd.conf</VAR> file, specifying the
+ corresponding PPD file in the<VAR> /etc/cups/ppd</VAR> directory for
+ each printer. For a printer named <CODE>MyPrinter</CODE> the entry
+ would look like:</P>
+<UL>
+<PRE>
+Printer Description:MyPrinter@MyServer:\
+ :pr=|/usr/bin/lp -d MyPrinter:\
+ :op=daemon:\
+ :pd=/etc/cups/ppd/MyPrinter.ppd:
+</PRE>
+</UL>
+
+<!-- NEED 2in -->
+<H2><A NAME="8_5">Printing to Mac OS Servers</A></H2>
+<P>CUPS currently does not provide a backend to communicate with a Mac
+ OS server. However, you can write and install a short shell script in
+ the<VAR> /usr/lib/cups/backend</VAR> directory that sends a print file
+ using the appropriate command. The following is a short script that
+ will run the <CODE>papif</CODE> command provided with CAP.</P>
+<P>After copying this script to<VAR> /usr/lib/cups/backend/cap</VAR>,
+ specify a device URI of <CODE>cap://server/printer</CODE> to use this
+ backend with a print queue.
+<!-- NEED 8in -->
+</P>
+<UL>
+<PRE>
+<I>&quot;/usr/lib/cups/backend/cap&quot;</I>
+#!/bin/sh
+#
+# Usage: cap job user title copies options [filename]
+#
+
+# No arguments means show available devices...
+
+if test ${#argv} = 0; then
+ echo &quot;network cap \&quot;Unknown\&quot; \&quot;Mac OS Printer via CAP\&quot;&quot;
+ exit 0
+fi
+
+# Collect arguments...
+
+user=$2
+copies=$4
+
+if test ${#argv} = 5; then
+ # Get print file from stdin; copies have already been handled...
+ file=/var/tmp/$$.prn
+ copies=1
+ cat &gt; $file
+else
+ # Print file is on command-line...
+ file=$6
+fi
+
+# Create a dummy cap.printers file for this printer based
+# upon a device URI of &quot;cap://server/printer&quot;...
+
+echo $PRINTER/$DEVICE_URI | \
+ awk -F/ '{print $1 &quot;=&quot; $5 &quot;:LaserWriter@&quot; $4}' &gt; /var/tmp/$$.cap
+
+CAPPRINTERS=/var/tmp/$$.cap; export CAPPRINTERS
+
+# Send the file to the printer, once for each copy. This assumes that you
+# have properly initialized the cap.printers file...
+
+while [ $copies -gt 0 ]; do
+ papif -n $user &lt; $file
+
+ copies=`expr $copies - 1`
+done
+
+# Remove any temporary files...
+if test ${#argv} = 5; then
+ /bin/rm -f $file
+fi
+
+/bin/rm -f /var/tmp/$$.cap
+
+exit 0
+</PRE>
+</UL>
+
+<!-- NEED 2in -->
+<H2><A NAME="8_6">Printing from Windows Clients</A></H2>
+<P>While CUPS does not provide Windows support directly, the free SAMBA
+ software package does. SAMBA version 2.0.6 is the first release of
+ SAMBA that supports CUPS. You can download SAMBA from:</P>
+<UL>
+<PRE>
+<A HREF="http://www.samba.org">http://www.samba.org</A>
+</PRE>
+</UL>
+<P>To configure SAMBA for CUPS, edit the<VAR> smb.conf</VAR> file and
+ replace the existing printing commands and options with the line:</P>
+<UL>
+<PRE>
+printing = cups
+printcap name = cups
+</PRE>
+</UL>
+<P>That's all there is to it! Remote users will now be able to browse
+ and print to printers on your system.</P>
+<H3><A NAME="8_6_1">Exporting Printer Drivers</A></H3>
+<P>You can optionally export printer drivers from your CUPS server using
+ the <CODE>cupsaddsmb</CODE> command and the SAMBA 2.2.0 or higher
+ software.</P>
+<P>Before you can export the printers you must download the current
+ Adobe PostScript printer drivers from the Adobe web site (<A HREF="http://www.adobe.com/">
+http://www.adobe.com/</A>). Use the free <CODE>unzip</CODE> software to
+ extract the files from the self-extracting ZIP file containing the
+ drivers; you will need the following files:</P>
+<UL>
+<PRE>
+ADFONTS.MFM
+ADOBEPS4.DRV
+ADOBEPS4.HLP
+ADOBEPS5.DLL
+ADOBEPSU.DLL
+ADOBEPSU.HLP
+DEFPRTR2.PPD
+ICONLIB.DLL
+PSMON.DLL
+</PRE>
+</UL>
+<P>Copy these files to the<VAR> /usr/share/cups/drivers</VAR> directory
+ - you may need to rename some of the files so the filenames are all
+ UPPERCASE.</P>
+<P>Next, add a <CODE>print$</CODE> share for the printer drivers to your<VAR>
+ smb.conf</VAR> file:</P>
+<UL>
+<PRE>
+[print$]
+ comment = Printer Drivers
+ path = /etc/samba/drivers
+ browseable = yes
+ guest ok = no
+ read only = yes
+ write list = root
+</PRE>
+</UL>
+<P>The directory for your printer drivers can be anywhere on the system;
+ just make sure it is writable by the users specified by the <CODE>write
+ list</CODE> directive. Also, make sure that you have SAMBA passwords
+ defined for each user in the <CODE>write list</CODE> using the <CODE>
+smbpasswd(1)</CODE> command. Otherwise you will not be able to
+ authenticate</P>
+<P>Finally, run the <CODE>cupsaddsmb</CODE> command to export the
+ printer drivers for one or more queues:</P>
+<UL>
+<PRE>
+<KBD>cupsaddsmb -U root printer1 ... printerN <I>ENTER</I></KBD>
+</PRE>
+</UL>
+<P>Running <CODE>cupsaddsmb</CODE> with the <CODE>-a</CODE> option will
+ export all printers:</P>
+<UL>
+<PRE>
+<KBD>cupsaddsmb -U root -a <I>ENTER</I></KBD>
+</PRE>
+</UL>
+<H2><A NAME="8_7">Printing to Windows Servers</A></H2>
+<P>CUPS can print to Windows servers in one of two ways. The first way
+ uses the LPD protocol on the CUPS system and the &quot;TCP/IP Printing
+ Services&quot; on the Windows system. You can find out more about this
+ configuration in the<A HREF="#LPD"> LPD</A> section earlier in this
+ chapter.</P>
+<P>The second way is through the Microsoft Server Message Block (&quot;SMB&quot;)
+ protocol. Support for this protocol is provided with the free SAMBA
+ software package. You can download SAMBA from:</P>
+<UL>
+<PRE>
+<A HREF="http://www.samba.org">http://www.samba.org</A>
+</PRE>
+</UL>
+<P>To configure CUPS for SAMBA, run the following command:</P>
+<UL>
+<PRE>
+<B>ln -s `which smbspool` /usr/lib/cups/backend/smb ENTER</B>
+</PRE>
+</UL>
+<P>The <CODE>smbspool(1)</CODE> program is provided with SAMBA starting
+ with SAMBA 2.0.6. Once you have made the link you can configure your
+ printers with one of the following device URIs:</P>
+<UL>
+<PRE>
+smb://workgroup/server/sharename
+smb://server/sharename
+smb://user:pass@workgroup/server/sharename
+smb://user:pass@server/sharename
+</PRE>
+</UL>
+<P>The <CODE>workgroup</CODE> name need only be specified if your system
+ is using a different workgroup. The <CODE>user:pass</CODE> strings are
+ required when printing to Windows NT servers or to shares with
+ passwords enabled under Windows 95 and 98.</P>
+<H1 ALIGN="RIGHT"><A NAME="LICENSE">A - Software License Agreement</A></H1>
+<H2 ALIGN="CENTER"><A NAME="9_1">Common UNIX Printing System License
+ Agreement</A></H2>
+<P ALIGN="CENTER">Copyright 1997-2002 by Easy Software Products
+<BR> 44141 AIRPORT VIEW DR STE 204
+<BR> HOLLYWOOD, MARYLAND 20636-3111 USA
+<BR>
+<BR> Voice: +1.301.373.9600
+<BR> Email:<A HREF="mailto:cups-info@cups.org"> cups-info@cups.org</A>
+<BR> WWW:<A HREF="http://www.cups.org"> http://www.cups.org</A></P>
+<H3><A NAME="9_1_1">Introduction</A></H3>
+<P>The Common UNIX Printing System<SUP>TM</SUP>, (&quot;CUPS<SUP>TM</SUP>&quot;),
+ is provided under the GNU General Public License (&quot;GPL&quot;) and GNU
+ Library General Public License (&quot;LGPL&quot;), Version 2. A copy of these
+ licenses follow this introduction.</P>
+<P>The GNU LGPL applies to the CUPS API library, located in the &quot;cups&quot;
+ subdirectory of the CUPS source distribution and in the
+ &quot;/usr/include/cups&quot; directory and &quot;libcups.a&quot;, &quot;libcups_s.a&quot;,
+ &quot;libcups.sl&quot;, or &quot;libcups.so&quot; files in the binary distributions.</P>
+<P>The GNU GPL applies to the remainder of the CUPS distribution,
+ including the &quot;pstoraster&quot; filter which is based upon GNU Ghostscript
+ 5.50 and the &quot;pdftops&quot; filter which is based upon Xpdf 0.93a.</P>
+<P>For those not familiar with the GNU GPL, the license basically allows
+ you to:</P>
+<UL>
+<LI>Use the CUPS software at no charge.</LI>
+<LI>Distribute verbatim copies of the software in source or binary form.</LI>
+<LI>Sell verbatim copies of the software for a media fee, or sell
+ support for the software.</LI>
+<LI>Distribute or sell printer drivers and filters that use CUPS so long
+ as source code is made available under the GPL.</LI>
+</UL>
+<P>What this license<B> does not</B> allow you to do is make changes or
+ add features to CUPS and then sell a binary distribution without source
+ code. You must provide source for any new drivers, changes, or
+ additions to the software, and all code must be provided under the GPL
+ or LGPL as appropriate.</P>
+<P>The GNU LGPL relaxes the &quot;link-to&quot; restriction, allowing you to
+ develop applications that use the CUPS API library under other licenses
+ and/or conditions as appropriate for your application.</P>
+<H3><A NAME="9_1_2">Trademarks</A></H3>
+<P>Easy Software Products has trademarked the Common UNIX Printing
+ System, CUPS, and CUPS logo. These names and logos may be used freely
+ in any direct port or binary distribution of CUPS. To use them in
+ derivative products, please contract Easy Software Products for written
+ permission. Our intention is to protect the value of these trademarks
+ and ensure that any derivative product meets the same high-quality
+ standards as the original.</P>
+<H3><A NAME="9_1_3">Binary Distribution Rights</A></H3>
+<P>Easy Software Products also sells rights to the CUPS source code
+ under a binary distribution license for vendors that are unable to
+ release source code for their drivers, additions, and modifications to
+ CUPS under the GNU GPL and LGPL. For information please contact us at
+ the address shown above.</P>
+<P>The Common UNIX Printing System provides a &quot;pstoraster&quot; filter that
+ utilizes the GNU GhostScript 5.50 core to convert PostScript files into
+ a stream of raster images. For binary distribution licensing of this
+ software, please contact:<BLOCKQUOTE> Miles Jones
+<BR> Director of Marketing
+<BR> Artifex Software Inc.
+<BR> 454 Las Gallinas Ave., Suite 108
+<BR> San Rafael, CA 94903 USA
+<BR> Voice: +1.415.492.9861
+<BR> Fax: +1.415.492.9862
+<BR> EMail:<A HREF="mailto:info@arsoft.com"> info@arsoft.com</A></BLOCKQUOTE>
+</P>
+<P>The &quot;pdftops&quot; filter is based on the Xpdf 0.93a software. For binary
+ distribution licensing of this software, please contact:<BLOCKQUOTE>
+ Derek B. Noonburg
+<BR> Email:<A HREF="mailto:derekn@foolabs.com"> derekn@foolabs.com</A>
+<BR> WWW:<A HREF="http://www.foolabs.com/xpdf/">
+ http://www.foolabs.com/xpdf/</A></BLOCKQUOTE></P>
+<H3><A NAME="9_1_4">Support</A></H3>
+<P>Easy Software Products sells software support for CUPS as well as a
+ commercial printing product based on CUPS called ESP Print Pro. You can
+ find out more at our web site:</P>
+<UL>
+<PRE>
+<A HREF="http://www.easysw.com">http://www.easysw.com</A>
+</PRE>
+</UL>
+
+<!-- NEW PAGE -->
+<H2><A NAME="9_2">GNU GENERAL PUBLIC LICENSE</A></H2>
+<P>Version 2, June 1991</P>
+<PRE>
+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.
+</PRE>
+<PRE>
+
+</PRE>
+<H4>Preamble</H4>
+<P>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.</P>
+<P>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.</P>
+<P>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.</P>
+<P>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.</P>
+<P>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.</P>
+<P>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.</P>
+<P>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.</P>
+<P>The precise terms and conditions for copying, distribution and
+ modification follow.</P>
+<H4>GNU GENERAL PUBLIC LICENSE
+<BR> TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION</H4>
+<OL START="0">
+<LI>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 &quot;Program&quot;, below,
+ refers to any such program or work, and a &quot;work based on the Program&quot;
+ 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 &quot;modification&quot;.) Each licensee is addressed as &quot;you&quot;.</LI>
+<P>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.</P>
+<LI>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.</LI>
+<P>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.</P>
+<LI>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:
+<OL TYPE="a">
+<LI>You must cause the modified files to carry prominent notices stating
+ that you changed the files and the date of any change.</LI>
+<LI>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.</LI>
+<LI>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.)</LI>
+</OL>
+</LI>
+<P>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.</P>
+<P>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.</P>
+<P>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.</P>
+<LI>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:
+<OL TYPE="a">
+<LI>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,</LI>
+<LI>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,</LI>
+<LI>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.)</LI>
+</OL>
+</LI>
+<P>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.</P>
+<P>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.</P>
+<LI>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.</LI>
+<LI>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.</LI>
+<LI>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.</LI>
+<LI>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.</LI>
+<P>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.</P>
+<P>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.</P>
+<P>This section is intended to make thoroughly clear what is believed to
+ be a consequence of the rest of this License.</P>
+<LI>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.</LI>
+<LI>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.</LI>
+<P>Each version is given a distinguishing version number. If the Program
+ specifies a version number of this License which applies to it and &quot;any
+ later version&quot;, 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.</P>
+<LI>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.</LI>
+</OL>
+<H4>NO WARRANTY</H4>
+<OL START="11">
+<LI>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 &quot;AS IS&quot; 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.</LI>
+<LI>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.</LI>
+</OL>
+<H4>END OF TERMS AND CONDITIONS</H4>
+
+<!-- NEW PAGE -->
+<H2><A NAME="9_3">GNU LIBRARY GENERAL PUBLIC LICENSE</A></H2>
+<P>Version 2, June 1991</P>
+<PRE>
+Copyright (C) 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.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+</PRE>
+<H4>Preamble</H4>
+<P>The licenses for most software are designed to take away your freedom
+ to share and change it. By contrast, the GNU General Public Licenses
+ are intended to guarantee your freedom to share and change free
+ software--to make sure the software is free for all its users.</P>
+<P>This license, the Library General Public License, applies to some
+ specially designated Free Software Foundation software, and to any
+ other libraries whose authors decide to use it. You can use it for your
+ libraries, too.</P>
+<P>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.</P>
+<P>To protect your rights, we need to make restrictions that forbid
+ anyone to deny you these rights or to ask you to surrender the rights.
+ These restrictions translate to certain responsibilities for you if you
+ distribute copies of the library, or if you modify it.</P>
+<P>For example, if you distribute copies of the library, whether gratis
+ or for a fee, you must give the recipients all the rights that we gave
+ you. You must make sure that they, too, receive or can get the source
+ code. If you link a program with the library, you must provide complete
+ object files to the recipients so that they can relink them with the
+ library, after making changes to the library and recompiling it. And
+ you must show them these terms so they know their rights.</P>
+<P>Our method of protecting your rights has two steps: (1) copyright the
+ library, and (2) offer you this license which gives you legal
+ permission to copy, distribute and/or modify the library.</P>
+<P>Also, for each distributor's protection, we want to make certain that
+ everyone understands that there is no warranty for this free library.
+ If the library is modified by someone else and passed on, we want its
+ recipients to know that what they have is not the original version, so
+ that any problems introduced by others will not reflect on the original
+ authors' reputations.</P>
+<P>Finally, any free program is threatened constantly by software
+ patents. We wish to avoid the danger that companies distributing free
+ software will individually obtain patent licenses, thus in effect
+ transforming the program into proprietary software. To prevent this, we
+ have made it clear that any patent must be licensed for everyone's free
+ use or not licensed at all.</P>
+<P>Most GNU software, including some libraries, is covered by the
+ ordinary GNU General Public License, which was designed for utility
+ programs. This license, the GNU Library General Public License, applies
+ to certain designated libraries. This license is quite different from
+ the ordinary one; be sure to read it in full, and don't assume that
+ anything in it is the same as in the ordinary license.</P>
+<P>The reason we have a separate public license for some libraries is
+ that they blur the distinction we usually make between modifying or
+ adding to a program and simply using it. Linking a program with a
+ library, without changing the library, is in some sense simply using
+ the library, and is analogous to running a utility program or
+ application program. However, in a textual and legal sense, the linked
+ executable is a combined work, a derivative of the original library,
+ and the ordinary General Public License treats it as such.</P>
+<P>Because of this blurred distinction, using the ordinary General
+ Public License for libraries did not effectively promote software
+ sharing, because most developers did not use the libraries. We
+ concluded that weaker conditions might promote sharing better.</P>
+<P>However, unrestricted linking of non-free programs would deprive the
+ users of those programs of all benefit from the free status of the
+ libraries themselves. This Library General Public License is intended
+ to permit developers of non-free programs to use free libraries, while
+ preserving your freedom as a user of such programs to change the free
+ libraries that are incorporated in them. (We have not seen how to
+ achieve this as regards changes in header files, but we have achieved
+ it as regards changes in the actual functions of the Library.) The hope
+ is that this will lead to faster development of free libraries.</P>
+<P>The precise terms and conditions for copying, distribution and
+ modification follow. Pay close attention to the difference between a
+ &quot;work based on the library&quot; and a &quot;work that uses the library&quot;. The
+ former contains code derived from the library, while the latter only
+ works together with the library.</P>
+<P>Note that it is possible for a library to be covered by the ordinary
+ General Public License rather than by this special one.</P>
+<H4>TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION</H4>
+<P><STRONG>0.</STRONG> This License Agreement applies to any software
+ library which contains a notice placed by the copyright holder or other
+ authorized party saying it may be distributed under the terms of this
+ Library General Public License (also called &quot;this License&quot;). Each
+ licensee is addressed as &quot;you&quot;.</P>
+<P>A &quot;library&quot; means a collection of software functions and/or data
+ prepared so as to be conveniently linked with application programs
+ (which use some of those functions and data) to form executables.</P>
+<P>The &quot;Library&quot;, below, refers to any such software library or work
+ which has been distributed under these terms. A &quot;work based on the
+ Library&quot; means either the Library or any derivative work under
+ copyright law: that is to say, a work containing the Library or a
+ portion of it, either verbatim or with modifications and/or translated
+ straightforwardly into another language. (Hereinafter, translation is
+ included without limitation in the term &quot;modification&quot;.)</P>
+<P>&quot;Source code&quot; for a work means the preferred form of the work for
+ making modifications to it. For a library, complete source code means
+ all the source code for all modules it contains, plus any associated
+ interface definition files, plus the scripts used to control
+ compilation and installation of the library.</P>
+<P>Activities other than copying, distribution and modification are not
+ covered by this License; they are outside its scope. The act of running
+ a program using the Library is not restricted, and output from such a
+ program is covered only if its contents constitute a work based on the
+ Library (independent of the use of the Library in a tool for writing
+ it). Whether that is true depends on what the Library does and what the
+ program that uses the Library does.</P>
+<P><STRONG>1.</STRONG> You may copy and distribute verbatim copies of
+ the Library's complete source code as you receive it, in any medium,
+ provided that you conspicuously and appropriately publish on each copy
+ an appropriate copyright notice and disclaimer of warranty; keep intact
+ all the notices that refer to this License and to the absence of any
+ warranty; and distribute a copy of this License along with the Library.</P>
+<P>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.</P>
+<P><STRONG>2.</STRONG> You may modify your copy or copies of the Library
+ or any portion of it, thus forming a work based on the Library, and
+ copy and distribute such modifications or work under the terms of
+ Section 1 above, provided that you also meet all of these conditions:</P>
+<OL TYPE="a">
+<LI>The modified work must itself be a software library.</LI>
+<P></P>
+<LI>You must cause the files modified to carry prominent notices stating
+ that you changed the files and the date of any change.</LI>
+<P></P>
+<LI>You must cause the whole of the work to be licensed at no charge to
+ all third parties under the terms of this License.</LI>
+<P></P>
+<LI>If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses the
+ facility, other than as an argument passed when the facility is
+ invoked, then you must make a good faith effort to ensure that, in the
+ event an application does not supply such function or table, the
+ facility still operates, and performs whatever part of its purpose
+ remains meaningful.</LI>
+<P>(For example, a function in a library to compute square roots has a
+ purpose that is entirely well-defined independent of the application.
+ Therefore, Subsection 2d requires that any application-supplied
+ function or table used by this function must be optional: if the
+ application does not supply it, the square root function must still
+ compute square roots.)</P>
+</OL>
+<P>These requirements apply to the modified work as a whole. If
+ identifiable sections of that work are not derived from the Library,
+ and can be reasonably considered independent and separate works in
+ themselves, then this License, and its terms, do not apply to those
+ sections when you distribute them as separate works. But when you
+ distribute the same sections as part of a whole which is a work based
+ on the Library, the distribution of the whole must be on the terms of
+ this License, whose permissions for other licensees extend to the
+ entire whole, and thus to each and every part regardless of who wrote
+ it.</P>
+<P>Thus, it is not the intent of this section to claim rights or contest
+ your rights to work written entirely by you; rather, the intent is to
+ exercise the right to control the distribution of derivative or
+ collective works based on the Library.</P>
+<P>In addition, mere aggregation of another work not based on the
+ Library with the Library (or with a work based on the Library) on a
+ volume of a storage or distribution medium does not bring the other
+ work under the scope of this License.</P>
+<P><STRONG>3.</STRONG> You may opt to apply the terms of the ordinary
+ GNU General Public License instead of this License to a given copy of
+ the Library. To do this, you must alter all the notices that refer to
+ this License, so that they refer to the ordinary GNU General Public
+ License, version 2, instead of to this License. (If a newer version
+ than version 2 of the ordinary GNU General Public License has appeared,
+ then you can specify that version instead if you wish.) Do not make any
+ other change in these notices.</P>
+<P>Once this change is made in a given copy, it is irreversible for that
+ copy, so the ordinary GNU General Public License applies to all
+ subsequent copies and derivative works made from that copy.</P>
+<P>This option is useful when you wish to copy part of the code of the
+ Library into a program that is not a library.</P>
+<P><STRONG>4.</STRONG> You may copy and distribute the Library (or a
+ portion or derivative of it, under Section 2) in object code or
+ executable form under the terms of Sections 1 and 2 above provided that
+ you accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections 1
+ and 2 above on a medium customarily used for software interchange.</P>
+<P>If distribution of object code is made by offering access to copy
+ from a designated place, then offering equivalent access to copy the
+ source code from the same place satisfies the requirement to distribute
+ the source code, even though third parties are not compelled to copy
+ the source along with the object code.</P>
+<P><STRONG>5.</STRONG> A program that contains no derivative of any
+ portion of the Library, but is designed to work with the Library by
+ being compiled or linked with it, is called a &quot;work that uses the
+ Library&quot;. Such a work, in isolation, is not a derivative work of the
+ Library, and therefore falls outside the scope of this License.</P>
+<P>However, linking a &quot;work that uses the Library&quot; with the Library
+ creates an executable that is a derivative of the Library (because it
+ contains portions of the Library), rather than a &quot;work that uses the
+ library&quot;. The executable is therefore covered by this License. Section
+ 6 states terms for distribution of such executables.</P>
+<P>When a &quot;work that uses the Library&quot; uses material from a header file
+ that is part of the Library, the object code for the work may be a
+ derivative work of the Library even though the source code is not.
+ Whether this is true is especially significant if the work can be
+ linked without the Library, or if the work is itself a library. The
+ threshold for this to be true is not precisely defined by law.</P>
+<P>If such an object file uses only numerical parameters, data structure
+ layouts and accessors, and small macros and small inline functions (ten
+ lines or less in length), then the use of the object file is
+ unrestricted, regardless of whether it is legally a derivative work.
+ (Executables containing this object code plus portions of the Library
+ will still fall under Section 6.)</P>
+<P>Otherwise, if the work is a derivative of the Library, you may
+ distribute the object code for the work under the terms of Section 6.
+ Any executables containing that work also fall under Section 6, whether
+ or not they are linked directly with the Library itself.</P>
+<P><STRONG>6.</STRONG> As an exception to the Sections above, you may
+ also compile or link a &quot;work that uses the Library&quot; with the Library to
+ produce a work containing portions of the Library, and distribute that
+ work under terms of your choice, provided that the terms permit
+ modification of the work for the customer's own use and reverse
+ engineering for debugging such modifications.</P>
+<P>You must give prominent notice with each copy of the work that the
+ Library is used in it and that the Library and its use are covered by
+ this License. You must supply a copy of this License. If the work
+ during execution displays copyright notices, you must include the
+ copyright notice for the Library among them, as well as a reference
+ directing the user to the copy of this License. Also, you must do one
+ of these things:</P>
+<OL TYPE="a">
+<LI>Accompany the work with the complete corresponding machine-readable
+ source code for the Library including whatever changes were used in the
+ work (which must be distributed under Sections 1 and 2 above); and, if
+ the work is an executable linked with the Library, with the complete
+ machine-readable &quot;work that uses the Library&quot;, as object code and/or
+ source code, so that the user can modify the Library and then relink to
+ produce a modified executable containing the modified Library. (It is
+ understood that the user who changes the contents of definitions files
+ in the Library will not necessarily be able to recompile the
+ application to use the modified definitions.)</LI>
+<P></P>
+<LI>Accompany the work with a written offer, valid for at least three
+ years, to give the same user the materials specified in Subsection 6a,
+ above, for a charge no more than the cost of performing this
+ distribution.</LI>
+<P></P>
+<LI>If distribution of the work is made by offering access to copy from
+ a designated place, offer equivalent access to copy the above specified
+ materials from the same place.</LI>
+<P></P>
+<LI>Verify that the user has already received a copy of these materials
+ or that you have already sent this user a copy.</LI>
+</OL>
+<P>For an executable, the required form of the &quot;work that uses the
+ Library&quot; must include any data and utility programs needed for
+ reproducing the executable from it. However, as a special exception,
+ the source code distributed need not include anything that is normally
+ distributed (in either source or binary form) with the major components
+ (compiler, kernel, and so on) of the operating system on which the
+ executable runs, unless that component itself accompanies the
+ executable.</P>
+<P>It may happen that this requirement contradicts the license
+ restrictions of other proprietary libraries that do not normally
+ accompany the operating system. Such a contradiction means you cannot
+ use both them and the Library together in an executable that you
+ distribute.</P>
+<P><STRONG>7.</STRONG> You may place library facilities that are a work
+ based on the Library side-by-side in a single library together with
+ other library facilities not covered by this License, and distribute
+ such a combined library, provided that the separate distribution of the
+ work based on the Library and of the other library facilities is
+ otherwise permitted, and provided that you do these two things:</P>
+<OL TYPE="a">
+<LI>Accompany the combined library with a copy of the same work based on
+ the Library, uncombined with any other library facilities. This must be
+ distributed under the terms of the Sections above.</LI>
+<P></P>
+<LI>Give prominent notice with the combined library of the fact that
+ part of it is a work based on the Library, and explaining where to find
+ the accompanying uncombined form of the same work.</LI>
+</OL>
+<P><STRONG>8.</STRONG> You may not copy, modify, sublicense, link with,
+ or distribute the Library except as expressly provided under this
+ License. Any attempt otherwise to copy, modify, sublicense, link with,
+ or distribute the Library is void, and will automatically terminate
+ your rights under this License. However, parties who have received
+ copies, or rights, from you under this License will not have their
+ licenses terminated so long as such parties remain in full compliance.</P>
+<P><STRONG>9.</STRONG> You are not required to accept this License,
+ since you have not signed it. However, nothing else grants you
+ permission to modify or distribute the Library or its derivative works.
+ These actions are prohibited by law if you do not accept this License.
+ Therefore, by modifying or distributing the Library (or any work based
+ on the Library), you indicate your acceptance of this License to do so,
+ and all its terms and conditions for copying, distributing or modifying
+ the Library or works based on it.</P>
+<P><STRONG>10.</STRONG> Each time you redistribute the Library (or any
+ work based on the Library), the recipient automatically receives a
+ license from the original licensor to copy, distribute, link with or
+ modify the Library subject to these terms and conditions. You may not
+ impose any further restrictions on the recipients' exercise of the
+ rights granted herein. You are not responsible for enforcing compliance
+ by third parties to this License.</P>
+<P><STRONG>11.</STRONG> If, as a consequence of a court judgment or
+ allegation of patent infringement or for any other reason (not limited
+ to patent issues), conditions are imposed on you (whether by court
+ order, agreement or otherwise) that contradict the conditions of this
+ License, they do not excuse you from the conditions of this License. If
+ you cannot distribute so as to satisfy simultaneously your obligations
+ under this License and any other pertinent obligations, then as a
+ consequence you may not distribute the Library at all. For example, if
+ a patent license would not permit royalty-free redistribution of the
+ Library by all those who receive copies directly or indirectly through
+ you, then the only way you could satisfy both it and this License would
+ be to refrain entirely from distribution of the Library.</P>
+<P>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.</P>
+<P>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.</P>
+<P>This section is intended to make thoroughly clear what is believed to
+ be a consequence of the rest of this License.</P>
+<P><STRONG>12.</STRONG> If the distribution and/or use of the Library is
+ restricted in certain countries either by patents or by copyrighted
+ interfaces, the original copyright holder who places the Library under
+ this License may add an explicit geographical distribution limitation
+ excluding those countries, so that distribution is permitted only in or
+ among countries not thus excluded. In such case, this License
+ incorporates the limitation as if written in the body of this License.</P>
+<P><STRONG>13.</STRONG> The Free Software Foundation may publish revised
+ and/or new versions of the Library General Public License from time to
+ time. Such new versions will be similar in spirit to the present
+ version, but may differ in detail to address new problems or concerns.</P>
+<P>Each version is given a distinguishing version number. If the Library
+ specifies a version number of this License which applies to it and &quot;any
+ later version&quot;, you have the option of following the terms and
+ conditions either of that version or of any later version published by
+ the Free Software Foundation. If the Library does not specify a license
+ version number, you may choose any version ever published by the Free
+ Software Foundation.</P>
+<P><STRONG>14.</STRONG> If you wish to incorporate parts of the Library
+ into other free programs whose distribution conditions are incompatible
+ with these, write to the author to ask for permission. For software
+ which is copyrighted by the Free Software Foundation, write to the Free
+ Software Foundation; we sometimes make exceptions for this. Our
+ decision will be guided by the two goals of preserving the free status
+ of all derivatives of our free software and of promoting the sharing
+ and reuse of software generally.</P>
+<P><STRONG>NO WARRANTY</STRONG></P>
+<P><STRONG>15.</STRONG> BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE,
+ THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY
+ APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+ HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY &quot;AS IS&quot; WITHOUT
+ WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE
+ OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU
+ ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.</P>
+<P><STRONG>16.</STRONG> IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR
+ AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO
+ MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE
+ LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL
+ OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+ LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+ RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+ FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+ SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ DAMAGES.</P>
+<H4>END OF TERMS AND CONDITIONS</H4>
+<H1 ALIGN="RIGHT"><A NAME="COMMON_NETWORK">B - Common Network Settings</A>
+</H1>
+<P>This appendix covers many of the popular TCP/IP network interfaces
+ and printer servers available on the market today.</P>
+<H2><A NAME="10_1">Configuring a Network Interface</A></H2>
+<P>When you first install a network printer or print server on your LAN,
+ you need to set the Internet Protocol (&quot;IP&quot;) address. On most
+ higher-end &quot;workgroup&quot; printers, you can set the address through the
+ printer control panel. However, in most cases you will want to assign
+ the addresses remotely from your workstation. This makes administration
+ a bit easier and avoids assigning duplicate addresses accidentally.</P>
+<P>To setup your printer or print server for remote address assignment,
+ you'll need the Ethernet Media Access Control (&quot;MAC&quot;) address, also
+ sometimes called a node address, and the IP address you want to use for
+ the device. The Ethernet MAC address can often be found on the printer
+ test page or bottom of the print server.
+<!-- NEED 3in -->
+</P>
+<H3><A NAME="10_1_1">Configuring the IP Address Using ARP</A></H3>
+<P>The easiest way to set the IP address of a network device is to use
+ the <CODE>arp(8)</CODE> command. The <CODE>arp</CODE> sends an Address
+ Resolution Protocol (&quot;ARP&quot;) packet to the specified Ethernet MAC
+ address, setting the network device's IP address:</P>
+<UL>
+<PRE>
+<B>arp -s ip-address ethernet-address ENTER</B>
+<B>arp -s host.domain.com 08:00:69:00:12:34 ENTER</B>
+<B>arp -s 192.0.2.2 08:00:69:00:12:34 ENTER</B>
+</PRE>
+</UL>
+<H3><A NAME="10_1_2">Configuring the IP Address Using RARP</A></H3>
+<P>The most flexible way to remotely assign IP addresses under UNIX is
+ through the Reverse Address Resolution Protocol (&quot;RARP&quot;). RARP allows a
+ network device to request an IP address using its Ethernet MAC address,
+ and one or more RARP servers on the network will respond with an ARP
+ packet with the IP address the device can use.</P>
+<P>RARP should be used when you have to manage many printers or print
+ servers, or when you have a network device that does not remember its
+ IP address after a power cycle. If you just have a single printer or
+ print server, the <CODE>arp</CODE> command is the way to go.</P>
+<P>Some UNIX operating systems use a program called <CODE>rarpd(8)</CODE>
+ to manage RARP. Others, like Linux, support this protocol in the
+ kernel. For systems that provide the <CODE>rarpd</CODE> program you
+ will need to start it before RARP lookups will work:</P>
+<UL>
+<PRE>
+<B>rarpd ENTER</B>
+</PRE>
+</UL>
+<P>Under IRIX you can enable this functionality by default using:</P>
+<UL>
+<PRE>
+<B>chkconfig rarpd on ENTER</B>
+</PRE>
+</UL>
+<P>Both the <CODE>rarpd</CODE> program and kernel RARP support read a
+ list of Ethernet and IP addresses from the file<VAR> /etc/ethers</VAR>.
+ Each line contains the Ethernet address (colon delimited) followed by
+ an IP address or hostname like:</P>
+<UL>
+<PRE>
+08:00:69:00:12:34 myprinter.mydomain.com
+08:00:69:00:12:34 192.0.2.2
+</PRE>
+</UL>
+<P>Add a line to this file and cycle the power on the printer or print
+ server to set its address.
+<!-- NEED 2in -->
+</P>
+<H3><A NAME="10_1_3">Configuring the IP Address Using BOOTP</A></H3>
+<P>The BOOTP protocol is used when you need to provide additional
+ information such as the location of a configuration file to the network
+ interface. Using the standard <CODE>bootpd(8)</CODE> program supplied
+ with UNIX you simply need to add a line to the<VAR> /etc/bootptab</VAR>
+ file; for IRIX:</P>
+<UL>
+<PRE>
+myprinter 08:00:69:00:12:34 192.0.2.2 <VAR>myprinter.boot</VAR>
+</PRE>
+</UL>
+
+<!-- NEED 1in -->
+<P>Newer versions of <CODE>bootpd</CODE> use a different format:</P>
+<UL>
+<PRE>
+myprinter:ha=080069001234:ip=192.0.2.2:<VAR>t144=myprinter.boot</VAR>
+</PRE>
+</UL>
+<P>The<VAR> myprinter.boot</VAR> file resides in the<VAR>
+ /usr/local/boot</VAR> directory by default. If you do not need to
+ provide a boot file you may leave the last part of the line blank.
+<!-- NEED 2in -->
+
+<CENTER>
+<TABLE BGCOLOR="#cccccc" BORDER="1" CELLPADDING="5" WIDTH="80%">
+<TR><TD><B> NOTE:</B>
+<P>Some versions of UNIX do not enable the BOOTP service by default. The<VAR>
+ /etc/inetd.conf</VAR> usually contains a line for the BOOTP service
+ that can be uncommented if needed.</P>
+</TD></TR>
+</TABLE>
+</CENTER>
+</P>
+<H2><A NAME="10_2">Verifying the Printer Connection</A></H2>
+<P>To test that the IP address has been successfully assigned and that
+ the printer is properly connected to your LAN, type:</P>
+<UL>
+<PRE>
+<B>ping ip-address ENTER</B>
+</PRE>
+</UL>
+<P>If the connection is working properly you will see something like:</P>
+<UL>
+<PRE>
+<B>ping myprinter ENTER</B>
+PING myprinter (192.0.2.2): 56 data bytes
+64 bytes from 192.0.2.2: icmp_seq=0 ttl=15 time=5 ms
+64 bytes from 192.0.2.2: icmp_seq=1 ttl=15 time=3 ms
+64 bytes from 192.0.2.2: icmp_seq=2 ttl=15 time=3 ms
+64 bytes from 192.0.2.2: icmp_seq=3 ttl=15 time=3 ms
+</PRE>
+</UL>
+<P>If not, verify that the printer or print server is connected to the
+ LAN, it is powered on, the LAN cabling is good, and the IP address is
+ set correctly. You can usually see the current IP address and network
+ status by printing a configuration or test page on the device.
+<!-- NEED 4in -->
+</P>
+<H2><A NAME="10_3">Common Network Interface Settings</A></H2>
+<P>Once you have set the IP address you can access the printer or print
+ server using the <CODE>ipp</CODE>, <CODE>lpd</CODE>, or <CODE>socket</CODE>
+ backends. The following is a list of common network interfaces and
+ printer servers and the settings you should use with CUPS:
+<CENTER>
+<TABLE BORDER="1">
+<TR ALIGN="LEFT" VALIGN="TOP"><TH>Model/Manufacturer</TH><TH>Device
+ URI(s)</TH></TR>
+<TR ALIGN="LEFT" VALIGN="TOP"><TD>Apple LaserWriter</TD><TD>lpd://<I>
+address</I>/PASSTHRU</TD></TR>
+
+<!-- NEED 1in -->
+<TR ALIGN="LEFT" VALIGN="TOP"><TD>Axis w/o IPP
+<BR><A HREF="#AXIS"> (see directions)</A></TD><TD>socket://<I>address</I>
+:9100
+<BR> socket://<I>address</I>:9101
+<BR> socket://<I>address</I>:9102</TD></TR>
+
+<!-- NEED 1in -->
+<TR ALIGN="LEFT" VALIGN="TOP"><TD>Axis w/IPP</TD><TD>ipp://<I>address</I>
+/LPT1
+<BR> ipp://<I>address</I>/LPT2
+<BR> ipp://<I>address</I>/COM1</TD></TR>
+
+<!-- NEED 1in -->
+<TR ALIGN="LEFT" VALIGN="TOP"><TD>Castelle LANpress<SUP>TM</SUP></TD><TD>
+lpd://<I>address</I>/pr1
+<BR> lpd://<I>address</I>/pr2
+<BR> lpd://<I>address</I>/pr3</TD></TR>
+
+<!-- NEED 1in -->
+<TR ALIGN="LEFT" VALIGN="TOP"><TD>DPI NETPrint</TD><TD>lpd://<I>address</I>
+/pr1
+<BR> lpd://<I>address</I>/pr2
+<BR> lpd://<I>address</I>/pr3</TD></TR>
+<TR ALIGN="LEFT" VALIGN="TOP"><TD>EFI&reg; Fiery&reg; RIP</TD><TD>lpd://<I>
+address</I>/print</TD></TR>
+<TR ALIGN="LEFT" VALIGN="TOP"><TD>EPSON&reg; Multiprotocol Ethernet
+ Interface Board</TD><TD>socket://<I>address</I></TD></TR>
+
+<!-- NEED 1in -->
+<TR ALIGN="LEFT" VALIGN="TOP"><TD>Extended System ExtendNET</TD><TD>
+lpd://<I>address</I>/pr1
+<BR> lpd://<I>address</I>/pr2
+<BR> lpd://<I>address</I>/pr3</TD></TR>
+
+<!-- NEED 1in -->
+<TR ALIGN="LEFT" VALIGN="TOP"><TD>Hewlett Packard JetDirect w/o IPP</TD><TD>
+socket://<I>address</I>:9100
+<BR> socket://<I>address</I>:9101
+<BR> socket://<I>address</I>:9102</TD></TR>
+
+<!-- NEED 1in -->
+<TR ALIGN="LEFT" VALIGN="TOP"><TD>Hewlett Packard JetDirect w/IPP</TD><TD>
+ipp://<I>address</I>/ipp
+<BR> ipp://<I>address</I>/ipp/port1
+<BR> ipp://<I>address</I>/ipp/port2
+<BR> ipp://<I>address</I>/ipp/port3</TD></TR>
+
+<!-- NEED 1in -->
+<TR ALIGN="LEFT" VALIGN="TOP"><TD>Intel&reg; NetportExpress XL, PRO/100</TD><TD>
+lpd://<I>address</I>/LPT1_PASSTHRU
+<BR> lpd://<I>address</I>/LPT2_PASSTHRU
+<BR> lpd://<I>address</I>/COM1_PASSTHRU</TD></TR>
+<TR ALIGN="LEFT" VALIGN="TOP"><TD>Lexmark<SUP>TM</SUP> MarkNet</TD><TD>
+lpd://<I>address</I>/ps</TD></TR>
+
+<!-- NEED 1in -->
+<TR ALIGN="LEFT" VALIGN="TOP"><TD>Linksys EtherFast&reg;
+<BR><A HREF="#LINKSYS"> (see directions)</A></TD><TD>socket://<I>address</I>
+:4010
+<BR> socket://<I>address</I>:4020
+<BR> socket://<I>address</I>:4030</TD></TR>
+<TR ALIGN="LEFT" VALIGN="TOP"><TD>Kodak&reg;</TD><TD>lpd://<I>address</I>/ps</TD>
+</TR>
+<TR ALIGN="LEFT" VALIGN="TOP"><TD>QMS&reg; CrownNet<SUP>TM</SUP></TD><TD>
+lpd://<I>address</I>/ps</TD></TR>
+<TR ALIGN="LEFT" VALIGN="TOP"><TD>Tektronix&reg; PhaserShare<SUP>TM</SUP></TD><TD>
+socket://<I>address</I>:9100</TD></TR>
+<TR ALIGN="LEFT" VALIGN="TOP"><TD>XEROX&reg; 4512 NIC</TD><TD>lpd://<I>
+address</I>/PORT1</TD></TR>
+<TR ALIGN="LEFT" VALIGN="TOP"><TD>XEROX&reg; XNIC</TD><TD>lpd://<I>address</I>
+/PASSTHRU</TD></TR>
+<TR ALIGN="LEFT" VALIGN="TOP"><TD>XEROX&reg; (most others)</TD><TD>socket://<I>
+address</I>:5503</TD></TR>
+</TABLE>
+</CENTER>
+</P>
+<H2><A NAME="AXIS">Configuring Axis Print Servers</A></H2>
+<P>The Axis print servers can be configured using ARP, RARP, or BOOTP.
+ However, on models that do not provide IPP support an additional step
+ must be performed to configure the TCP/IP portion of the print server
+ for use with CUPS.
+<!-- NEED 3in -->
+</P>
+<P>Each print server contains a configuration file named<VAR> config</VAR>
+ that contains a list of network parameters used by the server. To
+ modify this file you must first download it from the print server using
+ the <CODE>ftp(1)</CODE> program:</P>
+<UL>
+<PRE>
+<B>ftp ip-address ENTER</B>
+Connected to ip-address.
+220 Axis NPS ### FTP Printer Server V#.## MON DD YEAR ready.
+ftp&gt; <B>user root ENTER</B>
+331 User name ok, need password
+Password: <B>pass ENTER</B> <I>(this is not echoed)</I>
+230 User logged in
+ftp&gt; <B>get config ENTER</B>
+local: config remote: config
+200 PORT command successful.
+150 Opening data connection for config (192,0,2,2),
+(mode ascii).
+226 Transfer complete.
+##### bytes received in #.## seconds (##### Kbytes/s)
+ftp&gt; <B>quit ENTER</B>
+221 Goodbye.
+</PRE>
+</UL>
+
+<!-- NEED 2in -->
+<P>Next, edit the file with your favorite text editor and locate the
+ lines beginning with:</P>
+<UL>
+<PRE>
+RTN_OPT. : YES
+RTEL_PR1. : 0
+RTEL_PR2. : 0
+RTEL_PR3. : 0
+RTEL_PR4. : 0
+RTEL_PR5. : 0
+RTEL_PR6. : 0
+RTEL_PR7. : 0
+RTEL_PR8. : 0
+</PRE>
+</UL>
+
+<!-- NEED 1in -->
+ Change the <CODE>RTN_OPT</CODE> line to read:
+<UL>
+<PRE>
+RTN_OPT. : <B>NO</B>
+</PRE>
+</UL>
+
+<!-- NEED 2in -->
+<P>This disables the Reverse TELNET protocol and enables the standard
+ TELNET protocol on the print server. Next, assign a port number for
+ each parallel and serial port on the server as follows:</P>
+<UL>
+<PRE>
+RTEL_PR1. : <B>9100</B>
+RTEL_PR2. : <B>9101</B>
+RTEL_PR3. : <B>9102</B>
+RTEL_PR4. : <B>9103</B>
+RTEL_PR5. : <B>9104</B>
+RTEL_PR6. : <B>9105</B>
+RTEL_PR7. : <B>9106</B>
+RTEL_PR8. : <B>9107</B>
+</PRE>
+</UL>
+
+<!-- NEED 4in -->
+<P>This essentially makes the Axis print server look like a Hewlett
+ Packard JetDirect EX print server. Save the file and then upload the
+ new<VAR> config</VAR> file using the <CODE>ftp</CODE> command:</P>
+<UL>
+<PRE>
+<B>ftp ip-address ENTER</B>
+Connected to ip-address.
+220 Axis NPS ### FTP Printer Server V#.## MON DD YEAR ready.
+ftp&gt; <B>user root ENTER</B>
+331 User name ok, need password
+Password: <B>pass ENTER</B> <I>(this is not echoed)</I>
+230 User logged in
+ftp&gt; <B>put config CONFIG ENTER</B>
+local: config remote: CONFIG
+200 PORT command successful.
+150 Opening data connection for config (192,0,2,2), (mode ascii).
+226 Transfer complete.
+##### bytes received in #.## seconds (##### Kbytes/s)
+ftp&gt; <B>get hardreset ENTER</B>
+local: hardreset remote: hardreset
+200 PORT command successful.
+421 Axis NPS ### hard reset, closing connection.
+ftp&gt; <B>quit ENTER</B>
+221 Goodbye.
+</PRE>
+</UL>
+<P>Your Axis print server is now ready for use!</P>
+<H2><A NAME="LINKSYS">Configuring Linksys Print Servers</A></H2>
+<P>The Linksys print servers can be configured using ARP, RARP, or
+ BOOTP. Like older Axis print servers, an additional step must be
+ performed to configure the TCP/IP portion of the print server for use
+ with CUPS.
+<!-- NEED 3in -->
+</P>
+<P>Each print server contains a configuration file named<VAR> CONFIG</VAR>
+ that contains a list of network parameters used by the server. To
+ modify this file you must first download it from the print server using
+ the <CODE>ftp(1)</CODE> program:</P>
+<UL>
+<PRE>
+<B>ftp -n ip-address ENTER</B>
+Connected to ip-address.
+220 Print Server Ready.
+Remote system type is Print.
+ftp&gt; <B>get CONFIG ENTER</B>
+local: CONFIG remote: CONFIG
+200 Command OK.
+150 Open ASCII Mode Connection.
+WARNING! 68 bare linefeeds received in ASCII mode
+File may not have transferred correctly.
+226 Transfer complete.
+##### bytes received in #.## seconds (##### Kbytes/s)
+ftp&gt; <B>quit ENTER</B>
+221 Goodbye.
+</PRE>
+</UL>
+
+<!-- NEED 2in -->
+<P>Next, edit the file with your favorite text editor and locate the
+ lines beginning with:</P>
+<UL>
+<PRE>
+0100 L1_PROUT:P1
+0120 L2_PROUT:P1
+0140 L3_PROUT:P1
+</PRE>
+</UL>
+<P>Change the port number for each parallel and serial port on the
+ server as follows:</P>
+<UL>
+<PRE>
+0100 L1_PROUT:<B>P1</B>
+0120 L2_PROUT:<B>P2</B>
+0140 L3_PROUT:<B>P3</B>
+</PRE>
+</UL>
+
+<!-- NEED 4in -->
+<P>This maps each virtual printer with a physical port. Save the file
+ and then upload the new<VAR> CONFIG</VAR> file using the <CODE>ftp</CODE>
+ command:</P>
+<UL>
+<PRE>
+<B>ftp -n ip-address ENTER</B>
+Connected to ip-address.
+220 Print Server Ready.
+Remote system type is Print.
+ftp&gt; <B>put CONFIG ENTER</B>
+local: CONFIG remote: CONFIG
+200 Command OK.
+150 Open ASCII Mode Connection.
+226 Transfer complete.
+##### bytes received in #.## seconds (##### Kbytes/s)
+ftp&gt; <B>quit ENTER</B>
+221 Goodbye.
+</PRE>
+</UL>
+<P>Your Linksys print server is now ready for use!</P>
+<H1 ALIGN="RIGHT"><A NAME="PRINTER_DRIVERS">C - Printer Drivers</A></H1>
+<P>This appendix lists the printer drivers that are provided with CUPS.</P>
+<H2><A NAME="11_1">Printer Drivers</A></H2>
+<P>CUPS includes the following printer drivers:</P>
+<UL>
+<LI><A HREF="#EPSON9">EPSON 9-pin Dot Matrix</A>,<VAR> epson9.ppd</VAR></LI>
+<LI><A HREF="#EPSON24">EPSON 24-pin Dot Matrix</A>,<VAR> epson24.ppd</VAR>
+</LI>
+<LI><A HREF="#STCOLOR">EPSON Stylus Color</A>,<VAR> stcolor.ppd</VAR></LI>
+<LI><A HREF="#STPHOTO">EPSON Stylus Photo</A>,<VAR> stphoto.ppd</VAR></LI>
+<LI><A HREF="#DESKJET">HP DeskJet</A>,<VAR> deskjet.ppd</VAR></LI>
+<LI><A HREF="#LASERJET">HP LaserJet</A>,<VAR> laserjet.ppd</VAR></LI>
+</UL>
+<H2><A NAME="EPSON9">EPSON 9-pin Dot Matrix</A></H2>
+<P>The EPSON 9-pin Dot Matrix driver (<VAR>epson9.ppd</VAR>) supports
+ 9-pin dot matrix printers that implement the ESC/P command set. It
+ provides 60x72, 120x72, and 240x72 DPI output in black only.</P>
+<H2><A NAME="EPSON24">EPSON 24-pin Dot Matrix</A></H2>
+<P>The EPSON 24-pin Dot Matrix driver (<VAR>epson9.ppd</VAR>) supports
+ 24-pin dot matrix printers that implement the ESC/P command set. It
+ provides 120x180, 180x180, 360x180, and 360x360 DPI output in black
+ only.</P>
+<H2><A NAME="STCOLOR">EPSON Stylus Color</A></H2>
+<P>The EPSON Stylus Color driver (<VAR>stcolor.ppd</VAR>) supports EPSON
+ Stylus Color printers that implement the ESC/P2 command set. It
+ provides 180, 360, and 720 DPI output in black and color (CMYK).</P>
+<H2><A NAME="STPHOTO">EPSON Stylus Photo</A></H2>
+<P>The EPSON Stylus Photo driver (<VAR>stphoto.ppd</VAR>) supports EPSON
+ Stylus Photo printers that implement the ESC/P2 command set. It
+ provides 180, 360, and 720 DPI output in black and color (CMYKcm).</P>
+<H2><A NAME="DESKJET">HP DeskJet</A></H2>
+<P>The HP DeskJet driver (<VAR>deskjet.ppd</VAR>) supports HP DeskJet
+ printers that implement the PCL command set. It provides 150, 300, and
+ 600 DPI output in black and color (CMYK).</P>
+<P>The DeskJet printers that implement the HP-PPA command set (720C,
+ 722C, 820C, and 1100C) are<B> not</B> supported due to a complete lack
+ of documentation and support from Hewlett Packard.</P>
+<P>The duplexer provided with the HP DeskJet 900 series printers is also
+ not supported for similar reasons.</P>
+<H2><A NAME="LASERJET">HP LaserJet</A></H2>
+<P>The HP LaserJet driver (<VAR>laserjet.ppd</VAR>) supports HP LaserJet
+ printers that implement the PCL command set. It provides 150, 300, and
+ 600 DPI output in black only and supports the duplexer if installed.</P>
+<P>LaserJet printers that do not implement PCL (3100, 3150) are not
+ supported due to a complete lack of documentation and support from
+ Hewlett Packard.</P>
+<H1 ALIGN="RIGHT"><A NAME="FILES">D - List of Files</A></H1>
+<P>This appendix lists the files and directories that are installed for
+ the Common UNIX Printing System.
+<CENTER>
+<TABLE BORDER="1" WIDTH="80%">
+<TR VALIGN="TOP"><TH>Pathname</TH><TH>Description</TH></TR>
+<TR VALIGN="TOP"><TD>/etc/cups/certs/</TD><TD>The location of
+ authentication certificate files for local HTTP clients.</TD></TR>
+<TR VALIGN="TOP"><TD>/etc/cups/classes.conf</TD><TD>The printer classes
+ configuration file for the scheduler.</TD></TR>
+<TR VALIGN="TOP"><TD>/etc/cups/cupsd.conf</TD><TD>The scheduler
+ configuration file.</TD></TR>
+<TR VALIGN="TOP"><TD>/etc/cups/interfaces/</TD><TD>The location of
+ System V interface scripts for printers.</TD></TR>
+<TR VALIGN="TOP"><TD>/etc/cups/mime.convs</TD><TD>The list of standard
+ file filters included with ESP Print Pro.</TD></TR>
+<TR VALIGN="TOP"><TD>/etc/cups/mime.types</TD><TD>The list of recognized
+ file types for ESP Print Pro.</TD></TR>
+<TR VALIGN="TOP"><TD>/etc/cups/ppd/</TD><TD>The location of PostScript
+ Printer Description (&quot;PPD&quot;) files for printers.</TD></TR>
+<TR VALIGN="TOP"><TD>/etc/cups/printers.conf</TD><TD>The printer
+ configuration file for the scheduler.</TD></TR>
+<TR VALIGN="TOP"><TD>/usr/bin/cancel</TD><TD>The System V cancel job(s)
+ command.</TD></TR>
+<TR VALIGN="TOP"><TD>/usr/bin/disable</TD><TD>The System V disable
+ printer command.</TD></TR>
+<TR VALIGN="TOP"><TD>/usr/bin/enable</TD><TD>The System V enable printer
+ command.</TD></TR>
+<TR VALIGN="TOP"><TD>/usr/bin/lp</TD><TD>The System V print command.</TD>
+</TR>
+<TR VALIGN="TOP"><TD>/usr/bin/lpoptions</TD><TD>Sets user-defined
+ printing options and defaults.</TD></TR>
+<TR VALIGN="TOP"><TD>/usr/bin/lppasswd</TD><TD>Adds, changes, or removes
+ Digest password accounts.</TD></TR>
+<TR VALIGN="TOP"><TD>/usr/bin/lpq</TD><TD>The Berkeley status command.</TD>
+</TR>
+<TR VALIGN="TOP"><TD>/usr/bin/lpr</TD><TD>The Berkeley print command.</TD>
+</TR>
+<TR VALIGN="TOP"><TD>/usr/bin/lprm</TD><TD>The Berkeley cancel job(s)
+ command.</TD></TR>
+<TR VALIGN="TOP"><TD>/usr/bin/lpstat</TD><TD>The System V status
+ command.</TD></TR>
+<TR VALIGN="TOP"><TD>/usr/include/cups/</TD><TD>CUPS API header files.</TD>
+</TR>
+<TR VALIGN="TOP"><TD>/usr/lib32/libcups.a
+<BR> /usr/lib32/libcupsimage.a</TD><TD>Static libraries (IRIX 6.5)</TD></TR>
+<TR VALIGN="TOP"><TD>/usr/lib/libcups.a
+<BR> /usr/lib/libcupsimage.a</TD><TD>Static libraries (all others)</TD></TR>
+<TR VALIGN="TOP"><TD>/usr/lib/libcups.sl.2
+<BR> /usr/lib/libcupsimage.sl.2</TD><TD>Shared libraries (HP-UX)</TD></TR>
+<TR VALIGN="TOP"><TD>/usr/lib32/libcups.so.2
+<BR> /usr/lib32/libcupsimage.so.2</TD><TD>Shared libraries (IRIX 6.5)</TD>
+</TR>
+<TR VALIGN="TOP"><TD>/usr/lib/libcups.so.2
+<BR> /usr/lib/libcupsimage.so.2</TD><TD>Shared libraries (all others)</TD>
+</TR>
+<TR VALIGN="TOP"><TD>/usr/lib/cups/backend/</TD><TD>Backends for various
+ types of printer connections.</TD></TR>
+<TR VALIGN="TOP"><TD>/usr/lib/cups/cgi-bin/</TD><TD>CGI programs for the
+ scheduler.</TD></TR>
+<TR VALIGN="TOP"><TD>/usr/lib/cups/daemon/</TD><TD>Daemons for polling
+ and LPD support.</TD></TR>
+<TR VALIGN="TOP"><TD>/usr/lib/cups/filter/</TD><TD>Filters for various
+ types of files.</TD></TR>
+<TR VALIGN="TOP"><TD>/usr/lib/locale/</TD><TD>The location of
+ language-specific message files. (System V)</TD></TR>
+<TR VALIGN="TOP"><TD>/usr/lib/nls/msg/</TD><TD>The location of
+ language-specific message files. (Compaq Tru64 UNIX)</TD></TR>
+<TR VALIGN="TOP"><TD>/usr/share/locale/</TD><TD>The location of
+ language-specific message files. (Linux, *BSD)</TD></TR>
+<TR VALIGN="TOP"><TD>/usr/sbin/accept</TD><TD>The accept-jobs command.</TD>
+</TR>
+<TR VALIGN="TOP"><TD>/usr/sbin/cupsd</TD><TD>The CUPS print scheduler.</TD>
+</TR>
+<TR VALIGN="TOP"><TD>/usr/sbin/lpadmin</TD><TD>The System V printer
+ administration tool.</TD></TR>
+<TR VALIGN="TOP"><TD>/usr/sbin/lpc</TD><TD>The Berkeley printer
+ administration tool.</TD></TR>
+<TR VALIGN="TOP"><TD>/usr/sbin/lpinfo</TD><TD>The get-devices and
+ get-ppds command.</TD></TR>
+<TR VALIGN="TOP"><TD>/usr/sbin/lpmove</TD><TD>The move-jobs command.</TD>
+</TR>
+<TR VALIGN="TOP"><TD>/usr/sbin/reject</TD><TD>The reject-jobs command.</TD>
+</TR>
+<TR VALIGN="TOP"><TD>/usr/share/catman/a_man/
+<BR> /usr/share/catman/u_man/</TD><TD>Man pages (IRIX)</TD></TR>
+<TR VALIGN="TOP"><TD>/usr/share/man/</TD><TD>Man pages (Compaq Tru64
+ UNIX, HP-UX, Solaris)</TD></TR>
+<TR VALIGN="TOP"><TD>/usr/man/</TD><TD>Man pages (all others)</TD></TR>
+<TR VALIGN="TOP"><TD>/usr/share/cups/data/</TD><TD>The location of
+ filter data files.</TD></TR>
+<TR VALIGN="TOP"><TD>/usr/share/cups/data/testprint.ps</TD><TD>The
+ PostScript test page file.</TD></TR>
+<TR VALIGN="TOP"><TD>/usr/share/cups/fonts/</TD><TD>The location of
+ PostScript fonts for the PostScript RIP.</TD></TR>
+<TR VALIGN="TOP"><TD>/usr/share/cups/model/</TD><TD>The location of
+ PostScript Printer Description (&quot;PPD&quot;) files and interface scripts that
+ may be used to setup a printer queue.</TD></TR>
+<TR VALIGN="TOP"><TD>/usr/share/cups/pstoraster/</TD><TD>Other
+ PostScript RIP initialization files.</TD></TR>
+<TR VALIGN="TOP"><TD>/usr/share/cups/pstoraster/Fontmap</TD><TD>The font
+ mapping file (converts filenames to fontnames)</TD></TR>
+<TR VALIGN="TOP"><TD>/usr/share/cups/templates/</TD><TD>The location of
+ HTML template files for the web interfaces.</TD></TR>
+<TR VALIGN="TOP"><TD>/usr/share/doc/cups/</TD><TD>Documentation and web
+ page data for the scheduler.</TD></TR>
+<TR VALIGN="TOP"><TD>/var/log/cups/</TD><TD>The location of scheduler
+ log files.</TD></TR>
+<TR VALIGN="TOP"><TD>/var/spool/cups/</TD><TD>The location of print
+ files waiting to be printed.</TD></TR>
+</TABLE>
+</CENTER>
+</P>
+<H1 ALIGN="RIGHT"><A NAME="FAQ">E - Troubleshooting Common Problems</A></H1>
+<P>This appendix covers some of the common problems first-time users
+ encounter when installing and configuring CUPS.</P>
+<P>Commercial support for CUPS is available from Easy Software Products.
+ For more information please contact us at:</P>
+<UL>
+<LI>WWW:<A HREF="http://www.easysw.com"> <CODE>http://www.easysw.com</CODE>
+</A></LI>
+<LI>EMail:<A HREF="mailto:info@easysw.com"> info@easysw.com</A></LI>
+<LI>Telephone (M-F, 9-5 EST): +1.301.373.9600</LI>
+</UL>
+<H2><A NAME="13_1">My Applications Don't See the Available Printers</A></H2>
+<P>Many applications read the<VAR> /etc/printcap</VAR> file to get a
+ list of available printers.</P>
+<P>The default CUPS configuration does not create the<VAR> /etc/printcap</VAR>
+ file automatically. To enable automatic creation and updating of this
+ file, use the<A HREF="#Printcap"> <CODE>Printcap</CODE></A> directive
+ described in<A HREF="#PRINTING_MANAGEMENT"> Chapter 6, &quot;Printing System
+ Management&quot;</A>.</P>
+<H2><A NAME="13_2">CUPS Doesn't Recognize My Username or Password!</A></H2>
+<P>CUPS will ask you for a UNIX username and password when you perform
+ printer administration tasks remotely or via a web browser. The default
+ configuration requires that you use the <CODE>root</CODE> username and
+ the corresponding password to authenticate the request.</P>
+<P>CUPS does not allow you to authenticate an administration request
+ with an account that has no password for security reasons. If you do
+ not have a password on your <CODE>root</CODE> account then you won't be
+ able to add printers remotely or via the web interface!
+<!-- NEED 2in -->
+</P>
+<P>To disable password authentication you need to edit the<VAR>
+ /etc/cups/cupsd.conf</VAR> file and comment out the lines reading:</P>
+<UL>
+<PRE>
+AuthType Basic
+AuthClass System
+</PRE>
+</UL>
+ for the<VAR> /admin</VAR> location. Then restart the CUPS server as
+ described in<A HREF="#PRINTING_MANAGEMENT"> Chapter 6, &quot;Printing System
+ Management&quot;</A>.
+<CENTER>
+<TABLE BGCOLOR="#cccccc" BORDER="1" CELLPADDING="5" WIDTH="80%">
+<TR><TD><B> NOTE:</B>
+<P>Disabling password checks will allow any local user to change your
+ printer and class configuration, but remote administration from another
+ machine will still not be allowed.</P>
+</TD></TR>
+</TABLE>
+</CENTER>
+<H2><A NAME="ALLOW_REMOTE">I Can't Do Administration Tasks from Another
+ Machine!</A></H2>
+<P>The default CUPS configuration limits administration to the local
+ machine. To open up access, edit the<VAR> /etc/cups/cupsd.conf</VAR>
+ and comment out the lines reading:</P>
+<UL>
+<PRE>
+Order deny,allow
+Deny from all
+Allow from 127.0.0.1
+</PRE>
+</UL>
+ for the<VAR> /admin</VAR> location. Then restart the CUPS server as
+ described in<A HREF="#PRINTING_MANAGEMENT"> Chapter 6, &quot;Printing System
+ Management&quot;</A>.
+<CENTER>
+<TABLE BGCOLOR="#cccccc" BORDER="1" CELLPADDING="5" WIDTH="80%">
+<TR><TD><B> NOTE:</B>
+<P>Allowing administration access from all hosts is a potential security
+ risk. Please read<A HREF="#PRINTING_SECURITY"> Chapter 6, &quot;Printing
+ System Management&quot;</A> for a description of these risks and ways to
+ minimize them.</P>
+</TD></TR>
+</TABLE>
+</CENTER>
+
+<!-- NEED 4in -->
+<H2><A NAME="13_4">I Can't Do Administration Tasks from My Web Browser!</A>
+</H2>
+<P>This problem is usually caused by:</P>
+<OL>
+<LI>not specifying the correct password for the root account.</LI>
+<LI>accessing the CUPS server using the hostname or IP address of the
+ server without enabling remote access for administration functions.
+ This can be corrected by following the instructions in the<A HREF="#ALLOW_REMOTE">
+ &quot;I Can't Do Administration Tasks from Another Machine!&quot;</A> section
+ earlier in this appendix.</LI>
+<LI>not setting a password on the root account. CUPS will not
+ authenticate a user account that does not have a password for security
+ reasons.</LI>
+<LI>authenticating using an account other than root, but the account you
+ are using is not a member of the system group.</LI>
+<LI>configuring CUPS to use Digest authentication, but your web browser
+ does not support Digest authentication.</LI>
+</OL>
+<H2><A NAME="13_5">Connection Refused Messages</A></H2>
+<P>Under normal circumstances, &quot;connection refused&quot; messages for a
+ networked printer should be expected from time to time. Most network
+ interfaces only allow a single connection to be made at any given time
+ (one job at a time) and will refuse access to all other systems while
+ the first connection is active. CUPS automatically retries the
+ connection once every 30 seconds.</P>
+<P>If the problem persists and you are unable to print any jobs to the
+ printer, verify that another machine is not maintaining a connection
+ with the printer, and that you have selected the proper port or printer
+ name for the printer.</P>
+<P>Also, most external print servers will refuse connections if the
+ connected printer is turned off or is off-line. Verify that the
+ affected printer is turned on and is online.</P>
+<H2><A NAME="13_6">Write Error Messages</A></H2>
+<P>If you get &quot;write error&quot; messages on a printer queue the printer
+ interface (usually a Hewlett Packard JetDirect interface) has timed out
+ and reset the network connection from your workstation.</P>
+<P>The error is caused by that startup delay between the initial setup
+ of the printer or plotter and the first page of print data that is
+ sent.
+<!-- NEED 3in -->
+</P>
+<P>To correct the problem, change the idle timeout on the interface to
+ at least 180 seconds or 3 minutes. To change the timeout on a Hewlett
+ Packard JetDirect interface, type:</P>
+<UL>
+<PRE>
+<B>telnet ip-address ENTER</B>
+
+Trying ip-address...
+Connected to ip-address.
+Escape character is `^]'.
+
+Please type [Return] two times, to initialize telnet configuration
+For HELP type &quot;?&quot;
+&gt; <B>idle-timeout: 180 ENTER</B>
+&gt; <B>quit ENTER</B>
+</PRE>
+</UL>
+</BODY>
+</HTML>
diff --git a/doc/sam.pdf b/doc/sam.pdf
new file mode 100644
index 000000000..cc151af19
--- /dev/null
+++ b/doc/sam.pdf
Binary files differ
diff --git a/doc/sam.shtml b/doc/sam.shtml
new file mode 100644
index 000000000..d520ead88
--- /dev/null
+++ b/doc/sam.shtml
@@ -0,0 +1,4611 @@
+<HTML>
+<HEAD>
+ <META NAME="COPYRIGHT" CONTENT="Copyright 1997-2002, All Rights Reserved">
+ <META NAME="DOCNUMBER" CONTENT="CUPS-SAM-1.1.13">
+ <META NAME="Author" CONTENT="Easy Software Products">
+ <TITLE>CUPS Software Administrators Manual</TITLE>
+</HEAD>
+<BODY>
+
+<H1 ALIGN="RIGHT">Preface</H1>
+
+<P>This software administrators manual provides printer administration
+information for the Common UNIX Printing System<SUP>TM</SUP>
+("CUPS<SUP>TM</SUP>"), version 1.1.13.
+
+<EMBED SRC="system-overview.shtml">
+
+<!-- NEED 3in -->
+<H2>Document Overview</H2>
+
+<P>This software administrators manual is organized into the following sections:</P>
+
+<UL>
+ <LI><A HREF="#OVERVIEW">1 - Printing System Overview</A>
+ <LI><A HREF="#BUILDING_INSTALLING">2 - Building and Installing CUPS</A>
+ <LI><A HREF="#MANAGING_PRINTERS">3 - Managing Printers</A>
+ <LI><A HREF="#PRINTER_CLASSES">4 - Printer Classes</A>
+ <LI><A HREF="#CLIENT_SETUP">5 - Client Setup</A>
+ <LI><A HREF="#PRINTING_MANAGEMENT">6 - Printing System Management</A>
+ <LI><A HREF="#PRINTING_OTHER">7 - Printing with Other Systems</A>
+ <LI><A HREF="#LICENSE">A - Software License Agreement</A>
+ <LI><A HREF="#COMMON_NETWORK">B - Common Network Settings</A>
+ <LI><A HREF="#PRINTER_DRIVERS">C - Printer Drivers</A>
+ <LI><A HREF="#FILES">D - List of Files</A>
+ <LI><A HREF="#FAQ">E - Troubleshooting Common Problems</A>
+</UL>
+
+<H2>Notation Conventions</H2>
+
+<P>Various font and syntax conventions are used in this guide. Examples and
+their meanings and uses are explained below:
+
+<CENTER><TABLE WIDTH="80%">
+<TR>
+ <TH>Example</TH>
+ <TD>&nbsp;&nbsp;&nbsp;</TD>
+ <TH>Description</TH>
+</TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR VALIGN="TOP">
+ <TD><CODE>lpstat</CODE><BR>
+ <CODE>lpstat(1)</CODE></TD>
+
+ <TD>&nbsp;&nbsp;&nbsp;</TD>
+
+ <TD>The names of commands; the first mention of a command or
+ function in a chapter is followed by a manual page section
+ number.</TD>
+</TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR VALIGN="TOP">
+ <TD><VAR>/var</VAR><BR>
+ <VAR>/usr/share/cups/data/testprint.ps</VAR></TD>
+
+ <TD>&nbsp;&nbsp;&nbsp;</TD>
+
+ <TD>File and directory names.</TD>
+</TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR VALIGN="TOP">
+ <TD NOWRAP><TT>Request ID is Printer-123</TT></TD>
+
+ <TD>&nbsp;&nbsp;&nbsp;</TD>
+
+ <TD>Screen output.</TD>
+</TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR VALIGN="TOP">
+ <TD NOWRAP><KBD>lp -d printer filename ENTER</KBD></TD>
+
+ <TD>&nbsp;&nbsp;&nbsp;</TD>
+
+ <TD>Literal user input; special keys like <KBD>ENTER</B></KBD> are
+ in ALL CAPS.</TD>
+</TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR VALIGN="TOP">
+ <TD>12.3</TD>
+
+ <TD>&nbsp;&nbsp;&nbsp;</TD>
+
+ <TD>Numbers in the text are written using the period (.) to indicate
+ the decimal point.</TD>
+</TR>
+</TABLE></CENTER>
+
+<!-- NEED 3in -->
+<H2>Abbreviations</H2>
+
+The following abbreviations are used throughout this manual:
+
+<UL>
+<DL>
+
+ <DT>kb
+ <DD>Kilobytes, or 1024 bytes<BR>&nbsp;
+
+ <DT>Mb
+ <DD>Megabytes, or 1048576 bytes<BR>&nbsp;
+
+ <DT>Gb
+ <DD>Gigabytes, or 1073741824 bytes<BR>&nbsp;
+
+</DL>
+</UL>
+
+<H2>Other References</H2>
+
+<UL>
+<DL>
+
+ <DT>CUPS Software Programmers Manual
+
+ <DD>A programmer guide for interfacing with and/or extending the CUPS
+ software.<BR>&nbsp;
+
+ <DT>CUPS Software Users Manual
+
+ <DD>An end-user guide for using the CUPS software.<BR>&nbsp;
+
+</DL>
+</UL>
+
+
+<EMBED SRC="printing-overview.shtml">
+
+
+<H1 ALIGN="RIGHT"><A NAME="BUILDING_INSTALLING">2 - Building and Installing CUPS</A></H1>
+
+<P>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, <A HREF="#BINARY">Installing a Binary Distribution</A>.
+
+<H2>Installing a Source Distribution</H2>
+
+<P>This section describes how to compile and install CUPS on your system
+from the source code.
+
+<H3><A NAME="REQUIREMENTS">Requirements</A></H3>
+
+<P>You'll need ANSI-compliant C and C++ compilers 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 compile and run
+under Microsoft Windows.
+
+<P>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
+significantly reduced functionality. Easy Software Products maintains a
+mirror of the current versions of these libraries at:
+
+<UL><PRE>
+<A HREF="ftp://ftp.easysw.com/pub/libraries">ftp://ftp.easysw.com/pub/libraries</A>
+</PRE></UL>
+
+<P>If you make changes to the man pages you'll need GNU groff or another
+nroff-like package. GNU groff is available from:
+
+<UL><PRE>
+<A HREF="ftp://ftp.gnu.org/pub/groff">ftp://ftp.gnu.org/pub/groff</A>
+</PRE></UL>
+
+<P>The documentation is formatted using the HTMLDOC software. If you need to
+make changes you can get the HTMLDOC software from:
+
+<UL><PRE>
+<A HREF="http://www.easysw.com/htmldoc">http://www.easysw.com/htmldoc</A>
+</PRE></UL>
+
+<P>Finally, you'll need a <CODE>make</CODE> program that
+understands the <CODE>include</CODE> directive - FreeBSD,
+NetBSD, and OpenBSD developers should use the <CODE>gmake</CODE>
+program.
+
+<H3><A NAME="COMPILING">Compiling CUPS</A></H3>
+
+<P>CUPS uses GNU autoconf to configure the makefiles and source code
+for your system. Type the following command to configure CUPS for your
+system:
+
+<UL><PRE>
+<B>./configure ENTER</B>
+</PRE></UL>
+
+<P>The default installation will put the CUPS software in the
+<VAR>/etc</VAR>, <VAR>/usr</VAR>, and <VAR>/var</VAR> directories on
+your system, which will overwrite any existing printing commands on
+your system. Use the <CODE>--prefix</CODE> option to install the CUPS
+software in another location:
+
+<UL><PRE>
+<B>./configure --prefix=/some/directory ENTER</B>
+</PRE></UL>
+
+<P>If the PNG, JPEG, TIFF, and ZLIB libraries are not installed in a
+system default location (typically <VAR>/usr/include</VAR> and
+<VAR>/usr/lib</VAR>) you'll need to set the <CODE>CFLAGS</CODE>,
+<CODE>CXXFLAGS</CODE>, and <CODE>LDFLAGS</CODE> environment variables
+prior to running configure:
+
+<UL><PRE>
+<B>setenv CFLAGS "-I/some/directory" ENTER</B>
+<B>setenv CXXFLAGS "-I/some/directory" ENTER</B>
+<B>setenv LDFLAGS "-L/some/directory" ENTER</B>
+<B>setenv DSOFLAGS "-L/some/directory" ENTER</B>
+<B>./configure ... ENTER</B>
+</PRE></UL>
+
+<P>or:
+
+<UL><PRE>
+<B>CFLAGS="-I/some/directory"; export CFLAGS ENTER</B>
+<B>CXXFLAGS="-I/some/directory"; export CXXFLAGS ENTER</B>
+<B>LDFLAGS="-L/some/directory"; export LDFLAGS ENTER</B>
+<B>DSOFLAGS="-L/some/directory"; export DSOFLAGS ENTER</B>
+<B>./configure ... ENTER</B>
+</PRE></UL>
+
+<P>To enable support for encryption, you'll also want to add the
+"--enable-ssl" option:
+
+<UL><PRE>
+./configure --enable-ssl
+</PRE></UL>
+
+<P>SSL and TLS support require the OpenSSL library, available at:
+
+<UL><PRE>
+<A HREF="http://www.openssl.org">http://www.openssl.org</A>
+</PRE></UL>
+
+<P>If the OpenSSL headers and libraries are not installed in the
+standard directories, use the <CODE>--with-openssl-includes</CODE>
+and <CODE>--with-openssl-libs</CODE> options:</P>
+
+<UL><PRE>
+./configure --enable-ssl \
+ --with-openssl-includes=/foo/bar/include \
+ --with-openssl-libs=/foo/bar/lib
+</PRE></UL>
+
+<P>Once you have configured things, just type:
+
+<UL><PRE>
+<B>make ENTER</B>
+</PRE></UL>
+
+<P>to build the software.
+
+<!-- NEED 4in -->
+<H3><A NAME="INSTALLING">Installing the Software</A></H3>
+
+<P>Use the "install" target to install the software:
+
+<UL><PRE>
+<B>make install ENTER</B>
+</PRE></UL>
+
+<CENTER><TABLE WIDTH="80%" BORDER="1" BGCOLOR="#cccccc" CELLPADDING="5">
+<TR>
+ <TD>
+ <B>WARNING:</B>
+
+ <P>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 reinstall the old printing system from your operating system CDs.
+ </TD>
+</TR>
+</TABLE></CENTER>
+
+<H3><A NAME="RUNNING">Running the Software</A></A></H3>
+
+<P>Once you have installed the software you can start the CUPS server by
+typing:
+
+<UL><PRE>
+<B>/usr/sbin/cupsd ENTER</B>
+</PRE></UL>
+
+<!-- NEED 4in -->
+<H2><A NAME="BINARY">Installing a Binary Distribution</A></H2>
+
+<P>CUPS comes in a variety of binary distribution formats. Easy
+Software Products provides binaries in TAR format with installation and
+removal scripts ("portable" distributions), and in RPM and DPKG formats
+for Red Hat and Debian-based distributions. Portable distributions are
+available for all platforms, while the RPM and DPKG distributions are
+only available for Linux.
+
+<CENTER><TABLE WIDTH="80%" BORDER="1" BGCOLOR="#cccccc" CELLPADDING="5">
+<TR>
+ <TD>
+ <B>WARNING:</B>
+
+ <P>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/or
+ reinstall the old printing system from your operating system CDs.
+ </TD>
+</TR>
+</TABLE></CENTER>
+
+
+<H3><A NAME="PORTABLE-BINARY">Installing a Portable Distribution</A></H3>
+
+<P>To install the CUPS software from a portable distribution you will
+need to be logged in as root; doing an <CODE>su</CODE> is good enough.
+Once you are the root user, run the installation script with:
+
+<UL><PRE>
+<B>./cups.install ENTER</B>
+</PRE></UL>
+
+<P>After asking you a few yes/no questions the CUPS software will be
+installed and the scheduler will be started automatically.
+
+<!-- NEED 2in -->
+<H3><A NAME="RPM-BINARY">Installing an RPM Distribution</A></H3>
+
+<P>To install the CUPS software from an RPM distribution you will need
+to be logged in as root; doing an <CODE>su</CODE> is good enough. Once
+you are the root user, run RPM with:
+
+<UL><PRE>
+<B>rpm -e lpr</B>
+<B>rpm -i cups-1.1-linux-M.m.n-intel.rpm ENTER</B>
+</PRE></UL>
+
+<P>After a short delay the CUPS software will be
+installed and the scheduler will be started automatically.
+
+<H3><A NAME="DPKG-BINARY">Installing an Debian Distribution</A></H3>
+
+<P>To install the CUPS software from a Debian distribution you will
+need to be logged in as root; doing an <CODE>su</CODE> is good enough.
+Once you are the root user, run dpkg with:
+
+<UL><PRE>
+<B>dpkg -i cups-1.1-linux-M.m.n-intel.deb ENTER</B>
+</PRE></UL>
+
+<P>After a short delay the CUPS software will be installed and the
+scheduler will be started automatically.
+
+
+<H1 ALIGN="RIGHT"><A NAME="MANAGING_PRINTERS">3 - Managing Printers</A></H1>
+
+<P>This chapter describes how to add your first printer and how to
+manage your printers.
+
+<H2>The Basics</H2>
+
+<P>Each printer queue has a name associated with it; the printer name
+must start with a letter and can contain up to 127 letters, numbers,
+and the underscore (_). Case is not significant, e.g. "PRINTER", "Printer",
+and "printer" are considered to be the same name.
+
+<P>Printer queues also have a device associated with them. The device can be
+a parallel port, a network interface, and so forth. Devices within CUPS use
+Uniform Resource Identifiers ("URIs") which are a more general form of
+Uniform Resource Locators ("URLs") that are used in your web browser. For
+example, the first parallel port in Linux usually uses a device URI of
+<CODE>parallel:/dev/lp1</CODE>.
+
+<!-- NEED 2.5in -->
+<P>You can see a complete list of supported devices by running the
+<CODE>lpinfo(8)</CODE> command:
+
+<UL><PRE>
+<B>lpinfo -v ENTER</B>
+file file
+network socket
+network http
+network ipp
+network lpd
+direct parallel:/dev/lp1
+serial serial:/dev/ttyS1?baud=115200
+serial serial:/dev/ttyS2?baud=115200
+direct usb:/dev/usb/lp0
+network smb
+</PRE></UL>
+
+<P>The <CODE>-v</CODE> option specifies that you want a list of available
+devices. The first word in each line is the type of device (direct, file,
+network, or serial) and is followed by the device URI or method name for
+that device. File devices have device URIs of the form
+<CODE>file:/directory/filename</CODE> while network devices use the more
+familiar <CODE>method://server</CODE> or <CODE>method://server/path</CODE>
+format.
+
+<P>Finally, printer queues usually have a PostScript Printer Description
+("PPD") file associated with them. PPD files describe the capabilities of
+each printer, the page sizes supported, etc., and are used for PostScript
+and non-PostScript printers. CUPS includes PPD files for HP LaserJet, HP
+DeskJet, EPSON 9-pin, EPSON 24-pin, and EPSON Stylus printers.
+
+<H2>Adding Your First Printer</H2>
+
+<P>CUPS provides two methods for adding printers: a command-line
+program called <CODE>lpadmin(8)</CODE> and a Web interface. The
+<CODE>lpadmin</CODE> command allows you to perform most printer
+administration tasks from the command-line and is located in
+<VAR>/usr/sbin</VAR>. The Web interface is located at:
+
+<UL><PRE>
+<A HREF="http://localhost:631/admin">http://localhost:631/admin</A>
+</PRE></UL>
+
+<P>and steps you through printer configuration. If you don't like
+command-line interfaces, try the <A HREF="#ADD_WEB">Web interface</A> instead.
+
+<H3>Adding Your First Printer from the Command-Line</H3>
+
+<P>Run the <CODE>lpadmin</CODE> command with the <CODE>-p</CODE> option to add a
+printer to CUPS:
+
+<UL><PRE>
+<B>/usr/sbin/lpadmin -p <I>printer</I> -E -v <I>device</I> -m <I>ppd</I> ENTER</B>
+</PRE></UL>
+
+<P>For an HP DeskJet printer connected to the parallel port this would look
+like:
+
+<UL><PRE>
+<B>/usr/sbin/lpadmin -p DeskJet -E -v parallel:/dev/lp1 -m deskjet.ppd ENTER</B>
+</PRE></UL>
+
+<P>Similarly, an HP LaserJet printer using a JetDirect network interface at
+IP address 11.22.33.44 would be added with the command:
+
+<UL><PRE>
+<B>/usr/sbin/lpadmin -p LaserJet -E -v socket://11.22.33.44 -m laserjet.ppd ENTER</B>
+</PRE></UL>
+
+<P>As you can see, <CODE>deskjet.ppd</CODE> and <CODE>laserjet.ppd</CODE> are
+the PPD files for the HP DeskJet and HP LaserJet drivers included with CUPS.
+You'll find a complete list of PPD files and the printers they will work with
+in <A HREF="#PRINTER_DRIVERS">Appendix C, "Printer Drivers"</A>.
+
+
+<P>For a dot matrix printer connected to the serial port this would might look like:
+
+<UL><PRE>
+<B>/usr/sbin/lpadmin -p DotMatrix -E -v serial:/dev/ttyS0?baud=9600+size=8+parity=none+flow=soft deskjet.ppd ENTER</B>
+</PRE></UL>
+
+<P>Here you specify the serial port (e.g. S0,S1, d0, d1), baud rate
+(e.g. 9600, 19200, 38400, 115200, etc.), number of bits, parity, and flow control.
+If you do not need flow control, delete the "+flow=soft" portion.
+
+
+<H3><A NAME="ADD_WEB">Adding Your First Printer from the Web</A></H3>
+
+<P>The CUPS web server provides a user-friendly "wizard" interface for
+adding your printers. Rather than figuring out which device URI and PPD file
+to use, you can instead click on the appropriate listings and fill in some
+simple information. Enter the following URL in your web browser to begin:
+
+<UL><PRE>
+<A HREF="http://localhost:631/admin">http://localhost:631/admin</A>
+</PRE></UL>
+
+<P>Click on the <VAR>Add Printer</VAR> button to add a printer.
+
+<H2>Managing Printers from the Command-Line</H2>
+
+<P>The <CODE>lpadmin</CODE> command enables you to perform most printer
+administration tasks from the command-line. You'll find <CODE>lpadmin</CODE>
+in the <VAR>/usr/sbin</VAR> directory.
+
+<H3>Adding and Modifying Printers</H3>
+
+<P>Run the <CODE>lpadmin</CODE> command with the <CODE>-p</CODE> option
+to add or modify a printer:
+
+<UL><PRE>
+<B>/usr/sbin/lpadmin -p <I>printer</I> <I>options</I> ENTER</B>
+</PRE></UL>
+
+<P>The <I>options</I> arguments can be any of the following:
+
+<UL>
+<DL>
+
+ <DT>-c <I>class</I>
+
+ <DD>Adds the named printer to printer class <VAR>class</VAR>.
+ If the class does not exist then it is created.
+
+ <DT>-i <I>interface</I>
+
+ <DD>Copies the named <VAR>interface</VAR> script to the printer.
+ Interface scripts are used by System V printer drivers. Since
+ all filtering is disabled when using an interface script, scripts
+ generally should not be used unless there is no other driver for
+ a printer.
+
+ <DT>-m <I>model</I>
+
+ <DD>Specifies a standard printer driver which is usually a PPD
+ file. A list of all available models can be displayed using the
+ <CODE>lpinfo</CODE> command with the <CODE>-m</CODE> option. A
+ list of printer drivers included with CUPS can be found in
+ <A HREF="#PRINTER_DRIVERS">Appendix C, "Printer Drivers"</A>.
+
+ <DT>-r <I>class</I>
+
+ <DD>Removes the named printer from printer class <VAR>class</CODE>.
+ If the resulting class becomes empty then it is removed.
+
+ <DT>-v <I>device-uri</I>
+
+ <DD>Sets the device for communicating with the printer. If a
+ job is currently printing on the named printer then the job
+ will be restarted and sent to the new device.
+
+ <DT>-D <I>info</I>
+
+ <DD>Provides a textual description of the printer, e.g.
+ "John's Personal Printer".
+
+ <DT>-E
+
+ <DD>Enables the printer and accepts job. This option is
+ equivalent to running the <CODE>enable(1)</CODE> and
+ <CODE>accept(8)</CODE> commands on the printer.
+
+ <DT>-L <I>location</I>
+
+ <DD>Provides a textual location for the printer, e.g.
+ "Computer Lab 5".
+
+ <DT>-P <I>ppd-file</I>
+
+ <DD>Specifies a local PPD file for the printer driver.
+
+</DL>
+</UL>
+
+<H3>Deleting Printers</H3>
+
+<P>Run the <CODE>lpadmin</CODE> command with the <CODE>-x</CODE> option
+to delete a printer:
+
+<UL><PRE>
+<B>/usr/sbin/lpadmin -x <I>printer</I> ENTER</B>
+</PRE></UL>
+
+<H3>Setting the Default Printer</H3>
+
+<P>Run the <CODE>lpadmin</CODE> command with the <CODE>-d</CODE> option
+to set a default printer:
+
+<UL><PRE>
+<B>/usr/sbin/lpadmin -d <I>printer</I> ENTER</B>
+</PRE></UL>
+
+<P>The default printer can be overridden by the user using the
+<CODE>lpoptions(1)</CODE> command.
+
+<H3>Starting and Stopping Printers</H3>
+
+<P>The <CODE>enable</CODE> and <CODE>disable</CODE> commands start and stop
+printer queues, respectively:
+
+<UL><PRE>
+<B>/usr/bin/enable <I>printer</I> ENTER</B>
+<B>/usr/bin/disable <I>printer</I> ENTER</B>
+</PRE></UL>
+
+<P>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 queued
+jobs are printed after the printer is enabled (started).
+
+<H3>Accepting and Rejecting Print Jobs</H3>
+
+<P>The <CODE>accept</CODE> and <CODE>reject</CODE> commands accept and reject
+print jobs for the named printer, respectively:
+
+<UL><PRE>
+<B>/usr/sbin/accept <I>printer</I> ENTER</B>
+<B>/usr/sbin/reject <I>printer</I> ENTER</B>
+</PRE></UL>
+
+<P>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.
+
+<H2>Managing Printers from the Web</H2>
+
+<P>The Web interface is located at:
+
+<UL><PRE>
+<A HREF="http://localhost:631/admin">http://localhost:631/admin</A>
+</PRE></UL>
+
+<P>From there you can perform all printer management tasks with a few
+simple mouse clicks.
+
+
+<H1 ALIGN="RIGHT"><A NAME="PRINTER_CLASSES">4 - Printer Classes</A></H1>
+
+<P>This chapter describes what printer classes are and how to manage them.
+
+<H2>The Basics</H2>
+
+<P>CUPS provides collections of printers called <I>printer classes</I>. Jobs
+sent to a class are forwarded to the first available printer in the class.
+Classes can themselves be members of other classes, so it is possible for
+you to define very large, distributed printer classes for high-availability
+printing.
+
+<P>CUPS also supports <I>implicit classes</I>. Implicit classes work just
+like printer classes, but they are created automatically based upon the
+available printers and classes on the network. This allows you to setup
+multiple print servers with identical printer configurations and have the
+client machines send their print jobs to the first available server. If
+one or more servers go down, the jobs are automatically redirected to the
+servers that are running, providing fail-safe printing.
+
+<H2>Managing Printer Classes from the Command-Line</H2>
+
+<P>Run the <CODE>lpadmin</CODE> command with the <CODE>-p</CODE> and <CODE>-c</CODE> options
+to add a printer to a class:
+
+<UL><PRE>
+<B>/usr/sbin/lpadmin -p <I>printer</I> -c <I>class</I> ENTER</B>
+</PRE></UL>
+
+<P>The <I>class</I> is created automatically if it doesn't exist. To remove a
+printer from a class use the <CODE>-r</CODE> option:
+
+<UL><PRE>
+<B>/usr/sbin/lpadmin -p <I>printer</I> -r <I>class</I> ENTER</B>
+</PRE></UL>
+
+<P>To remove the entire class just use the <CODE>-x</CODE> option:
+
+<UL><PRE>
+<B>/usr/sbin/lpadmin -x <I>class</I> ENTER</B>
+</PRE></UL>
+
+<H2>Managing Printer Classes from the Web Interface</H2>
+
+<P>The Web interface is located at:
+
+<UL><PRE>
+<A HREF="http://localhost:631/admin">http://localhost:631/admin</A>
+</PRE></UL>
+
+<P>The <VAR>Add Class</VAR> and <VAR>Modify Class</VAR> interfaces provide a
+list of available printers; click on the printers of interest to add them to
+the class.
+
+<H2>Implicit Classes</H2>
+
+<P>A noted earlier, implicit classes are created automatically from the
+available network printers and classes. To disable this functionality,
+set the <A HREF="#ImplicitClasses"><CODE>ImplicitClasses</CODE></A>
+directive to <CODE>Off</CODE> in the <CODE>cupsd.conf</CODE> file. You
+will find more information on doing this in
+<A HREF="#PRINTING_MANAGEMENT">Chapter 6, "Printing System
+Management"</A>.
+
+
+<H1 ALIGN="RIGHT"><A NAME="CLIENT_SETUP">5 - Client Setup</A></H1>
+
+<P>This chapter discusses several ways to configure CUPS clients for
+printing.
+
+<H2>The Basics</H2>
+
+<P>A client is any machine that sends print jobs to another machine for
+final printing. Clients can also be servers if they communicate directly with
+any printers of their own.
+
+<P>CUPS supports several methods of configuring client machines:
+
+<UL>
+
+ <LI><A HREF="#CLIENT_MANUAL">Manual configuration of print queues.</A>
+
+ <LI><A HREF="#CLIENT_SERVER">Specifying a single server for printing.</A>
+
+ <LI><A HREF="#CLIENT_AUTO">Automatic configuration of print queues.</A>
+
+ <LI><A HREF="#CLIENT_POLL">Specifying multiple servers for printing.</A>
+
+</UL>
+
+<H3><A NAME="CLIENT_MANUAL">Manual Configuration of Print Queues</A></H3>
+
+<P>The most tedious method of configuring client machines is to configure
+each remote queue by hand using the <CODE>lpadmin</CODE> command:
+
+<UL><PRE>
+<B>lpadmin -p <I>printer</I> -E -v ipp://<I>server</I>/printers/<I>printer</I> ENTER</B>
+</PRE></UL>
+
+<P>The <CODE>printer</CODE> name is the name of the printer on the server
+machine. The <CODE>server</CODE> name is the hostname or IP address of the
+server machine. Repeat the <CODE>lpadmin</CODE> command for each remote
+printer you wish to use.
+
+<H3><A NAME="CLIENT_SERVER">Specifying a Single Server for Printing</A></H3>
+
+<P>CUPS can be configured to run without a local spooler and send all
+jobs to a single server. However, if that server goes down then all
+printing will be disabled. Use this configuration only as absolutely needed.
+
+<P>The default server is normally "localhost". To override the default
+server create a file named <VAR>/etc/cups/client.conf</VAR> and add
+a line reading:
+
+<UL><PRE>
+ServerName <I>server</I>
+</PRE></UL>
+
+<P>to the file. The <VAR>server</VAR> name can be the hostname or IP address
+of the default server.
+
+<P>The default server can also be customized on a per-user basis. To set a
+user-specific server create a file named <VAR>~/.cupsrc</VAR> and add a line
+reading:
+
+<UL><PRE>
+ServerName <I>server</I>
+</PRE></UL>
+
+<P>to the file. The <VAR>server</VAR> name can be the hostname or IP
+address of the default server.
+
+<H3><A NAME="CLIENT_AUTO">Automatic Configuration of Print Queues</A></H3>
+
+<P>CUPS supports automatic client configuration of printers on the same
+subnet. To configure printers on the same subnet, <I>do nothing</I>.
+Each client should see the available printers within 30 seconds
+automatically. The printer and class lists are updated automatically as
+printers and servers are added or removed.
+
+<P>If you want to see printers on other subnets as well, use the
+<A HREF="#BrowsePoll"><CODE>BrowsePoll</CODE></A> directive as
+described next.
+
+<H3><A NAME="CLIENT_POLL">Specifying Multiple Servers for Printing</A></H3>
+
+<P>If you have CUPS servers on different subnets, then you should configure
+CUPS to poll those servers. Polling provides the benefits of automatic
+configuration without significant configuration on the clients, and multiple
+clients on the same subnet can share the same configuration information.
+
+<P>Polling is enabled by specifying one or more
+<A HREF="#BrowsePoll"><CODE>BrowsePoll</CODE></A> directives in the
+<VAR>/etc/cups/cupsd.conf</VAR> file. For information on making these
+changes, see <A HREF="#PRINTING_MANAGEMENT">Chapter 6, "Printing System
+Management"</A>.
+
+
+<H1 ALIGN="RIGHT"><A NAME="PRINTING_MANAGEMENT">6 - Printing System Management</A></H1>
+
+<P>This chapter shows how you can configure the CUPS server.
+
+<H2>The Basics</H2>
+
+<P>Several text files are used to configure CUPS. All of the server
+configuration files are located in the <VAR>/etc/cups</VAR> directory:
+
+<UL>
+<DL>
+
+ <!-- NEED 1in -->
+ <DT>classes.conf
+
+ <DD>This file contains information on each printer class.
+ Normally you manipulate this file using the
+ <CODE>lpadmin</CODE> command or the Web interface.<BR>&nbsp;
+
+ <!-- NEED 1in -->
+ <DT>client.conf
+
+ <DD>This file provides the default server name for client
+ machines. See <A HREF="#CLIENT_SETUP">Chapter 5, "Client
+ Setup"</A> for more information.<BR>&nbsp;
+
+ <!-- NEED 1in -->
+ <DT>cupsd.conf
+
+ <DD>This file controls how the CUPS server
+ (<VAR>/usr/sbin/cupsd</VAR>) operates and is normally edited by
+ hand.<BR>&nbsp;
+
+ <!-- NEED 1in -->
+ <DT>mime.convs
+
+ <DD>This file contains a list of standard file conversion filters
+ and their costs. You normally do not edit this file.<BR>&nbsp;
+
+ <!-- NEED 1in -->
+ <DT>mime.types
+
+ <DD>This file contains a list of standard file formats and how to
+ recognize them. You normally do not edit this file.<BR>&nbsp;
+
+ <!-- NEED 1in -->
+ <DT>printers.conf
+
+ <DD>This file contains information on each printer. Normally
+ you manipulate this file using the <CODE>lpadmin</CODE> command
+ or the Web Interface.<BR>&nbsp;
+
+</DL>
+</UL>
+
+<H2><A NAME="RESTARTING">Restarting the CUPS Server</A></H2>
+
+<P>Once you have made a change to a configuration file you need to
+restart the CUPS server by sending it a <CODE>HUP</CODE> signal or using the
+supplied initialization script. The CUPS distributions install the
+script in the <VAR>init.d</VAR> directory with the name
+<VAR>cups</VAR>. The location varies based upon the operating system:
+
+<UL><PRE>
+<B>/etc/rc.d/init.d/cups restart ENTER</B>
+<B>/etc/init.d/cups restart ENTER</B>
+<B>/sbin/init.d/cups restart ENTER</B>
+</PRE></UL>
+
+<H2>Changing the Server Configuration</H2>
+
+<P>The <VAR>/etc/cups/cupsd.conf</VAR> file contains configuration
+<I>directives</I> that control how the server functions. Each directive
+is listed on a line by itself followed by its value. Comments are
+introduced using the number sign ("#") character at the beginning of a
+line. Since the server configuration file consists of plain text, you
+can use your favorite text editor to make changes to it.
+
+<!-- NEED 4in -->
+<H2>Server Directives</H2>
+
+<P>The <VAR>cupsd.conf</VAR> file contains many directives that
+determine how the server operates:
+
+<UL>
+<TABLE CELLPADDING="0" CELLSPACING="0" BORDER="0">
+<TR>
+<TD VALIGN="TOP">
+
+ <LI><A HREF="#AccessLog"><CODE>AccessLog</CODE></A>
+ <LI><A HREF="#Allow"><CODE>Allow</CODE></A>
+ <LI><A HREF="#AuthClass"><CODE>AuthClass</CODE></A>
+ <LI><A HREF="#AuthGroupName"><CODE>AuthGroupName</CODE></A>
+ <LI><A HREF="#AuthType"><CODE>AuthType</CODE></A>
+ <LI><A HREF="#AutoPurgeJobs"><CODE>AutoPurgeJobs</CODE></A>
+ <LI><A HREF="#BrowseAddress"><CODE>BrowseAddress</CODE></A>
+ <LI><A HREF="#BrowseAllow"><CODE>BrowseAllow</CODE></A>
+ <LI><A HREF="#BrowseDeny"><CODE>BrowseDeny</CODE></A>
+ <LI><A HREF="#BrowseInterval"><CODE>BrowseInterval</CODE></A>
+ <LI><A HREF="#BrowseOrder"><CODE>BrowseOrder</CODE></A>
+ <LI><A HREF="#BrowsePoll"><CODE>BrowsePoll</CODE></A>
+ <LI><A HREF="#BrowsePort"><CODE>BrowsePort</CODE></A>
+ <LI><A HREF="#BrowseProtocols"><CODE>BrowseProtocols</CODE></A>
+ <LI><A HREF="#BrowseRelay"><CODE>BrowseRelay</CODE></A>
+ <LI><A HREF="#BrowseShortNames"><CODE>BrowseShortNames</CODE></A>
+ <LI><A HREF="#BrowseTimeout"><CODE>BrowseTimeout</CODE></A>
+ <LI><A HREF="#Browsing"><CODE>Browsing</CODE></A>
+ <LI><A HREF="#Classification"><CODE>Classification</CODE></A>
+ <LI><A HREF="#ClassifyOverride"><CODE>ClassifyOverride</CODE></A>
+ <LI><A HREF="#DataDir"><CODE>DataDir</CODE></A>
+ <LI><A HREF="#DefaultCharset"><CODE>DefaultCharset</CODE></A>
+ <LI><A HREF="#DefaultLanguage"><CODE>DefaultLanguage</CODE></A>
+ <LI><A HREF="#Deny"><CODE>Deny</CODE></A>
+ <LI><A HREF="#DocumentRoot"><CODE>DocumentRoot</CODE></A>
+
+</TD>
+<TD VALIGN="TOP">
+&nbsp;&nbsp;&nbsp;
+</TD>
+<TD VALIGN="TOP">
+
+ <LI><A HREF="#Encryption"><CODE>Encryption</CODE></A>
+ <LI><A HREF="#ErrorLog"><CODE>ErrorLog</CODE></A>
+ <LI><A HREF="#FilterLimit"><CODE>FilterLimit</CODE></A>
+ <LI><A HREF="#FontPath"><CODE>FontPath</CODE></A>
+ <LI><A HREF="#Group"><CODE>Group</CODE></A>
+ <LI><A HREF="#HideImplicitMembers"><CODE>HideImplicitMembers</CODE></A>
+ <LI><A HREF="#HostNameLookups"><CODE>HostNameLookups</CODE></A>
+ <LI><A HREF="#ImplicitClasses"><CODE>ImplicitClasses</CODE></A>
+ <LI><A HREF="#ImplicitAnyClasses"><CODE>ImplicitAnyClasses</CODE></A>
+ <LI><A HREF="#Include"><CODE>Include</CODE></A>
+ <LI><A HREF="#KeepAliveTimeout"><CODE>KeepAliveTimeout</CODE></A>
+ <LI><A HREF="#KeepAlive"><CODE>KeepAlive</CODE></A>
+ <LI><A HREF="#Limit"><CODE>Limit</CODE></A>
+ <LI><A HREF="#LimitExcept"><CODE>LimitExcept</CODE></A>
+ <LI><A HREF="#LimitRequestBody"><CODE>LimitRequestBody</CODE></A>
+ <LI><A HREF="#Listen"><CODE>Listen</CODE></A>
+ <LI><A HREF="#Location"><CODE>Location</CODE></A>
+ <LI><A HREF="#LogLevel"><CODE>LogLevel</CODE></A>
+ <LI><A HREF="#MaxClients"><CODE>MaxClients</CODE></A>
+ <LI><A HREF="#MaxJobs"><CODE>MaxJobs</CODE></A>
+ <LI><A HREF="#MaxJobsPerPrinter"><CODE>MaxJobsPerPrinter</CODE></A>
+ <LI><A HREF="#MaxJobsPerUser"><CODE>MaxJobsPerUser</CODE></A>
+ <LI><A HREF="#MaxLogSize"><CODE>MaxLogSize</CODE></A>
+ <LI><A HREF="#MaxRequestSize"><CODE>MaxRequestSize</CODE></A>
+ <LI><A HREF="#Order"><CODE>Order</CODE></A>
+
+</TD>
+<TD VALIGN="TOP">
+&nbsp;&nbsp;&nbsp;
+</TD>
+<TD VALIGN="TOP">
+
+ <LI><A HREF="#PageLog"><CODE>PageLog</CODE></A>
+ <LI><A HREF="#Port"><CODE>Port</CODE></A>
+ <LI><A HREF="#PreserveJobFiles"><CODE>PreserveJobFiles</CODE></A>
+ <LI><A HREF="#PreserveJobHistory"><CODE>PreserveJobHistory</CODE></A>
+ <LI><A HREF="#Printcap"><CODE>Printcap</CODE></A>
+ <LI><A HREF="#PrintcapFormat"><CODE>PrintcapFormat</CODE></A>
+ <LI><A HREF="#PrintcapGUI"><CODE>PrintcapGUI</CODE></A>
+ <LI><A HREF="#RemoteRoot"><CODE>RemoteRoot</CODE></A>
+ <LI><A HREF="#RequestRoot"><CODE>RequestRoot</CODE></A>
+ <LI><A HREF="#Require"><CODE>Require</CODE></A>
+ <LI><A HREF="#RIPCache"><CODE>RIPCache</CODE></A>
+ <LI><A HREF="#RunAsUser"><CODE>RunAsUser</CODE></A>
+ <LI><A HREF="#Satisfy"><CODE>Satisfy</CODE></A>
+ <LI><A HREF="#ServerAdmin"><CODE>ServerAdmin</CODE></A>
+ <LI><A HREF="#ServerBin"><CODE>ServerBin</CODE></A>
+ <LI><A HREF="#ServerCertificate"><CODE>ServerCertificate</CODE></A>
+ <LI><A HREF="#ServerKey"><CODE>ServerKey</CODE></A>
+ <LI><A HREF="#ServerName"><CODE>ServerName</CODE></A>
+ <LI><A HREF="#ServerRoot"><CODE>ServerRoot</CODE></A>
+ <LI><A HREF="#SSLListen"><CODE>SSLListen</CODE></A>
+ <LI><A HREF="#SSLPort"><CODE>SSLPort</CODE></A>
+ <LI><A HREF="#SystemGroup"><CODE>SystemGroup</CODE></A>
+ <LI><A HREF="#TempDir"><CODE>TempDir</CODE></A>
+ <LI><A HREF="#Timeout"><CODE>Timeout</CODE></A>
+ <LI><A HREF="#User"><CODE>User</CODE></A>
+
+</TD>
+</TR>
+</TABLE>
+</UL>
+
+<!-- NEED 3in -->
+<H3><A NAME="AccessLog">AccessLog</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+AccessLog /var/log/cups/access_log
+AccessLog /var/log/cups/access_log-%s
+AccessLog syslog
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>AccessLog</CODE> directive sets the name of the access log
+file. If the filename is not absolute then it is assumed to be relative
+to the <A HREF="#ServerRoot"><CODE>ServerRoot</CODE></A> directory. The
+access log file is stored in "common log format" and can be used by any
+web access reporting tool to generate a report on CUPS server activity.
+
+<P>The server name can be included in the filename by using
+<CODE>%s</CODE> in the name.
+
+<P>The special name "syslog" can be used to send the access information
+to the system log instead of a plain file.
+
+<P>The default access log file is <VAR>/var/log/cups/access_log</VAR>.
+
+<!-- NEED 6in -->
+<H3><A NAME="Allow">Allow</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+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
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>Allow</CODE> directive specifies a hostname, IP address,
+or network that is allowed access to the server. <CODE>Allow</CODE>
+directives are cummulative, so multiple <CODE>Allow</CODE> directives
+can be used to allow access for multiple hosts or networks. The
+<CODE>/mm</CODE> notation specifies a CIDR netmask:
+
+<CENTER><TABLE BORDER="1">
+<TR>
+ <TH WIDTH="10%">mm</TH>
+ <TH WIDTH="20%">netmask</TH>
+ <TH WIDTH="10%">mm</TH>
+ <TH WIDTH="20%">netmask</TH>
+</TR>
+<TR>
+ <TD ALIGN="CENTER">0</TD>
+ <TD ALIGN="CENTER">0.0.0.0</TD>
+ <TD ALIGN="CENTER">8</TD>
+ <TD ALIGN="CENTER">255.0.0.0</TD>
+</TR>
+<TR>
+ <TD ALIGN="CENTER">1</TD>
+ <TD ALIGN="CENTER">128.0.0.0</TD>
+ <TD ALIGN="CENTER">16</TD>
+ <TD ALIGN="CENTER">255.255.0.0</TD>
+</TR>
+<TR>
+ <TD ALIGN="CENTER">2</TD>
+ <TD ALIGN="CENTER">192.0.0.0</TD>
+ <TD ALIGN="CENTER">24</TD>
+ <TD ALIGN="CENTER">255.255.255.0</TD>
+</TR>
+<TR>
+ <TD ALIGN="CENTER">...</TD>
+ <TD ALIGN="CENTER">...</TD>
+ <TD ALIGN="CENTER">32</TD>
+ <TD ALIGN="CENTER">255.255.255.255</TD>
+</TR>
+</TABLE></CENTER>
+
+<P>The <CODE>Allow</CODE> directive must appear inside a
+<A HREF="#Location"><CODE>Location</CODE></A> directive.
+
+<!-- NEED 3in -->
+<H3><A NAME="AuthClass">AuthClass</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+AuthClass Anonymous
+AuthClass User
+AuthClass System
+AuthClass Group
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>AuthClass</CODE> directive defines what level of authentication
+is required:
+
+<UL>
+
+ <LI><CODE>Anonymous</CODE> - No authentication should be performed
+ (default.)
+
+ <LI><CODE>User</CODE> - A valid username and password is required.
+
+ <LI><CODE>System</CODE> - A valid username and password is
+ required, and the username must belong to the "sys" group; this
+ can be changed using the
+ <A HREF="#SystemGroup"><CODE>SystemGroup</CODE></A> directive.
+
+ <LI><CODE>Group</CODE> - A valid username and password is
+ required, and the username must belong to the group named by
+ the <CODE>AuthGroupName</CODE> directive.
+
+</UL>
+
+<P>The <CODE>AuthClass</CODE> directive must appear inside a
+<A HREF="#Location"><CODE>Location</CODE></A> directive.
+
+<!-- NEED 3in -->
+<H3><A NAME="AuthGroupName">AuthGroupName</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+AuthGroupName mygroup
+AuthGroupName lp
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>AuthGroupName</CODE> directive sets the group to use for
+<CODE>Group</CODE> authentication.
+
+<P>The <CODE>AuthGroupName</CODE> directive must appear inside a
+<A HREF="#Location"><CODE>Location</CODE></A> directive.
+
+<!-- NEED 3in -->
+<H3><A NAME="AuthType">AuthType</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+AuthType None
+AuthType Basic
+AuthType Digest
+AuthType BasicDigest
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>AuthType</CODE> directive defines the type of authentication to
+perform:
+
+<UL>
+
+ <LI><CODE>None</CODE> - No authentication should be performed
+ (default.)
+
+ <LI><CODE>Basic</CODE> - Basic authentication should be
+ performed using the UNIX password and group files.
+
+ <LI><CODE>Digest</CODE> - Digest authentication should be
+ performed using the <VAR>/etc/cups/passwd.md5</VAR> file.
+
+ <LI><CODE>BasicDigest</CODE> - Basic authentication should be
+ performed using the <VAR>/etc/cups/passwd.md5</VAR> file.
+
+</UL>
+
+<P>When using <CODE>Basic</CODE>, <CODE>Digest</CODE>, or
+<CODE>BasicDigest</CODE> authentication, clients connecting
+through the <CODE>localhost</CODE> interface can also
+authenticate using <A HREF="#CERTIFICATES">certificates</A>.
+
+<P>The <CODE>AuthType</CODE> directive must appear inside a
+<A HREF="#Location"><CODE>Location</CODE></A> directive.
+
+<!-- NEED 3in -->
+<H3><A NAME="AutoPurgeJobs">AutoPurgeJobs</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+AutoPurgeJobs Yes
+AutoPurgeJobs No
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>AutoPurgeJobs</CODE> directive specifies whether or not to purge
+completed jobs once they are no longer required for quotas. This option has
+no effect if quotas are not enabled. The default setting is <CODE>No</CODE>.
+
+<!-- NEED 5in -->
+<H3><A NAME="BrowseAddress">BrowseAddress</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+BrowseAddress 255.255.255.255:631
+BrowseAddress 192.0.2.255:631
+BrowseAddress host.domain.com:631
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>BrowseAddress</CODE> directive specifies an address to
+send browsing information to. Multiple <CODE>BrowseAddress</CODE>
+directives can be specified to send browsing information to different
+networks or systems.
+
+<P>The default address is <CODE>255.255.255.255:631</CODE> which will
+broadcast the information to all networks the server is connected to.
+
+<CENTER><TABLE WIDTH="80%" BORDER="1" CELLPADDING="5" BGCOLOR="#cccccc">
+<TR>
+ <TD>
+ <B>NOTE:</B>
+
+ <P>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.
+ </TD>
+</TR>
+</TABLE></CENTER>
+
+<!-- NEED 4in -->
+<H3><A NAME="BrowseAllow">BrowseAllow</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+BrowseAllow from all
+BrowseAllow from none
+BrowseAllow from 192.0.2
+BrowseAllow from 192.0.2.0/24
+BrowseAllow from 192.0.2.0/255.255.255.0
+BrowseAllow from *.domain.com
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>BrowseAllow</CODE> directive specifies a system or network
+to accept browse packets from. The default is to accept browse packets
+from all hosts.
+
+<P>Host and domain name matching require that you enable the
+<A HREF="#HostNameLookups"><CODE>HostNameLookups</CODE></A> directive.
+
+<P>IP address matching supports exact matches, partial addresses that
+match networks using netmasks of 255.0.0.0, 255.255.0.0, and 255.255.255.0,
+or network addresses using the specified netmask or bit count.
+
+<!-- NEED 4in -->
+<H3><A NAME="BrowseDeny">BrowseDeny</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+BrowseDeny from all
+BrowseDeny from none
+BrowseDeny from 192.0.2
+BrowseDeny from 192.0.2.0/24
+BrowseDeny from 192.0.2.0/255.255.255.0
+BrowseDeny from *.domain.com
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>BrowseDeny</CODE> directive specifies a system or network
+to reject browse packets from. The default is to deny browse packets
+from no hosts.
+
+<P>Host and domain name matching require that you enable the
+<A HREF="#HostNameLookups"><CODE>HostNameLookups</CODE></A> directive.
+
+<P>IP address matching supports exact matches, partial addresses that
+match networks using netmasks of 255.0.0.0, 255.255.0.0, and 255.255.255.0,
+or network addresses using the specified netmask or bit count.
+
+<!-- NEED 3in -->
+<H3><A NAME="BrowseOrder">BrowseOrder</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+BrowseOrder allow,deny
+BrowseOrder deny,allow
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>BrowseOrder</CODE> directive specifies the order of allow/deny
+processing. The default order is <CODE>deny,allow</CODE>:
+
+<UL>
+
+ <LI><CODE>allow,deny</CODE> - Browse packets are accepted unless
+ specifically denied.
+
+ <LI><CODE>deny,allow</CODE> - Browse packets are rejected unless
+ specifically allowed.
+
+</UL>
+
+<!-- NEED 3in -->
+<H3><A NAME="BrowseInterval">BrowseInterval</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+BrowseInterval 0
+BrowseInterval 30
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>BrowseInterval</CODE> directive specifies the maximum amount of
+time between browsing updates. Specifying a value of 0 seconds disables
+outgoing browse updates but allows a server to receive printer information
+from other hosts.
+
+<P>The <CODE>BrowseInterval</CODE> value should always be less than the
+<A HREF="#BrowseTimeout"><CODE>BrowseTimeout</CODE></A> value. Otherwise
+printers and classes will disappear from client systems between updates.
+
+<!-- NEED 3in -->
+<H3><A NAME="BrowsePoll">BrowsePoll</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+BrowsePoll 192.0.2.2:631
+BrowsePoll host.domain.com:631
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>BrowsePoll</CODE> directive polls a server for available
+printers once every
+<A HREF="#BrowseInterval"><CODE>BrowseInterval</CODE></A> seconds.
+Multiple <CODE>BrowsePoll</CODE> directives can be specified to poll
+multiple servers.
+
+<P>If <CODE>BrowseInterval</CODE> is set to 0 then the server is polled
+once every 30 seconds.
+
+<!-- NEED 3in -->
+<H3><A NAME="BrowsePort">BrowsePort</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+BrowsePort 631
+BrowsePort 9999
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>BrowsePort</CODE> directive specifies the UDP port number
+used for browse packets. The default port number is 631.
+
+<CENTER><TABLE WIDTH="80%" BORDER="1" CELLPADDING="5" BGCOLOR="#cccccc">
+<TR>
+ <TD>
+ <B>NOTE:</B>
+
+ <P>You must set the <CODE>BrowsePort</CODE> to the same value
+ on all of the systems that you want to see.
+ </TD>
+</TR>
+</TABLE></CENTER>
+
+<!-- NEED 3in -->
+<H3><A NAME="BrowseProtocols">BrowseProtocols</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+BrowseProtocols CUPS
+BrowseProtocols SLP
+BrowseProtocols CUPS SLP
+BrowseProtocols all
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>BrowseProtocols</CODE> directive specifies the protocols to
+use when collecting and distributing shared printers on the local network.
+The default protocol is <CODE>CUPS</CODE>, which is a broadcast-based
+protocol.
+
+<CENTER><TABLE WIDTH="80%" BORDER="1" CELLPADDING="5" BGCOLOR="#cccccc">
+<TR>
+ <TD>
+ <B>NOTE:</B>
+
+ <P>When using the <CODE>SLP</CODE> protocol, you must have at least
+ one Directory Agent (DA) server on your network. Otherwise the
+ CUPS scheduler (<CODE>cupsd</CODE>) will not respond to client
+ requests for several seconds while polling the network.
+ </TD>
+</TR>
+</TABLE></CENTER>
+
+<!-- NEED 4in -->
+<H3><A NAME="BrowseRelay">BrowseRelay</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+BrowseRelay 193.0.2.1 192.0.2.255
+BrowseRelay 193.0.2.0/255.255.255.0 192.0.2.255
+BrowseRelay 193.0.2.0/24 192.0.2.255
+BrowseRelay *.domain.com 192.0.2.255
+BrowseRelay host.domain.com 192.0.2.255
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>BrowseRelay</CODE> directive specifies source and destination
+addresses for relaying browsing information from one host or network to
+another. Multiple <CODE>BrowseRelay</CODE> directives can be specified
+as needed.
+
+<P><CODE>BrowseRelay</CODE> is typically used on systems that bridge
+multiple subnets using one or more network interfaces. It can also be
+used to relay printer information from polled servers with the line:
+
+<UL><PRE>
+BrowseRelay 127.0.0.1 255.255.255.255
+</PRE></UL>
+
+<P>This effectively provides access to printers on a WAN for all clients
+on the LAN(s).
+
+<!-- NEED 3in -->
+<H3><A NAME="BrowseShortNames">BrowseShortNames</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+BrowseShortNames Yes
+BrowseShortNames No
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>BrowseShortNames</CODE> directive specifies whether or not
+short names are used for remote printers when possible. Short names are
+just the remote printer name, without the server ("printer"). If more than
+one remote printer is detected with the same name, the printers will have
+long names ("printer@server1", "printer@server2".)
+
+<P>The default value for this option is <CODE>Yes</CODE>.
+
+<!-- NEED 3in -->
+<H3><A NAME="BrowseTimeout">BrowseTimeout</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+BrowseTimeout 300
+BrowseTimeout 60
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>BrowseTimeout</CODE> directive sets the timeout for
+printer or class information that is received in browse packets. Once a
+printer or class times out it is removed from the list of available
+destinations.
+
+<P>The <CODE>BrowseTimeout</CODE> value should always be greater than the
+<A HREF="#BrowseInterval"><CODE>BrowseInterval</CODE></A> value. Otherwise
+printers and classes will disappear from client systems between updates.
+
+<!-- NEED 4in -->
+<H3><A NAME="Browsing">Browsing</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+Browsing On
+Browsing Off
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>Browsing</CODE> directive controls whether or not network printer
+browsing is enabled. The default setting is <CODE>On</CODE>.
+
+<CENTER><TABLE WIDTH="80%" BORDER="1" CELLPADDING="5" BGCOLOR="#cccccc">
+<TR>
+ <TD>
+ <B>NOTE:</B>
+
+ <P>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.
+ </TD>
+</TR>
+</TABLE></CENTER>
+
+<!-- NEED 3in -->
+<H3><A NAME="Classification">Classification</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+Classification
+Classification classified
+Classification confidential
+Classification secret
+Classification topsecret
+Classification unclassified
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>Classification</CODE> directive sets the classification level
+on the server. When this option is set, at least one of the banner pages
+is forced to the classification level, and the classification is placed
+on each page of output. The default is no classification level.
+
+<!-- NEED 3in -->
+<H3><A NAME="ClassifyOverride">ClassifyOverride</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+ClassifyOverride Yes
+ClassifyOverride No
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>ClassifyOverride</CODE> directive specifies whether users
+can override the default classification level on the server. When the
+server classification is set, users can change the classification using
+the <CODE>job-sheets</CODE> option and can choose to only print one
+security banner before or after the job. If the <CODE>job-sheets</CODE>
+option is set to <CODE>none</CODE> then the server default classification
+is used.
+
+<P>The default is to not allow classification overrides.
+
+<!-- NEED 3in -->
+<H3><A NAME="DataDir">DataDir</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+DataDir /usr/share/cups
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>DataDir</CODE> directive sets the directory to use for data
+files.
+
+<!-- NEED 3in -->
+<H3><A NAME="DefaultCharset">DefaultCharset</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+DefaultCharset utf-8
+DefaultCharset iso-8859-1
+DefaultCharset windows-1251
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>DefaultCharset</CODE> directive sets the default character set
+to use for client connections. The default character set is
+<CODE>utf-8</CODE> but is overridden by the character set for the language
+specified by the client or the <CODE>DefaultLanguage</CODE> directive.
+
+<!-- NEED 3in -->
+<H3><A NAME="DefaultLanguage">DefaultLanguage</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+DefaultLanguage de
+DefaultLanguage en
+DefaultLanguage es
+DefaultLanguage fr
+DefaultLanguage it
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>DefaultLanguage</CODE> directive specifies the default language
+to use for client connections. Setting the default language also sets the
+default character set if a language localization file exists for it. The
+default language is "en" for English.
+
+<!-- NEED 5in -->
+<H3><A NAME="Deny">Deny</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+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
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>Deny</CODE> directive specifies a hostname, IP address, or
+network that is allowed access to the server. <CODE>Deny</CODE>
+directives are cummulative, so multiple <CODE>Deny</CODE> directives
+can be used to allow access for multiple hosts or networks. The
+<CODE>/mm</CODE> notation specifies a CIDR netmask:
+
+<CENTER><TABLE BORDER="1">
+<TR>
+ <TH WIDTH="10%">mm</TH>
+ <TH WIDTH="20%">netmask</TH>
+ <TH WIDTH="10%">mm</TH>
+ <TH WIDTH="20%">netmask</TH>
+</TR>
+<TR>
+ <TD ALIGN="CENTER">0</TD>
+ <TD ALIGN="CENTER">0.0.0.0</TD>
+ <TD ALIGN="CENTER">8</TD>
+ <TD ALIGN="CENTER">255.0.0.0</TD>
+</TR>
+<TR>
+ <TD ALIGN="CENTER">1</TD>
+ <TD ALIGN="CENTER">128.0.0.0</TD>
+ <TD ALIGN="CENTER">16</TD>
+ <TD ALIGN="CENTER">255.255.0.0</TD>
+</TR>
+<TR>
+ <TD ALIGN="CENTER">2</TD>
+ <TD ALIGN="CENTER">192.0.0.0</TD>
+ <TD ALIGN="CENTER">24</TD>
+ <TD ALIGN="CENTER">255.255.255.0</TD>
+</TR>
+<TR>
+ <TD ALIGN="CENTER">...</TD>
+ <TD ALIGN="CENTER">...</TD>
+ <TD ALIGN="CENTER">32</TD>
+ <TD ALIGN="CENTER">255.255.255.255</TD>
+</TR>
+</TABLE></CENTER>
+
+<P>The <CODE>Deny</CODE> directive must appear inside a
+<A HREF="#Location"><CODE>Location</CODE></A> directive.
+
+<!-- NEED 3in -->
+<H3><A NAME="DocumentRoot">DocumentRoot</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+DocumentRoot /usr/share/doc/cups
+DocumentRoot /foo/bar/doc/cups
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>DocumentRoot</CODE> directive specifies the location of
+web content for the HTTP server in CUPS. If an absolute path is not
+specified then it is assumed to be relative to the
+<A HREF="#ServerRoot"><CODE>ServerRoot</CODE></A> directory. The
+default directory is <VAR>/usr/share/doc/cups</VAR>.
+
+<P>Documents are first looked up in a sub-directory for the primary
+language requested by the client (e.g. <VAR>/usr/share/doc/cups/fr/...</VAR>)
+and then directly under the <CODE>DocumentRoot</CODE> directory
+(e.g. <VAR>/usr/share/doc/cups/...</VAR>), so it is possible to localize
+the web content by providing subdirectories for each language needed.
+
+<!-- NEED 3in -->
+<H3><A NAME="Encryption">Encryption</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+Encryption Never
+Encryption IfRequested
+Encryption Required
+Encryption Always
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>Encryption</CODE> directive must appear instead a
+<A HREF="#Location"><CODE>Location</CODE></A>
+section and specifies the encryption settings for that location.
+The default setting is <CODE>IfRequested</CODE> for all locations.
+
+<!-- NEED 3in -->
+<H3><A NAME="ErrorLog">ErrorLog</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+ErrorLog /var/log/cups/error_log
+ErrorLog /var/log/cups/error_log-%s
+ErrorLog syslog
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>ErrorLog</CODE> directive sets the name of the error log
+file. If the filename is not absolute then it is assumed to be relative
+to the <A HREF="#ServerRoot"><CODE>ServerRoot</CODE></A> directory. The
+default error log file is <VAR>/var/log/cups/error_log</VAR>.
+
+<P>The server name can be included in the filename by using
+<CODE>%s</CODE> in the name.
+
+<P>The special name "syslog" can be used to send the error information
+to the system log instead of a plain file.
+
+<!-- NEED 3in -->
+<H3><A NAME="FilterLimit">FilterLimit</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+FilterLimit 0
+FilterLimit 200
+FilterLimit 1000
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>FilterLimit</CODE> directive sets the maximum cost
+of all running job filters. It can be used to limit the number
+of filter programs that are run on a server to minimize disk,
+memory, and CPU resource problems. A limit of 0 disables filter
+limiting.
+
+<P>An average print to a non-PostScript printer needs a filter
+limit of about 200. A PostScript printer needs about half that
+(100). Setting the limit below these thresholds will effectively
+limit the scheduler to printing a single job at any time.
+
+<P>The default limit is 0.
+
+<!-- NEED 3in -->
+<H3><A NAME="FontPath">FontPath</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+FontPath /foo/bar/fonts
+FontPath /usr/share/cups/fonts:/foo/bar/fonts
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>FontPath</CODE> directive specifies the font path to use when
+searching for fonts. The default font path is
+<CODE>/usr/share/cups/fonts</CODE>.
+
+<!-- NEED 3in -->
+<H3><A NAME="Group">Group</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+Group sys
+Group system
+Group root
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>Group</CODE> directive specifies the UNIX group that
+filter and CGI programs run as. The default group is <CODE>sys</CODE>,
+<CODE>system</CODE>, or <CODE>root</CODE> depending on the operating
+system.
+
+<!-- NEED 3in -->
+<H3><A NAME="HideImplicitMembers">HideImplicitMembers</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+HideImplicitMembers Yes
+HideImplicitMembers No
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>HideImplicitMembers</CODE> directive controls
+whether the individual printers in an implicit class are shown
+to the user. The default is <CODE>No</CODE>.</P>
+
+<P><A HREF="#ImplicitClasses"><CODE>ImplicitClasses</CODE></A>
+must be enabled for this directive to have any effect.</P>
+
+<!-- NEED 3in -->
+<H3><A NAME="HostNameLookups">HostNameLookups</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+HostNameLookups On
+HostNameLookups Off
+HostNameLookups Double
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>HostNameLookups</CODE> directive controls whether
+or not CUPS looks up the hostname for connecting clients. The
+<CODE>Double</CODE> setting causes CUPS to verify that the
+hostname resolved from the address matches one of the addresses
+returned for that hostname. <CODE>Double</CODE> lookups also
+prevent clients with unregistered addresses from connecting
+to your server.
+
+The default is <CODE>Off</CODE> to avoid the potential server
+performance problems with hostname lookups. Set this option to
+<CODE>On</CODE> or <CODE>Double</CODE> only if absolutely
+required.
+
+<!-- NEED 3in -->
+<H3><A NAME="ImplicitClasses">ImplicitClasses</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+ImplicitClasses On
+ImplicitClasses Off
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>ImplicitClasses</CODE> directive controls whether implicit
+classes are created based upon the available network printers and classes.
+The default setting is <CODE>On</CODE> but is automatically turned
+<CODE>Off</CODE> if <A HREF="#Browsing"><CODE>Browsing</CODE></A> is
+turned <CODE>Off</CODE>.
+
+<!-- NEED 3in -->
+<H3><A NAME="ImplicitAnyClasses">ImplicitAnyClasses</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+ImplicitAnyClasses On
+ImplicitAnyClasses Off
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>ImplicitAnyClasses</CODE> directive controls
+whether implicit classes for local and remote printers are
+created with the name <CODE>AnyPrinter</CODE>. The default
+setting is <CODE>Off</CODE>.</P>
+
+<P><A HREF="#ImplicitClasses"><CODE>ImplicitClasses</CODE></A>
+must be enabled for this directive to have any effect.</P>
+
+<!-- NEED 3in -->
+<H3><A NAME="Include">Include</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+Include filename
+Include /foo/bar/filename
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>Include</CODE> directive includes the named file in
+the <CODE>cupsd.conf</CODE> file. If no leading path is
+provided, the file is assumed to be relative to the
+<A HREF="#ServerRoot"><CODE>ServerRoot</CODE></A> directory.</P>
+
+<!-- NEED 3in -->
+<H3><A NAME="KeepAlive">KeepAlive</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+KeepAlive On
+KeepAlive Off
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>KeepAlive</CODE> directive controls whether or not to support
+persistent HTTP connections. The default is <CODE>On</CODE>.
+
+<P>HTTP/1.1 clients automatically support persistent connections, while
+HTTP/1.0 clients must specifically request them using the
+<CODE>Keep-Alive</CODE> attribute in the <CODE>Connection:</CODE>
+field of each request.
+
+<!-- NEED 3in -->
+<H3><A NAME="KeepAliveTimeout">KeepAliveTimeout</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+KeepAliveTimeout 60
+KeepAliveTimeout 30
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>KeepAliveTimeout</CODE> directive controls how long a
+persistent HTTP connection will remain open after the last request. The
+default is 60 seconds.
+
+<!-- NEED 3in -->
+<H3><A NAME="Limit">Limit</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+&lt;Limit GET POST&gt;
+...
+&lt;/Limit&gt;
+
+&lt;Limit ALL&gt;
+...
+&lt;/Limit&gt;
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>Limit</CODE> directive groups access control directives for
+specific types of HTTP requests and must appear inside a
+<A HREF="#Location"><CODE>Location</CODE></A> section. Access can be limited
+for individual request types (<CODE>DELETE</CODE>, <CODE>GET</CODE>,
+<CODE>HEAD</CODE>, <CODE>OPTIONS</CODE>, <CODE>POST</CODE>, <CODE>PUT</CODE>,
+and <CODE>TRACE</CODE>) or for all request types (<CODE>ALL</CODE>). The
+request type names are case-sensitive for compatibility with Apache.
+
+<!-- NEED 3in -->
+<H3><A NAME="LimitExcept">LimitExcept</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+&lt;LimitExcept GET POST&gt;
+...
+&lt;/LimitExcept&gt;
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>LimitExcept</CODE> directive groups access control directives for
+specific types of HTTP requests and must appear inside a
+<A HREF="#Location"><CODE>Location</CODE></A> section. Unlike the
+<A HREF="#Limit"><CODE>Limit</CODE></A> directive, <CODE>LimitExcept</CODE>
+restricts access for all requests <I>except</I> those listed on the
+<CODE>LimitExcept</CODE> line.
+
+<!-- NEED 3in -->
+<H3><A NAME="LimitRequestBody">LimitRequestBody</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+LimitRequestBody 10485760
+LimitRequestBody 10m
+LimitRequestBody 0
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>LimitRequestBody</CODE> directive controls the maximum size of
+print files, IPP requests, and HTML form data in HTTP POST requests. The
+default limit is 0 which disables the limit check.
+
+<P>Also see the identical
+<A HREF="#MaxRequestSize"><CODE>MaxRequestSize</CODE></A> directive.
+
+<!-- NEED 3in -->
+<H3><A NAME="Listen">Listen</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+Listen 127.0.0.1:631
+Listen 192.0.2.1:631
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>Listen</CODE> directive specifies a network address and port
+to listen for connections. Multiple <CODE>Listen</CODE> directives can be
+provided to listen on multiple addresses.
+
+<P>The <CODE>Listen</CODE> directive is similar to the
+<A HREF="#Port"><CODE>Port</CODE></A> directive but allows you to restrict
+access to specific interfaces or networks.
+
+<!-- NEED 3in -->
+<H3><A NAME="Location">Location</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+&lt;Location /&gt;
+...
+&lt;/Location&gt;
+
+&lt;Location /admin&gt;
+...
+&lt;/Location&gt;
+
+&lt;Location /printers/name&gt;
+...
+&lt;/Location&gt;
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>Location</CODE> directive specifies access control and
+authentication options for the specified HTTP resource or path. More
+information can be found later in this chapter in
+<A HREF="#PRINTING_SECURITY">"Printing System Security"</A>.
+
+<!-- NEED 3in -->
+<H3><A NAME="LogLevel">LogLevel</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+LogLevel none
+LogLevel emerg
+LogLevel alert
+LogLevel crit
+LogLevel error
+LogLevel warn
+LogLevel notice
+LogLevel info
+LogLevel debug
+LogLevel debug2
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>LogLevel</CODE> directive specifies the level of logging
+for the <A HREF="#ErrorLog"><CODE>ErrorLog</CODE></A> file. The
+following values are recognized (each level logs everything under the
+preceding levels):
+
+<UL>
+
+ <LI><CODE>none</CODE> - Log nothing.
+
+ <LI><CODE>emerg</CODE> - Log emergency conditions that prevent the
+ server from running.
+
+ <LI><CODE>alert</CODE> - Log alerts that must be handled immediately.
+
+ <LI><CODE>crit</CODE> - Log critical errors that don't prevent
+ the server from running.
+
+ <LI><CODE>error</CODE> - Log general errors.
+
+ <LI><CODE>warn</CODE> - Log errors and warnings.
+
+ <LI><CODE>notice</CODE> - Log temporary error conditions.
+
+ <LI><CODE>info</CODE> - Log all requests and state changes (default).
+
+ <LI><CODE>debug</CODE> - Log basic debugging information.
+
+ <LI><CODE>debug2</CODE> - Log all debugging information.
+
+</UL>
+
+<!-- NEED 3in -->
+<H3><A NAME="MaxClients">MaxClients</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+MaxClients 100
+MaxClients 1024
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>MaxClients</CODE> directive controls the maximum number of
+simultaneous clients that will be allowed by the server. The default is
+100 clients.
+
+<CENTER><TABLE WIDTH="80%" BORDER="1" CELLPADDING="5" BGCOLOR="#cccccc">
+<TR>
+ <TD>
+ <B>NOTE:</B>
+
+ <P>Since each print job requires a file descriptor for the
+ status pipe, the CUPS server internally limits the
+ <CODE>MaxClients</CODE> value to 1/3 of the available file descriptors
+ to avoid possible problems when printing large numbers of jobs.
+ </TD>
+</TR>
+</TABLE></CENTER>
+
+<!-- NEED 3in -->
+<H3><A NAME="MaxJobs">MaxJobs</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+MaxJobs 100
+MaxJobs 9999
+MaxJobs 0
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>MaxJobs</CODE> directive controls the maximum number of jobs
+that are kept in memory. Once the number of jobs reaches the limit, the
+oldest completed job is automatically purged from the system to make room
+for the new one. If all of the known jobs are still pending or active then
+the new job will be rejected.
+
+<P>Setting the maximum to 0 disables this functionality. The default
+setting is 0.
+
+<!-- NEED 3in -->
+<H3><A NAME="MaxJobsPerPrinter">MaxJobsPerPrinter</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+MaxJobsPerPrinter 100
+MaxJobsPerPrinter 9999
+MaxJobsPerPrinter 0
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>MaxJobsPerPrinter</CODE> directive controls the maximum number of active jobs
+that are allowed for each printer or class. Once a printer or class reaches the limit, new jobs will be
+rejected until one of the active jobs is completed, stopped, aborted, or cancelled.
+
+<P>Setting the maximum to 0 disables this functionality. The default
+setting is 0.
+
+<!-- NEED 3in -->
+<H3><A NAME="MaxJobsPerUser">MaxJobsPerUser</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+MaxJobsPerUser 100
+MaxJobsPerUser 9999
+MaxJobsPerUser 0
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>MaxJobsPerUser</CODE> directive controls the maximum number of active jobs
+that are allowed for each user. Once a user reaches the limit, new jobs will be
+rejected until one of the active jobs is completed, stopped, aborted, or cancelled.
+
+<P>Setting the maximum to 0 disables this functionality. The default
+setting is 0.
+
+<!-- NEED 3in -->
+<H3><A NAME="MaxLogSize">MaxLogSize</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+MaxLogSize 1048576
+MaxLogSize 1m
+MaxLogSize 0
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>MaxLogSize</CODE> directive controls the maximum size of each
+log file. Once a log file reaches or exceeds the maximum size it is closed
+and renamed to <VAR>filename.O</VAR>. This allows you to rotate the logs
+automatically. The default size is 1048576 bytes (1MB).
+
+<P>Setting the maximum size to 0 disables log rotation.
+
+<!-- NEED 3in -->
+<H3><A NAME="MaxRequestSize">MaxRequestSize</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+MaxRequestSize 10485760
+MaxRequestSize 10m
+MaxRequestSize 0
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>MaxRequestSize</CODE> directive controls the maximum size of
+print files, IPP requests, and HTML form data in HTTP POST requests. The
+default limit is 0 which disables the limit check.
+
+<P>Also see the identical
+<A HREF="#LimitRequestBody"><CODE>LimitRequestBody</CODE></A> directive.
+
+<!-- NEED 3in -->
+<H3><A NAME="Order">Order</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+Order Allow,Deny
+Order Deny,Allow
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>Order</CODE> directive defines the default access control.
+The following values are supported:
+
+<UL>
+
+ <LI><CODE>Allow,Deny</CODE> - Allow requests from all
+ systems <I>except</I> for those listed in a <CODE>Deny</CODE>
+ directive.
+
+ <LI><CODE>Deny,Allow</CODE> - Allow requests only from
+ those listed in an <CODE>Allow</CODE> directive.
+
+</UL>
+
+<P>The <CODE>Order</CODE> directive must appear inside a
+<A HREF="#Location"><CODE>Location</CODE></A> directive.
+
+<!-- NEED 3in -->
+<H3><A NAME="PageLog">PageLog</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+PageLog /var/log/cups/page_log
+PageLog /var/log/cups/page_log-%s
+PageLog syslog
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>PageLog</CODE> directive sets the name of the page log
+file. If the filename is not absolute then it is assumed to be relative
+to the <A HREF="#ServerRoot"><CODE>ServerRoot</CODE></A> directory. The
+default page log file is <VAR>/var/log/cups/page_log</VAR>.
+
+<P>The server name can be included in the filename by using
+<CODE>%s</CODE> in the name.
+
+<P>The special name "syslog" can be used to send the page information
+to the system log instead of a plain file.
+
+<!-- NEED 3in -->
+<H3><A NAME="Port">Port</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+Port 631
+Port 80
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>Port</CODE> directive specifies a port to listen on.
+Multiple <CODE>Port</CODE> lines can be specified to listen on multiple
+ports. The default port is 631.
+
+<!-- NEED 3in -->
+<H3><A NAME="PreserveJobHistory">PreserveJobHistory</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+PreserveJobHistory On
+PreserveJobHistory Off
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>PreserveJobHistory</CODE> directive controls whether
+the history of completed, cancelled, or aborted print jobs is stored
+on disk.
+
+<P>A value of <CODE>On</CODE> (the default) preserves job information
+until the administrator purges it with the <CODE>cancel</CODE>
+command.
+
+<P>A value of <CODE>Off</CODE> removes the job information as soon as
+each job is completed, cancelled, or aborted.
+
+<!-- NEED 3in -->
+<H3><A NAME="PreserveJobFiles">PreserveJobFiles</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+PreserveJobFiles On
+PreserveJobFiles Off
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>PreserveJobFiles</CODE> directive controls whether the
+document files of completed, cancelled, or aborted print jobs are
+stored on disk.
+
+<P>A value of <CODE>On</CODE> preserves job files until the
+administrator purges them with the <CODE>cancel</CODE> command. Jobs
+can be restarted (and reprinted) as desired until they are purged.
+
+<P>A value of <CODE>Off</CODE> (the default) removes the job files as
+soon as each job is completed, cancelled, or aborted.
+
+<!-- NEED 3in -->
+<H3><A NAME="Printcap">Printcap</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+Printcap
+Printcap /etc/printcap
+Printcap /etc/printers.conf
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>Printcap</CODE> directive controls whether or not a
+printcap file is automatically generated and updated with a list
+of available printers. If specified with no value, then no
+printcap file will be generated. The default is to generate a
+file named <VAR>/etc/printcap</VAR>.
+
+<P>When a filename is specified (e.g. <VAR>/etc/printcap</VAR>), the
+printcap file is written whenever a printer is added or removed. The
+printcap file can then be used by applications that are hardcoded to
+look at the printcap file for the available printers.
+
+<!-- NEED 3in -->
+<H3><A NAME="PrintcapFormat">PrintcapFormat</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+PrintcapFormat BSD
+PrintcapFormat Solaris
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>PrintcapFormat</CODE> directive controls the output
+format of the printcap file. The default is to generate a BSD
+printcap file.
+
+<!-- NEED 3in -->
+<H3><A NAME="PrintcapGUI">PrintcapGUI</A></H3>
+<HR>
+
+<H4>Example</H4>
+
+<UL><PRE>
+PrintcapGUI /usr/bin/glpoptions
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>PrintcapGUI</CODE> directive sets the program to
+use when displaying an option panel from an IRIX application
+that uses the Impressario print API. The default program is the
+ESP Print Pro "glpoptions" GUI.
+
+<P>The program must accept the <CODE>-d</CODE> option to specify
+a printer and the <CODE>-o</CODE> option to specify one or more
+options. After allowing the user to select/change options, the
+program must then write the list of printing options without the
+<CODE>-o</CODE> to the standard output.
+
+<!-- NEED 3in -->
+<H3><A NAME="RemoteRoot">RemoteRoot</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+RemoteRoot remroot
+RemoteRoot root
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>RemoteRoot</CODE> directive sets the username for
+unauthenticated root requests from remote hosts. The default
+username is <VAR>remroot</VAR>. Setting <CODE>RemoteRoot</CODE>
+to <VAR>root</VAR> effectively disables this security mechanism.
+
+<!-- NEED 3in -->
+<H3><A NAME="RequestRoot">RequestRoot</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+RequestRoot /var/spool/cups
+RequestRoot /foo/bar/spool/cups
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>RequestRoot</CODE> directive sets the directory for
+incoming IPP requests and HTML forms. If an absolute path is not
+provided then it is assumed to be relative to the
+<A HREF="#ServerRoot"><CODE>ServerRoot</CODE></A> directory. The
+default request directory is <VAR>/var/spool/cups</VAR>.
+
+<!-- NEED 4in -->
+<H3><A NAME="Require">Require</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+Require group foo bar
+Require user john mary
+Require valid-user
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>Require</CODE> directive specifies that
+authentication is required for the resource. The
+<CODE>group</CODE> keyword specifies that the authenticated user
+must be a member of one or more of the named groups that follow.
+
+<P>The <CODE>user</CODE> keyboard specifies that the
+authenticated user must be one of the named users that follow.
+
+<P>The <CODE>valid-user</CODE> keyword specifies that any
+authenticated user may access the resource.
+
+<P>The default is to do no authentication. This directive must
+appear inside a <A HREF="#Location"><CODE>Location</CODE></A>
+directive.
+
+<!-- NEED 3in -->
+<H3><A NAME="RIPCache">RIPCache</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+RIPCache 8m
+RIPCache 1g
+RIPCache 2048k
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>RIPCache</CODE> directive sets the size of the memory
+cache used by Raster Image Processor ("RIP") filters such as
+<CODE>imagetoraster</CODE> and <CODE>pstoraster</CODE>. The size can
+be suffixed with a "k" for kilobytes, "m" for megabytes, or
+"g" for gigabytes. The default cache size is "8m", or 8 megabytes.
+
+<!-- NEED 3in -->
+<H3><A NAME="RunAsUser">RunAsUser</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+RunAsUser Yes
+RunAsUser No
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>RunAsUser</CODE> directive controls whether the
+scheduler runs as the unpriviledged user account (usually <CODE>lp</CODE>).
+The default is <CODE>No</CODE> which leaves the scheduler running as
+the <CODE>root</CODE> user.
+
+<P><B>Note:</B> Running as a non-priviledged user may prevent
+LPD and locally connected printers from working due to
+permission problems. The <CODE>lpd</CODE> backend will
+automatically use a non-priviledged mode that is not 100%
+compliant with RFC 1179. The <CODE>parallel</CODE>,
+<CODE>serial</CODE>, and <CODE>usb</CODE> backends will need
+write access to the corresponding device files.
+
+<!-- NEED 3in -->
+<H3><A NAME="Satisfy">Satisfy</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+Satisfy all
+Satisfy any
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>Satisfy</CODE> directive specifies whether all
+conditions must be satisfied to allow access to the resource. If
+set to <CODE>all</CODE>, then all authentication and access
+control conditions must be satified to allow access.
+
+<P>Setting <CODE>Satisfy</CODE> to <CODE>any</CODE> allows a user to
+gain access if the authentication or access control requirements are
+satisfied. For example, you might require authentication for remote
+access, but allow local access without authentication.
+
+<P>The default is <CODE>all</CODE>. This directive must appear
+inside a <A HREF="#Location"><CODE>Location</CODE></A>
+directive.
+
+<!-- NEED 3in -->
+<H3><A NAME="ServerAdmin">ServerAdmin</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+ServerAdmin user@host
+ServerAdmin root@foo.bar.com
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>ServerAdmin</CODE> directive identifies the email address for the
+administrator on the system. By default the administrator email address is
+<CODE>root@server</CODE>, where <CODE>server</CODE> is the server name.
+
+<!-- NEED 3in -->
+<H3><A NAME="ServerBin">ServerBin</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+ServerBin /usr/lib/cups
+ServerBin /foo/bar/lib/cups
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>ServerBin</CODE> directive sets the directory for
+server-run executables. If an absolute path is not provided then it is
+assumed to be relative to the
+<A HREF="#ServerRoot"><CODE>ServerRoot</CODE></A> directory. The
+default executable directory is <VAR>/usr/lib/cups</VAR>.
+
+<!-- NEED 3in -->
+<H3><A NAME="ServerCertificate">ServerCertificate</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+ServerCertificate /etc/cups/ssl/server.crt
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>ServerCertificate</CODE> directive specifies the
+location of the SSL certificate file used by the server when
+negotiating encrypted connections. The certificate must not be
+encrypted (password protected) since the scheduler normally runs
+in the background and will be unable to ask for a password.
+The default certificate file is <VAR>/etc/cups/ssl/server.crt</VAR>.
+
+<!-- NEED 3in -->
+<H3><A NAME="ServerKey">ServerKey</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+ServerKey /etc/cups/ssl/server.key
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>ServerKey</CODE> directive specifies the location
+of the SSL private key file used by the server when negotiating
+encrypted connections. The default key file is
+<VAR>/etc/cups/ssl/server.crt</VAR>.
+
+<!-- NEED 3in -->
+<H3><A NAME="ServerName"></A>ServerName</H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+ServerName foo.domain.com
+ServerName myserver.domain.com
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>ServerName</CODE> directive specifies the hostname that is
+reported to clients. By default the server name is the hostname.
+
+<!-- NEED 3in -->
+<H3><A NAME="ServerRoot">ServerRoot</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+ServerRoot /etc/cups
+ServerRoot /foo/bar/cups
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>ServerRoot</CODE> directive specifies the absolute path to
+the server configuration and state files. It is also used to resolve
+relative paths in the <VAR>cupsd.conf</VAR> file. The default server
+directory is <VAR>/etc/cups</VAR>.
+
+<!-- NEED 3in -->
+<H3><A NAME="SSLListen">SSLListen</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+SSLListen 127.0.0.1:443
+SSLListen 192.0.2.1:443
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>SSLListen</CODE> directive specifies a network
+address and port to listen for secure connections. Multiple
+<CODE>SSLListen</CODE> directives can be provided to listen on
+multiple addresses.
+
+<P>The <CODE>SSLListen</CODE> directive is similar to the
+<A HREF="#SSLPort"><CODE>SSLPort</CODE></A> directive but allows
+you to restrict access to specific interfaces or networks.
+
+<!-- NEED 3in -->
+<H3><A NAME="SSLPort">SSLPort</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+SSLPort 443
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>SSLPort</CODE> directive specifies a port to listen
+on for secure connections. Multiple <CODE>SSLPort</CODE> lines
+can be specified to listen on multiple ports.
+
+<!-- NEED 3in -->
+<H3><A NAME="SystemGroup">SystemGroup</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+SystemGroup sys
+SystemGroup system
+SystemGroup root
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>SystemGroup</CODE> directive specifies the system
+administration group for <CODE>System</CODE> authentication. More
+information can be found later in this chapter in
+<A HREF="#PRINTING_SECURITY">"Printing System Security"</A>.
+
+<!-- NEED 3in -->
+<H3><A NAME="TempDir">TempDir</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+TempDir /var/tmp
+TempDir /foo/bar/tmp
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>TempDir</CODE> directive specifies an absolute path for
+the directory to use for temporary files. The default directory is
+<VAR>/var/tmp</VAR>.
+
+<P>Temporary directories must be world-writable and should have the
+"sticky" permission bit enabled so that other users cannot delete
+filter temporary files. The following commands will create an
+appropriate temporary directory called <VAR>/foo/bar/tmp</VAR>:
+
+<UL><PRE>
+<B>mkdir /foo/bar/tmp ENTER</B>
+<B>chmod a+rwxt /foo/bar/tmp ENTER</B>
+</PRE></UL>
+
+<!-- NEED 3in -->
+<H3><A NAME="Timeout">Timeout</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+Timeout 300
+Timeout 90
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>Timeout</CODE> directive controls the amount of time to
+wait before an active HTTP or IPP request times out. The default
+timeout is 300 seconds.
+
+<!-- NEED 3in -->
+<H3><A NAME="User">User</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+User lp
+User guest
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>User</CODE> directive specifies the UNIX user that
+filter and CGI programs run as. The default user is <CODE>lp</CODE>.
+
+<!-- NEW PAGE -->
+<H2><A NAME="PRINTING_SECURITY">Printing System Security</A></H2>
+
+<P>CUPS provides support for address, certificate, and password (Basic
+and Digest) based authentication and access control. Certificate and
+password authentication provide ways to limit access to individual
+people or groups.
+
+<P>Address based access control allows you to limit access to specific
+systems, networks, or domains. While this does not provide authentication,
+it does allow you to limit the potential users of your system efficiently.
+
+<P>CUPS maintains a list of locations that have access control and/or
+authentication enabled. Locations are specified using the
+<A HREF="#Location"><CODE>Location</CODE></A> directive:
+
+<UL><PRE>
+&lt;Location /resource&gt;
+<A HREF="#AuthClass">AuthClass</A> ...
+<A HREF="#AuthGroupName">AuthGroupName</A> ...
+<A HREF="#AuthType">AuthType</A> ...
+
+<A HREF="#Order">Order</A> ...
+<A HREF="#Allow">Allow</A> from ...
+<A HREF="#Deny">Deny</A> from ...
+&lt;/Location&gt;
+</PRE></UL>
+
+<P>Locations generally follow the directory structure of the
+<A HREF="#DocumentRoot"><CODE>DocumentRoot</CODE></A> directory, however
+CUPS does have several virtual locations for administration, classes, jobs,
+and printers:
+
+<CENTER><TABLE BORDER="1">
+<TR>
+ <TH>Location</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>/admin</TD>
+ <TD>The path for all administration operations.</TD>
+</TR>
+<TR>
+ <TD>/classes</TD>
+ <TD>The path for all classes.</TD>
+</TR>
+<TR>
+ <TD>/classes/name</TD>
+ <TD>The resource for class <CODE>name</CODE>.</TD>
+</TR>
+<TR>
+ <TD>/jobs</TD>
+ <TD>The path for all jobs.</TD>
+</TR>
+<TR>
+ <TD>/jobs/id</TD>
+ <TD>The resource for job <CODE>id</CODE>.</TD>
+</TR>
+<TR>
+ <TD>/printers</TD>
+ <TD>The path for all printers.</TD>
+</TR>
+<TR>
+ <TD>/printers/name</TD>
+ <TD>The path for printer <CODE>name</CODE>.</TD>
+</TR>
+<TR>
+ <TD>/printers/name.ppd</TD>
+ <TD>The PPD file path for printer <CODE>name</CODE>.</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3><A NAME="CERTIFICATES">Authentication Using Certificates</A></H3>
+
+<P>CUPS supports a local certificate-based authentication scheme that
+can be used in place of <CODE>Basic</CODE> or <CODE>Digest</CODE>
+authentication by clients connecting through the <CODE>localhost</CODE>
+interface. Certificate authentication is not supported or allowed from
+clients on any other interface.
+
+<P>Certificates are 128-bit random numbers that refer to an internal
+authentication record in the server. A client connecting via the
+<CODE>localhost</CODE> interface sends a request with an
+authorization header of:
+
+<UL><PRE>
+Authorization: Local 0123456789ABCDEF0123456789ABCDEF
+</PRE></UL>
+
+<P>The server then looks up the local certificate and authenticates
+using the username associated with it.
+
+<P>Certificates are generated by the server automatically and stored in
+the <VAR>/etc/cups/certs</VAR> directory using the process ID of the
+CGI program started by the server. Certificate files are only readable
+by the <A HREF="#User"><CODE>User</CODE></A> and
+<A HREF="#Group"><CODE>Group</CODE></A> defined in the
+<VAR>cupsd.conf</VAR> file. When the CGI program ends the certificate
+is removed and invalidated automatically.
+
+<P>The special file <VAR>/etc/cups/certs/0</VAR> defines the <I>root
+certificate</I> which can be used by any client running as the super-user
+or another user that is part of the group defined by the
+<A HREF="#SystemGroup"><CODE>SystemGroup</CODE></A> directive. The
+root certificate is automatically regenerated every 5 minutes.
+
+<H3>Using Basic Authentication</H3>
+
+<P>Basic authentication uses UNIX users and passwords to authenticate
+access to resources such as printers and classes, and to limit access
+to administrative functions.
+
+<CENTER><TABLE WIDTH="80%" BORDER="1" CELLPADDING="5" BGCOLOR="#cccccc">
+<TR>
+ <TD>
+ <B>NOTE:</B>
+
+ <P>Basic authentication sends the username and password Base64
+ encoded from the client to the server, so it offers no
+ protection against eavesdropping. This means that a malicious
+ user can monitor network packets and discover valid users and
+ passwords that could result in a serious compromise in network
+ security. Use Basic authentication with extreme care.
+ </TD>
+</TR>
+</TABLE></CENTER>
+
+<P>The CUPS implementation of Basic authentication does not allow access
+through user accounts without a password. If you try to authenticate
+using an account without a password, your access will be immediately
+blocked.
+
+<P>Once a valid username and password is authenticated by CUPS, any
+additional group membership requirements are checked.
+
+<CENTER><TABLE WIDTH="80%" BORDER="1" CELLPADDING="5" BGCOLOR="#cccccc">
+<TR>
+ <TD>
+ <B>NOTE:</B>
+
+ <P>The root user is considered by CUPS to be a member of every
+ group.
+ </TD>
+</TR>
+</TABLE></CENTER>
+
+<!-- NEED 1in -->
+<P>Use the <CODE>AuthType</CODE> directive to enable Basic authentication:
+
+<UL><PRE>
+AuthType Basic
+</PRE></UL>
+
+<!-- NEED 7in -->
+<H3>Using Digest Authentication</H3>
+
+<P>Digest authentication uses users and passwords defined in the
+<VAR>/etc/cups/passwd.md5</VAR> file to authenticate access to
+resources such as printers and classes, and to limit access to
+administrative functions.
+
+<CENTER><TABLE WIDTH="80%" BORDER="1" CELLPADDING="5" BGCOLOR="#cccccc">
+<TR>
+ <TD>
+ <B>NOTE:</B>
+
+ <P>Unlike Basic authentication, Digest passes the MD5 sum
+ (basically a complicated checksum) of the username and password
+ instead of the strings themselves. Also, Digest authentication
+ does not use the UNIX password file, so if an attacker does
+ discover the original password it is less likely to result in a
+ serious security problem so long as you use a different UNIX
+ password than the corresponding Digest password.
+
+ <P>The current CUPS implementation of Digest authentication
+ uses the client's hostname or IP address for the "nonce" value.
+ The nonce value is an additional string added to the username
+ and password to make guessing the password more difficult. The
+ server checks that the nonce value matches the client's hostname
+ or address and rejects the MD5 sum if it doesn't. Future versions
+ of CUPS will support Digest "session" authentication which adds
+ the request data to the MD5 sum, providing even better
+ authentication and security.
+
+ <P>Digest authentication does not guarantee that an attacker
+ cannot gain unauthorized access, but it is safer than Basic
+ authentication and should be used in place of Basic
+ authentication whenever possible. <B>Support for Digest
+ authentication in web browsers is not yet universally
+ available.</B>
+ </TD>
+</TR>
+</TABLE></CENTER>
+
+<!-- NEED 2in -->
+<P>The <CODE>lppasswd(1)</CODE> command is used to add, change, or
+remove accounts from the <VAR>passwd.md5</VAR> file. To add a
+user to the default system group, type:
+
+<UL><PRE>
+<B>lppasswd -a user ENTER</B>
+Password: <B>(password) ENTER</B> [password is not echoed]
+Password again: <B>(password) ENTER</B> [password is not echoed]
+</PRE></UL>
+
+<!-- NEED 2in -->
+<P>Once added, a user can change his/her password by typing:
+
+<UL><PRE>
+<B>lppasswd ENTER</B>
+Old password: <B>(password) ENTER</B> [password is not echoed]
+Password: <B>(password) ENTER</B> [password is not echoed]
+Password again: <B>(password) ENTER</B> [password is not echoed]
+</PRE></UL>
+
+<!-- NEED 1in -->
+<P>To remove a user from the password file, type:
+
+<UL><PRE>
+<B>lppasswd -x user ENTER</B>
+</PRE></UL>
+
+<P>Once a valid username and password is authenticated by CUPS, any
+additional group membership requirements are checked.
+
+<CENTER><TABLE WIDTH="80%" BORDER="1" CELLPADDING="5" BGCOLOR="#cccccc">
+<TR>
+ <TD>
+ <B>NOTE:</B>
+
+ <P>The root user is considered by CUPS to be a member of every
+ group.
+ </TD>
+</TR>
+</TABLE></CENTER>
+
+<P>Use the <CODE>AuthType</CODE> directive to enable Digest authentication:
+
+<UL><PRE>
+AuthType Digest
+</PRE></UL>
+
+<H3>System and Group Authentication</H3>
+
+<P>The <A HREF="#AuthClass"><CODE>AuthClass</CODE></A> directive controls
+the level of authentication to perform. <CODE>System</CODE> and
+<CODE>Group</CODE> authentication extend the normal user-based authentication
+to require membership in a UNIX group. For <CODE>System</CODE> authentication
+each user must belong to the <CODE>sys</CODE>, <CODE>system</CODE>, or
+<CODE>root</CODE> group; the actual group depends on the operating system.
+
+<P>For <CODE>Group</CODE> authentication each user must belong to the
+group named by the <A HREF="#AuthGroupName"><CODE>AuthGroupName</CODE></A>
+directive:
+
+<UL><PRE>
+&lt;Location /path&gt;
+AuthType Digest
+AuthClass Group
+AuthGroupName mygroup
+&lt;/Location&gt;
+</PRE></UL>
+
+<P>The named group must be a valid UNIX user group, usually defined in the
+<VAR>/etc/group</VAR> or <VAR>/etc/netgroup</VAR> files. Additionally, when
+using Digest authentication you need to create user accounts with the named
+group:
+
+<UL><PRE>
+<B>lppasswd -g mygroup -a user ENTER</B>
+Password: <B>(password) ENTER</B> [password is not echoed]
+Password again: <B>(password) ENTER</B> [password is not echoed]
+</PRE></UL>
+
+<!-- NEW PAGE -->
+<H2><A NAME="PRINTER_ACCOUNTING">Printer Accounting</A></H2>
+
+<P>ESP Print Pro maintains a log of all accesses, errors, and
+pages that are printed. The log files are normally stored in the
+<VAR>/var/log/cups</VAR> directory. You can change this by
+editing the <VAR>/etc/cups/cupsd.conf</VAR> configuration file.
+
+<H3>The access_log File</H3>
+
+<P>The <VAR>access_log</VAR> 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:
+
+<UL><PRE>
+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
+</PRE></UL>
+
+<P>The <I>host</I> field will normally only be an IP address unless you
+have enabled the <A HREF="#HostNameLookups"><CODE>HostNameLookups</CODE></A>
+directive in the <VAR>cupsd.conf</VAR> file.
+
+<P>The <I>group</I> field always contains "-" in CUPS.
+
+<P>The <I>user</I> field is the authenticated username of the requesting user.
+If no username and password is supplied for the request then this field
+contains "-".
+
+<P>The <I>date-time</I> field is the date and time of the request in local time
+and is in the format:
+
+<UL><PRE>
+[DD/MON/YYYY:HH:MM:SS +ZZZZ]
+</PRE></UL>
+
+<P>where <I>ZZZZ</I> is the timezone offset in hours and minutes from Greenwich
+Mean Time (a.k.a. GMT a.k.a. ZULU.)
+
+<P>The <I>method</I> field is the HTTP method used ("GET", "PUT", "POST", etc.)
+
+<P>The <I>resource</I> field is the filename of the requested resource.
+
+<P>The <I>version</I> field is the HTTP specification version used by the
+client. For CUPS clients this will always be "HTTP/1.1".
+
+<P>The <I>status</I> 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.
+
+<P>The <I>bytes</I> field contains the number of bytes in the request.
+For POST requests the <I>bytes</I> field contains the number of bytes
+that was received from the client.
+
+<H3>The error_log File</H3>
+
+<P>The <VAR>error_log</VAR> file lists messages from the scheduler (errors,
+warnings, etc.):
+
+<UL><PRE>
+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'.
+</PRE></UL>
+
+<P>The <I>level</I> field contains the type of message:
+
+<UL>
+
+ <LI><CODE>E</CODE> - An error occurred.
+
+ <LI><CODE>W</CODE> - The server was unable to perform some action.
+
+ <LI><CODE>I</CODE> - Informational message.
+
+ <LI><CODE>D</CODE> - Debugging message.
+
+</UL>
+
+<P>The <I>date-time</I> field contains the date and time of when the page
+started printing. The format of this field is identical to the <I>data-time</I>
+field in the <VAR>access_log</VAR> file.
+
+<P>The <I>message</I> fields contains a free-form textual message.
+
+<H3>The page_log File</H3>
+
+<P>The <VAR>page_log</VAR> file lists each page that is sent to a printer.
+Each line contains the following information:
+
+<UL><PRE>
+printer user job-id date-time page-number num-copies job-billing
+
+DeskJet root 2 [20/May/1999:19:21:05 +0000] 1 0 acme-123
+</PRE></UL>
+
+<P>The <I>printer</I> 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.
+
+<P>The <I>user</I> field contains the name of the user (the IPP
+<CODE>requesting-user-name</CODE> attribute) that submitted this file for
+printing.
+
+<P>The <I>job-id</I> 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!
+
+<P>The <I>date-time</I> field contains the date and time of when the page
+started printing. The format of this field is identical to the <I>data-time</I>
+field in the <VAR>access_log</VAR> file.
+
+<P>The <I>page-number</I> and <I>num-pages</I> 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 <I>num-pages</I> field will always be 1.
+
+<P>The <I>job-billing</I> field contains a copy of the
+<CODE>job-billing</CODE> attribute provided with the IPP
+<CODE>create-job</CODE> or <CODE>print-job</CODE> requests or "-" if none
+was provided.
+
+<!-- NEW PAGE -->
+<H2><A NAME="FILE_TYPING_FILTERING">File Typing and Filtering</A></H2>
+
+<P>CUPS provides a MIME-based file typing and filtering mechanism to
+convert files to a printable format for each printer. On startup the
+CUPS server reads MIME database files from the <VAR>/etc/cups</VAR>
+directory (or a directory specified by the
+<A HREF="#ServerRoot"><CODE>ServerRoot</CODE></A> directive) to build
+a file type and conversion database in memory. These database files are
+plain ASCII text and can be edited with your favorite text editor.
+
+<P>The <VAR>mime.types</VAR> and <VAR>mime.convs</VAR> files define the
+standard file types and filters that are available on the system.
+
+<H3>mime.types</H3>
+
+<P>The <VAR>mime.types</VAR> file 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
+<CODE>text/html</CODE> file type is defined as:
+
+<UL><PRE>
+text/html html htm \
+ printable(0,1024) + \
+ (string(0,"&lt;HTML&gt;") string(0,"&lt;!DOCTYPE"))
+</PRE></UL>
+
+<P>The first two rules say that any file with an extension of
+<VAR>.html</VAR> or <VAR>.htm</VAR> is a HTML file. The third rule
+says that any file whose first 1024 characters are printable text and
+starts with the strings <CODE>&lt;HTML&gt;</CODE> or
+<CODE>&lt;!DOCTYPE</CODE> is a HTML file as well.
+
+<P>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 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.
+
+<P>The available tests are:
+
+<UL>
+
+ <LI><CODE>( expr )</CODE> - Parenthesis for expression grouping
+
+ <LI><CODE>+</CODE> - Logical AND
+
+ <LI><CODE>,</CODE> or whitespace - Logical OR
+
+ <LI><CODE>!</CODE> - Logical NOT
+
+ <LI><CODE>match("pattern")</CODE> - Pattern match on filename
+
+ <LI><CODE>extension</CODE> - Pattern match on "*.extension"
+
+ <LI><CODE>ascii(offset,length)</CODE> - True if bytes are valid
+ printable ASCII (CR, NL, TAB, BS, 32-126)
+
+ <LI><CODE>printable(offset,length)</CODE> - True if bytes are
+ printable 8-bit chars (CR, NL, TAB, BS, 32-126, 160-254)
+
+ <LI><CODE>string(offset,"string")</CODE> - True if bytes are
+ identical to string
+
+ <LI><CODE>contains(offset,range,"string")</CODE> - True if the
+ range of bytes contains the string
+
+ <LI><CODE>char(offset,value)</CODE> - True if byte is identical
+
+ <LI><CODE>short(offset,value)</CODE> - True if 16-bit integer
+ is identical (network or "big-endian" byte order)
+
+ <LI><CODE>int(offset,value)</CODE> - True if 32-bit integer is
+ identical (network or "big-endian" byte order)
+
+ <LI><CODE>locale("string")</CODE> - True if current locale
+ matches string
+
+</UL>
+
+<P>All numeric values can be in decimal (123), octal (0123), or hexadecimal
+(0x123) as desired.
+
+<!-- NEED 2.5in -->
+<P>Strings can be in quotes, all by themselves, as a string
+of hexadecimal values, or some combination:
+
+<UL><PRE>
+"string"
+'string'
+string
+&lt;737472696e67&gt;
+&lt;7374&gt;ring
+</PRE></UL>
+
+<P>As shown in the <CODE>text/html</CODE> example, rules can continue on
+multiple lines using the backslash (\) character. A more complex example is
+the <CODE>image/jpeg</CODE> rules:
+
+<UL><PRE>
+image/jpeg jpeg jpg jpe string(0,&lt;FFD8FF&gt;) &amp;&amp;\
+ (char(3,0xe0) char(3,0xe1) char(3,0xe2) char(3,0xe3)\
+ char(3,0xe4) char(3,0xe5) char(3,0xe6) char(3,0xe7)\
+ char(3,0xe8) char(3,0xe9) char(3,0xea) char(3,0xeb)\
+ char(3,0xec) char(3,0xed) char(3,0xee) char(3,0xef))
+</PRE></UL>
+
+<P>This rule states that any file with an extension of
+<VAR>.jpeg</VAR>, <VAR>.jpg</VAR>, or <VAR>.jpe</VAR> is a JPEG file.
+In addition, any file starting with the hexadecimal string
+<CODE>&lt;FFD8FF&gt;</CODE> (JPEG Start-Of-Image) followed by a
+character between and including <CODE>0xe0</CODE> and <CODE>0xef</CODE>
+(JPEG APPn markers) is also a JPEG file.
+
+<H3>mime.convs</A></H3>
+
+<P>The <VAR>mime.convs</VAR> file defines all of the filter programs that
+are known to the system. Each line consists of:
+
+<UL><PRE>
+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
+</PRE></UL>
+
+<P>The <I>source</I> field is a MIME type, optionally using a wildcard for
+the super-type or sub-type (e.g. "text/plain", "image/*", "*/postscript").
+
+<P>The <I>destination</I> field is a MIME type defined in the
+<VAR>mime.types</VAR> file.
+
+<P>The <I>cost</I> 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 <CODE>image/jpeg</CODE> to <CODE>application/vnd.cups-raster</CODE>,
+you could use the <CODE>imagetops</CODE> and <CODE>pstoraster</CODE>
+filters for a total cost of 100, or the <CODE>imagetoraster</CODE> filter
+for a total cost of 50.
+
+<P>The <I>program</I> 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 Description and CUPS
+Software Programmers Manual:
+
+<UL><PRE>
+program job user title options [filename]
+</PRE></UL>
+
+<P>If specified, the <I>filename</I> 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.
+
+<!-- NEED 4in -->
+<H3>Adding Filetypes and Filters</H3>
+
+<P>Adding a new file type or filter is fairly straight-forward. Rather
+than adding the new type and filter to the <VAR>mime.types</VAR> and
+<VAR>mime.convs</VAR> files which are overwritten when you upgrade to a
+new version of CUPS, you simple need to create new files with
+<VAR>.types</VAR> and <VAR>.convs</VAR> extensions in the
+<VAR>/etc/cups</VAR> directory. We recommend that you use the product
+or format name, e.g.:
+
+<UL><PRE>
+myproduct.types
+myproduct.convs
+</PRE></UL>
+
+<P>If you are providing a filter for a common file format or printer,
+add the company or author name:
+
+<UL><PRE>
+acme-msword.types
+acme.msword.convs
+</PRE></UL>
+
+<P>This will help to prevent name collisions if you install many
+different file types and filters.
+
+<P>Once you choose the names for these files, create them using your
+favorite text editor as described earlier in this chapter. Once you
+have created the files, restart the <CODE>cupsd</CODE> process as
+described earlier in <A HREF="#RESTARTING">"Restarting the CUPS Server"</A>.
+
+<H3>Printer Drivers and PPD Files</H3>
+
+<P>Most CUPS printer drivers utilize one or more printer-specific filters
+and a PPD file for each printer model. Printer driver filters are registered
+via the PPD file using <CODE>cupsFilter</CODE> attributes:
+
+<UL><PRE>
+*cupsFilter: "application/vnd.cups-raster 0 rastertohp"
+</PRE></UL>
+
+<P>The filter is specified using the source file type only; the destination
+file type is assumed to be <CODE>printer/name</CODE> - suitable for sending
+to the printer.
+
+<H3>Writing Your Own Filter or Printer Driver</H3>
+
+<P>CUPS supports an unlimited number of file formats and filters, and can
+handle any printer. If you'd like to write a filter or printer driver for
+your favorite file format or printer, consult the CUPS Software Programmers
+Manual for step-by-step instructions.
+
+
+<H1 ALIGN="RIGHT"><A NAME="PRINTING_OTHER">7 - Printing with Other Systems</A></H1>
+
+<P>This chapter describes how to print from client systems that use the
+LPD, Mac OS, or Windows printing protocols.
+
+<H2>The Basics</H2>
+
+<P>CUPS is based on the IPP protocol, so any system that supports IPP
+can send jobs to and receive jobs from CUPS automatically. However, not
+all systems support IPP yet. This chapter will show you how to connect
+these systems to your CUPS server, either to accept jobs from your
+server for printing, or to send jobs to your server.
+
+<H2>Printing from LPD Clients</H2>
+
+<P>CUPS supports limited functionality for LPD-based clients. With LPD you can
+print files to specific printers, list the queue status, and so forth. However,
+the automatic client configuration and printer options are not supported by
+the LPD protocol, so you must manually configure each client for the printers
+it needs to access.
+
+<P>The <CODE>cups-lpd(8)</CODE> program provides support for LPD clients.
+To enable LPD support on your server, edit the <VAR>/etc/inetd.conf</VAR>
+file and add a line reading:
+
+<UL><PRE>
+printer stream tcp nowait lp /usr/lib/cups/daemon/cups-lpd cups-lpd
+</PRE></UL>
+
+<P>The path to the <CODE>cups-lpd</CODE> may vary depending on your
+installation.
+
+<P>Once you have added this line, send the <CODE>inetd(8)</CODE> process
+a <CODE>HUP</CODE> signal or reboot the system:
+
+<UL><PRE>
+<B>killall -HUP inetd ENTER</B> [IRIX and some versions of Linux]
+<B>kill -HUP <I>pid</I> ENTER [Others]</B>
+<B>reboot ENTER [For all systems if the HUP signal fails]</B>
+</PRE></UL>
+
+<H2>Printing to LPD Servers</H2>
+
+<P>CUPS provides the <CODE>lpd</CODE> backend for printing to LPD-based
+servers and printers. Use a device URI of <CODE>lpd://server/name</CODE>
+to print to a printer on an LPD server, where <CODE>server</CODE>
+is the hostname or IP address of the server and <CODE>name</CODE> is
+the queue name.
+
+<P>Microsoft Windows NT provides an LPD service under the name "TCP/IP
+Printing Services". To enable LPD printing on NT, open the "Services"
+control panel, select the "TCP/IP Printing Services" service, and click
+on the "Start" button. Any shared printer will then be available via
+the LPD protocol.
+
+<H2>Printing from Mac OS Clients</H2>
+
+<P>CUPS does not provide Mac OS support directly. However, there are several
+free and commercial software packages that do.
+
+<H3>Columbia Appletalk Package (CAP)</H3>
+
+<P>Because the CAP LaserWriter server (<CODE>lwsrv(8)</CODE>) does
+not support specification of PPD files, we do not recommend that you
+use CAP with CUPS. However, you can run the <CODE>lpsrv</CODE> program
+for limited printing with the command:
+
+<UL><PRE>
+lwsrv -n "<I>Name</I>" -p <I>printer</I> -a /usr/lib/adicts -f /usr/lib/LW+Fonts
+</PRE></UL>
+
+<P>where <CODE>Name</CODE> is the name you want to use when sharing the
+printer, and <CODE>printer</CODE> is the name of the CUPS print queue.
+
+<!-- NEED 3in -->
+<H3>XINET KA/Spool</H3>
+
+<P>To use your system as a print server for Mac OS clients,
+configure each printer using a <CODE>papserver(8)</CODE> in the
+<VAR>/usr/adm/appletalk/services</VAR> file, specifying the
+corresponding PPD file in the <VAR>/etc/cups/ppd</VAR> directory for
+each printer. For a printer named <CODE>MyPrinter</CODE> the entry
+would look like:
+
+<UL><PRE>
+/usr/etc/appletalk/papserver -I -L -P /etc/cups/ppd/MyPrinter.ppd \
+"Printer Description" MyPrinter
+</PRE></UL>
+
+<CENTER><TABLE WIDTH="80%" BORDER="1" CELLPADDING="5" BGCOLOR="#cccccc">
+<TR>
+ <TD>
+ <B>NOTE:</B>
+
+ <P>Enter the text above on a single line without the backslash (\)
+ character.
+ </TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>NetATalk</H3>
+
+<P>To use your system as a print server for Mac OS clients,
+configure each printer in the <VAR>papd.conf</VAR> file, specifying the
+corresponding PPD file in the <VAR>/etc/cups/ppd</VAR> directory for
+each printer. For a printer named <CODE>MyPrinter</CODE> the entry
+would look like:
+
+<UL><PRE>
+Printer Description:MyPrinter@MyServer:\
+ :pr=|/usr/bin/lp -d MyPrinter:\
+ :op=daemon:\
+ :pd=/etc/cups/ppd/MyPrinter.ppd:
+</PRE></UL>
+
+<!-- NEED 2in -->
+
+<H2>Printing to Mac OS Servers</H2>
+
+<P>CUPS currently does not provide a backend to communicate with a Mac OS
+server. However, you can write and install a short shell script
+in the <VAR>/usr/lib/cups/backend</VAR> directory that sends a print file
+using the appropriate command. The following is a short script that will
+run the <CODE>papif</CODE> command provided with CAP.
+
+<P>After copying this script to <VAR>/usr/lib/cups/backend/cap</VAR>,
+specify a device URI of <CODE>cap://server/printer</CODE> to use this
+backend with a print queue.
+
+<!-- NEED 8in -->
+<UL>
+<PRE>
+<I>"/usr/lib/cups/backend/cap"</I>
+#!/bin/sh
+#
+# Usage: cap job user title copies options [filename]
+#
+
+# No arguments means show available devices...
+
+if test ${#argv} = 0; then
+ echo "network cap \"Unknown\" \"Mac OS Printer via CAP\""
+ exit 0
+fi
+
+# Collect arguments...
+
+user=$2
+copies=$4
+
+if test ${#argv} = 5; then
+ # Get print file from stdin; copies have already been handled...
+ file=/var/tmp/$$.prn
+ copies=1
+ cat &gt; $file
+else
+ # Print file is on command-line...
+ file=$6
+fi
+
+# Create a dummy cap.printers file for this printer based
+# upon a device URI of "cap://server/printer"...
+
+echo $PRINTER/$DEVICE_URI | \
+ awk -F/ '{print $1 "=" $5 ":LaserWriter@" $4}' &gt; /var/tmp/$$.cap
+
+CAPPRINTERS=/var/tmp/$$.cap; export CAPPRINTERS
+
+# Send the file to the printer, once for each copy. This assumes that you
+# have properly initialized the cap.printers file...
+
+while [ $copies -gt 0 ]; do
+ papif -n $user &lt; $file
+
+ copies=`expr $copies - 1`
+done
+
+# Remove any temporary files...
+if test ${#argv} = 5; then
+ /bin/rm -f $file
+fi
+
+/bin/rm -f /var/tmp/$$.cap
+
+exit 0
+</PRE></UL>
+
+<!-- NEED 2in -->
+<H2>Printing from Windows Clients</H2>
+
+<P>While CUPS does not provide Windows support directly, the free
+SAMBA software package does. SAMBA version 2.0.6 is the first release
+of SAMBA that supports CUPS. You can download SAMBA from:
+
+<UL><PRE>
+<A HREF="http://www.samba.org">http://www.samba.org</A>
+</PRE></UL>
+
+<P>To configure SAMBA for CUPS, edit the <VAR>smb.conf</VAR> file and
+replace the existing printing commands and options with the line:
+
+<UL><PRE>
+printing = cups
+printcap name = cups
+</PRE></UL>
+
+<P>That's all there is to it! Remote users will now be able to browse and
+print to printers on your system.
+
+<H3>Exporting Printer Drivers</H3>
+
+<P>You can optionally export printer drivers from your CUPS
+server using the <CODE>cupsaddsmb</CODE> command and the SAMBA
+2.2.0 or higher software.
+
+<P>Before you can export the printers you must download the
+current Adobe PostScript printer drivers from the Adobe web
+site (<A HREF="http://www.adobe.com/">http://www.adobe.com/</A>).
+Use the free <CODE>unzip</CODE> software to extract the files
+from the self-extracting ZIP file containing the drivers; you
+will need the following files:
+
+<UL><PRE>
+ADFONTS.MFM
+ADOBEPS4.DRV
+ADOBEPS4.HLP
+ADOBEPS5.DLL
+ADOBEPSU.DLL
+ADOBEPSU.HLP
+DEFPRTR2.PPD
+ICONLIB.DLL
+PSMON.DLL
+</PRE></UL>
+
+<P>Copy these files to the <VAR>/usr/share/cups/drivers</VAR>
+directory - you may need to rename some of the files so the
+filenames are all UPPERCASE.
+
+<P>Next, add a <CODE>print$</CODE> share for the printer
+drivers to your <VAR>smb.conf</VAR> file:
+
+<UL><PRE>
+[print$]
+ comment = Printer Drivers
+ path = /etc/samba/drivers
+ browseable = yes
+ guest ok = no
+ read only = yes
+ write list = root
+</PRE></UL>
+
+<P>The directory for your printer drivers can be anywhere on the
+system; just make sure it is writable by the users specified by
+the <CODE>write list</CODE> directive. Also, make sure that you
+have SAMBA passwords defined for each user in the <CODE>write
+list</CODE> using the <CODE>smbpasswd(1)</CODE> command.
+Otherwise you will not be able to authenticate
+
+<P>Finally, run the <CODE>cupsaddsmb</CODE> command to export
+the printer drivers for one or more queues:
+
+<UL><PRE>
+<KBD>cupsaddsmb -U root printer1 ... printerN <I>ENTER</I></KBD>
+</PRE></UL>
+
+<P>Running <CODE>cupsaddsmb</CODE> with the <CODE>-a</CODE> option
+will export all printers:
+
+<UL><PRE>
+<KBD>cupsaddsmb -U root -a <I>ENTER</I></KBD>
+</PRE></UL>
+
+<H2>Printing to Windows Servers</H2>
+
+<P>CUPS can print to Windows servers in one of two ways. The first way uses
+the LPD protocol on the CUPS system and the "TCP/IP Printing Services" on
+the Windows system. You can find out more about this configuration in the
+<A HREF="#LPD">LPD</A> section earlier in this chapter.
+
+<P>The second way is through the Microsoft Server Message Block ("SMB")
+protocol. Support for this protocol is provided with the free SAMBA
+software package. You can download SAMBA from:
+
+<UL><PRE>
+<A HREF="http://www.samba.org">http://www.samba.org</A>
+</PRE></UL>
+
+<P>To configure CUPS for SAMBA, run the following command:
+
+<UL><PRE>
+<B>ln -s `which smbspool` /usr/lib/cups/backend/smb ENTER</B>
+</PRE></UL>
+
+<P>The <CODE>smbspool(1)</CODE> program is provided with SAMBA starting
+with SAMBA 2.0.6. Once you have made the link you can configure your
+printers with one of the following device URIs:
+
+<UL><PRE>
+smb://workgroup/server/sharename
+smb://server/sharename
+smb://user:pass@workgroup/server/sharename
+smb://user:pass@server/sharename
+</PRE></UL>
+
+<P>The <CODE>workgroup</CODE> name need only be specified if your
+system is using a different workgroup. The <CODE>user:pass</CODE>
+strings are required when printing to Windows NT servers or to shares
+with passwords enabled under Windows 95 and 98.
+
+
+<H1 ALIGN="RIGHT"><A NAME="LICENSE">A - Software License Agreement</A></H1>
+
+<EMBED SRC="../LICENSE.html">
+
+
+<H1 ALIGN="RIGHT"><A NAME="COMMON_NETWORK">B - Common Network Settings</A></H1>
+
+<P>This appendix covers many of the popular TCP/IP network interfaces
+and printer servers available on the market today.
+
+<H2>Configuring a Network Interface</H2>
+
+<P>When you first install a network printer or print server on your
+LAN, you need to set the Internet Protocol ("IP") address. On most
+higher-end "workgroup" printers, you can set the address through the
+printer control panel. However, in most cases you will want to assign
+the addresses remotely from your workstation. This makes administration
+a bit easier and avoids assigning duplicate addresses accidentally.
+
+<P>To setup your printer or print server for remote address assignment,
+you'll need the Ethernet Media Access Control ("MAC") address, also
+sometimes called a node address, and the IP address you want to use for
+the device. The Ethernet MAC address can often be found on the printer
+test page or bottom of the print server.
+
+<!-- NEED 3in -->
+<H3>Configuring the IP Address Using ARP</H3>
+
+<P>The easiest way to set the IP address of a network device is to use
+the <CODE>arp(8)</CODE> command. The <CODE>arp</CODE> sends an Address
+Resolution Protocol ("ARP") packet to the specified Ethernet MAC address,
+setting the network device's IP address:
+
+<UL><PRE>
+<B>arp -s ip-address ethernet-address ENTER</B>
+<B>arp -s host.domain.com 08:00:69:00:12:34 ENTER</B>
+<B>arp -s 192.0.2.2 08:00:69:00:12:34 ENTER</B>
+</PRE></UL>
+
+<H3>Configuring the IP Address Using RARP</H3>
+
+<P>The most flexible way to remotely assign IP addresses under UNIX
+is through the Reverse Address Resolution Protocol ("RARP"). RARP
+allows a network device to request an IP address using its Ethernet
+MAC address, and one or more RARP servers on the network will
+respond with an ARP packet with the IP address the device can use.
+
+<P>RARP should be used when you have to manage many printers or print
+servers, or when you have a network device that does not remember its
+IP address after a power cycle. If you just have a single printer or
+print server, the <CODE>arp</CODE> command is the way to go.
+
+<P>Some UNIX operating systems use a program called
+<CODE>rarpd(8)</CODE> to manage RARP. Others, like Linux, support this
+protocol in the kernel. For systems that provide the <CODE>rarpd</CODE>
+program you will need to start it before RARP lookups will work:
+
+<UL><PRE>
+<B>rarpd ENTER</B>
+</PRE></UL>
+
+<P>Under IRIX you can enable this functionality by default using:
+
+<UL><PRE>
+<B>chkconfig rarpd on ENTER</B>
+</PRE></UL>
+
+<P>Both the <CODE>rarpd</CODE> program and kernel RARP support read a
+list of Ethernet and IP addresses from the file <VAR>/etc/ethers</VAR>.
+Each line contains the Ethernet address (colon delimited) followed by
+an IP address or hostname like:
+
+<UL><PRE>
+08:00:69:00:12:34 myprinter.mydomain.com
+08:00:69:00:12:34 192.0.2.2
+</PRE></UL>
+
+<P>Add a line to this file and cycle the power on the printer or print
+server to set its address.
+
+<!-- NEED 2in -->
+<H3>Configuring the IP Address Using BOOTP</H3>
+
+<P>The BOOTP protocol is used when you need to provide additional information
+such as the location of a configuration file to the network interface. Using
+the standard <CODE>bootpd(8)</CODE> program supplied with UNIX you simply need to
+add a line to the <VAR>/etc/bootptab</VAR> file; for IRIX:
+
+<UL><PRE>
+myprinter 08:00:69:00:12:34 192.0.2.2 <VAR>myprinter.boot</VAR>
+</PRE></UL>
+
+<!-- NEED 1in -->
+<P>Newer versions of <CODE>bootpd</CODE> use a different format:
+
+<UL><PRE>
+myprinter:ha=080069001234:ip=192.0.2.2:<VAR>t144=myprinter.boot</VAR>
+</PRE></UL>
+
+<P>The <VAR>myprinter.boot</VAR> file resides in the <VAR>/usr/local/boot</VAR>
+directory by default. If you do not need to provide a boot file you may leave
+the last part of the line blank.
+
+<!-- NEED 2in -->
+<CENTER><TABLE WIDTH="80%" BORDER="1" CELLPADDING="5" BGCOLOR="#cccccc">
+<TR>
+ <TD>
+ <B>NOTE:</B>
+
+ <P>Some versions of UNIX do not enable the BOOTP service by
+ default. The <VAR>/etc/inetd.conf</VAR> usually contains a
+ line for the BOOTP service that can be uncommented if
+ needed.
+ </TD>
+</TR>
+</TABLE></CENTER>
+
+<H2>Verifying the Printer Connection</H2>
+
+<P>To test that the IP address has been successfully assigned and that the
+printer is properly connected to your LAN, type:
+
+<UL><PRE>
+<B>ping ip-address ENTER</B>
+</PRE></UL>
+
+<P>If the connection is working properly you will see something like:
+
+<UL><PRE>
+<B>ping myprinter ENTER</B>
+PING myprinter (192.0.2.2): 56 data bytes
+64 bytes from 192.0.2.2: icmp_seq=0 ttl=15 time=5 ms
+64 bytes from 192.0.2.2: icmp_seq=1 ttl=15 time=3 ms
+64 bytes from 192.0.2.2: icmp_seq=2 ttl=15 time=3 ms
+64 bytes from 192.0.2.2: icmp_seq=3 ttl=15 time=3 ms
+</PRE></UL>
+
+<P>If not, verify that the printer or print server is connected to the
+LAN, it is powered on, the LAN cabling is good, and the IP address is
+set correctly. You can usually see the current IP address and network
+status by printing a configuration or test page on the device.
+
+<!-- NEED 4in -->
+<H2>Common Network Interface Settings</H2>
+
+<P>Once you have set the IP address you can access the printer or print
+server using the <CODE>ipp</CODE>, <CODE>lpd</CODE>, or
+<CODE>socket</CODE> backends. The following is a list of common network
+interfaces and printer servers and the settings you should use with
+CUPS:
+
+<CENTER><TABLE BORDER="1">
+<TR VALIGN="TOP" ALIGN="LEFT">
+ <TH>Model/Manufacturer</TH>
+ <TH>Device URI(s)</TH>
+</TR>
+<TR ALIGN="LEFT" VALIGN="TOP">
+ <TD>Apple LaserWriter</TD>
+ <TD>lpd://<I>address</I>/PASSTHRU</TD>
+</TR>
+<!-- NEED 1in -->
+<TR ALIGN="LEFT" VALIGN="TOP">
+ <TD>Axis w/o IPP<BR>
+ <A HREF="#AXIS">(see directions)</A></TD>
+ <TD>socket://<I>address</I>:9100<BR>
+ socket://<I>address</I>:9101<BR>
+ socket://<I>address</I>:9102</TD>
+</TR>
+<!-- NEED 1in -->
+<TR ALIGN="LEFT" VALIGN="TOP">
+ <TD>Axis w/IPP</TD>
+ <TD>ipp://<I>address</I>/LPT1<BR>
+ ipp://<I>address</I>/LPT2<BR>
+ ipp://<I>address</I>/COM1</TD>
+</TR>
+<!-- NEED 1in -->
+<TR ALIGN="LEFT" VALIGN="TOP">
+ <TD>Castelle LANpress<SUP>TM</SUP></TD>
+ <TD>lpd://<I>address</I>/pr1<BR>
+ lpd://<I>address</I>/pr2<BR>
+ lpd://<I>address</I>/pr3</TD>
+</TR>
+<!-- NEED 1in -->
+<TR ALIGN="LEFT" VALIGN="TOP">
+ <TD>DPI NETPrint</TD>
+ <TD>lpd://<I>address</I>/pr1<BR>
+ lpd://<I>address</I>/pr2<BR>
+ lpd://<I>address</I>/pr3</TD>
+</TR>
+<TR ALIGN="LEFT" VALIGN="TOP">
+ <TD>EFI&reg; Fiery&reg; RIP</TD>
+ <TD>lpd://<I>address</I>/print</TD>
+</TR>
+<TR ALIGN="LEFT" VALIGN="TOP">
+ <TD>EPSON&reg; Multiprotocol Ethernet Interface Board</TD>
+ <TD>socket://<I>address</I></TD>
+</TR>
+<!-- NEED 1in -->
+<TR ALIGN="LEFT" VALIGN="TOP">
+ <TD>Extended System ExtendNET</TD>
+ <TD>lpd://<I>address</I>/pr1<BR>
+ lpd://<I>address</I>/pr2<BR>
+ lpd://<I>address</I>/pr3</TD>
+</TR>
+<!-- NEED 1in -->
+<TR ALIGN="LEFT" VALIGN="TOP">
+ <TD>Hewlett Packard JetDirect w/o IPP</TD>
+ <TD>socket://<I>address</I>:9100<BR>
+ socket://<I>address</I>:9101<BR>
+ socket://<I>address</I>:9102</TD>
+</TR>
+<!-- NEED 1in -->
+<TR ALIGN="LEFT" VALIGN="TOP">
+ <TD>Hewlett Packard JetDirect w/IPP</TD>
+ <TD>ipp://<I>address</I>/ipp<BR>
+ ipp://<I>address</I>/ipp/port1<BR>
+ ipp://<I>address</I>/ipp/port2<BR>
+ ipp://<I>address</I>/ipp/port3</TD>
+</TR>
+<!-- NEED 1in -->
+<TR ALIGN="LEFT" VALIGN="TOP">
+ <TD>Intel® NetportExpress XL, PRO/100</TD>
+ <TD>lpd://<I>address</I>/LPT1_PASSTHRU<BR>
+ lpd://<I>address</I>/LPT2_PASSTHRU<BR>
+ lpd://<I>address</I>/COM1_PASSTHRU</TD>
+</TR>
+<TR ALIGN="LEFT" VALIGN="TOP">
+ <TD>Lexmark<SUP>TM</SUP> MarkNet</TD>
+ <TD>lpd://<I>address</I>/ps</TD>
+</TR>
+<!-- NEED 1in -->
+<TR ALIGN="LEFT" VALIGN="TOP">
+ <TD>Linksys EtherFast&reg;<BR>
+ <A HREF="#LINKSYS">(see directions)</A></TD>
+ <TD>socket://<I>address</I>:4010<BR>
+ socket://<I>address</I>:4020<BR>
+ socket://<I>address</I>:4030</TD>
+</TR>
+<TR ALIGN="LEFT" VALIGN="TOP">
+ <TD>Kodak&reg;</TD>
+ <TD>lpd://<I>address</I>/ps</TD>
+</TR>
+<TR ALIGN="LEFT" VALIGN="TOP">
+ <TD>QMS&reg; CrownNet<SUP>TM</SUP></TD>
+ <TD>lpd://<I>address</I>/ps</TD>
+</TR>
+<TR ALIGN="LEFT" VALIGN="TOP">
+ <TD>Tektronix&reg; PhaserShare<SUP>TM</SUP></TD>
+ <TD>socket://<I>address</I>:9100</TD>
+</TR>
+<TR ALIGN="LEFT" VALIGN="TOP">
+ <TD>XEROX&reg; 4512 NIC</TD>
+ <TD>lpd://<I>address</I>/PORT1</TD>
+</TR>
+<TR ALIGN="LEFT" VALIGN="TOP">
+ <TD>XEROX&reg; XNIC</TD>
+ <TD>lpd://<I>address</I>/PASSTHRU</TD>
+</TR>
+<TR ALIGN="LEFT" VALIGN="TOP">
+ <TD>XEROX&reg; (most others)</TD>
+ <TD>socket://<I>address</I>:5503</TD>
+</TR>
+</TABLE></CENTER>
+
+<H2><A NAME="AXIS">Configuring Axis Print Servers</A></H2>
+
+<P>The Axis print servers can be configured using ARP, RARP, or BOOTP.
+However, on models that do not provide IPP support an additional step
+must be performed to configure the TCP/IP portion of the print server
+for use with CUPS.
+
+<!-- NEED 3in -->
+<P>Each print server contains a configuration file named
+<VAR>config</VAR> that contains a list of network parameters used by
+the server. To modify this file you must first download it from the
+print server using the <CODE>ftp(1)</CODE> program:
+
+<UL><PRE>
+<B>ftp ip-address ENTER</B>
+Connected to ip-address.
+220 Axis NPS ### FTP Printer Server V#.## MON DD YEAR ready.
+ftp> <B>user root ENTER</B>
+331 User name ok, need password
+Password: <B>pass ENTER</B> <I>(this is not echoed)</I>
+230 User logged in
+ftp> <B>get config ENTER</B>
+local: config remote: config
+200 PORT command successful.
+150 Opening data connection for config (192,0,2,2),
+(mode ascii).
+226 Transfer complete.
+##### bytes received in #.## seconds (##### Kbytes/s)
+ftp> <B>quit ENTER</B>
+221 Goodbye.
+</PRE></UL>
+
+<!-- NEED 2in -->
+<P>Next, edit the file with your favorite text editor and locate the
+lines beginning with:
+
+<UL><PRE>
+RTN_OPT. : YES
+RTEL_PR1. : 0
+RTEL_PR2. : 0
+RTEL_PR3. : 0
+RTEL_PR4. : 0
+RTEL_PR5. : 0
+RTEL_PR6. : 0
+RTEL_PR7. : 0
+RTEL_PR8. : 0
+</PRE></UL>
+
+<!-- NEED 1in -->
+Change the <CODE>RTN_OPT</CODE> line to read:
+
+<UL><PRE>
+RTN_OPT. : <B>NO</B>
+</PRE></UL>
+
+<!-- NEED 2in -->
+<P>This disables the Reverse TELNET protocol and enables the standard
+TELNET protocol on the print server. Next, assign a port number for
+each parallel and serial port on the server as follows:
+
+<UL><PRE>
+RTEL_PR1. : <B>9100</B>
+RTEL_PR2. : <B>9101</B>
+RTEL_PR3. : <B>9102</B>
+RTEL_PR4. : <B>9103</B>
+RTEL_PR5. : <B>9104</B>
+RTEL_PR6. : <B>9105</B>
+RTEL_PR7. : <B>9106</B>
+RTEL_PR8. : <B>9107</B>
+</PRE></UL>
+
+<!-- NEED 4in -->
+<P>This essentially makes the Axis print server look like a Hewlett
+Packard JetDirect EX print server. Save the file and then upload the
+new <VAR>config</VAR> file using the <CODE>ftp</CODE> command:
+
+<UL><PRE>
+<B>ftp ip-address ENTER</B>
+Connected to ip-address.
+220 Axis NPS ### FTP Printer Server V#.## MON DD YEAR ready.
+ftp> <B>user root ENTER</B>
+331 User name ok, need password
+Password: <B>pass ENTER</B> <I>(this is not echoed)</I>
+230 User logged in
+ftp> <B>put config CONFIG ENTER</B>
+local: config remote: CONFIG
+200 PORT command successful.
+150 Opening data connection for config (192,0,2,2), (mode ascii).
+226 Transfer complete.
+##### bytes received in #.## seconds (##### Kbytes/s)
+ftp> <B>get hardreset ENTER</B>
+local: hardreset remote: hardreset
+200 PORT command successful.
+421 Axis NPS ### hard reset, closing connection.
+ftp> <B>quit ENTER</B>
+221 Goodbye.
+</PRE></UL>
+
+<P>Your Axis print server is now ready for use!
+
+<H2><A NAME="LINKSYS">Configuring Linksys Print Servers</A></H2>
+
+<P>The Linksys print servers can be configured using ARP, RARP, or
+BOOTP. Like older Axis print servers, an additional step must be
+performed to configure the TCP/IP portion of the print server for use
+with CUPS.
+
+<!-- NEED 3in -->
+<P>Each print server contains a configuration file named
+<VAR>CONFIG</VAR> that contains a list of network parameters used by
+the server. To modify this file you must first download it from the
+print server using the <CODE>ftp(1)</CODE> program:
+
+<UL><PRE>
+<B>ftp -n ip-address ENTER</B>
+Connected to ip-address.
+220 Print Server Ready.
+Remote system type is Print.
+ftp> <B>get CONFIG ENTER</B>
+local: CONFIG remote: CONFIG
+200 Command OK.
+150 Open ASCII Mode Connection.
+WARNING! 68 bare linefeeds received in ASCII mode
+File may not have transferred correctly.
+226 Transfer complete.
+##### bytes received in #.## seconds (##### Kbytes/s)
+ftp> <B>quit ENTER</B>
+221 Goodbye.
+</PRE></UL>
+
+<!-- NEED 2in -->
+<P>Next, edit the file with your favorite text editor and locate the
+lines beginning with:
+
+<UL><PRE>
+0100 L1_PROUT:P1
+0120 L2_PROUT:P1
+0140 L3_PROUT:P1
+</PRE></UL>
+
+<P>Change the port number for
+each parallel and serial port on the server as follows:
+
+<UL><PRE>
+0100 L1_PROUT:<B>P1</B>
+0120 L2_PROUT:<B>P2</B>
+0140 L3_PROUT:<B>P3</B>
+</PRE></UL>
+
+<!-- NEED 4in -->
+<P>This maps each virtual printer with a physical port. Save the file and then upload the
+new <VAR>CONFIG</VAR> file using the <CODE>ftp</CODE> command:
+
+<UL><PRE>
+<B>ftp -n ip-address ENTER</B>
+Connected to ip-address.
+220 Print Server Ready.
+Remote system type is Print.
+ftp> <B>put CONFIG ENTER</B>
+local: CONFIG remote: CONFIG
+200 Command OK.
+150 Open ASCII Mode Connection.
+226 Transfer complete.
+##### bytes received in #.## seconds (##### Kbytes/s)
+ftp> <B>quit ENTER</B>
+221 Goodbye.
+</PRE></UL>
+
+<P>Your Linksys print server is now ready for use!
+
+
+<H1 ALIGN="RIGHT"><A NAME="PRINTER_DRIVERS">C - Printer Drivers</A></H1>
+
+<P>This appendix lists the printer drivers that are provided with CUPS.
+
+<H2>Printer Drivers</H2>
+
+<P>CUPS includes the following printer drivers:
+
+<UL>
+
+ <LI><A HREF="#EPSON9">EPSON 9-pin Dot Matrix</A>, <VAR>epson9.ppd</VAR>
+
+ <LI><A HREF="#EPSON24">EPSON 24-pin Dot Matrix</A>, <VAR>epson24.ppd</VAR>
+
+ <LI><A HREF="#STCOLOR">EPSON Stylus Color</A>, <VAR>stcolor.ppd</VAR>
+
+ <LI><A HREF="#STPHOTO">EPSON Stylus Photo</A>, <VAR>stphoto.ppd</VAR>
+
+ <LI><A HREF="#DESKJET">HP DeskJet</A>, <VAR>deskjet.ppd</VAR>
+
+ <LI><A HREF="#LASERJET">HP LaserJet</A>, <VAR>laserjet.ppd</VAR>
+
+</UL>
+
+<H2><A NAME="EPSON9">EPSON 9-pin Dot Matrix</A></H2>
+
+<P>The EPSON 9-pin Dot Matrix driver (<VAR>epson9.ppd</VAR>) supports
+9-pin dot matrix printers that implement the ESC/P command set. It
+provides 60x72, 120x72, and 240x72 DPI output in black only.
+
+<H2><A NAME="EPSON24">EPSON 24-pin Dot Matrix</A></H2>
+
+<P>The EPSON 24-pin Dot Matrix driver (<VAR>epson9.ppd</VAR>) supports
+24-pin dot matrix printers that implement the ESC/P command set. It
+provides 120x180, 180x180, 360x180, and 360x360 DPI output in black
+only.
+
+<H2><A NAME="STCOLOR">EPSON Stylus Color</A></H2>
+
+<P>The EPSON Stylus Color driver (<VAR>stcolor.ppd</VAR>) supports
+EPSON Stylus Color printers that implement the ESC/P2 command set. It
+provides 180, 360, and 720 DPI output in black and color (CMYK).
+
+<H2><A NAME="STPHOTO">EPSON Stylus Photo</A></H2>
+
+<P>The EPSON Stylus Photo driver (<VAR>stphoto.ppd</VAR>) supports
+EPSON Stylus Photo printers that implement the ESC/P2 command set. It
+provides 180, 360, and 720 DPI output in black and color (CMYKcm).
+
+<H2><A NAME="DESKJET">HP DeskJet</A></H2>
+
+<P>The HP DeskJet driver (<VAR>deskjet.ppd</VAR>) supports HP DeskJet
+printers that implement the PCL command set. It provides 150, 300, and
+600 DPI output in black and color (CMYK).
+
+<P>The DeskJet printers that implement the HP-PPA command set (720C,
+722C, 820C, and 1100C) are <B>not</B> supported due to a complete lack
+of documentation and support from Hewlett Packard.
+
+<P>The duplexer provided with the HP DeskJet 900 series printers is also
+not supported for similar reasons.
+
+<H2><A NAME="LASERJET">HP LaserJet</A></H2>
+
+<P>The HP LaserJet driver (<VAR>laserjet.ppd</VAR>) supports HP
+LaserJet printers that implement the PCL command set. It provides 150,
+300, and 600 DPI output in black only and supports the duplexer if
+installed.
+
+<P>LaserJet printers that do not implement PCL (3100, 3150) are not
+supported due to a complete lack of documentation and support from
+Hewlett Packard.
+
+
+<H1 ALIGN="RIGHT"><A NAME="FILES">D - List of Files</A></H1>
+
+<P>This appendix lists the files and directories that are installed for
+the Common UNIX Printing System.
+
+<CENTER><TABLE BORDER="1" WIDTH="80%">
+<TR VALIGN="TOP">
+ <TH>Pathname</TH>
+ <TH>Description</TH>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/etc/cups/certs/</TD>
+ <TD>The location of authentication certificate files for local
+ HTTP clients.</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/etc/cups/classes.conf</TD>
+ <TD>The printer classes configuration file for the scheduler.</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/etc/cups/cupsd.conf</TD>
+ <TD>The scheduler configuration file.</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/etc/cups/interfaces/</TD>
+ <TD>The location of System V interface scripts for printers.</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/etc/cups/mime.convs</TD>
+ <TD>The list of standard file filters included with ESP Print Pro.</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/etc/cups/mime.types</TD>
+ <TD>The list of recognized file types for ESP Print Pro.</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/etc/cups/ppd/</TD>
+ <TD>The location of PostScript Printer Description ("PPD") files for
+ printers.</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/etc/cups/printers.conf</TD>
+ <TD>The printer configuration file for the scheduler.</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/usr/bin/cancel</TD>
+ <TD>The System V cancel job(s) command.</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/usr/bin/disable</TD>
+ <TD>The System V disable printer command.</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/usr/bin/enable</TD>
+ <TD>The System V enable printer command.</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/usr/bin/lp</TD>
+ <TD>The System V print command.</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/usr/bin/lpoptions</TD>
+ <TD>Sets user-defined printing options and defaults.</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/usr/bin/lppasswd</TD>
+ <TD>Adds, changes, or removes Digest password accounts.</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/usr/bin/lpq</TD>
+ <TD>The Berkeley status command.</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/usr/bin/lpr</TD>
+ <TD>The Berkeley print command.</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/usr/bin/lprm</TD>
+ <TD>The Berkeley cancel job(s) command.</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/usr/bin/lpstat</TD>
+ <TD>The System V status command.</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/usr/include/cups/</TD>
+ <TD>CUPS API header files.</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/usr/lib32/libcups.a<BR>
+ /usr/lib32/libcupsimage.a</TD>
+ <TD>Static libraries (IRIX 6.5)</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/usr/lib/libcups.a<BR>
+ /usr/lib/libcupsimage.a</TD>
+ <TD>Static libraries (all others)</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/usr/lib/libcups.sl.2<BR>
+ /usr/lib/libcupsimage.sl.2</TD>
+ <TD>Shared libraries (HP-UX)</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/usr/lib32/libcups.so.2<BR>
+ /usr/lib32/libcupsimage.so.2</TD>
+ <TD>Shared libraries (IRIX 6.5)</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/usr/lib/libcups.so.2<BR>
+ /usr/lib/libcupsimage.so.2</TD>
+ <TD>Shared libraries (all others)</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/usr/lib/cups/backend/</TD>
+ <TD>Backends for various types of printer connections.</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/usr/lib/cups/cgi-bin/</TD>
+ <TD>CGI programs for the scheduler.</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/usr/lib/cups/daemon/</TD>
+ <TD>Daemons for polling and LPD support.</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/usr/lib/cups/filter/</TD>
+ <TD>Filters for various types of files.</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/usr/lib/locale/</TD>
+ <TD>The location of language-specific message files. (System V)</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/usr/lib/nls/msg/</TD>
+ <TD>The location of language-specific message files. (Compaq Tru64 UNIX)</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/usr/share/locale/</TD>
+ <TD>The location of language-specific message files. (Linux, *BSD)</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/usr/sbin/accept</TD>
+ <TD>The accept-jobs command.</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/usr/sbin/cupsd</TD>
+ <TD>The CUPS print scheduler.</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/usr/sbin/lpadmin</TD>
+ <TD>The System V printer administration tool.</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/usr/sbin/lpc</TD>
+ <TD>The Berkeley printer administration tool.</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/usr/sbin/lpinfo</TD>
+ <TD>The get-devices and get-ppds command.</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/usr/sbin/lpmove</TD>
+ <TD>The move-jobs command.</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/usr/sbin/reject</TD>
+ <TD>The reject-jobs command.</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/usr/share/catman/a_man/<BR>
+ /usr/share/catman/u_man/</TD>
+ <TD>Man pages (IRIX)</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/usr/share/man/</TD>
+ <TD>Man pages (Compaq Tru64 UNIX, HP-UX, Solaris)</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/usr/man/</TD>
+ <TD>Man pages (all others)</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/usr/share/cups/data/</TD>
+ <TD>The location of filter data files.</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/usr/share/cups/data/testprint.ps</TD>
+ <TD>The PostScript test page file.</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/usr/share/cups/fonts/</TD>
+ <TD>The location of PostScript fonts for the PostScript RIP.</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/usr/share/cups/model/</TD>
+ <TD>The location of PostScript Printer Description ("PPD") files and
+ interface scripts that may be used to setup a printer queue.</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/usr/share/cups/pstoraster/</TD>
+ <TD>Other PostScript RIP initialization files.</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/usr/share/cups/pstoraster/Fontmap</TD>
+ <TD>The font mapping file (converts filenames to fontnames)</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/usr/share/cups/templates/</TD>
+ <TD>The location of HTML template files for the web interfaces.</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/usr/share/doc/cups/</TD>
+ <TD>Documentation and web page data for the scheduler.</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/var/log/cups/</TD>
+ <TD>The location of scheduler log files.</TD>
+</TR>
+<TR VALIGN="TOP">
+ <TD>/var/spool/cups/</TD>
+ <TD>The location of print files waiting to be printed.</TD>
+</TR>
+</TABLE></CENTER>
+
+
+<H1 ALIGN="RIGHT"><A NAME="FAQ">E - Troubleshooting Common Problems</A></H1>
+
+<P>This appendix covers some of the common problems first-time users
+encounter when installing and configuring CUPS.
+
+<P>Commercial support for CUPS is available from Easy Software Products.
+For more information please contact us at:
+
+<UL>
+
+ <LI>WWW: <A HREF="http://www.easysw.com">
+ <CODE>http://www.easysw.com</CODE></A>
+
+ <LI>EMail: <A HREF="mailto:info@easysw.com">info@easysw.com</A>
+
+ <LI>Telephone (M-F, 9-5 EST): +1.301.373.9600
+
+</UL>
+
+<H2>My Applications Don't See the Available Printers</H1>
+
+<P>Many applications read the <VAR>/etc/printcap</VAR> file to
+get a list of available printers.
+
+<P>The default CUPS configuration does not create the
+<VAR>/etc/printcap</VAR> file automatically. To enable automatic
+creation and updating of this file, use the
+<A HREF="#Printcap"><CODE>Printcap</CODE></A> directive described in
+<A HREF="#PRINTING_MANAGEMENT">Chapter 6, "Printing System Management"</A>.
+
+<H2>CUPS Doesn't Recognize My Username or Password!</H2>
+
+<P>CUPS will ask you for a UNIX username and password when you perform
+printer administration tasks remotely or via a web browser. The default
+configuration requires that you use the <CODE>root</CODE> username and
+the corresponding password to authenticate the request.
+
+<P>CUPS does not allow you to authenticate an administration request
+with an account that has no password for security reasons. If you do
+not have a password on your <CODE>root</CODE> account then you won't be
+able to add printers remotely or via the web interface!
+
+<!-- NEED 2in -->
+<P>To disable password authentication you need to edit the
+<VAR>/etc/cups/cupsd.conf</VAR> file and comment out the
+lines reading:
+
+<UL><PRE>
+AuthType Basic
+AuthClass System
+</UL></PRE>
+
+for the <VAR>/admin</VAR> location. Then restart the CUPS server as
+described in <A HREF="#PRINTING_MANAGEMENT">Chapter 6, "Printing System
+Management"</A>.
+
+<CENTER><TABLE WIDTH="80%" BORDER="1" CELLPADDING="5" BGCOLOR="#cccccc">
+<TR>
+ <TD>
+ <B>NOTE:</B>
+
+ <P>Disabling password checks will allow any local user to
+ change your printer and class configuration, but remote
+ administration from another machine will still not be allowed.
+ </TD>
+</TR>
+</TABLE></CENTER>
+
+<H2><A NAME="ALLOW_REMOTE">I Can't Do Administration Tasks from Another Machine!</A></H2>
+
+<P>The default CUPS configuration limits administration to the local
+machine. To open up access, edit the <VAR>/etc/cups/cupsd.conf</VAR>
+and comment out the lines reading:
+
+<UL><PRE>
+Order deny,allow
+Deny from all
+Allow from 127.0.0.1
+</PRE></UL>
+
+for the <VAR>/admin</VAR> location. Then restart the CUPS server as
+described in <A HREF="#PRINTING_MANAGEMENT">Chapter 6, "Printing System
+Management"</A>.
+
+<CENTER><TABLE WIDTH="80%" BORDER="1" CELLPADDING="5" BGCOLOR="#cccccc">
+<TR>
+ <TD>
+ <B>NOTE:</B>
+
+ <P>Allowing administration access from all hosts is a potential
+ security risk. Please read <A HREF="#PRINTING_SECURITY">Chapter
+ 6, "Printing System Management"</A> for a description of these
+ risks and ways to minimize them.
+ </TD>
+</TR>
+</TABLE></CENTER>
+
+<!-- NEED 4in -->
+<H2>I Can't Do Administration Tasks from My Web Browser!</H2>
+
+<P>This problem is usually caused by:
+
+<OL>
+
+ <LI>not specifying the correct password for the
+ root account.
+
+ <LI>accessing the CUPS server using the hostname or IP
+ address of the server without enabling remote access for
+ administration functions. This can be corrected by following
+ the instructions in the <A HREF="#ALLOW_REMOTE">"I Can't Do
+ Administration Tasks from Another Machine!"</A> section earlier
+ in this appendix.
+
+ <LI>not setting a password on the root account. CUPS will not
+ authenticate a user account that does not have a password for
+ security reasons.
+
+ <LI>authenticating using an account other than root, but the
+ account you are using is not a member of the system group.
+
+ <LI>configuring CUPS to use Digest authentication, but
+ your web browser does not support Digest authentication.
+
+</OL>
+
+<H2>Connection Refused Messages</H2>
+
+<P>Under normal circumstances, "connection refused" messages for a
+networked printer should be expected from time to time. Most network
+interfaces only allow a single connection to be made at any given time
+(one job at a time) and will refuse access to all other systems while
+the first connection is active. CUPS automatically retries the
+connection once every 30 seconds.
+
+<P>If the problem persists and you are unable to print any jobs to the printer,
+verify that another machine is not maintaining a connection with the printer,
+and that you have selected the proper port or printer name for the printer.
+
+<P>Also, most external print servers will refuse connections if the connected
+printer is turned off or is off-line. Verify that the affected printer is
+turned on and is online.
+
+<H2>Write Error Messages</H2>
+
+<P>If you get "write error" messages on a printer queue the printer
+interface (usually a Hewlett Packard JetDirect interface) has timed out
+and reset the network connection from your workstation.
+
+<P>The error is caused by that startup delay between the initial setup
+of the printer or plotter and the first page of print data that is
+sent.
+
+<!-- NEED 3in -->
+<P>To correct the problem, change the idle timeout on the interface to at least
+180 seconds or 3 minutes. To change the timeout on a Hewlett Packard
+JetDirect interface, type:
+
+<UL><PRE>
+<B>telnet ip-address ENTER</B>
+
+Trying ip-address...
+Connected to ip-address.
+Escape character is `^]'.
+
+Please type [Return] two times, to initialize telnet configuration
+For HELP type "?"
+> <B>idle-timeout: 180 ENTER</B>
+> <B>quit ENTER</B>
+</PRE></UL>
+
+</BODY>
+</HTML>
diff --git a/doc/sdd.html b/doc/sdd.html
new file mode 100644
index 000000000..30d0464ec
--- /dev/null
+++ b/doc/sdd.html
@@ -0,0 +1,591 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD>
+<TITLE>CUPS Software Design Description</TITLE>
+<META NAME="author" CONTENT="Easy Software Products">
+<META NAME="copyright" CONTENT="Copyright 1997-2002, All Rights Reserved">
+<META NAME="docnumber" CONTENT="CUPS-SDD-1.1">
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=iso-8859-1">
+<STYLE TYPE="text/css"><!--
+BODY { font-family: serif }
+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 }
+SUB { font-size: smaller }
+SUP { font-size: smaller }
+PRE { font-family: monospace }
+--></STYLE>
+</HEAD>
+<BODY>
+<CENTER><A HREF="#CONTENTS"><IMG SRC="images/cups-large.gif" BORDER="0" WIDTH="431" HEIGHT="511"><BR>
+<H1>CUPS Software Design Description</H1></A><BR>
+CUPS-SDD-1.1<BR>
+Easy Software Products<BR>
+Copyright 1997-2002, All Rights Reserved<BR>
+</CENTER>
+<HR>
+<H1 ALIGN="CENTER"><A NAME="CONTENTS">Table of Contents</A></H1>
+<BR>
+<BR><B><A HREF="#1">1 Scope</A></B>
+<UL>
+<LI><A HREF="#1_1">1.1 Identification</A></LI>
+<LI><A HREF="#1_2">1.2 System Overview</A></LI>
+<LI><A HREF="#1_3">1.3 Document Overview</A></LI>
+</UL>
+<B><A HREF="#2">2 References</A></B>
+<UL>
+<LI><A HREF="#2_1">2.1 CUPS Documentation</A></LI>
+<LI><A HREF="#2_2">2.2 Other Documents</A></LI>
+</UL>
+<B><A HREF="#3">3 Design Overview</A></B>
+<UL>
+<LI><A HREF="#3_1">3.1 Backends</A></LI>
+<UL>
+<LI><A HREF="#3_1_1">3.1.1 ipp</A></LI>
+<LI><A HREF="#3_1_2">3.1.2 lpd</A></LI>
+<LI><A HREF="#3_1_3">3.1.3 parallel</A></LI>
+<LI><A HREF="#3_1_4">3.1.4 serial</A></LI>
+<LI><A HREF="#3_1_5">3.1.5 socket</A></LI>
+<LI><A HREF="#3_1_6">3.1.6 usb</A></LI>
+</UL>
+<LI><A HREF="#3_2">3.2 Berkeley Commands</A></LI>
+<UL>
+<LI><A HREF="#3_2_1">3.2.1 lpc</A></LI>
+<LI><A HREF="#3_2_2">3.2.2 lpq</A></LI>
+<LI><A HREF="#3_2_3">3.2.3 lpr</A></LI>
+<LI><A HREF="#3_2_4">3.2.4 lprm</A></LI>
+</UL>
+<LI><A HREF="#3_3">3.3 CGI</A></LI>
+<UL>
+<LI><A HREF="#3_3_1">3.3.1 admin.cgi</A></LI>
+<LI><A HREF="#3_3_2">3.3.2 classes.cgi</A></LI>
+<LI><A HREF="#3_3_3">3.3.3 jobs.cgi</A></LI>
+<LI><A HREF="#3_3_4">3.3.4 printers.cgi</A></LI>
+</UL>
+<LI><A HREF="#3_4">3.4 CUPS Application Programmers Interface</A></LI>
+<UL>
+<LI><A HREF="#3_4_1">3.4.1 Convenience Functions</A></LI>
+<LI><A HREF="#3_4_2">3.4.2 HTTP Functions</A></LI>
+<LI><A HREF="#3_4_3">3.4.3 IPP Functions</A></LI>
+<LI><A HREF="#3_4_4">3.4.4 Language Functions</A></LI>
+<LI><A HREF="#3_4_5">3.4.5 PPD Functions</A></LI>
+</UL>
+<LI><A HREF="#3_5">3.5 CUPS Imaging Library</A></LI>
+<UL>
+<LI><A HREF="#3_5_1">3.5.1 Colorspace Conversion Functions</A></LI>
+<LI><A HREF="#3_5_2">3.5.2 Color Management Functions</A></LI>
+<LI><A HREF="#3_5_3">3.5.3 Image Management Functions</A></LI>
+<LI><A HREF="#3_5_4">3.5.4 Scaling Functions</A></LI>
+<LI><A HREF="#3_5_5">3.5.5 Image File Functions</A></LI>
+<LI><A HREF="#3_5_6">3.5.6 Raster Functions</A></LI>
+</UL>
+<LI><A HREF="#3_6">3.6 Daemons</A></LI>
+<UL>
+<LI><A HREF="#3_6_1">3.6.1 Line Printer Daemon</A></LI>
+<LI><A HREF="#3_6_2">3.6.2 Polling Daemon</A></LI>
+</UL>
+<LI><A HREF="#3_7">3.7 Filters</A></LI>
+<UL>
+<LI><A HREF="#3_7_1">3.7.1 hpgltops</A></LI>
+<LI><A HREF="#3_7_2">3.7.2 imagetops</A></LI>
+<LI><A HREF="#3_7_3">3.7.3 imagetoraster</A></LI>
+<LI><A HREF="#3_7_4">3.7.4 pdftops</A></LI>
+<LI><A HREF="#3_7_5">3.7.5 pstops</A></LI>
+<LI><A HREF="#3_7_6">3.7.6 pstoraster</A></LI>
+<LI><A HREF="#3_7_7">3.7.7 rastertoepson</A></LI>
+<LI><A HREF="#3_7_8">3.7.8 rastertohp</A></LI>
+<LI><A HREF="#3_7_9">3.7.9 texttops</A></LI>
+</UL>
+<LI><A HREF="#3_8">3.8 Scheduler</A></LI>
+<UL>
+<LI><A HREF="#3_8_1">3.8.1 Authorization</A></LI>
+<LI><A HREF="#3_8_2">3.8.2 Classes</A></LI>
+<LI><A HREF="#3_8_3">3.8.3 Client</A></LI>
+<LI><A HREF="#3_8_4">3.8.4 Configuration</A></LI>
+<LI><A HREF="#3_8_5">3.8.5 Devices</A></LI>
+<LI><A HREF="#3_8_6">3.8.6 Directory Services</A></LI>
+<LI><A HREF="#3_8_7">3.8.7 IPP</A></LI>
+<LI><A HREF="#3_8_8">3.8.8 Jobs</A></LI>
+<LI><A HREF="#3_8_9">3.8.9 Logging</A></LI>
+<LI><A HREF="#3_8_10">3.8.10 Main</A></LI>
+<LI><A HREF="#3_8_11">3.8.11 MIME</A></LI>
+<LI><A HREF="#3_8_12">3.8.12 PPDs</A></LI>
+<LI><A HREF="#3_8_13">3.8.13 Printers</A></LI>
+</UL>
+<LI><A HREF="#3_9">3.9 System V Commands</A></LI>
+<UL>
+<LI><A HREF="#3_9_1">3.9.1 accept</A></LI>
+<LI><A HREF="#3_9_2">3.9.2 cancel</A></LI>
+<LI><A HREF="#3_9_3">3.9.3 disable</A></LI>
+<LI><A HREF="#3_9_4">3.9.4 enable</A></LI>
+<LI><A HREF="#3_9_5">3.9.5 lp</A></LI>
+<LI><A HREF="#3_9_6">3.9.6 lpadmin</A></LI>
+<LI><A HREF="#3_9_7">3.9.7 lpinfo</A></LI>
+<LI><A HREF="#3_9_8">3.9.8 lpmove</A></LI>
+<LI><A HREF="#3_9_9">3.9.9 lpoptions</A></LI>
+<LI><A HREF="#3_9_10">3.9.10 lpstat</A></LI>
+<LI><A HREF="#3_9_11">3.9.11 reject</A></LI>
+</UL>
+</UL>
+<B><A HREF="#4">A Glossary</A></B>
+<UL>
+<LI><A HREF="#4_1">A.1 Terms</A></LI>
+<LI><A HREF="#4_2">A.2 Acronyms</A></LI>
+</UL>
+<HR>
+<H1><A NAME="1">1 Scope</A></H1>
+<H2><A NAME="1_1">1.1 Identification</A></H2>
+ This software design description document provides general information
+ on the architecture and coding of the Common UNIX Printing System
+ (&quot;CUPS&quot;) Version 1.1.
+<H2><A NAME="1_2">1.2 System Overview</A></H2>
+<P>CUPS provides a portable printing layer for UNIX&reg;-based operating
+ systems. It has been developed by<A HREF="http://www.easysw.com"> Easy
+ Software Products</A> to promote a standard printing solution for all
+ UNIX vendors and users. CUPS provides the System V and Berkeley
+ command-line interfaces.</P>
+<P>CUPS uses the Internet Printing Protocol (&quot;IPP&quot;) as the basis for
+ managing print jobs and queues. The Line Printer Daemon (&quot;LPD&quot;) Server
+ Message Block (&quot;SMB&quot;), and AppSocket (a.k.a. JetDirect) protocols are
+ also supported with reduced functionality. CUPS adds network printer
+ browsing and PostScript Printer Description (&quot;PPD&quot;) based printing
+ options to support real-world printing under UNIX.</P>
+<P>CUPS also includes a customized version of GNU Ghostscript (currently
+ based off GNU Ghostscript 5.50) and an image file RIP that are used to
+ support non-PostScript printers. Sample drivers for HP and EPSON
+ printers are included that use these filters.</P>
+<H2><A NAME="1_3">1.3 Document Overview</A></H2>
+ This software design description document is organized into the
+ following sections:
+<UL>
+<LI>1 - Scope</LI>
+<LI>2 - References</LI>
+<LI>3 - Design Overview</LI>
+<LI>A - Glossary</LI>
+</UL>
+<H1><A NAME="2">2 References</A></H1>
+<H2><A NAME="2_1">2.1 CUPS Documentation</A></H2>
+<P>The following CUPS documentation is referenced by this document:</P>
+<UL>
+<LI>CUPS-CMP-1.1: CUPS Configuration Management Plan</LI>
+<LI>CUPS-IDD-1.1: CUPS System Interface Design Description</LI>
+<LI>CUPS-IPP-1.1: CUPS Implementation of IPP</LI>
+<LI>CUPS-SAM-1.1.x: CUPS Software Administrators Manual</LI>
+<LI>CUPS-SDD-1.1: CUPS Software Design Description</LI>
+<LI>CUPS-SPM-1.1.x: CUPS Software Programming Manual</LI>
+<LI>CUPS-SSR-1.1: CUPS Software Security Report</LI>
+<LI>CUPS-STP-1.1: CUPS Software Test Plan</LI>
+<LI>CUPS-SUM-1.1.x: CUPS Software Users Manual</LI>
+<LI>CUPS-SVD-1.1: CUPS Software Version Description</LI>
+</UL>
+<H2><A NAME="2_2">2.2 Other Documents</A></H2>
+<P>The following non-CUPS documents are referenced by this document:</P>
+<UL>
+<LI><A HREF="http://partners.adobe.com/asn/developer/PDFS/TN/5003.PPD_Spec_v4.3.pdf">
+Adobe PostScript Printer Description File Format Specification, Version
+ 4.3.</A></LI>
+<LI><A HREF="http://partners.adobe.com/asn/developer/PDFS/TN/PLRM.pdf">
+Adobe PostScript Language Reference, Third Edition.</A></LI>
+<LI>IPP: Job and Printer Set Operations</LI>
+<LI>IPP/1.1: Encoding and Transport</LI>
+<LI>IPP/1.1: Implementers Guide</LI>
+<LI>IPP/1.1: Model and Semantics</LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc1179.txt">RFC 1179, Line Printer
+ Daemon Protocol</A></LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc2567.txt">RFC 2567, Design Goals
+ for an Internet Printing Protocol</A></LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc2568.txt">RFC 2568, Rationale
+ for the Structure of the Model and Protocol</A> for the Internet
+ Printing Protocol</LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc2569.txt">RFC 2569, Mapping
+ between LPD and IPP Protocols</A></LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616, Hypertext
+ Transfer Protocol -- HTTP/1.1</A></LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc2617.txt">RFC 2617, HTTP
+ Authentication: Basic and Digest Access</A> Authentication</LI>
+</UL>
+<H1><A NAME="3">3 Design Overview</A></H1>
+ CUPS is composed of 9 software sub-systems that operate together to
+ perform common printing tasks:
+<UL>
+<LI>Backends</LI>
+<LI>Berkeley Commands</LI>
+<LI>CGI</LI>
+<LI>CUPS Application Programmers Interface</LI>
+<LI>CUPS Imaging Library</LI>
+<LI>Daemons</LI>
+<LI>Filters</LI>
+<LI>Scheduler</LI>
+<LI>System V Commands</LI>
+</UL>
+<H2><A NAME="3_1">3.1 Backends</A></H2>
+ The backends implement communications over a number of different
+ interfaces. All backends are called with a common set of arguments:
+<UL>
+<LI>Device URI - the Uniform Resource Identifier for the output device
+ (e.g. <CODE>parallel:/dev/plp</CODE>, <CODE>ipp://hostname/resource</CODE>
+).</LI>
+<LI>Job Identifier - the job identifier for this job (integer).</LI>
+<LI>User Name - the user associated with this job (name string).</LI>
+<LI>Title - the title/job-name associated with this job (name string).</LI>
+<LI>Copies - the number of copies required (integer).</LI>
+<LI>Options - the options associated with this job (space separated
+ option strings).</LI>
+<LI>Filename (optional) - the file to print; if this option is not
+ specified, the backend must read the print file from the standard
+ input.</LI>
+</UL>
+<P>Backends are named using the scheme of the URI, so a URI of
+ &quot;ipp://hostname/resource&quot; would be processed by the &quot;ipp&quot; backend.</P>
+<H3><A NAME="3_1_1">3.1.1 ipp</A></H3>
+<P>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 <CODE>
+printer-uri-supported</CODE> attribute from the printer or host.</P>
+<H3><A NAME="3_1_2">3.1.2 lpd</A></H3>
+<P>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:</P>
+<UL>
+<PRE>lpd://hostname/queue
+</PRE>
+</UL>
+<H3><A NAME="3_1_3">3.1.3 parallel</A></H3>
+<P>The parallel backend sends the specified job to a local printer
+ connected via the specified parallel port device. The URI is of the
+ form:</P>
+<UL>
+<PRE>parallel:/dev/file
+</PRE>
+</UL>
+<H3><A NAME="3_1_4">3.1.4 serial</A></H3>
+<P>The serial backend sends the specified job to a local printer
+ connected via the specified serial port device. The URI is of the form:</P>
+<UL>
+<PRE>serial:/dev/file?option[+option+...]
+</PRE>
+</UL>
+ The options can be any combination of the following:
+<UL>
+<LI><CODE>baud=<I>rate</I></CODE> - Sets the baud rate for the device.</LI>
+<LI><CODE>bits=<I>7 or 8</I></CODE> - Sets the number of data bits.</LI>
+<LI><CODE>parity=<I>even</I></CODE> - Sets even parity checking.</LI>
+<LI><CODE>parity=<I>odd</I></CODE> - Sets odd parity checking.</LI>
+<LI><CODE>parity=<I>none</I></CODE> - Turns parity checking off.</LI>
+<LI><CODE>flow=dtrdsr<I></I></CODE> - Turns DTR/DSR (hardware) flow
+ control on.</LI>
+<LI><CODE>flow=hard<I></I></CODE> - Turns RTS/CTS (hardware) flow
+ control on.</LI>
+<LI><CODE>flow=none<I></I></CODE> - Turns flow control off.</LI>
+<LI><CODE>flow=rtscts<I></I></CODE> - Turns RTS/CTS (hardware) flow
+ control on.</LI>
+<LI><CODE>flow=xonxoff<I></I></CODE> - Turns XON/XOFF (software) flow
+ control on.</LI>
+</UL>
+<H3><A NAME="3_1_5">3.1.5 socket</A></H3>
+<P>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:</P>
+<UL>
+<PRE>socket://hostname[:port]
+</PRE>
+</UL>
+ The default port number is 9100.
+<H3><A NAME="3_1_6">3.1.6 usb</A></H3>
+<P>The usb backend sends the specified job to a local printer connected
+ via the specified usb port device. The URI is of the form:</P>
+<UL>
+<PRE>usb:/dev/file
+</PRE>
+</UL>
+<H2><A NAME="3_2">3.2 Berkeley Commands</A></H2>
+<P>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 hardcoded to use the Berkeley commands.</P>
+<H3><A NAME="3_2_1">3.2.1 lpc</A></H3>
+ The lpc command allows users and administrators to check the status and
+ control print queues. The version provided with CUPS supports the
+ following commands:
+<UL>
+<LI>quit - Quits the lpc command.</LI>
+<LI>status - Shows the status of printers and jobs in the queue.</LI>
+</UL>
+<H3><A NAME="3_2_2">3.2.2 lpq</A></H3>
+<P>The lpq command shows the current queue status.</P>
+<H3><A NAME="3_2_3">3.2.3 lpr</A></H3>
+<P>The lpr command submits a job for printing. The CUPS version of lpr
+ silently ignores the &quot;i&quot;, &quot;t&quot;, &quot;m&quot;, &quot;h&quot;, and &quot;s&quot; options.</P>
+<H3><A NAME="3_2_4">3.2.4 lprm</A></H3>
+<P>The lprm removes one or more print jobs.</P>
+<H2><A NAME="3_3">3.3 CGI</A></H2>
+<P>The Common Gateway Interface (CGI) programs provide a web-based
+ status interface to monitor the status of printers, classes, and jobs.
+ Each of the CGIs utilize HTML template files that can be customized to
+ provide alternate appearances.</P>
+<H3><A NAME="3_3_1">3.3.1 admin.cgi</A></H3>
+<P>The admin CGI provides administration interfaces for printers and
+ classes. The user can add, modify, delete, start, stop, and configure
+ printers and classes using &quot;wizard&quot; interfaces.</P>
+<H3><A NAME="3_3_2">3.3.2 classes.cgi</A></H3>
+<P>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.</P>
+<H3><A NAME="3_3_3">3.3.3 jobs.cgi</A></H3>
+<P>The jobs CGI lists the queued print jobs in order of priority. The
+ list can be limited by printer or job.</P>
+<H3><A NAME="3_3_4">3.3.4 printers.cgi</A></H3>
+<P>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.</P>
+<H2><A NAME="3_4">3.4 CUPS Application Programmers Interface</A></H2>
+<P>The CUPS Application Programmers Interface (&quot;API&quot;) provides common
+ convenience, HTTP, IPP, language, and PPD functions used by the CUPS
+ software.</P>
+<H3><A NAME="3_4_1">3.4.1 Convenience Functions</A></H3>
+<P>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.</P>
+<H3><A NAME="3_4_2">3.4.2 HTTP Functions</A></H3>
+<P>The HTTP functions provide functions to connect to HTTP servers,
+ issue requests, read data from a server, and write data to a server.</P>
+<H3><A NAME="3_4_3">3.4.3 IPP Functions</A></H3>
+<P>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.</P>
+<H3><A NAME="3_4_4">3.4.4 Language Functions</A></H3>
+<P>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, UTF-8, ISO-8859-1, etc.)</P>
+<H3><A NAME="3_4_5">3.4.5 PPD Functions</A></H3>
+<P>The PostScript Printer Description functions manage PPD files, select
+ options, check for option conflicts, and emit selected options in the
+ correct order.</P>
+<H2><A NAME="3_5">3.5 CUPS Imaging Library</A></H2>
+<P>The CUPS imaging library provides colorspace conversion, color
+ management, image management, scaling, image file, and raster functions
+ used by the CUPS raster filters.</P>
+<H3><A NAME="3_5_1">3.5.1 Colorspace Conversion Functions</A></H3>
+<P>The colorspace conversion functions handle conversion of grayscale
+ and RGB colors to grayscale, RGB, K, CMY, CMYK, and CMYKcm colorspaces.</P>
+<H3><A NAME="3_5_2">3.5.2 Color Management Functions</A></H3>
+<P>The color management functions handle gamut mapping and density
+ correction. These are integrated with the colorspace conversion
+ functions so that colorspace conversion and color management are
+ processed in a single step.</P>
+<H3><A NAME="3_5_3">3.5.3 Image Management Functions</A></H3>
+<P>The image management functions manage a tiled image database that is
+ swapped to/from disk as needed.</P>
+<H3><A NAME="3_5_4">3.5.4 Scaling Functions</A></H3>
+<P>The scaling functions provide image scaling services using
+ nearest-neighbor sampling and bilinear interpolation as appropriate.</P>
+<H3><A NAME="3_5_5">3.5.5 Image File Functions</A></H3>
+<P>The image file functions handle loading of all image file formats.</P>
+<H3><A NAME="3_5_6">3.5.6 Raster Functions</A></H3>
+<P>The raster functions manage streams of CUPS raster data (described in
+ the Interface Design Document) used by non-PostScript printer drivers
+ and raster filters.</P>
+<H2><A NAME="3_6">3.6 Daemons</A></H2>
+<P>The daemons provide additional network functions for the scheduler.
+ Currently only two daemons are provided with CUPS.</P>
+<H3><A NAME="3_6_1">3.6.1 Line Printer Daemon</A></H3>
+<P>The line printer daemon provides remote LPD client support and is run
+ by the <CODE>inetd(8)</CODE> daemon as needed.</P>
+<H3><A NAME="3_6_2">3.6.2 Polling Daemon</A></H3>
+<P>The polling daemon is used to poll a remote server for a list of
+ available printers and provide it to the scheduler for addition. A
+ separate polling daemon is run by the scheduler for every remote system
+ listed for polling in the scheduler configuration file.</P>
+<H2><A NAME="3_7">3.7 Filters</A></H2>
+<P>The filters implement file conversion services for CUPS. All filters
+ are called with a common set of arguments:</P>
+<UL>
+<LI>Printer name - the name of the destination printer (name string).</LI>
+<LI>Job Identifier - the job identifier for this job (integer).</LI>
+<LI>User Name - the user associated with this job (name string).</LI>
+<LI>Title - the title/job-name associated with this job (name string).</LI>
+<LI>Copies - the number of copies required (integer).</LI>
+<LI>Options - the options associated with this job (space separated
+ option strings).</LI>
+<LI>Filename (optional) - the file to print; if this option is not
+ specified, the filter must read the input file from the standard input.</LI>
+</UL>
+<P>Filters are added to the MIME conversion data file and implement all
+ necessary conversions from one file type to another.</P>
+<H3><A NAME="3_7_1">3.7.1 hpgltops</A></H3>
+<P>The hpgltops filter converts HP-GL/2 files into PostScript.</P>
+<H3><A NAME="3_7_2">3.7.2 imagetops</A></H3>
+<P>The imagetops filter converts image files into PostScript.</P>
+<H3><A NAME="3_7_3">3.7.3 imagetoraster</A></H3>
+<P>The imagetoraster filter converts image files into CUPS raster data.</P>
+<H3><A NAME="3_7_4">3.7.4 pdftops</A></H3>
+<P>The pdftops filter converts PDF files into PostScript.</P>
+<H3><A NAME="3_7_5">3.7.5 pstops</A></H3>
+<P>The pstops filter inserts printer-specific commands from PPD files
+ and performs page filtering as requested by the user.</P>
+<H3><A NAME="3_7_6">3.7.6 pstoraster</A></H3>
+<P>The pstoraster filter converts PostScript program data into CUPS
+ raster data.</P>
+<H3><A NAME="3_7_7">3.7.7 rastertoepson</A></H3>
+<P>The rastertoepson filter handles converting CUPS raster data to ESC/P
+ and supports both color and black-and-white printers.</P>
+<H3><A NAME="3_7_8">3.7.8 rastertohp</A></H3>
+<P>The rastertohp filter handles converting CUPS raster data to HP-PCL
+ and supports both color and black-and-white printers.</P>
+<H3><A NAME="3_7_9">3.7.9 texttops</A></H3>
+<P>The texttops filter converts text files into PostScript.</P>
+<H2><A NAME="3_8">3.8 Scheduler</A></H2>
+<P>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.</P>
+<H3><A NAME="3_8_1">3.8.1 Authorization</A></H3>
+<P>The authorization module is responsible for performing access control
+ and authentication for all HTTP and IPP requests entering the system.</P>
+<H3><A NAME="3_8_2">3.8.2 Classes</A></H3>
+<P>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.</P>
+<H3><A NAME="3_8_3">3.8.3 Client</A></H3>
+<P>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 and administration.</P>
+<P>Once authorized, all IPP requests are sent to the IPP module.</P>
+<H3><A NAME="3_8_4">3.8.4 Configuration</A></H3>
+<P>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.</P>
+<H3><A NAME="3_8_5">3.8.5 Devices</A></H3>
+<P>The devices module is responsible for managing the list of available
+ devices for the CUPS-Get-Devices operation.</P>
+<H3><A NAME="3_8_6">3.8.6 Directory Services</A></H3>
+<P>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.</P>
+<P>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.</P>
+<H3><A NAME="3_8_7">3.8.7 IPP</A></H3>
+<P>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.</P>
+<H3><A NAME="3_8_8">3.8.8 Jobs</A></H3>
+<P>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.</P>
+<H3><A NAME="3_8_9">3.8.9 Logging</A></H3>
+<P>The logging module manages the access, error, and page log files that
+ are generated by the scheduler.</P>
+<H3><A NAME="3_8_10">3.8.10 Main</A></H3>
+<P>The main module is responsible for timing out and dispatching input
+ and output for client connections. It also watches for incoming <CODE>
+SIGHUP</CODE> and <CODE>SIGCHLD</CODE> signals, reloads the server
+ configuration files as needed, and handles child process errors and
+ exits.</P>
+<H3><A NAME="3_8_11">3.8.11 MIME</A></H3>
+<P>The Multimedia Internet Mail Exchange module manages 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.</P>
+<H3><A NAME="3_8_12">3.8.12 PPDs</A></H3>
+<P>The PPDs module is responsible for managing the list of available PPD
+ files for the CUPS-Get-PPDs operation.</P>
+<H3><A NAME="3_8_13">3.8.13 Printers</A></H3>
+<P>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.</P>
+<H2><A NAME="3_9">3.9 System V Commands</A></H2>
+<P>The System V commands provide a robust command-line interface to CUPS
+ to submit and control printers and jobs.</P>
+<H3><A NAME="3_9_1">3.9.1 accept</A></H3>
+<P>The accept command tells the scheduler to accept new jobs for
+ specific printers.</P>
+<H3><A NAME="3_9_2">3.9.2 cancel</A></H3>
+<P>The cancel command tells the scheduler to cancel one or more jobs
+ that are queued for printing.</P>
+<H3><A NAME="3_9_3">3.9.3 disable</A></H3>
+<P>The disable command tells the scheduler to stop printing jobs on the
+ specified printers.</P>
+<H3><A NAME="3_9_4">3.9.4 enable</A></H3>
+<P>The enable command tells the scheduler to start printing jobs on the
+ specified printers.</P>
+<H3><A NAME="3_9_5">3.9.5 lp</A></H3>
+<P>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 &quot;f&quot;,
+ &quot;H&quot;, &quot;P&quot;, &quot;S&quot;, and &quot;y&quot; options are silently ignored.</P>
+<H3><A NAME="3_9_6">3.9.6 lpadmin</A></H3>
+<P>The lpadmin command manages printer queues and classes. The Solaris
+ &quot;A&quot;, &quot;F&quot;, &quot;I&quot;, &quot;M&quot;, &quot;P&quot;, &quot;Q&quot;, &quot;S&quot;, &quot;T&quot;, &quot;U&quot;, &quot;W&quot;, &quot;f&quot;, &quot;l&quot;, &quot;m&quot;, &quot;o&quot;,
+ &quot;s&quot;, &quot;t&quot;, and &quot;u&quot; options are not supported, and new options &quot;P&quot; (PPD
+ file) and &quot;E&quot; (enable and accept) are provided to configure
+ CUPS-specific features.</P>
+<H3><A NAME="3_9_7">3.9.7 lpinfo</A></H3>
+<P>The lpinfo command lists the available PPD files or devices as
+ selected by the user.</P>
+<H3><A NAME="3_9_8">3.9.8 lpmove</A></H3>
+<P>The lpmove command moves a print job to a new destination.</P>
+<H3><A NAME="3_9_9">3.9.9 lpoptions</A></H3>
+<P>The lpoptions command manages user-defined printers and options.</P>
+<H3><A NAME="3_9_10">3.9.10 lpstat</A></H3>
+<P>The lpstat command lists printers, classes, and jobs as requested by
+ the user.</P>
+<H3><A NAME="3_9_11">3.9.11 reject</A></H3>
+<P>The reject command tells the scheduler not to accept new jobs for
+ specific printers.</P>
+<H1 TYPE="A" VALUE="1"><A NAME="4">A Glossary</A></H1>
+<H2><A NAME="4_1">A.1 Terms</A></H2>
+<DL>
+<DT>C</DT>
+<DD>A computer language.</DD>
+<DT>parallel</DT>
+<DD>Sending or receiving data more than 1 bit at a time.</DD>
+<DT>pipe</DT>
+<DD>A one-way communications channel between two programs.</DD>
+<DT>serial</DT>
+<DD>Sending or receiving data 1 bit at a time.</DD>
+<DT>socket</DT>
+<DD>A two-way network communications channel.</DD>
+</DL>
+<H2><A NAME="4_2">A.2 Acronyms</A></H2>
+<DL>
+<DT>ASCII</DT>
+<DD>American Standard Code for Information Interchange</DD>
+<DT>CUPS</DT>
+<DD>Common UNIX Printing System</DD>
+<DT>ESC/P</DT>
+<DD>EPSON Standard Code for Printers</DD>
+<DT>FTP</DT>
+<DD>File Transfer Protocol</DD>
+<DT>HP-GL</DT>
+<DD>Hewlett-Packard Graphics Language</DD>
+<DT>HP-PCL</DT>
+<DD>Hewlett-Packard Page Control Language</DD>
+<DT>HP-PJL</DT>
+<DD>Hewlett-Packard Printer Job Language</DD>
+<DT>IETF</DT>
+<DD>Internet Engineering Task Force</DD>
+<DT>IPP</DT>
+<DD>Internet Printing Protocol</DD>
+<DT>ISO</DT>
+<DD>International Standards Organization</DD>
+<DT>LPD</DT>
+<DD>Line Printer Daemon</DD>
+<DT>MIME</DT>
+<DD>Multimedia Internet Mail Exchange</DD>
+<DT>PPD</DT>
+<DD>PostScript Printer Description</DD>
+<DT>SMB</DT>
+<DD>Server Message Block</DD>
+<DT>TFTP</DT>
+<DD>Trivial File Transfer Protocol</DD>
+</DL>
+</BODY>
+</HTML>
diff --git a/doc/sdd.pdf b/doc/sdd.pdf
new file mode 100644
index 000000000..2b86a22c8
--- /dev/null
+++ b/doc/sdd.pdf
Binary files differ
diff --git a/doc/sdd.shtml b/doc/sdd.shtml
new file mode 100644
index 000000000..e14ef4c0f
--- /dev/null
+++ b/doc/sdd.shtml
@@ -0,0 +1,564 @@
+<HTML>
+<HEAD>
+ <META NAME="COPYRIGHT" CONTENT="Copyright 1997-2002, All Rights Reserved">
+ <META NAME="DOCNUMBER" CONTENT="CUPS-SDD-1.1">
+ <META NAME="Author" CONTENT="Easy Software Products">
+ <TITLE>CUPS Software Design Description</TITLE>
+</HEAD>
+<BODY>
+
+<H1>Scope</H1>
+
+<H2>Identification</H2>
+
+This software design description document provides general information
+on the architecture and coding of the Common UNIX Printing System
+(&quot;CUPS&quot;) Version 1.1.
+
+<EMBED SRC="system-overview.shtml">
+
+<H2>Document Overview</H2>
+
+This software design description document is organized into the
+following sections:
+
+<UL>
+
+ <LI>1 - Scope
+
+ <LI>2 - References
+
+ <LI>3 - Design Overview
+
+ <LI>A - Glossary
+
+</UL>
+
+<EMBED SRC="references.shtml">
+
+<H1>Design Overview</H1>
+
+CUPS is composed of 9 software sub-systems that operate together to
+perform common printing tasks:
+
+<UL>
+
+ <LI>Backends
+
+ <LI>Berkeley Commands
+
+ <LI>CGI
+
+ <LI>CUPS Application Programmers Interface
+
+ <LI>CUPS Imaging Library
+
+ <LI>Daemons
+
+ <LI>Filters
+
+ <LI>Scheduler
+
+ <LI>System V Commands
+
+</UL>
+
+<H2>Backends</H2>
+
+The backends implement communications over a number of different interfaces.
+All backends are called with a common set of arguments:
+
+<UL>
+
+ <LI>Device URI - the Uniform Resource Identifier for the output device
+ (e.g. <CODE>parallel:/dev/plp</CODE>,
+ <CODE>ipp://hostname/resource</CODE>).
+
+ <LI>Job Identifier - the job identifier for this job (integer).
+
+ <LI>User Name - the user associated with this job (name string).
+
+ <LI>Title - the title/job-name associated with this job (name string).
+
+ <LI>Copies - the number of copies required (integer).
+
+ <LI>Options - the options associated with this job (space separated
+ option strings).
+
+ <LI>Filename (optional) - the file to print; if this option is not
+ specified, the backend must read the print file from the standard
+ input.
+
+</UL>
+
+<P>Backends are named using the scheme of the URI, so a URI of
+"ipp://hostname/resource" would be processed by the "ipp" backend.
+
+<H3>ipp</H3>
+
+<P>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
+<CODE>printer-uri-supported</CODE> attribute from the printer or host.
+
+<H3>lpd</H3>
+
+<P>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:
+
+<UL><PRE>lpd://hostname/queue
+</PRE></UL>
+
+<H3>parallel</H3>
+
+<P>The parallel backend sends the specified job to a local printer connected
+via the specified parallel port device. The URI is of the form:
+
+<UL><PRE>parallel:/dev/file
+</PRE></UL>
+
+<H3>serial</H3>
+
+<P>The serial backend sends the specified job to a local printer connected
+via the specified serial port device. The URI is of the form:
+
+<UL><PRE>serial:/dev/file?option[+option+...]
+</PRE></UL>
+
+The options can be any combination of the following:
+
+<UL>
+
+ <LI><CODE>baud=<I>rate</I></CODE> - Sets the baud rate for the device.
+
+ <LI><CODE>bits=<I>7 or 8</I></CODE> - Sets the number of data bits.
+
+ <LI><CODE>parity=<I>even</I></CODE> - Sets even parity checking.
+
+ <LI><CODE>parity=<I>odd</I></CODE> - Sets odd parity checking.
+
+ <LI><CODE>parity=<I>none</I></CODE> - Turns parity checking off.
+
+ <LI><CODE>flow=dtrdsr<I></I></CODE> - Turns DTR/DSR (hardware) flow
+ control on.
+
+ <LI><CODE>flow=hard<I></I></CODE> - Turns RTS/CTS
+ (hardware) flow control on.
+
+ <LI><CODE>flow=none<I></I></CODE> - Turns flow control off.
+
+ <LI><CODE>flow=rtscts<I></I></CODE> - Turns RTS/CTS
+ (hardware) flow control on.
+
+ <LI><CODE>flow=xonxoff<I></I></CODE> - Turns XON/XOFF
+ (software) flow control on.
+
+</UL>
+
+<H3>socket</H3>
+
+<P>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:
+
+<UL><PRE>socket://hostname[:port]
+</PRE></UL>
+
+The default port number is 9100.
+
+<H3>usb</H3>
+
+<P>The usb backend sends the specified job to a local printer connected
+via the specified usb port device. The URI is of the form:
+
+<UL><PRE>usb:/dev/file
+</PRE></UL>
+
+<H2>Berkeley Commands</H2>
+
+<P>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 hardcoded to use the Berkeley commands.
+
+<H3>lpc</H3>
+
+The lpc command allows users and administrators to check the status and
+control print queues. The version provided with CUPS supports the following
+commands:
+
+<UL>
+
+ <LI>quit - Quits the lpc command.
+
+ <LI>status - Shows the status of printers and jobs in the queue.
+
+</UL>
+
+<H3>lpq</H3>
+
+<P>The lpq command shows the current queue status.
+
+<H3>lpr</H3>
+
+<P>The lpr command submits a job for printing. The CUPS version of lpr silently
+ignores the "i", "t", "m", "h", and "s" options.
+
+<H3>lprm</H3>
+
+<P>The lprm removes one or more print jobs.
+
+<H2>CGI</H2>
+
+<P>The Common Gateway Interface (CGI) programs provide a web-based
+status interface to monitor the status of printers, classes, and jobs.
+Each of the CGIs utilize HTML template files that can be customized to
+provide alternate appearances.
+
+<H3>admin.cgi</H3>
+
+<P>The admin CGI provides administration interfaces for printers and
+classes. The user can add, modify, delete, start, stop, and configure
+printers and classes using "wizard" interfaces.
+
+<H3>classes.cgi</H3>
+
+<P>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.
+
+<H3>jobs.cgi</H3>
+
+<P>The jobs CGI lists the queued print jobs in order of priority. The
+list can be limited by printer or job.
+
+<H3>printers.cgi</H3>
+
+<P>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.
+
+<H2>CUPS Application Programmers Interface</H2>
+
+<P>The CUPS Application Programmers Interface ("API") provides common
+convenience, HTTP, IPP, language, and PPD functions used by the CUPS
+software.
+
+<H3>Convenience Functions</H3>
+
+<P>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.
+
+<H3>HTTP Functions</H3>
+
+<P>The HTTP functions provide functions to connect to HTTP servers,
+issue requests, read data from a server, and write data to a server.
+
+<H3>IPP Functions</H3>
+
+<P>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.
+
+<H3>Language Functions</H3>
+
+<P>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, UTF-8, ISO-8859-1, etc.)
+
+<H3>PPD Functions</H3>
+
+<P>The PostScript Printer Description functions manage PPD files,
+select options, check for option conflicts, and emit selected options
+in the correct order.
+
+<H2>CUPS Imaging Library</H2>
+
+<P>The CUPS imaging library provides colorspace conversion, color
+management, image management, scaling, image file, and raster functions
+used by the CUPS raster filters.
+
+<H3>Colorspace Conversion Functions</H3>
+
+<P>The colorspace conversion functions handle conversion of grayscale
+and RGB colors to grayscale, RGB, K, CMY, CMYK, and CMYKcm colorspaces.
+
+<H3>Color Management Functions</H3>
+
+<P>The color management functions handle gamut mapping and density
+correction. These are integrated with the colorspace conversion
+functions so that colorspace conversion and color management are
+processed in a single step.
+
+<H3>Image Management Functions</H3>
+
+<P>The image management functions manage a tiled image database that is
+swapped to/from disk as needed.
+
+<H3>Scaling Functions</H3>
+
+<P>The scaling functions provide image scaling services using
+nearest-neighbor sampling and bilinear interpolation as appropriate.
+
+<H3>Image File Functions</H3>
+
+<P>The image file functions handle loading of all image file formats.
+
+<H3>Raster Functions</H3>
+
+<P>The raster functions manage streams of CUPS raster data (described
+in the Interface Design Document) used by non-PostScript printer
+drivers and raster filters.
+
+<H2>Daemons</H2>
+
+<P>The daemons provide additional network functions for the scheduler.
+Currently only two daemons are provided with CUPS.
+
+<H3>Line Printer Daemon</H3>
+
+<P>The line printer daemon provides remote LPD client support and is
+run by the <CODE>inetd(8)</CODE> daemon as needed.
+
+<H3>Polling Daemon</H3>
+
+<P>The polling daemon is used to poll a remote server for a list of
+available printers and provide it to the scheduler for addition. A
+separate polling daemon is run by the scheduler for every remote
+system listed for polling in the scheduler configuration file.
+
+<H2>Filters</H2>
+
+<P>The filters implement file conversion services for CUPS. All filters
+are called with a common set of arguments:
+
+<UL>
+
+ <LI>Printer name - the name of the destination printer (name string).
+
+ <LI>Job Identifier - the job identifier for this job (integer).
+
+ <LI>User Name - the user associated with this job (name string).
+
+ <LI>Title - the title/job-name associated with this job (name string).
+
+ <LI>Copies - the number of copies required (integer).
+
+ <LI>Options - the options associated with this job (space separated
+ option strings).
+
+ <LI>Filename (optional) - the file to print; if this option is not
+ specified, the filter must read the input file from the standard
+ input.
+
+</UL>
+
+<P>Filters are added to the MIME conversion data file and implement all
+necessary conversions from one file type to another.
+
+<H3>hpgltops</H3>
+
+<P>The hpgltops filter converts HP-GL/2 files into PostScript.
+
+<H3>imagetops</H3>
+
+<P>The imagetops filter converts image files into PostScript.
+
+<H3>imagetoraster</H3>
+
+<P>The imagetoraster filter converts image files into CUPS raster data.
+
+<H3>pdftops</H3>
+
+<P>The pdftops filter converts PDF files into PostScript.
+
+<H3>pstops</H3>
+
+<P>The pstops filter inserts printer-specific commands from PPD files and
+performs page filtering as requested by the user.
+
+<H3>pstoraster</H3>
+
+<P>The pstoraster filter converts PostScript program data into CUPS
+raster data.
+
+<H3>rastertoepson</H3>
+
+<P>The rastertoepson filter handles converting CUPS raster data to
+ESC/P and supports both color and black-and-white printers.
+
+<H3>rastertohp</H3>
+
+<P>The rastertohp filter handles converting CUPS raster data to HP-PCL
+and supports both color and black-and-white printers.
+
+<H3>texttops</H3>
+
+<P>The texttops filter converts text files into PostScript.
+
+<H2>Scheduler</H2>
+
+<P>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.
+
+<H3>Authorization</H3>
+
+<P>The authorization module is responsible for performing access
+control and authentication for all HTTP and IPP requests entering the
+system.
+
+<H3>Classes</H3>
+
+<P>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.
+
+<H3>Client</H3>
+
+<P>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
+and administration.
+
+<P>Once authorized, all IPP requests are sent to the IPP module.
+
+<H3>Configuration</H3>
+
+<P>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.
+
+<H3>Devices</H3>
+
+<P>The devices module is responsible for managing the list of available
+devices for the CUPS-Get-Devices operation.
+
+<H3>Directory Services</H3>
+
+<P>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.
+
+<P>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.
+
+<H3>IPP</H3>
+
+<P>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.
+
+<H3>Jobs</H3>
+
+<P>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.
+
+<H3>Logging</H3>
+
+<P>The logging module manages the access, error, and page log files
+that are generated by the scheduler.
+
+<H3>Main</H3>
+
+<P>The main module is responsible for timing out and dispatching input
+and output for client connections. It also watches for incoming
+<CODE>SIGHUP</CODE> and <CODE>SIGCHLD</CODE> signals, reloads the
+server configuration files as needed, and handles child process errors
+and exits.
+
+<H3>MIME</H3>
+
+<P>The Multimedia Internet Mail Exchange module manages 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.
+
+<H3>PPDs</H3>
+
+<P>The PPDs module is responsible for managing the list of available
+PPD files for the CUPS-Get-PPDs operation.
+
+<H3>Printers</H3>
+
+<P>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.
+
+<H2>System V Commands</H2>
+
+<P>The System V commands provide a robust command-line interface to
+CUPS to submit and control printers and jobs.
+
+<H3>accept</H3>
+
+<P>The accept command tells the scheduler to accept new jobs for specific
+printers.
+
+<H3>cancel</H3>
+
+<P>The cancel command tells the scheduler to cancel one or more jobs that are
+queued for printing.
+
+<H3>disable</H3>
+
+<P>The disable command tells the scheduler to stop printing jobs on the
+specified printers.
+
+<H3>enable</H3>
+
+<P>The enable command tells the scheduler to start printing jobs on the
+specified printers.
+
+<H3>lp</H3>
+
+<P>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.
+
+<H3>lpadmin</H3>
+
+<P>The lpadmin command manages printer queues and classes. The Solaris
+"A", "F", "I", "M", "P", "Q", "S", "T", "U", "W", "f", "l", "m", "o",
+"s", "t", and "u" options are not supported, and new options "P" (PPD
+file) and "E" (enable and accept) are provided to configure
+CUPS-specific features.
+
+<H3>lpinfo</H3>
+
+<P>The lpinfo command lists the available PPD files or devices as selected
+by the user.
+
+<H3>lpmove</H3>
+
+<P>The lpmove command moves a print job to a new destination.
+
+<H3>lpoptions</H3>
+
+<P>The lpoptions command manages user-defined printers and options.
+
+<H3>lpstat</H3>
+
+<P>The lpstat command lists printers, classes, and jobs as requested by the
+user.
+
+<H3>reject</H3>
+
+<P>The reject command tells the scheduler not to accept new jobs for specific
+printers.
+
+<EMBED SRC="glossary.shtml">
+
+</BODY>
+</HTML>
diff --git a/doc/spm.html b/doc/spm.html
new file mode 100644
index 000000000..bf54d2859
--- /dev/null
+++ b/doc/spm.html
@@ -0,0 +1,7639 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD>
+<TITLE>CUPS Software Programmers Manual</TITLE>
+<META NAME="author" CONTENT="Easy Software Products">
+<META NAME="copyright" CONTENT="Copyright 1997-2002, All Rights Reserved">
+<META NAME="docnumber" CONTENT="CUPS-SPM-1.1.13">
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=iso-8859-1">
+<STYLE TYPE="text/css"><!--
+BODY { font-family: serif }
+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 }
+SUB { font-size: smaller }
+SUP { font-size: smaller }
+PRE { font-family: monospace }
+--></STYLE>
+</HEAD>
+<BODY BGCOLOR="#ffffff">
+<CENTER><A HREF="#CONTENTS"><IMG SRC="images/cups-large.gif" BORDER="0" WIDTH="431" HEIGHT="511"><BR>
+<H1>CUPS Software Programmers Manual</H1></A><BR>
+CUPS-SPM-1.1.13<BR>
+Easy Software Products<BR>
+Copyright 1997-2002, All Rights Reserved<BR>
+</CENTER>
+<HR>
+<H1 ALIGN="CENTER"><A NAME="CONTENTS">Table of Contents</A></H1>
+<BR>
+<BR><B><A HREF="#1">Preface</A></B>
+<UL>
+<LI><A HREF="#1_1">System Overview</A></LI>
+<LI><A HREF="#1_2">Document Overview</A></LI>
+<LI><A HREF="#1_3">Notation Conventions</A></LI>
+<LI><A HREF="#1_4">Abbreviations</A></LI>
+<LI><A HREF="#1_5">Other References</A></LI>
+</UL>
+<B><A HREF="#OVERVIEW">1 - Printing System Overview</A></B>
+<UL>
+<LI><A HREF="#2_1">The Printing Problem</A></LI>
+<LI><A HREF="#2_2">The Technology</A></LI>
+<LI><A HREF="#2_3">Jobs</A></LI>
+<LI><A HREF="#2_4">Classes</A></LI>
+<LI><A HREF="#2_5">Filters</A></LI>
+<LI><A HREF="#2_6">Backends</A></LI>
+<LI><A HREF="#2_7">Printer Drivers</A></LI>
+<LI><A HREF="#2_8">Networking</A></LI>
+</UL>
+<B><A HREF="#CUPS_API">2 - The CUPS API</A></B>
+<UL>
+<LI><A HREF="#3_1">The CUPS API Library</A></LI>
+<UL>
+<LI><A HREF="#3_1_1">Detecting the CUPS API Library in GNU Autoconf</A></LI>
+</UL>
+<LI><A HREF="#3_2">Printing Services</A></LI>
+<UL>
+<LI><A HREF="#3_2_1">Include Files</A></LI>
+<LI><A HREF="#3_2_2">Printing a File</A></LI>
+<LI><A HREF="#3_2_3">Printing Multiple Files</A></LI>
+<LI><A HREF="#3_2_4">Cancelling Jobs</A></LI>
+<LI><A HREF="#3_2_5">Getting the Available Printers and Classes</A></LI>
+<LI><A HREF="#3_2_6">Printing with Options</A></LI>
+<LI><A HREF="#3_2_7">Setting Printer Options</A></LI>
+<LI><A HREF="#3_2_8">Getting Errors</A></LI>
+<LI><A HREF="#3_2_9">Passwords and Authentication</A></LI>
+</UL>
+<LI><A HREF="#3_3">PPD Services</A></LI>
+<UL>
+<LI><A HREF="#3_3_1">Include Files</A></LI>
+<LI><A HREF="#3_3_2">Getting a PPD File for a Printer</A></LI>
+<LI><A HREF="#3_3_3">Loading a PPD File</A></LI>
+<LI><A HREF="#3_3_4">Freeing PPD File Information</A></LI>
+<LI><A HREF="#3_3_5">The PPD File Structure</A></LI>
+<LI><A HREF="#3_3_6">Marking Options</A></LI>
+<LI><A HREF="#3_3_7">Checking for Conflicts</A></LI>
+</UL>
+</UL>
+<B><A HREF="#WRITING_FILTERS">3 - Writing Filters</A></B>
+<UL>
+<LI><A HREF="#4_1">Overview</A></LI>
+<UL>
+<LI><A HREF="#4_1_1">Security Considerations</A></LI>
+<LI><A HREF="#4_1_2">Users and Groups</A></LI>
+<LI><A HREF="#4_1_3">Temporary Files</A></LI>
+<LI><A HREF="#4_1_4">Sending Messages to the User</A></LI>
+<LI><A HREF="#4_1_5">Page Accounting</A></LI>
+<LI><A HREF="#4_1_6">Command-Line Arguments</A></LI>
+<LI><A HREF="#4_1_7">Copy Generation</A></LI>
+<LI><A HREF="#4_1_8">Environment Variables</A></LI>
+</UL>
+<LI><A HREF="#4_2">Dissecting the HP-GL/2 Filter</A></LI>
+<UL>
+<LI><A HREF="#4_2_1">Initializing the Filter</A></LI>
+</UL>
+<LI><A HREF="#4_3">PostScript Output</A></LI>
+</UL>
+<B><A HREF="#WRITING_DRIVERS">4 - Writing Printer Drivers</A></B>
+<UL>
+<LI><A HREF="#5_1">Overview</A></LI>
+<UL>
+<LI><A HREF="#5_1_1">CUPS Raster Data</A></LI>
+<LI><A HREF="#5_1_2">Page Accounting</A></LI>
+<LI><A HREF="#5_1_3">Color Management</A></LI>
+<LI><A HREF="#5_1_4">Device and Bitmap Variables</A></LI>
+</UL>
+<LI><A HREF="#5_2">Dissecting the HP-PCL Driver</A></LI>
+<UL>
+<LI><A HREF="#5_2_1">PPD Files</A></LI>
+<LI><A HREF="#5_2_2">Reading Raster Data</A></LI>
+</UL>
+</UL>
+<B><A HREF="#WRITING_BACKENDS">5 - Writing Backends</A></B>
+<UL>
+<LI><A HREF="#6_1">Overview</A></LI>
+<UL>
+<LI><A HREF="#6_1_1">Security Considerations</A></LI>
+<LI><A HREF="#6_1_2">Command-Line Arguments</A></LI>
+<LI><A HREF="#6_1_3">Copy Generation</A></LI>
+<LI><A HREF="#6_1_4">Page Accounting</A></LI>
+<LI><A HREF="#6_1_5">Exclusive Access</A></LI>
+<LI><A HREF="#6_1_6">Retries</A></LI>
+</UL>
+<LI><A HREF="#6_2">Dissecting the Serial Port Backend</A></LI>
+<UL>
+<LI><A HREF="#6_2_1">Supporting Device Discovery</A></LI>
+<LI><A HREF="#6_2_2">Opening the Serial Port</A></LI>
+<LI><A HREF="#6_2_3">Writing Data to the Port</A></LI>
+<LI><A HREF="#6_2_4">Finishing Up</A></LI>
+</UL>
+</UL>
+<B><A HREF="#LICENSE">A - Software License Agreement</A></B>
+<UL>
+<LI><A HREF="#7_1">Common UNIX Printing System License Agreement</A></LI>
+<UL>
+<LI><A HREF="#7_1_1">Introduction</A></LI>
+<LI><A HREF="#7_1_2">Trademarks</A></LI>
+<LI><A HREF="#7_1_3">Binary Distribution Rights</A></LI>
+<LI><A HREF="#7_1_4">Support</A></LI>
+</UL>
+<LI><A HREF="#7_2">GNU GENERAL PUBLIC LICENSE</A></LI>
+<LI><A HREF="#7_3">GNU LIBRARY GENERAL PUBLIC LICENSE</A></LI>
+</UL>
+<B><A HREF="#CONSTANTS">B - Constants</A></B>
+<UL>
+<LI><A HREF="#8_1">CUPS Constants</A></LI>
+<UL>
+<LI><A HREF="#8_1_1">Version Number</A></LI>
+<LI><A HREF="#8_1_2">Printer Capabilities</A></LI>
+<LI><A HREF="#8_1_3">Encodings</A></LI>
+</UL>
+<LI><A HREF="#8_2">HTTP Constants</A></LI>
+<UL>
+<LI><A HREF="#8_2_1">Limits</A></LI>
+<LI><A HREF="#8_2_2">Status Codes</A></LI>
+<LI><A HREF="#8_2_3">Fields</A></LI>
+</UL>
+<LI><A HREF="#8_3">IPP Constants</A></LI>
+<UL>
+<LI><A HREF="#8_3_1">Limits</A></LI>
+<LI><A HREF="#8_3_2">Tags</A></LI>
+<LI><A HREF="#8_3_3">Resolution Units</A></LI>
+<LI><A HREF="#8_3_4">Finishings</A></LI>
+<LI><A HREF="#8_3_5">Orientations</A></LI>
+<LI><A HREF="#8_3_6">Qualities</A></LI>
+<LI><A HREF="#8_3_7">Job States</A></LI>
+<LI><A HREF="#8_3_8">Printer States</A></LI>
+<LI><A HREF="#8_3_9">Operations</A></LI>
+<LI><A HREF="#8_3_10">Status Codes</A></LI>
+</UL>
+<LI><A HREF="#8_4">PPD Constants</A></LI>
+<UL>
+<LI><A HREF="#8_4_1">PPD Format Version</A></LI>
+<LI><A HREF="#8_4_2">PPD User-Interface Types</A></LI>
+<LI><A HREF="#8_4_3">PPD Sections</A></LI>
+<LI><A HREF="#8_4_4">PPD Colorspaces</A></LI>
+</UL>
+<LI><A HREF="#8_5">Raster Constants</A></LI>
+<UL>
+<LI><A HREF="#8_5_1">Raster Sync Words</A></LI>
+<LI><A HREF="#8_5_2">Raster Stream Modes</A></LI>
+<LI><A HREF="#8_5_3">Raster Boolean Constants</A></LI>
+<LI><A HREF="#8_5_4">Raster Jog Values</A></LI>
+<LI><A HREF="#8_5_5">Raster Orientation Values</A></LI>
+<LI><A HREF="#8_5_6">Raster CutMedia Values</A></LI>
+<LI><A HREF="#8_5_7">Raster AdvanceMedia Values</A></LI>
+<LI><A HREF="#8_5_8">Raster LeadingEdge Values</A></LI>
+<LI><A HREF="#8_5_9">Raster Color Order Values</A></LI>
+<LI><A HREF="#8_5_10">Raster Colorspace Values</A></LI>
+</UL>
+</UL>
+<B><A HREF="#STRUCTURES">C - Structures</A></B>
+<UL>
+<LI><A HREF="#9_1">CUPS Structures</A></LI>
+<UL>
+<LI><A HREF="#cups_dest_t">CUPS Destinations</A></LI>
+<LI><A HREF="#cups_job_t">CUPS Jobs</A></LI>
+<LI><A HREF="#cups_lang_t">CUPS Messages</A></LI>
+<LI><A HREF="#cups_option_t">CUPS Options</A></LI>
+</UL>
+<LI><A HREF="#9_2">Networking Structures</A></LI>
+<UL>
+<LI><A HREF="#http_t">HTTP State</A></LI>
+<LI><A HREF="#ipp_t">IPP State</A></LI>
+</UL>
+<LI><A HREF="#9_3">Raster Structures</A></LI>
+<UL>
+<LI><A HREF="#cups_raster_header_t">Raster Page Header</A></LI>
+</UL>
+</UL>
+<B><A HREF="#FUNCTIONS">D - Functions</A></B>
+<UL>
+<LI><A HREF="#cupsAddOption">cupsAddOption()</A></LI>
+<UL>
+<LI><A HREF="#10_1_1">Usage</A></LI>
+<LI><A HREF="#10_1_2">Arguments</A></LI>
+<LI><A HREF="#10_1_3">Returns</A></LI>
+<LI><A HREF="#10_1_4">Description</A></LI>
+<LI><A HREF="#10_1_5">Example</A></LI>
+<LI><A HREF="#10_1_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#cupsCancelJob">cupsCancelJob()</A></LI>
+<UL>
+<LI><A HREF="#10_2_1">Usage</A></LI>
+<LI><A HREF="#10_2_2">Arguments</A></LI>
+<LI><A HREF="#10_2_3">Returns</A></LI>
+<LI><A HREF="#10_2_4">Description</A></LI>
+<LI><A HREF="#10_2_5">Example</A></LI>
+<LI><A HREF="#10_2_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#cupsDoFileRequest">cupsDoFileRequest()</A></LI>
+<UL>
+<LI><A HREF="#10_3_1">Usage</A></LI>
+<LI><A HREF="#10_3_2">Arguments</A></LI>
+<LI><A HREF="#10_3_3">Returns</A></LI>
+<LI><A HREF="#10_3_4">Description</A></LI>
+<LI><A HREF="#10_3_5">Example</A></LI>
+<LI><A HREF="#10_3_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#cupsDoRequest">cupsDoRequest()</A></LI>
+<UL>
+<LI><A HREF="#10_4_1">Usage</A></LI>
+<LI><A HREF="#10_4_2">Arguments</A></LI>
+<LI><A HREF="#10_4_3">Returns</A></LI>
+<LI><A HREF="#10_4_4">Description</A></LI>
+<LI><A HREF="#10_4_5">Example</A></LI>
+<LI><A HREF="#10_4_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#cupsFreeOptions">cupsFreeOptions()</A></LI>
+<UL>
+<LI><A HREF="#10_5_1">Usage</A></LI>
+<LI><A HREF="#10_5_2">Arguments</A></LI>
+<LI><A HREF="#10_5_3">Description</A></LI>
+<LI><A HREF="#10_5_4">Example</A></LI>
+<LI><A HREF="#10_5_5">See Also</A></LI>
+</UL>
+<LI><A HREF="#cupsGetClasses">cupsGetClasses()</A></LI>
+<UL>
+<LI><A HREF="#10_6_1">Usage</A></LI>
+<LI><A HREF="#10_6_2">Arguments</A></LI>
+<LI><A HREF="#10_6_3">Returns</A></LI>
+<LI><A HREF="#10_6_4">Description</A></LI>
+<LI><A HREF="#10_6_5">Example</A></LI>
+<LI><A HREF="#10_6_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#cupsGetDefault">cupsGetDefault()</A></LI>
+<UL>
+<LI><A HREF="#10_7_1">Usage</A></LI>
+<LI><A HREF="#10_7_2">Returns</A></LI>
+<LI><A HREF="#10_7_3">Description</A></LI>
+<LI><A HREF="#10_7_4">Example</A></LI>
+<LI><A HREF="#10_7_5">See Also</A></LI>
+</UL>
+<LI><A HREF="#cupsGetOption">cupsGetOption()</A></LI>
+<UL>
+<LI><A HREF="#10_8_1">Usage</A></LI>
+<LI><A HREF="#10_8_2">Arguments</A></LI>
+<LI><A HREF="#10_8_3">Returns</A></LI>
+<LI><A HREF="#10_8_4">Description</A></LI>
+<LI><A HREF="#10_8_5">See Also</A></LI>
+</UL>
+<LI><A HREF="#cupsGetPassword">cupsGetPassword()</A></LI>
+<UL>
+<LI><A HREF="#10_9_1">Usage</A></LI>
+<LI><A HREF="#10_9_2">Arguments</A></LI>
+<LI><A HREF="#10_9_3">Returns</A></LI>
+<LI><A HREF="#10_9_4">Description</A></LI>
+<LI><A HREF="#10_9_5">Example</A></LI>
+<LI><A HREF="#10_9_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#cupsGetPPD">cupsGetPPD()</A></LI>
+<UL>
+<LI><A HREF="#10_10_1">Usage</A></LI>
+<LI><A HREF="#10_10_2">Arguments</A></LI>
+<LI><A HREF="#10_10_3">Returns</A></LI>
+<LI><A HREF="#10_10_4">Description</A></LI>
+<LI><A HREF="#10_10_5">Example</A></LI>
+</UL>
+<LI><A HREF="#cupsGetPrinters">cupsGetPrinters()</A></LI>
+<UL>
+<LI><A HREF="#10_11_1">Usage</A></LI>
+<LI><A HREF="#10_11_2">Arguments</A></LI>
+<LI><A HREF="#10_11_3">Returns</A></LI>
+<LI><A HREF="#10_11_4">Description</A></LI>
+<LI><A HREF="#10_11_5">Example</A></LI>
+<LI><A HREF="#10_11_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#cupsLangDefault">cupsLangDefault()</A></LI>
+<UL>
+<LI><A HREF="#10_12_1">Usage</A></LI>
+<LI><A HREF="#10_12_2">Returns</A></LI>
+<LI><A HREF="#10_12_3">Description</A></LI>
+<LI><A HREF="#10_12_4">Example</A></LI>
+<LI><A HREF="#10_12_5">See Also</A></LI>
+</UL>
+<LI><A HREF="#cupsLangEncoding">cupsLangEncoding()</A></LI>
+<UL>
+<LI><A HREF="#10_13_1">Usage</A></LI>
+<LI><A HREF="#10_13_2">Arguments</A></LI>
+<LI><A HREF="#10_13_3">Returns</A></LI>
+<LI><A HREF="#10_13_4">Description</A></LI>
+<LI><A HREF="#10_13_5">Example</A></LI>
+<LI><A HREF="#10_13_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#cupsLangFlush">cupsLangFlush()</A></LI>
+<UL>
+<LI><A HREF="#10_14_1">Usage</A></LI>
+<LI><A HREF="#10_14_2">Description</A></LI>
+<LI><A HREF="#10_14_3">Example</A></LI>
+<LI><A HREF="#10_14_4">See Also</A></LI>
+</UL>
+<LI><A HREF="#cupsLangFree">cupsLangFree()</A></LI>
+<UL>
+<LI><A HREF="#10_15_1">Usage</A></LI>
+<LI><A HREF="#10_15_2">Arguments</A></LI>
+<LI><A HREF="#10_15_3">Description</A></LI>
+<LI><A HREF="#10_15_4">Example</A></LI>
+<LI><A HREF="#10_15_5">See Also</A></LI>
+</UL>
+<LI><A HREF="#cupsLangGet">cupsLangGet()</A></LI>
+<UL>
+<LI><A HREF="#10_16_1">Usage</A></LI>
+<LI><A HREF="#10_16_2">Arguments</A></LI>
+<LI><A HREF="#10_16_3">Returns</A></LI>
+<LI><A HREF="#10_16_4">Description</A></LI>
+<LI><A HREF="#10_16_5">Example</A></LI>
+<LI><A HREF="#10_16_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#cupsLangString">cupsLangString()</A></LI>
+<UL>
+<LI><A HREF="#10_17_1">Usage</A></LI>
+<LI><A HREF="#10_17_2">Arguments</A></LI>
+<LI><A HREF="#10_17_3">Returns</A></LI>
+<LI><A HREF="#10_17_4">Description</A></LI>
+<LI><A HREF="#10_17_5">Example</A></LI>
+<LI><A HREF="#10_17_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#cupsLastError">cupsLastError()</A></LI>
+<UL>
+<LI><A HREF="#10_18_1">Usage</A></LI>
+<LI><A HREF="#10_18_2">Returns</A></LI>
+<LI><A HREF="#10_18_3">Description</A></LI>
+<LI><A HREF="#10_18_4">Example</A></LI>
+<LI><A HREF="#10_18_5">See Also</A></LI>
+</UL>
+<LI><A HREF="#cupsMarkOptions">cupsMarkOptions()</A></LI>
+<UL>
+<LI><A HREF="#10_19_1">Usage</A></LI>
+<LI><A HREF="#10_19_2">Arguments</A></LI>
+<LI><A HREF="#10_19_3">Returns</A></LI>
+<LI><A HREF="#10_19_4">Description</A></LI>
+<LI><A HREF="#10_19_5">Example</A></LI>
+<LI><A HREF="#10_19_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#cupsParseOptions">cupsParseOptions()</A></LI>
+<UL>
+<LI><A HREF="#10_20_1">Usage</A></LI>
+<LI><A HREF="#10_20_2">Arguments</A></LI>
+<LI><A HREF="#10_20_3">Returns</A></LI>
+<LI><A HREF="#10_20_4">Description</A></LI>
+<LI><A HREF="#10_20_5">Example</A></LI>
+<LI><A HREF="#10_20_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#cupsPrintFile">cupsPrintFile()</A></LI>
+<UL>
+<LI><A HREF="#10_21_1">Usage</A></LI>
+<LI><A HREF="#10_21_2">Arguments</A></LI>
+<LI><A HREF="#10_21_3">Returns</A></LI>
+<LI><A HREF="#10_21_4">Description</A></LI>
+<LI><A HREF="#10_21_5">Example</A></LI>
+<LI><A HREF="#10_21_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#cupsPrintFiles">cupsPrintFiles()</A></LI>
+<UL>
+<LI><A HREF="#10_22_1">Usage</A></LI>
+<LI><A HREF="#10_22_2">Arguments</A></LI>
+<LI><A HREF="#10_22_3">Returns</A></LI>
+<LI><A HREF="#10_22_4">Description</A></LI>
+<LI><A HREF="#10_22_5">Example</A></LI>
+<LI><A HREF="#10_22_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#cupsRasterClose">cupsRasterClose()</A></LI>
+<UL>
+<LI><A HREF="#10_23_1">Usage</A></LI>
+<LI><A HREF="#10_23_2">Arguments</A></LI>
+<LI><A HREF="#10_23_3">Description</A></LI>
+<LI><A HREF="#10_23_4">Example</A></LI>
+<LI><A HREF="#10_23_5">See Also</A></LI>
+</UL>
+<LI><A HREF="#cupsRasterOpen">cupsRasterOpen()</A></LI>
+<UL>
+<LI><A HREF="#10_24_1">Usage</A></LI>
+<LI><A HREF="#10_24_2">Arguments</A></LI>
+<LI><A HREF="#10_24_3">Returns</A></LI>
+<LI><A HREF="#10_24_4">Description</A></LI>
+<LI><A HREF="#10_24_5">Example</A></LI>
+<LI><A HREF="#10_24_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#cupsRasterReadHeader">cupsRasterReadHeader()</A></LI>
+<UL>
+<LI><A HREF="#10_25_1">Usage</A></LI>
+<LI><A HREF="#10_25_2">Arguments</A></LI>
+<LI><A HREF="#10_25_3">Returns</A></LI>
+<LI><A HREF="#10_25_4">Description</A></LI>
+<LI><A HREF="#10_25_5">Example</A></LI>
+<LI><A HREF="#10_25_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#cupsRasterReadPixels">cupsRasterReadPixels()</A></LI>
+<UL>
+<LI><A HREF="#10_26_1">Usage</A></LI>
+<LI><A HREF="#10_26_2">Arguments</A></LI>
+<LI><A HREF="#10_26_3">Returns</A></LI>
+<LI><A HREF="#10_26_4">Description</A></LI>
+<LI><A HREF="#10_26_5">Example</A></LI>
+<LI><A HREF="#10_26_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#cupsRasterWriteHeader">cupsRasterWriteHeader()</A></LI>
+<UL>
+<LI><A HREF="#10_27_1">Usage</A></LI>
+<LI><A HREF="#10_27_2">Arguments</A></LI>
+<LI><A HREF="#10_27_3">Returns</A></LI>
+<LI><A HREF="#10_27_4">Description</A></LI>
+<LI><A HREF="#10_27_5">Example</A></LI>
+<LI><A HREF="#10_27_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#cupsRasterWritePixels">cupsRasterWritePixels()</A></LI>
+<UL>
+<LI><A HREF="#10_28_1">Usage</A></LI>
+<LI><A HREF="#10_28_2">Arguments</A></LI>
+<LI><A HREF="#10_28_3">Returns</A></LI>
+<LI><A HREF="#10_28_4">Description</A></LI>
+<LI><A HREF="#10_28_5">Example</A></LI>
+<LI><A HREF="#10_28_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#cupsServer">cupsServer()</A></LI>
+<UL>
+<LI><A HREF="#10_29_1">Usage</A></LI>
+<LI><A HREF="#10_29_2">Returns</A></LI>
+<LI><A HREF="#10_29_3">Description</A></LI>
+<LI><A HREF="#10_29_4">Example</A></LI>
+<LI><A HREF="#10_29_5">See Also</A></LI>
+</UL>
+<LI><A HREF="#cupsSetPasswordCB">cupsSetPasswordCB()</A></LI>
+<UL>
+<LI><A HREF="#10_30_1">Usage</A></LI>
+<LI><A HREF="#10_30_2">Arguments</A></LI>
+<LI><A HREF="#10_30_3">Description</A></LI>
+<LI><A HREF="#10_30_4">Example</A></LI>
+<LI><A HREF="#10_30_5">See Also</A></LI>
+</UL>
+<LI><A HREF="#cupsSetServer">cupsSetServer()</A></LI>
+<UL>
+<LI><A HREF="#10_31_1">Usage</A></LI>
+<LI><A HREF="#10_31_2">Arguments</A></LI>
+<LI><A HREF="#10_31_3">Description</A></LI>
+<LI><A HREF="#10_31_4">Example</A></LI>
+<LI><A HREF="#10_31_5">See Also</A></LI>
+</UL>
+<LI><A HREF="#cupsSetUser">cupsSetUser()</A></LI>
+<UL>
+<LI><A HREF="#10_32_1">Usage</A></LI>
+<LI><A HREF="#10_32_2">Arguments</A></LI>
+<LI><A HREF="#10_32_3">Description</A></LI>
+<LI><A HREF="#10_32_4">Example</A></LI>
+<LI><A HREF="#10_32_5">See Also</A></LI>
+</UL>
+<LI><A HREF="#cupsTempFile">cupsTempFile()</A></LI>
+<UL>
+<LI><A HREF="#10_33_1">Usage</A></LI>
+<LI><A HREF="#10_33_2">Arguments</A></LI>
+<LI><A HREF="#10_33_3">Returns</A></LI>
+<LI><A HREF="#10_33_4">Description</A></LI>
+<LI><A HREF="#10_33_5">Example</A></LI>
+</UL>
+<LI><A HREF="#cupsUser">cupsUser()</A></LI>
+<UL>
+<LI><A HREF="#10_34_1">Usage</A></LI>
+<LI><A HREF="#10_34_2">Returns</A></LI>
+<LI><A HREF="#10_34_3">Description</A></LI>
+<LI><A HREF="#10_34_4">Example</A></LI>
+<LI><A HREF="#10_34_5">See Also</A></LI>
+</UL>
+<LI><A HREF="#httpBlocking">httpBlocking()</A></LI>
+<UL>
+<LI><A HREF="#10_35_1">Usage</A></LI>
+<LI><A HREF="#10_35_2">Arguments</A></LI>
+<LI><A HREF="#10_35_3">Description</A></LI>
+<LI><A HREF="#10_35_4">Example</A></LI>
+<LI><A HREF="#10_35_5">See Also</A></LI>
+</UL>
+<LI><A HREF="#httpCheck">httpCheck()</A></LI>
+<UL>
+<LI><A HREF="#10_36_1">Usage</A></LI>
+<LI><A HREF="#10_36_2">Arguments</A></LI>
+<LI><A HREF="#10_36_3">Returns</A></LI>
+<LI><A HREF="#10_36_4">Description</A></LI>
+<LI><A HREF="#10_36_5">Example</A></LI>
+<LI><A HREF="#10_36_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#httpClearFields">httpClearFields()</A></LI>
+<UL>
+<LI><A HREF="#10_37_1">Usage</A></LI>
+<LI><A HREF="#10_37_2">Arguments</A></LI>
+<LI><A HREF="#10_37_3">Description</A></LI>
+<LI><A HREF="#10_37_4">Example</A></LI>
+<LI><A HREF="#10_37_5">See Also</A></LI>
+</UL>
+<LI><A HREF="#httpClose">httpClose()</A></LI>
+<UL>
+<LI><A HREF="#10_38_1">Usage</A></LI>
+<LI><A HREF="#10_38_2">Arguments</A></LI>
+<LI><A HREF="#10_38_3">Description</A></LI>
+<LI><A HREF="#10_38_4">Example</A></LI>
+<LI><A HREF="#10_38_5">See Also</A></LI>
+</UL>
+<LI><A HREF="#httpConnect">httpConnect()</A></LI>
+<UL>
+<LI><A HREF="#10_39_1">Usage</A></LI>
+<LI><A HREF="#10_39_2">Arguments</A></LI>
+<LI><A HREF="#10_39_3">Returns</A></LI>
+<LI><A HREF="#10_39_4">Description</A></LI>
+<LI><A HREF="#10_39_5">Example</A></LI>
+<LI><A HREF="#10_39_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#httpDecode64">httpDecode64()</A></LI>
+<UL>
+<LI><A HREF="#10_40_1">Usage</A></LI>
+<LI><A HREF="#10_40_2">Arguments</A></LI>
+<LI><A HREF="#10_40_3">Returns</A></LI>
+<LI><A HREF="#10_40_4">Description</A></LI>
+<LI><A HREF="#10_40_5">Example</A></LI>
+<LI><A HREF="#10_40_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#httpDelete">httpDelete()</A></LI>
+<UL>
+<LI><A HREF="#10_41_1">Usage</A></LI>
+<LI><A HREF="#10_41_2">Arguments</A></LI>
+<LI><A HREF="#10_41_3">Returns</A></LI>
+<LI><A HREF="#10_41_4">Description</A></LI>
+<LI><A HREF="#10_41_5">Example</A></LI>
+<LI><A HREF="#10_41_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#httpEncode64">httpEncode64()</A></LI>
+<UL>
+<LI><A HREF="#10_42_1">Usage</A></LI>
+<LI><A HREF="#10_42_2">Arguments</A></LI>
+<LI><A HREF="#10_42_3">Returns</A></LI>
+<LI><A HREF="#10_42_4">Description</A></LI>
+<LI><A HREF="#10_42_5">Example</A></LI>
+<LI><A HREF="#10_42_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#httpError">httpError()</A></LI>
+<UL>
+<LI><A HREF="#10_43_1">Usage</A></LI>
+<LI><A HREF="#10_43_2">Arguments</A></LI>
+<LI><A HREF="#10_43_3">Returns</A></LI>
+<LI><A HREF="#10_43_4">Description</A></LI>
+<LI><A HREF="#10_43_5">Example</A></LI>
+<LI><A HREF="#10_43_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#httpFlush">httpFlush()</A></LI>
+<UL>
+<LI><A HREF="#10_44_1">Usage</A></LI>
+<LI><A HREF="#10_44_2">Arguments</A></LI>
+<LI><A HREF="#10_44_3">Description</A></LI>
+<LI><A HREF="#10_44_4">Example</A></LI>
+<LI><A HREF="#10_44_5">See Also</A></LI>
+</UL>
+<LI><A HREF="#httpGet">httpGet()</A></LI>
+<UL>
+<LI><A HREF="#10_45_1">Usage</A></LI>
+<LI><A HREF="#10_45_2">Arguments</A></LI>
+<LI><A HREF="#10_45_3">Returns</A></LI>
+<LI><A HREF="#10_45_4">Description</A></LI>
+<LI><A HREF="#10_45_5">Example</A></LI>
+<LI><A HREF="#10_45_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#httpGets">httpGets()</A></LI>
+<UL>
+<LI><A HREF="#10_46_1">Usage</A></LI>
+<LI><A HREF="#10_46_2">Arguments</A></LI>
+<LI><A HREF="#10_46_3">Returns</A></LI>
+<LI><A HREF="#10_46_4">Description</A></LI>
+<LI><A HREF="#10_46_5">Example</A></LI>
+<LI><A HREF="#10_46_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#httpGetDateString">httpGetDateString()</A></LI>
+<UL>
+<LI><A HREF="#10_47_1">Usage</A></LI>
+<LI><A HREF="#10_47_2">Arguments</A></LI>
+<LI><A HREF="#10_47_3">Returns</A></LI>
+<LI><A HREF="#10_47_4">Description</A></LI>
+<LI><A HREF="#10_47_5">Example</A></LI>
+<LI><A HREF="#10_47_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#httpGetDateTime">httpGetDateTime()</A></LI>
+<UL>
+<LI><A HREF="#10_48_1">Usage</A></LI>
+<LI><A HREF="#10_48_2">Arguments</A></LI>
+<LI><A HREF="#10_48_3">Returns</A></LI>
+<LI><A HREF="#10_48_4">Description</A></LI>
+<LI><A HREF="#10_48_5">Example</A></LI>
+<LI><A HREF="#10_48_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#httpGetField">httpGetField()</A></LI>
+<UL>
+<LI><A HREF="#10_49_1">Usage</A></LI>
+<LI><A HREF="#10_49_2">Arguments</A></LI>
+<LI><A HREF="#10_49_3">Returns</A></LI>
+<LI><A HREF="#10_49_4">Description</A></LI>
+<LI><A HREF="#10_49_5">Example</A></LI>
+<LI><A HREF="#10_49_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#httpHead">httpHead()</A></LI>
+<UL>
+<LI><A HREF="#10_50_1">Usage</A></LI>
+<LI><A HREF="#10_50_2">Arguments</A></LI>
+<LI><A HREF="#10_50_3">Returns</A></LI>
+<LI><A HREF="#10_50_4">Description</A></LI>
+<LI><A HREF="#10_50_5">Example</A></LI>
+<LI><A HREF="#10_50_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#httpInitialize">httpInitialize()</A></LI>
+<UL>
+<LI><A HREF="#10_51_1">Usage</A></LI>
+<LI><A HREF="#10_51_2">Description</A></LI>
+<LI><A HREF="#10_51_3">Example</A></LI>
+<LI><A HREF="#10_51_4">See Also</A></LI>
+</UL>
+<LI><A HREF="#httpOptions">httpOptions()</A></LI>
+<UL>
+<LI><A HREF="#10_52_1">Usage</A></LI>
+<LI><A HREF="#10_52_2">Arguments</A></LI>
+<LI><A HREF="#10_52_3">Returns</A></LI>
+<LI><A HREF="#10_52_4">Description</A></LI>
+<LI><A HREF="#10_52_5">Example</A></LI>
+<LI><A HREF="#10_52_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#httpPost">httpPost()</A></LI>
+<UL>
+<LI><A HREF="#10_53_1">Usage</A></LI>
+<LI><A HREF="#10_53_2">Arguments</A></LI>
+<LI><A HREF="#10_53_3">Returns</A></LI>
+<LI><A HREF="#10_53_4">Description</A></LI>
+<LI><A HREF="#10_53_5">Example</A></LI>
+<LI><A HREF="#10_53_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#httpPrintf">httpPrintf()</A></LI>
+<UL>
+<LI><A HREF="#10_54_1">Usage</A></LI>
+<LI><A HREF="#10_54_2">Arguments</A></LI>
+<LI><A HREF="#10_54_3">Returns</A></LI>
+<LI><A HREF="#10_54_4">Description</A></LI>
+<LI><A HREF="#10_54_5">Example</A></LI>
+<LI><A HREF="#10_54_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#httpPut">httpPut()</A></LI>
+<UL>
+<LI><A HREF="#10_55_1">Usage</A></LI>
+<LI><A HREF="#10_55_2">Arguments</A></LI>
+<LI><A HREF="#10_55_3">Returns</A></LI>
+<LI><A HREF="#10_55_4">Description</A></LI>
+<LI><A HREF="#10_55_5">Example</A></LI>
+<LI><A HREF="#10_55_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#httpRead">httpRead()</A></LI>
+<UL>
+<LI><A HREF="#10_56_1">Usage</A></LI>
+<LI><A HREF="#10_56_2">Arguments</A></LI>
+<LI><A HREF="#10_56_3">Returns</A></LI>
+<LI><A HREF="#10_56_4">Description</A></LI>
+<LI><A HREF="#10_56_5">Example</A></LI>
+<LI><A HREF="#10_56_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#httpReconnect">httpReconnect()</A></LI>
+<UL>
+<LI><A HREF="#10_57_1">Usage</A></LI>
+<LI><A HREF="#10_57_2">Arguments</A></LI>
+<LI><A HREF="#10_57_3">Returns</A></LI>
+<LI><A HREF="#10_57_4">Description</A></LI>
+<LI><A HREF="#10_57_5">Example</A></LI>
+<LI><A HREF="#10_57_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#httpSeparate">httpSeparate()</A></LI>
+<UL>
+<LI><A HREF="#10_58_1">Usage</A></LI>
+<LI><A HREF="#10_58_2">Arguments</A></LI>
+<LI><A HREF="#10_58_3">Description</A></LI>
+<LI><A HREF="#10_58_4">Example</A></LI>
+<LI><A HREF="#10_58_5">See Also</A></LI>
+</UL>
+<LI><A HREF="#httpSetField">httpSetField()</A></LI>
+<UL>
+<LI><A HREF="#10_59_1">Usage</A></LI>
+<LI><A HREF="#10_59_2">Arguments</A></LI>
+<LI><A HREF="#10_59_3">Description</A></LI>
+<LI><A HREF="#10_59_4">Example</A></LI>
+<LI><A HREF="#10_59_5">See Also</A></LI>
+</UL>
+<LI><A HREF="#httpTrace">httpTrace()</A></LI>
+<UL>
+<LI><A HREF="#10_60_1">Usage</A></LI>
+<LI><A HREF="#10_60_2">Arguments</A></LI>
+<LI><A HREF="#10_60_3">Returns</A></LI>
+<LI><A HREF="#10_60_4">Description</A></LI>
+<LI><A HREF="#10_60_5">Example</A></LI>
+<LI><A HREF="#10_60_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#httpUpdate">httpUpdate()</A></LI>
+<UL>
+<LI><A HREF="#10_61_1">Usage</A></LI>
+<LI><A HREF="#10_61_2">Arguments</A></LI>
+<LI><A HREF="#10_61_3">Returns</A></LI>
+<LI><A HREF="#10_61_4">Description</A></LI>
+<LI><A HREF="#10_61_5">Example</A></LI>
+<LI><A HREF="#10_61_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#httpWrite">httpWrite()</A></LI>
+<UL>
+<LI><A HREF="#10_62_1">Usage</A></LI>
+<LI><A HREF="#10_62_2">Arguments</A></LI>
+<LI><A HREF="#10_62_3">Returns</A></LI>
+<LI><A HREF="#10_62_4">Description</A></LI>
+<LI><A HREF="#10_62_5">Example</A></LI>
+<LI><A HREF="#10_62_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#ippAddBoolean">ippAddBoolean()</A></LI>
+<UL>
+<LI><A HREF="#10_63_1">Usage</A></LI>
+<LI><A HREF="#10_63_2">Arguments</A></LI>
+<LI><A HREF="#10_63_3">Returns</A></LI>
+<LI><A HREF="#10_63_4">Description</A></LI>
+<LI><A HREF="#10_63_5">Example</A></LI>
+<LI><A HREF="#10_63_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#ippAddBooleans">ippAddBooleans()</A></LI>
+<UL>
+<LI><A HREF="#10_64_1">Usage</A></LI>
+<LI><A HREF="#10_64_2">Arguments</A></LI>
+<LI><A HREF="#10_64_3">Returns</A></LI>
+<LI><A HREF="#10_64_4">Description</A></LI>
+<LI><A HREF="#10_64_5">Example</A></LI>
+<LI><A HREF="#10_64_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#ippAddDate">ippAddDate()</A></LI>
+<UL>
+<LI><A HREF="#10_65_1">Usage</A></LI>
+<LI><A HREF="#10_65_2">Arguments</A></LI>
+<LI><A HREF="#10_65_3">Returns</A></LI>
+<LI><A HREF="#10_65_4">Description</A></LI>
+<LI><A HREF="#10_65_5">Example</A></LI>
+<LI><A HREF="#10_65_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#ippAddInteger">ippAddInteger()</A></LI>
+<UL>
+<LI><A HREF="#10_66_1">Usage</A></LI>
+<LI><A HREF="#10_66_2">Arguments</A></LI>
+<LI><A HREF="#10_66_3">Returns</A></LI>
+<LI><A HREF="#10_66_4">Description</A></LI>
+<LI><A HREF="#10_66_5">Example</A></LI>
+<LI><A HREF="#10_66_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#ippAddIntegers">ippAddIntegers()</A></LI>
+<UL>
+<LI><A HREF="#10_67_1">Usage</A></LI>
+<LI><A HREF="#10_67_2">Arguments</A></LI>
+<LI><A HREF="#10_67_3">Returns</A></LI>
+<LI><A HREF="#10_67_4">Description</A></LI>
+<LI><A HREF="#10_67_5">Example</A></LI>
+<LI><A HREF="#10_67_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#ippAddRange">ippAddRange()</A></LI>
+<UL>
+<LI><A HREF="#10_68_1">Usage</A></LI>
+<LI><A HREF="#10_68_2">Arguments</A></LI>
+<LI><A HREF="#10_68_3">Returns</A></LI>
+<LI><A HREF="#10_68_4">Description</A></LI>
+<LI><A HREF="#10_68_5">Example</A></LI>
+<LI><A HREF="#10_68_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#ippAddRanges">ippAddRanges()</A></LI>
+<UL>
+<LI><A HREF="#10_69_1">Usage</A></LI>
+<LI><A HREF="#10_69_2">Arguments</A></LI>
+<LI><A HREF="#10_69_3">Returns</A></LI>
+<LI><A HREF="#10_69_4">Description</A></LI>
+<LI><A HREF="#10_69_5">Example</A></LI>
+<LI><A HREF="#10_69_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#ippAddResolution">ippAddResolution()</A></LI>
+<UL>
+<LI><A HREF="#10_70_1">Usage</A></LI>
+<LI><A HREF="#10_70_2">Arguments</A></LI>
+<LI><A HREF="#10_70_3">Returns</A></LI>
+<LI><A HREF="#10_70_4">Description</A></LI>
+<LI><A HREF="#10_70_5">Example</A></LI>
+<LI><A HREF="#10_70_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#ippAddResolutions">ippAddResolutions()</A></LI>
+<UL>
+<LI><A HREF="#10_71_1">Usage</A></LI>
+<LI><A HREF="#10_71_2">Arguments</A></LI>
+<LI><A HREF="#10_71_3">Returns</A></LI>
+<LI><A HREF="#10_71_4">Description</A></LI>
+<LI><A HREF="#10_71_5">Example</A></LI>
+<LI><A HREF="#10_71_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#ippAddSeparator">ippAddSeparator()</A></LI>
+<UL>
+<LI><A HREF="#10_72_1">Usage</A></LI>
+<LI><A HREF="#10_72_2">Arguments</A></LI>
+<LI><A HREF="#10_72_3">Returns</A></LI>
+<LI><A HREF="#10_72_4">Description</A></LI>
+<LI><A HREF="#10_72_5">Example</A></LI>
+<LI><A HREF="#10_72_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#ippAddString">ippAddString()</A></LI>
+<UL>
+<LI><A HREF="#10_73_1">Usage</A></LI>
+<LI><A HREF="#10_73_2">Arguments</A></LI>
+<LI><A HREF="#10_73_3">Returns</A></LI>
+<LI><A HREF="#10_73_4">Description</A></LI>
+<LI><A HREF="#10_73_5">Example</A></LI>
+<LI><A HREF="#10_73_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#ippAddStrings">ippAddStrings()</A></LI>
+<UL>
+<LI><A HREF="#10_74_1">Usage</A></LI>
+<LI><A HREF="#10_74_2">Arguments</A></LI>
+<LI><A HREF="#10_74_3">Returns</A></LI>
+<LI><A HREF="#10_74_4">Description</A></LI>
+<LI><A HREF="#10_74_5">Example</A></LI>
+<LI><A HREF="#10_74_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#ippDateToTime">ippDateToTime()</A></LI>
+<UL>
+<LI><A HREF="#10_75_1">Usage</A></LI>
+<LI><A HREF="#10_75_2">Arguments</A></LI>
+<LI><A HREF="#10_75_3">Returns</A></LI>
+<LI><A HREF="#10_75_4">Description</A></LI>
+<LI><A HREF="#10_75_5">Example</A></LI>
+<LI><A HREF="#10_75_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#ippDelete">ippDelete()</A></LI>
+<UL>
+<LI><A HREF="#10_76_1">Usage</A></LI>
+<LI><A HREF="#10_76_2">Arguments</A></LI>
+<LI><A HREF="#10_76_3">Description</A></LI>
+<LI><A HREF="#10_76_4">Example</A></LI>
+<LI><A HREF="#10_76_5">See Also</A></LI>
+</UL>
+<LI><A HREF="#ippFindAttribute">ippFindAttribute()</A></LI>
+<UL>
+<LI><A HREF="#10_77_1">Usage</A></LI>
+<LI><A HREF="#10_77_2">Arguments</A></LI>
+<LI><A HREF="#10_77_3">Returns</A></LI>
+<LI><A HREF="#10_77_4">Description</A></LI>
+<LI><A HREF="#10_77_5">Example</A></LI>
+<LI><A HREF="#10_77_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#ippLength">ippLength()</A></LI>
+<UL>
+<LI><A HREF="#10_78_1">Usage</A></LI>
+<LI><A HREF="#10_78_2">Arguments</A></LI>
+<LI><A HREF="#10_78_3">Returns</A></LI>
+<LI><A HREF="#10_78_4">Description</A></LI>
+<LI><A HREF="#10_78_5">Example</A></LI>
+<LI><A HREF="#10_78_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#ippNew">ippNew()</A></LI>
+<UL>
+<LI><A HREF="#10_79_1">Usage</A></LI>
+<LI><A HREF="#10_79_2">Returns</A></LI>
+<LI><A HREF="#10_79_3">Description</A></LI>
+<LI><A HREF="#10_79_4">Example</A></LI>
+<LI><A HREF="#10_79_5">See Also</A></LI>
+</UL>
+<LI><A HREF="#ippPort">ippPort()</A></LI>
+<UL>
+<LI><A HREF="#10_80_1">Usage</A></LI>
+<LI><A HREF="#10_80_2">Returns</A></LI>
+<LI><A HREF="#10_80_3">Description</A></LI>
+<LI><A HREF="#10_80_4">Example</A></LI>
+<LI><A HREF="#10_80_5">See Also</A></LI>
+</UL>
+<LI><A HREF="#ippRead">ippRead()</A></LI>
+<UL>
+<LI><A HREF="#10_81_1">Usage</A></LI>
+<LI><A HREF="#10_81_2">Arguments</A></LI>
+<LI><A HREF="#10_81_3">Returns</A></LI>
+<LI><A HREF="#10_81_4">Description</A></LI>
+<LI><A HREF="#10_81_5">Example</A></LI>
+<LI><A HREF="#10_81_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#ippSetPort">ippSetPort()</A></LI>
+<UL>
+<LI><A HREF="#10_82_1">Usage</A></LI>
+<LI><A HREF="#10_82_2">Arguments</A></LI>
+<LI><A HREF="#10_82_3">Description</A></LI>
+<LI><A HREF="#10_82_4">Example</A></LI>
+<LI><A HREF="#10_82_5">See Also</A></LI>
+</UL>
+<LI><A HREF="#ippTimeToDate">ippTimeToDate()</A></LI>
+<UL>
+<LI><A HREF="#10_83_1">Usage</A></LI>
+<LI><A HREF="#10_83_2">Arguments</A></LI>
+<LI><A HREF="#10_83_3">Returns</A></LI>
+<LI><A HREF="#10_83_4">Description</A></LI>
+<LI><A HREF="#10_83_5">Example</A></LI>
+<LI><A HREF="#10_83_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#ippWrite">ippWrite()</A></LI>
+<UL>
+<LI><A HREF="#10_84_1">Usage</A></LI>
+<LI><A HREF="#10_84_2">Arguments</A></LI>
+<LI><A HREF="#10_84_3">Returns</A></LI>
+<LI><A HREF="#10_84_4">Description</A></LI>
+<LI><A HREF="#10_84_5">Example</A></LI>
+<LI><A HREF="#10_84_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#ppdClose">ppdClose()</A></LI>
+<UL>
+<LI><A HREF="#10_85_1">Usage</A></LI>
+<LI><A HREF="#10_85_2">Arguments</A></LI>
+<LI><A HREF="#10_85_3">Description</A></LI>
+<LI><A HREF="#10_85_4">Example</A></LI>
+<LI><A HREF="#10_85_5">See Also</A></LI>
+</UL>
+<LI><A HREF="#ppdConflicts">ppdConflicts()</A></LI>
+<UL>
+<LI><A HREF="#10_86_1">Usage</A></LI>
+<LI><A HREF="#10_86_2">Arguments</A></LI>
+<LI><A HREF="#10_86_3">Returns</A></LI>
+<LI><A HREF="#10_86_4">Description</A></LI>
+<LI><A HREF="#10_86_5">Example</A></LI>
+<LI><A HREF="#10_86_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#ppdEmit">ppdEmit()</A></LI>
+<UL>
+<LI><A HREF="#10_87_1">Usage</A></LI>
+<LI><A HREF="#10_87_2">Arguments</A></LI>
+<LI><A HREF="#10_87_3">Returns</A></LI>
+<LI><A HREF="#10_87_4">Description</A></LI>
+<LI><A HREF="#10_87_5">Example</A></LI>
+<LI><A HREF="#10_87_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#ppdEmitFd">ppdEmitFd()</A></LI>
+<UL>
+<LI><A HREF="#10_88_1">Usage</A></LI>
+<LI><A HREF="#10_88_2">Arguments</A></LI>
+<LI><A HREF="#10_88_3">Returns</A></LI>
+<LI><A HREF="#10_88_4">Description</A></LI>
+<LI><A HREF="#10_88_5">Example</A></LI>
+<LI><A HREF="#10_88_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#ppdFindChoice">ppdFindChoice()</A></LI>
+<UL>
+<LI><A HREF="#10_89_1">Usage</A></LI>
+<LI><A HREF="#10_89_2">Arguments</A></LI>
+<LI><A HREF="#10_89_3">Returns</A></LI>
+<LI><A HREF="#10_89_4">Description</A></LI>
+<LI><A HREF="#10_89_5">Example</A></LI>
+<LI><A HREF="#10_89_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#ppdFindMarkedChoice">ppdFindMarkedChoice()</A></LI>
+<UL>
+<LI><A HREF="#10_90_1">Usage</A></LI>
+<LI><A HREF="#10_90_2">Arguments</A></LI>
+<LI><A HREF="#10_90_3">Returns</A></LI>
+<LI><A HREF="#10_90_4">Description</A></LI>
+<LI><A HREF="#10_90_5">Example</A></LI>
+<LI><A HREF="#10_90_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#ppdFindOption">ppdFindOption()</A></LI>
+<UL>
+<LI><A HREF="#10_91_1">Usage</A></LI>
+<LI><A HREF="#10_91_2">Arguments</A></LI>
+<LI><A HREF="#10_91_3">Returns</A></LI>
+<LI><A HREF="#10_91_4">Description</A></LI>
+<LI><A HREF="#10_91_5">Example</A></LI>
+<LI><A HREF="#10_91_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#ppdIsMarked">ppdIsMarked()</A></LI>
+<UL>
+<LI><A HREF="#10_92_1">Usage</A></LI>
+<LI><A HREF="#10_92_2">Arguments</A></LI>
+<LI><A HREF="#10_92_3">Returns</A></LI>
+<LI><A HREF="#10_92_4">Description</A></LI>
+<LI><A HREF="#10_92_5">Example</A></LI>
+<LI><A HREF="#10_92_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#ppdMarkDefaults">ppdMarkDefaults()</A></LI>
+<UL>
+<LI><A HREF="#10_93_1">Usage</A></LI>
+<LI><A HREF="#10_93_2">Arguments</A></LI>
+<LI><A HREF="#10_93_3">Description</A></LI>
+<LI><A HREF="#10_93_4">Example</A></LI>
+<LI><A HREF="#10_93_5">See Also</A></LI>
+</UL>
+<LI><A HREF="#ppdMarkOption">ppdMarkOption()</A></LI>
+<UL>
+<LI><A HREF="#10_94_1">Usage</A></LI>
+<LI><A HREF="#10_94_2">Arguments</A></LI>
+<LI><A HREF="#10_94_3">Returns</A></LI>
+<LI><A HREF="#10_94_4">Description</A></LI>
+<LI><A HREF="#10_94_5">Example</A></LI>
+<LI><A HREF="#10_94_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#ppdOpen">ppdOpen()</A></LI>
+<UL>
+<LI><A HREF="#10_95_1">Usage</A></LI>
+<LI><A HREF="#10_95_2">Arguments</A></LI>
+<LI><A HREF="#10_95_3">Returns</A></LI>
+<LI><A HREF="#10_95_4">Description</A></LI>
+<LI><A HREF="#10_95_5">Example</A></LI>
+<LI><A HREF="#10_95_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#ppdOpenFd">ppdOpenFd()</A></LI>
+<UL>
+<LI><A HREF="#10_96_1">Usage</A></LI>
+<LI><A HREF="#10_96_2">Arguments</A></LI>
+<LI><A HREF="#10_96_3">Returns</A></LI>
+<LI><A HREF="#10_96_4">Description</A></LI>
+<LI><A HREF="#10_96_5">Example</A></LI>
+<LI><A HREF="#10_96_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#ppdOpenFile">ppdOpenFile()</A></LI>
+<UL>
+<LI><A HREF="#10_97_1">Usage</A></LI>
+<LI><A HREF="#10_97_2">Arguments</A></LI>
+<LI><A HREF="#10_97_3">Returns</A></LI>
+<LI><A HREF="#10_97_4">Description</A></LI>
+<LI><A HREF="#10_97_5">Example</A></LI>
+<LI><A HREF="#10_97_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#ppdPageLength">ppdPageLength()</A></LI>
+<UL>
+<LI><A HREF="#10_98_1">Usage</A></LI>
+<LI><A HREF="#10_98_2">Arguments</A></LI>
+<LI><A HREF="#10_98_3">Returns</A></LI>
+<LI><A HREF="#10_98_4">Description</A></LI>
+<LI><A HREF="#10_98_5">Example</A></LI>
+<LI><A HREF="#10_98_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#ppdPageSize">ppdPageSize()</A></LI>
+<UL>
+<LI><A HREF="#10_99_1">Usage</A></LI>
+<LI><A HREF="#10_99_2">Arguments</A></LI>
+<LI><A HREF="#10_99_3">Returns</A></LI>
+<LI><A HREF="#10_99_4">Description</A></LI>
+<LI><A HREF="#10_99_5">Example</A></LI>
+<LI><A HREF="#10_99_6">See Also</A></LI>
+</UL>
+<LI><A HREF="#ppdPageWidth">ppdPageWidth()</A></LI>
+<UL>
+<LI><A HREF="#10_100_1">Usage</A></LI>
+<LI><A HREF="#10_100_2">Arguments</A></LI>
+<LI><A HREF="#10_100_3">Returns</A></LI>
+<LI><A HREF="#10_100_4">Description</A></LI>
+<LI><A HREF="#10_100_5">Example</A></LI>
+<LI><A HREF="#10_100_6">See Also</A></LI>
+</UL>
+</UL>
+<HR>
+<H1 ALIGN="RIGHT"><A NAME="1">Preface</A></H1>
+<P>This software programmers manual provides software programming
+ information for the Common UNIX Printing System (&quot;CUPS&quot;) Version
+ 1.1.13.</P>
+<H2><A NAME="1_1">System Overview</A></H2>
+<P>CUPS provides a portable printing layer for UNIX&reg;-based operating
+ systems. It has been developed by<A HREF="http://www.easysw.com"> Easy
+ Software Products</A> to promote a standard printing solution for all
+ UNIX vendors and users. CUPS provides the System V and Berkeley
+ command-line interfaces.</P>
+<P>CUPS uses the Internet Printing Protocol (&quot;IPP&quot;) as the basis for
+ managing print jobs and queues. The Line Printer Daemon (&quot;LPD&quot;) Server
+ Message Block (&quot;SMB&quot;), and AppSocket (a.k.a. JetDirect) protocols are
+ also supported with reduced functionality. CUPS adds network printer
+ browsing and PostScript Printer Description (&quot;PPD&quot;) based printing
+ options to support real-world printing under UNIX.</P>
+<P>CUPS also includes a customized version of GNU Ghostscript (currently
+ based off GNU Ghostscript 5.50) and an image file RIP that are used to
+ support non-PostScript printers. Sample drivers for HP and EPSON
+ printers are included that use these filters.</P>
+
+<!-- NEED 2in -->
+<H2><A NAME="1_2">Document Overview</A></H2>
+<P>This software programmers manual is organized into the following
+ sections:</P>
+<UL>
+<LI><A HREF="#OVERVIEW">1 - Printing System Overview</A></LI>
+<LI><A HREF="#CUPS_API">2 - The CUPS API</A></LI>
+<LI><A HREF="#WRITING_FILTERS">3 - Writing Filters</A></LI>
+<LI><A HREF="#WRITING_DRIVERS">4 - Writing Printer Drivers</A></LI>
+<LI><A HREF="#WRITING_BACKENDS">5 - Writing Backends</A></LI>
+<LI><A HREF="#LICENSE">A - Software License Agreement</A></LI>
+<LI><A HREF="#CONSTANTS">B - Constants</A></LI>
+<LI><A HREF="#STRUCTURES">C - Structures</A></LI>
+<LI><A HREF="#FUNCTIONS">D - Functions</A></LI>
+</UL>
+<H2><A NAME="1_3">Notation Conventions</A></H2>
+<P>Various font and syntax conventions are used in this guide. Examples
+ and their meanings and uses are explained below:
+<CENTER>
+<TABLE WIDTH="80%">
+<TR><TH>Example</TH><TD>&nbsp;&nbsp;&nbsp;</TD><TH>Description</TH></TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR VALIGN="TOP"><TD><CODE>lpstat</CODE>
+<BR> <CODE>lpstat(1)</CODE></TD><TD>&nbsp;&nbsp;&nbsp;</TD><TD>The names of commands;
+ the first mention of a command or function in a chapter is followed by
+ a manual page section number.</TD></TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR VALIGN="TOP"><TD><VAR>/var</VAR>
+<BR><VAR> /usr/share/cups/data/testprint.ps</VAR></TD><TD>&nbsp;&nbsp;&nbsp;</TD><TD>
+File and directory names.</TD></TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR VALIGN="TOP"><TD NOWRAP><TT>Request ID is Printer-123</TT></TD><TD>
+&nbsp;&nbsp;&nbsp;</TD><TD>Screen output.</TD></TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR VALIGN="TOP"><TD NOWRAP><KBD>lp -d printer filename ENTER</KBD></TD><TD>
+&nbsp;&nbsp;&nbsp;</TD><TD>Literal user input; special keys like <KBD>ENTER</KBD> are
+ in ALL CAPS.</TD></TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR VALIGN="TOP"><TD>12.3</TD><TD>&nbsp;&nbsp;&nbsp;</TD><TD>Numbers in the text are
+ written using the period (.) to indicate the decimal point.</TD></TR>
+</TABLE>
+</CENTER>
+
+<!-- NEED 3in -->
+</P>
+<H2><A NAME="1_4">Abbreviations</A></H2>
+ The following abbreviations are used throughout this manual:
+<UL>
+<DL>
+<DT>kb</DT>
+<DD>Kilobytes, or 1024 bytes
+<BR>&nbsp;</DD>
+<DT>Mb</DT>
+<DD>Megabytes, or 1048576 bytes
+<BR>&nbsp;</DD>
+<DT>Gb</DT>
+<DD>Gigabytes, or 1073741824 bytes
+<BR>&nbsp;</DD>
+</DL>
+</UL>
+<H2><A NAME="1_5">Other References</A></H2>
+<UL>
+<DL>
+<DT>CUPS Software Administrators Manual</DT>
+<DD>An administration guide for the CUPS software.
+<BR>&nbsp;</DD>
+<DT>CUPS Software Users Manual</DT>
+<DD>An end-user guide for using the CUPS software.
+<BR>&nbsp;</DD>
+</DL>
+</UL>
+<H1 ALIGN="RIGHT"><A NAME="OVERVIEW">1 - Printing System Overview</A></H1>
+<P>This chapter provides an overview of how the Common UNIX Printing
+ System works.</P>
+<H2><A NAME="2_1">The Printing Problem</A></H2>
+<P>For years<I> the printing problem</I> has plagued UNIX. Unlike
+ Microsoft&reg; Windows&reg; or Mac OS, UNIX has no standard interface or system
+ in place for supporting printers. Among the solutions currently
+ available, the Berkeley and System V printing systems are the most
+ prevalent.</P>
+<P>These printing systems support line printers (text only) or
+ PostScript printers (text and graphics), and with some coaxing they can
+ be made to support a full range of printers and file formats. However,
+ because each varient of the UNIX operating system uses a different
+ printing system than the next developing printer drivers for a wide
+ range of printers and operating systems is extremely difficult. That
+ combined with the limited volume of customers for each UNIX varient has
+ forced most printer vendors to give up supporting UNIX entirely.</P>
+<P>CUPS is designed to eliminate<I> the printing problem</I>. 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.</P>
+<H2><A NAME="2_2">The Technology</A></H2>
+<P>CUPS is based upon an emerging Internet standard called the Internet
+ Printing Protocol. IPP has been embraced by dozens of printer and
+ printer server manufacturers and is supported by Microsoft Windows
+ 2000.</P>
+<P>IPP defines a standard protocol for printing as well as managing
+ print jobs and printer options like media size, resolution, and so
+ forth. Like all IP-based protocols, IPP can be used locally or over the
+ Internet to printers hundreds or thousands of miles away. Unlike other
+ protocols, however, IPP also supports access control, authentication,
+ and encryption, making it a much more capable and secure printing
+ solution than older ones.</P>
+<P>IPP is layered on top of the Hyper-Text Transport Protocol (&quot;HTTP&quot;)
+ which is the basis of web servers on the Internet. This allows users to
+ view documentation, check status information on a printer or server,
+ and manage their printers, classes, and jobs using their web browser.</P>
+<P>CUPS provides a complete IPP/1.1 based printing system that provides
+ Basic, Digest, and local certificate authentication and user, domain,
+ or IP-based access control. TLS encryption will be available in future
+ versions of CUPS.</P>
+<H2><A NAME="2_3">Jobs</A></H2>
+<P>Each file or set of files that is submitted for printing is called a<I>
+ job</I>. 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.</P>
+<H2><A NAME="2_4">Classes</A></H2>
+<P>CUPS supports collections of printers known as<I> classes</I>. Jobs
+ sent to a class are forwarded to the first available printer in the
+ class.</P>
+<H2><A NAME="2_5">Filters</A></H2>
+<P>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.</P>
+<P>CUPS provides filters for printing many types of image files, HP-GL/2
+ files, PDF files, and text files. CUPS also supplies PostScript and
+ image file Raster Image Processor (&quot;RIP&quot;) filters that convert
+ PostScript or image files into bitmaps that can be sent to a raster
+ printer.</P>
+<H2><A NAME="2_6">Backends</A></H2>
+<P>Backends perform the most important task of all - they send the
+ filtered print data to the printer.</P>
+<P>CUPS provides backends for printing over parallel, serial, and USB
+ ports, and over the network via the IPP, JetDirect (AppSocket), and
+ Line Printer Daemon (&quot;LPD&quot;) protocols. Additional backends are
+ available in network service packages such as the SMB backend included
+ with the popular SAMBA software.</P>
+<P>Backends are also used to determine the available devices. On startup
+ each backend is asked for a list of devices it supports, and any
+ information that is available. This allows the parallel backend to tell
+ CUPS that an EPSON Stylus Color 600 printer is attached to parallel
+ port 1, for example.</P>
+<H2><A NAME="2_7">Printer Drivers</A></H2>
+<P>Printer drivers in CUPS consist of one of more filters specific to a
+ printer. CUPS includes sample printer drivers for Hewlett-Packard
+ LaserJet and DeskJet printers and EPSON 9-pin, 24-pin, Stylus Color,
+ and Stylus Photo printers. While these drivers do not generate optimal
+ output for the different printer models, they do provide basic printing
+ and demonstrate how you can write your own printer drivers and
+ incorporate them into CUPS.</P>
+<H2><A NAME="2_8">Networking</A></H2>
+<P>Printers and classes on the local system are automatically shared
+ with other systems on the network. This allows you to setup one system
+ to print to a printer and use this system as a printer server or spool
+ host for all of the others. Users may then select a local printer by
+ name or a remote printer using &quot;name@server&quot;.</P>
+<P>CUPS also provides<I> implicit classes</I>, which are collections of
+ printers and/or classes with the same name. This allows you to setup
+ multiple servers pointing to the same physical network printer, for
+ example, so that you aren't relying on a single system for printing.
+ Because this also works with printer classes, you can setup multiple
+ servers and printers and never worry about a single point of failure
+ unless all of the printers and servers go down!</P>
+<H1 ALIGN="RIGHT"><A NAME="CUPS_API">2 - The CUPS API</A></H1>
+<P>This chapter describes the CUPS Application Programmers Interface
+ (&quot;API&quot;).</P>
+<H2><A NAME="3_1">The CUPS API Library</A></H2>
+<P>The CUPS library provides a whole collection of interfaces needed to
+ support the internal needs of the CUPS software as well as the needs of
+ applications, filters, printer drivers, and backends.</P>
+<P>Unlike the rest of CUPS, the CUPS API library is provided under the
+ GNU Library General Public License. This means that you can use the
+ CUPS API library in both proprietary and open-source programs.</P>
+<P>Programs that use the CUPS API library typically will include the <CODE>
+&lt;cups/cups.h&gt;</CODE> header file:</P>
+<UL>
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+...
+
+jobid = cupsPrintFile(&quot;myprinter&quot;, &quot;filename.ps&quot;, &quot;title&quot;,
+ num_options, options);
+</PRE>
+</UL>
+<P>Use the <CODE>-lcups</CODE> compiler option when linking to the CUPS
+ API library:</P>
+<UL>
+<PRE>
+<B>cc -o program program.c -lcups ENTER</B>
+</PRE>
+</UL>
+<P>Additional options and libraries may be required depending on the
+ operating system and the location of the CUPS API library.</P>
+<H3><A NAME="3_1_1">Detecting the CUPS API Library in GNU Autoconf</A></H3>
+<P>GNU autoconf is a popular configuration tool used by many programs.
+ Add the following lines to your<VAR> configure.in file to check for the
+ CUPS API library in your configuration script:</VAR></P>
+<UL>
+<PRE>
+AC_CHECK_LIB(socket,socket,
+if test &quot;$uname&quot; != &quot;IRIX&quot;; then
+ LIBS=&quot;-lsocket $LIBS&quot;
+else
+ echo &quot;Not using -lsocket since you are running IRIX.&quot;
+fi)
+AC_CHECK_LIB(nsl,gethostbyaddr,
+if test &quot;$uname&quot; != &quot;IRIX&quot;; then
+ LIBS=&quot;-lnsl $LIBS&quot;
+else
+ echo &quot;Not using -lnsl since you are running IRIX.&quot;
+fi)
+
+AC_CHECK_LIB(cups,httpConnect)
+</PRE>
+</UL>
+<H2><A NAME="3_2">Printing Services</A></H2>
+<P>The CUPS API library provides some basic printing services for
+ applications that need to print files.</P>
+<H3><A NAME="3_2_1">Include Files</A></H3>
+<P>The include file used by all of these functions is <CODE>
+&lt;cups/cups.h&gt;</CODE>:</P>
+<UL>
+<PRE>
+#include &lt;cups/cups.h&gt;
+</PRE>
+</UL>
+<H3><A NAME="3_2_2">Printing a File</A></H3>
+<P>The CUPS API provides two functions for printing files. The first is <CODE>
+cupsPrintFile</CODE> which prints a single named file:</P>
+<UL>
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+...
+
+int jobid;
+
+...
+
+jobid = cupsPrintFile(&quot;<I>name</I>&quot;, &quot;<I>filename</I>&quot;, &quot;<I>title</I>&quot;, 0, NULL);
+</PRE>
+</UL>
+<P>The <CODE>name</CODE> string is the name of the printer or class to
+ print to. The <CODE>filename</CODE> string is the name of the file to
+ print. The <CODE>title</CODE> string is the name of the print job, e.g.
+ &quot;Acme Word Document&quot;.</P>
+<P>The return value is a unique ID number for the print job or 0 if
+ there was an error.</P>
+<H3><A NAME="3_2_3">Printing Multiple Files</A></H3>
+<P>The second printing function is <CODE>cupsPrintFiles</CODE>:</P>
+<UL>
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+...
+
+int jobid;
+int num_files;
+const char *files[100];
+...
+
+jobid = cupsPrintFiles(&quot;name&quot;, <I>num_files</I>, <I>files</I>, &quot;title&quot;, 0, NULL);
+</PRE>
+</UL>
+<P>Instead of passing a filename string as with <CODE>cupsPrintFile()</CODE>
+, you pass a file count (<CODE>num_files</CODE>) and filename pointer
+ array (<CODE>files</CODE>) for each file that you want to print.</P>
+<P>As with <CODE>cupsPrintFile()</CODE>, the return value is a unique ID
+ for the print job.</P>
+<H3><A NAME="3_2_4">Cancelling Jobs</A></H3>
+<P>The <CODE>cupsCancelJob()</CODE> function cancels a queued print job:</P>
+<UL>
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+...
+
+int jobid;
+int status;
+...
+
+status = cupsCancelJob(&quot;<I>name</I>&quot;, <I>jobid</I>);
+</PRE>
+</UL>
+<P>The <CODE>name</CODE> string specifies the destination and is used to
+ determine the server to send the request to. The <CODE>jobid</CODE>
+ value is the integer returned from a previous <CODE>cupsPrintFile()</CODE>
+ or <CODE>cupsPrintFiles()</CODE> call.</P>
+<P><CODE>cupsCancelJob()</CODE> returns <CODE>1</CODE> if the job was
+ successfully cancelled and <CODE>0</CODE> if there was an error.</P>
+<H3><A NAME="3_2_5">Getting the Available Printers and Classes</A></H3>
+<P>The <CODE>cupsGetDests()</CODE> function can be used to get a list of
+ the available printers, classes, and instances that a user has defined:</P>
+<UL>
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+...
+
+int num_dests;
+cups_dest_t *dests;
+
+...
+
+num_dests = cupsGetDests(&amp;dests);
+</PRE>
+</UL>
+<P>Each destination is stored in a <CODE>cups_dest_t</CODE> structure
+ which defines the printer or class name, the instance name (if any), if
+ it is the default destination, and the default options the user has
+ defined for the destination:</P>
+<UL>
+<PRE>
+typedef struct /**** Destination ****/
+{
+ char *name, /* Printer or class name */
+ *instance; /* Local instance name or NULL */
+ int is_default; /* Is this printer the default? */
+ int num_options; /* Number of options */
+ cups_option_t *options; /* Options */
+} cups_dest_t;
+</PRE>
+</UL>
+<P>The destinations are sorted by name and instance for your
+ convenience. Once you have the list of available destinations, you can
+ lookup a specific destination using the <CODE>cupsGetDest()</CODE>
+ function:</P>
+<UL>
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+...
+
+int num_dests;
+cups_dest_t *dests;
+cups_dest_t *mydest;
+
+...
+
+mydest = cupsGetDest(&quot;<I>name</I>&quot;, &quot;<I>instance</I>&quot;, num_dests, dests);
+</PRE>
+</UL>
+<P>The <CODE>name</CODE> string is the printer or class name. You can
+ pass a value of <CODE>NULL</CODE> to get the default destination.</P>
+<P>The <CODE>instance</CODE> string is the user-defined instance name.
+ Pass <CODE>NULL</CODE> to select the default instance, e.g. &quot;name&quot;
+ instead of &quot;name/instance&quot;.</P>
+<H3><A NAME="3_2_6">Printing with Options</A></H3>
+<P>All of the previous printing examples have passed <CODE>0</CODE> and <CODE>
+NULL</CODE> for the last two arguments to the <CODE>cupsPrintFile()</CODE>
+ and <CODE>cupsPrintFiles()</CODE> functions. These last two arguments
+ are the number of options and a pointer to the option array:</P>
+<UL>
+<PRE>
+int cupsPrintFile(const char *name, const char *filename, const char *title,
+ int num_options, cups_option_t *options);
+int cupsPrintFiles(const char *name, int num_files, const char **files,
+ const char *title, int num_options,
+ cups_option_t *options);
+</PRE>
+</UL>
+<P>The <CODE>cups_option_t</CODE> structure holds each option and its
+ value. These are converted as needed and passed to the CUPS server when
+ printing a file.</P>
+<P>The simplest way of handling options is to use the <CODE>num_options</CODE>
+ and <CODE>options</CODE> members of the <CODE>cups_dest_t</CODE>
+ structure described earlier:</P>
+<UL>
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+...
+
+int jobid;
+int num_dests;
+cups_dest_t *dests;
+cups_dest_t *mydest;
+
+...
+
+mydest = cupsGetDest(&quot;<I>name</I>&quot;, &quot;<I>instance</I>&quot;, num_dests, dests);
+
+jobid = cupsPrintFile(mydest-&gt;name, &quot;filename&quot;, &quot;title&quot;,
+ mydest-&gt;num_options, mydest-&gt;options);
+</PRE>
+</UL>
+<P>This effectively uses the options a user has previous selected
+ without a lot of code.</P>
+<H3><A NAME="3_2_7">Setting Printer Options</A></H3>
+<P>Options can also be set by your program using the <CODE>
+cupsAddOption()</CODE> function:</P>
+<UL>
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+...
+
+int num_options;
+cups_option_t *options;
+
+...
+
+num_options = 0;
+options = NULL;
+
+...
+
+num_options = cupsAddOption(&quot;<I>name</I>&quot;, &quot;<I>value</I>&quot;, num_options, &amp;options);
+num_options = cupsAddOption(&quot;<I>name</I>&quot;, &quot;<I>value</I>&quot;, num_options, &amp;options);
+num_options = cupsAddOption(&quot;<I>name</I>&quot;, &quot;<I>value</I>&quot;, num_options, &amp;options);
+num_options = cupsAddOption(&quot;<I>name</I>&quot;, &quot;<I>value</I>&quot;, num_options, &amp;options);
+</PRE>
+</UL>
+<P>The <CODE>name</CODE> string is the name of the option, and the <CODE>
+value</CODE> string is the value for that option.</P>
+<P>Each call to <CODE>cupsAddOption()</CODE> returns the new number of
+ options. Since adding two options with the same name overwrites the
+ first value with the second, do not assume that calling <CODE>
+cupsAddOptions()</CODE> 20 times will result in 20 options.</P>
+<P>Call <CODE>cupsFreeOptions</CODE> once you are done using the
+ options:</P>
+<UL>
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+...
+
+int num_options;
+cups_option_t *options;
+
+...
+
+cupsFreeOptions(num_options, options);
+</PRE>
+</UL>
+<H3><A NAME="3_2_8">Getting Errors</A></H3>
+<P>If any of the CUPS API printing functions returns an error, the
+ reason for that error can be found by calling <CODE>cupsLastError()</CODE>
+ and <CODE>cupsErrorString()</CODE>. <CODE>cupsLastError()</CODE>
+ returns the last IPP error code that was encountered. <CODE>
+cupsErrorString()</CODE> converts the error code to a localized message
+ string suitable for presentation to the user:</P>
+<UL>
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+...
+
+int jobid;
+
+...
+
+if (jobid == 0)
+ puts(cupsErrorString(cupsLastError()));
+</PRE>
+</UL>
+<H3><A NAME="3_2_9">Passwords and Authentication</A></H3>
+<P>CUPS supports authentication of any request, including submission of
+ print jobs. The default mechanism for getting the username and password
+ is to use the login user and a password from the console.</P>
+<P>To support other types of applications, in particular Graphical User
+ Interfaces (&quot;GUIs&quot;), the CUPS API provides functions to set the default
+ username and to register a callback function that returns a password
+ string.</P>
+<P>The<A HREF="#cupsSetPasswordCB"> <CODE>cupsSetPasswordCB()</CODE></A>
+ function is used to set a password callback in your program. Only one
+ function can be used at any time.</P>
+<P>The<A HREF="#cupsSetUser"> <CODE>cupsSetUser()</CODE></A> function
+ sets the current username for authentication. This function can be
+ called by your password callback function to change the current
+ username as needed.</P>
+<P>The following example shows a simple password callback that gets a
+ username and password from the user:</P>
+<UL>
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+const char *
+my_password_cb(const char *prompt)
+{
+ char user[65];
+
+
+ puts(prompt);
+
+ /* Get a username from the user */
+ printf(&quot;Username: &quot;);
+ if (fgets(user, sizeof(user), stdin) == NULL)
+ return (NULL);
+
+ /* Strip the newline from the string and set the user */
+ user[strlen(user) - 1] = '\0';
+
+ cupsSetUser(user);
+
+ /* Use getpass() to ask for the password... */
+ return (getpass(&quot;Password: &quot;));
+}
+
+...
+
+cupsSetPasswordCB(my_password_cb);
+</PRE>
+</UL>
+<P>Similarly, a GUI interface could display the prompt string in a
+ window with input fields for the username and password. The username
+ should probably default to the value of<A HREF="#cupsUser"> <CODE>
+cupsUser()</CODE></A> to make things easier on the user.</P>
+<H2><A NAME="3_3">PPD Services</A></H2>
+<P>CUPS includes functions to access and manipulate PostScript Printer
+ Description (&quot;PPD&quot;) files that are used with the printer drivers in
+ CUPS.</P>
+<P>Each PPD file enumerates the available features provided by a
+ printer, including conflict information for specific options (e.g.
+ can't duplex output on envelopes.)</P>
+<H3><A NAME="3_3_1">Include Files</A></H3>
+<P>Include the <CODE>&lt;cups/ppd.h&gt;</CODE> header file to use the PPD
+ functions:</P>
+<UL>
+<PRE>
+#include &lt;cups/ppd.h&gt;
+</PRE>
+</UL>
+<P>This header file is also included by the <CODE>&lt;cups/cups.h&gt;</CODE>
+ header file.</P>
+<H3><A NAME="3_3_2">Getting a PPD File for a Printer</A></H3>
+<P>The <CODE>cupsGetPPD()</CODE> function retrieves the PPD file for the
+ named printer or class:</P>
+<UL>
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+...
+
+const char *filename;
+
+filename = cupsGetPPD(&quot;<I>name</I>&quot;);
+</PRE>
+</UL>
+<P>The <CODE>name</CODE> string is the name of the printer or class,
+ including the remote server name as appropriate (e.g.
+ &quot;printer@server&quot;.)</P>
+<P>The return value is a pointer to a filename in static storage; this
+ value is overwritten with each call to <CODE>cupsGetPPD()</CODE>. If
+ the printer or class does not exist, a <CODE>NULL</CODE> pointer will
+ be returned.</P>
+<H3><A NAME="3_3_3">Loading a PPD File</A></H3>
+<P>The <CODE>ppdOpenFile()</CODE> function &quot;opens&quot; a PPD file and loads
+ it into memory:</P>
+<UL>
+<PRE>
+#include &lt;cups/ppd.h&gt;
+
+...
+
+ppd_file_t *ppd;
+
+ppd = ppdOpenFile(&quot;<I>filename</I>&quot;);
+</PRE>
+</UL>
+<P>The <CODE>filename</CODE> string is the name of the file to load,
+ such as the value returned by the <CODE>cupsGetPPD()</CODE> function.</P>
+<P>The return value is a pointer to a structure describing the contents
+ of the PPD file or NULL if the PPD file could not be read.</P>
+<H3><A NAME="3_3_4">Freeing PPD File Information</A></H3>
+<P>Once you are done using a PPD file, call the <CODE>ppdClose()</CODE>
+ function to free all memory that has been used:</P>
+<UL>
+<PRE>
+#include &lt;cups/ppd.h&gt;
+
+...
+
+ppd_file_t *ppd;
+
+...
+
+ppdClose(ppd);
+</PRE>
+</UL>
+<H3><A NAME="3_3_5">The PPD File Structure</A></H3>
+<P>Each PPD file contains a number of capability attributes, printer
+ options, and conflict definitions. The page size options also include
+ the physical margins for the printer and the minimum and maximum sizes
+ for the printer. All of this information is stored in the <CODE>
+ppd_file_t</CODE> structure.</P>
+<H4>Capabilities</H4>
+<P>Each PPD file contains a number of informational attributes that
+ describe the capabilities of the printer. These are provided in the <CODE>
+ppd_file_t</CODE> structure in the following members:
+<CENTER>
+<TABLE BORDER="1" WIDTH="80%">
+<TR><TH>Member</TH><TH>Type</TH><TH>Description</TH></TR>
+<TR><TD><CODE>accurate_screens</CODE></TD><TD><CODE>int</CODE></TD><TD>1
+ = supports accurate screens</TD></TR>
+<TR><TD><CODE>color_device</CODE></TD><TD><CODE>int</CODE></TD><TD>1 =
+ color device</TD></TR>
+<TR><TD><CODE>colorspace</CODE></TD><TD><CODE>ppd_cs_t</CODE></TD><TD>
+Default colorspace: PPD_CS_CMYK, PPD_CS_CMY, PPD_CS_GRAY, PPD_CS_RGB,
+ PPD_CS_RGBK, PPD_CS_N</TD></TR>
+<TR><TD><CODE>contone_only</CODE></TD><TD><CODE>int</CODE></TD><TD>1 =
+ printer is continuous tone only</TD></TR>
+<TR><TD><CODE>num_emulations
+<BR> emulations</CODE></TD><TD><CODE>int
+<BR> ppd_emul_t *</CODE></TD><TD>Emulations supported by the printer</TD>
+</TR>
+<TR><TD><CODE>flip_duplex</CODE></TD><TD><CODE>int</CODE></TD><TD>1 =
+ need to flip odd pages when duplexing</TD></TR>
+<TR><TD><CODE>num_fonts
+<BR> fonts</CODE></TD><TD><CODE>int
+<BR> char **</CODE></TD><TD>The fonts available on the printer.</TD></TR>
+<TR><TD><CODE>jcl_begin
+<BR> jcl_ps
+<BR> jcl_end</CODE></TD><TD><CODE>char *</CODE></TD><TD>Job Control
+ Language commands for PostScript output</TD></TR>
+<TR><TD><CODE>landscape</CODE></TD><TD><CODE>int</CODE></TD><TD>
+Landscape orientation, -90 or 90 degrees</TD></TR>
+<TR><TD><CODE>lang_encoding</CODE></TD><TD><CODE>char *</CODE></TD><TD>
+The character used for the option strings</TD></TR>
+<TR><TD><CODE>lang_version</CODE></TD><TD><CODE>char *</CODE></TD><TD>
+The language used for the options strings (English, French, etc.)</TD></TR>
+<TR><TD><CODE>language_level</CODE></TD><TD><CODE>int</CODE></TD><TD>
+PostScript language level, 1 to 3</TD></TR>
+<TR><TD><CODE>manual_copies</CODE></TD><TD><CODE>int</CODE></TD><TD>1 =
+ Copies are done manually</TD></TR>
+<TR><TD><CODE>model_number</CODE></TD><TD><CODE>int</CODE></TD><TD>
+Driver-specific model number.</TD></TR>
+<TR><TD><CODE>patches</CODE></TD><TD><CODE>char *</CODE></TD><TD>Patch
+ commands to send to the printer</TD></TR>
+<TR><TD><CODE>manufacturer</CODE></TD><TD><CODE>char *</CODE></TD><TD>
+The Manufacturer attribute from the PPD file, if any</TD></TR>
+<TR><TD><CODE>modelname</CODE></TD><TD><CODE>char *</CODE></TD><TD>The
+ ModelName attribute from the PPD file</TD></TR>
+<TR><TD><CODE>nickname</CODE></TD><TD><CODE>char *</CODE></TD><TD>The
+ NickName attribute from the PPD file, if any</TD></TR>
+<TR><TD><CODE>product</CODE></TD><TD><CODE>char *</CODE></TD><TD>The
+ Product attribute from the PPD file, if any</TD></TR>
+<TR><TD><CODE>shortnickname</CODE></TD><TD><CODE>char *</CODE></TD><TD>
+The ShortNickName attribute from the PPD file, if any</TD></TR>
+<TR><TD><CODE>throughput</CODE></TD><TD><CODE>int</CODE></TD><TD>Number
+ of pages per minute</TD></TR>
+<TR><TD><CODE>ttrasterizer</CODE></TD><TD><CODE>char *</CODE></TD><TD>
+The TruType font rasterizer (Type42)</TD></TR>
+<TR><TD><CODE>variable_sizes</CODE></TD><TD><CODE>int</CODE></TD><TD>1 =
+ supports variable sizes</TD></TR>
+</TABLE>
+</CENTER>
+</P>
+<H4>Options and Groups</H4>
+<P>PPD files support multiple options, which are stored in <CODE>
+ppd_option_t</CODE> and <CODE>ppd_choice_t</CODE> structures by the PPD
+ functions.</P>
+<P>Each option in turn is associated with a group stored in the <CODE>
+ppd_group_t</CODE> structure. Groups can be specified in the PPD file;
+ if an option is not associated with a group then it is put in a
+ &quot;General&quot; or &quot;Extra&quot; group depending on the option.</P>
+<P>Groups can also have sub-groups; CUPS currently limits the depth of
+ sub-groups to 1 level to reduce programming complexity.</P>
+<H4>Conflicts</H4>
+<P>PPD files support specification of conflict conditions between
+ different options. Conflicts are stored in <CODE>ppd_conflict_t</CODE>
+ structures which specify the options that conflict with each other.</P>
+<H4>Page Sizes</H4>
+<P>PPD files specify all of the available pages sizes and the physical
+ margins associated with them. These sizes are stored in <CODE>
+ppd_size_t</CODE> structures and are available in the <CODE>num_sizes</CODE>
+ and <CODE>sizes</CODE> members of the <CODE>ppd_file_t</CODE>
+ structure. You can lookup a particular page size with the <CODE>
+ppdPageWidth()</CODE>, <CODE>ppdPageLength()</CODE>, and <CODE>
+ppdPageSize()</CODE> functions:</P>
+<UL>
+<PRE>
+#include &lt;cups/ppd.h&gt;
+
+...
+
+ppd_file_t *ppd;
+ppd_size_t *size;
+float width;
+float length;
+
+...
+
+size = ppdPageSize(ppd, &quot;<I>size</I>&quot;);
+width = ppdPageWidth(ppd, &quot;<I>size</I>&quot;);
+length = ppdPageLength(ppd, &quot;<I>size</I>&quot;);
+</PRE>
+</UL>
+<P>The <CODE>size</CODE> string is the named page size option. The width
+ and length are in points; there are 72 points per inch. The <CODE>
+ppd_size_t</CODE> structure contains the width, length, and margin
+ information:</P>
+<UL>
+<PRE>
+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;
+</PRE>
+</UL>
+<H4>Custom Page Sizes</H4>
+<P>Besides the standard page sizes listed in a PPD file, some printers
+ support variable or custom page sizes. If <CODE>variables_sizes</CODE>
+ is non-zero, the <CODE>custom_min</CODE>, <CODE>custom_max</CODE>, and <CODE>
+custom_margins</CODE> members of the <CODE>ppd_file_t</CODE> structure
+ define the limits of the variable sizes.</P>
+<P>To get the resulting media size, use a page size string of <CODE>
+Custom.<I>width</I>x<I>length</I></CODE>, where <CODE>width</CODE> and <CODE>
+length</CODE> are integer values in points:</P>
+<UL>
+<PRE>
+Custom.612x792 [8.5 inches wide, 11 inches long]
+Custom.1224x792 [17 inches wide, 11 inches long]
+</PRE>
+</UL>
+<H3><A NAME="3_3_6">Marking Options</A></H3>
+<P>Before marking any user-defined options, call the <CODE>
+ppdMarkDefaults()</CODE> function to mark the default options from the
+ PPD file:</P>
+<UL>
+<PRE>
+#include &lt;cups/ppd.h&gt;
+
+...
+
+ppd_file_t *ppd;
+
+...
+
+ppdMarkDefaults(ppd);
+</PRE>
+</UL>
+<P>Then call the <CODE>ppdMarkOption()</CODE> function to mark
+ individual options:</P>
+<UL>
+<PRE>
+#include &lt;cups/ppd.h&gt;
+
+...
+
+ppd_file_t *ppd;
+int conflicts;
+
+...
+
+conflicts = ppdMarkOption(ppd, &quot;<I>name</I>&quot;, &quot;<I>value</I>&quot;);
+</PRE>
+</UL>
+<P>The <CODE>name</CODE> and <CODE>value</CODE> strings choose a
+ particular option and choice, respectively. The return value is 0 if
+ there are not conflicts created by the selection.</P>
+<P>CUPS also provides a convenience function for marking all options in
+ the <CODE>cups_option_t</CODE> structure:</P>
+<UL>
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+...
+
+ppd_file_t *ppd;
+int num_options;
+cups_option_t *options;
+int conflicts;
+
+...
+
+conflicts = cupsMarkOptions(ppd, num_options, options);
+</PRE>
+</UL>
+<P>The <CODE>cupsMarkOptions()</CODE> function also handles mapping the
+ IPP job template attributes to PPD options. The return value is the
+ number of conflicts present.</P>
+<H3><A NAME="3_3_7">Checking for Conflicts</A></H3>
+<P>The <CODE>ppdMarkOption()</CODE> and <CODE>cupsMarkOptions()</CODE>
+ functions return the number of conflicts with the currently marked
+ options.</P>
+<P>Call the <CODE>ppdConflicts()</CODE> function to get the number of
+ conflicts after you have marked all of the options:</P>
+<UL>
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+...
+
+ppd_file_t *ppd;
+int conflicts;
+
+...
+
+conflicts = ppdConflicts(ppd);
+</PRE>
+</UL>
+<P>The return value is the number of conflicting options, or 0 if there
+ are no conflicts.</P>
+<H1 ALIGN="RIGHT"><A NAME="WRITING_FILTERS">3 - Writing Filters</A></H1>
+<P>This chapter describes how to write a file filter for CUPS.</P>
+<H2><A NAME="4_1">Overview</A></H2>
+<P>File filters are programs that convert from one or more MIME types to
+ another type. Filters use a common command-line and environment
+ interface that allows them to be joined as needed to print files to any
+ type of printer.</P>
+<H3><A NAME="4_1_1">Security Considerations</A></H3>
+<P>Filters are normally run as a non-priviledged user, so the major
+ security consideration is resource utilization - filters should not
+ depend on unlimited amounts of memory and disk space.</P>
+<H3><A NAME="4_1_2">Users and Groups</A></H3>
+<P>The default CUPS configuration runs filters as user &quot;lp&quot; and group
+ &quot;other&quot;.</P>
+<H3><A NAME="4_1_3">Temporary Files</A></H3>
+<P>Temporary files should be created in the directory specified by the
+ &quot;TMPDIR&quot; environment variable. The<A HREF="#cupsTempFile"> <CODE>
+cupsTempFile()</CODE></A> function can be used to safely choose
+ temporary files in this directory.</P>
+<H3><A NAME="4_1_4">Sending Messages to the User</A></H3>
+<P>The CUPS scheduler collects messages sent to the standard error file
+ by the filter. These messages are relayed to the user based upon the
+ scheduler <CODE>LogLevel</CODE> directive.</P>
+<P>The type of message is determined by an initial prefix sent on each
+ line:</P>
+<UL>
+<LI><CODE>DEBUG:</CODE> - a debug message</LI>
+<LI><CODE>INFO:</CODE> - an informational message</LI>
+<LI><CODE>WARNING:</CODE> - a warning message</LI>
+<LI><CODE>ERROR:</CODE> - an error message</LI>
+<LI><CODE>PAGE:</CODE> - a page accounting message</LI>
+</UL>
+<P>If the line of text does not begin with any of the above prefixes, it
+ is treated as a debug message. Text following the prefix is copied to
+ the <CODE>printer-state-message</CODE> attribute for the printer, and
+ also added to the<VAR> error_log</VAR> unless it is an informational or
+ page accounting message.</P>
+<H3><A NAME="4_1_5">Page Accounting</A></H3>
+<P>Page accounting messages are used to inform the server when one or
+ more pages are printed. Each line has the form:</P>
+<UL>
+<PRE>
+PAGE: page-number copy-count
+</PRE>
+</UL>
+<P>The<I> page-number</I> field is the current page number, starting at
+ 1. The<I> copy-count</I> field specifies the number of copies of that
+ page that was produced.</P>
+<P>Page account messages are added to the<VAR> page_log</VAR> file and
+ cause the <CODE>job-sheets-completed</CODE> attribute to be updated for
+ the job.</P>
+<H3><A NAME="4_1_6">Command-Line Arguments</A></H3>
+<P>Every filter accepts exactly 6 or 7 command-line arguments:</P>
+<UL>
+<PRE>
+printer job user title copies options [filename]
+</PRE>
+<LI><CODE>printer</CODE> - The name of the printer queue (normally this
+ is the name of the program being run)</LI>
+<LI><CODE>job</CODE> - The numeric job ID for the job being printed</LI>
+<LI><CODE>user</CODE> - The string from the <CODE>originating-user-name</CODE>
+ attribute</LI>
+<LI><CODE>title</CODE> - The string from the <CODE>job-name</CODE>
+ attribute</LI>
+<LI><CODE>copies</CODE> - The numeric value from the <CODE>number-copies</CODE>
+ attribute</LI>
+<LI><CODE>options</CODE> - String representations of the job template
+ attributes, separated by spaces. Boolean attributes are provided as
+ &quot;name&quot; for true values and &quot;noname&quot; for false values. All other
+ attributes are provided as &quot;name=value&quot; for single-valued attributes
+ and &quot;name=value1,value2,...,valueN&quot; for set attributes</LI>
+<LI><CODE>filename</CODE> - The request file</LI>
+</UL>
+<P>The<I> filename</I> argument is only provided to the first filter in
+ the chain; all filters<B> must</B> be prepared to read the print file
+ from the standard input if the<I> filename</I> argument is omitted.</P>
+<H3><A NAME="4_1_7">Copy Generation</A></H3>
+<P>The<I> copies</I> argument specifies the number of copies to produce
+ of the input file. In general, you should only generate copies if the<I>
+ filename</I> argument is supplied. The only exception to this are
+ filters that produce device-independent PostScript output (without any
+ printer commands from the printer's PPD file), since the PostScript
+ filter <CODE>pstops</CODE> is responsible for copy generation.</P>
+<H3><A NAME="4_1_8">Environment Variables</A></H3>
+<P>Every filter receives a fixed set of environment variables that can
+ be used by the filter:</P>
+<UL>
+<LI><CODE>CHARSET</CODE> - The character set used by the client for this
+ print file</LI>
+<LI><CODE>CONTENT_TYPE</CODE> - The original document type, such as
+ &quot;application/postscript&quot;</LI>
+<LI><CODE>CUPS_DATADIR</CODE> - The location of CUPS data files</LI>
+<LI><CODE>CUPS_SERVERROOT</CODE> - The location of CUPS configuration
+ files</LI>
+<LI><CODE>DEVICE_URI</CODE> - The output device URI</LI>
+<LI><CODE>LANG</CODE> - The language used by the client for this print
+ file</LI>
+<LI><CODE>PATH</CODE> - The execution path exported to the filter</LI>
+<LI><CODE>PPD</CODE> - The full filename of the printer's PPD file</LI>
+<LI><CODE>PRINTER</CODE> - The name of the printer queue</LI>
+<LI><CODE>RIP_CACHE</CODE> - The maximum amount of memory each filter
+ should use</LI>
+<LI><CODE>SOFTWARE</CODE> - The name of the CUPS software, typically
+ &quot;CUPS/1.1&quot;</LI>
+<LI><CODE>TZ</CODE> - The local timezone</LI>
+<LI><CODE>USER</CODE> - The name of the current user</LI>
+</UL>
+<H2><A NAME="4_2">Dissecting the HP-GL/2 Filter</A></H2>
+<P>The HP-GL/2 filter (<CODE>hpgltops</CODE>) provided with CUPS is a
+ complex program that converts HP-GL/2 files into device-independent
+ PostScript output. Since it produces device-independent PostScript
+ output, it does not need to handle copy generation or writing printer
+ options from the printer's PPD file.</P>
+<H3><A NAME="4_2_1">Initializing the Filter</A></H3>
+<P>The first task of any filter is to ensure that the correct number of
+ command-line arguments are present:</P>
+<UL>
+<PRE>
+if (argc &lt; 6 || argc &gt; 7)
+{
+ fputs(&quot;ERROR: hpgltops job-id user title copies options [file]\n&quot;, stderr);
+ return (1);
+}
+</PRE>
+</UL>
+<P>After this you open the print file or read from the standard input as
+ needed:</P>
+<UL>
+<PRE>
+FILE *fp;
+
+/*
+ * 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], &quot;rb&quot;)) == NULL)
+ {
+ perror(&quot;ERROR: unable to open print file - &quot;);
+ return (1);
+ }
+}
+</PRE>
+</UL>
+<P>Once the print file has been opened, options can be processed using
+ the<A HREF="#cupsParseOptions"> <CODE>cupsParseOptions()</CODE></A> and<A
+HREF="#cupsGetOption"> <CODE>cupsGetOption()</CODE></A> functions:</P>
+<UL>
+<PRE>
+int num_options;
+cups_option_t *options;
+const char *val;
+
+/*
+ * Process command-line options and write the prolog...
+ */
+
+options = NULL;
+num_options = cupsParseOptions(argv[5], 0,
+
+if ((val = cupsGetOption(&quot;blackplot&quot;, num_options, options)) != NULL)
+ shading = 0;
+
+if ((val = cupsGetOption(&quot;fitplot&quot;, num_options, options)) != NULL)
+ FitPlot = 1;
+
+if ((val = cupsGetOption(&quot;penwidth&quot;, num_options, options)) != NULL)
+ PenWidth = (float)atoi(val) * 0.001f;
+</PRE>
+</UL>
+<P>After the options have been processed, the filter writes PostScript
+ code to the standard output based on the print file, closes the print
+ file (as needed), and returns 0 to the scheduler.</P>
+<H2><A NAME="4_3">PostScript Output</A></H2>
+<P>Filters that produce PostScript output must generate output
+ conforming to the Adobe Document Structuring Conventions, 3.0. In
+ general this means the beginning of each file must begin with:</P>
+<UL>
+<PRE>
+%!PS-Adobe-3.0
+%%BoundingBox: left bottom right top
+%%Pages: (atend)
+%%EndComments
+</PRE>
+</UL>
+<P>The<I> left</I>,<I> bottom</I>,<I> right</I>, and<I> top</I> values
+ are integers in points from the lower-lefthand corner of the page.</P>
+<P>Pages must be surrounded by:</P>
+<UL>
+<PRE>
+%%Page: number number
+gsave
+...
+grestore
+showpage
+</PRE>
+</UL>
+<P>And the end of each file must contain:</P>
+<UL>
+<PRE>
+%%Trailer
+%%Pages: number-pages
+%%EOF
+</PRE>
+</UL>
+<P>These comments allow the PostScript filter to correctly perform page
+ accounting, copy generation, N-up printing, and so forth.</P>
+<H1 ALIGN="RIGHT"><A NAME="WRITING_DRIVERS">4 - Writing Printer Drivers</A>
+</H1>
+<P>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.</P>
+<H2><A NAME="5_1">Overview</A></H2>
+<P>Raster printers utilitize PPD files that specify one or more
+ device-specific filters that handle converting print files for the
+ printer. The simplest raster printer drivers provide a single filter
+ that converts CUPS raster data to the printer's native format.</P>
+<H3><A NAME="5_1_1">CUPS Raster Data</A></H3>
+<P>CUPS raster data (<CODE>application/vnd.cups-raster</CODE>) consists
+ of a stream of raster page descriptions produced by one of the RIP
+ filters, such as <CODE>pstoraster</CODE> or <CODE>imagetoraster</CODE>.</P>
+<P>Each page of data begins with a page dictionary structure called<A HREF="#cups_raster_header_t">
+ <CODE>cups_raster_header_t</CODE></A>. This structure contains the
+ colorspace, bits per color, media size, media type, hardware
+ resolution, and so forth.</P>
+<P>After the page dictionary comes the page data which is a
+ full-resolution, uncompressed bitmap representing the page in the
+ printer's output colorspace.</P>
+<H3><A NAME="5_1_2">Page Accounting</A></H3>
+<P>Printer drivers must handle all page accounting. This means they must
+ send &quot;PAGE:&quot; messages to the standard error file for each page (and in
+ many cases, copy) sent to the printer.</P>
+<H3><A NAME="5_1_3">Color Management</A></H3>
+<P>Printer drivers can implement their color management via the <CODE>
+cupsColorProfile</CODE> attributes in the PPD file or internally in the
+ driver from a device-independent colorspace. In general, color
+ management performed by the RIP filters is more efficient than that
+ performed inside printer drivers.</P>
+<P>For example, the <CODE>pstoraster</CODE> filter often only has to
+ perform a color conversion once each time the color is used for
+ multiple output pixels, while the raster filter must convert every
+ pixel on the page.</P>
+<H3><A NAME="5_1_4">Device and Bitmap Variables</A></H3>
+<P>Besides the standard PostScript page device dictionary variables
+ defined in the Adobe PostScript Level 3 reference manual, the CUPS
+ filters support additional variables that are passed in the page device
+ dictionary header for the page and in some cases control the type of
+ raster data that is generated:
+<CENTER>
+<TABLE BORDER="1" WIDTH="90%">
+<TR><TH>Variable</TH><TH>Type</TH><TH>Description</TH></TR>
+<TR><TD>cupsWidth</TD><TD>read-only integer</TD><TD>Width of bitmap in
+ pixels</TD></TR>
+<TR><TD>cupsHeight</TD><TD>read-only integer</TD><TD>Height of bitmap in
+ pixels</TD></TR>
+<TR><TD>cupsMediaType</TD><TD>read-write integer</TD><TD>Device-specific
+ media type code</TD></TR>
+<TR><TD>cupsBitsPerColor</TD><TD>read-write integer</TD><TD>Number of
+ bits per color; 1, 2, 4, and 8 are currently supported</TD></TR>
+<TR><TD>cupsBitsPerPixel</TD><TD>read-only integer</TD><TD>Number of
+ bits per pixel; 1 to 32</TD></TR>
+<TR><TD>cupsBytesPerLine</TD><TD>read-only integer</TD><TD>Number of
+ bytes per line of raster graphics</TD></TR>
+<TR><TD>cupsColorOrder</TD><TD>read-write enum</TD><TD>The order of
+ color values in the bitmap:
+<UL>
+<LI><CODE>CUPS_ORDER_CHUNKED</CODE> - CMYK&nbsp;CMYK&nbsp;CMYK</LI>
+<LI><CODE>CUPS_ORDER_BANDED</CODE> - CCC&nbsp;MMM&nbsp;YYY&nbsp;KKK</LI>
+<LI><CODE>CUPS_ORDER_PLANAR</CODE> - CCC&nbsp;...&nbsp;MMM&nbsp;...&nbsp;YYY&nbsp;...&nbsp;KKK&nbsp;...</LI>
+</UL>
+</TD></TR>
+<TR><TD>cupsColorSpace</TD><TD>read-write enum</TD><TD>The colorspace of
+ the bitmap:
+<UL>
+<LI><CODE>CUPS_CSPACE_W</CODE> - White (luminance)</LI>
+<LI><CODE>CUPS_CSPACE_RGB</CODE> - Red, green, blue</LI>
+<LI><CODE>CUPS_CSPACE_RGBA</CODE> - Red, green, blue, alpha</LI>
+<LI><CODE>CUPS_CSPACE_K</CODE> - Black</LI>
+<LI><CODE>CUPS_CSPACE_CMY</CODE> - Cyan, magenta, yellow</LI>
+<LI><CODE>CUPS_CSPACE_YMC</CODE> - Yellow, magenta, cyan</LI>
+<LI><CODE>CUPS_CSPACE_CMYK</CODE> - Cyan, magenta, yellow, black</LI>
+<LI><CODE>CUPS_CSPACE_YMCK</CODE> - Yellow, magenta, cyan, black</LI>
+<LI><CODE>CUPS_CSPACE_KCMY</CODE> - Black, cyan, magenta, yellow</LI>
+<LI><CODE>CUPS_CSPACE_KCMYcm</CODE> - Black, cyan, magenta, yellow,
+ light cyan, light magenta</LI>
+<LI><CODE>CUPS_CSPACE_GMCK</CODE> - Metallic yellow (gold), metallic
+ magenta, metallic cyan, black</LI>
+<LI><CODE>CUPS_CSPACE_GMCS</CODE> - Metallic yellow (gold), metallic
+ magenta, metallic cyan, metallic grey (silver)</LI>
+<LI><CODE>CUPS_CSPACE_WHITE</CODE> - White pigment (black as white
+ pigment)</LI>
+<LI><CODE>CUPS_CSPACE_GOLD</CODE> - Gold foil (black as gold foil)</LI>
+<LI><CODE>CUPS_CSPACE_SILVER</CODE> - Silver foil (black as silver foil)</LI>
+</UL>
+</TD></TR>
+<TR><TD>cupsCompression</TD><TD>read-write integer</TD><TD>
+Device-specific compression type code</TD></TR>
+<TR><TD>cupsRowCount</TD><TD>read-write integer</TD><TD>Device-specific
+ row count value</TD></TR>
+<TR><TD>cupsRowFeed</TD><TD>read-write integer</TD><TD>Device-specific
+ row feed value</TD></TR>
+<TR><TD>cupsRowStep</TD><TD>read-write integer</TD><TD>Device-specific
+ row step value</TD></TR>
+</TABLE>
+</CENTER>
+</P>
+<P>Bitmaps with a colorspace of CUPS_CSPACE_KCMYcm and more than 1 bit
+ per color are transmitted to the raster driver in KCMY colorspace; the
+ driver is responsible for producing the correct separation of normal
+ and light cyan and magenta inks.</P>
+<H2><A NAME="5_2">Dissecting the HP-PCL Driver</A></H2>
+<P>The HP-PCL driver provided with CUPS (<CODE>rastertohp</CODE>)
+ converts bitmap data from the raster filters into HP-PCL commands for
+ most PCL-compatible printers. The actual format of the raster data is
+ controlled by the PPD file being used -<VAR> deskjet.ppd</VAR> or<VAR>
+ laserjet.ppd</VAR>.</P>
+<H3><A NAME="5_2_1">PPD Files</A></H3>
+<P>PPD files play an important part of all raster printer drivers.
+ Options defined in the PPD file contain PostScript commands that
+ control the raster data that is sent to the printer driver.</P>
+<P>A typical CUPS printer driver will include <CODE>ColorModel</CODE>, <CODE>
+InputSlot</CODE>, <CODE>PageSize</CODE>, <CODE>PageRegion</CODE>, and <CODE>
+Resolution</CODE> options. Each option is shown using the standard PPD
+ format:</P>
+<UL>
+<PRE>
+*OpenUI *PageSize/Media Size: PickOne
+*OrderDependency: 10 AnySetup *PageSize
+*DefaultPageSize: Letter
+*PageSize Letter/US Letter: &quot;&lt;&lt;
+/PageSize [612 792]
+/ImagingBBox null
+&gt;&gt; setpagedevice&quot;
+*End
+*PageSize Legal/US Legal: &quot;&lt;&lt;
+/PageSize [612 1008]
+/ImagingBBox null
+&gt;&gt; setpagedevice&quot;
+*End
+*PageSize A4/A4: &quot;&lt;&lt;
+/PageSize [595 842]
+/ImagingBBox null
+&gt;&gt; setpagedevice&quot;
+*End
+*CloseUI: *PageSize
+</PRE>
+</UL>
+<P>The <CODE>OpenUI</CODE> keyword specifies the new option. The first
+ name is the option with an asterisk (*) in front of it. The first name
+ is usually followed by a slash (/) and a human-readable version of the
+ option name.</P>
+<P>Every option<B> must</B> have a default value, specified using the <CODE>
+Default<I>Option</I></CODE> keyword.</P>
+<P>Each option begins with the option name followed by the computer and
+ human-readable values. The PostScript commands follow these inside
+ double quotes. PostScript commands can be provided on a single line:</P>
+<UL>
+<PRE>
+*PageSize A4/A4: &quot;&lt;&lt;/PageSize[595 842]/ImagingBBox null&gt;&gt; setpagedevice&quot;
+</PRE>
+</UL>
+<P>or broken down on separate lines using the <CODE>End</CODE> keyword
+ to terminate them:</P>
+<UL>
+<PRE>
+*PageSize A4/A4: &quot;&lt;&lt;
+/PageSize [595 842]
+/ImagingBBox null
+&gt;&gt; setpagedevice&quot;
+*End
+</PRE>
+</UL>
+<P>The choice of the two formats is usually esthetic. However, each line
+ in a PPD file must not exceed 255 characters, so if your PostScript
+ commands are long you may need to break them up on separate lines.</P>
+<H3><A NAME="5_2_2">Reading Raster Data</A></H3>
+<P>As with any filter, your printer driver should handle raster data
+ from a filename specified on the command-line or from the standard
+ input. The<A HREF="#cupsRasterOpen"> <CODE>cupsRasterOpen()</CODE></A>
+ function opens a raster stream for printing:</P>
+<UL>
+<PRE>
+int fd; /* File descriptor */
+cups_raster_t *ras; /* Raster stream for printing */
+
+
+/*
+ * Check for valid arguments...
+ */
+
+if (argc &lt; 6 || argc &gt; 7)
+{
+ /*
+ * We don't have the correct number of arguments; write an error message
+ * and return.
+ */
+
+ fputs(&quot;ERROR: rastertopcl job-id user title copies options [file]\n&quot;, stderr);
+ return (1);
+}
+
+/*
+ * Open the page stream...
+ */
+
+if (argc == 7)
+{
+ if ((fd = open(argv[6], O_RDONLY)) == -1)
+ {
+ perror(&quot;ERROR: Unable to open raster file - &quot;);
+ sleep(1);
+ return (1);
+ }
+}
+else
+ fd = 0;
+
+ras = cupsRasterOpen(fd, CUPS_RASTER_READ);
+</PRE>
+</UL>
+<P>Once you have opened the raster stream you just need to read each
+ page and print it:</P>
+<UL>
+<PRE>
+cups_raster_header_t header;
+int y;
+unsigned char data[8192];
+
+while (cupsRasterReadHeader(ras, &amp;header))
+{
+ ... initialize the printer ...
+ for (y = header.cupsHeight; y &gt; 0; y ++)
+ {
+ cupsRasterReadPixels(ras, data, header.cupsBytesPerLine);
+ ... send raster line to printer ...
+ }
+}
+</PRE>
+</UL>
+<P>After you have processed all pages, close the raster stream and
+ return:</P>
+<UL>
+<PRE>
+cupsRasterClose(ras);
+
+return (0);
+</PRE>
+</UL>
+<H1 ALIGN="RIGHT"><A NAME="WRITING_BACKENDS">5 - Writing Backends</A></H1>
+<P>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.</P>
+<H2><A NAME="6_1">Overview</A></H2>
+<P>Backends are special filters that communicate with printers directly.
+ They are treated slightly differently than filters, however, and have
+ some unique requirements.</P>
+<H3><A NAME="6_1_1">Security Considerations</A></H3>
+<P>Backends are run as the root user, so special care must be taken to
+ avoid potential security violations. In particular, remember that a
+ backend will be able to manipulate disk files, devices, and other
+ resources that potentially could damage a system or printer.</P>
+<H3><A NAME="6_1_2">Command-Line Arguments</A></H3>
+<P>Besides the standard filter arguments, backends are also run with no
+ arguments to get a list of available devices. This discovery process is
+ described later in this chapter.</P>
+<H3><A NAME="6_1_3">Copy Generation</A></H3>
+<P>Like filters, backends should send multiple copies of the print file
+ only if a filename is supplied on the command-line. Otherwise the
+ backend should assume that the upstream filter has already added the
+ necessary commands or data to produce the multiple copies.</P>
+<H3><A NAME="6_1_4">Page Accounting</A></H3>
+<P>Backend filters generally do not do page accounting, however they
+ should at a minimum produce a single page message for each copy that is
+ produced when a filename is present on the command-line. This is
+ because the user selected &quot;raw&quot; printing and no other accounting
+ information is possible.</P>
+<H3><A NAME="6_1_5">Exclusive Access</A></H3>
+<P>Backends that talk to local character or block devices should open
+ the device file in exclusive mode (<CODE>O_EXCL</CODE>) to cooperate
+ with other printers defined for the same device.</P>
+<H3><A NAME="6_1_6">Retries</A></H3>
+<P>All backends<B> must</B> retry connections to the device. This
+ includes backends that talk to local character or block devices, as the
+ user may define more than one printer queue pointing at the same
+ physical device.</P>
+<P>To prevent excess CPU utilitization, the backend should go to sleep
+ for an amount of time between retries; the CUPS-supplied backends retry
+ once every 30 seconds.</P>
+<H2><A NAME="6_2">Dissecting the Serial Port Backend</A></H2>
+<P>The serial port backend provides support for serial printers. Since
+ it does everything a good backend needs to do, it provides an excellent
+ example of what to do.</P>
+<H3><A NAME="6_2_1">Supporting Device Discovery</A></H3>
+<P>As previously noted, backends are special filter programs that talk
+ to printer devices. Another task a backend must perform is to list the
+ available devices it supports. The backend lists the available devices
+ when no additioanl arguments are supplied on the command-line (i.e.
+ just the command name...)</P>
+<P>The serial backend lists devices by looking at serial port files in
+ the<VAR> /dev</VAR> directory, by consulting a hardware inventory
+ (IRIX), and in some cases by trying to open the ports to see if they
+ actually exist.</P>
+<P>Once it finds a serial port it writes a single line for each port to
+ the standard error file. Each line looks like this:</P>
+<UL>
+<PRE>
+serial serial:/dev/ttyS0?baud=115200 &quot;Unknown&quot; &quot;Serial Port 1&quot;
+</PRE>
+</UL>
+<P>The first word &quot;serial&quot; is the<I> device class</I>; this identifies
+ the class of device which can be used to categorize it in user
+ interfaces. CUPS currently recognizes the following classes:</P>
+<UL>
+<LI>&quot;file&quot; - a disk file.</LI>
+<LI>&quot;direct&quot; - a parallel or fixed-rate serial data port, currently used
+ for Centronics, IEEE-1284, and USB printer ports.</LI>
+<LI>&quot;serial&quot; - a variable-rate serial port.</LI>
+<LI>&quot;network&quot; - a network connection, typically via AppSocket, HTTP,
+ IPP, LPD, or SMB/CIFS protocols.</LI>
+</UL>
+<P>After the device class is the<I> device URI</I>, in this case
+ &quot;serial:/dev/ttyS0?baud=115200&quot;. This is the URI that should be used by
+ the user to select this port. For serial ports, the &quot;baud=115200&quot;
+ specifies the maximum baud rate supported by the port - the actual
+ value will vary based on the speed the user selects for the printer.</P>
+<P>The last two strings are the model and description for the port. The
+ &quot;Unknown&quot; string means that the printer model is unknown - some devices
+ are able to provide a make and model such as &quot;HP DeskJet&quot; that allows
+ users and software to choose an appropriate printer driver more easily.
+ Both the model and description must be enclosed inside double quotes.</P>
+<H3><A NAME="6_2_2">Opening the Serial Port</A></H3>
+<P>As noted previously, all backends should open device files in
+ exclusive mode, and retry as needed until the port is available. The
+ serial port does this using a <CODE>do-while</CODE> loop:</P>
+<UL>
+<PRE>
+do
+{
+ if ((fd = open(resource, O_WRONLY | O_NOCTTY | O_EXCL)) == -1)
+ {
+ if (errno == EBUSY)
+ {
+ fputs(&quot;INFO: Serial port busy; will retry in 30 seconds...\n&quot;, stderr);
+ sleep(30);
+ }
+ else
+ {
+ perror(&quot;ERROR: Unable to open serial port device file&quot;);
+ return (1);
+ }
+ }
+}
+while (fd &lt; 0);
+</PRE>
+</UL>
+<P>If the port is busy or in use by another process, the backend will go
+ to sleep for 30 seconds and try again. If another error is detected a
+ message is sent to the user and the backend aborts the print job until
+ the problem can be corrected.</P>
+<H3><A NAME="6_2_3">Writing Data to the Port</A></H3>
+<P>Network and character devices pose an interesting problem when
+ writing data to the port - they may not be able to write all of the
+ bytes in your buffer before returning. To work around this problem you
+ must loop until all bytes have been written:</P>
+<UL>
+<PRE>
+while (nbytes &gt; 0)
+{
+ if ((wbytes = write(fd, bufptr, nbytes)) &lt; 0)
+ if (errno == ENOTTY)
+ wbytes = write(fd, bufptr, nbytes);
+
+ if (wbytes &lt; 0)
+ {
+ perror(&quot;ERROR: Unable to send print file to printer&quot;);
+ break;
+ }
+
+ nbytes -= wbytes;
+ bufptr += wbytes;
+}
+</PRE>
+</UL>
+<P>The check for the <CODE>ENOTTY</CODE> error is needed on some
+ platforms to clear an error from a previous <CODE>ioctl()</CODE> call.</P>
+<H3><A NAME="6_2_4">Finishing Up</A></H3>
+<P>Once you have sent the print file, return 0 if the file printed
+ successfully or 1 if it did not. This will allow the scheduler to stop
+ the print job if there is a device error, preserving the print job for
+ later printing once the problem has been corrected.</P>
+<H1 ALIGN="RIGHT"><A NAME="LICENSE">A - Software License Agreement</A></H1>
+<H2 ALIGN="CENTER"><A NAME="7_1">Common UNIX Printing System License
+ Agreement</A></H2>
+<P ALIGN="CENTER">Copyright 1997-2002 by Easy Software Products
+<BR> 44141 AIRPORT VIEW DR STE 204
+<BR> HOLLYWOOD, MARYLAND 20636-3111 USA
+<BR>
+<BR> Voice: +1.301.373.9600
+<BR> Email:<A HREF="mailto:cups-info@cups.org"> cups-info@cups.org</A>
+<BR> WWW:<A HREF="http://www.cups.org"> http://www.cups.org</A></P>
+<H3><A NAME="7_1_1">Introduction</A></H3>
+<P>The Common UNIX Printing System<SUP>TM</SUP>, (&quot;CUPS<SUP>TM</SUP>&quot;),
+ is provided under the GNU General Public License (&quot;GPL&quot;) and GNU
+ Library General Public License (&quot;LGPL&quot;), Version 2. A copy of these
+ licenses follow this introduction.</P>
+<P>The GNU LGPL applies to the CUPS API library, located in the &quot;cups&quot;
+ subdirectory of the CUPS source distribution and in the
+ &quot;/usr/include/cups&quot; directory and &quot;libcups.a&quot;, &quot;libcups_s.a&quot;,
+ &quot;libcups.sl&quot;, or &quot;libcups.so&quot; files in the binary distributions.</P>
+<P>The GNU GPL applies to the remainder of the CUPS distribution,
+ including the &quot;pstoraster&quot; filter which is based upon GNU Ghostscript
+ 5.50 and the &quot;pdftops&quot; filter which is based upon Xpdf 0.93a.</P>
+<P>For those not familiar with the GNU GPL, the license basically allows
+ you to:</P>
+<UL>
+<LI>Use the CUPS software at no charge.</LI>
+<LI>Distribute verbatim copies of the software in source or binary form.</LI>
+<LI>Sell verbatim copies of the software for a media fee, or sell
+ support for the software.</LI>
+<LI>Distribute or sell printer drivers and filters that use CUPS so long
+ as source code is made available under the GPL.</LI>
+</UL>
+<P>What this license<B> does not</B> allow you to do is make changes or
+ add features to CUPS and then sell a binary distribution without source
+ code. You must provide source for any new drivers, changes, or
+ additions to the software, and all code must be provided under the GPL
+ or LGPL as appropriate.</P>
+<P>The GNU LGPL relaxes the &quot;link-to&quot; restriction, allowing you to
+ develop applications that use the CUPS API library under other licenses
+ and/or conditions as appropriate for your application.</P>
+<H3><A NAME="7_1_2">Trademarks</A></H3>
+<P>Easy Software Products has trademarked the Common UNIX Printing
+ System, CUPS, and CUPS logo. These names and logos may be used freely
+ in any direct port or binary distribution of CUPS. To use them in
+ derivative products, please contract Easy Software Products for written
+ permission. Our intention is to protect the value of these trademarks
+ and ensure that any derivative product meets the same high-quality
+ standards as the original.</P>
+<H3><A NAME="7_1_3">Binary Distribution Rights</A></H3>
+<P>Easy Software Products also sells rights to the CUPS source code
+ under a binary distribution license for vendors that are unable to
+ release source code for their drivers, additions, and modifications to
+ CUPS under the GNU GPL and LGPL. For information please contact us at
+ the address shown above.</P>
+<P>The Common UNIX Printing System provides a &quot;pstoraster&quot; filter that
+ utilizes the GNU GhostScript 5.50 core to convert PostScript files into
+ a stream of raster images. For binary distribution licensing of this
+ software, please contact:<BLOCKQUOTE> Miles Jones
+<BR> Director of Marketing
+<BR> Artifex Software Inc.
+<BR> 454 Las Gallinas Ave., Suite 108
+<BR> San Rafael, CA 94903 USA
+<BR> Voice: +1.415.492.9861
+<BR> Fax: +1.415.492.9862
+<BR> EMail:<A HREF="mailto:info@arsoft.com"> info@arsoft.com</A></BLOCKQUOTE>
+</P>
+<P>The &quot;pdftops&quot; filter is based on the Xpdf 0.93a software. For binary
+ distribution licensing of this software, please contact:<BLOCKQUOTE>
+ Derek B. Noonburg
+<BR> Email:<A HREF="mailto:derekn@foolabs.com"> derekn@foolabs.com</A>
+<BR> WWW:<A HREF="http://www.foolabs.com/xpdf/">
+ http://www.foolabs.com/xpdf/</A></BLOCKQUOTE></P>
+<H3><A NAME="7_1_4">Support</A></H3>
+<P>Easy Software Products sells software support for CUPS as well as a
+ commercial printing product based on CUPS called ESP Print Pro. You can
+ find out more at our web site:</P>
+<UL>
+<PRE>
+<A HREF="http://www.easysw.com">http://www.easysw.com</A>
+</PRE>
+</UL>
+
+<!-- NEW PAGE -->
+<H2><A NAME="7_2">GNU GENERAL PUBLIC LICENSE</A></H2>
+<P>Version 2, June 1991</P>
+<PRE>
+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.
+</PRE>
+<PRE>
+
+</PRE>
+<H4>Preamble</H4>
+<P>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.</P>
+<P>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.</P>
+<P>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.</P>
+<P>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.</P>
+<P>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.</P>
+<P>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.</P>
+<P>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.</P>
+<P>The precise terms and conditions for copying, distribution and
+ modification follow.</P>
+<H4>GNU GENERAL PUBLIC LICENSE
+<BR> TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION</H4>
+<OL START="0">
+<LI>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 &quot;Program&quot;, below,
+ refers to any such program or work, and a &quot;work based on the Program&quot;
+ 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 &quot;modification&quot;.) Each licensee is addressed as &quot;you&quot;.</LI>
+<P>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.</P>
+<LI>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.</LI>
+<P>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.</P>
+<LI>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:
+<OL TYPE="a">
+<LI>You must cause the modified files to carry prominent notices stating
+ that you changed the files and the date of any change.</LI>
+<LI>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.</LI>
+<LI>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.)</LI>
+</OL>
+</LI>
+<P>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.</P>
+<P>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.</P>
+<P>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.</P>
+<LI>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:
+<OL TYPE="a">
+<LI>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,</LI>
+<LI>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,</LI>
+<LI>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.)</LI>
+</OL>
+</LI>
+<P>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.</P>
+<P>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.</P>
+<LI>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.</LI>
+<LI>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.</LI>
+<LI>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.</LI>
+<LI>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.</LI>
+<P>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.</P>
+<P>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.</P>
+<P>This section is intended to make thoroughly clear what is believed to
+ be a consequence of the rest of this License.</P>
+<LI>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.</LI>
+<LI>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.</LI>
+<P>Each version is given a distinguishing version number. If the Program
+ specifies a version number of this License which applies to it and &quot;any
+ later version&quot;, 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.</P>
+<LI>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.</LI>
+</OL>
+<H4>NO WARRANTY</H4>
+<OL START="11">
+<LI>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 &quot;AS IS&quot; 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.</LI>
+<LI>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.</LI>
+</OL>
+<H4>END OF TERMS AND CONDITIONS</H4>
+
+<!-- NEW PAGE -->
+<H2><A NAME="7_3">GNU LIBRARY GENERAL PUBLIC LICENSE</A></H2>
+<P>Version 2, June 1991</P>
+<PRE>
+Copyright (C) 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.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+</PRE>
+<H4>Preamble</H4>
+<P>The licenses for most software are designed to take away your freedom
+ to share and change it. By contrast, the GNU General Public Licenses
+ are intended to guarantee your freedom to share and change free
+ software--to make sure the software is free for all its users.</P>
+<P>This license, the Library General Public License, applies to some
+ specially designated Free Software Foundation software, and to any
+ other libraries whose authors decide to use it. You can use it for your
+ libraries, too.</P>
+<P>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.</P>
+<P>To protect your rights, we need to make restrictions that forbid
+ anyone to deny you these rights or to ask you to surrender the rights.
+ These restrictions translate to certain responsibilities for you if you
+ distribute copies of the library, or if you modify it.</P>
+<P>For example, if you distribute copies of the library, whether gratis
+ or for a fee, you must give the recipients all the rights that we gave
+ you. You must make sure that they, too, receive or can get the source
+ code. If you link a program with the library, you must provide complete
+ object files to the recipients so that they can relink them with the
+ library, after making changes to the library and recompiling it. And
+ you must show them these terms so they know their rights.</P>
+<P>Our method of protecting your rights has two steps: (1) copyright the
+ library, and (2) offer you this license which gives you legal
+ permission to copy, distribute and/or modify the library.</P>
+<P>Also, for each distributor's protection, we want to make certain that
+ everyone understands that there is no warranty for this free library.
+ If the library is modified by someone else and passed on, we want its
+ recipients to know that what they have is not the original version, so
+ that any problems introduced by others will not reflect on the original
+ authors' reputations.</P>
+<P>Finally, any free program is threatened constantly by software
+ patents. We wish to avoid the danger that companies distributing free
+ software will individually obtain patent licenses, thus in effect
+ transforming the program into proprietary software. To prevent this, we
+ have made it clear that any patent must be licensed for everyone's free
+ use or not licensed at all.</P>
+<P>Most GNU software, including some libraries, is covered by the
+ ordinary GNU General Public License, which was designed for utility
+ programs. This license, the GNU Library General Public License, applies
+ to certain designated libraries. This license is quite different from
+ the ordinary one; be sure to read it in full, and don't assume that
+ anything in it is the same as in the ordinary license.</P>
+<P>The reason we have a separate public license for some libraries is
+ that they blur the distinction we usually make between modifying or
+ adding to a program and simply using it. Linking a program with a
+ library, without changing the library, is in some sense simply using
+ the library, and is analogous to running a utility program or
+ application program. However, in a textual and legal sense, the linked
+ executable is a combined work, a derivative of the original library,
+ and the ordinary General Public License treats it as such.</P>
+<P>Because of this blurred distinction, using the ordinary General
+ Public License for libraries did not effectively promote software
+ sharing, because most developers did not use the libraries. We
+ concluded that weaker conditions might promote sharing better.</P>
+<P>However, unrestricted linking of non-free programs would deprive the
+ users of those programs of all benefit from the free status of the
+ libraries themselves. This Library General Public License is intended
+ to permit developers of non-free programs to use free libraries, while
+ preserving your freedom as a user of such programs to change the free
+ libraries that are incorporated in them. (We have not seen how to
+ achieve this as regards changes in header files, but we have achieved
+ it as regards changes in the actual functions of the Library.) The hope
+ is that this will lead to faster development of free libraries.</P>
+<P>The precise terms and conditions for copying, distribution and
+ modification follow. Pay close attention to the difference between a
+ &quot;work based on the library&quot; and a &quot;work that uses the library&quot;. The
+ former contains code derived from the library, while the latter only
+ works together with the library.</P>
+<P>Note that it is possible for a library to be covered by the ordinary
+ General Public License rather than by this special one.</P>
+<H4>TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION</H4>
+<P><STRONG>0.</STRONG> This License Agreement applies to any software
+ library which contains a notice placed by the copyright holder or other
+ authorized party saying it may be distributed under the terms of this
+ Library General Public License (also called &quot;this License&quot;). Each
+ licensee is addressed as &quot;you&quot;.</P>
+<P>A &quot;library&quot; means a collection of software functions and/or data
+ prepared so as to be conveniently linked with application programs
+ (which use some of those functions and data) to form executables.</P>
+<P>The &quot;Library&quot;, below, refers to any such software library or work
+ which has been distributed under these terms. A &quot;work based on the
+ Library&quot; means either the Library or any derivative work under
+ copyright law: that is to say, a work containing the Library or a
+ portion of it, either verbatim or with modifications and/or translated
+ straightforwardly into another language. (Hereinafter, translation is
+ included without limitation in the term &quot;modification&quot;.)</P>
+<P>&quot;Source code&quot; for a work means the preferred form of the work for
+ making modifications to it. For a library, complete source code means
+ all the source code for all modules it contains, plus any associated
+ interface definition files, plus the scripts used to control
+ compilation and installation of the library.</P>
+<P>Activities other than copying, distribution and modification are not
+ covered by this License; they are outside its scope. The act of running
+ a program using the Library is not restricted, and output from such a
+ program is covered only if its contents constitute a work based on the
+ Library (independent of the use of the Library in a tool for writing
+ it). Whether that is true depends on what the Library does and what the
+ program that uses the Library does.</P>
+<P><STRONG>1.</STRONG> You may copy and distribute verbatim copies of
+ the Library's complete source code as you receive it, in any medium,
+ provided that you conspicuously and appropriately publish on each copy
+ an appropriate copyright notice and disclaimer of warranty; keep intact
+ all the notices that refer to this License and to the absence of any
+ warranty; and distribute a copy of this License along with the Library.</P>
+<P>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.</P>
+<P><STRONG>2.</STRONG> You may modify your copy or copies of the Library
+ or any portion of it, thus forming a work based on the Library, and
+ copy and distribute such modifications or work under the terms of
+ Section 1 above, provided that you also meet all of these conditions:</P>
+<OL TYPE="a">
+<LI>The modified work must itself be a software library.</LI>
+<P></P>
+<LI>You must cause the files modified to carry prominent notices stating
+ that you changed the files and the date of any change.</LI>
+<P></P>
+<LI>You must cause the whole of the work to be licensed at no charge to
+ all third parties under the terms of this License.</LI>
+<P></P>
+<LI>If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses the
+ facility, other than as an argument passed when the facility is
+ invoked, then you must make a good faith effort to ensure that, in the
+ event an application does not supply such function or table, the
+ facility still operates, and performs whatever part of its purpose
+ remains meaningful.</LI>
+<P>(For example, a function in a library to compute square roots has a
+ purpose that is entirely well-defined independent of the application.
+ Therefore, Subsection 2d requires that any application-supplied
+ function or table used by this function must be optional: if the
+ application does not supply it, the square root function must still
+ compute square roots.)</P>
+</OL>
+<P>These requirements apply to the modified work as a whole. If
+ identifiable sections of that work are not derived from the Library,
+ and can be reasonably considered independent and separate works in
+ themselves, then this License, and its terms, do not apply to those
+ sections when you distribute them as separate works. But when you
+ distribute the same sections as part of a whole which is a work based
+ on the Library, the distribution of the whole must be on the terms of
+ this License, whose permissions for other licensees extend to the
+ entire whole, and thus to each and every part regardless of who wrote
+ it.</P>
+<P>Thus, it is not the intent of this section to claim rights or contest
+ your rights to work written entirely by you; rather, the intent is to
+ exercise the right to control the distribution of derivative or
+ collective works based on the Library.</P>
+<P>In addition, mere aggregation of another work not based on the
+ Library with the Library (or with a work based on the Library) on a
+ volume of a storage or distribution medium does not bring the other
+ work under the scope of this License.</P>
+<P><STRONG>3.</STRONG> You may opt to apply the terms of the ordinary
+ GNU General Public License instead of this License to a given copy of
+ the Library. To do this, you must alter all the notices that refer to
+ this License, so that they refer to the ordinary GNU General Public
+ License, version 2, instead of to this License. (If a newer version
+ than version 2 of the ordinary GNU General Public License has appeared,
+ then you can specify that version instead if you wish.) Do not make any
+ other change in these notices.</P>
+<P>Once this change is made in a given copy, it is irreversible for that
+ copy, so the ordinary GNU General Public License applies to all
+ subsequent copies and derivative works made from that copy.</P>
+<P>This option is useful when you wish to copy part of the code of the
+ Library into a program that is not a library.</P>
+<P><STRONG>4.</STRONG> You may copy and distribute the Library (or a
+ portion or derivative of it, under Section 2) in object code or
+ executable form under the terms of Sections 1 and 2 above provided that
+ you accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections 1
+ and 2 above on a medium customarily used for software interchange.</P>
+<P>If distribution of object code is made by offering access to copy
+ from a designated place, then offering equivalent access to copy the
+ source code from the same place satisfies the requirement to distribute
+ the source code, even though third parties are not compelled to copy
+ the source along with the object code.</P>
+<P><STRONG>5.</STRONG> A program that contains no derivative of any
+ portion of the Library, but is designed to work with the Library by
+ being compiled or linked with it, is called a &quot;work that uses the
+ Library&quot;. Such a work, in isolation, is not a derivative work of the
+ Library, and therefore falls outside the scope of this License.</P>
+<P>However, linking a &quot;work that uses the Library&quot; with the Library
+ creates an executable that is a derivative of the Library (because it
+ contains portions of the Library), rather than a &quot;work that uses the
+ library&quot;. The executable is therefore covered by this License. Section
+ 6 states terms for distribution of such executables.</P>
+<P>When a &quot;work that uses the Library&quot; uses material from a header file
+ that is part of the Library, the object code for the work may be a
+ derivative work of the Library even though the source code is not.
+ Whether this is true is especially significant if the work can be
+ linked without the Library, or if the work is itself a library. The
+ threshold for this to be true is not precisely defined by law.</P>
+<P>If such an object file uses only numerical parameters, data structure
+ layouts and accessors, and small macros and small inline functions (ten
+ lines or less in length), then the use of the object file is
+ unrestricted, regardless of whether it is legally a derivative work.
+ (Executables containing this object code plus portions of the Library
+ will still fall under Section 6.)</P>
+<P>Otherwise, if the work is a derivative of the Library, you may
+ distribute the object code for the work under the terms of Section 6.
+ Any executables containing that work also fall under Section 6, whether
+ or not they are linked directly with the Library itself.</P>
+<P><STRONG>6.</STRONG> As an exception to the Sections above, you may
+ also compile or link a &quot;work that uses the Library&quot; with the Library to
+ produce a work containing portions of the Library, and distribute that
+ work under terms of your choice, provided that the terms permit
+ modification of the work for the customer's own use and reverse
+ engineering for debugging such modifications.</P>
+<P>You must give prominent notice with each copy of the work that the
+ Library is used in it and that the Library and its use are covered by
+ this License. You must supply a copy of this License. If the work
+ during execution displays copyright notices, you must include the
+ copyright notice for the Library among them, as well as a reference
+ directing the user to the copy of this License. Also, you must do one
+ of these things:</P>
+<OL TYPE="a">
+<LI>Accompany the work with the complete corresponding machine-readable
+ source code for the Library including whatever changes were used in the
+ work (which must be distributed under Sections 1 and 2 above); and, if
+ the work is an executable linked with the Library, with the complete
+ machine-readable &quot;work that uses the Library&quot;, as object code and/or
+ source code, so that the user can modify the Library and then relink to
+ produce a modified executable containing the modified Library. (It is
+ understood that the user who changes the contents of definitions files
+ in the Library will not necessarily be able to recompile the
+ application to use the modified definitions.)</LI>
+<P></P>
+<LI>Accompany the work with a written offer, valid for at least three
+ years, to give the same user the materials specified in Subsection 6a,
+ above, for a charge no more than the cost of performing this
+ distribution.</LI>
+<P></P>
+<LI>If distribution of the work is made by offering access to copy from
+ a designated place, offer equivalent access to copy the above specified
+ materials from the same place.</LI>
+<P></P>
+<LI>Verify that the user has already received a copy of these materials
+ or that you have already sent this user a copy.</LI>
+</OL>
+<P>For an executable, the required form of the &quot;work that uses the
+ Library&quot; must include any data and utility programs needed for
+ reproducing the executable from it. However, as a special exception,
+ the source code distributed need not include anything that is normally
+ distributed (in either source or binary form) with the major components
+ (compiler, kernel, and so on) of the operating system on which the
+ executable runs, unless that component itself accompanies the
+ executable.</P>
+<P>It may happen that this requirement contradicts the license
+ restrictions of other proprietary libraries that do not normally
+ accompany the operating system. Such a contradiction means you cannot
+ use both them and the Library together in an executable that you
+ distribute.</P>
+<P><STRONG>7.</STRONG> You may place library facilities that are a work
+ based on the Library side-by-side in a single library together with
+ other library facilities not covered by this License, and distribute
+ such a combined library, provided that the separate distribution of the
+ work based on the Library and of the other library facilities is
+ otherwise permitted, and provided that you do these two things:</P>
+<OL TYPE="a">
+<LI>Accompany the combined library with a copy of the same work based on
+ the Library, uncombined with any other library facilities. This must be
+ distributed under the terms of the Sections above.</LI>
+<P></P>
+<LI>Give prominent notice with the combined library of the fact that
+ part of it is a work based on the Library, and explaining where to find
+ the accompanying uncombined form of the same work.</LI>
+</OL>
+<P><STRONG>8.</STRONG> You may not copy, modify, sublicense, link with,
+ or distribute the Library except as expressly provided under this
+ License. Any attempt otherwise to copy, modify, sublicense, link with,
+ or distribute the Library is void, and will automatically terminate
+ your rights under this License. However, parties who have received
+ copies, or rights, from you under this License will not have their
+ licenses terminated so long as such parties remain in full compliance.</P>
+<P><STRONG>9.</STRONG> You are not required to accept this License,
+ since you have not signed it. However, nothing else grants you
+ permission to modify or distribute the Library or its derivative works.
+ These actions are prohibited by law if you do not accept this License.
+ Therefore, by modifying or distributing the Library (or any work based
+ on the Library), you indicate your acceptance of this License to do so,
+ and all its terms and conditions for copying, distributing or modifying
+ the Library or works based on it.</P>
+<P><STRONG>10.</STRONG> Each time you redistribute the Library (or any
+ work based on the Library), the recipient automatically receives a
+ license from the original licensor to copy, distribute, link with or
+ modify the Library subject to these terms and conditions. You may not
+ impose any further restrictions on the recipients' exercise of the
+ rights granted herein. You are not responsible for enforcing compliance
+ by third parties to this License.</P>
+<P><STRONG>11.</STRONG> If, as a consequence of a court judgment or
+ allegation of patent infringement or for any other reason (not limited
+ to patent issues), conditions are imposed on you (whether by court
+ order, agreement or otherwise) that contradict the conditions of this
+ License, they do not excuse you from the conditions of this License. If
+ you cannot distribute so as to satisfy simultaneously your obligations
+ under this License and any other pertinent obligations, then as a
+ consequence you may not distribute the Library at all. For example, if
+ a patent license would not permit royalty-free redistribution of the
+ Library by all those who receive copies directly or indirectly through
+ you, then the only way you could satisfy both it and this License would
+ be to refrain entirely from distribution of the Library.</P>
+<P>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.</P>
+<P>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.</P>
+<P>This section is intended to make thoroughly clear what is believed to
+ be a consequence of the rest of this License.</P>
+<P><STRONG>12.</STRONG> If the distribution and/or use of the Library is
+ restricted in certain countries either by patents or by copyrighted
+ interfaces, the original copyright holder who places the Library under
+ this License may add an explicit geographical distribution limitation
+ excluding those countries, so that distribution is permitted only in or
+ among countries not thus excluded. In such case, this License
+ incorporates the limitation as if written in the body of this License.</P>
+<P><STRONG>13.</STRONG> The Free Software Foundation may publish revised
+ and/or new versions of the Library General Public License from time to
+ time. Such new versions will be similar in spirit to the present
+ version, but may differ in detail to address new problems or concerns.</P>
+<P>Each version is given a distinguishing version number. If the Library
+ specifies a version number of this License which applies to it and &quot;any
+ later version&quot;, you have the option of following the terms and
+ conditions either of that version or of any later version published by
+ the Free Software Foundation. If the Library does not specify a license
+ version number, you may choose any version ever published by the Free
+ Software Foundation.</P>
+<P><STRONG>14.</STRONG> If you wish to incorporate parts of the Library
+ into other free programs whose distribution conditions are incompatible
+ with these, write to the author to ask for permission. For software
+ which is copyrighted by the Free Software Foundation, write to the Free
+ Software Foundation; we sometimes make exceptions for this. Our
+ decision will be guided by the two goals of preserving the free status
+ of all derivatives of our free software and of promoting the sharing
+ and reuse of software generally.</P>
+<P><STRONG>NO WARRANTY</STRONG></P>
+<P><STRONG>15.</STRONG> BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE,
+ THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY
+ APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+ HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY &quot;AS IS&quot; WITHOUT
+ WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE
+ OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU
+ ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.</P>
+<P><STRONG>16.</STRONG> IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR
+ AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO
+ MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE
+ LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL
+ OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+ LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+ RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+ FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+ SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ DAMAGES.</P>
+<H4>END OF TERMS AND CONDITIONS</H4>
+<H1 ALIGN="RIGHT"><A NAME="CONSTANTS">B - Constants</A></H1>
+<P>This appendix lists all of the constants that are defined by the CUPS
+ API.</P>
+<H2><A NAME="8_1">CUPS Constants</A></H2>
+<H3><A NAME="8_1_1">Version Number</A></H3>
+<P>The <CODE>CUPS_VERSION</CODE> constant is a floating-point number
+ representing the API version number. The current version number is
+ 1.0100 which represents CUPS version 1.1.0.</P>
+<H3><A NAME="8_1_2">Printer Capabilities</A></H3>
+<P>The <CODE>CUPS_PRINTER</CODE> constants represent capability bits for
+ printers and classes:</P>
+<UL>
+<LI><CODE>CUPS_PRINTER_LOCAL</CODE> - Is a local printer or class.</LI>
+<LI><CODE>CUPS_PRINTER_REMOTE</CODE> - Is a remote printer or class.</LI>
+<LI><CODE>CUPS_PRINTER_CLASS</CODE> - Is a class.</LI>
+<LI><CODE>CUPS_PRINTER_BW</CODE> - Printer prints in black and white.</LI>
+<LI><CODE>CUPS_PRINTER_COLOR</CODE> - Printer prints in color.</LI>
+<LI><CODE>CUPS_PRINTER_DUPLEX</CODE> - Printer can print double-sided.</LI>
+<LI><CODE>CUPS_PRINTER_STAPLE</CODE> - Printer can staple output.</LI>
+<LI><CODE>CUPS_PRINTER_COPIES</CODE> - Printer can produce multiple
+ copies on its own.</LI>
+<LI><CODE>CUPS_PRINTER_COLLATE</CODE> - Printer can collate copies.</LI>
+<LI><CODE>CUPS_PRINTER_PUNCH</CODE> - Printer can punch holes in output.</LI>
+<LI><CODE>CUPS_PRINTER_COVER</CODE> - Printer can put covers on output.</LI>
+<LI><CODE>CUPS_PRINTER_BIND</CODE> - Printer can bind output.</LI>
+<LI><CODE>CUPS_PRINTER_SORT</CODE> - Printer can sort output.</LI>
+<LI><CODE>CUPS_PRINTER_SMALL</CODE> - Printer can print on media up to
+ 9x14 inches.</LI>
+<LI><CODE>CUPS_PRINTER_MEDIUM</CODE> - Printer can print on media from
+ 9x14 to 18x24 inches.</LI>
+<LI><CODE>CUPS_PRINTER_LARGE</CODE> - Printer can print on media larger
+ than 18x24 inches.</LI>
+<LI><CODE>CUPS_PRINTER_VARIABLE</CODE> - Printer can print on variable
+ or custom media sizes.</LI>
+<LI><CODE>CUPS_PRINTER_IMPLICIT</CODE> - Is an implicit class.</LI>
+<LI><CODE>CUPS_PRINTER_OPTIONS</CODE> - All of the printer capability
+ and option bits.</LI>
+</UL>
+<H3><A NAME="8_1_3">Encodings</A></H3>
+<P>CUPS defines the following character set encoding constants:</P>
+<UL>
+<LI><CODE>CUPS_US_ASCII</CODE> - US ASCII character set.</LI>
+<LI><CODE>CUPS_UTF_8</CODE> - UTF-8 encoding of Unicode.</LI>
+<LI><CODE>CUPS_ISO8859_1</CODE> - ISO-8859-1 character set.</LI>
+<LI><CODE>CUPS_ISO8859_2</CODE> - ISO-8859-2 character set.</LI>
+<LI><CODE>CUPS_ISO8859_3</CODE> - ISO-8859-3 character set.</LI>
+<LI><CODE>CUPS_ISO8859_4</CODE> - ISO-8859-4 character set.</LI>
+<LI><CODE>CUPS_ISO8859_5</CODE> - ISO-8859-5 character set.</LI>
+<LI><CODE>CUPS_ISO8859_6</CODE> - ISO-8859-6 character set.</LI>
+<LI><CODE>CUPS_ISO8859_7</CODE> - ISO-8859-7 character set.</LI>
+<LI><CODE>CUPS_ISO8859_8</CODE> - ISO-8859-8 character set.</LI>
+<LI><CODE>CUPS_ISO8859_9</CODE> - ISO-8859-9 character set.</LI>
+<LI><CODE>CUPS_ISO8859_10</CODE> - ISO-8859-10 character set.</LI>
+<LI><CODE>CUPS_ISO8859_13</CODE> - ISO-8859-13 character set.</LI>
+<LI><CODE>CUPS_ISO8859_14</CODE> - ISO-8859-14 character set.</LI>
+<LI><CODE>CUPS_ISO8859_15</CODE> - ISO-8859-15 character set.</LI>
+<LI><CODE>CUPS_WINDOWS_874</CODE> - Windows code page 874.</LI>
+<LI><CODE>CUPS_WINDOWS_1250</CODE> - Windows code page 1250.</LI>
+<LI><CODE>CUPS_WINDOWS_1251</CODE> - Windows code page 1251.</LI>
+<LI><CODE>CUPS_WINDOWS_1252</CODE> - Windows code page 1252.</LI>
+<LI><CODE>CUPS_WINDOWS_1253</CODE> - Windows code page 1253.</LI>
+<LI><CODE>CUPS_WINDOWS_1254</CODE> - Windows code page 1254.</LI>
+<LI><CODE>CUPS_WINDOWS_1255</CODE> - Windows code page 1255.</LI>
+<LI><CODE>CUPS_WINDOWS_1256</CODE> - Windows code page 1256.</LI>
+<LI><CODE>CUPS_WINDOWS_1257</CODE> - Windows code page 1257.</LI>
+<LI><CODE>CUPS_WINDOWS_1258</CODE> - Windows code page 1258.</LI>
+<LI><CODE>CUPS_KOI8_R</CODE> - Russian code page koi8-r.</LI>
+<LI><CODE>CUPS_KOI8_U</CODE> - Ukrainian code page koi8-r.</LI>
+</UL>
+<H2><A NAME="8_2">HTTP Constants</A></H2>
+<H3><A NAME="8_2_1">Limits</A></H3>
+<P>The following constants define the limits for strings:</P>
+<UL>
+<LI><CODE>HTTP_MAX_BUFFER</CODE> - Size of socket buffer.</LI>
+<LI><CODE>HTTP_MAX_HOST</CODE> - Maximum length of hostname.</LI>
+<LI><CODE>HTTP_MAX_URI</CODE> - Maximum length of URI.</LI>
+<LI><CODE>HTTP_MAX_VALUE</CODE> - Maximum length of field values.</LI>
+</UL>
+<H3><A NAME="8_2_2">Status Codes</A></H3>
+<P>The following status codes can be returned by <CODE>httpUpdate()</CODE>
+:</P>
+<UL>
+<LI><CODE>HTTP_ERROR</CODE> - A network error occurred</LI>
+<LI><CODE>HTTP_CONTINUE</CODE> - Continue response from HTTP proxy</LI>
+<LI><CODE>HTTP_OK</CODE> - OPTIONS/GET/HEAD/POST/TRACE command was
+ successful</LI>
+<LI><CODE>HTTP_CREATED</CODE> - PUT command was successful</LI>
+<LI><CODE>HTTP_ACCEPTED</CODE> - DELETE command was successful</LI>
+<LI><CODE>HTTP_NOT_AUTHORITATIVE</CODE> - Information isn't
+ authoritative</LI>
+<LI><CODE>HTTP_NO_CONTENT</CODE> - Successful command</LI>
+<LI><CODE>HTTP_RESET_CONTENT</CODE> - Content was reset/recreated</LI>
+<LI><CODE>HTTP_PARTIAL_CONTENT</CODE> - Only a partial file was
+ recieved/sent</LI>
+<LI><CODE>HTTP_MULTIPLE_CHOICES</CODE> - Multiple files match request</LI>
+<LI><CODE>HTTP_MOVED_PERMANENTLY</CODE> - Document has moved permanently</LI>
+<LI><CODE>HTTP_MOVED_TEMPORARILY</CODE> - Document has moved temporarily</LI>
+<LI><CODE>HTTP_SEE_OTHER</CODE> - See this other link...</LI>
+<LI><CODE>HTTP_NOT_MODIFIED</CODE> - File not modified</LI>
+<LI><CODE>HTTP_USE_PROXY</CODE> - Must use a proxy to access this URI</LI>
+<LI><CODE>HTTP_BAD_REQUEST</CODE> - Bad request</LI>
+<LI><CODE>HTTP_UNAUTHORIZED</CODE> - Unauthorized to access host</LI>
+<LI><CODE>HTTP_PAYMENT_REQUIRED</CODE> - Payment required</LI>
+<LI><CODE>HTTP_FORBIDDEN</CODE> - Forbidden to access this URI</LI>
+<LI><CODE>HTTP_NOT_FOUND</CODE> - URI was not found</LI>
+<LI><CODE>HTTP_METHOD_NOT_ALLOWED</CODE> - Method is not allowed</LI>
+<LI><CODE>HTTP_NOT_ACCEPTABLE</CODE> - Not Acceptable</LI>
+<LI><CODE>HTTP_PROXY_AUTHENTICATION</CODE> - Proxy Authentication is
+ Required</LI>
+<LI><CODE>HTTP_REQUEST_TIMEOUT</CODE> - Request timed out</LI>
+<LI><CODE>HTTP_CONFLICT</CODE> - Request is self-conflicting</LI>
+<LI><CODE>HTTP_GONE</CODE> - Server has gone away</LI>
+<LI><CODE>HTTP_LENGTH_REQUIRED</CODE> - A content length or encoding is
+ required</LI>
+<LI><CODE>HTTP_PRECONDITION</CODE> - Precondition failed</LI>
+<LI><CODE>HTTP_REQUEST_TOO_LARGE</CODE> - Request entity too large</LI>
+<LI><CODE>HTTP_URI_TOO_LONG</CODE> - URI too long</LI>
+<LI><CODE>HTTP_UNSUPPORTED_MEDIATYPE</CODE> - The requested media type
+ is unsupported</LI>
+<LI><CODE>HTTP_SERVER_ERROR</CODE> - Internal server error</LI>
+<LI><CODE>HTTP_NOT_IMPLEMENTED</CODE> - Feature not implemented</LI>
+<LI><CODE>HTTP_BAD_GATEWAY</CODE> - Bad gateway</LI>
+<LI><CODE>HTTP_SERVICE_UNAVAILABLE</CODE> - Service is unavailable</LI>
+<LI><CODE>HTTP_GATEWAY_TIMEOUT</CODE> - Gateway connection timed out</LI>
+<LI><CODE>HTTP_NOT_SUPPORTED</CODE> - HTTP version not supported</LI>
+</UL>
+<H3><A NAME="8_2_3">Fields</A></H3>
+<P>The following fields are indices for each of the standard HTTP fields
+ in HTTP 1/1:</P>
+<UL>
+<LI><CODE>HTTP_FIELD_ACCEPT_LANGUAGE</CODE> - Accept-Language</LI>
+<LI><CODE>HTTP_FIELD_ACCEPT_RANGES</CODE> - Accept-Ranges</LI>
+<LI><CODE>HTTP_FIELD_AUTHORIZATION</CODE> - Authorization</LI>
+<LI><CODE>HTTP_FIELD_CONNECTION</CODE> - Connection</LI>
+<LI><CODE>HTTP_FIELD_CONTENT_ENCODING</CODE> - Content-Encoding</LI>
+<LI><CODE>HTTP_FIELD_CONTENT_LANGUAGE</CODE> - Content-Language</LI>
+<LI><CODE>HTTP_FIELD_CONTENT_LENGTH</CODE> - Content-Length</LI>
+<LI><CODE>HTTP_FIELD_CONTENT_LOCATION</CODE> - Content-Location</LI>
+<LI><CODE>HTTP_FIELD_CONTENT_MD5</CODE> - Content-MD5</LI>
+<LI><CODE>HTTP_FIELD_CONTENT_RANGE</CODE> - Content-Range</LI>
+<LI><CODE>HTTP_FIELD_CONTENT_TYPE</CODE> - Content-Type</LI>
+<LI><CODE>HTTP_FIELD_CONTENT_VERSION</CODE> - Content-Version</LI>
+<LI><CODE>HTTP_FIELD_DATE</CODE> - Date</LI>
+<LI><CODE>HTTP_FIELD_HOST</CODE> - Host</LI>
+<LI><CODE>HTTP_FIELD_IF_MODIFIED_SINCE</CODE> - If-Modified-Since</LI>
+<LI><CODE>HTTP_FIELD_IF_UNMODIFIED_SINCE</CODE> - If-Unmodified-Since</LI>
+<LI><CODE>HTTP_FIELD_KEEP_ALIVE</CODE> - Keep-Alive</LI>
+<LI><CODE>HTTP_FIELD_LAST_MODIFIED</CODE> - Last-Modified</LI>
+<LI><CODE>HTTP_FIELD_LINK</CODE> - Link</LI>
+<LI><CODE>HTTP_FIELD_LOCATION</CODE> - Location</LI>
+<LI><CODE>HTTP_FIELD_RANGE</CODE> - Range</LI>
+<LI><CODE>HTTP_FIELD_REFERER</CODE> - Referer</LI>
+<LI><CODE>HTTP_FIELD_RETRY_AFTER</CODE> - Retry-After</LI>
+<LI><CODE>HTTP_FIELD_TRANSFER_ENCODING</CODE> - Transfer-Encoding</LI>
+<LI><CODE>HTTP_FIELD_UPGRADE</CODE> - Upgrade</LI>
+<LI><CODE>HTTP_FIELD_USER_AGENT</CODE> - User-Agent</LI>
+<LI><CODE>HTTP_FIELD_WWW_AUTHENTICATE</CODE> - WWW-Authenticate</LI>
+</UL>
+<H2><A NAME="8_3">IPP Constants</A></H2>
+<H3><A NAME="8_3_1">Limits</A></H3>
+<P>The following constants define array limits for IPP data:</P>
+<UL>
+<LI><CODE>IPP_MAX_NAME</CODE> - Maximum length of an attribute name</LI>
+<LI><CODE>IPP_MAX_VALUES</CODE> - Maximum number of set-of values that
+ can be read in a request.</LI>
+</UL>
+<H3><A NAME="8_3_2">Tags</A></H3>
+<UL>
+<LI><CODE>IPP_TAG_ZERO</CODE> - Wildcard tag value for searches; also
+ used to separate groups of attributes</LI>
+<LI><CODE>IPP_TAG_OPERATION</CODE> - Tag for values of type operation</LI>
+<LI><CODE>IPP_TAG_JOB</CODE> - Tag for values of type job</LI>
+<LI><CODE>IPP_TAG_END</CODE> - Tag for values of type end</LI>
+<LI><CODE>IPP_TAG_PRINTER</CODE> - Tag for values of type printer</LI>
+<LI><CODE>IPP_TAG_UNSUPPORTED_GROUP</CODE> - Tag for values of type
+ unsupported_group</LI>
+<LI><CODE>IPP_TAG_UNSUPPORTED_VALUE</CODE> - Tag for values of type
+ unsupported_value</LI>
+<LI><CODE>IPP_TAG_DEFAULT</CODE> - Tag for values of type default</LI>
+<LI><CODE>IPP_TAG_UNKNOWN</CODE> - Tag for values of type unknown</LI>
+<LI><CODE>IPP_TAG_NOVALUE</CODE> - Tag for values of type novalue</LI>
+<LI><CODE>IPP_TAG_NOTSETTABLE</CODE> - Tag for values of type
+ notsettable</LI>
+<LI><CODE>IPP_TAG_DELETEATTR</CODE> - Tag for values of type deleteattr</LI>
+<LI><CODE>IPP_TAG_ANYVALUE</CODE> - Tag for values of type anyvalue</LI>
+<LI><CODE>IPP_TAG_INTEGER</CODE> - Tag for values of type integer</LI>
+<LI><CODE>IPP_TAG_BOOLEAN</CODE> - Tag for values of type boolean</LI>
+<LI><CODE>IPP_TAG_ENUM</CODE> - Tag for values of type enum</LI>
+<LI><CODE>IPP_TAG_STRING</CODE> - Tag for values of type string</LI>
+<LI><CODE>IPP_TAG_DATE</CODE> - Tag for values of type date</LI>
+<LI><CODE>IPP_TAG_RESOLUTION</CODE> - Tag for values of type resolution</LI>
+<LI><CODE>IPP_TAG_RANGE</CODE> - Tag for values of type range</LI>
+<LI><CODE>IPP_TAG_COLLECTION</CODE> - Tag for values of type collection</LI>
+<LI><CODE>IPP_TAG_TEXTLANG</CODE> - Tag for values of type textlang</LI>
+<LI><CODE>IPP_TAG_NAMELANG</CODE> - Tag for values of type namelang</LI>
+<LI><CODE>IPP_TAG_TEXT</CODE> - Tag for values of type text</LI>
+<LI><CODE>IPP_TAG_NAME</CODE> - Tag for values of type name</LI>
+<LI><CODE>IPP_TAG_KEYWORD</CODE> - Tag for values of type keyword</LI>
+<LI><CODE>IPP_TAG_URI</CODE> - Tag for values of type uri</LI>
+<LI><CODE>IPP_TAG_URISCHEME</CODE> - Tag for values of type urischeme</LI>
+<LI><CODE>IPP_TAG_CHARSET</CODE> - Tag for values of type charset</LI>
+<LI><CODE>IPP_TAG_LANGUAGE</CODE> - Tag for values of type language</LI>
+<LI><CODE>IPP_TAG_MIMETYPE</CODE> - Tag for values of type mimetype</LI>
+</UL>
+<H3><A NAME="8_3_3">Resolution Units</A></H3>
+<P>The <CODE>IPP_RES_PER_INCH</CODE> and <CODE>IPP_RES_PER_CM</CODE>
+ constants specify dots per inch and dots per centimeter, respectively.</P>
+<H3><A NAME="8_3_4">Finishings</A></H3>
+<P>The finishing values specify special finishing operations to be
+ performed on the job.</P>
+<UL>
+<LI><CODE>IPP_FINISH_NONE</CODE> - Do no finishing</LI>
+<LI><CODE>IPP_FINISH_STAPLE</CODE> - Staple the job</LI>
+<LI><CODE>IPP_FINISH_PUNCH</CODE> - Punch the job</LI>
+<LI><CODE>IPP_FINISH_COVER</CODE> - Cover the job</LI>
+<LI><CODE>IPP_FINISH_BIND</CODE> - Bind the job</LI>
+</UL>
+<H3><A NAME="8_3_5">Orientations</A></H3>
+<P>The orientation values specify the orientation of the job.</P>
+<UL>
+<LI><CODE>IPP_PORTRAIT</CODE> - No rotation</LI>
+<LI><CODE>IPP_LANDSCAPE</CODE> - 90 degrees counter-clockwise</LI>
+<LI><CODE>IPP_REVERSE_LANDSCAPE</CODE> - 90 degrees clockwise</LI>
+<LI><CODE>IPP_REVERSE_PORTRAIT</CODE> - 180 degrees</LI>
+</UL>
+<H3><A NAME="8_3_6">Qualities</A></H3>
+<P>The quality values specify the desired quality of the print.</P>
+<UL>
+<LI><CODE>IPP_QUALITY_DRAFT</CODE> - Draft quality</LI>
+<LI><CODE>IPP_QUALITY_NORMAL</CODE> - Normal quality</LI>
+<LI><CODE>IPP_QUALITY_HIGH</CODE> - High quality</LI>
+</UL>
+<H3><A NAME="8_3_7">Job States</A></H3>
+<P>The job state values are used to represent the current job state.</P>
+<UL>
+<LI><CODE>IPP_JOB_PENDING</CODE> - Job is pending</LI>
+<LI><CODE>IPP_JOB_HELD</CODE> - Job is held</LI>
+<LI><CODE>IPP_JOB_PROCESSING</CODE> - Job is processing</LI>
+<LI><CODE>IPP_JOB_STOPPED</CODE> - Job is stopped</LI>
+<LI><CODE>IPP_JOB_CANCELLED</CODE> - Job is cancelled</LI>
+<LI><CODE>IPP_JOB_ABORTED</CODE> - Job is aborted</LI>
+<LI><CODE>IPP_JOB_COMPLETED</CODE> - Job is completed</LI>
+</UL>
+<H3><A NAME="8_3_8">Printer States</A></H3>
+<P>The printer state values are used to represent the current printer
+ state.</P>
+<UL>
+<LI><CODE>IPP_PRINTER_IDLE</CODE> - Printer is idle</LI>
+<LI><CODE>IPP_PRINTER_PROCESSING</CODE> - Printer is processing</LI>
+<LI><CODE>IPP_PRINTER_STOPPED</CODE> - Printer is stopped</LI>
+</UL>
+<H3><A NAME="8_3_9">Operations</A></H3>
+<P>The operation values represent the available IPP operations.</P>
+<UL>
+<LI><CODE>IPP_PRINT_JOB</CODE> - Print a file</LI>
+<LI><CODE>IPP_PRINT_URI</CODE> - Print a URI</LI>
+<LI><CODE>IPP_VALIDATE_JOB</CODE> - Validate job attributes</LI>
+<LI><CODE>IPP_CREATE_JOB</CODE> - Create a new job</LI>
+<LI><CODE>IPP_SEND_DOCUMENT</CODE> - Send a document to a job</LI>
+<LI><CODE>IPP_SEND_URI</CODE> - Send a URI to a job</LI>
+<LI><CODE>IPP_CANCEL_JOB</CODE> - Cancel a job</LI>
+<LI><CODE>IPP_GET_JOB_ATTRIBUTES</CODE> - Get job attributes</LI>
+<LI><CODE>IPP_GET_JOBS</CODE> - Get a list of all jobs</LI>
+<LI><CODE>IPP_GET_PRINTER_ATTRIBUTES</CODE> - Get printer attributes</LI>
+<LI><CODE>IPP_HOLD_JOB</CODE> - Hold a pending job</LI>
+<LI><CODE>IPP_RELEASE_JOB</CODE> - Release a held job</LI>
+<LI><CODE>IPP_RESTART_JOB</CODE> - Restart a completed job</LI>
+<LI><CODE>IPP_PAUSE_PRINTER</CODE> - Pause a printer</LI>
+<LI><CODE>IPP_RESUME_PRINTER</CODE> - Restart a paused printer</LI>
+<LI><CODE>IPP_PURGE_JOBS</CODE> - Purge jobs from the queue</LI>
+<LI><CODE>IPP_SET_PRINTER_ATTRIBUTES</CODE> - Set printer attributes</LI>
+<LI><CODE>IPP_SET_JOB_ATTRIBUTES</CODE> - Set job attributes</LI>
+<LI><CODE>IPP_GET_PRINTER_SUPPORTED_VALUES</CODE> - Get printer
+ supported values</LI>
+<LI><CODE>CUPS_GET_DEFAULT</CODE> - Get the default destination</LI>
+<LI><CODE>CUPS_GET_PRINTERS</CODE> - Get a list of all printers</LI>
+<LI><CODE>CUPS_ADD_PRINTER</CODE> - Add or modify a printer</LI>
+<LI><CODE>CUPS_DELETE_PRINTER</CODE> - Delete a printer</LI>
+<LI><CODE>CUPS_GET_CLASSES</CODE> - Get a list of all classes</LI>
+<LI><CODE>CUPS_ADD_CLASS</CODE> - Add or modify a class</LI>
+<LI><CODE>CUPS_DELETE_CLASS</CODE> - Delete a class</LI>
+<LI><CODE>CUPS_ACCEPT_JOBS</CODE> - Accept jobs on a printer or class</LI>
+<LI><CODE>CUPS_REJECT_JOBS</CODE> - Reject jobs on a printer or class</LI>
+<LI><CODE>CUPS_SET_DEFAULT</CODE> - Set the default destination</LI>
+<LI><CODE>CUPS_GET_DEVICES</CODE> - Get a list of all devices</LI>
+<LI><CODE>CUPS_GET_PPDS</CODE> - Get a list of all PPDs</LI>
+<LI><CODE>CUPS_MOVE_JOB</CODE> - Move a job to a new destination</LI>
+</UL>
+<H3><A NAME="8_3_10">Status Codes</A></H3>
+<P>Status codes are returned by all IPP requests.</P>
+<UL>
+<LI><CODE>IPP_OK</CODE> - Request completed with no errors</LI>
+<LI><CODE>IPP_OK_SUBST</CODE> - Request completed but some attribute
+ values were substituted</LI>
+<LI><CODE>IPP_OK_CONFLICT</CODE> - Request completed but some attributes
+ conflicted</LI>
+<LI><CODE>IPP_BAD_REQUEST</CODE> - The request was bad</LI>
+<LI><CODE>IPP_FORBIDDEN</CODE> - You don't have access to the resource</LI>
+<LI><CODE>IPP_NOT_AUTHENTICATED</CODE> - You are not authenticated for
+ the resource</LI>
+<LI><CODE>IPP_NOT_AUTHORIZED</CODE> - You not authorized to access the
+ resource</LI>
+<LI><CODE>IPP_NOT_POSSIBLE</CODE> - The requested operation cannot be
+ completed</LI>
+<LI><CODE>IPP_TIMEOUT</CODE> - A timeout occurred</LI>
+<LI><CODE>IPP_NOT_FOUND</CODE> - The resource was not found</LI>
+<LI><CODE>IPP_GONE</CODE> - The resource has gone away</LI>
+<LI><CODE>IPP_REQUEST_ENTITY</CODE> - The request was too large</LI>
+<LI><CODE>IPP_REQUEST_VALUE</CODE> - The request contained a value that
+ was unknown to the server</LI>
+<LI><CODE>IPP_DOCUMENT_FORMAT</CODE> - The document format is not
+ supported by the server</LI>
+<LI><CODE>IPP_ATTRIBUTES</CODE> - Required attributes are missing</LI>
+<LI><CODE>IPP_URI_SCHEME</CODE> - The URI scheme is not supported</LI>
+<LI><CODE>IPP_CHARSET</CODE> - The charset is not supported</LI>
+<LI><CODE>IPP_CONFLICT</CODE> - One or more attributes conflict</LI>
+<LI><CODE>IPP_COMPRESSION_NOT_SUPPORTED</CODE> - The specified
+ compression is not supported</LI>
+<LI><CODE>IPP_COMPRESSION_ERROR</CODE> - The compressed data contained
+ an error</LI>
+<LI><CODE>IPP_DOCUMENT_FORMAT_ERROR</CODE> - The document data contained
+ an error in it</LI>
+<LI><CODE>IPP_DOCUMENT_ACCESS_ERROR</CODE> - The remote document could
+ not be accessed</LI>
+<LI><CODE>IPP_INTERNAL_ERROR</CODE> - The server encountered an internal
+ error</LI>
+<LI><CODE>IPP_OPERATION_NOT_SUPPORTED</CODE> - The requested operation
+ is not supported</LI>
+<LI><CODE>IPP_SERVICE_UNAVAILABLE</CODE> - The requested service is
+ unavailable</LI>
+<LI><CODE>IPP_VERSION_NOT_SUPPORTED</CODE> - The IPP request version is
+ not supported</LI>
+<LI><CODE>IPP_DEVICE_ERROR</CODE> - The output device encountered an
+ error</LI>
+<LI><CODE>IPP_TEMPORARY_ERROR</CODE> - A temporary error occurred</LI>
+<LI><CODE>IPP_NOT_ACCEPTING</CODE> - The destination is not accepting
+ jobs</LI>
+<LI><CODE>IPP_PRINTER_BUSY</CODE> - The destination is busy</LI>
+<LI><CODE>IPP_ERROR_JOB_CANCELLED</CODE> - The requested job has been
+ cancelled</LI>
+<LI><CODE>IPP_MULTIPLE_JOBS_NOT_SUPPORTED</CODE> - The server does not
+ support multiple jobs</LI>
+</UL>
+<H2><A NAME="8_4">PPD Constants</A></H2>
+<H3><A NAME="8_4_1">PPD Format Version</A></H3>
+<P>The <CODE>PPD_VERSION</CODE> constant defines a floating point number
+ representing the newest format version that is supported by CUPS,
+ currently 4.3.</P>
+<H3><A NAME="8_4_2">PPD User-Interface Types</A></H3>
+<P>Each printer option has a type associated with it:</P>
+<UL>
+<LI><CODE>PPD_UI_BOOLEAN</CODE> - The user can turn this option on or
+ off</LI>
+<LI><CODE>PPD_UI_PICKONE</CODE> - The user can choose one option value
+ to use.</LI>
+<LI><CODE>PPD_UI_PICKMANY</CODE> - The user can choose zero or more
+ option values.</LI>
+</UL>
+<H3><A NAME="8_4_3">PPD Sections</A></H3>
+<P>Some options must be output before others, or in different sections
+ of the output document. The <CODE>ppd_section_t</CODE> enumeration
+ defines which section the option must be output in:</P>
+<UL>
+<LI><CODE>PPD_ORDER_ANY</CODE> - The option can be output in any of the
+ document, page, or prolog sections of the document</LI>
+<LI><CODE>PPD_ORDER_DOCUMENT</CODE> - The option must be output in the
+ DocumentSetup section of the document</LI>
+<LI><CODE>PPD_ORDER_EXIT</CODE> - The option must be output before the
+ document</LI>
+<LI><CODE>PPD_ORDER_JCL</CODE> - The option must be output in the job
+ control section of the document</LI>
+<LI><CODE>PPD_ORDER_PAGE</CODE> - The option must be output in the
+ PageSetup section of the document</LI>
+<LI><CODE>PPD_ORDER_PROLOG</CODE> - The option must be output in the
+ Prolog section of the document</LI>
+</UL>
+<H3><A NAME="8_4_4">PPD Colorspaces</A></H3>
+<P>Each printer has a default colorspace:</P>
+<UL>
+<LI><CODE>PPD_CS_CMYK</CODE> - The printer uses CMYK colors by default</LI>
+<LI><CODE>PPD_CS_CMY</CODE> - The printer uses CMY colors by default</LI>
+<LI><CODE>PPD_CS_GRAY</CODE> - The printer uses grayscale by default</LI>
+<LI><CODE>PPD_CS_RGB</CODE> - The printer uses RGB colors by default</LI>
+<LI><CODE>PPD_CS_RGBK</CODE> - The printer uses RGBK colors by default</LI>
+<LI><CODE>PPD_CS_N</CODE> - The printer uses a DeviceN colorspace by
+ default</LI>
+</UL>
+<H2><A NAME="8_5">Raster Constants</A></H2>
+<H3><A NAME="8_5_1">Raster Sync Words</A></H3>
+<P>The <CODE>CUPS_RASTER_SYNC</CODE> and <CODE>CUPS_RASTER_REVSYNC</CODE>
+ constants define the standard sync words at the beginning of each CUPS
+ raster file.</P>
+<H3><A NAME="8_5_2">Raster Stream Modes</A></H3>
+<P>The <CODE>CUPS_RASTER_READ</CODE> and <CODE>CUPS_RASTER_WRITE</CODE>
+ constants are used with the<A HREF="#cupsRasterOpen"> <CODE>
+cupsRasterOpen()</CODE></A> function to specify a stream for reading or
+ writing.</P>
+<H3><A NAME="8_5_3">Raster Boolean Constants</A></H3>
+<P>The <CODE>CUPS_FALSE</CODE> and <CODE>CUPS_TRUE</CODE> constants
+ represent boolean values in the page header.</P>
+<H3><A NAME="8_5_4">Raster Jog Values</A></H3>
+<P>The <CODE>cups_jog_t</CODE> enumeration defines constants for the Jog
+ page device dictionary variable:</P>
+<UL>
+<LI><CODE>CUPS_JOG_NONE</CODE> - Do no jogging</LI>
+<LI><CODE>CUPS_JOG_FILE</CODE> - Jog pages after each file</LI>
+<LI><CODE>CUPS_JOG_JOB</CODE> - Jog pages after each job</LI>
+<LI><CODE>CUPS_JOG_SET</CODE> - Jog pages after each set of jobs</LI>
+</UL>
+<H3><A NAME="8_5_5">Raster Orientation Values</A></H3>
+<P>The <CODE>cups_orient_t</CODE> enumeration defines constants for the
+ Orientation page device dictionary variable:</P>
+<UL>
+<LI><CODE>CUPS_ORIENT_0</CODE> - Portrait orientation</LI>
+<LI><CODE>CUPS_ORIENT_90</CODE> - Landscape orientation</LI>
+<LI><CODE>CUPS_ORIENT_180</CODE> - Reverse-portrait orientation</LI>
+<LI><CODE>CUPS_ORIENT_270</CODE> - Reverse-landscape orientation</LI>
+</UL>
+<H3><A NAME="8_5_6">Raster CutMedia Values</A></H3>
+<P>The <CODE>cups_cut_t</CODE> enumeration defines constants for the
+ CutMedia page device dictionary variable:</P>
+<UL>
+<LI><CODE>CUPS_CUT_NONE</CODE> - Do no jogging</LI>
+<LI><CODE>CUPS_CUT_FILE</CODE> - Cut pages after each file</LI>
+<LI><CODE>CUPS_CUT_JOB</CODE> - Cut pages after each job</LI>
+<LI><CODE>CUPS_CUT_SET</CODE> - Cut pages after each set of jobs</LI>
+<LI><CODE>CUPS_CUT_PAGE</CODE> - Cut each page</LI>
+</UL>
+<H3><A NAME="8_5_7">Raster AdvanceMedia Values</A></H3>
+<P>The <CODE>cups_advance_t</CODE> enumeration defines constants for the
+ AdvanceMedia page device dictionary variable:</P>
+<UL>
+<LI><CODE>CUPS_ADVANCE_NONE</CODE> - Do no jogging</LI>
+<LI><CODE>CUPS_ADVANCE_FILE</CODE> - Advance media after each file</LI>
+<LI><CODE>CUPS_ADVANCE_JOB</CODE> - Advance media after each job</LI>
+<LI><CODE>CUPS_ADVANCE_SET</CODE> - Advance media after each set of jobs</LI>
+<LI><CODE>CUPS_ADVANCE_PAGE</CODE> - Advance media for each page</LI>
+</UL>
+<H3><A NAME="8_5_8">Raster LeadingEdge Values</A></H3>
+<P>The <CODE>cups_edge_t</CODE> enumeration defines constants for the
+ LeadingEdge page device dictionary variable:</P>
+<UL>
+<LI><CODE>CUPS_EDGE_TOP</CODE> - The top of the media is the leading
+ edge</LI>
+<LI><CODE>CUPS_EDGE_RIGHT</CODE> - The right of the media is the leading
+ edge</LI>
+<LI><CODE>CUPS_EDGE_BOTTOM</CODE> - The bottom of the media is the
+ leading edge</LI>
+<LI><CODE>CUPS_EDGE_LEFT</CODE> - The left of the media is the leading
+ edge</LI>
+</UL>
+<H3><A NAME="8_5_9">Raster Color Order Values</A></H3>
+<P>The <CODE>cups_order_t</CODE> enumeration defines the possible color
+ value orderings:</P>
+<UL>
+<LI><CODE>CUPS_ORDER_CHUNKED</CODE> - CMYK&nbsp;CMYK&nbsp;CMYK</LI>
+<LI><CODE>CUPS_ORDER_BANDED</CODE> - CCC&nbsp;MMM&nbsp;YYY&nbsp;KKK</LI>
+<LI><CODE>CUPS_ORDER_PLANAR</CODE> - CCC&nbsp;...&nbsp;MMM&nbsp;...&nbsp;YYY&nbsp;...&nbsp;KKK&nbsp;...</LI>
+</UL>
+<H3><A NAME="8_5_10">Raster Colorspace Values</A></H3>
+<P>The <CODE>cups_cspace_t</CODE> enumeration defines the possible
+ colorspaces:</P>
+<UL>
+<LI><CODE>CUPS_CSPACE_W</CODE> - White (luminance)</LI>
+<LI><CODE>CUPS_CSPACE_RGB</CODE> - Red, green, blue</LI>
+<LI><CODE>CUPS_CSPACE_RGBA</CODE> - Red, green, blue, alpha</LI>
+<LI><CODE>CUPS_CSPACE_K</CODE> - Black</LI>
+<LI><CODE>CUPS_CSPACE_CMY</CODE> - Cyan, magenta, yellow</LI>
+<LI><CODE>CUPS_CSPACE_YMC</CODE> - Yellow, magenta, cyan</LI>
+<LI><CODE>CUPS_CSPACE_CMYK</CODE> - Cyan, magenta, yellow, black</LI>
+<LI><CODE>CUPS_CSPACE_YMCK</CODE> - Yellow, magenta, cyan, black</LI>
+<LI><CODE>CUPS_CSPACE_KCMY</CODE> - Black, cyan, magenta, yellow</LI>
+<LI><CODE>CUPS_CSPACE_KCMYcm</CODE> - Black, cyan, magenta, yellow,
+ light cyan, light magenta</LI>
+<LI><CODE>CUPS_CSPACE_GMCK</CODE> - Metallic yellow (gold), metallic
+ magenta, metallic cyan, black</LI>
+<LI><CODE>CUPS_CSPACE_GMCS</CODE> - Metallic yellow (gold), metallic
+ magenta, metallic cyan, metallic grey (silver)</LI>
+<LI><CODE>CUPS_CSPACE_WHITE</CODE> - White pigment (black as white
+ pigment)</LI>
+<LI><CODE>CUPS_CSPACE_GOLD</CODE> - Gold foil (black as gold foil)</LI>
+<LI><CODE>CUPS_CSPACE_SILVER</CODE> - Silver foil (black as silver foil)</LI>
+</UL>
+<H1 ALIGN="RIGHT"><A NAME="STRUCTURES">C - Structures</A></H1>
+<P>This appendix describes all of the structures that are defined by the
+ CUPS API.</P>
+<H2><A NAME="9_1">CUPS Structures</A></H2>
+<H3><A NAME="cups_dest_t">CUPS Destinations</A></H3>
+<P>The CUPS destination structure (<CODE>cups_dest_t</CODE>) contains
+ information on a specific destination or instance:
+<CENTER>
+<TABLE BORDER="1" WIDTH="90%">
+<TR><TH>Member</TH><TH>Type</TH><TH>Description</TH></TR>
+<TR><TD>name</TD><TD>char *</TD><TD>The name of the printer or class.</TD>
+</TR>
+<TR><TD>instance</TD><TD>char *</TD><TD>The instance of the printer or
+ class; NULL for the primary instance.</TD></TR>
+<TR><TD>is_default</TD><TD>int</TD><TD>1 if the destination is set as
+ the default, 0 otherwise.</TD></TR>
+<TR><TD>num_options</TD><TD>int</TD><TD>The number of options associated
+ with this destination.</TD></TR>
+<TR><TD>options</TD><TD><A HREF="#cups_option_t">cups_option_t *</A></TD><TD>
+The options associated with this destination.</TD></TR>
+</TABLE>
+</CENTER>
+</P>
+<H3><A NAME="cups_job_t">CUPS Jobs</A></H3>
+<P>The CUPS job structure (<CODE>cups_job_t</CODE>) contains information
+ on a specific job:
+<CENTER>
+<TABLE BORDER="1" WIDTH="90%">
+<TR><TH>Member</TH><TH>Type</TH><TH>Description</TH></TR>
+<TR><TD>id</TD><TD>int</TD><TD>The job ID for this job.</TD></TR>
+<TR><TD>dest</TD><TD>char *</TD><TD>The destination for this job
+ (printer or class name).</TD></TR>
+<TR><TD>title</TD><TD>char *</TD><TD>The job-name for this job (title).</TD>
+</TR>
+<TR><TD>user</TD><TD>char *</TD><TD>The job-originating-user-name for
+ this job (username).</TD></TR>
+<TR><TD>format</TD><TD>char *</TD><TD>The document-format for this job
+ (MIME type string).</TD></TR>
+<TR><TD>state</TD><TD>ipp_jstate</TD><TD>The current state of the job.</TD>
+</TR>
+<TR><TD>size</TD><TD>int</TD><TD>The size of this job in kilobytes.</TD></TR>
+<TR><TD>priority</TD><TD>int</TD><TD>The priority of this job from 1 to
+ 100 (50 is normal).</TD></TR>
+<TR><TD>completed_time</TD><TD>time_t</TD><TD>The time the job was
+ completed, or 0 if not yet completed.</TD></TR>
+<TR><TD>creation_time</TD><TD>time_t</TD><TD>The time the job was
+ queued.</TD></TR>
+<TR><TD>processing_time</TD><TD>time_t</TD><TD>The time the job started
+ printing.</TD></TR>
+</TABLE>
+</CENTER>
+</P>
+<H3><A NAME="cups_lang_t">CUPS Messages</A></H3>
+<P>The CUPS messages structure (<CODE>cups_lang_t</CODE>) contains the
+ character set, locale name, and messages array:
+<CENTER>
+<TABLE BORDER="1" WIDTH="90%">
+<TR><TH>Member</TH><TH>Type</TH><TH>Description</TH></TR>
+<TR><TD>next</TD><TD>cups_lang_t *</TD><TD>Pointer to the next messages
+ structure in memory.</TD></TR>
+<TR><TD>used</TD><TD>int</TD><TD>The number of active users of this
+ messages structure.</TD></TR>
+<TR><TD>encoding</TD><TD>cups_encoding_t</TD><TD>The character encoding
+ of the message strings.</TD></TR>
+<TR><TD>language</TD><TD>char [16]</TD><TD>The language/locale name.</TD>
+</TR>
+<TR><TD>messages</TD><TD>char *[]</TD><TD>The array of message strings.</TD>
+</TR>
+</TABLE>
+</CENTER>
+</P>
+<H3><A NAME="cups_option_t">CUPS Options</A></H3>
+<P>The CUPS option structure (<CODE>cups_option_t</CODE>) contains the
+ option name and string value:
+<CENTER>
+<TABLE BORDER="1" WIDTH="90%">
+<TR><TH>Member</TH><TH>Type</TH><TH>Description</TH></TR>
+<TR><TD>name</TD><TD>char *</TD><TD>The name of the option.</TD></TR>
+<TR><TD>value</TD><TD>char *</TD><TD>The string value of the option.</TD>
+</TR>
+</TABLE>
+</CENTER>
+</P>
+<H2><A NAME="9_2">Networking Structures</A></H2>
+<H3><A NAME="http_t">HTTP State</A></H3>
+<P>The HTTP state structure (<CODE>http_t</CODE>) contains the current
+ state of a HTTP request or response:
+<CENTER>
+<TABLE BORDER="1" WIDTH="90%">
+<TR><TH>Member</TH><TH>Type</TH><TH>Description</TH></TR>
+<TR><TD>fd</TD><TD>int</TD><TD>The socket for the HTTP connection.</TD></TR>
+<TR><TD>blocking</TD><TD>int</TD><TD>1 if the HTTP functions should
+ block, 0 if not.</TD></TR>
+<TR><TD>error</TD><TD>int</TD><TD>The last OS error that occurred on the
+ socket.</TD></TR>
+<TR><TD>activity</TD><TD>time_t</TD><TD>The last time the HTTP
+ connection was used.</TD></TR>
+<TR><TD>state</TD><TD>http_state_t</TD><TD>The current HTTP
+ request/response state.</TD></TR>
+<TR><TD>status</TD><TD>int</TD><TD>The last HTTP status seen.</TD></TR>
+<TR><TD>version</TD><TD>http_version_t</TD><TD>The HTTP protocol version
+ in use.</TD></TR>
+<TR><TD>keep_alive</TD><TD>http_keep_alive_t</TD><TD>Whether or not to
+ use Keep-Alive</TD></TR>
+<TR><TD>hostaddr</TD><TD>struct sockaddr_in</TD><TD>The IPv4 address of
+ the HTTP server.</TD></TR>
+<TR><TD>hostname</TD><TD>char []</TD><TD>The hostname of the HTTP
+ server.</TD></TR>
+<TR><TD>fields</TD><TD>char [][]</TD><TD>The string values of all HTTP
+ request/response fields.</TD></TR>
+<TR><TD>data</TD><TD>char *</TD><TD>Current byte in data buffer.</TD></TR>
+<TR><TD>data_encoding</TD><TD>http_encoding_t</TD><TD>The transfer
+ encoding for the request/response.</TD></TR>
+<TR><TD>data_remaining</TD><TD>int</TD><TD>The number of bytes remaining
+ in the current request, response, or chunk.</TD></TR>
+<TR><TD>used</TD><TD>int</TD><TD>The number of bytes that are used in
+ the buffer.</TD></TR>
+<TR><TD>buffer</TD><TD>char []</TD><TD>The read/write buffer.</TD></TR>
+<TR><TD>auth_type</TD><TD>int</TD><TD>The type of authentication in use.</TD>
+</TR>
+<TR><TD>md5_state</TD><TD>md5_state_t</TD><TD>The current MD5 digest
+ state.</TD></TR>
+<TR><TD>nonce</TD><TD>char []</TD><TD>The nonce value for Digest
+ authentication.</TD></TR>
+<TR><TD>nonce_count</TD><TD>int</TD><TD>The nonce count value.</TD></TR>
+<TR><TD>tls</TD><TD>void *</TD><TD>A pointer to private encryption data.</TD>
+</TR>
+<TR><TD>encryption</TD><TD>http_encryption_t</TD><TD>The current
+ encryption mode.</TD></TR>
+</TABLE>
+</CENTER>
+</P>
+<H3><A NAME="ipp_t">IPP State</A></H3>
+<P>The IPP state structure (<CODE>ipp_t</CODE>) contains the current
+ state of a IPP request or response:
+<CENTER>
+<TABLE BORDER="1" WIDTH="90%">
+<TR><TH>Member</TH><TH>Type</TH><TH>Description</TH></TR>
+<TR><TD></TD><TD></TD><TD></TD></TR>
+</TABLE>
+</CENTER>
+</P>
+<H2><A NAME="9_3">Raster Structures</A></H2>
+<H3><A NAME="cups_raster_header_t">Raster Page Header</A></H3>
+<P>The raster page header (<CODE>cups_raster_header_t</CODE>) consists
+ of the PostScript page device dictionary for the page:
+<CENTER>
+<TABLE BORDER="1" WIDTH="90%">
+<TR><TH>Member</TH><TH>Type</TH><TH>Description</TH></TR>
+<TR><TD>MediaClass</TD><TD>char[64]</TD><TD>The media class name</TD></TR>
+<TR><TD>MediaColor</TD><TD>char[64]</TD><TD>The media color name</TD></TR>
+<TR><TD>MediaType</TD><TD>char[64]</TD><TD>The media type name</TD></TR>
+<TR><TD>OutputType</TD><TD>char[64]</TD><TD>The output type name</TD></TR>
+<TR><TD>AdvanceDistance</TD><TD>unsigned</TD><TD>The distance to advance
+ the media in points</TD></TR>
+<TR><TD>AdvanceMedia</TD><TD>cups_adv_t</TD><TD>When to advance the
+ media</TD></TR>
+<TR><TD>Collate</TD><TD>cups_bool_t</TD><TD>Whether or not to produce
+ collated copies</TD></TR>
+<TR><TD>CutMedia</TD><TD>cups_cut_t</TD><TD>When to cut the media</TD></TR>
+<TR><TD>Duplex</TD><TD>cups_bool_t</TD><TD>Whether or not to print on
+ both sides of the paper</TD></TR>
+<TR><TD>HWResolution</TD><TD>unsigned[2]</TD><TD>The resolution of the
+ page image in pixels per inch; the HWResolution[0] represents the
+ horizontal resolution and HWResolution[1] represents the vertical
+ resolution</TD></TR>
+<TR><TD>ImagingBoundingBox</TD><TD>unsigned[4]</TD><TD>The bounding box
+ for the page in points; the elements represent the left, bottom, right,
+ and top coordinates of the imaged area (if 0 then the whole page is
+ imaged)</TD></TR>
+<TR><TD>InsertSheet</TD><TD>cups_bool_t</TD><TD>Whether or not to insert
+ a sheet before this page</TD></TR>
+<TR><TD>Jog</TD><TD>cups_jog_t</TD><TD>When to jog copies of the page</TD>
+</TR>
+<TR><TD>LeadingEdge</TD><TD>cups_edge_t</TD><TD>The leading edge of the
+ page</TD></TR>
+<TR><TD>Margins</TD><TD>unsigned[2]</TD><TD>The lower-lefthand margin of
+ the page in points</TD></TR>
+<TR><TD>ManualFeed</TD><TD>cups_bool_t</TD><TD>Whether or not to
+ manually feed the page</TD></TR>
+<TR><TD>MediaPosition</TD><TD>unsigned</TD><TD>The input slot number to
+ use</TD></TR>
+<TR><TD>MediaWeight</TD><TD>unsigned</TD><TD>The weight of the output
+ media in grams/m<SUP>2</SUP></TD></TR>
+<TR><TD>MirrorPrint</TD><TD>cups_bool_t</TD><TD>Whether or not to mirror
+ the print</TD></TR>
+<TR><TD>NegativePrint</TD><TD>cups_bool_t</TD><TD>Whether or not to
+ invert the print</TD></TR>
+<TR><TD>NumCopies</TD><TD>unsigned</TD><TD>The number of copies to
+ produce</TD></TR>
+<TR><TD>Orientation</TD><TD>cups_orient_t</TD><TD>The orientation of the
+ page image</TD></TR>
+<TR><TD>OutputFaceUp</TD><TD>cups_bool_t</TD><TD>Whether or not to
+ output the page face up</TD></TR>
+<TR><TD>PageSize</TD><TD>unsigned[2]</TD><TD>The width and height of the
+ page in points</TD></TR>
+<TR><TD>Separations</TD><TD>cups_bool_t</TD><TD>Whether or not to output
+ separations</TD></TR>
+<TR><TD>TraySwitch</TD><TD>cups_bool_t</TD><TD>Whether or not to
+ automatically switch trays for the requested media size/type</TD></TR>
+<TR><TD>Tumble</TD><TD>cups_bool_t</TD><TD>Whether or not to rotate the
+ back side of the page</TD></TR>
+<TR><TD>cupsWidth</TD><TD>unsigned</TD><TD>The width of the page image
+ in pixels</TD></TR>
+<TR><TD>cupsHeight</TD><TD>unsigned</TD><TD>The height of the page image
+ in pixels</TD></TR>
+<TR><TD>cupsMediaType</TD><TD>unsigned</TD><TD>The device-specific media
+ type code</TD></TR>
+<TR><TD>cupsBitsPerColor</TD><TD>unsigned</TD><TD>The number of bits per
+ color</TD></TR>
+<TR><TD>cupsBitsPerPixel</TD><TD>unsigned</TD><TD>The number of bits per
+ pixel</TD></TR>
+<TR><TD>cupsBytesPerLine</TD><TD>unsigned</TD><TD>The number of bytes
+ per line of image data</TD></TR>
+<TR><TD>cupsColorOrder</TD><TD>cups_order_t</TD><TD>The order of color
+ values</TD></TR>
+<TR><TD>cupsColorSpace</TD><TD>cups_cspace_t</TD><TD>The type of color
+ values</TD></TR>
+<TR><TD>cupsCompression</TD><TD>unsigned</TD><TD>The device-specific
+ compression code</TD></TR>
+<TR><TD>cupsRowCount</TD><TD>unsigned</TD><TD>The device-specific row
+ count</TD></TR>
+<TR><TD>cupsRowFeed</TD><TD>unsigned</TD><TD>The device-specific row
+ feed</TD></TR>
+<TR><TD>cupsRowStep</TD><TD>unsigned</TD><TD>The device-specific row
+ step</TD></TR>
+</TABLE>
+</CENTER>
+</P>
+<H1 ALIGN="RIGHT"><A NAME="FUNCTIONS">D - Functions</A></H1>
+<P>This appendix provides a reference for all of the CUPS API functions.
+<!-- NEW PAGE -->
+</P>
+<H2><A NAME="cupsAddOption">cupsAddOption()</A></H2>
+<H3><A NAME="10_1_1">Usage</A></H3>
+<PRE>
+int
+cupsAddOption(const char *name,
+ const char *value,
+ int num_options,
+ cups_option_t **options);
+</PRE>
+<H3><A NAME="10_1_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>name</TD><TD>The name of the option.</TD></TR>
+<TR><TD>value</TD><TD>The value of the option.</TD></TR>
+<TR><TD>num_options</TD><TD>Number of options currently in the array.</TD>
+</TR>
+<TR><TD>options</TD><TD>Pointer to the options array.</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_1_3">Returns</A></H3>
+<P>The new number of options.</P>
+<H3><A NAME="10_1_4">Description</A></H3>
+<P><CODE>cupsAddOption()</CODE> adds an option to the specified array.</P>
+<H3><A NAME="10_1_5">Example</A></H3>
+<PRE>
+#include &lt;cups.h&gt;
+
+...
+
+/* Declare the options array */
+int num_options;
+<A HREF="#cups_option_t">cups_option_t</A> *options;
+
+/* Initialize the options array */
+num_options = 0;
+options = (cups_option_t *)0;
+
+/* Add options using cupsAddOption() */
+num_options = cupsAddOption(&quot;media&quot;, &quot;letter&quot;, num_options, &amp;options);
+num_options = cupsAddOption(&quot;resolution&quot;, &quot;300dpi&quot;, num_options, &amp;options);
+</PRE>
+<H3><A NAME="10_1_6">See Also</A></H3>
+<A HREF="#cupsFreeOptions"> <CODE>cupsFreeOptions()</CODE></A>,<A HREF="#cupsGetOption">
+ <CODE>cupsGetOption()</CODE></A>,<A HREF="#cupsParseOptions"> <CODE>
+cupsParseOptions()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="cupsCancelJob">cupsCancelJob()</A></H2>
+<H3><A NAME="10_2_1">Usage</A></H3>
+<PRE>
+int
+cupsCancelJob(const char *dest,
+ int job);
+</PRE>
+<H3><A NAME="10_2_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>dest</TD><TD>Printer or class name</TD></TR>
+<TR><TD>job</TD><TD>Job ID</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_2_3">Returns</A></H3>
+<P>1 on success, 0 on failure. On failure the error can be found by
+ calling<A HREF="#cupsLastError"> <CODE>cupsLastError()</CODE></A>.</P>
+<H3><A NAME="10_2_4">Description</A></H3>
+<P><CODE>cupsCancelJob()</CODE> cancels the specifies job.</P>
+<H3><A NAME="10_2_5">Example</A></H3>
+<PRE>
+#include &lt;cups.h&gt;
+
+cupsCancelJob(&quot;LaserJet&quot;, 1);
+</PRE>
+<H3><A NAME="10_2_6">See Also</A></H3>
+<P><A HREF="#cupsLastError"> <CODE>cupsLastError()</CODE></A>,<A HREF="#cupsPrintFile">
+ <CODE>cupsPrintFile()</CODE></A>
+<!-- NEW PAGE -->
+</P>
+<H2><A NAME="cupsDoFileRequest">cupsDoFileRequest()</A></H2>
+<H3><A NAME="10_3_1">Usage</A></H3>
+<PRE>
+ipp_t *
+cupsDoFileRequest(http_t *http,
+ ipp_t *request,
+ const char *resource,
+ const char *filename);
+</PRE>
+<H3><A NAME="10_3_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>http</TD><TD>HTTP connection to server.</TD></TR>
+<TR><TD>request</TD><TD>IPP request data.</TD></TR>
+<TR><TD>resource</TD><TD>HTTP resource name for POST.</TD></TR>
+<TR><TD>filename</TD><TD>File to send with POST request (<CODE>NULL</CODE>
+ pointer if none.)</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_3_3">Returns</A></H3>
+<P>IPP response data or <CODE>NULL</CODE> if the request fails. On
+ failure the error can be found by calling<A HREF="#cupsLastError"> <CODE>
+cupsLastError()</CODE></A>.</P>
+<H3><A NAME="10_3_4">Description</A></H3>
+<P><CODE>cupsDoFileRequest()</CODE> 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.</P>
+<H3><A NAME="10_3_5">Example</A></H3>
+<PRE>
+#include &lt;cups.h&gt;
+
+<A HREF="#http_t">http_t</A> *http;
+<A HREF="#cups_lang_t">cups_lang_t</A> *language;
+<A HREF="#ipp_t">ipp_t</A> *request;
+ipp_t *response;
+
+...
+
+/* Get the default language */
+language = <A HREF="#cupsLangDefault">cupsLangDefault()</A>;
+
+/* Create a new IPP request */
+request = <A HREF="#ippNew">ippNew()</A>;
+
+request-&gt;request.op.operation_id = IPP_PRINT_FILE;
+request-&gt;request.op.request_id = 1;
+
+/* Add required attributes */
+<A HREF="#ippAddString">ippAddString</A>(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ &quot;attributes-charset&quot;, NULL, <A HREF="#cupsLangEncoding">cupsLangEncoding</A>(language));
+
+ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ &quot;attributes-natural-language&quot;, NULL,
+ language != NULL ? language-&gt;language : &quot;C&quot;);
+
+ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, &quot;printer-uri&quot;,
+ NULL, &quot;ipp://hostname/resource&quot;);
+
+ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, &quot;requesting-user-name&quot;,
+ NULL, <A HREF="#cupsUser">cupsUser()</A>);
+
+/* Do the request... */
+response = cupsDoFileRequest(http, request, &quot;/resource&quot;, &quot;filename.txt&quot;);
+</PRE>
+<H3><A NAME="10_3_6">See Also</A></H3>
+<P><A HREF="#cupsLangDefault"> <CODE>cupsLangDefault()</CODE></A>,<A HREF="#cupsLangEncoding">
+ <CODE>cupsLangEncoding()</CODE></A>,<A HREF="#cupsUser"> <CODE>
+cupsUser()</CODE></A>,<A HREF="#httpConnect"> <CODE>httpConnect()</CODE></A>
+,<A HREF="#ippAddString"> <CODE>ippAddString()</CODE></A>,<A HREF="#ippNew">
+ <CODE>ippNew()</CODE></A>
+<!-- NEW PAGE -->
+</P>
+<H2><A NAME="cupsDoRequest">cupsDoRequest()</A></H2>
+<H3><A NAME="10_4_1">Usage</A></H3>
+<PRE>
+ipp_t *
+cupsDoRequest(http_t *http,
+ ipp_t *request,
+ const char *resource);
+</PRE>
+<H3><A NAME="10_4_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>http</TD><TD>HTTP connection to server.</TD></TR>
+<TR><TD>request</TD><TD>IPP request data.</TD></TR>
+<TR><TD>resource</TD><TD>HTTP resource name for POST.</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_4_3">Returns</A></H3>
+<P>IPP response data or <CODE>NULL</CODE> if the request fails. On
+ failure the error can be found by calling<A HREF="#cupsLastError"> <CODE>
+cupsLastError()</CODE></A>.</P>
+<H3><A NAME="10_4_4">Description</A></H3>
+<P><CODE>cupsDoRequest()</CODE> 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.</P>
+<H3><A NAME="10_4_5">Example</A></H3>
+<PRE>
+#include &lt;cups.h&gt;
+
+<A HREF="#http_t">http_t</A> *http;
+<A HREF="#cups_lang_t">cups_lang_t</A> *language;
+<A HREF="#ipp_t">ipp_t</A> *request;
+ipp_t *response;
+
+...
+
+/* Get the default language */
+language = <A HREF="#cupsLangDefault">cupsLangDefault()</A>;
+
+/* Create a new IPP request */
+request = <A HREF="#ippNew">ippNew()</A>;
+
+request-&gt;request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
+request-&gt;request.op.request_id = 1;
+
+/* Add required attributes */
+<A HREF="#ippAddString">ippAddString</A>(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ &quot;attributes-charset&quot;, NULL, <A HREF="#cupsLangEncoding">cupsLangEncoding</A>(language));
+
+ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ &quot;attributes-natural-language&quot;, NULL,
+ language != NULL ? language-&gt;language : &quot;C&quot;);
+
+ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, &quot;printer-uri&quot;,
+ NULL, &quot;ipp://hostname/resource&quot;);
+
+/* Do the request... */
+response = cupsDoRequest(http, request, &quot;/resource&quot;);
+</PRE>
+<H3><A NAME="10_4_6">See Also</A></H3>
+<P><A HREF="#cupsLangDefault"> <CODE>cupsLangDefault()</CODE></A>,<A HREF="#cupsLangEncoding">
+ <CODE>cupsLangEncoding()</CODE></A>,<A HREF="#cupsUser"> <CODE>
+cupsUser()</CODE></A>,<A HREF="#httpConnect"> <CODE>httpConnect()</CODE></A>
+,<A HREF="#ippAddString"> <CODE>ippAddString()</CODE></A>,<A HREF="#ippNew">
+ <CODE>ippNew()</CODE></A>
+<!-- NEW PAGE -->
+</P>
+<H2><A NAME="cupsFreeOptions">cupsFreeOptions()</A></H2>
+<H3><A NAME="10_5_1">Usage</A></H3>
+<PRE>
+void
+cupsFreeOptions(int num_options,
+ cups_option_t *options);
+
+</PRE>
+<H3><A NAME="10_5_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>num_options</TD><TD>Number of options in array.</TD></TR>
+<TR><TD>options</TD><TD>Pointer to options array.</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_5_3">Description</A></H3>
+<P><CODE>cupsFreeOptions()</CODE> frees all memory associated with the
+ option array specified.</P>
+<H3><A NAME="10_5_4">Example</A></H3>
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+int num_options;
+cups_option_t *options;
+
+...
+
+cupsFreeOptions(num_options, options);
+</PRE>
+<H3><A NAME="10_5_5">See Also</A></H3>
+<P><A HREF="#cupsAddOption"> cupsAddOption()</A>,<A HREF="#cupsGetOption">
+ cupsGetOption()</A>,<A HREF="#cupsMarkOptions"> cupsMarkOptions()</A>,<A
+HREF="#cupsParseOptions"> cupsParseOptions()</A>
+<!-- NEW PAGE -->
+</P>
+<H2><A NAME="cupsGetClasses">cupsGetClasses()</A></H2>
+<H3><A NAME="10_6_1">Usage</A></H3>
+<PRE>
+int
+cupsGetClasses(char ***classes);
+</PRE>
+<H3><A NAME="10_6_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>classes</TD><TD>Pointer to character pointer array.</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_6_3">Returns</A></H3>
+<P>The number of printer classes available.</P>
+<H3><A NAME="10_6_4">Description</A></H3>
+<P><CODE>cupsGetClasses()</CODE> gets a list of the available printer
+ classes. The returned array should be freed using the <CODE>free()</CODE>
+ when it is no longer needed.</P>
+<H3><A NAME="10_6_5">Example</A></H3>
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+int i;
+int num_classes;
+char **classes;
+
+...
+
+num_classes = cupsGetClasses(
+
+...
+
+if (num_classes &gt; 0)
+{
+ for (i = 0; i &lt;num_classes; i ++)
+ free(classes[i]);
+
+ free(classes);
+}
+</PRE>
+<H3><A NAME="10_6_6">See Also</A></H3>
+<P><A HREF="#cupsGetDefault"> cupsGetDefault(),<A HREF="#cupsGetPrinters">
+ cupsGetPrinters()
+<!-- NEW PAGE -->
+</A></A></P>
+<H2><A NAME="cupsGetDefault">cupsGetDefault()</A></H2>
+<H3><A NAME="10_7_1">Usage</A></H3>
+<PRE>
+const char *
+cupsGetDefault(void);
+</PRE>
+<H3><A NAME="10_7_2">Returns</A></H3>
+<P>A pointer to the default destination.</P>
+<H3><A NAME="10_7_3">Description</A></H3>
+<P><CODE>cupsGetDefault()</CODE> 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.</P>
+<H3><A NAME="10_7_4">Example</A></H3>
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+printf(&quot;The default destination is %s\n&quot;, cupsGetDefault());
+</PRE>
+<H3><A NAME="10_7_5">See Also</A></H3>
+<P><A HREF="#cupsGetClasses"> cupsGetClasses(),<A HREF="#cupsGetPrinters">
+ cupsGetPrinters()
+<!-- NEW PAGE -->
+</A></A></P>
+<H2><A NAME="cupsGetOption">cupsGetOption()</A></H2>
+<H3><A NAME="10_8_1">Usage</A></H3>
+<PRE>
+const char *
+cupsGetOption(const char *name,
+ int num_options,
+ cups_option_t *options);
+</PRE>
+<H3><A NAME="10_8_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>name</TD><TD>The name of the option.</TD></TR>
+<TR><TD>num_options</TD><TD>The number of options in the array.</TD></TR>
+<TR><TD>options</TD><TD>The options array.</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_8_3">Returns</A></H3>
+<P>A pointer to the option values or <CODE>NULL</CODE> if the option is
+ not defined.</P>
+<H3><A NAME="10_8_4">Description</A></H3>
+<P><CODE>cupsGetOption()</CODE> returns the first occurrence of the
+ named option. If the option is not included in the options array then a
+ <CODE>NULL</CODE> pointer is returned.</P>
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+int num_options;
+cups_option_t *options;
+const char *media;
+
+...
+
+media = cupsGetOption(&quot;media&quot;, num_options, options);
+</PRE>
+<H3><A NAME="10_8_5">See Also</A></H3>
+<P><A HREF="#cupsAddOption"> cupsAddOption()</A>,<A HREF="#cupsFreeOptions">
+ cupsFreeOptions()</A>,<A HREF="#cupsMarkOptions"> cupsMarkOptions()</A>
+,<A HREF="#cupsParseOptions"> cupsParseOptions()</A>
+<!-- NEW PAGE -->
+</P>
+<H2><A NAME="cupsGetPassword">cupsGetPassword()</A></H2>
+<H3><A NAME="10_9_1">Usage</A></H3>
+<PRE>
+const char *
+cupsGetPassword(const char *prompt);
+</PRE>
+<H3><A NAME="10_9_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>prompt</TD><TD>The prompt to display to the user.</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_9_3">Returns</A></H3>
+<P>A pointer to the password that was entered or <CODE>NULL</CODE> if no
+ password was entered.</P>
+<H3><A NAME="10_9_4">Description</A></H3>
+<P><CODE>cupsGetPassword()</CODE> displays the prompt string and asks
+ the user for a password. The password text is not echoed to the user.</P>
+<H3><A NAME="10_9_5">Example</A></H3>
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+char *password;
+
+...
+
+password = cupsGetPassword(&quot;Please enter a password:&quot;);
+</PRE>
+<H3><A NAME="10_9_6">See Also</A></H3>
+<P><A HREF="#cupsServer"> cupsServer()</A>,<A HREF="#cupsSetPasswordCB">
+ cupsSetPasswordCB()</A>,<A HREF="#cupsSetServer"> cupsSetServer()</A>,<A
+HREF="#cupsSetUser"> cupsSetUser()</A>,<A HREF="#cupsUser"> cupsUser()</A>
+<!-- NEW PAGE -->
+
+</P>
+<H2><A NAME="cupsGetPPD">cupsGetPPD()</A></H2>
+<H3><A NAME="10_10_1">Usage</A></H3>
+<PRE>
+const char *
+cupsGetPPD(const char *printer);
+</PRE>
+<H3><A NAME="10_10_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>printer</TD><TD>The name of the printer.</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_10_3">Returns</A></H3>
+<P>The name of a temporary file containing the PPD file or <CODE>NULL</CODE>
+ if the printer cannot be located or does not have a PPD file.</P>
+<H3><A NAME="10_10_4">Description</A></H3>
+<P><CODE>cupsGetPPD()</CODE> gets a copy of the PPD file for the named
+ printer. The printer name can be of the form &quot;printer&quot; or
+ &quot;printer@hostname&quot;.</P>
+<P>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 <CODE>cupsGetPPD()</CODE>.</P>
+<H3><A NAME="10_10_5">Example</A></H3>
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+char *ppd;
+
+...
+
+ppd = cupsGetPPD(&quot;printer@hostname&quot;);
+
+...
+
+unlink(ppd);
+</PRE>
+
+<!-- NEW PAGE -->
+<H2><A NAME="cupsGetPrinters">cupsGetPrinters()</A></H2>
+<H3><A NAME="10_11_1">Usage</A></H3>
+<PRE>
+int
+cupsGetPrinters(char ***printers);
+</PRE>
+<H3><A NAME="10_11_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>printers</TD><TD>Pointer to character pointer array.</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_11_3">Returns</A></H3>
+<P>The number of printer printers available.</P>
+<H3><A NAME="10_11_4">Description</A></H3>
+<P><CODE>cupsGetPrinters()</CODE> gets a list of the available printers.
+ The returned array should be freed using the <CODE>free()</CODE> when
+ it is no longer needed.</P>
+<H3><A NAME="10_11_5">Example</A></H3>
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+int i;
+int num_printers;
+char **printers;
+
+...
+
+num_printers = cupsGetPrinters(
+
+...
+
+if (num_printers &gt; 0)
+{
+ for (i = 0; i &lt;num_printers; i ++)
+ free(printers[i]);
+
+ free(printers);
+}
+</PRE>
+<H3><A NAME="10_11_6">See Also</A></H3>
+<P><A HREF="#cupsGetClasses"> cupsGetClasses(),<A HREF="#cupsGetDefault">
+ cupsGetDefault()
+<!-- NEW PAGE -->
+</A></A></P>
+<H2><A NAME="cupsLangDefault">cupsLangDefault()</A></H2>
+<H3><A NAME="10_12_1">Usage</A></H3>
+<PRE>
+const char *
+cupsLangDefault(void);
+</PRE>
+<H3><A NAME="10_12_2">Returns</A></H3>
+<P>A pointer to the default language structure.</P>
+<H3><A NAME="10_12_3">Description</A></H3>
+<P><CODE>cupsLangDefault()</CODE> returns a language structure for the
+ default language. The default language is defined by the <CODE>LANG</CODE>
+ environment variable. If the specified language cannot be located then
+ the POSIX (English) locale is used.</P>
+<P>Call <CODE>cupsLangFree()</CODE> to free any memory associated with
+ the language structure when you are done.</P>
+<H3><A NAME="10_12_4">Example</A></H3>
+<PRE>
+#include &lt;cups/language.h&gt;
+
+cups_lang_t *language;
+...
+
+language = cupsLangDefault();
+
+...
+
+cupsLangFree(language);
+</PRE>
+<H3><A NAME="10_12_5">See Also</A></H3>
+<P><A HREF="#cupsLangEncoding"> cupsLangEncoding()</A>,<A HREF="#cupsLangFlush">
+ cupsLangFlush()</A>,<A HREF="#cupsLangFree"> cupsLangFree()</A>,<A HREF="#cupsLangGet">
+ cupsLangGet()</A>,<A HREF="#cupsLangString"> cupsLangString()</A>
+<!-- NEW PAGE -->
+</P>
+<H2><A NAME="cupsLangEncoding">cupsLangEncoding()</A></H2>
+<H3><A NAME="10_13_1">Usage</A></H3>
+<PRE>
+char *
+cupsLangEncoding(cups_lang_t *language);
+</PRE>
+<H3><A NAME="10_13_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>language</TD><TD>The language structure.</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_13_3">Returns</A></H3>
+<P>A pointer to the encoding string.</P>
+<H3><A NAME="10_13_4">Description</A></H3>
+<P><CODE>cupsLangEncoding()</CODE> returns the language encoding used
+ for the specified language, e.g. &quot;iso-8859-1&quot;, &quot;utf-8&quot;, etc.</P>
+<H3><A NAME="10_13_5">Example</A></H3>
+<PRE>
+#include &lt;cups/language.h&gt;
+
+cups_lang_t *language;
+char *encoding;
+...
+
+language = cupsLangDefault();
+encoding = cupsLangEncoding(language);
+...
+
+cupsLangFree(language);
+</PRE>
+<H3><A NAME="10_13_6">See Also</A></H3>
+<P><A HREF="#cupsLangDefault"> cupsLangDefault()</A>,<A HREF="#cupsLangFlush">
+ cupsLangFlush()</A>,<A HREF="#cupsLangFree"> cupsLangFree()</A>,<A HREF="#cupsLangGet">
+ cupsLangGet()</A>,<A HREF="#cupsLangString"> cupsLangString()</A>
+<!-- NEW PAGE -->
+</P>
+<H2><A NAME="cupsLangFlush">cupsLangFlush()</A></H2>
+<H3><A NAME="10_14_1">Usage</A></H3>
+<PRE>
+void
+cupsLangFlush(void);
+</PRE>
+<H3><A NAME="10_14_2">Description</A></H3>
+<P><CODE>cupsLangFlush()</CODE> frees all language structures that have
+ been allocated.</P>
+<H3><A NAME="10_14_3">Example</A></H3>
+<PRE>
+#include &lt;cups/language.h&gt;
+
+...
+
+cupsLangFlush();
+</PRE>
+<H3><A NAME="10_14_4">See Also</A></H3>
+<P><A HREF="#cupsLangDefault"> cupsLangDefault()</A>,<A HREF="#cupsLangEncoding">
+ cupsLangEncoding()</A>,<A HREF="#cupsLangFree"> cupsLangFree()</A>,<A HREF="#cupsLangGet">
+ cupsLangGet()</A>,<A HREF="#cupsLangString"> cupsLangString()</A>
+<!-- NEW PAGE -->
+</P>
+<H2><A NAME="cupsLangFree">cupsLangFree()</A></H2>
+<H3><A NAME="10_15_1">Usage</A></H3>
+<PRE>
+void
+cupsLangFree(cups_lang_t *language);
+</PRE>
+<H3><A NAME="10_15_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>language</TD><TD>The language structure to free.</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_15_3">Description</A></H3>
+<P><CODE>cupsLangFree()</CODE> frees the specified language structure.</P>
+<H3><A NAME="10_15_4">Example</A></H3>
+<PRE>
+#include &lt;cups/language.h&gt;
+
+cups_lang_t *language;
+...
+
+cupsLangFree(language);
+</PRE>
+<H3><A NAME="10_15_5">See Also</A></H3>
+<P><A HREF="#cupsLangDefault"> cupsLangDefault()</A>,<A HREF="#cupsLangEncoding">
+ cupsLangEncoding()</A>,<A HREF="#cupsLangFlush"> cupsLangFlush()</A>,<A HREF="#cupsLangGet">
+ cupsLangGet()</A>,<A HREF="#cupsLangString"> cupsLangString()</A>
+<!-- NEW PAGE -->
+</P>
+<H2><A NAME="cupsLangGet">cupsLangGet()</A></H2>
+<H3><A NAME="10_16_1">Usage</A></H3>
+<PRE>
+cups_lang_t *
+cupsLangGet(const char *name);
+</PRE>
+<H3><A NAME="10_16_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>name</TD><TD>The name of the locale.</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_16_3">Returns</A></H3>
+<P>A pointer to a language structure.</P>
+<H3><A NAME="10_16_4">Description</A></H3>
+<P><CODE>cupsLangGet()</CODE> returns a language structure for the
+ specified locale. If the locale is not defined then the POSIX (English)
+ locale is substituted.</P>
+<H3><A NAME="10_16_5">Example</A></H3>
+<PRE>
+#include &lt;cups/language.h&gt;
+
+cups_lang_t *language;
+
+...
+
+language = cupsLangGet(&quot;fr&quot;);
+
+...
+
+cupsLangFree(language);
+</PRE>
+<H3><A NAME="10_16_6">See Also</A></H3>
+<P><A HREF="#cupsLangDefault"> cupsLangDefault()</A>,<A HREF="#cupsLangEncoding">
+ cupsLangEncoding()</A>,<A HREF="#cupsLangFlush"> cupsLangFlush()</A>,<A HREF="#cupsLangFree">
+ cupsLangFree()</A>,<A HREF="#cupsLangString"> cupsLangString()</A>
+<!-- NEW PAGE -->
+</P>
+<H2><A NAME="cupsLangString">cupsLangString()</A></H2>
+<H3><A NAME="10_17_1">Usage</A></H3>
+<PRE>
+char *
+cupsLangString(cups_lang_t *language,
+ int message);
+</PRE>
+<H3><A NAME="10_17_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>language</TD><TD>The language to query.</TD></TR>
+<TR><TD>message</TD><TD>The message number.</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_17_3">Returns</A></H3>
+<P>A pointer to the message string or <CODE>NULL</CODE> if the message
+ is not defined.</P>
+<H3><A NAME="10_17_4">Description</A></H3>
+<P><CODE>cupsLangString()</CODE> returns a pointer to the specified
+ message string in the specified language.</P>
+<H3><A NAME="10_17_5">Example</A></H3>
+<PRE>
+#include &lt;cups/language.h&gt;
+
+cups_lang_t *language;
+char *s;
+...
+
+language = cupsLangGet(&quot;fr&quot;);
+
+s = cupsLangString(language, CUPS_MSG_YES);
+
+...
+
+cupsLangFree(language);
+</PRE>
+<H3><A NAME="10_17_6">See Also</A></H3>
+<P><A HREF="#cupsLangDefault"> cupsLangDefault()</A>,<A HREF="#cupsLangEncoding">
+ cupsLangEncoding()</A>,<A HREF="#cupsLangFlush"> cupsLangFlush()</A>,<A HREF="#cupsLangFree">
+ cupsLangFree()</A>,<A HREF="#cupsLangGet"> cupsLangGet()</A>
+<!-- NEW PAGE -->
+</P>
+<H2><A NAME="cupsLastError">cupsLastError()</A></H2>
+<H3><A NAME="10_18_1">Usage</A></H3>
+<PRE>
+ipp_status_t
+cupsLastError(void);
+</PRE>
+<H3><A NAME="10_18_2">Returns</A></H3>
+<P>An enumeration containing the last IPP error.</P>
+<H3><A NAME="10_18_3">Description</A></H3>
+<P><CODE>cupsLastError()</CODE> returns the last IPP error that
+ occurred. If no error occurred then it will return <CODE>IPP_OK</CODE>
+ or <CODE>IPP_OK_CONFLICT</CODE>.</P>
+<H3><A NAME="10_18_4">Example</A></H3>
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+ipp_status_t status;
+
+...
+
+status = cupsLastError();
+</PRE>
+<H3><A NAME="10_18_5">See Also</A></H3>
+<P><A HREF="#cupsCancelJob"> cupsCancelJob()</A>,<A HREF="#cupsPrintFile">
+ cupsPrintFile()</A>
+<!-- NEW PAGE -->
+</P>
+<H2><A NAME="cupsMarkOptions">cupsMarkOptions()</A></H2>
+<H3><A NAME="10_19_1">Usage</A></H3>
+<PRE>
+int
+cupsMarkOptions(ppd_file_t *ppd,
+ int num_options,
+ cups_option_t *options);
+</PRE>
+<H3><A NAME="10_19_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>ppd</TD><TD>The PPD file to mark.</TD></TR>
+<TR><TD>num_options</TD><TD>The number of options in the options array.</TD>
+</TR>
+<TR><TD>options</TD><TD>A pointer to the options array.</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_19_3">Returns</A></H3>
+<P>The number of conflicts found.</P>
+<H3><A NAME="10_19_4">Description</A></H3>
+<P><CODE>cupsMarkOptions()</CODE> marks options in the PPD file. It also
+ handles mapping of IPP option names and values to PPD option names.</P>
+<H3><A NAME="10_19_5">Example</A></H3>
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+int num_options;
+cups_option_t *options;
+ppd_file_t *ppd;
+
+...
+
+cupsMarkOptions(ppd, num_options, options);
+</PRE>
+<H3><A NAME="10_19_6">See Also</A></H3>
+<P><A HREF="#cupsAddOption"> cupsAddOption()</A>,<A HREF="#cupsFreeOptions">
+ cupsFreeOptions()</A>,<A HREF="#cupsGetOption"> cupsGetOption()</A>,<A HREF="#cupsParseOptions">
+ cupsParseOptions()</A>
+<!-- NEW PAGE -->
+</P>
+<H2><A NAME="cupsParseOptions">cupsParseOptions()</A></H2>
+<H3><A NAME="10_20_1">Usage</A></H3>
+<PRE>
+int
+cupsParseOptions(const char *arg,
+ int num_options,
+ cups_option_t **options);
+</PRE>
+<H3><A NAME="10_20_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>arg</TD><TD>The string containing one or more options.</TD></TR>
+<TR><TD>num_options</TD><TD>The number of options in the options array.</TD>
+</TR>
+<TR><TD>options</TD><TD>A pointer to the options array pointer.</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_20_3">Returns</A></H3>
+<P>The new number of options in the array.</P>
+<H3><A NAME="10_20_4">Description</A></H3>
+<P><CODE>cupsParseOptions()</CODE> parses the specifies string for one
+ or more options of the form &quot;name=value&quot;, &quot;name&quot;, or &quot;noname&quot;. It can
+ be called multiple times to combine the options from several strings.</P>
+<H3><A NAME="10_20_5">Example</A></H3>
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+int num_options;
+cups_option_t *options;
+
+...
+
+num_options = 0;
+options = (cups_option_t *)0;
+num_options = cupsParseOptions(argv[5], num_options, &amp;options);
+</PRE>
+<H3><A NAME="10_20_6">See Also</A></H3>
+<P><A HREF="#cupsAddOption"> cupsAddOption()</A>,<A HREF="#cupsFreeOptions">
+ cupsFreeOptions()</A>,<A HREF="#cupsGetOption"> cupsGetOption()</A>,<A HREF="#cupsMarkOptions">
+ cupsMarkOptions()</A>
+<!-- NEW PAGE -->
+</P>
+<H2><A NAME="cupsPrintFile">cupsPrintFile()</A></H2>
+<H3><A NAME="10_21_1">Usage</A></H3>
+<PRE>
+int
+cupsPrintFile(const char *printer,
+ const char *filename,
+ const char *title,
+ int num_options,
+ cups_option_t *options);
+</PRE>
+<H3><A NAME="10_21_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>printer</TD><TD>The printer or class to print to.</TD></TR>
+<TR><TD>filename</TD><TD>The file to print.</TD></TR>
+<TR><TD>title</TD><TD>The job title.</TD></TR>
+<TR><TD>num_options</TD><TD>The number of options in the options array.</TD>
+</TR>
+<TR><TD>options</TD><TD>A pointer to the options array.</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_21_3">Returns</A></H3>
+<P>The new job ID number or 0 on error.</P>
+<H3><A NAME="10_21_4">Description</A></H3>
+<P><CODE>cupsPrintFile()</CODE> 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 <CODE>cupsLastError()</CODE>.</P>
+<H3><A NAME="10_21_5">Example</A></H3>
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+int num_options;
+cups_option_t *options;
+int jobid;
+
+...
+
+jobid = cupsPrintFile(&quot;printer@hostname&quot;, &quot;filename.ps&quot;, &quot;Job Title&quot;,
+ num_options, options);
+</PRE>
+<H3><A NAME="10_21_6">See Also</A></H3>
+<P><A HREF="#cupsCancelJob"> cupsCancelJob()</A>,<A HREF="#cupsLastError">
+ cupsLastError()</A>,<A HREF="#cupsPrintFiles"> cupsPrintFiles()</A>
+<!-- NEW PAGE -->
+</P>
+<H2><A NAME="cupsPrintFiles">cupsPrintFiles()</A></H2>
+<H3><A NAME="10_22_1">Usage</A></H3>
+<PRE>
+int
+cupsPrintFiles(const char *printer,
+ int num_files,
+ const char **files,
+ const char *title,
+ int num_options,
+ cups_option_t *options);
+</PRE>
+<H3><A NAME="10_22_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>printer</TD><TD>The printer or class to print to.</TD></TR>
+<TR><TD>num_files</TD><TD>The number of files to print.</TD></TR>
+<TR><TD>files</TD><TD>The files to print.</TD></TR>
+<TR><TD>title</TD><TD>The job title.</TD></TR>
+<TR><TD>num_options</TD><TD>The number of options in the options array.</TD>
+</TR>
+<TR><TD>options</TD><TD>A pointer to the options array.</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_22_3">Returns</A></H3>
+<P>The new job ID number or 0 on error.</P>
+<H3><A NAME="10_22_4">Description</A></H3>
+<P><CODE>cupsPrintFiles()</CODE> sends multiple files to the specified
+ printer or class for printing. If the job cannot be printed the error
+ code can be found by calling <CODE>cupsLastError()</CODE>.</P>
+<H3><A NAME="10_22_5">Example</A></H3>
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+int num_files;
+const char *files[100];
+int num_options;
+cups_option_t *options;
+int jobid;
+
+...
+
+jobid = cupsPrintFiles(&quot;printer@hostname&quot;, num_files, files,
+ &quot;Job Title&quot;, num_options, options);
+</PRE>
+<H3><A NAME="10_22_6">See Also</A></H3>
+<P><A HREF="#cupsCancelJob"> cupsCancelJob()</A>,<A HREF="#cupsLastError">
+ cupsLastError()</A>,<A HREF="#cupsPrintFile"> cupsPrintFile()</A>
+<!-- NEW PAGE -->
+</P>
+<H2><A NAME="cupsRasterClose">cupsRasterClose()</A></H2>
+<H3><A NAME="10_23_1">Usage</A></H3>
+<PRE>
+void
+cupsRasterClose(cups_raster_t *ras);
+</PRE>
+<H3><A NAME="10_23_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>ras</TD><TD>The raster stream to close.</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_23_3">Description</A></H3>
+<P><CODE>cupsRasterClose()</CODE> closes the specified raster stream.</P>
+<H3><A NAME="10_23_4">Example</A></H3>
+<PRE>
+#include &lt;cups/raster.h&gt;
+
+cups_raster_t *ras;
+
+...
+
+cupsRasterClose(ras);
+</PRE>
+<H3><A NAME="10_23_5">See Also</A></H3>
+<P><A HREF="#cupsRasterOpen"> cupsRasterOpen()</A>,<A HREF="#cupsRasterReadHeader">
+ cupsRasterReadHeader()</A>,<A HREF="#cupsRasterReadPixels">
+ cupsRasterReadPixels()</A>,<A HREF="#cupsRasterWriteHeader">
+ cupsRasterWriteHeader()</A>,<A HREF="#cupsRasterWritePixels">
+ cupsRasterWritePixels()</A>
+<!-- NEW PAGE -->
+</P>
+<H2><A NAME="cupsRasterOpen">cupsRasterOpen()</A></H2>
+<H3><A NAME="10_24_1">Usage</A></H3>
+<PRE>
+cups_raster_t *
+cupsRasterOpen(int fd,
+ cups_mode_t mode);
+</PRE>
+<H3><A NAME="10_24_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>fd</TD><TD>The file descriptor to use.</TD></TR>
+<TR><TD>mode</TD><TD>The mode to use; <CODE>CUPS_RASTER_READ</CODE> or <CODE>
+CUPS_RASTER_WRITE</CODE>.</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_24_3">Returns</A></H3>
+<P>A pointer to a raster stream or <CODE>NULL</CODE> if there was an
+ error.</P>
+<H3><A NAME="10_24_4">Description</A></H3>
+<P><CODE>cupsRasterOpen()</CODE> opens a raster stream for reading or
+ writing.</P>
+<H3><A NAME="10_24_5">Example</A></H3>
+<PRE>
+#include &lt;cups/raster.h&gt;
+
+cups_raster_t *ras;
+
+...
+
+ras = cupsRasterOpen(0, CUPS_RASTER_READ);
+</PRE>
+<H3><A NAME="10_24_6">See Also</A></H3>
+<P><A HREF="#cupsRasterClose"> cupsRasterClose()</A>,<A HREF="#cupsRasterReadHeader">
+ cupsRasterReadHeader()</A>,<A HREF="#cupsRasterReadPixels">
+ cupsRasterReadPixels()</A>,<A HREF="#cupsRasterWriteHeader">
+ cupsRasterWriteHeader()</A>,<A HREF="#cupsRasterWritePixels">
+ cupsRasterWritePixels()</A>
+<!-- NEW PAGE -->
+</P>
+<H2><A NAME="cupsRasterReadHeader">cupsRasterReadHeader()</A></H2>
+<H3><A NAME="10_25_1">Usage</A></H3>
+<PRE>
+unsigned
+cupsRasterReadHeader(cups_raster_t *ras,
+ cups_page_header_t *header);
+</PRE>
+<H3><A NAME="10_25_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>ras</TD><TD>The raster stream to read from.</TD></TR>
+<TR><TD>header</TD><TD>A pointer to a page header structure to read
+ into.</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_25_3">Returns</A></H3>
+<P>1 on success, 0 on EOF or error.</P>
+<H3><A NAME="10_25_4">Description</A></H3>
+<P><CODE>cupsRasterReadHeader()</CODE> reads a page header from the
+ specified raster stream.</P>
+<H3><A NAME="10_25_5">Example</A></H3>
+<PRE>
+#include &lt;cups/raster.h&gt;
+
+int line;
+cups_raster_t *ras;
+cups_raster_header_t header;
+unsigned char pixels[8192];
+...
+
+while (cupsRasterReadHeader(ras, &amp;header))
+{
+ ...
+
+ for (line = 0; line &lt; header.cupsHeight; line ++)
+ {
+ cupsRasterReadPixels(ras, pixels, header.cupsBytesPerLine);
+
+ ...
+ }
+}
+</PRE>
+<H3><A NAME="10_25_6">See Also</A></H3>
+<P><A HREF="#cupsRasterClose"> cupsRasterClose()</A>,<A HREF="#cupsRasterOpen">
+ cupsRasterOpen()</A>,<A HREF="#cupsRasterReadPixels">
+ cupsRasterReadPixels()</A>,<A HREF="#cupsRasterWriteHeader">
+ cupsRasterWriteHeader()</A>,<A HREF="#cupsRasterWritePixels">
+ cupsRasterWritePixels()</A>
+<!-- NEW PAGE -->
+</P>
+<H2><A NAME="cupsRasterReadPixels">cupsRasterReadPixels()</A></H2>
+<H3><A NAME="10_26_1">Usage</A></H3>
+<PRE>
+unsigned
+cupsRasterReadPixels(cups_raster_t *ras,
+ unsigned char *pixels,
+ unsigned length);
+</PRE>
+<H3><A NAME="10_26_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>ras</TD><TD>The raster stream to read from.</TD></TR>
+<TR><TD>pixels</TD><TD>The pointer to a pixel buffer.</TD></TR>
+<TR><TD>length</TD><TD>The number of bytes of pixel data to read.</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_26_3">Returns</A></H3>
+<P>The number of bytes read or 0 on EOF or error.</P>
+<H3><A NAME="10_26_4">Description</A></H3>
+<P><CODE>cupsRasterReadPixels()</CODE> reads pixel data from the
+ specified raster stream.</P>
+<H3><A NAME="10_26_5">Example</A></H3>
+<PRE>
+#include &lt;cups/raster.h&gt;
+
+int line;
+cups_raster_t *ras;
+cups_raster_header_t header;
+unsigned char pixels[8192];
+...
+
+while (cupsRasterReadHeader(ras, &amp;header))
+{
+ ...
+
+ for (line = 0; line &lt; header.cupsHeight; line ++)
+ {
+ cupsRasterReadPixels(ras, pixels, header.cupsBytesPerLine);
+
+ ...
+ }
+}
+</PRE>
+<H3><A NAME="10_26_6">See Also</A></H3>
+<P><A HREF="#cupsRasterClose"> cupsRasterClose()</A>,<A HREF="#cupsRasterOpen">
+ cupsRasterOpen()</A>,<A HREF="#cupsRasterReadHeader">
+ cupsRasterReadHeader()</A>,<A HREF="#cupsRasterWriteHeader">
+ cupsRasterWriteHeader()</A>,<A HREF="#cupsRasterWritePixels">
+ cupsRasterWritePixels()</A>
+<!-- NEW PAGE -->
+</P>
+<H2><A NAME="cupsRasterWriteHeader">cupsRasterWriteHeader()</A></H2>
+<H3><A NAME="10_27_1">Usage</A></H3>
+<PRE>
+unsigned
+cupsRasterWriteHeader(cups_raster_t *ras,
+ cups_page_header_t *header);
+</PRE>
+<H3><A NAME="10_27_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>ras</TD><TD>The raster stream to write to.</TD></TR>
+<TR><TD>header</TD><TD>A pointer to the page header to write.</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_27_3">Returns</A></H3>
+<P>1 on success, 0 on error.</P>
+<H3><A NAME="10_27_4">Description</A></H3>
+<P><CODE>cupsRasterWriteHeader()</CODE> writes the specified page header
+ to a raster stream.</P>
+<H3><A NAME="10_27_5">Example</A></H3>
+<PRE>
+#include &lt;cups/raster.h&gt;
+
+int line;
+cups_raster_t *ras;
+cups_raster_header_t header;
+unsigned char pixels[8192];
+...
+
+cupsRasterWriteHeader(ras, &amp;header);
+
+for (line = 0; line &lt; header.cupsHeight; line ++)
+{
+ ...
+
+ cupsRasterWritePixels(ras, pixels, header.cupsBytesPerLine);
+}
+</PRE>
+<H3><A NAME="10_27_6">See Also</A></H3>
+<P><A HREF="#cupsRasterClose"> cupsRasterClose()</A>,<A HREF="#cupsRasterOpen">
+ cupsRasterOpen()</A>,<A HREF="#cupsRasterReadHeader">
+ cupsRasterReadHeader()</A>,<A HREF="#cupsRasterReadPixels">
+ cupsRasterReadPixels()</A>,<A HREF="#cupsRasterWritePixels">
+ cupsRasterWritePixels()</A>
+<!-- NEW PAGE -->
+</P>
+<H2><A NAME="cupsRasterWritePixels">cupsRasterWritePixels()</A></H2>
+<H3><A NAME="10_28_1">Usage</A></H3>
+<PRE>
+unsigned
+cupsRasterWritePixels(cups_raster_t *ras,
+ unsigned char *pixels,
+ unsigned length);
+</PRE>
+<H3><A NAME="10_28_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>ras</TD><TD>The raster stream to write to.</TD></TR>
+<TR><TD>pixels</TD><TD>The pixel data to write.</TD></TR>
+<TR><TD>length</TD><TD>The number of bytes to write.</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_28_3">Returns</A></H3>
+<P>The number of bytes written.</P>
+<H3><A NAME="10_28_4">Description</A></H3>
+<P><CODE>cupsRasterWritePixels()</CODE> writes the specified pixel data
+ to a raster stream.</P>
+<H3><A NAME="10_28_5">Example</A></H3>
+<PRE>
+#include &lt;cups/raster.h&gt;
+
+int line;
+cups_raster_t *ras;
+cups_raster_header_t header;
+unsigned char pixels[8192];
+...
+
+cupsRasterWriteHeader(ras, &amp;header);
+
+for (line = 0; line &lt; header.cupsHeight; line ++)
+{
+ ...
+
+ cupsRasterWritePixels(ras, pixels, header.cupsBytesPerLine);
+}
+</PRE>
+<H3><A NAME="10_28_6">See Also</A></H3>
+<P><A HREF="#cupsRasterClose"> cupsRasterClose()</A>,<A HREF="#cupsRasterOpen">
+ cupsRasterOpen()</A>,<A HREF="#cupsRasterReadHeader">
+ cupsRasterReadHeader()</A>,<A HREF="#cupsRasterReadPixels">
+ cupsRasterReadPixels()</A>,<A HREF="#cupsRasterWriteHeader">
+ cupsRasterWriteHeader()</A>
+<!-- NEW PAGE -->
+</P>
+<H2><A NAME="cupsServer">cupsServer()</A></H2>
+<H3><A NAME="10_29_1">Usage</A></H3>
+<PRE>
+const char *
+cupsServer(void);
+</PRE>
+<H3><A NAME="10_29_2">Returns</A></H3>
+<P>A pointer to the default server name.</P>
+<H3><A NAME="10_29_3">Description</A></H3>
+<P><CODE>cupsServer()</CODE> 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 <CODE>cupsServer()</CODE></P>
+<P>The default server is determined from the following locations:</P>
+<OL>
+<LI>The <CODE>CUPS_SERVER</CODE> environment variable,</LI>
+<LI>The <CODE>ServerName</CODE> directive in the<VAR> client.conf</VAR>
+ file,</LI>
+<LI>The default host, &quot;localhost&quot;.</LI>
+</OL>
+<H3><A NAME="10_29_4">Example</A></H3>
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+const char *server;
+
+server = cupsServer();
+</PRE>
+<H3><A NAME="10_29_5">See Also</A></H3>
+<P><A HREF="#cupsGetPassword"> cupsGetPassword()</A>,<A HREF="#cupsSetPasswordCB">
+ cupsSetPasswordCB()</A>,<A HREF="#cupsSetServer"> cupsSetServer()</A>,<A
+HREF="#cupsSetUser"> cupsSetUser()</A>,<A HREF="#cupsUser"> cupsUser()</A>
+<!-- NEW PAGE -->
+
+</P>
+<H2><A NAME="cupsSetPasswordCB">cupsSetPasswordCB()</A></H2>
+<H3><A NAME="10_30_1">Usage</A></H3>
+<PRE>
+void
+cupsSetPasswordCB(const char *(*cb)(const char *prompt));
+</PRE>
+<H3><A NAME="10_30_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>cb</TD><TD>The password callback function.</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_30_3">Description</A></H3>
+<P><CODE>cupsSetPasswordCB()</CODE> sets the callback function to use
+ when asking the user for a password. The callback function must accept
+ a single character string pointer (the prompt string) and return <CODE>
+NULL</CODE> if the user did not enter a password string or a pointer to
+ the password string otherwise.</P>
+<H3><A NAME="10_30_4">Example</A></H3>
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+const char *
+my_password_cb(const char *prompt)
+{
+ return (getpass(prompt));
+}
+
+...
+
+char *password;
+
+...
+
+cupsSetPasswordCB(my_password_cb);
+password = cupsGetPassword(&quot;Please enter a password:&quot;);
+</PRE>
+<H3><A NAME="10_30_5">See Also</A></H3>
+<P><A HREF="#cupsServer"> cupsServer()</A>,<A HREF="#cupsSetServer">
+ cupsSetServer()</A>,<A HREF="#cupsSetUser"> cupsSetUser()</A>,<A HREF="#cupsUser">
+ cupsUser()</A>
+<!-- NEW PAGE -->
+</P>
+<H2><A NAME="cupsSetServer">cupsSetServer()</A></H2>
+<H3><A NAME="10_31_1">Usage</A></H3>
+<PRE>
+void
+cupsSetServer(const char *server);
+</PRE>
+<H3><A NAME="10_31_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>server</TD><TD>The default server to use.</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_31_3">Description</A></H3>
+<P><CODE>cupsSetServer()</CODE> sets the default server to use for the
+ CUPS API. If the <CODE>server</CODE> argument is <CODE>NULL</CODE>, the
+ default server is used.</P>
+<H3><A NAME="10_31_4">Example</A></H3>
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+cupsSetServer(&quot;foo.bar.com&quot;);
+</PRE>
+<H3><A NAME="10_31_5">See Also</A></H3>
+<P><A HREF="#cupsServer"> cupsServer()</A>,<A HREF="#cupsSetPasswordCB">
+ cupsSetPasswordCB()</A>,<A HREF="#cupsSetUser"> cupsSetUser()</A>,<A HREF="#cupsUser">
+ cupsUser()</A>
+<!-- NEW PAGE -->
+</P>
+<H2><A NAME="cupsSetUser">cupsSetUser()</A></H2>
+<H3><A NAME="10_32_1">Usage</A></H3>
+<PRE>
+void
+cupsSetUser(const char *user);
+</PRE>
+<H3><A NAME="10_32_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>user</TD><TD>The user name string to use.</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_32_3">Description</A></H3>
+<P><CODE>cupsSetUser()</CODE> sets the default user name for
+ authentication. If the <CODE>user</CODE> argument is <CODE>NULL</CODE>
+ then the current login user is used.</P>
+<H3><A NAME="10_32_4">Example</A></H3>
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+...
+
+cupsSetUser(&quot;root&quot;);
+</PRE>
+<H3><A NAME="10_32_5">See Also</A></H3>
+<P><A HREF="#cupsServer"> cupsServer()</A>,<A HREF="#cupsSetPasswordCB">
+ cupsSetPasswordCB()</A>,<A HREF="#cupsSetServer"> cupsSetServer()</A>,<A
+HREF="#cupsUser"> cupsUser()</A>
+<!-- NEW PAGE -->
+</P>
+<H2><A NAME="cupsTempFile">cupsTempFile()</A></H2>
+<H3><A NAME="10_33_1">Usage</A></H3>
+<PRE>
+char *
+cupsTempFile(char *filename,
+ int length);
+</PRE>
+<H3><A NAME="10_33_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>filename</TD><TD>The character string to hold the temporary
+ filename.</TD></TR>
+<TR><TD>length</TD><TD>The size of the filename string in bytes.</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_33_3">Returns</A></H3>
+<P>A pointer to <CODE>filename</CODE>.</P>
+<H3><A NAME="10_33_4">Description</A></H3>
+<P><CODE>cupsTempFile()</CODE> generates a temporary filename for the<VAR>
+ /var/tmp</VAR> directory or the directory specified by the <CODE>TMPDIR</CODE>
+ environment variable.</P>
+<H3><A NAME="10_33_5">Example</A></H3>
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+char filename[256];
+
+cupsTempFile(filename, sizeof(filename));
+</PRE>
+
+<!-- NEW PAGE -->
+<H2><A NAME="cupsUser">cupsUser()</A></H2>
+<H3><A NAME="10_34_1">Usage</A></H3>
+<PRE>
+const char *
+cupsUser(void);
+</PRE>
+<H3><A NAME="10_34_2">Returns</A></H3>
+<P>A pointer to the current username or <CODE>NULL</CODE> if the user ID
+ is undefined.</P>
+<H3><A NAME="10_34_3">Description</A></H3>
+<P><CODE>cupsUser()</CODE> returns the name associated with the current
+ user ID as reported by the <CODE>getuid()</CODE> system call.</P>
+<H3><A NAME="10_34_4">Example</A></H3>
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+const char *user;
+
+user = cupsUser();
+</PRE>
+<H3><A NAME="10_34_5">See Also</A></H3>
+<P><A HREF="#cupsGetPassword"> cupsGetPassword()</A>,<A HREF="#cupsServer">
+ cupsServer()</A>
+<!-- NEW PAGE -->
+</P>
+<H2><A NAME="httpBlocking">httpBlocking()</A></H2>
+<H3><A NAME="10_35_1">Usage</A></H3>
+<PRE>
+void httpBlocking(http_t *http, int blocking)
+</PRE>
+<H3><A NAME="10_35_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>http</TD><TD>The HTTP connection</TD></TR>
+<TR><TD>blocking</TD><TD>0 if the connection should be non-blocking, 1
+ if it should be blocking</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_35_3">Description</A></H3>
+<P>The <CODE>httpBlocking()</CODE> function sets the blocking mode for
+ the HTTP connection. By default HTTP connections will block (stop) the
+ client program until data is available or can be sent to the server.</P>
+<H3><A NAME="10_35_4">Example</A></H3>
+<PRE>
+#include &lt;cups/http.h&gt;
+
+http_t *http;
+
+http = httpConnect(&quot;server&quot;, port);
+httpBlocking(http, 0);
+</PRE>
+<H3><A NAME="10_35_5">See Also</A></H3>
+<A HREF="#httpCheck"> <CODE>httpCheck()</CODE></A>,<A HREF="#httpConnect">
+ <CODE>httpConnect()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="httpCheck">httpCheck()</A></H2>
+<H3><A NAME="10_36_1">Usage</A></H3>
+<PRE>
+int httpCheck(http_t *http);
+</PRE>
+<H3><A NAME="10_36_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>http</TD><TD>The HTTP connection</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_36_3">Returns</A></H3>
+<P>0 if there is no data pending, 1 otherwise.</P>
+<H3><A NAME="10_36_4">Description</A></H3>
+<P>The <CODE>httpCheck()</CODE> function checks to see if there is any
+ data pending on an HTTP connection.</P>
+<H3><A NAME="10_36_5">Example</A></H3>
+<PRE>
+#include &lt;cups/http.h&gt;
+
+http_t *http;
+
+if (httpCheck(http))
+{
+ ... do something ...
+}
+</PRE>
+<H3><A NAME="10_36_6">See Also</A></H3>
+<A HREF="#httpBlocking"> <CODE>httpBlocking()</CODE></A>,<A HREF="#httpConnect">
+ <CODE>httpConnect()</CODE></A>,<A HREF="#httpGets"> <CODE>httpGets()</CODE>
+</A>,<A HREF="#httpRead"> <CODE>httpRead()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="httpClearFields">httpClearFields()</A></H2>
+<H3><A NAME="10_37_1">Usage</A></H3>
+<PRE>
+void httpClearFields(http_t *http)
+</PRE>
+<H3><A NAME="10_37_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>http</TD><TD>The HTTP connection</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_37_3">Description</A></H3>
+<P>The <CODE>httpClearFields()</CODE> function clears all HTTP request
+ fields for the HTTP connection.</P>
+<H3><A NAME="10_37_4">Example</A></H3>
+<PRE>
+#include &lt;cups/http.h&gt;
+
+http_t *http;
+
+httpClearFields(http);
+</PRE>
+<H3><A NAME="10_37_5">See Also</A></H3>
+<A HREF="#httpConnect"> <CODE>httpConnect()</CODE></A>,<A HREF="#httpGetField">
+ <CODE>httpGetField()</CODE></A>,<A HREF="#httpSetField"> <CODE>
+httpSetField()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="httpClose">httpClose()</A></H2>
+<H3><A NAME="10_38_1">Usage</A></H3>
+<PRE>
+void httpClose(http_t *http);
+</PRE>
+<H3><A NAME="10_38_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>http</TD><TD>The HTTP connection</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_38_3">Description</A></H3>
+<P>The <CODE>httpClose()</CODE> function closes an active HTTP
+ connection.</P>
+<H3><A NAME="10_38_4">Example</A></H3>
+<PRE>
+#include &lt;cups/http.h&gt;
+
+http_t *http;
+
+httpClose(http);
+</PRE>
+<H3><A NAME="10_38_5">See Also</A></H3>
+<A HREF="#httpConnect"> <CODE>httpConnect()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="httpConnect">httpConnect()</A></H2>
+<H3><A NAME="10_39_1">Usage</A></H3>
+<PRE>
+http_t *httpConnect(const char *hostname, int port);
+</PRE>
+<H3><A NAME="10_39_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>hostname</TD><TD>The name or IP address of the server to connect
+ to</TD></TR>
+<TR><TD>port</TD><TD>The port number to use</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_39_3">Returns</A></H3>
+<P>A pointer to a HTTP connection structure or NULL if the connection
+ could not be made.</P>
+<H3><A NAME="10_39_4">Description</A></H3>
+<P>The <CODE>httpConnect()</CODE> function opens a HTTP connection to
+ the specified server and port.</P>
+<H3><A NAME="10_39_5">Example</A></H3>
+<PRE>
+#include &lt;cups/http.h&gt;
+
+http_t *http;
+
+http = httpConnect(cupsServer(), ippPort());
+</PRE>
+<H3><A NAME="10_39_6">See Also</A></H3>
+<A HREF="#httpClose"> <CODE>httpClose()</CODE></A>,<A HREF="#httpGet"> <CODE>
+httpGet()</CODE></A>,<A HREF="#httpGets"> <CODE>httpGets()</CODE></A>,<A HREF="#httpPost">
+ <CODE>httpPost()</CODE></A>,<A HREF="#httpRead"> <CODE>httpRead()</CODE>
+</A>,<A HREF="#httpWrite"> <CODE>httpWrite()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="httpDecode64">httpDecode64()</A></H2>
+<H3><A NAME="10_40_1">Usage</A></H3>
+<PRE>
+char *httpDecode64(char *out, const char *in);
+</PRE>
+<H3><A NAME="10_40_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>out</TD><TD>The output string</TD></TR>
+<TR><TD>in</TD><TD>The input string</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_40_3">Returns</A></H3>
+<P>A pointer to the decoded string.</P>
+<H3><A NAME="10_40_4">Description</A></H3>
+<P>The <CODE>httpDecode64()</CODE> function decodes a base-64 encoded
+ string to the original string.</P>
+<H3><A NAME="10_40_5">Example</A></H3>
+<PRE>
+#include &lt;cups/http.h&gt;
+
+char encoded_string[255];
+char original_string[255];
+
+httpDecode64(original_string, encoded_string);
+</PRE>
+<H3><A NAME="10_40_6">See Also</A></H3>
+<A HREF="#httpEncode64"> <CODE>httpEncode64()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="httpDelete">httpDelete()</A></H2>
+<H3><A NAME="10_41_1">Usage</A></H3>
+<PRE>
+int httpDelete(http_t *http, const char *uri);
+</PRE>
+<H3><A NAME="10_41_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>http</TD><TD>The HTTP connection</TD></TR>
+<TR><TD>uri</TD><TD>The URI to delete</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_41_3">Returns</A></H3>
+<P>0 on success, non-zero on failure.</P>
+<H3><A NAME="10_41_4">Description</A></H3>
+<P>The <CODE>httpDelete()</CODE> function sends a HTTP DELETE request to
+ the server.</P>
+<H3><A NAME="10_41_5">Example</A></H3>
+<PRE>
+#include &lt;cups/http.h&gt;
+
+http_t *http;
+
+httpDelete(http, &quot;/some/uri&quot;);
+</PRE>
+<H3><A NAME="10_41_6">See Also</A></H3>
+<A HREF="#httpConnect"> <CODE>httpConnect()</CODE></A>,<A HREF="#httpSetField">
+ <CODE>httpSetField()</CODE></A>,<A HREF="#httpUpdate"> <CODE>
+httpUpdate()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="httpEncode64">httpEncode64()</A></H2>
+<H3><A NAME="10_42_1">Usage</A></H3>
+<PRE>
+char *httpEncode64(char *out, const char *in);
+</PRE>
+<H3><A NAME="10_42_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>out</TD><TD>The output string</TD></TR>
+<TR><TD>in</TD><TD>The input string</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_42_3">Returns</A></H3>
+<P>A pointer to the encoded string.</P>
+<H3><A NAME="10_42_4">Description</A></H3>
+<P>The <CODE>httpEncode64()</CODE> function decodes a base-64 encoded
+ string to the original string.</P>
+<H3><A NAME="10_42_5">Example</A></H3>
+<PRE>
+#include &lt;cups/http.h&gt;
+
+char encoded_string[255];
+char original_string[255];
+
+httpEncode64(encoded_string, original_string);
+</PRE>
+<H3><A NAME="10_42_6">See Also</A></H3>
+<A HREF="#httpDecode64"> <CODE>httpDecode64()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="httpError">httpError()</A></H2>
+<H3><A NAME="10_43_1">Usage</A></H3>
+<PRE>
+int httpError(http_t *http);
+</PRE>
+<H3><A NAME="10_43_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>http</TD><TD>The HTTP connection</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_43_3">Returns</A></H3>
+<P>The last error that occurred or 0 if no error has occurred.</P>
+<H3><A NAME="10_43_4">Description</A></H3>
+<P>The <CODE>httpError()</CODE> function returns the last error that
+ occurred on the HTTP connection.</P>
+<H3><A NAME="10_43_5">Example</A></H3>
+<PRE>
+#include &lt;cups/http.h&gt;
+
+http_t *http;
+
+if (httpError(http))
+{
+ ... show an error message ...
+}
+</PRE>
+<H3><A NAME="10_43_6">See Also</A></H3>
+<A HREF="#httpConnect"> <CODE>httpConnect()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="httpFlush">httpFlush()</A></H2>
+<H3><A NAME="10_44_1">Usage</A></H3>
+<PRE>
+void httpFlush(http_t *http);
+</PRE>
+<H3><A NAME="10_44_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>http</TD><TD>The HTTP connection</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_44_3">Description</A></H3>
+<P>The <CODE>httpFlush()</CODE> function flushes any remaining data left
+ from a GET or POST operation.</P>
+<H3><A NAME="10_44_4">Example</A></H3>
+<PRE>
+#include &lt;cups/http.h&gt;
+
+http_t *http;
+
+httpFlush(http);
+</PRE>
+<H3><A NAME="10_44_5">See Also</A></H3>
+<A HREF="#httpConnect"> <CODE>httpConnect()</CODE></A>,
+<!-- NEW PAGE -->
+
+<H2><A NAME="httpGet">httpGet()</A></H2>
+<H3><A NAME="10_45_1">Usage</A></H3>
+<PRE>
+int httpGet(http_t *http, const char *uri);
+</PRE>
+<H3><A NAME="10_45_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>http</TD><TD>The HTTP connection</TD></TR>
+<TR><TD>uri</TD><TD>The URI to get</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_45_3">Returns</A></H3>
+<P>0 on success, non-zero on failure.</P>
+<H3><A NAME="10_45_4">Description</A></H3>
+<P>The <CODE>httpGet()</CODE> function sends a HTTP GET request to the
+ server.</P>
+<H3><A NAME="10_45_5">Example</A></H3>
+<PRE>
+#include &lt;cups/http.h&gt;
+
+http_t *http;
+
+httpGet(http, &quot;/some/uri&quot;);
+</PRE>
+<H3><A NAME="10_45_6">See Also</A></H3>
+<A HREF="#httpConnect"> <CODE>httpConnect()</CODE></A>,<A HREF="#httpSetField">
+ <CODE>httpSetField()</CODE></A>,<A HREF="#httpUpdate"> <CODE>
+httpUpdate()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="httpGets">httpGets()</A></H2>
+<H3><A NAME="10_46_1">Usage</A></H3>
+<PRE>
+char *httpGets(char *line, int length, http_t *http)
+</PRE>
+<H3><A NAME="10_46_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>line</TD><TD>The string to fill with a line from the HTTP
+ connection</TD></TR>
+<TR><TD>length</TD><TD>The maximum length of the string</TD></TR>
+<TR><TD>http</TD><TD>The HTTP connection</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_46_3">Returns</A></H3>
+<P>A pointer to the string or NULL if no line could be retrieved.</P>
+<H3><A NAME="10_46_4">Description</A></H3>
+<P>The <CODE>httpGets()</CODE> function is used to read a request line
+ from the HTTP connection. It is not normally used by a client program.</P>
+<H3><A NAME="10_46_5">Example</A></H3>
+<PRE>
+#include &lt;cups/http.h&gt;
+
+http_t *http;
+char line[1024];
+
+if (httpGets(line, sizeof(line), http))
+{
+ ... process the line ...
+}
+</PRE>
+<H3><A NAME="10_46_6">See Also</A></H3>
+<A HREF="#httpConnect"> <CODE>httpConnect()</CODE></A>,<A HREF="#httpUpdate">
+ <CODE>httpUpdate()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="httpGetDateString">httpGetDateString()</A></H2>
+<H3><A NAME="10_47_1">Usage</A></H3>
+<PRE>
+const char *httpGetDateString(time_t time)
+</PRE>
+<H3><A NAME="10_47_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>time</TD><TD>The UNIX date/time value</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_47_3">Returns</A></H3>
+<P>A pointer to a static string containing the HTTP date/time string for
+ the specified UNIX time value.</P>
+<H3><A NAME="10_47_4">Description</A></H3>
+<P>The <CODE>httpGetDateString()</CODE> function generates a date/time
+ string suitable for HTTP requests from a UNIX time value.</P>
+<H3><A NAME="10_47_5">Example</A></H3>
+<PRE>
+#include &lt;cups/http.h&gt;
+
+puts(httpGetDateString(time(NULL)));
+</PRE>
+<H3><A NAME="10_47_6">See Also</A></H3>
+<A HREF="#httpGetDateTime"> <CODE>httpGetDateTime()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="httpGetDateTime">httpGetDateTime()</A></H2>
+<H3><A NAME="10_48_1">Usage</A></H3>
+<PRE>
+time_t httpGetDateTime(const char *date)
+</PRE>
+<H3><A NAME="10_48_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>date</TD><TD>The HTTP date/time string</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_48_3">Returns</A></H3>
+<P>A UNIX time value.</P>
+<H3><A NAME="10_48_4">Description</A></H3>
+<P>The <CODE>httpGetDateTime()</CODE> function converts a HTTP date/time
+ string to a UNIX time value.</P>
+<H3><A NAME="10_48_5">Example</A></H3>
+<PRE>
+#include &lt;cups/http.h&gt;
+
+printf(&quot;%d\n&quot;, httpGetDateTime(&quot;Fri, 30 June 2000 12:34:56 GMT&quot;));
+</PRE>
+<H3><A NAME="10_48_6">See Also</A></H3>
+<A HREF="#httpGetDateString"> <CODE>httpGetDateString()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="httpGetField">httpGetField()</A></H2>
+<H3><A NAME="10_49_1">Usage</A></H3>
+<PRE>
+const char *httpGetField(http_t *http, http_field_t field);
+</PRE>
+<H3><A NAME="10_49_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>http</TD><TD>The HTTP connection</TD></TR>
+<TR><TD>field</TD><TD>The HTTP field</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_49_3">Returns</A></H3>
+<P>A pointer to the field value string.</P>
+<H3><A NAME="10_49_4">Description</A></H3>
+<P>The <CODE>httpGetField()</CODE> function returns the current value
+ for the specified HTTP field.</P>
+<H3><A NAME="10_49_5">Example</A></H3>
+<PRE>
+#include &lt;cups/http.h&gt;
+
+http_t *http;
+
+httpGet(http, &quot;/some/uri&quot;);
+while (httpUpdate(http) == HTTP_CONTINUE);
+
+puts(httpGetField(http, HTTP_FIELD_CONTENT_TYPE));
+</PRE>
+<H3><A NAME="10_49_6">See Also</A></H3>
+<A HREF="#httpConnect"> <CODE>httpConnect()</CODE></A>,<A HREF="#httpSetField">
+ <CODE>httpSetField()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="httpHead">httpHead()</A></H2>
+<H3><A NAME="10_50_1">Usage</A></H3>
+<PRE>
+int httpHead(http_t *http, const char *uri);
+</PRE>
+<H3><A NAME="10_50_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>http</TD><TD>The HTTP connection</TD></TR>
+<TR><TD>uri</TD><TD>The URI to head</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_50_3">Returns</A></H3>
+<P>0 on success, non-zero on failure.</P>
+<H3><A NAME="10_50_4">Description</A></H3>
+<P>The <CODE>httpHead()</CODE> function sends a HTTP HEAD request to the
+ server.</P>
+<H3><A NAME="10_50_5">Example</A></H3>
+<PRE>
+#include &lt;cups/http.h&gt;
+
+http_t *http;
+
+httpHead(http, &quot;/some/uri&quot;);
+</PRE>
+<H3><A NAME="10_50_6">See Also</A></H3>
+<A HREF="#httpConnect"> <CODE>httpConnect()</CODE></A>,<A HREF="#httpSetField">
+ <CODE>httpSetField()</CODE></A>,<A HREF="#httpUpdate"> <CODE>
+httpUpdate()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="httpInitialize">httpInitialize()</A></H2>
+<H3><A NAME="10_51_1">Usage</A></H3>
+<PRE>
+void httpInitialize(void);
+</PRE>
+<H3><A NAME="10_51_2">Description</A></H3>
+<P>The <CODE>httpInitialize()</CODE> function initializes the networking
+ code as needed by the underlying platform. It is called automatically
+ by the <CODE>httpConnect()</CODE> function.</P>
+<H3><A NAME="10_51_3">Example</A></H3>
+<PRE>
+#include &lt;cups/http.h&gt;
+
+httpInitialize();
+</PRE>
+<H3><A NAME="10_51_4">See Also</A></H3>
+<A HREF="#httpConnect"> <CODE>httpConnect()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="httpOptions">httpOptions()</A></H2>
+<H3><A NAME="10_52_1">Usage</A></H3>
+<PRE>
+int httpOptions(http_t *http, const char *uri);
+</PRE>
+<H3><A NAME="10_52_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>http</TD><TD>The HTTP connection</TD></TR>
+<TR><TD>uri</TD><TD>The URI to check for options</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_52_3">Returns</A></H3>
+<P>0 on success, non-zero on failure.</P>
+<H3><A NAME="10_52_4">Description</A></H3>
+<P>The <CODE>httpOptions()</CODE> function sends a HTTP OPTIONS request
+ to the server.</P>
+<H3><A NAME="10_52_5">Example</A></H3>
+<PRE>
+#include &lt;cups/http.h&gt;
+
+http_t *http;
+
+httpOptions(http, &quot;/some/uri&quot;);
+</PRE>
+<H3><A NAME="10_52_6">See Also</A></H3>
+<A HREF="#httpConnect"> <CODE>httpConnect()</CODE></A>,<A HREF="#httpSetField">
+ <CODE>httpSetField()</CODE></A>,<A HREF="#httpUpdate"> <CODE>
+httpUpdate()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="httpPost">httpPost()</A></H2>
+<H3><A NAME="10_53_1">Usage</A></H3>
+<PRE>
+int httpPost(http_t *http, const char *uri);
+</PRE>
+<H3><A NAME="10_53_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>http</TD><TD>The HTTP connection</TD></TR>
+<TR><TD>uri</TD><TD>The URI to post to</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_53_3">Returns</A></H3>
+<P>0 on success, non-zero on failure.</P>
+<H3><A NAME="10_53_4">Description</A></H3>
+<P>The <CODE>httpPost()</CODE> function sends a HTTP POST request to the
+ server.</P>
+<H3><A NAME="10_53_5">Example</A></H3>
+<PRE>
+#include &lt;cups/http.h&gt;
+
+http_t *http;
+
+httpPost(http, &quot;/some/uri&quot;);
+</PRE>
+<H3><A NAME="10_53_6">See Also</A></H3>
+<A HREF="#httpConnect"> <CODE>httpConnect()</CODE></A>,<A HREF="#httpSetField">
+ <CODE>httpSetField()</CODE></A>,<A HREF="#httpUpdate"> <CODE>
+httpUpdate()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="httpPrintf">httpPrintf()</A></H2>
+<H3><A NAME="10_54_1">Usage</A></H3>
+<PRE>
+int httpPrintf(http_t *http, const char *format, ...);
+</PRE>
+<H3><A NAME="10_54_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>http</TD><TD>The HTTP connection</TD></TR>
+<TR><TD>format</TD><TD>A printf-style format string</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_54_3">Returns</A></H3>
+<P>The number of bytes written.</P>
+<H3><A NAME="10_54_4">Description</A></H3>
+<P>The <CODE>httpPrintf()</CODE> function sends a formatted string to
+ the HTTP connection. It is normally only used by the CUPS API and
+ scheduler.</P>
+<H3><A NAME="10_54_5">Example</A></H3>
+<PRE>
+#include &lt;cups/http.h&gt;
+
+http_t *http;
+
+httpPrintf(http, &quot;GET / HTTP/1.1 \r\n&quot;);
+</PRE>
+<H3><A NAME="10_54_6">See Also</A></H3>
+<A HREF="#httpConnect"> <CODE>httpConnect()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="httpPut">httpPut()</A></H2>
+<H3><A NAME="10_55_1">Usage</A></H3>
+<PRE>
+int httpPut(http_t *http, const char *uri);
+</PRE>
+<H3><A NAME="10_55_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>http</TD><TD>The HTTP connection</TD></TR>
+<TR><TD>uri</TD><TD>The URI to put</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_55_3">Returns</A></H3>
+<P>0 on success, non-zero on failure.</P>
+<H3><A NAME="10_55_4">Description</A></H3>
+<P>The <CODE>httpPut()</CODE> function sends a HTTP PUT request to the
+ server.</P>
+<H3><A NAME="10_55_5">Example</A></H3>
+<PRE>
+#include &lt;cups/http.h&gt;
+
+http_t *http;
+
+httpDelete(http, &quot;/some/uri&quot;);
+</PRE>
+<H3><A NAME="10_55_6">See Also</A></H3>
+<A HREF="#httpConnect"> <CODE>httpConnect()</CODE></A>,<A HREF="#httpSetField">
+ <CODE>httpSetField()</CODE></A>,<A HREF="#httpUpdate"> <CODE>
+httpUpdate()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="httpRead">httpRead()</A></H2>
+<H3><A NAME="10_56_1">Usage</A></H3>
+<PRE>
+int httpRead(http_t *http, char *buffer, int length);
+</PRE>
+<H3><A NAME="10_56_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>http</TD><TD>The HTTP connection</TD></TR>
+<TR><TD>buffer</TD><TD>The buffer to read into</TD></TR>
+<TR><TD>length</TD><TD>The number of bytes to read</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_56_3">Returns</A></H3>
+<P>The number of bytes read or -1 on error.</P>
+<H3><A NAME="10_56_4">Description</A></H3>
+<P>The <CODE>httpRead()</CODE> function reads data from the HTTP
+ connection, possibly the result of a GET or POST request.</P>
+<H3><A NAME="10_56_5">Example</A></H3>
+<PRE>
+#include &lt;cups/http.h&gt;
+
+http_t *http;
+char buffer[1024];
+int bytes;
+
+httpGet(http, &quot;/&quot;);
+while (httpUpdate(http) != HTTP_CONTINUE);
+while ((bytes = httpRead(http, buffer, sizeof(buffer) - 1)) &gt; 0)
+{
+ buffer[bytes] = '\0';
+ fputs(buffer, stdout);
+}
+</PRE>
+<H3><A NAME="10_56_6">See Also</A></H3>
+<A HREF="#httpConnect"> <CODE>httpConnect()</CODE></A>,<A HREF="#httpWrite">
+ <CODE>httpWrite()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="httpReconnect">httpReconnect()</A></H2>
+<H3><A NAME="10_57_1">Usage</A></H3>
+<PRE>
+int httpReconnect(http_t *http);
+</PRE>
+<H3><A NAME="10_57_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>http</TD><TD>The HTTP connection</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_57_3">Returns</A></H3>
+<P>0 on success, non-zero on failure.</P>
+<H3><A NAME="10_57_4">Description</A></H3>
+<P>The <CODE>httpReconnect()</CODE> function reconnects to the HTTP
+ server. This is usually done automatically if the HTTP functions detect
+ that the server connection has terminated.</P>
+<H3><A NAME="10_57_5">Example</A></H3>
+<PRE>
+#include &lt;cups/http.h&gt;
+
+http_t *http;
+
+httpReconnect(http);
+</PRE>
+<H3><A NAME="10_57_6">See Also</A></H3>
+<A HREF="#httpConnect"> <CODE>httpConnect()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="httpSeparate">httpSeparate()</A></H2>
+<H3><A NAME="10_58_1">Usage</A></H3>
+<PRE>
+void httpSeparate(const char *uri, char *method,
+ char *username, char *host, int *port,
+ char *resource);
+</PRE>
+<H3><A NAME="10_58_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>uri</TD><TD>The URI to separate</TD></TR>
+<TR><TD>method</TD><TD>The method (scheme) of the URI</TD></TR>
+<TR><TD>username</TD><TD>The username (and password) portion of the URI,
+ if any</TD></TR>
+<TR><TD>host</TD><TD>The hostname portion of the URI, if any</TD></TR>
+<TR><TD>port</TD><TD>The port number for the URI, either as specified or
+ as default for the method/scheme</TD></TR>
+<TR><TD>resource</TD><TD>The resource string, usually a filename on the
+ server</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_58_3">Description</A></H3>
+<P>The <CODE>httpSeparate()</CODE> function separates the specified URI
+ into its component parts. The method, username, hostname, and resource
+ strings should be at least <CODE>HTTP_MAX_URI</CODE> characters long to
+ avoid potential buffer overflow problems.</P>
+<H3><A NAME="10_58_4">Example</A></H3>
+<PRE>
+char uri[HTTP_MAX_URI];
+char method[HTTP_MAX_URI];
+char username[HTTP_MAX_URI];
+char host[HTTP_MAX_URI];
+char resource[HTTP_MAX_URI];
+int port;
+
+httpSeparate(uri, method, username, host, &amp;port, resource);
+</PRE>
+<H3><A NAME="10_58_5">See Also</A></H3>
+<A HREF="#httpConnect"> <CODE>httpConnect()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="httpSetField">httpSetField()</A></H2>
+<H3><A NAME="10_59_1">Usage</A></H3>
+<PRE>
+void httpSetField(http_t *http, http_field_t field, const char *value);
+</PRE>
+<H3><A NAME="10_59_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>http</TD><TD>The HTTP connection</TD></TR>
+<TR><TD>field</TD><TD>The HTTP field</TD></TR>
+<TR><TD>value</TD><TD>The string value for the field</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_59_3">Description</A></H3>
+<P>The <CODE>httpSetField()</CODE> function sets the current value for
+ the specified HTTP field.</P>
+<H3><A NAME="10_59_4">Example</A></H3>
+<PRE>
+#include &lt;cups/http.h&gt;
+
+http_t *http;
+
+httpSetField(http, HTTP_FIELD_AUTHORIZATION, &quot;Basic dfdr34453454325&quot;));
+httpGet(http, &quot;/some/uri&quot;);
+while (httpUpdate(http) == HTTP_CONTINUE);
+</PRE>
+<H3><A NAME="10_59_5">See Also</A></H3>
+<A HREF="#httpConnect"> <CODE>httpConnect()</CODE></A>,<A HREF="#httpGetField">
+ <CODE>httpGetField()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="httpTrace">httpTrace()</A></H2>
+<H3><A NAME="10_60_1">Usage</A></H3>
+<PRE>
+int httpTrace(http_t *http, const char *uri);
+</PRE>
+<H3><A NAME="10_60_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>http</TD><TD>The HTTP connection</TD></TR>
+<TR><TD>uri</TD><TD>The URI to trace</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_60_3">Returns</A></H3>
+<P>0 on success, non-zero on failure.</P>
+<H3><A NAME="10_60_4">Description</A></H3>
+<P>The <CODE>httpTrace()</CODE> function sends a HTTP TRACE request to
+ the server.</P>
+<H3><A NAME="10_60_5">Example</A></H3>
+<PRE>
+#include &lt;cups/http.h&gt;
+
+http_t *http;
+
+httpTrace(http, &quot;/some/uri&quot;);
+</PRE>
+<H3><A NAME="10_60_6">See Also</A></H3>
+<A HREF="#httpConnect"> <CODE>httpConnect()</CODE></A>,<A HREF="#httpSetField">
+ <CODE>httpSetField()</CODE></A>,<A HREF="#httpUpdate"> <CODE>
+httpUpdate()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="httpUpdate">httpUpdate()</A></H2>
+<H3><A NAME="10_61_1">Usage</A></H3>
+<PRE>
+http_status_t httpUpdate(http_t *http);
+</PRE>
+<H3><A NAME="10_61_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>http</TD><TD>The HTTP connection</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_61_3">Returns</A></H3>
+<P>The HTTP status of the current request.</P>
+<H3><A NAME="10_61_4">Description</A></H3>
+<P>The <CODE>httpUpdate()</CODE> function updates the current request
+ status. It is used after any DELETE, GET, HEAD, OPTIONS, POST, PUT, or
+ TRACE request to finalize the HTTP request and retrieve the request
+ status.</P>
+<P>Since proxies and the current blocking mode can cause the request to
+ take longer, programs should continue calling <CODE>httpUpdate()</CODE>
+ until the return status is not the constant value <CODE>HTTP_CONTINUE</CODE>
+.</P>
+<H3><A NAME="10_61_5">Example</A></H3>
+<PRE>
+#include &lt;cups/http.h&gt;
+
+http_t *http;
+http_status_t status;
+
+httpGet(http, &quot;/some/uri&quot;);
+while ((status = httpUpdate(http)) == HTTP_CONTINUE);
+printf(&quot;Request status is %d\n&quot;, status);
+</PRE>
+<H3><A NAME="10_61_6">See Also</A></H3>
+<A HREF="#httpConnect"> <CODE>httpConnect()</CODE></A>,<A HREF="#httpDelete">
+ <CODE>httpDelete()</CODE></A>,<A HREF="#httpGet"> <CODE>httpGet()</CODE>
+</A>,<A HREF="#httpHead"> <CODE>httpHead()</CODE></A>,<A HREF="#httpOptions">
+ <CODE>httpOptions()</CODE></A>,<A HREF="#httpPost"> <CODE>httpPost()</CODE>
+</A>,<A HREF="#httpPut"> <CODE>httpPut()</CODE></A>,<A HREF="#httpTrace">
+ <CODE>httpTrace()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="httpWrite">httpWrite()</A></H2>
+<H3><A NAME="10_62_1">Usage</A></H3>
+<PRE>
+int httpWrite(http_t *http, char *buffer, int length);
+</PRE>
+<H3><A NAME="10_62_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>http</TD><TD>The HTTP connection</TD></TR>
+<TR><TD>buffer</TD><TD>The buffer to read into</TD></TR>
+<TR><TD>length</TD><TD>The number of bytes to read</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_62_3">Returns</A></H3>
+<P>The number of bytes read or -1 on error.</P>
+<H3><A NAME="10_62_4">Description</A></H3>
+<P>The <CODE>httpWrite()</CODE> function reads data from the HTTP
+ connection, possibly the result of a GET or POST request.</P>
+<H3><A NAME="10_62_5">Example</A></H3>
+<PRE>
+#include &lt;cups/http.h&gt;
+
+http_t *http;
+FILE *fp;
+char buffer[1024];
+int bytes;
+
+httpPost(http, &quot;/&quot;);
+
+while ((bytes = fread(buffer, 1, sizeof(buffer), fp)) &gt; 0)
+ httpWrite(http, buffer, bytes);
+
+while (httpUpdate(http) != HTTP_CONTINUE);
+
+while ((bytes = httpRead(http, buffer, sizeof(buffer) - 1)) &gt; 0)
+{
+ buffer[bytes] = '\0';
+ fputs(buffer, stdout);
+}
+</PRE>
+<H3><A NAME="10_62_6">See Also</A></H3>
+<A HREF="#httpConnect"> <CODE>httpConnect()</CODE></A>,<A HREF="#httpRead">
+ <CODE>httpRead()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="ippAddBoolean">ippAddBoolean()</A></H2>
+<H3><A NAME="10_63_1">Usage</A></H3>
+<PRE>
+ipp_attribute_t *ippAddBoolean(ipp_t *ipp, ipp_tag_t group,
+ const char *name, char value);
+</PRE>
+<H3><A NAME="10_63_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>ipp</TD><TD>The IPP request</TD></TR>
+<TR><TD>group</TD><TD>The IPP group</TD></TR>
+<TR><TD>name</TD><TD>The name of attribute</TD></TR>
+<TR><TD>value</TD><TD>The boolean value</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_63_3">Returns</A></H3>
+<P>A pointer to the new attribute or NULL if the attribute could not be
+ created.</P>
+<H3><A NAME="10_63_4">Description</A></H3>
+<P>The <CODE>ippAddBoolean()</CODE> function adds a single boolean
+ attribute value to the specified IPP request.</P>
+<H3><A NAME="10_63_5">Example</A></H3>
+<PRE>
+#include &lt;cups/ipp.h&gt;
+
+ipp_t *ipp;
+
+ippAddBoolean(ipp, IPP_TAG_OPERATION, &quot;my-jobs&quot;, 1);
+</PRE>
+<H3><A NAME="10_63_6">See Also</A></H3>
+<A HREF="#ippAddBooleans"> <CODE>ippAddBooleans()</CODE></A>,<A HREF="#ippAddDate">
+ <CODE>ippAddDate()</CODE></A>,<A HREF="#ippAddInteger"> <CODE>
+ippAddInteger()</CODE></A>,<A HREF="#ippAddIntegers"> <CODE>
+ippAddIntegers()</CODE></A>,<A HREF="#ippAddRange"> <CODE>ippAddRange()</CODE>
+</A>,<A HREF="#ippAddRanges"> <CODE>ippAddRanges()</CODE></A>,<A HREF="#ippAddResolution">
+ <CODE>ippAddResolution()</CODE></A>,<A HREF="#ippAddResolutions"> <CODE>
+ippAddResolutions()</CODE></A>,<A HREF="#ippAddSeparator"> <CODE>
+ippAddSeparator()</CODE></A>,<A HREF="#ippAddString"> <CODE>
+ippAddString()</CODE></A>,<A HREF="#ippAddStrings"> <CODE>
+ippAddStrings()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="ippAddBooleans">ippAddBooleans()</A></H2>
+<H3><A NAME="10_64_1">Usage</A></H3>
+<PRE>
+ipp_attribute_t *ippAddBooleans(ipp_t *ipp, ipp_tag_t group,
+ const char *name, int num_values,
+ const char *values);
+</PRE>
+<H3><A NAME="10_64_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>ipp</TD><TD>The IPP request</TD></TR>
+<TR><TD>group</TD><TD>The IPP group</TD></TR>
+<TR><TD>name</TD><TD>The name of attribute</TD></TR>
+<TR><TD>num_values</TD><TD>The number of values</TD></TR>
+<TR><TD>values</TD><TD>The boolean values</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_64_3">Returns</A></H3>
+<P>A pointer to the new attribute or NULL if the attribute could not be
+ created.</P>
+<H3><A NAME="10_64_4">Description</A></H3>
+<P>The <CODE>ippAddBooleans()</CODE> function adds one or more boolean
+ attribute values to the specified IPP request. If the <CODE>values</CODE>
+ pointer is <CODE>NULL</CODE> then an array of <CODE>num_values</CODE>
+ false values is created.</P>
+<H3><A NAME="10_64_5">Example</A></H3>
+<PRE>
+#include &lt;cups/ipp.h&gt;
+
+ipp_t *ipp;
+char values[10];
+
+ippAddBooleans(ipp, IPP_TAG_OPERATION, &quot;some-attribute&quot;, 10, values);
+</PRE>
+<H3><A NAME="10_64_6">See Also</A></H3>
+<A HREF="#ippAddBoolean"> <CODE>ippAddBoolean()</CODE></A>,<A HREF="#ippAddDate">
+ <CODE>ippAddDate()</CODE></A>,<A HREF="#ippAddInteger"> <CODE>
+ippAddInteger()</CODE></A>,<A HREF="#ippAddIntegers"> <CODE>
+ippAddIntegers()</CODE></A>,<A HREF="#ippAddRange"> <CODE>ippAddRange()</CODE>
+</A>,<A HREF="#ippAddRanges"> <CODE>ippAddRanges()</CODE></A>,<A HREF="#ippAddResolution">
+ <CODE>ippAddResolution()</CODE></A>,<A HREF="#ippAddResolutions"> <CODE>
+ippAddResolutions()</CODE></A>,<A HREF="#ippAddSeparator"> <CODE>
+ippAddSeparator()</CODE></A>,<A HREF="#ippAddString"> <CODE>
+ippAddString()</CODE></A>,<A HREF="#ippAddStrings"> <CODE>
+ippAddStrings()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="ippAddDate">ippAddDate()</A></H2>
+<H3><A NAME="10_65_1">Usage</A></H3>
+<PRE>
+ipp_attribute_t *ippAddDate(ipp_t *ipp, ipp_tag_t group,
+ const char *name, ipp_uchar_t *value);
+</PRE>
+<H3><A NAME="10_65_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>ipp</TD><TD>The IPP request</TD></TR>
+<TR><TD>group</TD><TD>The IPP group</TD></TR>
+<TR><TD>name</TD><TD>The name of attribute</TD></TR>
+<TR><TD>value</TD><TD>The date value</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_65_3">Returns</A></H3>
+<P>A pointer to the new attribute or NULL if the attribute could not be
+ created.</P>
+<H3><A NAME="10_65_4">Description</A></H3>
+<P>The <CODE>ippAddDate()</CODE> function adds a single date-time
+ attribute value to the specified IPP request.</P>
+<H3><A NAME="10_65_5">Example</A></H3>
+<PRE>
+#include &lt;cups/ipp.h&gt;
+
+ipp_t *ipp;
+
+ippAddDate(ipp, IPP_TAG_OPERATION, &quot;some-attribute&quot;,
+ ippTimeToDate(time(NULL));
+</PRE>
+<H3><A NAME="10_65_6">See Also</A></H3>
+<A HREF="#ippAddBoolean"> <CODE>ippAddBoolean()</CODE></A>,<A HREF="#ippAddBooleans">
+ <CODE>ippAddBooleans()</CODE></A>,<A HREF="#ippAddInteger"> <CODE>
+ippAddInteger()</CODE></A>,<A HREF="#ippAddIntegers"> <CODE>
+ippAddIntegers()</CODE></A>,<A HREF="#ippAddRange"> <CODE>ippAddRange()</CODE>
+</A>,<A HREF="#ippAddRanges"> <CODE>ippAddRanges()</CODE></A>,<A HREF="#ippAddResolution">
+ <CODE>ippAddResolution()</CODE></A>,<A HREF="#ippAddResolutions"> <CODE>
+ippAddResolutions()</CODE></A>,<A HREF="#ippAddSeparator"> <CODE>
+ippAddSeparator()</CODE></A>,<A HREF="#ippAddString"> <CODE>
+ippAddString()</CODE></A>,<A HREF="#ippAddStrings"> <CODE>
+ippAddStrings()</CODE></A>,<A HREF="#ippTimeToDate"> <CODE>
+ippTimeToDate()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="ippAddInteger">ippAddInteger()</A></H2>
+<H3><A NAME="10_66_1">Usage</A></H3>
+<PRE>
+ipp_attribute_t *ippAddInteger(ipp_t *ipp, ipp_tag_t group,
+ ipp_tag_t tag, const char *name,
+ int value);
+</PRE>
+<H3><A NAME="10_66_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>ipp</TD><TD>The IPP request</TD></TR>
+<TR><TD>group</TD><TD>The IPP group</TD></TR>
+<TR><TD>tag</TD><TD>The type of integer value (IPP_TAG_INTEGER or
+ IPP_TAG_ENUM)</TD></TR>
+<TR><TD>name</TD><TD>The name of attribute</TD></TR>
+<TR><TD>value</TD><TD>The integer value</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_66_3">Returns</A></H3>
+<P>A pointer to the new attribute or NULL if the attribute could not be
+ created.</P>
+<H3><A NAME="10_66_4">Description</A></H3>
+<P>The <CODE>ippAddInteger()</CODE> function adds a single integer
+ attribute value to the specified IPP request.</P>
+<H3><A NAME="10_66_5">Example</A></H3>
+<PRE>
+#include &lt;cups/ipp.h&gt;
+
+ipp_t *ipp;
+
+ippAddInteger(ipp, IPP_TAG_OPERATION, &quot;limit&quot;, 100);
+</PRE>
+<H3><A NAME="10_66_6">See Also</A></H3>
+<A HREF="#ippAddBoolean"> <CODE>ippAddBoolean()</CODE></A>,<A HREF="#ippAddBooleans">
+ <CODE>ippAddBooleans()</CODE></A>,<A HREF="#ippAddDate"> <CODE>
+ippAddDate()</CODE></A>,<A HREF="#ippAddIntegers"> <CODE>
+ippAddIntegers()</CODE></A>,<A HREF="#ippAddRange"> <CODE>ippAddRange()</CODE>
+</A>,<A HREF="#ippAddRanges"> <CODE>ippAddRanges()</CODE></A>,<A HREF="#ippAddResolution">
+ <CODE>ippAddResolution()</CODE></A>,<A HREF="#ippAddResolutions"> <CODE>
+ippAddResolutions()</CODE></A>,<A HREF="#ippAddSeparator"> <CODE>
+ippAddSeparator()</CODE></A>,<A HREF="#ippAddString"> <CODE>
+ippAddString()</CODE></A>,<A HREF="#ippAddStrings"> <CODE>
+ippAddStrings()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="ippAddIntegers">ippAddIntegers()</A></H2>
+<H3><A NAME="10_67_1">Usage</A></H3>
+<PRE>
+ipp_attribute_t *ippAddIntegers(ipp_t *ipp, ipp_tag_t group,
+ ipp_tag_t tag, const char *name,
+ int num_values, const int *values);
+</PRE>
+<H3><A NAME="10_67_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>ipp</TD><TD>The IPP request</TD></TR>
+<TR><TD>group</TD><TD>The IPP group</TD></TR>
+<TR><TD>tag</TD><TD>The type of integer value (IPP_TAG_INTEGER or
+ IPP_TAG_ENUM)</TD></TR>
+<TR><TD>name</TD><TD>The name of attribute</TD></TR>
+<TR><TD>num_values</TD><TD>The number of values</TD></TR>
+<TR><TD>values</TD><TD>The integer values</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_67_3">Returns</A></H3>
+<P>A pointer to the new attribute or NULL if the attribute could not be
+ created.</P>
+<H3><A NAME="10_67_4">Description</A></H3>
+<P>The <CODE>ippAddIntegers()</CODE> function adds one or more integer
+ attribute values to the specified IPP request. If the <CODE>values</CODE>
+ pointer is <CODE>NULL</CODE> then an array of <CODE>num_values</CODE> 0
+ values is created.</P>
+<H3><A NAME="10_67_5">Example</A></H3>
+<PRE>
+#include &lt;cups/ipp.h&gt;
+
+ipp_t *ipp;
+int values[100];
+
+ippAddIntegers(ipp, IPP_TAG_OPERATION, &quot;some-attribute&quot;, 100, values);
+</PRE>
+<H3><A NAME="10_67_6">See Also</A></H3>
+<A HREF="#ippAddBoolean"> <CODE>ippAddBoolean()</CODE></A>,<A HREF="#ippAddBooleans">
+ <CODE>ippAddBooleans()</CODE></A>,<A HREF="#ippAddDate"> <CODE>
+ippAddDate()</CODE></A>,<A HREF="#ippAddInteger"> <CODE>ippAddInteger()</CODE>
+</A>,<A HREF="#ippAddRange"> <CODE>ippAddRange()</CODE></A>,<A HREF="#ippAddRanges">
+ <CODE>ippAddRanges()</CODE></A>,<A HREF="#ippAddResolution"> <CODE>
+ippAddResolution()</CODE></A>,<A HREF="#ippAddResolutions"> <CODE>
+ippAddResolutions()</CODE></A>,<A HREF="#ippAddSeparator"> <CODE>
+ippAddSeparator()</CODE></A>,<A HREF="#ippAddString"> <CODE>
+ippAddString()</CODE></A>,<A HREF="#ippAddStrings"> <CODE>
+ippAddStrings()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="ippAddRange">ippAddRange()</A></H2>
+<H3><A NAME="10_68_1">Usage</A></H3>
+<PRE>
+ipp_attribute_t *ippAddRange(ipp_t *ipp, ipp_tag_t group,
+ const char *name, int low,
+ int high);
+</PRE>
+<H3><A NAME="10_68_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>ipp</TD><TD>The IPP request</TD></TR>
+<TR><TD>group</TD><TD>The IPP group</TD></TR>
+<TR><TD>name</TD><TD>The name of attribute</TD></TR>
+<TR><TD>low</TD><TD>The lower value</TD></TR>
+<TR><TD>high</TD><TD>The higher value</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_68_3">Returns</A></H3>
+<P>A pointer to the new attribute or NULL if the attribute could not be
+ created.</P>
+<H3><A NAME="10_68_4">Description</A></H3>
+<P>The <CODE>ippAddRange()</CODE> function adds a single range attribute
+ value to the specified IPP request.</P>
+<H3><A NAME="10_68_5">Example</A></H3>
+<PRE>
+#include &lt;cups/ipp.h&gt;
+
+ipp_t *ipp;
+
+ippAddRange(ipp, IPP_TAG_OPERATION, &quot;page-ranges&quot;, 1, 10);
+</PRE>
+<H3><A NAME="10_68_6">See Also</A></H3>
+<A HREF="#ippAddBoolean"> <CODE>ippAddBoolean()</CODE></A>,<A HREF="#ippAddBooleans">
+ <CODE>ippAddBooleans()</CODE></A>,<A HREF="#ippAddDate"> <CODE>
+ippAddDate()</CODE></A>,<A HREF="#ippAddInteger"> <CODE>ippAddInteger()</CODE>
+</A>,<A HREF="#ippAddIntegers"> <CODE>ippAddIntegers()</CODE></A>,<A HREF="#ippAddRanges">
+ <CODE>ippAddRanges()</CODE></A>,<A HREF="#ippAddResolution"> <CODE>
+ippAddResolution()</CODE></A>,<A HREF="#ippAddResolutions"> <CODE>
+ippAddResolutions()</CODE></A>,<A HREF="#ippAddSeparator"> <CODE>
+ippAddSeparator()</CODE></A>,<A HREF="#ippAddString"> <CODE>
+ippAddString()</CODE></A>,<A HREF="#ippAddStrings"> <CODE>
+ippAddStrings()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="ippAddRanges">ippAddRanges()</A></H2>
+<H3><A NAME="10_69_1">Usage</A></H3>
+<PRE>
+ipp_attribute_t *ippAddRanges(ipp_t *ipp, ipp_tag_t group,
+ const char *name, int num_values,
+ const int *lows, const int *highs);
+</PRE>
+<H3><A NAME="10_69_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>ipp</TD><TD>The IPP request</TD></TR>
+<TR><TD>group</TD><TD>The IPP group</TD></TR>
+<TR><TD>name</TD><TD>The name of attribute</TD></TR>
+<TR><TD>num_values</TD><TD>The number of range values</TD></TR>
+<TR><TD>lows</TD><TD>The lower values</TD></TR>
+<TR><TD>highs</TD><TD>The higher values</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_69_3">Returns</A></H3>
+<P>A pointer to the new attribute or NULL if the attribute could not be
+ created.</P>
+<H3><A NAME="10_69_4">Description</A></H3>
+<P>The <CODE>ippAddRanges()</CODE> function adds one or more range
+ attribute values to the specified IPP request. If the <CODE>values</CODE>
+ pointer is <CODE>NULL</CODE> then an array of <CODE>num_values</CODE>
+ 0,0 ranges is created.</P>
+<H3><A NAME="10_69_5">Example</A></H3>
+<PRE>
+#include &lt;cups/ipp.h&gt;
+
+ipp_t *ipp;
+int lows[2];
+int highs[2];
+
+ippAddRanges(ipp, IPP_TAG_OPERATION, &quot;page-ranges&quot;, 2, lows, highs);
+</PRE>
+<H3><A NAME="10_69_6">See Also</A></H3>
+<A HREF="#ippAddBoolean"> <CODE>ippAddBoolean()</CODE></A>,<A HREF="#ippAddBooleans">
+ <CODE>ippAddBooleans()</CODE></A>,<A HREF="#ippAddDate"> <CODE>
+ippAddDate()</CODE></A>,<A HREF="#ippAddInteger"> <CODE>ippAddInteger()</CODE>
+</A>,<A HREF="#ippAddIntegers"> <CODE>ippAddIntegers()</CODE></A>,<A HREF="#ippAddRange">
+ <CODE>ippAddRange()</CODE></A>,<A HREF="#ippAddResolution"> <CODE>
+ippAddResolution()</CODE></A>,<A HREF="#ippAddResolutions"> <CODE>
+ippAddResolutions()</CODE></A>,<A HREF="#ippAddSeparator"> <CODE>
+ippAddSeparator()</CODE></A>,<A HREF="#ippAddString"> <CODE>
+ippAddString()</CODE></A>,<A HREF="#ippAddStrings"> <CODE>
+ippAddStrings()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="ippAddResolution">ippAddResolution()</A></H2>
+<H3><A NAME="10_70_1">Usage</A></H3>
+<PRE>
+ipp_attribute_t *ippAddResolution(ipp_t *ipp, ipp_tag_t group,
+ const char *name, int xres,
+ int yres, ipp_res_t units);
+</PRE>
+<H3><A NAME="10_70_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>ipp</TD><TD>The IPP request</TD></TR>
+<TR><TD>group</TD><TD>The IPP group</TD></TR>
+<TR><TD>name</TD><TD>The name of attribute</TD></TR>
+<TR><TD>xres</TD><TD>The horizontal resolution</TD></TR>
+<TR><TD>yres</TD><TD>The vertical resolution</TD></TR>
+<TR><TD>units</TD><TD>The resolution units</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_70_3">Returns</A></H3>
+<P>A pointer to the new attribute or NULL if the attribute could not be
+ created.</P>
+<H3><A NAME="10_70_4">Description</A></H3>
+<P>The <CODE>ippAddResolution()</CODE> function adds a single resolution
+ attribute value to the specified IPP request.</P>
+<H3><A NAME="10_70_5">Example</A></H3>
+<PRE>
+#include &lt;cups/ipp.h&gt;
+
+ipp_t *ipp;
+
+ippAddBoolean(ipp, IPP_TAG_OPERATION, &quot;printer-resolution&quot;,
+ 720, 720, IPP_RES_PER_INCH);
+</PRE>
+<H3><A NAME="10_70_6">See Also</A></H3>
+<A HREF="#ippAddBoolean"> <CODE>ippAddBoolean()</CODE></A>,<A HREF="#ippAddBooleans">
+ <CODE>ippAddBooleans()</CODE></A>,<A HREF="#ippAddDate"> <CODE>
+ippAddDate()</CODE></A>,<A HREF="#ippAddInteger"> <CODE>ippAddInteger()</CODE>
+</A>,<A HREF="#ippAddIntegers"> <CODE>ippAddIntegers()</CODE></A>,<A HREF="#ippAddRange">
+ <CODE>ippAddRange()</CODE></A>,<A HREF="#ippAddRanges"> <CODE>
+ippAddRanges()</CODE></A>,<A HREF="#ippAddResolutions"> <CODE>
+ippAddResolutions()</CODE></A>,<A HREF="#ippAddSeparator"> <CODE>
+ippAddSeparator()</CODE></A>,<A HREF="#ippAddString"> <CODE>
+ippAddString()</CODE></A>,<A HREF="#ippAddStrings"> <CODE>
+ippAddStrings()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="ippAddResolutions">ippAddResolutions()</A></H2>
+<H3><A NAME="10_71_1">Usage</A></H3>
+<PRE>
+ipp_attribute_t *ippAddResolutions(ipp_t *ipp, ipp_tag_t group,
+ const char *name, int num_values,
+ const int *xres, const int *yres,
+ const ipp_res_t *units);
+</PRE>
+<H3><A NAME="10_71_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>ipp</TD><TD>The IPP request</TD></TR>
+<TR><TD>group</TD><TD>The IPP group</TD></TR>
+<TR><TD>name</TD><TD>The name of attribute</TD></TR>
+<TR><TD>num_values</TD><TD>The number of resolution values</TD></TR>
+<TR><TD>xres</TD><TD>The horizontal resolutions</TD></TR>
+<TR><TD>yres</TD><TD>The vertical resolutions</TD></TR>
+<TR><TD>units</TD><TD>The resolution units</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_71_3">Returns</A></H3>
+<P>A pointer to the new attribute or NULL if the attribute could not be
+ created.</P>
+<H3><A NAME="10_71_4">Description</A></H3>
+<P>The <CODE>ippAddResolutions()</CODE> function adds one or more
+ resolution attribute values to the specified IPP request. If the <CODE>
+values</CODE> pointer is <CODE>NULL</CODE> then an array of <CODE>
+num_values</CODE> 0,0 resolutions is created.</P>
+<H3><A NAME="10_71_5">Example</A></H3>
+<PRE>
+#include &lt;cups/ipp.h&gt;
+
+ipp_t *ipp;
+int xres[5];
+int yres[5];
+ipp_res_t units[5];
+
+ippAddBoolean(ipp, IPP_TAG_OPERATION, &quot;printer-resolutions-supported&quot;,
+ 5, xres, yres, units);
+</PRE>
+<H3><A NAME="10_71_6">See Also</A></H3>
+<A HREF="#ippAddBoolean"> <CODE>ippAddBoolean()</CODE></A>,<A HREF="#ippAddBooleans">
+ <CODE>ippAddBooleans()</CODE></A>,<A HREF="#ippAddDate"> <CODE>
+ippAddDate()</CODE></A>,<A HREF="#ippAddInteger"> <CODE>ippAddInteger()</CODE>
+</A>,<A HREF="#ippAddIntegers"> <CODE>ippAddIntegers()</CODE></A>,<A HREF="#ippAddRange">
+ <CODE>ippAddRange()</CODE></A>,<A HREF="#ippAddRanges"> <CODE>
+ippAddRanges()</CODE></A>,<A HREF="#ippAddResolution"> <CODE>
+ippAddResolution()</CODE></A>,<A HREF="#ippAddSeparator"> <CODE>
+ippAddSeparator()</CODE></A>,<A HREF="#ippAddString"> <CODE>
+ippAddString()</CODE></A>,<A HREF="#ippAddStrings"> <CODE>
+ippAddStrings()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="ippAddSeparator">ippAddSeparator()</A></H2>
+<H3><A NAME="10_72_1">Usage</A></H3>
+<PRE>
+ipp_attribute_t *ippAddSeparator(ipp_t *ipp);
+</PRE>
+<H3><A NAME="10_72_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>ipp</TD><TD>The IPP request</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_72_3">Returns</A></H3>
+<P>A pointer to the new separator or NULL if the separator could not be
+ created.</P>
+<H3><A NAME="10_72_4">Description</A></H3>
+<P>The <CODE>ippAddSeparator()</CODE> function adds a group separator to
+ the specified IPP request.</P>
+<H3><A NAME="10_72_5">Example</A></H3>
+<PRE>
+#include &lt;cups/ipp.h&gt;
+
+ipp_t *ipp;
+
+ippAddSeparator(ipp);
+</PRE>
+<H3><A NAME="10_72_6">See Also</A></H3>
+<A HREF="#ippAddBoolean"> <CODE>ippAddBoolean()</CODE></A>,<A HREF="#ippAddBooleans">
+ <CODE>ippAddBooleans()</CODE></A>,<A HREF="#ippAddDate"> <CODE>
+ippAddDate()</CODE></A>,<A HREF="#ippAddInteger"> <CODE>ippAddInteger()</CODE>
+</A>,<A HREF="#ippAddIntegers"> <CODE>ippAddIntegers()</CODE></A>,<A HREF="#ippAddRange">
+ <CODE>ippAddRange()</CODE></A>,<A HREF="#ippAddRanges"> <CODE>
+ippAddRanges()</CODE></A>,<A HREF="#ippAddResolution"> <CODE>
+ippAddResolution()</CODE></A>,<A HREF="#ippAddResolutions"> <CODE>
+ippAddResolutions()</CODE></A>,<A HREF="#ippAddString"> <CODE>
+ippAddString()</CODE></A>,<A HREF="#ippAddStrings"> <CODE>
+ippAddStrings()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="ippAddString">ippAddString()</A></H2>
+<H3><A NAME="10_73_1">Usage</A></H3>
+<PRE>
+ipp_attribute_t *ippAddString(ipp_t *ipp, ipp_tag_t group,
+ ipp_tag_t tag, const char *name,
+ const char *charset, const char *value);
+</PRE>
+<H3><A NAME="10_73_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>ipp</TD><TD>The IPP request</TD></TR>
+<TR><TD>group</TD><TD>The IPP group</TD></TR>
+<TR><TD>tag</TD><TD>The type of string value</TD></TR>
+<TR><TD>name</TD><TD>The name of attribute</TD></TR>
+<TR><TD>charset</TD><TD>The character set for the string</TD></TR>
+<TR><TD>value</TD><TD>The string value</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_73_3">Returns</A></H3>
+<P>A pointer to the new attribute or NULL if the attribute could not be
+ created.</P>
+<H3><A NAME="10_73_4">Description</A></H3>
+<P>The <CODE>ippAddString()</CODE> function adds a single string
+ attribute value to the specified IPP request. For <CODE>
+IPP_TAG_NAMELANG</CODE> and <CODE>IPP_TAG_TEXTLANG</CODE> strings, the
+ charset value is provided with the string to identify the string
+ encoding used. Otherwise the charset value is ignored.</P>
+<H3><A NAME="10_73_5">Example</A></H3>
+<PRE>
+#include &lt;cups/ipp.h&gt;
+
+ipp_t *ipp;
+
+ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_NAME, &quot;job-name&quot;,
+ NULL, &quot;abc123&quot;);
+</PRE>
+<H3><A NAME="10_73_6">See Also</A></H3>
+<A HREF="#ippAddBoolean"> <CODE>ippAddBoolean()</CODE></A>,<A HREF="#ippAddBooleans">
+ <CODE>ippAddBooleans()</CODE></A>,<A HREF="#ippAddDate"> <CODE>
+ippAddDate()</CODE></A>,<A HREF="#ippAddInteger"> <CODE>ippAddInteger()</CODE>
+</A>,<A HREF="#ippAddIntegers"> <CODE>ippAddIntegers()</CODE></A>,<A HREF="#ippAddRange">
+ <CODE>ippAddRange()</CODE></A>,<A HREF="#ippAddRanges"> <CODE>
+ippAddRanges()</CODE></A>,<A HREF="#ippAddResolution"> <CODE>
+ippAddResolution()</CODE></A>,<A HREF="#ippAddResolutions"> <CODE>
+ippAddResolutions()</CODE></A>,<A HREF="#ippAddSeparator"> <CODE>
+ippAddSeparator()</CODE></A>,<A HREF="#ippAddStrings"> <CODE>
+ippAddStrings()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="ippAddStrings">ippAddStrings()</A></H2>
+<H3><A NAME="10_74_1">Usage</A></H3>
+<PRE>
+ipp_attribute_t *ippAddStrings(ipp_t *ipp, ipp_tag_t group,
+ ipp_tag_t tag, const char *name,
+ int num_values, const char *charset,
+ const char **values);
+</PRE>
+<H3><A NAME="10_74_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>ipp</TD><TD>The IPP request</TD></TR>
+<TR><TD>group</TD><TD>The IPP group</TD></TR>
+<TR><TD>tag</TD><TD>The type of string value</TD></TR>
+<TR><TD>name</TD><TD>The name of attribute</TD></TR>
+<TR><TD>num_values</TD><TD>The number of strings</TD></TR>
+<TR><TD>charset</TD><TD>The character set for the strings</TD></TR>
+<TR><TD>values</TD><TD>The string values</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_74_3">Returns</A></H3>
+<P>A pointer to the new attribute or NULL if the attribute could not be
+ created.</P>
+<H3><A NAME="10_74_4">Description</A></H3>
+<P>The <CODE>ippAddStrings()</CODE> function adds one or more string
+ attribute values to the specified IPP request. For <CODE>
+IPP_TAG_NAMELANG</CODE> and <CODE>IPP_TAG_TEXTLANG</CODE> strings, the
+ charset value is provided with the strings to identify the string
+ encoding used. Otherwise the charset value is ignored. If the <CODE>
+values</CODE> pointer is <CODE>NULL</CODE> then an array of <CODE>
+num_values</CODE> NULL strings is created.</P>
+<H3><A NAME="10_74_5">Example</A></H3>
+<PRE>
+#include &lt;cups/ipp.h&gt;
+
+ipp_t *ipp;
+char *values[2] = { &quot;one&quot;, &quot;two&quot; };
+
+ippAddStrings(ipp, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, &quot;attr-name&quot;,
+ 2, NULL, values);
+</PRE>
+<H3><A NAME="10_74_6">See Also</A></H3>
+<A HREF="#ippAddBoolean"> <CODE>ippAddBoolean()</CODE></A>,<A HREF="#ippAddBooleans">
+ <CODE>ippAddBooleans()</CODE></A>,<A HREF="#ippAddDate"> <CODE>
+ippAddDate()</CODE></A>,<A HREF="#ippAddInteger"> <CODE>ippAddInteger()</CODE>
+</A>,<A HREF="#ippAddIntegers"> <CODE>ippAddIntegers()</CODE></A>,<A HREF="#ippAddRange">
+ <CODE>ippAddRange()</CODE></A>,<A HREF="#ippAddRanges"> <CODE>
+ippAddRanges()</CODE></A>,<A HREF="#ippAddResolution"> <CODE>
+ippAddResolution()</CODE></A>,<A HREF="#ippAddResolutions"> <CODE>
+ippAddResolutions()</CODE></A>,<A HREF="#ippAddSeparator"> <CODE>
+ippAddSeparator()</CODE></A>,<A HREF="#ippAddString"> <CODE>
+ippAddString()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="ippDateToTime">ippDateToTime()</A></H2>
+<H3><A NAME="10_75_1">Usage</A></H3>
+<PRE>
+time_t ippDateToTime(const ipp_uchar_t date[11]);
+</PRE>
+<H3><A NAME="10_75_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>date</TD><TD>The IPP date-time value</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_75_3">Returns</A></H3>
+<P>A UNIX time value.</P>
+<H3><A NAME="10_75_4">Description</A></H3>
+<P>The <CODE>ippDateToTime()</CODE> function converts an IPP date-time
+ value to a UNIX time value.</P>
+<H3><A NAME="10_75_5">Example</A></H3>
+<PRE>
+#include &lt;cups/ipp.h&gt;
+
+ipp_uchar_t date[11];
+
+printf(&quot;UNIX time is %d\n&quot;, ippDateToTime(date));
+</PRE>
+<H3><A NAME="10_75_6">See Also</A></H3>
+<A HREF="#ippTimeToDate"> <CODE>ippTimeToDate()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="ippDelete">ippDelete()</A></H2>
+<H3><A NAME="10_76_1">Usage</A></H3>
+<PRE>
+void ippDelete(ipp_t *ipp);
+</PRE>
+<H3><A NAME="10_76_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>ipp</TD><TD>The IPP request or response</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_76_3">Description</A></H3>
+<P>The <CODE>ippDelete()</CODE> function deletes all memory used by an
+ IPP request or response.</P>
+<H3><A NAME="10_76_4">Example</A></H3>
+<PRE>
+#include &lt;cups/ipp.h&gt;
+
+ipp_t *ipp;
+
+ippDelete(ipp);
+</PRE>
+<H3><A NAME="10_76_5">See Also</A></H3>
+<A HREF="#ippNew"> <CODE>ippNew()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="ippFindAttribute">ippFindAttribute()</A></H2>
+<H3><A NAME="10_77_1">Usage</A></H3>
+<PRE>
+ipp_attribute_t *ippFindAttribute(ipp_t *ipp, const char *name, ipp_tag_t tag);
+</PRE>
+<H3><A NAME="10_77_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>ipp</TD><TD>The IPP request or response</TD></TR>
+<TR><TD>name</TD><TD>The name of the attribute</TD></TR>
+<TR><TD>tag</TD><TD>The required value tag for the attribute or <CODE>
+IPP_TAG_ZERO</CODE> for any type of value.</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_77_3">Returns</A></H3>
+<P>A pointer to the first occurrence of the requested attribute, or <CODE>
+NULL</CODE> if it was not found.</P>
+<H3><A NAME="10_77_4">Description</A></H3>
+<P><CODE>ippFindAttribute()</CODE> finds the first occurrence of the
+ named attribute. The <CODE>tag</CODE> parameter restricts the search to
+ a specific value type - use <CODE>IPP_TAG_ZERO</CODE> to find any value
+ with the name.</P>
+<P>The value tags <CODE>IPP_TAG_NAME</CODE> and <CODE>IPP_TAG_TEXT</CODE>
+ match the name/text values with or without the language code.</P>
+<H3><A NAME="10_77_5">Example</A></H3>
+<PRE>
+ipp_attribute_t *attr;
+
+attr = ippFindAttribute(response, &quot;printer-state-message&quot;, IPP_TAG_TEXT);
+</PRE>
+<H3><A NAME="10_77_6">See Also</A></H3>
+<A HREF="#cupsDoFileRequest"> <CODE>cupsDoFileRequest()</CODE></A>,<A HREF="#cupsDoRequest">
+ <CODE>cupsDoRequest()</CODE></A>,<A HREF="#ippDelete"> <CODE>
+ippDelete()</CODE></A>,<A HREF="#ippNew"> <CODE>ippNew()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="ippLength">ippLength()</A></H2>
+<H3><A NAME="10_78_1">Usage</A></H3>
+<PRE>
+int ippLength(ipp_t *ipp);
+</PRE>
+<H3><A NAME="10_78_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>ipp</TD><TD>The IPP request or response</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_78_3">Returns</A></H3>
+<P>The total encoded length of the IPP request or response in bytes.</P>
+<H3><A NAME="10_78_4">Description</A></H3>
+<P><CODE>ippLength()</CODE> returns the length of the IPP request or
+ response in bytes.</P>
+<H3><A NAME="10_78_5">Example</A></H3>
+<PRE>
+printf(&quot;The length of the response is %d bytes.\n&quot;, ippLength(response));
+</PRE>
+<H3><A NAME="10_78_6">See Also</A></H3>
+<A HREF="#ippDelete"> <CODE>ippDelete()</CODE></A>,<A HREF="#ippNew"> <CODE>
+ippNew()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="ippNew">ippNew()</A></H2>
+<H3><A NAME="10_79_1">Usage</A></H3>
+<PRE>
+ipp_t *ippNew(void);
+</PRE>
+<H3><A NAME="10_79_2">Returns</A></H3>
+<P>A pointer to a new IPP request or response.</P>
+<H3><A NAME="10_79_3">Description</A></H3>
+<P>The <CODE>ippNew()</CODE> function creates a new IPP request or
+ response.</P>
+<H3><A NAME="10_79_4">Example</A></H3>
+<PRE>
+#include &lt;cups/ipp.h&gt;
+
+ipp_t *ipp;
+
+ipp = ippNew();
+</PRE>
+<H3><A NAME="10_79_5">See Also</A></H3>
+<A HREF="#ippDelete"> <CODE>ippDelete()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="ippPort">ippPort()</A></H2>
+<H3><A NAME="10_80_1">Usage</A></H3>
+<PRE>
+int ippPort(void);
+</PRE>
+<H3><A NAME="10_80_2">Returns</A></H3>
+<P>The default TCP/IP port number for IPP requests.</P>
+<H3><A NAME="10_80_3">Description</A></H3>
+<P>The <CODE>ippPort()</CODE> function returns the default IPP port
+ number for requests.</P>
+<H3><A NAME="10_80_4">Example</A></H3>
+<PRE>
+#include &lt;cups/http.h&gt;
+#include &lt;cups/ipp.h&gt;
+
+http_t *http;
+
+http = httpConnect(cupsServer(), ippPort());
+</PRE>
+<H3><A NAME="10_80_5">See Also</A></H3>
+<A HREF="#cupsServer"> <CODE>cupsServer()</CODE></A>,<A HREF="#ippSetPort">
+ <CODE>ippSetPort()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="ippRead">ippRead()</A></H2>
+<H3><A NAME="10_81_1">Usage</A></H3>
+<PRE>
+ipp_state_t ippRead(http_t *http, ipp_t *ipp);
+</PRE>
+<H3><A NAME="10_81_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>http</TD><TD>The HTTP connection</TD></TR>
+<TR><TD>ipp</TD><TD>The IPP request or response</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_81_3">Returns</A></H3>
+<P>The current read state.</P>
+<H3><A NAME="10_81_4">Description</A></H3>
+<P>The <CODE>ippRead()</CODE> function reads IPP attributes from the
+ specified HTTP connection. Programs should continue calling <CODE>
+ippRead()</CODE> until <CODE>IPP_ERROR</CODE> or <CODE>IPP_DATA</CODE>
+ is returned.</P>
+<H3><A NAME="10_81_5">Example</A></H3>
+<PRE>
+#include &lt;cups/http.h&gt;
+#include &lt;cups/ipp.h&gt;
+
+http_t *http;
+ipp_t *ipp;
+ipp_state_t status;
+
+ipp = ippNew();
+
+while ((status = ippRead(http, ipp)) != IPP_ERROR)
+ if (status == IPP_DATA)
+ break;
+
+if (status == IPP_DATA)
+{
+ ... read additional non-IPP data using httpRead() ...
+}
+</PRE>
+<H3><A NAME="10_81_6">See Also</A></H3>
+<A HREF="#ippWrite"> <CODE>ippWrite()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="ippSetPort">ippSetPort()</A></H2>
+<H3><A NAME="10_82_1">Usage</A></H3>
+<PRE>
+void
+ippSetPort(int port);
+</PRE>
+<H3><A NAME="10_82_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>port</TD><TD>The port number to use</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_82_3">Description</A></H3>
+<P>The <CODE>ippSetPort()</CODE> function sets the default IPP port
+ number for requests.</P>
+<H3><A NAME="10_82_4">Example</A></H3>
+<PRE>
+#include &lt;cups/http.h&gt;
+#include &lt;cups/ipp.h&gt;
+
+...
+
+ippSetPort(8631);
+</PRE>
+<H3><A NAME="10_82_5">See Also</A></H3>
+<A HREF="#ippPort"> <CODE>ippPort()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="ippTimeToDate">ippTimeToDate()</A></H2>
+<H3><A NAME="10_83_1">Usage</A></H3>
+<PRE>
+ipp_uchar_t *ippTimeToDate(time_t time);
+</PRE>
+<H3><A NAME="10_83_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>time</TD><TD>The UNIX time value</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_83_3">Returns</A></H3>
+<P>A static pointer to an IPP date-time value.</P>
+<H3><A NAME="10_83_4">Description</A></H3>
+<P>The <CODE>ippTimeToDate()</CODE> function converts a UNIX time to an
+ IPP date-time value.</P>
+<H3><A NAME="10_83_5">Example</A></H3>
+<PRE>
+#include &lt;cups/ipp.h&gt;
+
+ipp_uchar_t *date;
+
+date = ippTimeToDate(time(NULL));
+</PRE>
+<H3><A NAME="10_83_6">See Also</A></H3>
+<A HREF="#ippDateToTime"> <CODE>ippDateToTime()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="ippWrite">ippWrite()</A></H2>
+<H3><A NAME="10_84_1">Usage</A></H3>
+<PRE>
+ipp_state_t ippWrite(http_t *http, ipp_t *ipp);
+</PRE>
+<H3><A NAME="10_84_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>http</TD><TD>The HTTP connection</TD></TR>
+<TR><TD>ipp</TD><TD>The IPP request or response</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_84_3">Returns</A></H3>
+<P>The current write state.</P>
+<H3><A NAME="10_84_4">Description</A></H3>
+<P>The <CODE>ippWrite()</CODE> function writes IPP attributes to the
+ specified HTTP connection. Programs should continue calling <CODE>
+ippWrite()</CODE> until <CODE>IPP_ERROR</CODE> or <CODE>IPP_DATA</CODE>
+ is returned.</P>
+<H3><A NAME="10_84_5">Example</A></H3>
+<PRE>
+#include &lt;cups/http.h&gt;
+#include &lt;cups/ipp.h&gt;
+
+http_t *http;
+ipp_t *ipp;
+ipp_state_t status;
+
+ipp = ippNew();
+... add attributes ...
+
+while ((status = ippWrite(http, ipp)) != IPP_ERROR)
+ if (status == IPP_DATA)
+ break;
+
+if (status == IPP_DATA)
+{
+ ... read additional non-IPP data using httpWrite() ...
+}
+</PRE>
+<H3><A NAME="10_84_6">See Also</A></H3>
+<A HREF="#ippRead"> <CODE>ippRead()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="ppdClose">ppdClose()</A></H2>
+<H3><A NAME="10_85_1">Usage</A></H3>
+<PRE>
+void ppdClose(ppd_file_t *ppd);
+</PRE>
+<H3><A NAME="10_85_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>ppd</TD><TD>The PPD file</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_85_3">Description</A></H3>
+<P>The <CODE>ppdClose()</CODE> function frees all memory associated with
+ the PPD file.</P>
+<H3><A NAME="10_85_4">Example</A></H3>
+<PRE>
+#include &lt;cups/ppd.h&gt;
+
+ppd_file_t *ppd;
+
+ppdClose(ppd);
+</PRE>
+<H3><A NAME="10_85_5">See Also</A></H3>
+<A HREF="#ppdOpen"> <CODE>ppdOpen()</CODE></A>,<A HREF="#ppdOpenFd"> <CODE>
+ppdOpenFd()</CODE></A>,<A HREF="#ppdOpenFile"> <CODE>ppdOpenFile()</CODE>
+</A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="ppdConflicts">ppdConflicts()</A></H2>
+<H3><A NAME="10_86_1">Usage</A></H3>
+<PRE>
+int ppdConflicts(ppd_file_t *ppd);
+</PRE>
+<H3><A NAME="10_86_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>ppd</TD><TD>The PPD file</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_86_3">Returns</A></H3>
+<P>The number of option conflicts in the file.</P>
+<H3><A NAME="10_86_4">Description</A></H3>
+<P>The <CODE>ppdConflicts()</CODE> function returns the number of
+ conflicts with the currently selected options.</P>
+<H3><A NAME="10_86_5">Example</A></H3>
+<PRE>
+#include &lt;cups/ppd.h&gt;
+
+ppd_file_t *ppd;
+
+printf(&quot;%d conflicts\n&quot;, ppdConflicts(ppd));
+</PRE>
+<H3><A NAME="10_86_6">See Also</A></H3>
+<A HREF="#cupsMarkOptions"> <CODE>cupsMarkOptions()</CODE></A>,<A HREF="#ppdIsMarked">
+ <CODE>ppdIsMarked()</CODE></A>,<A HREF="#ppdMarkDefaults"> <CODE>
+ppdMarkDefaults()</CODE></A>,<A HREF="#ppdMarkOption"> <CODE>
+ppdMarkOption()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="ppdEmit">ppdEmit()</A></H2>
+<H3><A NAME="10_87_1">Usage</A></H3>
+<PRE>
+int ppdEmit(ppd_file_t *ppd, FILE *file, ppd_section_t section);
+</PRE>
+<H3><A NAME="10_87_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>ppd</TD><TD>The PPD file</TD></TR>
+<TR><TD>file</TD><TD>The file to write to</TD></TR>
+<TR><TD>section</TD><TD>The option section to write</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_87_3">Returns</A></H3>
+<P>0 on success, -1 on error.</P>
+<H3><A NAME="10_87_4">Description</A></H3>
+<P>The <CODE>ppdEmit()</CODE> function sends printer-specific option
+ commands to the specified file.</P>
+<H3><A NAME="10_87_5">Example</A></H3>
+<PRE>
+#include &lt;cups/ppd.h&gt;
+
+ppd_file_t *ppd;
+
+ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
+</PRE>
+<H3><A NAME="10_87_6">See Also</A></H3>
+<A HREF="#ppdEmitFd"> <CODE>ppdEmitFd()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="ppdEmitFd">ppdEmitFd()</A></H2>
+<H3><A NAME="10_88_1">Usage</A></H3>
+<PRE>
+int ppdEmitFd(ppd_file_t *ppd, int fd, ppd_section_t section);
+</PRE>
+<H3><A NAME="10_88_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>ppd</TD><TD>The PPD file</TD></TR>
+<TR><TD>fd</TD><TD>The file descriptor to write to</TD></TR>
+<TR><TD>section</TD><TD>The option section to write</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_88_3">Returns</A></H3>
+<P>0 on success, -1 on error.</P>
+<H3><A NAME="10_88_4">Description</A></H3>
+<P>The <CODE>ppdEmitFd()</CODE> function sends printer-specific option
+ commands to the specified file descriptor.</P>
+<H3><A NAME="10_88_5">Example</A></H3>
+<PRE>
+#include &lt;cups/ppd.h&gt;
+
+ppd_file_t *ppd;
+
+ppdEmitFd(ppd, 1, PPD_ORDER_PAGE);
+</PRE>
+<H3><A NAME="10_88_6">See Also</A></H3>
+<A HREF="#ppdEmit"> <CODE>ppdEmit()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="ppdFindChoice">ppdFindChoice()</A></H2>
+<H3><A NAME="10_89_1">Usage</A></H3>
+<PRE>
+ppd_choice_t *ppdFindChoice(ppd_option_t *option, const char *choice);
+</PRE>
+<H3><A NAME="10_89_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>option</TD><TD>A pointer to the option</TD></TR>
+<TR><TD>choice</TD><TD>The name of the choice</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_89_3">Returns</A></H3>
+<P>A pointer to the choice data or NULL if the choice does not exist.</P>
+<H3><A NAME="10_89_4">Description</A></H3>
+<P>The <CODE>ppdFindChoice()</CODE> function returns a pointer to the
+ choice data for the specified option.</P>
+<H3><A NAME="10_89_5">Example</A></H3>
+<PRE>
+#include &lt;cups/ppd.h&gt;
+
+ppd_file_t *ppd;
+ppd_option_t *option;
+ppd_choice_t *choice;
+
+option = ppdFindOption(ppd, &quot;PageSize&quot;);
+choice = ppdFindChoice(option, &quot;Letter&quot;);
+</PRE>
+<H3><A NAME="10_89_6">See Also</A></H3>
+<A HREF="#ppdFindMarkedChoice"> <CODE>ppdFindMarkedChoice()</CODE></A>,<A
+HREF="#ppdFindOption"> <CODE>ppdFindOption()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="ppdFindMarkedChoice">ppdFindMarkedChoice()</A></H2>
+<H3><A NAME="10_90_1">Usage</A></H3>
+<PRE>
+ppd_choice_t *ppdFindMarkedChoice(ppd_file_t *ppd, const char *keyword);
+</PRE>
+<H3><A NAME="10_90_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>ppd</TD><TD>The PPD file</TD></TR>
+<TR><TD>keyword</TD><TD>The name of the option</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_90_3">Returns</A></H3>
+<P>A pointer to the choice data or NULL if the choice does not exist or
+ is not marked.</P>
+<H3><A NAME="10_90_4">Description</A></H3>
+<P>The <CODE>ppdFindMarkedChoice()</CODE> function returns a pointer to
+ the marked choice data for the specified option.</P>
+<H3><A NAME="10_90_5">Example</A></H3>
+<PRE>
+#include &lt;cups/ppd.h&gt;
+
+ppd_file_t *ppd;
+ppd_choice_t *choice;
+
+choice = ppdFindMarkedChoice(ppd, &quot;PageSize&quot;);
+</PRE>
+<H3><A NAME="10_90_6">See Also</A></H3>
+<A HREF="#ppdFindChoice"> <CODE>ppdFindChoice()</CODE></A>,<A HREF="#ppdFindOption">
+ <CODE>ppdFindOption()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="ppdFindOption">ppdFindOption()</A></H2>
+<H3><A NAME="10_91_1">Usage</A></H3>
+<PRE>
+ppd_option_t *ppdFindOption(ppd_file_t *ppd, const char *keyword);
+</PRE>
+<H3><A NAME="10_91_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>ppd</TD><TD>The PPD file</TD></TR>
+<TR><TD>keyword</TD><TD>The name of the option</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_91_3">Returns</A></H3>
+<P>A pointer to the option data or NULL if the option does not exist.</P>
+<H3><A NAME="10_91_4">Description</A></H3>
+<P>The <CODE>ppdFindOption()</CODE> function returns a pointer to the
+ option data for the specified option.</P>
+<H3><A NAME="10_91_5">Example</A></H3>
+<PRE>
+#include &lt;cups/ppd.h&gt;
+
+ppd_file_t *ppd;
+ppd_option_t *option;
+
+option = ppdFindOption(ppd, &quot;PageSize&quot;);
+</PRE>
+<H3><A NAME="10_91_6">See Also</A></H3>
+<A HREF="#ppdFindChoice"> <CODE>ppdFindChoice()</CODE></A>,<A HREF="#ppdFindMarkedChoice">
+ <CODE>ppdFindMarkedChoice()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="ppdIsMarked">ppdIsMarked()</A></H2>
+<H3><A NAME="10_92_1">Usage</A></H3>
+<PRE>
+int ppdIsMarked(ppd_file_t *ppd, const char *keyword, char char *choice);
+</PRE>
+<H3><A NAME="10_92_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>ppd</TD><TD>The PPD file</TD></TR>
+<TR><TD>keyword</TD><TD>The name of the option</TD></TR>
+<TR><TD>choice</TD><TD>The name of the option choice</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_92_3">Returns</A></H3>
+<P>1 if the choice is marked, 0 otherwise.</P>
+<H3><A NAME="10_92_4">Description</A></H3>
+<P>The <CODE>ppdIsMarked()</CODE> function returns whether or not the
+ specified option choice is marked.</P>
+<H3><A NAME="10_92_5">Example</A></H3>
+<PRE>
+#include &lt;cups/ppd.h&gt;
+
+ppd_file_t *ppd;
+
+printf(&quot;Letter size %s selected.\n&quot;,
+ ppdIsMarked(ppd, &quot;PageSize&quot;, &quot;Letter&quot;) ? &quot;is&quot; : &quot;is not&quot;);
+</PRE>
+<H3><A NAME="10_92_6">See Also</A></H3>
+<A HREF="#cupsMarkOptions"> <CODE>cupsMarkOptions()</CODE></A>,<A HREF="#ppdConflicts">
+ <CODE>ppdConflicts()</CODE></A>,<A HREF="#ppdIsMarked"> <CODE>
+ppdIsMarked()</CODE></A>,<A HREF="#ppdMarkDefaults"> <CODE>
+ppdMarkDefaults()</CODE></A>,<A HREF="#ppdMarkOption"> <CODE>
+ppdMarkOption()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="ppdMarkDefaults">ppdMarkDefaults()</A></H2>
+<H3><A NAME="10_93_1">Usage</A></H3>
+<PRE>
+void ppdMarkDefaults(ppd_file_t *ppd);
+</PRE>
+<H3><A NAME="10_93_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>ppd</TD><TD>The PPD file</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_93_3">Description</A></H3>
+<P>The <CODE>ppdMarkDefaults()</CODE> function marks all of the default
+ choices in the PPD file.</P>
+<H3><A NAME="10_93_4">Example</A></H3>
+<PRE>
+#include &lt;cups/ppd.h&gt;
+
+ppd_file_t *ppd;
+
+ppdMarkDefaults(ppd);
+</PRE>
+<H3><A NAME="10_93_5">See Also</A></H3>
+<A HREF="#cupsMarkOptions"> <CODE>cupsMarkOptions()</CODE></A>,<A HREF="#ppdConflicts">
+ <CODE>ppdConflicts()</CODE></A>,<A HREF="#ppdIsMarked"> <CODE>
+ppdIsMarked()</CODE></A>,<A HREF="#ppdMarkDefaults"> <CODE>
+ppdMarkDefaults()</CODE></A>,<A HREF="#ppdMarkOption"> <CODE>
+ppdMarkOption()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="ppdMarkOption">ppdMarkOption()</A></H2>
+<H3><A NAME="10_94_1">Usage</A></H3>
+<PRE>
+int ppdMarkOption(ppd_file_t *ppd, const char *keyword, const char *choice);
+</PRE>
+<H3><A NAME="10_94_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>ppd</TD><TD>The PPD file</TD></TR>
+<TR><TD>keyword</TD><TD>The name of the option</TD></TR>
+<TR><TD>choice</TD><TD>The name of the choice</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_94_3">Returns</A></H3>
+<P>The number of conflicts in the PPD file.</P>
+<H3><A NAME="10_94_4">Description</A></H3>
+<P>The <CODE>ppdMarkOption()</CODE> function marks the specified option
+ choice.</P>
+<H3><A NAME="10_94_5">Example</A></H3>
+<PRE>
+#include &lt;cups/ppd.h&gt;
+
+ppd_file_t *ppd;
+
+ppdMarkOption(ppd, &quot;PageSize&quot;, &quot;Letter&quot;);
+</PRE>
+<H3><A NAME="10_94_6">See Also</A></H3>
+<A HREF="#cupsMarkOptions"> <CODE>cupsMarkOptions()</CODE></A>,<A HREF="#ppdConflicts">
+ <CODE>ppdConflicts()</CODE></A>,<A HREF="#ppdIsMarked"> <CODE>
+ppdIsMarked()</CODE></A>,<A HREF="#ppdMarkDefaults"> <CODE>
+ppdMarkDefaults()</CODE></A>,<A HREF="#ppdMarkOption"> <CODE>
+ppdMarkOption()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="ppdOpen">ppdOpen()</A></H2>
+<H3><A NAME="10_95_1">Usage</A></H3>
+<PRE>
+ppd_file_t *ppdOpen(FILE *file);
+</PRE>
+<H3><A NAME="10_95_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>file</TD><TD>The file to read from</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_95_3">Returns</A></H3>
+<P>A pointer to a PPD file structure or NULL if the PPD file could not
+ be read.</P>
+<H3><A NAME="10_95_4">Description</A></H3>
+<P>The <CODE>ppdOpen()</CODE> function reads a PPD file from the
+ specified file into memory.</P>
+<H3><A NAME="10_95_5">Example</A></H3>
+<PRE>
+#include &lt;cups/ppd.h&gt;
+
+ppd_file_t *ppd;
+FILE *file;
+
+file = fopen(&quot;filename.ppd&quot;, &quot;rb&quot;);
+ppd = ppdOpen(file);
+fclose(file);
+</PRE>
+<H3><A NAME="10_95_6">See Also</A></H3>
+<A HREF="#ppdClose"> <CODE>ppdClose()</CODE></A>,<A HREF="#ppdOpenFd"> <CODE>
+ppdOpenFd()</CODE></A>,<A HREF="#ppdOpenFile"> <CODE>ppdOpenFile()</CODE>
+</A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="ppdOpenFd">ppdOpenFd()</A></H2>
+<H3><A NAME="10_96_1">Usage</A></H3>
+<PRE>
+ppd_file_t *ppdOpenFd(int fd);
+</PRE>
+<H3><A NAME="10_96_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>fd</TD><TD>The file descriptor to read from</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_96_3">Returns</A></H3>
+<P>A pointer to a PPD file structure or NULL if the PPD file could not
+ be read.</P>
+<H3><A NAME="10_96_4">Description</A></H3>
+<P>The <CODE>ppdOpenFd()</CODE> function reads a PPD file from the
+ specified file descriptor into memory.</P>
+<H3><A NAME="10_96_5">Example</A></H3>
+<PRE>
+#include &lt;cups/ppd.h&gt;
+
+ppd_file_t *ppd;
+int fd;
+
+fd = open(&quot;filename.ppd&quot;, O_RDONLY);
+ppd = ppdOpenFd(fd);
+close(fd);
+</PRE>
+<H3><A NAME="10_96_6">See Also</A></H3>
+<A HREF="#ppdClose"> <CODE>ppdClose()</CODE></A>,<A HREF="#ppdOpen"> <CODE>
+ppdOpen()</CODE></A>,<A HREF="#ppdOpenFile"> <CODE>ppdOpenFile()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="ppdOpenFile">ppdOpenFile()</A></H2>
+<H3><A NAME="10_97_1">Usage</A></H3>
+<PRE>
+ppd_file_t *ppdOpenFile(const char *filename);
+</PRE>
+<H3><A NAME="10_97_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>filename</TD><TD>The name of the file to read from</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_97_3">Returns</A></H3>
+<P>A pointer to a PPD file structure or NULL if the PPD file could not
+ be read.</P>
+<H3><A NAME="10_97_4">Description</A></H3>
+<P>The <CODE>ppdOpenFile()</CODE> function reads a PPD file from the
+ named file into memory.</P>
+<H3><A NAME="10_97_5">Example</A></H3>
+<PRE>
+#include &lt;cups/ppd.h&gt;
+
+ppd_file_t *ppd;
+
+ppd = ppdOpenFile(&quot;filename.ppd&quot;);
+</PRE>
+<H3><A NAME="10_97_6">See Also</A></H3>
+<A HREF="#ppdClose"> <CODE>ppdClose()</CODE></A>,<A HREF="#ppdOpen"> <CODE>
+ppdOpen()</CODE></A>,<A HREF="#ppdOpenFd"> <CODE>ppdOpenFd()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="ppdPageLength">ppdPageLength()</A></H2>
+<H3><A NAME="10_98_1">Usage</A></H3>
+<PRE>
+float ppdPageLength(ppd_file_t *ppd, const char *name);
+</PRE>
+<H3><A NAME="10_98_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>ppd</TD><TD>The PPD file</TD></TR>
+<TR><TD>name</TD><TD>The name of the page size</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_98_3">Returns</A></H3>
+<P>The length of the specified page size in points or 0 if the page size
+ does not exist.</P>
+<H3><A NAME="10_98_4">Description</A></H3>
+<P>The <CODE>ppdPageLength()</CODE> function returns the page length of
+ the specified page size.</P>
+<H3><A NAME="10_98_5">Example</A></H3>
+<PRE>
+#include &lt;cups/ppd.h&gt;
+
+ppd_file_t *ppd;
+
+printf(&quot;Length = %.0f\n&quot;, ppdPageLength(ppd, &quot;Letter&quot;));
+</PRE>
+<H3><A NAME="10_98_6">See Also</A></H3>
+<A HREF="#ppdPageLength"> <CODE>ppdPageLength()</CODE></A>,<A HREF="#ppdPageSize">
+ <CODE>ppdPageSize()</CODE></A>,<A HREF="#ppdPageWidth"> <CODE>
+ppdPageWidth()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="ppdPageSize">ppdPageSize()</A></H2>
+<H3><A NAME="10_99_1">Usage</A></H3>
+<PRE>
+ppd_size_t *ppdPageSize(ppd_file_t *ppd, const char *name);
+</PRE>
+<H3><A NAME="10_99_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>ppd</TD><TD>The PPD file</TD></TR>
+<TR><TD>name</TD><TD>The name of the page size</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_99_3">Returns</A></H3>
+<P>A pointer to the page size record of the specified page size in
+ points or NULL if the page size does not exist.</P>
+<H3><A NAME="10_99_4">Description</A></H3>
+<P>The <CODE>ppdPageSize()</CODE> function returns the page size record
+ for the specified page size.</P>
+<H3><A NAME="10_99_5">Example</A></H3>
+<PRE>
+#include &lt;cups/ppd.h&gt;
+
+ppd_file_t *ppd;
+ppd_size_t *size;
+
+size = ppdPageSize(ppd, &quot;Letter&quot;);
+if (size != NULL)
+{
+ printf(&quot; Width = %.0f\n&quot;, size-&gt;width);
+ printf(&quot;Length = %.0f\n&quot;, size-&gt;length);
+ printf(&quot; Left = %.0f\n&quot;, size-&gt;left);
+ printf(&quot; Right = %.0f\n&quot;, size-&gt;right);
+ printf(&quot;Bottom = %.0f\n&quot;, size-&gt;bottom);
+ printf(&quot; Top = %.0f\n&quot;, size-&gt;top);
+}
+</PRE>
+<H3><A NAME="10_99_6">See Also</A></H3>
+<A HREF="#ppdPageLength"> <CODE>ppdPageLength()</CODE></A>,<A HREF="#ppdPageWidth">
+ <CODE>ppdPageWidth()</CODE></A>
+<!-- NEW PAGE -->
+
+<H2><A NAME="ppdPageWidth">ppdPageWidth()</A></H2>
+<H3><A NAME="10_100_1">Usage</A></H3>
+<PRE>
+float ppdPageWidth(ppd_file_t *ppd, const char *name);
+</PRE>
+<H3><A NAME="10_100_2">Arguments</A></H3>
+<CENTER>
+<TABLE BORDER WIDTH="80%">
+<TR><TH>Argument</TH><TH>Description</TH></TR>
+<TR><TD>ppd</TD><TD>The PPD file</TD></TR>
+<TR><TD>name</TD><TD>The name of the page size</TD></TR>
+</TABLE>
+</CENTER>
+<H3><A NAME="10_100_3">Returns</A></H3>
+<P>The width of the specified page size in points or 0 if the page size
+ does not exist.</P>
+<H3><A NAME="10_100_4">Description</A></H3>
+<P>The <CODE>ppdPageWidth()</CODE> function returns the page width of
+ the specified page size.</P>
+<H3><A NAME="10_100_5">Example</A></H3>
+<PRE>
+#include &lt;cups/ppd.h&gt;
+
+ppd_file_t *ppd;
+
+printf(&quot;Width = %.0f\n&quot;, ppdPageWidth(ppd, &quot;Letter&quot;));
+</PRE>
+<H3><A NAME="10_100_6">See Also</A></H3>
+<A HREF="#ppdPageLength"> <CODE>ppdPageLength()</CODE></A>,<A HREF="#ppdPageSize">
+ <CODE>ppdPageSize()</CODE></A></BODY>
+</HTML>
diff --git a/doc/spm.pdf b/doc/spm.pdf
new file mode 100644
index 000000000..733118725
--- /dev/null
+++ b/doc/spm.pdf
Binary files differ
diff --git a/doc/spm.shtml b/doc/spm.shtml
new file mode 100644
index 000000000..0ca9c943c
--- /dev/null
+++ b/doc/spm.shtml
@@ -0,0 +1,8667 @@
+<HTML>
+<HEAD>
+ <META NAME="COPYRIGHT" CONTENT="Copyright 1997-2002, All Rights Reserved">
+ <META NAME="DOCNUMBER" CONTENT="CUPS-SPM-1.1.13">
+ <META NAME="Author" CONTENT="Easy Software Products">
+ <TITLE>CUPS Software Programmers Manual</TITLE>
+</HEAD>
+<BODY>
+
+<H1 ALIGN="RIGHT">Preface</H1>
+
+<P>This software programmers manual provides software
+programming information for the Common UNIX Printing System
+("CUPS") Version 1.1.13.
+
+<EMBED SRC="system-overview.shtml">
+
+<!-- NEED 2in -->
+<H2>Document Overview</H2>
+
+<P>This software programmers manual is organized into the following sections:
+
+<UL>
+ <LI><A HREF="#OVERVIEW">1 - Printing System Overview</A>
+ <LI><A HREF="#CUPS_API">2 - The CUPS API</A>
+ <LI><A HREF="#WRITING_FILTERS">3 - Writing Filters</A>
+ <LI><A HREF="#WRITING_DRIVERS">4 - Writing Printer Drivers</A>
+ <LI><A HREF="#WRITING_BACKENDS">5 - Writing Backends</A>
+ <LI><A HREF="#LICENSE">A - Software License Agreement</A>
+ <LI><A HREF="#CONSTANTS">B - Constants</A>
+ <LI><A HREF="#STRUCTURES">C - Structures</A>
+ <LI><A HREF="#FUNCTIONS">D - Functions</A>
+</UL>
+
+<H2>Notation Conventions</H2>
+
+<P>Various font and syntax conventions are used in this guide. Examples and
+their meanings and uses are explained below:
+
+<CENTER><TABLE WIDTH="80%">
+<TR>
+ <TH>Example</TH>
+ <TD>&nbsp;&nbsp;&nbsp;</TD>
+ <TH>Description</TH>
+</TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR VALIGN="TOP">
+ <TD><CODE>lpstat</CODE><BR>
+ <CODE>lpstat(1)</CODE></TD>
+
+ <TD>&nbsp;&nbsp;&nbsp;</TD>
+
+ <TD>The names of commands; the first mention of a command or
+ function in a chapter is followed by a manual page section
+ number.</TD>
+</TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR VALIGN="TOP">
+ <TD><VAR>/var</VAR><BR>
+ <VAR>/usr/share/cups/data/testprint.ps</VAR></TD>
+
+ <TD>&nbsp;&nbsp;&nbsp;</TD>
+
+ <TD>File and directory names.</TD>
+</TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR VALIGN="TOP">
+ <TD NOWRAP><TT>Request ID is Printer-123</TT></TD>
+
+ <TD>&nbsp;&nbsp;&nbsp;</TD>
+
+ <TD>Screen output.</TD>
+</TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR VALIGN="TOP">
+ <TD NOWRAP><KBD>lp -d printer filename ENTER</KBD></TD>
+
+ <TD>&nbsp;&nbsp;&nbsp;</TD>
+
+ <TD>Literal user input; special keys like <KBD>ENTER</B></KBD> are
+ in ALL CAPS.</TD>
+</TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR VALIGN="TOP">
+ <TD>12.3</TD>
+
+ <TD>&nbsp;&nbsp;&nbsp;</TD>
+
+ <TD>Numbers in the text are written using the period (.) to indicate
+ the decimal point.</TD>
+</TR>
+</TABLE></CENTER>
+
+<!-- NEED 3in -->
+<H2>Abbreviations</H2>
+
+The following abbreviations are used throughout this manual:
+
+<UL>
+<DL>
+
+ <DT>kb
+ <DD>Kilobytes, or 1024 bytes<BR>&nbsp;
+
+ <DT>Mb
+ <DD>Megabytes, or 1048576 bytes<BR>&nbsp;
+
+ <DT>Gb
+ <DD>Gigabytes, or 1073741824 bytes<BR>&nbsp;
+
+</DL>
+</UL>
+
+<H2>Other References</H2>
+
+<UL>
+<DL>
+
+ <DT>CUPS Software Administrators Manual
+
+ <DD>An administration guide for the CUPS software.<BR>&nbsp;
+
+ <DT>CUPS Software Users Manual
+
+ <DD>An end-user guide for using the CUPS software.<BR>&nbsp;
+
+</DL>
+</UL>
+
+
+<EMBED SRC="printing-overview.shtml">
+
+
+<H1 ALIGN="RIGHT"><A NAME="CUPS_API">2 - The CUPS API</A></H1>
+
+<P>This chapter describes the CUPS Application Programmers Interface ("API").
+
+<H2>The CUPS API Library</H2>
+
+<P>The CUPS library provides a whole collection of interfaces needed to
+support the internal needs of the CUPS software as well as the needs of
+applications, filters, printer drivers, and backends.
+
+<P>Unlike the rest of CUPS, the CUPS API library is provided under the
+GNU Library General Public License. This means that you can use the
+CUPS API library in both proprietary and open-source programs.
+
+<P>Programs that use the CUPS API library typically will include the
+<CODE>&lt;cups/cups.h&gt;</CODE> header file:
+
+<UL><PRE>
+#include &lt;cups/cups.h&gt;
+
+...
+
+jobid = cupsPrintFile("myprinter", "filename.ps", "title",
+ num_options, options);
+</PRE></UL>
+
+<P>Use the <CODE>-lcups</CODE> compiler option when linking to the CUPS API
+library:
+
+<UL><PRE>
+<B>cc -o program program.c -lcups ENTER</B>
+</PRE></UL>
+
+<P>Additional options and libraries may be required depending on the
+operating system and the location of the CUPS API library.
+
+<H3>Detecting the CUPS API Library in GNU Autoconf</H3>
+
+<P>GNU autoconf is a popular configuration tool used by many programs.
+Add the following lines to your <VAR>configure.in</CODE> file to check
+for the CUPS API library in your configuration script:
+
+<UL><PRE>
+AC_CHECK_LIB(socket,socket,
+if test "$uname" != "IRIX"; then
+ LIBS="-lsocket $LIBS"
+else
+ echo "Not using -lsocket since you are running IRIX."
+fi)
+AC_CHECK_LIB(nsl,gethostbyaddr,
+if test "$uname" != "IRIX"; then
+ LIBS="-lnsl $LIBS"
+else
+ echo "Not using -lnsl since you are running IRIX."
+fi)
+
+AC_CHECK_LIB(cups,httpConnect)
+</PRE></UL>
+
+<H2>Printing Services</H2>
+
+<P>The CUPS API library provides some basic printing services for applications
+that need to print files.
+
+<H3>Include Files</H3>
+
+<P>The include file used by all of these functions is
+<CODE>&lt;cups/cups.h&gt;</CODE>:
+
+<UL><PRE>
+#include &lt;cups/cups.h&gt;
+</PRE></UL>
+
+<H3>Printing a File</H3>
+
+<P>The CUPS API provides two functions for printing files. The first is
+<CODE>cupsPrintFile</CODE> which prints a single named file:
+
+<UL><PRE>
+#include &lt;cups/cups.h&gt;
+
+...
+
+int jobid;
+
+...
+
+jobid = cupsPrintFile("<I>name</I>", "<I>filename</I>", "<I>title</I>", 0, NULL);
+</PRE></UL>
+
+<P>The <CODE>name</CODE> string is the name of the printer or class to
+print to. The <CODE>filename</CODE> string is the name of the file to
+print. The <CODE>title</CODE> string is the name of the print job, e.g.
+"Acme Word Document".
+
+<P>The return value is a unique ID number for the print job or 0 if there
+was an error.
+
+<H3>Printing Multiple Files</H3>
+
+<P>The second printing function is <CODE>cupsPrintFiles</CODE>:
+
+<UL><PRE>
+#include &lt;cups/cups.h&gt;
+
+...
+
+int jobid;
+int num_files;
+const char *files[100];
+...
+
+jobid = cupsPrintFiles("name", <I>num_files</I>, <I>files</I>, "title", 0, NULL);
+</PRE></UL>
+
+<P>Instead of passing a filename string as with <CODE>cupsPrintFile()</CODE>,
+you pass a file count (<CODE>num_files</CODE>) and filename pointer array
+(<CODE>files</CODE>) for each file that you want to print.
+
+<P>As with <CODE>cupsPrintFile()</CODE>, the return value is a unique ID for
+the print job.
+
+<H3>Cancelling Jobs</H3>
+
+<P>The <CODE>cupsCancelJob()</CODE> function cancels a queued print job:
+
+<UL><PRE>
+#include &lt;cups/cups.h&gt;
+
+...
+
+int jobid;
+int status;
+...
+
+status = cupsCancelJob("<I>name</I>", <I>jobid</I>);
+</PRE></UL>
+
+<P>The <CODE>name</CODE> string specifies the destination and is used
+to determine the server to send the request to. The <CODE>jobid</CODE>
+value is the integer returned from a previous <CODE>cupsPrintFile()</CODE>
+or <CODE>cupsPrintFiles()</CODE> call.
+
+<P><CODE>cupsCancelJob()</CODE> returns <CODE>1</CODE> if the job was
+successfully cancelled and <CODE>0</CODE> if there was an error.
+
+<H3>Getting the Available Printers and Classes</H3>
+
+<P>The <CODE>cupsGetDests()</CODE> function can be used to get a list
+of the available printers, classes, and instances that a user has defined:
+
+<UL><PRE>
+#include &lt;cups/cups.h&gt;
+
+...
+
+int num_dests;
+cups_dest_t *dests;
+
+...
+
+num_dests = cupsGetDests(&amp;dests);
+</PRE></UL>
+
+<P>Each destination is stored in a <CODE>cups_dest_t</CODE> structure which
+defines the printer or class name, the instance name (if any), if it is the
+default destination, and the default options the user has defined for the
+destination:
+
+<UL><PRE>
+typedef struct /**** Destination ****/
+{
+ char *name, /* Printer or class name */
+ *instance; /* Local instance name or NULL */
+ int is_default; /* Is this printer the default? */
+ int num_options; /* Number of options */
+ cups_option_t *options; /* Options */
+} cups_dest_t;
+</PRE></UL>
+
+<P>The destinations are sorted by name and instance for your convenience.
+Once you have the list of available destinations, you can lookup a specific
+destination using the <CODE>cupsGetDest()</CODE> function:
+
+<UL><PRE>
+#include &lt;cups/cups.h&gt;
+
+...
+
+int num_dests;
+cups_dest_t *dests;
+cups_dest_t *mydest;
+
+...
+
+mydest = cupsGetDest("<I>name</I>", "<I>instance</I>", num_dests, dests);
+</PRE></UL>
+
+<P>The <CODE>name</CODE> string is the printer or class name. You can pass
+a value of <CODE>NULL</CODE> to get the default destination.
+
+<P>The <CODE>instance</CODE> string is the user-defined instance name. Pass
+<CODE>NULL</CODE> to select the default instance, e.g. "name" instead of
+"name/instance".
+
+<H3>Printing with Options</H3>
+
+<P>All of the previous printing examples have passed <CODE>0</CODE> and
+<CODE>NULL</CODE> for the last two arguments to the <CODE>cupsPrintFile()</CODE>
+and <CODE>cupsPrintFiles()</CODE> functions. These last two arguments are the
+number of options and a pointer to the option array:
+
+<UL><PRE>
+int cupsPrintFile(const char *name, const char *filename, const char *title,
+ int num_options, cups_option_t *options);
+int cupsPrintFiles(const char *name, int num_files, const char **files,
+ const char *title, int num_options,
+ cups_option_t *options);
+</UL></PRE>
+
+<P>The <CODE>cups_option_t</CODE> structure holds each option and its value.
+These are converted as needed and passed to the CUPS server when printing a
+file.
+
+<P>The simplest way of handling options is to use the <CODE>num_options</CODE>
+and <CODE>options</CODE> members of the <CODE>cups_dest_t</CODE>
+structure described earlier:
+
+<UL><PRE>
+#include &lt;cups/cups.h&gt;
+
+...
+
+int jobid;
+int num_dests;
+cups_dest_t *dests;
+cups_dest_t *mydest;
+
+...
+
+mydest = cupsGetDest("<I>name</I>", "<I>instance</I>", num_dests, dests);
+
+jobid = cupsPrintFile(mydest-&gt;name, "filename", "title",
+ mydest-&gt;num_options, mydest-&gt;options);
+</PRE></UL>
+
+<P>This effectively uses the options a user has previous selected without a
+lot of code.
+
+<H3>Setting Printer Options</H3>
+
+<P>Options can also be set by your program using the <CODE>cupsAddOption()</CODE>
+function:
+
+<UL><PRE>
+#include &lt;cups/cups.h&gt;
+
+...
+
+int num_options;
+cups_option_t *options;
+
+...
+
+num_options = 0;
+options = NULL;
+
+...
+
+num_options = cupsAddOption("<I>name</I>", "<I>value</I>", num_options, &amp;options);
+num_options = cupsAddOption("<I>name</I>", "<I>value</I>", num_options, &amp;options);
+num_options = cupsAddOption("<I>name</I>", "<I>value</I>", num_options, &amp;options);
+num_options = cupsAddOption("<I>name</I>", "<I>value</I>", num_options, &amp;options);
+</PRE></UL>
+
+<P>The <CODE>name</CODE> string is the name of the option, and the
+<CODE>value</CODE> string is the value for that option.
+
+<P>Each call to <CODE>cupsAddOption()</CODE> returns the new number of
+options. Since adding two options with the same name overwrites the
+first value with the second, do not assume that calling
+<CODE>cupsAddOptions()</CODE> 20 times will result in 20 options.
+
+<P>Call <CODE>cupsFreeOptions</CODE> once you are done using the options:
+
+<UL><PRE>
+#include &lt;cups/cups.h&gt;
+
+...
+
+int num_options;
+cups_option_t *options;
+
+...
+
+cupsFreeOptions(num_options, options);
+</PRE></UL>
+
+<H3>Getting Errors</H3>
+
+<P>If any of the CUPS API printing functions returns an error, the reason for
+that error can be found by calling <CODE>cupsLastError()</CODE> and
+<CODE>cupsErrorString()</CODE>. <CODE>cupsLastError()</CODE> returns the
+last IPP error code that was encountered. <CODE>cupsErrorString()</CODE>
+converts the error code to a localized message string suitable for
+presentation to the user:
+
+<UL><PRE>
+#include &lt;cups/cups.h&gt;
+
+...
+
+int jobid;
+
+...
+
+if (jobid == 0)
+ puts(cupsErrorString(cupsLastError()));
+</PRE></UL>
+
+<H3>Passwords and Authentication</H3>
+
+<P>CUPS supports authentication of any request, including
+submission of print jobs. The default mechanism for getting the
+username and password is to use the login user and a password
+from the console.
+
+<P>To support other types of applications, in particular
+Graphical User Interfaces ("GUIs"), the CUPS API provides
+functions to set the default username and to register a callback
+function that returns a password string.
+
+<P>The <A HREF="#cupsSetPasswordCB"><CODE>cupsSetPasswordCB()</CODE></A>
+function is used to set a password callback in your program. Only one
+function can be used at any time.
+
+<P>The <A HREF="#cupsSetUser"><CODE>cupsSetUser()</CODE></A> function sets
+the current username for authentication. This function can be called by
+your password callback function to change the current username as needed.
+
+<P>The following example shows a simple password callback that gets a
+username and password from the user:
+
+<UL><PRE>
+#include &lt;cups/cups.h&gt;
+
+const char *
+my_password_cb(const char *prompt)
+{
+ char user[65];
+
+
+ puts(prompt);
+
+ /* Get a username from the user */
+ printf("Username: ");
+ if (fgets(user, sizeof(user), stdin) == NULL)
+ return (NULL);
+
+ /* Strip the newline from the string and set the user */
+ user[strlen(user) - 1] = '\0';
+
+ cupsSetUser(user);
+
+ /* Use getpass() to ask for the password... */
+ return (getpass("Password: "));
+}
+
+...
+
+cupsSetPasswordCB(my_password_cb);
+</PRE></UL>
+
+<P>Similarly, a GUI interface could display the prompt string in a
+window with input fields for the username and password. The username
+should probably default to the value of
+<A HREF="#cupsUser"><CODE>cupsUser()</CODE></A> to make things easier
+on the user.
+
+<H2>PPD Services</H2>
+
+<P>CUPS includes functions to access and manipulate PostScript Printer
+Description ("PPD") files that are used with the printer drivers in CUPS.
+
+<P>Each PPD file enumerates the available features provided by a
+printer, including conflict information for specific options (e.g.
+can't duplex output on envelopes.)
+
+<H3>Include Files</H3>
+
+<P>Include the <CODE>&lt;cups/ppd.h&gt;</CODE> header file to use the PPD
+functions:
+
+<UL><PRE>
+#include &lt;cups/ppd.h&gt;
+</PRE></UL>
+
+<P>This header file is also included by the
+<CODE>&lt;cups/cups.h&gt;</CODE> header file.
+
+<H3>Getting a PPD File for a Printer</H3>
+
+<P>The <CODE>cupsGetPPD()</CODE> function retrieves the PPD file for the
+named printer or class:
+
+<UL><PRE>
+#include &lt;cups/cups.h&gt;
+
+...
+
+const char *filename;
+
+filename = cupsGetPPD("<I>name</I>");
+</PRE></UL>
+
+<P>The <CODE>name</CODE> string is the name of the printer or class, including
+the remote server name as appropriate (e.g. "printer@server".)
+
+<P>The return value is a pointer to a filename in static storage; this value
+is overwritten with each call to <CODE>cupsGetPPD()</CODE>. If the printer
+or class does not exist, a <CODE>NULL</CODE> pointer will be returned.
+
+<H3>Loading a PPD File</H3>
+
+<P>The <CODE>ppdOpenFile()</CODE> function "opens" a PPD file and loads it
+into memory:
+
+<UL><PRE>
+#include &lt;cups/ppd.h&gt;
+
+...
+
+ppd_file_t *ppd;
+
+ppd = ppdOpenFile("<I>filename</I>");
+</PRE></UL>
+
+<P>The <CODE>filename</CODE> string is the name of the file to load, such as
+the value returned by the <CODE>cupsGetPPD()</CODE> function.
+
+<P>The return value is a pointer to a structure describing the contents of the
+PPD file or NULL if the PPD file could not be read.
+
+<H3>Freeing PPD File Information</H3>
+
+<P>Once you are done using a PPD file, call the <CODE>ppdClose()</CODE> function
+to free all memory that has been used:
+
+<UL><PRE>
+#include &lt;cups/ppd.h&gt;
+
+...
+
+ppd_file_t *ppd;
+
+...
+
+ppdClose(ppd);
+</PRE></UL>
+
+<H3>The PPD File Structure</H3>
+
+<P>Each PPD file contains a number of capability attributes, printer options,
+and conflict definitions. The page size options also include the physical
+margins for the printer and the minimum and maximum sizes for the printer.
+All of this information is stored in the <CODE>ppd_file_t</CODE> structure.
+
+<H4>Capabilities</H4>
+
+<P>Each PPD file contains a number of informational attributes that
+describe the capabilities of the printer. These are provided in the
+<CODE>ppd_file_t</CODE> structure in the following members:
+
+<CENTER><TABLE WIDTH="80%" BORDER="1">
+<TR>
+ <TH>Member</TH>
+ <TH>Type</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD><CODE>accurate_screens</CODE></TD>
+ <TD><CODE>int</CODE></TD>
+ <TD>1 = supports accurate screens</TD>
+</TR>
+<TR>
+ <TD><CODE>color_device</CODE></TD>
+ <TD><CODE>int</CODE></TD>
+ <TD>1 = color device</TD>
+</TR>
+<TR>
+ <TD><CODE>colorspace</CODE></TD>
+ <TD><CODE>ppd_cs_t</CODE></TD>
+ <TD>Default colorspace: PPD_CS_CMYK, PPD_CS_CMY, PPD_CS_GRAY,
+ PPD_CS_RGB, PPD_CS_RGBK, PPD_CS_N</TD>
+</TR>
+<TR>
+ <TD><CODE>contone_only</CODE></TD>
+ <TD><CODE>int</CODE></TD>
+ <TD>1 = printer is continuous tone only</TD>
+</TR>
+<TR>
+ <TD><CODE>num_emulations<BR>
+ emulations</CODE></TD>
+ <TD><CODE>int<BR>
+ ppd_emul_t *</CODE></TD>
+ <TD>Emulations supported by the printer</TD>
+</TR>
+<TR>
+ <TD><CODE>flip_duplex</CODE></TD>
+ <TD><CODE>int</CODE></TD>
+ <TD>1 = need to flip odd pages when duplexing</TD>
+</TR>
+<TR>
+ <TD><CODE>num_fonts<BR>
+ fonts</CODE></TD>
+ <TD><CODE>int<BR>
+ char **</CODE></TD>
+ <TD>The fonts available on the printer.</TD>
+</TR>
+<TR>
+ <TD><CODE>jcl_begin<BR>
+ jcl_ps<BR>
+ jcl_end</CODE></TD>
+ <TD><CODE>char *</CODE></TD>
+ <TD>Job Control Language commands for PostScript output</TD>
+</TR>
+<TR>
+ <TD><CODE>landscape</CODE></TD>
+ <TD><CODE>int</CODE></TD>
+ <TD>Landscape orientation, -90 or 90 degrees</TD>
+</TR>
+<TR>
+ <TD><CODE>lang_encoding</CODE></TD>
+ <TD><CODE>char *</CODE></TD>
+ <TD>The character used for the option strings</TD>
+</TR>
+<TR>
+ <TD><CODE>lang_version</CODE></TD>
+ <TD><CODE>char *</CODE></TD>
+ <TD>The language used for the options strings (English, French, etc.)</TD>
+</TR>
+<TR>
+ <TD><CODE>language_level</CODE></TD>
+ <TD><CODE>int</CODE></TD>
+ <TD>PostScript language level, 1 to 3</TD>
+</TR>
+<TR>
+ <TD><CODE>manual_copies</CODE></TD>
+ <TD><CODE>int</CODE></TD>
+ <TD>1 = Copies are done manually</TD>
+</TR>
+<TR>
+ <TD><CODE>model_number</CODE></TD>
+ <TD><CODE>int</CODE></TD>
+ <TD>Driver-specific model number.</TD>
+</TR>
+<TR>
+ <TD><CODE>patches</CODE></TD>
+ <TD><CODE>char *</CODE></TD>
+ <TD>Patch commands to send to the printer</TD>
+</TR>
+<TR>
+ <TD><CODE>manufacturer</CODE></TD>
+ <TD><CODE>char *</CODE></TD>
+ <TD>The Manufacturer attribute from the PPD file, if any</TD>
+</TR>
+<TR>
+ <TD><CODE>modelname</CODE></TD>
+ <TD><CODE>char *</CODE></TD>
+ <TD>The ModelName attribute from the PPD file</TD>
+</TR>
+<TR>
+ <TD><CODE>nickname</CODE></TD>
+ <TD><CODE>char *</CODE></TD>
+ <TD>The NickName attribute from the PPD file, if any</TD>
+</TR>
+<TR>
+ <TD><CODE>product</CODE></TD>
+ <TD><CODE>char *</CODE></TD>
+ <TD>The Product attribute from the PPD file, if any</TD>
+</TR>
+<TR>
+ <TD><CODE>shortnickname</CODE></TD>
+ <TD><CODE>char *</CODE></TD>
+ <TD>The ShortNickName attribute from the PPD file, if any</TD>
+</TR>
+<TR>
+ <TD><CODE>throughput</CODE></TD>
+ <TD><CODE>int</CODE></TD>
+ <TD>Number of pages per minute</TD>
+</TR>
+<TR>
+ <TD><CODE>ttrasterizer</CODE></TD>
+ <TD><CODE>char *</CODE></TD>
+ <TD>The TruType font rasterizer (Type42)</TD>
+</TR>
+<TR>
+ <TD><CODE>variable_sizes</CODE></TD>
+ <TD><CODE>int</CODE></TD>
+ <TD>1 = supports variable sizes</TD>
+</TR>
+</TABLE></CENTER>
+
+<H4>Options and Groups</H4>
+
+<P>PPD files support multiple options, which are stored in
+<CODE>ppd_option_t</CODE> and <CODE>ppd_choice_t</CODE> structures by
+the PPD functions.
+
+<P>Each option in turn is associated with a group
+stored in the <CODE>ppd_group_t</CODE> structure. Groups can be
+specified in the PPD file; if an option is not associated with a group
+then it is put in a "General" or "Extra" group depending on the option.
+
+<P>Groups can also have sub-groups; CUPS currently limits the depth of
+sub-groups to 1 level to reduce programming complexity.
+
+<H4>Conflicts</H4>
+
+<P>PPD files support specification of conflict conditions between
+different options. Conflicts are stored in <CODE>ppd_conflict_t</CODE>
+structures which specify the options that conflict with each other.
+
+<H4>Page Sizes</H4>
+
+<P>PPD files specify all of the available pages sizes and the physical
+margins associated with them. These sizes are stored in
+<CODE>ppd_size_t</CODE> structures and are available in the
+<CODE>num_sizes</CODE> and <CODE>sizes</CODE> members of the
+<CODE>ppd_file_t</CODE> structure. You can lookup a particular page size
+with the <CODE>ppdPageWidth()</CODE>, <CODE>ppdPageLength()</CODE>, and
+<CODE>ppdPageSize()</CODE> functions:
+
+<UL><PRE>
+#include &lt;cups/ppd.h&gt;
+
+...
+
+ppd_file_t *ppd;
+ppd_size_t *size;
+float width;
+float length;
+
+...
+
+size = ppdPageSize(ppd, "<I>size</I>");
+width = ppdPageWidth(ppd, "<I>size</I>");
+length = ppdPageLength(ppd, "<I>size</I>");
+</PRE></UL>
+
+<P>The <CODE>size</CODE> string is the named page size option. The
+width and length are in points; there are 72 points per inch. The
+<CODE>ppd_size_t</CODE> structure contains the width, length, and
+margin information:
+
+<UL><PRE>
+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;
+</PRE></UL>
+
+<H4>Custom Page Sizes</H4>
+
+<P>Besides the standard page sizes listed in a PPD file, some printers
+support variable or custom page sizes. If <CODE>variables_sizes</CODE>
+is non-zero, the <CODE>custom_min</CODE>, <CODE>custom_max</CODE>, and
+<CODE>custom_margins</CODE> members of the <CODE>ppd_file_t</CODE>
+structure define the limits of the variable sizes.
+
+<P>To get the resulting media size, use a page size string of
+<CODE>Custom.<I>width</I>x<I>length</I></CODE>, where <CODE>width</CODE>
+and <CODE>length</CODE> are integer values in points:
+
+<UL><PRE>
+Custom.612x792 [8.5 inches wide, 11 inches long]
+Custom.1224x792 [17 inches wide, 11 inches long]
+</PRE></UL>
+
+<H3>Marking Options</H3>
+
+<P>Before marking any user-defined options, call the <CODE>ppdMarkDefaults()</CODE>
+function to mark the default options from the PPD file:
+
+<UL><PRE>
+#include &lt;cups/ppd.h&gt;
+
+...
+
+ppd_file_t *ppd;
+
+...
+
+ppdMarkDefaults(ppd);
+</PRE></UL>
+
+<P>Then call the <CODE>ppdMarkOption()</CODE> function to mark individual
+options:
+
+<UL><PRE>
+#include &lt;cups/ppd.h&gt;
+
+...
+
+ppd_file_t *ppd;
+int conflicts;
+
+...
+
+conflicts = ppdMarkOption(ppd, "<I>name</I>", "<I>value</I>");
+</PRE></UL>
+
+<P>The <CODE>name</CODE> and <CODE>value</CODE> strings choose a
+particular option and choice, respectively. The return value is 0
+if there are not conflicts created by the selection.
+
+<P>CUPS also provides a convenience function for marking all options
+in the <CODE>cups_option_t</CODE> structure:
+
+<UL><PRE>
+#include &lt;cups/cups.h&gt;
+
+...
+
+ppd_file_t *ppd;
+int num_options;
+cups_option_t *options;
+int conflicts;
+
+...
+
+conflicts = cupsMarkOptions(ppd, num_options, options);
+</PRE></UL>
+
+<P>The <CODE>cupsMarkOptions()</CODE> function also handles mapping the
+IPP job template attributes to PPD options. The return value is the number
+of conflicts present.
+
+<H3>Checking for Conflicts</H3>
+
+<P>The <CODE>ppdMarkOption()</CODE> and <CODE>cupsMarkOptions()</CODE>
+functions return the number of conflicts with the currently marked options.
+
+<P>Call the <CODE>ppdConflicts()</CODE> function to get the number of
+conflicts after you have marked all of the options:
+
+<UL><PRE>
+#include &lt;cups/cups.h&gt;
+
+...
+
+ppd_file_t *ppd;
+int conflicts;
+
+...
+
+conflicts = ppdConflicts(ppd);
+</PRE></UL>
+
+<P>The return value is the number of conflicting options, or 0 if there
+are no conflicts.
+
+
+<H1 ALIGN="RIGHT"><A NAME="WRITING_FILTERS">3 - Writing Filters</A></H1>
+
+<P>This chapter describes how to write a file filter for CUPS.
+
+<H2>Overview</H2>
+
+<P>File filters are programs that convert from one or more MIME types to
+another type. Filters use a common command-line and environment interface
+that allows them to be joined as needed to print files to any type of
+printer.
+
+<H3>Security Considerations</H3>
+
+<P>Filters are normally run as a non-priviledged user, so the major
+security consideration is resource utilization - filters should not
+depend on unlimited amounts of memory and disk space.
+
+<H3>Users and Groups</H3>
+
+<P>The default CUPS configuration runs filters as user "lp" and group "other".
+
+<H3>Temporary Files</H3>
+
+<P>Temporary files should be created in the directory specified by the
+"TMPDIR" environment variable. The
+<A HREF="#cupsTempFile"><CODE>cupsTempFile()</CODE></A> function can be
+used to safely choose temporary files in this directory.
+
+<H3>Sending Messages to the User</H3>
+
+<P>The CUPS scheduler collects messages sent to the standard error file
+by the filter. These messages are relayed to the user based upon the
+scheduler <CODE>LogLevel</CODE> directive.
+
+<P>The type of message is determined by an initial prefix sent on each
+line:
+
+<UL>
+
+ <LI><CODE>DEBUG:</CODE> - a debug message
+
+ <LI><CODE>INFO:</CODE> - an informational message
+
+ <LI><CODE>WARNING:</CODE> - a warning message
+
+ <LI><CODE>ERROR:</CODE> - an error message
+
+ <LI><CODE>PAGE:</CODE> - a page accounting message
+
+</UL>
+
+<P>If the line of text does not begin with any of the above prefixes, it
+is treated as a debug message. Text following the prefix is copied to the
+<CODE>printer-state-message</CODE> attribute for the printer, and also
+added to the <VAR>error_log</VAR> unless it is an informational or page
+accounting message.
+
+<H3>Page Accounting</H3>
+
+<P>Page accounting messages are used to inform the server when one or more
+pages are printed. Each line has the form:
+
+<UL><PRE>
+PAGE: page-number copy-count
+</PRE></UL>
+
+<P>The <I>page-number</I> field is the current page number, starting at 1.
+The <I>copy-count</I> field specifies the number of copies of that page
+that was produced.
+
+<P>Page account messages are added to the <VAR>page_log</VAR> file and
+cause the <CODE>job-sheets-completed</CODE> attribute to be updated for
+the job.
+
+<H3>Command-Line Arguments</H3>
+
+<P>Every filter accepts exactly 6 or 7 command-line arguments:
+
+<UL><PRE>
+printer job user title copies options [filename]
+</PRE>
+
+ <LI><CODE>printer</CODE> - The name of the printer queue (normally
+ this is the name of the program being run)
+
+ <LI><CODE>job</CODE> - The numeric job ID for the job being
+ printed
+
+ <LI><CODE>user</CODE> - The string from the
+ <CODE>originating-user-name</CODE> attribute
+
+ <LI><CODE>title</CODE> - The string from the
+ <CODE>job-name</CODE> attribute
+
+ <LI><CODE>copies</CODE> - The numeric value from the
+ <CODE>number-copies</CODE> attribute
+
+ <LI><CODE>options</CODE> - String representations of the
+ job template attributes, separated by spaces. Boolean attributes
+ are provided as "name" for true values and "noname" for false
+ values. All other attributes are provided as "name=value" for
+ single-valued attributes and "name=value1,value2,...,valueN" for
+ set attributes
+
+ <LI><CODE>filename</CODE> - The request file
+
+</UL>
+
+<P>The <I>filename</I> argument is only provided to the first filter in the
+chain; all filters <B>must</B> be prepared to read the print file from
+the standard input if the <I>filename</I> argument is omitted.
+
+<H3>Copy Generation</H3>
+
+<P>The <I>copies</I> argument specifies the number of copies to produce
+of the input file. In general, you should only generate copies if the
+<I>filename</I> argument is supplied. The only exception to this are
+filters that produce device-independent PostScript output (without any
+printer commands from the printer's PPD file), since the PostScript
+filter <CODE>pstops</CODE> is responsible for copy generation.
+
+<H3>Environment Variables</H3>
+
+<P>Every filter receives a fixed set of environment variables that can
+be used by the filter:
+
+<UL>
+
+ <LI><CODE>CHARSET</CODE> - The character set used by the client for
+ this print file
+
+ <LI><CODE>CONTENT_TYPE</CODE> - The original document type, such as
+ "application/postscript"
+
+ <LI><CODE>CUPS_DATADIR</CODE> - The location of CUPS data files
+
+ <LI><CODE>CUPS_SERVERROOT</CODE> - The location of CUPS configuration
+ files
+
+ <LI><CODE>DEVICE_URI</CODE> - The output device URI
+
+ <LI><CODE>LANG</CODE> - The language used by the client for
+ this print file
+
+ <LI><CODE>PATH</CODE> - The execution path exported to the filter
+
+ <LI><CODE>PPD</CODE> - The full filename of the printer's PPD file
+
+ <LI><CODE>PRINTER</CODE> - The name of the printer queue
+
+ <LI><CODE>RIP_CACHE</CODE> - The maximum amount of memory each filter
+ should use
+
+ <LI><CODE>SOFTWARE</CODE> - The name of the CUPS software, typically
+ "CUPS/1.1"
+
+ <LI><CODE>TZ</CODE> - The local timezone
+
+ <LI><CODE>USER</CODE> - The name of the current user
+
+</UL>
+
+<H2>Dissecting the HP-GL/2 Filter</H2>
+
+<P>The HP-GL/2 filter (<CODE>hpgltops</CODE>) provided with CUPS is a
+complex program that converts HP-GL/2 files into device-independent PostScript
+output. Since it produces device-independent PostScript output, it does not
+need to handle copy generation or writing printer options from the printer's
+PPD file.
+
+<H3>Initializing the Filter</H3>
+
+<P>The first task of any filter is to ensure that the correct number of
+command-line arguments are present:
+
+<UL><PRE>
+if (argc &lt; 6 || argc > 7)
+{
+ fputs("ERROR: hpgltops job-id user title copies options [file]\n", stderr);
+ return (1);
+}
+</PRE></UL>
+
+<P>After this you open the print file or read from the standard input
+as needed:
+
+<UL><PRE>
+FILE *fp;
+
+/*
+ * 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);
+ }
+}
+</PRE></UL>
+
+<P>Once the print file has been opened, options can be processed using
+the <A HREF="#cupsParseOptions"><CODE>cupsParseOptions()</CODE></A> and
+<A HREF="#cupsGetOption"><CODE>cupsGetOption()</CODE></A> functions:
+
+<UL><PRE>
+int num_options;
+cups_option_t *options;
+const char *val;
+
+/*
+ * Process command-line options and write the prolog...
+ */
+
+options = NULL;
+num_options = cupsParseOptions(argv[5], 0, &options);
+
+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)atoi(val) * 0.001f;
+</PRE></UL>
+
+<P>After the options have been processed, the filter writes PostScript code
+to the standard output based on the print file, closes the print file (as
+needed), and returns 0 to the scheduler.
+
+<H2>PostScript Output</H2>
+
+<P>Filters that produce PostScript output must generate output conforming
+to the Adobe Document Structuring Conventions, 3.0. In general this means
+the beginning of each file must begin with:
+
+<UL><PRE>
+%!PS-Adobe-3.0
+%%BoundingBox: left bottom right top
+%%Pages: (atend)
+%%EndComments
+</PRE></UL>
+
+<P>The <I>left</I>, <I>bottom</I>, <I>right</I>, and <I>top</I> values
+are integers in points from the lower-lefthand corner of the page.
+
+<P>Pages must be surrounded by:
+
+<UL><PRE>
+%%Page: number number
+gsave
+...
+grestore
+showpage
+</PRE></UL>
+
+<P>And the end of each file must contain:
+
+<UL><PRE>
+%%Trailer
+%%Pages: number-pages
+%%EOF
+</PRE></UL>
+
+<P>These comments allow the PostScript filter to correctly perform page
+accounting, copy generation, N-up printing, and so forth.
+
+<H1 ALIGN="RIGHT"><A NAME="WRITING_DRIVERS">4 - Writing Printer Drivers</A></H1>
+
+<P>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.
+
+<H2>Overview</H2>
+
+<P>Raster printers utilitize PPD files that specify one or more
+device-specific filters that handle converting print files for the
+printer. The simplest raster printer drivers provide a single filter
+that converts CUPS raster data to the printer's native format.
+
+<H3>CUPS Raster Data</H3>
+
+<P>CUPS raster data (<CODE>application/vnd.cups-raster</CODE>) consists of
+a stream of raster page descriptions produced by one of the RIP filters,
+such as <CODE>pstoraster</CODE> or <CODE>imagetoraster</CODE>.
+
+<P>Each page of data begins with a page dictionary structure called
+<A HREF="#cups_raster_header_t"><CODE>cups_raster_header_t</CODE></A>. This
+structure contains the colorspace, bits per color, media size, media type,
+hardware resolution, and so forth.
+
+<P>After the page dictionary comes the page data which is a full-resolution,
+uncompressed bitmap representing the page in the printer's output colorspace.
+
+<H3>Page Accounting</H3>
+
+<P>Printer drivers must handle all page accounting. This means they must
+send "PAGE:" messages to the standard error file for each page (and in many
+cases, copy) sent to the printer.
+
+<H3>Color Management</H3>
+
+<P>Printer drivers can implement their color management via the
+<CODE>cupsColorProfile</CODE> attributes in the PPD file or internally
+in the driver from a device-independent colorspace. In general, color
+management performed by the RIP filters is more efficient than that
+performed inside printer drivers.
+
+<P>For example, the <CODE>pstoraster</CODE> filter often only has to
+perform a color conversion once each time the color is used for
+multiple output pixels, while the raster filter must convert every
+pixel on the page.
+
+<H3>Device and Bitmap Variables</H3>
+
+<P>Besides the standard PostScript page device dictionary variables defined
+in the Adobe PostScript Level 3 reference manual, the CUPS filters support
+additional variables that are passed in the page device dictionary header for
+the page and in some cases control the type of raster data that is generated:
+
+<CENTER><TABLE WIDTH="90%" BORDER="1">
+<TR>
+ <TH>Variable</TH>
+ <TH>Type</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>cupsWidth</TD>
+ <TD>read-only integer</TD>
+ <TD>Width of bitmap in pixels</TD>
+</TR>
+<TR>
+ <TD>cupsHeight</TD>
+ <TD>read-only integer </TD>
+ <TD>Height of bitmap in pixels</TD>
+</TR>
+<TR>
+ <TD>cupsMediaType</TD>
+ <TD>read-write integer</TD>
+ <TD>Device-specific media type code</TD>
+</TR>
+<TR>
+ <TD>cupsBitsPerColor</TD>
+ <TD>read-write integer</TD>
+ <TD>Number of bits per color; 1, 2, 4, and 8 are currently
+ supported</TD>
+</TR>
+<TR>
+ <TD>cupsBitsPerPixel</TD>
+ <TD>read-only integer </TD>
+ <TD>Number of bits per pixel; 1 to 32</TD>
+</TR>
+<TR>
+ <TD>cupsBytesPerLine</TD>
+ <TD>read-only integer</TD>
+ <TD>Number of bytes per line of raster graphics</TD>
+</TR>
+<TR>
+ <TD>cupsColorOrder</TD>
+ <TD>read-write enum</TD>
+ <TD>The order of color values in the bitmap:
+ <UL>
+ <LI><CODE>CUPS_ORDER_CHUNKED</CODE> - CMYK&nbsp;CMYK&nbsp;CMYK
+ <LI><CODE>CUPS_ORDER_BANDED</CODE> - CCC&nbsp;MMM&nbsp;YYY&nbsp;KKK
+ <LI><CODE>CUPS_ORDER_PLANAR</CODE> - CCC&nbsp;...&nbsp;MMM&nbsp;...&nbsp;YYY&nbsp;...&nbsp;KKK&nbsp;...
+ </UL>
+ </TD>
+</TR>
+<TR>
+ <TD>cupsColorSpace</TD>
+ <TD>read-write enum</TD>
+ <TD>The colorspace of the bitmap:
+ <UL>
+ <LI><CODE>CUPS_CSPACE_W</CODE> - White (luminance)
+ <LI><CODE>CUPS_CSPACE_RGB</CODE> - Red, green, blue
+ <LI><CODE>CUPS_CSPACE_RGBA</CODE> - Red, green, blue, alpha
+ <LI><CODE>CUPS_CSPACE_K</CODE> - Black
+ <LI><CODE>CUPS_CSPACE_CMY</CODE> - Cyan, magenta, yellow
+ <LI><CODE>CUPS_CSPACE_YMC</CODE> - Yellow, magenta, cyan
+ <LI><CODE>CUPS_CSPACE_CMYK</CODE> - Cyan, magenta, yellow, black
+ <LI><CODE>CUPS_CSPACE_YMCK</CODE> - Yellow, magenta, cyan, black
+ <LI><CODE>CUPS_CSPACE_KCMY</CODE> - Black, cyan, magenta, yellow
+ <LI><CODE>CUPS_CSPACE_KCMYcm</CODE> - Black, cyan, magenta, yellow,
+ light cyan, light magenta
+ <LI><CODE>CUPS_CSPACE_GMCK</CODE> - Metallic yellow (gold), metallic magenta,
+ metallic cyan, black
+ <LI><CODE>CUPS_CSPACE_GMCS</CODE> - Metallic yellow (gold), metallic magenta,
+ metallic cyan, metallic grey (silver)
+ <LI><CODE>CUPS_CSPACE_WHITE</CODE> - White pigment (black as white pigment)
+ <LI><CODE>CUPS_CSPACE_GOLD</CODE> - Gold foil (black as gold foil)
+ <LI><CODE>CUPS_CSPACE_SILVER</CODE> - Silver foil (black as silver foil)
+ </UL>
+ </TD>
+</TR>
+<TR>
+ <TD>cupsCompression</TD>
+ <TD>read-write integer</TD>
+ <TD>Device-specific compression type code</TD>
+</TR>
+<TR>
+ <TD>cupsRowCount</TD>
+ <TD>read-write integer</TD>
+ <TD>Device-specific row count value</TD>
+</TR>
+<TR>
+ <TD>cupsRowFeed</TD>
+ <TD>read-write integer</TD>
+ <TD>Device-specific row feed value</TD>
+</TR>
+<TR>
+ <TD>cupsRowStep</TD>
+ <TD>read-write integer</TD>
+ <TD>Device-specific row step value</TD>
+</TR>
+</TABLE></CENTER>
+
+<P>Bitmaps with a colorspace of CUPS_CSPACE_KCMYcm and more than 1 bit per
+color are transmitted to the raster driver in KCMY colorspace; the driver
+is responsible for producing the correct separation of normal and light
+cyan and magenta inks.
+
+<H2>Dissecting the HP-PCL Driver</H2>
+
+<P>The HP-PCL driver provided with CUPS (<CODE>rastertohp</CODE>) converts
+bitmap data from the raster filters into HP-PCL commands for most
+PCL-compatible printers. The actual format of the raster data is controlled
+by the PPD file being used - <VAR>deskjet.ppd</VAR> or <VAR>laserjet.ppd</VAR>.
+
+<H3>PPD Files</H3>
+
+<P>PPD files play an important part of all raster printer drivers. Options
+defined in the PPD file contain PostScript commands that control the raster
+data that is sent to the printer driver.
+
+<P>A typical CUPS printer driver will include <CODE>ColorModel</CODE>,
+<CODE>InputSlot</CODE>, <CODE>PageSize</CODE>, <CODE>PageRegion</CODE>,
+and <CODE>Resolution</CODE> options. Each option is shown using the
+standard PPD format:
+
+<UL><PRE>
+*OpenUI *PageSize/Media Size: PickOne
+*OrderDependency: 10 AnySetup *PageSize
+*DefaultPageSize: Letter
+*PageSize Letter/US Letter: "&lt;&lt;
+/PageSize [612 792]
+/ImagingBBox null
+>> setpagedevice"
+*End
+*PageSize Legal/US Legal: "&lt;&lt;
+/PageSize [612 1008]
+/ImagingBBox null
+>> setpagedevice"
+*End
+*PageSize A4/A4: "&lt;&lt;
+/PageSize [595 842]
+/ImagingBBox null
+>> setpagedevice"
+*End
+*CloseUI: *PageSize
+</UL></PRE>
+
+<P>The <CODE>OpenUI</CODE> keyword specifies the new option. The first
+name is the option with an asterisk (*) in front of it. The first name is
+usually followed by a slash (/) and a human-readable version of the
+option name.
+
+<P>Every option <B>must</B> have a default value, specified using the
+<CODE>Default<I>Option</I></CODE> keyword.
+
+<P>Each option begins with the option name followed by the computer and
+human-readable values. The PostScript commands follow these inside double
+quotes. PostScript commands can be provided on a single line:
+
+<UL><PRE>
+*PageSize A4/A4: "&lt;&lt;/PageSize[595 842]/ImagingBBox null>> setpagedevice"
+</PRE></UL>
+
+<P>or broken down on separate lines using the <CODE>End</CODE> keyword to
+terminate them:
+
+<UL><PRE>
+*PageSize A4/A4: "&lt;&lt;
+/PageSize [595 842]
+/ImagingBBox null
+>> setpagedevice"
+*End
+</PRE></UL>
+
+<P>The choice of the two formats is usually esthetic. However, each line in
+a PPD file must not exceed 255 characters, so if your PostScript commands are
+long you may need to break them up on separate lines.
+
+<H3>Reading Raster Data</H3>
+
+<P>As with any filter, your printer driver should handle raster data from
+a filename specified on the command-line or from the standard input. The
+<A HREF="#cupsRasterOpen"><CODE>cupsRasterOpen()</CODE></A> function opens
+a raster stream for printing:
+
+<UL><PRE>
+int fd; /* File descriptor */
+cups_raster_t *ras; /* Raster stream for printing */
+
+
+/*
+ * Check for valid arguments...
+ */
+
+if (argc &lt; 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);
+</PRE></UL>
+
+<P>Once you have opened the raster stream you just need to read each
+page and print it:
+
+<UL><PRE>
+cups_raster_header_t header;
+int y;
+unsigned char data[8192];
+
+while (cupsRasterReadHeader(ras, &amp;header))
+{
+ ... initialize the printer ...
+ for (y = header.cupsHeight; y > 0; y ++)
+ {
+ cupsRasterReadPixels(ras, data, header.cupsBytesPerLine);
+ ... send raster line to printer ...
+ }
+}
+</PRE></UL>
+
+<P>After you have processed all pages, close the raster stream and
+return:
+
+<UL><PRE>
+cupsRasterClose(ras);
+
+return (0);
+</PRE></UL>
+
+<H1 ALIGN="RIGHT"><A NAME="WRITING_BACKENDS">5 - Writing Backends</A></H1>
+
+<P>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.
+
+<H2>Overview</H2>
+
+<P>Backends are special filters that communicate with printers directly.
+They are treated slightly differently than filters, however, and have some
+unique requirements.
+
+<H3>Security Considerations</H3>
+
+<P>Backends are run as the root user, so special care must be taken to
+avoid potential security violations. In particular, remember that a backend
+will be able to manipulate disk files, devices, and other resources that
+potentially could damage a system or printer.
+
+<H3>Command-Line Arguments</H3>
+
+<P>Besides the standard filter arguments, backends are also run with no
+arguments to get a list of available devices. This discovery process is
+described later in this chapter.
+
+<H3>Copy Generation</H3>
+
+<P>Like filters, backends should send multiple copies of the print file only
+if a filename is supplied on the command-line. Otherwise the backend should
+assume that the upstream filter has already added the necessary commands or
+data to produce the multiple copies.
+
+<H3>Page Accounting</H3>
+
+<P>Backend filters generally do not do page accounting, however they should
+at a minimum produce a single page message for each copy that is produced
+when a filename is present on the command-line. This is because the user
+selected "raw" printing and no other accounting information is possible.
+
+<H3>Exclusive Access</H3>
+
+<P>Backends that talk to local character or block devices should open the
+device file in exclusive mode (<CODE>O_EXCL</CODE>) to cooperate with other
+printers defined for the same device.
+
+<H3>Retries</H3>
+
+<P>All backends <B>must</B> retry connections to the device. This
+includes backends that talk to local character or block devices, as the
+user may define more than one printer queue pointing at the same
+physical device.
+
+<P>To prevent excess CPU utilitization, the backend should go to sleep
+for an amount of time between retries; the CUPS-supplied backends retry
+once every 30 seconds.
+
+<H2>Dissecting the Serial Port Backend</H2>
+
+<P>The serial port backend provides support for serial printers. Since
+it does everything a good backend needs to do, it provides an excellent
+example of what to do.
+
+<H3>Supporting Device Discovery</H3>
+
+<P>As previously noted, backends are special filter programs that talk
+to printer devices. Another task a backend must perform is to list the
+available devices it supports. The backend lists the available devices
+when no additioanl arguments are supplied on the command-line (i.e.
+just the command name...)
+
+<P>The serial backend lists devices by looking at serial port files in the
+<VAR>/dev</VAR> directory, by consulting a hardware inventory (IRIX), and
+in some cases by trying to open the ports to see if they actually exist.
+
+<P>Once it finds a serial port it writes a single line for each port to
+the standard error file. Each line looks like this:
+
+<UL><PRE>
+serial serial:/dev/ttyS0?baud=115200 "Unknown" "Serial Port 1"
+</PRE></UL>
+
+<P>The first word "serial" is the <I>device class</I>; this identifies the
+class of device which can be used to categorize it in user interfaces. CUPS
+currently recognizes the following classes:
+
+<UL>
+
+ <LI>"file" - a disk file.
+
+ <LI>"direct" - a parallel or fixed-rate serial data port,
+ currently used for Centronics, IEEE-1284, and USB printer
+ ports.
+
+ <LI>"serial" - a variable-rate serial port.
+
+ <LI>"network" - a network connection, typically via AppSocket,
+ HTTP, IPP, LPD, or SMB/CIFS protocols.
+
+</UL>
+
+<P>After the device class is the <I>device URI</I>, in this case
+"serial:/dev/ttyS0?baud=115200". This is the URI that should be used by
+the user to select this port. For serial ports, the "baud=115200"
+specifies the maximum baud rate supported by the port - the actual
+value will vary based on the speed the user selects for the printer.
+
+<P>The last two strings are the model and description for the port. The
+"Unknown" string means that the printer model is unknown - some devices
+are able to provide a make and model such as "HP DeskJet" that allows
+users and software to choose an appropriate printer driver more easily.
+Both the model and description must be enclosed inside double quotes.
+
+<H3>Opening the Serial Port</H3>
+
+<P>As noted previously, all backends should open device files in exclusive
+mode, and retry as needed until the port is available. The serial port does
+this using a <CODE>do-while</CODE> loop:
+
+<UL><PRE>
+do
+{
+ if ((fd = open(resource, O_WRONLY | O_NOCTTY | O_EXCL)) == -1)
+ {
+ if (errno == EBUSY)
+ {
+ fputs("INFO: Serial port busy; will retry in 30 seconds...\n", stderr);
+ sleep(30);
+ }
+ else
+ {
+ perror("ERROR: Unable to open serial port device file");
+ return (1);
+ }
+ }
+}
+while (fd &lt; 0);
+</PRE></UL>
+
+<P>If the port is busy or in use by another process, the backend will
+go to sleep for 30 seconds and try again. If another error is detected
+a message is sent to the user and the backend aborts the print job
+until the problem can be corrected.
+
+<H3>Writing Data to the Port</H3>
+
+<P>Network and character devices pose an interesting problem when writing
+data to the port - they may not be able to write all of the bytes in your
+buffer before returning. To work around this problem you must loop until
+all bytes have been written:
+
+<UL><PRE>
+while (nbytes > 0)
+{
+ if ((wbytes = write(fd, bufptr, nbytes)) &lt; 0)
+ if (errno == ENOTTY)
+ wbytes = write(fd, bufptr, nbytes);
+
+ if (wbytes &lt; 0)
+ {
+ perror("ERROR: Unable to send print file to printer");
+ break;
+ }
+
+ nbytes -= wbytes;
+ bufptr += wbytes;
+}
+</PRE></UL>
+
+<P>The check for the <CODE>ENOTTY</CODE> error is needed on some platforms
+to clear an error from a previous <CODE>ioctl()</CODE> call.
+
+<H3>Finishing Up</H3>
+
+<P>Once you have sent the print file, return 0 if the file printed
+successfully or 1 if it did not. This will allow the scheduler to stop
+the print job if there is a device error, preserving the print job for
+later printing once the problem has been corrected.
+
+<H1 ALIGN="RIGHT"><A NAME="LICENSE">A - Software License Agreement</A></H1>
+
+<EMBED SRC="../LICENSE.html">
+
+
+<H1 ALIGN="RIGHT"><A NAME="CONSTANTS">B - Constants</A></H1>
+
+<P>This appendix lists all of the constants that are defined by the CUPS
+API.
+
+<H2>CUPS Constants</H2>
+
+<H3>Version Number</H3>
+
+<P>The <CODE>CUPS_VERSION</CODE> constant is a floating-point number
+representing the API version number. The current version number is
+1.0100 which represents CUPS version 1.1.0.
+
+<H3>Printer Capabilities</H3>
+
+<P>The <CODE>CUPS_PRINTER</CODE> constants represent capability bits for
+printers and classes:
+
+<UL>
+
+ <LI><CODE>CUPS_PRINTER_LOCAL</CODE> - Is a local printer or class.
+
+ <LI><CODE>CUPS_PRINTER_REMOTE</CODE> - Is a remote printer or class.
+
+ <LI><CODE>CUPS_PRINTER_CLASS</CODE> - Is a class.
+
+ <LI><CODE>CUPS_PRINTER_BW</CODE> - Printer prints in black and white.
+
+ <LI><CODE>CUPS_PRINTER_COLOR</CODE> - Printer prints in color.
+
+ <LI><CODE>CUPS_PRINTER_DUPLEX</CODE> - Printer can print double-sided.
+
+ <LI><CODE>CUPS_PRINTER_STAPLE</CODE> - Printer can staple output.
+
+ <LI><CODE>CUPS_PRINTER_COPIES</CODE> - Printer can produce multiple
+ copies on its own.
+
+ <LI><CODE>CUPS_PRINTER_COLLATE</CODE> - Printer can collate copies.
+
+ <LI><CODE>CUPS_PRINTER_PUNCH</CODE> - Printer can punch holes in output.
+
+ <LI><CODE>CUPS_PRINTER_COVER</CODE> - Printer can put covers on output.
+
+ <LI><CODE>CUPS_PRINTER_BIND</CODE> - Printer can bind output.
+
+ <LI><CODE>CUPS_PRINTER_SORT</CODE> - Printer can sort output.
+
+ <LI><CODE>CUPS_PRINTER_SMALL</CODE> - Printer can print on media up
+ to 9x14 inches.
+
+ <LI><CODE>CUPS_PRINTER_MEDIUM</CODE> - Printer can print on media
+ from 9x14 to 18x24 inches.
+
+ <LI><CODE>CUPS_PRINTER_LARGE</CODE> - Printer can print on media
+ larger than 18x24 inches.
+
+ <LI><CODE>CUPS_PRINTER_VARIABLE</CODE> - Printer can print on
+ variable or custom media sizes.
+
+ <LI><CODE>CUPS_PRINTER_IMPLICIT</CODE> - Is an implicit class.
+
+ <LI><CODE>CUPS_PRINTER_OPTIONS</CODE> - All of the printer capability
+ and option bits.
+
+</UL>
+
+<H3>Encodings</H3>
+
+<P>CUPS defines the following character set encoding constants:
+
+<UL>
+
+ <LI><CODE>CUPS_US_ASCII</CODE> - US ASCII character set.
+
+ <LI><CODE>CUPS_UTF_8</CODE> - UTF-8 encoding of Unicode.
+
+ <LI><CODE>CUPS_ISO8859_1</CODE> - ISO-8859-1 character set.
+
+ <LI><CODE>CUPS_ISO8859_2</CODE> - ISO-8859-2 character set.
+
+ <LI><CODE>CUPS_ISO8859_3</CODE> - ISO-8859-3 character set.
+
+ <LI><CODE>CUPS_ISO8859_4</CODE> - ISO-8859-4 character set.
+
+ <LI><CODE>CUPS_ISO8859_5</CODE> - ISO-8859-5 character set.
+
+ <LI><CODE>CUPS_ISO8859_6</CODE> - ISO-8859-6 character set.
+
+ <LI><CODE>CUPS_ISO8859_7</CODE> - ISO-8859-7 character set.
+
+ <LI><CODE>CUPS_ISO8859_8</CODE> - ISO-8859-8 character set.
+
+ <LI><CODE>CUPS_ISO8859_9</CODE> - ISO-8859-9 character set.
+
+ <LI><CODE>CUPS_ISO8859_10</CODE> - ISO-8859-10 character set.
+
+ <LI><CODE>CUPS_ISO8859_13</CODE> - ISO-8859-13 character set.
+
+ <LI><CODE>CUPS_ISO8859_14</CODE> - ISO-8859-14 character set.
+
+ <LI><CODE>CUPS_ISO8859_15</CODE> - ISO-8859-15 character set.
+
+ <LI><CODE>CUPS_WINDOWS_874</CODE> - Windows code page 874.
+
+ <LI><CODE>CUPS_WINDOWS_1250</CODE> - Windows code page 1250.
+
+ <LI><CODE>CUPS_WINDOWS_1251</CODE> - Windows code page 1251.
+
+ <LI><CODE>CUPS_WINDOWS_1252</CODE> - Windows code page 1252.
+
+ <LI><CODE>CUPS_WINDOWS_1253</CODE> - Windows code page 1253.
+
+ <LI><CODE>CUPS_WINDOWS_1254</CODE> - Windows code page 1254.
+
+ <LI><CODE>CUPS_WINDOWS_1255</CODE> - Windows code page 1255.
+
+ <LI><CODE>CUPS_WINDOWS_1256</CODE> - Windows code page 1256.
+
+ <LI><CODE>CUPS_WINDOWS_1257</CODE> - Windows code page 1257.
+
+ <LI><CODE>CUPS_WINDOWS_1258</CODE> - Windows code page 1258.
+
+ <LI><CODE>CUPS_KOI8_R</CODE> - Russian code page koi8-r.
+
+ <LI><CODE>CUPS_KOI8_U</CODE> - Ukrainian code page koi8-r.
+
+</UL>
+
+<H2>HTTP Constants</H2>
+
+<H3>Limits</H3>
+
+<P>The following constants define the limits for strings:
+
+<UL>
+
+ <LI><CODE>HTTP_MAX_BUFFER</CODE> - Size of socket buffer.
+
+ <LI><CODE>HTTP_MAX_HOST</CODE> - Maximum length of hostname.
+
+ <LI><CODE>HTTP_MAX_URI</CODE> - Maximum length of URI.
+
+ <LI><CODE>HTTP_MAX_VALUE</CODE> - Maximum length of field values.
+
+</UL>
+
+<H3>Status Codes</H3>
+
+<P>The following status codes can be returned by <CODE>httpUpdate()</CODE>:
+
+<UL>
+
+ <LI><CODE>HTTP_ERROR</CODE> - A network error occurred
+
+ <LI><CODE>HTTP_CONTINUE</CODE> - Continue response from HTTP proxy
+
+ <LI><CODE>HTTP_OK</CODE> - OPTIONS/GET/HEAD/POST/TRACE command was successful
+
+ <LI><CODE>HTTP_CREATED</CODE> - PUT command was successful
+
+ <LI><CODE>HTTP_ACCEPTED</CODE> - DELETE command was successful
+
+ <LI><CODE>HTTP_NOT_AUTHORITATIVE</CODE> - Information isn't authoritative
+
+ <LI><CODE>HTTP_NO_CONTENT</CODE> - Successful command
+
+ <LI><CODE>HTTP_RESET_CONTENT</CODE> - Content was reset/recreated
+
+ <LI><CODE>HTTP_PARTIAL_CONTENT</CODE> - Only a partial file was recieved/sent
+
+ <LI><CODE>HTTP_MULTIPLE_CHOICES</CODE> - Multiple files match request
+
+ <LI><CODE>HTTP_MOVED_PERMANENTLY</CODE> - Document has moved permanently
+
+ <LI><CODE>HTTP_MOVED_TEMPORARILY</CODE> - Document has moved temporarily
+
+ <LI><CODE>HTTP_SEE_OTHER</CODE> - See this other link...
+
+ <LI><CODE>HTTP_NOT_MODIFIED</CODE> - File not modified
+
+ <LI><CODE>HTTP_USE_PROXY</CODE> - Must use a proxy to access this URI
+
+ <LI><CODE>HTTP_BAD_REQUEST</CODE> - Bad request
+
+ <LI><CODE>HTTP_UNAUTHORIZED</CODE> - Unauthorized to access host
+
+ <LI><CODE>HTTP_PAYMENT_REQUIRED</CODE> - Payment required
+
+ <LI><CODE>HTTP_FORBIDDEN</CODE> - Forbidden to access this URI
+
+ <LI><CODE>HTTP_NOT_FOUND</CODE> - URI was not found
+
+ <LI><CODE>HTTP_METHOD_NOT_ALLOWED</CODE> - Method is not allowed
+
+ <LI><CODE>HTTP_NOT_ACCEPTABLE</CODE> - Not Acceptable
+
+ <LI><CODE>HTTP_PROXY_AUTHENTICATION</CODE> - Proxy Authentication is Required
+
+ <LI><CODE>HTTP_REQUEST_TIMEOUT</CODE> - Request timed out
+
+ <LI><CODE>HTTP_CONFLICT</CODE> - Request is self-conflicting
+
+ <LI><CODE>HTTP_GONE</CODE> - Server has gone away
+
+ <LI><CODE>HTTP_LENGTH_REQUIRED</CODE> - A content length or encoding is required
+
+ <LI><CODE>HTTP_PRECONDITION</CODE> - Precondition failed
+
+ <LI><CODE>HTTP_REQUEST_TOO_LARGE</CODE> - Request entity too large
+
+ <LI><CODE>HTTP_URI_TOO_LONG</CODE> - URI too long
+
+ <LI><CODE>HTTP_UNSUPPORTED_MEDIATYPE</CODE> - The requested media type is unsupported
+
+ <LI><CODE>HTTP_SERVER_ERROR</CODE> - Internal server error
+
+ <LI><CODE>HTTP_NOT_IMPLEMENTED</CODE> - Feature not implemented
+
+ <LI><CODE>HTTP_BAD_GATEWAY</CODE> - Bad gateway
+
+ <LI><CODE>HTTP_SERVICE_UNAVAILABLE</CODE> - Service is unavailable
+
+ <LI><CODE>HTTP_GATEWAY_TIMEOUT</CODE> - Gateway connection timed out
+
+ <LI><CODE>HTTP_NOT_SUPPORTED</CODE> - HTTP version not supported
+
+</UL>
+
+<H3>Fields</H3>
+
+<P>The following fields are indices for each of the standard HTTP fields in
+HTTP 1/1:
+
+<UL>
+
+ <LI><CODE>HTTP_FIELD_ACCEPT_LANGUAGE</CODE> - Accept-Language
+
+ <LI><CODE>HTTP_FIELD_ACCEPT_RANGES</CODE> - Accept-Ranges
+
+ <LI><CODE>HTTP_FIELD_AUTHORIZATION</CODE> - Authorization
+
+ <LI><CODE>HTTP_FIELD_CONNECTION</CODE> - Connection
+
+ <LI><CODE>HTTP_FIELD_CONTENT_ENCODING</CODE> - Content-Encoding
+
+ <LI><CODE>HTTP_FIELD_CONTENT_LANGUAGE</CODE> - Content-Language
+
+ <LI><CODE>HTTP_FIELD_CONTENT_LENGTH</CODE> - Content-Length
+
+ <LI><CODE>HTTP_FIELD_CONTENT_LOCATION</CODE> - Content-Location
+
+ <LI><CODE>HTTP_FIELD_CONTENT_MD5</CODE> - Content-MD5
+
+ <LI><CODE>HTTP_FIELD_CONTENT_RANGE</CODE> - Content-Range
+
+ <LI><CODE>HTTP_FIELD_CONTENT_TYPE</CODE> - Content-Type
+
+ <LI><CODE>HTTP_FIELD_CONTENT_VERSION</CODE> - Content-Version
+
+ <LI><CODE>HTTP_FIELD_DATE</CODE> - Date
+
+ <LI><CODE>HTTP_FIELD_HOST</CODE> - Host
+
+ <LI><CODE>HTTP_FIELD_IF_MODIFIED_SINCE</CODE> - If-Modified-Since
+
+ <LI><CODE>HTTP_FIELD_IF_UNMODIFIED_SINCE</CODE> - If-Unmodified-Since
+
+ <LI><CODE>HTTP_FIELD_KEEP_ALIVE</CODE> - Keep-Alive
+
+ <LI><CODE>HTTP_FIELD_LAST_MODIFIED</CODE> - Last-Modified
+
+ <LI><CODE>HTTP_FIELD_LINK</CODE> - Link
+
+ <LI><CODE>HTTP_FIELD_LOCATION</CODE> - Location
+
+ <LI><CODE>HTTP_FIELD_RANGE</CODE> - Range
+
+ <LI><CODE>HTTP_FIELD_REFERER</CODE> - Referer
+
+ <LI><CODE>HTTP_FIELD_RETRY_AFTER</CODE> - Retry-After
+
+ <LI><CODE>HTTP_FIELD_TRANSFER_ENCODING</CODE> - Transfer-Encoding
+
+ <LI><CODE>HTTP_FIELD_UPGRADE</CODE> - Upgrade
+
+ <LI><CODE>HTTP_FIELD_USER_AGENT</CODE> - User-Agent
+
+ <LI><CODE>HTTP_FIELD_WWW_AUTHENTICATE</CODE> - WWW-Authenticate
+
+
+</UL>
+
+<H2>IPP Constants</H2>
+
+<H3>Limits</H3>
+
+<P>The following constants define array limits for IPP data:
+
+<UL>
+
+ <LI><CODE>IPP_MAX_NAME</CODE> - Maximum length of an attribute name
+
+ <LI><CODE>IPP_MAX_VALUES</CODE> - Maximum number of set-of values
+ that can be read in a request.
+
+</UL>
+
+<H3>Tags</H3>
+
+<UL>
+
+ <LI><CODE>IPP_TAG_ZERO</CODE> - Wildcard tag value for searches; also
+ used to separate groups of attributes
+
+ <LI><CODE>IPP_TAG_OPERATION</CODE> - Tag for values of type operation
+
+ <LI><CODE>IPP_TAG_JOB</CODE> - Tag for values of type job
+
+ <LI><CODE>IPP_TAG_END</CODE> - Tag for values of type end
+
+ <LI><CODE>IPP_TAG_PRINTER</CODE> - Tag for values of type printer
+
+ <LI><CODE>IPP_TAG_UNSUPPORTED_GROUP</CODE> - Tag for values of type unsupported_group
+
+ <LI><CODE>IPP_TAG_UNSUPPORTED_VALUE</CODE> - Tag for values of type unsupported_value
+
+ <LI><CODE>IPP_TAG_DEFAULT</CODE> - Tag for values of type default
+
+ <LI><CODE>IPP_TAG_UNKNOWN</CODE> - Tag for values of type unknown
+
+ <LI><CODE>IPP_TAG_NOVALUE</CODE> - Tag for values of type novalue
+
+ <LI><CODE>IPP_TAG_NOTSETTABLE</CODE> - Tag for values of type notsettable
+
+ <LI><CODE>IPP_TAG_DELETEATTR</CODE> - Tag for values of type deleteattr
+
+ <LI><CODE>IPP_TAG_ANYVALUE</CODE> - Tag for values of type anyvalue
+
+ <LI><CODE>IPP_TAG_INTEGER</CODE> - Tag for values of type integer
+
+ <LI><CODE>IPP_TAG_BOOLEAN</CODE> - Tag for values of type boolean
+
+ <LI><CODE>IPP_TAG_ENUM</CODE> - Tag for values of type enum
+
+ <LI><CODE>IPP_TAG_STRING</CODE> - Tag for values of type string
+
+ <LI><CODE>IPP_TAG_DATE</CODE> - Tag for values of type date
+
+ <LI><CODE>IPP_TAG_RESOLUTION</CODE> - Tag for values of type resolution
+
+ <LI><CODE>IPP_TAG_RANGE</CODE> - Tag for values of type range
+
+ <LI><CODE>IPP_TAG_COLLECTION</CODE> - Tag for values of type collection
+
+ <LI><CODE>IPP_TAG_TEXTLANG</CODE> - Tag for values of type textlang
+
+ <LI><CODE>IPP_TAG_NAMELANG</CODE> - Tag for values of type namelang
+
+ <LI><CODE>IPP_TAG_TEXT</CODE> - Tag for values of type text
+
+ <LI><CODE>IPP_TAG_NAME</CODE> - Tag for values of type name
+
+ <LI><CODE>IPP_TAG_KEYWORD</CODE> - Tag for values of type keyword
+
+ <LI><CODE>IPP_TAG_URI</CODE> - Tag for values of type uri
+
+ <LI><CODE>IPP_TAG_URISCHEME</CODE> - Tag for values of type urischeme
+
+ <LI><CODE>IPP_TAG_CHARSET</CODE> - Tag for values of type charset
+
+ <LI><CODE>IPP_TAG_LANGUAGE</CODE> - Tag for values of type language
+
+ <LI><CODE>IPP_TAG_MIMETYPE</CODE> - Tag for values of type mimetype
+
+</UL>
+
+<H3>Resolution Units</H3>
+
+<P>The <CODE>IPP_RES_PER_INCH</CODE> and <CODE>IPP_RES_PER_CM</CODE> constants
+specify dots per inch and dots per centimeter, respectively.
+
+<H3>Finishings</H3>
+
+<P>The finishing values specify special finishing operations to be
+performed on the job.
+
+<UL>
+
+ <LI><CODE>IPP_FINISH_NONE</CODE> - Do no finishing
+
+ <LI><CODE>IPP_FINISH_STAPLE</CODE> - Staple the job
+
+ <LI><CODE>IPP_FINISH_PUNCH</CODE> - Punch the job
+
+ <LI><CODE>IPP_FINISH_COVER</CODE> - Cover the job
+
+ <LI><CODE>IPP_FINISH_BIND</CODE> - Bind the job
+
+</UL>
+
+<H3>Orientations</H3>
+
+<P>The orientation values specify the orientation of the job.
+
+<UL>
+
+ <LI><CODE>IPP_PORTRAIT</CODE> - No rotation
+
+ <LI><CODE>IPP_LANDSCAPE</CODE> - 90 degrees counter-clockwise
+
+ <LI><CODE>IPP_REVERSE_LANDSCAPE</CODE> - 90 degrees clockwise
+
+ <LI><CODE>IPP_REVERSE_PORTRAIT</CODE> - 180 degrees
+
+</UL>
+
+<H3>Qualities</H3>
+
+<P>The quality values specify the desired quality of the print.
+<UL>
+
+ <LI><CODE>IPP_QUALITY_DRAFT</CODE> - Draft quality
+
+ <LI><CODE>IPP_QUALITY_NORMAL</CODE> - Normal quality
+
+ <LI><CODE>IPP_QUALITY_HIGH</CODE> - High quality
+
+</UL>
+
+<H3>Job States</H3>
+
+<P>The job state values are used to represent the current job state.
+
+<UL>
+
+ <LI><CODE>IPP_JOB_PENDING</CODE> - Job is pending
+
+ <LI><CODE>IPP_JOB_HELD</CODE> - Job is held
+
+ <LI><CODE>IPP_JOB_PROCESSING</CODE> - Job is processing
+
+ <LI><CODE>IPP_JOB_STOPPED</CODE> - Job is stopped
+
+ <LI><CODE>IPP_JOB_CANCELLED</CODE> - Job is cancelled
+
+ <LI><CODE>IPP_JOB_ABORTED</CODE> - Job is aborted
+
+ <LI><CODE>IPP_JOB_COMPLETED</CODE> - Job is completed
+
+</UL>
+
+<H3>Printer States</H3>
+
+<P>The printer state values are used to represent the current printer
+state.
+
+<UL>
+
+ <LI><CODE>IPP_PRINTER_IDLE</CODE> - Printer is idle
+
+ <LI><CODE>IPP_PRINTER_PROCESSING</CODE> - Printer is processing
+
+ <LI><CODE>IPP_PRINTER_STOPPED</CODE> - Printer is stopped
+
+</UL>
+
+<H3>Operations</H3>
+
+<P>The operation values represent the available IPP operations.
+
+<UL>
+
+ <LI><CODE>IPP_PRINT_JOB</CODE> - Print a file
+
+ <LI><CODE>IPP_PRINT_URI</CODE> - Print a URI
+
+ <LI><CODE>IPP_VALIDATE_JOB</CODE> - Validate job attributes
+
+ <LI><CODE>IPP_CREATE_JOB</CODE> - Create a new job
+
+ <LI><CODE>IPP_SEND_DOCUMENT</CODE> - Send a document to a job
+
+ <LI><CODE>IPP_SEND_URI</CODE> - Send a URI to a job
+
+ <LI><CODE>IPP_CANCEL_JOB</CODE> - Cancel a job
+
+ <LI><CODE>IPP_GET_JOB_ATTRIBUTES</CODE> - Get job attributes
+
+ <LI><CODE>IPP_GET_JOBS</CODE> - Get a list of all jobs
+
+ <LI><CODE>IPP_GET_PRINTER_ATTRIBUTES</CODE> - Get printer attributes
+
+ <LI><CODE>IPP_HOLD_JOB</CODE> - Hold a pending job
+
+ <LI><CODE>IPP_RELEASE_JOB</CODE> - Release a held job
+
+ <LI><CODE>IPP_RESTART_JOB</CODE> - Restart a completed job
+
+ <LI><CODE>IPP_PAUSE_PRINTER</CODE> - Pause a printer
+
+ <LI><CODE>IPP_RESUME_PRINTER</CODE> - Restart a paused printer
+
+ <LI><CODE>IPP_PURGE_JOBS</CODE> - Purge jobs from the queue
+
+ <LI><CODE>IPP_SET_PRINTER_ATTRIBUTES</CODE> - Set printer attributes
+
+ <LI><CODE>IPP_SET_JOB_ATTRIBUTES</CODE> - Set job attributes
+
+ <LI><CODE>IPP_GET_PRINTER_SUPPORTED_VALUES</CODE> - Get printer supported values
+
+ <LI><CODE>CUPS_GET_DEFAULT</CODE> - Get the default destination
+
+ <LI><CODE>CUPS_GET_PRINTERS</CODE> - Get a list of all printers
+
+ <LI><CODE>CUPS_ADD_PRINTER</CODE> - Add or modify a printer
+
+ <LI><CODE>CUPS_DELETE_PRINTER</CODE> - Delete a printer
+
+ <LI><CODE>CUPS_GET_CLASSES</CODE> - Get a list of all classes
+
+ <LI><CODE>CUPS_ADD_CLASS</CODE> - Add or modify a class
+
+ <LI><CODE>CUPS_DELETE_CLASS</CODE> - Delete a class
+
+ <LI><CODE>CUPS_ACCEPT_JOBS</CODE> - Accept jobs on a printer or class
+
+ <LI><CODE>CUPS_REJECT_JOBS</CODE> - Reject jobs on a printer or class
+
+ <LI><CODE>CUPS_SET_DEFAULT</CODE> - Set the default destination
+
+ <LI><CODE>CUPS_GET_DEVICES</CODE> - Get a list of all devices
+
+ <LI><CODE>CUPS_GET_PPDS</CODE> - Get a list of all PPDs
+
+ <LI><CODE>CUPS_MOVE_JOB</CODE> - Move a job to a new destination
+
+</UL>
+
+<H3>Status Codes</H3>
+
+<P>Status codes are returned by all IPP requests.
+
+<UL>
+
+ <LI><CODE>IPP_OK</CODE> - Request completed with no errors
+
+ <LI><CODE>IPP_OK_SUBST</CODE> - Request completed but some attribute
+ values were substituted
+
+ <LI><CODE>IPP_OK_CONFLICT</CODE> - Request completed but some attributes
+ conflicted
+
+ <LI><CODE>IPP_BAD_REQUEST</CODE> - The request was bad
+
+ <LI><CODE>IPP_FORBIDDEN</CODE> - You don't have access to the resource
+
+ <LI><CODE>IPP_NOT_AUTHENTICATED</CODE> - You are not authenticated for
+ the resource
+
+ <LI><CODE>IPP_NOT_AUTHORIZED</CODE> - You not authorized to access
+ the resource
+
+ <LI><CODE>IPP_NOT_POSSIBLE</CODE> - The requested operation cannot be
+ completed
+
+ <LI><CODE>IPP_TIMEOUT</CODE> - A timeout occurred
+
+ <LI><CODE>IPP_NOT_FOUND</CODE> - The resource was not found
+
+ <LI><CODE>IPP_GONE</CODE> - The resource has gone away
+
+ <LI><CODE>IPP_REQUEST_ENTITY</CODE> - The request was too large
+
+ <LI><CODE>IPP_REQUEST_VALUE</CODE> - The request contained a value
+ that was unknown to the server
+
+ <LI><CODE>IPP_DOCUMENT_FORMAT</CODE> - The document format is not
+ supported by the server
+
+ <LI><CODE>IPP_ATTRIBUTES</CODE> - Required attributes are missing
+
+ <LI><CODE>IPP_URI_SCHEME</CODE> - The URI scheme is not supported
+
+ <LI><CODE>IPP_CHARSET</CODE> - The charset is not supported
+
+ <LI><CODE>IPP_CONFLICT</CODE> - One or more attributes conflict
+
+ <LI><CODE>IPP_COMPRESSION_NOT_SUPPORTED</CODE> - The specified
+ compression is not supported
+
+ <LI><CODE>IPP_COMPRESSION_ERROR</CODE> - The compressed data
+ contained an error
+
+ <LI><CODE>IPP_DOCUMENT_FORMAT_ERROR</CODE> - The document data
+ contained an error in it
+
+ <LI><CODE>IPP_DOCUMENT_ACCESS_ERROR</CODE> - The remote document
+ could not be accessed
+
+ <LI><CODE>IPP_INTERNAL_ERROR</CODE> - The server encountered an
+ internal error
+
+ <LI><CODE>IPP_OPERATION_NOT_SUPPORTED</CODE> - The requested operation
+ is not supported
+
+ <LI><CODE>IPP_SERVICE_UNAVAILABLE</CODE> - The requested service
+ is unavailable
+
+ <LI><CODE>IPP_VERSION_NOT_SUPPORTED</CODE> - The IPP request
+ version is not supported
+
+ <LI><CODE>IPP_DEVICE_ERROR</CODE> - The output device encountered
+ an error
+
+ <LI><CODE>IPP_TEMPORARY_ERROR</CODE> - A temporary error occurred
+
+ <LI><CODE>IPP_NOT_ACCEPTING</CODE> - The destination is not accepting
+ jobs
+
+ <LI><CODE>IPP_PRINTER_BUSY</CODE> - The destination is busy
+
+ <LI><CODE>IPP_ERROR_JOB_CANCELLED</CODE> - The requested job has been
+ cancelled
+
+ <LI><CODE>IPP_MULTIPLE_JOBS_NOT_SUPPORTED</CODE> - The server
+ does not support multiple jobs
+
+</UL>
+
+<H2>PPD Constants</H2>
+
+<H3>PPD Format Version</H3>
+
+<P>The <CODE>PPD_VERSION</CODE> constant defines a floating point number
+representing the newest format version that is supported by CUPS, currently
+4.3.
+
+<H3>PPD User-Interface Types</H3>
+
+<P>Each printer option has a type associated with it:
+
+<UL>
+
+ <LI><CODE>PPD_UI_BOOLEAN</CODE> - The user can turn this option on or off
+
+ <LI><CODE>PPD_UI_PICKONE</CODE> - The user can choose one option value
+ to use.
+
+ <LI><CODE>PPD_UI_PICKMANY</CODE> - The user can choose zero or more
+ option values.
+
+</UL>
+
+<H3>PPD Sections</H3>
+
+<P>Some options must be output before others, or in different sections of
+the output document. The <CODE>ppd_section_t</CODE> enumeration defines
+which section the option must be output in:
+
+<UL>
+
+ <LI><CODE>PPD_ORDER_ANY</CODE> - The option can be output in any of
+ the document, page, or prolog sections of the document
+
+ <LI><CODE>PPD_ORDER_DOCUMENT</CODE> - The option must be output in
+ the DocumentSetup section of the document
+
+ <LI><CODE>PPD_ORDER_EXIT</CODE> - The option must be output before
+ the document
+
+ <LI><CODE>PPD_ORDER_JCL</CODE> - The option must be output in the
+ job control section of the document
+
+ <LI><CODE>PPD_ORDER_PAGE</CODE> - The option must be output in the
+ PageSetup section of the document
+
+ <LI><CODE>PPD_ORDER_PROLOG</CODE> - The option must be output in the
+ Prolog section of the document
+
+</UL>
+
+<H3>PPD Colorspaces</H3>
+
+<P>Each printer has a default colorspace:
+
+<UL>
+
+ <LI><CODE>PPD_CS_CMYK</CODE> - The printer uses CMYK colors by default
+
+ <LI><CODE>PPD_CS_CMY</CODE> - The printer uses CMY colors by default
+
+ <LI><CODE>PPD_CS_GRAY</CODE> - The printer uses grayscale by default
+
+ <LI><CODE>PPD_CS_RGB</CODE> - The printer uses RGB colors by default
+
+ <LI><CODE>PPD_CS_RGBK</CODE> - The printer uses RGBK colors by default
+
+ <LI><CODE>PPD_CS_N</CODE> - The printer uses a DeviceN colorspace
+ by default
+
+</UL>
+
+<H2>Raster Constants</H2>
+
+<H3>Raster Sync Words</H3>
+
+<P>The <CODE>CUPS_RASTER_SYNC</CODE> and <CODE>CUPS_RASTER_REVSYNC</CODE>
+constants define the standard sync words at the beginning of each CUPS
+raster file.
+
+<H3>Raster Stream Modes</H3>
+
+<P>The <CODE>CUPS_RASTER_READ</CODE> and <CODE>CUPS_RASTER_WRITE</CODE>
+constants are used with the
+<A HREF="#cupsRasterOpen"><CODE>cupsRasterOpen()</CODE></A> function to
+specify a stream for reading or writing.
+
+<H3>Raster Boolean Constants</H3>
+
+<P>The <CODE>CUPS_FALSE</CODE> and <CODE>CUPS_TRUE</CODE> constants
+represent boolean values in the page header.
+
+<H3>Raster Jog Values</H3>
+
+<P>The <CODE>cups_jog_t</CODE> enumeration defines constants for the
+Jog page device dictionary variable:
+
+<UL>
+
+ <LI><CODE>CUPS_JOG_NONE</CODE> - Do no jogging
+
+ <LI><CODE>CUPS_JOG_FILE</CODE> - Jog pages after each file
+
+ <LI><CODE>CUPS_JOG_JOB</CODE> - Jog pages after each job
+
+ <LI><CODE>CUPS_JOG_SET</CODE> - Jog pages after each set of jobs
+
+</UL>
+
+<H3>Raster Orientation Values</H3>
+
+<P>The <CODE>cups_orient_t</CODE> enumeration defines constants for the
+Orientation page device dictionary variable:
+
+<UL>
+
+ <LI><CODE>CUPS_ORIENT_0</CODE> - Portrait orientation
+
+ <LI><CODE>CUPS_ORIENT_90</CODE> - Landscape orientation
+
+ <LI><CODE>CUPS_ORIENT_180</CODE> - Reverse-portrait orientation
+
+ <LI><CODE>CUPS_ORIENT_270</CODE> - Reverse-landscape orientation
+
+</UL>
+
+<H3>Raster CutMedia Values</H3>
+
+<P>The <CODE>cups_cut_t</CODE> enumeration defines constants for the
+CutMedia page device dictionary variable:
+
+<UL>
+
+ <LI><CODE>CUPS_CUT_NONE</CODE> - Do no jogging
+
+ <LI><CODE>CUPS_CUT_FILE</CODE> - Cut pages after each file
+
+ <LI><CODE>CUPS_CUT_JOB</CODE> - Cut pages after each job
+
+ <LI><CODE>CUPS_CUT_SET</CODE> - Cut pages after each set of jobs
+
+ <LI><CODE>CUPS_CUT_PAGE</CODE> - Cut each page
+
+</UL>
+
+<H3>Raster AdvanceMedia Values</H3>
+
+<P>The <CODE>cups_advance_t</CODE> enumeration defines constants for the
+AdvanceMedia page device dictionary variable:
+
+<UL>
+
+ <LI><CODE>CUPS_ADVANCE_NONE</CODE> - Do no jogging
+
+ <LI><CODE>CUPS_ADVANCE_FILE</CODE> - Advance media after each file
+
+ <LI><CODE>CUPS_ADVANCE_JOB</CODE> - Advance media after each job
+
+ <LI><CODE>CUPS_ADVANCE_SET</CODE> - Advance media after each set of jobs
+
+ <LI><CODE>CUPS_ADVANCE_PAGE</CODE> - Advance media for each page
+
+</UL>
+
+<H3>Raster LeadingEdge Values</H3>
+
+<P>The <CODE>cups_edge_t</CODE> enumeration defines constants for the
+LeadingEdge page device dictionary variable:
+
+<UL>
+
+ <LI><CODE>CUPS_EDGE_TOP</CODE> - The top of the media is the leading
+ edge
+
+ <LI><CODE>CUPS_EDGE_RIGHT</CODE> - The right of the media is the leading
+ edge
+
+ <LI><CODE>CUPS_EDGE_BOTTOM</CODE> - The bottom of the media is the
+ leading edge
+
+ <LI><CODE>CUPS_EDGE_LEFT</CODE> - The left of the media is the leading
+ edge
+
+</UL>
+
+<H3>Raster Color Order Values</H3>
+
+<P>The <CODE>cups_order_t</CODE> enumeration defines the possible color
+value orderings:
+
+<UL>
+
+ <LI><CODE>CUPS_ORDER_CHUNKED</CODE> - CMYK&nbsp;CMYK&nbsp;CMYK
+
+ <LI><CODE>CUPS_ORDER_BANDED</CODE> - CCC&nbsp;MMM&nbsp;YYY&nbsp;KKK
+
+ <LI><CODE>CUPS_ORDER_PLANAR</CODE> - CCC&nbsp;...&nbsp;MMM&nbsp;...&nbsp;YYY&nbsp;...&nbsp;KKK&nbsp;...
+
+</UL>
+
+<H3>Raster Colorspace Values</H3>
+
+<P>The <CODE>cups_cspace_t</CODE> enumeration defines the possible colorspaces:
+
+<UL>
+
+ <LI><CODE>CUPS_CSPACE_W</CODE> - White (luminance)
+
+ <LI><CODE>CUPS_CSPACE_RGB</CODE> - Red, green, blue
+
+ <LI><CODE>CUPS_CSPACE_RGBA</CODE> - Red, green, blue, alpha
+
+ <LI><CODE>CUPS_CSPACE_K</CODE> - Black
+
+ <LI><CODE>CUPS_CSPACE_CMY</CODE> - Cyan, magenta, yellow
+
+ <LI><CODE>CUPS_CSPACE_YMC</CODE> - Yellow, magenta, cyan
+
+ <LI><CODE>CUPS_CSPACE_CMYK</CODE> - Cyan, magenta, yellow, black
+
+ <LI><CODE>CUPS_CSPACE_YMCK</CODE> - Yellow, magenta, cyan, black
+
+ <LI><CODE>CUPS_CSPACE_KCMY</CODE> - Black, cyan, magenta, yellow
+
+ <LI><CODE>CUPS_CSPACE_KCMYcm</CODE> - Black, cyan, magenta, yellow,
+ light cyan, light magenta
+
+ <LI><CODE>CUPS_CSPACE_GMCK</CODE> - Metallic yellow (gold), metallic magenta,
+ metallic cyan, black
+
+ <LI><CODE>CUPS_CSPACE_GMCS</CODE> - Metallic yellow (gold), metallic magenta,
+ metallic cyan, metallic grey (silver)
+
+ <LI><CODE>CUPS_CSPACE_WHITE</CODE> - White pigment (black as white pigment)
+
+ <LI><CODE>CUPS_CSPACE_GOLD</CODE> - Gold foil (black as gold foil)
+
+ <LI><CODE>CUPS_CSPACE_SILVER</CODE> - Silver foil (black as silver foil)
+
+</UL>
+
+<H1 ALIGN="RIGHT"><A NAME="STRUCTURES">C - Structures</A></H1>
+
+<P>This appendix describes all of the structures that are
+defined by the CUPS API.
+
+<H2>CUPS Structures</H2>
+
+<H3><A NAME="cups_dest_t">CUPS Destinations</A></H3>
+
+<P>The CUPS destination structure (<CODE>cups_dest_t</CODE>)
+contains information on a specific destination or instance:
+
+<CENTER><TABLE WIDTH="90%" BORDER="1">
+<TR>
+ <TH>Member</TH>
+ <TH>Type</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>name</TD>
+ <TD>char *</TD>
+ <TD>The name of the printer or class.</TD>
+</TR>
+<TR>
+ <TD>instance</TD>
+ <TD>char *</TD>
+ <TD>The instance of the printer or class; NULL for the primary
+ instance.</TD>
+</TR>
+<TR>
+ <TD>is_default</TD>
+ <TD>int</TD>
+ <TD>1 if the destination is set as the default, 0 otherwise.</TD>
+</TR>
+<TR>
+ <TD>num_options</TD>
+ <TD>int</TD>
+ <TD>The number of options associated with this destination.</TD>
+</TR>
+<TR>
+ <TD>options</TD>
+ <TD><A HREF="#cups_option_t">cups_option_t *</A></TD>
+ <TD>The options associated with this destination.</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3><A NAME="cups_job_t">CUPS Jobs</A></H3>
+
+<P>The CUPS job structure (<CODE>cups_job_t</CODE>) contains
+information on a specific job:
+
+<CENTER><TABLE WIDTH="90%" BORDER="1">
+<TR>
+ <TH>Member</TH>
+ <TH>Type</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>id</TD>
+ <TD>int</TD>
+ <TD>The job ID for this job.</TD>
+</TR>
+<TR>
+ <TD>dest</TD>
+ <TD>char *</TD>
+ <TD>The destination for this job (printer or class name).</TD>
+</TR>
+<TR>
+ <TD>title</TD>
+ <TD>char *</TD>
+ <TD>The job-name for this job (title).</TD>
+</TR>
+<TR>
+ <TD>user</TD>
+ <TD>char *</TD>
+ <TD>The job-originating-user-name for this job (username).</TD>
+</TR>
+<TR>
+ <TD>format</TD>
+ <TD>char *</TD>
+ <TD>The document-format for this job (MIME type string).</TD>
+</TR>
+<TR>
+ <TD>state</TD>
+ <TD>ipp_jstate</TD>
+ <TD>The current state of the job.</TD>
+</TR>
+<TR>
+ <TD>size</TD>
+ <TD>int</TD>
+ <TD>The size of this job in kilobytes.</TD>
+</TR>
+<TR>
+ <TD>priority</TD>
+ <TD>int</TD>
+ <TD>The priority of this job from 1 to 100 (50 is normal).</TD>
+</TR>
+<TR>
+ <TD>completed_time</TD>
+ <TD>time_t</TD>
+ <TD>The time the job was completed, or 0 if not yet completed.</TD>
+</TR>
+<TR>
+ <TD>creation_time</TD>
+ <TD>time_t</TD>
+ <TD>The time the job was queued.</TD>
+</TR>
+<TR>
+ <TD>processing_time</TD>
+ <TD>time_t</TD>
+ <TD>The time the job started printing.</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3><A NAME="cups_lang_t">CUPS Messages</A></H3>
+
+<P>The CUPS messages structure (<CODE>cups_lang_t</CODE>)
+contains the character set, locale name, and messages array:
+
+<CENTER><TABLE WIDTH="90%" BORDER="1">
+<TR>
+ <TH>Member</TH>
+ <TH>Type</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>next</TD>
+ <TD>cups_lang_t *</TD>
+ <TD>Pointer to the next messages structure in memory.</TD>
+</TR>
+<TR>
+ <TD>used</TD>
+ <TD>int</TD>
+ <TD>The number of active users of this messages structure.</TD>
+</TR>
+<TR>
+ <TD>encoding</TD>
+ <TD>cups_encoding_t</TD>
+ <TD>The character encoding of the message strings.</TD>
+</TR>
+<TR>
+ <TD>language</TD>
+ <TD>char [16]</TD>
+ <TD>The language/locale name.</TD>
+</TR>
+<TR>
+ <TD>messages</TD>
+ <TD>char *[]</TD>
+ <TD>The array of message strings.</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3><A NAME="cups_option_t">CUPS Options</A></H3>
+
+<P>The CUPS option structure (<CODE>cups_option_t</CODE>)
+contains the option name and string value:
+
+<CENTER><TABLE WIDTH="90%" BORDER="1">
+<TR>
+ <TH>Member</TH>
+ <TH>Type</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>name</TD>
+ <TD>char *</TD>
+ <TD>The name of the option.</TD>
+</TR>
+<TR>
+ <TD>value</TD>
+ <TD>char *</TD>
+ <TD>The string value of the option.</TD>
+</TR>
+</TABLE></CENTER>
+
+<H2>Networking Structures</H2>
+
+<H3><A NAME="http_t">HTTP State</A></H3>
+
+<P>The HTTP state structure (<CODE>http_t</CODE>) contains the
+current state of a HTTP request or response:
+
+<CENTER><TABLE WIDTH="90%" BORDER="1">
+<TR>
+ <TH>Member</TH>
+ <TH>Type</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>fd</TD>
+ <TD>int</TD>
+ <TD>The socket for the HTTP connection.</TD>
+</TR>
+<TR>
+ <TD>blocking</TD>
+ <TD>int</TD>
+ <TD>1 if the HTTP functions should block, 0 if not.</TD>
+</TR>
+<TR>
+ <TD>error</TD>
+ <TD>int</TD>
+ <TD>The last OS error that occurred on the socket.</TD>
+</TR>
+<TR>
+ <TD>activity</TD>
+ <TD>time_t</TD>
+ <TD>The last time the HTTP connection was used.</TD>
+</TR>
+<TR>
+ <TD>state</TD>
+ <TD>http_state_t</TD>
+ <TD>The current HTTP request/response state.</TD>
+</TR>
+<TR>
+ <TD>status</TD>
+ <TD>int</TD>
+ <TD>The last HTTP status seen.</TD>
+</TR>
+<TR>
+ <TD>version</TD>
+ <TD>http_version_t</TD>
+ <TD>The HTTP protocol version in use.</TD>
+</TR>
+<TR>
+ <TD>keep_alive</TD>
+ <TD>http_keep_alive_t</TD>
+ <TD>Whether or not to use Keep-Alive</TD>
+</TR>
+<TR>
+ <TD>hostaddr</TD>
+ <TD>struct sockaddr_in</TD>
+ <TD>The IPv4 address of the HTTP server.</TD>
+</TR>
+<TR>
+ <TD>hostname</TD>
+ <TD>char []</TD>
+ <TD>The hostname of the HTTP server.</TD>
+</TR>
+<TR>
+ <TD>fields</TD>
+ <TD>char [][]</TD>
+ <TD>The string values of all HTTP request/response
+ fields.</TD>
+</TR>
+<TR>
+ <TD>data</TD>
+ <TD>char *</TD>
+ <TD>Current byte in data buffer.</TD>
+</TR>
+<TR>
+ <TD>data_encoding</TD>
+ <TD>http_encoding_t</TD>
+ <TD>The transfer encoding for the request/response.</TD>
+</TR>
+<TR>
+ <TD>data_remaining</TD>
+ <TD>int</TD>
+ <TD>The number of bytes remaining in the current request,
+ response, or chunk.</TD>
+</TR>
+<TR>
+ <TD>used</TD>
+ <TD>int</TD>
+ <TD>The number of bytes that are used in the buffer.</TD>
+</TR>
+<TR>
+ <TD>buffer</TD>
+ <TD>char []</TD>
+ <TD>The read/write buffer.</TD>
+</TR>
+<TR>
+ <TD>auth_type</TD>
+ <TD>int</TD>
+ <TD>The type of authentication in use.</TD>
+</TR>
+<TR>
+ <TD>md5_state</TD>
+ <TD>md5_state_t</TD>
+ <TD>The current MD5 digest state.</TD>
+</TR>
+<TR>
+ <TD>nonce</TD>
+ <TD>char []</TD>
+ <TD>The nonce value for Digest authentication.</TD>
+</TR>
+<TR>
+ <TD>nonce_count</TD>
+ <TD>int</TD>
+ <TD>The nonce count value.</TD>
+</TR>
+<TR>
+ <TD>tls</TD>
+ <TD>void *</TD>
+ <TD>A pointer to private encryption data.</TD>
+</TR>
+<TR>
+ <TD>encryption</TD>
+ <TD>http_encryption_t</TD>
+ <TD>The current encryption mode.</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3><A NAME="ipp_t">IPP State</A></H3>
+
+<P>The IPP state structure (<CODE>ipp_t</CODE>) contains the
+current state of a IPP request or response:
+
+<CENTER><TABLE WIDTH="90%" BORDER="1">
+<TR>
+ <TH>Member</TH>
+ <TH>Type</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+</TR>
+</TABLE></CENTER>
+
+<H2>Raster Structures</H2>
+
+<H3><A NAME="cups_raster_header_t">Raster Page Header</A></H3>
+
+<P>The raster page header (<CODE>cups_raster_header_t</CODE>)
+consists of the PostScript page device dictionary for the page:
+
+<CENTER><TABLE WIDTH="90%" BORDER="1">
+<TR>
+ <TH>Member</TH>
+ <TH>Type</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>MediaClass</TD>
+ <TD>char[64]</TD>
+ <TD>The media class name</TD>
+</TR>
+<TR>
+ <TD>MediaColor</TD>
+ <TD>char[64]</TD>
+ <TD>The media color name</TD>
+</TR>
+<TR>
+ <TD>MediaType</TD>
+ <TD>char[64]</TD>
+ <TD>The media type name</TD>
+</TR>
+<TR>
+ <TD>OutputType</TD>
+ <TD>char[64]</TD>
+ <TD>The output type name</TD>
+</TR>
+<TR>
+ <TD>AdvanceDistance</TD>
+ <TD>unsigned</TD>
+ <TD>The distance to advance the media in points</TD>
+</TR>
+<TR>
+ <TD>AdvanceMedia</TD>
+ <TD>cups_adv_t</TD>
+ <TD>When to advance the media</TD>
+</TR>
+<TR>
+ <TD>Collate</TD>
+ <TD>cups_bool_t</TD>
+ <TD>Whether or not to produce collated copies</TD>
+</TR>
+<TR>
+ <TD>CutMedia</TD>
+ <TD>cups_cut_t</TD>
+ <TD>When to cut the media</TD>
+</TR>
+<TR>
+ <TD>Duplex</TD>
+ <TD>cups_bool_t</TD>
+ <TD>Whether or not to print on both sides of the paper</TD>
+</TR>
+<TR>
+ <TD>HWResolution</TD>
+ <TD>unsigned[2]</TD>
+ <TD>The resolution of the page image in pixels per inch; the
+ HWResolution[0] represents the horizontal resolution and
+ HWResolution[1] represents the vertical resolution</TD>
+</TR>
+<TR>
+ <TD>ImagingBoundingBox</TD>
+ <TD>unsigned[4]</TD>
+ <TD>The bounding box for the page in points; the elements
+ represent the left, bottom, right, and top coordinates of the
+ imaged area (if 0 then the whole page is imaged)</TD>
+</TR>
+<TR>
+ <TD>InsertSheet</TD>
+ <TD>cups_bool_t</TD>
+ <TD>Whether or not to insert a sheet before this page</TD>
+</TR>
+<TR>
+ <TD>Jog</TD>
+ <TD>cups_jog_t</TD>
+ <TD>When to jog copies of the page</TD>
+</TR>
+<TR>
+ <TD>LeadingEdge</TD>
+ <TD>cups_edge_t</TD>
+ <TD>The leading edge of the page</TD>
+</TR>
+<TR>
+ <TD>Margins</TD>
+ <TD>unsigned[2]</TD>
+ <TD>The lower-lefthand margin of the page in points</TD>
+</TR>
+<TR>
+ <TD>ManualFeed</TD>
+ <TD>cups_bool_t</TD>
+ <TD>Whether or not to manually feed the page</TD>
+</TR>
+<TR>
+ <TD>MediaPosition</TD>
+ <TD>unsigned</TD>
+ <TD>The input slot number to use</TD>
+</TR>
+<TR>
+ <TD>MediaWeight</TD>
+ <TD>unsigned</TD>
+ <TD>The weight of the output media in grams/m<SUP>2</SUP></TD>
+</TR>
+<TR>
+ <TD>MirrorPrint</TD>
+ <TD>cups_bool_t</TD>
+ <TD>Whether or not to mirror the print</TD>
+</TR>
+<TR>
+ <TD>NegativePrint</TD>
+ <TD>cups_bool_t</TD>
+ <TD>Whether or not to invert the print</TD>
+</TR>
+<TR>
+ <TD>NumCopies</TD>
+ <TD>unsigned</TD>
+ <TD>The number of copies to produce</TD>
+</TR>
+<TR>
+ <TD>Orientation</TD>
+ <TD>cups_orient_t</TD>
+ <TD>The orientation of the page image</TD>
+</TR>
+<TR>
+ <TD>OutputFaceUp</TD>
+ <TD>cups_bool_t</TD>
+ <TD>Whether or not to output the page face up</TD>
+</TR>
+<TR>
+ <TD>PageSize</TD>
+ <TD>unsigned[2]</TD>
+ <TD>The width and height of the page in points</TD>
+</TR>
+<TR>
+ <TD>Separations</TD>
+ <TD>cups_bool_t</TD>
+ <TD>Whether or not to output separations</TD>
+</TR>
+<TR>
+ <TD>TraySwitch</TD>
+ <TD>cups_bool_t</TD>
+ <TD>Whether or not to automatically switch trays for the requested
+ media size/type</TD>
+</TR>
+<TR>
+ <TD>Tumble</TD>
+ <TD>cups_bool_t</TD>
+ <TD>Whether or not to rotate the back side of the page</TD>
+</TR>
+<TR>
+ <TD>cupsWidth</TD>
+ <TD>unsigned</TD>
+ <TD>The width of the page image in pixels</TD>
+</TR>
+<TR>
+ <TD>cupsHeight</TD>
+ <TD>unsigned</TD>
+ <TD>The height of the page image in pixels</TD>
+</TR>
+<TR>
+ <TD>cupsMediaType</TD>
+ <TD>unsigned</TD>
+ <TD>The device-specific media type code</TD>
+</TR>
+<TR>
+ <TD>cupsBitsPerColor</TD>
+ <TD>unsigned</TD>
+ <TD>The number of bits per color</TD>
+</TR>
+<TR>
+ <TD>cupsBitsPerPixel</TD>
+ <TD>unsigned</TD>
+ <TD>The number of bits per pixel</TD>
+</TR>
+<TR>
+ <TD>cupsBytesPerLine</TD>
+ <TD>unsigned</TD>
+ <TD>The number of bytes per line of image data</TD>
+</TR>
+<TR>
+ <TD>cupsColorOrder</TD>
+ <TD>cups_order_t</TD>
+ <TD>The order of color values</TD>
+</TR>
+<TR>
+ <TD>cupsColorSpace</TD>
+ <TD>cups_cspace_t</TD>
+ <TD>The type of color values</TD>
+</TR>
+<TR>
+ <TD>cupsCompression</TD>
+ <TD>unsigned</TD>
+ <TD>The device-specific compression code</TD>
+</TR>
+<TR>
+ <TD>cupsRowCount</TD>
+ <TD>unsigned</TD>
+ <TD>The device-specific row count</TD>
+</TR>
+<TR>
+ <TD>cupsRowFeed</TD>
+ <TD>unsigned</TD>
+ <TD>The device-specific row feed</TD>
+</TR>
+<TR>
+ <TD>cupsRowStep</TD>
+ <TD>unsigned</TD>
+ <TD>The device-specific row step</TD>
+</TR>
+</TABLE></CENTER>
+
+<H1 ALIGN="RIGHT"><A NAME="FUNCTIONS">D - Functions</A></H1>
+
+<P>This appendix provides a reference for all of the CUPS API functions.
+
+<!-- NEW PAGE --><H2><A NAME="cupsAddOption">cupsAddOption()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+int
+cupsAddOption(const char *name,
+ const char *value,
+ int num_options,
+ cups_option_t **options);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>name</TD>
+ <TD>The name of the option.</TD>
+</TR>
+<TR>
+ <TD>value</TD>
+ <TD>The value of the option.</TD>
+</TR>
+<TR>
+ <TD>num_options</TD>
+ <TD>Number of options currently in the array.</TD>
+</TR>
+<TR>
+ <TD>options</TD>
+ <TD>Pointer to the options array.</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>The new number of options.
+
+<H3>Description</H3>
+
+<P><CODE>cupsAddOption()</CODE> adds an option to the specified array.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups.h&gt;
+
+...
+
+/* Declare the options array */
+int num_options;
+<A HREF="#cups_option_t">cups_option_t</A> *options;
+
+/* Initialize the options array */
+num_options = 0;
+options = (cups_option_t *)0;
+
+/* Add options using cupsAddOption() */
+num_options = cupsAddOption("media", "letter", num_options, &amp;options);
+num_options = cupsAddOption("resolution", "300dpi", num_options, &amp;options);
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#cupsFreeOptions"><CODE>cupsFreeOptions()</CODE></A>,
+<A HREF="#cupsGetOption"><CODE>cupsGetOption()</CODE></A>,
+<A HREF="#cupsParseOptions"><CODE>cupsParseOptions()</CODE></A>
+
+<!-- NEW PAGE --><H2><A NAME="cupsCancelJob">cupsCancelJob()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+int
+cupsCancelJob(const char *dest,
+ int job);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>dest</TD>
+ <TD>Printer or class name</TD>
+</TR>
+<TR>
+ <TD>job</TD>
+ <TD>Job ID</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>1 on success, 0 on failure. On failure the error can be found by calling
+<A HREF="#cupsLastError"><CODE>cupsLastError()</CODE></A>.
+
+<H3>Description</H3>
+
+<P><CODE>cupsCancelJob()</CODE> cancels the specifies job.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups.h&gt;
+
+cupsCancelJob("LaserJet", 1);
+</PRE>
+
+<H3>See Also</H3>
+
+<P>
+<A HREF="#cupsLastError"><CODE>cupsLastError()</CODE></A>,
+<A HREF="#cupsPrintFile"><CODE>cupsPrintFile()</CODE></A>
+
+<!-- NEW PAGE --><H2><A NAME="cupsDoFileRequest">cupsDoFileRequest()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+ipp_t *
+cupsDoFileRequest(http_t *http,
+ ipp_t *request,
+ const char *resource,
+ const char *filename);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>http</TD>
+ <TD>HTTP connection to server.</TD>
+</TR>
+<TR>
+ <TD>request</TD>
+ <TD>IPP request data.</TD>
+</TR>
+<TR>
+ <TD>resource</TD>
+ <TD>HTTP resource name for POST.</TD>
+</TR>
+<TR>
+ <TD>filename</TD>
+ <TD>File to send with POST request (<CODE>NULL</CODE> pointer if none.)</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>IPP response data or <CODE>NULL</CODE> if the request fails. On failure
+the error can be found by calling
+<A HREF="#cupsLastError"><CODE>cupsLastError()</CODE></A>.
+
+<H3>Description</H3>
+
+<P><CODE>cupsDoFileRequest()</CODE> 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.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups.h&gt;
+
+<A HREF="#http_t">http_t</A> *http;
+<A HREF="#cups_lang_t">cups_lang_t</A> *language;
+<A HREF="#ipp_t">ipp_t</A> *request;
+ipp_t *response;
+
+...
+
+/* Get the default language */
+language = <A HREF="#cupsLangDefault">cupsLangDefault()</A>;
+
+/* Create a new IPP request */
+request = <A HREF="#ippNew">ippNew()</A>;
+
+request-&gt;request.op.operation_id = IPP_PRINT_FILE;
+request-&gt;request.op.request_id = 1;
+
+/* Add required attributes */
+<A HREF="#ippAddString">ippAddString</A>(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, <A HREF="#cupsLangEncoding">cupsLangEncoding</A>(language));
+
+ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL,
+ language != NULL ? language-&gt;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, <A HREF="#cupsUser">cupsUser()</A>);
+
+/* Do the request... */
+response = cupsDoFileRequest(http, request, "/resource", "filename.txt");
+</PRE>
+
+<H3>See Also</H3>
+
+<P>
+<A HREF="#cupsLangDefault"><CODE>cupsLangDefault()</CODE></A>,
+<A HREF="#cupsLangEncoding"><CODE>cupsLangEncoding()</CODE></A>,
+<A HREF="#cupsUser"><CODE>cupsUser()</CODE></A>,
+<A HREF="#httpConnect"><CODE>httpConnect()</CODE></A>,
+<A HREF="#ippAddString"><CODE>ippAddString()</CODE></A>,
+<A HREF="#ippNew"><CODE>ippNew()</CODE></A>
+
+<!-- NEW PAGE --><H2><A NAME="cupsDoRequest">cupsDoRequest()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+ipp_t *
+cupsDoRequest(http_t *http,
+ ipp_t *request,
+ const char *resource);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>http</TD>
+ <TD>HTTP connection to server.</TD>
+</TR>
+<TR>
+ <TD>request</TD>
+ <TD>IPP request data.</TD>
+</TR>
+<TR>
+ <TD>resource</TD>
+ <TD>HTTP resource name for POST.</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>IPP response data or <CODE>NULL</CODE> if the request fails. On failure
+the error can be found by calling
+<A HREF="#cupsLastError"><CODE>cupsLastError()</CODE></A>.
+
+<H3>Description</H3>
+
+<P><CODE>cupsDoRequest()</CODE> 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.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups.h&gt;
+
+<A HREF="#http_t">http_t</A> *http;
+<A HREF="#cups_lang_t">cups_lang_t</A> *language;
+<A HREF="#ipp_t">ipp_t</A> *request;
+ipp_t *response;
+
+...
+
+/* Get the default language */
+language = <A HREF="#cupsLangDefault">cupsLangDefault()</A>;
+
+/* Create a new IPP request */
+request = <A HREF="#ippNew">ippNew()</A>;
+
+request-&gt;request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
+request-&gt;request.op.request_id = 1;
+
+/* Add required attributes */
+<A HREF="#ippAddString">ippAddString</A>(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, <A HREF="#cupsLangEncoding">cupsLangEncoding</A>(language));
+
+ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL,
+ language != NULL ? language-&gt;language : "C");
+
+ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, "ipp://hostname/resource");
+
+/* Do the request... */
+response = cupsDoRequest(http, request, "/resource");
+</PRE>
+
+<H3>See Also</H3>
+
+<P>
+<A HREF="#cupsLangDefault"><CODE>cupsLangDefault()</CODE></A>,
+<A HREF="#cupsLangEncoding"><CODE>cupsLangEncoding()</CODE></A>,
+<A HREF="#cupsUser"><CODE>cupsUser()</CODE></A>,
+<A HREF="#httpConnect"><CODE>httpConnect()</CODE></A>,
+<A HREF="#ippAddString"><CODE>ippAddString()</CODE></A>,
+<A HREF="#ippNew"><CODE>ippNew()</CODE></A>
+
+<!-- NEW PAGE --><H2><A NAME="cupsFreeOptions">cupsFreeOptions()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+void
+cupsFreeOptions(int num_options,
+ cups_option_t *options);
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>num_options</TD>
+ <TD>Number of options in array.</TD>
+</TR>
+<TR>
+ <TD>options</TD>
+ <TD>Pointer to options array.</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Description</H3>
+
+<P><CODE>cupsFreeOptions()</CODE> frees all memory associated with the
+option array specified.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+int num_options;
+cups_option_t *options;
+
+...
+
+cupsFreeOptions(num_options, options);
+</PRE>
+
+<H3>See Also</H3>
+
+<P>
+<A HREF="#cupsAddOption">cupsAddOption()</A>,
+<A HREF="#cupsGetOption">cupsGetOption()</A>,
+<A HREF="#cupsMarkOptions">cupsMarkOptions()</A>,
+<A HREF="#cupsParseOptions">cupsParseOptions()</A>
+
+<!-- NEW PAGE --><H2><A NAME="cupsGetClasses">cupsGetClasses()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+int
+cupsGetClasses(char ***classes);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>classes</TD>
+ <TD>Pointer to character pointer array.</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>The number of printer classes available.
+
+<H3>Description</H3>
+
+<P><CODE>cupsGetClasses()</CODE> gets a list of the available printer classes.
+The returned array should be freed using the <CODE>free()</CODE> when it is
+no longer needed.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+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);
+}
+</PRE>
+
+<H3>See Also</H3>
+
+<P>
+<A HREF="#cupsGetDefault">cupsGetDefault()</CODE>,
+<A HREF="#cupsGetPrinters">cupsGetPrinters()</CODE>
+
+<!-- NEW PAGE --><H2><A NAME="cupsGetDefault">cupsGetDefault()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+const char *
+cupsGetDefault(void);
+</PRE>
+
+<H3>Returns</H3>
+
+<P>A pointer to the default destination.
+
+<H3>Description</H3>
+
+<P><CODE>cupsGetDefault()</CODE> 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.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+printf("The default destination is %s\n", cupsGetDefault());
+</PRE>
+
+<H3>See Also</H3>
+
+<P>
+<A HREF="#cupsGetClasses">cupsGetClasses()</CODE>,
+<A HREF="#cupsGetPrinters">cupsGetPrinters()</CODE>
+
+<!-- NEW PAGE --><H2><A NAME="cupsGetOption">cupsGetOption()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+const char *
+cupsGetOption(const char *name,
+ int num_options,
+ cups_option_t *options);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>name</TD>
+ <TD>The name of the option.</TD>
+</TR>
+<TR>
+ <TD>num_options</TD>
+ <TD>The number of options in the array.</TD>
+</TR>
+<TR>
+ <TD>options</TD>
+ <TD>The options array.</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>A pointer to the option values or <CODE>NULL</CODE> if the option is
+not defined.
+
+<H3>Description</H3>
+
+<P><CODE>cupsGetOption()</CODE> returns the first occurrence of the
+named option. If the option is not included in the options array then a
+<CODE>NULL</CODE> pointer is returned.
+
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+int num_options;
+cups_option_t *options;
+const char *media;
+
+...
+
+media = cupsGetOption("media", num_options, options);
+</PRE>
+
+<H3>See Also</H3>
+
+<P>
+<A HREF="#cupsAddOption">cupsAddOption()</A>,
+<A HREF="#cupsFreeOptions">cupsFreeOptions()</A>,
+<A HREF="#cupsMarkOptions">cupsMarkOptions()</A>,
+<A HREF="#cupsParseOptions">cupsParseOptions()</A>
+
+<!-- NEW PAGE --><H2><A NAME="cupsGetPassword">cupsGetPassword()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+const char *
+cupsGetPassword(const char *prompt);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>prompt</TD>
+ <TD>The prompt to display to the user.</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>A pointer to the password that was entered or <CODE>NULL</CODE> if no
+password was entered.
+
+<H3>Description</H3>
+
+<P><CODE>cupsGetPassword()</CODE> displays the prompt string and asks the user
+for a password. The password text is not echoed to the user.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+char *password;
+
+...
+
+password = cupsGetPassword("Please enter a password:");
+</PRE>
+
+<H3>See Also</H3>
+
+<P>
+<A HREF="#cupsServer">cupsServer()</A>,
+<A HREF="#cupsSetPasswordCB">cupsSetPasswordCB()</A>,
+<A HREF="#cupsSetServer">cupsSetServer()</A>,
+<A HREF="#cupsSetUser">cupsSetUser()</A>,
+<A HREF="#cupsUser">cupsUser()</A>
+
+<!-- NEW PAGE --><H2><A NAME="cupsGetPPD">cupsGetPPD()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+const char *
+cupsGetPPD(const char *printer);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>printer</TD>
+ <TD>The name of the printer.</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>The name of a temporary file containing the PPD file or <CODE>NULL</CODE>
+if the printer cannot be located or does not have a PPD file.
+
+<H3>Description</H3>
+
+<P><CODE>cupsGetPPD()</CODE> gets a copy of the PPD file for the named printer.
+The printer name can be of the form "printer" or "printer@hostname".
+
+<P>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 <CODE>cupsGetPPD()</CODE>.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+char *ppd;
+
+...
+
+ppd = cupsGetPPD("printer@hostname");
+
+...
+
+unlink(ppd);
+</PRE>
+
+<!-- NEW PAGE --><H2><A NAME="cupsGetPrinters">cupsGetPrinters()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+int
+cupsGetPrinters(char ***printers);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>printers</TD>
+ <TD>Pointer to character pointer array.</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>The number of printer printers available.
+
+<H3>Description</H3>
+
+<P><CODE>cupsGetPrinters()</CODE> gets a list of the available printers.
+The returned array should be freed using the <CODE>free()</CODE> when it is
+no longer needed.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+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);
+}
+</PRE>
+
+<H3>See Also</H3>
+
+<P>
+<A HREF="#cupsGetClasses">cupsGetClasses()</CODE>,
+<A HREF="#cupsGetDefault">cupsGetDefault()</CODE>
+
+<!-- NEW PAGE --><H2><A NAME="cupsLangDefault">cupsLangDefault()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+const char *
+cupsLangDefault(void);
+</PRE>
+
+<H3>Returns</H3>
+
+<P>A pointer to the default language structure.
+
+<H3>Description</H3>
+
+<P><CODE>cupsLangDefault()</CODE> returns a language structure for the default
+language. The default language is defined by the <CODE>LANG</CODE> environment
+variable. If the specified language cannot be located then the POSIX (English)
+locale is used.
+
+<P>Call <CODE>cupsLangFree()</CODE> to free any memory associated with the
+language structure when you are done.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/language.h&gt;
+
+cups_lang_t *language;
+...
+
+language = cupsLangDefault();
+
+...
+
+cupsLangFree(language);
+</PRE>
+
+<H3>See Also</H3>
+
+<P>
+<A HREF="#cupsLangEncoding">cupsLangEncoding()</A>,
+<A HREF="#cupsLangFlush">cupsLangFlush()</A>,
+<A HREF="#cupsLangFree">cupsLangFree()</A>,
+<A HREF="#cupsLangGet">cupsLangGet()</A>,
+<A HREF="#cupsLangString">cupsLangString()</A>
+
+<!-- NEW PAGE --><H2><A NAME="cupsLangEncoding">cupsLangEncoding()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+char *
+cupsLangEncoding(cups_lang_t *language);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>language</TD>
+ <TD>The language structure.</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>A pointer to the encoding string.
+
+<H3>Description</H3>
+
+<P><CODE>cupsLangEncoding()</CODE> returns the language encoding used for the
+specified language, e.g. "iso-8859-1", "utf-8", etc.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/language.h&gt;
+
+cups_lang_t *language;
+char *encoding;
+...
+
+language = cupsLangDefault();
+encoding = cupsLangEncoding(language);
+...
+
+cupsLangFree(language);
+</PRE>
+
+<H3>See Also</H3>
+
+<P>
+<A HREF="#cupsLangDefault">cupsLangDefault()</A>,
+<A HREF="#cupsLangFlush">cupsLangFlush()</A>,
+<A HREF="#cupsLangFree">cupsLangFree()</A>,
+<A HREF="#cupsLangGet">cupsLangGet()</A>,
+<A HREF="#cupsLangString">cupsLangString()</A>
+
+<!-- NEW PAGE --><H2><A NAME="cupsLangFlush">cupsLangFlush()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+void
+cupsLangFlush(void);
+</PRE>
+
+<H3>Description</H3>
+
+<P><CODE>cupsLangFlush()</CODE> frees all language structures that have been
+allocated.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/language.h&gt;
+
+...
+
+cupsLangFlush();
+</PRE>
+
+<H3>See Also</H3>
+
+<P>
+<A HREF="#cupsLangDefault">cupsLangDefault()</A>,
+<A HREF="#cupsLangEncoding">cupsLangEncoding()</A>,
+<A HREF="#cupsLangFree">cupsLangFree()</A>,
+<A HREF="#cupsLangGet">cupsLangGet()</A>,
+<A HREF="#cupsLangString">cupsLangString()</A>
+
+<!-- NEW PAGE --><H2><A NAME="cupsLangFree">cupsLangFree()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+void
+cupsLangFree(cups_lang_t *language);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>language</TD>
+ <TD>The language structure to free.</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Description</H3>
+
+<P><CODE>cupsLangFree()</CODE> frees the specified language structure.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/language.h&gt;
+
+cups_lang_t *language;
+...
+
+cupsLangFree(language);
+</PRE>
+
+<H3>See Also</H3>
+
+<P>
+<A HREF="#cupsLangDefault">cupsLangDefault()</A>,
+<A HREF="#cupsLangEncoding">cupsLangEncoding()</A>,
+<A HREF="#cupsLangFlush">cupsLangFlush()</A>,
+<A HREF="#cupsLangGet">cupsLangGet()</A>,
+<A HREF="#cupsLangString">cupsLangString()</A>
+
+<!-- NEW PAGE --><H2><A NAME="cupsLangGet">cupsLangGet()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+cups_lang_t *
+cupsLangGet(const char *name);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>name</TD>
+ <TD>The name of the locale.</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>A pointer to a language structure.
+
+<H3>Description</H3>
+
+<P><CODE>cupsLangGet()</CODE> returns a language structure for the specified
+locale. If the locale is not defined then the POSIX (English) locale is
+substituted.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/language.h&gt;
+
+cups_lang_t *language;
+
+...
+
+language = cupsLangGet("fr");
+
+...
+
+cupsLangFree(language);
+</PRE>
+
+<H3>See Also</H3>
+
+<P>
+<A HREF="#cupsLangDefault">cupsLangDefault()</A>,
+<A HREF="#cupsLangEncoding">cupsLangEncoding()</A>,
+<A HREF="#cupsLangFlush">cupsLangFlush()</A>,
+<A HREF="#cupsLangFree">cupsLangFree()</A>,
+<A HREF="#cupsLangString">cupsLangString()</A>
+
+<!-- NEW PAGE --><H2><A NAME="cupsLangString">cupsLangString()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+char *
+cupsLangString(cups_lang_t *language,
+ int message);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>language</TD>
+ <TD>The language to query.</TD>
+</TR>
+<TR>
+ <TD>message</TD>
+ <TD>The message number.</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>A pointer to the message string or <CODE>NULL</CODE> if the message is
+not defined.
+
+<H3>Description</H3>
+
+<P><CODE>cupsLangString()</CODE> returns a pointer to the specified message
+string in the specified language.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/language.h&gt;
+
+cups_lang_t *language;
+char *s;
+...
+
+language = cupsLangGet("fr");
+
+s = cupsLangString(language, CUPS_MSG_YES);
+
+...
+
+cupsLangFree(language);
+</PRE>
+
+<H3>See Also</H3>
+
+<P>
+<A HREF="#cupsLangDefault">cupsLangDefault()</A>,
+<A HREF="#cupsLangEncoding">cupsLangEncoding()</A>,
+<A HREF="#cupsLangFlush">cupsLangFlush()</A>,
+<A HREF="#cupsLangFree">cupsLangFree()</A>,
+<A HREF="#cupsLangGet">cupsLangGet()</A>
+
+<!-- NEW PAGE --><H2><A NAME="cupsLastError">cupsLastError()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+ipp_status_t
+cupsLastError(void);
+</PRE>
+
+<H3>Returns</H3>
+
+<P>An enumeration containing the last IPP error.
+
+<H3>Description</H3>
+
+<P><CODE>cupsLastError()</CODE> returns the last IPP error that occurred.
+If no error occurred then it will return <CODE>IPP_OK</CODE> or
+<CODE>IPP_OK_CONFLICT</CODE>.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+ipp_status_t status;
+
+...
+
+status = cupsLastError();
+</PRE>
+
+<H3>See Also</H3>
+
+<P>
+<A HREF="#cupsCancelJob">cupsCancelJob()</A>,
+<A HREF="#cupsPrintFile">cupsPrintFile()</A>
+
+<!-- NEW PAGE --><H2><A NAME="cupsMarkOptions">cupsMarkOptions()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+int
+cupsMarkOptions(ppd_file_t *ppd,
+ int num_options,
+ cups_option_t *options);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>ppd</TD>
+ <TD>The PPD file to mark.</TD>
+</TR>
+<TR>
+ <TD>num_options</TD>
+ <TD>The number of options in the options array.</TD>
+</TR>
+<TR>
+ <TD>options</TD>
+ <TD>A pointer to the options array.</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>The number of conflicts found.
+
+<H3>Description</H3>
+
+<P><CODE>cupsMarkOptions()</CODE> marks options in the PPD file. It also
+handles mapping of IPP option names and values to PPD option names.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+int num_options;
+cups_option_t *options;
+ppd_file_t *ppd;
+
+...
+
+cupsMarkOptions(ppd, num_options, options);
+</PRE>
+
+<H3>See Also</H3>
+
+<P>
+<A HREF="#cupsAddOption">cupsAddOption()</A>,
+<A HREF="#cupsFreeOptions">cupsFreeOptions()</A>,
+<A HREF="#cupsGetOption">cupsGetOption()</A>,
+<A HREF="#cupsParseOptions">cupsParseOptions()</A>
+
+<!-- NEW PAGE --><H2><A NAME="cupsParseOptions">cupsParseOptions()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+int
+cupsParseOptions(const char *arg,
+ int num_options,
+ cups_option_t **options);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>arg</TD>
+ <TD>The string containing one or more options.</TD>
+</TR>
+<TR>
+ <TD>num_options</TD>
+ <TD>The number of options in the options array.</TD>
+</TR>
+<TR>
+ <TD>options</TD>
+ <TD>A pointer to the options array pointer.</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>The new number of options in the array.
+
+<H3>Description</H3>
+
+<P><CODE>cupsParseOptions()</CODE> 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.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+int num_options;
+cups_option_t *options;
+
+...
+
+num_options = 0;
+options = (cups_option_t *)0;
+num_options = cupsParseOptions(argv[5], num_options, &amp;options);
+</PRE>
+
+<H3>See Also</H3>
+
+<P>
+<A HREF="#cupsAddOption">cupsAddOption()</A>,
+<A HREF="#cupsFreeOptions">cupsFreeOptions()</A>,
+<A HREF="#cupsGetOption">cupsGetOption()</A>,
+<A HREF="#cupsMarkOptions">cupsMarkOptions()</A>
+
+<!-- NEW PAGE --><H2><A NAME="cupsPrintFile">cupsPrintFile()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+int
+cupsPrintFile(const char *printer,
+ const char *filename,
+ const char *title,
+ int num_options,
+ cups_option_t *options);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>printer</TD>
+ <TD>The printer or class to print to.</TD>
+</TR>
+<TR>
+ <TD>filename</TD>
+ <TD>The file to print.</TD>
+</TR>
+<TR>
+ <TD>title</TD>
+ <TD>The job title.</TD>
+</TR>
+<TR>
+ <TD>num_options</TD>
+ <TD>The number of options in the options array.</TD>
+</TR>
+<TR>
+ <TD>options</TD>
+ <TD>A pointer to the options array.</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>The new job ID number or 0 on error.
+
+<H3>Description</H3>
+
+<P><CODE>cupsPrintFile()</CODE> 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 <CODE>cupsLastError()</CODE>.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+int num_options;
+cups_option_t *options;
+int jobid;
+
+...
+
+jobid = cupsPrintFile("printer@hostname", "filename.ps", "Job Title",
+ num_options, options);
+</PRE>
+
+<H3>See Also</H3>
+
+<P>
+<A HREF="#cupsCancelJob">cupsCancelJob()</A>,
+<A HREF="#cupsLastError">cupsLastError()</A>,
+<A HREF="#cupsPrintFiles">cupsPrintFiles()</A>
+
+<!-- NEW PAGE --><H2><A NAME="cupsPrintFiles">cupsPrintFiles()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+int
+cupsPrintFiles(const char *printer,
+ int num_files,
+ const char **files,
+ const char *title,
+ int num_options,
+ cups_option_t *options);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>printer</TD>
+ <TD>The printer or class to print to.</TD>
+</TR>
+<TR>
+ <TD>num_files</TD>
+ <TD>The number of files to print.</TD>
+</TR>
+<TR>
+ <TD>files</TD>
+ <TD>The files to print.</TD>
+</TR>
+<TR>
+ <TD>title</TD>
+ <TD>The job title.</TD>
+</TR>
+<TR>
+ <TD>num_options</TD>
+ <TD>The number of options in the options array.</TD>
+</TR>
+<TR>
+ <TD>options</TD>
+ <TD>A pointer to the options array.</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>The new job ID number or 0 on error.
+
+<H3>Description</H3>
+
+<P><CODE>cupsPrintFiles()</CODE> sends multiple files to the specified
+printer or class for printing. If the job cannot be printed the error
+code can be found by calling <CODE>cupsLastError()</CODE>.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+int num_files;
+const char *files[100];
+int num_options;
+cups_option_t *options;
+int jobid;
+
+...
+
+jobid = cupsPrintFiles("printer@hostname", num_files, files,
+ "Job Title", num_options, options);
+</PRE>
+
+<H3>See Also</H3>
+
+<P>
+<A HREF="#cupsCancelJob">cupsCancelJob()</A>,
+<A HREF="#cupsLastError">cupsLastError()</A>,
+<A HREF="#cupsPrintFile">cupsPrintFile()</A>
+
+<!-- NEW PAGE --><H2><A NAME="cupsRasterClose">cupsRasterClose()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+void
+cupsRasterClose(cups_raster_t *ras);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>ras</TD>
+ <TD>The raster stream to close.</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Description</H3>
+
+<P><CODE>cupsRasterClose()</CODE> closes the specified raster stream.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/raster.h&gt;
+
+cups_raster_t *ras;
+
+...
+
+cupsRasterClose(ras);
+</PRE>
+
+<H3>See Also</H3>
+
+<P>
+<A HREF="#cupsRasterOpen">cupsRasterOpen()</A>,
+<A HREF="#cupsRasterReadHeader">cupsRasterReadHeader()</A>,
+<A HREF="#cupsRasterReadPixels">cupsRasterReadPixels()</A>,
+<A HREF="#cupsRasterWriteHeader">cupsRasterWriteHeader()</A>,
+<A HREF="#cupsRasterWritePixels">cupsRasterWritePixels()</A>
+
+
+<!-- NEW PAGE --><H2><A NAME="cupsRasterOpen">cupsRasterOpen()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+cups_raster_t *
+cupsRasterOpen(int fd,
+ cups_mode_t mode);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>fd</TD>
+ <TD>The file descriptor to use.</TD>
+</TR>
+<TR>
+ <TD>mode</TD>
+ <TD>The mode to use; <CODE>CUPS_RASTER_READ</CODE> or
+ <CODE>CUPS_RASTER_WRITE</CODE>.</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>A pointer to a raster stream or <CODE>NULL</CODE> if there was an error.
+
+<H3>Description</H3>
+
+<P><CODE>cupsRasterOpen()</CODE> opens a raster stream for reading or writing.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/raster.h&gt;
+
+cups_raster_t *ras;
+
+...
+
+ras = cupsRasterOpen(0, CUPS_RASTER_READ);
+</PRE>
+
+<H3>See Also</H3>
+
+<P>
+<A HREF="#cupsRasterClose">cupsRasterClose()</A>,
+<A HREF="#cupsRasterReadHeader">cupsRasterReadHeader()</A>,
+<A HREF="#cupsRasterReadPixels">cupsRasterReadPixels()</A>,
+<A HREF="#cupsRasterWriteHeader">cupsRasterWriteHeader()</A>,
+<A HREF="#cupsRasterWritePixels">cupsRasterWritePixels()</A>
+
+<!-- NEW PAGE --><H2><A NAME="cupsRasterReadHeader">cupsRasterReadHeader()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+unsigned
+cupsRasterReadHeader(cups_raster_t *ras,
+ cups_page_header_t *header);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>ras</TD>
+ <TD>The raster stream to read from.</TD>
+</TR>
+<TR>
+ <TD>header</TD>
+ <TD>A pointer to a page header structure to read into.</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>1 on success, 0 on EOF or error.
+
+<H3>Description</H3>
+
+<P><CODE>cupsRasterReadHeader()</CODE> reads a page header from the specified
+raster stream.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/raster.h&gt;
+
+int line;
+cups_raster_t *ras;
+cups_raster_header_t header;
+unsigned char pixels[8192];
+...
+
+while (cupsRasterReadHeader(ras, &amp;header))
+{
+ ...
+
+ for (line = 0; line &lt; header.cupsHeight; line ++)
+ {
+ cupsRasterReadPixels(ras, pixels, header.cupsBytesPerLine);
+
+ ...
+ }
+}
+</PRE>
+
+<H3>See Also</H3>
+
+<P>
+<A HREF="#cupsRasterClose">cupsRasterClose()</A>,
+<A HREF="#cupsRasterOpen">cupsRasterOpen()</A>,
+<A HREF="#cupsRasterReadPixels">cupsRasterReadPixels()</A>,
+<A HREF="#cupsRasterWriteHeader">cupsRasterWriteHeader()</A>,
+<A HREF="#cupsRasterWritePixels">cupsRasterWritePixels()</A>
+
+<!-- NEW PAGE --><H2><A NAME="cupsRasterReadPixels">cupsRasterReadPixels()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+unsigned
+cupsRasterReadPixels(cups_raster_t *ras,
+ unsigned char *pixels,
+ unsigned length);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>ras</TD>
+ <TD>The raster stream to read from.</TD>
+</TR>
+<TR>
+ <TD>pixels</TD>
+ <TD>The pointer to a pixel buffer.</TD>
+</TR>
+<TR>
+ <TD>length</TD>
+ <TD>The number of bytes of pixel data to read.</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>The number of bytes read or 0 on EOF or error.
+
+<H3>Description</H3>
+
+<P><CODE>cupsRasterReadPixels()</CODE> reads pixel data from the specified
+raster stream.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/raster.h&gt;
+
+int line;
+cups_raster_t *ras;
+cups_raster_header_t header;
+unsigned char pixels[8192];
+...
+
+while (cupsRasterReadHeader(ras, &amp;header))
+{
+ ...
+
+ for (line = 0; line &lt; header.cupsHeight; line ++)
+ {
+ cupsRasterReadPixels(ras, pixels, header.cupsBytesPerLine);
+
+ ...
+ }
+}
+</PRE>
+
+<H3>See Also</H3>
+
+<P>
+<A HREF="#cupsRasterClose">cupsRasterClose()</A>,
+<A HREF="#cupsRasterOpen">cupsRasterOpen()</A>,
+<A HREF="#cupsRasterReadHeader">cupsRasterReadHeader()</A>,
+<A HREF="#cupsRasterWriteHeader">cupsRasterWriteHeader()</A>,
+<A HREF="#cupsRasterWritePixels">cupsRasterWritePixels()</A>
+
+<!-- NEW PAGE --><H2><A NAME="cupsRasterWriteHeader">cupsRasterWriteHeader()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+unsigned
+cupsRasterWriteHeader(cups_raster_t *ras,
+ cups_page_header_t *header);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>ras</TD>
+ <TD>The raster stream to write to.</TD>
+</TR>
+<TR>
+ <TD>header</TD>
+ <TD>A pointer to the page header to write.</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>1 on success, 0 on error.
+
+<H3>Description</H3>
+
+<P><CODE>cupsRasterWriteHeader()</CODE> writes the specified page header to
+a raster stream.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/raster.h&gt;
+
+int line;
+cups_raster_t *ras;
+cups_raster_header_t header;
+unsigned char pixels[8192];
+...
+
+cupsRasterWriteHeader(ras, &amp;header);
+
+for (line = 0; line &lt; header.cupsHeight; line ++)
+{
+ ...
+
+ cupsRasterWritePixels(ras, pixels, header.cupsBytesPerLine);
+}
+</PRE>
+
+<H3>See Also</H3>
+
+<P>
+<A HREF="#cupsRasterClose">cupsRasterClose()</A>,
+<A HREF="#cupsRasterOpen">cupsRasterOpen()</A>,
+<A HREF="#cupsRasterReadHeader">cupsRasterReadHeader()</A>,
+<A HREF="#cupsRasterReadPixels">cupsRasterReadPixels()</A>,
+<A HREF="#cupsRasterWritePixels">cupsRasterWritePixels()</A>
+
+<!-- NEW PAGE --><H2><A NAME="cupsRasterWritePixels">cupsRasterWritePixels()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+unsigned
+cupsRasterWritePixels(cups_raster_t *ras,
+ unsigned char *pixels,
+ unsigned length);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>ras</TD>
+ <TD>The raster stream to write to.</TD>
+</TR>
+<TR>
+ <TD>pixels</TD>
+ <TD>The pixel data to write.</TD>
+</TR>
+<TR>
+ <TD>length</TD>
+ <TD>The number of bytes to write.</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>The number of bytes written.
+
+<H3>Description</H3>
+
+<P><CODE>cupsRasterWritePixels()</CODE> writes the specified pixel data to a
+raster stream.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/raster.h&gt;
+
+int line;
+cups_raster_t *ras;
+cups_raster_header_t header;
+unsigned char pixels[8192];
+...
+
+cupsRasterWriteHeader(ras, &amp;header);
+
+for (line = 0; line &lt; header.cupsHeight; line ++)
+{
+ ...
+
+ cupsRasterWritePixels(ras, pixels, header.cupsBytesPerLine);
+}
+</PRE>
+
+<H3>See Also</H3>
+
+<P>
+<A HREF="#cupsRasterClose">cupsRasterClose()</A>,
+<A HREF="#cupsRasterOpen">cupsRasterOpen()</A>,
+<A HREF="#cupsRasterReadHeader">cupsRasterReadHeader()</A>,
+<A HREF="#cupsRasterReadPixels">cupsRasterReadPixels()</A>,
+<A HREF="#cupsRasterWriteHeader">cupsRasterWriteHeader()</A>
+
+<!-- NEW PAGE --><H2><A NAME="cupsServer">cupsServer()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+const char *
+cupsServer(void);
+</PRE>
+
+<H3>Returns</H3>
+
+<P>A pointer to the default server name.
+
+<H3>Description</H3>
+
+<P><CODE>cupsServer()</CODE> 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 <CODE>cupsServer()</CODE>
+
+<P>The default server is determined from the following locations:
+
+<OL>
+
+ <LI>The <CODE>CUPS_SERVER</CODE> environment variable,
+
+ <LI>The <CODE>ServerName</CODE> directive in the
+ <VAR>client.conf</VAR> file,
+
+ <LI>The default host, "localhost".
+
+</OL>
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+const char *server;
+
+server = cupsServer();
+</PRE>
+
+<H3>See Also</H3>
+
+<P>
+<A HREF="#cupsGetPassword">cupsGetPassword()</A>,
+<A HREF="#cupsSetPasswordCB">cupsSetPasswordCB()</A>,
+<A HREF="#cupsSetServer">cupsSetServer()</A>,
+<A HREF="#cupsSetUser">cupsSetUser()</A>,
+<A HREF="#cupsUser">cupsUser()</A>
+
+<!-- NEW PAGE --><H2><A NAME="cupsSetPasswordCB">cupsSetPasswordCB()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+void
+cupsSetPasswordCB(const char *(*cb)(const char *prompt));
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>cb</TD>
+ <TD>The password callback function.</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Description</H3>
+
+<P><CODE>cupsSetPasswordCB()</CODE> sets the callback function to use when
+asking the user for a password. The callback function must accept a single
+character string pointer (the prompt string) and return <CODE>NULL</CODE>
+if the user did not enter a password string or a pointer to the password
+string otherwise.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+const char *
+my_password_cb(const char *prompt)
+{
+ return (getpass(prompt));
+}
+
+...
+
+char *password;
+
+...
+
+cupsSetPasswordCB(my_password_cb);
+password = cupsGetPassword("Please enter a password:");
+</PRE>
+
+<H3>See Also</H3>
+
+<P>
+<A HREF="#cupsServer">cupsServer()</A>,
+<A HREF="#cupsSetServer">cupsSetServer()</A>,
+<A HREF="#cupsSetUser">cupsSetUser()</A>,
+<A HREF="#cupsUser">cupsUser()</A>
+
+<!-- NEW PAGE --><H2><A NAME="cupsSetServer">cupsSetServer()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+void
+cupsSetServer(const char *server);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>server</TD>
+ <TD>The default server to use.</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Description</H3>
+
+<P><CODE>cupsSetServer()</CODE> sets the default server to use for
+the CUPS API. If the <CODE>server</CODE> argument is <CODE>NULL</CODE>,
+the default server is used.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+cupsSetServer("foo.bar.com");
+</PRE>
+
+<H3>See Also</H3>
+
+<P>
+<A HREF="#cupsServer">cupsServer()</A>,
+<A HREF="#cupsSetPasswordCB">cupsSetPasswordCB()</A>,
+<A HREF="#cupsSetUser">cupsSetUser()</A>,
+<A HREF="#cupsUser">cupsUser()</A>
+
+<!-- NEW PAGE --><H2><A NAME="cupsSetUser">cupsSetUser()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+void
+cupsSetUser(const char *user);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>user</TD>
+ <TD>The user name string to use.</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Description</H3>
+
+<P><CODE>cupsSetUser()</CODE> sets the default user name for authentication.
+If the <CODE>user</CODE> argument is <CODE>NULL</CODE> then the current
+login user is used.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+...
+
+cupsSetUser("root");
+</PRE>
+
+<H3>See Also</H3>
+
+<P>
+<A HREF="#cupsServer">cupsServer()</A>,
+<A HREF="#cupsSetPasswordCB">cupsSetPasswordCB()</A>,
+<A HREF="#cupsSetServer">cupsSetServer()</A>,
+<A HREF="#cupsUser">cupsUser()</A>
+
+<!-- NEW PAGE --><H2><A NAME="cupsTempFile">cupsTempFile()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+char *
+cupsTempFile(char *filename,
+ int length);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>filename</TD>
+ <TD>The character string to hold the temporary filename.</TD>
+</TR>
+<TR>
+ <TD>length</TD>
+ <TD>The size of the filename string in bytes.</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>A pointer to <CODE>filename</CODE>.
+
+<H3>Description</H3>
+
+<P><CODE>cupsTempFile()</CODE> generates a temporary filename for the
+<VAR>/var/tmp</VAR> directory or the directory specified by the
+<CODE>TMPDIR</CODE> environment variable.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+char filename[256];
+
+cupsTempFile(filename, sizeof(filename));
+</PRE>
+
+<!-- NEW PAGE --><H2><A NAME="cupsUser">cupsUser()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+const char *
+cupsUser(void);
+</PRE>
+
+<H3>Returns</H3>
+
+<P>A pointer to the current username or <CODE>NULL</CODE> if the user ID is
+undefined.
+
+<H3>Description</H3>
+
+<P><CODE>cupsUser()</CODE> returns the name associated with the current
+user ID as reported by the <CODE>getuid()</CODE> system call.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/cups.h&gt;
+
+const char *user;
+
+user = cupsUser();
+</PRE>
+
+<H3>See Also</H3>
+
+<P>
+<A HREF="#cupsGetPassword">cupsGetPassword()</A>,
+<A HREF="#cupsServer">cupsServer()</A>
+
+<!-- NEW PAGE --><H2><A NAME="httpBlocking">httpBlocking()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+void httpBlocking(http_t *http, int blocking)
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>http</TD>
+ <TD>The HTTP connection</TD>
+</TR>
+<TR>
+ <TD>blocking</TD>
+ <TD>0 if the connection should be non-blocking, 1 if it should
+ be blocking</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Description</H3>
+
+<P>The <CODE>httpBlocking()</CODE> function sets the blocking mode for the
+HTTP connection. By default HTTP connections will block (stop) the client
+program until data is available or can be sent to the server.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/http.h&gt;
+
+http_t *http;
+
+http = httpConnect("server", port);
+httpBlocking(http, 0);
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#httpCheck"><CODE>httpCheck()</CODE></A>,
+<A HREF="#httpConnect"><CODE>httpConnect()</CODE></A>
+
+<!-- NEW PAGE --><H2><A NAME="httpCheck">httpCheck()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+int httpCheck(http_t *http);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>http</TD>
+ <TD>The HTTP connection</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>0 if there is no data pending, 1 otherwise.
+
+<H3>Description</H3>
+
+<P>The <CODE>httpCheck()</CODE> function checks to see if there is any data
+pending on an HTTP connection.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/http.h&gt;
+
+http_t *http;
+
+if (httpCheck(http))
+{
+ ... do something ...
+}
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#httpBlocking"><CODE>httpBlocking()</CODE></A>,
+<A HREF="#httpConnect"><CODE>httpConnect()</CODE></A>,
+<A HREF="#httpGets"><CODE>httpGets()</CODE></A>,
+<A HREF="#httpRead"><CODE>httpRead()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="httpClearFields">httpClearFields()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+void httpClearFields(http_t *http)
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>http</TD>
+ <TD>The HTTP connection</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Description</H3>
+
+<P>The <CODE>httpClearFields()</CODE> function clears all HTTP request fields
+for the HTTP connection.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/http.h&gt;
+
+http_t *http;
+
+httpClearFields(http);
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#httpConnect"><CODE>httpConnect()</CODE></A>,
+<A HREF="#httpGetField"><CODE>httpGetField()</CODE></A>,
+<A HREF="#httpSetField"><CODE>httpSetField()</CODE></A>
+
+<!-- NEW PAGE --><H2><A NAME="httpClose">httpClose()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+void httpClose(http_t *http);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>http</TD>
+ <TD>The HTTP connection</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Description</H3>
+
+<P>The <CODE>httpClose()</CODE> function closes an active HTTP connection.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/http.h&gt;
+
+http_t *http;
+
+httpClose(http);
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#httpConnect"><CODE>httpConnect()</CODE></A>
+
+<!-- NEW PAGE --><H2><A NAME="httpConnect">httpConnect()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+http_t *httpConnect(const char *hostname, int port);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>hostname</TD>
+ <TD>The name or IP address of the server to connect to</TD>
+</TR>
+<TR>
+ <TD>port</TD>
+ <TD>The port number to use</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>A pointer to a HTTP connection structure or NULL if the connection could
+not be made.
+
+<H3>Description</H3>
+
+<P>The <CODE>httpConnect()</CODE> function opens a HTTP connection to the
+specified server and port.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/http.h&gt;
+
+http_t *http;
+
+http = httpConnect(cupsServer(), ippPort());
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#httpClose"><CODE>httpClose()</CODE></A>,
+<A HREF="#httpGet"><CODE>httpGet()</CODE></A>,
+<A HREF="#httpGets"><CODE>httpGets()</CODE></A>,
+<A HREF="#httpPost"><CODE>httpPost()</CODE></A>,
+<A HREF="#httpRead"><CODE>httpRead()</CODE></A>,
+<A HREF="#httpWrite"><CODE>httpWrite()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="httpDecode64">httpDecode64()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+char *httpDecode64(char *out, const char *in);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>out</TD>
+ <TD>The output string</TD>
+</TR>
+<TR>
+ <TD>in</TD>
+ <TD>The input string</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>A pointer to the decoded string.
+
+<H3>Description</H3>
+
+<P>The <CODE>httpDecode64()</CODE> function decodes a base-64 encoded string
+to the original string.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/http.h&gt;
+
+char encoded_string[255];
+char original_string[255];
+
+httpDecode64(original_string, encoded_string);
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#httpEncode64"><CODE>httpEncode64()</CODE></A>
+
+<!-- NEW PAGE --><H2><A NAME="httpDelete">httpDelete()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+int httpDelete(http_t *http, const char *uri);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>http</TD>
+ <TD>The HTTP connection</TD>
+</TR>
+<TR>
+ <TD>uri</TD>
+ <TD>The URI to delete</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>0 on success, non-zero on failure.
+
+<H3>Description</H3>
+
+<P>The <CODE>httpDelete()</CODE> function sends a HTTP DELETE request to
+the server.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/http.h&gt;
+
+http_t *http;
+
+httpDelete(http, "/some/uri");
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#httpConnect"><CODE>httpConnect()</CODE></A>,
+<A HREF="#httpSetField"><CODE>httpSetField()</CODE></A>,
+<A HREF="#httpUpdate"><CODE>httpUpdate()</CODE></A>
+
+<!-- NEW PAGE --><H2><A NAME="httpEncode64">httpEncode64()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+char *httpEncode64(char *out, const char *in);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>out</TD>
+ <TD>The output string</TD>
+</TR>
+<TR>
+ <TD>in</TD>
+ <TD>The input string</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>A pointer to the encoded string.
+
+<H3>Description</H3>
+
+<P>The <CODE>httpEncode64()</CODE> function decodes a base-64 encoded string
+to the original string.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/http.h&gt;
+
+char encoded_string[255];
+char original_string[255];
+
+httpEncode64(encoded_string, original_string);
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#httpDecode64"><CODE>httpDecode64()</CODE></A>
+
+<!-- NEW PAGE --><H2><A NAME="httpError">httpError()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+int httpError(http_t *http);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>http</TD>
+ <TD>The HTTP connection</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>The last error that occurred or 0 if no error has occurred.
+
+<H3>Description</H3>
+
+<P>The <CODE>httpError()</CODE> function returns the last error that occurred
+on the HTTP connection.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/http.h&gt;
+
+http_t *http;
+
+if (httpError(http))
+{
+ ... show an error message ...
+}
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#httpConnect"><CODE>httpConnect()</CODE></A>
+
+<!-- NEW PAGE --><H2><A NAME="httpFlush">httpFlush()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+void httpFlush(http_t *http);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>http</TD>
+ <TD>The HTTP connection</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Description</H3>
+
+<P>The <CODE>httpFlush()</CODE> function flushes any remaining data left from
+a GET or POST operation.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/http.h&gt;
+
+http_t *http;
+
+httpFlush(http);
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#httpConnect"><CODE>httpConnect()</CODE></A>,
+
+<!-- NEW PAGE --><H2><A NAME="httpGet">httpGet()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+int httpGet(http_t *http, const char *uri);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>http</TD>
+ <TD>The HTTP connection</TD>
+</TR>
+<TR>
+ <TD>uri</TD>
+ <TD>The URI to get</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>0 on success, non-zero on failure.
+
+<H3>Description</H3>
+
+<P>The <CODE>httpGet()</CODE> function sends a HTTP GET request to the
+server.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/http.h&gt;
+
+http_t *http;
+
+httpGet(http, "/some/uri");
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#httpConnect"><CODE>httpConnect()</CODE></A>,
+<A HREF="#httpSetField"><CODE>httpSetField()</CODE></A>,
+<A HREF="#httpUpdate"><CODE>httpUpdate()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="httpGets">httpGets()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+char *httpGets(char *line, int length, http_t *http)
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>line</TD>
+ <TD>The string to fill with a line from the HTTP connection</TD>
+</TR>
+<TR>
+ <TD>length</TD>
+ <TD>The maximum length of the string</TD>
+</TR>
+<TR>
+ <TD>http</TD>
+ <TD>The HTTP connection</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>A pointer to the string or NULL if no line could be retrieved.
+
+<H3>Description</H3>
+
+<P>The <CODE>httpGets()</CODE> function is used to read a request line from
+the HTTP connection. It is not normally used by a client program.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/http.h&gt;
+
+http_t *http;
+char line[1024];
+
+if (httpGets(line, sizeof(line), http))
+{
+ ... process the line ...
+}
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#httpConnect"><CODE>httpConnect()</CODE></A>,
+<A HREF="#httpUpdate"><CODE>httpUpdate()</CODE></A>
+
+<!-- NEW PAGE --><H2><A NAME="httpGetDateString">httpGetDateString()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+const char *httpGetDateString(time_t time)
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>time</TD>
+ <TD>The UNIX date/time value</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>A pointer to a static string containing the HTTP date/time string for
+the specified UNIX time value.
+
+<H3>Description</H3>
+
+<P>The <CODE>httpGetDateString()</CODE> function generates a date/time string
+suitable for HTTP requests from a UNIX time value.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/http.h&gt;
+
+puts(httpGetDateString(time(NULL)));
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#httpGetDateTime"><CODE>httpGetDateTime()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="httpGetDateTime">httpGetDateTime()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+time_t httpGetDateTime(const char *date)
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>date</TD>
+ <TD>The HTTP date/time string</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>A UNIX time value.
+
+<H3>Description</H3>
+
+<P>The <CODE>httpGetDateTime()</CODE> function converts a HTTP
+date/time string to a UNIX time value.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/http.h&gt;
+
+printf("%d\n", httpGetDateTime("Fri, 30 June 2000 12:34:56 GMT"));
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#httpGetDateString"><CODE>httpGetDateString()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="httpGetField">httpGetField()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+const char *httpGetField(http_t *http, http_field_t field);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>http</TD>
+ <TD>The HTTP connection</TD>
+</TR>
+<TR>
+ <TD>field</TD>
+ <TD>The HTTP field</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>A pointer to the field value string.
+
+<H3>Description</H3>
+
+<P>The <CODE>httpGetField()</CODE> function returns the current value for
+the specified HTTP field.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/http.h&gt;
+
+http_t *http;
+
+httpGet(http, "/some/uri");
+while (httpUpdate(http) == HTTP_CONTINUE);
+
+puts(httpGetField(http, HTTP_FIELD_CONTENT_TYPE));
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#httpConnect"><CODE>httpConnect()</CODE></A>,
+<A HREF="#httpSetField"><CODE>httpSetField()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="httpHead">httpHead()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+int httpHead(http_t *http, const char *uri);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>http</TD>
+ <TD>The HTTP connection</TD>
+</TR>
+<TR>
+ <TD>uri</TD>
+ <TD>The URI to head</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>0 on success, non-zero on failure.
+
+<H3>Description</H3>
+
+<P>The <CODE>httpHead()</CODE> function sends a HTTP HEAD request to the
+server.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/http.h&gt;
+
+http_t *http;
+
+httpHead(http, "/some/uri");
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#httpConnect"><CODE>httpConnect()</CODE></A>,
+<A HREF="#httpSetField"><CODE>httpSetField()</CODE></A>,
+<A HREF="#httpUpdate"><CODE>httpUpdate()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="httpInitialize">httpInitialize()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+void httpInitialize(void);
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>httpInitialize()</CODE> function initializes the networking
+code as needed by the underlying platform. It is called automatically by
+the <CODE>httpConnect()</CODE> function.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/http.h&gt;
+
+httpInitialize();
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#httpConnect"><CODE>httpConnect()</CODE></A>
+
+<!-- NEW PAGE --><H2><A NAME="httpOptions">httpOptions()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+int httpOptions(http_t *http, const char *uri);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>http</TD>
+ <TD>The HTTP connection</TD>
+</TR>
+<TR>
+ <TD>uri</TD>
+ <TD>The URI to check for options</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>0 on success, non-zero on failure.
+
+<H3>Description</H3>
+
+<P>The <CODE>httpOptions()</CODE> function sends a HTTP OPTIONS request to the
+server.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/http.h&gt;
+
+http_t *http;
+
+httpOptions(http, "/some/uri");
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#httpConnect"><CODE>httpConnect()</CODE></A>,
+<A HREF="#httpSetField"><CODE>httpSetField()</CODE></A>,
+<A HREF="#httpUpdate"><CODE>httpUpdate()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="httpPost">httpPost()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+int httpPost(http_t *http, const char *uri);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>http</TD>
+ <TD>The HTTP connection</TD>
+</TR>
+<TR>
+ <TD>uri</TD>
+ <TD>The URI to post to</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>0 on success, non-zero on failure.
+
+<H3>Description</H3>
+
+<P>The <CODE>httpPost()</CODE> function sends a HTTP POST request to the
+server.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/http.h&gt;
+
+http_t *http;
+
+httpPost(http, "/some/uri");
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#httpConnect"><CODE>httpConnect()</CODE></A>,
+<A HREF="#httpSetField"><CODE>httpSetField()</CODE></A>,
+<A HREF="#httpUpdate"><CODE>httpUpdate()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="httpPrintf">httpPrintf()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+int httpPrintf(http_t *http, const char *format, ...);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>http</TD>
+ <TD>The HTTP connection</TD>
+</TR>
+<TR>
+ <TD>format</TD>
+ <TD>A printf-style format string</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>The number of bytes written.
+
+<H3>Description</H3>
+
+<P>The <CODE>httpPrintf()</CODE> function sends a formatted string to the
+HTTP connection. It is normally only used by the CUPS API and scheduler.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/http.h&gt;
+
+http_t *http;
+
+httpPrintf(http, "GET / HTTP/1.1 \r\n");
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#httpConnect"><CODE>httpConnect()</CODE></A>
+
+<!-- NEW PAGE --><H2><A NAME="httpPut">httpPut()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+int httpPut(http_t *http, const char *uri);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>http</TD>
+ <TD>The HTTP connection</TD>
+</TR>
+<TR>
+ <TD>uri</TD>
+ <TD>The URI to put</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>0 on success, non-zero on failure.
+
+<H3>Description</H3>
+
+<P>The <CODE>httpPut()</CODE> function sends a HTTP PUT request to the
+server.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/http.h&gt;
+
+http_t *http;
+
+httpDelete(http, "/some/uri");
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#httpConnect"><CODE>httpConnect()</CODE></A>,
+<A HREF="#httpSetField"><CODE>httpSetField()</CODE></A>,
+<A HREF="#httpUpdate"><CODE>httpUpdate()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="httpRead">httpRead()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+int httpRead(http_t *http, char *buffer, int length);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>http</TD>
+ <TD>The HTTP connection</TD>
+</TR>
+<TR>
+ <TD>buffer</TD>
+ <TD>The buffer to read into</TD>
+</TR>
+<TR>
+ <TD>length</TD>
+ <TD>The number of bytes to read</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>The number of bytes read or -1 on error.
+
+<H3>Description</H3>
+
+<P>The <CODE>httpRead()</CODE> function reads data from the HTTP connection,
+possibly the result of a GET or POST request.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/http.h&gt;
+
+http_t *http;
+char buffer[1024];
+int bytes;
+
+httpGet(http, "/");
+while (httpUpdate(http) != HTTP_CONTINUE);
+while ((bytes = httpRead(http, buffer, sizeof(buffer) - 1)) > 0)
+{
+ buffer[bytes] = '\0';
+ fputs(buffer, stdout);
+}
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#httpConnect"><CODE>httpConnect()</CODE></A>,
+<A HREF="#httpWrite"><CODE>httpWrite()</CODE></A>
+
+<!-- NEW PAGE --><H2><A NAME="httpReconnect">httpReconnect()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+int httpReconnect(http_t *http);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>http</TD>
+ <TD>The HTTP connection</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>0 on success, non-zero on failure.
+
+<H3>Description</H3>
+
+<P>The <CODE>httpReconnect()</CODE> function reconnects to the HTTP server.
+This is usually done automatically if the HTTP functions detect that the
+server connection has terminated.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/http.h&gt;
+
+http_t *http;
+
+httpReconnect(http);
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#httpConnect"><CODE>httpConnect()</CODE></A>
+
+<!-- NEW PAGE --><H2><A NAME="httpSeparate">httpSeparate()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+void httpSeparate(const char *uri, char *method,
+ char *username, char *host, int *port,
+ char *resource);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>uri</TD>
+ <TD>The URI to separate</TD>
+</TR>
+<TR>
+ <TD>method</TD>
+ <TD>The method (scheme) of the URI</TD>
+</TR>
+<TR>
+ <TD>username</TD>
+ <TD>The username (and password) portion of the URI, if any</TD>
+</TR>
+<TR>
+ <TD>host</TD>
+ <TD>The hostname portion of the URI, if any</TD>
+</TR>
+<TR>
+ <TD>port</TD>
+ <TD>The port number for the URI, either as specified or as
+ default for the method/scheme</TD>
+</TR>
+<TR>
+ <TD>resource</TD>
+ <TD>The resource string, usually a filename on the server</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Description</H3>
+
+<P>The <CODE>httpSeparate()</CODE> function separates the specified URI into
+its component parts. The method, username, hostname, and resource strings should
+be at least <CODE>HTTP_MAX_URI</CODE> characters long to avoid potential
+buffer overflow problems.
+
+<H3>Example</H3>
+
+<PRE>
+char uri[HTTP_MAX_URI];
+char method[HTTP_MAX_URI];
+char username[HTTP_MAX_URI];
+char host[HTTP_MAX_URI];
+char resource[HTTP_MAX_URI];
+int port;
+
+httpSeparate(uri, method, username, host, &amp;port, resource);
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#httpConnect"><CODE>httpConnect()</CODE></A>
+
+<!-- NEW PAGE --><H2><A NAME="httpSetField">httpSetField()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+void httpSetField(http_t *http, http_field_t field, const char *value);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>http</TD>
+ <TD>The HTTP connection</TD>
+</TR>
+<TR>
+ <TD>field</TD>
+ <TD>The HTTP field</TD>
+</TR>
+<TR>
+ <TD>value</TD>
+ <TD>The string value for the field</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Description</H3>
+
+<P>The <CODE>httpSetField()</CODE> function sets the current value for
+the specified HTTP field.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/http.h&gt;
+
+http_t *http;
+
+httpSetField(http, HTTP_FIELD_AUTHORIZATION, "Basic dfdr34453454325"));
+httpGet(http, "/some/uri");
+while (httpUpdate(http) == HTTP_CONTINUE);
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#httpConnect"><CODE>httpConnect()</CODE></A>,
+<A HREF="#httpGetField"><CODE>httpGetField()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="httpTrace">httpTrace()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+int httpTrace(http_t *http, const char *uri);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>http</TD>
+ <TD>The HTTP connection</TD>
+</TR>
+<TR>
+ <TD>uri</TD>
+ <TD>The URI to trace</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>0 on success, non-zero on failure.
+
+<H3>Description</H3>
+
+<P>The <CODE>httpTrace()</CODE> function sends a HTTP TRACE request to the
+server.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/http.h&gt;
+
+http_t *http;
+
+httpTrace(http, "/some/uri");
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#httpConnect"><CODE>httpConnect()</CODE></A>,
+<A HREF="#httpSetField"><CODE>httpSetField()</CODE></A>,
+<A HREF="#httpUpdate"><CODE>httpUpdate()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="httpUpdate">httpUpdate()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+http_status_t httpUpdate(http_t *http);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>http</TD>
+ <TD>The HTTP connection</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>The HTTP status of the current request.
+
+<H3>Description</H3>
+
+<P>The <CODE>httpUpdate()</CODE> function updates the current request status.
+It is used after any DELETE, GET, HEAD, OPTIONS, POST, PUT, or TRACE
+request to finalize the HTTP request and retrieve the request status.
+
+<P>Since proxies and the current blocking mode can cause the request to
+take longer, programs should continue calling <CODE>httpUpdate()</CODE>
+until the return status is not the constant value <CODE>HTTP_CONTINUE</CODE>.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/http.h&gt;
+
+http_t *http;
+http_status_t status;
+
+httpGet(http, "/some/uri");
+while ((status = httpUpdate(http)) == HTTP_CONTINUE);
+printf("Request status is %d\n", status);
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#httpConnect"><CODE>httpConnect()</CODE></A>,
+<A HREF="#httpDelete"><CODE>httpDelete()</CODE></A>,
+<A HREF="#httpGet"><CODE>httpGet()</CODE></A>,
+<A HREF="#httpHead"><CODE>httpHead()</CODE></A>,
+<A HREF="#httpOptions"><CODE>httpOptions()</CODE></A>,
+<A HREF="#httpPost"><CODE>httpPost()</CODE></A>,
+<A HREF="#httpPut"><CODE>httpPut()</CODE></A>,
+<A HREF="#httpTrace"><CODE>httpTrace()</CODE></A>
+
+<!-- NEW PAGE --><H2><A NAME="httpWrite">httpWrite()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+int httpWrite(http_t *http, char *buffer, int length);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>http</TD>
+ <TD>The HTTP connection</TD>
+</TR>
+<TR>
+ <TD>buffer</TD>
+ <TD>The buffer to read into</TD>
+</TR>
+<TR>
+ <TD>length</TD>
+ <TD>The number of bytes to read</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>The number of bytes read or -1 on error.
+
+<H3>Description</H3>
+
+<P>The <CODE>httpWrite()</CODE> function reads data from the HTTP connection,
+possibly the result of a GET or POST request.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/http.h&gt;
+
+http_t *http;
+FILE *fp;
+char buffer[1024];
+int bytes;
+
+httpPost(http, "/");
+
+while ((bytes = fread(buffer, 1, sizeof(buffer), fp)) > 0)
+ httpWrite(http, buffer, bytes);
+
+while (httpUpdate(http) != HTTP_CONTINUE);
+
+while ((bytes = httpRead(http, buffer, sizeof(buffer) - 1)) > 0)
+{
+ buffer[bytes] = '\0';
+ fputs(buffer, stdout);
+}
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#httpConnect"><CODE>httpConnect()</CODE></A>,
+<A HREF="#httpRead"><CODE>httpRead()</CODE></A>
+
+<!-- NEW PAGE --><H2><A NAME="ippAddBoolean">ippAddBoolean()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+ipp_attribute_t *ippAddBoolean(ipp_t *ipp, ipp_tag_t group,
+ const char *name, char value);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>ipp</TD>
+ <TD>The IPP request</TD>
+</TR>
+<TR>
+ <TD>group</TD>
+ <TD>The IPP group</TD>
+</TR>
+<TR>
+ <TD>name</TD>
+ <TD>The name of attribute</TD>
+</TR>
+<TR>
+ <TD>value</TD>
+ <TD>The boolean value</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>A pointer to the new attribute or NULL if the attribute could not be
+created.
+
+<H3>Description</H3>
+
+<P>The <CODE>ippAddBoolean()</CODE> function adds a single boolean attribute
+value to the specified IPP request.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/ipp.h>
+
+ipp_t *ipp;
+
+ippAddBoolean(ipp, IPP_TAG_OPERATION, "my-jobs", 1);
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#ippAddBooleans"><CODE>ippAddBooleans()</CODE></A>,
+<A HREF="#ippAddDate"><CODE>ippAddDate()</CODE></A>,
+<A HREF="#ippAddInteger"><CODE>ippAddInteger()</CODE></A>,
+<A HREF="#ippAddIntegers"><CODE>ippAddIntegers()</CODE></A>,
+<A HREF="#ippAddRange"><CODE>ippAddRange()</CODE></A>,
+<A HREF="#ippAddRanges"><CODE>ippAddRanges()</CODE></A>,
+<A HREF="#ippAddResolution"><CODE>ippAddResolution()</CODE></A>,
+<A HREF="#ippAddResolutions"><CODE>ippAddResolutions()</CODE></A>,
+<A HREF="#ippAddSeparator"><CODE>ippAddSeparator()</CODE></A>,
+<A HREF="#ippAddString"><CODE>ippAddString()</CODE></A>,
+<A HREF="#ippAddStrings"><CODE>ippAddStrings()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="ippAddBooleans">ippAddBooleans()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+ipp_attribute_t *ippAddBooleans(ipp_t *ipp, ipp_tag_t group,
+ const char *name, int num_values,
+ const char *values);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>ipp</TD>
+ <TD>The IPP request</TD>
+</TR>
+<TR>
+ <TD>group</TD>
+ <TD>The IPP group</TD>
+</TR>
+<TR>
+ <TD>name</TD>
+ <TD>The name of attribute</TD>
+</TR>
+<TR>
+ <TD>num_values</TD>
+ <TD>The number of values</TD>
+</TR>
+<TR>
+ <TD>values</TD>
+ <TD>The boolean values</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>A pointer to the new attribute or NULL if the attribute could not be
+created.
+
+<H3>Description</H3>
+
+<P>The <CODE>ippAddBooleans()</CODE> function adds one or more boolean
+attribute values to the specified IPP request. If the
+<CODE>values</CODE> pointer is <CODE>NULL</CODE> then an array of
+<CODE>num_values</CODE> false values is created.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/ipp.h>
+
+ipp_t *ipp;
+char values[10];
+
+ippAddBooleans(ipp, IPP_TAG_OPERATION, "some-attribute", 10, values);
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#ippAddBoolean"><CODE>ippAddBoolean()</CODE></A>,
+<A HREF="#ippAddDate"><CODE>ippAddDate()</CODE></A>,
+<A HREF="#ippAddInteger"><CODE>ippAddInteger()</CODE></A>,
+<A HREF="#ippAddIntegers"><CODE>ippAddIntegers()</CODE></A>,
+<A HREF="#ippAddRange"><CODE>ippAddRange()</CODE></A>,
+<A HREF="#ippAddRanges"><CODE>ippAddRanges()</CODE></A>,
+<A HREF="#ippAddResolution"><CODE>ippAddResolution()</CODE></A>,
+<A HREF="#ippAddResolutions"><CODE>ippAddResolutions()</CODE></A>,
+<A HREF="#ippAddSeparator"><CODE>ippAddSeparator()</CODE></A>,
+<A HREF="#ippAddString"><CODE>ippAddString()</CODE></A>,
+<A HREF="#ippAddStrings"><CODE>ippAddStrings()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="ippAddDate">ippAddDate()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+ipp_attribute_t *ippAddDate(ipp_t *ipp, ipp_tag_t group,
+ const char *name, ipp_uchar_t *value);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>ipp</TD>
+ <TD>The IPP request</TD>
+</TR>
+<TR>
+ <TD>group</TD>
+ <TD>The IPP group</TD>
+</TR>
+<TR>
+ <TD>name</TD>
+ <TD>The name of attribute</TD>
+</TR>
+<TR>
+ <TD>value</TD>
+ <TD>The date value</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>A pointer to the new attribute or NULL if the attribute could not be
+created.
+
+<H3>Description</H3>
+
+<P>The <CODE>ippAddDate()</CODE> function adds a single date-time attribute
+value to the specified IPP request.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/ipp.h>
+
+ipp_t *ipp;
+
+ippAddDate(ipp, IPP_TAG_OPERATION, "some-attribute",
+ ippTimeToDate(time(NULL));
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#ippAddBoolean"><CODE>ippAddBoolean()</CODE></A>,
+<A HREF="#ippAddBooleans"><CODE>ippAddBooleans()</CODE></A>,
+<A HREF="#ippAddInteger"><CODE>ippAddInteger()</CODE></A>,
+<A HREF="#ippAddIntegers"><CODE>ippAddIntegers()</CODE></A>,
+<A HREF="#ippAddRange"><CODE>ippAddRange()</CODE></A>,
+<A HREF="#ippAddRanges"><CODE>ippAddRanges()</CODE></A>,
+<A HREF="#ippAddResolution"><CODE>ippAddResolution()</CODE></A>,
+<A HREF="#ippAddResolutions"><CODE>ippAddResolutions()</CODE></A>,
+<A HREF="#ippAddSeparator"><CODE>ippAddSeparator()</CODE></A>,
+<A HREF="#ippAddString"><CODE>ippAddString()</CODE></A>,
+<A HREF="#ippAddStrings"><CODE>ippAddStrings()</CODE></A>,
+<A HREF="#ippTimeToDate"><CODE>ippTimeToDate()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="ippAddInteger">ippAddInteger()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+ipp_attribute_t *ippAddInteger(ipp_t *ipp, ipp_tag_t group,
+ ipp_tag_t tag, const char *name,
+ int value);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>ipp</TD>
+ <TD>The IPP request</TD>
+</TR>
+<TR>
+ <TD>group</TD>
+ <TD>The IPP group</TD>
+</TR>
+<TR>
+ <TD>tag</TD>
+ <TD>The type of integer value (IPP_TAG_INTEGER or IPP_TAG_ENUM)</TD>
+</TR>
+<TR>
+ <TD>name</TD>
+ <TD>The name of attribute</TD>
+</TR>
+<TR>
+ <TD>value</TD>
+ <TD>The integer value</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>A pointer to the new attribute or NULL if the attribute could not be
+created.
+
+<H3>Description</H3>
+
+<P>The <CODE>ippAddInteger()</CODE> function adds a single integer attribute
+value to the specified IPP request.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/ipp.h>
+
+ipp_t *ipp;
+
+ippAddInteger(ipp, IPP_TAG_OPERATION, "limit", 100);
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#ippAddBoolean"><CODE>ippAddBoolean()</CODE></A>,
+<A HREF="#ippAddBooleans"><CODE>ippAddBooleans()</CODE></A>,
+<A HREF="#ippAddDate"><CODE>ippAddDate()</CODE></A>,
+<A HREF="#ippAddIntegers"><CODE>ippAddIntegers()</CODE></A>,
+<A HREF="#ippAddRange"><CODE>ippAddRange()</CODE></A>,
+<A HREF="#ippAddRanges"><CODE>ippAddRanges()</CODE></A>,
+<A HREF="#ippAddResolution"><CODE>ippAddResolution()</CODE></A>,
+<A HREF="#ippAddResolutions"><CODE>ippAddResolutions()</CODE></A>,
+<A HREF="#ippAddSeparator"><CODE>ippAddSeparator()</CODE></A>,
+<A HREF="#ippAddString"><CODE>ippAddString()</CODE></A>,
+<A HREF="#ippAddStrings"><CODE>ippAddStrings()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="ippAddIntegers">ippAddIntegers()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+ipp_attribute_t *ippAddIntegers(ipp_t *ipp, ipp_tag_t group,
+ ipp_tag_t tag, const char *name,
+ int num_values, const int *values);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>ipp</TD>
+ <TD>The IPP request</TD>
+</TR>
+<TR>
+ <TD>group</TD>
+ <TD>The IPP group</TD>
+</TR>
+<TR>
+ <TD>tag</TD>
+ <TD>The type of integer value (IPP_TAG_INTEGER or IPP_TAG_ENUM)</TD>
+</TR>
+<TR>
+ <TD>name</TD>
+ <TD>The name of attribute</TD>
+</TR>
+<TR>
+ <TD>num_values</TD>
+ <TD>The number of values</TD>
+</TR>
+<TR>
+ <TD>values</TD>
+ <TD>The integer values</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>A pointer to the new attribute or NULL if the attribute could not be
+created.
+
+<H3>Description</H3>
+
+<P>The <CODE>ippAddIntegers()</CODE> function adds one or more integer
+attribute values to the specified IPP request. If the
+<CODE>values</CODE> pointer is <CODE>NULL</CODE> then an array of
+<CODE>num_values</CODE> 0 values is created.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/ipp.h>
+
+ipp_t *ipp;
+int values[100];
+
+ippAddIntegers(ipp, IPP_TAG_OPERATION, "some-attribute", 100, values);
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#ippAddBoolean"><CODE>ippAddBoolean()</CODE></A>,
+<A HREF="#ippAddBooleans"><CODE>ippAddBooleans()</CODE></A>,
+<A HREF="#ippAddDate"><CODE>ippAddDate()</CODE></A>,
+<A HREF="#ippAddInteger"><CODE>ippAddInteger()</CODE></A>,
+<A HREF="#ippAddRange"><CODE>ippAddRange()</CODE></A>,
+<A HREF="#ippAddRanges"><CODE>ippAddRanges()</CODE></A>,
+<A HREF="#ippAddResolution"><CODE>ippAddResolution()</CODE></A>,
+<A HREF="#ippAddResolutions"><CODE>ippAddResolutions()</CODE></A>,
+<A HREF="#ippAddSeparator"><CODE>ippAddSeparator()</CODE></A>,
+<A HREF="#ippAddString"><CODE>ippAddString()</CODE></A>,
+<A HREF="#ippAddStrings"><CODE>ippAddStrings()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="ippAddRange">ippAddRange()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+ipp_attribute_t *ippAddRange(ipp_t *ipp, ipp_tag_t group,
+ const char *name, int low,
+ int high);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>ipp</TD>
+ <TD>The IPP request</TD>
+</TR>
+<TR>
+ <TD>group</TD>
+ <TD>The IPP group</TD>
+</TR>
+<TR>
+ <TD>name</TD>
+ <TD>The name of attribute</TD>
+</TR>
+<TR>
+ <TD>low</TD>
+ <TD>The lower value</TD>
+</TR>
+<TR>
+ <TD>high</TD>
+ <TD>The higher value</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>A pointer to the new attribute or NULL if the attribute could not be
+created.
+
+<H3>Description</H3>
+
+<P>The <CODE>ippAddRange()</CODE> function adds a single range attribute
+value to the specified IPP request.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/ipp.h>
+
+ipp_t *ipp;
+
+ippAddRange(ipp, IPP_TAG_OPERATION, "page-ranges", 1, 10);
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#ippAddBoolean"><CODE>ippAddBoolean()</CODE></A>,
+<A HREF="#ippAddBooleans"><CODE>ippAddBooleans()</CODE></A>,
+<A HREF="#ippAddDate"><CODE>ippAddDate()</CODE></A>,
+<A HREF="#ippAddInteger"><CODE>ippAddInteger()</CODE></A>,
+<A HREF="#ippAddIntegers"><CODE>ippAddIntegers()</CODE></A>,
+<A HREF="#ippAddRanges"><CODE>ippAddRanges()</CODE></A>,
+<A HREF="#ippAddResolution"><CODE>ippAddResolution()</CODE></A>,
+<A HREF="#ippAddResolutions"><CODE>ippAddResolutions()</CODE></A>,
+<A HREF="#ippAddSeparator"><CODE>ippAddSeparator()</CODE></A>,
+<A HREF="#ippAddString"><CODE>ippAddString()</CODE></A>,
+<A HREF="#ippAddStrings"><CODE>ippAddStrings()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="ippAddRanges">ippAddRanges()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+ipp_attribute_t *ippAddRanges(ipp_t *ipp, ipp_tag_t group,
+ const char *name, int num_values,
+ const int *lows, const int *highs);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>ipp</TD>
+ <TD>The IPP request</TD>
+</TR>
+<TR>
+ <TD>group</TD>
+ <TD>The IPP group</TD>
+</TR>
+<TR>
+ <TD>name</TD>
+ <TD>The name of attribute</TD>
+</TR>
+<TR>
+ <TD>num_values</TD>
+ <TD>The number of range values</TD>
+</TR>
+<TR>
+ <TD>lows</TD>
+ <TD>The lower values</TD>
+</TR>
+<TR>
+ <TD>highs</TD>
+ <TD>The higher values</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>A pointer to the new attribute or NULL if the attribute could not be
+created.
+
+<H3>Description</H3>
+
+<P>The <CODE>ippAddRanges()</CODE> function adds one or more range
+attribute values to the specified IPP request. If the
+<CODE>values</CODE> pointer is <CODE>NULL</CODE> then an array of
+<CODE>num_values</CODE> 0,0 ranges is created.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/ipp.h>
+
+ipp_t *ipp;
+int lows[2];
+int highs[2];
+
+ippAddRanges(ipp, IPP_TAG_OPERATION, "page-ranges", 2, lows, highs);
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#ippAddBoolean"><CODE>ippAddBoolean()</CODE></A>,
+<A HREF="#ippAddBooleans"><CODE>ippAddBooleans()</CODE></A>,
+<A HREF="#ippAddDate"><CODE>ippAddDate()</CODE></A>,
+<A HREF="#ippAddInteger"><CODE>ippAddInteger()</CODE></A>,
+<A HREF="#ippAddIntegers"><CODE>ippAddIntegers()</CODE></A>,
+<A HREF="#ippAddRange"><CODE>ippAddRange()</CODE></A>,
+<A HREF="#ippAddResolution"><CODE>ippAddResolution()</CODE></A>,
+<A HREF="#ippAddResolutions"><CODE>ippAddResolutions()</CODE></A>,
+<A HREF="#ippAddSeparator"><CODE>ippAddSeparator()</CODE></A>,
+<A HREF="#ippAddString"><CODE>ippAddString()</CODE></A>,
+<A HREF="#ippAddStrings"><CODE>ippAddStrings()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="ippAddResolution">ippAddResolution()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+ipp_attribute_t *ippAddResolution(ipp_t *ipp, ipp_tag_t group,
+ const char *name, int xres,
+ int yres, ipp_res_t units);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>ipp</TD>
+ <TD>The IPP request</TD>
+</TR>
+<TR>
+ <TD>group</TD>
+ <TD>The IPP group</TD>
+</TR>
+<TR>
+ <TD>name</TD>
+ <TD>The name of attribute</TD>
+</TR>
+<TR>
+ <TD>xres</TD>
+ <TD>The horizontal resolution</TD>
+</TR>
+<TR>
+ <TD>yres</TD>
+ <TD>The vertical resolution</TD>
+</TR>
+<TR>
+ <TD>units</TD>
+ <TD>The resolution units</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>A pointer to the new attribute or NULL if the attribute could not be
+created.
+
+<H3>Description</H3>
+
+<P>The <CODE>ippAddResolution()</CODE> function adds a single resolution attribute
+value to the specified IPP request.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/ipp.h>
+
+ipp_t *ipp;
+
+ippAddBoolean(ipp, IPP_TAG_OPERATION, "printer-resolution",
+ 720, 720, IPP_RES_PER_INCH);
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#ippAddBoolean"><CODE>ippAddBoolean()</CODE></A>,
+<A HREF="#ippAddBooleans"><CODE>ippAddBooleans()</CODE></A>,
+<A HREF="#ippAddDate"><CODE>ippAddDate()</CODE></A>,
+<A HREF="#ippAddInteger"><CODE>ippAddInteger()</CODE></A>,
+<A HREF="#ippAddIntegers"><CODE>ippAddIntegers()</CODE></A>,
+<A HREF="#ippAddRange"><CODE>ippAddRange()</CODE></A>,
+<A HREF="#ippAddRanges"><CODE>ippAddRanges()</CODE></A>,
+<A HREF="#ippAddResolutions"><CODE>ippAddResolutions()</CODE></A>,
+<A HREF="#ippAddSeparator"><CODE>ippAddSeparator()</CODE></A>,
+<A HREF="#ippAddString"><CODE>ippAddString()</CODE></A>,
+<A HREF="#ippAddStrings"><CODE>ippAddStrings()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="ippAddResolutions">ippAddResolutions()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+ipp_attribute_t *ippAddResolutions(ipp_t *ipp, ipp_tag_t group,
+ const char *name, int num_values,
+ const int *xres, const int *yres,
+ const ipp_res_t *units);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>ipp</TD>
+ <TD>The IPP request</TD>
+</TR>
+<TR>
+ <TD>group</TD>
+ <TD>The IPP group</TD>
+</TR>
+<TR>
+ <TD>name</TD>
+ <TD>The name of attribute</TD>
+</TR>
+<TR>
+ <TD>num_values</TD>
+ <TD>The number of resolution values</TD>
+</TR>
+<TR>
+ <TD>xres</TD>
+ <TD>The horizontal resolutions</TD>
+</TR>
+<TR>
+ <TD>yres</TD>
+ <TD>The vertical resolutions</TD>
+</TR>
+<TR>
+ <TD>units</TD>
+ <TD>The resolution units</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>A pointer to the new attribute or NULL if the attribute could not be
+created.
+
+<H3>Description</H3>
+
+<P>The <CODE>ippAddResolutions()</CODE> function adds one or more
+resolution attribute values to the specified IPP request. If the
+<CODE>values</CODE> pointer is <CODE>NULL</CODE> then an array of
+<CODE>num_values</CODE> 0,0 resolutions is created.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/ipp.h>
+
+ipp_t *ipp;
+int xres[5];
+int yres[5];
+ipp_res_t units[5];
+
+ippAddBoolean(ipp, IPP_TAG_OPERATION, "printer-resolutions-supported",
+ 5, xres, yres, units);
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#ippAddBoolean"><CODE>ippAddBoolean()</CODE></A>,
+<A HREF="#ippAddBooleans"><CODE>ippAddBooleans()</CODE></A>,
+<A HREF="#ippAddDate"><CODE>ippAddDate()</CODE></A>,
+<A HREF="#ippAddInteger"><CODE>ippAddInteger()</CODE></A>,
+<A HREF="#ippAddIntegers"><CODE>ippAddIntegers()</CODE></A>,
+<A HREF="#ippAddRange"><CODE>ippAddRange()</CODE></A>,
+<A HREF="#ippAddRanges"><CODE>ippAddRanges()</CODE></A>,
+<A HREF="#ippAddResolution"><CODE>ippAddResolution()</CODE></A>,
+<A HREF="#ippAddSeparator"><CODE>ippAddSeparator()</CODE></A>,
+<A HREF="#ippAddString"><CODE>ippAddString()</CODE></A>,
+<A HREF="#ippAddStrings"><CODE>ippAddStrings()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="ippAddSeparator">ippAddSeparator()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+ipp_attribute_t *ippAddSeparator(ipp_t *ipp);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>ipp</TD>
+ <TD>The IPP request</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>A pointer to the new separator or NULL if the separator could not be
+created.
+
+<H3>Description</H3>
+
+<P>The <CODE>ippAddSeparator()</CODE> function adds a group separator
+to the specified IPP request.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/ipp.h>
+
+ipp_t *ipp;
+
+ippAddSeparator(ipp);
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#ippAddBoolean"><CODE>ippAddBoolean()</CODE></A>,
+<A HREF="#ippAddBooleans"><CODE>ippAddBooleans()</CODE></A>,
+<A HREF="#ippAddDate"><CODE>ippAddDate()</CODE></A>,
+<A HREF="#ippAddInteger"><CODE>ippAddInteger()</CODE></A>,
+<A HREF="#ippAddIntegers"><CODE>ippAddIntegers()</CODE></A>,
+<A HREF="#ippAddRange"><CODE>ippAddRange()</CODE></A>,
+<A HREF="#ippAddRanges"><CODE>ippAddRanges()</CODE></A>,
+<A HREF="#ippAddResolution"><CODE>ippAddResolution()</CODE></A>,
+<A HREF="#ippAddResolutions"><CODE>ippAddResolutions()</CODE></A>,
+<A HREF="#ippAddString"><CODE>ippAddString()</CODE></A>,
+<A HREF="#ippAddStrings"><CODE>ippAddStrings()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="ippAddString">ippAddString()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+ipp_attribute_t *ippAddString(ipp_t *ipp, ipp_tag_t group,
+ ipp_tag_t tag, const char *name,
+ const char *charset, const char *value);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>ipp</TD>
+ <TD>The IPP request</TD>
+</TR>
+<TR>
+ <TD>group</TD>
+ <TD>The IPP group</TD>
+</TR>
+<TR>
+ <TD>tag</TD>
+ <TD>The type of string value</TD>
+</TR>
+<TR>
+ <TD>name</TD>
+ <TD>The name of attribute</TD>
+</TR>
+<TR>
+ <TD>charset</TD>
+ <TD>The character set for the string</TD>
+</TR>
+<TR>
+ <TD>value</TD>
+ <TD>The string value</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>A pointer to the new attribute or NULL if the attribute could not be
+created.
+
+<H3>Description</H3>
+
+<P>The <CODE>ippAddString()</CODE> function adds a single string attribute
+value to the specified IPP request. For <CODE>IPP_TAG_NAMELANG</CODE> and
+<CODE>IPP_TAG_TEXTLANG</CODE> strings, the charset value is provided with
+the string to identify the string encoding used. Otherwise the charset value
+is ignored.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/ipp.h>
+
+ipp_t *ipp;
+
+ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name",
+ NULL, "abc123");
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#ippAddBoolean"><CODE>ippAddBoolean()</CODE></A>,
+<A HREF="#ippAddBooleans"><CODE>ippAddBooleans()</CODE></A>,
+<A HREF="#ippAddDate"><CODE>ippAddDate()</CODE></A>,
+<A HREF="#ippAddInteger"><CODE>ippAddInteger()</CODE></A>,
+<A HREF="#ippAddIntegers"><CODE>ippAddIntegers()</CODE></A>,
+<A HREF="#ippAddRange"><CODE>ippAddRange()</CODE></A>,
+<A HREF="#ippAddRanges"><CODE>ippAddRanges()</CODE></A>,
+<A HREF="#ippAddResolution"><CODE>ippAddResolution()</CODE></A>,
+<A HREF="#ippAddResolutions"><CODE>ippAddResolutions()</CODE></A>,
+<A HREF="#ippAddSeparator"><CODE>ippAddSeparator()</CODE></A>,
+<A HREF="#ippAddStrings"><CODE>ippAddStrings()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="ippAddStrings">ippAddStrings()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+ipp_attribute_t *ippAddStrings(ipp_t *ipp, ipp_tag_t group,
+ ipp_tag_t tag, const char *name,
+ int num_values, const char *charset,
+ const char **values);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>ipp</TD>
+ <TD>The IPP request</TD>
+</TR>
+<TR>
+ <TD>group</TD>
+ <TD>The IPP group</TD>
+</TR>
+<TR>
+ <TD>tag</TD>
+ <TD>The type of string value</TD>
+</TR>
+<TR>
+ <TD>name</TD>
+ <TD>The name of attribute</TD>
+</TR>
+<TR>
+ <TD>num_values</TD>
+ <TD>The number of strings</TD>
+</TR>
+<TR>
+ <TD>charset</TD>
+ <TD>The character set for the strings</TD>
+</TR>
+<TR>
+ <TD>values</TD>
+ <TD>The string values</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>A pointer to the new attribute or NULL if the attribute could not be
+created.
+
+<H3>Description</H3>
+
+<P>The <CODE>ippAddStrings()</CODE> function adds one or more string
+attribute values to the specified IPP request. For
+<CODE>IPP_TAG_NAMELANG</CODE> and <CODE>IPP_TAG_TEXTLANG</CODE>
+strings, the charset value is provided with the strings to identify the
+string encoding used. Otherwise the charset value is ignored. If the
+<CODE>values</CODE> pointer is <CODE>NULL</CODE> then an array of
+<CODE>num_values</CODE> NULL strings is created.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/ipp.h>
+
+ipp_t *ipp;
+char *values[2] = { "one", "two" };
+
+ippAddStrings(ipp, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "attr-name",
+ 2, NULL, values);
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#ippAddBoolean"><CODE>ippAddBoolean()</CODE></A>,
+<A HREF="#ippAddBooleans"><CODE>ippAddBooleans()</CODE></A>,
+<A HREF="#ippAddDate"><CODE>ippAddDate()</CODE></A>,
+<A HREF="#ippAddInteger"><CODE>ippAddInteger()</CODE></A>,
+<A HREF="#ippAddIntegers"><CODE>ippAddIntegers()</CODE></A>,
+<A HREF="#ippAddRange"><CODE>ippAddRange()</CODE></A>,
+<A HREF="#ippAddRanges"><CODE>ippAddRanges()</CODE></A>,
+<A HREF="#ippAddResolution"><CODE>ippAddResolution()</CODE></A>,
+<A HREF="#ippAddResolutions"><CODE>ippAddResolutions()</CODE></A>,
+<A HREF="#ippAddSeparator"><CODE>ippAddSeparator()</CODE></A>,
+<A HREF="#ippAddString"><CODE>ippAddString()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="ippDateToTime">ippDateToTime()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+time_t ippDateToTime(const ipp_uchar_t date[11]);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>date</TD>
+ <TD>The IPP date-time value</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>A UNIX time value.
+
+<H3>Description</H3>
+
+<P>The <CODE>ippDateToTime()</CODE> function converts an IPP date-time value
+to a UNIX time value.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/ipp.h>
+
+ipp_uchar_t date[11];
+
+printf("UNIX time is %d\n", ippDateToTime(date));
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#ippTimeToDate"><CODE>ippTimeToDate()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="ippDelete">ippDelete()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+void ippDelete(ipp_t *ipp);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>ipp</TD>
+ <TD>The IPP request or response</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Description</H3>
+
+<P>The <CODE>ippDelete()</CODE> function deletes all memory used by an IPP
+request or response.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/ipp.h>
+
+ipp_t *ipp;
+
+ippDelete(ipp);
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#ippNew"><CODE>ippNew()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="ippFindAttribute">ippFindAttribute()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+ipp_attribute_t *ippFindAttribute(ipp_t *ipp, const char *name, ipp_tag_t tag);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>ipp</TD>
+ <TD>The IPP request or response</TD>
+</TR>
+<TR>
+ <TD>name</TD>
+ <TD>The name of the attribute</TD>
+</TR>
+<TR>
+ <TD>tag</TD>
+ <TD>The required value tag for the attribute or
+ <CODE>IPP_TAG_ZERO</CODE> for any type of value.</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>A pointer to the first occurrence of the requested attribute, or
+<CODE>NULL</CODE> if it was not found.
+
+<H3>Description</H3>
+
+<P><CODE>ippFindAttribute()</CODE> finds the first occurrence of the named
+attribute. The <CODE>tag</CODE> parameter restricts the search to a specific
+value type - use <CODE>IPP_TAG_ZERO</CODE> to find any value with the name.
+
+<P>The value tags <CODE>IPP_TAG_NAME</CODE> and <CODE>IPP_TAG_TEXT</CODE>
+match the name/text values with or without the language code.
+
+<H3>Example</H3>
+
+<PRE>
+ipp_attribute_t *attr;
+
+attr = ippFindAttribute(response, "printer-state-message", IPP_TAG_TEXT);
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#cupsDoFileRequest"><CODE>cupsDoFileRequest()</CODE></A>,
+<A HREF="#cupsDoRequest"><CODE>cupsDoRequest()</CODE></A>,
+<A HREF="#ippDelete"><CODE>ippDelete()</CODE></A>,
+<A HREF="#ippNew"><CODE>ippNew()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="ippLength">ippLength()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+int ippLength(ipp_t *ipp);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>ipp</TD>
+ <TD>The IPP request or response</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>The total encoded length of the IPP request or response in bytes.
+
+<H3>Description</H3>
+
+<P><CODE>ippLength()</CODE> returns the length of the IPP request or
+response in bytes.
+
+<H3>Example</H3>
+
+<PRE>
+printf("The length of the response is %d bytes.\n", ippLength(response));
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#ippDelete"><CODE>ippDelete()</CODE></A>,
+<A HREF="#ippNew"><CODE>ippNew()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="ippNew">ippNew()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+ipp_t *ippNew(void);
+</PRE>
+
+<H3>Returns</H3>
+
+<P>A pointer to a new IPP request or response.
+
+<H3>Description</H3>
+
+<P>The <CODE>ippNew()</CODE> function creates a new IPP request or response.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/ipp.h>
+
+ipp_t *ipp;
+
+ipp = ippNew();
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#ippDelete"><CODE>ippDelete()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="ippPort">ippPort()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+int ippPort(void);
+</PRE>
+
+<H3>Returns</H3>
+
+<P>The default TCP/IP port number for IPP requests.
+
+<H3>Description</H3>
+
+<P>The <CODE>ippPort()</CODE> function returns the default IPP port number
+for requests.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/http.h>
+#include &lt;cups/ipp.h>
+
+http_t *http;
+
+http = httpConnect(cupsServer(), ippPort());
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#cupsServer"><CODE>cupsServer()</CODE></A>,
+<A HREF="#ippSetPort"><CODE>ippSetPort()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="ippRead">ippRead()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+ipp_state_t ippRead(http_t *http, ipp_t *ipp);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>http</TD>
+ <TD>The HTTP connection</TD>
+</TR>
+<TR>
+ <TD>ipp</TD>
+ <TD>The IPP request or response</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>The current read state.
+
+<H3>Description</H3>
+
+<P>The <CODE>ippRead()</CODE> function reads IPP attributes from the specified
+HTTP connection. Programs should continue calling <CODE>ippRead()</CODE> until
+<CODE>IPP_ERROR</CODE> or <CODE>IPP_DATA</CODE> is returned.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/http.h>
+#include &lt;cups/ipp.h>
+
+http_t *http;
+ipp_t *ipp;
+ipp_state_t status;
+
+ipp = ippNew();
+
+while ((status = ippRead(http, ipp)) != IPP_ERROR)
+ if (status == IPP_DATA)
+ break;
+
+if (status == IPP_DATA)
+{
+ ... read additional non-IPP data using httpRead() ...
+}
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#ippWrite"><CODE>ippWrite()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="ippSetPort">ippSetPort()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+void
+ippSetPort(int port);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>port</TD>
+ <TD>The port number to use</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Description</H3>
+
+<P>The <CODE>ippSetPort()</CODE> function sets the default IPP port number
+for requests.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/http.h>
+#include &lt;cups/ipp.h>
+
+...
+
+ippSetPort(8631);
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#ippPort"><CODE>ippPort()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="ippTimeToDate">ippTimeToDate()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+ipp_uchar_t *ippTimeToDate(time_t time);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>time</TD>
+ <TD>The UNIX time value</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>A static pointer to an IPP date-time value.
+
+<H3>Description</H3>
+
+<P>The <CODE>ippTimeToDate()</CODE> function converts a UNIX time to an IPP
+date-time value.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/ipp.h>
+
+ipp_uchar_t *date;
+
+date = ippTimeToDate(time(NULL));
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#ippDateToTime"><CODE>ippDateToTime()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="ippWrite">ippWrite()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+ipp_state_t ippWrite(http_t *http, ipp_t *ipp);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>http</TD>
+ <TD>The HTTP connection</TD>
+</TR>
+<TR>
+ <TD>ipp</TD>
+ <TD>The IPP request or response</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>The current write state.
+
+<H3>Description</H3>
+
+<P>The <CODE>ippWrite()</CODE> function writes IPP attributes to the specified
+HTTP connection. Programs should continue calling <CODE>ippWrite()</CODE> until
+<CODE>IPP_ERROR</CODE> or <CODE>IPP_DATA</CODE> is returned.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/http.h>
+#include &lt;cups/ipp.h>
+
+http_t *http;
+ipp_t *ipp;
+ipp_state_t status;
+
+ipp = ippNew();
+... add attributes ...
+
+while ((status = ippWrite(http, ipp)) != IPP_ERROR)
+ if (status == IPP_DATA)
+ break;
+
+if (status == IPP_DATA)
+{
+ ... read additional non-IPP data using httpWrite() ...
+}
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#ippRead"><CODE>ippRead()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="ppdClose">ppdClose()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+void ppdClose(ppd_file_t *ppd);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>ppd</TD>
+ <TD>The PPD file</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Description</H3>
+
+<P>The <CODE>ppdClose()</CODE> function frees all memory associated with the
+PPD file.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/ppd.h>
+
+ppd_file_t *ppd;
+
+ppdClose(ppd);
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#ppdOpen"><CODE>ppdOpen()</CODE></A>,
+<A HREF="#ppdOpenFd"><CODE>ppdOpenFd()</CODE></A>,
+<A HREF="#ppdOpenFile"><CODE>ppdOpenFile()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="ppdConflicts">ppdConflicts()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+int ppdConflicts(ppd_file_t *ppd);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>ppd</TD>
+ <TD>The PPD file</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>The number of option conflicts in the file.
+
+<H3>Description</H3>
+
+<P>The <CODE>ppdConflicts()</CODE> function returns the number of conflicts
+with the currently selected options.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/ppd.h>
+
+ppd_file_t *ppd;
+
+printf("%d conflicts\n", ppdConflicts(ppd));
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#cupsMarkOptions"><CODE>cupsMarkOptions()</CODE></A>,
+<A HREF="#ppdIsMarked"><CODE>ppdIsMarked()</CODE></A>,
+<A HREF="#ppdMarkDefaults"><CODE>ppdMarkDefaults()</CODE></A>,
+<A HREF="#ppdMarkOption"><CODE>ppdMarkOption()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="ppdEmit">ppdEmit()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+int ppdEmit(ppd_file_t *ppd, FILE *file, ppd_section_t section);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>ppd</TD>
+ <TD>The PPD file</TD>
+</TR>
+<TR>
+ <TD>file</TD>
+ <TD>The file to write to</TD>
+</TR>
+<TR>
+ <TD>section</TD>
+ <TD>The option section to write</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>0 on success, -1 on error.
+
+<H3>Description</H3>
+
+<P>The <CODE>ppdEmit()</CODE> function sends printer-specific option
+commands to the specified file.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/ppd.h>
+
+ppd_file_t *ppd;
+
+ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#ppdEmitFd"><CODE>ppdEmitFd()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="ppdEmitFd">ppdEmitFd()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+int ppdEmitFd(ppd_file_t *ppd, int fd, ppd_section_t section);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>ppd</TD>
+ <TD>The PPD file</TD>
+</TR>
+<TR>
+ <TD>fd</TD>
+ <TD>The file descriptor to write to</TD>
+</TR>
+<TR>
+ <TD>section</TD>
+ <TD>The option section to write</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>0 on success, -1 on error.
+
+<H3>Description</H3>
+
+<P>The <CODE>ppdEmitFd()</CODE> function sends printer-specific option
+commands to the specified file descriptor.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/ppd.h>
+
+ppd_file_t *ppd;
+
+ppdEmitFd(ppd, 1, PPD_ORDER_PAGE);
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#ppdEmit"><CODE>ppdEmit()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="ppdFindChoice">ppdFindChoice()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+ppd_choice_t *ppdFindChoice(ppd_option_t *option, const char *choice);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>option</TD>
+ <TD>A pointer to the option</TD>
+</TR>
+<TR>
+ <TD>choice</TD>
+ <TD>The name of the choice</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>A pointer to the choice data or NULL if the choice does not exist.
+
+<H3>Description</H3>
+
+<P>The <CODE>ppdFindChoice()</CODE> function returns a pointer to the choice
+data for the specified option.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/ppd.h>
+
+ppd_file_t *ppd;
+ppd_option_t *option;
+ppd_choice_t *choice;
+
+option = ppdFindOption(ppd, "PageSize");
+choice = ppdFindChoice(option, "Letter");
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#ppdFindMarkedChoice"><CODE>ppdFindMarkedChoice()</CODE></A>,
+<A HREF="#ppdFindOption"><CODE>ppdFindOption()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="ppdFindMarkedChoice">ppdFindMarkedChoice()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+ppd_choice_t *ppdFindMarkedChoice(ppd_file_t *ppd, const char *keyword);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>ppd</TD>
+ <TD>The PPD file</TD>
+</TR>
+<TR>
+ <TD>keyword</TD>
+ <TD>The name of the option</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>A pointer to the choice data or NULL if the choice does not exist or
+is not marked.
+
+<H3>Description</H3>
+
+<P>The <CODE>ppdFindMarkedChoice()</CODE> function returns a pointer to
+the marked choice data for the specified option.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/ppd.h>
+
+ppd_file_t *ppd;
+ppd_choice_t *choice;
+
+choice = ppdFindMarkedChoice(ppd, "PageSize");
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#ppdFindChoice"><CODE>ppdFindChoice()</CODE></A>,
+<A HREF="#ppdFindOption"><CODE>ppdFindOption()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="ppdFindOption">ppdFindOption()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+ppd_option_t *ppdFindOption(ppd_file_t *ppd, const char *keyword);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>ppd</TD>
+ <TD>The PPD file</TD>
+</TR>
+<TR>
+ <TD>keyword</TD>
+ <TD>The name of the option</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>A pointer to the option data or NULL if the option does not exist.
+
+<H3>Description</H3>
+
+<P>The <CODE>ppdFindOption()</CODE> function returns a pointer to the option
+data for the specified option.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/ppd.h>
+
+ppd_file_t *ppd;
+ppd_option_t *option;
+
+option = ppdFindOption(ppd, "PageSize");
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#ppdFindChoice"><CODE>ppdFindChoice()</CODE></A>,
+<A HREF="#ppdFindMarkedChoice"><CODE>ppdFindMarkedChoice()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="ppdIsMarked">ppdIsMarked()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+int ppdIsMarked(ppd_file_t *ppd, const char *keyword, char char *choice);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>ppd</TD>
+ <TD>The PPD file</TD>
+</TR>
+<TR>
+ <TD>keyword</TD>
+ <TD>The name of the option</TD>
+</TR>
+<TR>
+ <TD>choice</TD>
+ <TD>The name of the option choice</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>1 if the choice is marked, 0 otherwise.
+
+<H3>Description</H3>
+
+<P>The <CODE>ppdIsMarked()</CODE> function returns whether or not the
+specified option choice is marked.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/ppd.h>
+
+ppd_file_t *ppd;
+
+printf("Letter size %s selected.\n",
+ ppdIsMarked(ppd, "PageSize", "Letter") ? "is" : "is not");
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#cupsMarkOptions"><CODE>cupsMarkOptions()</CODE></A>,
+<A HREF="#ppdConflicts"><CODE>ppdConflicts()</CODE></A>,
+<A HREF="#ppdIsMarked"><CODE>ppdIsMarked()</CODE></A>,
+<A HREF="#ppdMarkDefaults"><CODE>ppdMarkDefaults()</CODE></A>,
+<A HREF="#ppdMarkOption"><CODE>ppdMarkOption()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="ppdMarkDefaults">ppdMarkDefaults()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+void ppdMarkDefaults(ppd_file_t *ppd);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>ppd</TD>
+ <TD>The PPD file</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Description</H3>
+
+<P>The <CODE>ppdMarkDefaults()</CODE> function marks all of the default
+choices in the PPD file.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/ppd.h>
+
+ppd_file_t *ppd;
+
+ppdMarkDefaults(ppd);
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#cupsMarkOptions"><CODE>cupsMarkOptions()</CODE></A>,
+<A HREF="#ppdConflicts"><CODE>ppdConflicts()</CODE></A>,
+<A HREF="#ppdIsMarked"><CODE>ppdIsMarked()</CODE></A>,
+<A HREF="#ppdMarkDefaults"><CODE>ppdMarkDefaults()</CODE></A>,
+<A HREF="#ppdMarkOption"><CODE>ppdMarkOption()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="ppdMarkOption">ppdMarkOption()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+int ppdMarkOption(ppd_file_t *ppd, const char *keyword, const char *choice);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>ppd</TD>
+ <TD>The PPD file</TD>
+</TR>
+<TR>
+ <TD>keyword</TD>
+ <TD>The name of the option</TD>
+</TR>
+<TR>
+ <TD>choice</TD>
+ <TD>The name of the choice</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>The number of conflicts in the PPD file.
+
+<H3>Description</H3>
+
+<P>The <CODE>ppdMarkOption()</CODE> function marks the specified option
+choice.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/ppd.h>
+
+ppd_file_t *ppd;
+
+ppdMarkOption(ppd, "PageSize", "Letter");
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#cupsMarkOptions"><CODE>cupsMarkOptions()</CODE></A>,
+<A HREF="#ppdConflicts"><CODE>ppdConflicts()</CODE></A>,
+<A HREF="#ppdIsMarked"><CODE>ppdIsMarked()</CODE></A>,
+<A HREF="#ppdMarkDefaults"><CODE>ppdMarkDefaults()</CODE></A>,
+<A HREF="#ppdMarkOption"><CODE>ppdMarkOption()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="ppdOpen">ppdOpen()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+ppd_file_t *ppdOpen(FILE *file);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>file</TD>
+ <TD>The file to read from</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>A pointer to a PPD file structure or NULL if the PPD file could not be
+read.
+
+<H3>Description</H3>
+
+<P>The <CODE>ppdOpen()</CODE> function reads a PPD file from the specified
+file into memory.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/ppd.h>
+
+ppd_file_t *ppd;
+FILE *file;
+
+file = fopen("filename.ppd", "rb");
+ppd = ppdOpen(file);
+fclose(file);
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#ppdClose"><CODE>ppdClose()</CODE></A>,
+<A HREF="#ppdOpenFd"><CODE>ppdOpenFd()</CODE></A>,
+<A HREF="#ppdOpenFile"><CODE>ppdOpenFile()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="ppdOpenFd">ppdOpenFd()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+ppd_file_t *ppdOpenFd(int fd);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>fd</TD>
+ <TD>The file descriptor to read from</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>A pointer to a PPD file structure or NULL if the PPD file could not be
+read.
+
+<H3>Description</H3>
+
+<P>The <CODE>ppdOpenFd()</CODE> function reads a PPD file from the specified
+file descriptor into memory.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/ppd.h>
+
+ppd_file_t *ppd;
+int fd;
+
+fd = open("filename.ppd", O_RDONLY);
+ppd = ppdOpenFd(fd);
+close(fd);
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#ppdClose"><CODE>ppdClose()</CODE></A>,
+<A HREF="#ppdOpen"><CODE>ppdOpen()</CODE></A>,
+<A HREF="#ppdOpenFile"><CODE>ppdOpenFile()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="ppdOpenFile">ppdOpenFile()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+ppd_file_t *ppdOpenFile(const char *filename);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>filename</TD>
+ <TD>The name of the file to read from</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>A pointer to a PPD file structure or NULL if the PPD file could not be
+read.
+
+<H3>Description</H3>
+
+<P>The <CODE>ppdOpenFile()</CODE> function reads a PPD file from the named
+file into memory.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/ppd.h>
+
+ppd_file_t *ppd;
+
+ppd = ppdOpenFile("filename.ppd");
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#ppdClose"><CODE>ppdClose()</CODE></A>,
+<A HREF="#ppdOpen"><CODE>ppdOpen()</CODE></A>,
+<A HREF="#ppdOpenFd"><CODE>ppdOpenFd()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="ppdPageLength">ppdPageLength()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+float ppdPageLength(ppd_file_t *ppd, const char *name);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>ppd</TD>
+ <TD>The PPD file</TD>
+</TR>
+<TR>
+ <TD>name</TD>
+ <TD>The name of the page size</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>The length of the specified page size in points or 0 if the page size
+does not exist.
+
+<H3>Description</H3>
+
+<P>The <CODE>ppdPageLength()</CODE> function returns the page length of the
+specified page size.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/ppd.h>
+
+ppd_file_t *ppd;
+
+printf("Length = %.0f\n", ppdPageLength(ppd, "Letter"));
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#ppdPageLength"><CODE>ppdPageLength()</CODE></A>,
+<A HREF="#ppdPageSize"><CODE>ppdPageSize()</CODE></A>,
+<A HREF="#ppdPageWidth"><CODE>ppdPageWidth()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="ppdPageSize">ppdPageSize()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+ppd_size_t *ppdPageSize(ppd_file_t *ppd, const char *name);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>ppd</TD>
+ <TD>The PPD file</TD>
+</TR>
+<TR>
+ <TD>name</TD>
+ <TD>The name of the page size</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>A pointer to the page size record of the specified page size in
+points or NULL if the page size does not exist.
+
+<H3>Description</H3>
+
+<P>The <CODE>ppdPageSize()</CODE> function returns the page size record for the
+specified page size.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/ppd.h>
+
+ppd_file_t *ppd;
+ppd_size_t *size;
+
+size = ppdPageSize(ppd, "Letter");
+if (size != NULL)
+{
+ printf(" Width = %.0f\n", size->width);
+ printf("Length = %.0f\n", size->length);
+ printf(" Left = %.0f\n", size->left);
+ printf(" Right = %.0f\n", size->right);
+ printf("Bottom = %.0f\n", size->bottom);
+ printf(" Top = %.0f\n", size->top);
+}
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#ppdPageLength"><CODE>ppdPageLength()</CODE></A>,
+<A HREF="#ppdPageWidth"><CODE>ppdPageWidth()</CODE></A>
+
+
+<!-- NEW PAGE --><H2><A NAME="ppdPageWidth">ppdPageWidth()</A></H2>
+
+<H3>Usage</H3>
+
+<PRE>
+float ppdPageWidth(ppd_file_t *ppd, const char *name);
+</PRE>
+
+<H3>Arguments</H3>
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<TR>
+ <TH>Argument</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>ppd</TD>
+ <TD>The PPD file</TD>
+</TR>
+<TR>
+ <TD>name</TD>
+ <TD>The name of the page size</TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Returns</H3>
+
+<P>The width of the specified page size in points or 0 if the page size
+does not exist.
+
+<H3>Description</H3>
+
+<P>The <CODE>ppdPageWidth()</CODE> function returns the page width of the
+specified page size.
+
+<H3>Example</H3>
+
+<PRE>
+#include &lt;cups/ppd.h>
+
+ppd_file_t *ppd;
+
+printf("Width = %.0f\n", ppdPageWidth(ppd, "Letter"));
+</PRE>
+
+<H3>See Also</H3>
+
+<A HREF="#ppdPageLength"><CODE>ppdPageLength()</CODE></A>,
+<A HREF="#ppdPageSize"><CODE>ppdPageSize()</CODE></A>
+
+
+</BODY>
+</HTML>
diff --git a/doc/sps.html b/doc/sps.html
new file mode 100644
index 000000000..d8f2a1ffa
--- /dev/null
+++ b/doc/sps.html
@@ -0,0 +1,297 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD>
+<TITLE>CUPS Software Performance Specification</TITLE>
+<META NAME="author" CONTENT="Easy Software Products">
+<META NAME="copyright" CONTENT="Copyright 1997-2002, All Rights Reserved">
+<META NAME="docnumber" CONTENT="CUPS-SPS-1.1">
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=iso-8859-1">
+<STYLE TYPE="text/css"><!--
+BODY { font-family: serif }
+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 }
+SUB { font-size: smaller }
+SUP { font-size: smaller }
+PRE { font-family: monospace }
+--></STYLE>
+</HEAD>
+<BODY>
+<CENTER><A HREF="#CONTENTS"><IMG SRC="images/cups-large.gif" BORDER="0" WIDTH="431" HEIGHT="511"><BR>
+<H1>CUPS Software Performance Specification</H1></A><BR>
+CUPS-SPS-1.1<BR>
+Easy Software Products<BR>
+Copyright 1997-2002, All Rights Reserved<BR>
+</CENTER>
+<HR>
+<H1 ALIGN="CENTER"><A NAME="CONTENTS">Table of Contents</A></H1>
+<BR>
+<BR><B><A HREF="#1">1 Scope</A></B>
+<UL>
+<LI><A HREF="#1_1">1.1 Identification</A></LI>
+<LI><A HREF="#1_2">1.2 System Overview</A></LI>
+<LI><A HREF="#1_3">1.3 Document Overview</A></LI>
+</UL>
+<B><A HREF="#2">2 References</A></B>
+<UL>
+<LI><A HREF="#2_1">2.1 CUPS Documentation</A></LI>
+<LI><A HREF="#2_2">2.2 Other Documents</A></LI>
+</UL>
+<B><A HREF="#3">3 Programs</A></B>
+<BR>
+<BR><B><A HREF="#4">4 Scheduler Objects</A></B>
+<BR>
+<BR><B><A HREF="#5">A Glossary</A></B>
+<UL>
+<LI><A HREF="#5_1">A.1 Terms</A></LI>
+<LI><A HREF="#5_2">A.2 Acronyms</A></LI>
+</UL>
+<HR>
+<H1><A NAME="1">1 Scope</A></H1>
+<H2><A NAME="1_1">1.1 Identification</A></H2>
+<P>This software performance specification provides an analysis of the
+ memory, disk, and processor utilitization of each program in the Common
+ UNIX Printing System (&quot;CUPS&quot;) Version 1.1.</P>
+<P>For the purposes of comparison, all figures are for the Linux Intel
+ platform. Memory utilization on other platforms should be similar.</P>
+<H2><A NAME="1_2">1.2 System Overview</A></H2>
+<P>CUPS provides a portable printing layer for UNIX&reg;-based operating
+ systems. It has been developed by<A HREF="http://www.easysw.com"> Easy
+ Software Products</A> to promote a standard printing solution for all
+ UNIX vendors and users. CUPS provides the System V and Berkeley
+ command-line interfaces.</P>
+<P>CUPS uses the Internet Printing Protocol (&quot;IPP&quot;) as the basis for
+ managing print jobs and queues. The Line Printer Daemon (&quot;LPD&quot;) Server
+ Message Block (&quot;SMB&quot;), and AppSocket (a.k.a. JetDirect) protocols are
+ also supported with reduced functionality. CUPS adds network printer
+ browsing and PostScript Printer Description (&quot;PPD&quot;) based printing
+ options to support real-world printing under UNIX.</P>
+<P>CUPS also includes a customized version of GNU Ghostscript (currently
+ based off GNU Ghostscript 5.50) and an image file RIP that are used to
+ support non-PostScript printers. Sample drivers for HP and EPSON
+ printers are included that use these filters.</P>
+<H2><A NAME="1_3">1.3 Document Overview</A></H2>
+<P>This software performance specification is organized into the
+ following sections:</P>
+<UL>
+<LI>1 - Scope</LI>
+<LI>2 - References</LI>
+<LI>3 - Programs</LI>
+<LI>4 - Scheduler Objects</LI>
+<LI>A - Glossary</LI>
+</UL>
+<H1><A NAME="2">2 References</A></H1>
+<H2><A NAME="2_1">2.1 CUPS Documentation</A></H2>
+<P>The following CUPS documentation is referenced by this document:</P>
+<UL>
+<LI>CUPS-CMP-1.1: CUPS Configuration Management Plan</LI>
+<LI>CUPS-IDD-1.1: CUPS System Interface Design Description</LI>
+<LI>CUPS-IPP-1.1: CUPS Implementation of IPP</LI>
+<LI>CUPS-SAM-1.1.x: CUPS Software Administrators Manual</LI>
+<LI>CUPS-SDD-1.1: CUPS Software Design Description</LI>
+<LI>CUPS-SPM-1.1.x: CUPS Software Programming Manual</LI>
+<LI>CUPS-SSR-1.1: CUPS Software Security Report</LI>
+<LI>CUPS-STP-1.1: CUPS Software Test Plan</LI>
+<LI>CUPS-SUM-1.1.x: CUPS Software Users Manual</LI>
+<LI>CUPS-SVD-1.1: CUPS Software Version Description</LI>
+</UL>
+<H2><A NAME="2_2">2.2 Other Documents</A></H2>
+<P>The following non-CUPS documents are referenced by this document:</P>
+<UL>
+<LI><A HREF="http://partners.adobe.com/asn/developer/PDFS/TN/5003.PPD_Spec_v4.3.pdf">
+Adobe PostScript Printer Description File Format Specification, Version
+ 4.3.</A></LI>
+<LI><A HREF="http://partners.adobe.com/asn/developer/PDFS/TN/PLRM.pdf">
+Adobe PostScript Language Reference, Third Edition.</A></LI>
+<LI>IPP: Job and Printer Set Operations</LI>
+<LI>IPP/1.1: Encoding and Transport</LI>
+<LI>IPP/1.1: Implementers Guide</LI>
+<LI>IPP/1.1: Model and Semantics</LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc1179.txt">RFC 1179, Line Printer
+ Daemon Protocol</A></LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc2567.txt">RFC 2567, Design Goals
+ for an Internet Printing Protocol</A></LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc2568.txt">RFC 2568, Rationale
+ for the Structure of the Model and Protocol</A> for the Internet
+ Printing Protocol</LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc2569.txt">RFC 2569, Mapping
+ between LPD and IPP Protocols</A></LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616, Hypertext
+ Transfer Protocol -- HTTP/1.1</A></LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc2617.txt">RFC 2617, HTTP
+ Authentication: Basic and Digest Access</A> Authentication</LI>
+</UL>
+<H1><A NAME="3">3 Programs</A></H1>
+<P>The following table describes the average memory, disk, and CPU usage
+ of each program in CUPS.</P>
+<P>The base memory column shows the initial memory requirements for each
+ program, including any shared libraries that are provided by CUPS.</P>
+<P>The max memory column shows the maximum amount of memory that will be
+ used by the program based upon the default configuration settings
+ supplied with CUPS.</P>
+<P>The temp files column indicates whether any temporary files are
+ created.</P>
+<P>The CPU usage column specifies a relative CPU usage by the program
+ under normal conditions, either low, medium, or high. Low usage
+ indicates that the program will never use more than 33% of the
+ available CPU time. Medium usage indicates the program will use as much
+ as 66% of the available CPU time. High usage indicates the program uses
+ 66% or more of the available CPU time.
+<CENTER>
+<TABLE BORDER="1" WIDTH="80%">
+<TR><TH COLSPAN="3">Backends</TH></TR>
+<TR><TH>Program</TH><TH>Base Memory</TH><TH>Max Memory</TH><TH>Temp
+ Files</TH><TH>CPU Usage</TH></TR>
+<TR><TD>ipp</TD><TD>91k</TD><TD>256k</TD><TD>Up to size of print file</TD><TD>
+Low</TD></TR>
+<TR><TD>lpd</TD><TD>89k</TD><TD>89k</TD><TD>Up to size of print file</TD><TD>
+Low</TD></TR>
+<TR><TD>parallel</TD><TD>85k</TD><TD>85k</TD><TD>Up to size of print
+ file</TD><TD>Low</TD></TR>
+<TR><TD>serial</TD><TD>85k</TD><TD>85k</TD><TD>Up to size of print file</TD><TD>
+Low</TD></TR>
+<TR><TD>socket</TD><TD>85k</TD><TD>85k</TD><TD>Up to size of print file</TD><TD>
+Low</TD></TR>
+<TR><TD>usb</TD><TD>85k</TD><TD>85k</TD><TD>Up to size of print file</TD><TD>
+Low</TD></TR>
+<TR><TH COLSPAN="3">CGIs</TH></TR>
+<TR><TH>Program</TH><TH>Base Memory</TH><TH>Max Memory</TH><TH>Temp
+ Files</TH><TH>CPU Usage</TH></TR>
+<TR><TD>admin.cgi</TD><TD>107k</TD><TD>256k</TD><TD>Up to size of PPD
+ file</TD><TD>Medium</TD></TR>
+<TR><TD>classes.cgi</TD><TD>95k</TD><TD>Size of class objects</TD><TD>
+None</TD><TD>Medium</TD></TR>
+<TR><TD>jobs.cgi</TD><TD>93k</TD><TD>Size of job objects</TD><TD>None</TD><TD>
+Medium</TD></TR>
+<TR><TD>printers.cgi</TD><TD>95k</TD><TD>Size of printer objects</TD><TD>
+None</TD><TD>Medium</TD></TR>
+<TR><TH COLSPAN="3">Command-Line Programs</TH></TR>
+<TR><TH>Program</TH><TH>Base Memory</TH><TH>Max Memory</TH><TH>Temp
+ Files</TH><TH>CPU Usage</TH></TR>
+<TR><TD>accept</TD><TD>88k</TD><TD>128k</TD><TD>None</TD><TD>Low</TD></TR>
+<TR><TD>cancel</TD><TD>88k</TD><TD>128k</TD><TD>None</TD><TD>Low</TD></TR>
+<TR><TD>disable</TD><TD>88k</TD><TD>128k</TD><TD>None</TD><TD>Low</TD></TR>
+<TR><TD>enable</TD><TD>88k</TD><TD>128k</TD><TD>None</TD><TD>Low</TD></TR>
+<TR><TD>lp</TD><TD>90k</TD><TD>256k</TD><TD>None</TD><TD>Low</TD></TR>
+<TR><TD>lpadmin</TD><TD>148k</TD><TD>256k</TD><TD>None</TD><TD>Low</TD></TR>
+<TR><TD>lpc</TD><TD>86k</TD><TD>Size of job and printer objects</TD><TD>
+None</TD><TD>Medium</TD></TR>
+<TR><TD>lpinfo</TD><TD>89k</TD><TD>Size of device and PPD objects</TD><TD>
+None</TD><TD>Medium</TD></TR>
+<TR><TD>lpmove</TD><TD>88k</TD><TD>128k</TD><TD>None</TD><TD>Low</TD></TR>
+<TR><TD>lpoptions</TD><TD>89k</TD><TD>128k</TD><TD>None</TD><TD>Low</TD></TR>
+<TR><TD>lppasswd</TD><TD>90k</TD><TD>90k</TD><TD>None</TD><TD>Low</TD></TR>
+<TR><TD>lpq</TD><TD>87k</TD><TD>Size of job objects</TD><TD>None</TD><TD>
+Medium</TD></TR>
+<TR><TD>lpr</TD><TD>87k</TD><TD>256k</TD><TD>None</TD><TD>Low</TD></TR>
+<TR><TD>lprm</TD><TD>84k</TD><TD>128k</TD><TD>None</TD><TD>Low</TD></TR>
+<TR><TD>lpstat</TD><TD>119k</TD><TD>Size of job, printer, and class
+ objects</TD><TD>None</TD><TD>Medium</TD></TR>
+<TR><TD>reject</TD><TD>88k</TD><TD>128k</TD><TD>None</TD><TD>Low</TD></TR>
+<TR><TH COLSPAN="3">Daemons</TH></TR>
+<TR><TH>Program</TH><TH>Base Memory</TH><TH>Max Memory</TH><TH>Temp
+ Files</TH><TH>CPU Usage</TH></TR>
+<TR><TD>cups-lpd</TD><TD>92k</TD><TD>256k</TD><TD>One file per control
+ or data file from client</TD><TD>Low</TD></TR>
+<TR><TD>cupsd</TD><TD>308k</TD><TD>See Scheduler Requirements</TD><TD>
+See Scheduler Requirements</TD><TD>Medium</TD></TR>
+<TR><TD>cups-polld</TD><TD>84k</TD><TD>Size of printer and class objects</TD><TD>
+None</TD><TD>Low</TD></TR>
+<TR><TH COLSPAN="3">Filters</TH></TR>
+<TR><TH>Program</TH><TH>Base Memory</TH><TH>Max Memory</TH><TH>Temp
+ Files</TH><TH>CPU Usage</TH></TR>
+<TR><TD>hpgltops</TD><TD>263k</TD><TD>320k</TD><TD>None</TD><TD>Medium</TD>
+</TR>
+<TR><TD>imagetops</TD><TD>628k</TD><TD>10M</TD><TD>Swap file for
+ uncompressed image data</TD><TD>Medium</TD></TR>
+<TR><TD>imagetoraster</TD><TD>652k</TD><TD>10M</TD><TD>Swap file for
+ uncompressed image data</TD><TD>High</TD></TR>
+<TR><TD>pstops</TD><TD>775k</TD><TD>840k</TD><TD>Up to size of print
+ file</TD><TD>Medium</TD></TR>
+<TR><TD>pstoraster</TD><TD>4M</TD><TD>14M</TD><TD>Swap file for command
+ lists</TD><TD>High</TD></TR>
+<TR><TD>rastertoepson</TD><TD>693k</TD><TD>1M</TD><TD>None</TD><TD>Low</TD>
+</TR>
+<TR><TD>rastertohp</TD><TD>690k</TD><TD>1M</TD><TD>None</TD><TD>Low</TD></TR>
+<TR><TD>texttops</TD><TD>638k</TD><TD>4*cols*rows</TD><TD>None</TD><TD>
+Low</TD></TR>
+</TABLE>
+</CENTER>
+</P>
+<H1><A NAME="4">4 Scheduler Objects</A></H1>
+<P>The <CODE>cupsd</CODE> program is the CUPS scheduler process. It
+ manages many interdependent server objects that are used to manage and
+ print files to printers.</P>
+<P>The following table provides the memory and disk cost associated with
+ each server object.
+<CENTER>
+<TABLE BORDER="1" WIDTH="80%">
+<TR><TH>Object</TH><TH>Memory Per</TH><TH>Disk Per</TH></TR>
+<TR><TD>Browse ACL</TD><TD>1k</TD><TD>120</TD></TR>
+<TR><TD>Browse Poll</TD><TD>24</TD><TD>80</TD></TR>
+<TR><TD>Browse Relay</TD><TD>28</TD><TD>80</TD></TR>
+<TR><TD>Certificate</TD><TD>76</TD><TD>32</TD></TR>
+<TR><TD>Class</TD><TD>9k</TD><TD>200</TD></TR>
+<TR><TD>Client</TD><TD>13k</TD><TD>-</TD></TR>
+<TR><TD>Device</TD><TD>256</TD><TD>-</TD></TR>
+<TR><TD>Job</TD><TD>2k</TD><TD>1k + size of document files</TD></TR>
+<TR><TD>Location ACL</TD><TD>1k</TD><TD>120</TD></TR>
+<TR><TD>MIME Filter</TD><TD>268</TD><TD>80</TD></TR>
+<TR><TD>MIME Type</TD><TD>340</TD><TD>80</TD></TR>
+<TR><TD>PPD</TD><TD>200</TD><TD>656</TD></TR>
+<TR><TD>Printer</TD><TD>11k</TD><TD>32k</TD></TR>
+</TABLE>
+</CENTER>
+</P>
+<H1 TYPE="A" VALUE="1"><A NAME="5">A Glossary</A></H1>
+<H2><A NAME="5_1">A.1 Terms</A></H2>
+<DL>
+<DT>C</DT>
+<DD>A computer language.</DD>
+<DT>parallel</DT>
+<DD>Sending or receiving data more than 1 bit at a time.</DD>
+<DT>pipe</DT>
+<DD>A one-way communications channel between two programs.</DD>
+<DT>serial</DT>
+<DD>Sending or receiving data 1 bit at a time.</DD>
+<DT>socket</DT>
+<DD>A two-way network communications channel.</DD>
+</DL>
+<H2><A NAME="5_2">A.2 Acronyms</A></H2>
+<DL>
+<DT>ASCII</DT>
+<DD>American Standard Code for Information Interchange</DD>
+<DT>CUPS</DT>
+<DD>Common UNIX Printing System</DD>
+<DT>ESC/P</DT>
+<DD>EPSON Standard Code for Printers</DD>
+<DT>FTP</DT>
+<DD>File Transfer Protocol</DD>
+<DT>HP-GL</DT>
+<DD>Hewlett-Packard Graphics Language</DD>
+<DT>HP-PCL</DT>
+<DD>Hewlett-Packard Page Control Language</DD>
+<DT>HP-PJL</DT>
+<DD>Hewlett-Packard Printer Job Language</DD>
+<DT>IETF</DT>
+<DD>Internet Engineering Task Force</DD>
+<DT>IPP</DT>
+<DD>Internet Printing Protocol</DD>
+<DT>ISO</DT>
+<DD>International Standards Organization</DD>
+<DT>LPD</DT>
+<DD>Line Printer Daemon</DD>
+<DT>MIME</DT>
+<DD>Multimedia Internet Mail Exchange</DD>
+<DT>PPD</DT>
+<DD>PostScript Printer Description</DD>
+<DT>SMB</DT>
+<DD>Server Message Block</DD>
+<DT>TFTP</DT>
+<DD>Trivial File Transfer Protocol</DD>
+</DL>
+</BODY>
+</HTML>
diff --git a/doc/sps.pdf b/doc/sps.pdf
new file mode 100644
index 000000000..5860931ca
--- /dev/null
+++ b/doc/sps.pdf
Binary files differ
diff --git a/doc/sps.shtml b/doc/sps.shtml
new file mode 100644
index 000000000..88959006e
--- /dev/null
+++ b/doc/sps.shtml
@@ -0,0 +1,457 @@
+<HTML>
+<HEAD>
+ <META NAME="COPYRIGHT" CONTENT="Copyright 1997-2002, All Rights Reserved">
+ <META NAME="DOCNUMBER" CONTENT="CUPS-SPS-1.1">
+ <META NAME="Author" CONTENT="Easy Software Products">
+ <TITLE>CUPS Software Performance Specification</TITLE>
+</HEAD>
+<BODY>
+
+<H1>Scope</H1>
+
+<H2>Identification</H2>
+
+<P>This software performance specification provides an analysis of the
+memory, disk, and processor utilitization of each program in the
+Common UNIX Printing System ("CUPS") Version 1.1.</P>
+
+<P>For the purposes of comparison, all figures are for the Linux Intel
+platform. Memory utilization on other platforms should be similar.
+
+<EMBED SRC="system-overview.shtml">
+
+<H2>Document Overview</H2>
+
+<P>This software performance specification is organized into the
+following sections:</P>
+
+<UL>
+ <LI>1 - Scope</LI>
+ <LI>2 - References</LI>
+ <LI>3 - Programs</LI>
+ <LI>4 - Scheduler Objects</LI>
+ <LI>A - Glossary</LI>
+</UL>
+
+<EMBED SRC="references.shtml">
+
+<H1>Programs</H1>
+
+<P>The following table describes the average memory, disk, and CPU usage of
+each program in CUPS.
+
+<P>The base memory column shows the initial memory requirements for each
+program, including any shared libraries that are provided by CUPS.
+
+<P>The max memory column shows the maximum amount of memory that will be
+used by the program based upon the default configuration settings supplied
+with CUPS.
+
+<P>The temp files column indicates whether any temporary files are created.
+
+<P>The CPU usage column specifies a relative CPU usage by the program under
+normal conditions, either low, medium, or high. Low usage indicates that
+the program will never use more than 33% of the available CPU time. Medium
+usage indicates the program will use as much as 66% of the available CPU
+time. High usage indicates the program uses 66% or more of the available CPU
+time.
+
+<CENTER><TABLE WIDTH="80%" BORDER="1">
+<TR>
+ <TH COLSPAN="3">Backends</TH>
+</TR>
+<TR>
+ <TH>Program</TH>
+ <TH>Base Memory</TH>
+ <TH>Max Memory</TH>
+ <TH>Temp Files</TH>
+ <TH>CPU Usage</TH>
+</TR>
+<TR>
+ <TD>ipp</TD>
+ <TD>91k</TD>
+ <TD>256k</TD>
+ <TD>Up to size of print file</TD>
+ <TD>Low</TD>
+</TR>
+<TR>
+ <TD>lpd</TD>
+ <TD>89k</TD>
+ <TD>89k</TD>
+ <TD>Up to size of print file</TD>
+ <TD>Low</TD>
+</TR>
+<TR>
+ <TD>parallel</TD>
+ <TD>85k</TD>
+ <TD>85k</TD>
+ <TD>Up to size of print file</TD>
+ <TD>Low</TD>
+</TR>
+<TR>
+ <TD>serial</TD>
+ <TD>85k</TD>
+ <TD>85k</TD>
+ <TD>Up to size of print file</TD>
+ <TD>Low</TD>
+</TR>
+<TR>
+ <TD>socket</TD>
+ <TD>85k</TD>
+ <TD>85k</TD>
+ <TD>Up to size of print file</TD>
+ <TD>Low</TD>
+</TR>
+<TR>
+ <TD>usb</TD>
+ <TD>85k</TD>
+ <TD>85k</TD>
+ <TD>Up to size of print file</TD>
+ <TD>Low</TD>
+</TR>
+<TR>
+ <TH COLSPAN="3">CGIs</TH>
+</TR>
+<TR>
+ <TH>Program</TH>
+ <TH>Base Memory</TH>
+ <TH>Max Memory</TH>
+ <TH>Temp Files</TH>
+ <TH>CPU Usage</TH>
+</TR>
+<TR>
+ <TD>admin.cgi</TD>
+ <TD>107k</TD>
+ <TD>256k</TD>
+ <TD>Up to size of PPD file</TD>
+ <TD>Medium</TD>
+</TR>
+<TR>
+ <TD>classes.cgi</TD>
+ <TD>95k</TD>
+ <TD>Size of class objects</TD>
+ <TD>None</TD>
+ <TD>Medium</TD>
+</TR>
+<TR>
+ <TD>jobs.cgi</TD>
+ <TD>93k</TD>
+ <TD>Size of job objects</TD>
+ <TD>None</TD>
+ <TD>Medium</TD>
+</TR>
+<TR>
+ <TD>printers.cgi</TD>
+ <TD>95k</TD>
+ <TD>Size of printer objects</TD>
+ <TD>None</TD>
+ <TD>Medium</TD>
+</TR>
+<TR>
+ <TH COLSPAN="3">Command-Line Programs</TH>
+</TR>
+<TR>
+ <TH>Program</TH>
+ <TH>Base Memory</TH>
+ <TH>Max Memory</TH>
+ <TH>Temp Files</TH>
+ <TH>CPU Usage</TH>
+</TR>
+<TR>
+ <TD>accept</TD>
+ <TD>88k</TD>
+ <TD>128k</TD>
+ <TD>None</TD>
+ <TD>Low</TD>
+</TR>
+<TR>
+ <TD>cancel</TD>
+ <TD>88k</TD>
+ <TD>128k</TD>
+ <TD>None</TD>
+ <TD>Low</TD>
+</TR>
+<TR>
+ <TD>disable</TD>
+ <TD>88k</TD>
+ <TD>128k</TD>
+ <TD>None</TD>
+ <TD>Low</TD>
+</TR>
+<TR>
+ <TD>enable</TD>
+ <TD>88k</TD>
+ <TD>128k</TD>
+ <TD>None</TD>
+ <TD>Low</TD>
+</TR>
+<TR>
+ <TD>lp</TD>
+ <TD>90k</TD>
+ <TD>256k</TD>
+ <TD>None</TD>
+ <TD>Low</TD>
+</TR>
+<TR>
+ <TD>lpadmin</TD>
+ <TD>148k</TD>
+ <TD>256k</TD>
+ <TD>None</TD>
+ <TD>Low</TD>
+</TR>
+<TR>
+ <TD>lpc</TD>
+ <TD>86k</TD>
+ <TD>Size of job and printer objects</TD>
+ <TD>None</TD>
+ <TD>Medium</TD>
+</TR>
+<TR>
+ <TD>lpinfo</TD>
+ <TD>89k</TD>
+ <TD>Size of device and PPD objects</TD>
+ <TD>None</TD>
+ <TD>Medium</TD>
+</TR>
+<TR>
+ <TD>lpmove</TD>
+ <TD>88k</TD>
+ <TD>128k</TD>
+ <TD>None</TD>
+ <TD>Low</TD>
+</TR>
+<TR>
+ <TD>lpoptions</TD>
+ <TD>89k</TD>
+ <TD>128k</TD>
+ <TD>None</TD>
+ <TD>Low</TD>
+</TR>
+<TR>
+ <TD>lppasswd</TD>
+ <TD>90k</TD>
+ <TD>90k</TD>
+ <TD>None</TD>
+ <TD>Low</TD>
+</TR>
+<TR>
+ <TD>lpq</TD>
+ <TD>87k</TD>
+ <TD>Size of job objects</TD>
+ <TD>None</TD>
+ <TD>Medium</TD>
+</TR>
+<TR>
+ <TD>lpr</TD>
+ <TD>87k</TD>
+ <TD>256k</TD>
+ <TD>None</TD>
+ <TD>Low</TD>
+</TR>
+<TR>
+ <TD>lprm</TD>
+ <TD>84k</TD>
+ <TD>128k</TD>
+ <TD>None</TD>
+ <TD>Low</TD>
+</TR>
+<TR>
+ <TD>lpstat</TD>
+ <TD>119k</TD>
+ <TD>Size of job, printer, and class objects</TD>
+ <TD>None</TD>
+ <TD>Medium</TD>
+</TR>
+<TR>
+ <TD>reject</TD>
+ <TD>88k</TD>
+ <TD>128k</TD>
+ <TD>None</TD>
+ <TD>Low</TD>
+</TR>
+<TR>
+ <TH COLSPAN="3">Daemons</TH>
+</TR>
+<TR>
+ <TH>Program</TH>
+ <TH>Base Memory</TH>
+ <TH>Max Memory</TH>
+ <TH>Temp Files</TH>
+ <TH>CPU Usage</TH>
+</TR>
+<TR>
+ <TD>cups-lpd</TD>
+ <TD>92k</TD>
+ <TD>256k</TD>
+ <TD>One file per control or data file from client</TD>
+ <TD>Low</TD>
+</TR>
+<TR>
+ <TD>cupsd</TD>
+ <TD>308k</TD>
+ <TD>See Scheduler Requirements</TD>
+ <TD>See Scheduler Requirements</TD>
+ <TD>Medium</TD>
+</TR>
+<TR>
+ <TD>cups-polld</TD>
+ <TD>84k</TD>
+ <TD>Size of printer and class objects</TD>
+ <TD>None</TD>
+ <TD>Low</TD>
+</TR>
+<TR>
+ <TH COLSPAN="3">Filters</TH>
+</TR>
+<TR>
+ <TH>Program</TH>
+ <TH>Base Memory</TH>
+ <TH>Max Memory</TH>
+ <TH>Temp Files</TH>
+ <TH>CPU Usage</TH>
+</TR>
+<TR>
+ <TD>hpgltops</TD>
+ <TD>263k</TD>
+ <TD>320k</TD>
+ <TD>None</TD>
+ <TD>Medium</TD>
+</TR>
+<TR>
+ <TD>imagetops</TD>
+ <TD>628k</TD>
+ <TD>10M</TD>
+ <TD>Swap file for uncompressed image data</TD>
+ <TD>Medium</TD>
+</TR>
+<TR>
+ <TD>imagetoraster</TD>
+ <TD>652k</TD>
+ <TD>10M</TD>
+ <TD>Swap file for uncompressed image data</TD>
+ <TD>High</TD>
+</TR>
+<TR>
+ <TD>pstops</TD>
+ <TD>775k</TD>
+ <TD>840k</TD>
+ <TD>Up to size of print file</TD>
+ <TD>Medium</TD>
+</TR>
+<TR>
+ <TD>pstoraster</TD>
+ <TD>4M</TD>
+ <TD>14M</TD>
+ <TD>Swap file for command lists</TD>
+ <TD>High</TD>
+</TR>
+<TR>
+ <TD>rastertoepson</TD>
+ <TD>693k</TD>
+ <TD>1M</TD>
+ <TD>None</TD>
+ <TD>Low</TD>
+</TR>
+<TR>
+ <TD>rastertohp</TD>
+ <TD>690k</TD>
+ <TD>1M</TD>
+ <TD>None</TD>
+ <TD>Low</TD>
+</TR>
+<TR>
+ <TD>texttops</TD>
+ <TD>638k</TD>
+ <TD>4*cols*rows</TD>
+ <TD>None</TD>
+ <TD>Low</TD>
+</TR>
+</TABLE></CENTER>
+
+
+<H1>Scheduler Objects</H1>
+
+<P>The <CODE>cupsd</CODE> program is the CUPS scheduler process. It manages
+many interdependent server objects that are used to manage and print files
+to printers.
+
+<P>The following table provides the memory and disk cost associated with each
+server object.
+
+<CENTER><TABLE WIDTH="80%" BORDER="1">
+<TR>
+ <TH>Object</TH>
+ <TH>Memory Per</TH>
+ <TH>Disk Per</TH>
+</TR>
+<TR>
+ <TD>Browse ACL</TD>
+ <TD>1k</TD>
+ <TD>120</TD>
+</TR>
+<TR>
+ <TD>Browse Poll</TD>
+ <TD>24</TD>
+ <TD>80</TD>
+</TR>
+<TR>
+ <TD>Browse Relay</TD>
+ <TD>28</TD>
+ <TD>80</TD>
+</TR>
+<TR>
+ <TD>Certificate</TD>
+ <TD>76</TD>
+ <TD>32</TD>
+</TR>
+<TR>
+ <TD>Class</TD>
+ <TD>9k</TD>
+ <TD>200</TD>
+</TR>
+<TR>
+ <TD>Client</TD>
+ <TD>13k</TD>
+ <TD>-</TD>
+</TR>
+<TR>
+ <TD>Device</TD>
+ <TD>256</TD>
+ <TD>-</TD>
+</TR>
+<TR>
+ <TD>Job</TD>
+ <TD>2k</TD>
+ <TD>1k + size of document files</TD>
+</TR>
+<TR>
+ <TD>Location ACL</TD>
+ <TD>1k</TD>
+ <TD>120</TD>
+</TR>
+<TR>
+ <TD>MIME Filter</TD>
+ <TD>268</TD>
+ <TD>80</TD>
+</TR>
+<TR>
+ <TD>MIME Type</TD>
+ <TD>340</TD>
+ <TD>80</TD>
+</TR>
+<TR>
+ <TD>PPD</TD>
+ <TD>200</TD>
+ <TD>656</TD>
+</TR>
+<TR>
+ <TD>Printer</TD>
+ <TD>11k</TD>
+ <TD>32k</TD>
+</TR>
+</TABLE></CENTER>
+
+<EMBED SRC="glossary.shtml">
+
+</BODY>
+</HTML>
diff --git a/doc/ssr.html b/doc/ssr.html
new file mode 100644
index 000000000..e5e548842
--- /dev/null
+++ b/doc/ssr.html
@@ -0,0 +1,269 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD>
+<TITLE>CUPS Software Security Report</TITLE>
+<META NAME="author" CONTENT="Easy Software Products">
+<META NAME="copyright" CONTENT="Copyright 1997-2002, All Rights Reserved">
+<META NAME="docnumber" CONTENT="CUPS-SSR-1.1">
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=iso-8859-1">
+<STYLE TYPE="text/css"><!--
+BODY { font-family: serif }
+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 }
+SUB { font-size: smaller }
+SUP { font-size: smaller }
+PRE { font-family: monospace }
+--></STYLE>
+</HEAD>
+<BODY>
+<CENTER><A HREF="#CONTENTS"><IMG SRC="images/cups-large.gif" BORDER="0" WIDTH="431" HEIGHT="511"><BR>
+<H1>CUPS Software Security Report</H1></A><BR>
+CUPS-SSR-1.1<BR>
+Easy Software Products<BR>
+Copyright 1997-2002, All Rights Reserved<BR>
+</CENTER>
+<HR>
+<H1 ALIGN="CENTER"><A NAME="CONTENTS">Table of Contents</A></H1>
+<BR>
+<BR><B><A HREF="#1">1 Scope</A></B>
+<UL>
+<LI><A HREF="#1_1">1.1 Identification</A></LI>
+<LI><A HREF="#1_2">1.2 System Overview</A></LI>
+<LI><A HREF="#1_3">1.3 Document Overview</A></LI>
+</UL>
+<B><A HREF="#2">2 References</A></B>
+<UL>
+<LI><A HREF="#2_1">2.1 CUPS Documentation</A></LI>
+<LI><A HREF="#2_2">2.2 Other Documents</A></LI>
+</UL>
+<B><A HREF="#3">3 Local Access Risks</A></B>
+<UL>
+<LI><A HREF="#3_1">3.1 Security Breaches</A></LI>
+</UL>
+<B><A HREF="#4">4 Remote Access Risks</A></B>
+<UL>
+<LI><A HREF="#4_1">4.1 Denial of Service Attacks</A></LI>
+<LI><A HREF="#4_2">4.2 Security Breaches</A></LI>
+</UL>
+<B><A HREF="#5">A Glossary</A></B>
+<UL>
+<LI><A HREF="#5_1">A.1 Terms</A></LI>
+<LI><A HREF="#5_2">A.2 Acronyms</A></LI>
+</UL>
+<HR>
+<H1><A NAME="1">1 Scope</A></H1>
+<H2><A NAME="1_1">1.1 Identification</A></H2>
+<P>This software security report provides an analysis of possible
+ security concerns for the Common UNIX Printing System (&quot;CUPS&quot;) Version
+ 1.1.</P>
+<H2><A NAME="1_2">1.2 System Overview</A></H2>
+<P>CUPS provides a portable printing layer for UNIX&reg;-based operating
+ systems. It has been developed by<A HREF="http://www.easysw.com"> Easy
+ Software Products</A> to promote a standard printing solution for all
+ UNIX vendors and users. CUPS provides the System V and Berkeley
+ command-line interfaces.</P>
+<P>CUPS uses the Internet Printing Protocol (&quot;IPP&quot;) as the basis for
+ managing print jobs and queues. The Line Printer Daemon (&quot;LPD&quot;) Server
+ Message Block (&quot;SMB&quot;), and AppSocket (a.k.a. JetDirect) protocols are
+ also supported with reduced functionality. CUPS adds network printer
+ browsing and PostScript Printer Description (&quot;PPD&quot;) based printing
+ options to support real-world printing under UNIX.</P>
+<P>CUPS also includes a customized version of GNU Ghostscript (currently
+ based off GNU Ghostscript 5.50) and an image file RIP that are used to
+ support non-PostScript printers. Sample drivers for HP and EPSON
+ printers are included that use these filters.</P>
+<H2><A NAME="1_3">1.3 Document Overview</A></H2>
+<P>This software security report is organized into the following
+ sections:</P>
+<UL>
+<LI>1 - Scope</LI>
+<LI>2 - References</LI>
+<LI>3 - Local Access Risks</LI>
+<LI>4 - Remote Access Risks</LI>
+<LI>A - Glossary</LI>
+</UL>
+<H1><A NAME="2">2 References</A></H1>
+<H2><A NAME="2_1">2.1 CUPS Documentation</A></H2>
+<P>The following CUPS documentation is referenced by this document:</P>
+<UL>
+<LI>CUPS-CMP-1.1: CUPS Configuration Management Plan</LI>
+<LI>CUPS-IDD-1.1: CUPS System Interface Design Description</LI>
+<LI>CUPS-IPP-1.1: CUPS Implementation of IPP</LI>
+<LI>CUPS-SAM-1.1.x: CUPS Software Administrators Manual</LI>
+<LI>CUPS-SDD-1.1: CUPS Software Design Description</LI>
+<LI>CUPS-SPM-1.1.x: CUPS Software Programming Manual</LI>
+<LI>CUPS-SSR-1.1: CUPS Software Security Report</LI>
+<LI>CUPS-STP-1.1: CUPS Software Test Plan</LI>
+<LI>CUPS-SUM-1.1.x: CUPS Software Users Manual</LI>
+<LI>CUPS-SVD-1.1: CUPS Software Version Description</LI>
+</UL>
+<H2><A NAME="2_2">2.2 Other Documents</A></H2>
+<P>The following non-CUPS documents are referenced by this document:</P>
+<UL>
+<LI><A HREF="http://partners.adobe.com/asn/developer/PDFS/TN/5003.PPD_Spec_v4.3.pdf">
+Adobe PostScript Printer Description File Format Specification, Version
+ 4.3.</A></LI>
+<LI><A HREF="http://partners.adobe.com/asn/developer/PDFS/TN/PLRM.pdf">
+Adobe PostScript Language Reference, Third Edition.</A></LI>
+<LI>IPP: Job and Printer Set Operations</LI>
+<LI>IPP/1.1: Encoding and Transport</LI>
+<LI>IPP/1.1: Implementers Guide</LI>
+<LI>IPP/1.1: Model and Semantics</LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc1179.txt">RFC 1179, Line Printer
+ Daemon Protocol</A></LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc2567.txt">RFC 2567, Design Goals
+ for an Internet Printing Protocol</A></LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc2568.txt">RFC 2568, Rationale
+ for the Structure of the Model and Protocol</A> for the Internet
+ Printing Protocol</LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc2569.txt">RFC 2569, Mapping
+ between LPD and IPP Protocols</A></LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616, Hypertext
+ Transfer Protocol -- HTTP/1.1</A></LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc2617.txt">RFC 2617, HTTP
+ Authentication: Basic and Digest Access</A> Authentication</LI>
+</UL>
+<H1><A NAME="3">3 Local Access Risks</A></H1>
+<P>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.</P>
+<H2><A NAME="3_1">3.1 Security Breaches</A></H2>
+<P>There is one known security vulnerability with local access:</P>
+<OL>
+<LI>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.</LI>
+<P>We recommend that any password-protected accounts used for remote
+ printing have limited access priviledges so that the possible damages
+ can be minimized.</P>
+<P>The device URI is &quot;sanitized&quot; (the username and password are removed)
+ when sent to an IPP client so that a remote user cannot exploit this
+ vulnerability.</P>
+</OL>
+<H1><A NAME="4">4 Remote Access Risks</A></H1>
+<P>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.</P>
+<H2><A NAME="4_1">4.1 Denial of Service Attacks</A></H2>
+<P>Like all Internet services, the CUPS server is vulnerable to denial
+ of service attacks, including:</P>
+<OL>
+<LI>Establishing multiple connections to the server until the server
+ will accept no more.</LI>
+<P>This cannot be protected against by the current software. It is
+ possible that future versions of the CUPS software could be configured
+ to limit the number of connections allowed from a single host, however
+ that still would not prevent a distributed attack.</P>
+<LI>Repeatedly opening and closing connections to the server as fast as
+ possible.</LI>
+<P>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.</P>
+<LI>Flooding the network with broadcast packets on port 631.</LI>
+<P>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.</P>
+<LI>Sending partial IPP requests; specifically, sending part of an
+ attribute value and then stopping transmission.</LI>
+<P>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.</P>
+<LI>Sending large/long print jobs to printers, preventing other users
+ from printing.</LI>
+<P>There are limited facilities for protecting against large print jobs
+ (the <CODE>MaxRequestSize</CODE> 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.</P>
+</OL>
+<H2><A NAME="4_2">4.2 Security Breaches</A></H2>
+<P>The current CUPS server supports Basic, Digest, and local certificate
+ authentication:</P>
+<OL>
+<LI>Basic authentication essentially places the clear text of the
+ username and password on the network. Since CUPS uses the UNIX username
+ and password account information, the authentication information could
+ be used to gain access to accounts (possibly priviledged accounts) on
+ the server.</LI>
+<LI>Digest authentication uses an MD5 checksum of the username,
+ password, and domain (&quot;CUPS&quot;), so the original username and password is
+ not sent over the network. However, the current implementation does not
+ authenticate the entire message and uses the client's IP address for
+ the nonce value, making it possible to launch &quot;man in the middle&quot; and
+ replay attacks from the same client. The next minor release of CUPS
+ will support Digest authentication of the entire message body,
+ effectively stopping these methods of attack.</LI>
+<LI>Local certificate authentication passes 128-bit &quot;certificates&quot; that
+ identify an authenticated user. Certificates are created on-the-fly
+ from random data and stored in files under <CODE>/etc/cups/certs</CODE>
+. They have restricted read permissions: root + system for the root
+ certificate, and lp + system for CGI certificates. Because certificates
+ are only available on the local system, the CUPS server does not accept
+ local authentication unless the client is connected to the localhost
+ address (127.0.0.1.)</LI>
+</OL>
+<P>The default CUPS configuration disables remote administration. We do
+ not recommend that remote administration be enabled for all hosts.
+ However, if you have a trusted network or subnet, access can be
+ restricted accordingly. Also, we highly recommend using Digest
+ authentication when possible. Unfortunately, most web browsers do not
+ support Digest authentication at this time.</P>
+<H1 TYPE="A" VALUE="1"><A NAME="5">A Glossary</A></H1>
+<H2><A NAME="5_1">A.1 Terms</A></H2>
+<DL>
+<DT>C</DT>
+<DD>A computer language.</DD>
+<DT>parallel</DT>
+<DD>Sending or receiving data more than 1 bit at a time.</DD>
+<DT>pipe</DT>
+<DD>A one-way communications channel between two programs.</DD>
+<DT>serial</DT>
+<DD>Sending or receiving data 1 bit at a time.</DD>
+<DT>socket</DT>
+<DD>A two-way network communications channel.</DD>
+</DL>
+<H2><A NAME="5_2">A.2 Acronyms</A></H2>
+<DL>
+<DT>ASCII</DT>
+<DD>American Standard Code for Information Interchange</DD>
+<DT>CUPS</DT>
+<DD>Common UNIX Printing System</DD>
+<DT>ESC/P</DT>
+<DD>EPSON Standard Code for Printers</DD>
+<DT>FTP</DT>
+<DD>File Transfer Protocol</DD>
+<DT>HP-GL</DT>
+<DD>Hewlett-Packard Graphics Language</DD>
+<DT>HP-PCL</DT>
+<DD>Hewlett-Packard Page Control Language</DD>
+<DT>HP-PJL</DT>
+<DD>Hewlett-Packard Printer Job Language</DD>
+<DT>IETF</DT>
+<DD>Internet Engineering Task Force</DD>
+<DT>IPP</DT>
+<DD>Internet Printing Protocol</DD>
+<DT>ISO</DT>
+<DD>International Standards Organization</DD>
+<DT>LPD</DT>
+<DD>Line Printer Daemon</DD>
+<DT>MIME</DT>
+<DD>Multimedia Internet Mail Exchange</DD>
+<DT>PPD</DT>
+<DD>PostScript Printer Description</DD>
+<DT>SMB</DT>
+<DD>Server Message Block</DD>
+<DT>TFTP</DT>
+<DD>Trivial File Transfer Protocol</DD>
+</DL>
+</BODY>
+</HTML>
diff --git a/doc/ssr.pdf b/doc/ssr.pdf
new file mode 100644
index 000000000..afb05b63a
--- /dev/null
+++ b/doc/ssr.pdf
Binary files differ
diff --git a/doc/ssr.shtml b/doc/ssr.shtml
new file mode 100644
index 000000000..8dc9cf590
--- /dev/null
+++ b/doc/ssr.shtml
@@ -0,0 +1,167 @@
+<HTML>
+<HEAD>
+ <META NAME="COPYRIGHT" CONTENT="Copyright 1997-2002, All Rights Reserved">
+ <META NAME="DOCNUMBER" CONTENT="CUPS-SSR-1.1">
+ <META NAME="Author" CONTENT="Easy Software Products">
+ <TITLE>CUPS Software Security Report</TITLE>
+</HEAD>
+<BODY>
+
+<H1>Scope</H1>
+
+<H2>Identification</H2>
+
+<P>This software security report provides an analysis of possible security
+concerns for the Common UNIX Printing System ("CUPS") Version 1.1.</P>
+
+<EMBED SRC="system-overview.shtml">
+
+<H2>Document Overview</H2>
+
+<P>This software security report is organized into the following sections:</P>
+
+<UL>
+ <LI>1 - Scope</LI>
+ <LI>2 - References</LI>
+ <LI>3 - Local Access Risks</LI>
+ <LI>4 - Remote Access Risks</LI>
+ <LI>A - Glossary</LI>
+</UL>
+
+<EMBED SRC="references.shtml">
+
+<H1>Local Access Risks</H1>
+
+<P>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.
+
+<H2>Security Breaches</H2>
+
+<P>There is one known security vulnerability with local access:
+
+<OL>
+
+ <LI>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.
+
+ <P>We recommend that any password-protected accounts used for
+ remote printing have limited access priviledges so that the
+ possible damages can be minimized.
+
+ <P>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.
+
+</OL>
+
+<H1>Remote Access Risks</H1>
+
+<P>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.
+
+<H2>Denial of Service Attacks</H2>
+
+<P>Like all Internet services, the CUPS server is vulnerable to denial of
+service attacks, including:
+
+<OL>
+
+ <LI>Establishing multiple connections to the server until the server
+ will accept no more.
+
+ <P>This cannot be protected against by the current software. It
+ is possible that future versions of the CUPS software could be
+ configured to limit the number of connections allowed from a
+ single host, however that still would not prevent a distributed
+ attack.
+
+ <LI>Repeatedly opening and closing connections to the server as fast
+ as possible.
+
+ <P>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.
+
+ <LI>Flooding the network with broadcast packets on port 631.
+
+ <P>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.
+
+ <LI>Sending partial IPP requests; specifically, sending part of an
+ attribute value and then stopping transmission.
+
+ <P>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.
+
+ <LI>Sending large/long print jobs to printers, preventing other users
+ from printing.
+
+ <P>There are limited facilities for protecting against large print
+ jobs (the <CODE>MaxRequestSize</CODE> 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.
+
+</OL>
+
+<H2>Security Breaches</H2>
+
+<P>The current CUPS server supports Basic, Digest, and local certificate
+authentication:
+
+<OL>
+
+ <LI>Basic authentication essentially places the clear text of
+ the username and password on the network. Since CUPS uses the
+ UNIX username and password account information, the
+ authentication information could be used to gain access to
+ accounts (possibly priviledged accounts) on the server.
+
+ <LI>Digest authentication uses an MD5 checksum of the username,
+ password, and domain ("CUPS"), so the original username and
+ password is not sent over the network. However, the current
+ implementation does not authenticate the entire message and
+ uses the client's IP address for the nonce value, making it
+ possible to launch "man in the middle" and replay attacks from
+ the same client. The next minor release of CUPS will support
+ Digest authentication of the entire message body, effectively
+ stopping these methods of attack.
+
+ <LI>Local certificate authentication passes 128-bit
+ "certificates" that identify an authenticated user.
+ Certificates are created on-the-fly from random data and stored
+ in files under <CODE>/etc/cups/certs</CODE>. They have
+ restricted read permissions: root + system for the root
+ certificate, and lp + system for CGI certificates. Because
+ certificates are only available on the local system, the CUPS
+ server does not accept local authentication unless the client
+ is connected to the localhost address (127.0.0.1.)
+
+</OL>
+
+<P>The default CUPS configuration disables remote administration. We do
+not recommend that remote administration be enabled for all hosts.
+However, if you have a trusted network or subnet, access can be
+restricted accordingly.
+
+Also, we highly recommend using Digest authentication when possible.
+Unfortunately, most web browsers do not support Digest authentication
+at this time.
+
+<EMBED SRC="glossary.shtml">
+
+</BODY>
+</HTML>
diff --git a/doc/stp.html b/doc/stp.html
new file mode 100644
index 000000000..6eaf16945
--- /dev/null
+++ b/doc/stp.html
@@ -0,0 +1,262 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD>
+<TITLE>CUPS Software Test Plan</TITLE>
+<META NAME="author" CONTENT="Easy Software Products">
+<META NAME="copyright" CONTENT="Copyright 1997-2002, All Rights Reserved">
+<META NAME="docnumber" CONTENT="CUPS-STP-1.1">
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=iso-8859-1">
+<STYLE TYPE="text/css"><!--
+BODY { font-family: serif }
+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 }
+SUB { font-size: smaller }
+SUP { font-size: smaller }
+PRE { font-family: monospace }
+--></STYLE>
+</HEAD>
+<BODY>
+<CENTER><A HREF="#CONTENTS"><IMG SRC="images/cups-large.gif" BORDER="0" WIDTH="431" HEIGHT="511"><BR>
+<H1>CUPS Software Test Plan</H1></A><BR>
+CUPS-STP-1.1<BR>
+Easy Software Products<BR>
+Copyright 1997-2002, All Rights Reserved<BR>
+</CENTER>
+<HR>
+<H1 ALIGN="CENTER"><A NAME="CONTENTS">Table of Contents</A></H1>
+<BR>
+<BR><B><A HREF="#1">1 Scope</A></B>
+<UL>
+<LI><A HREF="#1_1">1.1 Identification</A></LI>
+<LI><A HREF="#1_2">1.2 System Overview</A></LI>
+<LI><A HREF="#1_3">1.3 Document Overview</A></LI>
+</UL>
+<B><A HREF="#2">2 References</A></B>
+<UL>
+<LI><A HREF="#2_1">2.1 CUPS Documentation</A></LI>
+<LI><A HREF="#2_2">2.2 Other Documents</A></LI>
+</UL>
+<B><A HREF="#3">3 Test Procedure</A></B>
+<BR>
+<BR><B><A HREF="#4">4 IPP Compliance Tests</A></B>
+<UL>
+<LI><A HREF="#4_1">4.1 Request Tests</A></LI>
+<LI><A HREF="#4_2">4.2 CUPS Printer Operation Tests</A></LI>
+<LI><A HREF="#4_3">4.3 Job Operation Tests</A></LI>
+</UL>
+<B><A HREF="#5">5 Command Tests</A></B>
+<UL>
+<LI><A HREF="#5_1">5.1 lpadmin</A></LI>
+<LI><A HREF="#5_2">5.2 lpc</A></LI>
+<LI><A HREF="#5_3">5.3 lpq</A></LI>
+<LI><A HREF="#5_4">5.4 lpstat</A></LI>
+<LI><A HREF="#5_5">5.5 lp</A></LI>
+<LI><A HREF="#5_6">5.6 lpr</A></LI>
+<LI><A HREF="#5_7">5.7 lprm</A></LI>
+<LI><A HREF="#5_8">5.8 cancel</A></LI>
+<LI><A HREF="#5_9">5.9 lpinfo</A></LI>
+</UL>
+<B><A HREF="#6">A Glossary</A></B>
+<UL>
+<LI><A HREF="#6_1">A.1 Terms</A></LI>
+<LI><A HREF="#6_2">A.2 Acronyms</A></LI>
+</UL>
+<HR>
+<H1><A NAME="1">1 Scope</A></H1>
+<H2><A NAME="1_1">1.1 Identification</A></H2>
+<P>This software test plan provides detailed tests that are used to
+ evaluate the stability and compliance of the Common UNIX Printing
+ System (&quot;CUPS&quot;) Version 1.1.</P>
+<H2><A NAME="1_2">1.2 System Overview</A></H2>
+<P>CUPS provides a portable printing layer for UNIX&reg;-based operating
+ systems. It has been developed by<A HREF="http://www.easysw.com"> Easy
+ Software Products</A> to promote a standard printing solution for all
+ UNIX vendors and users. CUPS provides the System V and Berkeley
+ command-line interfaces.</P>
+<P>CUPS uses the Internet Printing Protocol (&quot;IPP&quot;) as the basis for
+ managing print jobs and queues. The Line Printer Daemon (&quot;LPD&quot;) Server
+ Message Block (&quot;SMB&quot;), and AppSocket (a.k.a. JetDirect) protocols are
+ also supported with reduced functionality. CUPS adds network printer
+ browsing and PostScript Printer Description (&quot;PPD&quot;) based printing
+ options to support real-world printing under UNIX.</P>
+<P>CUPS also includes a customized version of GNU Ghostscript (currently
+ based off GNU Ghostscript 5.50) and an image file RIP that are used to
+ support non-PostScript printers. Sample drivers for HP and EPSON
+ printers are included that use these filters.</P>
+<H2><A NAME="1_3">1.3 Document Overview</A></H2>
+<P>This software test plan is organized into the following sections:</P>
+<UL>
+<LI>1 - Scope</LI>
+<LI>2 - References</LI>
+<LI>3 - Test Procedure</LI>
+<LI>4 - IPP Compliance Tests</LI>
+<LI>5 - Command Tests</LI>
+<LI>A - Glossary</LI>
+</UL>
+<H1><A NAME="2">2 References</A></H1>
+<H2><A NAME="2_1">2.1 CUPS Documentation</A></H2>
+<P>The following CUPS documentation is referenced by this document:</P>
+<UL>
+<LI>CUPS-CMP-1.1: CUPS Configuration Management Plan</LI>
+<LI>CUPS-IDD-1.1: CUPS System Interface Design Description</LI>
+<LI>CUPS-IPP-1.1: CUPS Implementation of IPP</LI>
+<LI>CUPS-SAM-1.1.x: CUPS Software Administrators Manual</LI>
+<LI>CUPS-SDD-1.1: CUPS Software Design Description</LI>
+<LI>CUPS-SPM-1.1.x: CUPS Software Programming Manual</LI>
+<LI>CUPS-SSR-1.1: CUPS Software Security Report</LI>
+<LI>CUPS-STP-1.1: CUPS Software Test Plan</LI>
+<LI>CUPS-SUM-1.1.x: CUPS Software Users Manual</LI>
+<LI>CUPS-SVD-1.1: CUPS Software Version Description</LI>
+</UL>
+<H2><A NAME="2_2">2.2 Other Documents</A></H2>
+<P>The following non-CUPS documents are referenced by this document:</P>
+<UL>
+<LI><A HREF="http://partners.adobe.com/asn/developer/PDFS/TN/5003.PPD_Spec_v4.3.pdf">
+Adobe PostScript Printer Description File Format Specification, Version
+ 4.3.</A></LI>
+<LI><A HREF="http://partners.adobe.com/asn/developer/PDFS/TN/PLRM.pdf">
+Adobe PostScript Language Reference, Third Edition.</A></LI>
+<LI>IPP: Job and Printer Set Operations</LI>
+<LI>IPP/1.1: Encoding and Transport</LI>
+<LI>IPP/1.1: Implementers Guide</LI>
+<LI>IPP/1.1: Model and Semantics</LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc1179.txt">RFC 1179, Line Printer
+ Daemon Protocol</A></LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc2567.txt">RFC 2567, Design Goals
+ for an Internet Printing Protocol</A></LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc2568.txt">RFC 2568, Rationale
+ for the Structure of the Model and Protocol</A> for the Internet
+ Printing Protocol</LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc2569.txt">RFC 2569, Mapping
+ between LPD and IPP Protocols</A></LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616, Hypertext
+ Transfer Protocol -- HTTP/1.1</A></LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc2617.txt">RFC 2617, HTTP
+ Authentication: Basic and Digest Access</A> Authentication</LI>
+</UL>
+<H1><A NAME="3">3 Test Procedure</A></H1>
+<P>The test software and data files are located in the<VAR> test</VAR>
+ subdirectory of the source distribution. A script is provided to
+ compile the <CODE>ipptest</CODE> program and run all of the tests that
+ follow, producing a success/fail report.</P>
+<P>The <CODE>test</CODE> target of the top-level makefile can be used to
+ run this script:</P>
+<UL>
+<PRE>
+make test
+</PRE>
+</UL>
+<P>or you can run the test script directly:</P>
+<UL>
+<PRE>
+cd test
+./run-stp-tests
+</PRE>
+</UL>
+<P>A Software Test Report is stored in HTML and PDF files that are
+ generated using the<A HREF="http://www.easysw.com/htmldoc"> HTMLDOC</A>
+ software.</P>
+<H1><A NAME="4">4 IPP Compliance Tests</A></H1>
+<P>This section describes the tests used to validate the IPP standards
+ compliance of the CUPS server.</P>
+<H2><A NAME="4_1">4.1 Request Tests</A></H2>
+<P>These tests verify that the CUPS scheduler only accepts valid IPP
+ requests that start with the <CODE>attributes-charset</CODE> and <CODE>
+attributes-natural-language</CODE> attributes and also contain a <CODE>
+printer-uri</CODE> or <CODE>job-uri</CODE> attribute.</P>
+<P>It also verifies that the CUPS scheduler always responds with <CODE>
+attributes-charset</CODE> and <CODE>attributes-natural-language</CODE>
+ attributes, using default values if they are not provided by the
+ client.</P>
+<H2><A NAME="4_2">4.2 CUPS Printer Operation Tests</A></H2>
+<P>These tests verify that the CUPS printer operations are supported and
+ function properly. Two printers called <CODE>Test1</CODE> and <CODE>
+Test2</CODE> are created, one as a PostScript printer and one as a
+ raster printer.</P>
+<H2><A NAME="4_3">4.3 Job Operation Tests</A></H2>
+<P>These test verify that the CUPS scheduler accepts print jobs for all
+ supported file formats and that the <CODE>cancel-job</CODE>, <CODE>
+hold-job</CODE>, and <CODE>resume-job</CODE> operations work.</P>
+<H1><A NAME="5">5 Command Tests</A></H1>
+<P>This section describes the tests used to validate the Berkeley and
+ System V commands included with CUPS.</P>
+<H2><A NAME="5_1">5.1 lpadmin</A></H2>
+<P>This test verifies that printers can be added, modified, and
+ defaulted using the <CODE>lpadmin</CODE> command.</P>
+<H2><A NAME="5_2">5.2 lpc</A></H2>
+<P>This test verifies that the <CODE>lpc</CODE> command can show the
+ current status of all print queues.</P>
+<H2><A NAME="5_3">5.3 lpq</A></H2>
+<P>This test verifies that the <CODE>lpq</CODE> command lists any jobs
+ in the queue.</P>
+<H2><A NAME="5_4">5.4 lpstat</A></H2>
+<P>This test verifies that the <CODE>lpstat</CODE> command works with
+ all reports using the &quot;<CODE>-t</CODE>&quot; option.</P>
+<H2><A NAME="5_5">5.5 lp</A></H2>
+<P>This test verifies that the <CODE>lp</CODE> command works with both
+ the default destination and a specific destination.</P>
+<H2><A NAME="5_6">5.6 lpr</A></H2>
+<P>This test verifies that the <CODE>lpr</CODE> command works with both
+ the default destination and a specific destination.</P>
+<H2><A NAME="5_7">5.7 lprm</A></H2>
+<P>This test verifies that the <CODE>lprm</CODE> command can properly
+ cancel a job.</P>
+<H2><A NAME="5_8">5.8 cancel</A></H2>
+<P>This test verifies that the <CODE>cancel</CODE> command can properly
+ cancel a job or all jobs.</P>
+<H2><A NAME="5_9">5.9 lpinfo</A></H2>
+<P>This test verifies that the <CODE>lpinfo</CODE> command returns a
+ list of available printer drivers and devices.</P>
+<H1 TYPE="A" VALUE="1"><A NAME="6">A Glossary</A></H1>
+<H2><A NAME="6_1">A.1 Terms</A></H2>
+<DL>
+<DT>C</DT>
+<DD>A computer language.</DD>
+<DT>parallel</DT>
+<DD>Sending or receiving data more than 1 bit at a time.</DD>
+<DT>pipe</DT>
+<DD>A one-way communications channel between two programs.</DD>
+<DT>serial</DT>
+<DD>Sending or receiving data 1 bit at a time.</DD>
+<DT>socket</DT>
+<DD>A two-way network communications channel.</DD>
+</DL>
+<H2><A NAME="6_2">A.2 Acronyms</A></H2>
+<DL>
+<DT>ASCII</DT>
+<DD>American Standard Code for Information Interchange</DD>
+<DT>CUPS</DT>
+<DD>Common UNIX Printing System</DD>
+<DT>ESC/P</DT>
+<DD>EPSON Standard Code for Printers</DD>
+<DT>FTP</DT>
+<DD>File Transfer Protocol</DD>
+<DT>HP-GL</DT>
+<DD>Hewlett-Packard Graphics Language</DD>
+<DT>HP-PCL</DT>
+<DD>Hewlett-Packard Page Control Language</DD>
+<DT>HP-PJL</DT>
+<DD>Hewlett-Packard Printer Job Language</DD>
+<DT>IETF</DT>
+<DD>Internet Engineering Task Force</DD>
+<DT>IPP</DT>
+<DD>Internet Printing Protocol</DD>
+<DT>ISO</DT>
+<DD>International Standards Organization</DD>
+<DT>LPD</DT>
+<DD>Line Printer Daemon</DD>
+<DT>MIME</DT>
+<DD>Multimedia Internet Mail Exchange</DD>
+<DT>PPD</DT>
+<DD>PostScript Printer Description</DD>
+<DT>SMB</DT>
+<DD>Server Message Block</DD>
+<DT>TFTP</DT>
+<DD>Trivial File Transfer Protocol</DD>
+</DL>
+</BODY>
+</HTML>
diff --git a/doc/stp.pdf b/doc/stp.pdf
new file mode 100644
index 000000000..02ad677a3
--- /dev/null
+++ b/doc/stp.pdf
Binary files differ
diff --git a/doc/stp.shtml b/doc/stp.shtml
new file mode 100644
index 000000000..ebd4a85fc
--- /dev/null
+++ b/doc/stp.shtml
@@ -0,0 +1,144 @@
+<HTML>
+<HEAD>
+ <META NAME="Description" CONTENT="Common UNIX Printing System Software Test Plan">
+ <META NAME="COPYRIGHT" CONTENT="Copyright 1997-2002, All Rights Reserved">
+ <META NAME="DOCNUMBER" CONTENT="CUPS-STP-1.1">
+ <META NAME="Author" CONTENT="Easy Software Products">
+ <TITLE>CUPS Software Test Plan</TITLE>
+</HEAD>
+<BODY>
+
+<H1>Scope</H1>
+
+<H2>Identification</H2>
+
+<P>This software test plan provides detailed tests that are used
+to evaluate the stability and compliance of the Common UNIX
+Printing System ("CUPS") Version 1.1.
+
+<EMBED SRC="system-overview.shtml">
+
+<H2>Document Overview</H2>
+
+<P>This software test plan is organized into the following sections:
+
+<UL>
+ <LI>1 - Scope</LI>
+ <LI>2 - References</LI>
+ <LI>3 - Test Procedure</LI>
+ <LI>4 - IPP Compliance Tests</LI>
+ <LI>5 - Command Tests</LI>
+ <LI>A - Glossary</LI>
+</UL>
+
+<EMBED SRC="references.shtml">
+
+<H1>Test Procedure</H1>
+
+<P>The test software and data files are located in the <VAR>test</VAR>
+subdirectory of the source distribution. A script is provided to compile
+the <CODE>ipptest</CODE> program and run all of the tests that follow,
+producing a success/fail report.
+
+<P>The <CODE>test</CODE> target of the top-level makefile can be used to
+run this script:
+
+<UL><PRE>
+make test
+</PRE></UL>
+
+<P>or you can run the test script directly:
+
+<UL><PRE>
+cd test
+./run-stp-tests
+</PRE></UL>
+
+<P>A Software Test Report is stored in HTML and PDF files that
+are generated using the
+<A HREF="http://www.easysw.com/htmldoc">HTMLDOC</A> software.
+
+<H1>IPP Compliance Tests</H1>
+
+<P>This section describes the tests used to validate the IPP
+standards compliance of the CUPS server.
+
+<H2>Request Tests</H2>
+
+<P>These tests verify that the CUPS scheduler only accepts valid
+IPP requests that start with the <CODE>attributes-charset</CODE>
+and <CODE>attributes-natural-language</CODE> attributes and also
+contain a <CODE>printer-uri</CODE> or <CODE>job-uri</CODE> attribute.
+
+<P>It also verifies that the CUPS scheduler always responds with
+<CODE>attributes-charset</CODE> and
+<CODE>attributes-natural-language</CODE> attributes, using
+default values if they are not provided by the client.
+
+<H2>CUPS Printer Operation Tests</H2>
+
+<P>These tests verify that the CUPS printer operations are supported
+and function properly. Two printers called <CODE>Test1</CODE> and
+<CODE>Test2</CODE> are created, one as a PostScript printer and one
+as a raster printer.
+
+<H2>Job Operation Tests</H2>
+
+<P>These test verify that the CUPS scheduler accepts print jobs for
+all supported file formats and that the <CODE>cancel-job</CODE>,
+<CODE>hold-job</CODE>, and <CODE>resume-job</CODE> operations work.
+
+<H1>Command Tests</H1>
+
+<P>This section describes the tests used to validate the
+Berkeley and System V commands included with CUPS.
+
+<H2>lpadmin</H2>
+
+<P>This test verifies that printers can be added, modified, and
+defaulted using the <CODE>lpadmin</CODE> command.
+
+<H2>lpc</H2>
+
+<P>This test verifies that the <CODE>lpc</CODE> command can show
+the current status of all print queues.
+
+<H2>lpq</H2>
+
+<P>This test verifies that the <CODE>lpq</CODE> command lists
+any jobs in the queue.
+
+<H2>lpstat</H2>
+
+<P>This test verifies that the <CODE>lpstat</CODE> command works
+with all reports using the "<CODE>-t</CODE>" option.
+
+<H2>lp</H2>
+
+<P>This test verifies that the <CODE>lp</CODE> command works
+with both the default destination and a specific destination.
+
+<H2>lpr</H2>
+
+<P>This test verifies that the <CODE>lpr</CODE> command works
+with both the default destination and a specific destination.
+
+<H2>lprm</H2>
+
+<P>This test verifies that the <CODE>lprm</CODE> command can
+properly cancel a job.
+
+<H2>cancel</H2>
+
+<P>This test verifies that the <CODE>cancel</CODE> command can
+properly cancel a job or all jobs.
+
+<H2>lpinfo</H2>
+
+<P>This test verifies that the <CODE>lpinfo</CODE> command
+returns a list of available printer drivers and devices.
+
+<EMBED SRC="glossary.shtml">
+
+</BODY>
+</HTML>
diff --git a/doc/sum.html b/doc/sum.html
new file mode 100644
index 000000000..657579f7a
--- /dev/null
+++ b/doc/sum.html
@@ -0,0 +1,1643 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD>
+<TITLE>CUPS Software Users Manual</TITLE>
+<META NAME="author" CONTENT="Easy Software Products">
+<META NAME="copyright" CONTENT="Copyright 1997-2002, All Rights Reserved">
+<META NAME="docnumber" CONTENT="CUPS-SUM-1.1.13">
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=iso-8859-1">
+<STYLE TYPE="text/css"><!--
+BODY { font-family: serif }
+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 }
+SUB { font-size: smaller }
+SUP { font-size: smaller }
+PRE { font-family: monospace }
+--></STYLE>
+</HEAD>
+<BODY BGCOLOR="#ffffff">
+<CENTER><A HREF="#CONTENTS"><IMG SRC="images/cups-large.gif" BORDER="0" WIDTH="431" HEIGHT="511"><BR>
+<H1>CUPS Software Users Manual</H1></A><BR>
+CUPS-SUM-1.1.13<BR>
+Easy Software Products<BR>
+Copyright 1997-2002, All Rights Reserved<BR>
+</CENTER>
+<HR>
+<H1 ALIGN="CENTER"><A NAME="CONTENTS">Table of Contents</A></H1>
+<BR>
+<BR><B><A HREF="#1">Preface</A></B>
+<UL>
+<LI><A HREF="#1_1">System Overview</A></LI>
+<LI><A HREF="#1_2">Document Overview</A></LI>
+<LI><A HREF="#1_3">Notation Conventions</A></LI>
+<LI><A HREF="#1_4">Abbreviations</A></LI>
+<LI><A HREF="#1_5">Other References</A></LI>
+</UL>
+<B><A HREF="#OVERVIEW">1 - Printing System Overview</A></B>
+<UL>
+<LI><A HREF="#2_1">The Printing Problem</A></LI>
+<LI><A HREF="#2_2">The Technology</A></LI>
+<LI><A HREF="#2_3">Jobs</A></LI>
+<LI><A HREF="#2_4">Classes</A></LI>
+<LI><A HREF="#2_5">Filters</A></LI>
+<LI><A HREF="#2_6">Backends</A></LI>
+<LI><A HREF="#2_7">Printer Drivers</A></LI>
+<LI><A HREF="#2_8">Networking</A></LI>
+</UL>
+<B><A HREF="#USING_SYSTEM">2 - Using the Printing System</A></B>
+<UL>
+<LI><A HREF="#3_1">Submitting Files for Printing</A></LI>
+<LI><A HREF="#3_2">Choosing a Printer</A></LI>
+<LI><A HREF="#3_3">Setting Printer Options</A></LI>
+<LI><A HREF="#3_4">Printing Multiple Copies</A></LI>
+<LI><A HREF="#3_5">Checking the Printer Status from the Command-Line</A></LI>
+<LI><A HREF="#3_6">Checking the Printer Status from the Web</A></LI>
+<LI><A HREF="#3_7">Canceling a Print Job</A></LI>
+</UL>
+<B><A HREF="#STANDARD_OPTIONS">3 - Standard Printer Options</A></B>
+<UL>
+<LI><A HREF="#4_1">General Options</A></LI>
+<UL>
+<LI><A HREF="#4_1_1">Setting the Orientation</A></LI>
+<LI><A HREF="#4_1_2">Selecting the Media Size, Type, and Source</A></LI>
+<LI><A HREF="#4_1_3">Printing On Both Sides of the Paper</A></LI>
+</UL>
+<LI><A HREF="#4_2">Banner Options</A></LI>
+<UL>
+<LI><A HREF="#4_2_1">Selecting the Banner Page(s)</A></LI>
+</UL>
+<LI><A HREF="#4_3">Document Options</A></LI>
+<UL>
+<LI><A HREF="#4_3_1">Selecting a Range of Pages</A></LI>
+<LI><A HREF="#4_3_2">Selecting Even or Odd Pages</A></LI>
+<LI><A HREF="#4_3_3">N-Up Printing</A></LI>
+<LI><A HREF="#4_3_4">Setting the Brightness</A></LI>
+<LI><A HREF="#4_3_5">Setting the Gamma Correction</A></LI>
+</UL>
+<LI><A HREF="#4_4">Text Options</A></LI>
+<UL>
+<LI><A HREF="#4_4_1">Setting the Number of Characters Per Inch</A></LI>
+<LI><A HREF="#4_4_2">Setting the Number of Lines Per Inch</A></LI>
+<LI><A HREF="#4_4_3">Setting the Number of Columns</A></LI>
+<LI><A HREF="#4_4_4">Setting the Page Margins</A></LI>
+<LI><A HREF="#4_4_5">Pretty Printing</A></LI>
+</UL>
+<LI><A HREF="#4_5">Image Options</A></LI>
+<UL>
+<LI><A HREF="#4_5_1">Positioning the Image</A></LI>
+<LI><A HREF="#4_5_2">Scaling the Image</A></LI>
+<LI><A HREF="#4_5_3">Adjusting the Hue (Tint) of an Image</A></LI>
+<LI><A HREF="#4_5_4">Adjusting the Saturation (Color) of an Image</A></LI>
+</UL>
+<LI><A HREF="#4_6">HP-GL/2 Options</A></LI>
+<UL>
+<LI><A HREF="#4_6_1">Printing in Black</A></LI>
+<LI><A HREF="#4_6_2">Fitting the Plot on the Page</A></LI>
+<LI><A HREF="#4_6_3">Setting the Default Pen Width</A></LI>
+</UL>
+<LI><A HREF="#4_7">Raw or Unfiltered Output</A></LI>
+</UL>
+<B><A HREF="#SAVING_OPTIONS">4 - Saving Printer Options and Defaults</A></B>
+<UL>
+<LI><A HREF="#5_1">Printer Options</A></LI>
+<LI><A HREF="#5_2">Setting Options for a Specific Printer</A></LI>
+<LI><A HREF="#5_3">Viewing the Current Defaults</A></LI>
+<LI><A HREF="#5_4">Setting the Default Printer</A></LI>
+<LI><A HREF="#5_5">Printer Instances</A></LI>
+<LI><A HREF="#5_6">Removing Instances</A></LI>
+</UL>
+<B><A HREF="#LICENSE">A - Software License Agreement</A></B>
+<UL>
+<LI><A HREF="#6_1">Common UNIX Printing System License Agreement</A></LI>
+<UL>
+<LI><A HREF="#6_1_1">Introduction</A></LI>
+<LI><A HREF="#6_1_2">Trademarks</A></LI>
+<LI><A HREF="#6_1_3">Binary Distribution Rights</A></LI>
+<LI><A HREF="#6_1_4">Support</A></LI>
+</UL>
+<LI><A HREF="#6_2">GNU GENERAL PUBLIC LICENSE</A></LI>
+<LI><A HREF="#6_3">GNU LIBRARY GENERAL PUBLIC LICENSE</A></LI>
+</UL>
+<HR>
+<H1 ALIGN="RIGHT"><A NAME="1">Preface</A></H1>
+<P>This software users manual describes how to use the Common UNIX
+ Printing System<SUP>TM</SUP> (&quot;CUPS<SUP>TM</SUP>&quot;) Version 1.1.13.</P>
+<H2><A NAME="1_1">System Overview</A></H2>
+<P>CUPS provides a portable printing layer for UNIX&reg;-based operating
+ systems. It has been developed by<A HREF="http://www.easysw.com"> Easy
+ Software Products</A> to promote a standard printing solution for all
+ UNIX vendors and users. CUPS provides the System V and Berkeley
+ command-line interfaces.</P>
+<P>CUPS uses the Internet Printing Protocol (&quot;IPP&quot;) as the basis for
+ managing print jobs and queues. The Line Printer Daemon (&quot;LPD&quot;) Server
+ Message Block (&quot;SMB&quot;), and AppSocket (a.k.a. JetDirect) protocols are
+ also supported with reduced functionality. CUPS adds network printer
+ browsing and PostScript Printer Description (&quot;PPD&quot;) based printing
+ options to support real-world printing under UNIX.</P>
+<P>CUPS also includes a customized version of GNU Ghostscript (currently
+ based off GNU Ghostscript 5.50) and an image file RIP that are used to
+ support non-PostScript printers. Sample drivers for HP and EPSON
+ printers are included that use these filters.</P>
+
+<!-- NEED 2in -->
+<H2><A NAME="1_2">Document Overview</A></H2>
+<P>This software users manual is organized into the following sections:</P>
+<UL>
+<LI><A HREF="#OVERVIEW">1 - Printing System Overview</A></LI>
+<LI><A HREF="#USING_SYSTEM">2 - Using the Printing System</A></LI>
+<LI><A HREF="#STANDARD_OPTIONS">3 - Standard Printer Options</A></LI>
+<LI><A HREF="#SAVING_OPTIONS">4 - Saving Printer Options and Defaults</A>
+</LI>
+<LI><A HREF="#LICENSE">A - Software License Agreement</A></LI>
+</UL>
+<H2><A NAME="1_3">Notation Conventions</A></H2>
+<P>Various font and syntax conventions are used in this guide. Examples
+ and their meanings and uses are explained below:
+<CENTER>
+<TABLE WIDTH="80%">
+<TR><TH>Example</TH><TD>&nbsp;&nbsp;&nbsp;</TD><TH>Description</TH></TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR VALIGN="TOP"><TD><CODE>lpstat</CODE>
+<BR> <CODE>lpstat(1)</CODE></TD><TD>&nbsp;&nbsp;&nbsp;</TD><TD>The names of commands;
+ the first mention of a command or function in a chapter is followed by
+ a manual page section number.</TD></TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR VALIGN="TOP"><TD><VAR>/var</VAR>
+<BR><VAR> /usr/share/cups/data/testprint.ps</VAR></TD><TD>&nbsp;&nbsp;&nbsp;</TD><TD>
+File and directory names.</TD></TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR VALIGN="TOP"><TD NOWRAP><TT>Request ID is Printer-123</TT></TD><TD>
+&nbsp;&nbsp;&nbsp;</TD><TD>Screen output.</TD></TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR VALIGN="TOP"><TD NOWRAP><KBD>lp -d printer filename ENTER</KBD></TD><TD>
+&nbsp;&nbsp;&nbsp;</TD><TD>Literal user input; special keys like <KBD>ENTER</KBD> are
+ in ALL CAPS.</TD></TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR VALIGN="TOP"><TD>12.3</TD><TD>&nbsp;&nbsp;&nbsp;</TD><TD>Numbers in the text are
+ written using the period (.) to indicate the decimal point.</TD></TR>
+</TABLE>
+</CENTER>
+
+<!-- NEED 3in -->
+</P>
+<H2><A NAME="1_4">Abbreviations</A></H2>
+ The following abbreviations are used throughout this manual:
+<UL>
+<DL>
+<DT>kb</DT>
+<DD>Kilobytes, or 1024 bytes
+<BR>&nbsp;</DD>
+<DT>Mb</DT>
+<DD>Megabytes, or 1048576 bytes
+<BR>&nbsp;</DD>
+<DT>Gb</DT>
+<DD>Gigabytes, or 1073741824 bytes
+<BR>&nbsp;</DD>
+</DL>
+</UL>
+<H2><A NAME="1_5">Other References</A></H2>
+<UL>
+<DL>
+<DT>CUPS Software Administrators Manual</DT>
+<DD>An administration guide for the CUPS software.
+<BR>&nbsp;</DD>
+<DT>CUPS Software Programmers Manual</DT>
+<DD>A programmer guide for interfacing with and/or extending the CUPS
+ software.
+<BR>&nbsp;</DD>
+</DL>
+</UL>
+<H1 ALIGN="RIGHT"><A NAME="OVERVIEW">1 - Printing System Overview</A></H1>
+<P>This chapter provides an overview of how the Common UNIX Printing
+ System works.</P>
+<H2><A NAME="2_1">The Printing Problem</A></H2>
+<P>For years<I> the printing problem</I> has plagued UNIX. Unlike
+ Microsoft&reg; Windows&reg; or Mac OS, UNIX has no standard interface or system
+ in place for supporting printers. Among the solutions currently
+ available, the Berkeley and System V printing systems are the most
+ prevalent.</P>
+<P>These printing systems support line printers (text only) or
+ PostScript printers (text and graphics), and with some coaxing they can
+ be made to support a full range of printers and file formats. However,
+ because each varient of the UNIX operating system uses a different
+ printing system than the next developing printer drivers for a wide
+ range of printers and operating systems is extremely difficult. That
+ combined with the limited volume of customers for each UNIX varient has
+ forced most printer vendors to give up supporting UNIX entirely.</P>
+<P>CUPS is designed to eliminate<I> the printing problem</I>. 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.</P>
+<H2><A NAME="2_2">The Technology</A></H2>
+<P>CUPS is based upon an emerging Internet standard called the Internet
+ Printing Protocol. IPP has been embraced by dozens of printer and
+ printer server manufacturers and is supported by Microsoft Windows
+ 2000.</P>
+<P>IPP defines a standard protocol for printing as well as managing
+ print jobs and printer options like media size, resolution, and so
+ forth. Like all IP-based protocols, IPP can be used locally or over the
+ Internet to printers hundreds or thousands of miles away. Unlike other
+ protocols, however, IPP also supports access control, authentication,
+ and encryption, making it a much more capable and secure printing
+ solution than older ones.</P>
+<P>IPP is layered on top of the Hyper-Text Transport Protocol (&quot;HTTP&quot;)
+ which is the basis of web servers on the Internet. This allows users to
+ view documentation, check status information on a printer or server,
+ and manage their printers, classes, and jobs using their web browser.</P>
+<P>CUPS provides a complete IPP/1.1 based printing system that provides
+ Basic, Digest, and local certificate authentication and user, domain,
+ or IP-based access control. TLS encryption will be available in future
+ versions of CUPS.</P>
+<H2><A NAME="2_3">Jobs</A></H2>
+<P>Each file or set of files that is submitted for printing is called a<I>
+ job</I>. 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.</P>
+<H2><A NAME="2_4">Classes</A></H2>
+<P>CUPS supports collections of printers known as<I> classes</I>. Jobs
+ sent to a class are forwarded to the first available printer in the
+ class.</P>
+<H2><A NAME="2_5">Filters</A></H2>
+<P>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.</P>
+<P>CUPS provides filters for printing many types of image files, HP-GL/2
+ files, PDF files, and text files. CUPS also supplies PostScript and
+ image file Raster Image Processor (&quot;RIP&quot;) filters that convert
+ PostScript or image files into bitmaps that can be sent to a raster
+ printer.</P>
+<H2><A NAME="2_6">Backends</A></H2>
+<P>Backends perform the most important task of all - they send the
+ filtered print data to the printer.</P>
+<P>CUPS provides backends for printing over parallel, serial, and USB
+ ports, and over the network via the IPP, JetDirect (AppSocket), and
+ Line Printer Daemon (&quot;LPD&quot;) protocols. Additional backends are
+ available in network service packages such as the SMB backend included
+ with the popular SAMBA software.</P>
+<P>Backends are also used to determine the available devices. On startup
+ each backend is asked for a list of devices it supports, and any
+ information that is available. This allows the parallel backend to tell
+ CUPS that an EPSON Stylus Color 600 printer is attached to parallel
+ port 1, for example.</P>
+<H2><A NAME="2_7">Printer Drivers</A></H2>
+<P>Printer drivers in CUPS consist of one of more filters specific to a
+ printer. CUPS includes sample printer drivers for Hewlett-Packard
+ LaserJet and DeskJet printers and EPSON 9-pin, 24-pin, Stylus Color,
+ and Stylus Photo printers. While these drivers do not generate optimal
+ output for the different printer models, they do provide basic printing
+ and demonstrate how you can write your own printer drivers and
+ incorporate them into CUPS.</P>
+<H2><A NAME="2_8">Networking</A></H2>
+<P>Printers and classes on the local system are automatically shared
+ with other systems on the network. This allows you to setup one system
+ to print to a printer and use this system as a printer server or spool
+ host for all of the others. Users may then select a local printer by
+ name or a remote printer using &quot;name@server&quot;.</P>
+<P>CUPS also provides<I> implicit classes</I>, which are collections of
+ printers and/or classes with the same name. This allows you to setup
+ multiple servers pointing to the same physical network printer, for
+ example, so that you aren't relying on a single system for printing.
+ Because this also works with printer classes, you can setup multiple
+ servers and printers and never worry about a single point of failure
+ unless all of the printers and servers go down!</P>
+<H1 ALIGN="RIGHT"><A NAME="USING_SYSTEM">2 - Using the Printing System</A>
+</H1>
+<P>This chapter shows you how to submit, query, and cancel print jobs to
+ different printers.</P>
+<H2><A NAME="3_1">Submitting Files for Printing</A></H2>
+<P>CUPS provides both the System V (<CODE>lp(1)</CODE>) and Berkeley (<CODE>
+lpr(1)</CODE>) printing commands. Type the following command to print a
+ file to the default (or only) printer on the system:</P>
+<UL>
+<PRE>
+<B>lp filename ENTER</B>
+</PRE>
+</UL>
+<P>or:</P>
+<UL>
+<PRE>
+<B>lpr filename ENTER</B>
+</PRE>
+</UL>
+<P>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!</P>
+<H2><A NAME="3_2">Choosing a Printer</A></H2>
+<P>Many systems will have more than one printer available to the user.
+ These printers can be attached to the local system via a parallel,
+ serial, or USB port, or available over the network.</P>
+<P>Use the <CODE>lpstat(1)</CODE> command to see a list of available
+ printers:</P>
+<UL>
+<PRE>
+<B>lpstat -p -d ENTER</B>
+</PRE>
+</UL>
+<P>The <CODE>-p</CODE> option specifies that you want to see a list of
+ printers, and the <CODE>-d</CODE> option reports the current system
+ default printer or class.</P>
+<P>Use the <CODE>-d</CODE> option with the <CODE>lp</CODE> command to
+ print to a specific printer:</P>
+<UL>
+<PRE>
+<B>lp -d printer filename ENTER</B>
+</PRE>
+</UL>
+<P>or the <CODE>-P</CODE> option with the <CODE>lpr</CODE> command:</P>
+<UL>
+<PRE>
+<B>lpr -P printer filename ENTER</B>
+</PRE>
+</UL>
+<H2><A NAME="3_3">Setting Printer Options</A></H2>
+<P>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.</P>
+<P>The <CODE>lp</CODE> and <CODE>lpr</CODE> commands allow you to pass
+ printer options using the <CODE>-o</CODE> option:</P>
+<UL>
+<PRE>
+<B>lp -o landscape -o scaling=75 -o media=A4 filename.jpg
+<B>lpr -o landscape -o scaling=75 -o media=A4 filename.jpg
+</B></B></PRE>
+</UL>
+<P>The available printer options vary depending on the printer. The
+ standard options are described in<A HREF="#STANDARD_OPTIONS"> Chapter
+ 3, &quot;Standard Printing Options&quot;</A>.</P>
+<H2><A NAME="3_4">Printing Multiple Copies</A></H2>
+<P>Both the <CODE>lp</CODE> and <CODE>lpr</CODE> commands have options
+ for printing more than one copy of a file:</P>
+<UL>
+<PRE>
+<B>lp -n <I>num-copies</I> filename ENTER</B>
+<B>lpr -#<I>num-copies</I> filename ENTER</B>
+</PRE>
+</UL>
+<P>Copies are normally<I> not</I> collated for you. Use the <CODE>-o
+ Collate=True</CODE> option to get collated copies :</P>
+<UL>
+<PRE>
+<B>lp -n <I>num-copies</I> -o Collate=True filename ENTER</B>
+<B>lpr -#<I>num-copies</I> -o Collate=True filename ENTER</B>
+</PRE>
+</UL>
+
+<!-- NEED 3in -->
+<H2><A NAME="3_5">Checking the Printer Status from the Command-Line</A></H2>
+<P>The <CODE>lpstat</CODE> command can be used to check for jobs that
+ you have submitted for printing:</P>
+<UL>
+<PRE>
+<B>lpstat ENTER</B>
+Printer-1 johndoe 4427776
+Printer-2 johndoe 15786
+Printer-3 johndoe 372842
+</PRE>
+</UL>
+<P>The jobs are listed in the order they will be printed. Use the <CODE>
+-p</CODE> option to see which files and printers are active:</P>
+<UL>
+<PRE>
+<B>lpstat -p ENTER</B>
+printer DeskJet now printing DeskJet-1.
+</PRE>
+</UL>
+
+<!-- NEED 2in -->
+<P>Use the <CODE>-o</CODE> and <CODE>-p</CODE> options together to show
+ the jobs and the printers:</P>
+<UL>
+<PRE>
+<B>lpstat -o -p ENTER</B>
+Printer-1 johndoe 4427776
+Printer-2 johndoe 15786
+Printer-3 johndoe 372842
+printer DeskJet now printing DeskJet-1.
+</PRE>
+</UL>
+<H2><A NAME="3_6">Checking the Printer Status from the Web</A></H2>
+<P>Since CUPS uses the Internet Printing Protocol, it is also a
+ fully-functional web server. To use your web browser to monitor the
+ printers on your system, open the URL:</P>
+<UL>
+<PRE>
+<A HREF="http://localhost:631">http://localhost:631</A>
+</PRE>
+</UL>
+<P>From there you can view the status of classes, jobs, and printers
+ with the click of a button!</P>
+<H2><A NAME="3_7">Canceling a Print Job</A></H2>
+<P>The <CODE>cancel(1)</CODE> and <CODE>lprm(1)</CODE> commands cancel a
+ print job:</P>
+<UL>
+<PRE>
+<B>cancel <I>job-id</I> ENTER</B>
+<B>lprm <I>job-id</I> ENTER</B>
+</PRE>
+</UL>
+<P>The <CODE>job-id</CODE> is the number that was reported to you by the
+ <CODE>lp</CODE> or <CODE>lpstat</CODE> commands.</P>
+<H1 ALIGN="RIGHT"><A NAME="STANDARD_OPTIONS">3 - Standard Printer
+ Options</A></H1>
+<P>This chapter describes the standard printer options that are
+ available when printing with the <CODE>lp</CODE> and <CODE>lpr</CODE>
+ commands.</P>
+<H2><A NAME="4_1">General Options</A></H2>
+<P>The following options apply when printing all types of files.</P>
+<H3><A NAME="4_1_1">Setting the Orientation</A></H3>
+<P>The <CODE>-o landscape</CODE> option will rotate the page 90 degrees
+ to print in landscape orientation:</P>
+<UL>
+<PRE>
+<B>lp -o landscape filename ENTER</B>
+<B>lpr -o landscape filename ENTER</B>
+</PRE>
+</UL>
+
+<!-- NEED 2in -->
+<H3><A NAME="4_1_2">Selecting the Media Size, Type, and Source</A></H3>
+<P>The <CODE>-o media=xyz</CODE> option sets the media size, type,
+ and/or source:</P>
+<UL>
+<PRE>
+<B>lp -o media=Letter filename ENTER</B>
+<B>lp -o media=Letter,MultiPurpose filename ENTER</B>
+<B>lpr -o media=Letter,Transparency filename ENTER</B>
+<B>lpr -o media=Letter,MultiPurpose,Transparency filename ENTER</B>
+</PRE>
+</UL>
+
+<!-- NEED 3in -->
+<P>The available media sizes, types, and sources depend on the printer,
+ but most support the following options (case is not significant):</P>
+<UL>
+<LI><CODE>Letter</CODE> - US Letter (8.5x11 inches, or 216x279mm)</LI>
+<LI><CODE>Legal</CODE> - US Legal (8.5x14 inches, or 216x356mm)</LI>
+<LI><CODE>A4</CODE> - ISO A4 (8.27x11.69 inches, or 210x297mm)</LI>
+<LI><CODE>COM10</CODE> - US #10 Envelope (9.5x4.125 inches, or
+ 241x105mm)</LI>
+<LI><CODE>DL</CODE> - ISO DL Envelope (8.66x4.33 inches, or 220x110mm)</LI>
+<LI><CODE>Transparency</CODE> - Transparency media type or source</LI>
+<LI><CODE>Upper</CODE> - Upper paper tray</LI>
+<LI><CODE>Lower</CODE> - Lower paper tray</LI>
+<LI><CODE>MultiPurpose</CODE> - Multi-purpose paper tray</LI>
+<LI><CODE>LargeCapacity</CODE> - Large capacity paper tray</LI>
+</UL>
+<P>The actual options supported are defined in the printer's PPD file in
+ the <CODE>PageSize</CODE>, <CODE>InputSlot</CODE>, and <CODE>MediaType</CODE>
+ options.</P>
+<H3><A NAME="4_1_3">Printing On Both Sides of the Paper</A></H3>
+<P>The <CODE>-o sides=two-sided-short-edge</CODE> and <CODE>-o
+ sides=two-sided-long-edge</CODE> options will enable duplexing on the
+ printer, if the printer supports it. The <CODE>-o
+ sides=two-sided-short-edge</CODE> option is suitable for landscape
+ pages, while the <CODE>-o sides=two-sided-long-edge</CODE> option is
+ suitable for portrait pages:</P>
+<UL>
+<PRE>
+<B>lp -o sides=two-sided-short-edge filename ENTER</B>
+<B>lp -o sides=two-sided-long-edge filename ENTER</B>
+<B>lpr -o sides=two-sided-long-edge filename ENTER</B>
+</PRE>
+</UL>
+<P>The default is to print single-sided:</P>
+<UL>
+<PRE>
+<B>lp -o sides=one-sided filename ENTER</B>
+<B>lpr -o sides=one-sided filename ENTER</B>
+</PRE>
+</UL>
+<H2><A NAME="4_2">Banner Options</A></H2>
+<P>The following options apply when printing all types of files.</P>
+<H3><A NAME="4_2_1">Selecting the Banner Page(s)</A></H3>
+<P>The <CODE>-o jobsheets=start,end</CODE> option sets the banner
+ page(s) to use for a job:</P>
+<UL>
+<PRE>
+<B>lp -o job-sheets=none filename ENTER</B>
+<B>lp -o job-sheets=standard filename ENTER</B>
+<B>lpr -o job-sheets=classified,classified filename ENTER</B>
+</PRE>
+</UL>
+<P>If only one banner file is specified, it will be printed before the
+ files in the job. If a second banner file is specified, it is printed
+ after the files in the job.</P>
+<P>The available banner pages depend on the local system configuration;
+ CUPS includes the following banner files:</P>
+<UL>
+<LI><CODE>none</CODE> - Do not produce a banner page.</LI>
+<LI><CODE>classified</CODE> - A banner page with a &quot;classified&quot; label at
+ the top and bottom.</LI>
+<LI><CODE>confidential</CODE> - A banner page with a &quot;confidential&quot;
+ label at the top and bottom.</LI>
+<LI><CODE>secret</CODE> - A banner page with a &quot;secret&quot; label at the top
+ and bottom.</LI>
+<LI><CODE>standard</CODE> - A banner page with no label at the top and
+ bottom.</LI>
+<LI><CODE>topsecret</CODE> - A banner page with a &quot;top secret&quot; label at
+ the top and bottom.</LI>
+<LI><CODE>unclassified</CODE> - A banner page with an &quot;unclassified&quot;
+ label at the top and bottom.</LI>
+</UL>
+<H2><A NAME="4_3">Document Options</A></H2>
+<P>The following options apply when printing all types of files.</P>
+<H3><A NAME="4_3_1">Selecting a Range of Pages</A></H3>
+<P>The <CODE>-o page-ranges=pages</CODE> option selects a range of pages
+ for printing:</P>
+<UL>
+<PRE>
+<B>lp -o page-ranges=1 filename ENTER</B>
+<B>lp -o page-ranges=1-4 filename ENTER</B>
+<B>lp -o page-ranges=1-4,7,9-12 filename ENTER</B>
+<B>lpr -o page-ranges=1-4,7,9-12 filename ENTER</B>
+</PRE>
+</UL>
+<P>As shown above, the <CODE>pages</CODE> 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 <CODE>page-ranges</CODE> option.</P>
+<P>The default is to print all pages.</P>
+<H3><A NAME="4_3_2">Selecting Even or Odd Pages</A></H3>
+<P>Use the <CODE>-o page-set=set</CODE> option to select the even or odd
+ pages:</P>
+<UL>
+<PRE>
+<B>lp -o page-set=odd filename ENTER</B>
+<B>lp -o page-set=even filename ENTER</B>
+<B>lpr -o page-set=even filename ENTER</B>
+</PRE>
+</UL>
+<P>The default is to print all pages.</P>
+<H3><A NAME="4_3_3">N-Up Printing</A></H3>
+<P>The <CODE>-o number-up=value</CODE> 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:</P>
+<UL>
+<PRE>
+<B>lp -o number-up=1 filename ENTER</B>
+<B>lp -o number-up=2 filename ENTER</B>
+<B>lp -o number-up=4 filename ENTER</B>
+<B>lpr -o number-up=4 filename ENTER</B>
+</PRE>
+</UL>
+<P>The default format is 1-Up.</P>
+<H3><A NAME="4_3_4">Setting the Brightness</A></H3>
+<P>You can control the overall brightness of the printed output using
+ the <CODE>-o brightness=percent</CODE> option:</P>
+<UL>
+<PRE>
+<B>lp -o brightness=120 filename ENTER</B>
+<B>lpr -o brightness=120 filename ENTER</B>
+</PRE>
+</UL>
+<P>Values greater than 100 will lighten the print, while values less
+ than 100 will darken it.</P>
+<H3><A NAME="4_3_5">Setting the Gamma Correction</A></H3>
+<P>You can control the overall gamma correction of the printed output
+ using the <CODE>-o gamma=value</CODE> option:</P>
+<UL>
+<PRE>
+<B>lp -o gamma=1700 filename ENTER</B>
+<B>lpr -o gamma=1700 filename ENTER</B>
+</PRE>
+</UL>
+<P>Values greater than 1000 will lighten the print, while values less
+ than 1000 will darken it. The default gamma is 1000.</P>
+<H2><A NAME="4_4">Text Options</A></H2>
+<P>The following options apply when printing text files.</P>
+<H3><A NAME="4_4_1">Setting the Number of Characters Per Inch</A></H3>
+<P>The <CODE>-o cpi=value</CODE> option sets the number of characters
+ per inch:</P>
+<UL>
+<PRE>
+<B>lp -o cpi=10 filename ENTER</B>
+<B>lp -o cpi=12 filename ENTER</B>
+<B>lpr -o cpi=17 filename ENTER</B>
+</PRE>
+</UL>
+<P>The default characters per inch is 10.</P>
+<H3><A NAME="4_4_2">Setting the Number of Lines Per Inch</A></H3>
+<P>The <CODE>-o lpi=value</CODE> option sets the number of lines per
+ inch:</P>
+<UL>
+<PRE>
+<B>lp -o lpi=6 filename ENTER</B>
+<B>lpr -o lpi=8 filename ENTER</B>
+</PRE>
+</UL>
+<P>The default lines per inch is 6.</P>
+<H3><A NAME="4_4_3">Setting the Number of Columns</A></H3>
+<P>The <CODE>-o columns=value</CODE> option sets the number of text
+ columns:</P>
+<UL>
+<PRE>
+<B>lp -o columns=2 filename ENTER</B>
+<B>lpr -o columns=3 filename ENTER</B>
+</PRE>
+</UL>
+<P>The default number of columns is 1.</P>
+<H3><A NAME="4_4_4">Setting the Page Margins</A></H3>
+<P>Normally the page margins are set to the hard limits of the printer.
+ Use the <CODE>-o page-left=value</CODE>, <CODE>-o page-right=value</CODE>
+, <CODE>-o page-top=value</CODE>, and <CODE>-o page-bottom=value</CODE>
+ options to adjust the page margins:</P>
+<UL>
+<PRE>
+<B>lp -o page-left=<I>value</I> filename ENTER</B>
+<B>lp -o page-right=<I>value</I> filename ENTER</B>
+<B>lp -o page-top=<I>value</I> filename ENTER</B>
+<B>lp -o page-bottom=<I>value</I> filename ENTER</B>
+<B>lpr -o page-bottom=<I>value</I> filename ENTER</B>
+</PRE>
+</UL>
+<P>The <CODE>value</CODE> argument is the margin in points; each point
+ is 1/72 inch or 0.35mm.</P>
+<H3><A NAME="4_4_5">Pretty Printing</A></H3>
+<P>The <CODE>-o prettyprint</CODE> 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:</P>
+<UL>
+<PRE>
+<B>lp -o prettyprint filename ENTER</B>
+<B>lpr -o prettyprint filename ENTER</B>
+</PRE>
+</UL>
+<H2><A NAME="4_5">Image Options</A></H2>
+<P>The following options apply when printing image files.</P>
+<H3><A NAME="4_5_1">Positioning the Image</A></H3>
+<P>The <CODE>-o position=name</CODE> option specifies the position of
+ the image on the page:</P>
+<UL>
+<LI><CODE>center</CODE> - Center the image on the page (default)</LI>
+<LI><CODE>top</CODE> - Print the image centered at the top of the page</LI>
+<LI><CODE>left</CODE> - Print the image centered on the left of page</LI>
+<LI><CODE>right</CODE> - Print the image centered on the right of the
+ page</LI>
+<LI><CODE>top-left</CODE> - Print the image at the top left corner of
+ the page</LI>
+<LI><CODE>top-right</CODE> - Print the image at the top right corner of
+ the page</LI>
+<LI><CODE>bottom</CODE> - Print the image centered at the bottom of the
+ page</LI>
+<LI><CODE>bottom-left</CODE> - Print the image at the bottom left corner
+ of the page</LI>
+<LI><CODE>bottom-right</CODE> - Print the image at the bottom right
+ corner of the page</LI>
+</UL>
+<H3><A NAME="4_5_2">Scaling the Image</A></H3>
+<P>The <CODE>-o scaling=percent</CODE>, <CODE>-o ppi=value</CODE>, and <CODE>
+-o natural-scaling=percent</CODE> options change the size of a printed
+ image:</P>
+<UL>
+<PRE>
+<B>lp -o scaling=<I>percent</I> filename ENTER</B>
+<B>lp -o ppi=<I>value</I> filename ENTER</B>
+<B>lpr -o natural-scaling=<I>percent</I> filename ENTER</B>
+</PRE>
+</UL>
+<P>The <CODE>scaling=percent</CODE> value is a number from 1 to 800
+ specifying the size in relation to the page (<I>not</I> 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.</P>
+<P>The <CODE>ppi=value</CODE> 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.</P>
+<P>The <CODE>natural-scaling=percent</CODE> value is a number from 1 to
+ 800 specifying the size in relation to the natural image size. A
+ scaling of 100 percent will print the image at its natural size, while
+ a scaling of 50 percent will print the image at half its natural size.
+ If the specified scaling makes the image larger than the page, multiple
+ pages will be printed to satisfy the request.</P>
+<H3><A NAME="4_5_3">Adjusting the Hue (Tint) of an Image</A></H3>
+<P>The <CODE>-o hue=value</CODE> option will adjust the hue of the
+ printed image, much like the tint control on your television:</P>
+<UL>
+<PRE>
+<B>lp -o hue=<I>value</I> filename ENTER</B>
+<B>lpr -o hue=<I>value</I> filename ENTER</B>
+</PRE>
+</UL>
+
+<!-- NEED 3in -->
+<P>The <CODE>value</CODE> 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:
+<CENTER>
+<TABLE BORDER="1" WIDTH="50%">
+<TR><TH>Original</TH><TH>hue=-45</TH><TH>hue=45</TH></TR>
+<TR><TD>Red</TD><TD>Purple</TD><TD>Yellow-orange</TD></TR>
+<TR><TD>Green</TD><TD>Yellow-green</TD><TD>Blue-green</TD></TR>
+<TR><TD>Yellow</TD><TD>Orange</TD><TD>Green-yellow</TD></TR>
+<TR><TD>Blue</TD><TD>Sky-blue</TD><TD>Purple</TD></TR>
+<TR><TD>Magenta</TD><TD>Indigo</TD><TD>Crimson</TD></TR>
+<TR><TD>Cyan</TD><TD>Blue-green</TD><TD>Light-navy-blue</TD></TR>
+</TABLE>
+</CENTER>
+</P>
+<P>The default hue adjustment is 0.</P>
+<H3><A NAME="4_5_4">Adjusting the Saturation (Color) of an Image</A></H3>
+<P>The <CODE>-o saturation=percent</CODE> option adjusts the saturation
+ of the colors in an image, much like the color knob on your television:</P>
+<UL>
+<PRE>
+<B>lp -o saturation=<I>percent</I> filename ENTER</B>
+<B>lpr -o saturation=<I>percent</I> filename ENTER</B>
+</PRE>
+</UL>
+<P>The <CODE>percent</CODE> 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.</P>
+<P>The default saturation is 100.
+<!-- NEED 4in -->
+</P>
+<H2><A NAME="4_6">HP-GL/2 Options</A></H2>
+<P>The following options apply to HP-GL/2 files.</P>
+<H3><A NAME="4_6_1">Printing in Black</A></H3>
+<P>The <CODE>-o blackplot</CODE> option specifies that all pens should
+ plot in black:</P>
+<UL>
+<PRE>
+<B>lp -o blackplot filename ENTER</B>
+<B>lpr -o blackplot filename ENTER</B>
+</PRE>
+</UL>
+<P>The default is to use the colors defined in the plot file or the
+ standard pen colors defined in the HP-GL/2 reference manual from
+ Hewlett Packard.</P>
+<H3><A NAME="4_6_2">Fitting the Plot on the Page</A></H3>
+<P>The <CODE>-o fitplot</CODE> option specifies that the plot should be
+ scaled to fit on the page:</P>
+<UL>
+<PRE>
+<B>lp -o fitplot filename ENTER</B>
+<B>lpr -o fitplot filename ENTER</B>
+</PRE>
+</UL>
+<P>The default is to use the absolute distances specified in the plot
+ file.
+<CENTER>
+<TABLE BGCOLOR="#cccccc" BORDER="1" CELLPADDING="5" WIDTH="80%">
+<TR><TD><B> NOTE:</B>
+<P>This feature depends upon an accurate plot size (<CODE>PS</CODE>)
+ command in the HP-GL/2 file. If no plot size is given in the file than
+ the HP-GL/2 filter assumes the plot is ANSI E size.</P>
+</TD></TR>
+</TABLE>
+</CENTER>
+</P>
+<H3><A NAME="4_6_3">Setting the Default Pen Width</A></H3>
+<P>The <CODE>-o penwidth=value</CODE> option specifies the default pen
+ width for HP-GL/2 files:</P>
+<UL>
+<PRE>
+<B>lp -o penwidth=<I>value</I> filename ENTER</B>
+<B>lpr -o penwidth=<I>value</I> filename ENTER</B>
+</PRE>
+</UL>
+<P>The pen width <CODE>value</CODE> specifies the pen width in
+ micrometers. The default value of 1000 produces lines that are 1
+ millimeter in width. Specifying a pen width of 0 produces lines that
+ are exactly 1 pixel wide.
+<CENTER>
+<TABLE BGCOLOR="#cccccc" BORDER="1" CELLPADDING="5" WIDTH="80%">
+<TR><TD><B> NOTE:</B>
+<P>This option is ignored when the pen widths are set in the plot file.</P>
+</TD></TR>
+</TABLE>
+</CENTER>
+</P>
+<H2><A NAME="4_7">Raw or Unfiltered Output</A></H2>
+<P>The <CODE>-o raw</CODE> option allows you to send files directly to a
+ printer without filtering. This is sometimes required when printing
+ from applications that provide their own &quot;printer drivers&quot; for your
+ printer:</P>
+<UL>
+<PRE>
+<B>lp -o raw filename ENTER</B>
+<B>lpr -o raw filename ENTER</B>
+</PRE>
+</UL>
+<P>The <CODE>-l</CODE> option can also be used with the <CODE>lpr</CODE>
+ command to send files directly to a printer:</P>
+<UL>
+<PRE>
+<B>lpr -l filename ENTER</B>
+</PRE>
+</UL>
+<H1 ALIGN="RIGHT"><A NAME="SAVING_OPTIONS">4 - Saving Printer Options
+ and Defaults</A></H1>
+<P>This chapter describes how to save printer options for your printer
+ and set your own default printer.</P>
+<H2><A NAME="5_1">Printer Options</A></H2>
+<P>Each printer supports a large number of options, which you learned
+ about in<A HREF="#STANDARD_OPTIONS"> Chapter 3, &quot;Standard Printer
+ Options&quot;</A>. Rather than specifying these options each time you print
+ a file, CUPS allows you to save them as &quot;default&quot; options for the
+ printer.</P>
+<P>The <CODE>lpoptions(1)</CODE> command saves the options for your
+ printers. Like the <CODE>lp</CODE> and <CODE>lpr</CODE> commands, it
+ accepts printer options using the <CODE>-o</CODE> argument:</P>
+<UL>
+<PRE>
+<B>lpoptions -o media=A4 -o sides=two-sided-long-edge ENTER</B>
+<B>lpoptions -o media=Legal -o scaling=100 ENTER</B>
+</PRE>
+</UL>
+<P>Once saved, any <CODE>lp</CODE> or <CODE>lpr</CODE> command will use
+ them when you print.</P>
+<H2><A NAME="5_2">Setting Options for a Specific Printer</A></H2>
+<P>The previous example shows how to set the options for the default
+ printer. The <CODE>-p printer</CODE> option specifies the options are
+ for another printer:</P>
+<UL>
+<PRE>
+<B>lpoptions -p laserjet -o media=A4 -o sides=two-sided-long-edge ENTER</B>
+<B>lpoptions -p deskjet -o media=Legal -o scaling=100 ENTER</B>
+</PRE>
+</UL>
+<H2><A NAME="5_3">Viewing the Current Defaults</A></H2>
+<P>The <CODE>lpoptions</CODE> command can also be used to show the
+ current options by not specifying any new options on the command-line:</P>
+<UL>
+<PRE>
+<B>lpoptions ENTER</B>
+media=A4 sides=two-sided-long-edge
+<B>lpoptions -p deskjet ENTER</B>
+media=Legal scaling=100
+</PRE>
+</UL>
+<H2><A NAME="5_4">Setting the Default Printer</A></H2>
+<P>The administrator normally will set a system-wide default printer
+ that is normally used as the default printer by everyone. Use the <CODE>
+-d printer</CODE> option to set your own default printer:</P>
+<UL>
+<PRE>
+<B>lpoptions -d deskjet ENTER</B>
+</PRE>
+</UL>
+<P>The printer can be local (<CODE>deskjet</CODE>) or remote (<CODE>
+deskjet@server</CODE>).</P>
+<H2><A NAME="5_5">Printer Instances</A></H2>
+<P>Besides setting options for each print queue, CUPS supports<I>
+ printer instances</I> which allow you to define several different sets
+ of options for each printer. You specify a printer instance using the
+ slash (<CODE>/</CODE>) character:</P>
+<UL>
+<PRE>
+<B>lpoptions -p laserjet/duplex -o sides=two-sided-long-edge ENTER</B>
+<B>lpoptions -p laserjet/legal -o media=Legal ENTER</B>
+</PRE>
+</UL>
+<P>The <CODE>lp</CODE> and lpr commands also understand this notation:</P>
+<UL>
+<PRE>
+<B>lp -d laserjet/duplex filename ENTER</B>
+<B>lpr -P laserjet/legal filename ENTER</B>
+</PRE>
+</UL>
+<H2><A NAME="5_6">Removing Instances</A></H2>
+<P>Use the <CODE>-x printer/instance</CODE> option to remove a printer
+ instance that you no longer need:</P>
+<UL>
+<PRE>
+<B>lpoptions -x laserjet ENTER</B>
+<B>lpoptions -x laserjet/duplex ENTER</B>
+<B>lpoptions -x laserjet/legal ENTER</B>
+</PRE>
+</UL>
+<P>The <CODE>-x</CODE> option only removes the default options for that
+ printer and instance; the original print queue will remain until
+ deleted with the <CODE>lpadmin(8)</CODE> command by the administrator.</P>
+<H1 ALIGN="RIGHT"><A NAME="LICENSE">A - Software License Agreement</A></H1>
+<H2 ALIGN="CENTER"><A NAME="6_1">Common UNIX Printing System License
+ Agreement</A></H2>
+<P ALIGN="CENTER">Copyright 1997-2002 by Easy Software Products
+<BR> 44141 AIRPORT VIEW DR STE 204
+<BR> HOLLYWOOD, MARYLAND 20636-3111 USA
+<BR>
+<BR> Voice: +1.301.373.9600
+<BR> Email:<A HREF="mailto:cups-info@cups.org"> cups-info@cups.org</A>
+<BR> WWW:<A HREF="http://www.cups.org"> http://www.cups.org</A></P>
+<H3><A NAME="6_1_1">Introduction</A></H3>
+<P>The Common UNIX Printing System<SUP>TM</SUP>, (&quot;CUPS<SUP>TM</SUP>&quot;),
+ is provided under the GNU General Public License (&quot;GPL&quot;) and GNU
+ Library General Public License (&quot;LGPL&quot;), Version 2. A copy of these
+ licenses follow this introduction.</P>
+<P>The GNU LGPL applies to the CUPS API library, located in the &quot;cups&quot;
+ subdirectory of the CUPS source distribution and in the
+ &quot;/usr/include/cups&quot; directory and &quot;libcups.a&quot;, &quot;libcups_s.a&quot;,
+ &quot;libcups.sl&quot;, or &quot;libcups.so&quot; files in the binary distributions.</P>
+<P>The GNU GPL applies to the remainder of the CUPS distribution,
+ including the &quot;pstoraster&quot; filter which is based upon GNU Ghostscript
+ 5.50 and the &quot;pdftops&quot; filter which is based upon Xpdf 0.93a.</P>
+<P>For those not familiar with the GNU GPL, the license basically allows
+ you to:</P>
+<UL>
+<LI>Use the CUPS software at no charge.</LI>
+<LI>Distribute verbatim copies of the software in source or binary form.</LI>
+<LI>Sell verbatim copies of the software for a media fee, or sell
+ support for the software.</LI>
+<LI>Distribute or sell printer drivers and filters that use CUPS so long
+ as source code is made available under the GPL.</LI>
+</UL>
+<P>What this license<B> does not</B> allow you to do is make changes or
+ add features to CUPS and then sell a binary distribution without source
+ code. You must provide source for any new drivers, changes, or
+ additions to the software, and all code must be provided under the GPL
+ or LGPL as appropriate.</P>
+<P>The GNU LGPL relaxes the &quot;link-to&quot; restriction, allowing you to
+ develop applications that use the CUPS API library under other licenses
+ and/or conditions as appropriate for your application.</P>
+<H3><A NAME="6_1_2">Trademarks</A></H3>
+<P>Easy Software Products has trademarked the Common UNIX Printing
+ System, CUPS, and CUPS logo. These names and logos may be used freely
+ in any direct port or binary distribution of CUPS. To use them in
+ derivative products, please contract Easy Software Products for written
+ permission. Our intention is to protect the value of these trademarks
+ and ensure that any derivative product meets the same high-quality
+ standards as the original.</P>
+<H3><A NAME="6_1_3">Binary Distribution Rights</A></H3>
+<P>Easy Software Products also sells rights to the CUPS source code
+ under a binary distribution license for vendors that are unable to
+ release source code for their drivers, additions, and modifications to
+ CUPS under the GNU GPL and LGPL. For information please contact us at
+ the address shown above.</P>
+<P>The Common UNIX Printing System provides a &quot;pstoraster&quot; filter that
+ utilizes the GNU GhostScript 5.50 core to convert PostScript files into
+ a stream of raster images. For binary distribution licensing of this
+ software, please contact:<BLOCKQUOTE> Miles Jones
+<BR> Director of Marketing
+<BR> Artifex Software Inc.
+<BR> 454 Las Gallinas Ave., Suite 108
+<BR> San Rafael, CA 94903 USA
+<BR> Voice: +1.415.492.9861
+<BR> Fax: +1.415.492.9862
+<BR> EMail:<A HREF="mailto:info@arsoft.com"> info@arsoft.com</A></BLOCKQUOTE>
+</P>
+<P>The &quot;pdftops&quot; filter is based on the Xpdf 0.93a software. For binary
+ distribution licensing of this software, please contact:<BLOCKQUOTE>
+ Derek B. Noonburg
+<BR> Email:<A HREF="mailto:derekn@foolabs.com"> derekn@foolabs.com</A>
+<BR> WWW:<A HREF="http://www.foolabs.com/xpdf/">
+ http://www.foolabs.com/xpdf/</A></BLOCKQUOTE></P>
+<H3><A NAME="6_1_4">Support</A></H3>
+<P>Easy Software Products sells software support for CUPS as well as a
+ commercial printing product based on CUPS called ESP Print Pro. You can
+ find out more at our web site:</P>
+<UL>
+<PRE>
+<A HREF="http://www.easysw.com">http://www.easysw.com</A>
+</PRE>
+</UL>
+
+<!-- NEW PAGE -->
+<H2><A NAME="6_2">GNU GENERAL PUBLIC LICENSE</A></H2>
+<P>Version 2, June 1991</P>
+<PRE>
+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.
+</PRE>
+<PRE>
+
+</PRE>
+<H4>Preamble</H4>
+<P>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.</P>
+<P>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.</P>
+<P>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.</P>
+<P>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.</P>
+<P>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.</P>
+<P>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.</P>
+<P>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.</P>
+<P>The precise terms and conditions for copying, distribution and
+ modification follow.</P>
+<H4>GNU GENERAL PUBLIC LICENSE
+<BR> TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION</H4>
+<OL START="0">
+<LI>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 &quot;Program&quot;, below,
+ refers to any such program or work, and a &quot;work based on the Program&quot;
+ 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 &quot;modification&quot;.) Each licensee is addressed as &quot;you&quot;.</LI>
+<P>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.</P>
+<LI>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.</LI>
+<P>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.</P>
+<LI>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:
+<OL TYPE="a">
+<LI>You must cause the modified files to carry prominent notices stating
+ that you changed the files and the date of any change.</LI>
+<LI>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.</LI>
+<LI>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.)</LI>
+</OL>
+</LI>
+<P>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.</P>
+<P>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.</P>
+<P>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.</P>
+<LI>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:
+<OL TYPE="a">
+<LI>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,</LI>
+<LI>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,</LI>
+<LI>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.)</LI>
+</OL>
+</LI>
+<P>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.</P>
+<P>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.</P>
+<LI>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.</LI>
+<LI>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.</LI>
+<LI>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.</LI>
+<LI>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.</LI>
+<P>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.</P>
+<P>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.</P>
+<P>This section is intended to make thoroughly clear what is believed to
+ be a consequence of the rest of this License.</P>
+<LI>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.</LI>
+<LI>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.</LI>
+<P>Each version is given a distinguishing version number. If the Program
+ specifies a version number of this License which applies to it and &quot;any
+ later version&quot;, 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.</P>
+<LI>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.</LI>
+</OL>
+<H4>NO WARRANTY</H4>
+<OL START="11">
+<LI>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 &quot;AS IS&quot; 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.</LI>
+<LI>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.</LI>
+</OL>
+<H4>END OF TERMS AND CONDITIONS</H4>
+
+<!-- NEW PAGE -->
+<H2><A NAME="6_3">GNU LIBRARY GENERAL PUBLIC LICENSE</A></H2>
+<P>Version 2, June 1991</P>
+<PRE>
+Copyright (C) 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.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+</PRE>
+<H4>Preamble</H4>
+<P>The licenses for most software are designed to take away your freedom
+ to share and change it. By contrast, the GNU General Public Licenses
+ are intended to guarantee your freedom to share and change free
+ software--to make sure the software is free for all its users.</P>
+<P>This license, the Library General Public License, applies to some
+ specially designated Free Software Foundation software, and to any
+ other libraries whose authors decide to use it. You can use it for your
+ libraries, too.</P>
+<P>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.</P>
+<P>To protect your rights, we need to make restrictions that forbid
+ anyone to deny you these rights or to ask you to surrender the rights.
+ These restrictions translate to certain responsibilities for you if you
+ distribute copies of the library, or if you modify it.</P>
+<P>For example, if you distribute copies of the library, whether gratis
+ or for a fee, you must give the recipients all the rights that we gave
+ you. You must make sure that they, too, receive or can get the source
+ code. If you link a program with the library, you must provide complete
+ object files to the recipients so that they can relink them with the
+ library, after making changes to the library and recompiling it. And
+ you must show them these terms so they know their rights.</P>
+<P>Our method of protecting your rights has two steps: (1) copyright the
+ library, and (2) offer you this license which gives you legal
+ permission to copy, distribute and/or modify the library.</P>
+<P>Also, for each distributor's protection, we want to make certain that
+ everyone understands that there is no warranty for this free library.
+ If the library is modified by someone else and passed on, we want its
+ recipients to know that what they have is not the original version, so
+ that any problems introduced by others will not reflect on the original
+ authors' reputations.</P>
+<P>Finally, any free program is threatened constantly by software
+ patents. We wish to avoid the danger that companies distributing free
+ software will individually obtain patent licenses, thus in effect
+ transforming the program into proprietary software. To prevent this, we
+ have made it clear that any patent must be licensed for everyone's free
+ use or not licensed at all.</P>
+<P>Most GNU software, including some libraries, is covered by the
+ ordinary GNU General Public License, which was designed for utility
+ programs. This license, the GNU Library General Public License, applies
+ to certain designated libraries. This license is quite different from
+ the ordinary one; be sure to read it in full, and don't assume that
+ anything in it is the same as in the ordinary license.</P>
+<P>The reason we have a separate public license for some libraries is
+ that they blur the distinction we usually make between modifying or
+ adding to a program and simply using it. Linking a program with a
+ library, without changing the library, is in some sense simply using
+ the library, and is analogous to running a utility program or
+ application program. However, in a textual and legal sense, the linked
+ executable is a combined work, a derivative of the original library,
+ and the ordinary General Public License treats it as such.</P>
+<P>Because of this blurred distinction, using the ordinary General
+ Public License for libraries did not effectively promote software
+ sharing, because most developers did not use the libraries. We
+ concluded that weaker conditions might promote sharing better.</P>
+<P>However, unrestricted linking of non-free programs would deprive the
+ users of those programs of all benefit from the free status of the
+ libraries themselves. This Library General Public License is intended
+ to permit developers of non-free programs to use free libraries, while
+ preserving your freedom as a user of such programs to change the free
+ libraries that are incorporated in them. (We have not seen how to
+ achieve this as regards changes in header files, but we have achieved
+ it as regards changes in the actual functions of the Library.) The hope
+ is that this will lead to faster development of free libraries.</P>
+<P>The precise terms and conditions for copying, distribution and
+ modification follow. Pay close attention to the difference between a
+ &quot;work based on the library&quot; and a &quot;work that uses the library&quot;. The
+ former contains code derived from the library, while the latter only
+ works together with the library.</P>
+<P>Note that it is possible for a library to be covered by the ordinary
+ General Public License rather than by this special one.</P>
+<H4>TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION</H4>
+<P><STRONG>0.</STRONG> This License Agreement applies to any software
+ library which contains a notice placed by the copyright holder or other
+ authorized party saying it may be distributed under the terms of this
+ Library General Public License (also called &quot;this License&quot;). Each
+ licensee is addressed as &quot;you&quot;.</P>
+<P>A &quot;library&quot; means a collection of software functions and/or data
+ prepared so as to be conveniently linked with application programs
+ (which use some of those functions and data) to form executables.</P>
+<P>The &quot;Library&quot;, below, refers to any such software library or work
+ which has been distributed under these terms. A &quot;work based on the
+ Library&quot; means either the Library or any derivative work under
+ copyright law: that is to say, a work containing the Library or a
+ portion of it, either verbatim or with modifications and/or translated
+ straightforwardly into another language. (Hereinafter, translation is
+ included without limitation in the term &quot;modification&quot;.)</P>
+<P>&quot;Source code&quot; for a work means the preferred form of the work for
+ making modifications to it. For a library, complete source code means
+ all the source code for all modules it contains, plus any associated
+ interface definition files, plus the scripts used to control
+ compilation and installation of the library.</P>
+<P>Activities other than copying, distribution and modification are not
+ covered by this License; they are outside its scope. The act of running
+ a program using the Library is not restricted, and output from such a
+ program is covered only if its contents constitute a work based on the
+ Library (independent of the use of the Library in a tool for writing
+ it). Whether that is true depends on what the Library does and what the
+ program that uses the Library does.</P>
+<P><STRONG>1.</STRONG> You may copy and distribute verbatim copies of
+ the Library's complete source code as you receive it, in any medium,
+ provided that you conspicuously and appropriately publish on each copy
+ an appropriate copyright notice and disclaimer of warranty; keep intact
+ all the notices that refer to this License and to the absence of any
+ warranty; and distribute a copy of this License along with the Library.</P>
+<P>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.</P>
+<P><STRONG>2.</STRONG> You may modify your copy or copies of the Library
+ or any portion of it, thus forming a work based on the Library, and
+ copy and distribute such modifications or work under the terms of
+ Section 1 above, provided that you also meet all of these conditions:</P>
+<OL TYPE="a">
+<LI>The modified work must itself be a software library.</LI>
+<P></P>
+<LI>You must cause the files modified to carry prominent notices stating
+ that you changed the files and the date of any change.</LI>
+<P></P>
+<LI>You must cause the whole of the work to be licensed at no charge to
+ all third parties under the terms of this License.</LI>
+<P></P>
+<LI>If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses the
+ facility, other than as an argument passed when the facility is
+ invoked, then you must make a good faith effort to ensure that, in the
+ event an application does not supply such function or table, the
+ facility still operates, and performs whatever part of its purpose
+ remains meaningful.</LI>
+<P>(For example, a function in a library to compute square roots has a
+ purpose that is entirely well-defined independent of the application.
+ Therefore, Subsection 2d requires that any application-supplied
+ function or table used by this function must be optional: if the
+ application does not supply it, the square root function must still
+ compute square roots.)</P>
+</OL>
+<P>These requirements apply to the modified work as a whole. If
+ identifiable sections of that work are not derived from the Library,
+ and can be reasonably considered independent and separate works in
+ themselves, then this License, and its terms, do not apply to those
+ sections when you distribute them as separate works. But when you
+ distribute the same sections as part of a whole which is a work based
+ on the Library, the distribution of the whole must be on the terms of
+ this License, whose permissions for other licensees extend to the
+ entire whole, and thus to each and every part regardless of who wrote
+ it.</P>
+<P>Thus, it is not the intent of this section to claim rights or contest
+ your rights to work written entirely by you; rather, the intent is to
+ exercise the right to control the distribution of derivative or
+ collective works based on the Library.</P>
+<P>In addition, mere aggregation of another work not based on the
+ Library with the Library (or with a work based on the Library) on a
+ volume of a storage or distribution medium does not bring the other
+ work under the scope of this License.</P>
+<P><STRONG>3.</STRONG> You may opt to apply the terms of the ordinary
+ GNU General Public License instead of this License to a given copy of
+ the Library. To do this, you must alter all the notices that refer to
+ this License, so that they refer to the ordinary GNU General Public
+ License, version 2, instead of to this License. (If a newer version
+ than version 2 of the ordinary GNU General Public License has appeared,
+ then you can specify that version instead if you wish.) Do not make any
+ other change in these notices.</P>
+<P>Once this change is made in a given copy, it is irreversible for that
+ copy, so the ordinary GNU General Public License applies to all
+ subsequent copies and derivative works made from that copy.</P>
+<P>This option is useful when you wish to copy part of the code of the
+ Library into a program that is not a library.</P>
+<P><STRONG>4.</STRONG> You may copy and distribute the Library (or a
+ portion or derivative of it, under Section 2) in object code or
+ executable form under the terms of Sections 1 and 2 above provided that
+ you accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections 1
+ and 2 above on a medium customarily used for software interchange.</P>
+<P>If distribution of object code is made by offering access to copy
+ from a designated place, then offering equivalent access to copy the
+ source code from the same place satisfies the requirement to distribute
+ the source code, even though third parties are not compelled to copy
+ the source along with the object code.</P>
+<P><STRONG>5.</STRONG> A program that contains no derivative of any
+ portion of the Library, but is designed to work with the Library by
+ being compiled or linked with it, is called a &quot;work that uses the
+ Library&quot;. Such a work, in isolation, is not a derivative work of the
+ Library, and therefore falls outside the scope of this License.</P>
+<P>However, linking a &quot;work that uses the Library&quot; with the Library
+ creates an executable that is a derivative of the Library (because it
+ contains portions of the Library), rather than a &quot;work that uses the
+ library&quot;. The executable is therefore covered by this License. Section
+ 6 states terms for distribution of such executables.</P>
+<P>When a &quot;work that uses the Library&quot; uses material from a header file
+ that is part of the Library, the object code for the work may be a
+ derivative work of the Library even though the source code is not.
+ Whether this is true is especially significant if the work can be
+ linked without the Library, or if the work is itself a library. The
+ threshold for this to be true is not precisely defined by law.</P>
+<P>If such an object file uses only numerical parameters, data structure
+ layouts and accessors, and small macros and small inline functions (ten
+ lines or less in length), then the use of the object file is
+ unrestricted, regardless of whether it is legally a derivative work.
+ (Executables containing this object code plus portions of the Library
+ will still fall under Section 6.)</P>
+<P>Otherwise, if the work is a derivative of the Library, you may
+ distribute the object code for the work under the terms of Section 6.
+ Any executables containing that work also fall under Section 6, whether
+ or not they are linked directly with the Library itself.</P>
+<P><STRONG>6.</STRONG> As an exception to the Sections above, you may
+ also compile or link a &quot;work that uses the Library&quot; with the Library to
+ produce a work containing portions of the Library, and distribute that
+ work under terms of your choice, provided that the terms permit
+ modification of the work for the customer's own use and reverse
+ engineering for debugging such modifications.</P>
+<P>You must give prominent notice with each copy of the work that the
+ Library is used in it and that the Library and its use are covered by
+ this License. You must supply a copy of this License. If the work
+ during execution displays copyright notices, you must include the
+ copyright notice for the Library among them, as well as a reference
+ directing the user to the copy of this License. Also, you must do one
+ of these things:</P>
+<OL TYPE="a">
+<LI>Accompany the work with the complete corresponding machine-readable
+ source code for the Library including whatever changes were used in the
+ work (which must be distributed under Sections 1 and 2 above); and, if
+ the work is an executable linked with the Library, with the complete
+ machine-readable &quot;work that uses the Library&quot;, as object code and/or
+ source code, so that the user can modify the Library and then relink to
+ produce a modified executable containing the modified Library. (It is
+ understood that the user who changes the contents of definitions files
+ in the Library will not necessarily be able to recompile the
+ application to use the modified definitions.)</LI>
+<P></P>
+<LI>Accompany the work with a written offer, valid for at least three
+ years, to give the same user the materials specified in Subsection 6a,
+ above, for a charge no more than the cost of performing this
+ distribution.</LI>
+<P></P>
+<LI>If distribution of the work is made by offering access to copy from
+ a designated place, offer equivalent access to copy the above specified
+ materials from the same place.</LI>
+<P></P>
+<LI>Verify that the user has already received a copy of these materials
+ or that you have already sent this user a copy.</LI>
+</OL>
+<P>For an executable, the required form of the &quot;work that uses the
+ Library&quot; must include any data and utility programs needed for
+ reproducing the executable from it. However, as a special exception,
+ the source code distributed need not include anything that is normally
+ distributed (in either source or binary form) with the major components
+ (compiler, kernel, and so on) of the operating system on which the
+ executable runs, unless that component itself accompanies the
+ executable.</P>
+<P>It may happen that this requirement contradicts the license
+ restrictions of other proprietary libraries that do not normally
+ accompany the operating system. Such a contradiction means you cannot
+ use both them and the Library together in an executable that you
+ distribute.</P>
+<P><STRONG>7.</STRONG> You may place library facilities that are a work
+ based on the Library side-by-side in a single library together with
+ other library facilities not covered by this License, and distribute
+ such a combined library, provided that the separate distribution of the
+ work based on the Library and of the other library facilities is
+ otherwise permitted, and provided that you do these two things:</P>
+<OL TYPE="a">
+<LI>Accompany the combined library with a copy of the same work based on
+ the Library, uncombined with any other library facilities. This must be
+ distributed under the terms of the Sections above.</LI>
+<P></P>
+<LI>Give prominent notice with the combined library of the fact that
+ part of it is a work based on the Library, and explaining where to find
+ the accompanying uncombined form of the same work.</LI>
+</OL>
+<P><STRONG>8.</STRONG> You may not copy, modify, sublicense, link with,
+ or distribute the Library except as expressly provided under this
+ License. Any attempt otherwise to copy, modify, sublicense, link with,
+ or distribute the Library is void, and will automatically terminate
+ your rights under this License. However, parties who have received
+ copies, or rights, from you under this License will not have their
+ licenses terminated so long as such parties remain in full compliance.</P>
+<P><STRONG>9.</STRONG> You are not required to accept this License,
+ since you have not signed it. However, nothing else grants you
+ permission to modify or distribute the Library or its derivative works.
+ These actions are prohibited by law if you do not accept this License.
+ Therefore, by modifying or distributing the Library (or any work based
+ on the Library), you indicate your acceptance of this License to do so,
+ and all its terms and conditions for copying, distributing or modifying
+ the Library or works based on it.</P>
+<P><STRONG>10.</STRONG> Each time you redistribute the Library (or any
+ work based on the Library), the recipient automatically receives a
+ license from the original licensor to copy, distribute, link with or
+ modify the Library subject to these terms and conditions. You may not
+ impose any further restrictions on the recipients' exercise of the
+ rights granted herein. You are not responsible for enforcing compliance
+ by third parties to this License.</P>
+<P><STRONG>11.</STRONG> If, as a consequence of a court judgment or
+ allegation of patent infringement or for any other reason (not limited
+ to patent issues), conditions are imposed on you (whether by court
+ order, agreement or otherwise) that contradict the conditions of this
+ License, they do not excuse you from the conditions of this License. If
+ you cannot distribute so as to satisfy simultaneously your obligations
+ under this License and any other pertinent obligations, then as a
+ consequence you may not distribute the Library at all. For example, if
+ a patent license would not permit royalty-free redistribution of the
+ Library by all those who receive copies directly or indirectly through
+ you, then the only way you could satisfy both it and this License would
+ be to refrain entirely from distribution of the Library.</P>
+<P>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.</P>
+<P>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.</P>
+<P>This section is intended to make thoroughly clear what is believed to
+ be a consequence of the rest of this License.</P>
+<P><STRONG>12.</STRONG> If the distribution and/or use of the Library is
+ restricted in certain countries either by patents or by copyrighted
+ interfaces, the original copyright holder who places the Library under
+ this License may add an explicit geographical distribution limitation
+ excluding those countries, so that distribution is permitted only in or
+ among countries not thus excluded. In such case, this License
+ incorporates the limitation as if written in the body of this License.</P>
+<P><STRONG>13.</STRONG> The Free Software Foundation may publish revised
+ and/or new versions of the Library General Public License from time to
+ time. Such new versions will be similar in spirit to the present
+ version, but may differ in detail to address new problems or concerns.</P>
+<P>Each version is given a distinguishing version number. If the Library
+ specifies a version number of this License which applies to it and &quot;any
+ later version&quot;, you have the option of following the terms and
+ conditions either of that version or of any later version published by
+ the Free Software Foundation. If the Library does not specify a license
+ version number, you may choose any version ever published by the Free
+ Software Foundation.</P>
+<P><STRONG>14.</STRONG> If you wish to incorporate parts of the Library
+ into other free programs whose distribution conditions are incompatible
+ with these, write to the author to ask for permission. For software
+ which is copyrighted by the Free Software Foundation, write to the Free
+ Software Foundation; we sometimes make exceptions for this. Our
+ decision will be guided by the two goals of preserving the free status
+ of all derivatives of our free software and of promoting the sharing
+ and reuse of software generally.</P>
+<P><STRONG>NO WARRANTY</STRONG></P>
+<P><STRONG>15.</STRONG> BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE,
+ THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY
+ APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+ HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY &quot;AS IS&quot; WITHOUT
+ WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE
+ OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU
+ ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.</P>
+<P><STRONG>16.</STRONG> IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR
+ AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO
+ MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE
+ LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL
+ OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+ LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+ RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+ FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+ SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ DAMAGES.</P>
+<H4>END OF TERMS AND CONDITIONS</H4>
+</BODY>
+</HTML>
diff --git a/doc/sum.pdf b/doc/sum.pdf
new file mode 100644
index 000000000..d8da918bd
--- /dev/null
+++ b/doc/sum.pdf
Binary files differ
diff --git a/doc/sum.shtml b/doc/sum.shtml
new file mode 100644
index 000000000..50578fb04
--- /dev/null
+++ b/doc/sum.shtml
@@ -0,0 +1,887 @@
+<HTML>
+<HEAD>
+ <META NAME="Description" CONTENT="Common UNIX Printing System Software Users Manual">
+ <META NAME="COPYRIGHT" CONTENT="Copyright 1997-2002, All Rights Reserved">
+ <META NAME="DOCNUMBER" CONTENT="CUPS-SUM-1.1.13">
+ <META NAME="Author" CONTENT="Easy Software Products">
+ <TITLE>CUPS Software Users Manual</TITLE>
+</HEAD>
+<BODY>
+
+<H1 ALIGN="RIGHT">Preface</H1>
+
+<P>This software users manual describes how to use the Common UNIX Printing
+System<SUP>TM</SUP> ("CUPS<SUP>TM</SUP>") Version 1.1.13.
+
+<EMBED SRC="system-overview.shtml">
+
+<!-- NEED 2in -->
+<H2>Document Overview</H2>
+
+<P>This software users manual is organized into the following sections:</P>
+
+<UL>
+ <LI><A HREF="#OVERVIEW">1 - Printing System Overview</A>
+ <LI><A HREF="#USING_SYSTEM">2 - Using the Printing System</A>
+ <LI><A HREF="#STANDARD_OPTIONS">3 - Standard Printer Options</A>
+ <LI><A HREF="#SAVING_OPTIONS">4 - Saving Printer Options and Defaults</A>
+ <LI><A HREF="#LICENSE">A - Software License Agreement</A>
+</UL>
+
+<H2>Notation Conventions</H2>
+
+<P>Various font and syntax conventions are used in this guide. Examples and
+their meanings and uses are explained below:
+
+<CENTER><TABLE WIDTH="80%">
+<TR>
+ <TH>Example</TH>
+ <TD>&nbsp;&nbsp;&nbsp;</TD>
+ <TH>Description</TH>
+</TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR VALIGN="TOP">
+ <TD><CODE>lpstat</CODE><BR>
+ <CODE>lpstat(1)</CODE></TD>
+
+ <TD>&nbsp;&nbsp;&nbsp;</TD>
+
+ <TD>The names of commands; the first mention of a command or
+ function in a chapter is followed by a manual page section
+ number.</TD>
+</TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR VALIGN="TOP">
+ <TD><VAR>/var</VAR><BR>
+ <VAR>/usr/share/cups/data/testprint.ps</VAR></TD>
+
+ <TD>&nbsp;&nbsp;&nbsp;</TD>
+
+ <TD>File and directory names.</TD>
+</TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR VALIGN="TOP">
+ <TD NOWRAP><TT>Request ID is Printer-123</TT></TD>
+
+ <TD>&nbsp;&nbsp;&nbsp;</TD>
+
+ <TD>Screen output.</TD>
+</TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR VALIGN="TOP">
+ <TD NOWRAP><KBD>lp -d printer filename ENTER</KBD></TD>
+
+ <TD>&nbsp;&nbsp;&nbsp;</TD>
+
+ <TD>Literal user input; special keys like <KBD>ENTER</B></KBD> are
+ in ALL CAPS.</TD>
+</TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR VALIGN="TOP">
+ <TD>12.3</TD>
+
+ <TD>&nbsp;&nbsp;&nbsp;</TD>
+
+ <TD>Numbers in the text are written using the period (.) to indicate
+ the decimal point.</TD>
+</TR>
+</TABLE></CENTER>
+
+<!-- NEED 3in -->
+<H2>Abbreviations</H2>
+
+The following abbreviations are used throughout this manual:
+
+<UL>
+<DL>
+
+ <DT>kb
+ <DD>Kilobytes, or 1024 bytes<BR>&nbsp;
+
+ <DT>Mb
+ <DD>Megabytes, or 1048576 bytes<BR>&nbsp;
+
+ <DT>Gb
+ <DD>Gigabytes, or 1073741824 bytes<BR>&nbsp;
+
+</DL>
+</UL>
+
+<H2>Other References</H2>
+
+<UL>
+<DL>
+
+ <DT>CUPS Software Administrators Manual
+
+ <DD>An administration guide for the CUPS software.<BR>&nbsp;
+
+ <DT>CUPS Software Programmers Manual
+
+ <DD>A programmer guide for interfacing with and/or extending the CUPS
+ software.<BR>&nbsp;
+
+</DL>
+</UL>
+
+
+<EMBED SRC="printing-overview.shtml">
+
+
+<H1 ALIGN="RIGHT"><A NAME="USING_SYSTEM">2 - Using the Printing System</A></H1>
+
+<P>This chapter shows you how to submit, query, and cancel print jobs to
+different printers.
+
+<H2>Submitting Files for Printing</H2>
+
+<P>CUPS provides both the System V (<CODE>lp(1)</CODE>) and Berkeley
+(<CODE>lpr(1)</CODE>) printing commands. Type the following command to
+print a file to the default (or only) printer on the system:
+
+<UL><PRE>
+<B>lp filename ENTER</B>
+</PRE></UL>
+
+<P>or:
+
+<UL><PRE>
+<B>lpr filename ENTER</B>
+</PRE></UL>
+
+<P>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!
+
+<H2>Choosing a Printer</H2>
+
+<P>Many systems will have more than one printer available to the user. These
+printers can be attached to the local system via a parallel, serial, or USB
+port, or available over the network.
+
+<P>Use the <CODE>lpstat(1)</CODE> command to see a list of available printers:
+
+<UL><PRE>
+<B>lpstat -p -d ENTER</B>
+</PRE></UL>
+
+<P>The <CODE>-p</CODE> option specifies that you want to see a list of
+printers, and the <CODE>-d</CODE> option reports the current system
+default printer or class.
+
+<P>Use the <CODE>-d</CODE> option with the <CODE>lp</CODE> command to
+print to a specific printer:
+
+<UL><PRE>
+<B>lp -d printer filename ENTER</B>
+</PRE></UL>
+
+<P>or the <CODE>-P</CODE> option with the <CODE>lpr</CODE> command:
+
+<UL><PRE>
+<B>lpr -P printer filename ENTER</B>
+</PRE></UL>
+
+<H2>Setting Printer Options</H2>
+
+<P>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.
+
+<P>The <CODE>lp</CODE> and <CODE>lpr</CODE> commands allow you to pass
+printer options using the <CODE>-o</CODE> option:
+
+<UL><PRE>
+<B>lp -o landscape -o scaling=75 -o media=A4 filename.jpg
+<B>lpr -o landscape -o scaling=75 -o media=A4 filename.jpg
+</PRE></UL>
+
+<P>The available printer options vary depending on the printer. The standard
+options are described in <A HREF="#STANDARD_OPTIONS">Chapter 3, "Standard
+Printing Options"</A>.
+
+<H2>Printing Multiple Copies</H2>
+
+<P>Both the <CODE>lp</CODE> and <CODE>lpr</CODE> commands have options for
+printing more than one copy of a file:
+
+<UL><PRE>
+<B>lp -n <I>num-copies</I> filename ENTER</B>
+<B>lpr -#<I>num-copies</I> filename ENTER</B>
+</PRE></UL>
+
+<P>Copies are normally <I>not</I> collated for you. Use the <CODE>-o
+Collate=True</CODE> option to get collated copies :
+
+<UL><PRE>
+<B>lp -n <I>num-copies</I> -o Collate=True filename ENTER</B>
+<B>lpr -#<I>num-copies</I> -o Collate=True filename ENTER</B>
+</PRE></UL>
+
+<!-- NEED 3in -->
+<H2>Checking the Printer Status from the Command-Line</H2>
+
+<P>The <CODE>lpstat</CODE> command can be used to check for jobs that you
+have submitted for printing:
+
+<UL><PRE>
+<B>lpstat ENTER</B>
+Printer-1 johndoe 4427776
+Printer-2 johndoe 15786
+Printer-3 johndoe 372842
+</PRE></UL>
+
+<P>The jobs are listed in the order they will be printed. Use the
+<CODE>-p</CODE> option to see which files and printers are active:
+
+<UL><PRE>
+<B>lpstat -p ENTER</B>
+printer DeskJet now printing DeskJet-1.
+</PRE></UL>
+
+<!-- NEED 2in -->
+<P>Use the <CODE>-o</CODE> and <CODE>-p</CODE> options together to show
+the jobs and the printers:
+
+<UL><PRE>
+<B>lpstat -o -p ENTER</B>
+Printer-1 johndoe 4427776
+Printer-2 johndoe 15786
+Printer-3 johndoe 372842
+printer DeskJet now printing DeskJet-1.
+</PRE></UL>
+
+<H2>Checking the Printer Status from the Web</H2>
+
+<P>Since CUPS uses the Internet Printing Protocol, it is also a
+fully-functional web server. To use your web browser to monitor the
+printers on your system, open the URL:
+
+<UL><PRE>
+<A HREF="http://localhost:631">http://localhost:631</A>
+</PRE></UL>
+
+<P>From there you can view the status of classes, jobs, and printers
+with the click of a button!
+
+<H2>Canceling a Print Job</H2>
+
+<P>The <CODE>cancel(1)</CODE> and <CODE>lprm(1)</CODE> commands cancel
+a print job:
+
+<UL><PRE>
+<B>cancel <I>job-id</I> ENTER</B>
+<B>lprm <I>job-id</I> ENTER</B>
+</PRE></UL>
+
+<P>The <CODE>job-id</CODE> is the number that was reported to you by
+the <CODE>lp</CODE> or <CODE>lpstat</CODE> commands.
+
+
+<H1 ALIGN="RIGHT"><A NAME="STANDARD_OPTIONS">3 - Standard Printer Options</A></H1>
+
+<P>This chapter describes the standard printer options that are available
+when printing with the <CODE>lp</CODE> and <CODE>lpr</CODE> commands.
+
+<H2>General Options</H2>
+
+<P>The following options apply when printing all types of files.
+
+<H3>Setting the Orientation</H3>
+
+<P>The <CODE>-o landscape</CODE> option will rotate the page 90 degrees
+to print in landscape orientation:
+
+<UL><PRE>
+<B>lp -o landscape filename ENTER</B>
+<B>lpr -o landscape filename ENTER</B>
+</PRE></UL>
+
+<!-- NEED 2in -->
+<H3>Selecting the Media Size, Type, and Source</H3>
+
+<P>The <CODE>-o media=xyz</CODE> option sets the media size, type,
+and/or source:
+
+<UL><PRE>
+<B>lp -o media=Letter filename ENTER</B>
+<B>lp -o media=Letter,MultiPurpose filename ENTER</B>
+<B>lpr -o media=Letter,Transparency filename ENTER</B>
+<B>lpr -o media=Letter,MultiPurpose,Transparency filename ENTER</B>
+</PRE></UL>
+
+<!-- NEED 3in -->
+<P>The available media sizes, types, and sources depend on the printer, but
+most support the following options (case is not significant):
+
+<UL>
+
+ <LI><CODE>Letter</CODE> - US Letter (8.5x11 inches, or 216x279mm)
+
+ <LI><CODE>Legal</CODE> - US Legal (8.5x14 inches, or 216x356mm)
+
+ <LI><CODE>A4</CODE> - ISO A4 (8.27x11.69 inches, or 210x297mm)
+
+ <LI><CODE>COM10</CODE> - US #10 Envelope (9.5x4.125 inches, or
+ 241x105mm)
+
+ <LI><CODE>DL</CODE> - ISO DL Envelope (8.66x4.33 inches, or 220x110mm)
+
+ <LI><CODE>Transparency</CODE> - Transparency media type or source
+
+ <LI><CODE>Upper</CODE> - Upper paper tray
+
+ <LI><CODE>Lower</CODE> - Lower paper tray
+
+ <LI><CODE>MultiPurpose</CODE> - Multi-purpose paper tray
+
+ <LI><CODE>LargeCapacity</CODE> - Large capacity paper tray
+
+</UL>
+
+<P>The actual options supported are defined in the printer's PPD file
+in the <CODE>PageSize</CODE>, <CODE>InputSlot</CODE>, and
+<CODE>MediaType</CODE> options.
+
+<H3>Printing On Both Sides of the Paper</H3>
+
+<P>The <CODE>-o sides=two-sided-short-edge</CODE> and <CODE>-o
+sides=two-sided-long-edge</CODE> options will enable duplexing on the
+printer, if the printer supports it. The <CODE>-o
+sides=two-sided-short-edge</CODE> option is suitable for landscape
+pages, while the <CODE>-o sides=two-sided-long-edge</CODE> option is
+suitable for portrait pages:
+
+<UL><PRE>
+<B>lp -o sides=two-sided-short-edge filename ENTER</B>
+<B>lp -o sides=two-sided-long-edge filename ENTER</B>
+<B>lpr -o sides=two-sided-long-edge filename ENTER</B>
+</PRE></UL>
+
+<P>The default is to print single-sided:
+
+<UL><PRE>
+<B>lp -o sides=one-sided filename ENTER</B>
+<B>lpr -o sides=one-sided filename ENTER</B>
+</PRE></UL>
+
+<H2>Banner Options</H2>
+
+<P>The following options apply when printing all types of files.
+
+<H3>Selecting the Banner Page(s)</H3>
+
+<P>The <CODE>-o jobsheets=start,end</CODE> option sets the banner page(s) to
+use for a job:
+
+<UL><PRE>
+<B>lp -o job-sheets=none filename ENTER</B>
+<B>lp -o job-sheets=standard filename ENTER</B>
+<B>lpr -o job-sheets=classified,classified filename ENTER</B>
+</PRE></UL>
+
+<P>If only one banner file is specified, it will be printed before the
+files in the job. If a second banner file is specified, it is printed after
+the files in the job.
+
+<P>The available banner pages depend on the local system configuration; CUPS
+includes the following banner files:
+
+<UL>
+
+ <LI><CODE>none</CODE> - Do not produce a banner page.
+
+ <LI><CODE>classified</CODE> - A banner page with a "classified"
+ label at the top and bottom.
+
+ <LI><CODE>confidential</CODE> - A banner page with a
+ "confidential" label at the top and bottom.
+
+ <LI><CODE>secret</CODE> - A banner page with a "secret" label
+ at the top and bottom.
+
+ <LI><CODE>standard</CODE> - A banner page with no label at the
+ top and bottom.
+
+ <LI><CODE>topsecret</CODE> - A banner page with a "top secret"
+ label at the top and bottom.
+
+ <LI><CODE>unclassified</CODE> - A banner page with an
+ "unclassified" label at the top and bottom.
+
+</UL>
+
+<H2>Document Options</H2>
+
+<P>The following options apply when printing all types of files.
+
+<H3>Selecting a Range of Pages</H3>
+
+<P>The <CODE>-o page-ranges=pages</CODE> option selects a range of
+pages for printing:
+
+<UL><PRE>
+<B>lp -o page-ranges=1 filename ENTER</B>
+<B>lp -o page-ranges=1-4 filename ENTER</B>
+<B>lp -o page-ranges=1-4,7,9-12 filename ENTER</B>
+<B>lpr -o page-ranges=1-4,7,9-12 filename ENTER</B>
+</PRE></UL>
+
+<P>As shown above, the <CODE>pages</CODE> 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 <CODE>page-ranges</CODE> option.
+
+<P>The default is to print all pages.
+
+<H3>Selecting Even or Odd Pages</H3>
+
+<P>Use the <CODE>-o page-set=set</CODE> option to select the even or odd pages:
+
+<UL><PRE>
+<B>lp -o page-set=odd filename ENTER</B>
+<B>lp -o page-set=even filename ENTER</B>
+<B>lpr -o page-set=even filename ENTER</B>
+</PRE></UL>
+
+<P>The default is to print all pages.
+
+<H3>N-Up Printing</H3>
+
+<P>The <CODE>-o number-up=value</CODE> 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:
+
+<UL><PRE>
+<B>lp -o number-up=1 filename ENTER</B>
+<B>lp -o number-up=2 filename ENTER</B>
+<B>lp -o number-up=4 filename ENTER</B>
+<B>lpr -o number-up=4 filename ENTER</B>
+</PRE></UL>
+
+<P>The default format is 1-Up.
+
+<H3>Setting the Brightness</H3>
+
+<P>You can control the overall brightness of the printed output using the
+<CODE>-o brightness=percent</CODE> option:
+
+<UL><PRE>
+<B>lp -o brightness=120 filename ENTER</B>
+<B>lpr -o brightness=120 filename ENTER</B>
+</PRE></UL>
+
+<P>Values greater than 100 will lighten the print, while values less than
+100 will darken it.
+
+<H3>Setting the Gamma Correction</H3>
+
+<P>You can control the overall gamma correction of the printed output
+using the <CODE>-o gamma=value</CODE> option:
+
+<UL><PRE>
+<B>lp -o gamma=1700 filename ENTER</B>
+<B>lpr -o gamma=1700 filename ENTER</B>
+</PRE></UL>
+
+<P>Values greater than 1000 will lighten the print, while values less
+than 1000 will darken it. The default gamma is 1000.
+
+<H2>Text Options</H2>
+
+<P>The following options apply when printing text files.
+
+<H3>Setting the Number of Characters Per Inch</H3>
+
+<P>The <CODE>-o cpi=value</CODE> option sets the number of characters per inch:
+
+<UL><PRE>
+<B>lp -o cpi=10 filename ENTER</B>
+<B>lp -o cpi=12 filename ENTER</B>
+<B>lpr -o cpi=17 filename ENTER</B>
+</PRE></UL>
+
+<P>The default characters per inch is 10.
+
+<H3>Setting the Number of Lines Per Inch</H3>
+
+<P>The <CODE>-o lpi=value</CODE> option sets the number of lines per inch:
+
+<UL><PRE>
+<B>lp -o lpi=6 filename ENTER</B>
+<B>lpr -o lpi=8 filename ENTER</B>
+</PRE></UL>
+
+<P>The default lines per inch is 6.
+
+<H3>Setting the Number of Columns</H3>
+
+<P>The <CODE>-o columns=value</CODE> option sets the number of text columns:
+
+<UL><PRE>
+<B>lp -o columns=2 filename ENTER</B>
+<B>lpr -o columns=3 filename ENTER</B>
+</PRE></UL>
+
+<P>The default number of columns is 1.
+
+<H3>Setting the Page Margins</H3>
+
+<P>Normally the page margins are set to the hard limits of the printer.
+Use the <CODE>-o page-left=value</CODE>, <CODE>-o
+page-right=value</CODE>, <CODE>-o page-top=value</CODE>, and <CODE>-o
+page-bottom=value</CODE> options to adjust the page margins:
+
+<UL><PRE>
+<B>lp -o page-left=<I>value</I> filename ENTER</B>
+<B>lp -o page-right=<I>value</I> filename ENTER</B>
+<B>lp -o page-top=<I>value</I> filename ENTER</B>
+<B>lp -o page-bottom=<I>value</I> filename ENTER</B>
+<B>lpr -o page-bottom=<I>value</I> filename ENTER</B>
+</PRE></UL>
+
+<P>The <CODE>value</CODE> argument is the margin in points; each point is 1/72 inch
+or 0.35mm.
+
+<H3>Pretty Printing</H3>
+
+<P>The <CODE>-o prettyprint</CODE> 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:
+
+<UL><PRE>
+<B>lp -o prettyprint filename ENTER</B>
+<B>lpr -o prettyprint filename ENTER</B>
+</PRE></UL>
+
+<H2>Image Options</H2>
+
+<P>The following options apply when printing image files.
+
+<H3>Positioning the Image</H3>
+
+<P>The <CODE>-o position=name</CODE> option specifies the position of the
+image on the page:
+
+<UL>
+
+ <LI><CODE>center</CODE> - Center the image on the page (default)
+
+ <LI><CODE>top</CODE> - Print the image centered at the top of the page
+
+ <LI><CODE>left</CODE> - Print the image centered on the left of page
+
+ <LI><CODE>right</CODE> - Print the image centered on the right of the page
+
+ <LI><CODE>top-left</CODE> - Print the image at the top left corner of
+ the page
+
+ <LI><CODE>top-right</CODE> - Print the image at the top right corner of
+ the page
+
+ <LI><CODE>bottom</CODE> - Print the image centered at the bottom of
+ the page
+
+ <LI><CODE>bottom-left</CODE> - Print the image at the bottom left
+ corner of the page
+
+ <LI><CODE>bottom-right</CODE> - Print the image at the bottom right
+ corner of the page
+
+</UL>
+
+<H3>Scaling the Image</H3>
+
+<P>The <CODE>-o scaling=percent</CODE>, <CODE>-o
+ppi=value</CODE>, and <CODE>-o natural-scaling=percent</CODE>
+options change the size of a printed image:
+
+<UL><PRE>
+<B>lp -o scaling=<I>percent</I> filename ENTER</B>
+<B>lp -o ppi=<I>value</I> filename ENTER</B>
+<B>lpr -o natural-scaling=<I>percent</I> filename ENTER</B>
+</PRE></UL>
+
+<P>The <CODE>scaling=percent</CODE> value is a number from 1 to 800
+specifying the size in relation to the page (<I>not</I> 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.
+
+<P>The <CODE>ppi=value</CODE> 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.
+
+<P>The <CODE>natural-scaling=percent</CODE> value is a number
+from 1 to 800 specifying the size in relation to the natural
+image size. A scaling of 100 percent will print the image at its
+natural size, while a scaling of 50 percent will print the image
+at half its natural size. If the specified scaling makes the
+image larger than the page, multiple pages will be printed to
+satisfy the request.
+
+<H3>Adjusting the Hue (Tint) of an Image</H3>
+
+<P>The <CODE>-o hue=value</CODE> option will adjust the hue of the
+printed image, much like the tint control on your television:
+
+<UL><PRE>
+<B>lp -o hue=<I>value</I> filename ENTER</B>
+<B>lpr -o hue=<I>value</I> filename ENTER</B>
+</PRE></UL>
+
+<!-- NEED 3in -->
+<P>The <CODE>value</CODE> 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:
+
+<CENTER><TABLE WIDTH="50%" BORDER="1">
+<TR>
+ <TH>Original</TH>
+ <TH>hue=-45</TH>
+ <TH>hue=45</TH>
+</TR>
+<TR>
+ <TD>Red</TD>
+ <TD>Purple</TD>
+ <TD>Yellow-orange</TD>
+</TR>
+<TR>
+ <TD>Green</TD>
+ <TD>Yellow-green</TD>
+ <TD>Blue-green</TD>
+</TR>
+<TR>
+ <TD>Yellow</TD>
+ <TD>Orange</TD>
+ <TD>Green-yellow</TD>
+</TR>
+<TR>
+ <TD>Blue</TD>
+ <TD>Sky-blue</TD>
+ <TD>Purple</TD>
+</TR>
+<TR>
+ <TD>Magenta</TD>
+ <TD>Indigo</TD>
+ <TD>Crimson</TD>
+</TR>
+<TR>
+ <TD>Cyan</TD>
+ <TD>Blue-green</TD>
+ <TD>Light-navy-blue</TD>
+</TR>
+</TABLE></CENTER>
+
+<P>The default hue adjustment is 0.
+
+<H3>Adjusting the Saturation (Color) of an Image</H3>
+
+<P>The <CODE>-o saturation=percent</CODE> option adjusts the saturation
+of the colors in an image, much like the color knob on your television:
+
+<UL><PRE>
+<B>lp -o saturation=<I>percent</I> filename ENTER</B>
+<B>lpr -o saturation=<I>percent</I> filename ENTER</B>
+</PRE></UL>
+
+<P>The <CODE>percent</CODE> 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.
+
+<P>The default saturation is 100.
+
+<!-- NEED 4in -->
+<H2>HP-GL/2 Options</H2>
+
+<P>The following options apply to HP-GL/2 files.
+
+<H3>Printing in Black</H3>
+
+<P>The <CODE>-o blackplot</CODE> option specifies that all pens should
+plot in black:
+
+<UL><PRE>
+<B>lp -o blackplot filename ENTER</B>
+<B>lpr -o blackplot filename ENTER</B>
+</PRE></UL>
+
+<P>The default is to use the colors defined in the plot file or the
+standard pen colors defined in the HP-GL/2 reference manual from
+Hewlett Packard.
+
+<H3>Fitting the Plot on the Page</H3>
+
+<P>The <CODE>-o fitplot</CODE> option specifies that the plot should be
+scaled to fit on the page:
+
+<UL><PRE>
+<B>lp -o fitplot filename ENTER</B>
+<B>lpr -o fitplot filename ENTER</B>
+</PRE></UL>
+
+<P>The default is to use the absolute distances specified in the plot
+file.
+
+<CENTER><TABLE WIDTH="80%" CELLPADDING="5" BORDER="1" BGCOLOR="#cccccc">
+<TR>
+ <TD>
+ <B>NOTE:</B>
+
+ <P>This feature depends upon an accurate plot size (<CODE>PS</CODE>)
+ command in the HP-GL/2 file. If no plot size is given in the file
+ than the HP-GL/2 filter assumes the plot is ANSI E size.
+ </TD>
+</TR>
+</TABLE></CENTER>
+
+<H3>Setting the Default Pen Width</H3>
+
+<P>The <CODE>-o penwidth=value</CODE> option specifies the default pen
+width for HP-GL/2 files:
+
+<UL><PRE>
+<B>lp -o penwidth=<I>value</I> filename ENTER</B>
+<B>lpr -o penwidth=<I>value</I> filename ENTER</B>
+</PRE></UL>
+
+<P>The pen width <CODE>value</CODE> specifies the pen width in micrometers.
+The default value of 1000 produces lines that are 1 millimeter in width.
+Specifying a pen width of 0 produces lines that are exactly 1 pixel wide.
+
+<CENTER><TABLE WIDTH="80%" CELLPADDING="5" BORDER="1" BGCOLOR="#cccccc">
+<TR>
+ <TD>
+ <B>NOTE:</B>
+
+ <P>This option is ignored when the pen widths are set in the
+ plot file.
+ </TD>
+</TR>
+</TABLE></CENTER>
+
+<H2>Raw or Unfiltered Output</H2>
+
+<P>The <CODE>-o raw</CODE> option allows you to send files directly to
+a printer without filtering. This is sometimes required when printing
+from applications that provide their own "printer drivers" for your
+printer:
+
+<UL><PRE>
+<B>lp -o raw filename ENTER</B>
+<B>lpr -o raw filename ENTER</B>
+</PRE></UL>
+
+<P>The <CODE>-l</CODE> option can also be used with the
+<CODE>lpr</CODE> command to send files directly to a printer:
+
+<UL><PRE>
+<B>lpr -l filename ENTER</B>
+</PRE></UL>
+
+
+<H1 ALIGN="RIGHT"><A NAME="SAVING_OPTIONS">4 - Saving Printer Options and Defaults</A></H1>
+
+<P>This chapter describes how to save printer options for your printer and
+set your own default printer.
+
+<H2>Printer Options</H2>
+
+<P>Each printer supports a large number of options, which you learned about
+in <A HREF="#STANDARD_OPTIONS">Chapter 3, "Standard Printer Options"</A>.
+Rather than specifying these options each time you print a file, CUPS allows
+you to save them as "default" options for the printer.
+
+<P>The <CODE>lpoptions(1)</CODE> command saves the options for your printers.
+Like the <CODE>lp</CODE> and <CODE>lpr</CODE> commands, it accepts printer
+options using the <CODE>-o</CODE> argument:
+
+<UL><PRE>
+<B>lpoptions -o media=A4 -o sides=two-sided-long-edge ENTER</B>
+<B>lpoptions -o media=Legal -o scaling=100 ENTER</B>
+</PRE></UL>
+
+<P>Once saved, any <CODE>lp</CODE> or <CODE>lpr</CODE> command will
+use them when you print.
+
+<H2>Setting Options for a Specific Printer</H2>
+
+<P>The previous example shows how to set the options for the default
+printer. The <CODE>-p printer</CODE> option specifies the options are
+for another printer:
+
+<UL><PRE>
+<B>lpoptions -p laserjet -o media=A4 -o sides=two-sided-long-edge ENTER</B>
+<B>lpoptions -p deskjet -o media=Legal -o scaling=100 ENTER</B>
+</PRE></UL>
+
+<H2>Viewing the Current Defaults</H2>
+
+<P>The <CODE>lpoptions</CODE> command can also be used to show the current
+options by not specifying any new options on the command-line:
+
+<UL><PRE>
+<B>lpoptions ENTER</B>
+media=A4 sides=two-sided-long-edge
+<B>lpoptions -p deskjet ENTER</B>
+media=Legal scaling=100
+</PRE></UL>
+
+<H2>Setting the Default Printer</H2>
+
+<P>The administrator normally will set a system-wide default printer
+that is normally used as the default printer by everyone. Use the
+<CODE>-d printer</CODE> option to set your own default printer:
+
+<UL><PRE>
+<B>lpoptions -d deskjet ENTER</B>
+</PRE></UL>
+
+<P>The printer can be local (<CODE>deskjet</CODE>) or remote
+(<CODE>deskjet@server</CODE>).
+
+<H2>Printer Instances</H2>
+
+<P>Besides setting options for each print queue, CUPS supports
+<I>printer instances</I> which allow you to define several different
+sets of options for each printer. You specify a printer instance using
+the slash (<CODE>/</CODE>) character:
+
+<UL><PRE>
+<B>lpoptions -p laserjet/duplex -o sides=two-sided-long-edge ENTER</B>
+<B>lpoptions -p laserjet/legal -o media=Legal ENTER</B>
+</PRE></UL>
+
+<P>The <CODE>lp</CODE> and </CODE>lpr</CODE> commands also understand
+this notation:
+
+<UL><PRE>
+<B>lp -d laserjet/duplex filename ENTER</B>
+<B>lpr -P laserjet/legal filename ENTER</B>
+</PRE></UL>
+
+<H2>Removing Instances</H2>
+
+<P>Use the <CODE>-x printer/instance</CODE> option to remove a printer
+instance that you no longer need:
+
+<UL><PRE>
+<B>lpoptions -x laserjet ENTER</B>
+<B>lpoptions -x laserjet/duplex ENTER</B>
+<B>lpoptions -x laserjet/legal ENTER</B>
+</PRE></UL>
+
+<P>The <CODE>-x</CODE> option only removes the default options for that
+printer and instance; the original print queue will remain until deleted
+with the <CODE>lpadmin(8)</CODE> command by the administrator.
+
+
+<H1 ALIGN="RIGHT"><A NAME="LICENSE">A - Software License
+Agreement</A></H1>
+
+<EMBED SRC="../LICENSE.html">
+
+</BODY>
+</HTML>
diff --git a/doc/svd.html b/doc/svd.html
new file mode 100644
index 000000000..cd672f2d5
--- /dev/null
+++ b/doc/svd.html
@@ -0,0 +1,296 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD>
+<TITLE>CUPS Software Version Description</TITLE>
+<META NAME="author" CONTENT="Easy Software Products">
+<META NAME="copyright" CONTENT="Copyright 1997-2002, All Rights Reserved">
+<META NAME="docnumber" CONTENT="CUPS-SVD-1.1">
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=iso-8859-1">
+<STYLE TYPE="text/css"><!--
+BODY { font-family: serif }
+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 }
+SUB { font-size: smaller }
+SUP { font-size: smaller }
+PRE { font-family: monospace }
+--></STYLE>
+</HEAD>
+<BODY>
+<CENTER><A HREF="#CONTENTS"><IMG SRC="images/cups-large.gif" BORDER="0" WIDTH="431" HEIGHT="511"><BR>
+<H1>CUPS Software Version Description</H1></A><BR>
+CUPS-SVD-1.1<BR>
+Easy Software Products<BR>
+Copyright 1997-2002, All Rights Reserved<BR>
+</CENTER>
+<HR>
+<H1 ALIGN="CENTER"><A NAME="CONTENTS">Table of Contents</A></H1>
+<BR>
+<BR><B><A HREF="#1">1 Scope</A></B>
+<UL>
+<LI><A HREF="#1_1">1.1 Identification</A></LI>
+<LI><A HREF="#1_2">1.2 System Overview</A></LI>
+<LI><A HREF="#1_3">1.3 Document Overview</A></LI>
+</UL>
+<B><A HREF="#2">2 References</A></B>
+<UL>
+<LI><A HREF="#2_1">2.1 CUPS Documentation</A></LI>
+<LI><A HREF="#2_2">2.2 Other Documents</A></LI>
+</UL>
+<B><A HREF="#3">3 Additions</A></B>
+<UL>
+<LI><A HREF="#3_1">3.1 Filters</A></LI>
+<UL>
+<LI><A HREF="#3_1_1">3.1.1 imagetoraster, imagetops</A></LI>
+<LI><A HREF="#3_1_2">3.1.2 pdftops</A></LI>
+<LI><A HREF="#3_1_3">3.1.3 pstoraster</A></LI>
+<LI><A HREF="#3_1_4">3.1.4 rastertoepson</A></LI>
+</UL>
+<LI><A HREF="#3_2">3.2 User-Defined Printers and Options</A></LI>
+<LI><A HREF="#3_3">3.3 Daemons</A></LI>
+<UL>
+<LI><A HREF="#3_3_1">3.3.1 cups-lpd</A></LI>
+<LI><A HREF="#3_3_2">3.3.2 cups-polld</A></LI>
+</UL>
+<LI><A HREF="#3_4">3.4 Commands</A></LI>
+<UL>
+<LI><A HREF="#3_4_1">3.4.1 lpoptions</A></LI>
+<LI><A HREF="#3_4_2">3.4.2 lpmove</A></LI>
+<LI><A HREF="#3_4_3">3.4.3 lpinfo</A></LI>
+</UL>
+<LI><A HREF="#3_5">3.5 IPP Implementation</A></LI>
+</UL>
+<B><A HREF="#4">4 Changes</A></B>
+<UL>
+<LI><A HREF="#4_1">4.1 Directory Structure</A></LI>
+<LI><A HREF="#4_2">4.2 IPP Implementation</A></LI>
+</UL>
+<B><A HREF="#5">A Glossary</A></B>
+<UL>
+<LI><A HREF="#5_1">A.1 Terms</A></LI>
+<LI><A HREF="#5_2">A.2 Acronyms</A></LI>
+</UL>
+<HR>
+<H1><A NAME="1">1 Scope</A></H1>
+<H2><A NAME="1_1">1.1 Identification</A></H2>
+ This software version description document provides release information
+ for the Common UNIX Printing System (&quot;CUPS&quot;) Version 1.1.
+<H2><A NAME="1_2">1.2 System Overview</A></H2>
+<P>CUPS provides a portable printing layer for UNIX&reg;-based operating
+ systems. It has been developed by<A HREF="http://www.easysw.com"> Easy
+ Software Products</A> to promote a standard printing solution for all
+ UNIX vendors and users. CUPS provides the System V and Berkeley
+ command-line interfaces.</P>
+<P>CUPS uses the Internet Printing Protocol (&quot;IPP&quot;) as the basis for
+ managing print jobs and queues. The Line Printer Daemon (&quot;LPD&quot;) Server
+ Message Block (&quot;SMB&quot;), and AppSocket (a.k.a. JetDirect) protocols are
+ also supported with reduced functionality. CUPS adds network printer
+ browsing and PostScript Printer Description (&quot;PPD&quot;) based printing
+ options to support real-world printing under UNIX.</P>
+<P>CUPS also includes a customized version of GNU Ghostscript (currently
+ based off GNU Ghostscript 5.50) and an image file RIP that are used to
+ support non-PostScript printers. Sample drivers for HP and EPSON
+ printers are included that use these filters.</P>
+<H2><A NAME="1_3">1.3 Document Overview</A></H2>
+<P>This software version description document is organized into the
+ following sections:</P>
+<UL>
+<LI><A HREF="#1">1 - Scope</A></LI>
+<LI><A HREF="#2">2 - References</A></LI>
+<LI><A HREF="#3">3 - Additions</A></LI>
+<LI><A HREF="#4">4 - Changes</A></LI>
+<LI><A HREF="#5">A - Glossary</A></LI>
+</UL>
+<H1><A NAME="2">2 References</A></H1>
+<H2><A NAME="2_1">2.1 CUPS Documentation</A></H2>
+<P>The following CUPS documentation is referenced by this document:</P>
+<UL>
+<LI>CUPS-CMP-1.1: CUPS Configuration Management Plan</LI>
+<LI>CUPS-IDD-1.1: CUPS System Interface Design Description</LI>
+<LI>CUPS-IPP-1.1: CUPS Implementation of IPP</LI>
+<LI>CUPS-SAM-1.1.x: CUPS Software Administrators Manual</LI>
+<LI>CUPS-SDD-1.1: CUPS Software Design Description</LI>
+<LI>CUPS-SPM-1.1.x: CUPS Software Programming Manual</LI>
+<LI>CUPS-SSR-1.1: CUPS Software Security Report</LI>
+<LI>CUPS-STP-1.1: CUPS Software Test Plan</LI>
+<LI>CUPS-SUM-1.1.x: CUPS Software Users Manual</LI>
+<LI>CUPS-SVD-1.1: CUPS Software Version Description</LI>
+</UL>
+<H2><A NAME="2_2">2.2 Other Documents</A></H2>
+<P>The following non-CUPS documents are referenced by this document:</P>
+<UL>
+<LI><A HREF="http://partners.adobe.com/asn/developer/PDFS/TN/5003.PPD_Spec_v4.3.pdf">
+Adobe PostScript Printer Description File Format Specification, Version
+ 4.3.</A></LI>
+<LI><A HREF="http://partners.adobe.com/asn/developer/PDFS/TN/PLRM.pdf">
+Adobe PostScript Language Reference, Third Edition.</A></LI>
+<LI>IPP: Job and Printer Set Operations</LI>
+<LI>IPP/1.1: Encoding and Transport</LI>
+<LI>IPP/1.1: Implementers Guide</LI>
+<LI>IPP/1.1: Model and Semantics</LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc1179.txt">RFC 1179, Line Printer
+ Daemon Protocol</A></LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc2567.txt">RFC 2567, Design Goals
+ for an Internet Printing Protocol</A></LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc2568.txt">RFC 2568, Rationale
+ for the Structure of the Model and Protocol</A> for the Internet
+ Printing Protocol</LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc2569.txt">RFC 2569, Mapping
+ between LPD and IPP Protocols</A></LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616, Hypertext
+ Transfer Protocol -- HTTP/1.1</A></LI>
+<LI><A HREF="http://www.ietf.org/rfc/rfc2617.txt">RFC 2617, HTTP
+ Authentication: Basic and Digest Access</A> Authentication</LI>
+</UL>
+<H1><A NAME="3">3 Additions</A></H1>
+<P>CUPS 1.1 includes many new features from the 1.0.x releases.</P>
+<H2><A NAME="3_1">3.1 Filters</A></H2>
+<H3><A NAME="3_1_1">3.1.1 <CODE>imagetoraster</CODE>, <CODE>imagetops</CODE>
+</A></H3>
+<P>The image file filters have been upgraded to support conversion of
+ Microsoft Bitmap (&quot;BMP&quot;) and Alias PIX files.</P>
+<H3><A NAME="3_1_2">3.1.2 pdftops</A></H3>
+<P>A new pdftops filter has been developed that is based on the
+ excellent Xpdf 0.90 software from Derek B. Noonburg. The new filter is
+ faster, smaller, and considerably more reliable than the
+ Ghostscript-based filter in CUPS 1.0.</P>
+<H3><A NAME="3_1_3">3.1.3 pstoraster</A></H3>
+<P>The <CODE>pstoraster</CODE> filter has been integrated with GNU
+ GhostScript 5.50. The new RIP supports most Level 3 PostScript language
+ features.</P>
+<H3><A NAME="3_1_4">3.1.4 rastertoepson</A></H3>
+<P>The new <CODE>rastertoepson</CODE> filter supports EPSON printers
+ using the ESC/P or ESC/P2 command sets. PPDs are supplied for 9-pin,
+ 24-pin, Stylus Color, and Stylus Photo printers.</P>
+<H2><A NAME="3_2">3.2 User-Defined Printers and Options</A></H2>
+<P>The new <CODE>lpoptions</CODE> command allows users to configure
+ default document options and create additional &quot;instances&quot; of existing
+ printers, each with unique options.</P>
+<P>The <CODE>lp</CODE>, <CODE>lpr</CODE>, and <CODE>lpstat</CODE>
+ commands have been upgraded to use this option and printer instance
+ information automatically.</P>
+<H2><A NAME="3_3">3.3 Daemons</A></H2>
+<P>CUPS 1.1 includes two new daemons that provide enhanced network
+ printing support.</P>
+<H3><A NAME="3_3_1">3.3.1 cups-lpd</A></H3>
+<P>The <CODE>cups-lpd</CODE> daemon provides support for clients using
+ the Line Printer Daemon protocol.</P>
+<H3><A NAME="3_3_2">3.3.2 cups-polld</A></H3>
+<P>The <CODE>cups-polld</CODE> daemon provides remote polling services
+ for the scheduler.</P>
+<H2><A NAME="3_4">3.4 Commands</A></H2>
+<P>CUPS 1.1 includes several new printing commands.</P>
+<H3><A NAME="3_4_1">3.4.1 lpoptions</A></H3>
+<P>The <CODE>lpoptions</CODE> command provides user-defined printers and
+ options.</P>
+<H3><A NAME="3_4_2">3.4.2 lpmove</A></H3>
+<P>The <CODE>lpmove</CODE> command moves a print job to a new
+ destination.</P>
+<H3><A NAME="3_4_3">3.4.3 lpinfo</A></H3>
+<P>The <CODE>lpinfo</CODE> command lists the available PPD files or
+ devices.</P>
+<H2><A NAME="3_5">3.5 IPP Implementation</A></H2>
+<P>CUPS 1.1 adds support for the <CODE>set-job-attributes</CODE>
+ extension operation as well as two new CUPS-specific extension
+ operations to determine which devices and printer drivers are available
+ on the system.</P>
+<P>Further information on the CUPS implementation of IPP can be found in
+ CUPS-IPP-1.1.</P>
+<H1><A NAME="4">4 Changes</A></H1>
+<P>CUPS 1.1 includes many changes from the 1.0.x releases.</P>
+<H2><A NAME="4_1">4.1 Directory Structure</A></H2>
+<P>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.
+<CENTER>
+<TABLE BORDER WIDTH="80%"><CAPTION> Table 1: Directory structure changes
+ from CUPS 1.0.x to 1.1.x.</CAPTION>
+<TR><TH>Description</TH><TH>CUPS 1.0.x</TH><TH>CUPS 1.1.x</TH></TR>
+<TR><TD>Backends</TD><TD>/var/cups/backend</TD><TD>/usr/lib/cups/backend</TD>
+</TR>
+<TR><TD>CGI programs</TD><TD>/var/cups/cgi-bin</TD><TD>
+/usr/lib/cups/cgi-bin</TD></TR>
+<TR><TD>Configuration files</TD><TD>/var/cups/conf</TD><TD>/etc/cups</TD>
+</TR>
+<TR><TD>Documentation</TD><TD>/usr/share/cups/doc</TD><TD>
+/usr/share/doc/cups</TD></TR>
+<TR><TD>Filter programs</TD><TD>/var/cups/filter</TD><TD>
+/usr/lib/cups/filter</TD></TR>
+<TR><TD>Interface scripts</TD><TD>/var/cups/interfaces</TD><TD>
+/etc/cups/interfaces</TD></TR>
+<TR><TD>Locale data</TD><TD>/usr/lib/locale</TD><TD>/usr/share/locale</TD>
+</TR>
+<TR><TD>Log files</TD><TD>/var/cups/logs</TD><TD>/var/log/cups</TD></TR>
+<TR><TD>PPD files</TD><TD>/var/cups/ppd</TD><TD>/etc/cups/ppd</TD></TR>
+<TR><TD>Request files</TD><TD>/var/cups/requests</TD><TD>/var/spool/cups</TD>
+</TR>
+</TABLE>
+</CENTER>
+</P>
+<H2><A NAME="4_2">4.2 IPP Implementation</A></H2>
+<P>CUPS 1.1 is based on version 1.1 of the Internet Printing Protocol.</P>
+<P>The new scheduler supports the <CODE>create-job</CODE> and <CODE>
+send-document</CODE> operations. In addition, the <CODE>job-sheets</CODE>
+, <CODE>job-sheets-default</CODE>, and <CODE>job-sheets-supported</CODE>
+ attributes are now supported for banner pages.</P>
+<P>The <CODE>CUPS-get-printers</CODE> and <CODE>CUPS-get-classes</CODE>
+ operations have been upgraded to support limited filtering based upon
+ the <CODE>printer-type</CODE>, <CODE>printer-location</CODE>, <CODE>
+printer-info</CODE>, and <CODE>printer-make-and-model</CODE> attributes.</P>
+<P>The <CODE>CUPS-add-printer</CODE> operation now supports the <CODE>
+ppd-name</CODE> attribute to specify a locally-available PPD file rather
+ than sending the PPD file from the client with the request.</P>
+<P>Further information on the CUPS implementation of IPP can be found in
+ CUPS-IPP-1.1.</P>
+<H1 TYPE="A" VALUE="1"><A NAME="5">A Glossary</A></H1>
+<H2><A NAME="5_1">A.1 Terms</A></H2>
+<DL>
+<DT>C</DT>
+<DD>A computer language.</DD>
+<DT>parallel</DT>
+<DD>Sending or receiving data more than 1 bit at a time.</DD>
+<DT>pipe</DT>
+<DD>A one-way communications channel between two programs.</DD>
+<DT>serial</DT>
+<DD>Sending or receiving data 1 bit at a time.</DD>
+<DT>socket</DT>
+<DD>A two-way network communications channel.</DD>
+</DL>
+<H2><A NAME="5_2">A.2 Acronyms</A></H2>
+<DL>
+<DT>ASCII</DT>
+<DD>American Standard Code for Information Interchange</DD>
+<DT>CUPS</DT>
+<DD>Common UNIX Printing System</DD>
+<DT>ESC/P</DT>
+<DD>EPSON Standard Code for Printers</DD>
+<DT>FTP</DT>
+<DD>File Transfer Protocol</DD>
+<DT>HP-GL</DT>
+<DD>Hewlett-Packard Graphics Language</DD>
+<DT>HP-PCL</DT>
+<DD>Hewlett-Packard Page Control Language</DD>
+<DT>HP-PJL</DT>
+<DD>Hewlett-Packard Printer Job Language</DD>
+<DT>IETF</DT>
+<DD>Internet Engineering Task Force</DD>
+<DT>IPP</DT>
+<DD>Internet Printing Protocol</DD>
+<DT>ISO</DT>
+<DD>International Standards Organization</DD>
+<DT>LPD</DT>
+<DD>Line Printer Daemon</DD>
+<DT>MIME</DT>
+<DD>Multimedia Internet Mail Exchange</DD>
+<DT>PPD</DT>
+<DD>PostScript Printer Description</DD>
+<DT>SMB</DT>
+<DD>Server Message Block</DD>
+<DT>TFTP</DT>
+<DD>Trivial File Transfer Protocol</DD>
+</DL>
+</BODY>
+</HTML>
diff --git a/doc/svd.pdf b/doc/svd.pdf
new file mode 100644
index 000000000..6642960f0
--- /dev/null
+++ b/doc/svd.pdf
Binary files differ
diff --git a/doc/svd.shtml b/doc/svd.shtml
new file mode 100644
index 000000000..b536bb200
--- /dev/null
+++ b/doc/svd.shtml
@@ -0,0 +1,212 @@
+<HTML>
+<HEAD>
+ <META NAME="COPYRIGHT" CONTENT="Copyright 1997-2002, All Rights Reserved">
+ <META NAME="DOCNUMBER" CONTENT="CUPS-SVD-1.1">
+ <META NAME="Author" CONTENT="Easy Software Products">
+ <TITLE>CUPS Software Version Description</TITLE>
+</HEAD>
+<BODY>
+
+<H1>Scope</H1>
+
+<H2>Identification</H2>
+
+This software version description document provides release information for the
+Common UNIX Printing System ("CUPS") Version 1.1.
+
+<EMBED SRC="system-overview.shtml">
+
+<H2>Document Overview</H2>
+
+<P>This software version description document is organized into the following
+sections:</P>
+
+<UL>
+ <LI><A HREF="#1">1 - Scope</A></LI>
+ <LI><A HREF="#2">2 - References</A></LI>
+ <LI><A HREF="#3">3 - Additions</A></LI>
+ <LI><A HREF="#4">4 - Changes</A></LI>
+ <LI><A HREF="#5">A - Glossary</A></LI>
+</UL>
+
+<EMBED SRC="references.shtml">
+
+<H1>Additions</H1>
+
+<P>CUPS 1.1 includes many new features from the 1.0.x releases.
+
+<H2>Filters</H2>
+
+<H3><CODE>imagetoraster</CODE>, <CODE>imagetops</CODE></H3>
+
+<P>The image file filters have been upgraded to support conversion of
+Microsoft Bitmap ("BMP") and Alias PIX files.
+
+<H3>pdftops</H3>
+
+<P>A new pdftops filter has been developed that is based on the
+excellent Xpdf 0.90 software from Derek B. Noonburg. The new filter is
+faster, smaller, and considerably more reliable than the
+Ghostscript-based filter in CUPS 1.0.
+
+<H3>pstoraster</H3>
+
+<P>The <CODE>pstoraster</CODE> filter has been integrated with GNU
+GhostScript 5.50. The new RIP supports most Level 3 PostScript language
+features.
+
+<H3>rastertoepson</H3>
+
+<P>The new <CODE>rastertoepson</CODE> filter supports EPSON printers
+using the ESC/P or ESC/P2 command sets. PPDs are supplied for 9-pin,
+24-pin, Stylus Color, and Stylus Photo printers.
+
+<H2>User-Defined Printers and Options</H2>
+
+<P>The new <CODE>lpoptions</CODE> command allows users to configure default
+document options and create additional "instances" of existing printers,
+each with unique options.
+
+<P>The <CODE>lp</CODE>, <CODE>lpr</CODE>, and <CODE>lpstat</CODE> commands
+have been upgraded to use this option and printer instance information
+automatically.
+
+<H2>Daemons</H2>
+
+<P>CUPS 1.1 includes two new daemons that provide enhanced network printing
+support.
+
+<H3>cups-lpd</H3>
+
+<P>The <CODE>cups-lpd</CODE> daemon provides support for clients using the
+Line Printer Daemon protocol.
+
+<H3>cups-polld</H3>
+
+<P>The <CODE>cups-polld</CODE> daemon provides remote polling services for
+the scheduler.
+
+<H2>Commands</H2>
+
+<P>CUPS 1.1 includes several new printing commands.
+
+<H3>lpoptions</H3>
+
+<P>The <CODE>lpoptions</CODE> command provides user-defined printers and
+options.
+
+<H3>lpmove</H3>
+
+<P>The <CODE>lpmove</CODE> command moves a print job to a new destination.
+
+<H3>lpinfo</H3>
+
+<P>The <CODE>lpinfo</CODE> command lists the available PPD files or devices.
+
+<H2>IPP Implementation</H2>
+
+<P>CUPS 1.1 adds support for the <CODE>set-job-attributes</CODE>
+extension operation as well as two new CUPS-specific extension
+operations to determine which devices and printer drivers are available
+on the system.
+
+<P>Further information on the CUPS implementation of IPP can be found
+in CUPS-IPP-1.1.
+
+
+<H1>Changes</H1>
+
+<P>CUPS 1.1 includes many changes from the 1.0.x releases.
+
+<H2>Directory Structure</H2>
+
+<P>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.
+
+<CENTER><TABLE WIDTH="80%" BORDER>
+<CAPTION>Table 1: Directory structure changes from CUPS 1.0.x to 1.1.x.</CAPTION>
+<TR>
+ <TH>Description</TH>
+ <TH>CUPS 1.0.x</TH>
+ <TH>CUPS 1.1.x</TH>
+</TR>
+<TR>
+ <TD>Backends</TD>
+ <TD>/var/cups/backend</TD>
+ <TD>/usr/lib/cups/backend</TD>
+</TR>
+<TR>
+ <TD>CGI programs</TD>
+ <TD>/var/cups/cgi-bin</TD>
+ <TD>/usr/lib/cups/cgi-bin</TD>
+</TR>
+<TR>
+ <TD>Configuration files</TD>
+ <TD>/var/cups/conf</TD>
+ <TD>/etc/cups</TD>
+</TR>
+<TR>
+ <TD>Documentation</TD>
+ <TD>/usr/share/cups/doc</TD>
+ <TD>/usr/share/doc/cups</TD>
+</TR>
+<TR>
+ <TD>Filter programs</TD>
+ <TD>/var/cups/filter</TD>
+ <TD>/usr/lib/cups/filter</TD>
+</TR>
+<TR>
+ <TD>Interface scripts</TD>
+ <TD>/var/cups/interfaces</TD>
+ <TD>/etc/cups/interfaces</TD>
+</TR>
+<TR>
+ <TD>Locale data</TD>
+ <TD>/usr/lib/locale</TD>
+ <TD>/usr/share/locale</TD>
+</TR>
+<TR>
+ <TD>Log files</TD>
+ <TD>/var/cups/logs</TD>
+ <TD>/var/log/cups</TD>
+</TR>
+<TR>
+ <TD>PPD files</TD>
+ <TD>/var/cups/ppd</TD>
+ <TD>/etc/cups/ppd</TD>
+</TR>
+<TR>
+ <TD>Request files</TD>
+ <TD>/var/cups/requests</TD>
+ <TD>/var/spool/cups</TD>
+</TR>
+</TABLE></CENTER>
+
+<H2>IPP Implementation</H2>
+
+<P>CUPS 1.1 is based on version 1.1 of the Internet Printing Protocol.
+
+<P>The new scheduler supports the <CODE>create-job</CODE> and
+<CODE>send-document</CODE> operations. In addition, the
+<CODE>job-sheets</CODE>, <CODE>job-sheets-default</CODE>, and
+<CODE>job-sheets-supported</CODE> attributes are now supported for
+banner pages.
+
+<P>The <CODE>CUPS-get-printers</CODE> and <CODE>CUPS-get-classes</CODE>
+operations have been upgraded to support limited filtering based upon
+the <CODE>printer-type</CODE>, <CODE>printer-location</CODE>,
+<CODE>printer-info</CODE>, and <CODE>printer-make-and-model</CODE>
+attributes.
+
+<P>The <CODE>CUPS-add-printer</CODE> operation now supports the
+<CODE>ppd-name</CODE> attribute to specify a locally-available PPD file
+rather than sending the PPD file from the client with the request.
+
+<P>Further information on the CUPS implementation of IPP can be found
+in CUPS-IPP-1.1.
+
+<EMBED SRC="glossary.shtml">
+
+</BODY>
+</HTML>
diff --git a/doc/system-overview.shtml b/doc/system-overview.shtml
new file mode 100644
index 000000000..54b7df5e9
--- /dev/null
+++ b/doc/system-overview.shtml
@@ -0,0 +1,19 @@
+<H2>System Overview</H2>
+
+<P>CUPS provides a portable printing layer for UNIX&reg;-based
+operating systems. It has been developed by
+<A HREF="http://www.easysw.com">Easy Software Products</A> to promote a
+standard printing solution for all UNIX vendors and users. CUPS
+provides the System V and Berkeley command-line interfaces.
+
+<P>CUPS uses the Internet Printing Protocol ("IPP") as the basis for
+managing print jobs and queues. The Line Printer Daemon ("LPD") Server
+Message Block ("SMB"), and AppSocket (a.k.a. JetDirect) protocols are
+also supported with reduced functionality. CUPS adds network printer
+browsing and PostScript Printer Description ("PPD") based
+printing options to support real-world printing under UNIX.
+
+<P>CUPS also includes a customized version of GNU Ghostscript
+(currently based off GNU Ghostscript 5.50) and an image file RIP that
+are used to support non-PostScript printers. Sample drivers for HP and
+EPSON printers are included that use these filters.
diff --git a/filter/.cvsignore b/filter/.cvsignore
new file mode 100644
index 000000000..28ffe6753
--- /dev/null
+++ b/filter/.cvsignore
@@ -0,0 +1,13 @@
+hpgltops
+imagetops
+imagetoraster
+libcupsimage.a
+libcupsimage.dylib.2
+libcupsimage.sl.2
+libcupsimage.so.2
+libcupsimage_s.a
+pstops
+rastertodymo
+rastertoepson
+rastertohp
+texttops
diff --git a/filter/Makefile b/filter/Makefile
new file mode 100644
index 000000000..c3f0cbc05
--- /dev/null
+++ b/filter/Makefile
@@ -0,0 +1,246 @@
+#
+# "$Id$"
+#
+# Filter makefile for the Common UNIX Printing System (CUPS).
+#
+# Copyright 1997-2002 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 \
+ rastertodymo rastertoepson rastertohp
+
+HPGLOBJS = hpgl-attr.o hpgl-config.o hpgl-main.o hpgl-prolog.o \
+ hpgl-char.o hpgl-input.o hpgl-polygon.o hpgl-vector.o
+IMAGEOBJS = image-bmp.o image-colorspace.o image-gif.o image-jpeg.o \
+ image-photocd.o image-pix.o image-png.o image-pnm.o \
+ image-sgi.o image-sgilib.o image-sun.o image-tiff.o \
+ image-zoom.o image.o raster.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 \
+ rastertodymo.o rastertoepson.o rastertohp.o texttops.o \
+ textcommon.o
+
+#
+# Make all targets...
+#
+
+all: $(TARGETS)
+
+
+#
+# Clean all object files...
+#
+
+clean:
+ $(RM) $(OBJS) $(TARGETS) $(LIBCUPSIMAGE) `basename $(LIBCUPSIMAGE) .2`
+
+
+#
+# Install all targets...
+#
+
+install:
+ $(INSTALL_DIR) $(SERVERBIN)/filter
+ for file in $(TARGETS); do \
+ $(INSTALL_BIN) $$file $(SERVERBIN)/filter; \
+ done
+ $(INSTALL_DIR) $(LIBDIR)
+ $(INSTALL_LIB) $(LIBCUPSIMAGE) $(LIBDIR)
+ -if test $(LIBCUPSIMAGE) = "libcupsimage.so.2" -o $(LIBCUPSIMAGE) = "libcupsimage.sl.2"; then \
+ $(RM) $(LIBDIR)/`basename $(LIBCUPSIMAGE) .2`; \
+ $(LN) $(LIBCUPSIMAGE) $(LIBDIR)/`basename $(LIBCUPSIMAGE) .2`; \
+ fi
+ -if test $(LIBCUPSIMAGE) = "libcupsimage.2.dylib"; then \
+ $(RM) $(LIBDIR)/libcupsimage.dylib; \
+ $(LN) $(LIBCUPSIMAGE) $(LIBDIR)/libcupsimage.dylib; \
+ fi
+ $(INSTALL_DIR) $(INCLUDEDIR)/cups
+ $(INSTALL_DATA) image.h $(INCLUDEDIR)/cups
+ $(INSTALL_DATA) raster.h $(INCLUDEDIR)/cups
+
+
+#
+# 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) ../Makedefs
+ echo Linking $@...
+ $(DSO) $(DSOFLAGS) -o $@ $(IMAGEOBJS) $(DSOLIBS) -lm
+ $(RM) `basename $@ .2`
+ $(LN) $@ `basename $@ .2`
+
+
+#
+# libcupsimage.2.dylib
+#
+
+libcupsimage.2.dylib: $(IMAGEOBJS) ../Makedefs
+ echo Linking $@...
+ $(DSO) $(DSOFLAGS) -o $@ \
+ -dylib_install_name $(LIBDIR)/libcupsimage.dylib \
+ -dylib_current_version 2.0.0 \
+ -dylib_compatibility_version 2.0.0 \
+ $(IMAGEOBJS) $(DSOLIBS) $(LINKCUPS) -lm -lcc_dynamic
+ $(RM) libcupsimage.dylib
+ $(LN) $@ libcupsimage.dylib
+
+
+#
+# libcupsimage_s.a
+#
+
+libcupsimage_s.a: $(IMAGEOBJS) ../Makedefs
+ echo Linking $@...
+ $(DSO) $(DSOFLAGS) -o libcupsimage_s.o $(IMAGEOBJS) $(DSOLIBS) \
+ $(LINKCUPS) -lm
+ $(RM) $@
+ $(AR) $(ARFLAGS) $@ libcupsimage_s.o
+
+
+#
+# libcupsimage.la
+#
+
+libcupsimage.la: $(IMAGEOBJS) ../Makedefs
+ echo Linking $@...
+ $(DSO) -o $(DSOFLAGS) $@ $(IMAGEOBJS:.o=.lo) $(DSOLIBS) \
+ -rpath $(LIBDIR) -version-info 2:0
+
+
+#
+# libcupsimage.a
+#
+
+libcupsimage.a: $(IMAGEOBJS) ../Makedefs
+ echo Archiving $@...
+ $(RM) $@
+ $(AR) $(ARFLAGS) $@ $(IMAGEOBJS)
+ $(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 $(LINKCUPSIMAGE) \
+ $(IMGLIBS) $(LIBS)
+imagetops.o: common.h image.h
+
+
+#
+# imagetoraster
+#
+
+imagetoraster: imagetoraster.o common.o $(LIBCUPSIMAGE) ../Makedefs \
+ ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ imagetoraster.o common.o $(LINKCUPSIMAGE) \
+ $(IMGLIBS) $(LIBS)
+imagetoraster.o: 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
+
+
+#
+# rastertodymo
+#
+
+rastertodymo: rastertodymo.o ../Makedefs ../cups/$(LIBCUPS) $(LIBCUPSIMAGE)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ rastertodymo.o $(LINKCUPSIMAGE) $(IMGLIBS) $(LIBS)
+rastertodymo.o: raster.h
+
+
+#
+# rastertoepson
+#
+
+rastertoepson: rastertoepson.o ../Makedefs ../cups/$(LIBCUPS) $(LIBCUPSIMAGE)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ rastertoepson.o $(LINKCUPSIMAGE) $(IMGLIBS) $(LIBS)
+rastertoepson.o: raster.h
+
+
+#
+# rastertohp
+#
+
+rastertohp: rastertohp.o ../Makedefs ../cups/$(LIBCUPS) $(LIBCUPSIMAGE)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ rastertohp.o $(LINKCUPSIMAGE) $(IMGLIBS) $(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 000000000..e80f3b059
--- /dev/null
+++ b/filter/common.c
@@ -0,0 +1,400 @@
+/*
+ * "$Id$"
+ *
+ * Common filter routines for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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.
+ * UpdatePageVars() - Update the page variables for the orientation.
+ * WriteLabelProlog() - Write the prolog with the classification
+ * and page label.
+ * WriteLabels() - Write the actual page labels.
+ */
+
+/*
+ * 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? */
+{
+ 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 & 3)
+ {
+ 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 & 3)
+ {
+ 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 & 3)
+ {
+ case 0 :
+ PageBottom = (float)atof(val);
+ break;
+ case 1 :
+ PageLeft = (float)atof(val);
+ break;
+ case 2 :
+ PageTop = PageLength - (float)atof(val);
+ break;
+ case 3 :
+ PageRight = PageWidth - (float)atof(val);
+ break;
+ }
+ }
+
+ if ((val = cupsGetOption("page-top", num_options, options)) != NULL)
+ {
+ switch (Orientation & 3)
+ {
+ case 0 :
+ PageTop = PageLength - (float)atof(val);
+ break;
+ case 1 :
+ PageRight = PageWidth - (float)atof(val);
+ break;
+ case 2 :
+ PageBottom = (float)atof(val);
+ break;
+ case 3 :
+ PageLeft = (float)atof(val);
+ break;
+ }
+ }
+
+ if (change_size)
+ UpdatePageVars();
+
+ 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);
+}
+
+
+/*
+ * 'UpdatePageVars()' - Update the page variables for the orientation.
+ */
+
+void
+UpdatePageVars(void)
+{
+ float temp; /* Swapping variable */
+
+
+ switch (Orientation & 3)
+ {
+ 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;
+ }
+}
+
+
+/*
+ * 'WriteLabelProlog()' - Write the prolog with the classification
+ * and page label.
+ */
+
+void
+WriteLabelProlog(const char *label, /* I - Page label */
+ float bottom, /* I - Bottom position in points */
+ float top, /* I - Top position in points */
+ float width) /* I - Width in points */
+{
+ const char *classification; /* CLASSIFICATION environment variable */
+
+
+ /*
+ * First get the current classification...
+ */
+
+ if ((classification = getenv("CLASSIFICATION")) == NULL)
+ classification = "";
+ if (strcmp(classification, "none") == 0)
+ classification = "";
+
+ /*
+ * If there is nothing to show, bind an empty 'write labels' procedure
+ * and return...
+ */
+
+ if (!classification[0] && (label == NULL || !label[0]))
+ {
+ puts("/espWL{}bind def");
+ return;
+ }
+
+ /*
+ * Set the classification + page label string...
+ */
+
+ if (strcmp(classification, "confidential") == 0)
+ printf("/espPL(CONFIDENTIAL");
+ else if (strcmp(classification, "classified") == 0)
+ printf("/espPL(CLASSIFIED");
+ else if (strcmp(classification, "secret") == 0)
+ printf("/espPL(SECRET");
+ else if (strcmp(classification, "topsecret") == 0)
+ printf("/espPL(TOP SECRET");
+ else if (strcmp(classification, "unclassified") == 0)
+ printf("/espPL(UNCLASSIFIED");
+ else
+ printf("/espPL(");
+
+ if (classification[0] && label)
+ printf(" - %s)def\n", label);
+ else if (label)
+ printf("%s)def\n", label);
+ else
+ puts(")def");
+
+ /*
+ * Then get a 14 point Helvetica-Bold font...
+ */
+
+ puts("/espPF /Helvetica-Bold findfont 14 scalefont def");
+
+ /*
+ * Finally, the procedure to write the labels on the page...
+ */
+
+ puts("/espWL{");
+ puts(" espPF setfont");
+ printf(" espPL stringwidth pop dup 12 add exch -0.5 mul %.0f add\n",
+ width * 0.5f);
+ puts(" 1 setgray");
+ printf(" dup 6 sub %.0f 3 index 20 rectfill\n", bottom - 2.0);
+ printf(" dup 6 sub %.0f 3 index 20 rectfill\n", top - 18.0);
+ puts(" 0 setgray");
+ printf(" dup 6 sub %.0f 3 index 20 rectstroke\n", bottom - 2.0);
+ printf(" dup 6 sub %.0f 3 index 20 rectstroke\n", top - 18.0);
+ printf(" dup %.0f moveto espPL show\n", bottom + 2.0);
+ printf(" %.0f moveto espPL show\n", top - 14.0);
+ puts("pop");
+ puts("}bind def");
+}
+
+
+/*
+ * 'WriteLabels()' - Write the actual page labels.
+ */
+
+void
+WriteLabels(int orient) /* I - Orientation of the page */
+{
+ float width, /* Width of page */
+ length; /* Length of page */
+
+
+ puts("gsave");
+
+ if ((orient ^ Orientation) & 1)
+ {
+ width = PageLength;
+ length = PageWidth;
+ }
+ else
+ {
+ width = PageWidth;
+ length = PageLength;
+ }
+
+ switch (orient & 3)
+ {
+ case 1 : /* Landscape */
+ printf("%.1f 0.0 translate 90 rotate\n", length);
+ break;
+ case 2 : /* Reverse Portrait */
+ printf("%.1f %.1f translate 180 rotate\n", width, length);
+ break;
+ case 3 : /* Reverse Landscape */
+ printf("0.0 %.1f translate -90 rotate\n", width);
+ break;
+ }
+
+ puts("espWL");
+ puts("grestore");
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/common.h b/filter/common.h
new file mode 100644
index 000000000..552fefea9
--- /dev/null
+++ b/filter/common.h
@@ -0,0 +1,71 @@
+/*
+ * "$Id$"
+ *
+ * Common filter definitions for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <time.h>
+
+#include <cups/cups.h>
+#include <cups/language.h>
+#include <cups/string.h>
+
+
+/*
+ * 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);
+extern void UpdatePageVars(void);
+extern void WriteLabelProlog(const char *label, float bottom,
+ float top, float width);
+extern void WriteLabels(int orient);
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/form-main.c b/filter/form-main.c
new file mode 100644
index 000000000..f0db7733e
--- /dev/null
+++ b/filter/form-main.c
@@ -0,0 +1,60 @@
+/*
+ * "$Id$"
+ *
+ * CUPS form main entry for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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() - Load the specified form file and output PostScript.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "form.h"
+
+
+/*
+ * Globals...
+ */
+
+int NumOptions; /* Number of command-line options */
+cups_option_t *Options; /* Command-line options */
+ppd_file_t *PPD; /* PPD file */
+
+
+/*
+ * 'main()' - Load the specified form file and output PostScript.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+
+ return (0);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/form-ps.c b/filter/form-ps.c
new file mode 100644
index 000000000..770582e2b
--- /dev/null
+++ b/filter/form-ps.c
@@ -0,0 +1,47 @@
+/*
+ * "$Id$"
+ *
+ * CUPS form PostScript routines for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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"
+
+
+/*
+ * 'formWrite()' - Write PostScript output for the given form document.
+ */
+
+void
+formWrite(tree_t *t) /* I - Document tree to write */
+{
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/form-tree.c b/filter/form-tree.c
new file mode 100644
index 000000000..86ba9c068
--- /dev/null
+++ b/filter/form-tree.c
@@ -0,0 +1,622 @@
+/*
+ * "$Id$"
+ *
+ * CUPS form document tree routines for the Common UNIX Printing
+ * System (CUPS).
+ *
+ * Copyright 1997-2002 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"
+
+
+/*
+ * Local functions...
+ */
+
+static int compare_attr(attr_t *a0, attr_t *a1);
+static int compare_elements(char **e0, char **e1);
+static int parse_attr(tree_t *t, FILE *fp);
+static int parse_element(tree_t *t, FILE *fp);
+
+
+/*
+ * Local globals...
+ */
+
+static char *elements[] =
+ {
+ "",
+ "!--",
+ "ARC",
+ "BOX",
+ "BR",
+ "B",
+ "CUPSFORM",
+ "DEFVAR",
+ "FONT",
+ "H1",
+ "H2",
+ "H3",
+ "H4",
+ "H5",
+ "H6",
+ "HEAD",
+ "IMG",
+ "I",
+ "LINE",
+ "PAGE",
+ "PIE",
+ "POLY",
+ "PRE",
+ "P",
+ "RECT",
+ "TEXT",
+ "TT",
+ "VAR"
+ };
+
+
+/*
+ * 'formDelete()' - Delete a node and its children.
+ */
+
+void
+formDelete(tree_t *t) /* I - Tree node */
+{
+}
+
+
+/*
+ * 'formGetAttr()' - Get a node attribute value.
+ */
+
+char * /* O - Value or NULL */
+formGetAttr(tree_t *t, /* I - Tree node */
+ const char *name) /* I - Name of attribute */
+{
+}
+
+
+/*
+ * 'formNew()' - Create a new form node.
+ */
+
+tree_t * /* O - New tree node */
+formNew(tree_t *p) /* I - Parent node */
+{
+ tree_t *t; /* New tree node */
+
+
+ /*
+ * Allocate the new node...
+ */
+
+ if ((t = (tree_t *)calloc(sizeof(tree_t), 1)) == NULL)
+ return (NULL);
+
+ /*
+ * Set/copy attributes...
+ */
+
+ if (p == NULL)
+ {
+ t->bg[0] = 1.0;
+ t->bg[1] = 1.0;
+ t->bg[2] = 1.0;
+ t->halign = HALIGN_LEFT;
+ t->valign = VALIGN_MIDDLE;
+ t->typeface = "Courier";
+ t->size = 12.0;
+ }
+ else
+ {
+ memcpy(t, p, sizeof(tree_t));
+
+ t->prev = NULL;
+ t->next = NULL;
+ t->child = NULL;
+ t->last_child = NULL;
+ t->parent = NULL;
+ t->num_attrs = 0;
+ t->attrs = NULL;
+ t->data = NULL;
+ }
+
+ /*
+ * Return the new node...
+ */
+
+ return (t);
+}
+
+
+/*
+ * 'formRead()' - Read a form tree from a file.
+ */
+
+tree_t * /* O - New form tree */
+formRead(FILE *fp, /* I - File to read from */
+ tree_t *p) /* I - Parent node */
+{
+ int ch, /* Character from file */
+ closech, /* Closing character */
+ have_whitespace; /* Leading whitespace? */
+ static char s[10240]; /* String from file */
+ uchar *ptr, /* Pointer in string */
+ glyph[16], /* Glyph name (&#nnn;) */
+ *glyphptr; /* Pointer in glyph string */
+ tree_t *tree, /* "top" of this tree */
+ *t, /* New tree node */
+ *prev, /* Previous tree node */
+ *temp; /* Temporary looping var */
+ uchar *face, /* Typeface for FONT tag */
+ *color, /* Color for FONT tag */
+ *size; /* Size for FONT tag */
+
+
+ /*
+ * Start off with no previous tree node...
+ */
+
+ prev = NULL;
+ tree = NULL;
+
+ /*
+ * Parse data until we hit end-of-file...
+ */
+
+ while ((ch = getc(fp)) != EOF)
+ {
+ /*
+ * Ignore leading whitespace...
+ */
+
+ have_whitespace = 0;
+ closech = '/';
+
+ if (p == NULL || !p->preformatted)
+ {
+ while (isspace(ch))
+ {
+ have_whitespace = 1;
+ ch = getc(fp);
+ }
+
+ if (ch == EOF)
+ break;
+ }
+
+ /*
+ * Allocate a new tree node - use calloc() to get zeroed data...
+ */
+
+ t = formNew(p);
+
+ /*
+ * See what the character was...
+ */
+
+ if (ch == '<')
+ {
+ /*
+ * Markup char; grab the next char to see if this is a /...
+ */
+
+ ch = getc(fp);
+ if (ch == ' ')
+ {
+ /*
+ * Illegal lone "<"! Ignore it...
+ */
+
+ free(t);
+ continue;
+ }
+
+ if (ch != '/')
+ ungetc(ch, fp);
+
+ if (parse_element(t, fp) < 0)
+ {
+ free(t);
+ break;
+ }
+
+ if ((closech = getc(fp)) == '/')
+ getc(fp);
+
+ /*
+ * If this is the matching close mark, or if we are starting the same
+ * element, or if we've completed a list, we're done!
+ */
+
+ if (ch == '/')
+ {
+ /*
+ * Close element; find matching element...
+ */
+
+ for (temp = p; temp != NULL; temp = temp->p)
+ if (temp->element == t->element)
+ break;
+
+ free(t);
+
+ if (temp != NULL)
+ break;
+ else
+ continue;
+ }
+ }
+ else if (t->preformatted)
+ {
+ /*
+ * Read a pre-formatted string into the current tree node...
+ */
+
+ ptr = s;
+ while (ch != '<' && ch != EOF && ptr < (s + sizeof(s) - 1))
+ {
+ if (ch == '&')
+ {
+ for (glyphptr = glyph;
+ (ch = getc(fp)) != EOF && (glyphptr - glyph) < 15;
+ glyphptr ++)
+ if (!isalnum(ch))
+ break;
+ else
+ *glyphptr = ch;
+
+ *glyphptr = '\0';
+ if (atoi(glyph) > 0)
+ ch = atoi(glyph);
+ else if (strcmp(glyph, "lt") == 0)
+ ch = '<';
+ else if (strcmp(glyph, "gt") == 0)
+ ch = '>';
+ else if (strcmp(glyph, "quot") == 0)
+ ch = '\'';
+ else if (strcmp(glyph, "nbsp") == 0)
+ ch = ' ';
+ else
+ ch = '&';
+ }
+
+ if (ch != 0)
+ *ptr++ = ch;
+
+ if (ch == '\n')
+ break;
+
+ ch = getc(fp);
+ }
+
+ *ptr = '\0';
+
+ if (ch == '<')
+ ungetc(ch, fp);
+
+ t->element = ELEMENT_FRAGMENT;
+ t->data = strdup(s);
+ }
+ else
+ {
+ /*
+ * Read the next string fragment...
+ */
+
+ ptr = s;
+ if (have_whitespace)
+ *ptr++ = ' ';
+
+ while (!isspace(ch) && ch != '<' && ch != EOF && ptr < (s + sizeof(s) - 1))
+ {
+ if (ch == '&')
+ {
+ for (glyphptr = glyph;
+ (ch = getc(fp)) != EOF && (glyphptr - glyph) < 15;
+ glyphptr ++)
+ if (!isalnum(ch))
+ break;
+ else
+ *glyphptr = ch;
+
+ *glyphptr = '\0';
+ if (atoi(glyph) > 0)
+ ch = atoi(glyph);
+ else if (strcmp(glyph, "lt") == 0)
+ ch = '<';
+ else if (strcmp(glyph, "gt") == 0)
+ ch = '>';
+ else if (strcmp(glyph, "quot") == 0)
+ ch = '\'';
+ else if (strcmp(glyph, "nbsp") == 0)
+ ch = ' ';
+ else
+ ch = '&';
+ }
+
+ if (ch != 0)
+ *ptr++ = ch;
+
+ ch = getc(fp);
+ }
+
+ if (isspace(ch))
+ *ptr++ = ' ';
+
+ *ptr = '\0';
+
+ if (ch == '<')
+ ungetc(ch, fp);
+
+ t->element = ELEMENT_FRAGMENT;
+ t->data = strdup(s);
+ }
+
+ /*
+ * If the p tree pointer is not NULL and this is the first
+ * entry we've read, set the child pointer...
+ */
+
+ if (p != NULL && prev == NULL)
+ p->child = t;
+
+ if (p != NULL)
+ p->last_child = t;
+
+ /*
+ * Do the prev/next links...
+ */
+
+ t->parent = p;
+ t->prev = prev;
+ if (prev != NULL)
+ prev->next = t;
+ else
+ tree = t;
+
+ prev = t;
+
+ /*
+ * Do child stuff as needed...
+ */
+
+ if (closech == '>')
+ t->child = formRead(t, fp);
+ }
+
+ return (tree);
+}
+
+
+/*
+ * 'formSetAttr()' - Set a node attribute.
+ */
+
+void
+formSetAttr(tree_t *t, /* I - Tree node */
+ const char *name, /* I - Attribute name */
+ const char *value) /* I - Attribute value */
+{
+}
+
+
+/*
+ * 'compare_attr()' - Compare two attributes.
+ */
+
+static int /* O - -1 if a0 < a1, etc. */
+compare_attr(attr_t *a0, /* I - First attribute */
+ attr_t *a1) /* I - Second attribute */
+{
+ return (strcasecmp(a0->name, a1->name));
+}
+
+
+/*
+ * 'compare_elements()' - Compare two elements.
+ */
+
+static int /* O - -1 if e0 < e1, etc. */
+compare_elements(char **e0, /* I - First element */
+ char **e1) /* I - Second element */
+{
+ return (strcasecmp(*e0, *e1));
+}
+
+
+/*
+ * 'parse_attr()' - Parse an element attribute string.
+ */
+
+static int /* O - -1 on error, 0 on success */
+parse_attr(tree_t *t, /* I - Current tree node */
+ FILE *fp) /* I - Input file */
+{
+ char name[1024], /* Name of attr */
+ value[10240], /* Value of attr */
+ *ptr; /* Temporary pointer */
+ int ch; /* Character from file */
+
+
+ ptr = name;
+ while ((ch = getc(fp)) != EOF)
+ if (isalnum(ch))
+ {
+ if (ptr < (name + sizeof(name) - 1))
+ *ptr++ = ch;
+ }
+ else
+ break;
+
+ *ptr = '\0';
+
+ while (isspace(ch) || ch == '\r')
+ ch = getc(fp);
+
+ switch (ch)
+ {
+ default :
+ ungetc(ch, fp);
+ return (formSetAttr(t, name, NULL));
+ case EOF :
+ return (-1);
+ case '=' :
+ ptr = value;
+ ch = getc(fp);
+
+ while (isspace(ch) || ch == '\r')
+ ch = getc(fp);
+
+ if (ch == EOF)
+ return (-1);
+
+ if (ch == '\'')
+ {
+ while ((ch = getc(fp)) != EOF)
+ if (ch == '\'')
+ break;
+ else if (ptr < (value + sizeof(value) - 1))
+ *ptr++ = ch;
+
+ *ptr = '\0';
+ }
+ else if (ch == '\"')
+ {
+ while ((ch = getc(fp)) != EOF)
+ if (ch == '\"')
+ break;
+ else if (ptr < (value + sizeof(value) - 1))
+ *ptr++ = ch;
+
+ *ptr = '\0';
+ }
+ else
+ {
+ *ptr++ = ch;
+ while ((ch = getc(fp)) != EOF)
+ if (isspace(ch) || ch == '>' || ch == '/' || ch == '\r')
+ break;
+ else if (ptr < (value + sizeof(value) - 1))
+ *ptr++ = ch;
+
+ *ptr = '\0';
+ if (ch == '>' || ch == '/')
+ ungetc(ch, fp);
+ }
+
+ return (formSetAttr(t, name, value));
+ }
+}
+
+
+/*
+ * 'parse_element()' - Parse an element.
+ */
+
+static int /* O - -1 on error or ELEMENT_nnnn */
+parse_element(tree_t *t, /* I - Current tree node */
+ FILE *fp) /* I - Input file */
+{
+ int ch; /* Character from file */
+ char element[255], /* Element string... */
+ *eptr, /* Current character... */
+ comment[10240], /* Comment string */
+ *cptr, /* Current char... */
+ **temp; /* Element variable entry */
+
+
+ eptr = element;
+
+ while ((ch = getc(fp)) != EOF && eptr < (element + sizeof(element) - 1))
+ if (ch == '>' || ch == '/' || isspace(ch))
+ break;
+ else
+ *eptr++ = ch;
+
+ *eptr = '\0';
+
+ if (ch == EOF)
+ return (ELEMENT_ERROR);
+
+ eptr = element;
+ temp = bsearch(&mptr, elements, sizeof(elements) / sizeof(elements[0]),
+ sizeof(elements[0]),
+ (int (*)(const void *, const void *))compare_elements);
+
+ if (temp == NULL)
+ {
+ /*
+ * Unrecognized element stuff...
+ */
+
+ t->element = ELEMENT_COMMENT;
+ strcpy(comment, element);
+ cptr = comment + strlen(comment);
+ }
+ else
+ {
+ t->element = (element_t)((char **)temp - elements);
+ cptr = comment;
+ }
+
+ if (t->element == ELEMENT_COMMENT)
+ {
+ while (ch != EOF && ch != '>' && cptr < (comment + sizeof(comment) - 1))
+ {
+ *cptr++ = ch;
+ ch = getc(fp);
+ }
+
+ *cptr = '\0';
+ t->data = strdup(comment);
+ }
+ else
+ {
+ while (ch != EOF && ch != '>' && ch != '/')
+ {
+ if (!isspace(ch))
+ {
+ ungetc(ch, fp);
+ parse_variable(t, fp);
+ }
+
+ ch = getc(fp);
+ }
+
+ if (ch != EOF)
+ ungetc(ch, fp);
+ }
+
+ return (t->element);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/form.h b/filter/form.h
new file mode 100644
index 000000000..c9207159a
--- /dev/null
+++ b/filter/form.h
@@ -0,0 +1,175 @@
+/*
+ * "$Id$"
+ *
+ * CUPS form header file for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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"
+
+
+/*
+ * Form elements...
+ */
+
+typedef enum
+{
+ ELEMENT_FILE = -1, /* Pseudo element, not in file, but above */
+ ELEMENT_FRAGMENT, /* Text fragment */
+ ELEMENT_COMMENT, /* <!-- .... --> */
+ ELEMENT_ARC,
+ ELEMENT_BOX,
+ ELEMENT_BR,
+ ELEMENT_B,
+ ELEMENT_CUPSFORM,
+ ELEMENT_DEFVAR,
+ ELEMENT_FONT,
+ ELEMENT_H1,
+ ELEMENT_H2,
+ ELEMENT_H3,
+ ELEMENT_H4,
+ ELEMENT_H5,
+ ELEMENT_H6,
+ ELEMENT_HEAD,
+ ELEMENT_IMG,
+ ELEMENT_I,
+ ELEMENT_LINE,
+ ELEMENT_PAGE,
+ ELEMENT_PIE,
+ ELEMENT_POLY,
+ ELEMENT_PRE,
+ ELEMENT_P,
+ ELEMENT_RECT,
+ ELEMENT_TEXT,
+ ELEMENT_TT,
+ ELEMENT_VAR
+} element_t;
+
+
+/*
+ * Font styles...
+ */
+
+typedef enum
+{
+ STYLE_NORMAL,
+ STYLE_BOLD,
+ STYLE_ITALIC,
+ STYLE_BOLD_ITALIC
+} style_t;
+
+
+/*
+ * Text alignments...
+ */
+
+typedef enum
+{
+ HALIGN_LEFT,
+ HALIGN_CENTER,
+ HALIGN_RIGHT
+} halign_t;
+
+typedef enum
+{
+ VALIGN_BOTTOM,
+ VALIGN_CENTER,
+ VALIGN_TOP
+} valign_t;
+
+
+/*
+ * Text directions...
+ */
+
+typedef enun
+{
+ DIR_LEFT_TO_RIGHT,
+ DIR_RIGHT_TO_LEFT
+} dir_t;
+
+
+/*
+ * Attribute structure...
+ */
+
+typedef struct
+{
+ char *name, /* Name of attribute */
+ *value; /* Value of attribute */
+} attr_t;
+
+
+/*
+ * Form document tree structure...
+ */
+
+typedef struct tree_str
+{
+ struct tree_str *prev, /* Previous tree node */
+ *next, /* Next tree node */
+ *parent, /* Parent tree node */
+ *child, /* First child node */
+ *last_child; /* Last child node */
+ element_t element; /* Element type */
+ float x, y, w, h; /* Position and size in points */
+ float bg[3], fg[3]; /* Colors of element */
+ float thickness; /* Thickness of lines */
+ int preformatted; /* Preformatted text? */
+ float size; /* Height of text in points */
+ char *typeface; /* Typeface of text */
+ style_t style; /* Style of text */
+ halign_t halign; /* Horizontal alignment */
+ valign_t valign; /* Vertical alignment */
+ dir_t dir; /* Direction of text */
+ int num_attrs; /* Number of attributes */
+ attr_t *attrs; /* Attributes */
+ void *data; /* Text fragment data */
+} tree_t;
+
+
+/*
+ * Globals...
+ */
+
+extern int NumOptions; /* Number of command-line options */
+extern cups_option_t *Options; /* Command-line options */
+extern ppd_file_t *PPD; /* PPD file */
+
+
+/*
+ * Prototypes...
+ */
+
+extern void formDelete(tree_t *t);
+extern char *formGetAttr(tree_t *t, const char *name);
+extern tree_t *formNew(tree_t *p);
+extern tree_t *formRead(FILE *fp, tree_t *p);
+extern void formSetAttr(tree_t *t, const char *name, const char *value);
+extern void formWrite(tree_t *p);
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/hpgl-attr.c b/filter/hpgl-attr.c
new file mode 100644
index 000000000..0653ba6cb
--- /dev/null
+++ b/filter/hpgl-attr.c
@@ -0,0 +1,452 @@
+/*
+ * "$Id$"
+ *
+ * HP-GL/2 attribute processing for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1993-2002 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 - ColorRange[0][0]) /
+ (ColorRange[0][1] - ColorRange[0][0]);
+ Pens[i].rgb[1] = (params[2].value.number - ColorRange[1][0]) /
+ (ColorRange[1][1] - ColorRange[1][0]);
+ Pens[i].rgb[2] = (params[3].value.number - ColorRange[2][0]) /
+ (ColorRange[2][1] - ColorRange[2][0]);
+
+ fprintf(stderr, "DEBUG: Pen %d %.0f %.0f %.0f = %.3f %.3f %.3f\n",
+ i, params[1].value.number, params[2].value.number,
+ params[3].value.number, Pens[i].rgb[0], Pens[i].rgb[1],
+ Pens[i].rgb[2]);
+ }
+
+ 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 000000000..5227f7bf1
--- /dev/null
+++ b/filter/hpgl-char.c
@@ -0,0 +1,500 @@
+/*
+ * "$Id$"
+ *
+ * HP-GL/2 character processing for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1993-2002 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);
+ puts("SA");
+ }
+ }
+ 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);
+ puts("SS");
+ }
+ }
+}
+
+
+/*
+ * '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[1], 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 000000000..bdb1c1082
--- /dev/null
+++ b/filter/hpgl-config.c
@@ -0,0 +1,641 @@
+/*
+ * "$Id$"
+ *
+ * HP-GL/2 configuration routines for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1993-2002 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"
+
+#define max(a,b) ((a) < (b) ? (b) : (a))
+
+
+/*
+ * '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)
+ {
+ default : /* 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] * 1016.0f / 72.0f;
+ top = bottom + page_height * Scaling2[1] * 1016.0f / 72.0f;
+ 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)
+ scaling *= max(page_width, page_height) / max(PlotSize[1], 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] = 0.0;
+ IW1[1] = 0.0;
+ IW2[0] = 0.0;
+ IW2[1] = 0.0;
+
+ 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] = 0.0;
+ IW1[1] = 0.0;
+ IW2[0] = 0.0;
+ IW2[1] = 0.0;
+
+ 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;
+ }
+
+ PlotSizeSet = 0;
+ 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];
+ }
+
+ PlotSizeSet = 1;
+ 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 when scaling.
+ *
+ * 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;
+ }
+
+ PlotSizeSet = 1;
+ 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 000000000..1feb3038b
--- /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-2002 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 <ctype.h>
+
+#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 000000000..fb78576e7
--- /dev/null
+++ b/filter/hpgl-main.c
@@ -0,0 +1,265 @@
+/*
+ * "$Id$"
+ *
+ * HP-GL/2 filter main entry for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1993-2002 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 */
+
+
+ /*
+ * Make sure status messages are not buffered...
+ */
+
+ setbuf(stderr, NULL);
+
+ /*
+ * Check command-line...
+ */
+
+ 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)atoi(val) * 0.001f;
+
+ /*
+ * 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, &params)) >= 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 000000000..bcde250db
--- /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-2002 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 000000000..47dd95d32
--- /dev/null
+++ b/filter/hpgl-prolog.c
@@ -0,0 +1,407 @@
+/*
+ * "$Id$"
+ *
+ * HP-GL/2 prolog routines for for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1993-2002 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 <stdarg.h>
+
+
+/*
+ * '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 */
+ const char *datadir; /* CUPS_DATADIR environment variable */
+ char filename[1024]; /* Name of 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), CUPS_STRFTIME_FORMAT, curtm);
+ printf("%%%%CreationDate: %s\n", 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 ((datadir = getenv("CUPS_DATADIR")) == NULL)
+ datadir = CUPS_DATADIR;
+
+ snprintf(filename, sizeof(filename), "%s/data/HPGLprolog", datadir);
+
+ if ((prolog = fopen(filename, "r")) == NULL)
+ {
+ fprintf(stderr, "ERROR: Unable to open HPGL prolog \"%s\" for reading - %s\n",
+ filename, strerror(errno));
+ 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 ++;
+
+ printf("%%%%Page: %d %d\n", PageCount, PageCount);
+
+ landscape = 0;
+
+ if (!FitPlot && PlotSizeSet)
+ {
+ /*
+ * 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];
+ }
+
+ fprintf(stderr, "DEBUG: hpgltops setting page size (%.0f x %.0f)\n",
+ width, length);
+
+ if (PPD != NULL)
+ {
+ fputs("DEBUG: hpgltops has a PPD file!\n", stderr);
+
+ /*
+ * 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("%%BeginPageSetup");
+ 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("<</PageSize[5 -2 roll]/ImagingBBox null>>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("%%EndPageSetup");
+ }
+ }
+ else
+ {
+ fputs("DEBUG: hpgltops does not have a PPD file!\n", stderr);
+
+ puts("%%BeginPageSetup");
+ printf("%%%%BeginFeature: PageSize w%.0fh%.0f\n", width, length);
+ printf("<</PageSize[%.0f %.0f]/ImageBBox null>>setpagedevice\n",
+ width, length);
+ puts("%%EndFeature");
+ puts("%%EndPageSetup");
+
+ PageLeft = 0.0;
+ PageRight = width;
+ PageWidth = width;
+ PageBottom = 0.0;
+ PageTop = length;
+ PageLength = length;
+ }
+ }
+
+ 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 000000000..b594947b2
--- /dev/null
+++ b/filter/hpgl-vector.c
@@ -0,0 +1,731 @@
+/*
+ * "$Id$"
+ *
+ * HP-GL/2 vector routines for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1993-2002 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;
+
+#ifdef DEBUG
+ fputs("DEBUG: 7-bit\n", stderr);
+#endif /* DEBUG */
+ 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[1], Pens[PenNumber].rgb[2],
+ Pens[PenNumber].width * PenScaling);
+
+#ifdef DEBUG
+ fprintf(stderr, "DEBUG: set pen #%d\n", PenNumber);
+#endif /* DEBUG */
+ break;
+ case '<' : /* Next coords are a move-to */
+ draw = 0;
+ s ++;
+
+#ifdef DEBUG
+ fputs("DEBUG: moveto\n", stderr);
+#endif /* DEBUG */
+ break;
+ case '>' : /* Set fractional bits */
+ s ++;
+ temp = (int)decode_number(&s, base_bits, 1.0);
+ frac_bits = 1.0 / (1 << temp);
+
+#ifdef DEBUG
+ fprintf(stderr, "DEBUG: set fractional bits %d\n", temp);
+#endif /* DEBUG */
+ break;
+ case '=' : /* Next coords are absolute */
+ s ++;
+ abscoords = 1;
+
+#ifdef DEBUG
+ fputs("DEBUG: absolute\n", stderr);
+#endif /* DEBUG */
+ break;
+ default :
+ if (*s >= 63)
+ {
+ /*
+ * Coordinate...
+ */
+
+ x = decode_number(&s, base_bits, frac_bits);
+ y = decode_number(&s, base_bits, frac_bits);
+
+#ifdef DEBUG
+ fprintf(stderr, "DEBUG: coords %.3f %.3f\n", x, y);
+#endif /* DEBUG */
+
+ 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 000000000..36de1ac77
--- /dev/null
+++ b/filter/hpgltops.h
@@ -0,0 +1,233 @@
+/*
+ * "$Id$"
+ *
+ * HP-GL/2 to PostScript filter for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1993-2002 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 <math.h>
+
+#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 PlotSizeSet VALUE(0); /* Plot size set? */
+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-bmp.c b/filter/image-bmp.c
new file mode 100644
index 000000000..663460597
--- /dev/null
+++ b/filter/image-bmp.c
@@ -0,0 +1,510 @@
+/*
+ * "$Id$"
+ *
+ * BMP image routines for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1993-2002 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:
+ *
+ * ImageReadBMP() - Read a BMP image file.
+ * read_word() - Read a 16-bit unsigned integer.
+ * read_dword() - Read a 32-bit unsigned integer.
+ * read_long() - Read a 32-bit signed integer.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "image.h"
+
+
+/*
+ * Constants for the bitmap compression...
+ */
+
+# define BI_RGB 0 /* No compression - straight BGR data */
+# define BI_RLE8 1 /* 8-bit run-length compression */
+# define BI_RLE4 2 /* 4-bit run-length compression */
+# define BI_BITFIELDS 3 /* RGB bitmap with RGB masks */
+
+
+/*
+ * Local functions...
+ */
+
+static unsigned short read_word(FILE *fp);
+static unsigned int read_dword(FILE *fp);
+static int read_long(FILE *fp);
+
+
+/*
+ * 'ImageReadBMP()' - Read a BMP image file.
+ */
+
+int /* O - Read status */
+ImageReadBMP(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 offset, /* Offset to bitmap data */
+ info_size, /* Size of info header */
+ planes, /* Number of planes (always 1) */
+ depth, /* Depth of image (bits) */
+ compression, /* Type of compression */
+ image_size, /* Size of image in bytes */
+ colors_used, /* Number of colors used */
+ colors_important, /* Number of important colors */
+ bpp, /* Bytes per pixel */
+ x, y, /* Looping vars */
+ color, /* Color of RLE pixel */
+ count, /* Number of times to repeat */
+ temp, /* Temporary color */
+ align; /* Alignment bytes */
+ ib_t bit, /* Bit in image */
+ byte; /* Byte in image */
+ ib_t *in, /* Input pixels */
+ *out, /* Output pixels */
+ *ptr; /* Pointer into pixels */
+ ib_t colormap[256][4]; /* Colormap */
+
+
+ (void)secondary;
+
+ /*
+ * Get the header...
+ */
+
+ getc(fp); /* Skip "BM" sync chars */
+ getc(fp);
+ read_dword(fp); /* Skip size */
+ read_word(fp); /* Skip reserved stuff */
+ read_word(fp);
+ offset = read_dword(fp);
+
+ fprintf(stderr, "offset = %d\n", offset);
+
+ /*
+ * Then the bitmap information...
+ */
+
+ info_size = read_dword(fp);
+ img->xsize = read_long(fp);
+ img->ysize = read_long(fp);
+ planes = read_word(fp);
+ depth = read_word(fp);
+ compression = read_dword(fp);
+ image_size = read_dword(fp);
+ img->xppi = read_long(fp) * 0.0254 + 0.5;
+ img->yppi = read_long(fp) * 0.0254 + 0.5;
+ colors_used = read_dword(fp);
+ colors_important = read_dword(fp);
+
+ /*
+ * Make sure the resolution info is valid...
+ */
+
+ if (img->xppi == 0)
+ img->xppi = 128;
+ if (img->yppi == 0)
+ img->yppi = 128;
+
+ fprintf(stderr, "info_size = %d, xsize = %d, ysize = %d, planes = %d, depth = %d\n",
+ info_size, img->xsize, img->ysize, planes, depth);
+ fprintf(stderr, "compression = %d, image_size = %d, xppi = %d, yppi = %d\n",
+ compression, image_size, img->xppi, img->yppi);
+ fprintf(stderr, "colors_used = %d, colors_important = %d\n", colors_used,
+ colors_important);
+
+ if (info_size > 40)
+ for (info_size -= 40; info_size > 0; info_size --)
+ getc(fp);
+
+ /*
+ * Get colormap...
+ */
+
+ if (colors_used == 0 && depth <= 8)
+ colors_used = 1 << depth;
+
+ fread(colormap, colors_used, 4, fp);
+
+ /*
+ * Setup image and buffers...
+ */
+
+ img->colorspace = primary;
+
+ ImageSetMaxTiles(img, 0);
+
+ in = malloc(img->xsize * 3);
+ bpp = ImageGetDepth(img);
+ out = malloc(img->xsize * bpp);
+
+ /*
+ * Read the image data...
+ */
+
+ color = 0;
+ count = 0;
+ align = 0;
+
+ for (y = img->ysize - 1; y >= 0; y --)
+ {
+ if (img->colorspace == IMAGE_RGB)
+ ptr = out;
+ else
+ ptr = in;
+
+ switch (depth)
+ {
+ case 1 : /* Bitmap */
+ for (x = img->xsize, bit = 128, byte = 0; x > 0; x --)
+ {
+ if (bit == 128)
+ byte = getc(fp);
+
+ if (byte & bit)
+ {
+ *ptr++ = colormap[1][2];
+ *ptr++ = colormap[1][1];
+ *ptr++ = colormap[1][0];
+ }
+ else
+ {
+ *ptr++ = colormap[0][2];
+ *ptr++ = colormap[0][1];
+ *ptr++ = colormap[0][0];
+ }
+
+ if (bit > 1)
+ bit >>= 1;
+ else
+ bit = 128;
+ }
+
+ /*
+ * Read remaining bytes to align to 32 bits...
+ */
+
+ for (temp = (img->xsize + 7) / 8; temp & 3; temp ++)
+ getc(fp);
+ break;
+
+ case 4 : /* 16-color */
+ for (x = img->xsize, bit = 0xf0, temp = 0; x > 0; x --)
+ {
+ /*
+ * Get a new count as needed...
+ */
+
+ if (compression != BI_RLE4 && count == 0)
+ {
+ count = 2;
+ color = -1;
+ }
+
+ if (count == 0)
+ {
+ while (align > 0)
+ {
+ align --;
+ getc(fp);
+ }
+
+ if ((count = getc(fp)) == 0)
+ {
+ if ((count = getc(fp)) == 0)
+ {
+ /*
+ * End of line...
+ */
+
+ x ++;
+ continue;
+ }
+ else if (count == 1)
+ {
+ /*
+ * End of image...
+ */
+
+ break;
+ }
+ else if (count == 2)
+ {
+ /*
+ * Delta...
+ */
+
+ count = getc(fp) * getc(fp) * img->xsize;
+ color = 0;
+ }
+ else
+ {
+ /*
+ * Absolute...
+ */
+
+ color = -1;
+ align = ((4 - (count & 3)) / 2) & 1;
+ }
+ }
+ else
+ color = getc(fp);
+ }
+
+ /*
+ * Get a new color as needed...
+ */
+
+ count --;
+
+ if (bit == 0xf0)
+ {
+ if (color < 0)
+ temp = getc(fp);
+ else
+ temp = color;
+
+ /*
+ * Copy the color value...
+ */
+
+ *ptr++ = colormap[temp >> 4][2];
+ *ptr++ = colormap[temp >> 4][1];
+ *ptr++ = colormap[temp >> 4][0];
+ bit = 0x0f;
+ }
+ else
+ {
+ /*
+ * Copy the color value...
+ */
+
+ *ptr++ = colormap[temp & 15][2];
+ *ptr++ = colormap[temp & 15][1];
+ *ptr++ = colormap[temp & 15][0];
+ bit = 0xf0;
+ }
+ }
+ break;
+
+ case 8 : /* 256-color */
+ for (x = img->xsize; x > 0; x --)
+ {
+ /*
+ * Get a new count as needed...
+ */
+
+ if (compression != BI_RLE8)
+ {
+ count = 1;
+ color = -1;
+ }
+
+ if (count == 0)
+ {
+ while (align > 0)
+ {
+ align --;
+ getc(fp);
+ }
+
+ if ((count = getc(fp)) == 0)
+ {
+ if ((count = getc(fp)) == 0)
+ {
+ /*
+ * End of line...
+ */
+
+ x ++;
+ continue;
+ }
+ else if (count == 1)
+ {
+ /*
+ * End of image...
+ */
+
+ break;
+ }
+ else if (count == 2)
+ {
+ /*
+ * Delta...
+ */
+
+ count = getc(fp) * getc(fp) * img->xsize;
+ color = 0;
+ }
+ else
+ {
+ /*
+ * Absolute...
+ */
+
+ color = -1;
+ align = (2 - (count & 1)) & 1;
+ }
+ }
+ else
+ color = getc(fp);
+ }
+
+ /*
+ * Get a new color as needed...
+ */
+
+ if (color < 0)
+ temp = getc(fp);
+ else
+ temp = color;
+
+ count --;
+
+ /*
+ * Copy the color value...
+ */
+
+ *ptr++ = colormap[temp][2];
+ *ptr++ = colormap[temp][1];
+ *ptr++ = colormap[temp][0];
+ }
+ break;
+
+ case 24 : /* 24-bit RGB */
+ for (x = img->xsize; x > 0; x --, ptr += 3)
+ {
+ ptr[2] = getc(fp);
+ ptr[1] = getc(fp);
+ ptr[0] = getc(fp);
+ }
+
+ /*
+ * Read remaining bytes to align to 32 bits...
+ */
+
+ for (temp = img->xsize * 3; temp & 3; temp ++)
+ getc(fp);
+ break;
+ }
+
+ if (img->colorspace == IMAGE_RGB)
+ {
+ if (saturation != 100 || hue != 0)
+ ImageRGBAdjust(out, img->xsize, saturation, hue);
+ }
+ else
+ {
+ if (saturation != 100 || hue != 0)
+ 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);
+ }
+
+ fclose(fp);
+ free(in);
+ free(out);
+
+ return (0);
+}
+
+
+/*
+ * 'read_word()' - Read a 16-bit unsigned integer.
+ */
+
+static unsigned short /* O - 16-bit unsigned integer */
+read_word(FILE *fp) /* I - File to read from */
+{
+ unsigned char b0, b1; /* Bytes from file */
+
+ b0 = getc(fp);
+ b1 = getc(fp);
+
+ return ((b1 << 8) | b0);
+}
+
+
+/*
+ * 'read_dword()' - Read a 32-bit unsigned integer.
+ */
+
+static unsigned int /* O - 32-bit unsigned integer */
+read_dword(FILE *fp) /* I - File to read from */
+{
+ unsigned char b0, b1, b2, b3; /* Bytes from file */
+
+ b0 = getc(fp);
+ b1 = getc(fp);
+ b2 = getc(fp);
+ b3 = getc(fp);
+
+ return ((((((b3 << 8) | b2) << 8) | b1) << 8) | b0);
+}
+
+
+/*
+ * 'read_long()' - Read a 32-bit signed integer.
+ */
+
+static int /* O - 32-bit signed integer */
+read_long(FILE *fp) /* I - File to read from */
+{
+ unsigned char b0, b1, b2, b3; /* Bytes from file */
+
+ b0 = getc(fp);
+ b1 = getc(fp);
+ b2 = getc(fp);
+ b3 = getc(fp);
+
+ return ((int)(((((b3 << 8) | b2) << 8) | b1) << 8) | b0);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/image-colorspace.c b/filter/image-colorspace.c
new file mode 100644
index 000000000..1c0a53748
--- /dev/null
+++ b/filter/image-colorspace.c
@@ -0,0 +1,926 @@
+/*
+ * "$Id$"
+ *
+ * Colorspace conversions for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1993-2002 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:
+ *
+ * ImageSetProfile() - Set the device color profile.
+ * ImageWhiteToWhite() - Convert luminance colors to device-dependent
+ * ImageWhiteToRGB() - Convert luminance data to RGB.
+ * ImageWhiteToBlack() - Convert luminance colors to black.
+ * 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 <math.h>
+
+
+/*
+ * Define some math constants that are required...
+ */
+
+#ifndef M_PI
+# define M_PI 3.14159265358979323846
+#endif /* !M_PI */
+
+#ifndef M_SQRT2
+# define M_SQRT2 1.41421356237309504880
+#endif /* !M_SQRT2 */
+
+#ifndef M_SQRT1_2
+# define M_SQRT1_2 0.70710678118654752440
+#endif /* !M_SQRT1_2 */
+
+
+/*
+ * Local globals...
+ */
+
+static int ImageHaveProfile = 0; /* Do we have a color profile? */
+static int ImageDensity[256]; /* Ink/marker density LUT */
+static int ImageMatrix[3][3][256]; /* Color transform matrix LUT */
+
+
+/*
+ * Local functions...
+ */
+
+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);
+
+
+/*
+ * 'ImageSetProfile()' - Set the device color profile.
+ */
+
+void
+ImageSetProfile(float d, /* I - Ink/marker density */
+ float g, /* I - Ink/marker gamma */
+ float matrix[3][3]) /* I - Color transform matrix */
+{
+ int i, j, k; /* Looping vars */
+ float m; /* Current matrix value */
+ int *im; /* Pointer into ImageMatrix */
+
+ ImageHaveProfile = 1;
+
+ for (i = 0, im = ImageMatrix[0][0]; i < 3; i ++)
+ for (j = 0; j < 3; j ++)
+ for (k = 0, m = matrix[i][j]; k < 256; k ++)
+ *im++ = (int)(k * m + 0.5);
+
+ for (k = 0, im = ImageDensity; k < 256; k ++)
+ *im++ = 255.0 * d * pow((float)k / 255.0, g) + 0.5;
+}
+
+
+/*
+ * 'ImageWhiteToWhite()' - Convert luminance colors to device-dependent
+ * luminance.
+ */
+
+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 * k / (km * 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 * k / (km * 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 000000000..f177ac69e
--- /dev/null
+++ b/filter/image-gif.c
@@ -0,0 +1,644 @@
+/*
+ * "$Id$"
+ *
+ * GIF image routines for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1993-2002 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 000000000..96547b2c1
--- /dev/null
+++ b/filter/image-jpeg.c
@@ -0,0 +1,194 @@
+/*
+ * "$Id$"
+ *
+ * JPEG image routines for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1993-2002 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 <jpeglib.h> /* 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);
+ }
+ }
+
+ fprintf(stderr, "DEBUG: JPEG image %dx%dx%d, %dx%d PPI\n",
+ img->xsize, img->ysize, cinfo.output_components,
+ img->xppi, img->yppi);
+
+ 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 000000000..88ecd5719
--- /dev/null
+++ b/filter/image-photocd.c
@@ -0,0 +1,323 @@
+/*
+ * "$Id$"
+ *
+ * PhotoCD routines for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1993-2002 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);
+ else
+ rgb = NULL;
+
+ 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.
+ */
+
+ cb = cr = 0.0f;
+
+ 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-pix.c b/filter/image-pix.c
new file mode 100644
index 000000000..0e391fd16
--- /dev/null
+++ b/filter/image-pix.c
@@ -0,0 +1,223 @@
+/*
+ * "$Id$"
+ *
+ * Alias PIX image routines for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1993-2002 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:
+ *
+ * ImageReadPIX() - Read a PIX image file.
+ * read_short() - Read a 16-bit integer.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "image.h"
+
+
+/*
+ * Local functions...
+ */
+
+static short read_short(FILE *fp);
+
+
+/*
+ * 'ImageReadPIX()' - Read a PIX image file.
+ */
+
+int /* O - Read status */
+ImageReadPIX(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 */
+{
+ short width, /* Width of image */
+ height, /* Height of image */
+ depth; /* Depth of image (bits) */
+ int count, /* Repetition count */
+ bpp, /* Bytes per pixel */
+ x, y; /* Looping vars */
+ ib_t r, g, b; /* Red, green/gray, blue values */
+ ib_t *in, /* Input pixels */
+ *out, /* Output pixels */
+ *ptr; /* Pointer into pixels */
+
+
+ /*
+ * Get the image dimensions and setup the image...
+ */
+
+ width = read_short(fp);
+ height = read_short(fp);
+ read_short(fp);
+ read_short(fp);
+ depth = read_short(fp);
+
+ if (depth == 8)
+ img->colorspace = secondary;
+ else
+ img->colorspace = primary;
+
+ img->xsize = width;
+ img->ysize = height;
+
+ ImageSetMaxTiles(img, 0);
+
+ in = malloc(img->xsize * (depth / 8));
+ bpp = ImageGetDepth(img);
+ out = malloc(img->xsize * bpp);
+
+ /*
+ * Read the image data...
+ */
+
+ if (depth == 8)
+ {
+ for (count = 0, y = 0, g = 0; y < img->ysize; y ++)
+ {
+ if (img->colorspace == IMAGE_WHITE)
+ ptr = out;
+ else
+ ptr = in;
+
+ for (x = img->xsize; x > 0; x --, count --)
+ {
+ if (count == 0)
+ {
+ count = getc(fp);
+ g = getc(fp);
+ }
+
+ *ptr++ = g;
+ }
+
+ if (img->colorspace != IMAGE_WHITE)
+ 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
+ {
+ for (count = 0, y = 0, r = 0, g = 0, b = 0; y < img->ysize; y ++)
+ {
+ if (img->colorspace == IMAGE_RGB)
+ ptr = out;
+ else
+ ptr = in;
+
+ for (x = img->xsize; x > 0; x --, count --)
+ {
+ if (count == 0)
+ {
+ count = getc(fp);
+ b = getc(fp);
+ g = getc(fp);
+ r = getc(fp);
+ }
+
+ *ptr++ = r;
+ *ptr++ = g;
+ *ptr++ = b;
+ }
+
+ if (img->colorspace == IMAGE_RGB)
+ {
+ if (saturation != 100 || hue != 0)
+ ImageRGBAdjust(out, img->xsize, saturation, hue);
+ }
+ else
+ {
+ if (saturation != 100 || hue != 0)
+ 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);
+ }
+ }
+
+ fclose(fp);
+ free(in);
+ free(out);
+
+ return (0);
+}
+
+
+/*
+ * 'read_short()' - Read a 16-bit integer.
+ */
+
+static short /* O - Value from file */
+read_short(FILE *fp) /* I - File to read from */
+{
+ int ch; /* Character from file */
+
+
+ ch = getc(fp);
+ return ((ch << 8) | getc(fp));
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/image-png.c b/filter/image-png.c
new file mode 100644
index 000000000..a28da3d83
--- /dev/null
+++ b/filter/image-png.c
@@ -0,0 +1,250 @@
+/*
+ * "$Id$"
+ *
+ * PNG image routines for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1993-2002 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 <png.h> /* 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 */
+ int pass, /* Current pass */
+ passes; /* Number of passes required */
+ ib_t *in, /* Input pixels */
+ *inptr, /* Pointer into pixels */
+ *out; /* Output pixels */
+ png_color_16 bg; /* Background color */
+
+ /*
+ * 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);
+
+ passes = png_set_interlace_handling(pp);
+
+ /*
+ * Handle transparency...
+ */
+
+ if (png_get_valid(pp, info, PNG_INFO_tRNS))
+ png_set_tRNS_to_alpha(pp);
+
+ bg.red = 65535;
+ bg.green = 65535;
+ bg.blue = 65535;
+
+ png_set_background(pp, &bg, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
+
+ if (passes == 1)
+ {
+ /*
+ * Load one row at a time...
+ */
+
+ 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);
+ }
+ else
+ {
+ /*
+ * Interlaced images must be loaded all at once...
+ */
+
+ if (info->color_type == PNG_COLOR_TYPE_GRAY ||
+ info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ in = malloc(img->xsize * img->ysize);
+ else
+ in = malloc(img->xsize * img->ysize * 3);
+ }
+
+ bpp = ImageGetDepth(img);
+ out = malloc(img->xsize * bpp);
+
+ /*
+ * Read the image, interlacing as needed...
+ */
+
+ for (pass = 1; pass <= passes; pass ++)
+ for (inptr = in, y = 0; y < img->ysize; y ++)
+ {
+ png_read_row(pp, (png_bytep)inptr, NULL);
+
+ if (pass == passes)
+ {
+ /*
+ * Output this row...
+ */
+
+ if (info->color_type == PNG_COLOR_TYPE_GRAY ||
+ info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ {
+ switch (img->colorspace)
+ {
+ case IMAGE_WHITE :
+ memcpy(out, inptr, img->xsize);
+ break;
+ case IMAGE_RGB :
+ ImageWhiteToRGB(inptr, out, img->xsize);
+ break;
+ case IMAGE_BLACK :
+ ImageWhiteToBlack(inptr, out, img->xsize);
+ break;
+ case IMAGE_CMY :
+ ImageWhiteToCMY(inptr, out, img->xsize);
+ break;
+ case IMAGE_CMYK :
+ ImageWhiteToCMYK(inptr, out, img->xsize);
+ break;
+ }
+ }
+ else
+ {
+ if ((saturation != 100 || hue != 0) && bpp > 1)
+ ImageRGBAdjust(inptr, img->xsize, saturation, hue);
+
+ switch (img->colorspace)
+ {
+ case IMAGE_WHITE :
+ ImageRGBToWhite(inptr, out, img->xsize);
+ break;
+ case IMAGE_RGB :
+ memcpy(out, inptr, img->xsize * 3);
+ break;
+ case IMAGE_BLACK :
+ ImageRGBToBlack(inptr, out, img->xsize);
+ break;
+ case IMAGE_CMY :
+ ImageRGBToCMY(inptr, out, img->xsize);
+ break;
+ case IMAGE_CMYK :
+ ImageRGBToCMYK(inptr, out, img->xsize);
+ break;
+ }
+ }
+
+ if (lut)
+ ImageLut(out, img->xsize * bpp, lut);
+
+ ImagePutRow(img, 0, y, img->xsize, out);
+ }
+
+ if (passes > 1)
+ {
+ if (info->color_type == PNG_COLOR_TYPE_GRAY ||
+ info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ inptr += img->xsize;
+ else
+ inptr += img->xsize * 3;
+ }
+ }
+
+ png_read_end(pp, info);
+ png_read_destroy(pp, info, NULL);
+
+ fclose(fp);
+ free(in);
+ free(out);
+
+ 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 000000000..c681d4e69
--- /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-2002 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 <ctype.h>
+
+
+/*
+ * '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 000000000..ea27aa03d
--- /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-2002 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], alpha = rows[3], 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 000000000..519038c6c
--- /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-2002 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 <stdio.h>
+# include <stdlib.h>
+# include <string.h>
+
+# 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 000000000..598c41ca6
--- /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-2002 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 000000000..418ca4643
--- /dev/null
+++ b/filter/image-sun.c
@@ -0,0 +1,377 @@
+/*
+ * "$Id$"
+ *
+ * Sun Raster image file routines for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1993-2002 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;
+ run_value = 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 000000000..5e2237d4f
--- /dev/null
+++ b/filter/image-tiff.c
@@ -0,0 +1,1707 @@
+/*
+ * "$Id$"
+ *
+ * TIFF file routines for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1993-2002 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.h> /* TIFF image definitions */
+# include <tiffio.h>
+# include <unistd.h>
+
+
+/*
+ * '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 */
+ compression, /* Type of compression */
+ orientation, /* Orientation */
+ resunit, /* Units for resolution */
+ samples, /* Number of samples/pixel */
+ bits, /* Number of bits/pixel */
+ inkset, /* Ink set for color separations */
+ numinks; /* Number of inks in set */
+ 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 */
+ row, /* Current row in image */
+ 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)
+ {
+ fputs("ERROR: TIFFFdOpen() failed!\n", stderr);
+ fclose(fp);
+ return (-1);
+ }
+
+ if (!TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width))
+ {
+ fputs("ERROR: No image width tag in the file!\n", stderr);
+ TIFFClose(tif);
+ fclose(fp);
+ return (-1);
+ }
+
+ if (!TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height))
+ {
+ fputs("ERROR: No image height tag in the file!\n", stderr);
+ TIFFClose(tif);
+ fclose(fp);
+ return (-1);
+ }
+
+ if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric))
+ {
+ fputs("ERROR: No photometric tag in the file!\n", stderr);
+ TIFFClose(tif);
+ fclose(fp);
+ return (-1);
+ }
+
+ if (!TIFFGetField(tif, TIFFTAG_COMPRESSION, &compression))
+ {
+ fputs("ERROR: No compression tag in the file!\n", stderr);
+ TIFFClose(tif);
+ fclose(fp);
+ return (-1);
+ }
+
+ if (!TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &samples))
+ samples = 1;
+
+ if (!TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bits))
+ bits = 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;
+ }
+
+ fprintf(stderr, "DEBUG: TIFF resolution = %fx%f, units=%d\n",
+ xres, yres, resunit);
+ fprintf(stderr, "DEBUG: Stored resolution = %dx%d PPI\n",
+ img->xppi, img->yppi);
+ }
+
+ /*
+ * 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 :
+ fputs("DEBUG: orientation = top-right\n", stderr);
+ break;
+ case ORIENTATION_RIGHTTOP :
+ fputs("DEBUG: orientation = right-top\n", stderr);
+ break;
+ default :
+ case ORIENTATION_TOPLEFT :
+ fputs("DEBUG: orientation = top-left\n", stderr);
+ break;
+ case ORIENTATION_LEFTTOP :
+ fputs("DEBUG: orientation = left-top\n", stderr);
+ break;
+ case ORIENTATION_BOTLEFT :
+ fputs("DEBUG: orientation = bottom-left\n", stderr);
+ break;
+ case ORIENTATION_LEFTBOT :
+ fputs("DEBUG: orientation = left-bottom\n", stderr);
+ break;
+ case ORIENTATION_BOTRIGHT :
+ fputs("DEBUG: orientation = bottom-right\n", stderr);
+ break;
+ case ORIENTATION_RIGHTBOT :
+ fputs("DEBUG: orientation = right-bottom\n", stderr);
+ break;
+ }
+
+ 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...
+ */
+
+ fprintf(stderr, "DEBUG: photometric = %d\n", photometric);
+ fprintf(stderr, "DEBUG: compression = %d\n", compression);
+
+ switch (photometric)
+ {
+ case PHOTOMETRIC_MINISWHITE :
+ case PHOTOMETRIC_MINISBLACK :
+ if (photometric == PHOTOMETRIC_MINISWHITE)
+ {
+ zero = 255;
+ one = 0;
+ }
+ else
+ {
+ zero = 0;
+ one = 255;
+ }
+
+ if (orientation < ORIENTATION_LEFTTOP)
+ {
+ /*
+ * Row major order...
+ */
+
+ for (y = ystart, ycount = img->ysize, row = 0;
+ ycount > 0;
+ ycount --, y += ydir, row ++)
+ {
+ if (bits == 1)
+ {
+ TIFFReadScanline(tif, scanline, row, 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, row, 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, row, 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, row, 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, row, 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, row = 0;
+ xcount > 0;
+ xcount --, x += xdir, row ++)
+ {
+ if (bits == 1)
+ {
+ TIFFReadScanline(tif, scanline, row, 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, row, 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, row, 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, row, 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, row, 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))
+ {
+ fputs("ERROR: No colormap tag in the file!\n", stderr);
+ 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, row = 0;
+ ycount > 0;
+ ycount --, y += ydir, row ++)
+ {
+ if (bits == 1)
+ {
+ TIFFReadScanline(tif, scanline, row, 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, row, 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, row, 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, row, 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, row = 0;
+ xcount > 0;
+ xcount --, x += xdir, row ++)
+ {
+ if (bits == 1)
+ {
+ TIFFReadScanline(tif, scanline, row, 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, row, 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, row, 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, row, 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, row = 0;
+ ycount > 0;
+ ycount --, y += ydir, row ++)
+ {
+ if (bits == 1)
+ {
+ TIFFReadScanline(tif, scanline, row, 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, row, 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, row, 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, row, 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, row, 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, row = 0;
+ xcount > 0;
+ xcount --, x += xdir, row ++)
+ {
+ if (bits == 1)
+ {
+ TIFFReadScanline(tif, scanline, row, 0);
+ for (ycount = img->ysize, scanptr = scanline, p = in + ystart * 3, bit = 0xf0;
+ ycount > 0;
+ ycount --, 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, row, 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, row, 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, row, 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, row, 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 :
+ if (!TIFFGetField(tif, TIFFTAG_INKSET, &inkset) &&
+ !TIFFGetField(tif, TIFFTAG_NUMBEROFINKS, &numinks))
+ {
+ fputs("ERROR: No inkset or number-of-inks tag in the file!\n", stderr);
+ fclose(fp);
+ return (-1);
+ }
+
+ if (inkset == INKSET_CMYK || numinks == 4)
+ {
+ if (orientation < ORIENTATION_LEFTTOP)
+ {
+ /*
+ * Row major order...
+ */
+
+ for (y = ystart, ycount = img->ysize, row = 0;
+ ycount > 0;
+ ycount --, y += ydir, row ++)
+ {
+ if (bits == 1)
+ {
+ TIFFReadScanline(tif, scanline, row, 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, row, 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, row, 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 if (img->colorspace == IMAGE_CMYK)
+ {
+ TIFFReadScanline(tif, scanline, row, 0);
+ ImagePutRow(img, 0, y, img->xsize, scanline);
+ }
+ else
+ {
+ TIFFReadScanline(tif, scanline, row, 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, row = 0;
+ xcount > 0;
+ xcount --, x += xdir, row ++)
+ {
+ if (bits == 1)
+ {
+ TIFFReadScanline(tif, scanline, row, 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, row, 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, row, 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 if (img->colorspace == IMAGE_CMYK)
+ {
+ TIFFReadScanline(tif, scanline, row, 0);
+ ImagePutCol(img, x, 0, img->ysize, scanline);
+ }
+ else
+ {
+ TIFFReadScanline(tif, scanline, row, 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);
+ fputs("ERROR: Unknown TIFF photometric value!\n", stderr);
+ 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 000000000..a9af072b5
--- /dev/null
+++ b/filter/image-zoom.c
@@ -0,0 +1,310 @@
+/*
+ * "$Id$"
+ *
+ * Image zoom routines for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1993-2002 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 000000000..c2065bf82
--- /dev/null
+++ b/filter/image.c
@@ -0,0 +1,773 @@
+/*
+ * "$Id$"
+ *
+ * Base image support for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1993-2002 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.
+ * 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 <unistd.h>
+#include <ctype.h>
+#include <math.h>
+#include <cups/cups.h>
+
+
+/*
+ * 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... */
+
+
+ fprintf(stderr, "DEBUG: ImageOpen(\"%s\", %d, %d, %d, %d, %p)\n",
+ filename ? filename : "(null)", primary, secondary,
+ saturation, hue, lut);
+
+ /*
+ * Range check...
+ */
+
+ if (filename == NULL)
+ {
+ fputs("ERROR: Image filename == NULL!\n", stderr);
+ return (NULL);
+ }
+
+ /*
+ * Figure out the file type...
+ */
+
+ if ((fp = fopen(filename, "r")) == NULL)
+ {
+ perror("ERROR: Unable to open image file");
+ return (NULL);
+ }
+
+ if (fread(header, 1, sizeof(header), fp) == 0)
+ {
+ perror("ERROR: Unable to read image file header");
+
+ 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)
+ {
+ perror("ERROR: Unable to allocate memory for image file");
+ 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 (memcmp(header, "BM", 2) == 0)
+ status = ImageReadBMP(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);
+ else if (memcmp(header + 8, "\000\010", 2) == 0 ||
+ memcmp(header + 8, "\000\030", 2) == 0)
+ status = ImageReadPIX(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, "\377\330\377", 3) == 0 && /* Start-of-Image */
+ header[3] >= 0xe0 && header[3] <= 0xef) /* APPn */
+ 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
+ {
+ fputs("ERROR: Unknown image file format!\n", stderr);
+ 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, next = NULL; current != NULL; current = next)
+ {
+ fprintf(stderr, "DEBUG: Freeing cache (%p, next = %p)...\n",
+ current, next);
+
+ next = current->next;
+ free(current);
+ }
+
+ /*
+ * Free the rest of memory...
+ */
+
+ if (img->tiles != NULL)
+ {
+ fprintf(stderr, "DEBUG: Freeing tiles (%p)...\n", img->tiles[0]);
+
+ free(img->tiles[0]);
+
+ fprintf(stderr, "DEBUG: Freeing tile pointers (%p)...\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);
+}
+
+
+/*
+ * '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 (%p)...\n",
+ img->num_ics, ic);
+ }
+ else
+ {
+ fprintf(stderr, "DEBUG: Flushing old cache tile (%p)...\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 %ld...\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 fd; /* Cache file descriptor */
+ 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)
+ {
+ if ((fd = cupsTempFd(img->cachename, sizeof(img->cachename))) < 0)
+ {
+ perror("ERROR: Unable to create image swap file");
+ tile->ic = NULL;
+ tile->dirty = 0;
+ return;
+ }
+
+ fprintf(stderr, "DEBUG: Created swap file \"%s\"...\n", img->cachename);
+
+ if ((img->cachefile = fdopen(fd, "wb+")) == NULL)
+ {
+ perror("ERROR: Unable to create image swap file");
+ close(fd);
+ unlink(img->cachename);
+ 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 %ld...\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 000000000..c33c49d84
--- /dev/null
+++ b/filter/image.h
@@ -0,0 +1,231 @@
+/*
+ * "$Id$"
+ *
+ * Image library definitions for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1993-2002 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 <stdio.h>
+# include <stdlib.h>
+# include <string.h>
+# include <errno.h>
+# include <config.h>
+
+
+/*
+ * 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 ImageReadBMP(image_t *img, FILE *fp, int primary, int secondary,
+ int saturation, int hue, const ib_t *lut);
+extern int ImageReadFPX(image_t *img, FILE *fp, int primary, int secondary,
+ int saturation, int hue, const ib_t *lut);
+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 ImageReadPIX(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 000000000..e87d97a06
--- /dev/null
+++ b/filter/imagetops.c
@@ -0,0 +1,870 @@
+/*
+ * "$Id$"
+ *
+ * Image file to PostScript filter for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1993-2002 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 <math.h>
+
+
+/*
+ * Globals...
+ */
+
+int Flip = 0, /* Flip/mirror pages */
+ XPosition = 0, /* Horizontal position on page */
+ YPosition = 0, /* Vertical position on page */
+ Collate = 0, /* Collate copies? */
+ Copies = 1; /* Number of copies */
+
+
+/*
+ * Local functions...
+ */
+
+static void ps_hex(ib_t *, int, 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;
+ float aspect; /* Aspect ratio */
+ 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 */
+ ppd_choice_t *choice; /* PPD option choice */
+ 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 xppi, yppi; /* Pixels-per-inch */
+ int hue, sat; /* Hue and saturation adjustment */
+ int realcopies; /* Real copies being printed */
+ float left, top; /* Left and top of image */
+ char filename[1024]; /* Name of file to print */
+ time_t curtime; /* Current time */
+ struct tm *curtm; /* Current date */
+ char curdate[255]; /* Current date string */
+
+
+ /*
+ * Make sure status messages are not buffered...
+ */
+
+ setbuf(stderr, NULL);
+
+ /*
+ * Check command-line...
+ */
+
+ if (argc < 6 || argc > 7)
+ {
+ fputs("ERROR: imagetops 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] ? argv[6] : "(null)");
+
+ /*
+ * Copy stdin as needed...
+ */
+
+ if (argc == 6)
+ {
+ int fd; /* File to write to */
+ char buffer[8192]; /* Buffer to read into */
+ int bytes; /* # of bytes to read */
+
+
+ if ((fd = cupsTempFd(filename, sizeof(filename))) < 0)
+ {
+ perror("ERROR: Unable to copy image file");
+ return (1);
+ }
+
+ fprintf(stderr, "DEBUG: imagetoraster - copying to temp print file \"%s\"\n",
+ filename);
+
+ while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0)
+ write(fd, buffer, bytes);
+
+ close(fd);
+ }
+ else
+ {
+ strncpy(filename, argv[6], sizeof(filename) - 1);
+ filename[sizeof(filename) - 1] = '\0';
+ }
+
+ /*
+ * Process command-line options and write the prolog...
+ */
+
+ zoom = 0.0;
+ xppi = 0;
+ yppi = 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-uncollated-copies allows for uncollated copies.
+ */
+
+ Collate = strcasecmp(val, "separate-documents-uncollated-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)
+ if (sscanf(val, "%dx%d", &xppi, &yppi) < 2)
+ yppi = xppi;
+
+ if ((val = cupsGetOption("position", num_options, options)) != NULL)
+ {
+ if (strcasecmp(val, "center") == 0)
+ {
+ XPosition = 0;
+ YPosition = 0;
+ }
+ else if (strcasecmp(val, "top") == 0)
+ {
+ XPosition = 0;
+ YPosition = 1;
+ }
+ else if (strcasecmp(val, "left") == 0)
+ {
+ XPosition = -1;
+ YPosition = 0;
+ }
+ else if (strcasecmp(val, "right") == 0)
+ {
+ XPosition = 1;
+ YPosition = 0;
+ }
+ else if (strcasecmp(val, "top-left") == 0)
+ {
+ XPosition = -1;
+ YPosition = 1;
+ }
+ else if (strcasecmp(val, "top-right") == 0)
+ {
+ XPosition = 1;
+ YPosition = 1;
+ }
+ else if (strcasecmp(val, "bottom") == 0)
+ {
+ XPosition = 0;
+ YPosition = -1;
+ }
+ else if (strcasecmp(val, "bottom-left") == 0)
+ {
+ XPosition = -1;
+ YPosition = -1;
+ }
+ else if (strcasecmp(val, "bottom-right") == 0)
+ {
+ XPosition = 1;
+ YPosition = -1;
+ }
+ }
+
+ 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;
+
+ img = ImageOpen(filename, colorspace, IMAGE_WHITE, sat, hue, NULL);
+
+ if (argc == 6)
+ unlink(filename);
+
+ if (img == NULL)
+ {
+ fputs("ERROR: Unable to open image file for printing!\n", stderr);
+ ppdClose(ppd);
+ return (1);
+ }
+
+ colorspace = img->colorspace;
+
+ /*
+ * Scale as necessary...
+ */
+
+ xprint = (PageRight - PageLeft) / 72.0;
+ yprint = (PageTop - PageBottom) / 72.0;
+
+ if (zoom == 0.0 && xppi == 0)
+ {
+ xppi = img->xppi;
+ yppi = img->yppi;
+ }
+
+ if (yppi == 0)
+ yppi = xppi;
+
+ if (xppi > 0)
+ {
+ /*
+ * Scale the image as neccesary to match the desired pixels-per-inch.
+ */
+
+ xinches = (float)img->xsize / (float)xppi;
+ yinches = (float)img->ysize / (float)yppi;
+
+ if ((val = cupsGetOption("natural-scaling", num_options, options)) != NULL)
+ {
+ xinches = xinches * atoi(val) / 100;
+ yinches = yinches * atoi(val) / 100;
+ }
+
+ if (cupsGetOption("orientation", num_options, options) == NULL &&
+ cupsGetOption("landscape", num_options, options) == NULL)
+ {
+ /*
+ * 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...
+ */
+
+ aspect = (float)img->yppi / (float)img->xppi;
+
+ fprintf(stderr, "DEBUG: img->xppi = %d, img->yppi = %d, aspect = %f\n",
+ img->xppi, img->yppi, aspect);
+
+ xsize = xprint * zoom;
+ ysize = xsize * img->ysize / img->xsize / aspect;
+
+ if (ysize > (yprint * zoom))
+ {
+ ysize = yprint * zoom;
+ xsize = ysize * img->xsize * aspect / img->ysize;
+ }
+
+ xsize2 = yprint * zoom;
+ ysize2 = xsize2 * img->ysize / img->xsize / aspect;
+
+ if (ysize2 > (xprint * zoom))
+ {
+ ysize2 = xprint * zoom;
+ xsize2 = ysize2 * img->xsize * aspect / img->ysize;
+ }
+
+ fprintf(stderr, "DEBUG: xsize = %.0f, ysize = %.0f\n", xsize, ysize);
+ fprintf(stderr, "DEBUG: xsize2 = %.0f, ysize2 = %.0f\n", xsize2, ysize2);
+
+ if (cupsGetOption("orientation", num_options, options) == NULL &&
+ cupsGetOption("landscape", num_options, options) == NULL)
+ {
+ /*
+ * 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;
+ }
+ }
+ else if (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
+ {
+ xinches = xsize;
+ yinches = ysize;
+ xprint = (PageRight - PageLeft) / 72.0;
+ yprint = (PageTop - PageBottom) / 72.0;
+ }
+ }
+
+ /*
+ * Compute the number of pages to print and the size of the image on each
+ * page...
+ */
+
+ xpages = ceil(xinches / xprint);
+ ypages = ceil(yinches / yprint);
+
+ xprint = xinches / xpages;
+ yprint = yinches / ypages;
+
+ /*
+ * Update the page size for custom sizes...
+ */
+
+ if ((choice = ppdFindMarkedChoice(ppd, "PageSize")) != NULL &&
+ strcasecmp(choice->choice, "Custom") == 0)
+ {
+ float width, /* New width in points */
+ length; /* New length in points */
+ char s[255]; /* New custom page size... */
+
+
+ if (Orientation & 1)
+ {
+ width = yprint * 72.0;
+ length = xprint * 72.0;
+ }
+ else
+ {
+ width = xprint * 72.0;
+ length = yprint * 72.0;
+ }
+
+ /*
+ * Add margins to page size...
+ */
+
+ width += ppd->custom_margins[0] + ppd->custom_margins[2];
+ length += ppd->custom_margins[1] + ppd->custom_margins[3];
+
+ /*
+ * Enforce minimums...
+ */
+
+ if (width < ppd->custom_min[0])
+ width = ppd->custom_min[0];
+
+ if (length < ppd->custom_min[1])
+ length = ppd->custom_min[1];
+
+ /*
+ * Set the new custom size...
+ */
+
+ sprintf(s, "Custom.%.0fx%.0f", width, length);
+ ppdMarkOption(ppd, "PageSize", s);
+
+ /*
+ * Update page variables...
+ */
+
+ PageWidth = width;
+ PageLength = length;
+ PageLeft = ppd->custom_margins[0];
+ PageRight = width - ppd->custom_margins[2];
+ PageBottom = ppd->custom_margins[1];
+ PageTop = length - ppd->custom_margins[3];
+
+ UpdatePageVars();
+ }
+
+ /*
+ * 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 (Copies > 1 && !slowcollate)
+ {
+ realcopies = Copies;
+ Copies = 1;
+ }
+ else
+ realcopies = 1;
+
+ /*
+ * 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...
+ */
+
+ ppdEmitJCL(ppd, stdout, atoi(argv[1]), argv[2], argv[3]);
+
+ /*
+ * Start sending the document with any commands needed...
+ */
+
+ curtime = time(NULL);
+ curtm = localtime(&curtime);
+
+ puts("%!PS-Adobe-3.0");
+ printf("%%%%BoundingBox: %.0f %.0f %.0f %.0f\n", PageLeft, PageBottom,
+ PageRight, PageTop);
+ printf("%%%%LanguageLevel: %d\n", LanguageLevel);
+ printf("%%%%Pages: %d\n", xpages * ypages * Copies);
+ puts("%%DocumentData: Clean7Bit");
+ puts("%%DocumentNeededResources: font Helvetica-Bold");
+ puts("%%Creator: imagetops/" CUPS_SVERSION);
+ strftime(curdate, sizeof(curdate), CUPS_STRFTIME_FORMAT, curtm);
+ printf("%%%%CreationDate: %s\n", curdate);
+ printf("%%%%Title: %s\n", argv[3]);
+ printf("%%%%For: %s\n", argv[2]);
+ if (Orientation & 1)
+ puts("%%Orientation: Landscape");
+ puts("%%EndComments");
+ puts("%%BeginProlog");
+
+ 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);
+
+ WriteLabelProlog(cupsGetOption("page-label", num_options, options),
+ PageBottom, PageTop, PageWidth);
+
+ if (realcopies > 1)
+ {
+ if (ppd == NULL || ppd->language_level == 1)
+ printf("/#copies %d def\n", realcopies);
+ else
+ printf("<</NumCopies %d>>setpagedevice\n", realcopies);
+ }
+
+ puts("%%EndProlog");
+
+ /*
+ * Output the pages...
+ */
+
+ 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 ++)
+ {
+ if (ppd && ppd->num_filters == 0)
+ fprintf(stderr, "PAGE: %d %d\n", page, realcopies);
+
+ fprintf(stderr, "INFO: Printing page %d...\n", page);
+
+ printf("%%%%Page: %d %d\n", page, 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;
+
+ switch (XPosition)
+ {
+ case -1 :
+ left = PageLeft;
+ break;
+ default :
+ left = (PageWidth - xprint * 72.0) * 0.5;
+ break;
+ case 1 :
+ left = PageRight - xprint * 72.0;
+ break;
+ }
+
+ switch (YPosition)
+ {
+ case -1 :
+ top = PageBottom + 72.0 * yprint;
+ break;
+ default :
+ top = (PageLength + yprint * 72.0) * 0.5;
+ break;
+ case 1 :
+ top = PageTop;
+ break;
+ }
+
+ printf("%.1f %.1f translate\n", left, top);
+
+ 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), y == y1);
+ }
+ }
+ 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");
+ WriteLabels(Orientation);
+ puts("showpage");
+ }
+
+ puts("%%EOF");
+
+ /*
+ * 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 last_line) /* I - Last line of raster data? */
+{
+ static int col = 0; /* Current column */
+ static char *hex = "0123456789ABCDEF";
+ /* Hex digits */
+
+
+ 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 += 2;
+ if (col > 78)
+ {
+ putchar('\n');
+ col = 0;
+ }
+ }
+
+ if (last_line && col)
+ {
+ putchar('\n');
+ col = 0;
+ }
+}
+
+
+/*
+ * '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 */
+ static int col = 0; /* Current column */
+
+
+ while (length > 3)
+ {
+ b = (((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3];
+
+ if (b == 0)
+ {
+ putchar('z');
+ col ++;
+ }
+ 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);
+ col += 5;
+ }
+
+ data += 4;
+ length -= 4;
+
+ if (col >= 75)
+ {
+ putchar('\n');
+ col = 0;
+ }
+ }
+
+ 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("~>");
+ col = 0;
+ }
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/imagetoraster.c b/filter/imagetoraster.c
new file mode 100644
index 000000000..6fef67201
--- /dev/null
+++ b/filter/imagetoraster.c
@@ -0,0 +1,4452 @@
+/*
+ * "$Id$"
+ *
+ * Image file to raster filter for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1993-2002 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...
+ * exec_code() - Execute PostScript setpagedevice commands as
+ * appropriate.
+ * 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 "common.h"
+#include "image.h"
+#include "raster.h"
+#include <unistd.h>
+#include <math.h>
+
+
+/*
+ * Globals...
+ */
+
+int Flip = 0, /* Flip/mirror pages */
+ XPosition = 0, /* Horizontal position on page */
+ YPosition = 0, /* Vertical position on page */
+ 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_code(cups_page_header_t *header, const char *code);
+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;
+ float aspect; /* Aspect ratio */
+ 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 */
+ **choices; /* List of marked choices */
+ int count; /* Number of marked choices */
+ 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 xppi, yppi; /* 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 */
+ char filename[1024]; /* Name of file to print */
+
+
+ /*
+ * Make sure status messages are not buffered...
+ */
+
+ setbuf(stderr, NULL);
+
+ /*
+ * Check command-line...
+ */
+
+ if (argc < 6 || 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] ? argv[6] : "(null)");
+
+ /*
+ * See if we need to use the imagetops and pstoraster filters instead...
+ */
+
+ options = NULL;
+ num_options = cupsParseOptions(argv[5], 0, &options);
+
+ if (getenv("CLASSIFICATION") ||
+ cupsGetOption("page-label", num_options, options))
+ {
+ /*
+ * Yes, fork a copy of pstoraster and then transfer control to imagetops...
+ */
+
+ int mypipes[2]; /* New pipes for imagetops | pstoraster */
+ int pid; /* PID of pstoraster */
+
+
+ cupsFreeOptions(num_options, options);
+
+ if (pipe(mypipes))
+ {
+ perror("ERROR: Unable to create pipes for imagetops | pstoraster");
+ return (errno);
+ }
+
+ if ((pid = fork()) == 0)
+ {
+ /*
+ * Child process for pstoraster... Assign new pipe input to pstoraster...
+ */
+
+ close(0);
+ dup(mypipes[0]);
+ close(mypipes[0]);
+ close(mypipes[1]);
+
+ execlp("pstoraster", argv[0], argv[1], argv[2], argv[3], argv[4], argv[5],
+ NULL);
+ perror("ERROR: Unable to exec pstoraster");
+ return (errno);
+ }
+ else if (pid < 0)
+ {
+ /*
+ * Error!
+ */
+
+ perror("ERROR: Unable to fork pstoraster");
+ return (errno);
+ }
+
+ /*
+ * Update stdout so it points at the new pstoraster...
+ */
+
+ close(1);
+ dup(mypipes[1]);
+ close(mypipes[0]);
+ close(mypipes[1]);
+
+ /*
+ * Run imagetops to get the classification or page labelling that was
+ * requested...
+ */
+
+ execlp("imagetops", argv[0], argv[1], argv[2], argv[3], argv[4], argv[5],
+ argv[6], NULL);
+ perror("ERROR: Unable to exec imagetops");
+ return (errno);
+ }
+
+ /*
+ * Copy stdin as needed...
+ */
+
+ if (argc == 6)
+ {
+ int fd; /* File to write to */
+ char buffer[8192]; /* Buffer to read into */
+ int bytes; /* # of bytes to read */
+
+
+ if ((fd = cupsTempFd(filename, sizeof(filename))) < 0)
+ {
+ perror("ERROR: Unable to copy image file");
+ return (1);
+ }
+
+ fprintf(stderr, "DEBUG: imagetoraster - copying to temp print file \"%s\"\n",
+ filename);
+
+ while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0)
+ write(fd, buffer, bytes);
+
+ close(fd);
+ }
+ else
+ {
+ strncpy(filename, argv[6], sizeof(filename) - 1);
+ filename[sizeof(filename) - 1] = '\0';
+ }
+
+ /*
+ * Process command-line options and write the prolog...
+ */
+
+ zoom = 0.0;
+ xppi = 0;
+ yppi = 0;
+ hue = 0;
+ sat = 100;
+ g = 1.0;
+ b = 1.0;
+
+ Copies = atoi(argv[4]);
+
+ 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)
+ if (sscanf(val, "%dx%d", &xppi, &yppi) < 2)
+ yppi = xppi;
+
+ if ((val = cupsGetOption("position", num_options, options)) != NULL)
+ {
+ if (strcasecmp(val, "center") == 0)
+ {
+ XPosition = 0;
+ YPosition = 0;
+ }
+ else if (strcasecmp(val, "top") == 0)
+ {
+ XPosition = 0;
+ YPosition = 1;
+ }
+ else if (strcasecmp(val, "left") == 0)
+ {
+ XPosition = -1;
+ YPosition = 0;
+ }
+ else if (strcasecmp(val, "right") == 0)
+ {
+ XPosition = 1;
+ YPosition = 0;
+ }
+ else if (strcasecmp(val, "top-left") == 0)
+ {
+ XPosition = -1;
+ YPosition = 1;
+ }
+ else if (strcasecmp(val, "top-right") == 0)
+ {
+ XPosition = 1;
+ YPosition = 1;
+ }
+ else if (strcasecmp(val, "bottom") == 0)
+ {
+ XPosition = 0;
+ YPosition = -1;
+ }
+ else if (strcasecmp(val, "bottom-left") == 0)
+ {
+ XPosition = -1;
+ YPosition = -1;
+ }
+ else if (strcasecmp(val, "bottom-right") == 0)
+ {
+ XPosition = 1;
+ YPosition = -1;
+ }
+ }
+
+ 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_K;
+
+ if (ppd && ppd->patches)
+ exec_code(&header, ppd->patches);
+
+ if ((count = ppdCollect(ppd, PPD_ORDER_DOCUMENT, &choices)) > 0)
+ for (i = 0; i < count; i ++)
+ exec_code(&header, choices[i]->code);
+
+ if ((count = ppdCollect(ppd, PPD_ORDER_ANY, &choices)) > 0)
+ for (i = 0; i < count; i ++)
+ exec_code(&header, choices[i]->code);
+
+ if ((count = ppdCollect(ppd, PPD_ORDER_PROLOG, &choices)) > 0)
+ for (i = 0; i < count; i ++)
+ exec_code(&header, choices[i]->code);
+
+ if ((count = ppdCollect(ppd, PPD_ORDER_PAGE, &choices)) > 0)
+ for (i = 0; i < count; i ++)
+ exec_code(&header, choices[i]->code);
+
+ /*
+ * Get the media type and resolution that have been chosen...
+ */
+
+ if ((choice = ppdFindMarkedChoice(ppd, "MediaType")) != NULL)
+ media_type = choice->choice;
+ else
+ media_type = "";
+
+ if ((choice = ppdFindMarkedChoice(ppd, "Resolution")) != NULL)
+ 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;
+ }
+ else
+ 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);
+
+ img = ImageOpen(filename, primary, secondary, sat, hue, lut);
+
+ if (argc == 6)
+ unlink(filename);
+
+ if (img == NULL)
+ {
+ fputs("ERROR: Unable to open image file for printing!\n", stderr);
+ ppdClose(ppd);
+ return (1);
+ }
+
+ /*
+ * Scale as necessary...
+ */
+
+ if (zoom == 0.0 && xppi == 0)
+ {
+ xppi = img->xppi;
+ yppi = img->yppi;
+ }
+
+ if (yppi == 0)
+ yppi = xppi;
+
+ if (xppi > 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)xppi;
+ yinches = (float)img->ysize / (float)yppi;
+
+ if ((val = cupsGetOption("natural-scaling", num_options, options)) != NULL)
+ {
+ xinches = xinches * atoi(val) / 100;
+ yinches = yinches * atoi(val) / 100;
+ }
+
+ if (cupsGetOption("orientation", num_options, options) == NULL &&
+ cupsGetOption("landscape", num_options, options) == NULL)
+ {
+ /*
+ * 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;
+ aspect = (float)img->yppi / (float)img->xppi;
+
+ fprintf(stderr, "DEBUG: img->xppi = %d, img->yppi = %d, aspect = %f\n",
+ img->xppi, img->yppi, aspect);
+
+ xsize = xprint * zoom;
+ ysize = xsize * img->ysize / img->xsize / aspect;
+
+ if (ysize > (yprint * zoom))
+ {
+ ysize = yprint * zoom;
+ xsize = ysize * img->xsize * aspect / img->ysize;
+ }
+
+ xsize2 = yprint * zoom;
+ ysize2 = xsize2 * img->ysize / img->xsize / aspect;
+
+ if (ysize2 > (xprint * zoom))
+ {
+ ysize2 = xprint * zoom;
+ xsize2 = ysize2 * img->xsize * aspect / img->ysize;
+ }
+
+ fprintf(stderr, "DEBUG: xsize = %.0f, ysize = %.0f\n", xsize, ysize);
+ fprintf(stderr, "DEBUG: xsize2 = %.0f, ysize2 = %.0f\n", xsize2, ysize2);
+
+ if (cupsGetOption("orientation", num_options, options) == NULL &&
+ cupsGetOption("landscape", num_options, options) == NULL)
+ {
+ /*
+ * 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;
+ }
+ }
+ else if (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
+ {
+ xinches = xsize;
+ yinches = ysize;
+ xprint = (PageRight - PageLeft) / 72.0;
+ yprint = (PageTop - PageBottom) / 72.0;
+ }
+ }
+
+ xpages = ceil(xinches / xprint);
+ ypages = ceil(yinches / yprint);
+
+ fprintf(stderr, "DEBUG: xpages = %d, ypages = %d\n", xpages, ypages);
+
+ /*
+ * Compute the bitmap size...
+ */
+
+ xprint = xinches / xpages;
+ yprint = yinches / ypages;
+
+ if ((choice = ppdFindMarkedChoice(ppd, "PageSize")) != NULL &&
+ strcasecmp(choice->choice, "Custom") == 0)
+ {
+ float width, /* New width in points */
+ length; /* New length in points */
+
+
+ if (Orientation & 1)
+ {
+ width = yprint * 72.0;
+ length = xprint * 72.0;
+ }
+ else
+ {
+ width = xprint * 72.0;
+ length = yprint * 72.0;
+ }
+
+ /*
+ * Add margins to page size...
+ */
+
+ width += ppd->custom_margins[0] + ppd->custom_margins[2];
+ length += ppd->custom_margins[1] + ppd->custom_margins[3];
+
+ /*
+ * Enforce minimums...
+ */
+
+ if (width < ppd->custom_min[0])
+ width = ppd->custom_min[0];
+
+ if (length < ppd->custom_min[1])
+ length = ppd->custom_min[1];
+
+ /*
+ * Set the new custom size...
+ */
+
+ header.PageSize[0] = width + 0.5;
+ header.PageSize[1] = length + 0.5;
+
+ /*
+ * Update page variables...
+ */
+
+ PageWidth = width;
+ PageLength = length;
+ PageLeft = ppd->custom_margins[0];
+ PageRight = width - ppd->custom_margins[2];
+ PageBottom = ppd->custom_margins[1];
+ PageTop = length - ppd->custom_margins[3];
+
+ /*
+ * Remove margins from page size...
+ */
+
+ width -= ppd->custom_margins[0] + ppd->custom_margins[2];
+ length -= ppd->custom_margins[1] + ppd->custom_margins[3];
+
+ /*
+ * Set the bitmap size...
+ */
+
+ header.cupsWidth = width * header.HWResolution[0] / 72.0;
+ header.cupsHeight = length * header.HWResolution[1] / 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;
+
+ fprintf(stderr, "DEBUG: PageSize = [%d %d]\n", header.PageSize[0],
+ header.PageSize[1]);
+
+ switch (Orientation)
+ {
+ case 0 :
+ switch (XPosition)
+ {
+ case -1 :
+ header.ImagingBoundingBox[0] = PageLeft;
+ header.ImagingBoundingBox[2] = PageLeft + xprint * 72;
+ break;
+ default :
+ header.ImagingBoundingBox[0] = (PageRight + PageLeft - xprint * 72) / 2;
+ header.ImagingBoundingBox[2] = (PageRight + PageLeft + xprint * 72) / 2;
+ break;
+ case 1 :
+ header.ImagingBoundingBox[0] = PageRight - xprint * 72;
+ header.ImagingBoundingBox[2] = PageRight;
+ break;
+ }
+
+ switch (YPosition)
+ {
+ case -1 :
+ header.ImagingBoundingBox[1] = PageBottom;
+ header.ImagingBoundingBox[3] = PageBottom + yprint * 72;
+ break;
+ default :
+ header.ImagingBoundingBox[1] = (PageTop + PageBottom - yprint * 72) / 2;
+ header.ImagingBoundingBox[3] = (PageTop + PageBottom + yprint * 72) / 2;
+ break;
+ case 1 :
+ header.ImagingBoundingBox[1] = PageTop - yprint * 72;
+ header.ImagingBoundingBox[3] = PageTop;
+ break;
+ }
+ break;
+
+ case 1 :
+ switch (XPosition)
+ {
+ case -1 :
+ header.ImagingBoundingBox[0] = PageBottom;
+ header.ImagingBoundingBox[2] = PageBottom + yprint * 72;
+ break;
+ default :
+ header.ImagingBoundingBox[0] = (PageTop + PageBottom - yprint * 72) / 2;
+ header.ImagingBoundingBox[2] = (PageTop + PageBottom + yprint * 72) / 2;
+ break;
+ case 1 :
+ header.ImagingBoundingBox[0] = PageTop - yprint * 72;
+ header.ImagingBoundingBox[2] = PageTop;
+ break;
+ }
+
+ switch (YPosition)
+ {
+ case -1 :
+ header.ImagingBoundingBox[1] = PageLeft;
+ header.ImagingBoundingBox[3] = PageLeft + xprint * 72;
+ break;
+ default :
+ header.ImagingBoundingBox[1] = (PageRight + PageLeft - xprint * 72) / 2;
+ header.ImagingBoundingBox[3] = (PageRight + PageLeft + xprint * 72) / 2;
+ break;
+ case 1 :
+ header.ImagingBoundingBox[1] = PageRight - xprint * 72;
+ header.ImagingBoundingBox[3] = PageRight;
+ break;
+ }
+ break;
+
+ case 2 :
+ switch (XPosition)
+ {
+ case 1 :
+ header.ImagingBoundingBox[0] = PageLeft;
+ header.ImagingBoundingBox[2] = PageLeft + xprint * 72;
+ break;
+ default :
+ header.ImagingBoundingBox[0] = (PageRight + PageLeft - xprint * 72) / 2;
+ header.ImagingBoundingBox[2] = (PageRight + PageLeft + xprint * 72) / 2;
+ break;
+ case -1 :
+ header.ImagingBoundingBox[0] = PageRight - xprint * 72;
+ header.ImagingBoundingBox[2] = PageRight;
+ break;
+ }
+
+ switch (YPosition)
+ {
+ case 1 :
+ header.ImagingBoundingBox[1] = PageBottom;
+ header.ImagingBoundingBox[3] = PageBottom + yprint * 72;
+ break;
+ default :
+ header.ImagingBoundingBox[1] = (PageTop + PageBottom - yprint * 72) / 2;
+ header.ImagingBoundingBox[3] = (PageTop + PageBottom + yprint * 72) / 2;
+ break;
+ case -1 :
+ header.ImagingBoundingBox[1] = PageTop - yprint * 72;
+ header.ImagingBoundingBox[3] = PageTop;
+ break;
+ }
+ break;
+
+ case 3 :
+ switch (XPosition)
+ {
+ case 1 :
+ header.ImagingBoundingBox[0] = PageBottom;
+ header.ImagingBoundingBox[2] = PageBottom + yprint * 72;
+ break;
+ default :
+ header.ImagingBoundingBox[0] = (PageTop + PageBottom - yprint * 72) / 2;
+ header.ImagingBoundingBox[2] = (PageTop + PageBottom + yprint * 72) / 2;
+ break;
+ case -1 :
+ header.ImagingBoundingBox[0] = PageTop - yprint * 72;
+ header.ImagingBoundingBox[2] = PageTop;
+ break;
+ }
+
+ switch (YPosition)
+ {
+ case 1 :
+ header.ImagingBoundingBox[1] = PageLeft;
+ header.ImagingBoundingBox[3] = PageLeft + xprint * 72;
+ break;
+ default :
+ header.ImagingBoundingBox[1] = (PageRight + PageLeft - xprint * 72) / 2;
+ header.ImagingBoundingBox[3] = (PageRight + PageLeft + xprint * 72) / 2;
+ break;
+ case -1 :
+ header.ImagingBoundingBox[1] = PageRight - xprint * 72;
+ header.ImagingBoundingBox[3] = PageRight;
+ break;
+ }
+ break;
+ }
+
+ switch (header.cupsColorOrder)
+ {
+ default :
+ 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 && YPosition <= 0)
+ {
+ memset(row, blank, header.cupsBytesPerLine);
+
+ y = header.cupsHeight - z->ysize;
+ if (YPosition == 0)
+ y /= 2;
+
+ for (; 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 && YPosition >= 0)
+ {
+ memset(row, blank, header.cupsBytesPerLine);
+
+ y = header.cupsHeight - z->ysize;
+ if (YPosition == 0)
+ y = y - y / 2;
+
+ for (; 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_code()' - Execute PostScript setpagedevice commands as appropriate.
+ */
+
+static void
+exec_code(cups_page_header_t *header, /* I - Page header */
+ const char *code) /* I - Option choice to execute */
+{
+ char *ptr, /* Pointer into name/value string */
+ name[255], /* Name of pagedevice entry */
+ value[1024]; /* Value of pagedevice entry */
+
+
+ for (; *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, (char **)&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 || /* Compatibility */
+ strcmp(name, "MediaPosition") == 0)
+ header->MediaPosition = atoi(value);
+ else if (strcmp(name, "MediaClass") == 0)
+ strncpy(header->MediaClass, value, sizeof(header->MediaClass) - 1);
+ else if (strcmp(name, "MediaColor") == 0)
+ strncpy(header->MediaColor, value, sizeof(header->MediaColor) - 1);
+ 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 */
+
+
+ switch (XPosition)
+ {
+ case -1 :
+ bitoffset = 0;
+ break;
+ default :
+ bitoffset = header->cupsBitsPerPixel * ((header->cupsWidth - xsize) / 2);
+ break;
+ case 1 :
+ bitoffset = header->cupsBitsPerPixel * (header->cupsWidth - xsize);
+ break;
+ }
+
+ 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 */
+
+
+ switch (XPosition)
+ {
+ case -1 :
+ bitoffset = 0;
+ break;
+ default :
+ bitoffset = header->cupsBitsPerPixel * ((header->cupsWidth - xsize) / 2);
+ break;
+ case 1 :
+ bitoffset = header->cupsBitsPerPixel * (header->cupsWidth - xsize);
+ break;
+ }
+
+ 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 */
+
+
+ (void)z;
+
+ switch (XPosition)
+ {
+ case -1 :
+ bitoffset = 0;
+ break;
+ default :
+ bitoffset = header->cupsBitsPerPixel * ((header->cupsWidth - xsize) / 2);
+ break;
+ case 1 :
+ bitoffset = header->cupsBitsPerPixel * (header->cupsWidth - xsize);
+ break;
+ }
+
+ 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 */
+
+
+ switch (XPosition)
+ {
+ case -1 :
+ bitoffset = 0;
+ break;
+ default :
+ bitoffset = header->cupsBitsPerPixel * ((header->cupsWidth - xsize) / 2);
+ break;
+ case 1 :
+ bitoffset = header->cupsBitsPerPixel * (header->cupsWidth - xsize);
+ break;
+ }
+
+ 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 */
+
+
+ switch (XPosition)
+ {
+ case -1 :
+ bitoffset = 0;
+ break;
+ default :
+ bitoffset = header->cupsBitsPerPixel * ((header->cupsWidth - xsize) / 2);
+ break;
+ case 1 :
+ bitoffset = header->cupsBitsPerPixel * (header->cupsWidth - xsize);
+ break;
+ }
+
+ 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 */
+
+
+ switch (XPosition)
+ {
+ case -1 :
+ bitoffset = 0;
+ break;
+ default :
+ bitoffset = header->cupsBitsPerPixel * ((header->cupsWidth - xsize) / 2);
+ break;
+ case 1 :
+ bitoffset = header->cupsBitsPerPixel * (header->cupsWidth - xsize);
+ break;
+ }
+
+ 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 */
+
+
+ (void)z;
+
+ switch (XPosition)
+ {
+ case -1 :
+ bitoffset = 0;
+ break;
+ default :
+ bitoffset = header->cupsBitsPerPixel * ((header->cupsWidth - xsize) / 2);
+ break;
+ case 1 :
+ bitoffset = header->cupsBitsPerPixel * (header->cupsWidth - xsize);
+ break;
+ }
+
+ 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 */
+
+
+ switch (XPosition)
+ {
+ case -1 :
+ bitoffset = 0;
+ break;
+ default :
+ bitoffset = header->cupsBitsPerPixel * ((header->cupsWidth - xsize) / 2);
+ break;
+ case 1 :
+ bitoffset = header->cupsBitsPerPixel * (header->cupsWidth - xsize);
+ break;
+ }
+
+ 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 */
+
+
+ switch (XPosition)
+ {
+ case -1 :
+ bitoffset = 0;
+ break;
+ default :
+ bitoffset = header->cupsBitsPerPixel * ((header->cupsWidth - xsize) / 2);
+ break;
+ case 1 :
+ bitoffset = header->cupsBitsPerPixel * (header->cupsWidth - xsize);
+ break;
+ }
+
+ 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 000000000..be58e93aa
--- /dev/null
+++ b/filter/pstops.c
@@ -0,0 +1,1147 @@
+/*
+ * "$Id$"
+ *
+ * PostScript filter for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1993-2002 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 */
+ UseESPsp = 0; /* Use ESPshowpage? */
+
+
+/*
+ * 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 tempfd; /* Temporary file descriptor */
+ int number; /* Page number */
+ int slowcollate; /* 1 if we need to collate manually */
+ int sloworder; /* 1 if we need to order manually */
+ int slowduplex; /* 1 if we need an even number of pages */
+ 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 real_page; /* "Real" page number in document */
+ int page_count; /* Page count for NUp */
+ int basepage; /* Base page number */
+ int subpage; /* Sub-page number */
+ int copy; /* Current copy */
+ int saweof; /* Did we see a %%EOF tag? */
+
+
+ /*
+ * Make sure status messages are not buffered...
+ */
+
+ setbuf(stderr, NULL);
+
+ /*
+ * Check command-line...
+ */
+
+ 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)
+ {
+ fprintf(stderr, "ERROR: unable to open print file \"%s\" - %s\n",
+ argv[6], strerror(errno));
+ 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-uncollated-copies allows for uncollated copies.
+ */
+
+ Collate = strcasecmp(val, "separate-documents-uncollated-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 (ppd && ppd->manual_copies && Duplex && Copies > 1)
+ {
+ /*
+ * Force collated copies when printing a duplexed document to
+ * a non-PS printer that doesn't do hardware copy generation.
+ * Otherwise the copies will end up on the front/back side of
+ * each page. Also, set the "slowduplex" option to make sure
+ * that we output an even number of pages...
+ */
+
+ Collate = 1;
+ slowduplex = 1;
+ }
+ else
+ slowduplex = 0;
+
+ 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)
+ {
+ tempfd = cupsTempFd(tempfile, sizeof(tempfile));
+ temp = fdopen(tempfd, "wb+");
+
+ if (temp == NULL)
+ slowcollate = sloworder = 0;
+ }
+ else
+ temp = 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...
+ */
+
+ ppdEmitJCL(ppd, stdout, atoi(argv[1]), argv[2], argv[3]);
+
+ /*
+ * 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);
+ }
+
+ /*
+ * See if this is an EPS file...
+ */
+
+ UseESPsp = strstr(line, "EPS") != NULL;
+
+ /*
+ * Start sending the document with any commands needed...
+ */
+
+ puts(line);
+
+ saweof = 0;
+
+ 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);
+
+ /*
+ * Figure out if we should use ESPshowpage or not...
+ */
+
+ val = cupsGetOption("page-label", num_options, options);
+
+ if (val != NULL || getenv("CLASSIFICATION") != NULL || NUp > 1)
+ {
+ /*
+ * Yes, use ESPshowpage...
+ */
+
+ UseESPsp = 1;
+ }
+
+ if (NUp == 2)
+ {
+ /*
+ * For 2-up output, rotate the labels to match the orientation
+ * of the pages...
+ */
+
+ if (Orientation & 1)
+ WriteLabelProlog(val, PageBottom, PageWidth - PageLength + PageTop,
+ PageLength);
+ else
+ WriteLabelProlog(val, PageLeft, PageRight, PageLength);
+ }
+ else
+ WriteLabelProlog(val, PageBottom, PageTop, PageWidth);
+
+ if (UseESPsp)
+ puts("userdict begin\n"
+ "/ESPshowpage /showpage load def\n"
+ "/showpage { } def\n"
+ "end");
+
+ if (Copies > 1 && (!Collate || !slowcollate))
+ {
+ if (Collate)
+ printf("%%%%Requirements: numcopies(%d) collate\n", Copies);
+ else
+ printf("%%%%Requirements: numcopies(%d)\n", Copies);
+
+ if (LanguageLevel == 1)
+ printf("/#copies %d def\n", Copies);
+ else
+ printf("<</NumCopies %d>>setpagedevice\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, "%%", 2) == 0)
+ fprintf(stderr, "DEBUG: %d %s", level, line);
+
+ if (strncmp(line, "%%BeginDocument:", 16) == 0 ||
+ strncmp(line, "%%BeginDocument ", 16) == 0) /* Adobe Acrobat BUG */
+ level ++;
+ else if (strncmp(line, "%%EndDocument", 13) == 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, "ASCII") == NULL && strstr(line, "Hex") == NULL))
+ {
+ /*
+ * Copy binary data...
+ */
+
+ tbytes = atoi(strchr(line, ':') + 1);
+ fputs(line, stdout);
+
+ while (tbytes > 0)
+ {
+ if (tbytes > sizeof(line))
+ nbytes = fread(line, 1, sizeof(line), fp);
+ else
+ nbytes = fread(line, 1, tbytes, fp);
+
+ if (nbytes < 1)
+ {
+ perror("ERROR: Early end-of-file while reading binary data");
+ return (1);
+ }
+
+ fwrite(line, 1, nbytes, stdout);
+ tbytes -= nbytes;
+ }
+ }
+ else
+ fputs(line, stdout);
+ }
+
+ /*
+ * Then read all of the pages, filtering as needed...
+ */
+
+ for (page = 1, real_page = 1;;)
+ {
+ if (strncmp(line, "%%", 2) == 0)
+ fprintf(stderr, "DEBUG: %d %s", level, line);
+
+ if (strncmp(line, "%%BeginDocument:", 16) == 0 ||
+ strncmp(line, "%%BeginDocument ", 16) == 0) /* Adobe Acrobat BUG */
+ level ++;
+ else if (strncmp(line, "%%EndDocument", 13) == 0 && level > 0)
+ level --;
+ else if (strcmp(line, "\004") == 0)
+ break;
+ else if (strncmp(line, "%%EOF", 5) == 0 && level == 0)
+ {
+ fputs("DEBUG: Saw EOF!\n", stderr);
+ saweof = 1;
+ break;
+ }
+ else if (strncmp(line, "%%Page:", 7) == 0 && level == 0)
+ {
+ if (!check_range(real_page))
+ {
+ 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)
+ {
+ real_page ++;
+ 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 ++;
+ real_page ++;
+ }
+ else if (strncmp(line, "%%BeginBinary:", 14) == 0 ||
+ (strncmp(line, "%%BeginData:", 12) == 0 &&
+ strstr(line, "ASCII") == NULL && strstr(line, "Hex") == NULL))
+ {
+ /*
+ * Copy binary data...
+ */
+
+ tbytes = atoi(strchr(line, ':') + 1);
+
+ if (!sloworder)
+ fputs(line, stdout);
+ if (slowcollate || sloworder)
+ fputs(line, temp);
+
+ while (tbytes > 0)
+ {
+ if (tbytes > sizeof(line))
+ nbytes = fread(line, 1, sizeof(line), fp);
+ else
+ nbytes = fread(line, 1, tbytes, fp);
+
+ if (nbytes < 1)
+ {
+ perror("ERROR: Early end-of-file while reading binary data");
+ return (1);
+ }
+
+ if (!sloworder)
+ fwrite(line, 1, nbytes, stdout);
+
+ if (slowcollate || sloworder)
+ fwrite(line, 1, nbytes, temp);
+
+ tbytes -= nbytes;
+ }
+ }
+ else if (strncmp(line, "%%Trailer", 9) == 0 && level == 0)
+ {
+ fputs("DEBUG: Saw Trailer!\n", stderr);
+ break;
+ }
+ else
+ {
+ if (!sloworder)
+ fputs(line, stdout);
+
+ if (slowcollate || sloworder)
+ fputs(line, 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 (slowduplex && !(page & 1))
+ {
+ /*
+ * Make sure we have an even number of pages...
+ */
+
+ 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(NUp - 1);
+ puts("showpage");
+ end_nup(NUp - 1);
+ }
+ }
+
+ if (slowcollate || sloworder)
+ {
+ Pages[NumPages] = ftell(temp);
+
+ if (!sloworder)
+ {
+ while (Copies > 1)
+ {
+ 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);
+ }
+
+ if (slowduplex && !(page & 1))
+ {
+ /*
+ * Make sure we have an even number of pages...
+ */
+
+ 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(NUp - 1);
+ puts("showpage");
+ end_nup(NUp - 1);
+ }
+
+ Copies --;
+ }
+ }
+ else
+ {
+ page_count = (NumPages + NUp - 1) / NUp;
+ copy = 0;
+
+ do
+ {
+ if (slowduplex && (page_count & 1))
+ {
+ basepage = page_count - 1;
+ }
+ else
+ basepage = page_count - 1 - slowduplex;
+
+ for (; basepage >= 0; basepage -= 1 + slowduplex)
+ {
+ if (ppd == NULL || ppd->num_filters == 0)
+ fprintf(stderr, "PAGE: %d %d\n", page,
+ slowcollate ? 1 : Copies);
+
+ printf("%%%%Page: %d %d\n", page, page);
+ page ++;
+
+ ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
+
+ for (subpage = 0, number = basepage * 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);
+ }
+
+ if (slowduplex)
+ {
+ if (number < NumPages)
+ {
+ if (ppd == NULL || ppd->num_filters == 0)
+ fprintf(stderr, "PAGE: %d %d\n", page,
+ slowcollate ? 1 : Copies);
+
+ printf("%%%%Page: %d %d\n", page, page);
+ page ++;
+
+ ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
+
+ for (subpage = 0, number = (basepage + 1) * 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);
+ }
+ }
+ else
+ {
+ /*
+ * Make sure we have an even number of pages...
+ */
+
+ if (ppd == NULL || ppd->num_filters == 0)
+ fprintf(stderr, "PAGE: %d %d\n", page, slowcollate ? 1 : Copies);
+
+ printf("%%%%Page: %d %d\n", page, page);
+ page ++;
+ ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
+
+ start_nup(NUp - 1);
+ puts("showpage");
+ end_nup(NUp - 1);
+
+ basepage = page_count - 1;
+ }
+ }
+ }
+
+ copy ++;
+ }
+ while (copy < Copies && slowcollate);
+ }
+ }
+
+ /*
+ * Copy the trailer, if any...
+ */
+
+ while (psgets(line, sizeof(line), fp) != NULL)
+ {
+ if (strcmp(line, "\004") != 0)
+ fputs(line, stdout);
+
+ if (strncmp(line, "%%EOF", 5) == 0)
+ {
+ fputs("DEBUG: Saw EOF!\n", stderr);
+ saweof = 1;
+ break;
+ }
+ }
+ }
+ 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);
+
+ saweof = 1;
+
+ while ((nbytes = fread(line, 1, sizeof(line), fp)) > 0)
+ {
+ fwrite(line, 1, nbytes, stdout);
+
+ if (slowcollate)
+ fwrite(line, 1, nbytes, temp);
+ }
+
+ if (UseESPsp)
+ puts("ESPshowpage");
+
+ 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);
+ Copies --;
+
+ if (UseESPsp)
+ puts("ESPshowpage");
+ }
+ }
+ }
+
+ /*
+ * Send %%EOF if needed...
+ */
+
+ if (!saweof)
+ puts("%%EOF");
+
+ /*
+ * End the job with the appropriate JCL command or CTRL-D otherwise.
+ */
+
+ if (ppd != NULL && ppd->jcl_end)
+ fputs(ppd->jcl_end, stdout);
+ else if (ppd != NULL && ppd->num_filters == 0)
+ 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) % (NUp << 1)) < NUp)
+ return (0);
+ if (strcasecmp(PageSet, "odd") == 0 && ((page - 1) % (NUp << 1)) >= NUp)
+ 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) || length == 0)
+ 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("userdict /ESPsave get restore");
+
+ switch (NUp)
+ {
+ case 1 :
+ if (UseESPsp)
+ {
+ WriteLabels(Orientation);
+ puts("ESPshowpage");
+ }
+ break;
+
+ case 2 :
+ if ((number & 1) == 1 && UseESPsp)
+ {
+ if (Orientation & 1)
+ {
+ /*
+ * Rotate the labels back to portrait...
+ */
+
+ WriteLabels(Orientation - 1);
+ }
+ else
+ {
+ /*
+ * Rotate the labels to landscape...
+ */
+
+ WriteLabels(Orientation + 1);
+ }
+
+ puts("ESPshowpage");
+ }
+ break;
+
+ case 4 :
+ if ((number & 3) == 3 && UseESPsp)
+ {
+ WriteLabels(Orientation);
+ 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;
+ ch = EOF;
+
+ 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... */
+
+ ch = 0x0a;
+ break;
+ }
+ else if (ch == 0x0a)
+ break;
+ else
+ *bufptr++ = ch;
+ }
+
+ /*
+ * Add a trailing newline if it is there...
+ */
+
+ if (ch == '\n')
+ *bufptr++ = '\n';
+
+ /*
+ * 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("userdict /ESPsave save put");
+
+ if (Flip)
+ printf("%.1f 0.0 translate -1 1 scale\n", PageWidth);
+
+ pw = PageRight - PageLeft;
+ pl = PageTop - PageBottom;
+
+ fprintf(stderr, "DEBUG: pw = %.1f, pl = %.1f\n", pw, pl);
+ fprintf(stderr, "DEBUG: PageLeft = %.1f, PageRight = %.1f\n", PageLeft, PageRight);
+ fprintf(stderr, "DEBUG: PageTop = %.1f, PageBottom = %.1f\n", PageTop, PageBottom);
+ fprintf(stderr, "DEBUG: PageWidth = %.1f, PageLength = %.1f\n", PageWidth, PageLength);
+
+ switch (Orientation)
+ {
+ case 1 : /* Landscape */
+ printf("%.1f 0.0 translate 90 rotate\n", PageLength);
+ break;
+ case 2 : /* Reverse Portrait */
+ printf("%.1f %.1f translate 180 rotate\n", PageWidth, PageLength);
+ break;
+ case 3 : /* Reverse Landscape */
+ printf("0.0 %.1f 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("%.1f %.1f translate\n", PageWidth - PageRight, PageBottom);
+ else
+ printf("%.1f %.1f translate\n", PageLeft, PageBottom);
+
+ if (Orientation & 1)
+ {
+ printf("0.0 %.1f translate -90 rotate\n", pl);
+ printf("%.1f %.1f translate %.3f %.3f scale\n",
+ ty, tx + l * x, w / PageWidth, l / PageLength);
+ }
+ else
+ {
+ printf("%.1f 0.0 translate 90 rotate\n", pw);
+ printf("%.1f %.1f translate %.3f %.3f scale\n",
+ tx + w * x, ty, w / PageWidth, l / PageLength);
+ }
+
+ printf("newpath\n"
+ "0.0 0.0 moveto\n"
+ "%.1f 0.0 lineto\n"
+ "%.1f %.1f lineto\n"
+ "0.0 %.1f 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("%.1f %.1f translate\n", PageWidth - PageRight, PageBottom);
+ else
+ printf("%.1f %.1f translate\n", PageLeft, PageBottom);
+
+ printf("%.1f %.1f translate %.3f %.3f scale\n", x * w, y * l,
+ w / PageWidth, l / PageLength);
+ printf("newpath\n"
+ "0.0 0.0 moveto\n"
+ "%.1f 0.0 lineto\n"
+ "%.1f %.1f lineto\n"
+ "0.0 %.1f 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 000000000..316b07777
--- /dev/null
+++ b/filter/raster.c
@@ -0,0 +1,252 @@
+/*
+ * "$Id$"
+ *
+ * Raster file routines for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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 <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#if defined(WIN32) || defined(__EMX__)
+# include <io.h>
+#else
+# include <unistd.h>
+#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 000000000..00cefe2bc
--- /dev/null
+++ b/filter/raster.h
@@ -0,0 +1,233 @@
+/*
+ * "$Id$"
+ *
+ * Raster file definitions for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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/rastertodymo.c b/filter/rastertodymo.c
new file mode 100644
index 000000000..aef71745d
--- /dev/null
+++ b/filter/rastertodymo.c
@@ -0,0 +1,361 @@
+/*
+ * "$Id$"
+ *
+ * DYMO label printer filter for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 2001 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.
+ * CancelJob() - Cancel the current job...
+ * CompressData() - Compress a line of graphics.
+ * OutputLine() - Output a line of graphics.
+ * main() - Main entry and processing of driver.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups.h>
+#include <cups/string.h>
+#include "raster.h"
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+
+
+/*
+ * Globals...
+ */
+
+unsigned char *Buffer; /* Output buffer */
+int Page, /* Current page */
+ Feed; /* Number of lines to skip */
+
+
+/*
+ * Prototypes...
+ */
+
+void Setup(void);
+void StartPage(cups_page_header_t *header);
+void EndPage(void);
+
+void CancelJob(int sig);
+
+/**** MRS - supported resolutions = 136, 203, 300 ****/
+
+
+/*
+ * 'Setup()' - Prepare the printer for printing.
+ */
+
+void
+Setup(void)
+{
+ int i; /* Looping var */
+
+
+ /*
+ * Clear any remaining data...
+ */
+
+ for (i = 0; i < 100; i ++)
+ putchar(0x1b);
+}
+
+
+/*
+ * 'StartPage()' - Start a page of graphics.
+ */
+
+void
+StartPage(cups_page_header_t *header) /* I - Page header */
+{
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ struct sigaction action; /* Actions for POSIX signals */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+
+
+ /*
+ * Register a signal handler to eject the current page if the
+ * job is cancelled.
+ */
+
+#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
+ sigset(SIGTERM, CancelJob);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+
+ sigemptyset(&action.sa_mask);
+ action.sa_handler = CancelJob;
+ sigaction(SIGTERM, &action, NULL);
+#else
+ signal(SIGTERM, CancelJob);
+#endif /* HAVE_SIGSET */
+
+ /*
+ * Setup printer/job attributes...
+ */
+
+ printf("\033L%c%c", header->cupsHeight, header->cupsHeight >> 8);
+ printf("\033D%c", header->cupsBytesPerLine);
+
+ printf("\033%c", header->cupsCompression + 'c'); /* Darkness */
+
+ /*
+ * Allocate memory for a line of graphics...
+ */
+
+ Buffer = malloc(header->cupsBytesPerLine);
+ Feed = 0;
+}
+
+
+/*
+ * 'EndPage()' - Finish a page of graphics.
+ */
+
+void
+EndPage(void)
+{
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ struct sigaction action; /* Actions for POSIX signals */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+
+
+ /*
+ * Eject the current page...
+ */
+
+ printf("\033E");
+
+ fflush(stdout);
+
+ /*
+ * Unregister the signal handler...
+ */
+
+#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
+ sigset(SIGTERM, SIG_IGN);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+
+ sigemptyset(&action.sa_mask);
+ action.sa_handler = SIG_IGN;
+ sigaction(SIGTERM, &action, NULL);
+#else
+ signal(SIGTERM, SIG_IGN);
+#endif /* HAVE_SIGSET */
+
+ /*
+ * Free memory...
+ */
+
+ free(Buffer);
+}
+
+
+/*
+ * 'CancelJob()' - Cancel the current job...
+ */
+
+void
+CancelJob(int sig) /* I - Signal */
+{
+ int i; /* Looping var */
+
+
+ (void)sig;
+
+ /*
+ * Send out lots of ESC bytes to clear out any pending raster data...
+ */
+
+ for (i = 0; i < 100; i ++)
+ putchar(0x1b);
+
+ /*
+ * End the current page and exit...
+ */
+
+ EndPage();
+
+ exit(0);
+}
+
+
+/*
+ * '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 y; /* Current line */
+
+
+ /*
+ * Make sure status messages are not buffered...
+ */
+
+ setbuf(stderr, NULL);
+
+ /*
+ * Check command-line...
+ */
+
+ if (argc < 6 || argc > 7)
+ {
+ /*
+ * We don't have the correct number of arguments; write an error message
+ * and return.
+ */
+
+ fputs("ERROR: rastertodymo 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 1\n", Page);
+
+ /*
+ * 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 & 15) == 0)
+ fprintf(stderr, "INFO: Printing page %d, %d%% complete...\n", Page,
+ 100 * y / header.cupsHeight);
+
+ /*
+ * Read a line of graphics...
+ */
+
+ if (cupsRasterReadPixels(ras, Buffer, header.cupsBytesPerLine) < 1)
+ break;
+
+ /*
+ * See if the line is blank; if not, write it to the printer...
+ */
+
+ if (Buffer[0] ||
+ memcmp(Buffer, Buffer + 1, header.cupsBytesPerLine - 1))
+ {
+ if (Feed)
+ {
+ printf("\033f\001%c", Feed);
+ Feed = 0;
+ }
+ putchar(0x16);
+ fwrite(Buffer, header.cupsBytesPerLine, 1, stdout);
+ }
+ else
+ Feed ++;
+ }
+
+ /*
+ * Eject the page...
+ */
+
+ EndPage();
+ }
+
+ /*
+ * 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: " CUPS_SVERSION " is ready to print.\n", stderr);
+
+ return (Page == 0);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/rastertoepson.c b/filter/rastertoepson.c
new file mode 100644
index 000000000..7615adf5e
--- /dev/null
+++ b/filter/rastertoepson.c
@@ -0,0 +1,1131 @@
+/*
+ * "$Id$"
+ *
+ * EPSON ESC/P and ESC/P2 filter for the Common UNIX Printing System
+ * (CUPS).
+ *
+ * Copyright 1993-2002 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 <cups/cups.h>
+#include <cups/ppd.h>
+#include <cups/string.h>
+#include "raster.h"
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+
+
+/*
+ * Model numbers...
+ */
+
+#define EPSON_9PIN 0
+#define EPSON_24PIN 1
+#define EPSON_COLOR 2
+#define EPSON_PHOTO 3
+#define EPSON_ICOLOR 4
+#define EPSON_IPHOTO 5
+
+
+/*
+ * Macros...
+ */
+
+#define pwrite(s,n) fwrite((s), 1, (n), stdout)
+
+
+/*
+ * Globals...
+ */
+
+unsigned char *Planes[6], /* Output buffers */
+ *CompBuffer, /* Compression buffer */
+ *LineBuffers[2]; /* Line bitmap buffers */
+int Model, /* Model number */
+ NumPlanes, /* Number of color planes */
+ Feed; /* Number of lines to skip */
+int DotBit, /* Bit in buffers */
+ DotBytes, /* # bytes in a dot column */
+ DotColumns, /* # columns in 1/60 inch */
+ LineCount, /* # of lines processed */
+ EvenOffset, /* Offset into 'even' buffers */
+ OddOffset, /* Offset into 'odd' buffers */
+ Shingling; /* Shingle output? */
+
+
+/*
+ * Prototypes...
+ */
+
+void Setup(void);
+void StartPage(const ppd_file_t *ppd, const cups_page_header_t *header);
+void EndPage(const cups_page_header_t *header);
+void Shutdown(void);
+
+void CancelJob(int sig);
+void CompressData(const unsigned char *line, int length, int plane,
+ int type, int xstep, int ystep);
+void OutputLine(const cups_page_header_t *header);
+void OutputRows(const cups_page_header_t *header, int row);
+
+
+/*
+ * 'Setup()' - Prepare the printer for printing.
+ */
+
+void
+Setup(void)
+{
+ const char *device_uri; /* The device for the printer... */
+
+
+ /*
+ * EPSON USB printers need an additional command issued at the
+ * beginning of each job to exit from "packet" mode...
+ */
+
+ if ((device_uri = getenv("DEVICE_URI")) != NULL &&
+ strncmp(device_uri, "usb:", 4) == 0)
+ pwrite("\000\000\000\033\001@EJL 1284.4\n@EJL \n\033@", 29);
+}
+
+
+/*
+ * 'StartPage()' - Start a page of graphics.
+ */
+
+void
+StartPage(const ppd_file_t *ppd, /* I - PPD file */
+ const cups_page_header_t *header) /* I - Page header */
+{
+ int n, t; /* Numbers */
+ int plane; /* Looping var */
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ struct sigaction action; /* Actions for POSIX signals */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+
+
+ /*
+ * Register a signal handler to eject the current page if the
+ * job is cancelled.
+ */
+
+#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
+ sigset(SIGTERM, CancelJob);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+
+ sigemptyset(&action.sa_mask);
+ action.sa_handler = CancelJob;
+ sigaction(SIGTERM, &action, NULL);
+#else
+ signal(SIGTERM, CancelJob);
+#endif /* HAVE_SIGSET */
+
+ /*
+ * Send a reset sequence.
+ */
+
+ if (ppd->nickname && strstr(ppd->nickname, "OKIDATA") != NULL)
+ printf("\033{A"); /* Set EPSON emulation mode */
+
+ printf("\033@");
+
+ /*
+ * See which type of printer we are using...
+ */
+
+ Model = ppd->model_number;
+
+ switch (ppd->model_number)
+ {
+ case EPSON_9PIN :
+ case EPSON_24PIN :
+ printf("\033P"); /* Set 10 CPI */
+
+ if (header->HWResolution[0] == 360 || header->HWResolution[0] == 240)
+ {
+ printf("\033x1"); /* LQ printing */
+ printf("\033U1"); /* Unidirectional */
+ }
+ else
+ {
+ printf("\033x0"); /* Draft printing */
+ printf("\033U0"); /* Bidirectional */
+ }
+
+ printf("\033l%c\033Q%c", 0, /* Side margins */
+ (int)(10.0 * header->PageSize[0] / 72.0 + 0.5));
+ printf("\033C%c%c", 0, /* Page length */
+ (int)(header->PageSize[1] / 72.0 + 0.5));
+ printf("\033N%c", 0); /* Bottom margin */
+
+ /*
+ * Setup various buffer limits...
+ */
+
+ DotBytes = header->cupsRowCount / 8;
+ DotColumns = header->HWResolution[0] / 60;
+ Shingling = 0;
+
+ if (ppd->model_number == EPSON_9PIN)
+ printf("\033\063\030"); /* Set line feed */
+ else
+ switch (header->HWResolution[0])
+ {
+ case 60:
+ case 120 :
+ printf("\033\063\030"); /* Set line feed */
+ break;
+
+ case 180 :
+ case 360 :
+ Shingling = 1;
+
+ if (header->HWResolution[1] == 180)
+ printf("\033\063\010");/* Set line feed */
+ else
+ printf("\033+\010"); /* Set line feed */
+ break;
+ }
+ break;
+
+ default :
+ /*
+ * Set graphics mode...
+ */
+
+ pwrite("\033(G\001\000\001", 6); /* Graphics mode */
+
+ /*
+ * Set the media size...
+ */
+
+ if (Model < EPSON_ICOLOR)
+ {
+ pwrite("\033(U\001\000", 5); /* Resolution/units */
+ putchar(3600 / header->HWResolution[1]);
+ }
+ else
+ {
+ pwrite("\033(U\005\000", 5);
+ putchar(1440 / header->HWResolution[1]);
+ putchar(1440 / header->HWResolution[1]);
+ putchar(1440 / header->HWResolution[0]);
+ putchar(0xa0); /* n/1440ths... */
+ putchar(0x05);
+ }
+
+ 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);
+
+ 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 */
+
+ DotBytes = 0;
+ DotColumns = 0;
+ Shingling = 0;
+ break;
+ }
+
+ /*
+ * 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;
+
+ Feed = 0; /* No blank lines yet */
+
+ /*
+ * Allocate memory for a line/row of graphics...
+ */
+
+ Planes[0] = malloc(header->cupsBytesPerLine);
+ for (plane = 1; plane < NumPlanes; plane ++)
+ Planes[plane] = Planes[0] + plane * header->cupsBytesPerLine / NumPlanes;
+
+ if (header->cupsCompression || DotBytes)
+ CompBuffer = calloc(2, header->cupsWidth);
+ else
+ CompBuffer = NULL;
+
+ if (DotBytes)
+ {
+ LineBuffers[0] = calloc(DotBytes, header->cupsWidth * (Shingling + 1));
+ LineBuffers[1] = LineBuffers[0] + DotBytes * header->cupsWidth;
+ DotBit = 128;
+ LineCount = 0;
+ EvenOffset = 0;
+ OddOffset = 0;
+ }
+}
+
+
+/*
+ * 'EndPage()' - Finish a page of graphics.
+ */
+
+void
+EndPage(const cups_page_header_t *header) /* I - Page header */
+{
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ struct sigaction action; /* Actions for POSIX signals */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+
+
+ if (DotBytes && header)
+ {
+ /*
+ * Flush remaining graphics as needed...
+ */
+
+ if (!Shingling)
+ OutputRows(header, 0);
+ else if (OddOffset > EvenOffset)
+ {
+ OutputRows(header, 1);
+ OutputRows(header, 0);
+ }
+ else
+ {
+ OutputRows(header, 0);
+ OutputRows(header, 1);
+ }
+ }
+
+ /*
+ * Eject the current page...
+ */
+
+ putchar(12); /* Form feed */
+ fflush(stdout);
+
+ /*
+ * Unregister the signal handler...
+ */
+
+#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
+ sigset(SIGTERM, SIG_IGN);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+
+ sigemptyset(&action.sa_mask);
+ action.sa_handler = SIG_IGN;
+ sigaction(SIGTERM, &action, NULL);
+#else
+ signal(SIGTERM, SIG_IGN);
+#endif /* HAVE_SIGSET */
+
+ /*
+ * Free memory...
+ */
+
+ free(Planes[0]);
+
+ if (CompBuffer)
+ free(CompBuffer);
+
+ if (DotBytes)
+ free(LineBuffers[0]);
+}
+
+
+/*
+ * 'Shutdown()' - Shutdown the printer.
+ */
+
+void
+Shutdown(void)
+{
+ /*
+ * Send a reset sequence.
+ */
+
+ printf("\033@");
+}
+
+
+/*
+ * 'CancelJob()' - Cancel the current job...
+ */
+
+void
+CancelJob(int sig) /* I - Signal */
+{
+ int i; /* Looping var */
+
+
+ (void)sig;
+
+ /*
+ * Send out lots of NUL bytes to clear out any pending raster data...
+ */
+
+ if (DotBytes)
+ i = DotBytes * 360 * 8;
+ else
+ i = 720;
+
+ for (; i > 0; i --)
+ putchar(0);
+
+ /*
+ * End the current page and exit...
+ */
+
+ EndPage(NULL);
+ Shutdown();
+
+ exit(0);
+}
+
+
+/*
+ * 'CompressData()' - Compress a line of graphics.
+ */
+
+void
+CompressData(const 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 */
+{
+ const unsigned char *line_ptr, /* Current byte pointer */
+ *line_end, /* End-of-line byte pointer */
+ *start; /* Start of compression sequence */
+ unsigned char *comp_ptr, /* Pointer into compression buffer */
+ temp; /* Current byte */
+ int count; /* Count of bytes for output */
+ static int ctable[6] = { 0, 2, 1, 4, 18, 17 };
+ /* KCMYcm color values */
+
+
+ /*
+ * Setup pointers...
+ */
+
+ line_ptr = line;
+ line_end = line + length;
+
+ /*
+ * Do depletion for 720 DPI printing...
+ */
+
+ if (ystep == 5)
+ {
+ for (comp_ptr = (unsigned char *)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;
+ }
+
+ putchar(0x0d); /* Move print head to left margin */
+
+ if (Model < EPSON_ICOLOR)
+ {
+ /*
+ * Do graphics the "old" way...
+ */
+
+ if (NumPlanes > 1)
+ {
+ /*
+ * Set the color...
+ */
+
+ if (plane > 3)
+ printf("\033(r%c%c%c%c", 2, 0, 1, ctable[plane] & 15);
+ /* 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...
+ */
+
+ length *= 8;
+ printf("\033."); /* Raster graphics */
+ putchar(type);
+ putchar(ystep);
+ putchar(xstep);
+ putchar(1);
+ putchar(length);
+ putchar(length >> 8);
+ }
+ else
+ {
+ /*
+ * Do graphics the "new" way...
+ */
+
+ printf("\033i");
+ putchar(ctable[plane]);
+ putchar(type);
+ putchar(1);
+ putchar(length & 255);
+ putchar(length >> 8);
+ putchar(1);
+ putchar(0);
+ }
+
+ pwrite(line_ptr, line_end - line_ptr);
+ fflush(stdout);
+}
+
+
+/*
+ * 'OutputLine()' - Output a line of graphics.
+ */
+
+void
+OutputLine(const cups_page_header_t *header) /* I - Page header */
+{
+ if (header->cupsRowCount)
+ {
+ int width;
+ unsigned char *tempptr,
+ *evenptr,
+ *oddptr;
+ register int x;
+ unsigned char bit;
+ const unsigned char *pixel;
+ unsigned char *temp;
+
+
+ /*
+ * Collect bitmap data in the line buffers and write after each buffer.
+ */
+
+ for (x = header->cupsWidth, bit = 128, pixel = Planes[0],
+ temp = CompBuffer;
+ x > 0;
+ x --, temp ++)
+ {
+ if (*pixel & bit)
+ *temp |= DotBit;
+
+ if (bit > 1)
+ bit >>= 1;
+ else
+ {
+ bit = 128;
+ pixel ++;
+ }
+ }
+
+ if (DotBit > 1)
+ DotBit >>= 1;
+ else
+ {
+ /*
+ * Copy the holding buffer to the output buffer, shingling as necessary...
+ */
+
+ if (Shingling && LineCount != 0)
+ {
+ /*
+ * Shingle the output...
+ */
+
+ if (LineCount & 1)
+ {
+ evenptr = LineBuffers[1] + OddOffset;
+ oddptr = LineBuffers[0] + EvenOffset + DotBytes;
+ }
+ else
+ {
+ evenptr = LineBuffers[0] + EvenOffset;
+ oddptr = LineBuffers[1] + OddOffset + DotBytes;
+ }
+
+ for (width = header->cupsWidth, tempptr = CompBuffer;
+ width > 0;
+ width -= 2, tempptr += 2, oddptr += DotBytes * 2,
+ evenptr += DotBytes * 2)
+ {
+ evenptr[0] = tempptr[0];
+ oddptr[0] = tempptr[1];
+ }
+ }
+ else
+ {
+ /*
+ * Don't shingle the output...
+ */
+
+ for (width = header->cupsWidth, tempptr = CompBuffer,
+ evenptr = LineBuffers[0] + EvenOffset;
+ width >= 0;
+ width --, tempptr ++, evenptr += DotBytes)
+ *evenptr = tempptr[0];
+ }
+
+ if (Shingling && LineCount != 0)
+ {
+ EvenOffset ++;
+ OddOffset ++;
+
+ if (EvenOffset == DotBytes)
+ {
+ EvenOffset = 0;
+ OutputRows(header, 0);
+ }
+
+ if (OddOffset == DotBytes)
+ {
+ OddOffset = 0;
+ OutputRows(header, 1);
+ }
+ }
+ else
+ {
+ EvenOffset ++;
+
+ if (EvenOffset == DotBytes)
+ {
+ EvenOffset = 0;
+ OutputRows(header, 0);
+ }
+ }
+
+ DotBit = 128;
+ LineCount ++;
+
+ memset(CompBuffer, 0, header->cupsWidth);
+ }
+ }
+ else
+ {
+ int plane; /* Current plane */
+ int bytes; /* Bytes per plane */
+ int xstep, ystep; /* X & Y resolutions */
+
+
+ /*
+ * Write a single line of 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 ++;
+ }
+}
+
+
+/*
+ * 'OutputRows()' - Output 8, 24, or 48 rows.
+ */
+
+void
+OutputRows(const cups_page_header_t *header, /* I - Page image header */
+ int row) /* I - Row number (0 or 1) */
+{
+ unsigned i, n; /* Looping vars */
+ int dot_count, /* Number of bytes to print */
+ dot_min; /* Minimum number of bytes */
+ unsigned char *dot_ptr, /* Pointer to print data */
+ *ptr; /* Current data */
+
+
+ dot_min = DotBytes * DotColumns;
+
+ if (LineBuffers[row][0] != 0 ||
+ memcmp(LineBuffers[row], LineBuffers[row] + 1,
+ header->cupsWidth * DotBytes - 1))
+ {
+ /*
+ * Skip leading space...
+ */
+
+ i = 0;
+ dot_count = header->cupsWidth * DotBytes;
+ dot_ptr = LineBuffers[row];
+
+ while (dot_count >= dot_min && dot_ptr[0] == 0 &&
+ memcmp(dot_ptr, dot_ptr + 1, dot_min - 1) == 0)
+ {
+ i ++;
+ dot_ptr += dot_min;
+ dot_count -= dot_min;
+ }
+
+ /*
+ * Skip trailing space...
+ */
+
+ while (dot_count >= dot_min && dot_ptr[dot_count - dot_min] == 0 &&
+ memcmp(dot_ptr + dot_count - dot_min,
+ dot_ptr + dot_count - dot_min + 1, dot_min - 1) == 0)
+ dot_count -= dot_min;
+
+ /*
+ * Position print head for printing...
+ */
+
+ putchar(0x1b);
+ putchar('$');
+ putchar(i & 255);
+ putchar(i >> 8);
+
+ /*
+ * Start bitmap graphics for this line...
+ */
+
+ printf("\033*"); /* Select bit image */
+ switch (header->HWResolution[0])
+ {
+ case 60 : /* 60x60/72 DPI gfx */
+ putchar(0);
+ break;
+ case 120 : /* 120x60/72 DPI gfx */
+ putchar(1);
+ break;
+ case 180 : /* 180 DPI gfx */
+ putchar(39);
+ break;
+ case 240 : /* 240x72 DPI gfx */
+ putchar(3);
+ break;
+ case 360 : /* 360x180/360 DPI gfx */
+ if (header->HWResolution[1] == 180)
+ {
+ if (Shingling && LineCount != 0)
+ putchar(40); /* 360x180 fast */
+ else
+ putchar(41); /* 360x180 slow */
+ }
+ else
+ {
+ if (Shingling && LineCount != 0)
+ putchar(72); /* 360x360 fast */
+ else
+ putchar(73); /* 360x360 slow */
+ }
+ break;
+ }
+
+ n = (unsigned)dot_count / DotBytes;
+ putchar(n & 255);
+ putchar(n / 256);
+
+ /*
+ * Write the graphics data...
+ */
+
+ if (header->HWResolution[0] == 120 ||
+ header->HWResolution[0] == 240)
+ {
+ /*
+ * Need to interleave the dots to avoid hosing the print head...
+ */
+
+ for (n = dot_count / 2, ptr = dot_ptr; n > 0; n --, ptr += 2)
+ {
+ putchar(*ptr);
+ putchar(0);
+ }
+
+ /*
+ * Move the head back and print the odd bytes...
+ */
+
+ putchar(0x1b);
+ putchar('$');
+ putchar(i & 255);
+ putchar(i >> 8);
+
+ if (header->HWResolution[0] == 120)
+ printf("\033*\001"); /* Select bit image */
+ else
+ printf("\033*\003"); /* Select bit image */
+
+ n = (unsigned)dot_count / DotBytes;
+ putchar(n & 255);
+ putchar(n / 256);
+
+ for (n = dot_count / 2, ptr = dot_ptr + 1; n > 0; n --, ptr += 2)
+ {
+ putchar(0);
+ putchar(*ptr);
+ }
+ }
+ else
+ pwrite(dot_ptr, dot_count);
+ }
+
+ /*
+ * Feed the paper...
+ */
+
+ putchar('\n');
+
+ if (Shingling && row == 1)
+ {
+ if (header->HWResolution[1] == 360)
+ printf("\n\n\n\n");
+ else
+ printf("\n");
+ }
+
+ fflush(stdout);
+
+ /*
+ * Clear the buffer...
+ */
+
+ memset(LineBuffers[row], 0, header->cupsWidth * DotBytes);
+}
+
+
+/*
+ * '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 */
+
+
+ /*
+ * Make sure status messages are not buffered...
+ */
+
+ setbuf(stderr, NULL);
+
+ /*
+ * Check command-line...
+ */
+
+ 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(ppd, &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;
+
+ /*
+ * 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: " CUPS_SVERSION " is 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 000000000..ba13b03e5
--- /dev/null
+++ b/filter/rastertohp.c
@@ -0,0 +1,806 @@
+/*
+ * "$Id$"
+ *
+ * Hewlett-Packard Page Control Language filter for the Common UNIX
+ * Printing System (CUPS).
+ *
+ * Copyright 1993-2002 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.
+ * CancelJob() - Cancel the current job...
+ * CompressData() - Compress a line of graphics.
+ * OutputLine() - Output a line of graphics.
+ * main() - Main entry and processing of driver.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups.h>
+#include <cups/string.h>
+#include "raster.h"
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+
+
+/*
+ * Globals...
+ */
+
+unsigned char *Planes[4], /* Output buffers */
+ *CompBuffer, /* Compression buffer */
+ *BitBuffer; /* Buffer for output bits */
+int NumPlanes, /* Number of color planes */
+ ColorBits, /* Number of bits per color */
+ Feed, /* Number of lines to skip */
+ Duplex, /* Current duplex mode */
+ Page; /* Current page number */
+
+
+/*
+ * Prototypes...
+ */
+
+void Setup(void);
+void StartPage(ppd_file_t *ppd, cups_page_header_t *header);
+void EndPage(void);
+void Shutdown(void);
+
+void CancelJob(int sig);
+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(ppd_file_t *ppd, /* I - PPD file */
+ cups_page_header_t *header) /* I - Page header */
+{
+ int plane; /* Looping var */
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ struct sigaction action; /* Actions for POSIX signals */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+
+
+ /*
+ * Register a signal handler to eject the current page if the
+ * job is cancelled.
+ */
+
+#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
+ sigset(SIGTERM, CancelJob);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+
+ sigemptyset(&action.sa_mask);
+ action.sa_handler = CancelJob;
+ sigaction(SIGTERM, &action, NULL);
+#else
+ signal(SIGTERM, CancelJob);
+#endif /* HAVE_SIGSET */
+
+ /*
+ * Setup printer/job attributes...
+ */
+
+ Duplex = header->Duplex;
+ ColorBits = header->cupsBitsPerColor;
+
+ if (!Duplex || (Page & 1))
+ {
+ /*
+ * Set the media type, position, and size...
+ */
+
+ printf("\033&l6D\033&k12H"); /* Set 6 LPI, 10 CPI */
+ printf("\033&l0O"); /* Set portrait orientation */
+
+ switch (header->PageSize[1])
+ {
+ case 540 : /* Monarch Envelope */
+ printf("\033&l80A"); /* Set page size */
+ break;
+
+ case 624 : /* DL Envelope */
+ printf("\033&l90A"); /* Set page size */
+ break;
+
+ case 649 : /* C5 Envelope */
+ printf("\033&l91A"); /* Set page size */
+ break;
+
+ case 684 : /* COM-10 Envelope */
+ printf("\033&l81A"); /* Set page size */
+ break;
+
+ case 709 : /* B5 Envelope */
+ printf("\033&l100A"); /* Set page size */
+ break;
+
+ case 756 : /* Executive */
+ printf("\033&l1A"); /* Set page size */
+ break;
+
+ case 792 : /* Letter */
+ printf("\033&l2A"); /* Set page size */
+ break;
+
+ case 842 : /* A4 */
+ printf("\033&l26A"); /* Set page size */
+ break;
+
+ case 1008 : /* Legal */
+ printf("\033&l3A"); /* Set page size */
+ break;
+
+ case 1191 : /* A3 */
+ printf("\033&l27A"); /* Set page size */
+ break;
+
+ case 1224 : /* Tabloid */
+ printf("\033&l6A"); /* Set page size */
+ break;
+ }
+
+ printf("\033&l%dP", /* Set page length */
+ header->PageSize[1] / 12);
+ printf("\033&l0E"); /* Set top margin to 0 */
+
+ printf("\033&l%dX", header->NumCopies); /* Set number copies */
+
+ if (header->MediaPosition)
+ printf("\033&l%dH", /* Set media position */
+ header->MediaPosition);
+
+ if (header->cupsMediaType)
+ printf("\033&l%dM", /* Set media type */
+ header->cupsMediaType);
+
+ if (header->Duplex)
+ printf("\033&l%dS", /* Set duplex mode */
+ header->Duplex + header->Tumble);
+
+ printf("\033&l0L"); /* Turn off perforation skip */
+
+ if (ppd && ppd->model_number == 2)
+ printf("\033&l-2H"); /* Load media */
+ }
+ else
+ printf("\033&a2G"); /* Set back side */
+
+ /*
+ * Set graphics mode...
+ */
+
+ printf("\033*t%dR", header->HWResolution[0]); /* Set resolution */
+
+ if (ppd->model_number == 2)
+ {
+ /*
+ * Figure out the number of color planes...
+ */
+
+ if (header->cupsColorSpace == CUPS_CSPACE_KCMY)
+ NumPlanes = 4;
+ else
+ NumPlanes = 1;
+
+ /*
+ * Send 26-byte configure image data command with horizontal and
+ * vertical resolutions as well as a color count...
+ */
+
+ printf("\033*g26W");
+ putchar(2); /* Format 2 */
+ putchar(NumPlanes); /* Output planes */
+
+ putchar(header->HWResolution[0] >> 8); /* Black resolution */
+ putchar(header->HWResolution[0]);
+ putchar(header->HWResolution[1] >> 8);
+ putchar(header->HWResolution[1]);
+ putchar(0);
+ putchar(1 << ColorBits); /* # of black levels */
+
+ putchar(header->HWResolution[0] >> 8); /* Cyan resolution */
+ putchar(header->HWResolution[0]);
+ putchar(header->HWResolution[1] >> 8);
+ putchar(header->HWResolution[1]);
+ putchar(0);
+ putchar(1 << ColorBits); /* # of cyan levels */
+
+ putchar(header->HWResolution[0] >> 8); /* Magenta resolution */
+ putchar(header->HWResolution[0]);
+ putchar(header->HWResolution[1] >> 8);
+ putchar(header->HWResolution[1]);
+ putchar(0);
+ putchar(1 << ColorBits); /* # of magenta levels */
+
+ putchar(header->HWResolution[0] >> 8); /* Yellow resolution */
+ putchar(header->HWResolution[0]);
+ putchar(header->HWResolution[1] >> 8);
+ putchar(header->HWResolution[1]);
+ putchar(0);
+ putchar(1 << ColorBits); /* # of yellow levels */
+ }
+ else
+ {
+ if (header->cupsColorSpace == CUPS_CSPACE_KCMY)
+ {
+ NumPlanes = 4;
+ printf("\033*r-4U"); /* Set KCMY graphics */
+ }
+ else if (header->cupsColorSpace == CUPS_CSPACE_CMY)
+ {
+ NumPlanes = 3;
+ printf("\033*r-3U"); /* Set CMY graphics */
+ }
+ else
+ NumPlanes = 1; /* Black&white graphics */
+ }
+
+ /*
+ * Set size and position of graphics...
+ */
+
+ printf("\033*r%dS", header->cupsWidth); /* Set width */
+ printf("\033*r%dT", header->cupsHeight); /* Set height */
+
+ printf("\033&a0H"); /* Set horizontal position */
+
+ if (ppd)
+ printf("\033&a%.0fV", /* Set vertical position */
+ 10.0 * (ppd->sizes[0].length - ppd->sizes[0].top));
+ else
+ printf("\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 (ColorBits > 1)
+ BitBuffer = malloc(ColorBits * ((header->cupsWidth + 7) / 8));
+ else
+ BitBuffer = NULL;
+
+ if (header->cupsCompression)
+ CompBuffer = malloc(header->cupsBytesPerLine * 2);
+ else
+ CompBuffer = NULL;
+}
+
+
+/*
+ * 'EndPage()' - Finish a page of graphics.
+ */
+
+void
+EndPage(void)
+{
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ struct sigaction action; /* Actions for POSIX signals */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+
+
+ /*
+ * Eject the current page...
+ */
+
+ if (NumPlanes > 1)
+ {
+ printf("\033*rC"); /* End color GFX */
+
+ if (!(Duplex && (Page & 1)))
+ printf("\033&l0H"); /* Eject current page */
+ }
+ else
+ {
+ printf("\033*r0B"); /* End GFX */
+
+ if (!(Duplex && (Page & 1)))
+ printf("\014"); /* Eject current page */
+ }
+
+ fflush(stdout);
+
+ /*
+ * Unregister the signal handler...
+ */
+
+#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
+ sigset(SIGTERM, SIG_IGN);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+
+ sigemptyset(&action.sa_mask);
+ action.sa_handler = SIG_IGN;
+ sigaction(SIGTERM, &action, NULL);
+#else
+ signal(SIGTERM, SIG_IGN);
+#endif /* HAVE_SIGSET */
+
+ /*
+ * Free memory...
+ */
+
+ free(Planes[0]);
+
+ if (BitBuffer)
+ free(BitBuffer);
+
+ if (CompBuffer)
+ free(CompBuffer);
+}
+
+
+/*
+ * 'Shutdown()' - Shutdown the printer.
+ */
+
+void
+Shutdown(void)
+{
+ /*
+ * Send a PCL reset sequence.
+ */
+
+ putchar(0x1b);
+ putchar('E');
+}
+
+
+/*
+ * 'CancelJob()' - Cancel the current job...
+ */
+
+void
+CancelJob(int sig) /* I - Signal */
+{
+ int i; /* Looping var */
+
+
+ (void)sig;
+
+ /*
+ * Send out lots of NUL bytes to clear out any pending raster data...
+ */
+
+ for (i = 0; i < 600; i ++)
+ putchar(0);
+
+ /*
+ * End the current page and exit...
+ */
+
+ EndPage();
+ Shutdown();
+
+ exit(0);
+}
+
+
+/*
+ * '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)
+ {
+ default :
+ /*
+ * 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 */
+ bytes, /* Bytes to write */
+ count; /* Bytes to convert */
+ unsigned char bit, /* Current plane data */
+ bit0, /* Current low bit data */
+ bit1, /* Current high bit data */
+ *plane_ptr, /* Pointer into Planes */
+ *bit_ptr; /* Pointer into BitBuffer */
+
+
+ /*
+ * Output whitespace as needed...
+ */
+
+ if (Feed > 0)
+ {
+ printf("\033*b%dY", Feed);
+ Feed = 0;
+ }
+
+ /*
+ * Write bitmap data as needed...
+ */
+
+ bytes = (header->cupsWidth + 7) / 8;
+
+ for (plane = 0; plane < NumPlanes; plane ++)
+ if (ColorBits == 1)
+ {
+ /*
+ * Send bits as-is...
+ */
+
+ CompressData(Planes[plane], bytes, plane < (NumPlanes - 1) ? 'V' : 'W',
+ header->cupsCompression);
+ }
+ else
+ {
+ /*
+ * Separate low and high bit data into separate buffers.
+ */
+
+ for (count = header->cupsBytesPerLine / NumPlanes,
+ plane_ptr = Planes[plane], bit_ptr = BitBuffer;
+ count > 0;
+ count -= 2, plane_ptr += 2, bit_ptr ++)
+ {
+ bit = plane_ptr[0];
+
+ bit0 = ((bit & 64) << 1) | ((bit & 16) << 2) | ((bit & 4) << 3) | ((bit & 1) << 4);
+ bit1 = (bit & 128) | ((bit & 32) << 1) | ((bit & 8) << 2) | ((bit & 2) << 3);
+
+ if (count > 1)
+ {
+ bit = plane_ptr[1];
+
+ bit0 |= (bit & 1) | ((bit & 4) >> 1) | ((bit & 16) >> 2) | ((bit & 64) >> 3);
+ bit1 |= ((bit & 2) >> 1) | ((bit & 8) >> 2) | ((bit & 32) >> 3) | ((bit & 128) >> 4);
+ }
+
+ bit_ptr[0] = bit0;
+ bit_ptr[bytes] = bit1;
+ }
+
+ /*
+ * Send low and high bits...
+ */
+
+ CompressData(BitBuffer, bytes, 'V', header->cupsCompression);
+ CompressData(BitBuffer + bytes, bytes, plane < (NumPlanes - 1) ? 'V' : 'W',
+ header->cupsCompression);
+ }
+
+ fflush(stdout);
+}
+
+
+/*
+ * '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 y; /* Current line */
+ ppd_file_t *ppd; /* PPD file */
+
+
+ /*
+ * Make sure status messages are not buffered...
+ */
+
+ setbuf(stderr, NULL);
+
+ /*
+ * Check command-line...
+ */
+
+ 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...
+ */
+
+ 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(ppd, &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();
+ }
+
+ /*
+ * Shutdown the printer...
+ */
+
+ Shutdown();
+
+ if (ppd)
+ 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: " CUPS_SVERSION " is 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 000000000..87e26134a
--- /dev/null
+++ b/filter/textcommon.c
@@ -0,0 +1,1155 @@
+/*
+ * "$Id$"
+ *
+ * Common text filter routines for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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 */
+float CharsPerInch = 10; /* Number of character columns per inch */
+float LinesPerInch = 6; /* Number of lines per inch */
+int UTF8 = 0; /* Use UTF-8 encoding? */
+int NumKeywords = 0; /* Number of known keywords */
+char **Keywords = NULL; /* List of known keywords */
+
+
+/*
+ * Local globals...
+ */
+
+static char *code_keywords[] = /* List of known C/C++ 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"
+ },
+ *sh_keywords[] = /* List of known Boure/Korn/zsh/bash keywords... */
+ {
+ "alias",
+ "bg",
+ "break",
+ "case",
+ "cd",
+ "command",
+ "continue",
+ "do",
+ "done",
+ "echo",
+ "elif",
+ "else",
+ "esac",
+ "eval",
+ "exec",
+ "exit",
+ "export",
+ "fc",
+ "fg",
+ "fi",
+ "for",
+ "function",
+ "getopts",
+ "if",
+ "in",
+ "jobs",
+ "kill",
+ "let",
+ "limit",
+ "newgrp",
+ "print",
+ "pwd",
+ "read",
+ "readonly",
+ "return",
+ "select",
+ "set",
+ "shift",
+ "test",
+ "then",
+ "time",
+ "times",
+ "trap",
+ "typeset",
+ "ulimit",
+ "umask",
+ "unalias",
+ "unlimit",
+ "unset",
+ "until",
+ "wait",
+ "whence"
+ "while",
+ },
+ *csh_keywords[] = /* List of known csh/tcsh keywords... */
+ {
+ "alias",
+ "aliases",
+ "bg",
+ "bindkey",
+ "break",
+ "breaksw",
+ "builtins",
+ "case",
+ "cd",
+ "chdir",
+ "complete",
+ "continue",
+ "default",
+ "dirs",
+ "echo",
+ "echotc",
+ "else",
+ "end",
+ "endif",
+ "eval",
+ "exec",
+ "exit",
+ "fg",
+ "foreach",
+ "glob",
+ "goto",
+ "history",
+ "if",
+ "jobs",
+ "kill",
+ "limit",
+ "login",
+ "logout",
+ "ls",
+ "nice",
+ "nohup",
+ "notify",
+ "onintr",
+ "popd",
+ "pushd",
+ "pwd",
+ "rehash",
+ "repeat",
+ "set",
+ "setenv",
+ "settc",
+ "shift",
+ "source",
+ "stop",
+ "suspend",
+ "switch",
+ "telltc",
+ "then",
+ "time",
+ "umask",
+ "unalias",
+ "unbindkey",
+ "unhash",
+ "unlimit",
+ "unset",
+ "unsetenv",
+ "wait",
+ "where",
+ "which",
+ "while"
+ },
+ *perl_keywords[] = /* List of known perl keywords... */
+ {
+ "abs",
+ "accept",
+ "alarm",
+ "and",
+ "atan2",
+ "bind",
+ "binmode",
+ "bless",
+ "caller",
+ "chdir",
+ "chmod",
+ "chomp",
+ "chop",
+ "chown",
+ "chr",
+ "chroot",
+ "closdir",
+ "close",
+ "connect",
+ "continue",
+ "cos",
+ "crypt",
+ "dbmclose",
+ "dbmopen",
+ "defined",
+ "delete",
+ "die",
+ "do",
+ "dump",
+ "each",
+ "else",
+ "elsif",
+ "endgrent",
+ "endhostent",
+ "endnetent",
+ "endprotoent",
+ "endpwent",
+ "endservent",
+ "eof",
+ "eval",
+ "exec",
+ "exists",
+ "exit",
+ "exp",
+ "fcntl",
+ "fileno",
+ "flock",
+ "for",
+ "foreach",
+ "fork",
+ "format",
+ "formline",
+ "getc",
+ "getgrent",
+ "getgrgid",
+ "getgrnam",
+ "gethostbyaddr",
+ "gethostbyname",
+ "gethostent",
+ "getlogin",
+ "getnetbyaddr",
+ "getnetbyname",
+ "getnetent",
+ "getpeername",
+ "getpgrp",
+ "getppid",
+ "getpriority",
+ "getprotobyname",
+ "getprotobynumber",
+ "getprotoent",
+ "getpwent",
+ "getpwnam",
+ "getpwuid",
+ "getservbyname",
+ "getservbyport",
+ "getservent",
+ "getsockname",
+ "getsockopt",
+ "glob",
+ "gmtime",
+ "goto",
+ "grep",
+ "hex",
+ "if",
+ "import",
+ "index",
+ "int",
+ "ioctl",
+ "join",
+ "keys",
+ "kill",
+ "last",
+ "lc",
+ "lcfirst",
+ "length",
+ "link",
+ "listen",
+ "local",
+ "localtime",
+ "log",
+ "lstat",
+ "map",
+ "mkdir",
+ "msgctl",
+ "msgget",
+ "msgrcv",
+ "msgsend",
+ "my",
+ "next",
+ "no",
+ "not",
+ "oct",
+ "open",
+ "opendir",
+ "or",
+ "ord",
+ "pack",
+ "package",
+ "pipe",
+ "pop",
+ "pos",
+ "print",
+ "printf",
+ "push",
+ "quotemeta",
+ "rand",
+ "read",
+ "readdir",
+ "readlink",
+ "recv",
+ "redo",
+ "ref",
+ "rename",
+ "require",
+ "reset",
+ "return",
+ "reverse",
+ "rewinddir",
+ "rindex",
+ "rmdir",
+ "scalar",
+ "seek",
+ "seekdir",
+ "select",
+ "semctl",
+ "semget",
+ "semop",
+ "send",
+ "setgrent",
+ "sethostent",
+ "setnetent",
+ "setpgrp",
+ "setpriority",
+ "setprotoent",
+ "setpwent",
+ "setservent",
+ "setsockopt",
+ "shift",
+ "shmctl",
+ "shmget",
+ "shmread",
+ "shmwrite",
+ "shutdown",
+ "sin",
+ "sleep",
+ "socket",
+ "socketpair",
+ "sort",
+ "splice",
+ "split",
+ "sprintf",
+ "sqrt",
+ "srand",
+ "stat",
+ "study",
+ "sub",
+ "substr",
+ "symlink",
+ "syscall",
+ "sysread",
+ "sysseek",
+ "system",
+ "syswrite",
+ "tell",
+ "telldir",
+ "tie",
+ "tied",
+ "time",
+ "times"
+ "times",
+ "truncate",
+ "uc",
+ "ucfirst",
+ "umask",
+ "undef",
+ "unless",
+ "unlink",
+ "unpack",
+ "unshift",
+ "untie",
+ "until",
+ "use",
+ "utime",
+ "values",
+ "vec",
+ "wait",
+ "waitpid",
+ "wantarray",
+ "warn",
+ "while",
+ "write"
+ };
+
+
+/*
+ * 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(const 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 */
+
+
+ /*
+ * Make sure status messages are not buffered...
+ */
+
+ setbuf(stderr, NULL);
+
+ /*
+ * Check command-line...
+ */
+
+ 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)
+ {
+ PageLeft = 72.0f;
+ PageRight = PageWidth - 36.0f;
+ PageBottom = PageBottom > 36.0f ? PageBottom : 36.0f;
+ PageTop = PageLength - 36.0f;
+ CharsPerInch = 12;
+ LinesPerInch = 8;
+
+ if ((val = getenv("CONTENT_TYPE")) == NULL)
+ {
+ PrettyPrint = PRETTY_CODE;
+ NumKeywords = sizeof(code_keywords) / sizeof(code_keywords[0]);
+ Keywords = code_keywords;
+ }
+ else if (strcasecmp(val, "application/x-cshell") == 0)
+ {
+ PrettyPrint = PRETTY_SHELL;
+ NumKeywords = sizeof(csh_keywords) / sizeof(csh_keywords[0]);
+ Keywords = csh_keywords;
+ }
+ else if (strcasecmp(val, "application/x-perl") == 0)
+ {
+ PrettyPrint = PRETTY_PERL;
+ NumKeywords = sizeof(perl_keywords) / sizeof(perl_keywords[0]);
+ Keywords = perl_keywords;
+ }
+ else if (strcasecmp(val, "application/x-shell") == 0)
+ {
+ PrettyPrint = PRETTY_SHELL;
+ NumKeywords = sizeof(sh_keywords) / sizeof(sh_keywords[0]);
+ Keywords = sh_keywords;
+ }
+ else
+ {
+ PrettyPrint = PRETTY_CODE;
+ NumKeywords = sizeof(code_keywords) / sizeof(code_keywords[0]);
+ Keywords = code_keywords;
+ }
+ }
+
+ ppd = SetCommonOptions(num_options, options, 1);
+
+ 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 = atof(val);
+
+ if ((val = cupsGetOption("lpi", num_options, options)) != NULL)
+ LinesPerInch = atof(val);
+
+ if ((val = cupsGetOption("prettyprint", num_options, options)) != NULL)
+ PageTop -= 216.0f / LinesPerInch;
+
+ Copies = atoi(argv[4]);
+
+ WriteProlog(argv[3], argv[2], getenv("CLASSIFICATION"),
+ cupsGetOption("page-label", num_options, options), ppd);
+
+ /*
+ * Read text from the specified source and print it...
+ */
+
+ lastch = 0;
+ 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, NumKeywords, sizeof(char *),
+ 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, NumKeywords, sizeof(char *),
+ 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, NumKeywords, sizeof(char *),
+ 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, NumKeywords, sizeof(char *),
+ 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 &&
+ PrettyPrint != PRETTY_SHELL)
+ {
+ /*
+ * Start a C-style comment...
+ */
+
+ ccomment = 1;
+ attr |= ATTR_ITALIC | ATTR_GREEN;
+ }
+ else if (ch == '/' && lastch == '/' && !cstring &&
+ PrettyPrint == PRETTY_CODE)
+ {
+ /*
+ * Start a C++-style comment...
+ */
+
+ attr |= ATTR_ITALIC | ATTR_GREEN;
+ }
+ else if (ch == '#' && !cstring && PrettyPrint != PRETTY_CODE)
+ {
+ /*
+ * Start a shell-style comment...
+ */
+
+ attr |= ATTR_ITALIC | ATTR_GREEN;
+ }
+ else if (ch == '#' && column == 0 && !ccomment && !cstring &&
+ PrettyPrint == PRETTY_CODE)
+ {
+ /*
+ * 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)
+ ch = Page[line][i].ch;
+ else if (ch == Page[line][i].ch)
+ Page[line][i].attr |= ATTR_BOLD;
+ else if (Page[line][i].ch == '_')
+ Page[line][i].attr |= ATTR_UNDERLINE;
+ else if (ch == '_')
+ {
+ Page[line][i].attr |= ATTR_UNDERLINE;
+
+ if (Page[line][i].ch)
+ ch = Page[line][i].ch;
+ }
+ else
+ Page[line][i].attr = attr;
+
+ Page[line][i].ch = ch;
+ }
+
+ if (PrettyPrint)
+ {
+ if ((ch == '{' || ch == '}') && !ccomment && !cstring &&
+ column < ColumnWidth)
+ {
+ /*
+ * Highlight curley braces...
+ */
+
+ Page[line][column].attr |= ATTR_BOLD;
+ }
+ else if ((ch == '/' || ch == '*') && lastch == '/' &&
+ column < ColumnWidth && PrettyPrint != PRETTY_SHELL)
+ {
+ /*
+ * Highlight first comment character...
+ */
+
+ Page[line][column - 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();
+
+ if (ppd != NULL)
+ ppdClose(ppd);
+
+ 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 000000000..025afc137
--- /dev/null
+++ b/filter/textcommon.h
@@ -0,0 +1,102 @@
+/*
+ * "$Id$"
+ *
+ * Common text filter definitions for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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
+
+#define PRETTY_OFF 0
+#define PRETTY_CODE 1
+#define PRETTY_SHELL 2
+#define PRETTY_PERL 3
+#define PRETTY_HTML 4
+
+
+/*
+ * 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 float CharsPerInch, /* Number of character columns per inch */
+ LinesPerInch; /* Number of lines per inch */
+extern int UTF8, /* Use UTF-8 encoding? */
+ NumKeywords; /* Number of known keywords */
+extern char **Keywords; /* List of known keywords... */
+
+
+/*
+ * Required functions...
+ */
+
+extern int TextMain(const char *name, int argc, char *argv[]);
+extern void WriteEpilogue(void);
+extern void WritePage(void);
+extern void WriteProlog(const char *title, const char *user,
+ const char *classification, const char *label,
+ ppd_file_t *ppd);
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/texttops.c b/filter/texttops.c
new file mode 100644
index 000000000..d202bd40c
--- /dev/null
+++ b/filter/texttops.c
@@ -0,0 +1,1316 @@
+/*
+ * "$Id$"
+ *
+ * Text to PostScript filter for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1993-2002 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(const 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 (getenv("PPD") == NULL)
+ {
+ switch (Orientation)
+ {
+ case 1 : /* Landscape */
+ printf("%.3f 0.0 translate 90 rotate\n", PageLength);
+ break;
+ case 2 : /* Reverse Portrait */
+ printf("%.3f %.3f translate 180 rotate\n", PageWidth, PageLength);
+ break;
+ case 3 : /* Reverse Landscape */
+ printf("0.0 %.3f translate -90 rotate\n", PageWidth);
+ break;
+ }
+ }
+
+ 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(const char *title, /* I - Title of job */
+ const char *user, /* I - Username */
+ const char *classification, /* I - Classification */
+ const char *label, /* I - Page label */
+ 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 */
+ const char *datadir; /* CUPS_DATADIR environment variable */
+ 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"
+ };
+
+
+ /*
+ * Get the data directory...
+ */
+
+ if ((datadir = getenv("CUPS_DATADIR")) == NULL)
+ datadir = CUPS_DATADIR;
+
+ /*
+ * Adjust margins as necessary...
+ */
+
+ if (classification || label)
+ {
+ /*
+ * Leave room for labels...
+ */
+
+ PageBottom += 36;
+ PageTop -= 36;
+ }
+
+ /*
+ * 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), CUPS_STRFTIME_FORMAT, 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("%%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...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/data/psglyphs", datadir);
+
+ if ((fp = fopen(filename, "r")) != NULL)
+ {
+ while (fscanf(fp, "%x%63s", &unicode, glyph) == 2)
+ Glyphs[unicode] = strdup(glyph);
+
+ fclose(fp);
+ }
+ else
+ {
+ fprintf(stderr, "ERROR: Unable to open \"%s\" - %s\n", filename,
+ strerror(errno));
+ exit(1);
+ }
+
+ /*
+ * Get the output character set...
+ */
+
+ charset = getenv("CHARSET");
+ if (charset != NULL && strcmp(charset, "us-ascii") != 0)
+ {
+ snprintf(filename, sizeof(filename), "%s/charsets/%s", datadir, 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 = 0;
+
+ /*
+ * Read the font description(s)...
+ */
+
+ 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:
+ *
+ * first last direction width normal [bold italic bold-italic]
+ */
+
+ lineptr = line;
+
+ start = strtol(lineptr, &lineptr, 16);
+ end = strtol(lineptr, &lineptr, 16);
+
+ while (isspace(*lineptr))
+ lineptr ++;
+
+ if (!*lineptr)
+ break; /* Must be a font mapping */
+
+ 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;
+
+ NumFonts ++;
+ }
+
+ /*
+ * Read encoding lines...
+ */
+
+ do
+ {
+ /*
+ * 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[Chars[ch]] = unicode;
+ }
+ while (fgets(line, sizeof(line), fp) != NULL);
+
+ 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 = PrettyPrint ? 2 : 1; 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("%%DocumentSuppliedResources: procset texttops 1.1 0");
+
+ for (i = 0; i < num_fonts; i ++)
+ {
+ if (ppd != NULL)
+ {
+ fprintf(stderr, "DEBUG: ppd->num_fonts = %d\n", ppd->num_fonts);
+
+ for (j = 0; j < ppd->num_fonts; j ++)
+ {
+ fprintf(stderr, "DEBUG: ppd->fonts[%d] = %s\n", j, ppd->fonts[j]);
+
+ if (strcmp(fonts[i], ppd->fonts[j]) == 0)
+ break;
+ }
+ }
+ else
+ j = 0;
+
+ if (ppd != NULL && j >= ppd->num_fonts)
+ {
+ /*
+ * Need to embed this font...
+ */
+
+ printf("%%%%+ font %s\n", fonts[i]);
+ }
+ }
+
+ puts("%%EndComments");
+
+ puts("%%BeginProlog");
+
+ /*
+ * Download any missing fonts...
+ */
+
+ for (i = 0; i < num_fonts; i ++)
+ {
+ if (ppd != NULL)
+ {
+ for (j = 0; j < ppd->num_fonts; j ++)
+ if (strcmp(fonts[i], ppd->fonts[j]) == 0)
+ break;
+ }
+ else
+ j = 0;
+
+ if (ppd != NULL && j >= ppd->num_fonts)
+ {
+ /*
+ * Need to embed this font...
+ */
+
+ printf("%%%%BeginResource: font %s\n", fonts[i]);
+
+ /**** MRS: Need to use CUPS_FONTPATH env var! ****/
+ /**** Also look for Fontmap file or name.pfa, name.pfb... ****/
+ snprintf(filename, sizeof(filename), "%s/fonts/%s", datadir, fonts[i]);
+ if ((fp = fopen(filename, "rb")) != NULL)
+ {
+ while ((j = fread(line, 1, sizeof(line), fp)) > 0)
+ fwrite(line, 1, j, stdout);
+
+ fclose(fp);
+ }
+
+ puts("\n%%EndResource");
+ }
+ }
+
+ /*
+ * 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 if (Codes[i * 256 + ch] > 255)
+ printf("/uni%04X", 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 = PrettyPrint ? 2 : 1; 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 [%.3f 0 0 %.3f 0 0] makefont def\n",
+ 120.0 / CharsPerInch, 68.0 / LinesPerInch);
+ printf("/FB /cupsBold findfont [%.3f 0 0 %.3f 0 0] makefont def\n",
+ 120.0 / CharsPerInch, 68.0 / LinesPerInch);
+ if (PrettyPrint)
+ printf("/FI /cupsItalic findfont [%.3f 0 0 %.3f 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 %.3f 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%.3f %.3f translate } {\n",
+ PageWidth - PageRight, PageTop + 72.0f / LinesPerInch);
+ printf("\t\t%.3f %.3f translate } ifelse\n",
+ PageLeft, PageTop + 72.0f / LinesPerInch);
+ }
+ else
+ printf("\t%.3f %.3f translate\n",
+ PageLeft, PageTop + 72.0f / LinesPerInch);
+
+ printf("\t0 0 %.3f %.3f 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 %.3f add %.3f } {\n",
+ PageRight - PageLeft - 36.0f / LinesPerInch,
+ (0.5f + 0.157f) * 72.0f / LinesPerInch);
+ printf("\t\t%.3f %.3f } ifelse\n", 36.0f / LinesPerInch,
+ (0.5f + 0.157f) * 72.0f / LinesPerInch);
+ }
+ else
+ printf("\t%.3f %.3f\n", 36.0f / LinesPerInch,
+ (0.5f + 0.157f) * 72.0f / LinesPerInch);
+
+ puts("\tmoveto T show");
+
+ printf("\tD dup stringwidth pop neg 2 div %.3f add %.3f\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%.3f %.3f } {\n", 36.0f / LinesPerInch,
+ (0.5f + 0.157f) * 72.0f / LinesPerInch);
+ printf("\t\tdup stringwidth pop neg %.3f add %.3f } ifelse\n",
+ PageRight - PageLeft - 36.0f / LinesPerInch,
+ (0.5f + 0.157f) * 72.0f / LinesPerInch);
+ }
+ else
+ printf("\tn dup stringwidth pop neg %.3f add %.3f\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 i; /* Looping var */
+ int col; /* Current column */
+ int attr; /* Current attribute */
+ int font, /* Font to use */
+ lastfont, /* Last font */
+ mono; /* Monospaced? */
+ lchar_t *start; /* First character in sequence */
+
+
+ for (col = 0, start = line; col < SizeColumns;)
+ {
+ while (col < SizeColumns && (line->ch == ' ' || line->ch == 0))
+ {
+ col ++;
+ line ++;
+ }
+
+ if (col >= SizeColumns)
+ break;
+
+ if (NumFonts == 1)
+ {
+ /*
+ * All characters in a single font - assume monospaced...
+ */
+
+ 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);
+ }
+ else
+ {
+ /*
+ * Multiple fonts; break up based on the font...
+ */
+
+ attr = line->attr;
+ start = line;
+ lastfont = Chars[line->ch] / 256;
+ mono = strncmp(Fonts[lastfont][0], "Courier", 7) == 0;
+ col ++;
+ line ++;
+
+ if (mono)
+ {
+ while (col < SizeColumns && line->ch != 0 && attr == line->attr)
+ {
+ font = Chars[line->ch] / 256;
+ if (strncmp(Fonts[font][0], "Courier", 7) != 0 ||
+ font != lastfont)
+ break;
+
+ col ++;
+ line ++;
+ }
+ }
+
+ if (Directions[lastfont] > 0)
+ write_string(col - (line - start), row, line - start, start);
+ else
+ {
+ /*
+ * Do right-to-left text...
+ */
+
+ while (col < SizeColumns && line->ch != 0 && attr == line->attr)
+ {
+ if (Directions[Chars[line->ch] / 256] > 0 &&
+ !ispunct(line->ch) && !isspace(line->ch))
+ break;
+
+ col ++;
+ line ++;
+ }
+
+ for (i = 1; start < line; i ++, start ++)
+ if (!isspace(start->ch))
+ write_string(col - i, row, 1, 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("%.3f ", x);
+
+ if (y == (int)y)
+ printf("%.0f ", y);
+ else
+ printf("%.3f ", y);
+
+ if (attr & ATTR_BOLD)
+ putchar('B');
+ else if (attr & ATTR_ITALIC)
+ putchar('I');
+ else
+ putchar('N');
+
+ if (attr & ATTR_UNDERLINE)
+ printf(" %.3f U", (float)len * 72.0 / (float)CharsPerInch);
+
+ if (NumFonts > 1)
+ {
+ /*
+ * 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(const char *s) /* I - String to write */
+{
+ int ch; /* Actual character value (UTF8) */
+ const unsigned char *utf8; /* UTF8 text */
+
+
+ if (NumFonts > 1)
+ {
+ /*
+ * 8/8 encoding...
+ */
+
+ putchar('<');
+
+ utf8 = (const unsigned char *)s;
+
+ while (*utf8)
+ {
+ if (*utf8 < 0xc0 || !UTF8)
+ 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 000000000..4d3a8b2ba
--- /dev/null
+++ b/fonts/AvantGarde-Book
Binary files differ
diff --git a/fonts/AvantGarde-BookOblique b/fonts/AvantGarde-BookOblique
new file mode 100644
index 000000000..c25c6ee4c
--- /dev/null
+++ b/fonts/AvantGarde-BookOblique
Binary files differ
diff --git a/fonts/AvantGarde-Demi b/fonts/AvantGarde-Demi
new file mode 100644
index 000000000..67046dbe6
--- /dev/null
+++ b/fonts/AvantGarde-Demi
Binary files differ
diff --git a/fonts/AvantGarde-DemiOblique b/fonts/AvantGarde-DemiOblique
new file mode 100644
index 000000000..e0f6559e9
--- /dev/null
+++ b/fonts/AvantGarde-DemiOblique
Binary files differ
diff --git a/fonts/Bookman-Demi b/fonts/Bookman-Demi
new file mode 100644
index 000000000..4e26c1cf5
--- /dev/null
+++ b/fonts/Bookman-Demi
Binary files differ
diff --git a/fonts/Bookman-DemiItalic b/fonts/Bookman-DemiItalic
new file mode 100644
index 000000000..6520e718d
--- /dev/null
+++ b/fonts/Bookman-DemiItalic
Binary files differ
diff --git a/fonts/Bookman-Light b/fonts/Bookman-Light
new file mode 100644
index 000000000..7cbac2c45
--- /dev/null
+++ b/fonts/Bookman-Light
Binary files differ
diff --git a/fonts/Bookman-LightItalic b/fonts/Bookman-LightItalic
new file mode 100644
index 000000000..3ef45dcbe
--- /dev/null
+++ b/fonts/Bookman-LightItalic
Binary files differ
diff --git a/fonts/Charter-Bold b/fonts/Charter-Bold
new file mode 100644
index 000000000..0d82077ec
--- /dev/null
+++ b/fonts/Charter-Bold
Binary files differ
diff --git a/fonts/Charter-BoldItalic b/fonts/Charter-BoldItalic
new file mode 100644
index 000000000..c7a5f8798
--- /dev/null
+++ b/fonts/Charter-BoldItalic
Binary files differ
diff --git a/fonts/Charter-Italic b/fonts/Charter-Italic
new file mode 100644
index 000000000..6abe1cdfd
--- /dev/null
+++ b/fonts/Charter-Italic
Binary files differ
diff --git a/fonts/Charter-Roman b/fonts/Charter-Roman
new file mode 100644
index 000000000..b25133d51
--- /dev/null
+++ b/fonts/Charter-Roman
Binary files differ
diff --git a/fonts/Courier b/fonts/Courier
new file mode 100644
index 000000000..0cadce7d1
--- /dev/null
+++ b/fonts/Courier
Binary files differ
diff --git a/fonts/Courier-Bold b/fonts/Courier-Bold
new file mode 100644
index 000000000..f1da6121b
--- /dev/null
+++ b/fonts/Courier-Bold
Binary files differ
diff --git a/fonts/Courier-BoldOblique b/fonts/Courier-BoldOblique
new file mode 100644
index 000000000..8b7c24ff3
--- /dev/null
+++ b/fonts/Courier-BoldOblique
Binary files differ
diff --git a/fonts/Courier-Oblique b/fonts/Courier-Oblique
new file mode 100644
index 000000000..107a51337
--- /dev/null
+++ b/fonts/Courier-Oblique
Binary files differ
diff --git a/fonts/Helvetica b/fonts/Helvetica
new file mode 100644
index 000000000..ff605552c
--- /dev/null
+++ b/fonts/Helvetica
Binary files differ
diff --git a/fonts/Helvetica-Bold b/fonts/Helvetica-Bold
new file mode 100644
index 000000000..aec380a33
--- /dev/null
+++ b/fonts/Helvetica-Bold
Binary files differ
diff --git a/fonts/Helvetica-BoldOblique b/fonts/Helvetica-BoldOblique
new file mode 100644
index 000000000..479904083
--- /dev/null
+++ b/fonts/Helvetica-BoldOblique
Binary files differ
diff --git a/fonts/Helvetica-Narrow b/fonts/Helvetica-Narrow
new file mode 100644
index 000000000..f2387225d
--- /dev/null
+++ b/fonts/Helvetica-Narrow
Binary files differ
diff --git a/fonts/Helvetica-Narrow-Bold b/fonts/Helvetica-Narrow-Bold
new file mode 100644
index 000000000..7ee6a2c81
--- /dev/null
+++ b/fonts/Helvetica-Narrow-Bold
Binary files differ
diff --git a/fonts/Helvetica-Narrow-BoldOblique b/fonts/Helvetica-Narrow-BoldOblique
new file mode 100644
index 000000000..d2e96f3b7
--- /dev/null
+++ b/fonts/Helvetica-Narrow-BoldOblique
Binary files differ
diff --git a/fonts/Helvetica-Narrow-Oblique b/fonts/Helvetica-Narrow-Oblique
new file mode 100644
index 000000000..4ff13e5f6
--- /dev/null
+++ b/fonts/Helvetica-Narrow-Oblique
Binary files differ
diff --git a/fonts/Helvetica-Oblique b/fonts/Helvetica-Oblique
new file mode 100644
index 000000000..876cda876
--- /dev/null
+++ b/fonts/Helvetica-Oblique
Binary files differ
diff --git a/fonts/Makefile b/fonts/Makefile
new file mode 100644
index 000000000..b6cdbb34b
--- /dev/null
+++ b/fonts/Makefile
@@ -0,0 +1,75 @@
+#
+# "$Id$"
+#
+# Fonts makefile for the Common UNIX Printing System (CUPS).
+#
+# Copyright 1993-2002 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:
+ $(INSTALL_DIR) $(DATADIR)/fonts
+ for file in $(FONTS); do \
+ $(INSTALL_DATA) $$file $(DATADIR)/fonts; \
+ done
+
+
+#
+# End of "$Id$".
+#
diff --git a/fonts/NewCenturySchlbk-Bold b/fonts/NewCenturySchlbk-Bold
new file mode 100644
index 000000000..321a282f4
--- /dev/null
+++ b/fonts/NewCenturySchlbk-Bold
Binary files differ
diff --git a/fonts/NewCenturySchlbk-BoldItalic b/fonts/NewCenturySchlbk-BoldItalic
new file mode 100644
index 000000000..31e589003
--- /dev/null
+++ b/fonts/NewCenturySchlbk-BoldItalic
Binary files differ
diff --git a/fonts/NewCenturySchlbk-Italic b/fonts/NewCenturySchlbk-Italic
new file mode 100644
index 000000000..2fbd61647
--- /dev/null
+++ b/fonts/NewCenturySchlbk-Italic
Binary files differ
diff --git a/fonts/NewCenturySchlbk-Roman b/fonts/NewCenturySchlbk-Roman
new file mode 100644
index 000000000..6cbded3c7
--- /dev/null
+++ b/fonts/NewCenturySchlbk-Roman
Binary files differ
diff --git a/fonts/Palatino-Bold b/fonts/Palatino-Bold
new file mode 100644
index 000000000..7f5df43f3
--- /dev/null
+++ b/fonts/Palatino-Bold
Binary files differ
diff --git a/fonts/Palatino-BoldItalic b/fonts/Palatino-BoldItalic
new file mode 100644
index 000000000..1c812b839
--- /dev/null
+++ b/fonts/Palatino-BoldItalic
Binary files differ
diff --git a/fonts/Palatino-Italic b/fonts/Palatino-Italic
new file mode 100644
index 000000000..8d0f820de
--- /dev/null
+++ b/fonts/Palatino-Italic
Binary files differ
diff --git a/fonts/Palatino-Roman b/fonts/Palatino-Roman
new file mode 100644
index 000000000..4101b7335
--- /dev/null
+++ b/fonts/Palatino-Roman
Binary files differ
diff --git a/fonts/Symbol b/fonts/Symbol
new file mode 100644
index 000000000..d0505e46c
--- /dev/null
+++ b/fonts/Symbol
Binary files differ
diff --git a/fonts/Times-Bold b/fonts/Times-Bold
new file mode 100644
index 000000000..47f8fd57d
--- /dev/null
+++ b/fonts/Times-Bold
Binary files differ
diff --git a/fonts/Times-BoldItalic b/fonts/Times-BoldItalic
new file mode 100644
index 000000000..2d19d942e
--- /dev/null
+++ b/fonts/Times-BoldItalic
Binary files differ
diff --git a/fonts/Times-Italic b/fonts/Times-Italic
new file mode 100644
index 000000000..aa9ff5f8a
--- /dev/null
+++ b/fonts/Times-Italic
Binary files differ
diff --git a/fonts/Times-Roman b/fonts/Times-Roman
new file mode 100644
index 000000000..cbae7ed15
--- /dev/null
+++ b/fonts/Times-Roman
Binary files differ
diff --git a/fonts/Utopia-Bold b/fonts/Utopia-Bold
new file mode 100644
index 000000000..06b91085a
--- /dev/null
+++ b/fonts/Utopia-Bold
Binary files differ
diff --git a/fonts/Utopia-BoldItalic b/fonts/Utopia-BoldItalic
new file mode 100644
index 000000000..c36689694
--- /dev/null
+++ b/fonts/Utopia-BoldItalic
Binary files differ
diff --git a/fonts/Utopia-Italic b/fonts/Utopia-Italic
new file mode 100644
index 000000000..e33f16af9
--- /dev/null
+++ b/fonts/Utopia-Italic
Binary files differ
diff --git a/fonts/Utopia-Regular b/fonts/Utopia-Regular
new file mode 100644
index 000000000..1772a3a0b
--- /dev/null
+++ b/fonts/Utopia-Regular
Binary files differ
diff --git a/fonts/ZapfChancery-MediumItalic b/fonts/ZapfChancery-MediumItalic
new file mode 100644
index 000000000..28443517d
--- /dev/null
+++ b/fonts/ZapfChancery-MediumItalic
Binary files differ
diff --git a/fonts/ZapfDingbats b/fonts/ZapfDingbats
new file mode 100644
index 000000000..4a3c386d2
--- /dev/null
+++ b/fonts/ZapfDingbats
Binary files differ
diff --git a/install-sh b/install-sh
new file mode 100755
index 000000000..398a88e14
--- /dev/null
+++ b/install-sh
@@ -0,0 +1,251 @@
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission. M.I.T. makes no representations about the
+# suitability of this software for any purpose. It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch. It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd="$cpprog"
+ shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd="$stripprog"
+ shift
+ continue;;
+
+ -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+ shift
+ continue;;
+
+ -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ # this colon is to work around a 386BSD /bin/sh bug
+ :
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+if [ x"$src" = x ]
+then
+ echo "install: no input file specified"
+ exit 1
+else
+ :
+fi
+
+if [ x"$dir_arg" != x ]; then
+ dst=$src
+ src=""
+
+ if [ -d $dst ]; then
+ instcmd=:
+ chmodcmd=""
+ else
+ instcmd=$mkdirprog
+ fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+ if [ -f $src -o -d $src ]
+ then
+ :
+ else
+ echo "install: $src does not exist"
+ exit 1
+ fi
+
+ if [ x"$dst" = x ]
+ then
+ echo "install: no destination specified"
+ exit 1
+ else
+ :
+ fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+ if [ -d $dst ]
+ then
+ dst="$dst"/`basename $src`
+ else
+ :
+ fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+# this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+ '
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+ pathcomp="${pathcomp}${1}"
+ shift
+
+ if [ ! -d "${pathcomp}" ] ;
+ then
+ $mkdirprog "${pathcomp}"
+ else
+ :
+ fi
+
+ pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+ $doit $instcmd $dst &&
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else : ; fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else : ; fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else : ; fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else : ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+ if [ x"$transformarg" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ dstfile=`basename $dst $transformbasename |
+ sed $transformarg`$transformbasename
+ fi
+
+# don't allow the sed command to completely eliminate the filename
+
+ if [ x"$dstfile" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ :
+ fi
+
+# Make a temp file name in the proper directory.
+
+ dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+ $doit $instcmd $src $dsttmp &&
+
+ trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing. If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else :;fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else :;fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else :;fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else :;fi &&
+
+# Now rename the file to the real destination.
+
+ $doit $rmcmd -f $dstdir/$dstfile &&
+ $doit $mvcmd $dsttmp $dstdir/$dstfile
+
+fi &&
+
+
+exit 0
diff --git a/locale/C/cups_C b/locale/C/cups_C
new file mode 100644
index 000000000..a151b3823
--- /dev/null
+++ b/locale/C/cups_C
@@ -0,0 +1,133 @@
+iso-8859-1
+OK
+Cancel
+Help
+Quit
+Close
+Yes
+No
+On
+Off
+Save
+Discard
+Default
+Options
+More Info
+Black
+Color
+Cyan
+Magenta
+Yellow
+Copyright 1993-2002 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.
+426 An upgrade to a secure connection is required. If you are seeing this message in a web browser then it does not support HTTP encryption upgrades.
+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 000000000..6f59773b0
--- /dev/null
+++ b/locale/Makefile
@@ -0,0 +1,77 @@
+#
+# "$Id$"
+#
+# Locale file makefile for the Common UNIX Printing System (CUPS).
+#
+# Copyright 1993-2002 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 be cs de en es fr he it ru_RU.koi8r ru_RU.cp1251 \
+ uk uk_UA.cp1251 zh_CN
+
+
+#
+# Make everything...
+#
+
+all: translate
+
+
+#
+# Clean all config and object files...
+#
+
+clean:
+
+
+#
+# Install files...
+#
+
+install:
+ $(INSTALL_DIR) $(LOCALEDIR)
+ for dir in $(LOCALES) ; do \
+ $(INSTALL_DIR) $(LOCALEDIR)/$$dir ; \
+ $(INSTALL_DATA) $$dir/cups_$$dir $(LOCALEDIR)/$$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)
+ echo Linking $<...
+ $(CC) $(LDFLAGS) -o translate translate.o $(LIBS)
+
+translate.o: ../cups/http.h
+
+
+#
+# End of "$Id$".
+#
diff --git a/locale/be/cups_be b/locale/be/cups_be
new file mode 100644
index 000000000..c7883d6b2
--- /dev/null
+++ b/locale/be/cups_be
@@ -0,0 +1,132 @@
+windows-1251
+OK
+Cancel
+Help
+Quit
+Close
+Yes
+No
+On
+Off
+Save
+Discard
+Default
+Options
+More Info
+Black
+Colour
+Cyan
+Magenta
+Yellow
+Copyright 1993-2002 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/cs/cups_cs b/locale/cs/cups_cs
new file mode 100644
index 000000000..98a1a89ec
--- /dev/null
+++ b/locale/cs/cups_cs
@@ -0,0 +1,133 @@
+iso-8859-2
+OK
+Zru¹it
+Nápovìda
+Ukonèit
+Zavøít
+Ano
+Ne
+Zap
+Vyp
+UloŸit
+Zahodit
+Výchozí
+MoŸnosti
+Více informací
+Èerná
+Barva
+Azurová
+Purpurová
+®lutá
+Copyright 1993-2002 Easy Software Products, v¹echna práva vyhrazena.
+Obecné
+Tiskárna
+Obrázek
+HP-GL/2
+Extra
+Dokument
+Ostatní
+Vytisknout stránky:
+Celý dokument
+Rozsah stránek:
+Obrácené poøadí:
+Formát stránky:
+ 1-Up
+ 2-Up
+ 4-Up
+Zvìt¹ení obrázku:
+PouŸít pøirozenou velikost
+Zvìt¹it podle procent
+Zvìt¹it podle PPI
+Zrcadlit obrázek:
+Barevné nasycení:
+Svìtlost:
+Pøizpùsobit stránce:
+Stínování:
+©íøka pera:
+Gamma korekce:
+Jas:
+Pøidat
+Smazat
+Zmìnit
+URI tiskárny
+Název tiskárny
+Umístìní tiskárny
+Info o tiskárnì
+Model tiskárny
+URI zaøízení
+Formátuji stránku
+Tisknu stránku
+Inicializuji tiskárnu
+Stav tiskárny
+Pøijímá úlohy
+Nepøijímá úlohy
+Vytisknout úlohy
+Tøída
+Lokální
+Vzdálená
+Duplexní
+Se¹ití
+Rychlé kopie
+Srovnané kopie
+Dìrování
+Obal
+Vazba
+Tøídìní
+Malé (aŸ do 9.5x14in)
+Støední (od 9.5x14in do 13x19in)
+Velké (13x19in a vìt¹í)
+Vlastní velikost
+Neèinná
+Probíhá zpracování
+Zastaveno
+V¹e
+Liché
+Sudé
+Svìtlej¹í Tmavìj¹í
+Velikost média
+Typ média
+Zdroj média
+Orientace:
+Portrét
+Krajina
+Stav úlohy
+Název úlohy
+UŸivatelské jméno
+Priorita
+Kopie
+Velikost souboru
+Nevyøízená
+Výstupní reŸim
+Rozli¹ení
+Text
+Hezký tisk
+Okraje
+Vlevo
+Vpravo
+Dole
+Nahoøe
+Soubor(y)
+Tisk
+400 Vá¹ prohlíŸeè odeslal poŸadavek, kterému tento server nerozumí.
+Server nemohl ovìøit, zda máte oprávnìní pøistupovat k tomuto zdroji.
+Pøístup k tomuto serveru je placený.
+Nemáte oprávnìní pøistupovat k tomuto zdroji.
+PoŸadovaný zdroj nebyl nalezen na tomto serveru.
+PoŸadovaná metoda není pøípustná.
+Odpovídající reprezentace zdroje nebyla nalezena.
+Nemáte oprávnìní pouŸívat tento server jako proxy hostitele.
+PoŸadavek zabral pøíli¹ mnoho èasu a byl pøeru¹en.
+PoŸadovaný zdroj má více neŸ jednu hodnotu.
+PoŸadovaný zdroj byl zru¹en bez náhrady.
+PoŸadovaná metoda vyŸaduje platné pole Content-Length.
+Podmínka tohoto poŸadavku byla vyhodnocena zápornì.
+PoŸadavek je pro tento server pøíli¹ velký ke zpracování.
+URI poŸadavku je pro tento server pøíli¹ velké ke zpracování.
+Formát poŸadavku nebyl serverem pochopen.
+426 Je vyŸadována aktualizace na zabezpeèený protokol. Vidíte-li tuto zprávu ve WWW prohlíŸeèi, znamená to, Ÿe není podporován.
+500 Server narazil na kritickou chybu a nemùŸe pokraèovat ve zpracování poŸadavku.
+PoŸadovaná metoda není implementována.
+Proxy server obdrŸel neplatnou odpovìï od nadøazeného serveru.
+PoŸadovaný zdroj je momentálnì nedostupný.
+Proxy server zabral pøíli¹ mnoho èasu na odpovìï tomuto serveru.
+Tento server nepodporuje HTTP ve verzi, kterou poŸaduje vá¹ prohlíŸeè.
diff --git a/locale/de/cups_de b/locale/de/cups_de
new file mode 100644
index 000000000..652d10f93
--- /dev/null
+++ b/locale/de/cups_de
@@ -0,0 +1,134 @@
+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-2002 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.
+426 An upgrade to a secure connection is required. If you are seeing this message in a web browser then it does not support HTTP encryption upgrades.
+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 000000000..e0730f7fa
--- /dev/null
+++ b/locale/en/cups_en
@@ -0,0 +1,133 @@
+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-2002 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.
+426 An upgrade to a secure connection is required. If you are seeing this message in a web browser then it does not support HTTP encryption upgrades.
+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 000000000..980d49225
--- /dev/null
+++ b/locale/es/cups_es
@@ -0,0 +1,133 @@
+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-2002 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.
+426 An upgrade to a secure connection is required. If you are seeing this message in a web browser then it does not support HTTP encryption upgrades.
+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 000000000..189697f2d
--- /dev/null
+++ b/locale/fr/cups_fr
@@ -0,0 +1,133 @@
+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-2002 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.
+426 An upgrade to a secure connection is required. If you are seeing this message in a web browser then it does not support HTTP encryption upgrades.
+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/he/cups_he b/locale/he/cups_he
new file mode 100644
index 000000000..06ae4f322
--- /dev/null
+++ b/locale/he/cups_he
@@ -0,0 +1,133 @@
+iso-8859-8
+OK
+Cancel
+Help
+Quit
+Close
+Yes
+No
+On
+Off
+Save
+Discard
+Default
+Options
+More Info
+Black
+Colour
+Cyan
+Magenta
+Yellow
+Copyright 1993-2001 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.
+426 An upgrade to a secure connection is required. If you are seeing this message in a web browser then it does not support HTTP encryption upgrades.
+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/it/cups_it b/locale/it/cups_it
new file mode 100644
index 000000000..e1c7586ff
--- /dev/null
+++ b/locale/it/cups_it
@@ -0,0 +1,133 @@
+iso-8859-1
+Continua
+Annulla
+Aiuto
+Esci
+Chiudi
+Sì
+No
+Attivo
+Inattivo
+Salva
+Abbandona
+Predefinito
+Opzioni
+Maggiori informazioni
+Nero
+Colore
+Ciano
+Fucsia
+Giallo
+Copyright 1993-2002 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
+Dimensione dell'immagine:
+Usa dimensione originale 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 della stampante
+Stato della stampante
+Accettazione dei lavori di stampa abilitata
+Accettazione dei lavori di stampa disabilitata
+Richieste di stampa
+Categoria
+Locale
+Remoto
+Fronte-retro
+Spillatura in corso
+Copie veloci
+Copie fascicolate
+Perforazione delle pagine (per fascicolatura)
+Inserimento copertina in corso
+Fascicolatura in corso
+Ordinamento in corso
+Piccolo (fino a 9.5x14")
+Medio (da 9.5x14" a 13x19")
+Grande (13x19" o maggiore)
+Formato personalizzato
+In attesa
+In elaborazione
+Fermo
+Tutto
+Dispari
+Pari
+Più scuro Più chiaro
+Formato del supporto
+Tipo del supporto
+Sorgente del supporto
+Orientamento:
+Verticale
+Orizzontale
+Stato del processo
+Nome del processo
+Nome dell'utente
+Priorità
+Copie
+Dimensioni del file
+In attesa
+Modo stampa
+Risoluzione
+Testo
+Stampa di qualità
+Margini
+Sinistro
+Destro
+Inferiore
+Superiore
+Nome/i file
+Stampa
+400 Il vostro browser ha inviato una richiesta che non può essere eseguita su questo server.
+Questo server non ha potuto verificare la vostra autorizzazione ad accedere alla risorsa.
+L'accesso a questo servizio è a pagamento.
+Non avete il permesso di accedere alla risorsa richiesta su questo server.
+La risorsa richiesta non è disponibile su questo server.
+Il metodo richiesto non è consentito con la risorsa selezionata.
+Una rappresentazione adatta per la risorsa non è disponibile su questo server.
+Non avete il permesso utilizzare questo server come proxy.
+La richiesta ha impiegato troppo tempo per essere completata ed è stata annullata.
+La risorsa richiesta ha più di un valore.
+La risorsa richiesta non è più disponibile e non è stata ancora sostituita.
+Il metodo chiesto richiede un campo "Content-Length" valido.
+I prerequisiti per la richiesta non possono essere soddisfatti.
+La richiesta è troppo grande per essere eseguita da questo server.
+L'URI richiesta è troppo grande per essere eseguita da questo server.
+Il formato della richiesta non è valido su questo server.
+426 È richiesto il passaggio ad una connessione sicura. Se state leggendo questo messaggio nella finestra del vostro browser web vuol dire che non è in grado di supportare il funzionamento con HTTP crittografato.
+500 Il server ha rilevato un errore non recuperabile e non può eseguire la vostra richiesta.
+Il metodo richiesto non è implementato da questo server.
+Il proxy server ha ricevuto una risposta non valida da un server di livello superiore.
+La risorsa richiesta non è attualmente 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 000000000..f9abe72d6
--- /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 <cups/language.h>.
+The HTTP status messages use the status codes defined in <cups/http.h>.
+
+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/ru_RU.cp1251/cups_ru_RU.cp1251 b/locale/ru_RU.cp1251/cups_ru_RU.cp1251
new file mode 100644
index 000000000..c7883d6b2
--- /dev/null
+++ b/locale/ru_RU.cp1251/cups_ru_RU.cp1251
@@ -0,0 +1,132 @@
+windows-1251
+OK
+Cancel
+Help
+Quit
+Close
+Yes
+No
+On
+Off
+Save
+Discard
+Default
+Options
+More Info
+Black
+Colour
+Cyan
+Magenta
+Yellow
+Copyright 1993-2002 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/ru_RU.koi8r/cups_ru_RU.koi8r b/locale/ru_RU.koi8r/cups_ru_RU.koi8r
new file mode 100644
index 000000000..b12c9fe8d
--- /dev/null
+++ b/locale/ru_RU.koi8r/cups_ru_RU.koi8r
@@ -0,0 +1,132 @@
+koi8-r
+OK
+Cancel
+Help
+Quit
+Close
+Yes
+No
+On
+Off
+Save
+Discard
+Default
+Options
+More Info
+Black
+Colour
+Cyan
+Magenta
+Yellow
+Copyright 1993-2002 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/translate.c b/locale/translate.c
new file mode 100644
index 000000000..e56690be6
--- /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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <cups/http.h>
+
+
+/*
+ * '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/locale/uk/cups_uk b/locale/uk/cups_uk
new file mode 100644
index 000000000..19fea95db
--- /dev/null
+++ b/locale/uk/cups_uk
@@ -0,0 +1,132 @@
+koi8-u
+OK
+Cancel
+Help
+Quit
+Close
+Yes
+No
+On
+Off
+Save
+Discard
+Default
+Options
+More Info
+Black
+Colour
+Cyan
+Magenta
+Yellow
+Copyright 1993-2002 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/uk_UA.cp1251/cups_uk_UA.cp1251 b/locale/uk_UA.cp1251/cups_uk_UA.cp1251
new file mode 100644
index 000000000..c7883d6b2
--- /dev/null
+++ b/locale/uk_UA.cp1251/cups_uk_UA.cp1251
@@ -0,0 +1,132 @@
+windows-1251
+OK
+Cancel
+Help
+Quit
+Close
+Yes
+No
+On
+Off
+Save
+Discard
+Default
+Options
+More Info
+Black
+Colour
+Cyan
+Magenta
+Yellow
+Copyright 1993-2002 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/zh_CN/cups_zh_CN b/locale/zh_CN/cups_zh_CN
new file mode 100644
index 000000000..26c56ceb5
--- /dev/null
+++ b/locale/zh_CN/cups_zh_CN
@@ -0,0 +1,133 @@
+utf-8
+确认
+å–消
+帮助
+退出
+关闭
+是
+ä¸
+打开
+关闭
+ä¿å­˜
+放弃
+默认
+选项
+更多信æ¯
+黑色
+颜色
+é’色
+洋红
+黄色
+Copyright 1993-2002 by Easy Software Products, All Rights Reserved.
+常规
+打å°æœº
+图åƒ
+HP-GL/2
+Extra
+文档
+其它
+打å°é¡µé¢ï¼š
+整个文档
+页é¢èŒƒå›´ï¼š
+åå‘:
+页é¢æ ¼å¼ï¼š
+ 1-Up
+ 2-Up
+ 4-Up
+图åƒç¼©æ”¾ï¼š
+使用图åƒæœ¬èº«çš„大å°
+按百分比缩放
+按 PPI 缩放
+é•œåƒå›¾åƒï¼š
+颜色饱和度:
+色度:
+适åˆé¡µé¢ï¼š
+阴影:
+笔宽:
+Gamma 校正:
+亮度:
+添加
+删除
+修改
+打å°æœº URI
+打å°æœºå称
+打å°æœºä½ç½®
+打å°æœºä¿¡æ¯
+打å°æœºåˆ¶é€ å’Œåž‹å·
+设备 URI
+正在格å¼åŒ–页é¢
+正在打å°é¡µé¢
+正在åˆå§‹åŒ–打å°æœº
+打å°æœºçŠ¶æ€
+正在接å—任务
+没有接å—任务
+打å°ä»»åŠ¡
+类别
+本地
+远程
+åŒå·¥
+正在分类
+快速å¤åˆ¶
+核对å¤åˆ¶
+正在打孔
+正在打å°å°é¢
+正在装订
+正在整ç†
+å°(24.1x35.6厘米)
+中(24.1x35.6厘米至33.0x48.3厘米)
+大(33.0x48.3厘米或更大)
+定制尺寸
+空闲
+正在处ç†
+åœæ­¢
+全部
+奇数页
+å¶æ•°é¡µ
+æ›´æ·± æ›´æµ…
+媒质大å°
+媒质类型
+媒质æ¥æº
+æ–¹å‘:
+纵å‘
+横å‘
+任务状æ€
+任务å
+用户å
+优先级
+å°æ•°
+文件大å°
+等待
+输出模å¼
+分辨率
+文字
+良好质é‡
+è¾¹è·
+å·¦
+å³
+下
+上
+文件å
+打å°
+400 您的æµè§ˆå™¨å‘é€äº†ä¸€ä¸ªæœ¬æœåŠ¡å™¨ä¸ç†è§£çš„请求。
+本æœåŠ¡å™¨æ— æ³•ç¡®è®¤æ‚¨æœ‰æƒè®¿é—®è¯¥èµ„æºã€‚
+您必须付费æ¥è®¿é—®æœ¬æœåŠ¡å™¨ã€‚
+您没有æƒé™è®¿é—®æœ¬æœåŠ¡å™¨ä¸Šçš„该资æºã€‚
+本æœåŠ¡å™¨ä¸Šæ²¡æœ‰è¦æ±‚的资æºã€‚
+请求的方法在该资æºä¸Šä¸å…许。
+本æœåŠ¡å™¨ä¸Šæ²¡æœ‰è¯¥èµ„æºçš„正确表示。
+您没有æƒé™å°†æœ¬æœåŠ¡å™¨ä½œä¸ºä»£ç†æœåŠ¡å™¨ã€‚
+请求过长时间没有完æˆï¼Œå·²ç»è¢«ä¸­æ­¢ã€‚
+请求的资æºæœ‰å¤šäºŽä¸€ä¸ªå€¼ã€‚
+请求的资æºå·²ç»ç”¨å®Œï¼Œä¸”没有被更æ¢ã€‚
+请求的方法需è¦æœ‰æ•ˆçš„ Content-Length 标识。
+请求的å‰æ为å‡ã€‚
+请求过长,本æœåŠ¡å™¨æ— æ³•å¤„ç†ã€‚
+请求的 URI 过长,本æœåŠ¡å™¨æ— æ³•å¤„ç†ã€‚
+本æœåŠ¡å™¨æ— æ³•è¯†åˆ«è¯¥è¯·æ±‚çš„æ ¼å¼ã€‚
+426 需è¦å®‰å…¨çš„连接。如果您在æµè§ˆå™¨ä¸­çœ‹åˆ°æœ¬ä¿¡æ¯ï¼Œæ‚¨çš„æµè§ˆå™¨ä¸æ”¯æŒ HTTP 加密。
+500 æœåŠ¡å™¨æ£€æµ‹åˆ°ä¸€ä¸ªæ— æ³•æ¢å¤çš„错误,无法处ç†æ‚¨çš„请求。
+本æœåŠ¡å™¨æ²¡æœ‰å®žçŽ°æ‰€è¯·æ±‚的方法。
+代ç†æœåŠ¡å™¨æ”¶åˆ°æ¥è‡ªä¸Šæ¸¸æœåŠ¡å™¨çš„无效应答。
+请求的资æºåœ¨æœ¬æœåŠ¡å™¨ä¸Šä¸å¯ç”¨ã€‚
+代ç†æœåŠ¡å™¨é•¿æ—¶é—´æ²¡æœ‰åº”答本æœåŠ¡å™¨ã€‚
+本æœåŠ¡å™¨ä¸æ”¯æŒæ‚¨çš„æµè§ˆå™¨æ‰€éœ€è¦çš„ HTTP 版本。
diff --git a/man/.cvsignore b/man/.cvsignore
new file mode 100644
index 000000000..8c6b76a2b
--- /dev/null
+++ b/man/.cvsignore
@@ -0,0 +1,6 @@
+*.0
+*.1
+*.3
+*.5
+*.8
+*.z
diff --git a/man/Makefile b/man/Makefile
new file mode 100644
index 000000000..9d52de9c1
--- /dev/null
+++ b/man/Makefile
@@ -0,0 +1,114 @@
+#
+# "$Id$"
+#
+# Man page makefile for the Common UNIX Printing System (CUPS).
+#
+# Copyright 1993-1999 by Easy Software Products.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Easy Software Products and are protected by Federal
+# copyright law. Distribution and use rights are outlined in the file
+# "LICENSE.txt" which should have been included with this file. If this
+# file is missing or damaged please contact Easy Software Products
+# at:
+#
+# Attn: CUPS Licensing Information
+# Easy Software Products
+# 44141 Airport View Drive, Suite 204
+# Hollywood, Maryland 20636-3111 USA
+#
+# Voice: (301) 373-9603
+# EMail: cups-info@cups.org
+# WWW: http://www.cups.org
+#
+
+include ../Makedefs
+
+#
+# Man pages...
+#
+
+MAN1 = backend.man filter.man lp.man lpoptions.man lppasswd.man \
+ lpq.man lprm.man lpr.man lpstat.man
+MAN3 = cups-config.man
+MAN5 = classes.conf.man cupsd.conf.man mime.convs.man mime.types.man \
+ printers.conf.man
+MAN8 = accept.man cupsaddsmb.man cups-lpd.man cups-polld.man \
+ cupsd.man enable.man lpadmin.man lpinfo.man lpmove.man \
+ lpc.man
+
+CAT1 = $(MAN1:.man=.$(CAT1EXT))
+CAT3 = $(MAN3:.man=.$(CAT3EXT))
+CAT5 = $(MAN5:.man=.$(CAT5EXT))
+CAT8 = $(MAN8:.man=.$(CAT8EXT))
+
+
+#
+# Make everything...
+#
+
+all: $(CAT1) $(CAT3) $(CAT5) $(CAT8)
+
+
+#
+# Clean all config and object files...
+#
+
+clean:
+ $(RM) $(CAT1) $(CAT3) $(CAT5) $(CAT8)
+
+
+#
+# Install files...
+#
+
+install:
+ $(INSTALL_DIR) $(MANDIR)/man1
+ for file in $(MAN1); do \
+ $(INSTALL_MAN) $$file $(MANDIR)/man1/`basename $$file man`1; \
+ done
+ $(RM) $(MANDIR)/man1/cancel.1
+ $(LN) lp.1 $(MANDIR)/man1/cancel.1
+ $(INSTALL_DIR) $(PMANDIR)/man3
+ for file in $(MAN3); do \
+ $(INSTALL_MAN) $$file $(PMANDIR)/man3/`basename $$file man`3; \
+ done
+ $(INSTALL_DIR) $(MANDIR)/man5
+ for file in $(MAN5); do \
+ $(INSTALL_MAN) $$file $(MANDIR)/man5/`basename $$file man`5; \
+ done
+ $(INSTALL_DIR) $(AMANDIR)/man$(MAN8EXT)
+ for file in $(MAN8); do \
+ $(INSTALL_MAN) $$file $(AMANDIR)/man$(MAN8EXT)/`basename $$file man`$(MAN8EXT); \
+ done
+ $(RM) $(AMANDIR)/man$(MAN8EXT)/reject.$(MAN8EXT)
+ $(LN) accept.$(MAN8EXT) $(AMANDIR)/man$(MAN8EXT)/reject.$(MAN8EXT)
+ $(RM) $(AMANDIR)/man$(MAN8EXT)/disable.$(MAN8EXT)
+ $(LN) enable.$(MAN8EXT) $(AMANDIR)/man$(MAN8EXT)/disable.$(MAN8EXT)
+ $(INSTALL_DIR) $(MANDIR)/cat1
+ for file in $(CAT1); do \
+ $(INSTALL_MAN) $$file $(MANDIR)/cat1; \
+ done
+ $(RM) $(MANDIR)/cat1/cancel.$(CAT1EXT)
+ $(LN) lp.$(CAT1EXT) $(MANDIR)/cat1/cancel.$(CAT1EXT)
+ $(INSTALL_DIR) $(PMANDIR)/cat3
+ for file in $(CAT3); do \
+ $(INSTALL_MAN) $$file $(PMANDIR)/cat3; \
+ done
+ $(INSTALL_DIR) $(MANDIR)/cat5
+ for file in $(CAT5); do \
+ $(INSTALL_MAN) $$file $(MANDIR)/cat5; \
+ done
+ $(INSTALL_DIR) $(AMANDIR)/cat$(MAN8EXT)
+ for file in $(CAT8); do \
+ $(INSTALL_MAN) $$file $(AMANDIR)/cat$(MAN8EXT); \
+ done
+ $(RM) $(AMANDIR)/cat$(MAN8EXT)/reject.$(CAT8EXT)
+ $(LN) accept.$(CAT8EXT) $(AMANDIR)/cat$(MAN8EXT)/reject.$(CAT8EXT)
+ $(RM) $(AMANDIR)/cat$(MAN8EXT)/disable.$(CAT8EXT)
+ $(LN) enable.$(CAT8EXT) $(AMANDIR)/cat$(MAN8EXT)/disable.$(CAT8EXT)
+
+
+#
+# End of "$Id$".
+#
diff --git a/man/accept.man b/man/accept.man
new file mode 100644
index 000000000..b09637d3f
--- /dev/null
+++ b/man/accept.man
@@ -0,0 +1,60 @@
+.\"
+.\" "$Id: accept.man 2060 2002-01-23 17:25:41Z mike $"
+.\"
+.\" accept/reject man page for the Common UNIX Printing System (CUPS).
+.\"
+.\" Copyright 1997-2002 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" "23 January 2001" "Easy Software Products"
+.SH NAME
+accept/reject \- accept/reject jobs sent to a destination
+.SH SYNOPSIS
+.B accept
+destination(s)
+.br
+.B reject
+[ -E ] [ -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".
+.LP
+The \fI-E\fR option forces encryption when connecting to the server.
+.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,
+http://localhost:631/documentation.html
+.SH COPYRIGHT
+Copyright 1993-2002 by Easy Software Products, All Rights Reserved.
+.\"
+.\" End of "$Id: accept.man 2060 2002-01-23 17:25:41Z mike $".
+.\"
diff --git a/man/backend.man b/man/backend.man
new file mode 100644
index 000000000..45c1a0758
--- /dev/null
+++ b/man/backend.man
@@ -0,0 +1,109 @@
+.\"
+.\" "$Id: backend.man 2010 2002-01-02 17:59:21Z mike $"
+.\"
+.\" backend man page for the Common UNIX Printing System (CUPS).
+.\"
+.\" Copyright 1997-2002 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 June 2000" "Easy Software Products"
+.SH NAME
+backend \- cups 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 the standard input to a temporary file
+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
+CUPS_DATADIR
+.br
+The directory where data files can be found.
+.TP 5
+CUPS_SERVERROOT
+.br
+The root directory of the server.
+.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
+SOFTWARE
+.br
+The name and version number of the server (typically CUPS/1.1).
+.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 Interface Design Description,
+CUPS Software Administrators Manual,
+CUPS Software Programmers Manual,
+http://localhost:631/documentation.html
+.SH COPYRIGHT
+Copyright 1993-2002 by Easy Software Products, All Rights Reserved.
+.\"
+.\" End of "$Id: backend.man 2010 2002-01-02 17:59:21Z mike $".
+.\"
diff --git a/man/classes.conf.man b/man/classes.conf.man
new file mode 100644
index 000000000..22eff311e
--- /dev/null
+++ b/man/classes.conf.man
@@ -0,0 +1,72 @@
+.\"
+.\" "$Id: classes.conf.man 2010 2002-01-02 17:59:21Z mike $"
+.\"
+.\" classes.conf man page for the Common UNIX Printing System (CUPS).
+.\"
+.\" Copyright 1997-2002 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 June 2000" "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 located in the \fI/etc/cups\fR directory and
+is generated automatically by the \fIcupsd(8)\fR program when printer
+classes are added or deleted.
+.LP
+Each line in the file can be a configuration directive, a blank line,
+or a comment. Comment lines start with the # character.
+.SH DIRECTIVES
+.TP 5
+<Class name> ... </Class>
+.br
+Defines a specific printer class.
+.TP 5
+Accepting
+.br
+Specifies whether or not the printer class is accepting new jobs.
+.TP 5
+Info
+.br
+Specifies human-readable text describing the printer class.
+.TP 5
+Location
+.br
+Specifies human-readable text describing the location of the printer class.
+.TP 5
+Printer
+.br
+Specifies a printer that is a member of the printer class.
+.TP 5
+State
+.br
+Specifies the initial state of the printer class (Idle or Stopped)
+.TP 5
+StateMessage
+.br
+Specifies the message associated with the state.
+.SH SEE ALSO
+cupsd(8), cupsd.conf(5), mime.convs(5), mime.types(5), printers.conf(5),
+CUPS Software Administrators Manual,
+http://localhost:631/documentation.html
+.SH COPYRIGHT
+Copyright 1993-2002 by Easy Software Products, All Rights Reserved.
+.\"
+.\" End of "$Id: classes.conf.man 2010 2002-01-02 17:59:21Z mike $".
+.\"
diff --git a/man/cups-config.man b/man/cups-config.man
new file mode 100644
index 000000000..4e4b8bb28
--- /dev/null
+++ b/man/cups-config.man
@@ -0,0 +1,95 @@
+.\"
+.\" "$Id: cups-config.man 2010 2002-01-02 17:59:21Z mike $"
+.\"
+.\" cups-config man page for the Common UNIX Printing System (CUPS).
+.\"
+.\" Copyright 1997-2002 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 cups-config 3 "Common UNIX Printing System" "25 October 2001" "Easy Software Products"
+.SH NAME
+cups-config \- get cups api, compiler, directory, and link information.
+.SH SYNOPSIS
+.B cups-config
+--api-version
+.br
+.B cups-config
+--cflags
+.br
+.B cups-config
+--datadir
+.br
+.B cups-config
+--help
+.br
+.B cups-config
+--ldflags
+.br
+.B cups-config
+[
+.I --image
+] [
+.I --static
+] --libs
+.br
+.B cups-config
+--serverbin
+.br
+.B cups-config
+--serverroot
+.br
+.B cups-config
+--version
+.br
+.SH DESCRIPTION
+\fBcups-config\fR is the CUPS program configuration utility. It should be
+used by application developers to determine the necessary command-line
+options for the compiler and linker, as well as determining installation
+directories for filters, configuration files, and drivers.
+.LP
+The \fI--api-version\fR command displays the current API version (major.minor).
+.LP
+The \fI--cflags\fR command displays the necessary compiler options.
+.LP
+The \fI--datadir\fR command displays the default CUPS data directory.
+.LP
+The \fI--help\fR command displays the program usage message.
+.LP
+The \fI--ldflags\fR command displays the necessary linker options.
+.LP
+The \fI--libs\fR command displays the necessary librarys to link to.
+The \fI--image\fR option adds the CUPS imaging library to the list.
+The \fI--static\fR option shows the static libraries instead of the
+default (shared) libraries.
+.LP
+The \fI--serverbin\fR command displays the default CUPS binary directory,
+where filters and backends are stored.
+.LP
+The \fI--serverroot\fR command displays the default CUPS configuration
+file directory.
+.LP
+The \fI--version\fR command displays the full version number of the
+CUPS installation (major.minor.patch).
+.SH SEE ALSO
+CUPS Software Programmers Manual,
+http://localhost:631/documentation.html
+.SH COPYRIGHT
+Copyright 1993-2002 by Easy Software Products, All Rights Reserved.
+.\"
+.\" End of "$Id: cups-config.man 2010 2002-01-02 17:59:21Z mike $".
+.\"
diff --git a/man/cups-lpd.man b/man/cups-lpd.man
new file mode 100644
index 000000000..731754e89
--- /dev/null
+++ b/man/cups-lpd.man
@@ -0,0 +1,92 @@
+.\"
+.\" "$Id: cups-lpd.man 2010 2002-01-02 17:59:21Z mike $"
+.\"
+.\" cups-lpd man page for the Common UNIX Printing System (CUPS).
+.\"
+.\" Copyright 1997-2002 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 cups-lpd 8 "Common UNIX Printing System" "13 February 2001" "Easy Software Products"
+.SH NAME
+cups-lpd \- receive print jobs and report printer status to lpd clients
+.SH SYNOPSIS
+.B cups-lpd
+[ -o
+.I option=value
+]
+.SH DESCRIPTION
+\fBcups-lpd\fR is the CUPS Line Printer Daemon ("LPD") mini-server that
+supports legacy client systems that use the LPD protocol.
+\fBcups-lpd\fR does not act as a standalone network daemon but instead
+operates using the Internet "super-server" \fBinetd(8)\fR. Add the
+following line to the \fBinetd.conf\fR file to enable the
+\fBcups-lpd\fR daemon:
+.br
+.nf
+
+ printer stream tcp nowait lp /usr/lib/cups/daemon/cups-lpd cups-lpd
+.fi
+.LP
+If you are using the newer \fIxinetd(8)\fR daemon, add the following
+lines to the \fBxinetd.conf\fR file:
+.br
+.nf
+
+ service printer
+ {
+ socket_type = stream
+ protocol = tcp
+ wait = no
+ user = lp
+ server = /usr/lib/cups/daemon/cups-lpd
+ }
+.fi
+.SH OPTIONS
+The \fI-o\fR option to \fBcups-lpd\fR inserts options for all print queues.
+Most often this is used to disable the "l" filter so that remote print jobs
+are filtered as needed for printing:
+.br
+.nf
+
+ printer stream tcp nowait lp /usr/lib/cups/daemon/cups-lpd cups-lpd \
+ -o document-format=application/octet-stream
+.fi
+.LP
+The example shown resets the document format to be
+\fIapplication/octet-stream\fR, which forces auto-detection of the print
+file type.
+.SH COMPATIBILITY
+\fBcups-lpd\fR does not enforce the restricted source port
+number specified in RFC 1179, as using restricted ports does not
+prevent determined users from submitting print jobs. While this
+behavior is different than standard Berkeley LPD
+implementations, it should not affect normal client operations.
+.LP
+The output of the status requests follows RFC 2569, Mapping
+between LPD and IPP Protocols. Since many LPD implementations
+stray from this definition, remote status reporting to LPD
+clients may be unreliable.
+.SH SEE ALSO
+inetd(8), xinetd(8),
+CUPS Software Administrators Manual,
+http://localhost:631/documentation.html
+.SH COPYRIGHT
+Copyright 1993-2002 by Easy Software Products, All Rights Reserved.
+.\"
+.\" End of "$Id: cups-lpd.man 2010 2002-01-02 17:59:21Z mike $".
+.\"
diff --git a/man/cups-polld.man b/man/cups-polld.man
new file mode 100644
index 000000000..0ee6ed8e3
--- /dev/null
+++ b/man/cups-polld.man
@@ -0,0 +1,46 @@
+.\"
+.\" "$Id: cups-polld.man 2010 2002-01-02 17:59:21Z mike $"
+.\"
+.\" cups-polld man page for the Common UNIX Printing System (CUPS).
+.\"
+.\" Copyright 1997-2002 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 cups-polld 8 "Common UNIX Printing System" "10 May 2000" "Easy Software Products"
+.SH NAME
+cups-polld \- cups printer polling daemon
+.SH SYNOPSIS
+.B cups-polld
+.I address ipp-port interval browse-port
+.SH DESCRIPTION
+\fBcups-polld\fR polls remote servers for a list of available printers
+and printer classes every \fIinterval\fR seconds. Printer and class
+information is then broadcast to the localhost interface (127.0.0.1)
+for reception by \fBcupsd(8)\fR.
+.PP
+This program is started automatically by \fBcupsd\fR for each
+BrowsePoll directive found in the \fBcupsd.conf\fR file.
+.SH SEE ALSO
+cupsd.conf(5),
+CUPS Software Administrators Manual,
+http://localhost:631/documentation.html
+.SH COPYRIGHT
+Copyright 1993-2002 by Easy Software Products, All Rights Reserved.
+.\"
+.\" End of "$Id: cups-polld.man 2010 2002-01-02 17:59:21Z mike $".
+.\"
diff --git a/man/cupsaddsmb.man b/man/cupsaddsmb.man
new file mode 100644
index 000000000..b916665bf
--- /dev/null
+++ b/man/cupsaddsmb.man
@@ -0,0 +1,114 @@
+.\"
+.\" "$Id: cupsaddsmb.man 2010 2002-01-02 17:59:21Z mike $"
+.\"
+.\" cupsaddsmb man page for the Common UNIX Printing System (CUPS).
+.\"
+.\" Copyright 1997-2002 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 cupsaddsmb 8 "Common UNIX Printing System" "9 November 2001" "Easy Software Products"
+.SH NAME
+cupsaddsmb \- export printers to samba for windows clients
+.SH SYNOPSIS
+.B cupsaddsmb
+[ -a ] [ -U
+.I user
+] [ -v ]
+.br
+.B cupsaddsmb
+[ -u
+.I user
+] [ -v ] [ printer1 ... printerN ]
+.SH DESCRIPTION
+\fIcupsaddsmb\fR exports printers to the SAMBA software (version
+2.2.0 or higher) for use with Windows clients. Depending on the
+SAMBA configuration, you may need to provide a password to
+export the printers. This program requires the Adobe PostScript
+printer driver files described below.
+.LP
+The \fI-a\fR option exports all known printers. Otherwise, only
+the named printers are exported.
+.LP
+The \fI-U\fR option specifies the print admin username which defaults
+to your current username.
+.LP
+The \fI-v\fR option specifies that verbose information should be
+shown and is useful for debugging SAMBA configuration problems.
+.SH SAMBA CONFIGURATION
+\fIcupsaddsmb\fR uses the new RPC-based printing support in
+SAMBA 2.2.x to provide printer drivers and PPD files to Windows
+client machines. In order to use this functionality, you must
+first configure SAMBA (via the smb.conf file) to support
+printing through CUPS and provide a printer driver download
+share, as follows:
+.nf
+
+ [global]
+ load printers = yes
+ printing = cups
+ printcap name = cups
+
+ [printers]
+ comment = All Printers
+ path = /var/spool/samba
+ browseable = no
+ public = yes
+ guest ok = yes
+ writable = no
+ printable = yes
+ printer admin = root
+
+ [print$]
+ comment = Printer Drivers
+ path = /etc/samba/drivers
+ browseable = yes
+ guest ok = no
+ read only = yes
+ write list = root
+.fi
+.LP
+This configuration assumes a FHS-compliant installation of
+SAMBA; adjust the [printers] and [print$] share paths
+accordingly on your system as needed.
+.SH ADOBE POSTSCRIPT DRIVERS FOR WINDOWS
+\fIcupsaddsmb\fR uses the Adobe PostScript printer drivers for
+Windows, which are available for download from the Adobe web
+site (http://www.adobe.com). Once you have extracted the driver
+files, create a "drivers" directory in the CUPS data directory
+(usually /usr/share/cups) and copy the Adobe files using
+UPPERCASE filenames, as follows:
+.nf
+
+ ADFONTS.MFM
+ ADOBEPS4.DRV
+ ADOBEPS4.HLP
+ ADOBEPS5.DLL
+ ADOBEPSU.DLL
+ ADOBEPSU.HLP
+ DEFPRTR2.PPD
+ ICONLIB.DLL
+ PSMON.DLL
+.fi
+.SH SEE ALSO
+CUPS Software Administrators Manual,
+http://localhost:631/documentation.html
+.SH COPYRIGHT
+Copyright 1993-2002 by Easy Software Products, All Rights Reserved.
+.\"
+.\" End of "$Id: cupsaddsmb.man 2010 2002-01-02 17:59:21Z mike $".
+.\"
diff --git a/man/cupsd.conf.man b/man/cupsd.conf.man
new file mode 100644
index 000000000..a91a4582e
--- /dev/null
+++ b/man/cupsd.conf.man
@@ -0,0 +1,246 @@
+.\"
+.\" "$Id: cupsd.conf.man 2010 2002-01-02 17:59:21Z mike $"
+.\"
+.\" cupsd.conf man page for the Common UNIX Printing System (CUPS).
+.\"
+.\" Copyright 1997-2002 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 June 2000" "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. It
+is normally located in the \fI/etc/cups\fR directory.
+.LP
+Each line in the file can be a configuration directive, a blank line,
+or a comment. Comment lines start with the # character. The
+configuration directives are intentionally similar to those used by the
+popular Apache web server software and are described below.
+.SH DIRECTIVES
+The following directives are understood by \fIcupsd\fR. Consult the CUPS
+Software Administrators Manual for a detailed description:
+.TP 5
+AccessLog
+.br
+Defines the access log filename.
+.TP 5
+Allow
+.br
+Allows access from the named hosts or addresses.
+.TP 5
+AuthClass
+.br
+Specifies the authentication class (User, Group, System)
+.TP 5
+AuthType
+.br
+Specifies the authentication type (None, Basic, Digest)
+.TP 5
+BrowseAddress
+.br
+Specifies a broadcast address for outgoing printer information packets.
+.TP 5
+BrowseAllow
+.br
+Allows incoming printer information packets from the named host or address.
+.TP 5
+BrowseDeny
+.br
+Denies incoming printer information packets from the named host or address.
+.TP 5
+BrowseInterval
+.br
+Specifies the maximum interval between printer information broadcasts.
+.TP 5
+BrowseOrder
+.br
+Specifies the order of printer information access control (allow,deny or deny,allow)
+.TP 5
+BrowsePoll
+.br
+Specifies a server to poll for printer information.
+.TP 5
+BrowsePort
+.br
+Specifies the port to listen to for printer information packets.
+.TP 5
+BrowseRelay
+.br
+Specifies that printer information packets should be relayed from one host or
+network to another.
+.TP 5
+BrowseShortNames
+.br
+Specifies whether remote printers will use short names ("printer") or not
+("printer@server"). This option is ignored if more than one remote printer
+exists with the same name.
+.TP 5
+BrowseTimeout
+.br
+Specifies the maximum interval between printer information updates before
+remote printers will be removed from the list of available printers.
+.TP 5
+Browsing
+.br
+Specifies whether or not remote printer browsing should be enabled.
+.TP 5
+DataDir
+.br
+Specified the directory where data files can be found.
+.TP 5
+DefaultCharset
+.br
+Specifies the default character set to use for text.
+.TP 5
+DefaultLanguage
+.br
+Specifies the default language to use for text and web content.
+.TP 5
+Deny
+.br
+Denies access to the named host or address.
+.TP 5
+DocumentRoot
+.br
+Specifies the root directory for the internal web server documents.
+.TP 5
+ErrorLog
+.br
+Specifies the error log filename.
+.TP 5
+Group
+.br
+Specifies the group name or ID that will be used when executing
+external programs.
+.TP 5
+HostNameLookups
+.br
+Specifies whether or not to do reverse lookups on client addresses.
+.TP 5
+ImplicitClasses
+.br
+Specifies whether or not to create implicit classes from identical
+remote printers.
+.TP 5
+KeepAlive
+.br
+Specifies whether or not to support HTTP Keep-Alive.
+.TP 5
+KeepAliveTimeout
+.br
+Specifies the connection timeout for HTTP Keep-Alive.
+.TP 5
+<Location /path> ... </Location>
+.br
+Specifies access control for the named location.
+.TP 5
+LogLevel
+.br
+Specifies the logging level (none, warn, error, info, or debug)
+.TP 5
+MaxClients
+.br
+Specifies the maximum number of simultaneous clients to support.
+.TP 5
+MaxLogSize
+.br
+Specifies the maximum size of the log files before they are
+rotated (0 to disable rotation)
+.TP 5
+MaxRequestSize
+.br
+Specifies the maximum request/file size in bytes (0 for no limit)
+.TP 5
+Order
+.br
+Specifies the order of HTTP access control (allow,deny or deny,allow)
+.TP 5
+PageLog
+.br
+Specifies the page log filename.
+.TP 5
+Port
+.br
+Specifies a port number to listen to for HTTP requests.
+.TP 5
+PreserveJobFiles
+.br
+Specifies whether or not to preserve job files after they are printed.
+.TP 5
+PreserveJobHistory
+.br
+Specifies whether or not to preserve the job history after they are
+printed.
+.TP 5
+Printcap
+.br
+Specifies the filename for a printcap file that is updated automatically
+with a list of available printers (needed for legacy applications)
+.TP 5
+RIPCache
+.br
+Specifies the maximum amount of memory to use when converting images
+and PostScript files to bitmaps for a printer.
+.TP 5
+RequestRoot
+.br
+Specifies the directory to store print jobs and other HTTP request
+data.
+.TP 5
+ServerAdmin
+.br
+Specifies the email address of the server administrator.
+.TP 5
+ServerBin
+.br
+Specifies the directory where backends, CGIs, daemons, and filters may
+be found.
+.TP 5
+ServerName
+.br
+Specifies the fully-qualified hostname of the server.
+.TP 5
+ServerRoot
+.br
+Specifies the directory where the server configuration files can be found.
+.TP 5
+SystemGroup
+.br
+Specifies the group to use for System class authentication.
+.TP 5
+TempDir
+.br
+Specifies the directory where temporary files are stored.
+.TP 5
+Timeout
+.br
+Specifies the HTTP request timeout in seconds.
+.TP 5
+User
+.br
+Specifies the user name or ID that is used when running external programs.
+.SH SEE ALSO
+classes.conf(5), cupsd(8), mime.convs(5), mime.types(5), printers.conf(5),
+CUPS Software Administrators Manual,
+http://localhost:631/documentation.html
+.SH COPYRIGHT
+Copyright 1993-2002 by Easy Software Products, All Rights Reserved.
+.\"
+.\" End of "$Id: cupsd.conf.man 2010 2002-01-02 17:59:21Z mike $".
+.\"
diff --git a/man/cupsd.man b/man/cupsd.man
new file mode 100644
index 000000000..835237125
--- /dev/null
+++ b/man/cupsd.man
@@ -0,0 +1,56 @@
+.\"
+.\" "$Id: cupsd.man 2010 2002-01-02 17:59:21Z mike $"
+.\"
+.\" cupsd man page for the Common UNIX Printing System (CUPS).
+.\"
+.\" Copyright 1997-2002 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" "19 October 2000" "Easy Software Products"
+.SH NAME
+cupsd \- common unix printing system daemon
+.SH SYNOPSIS
+.B cupsd
+[ \-c
+.I config-file
+] [ \-f ]
+.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.1. If no options are specified on the command-line then the
+default configuration file (usually \fI/etc/cups/cupsd.conf\fR) will be
+used.
+.PP
+The \fI-f\fR option forces \fIcupsd\fR to run in the foreground; the
+default is to run in the background as a "daemon".
+.SH COMPATIBILITY
+\fIcupsd\fR implements all of the required IPP/1.1 attributes and
+operations. It also implements 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 Implementation of IPP,
+CUPS Interface Design Description,
+CUPS Software Administrators Manual,
+http://localhost:631/documentation.html
+.SH COPYRIGHT
+Copyright 1993-2002 by Easy Software Products, All Rights Reserved.
+.\"
+.\" End of "$Id: cupsd.man 2010 2002-01-02 17:59:21Z mike $".
+.\"
diff --git a/man/enable.man b/man/enable.man
new file mode 100644
index 000000000..68ce9fb6b
--- /dev/null
+++ b/man/enable.man
@@ -0,0 +1,67 @@
+.\"
+.\" "$Id: enable.man 2060 2002-01-23 17:25:41Z mike $"
+.\"
+.\" enable/disable man page for the Common UNIX Printing System (CUPS).
+.\"
+.\" Copyright 1997-2002 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" "23 January 2001" "Easy Software Products"
+.SH NAME
+disable, enable \- stop/start printers and classes
+.SH SYNOPSIS
+.B disable
+[ -E ] [ \-c ] [ -h
+.I server
+] [ \-r
+.I reason
+] destination(s)
+.br
+.B enable
+[ -E ] 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".
+.LP
+The \fI-E\fR option forces encryption when connecting to the server.
+.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,
+http://localhost:631/documentation.html
+.SH COPYRIGHT
+Copyright 1993-2002 by Easy Software Products, All Rights Reserved.
+
+.\"
+.\" End of "$Id: enable.man 2060 2002-01-23 17:25:41Z mike $".
+.\"
diff --git a/man/filter.man b/man/filter.man
new file mode 100644
index 000000000..56d11214f
--- /dev/null
+++ b/man/filter.man
@@ -0,0 +1,116 @@
+.\"
+.\" "$Id: filter.man 2010 2002-01-02 17:59:21Z mike $"
+.\"
+.\" filter man page for the Common UNIX Printing System (CUPS).
+.\"
+.\" Copyright 1997-2002 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 June 2000" "Easy Software Products"
+.SH NAME
+filter \- cups 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 the standard input to a temporary
+file as required by the file format. All output must be sent to the
+standard output.
+.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
+CUPS_DATADIR
+.br
+The directory where data files can be found.
+.TP 5
+CUPS_SERVERROOT
+.br
+The root directory of the server.
+.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
+SOFTWARE
+.br
+The name and version number of the server (typically CUPS/1.1).
+.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 Interface Design Description,
+CUPS Software Administrators Manual,
+CUPS Software Programmers Manual,
+http://localhost:631/documentation.html
+.SH COPYRIGHT
+Copyright 1993-2002 by Easy Software Products, All Rights Reserved.
+.\"
+.\" End of "$Id: filter.man 2010 2002-01-02 17:59:21Z mike $".
+.\"
diff --git a/man/lp.man b/man/lp.man
new file mode 100644
index 000000000..9567e4524
--- /dev/null
+++ b/man/lp.man
@@ -0,0 +1,160 @@
+.\"
+.\" "$Id: lp.man 2010 2002-01-02 17:59:21Z mike $"
+.\"
+.\" lp/cancel man page for the Common UNIX Printing System (CUPS).
+.\"
+.\" Copyright 1997-2002 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" "25 September 2001" "Easy Software Products"
+.SH NAME
+lp \- print files
+.br
+cancel \- cancel jobs
+.SH SYNOPSIS
+.B lp
+[ -E ] [ \-c ] [ \-d
+.I destination
+] [ \-h
+.I server
+] [ \-m ] [ \-n
+.I num-copies
+[ \-o
+.I option
+] [ \-q
+.I priority
+] [ \-s ] [ \-t
+.I title
+] [ \-H
+.I handling
+] [ \-P
+.I page-list
+] [
+.I file(s)
+]
+.br
+.B lp
+[ -E ] [ \-c ] [ \-h
+.I server
+] [ \-i
+.I job-id
+] [ \-n
+.I num-copies
+[ \-o
+.I option
+] [ \-q
+.I priority
+] [ \-t
+.I title
+] [ \-H
+.I handling
+] [ \-P
+.I page-list
+]
+.br
+.B cancel
+[ \-a ] [ -h
+.I server
+] [
+.I id
+] [
+.I destination
+] [
+.I destination-id
+]
+.SH DESCRIPTION
+\fBlp\fR submits files for printing or alters a pending job.
+.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
+\-E
+.br
+Forces encryption when connecting to the server.
+.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
+\-i \fIjob-id\fR
+.br
+Specifies an existing job to modify.
+.TP 5
+\-m
+.br
+Send email when the job is completed (not supported CUPS 1.1.)
+.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
+\-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.
+.TP 5
+\-H \fIhandling\fR
+.br
+Specifies when the job should be printed. A value of
+\fIimmediate\fR will print the file immediately, a value of
+\fIhold\fR will hold the job indefinitely, and a time value
+(HH:MM) will hold the job until the specified time. Use a value
+of \fIresume\fR with the \fI-i\fR option to resume a held job.
+.TP 5
+\-P \fIpage-list\fR
+.br
+Specifies which pages to print in the document. The list can contain a
+list of numbers and ranges (#-#) separated by commas (e.g. 1,3-5,16).
+.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.1.
+.LP
+The "q" option accepts a different range of values than the
+Solaris lp command, matching the IPP job priority values (1-100)
+instead of the Solaris values (0-39).
+.SH SEE ALSO
+lpstat(1),
+CUPS Software Users Manual,
+http://localhost:631/documentation.html
+.SH COPYRIGHT
+Copyright 1993-2002 by Easy Software Products, All Rights Reserved.
+.\"
+.\" End of "$Id: lp.man 2010 2002-01-02 17:59:21Z mike $".
+.\"
diff --git a/man/lpadmin.man b/man/lpadmin.man
new file mode 100644
index 000000000..befc1cb07
--- /dev/null
+++ b/man/lpadmin.man
@@ -0,0 +1,155 @@
+.\"
+.\" "$Id: lpadmin.man 2010 2002-01-02 17:59:21Z mike $"
+.\"
+.\" lpadmin man page for the Common UNIX Printing System (CUPS).
+.\"
+.\" Copyright 1997-2002 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" "23 January 2001" "Easy Software Products"
+.SH NAME
+lpadmin \- configure cups printers and classes
+.SH SYNOPSIS
+.B lpadmin
+[ -E ] [ -h
+.I server
+] \-d
+.I destination
+.br
+.B lpadmin
+[ -E ] [ -h
+.I server
+] \-p
+.I printer
+.I option(s)
+.br
+.B lpadmin
+[ -E ] [ -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 \fI-E\fR option forces encryption when connecting to the server.
+.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
+\-o \fIname=value\fR
+.br
+Sets a PPD or server option for the printer. PPD options can be listed
+using the \fI-l\fR option with the \fIlpoptions(1)\fR command.
+.TP 5
+\-o \fIjob-k-limit=value\fR
+.br
+Sets the kilobyte limit for per-user quotas. The value is an integer number
+of kilobytes; one kilobyte is 1024 bytes.
+.TP 5
+\-o \fIjob-page-limit=value\fR
+.br
+Sets the page limit for per-user quotas. The value is the integer number of
+pages that can be printed; double-sided pages are counted as two pages.
+.TP 5
+\-o \fIjob-quota-period=value\fR
+.br
+Sets the accounting period for per-user quotas. The value is an integer number
+of seconds; 86,400 seconds are in one day.
+.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
+\-u \fIallow:user,user\fR
+\-u \fIdeny:user,user\fR
+\-u \fIallow:all\fR
+\-u \fIdeny:none\fR
+.br
+Sets user-level access control on a printer. The latter two forms turn
+user-level access control off.
+.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,
+http://localhost:631/documentation.html
+.SH COPYRIGHT
+Copyright 1993-2002 by Easy Software Products, All Rights Reserved.
+.\"
+.\" End of "$Id: lpadmin.man 2010 2002-01-02 17:59:21Z mike $".
+.\"
diff --git a/man/lpc.man b/man/lpc.man
new file mode 100644
index 000000000..e3e5c6ebe
--- /dev/null
+++ b/man/lpc.man
@@ -0,0 +1,80 @@
+.\"
+.\" "$Id: lpc.man 2010 2002-01-02 17:59:21Z mike $"
+.\"
+.\" lpc man page for the Common UNIX Printing System (CUPS).
+.\"
+.\" Copyright 1997-2002 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,
+http://localhost:631/documentation.html
+.SH COPYRIGHT
+Copyright 1993-2002 by Easy Software Products, All Rights Reserved.
+.\"
+.\" End of "$Id: lpc.man 2010 2002-01-02 17:59:21Z mike $".
+.\"
diff --git a/man/lpinfo.man b/man/lpinfo.man
new file mode 100644
index 000000000..99ed6b3a9
--- /dev/null
+++ b/man/lpinfo.man
@@ -0,0 +1,60 @@
+.\"
+.\" "$Id: lpinfo.man 2010 2002-01-02 17:59:21Z mike $"
+.\"
+.\" lpinfo man page for the Common UNIX Printing System (CUPS).
+.\"
+.\" Copyright 1997-2002 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 lpinfo 8 "Common UNIX Printing System" "23 January 2001" "Easy Software Products"
+.SH NAME
+lpinfo \- show available devices or drivers
+.SH SYNOPSIS
+.B lpinfo
+[ -E ] [ -l ] [ -m ] [ -v ]
+.SH DESCRIPTION
+\fBlpinfo\fR lists the available devices or drivers known to the CUPS
+server. One of the \fI-m\fR or \fI-v\fR options must be specified to
+get any output:
+.TP 5
+\-E
+.br
+Forces encryption when connecting to the server.
+.TP 5
+\-l
+.br
+Shows a "long" listing of devices or drivers.
+.TP 5
+\-m
+.br
+Shows the available printer drivers on the system.
+.TP 5
+\-v
+.br
+Shows the available printer devices on the system.
+.SH COMPATIBILITY
+The \fBlpinfo\fR command is unique to CUPS.
+.SH SEE ALSO
+lpadmin(8),
+CUPS Software Administrators Manual,
+http://localhost:631/documentation.html
+.SH COPYRIGHT
+Copyright 1993-2002 by Easy Software Products, All Rights Reserved.
+.\"
+.\" End of "$Id: lpinfo.man 2010 2002-01-02 17:59:21Z mike $".
+.\"
diff --git a/man/lpmove.man b/man/lpmove.man
new file mode 100644
index 000000000..bcbe13dfd
--- /dev/null
+++ b/man/lpmove.man
@@ -0,0 +1,53 @@
+.\"
+.\" "$Id: lpmove.man 2010 2002-01-02 17:59:21Z mike $"
+.\"
+.\" lpmove man page for the Common UNIX Printing System (CUPS).
+.\"
+.\" Copyright 1997-2002 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 lpmove 8 "Common UNIX Printing System" "23 January 2001" "Easy Software Products"
+.SH NAME
+lpmove \- move a job to a new destination
+.SH SYNOPSIS
+.B lpmove
+[ -E ]
+.I job destination
+.SH DESCRIPTION
+\fBlpmove\fR moves the specified \fIjob\fR to \fIdestination\fR. \fIjob\fR
+can be the job ID number or the old destination and job ID:
+.br
+.nf
+
+ lpmove 123 newprinter
+ lpmove oldprinter-123 newprinter
+.fi
+.LP
+The \fI-E\fR option forces encryption when connecting to the server.
+.SH COMPATIBILITY
+The System V version of this command also allows moving of all jobs from one
+queue to another. This functionality is currently not supported by CUPS.
+.SH SEE ALSO
+cancel(1), lp(1),
+CUPS Software Users Manual,
+http://localhost:631/documentation.html
+.SH COPYRIGHT
+Copyright 1993-2002 by Easy Software Products, All Rights Reserved.
+.\"
+.\" End of "$Id: lpmove.man 2010 2002-01-02 17:59:21Z mike $".
+.\"
diff --git a/man/lpoptions.man b/man/lpoptions.man
new file mode 100644
index 000000000..118e50893
--- /dev/null
+++ b/man/lpoptions.man
@@ -0,0 +1,116 @@
+.\"
+.\" "$Id: lpoptions.man 2010 2002-01-02 17:59:21Z mike $"
+.\"
+.\" lpoptions man page for the Common UNIX Printing System (CUPS).
+.\"
+.\" Copyright 1997-2002 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 lpoptions 1 "Common UNIX Printing System" "5 September 2000" "Easy Software Products"
+.SH NAME
+lpoptions \- display or set printer options and defaults
+.SH SYNOPSIS
+.B lpoptions
+[ -h
+.I server
+] -d
+.I dest[/instance]
+[ -o
+.I option=value
+] ... [ -o
+.I option=value
+]
+.br
+.B lpoptions
+[ -h
+.I server
+] [ -p
+.I dest[/instance]
+] -l
+.br
+.B lpoptions
+[ -h
+.I server
+] [ -o
+.I option=value
+] ... [ -o
+.I option=value
+] -p
+.I dest[/instance]
+] -r
+.I option
+]
+.br
+.B lpoptions
+[ -h
+.I server
+] -x
+.I dest[/instance]
+.SH DESCRIPTION
+\fBlpoptions\fR displays or sets printer options and defaults.
+\fBlpoptions\fR shows the default printer options when run with no
+arguments. Other options include:
+.TP 5
+\-d \fIdest[/instance]\fR
+.br
+Sets the default printer to \fIdest\fR. If \fIinstance\fR is supplied then
+that particular instance is used. This option overrides the system default
+printer for the current user.
+.TP 5
+\-h \fIserver\fR
+.br
+Specifies the CUPS server to communicate with.
+.TP 5
+\-l
+.br
+Lists the printer specific options and their current settings.
+.TP 5
+\-o \fIoption=value\fR
+.br
+Specifies a new option for the named destination.
+.TP 5
+\-p \fIdest[/instance]\fR
+.br
+Sets the destination and instance, if specified, for any options that follow.
+If the named instance does not exist then it is created.
+.TP 5
+\-r \fIoption\fR
+.br
+Removes the specified option for the named destination.
+.TP 5
+\-x \fIdest[/instance]\fR
+.br
+Removes the options for the named destination and instance, if specified.
+If the named instance does not exist then this does nothing.
+.LP
+If no options are specified using the \fI-o\fR option then the current
+options for the named printer are reported on the standard output.
+.LP
+Options set with the \fBlpoptions\fR command are used by the \fBlp(1)\fR
+and \fBlpr(1)\fR commands when submitting jobs.
+.SH COMPATIBILITY
+The \fBlpoptions\fR command is unique to CUPS.
+.SH SEE ALSO
+cancel(1), lp(1),
+CUPS Software Users Manual,
+http://localhost:631/documentation.html
+.SH COPYRIGHT
+Copyright 1993-2002 by Easy Software Products, All Rights Reserved.
+.\"
+.\" End of "$Id: lpoptions.man 2010 2002-01-02 17:59:21Z mike $".
+.\"
diff --git a/man/lppasswd.man b/man/lppasswd.man
new file mode 100644
index 000000000..be90f764f
--- /dev/null
+++ b/man/lppasswd.man
@@ -0,0 +1,61 @@
+.\"
+.\" "$Id: lppasswd.man 2010 2002-01-02 17:59:21Z mike $"
+.\"
+.\" lpadmin man page for the Common UNIX Printing System (CUPS).
+.\"
+.\" Copyright 1997-2002 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 lppasswd 1 "Common UNIX Printing System" "7 June 2001" "Easy Software Products"
+.SH NAME
+lppasswd \- add, change, or delete digest passwords.
+.SH SYNOPSIS
+.B lppasswd
+[ -a ] [ -g
+.I groupname
+] [ -x ] [
+.I username
+]
+.SH DESCRIPTION
+\fIlppasswd\fR adds, changes, or deletes passwords in the CUPS digest
+password file, \fIpasswd.md5\fR. When run by a normal user, \fIlppasswd\fR
+will prompt for the old and new passwords. When run by the super-user,
+\fIlppasswd\fR can add new accounts (\fI-a username\fR), change existing
+accounts (\fIusername\fR), or delete accounts (\fI-x username\fR) in the
+digest password file. Digest usernames do not have to match local UNIX
+usernames, but only UNIX usernames are supported by the CUPS client programs
+(\fIlp(1)\fR, \fIlpr(1)\fR, etc.)
+.LP
+The \fI-g\fR option specifies a group other than the system group - "sys",
+"system", or "root", depending on the operating system.
+.SH SECURITY ISSUES
+The \fIlppasswd\fR command is installed setuid to root. While every attempt
+has been made to make it secure against exploits that could grant super-user
+priviledges to unpriviledged users, paranoid system administrators may wish
+to disable or change the ownership of the program to an unpriviledged
+account.
+.SH SEE ALSO
+lp(1), lpr(1),
+CUPS Software Administrators Manual,
+CUPS Software Users Manual,
+http://localhost:631/documentation.html
+.SH COPYRIGHT
+Copyright 1993-2002 by Easy Software Products, All Rights Reserved.
+.\"
+.\" End of "$Id: lppasswd.man 2010 2002-01-02 17:59:21Z mike $".
+.\"
diff --git a/man/lpq.man b/man/lpq.man
new file mode 100644
index 000000000..b3155a67a
--- /dev/null
+++ b/man/lpq.man
@@ -0,0 +1,57 @@
+.\"
+.\" "$Id: lpq.man 2010 2002-01-02 17:59:21Z mike $"
+.\"
+.\" lpq man page for the Common UNIX Printing System (CUPS).
+.\"
+.\" Copyright 1997-2002 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" "13 February 2001" "Easy Software Products"
+.SH NAME
+lpq \- show printer queue status
+.SH SYNOPSIS
+.B lpq
+[ -E ] [ \-P
+.I dest
+] [ \-a ] [ \-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-E\fR option forces encryption when connecting to the server.
+.LP
+The \fI-a\fR option reports jobs on all printers.
+.LP
+The \fI-l\fR option requests a more verbose (long) reporting format.
+.SH SEE ALSO
+cancel(1), lp(1), lpr(1), lprm(1), lpstat(1)
+.br
+CUPS Software Users Manual,
+http://localhost:631/documentation.html
+.SH COPYRIGHT
+Copyright 1993-2002 by Easy Software Products, All Rights Reserved.
+.\"
+.\" End of "$Id: lpq.man 2010 2002-01-02 17:59:21Z mike $".
+.\"
diff --git a/man/lpr.man b/man/lpr.man
new file mode 100644
index 000000000..d86103fae
--- /dev/null
+++ b/man/lpr.man
@@ -0,0 +1,101 @@
+.\"
+.\" "$Id: lpr.man 2010 2002-01-02 17:59:21Z mike $"
+.\"
+.\" lpr man page for the Common UNIX Printing System (CUPS).
+.\"
+.\" Copyright 1997-2002 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" "23 January 2001" "Easy Software Products"
+.SH NAME
+lpr \- print files
+.SH SYNOPSIS
+.B lpr
+[ -E ] [ \-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
+\-E
+.br
+Forces encryption when connecting to the server.
+.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,
+http://localhost:631/documentation.html
+.SH COPYRIGHT
+Copyright 1993-2002 by Easy Software Products, All Rights Reserved.
+.\"
+.\" End of "$Id: lpr.man 2010 2002-01-02 17:59:21Z mike $".
+.\"
diff --git a/man/lprm.man b/man/lprm.man
new file mode 100644
index 000000000..4497ded45
--- /dev/null
+++ b/man/lprm.man
@@ -0,0 +1,54 @@
+.\"
+.\" "$Id: lprm.man 2010 2002-01-02 17:59:21Z mike $"
+.\"
+.\" lprm man page for the Common UNIX Printing System (CUPS).
+.\"
+.\" Copyright 1997-2002 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" "23 January 2001" "Easy Software Products"
+.SH NAME
+lprm \- cancel print jobs
+.SH SYNOPSIS
+.B lprm
+[ -E ] [ - ] [ -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.
+.LP
+The \fI-E\fR option forces encryption when connecting to the server.
+.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,
+http://localhost:631/documentation.html
+.SH COPYRIGHT
+Copyright 1993-2002 by Easy Software Products, All Rights Reserved.
+.\"
+.\" End of "$Id: lprm.man 2010 2002-01-02 17:59:21Z mike $".
+.\"
diff --git a/man/lpstat.man b/man/lpstat.man
new file mode 100644
index 000000000..ed5771a0a
--- /dev/null
+++ b/man/lpstat.man
@@ -0,0 +1,130 @@
+.\"
+.\" "$Id: lpstat.man 2010 2002-01-02 17:59:21Z mike $"
+.\"
+.\" lpstat man page for the Common UNIX Printing System (CUPS).
+.\"
+.\" Copyright 1997-2002 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" "23 January 2001" "Easy Software Products"
+.SH NAME
+lpstat \- print cups status information
+.SH SYNOPSIS
+.B lpstat
+[ -E ] [ -a [
+.I destination(s)
+] ] [ -c [
+.I class(es)
+] [ -d ] [ -h
+.I server
+] [ -l ] [ -o [
+.I destination(s)
+] ] [ -p [
+.I printer(s)
+] ] [ -r ] [ -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
+\-E
+.br
+Forces encryption when connecting to the server.
+.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
+\-l
+.br
+Shows a long listing of printers, classes, or jobs.
+.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
+\-R
+.br
+Shows the ranking of print jobs.
+.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.
+.LP
+The Solaris "-f", "-P", and "-S" options are silently ignored.
+.SH SEE ALSO
+cancel(1), lp(1),
+CUPS Software Users Manual,
+http://localhost:631/documentation.html
+.SH COPYRIGHT
+Copyright 1993-2002 by Easy Software Products, All Rights Reserved.
+.\"
+.\" End of "$Id: lpstat.man 2010 2002-01-02 17:59:21Z mike $".
+.\"
diff --git a/man/mime.convs.man b/man/mime.convs.man
new file mode 100644
index 000000000..c144596ed
--- /dev/null
+++ b/man/mime.convs.man
@@ -0,0 +1,54 @@
+.\"
+.\" "$Id: mime.convs.man 2010 2002-01-02 17:59:21Z mike $"
+.\"
+.\" mime.convs man page for the Common UNIX Printing System (CUPS).
+.\"
+.\" Copyright 1997-2002 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 June 2000" "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/etc/cups\fR) with
+the extension ".convs".
+.LP
+Each line in the \fImime.types\fR file is a comment, blank, or filter
+line. Comment lines start with the # character. Filter lines specify
+the source and destination MIME types along with a relative cost
+associated with the filter and the filter to run:
+.br
+.nf
+
+super/type super/type cost filter
+application/postscript application/vnd.cups-raster 50 pstoraster
+.fi
+.SH SEE ALSO
+classes.conf(5), cupsd(8), cupsd.conf(5), mime.types(5), printers.conf(5),
+CUPS Software Administrators Manual,
+http://localhost:631/documentation.html
+.SH COPYRIGHT
+Copyright 1993-2002 by Easy Software Products, All Rights Reserved.
+.\"
+.\" End of "$Id: mime.convs.man 2010 2002-01-02 17:59:21Z mike $".
+.\"
diff --git a/man/mime.types.man b/man/mime.types.man
new file mode 100644
index 000000000..f9621444f
--- /dev/null
+++ b/man/mime.types.man
@@ -0,0 +1,98 @@
+.\"
+.\" "$Id: mime.types.man 2010 2002-01-02 17:59:21Z mike $"
+.\"
+.\" mime.types man page for the Common UNIX Printing System (CUPS).
+.\"
+.\" Copyright 1997-2002 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 June 2000" "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/etc/cups\fR with the extension
+".types".
+.LP
+Each line in the \fImime.types\fR file is a comment, blank, or rule
+line. Comment lines start with the # character. Rule lines start with
+the MIME type name and are optionally followed by a series of file
+recognition rules that are used to automatically identify print and web
+files:
+.br
+.nf
+
+ super/type rule [ ... ruleN]
+.fi
+The rules may be grouped using parenthesis, joined using "+" for a
+logical AND and "," or whitespace for a logical OR, and negated using
+"!".
+.SH RULES
+Rules take two forms - a filename extension by itself and functions with test
+values inside parenthesis. The following functions are available:
+.TP 5
+match("pattern")
+.br
+Pattern match on filename
+.TP 5
+ascii(offset,length)
+.br
+True if bytes are valid printable ASCII (CR, NL, TAB, BS, 32-126)
+.TP 5
+printable(offset,length)
+.br
+True if bytes are printable 8-bit chars (CR, NL, TAB, BS, 32-126, 128-254)
+.TP 5
+string(offset,"string")
+.br
+True if bytes are identical to string
+.TP 5
+char(offset,value)
+.br
+True if byte is identical
+.TP 5
+short(offset,value)
+.br
+True if 16-bit integer is identical
+.TP 5
+int(offset,value)
+.br
+True if 32-bit integer is identical
+.TP 5
+locale("string")
+.br
+True if current locale matches string
+.TP 5
+contains(offset,range,"string")
+.br
+True if the range contains the string
+.SH STRING CONSTANTS
+String constants can be specified inside quotes ("") for strings
+containing whitespace and angle brackets (<>) for hexadecimal
+strings.
+.SH SEE ALSO
+classes.conf(5), cupsd(8), cupsd.conf(5), mime.convs(5), printers.conf(5),
+CUPS Software Administrators Manual,
+http://localhost:631/documentation.html
+.SH COPYRIGHT
+Copyright 1993-2002 by Easy Software Products, All Rights Reserved.
+.\"
+.\" End of "$Id: mime.types.man 2010 2002-01-02 17:59:21Z mike $".
+.\"
diff --git a/man/printers.conf.man b/man/printers.conf.man
new file mode 100644
index 000000000..fa24d3e9c
--- /dev/null
+++ b/man/printers.conf.man
@@ -0,0 +1,73 @@
+.\"
+.\" "$Id: printers.conf.man 2010 2002-01-02 17:59:21Z mike $"
+.\"
+.\" printers.conf man page for the Common UNIX Printing System (CUPS).
+.\"
+.\" Copyright 1997-2002 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 June 2000" "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 located in the \fI/etc/cups\fR directory and
+is generated automatically by the \fIcupsd(8)\fR program when printers
+are added or deleted.
+.LP
+Each line in the file can be a configuration directive, a blank line,
+or a comment. Comment lines start with the # character.
+.SH DIRECTIVES
+.TP 5
+Accepting
+.br
+Specifies whether or not the printer is accepting new jobs.
+.TP 5
+Info
+.br
+Specifies human-readable text describing the printer.
+.TP 5
+Location
+.br
+Specifies human-readable text describing the location of the printer.
+.TP 5
+DeviceURI
+.br
+Specifies the device URI for a printer.
+.TP 5
+<Printer name> ... </Printer>
+.br
+Defines a specific printer.
+.TP 5
+State
+.br
+Specifies the initial state of the printer (Idle or Stopped)
+.TP 5
+StateMessage
+.br
+Specifies the message associated with the state.
+.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,
+http://localhost:631/documentation.html
+.SH COPYRIGHT
+Copyright 1993-2002 by Easy Software Products, All Rights Reserved.
+.\"
+.\" End of "$Id: printers.conf.man 2010 2002-01-02 17:59:21Z mike $".
+.\"
diff --git a/pdftops/.cvsignore b/pdftops/.cvsignore
new file mode 100644
index 000000000..3c3f724b2
--- /dev/null
+++ b/pdftops/.cvsignore
@@ -0,0 +1 @@
+pdftops
diff --git a/pdftops/Array.cxx b/pdftops/Array.cxx
new file mode 100644
index 000000000..141afc8ca
--- /dev/null
+++ b/pdftops/Array.cxx
@@ -0,0 +1,52 @@
+//========================================================================
+//
+// Array.cc
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#include <stddef.h>
+#include "gmem.h"
+#include "Object.h"
+#include "Array.h"
+
+//------------------------------------------------------------------------
+// Array
+//------------------------------------------------------------------------
+
+Array::Array(XRef *xrefA) {
+ xref = xrefA;
+ elems = NULL;
+ size = length = 0;
+ ref = 1;
+}
+
+Array::~Array() {
+ int i;
+
+ for (i = 0; i < length; ++i)
+ elems[i].free();
+ gfree(elems);
+}
+
+void Array::add(Object *elem) {
+ if (length + 1 > size) {
+ size += 8;
+ elems = (Object *)grealloc(elems, size * sizeof(Object));
+ }
+ elems[length] = *elem;
+ ++length;
+}
+
+Object *Array::get(int i, Object *obj) {
+ return elems[i].fetch(xref, obj);
+}
+
+Object *Array::getNF(int i, Object *obj) {
+ return elems[i].copy(obj);
+}
diff --git a/pdftops/Array.h b/pdftops/Array.h
new file mode 100644
index 000000000..1616fc33f
--- /dev/null
+++ b/pdftops/Array.h
@@ -0,0 +1,56 @@
+//========================================================================
+//
+// Array.h
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifndef ARRAY_H
+#define ARRAY_H
+
+#ifdef __GNUC__
+#pragma interface
+#endif
+
+#include "Object.h"
+
+class XRef;
+
+//------------------------------------------------------------------------
+// Array
+//------------------------------------------------------------------------
+
+class Array {
+public:
+
+ // Constructor.
+ Array(XRef *xrefA);
+
+ // Destructor.
+ ~Array();
+
+ // Reference counting.
+ int incRef() { return ++ref; }
+ int decRef() { return --ref; }
+
+ // Get number of elements.
+ int getLength() { return length; }
+
+ // Add an element.
+ void add(Object *elem);
+
+ // Accessors.
+ Object *get(int i, Object *obj);
+ Object *getNF(int i, Object *obj);
+
+private:
+
+ XRef *xref; // the xref table for this PDF file
+ Object *elems; // array of elements
+ int size; // size of <elems> array
+ int length; // number of elements in array
+ int ref; // reference count
+};
+
+#endif
diff --git a/pdftops/CNS13CMapInfo.h b/pdftops/CNS13CMapInfo.h
new file mode 100644
index 000000000..284e6036d
--- /dev/null
+++ b/pdftops/CNS13CMapInfo.h
@@ -0,0 +1,47771 @@
+//========================================================================
+//
+// CNS13CMapInfo.h
+//
+// This file was automatically generated by makeCMapInfo.
+//
+// Copyright 1998 Derek B. Noonburg
+//
+//========================================================================
+
+#ifndef CNS13CMAPINFO_H
+#define CNS13CMAPINFO_H
+
+static Gushort cns13AdobeCNS10Map2[116] = {
+ 0x0000, 0x0000,
+ 0x0000, 0x0000,
+ 0x0100, 0x0100,
+ 0x0200, 0x0200,
+ 0x0300, 0x0300,
+ 0x0400, 0x0400,
+ 0x0500, 0x0500,
+ 0x0600, 0x0600,
+ 0x0700, 0x0700,
+ 0x0800, 0x0800,
+ 0x0900, 0x0900,
+ 0x0a00, 0x0a00,
+ 0x0b00, 0x0b00,
+ 0x0c00, 0x0c00,
+ 0x0d00, 0x0d00,
+ 0x0e00, 0x0e00,
+ 0x0f00, 0x0f00,
+ 0x1000, 0x1000,
+ 0x1100, 0x1100,
+ 0x1200, 0x1200,
+ 0x1300, 0x1300,
+ 0x1400, 0x1400,
+ 0x1500, 0x1500,
+ 0x1600, 0x1600,
+ 0x1700, 0x1700,
+ 0x1800, 0x1800,
+ 0x1900, 0x1900,
+ 0x1a00, 0x1a00,
+ 0x1b00, 0x1b00,
+ 0x1c00, 0x1c00,
+ 0x1d00, 0x1d00,
+ 0x1e00, 0x1e00,
+ 0x1f00, 0x1f00,
+ 0x2000, 0x2000,
+ 0x2100, 0x2100,
+ 0x2200, 0x2200,
+ 0x2300, 0x2300,
+ 0x2400, 0x2400,
+ 0x2500, 0x2500,
+ 0x2600, 0x2600,
+ 0x2700, 0x2700,
+ 0x2800, 0x2800,
+ 0x2900, 0x2900,
+ 0x2a00, 0x2a00,
+ 0x2b00, 0x2b00,
+ 0x2c00, 0x2c00,
+ 0x2d00, 0x2d00,
+ 0x2e00, 0x2e00,
+ 0x2f00, 0x2f00,
+ 0x3000, 0x3000,
+ 0x3100, 0x3100,
+ 0x3200, 0x3200,
+ 0x3300, 0x3300,
+ 0x3400, 0x3400,
+ 0x3500, 0x3500,
+ 0x3600, 0x3600,
+ 0x3700, 0x3700,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 cns13AdobeCNS10Enc16 = {
+ 0,
+ { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ cns13AdobeCNS10Map2, 58
+};
+
+static Gushort cns13AdobeCNS11Map2[140] = {
+ 0x0000, 0x0000,
+ 0x0000, 0x0000,
+ 0x0100, 0x0100,
+ 0x0200, 0x0200,
+ 0x0300, 0x0300,
+ 0x0400, 0x0400,
+ 0x0500, 0x0500,
+ 0x0600, 0x0600,
+ 0x0700, 0x0700,
+ 0x0800, 0x0800,
+ 0x0900, 0x0900,
+ 0x0a00, 0x0a00,
+ 0x0b00, 0x0b00,
+ 0x0c00, 0x0c00,
+ 0x0d00, 0x0d00,
+ 0x0e00, 0x0e00,
+ 0x0f00, 0x0f00,
+ 0x1000, 0x1000,
+ 0x1100, 0x1100,
+ 0x1200, 0x1200,
+ 0x1300, 0x1300,
+ 0x1400, 0x1400,
+ 0x1500, 0x1500,
+ 0x1600, 0x1600,
+ 0x1700, 0x1700,
+ 0x1800, 0x1800,
+ 0x1900, 0x1900,
+ 0x1a00, 0x1a00,
+ 0x1b00, 0x1b00,
+ 0x1c00, 0x1c00,
+ 0x1d00, 0x1d00,
+ 0x1e00, 0x1e00,
+ 0x1f00, 0x1f00,
+ 0x2000, 0x2000,
+ 0x2100, 0x2100,
+ 0x2200, 0x2200,
+ 0x2300, 0x2300,
+ 0x2400, 0x2400,
+ 0x2500, 0x2500,
+ 0x2600, 0x2600,
+ 0x2700, 0x2700,
+ 0x2800, 0x2800,
+ 0x2900, 0x2900,
+ 0x2a00, 0x2a00,
+ 0x2b00, 0x2b00,
+ 0x2c00, 0x2c00,
+ 0x2d00, 0x2d00,
+ 0x2e00, 0x2e00,
+ 0x2f00, 0x2f00,
+ 0x3000, 0x3000,
+ 0x3100, 0x3100,
+ 0x3200, 0x3200,
+ 0x3300, 0x3300,
+ 0x3400, 0x3400,
+ 0x3500, 0x3500,
+ 0x3600, 0x3600,
+ 0x3700, 0x3700,
+ 0x3800, 0x3800,
+ 0x3900, 0x3900,
+ 0x3a00, 0x3a00,
+ 0x3b00, 0x3b00,
+ 0x3c00, 0x3c00,
+ 0x3d00, 0x3d00,
+ 0x3e00, 0x3e00,
+ 0x3f00, 0x3f00,
+ 0x4000, 0x4000,
+ 0x4100, 0x4100,
+ 0x4200, 0x4200,
+ 0x4300, 0x4300,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 cns13AdobeCNS11Enc16 = {
+ 0,
+ { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ cns13AdobeCNS11Map2, 70
+};
+
+static Gushort cns13AdobeCNS12Map2[142] = {
+ 0x0000, 0x0000,
+ 0x0000, 0x0000,
+ 0x0100, 0x0100,
+ 0x0200, 0x0200,
+ 0x0300, 0x0300,
+ 0x0400, 0x0400,
+ 0x0500, 0x0500,
+ 0x0600, 0x0600,
+ 0x0700, 0x0700,
+ 0x0800, 0x0800,
+ 0x0900, 0x0900,
+ 0x0a00, 0x0a00,
+ 0x0b00, 0x0b00,
+ 0x0c00, 0x0c00,
+ 0x0d00, 0x0d00,
+ 0x0e00, 0x0e00,
+ 0x0f00, 0x0f00,
+ 0x1000, 0x1000,
+ 0x1100, 0x1100,
+ 0x1200, 0x1200,
+ 0x1300, 0x1300,
+ 0x1400, 0x1400,
+ 0x1500, 0x1500,
+ 0x1600, 0x1600,
+ 0x1700, 0x1700,
+ 0x1800, 0x1800,
+ 0x1900, 0x1900,
+ 0x1a00, 0x1a00,
+ 0x1b00, 0x1b00,
+ 0x1c00, 0x1c00,
+ 0x1d00, 0x1d00,
+ 0x1e00, 0x1e00,
+ 0x1f00, 0x1f00,
+ 0x2000, 0x2000,
+ 0x2100, 0x2100,
+ 0x2200, 0x2200,
+ 0x2300, 0x2300,
+ 0x2400, 0x2400,
+ 0x2500, 0x2500,
+ 0x2600, 0x2600,
+ 0x2700, 0x2700,
+ 0x2800, 0x2800,
+ 0x2900, 0x2900,
+ 0x2a00, 0x2a00,
+ 0x2b00, 0x2b00,
+ 0x2c00, 0x2c00,
+ 0x2d00, 0x2d00,
+ 0x2e00, 0x2e00,
+ 0x2f00, 0x2f00,
+ 0x3000, 0x3000,
+ 0x3100, 0x3100,
+ 0x3200, 0x3200,
+ 0x3300, 0x3300,
+ 0x3400, 0x3400,
+ 0x3500, 0x3500,
+ 0x3600, 0x3600,
+ 0x3700, 0x3700,
+ 0x3800, 0x3800,
+ 0x3900, 0x3900,
+ 0x3a00, 0x3a00,
+ 0x3b00, 0x3b00,
+ 0x3c00, 0x3c00,
+ 0x3d00, 0x3d00,
+ 0x3e00, 0x3e00,
+ 0x3f00, 0x3f00,
+ 0x4000, 0x4000,
+ 0x4100, 0x4100,
+ 0x4200, 0x4200,
+ 0x4300, 0x4300,
+ 0x4400, 0x4400,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 cns13AdobeCNS12Enc16 = {
+ 0,
+ { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ cns13AdobeCNS12Map2, 71
+};
+
+static Gushort cns13AdobeCNS13Map2[152] = {
+ 0x0000, 0x0000,
+ 0x0000, 0x0000,
+ 0x0100, 0x0100,
+ 0x0200, 0x0200,
+ 0x0300, 0x0300,
+ 0x0400, 0x0400,
+ 0x0500, 0x0500,
+ 0x0600, 0x0600,
+ 0x0700, 0x0700,
+ 0x0800, 0x0800,
+ 0x0900, 0x0900,
+ 0x0a00, 0x0a00,
+ 0x0b00, 0x0b00,
+ 0x0c00, 0x0c00,
+ 0x0d00, 0x0d00,
+ 0x0e00, 0x0e00,
+ 0x0f00, 0x0f00,
+ 0x1000, 0x1000,
+ 0x1100, 0x1100,
+ 0x1200, 0x1200,
+ 0x1300, 0x1300,
+ 0x1400, 0x1400,
+ 0x1500, 0x1500,
+ 0x1600, 0x1600,
+ 0x1700, 0x1700,
+ 0x1800, 0x1800,
+ 0x1900, 0x1900,
+ 0x1a00, 0x1a00,
+ 0x1b00, 0x1b00,
+ 0x1c00, 0x1c00,
+ 0x1d00, 0x1d00,
+ 0x1e00, 0x1e00,
+ 0x1f00, 0x1f00,
+ 0x2000, 0x2000,
+ 0x2100, 0x2100,
+ 0x2200, 0x2200,
+ 0x2300, 0x2300,
+ 0x2400, 0x2400,
+ 0x2500, 0x2500,
+ 0x2600, 0x2600,
+ 0x2700, 0x2700,
+ 0x2800, 0x2800,
+ 0x2900, 0x2900,
+ 0x2a00, 0x2a00,
+ 0x2b00, 0x2b00,
+ 0x2c00, 0x2c00,
+ 0x2d00, 0x2d00,
+ 0x2e00, 0x2e00,
+ 0x2f00, 0x2f00,
+ 0x3000, 0x3000,
+ 0x3100, 0x3100,
+ 0x3200, 0x3200,
+ 0x3300, 0x3300,
+ 0x3400, 0x3400,
+ 0x3500, 0x3500,
+ 0x3600, 0x3600,
+ 0x3700, 0x3700,
+ 0x3800, 0x3800,
+ 0x3900, 0x3900,
+ 0x3a00, 0x3a00,
+ 0x3b00, 0x3b00,
+ 0x3c00, 0x3c00,
+ 0x3d00, 0x3d00,
+ 0x3e00, 0x3e00,
+ 0x3f00, 0x3f00,
+ 0x4000, 0x4000,
+ 0x4100, 0x4100,
+ 0x4200, 0x4200,
+ 0x4300, 0x4300,
+ 0x4400, 0x4400,
+ 0x4500, 0x4500,
+ 0x4600, 0x4600,
+ 0x4700, 0x4700,
+ 0x4800, 0x4800,
+ 0x4900, 0x4900,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 cns13AdobeCNS13Enc16 = {
+ 0,
+ { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ cns13AdobeCNS13Map2, 76
+};
+
+static Gushort cns13B5HMap2[490] = {
+ 0x0000, 0x0000,
+ 0xa140, 0x0063,
+ 0xa159, 0x35af,
+ 0xa15d, 0x0080,
+ 0xa1a1, 0x00a2,
+ 0xa1f6, 0x00f8,
+ 0xa1f7, 0x00f7,
+ 0xa1f8, 0x00f9,
+ 0xa240, 0x0100,
+ 0xa2a1, 0x013f,
+ 0xa340, 0x019d,
+ 0xa3a1, 0x01dc,
+ 0xa3bd, 0x01f7,
+ 0xa440, 0x0253,
+ 0xa4a1, 0x0292,
+ 0xa540, 0x02f0,
+ 0xa5a1, 0x032f,
+ 0xa640, 0x038d,
+ 0xa6a1, 0x03cc,
+ 0xa740, 0x042a,
+ 0xa7a1, 0x0469,
+ 0xa840, 0x04c7,
+ 0xa8a1, 0x0506,
+ 0xa940, 0x0564,
+ 0xa9a1, 0x05a3,
+ 0xaa40, 0x0601,
+ 0xaaa1, 0x0640,
+ 0xab40, 0x069e,
+ 0xaba1, 0x06dd,
+ 0xac40, 0x073b,
+ 0xaca1, 0x077a,
+ 0xacfe, 0x097f,
+ 0xad40, 0x07d7,
+ 0xada1, 0x0816,
+ 0xae40, 0x0874,
+ 0xaea1, 0x08b3,
+ 0xaf40, 0x0911,
+ 0xafa1, 0x0950,
+ 0xafd0, 0x0980,
+ 0xb040, 0x09af,
+ 0xb0a1, 0x09ee,
+ 0xb140, 0x0a4c,
+ 0xb1a1, 0x0a8b,
+ 0xb240, 0x0ae9,
+ 0xb2a1, 0x0b28,
+ 0xb340, 0x0b86,
+ 0xb3a1, 0x0bc5,
+ 0xb440, 0x0c23,
+ 0xb4a1, 0x0c62,
+ 0xb540, 0x0cc0,
+ 0xb5a1, 0x0cff,
+ 0xb640, 0x0d5d,
+ 0xb6a1, 0x0d9c,
+ 0xb740, 0x0dfa,
+ 0xb7a1, 0x0e39,
+ 0xb840, 0x0e97,
+ 0xb8a1, 0x0ed6,
+ 0xb940, 0x0f34,
+ 0xb9a1, 0x0f73,
+ 0xba40, 0x0fd1,
+ 0xbaa1, 0x1010,
+ 0xbb40, 0x106e,
+ 0xbba1, 0x10ad,
+ 0xbbc8, 0x10d5,
+ 0xbc40, 0x110c,
+ 0xbca1, 0x114b,
+ 0xbd40, 0x11a9,
+ 0xbda1, 0x11e8,
+ 0xbe40, 0x1246,
+ 0xbe52, 0x10d4,
+ 0xbe53, 0x1258,
+ 0xbea1, 0x1284,
+ 0xbf40, 0x12e2,
+ 0xbfa1, 0x1321,
+ 0xc040, 0x137f,
+ 0xc0a1, 0x13be,
+ 0xc140, 0x141c,
+ 0xc1a1, 0x145b,
+ 0xc1ab, 0x1466,
+ 0xc240, 0x14ba,
+ 0xc2a1, 0x14f9,
+ 0xc2cb, 0x1465,
+ 0xc2cc, 0x1523,
+ 0xc340, 0x1556,
+ 0xc361, 0x1578,
+ 0xc3a1, 0x1596,
+ 0xc3b9, 0x15af,
+ 0xc3ba, 0x15ae,
+ 0xc3bb, 0x15b0,
+ 0xc440, 0x15f4,
+ 0xc456, 0x1577,
+ 0xc457, 0x160a,
+ 0xc4a1, 0x1632,
+ 0xc540, 0x1690,
+ 0xc5a1, 0x16cf,
+ 0xc640, 0x172d,
+ 0xc940, 0x176c,
+ 0xc94a, 0x0274,
+ 0xc94b, 0x1776,
+ 0xc96c, 0x1798,
+ 0xc9a1, 0x17ab,
+ 0xc9be, 0x1797,
+ 0xc9bf, 0x17c8,
+ 0xc9ed, 0x17f7,
+ 0xca40, 0x1809,
+ 0xcaa1, 0x1848,
+ 0xcaf7, 0x17f6,
+ 0xcaf8, 0x189e,
+ 0xcb40, 0x18a5,
+ 0xcba1, 0x18e4,
+ 0xcc40, 0x1942,
+ 0xcca1, 0x1981,
+ 0xcd40, 0x19df,
+ 0xcda1, 0x1a1e,
+ 0xce40, 0x1a7c,
+ 0xcea1, 0x1abb,
+ 0xcf40, 0x1b19,
+ 0xcfa1, 0x1b58,
+ 0xd040, 0x1bb6,
+ 0xd0a1, 0x1bf5,
+ 0xd140, 0x1c53,
+ 0xd1a1, 0x1c92,
+ 0xd240, 0x1cf0,
+ 0xd2a1, 0x1d2f,
+ 0xd340, 0x1d8d,
+ 0xd3a1, 0x1dcc,
+ 0xd440, 0x1e2a,
+ 0xd4a1, 0x1e69,
+ 0xd540, 0x1ec7,
+ 0xd5a1, 0x1f06,
+ 0xd640, 0x1f64,
+ 0xd6a1, 0x1fa3,
+ 0xd6cc, 0x2254,
+ 0xd6cd, 0x1fcf,
+ 0xd740, 0x2001,
+ 0xd77a, 0x22b9,
+ 0xd77b, 0x203b,
+ 0xd7a1, 0x203f,
+ 0xd840, 0x209d,
+ 0xd8a1, 0x20dc,
+ 0xd940, 0x213a,
+ 0xd9a1, 0x2179,
+ 0xda40, 0x21d7,
+ 0xdaa1, 0x2216,
+ 0xdadf, 0x1fce,
+ 0xdae0, 0x2255,
+ 0xdb40, 0x2274,
+ 0xdba1, 0x22b3,
+ 0xdba7, 0x22ba,
+ 0xdc40, 0x2312,
+ 0xdca1, 0x2351,
+ 0xdd40, 0x23af,
+ 0xdda1, 0x23ee,
+ 0xddfc, 0x2381,
+ 0xddfd, 0x2449,
+ 0xde40, 0x244b,
+ 0xdea1, 0x248a,
+ 0xdf40, 0x24e8,
+ 0xdfa1, 0x2527,
+ 0xe040, 0x2585,
+ 0xe0a1, 0x25c4,
+ 0xe140, 0x2622,
+ 0xe1a1, 0x2661,
+ 0xe240, 0x26bf,
+ 0xe2a1, 0x26fe,
+ 0xe340, 0x275c,
+ 0xe3a1, 0x279b,
+ 0xe440, 0x27f9,
+ 0xe4a1, 0x2838,
+ 0xe540, 0x2896,
+ 0xe5a1, 0x28d5,
+ 0xe640, 0x2933,
+ 0xe6a1, 0x2972,
+ 0xe740, 0x29d0,
+ 0xe7a1, 0x2a0f,
+ 0xe840, 0x2a6d,
+ 0xe8a1, 0x2aac,
+ 0xe8a3, 0x2aaf,
+ 0xe940, 0x2b0b,
+ 0xe976, 0x2b42,
+ 0xe9a1, 0x2b4b,
+ 0xea40, 0x2ba9,
+ 0xeaa1, 0x2be8,
+ 0xeb40, 0x2c46,
+ 0xeb5b, 0x2c62,
+ 0xeba1, 0x2c86,
+ 0xebf1, 0x2aae,
+ 0xebf2, 0x2cd6,
+ 0xec40, 0x2ce3,
+ 0xeca1, 0x2d22,
+ 0xecde, 0x2b41,
+ 0xecdf, 0x2d5f,
+ 0xed40, 0x2d7f,
+ 0xeda1, 0x2dbe,
+ 0xedaa, 0x2dc8,
+ 0xee40, 0x2e1d,
+ 0xeea1, 0x2e5c,
+ 0xeeeb, 0x3014,
+ 0xeeec, 0x2ea6,
+ 0xef40, 0x2eb9,
+ 0xefa1, 0x2ef8,
+ 0xf040, 0x2f56,
+ 0xf056, 0x2dc7,
+ 0xf057, 0x2f6c,
+ 0xf0a1, 0x2f94,
+ 0xf0cb, 0x2c61,
+ 0xf0cc, 0x2fbe,
+ 0xf140, 0x2ff1,
+ 0xf163, 0x3015,
+ 0xf16b, 0x3160,
+ 0xf16c, 0x301d,
+ 0xf1a1, 0x3030,
+ 0xf240, 0x308e,
+ 0xf268, 0x31ef,
+ 0xf269, 0x30b6,
+ 0xf2a1, 0x30cc,
+ 0xf2c3, 0x30ef,
+ 0xf340, 0x312b,
+ 0xf375, 0x3161,
+ 0xf3a1, 0x316b,
+ 0xf440, 0x31c9,
+ 0xf466, 0x31f0,
+ 0xf4a1, 0x3209,
+ 0xf4b5, 0x30ee,
+ 0xf4b6, 0x321d,
+ 0xf4fd, 0x3265,
+ 0xf540, 0x3267,
+ 0xf5a1, 0x32a6,
+ 0xf640, 0x3304,
+ 0xf663, 0x3264,
+ 0xf664, 0x3327,
+ 0xf6a1, 0x3342,
+ 0xf740, 0x33a0,
+ 0xf7a1, 0x33df,
+ 0xf840, 0x343d,
+ 0xf8a1, 0x347c,
+ 0xf940, 0x34da,
+ 0xf977, 0x3512,
+ 0xf9a1, 0x351a,
+ 0xf9c4, 0x3511,
+ 0xf9c5, 0x353d,
+ 0xf9c6, 0x3549,
+ 0xf9c7, 0x353e,
+ 0xf9d2, 0x354a,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 cns13B5HEnc16 = {
+ 0,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x3550, 0x3551, 0x3552, 0x3553, 0x3554, 0x3555, 0x3556, 0x3557,
+ 0x3558, 0x3559, 0x355a, 0x355b, 0x355c, 0x355d, 0x355e, 0x355f,
+ 0x3560, 0x3561, 0x3562, 0x3563, 0x3564, 0x3565, 0x3566, 0x3567,
+ 0x3568, 0x3569, 0x356a, 0x356b, 0x356c, 0x356d, 0x356e, 0x356f,
+ 0x3570, 0x3571, 0x3572, 0x3573, 0x3574, 0x3575, 0x3576, 0x3577,
+ 0x3578, 0x3579, 0x357a, 0x357b, 0x357c, 0x357d, 0x357e, 0x357f,
+ 0x3580, 0x3581, 0x3582, 0x3583, 0x3584, 0x3585, 0x3586, 0x3587,
+ 0x3588, 0x3589, 0x358a, 0x358b, 0x358c, 0x358d, 0x358e, 0x358f,
+ 0x3590, 0x3591, 0x3592, 0x3593, 0x3594, 0x3595, 0x3596, 0x3597,
+ 0x3598, 0x3599, 0x359a, 0x359b, 0x359c, 0x359d, 0x359e, 0x359f,
+ 0x35a0, 0x35a1, 0x35a2, 0x35a3, 0x35a4, 0x35a5, 0x35a6, 0x35a7,
+ 0x35a8, 0x35a9, 0x35aa, 0x35ab, 0x35ac, 0x35ad, 0x35ae, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ cns13B5HMap2, 245
+};
+
+static Gushort cns13B5VMap2[514] = {
+ 0x0000, 0x0000,
+ 0xa140, 0x0063,
+ 0xa159, 0x35af,
+ 0xa15d, 0x0080,
+ 0xa1a1, 0x00a2,
+ 0xa1f6, 0x00f8,
+ 0xa1f7, 0x00f7,
+ 0xa1f8, 0x00f9,
+ 0xa240, 0x0100,
+ 0xa2a1, 0x013f,
+ 0xa340, 0x019d,
+ 0xa3a1, 0x01dc,
+ 0xa3bd, 0x01f7,
+ 0xa440, 0x0253,
+ 0xa4a1, 0x0292,
+ 0xa540, 0x02f0,
+ 0xa5a1, 0x032f,
+ 0xa640, 0x038d,
+ 0xa6a1, 0x03cc,
+ 0xa740, 0x042a,
+ 0xa7a1, 0x0469,
+ 0xa840, 0x04c7,
+ 0xa8a1, 0x0506,
+ 0xa940, 0x0564,
+ 0xa9a1, 0x05a3,
+ 0xaa40, 0x0601,
+ 0xaaa1, 0x0640,
+ 0xab40, 0x069e,
+ 0xaba1, 0x06dd,
+ 0xac40, 0x073b,
+ 0xaca1, 0x077a,
+ 0xacfe, 0x097f,
+ 0xad40, 0x07d7,
+ 0xada1, 0x0816,
+ 0xae40, 0x0874,
+ 0xaea1, 0x08b3,
+ 0xaf40, 0x0911,
+ 0xafa1, 0x0950,
+ 0xafd0, 0x0980,
+ 0xb040, 0x09af,
+ 0xb0a1, 0x09ee,
+ 0xb140, 0x0a4c,
+ 0xb1a1, 0x0a8b,
+ 0xb240, 0x0ae9,
+ 0xb2a1, 0x0b28,
+ 0xb340, 0x0b86,
+ 0xb3a1, 0x0bc5,
+ 0xb440, 0x0c23,
+ 0xb4a1, 0x0c62,
+ 0xb540, 0x0cc0,
+ 0xb5a1, 0x0cff,
+ 0xb640, 0x0d5d,
+ 0xb6a1, 0x0d9c,
+ 0xb740, 0x0dfa,
+ 0xb7a1, 0x0e39,
+ 0xb840, 0x0e97,
+ 0xb8a1, 0x0ed6,
+ 0xb940, 0x0f34,
+ 0xb9a1, 0x0f73,
+ 0xba40, 0x0fd1,
+ 0xbaa1, 0x1010,
+ 0xbb40, 0x106e,
+ 0xbba1, 0x10ad,
+ 0xbbc8, 0x10d5,
+ 0xbc40, 0x110c,
+ 0xbca1, 0x114b,
+ 0xbd40, 0x11a9,
+ 0xbda1, 0x11e8,
+ 0xbe40, 0x1246,
+ 0xbe52, 0x10d4,
+ 0xbe53, 0x1258,
+ 0xbea1, 0x1284,
+ 0xbf40, 0x12e2,
+ 0xbfa1, 0x1321,
+ 0xc040, 0x137f,
+ 0xc0a1, 0x13be,
+ 0xc140, 0x141c,
+ 0xc1a1, 0x145b,
+ 0xc1ab, 0x1466,
+ 0xc240, 0x14ba,
+ 0xc2a1, 0x14f9,
+ 0xc2cb, 0x1465,
+ 0xc2cc, 0x1523,
+ 0xc340, 0x1556,
+ 0xc361, 0x1578,
+ 0xc3a1, 0x1596,
+ 0xc3b9, 0x15af,
+ 0xc3ba, 0x15ae,
+ 0xc3bb, 0x15b0,
+ 0xc440, 0x15f4,
+ 0xc456, 0x1577,
+ 0xc457, 0x160a,
+ 0xc4a1, 0x1632,
+ 0xc540, 0x1690,
+ 0xc5a1, 0x16cf,
+ 0xc640, 0x172d,
+ 0xc940, 0x176c,
+ 0xc94a, 0x0274,
+ 0xc94b, 0x1776,
+ 0xc96c, 0x1798,
+ 0xc9a1, 0x17ab,
+ 0xc9be, 0x1797,
+ 0xc9bf, 0x17c8,
+ 0xc9ed, 0x17f7,
+ 0xca40, 0x1809,
+ 0xcaa1, 0x1848,
+ 0xcaf7, 0x17f6,
+ 0xcaf8, 0x189e,
+ 0xcb40, 0x18a5,
+ 0xcba1, 0x18e4,
+ 0xcc40, 0x1942,
+ 0xcca1, 0x1981,
+ 0xcd40, 0x19df,
+ 0xcda1, 0x1a1e,
+ 0xce40, 0x1a7c,
+ 0xcea1, 0x1abb,
+ 0xcf40, 0x1b19,
+ 0xcfa1, 0x1b58,
+ 0xd040, 0x1bb6,
+ 0xd0a1, 0x1bf5,
+ 0xd140, 0x1c53,
+ 0xd1a1, 0x1c92,
+ 0xd240, 0x1cf0,
+ 0xd2a1, 0x1d2f,
+ 0xd340, 0x1d8d,
+ 0xd3a1, 0x1dcc,
+ 0xd440, 0x1e2a,
+ 0xd4a1, 0x1e69,
+ 0xd540, 0x1ec7,
+ 0xd5a1, 0x1f06,
+ 0xd640, 0x1f64,
+ 0xd6a1, 0x1fa3,
+ 0xd6cc, 0x2254,
+ 0xd6cd, 0x1fcf,
+ 0xd740, 0x2001,
+ 0xd77a, 0x22b9,
+ 0xd77b, 0x203b,
+ 0xd7a1, 0x203f,
+ 0xd840, 0x209d,
+ 0xd8a1, 0x20dc,
+ 0xd940, 0x213a,
+ 0xd9a1, 0x2179,
+ 0xda40, 0x21d7,
+ 0xdaa1, 0x2216,
+ 0xdadf, 0x1fce,
+ 0xdae0, 0x2255,
+ 0xdb40, 0x2274,
+ 0xdba1, 0x22b3,
+ 0xdba7, 0x22ba,
+ 0xdc40, 0x2312,
+ 0xdca1, 0x2351,
+ 0xdd40, 0x23af,
+ 0xdda1, 0x23ee,
+ 0xddfc, 0x2381,
+ 0xddfd, 0x2449,
+ 0xde40, 0x244b,
+ 0xdea1, 0x248a,
+ 0xdf40, 0x24e8,
+ 0xdfa1, 0x2527,
+ 0xe040, 0x2585,
+ 0xe0a1, 0x25c4,
+ 0xe140, 0x2622,
+ 0xe1a1, 0x2661,
+ 0xe240, 0x26bf,
+ 0xe2a1, 0x26fe,
+ 0xe340, 0x275c,
+ 0xe3a1, 0x279b,
+ 0xe440, 0x27f9,
+ 0xe4a1, 0x2838,
+ 0xe540, 0x2896,
+ 0xe5a1, 0x28d5,
+ 0xe640, 0x2933,
+ 0xe6a1, 0x2972,
+ 0xe740, 0x29d0,
+ 0xe7a1, 0x2a0f,
+ 0xe840, 0x2a6d,
+ 0xe8a1, 0x2aac,
+ 0xe8a3, 0x2aaf,
+ 0xe940, 0x2b0b,
+ 0xe976, 0x2b42,
+ 0xe9a1, 0x2b4b,
+ 0xea40, 0x2ba9,
+ 0xeaa1, 0x2be8,
+ 0xeb40, 0x2c46,
+ 0xeb5b, 0x2c62,
+ 0xeba1, 0x2c86,
+ 0xebf1, 0x2aae,
+ 0xebf2, 0x2cd6,
+ 0xec40, 0x2ce3,
+ 0xeca1, 0x2d22,
+ 0xecde, 0x2b41,
+ 0xecdf, 0x2d5f,
+ 0xed40, 0x2d7f,
+ 0xeda1, 0x2dbe,
+ 0xedaa, 0x2dc8,
+ 0xee40, 0x2e1d,
+ 0xeea1, 0x2e5c,
+ 0xeeeb, 0x3014,
+ 0xeeec, 0x2ea6,
+ 0xef40, 0x2eb9,
+ 0xefa1, 0x2ef8,
+ 0xf040, 0x2f56,
+ 0xf056, 0x2dc7,
+ 0xf057, 0x2f6c,
+ 0xf0a1, 0x2f94,
+ 0xf0cb, 0x2c61,
+ 0xf0cc, 0x2fbe,
+ 0xf140, 0x2ff1,
+ 0xf163, 0x3015,
+ 0xf16b, 0x3160,
+ 0xf16c, 0x301d,
+ 0xf1a1, 0x3030,
+ 0xf240, 0x308e,
+ 0xf268, 0x31ef,
+ 0xf269, 0x30b6,
+ 0xf2a1, 0x30cc,
+ 0xf2c3, 0x30ef,
+ 0xf340, 0x312b,
+ 0xf375, 0x3161,
+ 0xf3a1, 0x316b,
+ 0xf440, 0x31c9,
+ 0xf466, 0x31f0,
+ 0xf4a1, 0x3209,
+ 0xf4b5, 0x30ee,
+ 0xf4b6, 0x321d,
+ 0xf4fd, 0x3265,
+ 0xf540, 0x3267,
+ 0xf5a1, 0x32a6,
+ 0xf640, 0x3304,
+ 0xf663, 0x3264,
+ 0xf664, 0x3327,
+ 0xf6a1, 0x3342,
+ 0xf740, 0x33a0,
+ 0xf7a1, 0x33df,
+ 0xf840, 0x343d,
+ 0xf8a1, 0x347c,
+ 0xf940, 0x34da,
+ 0xf977, 0x3512,
+ 0xf9a1, 0x351a,
+ 0xf9c4, 0x3511,
+ 0xf9c5, 0x353d,
+ 0xf9c6, 0x3549,
+ 0xf9c7, 0x353e,
+ 0xf9d2, 0x354a,
+ 0xa14b, 0x354e,
+ 0xa15a, 0x35af,
+ 0xa15c, 0x35b1,
+ 0xa15d, 0x0082,
+ 0xa161, 0x0086,
+ 0xa165, 0x008a,
+ 0xa169, 0x008e,
+ 0xa16d, 0x0092,
+ 0xa171, 0x0096,
+ 0xa175, 0x009a,
+ 0xa179, 0x009e,
+ 0xa1e3, 0x354f,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 cns13B5VEnc16 = {
+ 1,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x3550, 0x3551, 0x3552, 0x3553, 0x3554, 0x3555, 0x3556, 0x3557,
+ 0x3558, 0x3559, 0x355a, 0x355b, 0x355c, 0x355d, 0x355e, 0x355f,
+ 0x3560, 0x3561, 0x3562, 0x3563, 0x3564, 0x3565, 0x3566, 0x3567,
+ 0x3568, 0x3569, 0x356a, 0x356b, 0x356c, 0x356d, 0x356e, 0x356f,
+ 0x3570, 0x3571, 0x3572, 0x3573, 0x3574, 0x3575, 0x3576, 0x3577,
+ 0x3578, 0x3579, 0x357a, 0x357b, 0x357c, 0x357d, 0x357e, 0x357f,
+ 0x3580, 0x3581, 0x3582, 0x3583, 0x3584, 0x3585, 0x3586, 0x3587,
+ 0x3588, 0x3589, 0x358a, 0x358b, 0x358c, 0x358d, 0x358e, 0x358f,
+ 0x3590, 0x3591, 0x3592, 0x3593, 0x3594, 0x3595, 0x3596, 0x3597,
+ 0x3598, 0x3599, 0x359a, 0x359b, 0x359c, 0x359d, 0x359e, 0x359f,
+ 0x35a0, 0x35a1, 0x35a2, 0x35a3, 0x35a4, 0x35a5, 0x35a6, 0x35a7,
+ 0x35a8, 0x35a9, 0x35aa, 0x35ab, 0x35ac, 0x35ad, 0x35ae, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ cns13B5VMap2, 257
+};
+
+static Gushort cns13B5pcHMap2[492] = {
+ 0x0000, 0x0000,
+ 0xa140, 0x0063,
+ 0xa159, 0x35af,
+ 0xa15d, 0x0080,
+ 0xa1a1, 0x00a2,
+ 0xa1f6, 0x00f8,
+ 0xa1f7, 0x00f7,
+ 0xa1f8, 0x00f9,
+ 0xa240, 0x0100,
+ 0xa2a1, 0x013f,
+ 0xa340, 0x019d,
+ 0xa3a1, 0x01dc,
+ 0xa3bd, 0x01f7,
+ 0xa3c0, 0x0232,
+ 0xa440, 0x0253,
+ 0xa4a1, 0x0292,
+ 0xa540, 0x02f0,
+ 0xa5a1, 0x032f,
+ 0xa640, 0x038d,
+ 0xa6a1, 0x03cc,
+ 0xa740, 0x042a,
+ 0xa7a1, 0x0469,
+ 0xa840, 0x04c7,
+ 0xa8a1, 0x0506,
+ 0xa940, 0x0564,
+ 0xa9a1, 0x05a3,
+ 0xaa40, 0x0601,
+ 0xaaa1, 0x0640,
+ 0xab40, 0x069e,
+ 0xaba1, 0x06dd,
+ 0xac40, 0x073b,
+ 0xaca1, 0x077a,
+ 0xacfe, 0x097f,
+ 0xad40, 0x07d7,
+ 0xada1, 0x0816,
+ 0xae40, 0x0874,
+ 0xaea1, 0x08b3,
+ 0xaf40, 0x0911,
+ 0xafa1, 0x0950,
+ 0xafd0, 0x0980,
+ 0xb040, 0x09af,
+ 0xb0a1, 0x09ee,
+ 0xb140, 0x0a4c,
+ 0xb1a1, 0x0a8b,
+ 0xb240, 0x0ae9,
+ 0xb2a1, 0x0b28,
+ 0xb340, 0x0b86,
+ 0xb3a1, 0x0bc5,
+ 0xb440, 0x0c23,
+ 0xb4a1, 0x0c62,
+ 0xb540, 0x0cc0,
+ 0xb5a1, 0x0cff,
+ 0xb640, 0x0d5d,
+ 0xb6a1, 0x0d9c,
+ 0xb740, 0x0dfa,
+ 0xb7a1, 0x0e39,
+ 0xb840, 0x0e97,
+ 0xb8a1, 0x0ed6,
+ 0xb940, 0x0f34,
+ 0xb9a1, 0x0f73,
+ 0xba40, 0x0fd1,
+ 0xbaa1, 0x1010,
+ 0xbb40, 0x106e,
+ 0xbba1, 0x10ad,
+ 0xbbc8, 0x10d5,
+ 0xbc40, 0x110c,
+ 0xbca1, 0x114b,
+ 0xbd40, 0x11a9,
+ 0xbda1, 0x11e8,
+ 0xbe40, 0x1246,
+ 0xbe52, 0x10d4,
+ 0xbe53, 0x1258,
+ 0xbea1, 0x1284,
+ 0xbf40, 0x12e2,
+ 0xbfa1, 0x1321,
+ 0xc040, 0x137f,
+ 0xc0a1, 0x13be,
+ 0xc140, 0x141c,
+ 0xc1a1, 0x145b,
+ 0xc1ab, 0x1466,
+ 0xc240, 0x14ba,
+ 0xc2a1, 0x14f9,
+ 0xc2cb, 0x1465,
+ 0xc2cc, 0x1523,
+ 0xc340, 0x1556,
+ 0xc361, 0x1578,
+ 0xc3a1, 0x1596,
+ 0xc3b9, 0x15af,
+ 0xc3ba, 0x15ae,
+ 0xc3bb, 0x15b0,
+ 0xc440, 0x15f4,
+ 0xc456, 0x1577,
+ 0xc457, 0x160a,
+ 0xc4a1, 0x1632,
+ 0xc540, 0x1690,
+ 0xc5a1, 0x16cf,
+ 0xc640, 0x172d,
+ 0xc940, 0x176c,
+ 0xc94a, 0x0274,
+ 0xc94b, 0x1776,
+ 0xc96c, 0x1798,
+ 0xc9a1, 0x17ab,
+ 0xc9be, 0x1797,
+ 0xc9bf, 0x17c8,
+ 0xc9ed, 0x17f7,
+ 0xca40, 0x1809,
+ 0xcaa1, 0x1848,
+ 0xcaf7, 0x17f6,
+ 0xcaf8, 0x189e,
+ 0xcb40, 0x18a5,
+ 0xcba1, 0x18e4,
+ 0xcc40, 0x1942,
+ 0xcca1, 0x1981,
+ 0xcd40, 0x19df,
+ 0xcda1, 0x1a1e,
+ 0xce40, 0x1a7c,
+ 0xcea1, 0x1abb,
+ 0xcf40, 0x1b19,
+ 0xcfa1, 0x1b58,
+ 0xd040, 0x1bb6,
+ 0xd0a1, 0x1bf5,
+ 0xd140, 0x1c53,
+ 0xd1a1, 0x1c92,
+ 0xd240, 0x1cf0,
+ 0xd2a1, 0x1d2f,
+ 0xd340, 0x1d8d,
+ 0xd3a1, 0x1dcc,
+ 0xd440, 0x1e2a,
+ 0xd4a1, 0x1e69,
+ 0xd540, 0x1ec7,
+ 0xd5a1, 0x1f06,
+ 0xd640, 0x1f64,
+ 0xd6a1, 0x1fa3,
+ 0xd6cc, 0x2254,
+ 0xd6cd, 0x1fcf,
+ 0xd740, 0x2001,
+ 0xd77a, 0x22b9,
+ 0xd77b, 0x203b,
+ 0xd7a1, 0x203f,
+ 0xd840, 0x209d,
+ 0xd8a1, 0x20dc,
+ 0xd940, 0x213a,
+ 0xd9a1, 0x2179,
+ 0xda40, 0x21d7,
+ 0xdaa1, 0x2216,
+ 0xdadf, 0x1fce,
+ 0xdae0, 0x2255,
+ 0xdb40, 0x2274,
+ 0xdba1, 0x22b3,
+ 0xdba7, 0x22ba,
+ 0xdc40, 0x2312,
+ 0xdca1, 0x2351,
+ 0xdd40, 0x23af,
+ 0xdda1, 0x23ee,
+ 0xddfc, 0x2381,
+ 0xddfd, 0x2449,
+ 0xde40, 0x244b,
+ 0xdea1, 0x248a,
+ 0xdf40, 0x24e8,
+ 0xdfa1, 0x2527,
+ 0xe040, 0x2585,
+ 0xe0a1, 0x25c4,
+ 0xe140, 0x2622,
+ 0xe1a1, 0x2661,
+ 0xe240, 0x26bf,
+ 0xe2a1, 0x26fe,
+ 0xe340, 0x275c,
+ 0xe3a1, 0x279b,
+ 0xe440, 0x27f9,
+ 0xe4a1, 0x2838,
+ 0xe540, 0x2896,
+ 0xe5a1, 0x28d5,
+ 0xe640, 0x2933,
+ 0xe6a1, 0x2972,
+ 0xe740, 0x29d0,
+ 0xe7a1, 0x2a0f,
+ 0xe840, 0x2a6d,
+ 0xe8a1, 0x2aac,
+ 0xe8a3, 0x2aaf,
+ 0xe940, 0x2b0b,
+ 0xe976, 0x2b42,
+ 0xe9a1, 0x2b4b,
+ 0xea40, 0x2ba9,
+ 0xeaa1, 0x2be8,
+ 0xeb40, 0x2c46,
+ 0xeb5b, 0x2c62,
+ 0xeba1, 0x2c86,
+ 0xebf1, 0x2aae,
+ 0xebf2, 0x2cd6,
+ 0xec40, 0x2ce3,
+ 0xeca1, 0x2d22,
+ 0xecde, 0x2b41,
+ 0xecdf, 0x2d5f,
+ 0xed40, 0x2d7f,
+ 0xeda1, 0x2dbe,
+ 0xedaa, 0x2dc8,
+ 0xee40, 0x2e1d,
+ 0xeea1, 0x2e5c,
+ 0xeeeb, 0x3014,
+ 0xeeec, 0x2ea6,
+ 0xef40, 0x2eb9,
+ 0xefa1, 0x2ef8,
+ 0xf040, 0x2f56,
+ 0xf056, 0x2dc7,
+ 0xf057, 0x2f6c,
+ 0xf0a1, 0x2f94,
+ 0xf0cb, 0x2c61,
+ 0xf0cc, 0x2fbe,
+ 0xf140, 0x2ff1,
+ 0xf163, 0x3015,
+ 0xf16b, 0x3160,
+ 0xf16c, 0x301d,
+ 0xf1a1, 0x3030,
+ 0xf240, 0x308e,
+ 0xf268, 0x31ef,
+ 0xf269, 0x30b6,
+ 0xf2a1, 0x30cc,
+ 0xf2c3, 0x30ef,
+ 0xf340, 0x312b,
+ 0xf375, 0x3161,
+ 0xf3a1, 0x316b,
+ 0xf440, 0x31c9,
+ 0xf466, 0x31f0,
+ 0xf4a1, 0x3209,
+ 0xf4b5, 0x30ee,
+ 0xf4b6, 0x321d,
+ 0xf4fd, 0x3265,
+ 0xf540, 0x3267,
+ 0xf5a1, 0x32a6,
+ 0xf640, 0x3304,
+ 0xf663, 0x3264,
+ 0xf664, 0x3327,
+ 0xf6a1, 0x3342,
+ 0xf740, 0x33a0,
+ 0xf7a1, 0x33df,
+ 0xf840, 0x343d,
+ 0xf8a1, 0x347c,
+ 0xf940, 0x34da,
+ 0xf977, 0x3512,
+ 0xf9a1, 0x351a,
+ 0xf9c4, 0x3511,
+ 0xf9c5, 0x353d,
+ 0xf9c6, 0x3549,
+ 0xf9c7, 0x353e,
+ 0xf9d2, 0x354a,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 cns13B5pcHEnc16 = {
+ 0,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
+ 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010,
+ 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018,
+ 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020,
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028,
+ 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030,
+ 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038,
+ 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040,
+ 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048,
+ 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050,
+ 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
+ 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0000,
+ 0x003d, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0060, 0x0061, 0x0062 },
+ cns13B5pcHMap2, 246
+};
+
+static Gushort cns13B5pcVMap2[516] = {
+ 0x0000, 0x0000,
+ 0xa140, 0x0063,
+ 0xa159, 0x35af,
+ 0xa15d, 0x0080,
+ 0xa1a1, 0x00a2,
+ 0xa1f6, 0x00f8,
+ 0xa1f7, 0x00f7,
+ 0xa1f8, 0x00f9,
+ 0xa240, 0x0100,
+ 0xa2a1, 0x013f,
+ 0xa340, 0x019d,
+ 0xa3a1, 0x01dc,
+ 0xa3bd, 0x01f7,
+ 0xa3c0, 0x0232,
+ 0xa440, 0x0253,
+ 0xa4a1, 0x0292,
+ 0xa540, 0x02f0,
+ 0xa5a1, 0x032f,
+ 0xa640, 0x038d,
+ 0xa6a1, 0x03cc,
+ 0xa740, 0x042a,
+ 0xa7a1, 0x0469,
+ 0xa840, 0x04c7,
+ 0xa8a1, 0x0506,
+ 0xa940, 0x0564,
+ 0xa9a1, 0x05a3,
+ 0xaa40, 0x0601,
+ 0xaaa1, 0x0640,
+ 0xab40, 0x069e,
+ 0xaba1, 0x06dd,
+ 0xac40, 0x073b,
+ 0xaca1, 0x077a,
+ 0xacfe, 0x097f,
+ 0xad40, 0x07d7,
+ 0xada1, 0x0816,
+ 0xae40, 0x0874,
+ 0xaea1, 0x08b3,
+ 0xaf40, 0x0911,
+ 0xafa1, 0x0950,
+ 0xafd0, 0x0980,
+ 0xb040, 0x09af,
+ 0xb0a1, 0x09ee,
+ 0xb140, 0x0a4c,
+ 0xb1a1, 0x0a8b,
+ 0xb240, 0x0ae9,
+ 0xb2a1, 0x0b28,
+ 0xb340, 0x0b86,
+ 0xb3a1, 0x0bc5,
+ 0xb440, 0x0c23,
+ 0xb4a1, 0x0c62,
+ 0xb540, 0x0cc0,
+ 0xb5a1, 0x0cff,
+ 0xb640, 0x0d5d,
+ 0xb6a1, 0x0d9c,
+ 0xb740, 0x0dfa,
+ 0xb7a1, 0x0e39,
+ 0xb840, 0x0e97,
+ 0xb8a1, 0x0ed6,
+ 0xb940, 0x0f34,
+ 0xb9a1, 0x0f73,
+ 0xba40, 0x0fd1,
+ 0xbaa1, 0x1010,
+ 0xbb40, 0x106e,
+ 0xbba1, 0x10ad,
+ 0xbbc8, 0x10d5,
+ 0xbc40, 0x110c,
+ 0xbca1, 0x114b,
+ 0xbd40, 0x11a9,
+ 0xbda1, 0x11e8,
+ 0xbe40, 0x1246,
+ 0xbe52, 0x10d4,
+ 0xbe53, 0x1258,
+ 0xbea1, 0x1284,
+ 0xbf40, 0x12e2,
+ 0xbfa1, 0x1321,
+ 0xc040, 0x137f,
+ 0xc0a1, 0x13be,
+ 0xc140, 0x141c,
+ 0xc1a1, 0x145b,
+ 0xc1ab, 0x1466,
+ 0xc240, 0x14ba,
+ 0xc2a1, 0x14f9,
+ 0xc2cb, 0x1465,
+ 0xc2cc, 0x1523,
+ 0xc340, 0x1556,
+ 0xc361, 0x1578,
+ 0xc3a1, 0x1596,
+ 0xc3b9, 0x15af,
+ 0xc3ba, 0x15ae,
+ 0xc3bb, 0x15b0,
+ 0xc440, 0x15f4,
+ 0xc456, 0x1577,
+ 0xc457, 0x160a,
+ 0xc4a1, 0x1632,
+ 0xc540, 0x1690,
+ 0xc5a1, 0x16cf,
+ 0xc640, 0x172d,
+ 0xc940, 0x176c,
+ 0xc94a, 0x0274,
+ 0xc94b, 0x1776,
+ 0xc96c, 0x1798,
+ 0xc9a1, 0x17ab,
+ 0xc9be, 0x1797,
+ 0xc9bf, 0x17c8,
+ 0xc9ed, 0x17f7,
+ 0xca40, 0x1809,
+ 0xcaa1, 0x1848,
+ 0xcaf7, 0x17f6,
+ 0xcaf8, 0x189e,
+ 0xcb40, 0x18a5,
+ 0xcba1, 0x18e4,
+ 0xcc40, 0x1942,
+ 0xcca1, 0x1981,
+ 0xcd40, 0x19df,
+ 0xcda1, 0x1a1e,
+ 0xce40, 0x1a7c,
+ 0xcea1, 0x1abb,
+ 0xcf40, 0x1b19,
+ 0xcfa1, 0x1b58,
+ 0xd040, 0x1bb6,
+ 0xd0a1, 0x1bf5,
+ 0xd140, 0x1c53,
+ 0xd1a1, 0x1c92,
+ 0xd240, 0x1cf0,
+ 0xd2a1, 0x1d2f,
+ 0xd340, 0x1d8d,
+ 0xd3a1, 0x1dcc,
+ 0xd440, 0x1e2a,
+ 0xd4a1, 0x1e69,
+ 0xd540, 0x1ec7,
+ 0xd5a1, 0x1f06,
+ 0xd640, 0x1f64,
+ 0xd6a1, 0x1fa3,
+ 0xd6cc, 0x2254,
+ 0xd6cd, 0x1fcf,
+ 0xd740, 0x2001,
+ 0xd77a, 0x22b9,
+ 0xd77b, 0x203b,
+ 0xd7a1, 0x203f,
+ 0xd840, 0x209d,
+ 0xd8a1, 0x20dc,
+ 0xd940, 0x213a,
+ 0xd9a1, 0x2179,
+ 0xda40, 0x21d7,
+ 0xdaa1, 0x2216,
+ 0xdadf, 0x1fce,
+ 0xdae0, 0x2255,
+ 0xdb40, 0x2274,
+ 0xdba1, 0x22b3,
+ 0xdba7, 0x22ba,
+ 0xdc40, 0x2312,
+ 0xdca1, 0x2351,
+ 0xdd40, 0x23af,
+ 0xdda1, 0x23ee,
+ 0xddfc, 0x2381,
+ 0xddfd, 0x2449,
+ 0xde40, 0x244b,
+ 0xdea1, 0x248a,
+ 0xdf40, 0x24e8,
+ 0xdfa1, 0x2527,
+ 0xe040, 0x2585,
+ 0xe0a1, 0x25c4,
+ 0xe140, 0x2622,
+ 0xe1a1, 0x2661,
+ 0xe240, 0x26bf,
+ 0xe2a1, 0x26fe,
+ 0xe340, 0x275c,
+ 0xe3a1, 0x279b,
+ 0xe440, 0x27f9,
+ 0xe4a1, 0x2838,
+ 0xe540, 0x2896,
+ 0xe5a1, 0x28d5,
+ 0xe640, 0x2933,
+ 0xe6a1, 0x2972,
+ 0xe740, 0x29d0,
+ 0xe7a1, 0x2a0f,
+ 0xe840, 0x2a6d,
+ 0xe8a1, 0x2aac,
+ 0xe8a3, 0x2aaf,
+ 0xe940, 0x2b0b,
+ 0xe976, 0x2b42,
+ 0xe9a1, 0x2b4b,
+ 0xea40, 0x2ba9,
+ 0xeaa1, 0x2be8,
+ 0xeb40, 0x2c46,
+ 0xeb5b, 0x2c62,
+ 0xeba1, 0x2c86,
+ 0xebf1, 0x2aae,
+ 0xebf2, 0x2cd6,
+ 0xec40, 0x2ce3,
+ 0xeca1, 0x2d22,
+ 0xecde, 0x2b41,
+ 0xecdf, 0x2d5f,
+ 0xed40, 0x2d7f,
+ 0xeda1, 0x2dbe,
+ 0xedaa, 0x2dc8,
+ 0xee40, 0x2e1d,
+ 0xeea1, 0x2e5c,
+ 0xeeeb, 0x3014,
+ 0xeeec, 0x2ea6,
+ 0xef40, 0x2eb9,
+ 0xefa1, 0x2ef8,
+ 0xf040, 0x2f56,
+ 0xf056, 0x2dc7,
+ 0xf057, 0x2f6c,
+ 0xf0a1, 0x2f94,
+ 0xf0cb, 0x2c61,
+ 0xf0cc, 0x2fbe,
+ 0xf140, 0x2ff1,
+ 0xf163, 0x3015,
+ 0xf16b, 0x3160,
+ 0xf16c, 0x301d,
+ 0xf1a1, 0x3030,
+ 0xf240, 0x308e,
+ 0xf268, 0x31ef,
+ 0xf269, 0x30b6,
+ 0xf2a1, 0x30cc,
+ 0xf2c3, 0x30ef,
+ 0xf340, 0x312b,
+ 0xf375, 0x3161,
+ 0xf3a1, 0x316b,
+ 0xf440, 0x31c9,
+ 0xf466, 0x31f0,
+ 0xf4a1, 0x3209,
+ 0xf4b5, 0x30ee,
+ 0xf4b6, 0x321d,
+ 0xf4fd, 0x3265,
+ 0xf540, 0x3267,
+ 0xf5a1, 0x32a6,
+ 0xf640, 0x3304,
+ 0xf663, 0x3264,
+ 0xf664, 0x3327,
+ 0xf6a1, 0x3342,
+ 0xf740, 0x33a0,
+ 0xf7a1, 0x33df,
+ 0xf840, 0x343d,
+ 0xf8a1, 0x347c,
+ 0xf940, 0x34da,
+ 0xf977, 0x3512,
+ 0xf9a1, 0x351a,
+ 0xf9c4, 0x3511,
+ 0xf9c5, 0x353d,
+ 0xf9c6, 0x3549,
+ 0xf9c7, 0x353e,
+ 0xf9d2, 0x354a,
+ 0xa14b, 0x354e,
+ 0xa15a, 0x35af,
+ 0xa15c, 0x35b1,
+ 0xa15d, 0x0082,
+ 0xa161, 0x0086,
+ 0xa165, 0x008a,
+ 0xa169, 0x008e,
+ 0xa16d, 0x0092,
+ 0xa171, 0x0096,
+ 0xa175, 0x009a,
+ 0xa179, 0x009e,
+ 0xa1e3, 0x354f,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 cns13B5pcVEnc16 = {
+ 1,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
+ 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010,
+ 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018,
+ 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020,
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028,
+ 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030,
+ 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038,
+ 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040,
+ 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048,
+ 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050,
+ 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
+ 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0000,
+ 0x003d, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0060, 0x0061, 0x0062 },
+ cns13B5pcVMap2, 258
+};
+
+static Gushort cns13CNS1HMap2[316] = {
+ 0x0000, 0x0000,
+ 0x2121, 0x0063,
+ 0x2221, 0x00c1,
+ 0x2321, 0x011f,
+ 0x2421, 0x014d,
+ 0x2521, 0x01ab,
+ 0x256e, 0x01f7,
+ 0x2621, 0x01fa,
+ 0x2721, 0x0253,
+ 0x2722, 0x0218,
+ 0x2725, 0x0254,
+ 0x2726, 0x021b,
+ 0x2727, 0x025a,
+ 0x2728, 0x021c,
+ 0x2729, 0x025b,
+ 0x272d, 0x021d,
+ 0x2730, 0x025f,
+ 0x2731, 0x176e,
+ 0x2732, 0x0260,
+ 0x2733, 0x0262,
+ 0x2734, 0x0220,
+ 0x2735, 0x0263,
+ 0x2736, 0x176f,
+ 0x2737, 0x0221,
+ 0x2738, 0x0264,
+ 0x273a, 0x0222,
+ 0x273b, 0x1770,
+ 0x273c, 0x0223,
+ 0x273d, 0x0266,
+ 0x273e, 0x0279,
+ 0x273f, 0x1775,
+ 0x2740, 0x027a,
+ 0x2742, 0x0224,
+ 0x2743, 0x027c,
+ 0x2747, 0x0225,
+ 0x2748, 0x0282,
+ 0x274c, 0x1776,
+ 0x274d, 0x0286,
+ 0x274e, 0x0226,
+ 0x274f, 0x0288,
+ 0x2751, 0x028c,
+ 0x2753, 0x0227,
+ 0x2756, 0x028e,
+ 0x2759, 0x022a,
+ 0x275b, 0x1777,
+ 0x275c, 0x02d0,
+ 0x2760, 0x02d5,
+ 0x2761, 0x022c,
+ 0x2762, 0x02d6,
+ 0x2766, 0x022d,
+ 0x2767, 0x02da,
+ 0x276e, 0x178a,
+ 0x276f, 0x02e1,
+ 0x2773, 0x178c,
+ 0x2774, 0x02e5,
+ 0x2779, 0x178d,
+ 0x277a, 0x02ea,
+ 0x277e, 0x0356,
+ 0x2821, 0x0357,
+ 0x2827, 0x035e,
+ 0x2828, 0x0362,
+ 0x2829, 0x022e,
+ 0x282b, 0x0363,
+ 0x2833, 0x17b2,
+ 0x2834, 0x036b,
+ 0x2837, 0x03f6,
+ 0x283b, 0x1812,
+ 0x283c, 0x03fa,
+ 0x283f, 0x03fe,
+ 0x2844, 0x0405,
+ 0x284d, 0x1813,
+ 0x284e, 0x1818,
+ 0x284f, 0x040f,
+ 0x2853, 0x1819,
+ 0x2854, 0x0508,
+ 0x285a, 0x18e7,
+ 0x285b, 0x050e,
+ 0x2863, 0x0230,
+ 0x2864, 0x051b,
+ 0x2865, 0x0520,
+ 0x2868, 0x0696,
+ 0x286c, 0x0231,
+ 0x286d, 0x069f,
+ 0x2871, 0x0826,
+ 0x287c, 0x09f5,
+ 0x2921, 0x1e33,
+ 0x2922, 0x09f8,
+ 0x2923, 0x1e34,
+ 0x2924, 0x09f9,
+ 0x2926, 0x0be1,
+ 0x292c, 0x0dbb,
+ 0x292f, 0x2360,
+ 0x2930, 0x2612,
+ 0x2931, 0x0f7b,
+ 0x2934, 0x1100,
+ 0x2936, 0x1289,
+ 0x2937, 0x13b2,
+ 0x2939, 0x2f0d,
+ 0x4221, 0x0232,
+ 0x4421, 0x0253,
+ 0x4521, 0x02b1,
+ 0x4621, 0x030f,
+ 0x4721, 0x036d,
+ 0x4821, 0x03cb,
+ 0x4921, 0x0429,
+ 0x4a21, 0x0487,
+ 0x4b21, 0x04e5,
+ 0x4c21, 0x0543,
+ 0x4d21, 0x05a1,
+ 0x4e21, 0x05ff,
+ 0x4f21, 0x065d,
+ 0x5021, 0x06bb,
+ 0x5121, 0x0719,
+ 0x5221, 0x0777,
+ 0x5321, 0x07d5,
+ 0x5421, 0x0833,
+ 0x5521, 0x0891,
+ 0x5621, 0x08ef,
+ 0x5721, 0x094d,
+ 0x5821, 0x09ab,
+ 0x5921, 0x0a09,
+ 0x5a21, 0x0a67,
+ 0x5b21, 0x0ac5,
+ 0x5c21, 0x0b23,
+ 0x5d21, 0x0b81,
+ 0x5e21, 0x0bdf,
+ 0x5f21, 0x0c3d,
+ 0x6021, 0x0c9b,
+ 0x6121, 0x0cf9,
+ 0x6221, 0x0d57,
+ 0x6321, 0x0db5,
+ 0x6421, 0x0e13,
+ 0x6521, 0x0e71,
+ 0x6621, 0x0ecf,
+ 0x6721, 0x0f2d,
+ 0x6821, 0x0f8b,
+ 0x6921, 0x0fe9,
+ 0x6a21, 0x1047,
+ 0x6b21, 0x10a5,
+ 0x6c21, 0x1103,
+ 0x6d21, 0x1161,
+ 0x6e21, 0x11bf,
+ 0x6f21, 0x121d,
+ 0x7021, 0x127b,
+ 0x7121, 0x12d9,
+ 0x7221, 0x1337,
+ 0x7321, 0x1395,
+ 0x7421, 0x13f3,
+ 0x7521, 0x1451,
+ 0x7621, 0x14af,
+ 0x7721, 0x150d,
+ 0x7821, 0x156b,
+ 0x7921, 0x15c9,
+ 0x7a21, 0x1627,
+ 0x7b21, 0x1685,
+ 0x7c21, 0x16e3,
+ 0x7d21, 0x1741,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 cns13CNS1HEnc16 = {
+ 0,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ cns13CNS1HMap2, 158
+};
+
+static Gushort cns13CNS1VMap2[340] = {
+ 0x0000, 0x0000,
+ 0x2121, 0x0063,
+ 0x2221, 0x00c1,
+ 0x2321, 0x011f,
+ 0x2421, 0x014d,
+ 0x2521, 0x01ab,
+ 0x256e, 0x01f7,
+ 0x2621, 0x01fa,
+ 0x2721, 0x0253,
+ 0x2722, 0x0218,
+ 0x2725, 0x0254,
+ 0x2726, 0x021b,
+ 0x2727, 0x025a,
+ 0x2728, 0x021c,
+ 0x2729, 0x025b,
+ 0x272d, 0x021d,
+ 0x2730, 0x025f,
+ 0x2731, 0x176e,
+ 0x2732, 0x0260,
+ 0x2733, 0x0262,
+ 0x2734, 0x0220,
+ 0x2735, 0x0263,
+ 0x2736, 0x176f,
+ 0x2737, 0x0221,
+ 0x2738, 0x0264,
+ 0x273a, 0x0222,
+ 0x273b, 0x1770,
+ 0x273c, 0x0223,
+ 0x273d, 0x0266,
+ 0x273e, 0x0279,
+ 0x273f, 0x1775,
+ 0x2740, 0x027a,
+ 0x2742, 0x0224,
+ 0x2743, 0x027c,
+ 0x2747, 0x0225,
+ 0x2748, 0x0282,
+ 0x274c, 0x1776,
+ 0x274d, 0x0286,
+ 0x274e, 0x0226,
+ 0x274f, 0x0288,
+ 0x2751, 0x028c,
+ 0x2753, 0x0227,
+ 0x2756, 0x028e,
+ 0x2759, 0x022a,
+ 0x275b, 0x1777,
+ 0x275c, 0x02d0,
+ 0x2760, 0x02d5,
+ 0x2761, 0x022c,
+ 0x2762, 0x02d6,
+ 0x2766, 0x022d,
+ 0x2767, 0x02da,
+ 0x276e, 0x178a,
+ 0x276f, 0x02e1,
+ 0x2773, 0x178c,
+ 0x2774, 0x02e5,
+ 0x2779, 0x178d,
+ 0x277a, 0x02ea,
+ 0x277e, 0x0356,
+ 0x2821, 0x0357,
+ 0x2827, 0x035e,
+ 0x2828, 0x0362,
+ 0x2829, 0x022e,
+ 0x282b, 0x0363,
+ 0x2833, 0x17b2,
+ 0x2834, 0x036b,
+ 0x2837, 0x03f6,
+ 0x283b, 0x1812,
+ 0x283c, 0x03fa,
+ 0x283f, 0x03fe,
+ 0x2844, 0x0405,
+ 0x284d, 0x1813,
+ 0x284e, 0x1818,
+ 0x284f, 0x040f,
+ 0x2853, 0x1819,
+ 0x2854, 0x0508,
+ 0x285a, 0x18e7,
+ 0x285b, 0x050e,
+ 0x2863, 0x0230,
+ 0x2864, 0x051b,
+ 0x2865, 0x0520,
+ 0x2868, 0x0696,
+ 0x286c, 0x0231,
+ 0x286d, 0x069f,
+ 0x2871, 0x0826,
+ 0x287c, 0x09f5,
+ 0x2921, 0x1e33,
+ 0x2922, 0x09f8,
+ 0x2923, 0x1e34,
+ 0x2924, 0x09f9,
+ 0x2926, 0x0be1,
+ 0x292c, 0x0dbb,
+ 0x292f, 0x2360,
+ 0x2930, 0x2612,
+ 0x2931, 0x0f7b,
+ 0x2934, 0x1100,
+ 0x2936, 0x1289,
+ 0x2937, 0x13b2,
+ 0x2939, 0x2f0d,
+ 0x4221, 0x0232,
+ 0x4421, 0x0253,
+ 0x4521, 0x02b1,
+ 0x4621, 0x030f,
+ 0x4721, 0x036d,
+ 0x4821, 0x03cb,
+ 0x4921, 0x0429,
+ 0x4a21, 0x0487,
+ 0x4b21, 0x04e5,
+ 0x4c21, 0x0543,
+ 0x4d21, 0x05a1,
+ 0x4e21, 0x05ff,
+ 0x4f21, 0x065d,
+ 0x5021, 0x06bb,
+ 0x5121, 0x0719,
+ 0x5221, 0x0777,
+ 0x5321, 0x07d5,
+ 0x5421, 0x0833,
+ 0x5521, 0x0891,
+ 0x5621, 0x08ef,
+ 0x5721, 0x094d,
+ 0x5821, 0x09ab,
+ 0x5921, 0x0a09,
+ 0x5a21, 0x0a67,
+ 0x5b21, 0x0ac5,
+ 0x5c21, 0x0b23,
+ 0x5d21, 0x0b81,
+ 0x5e21, 0x0bdf,
+ 0x5f21, 0x0c3d,
+ 0x6021, 0x0c9b,
+ 0x6121, 0x0cf9,
+ 0x6221, 0x0d57,
+ 0x6321, 0x0db5,
+ 0x6421, 0x0e13,
+ 0x6521, 0x0e71,
+ 0x6621, 0x0ecf,
+ 0x6721, 0x0f2d,
+ 0x6821, 0x0f8b,
+ 0x6921, 0x0fe9,
+ 0x6a21, 0x1047,
+ 0x6b21, 0x10a5,
+ 0x6c21, 0x1103,
+ 0x6d21, 0x1161,
+ 0x6e21, 0x11bf,
+ 0x6f21, 0x121d,
+ 0x7021, 0x127b,
+ 0x7121, 0x12d9,
+ 0x7221, 0x1337,
+ 0x7321, 0x1395,
+ 0x7421, 0x13f3,
+ 0x7521, 0x1451,
+ 0x7621, 0x14af,
+ 0x7721, 0x150d,
+ 0x7821, 0x156b,
+ 0x7921, 0x15c9,
+ 0x7a21, 0x1627,
+ 0x7b21, 0x1685,
+ 0x7c21, 0x16e3,
+ 0x7d21, 0x1741,
+ 0x212c, 0x354e,
+ 0x213b, 0x007c,
+ 0x213d, 0x007e,
+ 0x213e, 0x0082,
+ 0x2142, 0x0086,
+ 0x2146, 0x008a,
+ 0x214a, 0x008e,
+ 0x214e, 0x0092,
+ 0x2152, 0x0096,
+ 0x2156, 0x009a,
+ 0x215a, 0x009e,
+ 0x2244, 0x354f,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 cns13CNS1VEnc16 = {
+ 1,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ cns13CNS1VMap2, 170
+};
+
+static Gushort cns13CNS2HMap2[168] = {
+ 0x0000, 0x0000,
+ 0x2121, 0x176c,
+ 0x2221, 0x17ca,
+ 0x2321, 0x1828,
+ 0x2421, 0x1886,
+ 0x2521, 0x18e4,
+ 0x2621, 0x1942,
+ 0x2721, 0x19a0,
+ 0x2821, 0x19fe,
+ 0x2921, 0x1a5c,
+ 0x2a21, 0x1aba,
+ 0x2b21, 0x1b18,
+ 0x2c21, 0x1b76,
+ 0x2d21, 0x1bd4,
+ 0x2e21, 0x1c32,
+ 0x2f21, 0x1c90,
+ 0x3021, 0x1cee,
+ 0x3121, 0x1d4c,
+ 0x3221, 0x1daa,
+ 0x3321, 0x1e08,
+ 0x3421, 0x1e66,
+ 0x3521, 0x1ec4,
+ 0x3621, 0x1f22,
+ 0x3721, 0x1f80,
+ 0x3821, 0x1fde,
+ 0x3921, 0x203c,
+ 0x3a21, 0x209a,
+ 0x3b21, 0x20f8,
+ 0x3c21, 0x2156,
+ 0x3d21, 0x21b4,
+ 0x3e21, 0x2212,
+ 0x3f21, 0x2270,
+ 0x4021, 0x22ce,
+ 0x4121, 0x232c,
+ 0x4221, 0x238a,
+ 0x4321, 0x23e8,
+ 0x4421, 0x2446,
+ 0x4521, 0x24a4,
+ 0x4621, 0x2502,
+ 0x4721, 0x2560,
+ 0x4821, 0x25be,
+ 0x4921, 0x261c,
+ 0x4a21, 0x267a,
+ 0x4b21, 0x26d8,
+ 0x4c21, 0x2736,
+ 0x4d21, 0x2794,
+ 0x4e21, 0x27f2,
+ 0x4f21, 0x2850,
+ 0x5021, 0x28ae,
+ 0x5121, 0x290c,
+ 0x5221, 0x296a,
+ 0x5321, 0x29c8,
+ 0x5421, 0x2a26,
+ 0x5521, 0x2a84,
+ 0x5621, 0x2ae2,
+ 0x5721, 0x2b40,
+ 0x5821, 0x2b9e,
+ 0x5921, 0x2bfc,
+ 0x5a21, 0x2c5a,
+ 0x5b21, 0x2cb8,
+ 0x5c21, 0x2d16,
+ 0x5d21, 0x2d74,
+ 0x5e21, 0x2dd2,
+ 0x5f21, 0x2e30,
+ 0x6021, 0x2e8e,
+ 0x6121, 0x2eec,
+ 0x6221, 0x2f4a,
+ 0x6321, 0x2fa8,
+ 0x6421, 0x3006,
+ 0x6521, 0x3064,
+ 0x6621, 0x30c2,
+ 0x6721, 0x3120,
+ 0x6821, 0x317e,
+ 0x6921, 0x31dc,
+ 0x6a21, 0x323a,
+ 0x6b21, 0x3298,
+ 0x6c21, 0x32f6,
+ 0x6d21, 0x3354,
+ 0x6e21, 0x33b2,
+ 0x6f21, 0x3410,
+ 0x7021, 0x346e,
+ 0x7121, 0x34cc,
+ 0x7221, 0x352a,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 cns13CNS2HEnc16 = {
+ 0,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ cns13CNS2HMap2, 84
+};
+
+static Gushort cns13CNS2VMap2[168] = {
+ 0x0000, 0x0000,
+ 0x2121, 0x176c,
+ 0x2221, 0x17ca,
+ 0x2321, 0x1828,
+ 0x2421, 0x1886,
+ 0x2521, 0x18e4,
+ 0x2621, 0x1942,
+ 0x2721, 0x19a0,
+ 0x2821, 0x19fe,
+ 0x2921, 0x1a5c,
+ 0x2a21, 0x1aba,
+ 0x2b21, 0x1b18,
+ 0x2c21, 0x1b76,
+ 0x2d21, 0x1bd4,
+ 0x2e21, 0x1c32,
+ 0x2f21, 0x1c90,
+ 0x3021, 0x1cee,
+ 0x3121, 0x1d4c,
+ 0x3221, 0x1daa,
+ 0x3321, 0x1e08,
+ 0x3421, 0x1e66,
+ 0x3521, 0x1ec4,
+ 0x3621, 0x1f22,
+ 0x3721, 0x1f80,
+ 0x3821, 0x1fde,
+ 0x3921, 0x203c,
+ 0x3a21, 0x209a,
+ 0x3b21, 0x20f8,
+ 0x3c21, 0x2156,
+ 0x3d21, 0x21b4,
+ 0x3e21, 0x2212,
+ 0x3f21, 0x2270,
+ 0x4021, 0x22ce,
+ 0x4121, 0x232c,
+ 0x4221, 0x238a,
+ 0x4321, 0x23e8,
+ 0x4421, 0x2446,
+ 0x4521, 0x24a4,
+ 0x4621, 0x2502,
+ 0x4721, 0x2560,
+ 0x4821, 0x25be,
+ 0x4921, 0x261c,
+ 0x4a21, 0x267a,
+ 0x4b21, 0x26d8,
+ 0x4c21, 0x2736,
+ 0x4d21, 0x2794,
+ 0x4e21, 0x27f2,
+ 0x4f21, 0x2850,
+ 0x5021, 0x28ae,
+ 0x5121, 0x290c,
+ 0x5221, 0x296a,
+ 0x5321, 0x29c8,
+ 0x5421, 0x2a26,
+ 0x5521, 0x2a84,
+ 0x5621, 0x2ae2,
+ 0x5721, 0x2b40,
+ 0x5821, 0x2b9e,
+ 0x5921, 0x2bfc,
+ 0x5a21, 0x2c5a,
+ 0x5b21, 0x2cb8,
+ 0x5c21, 0x2d16,
+ 0x5d21, 0x2d74,
+ 0x5e21, 0x2dd2,
+ 0x5f21, 0x2e30,
+ 0x6021, 0x2e8e,
+ 0x6121, 0x2eec,
+ 0x6221, 0x2f4a,
+ 0x6321, 0x2fa8,
+ 0x6421, 0x3006,
+ 0x6521, 0x3064,
+ 0x6621, 0x30c2,
+ 0x6721, 0x3120,
+ 0x6821, 0x317e,
+ 0x6921, 0x31dc,
+ 0x6a21, 0x323a,
+ 0x6b21, 0x3298,
+ 0x6c21, 0x32f6,
+ 0x6d21, 0x3354,
+ 0x6e21, 0x33b2,
+ 0x6f21, 0x3410,
+ 0x7021, 0x346e,
+ 0x7121, 0x34cc,
+ 0x7221, 0x352a,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 cns13CNS2VEnc16 = {
+ 1,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ cns13CNS2VMap2, 84
+};
+
+static Gushort cns13ETHKB5HMap2[2252] = {
+ 0x0000, 0x0000,
+ 0x8840, 0x44c9,
+ 0x8856, 0x4961,
+ 0x88a1, 0x498a,
+ 0x88a9, 0x499c,
+ 0x8940, 0x4534,
+ 0x8943, 0x4536,
+ 0x8946, 0x4537,
+ 0x894c, 0x453b,
+ 0x894d, 0x43c3,
+ 0x894e, 0x453c,
+ 0x8951, 0x439a,
+ 0x8952, 0x453f,
+ 0x89a1, 0x456c,
+ 0x89a6, 0x43a2,
+ 0x89ab, 0x43ec,
+ 0x89ac, 0x4571,
+ 0x89ad, 0x43eb,
+ 0x89ae, 0x4572,
+ 0x89b0, 0x4573,
+ 0x89b5, 0x4576,
+ 0x89c1, 0x4581,
+ 0x89c5, 0x4584,
+ 0x89cf, 0x43bc,
+ 0x89d0, 0x458e,
+ 0x89d9, 0x439c,
+ 0x89da, 0x4597,
+ 0x89db, 0x439e,
+ 0x89dc, 0x4598,
+ 0x89dd, 0x439f,
+ 0x89de, 0x4599,
+ 0x89e1, 0x43a1,
+ 0x89e2, 0x459c,
+ 0x89e3, 0x43a3,
+ 0x89e4, 0x459d,
+ 0x89ea, 0x43a5,
+ 0x89ec, 0x45a3,
+ 0x89fa, 0x43a9,
+ 0x89fb, 0x45b1,
+ 0x8a40, 0x45b5,
+ 0x8a41, 0x4309,
+ 0x8a43, 0x430b,
+ 0x8a4d, 0x45b6,
+ 0x8a4e, 0x4316,
+ 0x8a5a, 0x45b7,
+ 0x8a5b, 0x4323,
+ 0x8a5e, 0x45b8,
+ 0x8a5f, 0x4327,
+ 0x8a64, 0x432c,
+ 0x8a71, 0x45b9,
+ 0x8a72, 0x433a,
+ 0x8a76, 0x433e,
+ 0x8a77, 0x45ba,
+ 0x8a78, 0x4340,
+ 0x8a7a, 0x45bb,
+ 0x8a7b, 0x4343,
+ 0x8a7c, 0x45bc,
+ 0x8a7d, 0x4345,
+ 0x8a7e, 0x45bd,
+ 0x8aa1, 0x4347,
+ 0x8aa8, 0x45be,
+ 0x8aa9, 0x434f,
+ 0x8aac, 0x4352,
+ 0x8ab2, 0x4358,
+ 0x8ab6, 0x45bf,
+ 0x8ab7, 0x435d,
+ 0x8ab8, 0x45c0,
+ 0x8ab9, 0x435f,
+ 0x8abb, 0x4361,
+ 0x8ac9, 0x436f,
+ 0x8acc, 0x45c1,
+ 0x8ace, 0x4374,
+ 0x8ad6, 0x45c2,
+ 0x8ad8, 0x437e,
+ 0x8adf, 0x4385,
+ 0x8ae6, 0x45c4,
+ 0x8ae7, 0x43db,
+ 0x8ae8, 0x45c5,
+ 0x8af6, 0x45d2,
+ 0x8b40, 0x45db,
+ 0x8b41, 0x438c,
+ 0x8b43, 0x45dc,
+ 0x8b45, 0x438e,
+ 0x8b46, 0x45de,
+ 0x8b47, 0x438f,
+ 0x8b48, 0x45df,
+ 0x8b49, 0x4390,
+ 0x8b4a, 0x45e0,
+ 0x8b4b, 0x4391,
+ 0x8b4c, 0x45e1,
+ 0x8b4d, 0x4392,
+ 0x8b51, 0x45e2,
+ 0x8b55, 0x45e5,
+ 0x8b58, 0x4397,
+ 0x8b59, 0x45e8,
+ 0x8b5a, 0x4398,
+ 0x8b5b, 0x43c4,
+ 0x8b5c, 0x45e9,
+ 0x8b61, 0x43a7,
+ 0x8b62, 0x45ee,
+ 0x8b68, 0x43ac,
+ 0x8b69, 0x45f4,
+ 0x8ba1, 0x460a,
+ 0x8bc0, 0x44df,
+ 0x8bde, 0x44fc,
+ 0x8d60, 0x4629,
+ 0x8d62, 0x43ba,
+ 0x8d63, 0x462b,
+ 0x8d68, 0x43bb,
+ 0x8d69, 0x43a0,
+ 0x8d6a, 0x43bd,
+ 0x8d6b, 0x4630,
+ 0x8d6e, 0x43be,
+ 0x8d6f, 0x4633,
+ 0x8d76, 0x43bf,
+ 0x8d77, 0x463a,
+ 0x8d7a, 0x43c0,
+ 0x8d7b, 0x463d,
+ 0x8d7c, 0x43c1,
+ 0x8d7d, 0x463e,
+ 0x8da1, 0x4640,
+ 0x8da5, 0x43c2,
+ 0x8da6, 0x4644,
+ 0x8da8, 0x43b9,
+ 0x8da9, 0x43ad,
+ 0x8daa, 0x4646,
+ 0x8db6, 0x43c7,
+ 0x8db7, 0x4652,
+ 0x8dc3, 0x43c8,
+ 0x8dc4, 0x465e,
+ 0x8dfa, 0x43f9,
+ 0x8dfb, 0x4694,
+ 0x8e40, 0x372b,
+ 0x8e45, 0x4698,
+ 0x8e46, 0x3730,
+ 0x8e6a, 0x3754,
+ 0x8e6b, 0x4699,
+ 0x8e6d, 0x3756,
+ 0x8e70, 0x3759,
+ 0x8e76, 0x469b,
+ 0x8e77, 0x375f,
+ 0x8e7b, 0x469c,
+ 0x8e7c, 0x3764,
+ 0x8ea1, 0x3766,
+ 0x8ea6, 0x469d,
+ 0x8ea7, 0x376b,
+ 0x8eac, 0x3770,
+ 0x8eb5, 0x3779,
+ 0x8eb8, 0x469e,
+ 0x8eb9, 0x377d,
+ 0x8ec9, 0x469f,
+ 0x8eca, 0x378d,
+ 0x8ece, 0x3791,
+ 0x8ed1, 0x3794,
+ 0x8ee5, 0x46a0,
+ 0x8ee6, 0x37a8,
+ 0x8eef, 0x46a1,
+ 0x8ef0, 0x37b1,
+ 0x8ef6, 0x46a2,
+ 0x8ef7, 0x37b8,
+ 0x8f40, 0x37c0,
+ 0x8f58, 0x37d8,
+ 0x8f59, 0x46a3,
+ 0x8f5a, 0x37d9,
+ 0x8f5f, 0x46a4,
+ 0x8f60, 0x37de,
+ 0x8f67, 0x46a5,
+ 0x8f68, 0x37e5,
+ 0x8f6a, 0x37e7,
+ 0x8f6f, 0x37ec,
+ 0x8f79, 0x46a6,
+ 0x8f7a, 0x37f7,
+ 0x8fa1, 0x37fc,
+ 0x8fb0, 0x46a7,
+ 0x8fb1, 0x380c,
+ 0x8fc5, 0x46a8,
+ 0x8fc6, 0x3820,
+ 0x8fc7, 0x46a9,
+ 0x8fc8, 0x3821,
+ 0x8fca, 0x46aa,
+ 0x8fcd, 0x3826,
+ 0x8fda, 0x46ab,
+ 0x8fdb, 0x3833,
+ 0x8fe3, 0x46ac,
+ 0x8fe4, 0x383c,
+ 0x8ffc, 0x46ad,
+ 0x8ffd, 0x3854,
+ 0x9040, 0x3856,
+ 0x9055, 0x46ae,
+ 0x9056, 0x386c,
+ 0x905c, 0x46af,
+ 0x905f, 0x3873,
+ 0x906e, 0x3882,
+ 0x906f, 0x46b2,
+ 0x9070, 0x3883,
+ 0x907b, 0x388d,
+ 0x90a1, 0x3891,
+ 0x90a6, 0x46b3,
+ 0x90a7, 0x3896,
+ 0x90b8, 0x46b4,
+ 0x90b9, 0x38a7,
+ 0x90dd, 0x38cb,
+ 0x90f2, 0x38e0,
+ 0x9140, 0x38ed,
+ 0x9165, 0x46b5,
+ 0x9166, 0x3912,
+ 0x916e, 0x46b6,
+ 0x916f, 0x391a,
+ 0x917e, 0x46b7,
+ 0x91a1, 0x3929,
+ 0x91a2, 0x46b8,
+ 0x91a3, 0x392a,
+ 0x91c0, 0x3947,
+ 0x91c8, 0x46b9,
+ 0x91c9, 0x3950,
+ 0x9240, 0x3986,
+ 0x9245, 0x398b,
+ 0x9264, 0x46ba,
+ 0x9265, 0x39ab,
+ 0x926d, 0x46bb,
+ 0x926e, 0x39b4,
+ 0x92a1, 0x39c5,
+ 0x92b3, 0x39d3,
+ 0x92c9, 0x39e9,
+ 0x92d2, 0x39f2,
+ 0x92e5, 0x46bc,
+ 0x92e6, 0x3a05,
+ 0x92f2, 0x46bd,
+ 0x92f3, 0x3a11,
+ 0x9340, 0x3a1d,
+ 0x9368, 0x46be,
+ 0x9369, 0x3a45,
+ 0x93a1, 0x3a5b,
+ 0x93aa, 0x46bf,
+ 0x93ab, 0x3a64,
+ 0x93c2, 0x46c0,
+ 0x93c3, 0x3a7b,
+ 0x93e5, 0x46c1,
+ 0x93e6, 0x3a9d,
+ 0x93e8, 0x46c2,
+ 0x93e9, 0x3aa0,
+ 0x93eb, 0x46c3,
+ 0x93ec, 0x3aa2,
+ 0x9440, 0x3ab5,
+ 0x9446, 0x46c4,
+ 0x9448, 0x3abc,
+ 0x9479, 0x46c5,
+ 0x947a, 0x3aee,
+ 0x94a1, 0x3af3,
+ 0x94cb, 0x46c6,
+ 0x94cc, 0x3b1e,
+ 0x9540, 0x3b51,
+ 0x954d, 0x46c7,
+ 0x954e, 0x3b5e,
+ 0x955a, 0x46c8,
+ 0x955b, 0x3b6a,
+ 0x955f, 0x46c9,
+ 0x9560, 0x3b6f,
+ 0x95a1, 0x3b8e,
+ 0x95c6, 0x46ca,
+ 0x95c7, 0x3bb3,
+ 0x95da, 0x3bc6,
+ 0x9640, 0x3beb,
+ 0x9645, 0x3bf0,
+ 0x9651, 0x46cb,
+ 0x9652, 0x3bfd,
+ 0x966a, 0x46cc,
+ 0x966b, 0x3c16,
+ 0x96a1, 0x3c2a,
+ 0x96d4, 0x46cd,
+ 0x96d5, 0x3c5d,
+ 0x96ee, 0x3c76,
+ 0x96fd, 0x3c85,
+ 0x9740, 0x3c87,
+ 0x97a1, 0x3cc6,
+ 0x9840, 0x3d24,
+ 0x9844, 0x46ce,
+ 0x9846, 0x3d2a,
+ 0x986f, 0x46d0,
+ 0x9870, 0x3d54,
+ 0x9875, 0x46d1,
+ 0x9877, 0x3d59,
+ 0x9878, 0x46d3,
+ 0x987a, 0x3d5a,
+ 0x987b, 0x46d5,
+ 0x98a1, 0x46d9,
+ 0x98a3, 0x3d5b,
+ 0x98a4, 0x46db,
+ 0x98af, 0x3d5c,
+ 0x98b0, 0x46e6,
+ 0x98b4, 0x43ca,
+ 0x98b5, 0x46ea,
+ 0x98b6, 0x3d5d,
+ 0x98b7, 0x46eb,
+ 0x98b8, 0x43cc,
+ 0x98b9, 0x3d5e,
+ 0x98ba, 0x46ec,
+ 0x98bb, 0x43fa,
+ 0x98bc, 0x46ed,
+ 0x98bd, 0x3d5f,
+ 0x98bf, 0x46ee,
+ 0x98c2, 0x3d61,
+ 0x98c3, 0x46f1,
+ 0x98c4, 0x3d62,
+ 0x98c5, 0x46f2,
+ 0x98c6, 0x3d63,
+ 0x98c8, 0x46f3,
+ 0x98d2, 0x43cd,
+ 0x98d3, 0x46fd,
+ 0x98d8, 0x43ce,
+ 0x98da, 0x4702,
+ 0x98db, 0x43d1,
+ 0x98dc, 0x4703,
+ 0x98df, 0x43d4,
+ 0x98e0, 0x4706,
+ 0x98e3, 0x3d65,
+ 0x98e4, 0x4709,
+ 0x98e7, 0x3d66,
+ 0x98e8, 0x470c,
+ 0x98ed, 0x3d67,
+ 0x98ee, 0x4711,
+ 0x98f0, 0x3d68,
+ 0x98f1, 0x4713,
+ 0x98f2, 0x3d69,
+ 0x98f3, 0x4714,
+ 0x98f4, 0x43d5,
+ 0x98f6, 0x4715,
+ 0x98fc, 0x3d6a,
+ 0x98fd, 0x471b,
+ 0x98fe, 0x43d7,
+ 0x9940, 0x471c,
+ 0x9942, 0x43fc,
+ 0x9943, 0x3d6b,
+ 0x9944, 0x471e,
+ 0x9945, 0x3d6c,
+ 0x9946, 0x471f,
+ 0x9947, 0x43d8,
+ 0x9948, 0x4720,
+ 0x994f, 0x3d6d,
+ 0x9950, 0x4727,
+ 0x9954, 0x43d9,
+ 0x9955, 0x472b,
+ 0x995c, 0x43da,
+ 0x995d, 0x4732,
+ 0x9964, 0x43dc,
+ 0x9965, 0x4739,
+ 0x996a, 0x3d6e,
+ 0x996b, 0x473e,
+ 0x996e, 0x3d6f,
+ 0x996f, 0x4741,
+ 0x9975, 0x3d70,
+ 0x9976, 0x4747,
+ 0x9978, 0x3d71,
+ 0x9979, 0x4749,
+ 0x99a1, 0x474f,
+ 0x99a2, 0x3d72,
+ 0x99a3, 0x4750,
+ 0x99a4, 0x43c5,
+ 0x99a5, 0x4751,
+ 0x99a6, 0x43c6,
+ 0x99a7, 0x4752,
+ 0x99ae, 0x3d73,
+ 0x99af, 0x4759,
+ 0x99b2, 0x43de,
+ 0x99b3, 0x475c,
+ 0x99b6, 0x3d74,
+ 0x99b7, 0x475f,
+ 0x99ba, 0x3d75,
+ 0x99bb, 0x4762,
+ 0x99ca, 0x43e0,
+ 0x99cb, 0x4771,
+ 0x99cd, 0x43e2,
+ 0x99ce, 0x4773,
+ 0x99d3, 0x43e3,
+ 0x99d4, 0x4778,
+ 0x99d6, 0x43e5,
+ 0x99d7, 0x477a,
+ 0x99df, 0x43df,
+ 0x99e0, 0x4782,
+ 0x99e2, 0x3d76,
+ 0x99e3, 0x4784,
+ 0x99e4, 0x43ab,
+ 0x99e5, 0x4785,
+ 0x99e6, 0x43e7,
+ 0x99e7, 0x4786,
+ 0x99e8, 0x43e9,
+ 0x99e9, 0x4787,
+ 0x99ef, 0x43fd,
+ 0x99f0, 0x478d,
+ 0x99f4, 0x3d77,
+ 0x99f5, 0x4791,
+ 0x9a40, 0x479b,
+ 0x9a4a, 0x3d78,
+ 0x9a4b, 0x47a5,
+ 0x9a4c, 0x3d79,
+ 0x9a4d, 0x47a6,
+ 0x9a59, 0x3d7a,
+ 0x9a5a, 0x47b2,
+ 0x9a5f, 0x43af,
+ 0x9a60, 0x47b7,
+ 0x9a61, 0x3d7b,
+ 0x9a62, 0x47b8,
+ 0x9a66, 0x43ed,
+ 0x9a67, 0x47bc,
+ 0x9a68, 0x3d7c,
+ 0x9a69, 0x43ee,
+ 0x9a6a, 0x47bd,
+ 0x9a6b, 0x43ff,
+ 0x9a6c, 0x47be,
+ 0x9a73, 0x3d7d,
+ 0x9a74, 0x47c5,
+ 0x9a75, 0x43f1,
+ 0x9a76, 0x47c6,
+ 0x9a7e, 0x3d7e,
+ 0x9aa1, 0x47ce,
+ 0x9aa3, 0x43f3,
+ 0x9aa4, 0x47d0,
+ 0x9aa5, 0x43f2,
+ 0x9aa6, 0x47d1,
+ 0x9aa9, 0x43f8,
+ 0x9aaa, 0x43f4,
+ 0x9aab, 0x47d4,
+ 0x9ab2, 0x3d7f,
+ 0x9ab3, 0x47db,
+ 0x9ab7, 0x3d80,
+ 0x9ab8, 0x47df,
+ 0x9ab9, 0x3d81,
+ 0x9aba, 0x47e0,
+ 0x9abb, 0x3d82,
+ 0x9abc, 0x47e1,
+ 0x9abd, 0x43b7,
+ 0x9abe, 0x47e2,
+ 0x9ac7, 0x3d83,
+ 0x9ac8, 0x47eb,
+ 0x9ad0, 0x3d84,
+ 0x9ad1, 0x47f3,
+ 0x9ad2, 0x3d85,
+ 0x9ad3, 0x47f4,
+ 0x9ad9, 0x3d86,
+ 0x9adc, 0x47fa,
+ 0x9ae2, 0x3d89,
+ 0x9ae3, 0x4800,
+ 0x9ae4, 0x3d8a,
+ 0x9ae5, 0x4801,
+ 0x9ae8, 0x3d8b,
+ 0x9ae9, 0x43b0,
+ 0x9aea, 0x4804,
+ 0x9aee, 0x43b2,
+ 0x9aef, 0x4808,
+ 0x9af2, 0x3d8c,
+ 0x9af3, 0x480b,
+ 0x9af6, 0x3d8d,
+ 0x9af7, 0x480e,
+ 0x9afb, 0x3d8e,
+ 0x9afc, 0x4812,
+ 0x9b40, 0x4815,
+ 0x9b46, 0x3d8f,
+ 0x9b47, 0x481b,
+ 0x9b4a, 0x3d90,
+ 0x9b4b, 0x481e,
+ 0x9b54, 0x3d92,
+ 0x9b55, 0x4827,
+ 0x9b58, 0x3d93,
+ 0x9b59, 0x482a,
+ 0x9b5a, 0x3d94,
+ 0x9b5b, 0x482b,
+ 0x9b5c, 0x3d95,
+ 0x9b5d, 0x482c,
+ 0x9b5e, 0x3d96,
+ 0x9b60, 0x482d,
+ 0x9b62, 0x482e,
+ 0x9b70, 0x3d98,
+ 0x9b74, 0x483c,
+ 0x9b77, 0x3d9d,
+ 0x9b79, 0x483e,
+ 0x9b7c, 0x3da0,
+ 0x9b7d, 0x4840,
+ 0x9b7e, 0x3da1,
+ 0x9ba1, 0x3da2,
+ 0x9ba2, 0x4841,
+ 0x9ba3, 0x3da3,
+ 0x9ba5, 0x4842,
+ 0x9ba7, 0x3da5,
+ 0x9bab, 0x4844,
+ 0x9bac, 0x3da9,
+ 0x9bad, 0x4845,
+ 0x9baf, 0x3daa,
+ 0x9bb0, 0x4847,
+ 0x9bb2, 0x3dab,
+ 0x9bba, 0x4849,
+ 0x9bbe, 0x3db3,
+ 0x9bbf, 0x484d,
+ 0x9bc0, 0x3db4,
+ 0x9bc7, 0x484e,
+ 0x9bca, 0x3dbb,
+ 0x9bcb, 0x4851,
+ 0x9bcc, 0x3dbc,
+ 0x9bcd, 0x4852,
+ 0x9bce, 0x43d0,
+ 0x9bcf, 0x4853,
+ 0x9bd0, 0x3dbd,
+ 0x9bd2, 0x4854,
+ 0x9bd3, 0x3dbf,
+ 0x9bd4, 0x4855,
+ 0x9bd5, 0x3dc0,
+ 0x9bd6, 0x4856,
+ 0x9bd8, 0x3dc1,
+ 0x9bdb, 0x4858,
+ 0x9bdd, 0x3dc4,
+ 0x9bdf, 0x3dc5,
+ 0x9be0, 0x485a,
+ 0x9be1, 0x3dc6,
+ 0x9be2, 0x485b,
+ 0x9be3, 0x3dc7,
+ 0x9be4, 0x485c,
+ 0x9be7, 0x3dc8,
+ 0x9be8, 0x485f,
+ 0x9be9, 0x3dc9,
+ 0x9bed, 0x4860,
+ 0x9bee, 0x3dcd,
+ 0x9bf0, 0x4861,
+ 0x9bf3, 0x3dcf,
+ 0x9bf4, 0x4864,
+ 0x9bf7, 0x4866,
+ 0x9bf8, 0x3dd1,
+ 0x9bfa, 0x4867,
+ 0x9bfb, 0x3dd3,
+ 0x9bfd, 0x4868,
+ 0x9c40, 0x3dd5,
+ 0x9c43, 0x486a,
+ 0x9c44, 0x3dd8,
+ 0x9c47, 0x486b,
+ 0x9c48, 0x3ddb,
+ 0x9c49, 0x486c,
+ 0x9c4a, 0x3ddc,
+ 0x9c4b, 0x486d,
+ 0x9c4d, 0x3ddd,
+ 0x9c54, 0x486f,
+ 0x9c55, 0x3de4,
+ 0x9c56, 0x4870,
+ 0x9c57, 0x3de5,
+ 0x9c5c, 0x4871,
+ 0x9c5d, 0x3dea,
+ 0x9c5e, 0x4872,
+ 0x9c60, 0x3deb,
+ 0x9c61, 0x4874,
+ 0x9c63, 0x4875,
+ 0x9c64, 0x3ded,
+ 0x9c67, 0x4876,
+ 0x9c69, 0x4877,
+ 0x9c6a, 0x3df1,
+ 0x9c6c, 0x4878,
+ 0x9c6d, 0x3df2,
+ 0x9c6e, 0x4879,
+ 0x9c6f, 0x3df3,
+ 0x9c73, 0x487a,
+ 0x9c75, 0x3df7,
+ 0x9c78, 0x487c,
+ 0x9c79, 0x3dfa,
+ 0x9c7a, 0x487d,
+ 0x9c7b, 0x3dfb,
+ 0x9c7d, 0x487e,
+ 0x9c7e, 0x3dfd,
+ 0x9ca1, 0x3dfe,
+ 0x9ca3, 0x487f,
+ 0x9ca5, 0x3e00,
+ 0x9ca6, 0x4881,
+ 0x9ca8, 0x3e01,
+ 0x9caa, 0x4883,
+ 0x9cab, 0x3e03,
+ 0x9cac, 0x4884,
+ 0x9cad, 0x3e04,
+ 0x9caf, 0x4885,
+ 0x9cb1, 0x3e06,
+ 0x9cbb, 0x4887,
+ 0x9cbe, 0x3e12,
+ 0x9cc3, 0x4888,
+ 0x9cc6, 0x3e17,
+ 0x9cce, 0x488b,
+ 0x9ccf, 0x3e1f,
+ 0x9cd1, 0x3e21,
+ 0x9cd4, 0x488c,
+ 0x9cd8, 0x3e24,
+ 0x9cdb, 0x4890,
+ 0x9cdc, 0x3e27,
+ 0x9ce6, 0x4891,
+ 0x9ce7, 0x3e31,
+ 0x9cea, 0x4892,
+ 0x9ceb, 0x3e34,
+ 0x9ced, 0x4893,
+ 0x9cee, 0x3e36,
+ 0x9cfa, 0x4894,
+ 0x9cfd, 0x3e42,
+ 0x9cfe, 0x4897,
+ 0x9d40, 0x43e8,
+ 0x9d41, 0x4898,
+ 0x9d46, 0x3e43,
+ 0x9d47, 0x489d,
+ 0x9d49, 0x3e44,
+ 0x9d4a, 0x489f,
+ 0x9d4c, 0x3e46,
+ 0x9d4e, 0x48a1,
+ 0x9d4f, 0x3e48,
+ 0x9d50, 0x48a2,
+ 0x9d51, 0x3e49,
+ 0x9d52, 0x48a3,
+ 0x9d55, 0x3e4a,
+ 0x9d56, 0x48a6,
+ 0x9d58, 0x48a7,
+ 0x9d5b, 0x48a9,
+ 0x9d61, 0x43c9,
+ 0x9d62, 0x3e4c,
+ 0x9d63, 0x48af,
+ 0x9d64, 0x3e4d,
+ 0x9d65, 0x48b0,
+ 0x9d78, 0x43f5,
+ 0x9d79, 0x3e4e,
+ 0x9d7a, 0x48c3,
+ 0x9d7e, 0x3e4f,
+ 0x9da1, 0x48c7,
+ 0x9da5, 0x3e50,
+ 0x9da9, 0x48cb,
+ 0x9daa, 0x3e54,
+ 0x9dab, 0x48cc,
+ 0x9dac, 0x3e55,
+ 0x9dae, 0x48cd,
+ 0x9db0, 0x3e58,
+ 0x9db1, 0x48cf,
+ 0x9db3, 0x3e59,
+ 0x9db4, 0x48d1,
+ 0x9db5, 0x3e5a,
+ 0x9db6, 0x48d2,
+ 0x9db7, 0x3e5b,
+ 0x9db8, 0x48d3,
+ 0x9dbc, 0x3e5c,
+ 0x9dbe, 0x48d7,
+ 0x9dbf, 0x3e5e,
+ 0x9dc1, 0x48d8,
+ 0x9dc3, 0x3e60,
+ 0x9dc5, 0x48da,
+ 0x9dc7, 0x3e62,
+ 0x9dc9, 0x48dc,
+ 0x9dca, 0x3e64,
+ 0x9dcb, 0x48dd,
+ 0x9dcd, 0x3e65,
+ 0x9dd2, 0x48df,
+ 0x9dd3, 0x3e6a,
+ 0x9dd6, 0x48e0,
+ 0x9dda, 0x3e6d,
+ 0x9dfc, 0x48e4,
+ 0x9dfd, 0x3e8f,
+ 0x9e40, 0x3e91,
+ 0x9e43, 0x48e5,
+ 0x9e44, 0x3e95,
+ 0x9e5f, 0x48e6,
+ 0x9e60, 0x3eb1,
+ 0x9e63, 0x48e7,
+ 0x9e64, 0x3eb4,
+ 0x9e66, 0x48e8,
+ 0x9e68, 0x3eb6,
+ 0x9e69, 0x48ea,
+ 0x9e6a, 0x3eb7,
+ 0x9e6b, 0x48eb,
+ 0x9e71, 0x3eb8,
+ 0x9e72, 0x48f1,
+ 0x9e73, 0x3eb9,
+ 0x9e74, 0x48f2,
+ 0x9e77, 0x3eba,
+ 0x9e79, 0x48f5,
+ 0x9e7a, 0x3ebc,
+ 0x9e7b, 0x48f6,
+ 0x9e7c, 0x3ebd,
+ 0x9e7d, 0x48f7,
+ 0x9e7e, 0x3ebe,
+ 0x9ea1, 0x3ebf,
+ 0x9ea3, 0x48f8,
+ 0x9ea4, 0x3ec1,
+ 0x9ea7, 0x48f9,
+ 0x9eaa, 0x3ec5,
+ 0x9eab, 0x48fb,
+ 0x9ead, 0x3ec7,
+ 0x9eae, 0x48fc,
+ 0x9eaf, 0x3ec8,
+ 0x9eb2, 0x48fd,
+ 0x9eb4, 0x3ecb,
+ 0x9eb5, 0x48ff,
+ 0x9eb6, 0x3ecc,
+ 0x9eb8, 0x4900,
+ 0x9eb9, 0x3ece,
+ 0x9eba, 0x4901,
+ 0x9ebc, 0x3ecf,
+ 0x9ebd, 0x4903,
+ 0x9ebf, 0x3ed0,
+ 0x9ec1, 0x4905,
+ 0x9ec5, 0x3ed3,
+ 0x9ec6, 0x4908,
+ 0x9ec7, 0x3ed4,
+ 0x9ecb, 0x4909,
+ 0x9ecd, 0x3ed9,
+ 0x9ece, 0x490b,
+ 0x9ed0, 0x3eda,
+ 0x9ed2, 0x490d,
+ 0x9ed3, 0x3edc,
+ 0x9ed4, 0x490e,
+ 0x9ed6, 0x3edd,
+ 0x9ed8, 0x4910,
+ 0x9eda, 0x3edf,
+ 0x9ef0, 0x3ef5,
+ 0x9ef2, 0x4912,
+ 0x9ef3, 0x3ef7,
+ 0x9ef5, 0x3ef9,
+ 0x9ef6, 0x4913,
+ 0x9ef9, 0x3efa,
+ 0x9efb, 0x4916,
+ 0x9efc, 0x3efc,
+ 0x9efe, 0x3efe,
+ 0x9f40, 0x3eff,
+ 0x9f43, 0x4917,
+ 0x9f44, 0x3f02,
+ 0x9f48, 0x4918,
+ 0x9f49, 0x3f06,
+ 0x9f4b, 0x4919,
+ 0x9f4d, 0x3f08,
+ 0x9f4f, 0x3f0a,
+ 0x9f61, 0x3f1c,
+ 0x9f67, 0x491b,
+ 0x9f69, 0x3f23,
+ 0x9f70, 0x491d,
+ 0x9f71, 0x3f2a,
+ 0x9fa1, 0x3f38,
+ 0x9fae, 0x3f45,
+ 0x9fb2, 0x3f49,
+ 0x9fb5, 0x491e,
+ 0x9fb6, 0x3f4c,
+ 0x9fbb, 0x491f,
+ 0x9fbc, 0x3f51,
+ 0x9fbf, 0x4920,
+ 0x9fc1, 0x4921,
+ 0x9fc2, 0x3f55,
+ 0x9fc9, 0x3f5c,
+ 0x9fcc, 0x4922,
+ 0x9fcd, 0x3f60,
+ 0x9fd4, 0x4923,
+ 0x9fd5, 0x3f68,
+ 0x9fd9, 0x3f6c,
+ 0x9fdb, 0x3f6e,
+ 0x9fe4, 0x4924,
+ 0x9fe5, 0x3f77,
+ 0x9fe7, 0x3f79,
+ 0x9feb, 0x3f7d,
+ 0x9ff0, 0x3f82,
+ 0x9ff9, 0x4925,
+ 0x9ffa, 0x3f8b,
+ 0xa040, 0x4926,
+ 0xa041, 0x3f90,
+ 0xa047, 0x4927,
+ 0xa048, 0x3f96,
+ 0xa055, 0x4928,
+ 0xa056, 0x3fa3,
+ 0xa058, 0x3fa5,
+ 0xa05b, 0x3fa8,
+ 0xa064, 0x3fb1,
+ 0xa06d, 0x4929,
+ 0xa06e, 0x3fba,
+ 0xa073, 0x3fbf,
+ 0xa078, 0x3fc4,
+ 0xa07b, 0x492a,
+ 0xa07c, 0x3fc7,
+ 0xa0a1, 0x3fca,
+ 0xa0a2, 0x492b,
+ 0xa0a3, 0x3fcb,
+ 0xa0a6, 0x3fce,
+ 0xa0a7, 0x492c,
+ 0xa0a8, 0x3fcf,
+ 0xa0ae, 0x3fd5,
+ 0xa0b0, 0x3fd7,
+ 0xa0c5, 0x492d,
+ 0xa0c6, 0x3fec,
+ 0xa0d0, 0x492e,
+ 0xa0d1, 0x3ff6,
+ 0xa0d4, 0x3ff9,
+ 0xa0d6, 0x3ffb,
+ 0xa0e0, 0x4005,
+ 0xa0e2, 0x4007,
+ 0xa0e3, 0x492f,
+ 0xa0e5, 0x4009,
+ 0xa0e7, 0x4930,
+ 0xa0ee, 0x43b4,
+ 0xa0ef, 0x4937,
+ 0xa0f2, 0x43b8,
+ 0xa0f3, 0x493a,
+ 0xa140, 0x0063,
+ 0xa159, 0x35af,
+ 0xa15d, 0x0080,
+ 0xa1a1, 0x00a2,
+ 0xa1f6, 0x00f8,
+ 0xa1f7, 0x00f7,
+ 0xa1f8, 0x00f9,
+ 0xa240, 0x0100,
+ 0xa2a1, 0x013f,
+ 0xa340, 0x019d,
+ 0xa3a1, 0x01dc,
+ 0xa3bd, 0x01f7,
+ 0xa440, 0x0253,
+ 0xa4a1, 0x0292,
+ 0xa540, 0x02f0,
+ 0xa5a1, 0x032f,
+ 0xa640, 0x038d,
+ 0xa6a1, 0x03cc,
+ 0xa740, 0x042a,
+ 0xa7a1, 0x0469,
+ 0xa840, 0x04c7,
+ 0xa8a1, 0x0506,
+ 0xa940, 0x0564,
+ 0xa9a1, 0x05a3,
+ 0xaa40, 0x0601,
+ 0xaaa1, 0x0640,
+ 0xab40, 0x069e,
+ 0xaba1, 0x06dd,
+ 0xac40, 0x073b,
+ 0xaca1, 0x077a,
+ 0xacfe, 0x097f,
+ 0xad40, 0x07d7,
+ 0xada1, 0x0816,
+ 0xae40, 0x0874,
+ 0xaea1, 0x08b3,
+ 0xaf40, 0x0911,
+ 0xafa1, 0x0950,
+ 0xafd0, 0x0980,
+ 0xb040, 0x09af,
+ 0xb0a1, 0x09ee,
+ 0xb140, 0x0a4c,
+ 0xb1a1, 0x0a8b,
+ 0xb240, 0x0ae9,
+ 0xb2a1, 0x0b28,
+ 0xb340, 0x0b86,
+ 0xb3a1, 0x0bc5,
+ 0xb440, 0x0c23,
+ 0xb4a1, 0x0c62,
+ 0xb540, 0x0cc0,
+ 0xb5a1, 0x0cff,
+ 0xb640, 0x0d5d,
+ 0xb6a1, 0x0d9c,
+ 0xb740, 0x0dfa,
+ 0xb7a1, 0x0e39,
+ 0xb840, 0x0e97,
+ 0xb8a1, 0x0ed6,
+ 0xb940, 0x0f34,
+ 0xb9a1, 0x0f73,
+ 0xba40, 0x0fd1,
+ 0xbaa1, 0x1010,
+ 0xbb40, 0x106e,
+ 0xbba1, 0x10ad,
+ 0xbbc8, 0x10d5,
+ 0xbc40, 0x110c,
+ 0xbca1, 0x114b,
+ 0xbd40, 0x11a9,
+ 0xbda1, 0x11e8,
+ 0xbe40, 0x1246,
+ 0xbe52, 0x10d4,
+ 0xbe53, 0x1258,
+ 0xbea1, 0x1284,
+ 0xbf40, 0x12e2,
+ 0xbfa1, 0x1321,
+ 0xc040, 0x137f,
+ 0xc0a1, 0x13be,
+ 0xc140, 0x141c,
+ 0xc1a1, 0x145b,
+ 0xc1ab, 0x1466,
+ 0xc240, 0x14ba,
+ 0xc2a1, 0x14f9,
+ 0xc2cb, 0x1465,
+ 0xc2cc, 0x1523,
+ 0xc340, 0x1556,
+ 0xc361, 0x1578,
+ 0xc3a1, 0x1596,
+ 0xc3b9, 0x15af,
+ 0xc3ba, 0x15ae,
+ 0xc3bb, 0x15b0,
+ 0xc440, 0x15f4,
+ 0xc456, 0x1577,
+ 0xc457, 0x160a,
+ 0xc4a1, 0x1632,
+ 0xc540, 0x1690,
+ 0xc5a1, 0x16cf,
+ 0xc640, 0x172d,
+ 0xc6a1, 0x01fa,
+ 0xc6bf, 0x0219,
+ 0xc6d8, 0x35b3,
+ 0xc6df, 0x1794,
+ 0xc6e0, 0x35ba,
+ 0xc740, 0x35d9,
+ 0xc7a1, 0x3618,
+ 0xc840, 0x3676,
+ 0xc8a1, 0x36b5,
+ 0xc8d4, 0x44c6,
+ 0xc8d7, 0x451c,
+ 0xc8e0, 0x02dc,
+ 0xc8e1, 0x4525,
+ 0xc8e9, 0x0509,
+ 0xc8ea, 0x452d,
+ 0xc8f1, 0x09f6,
+ 0xc8f5, 0x4992,
+ 0xc940, 0x176c,
+ 0xc94a, 0x0274,
+ 0xc94b, 0x1776,
+ 0xc96c, 0x1798,
+ 0xc9a1, 0x17ab,
+ 0xc9be, 0x1797,
+ 0xc9bf, 0x17c8,
+ 0xc9ed, 0x17f7,
+ 0xca40, 0x1809,
+ 0xcaa1, 0x1848,
+ 0xcaf7, 0x17f6,
+ 0xcaf8, 0x189e,
+ 0xcb40, 0x18a5,
+ 0xcba1, 0x18e4,
+ 0xcc40, 0x1942,
+ 0xcca1, 0x1981,
+ 0xcd40, 0x19df,
+ 0xcda1, 0x1a1e,
+ 0xce40, 0x1a7c,
+ 0xcea1, 0x1abb,
+ 0xcf40, 0x1b19,
+ 0xcfa1, 0x1b58,
+ 0xd040, 0x1bb6,
+ 0xd0a1, 0x1bf5,
+ 0xd140, 0x1c53,
+ 0xd1a1, 0x1c92,
+ 0xd240, 0x1cf0,
+ 0xd2a1, 0x1d2f,
+ 0xd340, 0x1d8d,
+ 0xd3a1, 0x1dcc,
+ 0xd440, 0x1e2a,
+ 0xd4a1, 0x1e69,
+ 0xd540, 0x1ec7,
+ 0xd5a1, 0x1f06,
+ 0xd640, 0x1f64,
+ 0xd6a1, 0x1fa3,
+ 0xd6cc, 0x2254,
+ 0xd6cd, 0x1fcf,
+ 0xd740, 0x2001,
+ 0xd77a, 0x22b9,
+ 0xd77b, 0x203b,
+ 0xd7a1, 0x203f,
+ 0xd840, 0x209d,
+ 0xd8a1, 0x20dc,
+ 0xd940, 0x213a,
+ 0xd9a1, 0x2179,
+ 0xda40, 0x21d7,
+ 0xdaa1, 0x2216,
+ 0xdadf, 0x1fce,
+ 0xdae0, 0x2255,
+ 0xdb40, 0x2274,
+ 0xdba1, 0x22b3,
+ 0xdba7, 0x22ba,
+ 0xdc40, 0x2312,
+ 0xdca1, 0x2351,
+ 0xdd40, 0x23af,
+ 0xdda1, 0x23ee,
+ 0xddfc, 0x2381,
+ 0xddfd, 0x2449,
+ 0xde40, 0x244b,
+ 0xdea1, 0x248a,
+ 0xdf40, 0x24e8,
+ 0xdfa1, 0x2527,
+ 0xe040, 0x2585,
+ 0xe0a1, 0x25c4,
+ 0xe140, 0x2622,
+ 0xe1a1, 0x2661,
+ 0xe240, 0x26bf,
+ 0xe2a1, 0x26fe,
+ 0xe340, 0x275c,
+ 0xe3a1, 0x279b,
+ 0xe440, 0x27f9,
+ 0xe4a1, 0x2838,
+ 0xe540, 0x2896,
+ 0xe5a1, 0x28d5,
+ 0xe640, 0x2933,
+ 0xe6a1, 0x2972,
+ 0xe740, 0x29d0,
+ 0xe7a1, 0x2a0f,
+ 0xe840, 0x2a6d,
+ 0xe8a1, 0x2aac,
+ 0xe8a3, 0x2aaf,
+ 0xe940, 0x2b0b,
+ 0xe976, 0x2b42,
+ 0xe9a1, 0x2b4b,
+ 0xea40, 0x2ba9,
+ 0xeaa1, 0x2be8,
+ 0xeb40, 0x2c46,
+ 0xeb5b, 0x2c62,
+ 0xeba1, 0x2c86,
+ 0xebf1, 0x2aae,
+ 0xebf2, 0x2cd6,
+ 0xec40, 0x2ce3,
+ 0xeca1, 0x2d22,
+ 0xecde, 0x2b41,
+ 0xecdf, 0x2d5f,
+ 0xed40, 0x2d7f,
+ 0xeda1, 0x2dbe,
+ 0xedaa, 0x2dc8,
+ 0xee40, 0x2e1d,
+ 0xeea1, 0x2e5c,
+ 0xeeeb, 0x3014,
+ 0xeeec, 0x2ea6,
+ 0xef40, 0x2eb9,
+ 0xefa1, 0x2ef8,
+ 0xf040, 0x2f56,
+ 0xf056, 0x2dc7,
+ 0xf057, 0x2f6c,
+ 0xf0a1, 0x2f94,
+ 0xf0cb, 0x2c61,
+ 0xf0cc, 0x2fbe,
+ 0xf140, 0x2ff1,
+ 0xf163, 0x3015,
+ 0xf16b, 0x3160,
+ 0xf16c, 0x301d,
+ 0xf1a1, 0x3030,
+ 0xf240, 0x308e,
+ 0xf268, 0x31ef,
+ 0xf269, 0x30b6,
+ 0xf2a1, 0x30cc,
+ 0xf2c3, 0x30ef,
+ 0xf340, 0x312b,
+ 0xf375, 0x3161,
+ 0xf3a1, 0x316b,
+ 0xf440, 0x31c9,
+ 0xf466, 0x31f0,
+ 0xf4a1, 0x3209,
+ 0xf4b5, 0x30ee,
+ 0xf4b6, 0x321d,
+ 0xf4fd, 0x3265,
+ 0xf540, 0x3267,
+ 0xf5a1, 0x32a6,
+ 0xf640, 0x3304,
+ 0xf663, 0x3264,
+ 0xf664, 0x3327,
+ 0xf6a1, 0x3342,
+ 0xf740, 0x33a0,
+ 0xf7a1, 0x33df,
+ 0xf840, 0x343d,
+ 0xf8a1, 0x347c,
+ 0xf940, 0x34da,
+ 0xf977, 0x3512,
+ 0xf9a1, 0x351a,
+ 0xf9c4, 0x3511,
+ 0xf9c5, 0x353d,
+ 0xf9c6, 0x3549,
+ 0xf9c7, 0x353e,
+ 0xf9d2, 0x354a,
+ 0xf9d6, 0x36e8,
+ 0xfa40, 0x400b,
+ 0xfa60, 0x402b,
+ 0xfa67, 0x4032,
+ 0xfaa1, 0x404a,
+ 0xfaa9, 0x4946,
+ 0xfaab, 0x4054,
+ 0xfabe, 0x4067,
+ 0xfac6, 0x406f,
+ 0xfad6, 0x407f,
+ 0xfb40, 0x40a8,
+ 0xfb49, 0x40b1,
+ 0xfb53, 0x4948,
+ 0xfb54, 0x40bc,
+ 0xfb6e, 0x4949,
+ 0xfb6f, 0x40d7,
+ 0xfba1, 0x40e7,
+ 0xfba3, 0x494a,
+ 0xfba4, 0x40ea,
+ 0xfbb9, 0x40ff,
+ 0xfbbf, 0x494b,
+ 0xfbc0, 0x4105,
+ 0xfbcd, 0x494c,
+ 0xfbce, 0x4112,
+ 0xfbf4, 0x4138,
+ 0xfbfa, 0x413e,
+ 0xfc40, 0x4143,
+ 0xfc4a, 0x494d,
+ 0xfc4b, 0x414d,
+ 0xfc50, 0x4151,
+ 0xfc52, 0x494e,
+ 0xfc53, 0x4153,
+ 0xfc63, 0x494f,
+ 0xfc64, 0x4163,
+ 0xfc6d, 0x4950,
+ 0xfc6e, 0x416d,
+ 0xfc75, 0x4951,
+ 0xfc76, 0x4174,
+ 0xfca1, 0x417d,
+ 0xfcba, 0x4195,
+ 0xfcbc, 0x4952,
+ 0xfcbe, 0x4198,
+ 0xfccc, 0x4954,
+ 0xfccd, 0x41a7,
+ 0xfce3, 0x4955,
+ 0xfce4, 0x41bd,
+ 0xfcee, 0x4956,
+ 0xfcef, 0x41c7,
+ 0xfcf2, 0x41ca,
+ 0xfd40, 0x41d7,
+ 0xfd49, 0x4957,
+ 0xfd4a, 0x41e0,
+ 0xfd6a, 0x4958,
+ 0xfd6b, 0x4201,
+ 0xfda1, 0x4215,
+ 0xfdb9, 0x422d,
+ 0xfdbc, 0x4230,
+ 0xfde3, 0x4959,
+ 0xfde4, 0x4258,
+ 0xfdf2, 0x495a,
+ 0xfdf3, 0x4266,
+ 0xfe40, 0x4272,
+ 0xfe53, 0x4285,
+ 0xfe6d, 0x495b,
+ 0xfe6e, 0x429f,
+ 0xfe70, 0x42a1,
+ 0xfe78, 0x495c,
+ 0xfe79, 0x42a9,
+ 0xfea1, 0x42af,
+ 0xfeab, 0x42b8,
+ 0xfede, 0x495d,
+ 0xfee0, 0x42eb,
+ 0xfeed, 0x495f,
+ 0xfeef, 0x42f8,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 cns13ETHKB5HEnc16 = {
+ 0,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
+ 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010,
+ 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018,
+ 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020,
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028,
+ 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030,
+ 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038,
+ 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040,
+ 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048,
+ 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050,
+ 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
+ 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ cns13ETHKB5HMap2, 1126
+};
+
+static Gushort cns13ETHKB5VMap2[2278] = {
+ 0x0000, 0x0000,
+ 0x8840, 0x44c9,
+ 0x8856, 0x4961,
+ 0x88a1, 0x498a,
+ 0x88a9, 0x499c,
+ 0x8940, 0x4534,
+ 0x8943, 0x4536,
+ 0x8946, 0x4537,
+ 0x894c, 0x453b,
+ 0x894d, 0x43c3,
+ 0x894e, 0x453c,
+ 0x8951, 0x439a,
+ 0x8952, 0x453f,
+ 0x89a1, 0x456c,
+ 0x89a6, 0x43a2,
+ 0x89ab, 0x43ec,
+ 0x89ac, 0x4571,
+ 0x89ad, 0x43eb,
+ 0x89ae, 0x4572,
+ 0x89b0, 0x4573,
+ 0x89b5, 0x4576,
+ 0x89c1, 0x4581,
+ 0x89c5, 0x4584,
+ 0x89cf, 0x43bc,
+ 0x89d0, 0x458e,
+ 0x89d9, 0x439c,
+ 0x89da, 0x4597,
+ 0x89db, 0x439e,
+ 0x89dc, 0x4598,
+ 0x89dd, 0x439f,
+ 0x89de, 0x4599,
+ 0x89e1, 0x43a1,
+ 0x89e2, 0x459c,
+ 0x89e3, 0x43a3,
+ 0x89e4, 0x459d,
+ 0x89ea, 0x43a5,
+ 0x89ec, 0x45a3,
+ 0x89fa, 0x43a9,
+ 0x89fb, 0x45b1,
+ 0x8a40, 0x45b5,
+ 0x8a41, 0x4309,
+ 0x8a43, 0x430b,
+ 0x8a4d, 0x45b6,
+ 0x8a4e, 0x4316,
+ 0x8a5a, 0x45b7,
+ 0x8a5b, 0x4323,
+ 0x8a5e, 0x45b8,
+ 0x8a5f, 0x4327,
+ 0x8a64, 0x432c,
+ 0x8a71, 0x45b9,
+ 0x8a72, 0x433a,
+ 0x8a76, 0x433e,
+ 0x8a77, 0x45ba,
+ 0x8a78, 0x4340,
+ 0x8a7a, 0x45bb,
+ 0x8a7b, 0x4343,
+ 0x8a7c, 0x45bc,
+ 0x8a7d, 0x4345,
+ 0x8a7e, 0x45bd,
+ 0x8aa1, 0x4347,
+ 0x8aa8, 0x45be,
+ 0x8aa9, 0x434f,
+ 0x8aac, 0x4352,
+ 0x8ab2, 0x4358,
+ 0x8ab6, 0x45bf,
+ 0x8ab7, 0x435d,
+ 0x8ab8, 0x45c0,
+ 0x8ab9, 0x435f,
+ 0x8abb, 0x4361,
+ 0x8ac9, 0x436f,
+ 0x8acc, 0x45c1,
+ 0x8ace, 0x4374,
+ 0x8ad6, 0x45c2,
+ 0x8ad8, 0x437e,
+ 0x8adf, 0x4385,
+ 0x8ae6, 0x45c4,
+ 0x8ae7, 0x43db,
+ 0x8ae8, 0x45c5,
+ 0x8af6, 0x45d2,
+ 0x8b40, 0x45db,
+ 0x8b41, 0x438c,
+ 0x8b43, 0x45dc,
+ 0x8b45, 0x438e,
+ 0x8b46, 0x45de,
+ 0x8b47, 0x438f,
+ 0x8b48, 0x45df,
+ 0x8b49, 0x4390,
+ 0x8b4a, 0x45e0,
+ 0x8b4b, 0x4391,
+ 0x8b4c, 0x45e1,
+ 0x8b4d, 0x4392,
+ 0x8b51, 0x45e2,
+ 0x8b55, 0x45e5,
+ 0x8b58, 0x4397,
+ 0x8b59, 0x45e8,
+ 0x8b5a, 0x4398,
+ 0x8b5b, 0x43c4,
+ 0x8b5c, 0x45e9,
+ 0x8b61, 0x43a7,
+ 0x8b62, 0x45ee,
+ 0x8b68, 0x43ac,
+ 0x8b69, 0x45f4,
+ 0x8ba1, 0x460a,
+ 0x8bc0, 0x44df,
+ 0x8bde, 0x44fc,
+ 0x8d60, 0x4629,
+ 0x8d62, 0x43ba,
+ 0x8d63, 0x462b,
+ 0x8d68, 0x43bb,
+ 0x8d69, 0x43a0,
+ 0x8d6a, 0x43bd,
+ 0x8d6b, 0x4630,
+ 0x8d6e, 0x43be,
+ 0x8d6f, 0x4633,
+ 0x8d76, 0x43bf,
+ 0x8d77, 0x463a,
+ 0x8d7a, 0x43c0,
+ 0x8d7b, 0x463d,
+ 0x8d7c, 0x43c1,
+ 0x8d7d, 0x463e,
+ 0x8da1, 0x4640,
+ 0x8da5, 0x43c2,
+ 0x8da6, 0x4644,
+ 0x8da8, 0x43b9,
+ 0x8da9, 0x43ad,
+ 0x8daa, 0x4646,
+ 0x8db6, 0x43c7,
+ 0x8db7, 0x4652,
+ 0x8dc3, 0x43c8,
+ 0x8dc4, 0x465e,
+ 0x8dfa, 0x43f9,
+ 0x8dfb, 0x4694,
+ 0x8e40, 0x372b,
+ 0x8e45, 0x4698,
+ 0x8e46, 0x3730,
+ 0x8e6a, 0x3754,
+ 0x8e6b, 0x4699,
+ 0x8e6d, 0x3756,
+ 0x8e70, 0x3759,
+ 0x8e76, 0x469b,
+ 0x8e77, 0x375f,
+ 0x8e7b, 0x469c,
+ 0x8e7c, 0x3764,
+ 0x8ea1, 0x3766,
+ 0x8ea6, 0x469d,
+ 0x8ea7, 0x376b,
+ 0x8eac, 0x3770,
+ 0x8eb5, 0x3779,
+ 0x8eb8, 0x469e,
+ 0x8eb9, 0x377d,
+ 0x8ec9, 0x469f,
+ 0x8eca, 0x378d,
+ 0x8ece, 0x3791,
+ 0x8ed1, 0x3794,
+ 0x8ee5, 0x46a0,
+ 0x8ee6, 0x37a8,
+ 0x8eef, 0x46a1,
+ 0x8ef0, 0x37b1,
+ 0x8ef6, 0x46a2,
+ 0x8ef7, 0x37b8,
+ 0x8f40, 0x37c0,
+ 0x8f58, 0x37d8,
+ 0x8f59, 0x46a3,
+ 0x8f5a, 0x37d9,
+ 0x8f5f, 0x46a4,
+ 0x8f60, 0x37de,
+ 0x8f67, 0x46a5,
+ 0x8f68, 0x37e5,
+ 0x8f6a, 0x37e7,
+ 0x8f6f, 0x37ec,
+ 0x8f79, 0x46a6,
+ 0x8f7a, 0x37f7,
+ 0x8fa1, 0x37fc,
+ 0x8fb0, 0x46a7,
+ 0x8fb1, 0x380c,
+ 0x8fc5, 0x46a8,
+ 0x8fc6, 0x3820,
+ 0x8fc7, 0x46a9,
+ 0x8fc8, 0x3821,
+ 0x8fca, 0x46aa,
+ 0x8fcd, 0x3826,
+ 0x8fda, 0x46ab,
+ 0x8fdb, 0x3833,
+ 0x8fe3, 0x46ac,
+ 0x8fe4, 0x383c,
+ 0x8ffc, 0x46ad,
+ 0x8ffd, 0x3854,
+ 0x9040, 0x3856,
+ 0x9055, 0x46ae,
+ 0x9056, 0x386c,
+ 0x905c, 0x46af,
+ 0x905f, 0x3873,
+ 0x906e, 0x3882,
+ 0x906f, 0x46b2,
+ 0x9070, 0x3883,
+ 0x907b, 0x388d,
+ 0x90a1, 0x3891,
+ 0x90a6, 0x46b3,
+ 0x90a7, 0x3896,
+ 0x90b8, 0x46b4,
+ 0x90b9, 0x38a7,
+ 0x90dd, 0x38cb,
+ 0x90f2, 0x38e0,
+ 0x9140, 0x38ed,
+ 0x9165, 0x46b5,
+ 0x9166, 0x3912,
+ 0x916e, 0x46b6,
+ 0x916f, 0x391a,
+ 0x917e, 0x46b7,
+ 0x91a1, 0x3929,
+ 0x91a2, 0x46b8,
+ 0x91a3, 0x392a,
+ 0x91c0, 0x3947,
+ 0x91c8, 0x46b9,
+ 0x91c9, 0x3950,
+ 0x9240, 0x3986,
+ 0x9245, 0x398b,
+ 0x9264, 0x46ba,
+ 0x9265, 0x39ab,
+ 0x926d, 0x46bb,
+ 0x926e, 0x39b4,
+ 0x92a1, 0x39c5,
+ 0x92b3, 0x39d3,
+ 0x92c9, 0x39e9,
+ 0x92d2, 0x39f2,
+ 0x92e5, 0x46bc,
+ 0x92e6, 0x3a05,
+ 0x92f2, 0x46bd,
+ 0x92f3, 0x3a11,
+ 0x9340, 0x3a1d,
+ 0x9368, 0x46be,
+ 0x9369, 0x3a45,
+ 0x93a1, 0x3a5b,
+ 0x93aa, 0x46bf,
+ 0x93ab, 0x3a64,
+ 0x93c2, 0x46c0,
+ 0x93c3, 0x3a7b,
+ 0x93e5, 0x46c1,
+ 0x93e6, 0x3a9d,
+ 0x93e8, 0x46c2,
+ 0x93e9, 0x3aa0,
+ 0x93eb, 0x46c3,
+ 0x93ec, 0x3aa2,
+ 0x9440, 0x3ab5,
+ 0x9446, 0x46c4,
+ 0x9448, 0x3abc,
+ 0x9479, 0x46c5,
+ 0x947a, 0x3aee,
+ 0x94a1, 0x3af3,
+ 0x94cb, 0x46c6,
+ 0x94cc, 0x3b1e,
+ 0x9540, 0x3b51,
+ 0x954d, 0x46c7,
+ 0x954e, 0x3b5e,
+ 0x955a, 0x46c8,
+ 0x955b, 0x3b6a,
+ 0x955f, 0x46c9,
+ 0x9560, 0x3b6f,
+ 0x95a1, 0x3b8e,
+ 0x95c6, 0x46ca,
+ 0x95c7, 0x3bb3,
+ 0x95da, 0x3bc6,
+ 0x9640, 0x3beb,
+ 0x9645, 0x3bf0,
+ 0x9651, 0x46cb,
+ 0x9652, 0x3bfd,
+ 0x966a, 0x46cc,
+ 0x966b, 0x3c16,
+ 0x96a1, 0x3c2a,
+ 0x96d4, 0x46cd,
+ 0x96d5, 0x3c5d,
+ 0x96ee, 0x3c76,
+ 0x96fd, 0x3c85,
+ 0x9740, 0x3c87,
+ 0x97a1, 0x3cc6,
+ 0x9840, 0x3d24,
+ 0x9844, 0x46ce,
+ 0x9846, 0x3d2a,
+ 0x986f, 0x46d0,
+ 0x9870, 0x3d54,
+ 0x9875, 0x46d1,
+ 0x9877, 0x3d59,
+ 0x9878, 0x46d3,
+ 0x987a, 0x3d5a,
+ 0x987b, 0x46d5,
+ 0x98a1, 0x46d9,
+ 0x98a3, 0x3d5b,
+ 0x98a4, 0x46db,
+ 0x98af, 0x3d5c,
+ 0x98b0, 0x46e6,
+ 0x98b4, 0x43ca,
+ 0x98b5, 0x46ea,
+ 0x98b6, 0x3d5d,
+ 0x98b7, 0x46eb,
+ 0x98b8, 0x43cc,
+ 0x98b9, 0x3d5e,
+ 0x98ba, 0x46ec,
+ 0x98bb, 0x43fa,
+ 0x98bc, 0x46ed,
+ 0x98bd, 0x3d5f,
+ 0x98bf, 0x46ee,
+ 0x98c2, 0x3d61,
+ 0x98c3, 0x46f1,
+ 0x98c4, 0x3d62,
+ 0x98c5, 0x46f2,
+ 0x98c6, 0x3d63,
+ 0x98c8, 0x46f3,
+ 0x98d2, 0x43cd,
+ 0x98d3, 0x46fd,
+ 0x98d8, 0x43ce,
+ 0x98da, 0x4702,
+ 0x98db, 0x43d1,
+ 0x98dc, 0x4703,
+ 0x98df, 0x43d4,
+ 0x98e0, 0x4706,
+ 0x98e3, 0x3d65,
+ 0x98e4, 0x4709,
+ 0x98e7, 0x3d66,
+ 0x98e8, 0x470c,
+ 0x98ed, 0x3d67,
+ 0x98ee, 0x4711,
+ 0x98f0, 0x3d68,
+ 0x98f1, 0x4713,
+ 0x98f2, 0x3d69,
+ 0x98f3, 0x4714,
+ 0x98f4, 0x43d5,
+ 0x98f6, 0x4715,
+ 0x98fc, 0x3d6a,
+ 0x98fd, 0x471b,
+ 0x98fe, 0x43d7,
+ 0x9940, 0x471c,
+ 0x9942, 0x43fc,
+ 0x9943, 0x3d6b,
+ 0x9944, 0x471e,
+ 0x9945, 0x3d6c,
+ 0x9946, 0x471f,
+ 0x9947, 0x43d8,
+ 0x9948, 0x4720,
+ 0x994f, 0x3d6d,
+ 0x9950, 0x4727,
+ 0x9954, 0x43d9,
+ 0x9955, 0x472b,
+ 0x995c, 0x43da,
+ 0x995d, 0x4732,
+ 0x9964, 0x43dc,
+ 0x9965, 0x4739,
+ 0x996a, 0x3d6e,
+ 0x996b, 0x473e,
+ 0x996e, 0x3d6f,
+ 0x996f, 0x4741,
+ 0x9975, 0x3d70,
+ 0x9976, 0x4747,
+ 0x9978, 0x3d71,
+ 0x9979, 0x4749,
+ 0x99a1, 0x474f,
+ 0x99a2, 0x3d72,
+ 0x99a3, 0x4750,
+ 0x99a4, 0x43c5,
+ 0x99a5, 0x4751,
+ 0x99a6, 0x43c6,
+ 0x99a7, 0x4752,
+ 0x99ae, 0x3d73,
+ 0x99af, 0x4759,
+ 0x99b2, 0x43de,
+ 0x99b3, 0x475c,
+ 0x99b6, 0x3d74,
+ 0x99b7, 0x475f,
+ 0x99ba, 0x3d75,
+ 0x99bb, 0x4762,
+ 0x99ca, 0x43e0,
+ 0x99cb, 0x4771,
+ 0x99cd, 0x43e2,
+ 0x99ce, 0x4773,
+ 0x99d3, 0x43e3,
+ 0x99d4, 0x4778,
+ 0x99d6, 0x43e5,
+ 0x99d7, 0x477a,
+ 0x99df, 0x43df,
+ 0x99e0, 0x4782,
+ 0x99e2, 0x3d76,
+ 0x99e3, 0x4784,
+ 0x99e4, 0x43ab,
+ 0x99e5, 0x4785,
+ 0x99e6, 0x43e7,
+ 0x99e7, 0x4786,
+ 0x99e8, 0x43e9,
+ 0x99e9, 0x4787,
+ 0x99ef, 0x43fd,
+ 0x99f0, 0x478d,
+ 0x99f4, 0x3d77,
+ 0x99f5, 0x4791,
+ 0x9a40, 0x479b,
+ 0x9a4a, 0x3d78,
+ 0x9a4b, 0x47a5,
+ 0x9a4c, 0x3d79,
+ 0x9a4d, 0x47a6,
+ 0x9a59, 0x3d7a,
+ 0x9a5a, 0x47b2,
+ 0x9a5f, 0x43af,
+ 0x9a60, 0x47b7,
+ 0x9a61, 0x3d7b,
+ 0x9a62, 0x47b8,
+ 0x9a66, 0x43ed,
+ 0x9a67, 0x47bc,
+ 0x9a68, 0x3d7c,
+ 0x9a69, 0x43ee,
+ 0x9a6a, 0x47bd,
+ 0x9a6b, 0x43ff,
+ 0x9a6c, 0x47be,
+ 0x9a73, 0x3d7d,
+ 0x9a74, 0x47c5,
+ 0x9a75, 0x43f1,
+ 0x9a76, 0x47c6,
+ 0x9a7e, 0x3d7e,
+ 0x9aa1, 0x47ce,
+ 0x9aa3, 0x43f3,
+ 0x9aa4, 0x47d0,
+ 0x9aa5, 0x43f2,
+ 0x9aa6, 0x47d1,
+ 0x9aa9, 0x43f8,
+ 0x9aaa, 0x43f4,
+ 0x9aab, 0x47d4,
+ 0x9ab2, 0x3d7f,
+ 0x9ab3, 0x47db,
+ 0x9ab7, 0x3d80,
+ 0x9ab8, 0x47df,
+ 0x9ab9, 0x3d81,
+ 0x9aba, 0x47e0,
+ 0x9abb, 0x3d82,
+ 0x9abc, 0x47e1,
+ 0x9abd, 0x43b7,
+ 0x9abe, 0x47e2,
+ 0x9ac7, 0x3d83,
+ 0x9ac8, 0x47eb,
+ 0x9ad0, 0x3d84,
+ 0x9ad1, 0x47f3,
+ 0x9ad2, 0x3d85,
+ 0x9ad3, 0x47f4,
+ 0x9ad9, 0x3d86,
+ 0x9adc, 0x47fa,
+ 0x9ae2, 0x3d89,
+ 0x9ae3, 0x4800,
+ 0x9ae4, 0x3d8a,
+ 0x9ae5, 0x4801,
+ 0x9ae8, 0x3d8b,
+ 0x9ae9, 0x43b0,
+ 0x9aea, 0x4804,
+ 0x9aee, 0x43b2,
+ 0x9aef, 0x4808,
+ 0x9af2, 0x3d8c,
+ 0x9af3, 0x480b,
+ 0x9af6, 0x3d8d,
+ 0x9af7, 0x480e,
+ 0x9afb, 0x3d8e,
+ 0x9afc, 0x4812,
+ 0x9b40, 0x4815,
+ 0x9b46, 0x3d8f,
+ 0x9b47, 0x481b,
+ 0x9b4a, 0x3d90,
+ 0x9b4b, 0x481e,
+ 0x9b54, 0x3d92,
+ 0x9b55, 0x4827,
+ 0x9b58, 0x3d93,
+ 0x9b59, 0x482a,
+ 0x9b5a, 0x3d94,
+ 0x9b5b, 0x482b,
+ 0x9b5c, 0x3d95,
+ 0x9b5d, 0x482c,
+ 0x9b5e, 0x3d96,
+ 0x9b60, 0x482d,
+ 0x9b62, 0x482e,
+ 0x9b70, 0x3d98,
+ 0x9b74, 0x483c,
+ 0x9b77, 0x3d9d,
+ 0x9b79, 0x483e,
+ 0x9b7c, 0x3da0,
+ 0x9b7d, 0x4840,
+ 0x9b7e, 0x3da1,
+ 0x9ba1, 0x3da2,
+ 0x9ba2, 0x4841,
+ 0x9ba3, 0x3da3,
+ 0x9ba5, 0x4842,
+ 0x9ba7, 0x3da5,
+ 0x9bab, 0x4844,
+ 0x9bac, 0x3da9,
+ 0x9bad, 0x4845,
+ 0x9baf, 0x3daa,
+ 0x9bb0, 0x4847,
+ 0x9bb2, 0x3dab,
+ 0x9bba, 0x4849,
+ 0x9bbe, 0x3db3,
+ 0x9bbf, 0x484d,
+ 0x9bc0, 0x3db4,
+ 0x9bc7, 0x484e,
+ 0x9bca, 0x3dbb,
+ 0x9bcb, 0x4851,
+ 0x9bcc, 0x3dbc,
+ 0x9bcd, 0x4852,
+ 0x9bce, 0x43d0,
+ 0x9bcf, 0x4853,
+ 0x9bd0, 0x3dbd,
+ 0x9bd2, 0x4854,
+ 0x9bd3, 0x3dbf,
+ 0x9bd4, 0x4855,
+ 0x9bd5, 0x3dc0,
+ 0x9bd6, 0x4856,
+ 0x9bd8, 0x3dc1,
+ 0x9bdb, 0x4858,
+ 0x9bdd, 0x3dc4,
+ 0x9bdf, 0x3dc5,
+ 0x9be0, 0x485a,
+ 0x9be1, 0x3dc6,
+ 0x9be2, 0x485b,
+ 0x9be3, 0x3dc7,
+ 0x9be4, 0x485c,
+ 0x9be7, 0x3dc8,
+ 0x9be8, 0x485f,
+ 0x9be9, 0x3dc9,
+ 0x9bed, 0x4860,
+ 0x9bee, 0x3dcd,
+ 0x9bf0, 0x4861,
+ 0x9bf3, 0x3dcf,
+ 0x9bf4, 0x4864,
+ 0x9bf7, 0x4866,
+ 0x9bf8, 0x3dd1,
+ 0x9bfa, 0x4867,
+ 0x9bfb, 0x3dd3,
+ 0x9bfd, 0x4868,
+ 0x9c40, 0x3dd5,
+ 0x9c43, 0x486a,
+ 0x9c44, 0x3dd8,
+ 0x9c47, 0x486b,
+ 0x9c48, 0x3ddb,
+ 0x9c49, 0x486c,
+ 0x9c4a, 0x3ddc,
+ 0x9c4b, 0x486d,
+ 0x9c4d, 0x3ddd,
+ 0x9c54, 0x486f,
+ 0x9c55, 0x3de4,
+ 0x9c56, 0x4870,
+ 0x9c57, 0x3de5,
+ 0x9c5c, 0x4871,
+ 0x9c5d, 0x3dea,
+ 0x9c5e, 0x4872,
+ 0x9c60, 0x3deb,
+ 0x9c61, 0x4874,
+ 0x9c63, 0x4875,
+ 0x9c64, 0x3ded,
+ 0x9c67, 0x4876,
+ 0x9c69, 0x4877,
+ 0x9c6a, 0x3df1,
+ 0x9c6c, 0x4878,
+ 0x9c6d, 0x3df2,
+ 0x9c6e, 0x4879,
+ 0x9c6f, 0x3df3,
+ 0x9c73, 0x487a,
+ 0x9c75, 0x3df7,
+ 0x9c78, 0x487c,
+ 0x9c79, 0x3dfa,
+ 0x9c7a, 0x487d,
+ 0x9c7b, 0x3dfb,
+ 0x9c7d, 0x487e,
+ 0x9c7e, 0x3dfd,
+ 0x9ca1, 0x3dfe,
+ 0x9ca3, 0x487f,
+ 0x9ca5, 0x3e00,
+ 0x9ca6, 0x4881,
+ 0x9ca8, 0x3e01,
+ 0x9caa, 0x4883,
+ 0x9cab, 0x3e03,
+ 0x9cac, 0x4884,
+ 0x9cad, 0x3e04,
+ 0x9caf, 0x4885,
+ 0x9cb1, 0x3e06,
+ 0x9cbb, 0x4887,
+ 0x9cbe, 0x3e12,
+ 0x9cc3, 0x4888,
+ 0x9cc6, 0x3e17,
+ 0x9cce, 0x488b,
+ 0x9ccf, 0x3e1f,
+ 0x9cd1, 0x3e21,
+ 0x9cd4, 0x488c,
+ 0x9cd8, 0x3e24,
+ 0x9cdb, 0x4890,
+ 0x9cdc, 0x3e27,
+ 0x9ce6, 0x4891,
+ 0x9ce7, 0x3e31,
+ 0x9cea, 0x4892,
+ 0x9ceb, 0x3e34,
+ 0x9ced, 0x4893,
+ 0x9cee, 0x3e36,
+ 0x9cfa, 0x4894,
+ 0x9cfd, 0x3e42,
+ 0x9cfe, 0x4897,
+ 0x9d40, 0x43e8,
+ 0x9d41, 0x4898,
+ 0x9d46, 0x3e43,
+ 0x9d47, 0x489d,
+ 0x9d49, 0x3e44,
+ 0x9d4a, 0x489f,
+ 0x9d4c, 0x3e46,
+ 0x9d4e, 0x48a1,
+ 0x9d4f, 0x3e48,
+ 0x9d50, 0x48a2,
+ 0x9d51, 0x3e49,
+ 0x9d52, 0x48a3,
+ 0x9d55, 0x3e4a,
+ 0x9d56, 0x48a6,
+ 0x9d58, 0x48a7,
+ 0x9d5b, 0x48a9,
+ 0x9d61, 0x43c9,
+ 0x9d62, 0x3e4c,
+ 0x9d63, 0x48af,
+ 0x9d64, 0x3e4d,
+ 0x9d65, 0x48b0,
+ 0x9d78, 0x43f5,
+ 0x9d79, 0x3e4e,
+ 0x9d7a, 0x48c3,
+ 0x9d7e, 0x3e4f,
+ 0x9da1, 0x48c7,
+ 0x9da5, 0x3e50,
+ 0x9da9, 0x48cb,
+ 0x9daa, 0x3e54,
+ 0x9dab, 0x48cc,
+ 0x9dac, 0x3e55,
+ 0x9dae, 0x48cd,
+ 0x9db0, 0x3e58,
+ 0x9db1, 0x48cf,
+ 0x9db3, 0x3e59,
+ 0x9db4, 0x48d1,
+ 0x9db5, 0x3e5a,
+ 0x9db6, 0x48d2,
+ 0x9db7, 0x3e5b,
+ 0x9db8, 0x48d3,
+ 0x9dbc, 0x3e5c,
+ 0x9dbe, 0x48d7,
+ 0x9dbf, 0x3e5e,
+ 0x9dc1, 0x48d8,
+ 0x9dc3, 0x3e60,
+ 0x9dc5, 0x48da,
+ 0x9dc7, 0x3e62,
+ 0x9dc9, 0x48dc,
+ 0x9dca, 0x3e64,
+ 0x9dcb, 0x48dd,
+ 0x9dcd, 0x3e65,
+ 0x9dd2, 0x48df,
+ 0x9dd3, 0x3e6a,
+ 0x9dd6, 0x48e0,
+ 0x9dda, 0x3e6d,
+ 0x9dfc, 0x48e4,
+ 0x9dfd, 0x3e8f,
+ 0x9e40, 0x3e91,
+ 0x9e43, 0x48e5,
+ 0x9e44, 0x3e95,
+ 0x9e5f, 0x48e6,
+ 0x9e60, 0x3eb1,
+ 0x9e63, 0x48e7,
+ 0x9e64, 0x3eb4,
+ 0x9e66, 0x48e8,
+ 0x9e68, 0x3eb6,
+ 0x9e69, 0x48ea,
+ 0x9e6a, 0x3eb7,
+ 0x9e6b, 0x48eb,
+ 0x9e71, 0x3eb8,
+ 0x9e72, 0x48f1,
+ 0x9e73, 0x3eb9,
+ 0x9e74, 0x48f2,
+ 0x9e77, 0x3eba,
+ 0x9e79, 0x48f5,
+ 0x9e7a, 0x3ebc,
+ 0x9e7b, 0x48f6,
+ 0x9e7c, 0x3ebd,
+ 0x9e7d, 0x48f7,
+ 0x9e7e, 0x3ebe,
+ 0x9ea1, 0x3ebf,
+ 0x9ea3, 0x48f8,
+ 0x9ea4, 0x3ec1,
+ 0x9ea7, 0x48f9,
+ 0x9eaa, 0x3ec5,
+ 0x9eab, 0x48fb,
+ 0x9ead, 0x3ec7,
+ 0x9eae, 0x48fc,
+ 0x9eaf, 0x3ec8,
+ 0x9eb2, 0x48fd,
+ 0x9eb4, 0x3ecb,
+ 0x9eb5, 0x48ff,
+ 0x9eb6, 0x3ecc,
+ 0x9eb8, 0x4900,
+ 0x9eb9, 0x3ece,
+ 0x9eba, 0x4901,
+ 0x9ebc, 0x3ecf,
+ 0x9ebd, 0x4903,
+ 0x9ebf, 0x3ed0,
+ 0x9ec1, 0x4905,
+ 0x9ec5, 0x3ed3,
+ 0x9ec6, 0x4908,
+ 0x9ec7, 0x3ed4,
+ 0x9ecb, 0x4909,
+ 0x9ecd, 0x3ed9,
+ 0x9ece, 0x490b,
+ 0x9ed0, 0x3eda,
+ 0x9ed2, 0x490d,
+ 0x9ed3, 0x3edc,
+ 0x9ed4, 0x490e,
+ 0x9ed6, 0x3edd,
+ 0x9ed8, 0x4910,
+ 0x9eda, 0x3edf,
+ 0x9ef0, 0x3ef5,
+ 0x9ef2, 0x4912,
+ 0x9ef3, 0x3ef7,
+ 0x9ef5, 0x3ef9,
+ 0x9ef6, 0x4913,
+ 0x9ef9, 0x3efa,
+ 0x9efb, 0x4916,
+ 0x9efc, 0x3efc,
+ 0x9efe, 0x3efe,
+ 0x9f40, 0x3eff,
+ 0x9f43, 0x4917,
+ 0x9f44, 0x3f02,
+ 0x9f48, 0x4918,
+ 0x9f49, 0x3f06,
+ 0x9f4b, 0x4919,
+ 0x9f4d, 0x3f08,
+ 0x9f4f, 0x3f0a,
+ 0x9f61, 0x3f1c,
+ 0x9f67, 0x491b,
+ 0x9f69, 0x3f23,
+ 0x9f70, 0x491d,
+ 0x9f71, 0x3f2a,
+ 0x9fa1, 0x3f38,
+ 0x9fae, 0x3f45,
+ 0x9fb2, 0x3f49,
+ 0x9fb5, 0x491e,
+ 0x9fb6, 0x3f4c,
+ 0x9fbb, 0x491f,
+ 0x9fbc, 0x3f51,
+ 0x9fbf, 0x4920,
+ 0x9fc1, 0x4921,
+ 0x9fc2, 0x3f55,
+ 0x9fc9, 0x3f5c,
+ 0x9fcc, 0x4922,
+ 0x9fcd, 0x3f60,
+ 0x9fd4, 0x4923,
+ 0x9fd5, 0x3f68,
+ 0x9fd9, 0x3f6c,
+ 0x9fdb, 0x3f6e,
+ 0x9fe4, 0x4924,
+ 0x9fe5, 0x3f77,
+ 0x9fe7, 0x3f79,
+ 0x9feb, 0x3f7d,
+ 0x9ff0, 0x3f82,
+ 0x9ff9, 0x4925,
+ 0x9ffa, 0x3f8b,
+ 0xa040, 0x4926,
+ 0xa041, 0x3f90,
+ 0xa047, 0x4927,
+ 0xa048, 0x3f96,
+ 0xa055, 0x4928,
+ 0xa056, 0x3fa3,
+ 0xa058, 0x3fa5,
+ 0xa05b, 0x3fa8,
+ 0xa064, 0x3fb1,
+ 0xa06d, 0x4929,
+ 0xa06e, 0x3fba,
+ 0xa073, 0x3fbf,
+ 0xa078, 0x3fc4,
+ 0xa07b, 0x492a,
+ 0xa07c, 0x3fc7,
+ 0xa0a1, 0x3fca,
+ 0xa0a2, 0x492b,
+ 0xa0a3, 0x3fcb,
+ 0xa0a6, 0x3fce,
+ 0xa0a7, 0x492c,
+ 0xa0a8, 0x3fcf,
+ 0xa0ae, 0x3fd5,
+ 0xa0b0, 0x3fd7,
+ 0xa0c5, 0x492d,
+ 0xa0c6, 0x3fec,
+ 0xa0d0, 0x492e,
+ 0xa0d1, 0x3ff6,
+ 0xa0d4, 0x3ff9,
+ 0xa0d6, 0x3ffb,
+ 0xa0e0, 0x4005,
+ 0xa0e2, 0x4007,
+ 0xa0e3, 0x492f,
+ 0xa0e5, 0x4009,
+ 0xa0e7, 0x4930,
+ 0xa0ee, 0x43b4,
+ 0xa0ef, 0x4937,
+ 0xa0f2, 0x43b8,
+ 0xa0f3, 0x493a,
+ 0xa140, 0x0063,
+ 0xa159, 0x35af,
+ 0xa15d, 0x0080,
+ 0xa1a1, 0x00a2,
+ 0xa1f6, 0x00f8,
+ 0xa1f7, 0x00f7,
+ 0xa1f8, 0x00f9,
+ 0xa240, 0x0100,
+ 0xa2a1, 0x013f,
+ 0xa340, 0x019d,
+ 0xa3a1, 0x01dc,
+ 0xa3bd, 0x01f7,
+ 0xa440, 0x0253,
+ 0xa4a1, 0x0292,
+ 0xa540, 0x02f0,
+ 0xa5a1, 0x032f,
+ 0xa640, 0x038d,
+ 0xa6a1, 0x03cc,
+ 0xa740, 0x042a,
+ 0xa7a1, 0x0469,
+ 0xa840, 0x04c7,
+ 0xa8a1, 0x0506,
+ 0xa940, 0x0564,
+ 0xa9a1, 0x05a3,
+ 0xaa40, 0x0601,
+ 0xaaa1, 0x0640,
+ 0xab40, 0x069e,
+ 0xaba1, 0x06dd,
+ 0xac40, 0x073b,
+ 0xaca1, 0x077a,
+ 0xacfe, 0x097f,
+ 0xad40, 0x07d7,
+ 0xada1, 0x0816,
+ 0xae40, 0x0874,
+ 0xaea1, 0x08b3,
+ 0xaf40, 0x0911,
+ 0xafa1, 0x0950,
+ 0xafd0, 0x0980,
+ 0xb040, 0x09af,
+ 0xb0a1, 0x09ee,
+ 0xb140, 0x0a4c,
+ 0xb1a1, 0x0a8b,
+ 0xb240, 0x0ae9,
+ 0xb2a1, 0x0b28,
+ 0xb340, 0x0b86,
+ 0xb3a1, 0x0bc5,
+ 0xb440, 0x0c23,
+ 0xb4a1, 0x0c62,
+ 0xb540, 0x0cc0,
+ 0xb5a1, 0x0cff,
+ 0xb640, 0x0d5d,
+ 0xb6a1, 0x0d9c,
+ 0xb740, 0x0dfa,
+ 0xb7a1, 0x0e39,
+ 0xb840, 0x0e97,
+ 0xb8a1, 0x0ed6,
+ 0xb940, 0x0f34,
+ 0xb9a1, 0x0f73,
+ 0xba40, 0x0fd1,
+ 0xbaa1, 0x1010,
+ 0xbb40, 0x106e,
+ 0xbba1, 0x10ad,
+ 0xbbc8, 0x10d5,
+ 0xbc40, 0x110c,
+ 0xbca1, 0x114b,
+ 0xbd40, 0x11a9,
+ 0xbda1, 0x11e8,
+ 0xbe40, 0x1246,
+ 0xbe52, 0x10d4,
+ 0xbe53, 0x1258,
+ 0xbea1, 0x1284,
+ 0xbf40, 0x12e2,
+ 0xbfa1, 0x1321,
+ 0xc040, 0x137f,
+ 0xc0a1, 0x13be,
+ 0xc140, 0x141c,
+ 0xc1a1, 0x145b,
+ 0xc1ab, 0x1466,
+ 0xc240, 0x14ba,
+ 0xc2a1, 0x14f9,
+ 0xc2cb, 0x1465,
+ 0xc2cc, 0x1523,
+ 0xc340, 0x1556,
+ 0xc361, 0x1578,
+ 0xc3a1, 0x1596,
+ 0xc3b9, 0x15af,
+ 0xc3ba, 0x15ae,
+ 0xc3bb, 0x15b0,
+ 0xc440, 0x15f4,
+ 0xc456, 0x1577,
+ 0xc457, 0x160a,
+ 0xc4a1, 0x1632,
+ 0xc540, 0x1690,
+ 0xc5a1, 0x16cf,
+ 0xc640, 0x172d,
+ 0xc6a1, 0x01fa,
+ 0xc6bf, 0x0219,
+ 0xc6d8, 0x35b3,
+ 0xc6df, 0x1794,
+ 0xc6e0, 0x35ba,
+ 0xc740, 0x35d9,
+ 0xc7a1, 0x3618,
+ 0xc840, 0x3676,
+ 0xc8a1, 0x36b5,
+ 0xc8d4, 0x44c6,
+ 0xc8d7, 0x451c,
+ 0xc8e0, 0x02dc,
+ 0xc8e1, 0x4525,
+ 0xc8e9, 0x0509,
+ 0xc8ea, 0x452d,
+ 0xc8f1, 0x09f6,
+ 0xc8f5, 0x4992,
+ 0xc940, 0x176c,
+ 0xc94a, 0x0274,
+ 0xc94b, 0x1776,
+ 0xc96c, 0x1798,
+ 0xc9a1, 0x17ab,
+ 0xc9be, 0x1797,
+ 0xc9bf, 0x17c8,
+ 0xc9ed, 0x17f7,
+ 0xca40, 0x1809,
+ 0xcaa1, 0x1848,
+ 0xcaf7, 0x17f6,
+ 0xcaf8, 0x189e,
+ 0xcb40, 0x18a5,
+ 0xcba1, 0x18e4,
+ 0xcc40, 0x1942,
+ 0xcca1, 0x1981,
+ 0xcd40, 0x19df,
+ 0xcda1, 0x1a1e,
+ 0xce40, 0x1a7c,
+ 0xcea1, 0x1abb,
+ 0xcf40, 0x1b19,
+ 0xcfa1, 0x1b58,
+ 0xd040, 0x1bb6,
+ 0xd0a1, 0x1bf5,
+ 0xd140, 0x1c53,
+ 0xd1a1, 0x1c92,
+ 0xd240, 0x1cf0,
+ 0xd2a1, 0x1d2f,
+ 0xd340, 0x1d8d,
+ 0xd3a1, 0x1dcc,
+ 0xd440, 0x1e2a,
+ 0xd4a1, 0x1e69,
+ 0xd540, 0x1ec7,
+ 0xd5a1, 0x1f06,
+ 0xd640, 0x1f64,
+ 0xd6a1, 0x1fa3,
+ 0xd6cc, 0x2254,
+ 0xd6cd, 0x1fcf,
+ 0xd740, 0x2001,
+ 0xd77a, 0x22b9,
+ 0xd77b, 0x203b,
+ 0xd7a1, 0x203f,
+ 0xd840, 0x209d,
+ 0xd8a1, 0x20dc,
+ 0xd940, 0x213a,
+ 0xd9a1, 0x2179,
+ 0xda40, 0x21d7,
+ 0xdaa1, 0x2216,
+ 0xdadf, 0x1fce,
+ 0xdae0, 0x2255,
+ 0xdb40, 0x2274,
+ 0xdba1, 0x22b3,
+ 0xdba7, 0x22ba,
+ 0xdc40, 0x2312,
+ 0xdca1, 0x2351,
+ 0xdd40, 0x23af,
+ 0xdda1, 0x23ee,
+ 0xddfc, 0x2381,
+ 0xddfd, 0x2449,
+ 0xde40, 0x244b,
+ 0xdea1, 0x248a,
+ 0xdf40, 0x24e8,
+ 0xdfa1, 0x2527,
+ 0xe040, 0x2585,
+ 0xe0a1, 0x25c4,
+ 0xe140, 0x2622,
+ 0xe1a1, 0x2661,
+ 0xe240, 0x26bf,
+ 0xe2a1, 0x26fe,
+ 0xe340, 0x275c,
+ 0xe3a1, 0x279b,
+ 0xe440, 0x27f9,
+ 0xe4a1, 0x2838,
+ 0xe540, 0x2896,
+ 0xe5a1, 0x28d5,
+ 0xe640, 0x2933,
+ 0xe6a1, 0x2972,
+ 0xe740, 0x29d0,
+ 0xe7a1, 0x2a0f,
+ 0xe840, 0x2a6d,
+ 0xe8a1, 0x2aac,
+ 0xe8a3, 0x2aaf,
+ 0xe940, 0x2b0b,
+ 0xe976, 0x2b42,
+ 0xe9a1, 0x2b4b,
+ 0xea40, 0x2ba9,
+ 0xeaa1, 0x2be8,
+ 0xeb40, 0x2c46,
+ 0xeb5b, 0x2c62,
+ 0xeba1, 0x2c86,
+ 0xebf1, 0x2aae,
+ 0xebf2, 0x2cd6,
+ 0xec40, 0x2ce3,
+ 0xeca1, 0x2d22,
+ 0xecde, 0x2b41,
+ 0xecdf, 0x2d5f,
+ 0xed40, 0x2d7f,
+ 0xeda1, 0x2dbe,
+ 0xedaa, 0x2dc8,
+ 0xee40, 0x2e1d,
+ 0xeea1, 0x2e5c,
+ 0xeeeb, 0x3014,
+ 0xeeec, 0x2ea6,
+ 0xef40, 0x2eb9,
+ 0xefa1, 0x2ef8,
+ 0xf040, 0x2f56,
+ 0xf056, 0x2dc7,
+ 0xf057, 0x2f6c,
+ 0xf0a1, 0x2f94,
+ 0xf0cb, 0x2c61,
+ 0xf0cc, 0x2fbe,
+ 0xf140, 0x2ff1,
+ 0xf163, 0x3015,
+ 0xf16b, 0x3160,
+ 0xf16c, 0x301d,
+ 0xf1a1, 0x3030,
+ 0xf240, 0x308e,
+ 0xf268, 0x31ef,
+ 0xf269, 0x30b6,
+ 0xf2a1, 0x30cc,
+ 0xf2c3, 0x30ef,
+ 0xf340, 0x312b,
+ 0xf375, 0x3161,
+ 0xf3a1, 0x316b,
+ 0xf440, 0x31c9,
+ 0xf466, 0x31f0,
+ 0xf4a1, 0x3209,
+ 0xf4b5, 0x30ee,
+ 0xf4b6, 0x321d,
+ 0xf4fd, 0x3265,
+ 0xf540, 0x3267,
+ 0xf5a1, 0x32a6,
+ 0xf640, 0x3304,
+ 0xf663, 0x3264,
+ 0xf664, 0x3327,
+ 0xf6a1, 0x3342,
+ 0xf740, 0x33a0,
+ 0xf7a1, 0x33df,
+ 0xf840, 0x343d,
+ 0xf8a1, 0x347c,
+ 0xf940, 0x34da,
+ 0xf977, 0x3512,
+ 0xf9a1, 0x351a,
+ 0xf9c4, 0x3511,
+ 0xf9c5, 0x353d,
+ 0xf9c6, 0x3549,
+ 0xf9c7, 0x353e,
+ 0xf9d2, 0x354a,
+ 0xf9d6, 0x36e8,
+ 0xfa40, 0x400b,
+ 0xfa60, 0x402b,
+ 0xfa67, 0x4032,
+ 0xfaa1, 0x404a,
+ 0xfaa9, 0x4946,
+ 0xfaab, 0x4054,
+ 0xfabe, 0x4067,
+ 0xfac6, 0x406f,
+ 0xfad6, 0x407f,
+ 0xfb40, 0x40a8,
+ 0xfb49, 0x40b1,
+ 0xfb53, 0x4948,
+ 0xfb54, 0x40bc,
+ 0xfb6e, 0x4949,
+ 0xfb6f, 0x40d7,
+ 0xfba1, 0x40e7,
+ 0xfba3, 0x494a,
+ 0xfba4, 0x40ea,
+ 0xfbb9, 0x40ff,
+ 0xfbbf, 0x494b,
+ 0xfbc0, 0x4105,
+ 0xfbcd, 0x494c,
+ 0xfbce, 0x4112,
+ 0xfbf4, 0x4138,
+ 0xfbfa, 0x413e,
+ 0xfc40, 0x4143,
+ 0xfc4a, 0x494d,
+ 0xfc4b, 0x414d,
+ 0xfc50, 0x4151,
+ 0xfc52, 0x494e,
+ 0xfc53, 0x4153,
+ 0xfc63, 0x494f,
+ 0xfc64, 0x4163,
+ 0xfc6d, 0x4950,
+ 0xfc6e, 0x416d,
+ 0xfc75, 0x4951,
+ 0xfc76, 0x4174,
+ 0xfca1, 0x417d,
+ 0xfcba, 0x4195,
+ 0xfcbc, 0x4952,
+ 0xfcbe, 0x4198,
+ 0xfccc, 0x4954,
+ 0xfccd, 0x41a7,
+ 0xfce3, 0x4955,
+ 0xfce4, 0x41bd,
+ 0xfcee, 0x4956,
+ 0xfcef, 0x41c7,
+ 0xfcf2, 0x41ca,
+ 0xfd40, 0x41d7,
+ 0xfd49, 0x4957,
+ 0xfd4a, 0x41e0,
+ 0xfd6a, 0x4958,
+ 0xfd6b, 0x4201,
+ 0xfda1, 0x4215,
+ 0xfdb9, 0x422d,
+ 0xfdbc, 0x4230,
+ 0xfde3, 0x4959,
+ 0xfde4, 0x4258,
+ 0xfdf2, 0x495a,
+ 0xfdf3, 0x4266,
+ 0xfe40, 0x4272,
+ 0xfe53, 0x4285,
+ 0xfe6d, 0x495b,
+ 0xfe6e, 0x429f,
+ 0xfe70, 0x42a1,
+ 0xfe78, 0x495c,
+ 0xfe79, 0x42a9,
+ 0xfea1, 0x42af,
+ 0xfeab, 0x42b8,
+ 0xfede, 0x495d,
+ 0xfee0, 0x42eb,
+ 0xfeed, 0x495f,
+ 0xfeef, 0x42f8,
+ 0xa14b, 0x354e,
+ 0xa15a, 0x35af,
+ 0xa15c, 0x35b1,
+ 0xa15d, 0x0082,
+ 0xa161, 0x0086,
+ 0xa165, 0x008a,
+ 0xa169, 0x008e,
+ 0xa16d, 0x0092,
+ 0xa171, 0x0096,
+ 0xa175, 0x009a,
+ 0xa179, 0x009e,
+ 0xa1e3, 0x354f,
+ 0xc6e4, 0x3711,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 cns13ETHKB5VEnc16 = {
+ 1,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
+ 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010,
+ 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018,
+ 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020,
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028,
+ 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030,
+ 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038,
+ 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040,
+ 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048,
+ 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050,
+ 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
+ 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ cns13ETHKB5VMap2, 1139
+};
+
+static Gushort cns13ETenB5HMap2[510] = {
+ 0x0000, 0x0000,
+ 0xa140, 0x0063,
+ 0xa159, 0x35af,
+ 0xa15d, 0x0080,
+ 0xa1a1, 0x00a2,
+ 0xa1f6, 0x00f8,
+ 0xa1f7, 0x00f7,
+ 0xa1f8, 0x00f9,
+ 0xa240, 0x0100,
+ 0xa2a1, 0x013f,
+ 0xa340, 0x019d,
+ 0xa3a1, 0x01dc,
+ 0xa3bd, 0x01f7,
+ 0xa440, 0x0253,
+ 0xa4a1, 0x0292,
+ 0xa540, 0x02f0,
+ 0xa5a1, 0x032f,
+ 0xa640, 0x038d,
+ 0xa6a1, 0x03cc,
+ 0xa740, 0x042a,
+ 0xa7a1, 0x0469,
+ 0xa840, 0x04c7,
+ 0xa8a1, 0x0506,
+ 0xa940, 0x0564,
+ 0xa9a1, 0x05a3,
+ 0xaa40, 0x0601,
+ 0xaaa1, 0x0640,
+ 0xab40, 0x069e,
+ 0xaba1, 0x06dd,
+ 0xac40, 0x073b,
+ 0xaca1, 0x077a,
+ 0xacfe, 0x097f,
+ 0xad40, 0x07d7,
+ 0xada1, 0x0816,
+ 0xae40, 0x0874,
+ 0xaea1, 0x08b3,
+ 0xaf40, 0x0911,
+ 0xafa1, 0x0950,
+ 0xafd0, 0x0980,
+ 0xb040, 0x09af,
+ 0xb0a1, 0x09ee,
+ 0xb140, 0x0a4c,
+ 0xb1a1, 0x0a8b,
+ 0xb240, 0x0ae9,
+ 0xb2a1, 0x0b28,
+ 0xb340, 0x0b86,
+ 0xb3a1, 0x0bc5,
+ 0xb440, 0x0c23,
+ 0xb4a1, 0x0c62,
+ 0xb540, 0x0cc0,
+ 0xb5a1, 0x0cff,
+ 0xb640, 0x0d5d,
+ 0xb6a1, 0x0d9c,
+ 0xb740, 0x0dfa,
+ 0xb7a1, 0x0e39,
+ 0xb840, 0x0e97,
+ 0xb8a1, 0x0ed6,
+ 0xb940, 0x0f34,
+ 0xb9a1, 0x0f73,
+ 0xba40, 0x0fd1,
+ 0xbaa1, 0x1010,
+ 0xbb40, 0x106e,
+ 0xbba1, 0x10ad,
+ 0xbbc8, 0x10d5,
+ 0xbc40, 0x110c,
+ 0xbca1, 0x114b,
+ 0xbd40, 0x11a9,
+ 0xbda1, 0x11e8,
+ 0xbe40, 0x1246,
+ 0xbe52, 0x10d4,
+ 0xbe53, 0x1258,
+ 0xbea1, 0x1284,
+ 0xbf40, 0x12e2,
+ 0xbfa1, 0x1321,
+ 0xc040, 0x137f,
+ 0xc0a1, 0x13be,
+ 0xc140, 0x141c,
+ 0xc1a1, 0x145b,
+ 0xc1ab, 0x1466,
+ 0xc240, 0x14ba,
+ 0xc2a1, 0x14f9,
+ 0xc2cb, 0x1465,
+ 0xc2cc, 0x1523,
+ 0xc340, 0x1556,
+ 0xc361, 0x1578,
+ 0xc3a1, 0x1596,
+ 0xc3b9, 0x15af,
+ 0xc3ba, 0x15ae,
+ 0xc3bb, 0x15b0,
+ 0xc440, 0x15f4,
+ 0xc456, 0x1577,
+ 0xc457, 0x160a,
+ 0xc4a1, 0x1632,
+ 0xc540, 0x1690,
+ 0xc5a1, 0x16cf,
+ 0xc640, 0x172d,
+ 0xc6a1, 0x01fa,
+ 0xc6bf, 0x0219,
+ 0xc6d8, 0x35b3,
+ 0xc6df, 0x1794,
+ 0xc6e0, 0x35ba,
+ 0xc740, 0x35d9,
+ 0xc7a1, 0x3618,
+ 0xc840, 0x3676,
+ 0xc8a1, 0x36b5,
+ 0xc940, 0x176c,
+ 0xc94a, 0x0274,
+ 0xc94b, 0x1776,
+ 0xc96c, 0x1798,
+ 0xc9a1, 0x17ab,
+ 0xc9be, 0x1797,
+ 0xc9bf, 0x17c8,
+ 0xc9ed, 0x17f7,
+ 0xca40, 0x1809,
+ 0xcaa1, 0x1848,
+ 0xcaf7, 0x17f6,
+ 0xcaf8, 0x189e,
+ 0xcb40, 0x18a5,
+ 0xcba1, 0x18e4,
+ 0xcc40, 0x1942,
+ 0xcca1, 0x1981,
+ 0xcd40, 0x19df,
+ 0xcda1, 0x1a1e,
+ 0xce40, 0x1a7c,
+ 0xcea1, 0x1abb,
+ 0xcf40, 0x1b19,
+ 0xcfa1, 0x1b58,
+ 0xd040, 0x1bb6,
+ 0xd0a1, 0x1bf5,
+ 0xd140, 0x1c53,
+ 0xd1a1, 0x1c92,
+ 0xd240, 0x1cf0,
+ 0xd2a1, 0x1d2f,
+ 0xd340, 0x1d8d,
+ 0xd3a1, 0x1dcc,
+ 0xd440, 0x1e2a,
+ 0xd4a1, 0x1e69,
+ 0xd540, 0x1ec7,
+ 0xd5a1, 0x1f06,
+ 0xd640, 0x1f64,
+ 0xd6a1, 0x1fa3,
+ 0xd6cc, 0x2254,
+ 0xd6cd, 0x1fcf,
+ 0xd740, 0x2001,
+ 0xd77a, 0x22b9,
+ 0xd77b, 0x203b,
+ 0xd7a1, 0x203f,
+ 0xd840, 0x209d,
+ 0xd8a1, 0x20dc,
+ 0xd940, 0x213a,
+ 0xd9a1, 0x2179,
+ 0xda40, 0x21d7,
+ 0xdaa1, 0x2216,
+ 0xdadf, 0x1fce,
+ 0xdae0, 0x2255,
+ 0xdb40, 0x2274,
+ 0xdba1, 0x22b3,
+ 0xdba7, 0x22ba,
+ 0xdc40, 0x2312,
+ 0xdca1, 0x2351,
+ 0xdd40, 0x23af,
+ 0xdda1, 0x23ee,
+ 0xddfc, 0x2381,
+ 0xddfd, 0x2449,
+ 0xde40, 0x244b,
+ 0xdea1, 0x248a,
+ 0xdf40, 0x24e8,
+ 0xdfa1, 0x2527,
+ 0xe040, 0x2585,
+ 0xe0a1, 0x25c4,
+ 0xe140, 0x2622,
+ 0xe1a1, 0x2661,
+ 0xe240, 0x26bf,
+ 0xe2a1, 0x26fe,
+ 0xe340, 0x275c,
+ 0xe3a1, 0x279b,
+ 0xe440, 0x27f9,
+ 0xe4a1, 0x2838,
+ 0xe540, 0x2896,
+ 0xe5a1, 0x28d5,
+ 0xe640, 0x2933,
+ 0xe6a1, 0x2972,
+ 0xe740, 0x29d0,
+ 0xe7a1, 0x2a0f,
+ 0xe840, 0x2a6d,
+ 0xe8a1, 0x2aac,
+ 0xe8a3, 0x2aaf,
+ 0xe940, 0x2b0b,
+ 0xe976, 0x2b42,
+ 0xe9a1, 0x2b4b,
+ 0xea40, 0x2ba9,
+ 0xeaa1, 0x2be8,
+ 0xeb40, 0x2c46,
+ 0xeb5b, 0x2c62,
+ 0xeba1, 0x2c86,
+ 0xebf1, 0x2aae,
+ 0xebf2, 0x2cd6,
+ 0xec40, 0x2ce3,
+ 0xeca1, 0x2d22,
+ 0xecde, 0x2b41,
+ 0xecdf, 0x2d5f,
+ 0xed40, 0x2d7f,
+ 0xeda1, 0x2dbe,
+ 0xedaa, 0x2dc8,
+ 0xee40, 0x2e1d,
+ 0xeea1, 0x2e5c,
+ 0xeeeb, 0x3014,
+ 0xeeec, 0x2ea6,
+ 0xef40, 0x2eb9,
+ 0xefa1, 0x2ef8,
+ 0xf040, 0x2f56,
+ 0xf056, 0x2dc7,
+ 0xf057, 0x2f6c,
+ 0xf0a1, 0x2f94,
+ 0xf0cb, 0x2c61,
+ 0xf0cc, 0x2fbe,
+ 0xf140, 0x2ff1,
+ 0xf163, 0x3015,
+ 0xf16b, 0x3160,
+ 0xf16c, 0x301d,
+ 0xf1a1, 0x3030,
+ 0xf240, 0x308e,
+ 0xf268, 0x31ef,
+ 0xf269, 0x30b6,
+ 0xf2a1, 0x30cc,
+ 0xf2c3, 0x30ef,
+ 0xf340, 0x312b,
+ 0xf375, 0x3161,
+ 0xf3a1, 0x316b,
+ 0xf440, 0x31c9,
+ 0xf466, 0x31f0,
+ 0xf4a1, 0x3209,
+ 0xf4b5, 0x30ee,
+ 0xf4b6, 0x321d,
+ 0xf4fd, 0x3265,
+ 0xf540, 0x3267,
+ 0xf5a1, 0x32a6,
+ 0xf640, 0x3304,
+ 0xf663, 0x3264,
+ 0xf664, 0x3327,
+ 0xf6a1, 0x3342,
+ 0xf740, 0x33a0,
+ 0xf7a1, 0x33df,
+ 0xf840, 0x343d,
+ 0xf8a1, 0x347c,
+ 0xf940, 0x34da,
+ 0xf977, 0x3512,
+ 0xf9a1, 0x351a,
+ 0xf9c4, 0x3511,
+ 0xf9c5, 0x353d,
+ 0xf9c6, 0x3549,
+ 0xf9c7, 0x353e,
+ 0xf9d2, 0x354a,
+ 0xf9d6, 0x36e8,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 cns13ETenB5HEnc16 = {
+ 0,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x3550, 0x3551, 0x3552, 0x3553, 0x3554, 0x3555, 0x3556, 0x3557,
+ 0x3558, 0x3559, 0x355a, 0x355b, 0x355c, 0x355d, 0x355e, 0x355f,
+ 0x3560, 0x3561, 0x3562, 0x3563, 0x3564, 0x3565, 0x3566, 0x3567,
+ 0x3568, 0x3569, 0x356a, 0x356b, 0x356c, 0x356d, 0x356e, 0x356f,
+ 0x3570, 0x3571, 0x3572, 0x3573, 0x3574, 0x3575, 0x3576, 0x3577,
+ 0x3578, 0x3579, 0x357a, 0x357b, 0x357c, 0x357d, 0x357e, 0x357f,
+ 0x3580, 0x3581, 0x3582, 0x3583, 0x3584, 0x3585, 0x3586, 0x3587,
+ 0x3588, 0x3589, 0x358a, 0x358b, 0x358c, 0x358d, 0x358e, 0x358f,
+ 0x3590, 0x3591, 0x3592, 0x3593, 0x3594, 0x3595, 0x3596, 0x3597,
+ 0x3598, 0x3599, 0x359a, 0x359b, 0x359c, 0x359d, 0x359e, 0x359f,
+ 0x35a0, 0x35a1, 0x35a2, 0x35a3, 0x35a4, 0x35a5, 0x35a6, 0x35a7,
+ 0x35a8, 0x35a9, 0x35aa, 0x35ab, 0x35ac, 0x35ad, 0x35ae, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ cns13ETenB5HMap2, 255
+};
+
+static Gushort cns13ETenB5VMap2[536] = {
+ 0x0000, 0x0000,
+ 0xa140, 0x0063,
+ 0xa159, 0x35af,
+ 0xa15d, 0x0080,
+ 0xa1a1, 0x00a2,
+ 0xa1f6, 0x00f8,
+ 0xa1f7, 0x00f7,
+ 0xa1f8, 0x00f9,
+ 0xa240, 0x0100,
+ 0xa2a1, 0x013f,
+ 0xa340, 0x019d,
+ 0xa3a1, 0x01dc,
+ 0xa3bd, 0x01f7,
+ 0xa440, 0x0253,
+ 0xa4a1, 0x0292,
+ 0xa540, 0x02f0,
+ 0xa5a1, 0x032f,
+ 0xa640, 0x038d,
+ 0xa6a1, 0x03cc,
+ 0xa740, 0x042a,
+ 0xa7a1, 0x0469,
+ 0xa840, 0x04c7,
+ 0xa8a1, 0x0506,
+ 0xa940, 0x0564,
+ 0xa9a1, 0x05a3,
+ 0xaa40, 0x0601,
+ 0xaaa1, 0x0640,
+ 0xab40, 0x069e,
+ 0xaba1, 0x06dd,
+ 0xac40, 0x073b,
+ 0xaca1, 0x077a,
+ 0xacfe, 0x097f,
+ 0xad40, 0x07d7,
+ 0xada1, 0x0816,
+ 0xae40, 0x0874,
+ 0xaea1, 0x08b3,
+ 0xaf40, 0x0911,
+ 0xafa1, 0x0950,
+ 0xafd0, 0x0980,
+ 0xb040, 0x09af,
+ 0xb0a1, 0x09ee,
+ 0xb140, 0x0a4c,
+ 0xb1a1, 0x0a8b,
+ 0xb240, 0x0ae9,
+ 0xb2a1, 0x0b28,
+ 0xb340, 0x0b86,
+ 0xb3a1, 0x0bc5,
+ 0xb440, 0x0c23,
+ 0xb4a1, 0x0c62,
+ 0xb540, 0x0cc0,
+ 0xb5a1, 0x0cff,
+ 0xb640, 0x0d5d,
+ 0xb6a1, 0x0d9c,
+ 0xb740, 0x0dfa,
+ 0xb7a1, 0x0e39,
+ 0xb840, 0x0e97,
+ 0xb8a1, 0x0ed6,
+ 0xb940, 0x0f34,
+ 0xb9a1, 0x0f73,
+ 0xba40, 0x0fd1,
+ 0xbaa1, 0x1010,
+ 0xbb40, 0x106e,
+ 0xbba1, 0x10ad,
+ 0xbbc8, 0x10d5,
+ 0xbc40, 0x110c,
+ 0xbca1, 0x114b,
+ 0xbd40, 0x11a9,
+ 0xbda1, 0x11e8,
+ 0xbe40, 0x1246,
+ 0xbe52, 0x10d4,
+ 0xbe53, 0x1258,
+ 0xbea1, 0x1284,
+ 0xbf40, 0x12e2,
+ 0xbfa1, 0x1321,
+ 0xc040, 0x137f,
+ 0xc0a1, 0x13be,
+ 0xc140, 0x141c,
+ 0xc1a1, 0x145b,
+ 0xc1ab, 0x1466,
+ 0xc240, 0x14ba,
+ 0xc2a1, 0x14f9,
+ 0xc2cb, 0x1465,
+ 0xc2cc, 0x1523,
+ 0xc340, 0x1556,
+ 0xc361, 0x1578,
+ 0xc3a1, 0x1596,
+ 0xc3b9, 0x15af,
+ 0xc3ba, 0x15ae,
+ 0xc3bb, 0x15b0,
+ 0xc440, 0x15f4,
+ 0xc456, 0x1577,
+ 0xc457, 0x160a,
+ 0xc4a1, 0x1632,
+ 0xc540, 0x1690,
+ 0xc5a1, 0x16cf,
+ 0xc640, 0x172d,
+ 0xc6a1, 0x01fa,
+ 0xc6bf, 0x0219,
+ 0xc6d8, 0x35b3,
+ 0xc6df, 0x1794,
+ 0xc6e0, 0x35ba,
+ 0xc740, 0x35d9,
+ 0xc7a1, 0x3618,
+ 0xc840, 0x3676,
+ 0xc8a1, 0x36b5,
+ 0xc940, 0x176c,
+ 0xc94a, 0x0274,
+ 0xc94b, 0x1776,
+ 0xc96c, 0x1798,
+ 0xc9a1, 0x17ab,
+ 0xc9be, 0x1797,
+ 0xc9bf, 0x17c8,
+ 0xc9ed, 0x17f7,
+ 0xca40, 0x1809,
+ 0xcaa1, 0x1848,
+ 0xcaf7, 0x17f6,
+ 0xcaf8, 0x189e,
+ 0xcb40, 0x18a5,
+ 0xcba1, 0x18e4,
+ 0xcc40, 0x1942,
+ 0xcca1, 0x1981,
+ 0xcd40, 0x19df,
+ 0xcda1, 0x1a1e,
+ 0xce40, 0x1a7c,
+ 0xcea1, 0x1abb,
+ 0xcf40, 0x1b19,
+ 0xcfa1, 0x1b58,
+ 0xd040, 0x1bb6,
+ 0xd0a1, 0x1bf5,
+ 0xd140, 0x1c53,
+ 0xd1a1, 0x1c92,
+ 0xd240, 0x1cf0,
+ 0xd2a1, 0x1d2f,
+ 0xd340, 0x1d8d,
+ 0xd3a1, 0x1dcc,
+ 0xd440, 0x1e2a,
+ 0xd4a1, 0x1e69,
+ 0xd540, 0x1ec7,
+ 0xd5a1, 0x1f06,
+ 0xd640, 0x1f64,
+ 0xd6a1, 0x1fa3,
+ 0xd6cc, 0x2254,
+ 0xd6cd, 0x1fcf,
+ 0xd740, 0x2001,
+ 0xd77a, 0x22b9,
+ 0xd77b, 0x203b,
+ 0xd7a1, 0x203f,
+ 0xd840, 0x209d,
+ 0xd8a1, 0x20dc,
+ 0xd940, 0x213a,
+ 0xd9a1, 0x2179,
+ 0xda40, 0x21d7,
+ 0xdaa1, 0x2216,
+ 0xdadf, 0x1fce,
+ 0xdae0, 0x2255,
+ 0xdb40, 0x2274,
+ 0xdba1, 0x22b3,
+ 0xdba7, 0x22ba,
+ 0xdc40, 0x2312,
+ 0xdca1, 0x2351,
+ 0xdd40, 0x23af,
+ 0xdda1, 0x23ee,
+ 0xddfc, 0x2381,
+ 0xddfd, 0x2449,
+ 0xde40, 0x244b,
+ 0xdea1, 0x248a,
+ 0xdf40, 0x24e8,
+ 0xdfa1, 0x2527,
+ 0xe040, 0x2585,
+ 0xe0a1, 0x25c4,
+ 0xe140, 0x2622,
+ 0xe1a1, 0x2661,
+ 0xe240, 0x26bf,
+ 0xe2a1, 0x26fe,
+ 0xe340, 0x275c,
+ 0xe3a1, 0x279b,
+ 0xe440, 0x27f9,
+ 0xe4a1, 0x2838,
+ 0xe540, 0x2896,
+ 0xe5a1, 0x28d5,
+ 0xe640, 0x2933,
+ 0xe6a1, 0x2972,
+ 0xe740, 0x29d0,
+ 0xe7a1, 0x2a0f,
+ 0xe840, 0x2a6d,
+ 0xe8a1, 0x2aac,
+ 0xe8a3, 0x2aaf,
+ 0xe940, 0x2b0b,
+ 0xe976, 0x2b42,
+ 0xe9a1, 0x2b4b,
+ 0xea40, 0x2ba9,
+ 0xeaa1, 0x2be8,
+ 0xeb40, 0x2c46,
+ 0xeb5b, 0x2c62,
+ 0xeba1, 0x2c86,
+ 0xebf1, 0x2aae,
+ 0xebf2, 0x2cd6,
+ 0xec40, 0x2ce3,
+ 0xeca1, 0x2d22,
+ 0xecde, 0x2b41,
+ 0xecdf, 0x2d5f,
+ 0xed40, 0x2d7f,
+ 0xeda1, 0x2dbe,
+ 0xedaa, 0x2dc8,
+ 0xee40, 0x2e1d,
+ 0xeea1, 0x2e5c,
+ 0xeeeb, 0x3014,
+ 0xeeec, 0x2ea6,
+ 0xef40, 0x2eb9,
+ 0xefa1, 0x2ef8,
+ 0xf040, 0x2f56,
+ 0xf056, 0x2dc7,
+ 0xf057, 0x2f6c,
+ 0xf0a1, 0x2f94,
+ 0xf0cb, 0x2c61,
+ 0xf0cc, 0x2fbe,
+ 0xf140, 0x2ff1,
+ 0xf163, 0x3015,
+ 0xf16b, 0x3160,
+ 0xf16c, 0x301d,
+ 0xf1a1, 0x3030,
+ 0xf240, 0x308e,
+ 0xf268, 0x31ef,
+ 0xf269, 0x30b6,
+ 0xf2a1, 0x30cc,
+ 0xf2c3, 0x30ef,
+ 0xf340, 0x312b,
+ 0xf375, 0x3161,
+ 0xf3a1, 0x316b,
+ 0xf440, 0x31c9,
+ 0xf466, 0x31f0,
+ 0xf4a1, 0x3209,
+ 0xf4b5, 0x30ee,
+ 0xf4b6, 0x321d,
+ 0xf4fd, 0x3265,
+ 0xf540, 0x3267,
+ 0xf5a1, 0x32a6,
+ 0xf640, 0x3304,
+ 0xf663, 0x3264,
+ 0xf664, 0x3327,
+ 0xf6a1, 0x3342,
+ 0xf740, 0x33a0,
+ 0xf7a1, 0x33df,
+ 0xf840, 0x343d,
+ 0xf8a1, 0x347c,
+ 0xf940, 0x34da,
+ 0xf977, 0x3512,
+ 0xf9a1, 0x351a,
+ 0xf9c4, 0x3511,
+ 0xf9c5, 0x353d,
+ 0xf9c6, 0x3549,
+ 0xf9c7, 0x353e,
+ 0xf9d2, 0x354a,
+ 0xf9d6, 0x36e8,
+ 0xa14b, 0x354e,
+ 0xa15a, 0x35af,
+ 0xa15c, 0x35b1,
+ 0xa15d, 0x0082,
+ 0xa161, 0x0086,
+ 0xa165, 0x008a,
+ 0xa169, 0x008e,
+ 0xa16d, 0x0092,
+ 0xa171, 0x0096,
+ 0xa175, 0x009a,
+ 0xa179, 0x009e,
+ 0xa1e3, 0x354f,
+ 0xc6e4, 0x3711,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 cns13ETenB5VEnc16 = {
+ 1,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x3550, 0x3551, 0x3552, 0x3553, 0x3554, 0x3555, 0x3556, 0x3557,
+ 0x3558, 0x3559, 0x355a, 0x355b, 0x355c, 0x355d, 0x355e, 0x355f,
+ 0x3560, 0x3561, 0x3562, 0x3563, 0x3564, 0x3565, 0x3566, 0x3567,
+ 0x3568, 0x3569, 0x356a, 0x356b, 0x356c, 0x356d, 0x356e, 0x356f,
+ 0x3570, 0x3571, 0x3572, 0x3573, 0x3574, 0x3575, 0x3576, 0x3577,
+ 0x3578, 0x3579, 0x357a, 0x357b, 0x357c, 0x357d, 0x357e, 0x357f,
+ 0x3580, 0x3581, 0x3582, 0x3583, 0x3584, 0x3585, 0x3586, 0x3587,
+ 0x3588, 0x3589, 0x358a, 0x358b, 0x358c, 0x358d, 0x358e, 0x358f,
+ 0x3590, 0x3591, 0x3592, 0x3593, 0x3594, 0x3595, 0x3596, 0x3597,
+ 0x3598, 0x3599, 0x359a, 0x359b, 0x359c, 0x359d, 0x359e, 0x359f,
+ 0x35a0, 0x35a1, 0x35a2, 0x35a3, 0x35a4, 0x35a5, 0x35a6, 0x35a7,
+ 0x35a8, 0x35a9, 0x35aa, 0x35ab, 0x35ac, 0x35ad, 0x35ae, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ cns13ETenB5VMap2, 268
+};
+
+static Gushort cns13ETenmsB5HMap2[510] = {
+ 0x0000, 0x0000,
+ 0xa140, 0x0063,
+ 0xa159, 0x35af,
+ 0xa15d, 0x0080,
+ 0xa1a1, 0x00a2,
+ 0xa1f6, 0x00f8,
+ 0xa1f7, 0x00f7,
+ 0xa1f8, 0x00f9,
+ 0xa240, 0x0100,
+ 0xa2a1, 0x013f,
+ 0xa340, 0x019d,
+ 0xa3a1, 0x01dc,
+ 0xa3bd, 0x01f7,
+ 0xa440, 0x0253,
+ 0xa4a1, 0x0292,
+ 0xa540, 0x02f0,
+ 0xa5a1, 0x032f,
+ 0xa640, 0x038d,
+ 0xa6a1, 0x03cc,
+ 0xa740, 0x042a,
+ 0xa7a1, 0x0469,
+ 0xa840, 0x04c7,
+ 0xa8a1, 0x0506,
+ 0xa940, 0x0564,
+ 0xa9a1, 0x05a3,
+ 0xaa40, 0x0601,
+ 0xaaa1, 0x0640,
+ 0xab40, 0x069e,
+ 0xaba1, 0x06dd,
+ 0xac40, 0x073b,
+ 0xaca1, 0x077a,
+ 0xacfe, 0x097f,
+ 0xad40, 0x07d7,
+ 0xada1, 0x0816,
+ 0xae40, 0x0874,
+ 0xaea1, 0x08b3,
+ 0xaf40, 0x0911,
+ 0xafa1, 0x0950,
+ 0xafd0, 0x0980,
+ 0xb040, 0x09af,
+ 0xb0a1, 0x09ee,
+ 0xb140, 0x0a4c,
+ 0xb1a1, 0x0a8b,
+ 0xb240, 0x0ae9,
+ 0xb2a1, 0x0b28,
+ 0xb340, 0x0b86,
+ 0xb3a1, 0x0bc5,
+ 0xb440, 0x0c23,
+ 0xb4a1, 0x0c62,
+ 0xb540, 0x0cc0,
+ 0xb5a1, 0x0cff,
+ 0xb640, 0x0d5d,
+ 0xb6a1, 0x0d9c,
+ 0xb740, 0x0dfa,
+ 0xb7a1, 0x0e39,
+ 0xb840, 0x0e97,
+ 0xb8a1, 0x0ed6,
+ 0xb940, 0x0f34,
+ 0xb9a1, 0x0f73,
+ 0xba40, 0x0fd1,
+ 0xbaa1, 0x1010,
+ 0xbb40, 0x106e,
+ 0xbba1, 0x10ad,
+ 0xbbc8, 0x10d5,
+ 0xbc40, 0x110c,
+ 0xbca1, 0x114b,
+ 0xbd40, 0x11a9,
+ 0xbda1, 0x11e8,
+ 0xbe40, 0x1246,
+ 0xbe52, 0x10d4,
+ 0xbe53, 0x1258,
+ 0xbea1, 0x1284,
+ 0xbf40, 0x12e2,
+ 0xbfa1, 0x1321,
+ 0xc040, 0x137f,
+ 0xc0a1, 0x13be,
+ 0xc140, 0x141c,
+ 0xc1a1, 0x145b,
+ 0xc1ab, 0x1466,
+ 0xc240, 0x14ba,
+ 0xc2a1, 0x14f9,
+ 0xc2cb, 0x1465,
+ 0xc2cc, 0x1523,
+ 0xc340, 0x1556,
+ 0xc361, 0x1578,
+ 0xc3a1, 0x1596,
+ 0xc3b9, 0x15af,
+ 0xc3ba, 0x15ae,
+ 0xc3bb, 0x15b0,
+ 0xc440, 0x15f4,
+ 0xc456, 0x1577,
+ 0xc457, 0x160a,
+ 0xc4a1, 0x1632,
+ 0xc540, 0x1690,
+ 0xc5a1, 0x16cf,
+ 0xc640, 0x172d,
+ 0xc6a1, 0x01fa,
+ 0xc6bf, 0x0219,
+ 0xc6d8, 0x35b3,
+ 0xc6df, 0x1794,
+ 0xc6e0, 0x35ba,
+ 0xc740, 0x35d9,
+ 0xc7a1, 0x3618,
+ 0xc840, 0x3676,
+ 0xc8a1, 0x36b5,
+ 0xc940, 0x176c,
+ 0xc94a, 0x0274,
+ 0xc94b, 0x1776,
+ 0xc96c, 0x1798,
+ 0xc9a1, 0x17ab,
+ 0xc9be, 0x1797,
+ 0xc9bf, 0x17c8,
+ 0xc9ed, 0x17f7,
+ 0xca40, 0x1809,
+ 0xcaa1, 0x1848,
+ 0xcaf7, 0x17f6,
+ 0xcaf8, 0x189e,
+ 0xcb40, 0x18a5,
+ 0xcba1, 0x18e4,
+ 0xcc40, 0x1942,
+ 0xcca1, 0x1981,
+ 0xcd40, 0x19df,
+ 0xcda1, 0x1a1e,
+ 0xce40, 0x1a7c,
+ 0xcea1, 0x1abb,
+ 0xcf40, 0x1b19,
+ 0xcfa1, 0x1b58,
+ 0xd040, 0x1bb6,
+ 0xd0a1, 0x1bf5,
+ 0xd140, 0x1c53,
+ 0xd1a1, 0x1c92,
+ 0xd240, 0x1cf0,
+ 0xd2a1, 0x1d2f,
+ 0xd340, 0x1d8d,
+ 0xd3a1, 0x1dcc,
+ 0xd440, 0x1e2a,
+ 0xd4a1, 0x1e69,
+ 0xd540, 0x1ec7,
+ 0xd5a1, 0x1f06,
+ 0xd640, 0x1f64,
+ 0xd6a1, 0x1fa3,
+ 0xd6cc, 0x2254,
+ 0xd6cd, 0x1fcf,
+ 0xd740, 0x2001,
+ 0xd77a, 0x22b9,
+ 0xd77b, 0x203b,
+ 0xd7a1, 0x203f,
+ 0xd840, 0x209d,
+ 0xd8a1, 0x20dc,
+ 0xd940, 0x213a,
+ 0xd9a1, 0x2179,
+ 0xda40, 0x21d7,
+ 0xdaa1, 0x2216,
+ 0xdadf, 0x1fce,
+ 0xdae0, 0x2255,
+ 0xdb40, 0x2274,
+ 0xdba1, 0x22b3,
+ 0xdba7, 0x22ba,
+ 0xdc40, 0x2312,
+ 0xdca1, 0x2351,
+ 0xdd40, 0x23af,
+ 0xdda1, 0x23ee,
+ 0xddfc, 0x2381,
+ 0xddfd, 0x2449,
+ 0xde40, 0x244b,
+ 0xdea1, 0x248a,
+ 0xdf40, 0x24e8,
+ 0xdfa1, 0x2527,
+ 0xe040, 0x2585,
+ 0xe0a1, 0x25c4,
+ 0xe140, 0x2622,
+ 0xe1a1, 0x2661,
+ 0xe240, 0x26bf,
+ 0xe2a1, 0x26fe,
+ 0xe340, 0x275c,
+ 0xe3a1, 0x279b,
+ 0xe440, 0x27f9,
+ 0xe4a1, 0x2838,
+ 0xe540, 0x2896,
+ 0xe5a1, 0x28d5,
+ 0xe640, 0x2933,
+ 0xe6a1, 0x2972,
+ 0xe740, 0x29d0,
+ 0xe7a1, 0x2a0f,
+ 0xe840, 0x2a6d,
+ 0xe8a1, 0x2aac,
+ 0xe8a3, 0x2aaf,
+ 0xe940, 0x2b0b,
+ 0xe976, 0x2b42,
+ 0xe9a1, 0x2b4b,
+ 0xea40, 0x2ba9,
+ 0xeaa1, 0x2be8,
+ 0xeb40, 0x2c46,
+ 0xeb5b, 0x2c62,
+ 0xeba1, 0x2c86,
+ 0xebf1, 0x2aae,
+ 0xebf2, 0x2cd6,
+ 0xec40, 0x2ce3,
+ 0xeca1, 0x2d22,
+ 0xecde, 0x2b41,
+ 0xecdf, 0x2d5f,
+ 0xed40, 0x2d7f,
+ 0xeda1, 0x2dbe,
+ 0xedaa, 0x2dc8,
+ 0xee40, 0x2e1d,
+ 0xeea1, 0x2e5c,
+ 0xeeeb, 0x3014,
+ 0xeeec, 0x2ea6,
+ 0xef40, 0x2eb9,
+ 0xefa1, 0x2ef8,
+ 0xf040, 0x2f56,
+ 0xf056, 0x2dc7,
+ 0xf057, 0x2f6c,
+ 0xf0a1, 0x2f94,
+ 0xf0cb, 0x2c61,
+ 0xf0cc, 0x2fbe,
+ 0xf140, 0x2ff1,
+ 0xf163, 0x3015,
+ 0xf16b, 0x3160,
+ 0xf16c, 0x301d,
+ 0xf1a1, 0x3030,
+ 0xf240, 0x308e,
+ 0xf268, 0x31ef,
+ 0xf269, 0x30b6,
+ 0xf2a1, 0x30cc,
+ 0xf2c3, 0x30ef,
+ 0xf340, 0x312b,
+ 0xf375, 0x3161,
+ 0xf3a1, 0x316b,
+ 0xf440, 0x31c9,
+ 0xf466, 0x31f0,
+ 0xf4a1, 0x3209,
+ 0xf4b5, 0x30ee,
+ 0xf4b6, 0x321d,
+ 0xf4fd, 0x3265,
+ 0xf540, 0x3267,
+ 0xf5a1, 0x32a6,
+ 0xf640, 0x3304,
+ 0xf663, 0x3264,
+ 0xf664, 0x3327,
+ 0xf6a1, 0x3342,
+ 0xf740, 0x33a0,
+ 0xf7a1, 0x33df,
+ 0xf840, 0x343d,
+ 0xf8a1, 0x347c,
+ 0xf940, 0x34da,
+ 0xf977, 0x3512,
+ 0xf9a1, 0x351a,
+ 0xf9c4, 0x3511,
+ 0xf9c5, 0x353d,
+ 0xf9c6, 0x3549,
+ 0xf9c7, 0x353e,
+ 0xf9d2, 0x354a,
+ 0xf9d6, 0x36e8,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 cns13ETenmsB5HEnc16 = {
+ 0,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
+ 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010,
+ 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018,
+ 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020,
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028,
+ 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030,
+ 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038,
+ 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040,
+ 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048,
+ 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050,
+ 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
+ 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ cns13ETenmsB5HMap2, 255
+};
+
+static Gushort cns13ETenmsB5VMap2[568] = {
+ 0x0000, 0x0000,
+ 0xa140, 0x0063,
+ 0xa14b, 0x354e,
+ 0xa14c, 0x006d,
+ 0xa14d, 0x0070,
+ 0xa156, 0x0138,
+ 0xa157, 0x007a,
+ 0xa158, 0x007a,
+ 0xa159, 0x35af,
+ 0xa15a, 0x35af,
+ 0xa15b, 0x35b1,
+ 0xa15c, 0x35b1,
+ 0xa15d, 0x0082,
+ 0xa15f, 0x0082,
+ 0xa161, 0x0086,
+ 0xa163, 0x0086,
+ 0xa165, 0x008a,
+ 0xa167, 0x008a,
+ 0xa169, 0x008e,
+ 0xa16b, 0x008e,
+ 0xa16d, 0x0092,
+ 0xa16f, 0x0092,
+ 0xa171, 0x0096,
+ 0xa173, 0x0096,
+ 0xa175, 0x009a,
+ 0xa177, 0x009a,
+ 0xa179, 0x009e,
+ 0xa17b, 0x009e,
+ 0xa17d, 0x0082,
+ 0xa1a1, 0x0086,
+ 0xa1a3, 0x008a,
+ 0xa1a5, 0x00a6,
+ 0xa1f6, 0x00f8,
+ 0xa1f7, 0x00f7,
+ 0xa1f8, 0x00f9,
+ 0xa240, 0x0100,
+ 0xa2a1, 0x013f,
+ 0xa340, 0x019d,
+ 0xa3a1, 0x01dc,
+ 0xa3bd, 0x01f7,
+ 0xa440, 0x0253,
+ 0xa4a1, 0x0292,
+ 0xa540, 0x02f0,
+ 0xa5a1, 0x032f,
+ 0xa640, 0x038d,
+ 0xa6a1, 0x03cc,
+ 0xa740, 0x042a,
+ 0xa7a1, 0x0469,
+ 0xa840, 0x04c7,
+ 0xa8a1, 0x0506,
+ 0xa940, 0x0564,
+ 0xa9a1, 0x05a3,
+ 0xaa40, 0x0601,
+ 0xaaa1, 0x0640,
+ 0xab40, 0x069e,
+ 0xaba1, 0x06dd,
+ 0xac40, 0x073b,
+ 0xaca1, 0x077a,
+ 0xacfe, 0x097f,
+ 0xad40, 0x07d7,
+ 0xada1, 0x0816,
+ 0xae40, 0x0874,
+ 0xaea1, 0x08b3,
+ 0xaf40, 0x0911,
+ 0xafa1, 0x0950,
+ 0xafd0, 0x0980,
+ 0xb040, 0x09af,
+ 0xb0a1, 0x09ee,
+ 0xb140, 0x0a4c,
+ 0xb1a1, 0x0a8b,
+ 0xb240, 0x0ae9,
+ 0xb2a1, 0x0b28,
+ 0xb340, 0x0b86,
+ 0xb3a1, 0x0bc5,
+ 0xb440, 0x0c23,
+ 0xb4a1, 0x0c62,
+ 0xb540, 0x0cc0,
+ 0xb5a1, 0x0cff,
+ 0xb640, 0x0d5d,
+ 0xb6a1, 0x0d9c,
+ 0xb740, 0x0dfa,
+ 0xb7a1, 0x0e39,
+ 0xb840, 0x0e97,
+ 0xb8a1, 0x0ed6,
+ 0xb940, 0x0f34,
+ 0xb9a1, 0x0f73,
+ 0xba40, 0x0fd1,
+ 0xbaa1, 0x1010,
+ 0xbb40, 0x106e,
+ 0xbba1, 0x10ad,
+ 0xbbc8, 0x10d5,
+ 0xbc40, 0x110c,
+ 0xbca1, 0x114b,
+ 0xbd40, 0x11a9,
+ 0xbda1, 0x11e8,
+ 0xbe40, 0x1246,
+ 0xbe52, 0x10d4,
+ 0xbe53, 0x1258,
+ 0xbea1, 0x1284,
+ 0xbf40, 0x12e2,
+ 0xbfa1, 0x1321,
+ 0xc040, 0x137f,
+ 0xc0a1, 0x13be,
+ 0xc140, 0x141c,
+ 0xc1a1, 0x145b,
+ 0xc1ab, 0x1466,
+ 0xc240, 0x14ba,
+ 0xc2a1, 0x14f9,
+ 0xc2cb, 0x1465,
+ 0xc2cc, 0x1523,
+ 0xc340, 0x1556,
+ 0xc361, 0x1578,
+ 0xc3a1, 0x1596,
+ 0xc3b9, 0x15af,
+ 0xc3ba, 0x15ae,
+ 0xc3bb, 0x15b0,
+ 0xc440, 0x15f4,
+ 0xc456, 0x1577,
+ 0xc457, 0x160a,
+ 0xc4a1, 0x1632,
+ 0xc540, 0x1690,
+ 0xc5a1, 0x16cf,
+ 0xc640, 0x172d,
+ 0xc6a1, 0x01fa,
+ 0xc6bf, 0x0219,
+ 0xc6d8, 0x35b3,
+ 0xc6df, 0x1794,
+ 0xc6e0, 0x35ba,
+ 0xc6e4, 0x3711,
+ 0xc6e6, 0x35c0,
+ 0xc740, 0x35d9,
+ 0xc7a1, 0x3618,
+ 0xc840, 0x3676,
+ 0xc8a1, 0x36b5,
+ 0xc940, 0x176c,
+ 0xc94a, 0x0274,
+ 0xc94b, 0x1776,
+ 0xc96c, 0x1798,
+ 0xc9a1, 0x17ab,
+ 0xc9be, 0x1797,
+ 0xc9bf, 0x17c8,
+ 0xc9ed, 0x17f7,
+ 0xca40, 0x1809,
+ 0xcaa1, 0x1848,
+ 0xcaf7, 0x17f6,
+ 0xcaf8, 0x189e,
+ 0xcb40, 0x18a5,
+ 0xcba1, 0x18e4,
+ 0xcc40, 0x1942,
+ 0xcca1, 0x1981,
+ 0xcd40, 0x19df,
+ 0xcda1, 0x1a1e,
+ 0xce40, 0x1a7c,
+ 0xcea1, 0x1abb,
+ 0xcf40, 0x1b19,
+ 0xcfa1, 0x1b58,
+ 0xd040, 0x1bb6,
+ 0xd0a1, 0x1bf5,
+ 0xd140, 0x1c53,
+ 0xd1a1, 0x1c92,
+ 0xd240, 0x1cf0,
+ 0xd2a1, 0x1d2f,
+ 0xd340, 0x1d8d,
+ 0xd3a1, 0x1dcc,
+ 0xd440, 0x1e2a,
+ 0xd4a1, 0x1e69,
+ 0xd540, 0x1ec7,
+ 0xd5a1, 0x1f06,
+ 0xd640, 0x1f64,
+ 0xd6a1, 0x1fa3,
+ 0xd6cc, 0x2254,
+ 0xd6cd, 0x1fcf,
+ 0xd740, 0x2001,
+ 0xd77a, 0x22b9,
+ 0xd77b, 0x203b,
+ 0xd7a1, 0x203f,
+ 0xd840, 0x209d,
+ 0xd8a1, 0x20dc,
+ 0xd940, 0x213a,
+ 0xd9a1, 0x2179,
+ 0xda40, 0x21d7,
+ 0xdaa1, 0x2216,
+ 0xdadf, 0x1fce,
+ 0xdae0, 0x2255,
+ 0xdb40, 0x2274,
+ 0xdba1, 0x22b3,
+ 0xdba7, 0x22ba,
+ 0xdc40, 0x2312,
+ 0xdca1, 0x2351,
+ 0xdd40, 0x23af,
+ 0xdda1, 0x23ee,
+ 0xddfc, 0x2381,
+ 0xddfd, 0x2449,
+ 0xde40, 0x244b,
+ 0xdea1, 0x248a,
+ 0xdf40, 0x24e8,
+ 0xdfa1, 0x2527,
+ 0xe040, 0x2585,
+ 0xe0a1, 0x25c4,
+ 0xe140, 0x2622,
+ 0xe1a1, 0x2661,
+ 0xe240, 0x26bf,
+ 0xe2a1, 0x26fe,
+ 0xe340, 0x275c,
+ 0xe3a1, 0x279b,
+ 0xe440, 0x27f9,
+ 0xe4a1, 0x2838,
+ 0xe540, 0x2896,
+ 0xe5a1, 0x28d5,
+ 0xe640, 0x2933,
+ 0xe6a1, 0x2972,
+ 0xe740, 0x29d0,
+ 0xe7a1, 0x2a0f,
+ 0xe840, 0x2a6d,
+ 0xe8a1, 0x2aac,
+ 0xe8a3, 0x2aaf,
+ 0xe940, 0x2b0b,
+ 0xe976, 0x2b42,
+ 0xe9a1, 0x2b4b,
+ 0xea40, 0x2ba9,
+ 0xeaa1, 0x2be8,
+ 0xeb40, 0x2c46,
+ 0xeb5b, 0x2c62,
+ 0xeba1, 0x2c86,
+ 0xebf1, 0x2aae,
+ 0xebf2, 0x2cd6,
+ 0xec40, 0x2ce3,
+ 0xeca1, 0x2d22,
+ 0xecde, 0x2b41,
+ 0xecdf, 0x2d5f,
+ 0xed40, 0x2d7f,
+ 0xeda1, 0x2dbe,
+ 0xedaa, 0x2dc8,
+ 0xee40, 0x2e1d,
+ 0xeea1, 0x2e5c,
+ 0xeeeb, 0x3014,
+ 0xeeec, 0x2ea6,
+ 0xef40, 0x2eb9,
+ 0xefa1, 0x2ef8,
+ 0xf040, 0x2f56,
+ 0xf056, 0x2dc7,
+ 0xf057, 0x2f6c,
+ 0xf0a1, 0x2f94,
+ 0xf0cb, 0x2c61,
+ 0xf0cc, 0x2fbe,
+ 0xf140, 0x2ff1,
+ 0xf163, 0x3015,
+ 0xf16b, 0x3160,
+ 0xf16c, 0x301d,
+ 0xf1a1, 0x3030,
+ 0xf240, 0x308e,
+ 0xf268, 0x31ef,
+ 0xf269, 0x30b6,
+ 0xf2a1, 0x30cc,
+ 0xf2c3, 0x30ef,
+ 0xf340, 0x312b,
+ 0xf375, 0x3161,
+ 0xf3a1, 0x316b,
+ 0xf440, 0x31c9,
+ 0xf466, 0x31f0,
+ 0xf4a1, 0x3209,
+ 0xf4b5, 0x30ee,
+ 0xf4b6, 0x321d,
+ 0xf4fd, 0x3265,
+ 0xf540, 0x3267,
+ 0xf5a1, 0x32a6,
+ 0xf640, 0x3304,
+ 0xf663, 0x3264,
+ 0xf664, 0x3327,
+ 0xf6a1, 0x3342,
+ 0xf740, 0x33a0,
+ 0xf7a1, 0x33df,
+ 0xf840, 0x343d,
+ 0xf8a1, 0x347c,
+ 0xf940, 0x34da,
+ 0xf977, 0x3512,
+ 0xf9a1, 0x351a,
+ 0xf9c4, 0x3511,
+ 0xf9c5, 0x353d,
+ 0xf9c6, 0x3549,
+ 0xf9c7, 0x353e,
+ 0xf9d2, 0x354a,
+ 0xf9d6, 0x36e8,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 cns13ETenmsB5VEnc16 = {
+ 1,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
+ 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010,
+ 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018,
+ 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020,
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028,
+ 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030,
+ 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038,
+ 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040,
+ 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048,
+ 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050,
+ 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
+ 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ cns13ETenmsB5VMap2, 284
+};
+
+static Gushort cns13HKdlaB5HMap2[2046] = {
+ 0x0000, 0x0000,
+ 0xa140, 0x0063,
+ 0xa159, 0x35af,
+ 0xa15d, 0x0080,
+ 0xa1a1, 0x00a2,
+ 0xa1f6, 0x00f8,
+ 0xa1f7, 0x00f7,
+ 0xa1f8, 0x00f9,
+ 0xa240, 0x0100,
+ 0xa2a1, 0x013f,
+ 0xa340, 0x019d,
+ 0xa3a1, 0x01dc,
+ 0xa3bd, 0x01f7,
+ 0xa440, 0x0253,
+ 0xa4a1, 0x0292,
+ 0xa540, 0x02f0,
+ 0xa5a1, 0x032f,
+ 0xa640, 0x038d,
+ 0xa6a1, 0x03cc,
+ 0xa740, 0x042a,
+ 0xa7a1, 0x0469,
+ 0xa840, 0x04c7,
+ 0xa8a1, 0x0506,
+ 0xa940, 0x0564,
+ 0xa9a1, 0x05a3,
+ 0xaa40, 0x0601,
+ 0xaaa1, 0x0640,
+ 0xab40, 0x069e,
+ 0xaba1, 0x06dd,
+ 0xac40, 0x073b,
+ 0xaca1, 0x077a,
+ 0xacfe, 0x097f,
+ 0xad40, 0x07d7,
+ 0xada1, 0x0816,
+ 0xae40, 0x0874,
+ 0xaea1, 0x08b3,
+ 0xaf40, 0x0911,
+ 0xafa1, 0x0950,
+ 0xafd0, 0x0980,
+ 0xb040, 0x09af,
+ 0xb0a1, 0x09ee,
+ 0xb140, 0x0a4c,
+ 0xb1a1, 0x0a8b,
+ 0xb240, 0x0ae9,
+ 0xb2a1, 0x0b28,
+ 0xb340, 0x0b86,
+ 0xb3a1, 0x0bc5,
+ 0xb440, 0x0c23,
+ 0xb4a1, 0x0c62,
+ 0xb540, 0x0cc0,
+ 0xb5a1, 0x0cff,
+ 0xb640, 0x0d5d,
+ 0xb6a1, 0x0d9c,
+ 0xb740, 0x0dfa,
+ 0xb7a1, 0x0e39,
+ 0xb840, 0x0e97,
+ 0xb8a1, 0x0ed6,
+ 0xb940, 0x0f34,
+ 0xb9a1, 0x0f73,
+ 0xba40, 0x0fd1,
+ 0xbaa1, 0x1010,
+ 0xbb40, 0x106e,
+ 0xbba1, 0x10ad,
+ 0xbbc8, 0x10d5,
+ 0xbc40, 0x110c,
+ 0xbca1, 0x114b,
+ 0xbd40, 0x11a9,
+ 0xbda1, 0x11e8,
+ 0xbe40, 0x1246,
+ 0xbe52, 0x10d4,
+ 0xbe53, 0x1258,
+ 0xbea1, 0x1284,
+ 0xbf40, 0x12e2,
+ 0xbfa1, 0x1321,
+ 0xc040, 0x137f,
+ 0xc0a1, 0x13be,
+ 0xc140, 0x141c,
+ 0xc1a1, 0x145b,
+ 0xc1ab, 0x1466,
+ 0xc240, 0x14ba,
+ 0xc2a1, 0x14f9,
+ 0xc2cb, 0x1465,
+ 0xc2cc, 0x1523,
+ 0xc340, 0x1556,
+ 0xc361, 0x1578,
+ 0xc3a1, 0x1596,
+ 0xc3b9, 0x15af,
+ 0xc3ba, 0x15ae,
+ 0xc3bb, 0x15b0,
+ 0xc440, 0x15f4,
+ 0xc456, 0x1577,
+ 0xc457, 0x160a,
+ 0xc4a1, 0x1632,
+ 0xc540, 0x1690,
+ 0xc5a1, 0x16cf,
+ 0xc640, 0x172d,
+ 0xc940, 0x176c,
+ 0xc94a, 0x0274,
+ 0xc94b, 0x1776,
+ 0xc96c, 0x1798,
+ 0xc9a1, 0x17ab,
+ 0xc9be, 0x1797,
+ 0xc9bf, 0x17c8,
+ 0xc9ed, 0x17f7,
+ 0xca40, 0x1809,
+ 0xcaa1, 0x1848,
+ 0xcaf7, 0x17f6,
+ 0xcaf8, 0x189e,
+ 0xcb40, 0x18a5,
+ 0xcba1, 0x18e4,
+ 0xcc40, 0x1942,
+ 0xcca1, 0x1981,
+ 0xcd40, 0x19df,
+ 0xcda1, 0x1a1e,
+ 0xce40, 0x1a7c,
+ 0xcea1, 0x1abb,
+ 0xcf40, 0x1b19,
+ 0xcfa1, 0x1b58,
+ 0xd040, 0x1bb6,
+ 0xd0a1, 0x1bf5,
+ 0xd140, 0x1c53,
+ 0xd1a1, 0x1c92,
+ 0xd240, 0x1cf0,
+ 0xd2a1, 0x1d2f,
+ 0xd340, 0x1d8d,
+ 0xd3a1, 0x1dcc,
+ 0xd440, 0x1e2a,
+ 0xd4a1, 0x1e69,
+ 0xd540, 0x1ec7,
+ 0xd5a1, 0x1f06,
+ 0xd640, 0x1f64,
+ 0xd6a1, 0x1fa3,
+ 0xd6cc, 0x2254,
+ 0xd6cd, 0x1fcf,
+ 0xd740, 0x2001,
+ 0xd77a, 0x22b9,
+ 0xd77b, 0x203b,
+ 0xd7a1, 0x203f,
+ 0xd840, 0x209d,
+ 0xd8a1, 0x20dc,
+ 0xd940, 0x213a,
+ 0xd9a1, 0x2179,
+ 0xda40, 0x21d7,
+ 0xdaa1, 0x2216,
+ 0xdadf, 0x1fce,
+ 0xdae0, 0x2255,
+ 0xdb40, 0x2274,
+ 0xdba1, 0x22b3,
+ 0xdba7, 0x22ba,
+ 0xdc40, 0x2312,
+ 0xdca1, 0x2351,
+ 0xdd40, 0x23af,
+ 0xdda1, 0x23ee,
+ 0xddfc, 0x2381,
+ 0xddfd, 0x2449,
+ 0xde40, 0x244b,
+ 0xdea1, 0x248a,
+ 0xdf40, 0x24e8,
+ 0xdfa1, 0x2527,
+ 0xe040, 0x2585,
+ 0xe0a1, 0x25c4,
+ 0xe140, 0x2622,
+ 0xe1a1, 0x2661,
+ 0xe240, 0x26bf,
+ 0xe2a1, 0x26fe,
+ 0xe340, 0x275c,
+ 0xe3a1, 0x279b,
+ 0xe440, 0x27f9,
+ 0xe4a1, 0x2838,
+ 0xe540, 0x2896,
+ 0xe5a1, 0x28d5,
+ 0xe640, 0x2933,
+ 0xe6a1, 0x2972,
+ 0xe740, 0x29d0,
+ 0xe7a1, 0x2a0f,
+ 0xe840, 0x2a6d,
+ 0xe8a1, 0x2aac,
+ 0xe8a3, 0x2aaf,
+ 0xe940, 0x2b0b,
+ 0xe976, 0x2b42,
+ 0xe9a1, 0x2b4b,
+ 0xea40, 0x2ba9,
+ 0xeaa1, 0x2be8,
+ 0xeb40, 0x2c46,
+ 0xeb5b, 0x2c62,
+ 0xeba1, 0x2c86,
+ 0xebf1, 0x2aae,
+ 0xebf2, 0x2cd6,
+ 0xec40, 0x2ce3,
+ 0xeca1, 0x2d22,
+ 0xecde, 0x2b41,
+ 0xecdf, 0x2d5f,
+ 0xed40, 0x2d7f,
+ 0xeda1, 0x2dbe,
+ 0xedaa, 0x2dc8,
+ 0xee40, 0x2e1d,
+ 0xeea1, 0x2e5c,
+ 0xeeeb, 0x3014,
+ 0xeeec, 0x2ea6,
+ 0xef40, 0x2eb9,
+ 0xefa1, 0x2ef8,
+ 0xf040, 0x2f56,
+ 0xf056, 0x2dc7,
+ 0xf057, 0x2f6c,
+ 0xf0a1, 0x2f94,
+ 0xf0cb, 0x2c61,
+ 0xf0cc, 0x2fbe,
+ 0xf140, 0x2ff1,
+ 0xf163, 0x3015,
+ 0xf16b, 0x3160,
+ 0xf16c, 0x301d,
+ 0xf1a1, 0x3030,
+ 0xf240, 0x308e,
+ 0xf268, 0x31ef,
+ 0xf269, 0x30b6,
+ 0xf2a1, 0x30cc,
+ 0xf2c3, 0x30ef,
+ 0xf340, 0x312b,
+ 0xf375, 0x3161,
+ 0xf3a1, 0x316b,
+ 0xf440, 0x31c9,
+ 0xf466, 0x31f0,
+ 0xf4a1, 0x3209,
+ 0xf4b5, 0x30ee,
+ 0xf4b6, 0x321d,
+ 0xf4fd, 0x3265,
+ 0xf540, 0x3267,
+ 0xf5a1, 0x32a6,
+ 0xf640, 0x3304,
+ 0xf663, 0x3264,
+ 0xf664, 0x3327,
+ 0xf6a1, 0x3342,
+ 0xf740, 0x33a0,
+ 0xf7a1, 0x33df,
+ 0xf840, 0x343d,
+ 0xf8a1, 0x347c,
+ 0xf940, 0x34da,
+ 0xf977, 0x3512,
+ 0xf9a1, 0x351a,
+ 0xf9c4, 0x3511,
+ 0xf9c5, 0x353d,
+ 0xf9c6, 0x3549,
+ 0xf9c7, 0x353e,
+ 0xf9d2, 0x354a,
+ 0xfa41, 0x4149,
+ 0xfa42, 0x3ea3,
+ 0xfa43, 0x3e84,
+ 0xfa44, 0x3e87,
+ 0xfa45, 0x3e05,
+ 0xfa46, 0x4096,
+ 0xfa47, 0x39c4,
+ 0xfa48, 0x3d6d,
+ 0xfa49, 0x3e7f,
+ 0xfa4a, 0x3c77,
+ 0xfa4b, 0x3e86,
+ 0xfa4c, 0x387c,
+ 0xfa4d, 0x3ea7,
+ 0xfa4e, 0x420e,
+ 0xfa4f, 0x3ea4,
+ 0xfa50, 0x418a,
+ 0xfa51, 0x405f,
+ 0xfa52, 0x4116,
+ 0xfa53, 0x408b,
+ 0xfa54, 0x3e66,
+ 0xfa55, 0x3e65,
+ 0xfa56, 0x3d8f,
+ 0xfa57, 0x419e,
+ 0xfa58, 0x3a66,
+ 0xfa59, 0x4161,
+ 0xfa5a, 0x3e8a,
+ 0xfa5b, 0x3d8e,
+ 0xfa5c, 0x3e8d,
+ 0xfa5d, 0x3dbc,
+ 0xfa5e, 0x3e95,
+ 0xfa5f, 0x39a3,
+ 0xfa60, 0x41f4,
+ 0xfa61, 0x3e91,
+ 0xfa62, 0x3bc6,
+ 0xfa63, 0x3dc3,
+ 0xfa64, 0x3eae,
+ 0xfa65, 0x3746,
+ 0xfa66, 0x3871,
+ 0xfa67, 0x3a00,
+ 0xfa68, 0x428c,
+ 0xfa69, 0x425b,
+ 0xfa6a, 0x3ead,
+ 0xfa6b, 0x4123,
+ 0xfa6c, 0x3ea6,
+ 0xfa6d, 0x3ea0,
+ 0xfa6e, 0x3b2e,
+ 0xfa6f, 0x3dbd,
+ 0xfa70, 0x3864,
+ 0xfa71, 0x3c7d,
+ 0xfa72, 0x3ea9,
+ 0xfa73, 0x420d,
+ 0xfa74, 0x3f58,
+ 0xfa75, 0x3e98,
+ 0xfa76, 0x3d70,
+ 0xfa77, 0x3ea8,
+ 0xfa78, 0x3e94,
+ 0xfa79, 0x3e9d,
+ 0xfa7a, 0x3aaa,
+ 0xfa7b, 0x3ea5,
+ 0xfa7c, 0x3ccc,
+ 0xfa7d, 0x4098,
+ 0xfa7e, 0x3e9f,
+ 0xfaa1, 0x41f5,
+ 0xfaa2, 0x3e8b,
+ 0xfaa3, 0x3b72,
+ 0xfaa4, 0x37e0,
+ 0xfaa5, 0x3adf,
+ 0xfaa6, 0x42e0,
+ 0xfaa7, 0x3e97,
+ 0xfaa8, 0x4192,
+ 0xfaa9, 0x3888,
+ 0xfaaa, 0x42c8,
+ 0xfaab, 0x3e90,
+ 0xfaac, 0x386f,
+ 0xfaad, 0x3e9c,
+ 0xfaae, 0x4144,
+ 0xfaaf, 0x4146,
+ 0xfab0, 0x3e9e,
+ 0xfab1, 0x3e89,
+ 0xfab2, 0x4093,
+ 0xfab3, 0x3e81,
+ 0xfab5, 0x3c0e,
+ 0xfab6, 0x3e85,
+ 0xfab7, 0x38dc,
+ 0xfab8, 0x4069,
+ 0xfab9, 0x37d8,
+ 0xfaba, 0x3e99,
+ 0xfabb, 0x3e83,
+ 0xfabc, 0x3e88,
+ 0xfabd, 0x3e80,
+ 0xfabe, 0x3eb1,
+ 0xfabf, 0x416a,
+ 0xfac0, 0x376b,
+ 0xfac1, 0x3e67,
+ 0xfac2, 0x3e78,
+ 0xfac3, 0x4262,
+ 0xfac4, 0x37f5,
+ 0xfac5, 0x37f4,
+ 0xfac6, 0x3b45,
+ 0xfac7, 0x3e59,
+ 0xfac8, 0x2abc,
+ 0xfac9, 0x3dbf,
+ 0xfaca, 0x40bd,
+ 0xfacb, 0x3e7e,
+ 0xfacc, 0x382d,
+ 0xfacd, 0x3eb0,
+ 0xface, 0x3eab,
+ 0xfacf, 0x3eb2,
+ 0xfad0, 0x4221,
+ 0xfad1, 0x3f6a,
+ 0xfad2, 0x381b,
+ 0xfad3, 0x3e9a,
+ 0xfad4, 0x4223,
+ 0xfad5, 0x3e8e,
+ 0xfad6, 0x3bfd,
+ 0xfad7, 0x405a,
+ 0xfad8, 0x3eaf,
+ 0xfad9, 0x3cc8,
+ 0xfada, 0x3948,
+ 0xfadb, 0x42bd,
+ 0xfadc, 0x40cc,
+ 0xfadd, 0x3e5c,
+ 0xfade, 0x3eac,
+ 0xfadf, 0x391a,
+ 0xfae0, 0x3eaa,
+ 0xfae1, 0x4399,
+ 0xfae2, 0x389a,
+ 0xfae3, 0x3e8c,
+ 0xfae4, 0x389f,
+ 0xfae5, 0x3ea1,
+ 0xfae6, 0x4187,
+ 0xfae7, 0x3e8f,
+ 0xfae8, 0x3fc3,
+ 0xfae9, 0x3ea2,
+ 0xfaea, 0x3e9b,
+ 0xfaeb, 0x3e7d,
+ 0xfaec, 0x4051,
+ 0xfaed, 0x3fbc,
+ 0xfaee, 0x3fd5,
+ 0xfaef, 0x3b14,
+ 0xfaf0, 0x4222,
+ 0xfaf1, 0x379b,
+ 0xfaf2, 0x407b,
+ 0xfaf3, 0x3788,
+ 0xfaf4, 0x3bb4,
+ 0xfaf5, 0x41d0,
+ 0xfaf6, 0x4264,
+ 0xfaf7, 0x385e,
+ 0xfaf8, 0x376c,
+ 0xfaf9, 0x3dbe,
+ 0xfafa, 0x3813,
+ 0xfafb, 0x3fff,
+ 0xfafc, 0x3d63,
+ 0xfafd, 0x3786,
+ 0xfafe, 0x3b4a,
+ 0xfb40, 0x373a,
+ 0xfb41, 0x427a,
+ 0xfb42, 0x3c7a,
+ 0xfb43, 0x4205,
+ 0xfb44, 0x3c26,
+ 0xfb45, 0x38af,
+ 0xfb46, 0x3936,
+ 0xfb47, 0x37a8,
+ 0xfb48, 0x3b74,
+ 0xfb49, 0x3f6d,
+ 0xfb4a, 0x3e96,
+ 0xfb4b, 0x37bc,
+ 0xfb4c, 0x3e7b,
+ 0xfb4d, 0x3fea,
+ 0xfb4e, 0x41ca,
+ 0xfb4f, 0x39d7,
+ 0xfb50, 0x40d1,
+ 0xfb51, 0x3b71,
+ 0xfb52, 0x3fcf,
+ 0xfb53, 0x07c2,
+ 0xfb54, 0x42fe,
+ 0xfb55, 0x3ccd,
+ 0xfb56, 0x3e70,
+ 0xfb57, 0x3e72,
+ 0xfb58, 0x374c,
+ 0xfb59, 0x3769,
+ 0xfb5a, 0x3b4f,
+ 0xfb5b, 0x379f,
+ 0xfb5c, 0x2e45,
+ 0xfb5d, 0x380d,
+ 0xfb5e, 0x3fa2,
+ 0xfb5f, 0x381c,
+ 0xfb60, 0x3f7c,
+ 0xfb61, 0x3f59,
+ 0xfb62, 0x3f9e,
+ 0xfb63, 0x3d93,
+ 0xfb64, 0x3815,
+ 0xfb65, 0x388b,
+ 0xfb66, 0x3c60,
+ 0xfb67, 0x38f0,
+ 0xfb68, 0x37aa,
+ 0xfb69, 0x3f34,
+ 0xfb6a, 0x3c12,
+ 0xfb6b, 0x3900,
+ 0xfb6c, 0x3faa,
+ 0xfb6d, 0x390b,
+ 0xfb6e, 0x3929,
+ 0xfb6f, 0x3f27,
+ 0xfb70, 0x3f90,
+ 0xfb71, 0x3f57,
+ 0xfb72, 0x3f5b,
+ 0xfb73, 0x3f62,
+ 0xfb74, 0x3d76,
+ 0xfb75, 0x39c8,
+ 0xfb76, 0x3f64,
+ 0xfb78, 0x393d,
+ 0xfb79, 0x3c66,
+ 0xfb7a, 0x39d0,
+ 0xfb7b, 0x4022,
+ 0xfb7c, 0x3f2c,
+ 0xfb7d, 0x3f28,
+ 0xfb7e, 0x39cc,
+ 0xfba1, 0x3f26,
+ 0xfba2, 0x39cd,
+ 0xfba3, 0x3f3f,
+ 0xfba4, 0x39c5,
+ 0xfba5, 0x3fce,
+ 0xfba6, 0x4034,
+ 0xfba7, 0x3f5e,
+ 0xfba8, 0x4032,
+ 0xfba9, 0x4054,
+ 0xfbaa, 0x4178,
+ 0xfbab, 0x3f60,
+ 0xfbac, 0x3f29,
+ 0xfbad, 0x405d,
+ 0xfbae, 0x3f43,
+ 0xfbaf, 0x3f68,
+ 0xfbb0, 0x4060,
+ 0xfbb1, 0x3f2a,
+ 0xfbb2, 0x4063,
+ 0xfbb3, 0x39e7,
+ 0xfbb4, 0x38b6,
+ 0xfbb5, 0x4090,
+ 0xfbb6, 0x4048,
+ 0xfbb7, 0x4012,
+ 0xfbb8, 0x3d7c,
+ 0xfbb9, 0x404b,
+ 0xfbba, 0x404d,
+ 0xfbbb, 0x404f,
+ 0xfbbc, 0x424f,
+ 0xfbbd, 0x3d79,
+ 0xfbbe, 0x3f40,
+ 0xfbbf, 0x3f0a,
+ 0xfbc0, 0x3fd0,
+ 0xfbc1, 0x3f36,
+ 0xfbc2, 0x406d,
+ 0xfbc3, 0x4085,
+ 0xfbc4, 0x4084,
+ 0xfbc5, 0x413e,
+ 0xfbc6, 0x413b,
+ 0xfbc7, 0x3fc6,
+ 0xfbc8, 0x4086,
+ 0xfbc9, 0x3952,
+ 0xfbca, 0x40a1,
+ 0xfbcb, 0x3f32,
+ 0xfbcc, 0x4203,
+ 0xfbcd, 0x3f66,
+ 0xfbce, 0x3d83,
+ 0xfbcf, 0x3e75,
+ 0xfbd0, 0x40a2,
+ 0xfbd1, 0x0570,
+ 0xfbd2, 0x3f39,
+ 0xfbd3, 0x0871,
+ 0xfbd4, 0x3f24,
+ 0xfbd5, 0x40ae,
+ 0xfbd6, 0x3f44,
+ 0xfbd7, 0x38f5,
+ 0xfbd8, 0x3fc9,
+ 0xfbd9, 0x3fcd,
+ 0xfbda, 0x3fb5,
+ 0xfbdb, 0x3e7c,
+ 0xfbdc, 0x3fd2,
+ 0xfbdd, 0x3f4d,
+ 0xfbde, 0x40bc,
+ 0xfbdf, 0x40b7,
+ 0xfbe0, 0x3858,
+ 0xfbe1, 0x43af,
+ 0xfbe2, 0x3f6c,
+ 0xfbe3, 0x3d85,
+ 0xfbe4, 0x4396,
+ 0xfbe5, 0x39a6,
+ 0xfbe6, 0x3f7d,
+ 0xfbe7, 0x3fbf,
+ 0xfbe8, 0x40c8,
+ 0xfbe9, 0x3f5f,
+ 0xfbea, 0x3f2b,
+ 0xfbeb, 0x3d72,
+ 0xfbec, 0x40cf,
+ 0xfbed, 0x3a05,
+ 0xfbee, 0x3d82,
+ 0xfbef, 0x40dc,
+ 0xfbf0, 0x3d65,
+ 0xfbf1, 0x40d4,
+ 0xfbf2, 0x40da,
+ 0xfbf3, 0x3f2d,
+ 0xfbf4, 0x0595,
+ 0xfbf5, 0x3d81,
+ 0xfbf6, 0x40f1,
+ 0xfbf7, 0x06f5,
+ 0xfbf8, 0x40f8,
+ 0xfbf9, 0x40fb,
+ 0xfbfa, 0x3f41,
+ 0xfbfb, 0x4118,
+ 0xfbfc, 0x3d89,
+ 0xfbfd, 0x3f5c,
+ 0xfbfe, 0x3d67,
+ 0xfc40, 0x3f0e,
+ 0xfc41, 0x3f13,
+ 0xfc42, 0x4122,
+ 0xfc43, 0x3fca,
+ 0xfc44, 0x4129,
+ 0xfc45, 0x3f0c,
+ 0xfc46, 0x3f0b,
+ 0xfc47, 0x3f61,
+ 0xfc48, 0x3d8a,
+ 0xfc49, 0x3f2e,
+ 0xfc4a, 0x1971,
+ 0xfc4b, 0x4135,
+ 0xfc4c, 0x3a2b,
+ 0xfc4d, 0x3f6b,
+ 0xfc4e, 0x3ba5,
+ 0xfc4f, 0x4044,
+ 0xfc50, 0x4255,
+ 0xfc51, 0x3737,
+ 0xfc52, 0x3f25,
+ 0xfc53, 0x3739,
+ 0xfc54, 0x3a30,
+ 0xfc55, 0x4143,
+ 0xfc56, 0x40c4,
+ 0xfc57, 0x3d64,
+ 0xfc58, 0x3fbe,
+ 0xfc59, 0x3fa6,
+ 0xfc5a, 0x402c,
+ 0xfc5b, 0x4157,
+ 0xfc5c, 0x3f9f,
+ 0xfc5d, 0x2b40,
+ 0xfc5e, 0x3fa7,
+ 0xfc5f, 0x4005,
+ 0xfc60, 0x4001,
+ 0xfc61, 0x1c9b,
+ 0xfc62, 0x3d84,
+ 0xfc63, 0x0a95,
+ 0xfc64, 0x416c,
+ 0xfc65, 0x4009,
+ 0xfc66, 0x3d75,
+ 0xfc67, 0x3adc,
+ 0xfc68, 0x3fa8,
+ 0xfc69, 0x3f37,
+ 0xfc6a, 0x4174,
+ 0xfc6b, 0x4006,
+ 0xfc6c, 0x4002,
+ 0xfc6d, 0x3fba,
+ 0xfc6e, 0x3fc0,
+ 0xfc6f, 0x12b0,
+ 0xfc70, 0x3fbd,
+ 0xfc71, 0x4173,
+ 0xfc72, 0x4186,
+ 0xfc73, 0x3a54,
+ 0xfc74, 0x3fc5,
+ 0xfc75, 0x4259,
+ 0xfc76, 0x3fc2,
+ 0xfc77, 0x3f15,
+ 0xfc78, 0x3f50,
+ 0xfc79, 0x3f86,
+ 0xfc7a, 0x3fc1,
+ 0xfc7b, 0x418c,
+ 0xfc7c, 0x3fc7,
+ 0xfc7d, 0x3f16,
+ 0xfc7e, 0x418e,
+ 0xfca1, 0x3f4b,
+ 0xfca2, 0x419d,
+ 0xfca3, 0x115f,
+ 0xfca4, 0x3fc4,
+ 0xfca5, 0x3384,
+ 0xfca6, 0x3d99,
+ 0xfca7, 0x41b9,
+ 0xfca8, 0x3a89,
+ 0xfca9, 0x41b7,
+ 0xfcaa, 0x3d8b,
+ 0xfcab, 0x3d66,
+ 0xfcac, 0x03e2,
+ 0xfcad, 0x3d6a,
+ 0xfcae, 0x3d7a,
+ 0xfcaf, 0x41e3,
+ 0xfcb0, 0x0619,
+ 0xfcb1, 0x3996,
+ 0xfcb2, 0x3fc8,
+ 0xfcb3, 0x3a9e,
+ 0xfcb4, 0x3f38,
+ 0xfcb5, 0x3d80,
+ 0xfcb6, 0x41de,
+ 0xfcb8, 0x42eb,
+ 0xfcb9, 0x3d86,
+ 0xfcba, 0x41db,
+ 0xfcbb, 0x3f3e,
+ 0xfcbc, 0x4056,
+ 0xfcbd, 0x41d9,
+ 0xfcbe, 0x3ff6,
+ 0xfcbf, 0x3f5d,
+ 0xfcc0, 0x3d74,
+ 0xfcc1, 0x41e8,
+ 0xfcc2, 0x41c7,
+ 0xfcc3, 0x3d91,
+ 0xfcc4, 0x3b4b,
+ 0xfcc5, 0x3d42,
+ 0xfcc6, 0x3aad,
+ 0xfcc7, 0x3aa5,
+ 0xfcc8, 0x41f2,
+ 0xfcc9, 0x3f4c,
+ 0xfcca, 0x41f8,
+ 0xfccb, 0x3f6e,
+ 0xfccc, 0x3f79,
+ 0xfccd, 0x3f8d,
+ 0xfcce, 0x4003,
+ 0xfccf, 0x3f91,
+ 0xfcd0, 0x3ac3,
+ 0xfcd1, 0x091a,
+ 0xfcd2, 0x4234,
+ 0xfcd3, 0x3ffb,
+ 0xfcd4, 0x4240,
+ 0xfcd6, 0x3ffd,
+ 0xfcd7, 0x3f78,
+ 0xfcd8, 0x3c75,
+ 0xfcd9, 0x3c73,
+ 0xfcda, 0x38a5,
+ 0xfcdb, 0x43f9,
+ 0xfcdc, 0x3cfe,
+ 0xfcdd, 0x4257,
+ 0xfcde, 0x4233,
+ 0xfcdf, 0x3d69,
+ 0xfce0, 0x3c7e,
+ 0xfce1, 0x3d6f,
+ 0xfce2, 0x4000,
+ 0xfce3, 0x3dc0,
+ 0xfce4, 0x4004,
+ 0xfce5, 0x0e72,
+ 0xfce6, 0x3938,
+ 0xfce7, 0x3fa4,
+ 0xfce8, 0x295a,
+ 0xfce9, 0x4273,
+ 0xfcea, 0x3ac9,
+ 0xfceb, 0x427d,
+ 0xfcec, 0x3aca,
+ 0xfced, 0x3fb2,
+ 0xfcee, 0x3fb6,
+ 0xfcef, 0x3f97,
+ 0xfcf0, 0x3f9a,
+ 0xfcf1, 0x428b,
+ 0xfcf2, 0x43fa,
+ 0xfcf3, 0x428a,
+ 0xfcf4, 0x3f51,
+ 0xfcf5, 0x3f98,
+ 0xfcf6, 0x41a3,
+ 0xfcf7, 0x3d5c,
+ 0xfcf8, 0x3f63,
+ 0xfcf9, 0x4290,
+ 0xfcfa, 0x1f94,
+ 0xfcfb, 0x42c6,
+ 0xfcfc, 0x42a2,
+ 0xfcfd, 0x3ffa,
+ 0xfcfe, 0x3f9d,
+ 0xfd40, 0x3ffe,
+ 0xfd41, 0x3f9b,
+ 0xfd42, 0x3fdf,
+ 0xfd43, 0x3fe6,
+ 0xfd44, 0x3fde,
+ 0xfd45, 0x42b7,
+ 0xfd46, 0x3ff4,
+ 0xfd47, 0x42b8,
+ 0xfd48, 0x3feb,
+ 0xfd49, 0x42bf,
+ 0xfd4a, 0x3d71,
+ 0xfd4b, 0x3f4f,
+ 0xfd4c, 0x42c5,
+ 0xfd4d, 0x42d5,
+ 0xfd4e, 0x42d0,
+ 0xfd4f, 0x42d8,
+ 0xfd50, 0x3f55,
+ 0xfd51, 0x3fe8,
+ 0xfd52, 0x3ff3,
+ 0xfd53, 0x42df,
+ 0xfd54, 0x3fd3,
+ 0xfd55, 0x3e73,
+ 0xfd56, 0x3f95,
+ 0xfd57, 0x42ee,
+ 0xfd58, 0x42f4,
+ 0xfd59, 0x3f8c,
+ 0xfd5a, 0x3fcf,
+ 0xfd5b, 0x42ec,
+ 0xfd5c, 0x3fd4,
+ 0xfd5d, 0x42f0,
+ 0xfd5e, 0x07c2,
+ 0xfd5f, 0x0955,
+ 0xfd60, 0x42fe,
+ 0xfd61, 0x4301,
+ 0xfd62, 0x3ccd,
+ 0xfd63, 0x4307,
+ 0xfd64, 0x43fb,
+ 0xfd65, 0x3fda,
+ 0xfd66, 0x3f8b,
+ 0xfd67, 0x3733,
+ 0xfd68, 0x3f8a,
+ 0xfd69, 0x3741,
+ 0xfd6a, 0x3740,
+ 0xfd6b, 0x3742,
+ 0xfd6c, 0x3f93,
+ 0xfd6d, 0x3f8f,
+ 0xfd6e, 0x3e70,
+ 0xfd6f, 0x42c9,
+ 0xfd70, 0x3e72,
+ 0xfd71, 0x3fa9,
+ 0xfd72, 0x42cd,
+ 0xfd73, 0x43d2,
+ 0xfd74, 0x3f8e,
+ 0xfd75, 0x3f77,
+ 0xfd76, 0x3d6e,
+ 0xfd77, 0x0d0a,
+ 0xfd78, 0x3f11,
+ 0xfd79, 0x3752,
+ 0xfd7a, 0x3f14,
+ 0xfd7b, 0x3f18,
+ 0xfd7c, 0x3f53,
+ 0xfd7d, 0x3f1f,
+ 0xfd7e, 0x3f1c,
+ 0xfda1, 0x3fb8,
+ 0xfda2, 0x339d,
+ 0xfda3, 0x3b3f,
+ 0xfda4, 0x3f52,
+ 0xfda5, 0x3f1a,
+ 0xfda6, 0x3f1d,
+ 0xfda7, 0x375c,
+ 0xfda8, 0x3885,
+ 0xfda9, 0x3761,
+ 0xfdaa, 0x3fd7,
+ 0xfdab, 0x3fd6,
+ 0xfdac, 0x3fd9,
+ 0xfdad, 0x3fd8,
+ 0xfdae, 0x3fdd,
+ 0xfdaf, 0x3e93,
+ 0xfdb0, 0x3769,
+ 0xfdb1, 0x376e,
+ 0xfdb2, 0x3b4c,
+ 0xfdb3, 0x3774,
+ 0xfdb4, 0x377f,
+ 0xfdb5, 0x377b,
+ 0xfdb6, 0x3782,
+ 0xfdb7, 0x3b4f,
+ 0xfdb8, 0x3792,
+ 0xfdb9, 0x3fe3,
+ 0xfdba, 0x3fdc,
+ 0xfdbb, 0x3fdb,
+ 0xfdbc, 0x3fe5,
+ 0xfdbd, 0x3b75,
+ 0xfdbe, 0x37a2,
+ 0xfdbf, 0x3fe2,
+ 0xfdc0, 0x3fe7,
+ 0xfdc1, 0x3e6d,
+ 0xfdc2, 0x0d2a,
+ 0xfdc3, 0x3e79,
+ 0xfdc4, 0x3e76,
+ 0xfdc5, 0x379f,
+ 0xfdc6, 0x3fee,
+ 0xfdc7, 0x42d4,
+ 0xfdc8, 0x3d94,
+ 0xfdc9, 0x3d61,
+ 0xfdca, 0x3fe1,
+ 0xfdcb, 0x375e,
+ 0xfdcc, 0x3b7a,
+ 0xfdcd, 0x380b,
+ 0xfdce, 0x3fec,
+ 0xfdcf, 0x3fef,
+ 0xfdd0, 0x2e45,
+ 0xfdd1, 0x3ffc,
+ 0xfdd2, 0x3fed,
+ 0xfdd3, 0x380d,
+ 0xfdd4, 0x3fe4,
+ 0xfdd5, 0x3f92,
+ 0xfdd6, 0x3fae,
+ 0xfdd7, 0x3811,
+ 0xfdd8, 0x3f7a,
+ 0xfdd9, 0x3b8b,
+ 0xfdda, 0x3f5a,
+ 0xfddb, 0x3816,
+ 0xfddc, 0x3fa2,
+ 0xfddd, 0x3b8e,
+ 0xfdde, 0x381c,
+ 0xfddf, 0x2054,
+ 0xfde0, 0x381f,
+ 0xfde1, 0x3fa0,
+ 0xfde2, 0x43fc,
+ 0xfde3, 0x3e16,
+ 0xfde4, 0x3b94,
+ 0xfde5, 0x3f7c,
+ 0xfde6, 0x4007,
+ 0xfde7, 0x3f7b,
+ 0xfde8, 0x3d73,
+ 0xfde9, 0x3e77,
+ 0xfdea, 0x3d92,
+ 0xfdeb, 0x3fa1,
+ 0xfdec, 0x37c1,
+ 0xfded, 0x37d3,
+ 0xfdee, 0x3e7a,
+ 0xfdef, 0x3f59,
+ 0xfdf0, 0x3c55,
+ 0xfdf1, 0x3ff8,
+ 0xfdf2, 0x3ff5,
+ 0xfdf3, 0x3c4c,
+ 0xfdf4, 0x3d8c,
+ 0xfdf5, 0x3fa3,
+ 0xfdf6, 0x37c0,
+ 0xfdf7, 0x3f54,
+ 0xfdf8, 0x3800,
+ 0xfdf9, 0x3b7f,
+ 0xfdfa, 0x3f9e,
+ 0xfdfb, 0x3822,
+ 0xfdfc, 0x3fe9,
+ 0xfdfd, 0x3823,
+ 0xfdfe, 0x3fe0,
+ 0xfe40, 0x3d93,
+ 0xfe41, 0x3ff9,
+ 0xfe42, 0x3827,
+ 0xfe43, 0x3fa5,
+ 0xfe44, 0x3ff0,
+ 0xfe45, 0x3836,
+ 0xfe46, 0x3f99,
+ 0xfe47, 0x3ff2,
+ 0xfe48, 0x3d8d,
+ 0xfe49, 0x43e6,
+ 0xfe4a, 0x3522,
+ 0xfe4b, 0x3ff1,
+ 0xfe4c, 0x3f9c,
+ 0xfe4d, 0x3fb1,
+ 0xfe4e, 0x3f96,
+ 0xfe4f, 0x3e6f,
+ 0xfe50, 0x3f69,
+ 0xfe51, 0x3ff7,
+ 0xfe52, 0x3f82,
+ 0xfe53, 0x3f88,
+ 0xfe54, 0x3f85,
+ 0xfe55, 0x3f83,
+ 0xfe56, 0x3f7f,
+ 0xfe57, 0x3f89,
+ 0xfe58, 0x3bb5,
+ 0xfe59, 0x3862,
+ 0xfe5a, 0x3f87,
+ 0xfe5b, 0x3f31,
+ 0xfe5c, 0x3815,
+ 0xfe5d, 0x387e,
+ 0xfe5e, 0x3f49,
+ 0xfe5f, 0x3f48,
+ 0xfe60, 0x3f47,
+ 0xfe61, 0x3f45,
+ 0xfe62, 0x43eb,
+ 0xfe63, 0x3882,
+ 0xfe64, 0x3f6f,
+ 0xfe65, 0x3f4e,
+ 0xfe66, 0x3bc8,
+ 0xfe67, 0x43fd,
+ 0xfe68, 0x3d6b,
+ 0xfe6a, 0x43fe,
+ 0xfe6b, 0x3fcb,
+ 0xfe6c, 0x3dd2,
+ 0xfe6d, 0x3879,
+ 0xfe6e, 0x3f10,
+ 0xfe6f, 0x382e,
+ 0xfe70, 0x388b,
+ 0xfe71, 0x3c60,
+ 0xfe72, 0x2a9f,
+ 0xfe73, 0x3c61,
+ 0xfe74, 0x3893,
+ 0xfe75, 0x3e74,
+ 0xfe76, 0x3fac,
+ 0xfe77, 0x3f81,
+ 0xfe78, 0x3bcd,
+ 0xfe79, 0x3bd4,
+ 0xfe7a, 0x3bd3,
+ 0xfe7b, 0x3fcc,
+ 0xfe7c, 0x3fd1,
+ 0xfe7d, 0x3f3d,
+ 0xfe7e, 0x3f4a,
+ 0xfea1, 0x2352,
+ 0xfea2, 0x38ad,
+ 0xfea3, 0x3f46,
+ 0xfea4, 0x38b5,
+ 0xfea5, 0x3f0d,
+ 0xfea6, 0x3fb3,
+ 0xfea7, 0x38c0,
+ 0xfea8, 0x3e2f,
+ 0xfea9, 0x38cf,
+ 0xfeaa, 0x38d5,
+ 0xfeab, 0x3f33,
+ 0xfeac, 0x3d95,
+ 0xfead, 0x3f35,
+ 0xfeae, 0x38d7,
+ 0xfeaf, 0x3f2f,
+ 0xfeb0, 0x38e0,
+ 0xfeb1, 0x3c02,
+ 0xfeb2, 0x3f72,
+ 0xfeb3, 0x3f70,
+ 0xfeb4, 0x3d96,
+ 0xfeb5, 0x38e6,
+ 0xfeb7, 0x4035,
+ 0xfeb8, 0x3f73,
+ 0xfeb9, 0x38f0,
+ 0xfeba, 0x3c0b,
+ 0xfebb, 0x38f7,
+ 0xfebc, 0x37aa,
+ 0xfebd, 0x43ff,
+ 0xfebe, 0x38fa,
+ 0xfebf, 0x3c11,
+ 0xfec0, 0x3f34,
+ 0xfec1, 0x3fb9,
+ 0xfec2, 0x3c12,
+ 0xfec3, 0x400a,
+ 0xfec4, 0x3d77,
+ 0xfec5, 0x3f42,
+ 0xfec6, 0x3900,
+ 0xfec7, 0x3902,
+ 0xfec8, 0x3f74,
+ 0xfec9, 0x3d97,
+ 0xfeca, 0x3faa,
+ 0xfecb, 0x3f19,
+ 0xfecc, 0x3f1b,
+ 0xfecd, 0x390e,
+ 0xfece, 0x3909,
+ 0xfecf, 0x390b,
+ 0xfed0, 0x3f12,
+ 0xfed1, 0x3f17,
+ 0xfed2, 0x3fb7,
+ 0xfed3, 0x3f20,
+ 0xfed4, 0x3fbb,
+ 0xfed5, 0x3f3c,
+ 0xfed6, 0x3fad,
+ 0xfed7, 0x3919,
+ 0xfed8, 0x3f56,
+ 0xfed9, 0x3f71,
+ 0xfeda, 0x3fb4,
+ 0xfedb, 0x391c,
+ 0xfedc, 0x3f1e,
+ 0xfedd, 0x3f3a,
+ 0xfede, 0x391b,
+ 0xfedf, 0x3d87,
+ 0xfee0, 0x3c3a,
+ 0xfee1, 0x3f22,
+ 0xfee2, 0x3e71,
+ 0xfee3, 0x3c39,
+ 0xfee4, 0x3d7e,
+ 0xfee5, 0x4124,
+ 0xfee6, 0x3f3b,
+ 0xfee7, 0x3e6e,
+ 0xfee8, 0x3fab,
+ 0xfee9, 0x3925,
+ 0xfeea, 0x3f30,
+ 0xfeeb, 0x3929,
+ 0xfeec, 0x3f84,
+ 0xfeed, 0x3f0f,
+ 0xfeee, 0x3f76,
+ 0xfeef, 0x3f94,
+ 0xfef0, 0x3932,
+ 0xfef1, 0x3f27,
+ 0xfef2, 0x3933,
+ 0xfef3, 0x3f75,
+ 0xfef4, 0x3937,
+ 0xfef5, 0x3d78,
+ 0xfef6, 0x3f21,
+ 0xfef7, 0x3f90,
+ 0xfef8, 0x3940,
+ 0xfef9, 0x3d7f,
+ 0xfefa, 0x394a,
+ 0xfefb, 0x3f80,
+ 0xfefc, 0x3f23,
+ 0xfefd, 0x3950,
+ 0xfefe, 0x3f7e,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 cns13HKdlaB5HEnc16 = {
+ 0,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
+ 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010,
+ 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018,
+ 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020,
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028,
+ 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030,
+ 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038,
+ 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040,
+ 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048,
+ 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050,
+ 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
+ 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ cns13HKdlaB5HMap2, 1023
+};
+
+static Gushort cns13HKdlaB5VMap2[2070] = {
+ 0x0000, 0x0000,
+ 0xa140, 0x0063,
+ 0xa159, 0x35af,
+ 0xa15d, 0x0080,
+ 0xa1a1, 0x00a2,
+ 0xa1f6, 0x00f8,
+ 0xa1f7, 0x00f7,
+ 0xa1f8, 0x00f9,
+ 0xa240, 0x0100,
+ 0xa2a1, 0x013f,
+ 0xa340, 0x019d,
+ 0xa3a1, 0x01dc,
+ 0xa3bd, 0x01f7,
+ 0xa440, 0x0253,
+ 0xa4a1, 0x0292,
+ 0xa540, 0x02f0,
+ 0xa5a1, 0x032f,
+ 0xa640, 0x038d,
+ 0xa6a1, 0x03cc,
+ 0xa740, 0x042a,
+ 0xa7a1, 0x0469,
+ 0xa840, 0x04c7,
+ 0xa8a1, 0x0506,
+ 0xa940, 0x0564,
+ 0xa9a1, 0x05a3,
+ 0xaa40, 0x0601,
+ 0xaaa1, 0x0640,
+ 0xab40, 0x069e,
+ 0xaba1, 0x06dd,
+ 0xac40, 0x073b,
+ 0xaca1, 0x077a,
+ 0xacfe, 0x097f,
+ 0xad40, 0x07d7,
+ 0xada1, 0x0816,
+ 0xae40, 0x0874,
+ 0xaea1, 0x08b3,
+ 0xaf40, 0x0911,
+ 0xafa1, 0x0950,
+ 0xafd0, 0x0980,
+ 0xb040, 0x09af,
+ 0xb0a1, 0x09ee,
+ 0xb140, 0x0a4c,
+ 0xb1a1, 0x0a8b,
+ 0xb240, 0x0ae9,
+ 0xb2a1, 0x0b28,
+ 0xb340, 0x0b86,
+ 0xb3a1, 0x0bc5,
+ 0xb440, 0x0c23,
+ 0xb4a1, 0x0c62,
+ 0xb540, 0x0cc0,
+ 0xb5a1, 0x0cff,
+ 0xb640, 0x0d5d,
+ 0xb6a1, 0x0d9c,
+ 0xb740, 0x0dfa,
+ 0xb7a1, 0x0e39,
+ 0xb840, 0x0e97,
+ 0xb8a1, 0x0ed6,
+ 0xb940, 0x0f34,
+ 0xb9a1, 0x0f73,
+ 0xba40, 0x0fd1,
+ 0xbaa1, 0x1010,
+ 0xbb40, 0x106e,
+ 0xbba1, 0x10ad,
+ 0xbbc8, 0x10d5,
+ 0xbc40, 0x110c,
+ 0xbca1, 0x114b,
+ 0xbd40, 0x11a9,
+ 0xbda1, 0x11e8,
+ 0xbe40, 0x1246,
+ 0xbe52, 0x10d4,
+ 0xbe53, 0x1258,
+ 0xbea1, 0x1284,
+ 0xbf40, 0x12e2,
+ 0xbfa1, 0x1321,
+ 0xc040, 0x137f,
+ 0xc0a1, 0x13be,
+ 0xc140, 0x141c,
+ 0xc1a1, 0x145b,
+ 0xc1ab, 0x1466,
+ 0xc240, 0x14ba,
+ 0xc2a1, 0x14f9,
+ 0xc2cb, 0x1465,
+ 0xc2cc, 0x1523,
+ 0xc340, 0x1556,
+ 0xc361, 0x1578,
+ 0xc3a1, 0x1596,
+ 0xc3b9, 0x15af,
+ 0xc3ba, 0x15ae,
+ 0xc3bb, 0x15b0,
+ 0xc440, 0x15f4,
+ 0xc456, 0x1577,
+ 0xc457, 0x160a,
+ 0xc4a1, 0x1632,
+ 0xc540, 0x1690,
+ 0xc5a1, 0x16cf,
+ 0xc640, 0x172d,
+ 0xc940, 0x176c,
+ 0xc94a, 0x0274,
+ 0xc94b, 0x1776,
+ 0xc96c, 0x1798,
+ 0xc9a1, 0x17ab,
+ 0xc9be, 0x1797,
+ 0xc9bf, 0x17c8,
+ 0xc9ed, 0x17f7,
+ 0xca40, 0x1809,
+ 0xcaa1, 0x1848,
+ 0xcaf7, 0x17f6,
+ 0xcaf8, 0x189e,
+ 0xcb40, 0x18a5,
+ 0xcba1, 0x18e4,
+ 0xcc40, 0x1942,
+ 0xcca1, 0x1981,
+ 0xcd40, 0x19df,
+ 0xcda1, 0x1a1e,
+ 0xce40, 0x1a7c,
+ 0xcea1, 0x1abb,
+ 0xcf40, 0x1b19,
+ 0xcfa1, 0x1b58,
+ 0xd040, 0x1bb6,
+ 0xd0a1, 0x1bf5,
+ 0xd140, 0x1c53,
+ 0xd1a1, 0x1c92,
+ 0xd240, 0x1cf0,
+ 0xd2a1, 0x1d2f,
+ 0xd340, 0x1d8d,
+ 0xd3a1, 0x1dcc,
+ 0xd440, 0x1e2a,
+ 0xd4a1, 0x1e69,
+ 0xd540, 0x1ec7,
+ 0xd5a1, 0x1f06,
+ 0xd640, 0x1f64,
+ 0xd6a1, 0x1fa3,
+ 0xd6cc, 0x2254,
+ 0xd6cd, 0x1fcf,
+ 0xd740, 0x2001,
+ 0xd77a, 0x22b9,
+ 0xd77b, 0x203b,
+ 0xd7a1, 0x203f,
+ 0xd840, 0x209d,
+ 0xd8a1, 0x20dc,
+ 0xd940, 0x213a,
+ 0xd9a1, 0x2179,
+ 0xda40, 0x21d7,
+ 0xdaa1, 0x2216,
+ 0xdadf, 0x1fce,
+ 0xdae0, 0x2255,
+ 0xdb40, 0x2274,
+ 0xdba1, 0x22b3,
+ 0xdba7, 0x22ba,
+ 0xdc40, 0x2312,
+ 0xdca1, 0x2351,
+ 0xdd40, 0x23af,
+ 0xdda1, 0x23ee,
+ 0xddfc, 0x2381,
+ 0xddfd, 0x2449,
+ 0xde40, 0x244b,
+ 0xdea1, 0x248a,
+ 0xdf40, 0x24e8,
+ 0xdfa1, 0x2527,
+ 0xe040, 0x2585,
+ 0xe0a1, 0x25c4,
+ 0xe140, 0x2622,
+ 0xe1a1, 0x2661,
+ 0xe240, 0x26bf,
+ 0xe2a1, 0x26fe,
+ 0xe340, 0x275c,
+ 0xe3a1, 0x279b,
+ 0xe440, 0x27f9,
+ 0xe4a1, 0x2838,
+ 0xe540, 0x2896,
+ 0xe5a1, 0x28d5,
+ 0xe640, 0x2933,
+ 0xe6a1, 0x2972,
+ 0xe740, 0x29d0,
+ 0xe7a1, 0x2a0f,
+ 0xe840, 0x2a6d,
+ 0xe8a1, 0x2aac,
+ 0xe8a3, 0x2aaf,
+ 0xe940, 0x2b0b,
+ 0xe976, 0x2b42,
+ 0xe9a1, 0x2b4b,
+ 0xea40, 0x2ba9,
+ 0xeaa1, 0x2be8,
+ 0xeb40, 0x2c46,
+ 0xeb5b, 0x2c62,
+ 0xeba1, 0x2c86,
+ 0xebf1, 0x2aae,
+ 0xebf2, 0x2cd6,
+ 0xec40, 0x2ce3,
+ 0xeca1, 0x2d22,
+ 0xecde, 0x2b41,
+ 0xecdf, 0x2d5f,
+ 0xed40, 0x2d7f,
+ 0xeda1, 0x2dbe,
+ 0xedaa, 0x2dc8,
+ 0xee40, 0x2e1d,
+ 0xeea1, 0x2e5c,
+ 0xeeeb, 0x3014,
+ 0xeeec, 0x2ea6,
+ 0xef40, 0x2eb9,
+ 0xefa1, 0x2ef8,
+ 0xf040, 0x2f56,
+ 0xf056, 0x2dc7,
+ 0xf057, 0x2f6c,
+ 0xf0a1, 0x2f94,
+ 0xf0cb, 0x2c61,
+ 0xf0cc, 0x2fbe,
+ 0xf140, 0x2ff1,
+ 0xf163, 0x3015,
+ 0xf16b, 0x3160,
+ 0xf16c, 0x301d,
+ 0xf1a1, 0x3030,
+ 0xf240, 0x308e,
+ 0xf268, 0x31ef,
+ 0xf269, 0x30b6,
+ 0xf2a1, 0x30cc,
+ 0xf2c3, 0x30ef,
+ 0xf340, 0x312b,
+ 0xf375, 0x3161,
+ 0xf3a1, 0x316b,
+ 0xf440, 0x31c9,
+ 0xf466, 0x31f0,
+ 0xf4a1, 0x3209,
+ 0xf4b5, 0x30ee,
+ 0xf4b6, 0x321d,
+ 0xf4fd, 0x3265,
+ 0xf540, 0x3267,
+ 0xf5a1, 0x32a6,
+ 0xf640, 0x3304,
+ 0xf663, 0x3264,
+ 0xf664, 0x3327,
+ 0xf6a1, 0x3342,
+ 0xf740, 0x33a0,
+ 0xf7a1, 0x33df,
+ 0xf840, 0x343d,
+ 0xf8a1, 0x347c,
+ 0xf940, 0x34da,
+ 0xf977, 0x3512,
+ 0xf9a1, 0x351a,
+ 0xf9c4, 0x3511,
+ 0xf9c5, 0x353d,
+ 0xf9c6, 0x3549,
+ 0xf9c7, 0x353e,
+ 0xf9d2, 0x354a,
+ 0xfa41, 0x4149,
+ 0xfa42, 0x3ea3,
+ 0xfa43, 0x3e84,
+ 0xfa44, 0x3e87,
+ 0xfa45, 0x3e05,
+ 0xfa46, 0x4096,
+ 0xfa47, 0x39c4,
+ 0xfa48, 0x3d6d,
+ 0xfa49, 0x3e7f,
+ 0xfa4a, 0x3c77,
+ 0xfa4b, 0x3e86,
+ 0xfa4c, 0x387c,
+ 0xfa4d, 0x3ea7,
+ 0xfa4e, 0x420e,
+ 0xfa4f, 0x3ea4,
+ 0xfa50, 0x418a,
+ 0xfa51, 0x405f,
+ 0xfa52, 0x4116,
+ 0xfa53, 0x408b,
+ 0xfa54, 0x3e66,
+ 0xfa55, 0x3e65,
+ 0xfa56, 0x3d8f,
+ 0xfa57, 0x419e,
+ 0xfa58, 0x3a66,
+ 0xfa59, 0x4161,
+ 0xfa5a, 0x3e8a,
+ 0xfa5b, 0x3d8e,
+ 0xfa5c, 0x3e8d,
+ 0xfa5d, 0x3dbc,
+ 0xfa5e, 0x3e95,
+ 0xfa5f, 0x39a3,
+ 0xfa60, 0x41f4,
+ 0xfa61, 0x3e91,
+ 0xfa62, 0x3bc6,
+ 0xfa63, 0x3dc3,
+ 0xfa64, 0x3eae,
+ 0xfa65, 0x3746,
+ 0xfa66, 0x3871,
+ 0xfa67, 0x3a00,
+ 0xfa68, 0x428c,
+ 0xfa69, 0x425b,
+ 0xfa6a, 0x3ead,
+ 0xfa6b, 0x4123,
+ 0xfa6c, 0x3ea6,
+ 0xfa6d, 0x3ea0,
+ 0xfa6e, 0x3b2e,
+ 0xfa6f, 0x3dbd,
+ 0xfa70, 0x3864,
+ 0xfa71, 0x3c7d,
+ 0xfa72, 0x3ea9,
+ 0xfa73, 0x420d,
+ 0xfa74, 0x3f58,
+ 0xfa75, 0x3e98,
+ 0xfa76, 0x3d70,
+ 0xfa77, 0x3ea8,
+ 0xfa78, 0x3e94,
+ 0xfa79, 0x3e9d,
+ 0xfa7a, 0x3aaa,
+ 0xfa7b, 0x3ea5,
+ 0xfa7c, 0x3ccc,
+ 0xfa7d, 0x4098,
+ 0xfa7e, 0x3e9f,
+ 0xfaa1, 0x41f5,
+ 0xfaa2, 0x3e8b,
+ 0xfaa3, 0x3b72,
+ 0xfaa4, 0x37e0,
+ 0xfaa5, 0x3adf,
+ 0xfaa6, 0x42e0,
+ 0xfaa7, 0x3e97,
+ 0xfaa8, 0x4192,
+ 0xfaa9, 0x3888,
+ 0xfaaa, 0x42c8,
+ 0xfaab, 0x3e90,
+ 0xfaac, 0x386f,
+ 0xfaad, 0x3e9c,
+ 0xfaae, 0x4144,
+ 0xfaaf, 0x4146,
+ 0xfab0, 0x3e9e,
+ 0xfab1, 0x3e89,
+ 0xfab2, 0x4093,
+ 0xfab3, 0x3e81,
+ 0xfab5, 0x3c0e,
+ 0xfab6, 0x3e85,
+ 0xfab7, 0x38dc,
+ 0xfab8, 0x4069,
+ 0xfab9, 0x37d8,
+ 0xfaba, 0x3e99,
+ 0xfabb, 0x3e83,
+ 0xfabc, 0x3e88,
+ 0xfabd, 0x3e80,
+ 0xfabe, 0x3eb1,
+ 0xfabf, 0x416a,
+ 0xfac0, 0x376b,
+ 0xfac1, 0x3e67,
+ 0xfac2, 0x3e78,
+ 0xfac3, 0x4262,
+ 0xfac4, 0x37f5,
+ 0xfac5, 0x37f4,
+ 0xfac6, 0x3b45,
+ 0xfac7, 0x3e59,
+ 0xfac8, 0x2abc,
+ 0xfac9, 0x3dbf,
+ 0xfaca, 0x40bd,
+ 0xfacb, 0x3e7e,
+ 0xfacc, 0x382d,
+ 0xfacd, 0x3eb0,
+ 0xface, 0x3eab,
+ 0xfacf, 0x3eb2,
+ 0xfad0, 0x4221,
+ 0xfad1, 0x3f6a,
+ 0xfad2, 0x381b,
+ 0xfad3, 0x3e9a,
+ 0xfad4, 0x4223,
+ 0xfad5, 0x3e8e,
+ 0xfad6, 0x3bfd,
+ 0xfad7, 0x405a,
+ 0xfad8, 0x3eaf,
+ 0xfad9, 0x3cc8,
+ 0xfada, 0x3948,
+ 0xfadb, 0x42bd,
+ 0xfadc, 0x40cc,
+ 0xfadd, 0x3e5c,
+ 0xfade, 0x3eac,
+ 0xfadf, 0x391a,
+ 0xfae0, 0x3eaa,
+ 0xfae1, 0x4399,
+ 0xfae2, 0x389a,
+ 0xfae3, 0x3e8c,
+ 0xfae4, 0x389f,
+ 0xfae5, 0x3ea1,
+ 0xfae6, 0x4187,
+ 0xfae7, 0x3e8f,
+ 0xfae8, 0x3fc3,
+ 0xfae9, 0x3ea2,
+ 0xfaea, 0x3e9b,
+ 0xfaeb, 0x3e7d,
+ 0xfaec, 0x4051,
+ 0xfaed, 0x3fbc,
+ 0xfaee, 0x3fd5,
+ 0xfaef, 0x3b14,
+ 0xfaf0, 0x4222,
+ 0xfaf1, 0x379b,
+ 0xfaf2, 0x407b,
+ 0xfaf3, 0x3788,
+ 0xfaf4, 0x3bb4,
+ 0xfaf5, 0x41d0,
+ 0xfaf6, 0x4264,
+ 0xfaf7, 0x385e,
+ 0xfaf8, 0x376c,
+ 0xfaf9, 0x3dbe,
+ 0xfafa, 0x3813,
+ 0xfafb, 0x3fff,
+ 0xfafc, 0x3d63,
+ 0xfafd, 0x3786,
+ 0xfafe, 0x3b4a,
+ 0xfb40, 0x373a,
+ 0xfb41, 0x427a,
+ 0xfb42, 0x3c7a,
+ 0xfb43, 0x4205,
+ 0xfb44, 0x3c26,
+ 0xfb45, 0x38af,
+ 0xfb46, 0x3936,
+ 0xfb47, 0x37a8,
+ 0xfb48, 0x3b74,
+ 0xfb49, 0x3f6d,
+ 0xfb4a, 0x3e96,
+ 0xfb4b, 0x37bc,
+ 0xfb4c, 0x3e7b,
+ 0xfb4d, 0x3fea,
+ 0xfb4e, 0x41ca,
+ 0xfb4f, 0x39d7,
+ 0xfb50, 0x40d1,
+ 0xfb51, 0x3b71,
+ 0xfb52, 0x3fcf,
+ 0xfb53, 0x07c2,
+ 0xfb54, 0x42fe,
+ 0xfb55, 0x3ccd,
+ 0xfb56, 0x3e70,
+ 0xfb57, 0x3e72,
+ 0xfb58, 0x374c,
+ 0xfb59, 0x3769,
+ 0xfb5a, 0x3b4f,
+ 0xfb5b, 0x379f,
+ 0xfb5c, 0x2e45,
+ 0xfb5d, 0x380d,
+ 0xfb5e, 0x3fa2,
+ 0xfb5f, 0x381c,
+ 0xfb60, 0x3f7c,
+ 0xfb61, 0x3f59,
+ 0xfb62, 0x3f9e,
+ 0xfb63, 0x3d93,
+ 0xfb64, 0x3815,
+ 0xfb65, 0x388b,
+ 0xfb66, 0x3c60,
+ 0xfb67, 0x38f0,
+ 0xfb68, 0x37aa,
+ 0xfb69, 0x3f34,
+ 0xfb6a, 0x3c12,
+ 0xfb6b, 0x3900,
+ 0xfb6c, 0x3faa,
+ 0xfb6d, 0x390b,
+ 0xfb6e, 0x3929,
+ 0xfb6f, 0x3f27,
+ 0xfb70, 0x3f90,
+ 0xfb71, 0x3f57,
+ 0xfb72, 0x3f5b,
+ 0xfb73, 0x3f62,
+ 0xfb74, 0x3d76,
+ 0xfb75, 0x39c8,
+ 0xfb76, 0x3f64,
+ 0xfb78, 0x393d,
+ 0xfb79, 0x3c66,
+ 0xfb7a, 0x39d0,
+ 0xfb7b, 0x4022,
+ 0xfb7c, 0x3f2c,
+ 0xfb7d, 0x3f28,
+ 0xfb7e, 0x39cc,
+ 0xfba1, 0x3f26,
+ 0xfba2, 0x39cd,
+ 0xfba3, 0x3f3f,
+ 0xfba4, 0x39c5,
+ 0xfba5, 0x3fce,
+ 0xfba6, 0x4034,
+ 0xfba7, 0x3f5e,
+ 0xfba8, 0x4032,
+ 0xfba9, 0x4054,
+ 0xfbaa, 0x4178,
+ 0xfbab, 0x3f60,
+ 0xfbac, 0x3f29,
+ 0xfbad, 0x405d,
+ 0xfbae, 0x3f43,
+ 0xfbaf, 0x3f68,
+ 0xfbb0, 0x4060,
+ 0xfbb1, 0x3f2a,
+ 0xfbb2, 0x4063,
+ 0xfbb3, 0x39e7,
+ 0xfbb4, 0x38b6,
+ 0xfbb5, 0x4090,
+ 0xfbb6, 0x4048,
+ 0xfbb7, 0x4012,
+ 0xfbb8, 0x3d7c,
+ 0xfbb9, 0x404b,
+ 0xfbba, 0x404d,
+ 0xfbbb, 0x404f,
+ 0xfbbc, 0x424f,
+ 0xfbbd, 0x3d79,
+ 0xfbbe, 0x3f40,
+ 0xfbbf, 0x3f0a,
+ 0xfbc0, 0x3fd0,
+ 0xfbc1, 0x3f36,
+ 0xfbc2, 0x406d,
+ 0xfbc3, 0x4085,
+ 0xfbc4, 0x4084,
+ 0xfbc5, 0x413e,
+ 0xfbc6, 0x413b,
+ 0xfbc7, 0x3fc6,
+ 0xfbc8, 0x4086,
+ 0xfbc9, 0x3952,
+ 0xfbca, 0x40a1,
+ 0xfbcb, 0x3f32,
+ 0xfbcc, 0x4203,
+ 0xfbcd, 0x3f66,
+ 0xfbce, 0x3d83,
+ 0xfbcf, 0x3e75,
+ 0xfbd0, 0x40a2,
+ 0xfbd1, 0x0570,
+ 0xfbd2, 0x3f39,
+ 0xfbd3, 0x0871,
+ 0xfbd4, 0x3f24,
+ 0xfbd5, 0x40ae,
+ 0xfbd6, 0x3f44,
+ 0xfbd7, 0x38f5,
+ 0xfbd8, 0x3fc9,
+ 0xfbd9, 0x3fcd,
+ 0xfbda, 0x3fb5,
+ 0xfbdb, 0x3e7c,
+ 0xfbdc, 0x3fd2,
+ 0xfbdd, 0x3f4d,
+ 0xfbde, 0x40bc,
+ 0xfbdf, 0x40b7,
+ 0xfbe0, 0x3858,
+ 0xfbe1, 0x43af,
+ 0xfbe2, 0x3f6c,
+ 0xfbe3, 0x3d85,
+ 0xfbe4, 0x4396,
+ 0xfbe5, 0x39a6,
+ 0xfbe6, 0x3f7d,
+ 0xfbe7, 0x3fbf,
+ 0xfbe8, 0x40c8,
+ 0xfbe9, 0x3f5f,
+ 0xfbea, 0x3f2b,
+ 0xfbeb, 0x3d72,
+ 0xfbec, 0x40cf,
+ 0xfbed, 0x3a05,
+ 0xfbee, 0x3d82,
+ 0xfbef, 0x40dc,
+ 0xfbf0, 0x3d65,
+ 0xfbf1, 0x40d4,
+ 0xfbf2, 0x40da,
+ 0xfbf3, 0x3f2d,
+ 0xfbf4, 0x0595,
+ 0xfbf5, 0x3d81,
+ 0xfbf6, 0x40f1,
+ 0xfbf7, 0x06f5,
+ 0xfbf8, 0x40f8,
+ 0xfbf9, 0x40fb,
+ 0xfbfa, 0x3f41,
+ 0xfbfb, 0x4118,
+ 0xfbfc, 0x3d89,
+ 0xfbfd, 0x3f5c,
+ 0xfbfe, 0x3d67,
+ 0xfc40, 0x3f0e,
+ 0xfc41, 0x3f13,
+ 0xfc42, 0x4122,
+ 0xfc43, 0x3fca,
+ 0xfc44, 0x4129,
+ 0xfc45, 0x3f0c,
+ 0xfc46, 0x3f0b,
+ 0xfc47, 0x3f61,
+ 0xfc48, 0x3d8a,
+ 0xfc49, 0x3f2e,
+ 0xfc4a, 0x1971,
+ 0xfc4b, 0x4135,
+ 0xfc4c, 0x3a2b,
+ 0xfc4d, 0x3f6b,
+ 0xfc4e, 0x3ba5,
+ 0xfc4f, 0x4044,
+ 0xfc50, 0x4255,
+ 0xfc51, 0x3737,
+ 0xfc52, 0x3f25,
+ 0xfc53, 0x3739,
+ 0xfc54, 0x3a30,
+ 0xfc55, 0x4143,
+ 0xfc56, 0x40c4,
+ 0xfc57, 0x3d64,
+ 0xfc58, 0x3fbe,
+ 0xfc59, 0x3fa6,
+ 0xfc5a, 0x402c,
+ 0xfc5b, 0x4157,
+ 0xfc5c, 0x3f9f,
+ 0xfc5d, 0x2b40,
+ 0xfc5e, 0x3fa7,
+ 0xfc5f, 0x4005,
+ 0xfc60, 0x4001,
+ 0xfc61, 0x1c9b,
+ 0xfc62, 0x3d84,
+ 0xfc63, 0x0a95,
+ 0xfc64, 0x416c,
+ 0xfc65, 0x4009,
+ 0xfc66, 0x3d75,
+ 0xfc67, 0x3adc,
+ 0xfc68, 0x3fa8,
+ 0xfc69, 0x3f37,
+ 0xfc6a, 0x4174,
+ 0xfc6b, 0x4006,
+ 0xfc6c, 0x4002,
+ 0xfc6d, 0x3fba,
+ 0xfc6e, 0x3fc0,
+ 0xfc6f, 0x12b0,
+ 0xfc70, 0x3fbd,
+ 0xfc71, 0x4173,
+ 0xfc72, 0x4186,
+ 0xfc73, 0x3a54,
+ 0xfc74, 0x3fc5,
+ 0xfc75, 0x4259,
+ 0xfc76, 0x3fc2,
+ 0xfc77, 0x3f15,
+ 0xfc78, 0x3f50,
+ 0xfc79, 0x3f86,
+ 0xfc7a, 0x3fc1,
+ 0xfc7b, 0x418c,
+ 0xfc7c, 0x3fc7,
+ 0xfc7d, 0x3f16,
+ 0xfc7e, 0x418e,
+ 0xfca1, 0x3f4b,
+ 0xfca2, 0x419d,
+ 0xfca3, 0x115f,
+ 0xfca4, 0x3fc4,
+ 0xfca5, 0x3384,
+ 0xfca6, 0x3d99,
+ 0xfca7, 0x41b9,
+ 0xfca8, 0x3a89,
+ 0xfca9, 0x41b7,
+ 0xfcaa, 0x3d8b,
+ 0xfcab, 0x3d66,
+ 0xfcac, 0x03e2,
+ 0xfcad, 0x3d6a,
+ 0xfcae, 0x3d7a,
+ 0xfcaf, 0x41e3,
+ 0xfcb0, 0x0619,
+ 0xfcb1, 0x3996,
+ 0xfcb2, 0x3fc8,
+ 0xfcb3, 0x3a9e,
+ 0xfcb4, 0x3f38,
+ 0xfcb5, 0x3d80,
+ 0xfcb6, 0x41de,
+ 0xfcb8, 0x42eb,
+ 0xfcb9, 0x3d86,
+ 0xfcba, 0x41db,
+ 0xfcbb, 0x3f3e,
+ 0xfcbc, 0x4056,
+ 0xfcbd, 0x41d9,
+ 0xfcbe, 0x3ff6,
+ 0xfcbf, 0x3f5d,
+ 0xfcc0, 0x3d74,
+ 0xfcc1, 0x41e8,
+ 0xfcc2, 0x41c7,
+ 0xfcc3, 0x3d91,
+ 0xfcc4, 0x3b4b,
+ 0xfcc5, 0x3d42,
+ 0xfcc6, 0x3aad,
+ 0xfcc7, 0x3aa5,
+ 0xfcc8, 0x41f2,
+ 0xfcc9, 0x3f4c,
+ 0xfcca, 0x41f8,
+ 0xfccb, 0x3f6e,
+ 0xfccc, 0x3f79,
+ 0xfccd, 0x3f8d,
+ 0xfcce, 0x4003,
+ 0xfccf, 0x3f91,
+ 0xfcd0, 0x3ac3,
+ 0xfcd1, 0x091a,
+ 0xfcd2, 0x4234,
+ 0xfcd3, 0x3ffb,
+ 0xfcd4, 0x4240,
+ 0xfcd6, 0x3ffd,
+ 0xfcd7, 0x3f78,
+ 0xfcd8, 0x3c75,
+ 0xfcd9, 0x3c73,
+ 0xfcda, 0x38a5,
+ 0xfcdb, 0x43f9,
+ 0xfcdc, 0x3cfe,
+ 0xfcdd, 0x4257,
+ 0xfcde, 0x4233,
+ 0xfcdf, 0x3d69,
+ 0xfce0, 0x3c7e,
+ 0xfce1, 0x3d6f,
+ 0xfce2, 0x4000,
+ 0xfce3, 0x3dc0,
+ 0xfce4, 0x4004,
+ 0xfce5, 0x0e72,
+ 0xfce6, 0x3938,
+ 0xfce7, 0x3fa4,
+ 0xfce8, 0x295a,
+ 0xfce9, 0x4273,
+ 0xfcea, 0x3ac9,
+ 0xfceb, 0x427d,
+ 0xfcec, 0x3aca,
+ 0xfced, 0x3fb2,
+ 0xfcee, 0x3fb6,
+ 0xfcef, 0x3f97,
+ 0xfcf0, 0x3f9a,
+ 0xfcf1, 0x428b,
+ 0xfcf2, 0x43fa,
+ 0xfcf3, 0x428a,
+ 0xfcf4, 0x3f51,
+ 0xfcf5, 0x3f98,
+ 0xfcf6, 0x41a3,
+ 0xfcf7, 0x3d5c,
+ 0xfcf8, 0x3f63,
+ 0xfcf9, 0x4290,
+ 0xfcfa, 0x1f94,
+ 0xfcfb, 0x42c6,
+ 0xfcfc, 0x42a2,
+ 0xfcfd, 0x3ffa,
+ 0xfcfe, 0x3f9d,
+ 0xfd40, 0x3ffe,
+ 0xfd41, 0x3f9b,
+ 0xfd42, 0x3fdf,
+ 0xfd43, 0x3fe6,
+ 0xfd44, 0x3fde,
+ 0xfd45, 0x42b7,
+ 0xfd46, 0x3ff4,
+ 0xfd47, 0x42b8,
+ 0xfd48, 0x3feb,
+ 0xfd49, 0x42bf,
+ 0xfd4a, 0x3d71,
+ 0xfd4b, 0x3f4f,
+ 0xfd4c, 0x42c5,
+ 0xfd4d, 0x42d5,
+ 0xfd4e, 0x42d0,
+ 0xfd4f, 0x42d8,
+ 0xfd50, 0x3f55,
+ 0xfd51, 0x3fe8,
+ 0xfd52, 0x3ff3,
+ 0xfd53, 0x42df,
+ 0xfd54, 0x3fd3,
+ 0xfd55, 0x3e73,
+ 0xfd56, 0x3f95,
+ 0xfd57, 0x42ee,
+ 0xfd58, 0x42f4,
+ 0xfd59, 0x3f8c,
+ 0xfd5a, 0x3fcf,
+ 0xfd5b, 0x42ec,
+ 0xfd5c, 0x3fd4,
+ 0xfd5d, 0x42f0,
+ 0xfd5e, 0x07c2,
+ 0xfd5f, 0x0955,
+ 0xfd60, 0x42fe,
+ 0xfd61, 0x4301,
+ 0xfd62, 0x3ccd,
+ 0xfd63, 0x4307,
+ 0xfd64, 0x43fb,
+ 0xfd65, 0x3fda,
+ 0xfd66, 0x3f8b,
+ 0xfd67, 0x3733,
+ 0xfd68, 0x3f8a,
+ 0xfd69, 0x3741,
+ 0xfd6a, 0x3740,
+ 0xfd6b, 0x3742,
+ 0xfd6c, 0x3f93,
+ 0xfd6d, 0x3f8f,
+ 0xfd6e, 0x3e70,
+ 0xfd6f, 0x42c9,
+ 0xfd70, 0x3e72,
+ 0xfd71, 0x3fa9,
+ 0xfd72, 0x42cd,
+ 0xfd73, 0x43d2,
+ 0xfd74, 0x3f8e,
+ 0xfd75, 0x3f77,
+ 0xfd76, 0x3d6e,
+ 0xfd77, 0x0d0a,
+ 0xfd78, 0x3f11,
+ 0xfd79, 0x3752,
+ 0xfd7a, 0x3f14,
+ 0xfd7b, 0x3f18,
+ 0xfd7c, 0x3f53,
+ 0xfd7d, 0x3f1f,
+ 0xfd7e, 0x3f1c,
+ 0xfda1, 0x3fb8,
+ 0xfda2, 0x339d,
+ 0xfda3, 0x3b3f,
+ 0xfda4, 0x3f52,
+ 0xfda5, 0x3f1a,
+ 0xfda6, 0x3f1d,
+ 0xfda7, 0x375c,
+ 0xfda8, 0x3885,
+ 0xfda9, 0x3761,
+ 0xfdaa, 0x3fd7,
+ 0xfdab, 0x3fd6,
+ 0xfdac, 0x3fd9,
+ 0xfdad, 0x3fd8,
+ 0xfdae, 0x3fdd,
+ 0xfdaf, 0x3e93,
+ 0xfdb0, 0x3769,
+ 0xfdb1, 0x376e,
+ 0xfdb2, 0x3b4c,
+ 0xfdb3, 0x3774,
+ 0xfdb4, 0x377f,
+ 0xfdb5, 0x377b,
+ 0xfdb6, 0x3782,
+ 0xfdb7, 0x3b4f,
+ 0xfdb8, 0x3792,
+ 0xfdb9, 0x3fe3,
+ 0xfdba, 0x3fdc,
+ 0xfdbb, 0x3fdb,
+ 0xfdbc, 0x3fe5,
+ 0xfdbd, 0x3b75,
+ 0xfdbe, 0x37a2,
+ 0xfdbf, 0x3fe2,
+ 0xfdc0, 0x3fe7,
+ 0xfdc1, 0x3e6d,
+ 0xfdc2, 0x0d2a,
+ 0xfdc3, 0x3e79,
+ 0xfdc4, 0x3e76,
+ 0xfdc5, 0x379f,
+ 0xfdc6, 0x3fee,
+ 0xfdc7, 0x42d4,
+ 0xfdc8, 0x3d94,
+ 0xfdc9, 0x3d61,
+ 0xfdca, 0x3fe1,
+ 0xfdcb, 0x375e,
+ 0xfdcc, 0x3b7a,
+ 0xfdcd, 0x380b,
+ 0xfdce, 0x3fec,
+ 0xfdcf, 0x3fef,
+ 0xfdd0, 0x2e45,
+ 0xfdd1, 0x3ffc,
+ 0xfdd2, 0x3fed,
+ 0xfdd3, 0x380d,
+ 0xfdd4, 0x3fe4,
+ 0xfdd5, 0x3f92,
+ 0xfdd6, 0x3fae,
+ 0xfdd7, 0x3811,
+ 0xfdd8, 0x3f7a,
+ 0xfdd9, 0x3b8b,
+ 0xfdda, 0x3f5a,
+ 0xfddb, 0x3816,
+ 0xfddc, 0x3fa2,
+ 0xfddd, 0x3b8e,
+ 0xfdde, 0x381c,
+ 0xfddf, 0x2054,
+ 0xfde0, 0x381f,
+ 0xfde1, 0x3fa0,
+ 0xfde2, 0x43fc,
+ 0xfde3, 0x3e16,
+ 0xfde4, 0x3b94,
+ 0xfde5, 0x3f7c,
+ 0xfde6, 0x4007,
+ 0xfde7, 0x3f7b,
+ 0xfde8, 0x3d73,
+ 0xfde9, 0x3e77,
+ 0xfdea, 0x3d92,
+ 0xfdeb, 0x3fa1,
+ 0xfdec, 0x37c1,
+ 0xfded, 0x37d3,
+ 0xfdee, 0x3e7a,
+ 0xfdef, 0x3f59,
+ 0xfdf0, 0x3c55,
+ 0xfdf1, 0x3ff8,
+ 0xfdf2, 0x3ff5,
+ 0xfdf3, 0x3c4c,
+ 0xfdf4, 0x3d8c,
+ 0xfdf5, 0x3fa3,
+ 0xfdf6, 0x37c0,
+ 0xfdf7, 0x3f54,
+ 0xfdf8, 0x3800,
+ 0xfdf9, 0x3b7f,
+ 0xfdfa, 0x3f9e,
+ 0xfdfb, 0x3822,
+ 0xfdfc, 0x3fe9,
+ 0xfdfd, 0x3823,
+ 0xfdfe, 0x3fe0,
+ 0xfe40, 0x3d93,
+ 0xfe41, 0x3ff9,
+ 0xfe42, 0x3827,
+ 0xfe43, 0x3fa5,
+ 0xfe44, 0x3ff0,
+ 0xfe45, 0x3836,
+ 0xfe46, 0x3f99,
+ 0xfe47, 0x3ff2,
+ 0xfe48, 0x3d8d,
+ 0xfe49, 0x43e6,
+ 0xfe4a, 0x3522,
+ 0xfe4b, 0x3ff1,
+ 0xfe4c, 0x3f9c,
+ 0xfe4d, 0x3fb1,
+ 0xfe4e, 0x3f96,
+ 0xfe4f, 0x3e6f,
+ 0xfe50, 0x3f69,
+ 0xfe51, 0x3ff7,
+ 0xfe52, 0x3f82,
+ 0xfe53, 0x3f88,
+ 0xfe54, 0x3f85,
+ 0xfe55, 0x3f83,
+ 0xfe56, 0x3f7f,
+ 0xfe57, 0x3f89,
+ 0xfe58, 0x3bb5,
+ 0xfe59, 0x3862,
+ 0xfe5a, 0x3f87,
+ 0xfe5b, 0x3f31,
+ 0xfe5c, 0x3815,
+ 0xfe5d, 0x387e,
+ 0xfe5e, 0x3f49,
+ 0xfe5f, 0x3f48,
+ 0xfe60, 0x3f47,
+ 0xfe61, 0x3f45,
+ 0xfe62, 0x43eb,
+ 0xfe63, 0x3882,
+ 0xfe64, 0x3f6f,
+ 0xfe65, 0x3f4e,
+ 0xfe66, 0x3bc8,
+ 0xfe67, 0x43fd,
+ 0xfe68, 0x3d6b,
+ 0xfe6a, 0x43fe,
+ 0xfe6b, 0x3fcb,
+ 0xfe6c, 0x3dd2,
+ 0xfe6d, 0x3879,
+ 0xfe6e, 0x3f10,
+ 0xfe6f, 0x382e,
+ 0xfe70, 0x388b,
+ 0xfe71, 0x3c60,
+ 0xfe72, 0x2a9f,
+ 0xfe73, 0x3c61,
+ 0xfe74, 0x3893,
+ 0xfe75, 0x3e74,
+ 0xfe76, 0x3fac,
+ 0xfe77, 0x3f81,
+ 0xfe78, 0x3bcd,
+ 0xfe79, 0x3bd4,
+ 0xfe7a, 0x3bd3,
+ 0xfe7b, 0x3fcc,
+ 0xfe7c, 0x3fd1,
+ 0xfe7d, 0x3f3d,
+ 0xfe7e, 0x3f4a,
+ 0xfea1, 0x2352,
+ 0xfea2, 0x38ad,
+ 0xfea3, 0x3f46,
+ 0xfea4, 0x38b5,
+ 0xfea5, 0x3f0d,
+ 0xfea6, 0x3fb3,
+ 0xfea7, 0x38c0,
+ 0xfea8, 0x3e2f,
+ 0xfea9, 0x38cf,
+ 0xfeaa, 0x38d5,
+ 0xfeab, 0x3f33,
+ 0xfeac, 0x3d95,
+ 0xfead, 0x3f35,
+ 0xfeae, 0x38d7,
+ 0xfeaf, 0x3f2f,
+ 0xfeb0, 0x38e0,
+ 0xfeb1, 0x3c02,
+ 0xfeb2, 0x3f72,
+ 0xfeb3, 0x3f70,
+ 0xfeb4, 0x3d96,
+ 0xfeb5, 0x38e6,
+ 0xfeb7, 0x4035,
+ 0xfeb8, 0x3f73,
+ 0xfeb9, 0x38f0,
+ 0xfeba, 0x3c0b,
+ 0xfebb, 0x38f7,
+ 0xfebc, 0x37aa,
+ 0xfebd, 0x43ff,
+ 0xfebe, 0x38fa,
+ 0xfebf, 0x3c11,
+ 0xfec0, 0x3f34,
+ 0xfec1, 0x3fb9,
+ 0xfec2, 0x3c12,
+ 0xfec3, 0x400a,
+ 0xfec4, 0x3d77,
+ 0xfec5, 0x3f42,
+ 0xfec6, 0x3900,
+ 0xfec7, 0x3902,
+ 0xfec8, 0x3f74,
+ 0xfec9, 0x3d97,
+ 0xfeca, 0x3faa,
+ 0xfecb, 0x3f19,
+ 0xfecc, 0x3f1b,
+ 0xfecd, 0x390e,
+ 0xfece, 0x3909,
+ 0xfecf, 0x390b,
+ 0xfed0, 0x3f12,
+ 0xfed1, 0x3f17,
+ 0xfed2, 0x3fb7,
+ 0xfed3, 0x3f20,
+ 0xfed4, 0x3fbb,
+ 0xfed5, 0x3f3c,
+ 0xfed6, 0x3fad,
+ 0xfed7, 0x3919,
+ 0xfed8, 0x3f56,
+ 0xfed9, 0x3f71,
+ 0xfeda, 0x3fb4,
+ 0xfedb, 0x391c,
+ 0xfedc, 0x3f1e,
+ 0xfedd, 0x3f3a,
+ 0xfede, 0x391b,
+ 0xfedf, 0x3d87,
+ 0xfee0, 0x3c3a,
+ 0xfee1, 0x3f22,
+ 0xfee2, 0x3e71,
+ 0xfee3, 0x3c39,
+ 0xfee4, 0x3d7e,
+ 0xfee5, 0x4124,
+ 0xfee6, 0x3f3b,
+ 0xfee7, 0x3e6e,
+ 0xfee8, 0x3fab,
+ 0xfee9, 0x3925,
+ 0xfeea, 0x3f30,
+ 0xfeeb, 0x3929,
+ 0xfeec, 0x3f84,
+ 0xfeed, 0x3f0f,
+ 0xfeee, 0x3f76,
+ 0xfeef, 0x3f94,
+ 0xfef0, 0x3932,
+ 0xfef1, 0x3f27,
+ 0xfef2, 0x3933,
+ 0xfef3, 0x3f75,
+ 0xfef4, 0x3937,
+ 0xfef5, 0x3d78,
+ 0xfef6, 0x3f21,
+ 0xfef7, 0x3f90,
+ 0xfef8, 0x3940,
+ 0xfef9, 0x3d7f,
+ 0xfefa, 0x394a,
+ 0xfefb, 0x3f80,
+ 0xfefc, 0x3f23,
+ 0xfefd, 0x3950,
+ 0xfefe, 0x3f7e,
+ 0xa14b, 0x354e,
+ 0xa15a, 0x35af,
+ 0xa15c, 0x35b1,
+ 0xa15d, 0x0082,
+ 0xa161, 0x0086,
+ 0xa165, 0x008a,
+ 0xa169, 0x008e,
+ 0xa16d, 0x0092,
+ 0xa171, 0x0096,
+ 0xa175, 0x009a,
+ 0xa179, 0x009e,
+ 0xa1e3, 0x354f,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 cns13HKdlaB5VEnc16 = {
+ 1,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
+ 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010,
+ 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018,
+ 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020,
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028,
+ 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030,
+ 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038,
+ 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040,
+ 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048,
+ 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050,
+ 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
+ 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ cns13HKdlaB5VMap2, 1035
+};
+
+static Gushort cns13HKdlbB5HMap2[1816] = {
+ 0x0000, 0x0000,
+ 0x8e40, 0x3d77,
+ 0x8e41, 0x3d6c,
+ 0x8e42, 0x3f59,
+ 0x8e43, 0x3919,
+ 0x8e44, 0x3e70,
+ 0x8e45, 0x3752,
+ 0x8e46, 0x38af,
+ 0x8e47, 0x3786,
+ 0x8e48, 0x3f1b,
+ 0x8e49, 0x3d5c,
+ 0x8e4a, 0x3f99,
+ 0x8e4b, 0x3fe8,
+ 0x8e4c, 0x388b,
+ 0x8e4d, 0x38dc,
+ 0x8e4e, 0x3faa,
+ 0x8e4f, 0x42c8,
+ 0x8e50, 0x3741,
+ 0x8e51, 0x3d7f,
+ 0x8e52, 0x42ec,
+ 0x8e53, 0x3f93,
+ 0x8e54, 0x389a,
+ 0x8e55, 0x3879,
+ 0x8e56, 0x373a,
+ 0x8e57, 0x42d0,
+ 0x8e58, 0x3e6f,
+ 0x8e59, 0x3f18,
+ 0x8e5a, 0x36e8,
+ 0x8e5b, 0x3739,
+ 0x8e5c, 0x3e99,
+ 0x8e5d, 0x3b4c,
+ 0x8e5e, 0x3dd2,
+ 0x8e5f, 0x3fa9,
+ 0x8e60, 0x3fac,
+ 0x8e61, 0x3fcb,
+ 0x8e62, 0x3733,
+ 0x8e63, 0x3f9f,
+ 0x8e64, 0x40da,
+ 0x8e65, 0x3f29,
+ 0x8e66, 0x3c66,
+ 0x8e67, 0x4222,
+ 0x8e68, 0x40ae,
+ 0x8e69, 0x3d7a,
+ 0x8e6a, 0x3f8d,
+ 0x8e6b, 0x39d0,
+ 0x8e6c, 0x4264,
+ 0x8e6d, 0x3d82,
+ 0x8e6e, 0x4203,
+ 0x8e6f, 0x41db,
+ 0x8e70, 0x3fde,
+ 0x8e71, 0x3ff4,
+ 0x8e72, 0x4004,
+ 0x8e73, 0x3f66,
+ 0x8e74, 0x3f9b,
+ 0x8e75, 0x3d66,
+ 0x8e76, 0x404b,
+ 0x8e77, 0x3fdf,
+ 0x8e78, 0x40fb,
+ 0x8e79, 0x4012,
+ 0x8e7a, 0x3fe6,
+ 0x8e7b, 0x42eb,
+ 0x8e7c, 0x4124,
+ 0x8e7d, 0x3d7c,
+ 0x8e7e, 0x3d69,
+ 0x8ea1, 0x3ffe,
+ 0x8ea2, 0x3d72,
+ 0x8ea3, 0x3fc6,
+ 0x8ea4, 0x3cfe,
+ 0x8ea5, 0x43f9,
+ 0x8ea6, 0x3d42,
+ 0x8ea7, 0x3f15,
+ 0x8ea8, 0x3fce,
+ 0x8ea9, 0x428b,
+ 0x8eaa, 0x40cf,
+ 0x8eab, 0x43f6,
+ 0x8eac, 0x4005,
+ 0x8ead, 0x3f2d,
+ 0x8eae, 0x4161,
+ 0x8eaf, 0x3f2c,
+ 0x8eb0, 0x3aca,
+ 0x8eb1, 0x3d6a,
+ 0x8eb2, 0x4063,
+ 0x8eb3, 0x3fc5,
+ 0x8eb4, 0x39e7,
+ 0x8eb5, 0x3f2a,
+ 0x8eb6, 0x4060,
+ 0x8eb7, 0x4273,
+ 0x8eb8, 0x4221,
+ 0x8eb9, 0x40a2,
+ 0x8eba, 0x3f68,
+ 0x8ebb, 0x40a1,
+ 0x8ebc, 0x3f57,
+ 0x8ebd, 0x3f70,
+ 0x8ebe, 0x3fb7,
+ 0x8ebf, 0x3746,
+ 0x8ec0, 0x3fab,
+ 0x8ec1, 0x3ff2,
+ 0x8ec2, 0x3f8c,
+ 0x8ec3, 0x3f88,
+ 0x8ec4, 0x37d3,
+ 0x8ec5, 0x3b74,
+ 0x8ec7, 0x42f4,
+ 0x8ec8, 0x3c4c,
+ 0x8ec9, 0x3b7a,
+ 0x8eca, 0x3885,
+ 0x8ecb, 0x3737,
+ 0x8ecc, 0x3fdb,
+ 0x8ecd, 0x3f1d,
+ 0x8ece, 0x3fec,
+ 0x8ecf, 0x3fe5,
+ 0x8ed0, 0x375e,
+ 0x8ed1, 0x3ff7,
+ 0x8ed2, 0x3813,
+ 0x8ed3, 0x3fe3,
+ 0x8ed4, 0x3f1a,
+ 0x8ed5, 0x38e6,
+ 0x8ed6, 0x3fdc,
+ 0x8ed7, 0x377f,
+ 0x8ed8, 0x3d87,
+ 0x8ed9, 0x3bd3,
+ 0x8eda, 0x3d78,
+ 0x8edb, 0x3bd4,
+ 0x8edc, 0x3f96,
+ 0x8edd, 0x3f95,
+ 0x8ede, 0x3d8c,
+ 0x8edf, 0x3937,
+ 0x8ee0, 0x3f1c,
+ 0x8ee1, 0x3932,
+ 0x8ee2, 0x3d6b,
+ 0x8ee3, 0x3800,
+ 0x8ee4, 0x3ff8,
+ 0x8ee5, 0x3c3a,
+ 0x8ee6, 0x3f42,
+ 0x8ee7, 0x43fd,
+ 0x8ee8, 0x3fb1,
+ 0x8ee9, 0x3792,
+ 0x8eea, 0x3f94,
+ 0x8eeb, 0x3f1e,
+ 0x8eec, 0x400a,
+ 0x8eed, 0x3882,
+ 0x8eee, 0x3f9c,
+ 0x8eef, 0x3d61,
+ 0x8ef0, 0x3f22,
+ 0x8ef1, 0x3fe9,
+ 0x8ef2, 0x3d92,
+ 0x8ef3, 0x377f,
+ 0x8ef4, 0x3b94,
+ 0x8ef5, 0x376e,
+ 0x8ef6, 0x4301,
+ 0x8ef7, 0x3f3a,
+ 0x8ef8, 0x3863,
+ 0x8ef9, 0x3ff1,
+ 0x8efa, 0x42fe,
+ 0x8efb, 0x3bfc,
+ 0x8efc, 0x3f45,
+ 0x8efd, 0x379f,
+ 0x8efe, 0x376b,
+ 0x8f40, 0x3f14,
+ 0x8f41, 0x3f47,
+ 0x8f42, 0x3862,
+ 0x8f43, 0x3769,
+ 0x8f44, 0x3c12,
+ 0x8f45, 0x3f49,
+ 0x8f46, 0x381f,
+ 0x8f47, 0x3929,
+ 0x8f48, 0x3f56,
+ 0x8f49, 0x3f34,
+ 0x8f4a, 0x3fdd,
+ 0x8f4b, 0x38fa,
+ 0x8f4c, 0x3f7b,
+ 0x8f4d, 0x3c11,
+ 0x8f4e, 0x3f7c,
+ 0x8f4f, 0x43ff,
+ 0x8f50, 0x3e73,
+ 0x8f51, 0x3f71,
+ 0x8f52, 0x3925,
+ 0x8f53, 0x3c55,
+ 0x8f54, 0x38b5,
+ 0x8f55, 0x3f5a,
+ 0x8f56, 0x3816,
+ 0x8f57, 0x3e6d,
+ 0x8f58, 0x3782,
+ 0x8f59, 0x3f11,
+ 0x8f5a, 0x3b8b,
+ 0x8f5b, 0x37c0,
+ 0x8f5c, 0x3815,
+ 0x8f5d, 0x383b,
+ 0x8f5e, 0x3d73,
+ 0x8f5f, 0x3d6e,
+ 0x8f60, 0x3f8a,
+ 0x8f61, 0x3f3e,
+ 0x8f62, 0x4234,
+ 0x8f63, 0x41e3,
+ 0x8f64, 0x3fc7,
+ 0x8f65, 0x3ff3,
+ 0x8f66, 0x4003,
+ 0x8f67, 0x4032,
+ 0x8f68, 0x3f6e,
+ 0x8f69, 0x41a3,
+ 0x8f6a, 0x4006,
+ 0x8f6b, 0x3f2b,
+ 0x8f6c, 0x3f7d,
+ 0x8f6d, 0x3c73,
+ 0x8f6e, 0x3f16,
+ 0x8f6f, 0x4002,
+ 0x8f70, 0x4056,
+ 0x8f71, 0x3fba,
+ 0x8f72, 0x3f6b,
+ 0x8f73, 0x3f91,
+ 0x8f74, 0x3fbe,
+ 0x8f75, 0x405a,
+ 0x8f76, 0x3adf,
+ 0x8f77, 0x3e41,
+ 0x8f78, 0x3d67,
+ 0x8f79, 0x3f60,
+ 0x8f7a, 0x41e8,
+ 0x8f7b, 0x3fc0,
+ 0x8f7c, 0x3d83,
+ 0x8f7d, 0x4173,
+ 0x8f7e, 0x3f5c,
+ 0x8fa1, 0x3f32,
+ 0x8fa2, 0x3f3f,
+ 0x8fa3, 0x3d63,
+ 0x8fa4, 0x4146,
+ 0x8fa5, 0x3fcd,
+ 0x8fa6, 0x3d79,
+ 0x8fa7, 0x3f28,
+ 0x8fa8, 0x3fc1,
+ 0x8fa9, 0x40bc,
+ 0x8faa, 0x3d71,
+ 0x8fab, 0x3f37,
+ 0x8fac, 0x42d8,
+ 0x8fad, 0x3feb,
+ 0x8fae, 0x4241,
+ 0x8faf, 0x3a30,
+ 0x8fb0, 0x39cd,
+ 0x8fb1, 0x42bf,
+ 0x8fb2, 0x420e,
+ 0x8fb3, 0x3f0a,
+ 0x8fb4, 0x39cc,
+ 0x8fb5, 0x4044,
+ 0x8fb6, 0x4098,
+ 0x8fb7, 0x418c,
+ 0x8fb8, 0x3d64,
+ 0x8fb9, 0x3f44,
+ 0x8fba, 0x404f,
+ 0x8fbb, 0x42d5,
+ 0x8fbc, 0x4290,
+ 0x8fbd, 0x4000,
+ 0x8fbe, 0x3a89,
+ 0x8fbf, 0x416c,
+ 0x8fc0, 0x40c4,
+ 0x8fc1, 0x404d,
+ 0x8fc2, 0x3dc0,
+ 0x8fc3, 0x3f50,
+ 0x8fc4, 0x4009,
+ 0x8fc5, 0x3faf,
+ 0x8fc6, 0x3f86,
+ 0x8fc7, 0x4093,
+ 0x8fc8, 0x3aad,
+ 0x8fc9, 0x3f38,
+ 0x8fca, 0x3d75,
+ 0x8fcb, 0x3f39,
+ 0x8fcc, 0x42cd,
+ 0x8fcd, 0x3f78,
+ 0x8fce, 0x3f9d,
+ 0x8fcf, 0x4090,
+ 0x8fd0, 0x3d80,
+ 0x8fd1, 0x3f2e,
+ 0x8fd2, 0x38b6,
+ 0x8fd3, 0x41b9,
+ 0x8fd4, 0x3d8a,
+ 0x8fd5, 0x3f24,
+ 0x8fd6, 0x3a9e,
+ 0x8fd7, 0x3adc,
+ 0x8fd8, 0x3d65,
+ 0x8fd9, 0x4085,
+ 0x8fda, 0x3f51,
+ 0x8fdb, 0x43fa,
+ 0x8fdc, 0x3f63,
+ 0x8fdd, 0x4178,
+ 0x8fde, 0x41b7,
+ 0x8fdf, 0x3e72,
+ 0x8fe0, 0x41d9,
+ 0x8fe1, 0x418e,
+ 0x8fe2, 0x3d76,
+ 0x8fe3, 0x42d4,
+ 0x8fe4, 0x42a2,
+ 0x8fe5, 0x4257,
+ 0x8fe6, 0x3f0c,
+ 0x8fe7, 0x3996,
+ 0x8fe8, 0x4255,
+ 0x8fe9, 0x40b7,
+ 0x8fea, 0x3f9a,
+ 0x8feb, 0x3fca,
+ 0x8fec, 0x3f5e,
+ 0x8fed, 0x3d85,
+ 0x8fee, 0x3ffa,
+ 0x8fef, 0x3fb6,
+ 0x8ff0, 0x3ac3,
+ 0x8ff1, 0x3fc8,
+ 0x8ff2, 0x3f4b,
+ 0x8ff3, 0x40f1,
+ 0x8ff4, 0x4034,
+ 0x8ff5, 0x3f5b,
+ 0x8ff6, 0x42c9,
+ 0x8ff7, 0x3c75,
+ 0x8ff8, 0x3f79,
+ 0x8ff9, 0x42c6,
+ 0x8ffa, 0x38cf,
+ 0x8ffb, 0x41f4,
+ 0x8ffc, 0x3f41,
+ 0x8ffd, 0x390b,
+ 0x8ffe, 0x38e0,
+ 0x9040, 0x427d,
+ 0x9041, 0x42f0,
+ 0x9042, 0x3f27,
+ 0x9043, 0x3822,
+ 0x9044, 0x37d8,
+ 0x9045, 0x37a2,
+ 0x9046, 0x3f73,
+ 0x9047, 0x42b8,
+ 0x9048, 0x3f19,
+ 0x9049, 0x42b7,
+ 0x904a, 0x3d8b,
+ 0x904b, 0x4129,
+ 0x904c, 0x40d4,
+ 0x904d, 0x38f5,
+ 0x904e, 0x4143,
+ 0x904f, 0x4022,
+ 0x9050, 0x41d0,
+ 0x9051, 0x41f5,
+ 0x9052, 0x3f43,
+ 0x9053, 0x40c8,
+ 0x9054, 0x4096,
+ 0x9055, 0x405d,
+ 0x9056, 0x4174,
+ 0x9057, 0x413e,
+ 0x9058, 0x413b,
+ 0x9059, 0x39c4,
+ 0x905a, 0x3d89,
+ 0x905b, 0x4205,
+ 0x905c, 0x36eb,
+ 0x905d, 0x39c5,
+ 0x905e, 0x3d84,
+ 0x905f, 0x4054,
+ 0x9060, 0x193f,
+ 0x9061, 0x0619,
+ 0x9062, 0x0871,
+ 0x9063, 0x115f,
+ 0x9064, 0x3f53,
+ 0x9065, 0x3f1f,
+ 0x9066, 0x339d,
+ 0x9067, 0x3fb8,
+ 0x9068, 0x3b3f,
+ 0x9069, 0x3f52,
+ 0x906a, 0x3761,
+ 0x906b, 0x375c,
+ 0x906c, 0x3fd9,
+ 0x906d, 0x3fd7,
+ 0x906e, 0x3fd6,
+ 0x906f, 0x3e93,
+ 0x9070, 0x3774,
+ 0x9071, 0x377b,
+ 0x9072, 0x3b4f,
+ 0x9073, 0x4007,
+ 0x9074, 0x3fe2,
+ 0x9075, 0x3e79,
+ 0x9076, 0x3e76,
+ 0x9077, 0x3fe7,
+ 0x9078, 0x0d2a,
+ 0x9079, 0x3fee,
+ 0x907a, 0x3fe1,
+ 0x907b, 0x3e77,
+ 0x907c, 0x3fa3,
+ 0x907d, 0x3f54,
+ 0x907e, 0x37bc,
+ 0x90a1, 0x3e7a,
+ 0x90a2, 0x3fa1,
+ 0x90a3, 0x37c1,
+ 0x90a4, 0x3ff5,
+ 0x90a5, 0x3f9e,
+ 0x90a6, 0x3b7f,
+ 0x90a7, 0x380b,
+ 0x90a8, 0x3fef,
+ 0x90a9, 0x3ffc,
+ 0x90aa, 0x380d,
+ 0x90ab, 0x3fed,
+ 0x90ac, 0x3fe4,
+ 0x90ad, 0x3811,
+ 0x90ae, 0x3f7a,
+ 0x90af, 0x3fa2,
+ 0x90b0, 0x3b8e,
+ 0x90b1, 0x381c,
+ 0x90b2, 0x3fa0,
+ 0x90b3, 0x3fe0,
+ 0x90b4, 0x3d93,
+ 0x90b5, 0x3827,
+ 0x90b6, 0x3ff0,
+ 0x90b7, 0x3fa5,
+ 0x90b8, 0x3836,
+ 0x90b9, 0x3d8d,
+ 0x90ba, 0x3f69,
+ 0x90bb, 0x3f82,
+ 0x90bc, 0x3f85,
+ 0x90bd, 0x3f83,
+ 0x90be, 0x3f89,
+ 0x90bf, 0x3f7f,
+ 0x90c0, 0x3bb5,
+ 0x90c1, 0x3f87,
+ 0x90c2, 0x3f31,
+ 0x90c3, 0x3d94,
+ 0x90c4, 0x0230,
+ 0x90c5, 0x43fe,
+ 0x90c6, 0x3f10,
+ 0x90c7, 0x387e,
+ 0x90c8, 0x43eb,
+ 0x90c9, 0x3f6f,
+ 0x90ca, 0x3e9b,
+ 0x90cb, 0x3f4e,
+ 0x90cc, 0x3bc8,
+ 0x90cd, 0x1e29,
+ 0x90ce, 0x3f48,
+ 0x90cf, 0x382e,
+ 0x90d0, 0x3c60,
+ 0x90d1, 0x2a9f,
+ 0x90d2, 0x3893,
+ 0x90d3, 0x43f7,
+ 0x90d4, 0x3e74,
+ 0x90d5, 0x3bcd,
+ 0x90d6, 0x3ac9,
+ 0x90d7, 0x3fcc,
+ 0x90d8, 0x3fd1,
+ 0x90d9, 0x3f3d,
+ 0x90da, 0x3f4a,
+ 0x90db, 0x38ad,
+ 0x90dc, 0x2352,
+ 0x90dd, 0x3f46,
+ 0x90de, 0x38b2,
+ 0x90df, 0x3fb3,
+ 0x90e0, 0x3f0d,
+ 0x90e1, 0x38c0,
+ 0x90e2, 0x3e2f,
+ 0x90e3, 0x38d5,
+ 0x90e4, 0x3f35,
+ 0x90e5, 0x38d7,
+ 0x90e6, 0x3f2f,
+ 0x90e7, 0x3f33,
+ 0x90e8, 0x3d95,
+ 0x90e9, 0x3c02,
+ 0x90ea, 0x3f72,
+ 0x90eb, 0x3d96,
+ 0x90ec, 0x38e7,
+ 0x90ed, 0x4035,
+ 0x90ee, 0x3c0b,
+ 0x90ef, 0x38f0,
+ 0x90f0, 0x38f7,
+ 0x90f1, 0x3fb9,
+ 0x90f2, 0x3900,
+ 0x90f3, 0x3f74,
+ 0x90f4, 0x3909,
+ 0x90f5, 0x3f12,
+ 0x90f6, 0x3f17,
+ 0x90f7, 0x3f20,
+ 0x90f8, 0x3fbb,
+ 0x90f9, 0x3f3c,
+ 0x90fa, 0x3fb4,
+ 0x90fb, 0x3fad,
+ 0x90fc, 0x391a,
+ 0x90fd, 0x391c,
+ 0x90fe, 0x391b,
+ 0x9140, 0x3c39,
+ 0x9141, 0x3e71,
+ 0x9142, 0x3d7e,
+ 0x9143, 0x3f3b,
+ 0x9144, 0x3f30,
+ 0x9145, 0x3f84,
+ 0x9146, 0x43f8,
+ 0x9147, 0x3f0f,
+ 0x9148, 0x3f76,
+ 0x9149, 0x3933,
+ 0x914a, 0x3f75,
+ 0x914b, 0x3940,
+ 0x914c, 0x3f21,
+ 0x914d, 0x3f90,
+ 0x914e, 0x394a,
+ 0x914f, 0x3f80,
+ 0x9150, 0x3f23,
+ 0x9151, 0x3950,
+ 0x9152, 0x3d97,
+ 0x9153, 0x2e45,
+ 0x9154, 0x0570,
+ 0x9155, 0x3ead,
+ 0x9156, 0x3522,
+ 0x9157, 0x0be3,
+ 0x9158, 0x0595,
+ 0x9159, 0x0228,
+ 0x915a, 0x0a95,
+ 0x915b, 0x12b0,
+ 0x915c, 0x091a,
+ 0x915d, 0x43fc,
+ 0x915e, 0x3f92,
+ 0x915f, 0x3fae,
+ 0x9160, 0x07c2,
+ 0x9161, 0x0955,
+ 0x9162, 0x3785,
+ 0x9163, 0x3e6e,
+ 0x9164, 0x3d6d,
+ 0x9165, 0x3f62,
+ 0x9166, 0x39c8,
+ 0x9167, 0x3f65,
+ 0x9168, 0x393d,
+ 0x9169, 0x3f26,
+ 0x916a, 0x406d,
+ 0x916b, 0x3fd0,
+ 0x916c, 0x3f36,
+ 0x916d, 0x4086,
+ 0x916e, 0x3952,
+ 0x916f, 0x3fd2,
+ 0x9170, 0x3858,
+ 0x9171, 0x3ffb,
+ 0x9172, 0x3f67,
+ 0x9173, 0x3e81,
+ 0x9174, 0x3fc9,
+ 0x9175, 0x3fb5,
+ 0x9176, 0x3e7c,
+ 0x9177, 0x3e75,
+ 0x9178, 0x3c77,
+ 0x9179, 0x3b2e,
+ 0x917a, 0x3f4d,
+ 0x917b, 0x43af,
+ 0x917c, 0x3e67,
+ 0x917d, 0x40bd,
+ 0x917e, 0x3f6c,
+ 0x91a1, 0x39a6,
+ 0x91a2, 0x3948,
+ 0x91a3, 0x3fbf,
+ 0x91a4, 0x3f5f,
+ 0x91a5, 0x3a05,
+ 0x91a6, 0x06f5,
+ 0x91a7, 0x40f8,
+ 0x91a8, 0x41ad,
+ 0x91a9, 0x3f0e,
+ 0x91aa, 0x4122,
+ 0x91ab, 0x3f13,
+ 0x91ac, 0x3f0b,
+ 0x91ad, 0x4135,
+ 0x91ae, 0x3a2b,
+ 0x91af, 0x4138,
+ 0x91b0, 0x0226,
+ 0x91b1, 0x4149,
+ 0x91b2, 0x3ba5,
+ 0x91b3, 0x4001,
+ 0x91b4, 0x3fbd,
+ 0x91b5, 0x3fa8,
+ 0x91b6, 0x4186,
+ 0x91b7, 0x3a54,
+ 0x91b8, 0x3fc2,
+ 0x91b9, 0x4192,
+ 0x91ba, 0x4187,
+ 0x91bb, 0x3384,
+ 0x91bc, 0x3fc4,
+ 0x91bd, 0x3d99,
+ 0x91be, 0x3aaa,
+ 0x91bf, 0x41de,
+ 0x91c1, 0x3ff6,
+ 0x91c2, 0x3f5d,
+ 0x91c3, 0x41c7,
+ 0x91c4, 0x3d91,
+ 0x91c5, 0x3d74,
+ 0x91c6, 0x3f4c,
+ 0x91c7, 0x41f2,
+ 0x91c8, 0x3aa5,
+ 0x91c9, 0x3b4b,
+ 0x91ca, 0x3d86,
+ 0x91cb, 0x41f8,
+ 0x91cc, 0x4240,
+ 0x91cd, 0x3ffd,
+ 0x91ce, 0x3fa7,
+ 0x91cf, 0x4259,
+ 0x91d0, 0x0e72,
+ 0x91d1, 0x4262,
+ 0x91d2, 0x3c7e,
+ 0x91d3, 0x3938,
+ 0x91d4, 0x4233,
+ 0x91d5, 0x295a,
+ 0x91d7, 0x3f97,
+ 0x91d8, 0x3fb2,
+ 0x91d9, 0x428a,
+ 0x91da, 0x3f98,
+ 0x91db, 0x1f94,
+ 0x91dc, 0x3f40,
+ 0x91dd, 0x3f4f,
+ 0x91de, 0x3f8f,
+ 0x91df, 0x3d6f,
+ 0x91e0, 0x42df,
+ 0x91e1, 0x3f55,
+ 0x91e2, 0x3fd3,
+ 0x91e3, 0x42ee,
+ 0x91e4, 0x3fcf,
+ 0x91e5, 0x3fd4,
+ 0x91e6, 0x3e7d,
+ 0x91e7, 0x4307,
+ 0x91e8, 0x43fb,
+ 0x91e9, 0x3fda,
+ 0x91ea, 0x0d0a,
+ 0x91eb, 0x3f77,
+ 0x91ec, 0x3dbf,
+ 0x91ed, 0x402c,
+ 0x91ee, 0x3fa4,
+ 0x91ef, 0x3d6f,
+ 0x91f0, 0x3ccd,
+ 0x91f1, 0x3f64,
+ 0x91f2, 0x3f8b,
+ 0x91f3, 0x386f,
+ 0x91f4, 0x1971,
+ 0x91f5, 0x1c9b,
+ 0x91f6, 0x0745,
+ 0x91f7, 0x1d75,
+ 0x91f8, 0x3888,
+ 0x91f9, 0x3742,
+ 0x91fa, 0x2b40,
+ 0x91fb, 0x36e9,
+ 0x91fc, 0x37e0,
+ 0x91fd, 0x3e16,
+ 0x91fe, 0x387c,
+ 0x9240, 0x37aa,
+ 0x9241, 0x3f8e,
+ 0x9242, 0x40dc,
+ 0x9243, 0x3c7a,
+ 0x9244, 0x3fa6,
+ 0x9245, 0x405f,
+ 0x9246, 0x3c26,
+ 0x9247, 0x385e,
+ 0x9248, 0x3f25,
+ 0x9249, 0x4048,
+ 0x924a, 0x3d81,
+ 0x924b, 0x390e,
+ 0x924c, 0x4084,
+ 0x924d, 0x4118,
+ 0x924e, 0x4157,
+ 0x924f, 0x3902,
+ 0x9250, 0x389f,
+ 0x9251, 0x3ff9,
+ 0x9252, 0x3823,
+ 0x9253, 0x3871,
+ 0x9254, 0x36ea,
+ 0x9255, 0x376c,
+ 0x9256, 0x3740,
+ 0x9257, 0x37f4,
+ 0x9258, 0x42e0,
+ 0x9259, 0x425b,
+ 0x925a, 0x36ed,
+ 0x925b, 0x3b14,
+ 0x925c, 0x42c5,
+ 0x925d, 0x408b,
+ 0x925e, 0x38a5,
+ 0x925f, 0x416a,
+ 0x9260, 0x419d,
+ 0x9261, 0x4144,
+ 0x9262, 0x424f,
+ 0x9263, 0x3f61,
+ 0x9264, 0x3fd8,
+ 0x9265, 0x061c,
+ 0xa140, 0x0063,
+ 0xa159, 0x35af,
+ 0xa15d, 0x0080,
+ 0xa1a1, 0x00a2,
+ 0xa1f6, 0x00f8,
+ 0xa1f7, 0x00f7,
+ 0xa1f8, 0x00f9,
+ 0xa240, 0x0100,
+ 0xa2a1, 0x013f,
+ 0xa340, 0x019d,
+ 0xa3a1, 0x01dc,
+ 0xa3bd, 0x01f7,
+ 0xa440, 0x0253,
+ 0xa4a1, 0x0292,
+ 0xa540, 0x02f0,
+ 0xa5a1, 0x032f,
+ 0xa640, 0x038d,
+ 0xa6a1, 0x03cc,
+ 0xa740, 0x042a,
+ 0xa7a1, 0x0469,
+ 0xa840, 0x04c7,
+ 0xa8a1, 0x0506,
+ 0xa940, 0x0564,
+ 0xa9a1, 0x05a3,
+ 0xaa40, 0x0601,
+ 0xaaa1, 0x0640,
+ 0xab40, 0x069e,
+ 0xaba1, 0x06dd,
+ 0xac40, 0x073b,
+ 0xaca1, 0x077a,
+ 0xacfe, 0x097f,
+ 0xad40, 0x07d7,
+ 0xada1, 0x0816,
+ 0xae40, 0x0874,
+ 0xaea1, 0x08b3,
+ 0xaf40, 0x0911,
+ 0xafa1, 0x0950,
+ 0xafd0, 0x0980,
+ 0xb040, 0x09af,
+ 0xb0a1, 0x09ee,
+ 0xb140, 0x0a4c,
+ 0xb1a1, 0x0a8b,
+ 0xb240, 0x0ae9,
+ 0xb2a1, 0x0b28,
+ 0xb340, 0x0b86,
+ 0xb3a1, 0x0bc5,
+ 0xb440, 0x0c23,
+ 0xb4a1, 0x0c62,
+ 0xb540, 0x0cc0,
+ 0xb5a1, 0x0cff,
+ 0xb640, 0x0d5d,
+ 0xb6a1, 0x0d9c,
+ 0xb740, 0x0dfa,
+ 0xb7a1, 0x0e39,
+ 0xb840, 0x0e97,
+ 0xb8a1, 0x0ed6,
+ 0xb940, 0x0f34,
+ 0xb9a1, 0x0f73,
+ 0xba40, 0x0fd1,
+ 0xbaa1, 0x1010,
+ 0xbb40, 0x106e,
+ 0xbba1, 0x10ad,
+ 0xbbc8, 0x10d5,
+ 0xbc40, 0x110c,
+ 0xbca1, 0x114b,
+ 0xbd40, 0x11a9,
+ 0xbda1, 0x11e8,
+ 0xbe40, 0x1246,
+ 0xbe52, 0x10d4,
+ 0xbe53, 0x1258,
+ 0xbea1, 0x1284,
+ 0xbf40, 0x12e2,
+ 0xbfa1, 0x1321,
+ 0xc040, 0x137f,
+ 0xc0a1, 0x13be,
+ 0xc140, 0x141c,
+ 0xc1a1, 0x145b,
+ 0xc1ab, 0x1466,
+ 0xc240, 0x14ba,
+ 0xc2a1, 0x14f9,
+ 0xc2cb, 0x1465,
+ 0xc2cc, 0x1523,
+ 0xc340, 0x1556,
+ 0xc361, 0x1578,
+ 0xc3a1, 0x1596,
+ 0xc3b9, 0x15af,
+ 0xc3ba, 0x15ae,
+ 0xc3bb, 0x15b0,
+ 0xc440, 0x15f4,
+ 0xc456, 0x1577,
+ 0xc457, 0x160a,
+ 0xc4a1, 0x1632,
+ 0xc540, 0x1690,
+ 0xc5a1, 0x16cf,
+ 0xc640, 0x172d,
+ 0xc940, 0x176c,
+ 0xc94a, 0x0274,
+ 0xc94b, 0x1776,
+ 0xc96c, 0x1798,
+ 0xc9a1, 0x17ab,
+ 0xc9be, 0x1797,
+ 0xc9bf, 0x17c8,
+ 0xc9ed, 0x17f7,
+ 0xca40, 0x1809,
+ 0xcaa1, 0x1848,
+ 0xcaf7, 0x17f6,
+ 0xcaf8, 0x189e,
+ 0xcb40, 0x18a5,
+ 0xcba1, 0x18e4,
+ 0xcc40, 0x1942,
+ 0xcca1, 0x1981,
+ 0xcd40, 0x19df,
+ 0xcda1, 0x1a1e,
+ 0xce40, 0x1a7c,
+ 0xcea1, 0x1abb,
+ 0xcf40, 0x1b19,
+ 0xcfa1, 0x1b58,
+ 0xd040, 0x1bb6,
+ 0xd0a1, 0x1bf5,
+ 0xd140, 0x1c53,
+ 0xd1a1, 0x1c92,
+ 0xd240, 0x1cf0,
+ 0xd2a1, 0x1d2f,
+ 0xd340, 0x1d8d,
+ 0xd3a1, 0x1dcc,
+ 0xd440, 0x1e2a,
+ 0xd4a1, 0x1e69,
+ 0xd540, 0x1ec7,
+ 0xd5a1, 0x1f06,
+ 0xd640, 0x1f64,
+ 0xd6a1, 0x1fa3,
+ 0xd6cc, 0x2254,
+ 0xd6cd, 0x1fcf,
+ 0xd740, 0x2001,
+ 0xd77a, 0x22b9,
+ 0xd77b, 0x203b,
+ 0xd7a1, 0x203f,
+ 0xd840, 0x209d,
+ 0xd8a1, 0x20dc,
+ 0xd940, 0x213a,
+ 0xd9a1, 0x2179,
+ 0xda40, 0x21d7,
+ 0xdaa1, 0x2216,
+ 0xdadf, 0x1fce,
+ 0xdae0, 0x2255,
+ 0xdb40, 0x2274,
+ 0xdba1, 0x22b3,
+ 0xdba7, 0x22ba,
+ 0xdc40, 0x2312,
+ 0xdca1, 0x2351,
+ 0xdd40, 0x23af,
+ 0xdda1, 0x23ee,
+ 0xddfc, 0x2381,
+ 0xddfd, 0x2449,
+ 0xde40, 0x244b,
+ 0xdea1, 0x248a,
+ 0xdf40, 0x24e8,
+ 0xdfa1, 0x2527,
+ 0xe040, 0x2585,
+ 0xe0a1, 0x25c4,
+ 0xe140, 0x2622,
+ 0xe1a1, 0x2661,
+ 0xe240, 0x26bf,
+ 0xe2a1, 0x26fe,
+ 0xe340, 0x275c,
+ 0xe3a1, 0x279b,
+ 0xe440, 0x27f9,
+ 0xe4a1, 0x2838,
+ 0xe540, 0x2896,
+ 0xe5a1, 0x28d5,
+ 0xe640, 0x2933,
+ 0xe6a1, 0x2972,
+ 0xe740, 0x29d0,
+ 0xe7a1, 0x2a0f,
+ 0xe840, 0x2a6d,
+ 0xe8a1, 0x2aac,
+ 0xe8a3, 0x2aaf,
+ 0xe940, 0x2b0b,
+ 0xe976, 0x2b42,
+ 0xe9a1, 0x2b4b,
+ 0xea40, 0x2ba9,
+ 0xeaa1, 0x2be8,
+ 0xeb40, 0x2c46,
+ 0xeb5b, 0x2c62,
+ 0xeba1, 0x2c86,
+ 0xebf1, 0x2aae,
+ 0xebf2, 0x2cd6,
+ 0xec40, 0x2ce3,
+ 0xeca1, 0x2d22,
+ 0xecde, 0x2b41,
+ 0xecdf, 0x2d5f,
+ 0xed40, 0x2d7f,
+ 0xeda1, 0x2dbe,
+ 0xedaa, 0x2dc8,
+ 0xee40, 0x2e1d,
+ 0xeea1, 0x2e5c,
+ 0xeeeb, 0x3014,
+ 0xeeec, 0x2ea6,
+ 0xef40, 0x2eb9,
+ 0xefa1, 0x2ef8,
+ 0xf040, 0x2f56,
+ 0xf056, 0x2dc7,
+ 0xf057, 0x2f6c,
+ 0xf0a1, 0x2f94,
+ 0xf0cb, 0x2c61,
+ 0xf0cc, 0x2fbe,
+ 0xf140, 0x2ff1,
+ 0xf163, 0x3015,
+ 0xf16b, 0x3160,
+ 0xf16c, 0x301d,
+ 0xf1a1, 0x3030,
+ 0xf240, 0x308e,
+ 0xf268, 0x31ef,
+ 0xf269, 0x30b6,
+ 0xf2a1, 0x30cc,
+ 0xf2c3, 0x30ef,
+ 0xf340, 0x312b,
+ 0xf375, 0x3161,
+ 0xf3a1, 0x316b,
+ 0xf440, 0x31c9,
+ 0xf466, 0x31f0,
+ 0xf4a1, 0x3209,
+ 0xf4b5, 0x30ee,
+ 0xf4b6, 0x321d,
+ 0xf4fd, 0x3265,
+ 0xf540, 0x3267,
+ 0xf5a1, 0x32a6,
+ 0xf640, 0x3304,
+ 0xf663, 0x3264,
+ 0xf664, 0x3327,
+ 0xf6a1, 0x3342,
+ 0xf740, 0x33a0,
+ 0xf7a1, 0x33df,
+ 0xf840, 0x343d,
+ 0xf8a1, 0x347c,
+ 0xf940, 0x34da,
+ 0xf977, 0x3512,
+ 0xf9a1, 0x351a,
+ 0xf9c4, 0x3511,
+ 0xf9c5, 0x353d,
+ 0xf9c6, 0x3549,
+ 0xf9c7, 0x353e,
+ 0xf9d2, 0x354a,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 cns13HKdlbB5HEnc16 = {
+ 0,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
+ 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010,
+ 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018,
+ 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020,
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028,
+ 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030,
+ 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038,
+ 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040,
+ 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048,
+ 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050,
+ 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
+ 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ cns13HKdlbB5HMap2, 908
+};
+
+static Gushort cns13HKdlbB5VMap2[1840] = {
+ 0x0000, 0x0000,
+ 0x8e40, 0x3d77,
+ 0x8e41, 0x3d6c,
+ 0x8e42, 0x3f59,
+ 0x8e43, 0x3919,
+ 0x8e44, 0x3e70,
+ 0x8e45, 0x3752,
+ 0x8e46, 0x38af,
+ 0x8e47, 0x3786,
+ 0x8e48, 0x3f1b,
+ 0x8e49, 0x3d5c,
+ 0x8e4a, 0x3f99,
+ 0x8e4b, 0x3fe8,
+ 0x8e4c, 0x388b,
+ 0x8e4d, 0x38dc,
+ 0x8e4e, 0x3faa,
+ 0x8e4f, 0x42c8,
+ 0x8e50, 0x3741,
+ 0x8e51, 0x3d7f,
+ 0x8e52, 0x42ec,
+ 0x8e53, 0x3f93,
+ 0x8e54, 0x389a,
+ 0x8e55, 0x3879,
+ 0x8e56, 0x373a,
+ 0x8e57, 0x42d0,
+ 0x8e58, 0x3e6f,
+ 0x8e59, 0x3f18,
+ 0x8e5a, 0x36e8,
+ 0x8e5b, 0x3739,
+ 0x8e5c, 0x3e99,
+ 0x8e5d, 0x3b4c,
+ 0x8e5e, 0x3dd2,
+ 0x8e5f, 0x3fa9,
+ 0x8e60, 0x3fac,
+ 0x8e61, 0x3fcb,
+ 0x8e62, 0x3733,
+ 0x8e63, 0x3f9f,
+ 0x8e64, 0x40da,
+ 0x8e65, 0x3f29,
+ 0x8e66, 0x3c66,
+ 0x8e67, 0x4222,
+ 0x8e68, 0x40ae,
+ 0x8e69, 0x3d7a,
+ 0x8e6a, 0x3f8d,
+ 0x8e6b, 0x39d0,
+ 0x8e6c, 0x4264,
+ 0x8e6d, 0x3d82,
+ 0x8e6e, 0x4203,
+ 0x8e6f, 0x41db,
+ 0x8e70, 0x3fde,
+ 0x8e71, 0x3ff4,
+ 0x8e72, 0x4004,
+ 0x8e73, 0x3f66,
+ 0x8e74, 0x3f9b,
+ 0x8e75, 0x3d66,
+ 0x8e76, 0x404b,
+ 0x8e77, 0x3fdf,
+ 0x8e78, 0x40fb,
+ 0x8e79, 0x4012,
+ 0x8e7a, 0x3fe6,
+ 0x8e7b, 0x42eb,
+ 0x8e7c, 0x4124,
+ 0x8e7d, 0x3d7c,
+ 0x8e7e, 0x3d69,
+ 0x8ea1, 0x3ffe,
+ 0x8ea2, 0x3d72,
+ 0x8ea3, 0x3fc6,
+ 0x8ea4, 0x3cfe,
+ 0x8ea5, 0x43f9,
+ 0x8ea6, 0x3d42,
+ 0x8ea7, 0x3f15,
+ 0x8ea8, 0x3fce,
+ 0x8ea9, 0x428b,
+ 0x8eaa, 0x40cf,
+ 0x8eab, 0x43f6,
+ 0x8eac, 0x4005,
+ 0x8ead, 0x3f2d,
+ 0x8eae, 0x4161,
+ 0x8eaf, 0x3f2c,
+ 0x8eb0, 0x3aca,
+ 0x8eb1, 0x3d6a,
+ 0x8eb2, 0x4063,
+ 0x8eb3, 0x3fc5,
+ 0x8eb4, 0x39e7,
+ 0x8eb5, 0x3f2a,
+ 0x8eb6, 0x4060,
+ 0x8eb7, 0x4273,
+ 0x8eb8, 0x4221,
+ 0x8eb9, 0x40a2,
+ 0x8eba, 0x3f68,
+ 0x8ebb, 0x40a1,
+ 0x8ebc, 0x3f57,
+ 0x8ebd, 0x3f70,
+ 0x8ebe, 0x3fb7,
+ 0x8ebf, 0x3746,
+ 0x8ec0, 0x3fab,
+ 0x8ec1, 0x3ff2,
+ 0x8ec2, 0x3f8c,
+ 0x8ec3, 0x3f88,
+ 0x8ec4, 0x37d3,
+ 0x8ec5, 0x3b74,
+ 0x8ec7, 0x42f4,
+ 0x8ec8, 0x3c4c,
+ 0x8ec9, 0x3b7a,
+ 0x8eca, 0x3885,
+ 0x8ecb, 0x3737,
+ 0x8ecc, 0x3fdb,
+ 0x8ecd, 0x3f1d,
+ 0x8ece, 0x3fec,
+ 0x8ecf, 0x3fe5,
+ 0x8ed0, 0x375e,
+ 0x8ed1, 0x3ff7,
+ 0x8ed2, 0x3813,
+ 0x8ed3, 0x3fe3,
+ 0x8ed4, 0x3f1a,
+ 0x8ed5, 0x38e6,
+ 0x8ed6, 0x3fdc,
+ 0x8ed7, 0x377f,
+ 0x8ed8, 0x3d87,
+ 0x8ed9, 0x3bd3,
+ 0x8eda, 0x3d78,
+ 0x8edb, 0x3bd4,
+ 0x8edc, 0x3f96,
+ 0x8edd, 0x3f95,
+ 0x8ede, 0x3d8c,
+ 0x8edf, 0x3937,
+ 0x8ee0, 0x3f1c,
+ 0x8ee1, 0x3932,
+ 0x8ee2, 0x3d6b,
+ 0x8ee3, 0x3800,
+ 0x8ee4, 0x3ff8,
+ 0x8ee5, 0x3c3a,
+ 0x8ee6, 0x3f42,
+ 0x8ee7, 0x43fd,
+ 0x8ee8, 0x3fb1,
+ 0x8ee9, 0x3792,
+ 0x8eea, 0x3f94,
+ 0x8eeb, 0x3f1e,
+ 0x8eec, 0x400a,
+ 0x8eed, 0x3882,
+ 0x8eee, 0x3f9c,
+ 0x8eef, 0x3d61,
+ 0x8ef0, 0x3f22,
+ 0x8ef1, 0x3fe9,
+ 0x8ef2, 0x3d92,
+ 0x8ef3, 0x377f,
+ 0x8ef4, 0x3b94,
+ 0x8ef5, 0x376e,
+ 0x8ef6, 0x4301,
+ 0x8ef7, 0x3f3a,
+ 0x8ef8, 0x3863,
+ 0x8ef9, 0x3ff1,
+ 0x8efa, 0x42fe,
+ 0x8efb, 0x3bfc,
+ 0x8efc, 0x3f45,
+ 0x8efd, 0x379f,
+ 0x8efe, 0x376b,
+ 0x8f40, 0x3f14,
+ 0x8f41, 0x3f47,
+ 0x8f42, 0x3862,
+ 0x8f43, 0x3769,
+ 0x8f44, 0x3c12,
+ 0x8f45, 0x3f49,
+ 0x8f46, 0x381f,
+ 0x8f47, 0x3929,
+ 0x8f48, 0x3f56,
+ 0x8f49, 0x3f34,
+ 0x8f4a, 0x3fdd,
+ 0x8f4b, 0x38fa,
+ 0x8f4c, 0x3f7b,
+ 0x8f4d, 0x3c11,
+ 0x8f4e, 0x3f7c,
+ 0x8f4f, 0x43ff,
+ 0x8f50, 0x3e73,
+ 0x8f51, 0x3f71,
+ 0x8f52, 0x3925,
+ 0x8f53, 0x3c55,
+ 0x8f54, 0x38b5,
+ 0x8f55, 0x3f5a,
+ 0x8f56, 0x3816,
+ 0x8f57, 0x3e6d,
+ 0x8f58, 0x3782,
+ 0x8f59, 0x3f11,
+ 0x8f5a, 0x3b8b,
+ 0x8f5b, 0x37c0,
+ 0x8f5c, 0x3815,
+ 0x8f5d, 0x383b,
+ 0x8f5e, 0x3d73,
+ 0x8f5f, 0x3d6e,
+ 0x8f60, 0x3f8a,
+ 0x8f61, 0x3f3e,
+ 0x8f62, 0x4234,
+ 0x8f63, 0x41e3,
+ 0x8f64, 0x3fc7,
+ 0x8f65, 0x3ff3,
+ 0x8f66, 0x4003,
+ 0x8f67, 0x4032,
+ 0x8f68, 0x3f6e,
+ 0x8f69, 0x41a3,
+ 0x8f6a, 0x4006,
+ 0x8f6b, 0x3f2b,
+ 0x8f6c, 0x3f7d,
+ 0x8f6d, 0x3c73,
+ 0x8f6e, 0x3f16,
+ 0x8f6f, 0x4002,
+ 0x8f70, 0x4056,
+ 0x8f71, 0x3fba,
+ 0x8f72, 0x3f6b,
+ 0x8f73, 0x3f91,
+ 0x8f74, 0x3fbe,
+ 0x8f75, 0x405a,
+ 0x8f76, 0x3adf,
+ 0x8f77, 0x3e41,
+ 0x8f78, 0x3d67,
+ 0x8f79, 0x3f60,
+ 0x8f7a, 0x41e8,
+ 0x8f7b, 0x3fc0,
+ 0x8f7c, 0x3d83,
+ 0x8f7d, 0x4173,
+ 0x8f7e, 0x3f5c,
+ 0x8fa1, 0x3f32,
+ 0x8fa2, 0x3f3f,
+ 0x8fa3, 0x3d63,
+ 0x8fa4, 0x4146,
+ 0x8fa5, 0x3fcd,
+ 0x8fa6, 0x3d79,
+ 0x8fa7, 0x3f28,
+ 0x8fa8, 0x3fc1,
+ 0x8fa9, 0x40bc,
+ 0x8faa, 0x3d71,
+ 0x8fab, 0x3f37,
+ 0x8fac, 0x42d8,
+ 0x8fad, 0x3feb,
+ 0x8fae, 0x4241,
+ 0x8faf, 0x3a30,
+ 0x8fb0, 0x39cd,
+ 0x8fb1, 0x42bf,
+ 0x8fb2, 0x420e,
+ 0x8fb3, 0x3f0a,
+ 0x8fb4, 0x39cc,
+ 0x8fb5, 0x4044,
+ 0x8fb6, 0x4098,
+ 0x8fb7, 0x418c,
+ 0x8fb8, 0x3d64,
+ 0x8fb9, 0x3f44,
+ 0x8fba, 0x404f,
+ 0x8fbb, 0x42d5,
+ 0x8fbc, 0x4290,
+ 0x8fbd, 0x4000,
+ 0x8fbe, 0x3a89,
+ 0x8fbf, 0x416c,
+ 0x8fc0, 0x40c4,
+ 0x8fc1, 0x404d,
+ 0x8fc2, 0x3dc0,
+ 0x8fc3, 0x3f50,
+ 0x8fc4, 0x4009,
+ 0x8fc5, 0x3faf,
+ 0x8fc6, 0x3f86,
+ 0x8fc7, 0x4093,
+ 0x8fc8, 0x3aad,
+ 0x8fc9, 0x3f38,
+ 0x8fca, 0x3d75,
+ 0x8fcb, 0x3f39,
+ 0x8fcc, 0x42cd,
+ 0x8fcd, 0x3f78,
+ 0x8fce, 0x3f9d,
+ 0x8fcf, 0x4090,
+ 0x8fd0, 0x3d80,
+ 0x8fd1, 0x3f2e,
+ 0x8fd2, 0x38b6,
+ 0x8fd3, 0x41b9,
+ 0x8fd4, 0x3d8a,
+ 0x8fd5, 0x3f24,
+ 0x8fd6, 0x3a9e,
+ 0x8fd7, 0x3adc,
+ 0x8fd8, 0x3d65,
+ 0x8fd9, 0x4085,
+ 0x8fda, 0x3f51,
+ 0x8fdb, 0x43fa,
+ 0x8fdc, 0x3f63,
+ 0x8fdd, 0x4178,
+ 0x8fde, 0x41b7,
+ 0x8fdf, 0x3e72,
+ 0x8fe0, 0x41d9,
+ 0x8fe1, 0x418e,
+ 0x8fe2, 0x3d76,
+ 0x8fe3, 0x42d4,
+ 0x8fe4, 0x42a2,
+ 0x8fe5, 0x4257,
+ 0x8fe6, 0x3f0c,
+ 0x8fe7, 0x3996,
+ 0x8fe8, 0x4255,
+ 0x8fe9, 0x40b7,
+ 0x8fea, 0x3f9a,
+ 0x8feb, 0x3fca,
+ 0x8fec, 0x3f5e,
+ 0x8fed, 0x3d85,
+ 0x8fee, 0x3ffa,
+ 0x8fef, 0x3fb6,
+ 0x8ff0, 0x3ac3,
+ 0x8ff1, 0x3fc8,
+ 0x8ff2, 0x3f4b,
+ 0x8ff3, 0x40f1,
+ 0x8ff4, 0x4034,
+ 0x8ff5, 0x3f5b,
+ 0x8ff6, 0x42c9,
+ 0x8ff7, 0x3c75,
+ 0x8ff8, 0x3f79,
+ 0x8ff9, 0x42c6,
+ 0x8ffa, 0x38cf,
+ 0x8ffb, 0x41f4,
+ 0x8ffc, 0x3f41,
+ 0x8ffd, 0x390b,
+ 0x8ffe, 0x38e0,
+ 0x9040, 0x427d,
+ 0x9041, 0x42f0,
+ 0x9042, 0x3f27,
+ 0x9043, 0x3822,
+ 0x9044, 0x37d8,
+ 0x9045, 0x37a2,
+ 0x9046, 0x3f73,
+ 0x9047, 0x42b8,
+ 0x9048, 0x3f19,
+ 0x9049, 0x42b7,
+ 0x904a, 0x3d8b,
+ 0x904b, 0x4129,
+ 0x904c, 0x40d4,
+ 0x904d, 0x38f5,
+ 0x904e, 0x4143,
+ 0x904f, 0x4022,
+ 0x9050, 0x41d0,
+ 0x9051, 0x41f5,
+ 0x9052, 0x3f43,
+ 0x9053, 0x40c8,
+ 0x9054, 0x4096,
+ 0x9055, 0x405d,
+ 0x9056, 0x4174,
+ 0x9057, 0x413e,
+ 0x9058, 0x413b,
+ 0x9059, 0x39c4,
+ 0x905a, 0x3d89,
+ 0x905b, 0x4205,
+ 0x905c, 0x36eb,
+ 0x905d, 0x39c5,
+ 0x905e, 0x3d84,
+ 0x905f, 0x4054,
+ 0x9060, 0x193f,
+ 0x9061, 0x0619,
+ 0x9062, 0x0871,
+ 0x9063, 0x115f,
+ 0x9064, 0x3f53,
+ 0x9065, 0x3f1f,
+ 0x9066, 0x339d,
+ 0x9067, 0x3fb8,
+ 0x9068, 0x3b3f,
+ 0x9069, 0x3f52,
+ 0x906a, 0x3761,
+ 0x906b, 0x375c,
+ 0x906c, 0x3fd9,
+ 0x906d, 0x3fd7,
+ 0x906e, 0x3fd6,
+ 0x906f, 0x3e93,
+ 0x9070, 0x3774,
+ 0x9071, 0x377b,
+ 0x9072, 0x3b4f,
+ 0x9073, 0x4007,
+ 0x9074, 0x3fe2,
+ 0x9075, 0x3e79,
+ 0x9076, 0x3e76,
+ 0x9077, 0x3fe7,
+ 0x9078, 0x0d2a,
+ 0x9079, 0x3fee,
+ 0x907a, 0x3fe1,
+ 0x907b, 0x3e77,
+ 0x907c, 0x3fa3,
+ 0x907d, 0x3f54,
+ 0x907e, 0x37bc,
+ 0x90a1, 0x3e7a,
+ 0x90a2, 0x3fa1,
+ 0x90a3, 0x37c1,
+ 0x90a4, 0x3ff5,
+ 0x90a5, 0x3f9e,
+ 0x90a6, 0x3b7f,
+ 0x90a7, 0x380b,
+ 0x90a8, 0x3fef,
+ 0x90a9, 0x3ffc,
+ 0x90aa, 0x380d,
+ 0x90ab, 0x3fed,
+ 0x90ac, 0x3fe4,
+ 0x90ad, 0x3811,
+ 0x90ae, 0x3f7a,
+ 0x90af, 0x3fa2,
+ 0x90b0, 0x3b8e,
+ 0x90b1, 0x381c,
+ 0x90b2, 0x3fa0,
+ 0x90b3, 0x3fe0,
+ 0x90b4, 0x3d93,
+ 0x90b5, 0x3827,
+ 0x90b6, 0x3ff0,
+ 0x90b7, 0x3fa5,
+ 0x90b8, 0x3836,
+ 0x90b9, 0x3d8d,
+ 0x90ba, 0x3f69,
+ 0x90bb, 0x3f82,
+ 0x90bc, 0x3f85,
+ 0x90bd, 0x3f83,
+ 0x90be, 0x3f89,
+ 0x90bf, 0x3f7f,
+ 0x90c0, 0x3bb5,
+ 0x90c1, 0x3f87,
+ 0x90c2, 0x3f31,
+ 0x90c3, 0x3d94,
+ 0x90c4, 0x0230,
+ 0x90c5, 0x43fe,
+ 0x90c6, 0x3f10,
+ 0x90c7, 0x387e,
+ 0x90c8, 0x43eb,
+ 0x90c9, 0x3f6f,
+ 0x90ca, 0x3e9b,
+ 0x90cb, 0x3f4e,
+ 0x90cc, 0x3bc8,
+ 0x90cd, 0x1e29,
+ 0x90ce, 0x3f48,
+ 0x90cf, 0x382e,
+ 0x90d0, 0x3c60,
+ 0x90d1, 0x2a9f,
+ 0x90d2, 0x3893,
+ 0x90d3, 0x43f7,
+ 0x90d4, 0x3e74,
+ 0x90d5, 0x3bcd,
+ 0x90d6, 0x3ac9,
+ 0x90d7, 0x3fcc,
+ 0x90d8, 0x3fd1,
+ 0x90d9, 0x3f3d,
+ 0x90da, 0x3f4a,
+ 0x90db, 0x38ad,
+ 0x90dc, 0x2352,
+ 0x90dd, 0x3f46,
+ 0x90de, 0x38b2,
+ 0x90df, 0x3fb3,
+ 0x90e0, 0x3f0d,
+ 0x90e1, 0x38c0,
+ 0x90e2, 0x3e2f,
+ 0x90e3, 0x38d5,
+ 0x90e4, 0x3f35,
+ 0x90e5, 0x38d7,
+ 0x90e6, 0x3f2f,
+ 0x90e7, 0x3f33,
+ 0x90e8, 0x3d95,
+ 0x90e9, 0x3c02,
+ 0x90ea, 0x3f72,
+ 0x90eb, 0x3d96,
+ 0x90ec, 0x38e7,
+ 0x90ed, 0x4035,
+ 0x90ee, 0x3c0b,
+ 0x90ef, 0x38f0,
+ 0x90f0, 0x38f7,
+ 0x90f1, 0x3fb9,
+ 0x90f2, 0x3900,
+ 0x90f3, 0x3f74,
+ 0x90f4, 0x3909,
+ 0x90f5, 0x3f12,
+ 0x90f6, 0x3f17,
+ 0x90f7, 0x3f20,
+ 0x90f8, 0x3fbb,
+ 0x90f9, 0x3f3c,
+ 0x90fa, 0x3fb4,
+ 0x90fb, 0x3fad,
+ 0x90fc, 0x391a,
+ 0x90fd, 0x391c,
+ 0x90fe, 0x391b,
+ 0x9140, 0x3c39,
+ 0x9141, 0x3e71,
+ 0x9142, 0x3d7e,
+ 0x9143, 0x3f3b,
+ 0x9144, 0x3f30,
+ 0x9145, 0x3f84,
+ 0x9146, 0x43f8,
+ 0x9147, 0x3f0f,
+ 0x9148, 0x3f76,
+ 0x9149, 0x3933,
+ 0x914a, 0x3f75,
+ 0x914b, 0x3940,
+ 0x914c, 0x3f21,
+ 0x914d, 0x3f90,
+ 0x914e, 0x394a,
+ 0x914f, 0x3f80,
+ 0x9150, 0x3f23,
+ 0x9151, 0x3950,
+ 0x9152, 0x3d97,
+ 0x9153, 0x2e45,
+ 0x9154, 0x0570,
+ 0x9155, 0x3ead,
+ 0x9156, 0x3522,
+ 0x9157, 0x0be3,
+ 0x9158, 0x0595,
+ 0x9159, 0x0228,
+ 0x915a, 0x0a95,
+ 0x915b, 0x12b0,
+ 0x915c, 0x091a,
+ 0x915d, 0x43fc,
+ 0x915e, 0x3f92,
+ 0x915f, 0x3fae,
+ 0x9160, 0x07c2,
+ 0x9161, 0x0955,
+ 0x9162, 0x3785,
+ 0x9163, 0x3e6e,
+ 0x9164, 0x3d6d,
+ 0x9165, 0x3f62,
+ 0x9166, 0x39c8,
+ 0x9167, 0x3f65,
+ 0x9168, 0x393d,
+ 0x9169, 0x3f26,
+ 0x916a, 0x406d,
+ 0x916b, 0x3fd0,
+ 0x916c, 0x3f36,
+ 0x916d, 0x4086,
+ 0x916e, 0x3952,
+ 0x916f, 0x3fd2,
+ 0x9170, 0x3858,
+ 0x9171, 0x3ffb,
+ 0x9172, 0x3f67,
+ 0x9173, 0x3e81,
+ 0x9174, 0x3fc9,
+ 0x9175, 0x3fb5,
+ 0x9176, 0x3e7c,
+ 0x9177, 0x3e75,
+ 0x9178, 0x3c77,
+ 0x9179, 0x3b2e,
+ 0x917a, 0x3f4d,
+ 0x917b, 0x43af,
+ 0x917c, 0x3e67,
+ 0x917d, 0x40bd,
+ 0x917e, 0x3f6c,
+ 0x91a1, 0x39a6,
+ 0x91a2, 0x3948,
+ 0x91a3, 0x3fbf,
+ 0x91a4, 0x3f5f,
+ 0x91a5, 0x3a05,
+ 0x91a6, 0x06f5,
+ 0x91a7, 0x40f8,
+ 0x91a8, 0x41ad,
+ 0x91a9, 0x3f0e,
+ 0x91aa, 0x4122,
+ 0x91ab, 0x3f13,
+ 0x91ac, 0x3f0b,
+ 0x91ad, 0x4135,
+ 0x91ae, 0x3a2b,
+ 0x91af, 0x4138,
+ 0x91b0, 0x0226,
+ 0x91b1, 0x4149,
+ 0x91b2, 0x3ba5,
+ 0x91b3, 0x4001,
+ 0x91b4, 0x3fbd,
+ 0x91b5, 0x3fa8,
+ 0x91b6, 0x4186,
+ 0x91b7, 0x3a54,
+ 0x91b8, 0x3fc2,
+ 0x91b9, 0x4192,
+ 0x91ba, 0x4187,
+ 0x91bb, 0x3384,
+ 0x91bc, 0x3fc4,
+ 0x91bd, 0x3d99,
+ 0x91be, 0x3aaa,
+ 0x91bf, 0x41de,
+ 0x91c1, 0x3ff6,
+ 0x91c2, 0x3f5d,
+ 0x91c3, 0x41c7,
+ 0x91c4, 0x3d91,
+ 0x91c5, 0x3d74,
+ 0x91c6, 0x3f4c,
+ 0x91c7, 0x41f2,
+ 0x91c8, 0x3aa5,
+ 0x91c9, 0x3b4b,
+ 0x91ca, 0x3d86,
+ 0x91cb, 0x41f8,
+ 0x91cc, 0x4240,
+ 0x91cd, 0x3ffd,
+ 0x91ce, 0x3fa7,
+ 0x91cf, 0x4259,
+ 0x91d0, 0x0e72,
+ 0x91d1, 0x4262,
+ 0x91d2, 0x3c7e,
+ 0x91d3, 0x3938,
+ 0x91d4, 0x4233,
+ 0x91d5, 0x295a,
+ 0x91d7, 0x3f97,
+ 0x91d8, 0x3fb2,
+ 0x91d9, 0x428a,
+ 0x91da, 0x3f98,
+ 0x91db, 0x1f94,
+ 0x91dc, 0x3f40,
+ 0x91dd, 0x3f4f,
+ 0x91de, 0x3f8f,
+ 0x91df, 0x3d6f,
+ 0x91e0, 0x42df,
+ 0x91e1, 0x3f55,
+ 0x91e2, 0x3fd3,
+ 0x91e3, 0x42ee,
+ 0x91e4, 0x3fcf,
+ 0x91e5, 0x3fd4,
+ 0x91e6, 0x3e7d,
+ 0x91e7, 0x4307,
+ 0x91e8, 0x43fb,
+ 0x91e9, 0x3fda,
+ 0x91ea, 0x0d0a,
+ 0x91eb, 0x3f77,
+ 0x91ec, 0x3dbf,
+ 0x91ed, 0x402c,
+ 0x91ee, 0x3fa4,
+ 0x91ef, 0x3d6f,
+ 0x91f0, 0x3ccd,
+ 0x91f1, 0x3f64,
+ 0x91f2, 0x3f8b,
+ 0x91f3, 0x386f,
+ 0x91f4, 0x1971,
+ 0x91f5, 0x1c9b,
+ 0x91f6, 0x0745,
+ 0x91f7, 0x1d75,
+ 0x91f8, 0x3888,
+ 0x91f9, 0x3742,
+ 0x91fa, 0x2b40,
+ 0x91fb, 0x36e9,
+ 0x91fc, 0x37e0,
+ 0x91fd, 0x3e16,
+ 0x91fe, 0x387c,
+ 0x9240, 0x37aa,
+ 0x9241, 0x3f8e,
+ 0x9242, 0x40dc,
+ 0x9243, 0x3c7a,
+ 0x9244, 0x3fa6,
+ 0x9245, 0x405f,
+ 0x9246, 0x3c26,
+ 0x9247, 0x385e,
+ 0x9248, 0x3f25,
+ 0x9249, 0x4048,
+ 0x924a, 0x3d81,
+ 0x924b, 0x390e,
+ 0x924c, 0x4084,
+ 0x924d, 0x4118,
+ 0x924e, 0x4157,
+ 0x924f, 0x3902,
+ 0x9250, 0x389f,
+ 0x9251, 0x3ff9,
+ 0x9252, 0x3823,
+ 0x9253, 0x3871,
+ 0x9254, 0x36ea,
+ 0x9255, 0x376c,
+ 0x9256, 0x3740,
+ 0x9257, 0x37f4,
+ 0x9258, 0x42e0,
+ 0x9259, 0x425b,
+ 0x925a, 0x36ed,
+ 0x925b, 0x3b14,
+ 0x925c, 0x42c5,
+ 0x925d, 0x408b,
+ 0x925e, 0x38a5,
+ 0x925f, 0x416a,
+ 0x9260, 0x419d,
+ 0x9261, 0x4144,
+ 0x9262, 0x424f,
+ 0x9263, 0x3f61,
+ 0x9264, 0x3fd8,
+ 0x9265, 0x061c,
+ 0xa140, 0x0063,
+ 0xa159, 0x35af,
+ 0xa15d, 0x0080,
+ 0xa1a1, 0x00a2,
+ 0xa1f6, 0x00f8,
+ 0xa1f7, 0x00f7,
+ 0xa1f8, 0x00f9,
+ 0xa240, 0x0100,
+ 0xa2a1, 0x013f,
+ 0xa340, 0x019d,
+ 0xa3a1, 0x01dc,
+ 0xa3bd, 0x01f7,
+ 0xa440, 0x0253,
+ 0xa4a1, 0x0292,
+ 0xa540, 0x02f0,
+ 0xa5a1, 0x032f,
+ 0xa640, 0x038d,
+ 0xa6a1, 0x03cc,
+ 0xa740, 0x042a,
+ 0xa7a1, 0x0469,
+ 0xa840, 0x04c7,
+ 0xa8a1, 0x0506,
+ 0xa940, 0x0564,
+ 0xa9a1, 0x05a3,
+ 0xaa40, 0x0601,
+ 0xaaa1, 0x0640,
+ 0xab40, 0x069e,
+ 0xaba1, 0x06dd,
+ 0xac40, 0x073b,
+ 0xaca1, 0x077a,
+ 0xacfe, 0x097f,
+ 0xad40, 0x07d7,
+ 0xada1, 0x0816,
+ 0xae40, 0x0874,
+ 0xaea1, 0x08b3,
+ 0xaf40, 0x0911,
+ 0xafa1, 0x0950,
+ 0xafd0, 0x0980,
+ 0xb040, 0x09af,
+ 0xb0a1, 0x09ee,
+ 0xb140, 0x0a4c,
+ 0xb1a1, 0x0a8b,
+ 0xb240, 0x0ae9,
+ 0xb2a1, 0x0b28,
+ 0xb340, 0x0b86,
+ 0xb3a1, 0x0bc5,
+ 0xb440, 0x0c23,
+ 0xb4a1, 0x0c62,
+ 0xb540, 0x0cc0,
+ 0xb5a1, 0x0cff,
+ 0xb640, 0x0d5d,
+ 0xb6a1, 0x0d9c,
+ 0xb740, 0x0dfa,
+ 0xb7a1, 0x0e39,
+ 0xb840, 0x0e97,
+ 0xb8a1, 0x0ed6,
+ 0xb940, 0x0f34,
+ 0xb9a1, 0x0f73,
+ 0xba40, 0x0fd1,
+ 0xbaa1, 0x1010,
+ 0xbb40, 0x106e,
+ 0xbba1, 0x10ad,
+ 0xbbc8, 0x10d5,
+ 0xbc40, 0x110c,
+ 0xbca1, 0x114b,
+ 0xbd40, 0x11a9,
+ 0xbda1, 0x11e8,
+ 0xbe40, 0x1246,
+ 0xbe52, 0x10d4,
+ 0xbe53, 0x1258,
+ 0xbea1, 0x1284,
+ 0xbf40, 0x12e2,
+ 0xbfa1, 0x1321,
+ 0xc040, 0x137f,
+ 0xc0a1, 0x13be,
+ 0xc140, 0x141c,
+ 0xc1a1, 0x145b,
+ 0xc1ab, 0x1466,
+ 0xc240, 0x14ba,
+ 0xc2a1, 0x14f9,
+ 0xc2cb, 0x1465,
+ 0xc2cc, 0x1523,
+ 0xc340, 0x1556,
+ 0xc361, 0x1578,
+ 0xc3a1, 0x1596,
+ 0xc3b9, 0x15af,
+ 0xc3ba, 0x15ae,
+ 0xc3bb, 0x15b0,
+ 0xc440, 0x15f4,
+ 0xc456, 0x1577,
+ 0xc457, 0x160a,
+ 0xc4a1, 0x1632,
+ 0xc540, 0x1690,
+ 0xc5a1, 0x16cf,
+ 0xc640, 0x172d,
+ 0xc940, 0x176c,
+ 0xc94a, 0x0274,
+ 0xc94b, 0x1776,
+ 0xc96c, 0x1798,
+ 0xc9a1, 0x17ab,
+ 0xc9be, 0x1797,
+ 0xc9bf, 0x17c8,
+ 0xc9ed, 0x17f7,
+ 0xca40, 0x1809,
+ 0xcaa1, 0x1848,
+ 0xcaf7, 0x17f6,
+ 0xcaf8, 0x189e,
+ 0xcb40, 0x18a5,
+ 0xcba1, 0x18e4,
+ 0xcc40, 0x1942,
+ 0xcca1, 0x1981,
+ 0xcd40, 0x19df,
+ 0xcda1, 0x1a1e,
+ 0xce40, 0x1a7c,
+ 0xcea1, 0x1abb,
+ 0xcf40, 0x1b19,
+ 0xcfa1, 0x1b58,
+ 0xd040, 0x1bb6,
+ 0xd0a1, 0x1bf5,
+ 0xd140, 0x1c53,
+ 0xd1a1, 0x1c92,
+ 0xd240, 0x1cf0,
+ 0xd2a1, 0x1d2f,
+ 0xd340, 0x1d8d,
+ 0xd3a1, 0x1dcc,
+ 0xd440, 0x1e2a,
+ 0xd4a1, 0x1e69,
+ 0xd540, 0x1ec7,
+ 0xd5a1, 0x1f06,
+ 0xd640, 0x1f64,
+ 0xd6a1, 0x1fa3,
+ 0xd6cc, 0x2254,
+ 0xd6cd, 0x1fcf,
+ 0xd740, 0x2001,
+ 0xd77a, 0x22b9,
+ 0xd77b, 0x203b,
+ 0xd7a1, 0x203f,
+ 0xd840, 0x209d,
+ 0xd8a1, 0x20dc,
+ 0xd940, 0x213a,
+ 0xd9a1, 0x2179,
+ 0xda40, 0x21d7,
+ 0xdaa1, 0x2216,
+ 0xdadf, 0x1fce,
+ 0xdae0, 0x2255,
+ 0xdb40, 0x2274,
+ 0xdba1, 0x22b3,
+ 0xdba7, 0x22ba,
+ 0xdc40, 0x2312,
+ 0xdca1, 0x2351,
+ 0xdd40, 0x23af,
+ 0xdda1, 0x23ee,
+ 0xddfc, 0x2381,
+ 0xddfd, 0x2449,
+ 0xde40, 0x244b,
+ 0xdea1, 0x248a,
+ 0xdf40, 0x24e8,
+ 0xdfa1, 0x2527,
+ 0xe040, 0x2585,
+ 0xe0a1, 0x25c4,
+ 0xe140, 0x2622,
+ 0xe1a1, 0x2661,
+ 0xe240, 0x26bf,
+ 0xe2a1, 0x26fe,
+ 0xe340, 0x275c,
+ 0xe3a1, 0x279b,
+ 0xe440, 0x27f9,
+ 0xe4a1, 0x2838,
+ 0xe540, 0x2896,
+ 0xe5a1, 0x28d5,
+ 0xe640, 0x2933,
+ 0xe6a1, 0x2972,
+ 0xe740, 0x29d0,
+ 0xe7a1, 0x2a0f,
+ 0xe840, 0x2a6d,
+ 0xe8a1, 0x2aac,
+ 0xe8a3, 0x2aaf,
+ 0xe940, 0x2b0b,
+ 0xe976, 0x2b42,
+ 0xe9a1, 0x2b4b,
+ 0xea40, 0x2ba9,
+ 0xeaa1, 0x2be8,
+ 0xeb40, 0x2c46,
+ 0xeb5b, 0x2c62,
+ 0xeba1, 0x2c86,
+ 0xebf1, 0x2aae,
+ 0xebf2, 0x2cd6,
+ 0xec40, 0x2ce3,
+ 0xeca1, 0x2d22,
+ 0xecde, 0x2b41,
+ 0xecdf, 0x2d5f,
+ 0xed40, 0x2d7f,
+ 0xeda1, 0x2dbe,
+ 0xedaa, 0x2dc8,
+ 0xee40, 0x2e1d,
+ 0xeea1, 0x2e5c,
+ 0xeeeb, 0x3014,
+ 0xeeec, 0x2ea6,
+ 0xef40, 0x2eb9,
+ 0xefa1, 0x2ef8,
+ 0xf040, 0x2f56,
+ 0xf056, 0x2dc7,
+ 0xf057, 0x2f6c,
+ 0xf0a1, 0x2f94,
+ 0xf0cb, 0x2c61,
+ 0xf0cc, 0x2fbe,
+ 0xf140, 0x2ff1,
+ 0xf163, 0x3015,
+ 0xf16b, 0x3160,
+ 0xf16c, 0x301d,
+ 0xf1a1, 0x3030,
+ 0xf240, 0x308e,
+ 0xf268, 0x31ef,
+ 0xf269, 0x30b6,
+ 0xf2a1, 0x30cc,
+ 0xf2c3, 0x30ef,
+ 0xf340, 0x312b,
+ 0xf375, 0x3161,
+ 0xf3a1, 0x316b,
+ 0xf440, 0x31c9,
+ 0xf466, 0x31f0,
+ 0xf4a1, 0x3209,
+ 0xf4b5, 0x30ee,
+ 0xf4b6, 0x321d,
+ 0xf4fd, 0x3265,
+ 0xf540, 0x3267,
+ 0xf5a1, 0x32a6,
+ 0xf640, 0x3304,
+ 0xf663, 0x3264,
+ 0xf664, 0x3327,
+ 0xf6a1, 0x3342,
+ 0xf740, 0x33a0,
+ 0xf7a1, 0x33df,
+ 0xf840, 0x343d,
+ 0xf8a1, 0x347c,
+ 0xf940, 0x34da,
+ 0xf977, 0x3512,
+ 0xf9a1, 0x351a,
+ 0xf9c4, 0x3511,
+ 0xf9c5, 0x353d,
+ 0xf9c6, 0x3549,
+ 0xf9c7, 0x353e,
+ 0xf9d2, 0x354a,
+ 0xa14b, 0x354e,
+ 0xa15a, 0x35af,
+ 0xa15c, 0x35b1,
+ 0xa15d, 0x0082,
+ 0xa161, 0x0086,
+ 0xa165, 0x008a,
+ 0xa169, 0x008e,
+ 0xa16d, 0x0092,
+ 0xa171, 0x0096,
+ 0xa175, 0x009a,
+ 0xa179, 0x009e,
+ 0xa1e3, 0x354f,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 cns13HKdlbB5VEnc16 = {
+ 1,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
+ 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010,
+ 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018,
+ 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020,
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028,
+ 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030,
+ 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038,
+ 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040,
+ 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048,
+ 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050,
+ 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
+ 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ cns13HKdlbB5VMap2, 920
+};
+
+static Gushort cns13HKgccsB5HMap2[1106] = {
+ 0x0000, 0x0000,
+ 0x8a40, 0x4308,
+ 0x8aa1, 0x4347,
+ 0x8b41, 0x438c,
+ 0x8b45, 0x438e,
+ 0x8b47, 0x438f,
+ 0x8b49, 0x4390,
+ 0x8b4b, 0x4391,
+ 0x8b4d, 0x4392,
+ 0x8b54, 0x4396,
+ 0x8b58, 0x4397,
+ 0x8b5a, 0x4398,
+ 0x8e40, 0x372b,
+ 0x8e46, 0x3730,
+ 0x8e6c, 0x3755,
+ 0x8e77, 0x375f,
+ 0x8e7e, 0x0121,
+ 0x8ea1, 0x3766,
+ 0x8ea7, 0x376b,
+ 0x8eca, 0x378d,
+ 0x8ee6, 0x37a8,
+ 0x8ef0, 0x37b1,
+ 0x8f40, 0x37c0,
+ 0x8f5a, 0x37d9,
+ 0x8f60, 0x37de,
+ 0x8f68, 0x37e5,
+ 0x8fa1, 0x37fc,
+ 0x8fc6, 0x3820,
+ 0x8fc8, 0x3821,
+ 0x8fdb, 0x3833,
+ 0x8ffd, 0x3854,
+ 0x9040, 0x3856,
+ 0x905e, 0x3872,
+ 0x9070, 0x3883,
+ 0x907a, 0x36e9,
+ 0x907b, 0x388d,
+ 0x90a1, 0x3891,
+ 0x90a7, 0x3896,
+ 0x90b9, 0x38a7,
+ 0x9140, 0x38ed,
+ 0x9166, 0x3912,
+ 0x916f, 0x391a,
+ 0x91a1, 0x3929,
+ 0x91a3, 0x392a,
+ 0x9240, 0x3986,
+ 0x92a1, 0x39c5,
+ 0x92af, 0x0119,
+ 0x92b1, 0x011c,
+ 0x92b2, 0x011b,
+ 0x92b3, 0x39d3,
+ 0x92e6, 0x3a05,
+ 0x92f3, 0x3a11,
+ 0x9340, 0x3a1d,
+ 0x9369, 0x3a45,
+ 0x93a1, 0x3a5b,
+ 0x93ab, 0x3a64,
+ 0x93c3, 0x3a7b,
+ 0x93e6, 0x3a9d,
+ 0x93ec, 0x3aa2,
+ 0x9440, 0x3ab5,
+ 0x9447, 0x3abb,
+ 0x94a1, 0x3af3,
+ 0x9540, 0x3b51,
+ 0x954e, 0x3b5e,
+ 0x955b, 0x3b6a,
+ 0x95a1, 0x3b8e,
+ 0x95c7, 0x3bb3,
+ 0x9640, 0x3beb,
+ 0x96a1, 0x3c2a,
+ 0x96d5, 0x3c5d,
+ 0x9740, 0x3c87,
+ 0x97a1, 0x3cc6,
+ 0x9840, 0x3d24,
+ 0x9877, 0x3d59,
+ 0x987a, 0x3d5a,
+ 0x98a3, 0x3d5b,
+ 0x98af, 0x3d5c,
+ 0x98b6, 0x3d5d,
+ 0x98b9, 0x3d5e,
+ 0x98bd, 0x3d5f,
+ 0x98c2, 0x3d61,
+ 0x98c4, 0x3d62,
+ 0x98c6, 0x3d63,
+ 0x98e3, 0x3d65,
+ 0x98e7, 0x3d66,
+ 0x98ed, 0x3d67,
+ 0x98f0, 0x3d68,
+ 0x98f2, 0x3d69,
+ 0x98fc, 0x3d6a,
+ 0x9943, 0x3d6b,
+ 0x9945, 0x3d6c,
+ 0x994f, 0x3d6d,
+ 0x996a, 0x3d6e,
+ 0x996e, 0x3d6f,
+ 0x9975, 0x3d70,
+ 0x9978, 0x3d71,
+ 0x99a2, 0x3d72,
+ 0x99ae, 0x3d73,
+ 0x99b6, 0x3d74,
+ 0x99ba, 0x3d75,
+ 0x99e2, 0x3d76,
+ 0x99f4, 0x3d77,
+ 0x9a4a, 0x3d78,
+ 0x9a4c, 0x3d79,
+ 0x9a59, 0x3d7a,
+ 0x9a61, 0x3d7b,
+ 0x9a68, 0x3d7c,
+ 0x9a73, 0x3d7d,
+ 0x9a7e, 0x3d7e,
+ 0x9ab2, 0x3d7f,
+ 0x9ab7, 0x3d80,
+ 0x9ab9, 0x3d81,
+ 0x9abb, 0x3d82,
+ 0x9ac7, 0x3d83,
+ 0x9ad0, 0x3d84,
+ 0x9ad2, 0x3d85,
+ 0x9ad9, 0x3d86,
+ 0x9ae2, 0x3d89,
+ 0x9ae4, 0x3d8a,
+ 0x9ae8, 0x3d8b,
+ 0x9af2, 0x3d8c,
+ 0x9af6, 0x3d8d,
+ 0x9afb, 0x3d8e,
+ 0x9b46, 0x3d8f,
+ 0x9b4a, 0x3d90,
+ 0x9b4c, 0x3d91,
+ 0x9b54, 0x3d92,
+ 0x9b58, 0x3d93,
+ 0x9b5a, 0x3d94,
+ 0x9b5c, 0x3d95,
+ 0x9b5e, 0x3d96,
+ 0x9b70, 0x3d98,
+ 0x9b76, 0x3d9c,
+ 0x9b7b, 0x3d9f,
+ 0x9b7e, 0x3da1,
+ 0x9ba1, 0x3da2,
+ 0x9ba3, 0x3da3,
+ 0x9ba7, 0x3da5,
+ 0x9bac, 0x3da9,
+ 0x9baf, 0x3daa,
+ 0x9bb2, 0x3dab,
+ 0x9bbe, 0x3db3,
+ 0x9bc0, 0x3db4,
+ 0x9bca, 0x3dbb,
+ 0x9bcc, 0x3dbc,
+ 0x9bd0, 0x3dbd,
+ 0x9bd3, 0x3dbf,
+ 0x9bd5, 0x3dc0,
+ 0x9bd8, 0x3dc1,
+ 0x9bdd, 0x3dc4,
+ 0x9bde, 0x1c14,
+ 0x9bdf, 0x3dc5,
+ 0x9be1, 0x3dc6,
+ 0x9be3, 0x3dc7,
+ 0x9be7, 0x3dc8,
+ 0x9be9, 0x3dc9,
+ 0x9bee, 0x3dcd,
+ 0x9bf3, 0x3dcf,
+ 0x9bf6, 0x3dd0,
+ 0x9bf8, 0x3dd1,
+ 0x9bfb, 0x3dd3,
+ 0x9c40, 0x3dd5,
+ 0x9c44, 0x3dd8,
+ 0x9c48, 0x3ddb,
+ 0x9c4a, 0x3ddc,
+ 0x9c4d, 0x3ddd,
+ 0x9c55, 0x3de4,
+ 0x9c57, 0x3de5,
+ 0x9c5d, 0x3dea,
+ 0x9c60, 0x3deb,
+ 0x9c62, 0x3dec,
+ 0x9c64, 0x3ded,
+ 0x9c68, 0x3df0,
+ 0x9c6a, 0x3df1,
+ 0x9c6b, 0x346a,
+ 0x9c6d, 0x3df2,
+ 0x9c6f, 0x3df3,
+ 0x9c75, 0x3df7,
+ 0x9c79, 0x3dfa,
+ 0x9c7b, 0x3dfb,
+ 0x9c7e, 0x3dfd,
+ 0x9ca1, 0x3dfe,
+ 0x9ca5, 0x3e00,
+ 0x9ca8, 0x3e01,
+ 0x9cab, 0x3e03,
+ 0x9cad, 0x3e04,
+ 0x9cb1, 0x3e06,
+ 0x9cbc, 0x3e10,
+ 0x9cc6, 0x3e17,
+ 0x9ccf, 0x3e1f,
+ 0x9cd8, 0x3e24,
+ 0x9cdc, 0x3e27,
+ 0x9ce7, 0x3e31,
+ 0x9ceb, 0x3e34,
+ 0x9cee, 0x3e36,
+ 0x9cfd, 0x3e42,
+ 0x9d46, 0x3e43,
+ 0x9d49, 0x3e44,
+ 0x9d4c, 0x3e46,
+ 0x9d4f, 0x3e48,
+ 0x9d51, 0x3e49,
+ 0x9d55, 0x3e4a,
+ 0x9d57, 0x25c1,
+ 0x9d5a, 0x3e4b,
+ 0x9d62, 0x3e4c,
+ 0x9d64, 0x3e4d,
+ 0x9d79, 0x3e4e,
+ 0x9d7e, 0x3e4f,
+ 0x9da5, 0x3e50,
+ 0x9daa, 0x3e54,
+ 0x9dac, 0x3e55,
+ 0x9db0, 0x3e58,
+ 0x9db3, 0x3e59,
+ 0x9db5, 0x3e5a,
+ 0x9db7, 0x3e5b,
+ 0x9dbc, 0x3e5c,
+ 0x9dbf, 0x3e5e,
+ 0x9dc3, 0x3e60,
+ 0x9dc7, 0x3e62,
+ 0x9dca, 0x3e64,
+ 0x9dcd, 0x3e65,
+ 0x9dd3, 0x3e6a,
+ 0x9dda, 0x3e6d,
+ 0x9dfd, 0x3e8f,
+ 0x9e40, 0x3e91,
+ 0x9e64, 0x3eb4,
+ 0x9e68, 0x3eb6,
+ 0x9e6a, 0x3eb7,
+ 0x9e71, 0x3eb8,
+ 0x9e73, 0x3eb9,
+ 0x9e77, 0x3eba,
+ 0x9e7a, 0x3ebc,
+ 0x9e7c, 0x3ebd,
+ 0x9e7e, 0x3ebe,
+ 0x9ea1, 0x3ebf,
+ 0x9ea4, 0x3ec1,
+ 0x9ea9, 0x3ec4,
+ 0x9eac, 0x3ec6,
+ 0x9eaf, 0x3ec8,
+ 0x9eb4, 0x3ecb,
+ 0x9eb6, 0x3ecc,
+ 0x9eb9, 0x3ece,
+ 0x9ebc, 0x3ecf,
+ 0x9ebf, 0x3ed0,
+ 0x9ec4, 0x3ed2,
+ 0x9ec7, 0x3ed4,
+ 0x9ecc, 0x3ed8,
+ 0x9ed0, 0x3eda,
+ 0x9ed3, 0x3edc,
+ 0x9ed6, 0x3edd,
+ 0x9eda, 0x3edf,
+ 0x9ef3, 0x3ef7,
+ 0x9ef9, 0x3efa,
+ 0x9efc, 0x3efc,
+ 0x9f40, 0x3eff,
+ 0x9f44, 0x3f02,
+ 0x9f49, 0x3f06,
+ 0x9f4d, 0x3f08,
+ 0x9f69, 0x3f23,
+ 0x9f71, 0x3f2a,
+ 0x9fa1, 0x3f38,
+ 0x9fb6, 0x3f4c,
+ 0x9fbc, 0x3f51,
+ 0x9fc0, 0x3f54,
+ 0x9fc2, 0x3f55,
+ 0x9fe5, 0x3f77,
+ 0x9ffa, 0x3f8b,
+ 0xa041, 0x3f90,
+ 0xa048, 0x3f96,
+ 0xa056, 0x3fa3,
+ 0xa06e, 0x3fba,
+ 0xa07c, 0x3fc7,
+ 0xa0a1, 0x3fca,
+ 0xa0a3, 0x3fcb,
+ 0xa0a8, 0x3fcf,
+ 0xa0c6, 0x3fec,
+ 0xa0d1, 0x3ff6,
+ 0xa0e4, 0x4008,
+ 0xa140, 0x0063,
+ 0xa159, 0x35af,
+ 0xa15d, 0x0080,
+ 0xa1a1, 0x00a2,
+ 0xa1f6, 0x00f8,
+ 0xa1f7, 0x00f7,
+ 0xa1f8, 0x00f9,
+ 0xa240, 0x0100,
+ 0xa2a1, 0x013f,
+ 0xa340, 0x019d,
+ 0xa3a1, 0x01dc,
+ 0xa3bd, 0x01f7,
+ 0xa440, 0x0253,
+ 0xa4a1, 0x0292,
+ 0xa540, 0x02f0,
+ 0xa5a1, 0x032f,
+ 0xa640, 0x038d,
+ 0xa6a1, 0x03cc,
+ 0xa740, 0x042a,
+ 0xa7a1, 0x0469,
+ 0xa840, 0x04c7,
+ 0xa8a1, 0x0506,
+ 0xa940, 0x0564,
+ 0xa9a1, 0x05a3,
+ 0xaa40, 0x0601,
+ 0xaaa1, 0x0640,
+ 0xab40, 0x069e,
+ 0xaba1, 0x06dd,
+ 0xac40, 0x073b,
+ 0xaca1, 0x077a,
+ 0xacfe, 0x097f,
+ 0xad40, 0x07d7,
+ 0xada1, 0x0816,
+ 0xae40, 0x0874,
+ 0xaea1, 0x08b3,
+ 0xaf40, 0x0911,
+ 0xafa1, 0x0950,
+ 0xafd0, 0x0980,
+ 0xb040, 0x09af,
+ 0xb0a1, 0x09ee,
+ 0xb140, 0x0a4c,
+ 0xb1a1, 0x0a8b,
+ 0xb240, 0x0ae9,
+ 0xb2a1, 0x0b28,
+ 0xb340, 0x0b86,
+ 0xb3a1, 0x0bc5,
+ 0xb440, 0x0c23,
+ 0xb4a1, 0x0c62,
+ 0xb540, 0x0cc0,
+ 0xb5a1, 0x0cff,
+ 0xb640, 0x0d5d,
+ 0xb6a1, 0x0d9c,
+ 0xb740, 0x0dfa,
+ 0xb7a1, 0x0e39,
+ 0xb840, 0x0e97,
+ 0xb8a1, 0x0ed6,
+ 0xb940, 0x0f34,
+ 0xb9a1, 0x0f73,
+ 0xba40, 0x0fd1,
+ 0xbaa1, 0x1010,
+ 0xbb40, 0x106e,
+ 0xbba1, 0x10ad,
+ 0xbbc8, 0x10d5,
+ 0xbc40, 0x110c,
+ 0xbca1, 0x114b,
+ 0xbd40, 0x11a9,
+ 0xbda1, 0x11e8,
+ 0xbe40, 0x1246,
+ 0xbe52, 0x10d4,
+ 0xbe53, 0x1258,
+ 0xbea1, 0x1284,
+ 0xbf40, 0x12e2,
+ 0xbfa1, 0x1321,
+ 0xc040, 0x137f,
+ 0xc0a1, 0x13be,
+ 0xc140, 0x141c,
+ 0xc1a1, 0x145b,
+ 0xc1ab, 0x1466,
+ 0xc240, 0x14ba,
+ 0xc2a1, 0x14f9,
+ 0xc2cb, 0x1465,
+ 0xc2cc, 0x1523,
+ 0xc340, 0x1556,
+ 0xc361, 0x1578,
+ 0xc3a1, 0x1596,
+ 0xc3b9, 0x15af,
+ 0xc3ba, 0x15ae,
+ 0xc3bb, 0x15b0,
+ 0xc440, 0x15f4,
+ 0xc456, 0x1577,
+ 0xc457, 0x160a,
+ 0xc4a1, 0x1632,
+ 0xc540, 0x1690,
+ 0xc5a1, 0x16cf,
+ 0xc640, 0x172d,
+ 0xc940, 0x176c,
+ 0xc94a, 0x0274,
+ 0xc94b, 0x1776,
+ 0xc96c, 0x1798,
+ 0xc9a1, 0x17ab,
+ 0xc9be, 0x1797,
+ 0xc9bf, 0x17c8,
+ 0xc9ed, 0x17f7,
+ 0xca40, 0x1809,
+ 0xcaa1, 0x1848,
+ 0xcaf7, 0x17f6,
+ 0xcaf8, 0x189e,
+ 0xcb40, 0x18a5,
+ 0xcba1, 0x18e4,
+ 0xcc40, 0x1942,
+ 0xcca1, 0x1981,
+ 0xcd40, 0x19df,
+ 0xcda1, 0x1a1e,
+ 0xce40, 0x1a7c,
+ 0xcea1, 0x1abb,
+ 0xcf40, 0x1b19,
+ 0xcfa1, 0x1b58,
+ 0xd040, 0x1bb6,
+ 0xd0a1, 0x1bf5,
+ 0xd140, 0x1c53,
+ 0xd1a1, 0x1c92,
+ 0xd240, 0x1cf0,
+ 0xd2a1, 0x1d2f,
+ 0xd340, 0x1d8d,
+ 0xd3a1, 0x1dcc,
+ 0xd440, 0x1e2a,
+ 0xd4a1, 0x1e69,
+ 0xd540, 0x1ec7,
+ 0xd5a1, 0x1f06,
+ 0xd640, 0x1f64,
+ 0xd6a1, 0x1fa3,
+ 0xd6cc, 0x2254,
+ 0xd6cd, 0x1fcf,
+ 0xd740, 0x2001,
+ 0xd77a, 0x22b9,
+ 0xd77b, 0x203b,
+ 0xd7a1, 0x203f,
+ 0xd840, 0x209d,
+ 0xd8a1, 0x20dc,
+ 0xd940, 0x213a,
+ 0xd9a1, 0x2179,
+ 0xda40, 0x21d7,
+ 0xdaa1, 0x2216,
+ 0xdadf, 0x1fce,
+ 0xdae0, 0x2255,
+ 0xdb40, 0x2274,
+ 0xdba1, 0x22b3,
+ 0xdba7, 0x22ba,
+ 0xdc40, 0x2312,
+ 0xdca1, 0x2351,
+ 0xdd40, 0x23af,
+ 0xdda1, 0x23ee,
+ 0xddfc, 0x2381,
+ 0xddfd, 0x2449,
+ 0xde40, 0x244b,
+ 0xdea1, 0x248a,
+ 0xdf40, 0x24e8,
+ 0xdfa1, 0x2527,
+ 0xe040, 0x2585,
+ 0xe0a1, 0x25c4,
+ 0xe140, 0x2622,
+ 0xe1a1, 0x2661,
+ 0xe240, 0x26bf,
+ 0xe2a1, 0x26fe,
+ 0xe340, 0x275c,
+ 0xe3a1, 0x279b,
+ 0xe440, 0x27f9,
+ 0xe4a1, 0x2838,
+ 0xe540, 0x2896,
+ 0xe5a1, 0x28d5,
+ 0xe640, 0x2933,
+ 0xe6a1, 0x2972,
+ 0xe740, 0x29d0,
+ 0xe7a1, 0x2a0f,
+ 0xe840, 0x2a6d,
+ 0xe8a1, 0x2aac,
+ 0xe8a3, 0x2aaf,
+ 0xe940, 0x2b0b,
+ 0xe976, 0x2b42,
+ 0xe9a1, 0x2b4b,
+ 0xea40, 0x2ba9,
+ 0xeaa1, 0x2be8,
+ 0xeb40, 0x2c46,
+ 0xeb5b, 0x2c62,
+ 0xeba1, 0x2c86,
+ 0xebf1, 0x2aae,
+ 0xebf2, 0x2cd6,
+ 0xec40, 0x2ce3,
+ 0xeca1, 0x2d22,
+ 0xecde, 0x2b41,
+ 0xecdf, 0x2d5f,
+ 0xed40, 0x2d7f,
+ 0xeda1, 0x2dbe,
+ 0xedaa, 0x2dc8,
+ 0xee40, 0x2e1d,
+ 0xeea1, 0x2e5c,
+ 0xeeeb, 0x3014,
+ 0xeeec, 0x2ea6,
+ 0xef40, 0x2eb9,
+ 0xefa1, 0x2ef8,
+ 0xf040, 0x2f56,
+ 0xf056, 0x2dc7,
+ 0xf057, 0x2f6c,
+ 0xf0a1, 0x2f94,
+ 0xf0cb, 0x2c61,
+ 0xf0cc, 0x2fbe,
+ 0xf140, 0x2ff1,
+ 0xf163, 0x3015,
+ 0xf16b, 0x3160,
+ 0xf16c, 0x301d,
+ 0xf1a1, 0x3030,
+ 0xf240, 0x308e,
+ 0xf268, 0x31ef,
+ 0xf269, 0x30b6,
+ 0xf2a1, 0x30cc,
+ 0xf2c3, 0x30ef,
+ 0xf340, 0x312b,
+ 0xf375, 0x3161,
+ 0xf3a1, 0x316b,
+ 0xf440, 0x31c9,
+ 0xf466, 0x31f0,
+ 0xf4a1, 0x3209,
+ 0xf4b5, 0x30ee,
+ 0xf4b6, 0x321d,
+ 0xf4fd, 0x3265,
+ 0xf540, 0x3267,
+ 0xf5a1, 0x32a6,
+ 0xf640, 0x3304,
+ 0xf663, 0x3264,
+ 0xf664, 0x3327,
+ 0xf6a1, 0x3342,
+ 0xf740, 0x33a0,
+ 0xf7a1, 0x33df,
+ 0xf840, 0x343d,
+ 0xf8a1, 0x347c,
+ 0xf940, 0x34da,
+ 0xf977, 0x3512,
+ 0xf9a1, 0x351a,
+ 0xf9c4, 0x3511,
+ 0xf9c5, 0x353d,
+ 0xf9c6, 0x3549,
+ 0xf9c7, 0x353e,
+ 0xf9d2, 0x354a,
+ 0xfa40, 0x400b,
+ 0xfaa1, 0x404a,
+ 0xfb40, 0x40a8,
+ 0xfba1, 0x40e7,
+ 0xfbc0, 0x4105,
+ 0xfbce, 0x4112,
+ 0xfc40, 0x4143,
+ 0xfc4b, 0x414d,
+ 0xfc4f, 0x212f,
+ 0xfc50, 0x4151,
+ 0xfc53, 0x4153,
+ 0xfc64, 0x4163,
+ 0xfc76, 0x4174,
+ 0xfca1, 0x417d,
+ 0xfcb9, 0x115f,
+ 0xfcba, 0x4195,
+ 0xfcbd, 0x4197,
+ 0xfce4, 0x41bd,
+ 0xfcef, 0x41c7,
+ 0xfd40, 0x41d7,
+ 0xfd4a, 0x41e0,
+ 0xfda1, 0x4215,
+ 0xfdf3, 0x4266,
+ 0xfe40, 0x4272,
+ 0xfe6e, 0x429f,
+ 0xfe79, 0x42a9,
+ 0xfea1, 0x42af,
+ 0xfeaa, 0x0120,
+ 0xfeab, 0x42b8,
+ 0xfee0, 0x42eb,
+ 0xfeef, 0x42f8,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 cns13HKgccsB5HEnc16 = {
+ 0,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
+ 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010,
+ 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018,
+ 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020,
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028,
+ 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030,
+ 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038,
+ 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040,
+ 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048,
+ 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050,
+ 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
+ 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ cns13HKgccsB5HMap2, 553
+};
+
+static Gushort cns13HKgccsB5VMap2[1130] = {
+ 0x0000, 0x0000,
+ 0x8a40, 0x4308,
+ 0x8aa1, 0x4347,
+ 0x8b41, 0x438c,
+ 0x8b45, 0x438e,
+ 0x8b47, 0x438f,
+ 0x8b49, 0x4390,
+ 0x8b4b, 0x4391,
+ 0x8b4d, 0x4392,
+ 0x8b54, 0x4396,
+ 0x8b58, 0x4397,
+ 0x8b5a, 0x4398,
+ 0x8e40, 0x372b,
+ 0x8e46, 0x3730,
+ 0x8e6c, 0x3755,
+ 0x8e77, 0x375f,
+ 0x8e7e, 0x0121,
+ 0x8ea1, 0x3766,
+ 0x8ea7, 0x376b,
+ 0x8eca, 0x378d,
+ 0x8ee6, 0x37a8,
+ 0x8ef0, 0x37b1,
+ 0x8f40, 0x37c0,
+ 0x8f5a, 0x37d9,
+ 0x8f60, 0x37de,
+ 0x8f68, 0x37e5,
+ 0x8fa1, 0x37fc,
+ 0x8fc6, 0x3820,
+ 0x8fc8, 0x3821,
+ 0x8fdb, 0x3833,
+ 0x8ffd, 0x3854,
+ 0x9040, 0x3856,
+ 0x905e, 0x3872,
+ 0x9070, 0x3883,
+ 0x907a, 0x36e9,
+ 0x907b, 0x388d,
+ 0x90a1, 0x3891,
+ 0x90a7, 0x3896,
+ 0x90b9, 0x38a7,
+ 0x9140, 0x38ed,
+ 0x9166, 0x3912,
+ 0x916f, 0x391a,
+ 0x91a1, 0x3929,
+ 0x91a3, 0x392a,
+ 0x9240, 0x3986,
+ 0x92a1, 0x39c5,
+ 0x92af, 0x0119,
+ 0x92b1, 0x011c,
+ 0x92b2, 0x011b,
+ 0x92b3, 0x39d3,
+ 0x92e6, 0x3a05,
+ 0x92f3, 0x3a11,
+ 0x9340, 0x3a1d,
+ 0x9369, 0x3a45,
+ 0x93a1, 0x3a5b,
+ 0x93ab, 0x3a64,
+ 0x93c3, 0x3a7b,
+ 0x93e6, 0x3a9d,
+ 0x93ec, 0x3aa2,
+ 0x9440, 0x3ab5,
+ 0x9447, 0x3abb,
+ 0x94a1, 0x3af3,
+ 0x9540, 0x3b51,
+ 0x954e, 0x3b5e,
+ 0x955b, 0x3b6a,
+ 0x95a1, 0x3b8e,
+ 0x95c7, 0x3bb3,
+ 0x9640, 0x3beb,
+ 0x96a1, 0x3c2a,
+ 0x96d5, 0x3c5d,
+ 0x9740, 0x3c87,
+ 0x97a1, 0x3cc6,
+ 0x9840, 0x3d24,
+ 0x9877, 0x3d59,
+ 0x987a, 0x3d5a,
+ 0x98a3, 0x3d5b,
+ 0x98af, 0x3d5c,
+ 0x98b6, 0x3d5d,
+ 0x98b9, 0x3d5e,
+ 0x98bd, 0x3d5f,
+ 0x98c2, 0x3d61,
+ 0x98c4, 0x3d62,
+ 0x98c6, 0x3d63,
+ 0x98e3, 0x3d65,
+ 0x98e7, 0x3d66,
+ 0x98ed, 0x3d67,
+ 0x98f0, 0x3d68,
+ 0x98f2, 0x3d69,
+ 0x98fc, 0x3d6a,
+ 0x9943, 0x3d6b,
+ 0x9945, 0x3d6c,
+ 0x994f, 0x3d6d,
+ 0x996a, 0x3d6e,
+ 0x996e, 0x3d6f,
+ 0x9975, 0x3d70,
+ 0x9978, 0x3d71,
+ 0x99a2, 0x3d72,
+ 0x99ae, 0x3d73,
+ 0x99b6, 0x3d74,
+ 0x99ba, 0x3d75,
+ 0x99e2, 0x3d76,
+ 0x99f4, 0x3d77,
+ 0x9a4a, 0x3d78,
+ 0x9a4c, 0x3d79,
+ 0x9a59, 0x3d7a,
+ 0x9a61, 0x3d7b,
+ 0x9a68, 0x3d7c,
+ 0x9a73, 0x3d7d,
+ 0x9a7e, 0x3d7e,
+ 0x9ab2, 0x3d7f,
+ 0x9ab7, 0x3d80,
+ 0x9ab9, 0x3d81,
+ 0x9abb, 0x3d82,
+ 0x9ac7, 0x3d83,
+ 0x9ad0, 0x3d84,
+ 0x9ad2, 0x3d85,
+ 0x9ad9, 0x3d86,
+ 0x9ae2, 0x3d89,
+ 0x9ae4, 0x3d8a,
+ 0x9ae8, 0x3d8b,
+ 0x9af2, 0x3d8c,
+ 0x9af6, 0x3d8d,
+ 0x9afb, 0x3d8e,
+ 0x9b46, 0x3d8f,
+ 0x9b4a, 0x3d90,
+ 0x9b4c, 0x3d91,
+ 0x9b54, 0x3d92,
+ 0x9b58, 0x3d93,
+ 0x9b5a, 0x3d94,
+ 0x9b5c, 0x3d95,
+ 0x9b5e, 0x3d96,
+ 0x9b70, 0x3d98,
+ 0x9b76, 0x3d9c,
+ 0x9b7b, 0x3d9f,
+ 0x9b7e, 0x3da1,
+ 0x9ba1, 0x3da2,
+ 0x9ba3, 0x3da3,
+ 0x9ba7, 0x3da5,
+ 0x9bac, 0x3da9,
+ 0x9baf, 0x3daa,
+ 0x9bb2, 0x3dab,
+ 0x9bbe, 0x3db3,
+ 0x9bc0, 0x3db4,
+ 0x9bca, 0x3dbb,
+ 0x9bcc, 0x3dbc,
+ 0x9bd0, 0x3dbd,
+ 0x9bd3, 0x3dbf,
+ 0x9bd5, 0x3dc0,
+ 0x9bd8, 0x3dc1,
+ 0x9bdd, 0x3dc4,
+ 0x9bde, 0x1c14,
+ 0x9bdf, 0x3dc5,
+ 0x9be1, 0x3dc6,
+ 0x9be3, 0x3dc7,
+ 0x9be7, 0x3dc8,
+ 0x9be9, 0x3dc9,
+ 0x9bee, 0x3dcd,
+ 0x9bf3, 0x3dcf,
+ 0x9bf6, 0x3dd0,
+ 0x9bf8, 0x3dd1,
+ 0x9bfb, 0x3dd3,
+ 0x9c40, 0x3dd5,
+ 0x9c44, 0x3dd8,
+ 0x9c48, 0x3ddb,
+ 0x9c4a, 0x3ddc,
+ 0x9c4d, 0x3ddd,
+ 0x9c55, 0x3de4,
+ 0x9c57, 0x3de5,
+ 0x9c5d, 0x3dea,
+ 0x9c60, 0x3deb,
+ 0x9c62, 0x3dec,
+ 0x9c64, 0x3ded,
+ 0x9c68, 0x3df0,
+ 0x9c6a, 0x3df1,
+ 0x9c6b, 0x346a,
+ 0x9c6d, 0x3df2,
+ 0x9c6f, 0x3df3,
+ 0x9c75, 0x3df7,
+ 0x9c79, 0x3dfa,
+ 0x9c7b, 0x3dfb,
+ 0x9c7e, 0x3dfd,
+ 0x9ca1, 0x3dfe,
+ 0x9ca5, 0x3e00,
+ 0x9ca8, 0x3e01,
+ 0x9cab, 0x3e03,
+ 0x9cad, 0x3e04,
+ 0x9cb1, 0x3e06,
+ 0x9cbc, 0x3e10,
+ 0x9cc6, 0x3e17,
+ 0x9ccf, 0x3e1f,
+ 0x9cd8, 0x3e24,
+ 0x9cdc, 0x3e27,
+ 0x9ce7, 0x3e31,
+ 0x9ceb, 0x3e34,
+ 0x9cee, 0x3e36,
+ 0x9cfd, 0x3e42,
+ 0x9d46, 0x3e43,
+ 0x9d49, 0x3e44,
+ 0x9d4c, 0x3e46,
+ 0x9d4f, 0x3e48,
+ 0x9d51, 0x3e49,
+ 0x9d55, 0x3e4a,
+ 0x9d57, 0x25c1,
+ 0x9d5a, 0x3e4b,
+ 0x9d62, 0x3e4c,
+ 0x9d64, 0x3e4d,
+ 0x9d79, 0x3e4e,
+ 0x9d7e, 0x3e4f,
+ 0x9da5, 0x3e50,
+ 0x9daa, 0x3e54,
+ 0x9dac, 0x3e55,
+ 0x9db0, 0x3e58,
+ 0x9db3, 0x3e59,
+ 0x9db5, 0x3e5a,
+ 0x9db7, 0x3e5b,
+ 0x9dbc, 0x3e5c,
+ 0x9dbf, 0x3e5e,
+ 0x9dc3, 0x3e60,
+ 0x9dc7, 0x3e62,
+ 0x9dca, 0x3e64,
+ 0x9dcd, 0x3e65,
+ 0x9dd3, 0x3e6a,
+ 0x9dda, 0x3e6d,
+ 0x9dfd, 0x3e8f,
+ 0x9e40, 0x3e91,
+ 0x9e64, 0x3eb4,
+ 0x9e68, 0x3eb6,
+ 0x9e6a, 0x3eb7,
+ 0x9e71, 0x3eb8,
+ 0x9e73, 0x3eb9,
+ 0x9e77, 0x3eba,
+ 0x9e7a, 0x3ebc,
+ 0x9e7c, 0x3ebd,
+ 0x9e7e, 0x3ebe,
+ 0x9ea1, 0x3ebf,
+ 0x9ea4, 0x3ec1,
+ 0x9ea9, 0x3ec4,
+ 0x9eac, 0x3ec6,
+ 0x9eaf, 0x3ec8,
+ 0x9eb4, 0x3ecb,
+ 0x9eb6, 0x3ecc,
+ 0x9eb9, 0x3ece,
+ 0x9ebc, 0x3ecf,
+ 0x9ebf, 0x3ed0,
+ 0x9ec4, 0x3ed2,
+ 0x9ec7, 0x3ed4,
+ 0x9ecc, 0x3ed8,
+ 0x9ed0, 0x3eda,
+ 0x9ed3, 0x3edc,
+ 0x9ed6, 0x3edd,
+ 0x9eda, 0x3edf,
+ 0x9ef3, 0x3ef7,
+ 0x9ef9, 0x3efa,
+ 0x9efc, 0x3efc,
+ 0x9f40, 0x3eff,
+ 0x9f44, 0x3f02,
+ 0x9f49, 0x3f06,
+ 0x9f4d, 0x3f08,
+ 0x9f69, 0x3f23,
+ 0x9f71, 0x3f2a,
+ 0x9fa1, 0x3f38,
+ 0x9fb6, 0x3f4c,
+ 0x9fbc, 0x3f51,
+ 0x9fc0, 0x3f54,
+ 0x9fc2, 0x3f55,
+ 0x9fe5, 0x3f77,
+ 0x9ffa, 0x3f8b,
+ 0xa041, 0x3f90,
+ 0xa048, 0x3f96,
+ 0xa056, 0x3fa3,
+ 0xa06e, 0x3fba,
+ 0xa07c, 0x3fc7,
+ 0xa0a1, 0x3fca,
+ 0xa0a3, 0x3fcb,
+ 0xa0a8, 0x3fcf,
+ 0xa0c6, 0x3fec,
+ 0xa0d1, 0x3ff6,
+ 0xa0e4, 0x4008,
+ 0xa140, 0x0063,
+ 0xa159, 0x35af,
+ 0xa15d, 0x0080,
+ 0xa1a1, 0x00a2,
+ 0xa1f6, 0x00f8,
+ 0xa1f7, 0x00f7,
+ 0xa1f8, 0x00f9,
+ 0xa240, 0x0100,
+ 0xa2a1, 0x013f,
+ 0xa340, 0x019d,
+ 0xa3a1, 0x01dc,
+ 0xa3bd, 0x01f7,
+ 0xa440, 0x0253,
+ 0xa4a1, 0x0292,
+ 0xa540, 0x02f0,
+ 0xa5a1, 0x032f,
+ 0xa640, 0x038d,
+ 0xa6a1, 0x03cc,
+ 0xa740, 0x042a,
+ 0xa7a1, 0x0469,
+ 0xa840, 0x04c7,
+ 0xa8a1, 0x0506,
+ 0xa940, 0x0564,
+ 0xa9a1, 0x05a3,
+ 0xaa40, 0x0601,
+ 0xaaa1, 0x0640,
+ 0xab40, 0x069e,
+ 0xaba1, 0x06dd,
+ 0xac40, 0x073b,
+ 0xaca1, 0x077a,
+ 0xacfe, 0x097f,
+ 0xad40, 0x07d7,
+ 0xada1, 0x0816,
+ 0xae40, 0x0874,
+ 0xaea1, 0x08b3,
+ 0xaf40, 0x0911,
+ 0xafa1, 0x0950,
+ 0xafd0, 0x0980,
+ 0xb040, 0x09af,
+ 0xb0a1, 0x09ee,
+ 0xb140, 0x0a4c,
+ 0xb1a1, 0x0a8b,
+ 0xb240, 0x0ae9,
+ 0xb2a1, 0x0b28,
+ 0xb340, 0x0b86,
+ 0xb3a1, 0x0bc5,
+ 0xb440, 0x0c23,
+ 0xb4a1, 0x0c62,
+ 0xb540, 0x0cc0,
+ 0xb5a1, 0x0cff,
+ 0xb640, 0x0d5d,
+ 0xb6a1, 0x0d9c,
+ 0xb740, 0x0dfa,
+ 0xb7a1, 0x0e39,
+ 0xb840, 0x0e97,
+ 0xb8a1, 0x0ed6,
+ 0xb940, 0x0f34,
+ 0xb9a1, 0x0f73,
+ 0xba40, 0x0fd1,
+ 0xbaa1, 0x1010,
+ 0xbb40, 0x106e,
+ 0xbba1, 0x10ad,
+ 0xbbc8, 0x10d5,
+ 0xbc40, 0x110c,
+ 0xbca1, 0x114b,
+ 0xbd40, 0x11a9,
+ 0xbda1, 0x11e8,
+ 0xbe40, 0x1246,
+ 0xbe52, 0x10d4,
+ 0xbe53, 0x1258,
+ 0xbea1, 0x1284,
+ 0xbf40, 0x12e2,
+ 0xbfa1, 0x1321,
+ 0xc040, 0x137f,
+ 0xc0a1, 0x13be,
+ 0xc140, 0x141c,
+ 0xc1a1, 0x145b,
+ 0xc1ab, 0x1466,
+ 0xc240, 0x14ba,
+ 0xc2a1, 0x14f9,
+ 0xc2cb, 0x1465,
+ 0xc2cc, 0x1523,
+ 0xc340, 0x1556,
+ 0xc361, 0x1578,
+ 0xc3a1, 0x1596,
+ 0xc3b9, 0x15af,
+ 0xc3ba, 0x15ae,
+ 0xc3bb, 0x15b0,
+ 0xc440, 0x15f4,
+ 0xc456, 0x1577,
+ 0xc457, 0x160a,
+ 0xc4a1, 0x1632,
+ 0xc540, 0x1690,
+ 0xc5a1, 0x16cf,
+ 0xc640, 0x172d,
+ 0xc940, 0x176c,
+ 0xc94a, 0x0274,
+ 0xc94b, 0x1776,
+ 0xc96c, 0x1798,
+ 0xc9a1, 0x17ab,
+ 0xc9be, 0x1797,
+ 0xc9bf, 0x17c8,
+ 0xc9ed, 0x17f7,
+ 0xca40, 0x1809,
+ 0xcaa1, 0x1848,
+ 0xcaf7, 0x17f6,
+ 0xcaf8, 0x189e,
+ 0xcb40, 0x18a5,
+ 0xcba1, 0x18e4,
+ 0xcc40, 0x1942,
+ 0xcca1, 0x1981,
+ 0xcd40, 0x19df,
+ 0xcda1, 0x1a1e,
+ 0xce40, 0x1a7c,
+ 0xcea1, 0x1abb,
+ 0xcf40, 0x1b19,
+ 0xcfa1, 0x1b58,
+ 0xd040, 0x1bb6,
+ 0xd0a1, 0x1bf5,
+ 0xd140, 0x1c53,
+ 0xd1a1, 0x1c92,
+ 0xd240, 0x1cf0,
+ 0xd2a1, 0x1d2f,
+ 0xd340, 0x1d8d,
+ 0xd3a1, 0x1dcc,
+ 0xd440, 0x1e2a,
+ 0xd4a1, 0x1e69,
+ 0xd540, 0x1ec7,
+ 0xd5a1, 0x1f06,
+ 0xd640, 0x1f64,
+ 0xd6a1, 0x1fa3,
+ 0xd6cc, 0x2254,
+ 0xd6cd, 0x1fcf,
+ 0xd740, 0x2001,
+ 0xd77a, 0x22b9,
+ 0xd77b, 0x203b,
+ 0xd7a1, 0x203f,
+ 0xd840, 0x209d,
+ 0xd8a1, 0x20dc,
+ 0xd940, 0x213a,
+ 0xd9a1, 0x2179,
+ 0xda40, 0x21d7,
+ 0xdaa1, 0x2216,
+ 0xdadf, 0x1fce,
+ 0xdae0, 0x2255,
+ 0xdb40, 0x2274,
+ 0xdba1, 0x22b3,
+ 0xdba7, 0x22ba,
+ 0xdc40, 0x2312,
+ 0xdca1, 0x2351,
+ 0xdd40, 0x23af,
+ 0xdda1, 0x23ee,
+ 0xddfc, 0x2381,
+ 0xddfd, 0x2449,
+ 0xde40, 0x244b,
+ 0xdea1, 0x248a,
+ 0xdf40, 0x24e8,
+ 0xdfa1, 0x2527,
+ 0xe040, 0x2585,
+ 0xe0a1, 0x25c4,
+ 0xe140, 0x2622,
+ 0xe1a1, 0x2661,
+ 0xe240, 0x26bf,
+ 0xe2a1, 0x26fe,
+ 0xe340, 0x275c,
+ 0xe3a1, 0x279b,
+ 0xe440, 0x27f9,
+ 0xe4a1, 0x2838,
+ 0xe540, 0x2896,
+ 0xe5a1, 0x28d5,
+ 0xe640, 0x2933,
+ 0xe6a1, 0x2972,
+ 0xe740, 0x29d0,
+ 0xe7a1, 0x2a0f,
+ 0xe840, 0x2a6d,
+ 0xe8a1, 0x2aac,
+ 0xe8a3, 0x2aaf,
+ 0xe940, 0x2b0b,
+ 0xe976, 0x2b42,
+ 0xe9a1, 0x2b4b,
+ 0xea40, 0x2ba9,
+ 0xeaa1, 0x2be8,
+ 0xeb40, 0x2c46,
+ 0xeb5b, 0x2c62,
+ 0xeba1, 0x2c86,
+ 0xebf1, 0x2aae,
+ 0xebf2, 0x2cd6,
+ 0xec40, 0x2ce3,
+ 0xeca1, 0x2d22,
+ 0xecde, 0x2b41,
+ 0xecdf, 0x2d5f,
+ 0xed40, 0x2d7f,
+ 0xeda1, 0x2dbe,
+ 0xedaa, 0x2dc8,
+ 0xee40, 0x2e1d,
+ 0xeea1, 0x2e5c,
+ 0xeeeb, 0x3014,
+ 0xeeec, 0x2ea6,
+ 0xef40, 0x2eb9,
+ 0xefa1, 0x2ef8,
+ 0xf040, 0x2f56,
+ 0xf056, 0x2dc7,
+ 0xf057, 0x2f6c,
+ 0xf0a1, 0x2f94,
+ 0xf0cb, 0x2c61,
+ 0xf0cc, 0x2fbe,
+ 0xf140, 0x2ff1,
+ 0xf163, 0x3015,
+ 0xf16b, 0x3160,
+ 0xf16c, 0x301d,
+ 0xf1a1, 0x3030,
+ 0xf240, 0x308e,
+ 0xf268, 0x31ef,
+ 0xf269, 0x30b6,
+ 0xf2a1, 0x30cc,
+ 0xf2c3, 0x30ef,
+ 0xf340, 0x312b,
+ 0xf375, 0x3161,
+ 0xf3a1, 0x316b,
+ 0xf440, 0x31c9,
+ 0xf466, 0x31f0,
+ 0xf4a1, 0x3209,
+ 0xf4b5, 0x30ee,
+ 0xf4b6, 0x321d,
+ 0xf4fd, 0x3265,
+ 0xf540, 0x3267,
+ 0xf5a1, 0x32a6,
+ 0xf640, 0x3304,
+ 0xf663, 0x3264,
+ 0xf664, 0x3327,
+ 0xf6a1, 0x3342,
+ 0xf740, 0x33a0,
+ 0xf7a1, 0x33df,
+ 0xf840, 0x343d,
+ 0xf8a1, 0x347c,
+ 0xf940, 0x34da,
+ 0xf977, 0x3512,
+ 0xf9a1, 0x351a,
+ 0xf9c4, 0x3511,
+ 0xf9c5, 0x353d,
+ 0xf9c6, 0x3549,
+ 0xf9c7, 0x353e,
+ 0xf9d2, 0x354a,
+ 0xfa40, 0x400b,
+ 0xfaa1, 0x404a,
+ 0xfb40, 0x40a8,
+ 0xfba1, 0x40e7,
+ 0xfbc0, 0x4105,
+ 0xfbce, 0x4112,
+ 0xfc40, 0x4143,
+ 0xfc4b, 0x414d,
+ 0xfc4f, 0x212f,
+ 0xfc50, 0x4151,
+ 0xfc53, 0x4153,
+ 0xfc64, 0x4163,
+ 0xfc76, 0x4174,
+ 0xfca1, 0x417d,
+ 0xfcb9, 0x115f,
+ 0xfcba, 0x4195,
+ 0xfcbd, 0x4197,
+ 0xfce4, 0x41bd,
+ 0xfcef, 0x41c7,
+ 0xfd40, 0x41d7,
+ 0xfd4a, 0x41e0,
+ 0xfda1, 0x4215,
+ 0xfdf3, 0x4266,
+ 0xfe40, 0x4272,
+ 0xfe6e, 0x429f,
+ 0xfe79, 0x42a9,
+ 0xfea1, 0x42af,
+ 0xfeaa, 0x0120,
+ 0xfeab, 0x42b8,
+ 0xfee0, 0x42eb,
+ 0xfeef, 0x42f8,
+ 0xa14b, 0x354e,
+ 0xa15a, 0x35af,
+ 0xa15c, 0x35b1,
+ 0xa15d, 0x0082,
+ 0xa161, 0x0086,
+ 0xa165, 0x008a,
+ 0xa169, 0x008e,
+ 0xa16d, 0x0092,
+ 0xa171, 0x0096,
+ 0xa175, 0x009a,
+ 0xa179, 0x009e,
+ 0xa1e3, 0x354f,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 cns13HKgccsB5VEnc16 = {
+ 1,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
+ 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010,
+ 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018,
+ 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020,
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028,
+ 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030,
+ 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038,
+ 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040,
+ 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048,
+ 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050,
+ 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
+ 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ cns13HKgccsB5VMap2, 565
+};
+
+static Gushort cns13HKm314B5HMap2[1086] = {
+ 0x0000, 0x0000,
+ 0xa140, 0x0063,
+ 0xa159, 0x35af,
+ 0xa15d, 0x0080,
+ 0xa1a1, 0x00a2,
+ 0xa1f6, 0x00f8,
+ 0xa1f7, 0x00f7,
+ 0xa1f8, 0x00f9,
+ 0xa240, 0x0100,
+ 0xa2a1, 0x013f,
+ 0xa340, 0x019d,
+ 0xa3a1, 0x01dc,
+ 0xa3bd, 0x01f7,
+ 0xa440, 0x0253,
+ 0xa4a1, 0x0292,
+ 0xa540, 0x02f0,
+ 0xa5a1, 0x032f,
+ 0xa640, 0x038d,
+ 0xa6a1, 0x03cc,
+ 0xa740, 0x042a,
+ 0xa7a1, 0x0469,
+ 0xa840, 0x04c7,
+ 0xa8a1, 0x0506,
+ 0xa940, 0x0564,
+ 0xa9a1, 0x05a3,
+ 0xaa40, 0x0601,
+ 0xaaa1, 0x0640,
+ 0xab40, 0x069e,
+ 0xaba1, 0x06dd,
+ 0xac40, 0x073b,
+ 0xaca1, 0x077a,
+ 0xacfe, 0x097f,
+ 0xad40, 0x07d7,
+ 0xada1, 0x0816,
+ 0xae40, 0x0874,
+ 0xaea1, 0x08b3,
+ 0xaf40, 0x0911,
+ 0xafa1, 0x0950,
+ 0xafd0, 0x0980,
+ 0xb040, 0x09af,
+ 0xb0a1, 0x09ee,
+ 0xb140, 0x0a4c,
+ 0xb1a1, 0x0a8b,
+ 0xb240, 0x0ae9,
+ 0xb2a1, 0x0b28,
+ 0xb340, 0x0b86,
+ 0xb3a1, 0x0bc5,
+ 0xb440, 0x0c23,
+ 0xb4a1, 0x0c62,
+ 0xb540, 0x0cc0,
+ 0xb5a1, 0x0cff,
+ 0xb640, 0x0d5d,
+ 0xb6a1, 0x0d9c,
+ 0xb740, 0x0dfa,
+ 0xb7a1, 0x0e39,
+ 0xb840, 0x0e97,
+ 0xb8a1, 0x0ed6,
+ 0xb940, 0x0f34,
+ 0xb9a1, 0x0f73,
+ 0xba40, 0x0fd1,
+ 0xbaa1, 0x1010,
+ 0xbb40, 0x106e,
+ 0xbba1, 0x10ad,
+ 0xbbc8, 0x10d5,
+ 0xbc40, 0x110c,
+ 0xbca1, 0x114b,
+ 0xbd40, 0x11a9,
+ 0xbda1, 0x11e8,
+ 0xbe40, 0x1246,
+ 0xbe52, 0x10d4,
+ 0xbe53, 0x1258,
+ 0xbea1, 0x1284,
+ 0xbf40, 0x12e2,
+ 0xbfa1, 0x1321,
+ 0xc040, 0x137f,
+ 0xc0a1, 0x13be,
+ 0xc140, 0x141c,
+ 0xc1a1, 0x145b,
+ 0xc1ab, 0x1466,
+ 0xc240, 0x14ba,
+ 0xc2a1, 0x14f9,
+ 0xc2cb, 0x1465,
+ 0xc2cc, 0x1523,
+ 0xc340, 0x1556,
+ 0xc361, 0x1578,
+ 0xc3a1, 0x1596,
+ 0xc3b9, 0x15af,
+ 0xc3ba, 0x15ae,
+ 0xc3bb, 0x15b0,
+ 0xc440, 0x15f4,
+ 0xc456, 0x1577,
+ 0xc457, 0x160a,
+ 0xc4a1, 0x1632,
+ 0xc540, 0x1690,
+ 0xc5a1, 0x16cf,
+ 0xc640, 0x172d,
+ 0xc740, 0x3d6d,
+ 0xc741, 0x39c4,
+ 0xc742, 0x4399,
+ 0xc743, 0x3e05,
+ 0xc744, 0x36ea,
+ 0xc745, 0x39c8,
+ 0xc746, 0x393d,
+ 0xc747, 0x439b,
+ 0xc748, 0x4022,
+ 0xc749, 0x439d,
+ 0xc74a, 0x4034,
+ 0xc74b, 0x439f,
+ 0xc74c, 0x3ea3,
+ 0xc74d, 0x3ea6,
+ 0xc74e, 0x4051,
+ 0xc74f, 0x4048,
+ 0xc751, 0x404b,
+ 0xc752, 0x404f,
+ 0xc753, 0x43a2,
+ 0xc754, 0x405a,
+ 0xc755, 0x3ea4,
+ 0xc756, 0x3dbd,
+ 0xc757, 0x3dbf,
+ 0xc758, 0x405c,
+ 0xc759, 0x405f,
+ 0xc75a, 0x43a4,
+ 0xc75b, 0x407b,
+ 0xc75c, 0x4082,
+ 0xc75d, 0x3f6d,
+ 0xc75e, 0x408b,
+ 0xc75f, 0x43a6,
+ 0xc760, 0x4093,
+ 0xc761, 0x4096,
+ 0xc762, 0x43a7,
+ 0xc763, 0x4098,
+ 0xc764, 0x3e7f,
+ 0xc765, 0x3c77,
+ 0xc766, 0x3ea7,
+ 0xc767, 0x3e8a,
+ 0xc768, 0x3e98,
+ 0xc769, 0x3e8c,
+ 0xc76a, 0x40a1,
+ 0xc76b, 0x3a00,
+ 0xc76c, 0x39a3,
+ 0xc76d, 0x3e8d,
+ 0xc76e, 0x43a8,
+ 0xc76f, 0x3f58,
+ 0xc770, 0x3dbc,
+ 0xc771, 0x3ccc,
+ 0xc772, 0x3ea8,
+ 0xc774, 0x3b2e,
+ 0xc775, 0x3bc6,
+ 0xc776, 0x3e8b,
+ 0xc777, 0x3e9f,
+ 0xc778, 0x432c,
+ 0xc779, 0x43a9,
+ 0xc77a, 0x3f08,
+ 0xc77b, 0x3ea5,
+ 0xc77c, 0x3e89,
+ 0xc77d, 0x3dc3,
+ 0xc77e, 0x3e82,
+ 0xc7a1, 0x3e81,
+ 0xc7a2, 0x3e94,
+ 0xc7a3, 0x3e83,
+ 0xc7a4, 0x3e88,
+ 0xc7a5, 0x43ab,
+ 0xc7a6, 0x3e91,
+ 0xc7a7, 0x43ac,
+ 0xc7a8, 0x3e7c,
+ 0xc7a9, 0x3e80,
+ 0xc7aa, 0x3e8f,
+ 0xc7ab, 0x3e67,
+ 0xc7ac, 0x3e78,
+ 0xc7ad, 0x3e68,
+ 0xc7ae, 0x43ad,
+ 0xc7af, 0x37d2,
+ 0xc7b0, 0x3f4d,
+ 0xc7b1, 0x43ae,
+ 0xc7b2, 0x3e7e,
+ 0xc7b3, 0x40bc,
+ 0xc7b4, 0x3e63,
+ 0xc7b5, 0x40bd,
+ 0xc7b6, 0x43af,
+ 0xc7b7, 0x40b7,
+ 0xc7b8, 0x3eb7,
+ 0xc7b9, 0x3eed,
+ 0xc7ba, 0x3f6a,
+ 0xc7bb, 0x3e95,
+ 0xc7bc, 0x3948,
+ 0xc7bd, 0x3cc8,
+ 0xc7be, 0x43b1,
+ 0xc7c0, 0x40cc,
+ 0xc7c1, 0x3e86,
+ 0xc7c2, 0x3c7a,
+ 0xc7c3, 0x3c7d,
+ 0xc7c4, 0x43b4,
+ 0xc7c5, 0x40d1,
+ 0xc7c6, 0x3d72,
+ 0xc7c7, 0x3c26,
+ 0xc7c8, 0x36eb,
+ 0xc7c9, 0x40bf,
+ 0xc7ca, 0x4100,
+ 0xc7cb, 0x3c85,
+ 0xc7cc, 0x43b5,
+ 0xc7cd, 0x3a1d,
+ 0xc7ce, 0x37f5,
+ 0xc7cf, 0x36ee,
+ 0xc7d0, 0x3e5f,
+ 0xc7d1, 0x4116,
+ 0xc7d2, 0x411f,
+ 0xc7d3, 0x4118,
+ 0xc7d4, 0x4123,
+ 0xc7d5, 0x4127,
+ 0xc7d6, 0x4129,
+ 0xc7d7, 0x43bc,
+ 0xc7d9, 0x3e8e,
+ 0xc7da, 0x386f,
+ 0xc7db, 0x4143,
+ 0xc7dc, 0x4146,
+ 0xc7dd, 0x4144,
+ 0xc7de, 0x4149,
+ 0xc7df, 0x3ba5,
+ 0xc7e0, 0x4157,
+ 0xc7e1, 0x4161,
+ 0xc7e2, 0x36ec,
+ 0xc7e3, 0x416a,
+ 0xc7e4, 0x4002,
+ 0xc7e5, 0x4186,
+ 0xc7e6, 0x3fba,
+ 0xc7e7, 0x3f50,
+ 0xc7e8, 0x3e96,
+ 0xc7e9, 0x418a,
+ 0xc7ea, 0x3fc1,
+ 0xc7eb, 0x3d8f,
+ 0xc7ec, 0x43c1,
+ 0xc7ed, 0x3ea0,
+ 0xc7ee, 0x3f16,
+ 0xc7ef, 0x3e9d,
+ 0xc7f0, 0x4192,
+ 0xc7f1, 0x3a66,
+ 0xc7f2, 0x3e9c,
+ 0xc7f3, 0x3e90,
+ 0xc7f4, 0x419d,
+ 0xc7f5, 0x43c2,
+ 0xc7f7, 0x37a8,
+ 0xc7f8, 0x419e,
+ 0xc7f9, 0x4187,
+ 0xc7fa, 0x3ea2,
+ 0xc7fb, 0x3e87,
+ 0xc7fc, 0x3e84,
+ 0xc7fd, 0x3eae,
+ 0xc7fe, 0x3b74,
+ 0xc840, 0x3b75,
+ 0xc841, 0x3b72,
+ 0xc842, 0x3eb2,
+ 0xc843, 0x3eac,
+ 0xc844, 0x41ca,
+ 0xc845, 0x41f4,
+ 0xc846, 0x41d0,
+ 0xc847, 0x3aaa,
+ 0xc848, 0x41f5,
+ 0xc849, 0x41f8,
+ 0xc84a, 0x41fb,
+ 0xc84b, 0x4205,
+ 0xc84c, 0x3d8e,
+ 0xc84d, 0x420e,
+ 0xc84e, 0x3d63,
+ 0xc84f, 0x4222,
+ 0xc850, 0x4221,
+ 0xc851, 0x4223,
+ 0xc852, 0x4069,
+ 0xc853, 0x402f,
+ 0xc854, 0x38a5,
+ 0xc855, 0x3cf5,
+ 0xc856, 0x3d69,
+ 0xc857, 0x425b,
+ 0xc858, 0x3ac8,
+ 0xc859, 0x3dc0,
+ 0xc85a, 0x39ea,
+ 0xc85b, 0x4000,
+ 0xc85c, 0x4264,
+ 0xc85d, 0x4262,
+ 0xc85e, 0x3fff,
+ 0xc85f, 0x3e9a,
+ 0xc860, 0x4273,
+ 0xc861, 0x3969,
+ 0xc862, 0x427a,
+ 0xc863, 0x43ca,
+ 0xc864, 0x3f9a,
+ 0xc865, 0x3eb5,
+ 0xc866, 0x43cb,
+ 0xc868, 0x3fb2,
+ 0xc869, 0x428a,
+ 0xc86c, 0x3adf,
+ 0xc86d, 0x42c8,
+ 0xc86e, 0x3ead,
+ 0xc86f, 0x43ce,
+ 0xc870, 0x3f8f,
+ 0xc871, 0x43cf,
+ 0xc872, 0x3e72,
+ 0xc873, 0x3eaa,
+ 0xc874, 0x43d3,
+ 0xc875, 0x42e0,
+ 0xc876, 0x382d,
+ 0xc877, 0x3fd5,
+ 0xc878, 0x3b14,
+ 0xc879, 0x36e8,
+ 0xc87a, 0x42f0,
+ 0xc87b, 0x3e7d,
+ 0xc87c, 0x42fe,
+ 0xc87d, 0x4305,
+ 0xc87e, 0x373a,
+ 0xc8a1, 0x3746,
+ 0xc8a2, 0x3752,
+ 0xc8a3, 0x36ed,
+ 0xc8a4, 0x3b4a,
+ 0xc8a5, 0x3b45,
+ 0xc8a6, 0x43da,
+ 0xc8a7, 0x3ede,
+ 0xc8a8, 0x376c,
+ 0xc8a9, 0x376b,
+ 0xc8aa, 0x3782,
+ 0xc8ab, 0x3e69,
+ 0xc8ac, 0x3b4f,
+ 0xc8ad, 0x3786,
+ 0xc8ae, 0x43db,
+ 0xc8af, 0x3788,
+ 0xc8b0, 0x43dc,
+ 0xc8b1, 0x3ecd,
+ 0xc8b2, 0x3797,
+ 0xc8b3, 0x420d,
+ 0xc8b4, 0x37d8,
+ 0xc8b5, 0x3b71,
+ 0xc8b6, 0x38dc,
+ 0xc8b7, 0x37e0,
+ 0xc8b8, 0x37f4,
+ 0xc8b9, 0x3813,
+ 0xc8ba, 0x3eb0,
+ 0xc8bb, 0x380d,
+ 0xc8bc, 0x3eaf,
+ 0xc8bd, 0x381b,
+ 0xc8bf, 0x381e,
+ 0xc8c1, 0x3eb1,
+ 0xc8c2, 0x3fe9,
+ 0xc8c3, 0x43e4,
+ 0xc8c4, 0x3ff9,
+ 0xc8c5, 0x3e59,
+ 0xc8c6, 0x3e99,
+ 0xc8c7, 0x3e5e,
+ 0xc8c8, 0x3bb4,
+ 0xc8c9, 0x3eab,
+ 0xc8ca, 0x43e7,
+ 0xc8cc, 0x385e,
+ 0xc8cd, 0x43e9,
+ 0xc8ce, 0x3dbe,
+ 0xc8cf, 0x3e85,
+ 0xc8d0, 0x3863,
+ 0xc8d2, 0x3d6c,
+ 0xc8d3, 0x3871,
+ 0xc8d4, 0x387c,
+ 0xc8d5, 0x3882,
+ 0xc8d6, 0x3e9b,
+ 0xc8d7, 0x3888,
+ 0xc8d8, 0x3c0e,
+ 0xc8d9, 0x382e,
+ 0xc8da, 0x389a,
+ 0xc8db, 0x388b,
+ 0xc8dc, 0x3c04,
+ 0xc8dd, 0x36e9,
+ 0xc8de, 0x42bd,
+ 0xc8df, 0x3bcd,
+ 0xc8e0, 0x389f,
+ 0xc8e1, 0x379b,
+ 0xc8e2, 0x38af,
+ 0xc8e3, 0x3e97,
+ 0xc8e4, 0x38f0,
+ 0xc8e5, 0x3bfd,
+ 0xc8e6, 0x3c11,
+ 0xc8e8, 0x43ef,
+ 0xc8e9, 0x3785,
+ 0xc8ea, 0x3902,
+ 0xc8eb, 0x3faa,
+ 0xc8ec, 0x3f19,
+ 0xc8ed, 0x3919,
+ 0xc8ee, 0x43f1,
+ 0xc8ef, 0x391a,
+ 0xc8f1, 0x3e66,
+ 0xc8f2, 0x3f22,
+ 0xc8f3, 0x3d7e,
+ 0xc8f4, 0x3c39,
+ 0xc8f5, 0x3ea1,
+ 0xc8f6, 0x43f2,
+ 0xc8f8, 0x3f30,
+ 0xc8f9, 0x3929,
+ 0xc8fa, 0x3fbc,
+ 0xc8fb, 0x3936,
+ 0xc8fd, 0x3f90,
+ 0xc8fe, 0x0aba,
+ 0xc940, 0x176c,
+ 0xc94a, 0x0274,
+ 0xc94b, 0x1776,
+ 0xc96c, 0x1798,
+ 0xc9a1, 0x17ab,
+ 0xc9be, 0x1797,
+ 0xc9bf, 0x17c8,
+ 0xc9ed, 0x17f7,
+ 0xca40, 0x1809,
+ 0xcaa1, 0x1848,
+ 0xcaf7, 0x17f6,
+ 0xcaf8, 0x189e,
+ 0xcb40, 0x18a5,
+ 0xcba1, 0x18e4,
+ 0xcc40, 0x1942,
+ 0xcca1, 0x1981,
+ 0xcd40, 0x19df,
+ 0xcda1, 0x1a1e,
+ 0xce40, 0x1a7c,
+ 0xcea1, 0x1abb,
+ 0xcf40, 0x1b19,
+ 0xcfa1, 0x1b58,
+ 0xd040, 0x1bb6,
+ 0xd0a1, 0x1bf5,
+ 0xd140, 0x1c53,
+ 0xd1a1, 0x1c92,
+ 0xd240, 0x1cf0,
+ 0xd2a1, 0x1d2f,
+ 0xd340, 0x1d8d,
+ 0xd3a1, 0x1dcc,
+ 0xd440, 0x1e2a,
+ 0xd4a1, 0x1e69,
+ 0xd540, 0x1ec7,
+ 0xd5a1, 0x1f06,
+ 0xd640, 0x1f64,
+ 0xd6a1, 0x1fa3,
+ 0xd6cc, 0x2254,
+ 0xd6cd, 0x1fcf,
+ 0xd740, 0x2001,
+ 0xd77a, 0x22b9,
+ 0xd77b, 0x203b,
+ 0xd7a1, 0x203f,
+ 0xd840, 0x209d,
+ 0xd8a1, 0x20dc,
+ 0xd940, 0x213a,
+ 0xd9a1, 0x2179,
+ 0xda40, 0x21d7,
+ 0xdaa1, 0x2216,
+ 0xdadf, 0x1fce,
+ 0xdae0, 0x2255,
+ 0xdb40, 0x2274,
+ 0xdba1, 0x22b3,
+ 0xdba7, 0x22ba,
+ 0xdc40, 0x2312,
+ 0xdca1, 0x2351,
+ 0xdd40, 0x23af,
+ 0xdda1, 0x23ee,
+ 0xddfc, 0x2381,
+ 0xddfd, 0x2449,
+ 0xde40, 0x244b,
+ 0xdea1, 0x248a,
+ 0xdf40, 0x24e8,
+ 0xdfa1, 0x2527,
+ 0xe040, 0x2585,
+ 0xe0a1, 0x25c4,
+ 0xe140, 0x2622,
+ 0xe1a1, 0x2661,
+ 0xe240, 0x26bf,
+ 0xe2a1, 0x26fe,
+ 0xe340, 0x275c,
+ 0xe3a1, 0x279b,
+ 0xe440, 0x27f9,
+ 0xe4a1, 0x2838,
+ 0xe540, 0x2896,
+ 0xe5a1, 0x28d5,
+ 0xe640, 0x2933,
+ 0xe6a1, 0x2972,
+ 0xe740, 0x29d0,
+ 0xe7a1, 0x2a0f,
+ 0xe840, 0x2a6d,
+ 0xe8a1, 0x2aac,
+ 0xe8a3, 0x2aaf,
+ 0xe940, 0x2b0b,
+ 0xe976, 0x2b42,
+ 0xe9a1, 0x2b4b,
+ 0xea40, 0x2ba9,
+ 0xeaa1, 0x2be8,
+ 0xeb40, 0x2c46,
+ 0xeb5b, 0x2c62,
+ 0xeba1, 0x2c86,
+ 0xebf1, 0x2aae,
+ 0xebf2, 0x2cd6,
+ 0xec40, 0x2ce3,
+ 0xeca1, 0x2d22,
+ 0xecde, 0x2b41,
+ 0xecdf, 0x2d5f,
+ 0xed40, 0x2d7f,
+ 0xeda1, 0x2dbe,
+ 0xedaa, 0x2dc8,
+ 0xee40, 0x2e1d,
+ 0xeea1, 0x2e5c,
+ 0xeeeb, 0x3014,
+ 0xeeec, 0x2ea6,
+ 0xef40, 0x2eb9,
+ 0xefa1, 0x2ef8,
+ 0xf040, 0x2f56,
+ 0xf056, 0x2dc7,
+ 0xf057, 0x2f6c,
+ 0xf0a1, 0x2f94,
+ 0xf0cb, 0x2c61,
+ 0xf0cc, 0x2fbe,
+ 0xf140, 0x2ff1,
+ 0xf163, 0x3015,
+ 0xf16b, 0x3160,
+ 0xf16c, 0x301d,
+ 0xf1a1, 0x3030,
+ 0xf240, 0x308e,
+ 0xf268, 0x31ef,
+ 0xf269, 0x30b6,
+ 0xf2a1, 0x30cc,
+ 0xf2c3, 0x30ef,
+ 0xf340, 0x312b,
+ 0xf375, 0x3161,
+ 0xf3a1, 0x316b,
+ 0xf440, 0x31c9,
+ 0xf466, 0x31f0,
+ 0xf4a1, 0x3209,
+ 0xf4b5, 0x30ee,
+ 0xf4b6, 0x321d,
+ 0xf4fd, 0x3265,
+ 0xf540, 0x3267,
+ 0xf5a1, 0x32a6,
+ 0xf640, 0x3304,
+ 0xf663, 0x3264,
+ 0xf664, 0x3327,
+ 0xf6a1, 0x3342,
+ 0xf740, 0x33a0,
+ 0xf7a1, 0x33df,
+ 0xf840, 0x343d,
+ 0xf8a1, 0x347c,
+ 0xf940, 0x34da,
+ 0xf977, 0x3512,
+ 0xf9a1, 0x351a,
+ 0xf9c4, 0x3511,
+ 0xf9c5, 0x353d,
+ 0xf9c6, 0x3549,
+ 0xf9c7, 0x353e,
+ 0xf9d2, 0x354a,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 cns13HKm314B5HEnc16 = {
+ 0,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
+ 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010,
+ 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018,
+ 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020,
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028,
+ 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030,
+ 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038,
+ 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040,
+ 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048,
+ 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050,
+ 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
+ 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ cns13HKm314B5HMap2, 543
+};
+
+static Gushort cns13HKm314B5VMap2[1110] = {
+ 0x0000, 0x0000,
+ 0xa140, 0x0063,
+ 0xa159, 0x35af,
+ 0xa15d, 0x0080,
+ 0xa1a1, 0x00a2,
+ 0xa1f6, 0x00f8,
+ 0xa1f7, 0x00f7,
+ 0xa1f8, 0x00f9,
+ 0xa240, 0x0100,
+ 0xa2a1, 0x013f,
+ 0xa340, 0x019d,
+ 0xa3a1, 0x01dc,
+ 0xa3bd, 0x01f7,
+ 0xa440, 0x0253,
+ 0xa4a1, 0x0292,
+ 0xa540, 0x02f0,
+ 0xa5a1, 0x032f,
+ 0xa640, 0x038d,
+ 0xa6a1, 0x03cc,
+ 0xa740, 0x042a,
+ 0xa7a1, 0x0469,
+ 0xa840, 0x04c7,
+ 0xa8a1, 0x0506,
+ 0xa940, 0x0564,
+ 0xa9a1, 0x05a3,
+ 0xaa40, 0x0601,
+ 0xaaa1, 0x0640,
+ 0xab40, 0x069e,
+ 0xaba1, 0x06dd,
+ 0xac40, 0x073b,
+ 0xaca1, 0x077a,
+ 0xacfe, 0x097f,
+ 0xad40, 0x07d7,
+ 0xada1, 0x0816,
+ 0xae40, 0x0874,
+ 0xaea1, 0x08b3,
+ 0xaf40, 0x0911,
+ 0xafa1, 0x0950,
+ 0xafd0, 0x0980,
+ 0xb040, 0x09af,
+ 0xb0a1, 0x09ee,
+ 0xb140, 0x0a4c,
+ 0xb1a1, 0x0a8b,
+ 0xb240, 0x0ae9,
+ 0xb2a1, 0x0b28,
+ 0xb340, 0x0b86,
+ 0xb3a1, 0x0bc5,
+ 0xb440, 0x0c23,
+ 0xb4a1, 0x0c62,
+ 0xb540, 0x0cc0,
+ 0xb5a1, 0x0cff,
+ 0xb640, 0x0d5d,
+ 0xb6a1, 0x0d9c,
+ 0xb740, 0x0dfa,
+ 0xb7a1, 0x0e39,
+ 0xb840, 0x0e97,
+ 0xb8a1, 0x0ed6,
+ 0xb940, 0x0f34,
+ 0xb9a1, 0x0f73,
+ 0xba40, 0x0fd1,
+ 0xbaa1, 0x1010,
+ 0xbb40, 0x106e,
+ 0xbba1, 0x10ad,
+ 0xbbc8, 0x10d5,
+ 0xbc40, 0x110c,
+ 0xbca1, 0x114b,
+ 0xbd40, 0x11a9,
+ 0xbda1, 0x11e8,
+ 0xbe40, 0x1246,
+ 0xbe52, 0x10d4,
+ 0xbe53, 0x1258,
+ 0xbea1, 0x1284,
+ 0xbf40, 0x12e2,
+ 0xbfa1, 0x1321,
+ 0xc040, 0x137f,
+ 0xc0a1, 0x13be,
+ 0xc140, 0x141c,
+ 0xc1a1, 0x145b,
+ 0xc1ab, 0x1466,
+ 0xc240, 0x14ba,
+ 0xc2a1, 0x14f9,
+ 0xc2cb, 0x1465,
+ 0xc2cc, 0x1523,
+ 0xc340, 0x1556,
+ 0xc361, 0x1578,
+ 0xc3a1, 0x1596,
+ 0xc3b9, 0x15af,
+ 0xc3ba, 0x15ae,
+ 0xc3bb, 0x15b0,
+ 0xc440, 0x15f4,
+ 0xc456, 0x1577,
+ 0xc457, 0x160a,
+ 0xc4a1, 0x1632,
+ 0xc540, 0x1690,
+ 0xc5a1, 0x16cf,
+ 0xc640, 0x172d,
+ 0xc740, 0x3d6d,
+ 0xc741, 0x39c4,
+ 0xc742, 0x4399,
+ 0xc743, 0x3e05,
+ 0xc744, 0x36ea,
+ 0xc745, 0x39c8,
+ 0xc746, 0x393d,
+ 0xc747, 0x439b,
+ 0xc748, 0x4022,
+ 0xc749, 0x439d,
+ 0xc74a, 0x4034,
+ 0xc74b, 0x439f,
+ 0xc74c, 0x3ea3,
+ 0xc74d, 0x3ea6,
+ 0xc74e, 0x4051,
+ 0xc74f, 0x4048,
+ 0xc751, 0x404b,
+ 0xc752, 0x404f,
+ 0xc753, 0x43a2,
+ 0xc754, 0x405a,
+ 0xc755, 0x3ea4,
+ 0xc756, 0x3dbd,
+ 0xc757, 0x3dbf,
+ 0xc758, 0x405c,
+ 0xc759, 0x405f,
+ 0xc75a, 0x43a4,
+ 0xc75b, 0x407b,
+ 0xc75c, 0x4082,
+ 0xc75d, 0x3f6d,
+ 0xc75e, 0x408b,
+ 0xc75f, 0x43a6,
+ 0xc760, 0x4093,
+ 0xc761, 0x4096,
+ 0xc762, 0x43a7,
+ 0xc763, 0x4098,
+ 0xc764, 0x3e7f,
+ 0xc765, 0x3c77,
+ 0xc766, 0x3ea7,
+ 0xc767, 0x3e8a,
+ 0xc768, 0x3e98,
+ 0xc769, 0x3e8c,
+ 0xc76a, 0x40a1,
+ 0xc76b, 0x3a00,
+ 0xc76c, 0x39a3,
+ 0xc76d, 0x3e8d,
+ 0xc76e, 0x43a8,
+ 0xc76f, 0x3f58,
+ 0xc770, 0x3dbc,
+ 0xc771, 0x3ccc,
+ 0xc772, 0x3ea8,
+ 0xc774, 0x3b2e,
+ 0xc775, 0x3bc6,
+ 0xc776, 0x3e8b,
+ 0xc777, 0x3e9f,
+ 0xc778, 0x432c,
+ 0xc779, 0x43a9,
+ 0xc77a, 0x3f08,
+ 0xc77b, 0x3ea5,
+ 0xc77c, 0x3e89,
+ 0xc77d, 0x3dc3,
+ 0xc77e, 0x3e82,
+ 0xc7a1, 0x3e81,
+ 0xc7a2, 0x3e94,
+ 0xc7a3, 0x3e83,
+ 0xc7a4, 0x3e88,
+ 0xc7a5, 0x43ab,
+ 0xc7a6, 0x3e91,
+ 0xc7a7, 0x43ac,
+ 0xc7a8, 0x3e7c,
+ 0xc7a9, 0x3e80,
+ 0xc7aa, 0x3e8f,
+ 0xc7ab, 0x3e67,
+ 0xc7ac, 0x3e78,
+ 0xc7ad, 0x3e68,
+ 0xc7ae, 0x43ad,
+ 0xc7af, 0x37d2,
+ 0xc7b0, 0x3f4d,
+ 0xc7b1, 0x43ae,
+ 0xc7b2, 0x3e7e,
+ 0xc7b3, 0x40bc,
+ 0xc7b4, 0x3e63,
+ 0xc7b5, 0x40bd,
+ 0xc7b6, 0x43af,
+ 0xc7b7, 0x40b7,
+ 0xc7b8, 0x3eb7,
+ 0xc7b9, 0x3eed,
+ 0xc7ba, 0x3f6a,
+ 0xc7bb, 0x3e95,
+ 0xc7bc, 0x3948,
+ 0xc7bd, 0x3cc8,
+ 0xc7be, 0x43b1,
+ 0xc7c0, 0x40cc,
+ 0xc7c1, 0x3e86,
+ 0xc7c2, 0x3c7a,
+ 0xc7c3, 0x3c7d,
+ 0xc7c4, 0x43b4,
+ 0xc7c5, 0x40d1,
+ 0xc7c6, 0x3d72,
+ 0xc7c7, 0x3c26,
+ 0xc7c8, 0x36eb,
+ 0xc7c9, 0x40bf,
+ 0xc7ca, 0x4100,
+ 0xc7cb, 0x3c85,
+ 0xc7cc, 0x43b5,
+ 0xc7cd, 0x3a1d,
+ 0xc7ce, 0x37f5,
+ 0xc7cf, 0x36ee,
+ 0xc7d0, 0x3e5f,
+ 0xc7d1, 0x4116,
+ 0xc7d2, 0x411f,
+ 0xc7d3, 0x4118,
+ 0xc7d4, 0x4123,
+ 0xc7d5, 0x4127,
+ 0xc7d6, 0x4129,
+ 0xc7d7, 0x43bc,
+ 0xc7d9, 0x3e8e,
+ 0xc7da, 0x386f,
+ 0xc7db, 0x4143,
+ 0xc7dc, 0x4146,
+ 0xc7dd, 0x4144,
+ 0xc7de, 0x4149,
+ 0xc7df, 0x3ba5,
+ 0xc7e0, 0x4157,
+ 0xc7e1, 0x4161,
+ 0xc7e2, 0x36ec,
+ 0xc7e3, 0x416a,
+ 0xc7e4, 0x4002,
+ 0xc7e5, 0x4186,
+ 0xc7e6, 0x3fba,
+ 0xc7e7, 0x3f50,
+ 0xc7e8, 0x3e96,
+ 0xc7e9, 0x418a,
+ 0xc7ea, 0x3fc1,
+ 0xc7eb, 0x3d8f,
+ 0xc7ec, 0x43c1,
+ 0xc7ed, 0x3ea0,
+ 0xc7ee, 0x3f16,
+ 0xc7ef, 0x3e9d,
+ 0xc7f0, 0x4192,
+ 0xc7f1, 0x3a66,
+ 0xc7f2, 0x3e9c,
+ 0xc7f3, 0x3e90,
+ 0xc7f4, 0x419d,
+ 0xc7f5, 0x43c2,
+ 0xc7f7, 0x37a8,
+ 0xc7f8, 0x419e,
+ 0xc7f9, 0x4187,
+ 0xc7fa, 0x3ea2,
+ 0xc7fb, 0x3e87,
+ 0xc7fc, 0x3e84,
+ 0xc7fd, 0x3eae,
+ 0xc7fe, 0x3b74,
+ 0xc840, 0x3b75,
+ 0xc841, 0x3b72,
+ 0xc842, 0x3eb2,
+ 0xc843, 0x3eac,
+ 0xc844, 0x41ca,
+ 0xc845, 0x41f4,
+ 0xc846, 0x41d0,
+ 0xc847, 0x3aaa,
+ 0xc848, 0x41f5,
+ 0xc849, 0x41f8,
+ 0xc84a, 0x41fb,
+ 0xc84b, 0x4205,
+ 0xc84c, 0x3d8e,
+ 0xc84d, 0x420e,
+ 0xc84e, 0x3d63,
+ 0xc84f, 0x4222,
+ 0xc850, 0x4221,
+ 0xc851, 0x4223,
+ 0xc852, 0x4069,
+ 0xc853, 0x402f,
+ 0xc854, 0x38a5,
+ 0xc855, 0x3cf5,
+ 0xc856, 0x3d69,
+ 0xc857, 0x425b,
+ 0xc858, 0x3ac8,
+ 0xc859, 0x3dc0,
+ 0xc85a, 0x39ea,
+ 0xc85b, 0x4000,
+ 0xc85c, 0x4264,
+ 0xc85d, 0x4262,
+ 0xc85e, 0x3fff,
+ 0xc85f, 0x3e9a,
+ 0xc860, 0x4273,
+ 0xc861, 0x3969,
+ 0xc862, 0x427a,
+ 0xc863, 0x43ca,
+ 0xc864, 0x3f9a,
+ 0xc865, 0x3eb5,
+ 0xc866, 0x43cb,
+ 0xc868, 0x3fb2,
+ 0xc869, 0x428a,
+ 0xc86c, 0x3adf,
+ 0xc86d, 0x42c8,
+ 0xc86e, 0x3ead,
+ 0xc86f, 0x43ce,
+ 0xc870, 0x3f8f,
+ 0xc871, 0x43cf,
+ 0xc872, 0x3e72,
+ 0xc873, 0x3eaa,
+ 0xc874, 0x43d3,
+ 0xc875, 0x42e0,
+ 0xc876, 0x382d,
+ 0xc877, 0x3fd5,
+ 0xc878, 0x3b14,
+ 0xc879, 0x36e8,
+ 0xc87a, 0x42f0,
+ 0xc87b, 0x3e7d,
+ 0xc87c, 0x42fe,
+ 0xc87d, 0x4305,
+ 0xc87e, 0x373a,
+ 0xc8a1, 0x3746,
+ 0xc8a2, 0x3752,
+ 0xc8a3, 0x36ed,
+ 0xc8a4, 0x3b4a,
+ 0xc8a5, 0x3b45,
+ 0xc8a6, 0x43da,
+ 0xc8a7, 0x3ede,
+ 0xc8a8, 0x376c,
+ 0xc8a9, 0x376b,
+ 0xc8aa, 0x3782,
+ 0xc8ab, 0x3e69,
+ 0xc8ac, 0x3b4f,
+ 0xc8ad, 0x3786,
+ 0xc8ae, 0x43db,
+ 0xc8af, 0x3788,
+ 0xc8b0, 0x43dc,
+ 0xc8b1, 0x3ecd,
+ 0xc8b2, 0x3797,
+ 0xc8b3, 0x420d,
+ 0xc8b4, 0x37d8,
+ 0xc8b5, 0x3b71,
+ 0xc8b6, 0x38dc,
+ 0xc8b7, 0x37e0,
+ 0xc8b8, 0x37f4,
+ 0xc8b9, 0x3813,
+ 0xc8ba, 0x3eb0,
+ 0xc8bb, 0x380d,
+ 0xc8bc, 0x3eaf,
+ 0xc8bd, 0x381b,
+ 0xc8bf, 0x381e,
+ 0xc8c1, 0x3eb1,
+ 0xc8c2, 0x3fe9,
+ 0xc8c3, 0x43e4,
+ 0xc8c4, 0x3ff9,
+ 0xc8c5, 0x3e59,
+ 0xc8c6, 0x3e99,
+ 0xc8c7, 0x3e5e,
+ 0xc8c8, 0x3bb4,
+ 0xc8c9, 0x3eab,
+ 0xc8ca, 0x43e7,
+ 0xc8cc, 0x385e,
+ 0xc8cd, 0x43e9,
+ 0xc8ce, 0x3dbe,
+ 0xc8cf, 0x3e85,
+ 0xc8d0, 0x3863,
+ 0xc8d2, 0x3d6c,
+ 0xc8d3, 0x3871,
+ 0xc8d4, 0x387c,
+ 0xc8d5, 0x3882,
+ 0xc8d6, 0x3e9b,
+ 0xc8d7, 0x3888,
+ 0xc8d8, 0x3c0e,
+ 0xc8d9, 0x382e,
+ 0xc8da, 0x389a,
+ 0xc8db, 0x388b,
+ 0xc8dc, 0x3c04,
+ 0xc8dd, 0x36e9,
+ 0xc8de, 0x42bd,
+ 0xc8df, 0x3bcd,
+ 0xc8e0, 0x389f,
+ 0xc8e1, 0x379b,
+ 0xc8e2, 0x38af,
+ 0xc8e3, 0x3e97,
+ 0xc8e4, 0x38f0,
+ 0xc8e5, 0x3bfd,
+ 0xc8e6, 0x3c11,
+ 0xc8e8, 0x43ef,
+ 0xc8e9, 0x3785,
+ 0xc8ea, 0x3902,
+ 0xc8eb, 0x3faa,
+ 0xc8ec, 0x3f19,
+ 0xc8ed, 0x3919,
+ 0xc8ee, 0x43f1,
+ 0xc8ef, 0x391a,
+ 0xc8f1, 0x3e66,
+ 0xc8f2, 0x3f22,
+ 0xc8f3, 0x3d7e,
+ 0xc8f4, 0x3c39,
+ 0xc8f5, 0x3ea1,
+ 0xc8f6, 0x43f2,
+ 0xc8f8, 0x3f30,
+ 0xc8f9, 0x3929,
+ 0xc8fa, 0x3fbc,
+ 0xc8fb, 0x3936,
+ 0xc8fd, 0x3f90,
+ 0xc8fe, 0x0aba,
+ 0xc940, 0x176c,
+ 0xc94a, 0x0274,
+ 0xc94b, 0x1776,
+ 0xc96c, 0x1798,
+ 0xc9a1, 0x17ab,
+ 0xc9be, 0x1797,
+ 0xc9bf, 0x17c8,
+ 0xc9ed, 0x17f7,
+ 0xca40, 0x1809,
+ 0xcaa1, 0x1848,
+ 0xcaf7, 0x17f6,
+ 0xcaf8, 0x189e,
+ 0xcb40, 0x18a5,
+ 0xcba1, 0x18e4,
+ 0xcc40, 0x1942,
+ 0xcca1, 0x1981,
+ 0xcd40, 0x19df,
+ 0xcda1, 0x1a1e,
+ 0xce40, 0x1a7c,
+ 0xcea1, 0x1abb,
+ 0xcf40, 0x1b19,
+ 0xcfa1, 0x1b58,
+ 0xd040, 0x1bb6,
+ 0xd0a1, 0x1bf5,
+ 0xd140, 0x1c53,
+ 0xd1a1, 0x1c92,
+ 0xd240, 0x1cf0,
+ 0xd2a1, 0x1d2f,
+ 0xd340, 0x1d8d,
+ 0xd3a1, 0x1dcc,
+ 0xd440, 0x1e2a,
+ 0xd4a1, 0x1e69,
+ 0xd540, 0x1ec7,
+ 0xd5a1, 0x1f06,
+ 0xd640, 0x1f64,
+ 0xd6a1, 0x1fa3,
+ 0xd6cc, 0x2254,
+ 0xd6cd, 0x1fcf,
+ 0xd740, 0x2001,
+ 0xd77a, 0x22b9,
+ 0xd77b, 0x203b,
+ 0xd7a1, 0x203f,
+ 0xd840, 0x209d,
+ 0xd8a1, 0x20dc,
+ 0xd940, 0x213a,
+ 0xd9a1, 0x2179,
+ 0xda40, 0x21d7,
+ 0xdaa1, 0x2216,
+ 0xdadf, 0x1fce,
+ 0xdae0, 0x2255,
+ 0xdb40, 0x2274,
+ 0xdba1, 0x22b3,
+ 0xdba7, 0x22ba,
+ 0xdc40, 0x2312,
+ 0xdca1, 0x2351,
+ 0xdd40, 0x23af,
+ 0xdda1, 0x23ee,
+ 0xddfc, 0x2381,
+ 0xddfd, 0x2449,
+ 0xde40, 0x244b,
+ 0xdea1, 0x248a,
+ 0xdf40, 0x24e8,
+ 0xdfa1, 0x2527,
+ 0xe040, 0x2585,
+ 0xe0a1, 0x25c4,
+ 0xe140, 0x2622,
+ 0xe1a1, 0x2661,
+ 0xe240, 0x26bf,
+ 0xe2a1, 0x26fe,
+ 0xe340, 0x275c,
+ 0xe3a1, 0x279b,
+ 0xe440, 0x27f9,
+ 0xe4a1, 0x2838,
+ 0xe540, 0x2896,
+ 0xe5a1, 0x28d5,
+ 0xe640, 0x2933,
+ 0xe6a1, 0x2972,
+ 0xe740, 0x29d0,
+ 0xe7a1, 0x2a0f,
+ 0xe840, 0x2a6d,
+ 0xe8a1, 0x2aac,
+ 0xe8a3, 0x2aaf,
+ 0xe940, 0x2b0b,
+ 0xe976, 0x2b42,
+ 0xe9a1, 0x2b4b,
+ 0xea40, 0x2ba9,
+ 0xeaa1, 0x2be8,
+ 0xeb40, 0x2c46,
+ 0xeb5b, 0x2c62,
+ 0xeba1, 0x2c86,
+ 0xebf1, 0x2aae,
+ 0xebf2, 0x2cd6,
+ 0xec40, 0x2ce3,
+ 0xeca1, 0x2d22,
+ 0xecde, 0x2b41,
+ 0xecdf, 0x2d5f,
+ 0xed40, 0x2d7f,
+ 0xeda1, 0x2dbe,
+ 0xedaa, 0x2dc8,
+ 0xee40, 0x2e1d,
+ 0xeea1, 0x2e5c,
+ 0xeeeb, 0x3014,
+ 0xeeec, 0x2ea6,
+ 0xef40, 0x2eb9,
+ 0xefa1, 0x2ef8,
+ 0xf040, 0x2f56,
+ 0xf056, 0x2dc7,
+ 0xf057, 0x2f6c,
+ 0xf0a1, 0x2f94,
+ 0xf0cb, 0x2c61,
+ 0xf0cc, 0x2fbe,
+ 0xf140, 0x2ff1,
+ 0xf163, 0x3015,
+ 0xf16b, 0x3160,
+ 0xf16c, 0x301d,
+ 0xf1a1, 0x3030,
+ 0xf240, 0x308e,
+ 0xf268, 0x31ef,
+ 0xf269, 0x30b6,
+ 0xf2a1, 0x30cc,
+ 0xf2c3, 0x30ef,
+ 0xf340, 0x312b,
+ 0xf375, 0x3161,
+ 0xf3a1, 0x316b,
+ 0xf440, 0x31c9,
+ 0xf466, 0x31f0,
+ 0xf4a1, 0x3209,
+ 0xf4b5, 0x30ee,
+ 0xf4b6, 0x321d,
+ 0xf4fd, 0x3265,
+ 0xf540, 0x3267,
+ 0xf5a1, 0x32a6,
+ 0xf640, 0x3304,
+ 0xf663, 0x3264,
+ 0xf664, 0x3327,
+ 0xf6a1, 0x3342,
+ 0xf740, 0x33a0,
+ 0xf7a1, 0x33df,
+ 0xf840, 0x343d,
+ 0xf8a1, 0x347c,
+ 0xf940, 0x34da,
+ 0xf977, 0x3512,
+ 0xf9a1, 0x351a,
+ 0xf9c4, 0x3511,
+ 0xf9c5, 0x353d,
+ 0xf9c6, 0x3549,
+ 0xf9c7, 0x353e,
+ 0xf9d2, 0x354a,
+ 0xa14b, 0x354e,
+ 0xa15a, 0x35af,
+ 0xa15c, 0x35b1,
+ 0xa15d, 0x0082,
+ 0xa161, 0x0086,
+ 0xa165, 0x008a,
+ 0xa169, 0x008e,
+ 0xa16d, 0x0092,
+ 0xa171, 0x0096,
+ 0xa175, 0x009a,
+ 0xa179, 0x009e,
+ 0xa1e3, 0x354f,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 cns13HKm314B5VEnc16 = {
+ 1,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
+ 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010,
+ 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018,
+ 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020,
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028,
+ 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030,
+ 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038,
+ 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040,
+ 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048,
+ 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050,
+ 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
+ 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ cns13HKm314B5VMap2, 555
+};
+
+static Gushort cns13HKm471B5HMap2[1380] = {
+ 0x0000, 0x0000,
+ 0xa140, 0x0063,
+ 0xa159, 0x35af,
+ 0xa15d, 0x0080,
+ 0xa1a1, 0x00a2,
+ 0xa1f6, 0x00f8,
+ 0xa1f7, 0x00f7,
+ 0xa1f8, 0x00f9,
+ 0xa240, 0x0100,
+ 0xa2a1, 0x013f,
+ 0xa340, 0x019d,
+ 0xa3a1, 0x01dc,
+ 0xa3bd, 0x01f7,
+ 0xa440, 0x0253,
+ 0xa4a1, 0x0292,
+ 0xa540, 0x02f0,
+ 0xa5a1, 0x032f,
+ 0xa640, 0x038d,
+ 0xa6a1, 0x03cc,
+ 0xa740, 0x042a,
+ 0xa7a1, 0x0469,
+ 0xa840, 0x04c7,
+ 0xa8a1, 0x0506,
+ 0xa940, 0x0564,
+ 0xa9a1, 0x05a3,
+ 0xaa40, 0x0601,
+ 0xaaa1, 0x0640,
+ 0xab40, 0x069e,
+ 0xaba1, 0x06dd,
+ 0xac40, 0x073b,
+ 0xaca1, 0x077a,
+ 0xacfe, 0x097f,
+ 0xad40, 0x07d7,
+ 0xada1, 0x0816,
+ 0xae40, 0x0874,
+ 0xaea1, 0x08b3,
+ 0xaf40, 0x0911,
+ 0xafa1, 0x0950,
+ 0xafd0, 0x0980,
+ 0xb040, 0x09af,
+ 0xb0a1, 0x09ee,
+ 0xb140, 0x0a4c,
+ 0xb1a1, 0x0a8b,
+ 0xb240, 0x0ae9,
+ 0xb2a1, 0x0b28,
+ 0xb340, 0x0b86,
+ 0xb3a1, 0x0bc5,
+ 0xb440, 0x0c23,
+ 0xb4a1, 0x0c62,
+ 0xb540, 0x0cc0,
+ 0xb5a1, 0x0cff,
+ 0xb640, 0x0d5d,
+ 0xb6a1, 0x0d9c,
+ 0xb740, 0x0dfa,
+ 0xb7a1, 0x0e39,
+ 0xb840, 0x0e97,
+ 0xb8a1, 0x0ed6,
+ 0xb940, 0x0f34,
+ 0xb9a1, 0x0f73,
+ 0xba40, 0x0fd1,
+ 0xbaa1, 0x1010,
+ 0xbb40, 0x106e,
+ 0xbba1, 0x10ad,
+ 0xbbc8, 0x10d5,
+ 0xbc40, 0x110c,
+ 0xbca1, 0x114b,
+ 0xbd40, 0x11a9,
+ 0xbda1, 0x11e8,
+ 0xbe40, 0x1246,
+ 0xbe52, 0x10d4,
+ 0xbe53, 0x1258,
+ 0xbea1, 0x1284,
+ 0xbf40, 0x12e2,
+ 0xbfa1, 0x1321,
+ 0xc040, 0x137f,
+ 0xc0a1, 0x13be,
+ 0xc140, 0x141c,
+ 0xc1a1, 0x145b,
+ 0xc1ab, 0x1466,
+ 0xc240, 0x14ba,
+ 0xc2a1, 0x14f9,
+ 0xc2cb, 0x1465,
+ 0xc2cc, 0x1523,
+ 0xc340, 0x1556,
+ 0xc361, 0x1578,
+ 0xc3a1, 0x1596,
+ 0xc3b9, 0x15af,
+ 0xc3ba, 0x15ae,
+ 0xc3bb, 0x15b0,
+ 0xc440, 0x15f4,
+ 0xc456, 0x1577,
+ 0xc457, 0x160a,
+ 0xc4a1, 0x1632,
+ 0xc540, 0x1690,
+ 0xc5a1, 0x16cf,
+ 0xc640, 0x172d,
+ 0xc940, 0x176c,
+ 0xc94a, 0x0274,
+ 0xc94b, 0x1776,
+ 0xc96c, 0x1798,
+ 0xc9a1, 0x17ab,
+ 0xc9be, 0x1797,
+ 0xc9bf, 0x17c8,
+ 0xc9ed, 0x17f7,
+ 0xca40, 0x1809,
+ 0xcaa1, 0x1848,
+ 0xcaf7, 0x17f6,
+ 0xcaf8, 0x189e,
+ 0xcb40, 0x18a5,
+ 0xcba1, 0x18e4,
+ 0xcc40, 0x1942,
+ 0xcca1, 0x1981,
+ 0xcd40, 0x19df,
+ 0xcda1, 0x1a1e,
+ 0xce40, 0x1a7c,
+ 0xcea1, 0x1abb,
+ 0xcf40, 0x1b19,
+ 0xcfa1, 0x1b58,
+ 0xd040, 0x1bb6,
+ 0xd0a1, 0x1bf5,
+ 0xd140, 0x1c53,
+ 0xd1a1, 0x1c92,
+ 0xd240, 0x1cf0,
+ 0xd2a1, 0x1d2f,
+ 0xd340, 0x1d8d,
+ 0xd3a1, 0x1dcc,
+ 0xd440, 0x1e2a,
+ 0xd4a1, 0x1e69,
+ 0xd540, 0x1ec7,
+ 0xd5a1, 0x1f06,
+ 0xd640, 0x1f64,
+ 0xd6a1, 0x1fa3,
+ 0xd6cc, 0x2254,
+ 0xd6cd, 0x1fcf,
+ 0xd740, 0x2001,
+ 0xd77a, 0x22b9,
+ 0xd77b, 0x203b,
+ 0xd7a1, 0x203f,
+ 0xd840, 0x209d,
+ 0xd8a1, 0x20dc,
+ 0xd940, 0x213a,
+ 0xd9a1, 0x2179,
+ 0xda40, 0x21d7,
+ 0xdaa1, 0x2216,
+ 0xdadf, 0x1fce,
+ 0xdae0, 0x2255,
+ 0xdb40, 0x2274,
+ 0xdba1, 0x22b3,
+ 0xdba7, 0x22ba,
+ 0xdc40, 0x2312,
+ 0xdca1, 0x2351,
+ 0xdd40, 0x23af,
+ 0xdda1, 0x23ee,
+ 0xddfc, 0x2381,
+ 0xddfd, 0x2449,
+ 0xde40, 0x244b,
+ 0xdea1, 0x248a,
+ 0xdf40, 0x24e8,
+ 0xdfa1, 0x2527,
+ 0xe040, 0x2585,
+ 0xe0a1, 0x25c4,
+ 0xe140, 0x2622,
+ 0xe1a1, 0x2661,
+ 0xe240, 0x26bf,
+ 0xe2a1, 0x26fe,
+ 0xe340, 0x275c,
+ 0xe3a1, 0x279b,
+ 0xe440, 0x27f9,
+ 0xe4a1, 0x2838,
+ 0xe540, 0x2896,
+ 0xe5a1, 0x28d5,
+ 0xe640, 0x2933,
+ 0xe6a1, 0x2972,
+ 0xe740, 0x29d0,
+ 0xe7a1, 0x2a0f,
+ 0xe840, 0x2a6d,
+ 0xe8a1, 0x2aac,
+ 0xe8a3, 0x2aaf,
+ 0xe940, 0x2b0b,
+ 0xe976, 0x2b42,
+ 0xe9a1, 0x2b4b,
+ 0xea40, 0x2ba9,
+ 0xeaa1, 0x2be8,
+ 0xeb40, 0x2c46,
+ 0xeb5b, 0x2c62,
+ 0xeba1, 0x2c86,
+ 0xebf1, 0x2aae,
+ 0xebf2, 0x2cd6,
+ 0xec40, 0x2ce3,
+ 0xeca1, 0x2d22,
+ 0xecde, 0x2b41,
+ 0xecdf, 0x2d5f,
+ 0xed40, 0x2d7f,
+ 0xeda1, 0x2dbe,
+ 0xedaa, 0x2dc8,
+ 0xee40, 0x2e1d,
+ 0xeea1, 0x2e5c,
+ 0xeeeb, 0x3014,
+ 0xeeec, 0x2ea6,
+ 0xef40, 0x2eb9,
+ 0xefa1, 0x2ef8,
+ 0xf040, 0x2f56,
+ 0xf056, 0x2dc7,
+ 0xf057, 0x2f6c,
+ 0xf0a1, 0x2f94,
+ 0xf0cb, 0x2c61,
+ 0xf0cc, 0x2fbe,
+ 0xf140, 0x2ff1,
+ 0xf163, 0x3015,
+ 0xf16b, 0x3160,
+ 0xf16c, 0x301d,
+ 0xf1a1, 0x3030,
+ 0xf240, 0x308e,
+ 0xf268, 0x31ef,
+ 0xf269, 0x30b6,
+ 0xf2a1, 0x30cc,
+ 0xf2c3, 0x30ef,
+ 0xf340, 0x312b,
+ 0xf375, 0x3161,
+ 0xf3a1, 0x316b,
+ 0xf440, 0x31c9,
+ 0xf466, 0x31f0,
+ 0xf4a1, 0x3209,
+ 0xf4b5, 0x30ee,
+ 0xf4b6, 0x321d,
+ 0xf4fd, 0x3265,
+ 0xf540, 0x3267,
+ 0xf5a1, 0x32a6,
+ 0xf640, 0x3304,
+ 0xf663, 0x3264,
+ 0xf664, 0x3327,
+ 0xf6a1, 0x3342,
+ 0xf740, 0x33a0,
+ 0xf7a1, 0x33df,
+ 0xf840, 0x343d,
+ 0xf8a1, 0x347c,
+ 0xf940, 0x34da,
+ 0xf977, 0x3512,
+ 0xf9a1, 0x351a,
+ 0xf9c4, 0x3511,
+ 0xf9c5, 0x353d,
+ 0xf9c6, 0x3549,
+ 0xf9c7, 0x353e,
+ 0xf9d2, 0x354a,
+ 0xfa40, 0x3d6d,
+ 0xfa41, 0x39c4,
+ 0xfa42, 0x4399,
+ 0xfa43, 0x3f4f,
+ 0xfa44, 0x3e05,
+ 0xfa45, 0x439a,
+ 0xfa46, 0x3b8e,
+ 0xfa47, 0x36ea,
+ 0xfa48, 0x39c8,
+ 0xfa49, 0x393d,
+ 0xfa4a, 0x439b,
+ 0xfa4b, 0x4022,
+ 0xfa4c, 0x39cc,
+ 0xfa4e, 0x439c,
+ 0xfa4f, 0x39c5,
+ 0xfa50, 0x439d,
+ 0xfa51, 0x4034,
+ 0xfa52, 0x439e,
+ 0xfa54, 0x3ea3,
+ 0xfa55, 0x3ea6,
+ 0xfa56, 0x43a0,
+ 0xfa57, 0x4051,
+ 0xfa58, 0x4048,
+ 0xfa5a, 0x404b,
+ 0xfa5b, 0x404f,
+ 0xfa5c, 0x4054,
+ 0xfa5d, 0x4178,
+ 0xfa5e, 0x3f0a,
+ 0xfa5f, 0x43a1,
+ 0xfa61, 0x405a,
+ 0xfa62, 0x3ea4,
+ 0xfa63, 0x3dbd,
+ 0xfa64, 0x43a3,
+ 0xfa65, 0x3dbf,
+ 0xfa66, 0x405c,
+ 0xfa67, 0x405f,
+ 0xfa69, 0x4063,
+ 0xfa6a, 0x43a4,
+ 0xfa6b, 0x407a,
+ 0xfa6d, 0x407d,
+ 0xfa6e, 0x4082,
+ 0xfa6f, 0x3f6d,
+ 0xfa70, 0x43a5,
+ 0xfa71, 0x408b,
+ 0xfa72, 0x43a6,
+ 0xfa73, 0x3f39,
+ 0xfa74, 0x4093,
+ 0xfa75, 0x4096,
+ 0xfa76, 0x43a7,
+ 0xfa77, 0x4098,
+ 0xfa78, 0x3e7f,
+ 0xfa79, 0x3c77,
+ 0xfa7a, 0x3ea7,
+ 0xfa7b, 0x4203,
+ 0xfa7c, 0x3ed1,
+ 0xfa7d, 0x3e8a,
+ 0xfa7e, 0x3e98,
+ 0xfaa1, 0x3e8c,
+ 0xfaa2, 0x40a1,
+ 0xfaa3, 0x3d83,
+ 0xfaa4, 0x3a00,
+ 0xfaa5, 0x39a3,
+ 0xfaa6, 0x3e8d,
+ 0xfaa7, 0x43a8,
+ 0xfaa8, 0x3f58,
+ 0xfaa9, 0x3dbc,
+ 0xfaaa, 0x40a2,
+ 0xfaab, 0x3ccc,
+ 0xfaac, 0x3ea8,
+ 0xfaae, 0x3b2e,
+ 0xfaaf, 0x3bc6,
+ 0xfab0, 0x3e8b,
+ 0xfab1, 0x3e9f,
+ 0xfab2, 0x432c,
+ 0xfab3, 0x43a9,
+ 0xfab4, 0x3f08,
+ 0xfab5, 0x3ea5,
+ 0xfab6, 0x3e89,
+ 0xfab7, 0x3dc3,
+ 0xfab8, 0x3e82,
+ 0xfab9, 0x3e81,
+ 0xfaba, 0x3e94,
+ 0xfabb, 0x43aa,
+ 0xfabc, 0x3e83,
+ 0xfabd, 0x3e88,
+ 0xfabe, 0x43ab,
+ 0xfabf, 0x3e91,
+ 0xfac0, 0x43ac,
+ 0xfac1, 0x3e7c,
+ 0xfac2, 0x3e80,
+ 0xfac3, 0x3e8f,
+ 0xfac4, 0x4325,
+ 0xfac5, 0x3e67,
+ 0xfac6, 0x3e78,
+ 0xfac7, 0x3e68,
+ 0xfac8, 0x43ad,
+ 0xfac9, 0x37d2,
+ 0xfaca, 0x3f4d,
+ 0xfacb, 0x43ae,
+ 0xfacc, 0x3e7e,
+ 0xfacd, 0x40bc,
+ 0xface, 0x3e63,
+ 0xfacf, 0x40bd,
+ 0xfad0, 0x43af,
+ 0xfad1, 0x3f6c,
+ 0xfad2, 0x3ef9,
+ 0xfad3, 0x40b7,
+ 0xfad4, 0x3eb7,
+ 0xfad5, 0x3eed,
+ 0xfad6, 0x3f6a,
+ 0xfad7, 0x39a6,
+ 0xfad8, 0x43b0,
+ 0xfad9, 0x3e95,
+ 0xfada, 0x3948,
+ 0xfadb, 0x3cc8,
+ 0xfadc, 0x43b1,
+ 0xfadf, 0x40cc,
+ 0xfae0, 0x3e86,
+ 0xfae1, 0x40c8,
+ 0xfae2, 0x3c7a,
+ 0xfae3, 0x3c7d,
+ 0xfae4, 0x43b4,
+ 0xfae5, 0x40d1,
+ 0xfae6, 0x3d72,
+ 0xfae7, 0x40d4,
+ 0xfae8, 0x3c26,
+ 0xfae9, 0x36eb,
+ 0xfaea, 0x40da,
+ 0xfaeb, 0x40d9,
+ 0xfaec, 0x40bf,
+ 0xfaed, 0x3d81,
+ 0xfaee, 0x40f1,
+ 0xfaef, 0x4100,
+ 0xfaf0, 0x3c85,
+ 0xfaf1, 0x43b5,
+ 0xfaf2, 0x3a1d,
+ 0xfaf3, 0x37f5,
+ 0xfaf4, 0x36ee,
+ 0xfaf5, 0x3e5f,
+ 0xfaf6, 0x4116,
+ 0xfaf7, 0x42bb,
+ 0xfaf8, 0x411f,
+ 0xfaf9, 0x43b6,
+ 0xfafa, 0x4118,
+ 0xfafb, 0x43b7,
+ 0xfafd, 0x4123,
+ 0xfafe, 0x4122,
+ 0xfb40, 0x4127,
+ 0xfb41, 0x43b9,
+ 0xfb42, 0x4129,
+ 0xfb43, 0x43ba,
+ 0xfb44, 0x3dd5,
+ 0xfb45, 0x3eef,
+ 0xfb46, 0x3d8a,
+ 0xfb47, 0x43bb,
+ 0xfb48, 0x3a2b,
+ 0xfb49, 0x43bc,
+ 0xfb4a, 0x4138,
+ 0xfb4b, 0x43bd,
+ 0xfb4c, 0x3e8e,
+ 0xfb4d, 0x3a30,
+ 0xfb4e, 0x386f,
+ 0xfb4f, 0x4143,
+ 0xfb50, 0x4146,
+ 0xfb51, 0x4144,
+ 0xfb52, 0x4149,
+ 0xfb53, 0x3ba5,
+ 0xfb54, 0x4157,
+ 0xfb55, 0x43be,
+ 0xfb56, 0x4161,
+ 0xfb57, 0x36ec,
+ 0xfb58, 0x416a,
+ 0xfb59, 0x3d84,
+ 0xfb5a, 0x4002,
+ 0xfb5b, 0x4186,
+ 0xfb5c, 0x3fba,
+ 0xfb5d, 0x43bf,
+ 0xfb5e, 0x3fc5,
+ 0xfb5f, 0x3f50,
+ 0xfb60, 0x3e96,
+ 0xfb61, 0x43c0,
+ 0xfb62, 0x418a,
+ 0xfb63, 0x3fc1,
+ 0xfb64, 0x3d8f,
+ 0xfb65, 0x43c1,
+ 0xfb66, 0x3ea0,
+ 0xfb67, 0x3f16,
+ 0xfb68, 0x3e9d,
+ 0xfb69, 0x418e,
+ 0xfb6a, 0x4192,
+ 0xfb6b, 0x3a66,
+ 0xfb6c, 0x3e9c,
+ 0xfb6d, 0x438f,
+ 0xfb6e, 0x3e90,
+ 0xfb6f, 0x419d,
+ 0xfb70, 0x43c2,
+ 0xfb72, 0x4356,
+ 0xfb73, 0x37a8,
+ 0xfb74, 0x419e,
+ 0xfb75, 0x4199,
+ 0xfb76, 0x4187,
+ 0xfb77, 0x3ea2,
+ 0xfb78, 0x419f,
+ 0xfb79, 0x3e87,
+ 0xfb7a, 0x3e84,
+ 0xfb7b, 0x3eae,
+ 0xfb7c, 0x3b74,
+ 0xfb7e, 0x37a2,
+ 0xfba1, 0x3b72,
+ 0xfba2, 0x3e79,
+ 0xfba3, 0x3e6d,
+ 0xfba4, 0x43c4,
+ 0xfba6, 0x3eb2,
+ 0xfba7, 0x43c6,
+ 0xfba8, 0x3eac,
+ 0xfba9, 0x41ca,
+ 0xfbaa, 0x41f4,
+ 0xfbab, 0x43c7,
+ 0xfbac, 0x41d0,
+ 0xfbad, 0x3aaa,
+ 0xfbae, 0x41de,
+ 0xfbaf, 0x41db,
+ 0xfbb0, 0x41e8,
+ 0xfbb1, 0x43c8,
+ 0xfbb2, 0x3ff6,
+ 0xfbb3, 0x41d9,
+ 0xfbb4, 0x3d42,
+ 0xfbb5, 0x41f5,
+ 0xfbb6, 0x41f8,
+ 0xfbb7, 0x41fb,
+ 0xfbb8, 0x4205,
+ 0xfbb9, 0x3d8e,
+ 0xfbba, 0x420e,
+ 0xfbbb, 0x3d63,
+ 0xfbbc, 0x4222,
+ 0xfbbd, 0x4221,
+ 0xfbbe, 0x4223,
+ 0xfbbf, 0x4069,
+ 0xfbc0, 0x402f,
+ 0xfbc1, 0x4242,
+ 0xfbc2, 0x38a5,
+ 0xfbc3, 0x4246,
+ 0xfbc4, 0x3cf5,
+ 0xfbc5, 0x3d69,
+ 0xfbc6, 0x3cfe,
+ 0xfbc7, 0x425b,
+ 0xfbc8, 0x3ac8,
+ 0xfbc9, 0x3dc0,
+ 0xfbca, 0x39ea,
+ 0xfbcb, 0x4000,
+ 0xfbcc, 0x4264,
+ 0xfbcd, 0x4262,
+ 0xfbce, 0x3fff,
+ 0xfbcf, 0x3e9a,
+ 0xfbd0, 0x4273,
+ 0xfbd1, 0x3969,
+ 0xfbd2, 0x427a,
+ 0xfbd3, 0x4283,
+ 0xfbd4, 0x43c9,
+ 0xfbd6, 0x3f9a,
+ 0xfbd7, 0x3eb5,
+ 0xfbd8, 0x43cb,
+ 0xfbda, 0x3fb2,
+ 0xfbdb, 0x428a,
+ 0xfbdd, 0x3b17,
+ 0xfbde, 0x428c,
+ 0xfbdf, 0x4290,
+ 0xfbe0, 0x3adf,
+ 0xfbe1, 0x43cd,
+ 0xfbe2, 0x42c5,
+ 0xfbe3, 0x42c8,
+ 0xfbe4, 0x3ead,
+ 0xfbe5, 0x43ce,
+ 0xfbe6, 0x3f8f,
+ 0xfbe7, 0x43cf,
+ 0xfbe8, 0x3e72,
+ 0xfbe9, 0x3e70,
+ 0xfbea, 0x43d0,
+ 0xfbeb, 0x3eaa,
+ 0xfbec, 0x43d1,
+ 0xfbed, 0x3fa9,
+ 0xfbee, 0x43d2,
+ 0xfbf1, 0x42d8,
+ 0xfbf2, 0x3ff3,
+ 0xfbf3, 0x42e0,
+ 0xfbf4, 0x3b00,
+ 0xfbf5, 0x4317,
+ 0xfbf6, 0x382d,
+ 0xfbf7, 0x3e73,
+ 0xfbf8, 0x3fd5,
+ 0xfbf9, 0x43d5,
+ 0xfbfb, 0x3b14,
+ 0xfbfc, 0x36e8,
+ 0xfbfd, 0x42f4,
+ 0xfbfe, 0x3b0e,
+ 0xfc40, 0x42ec,
+ 0xfc41, 0x42f0,
+ 0xfc42, 0x3e7d,
+ 0xfc43, 0x43d7,
+ 0xfc44, 0x42fe,
+ 0xfc45, 0x4305,
+ 0xfc46, 0x3fda,
+ 0xfc47, 0x3df1,
+ 0xfc48, 0x3733,
+ 0xfc49, 0x3d7d,
+ 0xfc4a, 0x43d8,
+ 0xfc4b, 0x373a,
+ 0xfc4c, 0x3740,
+ 0xfc4d, 0x3742,
+ 0xfc4e, 0x3746,
+ 0xfc4f, 0x3752,
+ 0xfc50, 0x3f1f,
+ 0xfc51, 0x43d9,
+ 0xfc52, 0x36ed,
+ 0xfc53, 0x3b4a,
+ 0xfc54, 0x375e,
+ 0xfc55, 0x3b45,
+ 0xfc56, 0x43da,
+ 0xfc57, 0x3ede,
+ 0xfc58, 0x3769,
+ 0xfc59, 0x376c,
+ 0xfc5a, 0x376b,
+ 0xfc5b, 0x376e,
+ 0xfc5c, 0x377f,
+ 0xfc5d, 0x377b,
+ 0xfc5e, 0x3782,
+ 0xfc5f, 0x3e69,
+ 0xfc60, 0x3b4f,
+ 0xfc61, 0x3786,
+ 0xfc62, 0x43db,
+ 0xfc63, 0x3788,
+ 0xfc64, 0x43dc,
+ 0xfc65, 0x3ecd,
+ 0xfc66, 0x3797,
+ 0xfc67, 0x420d,
+ 0xfc68, 0x43dd,
+ 0xfc69, 0x37bc,
+ 0xfc6a, 0x43de,
+ 0xfc6b, 0x37d8,
+ 0xfc6c, 0x3b71,
+ 0xfc6d, 0x3e7a,
+ 0xfc6e, 0x43df,
+ 0xfc6f, 0x38dc,
+ 0xfc70, 0x37e0,
+ 0xfc71, 0x37ee,
+ 0xfc72, 0x37f4,
+ 0xfc73, 0x3813,
+ 0xfc74, 0x43e0,
+ 0xfc76, 0x3eb0,
+ 0xfc77, 0x43e2,
+ 0xfc78, 0x3fed,
+ 0xfc79, 0x380d,
+ 0xfc7a, 0x3eaf,
+ 0xfc7b, 0x3f92,
+ 0xfc7c, 0x3816,
+ 0xfc7d, 0x381b,
+ 0xfc7e, 0x3fa2,
+ 0xfca1, 0x381c,
+ 0xfca2, 0x381e,
+ 0xfca4, 0x3eb1,
+ 0xfca5, 0x134a,
+ 0xfca6, 0x43e3,
+ 0xfca7, 0x3fe9,
+ 0xfca8, 0x43e4,
+ 0xfca9, 0x3ff9,
+ 0xfcaa, 0x3d93,
+ 0xfcab, 0x43e5,
+ 0xfcac, 0x3e59,
+ 0xfcad, 0x43e6,
+ 0xfcae, 0x3837,
+ 0xfcaf, 0x3f99,
+ 0xfcb0, 0x3e99,
+ 0xfcb1, 0x3e5e,
+ 0xfcb2, 0x3bb4,
+ 0xfcb3, 0x3eab,
+ 0xfcb4, 0x43e7,
+ 0xfcb6, 0x385e,
+ 0xfcb7, 0x43e9,
+ 0xfcb8, 0x3dbe,
+ 0xfcb9, 0x3e85,
+ 0xfcba, 0x3863,
+ 0xfcbc, 0x3d6c,
+ 0xfcbd, 0x3871,
+ 0xfcbe, 0x3ee0,
+ 0xfcbf, 0x43ea,
+ 0xfcc0, 0x387c,
+ 0xfcc1, 0x43eb,
+ 0xfcc2, 0x3eb8,
+ 0xfcc3, 0x3882,
+ 0xfcc4, 0x3e9b,
+ 0xfcc5, 0x43ec,
+ 0xfcc6, 0x3888,
+ 0xfcc7, 0x3c0e,
+ 0xfcc8, 0x382e,
+ 0xfcc9, 0x389a,
+ 0xfcca, 0x388b,
+ 0xfccb, 0x3c04,
+ 0xfccc, 0x36e9,
+ 0xfccd, 0x42bd,
+ 0xfcce, 0x3bcd,
+ 0xfccf, 0x389f,
+ 0xfcd0, 0x3dde,
+ 0xfcd1, 0x379b,
+ 0xfcd2, 0x3bd3,
+ 0xfcd3, 0x38af,
+ 0xfcd4, 0x3e97,
+ 0xfcd5, 0x38d6,
+ 0xfcd6, 0x3f35,
+ 0xfcd7, 0x38e0,
+ 0xfcd8, 0x4035,
+ 0xfcd9, 0x38f0,
+ 0xfcda, 0x43ed,
+ 0xfcdc, 0x3bfd,
+ 0xfcdd, 0x3c11,
+ 0xfcdf, 0x43ef,
+ 0xfce0, 0x3785,
+ 0xfce1, 0x3902,
+ 0xfce2, 0x3ddc,
+ 0xfce3, 0x43f0,
+ 0xfce4, 0x3faa,
+ 0xfce5, 0x390b,
+ 0xfce6, 0x3f19,
+ 0xfce7, 0x390e,
+ 0xfce8, 0x3919,
+ 0xfce9, 0x43f1,
+ 0xfcea, 0x3c3c,
+ 0xfceb, 0x391a,
+ 0xfcec, 0x3c3a,
+ 0xfced, 0x391b,
+ 0xfcee, 0x3e66,
+ 0xfcef, 0x3f22,
+ 0xfcf0, 0x3d7e,
+ 0xfcf1, 0x3e71,
+ 0xfcf2, 0x3c39,
+ 0xfcf3, 0x3ea1,
+ 0xfcf4, 0x43f2,
+ 0xfcf6, 0x3f30,
+ 0xfcf7, 0x3929,
+ 0xfcf8, 0x3fbc,
+ 0xfcf9, 0x3936,
+ 0xfcfa, 0x43f4,
+ 0xfcfb, 0x3937,
+ 0xfcfc, 0x3f90,
+ 0xfcfd, 0x43f5,
+ 0xfcfe, 0x0aba,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 cns13HKm471B5HEnc16 = {
+ 0,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
+ 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010,
+ 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018,
+ 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020,
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028,
+ 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030,
+ 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038,
+ 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040,
+ 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048,
+ 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050,
+ 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
+ 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ cns13HKm471B5HMap2, 690
+};
+
+static Gushort cns13HKm471B5VMap2[1404] = {
+ 0x0000, 0x0000,
+ 0xa140, 0x0063,
+ 0xa159, 0x35af,
+ 0xa15d, 0x0080,
+ 0xa1a1, 0x00a2,
+ 0xa1f6, 0x00f8,
+ 0xa1f7, 0x00f7,
+ 0xa1f8, 0x00f9,
+ 0xa240, 0x0100,
+ 0xa2a1, 0x013f,
+ 0xa340, 0x019d,
+ 0xa3a1, 0x01dc,
+ 0xa3bd, 0x01f7,
+ 0xa440, 0x0253,
+ 0xa4a1, 0x0292,
+ 0xa540, 0x02f0,
+ 0xa5a1, 0x032f,
+ 0xa640, 0x038d,
+ 0xa6a1, 0x03cc,
+ 0xa740, 0x042a,
+ 0xa7a1, 0x0469,
+ 0xa840, 0x04c7,
+ 0xa8a1, 0x0506,
+ 0xa940, 0x0564,
+ 0xa9a1, 0x05a3,
+ 0xaa40, 0x0601,
+ 0xaaa1, 0x0640,
+ 0xab40, 0x069e,
+ 0xaba1, 0x06dd,
+ 0xac40, 0x073b,
+ 0xaca1, 0x077a,
+ 0xacfe, 0x097f,
+ 0xad40, 0x07d7,
+ 0xada1, 0x0816,
+ 0xae40, 0x0874,
+ 0xaea1, 0x08b3,
+ 0xaf40, 0x0911,
+ 0xafa1, 0x0950,
+ 0xafd0, 0x0980,
+ 0xb040, 0x09af,
+ 0xb0a1, 0x09ee,
+ 0xb140, 0x0a4c,
+ 0xb1a1, 0x0a8b,
+ 0xb240, 0x0ae9,
+ 0xb2a1, 0x0b28,
+ 0xb340, 0x0b86,
+ 0xb3a1, 0x0bc5,
+ 0xb440, 0x0c23,
+ 0xb4a1, 0x0c62,
+ 0xb540, 0x0cc0,
+ 0xb5a1, 0x0cff,
+ 0xb640, 0x0d5d,
+ 0xb6a1, 0x0d9c,
+ 0xb740, 0x0dfa,
+ 0xb7a1, 0x0e39,
+ 0xb840, 0x0e97,
+ 0xb8a1, 0x0ed6,
+ 0xb940, 0x0f34,
+ 0xb9a1, 0x0f73,
+ 0xba40, 0x0fd1,
+ 0xbaa1, 0x1010,
+ 0xbb40, 0x106e,
+ 0xbba1, 0x10ad,
+ 0xbbc8, 0x10d5,
+ 0xbc40, 0x110c,
+ 0xbca1, 0x114b,
+ 0xbd40, 0x11a9,
+ 0xbda1, 0x11e8,
+ 0xbe40, 0x1246,
+ 0xbe52, 0x10d4,
+ 0xbe53, 0x1258,
+ 0xbea1, 0x1284,
+ 0xbf40, 0x12e2,
+ 0xbfa1, 0x1321,
+ 0xc040, 0x137f,
+ 0xc0a1, 0x13be,
+ 0xc140, 0x141c,
+ 0xc1a1, 0x145b,
+ 0xc1ab, 0x1466,
+ 0xc240, 0x14ba,
+ 0xc2a1, 0x14f9,
+ 0xc2cb, 0x1465,
+ 0xc2cc, 0x1523,
+ 0xc340, 0x1556,
+ 0xc361, 0x1578,
+ 0xc3a1, 0x1596,
+ 0xc3b9, 0x15af,
+ 0xc3ba, 0x15ae,
+ 0xc3bb, 0x15b0,
+ 0xc440, 0x15f4,
+ 0xc456, 0x1577,
+ 0xc457, 0x160a,
+ 0xc4a1, 0x1632,
+ 0xc540, 0x1690,
+ 0xc5a1, 0x16cf,
+ 0xc640, 0x172d,
+ 0xc940, 0x176c,
+ 0xc94a, 0x0274,
+ 0xc94b, 0x1776,
+ 0xc96c, 0x1798,
+ 0xc9a1, 0x17ab,
+ 0xc9be, 0x1797,
+ 0xc9bf, 0x17c8,
+ 0xc9ed, 0x17f7,
+ 0xca40, 0x1809,
+ 0xcaa1, 0x1848,
+ 0xcaf7, 0x17f6,
+ 0xcaf8, 0x189e,
+ 0xcb40, 0x18a5,
+ 0xcba1, 0x18e4,
+ 0xcc40, 0x1942,
+ 0xcca1, 0x1981,
+ 0xcd40, 0x19df,
+ 0xcda1, 0x1a1e,
+ 0xce40, 0x1a7c,
+ 0xcea1, 0x1abb,
+ 0xcf40, 0x1b19,
+ 0xcfa1, 0x1b58,
+ 0xd040, 0x1bb6,
+ 0xd0a1, 0x1bf5,
+ 0xd140, 0x1c53,
+ 0xd1a1, 0x1c92,
+ 0xd240, 0x1cf0,
+ 0xd2a1, 0x1d2f,
+ 0xd340, 0x1d8d,
+ 0xd3a1, 0x1dcc,
+ 0xd440, 0x1e2a,
+ 0xd4a1, 0x1e69,
+ 0xd540, 0x1ec7,
+ 0xd5a1, 0x1f06,
+ 0xd640, 0x1f64,
+ 0xd6a1, 0x1fa3,
+ 0xd6cc, 0x2254,
+ 0xd6cd, 0x1fcf,
+ 0xd740, 0x2001,
+ 0xd77a, 0x22b9,
+ 0xd77b, 0x203b,
+ 0xd7a1, 0x203f,
+ 0xd840, 0x209d,
+ 0xd8a1, 0x20dc,
+ 0xd940, 0x213a,
+ 0xd9a1, 0x2179,
+ 0xda40, 0x21d7,
+ 0xdaa1, 0x2216,
+ 0xdadf, 0x1fce,
+ 0xdae0, 0x2255,
+ 0xdb40, 0x2274,
+ 0xdba1, 0x22b3,
+ 0xdba7, 0x22ba,
+ 0xdc40, 0x2312,
+ 0xdca1, 0x2351,
+ 0xdd40, 0x23af,
+ 0xdda1, 0x23ee,
+ 0xddfc, 0x2381,
+ 0xddfd, 0x2449,
+ 0xde40, 0x244b,
+ 0xdea1, 0x248a,
+ 0xdf40, 0x24e8,
+ 0xdfa1, 0x2527,
+ 0xe040, 0x2585,
+ 0xe0a1, 0x25c4,
+ 0xe140, 0x2622,
+ 0xe1a1, 0x2661,
+ 0xe240, 0x26bf,
+ 0xe2a1, 0x26fe,
+ 0xe340, 0x275c,
+ 0xe3a1, 0x279b,
+ 0xe440, 0x27f9,
+ 0xe4a1, 0x2838,
+ 0xe540, 0x2896,
+ 0xe5a1, 0x28d5,
+ 0xe640, 0x2933,
+ 0xe6a1, 0x2972,
+ 0xe740, 0x29d0,
+ 0xe7a1, 0x2a0f,
+ 0xe840, 0x2a6d,
+ 0xe8a1, 0x2aac,
+ 0xe8a3, 0x2aaf,
+ 0xe940, 0x2b0b,
+ 0xe976, 0x2b42,
+ 0xe9a1, 0x2b4b,
+ 0xea40, 0x2ba9,
+ 0xeaa1, 0x2be8,
+ 0xeb40, 0x2c46,
+ 0xeb5b, 0x2c62,
+ 0xeba1, 0x2c86,
+ 0xebf1, 0x2aae,
+ 0xebf2, 0x2cd6,
+ 0xec40, 0x2ce3,
+ 0xeca1, 0x2d22,
+ 0xecde, 0x2b41,
+ 0xecdf, 0x2d5f,
+ 0xed40, 0x2d7f,
+ 0xeda1, 0x2dbe,
+ 0xedaa, 0x2dc8,
+ 0xee40, 0x2e1d,
+ 0xeea1, 0x2e5c,
+ 0xeeeb, 0x3014,
+ 0xeeec, 0x2ea6,
+ 0xef40, 0x2eb9,
+ 0xefa1, 0x2ef8,
+ 0xf040, 0x2f56,
+ 0xf056, 0x2dc7,
+ 0xf057, 0x2f6c,
+ 0xf0a1, 0x2f94,
+ 0xf0cb, 0x2c61,
+ 0xf0cc, 0x2fbe,
+ 0xf140, 0x2ff1,
+ 0xf163, 0x3015,
+ 0xf16b, 0x3160,
+ 0xf16c, 0x301d,
+ 0xf1a1, 0x3030,
+ 0xf240, 0x308e,
+ 0xf268, 0x31ef,
+ 0xf269, 0x30b6,
+ 0xf2a1, 0x30cc,
+ 0xf2c3, 0x30ef,
+ 0xf340, 0x312b,
+ 0xf375, 0x3161,
+ 0xf3a1, 0x316b,
+ 0xf440, 0x31c9,
+ 0xf466, 0x31f0,
+ 0xf4a1, 0x3209,
+ 0xf4b5, 0x30ee,
+ 0xf4b6, 0x321d,
+ 0xf4fd, 0x3265,
+ 0xf540, 0x3267,
+ 0xf5a1, 0x32a6,
+ 0xf640, 0x3304,
+ 0xf663, 0x3264,
+ 0xf664, 0x3327,
+ 0xf6a1, 0x3342,
+ 0xf740, 0x33a0,
+ 0xf7a1, 0x33df,
+ 0xf840, 0x343d,
+ 0xf8a1, 0x347c,
+ 0xf940, 0x34da,
+ 0xf977, 0x3512,
+ 0xf9a1, 0x351a,
+ 0xf9c4, 0x3511,
+ 0xf9c5, 0x353d,
+ 0xf9c6, 0x3549,
+ 0xf9c7, 0x353e,
+ 0xf9d2, 0x354a,
+ 0xfa40, 0x3d6d,
+ 0xfa41, 0x39c4,
+ 0xfa42, 0x4399,
+ 0xfa43, 0x3f4f,
+ 0xfa44, 0x3e05,
+ 0xfa45, 0x439a,
+ 0xfa46, 0x3b8e,
+ 0xfa47, 0x36ea,
+ 0xfa48, 0x39c8,
+ 0xfa49, 0x393d,
+ 0xfa4a, 0x439b,
+ 0xfa4b, 0x4022,
+ 0xfa4c, 0x39cc,
+ 0xfa4e, 0x439c,
+ 0xfa4f, 0x39c5,
+ 0xfa50, 0x439d,
+ 0xfa51, 0x4034,
+ 0xfa52, 0x439e,
+ 0xfa54, 0x3ea3,
+ 0xfa55, 0x3ea6,
+ 0xfa56, 0x43a0,
+ 0xfa57, 0x4051,
+ 0xfa58, 0x4048,
+ 0xfa5a, 0x404b,
+ 0xfa5b, 0x404f,
+ 0xfa5c, 0x4054,
+ 0xfa5d, 0x4178,
+ 0xfa5e, 0x3f0a,
+ 0xfa5f, 0x43a1,
+ 0xfa61, 0x405a,
+ 0xfa62, 0x3ea4,
+ 0xfa63, 0x3dbd,
+ 0xfa64, 0x43a3,
+ 0xfa65, 0x3dbf,
+ 0xfa66, 0x405c,
+ 0xfa67, 0x405f,
+ 0xfa69, 0x4063,
+ 0xfa6a, 0x43a4,
+ 0xfa6b, 0x407a,
+ 0xfa6d, 0x407d,
+ 0xfa6e, 0x4082,
+ 0xfa6f, 0x3f6d,
+ 0xfa70, 0x43a5,
+ 0xfa71, 0x408b,
+ 0xfa72, 0x43a6,
+ 0xfa73, 0x3f39,
+ 0xfa74, 0x4093,
+ 0xfa75, 0x4096,
+ 0xfa76, 0x43a7,
+ 0xfa77, 0x4098,
+ 0xfa78, 0x3e7f,
+ 0xfa79, 0x3c77,
+ 0xfa7a, 0x3ea7,
+ 0xfa7b, 0x4203,
+ 0xfa7c, 0x3ed1,
+ 0xfa7d, 0x3e8a,
+ 0xfa7e, 0x3e98,
+ 0xfaa1, 0x3e8c,
+ 0xfaa2, 0x40a1,
+ 0xfaa3, 0x3d83,
+ 0xfaa4, 0x3a00,
+ 0xfaa5, 0x39a3,
+ 0xfaa6, 0x3e8d,
+ 0xfaa7, 0x43a8,
+ 0xfaa8, 0x3f58,
+ 0xfaa9, 0x3dbc,
+ 0xfaaa, 0x40a2,
+ 0xfaab, 0x3ccc,
+ 0xfaac, 0x3ea8,
+ 0xfaae, 0x3b2e,
+ 0xfaaf, 0x3bc6,
+ 0xfab0, 0x3e8b,
+ 0xfab1, 0x3e9f,
+ 0xfab2, 0x432c,
+ 0xfab3, 0x43a9,
+ 0xfab4, 0x3f08,
+ 0xfab5, 0x3ea5,
+ 0xfab6, 0x3e89,
+ 0xfab7, 0x3dc3,
+ 0xfab8, 0x3e82,
+ 0xfab9, 0x3e81,
+ 0xfaba, 0x3e94,
+ 0xfabb, 0x43aa,
+ 0xfabc, 0x3e83,
+ 0xfabd, 0x3e88,
+ 0xfabe, 0x43ab,
+ 0xfabf, 0x3e91,
+ 0xfac0, 0x43ac,
+ 0xfac1, 0x3e7c,
+ 0xfac2, 0x3e80,
+ 0xfac3, 0x3e8f,
+ 0xfac4, 0x4325,
+ 0xfac5, 0x3e67,
+ 0xfac6, 0x3e78,
+ 0xfac7, 0x3e68,
+ 0xfac8, 0x43ad,
+ 0xfac9, 0x37d2,
+ 0xfaca, 0x3f4d,
+ 0xfacb, 0x43ae,
+ 0xfacc, 0x3e7e,
+ 0xfacd, 0x40bc,
+ 0xface, 0x3e63,
+ 0xfacf, 0x40bd,
+ 0xfad0, 0x43af,
+ 0xfad1, 0x3f6c,
+ 0xfad2, 0x3ef9,
+ 0xfad3, 0x40b7,
+ 0xfad4, 0x3eb7,
+ 0xfad5, 0x3eed,
+ 0xfad6, 0x3f6a,
+ 0xfad7, 0x39a6,
+ 0xfad8, 0x43b0,
+ 0xfad9, 0x3e95,
+ 0xfada, 0x3948,
+ 0xfadb, 0x3cc8,
+ 0xfadc, 0x43b1,
+ 0xfadf, 0x40cc,
+ 0xfae0, 0x3e86,
+ 0xfae1, 0x40c8,
+ 0xfae2, 0x3c7a,
+ 0xfae3, 0x3c7d,
+ 0xfae4, 0x43b4,
+ 0xfae5, 0x40d1,
+ 0xfae6, 0x3d72,
+ 0xfae7, 0x40d4,
+ 0xfae8, 0x3c26,
+ 0xfae9, 0x36eb,
+ 0xfaea, 0x40da,
+ 0xfaeb, 0x40d9,
+ 0xfaec, 0x40bf,
+ 0xfaed, 0x3d81,
+ 0xfaee, 0x40f1,
+ 0xfaef, 0x4100,
+ 0xfaf0, 0x3c85,
+ 0xfaf1, 0x43b5,
+ 0xfaf2, 0x3a1d,
+ 0xfaf3, 0x37f5,
+ 0xfaf4, 0x36ee,
+ 0xfaf5, 0x3e5f,
+ 0xfaf6, 0x4116,
+ 0xfaf7, 0x42bb,
+ 0xfaf8, 0x411f,
+ 0xfaf9, 0x43b6,
+ 0xfafa, 0x4118,
+ 0xfafb, 0x43b7,
+ 0xfafd, 0x4123,
+ 0xfafe, 0x4122,
+ 0xfb40, 0x4127,
+ 0xfb41, 0x43b9,
+ 0xfb42, 0x4129,
+ 0xfb43, 0x43ba,
+ 0xfb44, 0x3dd5,
+ 0xfb45, 0x3eef,
+ 0xfb46, 0x3d8a,
+ 0xfb47, 0x43bb,
+ 0xfb48, 0x3a2b,
+ 0xfb49, 0x43bc,
+ 0xfb4a, 0x4138,
+ 0xfb4b, 0x43bd,
+ 0xfb4c, 0x3e8e,
+ 0xfb4d, 0x3a30,
+ 0xfb4e, 0x386f,
+ 0xfb4f, 0x4143,
+ 0xfb50, 0x4146,
+ 0xfb51, 0x4144,
+ 0xfb52, 0x4149,
+ 0xfb53, 0x3ba5,
+ 0xfb54, 0x4157,
+ 0xfb55, 0x43be,
+ 0xfb56, 0x4161,
+ 0xfb57, 0x36ec,
+ 0xfb58, 0x416a,
+ 0xfb59, 0x3d84,
+ 0xfb5a, 0x4002,
+ 0xfb5b, 0x4186,
+ 0xfb5c, 0x3fba,
+ 0xfb5d, 0x43bf,
+ 0xfb5e, 0x3fc5,
+ 0xfb5f, 0x3f50,
+ 0xfb60, 0x3e96,
+ 0xfb61, 0x43c0,
+ 0xfb62, 0x418a,
+ 0xfb63, 0x3fc1,
+ 0xfb64, 0x3d8f,
+ 0xfb65, 0x43c1,
+ 0xfb66, 0x3ea0,
+ 0xfb67, 0x3f16,
+ 0xfb68, 0x3e9d,
+ 0xfb69, 0x418e,
+ 0xfb6a, 0x4192,
+ 0xfb6b, 0x3a66,
+ 0xfb6c, 0x3e9c,
+ 0xfb6d, 0x438f,
+ 0xfb6e, 0x3e90,
+ 0xfb6f, 0x419d,
+ 0xfb70, 0x43c2,
+ 0xfb72, 0x4356,
+ 0xfb73, 0x37a8,
+ 0xfb74, 0x419e,
+ 0xfb75, 0x4199,
+ 0xfb76, 0x4187,
+ 0xfb77, 0x3ea2,
+ 0xfb78, 0x419f,
+ 0xfb79, 0x3e87,
+ 0xfb7a, 0x3e84,
+ 0xfb7b, 0x3eae,
+ 0xfb7c, 0x3b74,
+ 0xfb7e, 0x37a2,
+ 0xfba1, 0x3b72,
+ 0xfba2, 0x3e79,
+ 0xfba3, 0x3e6d,
+ 0xfba4, 0x43c4,
+ 0xfba6, 0x3eb2,
+ 0xfba7, 0x43c6,
+ 0xfba8, 0x3eac,
+ 0xfba9, 0x41ca,
+ 0xfbaa, 0x41f4,
+ 0xfbab, 0x43c7,
+ 0xfbac, 0x41d0,
+ 0xfbad, 0x3aaa,
+ 0xfbae, 0x41de,
+ 0xfbaf, 0x41db,
+ 0xfbb0, 0x41e8,
+ 0xfbb1, 0x43c8,
+ 0xfbb2, 0x3ff6,
+ 0xfbb3, 0x41d9,
+ 0xfbb4, 0x3d42,
+ 0xfbb5, 0x41f5,
+ 0xfbb6, 0x41f8,
+ 0xfbb7, 0x41fb,
+ 0xfbb8, 0x4205,
+ 0xfbb9, 0x3d8e,
+ 0xfbba, 0x420e,
+ 0xfbbb, 0x3d63,
+ 0xfbbc, 0x4222,
+ 0xfbbd, 0x4221,
+ 0xfbbe, 0x4223,
+ 0xfbbf, 0x4069,
+ 0xfbc0, 0x402f,
+ 0xfbc1, 0x4242,
+ 0xfbc2, 0x38a5,
+ 0xfbc3, 0x4246,
+ 0xfbc4, 0x3cf5,
+ 0xfbc5, 0x3d69,
+ 0xfbc6, 0x3cfe,
+ 0xfbc7, 0x425b,
+ 0xfbc8, 0x3ac8,
+ 0xfbc9, 0x3dc0,
+ 0xfbca, 0x39ea,
+ 0xfbcb, 0x4000,
+ 0xfbcc, 0x4264,
+ 0xfbcd, 0x4262,
+ 0xfbce, 0x3fff,
+ 0xfbcf, 0x3e9a,
+ 0xfbd0, 0x4273,
+ 0xfbd1, 0x3969,
+ 0xfbd2, 0x427a,
+ 0xfbd3, 0x4283,
+ 0xfbd4, 0x43c9,
+ 0xfbd6, 0x3f9a,
+ 0xfbd7, 0x3eb5,
+ 0xfbd8, 0x43cb,
+ 0xfbda, 0x3fb2,
+ 0xfbdb, 0x428a,
+ 0xfbdd, 0x3b17,
+ 0xfbde, 0x428c,
+ 0xfbdf, 0x4290,
+ 0xfbe0, 0x3adf,
+ 0xfbe1, 0x43cd,
+ 0xfbe2, 0x42c5,
+ 0xfbe3, 0x42c8,
+ 0xfbe4, 0x3ead,
+ 0xfbe5, 0x43ce,
+ 0xfbe6, 0x3f8f,
+ 0xfbe7, 0x43cf,
+ 0xfbe8, 0x3e72,
+ 0xfbe9, 0x3e70,
+ 0xfbea, 0x43d0,
+ 0xfbeb, 0x3eaa,
+ 0xfbec, 0x43d1,
+ 0xfbed, 0x3fa9,
+ 0xfbee, 0x43d2,
+ 0xfbf1, 0x42d8,
+ 0xfbf2, 0x3ff3,
+ 0xfbf3, 0x42e0,
+ 0xfbf4, 0x3b00,
+ 0xfbf5, 0x4317,
+ 0xfbf6, 0x382d,
+ 0xfbf7, 0x3e73,
+ 0xfbf8, 0x3fd5,
+ 0xfbf9, 0x43d5,
+ 0xfbfb, 0x3b14,
+ 0xfbfc, 0x36e8,
+ 0xfbfd, 0x42f4,
+ 0xfbfe, 0x3b0e,
+ 0xfc40, 0x42ec,
+ 0xfc41, 0x42f0,
+ 0xfc42, 0x3e7d,
+ 0xfc43, 0x43d7,
+ 0xfc44, 0x42fe,
+ 0xfc45, 0x4305,
+ 0xfc46, 0x3fda,
+ 0xfc47, 0x3df1,
+ 0xfc48, 0x3733,
+ 0xfc49, 0x3d7d,
+ 0xfc4a, 0x43d8,
+ 0xfc4b, 0x373a,
+ 0xfc4c, 0x3740,
+ 0xfc4d, 0x3742,
+ 0xfc4e, 0x3746,
+ 0xfc4f, 0x3752,
+ 0xfc50, 0x3f1f,
+ 0xfc51, 0x43d9,
+ 0xfc52, 0x36ed,
+ 0xfc53, 0x3b4a,
+ 0xfc54, 0x375e,
+ 0xfc55, 0x3b45,
+ 0xfc56, 0x43da,
+ 0xfc57, 0x3ede,
+ 0xfc58, 0x3769,
+ 0xfc59, 0x376c,
+ 0xfc5a, 0x376b,
+ 0xfc5b, 0x376e,
+ 0xfc5c, 0x377f,
+ 0xfc5d, 0x377b,
+ 0xfc5e, 0x3782,
+ 0xfc5f, 0x3e69,
+ 0xfc60, 0x3b4f,
+ 0xfc61, 0x3786,
+ 0xfc62, 0x43db,
+ 0xfc63, 0x3788,
+ 0xfc64, 0x43dc,
+ 0xfc65, 0x3ecd,
+ 0xfc66, 0x3797,
+ 0xfc67, 0x420d,
+ 0xfc68, 0x43dd,
+ 0xfc69, 0x37bc,
+ 0xfc6a, 0x43de,
+ 0xfc6b, 0x37d8,
+ 0xfc6c, 0x3b71,
+ 0xfc6d, 0x3e7a,
+ 0xfc6e, 0x43df,
+ 0xfc6f, 0x38dc,
+ 0xfc70, 0x37e0,
+ 0xfc71, 0x37ee,
+ 0xfc72, 0x37f4,
+ 0xfc73, 0x3813,
+ 0xfc74, 0x43e0,
+ 0xfc76, 0x3eb0,
+ 0xfc77, 0x43e2,
+ 0xfc78, 0x3fed,
+ 0xfc79, 0x380d,
+ 0xfc7a, 0x3eaf,
+ 0xfc7b, 0x3f92,
+ 0xfc7c, 0x3816,
+ 0xfc7d, 0x381b,
+ 0xfc7e, 0x3fa2,
+ 0xfca1, 0x381c,
+ 0xfca2, 0x381e,
+ 0xfca4, 0x3eb1,
+ 0xfca5, 0x134a,
+ 0xfca6, 0x43e3,
+ 0xfca7, 0x3fe9,
+ 0xfca8, 0x43e4,
+ 0xfca9, 0x3ff9,
+ 0xfcaa, 0x3d93,
+ 0xfcab, 0x43e5,
+ 0xfcac, 0x3e59,
+ 0xfcad, 0x43e6,
+ 0xfcae, 0x3837,
+ 0xfcaf, 0x3f99,
+ 0xfcb0, 0x3e99,
+ 0xfcb1, 0x3e5e,
+ 0xfcb2, 0x3bb4,
+ 0xfcb3, 0x3eab,
+ 0xfcb4, 0x43e7,
+ 0xfcb6, 0x385e,
+ 0xfcb7, 0x43e9,
+ 0xfcb8, 0x3dbe,
+ 0xfcb9, 0x3e85,
+ 0xfcba, 0x3863,
+ 0xfcbc, 0x3d6c,
+ 0xfcbd, 0x3871,
+ 0xfcbe, 0x3ee0,
+ 0xfcbf, 0x43ea,
+ 0xfcc0, 0x387c,
+ 0xfcc1, 0x43eb,
+ 0xfcc2, 0x3eb8,
+ 0xfcc3, 0x3882,
+ 0xfcc4, 0x3e9b,
+ 0xfcc5, 0x43ec,
+ 0xfcc6, 0x3888,
+ 0xfcc7, 0x3c0e,
+ 0xfcc8, 0x382e,
+ 0xfcc9, 0x389a,
+ 0xfcca, 0x388b,
+ 0xfccb, 0x3c04,
+ 0xfccc, 0x36e9,
+ 0xfccd, 0x42bd,
+ 0xfcce, 0x3bcd,
+ 0xfccf, 0x389f,
+ 0xfcd0, 0x3dde,
+ 0xfcd1, 0x379b,
+ 0xfcd2, 0x3bd3,
+ 0xfcd3, 0x38af,
+ 0xfcd4, 0x3e97,
+ 0xfcd5, 0x38d6,
+ 0xfcd6, 0x3f35,
+ 0xfcd7, 0x38e0,
+ 0xfcd8, 0x4035,
+ 0xfcd9, 0x38f0,
+ 0xfcda, 0x43ed,
+ 0xfcdc, 0x3bfd,
+ 0xfcdd, 0x3c11,
+ 0xfcdf, 0x43ef,
+ 0xfce0, 0x3785,
+ 0xfce1, 0x3902,
+ 0xfce2, 0x3ddc,
+ 0xfce3, 0x43f0,
+ 0xfce4, 0x3faa,
+ 0xfce5, 0x390b,
+ 0xfce6, 0x3f19,
+ 0xfce7, 0x390e,
+ 0xfce8, 0x3919,
+ 0xfce9, 0x43f1,
+ 0xfcea, 0x3c3c,
+ 0xfceb, 0x391a,
+ 0xfcec, 0x3c3a,
+ 0xfced, 0x391b,
+ 0xfcee, 0x3e66,
+ 0xfcef, 0x3f22,
+ 0xfcf0, 0x3d7e,
+ 0xfcf1, 0x3e71,
+ 0xfcf2, 0x3c39,
+ 0xfcf3, 0x3ea1,
+ 0xfcf4, 0x43f2,
+ 0xfcf6, 0x3f30,
+ 0xfcf7, 0x3929,
+ 0xfcf8, 0x3fbc,
+ 0xfcf9, 0x3936,
+ 0xfcfa, 0x43f4,
+ 0xfcfb, 0x3937,
+ 0xfcfc, 0x3f90,
+ 0xfcfd, 0x43f5,
+ 0xfcfe, 0x0aba,
+ 0xa14b, 0x354e,
+ 0xa15a, 0x35af,
+ 0xa15c, 0x35b1,
+ 0xa15d, 0x0082,
+ 0xa161, 0x0086,
+ 0xa165, 0x008a,
+ 0xa169, 0x008e,
+ 0xa16d, 0x0092,
+ 0xa171, 0x0096,
+ 0xa175, 0x009a,
+ 0xa179, 0x009e,
+ 0xa1e3, 0x354f,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 cns13HKm471B5VEnc16 = {
+ 1,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
+ 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010,
+ 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018,
+ 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020,
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028,
+ 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030,
+ 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038,
+ 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040,
+ 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048,
+ 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050,
+ 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
+ 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ cns13HKm471B5VMap2, 702
+};
+
+static Gushort cns13HKscsB5HMap2[2258] = {
+ 0x0000, 0x0000,
+ 0x8840, 0x44c9,
+ 0x8856, 0x4961,
+ 0x88a1, 0x498a,
+ 0x88a9, 0x499c,
+ 0x8940, 0x4534,
+ 0x8943, 0x4536,
+ 0x8946, 0x4537,
+ 0x894c, 0x453b,
+ 0x894d, 0x43c3,
+ 0x894e, 0x453c,
+ 0x8951, 0x439a,
+ 0x8952, 0x453f,
+ 0x89a1, 0x456c,
+ 0x89a6, 0x43a2,
+ 0x89ab, 0x43ec,
+ 0x89ac, 0x4571,
+ 0x89ad, 0x43eb,
+ 0x89ae, 0x4572,
+ 0x89b0, 0x4573,
+ 0x89b5, 0x4576,
+ 0x89c1, 0x4581,
+ 0x89c5, 0x4584,
+ 0x89cf, 0x43bc,
+ 0x89d0, 0x458e,
+ 0x89d9, 0x439c,
+ 0x89da, 0x4597,
+ 0x89db, 0x439e,
+ 0x89dc, 0x4598,
+ 0x89dd, 0x439f,
+ 0x89de, 0x4599,
+ 0x89e1, 0x43a1,
+ 0x89e2, 0x459c,
+ 0x89e3, 0x43a3,
+ 0x89e4, 0x459d,
+ 0x89ea, 0x43a5,
+ 0x89ec, 0x45a3,
+ 0x89fa, 0x43a9,
+ 0x89fb, 0x45b1,
+ 0x8a40, 0x45b5,
+ 0x8a41, 0x4309,
+ 0x8a43, 0x430b,
+ 0x8a4d, 0x45b6,
+ 0x8a4e, 0x4316,
+ 0x8a5a, 0x45b7,
+ 0x8a5b, 0x4323,
+ 0x8a5e, 0x45b8,
+ 0x8a5f, 0x4327,
+ 0x8a64, 0x432c,
+ 0x8a71, 0x45b9,
+ 0x8a72, 0x433a,
+ 0x8a76, 0x433e,
+ 0x8a77, 0x45ba,
+ 0x8a78, 0x4340,
+ 0x8a7a, 0x45bb,
+ 0x8a7b, 0x4343,
+ 0x8a7c, 0x45bc,
+ 0x8a7d, 0x4345,
+ 0x8a7e, 0x45bd,
+ 0x8aa1, 0x4347,
+ 0x8aa8, 0x45be,
+ 0x8aa9, 0x434f,
+ 0x8aac, 0x4352,
+ 0x8ab2, 0x4358,
+ 0x8ab6, 0x45bf,
+ 0x8ab7, 0x435d,
+ 0x8ab8, 0x45c0,
+ 0x8ab9, 0x435f,
+ 0x8abb, 0x4361,
+ 0x8ac9, 0x436f,
+ 0x8acc, 0x45c1,
+ 0x8ace, 0x4374,
+ 0x8ad6, 0x45c2,
+ 0x8ad8, 0x437e,
+ 0x8adf, 0x4385,
+ 0x8ae6, 0x45c4,
+ 0x8ae7, 0x43db,
+ 0x8ae8, 0x45c5,
+ 0x8af6, 0x45d2,
+ 0x8b40, 0x45db,
+ 0x8b41, 0x438c,
+ 0x8b43, 0x45dc,
+ 0x8b45, 0x438e,
+ 0x8b46, 0x45de,
+ 0x8b47, 0x438f,
+ 0x8b48, 0x45df,
+ 0x8b49, 0x4390,
+ 0x8b4a, 0x45e0,
+ 0x8b4b, 0x4391,
+ 0x8b4c, 0x45e1,
+ 0x8b4d, 0x4392,
+ 0x8b51, 0x45e2,
+ 0x8b55, 0x45e5,
+ 0x8b58, 0x4397,
+ 0x8b59, 0x45e8,
+ 0x8b5a, 0x4398,
+ 0x8b5b, 0x43c4,
+ 0x8b5c, 0x45e9,
+ 0x8b61, 0x43a7,
+ 0x8b62, 0x45ee,
+ 0x8b68, 0x43ac,
+ 0x8b69, 0x45f4,
+ 0x8ba1, 0x460a,
+ 0x8bc0, 0x44df,
+ 0x8bde, 0x44fc,
+ 0x8d60, 0x4629,
+ 0x8d62, 0x43ba,
+ 0x8d63, 0x462b,
+ 0x8d68, 0x43bb,
+ 0x8d69, 0x43a0,
+ 0x8d6a, 0x43bd,
+ 0x8d6b, 0x4630,
+ 0x8d6e, 0x43be,
+ 0x8d6f, 0x4633,
+ 0x8d76, 0x43bf,
+ 0x8d77, 0x463a,
+ 0x8d7a, 0x43c0,
+ 0x8d7b, 0x463d,
+ 0x8d7c, 0x43c1,
+ 0x8d7d, 0x463e,
+ 0x8da1, 0x4640,
+ 0x8da5, 0x43c2,
+ 0x8da6, 0x4644,
+ 0x8da8, 0x43b9,
+ 0x8da9, 0x43ad,
+ 0x8daa, 0x4646,
+ 0x8db6, 0x43c7,
+ 0x8db7, 0x4652,
+ 0x8dc3, 0x43c8,
+ 0x8dc4, 0x465e,
+ 0x8dfa, 0x43f9,
+ 0x8dfb, 0x4694,
+ 0x8e40, 0x372b,
+ 0x8e45, 0x4698,
+ 0x8e46, 0x3730,
+ 0x8e6a, 0x3754,
+ 0x8e6b, 0x4699,
+ 0x8e6d, 0x3756,
+ 0x8e70, 0x3759,
+ 0x8e76, 0x469b,
+ 0x8e77, 0x375f,
+ 0x8e7b, 0x469c,
+ 0x8e7c, 0x3764,
+ 0x8ea1, 0x3766,
+ 0x8ea6, 0x469d,
+ 0x8ea7, 0x376b,
+ 0x8eac, 0x3770,
+ 0x8eb5, 0x3779,
+ 0x8eb8, 0x469e,
+ 0x8eb9, 0x377d,
+ 0x8ec9, 0x469f,
+ 0x8eca, 0x378d,
+ 0x8ece, 0x3791,
+ 0x8ed1, 0x3794,
+ 0x8ee5, 0x46a0,
+ 0x8ee6, 0x37a8,
+ 0x8eef, 0x46a1,
+ 0x8ef0, 0x37b1,
+ 0x8ef6, 0x46a2,
+ 0x8ef7, 0x37b8,
+ 0x8f40, 0x37c0,
+ 0x8f58, 0x37d8,
+ 0x8f59, 0x46a3,
+ 0x8f5a, 0x37d9,
+ 0x8f5f, 0x46a4,
+ 0x8f60, 0x37de,
+ 0x8f67, 0x46a5,
+ 0x8f68, 0x37e5,
+ 0x8f6a, 0x37e7,
+ 0x8f6f, 0x37ec,
+ 0x8f79, 0x46a6,
+ 0x8f7a, 0x37f7,
+ 0x8fa1, 0x37fc,
+ 0x8fb0, 0x46a7,
+ 0x8fb1, 0x380c,
+ 0x8fc5, 0x46a8,
+ 0x8fc6, 0x3820,
+ 0x8fc7, 0x46a9,
+ 0x8fc8, 0x3821,
+ 0x8fca, 0x46aa,
+ 0x8fcd, 0x3826,
+ 0x8fda, 0x46ab,
+ 0x8fdb, 0x3833,
+ 0x8fe3, 0x46ac,
+ 0x8fe4, 0x383c,
+ 0x8ffc, 0x46ad,
+ 0x8ffd, 0x3854,
+ 0x9040, 0x3856,
+ 0x9055, 0x46ae,
+ 0x9056, 0x386c,
+ 0x905c, 0x46af,
+ 0x905f, 0x3873,
+ 0x906e, 0x3882,
+ 0x906f, 0x46b2,
+ 0x9070, 0x3883,
+ 0x907b, 0x388d,
+ 0x90a1, 0x3891,
+ 0x90a6, 0x46b3,
+ 0x90a7, 0x3896,
+ 0x90b8, 0x46b4,
+ 0x90b9, 0x38a7,
+ 0x90dd, 0x38cb,
+ 0x90f2, 0x38e0,
+ 0x9140, 0x38ed,
+ 0x9165, 0x46b5,
+ 0x9166, 0x3912,
+ 0x916e, 0x46b6,
+ 0x916f, 0x391a,
+ 0x917e, 0x46b7,
+ 0x91a1, 0x3929,
+ 0x91a2, 0x46b8,
+ 0x91a3, 0x392a,
+ 0x91c0, 0x3947,
+ 0x91c8, 0x46b9,
+ 0x91c9, 0x3950,
+ 0x9240, 0x3986,
+ 0x9245, 0x398b,
+ 0x9264, 0x46ba,
+ 0x9265, 0x39ab,
+ 0x926d, 0x46bb,
+ 0x926e, 0x39b4,
+ 0x92a1, 0x39c5,
+ 0x92b3, 0x39d3,
+ 0x92c9, 0x39e9,
+ 0x92d2, 0x39f2,
+ 0x92e5, 0x46bc,
+ 0x92e6, 0x3a05,
+ 0x92f2, 0x46bd,
+ 0x92f3, 0x3a11,
+ 0x9340, 0x3a1d,
+ 0x9368, 0x46be,
+ 0x9369, 0x3a45,
+ 0x93a1, 0x3a5b,
+ 0x93aa, 0x46bf,
+ 0x93ab, 0x3a64,
+ 0x93c2, 0x46c0,
+ 0x93c3, 0x3a7b,
+ 0x93e5, 0x46c1,
+ 0x93e6, 0x3a9d,
+ 0x93e8, 0x46c2,
+ 0x93e9, 0x3aa0,
+ 0x93eb, 0x46c3,
+ 0x93ec, 0x3aa2,
+ 0x9440, 0x3ab5,
+ 0x9446, 0x46c4,
+ 0x9448, 0x3abc,
+ 0x9479, 0x46c5,
+ 0x947a, 0x3aee,
+ 0x94a1, 0x3af3,
+ 0x94cb, 0x46c6,
+ 0x94cc, 0x3b1e,
+ 0x9540, 0x3b51,
+ 0x954d, 0x46c7,
+ 0x954e, 0x3b5e,
+ 0x955a, 0x46c8,
+ 0x955b, 0x3b6a,
+ 0x955f, 0x46c9,
+ 0x9560, 0x3b6f,
+ 0x95a1, 0x3b8e,
+ 0x95c6, 0x46ca,
+ 0x95c7, 0x3bb3,
+ 0x95da, 0x3bc6,
+ 0x9640, 0x3beb,
+ 0x9645, 0x3bf0,
+ 0x9651, 0x46cb,
+ 0x9652, 0x3bfd,
+ 0x966a, 0x46cc,
+ 0x966b, 0x3c16,
+ 0x96a1, 0x3c2a,
+ 0x96d4, 0x46cd,
+ 0x96d5, 0x3c5d,
+ 0x96ee, 0x3c76,
+ 0x96fd, 0x3c85,
+ 0x9740, 0x3c87,
+ 0x97a1, 0x3cc6,
+ 0x9840, 0x3d24,
+ 0x9844, 0x46ce,
+ 0x9846, 0x3d2a,
+ 0x986f, 0x46d0,
+ 0x9870, 0x3d54,
+ 0x9875, 0x46d1,
+ 0x9877, 0x3d59,
+ 0x9878, 0x46d3,
+ 0x987a, 0x3d5a,
+ 0x987b, 0x46d5,
+ 0x98a1, 0x46d9,
+ 0x98a3, 0x3d5b,
+ 0x98a4, 0x46db,
+ 0x98af, 0x3d5c,
+ 0x98b0, 0x46e6,
+ 0x98b4, 0x43ca,
+ 0x98b5, 0x46ea,
+ 0x98b6, 0x3d5d,
+ 0x98b7, 0x46eb,
+ 0x98b8, 0x43cc,
+ 0x98b9, 0x3d5e,
+ 0x98ba, 0x46ec,
+ 0x98bb, 0x43fa,
+ 0x98bc, 0x46ed,
+ 0x98bd, 0x3d5f,
+ 0x98bf, 0x46ee,
+ 0x98c2, 0x3d61,
+ 0x98c3, 0x46f1,
+ 0x98c4, 0x3d62,
+ 0x98c5, 0x46f2,
+ 0x98c6, 0x3d63,
+ 0x98c8, 0x46f3,
+ 0x98d2, 0x43cd,
+ 0x98d3, 0x46fd,
+ 0x98d8, 0x43ce,
+ 0x98da, 0x4702,
+ 0x98db, 0x43d1,
+ 0x98dc, 0x4703,
+ 0x98df, 0x43d4,
+ 0x98e0, 0x4706,
+ 0x98e3, 0x3d65,
+ 0x98e4, 0x4709,
+ 0x98e7, 0x3d66,
+ 0x98e8, 0x470c,
+ 0x98ed, 0x3d67,
+ 0x98ee, 0x4711,
+ 0x98f0, 0x3d68,
+ 0x98f1, 0x4713,
+ 0x98f2, 0x3d69,
+ 0x98f3, 0x4714,
+ 0x98f4, 0x43d5,
+ 0x98f6, 0x4715,
+ 0x98fc, 0x3d6a,
+ 0x98fd, 0x471b,
+ 0x98fe, 0x43d7,
+ 0x9940, 0x471c,
+ 0x9942, 0x43fc,
+ 0x9943, 0x3d6b,
+ 0x9944, 0x471e,
+ 0x9945, 0x3d6c,
+ 0x9946, 0x471f,
+ 0x9947, 0x43d8,
+ 0x9948, 0x4720,
+ 0x994f, 0x3d6d,
+ 0x9950, 0x4727,
+ 0x9954, 0x43d9,
+ 0x9955, 0x472b,
+ 0x995c, 0x43da,
+ 0x995d, 0x4732,
+ 0x9964, 0x43dc,
+ 0x9965, 0x4739,
+ 0x996a, 0x3d6e,
+ 0x996b, 0x473e,
+ 0x996e, 0x3d6f,
+ 0x996f, 0x4741,
+ 0x9975, 0x3d70,
+ 0x9976, 0x4747,
+ 0x9978, 0x3d71,
+ 0x9979, 0x4749,
+ 0x99a1, 0x474f,
+ 0x99a2, 0x3d72,
+ 0x99a3, 0x4750,
+ 0x99a4, 0x43c5,
+ 0x99a5, 0x4751,
+ 0x99a6, 0x43c6,
+ 0x99a7, 0x4752,
+ 0x99ae, 0x3d73,
+ 0x99af, 0x4759,
+ 0x99b2, 0x43de,
+ 0x99b3, 0x475c,
+ 0x99b6, 0x3d74,
+ 0x99b7, 0x475f,
+ 0x99ba, 0x3d75,
+ 0x99bb, 0x4762,
+ 0x99ca, 0x43e0,
+ 0x99cb, 0x4771,
+ 0x99cd, 0x43e2,
+ 0x99ce, 0x4773,
+ 0x99d3, 0x43e3,
+ 0x99d4, 0x4778,
+ 0x99d6, 0x43e5,
+ 0x99d7, 0x477a,
+ 0x99df, 0x43df,
+ 0x99e0, 0x4782,
+ 0x99e2, 0x3d76,
+ 0x99e3, 0x4784,
+ 0x99e4, 0x43ab,
+ 0x99e5, 0x4785,
+ 0x99e6, 0x43e7,
+ 0x99e7, 0x4786,
+ 0x99e8, 0x43e9,
+ 0x99e9, 0x4787,
+ 0x99ef, 0x43fd,
+ 0x99f0, 0x478d,
+ 0x99f4, 0x3d77,
+ 0x99f5, 0x4791,
+ 0x9a40, 0x479b,
+ 0x9a4a, 0x3d78,
+ 0x9a4b, 0x47a5,
+ 0x9a4c, 0x3d79,
+ 0x9a4d, 0x47a6,
+ 0x9a59, 0x3d7a,
+ 0x9a5a, 0x47b2,
+ 0x9a5f, 0x43af,
+ 0x9a60, 0x47b7,
+ 0x9a61, 0x3d7b,
+ 0x9a62, 0x47b8,
+ 0x9a66, 0x43ed,
+ 0x9a67, 0x47bc,
+ 0x9a68, 0x3d7c,
+ 0x9a69, 0x43ee,
+ 0x9a6a, 0x47bd,
+ 0x9a6b, 0x43ff,
+ 0x9a6c, 0x47be,
+ 0x9a73, 0x3d7d,
+ 0x9a74, 0x47c5,
+ 0x9a75, 0x43f1,
+ 0x9a76, 0x47c6,
+ 0x9a7e, 0x3d7e,
+ 0x9aa1, 0x47ce,
+ 0x9aa3, 0x43f3,
+ 0x9aa4, 0x47d0,
+ 0x9aa5, 0x43f2,
+ 0x9aa6, 0x47d1,
+ 0x9aa9, 0x43f8,
+ 0x9aaa, 0x43f4,
+ 0x9aab, 0x47d4,
+ 0x9ab2, 0x3d7f,
+ 0x9ab3, 0x47db,
+ 0x9ab7, 0x3d80,
+ 0x9ab8, 0x47df,
+ 0x9ab9, 0x3d81,
+ 0x9aba, 0x47e0,
+ 0x9abb, 0x3d82,
+ 0x9abc, 0x47e1,
+ 0x9abd, 0x43b7,
+ 0x9abe, 0x47e2,
+ 0x9ac7, 0x3d83,
+ 0x9ac8, 0x47eb,
+ 0x9ad0, 0x3d84,
+ 0x9ad1, 0x47f3,
+ 0x9ad2, 0x3d85,
+ 0x9ad3, 0x47f4,
+ 0x9ad9, 0x3d86,
+ 0x9adc, 0x47fa,
+ 0x9ae2, 0x3d89,
+ 0x9ae3, 0x4800,
+ 0x9ae4, 0x3d8a,
+ 0x9ae5, 0x4801,
+ 0x9ae8, 0x3d8b,
+ 0x9ae9, 0x43b0,
+ 0x9aea, 0x4804,
+ 0x9aee, 0x43b2,
+ 0x9aef, 0x4808,
+ 0x9af2, 0x3d8c,
+ 0x9af3, 0x480b,
+ 0x9af6, 0x3d8d,
+ 0x9af7, 0x480e,
+ 0x9afb, 0x3d8e,
+ 0x9afc, 0x4812,
+ 0x9b40, 0x4815,
+ 0x9b46, 0x3d8f,
+ 0x9b47, 0x481b,
+ 0x9b4a, 0x3d90,
+ 0x9b4b, 0x481e,
+ 0x9b54, 0x3d92,
+ 0x9b55, 0x4827,
+ 0x9b58, 0x3d93,
+ 0x9b59, 0x482a,
+ 0x9b5a, 0x3d94,
+ 0x9b5b, 0x482b,
+ 0x9b5c, 0x3d95,
+ 0x9b5d, 0x482c,
+ 0x9b5e, 0x3d96,
+ 0x9b60, 0x482d,
+ 0x9b62, 0x482e,
+ 0x9b70, 0x3d98,
+ 0x9b74, 0x483c,
+ 0x9b77, 0x3d9d,
+ 0x9b79, 0x483e,
+ 0x9b7c, 0x3da0,
+ 0x9b7d, 0x4840,
+ 0x9b7e, 0x3da1,
+ 0x9ba1, 0x3da2,
+ 0x9ba2, 0x4841,
+ 0x9ba3, 0x3da3,
+ 0x9ba5, 0x4842,
+ 0x9ba7, 0x3da5,
+ 0x9bab, 0x4844,
+ 0x9bac, 0x3da9,
+ 0x9bad, 0x4845,
+ 0x9baf, 0x3daa,
+ 0x9bb0, 0x4847,
+ 0x9bb2, 0x3dab,
+ 0x9bba, 0x4849,
+ 0x9bbe, 0x3db3,
+ 0x9bbf, 0x484d,
+ 0x9bc0, 0x3db4,
+ 0x9bc7, 0x484e,
+ 0x9bca, 0x3dbb,
+ 0x9bcb, 0x4851,
+ 0x9bcc, 0x3dbc,
+ 0x9bcd, 0x4852,
+ 0x9bce, 0x43d0,
+ 0x9bcf, 0x4853,
+ 0x9bd0, 0x3dbd,
+ 0x9bd2, 0x4854,
+ 0x9bd3, 0x3dbf,
+ 0x9bd4, 0x4855,
+ 0x9bd5, 0x3dc0,
+ 0x9bd6, 0x4856,
+ 0x9bd8, 0x3dc1,
+ 0x9bdb, 0x4858,
+ 0x9bdd, 0x3dc4,
+ 0x9bdf, 0x3dc5,
+ 0x9be0, 0x485a,
+ 0x9be1, 0x3dc6,
+ 0x9be2, 0x485b,
+ 0x9be3, 0x3dc7,
+ 0x9be4, 0x485c,
+ 0x9be7, 0x3dc8,
+ 0x9be8, 0x485f,
+ 0x9be9, 0x3dc9,
+ 0x9bed, 0x4860,
+ 0x9bee, 0x3dcd,
+ 0x9bf0, 0x4861,
+ 0x9bf3, 0x3dcf,
+ 0x9bf4, 0x4864,
+ 0x9bf7, 0x4866,
+ 0x9bf8, 0x3dd1,
+ 0x9bfa, 0x4867,
+ 0x9bfb, 0x3dd3,
+ 0x9bfd, 0x4868,
+ 0x9c40, 0x3dd5,
+ 0x9c43, 0x486a,
+ 0x9c44, 0x3dd8,
+ 0x9c47, 0x486b,
+ 0x9c48, 0x3ddb,
+ 0x9c49, 0x486c,
+ 0x9c4a, 0x3ddc,
+ 0x9c4b, 0x486d,
+ 0x9c4d, 0x3ddd,
+ 0x9c54, 0x486f,
+ 0x9c55, 0x3de4,
+ 0x9c56, 0x4870,
+ 0x9c57, 0x3de5,
+ 0x9c5c, 0x4871,
+ 0x9c5d, 0x3dea,
+ 0x9c5e, 0x4872,
+ 0x9c60, 0x3deb,
+ 0x9c61, 0x4874,
+ 0x9c63, 0x4875,
+ 0x9c64, 0x3ded,
+ 0x9c67, 0x4876,
+ 0x9c69, 0x4877,
+ 0x9c6a, 0x3df1,
+ 0x9c6c, 0x4878,
+ 0x9c6d, 0x3df2,
+ 0x9c6e, 0x4879,
+ 0x9c6f, 0x3df3,
+ 0x9c73, 0x487a,
+ 0x9c75, 0x3df7,
+ 0x9c78, 0x487c,
+ 0x9c79, 0x3dfa,
+ 0x9c7a, 0x487d,
+ 0x9c7b, 0x3dfb,
+ 0x9c7d, 0x487e,
+ 0x9c7e, 0x3dfd,
+ 0x9ca1, 0x3dfe,
+ 0x9ca3, 0x487f,
+ 0x9ca5, 0x3e00,
+ 0x9ca6, 0x4881,
+ 0x9ca8, 0x3e01,
+ 0x9caa, 0x4883,
+ 0x9cab, 0x3e03,
+ 0x9cac, 0x4884,
+ 0x9cad, 0x3e04,
+ 0x9caf, 0x4885,
+ 0x9cb1, 0x3e06,
+ 0x9cbb, 0x4887,
+ 0x9cbe, 0x3e12,
+ 0x9cc3, 0x4888,
+ 0x9cc6, 0x3e17,
+ 0x9cce, 0x488b,
+ 0x9ccf, 0x3e1f,
+ 0x9cd1, 0x3e21,
+ 0x9cd4, 0x488c,
+ 0x9cd8, 0x3e24,
+ 0x9cdb, 0x4890,
+ 0x9cdc, 0x3e27,
+ 0x9ce6, 0x4891,
+ 0x9ce7, 0x3e31,
+ 0x9cea, 0x4892,
+ 0x9ceb, 0x3e34,
+ 0x9ced, 0x4893,
+ 0x9cee, 0x3e36,
+ 0x9cfa, 0x4894,
+ 0x9cfd, 0x3e42,
+ 0x9cfe, 0x4897,
+ 0x9d40, 0x43e8,
+ 0x9d41, 0x4898,
+ 0x9d46, 0x3e43,
+ 0x9d47, 0x489d,
+ 0x9d49, 0x3e44,
+ 0x9d4a, 0x489f,
+ 0x9d4c, 0x3e46,
+ 0x9d4e, 0x48a1,
+ 0x9d4f, 0x3e48,
+ 0x9d50, 0x48a2,
+ 0x9d51, 0x3e49,
+ 0x9d52, 0x48a3,
+ 0x9d55, 0x3e4a,
+ 0x9d56, 0x48a6,
+ 0x9d58, 0x48a7,
+ 0x9d5b, 0x48a9,
+ 0x9d61, 0x43c9,
+ 0x9d62, 0x3e4c,
+ 0x9d63, 0x48af,
+ 0x9d64, 0x3e4d,
+ 0x9d65, 0x48b0,
+ 0x9d78, 0x43f5,
+ 0x9d79, 0x3e4e,
+ 0x9d7a, 0x48c3,
+ 0x9d7e, 0x3e4f,
+ 0x9da1, 0x48c7,
+ 0x9da5, 0x3e50,
+ 0x9da9, 0x48cb,
+ 0x9daa, 0x3e54,
+ 0x9dab, 0x48cc,
+ 0x9dac, 0x3e55,
+ 0x9dae, 0x48cd,
+ 0x9db0, 0x3e58,
+ 0x9db1, 0x48cf,
+ 0x9db3, 0x3e59,
+ 0x9db4, 0x48d1,
+ 0x9db5, 0x3e5a,
+ 0x9db6, 0x48d2,
+ 0x9db7, 0x3e5b,
+ 0x9db8, 0x48d3,
+ 0x9dbc, 0x3e5c,
+ 0x9dbe, 0x48d7,
+ 0x9dbf, 0x3e5e,
+ 0x9dc1, 0x48d8,
+ 0x9dc3, 0x3e60,
+ 0x9dc5, 0x48da,
+ 0x9dc7, 0x3e62,
+ 0x9dc9, 0x48dc,
+ 0x9dca, 0x3e64,
+ 0x9dcb, 0x48dd,
+ 0x9dcd, 0x3e65,
+ 0x9dd2, 0x48df,
+ 0x9dd3, 0x3e6a,
+ 0x9dd6, 0x48e0,
+ 0x9dda, 0x3e6d,
+ 0x9dfc, 0x48e4,
+ 0x9dfd, 0x3e8f,
+ 0x9e40, 0x3e91,
+ 0x9e43, 0x48e5,
+ 0x9e44, 0x3e95,
+ 0x9e5f, 0x48e6,
+ 0x9e60, 0x3eb1,
+ 0x9e63, 0x48e7,
+ 0x9e64, 0x3eb4,
+ 0x9e66, 0x48e8,
+ 0x9e68, 0x3eb6,
+ 0x9e69, 0x48ea,
+ 0x9e6a, 0x3eb7,
+ 0x9e6b, 0x48eb,
+ 0x9e71, 0x3eb8,
+ 0x9e72, 0x48f1,
+ 0x9e73, 0x3eb9,
+ 0x9e74, 0x48f2,
+ 0x9e77, 0x3eba,
+ 0x9e79, 0x48f5,
+ 0x9e7a, 0x3ebc,
+ 0x9e7b, 0x48f6,
+ 0x9e7c, 0x3ebd,
+ 0x9e7d, 0x48f7,
+ 0x9e7e, 0x3ebe,
+ 0x9ea1, 0x3ebf,
+ 0x9ea3, 0x48f8,
+ 0x9ea4, 0x3ec1,
+ 0x9ea7, 0x48f9,
+ 0x9eaa, 0x3ec5,
+ 0x9eab, 0x48fb,
+ 0x9ead, 0x3ec7,
+ 0x9eae, 0x48fc,
+ 0x9eaf, 0x3ec8,
+ 0x9eb2, 0x48fd,
+ 0x9eb4, 0x3ecb,
+ 0x9eb5, 0x48ff,
+ 0x9eb6, 0x3ecc,
+ 0x9eb8, 0x4900,
+ 0x9eb9, 0x3ece,
+ 0x9eba, 0x4901,
+ 0x9ebc, 0x3ecf,
+ 0x9ebd, 0x4903,
+ 0x9ebf, 0x3ed0,
+ 0x9ec1, 0x4905,
+ 0x9ec5, 0x3ed3,
+ 0x9ec6, 0x4908,
+ 0x9ec7, 0x3ed4,
+ 0x9ecb, 0x4909,
+ 0x9ecd, 0x3ed9,
+ 0x9ece, 0x490b,
+ 0x9ed0, 0x3eda,
+ 0x9ed2, 0x490d,
+ 0x9ed3, 0x3edc,
+ 0x9ed4, 0x490e,
+ 0x9ed6, 0x3edd,
+ 0x9ed8, 0x4910,
+ 0x9eda, 0x3edf,
+ 0x9ef0, 0x3ef5,
+ 0x9ef2, 0x4912,
+ 0x9ef3, 0x3ef7,
+ 0x9ef5, 0x3ef9,
+ 0x9ef6, 0x4913,
+ 0x9ef9, 0x3efa,
+ 0x9efb, 0x4916,
+ 0x9efc, 0x3efc,
+ 0x9efe, 0x3efe,
+ 0x9f40, 0x3eff,
+ 0x9f43, 0x4917,
+ 0x9f44, 0x3f02,
+ 0x9f48, 0x4918,
+ 0x9f49, 0x3f06,
+ 0x9f4b, 0x4919,
+ 0x9f4d, 0x3f08,
+ 0x9f4f, 0x3f0a,
+ 0x9f61, 0x3f1c,
+ 0x9f67, 0x491b,
+ 0x9f69, 0x3f23,
+ 0x9f70, 0x491d,
+ 0x9f71, 0x3f2a,
+ 0x9fa1, 0x3f38,
+ 0x9fae, 0x3f45,
+ 0x9fb2, 0x3f49,
+ 0x9fb5, 0x491e,
+ 0x9fb6, 0x3f4c,
+ 0x9fbb, 0x491f,
+ 0x9fbc, 0x3f51,
+ 0x9fbf, 0x4920,
+ 0x9fc1, 0x4921,
+ 0x9fc2, 0x3f55,
+ 0x9fc9, 0x3f5c,
+ 0x9fcc, 0x4922,
+ 0x9fcd, 0x3f60,
+ 0x9fd4, 0x4923,
+ 0x9fd5, 0x3f68,
+ 0x9fd9, 0x3f6c,
+ 0x9fdb, 0x3f6e,
+ 0x9fe4, 0x4924,
+ 0x9fe5, 0x3f77,
+ 0x9fe7, 0x3f79,
+ 0x9feb, 0x3f7d,
+ 0x9ff0, 0x3f82,
+ 0x9ff9, 0x4925,
+ 0x9ffa, 0x3f8b,
+ 0xa040, 0x4926,
+ 0xa041, 0x3f90,
+ 0xa047, 0x4927,
+ 0xa048, 0x3f96,
+ 0xa055, 0x4928,
+ 0xa056, 0x3fa3,
+ 0xa058, 0x3fa5,
+ 0xa05b, 0x3fa8,
+ 0xa064, 0x3fb1,
+ 0xa06d, 0x4929,
+ 0xa06e, 0x3fba,
+ 0xa073, 0x3fbf,
+ 0xa078, 0x3fc4,
+ 0xa07b, 0x492a,
+ 0xa07c, 0x3fc7,
+ 0xa0a1, 0x3fca,
+ 0xa0a2, 0x492b,
+ 0xa0a3, 0x3fcb,
+ 0xa0a6, 0x3fce,
+ 0xa0a7, 0x492c,
+ 0xa0a8, 0x3fcf,
+ 0xa0ae, 0x3fd5,
+ 0xa0b0, 0x3fd7,
+ 0xa0c5, 0x492d,
+ 0xa0c6, 0x3fec,
+ 0xa0d0, 0x492e,
+ 0xa0d1, 0x3ff6,
+ 0xa0d4, 0x3ff9,
+ 0xa0d6, 0x3ffb,
+ 0xa0e0, 0x4005,
+ 0xa0e2, 0x4007,
+ 0xa0e3, 0x492f,
+ 0xa0e5, 0x4009,
+ 0xa0e7, 0x4930,
+ 0xa0ee, 0x43b4,
+ 0xa0ef, 0x4937,
+ 0xa0f2, 0x43b8,
+ 0xa0f3, 0x493a,
+ 0xa140, 0x0063,
+ 0xa159, 0x35af,
+ 0xa15d, 0x0080,
+ 0xa1a1, 0x00a2,
+ 0xa1f6, 0x00f8,
+ 0xa1f7, 0x00f7,
+ 0xa1f8, 0x00f9,
+ 0xa240, 0x0100,
+ 0xa2a1, 0x013f,
+ 0xa340, 0x019d,
+ 0xa3a1, 0x01dc,
+ 0xa3bd, 0x01f7,
+ 0xa440, 0x0253,
+ 0xa4a1, 0x0292,
+ 0xa540, 0x02f0,
+ 0xa5a1, 0x032f,
+ 0xa640, 0x038d,
+ 0xa6a1, 0x03cc,
+ 0xa740, 0x042a,
+ 0xa7a1, 0x0469,
+ 0xa840, 0x04c7,
+ 0xa8a1, 0x0506,
+ 0xa940, 0x0564,
+ 0xa9a1, 0x05a3,
+ 0xaa40, 0x0601,
+ 0xaaa1, 0x0640,
+ 0xab40, 0x069e,
+ 0xaba1, 0x06dd,
+ 0xac40, 0x073b,
+ 0xaca1, 0x077a,
+ 0xacfe, 0x097f,
+ 0xad40, 0x07d7,
+ 0xada1, 0x0816,
+ 0xae40, 0x0874,
+ 0xaea1, 0x08b3,
+ 0xaf40, 0x0911,
+ 0xafa1, 0x0950,
+ 0xafd0, 0x0980,
+ 0xb040, 0x09af,
+ 0xb0a1, 0x09ee,
+ 0xb140, 0x0a4c,
+ 0xb1a1, 0x0a8b,
+ 0xb240, 0x0ae9,
+ 0xb2a1, 0x0b28,
+ 0xb340, 0x0b86,
+ 0xb3a1, 0x0bc5,
+ 0xb440, 0x0c23,
+ 0xb4a1, 0x0c62,
+ 0xb540, 0x0cc0,
+ 0xb5a1, 0x0cff,
+ 0xb640, 0x0d5d,
+ 0xb6a1, 0x0d9c,
+ 0xb740, 0x0dfa,
+ 0xb7a1, 0x0e39,
+ 0xb840, 0x0e97,
+ 0xb8a1, 0x0ed6,
+ 0xb940, 0x0f34,
+ 0xb9a1, 0x0f73,
+ 0xba40, 0x0fd1,
+ 0xbaa1, 0x1010,
+ 0xbb40, 0x106e,
+ 0xbba1, 0x10ad,
+ 0xbbc8, 0x10d5,
+ 0xbc40, 0x110c,
+ 0xbca1, 0x114b,
+ 0xbd40, 0x11a9,
+ 0xbda1, 0x11e8,
+ 0xbe40, 0x1246,
+ 0xbe52, 0x10d4,
+ 0xbe53, 0x1258,
+ 0xbea1, 0x1284,
+ 0xbf40, 0x12e2,
+ 0xbfa1, 0x1321,
+ 0xc040, 0x137f,
+ 0xc0a1, 0x13be,
+ 0xc140, 0x141c,
+ 0xc1a1, 0x145b,
+ 0xc1ab, 0x1466,
+ 0xc240, 0x14ba,
+ 0xc2a1, 0x14f9,
+ 0xc2cb, 0x1465,
+ 0xc2cc, 0x1523,
+ 0xc340, 0x1556,
+ 0xc361, 0x1578,
+ 0xc3a1, 0x1596,
+ 0xc3b9, 0x15af,
+ 0xc3ba, 0x15ae,
+ 0xc3bb, 0x15b0,
+ 0xc440, 0x15f4,
+ 0xc456, 0x1577,
+ 0xc457, 0x160a,
+ 0xc4a1, 0x1632,
+ 0xc540, 0x1690,
+ 0xc5a1, 0x16cf,
+ 0xc640, 0x172d,
+ 0xc6a1, 0x01fa,
+ 0xc6bf, 0x0219,
+ 0xc6d0, 0x022a,
+ 0xc6d4, 0x022e,
+ 0xc6d6, 0x0230,
+ 0xc6d8, 0x35b3,
+ 0xc6e0, 0x35ba,
+ 0xc740, 0x35d9,
+ 0xc7a1, 0x3618,
+ 0xc840, 0x3676,
+ 0xc8a1, 0x36b5,
+ 0xc8cd, 0x36e1,
+ 0xc8d4, 0x44c6,
+ 0xc8d7, 0x451c,
+ 0xc8e0, 0x02dc,
+ 0xc8e1, 0x4525,
+ 0xc8e9, 0x0509,
+ 0xc8ea, 0x452d,
+ 0xc8f1, 0x09f6,
+ 0xc8f5, 0x4992,
+ 0xc940, 0x176c,
+ 0xc94a, 0x0274,
+ 0xc94b, 0x1776,
+ 0xc96c, 0x1798,
+ 0xc9a1, 0x17ab,
+ 0xc9be, 0x1797,
+ 0xc9bf, 0x17c8,
+ 0xc9ed, 0x17f7,
+ 0xca40, 0x1809,
+ 0xcaa1, 0x1848,
+ 0xcaf7, 0x17f6,
+ 0xcaf8, 0x189e,
+ 0xcb40, 0x18a5,
+ 0xcba1, 0x18e4,
+ 0xcc40, 0x1942,
+ 0xcca1, 0x1981,
+ 0xcd40, 0x19df,
+ 0xcda1, 0x1a1e,
+ 0xce40, 0x1a7c,
+ 0xcea1, 0x1abb,
+ 0xcf40, 0x1b19,
+ 0xcfa1, 0x1b58,
+ 0xd040, 0x1bb6,
+ 0xd0a1, 0x1bf5,
+ 0xd140, 0x1c53,
+ 0xd1a1, 0x1c92,
+ 0xd240, 0x1cf0,
+ 0xd2a1, 0x1d2f,
+ 0xd340, 0x1d8d,
+ 0xd3a1, 0x1dcc,
+ 0xd440, 0x1e2a,
+ 0xd4a1, 0x1e69,
+ 0xd540, 0x1ec7,
+ 0xd5a1, 0x1f06,
+ 0xd640, 0x1f64,
+ 0xd6a1, 0x1fa3,
+ 0xd6cc, 0x2254,
+ 0xd6cd, 0x1fcf,
+ 0xd740, 0x2001,
+ 0xd77a, 0x22b9,
+ 0xd77b, 0x203b,
+ 0xd7a1, 0x203f,
+ 0xd840, 0x209d,
+ 0xd8a1, 0x20dc,
+ 0xd940, 0x213a,
+ 0xd9a1, 0x2179,
+ 0xda40, 0x21d7,
+ 0xdaa1, 0x2216,
+ 0xdadf, 0x1fce,
+ 0xdae0, 0x2255,
+ 0xdb40, 0x2274,
+ 0xdba1, 0x22b3,
+ 0xdba7, 0x22ba,
+ 0xdc40, 0x2312,
+ 0xdca1, 0x2351,
+ 0xdd40, 0x23af,
+ 0xdda1, 0x23ee,
+ 0xddfc, 0x2381,
+ 0xddfd, 0x2449,
+ 0xde40, 0x244b,
+ 0xdea1, 0x248a,
+ 0xdf40, 0x24e8,
+ 0xdfa1, 0x2527,
+ 0xe040, 0x2585,
+ 0xe0a1, 0x25c4,
+ 0xe140, 0x2622,
+ 0xe1a1, 0x2661,
+ 0xe240, 0x26bf,
+ 0xe2a1, 0x26fe,
+ 0xe340, 0x275c,
+ 0xe3a1, 0x279b,
+ 0xe440, 0x27f9,
+ 0xe4a1, 0x2838,
+ 0xe540, 0x2896,
+ 0xe5a1, 0x28d5,
+ 0xe640, 0x2933,
+ 0xe6a1, 0x2972,
+ 0xe740, 0x29d0,
+ 0xe7a1, 0x2a0f,
+ 0xe840, 0x2a6d,
+ 0xe8a1, 0x2aac,
+ 0xe8a3, 0x2aaf,
+ 0xe940, 0x2b0b,
+ 0xe976, 0x2b42,
+ 0xe9a1, 0x2b4b,
+ 0xea40, 0x2ba9,
+ 0xeaa1, 0x2be8,
+ 0xeb40, 0x2c46,
+ 0xeb5b, 0x2c62,
+ 0xeba1, 0x2c86,
+ 0xebf1, 0x2aae,
+ 0xebf2, 0x2cd6,
+ 0xec40, 0x2ce3,
+ 0xeca1, 0x2d22,
+ 0xecde, 0x2b41,
+ 0xecdf, 0x2d5f,
+ 0xed40, 0x2d7f,
+ 0xeda1, 0x2dbe,
+ 0xedaa, 0x2dc8,
+ 0xee40, 0x2e1d,
+ 0xeea1, 0x2e5c,
+ 0xeeeb, 0x3014,
+ 0xeeec, 0x2ea6,
+ 0xef40, 0x2eb9,
+ 0xefa1, 0x2ef8,
+ 0xf040, 0x2f56,
+ 0xf056, 0x2dc7,
+ 0xf057, 0x2f6c,
+ 0xf0a1, 0x2f94,
+ 0xf0cb, 0x2c61,
+ 0xf0cc, 0x2fbe,
+ 0xf140, 0x2ff1,
+ 0xf163, 0x3015,
+ 0xf16b, 0x3160,
+ 0xf16c, 0x301d,
+ 0xf1a1, 0x3030,
+ 0xf240, 0x308e,
+ 0xf268, 0x31ef,
+ 0xf269, 0x30b6,
+ 0xf2a1, 0x30cc,
+ 0xf2c3, 0x30ef,
+ 0xf340, 0x312b,
+ 0xf375, 0x3161,
+ 0xf3a1, 0x316b,
+ 0xf440, 0x31c9,
+ 0xf466, 0x31f0,
+ 0xf4a1, 0x3209,
+ 0xf4b5, 0x30ee,
+ 0xf4b6, 0x321d,
+ 0xf4fd, 0x3265,
+ 0xf540, 0x3267,
+ 0xf5a1, 0x32a6,
+ 0xf640, 0x3304,
+ 0xf663, 0x3264,
+ 0xf664, 0x3327,
+ 0xf6a1, 0x3342,
+ 0xf740, 0x33a0,
+ 0xf7a1, 0x33df,
+ 0xf840, 0x343d,
+ 0xf8a1, 0x347c,
+ 0xf940, 0x34da,
+ 0xf977, 0x3512,
+ 0xf9a1, 0x351a,
+ 0xf9c4, 0x3511,
+ 0xf9c5, 0x353d,
+ 0xf9c6, 0x3549,
+ 0xf9c7, 0x353e,
+ 0xf9d2, 0x354a,
+ 0xf9d6, 0x36e8,
+ 0xfa40, 0x400b,
+ 0xfa60, 0x402b,
+ 0xfa67, 0x4032,
+ 0xfaa1, 0x404a,
+ 0xfaa9, 0x4946,
+ 0xfaab, 0x4054,
+ 0xfabe, 0x4067,
+ 0xfac6, 0x406f,
+ 0xfad6, 0x407f,
+ 0xfb40, 0x40a8,
+ 0xfb49, 0x40b1,
+ 0xfb53, 0x4948,
+ 0xfb54, 0x40bc,
+ 0xfb6e, 0x4949,
+ 0xfb6f, 0x40d7,
+ 0xfba1, 0x40e7,
+ 0xfba3, 0x494a,
+ 0xfba4, 0x40ea,
+ 0xfbb9, 0x40ff,
+ 0xfbbf, 0x494b,
+ 0xfbc0, 0x4105,
+ 0xfbcd, 0x494c,
+ 0xfbce, 0x4112,
+ 0xfbf4, 0x4138,
+ 0xfbfa, 0x413e,
+ 0xfc40, 0x4143,
+ 0xfc4a, 0x494d,
+ 0xfc4b, 0x414d,
+ 0xfc50, 0x4151,
+ 0xfc52, 0x494e,
+ 0xfc53, 0x4153,
+ 0xfc63, 0x494f,
+ 0xfc64, 0x4163,
+ 0xfc6d, 0x4950,
+ 0xfc6e, 0x416d,
+ 0xfc75, 0x4951,
+ 0xfc76, 0x4174,
+ 0xfca1, 0x417d,
+ 0xfcba, 0x4195,
+ 0xfcbc, 0x4952,
+ 0xfcbe, 0x4198,
+ 0xfccc, 0x4954,
+ 0xfccd, 0x41a7,
+ 0xfce3, 0x4955,
+ 0xfce4, 0x41bd,
+ 0xfcee, 0x4956,
+ 0xfcef, 0x41c7,
+ 0xfcf2, 0x41ca,
+ 0xfd40, 0x41d7,
+ 0xfd49, 0x4957,
+ 0xfd4a, 0x41e0,
+ 0xfd6a, 0x4958,
+ 0xfd6b, 0x4201,
+ 0xfda1, 0x4215,
+ 0xfdb9, 0x422d,
+ 0xfdbc, 0x4230,
+ 0xfde3, 0x4959,
+ 0xfde4, 0x4258,
+ 0xfdf2, 0x495a,
+ 0xfdf3, 0x4266,
+ 0xfe40, 0x4272,
+ 0xfe53, 0x4285,
+ 0xfe6d, 0x495b,
+ 0xfe6e, 0x429f,
+ 0xfe70, 0x42a1,
+ 0xfe78, 0x495c,
+ 0xfe79, 0x42a9,
+ 0xfea1, 0x42af,
+ 0xfeab, 0x42b8,
+ 0xfede, 0x495d,
+ 0xfee0, 0x42eb,
+ 0xfeed, 0x495f,
+ 0xfeef, 0x42f8,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 cns13HKscsB5HEnc16 = {
+ 0,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
+ 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010,
+ 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018,
+ 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020,
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028,
+ 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030,
+ 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038,
+ 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040,
+ 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048,
+ 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050,
+ 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
+ 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ cns13HKscsB5HMap2, 1129
+};
+
+static Gushort cns13HKscsB5VMap2[2284] = {
+ 0x0000, 0x0000,
+ 0x8840, 0x44c9,
+ 0x8856, 0x4961,
+ 0x88a1, 0x498a,
+ 0x88a9, 0x499c,
+ 0x8940, 0x4534,
+ 0x8943, 0x4536,
+ 0x8946, 0x4537,
+ 0x894c, 0x453b,
+ 0x894d, 0x43c3,
+ 0x894e, 0x453c,
+ 0x8951, 0x439a,
+ 0x8952, 0x453f,
+ 0x89a1, 0x456c,
+ 0x89a6, 0x43a2,
+ 0x89ab, 0x43ec,
+ 0x89ac, 0x4571,
+ 0x89ad, 0x43eb,
+ 0x89ae, 0x4572,
+ 0x89b0, 0x4573,
+ 0x89b5, 0x4576,
+ 0x89c1, 0x4581,
+ 0x89c5, 0x4584,
+ 0x89cf, 0x43bc,
+ 0x89d0, 0x458e,
+ 0x89d9, 0x439c,
+ 0x89da, 0x4597,
+ 0x89db, 0x439e,
+ 0x89dc, 0x4598,
+ 0x89dd, 0x439f,
+ 0x89de, 0x4599,
+ 0x89e1, 0x43a1,
+ 0x89e2, 0x459c,
+ 0x89e3, 0x43a3,
+ 0x89e4, 0x459d,
+ 0x89ea, 0x43a5,
+ 0x89ec, 0x45a3,
+ 0x89fa, 0x43a9,
+ 0x89fb, 0x45b1,
+ 0x8a40, 0x45b5,
+ 0x8a41, 0x4309,
+ 0x8a43, 0x430b,
+ 0x8a4d, 0x45b6,
+ 0x8a4e, 0x4316,
+ 0x8a5a, 0x45b7,
+ 0x8a5b, 0x4323,
+ 0x8a5e, 0x45b8,
+ 0x8a5f, 0x4327,
+ 0x8a64, 0x432c,
+ 0x8a71, 0x45b9,
+ 0x8a72, 0x433a,
+ 0x8a76, 0x433e,
+ 0x8a77, 0x45ba,
+ 0x8a78, 0x4340,
+ 0x8a7a, 0x45bb,
+ 0x8a7b, 0x4343,
+ 0x8a7c, 0x45bc,
+ 0x8a7d, 0x4345,
+ 0x8a7e, 0x45bd,
+ 0x8aa1, 0x4347,
+ 0x8aa8, 0x45be,
+ 0x8aa9, 0x434f,
+ 0x8aac, 0x4352,
+ 0x8ab2, 0x4358,
+ 0x8ab6, 0x45bf,
+ 0x8ab7, 0x435d,
+ 0x8ab8, 0x45c0,
+ 0x8ab9, 0x435f,
+ 0x8abb, 0x4361,
+ 0x8ac9, 0x436f,
+ 0x8acc, 0x45c1,
+ 0x8ace, 0x4374,
+ 0x8ad6, 0x45c2,
+ 0x8ad8, 0x437e,
+ 0x8adf, 0x4385,
+ 0x8ae6, 0x45c4,
+ 0x8ae7, 0x43db,
+ 0x8ae8, 0x45c5,
+ 0x8af6, 0x45d2,
+ 0x8b40, 0x45db,
+ 0x8b41, 0x438c,
+ 0x8b43, 0x45dc,
+ 0x8b45, 0x438e,
+ 0x8b46, 0x45de,
+ 0x8b47, 0x438f,
+ 0x8b48, 0x45df,
+ 0x8b49, 0x4390,
+ 0x8b4a, 0x45e0,
+ 0x8b4b, 0x4391,
+ 0x8b4c, 0x45e1,
+ 0x8b4d, 0x4392,
+ 0x8b51, 0x45e2,
+ 0x8b55, 0x45e5,
+ 0x8b58, 0x4397,
+ 0x8b59, 0x45e8,
+ 0x8b5a, 0x4398,
+ 0x8b5b, 0x43c4,
+ 0x8b5c, 0x45e9,
+ 0x8b61, 0x43a7,
+ 0x8b62, 0x45ee,
+ 0x8b68, 0x43ac,
+ 0x8b69, 0x45f4,
+ 0x8ba1, 0x460a,
+ 0x8bc0, 0x44df,
+ 0x8bde, 0x44fc,
+ 0x8d60, 0x4629,
+ 0x8d62, 0x43ba,
+ 0x8d63, 0x462b,
+ 0x8d68, 0x43bb,
+ 0x8d69, 0x43a0,
+ 0x8d6a, 0x43bd,
+ 0x8d6b, 0x4630,
+ 0x8d6e, 0x43be,
+ 0x8d6f, 0x4633,
+ 0x8d76, 0x43bf,
+ 0x8d77, 0x463a,
+ 0x8d7a, 0x43c0,
+ 0x8d7b, 0x463d,
+ 0x8d7c, 0x43c1,
+ 0x8d7d, 0x463e,
+ 0x8da1, 0x4640,
+ 0x8da5, 0x43c2,
+ 0x8da6, 0x4644,
+ 0x8da8, 0x43b9,
+ 0x8da9, 0x43ad,
+ 0x8daa, 0x4646,
+ 0x8db6, 0x43c7,
+ 0x8db7, 0x4652,
+ 0x8dc3, 0x43c8,
+ 0x8dc4, 0x465e,
+ 0x8dfa, 0x43f9,
+ 0x8dfb, 0x4694,
+ 0x8e40, 0x372b,
+ 0x8e45, 0x4698,
+ 0x8e46, 0x3730,
+ 0x8e6a, 0x3754,
+ 0x8e6b, 0x4699,
+ 0x8e6d, 0x3756,
+ 0x8e70, 0x3759,
+ 0x8e76, 0x469b,
+ 0x8e77, 0x375f,
+ 0x8e7b, 0x469c,
+ 0x8e7c, 0x3764,
+ 0x8ea1, 0x3766,
+ 0x8ea6, 0x469d,
+ 0x8ea7, 0x376b,
+ 0x8eac, 0x3770,
+ 0x8eb5, 0x3779,
+ 0x8eb8, 0x469e,
+ 0x8eb9, 0x377d,
+ 0x8ec9, 0x469f,
+ 0x8eca, 0x378d,
+ 0x8ece, 0x3791,
+ 0x8ed1, 0x3794,
+ 0x8ee5, 0x46a0,
+ 0x8ee6, 0x37a8,
+ 0x8eef, 0x46a1,
+ 0x8ef0, 0x37b1,
+ 0x8ef6, 0x46a2,
+ 0x8ef7, 0x37b8,
+ 0x8f40, 0x37c0,
+ 0x8f58, 0x37d8,
+ 0x8f59, 0x46a3,
+ 0x8f5a, 0x37d9,
+ 0x8f5f, 0x46a4,
+ 0x8f60, 0x37de,
+ 0x8f67, 0x46a5,
+ 0x8f68, 0x37e5,
+ 0x8f6a, 0x37e7,
+ 0x8f6f, 0x37ec,
+ 0x8f79, 0x46a6,
+ 0x8f7a, 0x37f7,
+ 0x8fa1, 0x37fc,
+ 0x8fb0, 0x46a7,
+ 0x8fb1, 0x380c,
+ 0x8fc5, 0x46a8,
+ 0x8fc6, 0x3820,
+ 0x8fc7, 0x46a9,
+ 0x8fc8, 0x3821,
+ 0x8fca, 0x46aa,
+ 0x8fcd, 0x3826,
+ 0x8fda, 0x46ab,
+ 0x8fdb, 0x3833,
+ 0x8fe3, 0x46ac,
+ 0x8fe4, 0x383c,
+ 0x8ffc, 0x46ad,
+ 0x8ffd, 0x3854,
+ 0x9040, 0x3856,
+ 0x9055, 0x46ae,
+ 0x9056, 0x386c,
+ 0x905c, 0x46af,
+ 0x905f, 0x3873,
+ 0x906e, 0x3882,
+ 0x906f, 0x46b2,
+ 0x9070, 0x3883,
+ 0x907b, 0x388d,
+ 0x90a1, 0x3891,
+ 0x90a6, 0x46b3,
+ 0x90a7, 0x3896,
+ 0x90b8, 0x46b4,
+ 0x90b9, 0x38a7,
+ 0x90dd, 0x38cb,
+ 0x90f2, 0x38e0,
+ 0x9140, 0x38ed,
+ 0x9165, 0x46b5,
+ 0x9166, 0x3912,
+ 0x916e, 0x46b6,
+ 0x916f, 0x391a,
+ 0x917e, 0x46b7,
+ 0x91a1, 0x3929,
+ 0x91a2, 0x46b8,
+ 0x91a3, 0x392a,
+ 0x91c0, 0x3947,
+ 0x91c8, 0x46b9,
+ 0x91c9, 0x3950,
+ 0x9240, 0x3986,
+ 0x9245, 0x398b,
+ 0x9264, 0x46ba,
+ 0x9265, 0x39ab,
+ 0x926d, 0x46bb,
+ 0x926e, 0x39b4,
+ 0x92a1, 0x39c5,
+ 0x92b3, 0x39d3,
+ 0x92c9, 0x39e9,
+ 0x92d2, 0x39f2,
+ 0x92e5, 0x46bc,
+ 0x92e6, 0x3a05,
+ 0x92f2, 0x46bd,
+ 0x92f3, 0x3a11,
+ 0x9340, 0x3a1d,
+ 0x9368, 0x46be,
+ 0x9369, 0x3a45,
+ 0x93a1, 0x3a5b,
+ 0x93aa, 0x46bf,
+ 0x93ab, 0x3a64,
+ 0x93c2, 0x46c0,
+ 0x93c3, 0x3a7b,
+ 0x93e5, 0x46c1,
+ 0x93e6, 0x3a9d,
+ 0x93e8, 0x46c2,
+ 0x93e9, 0x3aa0,
+ 0x93eb, 0x46c3,
+ 0x93ec, 0x3aa2,
+ 0x9440, 0x3ab5,
+ 0x9446, 0x46c4,
+ 0x9448, 0x3abc,
+ 0x9479, 0x46c5,
+ 0x947a, 0x3aee,
+ 0x94a1, 0x3af3,
+ 0x94cb, 0x46c6,
+ 0x94cc, 0x3b1e,
+ 0x9540, 0x3b51,
+ 0x954d, 0x46c7,
+ 0x954e, 0x3b5e,
+ 0x955a, 0x46c8,
+ 0x955b, 0x3b6a,
+ 0x955f, 0x46c9,
+ 0x9560, 0x3b6f,
+ 0x95a1, 0x3b8e,
+ 0x95c6, 0x46ca,
+ 0x95c7, 0x3bb3,
+ 0x95da, 0x3bc6,
+ 0x9640, 0x3beb,
+ 0x9645, 0x3bf0,
+ 0x9651, 0x46cb,
+ 0x9652, 0x3bfd,
+ 0x966a, 0x46cc,
+ 0x966b, 0x3c16,
+ 0x96a1, 0x3c2a,
+ 0x96d4, 0x46cd,
+ 0x96d5, 0x3c5d,
+ 0x96ee, 0x3c76,
+ 0x96fd, 0x3c85,
+ 0x9740, 0x3c87,
+ 0x97a1, 0x3cc6,
+ 0x9840, 0x3d24,
+ 0x9844, 0x46ce,
+ 0x9846, 0x3d2a,
+ 0x986f, 0x46d0,
+ 0x9870, 0x3d54,
+ 0x9875, 0x46d1,
+ 0x9877, 0x3d59,
+ 0x9878, 0x46d3,
+ 0x987a, 0x3d5a,
+ 0x987b, 0x46d5,
+ 0x98a1, 0x46d9,
+ 0x98a3, 0x3d5b,
+ 0x98a4, 0x46db,
+ 0x98af, 0x3d5c,
+ 0x98b0, 0x46e6,
+ 0x98b4, 0x43ca,
+ 0x98b5, 0x46ea,
+ 0x98b6, 0x3d5d,
+ 0x98b7, 0x46eb,
+ 0x98b8, 0x43cc,
+ 0x98b9, 0x3d5e,
+ 0x98ba, 0x46ec,
+ 0x98bb, 0x43fa,
+ 0x98bc, 0x46ed,
+ 0x98bd, 0x3d5f,
+ 0x98bf, 0x46ee,
+ 0x98c2, 0x3d61,
+ 0x98c3, 0x46f1,
+ 0x98c4, 0x3d62,
+ 0x98c5, 0x46f2,
+ 0x98c6, 0x3d63,
+ 0x98c8, 0x46f3,
+ 0x98d2, 0x43cd,
+ 0x98d3, 0x46fd,
+ 0x98d8, 0x43ce,
+ 0x98da, 0x4702,
+ 0x98db, 0x43d1,
+ 0x98dc, 0x4703,
+ 0x98df, 0x43d4,
+ 0x98e0, 0x4706,
+ 0x98e3, 0x3d65,
+ 0x98e4, 0x4709,
+ 0x98e7, 0x3d66,
+ 0x98e8, 0x470c,
+ 0x98ed, 0x3d67,
+ 0x98ee, 0x4711,
+ 0x98f0, 0x3d68,
+ 0x98f1, 0x4713,
+ 0x98f2, 0x3d69,
+ 0x98f3, 0x4714,
+ 0x98f4, 0x43d5,
+ 0x98f6, 0x4715,
+ 0x98fc, 0x3d6a,
+ 0x98fd, 0x471b,
+ 0x98fe, 0x43d7,
+ 0x9940, 0x471c,
+ 0x9942, 0x43fc,
+ 0x9943, 0x3d6b,
+ 0x9944, 0x471e,
+ 0x9945, 0x3d6c,
+ 0x9946, 0x471f,
+ 0x9947, 0x43d8,
+ 0x9948, 0x4720,
+ 0x994f, 0x3d6d,
+ 0x9950, 0x4727,
+ 0x9954, 0x43d9,
+ 0x9955, 0x472b,
+ 0x995c, 0x43da,
+ 0x995d, 0x4732,
+ 0x9964, 0x43dc,
+ 0x9965, 0x4739,
+ 0x996a, 0x3d6e,
+ 0x996b, 0x473e,
+ 0x996e, 0x3d6f,
+ 0x996f, 0x4741,
+ 0x9975, 0x3d70,
+ 0x9976, 0x4747,
+ 0x9978, 0x3d71,
+ 0x9979, 0x4749,
+ 0x99a1, 0x474f,
+ 0x99a2, 0x3d72,
+ 0x99a3, 0x4750,
+ 0x99a4, 0x43c5,
+ 0x99a5, 0x4751,
+ 0x99a6, 0x43c6,
+ 0x99a7, 0x4752,
+ 0x99ae, 0x3d73,
+ 0x99af, 0x4759,
+ 0x99b2, 0x43de,
+ 0x99b3, 0x475c,
+ 0x99b6, 0x3d74,
+ 0x99b7, 0x475f,
+ 0x99ba, 0x3d75,
+ 0x99bb, 0x4762,
+ 0x99ca, 0x43e0,
+ 0x99cb, 0x4771,
+ 0x99cd, 0x43e2,
+ 0x99ce, 0x4773,
+ 0x99d3, 0x43e3,
+ 0x99d4, 0x4778,
+ 0x99d6, 0x43e5,
+ 0x99d7, 0x477a,
+ 0x99df, 0x43df,
+ 0x99e0, 0x4782,
+ 0x99e2, 0x3d76,
+ 0x99e3, 0x4784,
+ 0x99e4, 0x43ab,
+ 0x99e5, 0x4785,
+ 0x99e6, 0x43e7,
+ 0x99e7, 0x4786,
+ 0x99e8, 0x43e9,
+ 0x99e9, 0x4787,
+ 0x99ef, 0x43fd,
+ 0x99f0, 0x478d,
+ 0x99f4, 0x3d77,
+ 0x99f5, 0x4791,
+ 0x9a40, 0x479b,
+ 0x9a4a, 0x3d78,
+ 0x9a4b, 0x47a5,
+ 0x9a4c, 0x3d79,
+ 0x9a4d, 0x47a6,
+ 0x9a59, 0x3d7a,
+ 0x9a5a, 0x47b2,
+ 0x9a5f, 0x43af,
+ 0x9a60, 0x47b7,
+ 0x9a61, 0x3d7b,
+ 0x9a62, 0x47b8,
+ 0x9a66, 0x43ed,
+ 0x9a67, 0x47bc,
+ 0x9a68, 0x3d7c,
+ 0x9a69, 0x43ee,
+ 0x9a6a, 0x47bd,
+ 0x9a6b, 0x43ff,
+ 0x9a6c, 0x47be,
+ 0x9a73, 0x3d7d,
+ 0x9a74, 0x47c5,
+ 0x9a75, 0x43f1,
+ 0x9a76, 0x47c6,
+ 0x9a7e, 0x3d7e,
+ 0x9aa1, 0x47ce,
+ 0x9aa3, 0x43f3,
+ 0x9aa4, 0x47d0,
+ 0x9aa5, 0x43f2,
+ 0x9aa6, 0x47d1,
+ 0x9aa9, 0x43f8,
+ 0x9aaa, 0x43f4,
+ 0x9aab, 0x47d4,
+ 0x9ab2, 0x3d7f,
+ 0x9ab3, 0x47db,
+ 0x9ab7, 0x3d80,
+ 0x9ab8, 0x47df,
+ 0x9ab9, 0x3d81,
+ 0x9aba, 0x47e0,
+ 0x9abb, 0x3d82,
+ 0x9abc, 0x47e1,
+ 0x9abd, 0x43b7,
+ 0x9abe, 0x47e2,
+ 0x9ac7, 0x3d83,
+ 0x9ac8, 0x47eb,
+ 0x9ad0, 0x3d84,
+ 0x9ad1, 0x47f3,
+ 0x9ad2, 0x3d85,
+ 0x9ad3, 0x47f4,
+ 0x9ad9, 0x3d86,
+ 0x9adc, 0x47fa,
+ 0x9ae2, 0x3d89,
+ 0x9ae3, 0x4800,
+ 0x9ae4, 0x3d8a,
+ 0x9ae5, 0x4801,
+ 0x9ae8, 0x3d8b,
+ 0x9ae9, 0x43b0,
+ 0x9aea, 0x4804,
+ 0x9aee, 0x43b2,
+ 0x9aef, 0x4808,
+ 0x9af2, 0x3d8c,
+ 0x9af3, 0x480b,
+ 0x9af6, 0x3d8d,
+ 0x9af7, 0x480e,
+ 0x9afb, 0x3d8e,
+ 0x9afc, 0x4812,
+ 0x9b40, 0x4815,
+ 0x9b46, 0x3d8f,
+ 0x9b47, 0x481b,
+ 0x9b4a, 0x3d90,
+ 0x9b4b, 0x481e,
+ 0x9b54, 0x3d92,
+ 0x9b55, 0x4827,
+ 0x9b58, 0x3d93,
+ 0x9b59, 0x482a,
+ 0x9b5a, 0x3d94,
+ 0x9b5b, 0x482b,
+ 0x9b5c, 0x3d95,
+ 0x9b5d, 0x482c,
+ 0x9b5e, 0x3d96,
+ 0x9b60, 0x482d,
+ 0x9b62, 0x482e,
+ 0x9b70, 0x3d98,
+ 0x9b74, 0x483c,
+ 0x9b77, 0x3d9d,
+ 0x9b79, 0x483e,
+ 0x9b7c, 0x3da0,
+ 0x9b7d, 0x4840,
+ 0x9b7e, 0x3da1,
+ 0x9ba1, 0x3da2,
+ 0x9ba2, 0x4841,
+ 0x9ba3, 0x3da3,
+ 0x9ba5, 0x4842,
+ 0x9ba7, 0x3da5,
+ 0x9bab, 0x4844,
+ 0x9bac, 0x3da9,
+ 0x9bad, 0x4845,
+ 0x9baf, 0x3daa,
+ 0x9bb0, 0x4847,
+ 0x9bb2, 0x3dab,
+ 0x9bba, 0x4849,
+ 0x9bbe, 0x3db3,
+ 0x9bbf, 0x484d,
+ 0x9bc0, 0x3db4,
+ 0x9bc7, 0x484e,
+ 0x9bca, 0x3dbb,
+ 0x9bcb, 0x4851,
+ 0x9bcc, 0x3dbc,
+ 0x9bcd, 0x4852,
+ 0x9bce, 0x43d0,
+ 0x9bcf, 0x4853,
+ 0x9bd0, 0x3dbd,
+ 0x9bd2, 0x4854,
+ 0x9bd3, 0x3dbf,
+ 0x9bd4, 0x4855,
+ 0x9bd5, 0x3dc0,
+ 0x9bd6, 0x4856,
+ 0x9bd8, 0x3dc1,
+ 0x9bdb, 0x4858,
+ 0x9bdd, 0x3dc4,
+ 0x9bdf, 0x3dc5,
+ 0x9be0, 0x485a,
+ 0x9be1, 0x3dc6,
+ 0x9be2, 0x485b,
+ 0x9be3, 0x3dc7,
+ 0x9be4, 0x485c,
+ 0x9be7, 0x3dc8,
+ 0x9be8, 0x485f,
+ 0x9be9, 0x3dc9,
+ 0x9bed, 0x4860,
+ 0x9bee, 0x3dcd,
+ 0x9bf0, 0x4861,
+ 0x9bf3, 0x3dcf,
+ 0x9bf4, 0x4864,
+ 0x9bf7, 0x4866,
+ 0x9bf8, 0x3dd1,
+ 0x9bfa, 0x4867,
+ 0x9bfb, 0x3dd3,
+ 0x9bfd, 0x4868,
+ 0x9c40, 0x3dd5,
+ 0x9c43, 0x486a,
+ 0x9c44, 0x3dd8,
+ 0x9c47, 0x486b,
+ 0x9c48, 0x3ddb,
+ 0x9c49, 0x486c,
+ 0x9c4a, 0x3ddc,
+ 0x9c4b, 0x486d,
+ 0x9c4d, 0x3ddd,
+ 0x9c54, 0x486f,
+ 0x9c55, 0x3de4,
+ 0x9c56, 0x4870,
+ 0x9c57, 0x3de5,
+ 0x9c5c, 0x4871,
+ 0x9c5d, 0x3dea,
+ 0x9c5e, 0x4872,
+ 0x9c60, 0x3deb,
+ 0x9c61, 0x4874,
+ 0x9c63, 0x4875,
+ 0x9c64, 0x3ded,
+ 0x9c67, 0x4876,
+ 0x9c69, 0x4877,
+ 0x9c6a, 0x3df1,
+ 0x9c6c, 0x4878,
+ 0x9c6d, 0x3df2,
+ 0x9c6e, 0x4879,
+ 0x9c6f, 0x3df3,
+ 0x9c73, 0x487a,
+ 0x9c75, 0x3df7,
+ 0x9c78, 0x487c,
+ 0x9c79, 0x3dfa,
+ 0x9c7a, 0x487d,
+ 0x9c7b, 0x3dfb,
+ 0x9c7d, 0x487e,
+ 0x9c7e, 0x3dfd,
+ 0x9ca1, 0x3dfe,
+ 0x9ca3, 0x487f,
+ 0x9ca5, 0x3e00,
+ 0x9ca6, 0x4881,
+ 0x9ca8, 0x3e01,
+ 0x9caa, 0x4883,
+ 0x9cab, 0x3e03,
+ 0x9cac, 0x4884,
+ 0x9cad, 0x3e04,
+ 0x9caf, 0x4885,
+ 0x9cb1, 0x3e06,
+ 0x9cbb, 0x4887,
+ 0x9cbe, 0x3e12,
+ 0x9cc3, 0x4888,
+ 0x9cc6, 0x3e17,
+ 0x9cce, 0x488b,
+ 0x9ccf, 0x3e1f,
+ 0x9cd1, 0x3e21,
+ 0x9cd4, 0x488c,
+ 0x9cd8, 0x3e24,
+ 0x9cdb, 0x4890,
+ 0x9cdc, 0x3e27,
+ 0x9ce6, 0x4891,
+ 0x9ce7, 0x3e31,
+ 0x9cea, 0x4892,
+ 0x9ceb, 0x3e34,
+ 0x9ced, 0x4893,
+ 0x9cee, 0x3e36,
+ 0x9cfa, 0x4894,
+ 0x9cfd, 0x3e42,
+ 0x9cfe, 0x4897,
+ 0x9d40, 0x43e8,
+ 0x9d41, 0x4898,
+ 0x9d46, 0x3e43,
+ 0x9d47, 0x489d,
+ 0x9d49, 0x3e44,
+ 0x9d4a, 0x489f,
+ 0x9d4c, 0x3e46,
+ 0x9d4e, 0x48a1,
+ 0x9d4f, 0x3e48,
+ 0x9d50, 0x48a2,
+ 0x9d51, 0x3e49,
+ 0x9d52, 0x48a3,
+ 0x9d55, 0x3e4a,
+ 0x9d56, 0x48a6,
+ 0x9d58, 0x48a7,
+ 0x9d5b, 0x48a9,
+ 0x9d61, 0x43c9,
+ 0x9d62, 0x3e4c,
+ 0x9d63, 0x48af,
+ 0x9d64, 0x3e4d,
+ 0x9d65, 0x48b0,
+ 0x9d78, 0x43f5,
+ 0x9d79, 0x3e4e,
+ 0x9d7a, 0x48c3,
+ 0x9d7e, 0x3e4f,
+ 0x9da1, 0x48c7,
+ 0x9da5, 0x3e50,
+ 0x9da9, 0x48cb,
+ 0x9daa, 0x3e54,
+ 0x9dab, 0x48cc,
+ 0x9dac, 0x3e55,
+ 0x9dae, 0x48cd,
+ 0x9db0, 0x3e58,
+ 0x9db1, 0x48cf,
+ 0x9db3, 0x3e59,
+ 0x9db4, 0x48d1,
+ 0x9db5, 0x3e5a,
+ 0x9db6, 0x48d2,
+ 0x9db7, 0x3e5b,
+ 0x9db8, 0x48d3,
+ 0x9dbc, 0x3e5c,
+ 0x9dbe, 0x48d7,
+ 0x9dbf, 0x3e5e,
+ 0x9dc1, 0x48d8,
+ 0x9dc3, 0x3e60,
+ 0x9dc5, 0x48da,
+ 0x9dc7, 0x3e62,
+ 0x9dc9, 0x48dc,
+ 0x9dca, 0x3e64,
+ 0x9dcb, 0x48dd,
+ 0x9dcd, 0x3e65,
+ 0x9dd2, 0x48df,
+ 0x9dd3, 0x3e6a,
+ 0x9dd6, 0x48e0,
+ 0x9dda, 0x3e6d,
+ 0x9dfc, 0x48e4,
+ 0x9dfd, 0x3e8f,
+ 0x9e40, 0x3e91,
+ 0x9e43, 0x48e5,
+ 0x9e44, 0x3e95,
+ 0x9e5f, 0x48e6,
+ 0x9e60, 0x3eb1,
+ 0x9e63, 0x48e7,
+ 0x9e64, 0x3eb4,
+ 0x9e66, 0x48e8,
+ 0x9e68, 0x3eb6,
+ 0x9e69, 0x48ea,
+ 0x9e6a, 0x3eb7,
+ 0x9e6b, 0x48eb,
+ 0x9e71, 0x3eb8,
+ 0x9e72, 0x48f1,
+ 0x9e73, 0x3eb9,
+ 0x9e74, 0x48f2,
+ 0x9e77, 0x3eba,
+ 0x9e79, 0x48f5,
+ 0x9e7a, 0x3ebc,
+ 0x9e7b, 0x48f6,
+ 0x9e7c, 0x3ebd,
+ 0x9e7d, 0x48f7,
+ 0x9e7e, 0x3ebe,
+ 0x9ea1, 0x3ebf,
+ 0x9ea3, 0x48f8,
+ 0x9ea4, 0x3ec1,
+ 0x9ea7, 0x48f9,
+ 0x9eaa, 0x3ec5,
+ 0x9eab, 0x48fb,
+ 0x9ead, 0x3ec7,
+ 0x9eae, 0x48fc,
+ 0x9eaf, 0x3ec8,
+ 0x9eb2, 0x48fd,
+ 0x9eb4, 0x3ecb,
+ 0x9eb5, 0x48ff,
+ 0x9eb6, 0x3ecc,
+ 0x9eb8, 0x4900,
+ 0x9eb9, 0x3ece,
+ 0x9eba, 0x4901,
+ 0x9ebc, 0x3ecf,
+ 0x9ebd, 0x4903,
+ 0x9ebf, 0x3ed0,
+ 0x9ec1, 0x4905,
+ 0x9ec5, 0x3ed3,
+ 0x9ec6, 0x4908,
+ 0x9ec7, 0x3ed4,
+ 0x9ecb, 0x4909,
+ 0x9ecd, 0x3ed9,
+ 0x9ece, 0x490b,
+ 0x9ed0, 0x3eda,
+ 0x9ed2, 0x490d,
+ 0x9ed3, 0x3edc,
+ 0x9ed4, 0x490e,
+ 0x9ed6, 0x3edd,
+ 0x9ed8, 0x4910,
+ 0x9eda, 0x3edf,
+ 0x9ef0, 0x3ef5,
+ 0x9ef2, 0x4912,
+ 0x9ef3, 0x3ef7,
+ 0x9ef5, 0x3ef9,
+ 0x9ef6, 0x4913,
+ 0x9ef9, 0x3efa,
+ 0x9efb, 0x4916,
+ 0x9efc, 0x3efc,
+ 0x9efe, 0x3efe,
+ 0x9f40, 0x3eff,
+ 0x9f43, 0x4917,
+ 0x9f44, 0x3f02,
+ 0x9f48, 0x4918,
+ 0x9f49, 0x3f06,
+ 0x9f4b, 0x4919,
+ 0x9f4d, 0x3f08,
+ 0x9f4f, 0x3f0a,
+ 0x9f61, 0x3f1c,
+ 0x9f67, 0x491b,
+ 0x9f69, 0x3f23,
+ 0x9f70, 0x491d,
+ 0x9f71, 0x3f2a,
+ 0x9fa1, 0x3f38,
+ 0x9fae, 0x3f45,
+ 0x9fb2, 0x3f49,
+ 0x9fb5, 0x491e,
+ 0x9fb6, 0x3f4c,
+ 0x9fbb, 0x491f,
+ 0x9fbc, 0x3f51,
+ 0x9fbf, 0x4920,
+ 0x9fc1, 0x4921,
+ 0x9fc2, 0x3f55,
+ 0x9fc9, 0x3f5c,
+ 0x9fcc, 0x4922,
+ 0x9fcd, 0x3f60,
+ 0x9fd4, 0x4923,
+ 0x9fd5, 0x3f68,
+ 0x9fd9, 0x3f6c,
+ 0x9fdb, 0x3f6e,
+ 0x9fe4, 0x4924,
+ 0x9fe5, 0x3f77,
+ 0x9fe7, 0x3f79,
+ 0x9feb, 0x3f7d,
+ 0x9ff0, 0x3f82,
+ 0x9ff9, 0x4925,
+ 0x9ffa, 0x3f8b,
+ 0xa040, 0x4926,
+ 0xa041, 0x3f90,
+ 0xa047, 0x4927,
+ 0xa048, 0x3f96,
+ 0xa055, 0x4928,
+ 0xa056, 0x3fa3,
+ 0xa058, 0x3fa5,
+ 0xa05b, 0x3fa8,
+ 0xa064, 0x3fb1,
+ 0xa06d, 0x4929,
+ 0xa06e, 0x3fba,
+ 0xa073, 0x3fbf,
+ 0xa078, 0x3fc4,
+ 0xa07b, 0x492a,
+ 0xa07c, 0x3fc7,
+ 0xa0a1, 0x3fca,
+ 0xa0a2, 0x492b,
+ 0xa0a3, 0x3fcb,
+ 0xa0a6, 0x3fce,
+ 0xa0a7, 0x492c,
+ 0xa0a8, 0x3fcf,
+ 0xa0ae, 0x3fd5,
+ 0xa0b0, 0x3fd7,
+ 0xa0c5, 0x492d,
+ 0xa0c6, 0x3fec,
+ 0xa0d0, 0x492e,
+ 0xa0d1, 0x3ff6,
+ 0xa0d4, 0x3ff9,
+ 0xa0d6, 0x3ffb,
+ 0xa0e0, 0x4005,
+ 0xa0e2, 0x4007,
+ 0xa0e3, 0x492f,
+ 0xa0e5, 0x4009,
+ 0xa0e7, 0x4930,
+ 0xa0ee, 0x43b4,
+ 0xa0ef, 0x4937,
+ 0xa0f2, 0x43b8,
+ 0xa0f3, 0x493a,
+ 0xa140, 0x0063,
+ 0xa159, 0x35af,
+ 0xa15d, 0x0080,
+ 0xa1a1, 0x00a2,
+ 0xa1f6, 0x00f8,
+ 0xa1f7, 0x00f7,
+ 0xa1f8, 0x00f9,
+ 0xa240, 0x0100,
+ 0xa2a1, 0x013f,
+ 0xa340, 0x019d,
+ 0xa3a1, 0x01dc,
+ 0xa3bd, 0x01f7,
+ 0xa440, 0x0253,
+ 0xa4a1, 0x0292,
+ 0xa540, 0x02f0,
+ 0xa5a1, 0x032f,
+ 0xa640, 0x038d,
+ 0xa6a1, 0x03cc,
+ 0xa740, 0x042a,
+ 0xa7a1, 0x0469,
+ 0xa840, 0x04c7,
+ 0xa8a1, 0x0506,
+ 0xa940, 0x0564,
+ 0xa9a1, 0x05a3,
+ 0xaa40, 0x0601,
+ 0xaaa1, 0x0640,
+ 0xab40, 0x069e,
+ 0xaba1, 0x06dd,
+ 0xac40, 0x073b,
+ 0xaca1, 0x077a,
+ 0xacfe, 0x097f,
+ 0xad40, 0x07d7,
+ 0xada1, 0x0816,
+ 0xae40, 0x0874,
+ 0xaea1, 0x08b3,
+ 0xaf40, 0x0911,
+ 0xafa1, 0x0950,
+ 0xafd0, 0x0980,
+ 0xb040, 0x09af,
+ 0xb0a1, 0x09ee,
+ 0xb140, 0x0a4c,
+ 0xb1a1, 0x0a8b,
+ 0xb240, 0x0ae9,
+ 0xb2a1, 0x0b28,
+ 0xb340, 0x0b86,
+ 0xb3a1, 0x0bc5,
+ 0xb440, 0x0c23,
+ 0xb4a1, 0x0c62,
+ 0xb540, 0x0cc0,
+ 0xb5a1, 0x0cff,
+ 0xb640, 0x0d5d,
+ 0xb6a1, 0x0d9c,
+ 0xb740, 0x0dfa,
+ 0xb7a1, 0x0e39,
+ 0xb840, 0x0e97,
+ 0xb8a1, 0x0ed6,
+ 0xb940, 0x0f34,
+ 0xb9a1, 0x0f73,
+ 0xba40, 0x0fd1,
+ 0xbaa1, 0x1010,
+ 0xbb40, 0x106e,
+ 0xbba1, 0x10ad,
+ 0xbbc8, 0x10d5,
+ 0xbc40, 0x110c,
+ 0xbca1, 0x114b,
+ 0xbd40, 0x11a9,
+ 0xbda1, 0x11e8,
+ 0xbe40, 0x1246,
+ 0xbe52, 0x10d4,
+ 0xbe53, 0x1258,
+ 0xbea1, 0x1284,
+ 0xbf40, 0x12e2,
+ 0xbfa1, 0x1321,
+ 0xc040, 0x137f,
+ 0xc0a1, 0x13be,
+ 0xc140, 0x141c,
+ 0xc1a1, 0x145b,
+ 0xc1ab, 0x1466,
+ 0xc240, 0x14ba,
+ 0xc2a1, 0x14f9,
+ 0xc2cb, 0x1465,
+ 0xc2cc, 0x1523,
+ 0xc340, 0x1556,
+ 0xc361, 0x1578,
+ 0xc3a1, 0x1596,
+ 0xc3b9, 0x15af,
+ 0xc3ba, 0x15ae,
+ 0xc3bb, 0x15b0,
+ 0xc440, 0x15f4,
+ 0xc456, 0x1577,
+ 0xc457, 0x160a,
+ 0xc4a1, 0x1632,
+ 0xc540, 0x1690,
+ 0xc5a1, 0x16cf,
+ 0xc640, 0x172d,
+ 0xc6a1, 0x01fa,
+ 0xc6bf, 0x0219,
+ 0xc6d0, 0x022a,
+ 0xc6d4, 0x022e,
+ 0xc6d6, 0x0230,
+ 0xc6d8, 0x35b3,
+ 0xc6e0, 0x35ba,
+ 0xc740, 0x35d9,
+ 0xc7a1, 0x3618,
+ 0xc840, 0x3676,
+ 0xc8a1, 0x36b5,
+ 0xc8cd, 0x36e1,
+ 0xc8d4, 0x44c6,
+ 0xc8d7, 0x451c,
+ 0xc8e0, 0x02dc,
+ 0xc8e1, 0x4525,
+ 0xc8e9, 0x0509,
+ 0xc8ea, 0x452d,
+ 0xc8f1, 0x09f6,
+ 0xc8f5, 0x4992,
+ 0xc940, 0x176c,
+ 0xc94a, 0x0274,
+ 0xc94b, 0x1776,
+ 0xc96c, 0x1798,
+ 0xc9a1, 0x17ab,
+ 0xc9be, 0x1797,
+ 0xc9bf, 0x17c8,
+ 0xc9ed, 0x17f7,
+ 0xca40, 0x1809,
+ 0xcaa1, 0x1848,
+ 0xcaf7, 0x17f6,
+ 0xcaf8, 0x189e,
+ 0xcb40, 0x18a5,
+ 0xcba1, 0x18e4,
+ 0xcc40, 0x1942,
+ 0xcca1, 0x1981,
+ 0xcd40, 0x19df,
+ 0xcda1, 0x1a1e,
+ 0xce40, 0x1a7c,
+ 0xcea1, 0x1abb,
+ 0xcf40, 0x1b19,
+ 0xcfa1, 0x1b58,
+ 0xd040, 0x1bb6,
+ 0xd0a1, 0x1bf5,
+ 0xd140, 0x1c53,
+ 0xd1a1, 0x1c92,
+ 0xd240, 0x1cf0,
+ 0xd2a1, 0x1d2f,
+ 0xd340, 0x1d8d,
+ 0xd3a1, 0x1dcc,
+ 0xd440, 0x1e2a,
+ 0xd4a1, 0x1e69,
+ 0xd540, 0x1ec7,
+ 0xd5a1, 0x1f06,
+ 0xd640, 0x1f64,
+ 0xd6a1, 0x1fa3,
+ 0xd6cc, 0x2254,
+ 0xd6cd, 0x1fcf,
+ 0xd740, 0x2001,
+ 0xd77a, 0x22b9,
+ 0xd77b, 0x203b,
+ 0xd7a1, 0x203f,
+ 0xd840, 0x209d,
+ 0xd8a1, 0x20dc,
+ 0xd940, 0x213a,
+ 0xd9a1, 0x2179,
+ 0xda40, 0x21d7,
+ 0xdaa1, 0x2216,
+ 0xdadf, 0x1fce,
+ 0xdae0, 0x2255,
+ 0xdb40, 0x2274,
+ 0xdba1, 0x22b3,
+ 0xdba7, 0x22ba,
+ 0xdc40, 0x2312,
+ 0xdca1, 0x2351,
+ 0xdd40, 0x23af,
+ 0xdda1, 0x23ee,
+ 0xddfc, 0x2381,
+ 0xddfd, 0x2449,
+ 0xde40, 0x244b,
+ 0xdea1, 0x248a,
+ 0xdf40, 0x24e8,
+ 0xdfa1, 0x2527,
+ 0xe040, 0x2585,
+ 0xe0a1, 0x25c4,
+ 0xe140, 0x2622,
+ 0xe1a1, 0x2661,
+ 0xe240, 0x26bf,
+ 0xe2a1, 0x26fe,
+ 0xe340, 0x275c,
+ 0xe3a1, 0x279b,
+ 0xe440, 0x27f9,
+ 0xe4a1, 0x2838,
+ 0xe540, 0x2896,
+ 0xe5a1, 0x28d5,
+ 0xe640, 0x2933,
+ 0xe6a1, 0x2972,
+ 0xe740, 0x29d0,
+ 0xe7a1, 0x2a0f,
+ 0xe840, 0x2a6d,
+ 0xe8a1, 0x2aac,
+ 0xe8a3, 0x2aaf,
+ 0xe940, 0x2b0b,
+ 0xe976, 0x2b42,
+ 0xe9a1, 0x2b4b,
+ 0xea40, 0x2ba9,
+ 0xeaa1, 0x2be8,
+ 0xeb40, 0x2c46,
+ 0xeb5b, 0x2c62,
+ 0xeba1, 0x2c86,
+ 0xebf1, 0x2aae,
+ 0xebf2, 0x2cd6,
+ 0xec40, 0x2ce3,
+ 0xeca1, 0x2d22,
+ 0xecde, 0x2b41,
+ 0xecdf, 0x2d5f,
+ 0xed40, 0x2d7f,
+ 0xeda1, 0x2dbe,
+ 0xedaa, 0x2dc8,
+ 0xee40, 0x2e1d,
+ 0xeea1, 0x2e5c,
+ 0xeeeb, 0x3014,
+ 0xeeec, 0x2ea6,
+ 0xef40, 0x2eb9,
+ 0xefa1, 0x2ef8,
+ 0xf040, 0x2f56,
+ 0xf056, 0x2dc7,
+ 0xf057, 0x2f6c,
+ 0xf0a1, 0x2f94,
+ 0xf0cb, 0x2c61,
+ 0xf0cc, 0x2fbe,
+ 0xf140, 0x2ff1,
+ 0xf163, 0x3015,
+ 0xf16b, 0x3160,
+ 0xf16c, 0x301d,
+ 0xf1a1, 0x3030,
+ 0xf240, 0x308e,
+ 0xf268, 0x31ef,
+ 0xf269, 0x30b6,
+ 0xf2a1, 0x30cc,
+ 0xf2c3, 0x30ef,
+ 0xf340, 0x312b,
+ 0xf375, 0x3161,
+ 0xf3a1, 0x316b,
+ 0xf440, 0x31c9,
+ 0xf466, 0x31f0,
+ 0xf4a1, 0x3209,
+ 0xf4b5, 0x30ee,
+ 0xf4b6, 0x321d,
+ 0xf4fd, 0x3265,
+ 0xf540, 0x3267,
+ 0xf5a1, 0x32a6,
+ 0xf640, 0x3304,
+ 0xf663, 0x3264,
+ 0xf664, 0x3327,
+ 0xf6a1, 0x3342,
+ 0xf740, 0x33a0,
+ 0xf7a1, 0x33df,
+ 0xf840, 0x343d,
+ 0xf8a1, 0x347c,
+ 0xf940, 0x34da,
+ 0xf977, 0x3512,
+ 0xf9a1, 0x351a,
+ 0xf9c4, 0x3511,
+ 0xf9c5, 0x353d,
+ 0xf9c6, 0x3549,
+ 0xf9c7, 0x353e,
+ 0xf9d2, 0x354a,
+ 0xf9d6, 0x36e8,
+ 0xfa40, 0x400b,
+ 0xfa60, 0x402b,
+ 0xfa67, 0x4032,
+ 0xfaa1, 0x404a,
+ 0xfaa9, 0x4946,
+ 0xfaab, 0x4054,
+ 0xfabe, 0x4067,
+ 0xfac6, 0x406f,
+ 0xfad6, 0x407f,
+ 0xfb40, 0x40a8,
+ 0xfb49, 0x40b1,
+ 0xfb53, 0x4948,
+ 0xfb54, 0x40bc,
+ 0xfb6e, 0x4949,
+ 0xfb6f, 0x40d7,
+ 0xfba1, 0x40e7,
+ 0xfba3, 0x494a,
+ 0xfba4, 0x40ea,
+ 0xfbb9, 0x40ff,
+ 0xfbbf, 0x494b,
+ 0xfbc0, 0x4105,
+ 0xfbcd, 0x494c,
+ 0xfbce, 0x4112,
+ 0xfbf4, 0x4138,
+ 0xfbfa, 0x413e,
+ 0xfc40, 0x4143,
+ 0xfc4a, 0x494d,
+ 0xfc4b, 0x414d,
+ 0xfc50, 0x4151,
+ 0xfc52, 0x494e,
+ 0xfc53, 0x4153,
+ 0xfc63, 0x494f,
+ 0xfc64, 0x4163,
+ 0xfc6d, 0x4950,
+ 0xfc6e, 0x416d,
+ 0xfc75, 0x4951,
+ 0xfc76, 0x4174,
+ 0xfca1, 0x417d,
+ 0xfcba, 0x4195,
+ 0xfcbc, 0x4952,
+ 0xfcbe, 0x4198,
+ 0xfccc, 0x4954,
+ 0xfccd, 0x41a7,
+ 0xfce3, 0x4955,
+ 0xfce4, 0x41bd,
+ 0xfcee, 0x4956,
+ 0xfcef, 0x41c7,
+ 0xfcf2, 0x41ca,
+ 0xfd40, 0x41d7,
+ 0xfd49, 0x4957,
+ 0xfd4a, 0x41e0,
+ 0xfd6a, 0x4958,
+ 0xfd6b, 0x4201,
+ 0xfda1, 0x4215,
+ 0xfdb9, 0x422d,
+ 0xfdbc, 0x4230,
+ 0xfde3, 0x4959,
+ 0xfde4, 0x4258,
+ 0xfdf2, 0x495a,
+ 0xfdf3, 0x4266,
+ 0xfe40, 0x4272,
+ 0xfe53, 0x4285,
+ 0xfe6d, 0x495b,
+ 0xfe6e, 0x429f,
+ 0xfe70, 0x42a1,
+ 0xfe78, 0x495c,
+ 0xfe79, 0x42a9,
+ 0xfea1, 0x42af,
+ 0xfeab, 0x42b8,
+ 0xfede, 0x495d,
+ 0xfee0, 0x42eb,
+ 0xfeed, 0x495f,
+ 0xfeef, 0x42f8,
+ 0xa14b, 0x354e,
+ 0xa15a, 0x35af,
+ 0xa15c, 0x35b1,
+ 0xa15d, 0x0082,
+ 0xa161, 0x0086,
+ 0xa165, 0x008a,
+ 0xa169, 0x008e,
+ 0xa16d, 0x0092,
+ 0xa171, 0x0096,
+ 0xa175, 0x009a,
+ 0xa179, 0x009e,
+ 0xa1e3, 0x354f,
+ 0xc6e4, 0x3711,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 cns13HKscsB5VEnc16 = {
+ 1,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
+ 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010,
+ 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018,
+ 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020,
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028,
+ 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030,
+ 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038,
+ 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040,
+ 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048,
+ 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050,
+ 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
+ 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ cns13HKscsB5VMap2, 1142
+};
+
+static Gushort cns13UniCNSUCS2HMap2[30910] = {
+ 0x0000, 0x0000,
+ 0x0020, 0x0001,
+ 0x00a2, 0x0106,
+ 0x00a5, 0x0104,
+ 0x00a7, 0x00b2,
+ 0x00a8, 0x35b3,
+ 0x00ac, 0x36e1,
+ 0x00b0, 0x0118,
+ 0x00b1, 0x00d4,
+ 0x00b7, 0x0073,
+ 0x00c0, 0x4964,
+ 0x00c1, 0x4962,
+ 0x00c8, 0x4968,
+ 0x00c9, 0x4966,
+ 0x00ca, 0x4971,
+ 0x00d2, 0x496c,
+ 0x00d3, 0x496a,
+ 0x00d7, 0x00d2,
+ 0x00e0, 0x4975,
+ 0x00e1, 0x4973,
+ 0x00e8, 0x497a,
+ 0x00e9, 0x4978,
+ 0x00ea, 0x4990,
+ 0x00ec, 0x497e,
+ 0x00ed, 0x497c,
+ 0x00f2, 0x4982,
+ 0x00f3, 0x4980,
+ 0x00f7, 0x00d3,
+ 0x00f8, 0x4998,
+ 0x00f9, 0x4986,
+ 0x00fa, 0x4984,
+ 0x00fc, 0x498b,
+ 0x0100, 0x4961,
+ 0x0101, 0x4972,
+ 0x0112, 0x4965,
+ 0x0113, 0x4977,
+ 0x011a, 0x4967,
+ 0x011b, 0x4979,
+ 0x012b, 0x497b,
+ 0x014b, 0x4999,
+ 0x014c, 0x4969,
+ 0x014d, 0x497f,
+ 0x0153, 0x4997,
+ 0x016b, 0x4983,
+ 0x01cd, 0x4963,
+ 0x01ce, 0x4974,
+ 0x01d0, 0x497d,
+ 0x01d1, 0x496b,
+ 0x01d2, 0x4981,
+ 0x01d4, 0x4985,
+ 0x01d6, 0x4987,
+ 0x01d8, 0x4988,
+ 0x01da, 0x4989,
+ 0x01dc, 0x498a,
+ 0x0250, 0x4993,
+ 0x0251, 0x4976,
+ 0x0254, 0x4995,
+ 0x025b, 0x4994,
+ 0x0261, 0x4991,
+ 0x026a, 0x499b,
+ 0x0275, 0x4996,
+ 0x0283, 0x4992,
+ 0x028a, 0x499a,
+ 0x02c6, 0x35b4,
+ 0x02c7, 0x01f8,
+ 0x02ca, 0x01f7,
+ 0x02cb, 0x01f9,
+ 0x02d9, 0x01f6,
+ 0x0308, 0x35b3,
+ 0x0391, 0x01a1,
+ 0x03a3, 0x01b2,
+ 0x03b1, 0x01b9,
+ 0x03c3, 0x01ca,
+ 0x0401, 0x3670,
+ 0x0410, 0x366a,
+ 0x0416, 0x3671,
+ 0x0436, 0x3692,
+ 0x0451, 0x3691,
+ 0x1ebe, 0x496e,
+ 0x1ebf, 0x498d,
+ 0x1ec0, 0x4970,
+ 0x1ec1, 0x498f,
+ 0x2013, 0x0079,
+ 0x2014, 0x007b,
+ 0x2018, 0x00a6,
+ 0x201c, 0x00a8,
+ 0x2022, 0x0068,
+ 0x2025, 0x006f,
+ 0x2026, 0x006e,
+ 0x2032, 0x00ad,
+ 0x2035, 0x00ac,
+ 0x203b, 0x00b1,
+ 0x203e, 0x00c3,
+ 0x20ac, 0x44c1,
+ 0x2103, 0x010a,
+ 0x2105, 0x00c2,
+ 0x2109, 0x010b,
+ 0x2116, 0x36e6,
+ 0x2121, 0x36e7,
+ 0x2160, 0x0157,
+ 0x2170, 0x020e,
+ 0x2190, 0x00f8,
+ 0x2191, 0x00f5,
+ 0x2192, 0x00f7,
+ 0x2193, 0x00f6,
+ 0x2196, 0x00f9,
+ 0x2198, 0x00fc,
+ 0x2199, 0x00fb,
+ 0x21b8, 0x36ad,
+ 0x21e7, 0x36ac,
+ 0x221a, 0x00d5,
+ 0x221e, 0x00dc,
+ 0x221f, 0x00e9,
+ 0x2220, 0x00e8,
+ 0x2223, 0x00fe,
+ 0x2225, 0x00fd,
+ 0x2229, 0x00e5,
+ 0x222b, 0x00ed,
+ 0x222e, 0x00ee,
+ 0x2234, 0x00f0,
+ 0x2235, 0x00ef,
+ 0x223c, 0x00e4,
+ 0x2252, 0x00dd,
+ 0x2260, 0x00db,
+ 0x2261, 0x00de,
+ 0x2266, 0x00d9,
+ 0x22a5, 0x00e7,
+ 0x22bf, 0x00ea,
+ 0x2400, 0x0232,
+ 0x2421, 0x0252,
+ 0x2460, 0x01fa,
+ 0x2474, 0x0204,
+ 0x2500, 0x0137,
+ 0x2502, 0x0138,
+ 0x250c, 0x013a,
+ 0x2510, 0x013b,
+ 0x2514, 0x013c,
+ 0x2518, 0x013d,
+ 0x251c, 0x0135,
+ 0x2524, 0x0134,
+ 0x252c, 0x0133,
+ 0x2534, 0x0132,
+ 0x253c, 0x0131,
+ 0x2550, 0x0142,
+ 0x2551, 0x370a,
+ 0x2552, 0x36f8,
+ 0x2553, 0x3701,
+ 0x2554, 0x36ef,
+ 0x2555, 0x36fa,
+ 0x2556, 0x3703,
+ 0x2557, 0x36f1,
+ 0x2558, 0x36fe,
+ 0x2559, 0x3707,
+ 0x255a, 0x36f5,
+ 0x255b, 0x3700,
+ 0x255c, 0x3709,
+ 0x255d, 0x36f7,
+ 0x255e, 0x0143,
+ 0x255f, 0x3704,
+ 0x2560, 0x36f2,
+ 0x2561, 0x0145,
+ 0x2562, 0x3706,
+ 0x2563, 0x36f4,
+ 0x2564, 0x36f9,
+ 0x2565, 0x3702,
+ 0x2566, 0x36f0,
+ 0x2567, 0x36ff,
+ 0x2568, 0x3708,
+ 0x2569, 0x36f6,
+ 0x256a, 0x0144,
+ 0x256b, 0x3705,
+ 0x256c, 0x36f3,
+ 0x256d, 0x013e,
+ 0x256f, 0x0141,
+ 0x2570, 0x0140,
+ 0x2571, 0x014a,
+ 0x2581, 0x0122,
+ 0x2589, 0x0130,
+ 0x258a, 0x012f,
+ 0x258b, 0x012e,
+ 0x258c, 0x012d,
+ 0x258d, 0x012c,
+ 0x258e, 0x012b,
+ 0x258f, 0x012a,
+ 0x2593, 0x3710,
+ 0x2594, 0x0136,
+ 0x2595, 0x0139,
+ 0x25a0, 0x00be,
+ 0x25a1, 0x00bd,
+ 0x25b2, 0x00b7,
+ 0x25b3, 0x00b6,
+ 0x25bc, 0x00c0,
+ 0x25bd, 0x00bf,
+ 0x25c6, 0x00bc,
+ 0x25c7, 0x00bb,
+ 0x25cb, 0x00b4,
+ 0x25ce, 0x00b8,
+ 0x25cf, 0x00b5,
+ 0x25e2, 0x0146,
+ 0x25e4, 0x0149,
+ 0x25e5, 0x0148,
+ 0x2605, 0x00ba,
+ 0x2606, 0x00b9,
+ 0x2609, 0x00f4,
+ 0x2640, 0x00f1,
+ 0x2641, 0x00f3,
+ 0x2642, 0x00f2,
+ 0x273d, 0x35c0,
+ 0x2e80, 0x44c8,
+ 0x2e84, 0x451c,
+ 0x2e86, 0x451d,
+ 0x2e8a, 0x4520,
+ 0x2e8c, 0x4521,
+ 0x2e95, 0x4523,
+ 0x2e9c, 0x4524,
+ 0x2e9d, 0x02dc,
+ 0x2ea5, 0x4525,
+ 0x2ea7, 0x4526,
+ 0x2eaa, 0x4527,
+ 0x2eac, 0x4528,
+ 0x2eae, 0x4529,
+ 0x2eb6, 0x452a,
+ 0x2ebc, 0x452b,
+ 0x2ebe, 0x452c,
+ 0x2ec6, 0x0509,
+ 0x2eca, 0x452d,
+ 0x2ecc, 0x452e,
+ 0x2ecf, 0x4530,
+ 0x2ed6, 0x4531,
+ 0x2ede, 0x4533,
+ 0x2ee3, 0x09f6,
+ 0x2f33, 0x0227,
+ 0x3000, 0x0063,
+ 0x3001, 0x0065,
+ 0x3003, 0x00b3,
+ 0x3005, 0x35ba,
+ 0x3008, 0x0094,
+ 0x300a, 0x0090,
+ 0x300c, 0x0098,
+ 0x300e, 0x009c,
+ 0x3010, 0x008c,
+ 0x3012, 0x0105,
+ 0x3014, 0x0088,
+ 0x301d, 0x00aa,
+ 0x3021, 0x0161,
+ 0x3041, 0x35c1,
+ 0x309b, 0x44c6,
+ 0x309d, 0x35b7,
+ 0x30a1, 0x3614,
+ 0x30fc, 0x35bd,
+ 0x30fd, 0x35b5,
+ 0x3105, 0x01d1,
+ 0x3231, 0x36e5,
+ 0x32a3, 0x00c1,
+ 0x338e, 0x0115,
+ 0x339c, 0x0110,
+ 0x33a1, 0x0114,
+ 0x33c4, 0x0117,
+ 0x33ce, 0x0113,
+ 0x33d1, 0x00ec,
+ 0x33d2, 0x00eb,
+ 0x33d5, 0x010f,
+ 0x3435, 0x39bd,
+ 0x3440, 0x3c67,
+ 0x344c, 0x4593,
+ 0x3464, 0x3a85,
+ 0x3473, 0x3dc5,
+ 0x347a, 0x4033,
+ 0x347d, 0x4597,
+ 0x347e, 0x46a3,
+ 0x3493, 0x439e,
+ 0x3496, 0x37dc,
+ 0x34a5, 0x4598,
+ 0x34af, 0x3c7f,
+ 0x34bc, 0x4380,
+ 0x34c1, 0x44fb,
+ 0x34c8, 0x3d00,
+ 0x34df, 0x3ea4,
+ 0x34e4, 0x3e54,
+ 0x34fb, 0x3dca,
+ 0x3506, 0x4336,
+ 0x353e, 0x44e7,
+ 0x3551, 0x45a1,
+ 0x3553, 0x43a5,
+ 0x3561, 0x40d8,
+ 0x356d, 0x45a4,
+ 0x3570, 0x3b2f,
+ 0x3572, 0x45a5,
+ 0x3577, 0x3ecb,
+ 0x3578, 0x4379,
+ 0x3584, 0x39fb,
+ 0x3597, 0x3b2d,
+ 0x3598, 0x45b0,
+ 0x35a1, 0x40e2,
+ 0x35a5, 0x45b1,
+ 0x35ad, 0x3efc,
+ 0x35bf, 0x45b2,
+ 0x35c1, 0x4580,
+ 0x35c5, 0x45b4,
+ 0x35c7, 0x459f,
+ 0x35ca, 0x3e43,
+ 0x35ce, 0x3e81,
+ 0x35d2, 0x3fc9,
+ 0x35d6, 0x3fb5,
+ 0x35db, 0x470d,
+ 0x35dd, 0x43ac,
+ 0x35f1, 0x4696,
+ 0x35f2, 0x4627,
+ 0x35f3, 0x3f6c,
+ 0x35fb, 0x45c8,
+ 0x35fe, 0x3f6a,
+ 0x3609, 0x45f5,
+ 0x3618, 0x4871,
+ 0x361a, 0x461a,
+ 0x3623, 0x40c6,
+ 0x362d, 0x3e86,
+ 0x3635, 0x492e,
+ 0x3639, 0x4165,
+ 0x363e, 0x3a08,
+ 0x3647, 0x4806,
+ 0x3648, 0x3806,
+ 0x3649, 0x4013,
+ 0x364e, 0x4698,
+ 0x365f, 0x3df3,
+ 0x367a, 0x3ee3,
+ 0x3681, 0x45a6,
+ 0x369a, 0x3c71,
+ 0x36a5, 0x4902,
+ 0x36aa, 0x3b30,
+ 0x36ac, 0x4900,
+ 0x36b0, 0x3cdf,
+ 0x36b1, 0x40cd,
+ 0x36b5, 0x3bc2,
+ 0x36b9, 0x4887,
+ 0x36bc, 0x3cff,
+ 0x36c1, 0x37c5,
+ 0x36c3, 0x40e5,
+ 0x36c4, 0x3905,
+ 0x36c5, 0x4296,
+ 0x36c7, 0x3d3a,
+ 0x36c8, 0x4820,
+ 0x36d3, 0x3a38,
+ 0x36d4, 0x3bb3,
+ 0x36d6, 0x3d0c,
+ 0x36dd, 0x3a36,
+ 0x36e1, 0x397c,
+ 0x36e2, 0x3cdd,
+ 0x36e5, 0x4216,
+ 0x36e6, 0x40fc,
+ 0x36f5, 0x3a18,
+ 0x3701, 0x3a34,
+ 0x3703, 0x460f,
+ 0x3708, 0x40ff,
+ 0x370a, 0x3cd5,
+ 0x370d, 0x4238,
+ 0x371c, 0x3dfe,
+ 0x3722, 0x3979,
+ 0x3723, 0x3980,
+ 0x3725, 0x3849,
+ 0x372c, 0x3c8c,
+ 0x372d, 0x3d37,
+ 0x3730, 0x495c,
+ 0x3732, 0x4106,
+ 0x3733, 0x3997,
+ 0x373a, 0x3e56,
+ 0x3740, 0x4202,
+ 0x3743, 0x4036,
+ 0x3762, 0x3db6,
+ 0x376f, 0x47cb,
+ 0x3797, 0x45ed,
+ 0x37a0, 0x3a28,
+ 0x37b9, 0x43b7,
+ 0x37be, 0x393e,
+ 0x37f2, 0x3ba1,
+ 0x37f8, 0x42d2,
+ 0x37fb, 0x3ef5,
+ 0x380f, 0x462c,
+ 0x3819, 0x39af,
+ 0x3820, 0x462f,
+ 0x382d, 0x412e,
+ 0x3836, 0x4133,
+ 0x3838, 0x43bb,
+ 0x3863, 0x46c3,
+ 0x38a0, 0x4145,
+ 0x38c3, 0x3912,
+ 0x38cc, 0x4076,
+ 0x38d1, 0x3a95,
+ 0x38fa, 0x44eb,
+ 0x3908, 0x4632,
+ 0x3914, 0x43be,
+ 0x3927, 0x3c31,
+ 0x3932, 0x4182,
+ 0x393f, 0x4633,
+ 0x394d, 0x4634,
+ 0x3963, 0x4163,
+ 0x3980, 0x3874,
+ 0x3989, 0x4638,
+ 0x398a, 0x3ce8,
+ 0x3992, 0x4376,
+ 0x3999, 0x39ba,
+ 0x399b, 0x3db3,
+ 0x39a1, 0x3e19,
+ 0x39a4, 0x3e0f,
+ 0x39b8, 0x463b,
+ 0x39dc, 0x3ece,
+ 0x39e2, 0x46c8,
+ 0x39e5, 0x393b,
+ 0x39ec, 0x4310,
+ 0x39f8, 0x463e,
+ 0x39fb, 0x4345,
+ 0x39fe, 0x4368,
+ 0x3a01, 0x41e0,
+ 0x3a03, 0x4640,
+ 0x3a06, 0x4377,
+ 0x3a17, 0x4190,
+ 0x3a18, 0x438f,
+ 0x3a29, 0x3a5e,
+ 0x3a2a, 0x3edf,
+ 0x3a34, 0x4319,
+ 0x3a4b, 0x4644,
+ 0x3a52, 0x3ed3,
+ 0x3a57, 0x419e,
+ 0x3a5c, 0x3fc4,
+ 0x3a5e, 0x3b07,
+ 0x3a66, 0x419c,
+ 0x3a67, 0x4333,
+ 0x3a97, 0x4647,
+ 0x3aab, 0x4091,
+ 0x3abd, 0x4649,
+ 0x3ade, 0x414c,
+ 0x3ae0, 0x3a7a,
+ 0x3af0, 0x46b2,
+ 0x3af2, 0x464c,
+ 0x3afb, 0x3af2,
+ 0x3b0e, 0x38e8,
+ 0x3b19, 0x46c5,
+ 0x3b22, 0x464e,
+ 0x3b2b, 0x4956,
+ 0x3b39, 0x474b,
+ 0x3b42, 0x4650,
+ 0x3b58, 0x4652,
+ 0x3b60, 0x393a,
+ 0x3b71, 0x4656,
+ 0x3b72, 0x4655,
+ 0x3b7b, 0x4657,
+ 0x3b7c, 0x385a,
+ 0x3b80, 0x41e2,
+ 0x3b96, 0x3a9c,
+ 0x3b99, 0x3a98,
+ 0x3ba1, 0x41e9,
+ 0x3bbc, 0x43c8,
+ 0x3bbe, 0x3db1,
+ 0x3bc2, 0x4134,
+ 0x3bc4, 0x3aa0,
+ 0x3bd7, 0x3aac,
+ 0x3bdd, 0x465f,
+ 0x3bec, 0x4664,
+ 0x3bf2, 0x4666,
+ 0x3bf3, 0x41f3,
+ 0x3bf4, 0x3a6e,
+ 0x3c0d, 0x41f7,
+ 0x3c11, 0x3e40,
+ 0x3c15, 0x3998,
+ 0x3c54, 0x3e00,
+ 0x3ccb, 0x4670,
+ 0x3ccd, 0x3ce5,
+ 0x3cd1, 0x4003,
+ 0x3cd6, 0x3cf7,
+ 0x3cdc, 0x404e,
+ 0x3ceb, 0x4217,
+ 0x3cef, 0x4675,
+ 0x3d13, 0x3773,
+ 0x3d1d, 0x393c,
+ 0x3d32, 0x4957,
+ 0x3d3b, 0x4245,
+ 0x3d46, 0x4685,
+ 0x3d4c, 0x3ceb,
+ 0x3d4e, 0x4242,
+ 0x3d51, 0x38ea,
+ 0x3d5f, 0x4159,
+ 0x3d62, 0x3c5e,
+ 0x3d69, 0x3cea,
+ 0x3d6a, 0x4689,
+ 0x3d6f, 0x3cfc,
+ 0x3d75, 0x468a,
+ 0x3d7d, 0x3c2f,
+ 0x3d85, 0x494b,
+ 0x3d8a, 0x468d,
+ 0x3d8f, 0x3abd,
+ 0x3d91, 0x468f,
+ 0x3da5, 0x3d56,
+ 0x3dad, 0x4699,
+ 0x3db4, 0x40a6,
+ 0x3dbf, 0x37d0,
+ 0x3dc6, 0x48de,
+ 0x3dc7, 0x4164,
+ 0x3dcc, 0x3d6f,
+ 0x3dcd, 0x3af3,
+ 0x3dd3, 0x37e1,
+ 0x3ddb, 0x3fff,
+ 0x3de7, 0x3999,
+ 0x3de8, 0x425d,
+ 0x3deb, 0x3e5a,
+ 0x3df3, 0x46d4,
+ 0x3df7, 0x48ab,
+ 0x3dfc, 0x462b,
+ 0x3dfd, 0x3c14,
+ 0x3e06, 0x491d,
+ 0x3e40, 0x4169,
+ 0x3e43, 0x436d,
+ 0x3e48, 0x4595,
+ 0x3e55, 0x427f,
+ 0x3e74, 0x3ee2,
+ 0x3ea8, 0x4304,
+ 0x3ea9, 0x46ed,
+ 0x3eaa, 0x4075,
+ 0x3ead, 0x3b9d,
+ 0x3eb1, 0x3ad8,
+ 0x3eb8, 0x3a4b,
+ 0x3ebf, 0x3b0b,
+ 0x3ec2, 0x3bd8,
+ 0x3ec7, 0x3975,
+ 0x3eca, 0x46f1,
+ 0x3ecc, 0x3be2,
+ 0x3ed0, 0x3854,
+ 0x3ed1, 0x46f2,
+ 0x3ed6, 0x3cad,
+ 0x3ed7, 0x429f,
+ 0x3eda, 0x3d02,
+ 0x3ede, 0x39f2,
+ 0x3ee1, 0x3ca8,
+ 0x3ee2, 0x46f6,
+ 0x3ee7, 0x3bdc,
+ 0x3ee9, 0x3ca4,
+ 0x3eeb, 0x396a,
+ 0x3ef0, 0x46f7,
+ 0x3ef3, 0x3add,
+ 0x3ef4, 0x46f8,
+ 0x3efa, 0x46f9,
+ 0x3efc, 0x3be8,
+ 0x3eff, 0x3af5,
+ 0x3f00, 0x3c0d,
+ 0x3f04, 0x42c3,
+ 0x3f06, 0x3ad7,
+ 0x3f0e, 0x46fb,
+ 0x3f53, 0x46fc,
+ 0x3f58, 0x3ae9,
+ 0x3f59, 0x4089,
+ 0x3f63, 0x3ae6,
+ 0x3f7c, 0x4700,
+ 0x3f93, 0x45cd,
+ 0x3fc0, 0x43cf,
+ 0x3fd7, 0x43d1,
+ 0x3fdc, 0x4704,
+ 0x3fe5, 0x46df,
+ 0x3fed, 0x4335,
+ 0x3ff9, 0x45d7,
+ 0x3ffa, 0x4354,
+ 0x4004, 0x410e,
+ 0x401d, 0x4709,
+ 0x4039, 0x470b,
+ 0x4045, 0x470c,
+ 0x4053, 0x45b6,
+ 0x4057, 0x399d,
+ 0x4062, 0x3bcb,
+ 0x4065, 0x3fd3,
+ 0x406a, 0x470f,
+ 0x406f, 0x4710,
+ 0x40a8, 0x43d5,
+ 0x40bb, 0x45c0,
+ 0x40bf, 0x3eec,
+ 0x40c8, 0x3b0e,
+ 0x40d8, 0x41ab,
+ 0x40df, 0x3e17,
+ 0x40fa, 0x3ebe,
+ 0x4103, 0x43d7,
+ 0x4104, 0x425c,
+ 0x4109, 0x471c,
+ 0x410e, 0x3b1b,
+ 0x4132, 0x3b25,
+ 0x4167, 0x471f,
+ 0x416c, 0x38ae,
+ 0x416e, 0x3b23,
+ 0x417f, 0x3b82,
+ 0x4190, 0x46c0,
+ 0x41b2, 0x4720,
+ 0x41c4, 0x4723,
+ 0x41ca, 0x373f,
+ 0x41cf, 0x4726,
+ 0x41db, 0x37bf,
+ 0x41ef, 0x3743,
+ 0x41f9, 0x3b3e,
+ 0x4211, 0x3b41,
+ 0x4240, 0x37f1,
+ 0x4260, 0x472b,
+ 0x426a, 0x3b55,
+ 0x427a, 0x472c,
+ 0x428c, 0x472f,
+ 0x4294, 0x4731,
+ 0x42b5, 0x4010,
+ 0x42b9, 0x38a6,
+ 0x42bc, 0x3c8a,
+ 0x42f4, 0x3bb9,
+ 0x42fb, 0x3cee,
+ 0x42fc, 0x41e6,
+ 0x432b, 0x377d,
+ 0x436e, 0x46ca,
+ 0x4397, 0x473b,
+ 0x43ba, 0x435f,
+ 0x43c1, 0x4695,
+ 0x43d9, 0x433e,
+ 0x43df, 0x3e49,
+ 0x43ed, 0x4745,
+ 0x43f2, 0x3e48,
+ 0x4401, 0x474a,
+ 0x4402, 0x3b73,
+ 0x4413, 0x474f,
+ 0x4425, 0x4751,
+ 0x442d, 0x4752,
+ 0x447a, 0x37af,
+ 0x448f, 0x4758,
+ 0x449f, 0x3ae2,
+ 0x44a0, 0x37ed,
+ 0x44a2, 0x4079,
+ 0x44b0, 0x475c,
+ 0x44b7, 0x3fa1,
+ 0x44c0, 0x3c07,
+ 0x44c5, 0x4210,
+ 0x44ce, 0x3d23,
+ 0x44dd, 0x39dd,
+ 0x44df, 0x3d22,
+ 0x44e4, 0x37e2,
+ 0x44e9, 0x41cf,
+ 0x44ea, 0x3b71,
+ 0x44eb, 0x3cf2,
+ 0x44ec, 0x3eb4,
+ 0x44f4, 0x3992,
+ 0x4503, 0x469f,
+ 0x4504, 0x4763,
+ 0x4509, 0x3e50,
+ 0x450b, 0x37d4,
+ 0x4516, 0x37f9,
+ 0x451d, 0x3767,
+ 0x4527, 0x37f7,
+ 0x452e, 0x3cd3,
+ 0x4533, 0x3c51,
+ 0x453b, 0x476a,
+ 0x453d, 0x38c4,
+ 0x453f, 0x3e12,
+ 0x4543, 0x37f3,
+ 0x4551, 0x3ae4,
+ 0x4552, 0x40b3,
+ 0x4555, 0x423e,
+ 0x455c, 0x378b,
+ 0x4562, 0x4940,
+ 0x456a, 0x3804,
+ 0x4577, 0x476e,
+ 0x4585, 0x38c5,
+ 0x45e9, 0x3ee4,
+ 0x4606, 0x4773,
+ 0x460f, 0x3815,
+ 0x4615, 0x3843,
+ 0x4617, 0x4774,
+ 0x465b, 0x381d,
+ 0x467a, 0x39e9,
+ 0x4680, 0x3d01,
+ 0x46cf, 0x3ba0,
+ 0x46d0, 0x3dfa,
+ 0x46f5, 0x3b9f,
+ 0x4713, 0x3833,
+ 0x4718, 0x3dc7,
+ 0x474e, 0x3ebc,
+ 0x477c, 0x3dcd,
+ 0x4798, 0x4781,
+ 0x47a6, 0x40a3,
+ 0x47b6, 0x3eea,
+ 0x47d5, 0x431a,
+ 0x47ed, 0x4783,
+ 0x47f4, 0x432f,
+ 0x4800, 0x461e,
+ 0x480b, 0x4352,
+ 0x4837, 0x4787,
+ 0x485d, 0x410f,
+ 0x4871, 0x3d03,
+ 0x489b, 0x3bbd,
+ 0x48ad, 0x4791,
+ 0x48ae, 0x494d,
+ 0x48d0, 0x3da7,
+ 0x48dd, 0x4120,
+ 0x48ed, 0x4288,
+ 0x48f3, 0x3ec1,
+ 0x48fa, 0x3e44,
+ 0x4906, 0x3bc7,
+ 0x4911, 0x4584,
+ 0x491e, 0x4794,
+ 0x4925, 0x3c0f,
+ 0x492a, 0x46ae,
+ 0x492d, 0x46cd,
+ 0x4935, 0x3cc3,
+ 0x493c, 0x3bf8,
+ 0x493e, 0x3d06,
+ 0x4945, 0x47a3,
+ 0x4951, 0x47a4,
+ 0x4953, 0x42ad,
+ 0x4965, 0x3899,
+ 0x496a, 0x47a9,
+ 0x4972, 0x3a24,
+ 0x4989, 0x379b,
+ 0x49a1, 0x38b7,
+ 0x49a7, 0x47ae,
+ 0x49df, 0x38aa,
+ 0x49e5, 0x47b1,
+ 0x49e7, 0x4621,
+ 0x4a0f, 0x38c3,
+ 0x4a1d, 0x3bec,
+ 0x4a24, 0x47b2,
+ 0x4a35, 0x47b4,
+ 0x4a96, 0x3ce7,
+ 0x4ab4, 0x4361,
+ 0x4ab8, 0x3da8,
+ 0x4ad1, 0x38e3,
+ 0x4ae4, 0x47b7,
+ 0x4aff, 0x38f2,
+ 0x4b19, 0x47b9,
+ 0x4b2c, 0x461f,
+ 0x4b37, 0x41a9,
+ 0x4b6f, 0x3c16,
+ 0x4b70, 0x47c0,
+ 0x4b72, 0x38fc,
+ 0x4b7b, 0x3c8d,
+ 0x4b7e, 0x400a,
+ 0x4b8e, 0x39f7,
+ 0x4b90, 0x3c20,
+ 0x4b93, 0x3a8c,
+ 0x4b96, 0x3942,
+ 0x4b97, 0x3c24,
+ 0x4b9d, 0x47c2,
+ 0x4bbd, 0x3c23,
+ 0x4bbe, 0x3954,
+ 0x4bc0, 0x3ddc,
+ 0x4c04, 0x3fbb,
+ 0x4c07, 0x3fb7,
+ 0x4c0e, 0x390c,
+ 0x4c3b, 0x3f3c,
+ 0x4c3e, 0x457b,
+ 0x4c5b, 0x3ed9,
+ 0x4c6d, 0x47c9,
+ 0x4c7d, 0x3e66,
+ 0x4ca4, 0x48be,
+ 0x4cae, 0x3c42,
+ 0x4cb0, 0x3c45,
+ 0x4cb7, 0x3e21,
+ 0x4ccd, 0x4578,
+ 0x4ce1, 0x3ef3,
+ 0x4ced, 0x40ab,
+ 0x4d09, 0x3ed6,
+ 0x4d10, 0x4117,
+ 0x4d34, 0x3935,
+ 0x4d91, 0x43f5,
+ 0x4d9c, 0x48c4,
+ 0x4e00, 0x0253,
+ 0x4e01, 0x0255,
+ 0x4e03, 0x0256,
+ 0x4e04, 0x48fe,
+ 0x4e07, 0x1771,
+ 0x4e08, 0x0269,
+ 0x4e09, 0x0267,
+ 0x4e0a, 0x026a,
+ 0x4e0b, 0x0268,
+ 0x4e0c, 0x1772,
+ 0x4e0d, 0x0294,
+ 0x4e0e, 0x177a,
+ 0x4e0f, 0x1778,
+ 0x4e10, 0x0293,
+ 0x4e11, 0x0292,
+ 0x4e14, 0x02f2,
+ 0x4e15, 0x02f1,
+ 0x4e16, 0x02f0,
+ 0x4e18, 0x02f3,
+ 0x4e19, 0x02ef,
+ 0x4e1a, 0x48fd,
+ 0x4e1c, 0x48e0,
+ 0x4e1e, 0x036e,
+ 0x4e21, 0x3d6d,
+ 0x4e24, 0x458d,
+ 0x4e26, 0x0528,
+ 0x4e28, 0x0218,
+ 0x4e2a, 0x3f57,
+ 0x4e2b, 0x026b,
+ 0x4e2c, 0x44f3,
+ 0x4e2d, 0x0295,
+ 0x4e2e, 0x177b,
+ 0x4e30, 0x0296,
+ 0x4e31, 0x178e,
+ 0x4e32, 0x0415,
+ 0x4e33, 0x18f4,
+ 0x4e36, 0x0219,
+ 0x4e37, 0x4517,
+ 0x4e38, 0x026c,
+ 0x4e39, 0x0297,
+ 0x4e3b, 0x02f4,
+ 0x4e3c, 0x178f,
+ 0x4e3d, 0x4537,
+ 0x4e3f, 0x021a,
+ 0x4e41, 0x36af,
+ 0x4e42, 0x176c,
+ 0x4e43, 0x0257,
+ 0x4e45, 0x026e,
+ 0x4e47, 0x1773,
+ 0x4e48, 0x026f,
+ 0x4e49, 0x408e,
+ 0x4e4b, 0x0298,
+ 0x4e4d, 0x02f5,
+ 0x4e4e, 0x02f7,
+ 0x4e4f, 0x02f6,
+ 0x4e52, 0x0370,
+ 0x4e56, 0x0529,
+ 0x4e58, 0x0831,
+ 0x4e59, 0x0254,
+ 0x4e5a, 0x36b1,
+ 0x4e5b, 0x44e5,
+ 0x4e5c, 0x176d,
+ 0x4e5d, 0x0258,
+ 0x4e5e, 0x0271,
+ 0x4e5f, 0x0270,
+ 0x4e69, 0x0372,
+ 0x4e6a, 0x3de5,
+ 0x4e73, 0x052a,
+ 0x4e78, 0x3d8e,
+ 0x4e7e, 0x09fb,
+ 0x4e7f, 0x1e35,
+ 0x4e80, 0x458e,
+ 0x4e81, 0x43bc,
+ 0x4e82, 0x0dbe,
+ 0x4e83, 0x2361,
+ 0x4e85, 0x021b,
+ 0x4e86, 0x0259,
+ 0x4e87, 0x458f,
+ 0x4e88, 0x029a,
+ 0x4e89, 0x459c,
+ 0x4e8b, 0x052b,
+ 0x4e8c, 0x025a,
+ 0x4e8d, 0x1774,
+ 0x4e8e, 0x0272,
+ 0x4e91, 0x029b,
+ 0x4e92, 0x029d,
+ 0x4e93, 0x177c,
+ 0x4e94, 0x029e,
+ 0x4e95, 0x029c,
+ 0x4e98, 0x39c4,
+ 0x4e99, 0x0373,
+ 0x4e9a, 0x48d5,
+ 0x4e9b, 0x052c,
+ 0x4e9e, 0x052d,
+ 0x4e9f, 0x06a3,
+ 0x4ea0, 0x021c,
+ 0x4ea1, 0x0273,
+ 0x4ea2, 0x029f,
+ 0x4ea4, 0x0374,
+ 0x4ea5, 0x0376,
+ 0x4ea6, 0x0375,
+ 0x4ea8, 0x0416,
+ 0x4eab, 0x052e,
+ 0x4ead, 0x06a4,
+ 0x4eb3, 0x0832,
+ 0x4eb6, 0x2363,
+ 0x4eb7, 0x413c,
+ 0x4eb9, 0x3377,
+ 0x4eba, 0x025b,
+ 0x4ebb, 0x44e6,
+ 0x4ebc, 0x39b1,
+ 0x4ebf, 0x4590,
+ 0x4ec0, 0x02a1,
+ 0x4ec1, 0x02a0,
+ 0x4ec2, 0x177d,
+ 0x4ec3, 0x02a2,
+ 0x4ec4, 0x02a8,
+ 0x4ec6, 0x02a3,
+ 0x4ec8, 0x177f,
+ 0x4ec9, 0x177e,
+ 0x4eca, 0x02a6,
+ 0x4ecd, 0x02a5,
+ 0x4ece, 0x3f62,
+ 0x4ed4, 0x02fa,
+ 0x4ed8, 0x02f9,
+ 0x4ed9, 0x0300,
+ 0x4eda, 0x1795,
+ 0x4edc, 0x1791,
+ 0x4edd, 0x1794,
+ 0x4ede, 0x0301,
+ 0x4edf, 0x0311,
+ 0x4ee1, 0x1793,
+ 0x4ee3, 0x02fe,
+ 0x4ee5, 0x02f8,
+ 0x4ee8, 0x1790,
+ 0x4ee9, 0x1792,
+ 0x4eea, 0x48cb,
+ 0x4eeb, 0x4591,
+ 0x4eee, 0x3d76,
+ 0x4ef0, 0x0383,
+ 0x4ef1, 0x17ba,
+ 0x4ef2, 0x0380,
+ 0x4ef3, 0x0384,
+ 0x4ef4, 0x17c4,
+ 0x4ef5, 0x17b8,
+ 0x4ef6, 0x0381,
+ 0x4ef7, 0x17bc,
+ 0x4ef8, 0x39ad,
+ 0x4efb, 0x0382,
+ 0x4efd, 0x0385,
+ 0x4eff, 0x0377,
+ 0x4f00, 0x17bb,
+ 0x4f01, 0x0386,
+ 0x4f02, 0x17bf,
+ 0x4f03, 0x39c8,
+ 0x4f04, 0x17c3,
+ 0x4f05, 0x17c0,
+ 0x4f08, 0x17bd,
+ 0x4f09, 0x0378,
+ 0x4f0a, 0x037a,
+ 0x4f0b, 0x0387,
+ 0x4f0d, 0x037c,
+ 0x4f0e, 0x17b5,
+ 0x4f0f, 0x037f,
+ 0x4f10, 0x037d,
+ 0x4f12, 0x17c5,
+ 0x4f13, 0x17c2,
+ 0x4f14, 0x17b9,
+ 0x4f15, 0x037b,
+ 0x4f18, 0x17b6,
+ 0x4f19, 0x0379,
+ 0x4f1a, 0x453c,
+ 0x4f1d, 0x17be,
+ 0x4f22, 0x17c1,
+ 0x4f28, 0x453d,
+ 0x4f29, 0x39be,
+ 0x4f2c, 0x17b7,
+ 0x4f2d, 0x182f,
+ 0x4f2f, 0x042c,
+ 0x4f30, 0x041f,
+ 0x4f32, 0x393d,
+ 0x4f33, 0x1830,
+ 0x4f34, 0x041c,
+ 0x4f36, 0x042e,
+ 0x4f37, 0x4592,
+ 0x4f38, 0x0424,
+ 0x4f39, 0x3f65,
+ 0x4f3a, 0x0423,
+ 0x4f3b, 0x1824,
+ 0x4f3c, 0x0427,
+ 0x4f3d, 0x0422,
+ 0x4f3e, 0x1829,
+ 0x4f3f, 0x1831,
+ 0x4f41, 0x182d,
+ 0x4f42, 0x39cb,
+ 0x4f43, 0x0425,
+ 0x4f45, 0x3b8f,
+ 0x4f46, 0x0428,
+ 0x4f47, 0x0419,
+ 0x4f48, 0x0431,
+ 0x4f49, 0x1826,
+ 0x4f4b, 0x39b4,
+ 0x4f4c, 0x1900,
+ 0x4f4d, 0x0417,
+ 0x4f4e, 0x042d,
+ 0x4f4f, 0x0418,
+ 0x4f50, 0x0420,
+ 0x4f52, 0x182b,
+ 0x4f53, 0x1827,
+ 0x4f54, 0x0426,
+ 0x4f55, 0x041e,
+ 0x4f56, 0x1823,
+ 0x4f57, 0x041a,
+ 0x4f58, 0x182e,
+ 0x4f59, 0x042f,
+ 0x4f5a, 0x0432,
+ 0x4f5b, 0x041d,
+ 0x4f5c, 0x042a,
+ 0x4f5d, 0x0430,
+ 0x4f5e, 0x041b,
+ 0x4f5f, 0x182c,
+ 0x4f60, 0x042b,
+ 0x4f61, 0x1832,
+ 0x4f62, 0x1825,
+ 0x4f63, 0x0429,
+ 0x4f64, 0x1828,
+ 0x4f67, 0x182a,
+ 0x4f69, 0x053d,
+ 0x4f6a, 0x1902,
+ 0x4f6b, 0x190e,
+ 0x4f6c, 0x0535,
+ 0x4f6e, 0x190f,
+ 0x4f6f, 0x0530,
+ 0x4f70, 0x053a,
+ 0x4f72, 0x3c72,
+ 0x4f73, 0x0533,
+ 0x4f74, 0x18fc,
+ 0x4f75, 0x053b,
+ 0x4f76, 0x18fb,
+ 0x4f77, 0x18ff,
+ 0x4f78, 0x1906,
+ 0x4f79, 0x1904,
+ 0x4f7a, 0x0543,
+ 0x4f7b, 0x053e,
+ 0x4f7c, 0x18f6,
+ 0x4f7d, 0x18f8,
+ 0x4f7e, 0x0540,
+ 0x4f7f, 0x0534,
+ 0x4f80, 0x18f9,
+ 0x4f81, 0x1905,
+ 0x4f82, 0x190c,
+ 0x4f83, 0x0539,
+ 0x4f84, 0x18fe,
+ 0x4f85, 0x18f7,
+ 0x4f86, 0x0538,
+ 0x4f87, 0x18fa,
+ 0x4f88, 0x053c,
+ 0x4f89, 0x18fd,
+ 0x4f8a, 0x39b5,
+ 0x4f8b, 0x0537,
+ 0x4f8d, 0x0532,
+ 0x4f8f, 0x0541,
+ 0x4f90, 0x1907,
+ 0x4f91, 0x0542,
+ 0x4f92, 0x190b,
+ 0x4f94, 0x1909,
+ 0x4f95, 0x190d,
+ 0x4f96, 0x053f,
+ 0x4f97, 0x1901,
+ 0x4f98, 0x18f5,
+ 0x4f9a, 0x1903,
+ 0x4f9b, 0x0536,
+ 0x4f9c, 0x1908,
+ 0x4f9d, 0x0531,
+ 0x4f9e, 0x190a,
+ 0x4fa2, 0x39c7,
+ 0x4fa8, 0x453e,
+ 0x4fab, 0x4022,
+ 0x4fae, 0x06b4,
+ 0x4faf, 0x06a8,
+ 0x4fb0, 0x3d4a,
+ 0x4fb2, 0x1a5d,
+ 0x4fb3, 0x1a65,
+ 0x4fb5, 0x06a7,
+ 0x4fb6, 0x06af,
+ 0x4fb7, 0x06bb,
+ 0x4fb9, 0x1a6b,
+ 0x4fba, 0x1a69,
+ 0x4fbb, 0x1a64,
+ 0x4fbd, 0x4594,
+ 0x4fbf, 0x06a9,
+ 0x4fc0, 0x1a6a,
+ 0x4fc1, 0x1a60,
+ 0x4fc2, 0x06b7,
+ 0x4fc3, 0x06ae,
+ 0x4fc4, 0x06b6,
+ 0x4fc5, 0x1a5b,
+ 0x4fc7, 0x1a67,
+ 0x4fc8, 0x46e8,
+ 0x4fc9, 0x1a5e,
+ 0x4fca, 0x06b2,
+ 0x4fcb, 0x1a5f,
+ 0x4fcc, 0x39cf,
+ 0x4fcd, 0x1a5a,
+ 0x4fce, 0x06b9,
+ 0x4fcf, 0x06ac,
+ 0x4fd0, 0x06b5,
+ 0x4fd1, 0x06ab,
+ 0x4fd3, 0x1a5c,
+ 0x4fd4, 0x1a61,
+ 0x4fd6, 0x1a68,
+ 0x4fd7, 0x06b3,
+ 0x4fd8, 0x06b0,
+ 0x4fd9, 0x1a63,
+ 0x4fda, 0x06b8,
+ 0x4fdb, 0x1a66,
+ 0x4fdc, 0x1a62,
+ 0x4fdd, 0x06ad,
+ 0x4fde, 0x06ba,
+ 0x4fdf, 0x06b1,
+ 0x4fe0, 0x06aa,
+ 0x4fe1, 0x06a6,
+ 0x4fe4, 0x3c66,
+ 0x4fe5, 0x39d0,
+ 0x4fec, 0x1a6c,
+ 0x4fee, 0x084c,
+ 0x4fef, 0x0836,
+ 0x4ff1, 0x0846,
+ 0x4ff2, 0x3f28,
+ 0x4ff3, 0x084b,
+ 0x4ff4, 0x1c24,
+ 0x4ff5, 0x1c23,
+ 0x4ff6, 0x1c28,
+ 0x4ff8, 0x0839,
+ 0x4ff9, 0x37b3,
+ 0x4ffa, 0x0842,
+ 0x4ffd, 0x3f26,
+ 0x4ffe, 0x084f,
+ 0x5000, 0x0843,
+ 0x5003, 0x4596,
+ 0x5005, 0x1c1d,
+ 0x5006, 0x083c,
+ 0x5007, 0x1c1e,
+ 0x5008, 0x4024,
+ 0x5009, 0x0851,
+ 0x500b, 0x0848,
+ 0x500c, 0x0833,
+ 0x500e, 0x1c31,
+ 0x500f, 0x0a0c,
+ 0x5011, 0x0841,
+ 0x5012, 0x0840,
+ 0x5013, 0x1c1f,
+ 0x5014, 0x0844,
+ 0x5015, 0x1e45,
+ 0x5016, 0x083b,
+ 0x5017, 0x1c2a,
+ 0x5018, 0x084a,
+ 0x5019, 0x0849,
+ 0x501a, 0x083f,
+ 0x501b, 0x1c22,
+ 0x501c, 0x1c2b,
+ 0x501e, 0x1c1c,
+ 0x501f, 0x083e,
+ 0x5020, 0x1c2c,
+ 0x5021, 0x0847,
+ 0x5022, 0x1c20,
+ 0x5023, 0x0835,
+ 0x5025, 0x0838,
+ 0x5026, 0x0837,
+ 0x5027, 0x1c2d,
+ 0x5028, 0x0845,
+ 0x5029, 0x083a,
+ 0x502a, 0x084e,
+ 0x502b, 0x0850,
+ 0x502c, 0x1c27,
+ 0x502d, 0x084d,
+ 0x502e, 0x39cc,
+ 0x502f, 0x1c2f,
+ 0x5030, 0x1c21,
+ 0x5031, 0x1c30,
+ 0x5033, 0x1c25,
+ 0x5034, 0x3910,
+ 0x5035, 0x1c2e,
+ 0x5037, 0x1c26,
+ 0x503c, 0x083d,
+ 0x5040, 0x1e4d,
+ 0x5041, 0x1e41,
+ 0x5043, 0x0a00,
+ 0x5045, 0x1e46,
+ 0x5046, 0x1e4c,
+ 0x5047, 0x09ff,
+ 0x5048, 0x1e3f,
+ 0x5049, 0x0a03,
+ 0x504a, 0x1e43,
+ 0x504b, 0x1e3c,
+ 0x504c, 0x0a01,
+ 0x504d, 0x1e40,
+ 0x504e, 0x0a06,
+ 0x504f, 0x0a0b,
+ 0x5051, 0x1e51,
+ 0x5053, 0x1e3b,
+ 0x5055, 0x0a07,
+ 0x5056, 0x3f2c,
+ 0x5057, 0x1e50,
+ 0x5058, 0x39d1,
+ 0x505a, 0x0a02,
+ 0x505b, 0x1e42,
+ 0x505c, 0x09fe,
+ 0x505d, 0x1e3d,
+ 0x505e, 0x1e39,
+ 0x505f, 0x1e47,
+ 0x5060, 0x1e3a,
+ 0x5061, 0x1e38,
+ 0x5062, 0x1e44,
+ 0x5063, 0x1e4a,
+ 0x5065, 0x0a04,
+ 0x5066, 0x3dc9,
+ 0x5068, 0x20b8,
+ 0x5069, 0x1e48,
+ 0x506a, 0x1e37,
+ 0x506b, 0x1e49,
+ 0x506c, 0x39cd,
+ 0x506d, 0x0a0e,
+ 0x506e, 0x1e4e,
+ 0x506f, 0x0a0d,
+ 0x5070, 0x1e36,
+ 0x5072, 0x1e3e,
+ 0x5073, 0x1e4f,
+ 0x5074, 0x0a09,
+ 0x5075, 0x0a08,
+ 0x5076, 0x0a05,
+ 0x5077, 0x0a0a,
+ 0x507a, 0x09fc,
+ 0x507d, 0x09fd,
+ 0x5080, 0x0bec,
+ 0x5081, 0x39ce,
+ 0x5082, 0x20bb,
+ 0x5083, 0x20b4,
+ 0x5085, 0x0be9,
+ 0x5087, 0x20bc,
+ 0x5088, 0x439c,
+ 0x508b, 0x20b2,
+ 0x508c, 0x20b5,
+ 0x508d, 0x0be8,
+ 0x508e, 0x20b6,
+ 0x5090, 0x41ec,
+ 0x5091, 0x0beb,
+ 0x5092, 0x20ba,
+ 0x5094, 0x20b0,
+ 0x5095, 0x20af,
+ 0x5096, 0x0bed,
+ 0x5098, 0x0bee,
+ 0x5099, 0x0bea,
+ 0x509a, 0x0bef,
+ 0x509b, 0x20ae,
+ 0x509c, 0x20b9,
+ 0x509d, 0x20b7,
+ 0x509e, 0x20b1,
+ 0x50a2, 0x0be7,
+ 0x50a3, 0x20b3,
+ 0x50a6, 0x3f3f,
+ 0x50ac, 0x0dc5,
+ 0x50ad, 0x0dbf,
+ 0x50ae, 0x2367,
+ 0x50af, 0x0dc8,
+ 0x50b0, 0x236d,
+ 0x50b1, 0x2370,
+ 0x50b2, 0x0dc1,
+ 0x50b4, 0x236a,
+ 0x50b5, 0x0dc0,
+ 0x50b6, 0x2373,
+ 0x50b7, 0x0dc6,
+ 0x50b8, 0x2374,
+ 0x50ba, 0x236f,
+ 0x50bb, 0x0dc7,
+ 0x50bd, 0x2364,
+ 0x50be, 0x0dc4,
+ 0x50bf, 0x2365,
+ 0x50c1, 0x236e,
+ 0x50c2, 0x236c,
+ 0x50c4, 0x2368,
+ 0x50c5, 0x0dc3,
+ 0x50c6, 0x2366,
+ 0x50c7, 0x0dc9,
+ 0x50c8, 0x236b,
+ 0x50c9, 0x2372,
+ 0x50ca, 0x2369,
+ 0x50cb, 0x2371,
+ 0x50cd, 0x39c5,
+ 0x50ce, 0x0f88,
+ 0x50cf, 0x0f85,
+ 0x50d0, 0x38d1,
+ 0x50d1, 0x0f86,
+ 0x50d3, 0x261c,
+ 0x50d4, 0x2614,
+ 0x50d5, 0x0f84,
+ 0x50d6, 0x0f81,
+ 0x50d7, 0x2615,
+ 0x50d9, 0x3fce,
+ 0x50da, 0x0f83,
+ 0x50db, 0x2618,
+ 0x50dd, 0x261a,
+ 0x50de, 0x4031,
+ 0x50df, 0x3afd,
+ 0x50e0, 0x2621,
+ 0x50e1, 0x4171,
+ 0x50e3, 0x2620,
+ 0x50e4, 0x261b,
+ 0x50e5, 0x0f80,
+ 0x50e6, 0x2613,
+ 0x50e7, 0x0f7e,
+ 0x50e8, 0x2616,
+ 0x50e9, 0x0f89,
+ 0x50ea, 0x2619,
+ 0x50ec, 0x261d,
+ 0x50ed, 0x0f82,
+ 0x50ee, 0x0f7f,
+ 0x50ef, 0x261f,
+ 0x50f0, 0x261e,
+ 0x50f1, 0x0f87,
+ 0x50f3, 0x2617,
+ 0x50f4, 0x3ce9,
+ 0x50f5, 0x1105,
+ 0x50f6, 0x2883,
+ 0x50f8, 0x2880,
+ 0x50f9, 0x1106,
+ 0x50fb, 0x1104,
+ 0x50fc, 0x39d2,
+ 0x50fd, 0x2887,
+ 0x50fe, 0x2884,
+ 0x50ff, 0x287d,
+ 0x5100, 0x1103,
+ 0x5101, 0x4032,
+ 0x5102, 0x1107,
+ 0x5103, 0x287e,
+ 0x5104, 0x1102,
+ 0x5105, 0x110a,
+ 0x5106, 0x2881,
+ 0x5108, 0x1108,
+ 0x510a, 0x2888,
+ 0x510b, 0x2885,
+ 0x510d, 0x39c6,
+ 0x510e, 0x4034,
+ 0x5110, 0x128d,
+ 0x5111, 0x2b04,
+ 0x5112, 0x128a,
+ 0x5113, 0x2b01,
+ 0x5114, 0x128c,
+ 0x5115, 0x128e,
+ 0x5117, 0x2b02,
+ 0x5118, 0x128b,
+ 0x511a, 0x2b03,
+ 0x511c, 0x2b00,
+ 0x511f, 0x13b5,
+ 0x5120, 0x2d3e,
+ 0x5121, 0x13b6,
+ 0x5122, 0x2d3c,
+ 0x5124, 0x2d3d,
+ 0x5125, 0x2d3b,
+ 0x5126, 0x2d3a,
+ 0x5129, 0x2d3f,
+ 0x512a, 0x13b4,
+ 0x512b, 0x39ae,
+ 0x512d, 0x2f0f,
+ 0x5130, 0x287f,
+ 0x5131, 0x2f0e,
+ 0x5132, 0x13b7,
+ 0x5133, 0x1575,
+ 0x5134, 0x307a,
+ 0x5137, 0x1668,
+ 0x5139, 0x32c6,
+ 0x513a, 0x32c5,
+ 0x513b, 0x16bc,
+ 0x513c, 0x16bb,
+ 0x513d, 0x340e,
+ 0x513f, 0x025c,
+ 0x5140, 0x0274,
+ 0x5141, 0x02aa,
+ 0x5143, 0x02a9,
+ 0x5144, 0x0303,
+ 0x5145, 0x0302,
+ 0x5146, 0x038a,
+ 0x5147, 0x0389,
+ 0x5148, 0x038b,
+ 0x5149, 0x0388,
+ 0x514b, 0x0434,
+ 0x514c, 0x0433,
+ 0x514d, 0x0435,
+ 0x5152, 0x0545,
+ 0x5154, 0x0544,
+ 0x5155, 0x0546,
+ 0x5156, 0x439a,
+ 0x5157, 0x06bc,
+ 0x5159, 0x0119,
+ 0x515a, 0x1c32,
+ 0x515b, 0x011a,
+ 0x515c, 0x0a0f,
+ 0x515d, 0x011c,
+ 0x515e, 0x011b,
+ 0x515f, 0x20bd,
+ 0x5160, 0x403a,
+ 0x5161, 0x011d,
+ 0x5162, 0x0f8a,
+ 0x5163, 0x011e,
+ 0x5165, 0x025d,
+ 0x5167, 0x02ab,
+ 0x5168, 0x038c,
+ 0x5169, 0x0547,
+ 0x516a, 0x403c,
+ 0x516b, 0x025e,
+ 0x516c, 0x02ae,
+ 0x516d, 0x02ac,
+ 0x5171, 0x038d,
+ 0x5174, 0x453f,
+ 0x5175, 0x0436,
+ 0x5176, 0x0549,
+ 0x5177, 0x0548,
+ 0x5178, 0x054a,
+ 0x5179, 0x3ace,
+ 0x517c, 0x0852,
+ 0x5180, 0x128f,
+ 0x5182, 0x021d,
+ 0x5186, 0x439f,
+ 0x5187, 0x1779,
+ 0x5188, 0x36b6,
+ 0x5189, 0x0304,
+ 0x518d, 0x038e,
+ 0x518f, 0x1833,
+ 0x5191, 0x06be,
+ 0x5192, 0x06bd,
+ 0x5193, 0x1c34,
+ 0x5194, 0x1c33,
+ 0x5195, 0x0a10,
+ 0x5196, 0x021e,
+ 0x5197, 0x02af,
+ 0x5198, 0x1780,
+ 0x519a, 0x3ea3,
+ 0x519c, 0x4540,
+ 0x519e, 0x1910,
+ 0x51a0, 0x06bf,
+ 0x51a2, 0x0855,
+ 0x51a4, 0x0853,
+ 0x51a7, 0x3ea6,
+ 0x51a8, 0x39da,
+ 0x51aa, 0x1290,
+ 0x51ab, 0x021f,
+ 0x51ac, 0x0306,
+ 0x51b0, 0x038f,
+ 0x51b1, 0x17c6,
+ 0x51b2, 0x4048,
+ 0x51b3, 0x4051,
+ 0x51b4, 0x3d7c,
+ 0x51b5, 0x4012,
+ 0x51b6, 0x0437,
+ 0x51b8, 0x4049,
+ 0x51b9, 0x1834,
+ 0x51bc, 0x1911,
+ 0x51bd, 0x054b,
+ 0x51be, 0x1912,
+ 0x51c3, 0x39db,
+ 0x51c4, 0x1c36,
+ 0x51c6, 0x0858,
+ 0x51c7, 0x422a,
+ 0x51c8, 0x1c38,
+ 0x51c9, 0x404b,
+ 0x51ca, 0x1c35,
+ 0x51cb, 0x0859,
+ 0x51cc, 0x0857,
+ 0x51cd, 0x0856,
+ 0x51ce, 0x1c39,
+ 0x51cf, 0x404c,
+ 0x51d0, 0x1e52,
+ 0x51d1, 0x404d,
+ 0x51d2, 0x3dad,
+ 0x51d3, 0x404f,
+ 0x51d4, 0x20be,
+ 0x51d7, 0x2375,
+ 0x51d8, 0x2622,
+ 0x51db, 0x459a,
+ 0x51dc, 0x110b,
+ 0x51dd, 0x1291,
+ 0x51de, 0x2b05,
+ 0x51df, 0x424f,
+ 0x51e0, 0x025f,
+ 0x51e1, 0x026d,
+ 0x51e2, 0x4052,
+ 0x51e4, 0x4541,
+ 0x51ed, 0x4054,
+ 0x51f0, 0x0a11,
+ 0x51f1, 0x0bf1,
+ 0x51f3, 0x0f8b,
+ 0x51f4, 0x4178,
+ 0x51f5, 0x176e,
+ 0x51f6, 0x02b0,
+ 0x51f8, 0x0309,
+ 0x51f9, 0x0307,
+ 0x51fc, 0x459b,
+ 0x51fd, 0x054c,
+ 0x51fe, 0x3f0a,
+ 0x5200, 0x0260,
+ 0x5202, 0x36b3,
+ 0x5203, 0x0275,
+ 0x5205, 0x43a1,
+ 0x5206, 0x02b1,
+ 0x5209, 0x1797,
+ 0x520a, 0x030a,
+ 0x520b, 0x4059,
+ 0x520c, 0x1796,
+ 0x520e, 0x0393,
+ 0x5210, 0x17c8,
+ 0x5211, 0x0391,
+ 0x5213, 0x17c7,
+ 0x5216, 0x0394,
+ 0x5217, 0x0390,
+ 0x521c, 0x1835,
+ 0x521d, 0x068b,
+ 0x521e, 0x1836,
+ 0x521f, 0x3f60,
+ 0x5220, 0x4930,
+ 0x5221, 0x1837,
+ 0x5224, 0x043a,
+ 0x5225, 0x0439,
+ 0x5226, 0x405a,
+ 0x5227, 0x43a2,
+ 0x5228, 0x043d,
+ 0x5229, 0x043b,
+ 0x522e, 0x0552,
+ 0x5230, 0x0551,
+ 0x5231, 0x1917,
+ 0x5232, 0x1914,
+ 0x5234, 0x3efb,
+ 0x5235, 0x1913,
+ 0x5236, 0x0553,
+ 0x5237, 0x054f,
+ 0x5238, 0x054e,
+ 0x523a, 0x0550,
+ 0x523b, 0x054d,
+ 0x523c, 0x405b,
+ 0x5241, 0x0554,
+ 0x5243, 0x06c1,
+ 0x5244, 0x1a6d,
+ 0x5246, 0x1916,
+ 0x5247, 0x06c6,
+ 0x5249, 0x1a6e,
+ 0x524a, 0x06c2,
+ 0x524b, 0x06c5,
+ 0x524c, 0x06c4,
+ 0x524d, 0x06c3,
+ 0x524e, 0x06c0,
+ 0x5252, 0x1c3c,
+ 0x5254, 0x085c,
+ 0x5255, 0x1c3f,
+ 0x5256, 0x085a,
+ 0x5257, 0x405d,
+ 0x5259, 0x39e4,
+ 0x525a, 0x1c3b,
+ 0x525b, 0x085d,
+ 0x525c, 0x085b,
+ 0x525d, 0x085e,
+ 0x525e, 0x1c3d,
+ 0x5260, 0x3f29,
+ 0x5261, 0x1c3a,
+ 0x5262, 0x1c40,
+ 0x5268, 0x4619,
+ 0x5269, 0x0bf5,
+ 0x526a, 0x0a12,
+ 0x526b, 0x1e53,
+ 0x526c, 0x1e55,
+ 0x526d, 0x1e54,
+ 0x526e, 0x1e56,
+ 0x526f, 0x0a13,
+ 0x5272, 0x0bf2,
+ 0x5273, 0x3f43,
+ 0x5274, 0x0bf3,
+ 0x5277, 0x0dcb,
+ 0x5278, 0x2377,
+ 0x5279, 0x43a3,
+ 0x527a, 0x2376,
+ 0x527b, 0x2378,
+ 0x527d, 0x0dcc,
+ 0x527f, 0x0dca,
+ 0x5280, 0x2623,
+ 0x5282, 0x0f8d,
+ 0x5283, 0x0f8c,
+ 0x5284, 0x2776,
+ 0x5287, 0x110c,
+ 0x528a, 0x1110,
+ 0x528b, 0x2889,
+ 0x528d, 0x110f,
+ 0x528f, 0x3dbf,
+ 0x5290, 0x459d,
+ 0x5291, 0x1292,
+ 0x5293, 0x1293,
+ 0x5294, 0x405e,
+ 0x5296, 0x307c,
+ 0x5297, 0x32c8,
+ 0x5298, 0x32c7,
+ 0x5299, 0x340f,
+ 0x529a, 0x3f68,
+ 0x529b, 0x0262,
+ 0x529f, 0x030c,
+ 0x52a0, 0x030b,
+ 0x52a1, 0x4542,
+ 0x52a3, 0x0395,
+ 0x52a4, 0x39e5,
+ 0x52a6, 0x17c9,
+ 0x52a8, 0x4543,
+ 0x52a9, 0x043f,
+ 0x52ab, 0x043e,
+ 0x52ac, 0x0441,
+ 0x52ad, 0x1838,
+ 0x52b5, 0x405c,
+ 0x52b9, 0x405f,
+ 0x52bb, 0x0556,
+ 0x52bc, 0x1918,
+ 0x52be, 0x0555,
+ 0x52c0, 0x1a6f,
+ 0x52c1, 0x06ca,
+ 0x52c2, 0x1a70,
+ 0x52c3, 0x06c9,
+ 0x52c5, 0x4060,
+ 0x52c7, 0x06c7,
+ 0x52c9, 0x06c8,
+ 0x52cc, 0x3ee1,
+ 0x52cd, 0x1c41,
+ 0x52d0, 0x4109,
+ 0x52d1, 0x3f2a,
+ 0x52d2, 0x0a14,
+ 0x52d3, 0x1e58,
+ 0x52d5, 0x0a17,
+ 0x52d6, 0x1e57,
+ 0x52d7, 0x0acf,
+ 0x52d8, 0x0a16,
+ 0x52d9, 0x0a15,
+ 0x52db, 0x0bf8,
+ 0x52dd, 0x0bf7,
+ 0x52de, 0x0bf6,
+ 0x52df, 0x0dcd,
+ 0x52e0, 0x4063,
+ 0x52e1, 0x39e7,
+ 0x52e2, 0x0dd0,
+ 0x52e4, 0x0dcf,
+ 0x52e6, 0x0dce,
+ 0x52e9, 0x2625,
+ 0x52eb, 0x2626,
+ 0x52ef, 0x288c,
+ 0x52f0, 0x1111,
+ 0x52f1, 0x288b,
+ 0x52f3, 0x1294,
+ 0x52f4, 0x2d40,
+ 0x52f5, 0x13b8,
+ 0x52f7, 0x307d,
+ 0x52f8, 0x1609,
+ 0x52f9, 0x0220,
+ 0x52fa, 0x0276,
+ 0x52fb, 0x02b4,
+ 0x52fc, 0x1781,
+ 0x52fe, 0x02b5,
+ 0x5301, 0x3d79,
+ 0x5305, 0x030d,
+ 0x5308, 0x0396,
+ 0x5309, 0x183a,
+ 0x530a, 0x1919,
+ 0x530d, 0x06cb,
+ 0x530e, 0x1c42,
+ 0x530f, 0x0a19,
+ 0x5310, 0x0a18,
+ 0x5311, 0x20c0,
+ 0x5312, 0x20bf,
+ 0x5315, 0x0263,
+ 0x5316, 0x02b7,
+ 0x5317, 0x030f,
+ 0x5319, 0x0a1a,
+ 0x531a, 0x176f,
+ 0x531c, 0x1798,
+ 0x531d, 0x0310,
+ 0x531f, 0x17cb,
+ 0x5320, 0x0398,
+ 0x5321, 0x0397,
+ 0x5322, 0x17ca,
+ 0x5323, 0x0442,
+ 0x5327, 0x459e,
+ 0x532a, 0x085f,
+ 0x532c, 0x3f36,
+ 0x532d, 0x1e59,
+ 0x532f, 0x0dd2,
+ 0x5330, 0x2627,
+ 0x5331, 0x0f8e,
+ 0x5332, 0x3fd0,
+ 0x5333, 0x406d,
+ 0x5334, 0x2b06,
+ 0x5337, 0x31c7,
+ 0x5338, 0x0221,
+ 0x5339, 0x02b8,
+ 0x533b, 0x4544,
+ 0x533c, 0x191b,
+ 0x533d, 0x1a71,
+ 0x533e, 0x0a1d,
+ 0x533f, 0x0a1b,
+ 0x5341, 0x0264,
+ 0x5342, 0x4947,
+ 0x5343, 0x0277,
+ 0x5344, 0x016b,
+ 0x5345, 0x02bb,
+ 0x5347, 0x02ba,
+ 0x5348, 0x02b9,
+ 0x5349, 0x0313,
+ 0x534a, 0x0312,
+ 0x534c, 0x1799,
+ 0x534d, 0x17cc,
+ 0x534e, 0x4545,
+ 0x5351, 0x055a,
+ 0x5352, 0x0557,
+ 0x5353, 0x0559,
+ 0x5354, 0x0558,
+ 0x5357, 0x06cc,
+ 0x535a, 0x0bf9,
+ 0x535c, 0x0265,
+ 0x535d, 0x4501,
+ 0x535e, 0x02bc,
+ 0x535f, 0x43a7,
+ 0x5360, 0x0315,
+ 0x5361, 0x0314,
+ 0x5363, 0x183b,
+ 0x5364, 0x480a,
+ 0x5366, 0x055b,
+ 0x5367, 0x3ecd,
+ 0x5369, 0x0222,
+ 0x536c, 0x1782,
+ 0x536d, 0x407a,
+ 0x536e, 0x0317,
+ 0x536f, 0x0316,
+ 0x5370, 0x0399,
+ 0x5372, 0x183c,
+ 0x5373, 0x0443,
+ 0x5374, 0x407b,
+ 0x5375, 0x0444,
+ 0x5377, 0x055c,
+ 0x537b, 0x06cd,
+ 0x537c, 0x1a72,
+ 0x537d, 0x4901,
+ 0x537e, 0x407d,
+ 0x537f, 0x0860,
+ 0x5382, 0x1770,
+ 0x5384, 0x02bd,
+ 0x538a, 0x17cd,
+ 0x538e, 0x183d,
+ 0x5392, 0x191c,
+ 0x5393, 0x4082,
+ 0x5394, 0x191d,
+ 0x5396, 0x1a74,
+ 0x5397, 0x1a73,
+ 0x5398, 0x1a76,
+ 0x5399, 0x1a75,
+ 0x539a, 0x06ce,
+ 0x539c, 0x1e5a,
+ 0x539d, 0x0862,
+ 0x539e, 0x1c43,
+ 0x539f, 0x0861,
+ 0x53a0, 0x4084,
+ 0x53a2, 0x3e2b,
+ 0x53a4, 0x20c1,
+ 0x53a5, 0x0bfa,
+ 0x53a6, 0x413b,
+ 0x53a7, 0x20c2,
+ 0x53a8, 0x413e,
+ 0x53a9, 0x45a0,
+ 0x53aa, 0x3fc6,
+ 0x53ab, 0x4085,
+ 0x53ac, 0x2628,
+ 0x53ad, 0x0f8f,
+ 0x53ae, 0x4086,
+ 0x53b0, 0x45a2,
+ 0x53b2, 0x1112,
+ 0x53b4, 0x307e,
+ 0x53b6, 0x0223,
+ 0x53b9, 0x1783,
+ 0x53bb, 0x0318,
+ 0x53c1, 0x408b,
+ 0x53c2, 0x43a6,
+ 0x53c3, 0x0a1e,
+ 0x53c5, 0x408c,
+ 0x53c8, 0x0266,
+ 0x53c9, 0x0278,
+ 0x53ca, 0x02bf,
+ 0x53cb, 0x02be,
+ 0x53cc, 0x38b6,
+ 0x53cd, 0x02c0,
+ 0x53d0, 0x39fa,
+ 0x53d1, 0x4546,
+ 0x53d2, 0x3e3d,
+ 0x53d4, 0x0560,
+ 0x53d6, 0x055f,
+ 0x53d7, 0x0561,
+ 0x53d8, 0x4547,
+ 0x53d9, 0x4090,
+ 0x53da, 0x3f39,
+ 0x53db, 0x06cf,
+ 0x53df, 0x0863,
+ 0x53e0, 0x4093,
+ 0x53e1, 0x2b07,
+ 0x53e2, 0x14c9,
+ 0x53e3, 0x0279,
+ 0x53e4, 0x031a,
+ 0x53e5, 0x0329,
+ 0x53e6, 0x0324,
+ 0x53e8, 0x031f,
+ 0x53e9, 0x031e,
+ 0x53ea, 0x0325,
+ 0x53eb, 0x0323,
+ 0x53ec, 0x031c,
+ 0x53ed, 0x032a,
+ 0x53ee, 0x031d,
+ 0x53ef, 0x0319,
+ 0x53f0, 0x0328,
+ 0x53f1, 0x0327,
+ 0x53f2, 0x0326,
+ 0x53f3, 0x031b,
+ 0x53f5, 0x0322,
+ 0x53f6, 0x4096,
+ 0x53f7, 0x3808,
+ 0x53f8, 0x0321,
+ 0x53fb, 0x032b,
+ 0x53fc, 0x0320,
+ 0x53fe, 0x40c1,
+ 0x5401, 0x03a0,
+ 0x5403, 0x03a6,
+ 0x5404, 0x03a2,
+ 0x5406, 0x03a8,
+ 0x5407, 0x17ce,
+ 0x5408, 0x03a5,
+ 0x5409, 0x039b,
+ 0x540a, 0x039e,
+ 0x540b, 0x03a1,
+ 0x540c, 0x039d,
+ 0x540d, 0x03a4,
+ 0x540e, 0x03a7,
+ 0x540f, 0x039c,
+ 0x5410, 0x039f,
+ 0x5411, 0x03a3,
+ 0x5412, 0x03a9,
+ 0x5413, 0x4098,
+ 0x5414, 0x3c77,
+ 0x5416, 0x3e7f,
+ 0x5418, 0x1847,
+ 0x5419, 0x1844,
+ 0x541a, 0x3e64,
+ 0x541b, 0x0451,
+ 0x541c, 0x1845,
+ 0x541d, 0x0445,
+ 0x541e, 0x0447,
+ 0x541f, 0x045f,
+ 0x5420, 0x045a,
+ 0x5421, 0x4203,
+ 0x5423, 0x45a3,
+ 0x5424, 0x184c,
+ 0x5425, 0x1846,
+ 0x5426, 0x0449,
+ 0x5427, 0x044b,
+ 0x5428, 0x184b,
+ 0x5429, 0x0452,
+ 0x542a, 0x1841,
+ 0x542b, 0x045e,
+ 0x542c, 0x0460,
+ 0x542d, 0x0446,
+ 0x542e, 0x0457,
+ 0x542f, 0x40ac,
+ 0x5430, 0x183f,
+ 0x5431, 0x045d,
+ 0x5432, 0x3e75,
+ 0x5433, 0x044e,
+ 0x5435, 0x0458,
+ 0x5437, 0x1840,
+ 0x5438, 0x0456,
+ 0x5439, 0x0454,
+ 0x543b, 0x0455,
+ 0x543c, 0x045b,
+ 0x543d, 0x1848,
+ 0x543e, 0x0448,
+ 0x5440, 0x045c,
+ 0x5441, 0x184a,
+ 0x5442, 0x0450,
+ 0x5443, 0x044d,
+ 0x5445, 0x1843,
+ 0x5446, 0x044c,
+ 0x5447, 0x184d,
+ 0x5448, 0x044f,
+ 0x544a, 0x0453,
+ 0x544b, 0x3ed1,
+ 0x544d, 0x3ea7,
+ 0x544e, 0x044a,
+ 0x544f, 0x1849,
+ 0x5454, 0x1842,
+ 0x5460, 0x192e,
+ 0x5461, 0x192d,
+ 0x5462, 0x0573,
+ 0x5463, 0x1930,
+ 0x5464, 0x1932,
+ 0x5465, 0x1927,
+ 0x5466, 0x192a,
+ 0x5467, 0x1931,
+ 0x5468, 0x0574,
+ 0x5469, 0x3f32,
+ 0x546a, 0x3d83,
+ 0x546b, 0x1924,
+ 0x546c, 0x1928,
+ 0x546d, 0x409d,
+ 0x546f, 0x192c,
+ 0x5470, 0x1a85,
+ 0x5471, 0x056f,
+ 0x5472, 0x1a89,
+ 0x5473, 0x0562,
+ 0x5474, 0x1929,
+ 0x5475, 0x0563,
+ 0x5476, 0x0570,
+ 0x5477, 0x0569,
+ 0x5478, 0x0565,
+ 0x547a, 0x1925,
+ 0x547b, 0x0568,
+ 0x547c, 0x056d,
+ 0x547d, 0x0576,
+ 0x547e, 0x1926,
+ 0x547f, 0x191f,
+ 0x5480, 0x0567,
+ 0x5481, 0x1920,
+ 0x5482, 0x1922,
+ 0x5484, 0x056a,
+ 0x5485, 0x46d9,
+ 0x5486, 0x056c,
+ 0x5487, 0x191e,
+ 0x5488, 0x1923,
+ 0x548b, 0x0575,
+ 0x548c, 0x0571,
+ 0x548d, 0x192b,
+ 0x548e, 0x0577,
+ 0x548f, 0x40a1,
+ 0x5490, 0x056e,
+ 0x5491, 0x1921,
+ 0x5492, 0x056b,
+ 0x5493, 0x45a7,
+ 0x5494, 0x3e98,
+ 0x5495, 0x0566,
+ 0x5496, 0x0564,
+ 0x5497, 0x3e8a,
+ 0x5498, 0x192f,
+ 0x549a, 0x0572,
+ 0x549c, 0x3f66,
+ 0x549e, 0x47ed,
+ 0x54a0, 0x1a84,
+ 0x54a1, 0x1a78,
+ 0x54a2, 0x1a87,
+ 0x54a3, 0x45a8,
+ 0x54a4, 0x40a2,
+ 0x54a5, 0x1a7a,
+ 0x54a6, 0x06d6,
+ 0x54a7, 0x06e4,
+ 0x54a8, 0x06d2,
+ 0x54a9, 0x06e3,
+ 0x54aa, 0x06db,
+ 0x54ab, 0x06e0,
+ 0x54ac, 0x06d0,
+ 0x54ad, 0x1a79,
+ 0x54ae, 0x1a7f,
+ 0x54af, 0x06df,
+ 0x54b0, 0x1a8b,
+ 0x54b1, 0x06e1,
+ 0x54b2, 0x3744,
+ 0x54b3, 0x06d7,
+ 0x54b4, 0x45a9,
+ 0x54b6, 0x1a81,
+ 0x54b7, 0x1a7e,
+ 0x54b8, 0x06d5,
+ 0x54b9, 0x45aa,
+ 0x54ba, 0x1a77,
+ 0x54bb, 0x06e2,
+ 0x54bc, 0x1a86,
+ 0x54bd, 0x06da,
+ 0x54be, 0x1a88,
+ 0x54bf, 0x06e5,
+ 0x54c0, 0x06d1,
+ 0x54c1, 0x06dc,
+ 0x54c2, 0x06d9,
+ 0x54c3, 0x1a7c,
+ 0x54c4, 0x06dd,
+ 0x54c5, 0x1a82,
+ 0x54c7, 0x06d8,
+ 0x54c8, 0x06de,
+ 0x54c9, 0x06d4,
+ 0x54cb, 0x39a3,
+ 0x54cc, 0x43a8,
+ 0x54cd, 0x3a00,
+ 0x54ce, 0x06d3,
+ 0x54cf, 0x1a7b,
+ 0x54d0, 0x45ab,
+ 0x54d6, 0x1a80,
+ 0x54da, 0x4923,
+ 0x54de, 0x1a8a,
+ 0x54e0, 0x1c57,
+ 0x54e1, 0x0870,
+ 0x54e2, 0x1c45,
+ 0x54e3, 0x4341,
+ 0x54e4, 0x1c4a,
+ 0x54e5, 0x0869,
+ 0x54e6, 0x0874,
+ 0x54e7, 0x1c48,
+ 0x54e8, 0x0864,
+ 0x54e9, 0x086e,
+ 0x54ea, 0x0873,
+ 0x54eb, 0x1c4f,
+ 0x54ed, 0x086f,
+ 0x54ee, 0x0872,
+ 0x54ef, 0x45ac,
+ 0x54f1, 0x1c52,
+ 0x54f2, 0x086a,
+ 0x54f3, 0x1c49,
+ 0x54f7, 0x1c55,
+ 0x54fa, 0x086c,
+ 0x54fb, 0x1c54,
+ 0x54fc, 0x0868,
+ 0x54fd, 0x0877,
+ 0x54ff, 0x1c4c,
+ 0x5501, 0x0866,
+ 0x5502, 0x3ccc,
+ 0x5503, 0x1c59,
+ 0x5504, 0x1c4d,
+ 0x5505, 0x1c51,
+ 0x5506, 0x086b,
+ 0x5507, 0x0876,
+ 0x5508, 0x1c4e,
+ 0x5509, 0x0871,
+ 0x550a, 0x1c53,
+ 0x550b, 0x1c5a,
+ 0x550c, 0x1e69,
+ 0x550d, 0x3a73,
+ 0x550e, 0x1c58,
+ 0x550f, 0x0878,
+ 0x5510, 0x0865,
+ 0x5511, 0x1c50,
+ 0x5512, 0x1c47,
+ 0x5513, 0x3ea9,
+ 0x5514, 0x086d,
+ 0x5517, 0x1c46,
+ 0x5518, 0x45ad,
+ 0x551a, 0x1c4b,
+ 0x551e, 0x3ea8,
+ 0x5523, 0x45ae,
+ 0x5525, 0x4309,
+ 0x5526, 0x1c44,
+ 0x5527, 0x0875,
+ 0x5528, 0x45af,
+ 0x552a, 0x1e61,
+ 0x552b, 0x409a,
+ 0x552c, 0x0a31,
+ 0x552d, 0x1e6f,
+ 0x552e, 0x0a2f,
+ 0x552f, 0x0a2c,
+ 0x5530, 0x1e66,
+ 0x5531, 0x0a28,
+ 0x5532, 0x1e6a,
+ 0x5533, 0x0a33,
+ 0x5534, 0x1e60,
+ 0x5535, 0x1e65,
+ 0x5536, 0x1e64,
+ 0x5537, 0x0867,
+ 0x5538, 0x0a2e,
+ 0x5539, 0x1e6d,
+ 0x553b, 0x1e70,
+ 0x553c, 0x1e5d,
+ 0x553e, 0x0c0c,
+ 0x553f, 0x43a9,
+ 0x5540, 0x1e71,
+ 0x5541, 0x0a34,
+ 0x5543, 0x0a26,
+ 0x5544, 0x0a23,
+ 0x5545, 0x1e68,
+ 0x5546, 0x0a20,
+ 0x5547, 0x40aa,
+ 0x5548, 0x1e6e,
+ 0x5549, 0x4068,
+ 0x554a, 0x0a27,
+ 0x554b, 0x1e72,
+ 0x554d, 0x1e5e,
+ 0x554e, 0x1e6c,
+ 0x554f, 0x0a2a,
+ 0x5550, 0x1e5f,
+ 0x5551, 0x1e62,
+ 0x5552, 0x1e67,
+ 0x5553, 0x43ae,
+ 0x5555, 0x0a2b,
+ 0x5556, 0x0a29,
+ 0x5557, 0x0a35,
+ 0x555c, 0x0a30,
+ 0x555d, 0x40a0,
+ 0x555e, 0x0a24,
+ 0x555f, 0x0abc,
+ 0x5561, 0x0a25,
+ 0x5562, 0x1e63,
+ 0x5563, 0x0a32,
+ 0x5564, 0x0a2d,
+ 0x5565, 0x1e6b,
+ 0x5566, 0x0a22,
+ 0x5569, 0x3e9f,
+ 0x556a, 0x0a21,
+ 0x556b, 0x3b2e,
+ 0x5571, 0x3bc6,
+ 0x5572, 0x3e8b,
+ 0x5573, 0x3f24,
+ 0x5575, 0x1e5b,
+ 0x5577, 0x20c7,
+ 0x5579, 0x435d,
+ 0x557b, 0x0bfb,
+ 0x557c, 0x0bfe,
+ 0x557d, 0x20d2,
+ 0x557e, 0x0c12,
+ 0x557f, 0x20d5,
+ 0x5580, 0x0bfc,
+ 0x5581, 0x20ce,
+ 0x5582, 0x0c02,
+ 0x5583, 0x0c08,
+ 0x5584, 0x0d1b,
+ 0x5586, 0x40ae,
+ 0x5587, 0x0c06,
+ 0x5588, 0x20cb,
+ 0x5589, 0x0c13,
+ 0x558a, 0x0bff,
+ 0x558b, 0x0c07,
+ 0x558c, 0x20d3,
+ 0x558d, 0x2387,
+ 0x558e, 0x20d8,
+ 0x558f, 0x20cc,
+ 0x5590, 0x430e,
+ 0x5591, 0x20c3,
+ 0x5592, 0x20d0,
+ 0x5593, 0x20ca,
+ 0x5594, 0x0c05,
+ 0x5595, 0x20d6,
+ 0x5598, 0x0c01,
+ 0x5599, 0x0c15,
+ 0x559a, 0x0c0e,
+ 0x559c, 0x0c03,
+ 0x559d, 0x0c00,
+ 0x559f, 0x0c0b,
+ 0x55a1, 0x20d7,
+ 0x55a2, 0x20c9,
+ 0x55a3, 0x20cf,
+ 0x55a4, 0x20d1,
+ 0x55a5, 0x20c5,
+ 0x55a6, 0x20d4,
+ 0x55a7, 0x0bfd,
+ 0x55a8, 0x20c4,
+ 0x55a9, 0x40af,
+ 0x55aa, 0x0c04,
+ 0x55ab, 0x0c14,
+ 0x55ac, 0x0c10,
+ 0x55ad, 0x20c6,
+ 0x55ae, 0x0c0a,
+ 0x55b0, 0x38f5,
+ 0x55b1, 0x0c11,
+ 0x55b2, 0x0c0d,
+ 0x55b3, 0x0c09,
+ 0x55b4, 0x39fe,
+ 0x55b5, 0x20cd,
+ 0x55b9, 0x43aa,
+ 0x55ba, 0x3e89,
+ 0x55bb, 0x0c0f,
+ 0x55bc, 0x3dc3,
+ 0x55bf, 0x2385,
+ 0x55c0, 0x2381,
+ 0x55c1, 0x3e4f,
+ 0x55c2, 0x2390,
+ 0x55c3, 0x237a,
+ 0x55c4, 0x2383,
+ 0x55c5, 0x0de0,
+ 0x55c7, 0x0dd9,
+ 0x55c8, 0x238c,
+ 0x55c9, 0x0de3,
+ 0x55ca, 0x237f,
+ 0x55cb, 0x237e,
+ 0x55cc, 0x237c,
+ 0x55cd, 0x238e,
+ 0x55ce, 0x0dd7,
+ 0x55cf, 0x2388,
+ 0x55d0, 0x237d,
+ 0x55d1, 0x0dda,
+ 0x55d2, 0x2386,
+ 0x55d3, 0x0dd5,
+ 0x55d4, 0x2382,
+ 0x55d5, 0x2389,
+ 0x55d6, 0x238b,
+ 0x55d7, 0x45b3,
+ 0x55d8, 0x43ab,
+ 0x55d9, 0x238f,
+ 0x55da, 0x0dde,
+ 0x55db, 0x237b,
+ 0x55dc, 0x0dd8,
+ 0x55dd, 0x2380,
+ 0x55de, 0x3e94,
+ 0x55df, 0x0dd3,
+ 0x55e1, 0x0ddf,
+ 0x55e2, 0x238a,
+ 0x55e3, 0x0ddb,
+ 0x55e5, 0x0de2,
+ 0x55e6, 0x0dd6,
+ 0x55e7, 0x011f,
+ 0x55e8, 0x0dd4,
+ 0x55e9, 0x2384,
+ 0x55ea, 0x3e7c,
+ 0x55ec, 0x37d2,
+ 0x55ef, 0x0ddd,
+ 0x55f0, 0x3e88,
+ 0x55f1, 0x3e83,
+ 0x55f2, 0x238d,
+ 0x55f5, 0x4786,
+ 0x55f6, 0x0f9f,
+ 0x55f7, 0x0f9a,
+ 0x55f9, 0x2637,
+ 0x55fa, 0x2633,
+ 0x55fb, 0x4626,
+ 0x55fc, 0x262d,
+ 0x55fd, 0x0f94,
+ 0x55fe, 0x0f90,
+ 0x55ff, 0x2636,
+ 0x5600, 0x0f91,
+ 0x5601, 0x2630,
+ 0x5602, 0x2632,
+ 0x5604, 0x2635,
+ 0x5605, 0x3e82,
+ 0x5606, 0x0f96,
+ 0x5608, 0x0f9d,
+ 0x5609, 0x0f97,
+ 0x560c, 0x262b,
+ 0x560d, 0x0f98,
+ 0x560f, 0x262e,
+ 0x5610, 0x0f9e,
+ 0x5611, 0x3f4d,
+ 0x5612, 0x262c,
+ 0x5613, 0x2631,
+ 0x5614, 0x0f95,
+ 0x5615, 0x262a,
+ 0x5616, 0x0f9b,
+ 0x5617, 0x0f93,
+ 0x561b, 0x0f92,
+ 0x561c, 0x262f,
+ 0x561d, 0x2634,
+ 0x561e, 0x3e68,
+ 0x561f, 0x0f9c,
+ 0x5620, 0x3f7d,
+ 0x5621, 0x43ad,
+ 0x5622, 0x3e67,
+ 0x5623, 0x4707,
+ 0x5625, 0x3e78,
+ 0x5627, 0x2629,
+ 0x5629, 0x1119,
+ 0x562a, 0x289d,
+ 0x562c, 0x289a,
+ 0x562d, 0x3e63,
+ 0x562e, 0x1113,
+ 0x562f, 0x111f,
+ 0x5632, 0x1116,
+ 0x5633, 0x2898,
+ 0x5634, 0x1118,
+ 0x5635, 0x2890,
+ 0x5636, 0x111e,
+ 0x5637, 0x40b7,
+ 0x5638, 0x289c,
+ 0x5639, 0x1115,
+ 0x563a, 0x289e,
+ 0x563b, 0x1114,
+ 0x563d, 0x2899,
+ 0x563e, 0x289b,
+ 0x563f, 0x1117,
+ 0x5640, 0x2897,
+ 0x5641, 0x2891,
+ 0x5642, 0x288e,
+ 0x5643, 0x3e7e,
+ 0x5645, 0x20c8,
+ 0x5646, 0x2894,
+ 0x5648, 0x288d,
+ 0x5649, 0x2893,
+ 0x564a, 0x2892,
+ 0x564c, 0x288f,
+ 0x564d, 0x40bc,
+ 0x564e, 0x111b,
+ 0x564f, 0x40bd,
+ 0x5650, 0x47cf,
+ 0x5652, 0x45c2,
+ 0x5653, 0x111a,
+ 0x5654, 0x43af,
+ 0x5657, 0x111c,
+ 0x5658, 0x2895,
+ 0x5659, 0x1295,
+ 0x565a, 0x2896,
+ 0x565d, 0x3ef9,
+ 0x565e, 0x2b10,
+ 0x5660, 0x2b09,
+ 0x5661, 0x3812,
+ 0x5662, 0x12a1,
+ 0x5663, 0x2b0d,
+ 0x5664, 0x1299,
+ 0x5665, 0x129d,
+ 0x5666, 0x2b0c,
+ 0x5668, 0x129c,
+ 0x5669, 0x1298,
+ 0x566a, 0x129b,
+ 0x566b, 0x1296,
+ 0x566c, 0x12a0,
+ 0x566d, 0x2b0e,
+ 0x566e, 0x2b0a,
+ 0x566f, 0x129f,
+ 0x5670, 0x2b08,
+ 0x5671, 0x129e,
+ 0x5672, 0x2b0f,
+ 0x5673, 0x2b0b,
+ 0x5674, 0x111d,
+ 0x5676, 0x12a2,
+ 0x5677, 0x2b11,
+ 0x5678, 0x129a,
+ 0x5679, 0x1297,
+ 0x567a, 0x3d85,
+ 0x567b, 0x3eb7,
+ 0x567c, 0x3eed,
+ 0x567e, 0x2d47,
+ 0x567f, 0x2d49,
+ 0x5680, 0x13ba,
+ 0x5681, 0x2d4a,
+ 0x5682, 0x2d48,
+ 0x5683, 0x2d46,
+ 0x5684, 0x2d45,
+ 0x5685, 0x13bc,
+ 0x5686, 0x2d44,
+ 0x5687, 0x13bd,
+ 0x5689, 0x4628,
+ 0x568a, 0x3949,
+ 0x568b, 0x3e4c,
+ 0x568c, 0x2d42,
+ 0x568e, 0x13b9,
+ 0x568f, 0x13be,
+ 0x5690, 0x13bb,
+ 0x5692, 0x39a6,
+ 0x5693, 0x2d41,
+ 0x5695, 0x14ca,
+ 0x5697, 0x2f13,
+ 0x5698, 0x2f11,
+ 0x5699, 0x2f16,
+ 0x569a, 0x2f14,
+ 0x569c, 0x2f12,
+ 0x569d, 0x2f15,
+ 0x569e, 0x39a4,
+ 0x569f, 0x3948,
+ 0x56a1, 0x436b,
+ 0x56a4, 0x3cc8,
+ 0x56a5, 0x1576,
+ 0x56a6, 0x3081,
+ 0x56a8, 0x1577,
+ 0x56aa, 0x3083,
+ 0x56ab, 0x307f,
+ 0x56ac, 0x3084,
+ 0x56ad, 0x3080,
+ 0x56ae, 0x14cb,
+ 0x56af, 0x45f7,
+ 0x56b1, 0x463f,
+ 0x56b2, 0x31c8,
+ 0x56b3, 0x31ca,
+ 0x56b4, 0x160c,
+ 0x56b5, 0x31c9,
+ 0x56b6, 0x160b,
+ 0x56b7, 0x160a,
+ 0x56b9, 0x486f,
+ 0x56bc, 0x160d,
+ 0x56bd, 0x32ca,
+ 0x56bf, 0x3e5d,
+ 0x56c0, 0x166b,
+ 0x56c1, 0x166a,
+ 0x56c2, 0x166c,
+ 0x56c3, 0x32c9,
+ 0x56c5, 0x3379,
+ 0x56c6, 0x3378,
+ 0x56c8, 0x16bd,
+ 0x56c9, 0x16bf,
+ 0x56ca, 0x16be,
+ 0x56cb, 0x337a,
+ 0x56cc, 0x16f6,
+ 0x56cd, 0x3481,
+ 0x56d1, 0x171f,
+ 0x56d3, 0x3480,
+ 0x56d4, 0x34c9,
+ 0x56d6, 0x488a,
+ 0x56d7, 0x1775,
+ 0x56da, 0x032d,
+ 0x56db, 0x032c,
+ 0x56dd, 0x03ac,
+ 0x56de, 0x03ab,
+ 0x56df, 0x17d0,
+ 0x56e0, 0x03aa,
+ 0x56e1, 0x17cf,
+ 0x56e2, 0x4548,
+ 0x56e4, 0x0463,
+ 0x56e5, 0x1850,
+ 0x56e7, 0x184f,
+ 0x56ea, 0x0461,
+ 0x56eb, 0x0464,
+ 0x56ed, 0x40c4,
+ 0x56ee, 0x184e,
+ 0x56ef, 0x40c3,
+ 0x56f0, 0x0462,
+ 0x56f1, 0x40bf,
+ 0x56f7, 0x1933,
+ 0x56f9, 0x1934,
+ 0x56fa, 0x0578,
+ 0x56fd, 0x3d64,
+ 0x56ff, 0x06e6,
+ 0x5700, 0x40c2,
+ 0x5701, 0x1c5b,
+ 0x5703, 0x0879,
+ 0x5707, 0x1e74,
+ 0x5708, 0x0a36,
+ 0x5709, 0x0a38,
+ 0x570a, 0x1e73,
+ 0x570b, 0x0a37,
+ 0x570c, 0x20d9,
+ 0x570d, 0x0c16,
+ 0x5712, 0x0de4,
+ 0x5714, 0x2391,
+ 0x5715, 0x3e36,
+ 0x5716, 0x0fa1,
+ 0x5718, 0x0fa0,
+ 0x571a, 0x289f,
+ 0x571b, 0x2b13,
+ 0x571c, 0x2b12,
+ 0x571d, 0x3a02,
+ 0x571e, 0x3505,
+ 0x571f, 0x027a,
+ 0x5720, 0x1784,
+ 0x5722, 0x179a,
+ 0x5728, 0x03af,
+ 0x5729, 0x03b3,
+ 0x572a, 0x17d2,
+ 0x572c, 0x03b1,
+ 0x572d, 0x03b0,
+ 0x572e, 0x17d1,
+ 0x572f, 0x03b2,
+ 0x5730, 0x03ae,
+ 0x5732, 0x3af9,
+ 0x5733, 0x03ad,
+ 0x5734, 0x17d3,
+ 0x573b, 0x046e,
+ 0x573e, 0x046b,
+ 0x573f, 0x4855,
+ 0x5740, 0x0467,
+ 0x5741, 0x1851,
+ 0x5742, 0x40cc,
+ 0x5743, 0x40de,
+ 0x5745, 0x1852,
+ 0x5746, 0x40c8,
+ 0x5747, 0x0469,
+ 0x5749, 0x1854,
+ 0x574a, 0x0465,
+ 0x574b, 0x1855,
+ 0x574c, 0x1853,
+ 0x574d, 0x0468,
+ 0x574e, 0x046a,
+ 0x574f, 0x046d,
+ 0x5750, 0x046c,
+ 0x5751, 0x0466,
+ 0x5752, 0x1856,
+ 0x5754, 0x4785,
+ 0x5757, 0x47e6,
+ 0x575b, 0x3982,
+ 0x575f, 0x3fbf,
+ 0x5761, 0x057d,
+ 0x5762, 0x1941,
+ 0x5764, 0x057f,
+ 0x5766, 0x057e,
+ 0x5767, 0x3f2b,
+ 0x5768, 0x1942,
+ 0x5769, 0x057c,
+ 0x576a, 0x057b,
+ 0x576b, 0x1938,
+ 0x576d, 0x1937,
+ 0x576f, 0x1935,
+ 0x5770, 0x193a,
+ 0x5771, 0x1939,
+ 0x5772, 0x1936,
+ 0x5773, 0x193f,
+ 0x5775, 0x193d,
+ 0x5776, 0x193b,
+ 0x5777, 0x057a,
+ 0x577a, 0x3f5f,
+ 0x577b, 0x193e,
+ 0x577c, 0x0580,
+ 0x577d, 0x1943,
+ 0x577e, 0x46dc,
+ 0x577f, 0x3a07,
+ 0x5780, 0x193c,
+ 0x5782, 0x06e7,
+ 0x5783, 0x0579,
+ 0x5788, 0x484b,
+ 0x578a, 0x3c7b,
+ 0x578b, 0x06e8,
+ 0x578c, 0x1a90,
+ 0x578d, 0x3a06,
+ 0x578f, 0x1a96,
+ 0x5790, 0x4166,
+ 0x5793, 0x06ee,
+ 0x5794, 0x1a94,
+ 0x5795, 0x1a9a,
+ 0x5797, 0x1a91,
+ 0x5798, 0x1a95,
+ 0x5799, 0x1a97,
+ 0x579a, 0x1a99,
+ 0x579b, 0x1a93,
+ 0x579c, 0x4608,
+ 0x579d, 0x1a92,
+ 0x579e, 0x1a8d,
+ 0x57a0, 0x06e9,
+ 0x57a1, 0x4864,
+ 0x57a2, 0x06eb,
+ 0x57a3, 0x06ea,
+ 0x57a4, 0x1a8f,
+ 0x57a5, 0x1a98,
+ 0x57a7, 0x4914,
+ 0x57aa, 0x4905,
+ 0x57ae, 0x06ed,
+ 0x57b4, 0x4741,
+ 0x57b5, 0x1a8c,
+ 0x57b6, 0x1c66,
+ 0x57b8, 0x1c65,
+ 0x57b9, 0x1c6a,
+ 0x57ba, 0x1c61,
+ 0x57bb, 0x3c79,
+ 0x57bc, 0x1c64,
+ 0x57bd, 0x1c63,
+ 0x57be, 0x372c,
+ 0x57bf, 0x1c67,
+ 0x57c1, 0x1c6b,
+ 0x57c2, 0x087b,
+ 0x57c3, 0x087e,
+ 0x57c4, 0x3b5b,
+ 0x57c6, 0x1c62,
+ 0x57c7, 0x1c68,
+ 0x57c8, 0x3d0b,
+ 0x57cb, 0x087d,
+ 0x57cc, 0x1c5d,
+ 0x57ce, 0x06ec,
+ 0x57cf, 0x1e82,
+ 0x57d0, 0x1c69,
+ 0x57d2, 0x1c60,
+ 0x57d4, 0x087c,
+ 0x57d5, 0x1c5f,
+ 0x57d7, 0x3c7d,
+ 0x57dc, 0x1e79,
+ 0x57dd, 0x3a05,
+ 0x57de, 0x3f01,
+ 0x57df, 0x0a39,
+ 0x57e0, 0x0a3d,
+ 0x57e1, 0x1e89,
+ 0x57e2, 0x1e77,
+ 0x57e3, 0x1e85,
+ 0x57e4, 0x0a3e,
+ 0x57e5, 0x1e87,
+ 0x57e6, 0x40cf,
+ 0x57e7, 0x1e8d,
+ 0x57e9, 0x1e91,
+ 0x57ec, 0x1e88,
+ 0x57ed, 0x1e7c,
+ 0x57ee, 0x1e84,
+ 0x57ef, 0x4754,
+ 0x57f0, 0x1e92,
+ 0x57f1, 0x1e90,
+ 0x57f2, 0x1e86,
+ 0x57f3, 0x1e81,
+ 0x57f4, 0x1e7a,
+ 0x57f5, 0x20e1,
+ 0x57f6, 0x1e78,
+ 0x57f7, 0x0a42,
+ 0x57f8, 0x1e7f,
+ 0x57f9, 0x0a43,
+ 0x57fa, 0x0a3f,
+ 0x57fb, 0x1e75,
+ 0x57fc, 0x1e8b,
+ 0x57fd, 0x1e7d,
+ 0x57fe, 0x408f,
+ 0x5800, 0x1e7b,
+ 0x5801, 0x1e8e,
+ 0x5802, 0x0a40,
+ 0x5803, 0x40d1,
+ 0x5804, 0x1e94,
+ 0x5805, 0x0a3a,
+ 0x5806, 0x0a3c,
+ 0x5807, 0x1e83,
+ 0x5808, 0x1e7e,
+ 0x5809, 0x087f,
+ 0x580a, 0x0a3b,
+ 0x580b, 0x1e80,
+ 0x580c, 0x1e8f,
+ 0x580d, 0x1e93,
+ 0x580e, 0x1e8a,
+ 0x5810, 0x1e8c,
+ 0x5812, 0x3d0a,
+ 0x5814, 0x1e76,
+ 0x5819, 0x20dc,
+ 0x581b, 0x20e5,
+ 0x581c, 0x20e4,
+ 0x581d, 0x0c1e,
+ 0x581e, 0x20dd,
+ 0x5820, 0x0c1f,
+ 0x5821, 0x0c1d,
+ 0x5822, 0x3c28,
+ 0x5823, 0x20df,
+ 0x5824, 0x0c1a,
+ 0x5825, 0x20e3,
+ 0x5826, 0x40d4,
+ 0x5827, 0x20de,
+ 0x5828, 0x20e0,
+ 0x5829, 0x20da,
+ 0x582a, 0x0c18,
+ 0x582c, 0x20ed,
+ 0x582d, 0x20ec,
+ 0x582e, 0x20e9,
+ 0x582f, 0x0c17,
+ 0x5830, 0x0c1b,
+ 0x5832, 0x1c5e,
+ 0x5833, 0x20e6,
+ 0x5834, 0x0c19,
+ 0x5835, 0x0a41,
+ 0x5836, 0x20e8,
+ 0x5837, 0x20db,
+ 0x5838, 0x20eb,
+ 0x5839, 0x20ea,
+ 0x583a, 0x3d72,
+ 0x583b, 0x20ee,
+ 0x583d, 0x239f,
+ 0x583f, 0x20e7,
+ 0x5840, 0x3d82,
+ 0x5844, 0x47bb,
+ 0x5847, 0x3ac2,
+ 0x5848, 0x20e2,
+ 0x5849, 0x2397,
+ 0x584a, 0x0def,
+ 0x584b, 0x0df2,
+ 0x584c, 0x0ded,
+ 0x584d, 0x2396,
+ 0x584e, 0x239a,
+ 0x584f, 0x2395,
+ 0x5851, 0x0de7,
+ 0x5852, 0x0df1,
+ 0x5853, 0x2392,
+ 0x5854, 0x0deb,
+ 0x5855, 0x2399,
+ 0x5857, 0x0de9,
+ 0x5858, 0x0de8,
+ 0x5859, 0x239c,
+ 0x585a, 0x0dea,
+ 0x585b, 0x239e,
+ 0x585c, 0x4949,
+ 0x585d, 0x239b,
+ 0x585e, 0x0de6,
+ 0x585f, 0x43df,
+ 0x5862, 0x0df0,
+ 0x5863, 0x23a0,
+ 0x5864, 0x2394,
+ 0x5865, 0x239d,
+ 0x5868, 0x2393,
+ 0x5869, 0x3d65,
+ 0x586b, 0x0dec,
+ 0x586c, 0x399a,
+ 0x586d, 0x0dee,
+ 0x586f, 0x2398,
+ 0x5871, 0x23a1,
+ 0x5872, 0x3c26,
+ 0x5873, 0x4355,
+ 0x5874, 0x263f,
+ 0x5875, 0x0fa2,
+ 0x5876, 0x2645,
+ 0x5879, 0x0fa7,
+ 0x587a, 0x2641,
+ 0x587b, 0x2648,
+ 0x587c, 0x2639,
+ 0x587d, 0x0fa9,
+ 0x587e, 0x0fa3,
+ 0x587f, 0x263e,
+ 0x5880, 0x1121,
+ 0x5881, 0x263d,
+ 0x5882, 0x2646,
+ 0x5883, 0x0fa4,
+ 0x5885, 0x0fa8,
+ 0x5886, 0x263c,
+ 0x5887, 0x2642,
+ 0x5888, 0x2647,
+ 0x5889, 0x2638,
+ 0x588a, 0x0fa6,
+ 0x588b, 0x2640,
+ 0x588e, 0x2644,
+ 0x588f, 0x264a,
+ 0x5890, 0x263a,
+ 0x5891, 0x2643,
+ 0x5893, 0x0fa5,
+ 0x5894, 0x2649,
+ 0x5898, 0x263b,
+ 0x5899, 0x4618,
+ 0x589a, 0x4903,
+ 0x589c, 0x1125,
+ 0x589d, 0x28a1,
+ 0x589e, 0x1123,
+ 0x589f, 0x1122,
+ 0x58a0, 0x28a3,
+ 0x58a1, 0x28a8,
+ 0x58a3, 0x28a4,
+ 0x58a5, 0x28a7,
+ 0x58a6, 0x1128,
+ 0x58a7, 0x3eeb,
+ 0x58a8, 0x1288,
+ 0x58a9, 0x1127,
+ 0x58aa, 0x40d7,
+ 0x58ab, 0x28a0,
+ 0x58ac, 0x28a6,
+ 0x58ae, 0x1126,
+ 0x58af, 0x28a5,
+ 0x58b0, 0x37a4,
+ 0x58b1, 0x28a2,
+ 0x58b3, 0x1124,
+ 0x58b5, 0x4840,
+ 0x58b6, 0x3dfd,
+ 0x58ba, 0x2b18,
+ 0x58bb, 0x36eb,
+ 0x58bc, 0x2b1a,
+ 0x58bd, 0x2b15,
+ 0x58be, 0x12a4,
+ 0x58bf, 0x2b17,
+ 0x58c1, 0x12a3,
+ 0x58c2, 0x2b19,
+ 0x58c5, 0x12a6,
+ 0x58c6, 0x2b1b,
+ 0x58c7, 0x12a5,
+ 0x58c8, 0x2b14,
+ 0x58c9, 0x2b16,
+ 0x58cb, 0x3a09,
+ 0x58ce, 0x13c2,
+ 0x58cf, 0x2d4d,
+ 0x58d1, 0x13c1,
+ 0x58d2, 0x2d4e,
+ 0x58d3, 0x13c0,
+ 0x58d4, 0x2d4c,
+ 0x58d5, 0x13bf,
+ 0x58d6, 0x2d4b,
+ 0x58d8, 0x14cd,
+ 0x58d9, 0x14cc,
+ 0x58da, 0x3085,
+ 0x58db, 0x3087,
+ 0x58dc, 0x40da,
+ 0x58dd, 0x3086,
+ 0x58de, 0x1578,
+ 0x58e0, 0x40d9,
+ 0x58e2, 0x157a,
+ 0x58e3, 0x31cb,
+ 0x58e4, 0x160e,
+ 0x58e7, 0x3411,
+ 0x58e8, 0x3410,
+ 0x58e9, 0x1720,
+ 0x58eb, 0x027b,
+ 0x58ec, 0x02c1,
+ 0x58ef, 0x046f,
+ 0x58f0, 0x4549,
+ 0x58f2, 0x3d68,
+ 0x58f3, 0x3c7a,
+ 0x58f4, 0x1a9b,
+ 0x58f9, 0x0c20,
+ 0x58fb, 0x40dc,
+ 0x58fc, 0x23a2,
+ 0x58fd, 0x0faa,
+ 0x58fe, 0x264b,
+ 0x58ff, 0x28a9,
+ 0x5902, 0x0224,
+ 0x5903, 0x1785,
+ 0x5904, 0x454a,
+ 0x5905, 0x4599,
+ 0x5906, 0x1857,
+ 0x5907, 0x454b,
+ 0x590a, 0x0224,
+ 0x590c, 0x1944,
+ 0x590d, 0x1a9c,
+ 0x590e, 0x1c6c,
+ 0x590f, 0x0880,
+ 0x5911, 0x4274,
+ 0x5912, 0x3088,
+ 0x5914, 0x166d,
+ 0x5915, 0x027c,
+ 0x5916, 0x032e,
+ 0x5917, 0x179c,
+ 0x5919, 0x03b4,
+ 0x591c, 0x0581,
+ 0x591f, 0x40e3,
+ 0x5920, 0x0a44,
+ 0x5922, 0x0fac,
+ 0x5924, 0x0fad,
+ 0x5925, 0x0fab,
+ 0x5927, 0x027d,
+ 0x5929, 0x02c2,
+ 0x592a, 0x02c4,
+ 0x592b, 0x02c3,
+ 0x592c, 0x1786,
+ 0x592d, 0x02c5,
+ 0x592e, 0x032f,
+ 0x592f, 0x179d,
+ 0x5931, 0x0330,
+ 0x5932, 0x454c,
+ 0x5934, 0x454d,
+ 0x5937, 0x03b6,
+ 0x593c, 0x17d4,
+ 0x593e, 0x0470,
+ 0x5940, 0x1858,
+ 0x5944, 0x0585,
+ 0x5945, 0x1945,
+ 0x5947, 0x0583,
+ 0x5949, 0x0582,
+ 0x594a, 0x1c6d,
+ 0x594e, 0x06f2,
+ 0x594f, 0x06f1,
+ 0x5950, 0x06f3,
+ 0x5951, 0x06f0,
+ 0x5953, 0x1a9d,
+ 0x5954, 0x0586,
+ 0x5955, 0x06ef,
+ 0x5957, 0x0881,
+ 0x595a, 0x0883,
+ 0x595c, 0x1e95,
+ 0x5960, 0x0c22,
+ 0x5961, 0x20ef,
+ 0x5962, 0x0a45,
+ 0x5965, 0x4852,
+ 0x5967, 0x0df3,
+ 0x5969, 0x0faf,
+ 0x596a, 0x0fae,
+ 0x596b, 0x264c,
+ 0x596d, 0x1129,
+ 0x596e, 0x12a7,
+ 0x5970, 0x2f17,
+ 0x5971, 0x337b,
+ 0x5972, 0x3412,
+ 0x5973, 0x027e,
+ 0x5974, 0x0331,
+ 0x5975, 0x3e6a,
+ 0x5976, 0x0332,
+ 0x5977, 0x17da,
+ 0x5978, 0x03b9,
+ 0x5979, 0x03bc,
+ 0x597b, 0x17d8,
+ 0x597c, 0x17d6,
+ 0x597d, 0x03bb,
+ 0x597e, 0x17d9,
+ 0x597f, 0x17db,
+ 0x5980, 0x17d5,
+ 0x5981, 0x03be,
+ 0x5982, 0x03bd,
+ 0x5983, 0x03ba,
+ 0x5984, 0x03b8,
+ 0x5985, 0x17d7,
+ 0x5989, 0x3d30,
+ 0x598a, 0x047b,
+ 0x598d, 0x0478,
+ 0x598e, 0x185d,
+ 0x598f, 0x1860,
+ 0x5990, 0x185f,
+ 0x5992, 0x0472,
+ 0x5993, 0x047a,
+ 0x5994, 0x3c99,
+ 0x5996, 0x0477,
+ 0x5997, 0x185c,
+ 0x5998, 0x185a,
+ 0x5999, 0x0476,
+ 0x599a, 0x3bb0,
+ 0x599d, 0x0471,
+ 0x599e, 0x0474,
+ 0x599f, 0x3daf,
+ 0x59a0, 0x185b,
+ 0x59a1, 0x1862,
+ 0x59a2, 0x185e,
+ 0x59a3, 0x0475,
+ 0x59a4, 0x0479,
+ 0x59a5, 0x047c,
+ 0x59a6, 0x1859,
+ 0x59a7, 0x1861,
+ 0x59a8, 0x0473,
+ 0x59ac, 0x3d81,
+ 0x59ae, 0x058b,
+ 0x59af, 0x0593,
+ 0x59b0, 0x3cd8,
+ 0x59b1, 0x1951,
+ 0x59b2, 0x194a,
+ 0x59b3, 0x0594,
+ 0x59b4, 0x1955,
+ 0x59b5, 0x1946,
+ 0x59b6, 0x194d,
+ 0x59b7, 0x3f2d,
+ 0x59b8, 0x3a10,
+ 0x59b9, 0x058a,
+ 0x59ba, 0x1947,
+ 0x59bb, 0x0588,
+ 0x59bc, 0x194e,
+ 0x59bd, 0x1952,
+ 0x59be, 0x0587,
+ 0x59c0, 0x1953,
+ 0x59c1, 0x194c,
+ 0x59c3, 0x194f,
+ 0x59c4, 0x3d04,
+ 0x59c5, 0x0596,
+ 0x59c6, 0x058d,
+ 0x59c7, 0x1956,
+ 0x59c8, 0x1954,
+ 0x59c9, 0x40ec,
+ 0x59ca, 0x0592,
+ 0x59cb, 0x0590,
+ 0x59cc, 0x194b,
+ 0x59cd, 0x058f,
+ 0x59ce, 0x1949,
+ 0x59cf, 0x1948,
+ 0x59d0, 0x058e,
+ 0x59d1, 0x058c,
+ 0x59d2, 0x0595,
+ 0x59d3, 0x0591,
+ 0x59d4, 0x0589,
+ 0x59d6, 0x1950,
+ 0x59d8, 0x06f5,
+ 0x59d9, 0x40f1,
+ 0x59da, 0x06fc,
+ 0x59db, 0x1aab,
+ 0x59dc, 0x06f4,
+ 0x59dd, 0x1aa3,
+ 0x59de, 0x1a9f,
+ 0x59e0, 0x1aaf,
+ 0x59e1, 0x1a9e,
+ 0x59e3, 0x06f7,
+ 0x59e4, 0x1aa8,
+ 0x59e5, 0x06fa,
+ 0x59e6, 0x06fd,
+ 0x59e8, 0x06f8,
+ 0x59e9, 0x1aac,
+ 0x59ea, 0x06fb,
+ 0x59eb, 0x3d59,
+ 0x59ec, 0x088a,
+ 0x59ed, 0x1ab2,
+ 0x59ee, 0x1aa0,
+ 0x59ef, 0x3d38,
+ 0x59f0, 0x3bb2,
+ 0x59f1, 0x1aa2,
+ 0x59f2, 0x1aa9,
+ 0x59f3, 0x1aad,
+ 0x59f4, 0x1ab1,
+ 0x59f5, 0x1aae,
+ 0x59f6, 0x1aa7,
+ 0x59f7, 0x1aaa,
+ 0x59f8, 0x3e4a,
+ 0x59f9, 0x40f8,
+ 0x59fa, 0x1aa4,
+ 0x59fb, 0x06ff,
+ 0x59fc, 0x1aa6,
+ 0x59fd, 0x1aa5,
+ 0x59fe, 0x1ab0,
+ 0x59ff, 0x06f6,
+ 0x5a00, 0x1aa1,
+ 0x5a01, 0x06fe,
+ 0x5a02, 0x3b8d,
+ 0x5a03, 0x06f9,
+ 0x5a09, 0x0890,
+ 0x5a0a, 0x1c75,
+ 0x5a0b, 0x3c89,
+ 0x5a0c, 0x088f,
+ 0x5a0d, 0x3b38,
+ 0x5a0f, 0x1c73,
+ 0x5a11, 0x0884,
+ 0x5a12, 0x3a13,
+ 0x5a13, 0x0889,
+ 0x5a15, 0x1c72,
+ 0x5a16, 0x1c6f,
+ 0x5a17, 0x1c74,
+ 0x5a18, 0x0885,
+ 0x5a19, 0x1c6e,
+ 0x5a1b, 0x0888,
+ 0x5a1c, 0x0886,
+ 0x5a1e, 0x1c76,
+ 0x5a1f, 0x0887,
+ 0x5a20, 0x088b,
+ 0x5a21, 0x3a1b,
+ 0x5a23, 0x088c,
+ 0x5a24, 0x40e8,
+ 0x5a25, 0x088e,
+ 0x5a27, 0x3de1,
+ 0x5a29, 0x088d,
+ 0x5a2a, 0x3b3b,
+ 0x5a2b, 0x3d40,
+ 0x5a2c, 0x3a0f,
+ 0x5a2d, 0x1c70,
+ 0x5a33, 0x1c77,
+ 0x5a35, 0x1e9c,
+ 0x5a36, 0x0a46,
+ 0x5a37, 0x20fd,
+ 0x5a38, 0x1e9b,
+ 0x5a39, 0x1eae,
+ 0x5a3c, 0x0a4c,
+ 0x5a3d, 0x3ac0,
+ 0x5a3e, 0x1eac,
+ 0x5a40, 0x0a4b,
+ 0x5a41, 0x0a47,
+ 0x5a42, 0x1eb5,
+ 0x5a43, 0x1ea5,
+ 0x5a44, 0x1ea8,
+ 0x5a45, 0x3917,
+ 0x5a46, 0x0a4f,
+ 0x5a47, 0x1eb2,
+ 0x5a48, 0x1eaa,
+ 0x5a49, 0x0a48,
+ 0x5a4a, 0x0a50,
+ 0x5a4c, 0x1eaf,
+ 0x5a4d, 0x1ead,
+ 0x5a50, 0x1e9e,
+ 0x5a51, 0x1eb3,
+ 0x5a52, 0x1ea7,
+ 0x5a53, 0x1ea2,
+ 0x5a54, 0x4603,
+ 0x5a55, 0x1e98,
+ 0x5a56, 0x1eb4,
+ 0x5a57, 0x1ea4,
+ 0x5a58, 0x1e97,
+ 0x5a59, 0x3b34,
+ 0x5a5a, 0x0a4e,
+ 0x5a5b, 0x1ea9,
+ 0x5a5c, 0x1eb6,
+ 0x5a5d, 0x1ea6,
+ 0x5a5e, 0x1e9a,
+ 0x5a5f, 0x1e9f,
+ 0x5a60, 0x1e96,
+ 0x5a61, 0x3d33,
+ 0x5a62, 0x0a4d,
+ 0x5a63, 0x40fb,
+ 0x5a64, 0x1ea3,
+ 0x5a65, 0x1ea0,
+ 0x5a66, 0x0a49,
+ 0x5a67, 0x1e99,
+ 0x5a68, 0x39b7,
+ 0x5a69, 0x1eb1,
+ 0x5a6a, 0x0a4a,
+ 0x5a6b, 0x3a42,
+ 0x5a6c, 0x1ea1,
+ 0x5a6d, 0x1e9d,
+ 0x5a6e, 0x3d3f,
+ 0x5a70, 0x1eb0,
+ 0x5a71, 0x3d34,
+ 0x5a77, 0x0c23,
+ 0x5a78, 0x20f6,
+ 0x5a79, 0x3ce1,
+ 0x5a7a, 0x20f3,
+ 0x5a7b, 0x2104,
+ 0x5a7c, 0x20f8,
+ 0x5a7d, 0x2105,
+ 0x5a7e, 0x3a11,
+ 0x5a7f, 0x0c25,
+ 0x5a81, 0x3a1d,
+ 0x5a82, 0x3d31,
+ 0x5a83, 0x2101,
+ 0x5a84, 0x20fe,
+ 0x5a86, 0x3b81,
+ 0x5a88, 0x4263,
+ 0x5a8a, 0x20ff,
+ 0x5a8b, 0x2102,
+ 0x5a8c, 0x2106,
+ 0x5a8e, 0x1eab,
+ 0x5a8f, 0x2108,
+ 0x5a90, 0x23b6,
+ 0x5a91, 0x4235,
+ 0x5a92, 0x0c26,
+ 0x5a93, 0x2109,
+ 0x5a94, 0x20f1,
+ 0x5a95, 0x20fb,
+ 0x5a96, 0x4100,
+ 0x5a97, 0x2100,
+ 0x5a99, 0x3a0a,
+ 0x5a9a, 0x0c24,
+ 0x5a9b, 0x0c27,
+ 0x5a9c, 0x2107,
+ 0x5a9d, 0x210a,
+ 0x5a9e, 0x20f5,
+ 0x5a9f, 0x20f2,
+ 0x5aa0, 0x4172,
+ 0x5aa1, 0x3cdc,
+ 0x5aa2, 0x20f4,
+ 0x5aa5, 0x20f9,
+ 0x5aa6, 0x20f7,
+ 0x5aa7, 0x0c28,
+ 0x5aa9, 0x2103,
+ 0x5aab, 0x40fa,
+ 0x5aac, 0x20fa,
+ 0x5aae, 0x20fc,
+ 0x5aaf, 0x20f0,
+ 0x5ab0, 0x23aa,
+ 0x5ab1, 0x23a8,
+ 0x5ab2, 0x0dfc,
+ 0x5ab3, 0x0dfa,
+ 0x5ab4, 0x23b2,
+ 0x5ab5, 0x23a9,
+ 0x5ab6, 0x23b3,
+ 0x5ab7, 0x23af,
+ 0x5ab8, 0x23a7,
+ 0x5ab9, 0x23b5,
+ 0x5aba, 0x23a6,
+ 0x5abb, 0x23ad,
+ 0x5abc, 0x0df9,
+ 0x5abd, 0x0df8,
+ 0x5abe, 0x0df7,
+ 0x5abf, 0x23ab,
+ 0x5ac0, 0x23b0,
+ 0x5ac1, 0x0df4,
+ 0x5ac2, 0x0dfb,
+ 0x5ac3, 0x3896,
+ 0x5ac4, 0x23a4,
+ 0x5ac6, 0x23ae,
+ 0x5ac7, 0x23a3,
+ 0x5ac8, 0x23ac,
+ 0x5ac9, 0x0df5,
+ 0x5aca, 0x23b1,
+ 0x5acb, 0x23a5,
+ 0x5acc, 0x0df6,
+ 0x5acd, 0x23b4,
+ 0x5ace, 0x3c88,
+ 0x5acf, 0x43b5,
+ 0x5ad3, 0x4102,
+ 0x5ad5, 0x2650,
+ 0x5ad6, 0x0fb4,
+ 0x5ad7, 0x0fb3,
+ 0x5ad8, 0x0fb5,
+ 0x5ad9, 0x265c,
+ 0x5ada, 0x2652,
+ 0x5adb, 0x2658,
+ 0x5adc, 0x264d,
+ 0x5add, 0x265b,
+ 0x5ade, 0x265a,
+ 0x5adf, 0x265e,
+ 0x5ae0, 0x2657,
+ 0x5ae1, 0x0fb0,
+ 0x5ae2, 0x2656,
+ 0x5ae3, 0x0fb6,
+ 0x5ae4, 0x3b86,
+ 0x5ae5, 0x264f,
+ 0x5ae6, 0x0fb1,
+ 0x5ae8, 0x265d,
+ 0x5ae9, 0x0fb2,
+ 0x5aea, 0x2651,
+ 0x5aeb, 0x2654,
+ 0x5aec, 0x2659,
+ 0x5aed, 0x2653,
+ 0x5aee, 0x264e,
+ 0x5af0, 0x3ee7,
+ 0x5af2, 0x37f5,
+ 0x5af3, 0x2655,
+ 0x5af4, 0x28ab,
+ 0x5af5, 0x112d,
+ 0x5af6, 0x28ae,
+ 0x5af7, 0x28ad,
+ 0x5af8, 0x28b0,
+ 0x5af9, 0x28b2,
+ 0x5afa, 0x36ee,
+ 0x5afb, 0x112b,
+ 0x5afd, 0x28ac,
+ 0x5afe, 0x3c1d,
+ 0x5aff, 0x28aa,
+ 0x5b01, 0x28b3,
+ 0x5b02, 0x28b1,
+ 0x5b03, 0x28af,
+ 0x5b05, 0x28b5,
+ 0x5b07, 0x28b4,
+ 0x5b08, 0x112f,
+ 0x5b09, 0x112a,
+ 0x5b0b, 0x112c,
+ 0x5b0c, 0x112e,
+ 0x5b0d, 0x48ff,
+ 0x5b0f, 0x28b6,
+ 0x5b10, 0x2b22,
+ 0x5b11, 0x3bf6,
+ 0x5b13, 0x2b21,
+ 0x5b14, 0x2b20,
+ 0x5b16, 0x2b23,
+ 0x5b17, 0x2b1c,
+ 0x5b19, 0x2b1d,
+ 0x5b1a, 0x2b25,
+ 0x5b1b, 0x2b1e,
+ 0x5b1d, 0x12a8,
+ 0x5b1e, 0x2b27,
+ 0x5b1f, 0x4941,
+ 0x5b20, 0x2b26,
+ 0x5b21, 0x2b1f,
+ 0x5b23, 0x2d52,
+ 0x5b24, 0x13c5,
+ 0x5b25, 0x2d50,
+ 0x5b26, 0x2d55,
+ 0x5b27, 0x2d54,
+ 0x5b28, 0x2b24,
+ 0x5b2a, 0x13c4,
+ 0x5b2b, 0x3b84,
+ 0x5b2c, 0x2d53,
+ 0x5b2d, 0x2d4f,
+ 0x5b2e, 0x2d57,
+ 0x5b2f, 0x2d56,
+ 0x5b30, 0x13c3,
+ 0x5b32, 0x2d51,
+ 0x5b34, 0x12a9,
+ 0x5b38, 0x14ce,
+ 0x5b3c, 0x2f18,
+ 0x5b3d, 0x3089,
+ 0x5b40, 0x160f,
+ 0x5b41, 0x38c8,
+ 0x5b43, 0x1610,
+ 0x5b44, 0x3a44,
+ 0x5b45, 0x31cc,
+ 0x5b46, 0x42b2,
+ 0x5b47, 0x32cd,
+ 0x5b48, 0x32cc,
+ 0x5b4a, 0x38cd,
+ 0x5b4b, 0x337c,
+ 0x5b4d, 0x3413,
+ 0x5b4e, 0x3482,
+ 0x5b4f, 0x3a31,
+ 0x5b50, 0x027f,
+ 0x5b53, 0x0281,
+ 0x5b54, 0x02c6,
+ 0x5b55, 0x0333,
+ 0x5b56, 0x17dc,
+ 0x5b57, 0x03bf,
+ 0x5b5a, 0x047f,
+ 0x5b5c, 0x047e,
+ 0x5b5d, 0x047d,
+ 0x5b5f, 0x0597,
+ 0x5b62, 0x1957,
+ 0x5b63, 0x0599,
+ 0x5b64, 0x0598,
+ 0x5b65, 0x1958,
+ 0x5b66, 0x454e,
+ 0x5b68, 0x461d,
+ 0x5b69, 0x0700,
+ 0x5b6b, 0x0891,
+ 0x5b6c, 0x1c78,
+ 0x5b6d, 0x3e5f,
+ 0x5b6e, 0x1eb8,
+ 0x5b70, 0x0a51,
+ 0x5b71, 0x0c2a,
+ 0x5b72, 0x1eb7,
+ 0x5b73, 0x0c29,
+ 0x5b74, 0x3732,
+ 0x5b75, 0x0fb7,
+ 0x5b76, 0x410a,
+ 0x5b77, 0x265f,
+ 0x5b78, 0x12aa,
+ 0x5b7a, 0x13c6,
+ 0x5b7b, 0x2d58,
+ 0x5b7c, 0x410c,
+ 0x5b7d, 0x1611,
+ 0x5b7f, 0x16c0,
+ 0x5b80, 0x0225,
+ 0x5b81, 0x179e,
+ 0x5b82, 0x4044,
+ 0x5b83, 0x0334,
+ 0x5b84, 0x179f,
+ 0x5b85, 0x03c3,
+ 0x5b87, 0x03c1,
+ 0x5b89, 0x03c4,
+ 0x5b8b, 0x0482,
+ 0x5b8c, 0x0481,
+ 0x5b8e, 0x1863,
+ 0x5b8f, 0x0483,
+ 0x5b90, 0x48e9,
+ 0x5b92, 0x1864,
+ 0x5b93, 0x1959,
+ 0x5b95, 0x195a,
+ 0x5b97, 0x059a,
+ 0x5b98, 0x059c,
+ 0x5b99, 0x059e,
+ 0x5b9a, 0x059b,
+ 0x5b9b, 0x059f,
+ 0x5b9c, 0x059d,
+ 0x5b9d, 0x4116,
+ 0x5b9e, 0x454f,
+ 0x5ba2, 0x0704,
+ 0x5ba3, 0x0701,
+ 0x5ba4, 0x0703,
+ 0x5ba5, 0x0705,
+ 0x5ba6, 0x0702,
+ 0x5ba7, 0x1c79,
+ 0x5ba8, 0x1ab3,
+ 0x5baa, 0x417b,
+ 0x5bac, 0x1c7b,
+ 0x5bad, 0x1c7a,
+ 0x5bae, 0x0897,
+ 0x5bb0, 0x0893,
+ 0x5bb3, 0x0894,
+ 0x5bb4, 0x0896,
+ 0x5bb5, 0x0898,
+ 0x5bb6, 0x0895,
+ 0x5bb8, 0x089a,
+ 0x5bb9, 0x0899,
+ 0x5bbf, 0x0a56,
+ 0x5bc0, 0x1eba,
+ 0x5bc1, 0x1eb9,
+ 0x5bc2, 0x0a55,
+ 0x5bc3, 0x3f25,
+ 0x5bc4, 0x0a54,
+ 0x5bc5, 0x0a53,
+ 0x5bc6, 0x0a57,
+ 0x5bc7, 0x0a52,
+ 0x5bca, 0x2110,
+ 0x5bcb, 0x210d,
+ 0x5bcc, 0x0c2c,
+ 0x5bcd, 0x210c,
+ 0x5bce, 0x2111,
+ 0x5bd0, 0x0c2e,
+ 0x5bd1, 0x210f,
+ 0x5bd2, 0x0c2b,
+ 0x5bd3, 0x0c2d,
+ 0x5bd4, 0x210e,
+ 0x5bd5, 0x4111,
+ 0x5bd6, 0x23b7,
+ 0x5bd7, 0x42bb,
+ 0x5bd8, 0x23b8,
+ 0x5bde, 0x0fb8,
+ 0x5bdf, 0x0fc0,
+ 0x5be0, 0x2660,
+ 0x5be1, 0x0fba,
+ 0x5be2, 0x0fbe,
+ 0x5be3, 0x2661,
+ 0x5be4, 0x0fbf,
+ 0x5be5, 0x0fbb,
+ 0x5be7, 0x0fb9,
+ 0x5be8, 0x0fbd,
+ 0x5be9, 0x1132,
+ 0x5bea, 0x210b,
+ 0x5beb, 0x1133,
+ 0x5bec, 0x1131,
+ 0x5bee, 0x1130,
+ 0x5bef, 0x2b28,
+ 0x5bf0, 0x12ab,
+ 0x5bf1, 0x2d59,
+ 0x5bf3, 0x4115,
+ 0x5bf5, 0x157b,
+ 0x5bf6, 0x1612,
+ 0x5bf8, 0x0282,
+ 0x5bfa, 0x03c5,
+ 0x5bff, 0x40dd,
+ 0x5c01, 0x0706,
+ 0x5c03, 0x1c7c,
+ 0x5c04, 0x089b,
+ 0x5c05, 0x4118,
+ 0x5c07, 0x0a5a,
+ 0x5c08, 0x0a59,
+ 0x5c09, 0x0a58,
+ 0x5c0a, 0x0c2f,
+ 0x5c0c, 0x2112,
+ 0x5c0d, 0x0fc1,
+ 0x5c0e, 0x12ac,
+ 0x5c0f, 0x0283,
+ 0x5c10, 0x1787,
+ 0x5c11, 0x02c7,
+ 0x5c12, 0x17a0,
+ 0x5c13, 0x411a,
+ 0x5c14, 0x411c,
+ 0x5c15, 0x17dd,
+ 0x5c16, 0x03c6,
+ 0x5c1a, 0x05a0,
+ 0x5c1c, 0x45ea,
+ 0x5c1e, 0x3a29,
+ 0x5c1f, 0x23ba,
+ 0x5c20, 0x3d89,
+ 0x5c22, 0x0284,
+ 0x5c23, 0x44e8,
+ 0x5c24, 0x02c8,
+ 0x5c25, 0x17de,
+ 0x5c28, 0x1865,
+ 0x5c2a, 0x1866,
+ 0x5c2c, 0x0484,
+ 0x5c30, 0x2113,
+ 0x5c31, 0x0c31,
+ 0x5c33, 0x23bb,
+ 0x5c37, 0x13c7,
+ 0x5c38, 0x0285,
+ 0x5c39, 0x0299,
+ 0x5c3a, 0x02c9,
+ 0x5c3b, 0x17a1,
+ 0x5c3c, 0x0335,
+ 0x5c3e, 0x0488,
+ 0x5c3f, 0x0487,
+ 0x5c40, 0x0485,
+ 0x5c44, 0x195b,
+ 0x5c45, 0x05a2,
+ 0x5c47, 0x195c,
+ 0x5c48, 0x05a1,
+ 0x5c49, 0x411f,
+ 0x5c4a, 0x3f5c,
+ 0x5c4b, 0x070a,
+ 0x5c4c, 0x1ab4,
+ 0x5c4d, 0x0709,
+ 0x5c4e, 0x0707,
+ 0x5c50, 0x089e,
+ 0x5c51, 0x089c,
+ 0x5c53, 0x3f02,
+ 0x5c54, 0x1c7e,
+ 0x5c55, 0x089d,
+ 0x5c56, 0x1c7d,
+ 0x5c58, 0x0892,
+ 0x5c59, 0x1ebb,
+ 0x5c5c, 0x0a5c,
+ 0x5c5e, 0x3d67,
+ 0x5c60, 0x0a5b,
+ 0x5c62, 0x0fc2,
+ 0x5c63, 0x2662,
+ 0x5c64, 0x1134,
+ 0x5c67, 0x28b7,
+ 0x5c68, 0x13c8,
+ 0x5c69, 0x2f19,
+ 0x5c6c, 0x166e,
+ 0x5c6d, 0x3483,
+ 0x5c6e, 0x1776,
+ 0x5c6f, 0x02ca,
+ 0x5c71, 0x0286,
+ 0x5c73, 0x17a3,
+ 0x5c74, 0x17a2,
+ 0x5c79, 0x03c7,
+ 0x5c7a, 0x17e0,
+ 0x5c7c, 0x17df,
+ 0x5c7e, 0x17e2,
+ 0x5c85, 0x4121,
+ 0x5c86, 0x186e,
+ 0x5c88, 0x1869,
+ 0x5c89, 0x186b,
+ 0x5c8a, 0x186d,
+ 0x5c8b, 0x186a,
+ 0x5c8c, 0x048c,
+ 0x5c8d, 0x1867,
+ 0x5c8f, 0x1868,
+ 0x5c90, 0x0489,
+ 0x5c92, 0x186c,
+ 0x5c93, 0x186f,
+ 0x5c94, 0x048b,
+ 0x5c95, 0x1870,
+ 0x5c99, 0x468c,
+ 0x5c9a, 0x4551,
+ 0x5c9c, 0x495a,
+ 0x5c9d, 0x196a,
+ 0x5c9e, 0x3a2a,
+ 0x5c9f, 0x1964,
+ 0x5ca0, 0x195f,
+ 0x5ca1, 0x05a5,
+ 0x5ca2, 0x1967,
+ 0x5ca3, 0x1965,
+ 0x5ca4, 0x195e,
+ 0x5ca5, 0x196b,
+ 0x5ca6, 0x196e,
+ 0x5ca7, 0x1969,
+ 0x5ca8, 0x1962,
+ 0x5ca9, 0x05a7,
+ 0x5caa, 0x1968,
+ 0x5cab, 0x05a8,
+ 0x5cac, 0x1963,
+ 0x5cad, 0x1966,
+ 0x5cae, 0x195d,
+ 0x5caf, 0x1961,
+ 0x5cb0, 0x196d,
+ 0x5cb1, 0x05a9,
+ 0x5cb3, 0x05aa,
+ 0x5cb5, 0x1960,
+ 0x5cb6, 0x196c,
+ 0x5cb7, 0x05a4,
+ 0x5cb8, 0x05a6,
+ 0x5cba, 0x412b,
+ 0x5cc1, 0x43b8,
+ 0x5cc2, 0x3d4c,
+ 0x5cc6, 0x1ac5,
+ 0x5cc7, 0x1abe,
+ 0x5cc8, 0x1ac4,
+ 0x5cc9, 0x1abd,
+ 0x5cca, 0x1abf,
+ 0x5ccb, 0x1ab9,
+ 0x5ccc, 0x1ab7,
+ 0x5cce, 0x1ac6,
+ 0x5ccf, 0x1ac3,
+ 0x5cd0, 0x1ab5,
+ 0x5cd1, 0x3f13,
+ 0x5cd2, 0x070c,
+ 0x5cd3, 0x1ac1,
+ 0x5cd6, 0x1ac0,
+ 0x5cd7, 0x1ab8,
+ 0x5cd8, 0x1ab6,
+ 0x5cd9, 0x070b,
+ 0x5cda, 0x1abc,
+ 0x5cdb, 0x1aba,
+ 0x5cde, 0x1abb,
+ 0x5cdf, 0x1ac7,
+ 0x5ce5, 0x4637,
+ 0x5ce8, 0x08a3,
+ 0x5ce9, 0x4122,
+ 0x5cea, 0x08a2,
+ 0x5cec, 0x1c7f,
+ 0x5ced, 0x089f,
+ 0x5cee, 0x1c81,
+ 0x5cef, 0x4123,
+ 0x5cf0, 0x08a4,
+ 0x5cf1, 0x1c82,
+ 0x5cf4, 0x08a7,
+ 0x5cf6, 0x08a5,
+ 0x5cf7, 0x1c83,
+ 0x5cf8, 0x1ac8,
+ 0x5cf9, 0x1c85,
+ 0x5cfb, 0x08a1,
+ 0x5cfd, 0x08a0,
+ 0x5cff, 0x1c80,
+ 0x5d00, 0x1c84,
+ 0x5d01, 0x08a6,
+ 0x5d06, 0x0a5f,
+ 0x5d07, 0x0a5e,
+ 0x5d0b, 0x1ebd,
+ 0x5d0c, 0x1ec1,
+ 0x5d0d, 0x1ec3,
+ 0x5d0e, 0x0a60,
+ 0x5d0f, 0x1ec6,
+ 0x5d10, 0x4127,
+ 0x5d11, 0x0a64,
+ 0x5d12, 0x1ec8,
+ 0x5d14, 0x0a66,
+ 0x5d15, 0x43b9,
+ 0x5d16, 0x0a62,
+ 0x5d17, 0x0a6a,
+ 0x5d18, 0x4128,
+ 0x5d19, 0x0a67,
+ 0x5d1a, 0x1ebf,
+ 0x5d1b, 0x0a61,
+ 0x5d1d, 0x1ebe,
+ 0x5d1e, 0x1ebc,
+ 0x5d1f, 0x1eca,
+ 0x5d20, 0x1ec0,
+ 0x5d22, 0x0a63,
+ 0x5d23, 0x1ec9,
+ 0x5d24, 0x0a68,
+ 0x5d25, 0x1ec5,
+ 0x5d26, 0x1ec4,
+ 0x5d27, 0x0a69,
+ 0x5d28, 0x1ec2,
+ 0x5d29, 0x0a65,
+ 0x5d2c, 0x3df7,
+ 0x5d2e, 0x1ecb,
+ 0x5d2f, 0x46d3,
+ 0x5d30, 0x1ec7,
+ 0x5d31, 0x2122,
+ 0x5d32, 0x2129,
+ 0x5d33, 0x211e,
+ 0x5d34, 0x0c34,
+ 0x5d35, 0x211a,
+ 0x5d36, 0x212a,
+ 0x5d37, 0x2114,
+ 0x5d38, 0x2127,
+ 0x5d39, 0x2125,
+ 0x5d3a, 0x211f,
+ 0x5d3c, 0x2128,
+ 0x5d3d, 0x2121,
+ 0x5d3e, 0x4629,
+ 0x5d3f, 0x2119,
+ 0x5d40, 0x212b,
+ 0x5d41, 0x2117,
+ 0x5d42, 0x2124,
+ 0x5d43, 0x2115,
+ 0x5d45, 0x212c,
+ 0x5d46, 0x4129,
+ 0x5d47, 0x0c35,
+ 0x5d48, 0x462a,
+ 0x5d49, 0x2126,
+ 0x5d4a, 0x23be,
+ 0x5d4b, 0x2118,
+ 0x5d4c, 0x0c32,
+ 0x5d4e, 0x211c,
+ 0x5d50, 0x0c33,
+ 0x5d51, 0x211b,
+ 0x5d52, 0x2120,
+ 0x5d55, 0x211d,
+ 0x5d56, 0x43ba,
+ 0x5d57, 0x3fca,
+ 0x5d59, 0x2123,
+ 0x5d5b, 0x3dd5,
+ 0x5d5e, 0x23c2,
+ 0x5d62, 0x23c5,
+ 0x5d63, 0x23bd,
+ 0x5d65, 0x23bf,
+ 0x5d67, 0x23c4,
+ 0x5d68, 0x23c3,
+ 0x5d69, 0x0dfd,
+ 0x5d6b, 0x2116,
+ 0x5d6c, 0x23c1,
+ 0x5d6f, 0x0dfe,
+ 0x5d70, 0x46e4,
+ 0x5d71, 0x23bc,
+ 0x5d72, 0x23c0,
+ 0x5d74, 0x3eef,
+ 0x5d77, 0x2669,
+ 0x5d79, 0x2670,
+ 0x5d7a, 0x2667,
+ 0x5d7c, 0x266e,
+ 0x5d7d, 0x2665,
+ 0x5d7e, 0x266d,
+ 0x5d7f, 0x2671,
+ 0x5d80, 0x2664,
+ 0x5d81, 0x2668,
+ 0x5d82, 0x2663,
+ 0x5d84, 0x0fc3,
+ 0x5d85, 0x3e34,
+ 0x5d86, 0x2666,
+ 0x5d87, 0x0fc4,
+ 0x5d88, 0x266c,
+ 0x5d89, 0x266b,
+ 0x5d8a, 0x266a,
+ 0x5d8b, 0x4124,
+ 0x5d8d, 0x266f,
+ 0x5d8e, 0x3f0c,
+ 0x5d92, 0x28bb,
+ 0x5d93, 0x28bd,
+ 0x5d94, 0x1137,
+ 0x5d95, 0x28be,
+ 0x5d97, 0x28b9,
+ 0x5d99, 0x28b8,
+ 0x5d9a, 0x28c2,
+ 0x5d9c, 0x28c0,
+ 0x5d9d, 0x1136,
+ 0x5d9e, 0x28c3,
+ 0x5d9f, 0x28ba,
+ 0x5da0, 0x28bf,
+ 0x5da1, 0x28c1,
+ 0x5da2, 0x28bc,
+ 0x5da4, 0x462d,
+ 0x5da7, 0x2b2c,
+ 0x5da8, 0x2b31,
+ 0x5da9, 0x2b2b,
+ 0x5daa, 0x2b30,
+ 0x5dab, 0x3e39,
+ 0x5dac, 0x2b29,
+ 0x5dad, 0x2b33,
+ 0x5dae, 0x2b2f,
+ 0x5daf, 0x2b34,
+ 0x5db0, 0x2b2e,
+ 0x5db1, 0x2b2a,
+ 0x5db2, 0x2b32,
+ 0x5db4, 0x2b35,
+ 0x5db5, 0x2b2d,
+ 0x5db6, 0x4158,
+ 0x5db7, 0x2d5b,
+ 0x5db8, 0x13cc,
+ 0x5db9, 0x462e,
+ 0x5dba, 0x13ca,
+ 0x5dbc, 0x13c9,
+ 0x5dbd, 0x13cb,
+ 0x5dc0, 0x2f1b,
+ 0x5dc1, 0x3bff,
+ 0x5dc2, 0x3023,
+ 0x5dc3, 0x308c,
+ 0x5dc6, 0x31cd,
+ 0x5dc9, 0x1613,
+ 0x5dcb, 0x32ce,
+ 0x5dcd, 0x166f,
+ 0x5dcf, 0x32cf,
+ 0x5dd1, 0x337f,
+ 0x5dd2, 0x16c2,
+ 0x5dd4, 0x16c1,
+ 0x5dd5, 0x337e,
+ 0x5dd6, 0x16f7,
+ 0x5dd7, 0x412c,
+ 0x5dd8, 0x3414,
+ 0x5ddb, 0x0226,
+ 0x5ddd, 0x0287,
+ 0x5dde, 0x03c8,
+ 0x5ddf, 0x17e3,
+ 0x5de0, 0x1871,
+ 0x5de1, 0x051a,
+ 0x5de2, 0x0a6b,
+ 0x5de5, 0x0288,
+ 0x5de6, 0x0338,
+ 0x5de7, 0x0337,
+ 0x5de8, 0x0336,
+ 0x5deb, 0x048d,
+ 0x5dee, 0x08a8,
+ 0x5df0, 0x23c6,
+ 0x5df1, 0x0289,
+ 0x5df4, 0x02cb,
+ 0x5df5, 0x3f61,
+ 0x5df7, 0x070d,
+ 0x5df9, 0x1ac9,
+ 0x5dfd, 0x0c36,
+ 0x5dfe, 0x028c,
+ 0x5dff, 0x1788,
+ 0x5e02, 0x0339,
+ 0x5e04, 0x17a4,
+ 0x5e06, 0x03c9,
+ 0x5e09, 0x4140,
+ 0x5e0a, 0x1872,
+ 0x5e0b, 0x3d8a,
+ 0x5e0c, 0x048e,
+ 0x5e0e, 0x1873,
+ 0x5e11, 0x05b0,
+ 0x5e12, 0x3f2e,
+ 0x5e14, 0x1970,
+ 0x5e15, 0x05ae,
+ 0x5e16, 0x05ad,
+ 0x5e17, 0x196f,
+ 0x5e18, 0x05ab,
+ 0x5e19, 0x1971,
+ 0x5e1a, 0x05ac,
+ 0x5e1b, 0x05af,
+ 0x5e1d, 0x070e,
+ 0x5e1f, 0x0710,
+ 0x5e20, 0x1acd,
+ 0x5e21, 0x1aca,
+ 0x5e24, 0x1ace,
+ 0x5e25, 0x070f,
+ 0x5e28, 0x1c87,
+ 0x5e29, 0x1c86,
+ 0x5e2b, 0x08aa,
+ 0x5e2d, 0x08a9,
+ 0x5e2e, 0x4135,
+ 0x5e33, 0x0a6e,
+ 0x5e34, 0x1ecd,
+ 0x5e36, 0x0a6d,
+ 0x5e37, 0x0a6f,
+ 0x5e38, 0x0a6c,
+ 0x5e3d, 0x0c38,
+ 0x5e3e, 0x1ecc,
+ 0x5e40, 0x0c39,
+ 0x5e41, 0x212e,
+ 0x5e42, 0x43a0,
+ 0x5e43, 0x0c3a,
+ 0x5e44, 0x212d,
+ 0x5e45, 0x0c37,
+ 0x5e48, 0x3a2c,
+ 0x5e4a, 0x23c9,
+ 0x5e4b, 0x23cb,
+ 0x5e4c, 0x0dff,
+ 0x5e4d, 0x23ca,
+ 0x5e4e, 0x23c8,
+ 0x5e4f, 0x23c7,
+ 0x5e53, 0x2674,
+ 0x5e54, 0x0fc9,
+ 0x5e55, 0x0fc7,
+ 0x5e57, 0x0fc8,
+ 0x5e58, 0x2672,
+ 0x5e5b, 0x0fc5,
+ 0x5e5c, 0x28c7,
+ 0x5e5d, 0x28c5,
+ 0x5e5e, 0x3a2b,
+ 0x5e5f, 0x1139,
+ 0x5e60, 0x28c6,
+ 0x5e61, 0x113a,
+ 0x5e62, 0x1138,
+ 0x5e63, 0x0fc6,
+ 0x5e66, 0x2b38,
+ 0x5e67, 0x2b36,
+ 0x5e69, 0x28c4,
+ 0x5e6a, 0x2d5d,
+ 0x5e6b, 0x13cd,
+ 0x5e6c, 0x2d5c,
+ 0x5e6d, 0x2f1c,
+ 0x5e6f, 0x2b39,
+ 0x5e70, 0x308d,
+ 0x5e72, 0x028d,
+ 0x5e73, 0x033b,
+ 0x5e74, 0x03cb,
+ 0x5e75, 0x17e4,
+ 0x5e76, 0x03ca,
+ 0x5e78, 0x05b1,
+ 0x5e79, 0x0e00,
+ 0x5e7a, 0x0227,
+ 0x5e7b, 0x02cc,
+ 0x5e7c, 0x033c,
+ 0x5e7d, 0x0711,
+ 0x5e7e, 0x0c3b,
+ 0x5e7f, 0x0228,
+ 0x5e80, 0x17a5,
+ 0x5e82, 0x17a6,
+ 0x5e83, 0x4108,
+ 0x5e84, 0x17e5,
+ 0x5e86, 0x4552,
+ 0x5e87, 0x0490,
+ 0x5e88, 0x1877,
+ 0x5e89, 0x1875,
+ 0x5e8a, 0x0491,
+ 0x5e8b, 0x1874,
+ 0x5e8c, 0x1876,
+ 0x5e8d, 0x1878,
+ 0x5e8f, 0x048f,
+ 0x5e95, 0x05b5,
+ 0x5e97, 0x05b3,
+ 0x5e9a, 0x05b2,
+ 0x5e9b, 0x1ad2,
+ 0x5e9c, 0x05b4,
+ 0x5ea0, 0x0712,
+ 0x5ea2, 0x1ad1,
+ 0x5ea3, 0x1ad3,
+ 0x5ea4, 0x1ad0,
+ 0x5ea5, 0x1ad4,
+ 0x5ea6, 0x0713,
+ 0x5ea7, 0x08ad,
+ 0x5ea8, 0x1c88,
+ 0x5eaa, 0x1c8a,
+ 0x5eab, 0x08ab,
+ 0x5eac, 0x1c8b,
+ 0x5ead, 0x08ac,
+ 0x5eae, 0x1c89,
+ 0x5eb0, 0x1acf,
+ 0x5eb1, 0x1ece,
+ 0x5eb2, 0x1ed1,
+ 0x5eb4, 0x1ecf,
+ 0x5eb5, 0x0a73,
+ 0x5eb6, 0x0a72,
+ 0x5eb7, 0x0a70,
+ 0x5eb9, 0x1ed0,
+ 0x5ebd, 0x43bd,
+ 0x5ebe, 0x0a74,
+ 0x5ec1, 0x0c3d,
+ 0x5ec4, 0x0c3f,
+ 0x5ec5, 0x23cc,
+ 0x5ec6, 0x23ce,
+ 0x5ec7, 0x23d0,
+ 0x5ec8, 0x0e02,
+ 0x5ec9, 0x0e01,
+ 0x5eca, 0x0c3c,
+ 0x5ecb, 0x23cf,
+ 0x5ecc, 0x23cd,
+ 0x5ecd, 0x3a30,
+ 0x5ece, 0x2678,
+ 0x5ed0, 0x413d,
+ 0x5ed1, 0x2676,
+ 0x5ed2, 0x267c,
+ 0x5ed3, 0x0fca,
+ 0x5ed4, 0x267d,
+ 0x5ed5, 0x267a,
+ 0x5ed6, 0x0fcb,
+ 0x5ed7, 0x2677,
+ 0x5ed8, 0x2675,
+ 0x5ed9, 0x267b,
+ 0x5eda, 0x113c,
+ 0x5edb, 0x28c9,
+ 0x5edc, 0x2679,
+ 0x5edd, 0x113e,
+ 0x5ede, 0x28ca,
+ 0x5edf, 0x113d,
+ 0x5ee0, 0x1140,
+ 0x5ee1, 0x28cb,
+ 0x5ee2, 0x113b,
+ 0x5ee3, 0x113f,
+ 0x5ee5, 0x2b3e,
+ 0x5ee6, 0x2b3c,
+ 0x5ee7, 0x2b3b,
+ 0x5ee8, 0x2b3d,
+ 0x5ee9, 0x2b3a,
+ 0x5eec, 0x157d,
+ 0x5eee, 0x31cf,
+ 0x5ef1, 0x32d0,
+ 0x5ef2, 0x3380,
+ 0x5ef3, 0x1742,
+ 0x5ef4, 0x0229,
+ 0x5ef6, 0x05b7,
+ 0x5ef7, 0x0492,
+ 0x5ef8, 0x386f,
+ 0x5ef9, 0x4143,
+ 0x5efa, 0x0714,
+ 0x5efb, 0x4144,
+ 0x5efc, 0x4146,
+ 0x5efe, 0x028e,
+ 0x5eff, 0x02cd,
+ 0x5f01, 0x033d,
+ 0x5f02, 0x17e6,
+ 0x5f04, 0x0493,
+ 0x5f05, 0x1879,
+ 0x5f07, 0x1ad5,
+ 0x5f08, 0x0715,
+ 0x5f0a, 0x0fcc,
+ 0x5f0b, 0x028f,
+ 0x5f0c, 0x3a3e,
+ 0x5f0d, 0x4149,
+ 0x5f0e, 0x3a3f,
+ 0x5f0f, 0x03cc,
+ 0x5f12, 0x0e03,
+ 0x5f13, 0x0290,
+ 0x5f14, 0x02ce,
+ 0x5f17, 0x033f,
+ 0x5f18, 0x033e,
+ 0x5f1a, 0x17e7,
+ 0x5f1b, 0x03cd,
+ 0x5f1d, 0x187a,
+ 0x5f1f, 0x0494,
+ 0x5f22, 0x1973,
+ 0x5f25, 0x4630,
+ 0x5f26, 0x05b8,
+ 0x5f28, 0x1972,
+ 0x5f29, 0x05ba,
+ 0x5f2d, 0x0716,
+ 0x5f2e, 0x1ad6,
+ 0x5f30, 0x1c8d,
+ 0x5f31, 0x08ae,
+ 0x5f33, 0x1c8c,
+ 0x5f35, 0x0a75,
+ 0x5f36, 0x1ed3,
+ 0x5f37, 0x0a76,
+ 0x5f38, 0x1ed4,
+ 0x5f3a, 0x414e,
+ 0x5f3c, 0x0c40,
+ 0x5f40, 0x23d1,
+ 0x5f43, 0x267f,
+ 0x5f44, 0x267e,
+ 0x5f46, 0x0fcd,
+ 0x5f48, 0x1141,
+ 0x5f49, 0x28cc,
+ 0x5f4a, 0x12ad,
+ 0x5f4b, 0x2b3f,
+ 0x5f4c, 0x13ce,
+ 0x5f4d, 0x3ba5,
+ 0x5f4e, 0x16c3,
+ 0x5f4f, 0x3416,
+ 0x5f50, 0x022a,
+ 0x5f51, 0x44e9,
+ 0x5f54, 0x1976,
+ 0x5f56, 0x1ad7,
+ 0x5f57, 0x0a77,
+ 0x5f58, 0x212f,
+ 0x5f59, 0x0e04,
+ 0x5f5c, 0x3d5a,
+ 0x5f5d, 0x14cf,
+ 0x5f61, 0x022b,
+ 0x5f62, 0x0496,
+ 0x5f63, 0x4152,
+ 0x5f64, 0x0495,
+ 0x5f65, 0x0717,
+ 0x5f67, 0x1c8e,
+ 0x5f69, 0x0a79,
+ 0x5f6a, 0x0b89,
+ 0x5f6b, 0x0a7a,
+ 0x5f6c, 0x0a78,
+ 0x5f6d, 0x0c41,
+ 0x5f6f, 0x2680,
+ 0x5f70, 0x0fce,
+ 0x5f71, 0x1142,
+ 0x5f72, 0x4154,
+ 0x5f73, 0x1777,
+ 0x5f74, 0x17e8,
+ 0x5f76, 0x187c,
+ 0x5f77, 0x0497,
+ 0x5f78, 0x187b,
+ 0x5f79, 0x0498,
+ 0x5f7b, 0x4058,
+ 0x5f7c, 0x05be,
+ 0x5f7d, 0x1979,
+ 0x5f7e, 0x1978,
+ 0x5f7f, 0x05bd,
+ 0x5f80, 0x05bb,
+ 0x5f82, 0x1977,
+ 0x5f83, 0x4631,
+ 0x5f85, 0x0719,
+ 0x5f86, 0x1ad8,
+ 0x5f87, 0x071c,
+ 0x5f88, 0x0718,
+ 0x5f89, 0x071e,
+ 0x5f8a, 0x071a,
+ 0x5f8c, 0x071d,
+ 0x5f90, 0x08b1,
+ 0x5f91, 0x08b0,
+ 0x5f92, 0x08af,
+ 0x5f96, 0x1ed6,
+ 0x5f97, 0x0a7b,
+ 0x5f98, 0x0a7e,
+ 0x5f99, 0x0a7c,
+ 0x5f9b, 0x1ed5,
+ 0x5f9c, 0x0a81,
+ 0x5f9e, 0x0a7d,
+ 0x5f9f, 0x1ed7,
+ 0x5fa0, 0x0a80,
+ 0x5fa1, 0x0a7f,
+ 0x5fa4, 0x402c,
+ 0x5fa5, 0x2131,
+ 0x5fa6, 0x2130,
+ 0x5fa7, 0x4157,
+ 0x5fa8, 0x0c44,
+ 0x5fa9, 0x0c42,
+ 0x5fab, 0x2132,
+ 0x5fac, 0x0e05,
+ 0x5fad, 0x23d3,
+ 0x5fae, 0x0e06,
+ 0x5faf, 0x23d2,
+ 0x5fb1, 0x3d98,
+ 0x5fb2, 0x28cd,
+ 0x5fb5, 0x1144,
+ 0x5fb6, 0x2681,
+ 0x5fb7, 0x1143,
+ 0x5fb9, 0x0fcf,
+ 0x5fba, 0x3f9f,
+ 0x5fbb, 0x2b41,
+ 0x5fbc, 0x2b40,
+ 0x5fbd, 0x13cf,
+ 0x5fbe, 0x2d5e,
+ 0x5fbf, 0x308e,
+ 0x5fc0, 0x31d1,
+ 0x5fc3, 0x02d0,
+ 0x5fc4, 0x44ea,
+ 0x5fc5, 0x0340,
+ 0x5fc9, 0x17a7,
+ 0x5fcc, 0x049a,
+ 0x5fcd, 0x049c,
+ 0x5fcf, 0x17eb,
+ 0x5fd0, 0x187f,
+ 0x5fd1, 0x187e,
+ 0x5fd2, 0x187d,
+ 0x5fd4, 0x17ea,
+ 0x5fd5, 0x17e9,
+ 0x5fd6, 0x03cf,
+ 0x5fd7, 0x049b,
+ 0x5fd8, 0x0499,
+ 0x5fd9, 0x03ce,
+ 0x5fdb, 0x3a4a,
+ 0x5fdd, 0x05bf,
+ 0x5fde, 0x197a,
+ 0x5fdf, 0x41af,
+ 0x5fe0, 0x05c0,
+ 0x5fe1, 0x1884,
+ 0x5fe3, 0x1886,
+ 0x5fe4, 0x1885,
+ 0x5fe5, 0x197b,
+ 0x5fe8, 0x1881,
+ 0x5fea, 0x04a0,
+ 0x5feb, 0x049e,
+ 0x5fed, 0x1880,
+ 0x5fee, 0x1882,
+ 0x5fef, 0x1888,
+ 0x5ff1, 0x049d,
+ 0x5ff3, 0x1883,
+ 0x5ff4, 0x188c,
+ 0x5ff5, 0x05c2,
+ 0x5ff7, 0x1889,
+ 0x5ff8, 0x049f,
+ 0x5ffa, 0x1887,
+ 0x5ffb, 0x188a,
+ 0x5ffd, 0x05c1,
+ 0x5fff, 0x05c3,
+ 0x6000, 0x188b,
+ 0x6009, 0x198f,
+ 0x600a, 0x1982,
+ 0x600b, 0x1980,
+ 0x600c, 0x198e,
+ 0x600d, 0x1989,
+ 0x600e, 0x0723,
+ 0x600f, 0x05c4,
+ 0x6010, 0x198a,
+ 0x6011, 0x198d,
+ 0x6012, 0x071f,
+ 0x6013, 0x198c,
+ 0x6014, 0x05c5,
+ 0x6015, 0x05ca,
+ 0x6016, 0x05c8,
+ 0x6017, 0x1983,
+ 0x6019, 0x197e,
+ 0x601a, 0x1985,
+ 0x601b, 0x05cf,
+ 0x601c, 0x1990,
+ 0x601d, 0x0720,
+ 0x601e, 0x1986,
+ 0x6020, 0x0721,
+ 0x6021, 0x05cb,
+ 0x6022, 0x1988,
+ 0x6023, 0x4185,
+ 0x6024, 0x1ae7,
+ 0x6025, 0x0722,
+ 0x6026, 0x197d,
+ 0x6027, 0x05cc,
+ 0x6028, 0x0724,
+ 0x6029, 0x05cd,
+ 0x602a, 0x05c9,
+ 0x602b, 0x05ce,
+ 0x602c, 0x1987,
+ 0x602d, 0x197c,
+ 0x602e, 0x198b,
+ 0x602f, 0x05c6,
+ 0x6031, 0x4161,
+ 0x6032, 0x197f,
+ 0x6033, 0x1984,
+ 0x6034, 0x1981,
+ 0x6035, 0x05c7,
+ 0x6037, 0x1ad9,
+ 0x6039, 0x1ada,
+ 0x603b, 0x4553,
+ 0x6040, 0x1ae4,
+ 0x6041, 0x1c92,
+ 0x6042, 0x1ae5,
+ 0x6043, 0x072a,
+ 0x6044, 0x1ae8,
+ 0x6045, 0x1ade,
+ 0x6046, 0x0729,
+ 0x6047, 0x1ae0,
+ 0x6049, 0x1ae1,
+ 0x604a, 0x4074,
+ 0x604c, 0x1ae3,
+ 0x604d, 0x0725,
+ 0x6050, 0x08b5,
+ 0x6052, 0x36ec,
+ 0x6053, 0x1adf,
+ 0x6054, 0x1adb,
+ 0x6055, 0x08b6,
+ 0x6058, 0x1ae9,
+ 0x6059, 0x08b2,
+ 0x605a, 0x1c90,
+ 0x605b, 0x1ae2,
+ 0x605d, 0x1c8f,
+ 0x605e, 0x1add,
+ 0x605f, 0x1ae6,
+ 0x6062, 0x0728,
+ 0x6063, 0x08b3,
+ 0x6064, 0x072e,
+ 0x6065, 0x08b4,
+ 0x6066, 0x1aea,
+ 0x6067, 0x1c91,
+ 0x6068, 0x0727,
+ 0x6069, 0x08b8,
+ 0x606a, 0x072d,
+ 0x606b, 0x072c,
+ 0x606c, 0x072b,
+ 0x606d, 0x08b7,
+ 0x606e, 0x1aeb,
+ 0x606f, 0x08b9,
+ 0x6070, 0x0726,
+ 0x6072, 0x1adc,
+ 0x6075, 0x3a56,
+ 0x6077, 0x4005,
+ 0x607e, 0x3a47,
+ 0x607f, 0x0a82,
+ 0x6080, 0x1c95,
+ 0x6081, 0x1c97,
+ 0x6083, 0x1c99,
+ 0x6084, 0x08ba,
+ 0x6085, 0x08c0,
+ 0x6086, 0x1eda,
+ 0x6087, 0x1c9d,
+ 0x6088, 0x1c94,
+ 0x6089, 0x0a84,
+ 0x608a, 0x1ed8,
+ 0x608c, 0x08bf,
+ 0x608d, 0x08bd,
+ 0x608e, 0x1c9f,
+ 0x6090, 0x1ed9,
+ 0x6092, 0x1c96,
+ 0x6094, 0x08be,
+ 0x6095, 0x1c9a,
+ 0x6096, 0x08c1,
+ 0x6097, 0x1c9c,
+ 0x609a, 0x08bc,
+ 0x609b, 0x1c9b,
+ 0x609c, 0x1c9e,
+ 0x609d, 0x1c98,
+ 0x609e, 0x416a,
+ 0x609f, 0x08bb,
+ 0x60a0, 0x0a85,
+ 0x60a2, 0x1c93,
+ 0x60a3, 0x0a83,
+ 0x60a4, 0x4001,
+ 0x60a7, 0x3adc,
+ 0x60a8, 0x0a86,
+ 0x60b0, 0x1edc,
+ 0x60b1, 0x1ee5,
+ 0x60b2, 0x0c47,
+ 0x60b3, 0x416c,
+ 0x60b4, 0x0a88,
+ 0x60b5, 0x0a8d,
+ 0x60b6, 0x0c48,
+ 0x60b7, 0x1ee7,
+ 0x60b8, 0x0a94,
+ 0x60b9, 0x2134,
+ 0x60ba, 0x1edd,
+ 0x60bb, 0x0a8c,
+ 0x60bc, 0x0a8f,
+ 0x60bd, 0x0a8a,
+ 0x60be, 0x1edb,
+ 0x60bf, 0x1ee9,
+ 0x60c0, 0x1eec,
+ 0x60c1, 0x2143,
+ 0x60c3, 0x1eea,
+ 0x60c4, 0x2138,
+ 0x60c5, 0x0a8b,
+ 0x60c6, 0x0a92,
+ 0x60c7, 0x0a96,
+ 0x60c8, 0x1ee4,
+ 0x60c9, 0x2133,
+ 0x60ca, 0x1ee8,
+ 0x60cb, 0x0a87,
+ 0x60cc, 0x2135,
+ 0x60cd, 0x1eeb,
+ 0x60ce, 0x2137,
+ 0x60cf, 0x1ee0,
+ 0x60d1, 0x0c45,
+ 0x60d3, 0x1ede,
+ 0x60d5, 0x0a91,
+ 0x60d7, 0x4635,
+ 0x60d8, 0x0a90,
+ 0x60d9, 0x1ee2,
+ 0x60da, 0x0a95,
+ 0x60db, 0x1ee6,
+ 0x60dc, 0x0a8e,
+ 0x60dd, 0x1ee3,
+ 0x60de, 0x3dcc,
+ 0x60df, 0x0a93,
+ 0x60e0, 0x0c49,
+ 0x60e1, 0x0c46,
+ 0x60e2, 0x2136,
+ 0x60e3, 0x3d75,
+ 0x60e4, 0x1ee1,
+ 0x60e6, 0x0a89,
+ 0x60e7, 0x3d84,
+ 0x60e8, 0x3d7b,
+ 0x60e9, 0x4009,
+ 0x60f0, 0x0c4e,
+ 0x60f1, 0x0c52,
+ 0x60f2, 0x213a,
+ 0x60f3, 0x0e0b,
+ 0x60f4, 0x0c50,
+ 0x60f5, 0x213e,
+ 0x60f6, 0x0c54,
+ 0x60f7, 0x23d4,
+ 0x60f8, 0x2140,
+ 0x60f9, 0x0e0d,
+ 0x60fa, 0x0c4c,
+ 0x60fb, 0x0c4f,
+ 0x60fc, 0x2141,
+ 0x60fd, 0x3fa8,
+ 0x60fe, 0x2142,
+ 0x60ff, 0x2148,
+ 0x6100, 0x0c56,
+ 0x6101, 0x0e0e,
+ 0x6103, 0x2144,
+ 0x6104, 0x2149,
+ 0x6105, 0x213d,
+ 0x6106, 0x0e18,
+ 0x6107, 0x3c35,
+ 0x6108, 0x0e0f,
+ 0x6109, 0x0c55,
+ 0x610a, 0x213b,
+ 0x610b, 0x214a,
+ 0x610c, 0x3c87,
+ 0x610d, 0x0e17,
+ 0x610e, 0x0c53,
+ 0x610f, 0x0e08,
+ 0x6110, 0x2147,
+ 0x6112, 0x0c57,
+ 0x6113, 0x213f,
+ 0x6114, 0x2139,
+ 0x6115, 0x0c4d,
+ 0x6116, 0x213c,
+ 0x6118, 0x2145,
+ 0x6119, 0x3ef6,
+ 0x611a, 0x0e07,
+ 0x611b, 0x0e0c,
+ 0x611c, 0x0c4a,
+ 0x611d, 0x2146,
+ 0x611f, 0x0e0a,
+ 0x6123, 0x0c4b,
+ 0x6127, 0x0e16,
+ 0x6128, 0x2683,
+ 0x6129, 0x23df,
+ 0x612b, 0x23d7,
+ 0x612c, 0x2682,
+ 0x612e, 0x23db,
+ 0x612f, 0x23dd,
+ 0x6130, 0x3f37,
+ 0x6132, 0x23da,
+ 0x6134, 0x0e15,
+ 0x6136, 0x23d9,
+ 0x6137, 0x0e19,
+ 0x613b, 0x2692,
+ 0x613d, 0x4636,
+ 0x613e, 0x0e14,
+ 0x613f, 0x0fd1,
+ 0x6140, 0x23e0,
+ 0x6141, 0x2684,
+ 0x6142, 0x4174,
+ 0x6144, 0x0e12,
+ 0x6145, 0x23d8,
+ 0x6146, 0x23dc,
+ 0x6147, 0x0fd0,
+ 0x6148, 0x0e09,
+ 0x6149, 0x23d5,
+ 0x614b, 0x0fd2,
+ 0x614c, 0x0e11,
+ 0x614d, 0x0e13,
+ 0x614e, 0x0e10,
+ 0x614f, 0x23de,
+ 0x6150, 0x3c32,
+ 0x6152, 0x2688,
+ 0x6154, 0x268e,
+ 0x6155, 0x1149,
+ 0x6156, 0x2695,
+ 0x6158, 0x0fd8,
+ 0x6159, 0x3fba,
+ 0x615a, 0x0fd7,
+ 0x615b, 0x2690,
+ 0x615c, 0x4186,
+ 0x615d, 0x1148,
+ 0x615e, 0x2685,
+ 0x615f, 0x0fd6,
+ 0x6160, 0x494c,
+ 0x6161, 0x2694,
+ 0x6162, 0x0fd4,
+ 0x6164, 0x4173,
+ 0x6165, 0x2691,
+ 0x6166, 0x28de,
+ 0x6167, 0x1146,
+ 0x6168, 0x0c51,
+ 0x616a, 0x2693,
+ 0x616b, 0x114d,
+ 0x616c, 0x268b,
+ 0x616e, 0x1147,
+ 0x616f, 0x3fc0,
+ 0x6170, 0x114c,
+ 0x6171, 0x2686,
+ 0x6172, 0x268a,
+ 0x6173, 0x2687,
+ 0x6174, 0x268d,
+ 0x6175, 0x0fd9,
+ 0x6176, 0x1145,
+ 0x6177, 0x0fd3,
+ 0x6179, 0x28d0,
+ 0x617a, 0x268f,
+ 0x617c, 0x114b,
+ 0x617d, 0x3fbd,
+ 0x617e, 0x114e,
+ 0x6180, 0x268c,
+ 0x6181, 0x4177,
+ 0x6182, 0x114a,
+ 0x6183, 0x28cf,
+ 0x6187, 0x417a,
+ 0x6189, 0x28d4,
+ 0x618a, 0x12b1,
+ 0x618b, 0x28ce,
+ 0x618c, 0x2b4d,
+ 0x618d, 0x28dd,
+ 0x618e, 0x1152,
+ 0x6190, 0x1150,
+ 0x6191, 0x12af,
+ 0x6192, 0x28da,
+ 0x6193, 0x28d6,
+ 0x6194, 0x1156,
+ 0x6195, 0x3de0,
+ 0x6196, 0x2b44,
+ 0x6198, 0x3a55,
+ 0x6199, 0x3a54,
+ 0x619a, 0x1154,
+ 0x619b, 0x28d5,
+ 0x619c, 0x4002,
+ 0x619d, 0x2b42,
+ 0x619f, 0x28d9,
+ 0x61a1, 0x28dc,
+ 0x61a2, 0x28d3,
+ 0x61a4, 0x1155,
+ 0x61a7, 0x114f,
+ 0x61a8, 0x2b43,
+ 0x61a9, 0x12b0,
+ 0x61aa, 0x28db,
+ 0x61ab, 0x1151,
+ 0x61ac, 0x1153,
+ 0x61ad, 0x28d8,
+ 0x61ae, 0x1157,
+ 0x61af, 0x28d7,
+ 0x61b0, 0x28d2,
+ 0x61b1, 0x28d1,
+ 0x61b2, 0x12ae,
+ 0x61b3, 0x28df,
+ 0x61b4, 0x2b46,
+ 0x61b5, 0x2d60,
+ 0x61b6, 0x12b3,
+ 0x61b7, 0x4639,
+ 0x61b8, 0x2b4c,
+ 0x61b9, 0x43bf,
+ 0x61ba, 0x2b4a,
+ 0x61bc, 0x2d61,
+ 0x61be, 0x12b4,
+ 0x61bf, 0x2b4b,
+ 0x61c0, 0x3a50,
+ 0x61c1, 0x2b48,
+ 0x61c2, 0x13d1,
+ 0x61c3, 0x2d5f,
+ 0x61c5, 0x2b45,
+ 0x61c6, 0x2b47,
+ 0x61c7, 0x13d2,
+ 0x61c8, 0x12b6,
+ 0x61c9, 0x13d0,
+ 0x61ca, 0x12b5,
+ 0x61cb, 0x13d4,
+ 0x61cc, 0x2b49,
+ 0x61cd, 0x12b2,
+ 0x61cf, 0x463a,
+ 0x61d0, 0x4181,
+ 0x61d3, 0x417e,
+ 0x61d6, 0x2f26,
+ 0x61d8, 0x2f1e,
+ 0x61da, 0x38b1,
+ 0x61de, 0x2d67,
+ 0x61df, 0x2f1f,
+ 0x61e0, 0x2d63,
+ 0x61e2, 0x3fc5,
+ 0x61e3, 0x14d0,
+ 0x61e4, 0x2d65,
+ 0x61e5, 0x2d64,
+ 0x61e6, 0x13d3,
+ 0x61e7, 0x2d62,
+ 0x61e8, 0x2d66,
+ 0x61e9, 0x2f27,
+ 0x61ea, 0x2f23,
+ 0x61eb, 0x2f25,
+ 0x61ed, 0x2f20,
+ 0x61f0, 0x2f24,
+ 0x61f1, 0x2f22,
+ 0x61f2, 0x157e,
+ 0x61f5, 0x1581,
+ 0x61f6, 0x1580,
+ 0x61f7, 0x157f,
+ 0x61f8, 0x1614,
+ 0x61f9, 0x31d3,
+ 0x61fa, 0x1615,
+ 0x61fb, 0x308f,
+ 0x61fc, 0x1670,
+ 0x61fd, 0x32d1,
+ 0x61fe, 0x1671,
+ 0x61ff, 0x16c4,
+ 0x6200, 0x16f8,
+ 0x6201, 0x3417,
+ 0x6203, 0x3418,
+ 0x6207, 0x3533,
+ 0x6208, 0x02d1,
+ 0x6209, 0x17a8,
+ 0x620a, 0x0341,
+ 0x620c, 0x03d1,
+ 0x620e, 0x03d0,
+ 0x6210, 0x03d3,
+ 0x6211, 0x04a2,
+ 0x6212, 0x04a1,
+ 0x6214, 0x1991,
+ 0x6215, 0x05d1,
+ 0x6216, 0x05d0,
+ 0x6219, 0x1ca0,
+ 0x621a, 0x0a97,
+ 0x621f, 0x0c58,
+ 0x6220, 0x23e1,
+ 0x6221, 0x0e1a,
+ 0x6223, 0x23e3,
+ 0x6224, 0x23e5,
+ 0x6225, 0x23e4,
+ 0x6227, 0x2697,
+ 0x6229, 0x2696,
+ 0x622a, 0x0fda,
+ 0x622b, 0x2698,
+ 0x622c, 0x463c,
+ 0x622d, 0x28e0,
+ 0x622e, 0x1158,
+ 0x6230, 0x12b7,
+ 0x6232, 0x13d5,
+ 0x6233, 0x14d1,
+ 0x6234, 0x13d6,
+ 0x6236, 0x02d2,
+ 0x6237, 0x451a,
+ 0x6239, 0x3fc2,
+ 0x623a, 0x188d,
+ 0x623d, 0x1992,
+ 0x623e, 0x05d3,
+ 0x623f, 0x05d2,
+ 0x6240, 0x05d4,
+ 0x6241, 0x072f,
+ 0x6242, 0x1aec,
+ 0x6246, 0x1ca1,
+ 0x6247, 0x08c2,
+ 0x6248, 0x0a99,
+ 0x6249, 0x0c59,
+ 0x624a, 0x214b,
+ 0x624b, 0x02d3,
+ 0x624c, 0x44ec,
+ 0x624d, 0x0291,
+ 0x624e, 0x02d4,
+ 0x6250, 0x17a9,
+ 0x6251, 0x0345,
+ 0x6252, 0x0344,
+ 0x6253, 0x0342,
+ 0x6258, 0x03d6,
+ 0x6259, 0x17f2,
+ 0x625a, 0x17f4,
+ 0x625b, 0x03d5,
+ 0x625c, 0x17ec,
+ 0x625e, 0x17ed,
+ 0x6260, 0x17f3,
+ 0x6261, 0x17ef,
+ 0x6262, 0x17f1,
+ 0x6263, 0x03d4,
+ 0x6264, 0x17ee,
+ 0x6265, 0x17f5,
+ 0x6266, 0x17f0,
+ 0x6268, 0x3f15,
+ 0x626d, 0x04a9,
+ 0x626e, 0x04b2,
+ 0x626f, 0x04b0,
+ 0x6270, 0x1897,
+ 0x6271, 0x1894,
+ 0x6272, 0x189c,
+ 0x6273, 0x04ae,
+ 0x6274, 0x189d,
+ 0x6276, 0x04a7,
+ 0x6277, 0x189a,
+ 0x6279, 0x04ad,
+ 0x627a, 0x1896,
+ 0x627b, 0x1895,
+ 0x627c, 0x04ab,
+ 0x627d, 0x189b,
+ 0x627e, 0x04ac,
+ 0x627f, 0x05d5,
+ 0x6280, 0x04a6,
+ 0x6281, 0x1898,
+ 0x6282, 0x3f86,
+ 0x6283, 0x188e,
+ 0x6284, 0x04a3,
+ 0x6285, 0x3f50,
+ 0x6286, 0x04b6,
+ 0x6287, 0x1893,
+ 0x6288, 0x1899,
+ 0x6289, 0x04a8,
+ 0x628a, 0x04aa,
+ 0x628c, 0x188f,
+ 0x628e, 0x1890,
+ 0x6290, 0x43c0,
+ 0x6291, 0x04b5,
+ 0x6292, 0x04af,
+ 0x6293, 0x04b4,
+ 0x6294, 0x1892,
+ 0x6295, 0x04b3,
+ 0x6296, 0x04a5,
+ 0x6297, 0x04a4,
+ 0x6298, 0x04b1,
+ 0x629d, 0x3e96,
+ 0x62a4, 0x3a69,
+ 0x62a6, 0x3fc1,
+ 0x62a8, 0x05e3,
+ 0x62a9, 0x199e,
+ 0x62aa, 0x1997,
+ 0x62ab, 0x05de,
+ 0x62ac, 0x05f1,
+ 0x62ad, 0x1993,
+ 0x62ae, 0x199a,
+ 0x62af, 0x199c,
+ 0x62b0, 0x199f,
+ 0x62b1, 0x05ec,
+ 0x62b3, 0x199b,
+ 0x62b4, 0x1994,
+ 0x62b5, 0x05ea,
+ 0x62b6, 0x1998,
+ 0x62b8, 0x19a0,
+ 0x62b9, 0x05db,
+ 0x62bb, 0x199d,
+ 0x62bc, 0x05e5,
+ 0x62bd, 0x05e4,
+ 0x62be, 0x1996,
+ 0x62bf, 0x05d9,
+ 0x62c2, 0x05da,
+ 0x62c3, 0x3d8f,
+ 0x62c4, 0x05d8,
+ 0x62c5, 0x418a,
+ 0x62c6, 0x05f0,
+ 0x62c7, 0x05e8,
+ 0x62c8, 0x05e2,
+ 0x62c9, 0x05d6,
+ 0x62ca, 0x1999,
+ 0x62cb, 0x05e1,
+ 0x62cc, 0x05d7,
+ 0x62cd, 0x05e9,
+ 0x62ce, 0x05f2,
+ 0x62cf, 0x1aee,
+ 0x62d0, 0x05e6,
+ 0x62d1, 0x1995,
+ 0x62d2, 0x05dc,
+ 0x62d3, 0x05df,
+ 0x62d5, 0x418c,
+ 0x62d6, 0x05ee,
+ 0x62d8, 0x05ed,
+ 0x62d9, 0x05e7,
+ 0x62da, 0x05eb,
+ 0x62db, 0x05dd,
+ 0x62dc, 0x0730,
+ 0x62df, 0x401c,
+ 0x62e5, 0x463d,
+ 0x62eb, 0x1af4,
+ 0x62ec, 0x073c,
+ 0x62ed, 0x0734,
+ 0x62ee, 0x0736,
+ 0x62ef, 0x073b,
+ 0x62f0, 0x1b00,
+ 0x62f1, 0x0739,
+ 0x62f2, 0x1ca2,
+ 0x62f3, 0x08c3,
+ 0x62f4, 0x073e,
+ 0x62f5, 0x1af1,
+ 0x62f6, 0x1af9,
+ 0x62f7, 0x073a,
+ 0x62f8, 0x1af8,
+ 0x62f9, 0x1af5,
+ 0x62fa, 0x1afd,
+ 0x62fb, 0x1aff,
+ 0x62fc, 0x0733,
+ 0x62fd, 0x0737,
+ 0x62fe, 0x073d,
+ 0x62ff, 0x08c5,
+ 0x6300, 0x1afa,
+ 0x6301, 0x0735,
+ 0x6302, 0x0740,
+ 0x6303, 0x1af3,
+ 0x6307, 0x0738,
+ 0x6308, 0x08c4,
+ 0x6309, 0x0732,
+ 0x630b, 0x1af0,
+ 0x630c, 0x1af7,
+ 0x630d, 0x1aef,
+ 0x630e, 0x1af2,
+ 0x630f, 0x1af6,
+ 0x6310, 0x1ca3,
+ 0x6311, 0x073f,
+ 0x6313, 0x1afb,
+ 0x6315, 0x1afe,
+ 0x6316, 0x0731,
+ 0x6318, 0x43c1,
+ 0x6328, 0x08d3,
+ 0x6329, 0x1caf,
+ 0x632a, 0x08d1,
+ 0x632c, 0x1ca5,
+ 0x632d, 0x1cb5,
+ 0x632e, 0x3edd,
+ 0x632f, 0x08c8,
+ 0x6331, 0x3a65,
+ 0x6332, 0x1eed,
+ 0x6333, 0x1cb7,
+ 0x6334, 0x1cb1,
+ 0x6335, 0x3f16,
+ 0x6336, 0x1ca8,
+ 0x6337, 0x3a63,
+ 0x6338, 0x1cba,
+ 0x6339, 0x1cab,
+ 0x633a, 0x08ce,
+ 0x633b, 0x1f04,
+ 0x633c, 0x1cae,
+ 0x633d, 0x08d0,
+ 0x633e, 0x08c7,
+ 0x6340, 0x1cbc,
+ 0x6341, 0x1cb0,
+ 0x6342, 0x08ca,
+ 0x6343, 0x1ca9,
+ 0x6344, 0x1ca6,
+ 0x6346, 0x08cb,
+ 0x6347, 0x1cb6,
+ 0x6348, 0x1cbd,
+ 0x6349, 0x08cd,
+ 0x634a, 0x1cad,
+ 0x634b, 0x1cac,
+ 0x634c, 0x08d5,
+ 0x634d, 0x08d4,
+ 0x634e, 0x08c6,
+ 0x634f, 0x08cc,
+ 0x6350, 0x08cf,
+ 0x6351, 0x1cb9,
+ 0x6354, 0x1cb3,
+ 0x6355, 0x08c9,
+ 0x6356, 0x1ca4,
+ 0x6357, 0x1cbb,
+ 0x6358, 0x1cb2,
+ 0x6359, 0x1cb4,
+ 0x635a, 0x1cb8,
+ 0x6364, 0x3fc7,
+ 0x6365, 0x1eee,
+ 0x6367, 0x0aa1,
+ 0x6368, 0x0ab5,
+ 0x6369, 0x0ab4,
+ 0x636b, 0x0aa9,
+ 0x636c, 0x418e,
+ 0x636d, 0x1f00,
+ 0x636e, 0x1efc,
+ 0x636f, 0x1ef9,
+ 0x6370, 0x1f0b,
+ 0x6371, 0x0aa4,
+ 0x6372, 0x0a9c,
+ 0x6375, 0x1efe,
+ 0x6376, 0x0c69,
+ 0x6377, 0x0aa0,
+ 0x6378, 0x1f06,
+ 0x6379, 0x4367,
+ 0x637a, 0x0ab6,
+ 0x637b, 0x0ab3,
+ 0x637c, 0x1f02,
+ 0x637d, 0x1ef1,
+ 0x637f, 0x3f4b,
+ 0x6380, 0x0ab2,
+ 0x6381, 0x1f08,
+ 0x6382, 0x1ef0,
+ 0x6383, 0x0aa7,
+ 0x6384, 0x0aab,
+ 0x6385, 0x1f07,
+ 0x6387, 0x1efa,
+ 0x6388, 0x0aac,
+ 0x6389, 0x0aa6,
+ 0x638a, 0x1eef,
+ 0x638b, 0x4188,
+ 0x638c, 0x0c5b,
+ 0x638d, 0x1f0a,
+ 0x638e, 0x1ef8,
+ 0x638f, 0x0ab1,
+ 0x6390, 0x1efb,
+ 0x6391, 0x1f09,
+ 0x6392, 0x0ab0,
+ 0x6394, 0x214c,
+ 0x6396, 0x0a9d,
+ 0x6397, 0x1ef6,
+ 0x6398, 0x0aa2,
+ 0x6399, 0x0aad,
+ 0x639b, 0x0aa8,
+ 0x639c, 0x1eff,
+ 0x639d, 0x1ef5,
+ 0x639e, 0x1ef3,
+ 0x639f, 0x1f05,
+ 0x63a0, 0x0a9a,
+ 0x63a1, 0x0aae,
+ 0x63a2, 0x0a9e,
+ 0x63a3, 0x0c5a,
+ 0x63a4, 0x1f03,
+ 0x63a5, 0x0a9f,
+ 0x63a7, 0x0a9b,
+ 0x63a8, 0x0aaa,
+ 0x63a9, 0x0aa5,
+ 0x63aa, 0x0aa3,
+ 0x63ab, 0x1ef7,
+ 0x63ac, 0x0aaf,
+ 0x63ad, 0x1ef4,
+ 0x63ae, 0x1f01,
+ 0x63af, 0x1efd,
+ 0x63b0, 0x214e,
+ 0x63b1, 0x214d,
+ 0x63b9, 0x3e9d,
+ 0x63bd, 0x1ef2,
+ 0x63be, 0x215e,
+ 0x63c0, 0x0c5d,
+ 0x63c1, 0x46a8,
+ 0x63c2, 0x2164,
+ 0x63c3, 0x2153,
+ 0x63c4, 0x2161,
+ 0x63c5, 0x23e6,
+ 0x63c6, 0x0c60,
+ 0x63c7, 0x2165,
+ 0x63c8, 0x2168,
+ 0x63c9, 0x0c5f,
+ 0x63ca, 0x2156,
+ 0x63cb, 0x2167,
+ 0x63cc, 0x2166,
+ 0x63cd, 0x0c61,
+ 0x63ce, 0x214f,
+ 0x63cf, 0x0c5c,
+ 0x63d0, 0x0c64,
+ 0x63d1, 0x3a66,
+ 0x63d2, 0x0c62,
+ 0x63d3, 0x2163,
+ 0x63d5, 0x2159,
+ 0x63d6, 0x0c66,
+ 0x63d7, 0x216a,
+ 0x63d8, 0x2162,
+ 0x63d9, 0x216b,
+ 0x63da, 0x0c6e,
+ 0x63db, 0x0c6c,
+ 0x63dc, 0x2160,
+ 0x63dd, 0x215f,
+ 0x63de, 0x3e60,
+ 0x63df, 0x215d,
+ 0x63e0, 0x2157,
+ 0x63e1, 0x0c65,
+ 0x63e2, 0x4641,
+ 0x63e3, 0x0c63,
+ 0x63e4, 0x1caa,
+ 0x63e5, 0x2150,
+ 0x63e6, 0x489f,
+ 0x63e7, 0x2404,
+ 0x63e8, 0x2151,
+ 0x63e9, 0x0c5e,
+ 0x63ea, 0x0c6b,
+ 0x63eb, 0x23e8,
+ 0x63ed, 0x0c67,
+ 0x63ef, 0x2152,
+ 0x63f0, 0x2169,
+ 0x63f1, 0x23e7,
+ 0x63f2, 0x215a,
+ 0x63f3, 0x2155,
+ 0x63f4, 0x0c6a,
+ 0x63f5, 0x215b,
+ 0x63f6, 0x2158,
+ 0x63f8, 0x4192,
+ 0x63f9, 0x0c6f,
+ 0x63fb, 0x4642,
+ 0x63fc, 0x3e9c,
+ 0x63fe, 0x3e9e,
+ 0x6406, 0x0e2a,
+ 0x6407, 0x4643,
+ 0x6409, 0x23eb,
+ 0x640a, 0x23fe,
+ 0x640b, 0x2403,
+ 0x640c, 0x23f7,
+ 0x640d, 0x0e26,
+ 0x640e, 0x2408,
+ 0x640f, 0x0e23,
+ 0x6410, 0x23e9,
+ 0x6412, 0x23ea,
+ 0x6413, 0x0e1c,
+ 0x6414, 0x0e25,
+ 0x6415, 0x23f1,
+ 0x6416, 0x0e28,
+ 0x6418, 0x23f2,
+ 0x641a, 0x23ff,
+ 0x641b, 0x2405,
+ 0x641c, 0x0e24,
+ 0x641e, 0x0e1e,
+ 0x641f, 0x23f0,
+ 0x6420, 0x23ec,
+ 0x6421, 0x2407,
+ 0x6422, 0x23f5,
+ 0x6424, 0x23ed,
+ 0x6425, 0x2401,
+ 0x6426, 0x23f8,
+ 0x6427, 0x2402,
+ 0x6428, 0x23fa,
+ 0x642a, 0x0e1f,
+ 0x642b, 0x2699,
+ 0x642c, 0x0e22,
+ 0x642d, 0x0e20,
+ 0x642e, 0x2406,
+ 0x642f, 0x23fd,
+ 0x6430, 0x23f9,
+ 0x6432, 0x45d9,
+ 0x6433, 0x23ee,
+ 0x6434, 0x0fe4,
+ 0x6435, 0x23fc,
+ 0x6436, 0x0e27,
+ 0x6437, 0x23f4,
+ 0x6438, 0x4191,
+ 0x6439, 0x23f3,
+ 0x643a, 0x419d,
+ 0x643b, 0x3a6b,
+ 0x643d, 0x0e21,
+ 0x643e, 0x0e1d,
+ 0x643f, 0x26ae,
+ 0x6440, 0x2400,
+ 0x6441, 0x23fb,
+ 0x6443, 0x23ef,
+ 0x644b, 0x26a9,
+ 0x644d, 0x269a,
+ 0x644e, 0x26a5,
+ 0x6450, 0x26ac,
+ 0x6451, 0x0fe2,
+ 0x6452, 0x0c6d,
+ 0x6453, 0x26aa,
+ 0x6454, 0x0fdd,
+ 0x6458, 0x0fdc,
+ 0x6459, 0x26b1,
+ 0x645a, 0x43c2,
+ 0x645b, 0x269b,
+ 0x645c, 0x26a8,
+ 0x645d, 0x269c,
+ 0x645e, 0x26a7,
+ 0x645f, 0x0fe0,
+ 0x6460, 0x26ab,
+ 0x6461, 0x215c,
+ 0x6465, 0x26b2,
+ 0x6466, 0x26a3,
+ 0x6467, 0x0fe3,
+ 0x6468, 0x28ee,
+ 0x6469, 0x1159,
+ 0x646b, 0x26b0,
+ 0x646c, 0x26af,
+ 0x646d, 0x0fe5,
+ 0x646e, 0x28e1,
+ 0x646f, 0x115a,
+ 0x6470, 0x28e2,
+ 0x6471, 0x3a5b,
+ 0x6472, 0x269f,
+ 0x6474, 0x269d,
+ 0x6475, 0x26a2,
+ 0x6476, 0x269e,
+ 0x6477, 0x26b3,
+ 0x6478, 0x0fdf,
+ 0x6479, 0x115b,
+ 0x647a, 0x0fe1,
+ 0x647b, 0x0fe6,
+ 0x647c, 0x436c,
+ 0x647d, 0x26a1,
+ 0x647f, 0x26ad,
+ 0x6482, 0x26a6,
+ 0x6485, 0x28e5,
+ 0x6487, 0x0fdb,
+ 0x6488, 0x115e,
+ 0x6489, 0x2b54,
+ 0x648a, 0x28ea,
+ 0x648b, 0x28e9,
+ 0x648c, 0x28eb,
+ 0x648d, 0x4323,
+ 0x648f, 0x28e8,
+ 0x6490, 0x115f,
+ 0x6491, 0x43c3,
+ 0x6492, 0x1165,
+ 0x6493, 0x1162,
+ 0x6495, 0x1163,
+ 0x6496, 0x28e3,
+ 0x6497, 0x28e6,
+ 0x6498, 0x28f0,
+ 0x6499, 0x116b,
+ 0x649a, 0x1169,
+ 0x649c, 0x28e7,
+ 0x649d, 0x2154,
+ 0x649e, 0x115c,
+ 0x649f, 0x28ed,
+ 0x64a0, 0x28e4,
+ 0x64a2, 0x116c,
+ 0x64a3, 0x28ec,
+ 0x64a4, 0x0fde,
+ 0x64a5, 0x1161,
+ 0x64a6, 0x26a4,
+ 0x64a9, 0x1164,
+ 0x64ab, 0x1168,
+ 0x64ac, 0x116a,
+ 0x64ad, 0x1167,
+ 0x64ae, 0x1166,
+ 0x64af, 0x42e1,
+ 0x64b0, 0x1160,
+ 0x64b1, 0x28ef,
+ 0x64b2, 0x115d,
+ 0x64b3, 0x116d,
+ 0x64b4, 0x4340,
+ 0x64b6, 0x3a64,
+ 0x64bb, 0x12bb,
+ 0x64bd, 0x2b53,
+ 0x64be, 0x12c5,
+ 0x64bf, 0x12c2,
+ 0x64c0, 0x4645,
+ 0x64c1, 0x12b9,
+ 0x64c2, 0x12c0,
+ 0x64c3, 0x2b55,
+ 0x64c4, 0x12be,
+ 0x64c5, 0x12b8,
+ 0x64c7, 0x12bf,
+ 0x64c9, 0x2b52,
+ 0x64ca, 0x13d8,
+ 0x64cb, 0x12ba,
+ 0x64cd, 0x12c1,
+ 0x64ce, 0x13d7,
+ 0x64cf, 0x2b51,
+ 0x64d0, 0x2b50,
+ 0x64d2, 0x12c3,
+ 0x64d3, 0x3f03,
+ 0x64d4, 0x12c4,
+ 0x64d6, 0x2b4f,
+ 0x64d7, 0x2b4e,
+ 0x64d8, 0x13d9,
+ 0x64d9, 0x2b58,
+ 0x64da, 0x12bd,
+ 0x64db, 0x2b56,
+ 0x64dd, 0x431e,
+ 0x64e0, 0x13da,
+ 0x64e1, 0x4199,
+ 0x64e2, 0x13df,
+ 0x64e3, 0x2d6a,
+ 0x64e4, 0x2d6c,
+ 0x64e5, 0x419a,
+ 0x64e6, 0x13dc,
+ 0x64e7, 0x37a8,
+ 0x64e8, 0x2d6d,
+ 0x64e9, 0x2d69,
+ 0x64ea, 0x434a,
+ 0x64eb, 0x2d6b,
+ 0x64ec, 0x13dd,
+ 0x64ed, 0x13e0,
+ 0x64ef, 0x2d68,
+ 0x64f0, 0x13db,
+ 0x64f1, 0x13de,
+ 0x64f2, 0x14d3,
+ 0x64f3, 0x2b57,
+ 0x64f4, 0x14d2,
+ 0x64f7, 0x14d8,
+ 0x64f8, 0x2f2b,
+ 0x64fa, 0x14d6,
+ 0x64fc, 0x2f2e,
+ 0x64fd, 0x2f2a,
+ 0x64fe, 0x14d4,
+ 0x64ff, 0x2f28,
+ 0x6500, 0x1582,
+ 0x6501, 0x2f2c,
+ 0x6503, 0x2f2d,
+ 0x6504, 0x2f29,
+ 0x6506, 0x14d5,
+ 0x6507, 0x3090,
+ 0x6509, 0x3093,
+ 0x650a, 0x4536,
+ 0x650c, 0x3094,
+ 0x650d, 0x3092,
+ 0x650e, 0x3095,
+ 0x650f, 0x1583,
+ 0x6510, 0x3091,
+ 0x6511, 0x3aa9,
+ 0x6513, 0x31d7,
+ 0x6514, 0x1617,
+ 0x6515, 0x31d6,
+ 0x6516, 0x31d5,
+ 0x6517, 0x31d4,
+ 0x6518, 0x1616,
+ 0x6519, 0x1618,
+ 0x651b, 0x32d2,
+ 0x651c, 0x1673,
+ 0x651d, 0x1672,
+ 0x651e, 0x4187,
+ 0x651f, 0x3ec0,
+ 0x6520, 0x3382,
+ 0x6521, 0x3381,
+ 0x6522, 0x3384,
+ 0x6523, 0x16f9,
+ 0x6524, 0x16c5,
+ 0x6525, 0x341b,
+ 0x6526, 0x3383,
+ 0x6529, 0x341a,
+ 0x652a, 0x16fb,
+ 0x652b, 0x16fa,
+ 0x652c, 0x1721,
+ 0x652d, 0x3484,
+ 0x652e, 0x34ca,
+ 0x652f, 0x02d5,
+ 0x6530, 0x3e62,
+ 0x6532, 0x216c,
+ 0x6533, 0x2b59,
+ 0x6534, 0x022c,
+ 0x6535, 0x44ed,
+ 0x6536, 0x03d7,
+ 0x6537, 0x17f6,
+ 0x6538, 0x04b9,
+ 0x6539, 0x04b7,
+ 0x653b, 0x04b8,
+ 0x653d, 0x19a1,
+ 0x653e, 0x05f3,
+ 0x653f, 0x0741,
+ 0x6541, 0x1b01,
+ 0x6543, 0x1b02,
+ 0x6545, 0x0742,
+ 0x6546, 0x1cbf,
+ 0x6548, 0x08d6,
+ 0x654a, 0x1cbe,
+ 0x654d, 0x419f,
+ 0x654f, 0x0abd,
+ 0x6551, 0x0ab9,
+ 0x6553, 0x1f0c,
+ 0x6554, 0x0ac0,
+ 0x6555, 0x0abf,
+ 0x6556, 0x0ab8,
+ 0x6557, 0x0abb,
+ 0x6558, 0x0abe,
+ 0x6559, 0x0aba,
+ 0x655c, 0x2170,
+ 0x655d, 0x0ab7,
+ 0x655e, 0x0c70,
+ 0x655f, 0x41a5,
+ 0x6562, 0x0c72,
+ 0x6564, 0x216f,
+ 0x6565, 0x2172,
+ 0x6566, 0x0c71,
+ 0x6567, 0x216d,
+ 0x6568, 0x2171,
+ 0x656a, 0x216e,
+ 0x656b, 0x3a6c,
+ 0x656c, 0x0e2b,
+ 0x656d, 0x41a4,
+ 0x656f, 0x2409,
+ 0x6572, 0x0fe7,
+ 0x6573, 0x26b4,
+ 0x6574, 0x12c6,
+ 0x6575, 0x116e,
+ 0x6576, 0x28f1,
+ 0x6577, 0x116f,
+ 0x6579, 0x28f3,
+ 0x657a, 0x28f2,
+ 0x657b, 0x28f4,
+ 0x657c, 0x2b5b,
+ 0x657f, 0x2b5a,
+ 0x6580, 0x2d6f,
+ 0x6581, 0x2d6e,
+ 0x6582, 0x13e1,
+ 0x6584, 0x3096,
+ 0x6585, 0x41a3,
+ 0x6586, 0x4648,
+ 0x6587, 0x02d6,
+ 0x6588, 0x410b,
+ 0x6589, 0x4554,
+ 0x658c, 0x2173,
+ 0x6590, 0x0c75,
+ 0x6591, 0x0c74,
+ 0x6592, 0x240a,
+ 0x6594, 0x2f2f,
+ 0x6595, 0x1674,
+ 0x6596, 0x341c,
+ 0x6597, 0x02d7,
+ 0x6599, 0x08d8,
+ 0x659b, 0x0ac2,
+ 0x659c, 0x0ac1,
+ 0x659d, 0x2174,
+ 0x659f, 0x0e2c,
+ 0x65a0, 0x26b5,
+ 0x65a1, 0x0fe8,
+ 0x65a2, 0x2b5c,
+ 0x65a4, 0x02d8,
+ 0x65a5, 0x0346,
+ 0x65a7, 0x05f4,
+ 0x65a8, 0x19a2,
+ 0x65aa, 0x1b03,
+ 0x65ab, 0x0743,
+ 0x65ac, 0x0ac3,
+ 0x65ae, 0x2176,
+ 0x65af, 0x0c76,
+ 0x65b0, 0x0e2d,
+ 0x65b2, 0x28f5,
+ 0x65b5, 0x41a7,
+ 0x65b6, 0x2d70,
+ 0x65b7, 0x14d9,
+ 0x65b8, 0x34cb,
+ 0x65b9, 0x02d9,
+ 0x65bb, 0x19a3,
+ 0x65bc, 0x05f5,
+ 0x65bd, 0x0744,
+ 0x65be, 0x3e3b,
+ 0x65bf, 0x1b04,
+ 0x65c1, 0x08d9,
+ 0x65c2, 0x1cc3,
+ 0x65c3, 0x1cc1,
+ 0x65c5, 0x08da,
+ 0x65c6, 0x1cc0,
+ 0x65cb, 0x0ac5,
+ 0x65cd, 0x1f0d,
+ 0x65ce, 0x0ac7,
+ 0x65cf, 0x0ac4,
+ 0x65d0, 0x2177,
+ 0x65d1, 0x41aa,
+ 0x65d2, 0x2178,
+ 0x65d3, 0x240b,
+ 0x65d4, 0x3ba8,
+ 0x65d6, 0x0fea,
+ 0x65d7, 0x0fe9,
+ 0x65da, 0x2d71,
+ 0x65db, 0x2f30,
+ 0x65dd, 0x3098,
+ 0x65de, 0x3097,
+ 0x65df, 0x31d8,
+ 0x65e0, 0x022d,
+ 0x65e1, 0x1789,
+ 0x65e2, 0x0745,
+ 0x65e3, 0x41ae,
+ 0x65e5, 0x02da,
+ 0x65e6, 0x0347,
+ 0x65e8, 0x03d9,
+ 0x65e9, 0x03d8,
+ 0x65ec, 0x03da,
+ 0x65ee, 0x17f8,
+ 0x65ef, 0x17f7,
+ 0x65f0, 0x189e,
+ 0x65f1, 0x04ba,
+ 0x65f2, 0x18a1,
+ 0x65f3, 0x18a0,
+ 0x65f4, 0x189f,
+ 0x65f5, 0x18a2,
+ 0x65fa, 0x05f6,
+ 0x65fb, 0x19a9,
+ 0x65fc, 0x19a5,
+ 0x65fd, 0x19ae,
+ 0x65ff, 0x464a,
+ 0x6600, 0x05fd,
+ 0x6602, 0x05fb,
+ 0x6603, 0x19aa,
+ 0x6604, 0x19a6,
+ 0x6605, 0x19ad,
+ 0x6606, 0x05fa,
+ 0x6607, 0x0601,
+ 0x6608, 0x19a8,
+ 0x6609, 0x19a4,
+ 0x660a, 0x0600,
+ 0x660b, 0x19ab,
+ 0x660c, 0x05f9,
+ 0x660d, 0x19ac,
+ 0x660e, 0x05fc,
+ 0x660f, 0x05fe,
+ 0x6610, 0x19b0,
+ 0x6611, 0x19af,
+ 0x6612, 0x19a7,
+ 0x6613, 0x05f8,
+ 0x6614, 0x05f7,
+ 0x6615, 0x05ff,
+ 0x6618, 0x41b1,
+ 0x661c, 0x1b09,
+ 0x661d, 0x1b0f,
+ 0x661e, 0x3a93,
+ 0x661f, 0x074b,
+ 0x6620, 0x0748,
+ 0x6621, 0x1b06,
+ 0x6622, 0x1b0b,
+ 0x6623, 0x4295,
+ 0x6624, 0x074e,
+ 0x6625, 0x0746,
+ 0x6626, 0x1b0a,
+ 0x6627, 0x0749,
+ 0x6628, 0x074c,
+ 0x662b, 0x1b0d,
+ 0x662d, 0x0747,
+ 0x662e, 0x1b12,
+ 0x662f, 0x074a,
+ 0x6630, 0x3a8d,
+ 0x6631, 0x074d,
+ 0x6632, 0x1b07,
+ 0x6633, 0x1b0c,
+ 0x6634, 0x1b10,
+ 0x6635, 0x1b08,
+ 0x6636, 0x1b05,
+ 0x6639, 0x1b11,
+ 0x663a, 0x1b0e,
+ 0x6641, 0x08e2,
+ 0x6642, 0x08db,
+ 0x6643, 0x08de,
+ 0x6644, 0x41b4,
+ 0x6645, 0x08e1,
+ 0x6647, 0x1cc6,
+ 0x6648, 0x3d99,
+ 0x6649, 0x08dc,
+ 0x664a, 0x1cc4,
+ 0x664b, 0x41b7,
+ 0x664c, 0x08e0,
+ 0x664f, 0x08dd,
+ 0x6651, 0x1cc7,
+ 0x6652, 0x08df,
+ 0x6653, 0x464b,
+ 0x6657, 0x409b,
+ 0x6659, 0x1f11,
+ 0x665a, 0x0ac9,
+ 0x665b, 0x1f10,
+ 0x665c, 0x1f12,
+ 0x665d, 0x0ac8,
+ 0x665e, 0x0acd,
+ 0x665f, 0x1cc5,
+ 0x6661, 0x1f0f,
+ 0x6662, 0x1f13,
+ 0x6663, 0x3a90,
+ 0x6664, 0x0aca,
+ 0x6665, 0x1f0e,
+ 0x6666, 0x0acc,
+ 0x6667, 0x41b9,
+ 0x6668, 0x0acb,
+ 0x666a, 0x217f,
+ 0x666b, 0x3a8b,
+ 0x666c, 0x217a,
+ 0x666e, 0x0c77,
+ 0x666f, 0x0c7b,
+ 0x6670, 0x0c78,
+ 0x6671, 0x217d,
+ 0x6672, 0x2180,
+ 0x6673, 0x41bb,
+ 0x6674, 0x0c79,
+ 0x6676, 0x0c7a,
+ 0x6677, 0x0c7f,
+ 0x6678, 0x2414,
+ 0x6679, 0x217e,
+ 0x667a, 0x0c7d,
+ 0x667b, 0x217b,
+ 0x667c, 0x2179,
+ 0x667d, 0x469b,
+ 0x667e, 0x0c7e,
+ 0x6680, 0x217c,
+ 0x6684, 0x0e33,
+ 0x6685, 0x4162,
+ 0x6686, 0x240c,
+ 0x6687, 0x0e30,
+ 0x6689, 0x0e2f,
+ 0x668a, 0x2411,
+ 0x668b, 0x2410,
+ 0x668c, 0x240d,
+ 0x668d, 0x0e35,
+ 0x668e, 0x3a89,
+ 0x6690, 0x240f,
+ 0x6691, 0x0c7c,
+ 0x6692, 0x464d,
+ 0x6694, 0x2413,
+ 0x6695, 0x240e,
+ 0x6696, 0x0e32,
+ 0x6697, 0x0e2e,
+ 0x6698, 0x0e34,
+ 0x6699, 0x2412,
+ 0x669a, 0x3d3d,
+ 0x669d, 0x0fed,
+ 0x669f, 0x26b8,
+ 0x66a0, 0x26b7,
+ 0x66a1, 0x26b6,
+ 0x66a2, 0x0feb,
+ 0x66a4, 0x40ba,
+ 0x66a8, 0x0fec,
+ 0x66a9, 0x28f9,
+ 0x66aa, 0x28fc,
+ 0x66ab, 0x1172,
+ 0x66ad, 0x4948,
+ 0x66ae, 0x1171,
+ 0x66af, 0x28fd,
+ 0x66b0, 0x28f8,
+ 0x66b1, 0x1174,
+ 0x66b2, 0x28fa,
+ 0x66b3, 0x40b5,
+ 0x66b4, 0x1173,
+ 0x66b5, 0x28f7,
+ 0x66b6, 0x3e13,
+ 0x66b7, 0x28fb,
+ 0x66b8, 0x12cc,
+ 0x66b9, 0x12c9,
+ 0x66ba, 0x2b65,
+ 0x66bb, 0x2b64,
+ 0x66bd, 0x2b63,
+ 0x66be, 0x2b5e,
+ 0x66bf, 0x3d9a,
+ 0x66c0, 0x2b5f,
+ 0x66c4, 0x12ca,
+ 0x66c6, 0x12c7,
+ 0x66c7, 0x12cb,
+ 0x66c8, 0x2b5d,
+ 0x66c9, 0x12c8,
+ 0x66ca, 0x2b60,
+ 0x66cc, 0x2b66,
+ 0x66cd, 0x40b8,
+ 0x66ce, 0x3a77,
+ 0x66cf, 0x2b62,
+ 0x66d2, 0x2d72,
+ 0x66d6, 0x13e4,
+ 0x66d8, 0x2f33,
+ 0x66d9, 0x13e3,
+ 0x66da, 0x2f31,
+ 0x66dc, 0x14da,
+ 0x66dd, 0x1585,
+ 0x66de, 0x3099,
+ 0x66e0, 0x1584,
+ 0x66e3, 0x31da,
+ 0x66e6, 0x1619,
+ 0x66e8, 0x31d9,
+ 0x66e9, 0x1675,
+ 0x66eb, 0x341d,
+ 0x66ec, 0x16fc,
+ 0x66ed, 0x3485,
+ 0x66f0, 0x02db,
+ 0x66f1, 0x3e84,
+ 0x66f2, 0x03dc,
+ 0x66f4, 0x04bb,
+ 0x66f6, 0x19b1,
+ 0x66f7, 0x074f,
+ 0x66f8, 0x08e3,
+ 0x66f9, 0x0ace,
+ 0x66fc, 0x0a1f,
+ 0x66fe, 0x0c80,
+ 0x6700, 0x0bf0,
+ 0x6701, 0x2181,
+ 0x6702, 0x41c4,
+ 0x6703, 0x0e36,
+ 0x6704, 0x26ba,
+ 0x6705, 0x26b9,
+ 0x6708, 0x02dc,
+ 0x6709, 0x03de,
+ 0x670a, 0x19b2,
+ 0x670b, 0x0603,
+ 0x670c, 0x3fe2,
+ 0x670d, 0x0602,
+ 0x670e, 0x3da1,
+ 0x670f, 0x1b13,
+ 0x6712, 0x1cc8,
+ 0x6714, 0x08e4,
+ 0x6716, 0x464f,
+ 0x6717, 0x08e6,
+ 0x6718, 0x1f14,
+ 0x671b, 0x0ad0,
+ 0x671d, 0x0c83,
+ 0x671e, 0x3d8b,
+ 0x671f, 0x0c82,
+ 0x6720, 0x2415,
+ 0x6721, 0x2522,
+ 0x6722, 0x26bb,
+ 0x6723, 0x2b67,
+ 0x6725, 0x379f,
+ 0x6726, 0x14db,
+ 0x6727, 0x161a,
+ 0x6728, 0x02dd,
+ 0x672a, 0x034a,
+ 0x672c, 0x0349,
+ 0x672d, 0x034c,
+ 0x672e, 0x0348,
+ 0x6731, 0x03e1,
+ 0x6733, 0x1800,
+ 0x6734, 0x03e0,
+ 0x6735, 0x03e2,
+ 0x6736, 0x3e41,
+ 0x6738, 0x17fb,
+ 0x6739, 0x17fa,
+ 0x673a, 0x17fd,
+ 0x673b, 0x17fc,
+ 0x673c, 0x17ff,
+ 0x673d, 0x03df,
+ 0x673e, 0x17f9,
+ 0x673f, 0x17fe,
+ 0x6744, 0x401b,
+ 0x6745, 0x18a3,
+ 0x6746, 0x04c5,
+ 0x6747, 0x18a4,
+ 0x6748, 0x18a8,
+ 0x6749, 0x04c4,
+ 0x674b, 0x18ac,
+ 0x674c, 0x18a7,
+ 0x674d, 0x18aa,
+ 0x674e, 0x04bd,
+ 0x6753, 0x04c7,
+ 0x6755, 0x18a6,
+ 0x6756, 0x04c2,
+ 0x6757, 0x04c8,
+ 0x6759, 0x18a5,
+ 0x675a, 0x18ab,
+ 0x675c, 0x04c1,
+ 0x675d, 0x18a9,
+ 0x675e, 0x04c3,
+ 0x675f, 0x04bc,
+ 0x6760, 0x04c6,
+ 0x6761, 0x3d66,
+ 0x6762, 0x41cb,
+ 0x6767, 0x41ca,
+ 0x676a, 0x0618,
+ 0x676c, 0x19b4,
+ 0x676d, 0x0604,
+ 0x676f, 0x060e,
+ 0x6771, 0x0607,
+ 0x6772, 0x0619,
+ 0x6773, 0x0609,
+ 0x6774, 0x19bc,
+ 0x6775, 0x0614,
+ 0x6776, 0x19b7,
+ 0x6777, 0x060a,
+ 0x6778, 0x19c6,
+ 0x677a, 0x19bf,
+ 0x677b, 0x19b8,
+ 0x677c, 0x0617,
+ 0x677d, 0x19c4,
+ 0x677e, 0x0612,
+ 0x677f, 0x0610,
+ 0x6781, 0x19c5,
+ 0x6783, 0x19c3,
+ 0x6784, 0x19bb,
+ 0x6785, 0x19b3,
+ 0x6786, 0x19ba,
+ 0x6787, 0x060b,
+ 0x6789, 0x0611,
+ 0x678b, 0x0605,
+ 0x678c, 0x19be,
+ 0x678d, 0x19bd,
+ 0x678e, 0x19b5,
+ 0x678f, 0x46c1,
+ 0x6790, 0x0613,
+ 0x6791, 0x19c1,
+ 0x6792, 0x19b6,
+ 0x6793, 0x0616,
+ 0x6794, 0x19c8,
+ 0x6795, 0x0606,
+ 0x6797, 0x060d,
+ 0x6798, 0x19b9,
+ 0x6799, 0x19c2,
+ 0x679a, 0x0615,
+ 0x679c, 0x0608,
+ 0x679d, 0x060c,
+ 0x679f, 0x19c0,
+ 0x67a0, 0x3d7a,
+ 0x67a4, 0x4651,
+ 0x67ac, 0x41e3,
+ 0x67ae, 0x1b34,
+ 0x67af, 0x0757,
+ 0x67b0, 0x0764,
+ 0x67b1, 0x41f4,
+ 0x67b2, 0x1b2f,
+ 0x67b3, 0x1b25,
+ 0x67b4, 0x075d,
+ 0x67b5, 0x1b23,
+ 0x67b6, 0x0756,
+ 0x67b7, 0x1b1e,
+ 0x67b8, 0x0760,
+ 0x67b9, 0x1b2b,
+ 0x67ba, 0x1b18,
+ 0x67bb, 0x1b1a,
+ 0x67bf, 0x37fa,
+ 0x67c0, 0x1b1d,
+ 0x67c1, 0x1b15,
+ 0x67c2, 0x1b2a,
+ 0x67c3, 0x1b3a,
+ 0x67c4, 0x075b,
+ 0x67c5, 0x1b1f,
+ 0x67c6, 0x1b31,
+ 0x67c8, 0x1b17,
+ 0x67c9, 0x1b38,
+ 0x67cb, 0x1b3c,
+ 0x67cc, 0x1b33,
+ 0x67cd, 0x1b24,
+ 0x67ce, 0x1b2c,
+ 0x67cf, 0x0761,
+ 0x67d0, 0x0754,
+ 0x67d1, 0x075c,
+ 0x67d2, 0x0768,
+ 0x67d3, 0x0751,
+ 0x67d4, 0x0753,
+ 0x67d6, 0x3b58,
+ 0x67d7, 0x41ce,
+ 0x67d8, 0x1b1c,
+ 0x67d9, 0x0765,
+ 0x67da, 0x075e,
+ 0x67db, 0x1b36,
+ 0x67dc, 0x1b19,
+ 0x67dd, 0x0767,
+ 0x67de, 0x0762,
+ 0x67df, 0x1b22,
+ 0x67e2, 0x0766,
+ 0x67e3, 0x1b29,
+ 0x67e4, 0x1b21,
+ 0x67e5, 0x075f,
+ 0x67e6, 0x1b35,
+ 0x67e7, 0x1b2d,
+ 0x67e9, 0x0759,
+ 0x67ea, 0x1b3b,
+ 0x67eb, 0x1b20,
+ 0x67ec, 0x0755,
+ 0x67ed, 0x1b32,
+ 0x67ee, 0x1b28,
+ 0x67ef, 0x075a,
+ 0x67f0, 0x1b2e,
+ 0x67f1, 0x0752,
+ 0x67f2, 0x1b16,
+ 0x67f3, 0x0763,
+ 0x67f4, 0x08f5,
+ 0x67f5, 0x0758,
+ 0x67f6, 0x1b27,
+ 0x67f7, 0x1b26,
+ 0x67f8, 0x1b1b,
+ 0x67f9, 0x3996,
+ 0x67fa, 0x1b37,
+ 0x67fc, 0x1b30,
+ 0x67fe, 0x4555,
+ 0x67ff, 0x0750,
+ 0x6800, 0x43c7,
+ 0x6801, 0x41d3,
+ 0x6802, 0x3fc8,
+ 0x6803, 0x3d6a,
+ 0x6804, 0x4556,
+ 0x680d, 0x4281,
+ 0x6810, 0x399c,
+ 0x6812, 0x1cdd,
+ 0x6813, 0x08fc,
+ 0x6814, 0x1cde,
+ 0x6816, 0x1cd2,
+ 0x6817, 0x08f1,
+ 0x6818, 0x08fd,
+ 0x681a, 0x1ccb,
+ 0x681b, 0x4072,
+ 0x681c, 0x1cd4,
+ 0x681d, 0x1cdc,
+ 0x681e, 0x46c2,
+ 0x681f, 0x1cca,
+ 0x6820, 0x1ce5,
+ 0x6821, 0x08e7,
+ 0x6822, 0x41d0,
+ 0x6825, 0x1ce4,
+ 0x6826, 0x1cdf,
+ 0x6828, 0x1ce0,
+ 0x6829, 0x08ef,
+ 0x682a, 0x08fa,
+ 0x682b, 0x1cd6,
+ 0x682d, 0x1cd7,
+ 0x682e, 0x1ce1,
+ 0x682f, 0x1cd8,
+ 0x6831, 0x1cd3,
+ 0x6832, 0x1ccd,
+ 0x6834, 0x1cdb,
+ 0x6835, 0x1cd5,
+ 0x6836, 0x3e2e,
+ 0x6837, 0x421d,
+ 0x6838, 0x08e8,
+ 0x6839, 0x08ec,
+ 0x683a, 0x1ce3,
+ 0x683b, 0x1ccf,
+ 0x683c, 0x08f8,
+ 0x683d, 0x08f4,
+ 0x683e, 0x4147,
+ 0x6840, 0x08f7,
+ 0x6841, 0x08fe,
+ 0x6842, 0x08ed,
+ 0x6843, 0x08f9,
+ 0x6844, 0x1cda,
+ 0x6845, 0x08fb,
+ 0x6846, 0x08ea,
+ 0x6847, 0x3beb,
+ 0x6848, 0x08e9,
+ 0x6849, 0x1ccc,
+ 0x684a, 0x4653,
+ 0x684b, 0x1cd0,
+ 0x684c, 0x08f2,
+ 0x684d, 0x1ce2,
+ 0x684e, 0x1cd9,
+ 0x684f, 0x1cd1,
+ 0x6850, 0x08f6,
+ 0x6851, 0x08f3,
+ 0x6853, 0x08eb,
+ 0x6854, 0x08ee,
+ 0x6855, 0x3d90,
+ 0x6856, 0x3814,
+ 0x685d, 0x41d6,
+ 0x6865, 0x4557,
+ 0x686b, 0x1f29,
+ 0x686d, 0x1f19,
+ 0x686f, 0x1f1e,
+ 0x6871, 0x1f2d,
+ 0x6872, 0x1f2a,
+ 0x6874, 0x1f23,
+ 0x6875, 0x1f22,
+ 0x6876, 0x0ad7,
+ 0x6877, 0x1f26,
+ 0x6878, 0x1f35,
+ 0x6879, 0x1f15,
+ 0x687b, 0x1f36,
+ 0x687c, 0x1f28,
+ 0x687d, 0x1f3a,
+ 0x687e, 0x1f2e,
+ 0x687f, 0x0ad6,
+ 0x6880, 0x1f2c,
+ 0x6881, 0x0ad1,
+ 0x6882, 0x0ae6,
+ 0x6883, 0x0adc,
+ 0x6884, 0x4654,
+ 0x6885, 0x0ae0,
+ 0x6886, 0x0adf,
+ 0x6887, 0x1f16,
+ 0x6888, 0x46b7,
+ 0x6889, 0x1f33,
+ 0x688a, 0x1f39,
+ 0x688b, 0x1f31,
+ 0x688c, 0x1f38,
+ 0x688f, 0x1f25,
+ 0x6890, 0x1f17,
+ 0x6891, 0x1f37,
+ 0x6892, 0x1f27,
+ 0x6893, 0x0ad4,
+ 0x6894, 0x0ae1,
+ 0x6896, 0x1f30,
+ 0x6897, 0x0ada,
+ 0x6898, 0x3aaa,
+ 0x689b, 0x1f2f,
+ 0x689c, 0x1f18,
+ 0x689d, 0x0ae2,
+ 0x689f, 0x0ae4,
+ 0x68a0, 0x1f32,
+ 0x68a1, 0x0ae5,
+ 0x68a2, 0x0ad3,
+ 0x68a3, 0x1f1f,
+ 0x68a4, 0x1f34,
+ 0x68a6, 0x40e4,
+ 0x68a7, 0x0ad9,
+ 0x68a8, 0x0ae3,
+ 0x68a9, 0x1f21,
+ 0x68aa, 0x1f2b,
+ 0x68ab, 0x1f1c,
+ 0x68ac, 0x1f20,
+ 0x68ad, 0x0ade,
+ 0x68ae, 0x1f1b,
+ 0x68af, 0x0ad2,
+ 0x68b0, 0x0adb,
+ 0x68b1, 0x0ad8,
+ 0x68b2, 0x1f24,
+ 0x68b3, 0x08f0,
+ 0x68b4, 0x2198,
+ 0x68b5, 0x0ad5,
+ 0x68b6, 0x3a9e,
+ 0x68b9, 0x3d14,
+ 0x68bd, 0x427c,
+ 0x68c3, 0x41dc,
+ 0x68c4, 0x0add,
+ 0x68c5, 0x3c2e,
+ 0x68c6, 0x219b,
+ 0x68c7, 0x21b1,
+ 0x68c8, 0x21a6,
+ 0x68c9, 0x0c97,
+ 0x68ca, 0x42eb,
+ 0x68cb, 0x0c92,
+ 0x68cc, 0x2195,
+ 0x68cd, 0x0c93,
+ 0x68ce, 0x21a5,
+ 0x68d0, 0x219e,
+ 0x68d1, 0x21ab,
+ 0x68d2, 0x0c8f,
+ 0x68d3, 0x2183,
+ 0x68d4, 0x21ad,
+ 0x68d5, 0x0c85,
+ 0x68d6, 0x218b,
+ 0x68d7, 0x0c88,
+ 0x68d8, 0x0c87,
+ 0x68da, 0x0c98,
+ 0x68dc, 0x2185,
+ 0x68dd, 0x21a7,
+ 0x68df, 0x0c8a,
+ 0x68e0, 0x0c86,
+ 0x68e1, 0x2193,
+ 0x68e3, 0x0c91,
+ 0x68e4, 0x218e,
+ 0x68e6, 0x21a9,
+ 0x68e7, 0x0c8d,
+ 0x68e8, 0x21a1,
+ 0x68e9, 0x21ae,
+ 0x68ea, 0x2188,
+ 0x68eb, 0x218d,
+ 0x68ec, 0x2187,
+ 0x68ee, 0x0c8c,
+ 0x68ef, 0x219a,
+ 0x68f0, 0x242b,
+ 0x68f1, 0x2189,
+ 0x68f2, 0x0c90,
+ 0x68f3, 0x2192,
+ 0x68f4, 0x21aa,
+ 0x68f5, 0x0c8b,
+ 0x68f6, 0x218f,
+ 0x68f7, 0x218c,
+ 0x68f8, 0x219d,
+ 0x68f9, 0x0c8e,
+ 0x68fa, 0x0c84,
+ 0x68fb, 0x0c9a,
+ 0x68fc, 0x21a0,
+ 0x68fd, 0x219f,
+ 0x6900, 0x41df,
+ 0x6901, 0x41de,
+ 0x6902, 0x42fb,
+ 0x6903, 0x429c,
+ 0x6904, 0x2184,
+ 0x6905, 0x0c89,
+ 0x6906, 0x21ac,
+ 0x6907, 0x2194,
+ 0x6908, 0x2196,
+ 0x6909, 0x4658,
+ 0x690a, 0x21a3,
+ 0x690b, 0x21a2,
+ 0x690c, 0x2182,
+ 0x690d, 0x0c94,
+ 0x690e, 0x0c96,
+ 0x690f, 0x218a,
+ 0x6910, 0x2191,
+ 0x6911, 0x2199,
+ 0x6912, 0x0c95,
+ 0x6913, 0x2190,
+ 0x6914, 0x219c,
+ 0x6915, 0x21af,
+ 0x6917, 0x21a4,
+ 0x6918, 0x3da2,
+ 0x691a, 0x3d80,
+ 0x691b, 0x37bd,
+ 0x6925, 0x21b0,
+ 0x692a, 0x2186,
+ 0x692c, 0x3f38,
+ 0x692f, 0x243f,
+ 0x6930, 0x0e3e,
+ 0x6932, 0x243d,
+ 0x6933, 0x2428,
+ 0x6934, 0x242d,
+ 0x6935, 0x2426,
+ 0x6936, 0x41e7,
+ 0x6937, 0x2439,
+ 0x6938, 0x2418,
+ 0x6939, 0x241f,
+ 0x693b, 0x2437,
+ 0x693c, 0x2441,
+ 0x693d, 0x2429,
+ 0x693e, 0x4056,
+ 0x693f, 0x241c,
+ 0x6940, 0x242f,
+ 0x6941, 0x2434,
+ 0x6942, 0x2420,
+ 0x6943, 0x4659,
+ 0x6944, 0x2431,
+ 0x6945, 0x241d,
+ 0x6946, 0x456f,
+ 0x6948, 0x2424,
+ 0x694a, 0x0e40,
+ 0x694b, 0x2438,
+ 0x694c, 0x2436,
+ 0x694e, 0x2419,
+ 0x694f, 0x243b,
+ 0x6951, 0x243c,
+ 0x6952, 0x243e,
+ 0x6953, 0x0e44,
+ 0x6954, 0x0e3c,
+ 0x6955, 0x3d86,
+ 0x6956, 0x1f1d,
+ 0x6957, 0x2421,
+ 0x6958, 0x2433,
+ 0x6959, 0x2422,
+ 0x695a, 0x0e39,
+ 0x695b, 0x0e49,
+ 0x695c, 0x243a,
+ 0x695d, 0x0e47,
+ 0x695e, 0x0e43,
+ 0x695f, 0x2417,
+ 0x6960, 0x0e3b,
+ 0x6961, 0x41e4,
+ 0x6962, 0x241a,
+ 0x6963, 0x0e48,
+ 0x6964, 0x465b,
+ 0x6965, 0x242a,
+ 0x6966, 0x2416,
+ 0x6967, 0x3d15,
+ 0x6968, 0x0e41,
+ 0x6969, 0x242e,
+ 0x696a, 0x241e,
+ 0x696b, 0x0e42,
+ 0x696c, 0x2427,
+ 0x696d, 0x0e38,
+ 0x696e, 0x0c99,
+ 0x696f, 0x2430,
+ 0x6970, 0x2197,
+ 0x6971, 0x241b,
+ 0x6972, 0x3a6d,
+ 0x6973, 0x41db,
+ 0x6974, 0x2435,
+ 0x6975, 0x0e3d,
+ 0x6976, 0x2432,
+ 0x6977, 0x0e3a,
+ 0x6978, 0x242c,
+ 0x6979, 0x0e45,
+ 0x697a, 0x2423,
+ 0x697b, 0x2440,
+ 0x6980, 0x3f3e,
+ 0x6982, 0x0e3f,
+ 0x6983, 0x24af,
+ 0x6985, 0x465d,
+ 0x6986, 0x0e46,
+ 0x698a, 0x3d74,
+ 0x698d, 0x26c9,
+ 0x698e, 0x26c7,
+ 0x6990, 0x26dd,
+ 0x6991, 0x26c5,
+ 0x6993, 0x26d7,
+ 0x6994, 0x0e37,
+ 0x6995, 0x0ff0,
+ 0x6996, 0x26c1,
+ 0x6997, 0x26dc,
+ 0x6998, 0x41e8,
+ 0x6999, 0x26c6,
+ 0x699a, 0x26d4,
+ 0x699b, 0x0ff5,
+ 0x699c, 0x0fee,
+ 0x699e, 0x26da,
+ 0x699f, 0x465c,
+ 0x69a0, 0x26bf,
+ 0x69a1, 0x26d9,
+ 0x69a2, 0x3730,
+ 0x69a3, 0x1000,
+ 0x69a4, 0x26d0,
+ 0x69a5, 0x26e0,
+ 0x69a6, 0x0ffe,
+ 0x69a7, 0x26c8,
+ 0x69a8, 0x0fef,
+ 0x69a9, 0x26ca,
+ 0x69aa, 0x26d8,
+ 0x69ab, 0x0ff8,
+ 0x69ac, 0x26c3,
+ 0x69ad, 0x0ffc,
+ 0x69ae, 0x0ff2,
+ 0x69af, 0x26cc,
+ 0x69b0, 0x26c2,
+ 0x69b1, 0x26bc,
+ 0x69b2, 0x3ff6,
+ 0x69b3, 0x26d6,
+ 0x69b4, 0x0ff9,
+ 0x69b5, 0x26df,
+ 0x69b6, 0x26bd,
+ 0x69b7, 0x0ff6,
+ 0x69b9, 0x26d2,
+ 0x69bb, 0x0ff7,
+ 0x69bc, 0x26c4,
+ 0x69bd, 0x26cf,
+ 0x69be, 0x26cb,
+ 0x69bf, 0x26cd,
+ 0x69c0, 0x3f5d,
+ 0x69c1, 0x0ff1,
+ 0x69c2, 0x26de,
+ 0x69c3, 0x0fff,
+ 0x69c4, 0x26ce,
+ 0x69c6, 0x26e1,
+ 0x69c9, 0x26be,
+ 0x69ca, 0x26d3,
+ 0x69cb, 0x0ff4,
+ 0x69cc, 0x0ffd,
+ 0x69cd, 0x0ffb,
+ 0x69ce, 0x26c0,
+ 0x69cf, 0x26d5,
+ 0x69d0, 0x0ffa,
+ 0x69d1, 0x39ef,
+ 0x69d3, 0x0ff3,
+ 0x69d4, 0x26d1,
+ 0x69d5, 0x3e3c,
+ 0x69d6, 0x465e,
+ 0x69d9, 0x26db,
+ 0x69e1, 0x41d8,
+ 0x69e2, 0x2909,
+ 0x69e4, 0x2905,
+ 0x69e5, 0x2901,
+ 0x69e6, 0x2915,
+ 0x69e7, 0x2912,
+ 0x69e8, 0x1177,
+ 0x69e9, 0x3d91,
+ 0x69eb, 0x2919,
+ 0x69ec, 0x2908,
+ 0x69ed, 0x1182,
+ 0x69ee, 0x290f,
+ 0x69f1, 0x2904,
+ 0x69f2, 0x290e,
+ 0x69f3, 0x117f,
+ 0x69f4, 0x2922,
+ 0x69f6, 0x291f,
+ 0x69f7, 0x2911,
+ 0x69f8, 0x2902,
+ 0x69f9, 0x41ed,
+ 0x69fa, 0x41c7,
+ 0x69fb, 0x2916,
+ 0x69fc, 0x2918,
+ 0x69fd, 0x117b,
+ 0x69fe, 0x290c,
+ 0x69ff, 0x2907,
+ 0x6a00, 0x28fe,
+ 0x6a01, 0x1178,
+ 0x6a02, 0x1180,
+ 0x6a03, 0x3e29,
+ 0x6a04, 0x291b,
+ 0x6a05, 0x1181,
+ 0x6a06, 0x28ff,
+ 0x6a07, 0x2921,
+ 0x6a08, 0x2914,
+ 0x6a09, 0x291a,
+ 0x6a0a, 0x117e,
+ 0x6a0b, 0x41d9,
+ 0x6a0c, 0x3d50,
+ 0x6a0d, 0x2917,
+ 0x6a0f, 0x291e,
+ 0x6a11, 0x1183,
+ 0x6a13, 0x117d,
+ 0x6a14, 0x2910,
+ 0x6a15, 0x2903,
+ 0x6a16, 0x2923,
+ 0x6a17, 0x2900,
+ 0x6a18, 0x291c,
+ 0x6a19, 0x117a,
+ 0x6a1a, 0x3d1e,
+ 0x6a1b, 0x290a,
+ 0x6a1c, 0x3b68,
+ 0x6a1d, 0x290b,
+ 0x6a1e, 0x1179,
+ 0x6a1f, 0x1176,
+ 0x6a20, 0x2906,
+ 0x6a21, 0x117c,
+ 0x6a23, 0x1175,
+ 0x6a25, 0x291d,
+ 0x6a26, 0x2920,
+ 0x6a27, 0x290d,
+ 0x6a28, 0x2b74,
+ 0x6a2b, 0x3d42,
+ 0x6a2c, 0x42ab,
+ 0x6a2d, 0x3b1f,
+ 0x6a32, 0x2b6c,
+ 0x6a33, 0x3aa4,
+ 0x6a34, 0x2b68,
+ 0x6a35, 0x12d9,
+ 0x6a38, 0x12ce,
+ 0x6a39, 0x12d3,
+ 0x6a3a, 0x12cf,
+ 0x6a3b, 0x2b76,
+ 0x6a3c, 0x2b81,
+ 0x6a3d, 0x12cd,
+ 0x6a3e, 0x2b6e,
+ 0x6a3f, 0x2b77,
+ 0x6a40, 0x2913,
+ 0x6a41, 0x2b78,
+ 0x6a44, 0x12d4,
+ 0x6a45, 0x41f0,
+ 0x6a46, 0x2b87,
+ 0x6a47, 0x12d8,
+ 0x6a48, 0x12db,
+ 0x6a49, 0x2b6a,
+ 0x6a4b, 0x12d7,
+ 0x6a4c, 0x3aab,
+ 0x6a4d, 0x2b85,
+ 0x6a4f, 0x2b7c,
+ 0x6a50, 0x2b7b,
+ 0x6a51, 0x2b73,
+ 0x6a52, 0x3aa5,
+ 0x6a53, 0x37ac,
+ 0x6a54, 0x2b7d,
+ 0x6a55, 0x2b84,
+ 0x6a56, 0x2b83,
+ 0x6a57, 0x37da,
+ 0x6a58, 0x12d2,
+ 0x6a59, 0x12d0,
+ 0x6a5a, 0x2b75,
+ 0x6a5b, 0x2b72,
+ 0x6a5d, 0x2b6f,
+ 0x6a5e, 0x2b82,
+ 0x6a5f, 0x12da,
+ 0x6a60, 0x2b80,
+ 0x6a61, 0x12d6,
+ 0x6a62, 0x12d5,
+ 0x6a64, 0x2b7a,
+ 0x6a65, 0x4660,
+ 0x6a66, 0x2b69,
+ 0x6a67, 0x2b6b,
+ 0x6a68, 0x2b6d,
+ 0x6a69, 0x2b7f,
+ 0x6a6a, 0x2b79,
+ 0x6a6b, 0x12d1,
+ 0x6a6d, 0x2b70,
+ 0x6a6f, 0x2b7e,
+ 0x6a71, 0x4662,
+ 0x6a74, 0x4661,
+ 0x6a76, 0x2b71,
+ 0x6a7a, 0x3aad,
+ 0x6a7e, 0x13ec,
+ 0x6a7f, 0x2d84,
+ 0x6a80, 0x13e5,
+ 0x6a81, 0x2d75,
+ 0x6a82, 0x4663,
+ 0x6a83, 0x2d80,
+ 0x6a84, 0x13e7,
+ 0x6a85, 0x2d87,
+ 0x6a87, 0x2d7c,
+ 0x6a89, 0x2d77,
+ 0x6a8a, 0x4136,
+ 0x6a8c, 0x2d88,
+ 0x6a8d, 0x2d73,
+ 0x6a8e, 0x2d7e,
+ 0x6a8f, 0x3c1b,
+ 0x6a90, 0x13ee,
+ 0x6a91, 0x2d83,
+ 0x6a92, 0x2d89,
+ 0x6a93, 0x2d7d,
+ 0x6a94, 0x13e6,
+ 0x6a95, 0x2d7f,
+ 0x6a96, 0x2d74,
+ 0x6a97, 0x13ed,
+ 0x6a99, 0x4665,
+ 0x6a9a, 0x2d86,
+ 0x6a9b, 0x2d79,
+ 0x6a9c, 0x13e9,
+ 0x6a9d, 0x41f2,
+ 0x6a9e, 0x2d7b,
+ 0x6a9f, 0x2d78,
+ 0x6aa0, 0x13ef,
+ 0x6aa1, 0x2d7a,
+ 0x6aa2, 0x13e8,
+ 0x6aa3, 0x13eb,
+ 0x6aa4, 0x2d82,
+ 0x6aa5, 0x2d76,
+ 0x6aa6, 0x2d85,
+ 0x6aa7, 0x37e3,
+ 0x6aa8, 0x2d81,
+ 0x6aab, 0x4667,
+ 0x6aac, 0x14dd,
+ 0x6aad, 0x2f3e,
+ 0x6aae, 0x14e2,
+ 0x6ab1, 0x3e53,
+ 0x6ab2, 0x3b4b,
+ 0x6ab3, 0x14dc,
+ 0x6ab4, 0x2f3d,
+ 0x6ab5, 0x4668,
+ 0x6ab6, 0x2f3a,
+ 0x6ab8, 0x14e0,
+ 0x6ab9, 0x2f35,
+ 0x6aba, 0x2f39,
+ 0x6abb, 0x14df,
+ 0x6abd, 0x2f36,
+ 0x6abe, 0x3aa1,
+ 0x6ac2, 0x14e1,
+ 0x6ac3, 0x14de,
+ 0x6ac5, 0x2f34,
+ 0x6ac6, 0x2f38,
+ 0x6ac7, 0x2f3c,
+ 0x6ac8, 0x41f5,
+ 0x6ac9, 0x3aa6,
+ 0x6aca, 0x3f4c,
+ 0x6acb, 0x309f,
+ 0x6acc, 0x309c,
+ 0x6acd, 0x30a5,
+ 0x6acf, 0x30a4,
+ 0x6ad0, 0x30a2,
+ 0x6ad1, 0x309d,
+ 0x6ad3, 0x1589,
+ 0x6ad4, 0x4669,
+ 0x6ad8, 0x3caa,
+ 0x6ad9, 0x309e,
+ 0x6ada, 0x1588,
+ 0x6adb, 0x13ea,
+ 0x6adc, 0x30a1,
+ 0x6add, 0x1587,
+ 0x6ade, 0x30a6,
+ 0x6adf, 0x30a0,
+ 0x6ae0, 0x309b,
+ 0x6ae1, 0x2f37,
+ 0x6ae5, 0x1586,
+ 0x6ae7, 0x309a,
+ 0x6ae8, 0x31df,
+ 0x6aea, 0x31de,
+ 0x6aeb, 0x30a3,
+ 0x6aec, 0x161b,
+ 0x6aee, 0x31e2,
+ 0x6af0, 0x31dd,
+ 0x6af1, 0x31e1,
+ 0x6af3, 0x31dc,
+ 0x6af6, 0x466a,
+ 0x6af8, 0x32d6,
+ 0x6af9, 0x31e0,
+ 0x6afa, 0x1678,
+ 0x6afb, 0x1676,
+ 0x6afc, 0x32d4,
+ 0x6b00, 0x32d7,
+ 0x6b02, 0x32d3,
+ 0x6b03, 0x32d5,
+ 0x6b04, 0x1677,
+ 0x6b05, 0x3aa7,
+ 0x6b08, 0x3386,
+ 0x6b0a, 0x16c6,
+ 0x6b0b, 0x3385,
+ 0x6b0f, 0x3420,
+ 0x6b10, 0x16fd,
+ 0x6b11, 0x341e,
+ 0x6b13, 0x3487,
+ 0x6b16, 0x1743,
+ 0x6b17, 0x34ce,
+ 0x6b18, 0x34cc,
+ 0x6b1a, 0x34cf,
+ 0x6b1d, 0x41f8,
+ 0x6b1e, 0x3534,
+ 0x6b20, 0x02de,
+ 0x6b21, 0x03e3,
+ 0x6b23, 0x061a,
+ 0x6b25, 0x19c9,
+ 0x6b28, 0x1b3d,
+ 0x6b2c, 0x1ce6,
+ 0x6b2d, 0x1ce8,
+ 0x6b2f, 0x1ce7,
+ 0x6b31, 0x1ce9,
+ 0x6b32, 0x0ae7,
+ 0x6b33, 0x1f3c,
+ 0x6b34, 0x1cea,
+ 0x6b35, 0x41fb,
+ 0x6b36, 0x1f3b,
+ 0x6b37, 0x1f3d,
+ 0x6b39, 0x21b2,
+ 0x6b3a, 0x0c9c,
+ 0x6b3b, 0x21b3,
+ 0x6b3c, 0x21b5,
+ 0x6b3d, 0x0c9d,
+ 0x6b3e, 0x0c9b,
+ 0x6b3f, 0x21b4,
+ 0x6b41, 0x2447,
+ 0x6b42, 0x2445,
+ 0x6b43, 0x2444,
+ 0x6b45, 0x2443,
+ 0x6b46, 0x2442,
+ 0x6b47, 0x0e4a,
+ 0x6b48, 0x2446,
+ 0x6b49, 0x1001,
+ 0x6b4a, 0x26e2,
+ 0x6b4b, 0x26e4,
+ 0x6b4c, 0x1002,
+ 0x6b4d, 0x26e3,
+ 0x6b4e, 0x1185,
+ 0x6b50, 0x1184,
+ 0x6b51, 0x2924,
+ 0x6b52, 0x3f6e,
+ 0x6b54, 0x2b89,
+ 0x6b55, 0x2b88,
+ 0x6b56, 0x2b8a,
+ 0x6b57, 0x3aae,
+ 0x6b59, 0x12dc,
+ 0x6b5b, 0x2d8a,
+ 0x6b5c, 0x13f0,
+ 0x6b5e, 0x2f3f,
+ 0x6b5f, 0x14e4,
+ 0x6b60, 0x30a7,
+ 0x6b61, 0x16c7,
+ 0x6b62, 0x02df,
+ 0x6b63, 0x034d,
+ 0x6b64, 0x03e4,
+ 0x6b65, 0x04c9,
+ 0x6b66, 0x061b,
+ 0x6b6a, 0x0769,
+ 0x6b6d, 0x1ceb,
+ 0x6b6f, 0x4515,
+ 0x6b72, 0x0e4b,
+ 0x6b74, 0x41fc,
+ 0x6b76, 0x29a2,
+ 0x6b77, 0x12dd,
+ 0x6b78, 0x14e5,
+ 0x6b79, 0x02e0,
+ 0x6b7a, 0x44ee,
+ 0x6b7b, 0x03e5,
+ 0x6b7e, 0x19cb,
+ 0x6b7f, 0x061d,
+ 0x6b80, 0x19ca,
+ 0x6b81, 0x466b,
+ 0x6b82, 0x1b3e,
+ 0x6b83, 0x076a,
+ 0x6b84, 0x1b3f,
+ 0x6b86, 0x076b,
+ 0x6b88, 0x1ced,
+ 0x6b89, 0x0900,
+ 0x6b8a, 0x08ff,
+ 0x6b8c, 0x1f43,
+ 0x6b8d, 0x1f41,
+ 0x6b8f, 0x1f40,
+ 0x6b91, 0x1f3f,
+ 0x6b94, 0x21b6,
+ 0x6b95, 0x21b9,
+ 0x6b96, 0x0c9f,
+ 0x6b97, 0x21b7,
+ 0x6b98, 0x0c9e,
+ 0x6b99, 0x21b8,
+ 0x6b9b, 0x2448,
+ 0x6b9e, 0x26e5,
+ 0x6ba2, 0x2927,
+ 0x6ba3, 0x2926,
+ 0x6ba4, 0x1186,
+ 0x6ba5, 0x2925,
+ 0x6ba6, 0x2928,
+ 0x6ba7, 0x2b8b,
+ 0x6baa, 0x2b8c,
+ 0x6bad, 0x2d8b,
+ 0x6bae, 0x13f1,
+ 0x6baf, 0x14e6,
+ 0x6bb0, 0x30a8,
+ 0x6bb2, 0x1679,
+ 0x6bb3, 0x178a,
+ 0x6bb5, 0x076c,
+ 0x6bb6, 0x1b40,
+ 0x6bb7, 0x0901,
+ 0x6bba, 0x0ae8,
+ 0x6bbc, 0x0ca0,
+ 0x6bbd, 0x21ba,
+ 0x6bbf, 0x0e4d,
+ 0x6bc0, 0x0e4c,
+ 0x6bc1, 0x466c,
+ 0x6bc3, 0x26e8,
+ 0x6bc5, 0x1187,
+ 0x6bc7, 0x2b8f,
+ 0x6bc8, 0x2b8e,
+ 0x6bc9, 0x2f40,
+ 0x6bca, 0x3421,
+ 0x6bcb, 0x02e1,
+ 0x6bcc, 0x178b,
+ 0x6bcd, 0x034e,
+ 0x6bcf, 0x04ca,
+ 0x6bd0, 0x18ad,
+ 0x6bd2, 0x076d,
+ 0x6bd3, 0x0e4e,
+ 0x6bd4, 0x02e2,
+ 0x6bd6, 0x1b41,
+ 0x6bd7, 0x076e,
+ 0x6bd8, 0x1b42,
+ 0x6bda, 0x13f2,
+ 0x6bdb, 0x02e3,
+ 0x6bdc, 0x4207,
+ 0x6bde, 0x19cc,
+ 0x6be0, 0x1b43,
+ 0x6be1, 0x4205,
+ 0x6be2, 0x1cf2,
+ 0x6be3, 0x1cf1,
+ 0x6be4, 0x1cef,
+ 0x6be6, 0x1cee,
+ 0x6be7, 0x1cf3,
+ 0x6be8, 0x1cf0,
+ 0x6bea, 0x466d,
+ 0x6beb, 0x0ae9,
+ 0x6bef, 0x0ca1,
+ 0x6bf0, 0x21bb,
+ 0x6bf2, 0x21bc,
+ 0x6bf7, 0x244c,
+ 0x6bf9, 0x244b,
+ 0x6bfa, 0x3f79,
+ 0x6bfb, 0x2449,
+ 0x6bfd, 0x0e4f,
+ 0x6bfe, 0x26ea,
+ 0x6bff, 0x292b,
+ 0x6c00, 0x292a,
+ 0x6c01, 0x2929,
+ 0x6c02, 0x292c,
+ 0x6c03, 0x2b91,
+ 0x6c04, 0x2b90,
+ 0x6c05, 0x12de,
+ 0x6c06, 0x2b92,
+ 0x6c08, 0x13f3,
+ 0x6c09, 0x2d8c,
+ 0x6c0b, 0x2f41,
+ 0x6c0c, 0x30a9,
+ 0x6c0d, 0x3388,
+ 0x6c0f, 0x02e4,
+ 0x6c10, 0x0350,
+ 0x6c11, 0x034f,
+ 0x6c13, 0x061e,
+ 0x6c14, 0x178c,
+ 0x6c15, 0x17aa,
+ 0x6c16, 0x03e6,
+ 0x6c18, 0x1801,
+ 0x6c19, 0x18ae,
+ 0x6c1b, 0x061f,
+ 0x6c1c, 0x38ab,
+ 0x6c1d, 0x19cd,
+ 0x6c1f, 0x076f,
+ 0x6c20, 0x1b44,
+ 0x6c23, 0x0902,
+ 0x6c24, 0x0906,
+ 0x6c25, 0x1cf4,
+ 0x6c26, 0x0905,
+ 0x6c27, 0x0903,
+ 0x6c2a, 0x1f44,
+ 0x6c2b, 0x0aeb,
+ 0x6c2c, 0x0ca4,
+ 0x6c2e, 0x0ca2,
+ 0x6c30, 0x21be,
+ 0x6c31, 0x3f63,
+ 0x6c33, 0x1003,
+ 0x6c34, 0x02e5,
+ 0x6c35, 0x44ef,
+ 0x6c36, 0x17ab,
+ 0x6c37, 0x4208,
+ 0x6c38, 0x0351,
+ 0x6c39, 0x3e05,
+ 0x6c3a, 0x44f0,
+ 0x6c3b, 0x17ae,
+ 0x6c3d, 0x4381,
+ 0x6c3e, 0x0354,
+ 0x6c3f, 0x17ad,
+ 0x6c40, 0x0353,
+ 0x6c41, 0x0352,
+ 0x6c42, 0x04cb,
+ 0x6c43, 0x17ac,
+ 0x6c46, 0x1802,
+ 0x6c49, 0x408d,
+ 0x6c4a, 0x1806,
+ 0x6c4b, 0x1808,
+ 0x6c4d, 0x03f0,
+ 0x6c4f, 0x1805,
+ 0x6c50, 0x03ec,
+ 0x6c52, 0x1803,
+ 0x6c54, 0x1807,
+ 0x6c55, 0x03ed,
+ 0x6c57, 0x03e8,
+ 0x6c58, 0x3bba,
+ 0x6c59, 0x03e9,
+ 0x6c5a, 0x420c,
+ 0x6c5b, 0x03ef,
+ 0x6c5c, 0x1804,
+ 0x6c5d, 0x03e7,
+ 0x6c5e, 0x04cc,
+ 0x6c5f, 0x03ea,
+ 0x6c61, 0x03ee,
+ 0x6c65, 0x18c0,
+ 0x6c66, 0x18be,
+ 0x6c67, 0x18b1,
+ 0x6c68, 0x04d8,
+ 0x6c69, 0x18b8,
+ 0x6c6a, 0x04d3,
+ 0x6c6b, 0x18b2,
+ 0x6c6d, 0x18ba,
+ 0x6c6e, 0x40ca,
+ 0x6c6f, 0x18b7,
+ 0x6c70, 0x04d6,
+ 0x6c71, 0x18b6,
+ 0x6c72, 0x04dd,
+ 0x6c73, 0x18bf,
+ 0x6c74, 0x04df,
+ 0x6c75, 0x466e,
+ 0x6c76, 0x04e1,
+ 0x6c78, 0x18b0,
+ 0x6c79, 0x420e,
+ 0x6c7a, 0x04d4,
+ 0x6c7b, 0x18c1,
+ 0x6c7d, 0x04db,
+ 0x6c7e, 0x04de,
+ 0x6c7f, 0x37a6,
+ 0x6c80, 0x19e4,
+ 0x6c81, 0x04ce,
+ 0x6c82, 0x04e5,
+ 0x6c83, 0x04dc,
+ 0x6c84, 0x18b3,
+ 0x6c85, 0x04d1,
+ 0x6c86, 0x04e0,
+ 0x6c87, 0x18bb,
+ 0x6c88, 0x04cf,
+ 0x6c8a, 0x19e2,
+ 0x6c8b, 0x18b4,
+ 0x6c8c, 0x04d7,
+ 0x6c8d, 0x04e2,
+ 0x6c8e, 0x18c2,
+ 0x6c8f, 0x18b5,
+ 0x6c90, 0x04d5,
+ 0x6c92, 0x04da,
+ 0x6c93, 0x19ce,
+ 0x6c94, 0x04e3,
+ 0x6c95, 0x18bc,
+ 0x6c96, 0x04d9,
+ 0x6c98, 0x04e4,
+ 0x6c99, 0x04cd,
+ 0x6c9a, 0x18b9,
+ 0x6c9b, 0x04d2,
+ 0x6c9c, 0x18bd,
+ 0x6c9d, 0x19e3,
+ 0x6c9f, 0x3889,
+ 0x6ca2, 0x3d63,
+ 0x6caa, 0x466f,
+ 0x6cab, 0x062b,
+ 0x6cac, 0x063b,
+ 0x6cad, 0x19d5,
+ 0x6cae, 0x0632,
+ 0x6caf, 0x3cf6,
+ 0x6cb0, 0x19ea,
+ 0x6cb1, 0x0623,
+ 0x6cb2, 0x3ecc,
+ 0x6cb3, 0x0626,
+ 0x6cb4, 0x19e1,
+ 0x6cb6, 0x19d3,
+ 0x6cb7, 0x19d7,
+ 0x6cb8, 0x062e,
+ 0x6cb9, 0x0630,
+ 0x6cba, 0x19da,
+ 0x6cbb, 0x0637,
+ 0x6cbc, 0x0629,
+ 0x6cbd, 0x0627,
+ 0x6cbf, 0x0636,
+ 0x6cc0, 0x19e6,
+ 0x6cc1, 0x0631,
+ 0x6cc2, 0x19d9,
+ 0x6cc3, 0x19db,
+ 0x6cc4, 0x062f,
+ 0x6cc5, 0x0634,
+ 0x6cc6, 0x19dc,
+ 0x6cc7, 0x19e9,
+ 0x6cc9, 0x0770,
+ 0x6cca, 0x063a,
+ 0x6ccb, 0x4070,
+ 0x6ccc, 0x0624,
+ 0x6ccd, 0x19e8,
+ 0x6cce, 0x3f91,
+ 0x6ccf, 0x19ec,
+ 0x6cd0, 0x19d8,
+ 0x6cd1, 0x19ee,
+ 0x6cd2, 0x19df,
+ 0x6cd3, 0x062d,
+ 0x6cd4, 0x19d4,
+ 0x6cd5, 0x062c,
+ 0x6cd6, 0x063e,
+ 0x6cd7, 0x0633,
+ 0x6cd9, 0x19d2,
+ 0x6cda, 0x1b4e,
+ 0x6cdb, 0x0639,
+ 0x6cdc, 0x063d,
+ 0x6cdd, 0x19e0,
+ 0x6cde, 0x19e5,
+ 0x6cdf, 0x3d57,
+ 0x6ce0, 0x063f,
+ 0x6ce1, 0x0638,
+ 0x6ce2, 0x062a,
+ 0x6ce3, 0x0620,
+ 0x6ce5, 0x0625,
+ 0x6ce7, 0x19d6,
+ 0x6ce8, 0x0621,
+ 0x6ce9, 0x19ed,
+ 0x6cea, 0x3f8d,
+ 0x6ceb, 0x19d0,
+ 0x6cec, 0x19cf,
+ 0x6ced, 0x19dd,
+ 0x6cee, 0x19d1,
+ 0x6cef, 0x063c,
+ 0x6cf0, 0x0907,
+ 0x6cf1, 0x0635,
+ 0x6cf2, 0x19de,
+ 0x6cf3, 0x0622,
+ 0x6cf5, 0x077f,
+ 0x6cf9, 0x19eb,
+ 0x6d00, 0x1b55,
+ 0x6d01, 0x1b58,
+ 0x6d02, 0x4671,
+ 0x6d03, 0x1b5b,
+ 0x6d04, 0x1b50,
+ 0x6d05, 0x3a19,
+ 0x6d06, 0x4672,
+ 0x6d07, 0x1b5e,
+ 0x6d08, 0x1b61,
+ 0x6d09, 0x1b63,
+ 0x6d0a, 0x1b4d,
+ 0x6d0b, 0x0771,
+ 0x6d0c, 0x0776,
+ 0x6d0d, 0x1cf9,
+ 0x6d0e, 0x0786,
+ 0x6d0f, 0x1b5c,
+ 0x6d10, 0x1b64,
+ 0x6d11, 0x1b54,
+ 0x6d12, 0x1b4c,
+ 0x6d16, 0x1d14,
+ 0x6d17, 0x0779,
+ 0x6d18, 0x1b59,
+ 0x6d19, 0x1b51,
+ 0x6d1a, 0x1b53,
+ 0x6d1b, 0x077e,
+ 0x6d1d, 0x1b56,
+ 0x6d1e, 0x0778,
+ 0x6d1f, 0x1b49,
+ 0x6d20, 0x1b5f,
+ 0x6d22, 0x1b62,
+ 0x6d24, 0x3ac3,
+ 0x6d25, 0x0775,
+ 0x6d26, 0x4673,
+ 0x6d27, 0x0781,
+ 0x6d28, 0x1b46,
+ 0x6d29, 0x0783,
+ 0x6d2a, 0x0773,
+ 0x6d2b, 0x0787,
+ 0x6d2c, 0x1b60,
+ 0x6d2d, 0x1b48,
+ 0x6d2e, 0x0784,
+ 0x6d2f, 0x1d0e,
+ 0x6d30, 0x19e7,
+ 0x6d31, 0x0777,
+ 0x6d32, 0x0772,
+ 0x6d33, 0x1b4f,
+ 0x6d34, 0x1b47,
+ 0x6d35, 0x0785,
+ 0x6d36, 0x077d,
+ 0x6d37, 0x1b5a,
+ 0x6d38, 0x0782,
+ 0x6d39, 0x0780,
+ 0x6d3a, 0x1b52,
+ 0x6d3b, 0x077a,
+ 0x6d3c, 0x1b4a,
+ 0x6d3d, 0x077b,
+ 0x6d3f, 0x1b4b,
+ 0x6d40, 0x1b5d,
+ 0x6d41, 0x0774,
+ 0x6d42, 0x1b57,
+ 0x6d4e, 0x4558,
+ 0x6d57, 0x3cf3,
+ 0x6d58, 0x1cfc,
+ 0x6d59, 0x090f,
+ 0x6d5a, 0x0914,
+ 0x6d5b, 0x409c,
+ 0x6d5c, 0x4222,
+ 0x6d5e, 0x1d05,
+ 0x6d5f, 0x1d0b,
+ 0x6d60, 0x1d07,
+ 0x6d61, 0x1cfa,
+ 0x6d62, 0x1cfd,
+ 0x6d63, 0x1cf6,
+ 0x6d65, 0x091b,
+ 0x6d66, 0x090c,
+ 0x6d67, 0x1d06,
+ 0x6d68, 0x1d0f,
+ 0x6d69, 0x0916,
+ 0x6d6a, 0x0908,
+ 0x6d6c, 0x0911,
+ 0x6d6d, 0x1cfe,
+ 0x6d6e, 0x0913,
+ 0x6d6f, 0x1cff,
+ 0x6d70, 0x1d09,
+ 0x6d71, 0x40f5,
+ 0x6d72, 0x39d7,
+ 0x6d74, 0x0915,
+ 0x6d75, 0x1d18,
+ 0x6d76, 0x1cf8,
+ 0x6d77, 0x090e,
+ 0x6d78, 0x090d,
+ 0x6d79, 0x0919,
+ 0x6d7a, 0x1cf5,
+ 0x6d7b, 0x1d16,
+ 0x6d7c, 0x1d0a,
+ 0x6d7d, 0x1d17,
+ 0x6d7e, 0x1d11,
+ 0x6d7f, 0x1d03,
+ 0x6d80, 0x1d12,
+ 0x6d81, 0x4674,
+ 0x6d82, 0x1d0c,
+ 0x6d83, 0x1d15,
+ 0x6d84, 0x1d13,
+ 0x6d85, 0x091a,
+ 0x6d86, 0x1d04,
+ 0x6d87, 0x090b,
+ 0x6d88, 0x090a,
+ 0x6d89, 0x0912,
+ 0x6d8a, 0x0918,
+ 0x6d8b, 0x1d10,
+ 0x6d8c, 0x0917,
+ 0x6d8d, 0x1d01,
+ 0x6d8e, 0x0aec,
+ 0x6d8f, 0x3de8,
+ 0x6d90, 0x1d19,
+ 0x6d91, 0x1d00,
+ 0x6d92, 0x1cfb,
+ 0x6d93, 0x0910,
+ 0x6d94, 0x091c,
+ 0x6d95, 0x0909,
+ 0x6d96, 0x4221,
+ 0x6d97, 0x1d08,
+ 0x6d98, 0x1d0d,
+ 0x6da4, 0x4676,
+ 0x6da5, 0x3ab9,
+ 0x6daa, 0x0b0e,
+ 0x6dab, 0x1f46,
+ 0x6dac, 0x1f4a,
+ 0x6dae, 0x0afb,
+ 0x6daf, 0x0af9,
+ 0x6db1, 0x4677,
+ 0x6db2, 0x0af0,
+ 0x6db3, 0x1f48,
+ 0x6db4, 0x1f47,
+ 0x6db5, 0x0b04,
+ 0x6db7, 0x1f4d,
+ 0x6db8, 0x0afe,
+ 0x6db9, 0x3ffb,
+ 0x6dba, 0x1f5f,
+ 0x6dbb, 0x1f6b,
+ 0x6dbc, 0x0aed,
+ 0x6dbd, 0x1f5c,
+ 0x6dbe, 0x1f55,
+ 0x6dbf, 0x0b10,
+ 0x6dc0, 0x1f45,
+ 0x6dc2, 0x1f61,
+ 0x6dc4, 0x0b0d,
+ 0x6dc5, 0x0b01,
+ 0x6dc6, 0x0b0c,
+ 0x6dc7, 0x0af7,
+ 0x6dc8, 0x1f51,
+ 0x6dc9, 0x1f63,
+ 0x6dca, 0x1f5b,
+ 0x6dcb, 0x0af8,
+ 0x6dcc, 0x0af2,
+ 0x6dcd, 0x1f69,
+ 0x6dcf, 0x1f62,
+ 0x6dd0, 0x1f64,
+ 0x6dd1, 0x0afa,
+ 0x6dd2, 0x0b02,
+ 0x6dd3, 0x1f66,
+ 0x6dd4, 0x1f4f,
+ 0x6dd5, 0x1f60,
+ 0x6dd6, 0x1f54,
+ 0x6dd7, 0x1f68,
+ 0x6dd8, 0x0b07,
+ 0x6dd9, 0x0aef,
+ 0x6dda, 0x0b05,
+ 0x6ddb, 0x1f59,
+ 0x6ddc, 0x1f57,
+ 0x6dde, 0x0afc,
+ 0x6ddf, 0x1f53,
+ 0x6de0, 0x1f52,
+ 0x6de1, 0x0af1,
+ 0x6de2, 0x1f4c,
+ 0x6de3, 0x1f6a,
+ 0x6de4, 0x0af3,
+ 0x6de5, 0x1f56,
+ 0x6de6, 0x0b11,
+ 0x6de8, 0x0b0b,
+ 0x6de9, 0x1f4b,
+ 0x6dea, 0x0b08,
+ 0x6deb, 0x0b06,
+ 0x6dec, 0x0b0f,
+ 0x6ded, 0x1f5d,
+ 0x6dee, 0x0b0a,
+ 0x6def, 0x1d02,
+ 0x6df0, 0x1f5e,
+ 0x6df1, 0x0b09,
+ 0x6df2, 0x1f65,
+ 0x6df3, 0x0aee,
+ 0x6df4, 0x1f5a,
+ 0x6df5, 0x0b00,
+ 0x6df6, 0x1f4e,
+ 0x6df7, 0x0aff,
+ 0x6df9, 0x0afd,
+ 0x6dfa, 0x0af5,
+ 0x6dfb, 0x0af4,
+ 0x6dfc, 0x21bf,
+ 0x6dfd, 0x1f67,
+ 0x6e00, 0x1f50,
+ 0x6e02, 0x3cfa,
+ 0x6e03, 0x21d4,
+ 0x6e04, 0x3abe,
+ 0x6e05, 0x0af6,
+ 0x6e0a, 0x3ac1,
+ 0x6e0f, 0x3cf0,
+ 0x6e15, 0x4678,
+ 0x6e18, 0x4679,
+ 0x6e19, 0x0cc1,
+ 0x6e1a, 0x0b03,
+ 0x6e1b, 0x0caf,
+ 0x6e1c, 0x21ce,
+ 0x6e1d, 0x0cbd,
+ 0x6e1f, 0x21c2,
+ 0x6e20, 0x0cac,
+ 0x6e21, 0x0ca8,
+ 0x6e22, 0x21e0,
+ 0x6e23, 0x0cae,
+ 0x6e24, 0x0cb2,
+ 0x6e25, 0x0cad,
+ 0x6e26, 0x0cb6,
+ 0x6e27, 0x21e4,
+ 0x6e28, 0x21db,
+ 0x6e29, 0x467a,
+ 0x6e2a, 0x4302,
+ 0x6e2b, 0x21c9,
+ 0x6e2c, 0x0cbb,
+ 0x6e2d, 0x0cb5,
+ 0x6e2e, 0x21d5,
+ 0x6e2f, 0x0ca5,
+ 0x6e30, 0x21e1,
+ 0x6e31, 0x21da,
+ 0x6e32, 0x0ca9,
+ 0x6e33, 0x21cf,
+ 0x6e34, 0x0cb8,
+ 0x6e35, 0x21ec,
+ 0x6e38, 0x0ca6,
+ 0x6e39, 0x21df,
+ 0x6e3a, 0x0cba,
+ 0x6e3b, 0x21d3,
+ 0x6e3c, 0x21c5,
+ 0x6e3e, 0x0cbe,
+ 0x6e3f, 0x21ca,
+ 0x6e40, 0x21d1,
+ 0x6e41, 0x21cb,
+ 0x6e43, 0x0cbc,
+ 0x6e44, 0x0cc4,
+ 0x6e45, 0x21c7,
+ 0x6e46, 0x21c0,
+ 0x6e49, 0x21c3,
+ 0x6e4a, 0x0cab,
+ 0x6e4b, 0x21d0,
+ 0x6e4d, 0x0cb9,
+ 0x6e4e, 0x0cc2,
+ 0x6e4f, 0x4234,
+ 0x6e50, 0x41d1,
+ 0x6e51, 0x21d2,
+ 0x6e52, 0x21ea,
+ 0x6e53, 0x21e2,
+ 0x6e54, 0x0ca7,
+ 0x6e55, 0x21e8,
+ 0x6e56, 0x0cb3,
+ 0x6e58, 0x0cb1,
+ 0x6e59, 0x40e6,
+ 0x6e5a, 0x21ee,
+ 0x6e5b, 0x0cb0,
+ 0x6e5c, 0x21d8,
+ 0x6e5d, 0x21cc,
+ 0x6e5e, 0x21d6,
+ 0x6e5f, 0x0cc7,
+ 0x6e60, 0x21dc,
+ 0x6e61, 0x21d9,
+ 0x6e62, 0x21c8,
+ 0x6e63, 0x0cc3,
+ 0x6e64, 0x21e6,
+ 0x6e65, 0x21e3,
+ 0x6e66, 0x21eb,
+ 0x6e67, 0x0caa,
+ 0x6e68, 0x21d7,
+ 0x6e69, 0x0cc6,
+ 0x6e6b, 0x21de,
+ 0x6e6e, 0x0cb4,
+ 0x6e6f, 0x0cb7,
+ 0x6e71, 0x21dd,
+ 0x6e72, 0x0cc5,
+ 0x6e73, 0x21cd,
+ 0x6e74, 0x1f49,
+ 0x6e76, 0x39d3,
+ 0x6e77, 0x21e7,
+ 0x6e78, 0x21e5,
+ 0x6e79, 0x21e9,
+ 0x6e7c, 0x4223,
+ 0x6e86, 0x467b,
+ 0x6e88, 0x21c4,
+ 0x6e89, 0x0cc0,
+ 0x6e8b, 0x3bbf,
+ 0x6e8d, 0x246c,
+ 0x6e8e, 0x246b,
+ 0x6e8f, 0x2451,
+ 0x6e90, 0x0e55,
+ 0x6e92, 0x246a,
+ 0x6e93, 0x2454,
+ 0x6e96, 0x0e5f,
+ 0x6e97, 0x2473,
+ 0x6e98, 0x0e5a,
+ 0x6e99, 0x2469,
+ 0x6e9a, 0x4581,
+ 0x6e9b, 0x244e,
+ 0x6e9c, 0x0e60,
+ 0x6e9d, 0x0e56,
+ 0x6e9e, 0x245d,
+ 0x6e9f, 0x2453,
+ 0x6ea0, 0x2456,
+ 0x6ea1, 0x246e,
+ 0x6ea2, 0x0e50,
+ 0x6ea3, 0x2475,
+ 0x6ea4, 0x246d,
+ 0x6ea5, 0x0e59,
+ 0x6ea6, 0x2462,
+ 0x6ea7, 0x0e64,
+ 0x6eaa, 0x0e63,
+ 0x6eab, 0x0e5d,
+ 0x6eae, 0x2474,
+ 0x6eaf, 0x0e51,
+ 0x6eb0, 0x2460,
+ 0x6eb1, 0x2457,
+ 0x6eb2, 0x2464,
+ 0x6eb3, 0x2470,
+ 0x6eb4, 0x0e65,
+ 0x6eb5, 0x41fe,
+ 0x6eb6, 0x0e53,
+ 0x6eb7, 0x245f,
+ 0x6eb8, 0x3e0c,
+ 0x6eb9, 0x2458,
+ 0x6eba, 0x0e5c,
+ 0x6ebb, 0x467d,
+ 0x6ebc, 0x0e5b,
+ 0x6ebd, 0x245b,
+ 0x6ebe, 0x2465,
+ 0x6ebf, 0x246f,
+ 0x6ec0, 0x2452,
+ 0x6ec1, 0x245c,
+ 0x6ec2, 0x0e54,
+ 0x6ec3, 0x2466,
+ 0x6ec4, 0x0e61,
+ 0x6ec5, 0x0e58,
+ 0x6ec6, 0x2459,
+ 0x6ec7, 0x0e57,
+ 0x6ec8, 0x2450,
+ 0x6ec9, 0x245e,
+ 0x6eca, 0x2472,
+ 0x6ecb, 0x0cbf,
+ 0x6ecc, 0x101f,
+ 0x6ecd, 0x2461,
+ 0x6ece, 0x26eb,
+ 0x6ecf, 0x2463,
+ 0x6ed0, 0x2471,
+ 0x6ed1, 0x0e5e,
+ 0x6ed2, 0x245a,
+ 0x6ed3, 0x0e52,
+ 0x6ed4, 0x0e62,
+ 0x6ed5, 0x119a,
+ 0x6ed6, 0x244f,
+ 0x6ed8, 0x2468,
+ 0x6ed9, 0x4069,
+ 0x6eda, 0x467f,
+ 0x6edb, 0x402f,
+ 0x6edc, 0x2467,
+ 0x6edd, 0x4538,
+ 0x6ee2, 0x467e,
+ 0x6ee8, 0x4681,
+ 0x6eeb, 0x2707,
+ 0x6eec, 0x101c,
+ 0x6eed, 0x26fc,
+ 0x6eee, 0x2701,
+ 0x6eef, 0x1011,
+ 0x6ef1, 0x26ed,
+ 0x6ef2, 0x101e,
+ 0x6ef4, 0x1008,
+ 0x6ef5, 0x26ec,
+ 0x6ef6, 0x270d,
+ 0x6ef7, 0x1020,
+ 0x6ef8, 0x26f0,
+ 0x6ef9, 0x2700,
+ 0x6efa, 0x423b,
+ 0x6efb, 0x26f2,
+ 0x6efc, 0x2710,
+ 0x6efd, 0x270c,
+ 0x6efe, 0x1006,
+ 0x6eff, 0x1010,
+ 0x6f00, 0x2946,
+ 0x6f01, 0x101d,
+ 0x6f02, 0x100e,
+ 0x6f03, 0x26ee,
+ 0x6f04, 0x4224,
+ 0x6f05, 0x270b,
+ 0x6f06, 0x1012,
+ 0x6f07, 0x2708,
+ 0x6f08, 0x2715,
+ 0x6f09, 0x26f4,
+ 0x6f0a, 0x26fd,
+ 0x6f0b, 0x3aba,
+ 0x6f0c, 0x3cfb,
+ 0x6f0d, 0x2713,
+ 0x6f0e, 0x2709,
+ 0x6f0f, 0x100d,
+ 0x6f12, 0x26fb,
+ 0x6f13, 0x1007,
+ 0x6f14, 0x1005,
+ 0x6f15, 0x1017,
+ 0x6f16, 0x41a0,
+ 0x6f17, 0x46ce,
+ 0x6f18, 0x26f9,
+ 0x6f19, 0x26f6,
+ 0x6f1c, 0x270f,
+ 0x6f1e, 0x2714,
+ 0x6f1f, 0x2712,
+ 0x6f20, 0x100b,
+ 0x6f21, 0x2716,
+ 0x6f22, 0x100f,
+ 0x6f23, 0x1016,
+ 0x6f24, 0x4683,
+ 0x6f25, 0x26ef,
+ 0x6f26, 0x292e,
+ 0x6f27, 0x26f8,
+ 0x6f29, 0x1009,
+ 0x6f2a, 0x101b,
+ 0x6f2b, 0x1018,
+ 0x6f2c, 0x100c,
+ 0x6f2d, 0x2702,
+ 0x6f2e, 0x26f3,
+ 0x6f2f, 0x1019,
+ 0x6f30, 0x2704,
+ 0x6f31, 0x1013,
+ 0x6f32, 0x1015,
+ 0x6f33, 0x1004,
+ 0x6f34, 0x4684,
+ 0x6f35, 0x2706,
+ 0x6f36, 0x26fe,
+ 0x6f37, 0x26f1,
+ 0x6f38, 0x1014,
+ 0x6f39, 0x270e,
+ 0x6f3a, 0x2711,
+ 0x6f3b, 0x26fa,
+ 0x6f3c, 0x2705,
+ 0x6f3d, 0x4282,
+ 0x6f3e, 0x100a,
+ 0x6f3f, 0x1189,
+ 0x6f40, 0x2703,
+ 0x6f41, 0x292d,
+ 0x6f43, 0x270a,
+ 0x6f44, 0x4240,
+ 0x6f4e, 0x26f5,
+ 0x6f4f, 0x2937,
+ 0x6f50, 0x2941,
+ 0x6f51, 0x118c,
+ 0x6f52, 0x2940,
+ 0x6f53, 0x294c,
+ 0x6f54, 0x118e,
+ 0x6f55, 0x293e,
+ 0x6f56, 0x3e52,
+ 0x6f57, 0x2942,
+ 0x6f58, 0x1199,
+ 0x6f5a, 0x2939,
+ 0x6f5b, 0x1191,
+ 0x6f5c, 0x4241,
+ 0x6f5d, 0x2945,
+ 0x6f5e, 0x2b9a,
+ 0x6f5f, 0x119d,
+ 0x6f60, 0x119c,
+ 0x6f61, 0x2947,
+ 0x6f62, 0x2936,
+ 0x6f63, 0x2951,
+ 0x6f64, 0x1197,
+ 0x6f66, 0x118d,
+ 0x6f67, 0x294a,
+ 0x6f69, 0x294e,
+ 0x6f6a, 0x2953,
+ 0x6f6b, 0x2948,
+ 0x6f6c, 0x293c,
+ 0x6f6d, 0x1190,
+ 0x6f6e, 0x1193,
+ 0x6f6f, 0x119b,
+ 0x6f70, 0x1196,
+ 0x6f72, 0x293f,
+ 0x6f73, 0x26ff,
+ 0x6f74, 0x4243,
+ 0x6f76, 0x293b,
+ 0x6f77, 0x2952,
+ 0x6f78, 0x1192,
+ 0x6f79, 0x3bbe,
+ 0x6f7a, 0x1195,
+ 0x6f7b, 0x2954,
+ 0x6f7c, 0x118a,
+ 0x6f7d, 0x2949,
+ 0x6f7e, 0x292f,
+ 0x6f7f, 0x294f,
+ 0x6f80, 0x13fc,
+ 0x6f81, 0x4687,
+ 0x6f82, 0x293d,
+ 0x6f84, 0x118b,
+ 0x6f85, 0x2938,
+ 0x6f86, 0x118f,
+ 0x6f87, 0x2930,
+ 0x6f88, 0x101a,
+ 0x6f89, 0x2934,
+ 0x6f8a, 0x4195,
+ 0x6f8b, 0x294d,
+ 0x6f8c, 0x2935,
+ 0x6f8d, 0x2933,
+ 0x6f8e, 0x1194,
+ 0x6f90, 0x294b,
+ 0x6f92, 0x2932,
+ 0x6f93, 0x2944,
+ 0x6f94, 0x2943,
+ 0x6f95, 0x2950,
+ 0x6f96, 0x293a,
+ 0x6f97, 0x1198,
+ 0x6f9d, 0x4239,
+ 0x6f9e, 0x2b9d,
+ 0x6f9f, 0x4246,
+ 0x6fa0, 0x12eb,
+ 0x6fa1, 0x12e1,
+ 0x6fa2, 0x2ba9,
+ 0x6fa3, 0x2b95,
+ 0x6fa4, 0x12e3,
+ 0x6fa5, 0x2ba1,
+ 0x6fa6, 0x12ea,
+ 0x6fa7, 0x12e5,
+ 0x6fa8, 0x2b9f,
+ 0x6fa9, 0x2d8e,
+ 0x6faa, 0x2ba5,
+ 0x6fab, 0x2bab,
+ 0x6fac, 0x2ba4,
+ 0x6fad, 0x2b93,
+ 0x6fae, 0x2ba2,
+ 0x6faf, 0x2bad,
+ 0x6fb0, 0x2baf,
+ 0x6fb1, 0x12e0,
+ 0x6fb2, 0x2bae,
+ 0x6fb3, 0x12e6,
+ 0x6fb4, 0x12ec,
+ 0x6fb5, 0x3e27,
+ 0x6fb6, 0x12e9,
+ 0x6fb8, 0x2ba8,
+ 0x6fb9, 0x12e8,
+ 0x6fba, 0x2ba3,
+ 0x6fbb, 0x3bbb,
+ 0x6fbc, 0x2b97,
+ 0x6fbd, 0x2b9c,
+ 0x6fbe, 0x4688,
+ 0x6fbf, 0x2ba7,
+ 0x6fc0, 0x12e7,
+ 0x6fc1, 0x12e4,
+ 0x6fc2, 0x12df,
+ 0x6fc3, 0x12e2,
+ 0x6fc4, 0x2b9b,
+ 0x6fc6, 0x2931,
+ 0x6fc7, 0x2b96,
+ 0x6fc8, 0x2b99,
+ 0x6fc9, 0x2baa,
+ 0x6fca, 0x2b9e,
+ 0x6fcb, 0x2b94,
+ 0x6fcc, 0x2d8d,
+ 0x6fcd, 0x2bac,
+ 0x6fce, 0x2b98,
+ 0x6fcf, 0x2ba6,
+ 0x6fd3, 0x4248,
+ 0x6fd4, 0x2d90,
+ 0x6fd5, 0x1400,
+ 0x6fd8, 0x13f4,
+ 0x6fd9, 0x3c74,
+ 0x6fda, 0x3c73,
+ 0x6fdb, 0x13f8,
+ 0x6fdc, 0x2d92,
+ 0x6fdd, 0x2d98,
+ 0x6fde, 0x2d96,
+ 0x6fdf, 0x13f6,
+ 0x6fe1, 0x13fe,
+ 0x6fe2, 0x2d99,
+ 0x6fe3, 0x2d91,
+ 0x6fe4, 0x13f9,
+ 0x6fe6, 0x2d95,
+ 0x6fe7, 0x2d94,
+ 0x6fe8, 0x2d9a,
+ 0x6fe9, 0x13ff,
+ 0x6feb, 0x13fa,
+ 0x6fec, 0x13fd,
+ 0x6fed, 0x2d93,
+ 0x6fee, 0x1401,
+ 0x6fef, 0x13fb,
+ 0x6ff0, 0x1402,
+ 0x6ff1, 0x13f5,
+ 0x6ff2, 0x2d97,
+ 0x6ff4, 0x2d8f,
+ 0x6ff6, 0x38a5,
+ 0x6ff7, 0x2f4e,
+ 0x6ff8, 0x4237,
+ 0x6ffa, 0x14eb,
+ 0x6ffb, 0x2f4b,
+ 0x6ffc, 0x2f4d,
+ 0x6ffe, 0x14e9,
+ 0x6fff, 0x2f49,
+ 0x7000, 0x2f4a,
+ 0x7001, 0x2f45,
+ 0x7003, 0x46e2,
+ 0x7004, 0x2ba0,
+ 0x7005, 0x2f46,
+ 0x7006, 0x14ea,
+ 0x7007, 0x2f42,
+ 0x7009, 0x14e7,
+ 0x700a, 0x2f4f,
+ 0x700b, 0x14e8,
+ 0x700c, 0x2f43,
+ 0x700e, 0x2f48,
+ 0x700f, 0x14ed,
+ 0x7011, 0x14ec,
+ 0x7014, 0x2f47,
+ 0x7015, 0x158f,
+ 0x7016, 0x30ad,
+ 0x7017, 0x30b3,
+ 0x7018, 0x1590,
+ 0x7019, 0x30aa,
+ 0x701a, 0x158d,
+ 0x701b, 0x158a,
+ 0x701c, 0x30b5,
+ 0x701d, 0x158e,
+ 0x701e, 0x3c76,
+ 0x701f, 0x158b,
+ 0x7020, 0x30ac,
+ 0x7021, 0x30af,
+ 0x7024, 0x30b4,
+ 0x7026, 0x2f4c,
+ 0x7027, 0x30ab,
+ 0x7028, 0x158c,
+ 0x7029, 0x30b2,
+ 0x702a, 0x31ef,
+ 0x702b, 0x30ae,
+ 0x702c, 0x468e,
+ 0x702f, 0x31e6,
+ 0x7030, 0x161d,
+ 0x7031, 0x31e9,
+ 0x7032, 0x161e,
+ 0x7033, 0x31f2,
+ 0x7034, 0x31e8,
+ 0x7035, 0x31e5,
+ 0x7037, 0x31e7,
+ 0x7038, 0x31eb,
+ 0x7039, 0x31ee,
+ 0x703a, 0x31ed,
+ 0x703b, 0x31f1,
+ 0x703c, 0x31e4,
+ 0x703e, 0x161c,
+ 0x703f, 0x31ec,
+ 0x7040, 0x31f0,
+ 0x7041, 0x31f3,
+ 0x7042, 0x31ea,
+ 0x7043, 0x32d8,
+ 0x7045, 0x32dd,
+ 0x7048, 0x32db,
+ 0x704a, 0x32da,
+ 0x704b, 0x4254,
+ 0x704c, 0x167a,
+ 0x7050, 0x4690,
+ 0x7051, 0x16c8,
+ 0x7052, 0x338c,
+ 0x7054, 0x4691,
+ 0x7055, 0x3389,
+ 0x7058, 0x16c9,
+ 0x705a, 0x3423,
+ 0x705b, 0x3422,
+ 0x705c, 0x3852,
+ 0x705d, 0x348a,
+ 0x705e, 0x1722,
+ 0x705f, 0x3488,
+ 0x7060, 0x348b,
+ 0x7061, 0x3489,
+ 0x7062, 0x34d0,
+ 0x7063, 0x1744,
+ 0x7064, 0x1752,
+ 0x7065, 0x351c,
+ 0x7066, 0x3506,
+ 0x7067, 0x3cf5,
+ 0x7068, 0x351b,
+ 0x7069, 0x3547,
+ 0x706b, 0x02e6,
+ 0x706c, 0x44f1,
+ 0x706f, 0x4692,
+ 0x7070, 0x03f2,
+ 0x7071, 0x180a,
+ 0x7074, 0x18c3,
+ 0x7075, 0x38c7,
+ 0x7076, 0x04e6,
+ 0x7078, 0x04e9,
+ 0x7079, 0x4099,
+ 0x707a, 0x18c4,
+ 0x707c, 0x04e7,
+ 0x707e, 0x4255,
+ 0x707f, 0x4693,
+ 0x7081, 0x4959,
+ 0x7082, 0x19f7,
+ 0x7083, 0x19f9,
+ 0x7084, 0x19f4,
+ 0x7085, 0x19f1,
+ 0x7086, 0x19f3,
+ 0x7089, 0x43f9,
+ 0x708a, 0x0643,
+ 0x708b, 0x40cb,
+ 0x708e, 0x0641,
+ 0x708f, 0x46b3,
+ 0x7091, 0x19f5,
+ 0x7092, 0x0642,
+ 0x7093, 0x19f2,
+ 0x7094, 0x19ef,
+ 0x7095, 0x0640,
+ 0x7096, 0x19f6,
+ 0x7098, 0x19f0,
+ 0x7099, 0x0644,
+ 0x709a, 0x19f8,
+ 0x709f, 0x1b66,
+ 0x70a0, 0x4742,
+ 0x70a1, 0x1b6a,
+ 0x70a3, 0x3972,
+ 0x70a4, 0x0790,
+ 0x70a5, 0x3cb7,
+ 0x70a6, 0x3d53,
+ 0x70a7, 0x4256,
+ 0x70a9, 0x1b6d,
+ 0x70ab, 0x0788,
+ 0x70ac, 0x078b,
+ 0x70ad, 0x078d,
+ 0x70ae, 0x078f,
+ 0x70af, 0x078c,
+ 0x70b0, 0x1b69,
+ 0x70b1, 0x1b68,
+ 0x70b3, 0x078a,
+ 0x70b4, 0x1b6b,
+ 0x70b7, 0x1b65,
+ 0x70b8, 0x078e,
+ 0x70b9, 0x3d69,
+ 0x70ba, 0x0789,
+ 0x70bb, 0x4812,
+ 0x70bc, 0x4559,
+ 0x70bd, 0x4270,
+ 0x70be, 0x1b67,
+ 0x70c0, 0x4733,
+ 0x70c4, 0x3baa,
+ 0x70c5, 0x1d27,
+ 0x70c8, 0x0921,
+ 0x70ca, 0x091d,
+ 0x70cb, 0x1d1e,
+ 0x70cc, 0x4258,
+ 0x70cd, 0x1d26,
+ 0x70ce, 0x1d2b,
+ 0x70cf, 0x0922,
+ 0x70d0, 0x396d,
+ 0x70d1, 0x1d1c,
+ 0x70d2, 0x1d22,
+ 0x70d3, 0x1d1b,
+ 0x70d4, 0x1d25,
+ 0x70d5, 0x4259,
+ 0x70d7, 0x1d21,
+ 0x70d8, 0x091e,
+ 0x70d9, 0x0920,
+ 0x70da, 0x1d2a,
+ 0x70dc, 0x1d1a,
+ 0x70dd, 0x1d1d,
+ 0x70de, 0x1d23,
+ 0x70df, 0x425b,
+ 0x70e0, 0x1d24,
+ 0x70e1, 0x1d2c,
+ 0x70e2, 0x1d20,
+ 0x70e4, 0x091f,
+ 0x70ef, 0x0b16,
+ 0x70f0, 0x1f72,
+ 0x70f1, 0x3ac8,
+ 0x70f3, 0x1f74,
+ 0x70f4, 0x1f70,
+ 0x70f5, 0x4760,
+ 0x70f6, 0x1f7c,
+ 0x70f7, 0x1f6e,
+ 0x70f8, 0x1f7b,
+ 0x70f9, 0x0b12,
+ 0x70fa, 0x1f6c,
+ 0x70fb, 0x21f2,
+ 0x70fc, 0x1f76,
+ 0x70fd, 0x0b15,
+ 0x70fe, 0x3d0e,
+ 0x70ff, 0x1f77,
+ 0x7100, 0x1f7a,
+ 0x7102, 0x1f7e,
+ 0x7104, 0x1f73,
+ 0x7105, 0x3a23,
+ 0x7106, 0x1f78,
+ 0x7109, 0x0b13,
+ 0x710b, 0x1f7d,
+ 0x710c, 0x1f71,
+ 0x710d, 0x1f6d,
+ 0x710e, 0x1f7f,
+ 0x7110, 0x1f75,
+ 0x7113, 0x1f79,
+ 0x7117, 0x1f6f,
+ 0x7119, 0x0cc8,
+ 0x711b, 0x21fc,
+ 0x711c, 0x0ccf,
+ 0x711d, 0x3d47,
+ 0x711e, 0x21f0,
+ 0x711f, 0x21f9,
+ 0x7120, 0x21ef,
+ 0x7121, 0x0ccc,
+ 0x7122, 0x21f7,
+ 0x7123, 0x21f5,
+ 0x7125, 0x21f6,
+ 0x7126, 0x0cca,
+ 0x7128, 0x21fa,
+ 0x7129, 0x3ba9,
+ 0x712b, 0x4261,
+ 0x712c, 0x426a,
+ 0x712e, 0x21f3,
+ 0x712f, 0x21f1,
+ 0x7130, 0x0ccb,
+ 0x7131, 0x21f4,
+ 0x7132, 0x21f8,
+ 0x7133, 0x3d54,
+ 0x7134, 0x3c7e,
+ 0x7135, 0x376d,
+ 0x7136, 0x0ccd,
+ 0x713a, 0x21fb,
+ 0x713b, 0x3ac5,
+ 0x713e, 0x372e,
+ 0x7140, 0x4398,
+ 0x7141, 0x247b,
+ 0x7142, 0x2482,
+ 0x7143, 0x2484,
+ 0x7144, 0x248a,
+ 0x7145, 0x4262,
+ 0x7146, 0x0e72,
+ 0x7147, 0x2476,
+ 0x7149, 0x0e6a,
+ 0x714a, 0x4264,
+ 0x714b, 0x2485,
+ 0x714c, 0x0e6f,
+ 0x714d, 0x248b,
+ 0x714e, 0x0e66,
+ 0x714f, 0x4267,
+ 0x7150, 0x2488,
+ 0x7151, 0x4865,
+ 0x7152, 0x2478,
+ 0x7153, 0x2489,
+ 0x7154, 0x2477,
+ 0x7156, 0x0e74,
+ 0x7158, 0x2483,
+ 0x7159, 0x0e67,
+ 0x715a, 0x248c,
+ 0x715c, 0x0e6c,
+ 0x715d, 0x247c,
+ 0x715e, 0x0e71,
+ 0x715f, 0x2487,
+ 0x7160, 0x247a,
+ 0x7161, 0x2481,
+ 0x7162, 0x247d,
+ 0x7163, 0x2479,
+ 0x7164, 0x0e69,
+ 0x7165, 0x0e70,
+ 0x7166, 0x0e6e,
+ 0x7167, 0x0e6b,
+ 0x7168, 0x0e73,
+ 0x7169, 0x0e68,
+ 0x716a, 0x2480,
+ 0x716b, 0x3cc5,
+ 0x716c, 0x0e6d,
+ 0x716e, 0x0cce,
+ 0x7170, 0x2486,
+ 0x7171, 0x3dc0,
+ 0x7172, 0x247e,
+ 0x7173, 0x47e7,
+ 0x7175, 0x3ced,
+ 0x7176, 0x4000,
+ 0x7177, 0x3957,
+ 0x7178, 0x247f,
+ 0x717a, 0x4924,
+ 0x717b, 0x271e,
+ 0x717c, 0x3835,
+ 0x717d, 0x1023,
+ 0x717e, 0x3970,
+ 0x7180, 0x271a,
+ 0x7181, 0x2720,
+ 0x7182, 0x271c,
+ 0x7184, 0x1025,
+ 0x7185, 0x271b,
+ 0x7186, 0x271f,
+ 0x7187, 0x2717,
+ 0x7188, 0x4706,
+ 0x7189, 0x2719,
+ 0x718a, 0x1024,
+ 0x718c, 0x39ea,
+ 0x718e, 0x3d3b,
+ 0x718f, 0x271d,
+ 0x7190, 0x2718,
+ 0x7192, 0x1026,
+ 0x7194, 0x1021,
+ 0x7196, 0x425f,
+ 0x7197, 0x2721,
+ 0x7198, 0x481d,
+ 0x7199, 0x1022,
+ 0x719a, 0x295a,
+ 0x719b, 0x2957,
+ 0x719c, 0x2963,
+ 0x719d, 0x295d,
+ 0x719e, 0x295f,
+ 0x719f, 0x119e,
+ 0x71a0, 0x2959,
+ 0x71a1, 0x2961,
+ 0x71a2, 0x48c1,
+ 0x71a3, 0x3ec8,
+ 0x71a4, 0x2960,
+ 0x71a5, 0x295e,
+ 0x71a7, 0x2964,
+ 0x71a8, 0x11a1,
+ 0x71a9, 0x295b,
+ 0x71aa, 0x2962,
+ 0x71ac, 0x119f,
+ 0x71ad, 0x3e1d,
+ 0x71af, 0x2956,
+ 0x71b0, 0x2958,
+ 0x71b1, 0x11a0,
+ 0x71b2, 0x2955,
+ 0x71b3, 0x2965,
+ 0x71b4, 0x425e,
+ 0x71b5, 0x295c,
+ 0x71b7, 0x468b,
+ 0x71b8, 0x2bb3,
+ 0x71b9, 0x12f3,
+ 0x71ba, 0x426e,
+ 0x71bc, 0x2bbe,
+ 0x71bd, 0x2bbc,
+ 0x71be, 0x12ed,
+ 0x71bf, 0x2bb2,
+ 0x71c0, 0x2bb5,
+ 0x71c2, 0x2bb1,
+ 0x71c3, 0x12f7,
+ 0x71c5, 0x2bb0,
+ 0x71c6, 0x2bbf,
+ 0x71c7, 0x2bba,
+ 0x71c8, 0x12f1,
+ 0x71c9, 0x12ee,
+ 0x71ca, 0x2bb9,
+ 0x71cb, 0x2bb7,
+ 0x71ce, 0x12f4,
+ 0x71cf, 0x2bbb,
+ 0x71d0, 0x12ef,
+ 0x71d1, 0x373d,
+ 0x71d2, 0x12f0,
+ 0x71d4, 0x2bb8,
+ 0x71d5, 0x12f2,
+ 0x71d6, 0x2bb4,
+ 0x71d8, 0x2bbd,
+ 0x71d9, 0x12f5,
+ 0x71da, 0x2bc0,
+ 0x71dc, 0x12f6,
+ 0x71dd, 0x4078,
+ 0x71df, 0x1404,
+ 0x71e0, 0x140b,
+ 0x71e1, 0x2d9b,
+ 0x71e2, 0x2da1,
+ 0x71e4, 0x2d9f,
+ 0x71e5, 0x1407,
+ 0x71e6, 0x1406,
+ 0x71e7, 0x1403,
+ 0x71e8, 0x2d9d,
+ 0x71eb, 0x3c81,
+ 0x71ec, 0x1409,
+ 0x71ed, 0x1408,
+ 0x71ee, 0x1405,
+ 0x71f0, 0x2da0,
+ 0x71f1, 0x2d9c,
+ 0x71f2, 0x2d9e,
+ 0x71f4, 0x140a,
+ 0x71f5, 0x46ee,
+ 0x71f6, 0x3e9a,
+ 0x71f8, 0x14f1,
+ 0x71f9, 0x2f52,
+ 0x71fb, 0x14ee,
+ 0x71fd, 0x2f54,
+ 0x71fe, 0x14f0,
+ 0x71ff, 0x2f51,
+ 0x7201, 0x2f50,
+ 0x7202, 0x30b9,
+ 0x7203, 0x2f53,
+ 0x7205, 0x30ba,
+ 0x7206, 0x1591,
+ 0x7207, 0x30b8,
+ 0x7209, 0x3dbb,
+ 0x720a, 0x30b7,
+ 0x720c, 0x30b6,
+ 0x720d, 0x1592,
+ 0x720e, 0x4271,
+ 0x720f, 0x39fc,
+ 0x7210, 0x161f,
+ 0x7213, 0x31f4,
+ 0x7215, 0x4273,
+ 0x7216, 0x3953,
+ 0x7217, 0x3969,
+ 0x7219, 0x32e1,
+ 0x721a, 0x32e0,
+ 0x721b, 0x167b,
+ 0x721d, 0x32df,
+ 0x721e, 0x338d,
+ 0x7222, 0x3424,
+ 0x7223, 0x348c,
+ 0x7224, 0x4276,
+ 0x7226, 0x34d1,
+ 0x7227, 0x3535,
+ 0x7228, 0x1766,
+ 0x7229, 0x3549,
+ 0x722a, 0x02e7,
+ 0x722b, 0x44f2,
+ 0x722c, 0x0645,
+ 0x722e, 0x4279,
+ 0x7230, 0x0791,
+ 0x7235, 0x140c,
+ 0x7236, 0x02e8,
+ 0x7238, 0x0647,
+ 0x7239, 0x0923,
+ 0x723a, 0x0e75,
+ 0x723b, 0x02e9,
+ 0x723d, 0x0b17,
+ 0x723e, 0x1027,
+ 0x723f, 0x178d,
+ 0x7240, 0x427a,
+ 0x7241, 0x1b6e,
+ 0x7242, 0x1d2d,
+ 0x7244, 0x2722,
+ 0x7246, 0x140d,
+ 0x7247, 0x02ea,
+ 0x7248, 0x0648,
+ 0x7249, 0x1b6f,
+ 0x724b, 0x21fd,
+ 0x724c, 0x0cd0,
+ 0x724f, 0x248d,
+ 0x7250, 0x3ac9,
+ 0x7252, 0x0e76,
+ 0x7253, 0x2723,
+ 0x7255, 0x427d,
+ 0x7256, 0x11a2,
+ 0x7257, 0x427e,
+ 0x7258, 0x1593,
+ 0x7259, 0x02eb,
+ 0x725a, 0x21fe,
+ 0x725b, 0x02ec,
+ 0x725c, 0x465a,
+ 0x725d, 0x03f4,
+ 0x725e, 0x180b,
+ 0x725f, 0x03f3,
+ 0x7260, 0x04ec,
+ 0x7261, 0x04eb,
+ 0x7262, 0x04ea,
+ 0x7263, 0x18c5,
+ 0x7266, 0x3ebb,
+ 0x7267, 0x0649,
+ 0x7269, 0x064a,
+ 0x726a, 0x19fa,
+ 0x726c, 0x1b71,
+ 0x726e, 0x1b74,
+ 0x726f, 0x0793,
+ 0x7270, 0x1b72,
+ 0x7272, 0x0792,
+ 0x7273, 0x1b73,
+ 0x7274, 0x0794,
+ 0x7276, 0x1d30,
+ 0x7277, 0x1d2f,
+ 0x7278, 0x1d2e,
+ 0x7279, 0x0924,
+ 0x727b, 0x1f81,
+ 0x727d, 0x0b18,
+ 0x727e, 0x1f80,
+ 0x727f, 0x1f83,
+ 0x7280, 0x0cd2,
+ 0x7281, 0x0b19,
+ 0x7282, 0x4283,
+ 0x7284, 0x0cd1,
+ 0x7285, 0x2202,
+ 0x7286, 0x2201,
+ 0x7287, 0x3aca,
+ 0x7288, 0x21ff,
+ 0x728b, 0x2203,
+ 0x728c, 0x248f,
+ 0x728d, 0x248e,
+ 0x728e, 0x2492,
+ 0x728f, 0x43c9,
+ 0x7290, 0x2491,
+ 0x7291, 0x2490,
+ 0x7292, 0x1028,
+ 0x7293, 0x2726,
+ 0x7294, 0x3acb,
+ 0x7295, 0x2725,
+ 0x7296, 0x1029,
+ 0x7297, 0x2724,
+ 0x7298, 0x2966,
+ 0x729a, 0x2967,
+ 0x729b, 0x11a3,
+ 0x729d, 0x2bc2,
+ 0x729f, 0x473a,
+ 0x72a1, 0x30bf,
+ 0x72a2, 0x1594,
+ 0x72a3, 0x30be,
+ 0x72a4, 0x30bd,
+ 0x72a5, 0x30bb,
+ 0x72a7, 0x167c,
+ 0x72a8, 0x31f6,
+ 0x72a9, 0x338f,
+ 0x72aa, 0x34d2,
+ 0x72ac, 0x02ed,
+ 0x72ad, 0x44f4,
+ 0x72ae, 0x17af,
+ 0x72af, 0x0355,
+ 0x72b0, 0x17b0,
+ 0x72b2, 0x3fb6,
+ 0x72b4, 0x180c,
+ 0x72ba, 0x18cb,
+ 0x72bd, 0x18c7,
+ 0x72bf, 0x18c6,
+ 0x72c0, 0x064b,
+ 0x72c1, 0x18ca,
+ 0x72c2, 0x04ee,
+ 0x72c3, 0x18c8,
+ 0x72c4, 0x04ed,
+ 0x72c5, 0x18cc,
+ 0x72c6, 0x18c9,
+ 0x72c9, 0x19fe,
+ 0x72ca, 0x1b75,
+ 0x72cb, 0x19fc,
+ 0x72cc, 0x1a03,
+ 0x72cd, 0x43ca,
+ 0x72ce, 0x064c,
+ 0x72d0, 0x064f,
+ 0x72d1, 0x1a04,
+ 0x72d2, 0x1a00,
+ 0x72d4, 0x1a01,
+ 0x72d6, 0x19fb,
+ 0x72d7, 0x064e,
+ 0x72d8, 0x19fd,
+ 0x72d9, 0x064d,
+ 0x72da, 0x1a02,
+ 0x72dc, 0x19ff,
+ 0x72df, 0x1b79,
+ 0x72e0, 0x0796,
+ 0x72e2, 0x3f97,
+ 0x72e3, 0x1b7c,
+ 0x72e4, 0x1b76,
+ 0x72e6, 0x1b7b,
+ 0x72e8, 0x1b77,
+ 0x72e9, 0x0795,
+ 0x72ea, 0x1b7a,
+ 0x72eb, 0x1b78,
+ 0x72f3, 0x1d36,
+ 0x72f4, 0x1d33,
+ 0x72f6, 0x1d35,
+ 0x72f7, 0x0929,
+ 0x72f8, 0x0928,
+ 0x72f9, 0x0926,
+ 0x72fa, 0x1d32,
+ 0x72fb, 0x1d37,
+ 0x72fc, 0x0925,
+ 0x72fd, 0x0927,
+ 0x72fe, 0x1d34,
+ 0x72ff, 0x1f8b,
+ 0x7300, 0x1d31,
+ 0x7301, 0x1d38,
+ 0x7302, 0x3f9a,
+ 0x7304, 0x3eb5,
+ 0x7307, 0x1f86,
+ 0x7308, 0x1f8a,
+ 0x730a, 0x1f89,
+ 0x730b, 0x2205,
+ 0x730c, 0x2210,
+ 0x730f, 0x1f8c,
+ 0x7310, 0x46ea,
+ 0x7311, 0x1f87,
+ 0x7312, 0x2204,
+ 0x7313, 0x0b1d,
+ 0x7316, 0x0b1c,
+ 0x7317, 0x1f85,
+ 0x7318, 0x1f88,
+ 0x7319, 0x0b1e,
+ 0x731b, 0x0b1b,
+ 0x731c, 0x0b1a,
+ 0x731d, 0x1f84,
+ 0x731e, 0x1f8d,
+ 0x7322, 0x2207,
+ 0x7323, 0x220e,
+ 0x7325, 0x0cd4,
+ 0x7326, 0x220d,
+ 0x7327, 0x220a,
+ 0x7328, 0x428a,
+ 0x7329, 0x0cd6,
+ 0x732a, 0x3d70,
+ 0x732b, 0x4285,
+ 0x732c, 0x3fb2,
+ 0x732d, 0x220c,
+ 0x732e, 0x428b,
+ 0x7330, 0x2206,
+ 0x7331, 0x2208,
+ 0x7332, 0x220b,
+ 0x7333, 0x2209,
+ 0x7334, 0x0cd5,
+ 0x7335, 0x220f,
+ 0x7336, 0x0cd3,
+ 0x7337, 0x0e77,
+ 0x7338, 0x46eb,
+ 0x7339, 0x43cc,
+ 0x733a, 0x2496,
+ 0x733b, 0x2495,
+ 0x733c, 0x2493,
+ 0x733e, 0x0e7a,
+ 0x733f, 0x0e79,
+ 0x7340, 0x2497,
+ 0x7341, 0x46ec,
+ 0x7342, 0x2494,
+ 0x7343, 0x2727,
+ 0x7344, 0x102a,
+ 0x7345, 0x0e78,
+ 0x7348, 0x43fa,
+ 0x7349, 0x2499,
+ 0x734a, 0x2498,
+ 0x734c, 0x272a,
+ 0x734d, 0x2728,
+ 0x734e, 0x11a4,
+ 0x734f, 0x3f51,
+ 0x7350, 0x102b,
+ 0x7351, 0x2729,
+ 0x7352, 0x2969,
+ 0x7357, 0x11a5,
+ 0x7358, 0x2968,
+ 0x7359, 0x2971,
+ 0x735a, 0x2970,
+ 0x735b, 0x296e,
+ 0x735d, 0x296d,
+ 0x735e, 0x296a,
+ 0x7361, 0x296f,
+ 0x7362, 0x2972,
+ 0x7365, 0x2bc8,
+ 0x7366, 0x2bc5,
+ 0x7368, 0x12f9,
+ 0x7369, 0x2bc4,
+ 0x736a, 0x2bca,
+ 0x736b, 0x2bc9,
+ 0x736c, 0x2bc7,
+ 0x736e, 0x2da3,
+ 0x7370, 0x140e,
+ 0x7371, 0x3f98,
+ 0x7372, 0x140f,
+ 0x7373, 0x2da2,
+ 0x7374, 0x3ed4,
+ 0x7375, 0x14f3,
+ 0x7376, 0x2f55,
+ 0x7377, 0x14f2,
+ 0x7378, 0x1595,
+ 0x737a, 0x1596,
+ 0x737b, 0x1620,
+ 0x737c, 0x31f8,
+ 0x737d, 0x31f7,
+ 0x737e, 0x32e2,
+ 0x737f, 0x3390,
+ 0x7380, 0x16ca,
+ 0x7381, 0x3426,
+ 0x7382, 0x3425,
+ 0x7383, 0x3427,
+ 0x7384, 0x0356,
+ 0x7385, 0x1b7d,
+ 0x7386, 0x092a,
+ 0x7387, 0x0b1f,
+ 0x7388, 0x1f8e,
+ 0x7389, 0x0357,
+ 0x738a, 0x17b1,
+ 0x738b, 0x02ee,
+ 0x738e, 0x180e,
+ 0x738f, 0x46e5,
+ 0x7392, 0x18d1,
+ 0x7393, 0x18cf,
+ 0x7395, 0x18cd,
+ 0x7396, 0x04ef,
+ 0x7397, 0x18ce,
+ 0x7398, 0x39f6,
+ 0x739c, 0x408a,
+ 0x739d, 0x1a0c,
+ 0x739e, 0x395b,
+ 0x739f, 0x0652,
+ 0x73a0, 0x1a0a,
+ 0x73a1, 0x1a06,
+ 0x73a2, 0x1a09,
+ 0x73a4, 0x1a05,
+ 0x73a5, 0x0654,
+ 0x73a6, 0x1a08,
+ 0x73a7, 0x4087,
+ 0x73a8, 0x0651,
+ 0x73a9, 0x0650,
+ 0x73aa, 0x428d,
+ 0x73ab, 0x0653,
+ 0x73ac, 0x1a0b,
+ 0x73ad, 0x1a07,
+ 0x73b2, 0x079b,
+ 0x73b3, 0x079e,
+ 0x73b4, 0x1b85,
+ 0x73b5, 0x1b84,
+ 0x73b6, 0x1b83,
+ 0x73b7, 0x0798,
+ 0x73b8, 0x1b8c,
+ 0x73b9, 0x1b82,
+ 0x73bb, 0x079a,
+ 0x73bc, 0x1d3d,
+ 0x73be, 0x1b89,
+ 0x73bf, 0x1b87,
+ 0x73c0, 0x079d,
+ 0x73c2, 0x1b7f,
+ 0x73c3, 0x1b8a,
+ 0x73c5, 0x1b81,
+ 0x73c6, 0x1b8b,
+ 0x73c7, 0x1b88,
+ 0x73c8, 0x1b80,
+ 0x73c9, 0x4290,
+ 0x73ca, 0x0799,
+ 0x73cb, 0x1b8d,
+ 0x73cc, 0x1b7e,
+ 0x73cd, 0x079c,
+ 0x73ce, 0x411b,
+ 0x73cf, 0x428c,
+ 0x73d0, 0x3b17,
+ 0x73d2, 0x1d42,
+ 0x73d3, 0x1d39,
+ 0x73d4, 0x1d44,
+ 0x73d5, 0x4073,
+ 0x73d6, 0x1d3c,
+ 0x73d7, 0x1d47,
+ 0x73d9, 0x1d3a,
+ 0x73da, 0x1d46,
+ 0x73db, 0x1d43,
+ 0x73dc, 0x1d41,
+ 0x73dd, 0x1d45,
+ 0x73de, 0x0930,
+ 0x73e0, 0x092e,
+ 0x73e1, 0x46f0,
+ 0x73e2, 0x3ca3,
+ 0x73e3, 0x1d3f,
+ 0x73e4, 0x42a5,
+ 0x73e5, 0x1d3b,
+ 0x73e6, 0x3cba,
+ 0x73e7, 0x1d3e,
+ 0x73e8, 0x1d49,
+ 0x73e9, 0x1d40,
+ 0x73ea, 0x092f,
+ 0x73eb, 0x1b86,
+ 0x73ed, 0x092b,
+ 0x73ee, 0x092d,
+ 0x73ef, 0x4011,
+ 0x73f3, 0x3cab,
+ 0x73f4, 0x1f9c,
+ 0x73f5, 0x1f91,
+ 0x73f6, 0x1f8f,
+ 0x73f7, 0x429a,
+ 0x73f8, 0x1f90,
+ 0x73f9, 0x3bf9,
+ 0x73fa, 0x1f97,
+ 0x73fb, 0x3cac,
+ 0x73fc, 0x1f98,
+ 0x73fd, 0x1f94,
+ 0x73fe, 0x0b24,
+ 0x73ff, 0x1f99,
+ 0x7400, 0x1f96,
+ 0x7401, 0x1f93,
+ 0x7403, 0x0b22,
+ 0x7404, 0x1f92,
+ 0x7405, 0x0b20,
+ 0x7406, 0x0b23,
+ 0x7407, 0x1f95,
+ 0x7408, 0x1f9d,
+ 0x7409, 0x092c,
+ 0x740a, 0x0b21,
+ 0x740b, 0x1f9b,
+ 0x740c, 0x1f9a,
+ 0x740d, 0x0b25,
+ 0x7411, 0x456c,
+ 0x7412, 0x3be6,
+ 0x7414, 0x39f4,
+ 0x7415, 0x429b,
+ 0x7416, 0x2215,
+ 0x7417, 0x40ad,
+ 0x7419, 0x46f3,
+ 0x741a, 0x2216,
+ 0x741b, 0x0ce0,
+ 0x741c, 0x38dd,
+ 0x741d, 0x221c,
+ 0x741e, 0x46f4,
+ 0x7420, 0x221e,
+ 0x7421, 0x2217,
+ 0x7422, 0x0cda,
+ 0x7423, 0x221b,
+ 0x7424, 0x221a,
+ 0x7425, 0x0cdb,
+ 0x7426, 0x0ce1,
+ 0x7428, 0x0ce2,
+ 0x7429, 0x221d,
+ 0x742a, 0x0cd8,
+ 0x742b, 0x2214,
+ 0x742c, 0x2212,
+ 0x742d, 0x2218,
+ 0x742e, 0x2211,
+ 0x742f, 0x0cdf,
+ 0x7430, 0x2213,
+ 0x7431, 0x2219,
+ 0x7432, 0x221f,
+ 0x7433, 0x0cd9,
+ 0x7434, 0x0cde,
+ 0x7435, 0x0cdc,
+ 0x7437, 0x3ae1,
+ 0x7438, 0x3b09,
+ 0x7439, 0x429e,
+ 0x743a, 0x0cd7,
+ 0x743c, 0x3adf,
+ 0x743f, 0x0e81,
+ 0x7440, 0x24a0,
+ 0x7441, 0x0e80,
+ 0x7442, 0x24a4,
+ 0x7443, 0x3a1a,
+ 0x7444, 0x249a,
+ 0x7445, 0x3bd7,
+ 0x7446, 0x24a5,
+ 0x7447, 0x42a4,
+ 0x7448, 0x3cb5,
+ 0x7449, 0x4291,
+ 0x744a, 0x249b,
+ 0x744d, 0x24a6,
+ 0x744e, 0x24a3,
+ 0x744f, 0x24a1,
+ 0x7451, 0x249e,
+ 0x7452, 0x249d,
+ 0x7453, 0x4231,
+ 0x7454, 0x24a7,
+ 0x7455, 0x0e7d,
+ 0x7456, 0x39f5,
+ 0x7457, 0x249f,
+ 0x7459, 0x0e82,
+ 0x745a, 0x0e7c,
+ 0x745b, 0x0e83,
+ 0x745d, 0x42c6,
+ 0x745e, 0x0e7f,
+ 0x745f, 0x0e7e,
+ 0x7460, 0x42a2,
+ 0x7462, 0x272b,
+ 0x7463, 0x102d,
+ 0x7464, 0x102c,
+ 0x7465, 0x4101,
+ 0x7467, 0x2730,
+ 0x7468, 0x3aee,
+ 0x7469, 0x11a6,
+ 0x746a, 0x102e,
+ 0x746b, 0x3be7,
+ 0x746c, 0x42a8,
+ 0x746d, 0x1030,
+ 0x746e, 0x2731,
+ 0x746f, 0x0e7b,
+ 0x7470, 0x102f,
+ 0x7471, 0x272d,
+ 0x7472, 0x272f,
+ 0x7473, 0x272c,
+ 0x7474, 0x42a9,
+ 0x7475, 0x272e,
+ 0x7476, 0x42a6,
+ 0x7479, 0x297c,
+ 0x747a, 0x3ad1,
+ 0x747c, 0x297b,
+ 0x747d, 0x2978,
+ 0x747e, 0x11a9,
+ 0x747f, 0x2bcb,
+ 0x7480, 0x11aa,
+ 0x7481, 0x2977,
+ 0x7482, 0x42ac,
+ 0x7483, 0x11a8,
+ 0x7485, 0x2979,
+ 0x7486, 0x2976,
+ 0x7487, 0x2973,
+ 0x7488, 0x297a,
+ 0x7489, 0x2974,
+ 0x748b, 0x11a7,
+ 0x748c, 0x3a21,
+ 0x748d, 0x469d,
+ 0x7490, 0x2da8,
+ 0x7492, 0x2bcf,
+ 0x7494, 0x2bce,
+ 0x7495, 0x2bd0,
+ 0x7497, 0x2da5,
+ 0x7498, 0x12fc,
+ 0x7499, 0x39f3,
+ 0x749a, 0x2bcc,
+ 0x749b, 0x3b0a,
+ 0x749c, 0x12fa,
+ 0x749e, 0x12fe,
+ 0x749f, 0x12fd,
+ 0x74a0, 0x2bcd,
+ 0x74a1, 0x2bd1,
+ 0x74a3, 0x12fb,
+ 0x74a4, 0x4170,
+ 0x74a5, 0x2dac,
+ 0x74a6, 0x1412,
+ 0x74a7, 0x14f4,
+ 0x74a8, 0x1413,
+ 0x74a9, 0x1410,
+ 0x74aa, 0x2da9,
+ 0x74ab, 0x2da7,
+ 0x74ad, 0x2daa,
+ 0x74af, 0x2dad,
+ 0x74b0, 0x1411,
+ 0x74b1, 0x2dab,
+ 0x74b2, 0x2da6,
+ 0x74b4, 0x3ca5,
+ 0x74b5, 0x2f58,
+ 0x74b6, 0x2f5b,
+ 0x74b7, 0x30c2,
+ 0x74b8, 0x2f56,
+ 0x74ba, 0x31f9,
+ 0x74bb, 0x2f5c,
+ 0x74bd, 0x1597,
+ 0x74be, 0x2f5a,
+ 0x74bf, 0x14f5,
+ 0x74c0, 0x2f57,
+ 0x74c1, 0x2f59,
+ 0x74c2, 0x2f5d,
+ 0x74c3, 0x30c3,
+ 0x74c5, 0x30c1,
+ 0x74c8, 0x42b5,
+ 0x74ca, 0x1598,
+ 0x74cb, 0x30c0,
+ 0x74cc, 0x3ade,
+ 0x74cf, 0x1621,
+ 0x74d0, 0x3a9b,
+ 0x74d3, 0x46fa,
+ 0x74d4, 0x167e,
+ 0x74d5, 0x3392,
+ 0x74d6, 0x167d,
+ 0x74d7, 0x3394,
+ 0x74d8, 0x3391,
+ 0x74d9, 0x3393,
+ 0x74da, 0x16fe,
+ 0x74db, 0x348d,
+ 0x74dc, 0x0358,
+ 0x74dd, 0x1a0d,
+ 0x74de, 0x1d4a,
+ 0x74e0, 0x0b26,
+ 0x74e1, 0x24a8,
+ 0x74e2, 0x12ff,
+ 0x74e3, 0x1599,
+ 0x74e4, 0x16cb,
+ 0x74e5, 0x348e,
+ 0x74e6, 0x0359,
+ 0x74e7, 0x3ffe,
+ 0x74e8, 0x1a0e,
+ 0x74e9, 0x0120,
+ 0x74ec, 0x1b8e,
+ 0x74ee, 0x1b8f,
+ 0x74f0, 0x3fe6,
+ 0x74f1, 0x3f9b,
+ 0x74f2, 0x3fdf,
+ 0x74f4, 0x1d4c,
+ 0x74f6, 0x0b27,
+ 0x74f8, 0x3ff4,
+ 0x74fb, 0x2220,
+ 0x74fd, 0x24ab,
+ 0x74fe, 0x24aa,
+ 0x74ff, 0x24a9,
+ 0x7500, 0x2732,
+ 0x7502, 0x2733,
+ 0x7504, 0x1031,
+ 0x7505, 0x3fde,
+ 0x7507, 0x297e,
+ 0x7508, 0x297d,
+ 0x750b, 0x2bd2,
+ 0x750c, 0x1300,
+ 0x750e, 0x42b7,
+ 0x750f, 0x2db1,
+ 0x7510, 0x2dae,
+ 0x7513, 0x2f5f,
+ 0x7514, 0x2f5e,
+ 0x7515, 0x14f6,
+ 0x7516, 0x30c4,
+ 0x7517, 0x32e3,
+ 0x7518, 0x035a,
+ 0x7519, 0x4583,
+ 0x751a, 0x079f,
+ 0x751c, 0x0b29,
+ 0x751d, 0x24ac,
+ 0x751e, 0x42b8,
+ 0x751f, 0x035b,
+ 0x7521, 0x1d4e,
+ 0x7522, 0x0b2a,
+ 0x7525, 0x0ce3,
+ 0x7528, 0x035c,
+ 0x752a, 0x180f,
+ 0x752b, 0x04f1,
+ 0x752c, 0x04f0,
+ 0x752d, 0x07a0,
+ 0x752e, 0x1b90,
+ 0x752f, 0x2221,
+ 0x7530, 0x035e,
+ 0x7534, 0x3e87,
+ 0x7535, 0x455a,
+ 0x7537, 0x04f2,
+ 0x7539, 0x18d3,
+ 0x753a, 0x18d2,
+ 0x753b, 0x3dfb,
+ 0x753d, 0x0655,
+ 0x753e, 0x1a11,
+ 0x753f, 0x1a0f,
+ 0x7542, 0x43cd,
+ 0x7546, 0x3f40,
+ 0x7547, 0x1b91,
+ 0x754a, 0x42bf,
+ 0x754b, 0x07a4,
+ 0x754c, 0x07a2,
+ 0x754d, 0x42be,
+ 0x754e, 0x07a3,
+ 0x754f, 0x07a1,
+ 0x7551, 0x3cfe,
+ 0x7553, 0x3feb,
+ 0x7554, 0x0931,
+ 0x7555, 0x3aea,
+ 0x7559, 0x0935,
+ 0x755a, 0x0934,
+ 0x755b, 0x1d4f,
+ 0x755c, 0x0933,
+ 0x755d, 0x0932,
+ 0x755f, 0x1d50,
+ 0x7560, 0x3d71,
+ 0x7562, 0x0b2d,
+ 0x7563, 0x1f9f,
+ 0x7564, 0x1f9e,
+ 0x7565, 0x0b2b,
+ 0x7567, 0x42c0,
+ 0x756a, 0x0ce6,
+ 0x756b, 0x0ce5,
+ 0x756c, 0x2223,
+ 0x756d, 0x46fd,
+ 0x756e, 0x42c1,
+ 0x756f, 0x2222,
+ 0x7570, 0x0b2e,
+ 0x7572, 0x46fe,
+ 0x7576, 0x0e85,
+ 0x7577, 0x24ae,
+ 0x7578, 0x0e86,
+ 0x7579, 0x24ad,
+ 0x757a, 0x3f4f,
+ 0x757d, 0x2735,
+ 0x757e, 0x297f,
+ 0x757f, 0x11ab,
+ 0x7580, 0x2bd3,
+ 0x7583, 0x3ae5,
+ 0x7584, 0x2db2,
+ 0x7586, 0x159b,
+ 0x7587, 0x159a,
+ 0x758a, 0x16cc,
+ 0x758b, 0x0362,
+ 0x758c, 0x1a12,
+ 0x758d, 0x46ff,
+ 0x758e, 0x42c5,
+ 0x758f, 0x0b2f,
+ 0x7590, 0x2736,
+ 0x7591, 0x1032,
+ 0x7592, 0x022e,
+ 0x7594, 0x18d4,
+ 0x7598, 0x1a13,
+ 0x7599, 0x0657,
+ 0x759d, 0x0656,
+ 0x759e, 0x42c7,
+ 0x75a2, 0x07a8,
+ 0x75a4, 0x07a6,
+ 0x75a7, 0x1b93,
+ 0x75aa, 0x1b94,
+ 0x75ab, 0x07a5,
+ 0x75b0, 0x1d51,
+ 0x75b1, 0x3ead,
+ 0x75b2, 0x0939,
+ 0x75b4, 0x42c8,
+ 0x75b5, 0x0b32,
+ 0x75b6, 0x1d57,
+ 0x75b8, 0x093f,
+ 0x75b9, 0x093d,
+ 0x75ba, 0x1d58,
+ 0x75bb, 0x1d53,
+ 0x75bc, 0x093c,
+ 0x75bd, 0x093b,
+ 0x75be, 0x0936,
+ 0x75bf, 0x1d56,
+ 0x75c0, 0x1d55,
+ 0x75c1, 0x1d52,
+ 0x75c2, 0x093e,
+ 0x75c3, 0x3f93,
+ 0x75c4, 0x1d54,
+ 0x75c5, 0x0937,
+ 0x75c7, 0x0938,
+ 0x75c8, 0x4701,
+ 0x75ca, 0x0b33,
+ 0x75cb, 0x1fa3,
+ 0x75cd, 0x0b34,
+ 0x75ce, 0x1fa0,
+ 0x75cf, 0x1fa2,
+ 0x75d0, 0x1fa6,
+ 0x75d1, 0x1fa5,
+ 0x75d2, 0x1fa1,
+ 0x75d4, 0x0b30,
+ 0x75d7, 0x222b,
+ 0x75d8, 0x0ceb,
+ 0x75d9, 0x0cea,
+ 0x75da, 0x2225,
+ 0x75db, 0x0ce8,
+ 0x75dc, 0x43ce,
+ 0x75dd, 0x2228,
+ 0x75de, 0x0cec,
+ 0x75df, 0x2229,
+ 0x75e0, 0x0ced,
+ 0x75e1, 0x2226,
+ 0x75e2, 0x0ce7,
+ 0x75e3, 0x0ce9,
+ 0x75e4, 0x222a,
+ 0x75e6, 0x2227,
+ 0x75e7, 0x2224,
+ 0x75ed, 0x24bb,
+ 0x75ef, 0x24b0,
+ 0x75f0, 0x0e88,
+ 0x75f1, 0x0e8b,
+ 0x75f2, 0x0e8a,
+ 0x75f3, 0x0e8f,
+ 0x75f4, 0x0e8e,
+ 0x75f5, 0x24bc,
+ 0x75f6, 0x24ba,
+ 0x75f7, 0x24b3,
+ 0x75f8, 0x24b7,
+ 0x75f9, 0x24b6,
+ 0x75fa, 0x0e8c,
+ 0x75fb, 0x24b9,
+ 0x75fc, 0x24b5,
+ 0x75fd, 0x24bd,
+ 0x75fe, 0x24b4,
+ 0x75ff, 0x0e8d,
+ 0x7600, 0x0e87,
+ 0x7601, 0x0e89,
+ 0x7602, 0x42c9,
+ 0x7603, 0x24b2,
+ 0x7607, 0x3f8f,
+ 0x7608, 0x2738,
+ 0x7609, 0x1036,
+ 0x760a, 0x273c,
+ 0x760b, 0x1035,
+ 0x760c, 0x2739,
+ 0x760d, 0x1034,
+ 0x760f, 0x24b1,
+ 0x7610, 0x24b8,
+ 0x7611, 0x273b,
+ 0x7613, 0x1037,
+ 0x7614, 0x273d,
+ 0x7615, 0x273a,
+ 0x7616, 0x2737,
+ 0x7619, 0x2982,
+ 0x761a, 0x2986,
+ 0x761b, 0x2988,
+ 0x761c, 0x2984,
+ 0x761d, 0x2983,
+ 0x761e, 0x2981,
+ 0x761f, 0x11ae,
+ 0x7620, 0x11ac,
+ 0x7621, 0x11b1,
+ 0x7623, 0x2985,
+ 0x7624, 0x11af,
+ 0x7625, 0x2980,
+ 0x7626, 0x11b0,
+ 0x7627, 0x1033,
+ 0x7628, 0x2987,
+ 0x7629, 0x11ad,
+ 0x762c, 0x42ca,
+ 0x762d, 0x2bd5,
+ 0x762f, 0x2bd4,
+ 0x7630, 0x2bdc,
+ 0x7631, 0x2bd6,
+ 0x7632, 0x2bdb,
+ 0x7633, 0x2bd8,
+ 0x7634, 0x1302,
+ 0x7635, 0x2bda,
+ 0x7638, 0x1303,
+ 0x763a, 0x1304,
+ 0x763b, 0x3e70,
+ 0x763c, 0x2bd9,
+ 0x763d, 0x2bd7,
+ 0x7640, 0x3ee6,
+ 0x7642, 0x1415,
+ 0x7643, 0x2db3,
+ 0x7646, 0x1414,
+ 0x7647, 0x2db6,
+ 0x7648, 0x2db4,
+ 0x764c, 0x1416,
+ 0x764d, 0x4702,
+ 0x764e, 0x3e72,
+ 0x764f, 0x42cc,
+ 0x7650, 0x2f63,
+ 0x7651, 0x42cb,
+ 0x7652, 0x14f9,
+ 0x7653, 0x2f64,
+ 0x7654, 0x3ef0,
+ 0x7656, 0x14f7,
+ 0x7657, 0x2f65,
+ 0x7658, 0x14f8,
+ 0x7659, 0x2f62,
+ 0x765a, 0x2f66,
+ 0x765c, 0x2f60,
+ 0x765f, 0x159c,
+ 0x7660, 0x30c5,
+ 0x7661, 0x159d,
+ 0x7662, 0x1622,
+ 0x7664, 0x2f61,
+ 0x7665, 0x1623,
+ 0x7666, 0x3eaa,
+ 0x7667, 0x3fa9,
+ 0x7669, 0x167f,
+ 0x766a, 0x32e4,
+ 0x766c, 0x16ce,
+ 0x766d, 0x3395,
+ 0x766e, 0x16cd,
+ 0x766f, 0x42cd,
+ 0x7670, 0x3428,
+ 0x7671, 0x1723,
+ 0x7673, 0x3aeb,
+ 0x7674, 0x4703,
+ 0x7675, 0x3543,
+ 0x7676, 0x022f,
+ 0x7678, 0x07aa,
+ 0x7679, 0x1b95,
+ 0x767a, 0x4705,
+ 0x767b, 0x0cee,
+ 0x767d, 0x0363,
+ 0x767e, 0x03f5,
+ 0x767f, 0x1810,
+ 0x7680, 0x43d3,
+ 0x7681, 0x18d6,
+ 0x7682, 0x04f4,
+ 0x7684, 0x0659,
+ 0x7686, 0x07ab,
+ 0x7689, 0x1fa8,
+ 0x768a, 0x1d59,
+ 0x768b, 0x0940,
+ 0x768c, 0x43d4,
+ 0x768e, 0x0b35,
+ 0x768f, 0x1fa7,
+ 0x7690, 0x42d0,
+ 0x7692, 0x222d,
+ 0x7693, 0x0cf1,
+ 0x7695, 0x222c,
+ 0x7696, 0x0cf0,
+ 0x7699, 0x24be,
+ 0x769a, 0x11b3,
+ 0x769b, 0x298c,
+ 0x769c, 0x2989,
+ 0x76a1, 0x42d5,
+ 0x76a4, 0x2db7,
+ 0x76a5, 0x42d6,
+ 0x76a6, 0x2f67,
+ 0x76aa, 0x31fb,
+ 0x76ab, 0x31fa,
+ 0x76ad, 0x3396,
+ 0x76ae, 0x0364,
+ 0x76af, 0x1a14,
+ 0x76b0, 0x0941,
+ 0x76b4, 0x0cf2,
+ 0x76b5, 0x24bf,
+ 0x76b7, 0x42d7,
+ 0x76b8, 0x273e,
+ 0x76ba, 0x11b4,
+ 0x76bb, 0x2bdd,
+ 0x76bd, 0x2f68,
+ 0x76be, 0x31fc,
+ 0x76bf, 0x0365,
+ 0x76c2, 0x065a,
+ 0x76c3, 0x07b0,
+ 0x76c4, 0x1b96,
+ 0x76c5, 0x07b1,
+ 0x76c6, 0x07af,
+ 0x76c8, 0x07ae,
+ 0x76c9, 0x1d5a,
+ 0x76ca, 0x0942,
+ 0x76cc, 0x42d8,
+ 0x76cd, 0x0943,
+ 0x76d2, 0x0b37,
+ 0x76d3, 0x1fa9,
+ 0x76d4, 0x0b36,
+ 0x76d6, 0x3f55,
+ 0x76da, 0x222e,
+ 0x76db, 0x0b38,
+ 0x76dc, 0x0cf3,
+ 0x76dd, 0x24c0,
+ 0x76de, 0x0e90,
+ 0x76e1, 0x1038,
+ 0x76e3, 0x1039,
+ 0x76e4, 0x11b5,
+ 0x76e5, 0x1306,
+ 0x76e6, 0x2bde,
+ 0x76e7, 0x1305,
+ 0x76e9, 0x2db8,
+ 0x76ea, 0x1417,
+ 0x76ec, 0x2f69,
+ 0x76ed, 0x31fd,
+ 0x76ee, 0x0366,
+ 0x76ef, 0x04f5,
+ 0x76f0, 0x1a17,
+ 0x76f1, 0x1a16,
+ 0x76f2, 0x065b,
+ 0x76f3, 0x1a15,
+ 0x76f4, 0x065c,
+ 0x76f5, 0x1a18,
+ 0x76f7, 0x1b9c,
+ 0x76f8, 0x07b4,
+ 0x76f9, 0x07b3,
+ 0x76fa, 0x1b9e,
+ 0x76fb, 0x1b9d,
+ 0x76fc, 0x07b8,
+ 0x76fe, 0x07b7,
+ 0x7701, 0x07b2,
+ 0x7703, 0x1b98,
+ 0x7707, 0x07b9,
+ 0x7708, 0x1b97,
+ 0x7709, 0x07b5,
+ 0x770a, 0x1b9b,
+ 0x770b, 0x07b6,
+ 0x770c, 0x3d62,
+ 0x770e, 0x3b02,
+ 0x7710, 0x1d5d,
+ 0x7711, 0x1d61,
+ 0x7712, 0x1d5f,
+ 0x7713, 0x1d5e,
+ 0x7715, 0x1d62,
+ 0x7719, 0x1d63,
+ 0x771b, 0x1d5c,
+ 0x771d, 0x1d5b,
+ 0x771e, 0x42de,
+ 0x771f, 0x0946,
+ 0x7722, 0x1d65,
+ 0x7723, 0x1d60,
+ 0x7724, 0x3fe8,
+ 0x7725, 0x1fb2,
+ 0x7726, 0x42df,
+ 0x7727, 0x1d66,
+ 0x7728, 0x0948,
+ 0x7729, 0x0945,
+ 0x772b, 0x3ff3,
+ 0x772d, 0x1fac,
+ 0x772f, 0x1fab,
+ 0x7731, 0x1fad,
+ 0x7733, 0x1fb0,
+ 0x7734, 0x1faf,
+ 0x7735, 0x1fb4,
+ 0x7736, 0x0b3c,
+ 0x7737, 0x0b39,
+ 0x7738, 0x0b3d,
+ 0x7739, 0x1faa,
+ 0x773a, 0x0b3e,
+ 0x773b, 0x1fb3,
+ 0x773c, 0x0b3b,
+ 0x773d, 0x1fb1,
+ 0x773e, 0x0b3a,
+ 0x7740, 0x42e0,
+ 0x7743, 0x470a,
+ 0x7744, 0x2231,
+ 0x7745, 0x2233,
+ 0x7746, 0x222f,
+ 0x774a, 0x2234,
+ 0x774b, 0x2236,
+ 0x774d, 0x2232,
+ 0x774e, 0x2235,
+ 0x774f, 0x0cf4,
+ 0x7752, 0x24c4,
+ 0x7754, 0x24c9,
+ 0x7755, 0x24c1,
+ 0x7756, 0x24c5,
+ 0x7758, 0x42e3,
+ 0x7759, 0x24ca,
+ 0x775a, 0x24c6,
+ 0x775b, 0x0e92,
+ 0x775c, 0x0e9a,
+ 0x775e, 0x0e95,
+ 0x775f, 0x24c2,
+ 0x7761, 0x103d,
+ 0x7762, 0x0e9d,
+ 0x7763, 0x0e96,
+ 0x7765, 0x0e9b,
+ 0x7766, 0x0e94,
+ 0x7767, 0x24c8,
+ 0x7768, 0x0e9c,
+ 0x7769, 0x24c7,
+ 0x776a, 0x0e98,
+ 0x776b, 0x0e93,
+ 0x776c, 0x0e99,
+ 0x776d, 0x24cb,
+ 0x776e, 0x2743,
+ 0x776f, 0x2745,
+ 0x7772, 0x396b,
+ 0x7777, 0x46a9,
+ 0x7778, 0x3b00,
+ 0x7779, 0x0e97,
+ 0x777a, 0x4317,
+ 0x777b, 0x3b04,
+ 0x777c, 0x2740,
+ 0x777d, 0x103b,
+ 0x777e, 0x2746,
+ 0x777f, 0x103c,
+ 0x7780, 0x2744,
+ 0x7781, 0x273f,
+ 0x7782, 0x2742,
+ 0x7783, 0x2747,
+ 0x7784, 0x103a,
+ 0x7785, 0x2741,
+ 0x7787, 0x11b7,
+ 0x7788, 0x2990,
+ 0x7789, 0x298f,
+ 0x778b, 0x11ba,
+ 0x778c, 0x11b8,
+ 0x778d, 0x298d,
+ 0x778e, 0x11b6,
+ 0x778f, 0x298e,
+ 0x7791, 0x11b9,
+ 0x7793, 0x382d,
+ 0x7795, 0x2be6,
+ 0x7797, 0x2be8,
+ 0x7798, 0x470e,
+ 0x7799, 0x2be7,
+ 0x779a, 0x2bdf,
+ 0x779b, 0x2be3,
+ 0x779c, 0x2be2,
+ 0x779d, 0x2be0,
+ 0x779e, 0x1308,
+ 0x77a0, 0x1307,
+ 0x77a1, 0x2be1,
+ 0x77a2, 0x2be4,
+ 0x77a5, 0x130a,
+ 0x77a7, 0x141c,
+ 0x77a8, 0x2dc0,
+ 0x77aa, 0x1419,
+ 0x77ab, 0x2dba,
+ 0x77ac, 0x141b,
+ 0x77ad, 0x141d,
+ 0x77af, 0x42e5,
+ 0x77b0, 0x141a,
+ 0x77b1, 0x2dbf,
+ 0x77b2, 0x2dbb,
+ 0x77b3, 0x1418,
+ 0x77b4, 0x2dbe,
+ 0x77b5, 0x2db9,
+ 0x77b6, 0x2dbd,
+ 0x77b7, 0x2dbc,
+ 0x77b9, 0x3e73,
+ 0x77ba, 0x2f6b,
+ 0x77bb, 0x14fc,
+ 0x77bd, 0x14fa,
+ 0x77be, 0x4711,
+ 0x77bf, 0x14fb,
+ 0x77c2, 0x2f6a,
+ 0x77c3, 0x3bb1,
+ 0x77c4, 0x30c8,
+ 0x77c5, 0x41c1,
+ 0x77c7, 0x159e,
+ 0x77c9, 0x30c6,
+ 0x77cb, 0x4712,
+ 0x77cc, 0x31fe,
+ 0x77cd, 0x3201,
+ 0x77ce, 0x31ff,
+ 0x77d0, 0x32e5,
+ 0x77d3, 0x1680,
+ 0x77d4, 0x3429,
+ 0x77d5, 0x348f,
+ 0x77d7, 0x1725,
+ 0x77d8, 0x34d3,
+ 0x77da, 0x1753,
+ 0x77db, 0x0367,
+ 0x77dc, 0x07ba,
+ 0x77de, 0x2238,
+ 0x77e0, 0x24cc,
+ 0x77e2, 0x0368,
+ 0x77e3, 0x04f6,
+ 0x77e5, 0x065d,
+ 0x77e6, 0x4081,
+ 0x77e7, 0x1b9f,
+ 0x77e9, 0x0949,
+ 0x77ec, 0x2239,
+ 0x77ed, 0x0cf5,
+ 0x77ee, 0x0e9e,
+ 0x77ef, 0x141e,
+ 0x77f0, 0x2dc1,
+ 0x77f1, 0x30c9,
+ 0x77f2, 0x3202,
+ 0x77f3, 0x0369,
+ 0x77f4, 0x42e9,
+ 0x77f7, 0x1a1e,
+ 0x77f8, 0x1a19,
+ 0x77f9, 0x1a1b,
+ 0x77fa, 0x1a1d,
+ 0x77fb, 0x1a1c,
+ 0x77fc, 0x1a1a,
+ 0x77fd, 0x065e,
+ 0x77fe, 0x3fd5,
+ 0x7802, 0x07bb,
+ 0x7803, 0x1ba9,
+ 0x7805, 0x1ba4,
+ 0x7806, 0x1ba1,
+ 0x7808, 0x3e46,
+ 0x7809, 0x1ba8,
+ 0x780c, 0x07bd,
+ 0x780e, 0x1ba7,
+ 0x780f, 0x1ba6,
+ 0x7810, 0x1ba5,
+ 0x7811, 0x1ba2,
+ 0x7813, 0x1baa,
+ 0x7814, 0x07bc,
+ 0x7818, 0x4713,
+ 0x781c, 0x4714,
+ 0x781d, 0x094d,
+ 0x781e, 0x3b13,
+ 0x781f, 0x0953,
+ 0x7820, 0x0952,
+ 0x7821, 0x1d6f,
+ 0x7822, 0x1d69,
+ 0x7823, 0x1d67,
+ 0x7825, 0x0950,
+ 0x7826, 0x1fbb,
+ 0x7827, 0x094b,
+ 0x7828, 0x1d6c,
+ 0x7829, 0x1d70,
+ 0x782a, 0x1d72,
+ 0x782b, 0x1d6e,
+ 0x782c, 0x1d68,
+ 0x782d, 0x0951,
+ 0x782e, 0x1d6d,
+ 0x782f, 0x1d6b,
+ 0x7830, 0x094a,
+ 0x7831, 0x1d73,
+ 0x7832, 0x0954,
+ 0x7833, 0x1d71,
+ 0x7834, 0x094e,
+ 0x7835, 0x1d6a,
+ 0x7837, 0x094f,
+ 0x7838, 0x094c,
+ 0x7839, 0x43d6,
+ 0x783c, 0x401a,
+ 0x783d, 0x3c6a,
+ 0x7842, 0x3ac4,
+ 0x7843, 0x0b40,
+ 0x7844, 0x3c2b,
+ 0x7845, 0x1fbc,
+ 0x7847, 0x4715,
+ 0x7848, 0x1fb5,
+ 0x7849, 0x1fb7,
+ 0x784a, 0x1fb9,
+ 0x784b, 0x3c6d,
+ 0x784c, 0x1fba,
+ 0x784d, 0x1fb8,
+ 0x784e, 0x0b41,
+ 0x7850, 0x1fbd,
+ 0x7851, 0x4716,
+ 0x7852, 0x1fb6,
+ 0x7853, 0x3f95,
+ 0x7854, 0x3c6b,
+ 0x785c, 0x223d,
+ 0x785d, 0x0cf6,
+ 0x785e, 0x2245,
+ 0x7860, 0x223a,
+ 0x7862, 0x2246,
+ 0x7864, 0x223b,
+ 0x7866, 0x4717,
+ 0x7868, 0x2244,
+ 0x7869, 0x2243,
+ 0x786a, 0x2240,
+ 0x786b, 0x0b3f,
+ 0x786c, 0x0cf7,
+ 0x786d, 0x223e,
+ 0x786e, 0x2241,
+ 0x786f, 0x0cf8,
+ 0x7870, 0x2242,
+ 0x7871, 0x223f,
+ 0x7879, 0x24d7,
+ 0x787a, 0x3ee9,
+ 0x787b, 0x24db,
+ 0x787c, 0x0ea5,
+ 0x787e, 0x274d,
+ 0x787f, 0x0ea8,
+ 0x7880, 0x24d9,
+ 0x7881, 0x36e8,
+ 0x7883, 0x24d6,
+ 0x7884, 0x24d1,
+ 0x7885, 0x24d3,
+ 0x7887, 0x24cd,
+ 0x7888, 0x3b15,
+ 0x7889, 0x0ea4,
+ 0x788c, 0x0ea3,
+ 0x788d, 0x3b14,
+ 0x788e, 0x0e9f,
+ 0x788f, 0x24d0,
+ 0x7891, 0x0ea6,
+ 0x7893, 0x0ea7,
+ 0x7894, 0x24cf,
+ 0x7895, 0x24d2,
+ 0x7896, 0x24da,
+ 0x7897, 0x0ea1,
+ 0x7899, 0x24d8,
+ 0x789a, 0x24ce,
+ 0x789e, 0x274f,
+ 0x789f, 0x103f,
+ 0x78a0, 0x2751,
+ 0x78a1, 0x24d5,
+ 0x78a2, 0x2753,
+ 0x78a3, 0x1043,
+ 0x78a4, 0x2754,
+ 0x78a5, 0x2750,
+ 0x78a7, 0x1040,
+ 0x78a8, 0x274c,
+ 0x78a9, 0x1042,
+ 0x78aa, 0x2749,
+ 0x78ab, 0x274e,
+ 0x78ac, 0x2752,
+ 0x78ad, 0x274b,
+ 0x78af, 0x42ec,
+ 0x78b0, 0x0ea0,
+ 0x78b1, 0x42f4,
+ 0x78b2, 0x2748,
+ 0x78b3, 0x1041,
+ 0x78b4, 0x274a,
+ 0x78b6, 0x3c6c,
+ 0x78b8, 0x4571,
+ 0x78b9, 0x3c63,
+ 0x78ba, 0x11bd,
+ 0x78bb, 0x2992,
+ 0x78bc, 0x11c1,
+ 0x78be, 0x11bf,
+ 0x78c1, 0x103e,
+ 0x78c3, 0x2999,
+ 0x78c5, 0x11bc,
+ 0x78c7, 0x42ed,
+ 0x78c8, 0x2998,
+ 0x78c9, 0x299b,
+ 0x78ca, 0x11be,
+ 0x78cb, 0x11bb,
+ 0x78cc, 0x2994,
+ 0x78cd, 0x2991,
+ 0x78ce, 0x2996,
+ 0x78cf, 0x2993,
+ 0x78d0, 0x11c2,
+ 0x78d1, 0x2995,
+ 0x78d2, 0x3b16,
+ 0x78d3, 0x42ee,
+ 0x78d4, 0x2997,
+ 0x78d5, 0x11c0,
+ 0x78d7, 0x42f2,
+ 0x78d8, 0x3f8c,
+ 0x78da, 0x130c,
+ 0x78db, 0x2bef,
+ 0x78dd, 0x2be9,
+ 0x78de, 0x2bed,
+ 0x78df, 0x2bf3,
+ 0x78e1, 0x2bf0,
+ 0x78e3, 0x2bee,
+ 0x78e5, 0x2beb,
+ 0x78e7, 0x130e,
+ 0x78e8, 0x130b,
+ 0x78e9, 0x2bea,
+ 0x78ea, 0x2bec,
+ 0x78ec, 0x130d,
+ 0x78ed, 0x2bf2,
+ 0x78ee, 0x3a81,
+ 0x78ef, 0x1422,
+ 0x78f0, 0x3b3a,
+ 0x78f1, 0x40be,
+ 0x78f2, 0x2dc8,
+ 0x78f3, 0x2dc2,
+ 0x78f4, 0x1421,
+ 0x78f5, 0x38b3,
+ 0x78f7, 0x141f,
+ 0x78f9, 0x2dca,
+ 0x78fa, 0x1420,
+ 0x78fb, 0x2dc5,
+ 0x78fd, 0x2dc3,
+ 0x78fe, 0x2dcb,
+ 0x78ff, 0x2dc7,
+ 0x7901, 0x1423,
+ 0x7902, 0x2dc4,
+ 0x7904, 0x2dcc,
+ 0x7905, 0x2dc9,
+ 0x7906, 0x3fcf,
+ 0x7909, 0x2f6f,
+ 0x790c, 0x2f6c,
+ 0x790e, 0x14fe,
+ 0x7910, 0x2f70,
+ 0x7911, 0x2f72,
+ 0x7912, 0x2f71,
+ 0x7913, 0x2f6d,
+ 0x7917, 0x30ce,
+ 0x7919, 0x159f,
+ 0x791b, 0x30cb,
+ 0x791c, 0x30cd,
+ 0x791d, 0x30ca,
+ 0x791e, 0x30cf,
+ 0x7921, 0x30cc,
+ 0x7923, 0x3204,
+ 0x7924, 0x3207,
+ 0x7925, 0x3203,
+ 0x7926, 0x1624,
+ 0x7927, 0x3205,
+ 0x7929, 0x3208,
+ 0x792a, 0x1625,
+ 0x792b, 0x1627,
+ 0x792c, 0x1626,
+ 0x792d, 0x32e6,
+ 0x792e, 0x42f0,
+ 0x792f, 0x32e8,
+ 0x7931, 0x32e7,
+ 0x7932, 0x471b,
+ 0x7933, 0x471a,
+ 0x7934, 0x42f3,
+ 0x7935, 0x3397,
+ 0x7936, 0x3783,
+ 0x7938, 0x3490,
+ 0x7939, 0x34d5,
+ 0x793a, 0x036a,
+ 0x793b, 0x44f7,
+ 0x793c, 0x4300,
+ 0x793d, 0x18d7,
+ 0x793e, 0x065f,
+ 0x793f, 0x1a20,
+ 0x7940, 0x0660,
+ 0x7942, 0x1a1f,
+ 0x7944, 0x1baf,
+ 0x7945, 0x1bae,
+ 0x7946, 0x07bf,
+ 0x7947, 0x07c2,
+ 0x7948, 0x07c1,
+ 0x7949, 0x07c0,
+ 0x794a, 0x1bab,
+ 0x794b, 0x1bad,
+ 0x794c, 0x1bac,
+ 0x794f, 0x1d76,
+ 0x7950, 0x0956,
+ 0x7951, 0x1d7a,
+ 0x7952, 0x1d79,
+ 0x7953, 0x1d78,
+ 0x7954, 0x1d74,
+ 0x7955, 0x0955,
+ 0x7956, 0x0959,
+ 0x7957, 0x095c,
+ 0x7958, 0x37e5,
+ 0x7959, 0x3b18,
+ 0x795a, 0x095d,
+ 0x795b, 0x1d75,
+ 0x795c, 0x1d77,
+ 0x795d, 0x095b,
+ 0x795e, 0x095a,
+ 0x795f, 0x0958,
+ 0x7960, 0x0957,
+ 0x7961, 0x1fc4,
+ 0x7962, 0x3e7d,
+ 0x7963, 0x1fc2,
+ 0x7964, 0x1fbe,
+ 0x7965, 0x0b42,
+ 0x7967, 0x1fbf,
+ 0x7968, 0x0b43,
+ 0x7969, 0x1fc0,
+ 0x796b, 0x1fc3,
+ 0x796d, 0x0b44,
+ 0x7970, 0x224a,
+ 0x7971, 0x4168,
+ 0x7972, 0x2249,
+ 0x7973, 0x2248,
+ 0x7974, 0x2247,
+ 0x7979, 0x24df,
+ 0x797a, 0x0ea9,
+ 0x797c, 0x24dc,
+ 0x797d, 0x24de,
+ 0x797e, 0x3e26,
+ 0x797f, 0x0eaa,
+ 0x7980, 0x42fc,
+ 0x7981, 0x0eab,
+ 0x7982, 0x24dd,
+ 0x7983, 0x3df6,
+ 0x7986, 0x42f9,
+ 0x7987, 0x4588,
+ 0x7988, 0x275d,
+ 0x798a, 0x2756,
+ 0x798d, 0x1046,
+ 0x798e, 0x1044,
+ 0x7990, 0x275f,
+ 0x7991, 0x471d,
+ 0x7992, 0x275e,
+ 0x7993, 0x275b,
+ 0x7994, 0x275a,
+ 0x7995, 0x2759,
+ 0x7996, 0x2758,
+ 0x7997, 0x275c,
+ 0x7998, 0x2755,
+ 0x7999, 0x43fc,
+ 0x799a, 0x299c,
+ 0x799b, 0x29a1,
+ 0x799c, 0x299f,
+ 0x799d, 0x42fe,
+ 0x799f, 0x395e,
+ 0x79a0, 0x299e,
+ 0x79a1, 0x299d,
+ 0x79a2, 0x29a0,
+ 0x79a4, 0x2bf5,
+ 0x79a5, 0x3b1e,
+ 0x79a6, 0x130f,
+ 0x79a7, 0x1424,
+ 0x79a8, 0x2dce,
+ 0x79a9, 0x4301,
+ 0x79aa, 0x1425,
+ 0x79ab, 0x2dcd,
+ 0x79ac, 0x2f74,
+ 0x79ad, 0x2f73,
+ 0x79ae, 0x14ff,
+ 0x79b0, 0x30d0,
+ 0x79b1, 0x15a0,
+ 0x79b2, 0x3209,
+ 0x79b3, 0x16cf,
+ 0x79b4, 0x3398,
+ 0x79b6, 0x3492,
+ 0x79b7, 0x3491,
+ 0x79b8, 0x17b2,
+ 0x79b9, 0x07c3,
+ 0x79bb, 0x1fc5,
+ 0x79bd, 0x0ead,
+ 0x79be, 0x036b,
+ 0x79bf, 0x04f9,
+ 0x79c0, 0x04f8,
+ 0x79c1, 0x04f7,
+ 0x79c4, 0x3ccd,
+ 0x79c5, 0x1a21,
+ 0x79c6, 0x4305,
+ 0x79c8, 0x0663,
+ 0x79c9, 0x0662,
+ 0x79cb, 0x07c7,
+ 0x79cc, 0x4233,
+ 0x79cd, 0x1bb1,
+ 0x79ce, 0x1bb4,
+ 0x79cf, 0x1bb2,
+ 0x79d1, 0x07c5,
+ 0x79d4, 0x4307,
+ 0x79d5, 0x1bb0,
+ 0x79d6, 0x1bb3,
+ 0x79d8, 0x0964,
+ 0x79dc, 0x1d81,
+ 0x79dd, 0x1d83,
+ 0x79de, 0x1d82,
+ 0x79df, 0x0961,
+ 0x79e0, 0x1d7d,
+ 0x79e2, 0x3c5a,
+ 0x79e3, 0x095f,
+ 0x79e4, 0x095e,
+ 0x79e6, 0x0962,
+ 0x79e7, 0x0960,
+ 0x79e9, 0x0963,
+ 0x79ea, 0x1d80,
+ 0x79eb, 0x1d7b,
+ 0x79ed, 0x1d7f,
+ 0x79ee, 0x1d7e,
+ 0x79f1, 0x3b27,
+ 0x79f4, 0x3b22,
+ 0x79f6, 0x1fc8,
+ 0x79f8, 0x1fc7,
+ 0x79fa, 0x1fc6,
+ 0x79fb, 0x0b45,
+ 0x7a00, 0x0cfd,
+ 0x7a02, 0x224b,
+ 0x7a03, 0x224d,
+ 0x7a04, 0x224f,
+ 0x7a05, 0x0cfc,
+ 0x7a06, 0x471e,
+ 0x7a08, 0x0cfa,
+ 0x7a0a, 0x224c,
+ 0x7a0b, 0x0cfb,
+ 0x7a0c, 0x224e,
+ 0x7a0d, 0x0cf9,
+ 0x7a10, 0x24e9,
+ 0x7a11, 0x24e0,
+ 0x7a12, 0x24e3,
+ 0x7a13, 0x24e7,
+ 0x7a14, 0x0eb1,
+ 0x7a15, 0x24e5,
+ 0x7a17, 0x24e4,
+ 0x7a18, 0x24e1,
+ 0x7a1a, 0x0eaf,
+ 0x7a1b, 0x24e8,
+ 0x7a1c, 0x0eae,
+ 0x7a1e, 0x0eb3,
+ 0x7a1f, 0x0eb2,
+ 0x7a20, 0x0eb0,
+ 0x7a22, 0x24e6,
+ 0x7a26, 0x2765,
+ 0x7a28, 0x2764,
+ 0x7a2b, 0x2760,
+ 0x7a2d, 0x3fda,
+ 0x7a2e, 0x1047,
+ 0x7a2f, 0x2763,
+ 0x7a30, 0x2762,
+ 0x7a31, 0x1048,
+ 0x7a37, 0x11c7,
+ 0x7a39, 0x29a3,
+ 0x7a3a, 0x3b21,
+ 0x7a3b, 0x11c8,
+ 0x7a3c, 0x11c4,
+ 0x7a3d, 0x11c6,
+ 0x7a3e, 0x3f8b,
+ 0x7a3f, 0x11c3,
+ 0x7a40, 0x11c5,
+ 0x7a43, 0x396c,
+ 0x7a44, 0x2bf6,
+ 0x7a45, 0x3df1,
+ 0x7a46, 0x1312,
+ 0x7a47, 0x2bf8,
+ 0x7a48, 0x2bf7,
+ 0x7a49, 0x3733,
+ 0x7a4a, 0x2761,
+ 0x7a4b, 0x1314,
+ 0x7a4c, 0x1313,
+ 0x7a4d, 0x1310,
+ 0x7a54, 0x2dd3,
+ 0x7a56, 0x2dd1,
+ 0x7a57, 0x1426,
+ 0x7a58, 0x2dd2,
+ 0x7a5a, 0x2dd4,
+ 0x7a5b, 0x2dd0,
+ 0x7a5c, 0x2dcf,
+ 0x7a5f, 0x2f75,
+ 0x7a60, 0x1502,
+ 0x7a61, 0x1500,
+ 0x7a65, 0x3736,
+ 0x7a67, 0x30d1,
+ 0x7a69, 0x15a2,
+ 0x7a6b, 0x15a1,
+ 0x7a6c, 0x320b,
+ 0x7a6e, 0x320a,
+ 0x7a70, 0x3399,
+ 0x7a74, 0x036c,
+ 0x7a75, 0x1811,
+ 0x7a76, 0x04fa,
+ 0x7a78, 0x1a22,
+ 0x7a79, 0x0665,
+ 0x7a7a, 0x0664,
+ 0x7a7b, 0x1a23,
+ 0x7a7d, 0x3737,
+ 0x7a7e, 0x1bb6,
+ 0x7a7f, 0x07c8,
+ 0x7a80, 0x1bb5,
+ 0x7a81, 0x07c9,
+ 0x7a83, 0x3d7d,
+ 0x7a84, 0x0965,
+ 0x7a85, 0x1d86,
+ 0x7a86, 0x1d84,
+ 0x7a87, 0x1d8a,
+ 0x7a88, 0x0966,
+ 0x7a89, 0x1d85,
+ 0x7a8a, 0x1d89,
+ 0x7a8b, 0x1d87,
+ 0x7a8f, 0x1fca,
+ 0x7a90, 0x1fcc,
+ 0x7a91, 0x43d8,
+ 0x7a92, 0x0b46,
+ 0x7a94, 0x1fcb,
+ 0x7a95, 0x0b47,
+ 0x7a96, 0x0d00,
+ 0x7a97, 0x0cff,
+ 0x7a98, 0x0cfe,
+ 0x7a99, 0x2250,
+ 0x7a9e, 0x24ec,
+ 0x7a9f, 0x0eb4,
+ 0x7aa2, 0x24eb,
+ 0x7aa3, 0x24ea,
+ 0x7aa8, 0x2766,
+ 0x7aa9, 0x104a,
+ 0x7aaa, 0x1049,
+ 0x7aab, 0x2767,
+ 0x7aae, 0x11ca,
+ 0x7aaf, 0x11c9,
+ 0x7ab0, 0x373a,
+ 0x7ab1, 0x2bfc,
+ 0x7ab2, 0x29a4,
+ 0x7ab3, 0x29a6,
+ 0x7ab4, 0x29a5,
+ 0x7ab5, 0x2bfb,
+ 0x7ab6, 0x2bf9,
+ 0x7ab7, 0x2bfd,
+ 0x7ab8, 0x2bfa,
+ 0x7aba, 0x1315,
+ 0x7abb, 0x3739,
+ 0x7abc, 0x4721,
+ 0x7abe, 0x2dd5,
+ 0x7abf, 0x1427,
+ 0x7ac0, 0x2dd6,
+ 0x7ac2, 0x373b,
+ 0x7ac4, 0x1503,
+ 0x7ac7, 0x1628,
+ 0x7ac8, 0x3d7f,
+ 0x7ac9, 0x4570,
+ 0x7aca, 0x16ff,
+ 0x7acb, 0x036d,
+ 0x7acf, 0x4724,
+ 0x7ad1, 0x1bb7,
+ 0x7ad3, 0x3f8a,
+ 0x7ad8, 0x1d8b,
+ 0x7ad9, 0x0967,
+ 0x7ada, 0x3740,
+ 0x7adb, 0x4725,
+ 0x7adc, 0x3951,
+ 0x7add, 0x3741,
+ 0x7adf, 0x0bde,
+ 0x7ae0, 0x0bdd,
+ 0x7ae2, 0x3b33,
+ 0x7ae3, 0x0d02,
+ 0x7ae4, 0x2252,
+ 0x7ae5, 0x0d01,
+ 0x7ae6, 0x2251,
+ 0x7ae7, 0x385d,
+ 0x7ae9, 0x3831,
+ 0x7aea, 0x3742,
+ 0x7aeb, 0x24ed,
+ 0x7aed, 0x104b,
+ 0x7aee, 0x2769,
+ 0x7aef, 0x104c,
+ 0x7af6, 0x1629,
+ 0x7af7, 0x320d,
+ 0x7af9, 0x03f6,
+ 0x7afa, 0x0666,
+ 0x7afb, 0x1a24,
+ 0x7afd, 0x07cb,
+ 0x7afe, 0x3b3d,
+ 0x7aff, 0x07ca,
+ 0x7b00, 0x1bb8,
+ 0x7b04, 0x1d8d,
+ 0x7b05, 0x1d8f,
+ 0x7b06, 0x0968,
+ 0x7b08, 0x1d91,
+ 0x7b09, 0x1d94,
+ 0x7b0a, 0x1d92,
+ 0x7b0b, 0x3746,
+ 0x7b0c, 0x3b63,
+ 0x7b0e, 0x1d93,
+ 0x7b0f, 0x1d90,
+ 0x7b10, 0x1d8c,
+ 0x7b11, 0x0969,
+ 0x7b12, 0x1d95,
+ 0x7b13, 0x1d8e,
+ 0x7b14, 0x3f77,
+ 0x7b18, 0x1fd5,
+ 0x7b19, 0x0b4d,
+ 0x7b1a, 0x1fde,
+ 0x7b1b, 0x0b4a,
+ 0x7b1d, 0x1fd7,
+ 0x7b1e, 0x0b4e,
+ 0x7b1f, 0x3f11,
+ 0x7b20, 0x0b48,
+ 0x7b22, 0x1fd2,
+ 0x7b23, 0x1fdf,
+ 0x7b24, 0x1fd3,
+ 0x7b25, 0x1fd0,
+ 0x7b26, 0x0b4c,
+ 0x7b27, 0x3b5f,
+ 0x7b28, 0x0b49,
+ 0x7b29, 0x3748,
+ 0x7b2a, 0x1fd6,
+ 0x7b2b, 0x1fd9,
+ 0x7b2c, 0x0b4b,
+ 0x7b2d, 0x1fda,
+ 0x7b2e, 0x0b4f,
+ 0x7b2f, 0x1fdb,
+ 0x7b30, 0x1fd1,
+ 0x7b31, 0x1fd8,
+ 0x7b32, 0x1fdc,
+ 0x7b33, 0x1fd4,
+ 0x7b34, 0x1fcf,
+ 0x7b35, 0x1fcd,
+ 0x7b38, 0x1fdd,
+ 0x7b39, 0x3d6e,
+ 0x7b3b, 0x1fce,
+ 0x7b40, 0x2259,
+ 0x7b42, 0x3ded,
+ 0x7b43, 0x3e25,
+ 0x7b44, 0x2255,
+ 0x7b45, 0x225b,
+ 0x7b46, 0x0d05,
+ 0x7b47, 0x2254,
+ 0x7b48, 0x2256,
+ 0x7b49, 0x0d03,
+ 0x7b4a, 0x2253,
+ 0x7b4b, 0x0d0a,
+ 0x7b4c, 0x2257,
+ 0x7b4d, 0x0d09,
+ 0x7b4e, 0x2258,
+ 0x7b4f, 0x0d0b,
+ 0x7b50, 0x0d06,
+ 0x7b51, 0x0d0c,
+ 0x7b52, 0x0d07,
+ 0x7b54, 0x0d08,
+ 0x7b55, 0x3747,
+ 0x7b56, 0x0d04,
+ 0x7b58, 0x225a,
+ 0x7b60, 0x0eb8,
+ 0x7b61, 0x24f8,
+ 0x7b62, 0x4727,
+ 0x7b63, 0x24fb,
+ 0x7b64, 0x24ef,
+ 0x7b65, 0x24f4,
+ 0x7b66, 0x24ee,
+ 0x7b67, 0x0eba,
+ 0x7b69, 0x24f2,
+ 0x7b6c, 0x4728,
+ 0x7b6d, 0x24f0,
+ 0x7b6e, 0x0eb9,
+ 0x7b6f, 0x374c,
+ 0x7b70, 0x24f7,
+ 0x7b71, 0x24f6,
+ 0x7b72, 0x24f3,
+ 0x7b73, 0x24f5,
+ 0x7b74, 0x24f1,
+ 0x7b75, 0x1050,
+ 0x7b76, 0x24fa,
+ 0x7b77, 0x0eb6,
+ 0x7b78, 0x24f9,
+ 0x7b7b, 0x4729,
+ 0x7b82, 0x2779,
+ 0x7b84, 0x1057,
+ 0x7b85, 0x2774,
+ 0x7b87, 0x1056,
+ 0x7b88, 0x276a,
+ 0x7b8a, 0x276c,
+ 0x7b8b, 0x104f,
+ 0x7b8c, 0x2771,
+ 0x7b8d, 0x2770,
+ 0x7b8e, 0x2773,
+ 0x7b8f, 0x1054,
+ 0x7b90, 0x276e,
+ 0x7b91, 0x276d,
+ 0x7b92, 0x3752,
+ 0x7b94, 0x1053,
+ 0x7b95, 0x104e,
+ 0x7b96, 0x276f,
+ 0x7b97, 0x1051,
+ 0x7b98, 0x2775,
+ 0x7b99, 0x2777,
+ 0x7b9b, 0x2772,
+ 0x7b9c, 0x276b,
+ 0x7b9d, 0x1052,
+ 0x7ba0, 0x11d2,
+ 0x7ba1, 0x104d,
+ 0x7ba2, 0x374b,
+ 0x7ba3, 0x3f14,
+ 0x7ba4, 0x2778,
+ 0x7bac, 0x29aa,
+ 0x7bad, 0x11cb,
+ 0x7baf, 0x29ac,
+ 0x7bb1, 0x11cc,
+ 0x7bb2, 0x461c,
+ 0x7bb4, 0x11ce,
+ 0x7bb5, 0x29af,
+ 0x7bb7, 0x29a7,
+ 0x7bb8, 0x1055,
+ 0x7bb9, 0x29ad,
+ 0x7bbe, 0x29a9,
+ 0x7bc0, 0x0eb7,
+ 0x7bc1, 0x11d1,
+ 0x7bc4, 0x11cd,
+ 0x7bc6, 0x11cf,
+ 0x7bc9, 0x1318,
+ 0x7bca, 0x29ae,
+ 0x7bcb, 0x29a8,
+ 0x7bcc, 0x11d3,
+ 0x7bce, 0x29ab,
+ 0x7bcf, 0x3f18,
+ 0x7bd0, 0x3750,
+ 0x7bd4, 0x2c07,
+ 0x7bd5, 0x2c02,
+ 0x7bd8, 0x2c0c,
+ 0x7bd9, 0x1316,
+ 0x7bda, 0x2c04,
+ 0x7bdb, 0x131a,
+ 0x7bdc, 0x2c0a,
+ 0x7bdd, 0x2c01,
+ 0x7bde, 0x2bfe,
+ 0x7bdf, 0x2c0d,
+ 0x7be0, 0x142d,
+ 0x7be1, 0x131b,
+ 0x7be2, 0x2c09,
+ 0x7be3, 0x2bff,
+ 0x7be4, 0x1319,
+ 0x7be5, 0x2c03,
+ 0x7be6, 0x131d,
+ 0x7be7, 0x2c00,
+ 0x7be8, 0x2c05,
+ 0x7be9, 0x131c,
+ 0x7bea, 0x2c08,
+ 0x7beb, 0x2c0b,
+ 0x7bf0, 0x2de9,
+ 0x7bf2, 0x2dda,
+ 0x7bf3, 0x2de1,
+ 0x7bf4, 0x2ddf,
+ 0x7bf7, 0x142b,
+ 0x7bf8, 0x2de6,
+ 0x7bf9, 0x2c06,
+ 0x7bfa, 0x3757,
+ 0x7bfb, 0x2ddd,
+ 0x7bfc, 0x3f1f,
+ 0x7bfd, 0x2de7,
+ 0x7bfe, 0x142a,
+ 0x7bff, 0x2ddc,
+ 0x7c00, 0x2ddb,
+ 0x7c01, 0x2de5,
+ 0x7c02, 0x2de2,
+ 0x7c03, 0x2de4,
+ 0x7c05, 0x2dd8,
+ 0x7c06, 0x2de8,
+ 0x7c07, 0x1428,
+ 0x7c09, 0x2de3,
+ 0x7c0a, 0x2dec,
+ 0x7c0b, 0x2de0,
+ 0x7c0c, 0x142c,
+ 0x7c0d, 0x1429,
+ 0x7c0e, 0x2dde,
+ 0x7c0f, 0x2dd9,
+ 0x7c10, 0x2deb,
+ 0x7c11, 0x1317,
+ 0x7c12, 0x472a,
+ 0x7c15, 0x4061,
+ 0x7c19, 0x2f78,
+ 0x7c1b, 0x43d9,
+ 0x7c1c, 0x2f76,
+ 0x7c1d, 0x2f7c,
+ 0x7c1e, 0x1508,
+ 0x7c1f, 0x2f7a,
+ 0x7c20, 0x2f79,
+ 0x7c21, 0x150a,
+ 0x7c22, 0x2f7f,
+ 0x7c23, 0x1509,
+ 0x7c25, 0x2f80,
+ 0x7c26, 0x2f7d,
+ 0x7c27, 0x1506,
+ 0x7c28, 0x2f7e,
+ 0x7c29, 0x2f77,
+ 0x7c2a, 0x1507,
+ 0x7c2b, 0x1505,
+ 0x7c2c, 0x30d6,
+ 0x7c2d, 0x2f7b,
+ 0x7c30, 0x2f81,
+ 0x7c33, 0x30d3,
+ 0x7c35, 0x3759,
+ 0x7c37, 0x15a7,
+ 0x7c38, 0x15a5,
+ 0x7c39, 0x30d5,
+ 0x7c3b, 0x30d7,
+ 0x7c3c, 0x30d4,
+ 0x7c3d, 0x15a6,
+ 0x7c3e, 0x15a3,
+ 0x7c40, 0x15a8,
+ 0x7c42, 0x3f1c,
+ 0x7c43, 0x162b,
+ 0x7c44, 0x375b,
+ 0x7c45, 0x3212,
+ 0x7c47, 0x3211,
+ 0x7c48, 0x320f,
+ 0x7c49, 0x320e,
+ 0x7c4a, 0x3210,
+ 0x7c4c, 0x162a,
+ 0x7c4d, 0x162c,
+ 0x7c50, 0x1681,
+ 0x7c51, 0x3fb8,
+ 0x7c53, 0x32ea,
+ 0x7c54, 0x32e9,
+ 0x7c56, 0x3eff,
+ 0x7c57, 0x339b,
+ 0x7c59, 0x339d,
+ 0x7c5a, 0x339f,
+ 0x7c5b, 0x339e,
+ 0x7c5c, 0x339c,
+ 0x7c5d, 0x3b3f,
+ 0x7c5f, 0x16d1,
+ 0x7c60, 0x16d0,
+ 0x7c63, 0x1701,
+ 0x7c64, 0x1700,
+ 0x7c65, 0x1702,
+ 0x7c66, 0x342b,
+ 0x7c67, 0x342a,
+ 0x7c69, 0x34d6,
+ 0x7c6a, 0x3493,
+ 0x7c6b, 0x34d7,
+ 0x7c6c, 0x1745,
+ 0x7c6d, 0x3b40,
+ 0x7c6e, 0x1746,
+ 0x7c6f, 0x3507,
+ 0x7c70, 0x3f52,
+ 0x7c72, 0x176b,
+ 0x7c73, 0x03f7,
+ 0x7c74, 0x469c,
+ 0x7c75, 0x1a25,
+ 0x7c78, 0x1bbb,
+ 0x7c7a, 0x1bba,
+ 0x7c7b, 0x472d,
+ 0x7c7c, 0x3b49,
+ 0x7c7d, 0x07cc,
+ 0x7c7e, 0x3f1a,
+ 0x7c7f, 0x1bbd,
+ 0x7c83, 0x375c,
+ 0x7c84, 0x1d96,
+ 0x7c85, 0x1d9c,
+ 0x7c86, 0x3f1d,
+ 0x7c88, 0x1d9a,
+ 0x7c89, 0x096a,
+ 0x7c8a, 0x1d98,
+ 0x7c8c, 0x1d99,
+ 0x7c8d, 0x1d9b,
+ 0x7c8e, 0x3b48,
+ 0x7c91, 0x1d97,
+ 0x7c92, 0x0b50,
+ 0x7c94, 0x1fe0,
+ 0x7c95, 0x0b52,
+ 0x7c96, 0x1fe2,
+ 0x7c97, 0x0b51,
+ 0x7c98, 0x1fe1,
+ 0x7c9c, 0x472e,
+ 0x7c9e, 0x225d,
+ 0x7c9f, 0x0d0d,
+ 0x7ca1, 0x225f,
+ 0x7ca2, 0x225c,
+ 0x7ca3, 0x1fe3,
+ 0x7ca5, 0x0d0e,
+ 0x7ca6, 0x375e,
+ 0x7ca7, 0x36ed,
+ 0x7ca8, 0x225e,
+ 0x7cac, 0x3885,
+ 0x7cae, 0x3b4a,
+ 0x7caf, 0x24fe,
+ 0x7cb1, 0x0ebb,
+ 0x7cb2, 0x24fc,
+ 0x7cb3, 0x0ebc,
+ 0x7cb4, 0x24fd,
+ 0x7cb5, 0x0ebd,
+ 0x7cb8, 0x4730,
+ 0x7cb9, 0x1058,
+ 0x7cba, 0x277d,
+ 0x7cbb, 0x277a,
+ 0x7cbc, 0x277c,
+ 0x7cbd, 0x1059,
+ 0x7cbf, 0x277b,
+ 0x7cc2, 0x3fd7,
+ 0x7cc5, 0x29b0,
+ 0x7cc7, 0x3761,
+ 0x7cc8, 0x29b1,
+ 0x7cc9, 0x3760,
+ 0x7cca, 0x11d4,
+ 0x7ccb, 0x29b3,
+ 0x7ccc, 0x29b2,
+ 0x7ccd, 0x3b45,
+ 0x7cce, 0x0121,
+ 0x7cd0, 0x2c11,
+ 0x7cd2, 0x2c0e,
+ 0x7cd3, 0x3d5c,
+ 0x7cd4, 0x2c0f,
+ 0x7cd5, 0x131e,
+ 0x7cd7, 0x2c10,
+ 0x7cd9, 0x1433,
+ 0x7cda, 0x3fd9,
+ 0x7cdc, 0x142f,
+ 0x7cdd, 0x1434,
+ 0x7cde, 0x1430,
+ 0x7cdf, 0x1432,
+ 0x7ce0, 0x142e,
+ 0x7ce2, 0x1431,
+ 0x7ce6, 0x3762,
+ 0x7ce7, 0x150b,
+ 0x7ce8, 0x2ded,
+ 0x7cea, 0x30d9,
+ 0x7cec, 0x30d8,
+ 0x7ced, 0x43da,
+ 0x7cee, 0x3213,
+ 0x7cef, 0x162d,
+ 0x7cf1, 0x33a1,
+ 0x7cf2, 0x32eb,
+ 0x7cf3, 0x3764,
+ 0x7cf4, 0x33a0,
+ 0x7cf5, 0x3765,
+ 0x7cf6, 0x34d8,
+ 0x7cf7, 0x351d,
+ 0x7cf8, 0x03f8,
+ 0x7cf9, 0x44f8,
+ 0x7cfb, 0x04fb,
+ 0x7cfc, 0x456d,
+ 0x7cfd, 0x1a26,
+ 0x7cfe, 0x0667,
+ 0x7d00, 0x07cf,
+ 0x7d01, 0x1bc2,
+ 0x7d02, 0x07cd,
+ 0x7d03, 0x1bc0,
+ 0x7d04, 0x07d2,
+ 0x7d05, 0x07ce,
+ 0x7d06, 0x07d3,
+ 0x7d07, 0x07d1,
+ 0x7d08, 0x1bc1,
+ 0x7d09, 0x07d0,
+ 0x7d0a, 0x096e,
+ 0x7d0b, 0x096d,
+ 0x7d0c, 0x1da7,
+ 0x7d0d, 0x0976,
+ 0x7d0e, 0x1da0,
+ 0x7d0f, 0x1da6,
+ 0x7d10, 0x0972,
+ 0x7d11, 0x1d9f,
+ 0x7d12, 0x1da5,
+ 0x7d13, 0x1da3,
+ 0x7d14, 0x0971,
+ 0x7d15, 0x0973,
+ 0x7d16, 0x1da2,
+ 0x7d17, 0x096c,
+ 0x7d18, 0x1da1,
+ 0x7d19, 0x0977,
+ 0x7d1a, 0x0974,
+ 0x7d1b, 0x0978,
+ 0x7d1c, 0x0975,
+ 0x7d1d, 0x1d9e,
+ 0x7d1e, 0x1d9d,
+ 0x7d1f, 0x1da4,
+ 0x7d20, 0x096f,
+ 0x7d21, 0x096b,
+ 0x7d22, 0x0970,
+ 0x7d25, 0x3ede,
+ 0x7d28, 0x1ff2,
+ 0x7d29, 0x1feb,
+ 0x7d2b, 0x0d13,
+ 0x7d2c, 0x1fea,
+ 0x7d2e, 0x0b56,
+ 0x7d2f, 0x0b5d,
+ 0x7d30, 0x0b5a,
+ 0x7d31, 0x0b60,
+ 0x7d32, 0x0b5f,
+ 0x7d33, 0x0b5b,
+ 0x7d35, 0x1fe4,
+ 0x7d36, 0x1fe7,
+ 0x7d38, 0x1fe6,
+ 0x7d39, 0x0b57,
+ 0x7d3a, 0x1fe8,
+ 0x7d3b, 0x1ff1,
+ 0x7d3c, 0x0b58,
+ 0x7d3d, 0x1fe5,
+ 0x7d3e, 0x1fee,
+ 0x7d40, 0x0b59,
+ 0x7d41, 0x1fec,
+ 0x7d42, 0x0b5e,
+ 0x7d43, 0x0b54,
+ 0x7d44, 0x0b5c,
+ 0x7d45, 0x1fe9,
+ 0x7d46, 0x0b53,
+ 0x7d47, 0x1fed,
+ 0x7d4a, 0x1ff0,
+ 0x7d4d, 0x3fdd,
+ 0x7d4e, 0x2270,
+ 0x7d4f, 0x2267,
+ 0x7d50, 0x0d10,
+ 0x7d51, 0x226e,
+ 0x7d52, 0x226b,
+ 0x7d53, 0x2263,
+ 0x7d54, 0x226c,
+ 0x7d55, 0x0d12,
+ 0x7d56, 0x2264,
+ 0x7d58, 0x2260,
+ 0x7d5a, 0x3e93,
+ 0x7d5b, 0x0ec3,
+ 0x7d5c, 0x2269,
+ 0x7d5d, 0x3769,
+ 0x7d5e, 0x0d0f,
+ 0x7d5f, 0x226f,
+ 0x7d61, 0x0d16,
+ 0x7d62, 0x0d18,
+ 0x7d63, 0x2262,
+ 0x7d66, 0x0d17,
+ 0x7d67, 0x2265,
+ 0x7d68, 0x0d11,
+ 0x7d69, 0x226d,
+ 0x7d6a, 0x2266,
+ 0x7d6b, 0x226a,
+ 0x7d6d, 0x2268,
+ 0x7d6e, 0x0d14,
+ 0x7d6f, 0x2261,
+ 0x7d70, 0x0d19,
+ 0x7d71, 0x0b55,
+ 0x7d72, 0x0d15,
+ 0x7d73, 0x0d1a,
+ 0x7d79, 0x0ebf,
+ 0x7d7a, 0x2505,
+ 0x7d7b, 0x2507,
+ 0x7d7c, 0x2509,
+ 0x7d7d, 0x250d,
+ 0x7d7f, 0x2503,
+ 0x7d80, 0x2501,
+ 0x7d81, 0x0ec1,
+ 0x7d83, 0x2508,
+ 0x7d84, 0x250c,
+ 0x7d85, 0x2504,
+ 0x7d86, 0x2500,
+ 0x7d88, 0x24ff,
+ 0x7d89, 0x376b,
+ 0x7d8c, 0x250a,
+ 0x7d8d, 0x2502,
+ 0x7d8e, 0x2506,
+ 0x7d8f, 0x0ec2,
+ 0x7d91, 0x0ec0,
+ 0x7d92, 0x250e,
+ 0x7d93, 0x0ebe,
+ 0x7d94, 0x250b,
+ 0x7d96, 0x278e,
+ 0x7d97, 0x3b53,
+ 0x7d9c, 0x105d,
+ 0x7d9d, 0x2786,
+ 0x7d9e, 0x11e1,
+ 0x7d9f, 0x2790,
+ 0x7da0, 0x1060,
+ 0x7da1, 0x2794,
+ 0x7da2, 0x1066,
+ 0x7da3, 0x2781,
+ 0x7da4, 0x46d7,
+ 0x7da6, 0x2791,
+ 0x7da7, 0x277e,
+ 0x7da8, 0x3c9c,
+ 0x7da9, 0x2793,
+ 0x7daa, 0x2782,
+ 0x7dab, 0x376c,
+ 0x7dac, 0x106d,
+ 0x7dad, 0x106a,
+ 0x7dae, 0x2792,
+ 0x7daf, 0x278c,
+ 0x7db0, 0x105c,
+ 0x7db1, 0x1064,
+ 0x7db2, 0x1063,
+ 0x7db3, 0x376e,
+ 0x7db4, 0x1062,
+ 0x7db5, 0x1068,
+ 0x7db7, 0x277f,
+ 0x7db8, 0x1069,
+ 0x7db9, 0x278d,
+ 0x7dba, 0x1065,
+ 0x7dbb, 0x105b,
+ 0x7dbc, 0x278f,
+ 0x7dbd, 0x105e,
+ 0x7dbf, 0x1067,
+ 0x7dc0, 0x2784,
+ 0x7dc1, 0x2783,
+ 0x7dc2, 0x2780,
+ 0x7dc4, 0x2788,
+ 0x7dc5, 0x2785,
+ 0x7dc6, 0x2789,
+ 0x7dc7, 0x106c,
+ 0x7dc9, 0x2795,
+ 0x7dca, 0x1061,
+ 0x7dcb, 0x278a,
+ 0x7dcd, 0x456e,
+ 0x7dce, 0x2787,
+ 0x7dcf, 0x4735,
+ 0x7dd0, 0x4737,
+ 0x7dd2, 0x106b,
+ 0x7dd3, 0x3b4e,
+ 0x7dd4, 0x4736,
+ 0x7dd6, 0x376f,
+ 0x7dd7, 0x29b8,
+ 0x7dd8, 0x11d9,
+ 0x7dd9, 0x11e2,
+ 0x7dda, 0x11de,
+ 0x7ddb, 0x29b5,
+ 0x7ddc, 0x3b4c,
+ 0x7ddd, 0x11db,
+ 0x7dde, 0x11df,
+ 0x7ddf, 0x29c1,
+ 0x7de0, 0x11d5,
+ 0x7de1, 0x29b9,
+ 0x7de3, 0x11dd,
+ 0x7de4, 0x3772,
+ 0x7de5, 0x3776,
+ 0x7de6, 0x29bc,
+ 0x7de7, 0x29b7,
+ 0x7de8, 0x11dc,
+ 0x7de9, 0x11e0,
+ 0x7dea, 0x29b6,
+ 0x7dec, 0x11da,
+ 0x7dee, 0x29c0,
+ 0x7def, 0x11d7,
+ 0x7df0, 0x29bf,
+ 0x7df1, 0x29be,
+ 0x7df2, 0x11e3,
+ 0x7df3, 0x28c8,
+ 0x7df4, 0x11d6,
+ 0x7df5, 0x3774,
+ 0x7df6, 0x29bd,
+ 0x7df7, 0x29b4,
+ 0x7df9, 0x11e4,
+ 0x7dfa, 0x29bb,
+ 0x7dfb, 0x11d8,
+ 0x7dfd, 0x4738,
+ 0x7dfe, 0x3ccf,
+ 0x7e03, 0x29ba,
+ 0x7e07, 0x3b4d,
+ 0x7e08, 0x1322,
+ 0x7e09, 0x1327,
+ 0x7e0a, 0x1320,
+ 0x7e0b, 0x2c1f,
+ 0x7e0c, 0x2c16,
+ 0x7e0d, 0x2c22,
+ 0x7e0e, 0x2c1a,
+ 0x7e0f, 0x2c20,
+ 0x7e10, 0x1328,
+ 0x7e11, 0x1321,
+ 0x7e12, 0x2c13,
+ 0x7e13, 0x2c19,
+ 0x7e14, 0x2c23,
+ 0x7e15, 0x2c1c,
+ 0x7e16, 0x2c21,
+ 0x7e17, 0x2c15,
+ 0x7e1a, 0x2c1d,
+ 0x7e1b, 0x1323,
+ 0x7e1c, 0x2c1b,
+ 0x7e1d, 0x1326,
+ 0x7e1e, 0x1325,
+ 0x7e1f, 0x2c17,
+ 0x7e21, 0x2c14,
+ 0x7e22, 0x2c1e,
+ 0x7e23, 0x1324,
+ 0x7e24, 0x2c25,
+ 0x7e25, 0x2c24,
+ 0x7e27, 0x377f,
+ 0x7e29, 0x2df8,
+ 0x7e2a, 0x2df4,
+ 0x7e2b, 0x143b,
+ 0x7e2d, 0x2dee,
+ 0x7e2e, 0x1435,
+ 0x7e2f, 0x1445,
+ 0x7e30, 0x2dfa,
+ 0x7e31, 0x143d,
+ 0x7e32, 0x1439,
+ 0x7e33, 0x2df1,
+ 0x7e34, 0x1440,
+ 0x7e35, 0x1443,
+ 0x7e36, 0x2dfc,
+ 0x7e37, 0x1438,
+ 0x7e38, 0x2df3,
+ 0x7e39, 0x1441,
+ 0x7e3a, 0x2dfe,
+ 0x7e3b, 0x2dfb,
+ 0x7e3c, 0x2def,
+ 0x7e3d, 0x143c,
+ 0x7e3e, 0x1436,
+ 0x7e3f, 0x1444,
+ 0x7e40, 0x2df6,
+ 0x7e41, 0x143f,
+ 0x7e42, 0x2df0,
+ 0x7e43, 0x143a,
+ 0x7e44, 0x2dfd,
+ 0x7e45, 0x143e,
+ 0x7e46, 0x1437,
+ 0x7e47, 0x2df7,
+ 0x7e48, 0x1442,
+ 0x7e49, 0x2df5,
+ 0x7e4c, 0x2df9,
+ 0x7e50, 0x2f83,
+ 0x7e51, 0x2f89,
+ 0x7e52, 0x1511,
+ 0x7e53, 0x2f8c,
+ 0x7e54, 0x150c,
+ 0x7e56, 0x2f84,
+ 0x7e57, 0x2f8b,
+ 0x7e58, 0x2f86,
+ 0x7e59, 0x1512,
+ 0x7e5a, 0x150f,
+ 0x7e5c, 0x2f82,
+ 0x7e5e, 0x150e,
+ 0x7e5f, 0x2f88,
+ 0x7e60, 0x2f8a,
+ 0x7e61, 0x1510,
+ 0x7e62, 0x2f87,
+ 0x7e63, 0x2f85,
+ 0x7e65, 0x46d2,
+ 0x7e67, 0x3766,
+ 0x7e68, 0x30e3,
+ 0x7e69, 0x15ac,
+ 0x7e6b, 0x15a9,
+ 0x7e6d, 0x15aa,
+ 0x7e6e, 0x377b,
+ 0x7e6f, 0x30df,
+ 0x7e70, 0x30dd,
+ 0x7e72, 0x30e1,
+ 0x7e73, 0x15ae,
+ 0x7e74, 0x30e2,
+ 0x7e75, 0x30db,
+ 0x7e76, 0x30da,
+ 0x7e77, 0x30de,
+ 0x7e78, 0x30dc,
+ 0x7e79, 0x15ab,
+ 0x7e7a, 0x30e0,
+ 0x7e7b, 0x3214,
+ 0x7e7c, 0x1631,
+ 0x7e7d, 0x1630,
+ 0x7e7e, 0x3215,
+ 0x7e7f, 0x3e51,
+ 0x7e80, 0x3217,
+ 0x7e81, 0x3216,
+ 0x7e82, 0x1632,
+ 0x7e86, 0x32f0,
+ 0x7e87, 0x32ed,
+ 0x7e8a, 0x32ec,
+ 0x7e8b, 0x32ef,
+ 0x7e8c, 0x1683,
+ 0x7e8d, 0x32f1,
+ 0x7e8e, 0x3ec9,
+ 0x7e8f, 0x1682,
+ 0x7e91, 0x33a2,
+ 0x7e92, 0x469e,
+ 0x7e93, 0x1703,
+ 0x7e94, 0x1705,
+ 0x7e95, 0x342c,
+ 0x7e96, 0x1704,
+ 0x7e97, 0x3494,
+ 0x7e98, 0x34da,
+ 0x7e99, 0x34dc,
+ 0x7e9a, 0x34d9,
+ 0x7e9b, 0x34db,
+ 0x7e9c, 0x1759,
+ 0x7e9f, 0x48bb,
+ 0x7ea4, 0x455b,
+ 0x7eac, 0x455c,
+ 0x7eba, 0x455d,
+ 0x7ec7, 0x455e,
+ 0x7ecf, 0x455f,
+ 0x7edf, 0x4560,
+ 0x7f06, 0x4561,
+ 0x7f36, 0x03f9,
+ 0x7f37, 0x4562,
+ 0x7f38, 0x07d4,
+ 0x7f39, 0x1d1f,
+ 0x7f3a, 0x0979,
+ 0x7f3d, 0x0b61,
+ 0x7f3e, 0x2271,
+ 0x7f40, 0x3780,
+ 0x7f43, 0x2c26,
+ 0x7f44, 0x1446,
+ 0x7f45, 0x2dff,
+ 0x7f47, 0x3782,
+ 0x7f48, 0x1513,
+ 0x7f49, 0x3e69,
+ 0x7f4a, 0x30e5,
+ 0x7f4b, 0x30e4,
+ 0x7f4c, 0x1633,
+ 0x7f4d, 0x32f2,
+ 0x7f4e, 0x3b4f,
+ 0x7f4f, 0x33a3,
+ 0x7f50, 0x1726,
+ 0x7f51, 0x1812,
+ 0x7f52, 0x44f6,
+ 0x7f53, 0x44f9,
+ 0x7f54, 0x0668,
+ 0x7f55, 0x04fc,
+ 0x7f58, 0x1bc3,
+ 0x7f5b, 0x1dad,
+ 0x7f5c, 0x1da8,
+ 0x7f5d, 0x1dac,
+ 0x7f5e, 0x1daa,
+ 0x7f5f, 0x097a,
+ 0x7f60, 0x1dab,
+ 0x7f61, 0x1da9,
+ 0x7f63, 0x1ff3,
+ 0x7f65, 0x2273,
+ 0x7f67, 0x2511,
+ 0x7f69, 0x0ec5,
+ 0x7f6b, 0x2510,
+ 0x7f6c, 0x2513,
+ 0x7f6d, 0x250f,
+ 0x7f6e, 0x0ec4,
+ 0x7f70, 0x106e,
+ 0x7f71, 0x4007,
+ 0x7f72, 0x0ec7,
+ 0x7f73, 0x2796,
+ 0x7f75, 0x11e5,
+ 0x7f76, 0x29c2,
+ 0x7f77, 0x11e6,
+ 0x7f78, 0x3f7b,
+ 0x7f79, 0x1329,
+ 0x7f7a, 0x2c29,
+ 0x7f7b, 0x2c27,
+ 0x7f7d, 0x2e02,
+ 0x7f7e, 0x2e01,
+ 0x7f7f, 0x2e00,
+ 0x7f83, 0x30e6,
+ 0x7f85, 0x15af,
+ 0x7f86, 0x30e7,
+ 0x7f87, 0x33a4,
+ 0x7f88, 0x1727,
+ 0x7f89, 0x3495,
+ 0x7f8a, 0x03fa,
+ 0x7f8b, 0x066a,
+ 0x7f8c, 0x0669,
+ 0x7f8d, 0x1bc5,
+ 0x7f8e, 0x07d5,
+ 0x7f8f, 0x421c,
+ 0x7f91, 0x1bc4,
+ 0x7f92, 0x1daf,
+ 0x7f93, 0x43db,
+ 0x7f94, 0x097b,
+ 0x7f95, 0x1ff4,
+ 0x7f96, 0x1dae,
+ 0x7f97, 0x3786,
+ 0x7f9a, 0x0b63,
+ 0x7f9b, 0x1ff7,
+ 0x7f9c, 0x1ff5,
+ 0x7f9e, 0x0b62,
+ 0x7fa0, 0x2276,
+ 0x7fa2, 0x2275,
+ 0x7fa3, 0x3788,
+ 0x7fa4, 0x0eca,
+ 0x7fa5, 0x2515,
+ 0x7fa6, 0x2514,
+ 0x7fa7, 0x2516,
+ 0x7fa8, 0x0ec9,
+ 0x7fa9, 0x0ec8,
+ 0x7fac, 0x29c3,
+ 0x7fad, 0x29c5,
+ 0x7fae, 0x43dc,
+ 0x7faf, 0x11e7,
+ 0x7fb0, 0x29c4,
+ 0x7fb1, 0x2c2a,
+ 0x7fb2, 0x132a,
+ 0x7fb3, 0x2f8e,
+ 0x7fb4, 0x4739,
+ 0x7fb5, 0x2f8d,
+ 0x7fb6, 0x15b0,
+ 0x7fb7, 0x30e8,
+ 0x7fb8, 0x15b2,
+ 0x7fb9, 0x15b1,
+ 0x7fba, 0x3218,
+ 0x7fbb, 0x32f3,
+ 0x7fbc, 0x1684,
+ 0x7fbd, 0x03fb,
+ 0x7fbe, 0x1bc6,
+ 0x7fbf, 0x07d6,
+ 0x7fc0, 0x1db2,
+ 0x7fc1, 0x097d,
+ 0x7fc2, 0x1db1,
+ 0x7fc3, 0x1db0,
+ 0x7fc5, 0x097c,
+ 0x7fc7, 0x1ffd,
+ 0x7fc9, 0x1fff,
+ 0x7fca, 0x1ff8,
+ 0x7fcc, 0x0b64,
+ 0x7fcd, 0x1ffa,
+ 0x7fce, 0x0b65,
+ 0x7fcf, 0x1ffe,
+ 0x7fd0, 0x1ffb,
+ 0x7fd2, 0x0b66,
+ 0x7fd4, 0x0d1c,
+ 0x7fd7, 0x2278,
+ 0x7fdb, 0x2517,
+ 0x7fdd, 0x3b5e,
+ 0x7fde, 0x279a,
+ 0x7fdf, 0x1071,
+ 0x7fe0, 0x106f,
+ 0x7fe2, 0x2797,
+ 0x7fe5, 0x2799,
+ 0x7fe6, 0x29ca,
+ 0x7fe7, 0x46e9,
+ 0x7fe8, 0x29cb,
+ 0x7fe9, 0x11e8,
+ 0x7fea, 0x29c8,
+ 0x7feb, 0x29c7,
+ 0x7fec, 0x29c9,
+ 0x7fed, 0x29c6,
+ 0x7fee, 0x132d,
+ 0x7fef, 0x2c2b,
+ 0x7ff0, 0x132b,
+ 0x7ff2, 0x2e04,
+ 0x7ff3, 0x1447,
+ 0x7ff4, 0x2e03,
+ 0x7ff5, 0x2eff,
+ 0x7ff7, 0x2f8f,
+ 0x7ff9, 0x1514,
+ 0x7ffa, 0x378e,
+ 0x7ffb, 0x1515,
+ 0x7ffc, 0x1448,
+ 0x7ffd, 0x30e9,
+ 0x7fff, 0x3219,
+ 0x8000, 0x1634,
+ 0x8001, 0x03fc,
+ 0x8002, 0x44fd,
+ 0x8003, 0x03fd,
+ 0x8004, 0x097f,
+ 0x8005, 0x066b,
+ 0x8006, 0x097e,
+ 0x8007, 0x1bc7,
+ 0x8008, 0x3791,
+ 0x800b, 0x0d1e,
+ 0x800c, 0x03fe,
+ 0x800d, 0x07d8,
+ 0x800e, 0x1bc8,
+ 0x8010, 0x07d7,
+ 0x8011, 0x07d9,
+ 0x8012, 0x03ff,
+ 0x8014, 0x1bca,
+ 0x8015, 0x0981,
+ 0x8016, 0x1db3,
+ 0x8017, 0x0983,
+ 0x8018, 0x0980,
+ 0x8019, 0x0982,
+ 0x801b, 0x2002,
+ 0x801c, 0x0b67,
+ 0x801d, 0x3792,
+ 0x801e, 0x2001,
+ 0x801f, 0x2000,
+ 0x8020, 0x473c,
+ 0x8021, 0x2519,
+ 0x8024, 0x279b,
+ 0x8025, 0x473d,
+ 0x8026, 0x11e9,
+ 0x8028, 0x132e,
+ 0x8029, 0x2c2d,
+ 0x802a, 0x2c2c,
+ 0x802c, 0x2e05,
+ 0x802e, 0x473e,
+ 0x802f, 0x3794,
+ 0x8030, 0x32f4,
+ 0x8031, 0x473f,
+ 0x8033, 0x0400,
+ 0x8034, 0x18d8,
+ 0x8035, 0x1a27,
+ 0x8036, 0x07da,
+ 0x8037, 0x1bcb,
+ 0x8039, 0x1db5,
+ 0x803b, 0x3797,
+ 0x803d, 0x0984,
+ 0x803e, 0x1db4,
+ 0x803f, 0x0985,
+ 0x8043, 0x2004,
+ 0x8046, 0x0b69,
+ 0x8047, 0x2003,
+ 0x8048, 0x2005,
+ 0x804a, 0x0b68,
+ 0x804f, 0x227a,
+ 0x8051, 0x2279,
+ 0x8052, 0x0d1f,
+ 0x8054, 0x4740,
+ 0x8056, 0x0ecb,
+ 0x8058, 0x0ecc,
+ 0x805a, 0x1073,
+ 0x805b, 0x3fe5,
+ 0x805c, 0x279d,
+ 0x805d, 0x279c,
+ 0x805e, 0x1072,
+ 0x8061, 0x3799,
+ 0x8062, 0x3fe3,
+ 0x8063, 0x3fdc,
+ 0x8064, 0x29cc,
+ 0x8066, 0x3fdb,
+ 0x8067, 0x29cd,
+ 0x806c, 0x2c2e,
+ 0x806f, 0x144c,
+ 0x8070, 0x144b,
+ 0x8071, 0x1449,
+ 0x8073, 0x144d,
+ 0x8075, 0x2f91,
+ 0x8076, 0x1517,
+ 0x8077, 0x1516,
+ 0x8078, 0x30eb,
+ 0x8079, 0x321a,
+ 0x807d, 0x16d3,
+ 0x807e, 0x16d2,
+ 0x807f, 0x0401,
+ 0x8080, 0x44fe,
+ 0x8082, 0x1cec,
+ 0x8084, 0x0ece,
+ 0x8085, 0x0d20,
+ 0x8086, 0x0ecd,
+ 0x8087, 0x1074,
+ 0x8089, 0x0402,
+ 0x808a, 0x17b3,
+ 0x808b, 0x0403,
+ 0x808f, 0x1a28,
+ 0x8090, 0x18db,
+ 0x8092, 0x18dc,
+ 0x8093, 0x04fe,
+ 0x8095, 0x18d9,
+ 0x8096, 0x04fd,
+ 0x8098, 0x0500,
+ 0x8099, 0x18da,
+ 0x809a, 0x0502,
+ 0x809b, 0x0501,
+ 0x809c, 0x18dd,
+ 0x809d, 0x04ff,
+ 0x809f, 0x4576,
+ 0x80a1, 0x0670,
+ 0x80a2, 0x066e,
+ 0x80a3, 0x1a2a,
+ 0x80a5, 0x066d,
+ 0x80a7, 0x37a0,
+ 0x80a9, 0x0672,
+ 0x80aa, 0x0674,
+ 0x80ab, 0x0671,
+ 0x80ad, 0x1a2d,
+ 0x80ae, 0x1a29,
+ 0x80af, 0x0675,
+ 0x80b1, 0x066f,
+ 0x80b2, 0x0503,
+ 0x80b4, 0x0673,
+ 0x80b5, 0x1a2c,
+ 0x80b6, 0x3eae,
+ 0x80b7, 0x4743,
+ 0x80b8, 0x1a2b,
+ 0x80ba, 0x066c,
+ 0x80bc, 0x4572,
+ 0x80bd, 0x3e7b,
+ 0x80c2, 0x1bd1,
+ 0x80c3, 0x07de,
+ 0x80c5, 0x1bd3,
+ 0x80c6, 0x3b74,
+ 0x80c7, 0x1bcd,
+ 0x80c8, 0x1bd0,
+ 0x80c9, 0x1bd9,
+ 0x80ca, 0x1bd7,
+ 0x80cc, 0x07e0,
+ 0x80cd, 0x1bdd,
+ 0x80ce, 0x07e3,
+ 0x80cf, 0x1bda,
+ 0x80d0, 0x1bd2,
+ 0x80d1, 0x1bcf,
+ 0x80d4, 0x227d,
+ 0x80d5, 0x1bd8,
+ 0x80d6, 0x07db,
+ 0x80d7, 0x1bdb,
+ 0x80d8, 0x1bcc,
+ 0x80d9, 0x1bd5,
+ 0x80da, 0x07dd,
+ 0x80db, 0x07e2,
+ 0x80dc, 0x1bd6,
+ 0x80dd, 0x07e6,
+ 0x80de, 0x07e4,
+ 0x80e0, 0x1bce,
+ 0x80e1, 0x07e1,
+ 0x80e3, 0x1bd4,
+ 0x80e4, 0x07e5,
+ 0x80e5, 0x07dc,
+ 0x80e6, 0x1bdc,
+ 0x80e9, 0x4744,
+ 0x80ec, 0x45e9,
+ 0x80ed, 0x098a,
+ 0x80ef, 0x0993,
+ 0x80f0, 0x0988,
+ 0x80f1, 0x0986,
+ 0x80f2, 0x1db7,
+ 0x80f3, 0x098e,
+ 0x80f4, 0x098b,
+ 0x80f5, 0x1db9,
+ 0x80f6, 0x4574,
+ 0x80f8, 0x098d,
+ 0x80f9, 0x1db8,
+ 0x80fa, 0x1db6,
+ 0x80fb, 0x1dbb,
+ 0x80fc, 0x0992,
+ 0x80fd, 0x0990,
+ 0x80fe, 0x227c,
+ 0x8100, 0x1dbc,
+ 0x8101, 0x1dba,
+ 0x8102, 0x0987,
+ 0x8103, 0x3fe7,
+ 0x8105, 0x0989,
+ 0x8106, 0x098c,
+ 0x8107, 0x37a2,
+ 0x8108, 0x098f,
+ 0x8109, 0x3b75,
+ 0x810a, 0x0991,
+ 0x810c, 0x4746,
+ 0x810e, 0x4747,
+ 0x8112, 0x4748,
+ 0x8114, 0x4749,
+ 0x8115, 0x200f,
+ 0x8116, 0x0b6b,
+ 0x8117, 0x3e6d,
+ 0x8118, 0x2006,
+ 0x8119, 0x2008,
+ 0x811a, 0x37a3,
+ 0x811b, 0x2009,
+ 0x811d, 0x2011,
+ 0x811e, 0x200d,
+ 0x811f, 0x200b,
+ 0x8121, 0x200e,
+ 0x8122, 0x2012,
+ 0x8123, 0x0b6c,
+ 0x8124, 0x0b70,
+ 0x8125, 0x2007,
+ 0x8127, 0x2010,
+ 0x8129, 0x0b6e,
+ 0x812a, 0x3a39,
+ 0x812b, 0x0b6d,
+ 0x812c, 0x200c,
+ 0x812d, 0x200a,
+ 0x812f, 0x0b6a,
+ 0x8130, 0x0b6f,
+ 0x8132, 0x3e79,
+ 0x8134, 0x45ec,
+ 0x8137, 0x3b72,
+ 0x8139, 0x0d26,
+ 0x813a, 0x2285,
+ 0x813d, 0x2283,
+ 0x813e, 0x0d28,
+ 0x8142, 0x3b76,
+ 0x8143, 0x227e,
+ 0x8144, 0x2527,
+ 0x8146, 0x0d27,
+ 0x8147, 0x2282,
+ 0x8148, 0x3e76,
+ 0x814a, 0x227f,
+ 0x814b, 0x0d23,
+ 0x814c, 0x0d29,
+ 0x814d, 0x2284,
+ 0x814e, 0x0d25,
+ 0x814f, 0x2281,
+ 0x8150, 0x1075,
+ 0x8151, 0x0d24,
+ 0x8152, 0x2280,
+ 0x8153, 0x0d2a,
+ 0x8154, 0x0d22,
+ 0x8155, 0x0d21,
+ 0x8156, 0x474c,
+ 0x8159, 0x474d,
+ 0x815b, 0x251f,
+ 0x815c, 0x251d,
+ 0x815e, 0x2523,
+ 0x8160, 0x251b,
+ 0x8161, 0x2528,
+ 0x8162, 0x2520,
+ 0x8164, 0x251a,
+ 0x8165, 0x0ed2,
+ 0x8166, 0x0ed8,
+ 0x8167, 0x2525,
+ 0x8169, 0x251e,
+ 0x816b, 0x0ed5,
+ 0x816d, 0x43c4,
+ 0x816e, 0x0ed3,
+ 0x816f, 0x2526,
+ 0x8170, 0x0ed0,
+ 0x8171, 0x0ecf,
+ 0x8172, 0x2521,
+ 0x8173, 0x0ed4,
+ 0x8174, 0x0d2b,
+ 0x8176, 0x2524,
+ 0x8177, 0x251c,
+ 0x8178, 0x0ed1,
+ 0x8179, 0x0ed6,
+ 0x817c, 0x4750,
+ 0x817f, 0x107a,
+ 0x8180, 0x1076,
+ 0x8182, 0x107b,
+ 0x8183, 0x27a0,
+ 0x8184, 0x43c5,
+ 0x8186, 0x279f,
+ 0x8187, 0x27a1,
+ 0x8188, 0x1078,
+ 0x8189, 0x279e,
+ 0x818a, 0x1079,
+ 0x818b, 0x27a4,
+ 0x818c, 0x27a3,
+ 0x818d, 0x27a2,
+ 0x818f, 0x1077,
+ 0x8193, 0x43c6,
+ 0x8195, 0x29d1,
+ 0x8197, 0x29d4,
+ 0x8198, 0x11ef,
+ 0x8199, 0x29d3,
+ 0x819a, 0x11ee,
+ 0x819b, 0x11ea,
+ 0x819e, 0x29d0,
+ 0x819f, 0x29cf,
+ 0x81a0, 0x11ed,
+ 0x81a2, 0x29d2,
+ 0x81a3, 0x29ce,
+ 0x81a5, 0x4753,
+ 0x81a6, 0x2c30,
+ 0x81a7, 0x2c3a,
+ 0x81a8, 0x1331,
+ 0x81a9, 0x1330,
+ 0x81aa, 0x4364,
+ 0x81ab, 0x2c34,
+ 0x81ac, 0x2c36,
+ 0x81ae, 0x2c31,
+ 0x81b0, 0x2c35,
+ 0x81b1, 0x2c2f,
+ 0x81b2, 0x2c38,
+ 0x81b3, 0x132f,
+ 0x81b4, 0x2c37,
+ 0x81b5, 0x2c33,
+ 0x81b6, 0x3eb2,
+ 0x81b7, 0x2c39,
+ 0x81b9, 0x2c32,
+ 0x81ba, 0x1450,
+ 0x81bb, 0x2e06,
+ 0x81bc, 0x2e0c,
+ 0x81bd, 0x1454,
+ 0x81be, 0x1456,
+ 0x81bf, 0x1453,
+ 0x81c0, 0x1452,
+ 0x81c1, 0x4755,
+ 0x81c2, 0x1451,
+ 0x81c3, 0x144f,
+ 0x81c4, 0x2e07,
+ 0x81c5, 0x2e0a,
+ 0x81c6, 0x144e,
+ 0x81c7, 0x2e0b,
+ 0x81c8, 0x3fee,
+ 0x81c9, 0x1455,
+ 0x81ca, 0x2e09,
+ 0x81cc, 0x2e08,
+ 0x81cd, 0x1518,
+ 0x81cf, 0x1519,
+ 0x81d0, 0x2f94,
+ 0x81d1, 0x2f92,
+ 0x81d5, 0x30ed,
+ 0x81d7, 0x30ec,
+ 0x81d8, 0x15b3,
+ 0x81d9, 0x321c,
+ 0x81da, 0x1635,
+ 0x81db, 0x321b,
+ 0x81dd, 0x32f5,
+ 0x81de, 0x33a5,
+ 0x81df, 0x16d4,
+ 0x81e0, 0x34dd,
+ 0x81e2, 0x1706,
+ 0x81e3, 0x0405,
+ 0x81e4, 0x4756,
+ 0x81e5, 0x0676,
+ 0x81e6, 0x2286,
+ 0x81e7, 0x107c,
+ 0x81e8, 0x1457,
+ 0x81e9, 0x2e0d,
+ 0x81ea, 0x0406,
+ 0x81ec, 0x0995,
+ 0x81ed, 0x0994,
+ 0x81ee, 0x2287,
+ 0x81ef, 0x42d1,
+ 0x81f2, 0x2c3b,
+ 0x81f3, 0x0407,
+ 0x81f4, 0x07e7,
+ 0x81f6, 0x3d61,
+ 0x81f7, 0x2288,
+ 0x81fa, 0x107d,
+ 0x81fb, 0x1332,
+ 0x81fc, 0x0408,
+ 0x81fe, 0x0677,
+ 0x81ff, 0x1bde,
+ 0x8200, 0x0996,
+ 0x8201, 0x1dbd,
+ 0x8202, 0x0b71,
+ 0x8204, 0x228b,
+ 0x8205, 0x0ed9,
+ 0x8207, 0x107e,
+ 0x8208, 0x1333,
+ 0x8209, 0x1458,
+ 0x820a, 0x151a,
+ 0x820b, 0x30ee,
+ 0x820c, 0x0409,
+ 0x820d, 0x0678,
+ 0x8210, 0x0997,
+ 0x8211, 0x2013,
+ 0x8212, 0x0d2c,
+ 0x8214, 0x107f,
+ 0x8215, 0x27a5,
+ 0x8216, 0x29d5,
+ 0x8218, 0x37aa,
+ 0x821a, 0x3fe1,
+ 0x821b, 0x040a,
+ 0x821c, 0x0d2d,
+ 0x821d, 0x2529,
+ 0x821e, 0x1080,
+ 0x821f, 0x040b,
+ 0x8220, 0x1a2e,
+ 0x8221, 0x1bdf,
+ 0x8222, 0x07e8,
+ 0x8225, 0x1dbf,
+ 0x8226, 0x420d,
+ 0x8228, 0x099a,
+ 0x8229, 0x37b0,
+ 0x822a, 0x0998,
+ 0x822c, 0x099b,
+ 0x822d, 0x3ed0,
+ 0x822f, 0x1dbe,
+ 0x8232, 0x2018,
+ 0x8233, 0x2015,
+ 0x8234, 0x2017,
+ 0x8235, 0x0b72,
+ 0x8236, 0x0b74,
+ 0x8237, 0x0b73,
+ 0x8238, 0x2014,
+ 0x8239, 0x0b75,
+ 0x823a, 0x2016,
+ 0x823c, 0x228c,
+ 0x823e, 0x4582,
+ 0x823f, 0x228e,
+ 0x8240, 0x252c,
+ 0x8242, 0x252d,
+ 0x8244, 0x252b,
+ 0x8245, 0x252e,
+ 0x8247, 0x0eda,
+ 0x8249, 0x252a,
+ 0x824b, 0x1081,
+ 0x824e, 0x29da,
+ 0x824f, 0x29d6,
+ 0x8250, 0x29d9,
+ 0x8251, 0x29db,
+ 0x8252, 0x29d8,
+ 0x8253, 0x29d7,
+ 0x8254, 0x4757,
+ 0x8255, 0x2c3c,
+ 0x8258, 0x1334,
+ 0x825a, 0x2e0f,
+ 0x825b, 0x2e0e,
+ 0x825c, 0x2e10,
+ 0x825e, 0x2f96,
+ 0x825f, 0x2f95,
+ 0x8261, 0x30f0,
+ 0x8262, 0x3b7a,
+ 0x8263, 0x30f1,
+ 0x8264, 0x30ef,
+ 0x8265, 0x3b7b,
+ 0x8266, 0x1636,
+ 0x8268, 0x321d,
+ 0x826b, 0x33a6,
+ 0x826c, 0x342d,
+ 0x826d, 0x3496,
+ 0x826e, 0x040c,
+ 0x826f, 0x0504,
+ 0x8271, 0x1459,
+ 0x8272, 0x040d,
+ 0x8274, 0x2019,
+ 0x8275, 0x228f,
+ 0x8276, 0x4759,
+ 0x8277, 0x172e,
+ 0x8278, 0x1813,
+ 0x8279, 0x4722,
+ 0x827a, 0x4563,
+ 0x827b, 0x37c8,
+ 0x827c, 0x1814,
+ 0x827d, 0x1816,
+ 0x827e, 0x040e,
+ 0x827f, 0x1817,
+ 0x8280, 0x1815,
+ 0x8283, 0x18e5,
+ 0x8285, 0x18e0,
+ 0x8287, 0x4132,
+ 0x828a, 0x18e4,
+ 0x828b, 0x0506,
+ 0x828d, 0x0507,
+ 0x828e, 0x18e1,
+ 0x828f, 0x18df,
+ 0x8290, 0x18de,
+ 0x8291, 0x18e2,
+ 0x8292, 0x0505,
+ 0x8293, 0x18e3,
+ 0x8294, 0x1be0,
+ 0x8298, 0x1a33,
+ 0x8299, 0x067b,
+ 0x829a, 0x1a32,
+ 0x829b, 0x1a34,
+ 0x829d, 0x067a,
+ 0x829e, 0x1a39,
+ 0x829f, 0x067e,
+ 0x82a0, 0x1a2f,
+ 0x82a1, 0x1a3d,
+ 0x82a2, 0x1a43,
+ 0x82a3, 0x0685,
+ 0x82a4, 0x1a40,
+ 0x82a5, 0x0682,
+ 0x82a6, 0x3d73,
+ 0x82a7, 0x1a36,
+ 0x82a8, 0x1a3c,
+ 0x82a9, 0x1a3e,
+ 0x82aa, 0x37bc,
+ 0x82ab, 0x1a31,
+ 0x82ac, 0x0681,
+ 0x82ad, 0x067c,
+ 0x82ae, 0x1a37,
+ 0x82af, 0x0683,
+ 0x82b0, 0x0686,
+ 0x82b1, 0x0680,
+ 0x82b3, 0x0679,
+ 0x82b4, 0x1a3b,
+ 0x82b5, 0x1a35,
+ 0x82b6, 0x1a42,
+ 0x82b7, 0x0688,
+ 0x82b8, 0x0684,
+ 0x82b9, 0x067f,
+ 0x82ba, 0x1a3a,
+ 0x82bb, 0x099c,
+ 0x82bc, 0x1a38,
+ 0x82bd, 0x067d,
+ 0x82be, 0x0687,
+ 0x82c0, 0x1a30,
+ 0x82c2, 0x1a3f,
+ 0x82c3, 0x1a41,
+ 0x82c4, 0x45e3,
+ 0x82ca, 0x475a,
+ 0x82cf, 0x4564,
+ 0x82d0, 0x37c1,
+ 0x82d1, 0x07f9,
+ 0x82d2, 0x07f3,
+ 0x82d3, 0x07fb,
+ 0x82d4, 0x07f8,
+ 0x82d5, 0x1be7,
+ 0x82d6, 0x1bea,
+ 0x82d7, 0x07f4,
+ 0x82d8, 0x475b,
+ 0x82d9, 0x1be1,
+ 0x82db, 0x07ed,
+ 0x82dc, 0x07f7,
+ 0x82de, 0x07fa,
+ 0x82df, 0x07fc,
+ 0x82e0, 0x1bf6,
+ 0x82e1, 0x1bed,
+ 0x82e2, 0x37c9,
+ 0x82e3, 0x07ec,
+ 0x82e4, 0x1bf5,
+ 0x82e5, 0x07f0,
+ 0x82e6, 0x07ee,
+ 0x82e7, 0x07e9,
+ 0x82e8, 0x1be5,
+ 0x82ea, 0x1bf4,
+ 0x82eb, 0x1be9,
+ 0x82ec, 0x1bec,
+ 0x82ed, 0x1bf9,
+ 0x82ee, 0x4018,
+ 0x82ef, 0x07fd,
+ 0x82f0, 0x1bf3,
+ 0x82f1, 0x07f5,
+ 0x82f2, 0x1bee,
+ 0x82f3, 0x1bf8,
+ 0x82f4, 0x1beb,
+ 0x82f5, 0x1bef,
+ 0x82f6, 0x1bf2,
+ 0x82f7, 0x3e77,
+ 0x82f9, 0x1be3,
+ 0x82fa, 0x1bf7,
+ 0x82fb, 0x1bf1,
+ 0x82fc, 0x412d,
+ 0x82fd, 0x3d92,
+ 0x82fe, 0x1be2,
+ 0x82ff, 0x43de,
+ 0x8300, 0x1be6,
+ 0x8301, 0x07f6,
+ 0x8302, 0x07f1,
+ 0x8303, 0x07ea,
+ 0x8304, 0x07ef,
+ 0x8305, 0x07eb,
+ 0x8306, 0x07fe,
+ 0x8307, 0x1be4,
+ 0x8308, 0x1dd0,
+ 0x8309, 0x07f2,
+ 0x830b, 0x3eb6,
+ 0x830c, 0x1bf0,
+ 0x830d, 0x1a7d,
+ 0x8316, 0x1dd3,
+ 0x8317, 0x09aa,
+ 0x8318, 0x37ca,
+ 0x8319, 0x1dc3,
+ 0x831a, 0x37c2,
+ 0x831b, 0x1dce,
+ 0x831c, 0x1dca,
+ 0x831d, 0x37d1,
+ 0x831e, 0x1ddd,
+ 0x8320, 0x1dd5,
+ 0x8322, 0x1dcb,
+ 0x8324, 0x1dd4,
+ 0x8325, 0x1dc5,
+ 0x8326, 0x1dc9,
+ 0x8327, 0x1de0,
+ 0x8328, 0x09ad,
+ 0x8329, 0x1dd8,
+ 0x832a, 0x1dcf,
+ 0x832b, 0x099d,
+ 0x832c, 0x1dde,
+ 0x832d, 0x1dc1,
+ 0x832f, 0x1dd7,
+ 0x8331, 0x09ac,
+ 0x8332, 0x09a7,
+ 0x8333, 0x1dc0,
+ 0x8334, 0x09a5,
+ 0x8335, 0x09a4,
+ 0x8336, 0x09a9,
+ 0x8337, 0x1dd6,
+ 0x8338, 0x09a1,
+ 0x8339, 0x09a8,
+ 0x833a, 0x1be8,
+ 0x833b, 0x2290,
+ 0x833c, 0x1dd1,
+ 0x833d, 0x3d2a,
+ 0x833f, 0x1dc7,
+ 0x8340, 0x09ab,
+ 0x8341, 0x1dc8,
+ 0x8342, 0x1dcc,
+ 0x8343, 0x09ae,
+ 0x8344, 0x1dc2,
+ 0x8345, 0x1dda,
+ 0x8347, 0x1dd9,
+ 0x8348, 0x1de1,
+ 0x8349, 0x09a3,
+ 0x834a, 0x09a0,
+ 0x834b, 0x1ddf,
+ 0x834c, 0x1ddb,
+ 0x834d, 0x1dd2,
+ 0x834e, 0x1dcd,
+ 0x834f, 0x09a6,
+ 0x8350, 0x09a2,
+ 0x8351, 0x1dc4,
+ 0x8352, 0x099e,
+ 0x8353, 0x1ddc,
+ 0x8354, 0x099f,
+ 0x8356, 0x1dc6,
+ 0x8357, 0x475d,
+ 0x8362, 0x37b6,
+ 0x8363, 0x41eb,
+ 0x8366, 0x3e1e,
+ 0x836f, 0x4565,
+ 0x8373, 0x201f,
+ 0x8374, 0x2021,
+ 0x8375, 0x2026,
+ 0x8376, 0x203a,
+ 0x8377, 0x0b83,
+ 0x8378, 0x0b79,
+ 0x837a, 0x201e,
+ 0x837b, 0x0b84,
+ 0x837d, 0x2029,
+ 0x837e, 0x2030,
+ 0x837f, 0x2036,
+ 0x8381, 0x2023,
+ 0x8383, 0x202a,
+ 0x8385, 0x37d3,
+ 0x8386, 0x0b86,
+ 0x8387, 0x2038,
+ 0x8388, 0x2033,
+ 0x8389, 0x0b81,
+ 0x838a, 0x0b7f,
+ 0x838b, 0x202f,
+ 0x838c, 0x202b,
+ 0x838d, 0x201d,
+ 0x838e, 0x0b76,
+ 0x838f, 0x2022,
+ 0x8390, 0x201a,
+ 0x8391, 0x37ec,
+ 0x8392, 0x0b7e,
+ 0x8393, 0x0b80,
+ 0x8394, 0x2027,
+ 0x8395, 0x2024,
+ 0x8396, 0x0b7b,
+ 0x8397, 0x2034,
+ 0x8398, 0x0b78,
+ 0x8399, 0x2025,
+ 0x839a, 0x22b9,
+ 0x839b, 0x202d,
+ 0x839c, 0x374d,
+ 0x839d, 0x202c,
+ 0x839e, 0x0b77,
+ 0x83a0, 0x0b82,
+ 0x83a2, 0x0b7a,
+ 0x83a3, 0x201b,
+ 0x83a4, 0x2020,
+ 0x83a5, 0x2031,
+ 0x83a6, 0x2037,
+ 0x83a7, 0x0b87,
+ 0x83a8, 0x201c,
+ 0x83a9, 0x2028,
+ 0x83aa, 0x202e,
+ 0x83ab, 0x0b7d,
+ 0x83ac, 0x37d6,
+ 0x83ae, 0x2039,
+ 0x83af, 0x2032,
+ 0x83b0, 0x2035,
+ 0x83b9, 0x42a7,
+ 0x83bd, 0x0b7c,
+ 0x83be, 0x3f59,
+ 0x83bf, 0x22a0,
+ 0x83c0, 0x2294,
+ 0x83c1, 0x0d35,
+ 0x83c2, 0x22b1,
+ 0x83c3, 0x22ba,
+ 0x83c4, 0x22bd,
+ 0x83c5, 0x0d33,
+ 0x83c6, 0x229c,
+ 0x83c7, 0x22b5,
+ 0x83c8, 0x229d,
+ 0x83c9, 0x22ab,
+ 0x83ca, 0x0d40,
+ 0x83cb, 0x22a7,
+ 0x83cc, 0x0d3d,
+ 0x83cd, 0x4055,
+ 0x83ce, 0x22a8,
+ 0x83cf, 0x2291,
+ 0x83d1, 0x22b6,
+ 0x83d3, 0x37d8,
+ 0x83d4, 0x0d46,
+ 0x83d5, 0x22b3,
+ 0x83d6, 0x22a9,
+ 0x83d7, 0x22bf,
+ 0x83d8, 0x22a4,
+ 0x83d9, 0x254e,
+ 0x83db, 0x22c2,
+ 0x83dc, 0x0d44,
+ 0x83dd, 0x22a2,
+ 0x83de, 0x22ae,
+ 0x83df, 0x0d47,
+ 0x83e0, 0x0d32,
+ 0x83e1, 0x22a6,
+ 0x83e2, 0x22c0,
+ 0x83e3, 0x229f,
+ 0x83e4, 0x2298,
+ 0x83e5, 0x22a3,
+ 0x83e7, 0x2297,
+ 0x83e8, 0x2295,
+ 0x83e9, 0x0d2e,
+ 0x83ea, 0x22b7,
+ 0x83eb, 0x229e,
+ 0x83ec, 0x22bb,
+ 0x83ed, 0x3d2c,
+ 0x83ee, 0x22bc,
+ 0x83ef, 0x0d36,
+ 0x83f0, 0x0d3b,
+ 0x83f1, 0x0d37,
+ 0x83f2, 0x0d3f,
+ 0x83f3, 0x22b2,
+ 0x83f4, 0x0d38,
+ 0x83f5, 0x22aa,
+ 0x83f6, 0x229a,
+ 0x83f8, 0x0d30,
+ 0x83f9, 0x2292,
+ 0x83fa, 0x22b4,
+ 0x83fb, 0x22be,
+ 0x83fc, 0x2299,
+ 0x83fd, 0x0d3e,
+ 0x83fe, 0x22c3,
+ 0x83ff, 0x22a5,
+ 0x8401, 0x22a1,
+ 0x8403, 0x0d2f,
+ 0x8404, 0x0d43,
+ 0x8405, 0x475f,
+ 0x8406, 0x22b0,
+ 0x8407, 0x0d45,
+ 0x8409, 0x22ac,
+ 0x840a, 0x0d3a,
+ 0x840b, 0x0d34,
+ 0x840c, 0x0d3c,
+ 0x840d, 0x0d31,
+ 0x840e, 0x0d42,
+ 0x840f, 0x22ad,
+ 0x8410, 0x229b,
+ 0x8411, 0x22af,
+ 0x8412, 0x2296,
+ 0x8413, 0x22b8,
+ 0x8414, 0x3c10,
+ 0x8416, 0x4037,
+ 0x8418, 0x3e7a,
+ 0x841b, 0x22c1,
+ 0x841c, 0x3eb3,
+ 0x8420, 0x3c55,
+ 0x8421, 0x3751,
+ 0x8423, 0x2293,
+ 0x8424, 0x4951,
+ 0x8426, 0x46d8,
+ 0x8429, 0x254d,
+ 0x842b, 0x2563,
+ 0x842c, 0x0eac,
+ 0x842d, 0x2552,
+ 0x842e, 0x422d,
+ 0x842f, 0x2550,
+ 0x8430, 0x253b,
+ 0x8431, 0x0ede,
+ 0x8432, 0x254b,
+ 0x8433, 0x255f,
+ 0x8434, 0x2547,
+ 0x8435, 0x0ee6,
+ 0x8436, 0x255e,
+ 0x8437, 0x2545,
+ 0x8438, 0x0d41,
+ 0x8439, 0x2555,
+ 0x843a, 0x2546,
+ 0x843b, 0x255c,
+ 0x843c, 0x0ee5,
+ 0x843d, 0x0edd,
+ 0x843e, 0x3d21,
+ 0x843f, 0x2530,
+ 0x8440, 0x2538,
+ 0x8442, 0x2551,
+ 0x8443, 0x2549,
+ 0x8444, 0x2562,
+ 0x8445, 0x254c,
+ 0x8446, 0x0eeb,
+ 0x8447, 0x255d,
+ 0x8448, 0x4718,
+ 0x8449, 0x0ee2,
+ 0x844a, 0x37e4,
+ 0x844b, 0x254f,
+ 0x844c, 0x2557,
+ 0x844d, 0x253c,
+ 0x844e, 0x2556,
+ 0x8450, 0x2567,
+ 0x8451, 0x2537,
+ 0x8452, 0x2558,
+ 0x8453, 0x3b7d,
+ 0x8454, 0x2565,
+ 0x8455, 0x398b,
+ 0x8456, 0x2531,
+ 0x8457, 0x0d39,
+ 0x8458, 0x37de,
+ 0x8459, 0x253f,
+ 0x845a, 0x253e,
+ 0x845b, 0x0ee4,
+ 0x845c, 0x3edb,
+ 0x845d, 0x2542,
+ 0x845e, 0x2544,
+ 0x845f, 0x2553,
+ 0x8460, 0x2564,
+ 0x8461, 0x0ee7,
+ 0x8462, 0x42da,
+ 0x8463, 0x0ee8,
+ 0x8464, 0x4761,
+ 0x8465, 0x2536,
+ 0x8466, 0x0ee0,
+ 0x8467, 0x253a,
+ 0x8468, 0x2560,
+ 0x8469, 0x0ee9,
+ 0x846b, 0x0ee1,
+ 0x846c, 0x0ee3,
+ 0x846d, 0x0eea,
+ 0x846e, 0x2566,
+ 0x846f, 0x2559,
+ 0x8470, 0x2554,
+ 0x8471, 0x37e0,
+ 0x8472, 0x3c93,
+ 0x8473, 0x2541,
+ 0x8474, 0x2540,
+ 0x8475, 0x0edf,
+ 0x8476, 0x2532,
+ 0x8477, 0x0edc,
+ 0x8478, 0x254a,
+ 0x8479, 0x2533,
+ 0x847a, 0x2548,
+ 0x847d, 0x253d,
+ 0x847e, 0x2561,
+ 0x847f, 0x394e,
+ 0x8480, 0x3b6e,
+ 0x8482, 0x0edb,
+ 0x8486, 0x2539,
+ 0x8488, 0x4762,
+ 0x848d, 0x2535,
+ 0x848e, 0x255b,
+ 0x848f, 0x2534,
+ 0x8490, 0x108e,
+ 0x8491, 0x27cd,
+ 0x8492, 0x3756,
+ 0x8493, 0x37ee,
+ 0x8494, 0x27bc,
+ 0x8496, 0x3b1d,
+ 0x8497, 0x27a6,
+ 0x8498, 0x27c4,
+ 0x8499, 0x1086,
+ 0x849a, 0x27b5,
+ 0x849b, 0x27bf,
+ 0x849c, 0x1089,
+ 0x849d, 0x27b8,
+ 0x849e, 0x1087,
+ 0x849f, 0x27a9,
+ 0x84a0, 0x27c7,
+ 0x84a1, 0x27a8,
+ 0x84a2, 0x27bb,
+ 0x84a3, 0x3b9e,
+ 0x84a4, 0x27a7,
+ 0x84a7, 0x27b9,
+ 0x84a8, 0x27c2,
+ 0x84a9, 0x27c0,
+ 0x84aa, 0x27b4,
+ 0x84ab, 0x27af,
+ 0x84ac, 0x27ad,
+ 0x84ad, 0x3d8c,
+ 0x84ae, 0x27ae,
+ 0x84af, 0x27c1,
+ 0x84b0, 0x27cc,
+ 0x84b1, 0x27b6,
+ 0x84b2, 0x1088,
+ 0x84b4, 0x27b1,
+ 0x84b6, 0x27c5,
+ 0x84b8, 0x108b,
+ 0x84b9, 0x27b0,
+ 0x84ba, 0x27aa,
+ 0x84bb, 0x27ba,
+ 0x84bc, 0x108f,
+ 0x84bd, 0x3c4c,
+ 0x84be, 0x4764,
+ 0x84bf, 0x1083,
+ 0x84c0, 0x108c,
+ 0x84c1, 0x27b2,
+ 0x84c2, 0x27ac,
+ 0x84c4, 0x1085,
+ 0x84c5, 0x255a,
+ 0x84c6, 0x1084,
+ 0x84c7, 0x27bd,
+ 0x84c9, 0x1082,
+ 0x84ca, 0x1091,
+ 0x84cb, 0x108a,
+ 0x84cc, 0x27be,
+ 0x84cd, 0x27b3,
+ 0x84ce, 0x27ab,
+ 0x84cf, 0x27c6,
+ 0x84d0, 0x27b7,
+ 0x84d1, 0x1090,
+ 0x84d2, 0x27ca,
+ 0x84d3, 0x108d,
+ 0x84d4, 0x27c9,
+ 0x84d6, 0x27c3,
+ 0x84d7, 0x27c8,
+ 0x84da, 0x3ff5,
+ 0x84db, 0x27cb,
+ 0x84de, 0x37ea,
+ 0x84e1, 0x4765,
+ 0x84e2, 0x37b5,
+ 0x84e4, 0x37ef,
+ 0x84e5, 0x3bd0,
+ 0x84e7, 0x2a03,
+ 0x84e9, 0x29f7,
+ 0x84ea, 0x29f6,
+ 0x84eb, 0x29f2,
+ 0x84ec, 0x11fb,
+ 0x84ee, 0x11f3,
+ 0x84ef, 0x2a06,
+ 0x84f0, 0x2a05,
+ 0x84f1, 0x252f,
+ 0x84f2, 0x29ef,
+ 0x84f3, 0x29f3,
+ 0x84f4, 0x29ed,
+ 0x84f6, 0x2a00,
+ 0x84f7, 0x29f1,
+ 0x84f8, 0x4766,
+ 0x84f9, 0x2a07,
+ 0x84fa, 0x29ea,
+ 0x84fb, 0x29e8,
+ 0x84fc, 0x29f4,
+ 0x84fd, 0x29fe,
+ 0x84fe, 0x29f9,
+ 0x84ff, 0x11fd,
+ 0x8500, 0x29df,
+ 0x8502, 0x29fd,
+ 0x8503, 0x398a,
+ 0x8505, 0x40eb,
+ 0x8506, 0x11fe,
+ 0x8507, 0x2543,
+ 0x8508, 0x29eb,
+ 0x8509, 0x29e2,
+ 0x850a, 0x29e5,
+ 0x850b, 0x2a0b,
+ 0x850c, 0x29ec,
+ 0x850d, 0x29e3,
+ 0x850e, 0x29e1,
+ 0x850f, 0x29de,
+ 0x8510, 0x4767,
+ 0x8511, 0x11f7,
+ 0x8512, 0x29f5,
+ 0x8513, 0x11f6,
+ 0x8514, 0x11fa,
+ 0x8515, 0x29f0,
+ 0x8516, 0x29f8,
+ 0x8517, 0x11f0,
+ 0x8518, 0x2a08,
+ 0x8519, 0x2a0c,
+ 0x851a, 0x11f2,
+ 0x851c, 0x29e7,
+ 0x851d, 0x29fb,
+ 0x851e, 0x29ff,
+ 0x851f, 0x29e4,
+ 0x8520, 0x2a09,
+ 0x8521, 0x11f9,
+ 0x8523, 0x11f8,
+ 0x8524, 0x29dc,
+ 0x8525, 0x11fc,
+ 0x8526, 0x2a02,
+ 0x8527, 0x29e6,
+ 0x8528, 0x29fa,
+ 0x8529, 0x29e0,
+ 0x852a, 0x29ee,
+ 0x852b, 0x29e9,
+ 0x852c, 0x11f4,
+ 0x852e, 0x29fc,
+ 0x852f, 0x2a0d,
+ 0x8530, 0x2a0a,
+ 0x8531, 0x2a01,
+ 0x8533, 0x4228,
+ 0x8534, 0x37f4,
+ 0x8538, 0x4768,
+ 0x853b, 0x29dd,
+ 0x853d, 0x11f1,
+ 0x853e, 0x2c4f,
+ 0x8540, 0x2c46,
+ 0x8541, 0x2c49,
+ 0x8542, 0x4062,
+ 0x8543, 0x133b,
+ 0x8544, 0x2c4b,
+ 0x8545, 0x2c40,
+ 0x8546, 0x2c47,
+ 0x8547, 0x2c4d,
+ 0x8548, 0x1338,
+ 0x8549, 0x133c,
+ 0x854a, 0x1336,
+ 0x854b, 0x37c0,
+ 0x854c, 0x400f,
+ 0x854d, 0x2c42,
+ 0x854e, 0x2c52,
+ 0x8551, 0x2c4c,
+ 0x8552, 0x4769,
+ 0x8553, 0x2c43,
+ 0x8554, 0x2c5b,
+ 0x8555, 0x2c55,
+ 0x8556, 0x2c3f,
+ 0x8557, 0x2e23,
+ 0x8558, 0x2c45,
+ 0x8559, 0x1337,
+ 0x855a, 0x37db,
+ 0x855b, 0x2c50,
+ 0x855d, 0x2c5a,
+ 0x855e, 0x133f,
+ 0x8560, 0x2c57,
+ 0x8561, 0x2c44,
+ 0x8562, 0x2c4a,
+ 0x8563, 0x2c4e,
+ 0x8564, 0x2c48,
+ 0x8565, 0x2c5c,
+ 0x8566, 0x2c59,
+ 0x8567, 0x2c56,
+ 0x8568, 0x1339,
+ 0x856a, 0x133e,
+ 0x856b, 0x2c41,
+ 0x856c, 0x2c5d,
+ 0x856d, 0x133d,
+ 0x856e, 0x2c53,
+ 0x856f, 0x476b,
+ 0x8571, 0x2c51,
+ 0x8573, 0x37f8,
+ 0x8575, 0x2c54,
+ 0x8576, 0x2e30,
+ 0x8577, 0x2e1d,
+ 0x8578, 0x2e22,
+ 0x8579, 0x2e2f,
+ 0x857a, 0x2e21,
+ 0x857b, 0x2e19,
+ 0x857c, 0x2e1e,
+ 0x857e, 0x145c,
+ 0x8580, 0x2e12,
+ 0x8581, 0x2e2a,
+ 0x8582, 0x2e2c,
+ 0x8583, 0x2e11,
+ 0x8584, 0x145b,
+ 0x8585, 0x2e2e,
+ 0x8586, 0x2e26,
+ 0x8587, 0x1462,
+ 0x8588, 0x2e2d,
+ 0x8589, 0x2e1f,
+ 0x858a, 0x1464,
+ 0x858b, 0x2e17,
+ 0x858c, 0x2c58,
+ 0x858d, 0x2e27,
+ 0x858e, 0x2e24,
+ 0x858f, 0x2e13,
+ 0x8590, 0x2e32,
+ 0x8591, 0x145e,
+ 0x8594, 0x145f,
+ 0x8595, 0x2e15,
+ 0x8596, 0x2e25,
+ 0x8598, 0x2e31,
+ 0x8599, 0x2e28,
+ 0x859a, 0x2e1b,
+ 0x859b, 0x1461,
+ 0x859c, 0x145d,
+ 0x859d, 0x2e29,
+ 0x859e, 0x2e1c,
+ 0x859f, 0x2e33,
+ 0x85a0, 0x2e16,
+ 0x85a1, 0x2e20,
+ 0x85a2, 0x2e2b,
+ 0x85a3, 0x2e18,
+ 0x85a4, 0x2e1a,
+ 0x85a6, 0x1465,
+ 0x85a7, 0x2e14,
+ 0x85a8, 0x1463,
+ 0x85a9, 0x151c,
+ 0x85aa, 0x145a,
+ 0x85af, 0x1460,
+ 0x85b0, 0x1520,
+ 0x85b1, 0x2fa6,
+ 0x85b3, 0x2f9c,
+ 0x85b4, 0x2f97,
+ 0x85b5, 0x2f9d,
+ 0x85b6, 0x2fa7,
+ 0x85b7, 0x2fab,
+ 0x85b8, 0x2faa,
+ 0x85b9, 0x1522,
+ 0x85ba, 0x1521,
+ 0x85bd, 0x2f9e,
+ 0x85be, 0x2fac,
+ 0x85bf, 0x2fa1,
+ 0x85c0, 0x2f99,
+ 0x85c1, 0x37fe,
+ 0x85c2, 0x2f9b,
+ 0x85c3, 0x2f9a,
+ 0x85c4, 0x2fa0,
+ 0x85c5, 0x2fa5,
+ 0x85c6, 0x2f98,
+ 0x85c7, 0x2f9f,
+ 0x85c8, 0x2fa4,
+ 0x85c9, 0x151f,
+ 0x85cb, 0x2fa2,
+ 0x85cd, 0x151d,
+ 0x85ce, 0x2fa3,
+ 0x85cf, 0x151b,
+ 0x85d0, 0x151e,
+ 0x85d1, 0x3101,
+ 0x85d2, 0x2fa8,
+ 0x85d5, 0x15b7,
+ 0x85d7, 0x30f9,
+ 0x85d8, 0x30fd,
+ 0x85d9, 0x30f5,
+ 0x85da, 0x30f8,
+ 0x85dc, 0x3100,
+ 0x85dd, 0x15b5,
+ 0x85de, 0x3105,
+ 0x85df, 0x30fe,
+ 0x85e0, 0x476d,
+ 0x85e1, 0x30f6,
+ 0x85e2, 0x3106,
+ 0x85e3, 0x30ff,
+ 0x85e4, 0x15b8,
+ 0x85e6, 0x3103,
+ 0x85e8, 0x30f7,
+ 0x85e9, 0x15b4,
+ 0x85ea, 0x15b6,
+ 0x85eb, 0x30f2,
+ 0x85ec, 0x30fa,
+ 0x85ed, 0x30f4,
+ 0x85ee, 0x3c56,
+ 0x85ef, 0x3104,
+ 0x85f0, 0x3102,
+ 0x85f1, 0x30f3,
+ 0x85f2, 0x30fb,
+ 0x85f6, 0x3225,
+ 0x85f7, 0x15ba,
+ 0x85f8, 0x30fc,
+ 0x85f9, 0x1638,
+ 0x85fa, 0x163a,
+ 0x85fb, 0x1637,
+ 0x85fc, 0x3c50,
+ 0x85fd, 0x322a,
+ 0x85fe, 0x3222,
+ 0x85ff, 0x3220,
+ 0x8600, 0x3224,
+ 0x8601, 0x3221,
+ 0x8602, 0x3800,
+ 0x8604, 0x3226,
+ 0x8605, 0x3228,
+ 0x8606, 0x163b,
+ 0x8607, 0x163d,
+ 0x8609, 0x3227,
+ 0x860a, 0x163e,
+ 0x860b, 0x163c,
+ 0x860c, 0x3229,
+ 0x860d, 0x4064,
+ 0x8610, 0x3b7f,
+ 0x8611, 0x1639,
+ 0x8614, 0x46be,
+ 0x8616, 0x37fb,
+ 0x8617, 0x1685,
+ 0x8618, 0x32f6,
+ 0x8619, 0x32fc,
+ 0x861a, 0x1687,
+ 0x861b, 0x3223,
+ 0x861c, 0x32fb,
+ 0x861e, 0x3302,
+ 0x861f, 0x32f9,
+ 0x8620, 0x3300,
+ 0x8621, 0x32ff,
+ 0x8622, 0x321f,
+ 0x8623, 0x32fa,
+ 0x8624, 0x2fa9,
+ 0x8625, 0x3303,
+ 0x8626, 0x32f8,
+ 0x8627, 0x32fd,
+ 0x8628, 0x3805,
+ 0x8629, 0x3301,
+ 0x862a, 0x32f7,
+ 0x862c, 0x33aa,
+ 0x862d, 0x1686,
+ 0x862e, 0x32fe,
+ 0x862f, 0x3f9e,
+ 0x8631, 0x3432,
+ 0x8632, 0x33ab,
+ 0x8633, 0x33a9,
+ 0x8634, 0x33a7,
+ 0x8636, 0x33ac,
+ 0x8638, 0x1707,
+ 0x8639, 0x3430,
+ 0x863a, 0x342e,
+ 0x863b, 0x3433,
+ 0x863c, 0x3431,
+ 0x863e, 0x3434,
+ 0x863f, 0x1708,
+ 0x8640, 0x342f,
+ 0x8642, 0x38c1,
+ 0x8643, 0x3497,
+ 0x8645, 0x3b66,
+ 0x8646, 0x34df,
+ 0x864b, 0x353e,
+ 0x864c, 0x3536,
+ 0x864d, 0x1818,
+ 0x864e, 0x0689,
+ 0x8650, 0x07ff,
+ 0x8652, 0x1de3,
+ 0x8653, 0x1de2,
+ 0x8654, 0x09af,
+ 0x8655, 0x0b88,
+ 0x8656, 0x203c,
+ 0x8659, 0x203b,
+ 0x865b, 0x0d48,
+ 0x865c, 0x0eed,
+ 0x865e, 0x0eec,
+ 0x865f, 0x0eee,
+ 0x8661, 0x27ce,
+ 0x8662, 0x2a0e,
+ 0x8663, 0x2c5e,
+ 0x8664, 0x2c60,
+ 0x8665, 0x2c5f,
+ 0x8667, 0x1466,
+ 0x8668, 0x2e34,
+ 0x8669, 0x2fad,
+ 0x866a, 0x351e,
+ 0x866b, 0x040f,
+ 0x866c, 0x3813,
+ 0x866d, 0x1a46,
+ 0x866f, 0x1a45,
+ 0x8670, 0x1a44,
+ 0x8671, 0x068a,
+ 0x8672, 0x476f,
+ 0x8673, 0x1bfd,
+ 0x8674, 0x1bfb,
+ 0x8677, 0x1bfa,
+ 0x8679, 0x0800,
+ 0x867a, 0x0802,
+ 0x867b, 0x0801,
+ 0x867c, 0x1bfc,
+ 0x867e, 0x380a,
+ 0x8685, 0x1def,
+ 0x8686, 0x1dec,
+ 0x8687, 0x1dea,
+ 0x868a, 0x09b0,
+ 0x868b, 0x1ded,
+ 0x868c, 0x09b5,
+ 0x868d, 0x1de7,
+ 0x868e, 0x1df6,
+ 0x8690, 0x1df8,
+ 0x8691, 0x1de8,
+ 0x8692, 0x4770,
+ 0x8693, 0x09b2,
+ 0x8694, 0x1df9,
+ 0x8695, 0x1df4,
+ 0x8696, 0x1de6,
+ 0x8697, 0x1deb,
+ 0x8698, 0x1df5,
+ 0x8699, 0x1df1,
+ 0x869a, 0x1dee,
+ 0x869c, 0x09b7,
+ 0x869d, 0x1df7,
+ 0x869e, 0x1de9,
+ 0x86a0, 0x3b88,
+ 0x86a1, 0x1df2,
+ 0x86a2, 0x1de4,
+ 0x86a3, 0x09b6,
+ 0x86a4, 0x09b3,
+ 0x86a5, 0x1df0,
+ 0x86a7, 0x1df3,
+ 0x86a8, 0x1de5,
+ 0x86a9, 0x09b4,
+ 0x86aa, 0x09b1,
+ 0x86ad, 0x3f06,
+ 0x86af, 0x0b92,
+ 0x86b0, 0x2043,
+ 0x86b1, 0x0b91,
+ 0x86b2, 0x43e0,
+ 0x86b3, 0x2046,
+ 0x86b4, 0x2049,
+ 0x86b5, 0x0b8e,
+ 0x86b6, 0x0b8c,
+ 0x86b7, 0x203e,
+ 0x86b8, 0x2047,
+ 0x86b9, 0x2045,
+ 0x86ba, 0x2042,
+ 0x86bb, 0x204a,
+ 0x86bd, 0x204d,
+ 0x86bf, 0x203d,
+ 0x86c0, 0x0b8b,
+ 0x86c1, 0x2040,
+ 0x86c2, 0x203f,
+ 0x86c3, 0x204c,
+ 0x86c4, 0x0b8d,
+ 0x86c5, 0x2041,
+ 0x86c6, 0x0b8f,
+ 0x86c7, 0x0b8a,
+ 0x86c8, 0x2044,
+ 0x86c9, 0x0b93,
+ 0x86cb, 0x0b90,
+ 0x86cc, 0x2048,
+ 0x86d0, 0x0d4f,
+ 0x86d1, 0x22d2,
+ 0x86d3, 0x22c7,
+ 0x86d4, 0x0d4c,
+ 0x86d6, 0x256d,
+ 0x86d7, 0x22d0,
+ 0x86d8, 0x22c4,
+ 0x86d9, 0x0d4a,
+ 0x86da, 0x22c9,
+ 0x86db, 0x0d4d,
+ 0x86dc, 0x22cd,
+ 0x86dd, 0x22cb,
+ 0x86de, 0x0d50,
+ 0x86df, 0x0d49,
+ 0x86e2, 0x22c5,
+ 0x86e3, 0x22c8,
+ 0x86e4, 0x0d4e,
+ 0x86e6, 0x22c6,
+ 0x86e8, 0x22d1,
+ 0x86e9, 0x22cf,
+ 0x86ea, 0x22ca,
+ 0x86eb, 0x22cc,
+ 0x86ec, 0x22ce,
+ 0x86ed, 0x0d4b,
+ 0x86ef, 0x4771,
+ 0x86f5, 0x256e,
+ 0x86f6, 0x2574,
+ 0x86f7, 0x256a,
+ 0x86f8, 0x2570,
+ 0x86f9, 0x0eef,
+ 0x86fa, 0x256c,
+ 0x86fb, 0x0ef5,
+ 0x86fe, 0x0ef4,
+ 0x8700, 0x0ef3,
+ 0x8701, 0x2573,
+ 0x8702, 0x0ef6,
+ 0x8704, 0x2569,
+ 0x8705, 0x2576,
+ 0x8706, 0x0ef8,
+ 0x8707, 0x0ef2,
+ 0x8708, 0x0ef1,
+ 0x8709, 0x2572,
+ 0x870a, 0x0ef9,
+ 0x870b, 0x2568,
+ 0x870c, 0x256b,
+ 0x870d, 0x2575,
+ 0x870e, 0x2571,
+ 0x8711, 0x27ee,
+ 0x8712, 0x27e3,
+ 0x8713, 0x0ef0,
+ 0x8718, 0x1098,
+ 0x8719, 0x27d7,
+ 0x871a, 0x27ec,
+ 0x871b, 0x27d8,
+ 0x871c, 0x1093,
+ 0x871e, 0x27d5,
+ 0x8720, 0x27de,
+ 0x8721, 0x27d6,
+ 0x8722, 0x1095,
+ 0x8723, 0x27d0,
+ 0x8724, 0x27eb,
+ 0x8725, 0x1096,
+ 0x8726, 0x27e8,
+ 0x8728, 0x27d1,
+ 0x8729, 0x109b,
+ 0x872a, 0x27e0,
+ 0x872c, 0x27da,
+ 0x872d, 0x27e1,
+ 0x872e, 0x27d4,
+ 0x8730, 0x27ed,
+ 0x8731, 0x27e5,
+ 0x8732, 0x27df,
+ 0x8733, 0x27cf,
+ 0x8734, 0x1097,
+ 0x8735, 0x27e6,
+ 0x8737, 0x109a,
+ 0x8738, 0x27ea,
+ 0x873a, 0x27e4,
+ 0x873b, 0x1094,
+ 0x873c, 0x27e2,
+ 0x873e, 0x27dc,
+ 0x873f, 0x1092,
+ 0x8740, 0x27d3,
+ 0x8741, 0x27db,
+ 0x8742, 0x27e7,
+ 0x8743, 0x27d9,
+ 0x8746, 0x27dd,
+ 0x874c, 0x1208,
+ 0x874d, 0x256f,
+ 0x874e, 0x2a20,
+ 0x874f, 0x2a29,
+ 0x8750, 0x2a1f,
+ 0x8751, 0x2a1b,
+ 0x8752, 0x2a18,
+ 0x8753, 0x1209,
+ 0x8754, 0x2a16,
+ 0x8755, 0x1099,
+ 0x8756, 0x2a0f,
+ 0x8757, 0x1207,
+ 0x8758, 0x2a15,
+ 0x8759, 0x1206,
+ 0x875a, 0x2a1a,
+ 0x875b, 0x2a17,
+ 0x875c, 0x2a27,
+ 0x875d, 0x2a22,
+ 0x875e, 0x2a1c,
+ 0x875f, 0x2a21,
+ 0x8760, 0x1202,
+ 0x8761, 0x2a19,
+ 0x8762, 0x2a2c,
+ 0x8763, 0x2a10,
+ 0x8765, 0x2a28,
+ 0x8766, 0x1203,
+ 0x8767, 0x2a2d,
+ 0x8768, 0x1205,
+ 0x8769, 0x2a2e,
+ 0x876a, 0x2a1e,
+ 0x876b, 0x27d2,
+ 0x876c, 0x2a24,
+ 0x876d, 0x2a1d,
+ 0x876e, 0x2a26,
+ 0x876f, 0x2a23,
+ 0x8770, 0x3e6c,
+ 0x8771, 0x380b,
+ 0x8773, 0x2a14,
+ 0x8774, 0x1200,
+ 0x8775, 0x2a2b,
+ 0x8776, 0x1201,
+ 0x8777, 0x2a12,
+ 0x8778, 0x1204,
+ 0x8779, 0x2c6b,
+ 0x877a, 0x2a25,
+ 0x877b, 0x2a2a,
+ 0x877d, 0x4045,
+ 0x8781, 0x2c68,
+ 0x8782, 0x11ff,
+ 0x8783, 0x1340,
+ 0x8784, 0x2c72,
+ 0x8785, 0x2c6e,
+ 0x8786, 0x3eb0,
+ 0x8787, 0x2c6c,
+ 0x8788, 0x2c67,
+ 0x8789, 0x2c76,
+ 0x878b, 0x43e2,
+ 0x878c, 0x3fef,
+ 0x878d, 0x1344,
+ 0x878f, 0x2c63,
+ 0x8790, 0x2c6f,
+ 0x8792, 0x2c66,
+ 0x8793, 0x2c65,
+ 0x8794, 0x2c73,
+ 0x8796, 0x2c69,
+ 0x8797, 0x2c64,
+ 0x8798, 0x2c6a,
+ 0x879a, 0x2c75,
+ 0x879b, 0x2c62,
+ 0x879c, 0x2c74,
+ 0x879d, 0x2c71,
+ 0x879e, 0x1342,
+ 0x879f, 0x1341,
+ 0x87a2, 0x1343,
+ 0x87a3, 0x2c6d,
+ 0x87a4, 0x2c61,
+ 0x87a5, 0x3d88,
+ 0x87a9, 0x3fec,
+ 0x87aa, 0x2e36,
+ 0x87ab, 0x146c,
+ 0x87ac, 0x2e3a,
+ 0x87ad, 0x2e37,
+ 0x87ae, 0x2e3e,
+ 0x87af, 0x2e44,
+ 0x87b0, 0x2e39,
+ 0x87b1, 0x380f,
+ 0x87b2, 0x2e4d,
+ 0x87b3, 0x1469,
+ 0x87b4, 0x2e47,
+ 0x87b5, 0x2e3c,
+ 0x87b6, 0x2e48,
+ 0x87b7, 0x2e43,
+ 0x87b8, 0x2e4a,
+ 0x87b9, 0x2e3b,
+ 0x87ba, 0x146e,
+ 0x87bb, 0x146d,
+ 0x87bc, 0x2e3d,
+ 0x87bd, 0x2e4b,
+ 0x87be, 0x2e35,
+ 0x87bf, 0x2e49,
+ 0x87c0, 0x1467,
+ 0x87c1, 0x3ffc,
+ 0x87c2, 0x2e41,
+ 0x87c3, 0x2e40,
+ 0x87c4, 0x2e45,
+ 0x87c5, 0x2e38,
+ 0x87c6, 0x146b,
+ 0x87c8, 0x146f,
+ 0x87c9, 0x2e3f,
+ 0x87ca, 0x2e46,
+ 0x87cb, 0x1470,
+ 0x87cc, 0x2e42,
+ 0x87ce, 0x3fed,
+ 0x87d1, 0x1468,
+ 0x87d2, 0x146a,
+ 0x87d3, 0x2fba,
+ 0x87d4, 0x2fb8,
+ 0x87d6, 0x3f92,
+ 0x87d7, 0x2fbe,
+ 0x87d8, 0x2fbc,
+ 0x87d9, 0x2fbf,
+ 0x87da, 0x3810,
+ 0x87db, 0x2fb1,
+ 0x87dc, 0x2fb9,
+ 0x87dd, 0x2fc3,
+ 0x87de, 0x2e4c,
+ 0x87df, 0x2fb5,
+ 0x87e0, 0x1526,
+ 0x87e1, 0x2a13,
+ 0x87e2, 0x2fb0,
+ 0x87e3, 0x2fbd,
+ 0x87e4, 0x2fb7,
+ 0x87e5, 0x2fb4,
+ 0x87e6, 0x2faf,
+ 0x87e7, 0x2fae,
+ 0x87e8, 0x2fc2,
+ 0x87ea, 0x2fb3,
+ 0x87eb, 0x2fb2,
+ 0x87ec, 0x1524,
+ 0x87ed, 0x2fbb,
+ 0x87ee, 0x380d,
+ 0x87ef, 0x1523,
+ 0x87f2, 0x1525,
+ 0x87f3, 0x2fb6,
+ 0x87f4, 0x2fc1,
+ 0x87f5, 0x3fae,
+ 0x87f6, 0x310a,
+ 0x87f9, 0x15be,
+ 0x87fa, 0x3108,
+ 0x87fb, 0x15bb,
+ 0x87fc, 0x3110,
+ 0x87fe, 0x15bf,
+ 0x87ff, 0x3112,
+ 0x8800, 0x3107,
+ 0x8801, 0x2fc0,
+ 0x8802, 0x3114,
+ 0x8803, 0x3109,
+ 0x8804, 0x3eaf,
+ 0x8805, 0x15bc,
+ 0x8806, 0x310f,
+ 0x8808, 0x3111,
+ 0x8809, 0x310c,
+ 0x880a, 0x3113,
+ 0x880b, 0x310e,
+ 0x880c, 0x310d,
+ 0x880d, 0x15bd,
+ 0x880f, 0x3811,
+ 0x8810, 0x322c,
+ 0x8813, 0x322f,
+ 0x8814, 0x163f,
+ 0x8816, 0x3230,
+ 0x8817, 0x322e,
+ 0x8818, 0x3f7a,
+ 0x8819, 0x322b,
+ 0x881b, 0x3306,
+ 0x881c, 0x3309,
+ 0x881d, 0x3305,
+ 0x881f, 0x168b,
+ 0x8820, 0x3307,
+ 0x8821, 0x168a,
+ 0x8822, 0x1689,
+ 0x8823, 0x1688,
+ 0x8824, 0x3308,
+ 0x8825, 0x33b1,
+ 0x8826, 0x33af,
+ 0x8827, 0x3e07,
+ 0x8828, 0x33ae,
+ 0x8829, 0x3304,
+ 0x882a, 0x33b0,
+ 0x882b, 0x330a,
+ 0x882c, 0x33ad,
+ 0x882d, 0x3b8b,
+ 0x882e, 0x3437,
+ 0x882f, 0x3415,
+ 0x8830, 0x3435,
+ 0x8831, 0x1709,
+ 0x8832, 0x3436,
+ 0x8833, 0x3438,
+ 0x8835, 0x349a,
+ 0x8836, 0x1728,
+ 0x8837, 0x3499,
+ 0x8838, 0x3498,
+ 0x8839, 0x1729,
+ 0x883b, 0x1747,
+ 0x883c, 0x3508,
+ 0x883d, 0x3520,
+ 0x883e, 0x351f,
+ 0x883f, 0x3521,
+ 0x8840, 0x0410,
+ 0x8841, 0x1bfe,
+ 0x8842, 0x3f5a,
+ 0x8843, 0x1dfa,
+ 0x8845, 0x3816,
+ 0x8848, 0x22d3,
+ 0x884a, 0x330b,
+ 0x884b, 0x349b,
+ 0x884c, 0x0411,
+ 0x884d, 0x0803,
+ 0x884e, 0x1bff,
+ 0x884f, 0x3844,
+ 0x8852, 0x204f,
+ 0x8853, 0x0b94,
+ 0x8855, 0x22d5,
+ 0x8856, 0x22d4,
+ 0x8857, 0x0d51,
+ 0x8859, 0x0efa,
+ 0x885a, 0x2a2f,
+ 0x885b, 0x120a,
+ 0x885d, 0x120b,
+ 0x885e, 0x381b,
+ 0x8860, 0x3a46,
+ 0x8861, 0x1345,
+ 0x8862, 0x172a,
+ 0x8863, 0x0412,
+ 0x8864, 0x4502,
+ 0x8865, 0x3dfc,
+ 0x8867, 0x1c00,
+ 0x8868, 0x068c,
+ 0x8869, 0x1c02,
+ 0x886a, 0x1c01,
+ 0x886b, 0x0804,
+ 0x886d, 0x1dfc,
+ 0x886e, 0x3b8e,
+ 0x886f, 0x1e03,
+ 0x8870, 0x09b8,
+ 0x8871, 0x1e01,
+ 0x8872, 0x1dff,
+ 0x8874, 0x1e06,
+ 0x8875, 0x1dfd,
+ 0x8877, 0x09b9,
+ 0x8879, 0x09bd,
+ 0x887c, 0x1e07,
+ 0x887d, 0x09bc,
+ 0x887e, 0x1e05,
+ 0x887f, 0x1e02,
+ 0x8880, 0x1e00,
+ 0x8881, 0x09ba,
+ 0x8883, 0x1e04,
+ 0x8884, 0x42f7,
+ 0x8887, 0x3b90,
+ 0x8888, 0x0b96,
+ 0x8889, 0x2050,
+ 0x888b, 0x0b9b,
+ 0x888c, 0x2060,
+ 0x888d, 0x0b9a,
+ 0x888e, 0x2062,
+ 0x8891, 0x2056,
+ 0x8892, 0x0b98,
+ 0x8893, 0x2061,
+ 0x8895, 0x2051,
+ 0x8896, 0x0b99,
+ 0x8897, 0x205d,
+ 0x8898, 0x2059,
+ 0x8899, 0x205b,
+ 0x889a, 0x2055,
+ 0x889b, 0x205c,
+ 0x889c, 0x381c,
+ 0x889e, 0x0b95,
+ 0x889f, 0x2058,
+ 0x88a0, 0x3fa0,
+ 0x88a1, 0x2057,
+ 0x88a2, 0x2053,
+ 0x88a4, 0x205e,
+ 0x88a7, 0x205a,
+ 0x88a8, 0x2052,
+ 0x88aa, 0x2054,
+ 0x88ab, 0x0b97,
+ 0x88ac, 0x205f,
+ 0x88ae, 0x4775,
+ 0x88b1, 0x0d54,
+ 0x88b2, 0x22e0,
+ 0x88b4, 0x381e,
+ 0x88b6, 0x22dc,
+ 0x88b7, 0x22de,
+ 0x88b8, 0x22d9,
+ 0x88b9, 0x22d8,
+ 0x88ba, 0x22d6,
+ 0x88bc, 0x22dd,
+ 0x88bd, 0x22df,
+ 0x88be, 0x22db,
+ 0x88bf, 0x3b91,
+ 0x88c0, 0x22da,
+ 0x88c1, 0x0d52,
+ 0x88c5, 0x3820,
+ 0x88c7, 0x3eb1,
+ 0x88c9, 0x22e2,
+ 0x88ca, 0x0f02,
+ 0x88cb, 0x2578,
+ 0x88cc, 0x257e,
+ 0x88cd, 0x2579,
+ 0x88cf, 0x36ea,
+ 0x88d0, 0x257f,
+ 0x88d2, 0x0f04,
+ 0x88d4, 0x0efc,
+ 0x88d5, 0x0f03,
+ 0x88d6, 0x2577,
+ 0x88d7, 0x22d7,
+ 0x88d8, 0x0eff,
+ 0x88d9, 0x0efd,
+ 0x88da, 0x257d,
+ 0x88db, 0x257c,
+ 0x88dc, 0x0efe,
+ 0x88dd, 0x0f00,
+ 0x88de, 0x257b,
+ 0x88df, 0x0efb,
+ 0x88e1, 0x0f01,
+ 0x88e6, 0x3b92,
+ 0x88e7, 0x27f0,
+ 0x88e8, 0x10a2,
+ 0x88eb, 0x27fb,
+ 0x88ec, 0x27fa,
+ 0x88ee, 0x27f5,
+ 0x88ef, 0x10a4,
+ 0x88f0, 0x27f9,
+ 0x88f1, 0x27f1,
+ 0x88f3, 0x109c,
+ 0x88f4, 0x109e,
+ 0x88f5, 0x3e08,
+ 0x88f6, 0x27f7,
+ 0x88f7, 0x27ef,
+ 0x88f8, 0x10a0,
+ 0x88f9, 0x109f,
+ 0x88fa, 0x27f3,
+ 0x88fb, 0x27f8,
+ 0x88fc, 0x27f6,
+ 0x88fd, 0x10a1,
+ 0x88fe, 0x27f4,
+ 0x88ff, 0x4776,
+ 0x8900, 0x42fa,
+ 0x8901, 0x22e1,
+ 0x8902, 0x109d,
+ 0x8905, 0x2a30,
+ 0x8906, 0x2a37,
+ 0x8907, 0x120d,
+ 0x8909, 0x2a3b,
+ 0x890a, 0x1211,
+ 0x890b, 0x2a33,
+ 0x890c, 0x2a31,
+ 0x890e, 0x2a3a,
+ 0x8910, 0x120c,
+ 0x8911, 0x2a39,
+ 0x8912, 0x120e,
+ 0x8914, 0x2a32,
+ 0x8915, 0x1210,
+ 0x8916, 0x2a38,
+ 0x8917, 0x2a34,
+ 0x891a, 0x10a3,
+ 0x891e, 0x2c77,
+ 0x891f, 0x2c83,
+ 0x8921, 0x134a,
+ 0x8922, 0x2c7e,
+ 0x8923, 0x2c80,
+ 0x8924, 0x4777,
+ 0x8925, 0x1348,
+ 0x8926, 0x2c78,
+ 0x8927, 0x2c7c,
+ 0x8929, 0x2c7f,
+ 0x892a, 0x1346,
+ 0x892b, 0x1349,
+ 0x892c, 0x2c82,
+ 0x892d, 0x2c7a,
+ 0x892f, 0x2c81,
+ 0x8930, 0x2c79,
+ 0x8931, 0x2c7d,
+ 0x8932, 0x1347,
+ 0x8933, 0x2e4f,
+ 0x8935, 0x2e4e,
+ 0x8936, 0x1472,
+ 0x8937, 0x2e54,
+ 0x8938, 0x1474,
+ 0x893b, 0x1471,
+ 0x893c, 0x2e50,
+ 0x893d, 0x1475,
+ 0x893e, 0x2e51,
+ 0x8941, 0x2e52,
+ 0x8942, 0x2e55,
+ 0x8943, 0x3e16,
+ 0x8944, 0x1473,
+ 0x8946, 0x2fc8,
+ 0x8947, 0x43e3,
+ 0x8949, 0x2fcb,
+ 0x894b, 0x2fc5,
+ 0x894c, 0x2fc7,
+ 0x894d, 0x3b94,
+ 0x894f, 0x2fc6,
+ 0x8950, 0x2fc9,
+ 0x8952, 0x2e53,
+ 0x8953, 0x2fc4,
+ 0x8954, 0x3b96,
+ 0x8956, 0x15c2,
+ 0x8957, 0x3118,
+ 0x8958, 0x311b,
+ 0x8959, 0x311d,
+ 0x895a, 0x3116,
+ 0x895c, 0x311a,
+ 0x895d, 0x311c,
+ 0x895e, 0x15c3,
+ 0x895f, 0x15c1,
+ 0x8960, 0x15c0,
+ 0x8961, 0x3119,
+ 0x8962, 0x3115,
+ 0x8963, 0x3231,
+ 0x8964, 0x1641,
+ 0x8965, 0x3b93,
+ 0x8966, 0x3232,
+ 0x8969, 0x330d,
+ 0x896a, 0x168c,
+ 0x896b, 0x330f,
+ 0x896c, 0x168d,
+ 0x896d, 0x330c,
+ 0x896e, 0x330e,
+ 0x896f, 0x16d6,
+ 0x8971, 0x33b2,
+ 0x8972, 0x16d5,
+ 0x8973, 0x343b,
+ 0x8974, 0x343a,
+ 0x8976, 0x3439,
+ 0x8977, 0x3dea,
+ 0x8979, 0x34e2,
+ 0x897b, 0x34e5,
+ 0x897c, 0x34e4,
+ 0x897e, 0x1819,
+ 0x897f, 0x0413,
+ 0x8980, 0x4708,
+ 0x8981, 0x0805,
+ 0x8982, 0x2063,
+ 0x8983, 0x0d55,
+ 0x8985, 0x2580,
+ 0x8986, 0x1527,
+ 0x8987, 0x3822,
+ 0x8988, 0x311e,
+ 0x8989, 0x3fe9,
+ 0x898a, 0x3823,
+ 0x898b, 0x0508,
+ 0x898f, 0x0b9d,
+ 0x8991, 0x4778,
+ 0x8993, 0x0b9c,
+ 0x8994, 0x3fe0,
+ 0x8995, 0x22e3,
+ 0x8996, 0x0d56,
+ 0x8997, 0x22e5,
+ 0x8998, 0x22e4,
+ 0x899b, 0x2581,
+ 0x899c, 0x0f05,
+ 0x899d, 0x27fc,
+ 0x899e, 0x27ff,
+ 0x899f, 0x27fe,
+ 0x89a1, 0x27fd,
+ 0x89a2, 0x2a3c,
+ 0x89a3, 0x2a3e,
+ 0x89a4, 0x2a3d,
+ 0x89a5, 0x3d93,
+ 0x89a6, 0x134c,
+ 0x89a7, 0x3826,
+ 0x89a9, 0x3825,
+ 0x89aa, 0x134b,
+ 0x89ac, 0x1476,
+ 0x89ad, 0x2e56,
+ 0x89ae, 0x2e58,
+ 0x89af, 0x2e57,
+ 0x89b2, 0x1528,
+ 0x89b6, 0x3120,
+ 0x89b7, 0x311f,
+ 0x89b9, 0x3233,
+ 0x89ba, 0x1642,
+ 0x89bc, 0x3827,
+ 0x89bd, 0x168e,
+ 0x89be, 0x33b4,
+ 0x89bf, 0x33b3,
+ 0x89c0, 0x1748,
+ 0x89c1, 0x4503,
+ 0x89c6, 0x4566,
+ 0x89d2, 0x0509,
+ 0x89d3, 0x1c03,
+ 0x89d4, 0x0806,
+ 0x89d5, 0x2066,
+ 0x89d6, 0x2064,
+ 0x89d9, 0x2065,
+ 0x89da, 0x22e7,
+ 0x89dc, 0x2588,
+ 0x89dd, 0x22e6,
+ 0x89df, 0x2582,
+ 0x89e0, 0x2586,
+ 0x89e1, 0x2585,
+ 0x89e2, 0x2587,
+ 0x89e3, 0x0f06,
+ 0x89e4, 0x2584,
+ 0x89e5, 0x2583,
+ 0x89e6, 0x2589,
+ 0x89e7, 0x3829,
+ 0x89e8, 0x2802,
+ 0x89e9, 0x2800,
+ 0x89eb, 0x2801,
+ 0x89ec, 0x2a41,
+ 0x89ed, 0x2a3f,
+ 0x89f0, 0x2a40,
+ 0x89f1, 0x2c84,
+ 0x89f2, 0x2e59,
+ 0x89f4, 0x1529,
+ 0x89f6, 0x3121,
+ 0x89f7, 0x3234,
+ 0x89f8, 0x1643,
+ 0x89fa, 0x3310,
+ 0x89fb, 0x33b5,
+ 0x89fc, 0x16d7,
+ 0x89fe, 0x343c,
+ 0x89ff, 0x34e6,
+ 0x8a00, 0x050a,
+ 0x8a02, 0x0808,
+ 0x8a04, 0x1c04,
+ 0x8a07, 0x1c05,
+ 0x8a08, 0x0807,
+ 0x8a0a, 0x09c3,
+ 0x8a0c, 0x09c1,
+ 0x8a0e, 0x09c0,
+ 0x8a0f, 0x09c7,
+ 0x8a10, 0x09bf,
+ 0x8a11, 0x09c8,
+ 0x8a12, 0x1e08,
+ 0x8a13, 0x09c5,
+ 0x8a15, 0x09c2,
+ 0x8a16, 0x09c6,
+ 0x8a17, 0x09c4,
+ 0x8a18, 0x09be,
+ 0x8a1b, 0x0ba5,
+ 0x8a1c, 0x3ba3,
+ 0x8a1d, 0x0b9f,
+ 0x8a1e, 0x206a,
+ 0x8a1f, 0x0ba4,
+ 0x8a22, 0x0ba6,
+ 0x8a23, 0x0ba0,
+ 0x8a25, 0x0ba1,
+ 0x8a27, 0x2068,
+ 0x8a29, 0x43e5,
+ 0x8a2a, 0x0b9e,
+ 0x8a2b, 0x3bd1,
+ 0x8a2c, 0x2069,
+ 0x8a2d, 0x0ba3,
+ 0x8a30, 0x2067,
+ 0x8a31, 0x0ba2,
+ 0x8a34, 0x0d61,
+ 0x8a36, 0x0d63,
+ 0x8a38, 0x477a,
+ 0x8a39, 0x22eb,
+ 0x8a3a, 0x0d62,
+ 0x8a3b, 0x0d57,
+ 0x8a3c, 0x0d5b,
+ 0x8a3d, 0x3ba2,
+ 0x8a3e, 0x0f19,
+ 0x8a3f, 0x258e,
+ 0x8a40, 0x22ed,
+ 0x8a41, 0x0d5c,
+ 0x8a44, 0x22f0,
+ 0x8a46, 0x0d60,
+ 0x8a48, 0x22f3,
+ 0x8a49, 0x3ff0,
+ 0x8a4a, 0x22f5,
+ 0x8a4c, 0x22f6,
+ 0x8a4d, 0x22ea,
+ 0x8a4e, 0x22e9,
+ 0x8a4f, 0x22f7,
+ 0x8a50, 0x0d5f,
+ 0x8a51, 0x22f4,
+ 0x8a52, 0x22f2,
+ 0x8a54, 0x0d5d,
+ 0x8a55, 0x0d59,
+ 0x8a56, 0x0d64,
+ 0x8a57, 0x22ee,
+ 0x8a59, 0x22ec,
+ 0x8a5b, 0x0d5e,
+ 0x8a5e, 0x0d5a,
+ 0x8a60, 0x0d58,
+ 0x8a61, 0x258d,
+ 0x8a62, 0x0f14,
+ 0x8a63, 0x0f0f,
+ 0x8a66, 0x0f0a,
+ 0x8a67, 0x3f8e,
+ 0x8a68, 0x0f1a,
+ 0x8a69, 0x0f0b,
+ 0x8a6b, 0x0f07,
+ 0x8a6c, 0x0f16,
+ 0x8a6d, 0x0f13,
+ 0x8a6e, 0x0f15,
+ 0x8a70, 0x0f0c,
+ 0x8a71, 0x0f11,
+ 0x8a72, 0x0f08,
+ 0x8a74, 0x2595,
+ 0x8a75, 0x2592,
+ 0x8a76, 0x258a,
+ 0x8a77, 0x258f,
+ 0x8a79, 0x0f17,
+ 0x8a7a, 0x2596,
+ 0x8a7b, 0x0f18,
+ 0x8a7c, 0x0f0e,
+ 0x8a7e, 0x3fa5,
+ 0x8a7f, 0x258c,
+ 0x8a81, 0x2594,
+ 0x8a82, 0x2590,
+ 0x8a83, 0x2593,
+ 0x8a84, 0x2591,
+ 0x8a85, 0x0f12,
+ 0x8a86, 0x258b,
+ 0x8a87, 0x0f0d,
+ 0x8a8b, 0x2805,
+ 0x8a8c, 0x10a6,
+ 0x8a8d, 0x10a9,
+ 0x8a8f, 0x2807,
+ 0x8a90, 0x382f,
+ 0x8a91, 0x10b1,
+ 0x8a92, 0x2806,
+ 0x8a93, 0x10ab,
+ 0x8a94, 0x477b,
+ 0x8a95, 0x1216,
+ 0x8a96, 0x2808,
+ 0x8a98, 0x10b0,
+ 0x8a99, 0x2804,
+ 0x8a9a, 0x10b2,
+ 0x8a9c, 0x382c,
+ 0x8a9e, 0x10a7,
+ 0x8aa0, 0x0f10,
+ 0x8aa1, 0x10aa,
+ 0x8aa3, 0x10a8,
+ 0x8aa4, 0x10ac,
+ 0x8aa5, 0x10ae,
+ 0x8aa6, 0x10a5,
+ 0x8aa7, 0x10b3,
+ 0x8aa8, 0x10af,
+ 0x8aa9, 0x383d,
+ 0x8aaa, 0x10ad,
+ 0x8aab, 0x2803,
+ 0x8aaf, 0x3841,
+ 0x8ab0, 0x121d,
+ 0x8ab2, 0x1219,
+ 0x8ab4, 0x477c,
+ 0x8ab6, 0x1220,
+ 0x8ab8, 0x2a44,
+ 0x8ab9, 0x1221,
+ 0x8aba, 0x2a50,
+ 0x8abb, 0x2a49,
+ 0x8abc, 0x1212,
+ 0x8abd, 0x2a51,
+ 0x8abe, 0x2a4b,
+ 0x8abf, 0x121c,
+ 0x8ac0, 0x2a4c,
+ 0x8ac2, 0x121b,
+ 0x8ac3, 0x2a4f,
+ 0x8ac4, 0x1215,
+ 0x8ac5, 0x2a4d,
+ 0x8ac6, 0x2a43,
+ 0x8ac7, 0x1214,
+ 0x8ac8, 0x2c8f,
+ 0x8ac9, 0x121a,
+ 0x8acb, 0x1217,
+ 0x8acd, 0x121f,
+ 0x8acf, 0x2a42,
+ 0x8ad1, 0x2a46,
+ 0x8ad2, 0x1213,
+ 0x8ad3, 0x2a45,
+ 0x8ad4, 0x2a47,
+ 0x8ad6, 0x121e,
+ 0x8ad7, 0x2a4a,
+ 0x8ad8, 0x2a4e,
+ 0x8ad9, 0x2a52,
+ 0x8ada, 0x39c2,
+ 0x8adb, 0x1222,
+ 0x8adc, 0x1352,
+ 0x8add, 0x2c8a,
+ 0x8ade, 0x2c90,
+ 0x8adf, 0x2c8d,
+ 0x8ae0, 0x2c85,
+ 0x8ae1, 0x2c91,
+ 0x8ae2, 0x2c86,
+ 0x8ae4, 0x2c8c,
+ 0x8ae6, 0x134d,
+ 0x8ae7, 0x1353,
+ 0x8ae8, 0x2c92,
+ 0x8aea, 0x3dd9,
+ 0x8aeb, 0x134f,
+ 0x8aed, 0x1359,
+ 0x8aee, 0x1354,
+ 0x8aef, 0x2c94,
+ 0x8af0, 0x2c8e,
+ 0x8af1, 0x1350,
+ 0x8af2, 0x2c87,
+ 0x8af3, 0x135a,
+ 0x8af4, 0x2c88,
+ 0x8af6, 0x135b,
+ 0x8af7, 0x1358,
+ 0x8af8, 0x1218,
+ 0x8afa, 0x134e,
+ 0x8afb, 0x2c95,
+ 0x8afc, 0x135c,
+ 0x8afe, 0x1355,
+ 0x8aff, 0x2c93,
+ 0x8b00, 0x1351,
+ 0x8b01, 0x1356,
+ 0x8b04, 0x147e,
+ 0x8b05, 0x2e5f,
+ 0x8b06, 0x2e68,
+ 0x8b07, 0x2e65,
+ 0x8b08, 0x2e67,
+ 0x8b0a, 0x147b,
+ 0x8b0b, 0x2e60,
+ 0x8b0c, 0x3836,
+ 0x8b0d, 0x2e66,
+ 0x8b0e, 0x1477,
+ 0x8b0f, 0x2e62,
+ 0x8b10, 0x147f,
+ 0x8b11, 0x2e5e,
+ 0x8b12, 0x2e63,
+ 0x8b13, 0x2e6a,
+ 0x8b14, 0x2c8b,
+ 0x8b15, 0x2e64,
+ 0x8b16, 0x2e5d,
+ 0x8b17, 0x1478,
+ 0x8b18, 0x2e5c,
+ 0x8b19, 0x1479,
+ 0x8b1a, 0x2e6b,
+ 0x8b1b, 0x147a,
+ 0x8b1c, 0x2e69,
+ 0x8b1d, 0x147d,
+ 0x8b1e, 0x2e5b,
+ 0x8b1f, 0x3837,
+ 0x8b20, 0x147c,
+ 0x8b22, 0x2e61,
+ 0x8b23, 0x2fce,
+ 0x8b24, 0x2fdc,
+ 0x8b25, 0x2fd7,
+ 0x8b26, 0x2fd9,
+ 0x8b27, 0x2fcd,
+ 0x8b28, 0x152a,
+ 0x8b2a, 0x2fcc,
+ 0x8b2b, 0x152d,
+ 0x8b2c, 0x152c,
+ 0x8b2d, 0x3f99,
+ 0x8b2e, 0x2fdb,
+ 0x8b2f, 0x2fd3,
+ 0x8b30, 0x2fd0,
+ 0x8b31, 0x2fd6,
+ 0x8b33, 0x2fcf,
+ 0x8b35, 0x2fd1,
+ 0x8b36, 0x2fda,
+ 0x8b37, 0x2fd8,
+ 0x8b39, 0x152b,
+ 0x8b3a, 0x2fdf,
+ 0x8b3b, 0x2fdd,
+ 0x8b3c, 0x2fd4,
+ 0x8b3d, 0x2fde,
+ 0x8b3e, 0x2fd5,
+ 0x8b3f, 0x383a,
+ 0x8b40, 0x3125,
+ 0x8b41, 0x15c4,
+ 0x8b42, 0x312c,
+ 0x8b43, 0x3ff2,
+ 0x8b45, 0x3313,
+ 0x8b46, 0x15cb,
+ 0x8b47, 0x2fd2,
+ 0x8b48, 0x3123,
+ 0x8b49, 0x15c7,
+ 0x8b4a, 0x3124,
+ 0x8b4b, 0x3129,
+ 0x8b4c, 0x383b,
+ 0x8b4e, 0x15c9,
+ 0x8b50, 0x3122,
+ 0x8b51, 0x312b,
+ 0x8b52, 0x312d,
+ 0x8b53, 0x3126,
+ 0x8b54, 0x3128,
+ 0x8b55, 0x312a,
+ 0x8b56, 0x3127,
+ 0x8b57, 0x312e,
+ 0x8b58, 0x15c6,
+ 0x8b59, 0x15cc,
+ 0x8b5a, 0x15c8,
+ 0x8b5c, 0x15c5,
+ 0x8b5d, 0x3237,
+ 0x8b5e, 0x3db8,
+ 0x8b5f, 0x1648,
+ 0x8b60, 0x3235,
+ 0x8b62, 0x3dd4,
+ 0x8b63, 0x3239,
+ 0x8b65, 0x323a,
+ 0x8b66, 0x1646,
+ 0x8b67, 0x323b,
+ 0x8b68, 0x3238,
+ 0x8b69, 0x3bf7,
+ 0x8b6a, 0x3236,
+ 0x8b6b, 0x1649,
+ 0x8b6c, 0x1645,
+ 0x8b6d, 0x323c,
+ 0x8b6f, 0x1647,
+ 0x8b70, 0x1644,
+ 0x8b74, 0x168f,
+ 0x8b77, 0x1690,
+ 0x8b78, 0x3312,
+ 0x8b79, 0x3311,
+ 0x8b7a, 0x3314,
+ 0x8b7d, 0x1691,
+ 0x8b7e, 0x33b6,
+ 0x8b7f, 0x33bb,
+ 0x8b80, 0x16d8,
+ 0x8b81, 0x3d8d,
+ 0x8b82, 0x33b8,
+ 0x8b84, 0x33b7,
+ 0x8b85, 0x33ba,
+ 0x8b86, 0x33b9,
+ 0x8b88, 0x3440,
+ 0x8b8a, 0x170a,
+ 0x8b8b, 0x343f,
+ 0x8b8c, 0x343d,
+ 0x8b8e, 0x343e,
+ 0x8b90, 0x383f,
+ 0x8b92, 0x172c,
+ 0x8b93, 0x172b,
+ 0x8b94, 0x349c,
+ 0x8b96, 0x172d,
+ 0x8b98, 0x34e7,
+ 0x8b9a, 0x1754,
+ 0x8b9b, 0x3840,
+ 0x8b9c, 0x175a,
+ 0x8b9e, 0x3522,
+ 0x8b9f, 0x353f,
+ 0x8ba0, 0x4505,
+ 0x8bbe, 0x4567,
+ 0x8be2, 0x4568,
+ 0x8c37, 0x050b,
+ 0x8c39, 0x206b,
+ 0x8c3b, 0x206c,
+ 0x8c3c, 0x2597,
+ 0x8c3d, 0x2809,
+ 0x8c3e, 0x2a53,
+ 0x8c3f, 0x1481,
+ 0x8c41, 0x1480,
+ 0x8c42, 0x2fe0,
+ 0x8c43, 0x312f,
+ 0x8c45, 0x3441,
+ 0x8c46, 0x050c,
+ 0x8c47, 0x1e09,
+ 0x8c48, 0x09c9,
+ 0x8c49, 0x0ba7,
+ 0x8c4a, 0x2599,
+ 0x8c4b, 0x2598,
+ 0x8c4c, 0x1223,
+ 0x8c4d, 0x2a54,
+ 0x8c4e, 0x1224,
+ 0x8c4f, 0x2e6c,
+ 0x8c50, 0x152e,
+ 0x8c51, 0x477d,
+ 0x8c54, 0x1763,
+ 0x8c55, 0x050d,
+ 0x8c56, 0x1a48,
+ 0x8c57, 0x1e0a,
+ 0x8c5a, 0x0ba8,
+ 0x8c5c, 0x206d,
+ 0x8c5f, 0x22f8,
+ 0x8c61, 0x0d65,
+ 0x8c62, 0x0f1b,
+ 0x8c64, 0x259b,
+ 0x8c65, 0x259a,
+ 0x8c66, 0x259c,
+ 0x8c68, 0x280a,
+ 0x8c6a, 0x10b4,
+ 0x8c6b, 0x135d,
+ 0x8c6c, 0x1225,
+ 0x8c6d, 0x135e,
+ 0x8c6f, 0x2e70,
+ 0x8c70, 0x2e6d,
+ 0x8c71, 0x2e6f,
+ 0x8c72, 0x2e6e,
+ 0x8c73, 0x1482,
+ 0x8c75, 0x2fe1,
+ 0x8c76, 0x3131,
+ 0x8c77, 0x3130,
+ 0x8c78, 0x18e7,
+ 0x8c79, 0x09cb,
+ 0x8c7a, 0x09ca,
+ 0x8c7b, 0x1e0b,
+ 0x8c7d, 0x206f,
+ 0x8c80, 0x22fa,
+ 0x8c81, 0x22f9,
+ 0x8c82, 0x0d66,
+ 0x8c84, 0x259e,
+ 0x8c86, 0x259d,
+ 0x8c89, 0x0f1d,
+ 0x8c8a, 0x0f1c,
+ 0x8c8c, 0x10b6,
+ 0x8c8d, 0x10b5,
+ 0x8c8f, 0x2a55,
+ 0x8c90, 0x2c98,
+ 0x8c91, 0x2c96,
+ 0x8c93, 0x135f,
+ 0x8c94, 0x2e72,
+ 0x8c95, 0x2e71,
+ 0x8c97, 0x2fe4,
+ 0x8c98, 0x2fe3,
+ 0x8c99, 0x2fe2,
+ 0x8c9a, 0x3132,
+ 0x8c9b, 0x3845,
+ 0x8c9c, 0x3523,
+ 0x8c9d, 0x050e,
+ 0x8c9e, 0x080a,
+ 0x8c9f, 0x3bad,
+ 0x8ca0, 0x080b,
+ 0x8ca1, 0x09cc,
+ 0x8ca3, 0x1e0d,
+ 0x8ca4, 0x1e0c,
+ 0x8ca5, 0x2070,
+ 0x8ca7, 0x0bae,
+ 0x8ca8, 0x0bac,
+ 0x8ca9, 0x0ba9,
+ 0x8caa, 0x0bad,
+ 0x8cab, 0x0bab,
+ 0x8cac, 0x0baa,
+ 0x8cad, 0x3ff1,
+ 0x8caf, 0x0d67,
+ 0x8cb0, 0x22fd,
+ 0x8cb2, 0x0f22,
+ 0x8cb3, 0x0d69,
+ 0x8cb4, 0x0d6e,
+ 0x8cb5, 0x22ff,
+ 0x8cb6, 0x0d70,
+ 0x8cb7, 0x0d6f,
+ 0x8cb8, 0x0d72,
+ 0x8cb9, 0x22fe,
+ 0x8cba, 0x22fb,
+ 0x8cbb, 0x0d6c,
+ 0x8cbc, 0x0d68,
+ 0x8cbd, 0x0d6a,
+ 0x8cbe, 0x22fc,
+ 0x8cbf, 0x0d71,
+ 0x8cc0, 0x0d6d,
+ 0x8cc1, 0x0d6b,
+ 0x8cc2, 0x0f24,
+ 0x8cc3, 0x0f23,
+ 0x8cc4, 0x0f21,
+ 0x8cc5, 0x0f25,
+ 0x8cc7, 0x0f1f,
+ 0x8cca, 0x0f1e,
+ 0x8ccc, 0x25a0,
+ 0x8ccd, 0x3e99,
+ 0x8ccf, 0x280d,
+ 0x8cd1, 0x10b8,
+ 0x8cd3, 0x10b7,
+ 0x8cd4, 0x477e,
+ 0x8cd5, 0x280c,
+ 0x8cd6, 0x384b,
+ 0x8cd7, 0x280e,
+ 0x8cd9, 0x2a58,
+ 0x8cda, 0x2a5a,
+ 0x8cdb, 0x3851,
+ 0x8cdc, 0x122e,
+ 0x8cdd, 0x2a5b,
+ 0x8cde, 0x1227,
+ 0x8cdf, 0x2a57,
+ 0x8ce0, 0x1226,
+ 0x8ce1, 0x1230,
+ 0x8ce2, 0x122c,
+ 0x8ce4, 0x1229,
+ 0x8ce5, 0x2a56,
+ 0x8ce6, 0x1228,
+ 0x8ce7, 0x2a5c,
+ 0x8ce8, 0x2a59,
+ 0x8ce9, 0x3bae,
+ 0x8cea, 0x122f,
+ 0x8ceb, 0x3f9c,
+ 0x8cec, 0x122a,
+ 0x8cee, 0x2c9a,
+ 0x8cf0, 0x2c9c,
+ 0x8cf1, 0x2c9b,
+ 0x8cf2, 0x477f,
+ 0x8cf3, 0x2c9d,
+ 0x8cf4, 0x1360,
+ 0x8cf5, 0x2c99,
+ 0x8cf7, 0x3fb1,
+ 0x8cf8, 0x1486,
+ 0x8cf9, 0x2e73,
+ 0x8cfa, 0x1483,
+ 0x8cfb, 0x1487,
+ 0x8cfc, 0x1485,
+ 0x8cfd, 0x1484,
+ 0x8cfe, 0x2fe5,
+ 0x8d00, 0x2fe8,
+ 0x8d02, 0x2fe7,
+ 0x8d03, 0x384f,
+ 0x8d04, 0x2fe6,
+ 0x8d05, 0x152f,
+ 0x8d06, 0x3133,
+ 0x8d08, 0x15cd,
+ 0x8d09, 0x3135,
+ 0x8d0a, 0x15ce,
+ 0x8d0b, 0x4573,
+ 0x8d0c, 0x3f96,
+ 0x8d0d, 0x164b,
+ 0x8d0f, 0x164a,
+ 0x8d10, 0x3316,
+ 0x8d11, 0x3853,
+ 0x8d12, 0x384e,
+ 0x8d13, 0x1692,
+ 0x8d14, 0x3317,
+ 0x8d15, 0x33bc,
+ 0x8d16, 0x16d9,
+ 0x8d18, 0x3e6f,
+ 0x8d19, 0x3442,
+ 0x8d1b, 0x172f,
+ 0x8d1c, 0x4780,
+ 0x8d1d, 0x4506,
+ 0x8d64, 0x050f,
+ 0x8d66, 0x0bb0,
+ 0x8d67, 0x0baf,
+ 0x8d68, 0x25a1,
+ 0x8d6b, 0x10ba,
+ 0x8d6c, 0x2c9e,
+ 0x8d6d, 0x1231,
+ 0x8d6e, 0x2c9f,
+ 0x8d6f, 0x2e74,
+ 0x8d70, 0x0510,
+ 0x8d72, 0x1c06,
+ 0x8d73, 0x080d,
+ 0x8d74, 0x080c,
+ 0x8d76, 0x1e0e,
+ 0x8d77, 0x09ce,
+ 0x8d78, 0x1e0f,
+ 0x8d79, 0x2073,
+ 0x8d7a, 0x39e1,
+ 0x8d7b, 0x2072,
+ 0x8d7d, 0x2071,
+ 0x8d80, 0x2301,
+ 0x8d81, 0x0d75,
+ 0x8d82, 0x3f69,
+ 0x8d84, 0x2300,
+ 0x8d85, 0x0d74,
+ 0x8d89, 0x2302,
+ 0x8d8a, 0x0d73,
+ 0x8d8c, 0x25a4,
+ 0x8d8d, 0x25a7,
+ 0x8d8e, 0x25a5,
+ 0x8d90, 0x25aa,
+ 0x8d91, 0x25a3,
+ 0x8d92, 0x25ab,
+ 0x8d93, 0x25a8,
+ 0x8d95, 0x10bc,
+ 0x8d96, 0x280f,
+ 0x8d99, 0x10bb,
+ 0x8d9b, 0x2a60,
+ 0x8d9c, 0x2a5e,
+ 0x8d9f, 0x1232,
+ 0x8da0, 0x2a5d,
+ 0x8da1, 0x2a5f,
+ 0x8da3, 0x1233,
+ 0x8da5, 0x2ca0,
+ 0x8da6, 0x3ff7,
+ 0x8da7, 0x2ca1,
+ 0x8da8, 0x1488,
+ 0x8da9, 0x3856,
+ 0x8daa, 0x3137,
+ 0x8dab, 0x3139,
+ 0x8dac, 0x3136,
+ 0x8dad, 0x3138,
+ 0x8dae, 0x323d,
+ 0x8daf, 0x3318,
+ 0x8db2, 0x3509,
+ 0x8db3, 0x0511,
+ 0x8db4, 0x080e,
+ 0x8db5, 0x1e10,
+ 0x8db6, 0x1e12,
+ 0x8db7, 0x1e11,
+ 0x8db9, 0x2076,
+ 0x8dba, 0x0bb2,
+ 0x8dbc, 0x2074,
+ 0x8dbe, 0x0bb1,
+ 0x8dbf, 0x2077,
+ 0x8dc0, 0x436a,
+ 0x8dc1, 0x2078,
+ 0x8dc2, 0x2075,
+ 0x8dc3, 0x4782,
+ 0x8dc5, 0x230e,
+ 0x8dc6, 0x0d7d,
+ 0x8dc7, 0x2306,
+ 0x8dc8, 0x230c,
+ 0x8dcb, 0x0d78,
+ 0x8dcc, 0x0d7b,
+ 0x8dcd, 0x2305,
+ 0x8dce, 0x0d76,
+ 0x8dcf, 0x2309,
+ 0x8dd0, 0x25b1,
+ 0x8dd1, 0x0d7a,
+ 0x8dd3, 0x2304,
+ 0x8dd4, 0x3f82,
+ 0x8dd5, 0x230a,
+ 0x8dd6, 0x2307,
+ 0x8dd7, 0x230d,
+ 0x8dd8, 0x2303,
+ 0x8dd9, 0x230b,
+ 0x8dda, 0x0d79,
+ 0x8ddb, 0x0d7c,
+ 0x8ddc, 0x2308,
+ 0x8ddd, 0x0d77,
+ 0x8ddf, 0x0f27,
+ 0x8de0, 0x25ad,
+ 0x8de1, 0x0f26,
+ 0x8de2, 0x25b4,
+ 0x8de3, 0x25b3,
+ 0x8de4, 0x0f2d,
+ 0x8de6, 0x0f2e,
+ 0x8de7, 0x25b5,
+ 0x8de8, 0x0f28,
+ 0x8de9, 0x25b2,
+ 0x8dea, 0x0f2c,
+ 0x8deb, 0x25b7,
+ 0x8dec, 0x25ae,
+ 0x8dee, 0x25b0,
+ 0x8def, 0x0f29,
+ 0x8df0, 0x25ac,
+ 0x8df1, 0x25af,
+ 0x8df2, 0x25b6,
+ 0x8df3, 0x0f2a,
+ 0x8df4, 0x25b8,
+ 0x8dfa, 0x0f2b,
+ 0x8dfc, 0x10bd,
+ 0x8dfd, 0x2814,
+ 0x8dfe, 0x281a,
+ 0x8dff, 0x2812,
+ 0x8e00, 0x281b,
+ 0x8e01, 0x3f85,
+ 0x8e02, 0x2811,
+ 0x8e03, 0x2816,
+ 0x8e04, 0x281c,
+ 0x8e05, 0x2819,
+ 0x8e06, 0x2818,
+ 0x8e07, 0x2817,
+ 0x8e09, 0x2810,
+ 0x8e0a, 0x2815,
+ 0x8e0d, 0x2813,
+ 0x8e0e, 0x3e5e,
+ 0x8e0f, 0x1238,
+ 0x8e10, 0x1235,
+ 0x8e11, 0x2a69,
+ 0x8e12, 0x2a6e,
+ 0x8e13, 0x2a70,
+ 0x8e14, 0x2a6d,
+ 0x8e15, 0x2a66,
+ 0x8e16, 0x2a68,
+ 0x8e17, 0x2a72,
+ 0x8e18, 0x2a6f,
+ 0x8e19, 0x2a6a,
+ 0x8e1a, 0x2a73,
+ 0x8e1b, 0x2a67,
+ 0x8e1c, 0x2a71,
+ 0x8e1d, 0x1236,
+ 0x8e1e, 0x123c,
+ 0x8e1f, 0x123a,
+ 0x8e20, 0x2a61,
+ 0x8e21, 0x123b,
+ 0x8e22, 0x1237,
+ 0x8e23, 0x2a62,
+ 0x8e24, 0x2a64,
+ 0x8e25, 0x2a63,
+ 0x8e26, 0x2a6b,
+ 0x8e28, 0x3f88,
+ 0x8e29, 0x1239,
+ 0x8e2a, 0x3bb4,
+ 0x8e2b, 0x1234,
+ 0x8e2d, 0x3eab,
+ 0x8e2e, 0x2a65,
+ 0x8e30, 0x2cab,
+ 0x8e31, 0x1362,
+ 0x8e33, 0x2ca2,
+ 0x8e34, 0x1363,
+ 0x8e35, 0x1366,
+ 0x8e36, 0x2ca7,
+ 0x8e38, 0x2ca4,
+ 0x8e39, 0x1365,
+ 0x8e3a, 0x4784,
+ 0x8e3c, 0x2ca8,
+ 0x8e3e, 0x2ca3,
+ 0x8e3f, 0x2cac,
+ 0x8e40, 0x2ca5,
+ 0x8e41, 0x2caa,
+ 0x8e42, 0x1364,
+ 0x8e44, 0x1361,
+ 0x8e45, 0x2ca6,
+ 0x8e46, 0x4312,
+ 0x8e47, 0x2e7a,
+ 0x8e48, 0x148b,
+ 0x8e49, 0x1489,
+ 0x8e4a, 0x148c,
+ 0x8e4b, 0x148a,
+ 0x8e4c, 0x2e79,
+ 0x8e4d, 0x2e76,
+ 0x8e4e, 0x2e75,
+ 0x8e4f, 0x3f83,
+ 0x8e50, 0x2e78,
+ 0x8e53, 0x2e77,
+ 0x8e54, 0x2ff6,
+ 0x8e55, 0x1535,
+ 0x8e56, 0x2fed,
+ 0x8e57, 0x2fec,
+ 0x8e59, 0x1530,
+ 0x8e5a, 0x2ff2,
+ 0x8e5b, 0x2ff1,
+ 0x8e5c, 0x2fe9,
+ 0x8e5d, 0x2ff4,
+ 0x8e5e, 0x2fee,
+ 0x8e5f, 0x1534,
+ 0x8e60, 0x2feb,
+ 0x8e61, 0x2ff3,
+ 0x8e62, 0x2fea,
+ 0x8e63, 0x1531,
+ 0x8e64, 0x1533,
+ 0x8e65, 0x2fef,
+ 0x8e66, 0x1532,
+ 0x8e67, 0x2ff0,
+ 0x8e68, 0x434d,
+ 0x8e69, 0x2ff5,
+ 0x8e6a, 0x313d,
+ 0x8e6c, 0x15d3,
+ 0x8e6d, 0x313a,
+ 0x8e6f, 0x313e,
+ 0x8e71, 0x43e7,
+ 0x8e72, 0x15d0,
+ 0x8e73, 0x313c,
+ 0x8e74, 0x15d5,
+ 0x8e75, 0x3f89,
+ 0x8e76, 0x15d2,
+ 0x8e77, 0x3f7f,
+ 0x8e78, 0x313b,
+ 0x8e7a, 0x15d4,
+ 0x8e7b, 0x313f,
+ 0x8e7c, 0x15cf,
+ 0x8e7e, 0x4324,
+ 0x8e80, 0x3e57,
+ 0x8e81, 0x164d,
+ 0x8e82, 0x164f,
+ 0x8e84, 0x3240,
+ 0x8e85, 0x164e,
+ 0x8e86, 0x323e,
+ 0x8e87, 0x15d1,
+ 0x8e88, 0x323f,
+ 0x8e89, 0x164c,
+ 0x8e8a, 0x1693,
+ 0x8e8b, 0x1695,
+ 0x8e8c, 0x331a,
+ 0x8e8d, 0x1694,
+ 0x8e8e, 0x3319,
+ 0x8e90, 0x33c1,
+ 0x8e91, 0x16db,
+ 0x8e92, 0x33c0,
+ 0x8e93, 0x16dc,
+ 0x8e94, 0x33be,
+ 0x8e95, 0x33bd,
+ 0x8e96, 0x33c2,
+ 0x8e98, 0x3443,
+ 0x8e9a, 0x33bf,
+ 0x8e9d, 0x34a1,
+ 0x8e9e, 0x349e,
+ 0x8ea1, 0x1749,
+ 0x8ea3, 0x34eb,
+ 0x8ea4, 0x34ea,
+ 0x8ea5, 0x34e9,
+ 0x8ea6, 0x350a,
+ 0x8ea7, 0x3bb5,
+ 0x8ea8, 0x3537,
+ 0x8ea9, 0x3524,
+ 0x8eaa, 0x175b,
+ 0x8eab, 0x0512,
+ 0x8eac, 0x09cf,
+ 0x8ead, 0x385e,
+ 0x8eb0, 0x43e9,
+ 0x8eb2, 0x0f2f,
+ 0x8eb6, 0x385f,
+ 0x8eba, 0x123d,
+ 0x8ebc, 0x38a0,
+ 0x8ebd, 0x2cad,
+ 0x8ec0, 0x1536,
+ 0x8ec2, 0x3140,
+ 0x8ec3, 0x3860,
+ 0x8ec9, 0x3525,
+ 0x8eca, 0x0513,
+ 0x8ecb, 0x068d,
+ 0x8ecc, 0x0810,
+ 0x8ecd, 0x080f,
+ 0x8ece, 0x4788,
+ 0x8ecf, 0x09d2,
+ 0x8ed1, 0x1e13,
+ 0x8ed2, 0x09d0,
+ 0x8ed3, 0x1e14,
+ 0x8ed4, 0x09d1,
+ 0x8ed7, 0x207d,
+ 0x8ed8, 0x2079,
+ 0x8eda, 0x3dbe,
+ 0x8edb, 0x0bb3,
+ 0x8edc, 0x207c,
+ 0x8edd, 0x207b,
+ 0x8ede, 0x207a,
+ 0x8edf, 0x0bb4,
+ 0x8ee0, 0x207e,
+ 0x8ee2, 0x4789,
+ 0x8ee4, 0x478a,
+ 0x8ee5, 0x2315,
+ 0x8ee6, 0x2313,
+ 0x8ee7, 0x2317,
+ 0x8ee9, 0x231e,
+ 0x8eeb, 0x231a,
+ 0x8eec, 0x231c,
+ 0x8eed, 0x478b,
+ 0x8eee, 0x2314,
+ 0x8eef, 0x230f,
+ 0x8ef1, 0x231b,
+ 0x8ef2, 0x478c,
+ 0x8ef4, 0x231d,
+ 0x8ef5, 0x2316,
+ 0x8ef6, 0x2319,
+ 0x8ef7, 0x2310,
+ 0x8ef8, 0x0d7f,
+ 0x8ef9, 0x2312,
+ 0x8efa, 0x2311,
+ 0x8efb, 0x0d7e,
+ 0x8efc, 0x0d80,
+ 0x8efe, 0x0f32,
+ 0x8eff, 0x25ba,
+ 0x8f00, 0x25bc,
+ 0x8f01, 0x25bb,
+ 0x8f02, 0x25c0,
+ 0x8f03, 0x0f30,
+ 0x8f05, 0x25bd,
+ 0x8f06, 0x25b9,
+ 0x8f07, 0x25be,
+ 0x8f09, 0x0f31,
+ 0x8f0a, 0x0f33,
+ 0x8f0b, 0x25c1,
+ 0x8f0d, 0x2820,
+ 0x8f0e, 0x281f,
+ 0x8f10, 0x281d,
+ 0x8f12, 0x10bf,
+ 0x8f13, 0x10c1,
+ 0x8f14, 0x10be,
+ 0x8f15, 0x10c0,
+ 0x8f16, 0x2a7a,
+ 0x8f18, 0x2a76,
+ 0x8f19, 0x3862,
+ 0x8f1a, 0x2a77,
+ 0x8f1b, 0x123f,
+ 0x8f1c, 0x1244,
+ 0x8f1d, 0x123e,
+ 0x8f1e, 0x1245,
+ 0x8f1f, 0x1240,
+ 0x8f20, 0x2a78,
+ 0x8f23, 0x2a79,
+ 0x8f24, 0x2a75,
+ 0x8f25, 0x1246,
+ 0x8f26, 0x1242,
+ 0x8f29, 0x1241,
+ 0x8f2a, 0x1243,
+ 0x8f2c, 0x2a74,
+ 0x8f2d, 0x3863,
+ 0x8f2e, 0x2caf,
+ 0x8f2f, 0x1368,
+ 0x8f30, 0x3bb7,
+ 0x8f32, 0x2cb1,
+ 0x8f33, 0x136a,
+ 0x8f34, 0x2cb4,
+ 0x8f35, 0x2cb0,
+ 0x8f36, 0x2cae,
+ 0x8f37, 0x2cb3,
+ 0x8f38, 0x1369,
+ 0x8f39, 0x2cb2,
+ 0x8f3b, 0x1367,
+ 0x8f3e, 0x148e,
+ 0x8f3f, 0x1491,
+ 0x8f40, 0x2e7c,
+ 0x8f41, 0x3d07,
+ 0x8f42, 0x148f,
+ 0x8f43, 0x2e7b,
+ 0x8f44, 0x148d,
+ 0x8f45, 0x1490,
+ 0x8f46, 0x2ff7,
+ 0x8f49, 0x1537,
+ 0x8f4a, 0x3bb8,
+ 0x8f4b, 0x2ffa,
+ 0x8f4d, 0x1538,
+ 0x8f4e, 0x15d7,
+ 0x8f4f, 0x3143,
+ 0x8f51, 0x3142,
+ 0x8f52, 0x3141,
+ 0x8f53, 0x3145,
+ 0x8f54, 0x15d6,
+ 0x8f55, 0x3244,
+ 0x8f56, 0x3242,
+ 0x8f58, 0x3245,
+ 0x8f59, 0x3241,
+ 0x8f5a, 0x3246,
+ 0x8f5b, 0x331c,
+ 0x8f5c, 0x3f31,
+ 0x8f5d, 0x331d,
+ 0x8f5e, 0x331b,
+ 0x8f5f, 0x1696,
+ 0x8f60, 0x33c4,
+ 0x8f61, 0x16dd,
+ 0x8f62, 0x33c5,
+ 0x8f63, 0x3445,
+ 0x8f64, 0x3444,
+ 0x8f66, 0x4569,
+ 0x8f6e, 0x456b,
+ 0x8f93, 0x4732,
+ 0x8f9b, 0x0514,
+ 0x8f9c, 0x0d81,
+ 0x8f9f, 0x0f34,
+ 0x8fa0, 0x3d94,
+ 0x8fa3, 0x10c2,
+ 0x8fa5, 0x3866,
+ 0x8fa6, 0x136c,
+ 0x8fa8, 0x136b,
+ 0x8fad, 0x15d8,
+ 0x8fae, 0x162f,
+ 0x8faf, 0x1697,
+ 0x8fb0, 0x0515,
+ 0x8fb1, 0x09d3,
+ 0x8fb2, 0x0f35,
+ 0x8fb3, 0x386a,
+ 0x8fb4, 0x3146,
+ 0x8fb5, 0x0230,
+ 0x8fb6, 0x47d3,
+ 0x8fb7, 0x43fd,
+ 0x8fb8, 0x42f6,
+ 0x8fb9, 0x48c9,
+ 0x8fba, 0x48c7,
+ 0x8fbb, 0x3d6b,
+ 0x8fbe, 0x48c6,
+ 0x8fbf, 0x18e9,
+ 0x8fc1, 0x478d,
+ 0x8fc2, 0x0516,
+ 0x8fc4, 0x0519,
+ 0x8fc5, 0x0518,
+ 0x8fc6, 0x0517,
+ 0x8fc9, 0x18e8,
+ 0x8fca, 0x478e,
+ 0x8fcb, 0x1a4a,
+ 0x8fcc, 0x478f,
+ 0x8fcd, 0x1a4c,
+ 0x8fce, 0x068e,
+ 0x8fd0, 0x48ae,
+ 0x8fd1, 0x0690,
+ 0x8fd2, 0x1a49,
+ 0x8fd3, 0x1a4b,
+ 0x8fd4, 0x068f,
+ 0x8fd5, 0x1a4e,
+ 0x8fd6, 0x1a4d,
+ 0x8fd7, 0x1a4f,
+ 0x8fda, 0x3fcb,
+ 0x8fe0, 0x1c0a,
+ 0x8fe1, 0x1c08,
+ 0x8fe2, 0x0813,
+ 0x8fe3, 0x1c07,
+ 0x8fe4, 0x0818,
+ 0x8fe5, 0x0815,
+ 0x8fe6, 0x0812,
+ 0x8fe8, 0x0819,
+ 0x8fea, 0x0814,
+ 0x8feb, 0x0817,
+ 0x8fed, 0x0816,
+ 0x8fee, 0x1c09,
+ 0x8ff0, 0x0811,
+ 0x8ff4, 0x09d9,
+ 0x8ff5, 0x1e16,
+ 0x8ff6, 0x1e1c,
+ 0x8ff7, 0x09d6,
+ 0x8ff8, 0x09dd,
+ 0x8ff9, 0x3871,
+ 0x8ffa, 0x09d8,
+ 0x8ffb, 0x1e19,
+ 0x8ffc, 0x1e1b,
+ 0x8ffd, 0x09db,
+ 0x8ffe, 0x1e15,
+ 0x8fff, 0x1e18,
+ 0x9000, 0x09d7,
+ 0x9001, 0x09d4,
+ 0x9002, 0x1e17,
+ 0x9003, 0x09da,
+ 0x9004, 0x1e1a,
+ 0x9005, 0x09dc,
+ 0x9006, 0x09d5,
+ 0x9008, 0x3ee0,
+ 0x900b, 0x2081,
+ 0x900c, 0x2084,
+ 0x900d, 0x0bb6,
+ 0x900f, 0x0bc0,
+ 0x9010, 0x0bbc,
+ 0x9011, 0x2082,
+ 0x9012, 0x3e4e,
+ 0x9014, 0x0bc4,
+ 0x9015, 0x0bbd,
+ 0x9016, 0x0bc2,
+ 0x9017, 0x0bb8,
+ 0x9019, 0x0bb5,
+ 0x901a, 0x0bb7,
+ 0x901b, 0x0bc3,
+ 0x901c, 0x2083,
+ 0x901d, 0x0bbb,
+ 0x901e, 0x0bbe,
+ 0x901f, 0x0bba,
+ 0x9020, 0x0bbf,
+ 0x9021, 0x2085,
+ 0x9022, 0x0bc1,
+ 0x9023, 0x0bb9,
+ 0x9024, 0x2080,
+ 0x902d, 0x231f,
+ 0x902e, 0x0d82,
+ 0x902f, 0x2321,
+ 0x9031, 0x0d84,
+ 0x9032, 0x0d86,
+ 0x9033, 0x4790,
+ 0x9034, 0x2320,
+ 0x9035, 0x0d83,
+ 0x9036, 0x0d87,
+ 0x9037, 0x3876,
+ 0x9038, 0x0d85,
+ 0x903c, 0x0f3b,
+ 0x903d, 0x25c6,
+ 0x903e, 0x0f43,
+ 0x903f, 0x25c3,
+ 0x9041, 0x0f44,
+ 0x9042, 0x0f39,
+ 0x9044, 0x25c4,
+ 0x9047, 0x0f3e,
+ 0x9049, 0x25c5,
+ 0x904a, 0x0f37,
+ 0x904b, 0x0f36,
+ 0x904c, 0x3f10,
+ 0x904d, 0x0f41,
+ 0x904e, 0x0f40,
+ 0x904f, 0x0f3f,
+ 0x9050, 0x0f3d,
+ 0x9051, 0x0f42,
+ 0x9052, 0x25c2,
+ 0x9053, 0x0f38,
+ 0x9054, 0x0f3a,
+ 0x9055, 0x0f3c,
+ 0x9056, 0x3dd2,
+ 0x9058, 0x10c4,
+ 0x9059, 0x10c7,
+ 0x905b, 0x10cb,
+ 0x905c, 0x10c5,
+ 0x905d, 0x10ca,
+ 0x905e, 0x10c8,
+ 0x9060, 0x10c3,
+ 0x9061, 0x3879,
+ 0x9062, 0x10c9,
+ 0x9063, 0x10c6,
+ 0x9064, 0x3c68,
+ 0x9067, 0x2a7f,
+ 0x9068, 0x1249,
+ 0x9069, 0x1247,
+ 0x906b, 0x2a80,
+ 0x906c, 0x3d60,
+ 0x906d, 0x124a,
+ 0x906e, 0x1248,
+ 0x906f, 0x2a7e,
+ 0x9070, 0x2a7d,
+ 0x9072, 0x1370,
+ 0x9073, 0x2a7c,
+ 0x9074, 0x136e,
+ 0x9075, 0x136d,
+ 0x9076, 0x2cb5,
+ 0x9077, 0x124b,
+ 0x9078, 0x136f,
+ 0x9079, 0x2cb6,
+ 0x907a, 0x1372,
+ 0x907b, 0x2cb7,
+ 0x907c, 0x1371,
+ 0x907d, 0x1493,
+ 0x907e, 0x2e7e,
+ 0x907f, 0x1492,
+ 0x9080, 0x1497,
+ 0x9081, 0x1495,
+ 0x9083, 0x153a,
+ 0x9084, 0x1494,
+ 0x9085, 0x2e7d,
+ 0x9086, 0x2cb8,
+ 0x9087, 0x1539,
+ 0x9088, 0x153b,
+ 0x908a, 0x15d9,
+ 0x908d, 0x3247,
+ 0x908f, 0x170c,
+ 0x9090, 0x170b,
+ 0x9091, 0x051b,
+ 0x9094, 0x181e,
+ 0x9095, 0x09de,
+ 0x9097, 0x181b,
+ 0x9099, 0x181a,
+ 0x909b, 0x181d,
+ 0x909e, 0x18ed,
+ 0x909f, 0x18ea,
+ 0x90a0, 0x18ef,
+ 0x90a1, 0x18eb,
+ 0x90a2, 0x051c,
+ 0x90a3, 0x051f,
+ 0x90a5, 0x18ec,
+ 0x90a6, 0x051e,
+ 0x90a7, 0x18ee,
+ 0x90a8, 0x387c,
+ 0x90aa, 0x051d,
+ 0x90ae, 0x3880,
+ 0x90af, 0x1a52,
+ 0x90b0, 0x1a54,
+ 0x90b1, 0x0693,
+ 0x90b2, 0x1a50,
+ 0x90b3, 0x1a53,
+ 0x90b4, 0x1a51,
+ 0x90b5, 0x0691,
+ 0x90b6, 0x0694,
+ 0x90b8, 0x0692,
+ 0x90bb, 0x3bc4,
+ 0x90bd, 0x1c0c,
+ 0x90be, 0x1c10,
+ 0x90bf, 0x1c0d,
+ 0x90c1, 0x081c,
+ 0x90c3, 0x081d,
+ 0x90c4, 0x387e,
+ 0x90c5, 0x1c0f,
+ 0x90c7, 0x1c11,
+ 0x90c8, 0x1c13,
+ 0x90ca, 0x081a,
+ 0x90cb, 0x1c12,
+ 0x90ce, 0x081b,
+ 0x90d4, 0x208c,
+ 0x90d5, 0x1c0e,
+ 0x90d6, 0x1e1d,
+ 0x90d7, 0x1e26,
+ 0x90d8, 0x1e24,
+ 0x90d9, 0x1e1f,
+ 0x90db, 0x1e25,
+ 0x90dc, 0x1e27,
+ 0x90dd, 0x09e0,
+ 0x90df, 0x1e22,
+ 0x90e0, 0x1e1e,
+ 0x90e1, 0x09df,
+ 0x90e2, 0x09e1,
+ 0x90e3, 0x1e21,
+ 0x90e4, 0x1e28,
+ 0x90e5, 0x1e23,
+ 0x90e8, 0x0bc5,
+ 0x90e9, 0x208f,
+ 0x90ea, 0x2087,
+ 0x90eb, 0x208d,
+ 0x90ed, 0x0bc6,
+ 0x90ef, 0x2086,
+ 0x90f0, 0x2088,
+ 0x90f1, 0x1c0b,
+ 0x90f2, 0x208a,
+ 0x90f4, 0x2089,
+ 0x90f5, 0x0d89,
+ 0x90f9, 0x2328,
+ 0x90fa, 0x2cb9,
+ 0x90fb, 0x2329,
+ 0x90fc, 0x2326,
+ 0x90fd, 0x0bc7,
+ 0x90fe, 0x0d8b,
+ 0x90ff, 0x2325,
+ 0x9100, 0x232b,
+ 0x9101, 0x232a,
+ 0x9102, 0x0d88,
+ 0x9103, 0x232e,
+ 0x9104, 0x2324,
+ 0x9105, 0x232d,
+ 0x9106, 0x2322,
+ 0x9107, 0x232c,
+ 0x9108, 0x2327,
+ 0x9109, 0x0d8a,
+ 0x910b, 0x25cd,
+ 0x910d, 0x25c8,
+ 0x910e, 0x25ce,
+ 0x910f, 0x25c9,
+ 0x9110, 0x25c7,
+ 0x9111, 0x25ca,
+ 0x9112, 0x0f45,
+ 0x9114, 0x25cc,
+ 0x9116, 0x25cb,
+ 0x9117, 0x0f46,
+ 0x9118, 0x10cd,
+ 0x9119, 0x10cc,
+ 0x911a, 0x2827,
+ 0x911b, 0x282a,
+ 0x911c, 0x2822,
+ 0x911d, 0x2826,
+ 0x911e, 0x10ce,
+ 0x911f, 0x2825,
+ 0x9120, 0x2823,
+ 0x9121, 0x2829,
+ 0x9122, 0x2824,
+ 0x9123, 0x2821,
+ 0x9124, 0x2828,
+ 0x9126, 0x2a86,
+ 0x9127, 0x124e,
+ 0x9128, 0x2ffb,
+ 0x9129, 0x2a83,
+ 0x912b, 0x2a82,
+ 0x912c, 0x2323,
+ 0x912d, 0x124d,
+ 0x912e, 0x2a87,
+ 0x912f, 0x2a81,
+ 0x9130, 0x124c,
+ 0x9131, 0x124f,
+ 0x9132, 0x2a85,
+ 0x9133, 0x2cba,
+ 0x9134, 0x1373,
+ 0x9135, 0x2cbb,
+ 0x9138, 0x2e7f,
+ 0x9139, 0x1498,
+ 0x913a, 0x2ffc,
+ 0x913e, 0x2ffe,
+ 0x913f, 0x3148,
+ 0x9140, 0x3147,
+ 0x9141, 0x3249,
+ 0x9143, 0x3248,
+ 0x9144, 0x331f,
+ 0x9146, 0x331e,
+ 0x9147, 0x33c6,
+ 0x9148, 0x16de,
+ 0x9149, 0x0520,
+ 0x914a, 0x081f,
+ 0x914b, 0x081e,
+ 0x914c, 0x09e4,
+ 0x914d, 0x09e3,
+ 0x914e, 0x1e2a,
+ 0x9150, 0x1e29,
+ 0x9151, 0x3f49,
+ 0x9152, 0x09e2,
+ 0x9153, 0x2093,
+ 0x9155, 0x2094,
+ 0x9156, 0x2090,
+ 0x9157, 0x0bc8,
+ 0x9158, 0x2091,
+ 0x9159, 0x3f45,
+ 0x915a, 0x2092,
+ 0x915c, 0x3f47,
+ 0x915e, 0x43eb,
+ 0x915f, 0x2331,
+ 0x9160, 0x2333,
+ 0x9161, 0x232f,
+ 0x9162, 0x2332,
+ 0x9163, 0x0d8c,
+ 0x9164, 0x2330,
+ 0x9165, 0x0d8d,
+ 0x9167, 0x3882,
+ 0x9168, 0x23e2,
+ 0x9169, 0x0f49,
+ 0x916a, 0x0f48,
+ 0x916c, 0x0f47,
+ 0x916e, 0x25cf,
+ 0x9170, 0x3eb8,
+ 0x9172, 0x282c,
+ 0x9173, 0x282e,
+ 0x9174, 0x10d2,
+ 0x9175, 0x10cf,
+ 0x9176, 0x3e9b,
+ 0x9177, 0x10d1,
+ 0x9178, 0x10d0,
+ 0x9179, 0x282d,
+ 0x917a, 0x282b,
+ 0x917c, 0x3f6f,
+ 0x9180, 0x2a8e,
+ 0x9181, 0x2a8b,
+ 0x9183, 0x1253,
+ 0x9184, 0x2a8d,
+ 0x9185, 0x2a88,
+ 0x9187, 0x1250,
+ 0x9189, 0x1251,
+ 0x918a, 0x2a8a,
+ 0x918b, 0x1252,
+ 0x918c, 0x43ec,
+ 0x918d, 0x2cc0,
+ 0x918e, 0x3f4e,
+ 0x918f, 0x2cc1,
+ 0x9190, 0x2cbe,
+ 0x9192, 0x1374,
+ 0x9193, 0x2cbd,
+ 0x9199, 0x2e83,
+ 0x919a, 0x2e80,
+ 0x919b, 0x2e82,
+ 0x919c, 0x149b,
+ 0x919d, 0x2e86,
+ 0x919e, 0x149a,
+ 0x919f, 0x2e84,
+ 0x91a0, 0x2e87,
+ 0x91a1, 0x2e85,
+ 0x91a2, 0x2e81,
+ 0x91a3, 0x1499,
+ 0x91a5, 0x3000,
+ 0x91a7, 0x3001,
+ 0x91a8, 0x2fff,
+ 0x91a9, 0x3883,
+ 0x91aa, 0x3003,
+ 0x91ab, 0x153c,
+ 0x91ad, 0x314a,
+ 0x91ae, 0x15dc,
+ 0x91af, 0x3002,
+ 0x91b0, 0x3149,
+ 0x91b1, 0x15db,
+ 0x91b2, 0x324c,
+ 0x91b4, 0x1650,
+ 0x91b5, 0x324b,
+ 0x91b6, 0x45ef,
+ 0x91b7, 0x324a,
+ 0x91b9, 0x3321,
+ 0x91ba, 0x1698,
+ 0x91bb, 0x3bc8,
+ 0x91bc, 0x3446,
+ 0x91bd, 0x34a3,
+ 0x91be, 0x34a2,
+ 0x91c0, 0x1730,
+ 0x91c1, 0x174a,
+ 0x91c2, 0x34a4,
+ 0x91c3, 0x350b,
+ 0x91c4, 0x3884,
+ 0x91c5, 0x175c,
+ 0x91c6, 0x0521,
+ 0x91c7, 0x0695,
+ 0x91c9, 0x0f4a,
+ 0x91cb, 0x1651,
+ 0x91cc, 0x0522,
+ 0x91cd, 0x0820,
+ 0x91ce, 0x0bc9,
+ 0x91cf, 0x0d8e,
+ 0x91d0, 0x153e,
+ 0x91d1, 0x0696,
+ 0x91d3, 0x1c15,
+ 0x91d4, 0x1c14,
+ 0x91d5, 0x1e2c,
+ 0x91d6, 0x415e,
+ 0x91d7, 0x09e7,
+ 0x91d8, 0x09e5,
+ 0x91d9, 0x09e9,
+ 0x91da, 0x1e2e,
+ 0x91dc, 0x09e8,
+ 0x91dd, 0x09e6,
+ 0x91df, 0x453a,
+ 0x91e2, 0x1e2d,
+ 0x91e3, 0x0bcc,
+ 0x91e4, 0x209a,
+ 0x91e5, 0x3c06,
+ 0x91e6, 0x0bcb,
+ 0x91e7, 0x0bcd,
+ 0x91e8, 0x209f,
+ 0x91e9, 0x0bcf,
+ 0x91ea, 0x209c,
+ 0x91ec, 0x2095,
+ 0x91ed, 0x0bce,
+ 0x91ee, 0x20a0,
+ 0x91f1, 0x2097,
+ 0x91f3, 0x2098,
+ 0x91f4, 0x2096,
+ 0x91f5, 0x0bca,
+ 0x91f7, 0x209e,
+ 0x91f8, 0x2099,
+ 0x91f9, 0x209b,
+ 0x91fa, 0x3af8,
+ 0x91fd, 0x233f,
+ 0x91fe, 0x382e,
+ 0x91ff, 0x233e,
+ 0x9200, 0x233c,
+ 0x9201, 0x2334,
+ 0x9202, 0x2343,
+ 0x9203, 0x2337,
+ 0x9204, 0x2341,
+ 0x9205, 0x2348,
+ 0x9206, 0x2340,
+ 0x9207, 0x0d96,
+ 0x9208, 0x3eb9,
+ 0x9209, 0x0d92,
+ 0x920a, 0x2335,
+ 0x920c, 0x233b,
+ 0x920d, 0x0d94,
+ 0x920e, 0x3888,
+ 0x920f, 0x233a,
+ 0x9210, 0x0d95,
+ 0x9211, 0x0d97,
+ 0x9212, 0x233d,
+ 0x9213, 0x4793,
+ 0x9214, 0x0d8f,
+ 0x9216, 0x2349,
+ 0x9217, 0x2347,
+ 0x9219, 0x2346,
+ 0x921a, 0x2338,
+ 0x921c, 0x2344,
+ 0x921e, 0x0d93,
+ 0x9223, 0x0d91,
+ 0x9224, 0x2345,
+ 0x9225, 0x2336,
+ 0x9226, 0x2339,
+ 0x9227, 0x2342,
+ 0x9228, 0x4795,
+ 0x922a, 0x3c0e,
+ 0x922b, 0x3ba6,
+ 0x922d, 0x2851,
+ 0x922e, 0x25da,
+ 0x9230, 0x25d3,
+ 0x9231, 0x25e6,
+ 0x9232, 0x25ef,
+ 0x9233, 0x25d6,
+ 0x9234, 0x0f55,
+ 0x9235, 0x3b26,
+ 0x9236, 0x25e3,
+ 0x9237, 0x0f4b,
+ 0x9238, 0x0f4d,
+ 0x9239, 0x0f59,
+ 0x923a, 0x25d4,
+ 0x923c, 0x41d2,
+ 0x923d, 0x0f4e,
+ 0x923e, 0x0f50,
+ 0x923f, 0x0f5a,
+ 0x9240, 0x0f4f,
+ 0x9241, 0x388a,
+ 0x9244, 0x389a,
+ 0x9245, 0x0f58,
+ 0x9246, 0x25dc,
+ 0x9248, 0x25d1,
+ 0x9249, 0x0f56,
+ 0x924a, 0x25db,
+ 0x924b, 0x0f52,
+ 0x924c, 0x25ed,
+ 0x924d, 0x0f57,
+ 0x924e, 0x25eb,
+ 0x924f, 0x25df,
+ 0x9250, 0x25e9,
+ 0x9251, 0x0f54,
+ 0x9252, 0x25d2,
+ 0x9253, 0x25ec,
+ 0x9254, 0x25e7,
+ 0x9255, 0x3e47,
+ 0x9256, 0x25ee,
+ 0x9257, 0x0f4c,
+ 0x9258, 0x4796,
+ 0x925a, 0x0f5b,
+ 0x925b, 0x0f51,
+ 0x925d, 0x3a03,
+ 0x925e, 0x25d8,
+ 0x925f, 0x3ce0,
+ 0x9260, 0x25e0,
+ 0x9261, 0x25e4,
+ 0x9262, 0x388b,
+ 0x9263, 0x25e8,
+ 0x9264, 0x0f53,
+ 0x9265, 0x25d7,
+ 0x9266, 0x25d5,
+ 0x9267, 0x25e1,
+ 0x926b, 0x4797,
+ 0x926c, 0x25de,
+ 0x926d, 0x25dd,
+ 0x926e, 0x3d05,
+ 0x926f, 0x25e2,
+ 0x9270, 0x25e5,
+ 0x9272, 0x25ea,
+ 0x9276, 0x2831,
+ 0x9277, 0x3c64,
+ 0x9278, 0x10d3,
+ 0x9279, 0x283b,
+ 0x927a, 0x2833,
+ 0x927b, 0x10d9,
+ 0x927c, 0x10dd,
+ 0x927d, 0x2844,
+ 0x927e, 0x284c,
+ 0x927f, 0x283d,
+ 0x9280, 0x10d5,
+ 0x9281, 0x3e01,
+ 0x9282, 0x2841,
+ 0x9283, 0x25d9,
+ 0x9284, 0x3cb9,
+ 0x9285, 0x10d6,
+ 0x9286, 0x2848,
+ 0x9287, 0x284d,
+ 0x9288, 0x2845,
+ 0x9289, 0x3ab5,
+ 0x928a, 0x2847,
+ 0x928b, 0x2850,
+ 0x928c, 0x2849,
+ 0x928d, 0x2837,
+ 0x928e, 0x2840,
+ 0x928f, 0x46bd,
+ 0x9291, 0x10de,
+ 0x9293, 0x10da,
+ 0x9294, 0x2835,
+ 0x9295, 0x2842,
+ 0x9296, 0x10d8,
+ 0x9297, 0x283c,
+ 0x9298, 0x10d7,
+ 0x9299, 0x284a,
+ 0x929a, 0x2839,
+ 0x929b, 0x2832,
+ 0x929c, 0x10db,
+ 0x929d, 0x284f,
+ 0x92a0, 0x2834,
+ 0x92a1, 0x2846,
+ 0x92a2, 0x2843,
+ 0x92a3, 0x283e,
+ 0x92a4, 0x2830,
+ 0x92a5, 0x282f,
+ 0x92a6, 0x2838,
+ 0x92a7, 0x284b,
+ 0x92a8, 0x10dc,
+ 0x92a9, 0x284e,
+ 0x92aa, 0x2836,
+ 0x92ab, 0x283a,
+ 0x92ac, 0x10d4,
+ 0x92ae, 0x4799,
+ 0x92b1, 0x4798,
+ 0x92b2, 0x125f,
+ 0x92b3, 0x125a,
+ 0x92b4, 0x2ab0,
+ 0x92b5, 0x2aac,
+ 0x92b6, 0x2a94,
+ 0x92b7, 0x1256,
+ 0x92b9, 0x36e9,
+ 0x92ba, 0x3bf5,
+ 0x92bb, 0x1255,
+ 0x92bc, 0x125b,
+ 0x92be, 0x3c60,
+ 0x92bf, 0x479a,
+ 0x92c0, 0x2a92,
+ 0x92c1, 0x1259,
+ 0x92c2, 0x2a9e,
+ 0x92c3, 0x2a90,
+ 0x92c5, 0x1254,
+ 0x92c6, 0x2aaf,
+ 0x92c7, 0x125d,
+ 0x92c8, 0x2aa1,
+ 0x92c9, 0x2aa6,
+ 0x92ca, 0x2aa0,
+ 0x92cb, 0x2cd3,
+ 0x92cc, 0x2a9c,
+ 0x92cd, 0x2aa4,
+ 0x92ce, 0x2aa2,
+ 0x92cf, 0x2a95,
+ 0x92d0, 0x2a8f,
+ 0x92d1, 0x2aaa,
+ 0x92d2, 0x125c,
+ 0x92d3, 0x2aab,
+ 0x92d4, 0x3861,
+ 0x92d5, 0x2aa5,
+ 0x92d7, 0x2a9a,
+ 0x92d8, 0x2a98,
+ 0x92d9, 0x2a93,
+ 0x92db, 0x400c,
+ 0x92dd, 0x2a9b,
+ 0x92de, 0x2aa8,
+ 0x92df, 0x2a97,
+ 0x92e0, 0x2aa7,
+ 0x92e1, 0x2aad,
+ 0x92e3, 0x479b,
+ 0x92e4, 0x1258,
+ 0x92e5, 0x3ca2,
+ 0x92e6, 0x2aa3,
+ 0x92e7, 0x2aa9,
+ 0x92e8, 0x2a9f,
+ 0x92e9, 0x2a99,
+ 0x92ea, 0x1257,
+ 0x92eb, 0x479c,
+ 0x92ec, 0x3964,
+ 0x92ee, 0x283f,
+ 0x92ef, 0x2a9d,
+ 0x92f0, 0x125e,
+ 0x92f1, 0x2a96,
+ 0x92f2, 0x3ab2,
+ 0x92f3, 0x479d,
+ 0x92f6, 0x3c04,
+ 0x92f7, 0x2cd8,
+ 0x92f8, 0x1377,
+ 0x92f9, 0x2cd7,
+ 0x92fa, 0x2cd5,
+ 0x92fb, 0x2ce7,
+ 0x92fc, 0x137b,
+ 0x92fd, 0x479f,
+ 0x92fe, 0x2ce4,
+ 0x92ff, 0x2cdc,
+ 0x9300, 0x2ce6,
+ 0x9301, 0x2cce,
+ 0x9302, 0x2cda,
+ 0x9303, 0x3867,
+ 0x9304, 0x137d,
+ 0x9306, 0x2cc6,
+ 0x9307, 0x3b11,
+ 0x9308, 0x2cc4,
+ 0x9309, 0x2ce5,
+ 0x930b, 0x2ce3,
+ 0x930c, 0x2ce2,
+ 0x930d, 0x2cd2,
+ 0x930e, 0x2cd1,
+ 0x930f, 0x2cc7,
+ 0x9310, 0x137f,
+ 0x9312, 0x2ccd,
+ 0x9313, 0x2cd6,
+ 0x9314, 0x2ce1,
+ 0x9315, 0x1382,
+ 0x9316, 0x2ce8,
+ 0x9318, 0x14a3,
+ 0x9319, 0x1384,
+ 0x931a, 0x137e,
+ 0x931b, 0x2ccb,
+ 0x931d, 0x2cd4,
+ 0x931e, 0x2cc3,
+ 0x931f, 0x2cc5,
+ 0x9320, 0x1375,
+ 0x9321, 0x1381,
+ 0x9322, 0x137a,
+ 0x9323, 0x2ccc,
+ 0x9324, 0x2cdb,
+ 0x9325, 0x2aae,
+ 0x9326, 0x1380,
+ 0x9327, 0x2cc2,
+ 0x9328, 0x149e,
+ 0x9329, 0x2cdd,
+ 0x932a, 0x2ce0,
+ 0x932b, 0x137c,
+ 0x932c, 0x3892,
+ 0x932d, 0x2cd0,
+ 0x932e, 0x1383,
+ 0x932f, 0x1379,
+ 0x9330, 0x3e03,
+ 0x9331, 0x3cbd,
+ 0x9333, 0x1378,
+ 0x9334, 0x2cd9,
+ 0x9335, 0x2cdf,
+ 0x9336, 0x1376,
+ 0x9338, 0x2cc9,
+ 0x9339, 0x2cde,
+ 0x933c, 0x2cca,
+ 0x9340, 0x4155,
+ 0x9341, 0x4277,
+ 0x9342, 0x3afa,
+ 0x9343, 0x47a0,
+ 0x9344, 0x4016,
+ 0x9345, 0x3e74,
+ 0x9346, 0x2ccf,
+ 0x9347, 0x2e8d,
+ 0x9348, 0x3c61,
+ 0x9349, 0x2e92,
+ 0x934a, 0x14a0,
+ 0x934b, 0x14a2,
+ 0x934c, 0x2e98,
+ 0x934d, 0x149c,
+ 0x934e, 0x2ea6,
+ 0x934f, 0x2e9e,
+ 0x9350, 0x2e93,
+ 0x9352, 0x2e9d,
+ 0x9354, 0x14a9,
+ 0x9355, 0x2e9c,
+ 0x9356, 0x2e8c,
+ 0x9357, 0x2e9b,
+ 0x9358, 0x2e8f,
+ 0x9359, 0x2ea7,
+ 0x935a, 0x14a8,
+ 0x935b, 0x14a6,
+ 0x935c, 0x2e90,
+ 0x935e, 0x2ea3,
+ 0x935f, 0x3cbb,
+ 0x9360, 0x2e95,
+ 0x9361, 0x2ea2,
+ 0x9362, 0x4268,
+ 0x9363, 0x2ea4,
+ 0x9364, 0x2e8b,
+ 0x9365, 0x14a1,
+ 0x9366, 0x46bc,
+ 0x9367, 0x2ea5,
+ 0x9368, 0x3bf0,
+ 0x9369, 0x3961,
+ 0x936a, 0x2e99,
+ 0x936b, 0x3893,
+ 0x936c, 0x14a5,
+ 0x936d, 0x2e96,
+ 0x936e, 0x39e8,
+ 0x9370, 0x14a7,
+ 0x9371, 0x2e9f,
+ 0x9373, 0x389e,
+ 0x9374, 0x3ce4,
+ 0x9375, 0x149f,
+ 0x9376, 0x2e91,
+ 0x9377, 0x2ea0,
+ 0x9378, 0x38f9,
+ 0x9379, 0x2e9a,
+ 0x937a, 0x2cc8,
+ 0x937b, 0x2ea1,
+ 0x937c, 0x2e8e,
+ 0x937d, 0x3c25,
+ 0x937e, 0x14a4,
+ 0x9380, 0x3014,
+ 0x9381, 0x3965,
+ 0x9382, 0x149d,
+ 0x9383, 0x2e89,
+ 0x9384, 0x47a1,
+ 0x9385, 0x42bd,
+ 0x9386, 0x3cc0,
+ 0x9387, 0x3ae0,
+ 0x9388, 0x3011,
+ 0x9389, 0x300a,
+ 0x938a, 0x1540,
+ 0x938c, 0x3005,
+ 0x938d, 0x3015,
+ 0x938e, 0x300c,
+ 0x938f, 0x2e97,
+ 0x9390, 0x3d3c,
+ 0x9391, 0x3017,
+ 0x9392, 0x3006,
+ 0x9394, 0x153f,
+ 0x9395, 0x3010,
+ 0x9396, 0x1541,
+ 0x9397, 0x1549,
+ 0x9398, 0x1547,
+ 0x9399, 0x3012,
+ 0x939a, 0x1548,
+ 0x939b, 0x3008,
+ 0x939c, 0x39ac,
+ 0x939d, 0x3009,
+ 0x939e, 0x300e,
+ 0x939f, 0x3013,
+ 0x93a0, 0x3ab1,
+ 0x93a1, 0x2e88,
+ 0x93a2, 0x1542,
+ 0x93a3, 0x301c,
+ 0x93a4, 0x3019,
+ 0x93a5, 0x3160,
+ 0x93a6, 0x300f,
+ 0x93a7, 0x300b,
+ 0x93a8, 0x301a,
+ 0x93a9, 0x3155,
+ 0x93aa, 0x300d,
+ 0x93ac, 0x1545,
+ 0x93ad, 0x47a2,
+ 0x93ae, 0x1544,
+ 0x93af, 0x2e8a,
+ 0x93b0, 0x1546,
+ 0x93b1, 0x3016,
+ 0x93b2, 0x3018,
+ 0x93b3, 0x1543,
+ 0x93b4, 0x301b,
+ 0x93b5, 0x3004,
+ 0x93b7, 0x3007,
+ 0x93b8, 0x3c90,
+ 0x93ba, 0x43f7,
+ 0x93bb, 0x3c8f,
+ 0x93bd, 0x3a27,
+ 0x93bf, 0x3e2d,
+ 0x93c0, 0x315e,
+ 0x93c2, 0x314e,
+ 0x93c3, 0x15e0,
+ 0x93c4, 0x315c,
+ 0x93c6, 0x39aa,
+ 0x93c7, 0x314c,
+ 0x93c8, 0x15e1,
+ 0x93ca, 0x3157,
+ 0x93cb, 0x3966,
+ 0x93cc, 0x3153,
+ 0x93cd, 0x15e6,
+ 0x93ce, 0x315d,
+ 0x93cf, 0x314d,
+ 0x93d0, 0x3150,
+ 0x93d1, 0x15de,
+ 0x93d2, 0x315f,
+ 0x93d3, 0x40e1,
+ 0x93d4, 0x3158,
+ 0x93d5, 0x315b,
+ 0x93d6, 0x15e4,
+ 0x93d7, 0x15e9,
+ 0x93d8, 0x15e7,
+ 0x93d9, 0x3154,
+ 0x93da, 0x314f,
+ 0x93db, 0x3c5f,
+ 0x93dc, 0x15e2,
+ 0x93de, 0x314b,
+ 0x93df, 0x15df,
+ 0x93e0, 0x3a20,
+ 0x93e1, 0x15dd,
+ 0x93e2, 0x15e5,
+ 0x93e3, 0x315a,
+ 0x93e4, 0x15e8,
+ 0x93e6, 0x3156,
+ 0x93e7, 0x3161,
+ 0x93e8, 0x15ea,
+ 0x93ec, 0x3152,
+ 0x93ee, 0x3159,
+ 0x93f0, 0x423f,
+ 0x93f1, 0x42aa,
+ 0x93f3, 0x3962,
+ 0x93f5, 0x325a,
+ 0x93f6, 0x3269,
+ 0x93f7, 0x325c,
+ 0x93f8, 0x3263,
+ 0x93f9, 0x3151,
+ 0x93fa, 0x3261,
+ 0x93fb, 0x3250,
+ 0x93fc, 0x3267,
+ 0x93fd, 0x1654,
+ 0x93fe, 0x3254,
+ 0x93ff, 0x3266,
+ 0x9400, 0x325b,
+ 0x9401, 0x3cd4,
+ 0x9403, 0x1653,
+ 0x9404, 0x3bc9,
+ 0x9406, 0x326b,
+ 0x9407, 0x325d,
+ 0x9408, 0x3a25,
+ 0x9409, 0x3262,
+ 0x940a, 0x3265,
+ 0x940b, 0x324e,
+ 0x940c, 0x3268,
+ 0x940d, 0x3259,
+ 0x940e, 0x325e,
+ 0x940f, 0x3252,
+ 0x9410, 0x3256,
+ 0x9411, 0x326a,
+ 0x9412, 0x3260,
+ 0x9413, 0x324f,
+ 0x9414, 0x3253,
+ 0x9415, 0x3255,
+ 0x9416, 0x325f,
+ 0x9417, 0x47a5,
+ 0x9418, 0x1652,
+ 0x9419, 0x3258,
+ 0x941b, 0x4148,
+ 0x941d, 0x47a6,
+ 0x9420, 0x3251,
+ 0x9424, 0x3943,
+ 0x9425, 0x38d0,
+ 0x9426, 0x38a3,
+ 0x9427, 0x3bcd,
+ 0x9428, 0x3257,
+ 0x9429, 0x3325,
+ 0x942a, 0x3329,
+ 0x942b, 0x169f,
+ 0x942c, 0x332b,
+ 0x942d, 0x47a7,
+ 0x942e, 0x1699,
+ 0x9430, 0x3327,
+ 0x9431, 0x332d,
+ 0x9432, 0x169e,
+ 0x9433, 0x169a,
+ 0x9435, 0x169b,
+ 0x9436, 0x3324,
+ 0x9437, 0x332a,
+ 0x9438, 0x169d,
+ 0x9439, 0x3328,
+ 0x943a, 0x169c,
+ 0x943b, 0x3323,
+ 0x943c, 0x3264,
+ 0x943d, 0x3326,
+ 0x943e, 0x47a8,
+ 0x943f, 0x3322,
+ 0x9440, 0x332c,
+ 0x9442, 0x4272,
+ 0x9443, 0x4275,
+ 0x9444, 0x16df,
+ 0x9445, 0x33cd,
+ 0x9446, 0x33d0,
+ 0x9447, 0x33cc,
+ 0x9448, 0x33ce,
+ 0x944a, 0x33c9,
+ 0x944c, 0x33c7,
+ 0x944d, 0x3c65,
+ 0x944f, 0x33cb,
+ 0x9450, 0x33c8,
+ 0x9451, 0x16e0,
+ 0x9454, 0x47aa,
+ 0x9455, 0x3448,
+ 0x9457, 0x344a,
+ 0x9458, 0x3c30,
+ 0x945b, 0x389f,
+ 0x945d, 0x3449,
+ 0x945e, 0x344b,
+ 0x9460, 0x170e,
+ 0x9462, 0x3447,
+ 0x9463, 0x170d,
+ 0x9464, 0x170f,
+ 0x9465, 0x3dde,
+ 0x9467, 0x3ab8,
+ 0x9468, 0x34a6,
+ 0x946a, 0x1731,
+ 0x946b, 0x34a5,
+ 0x946c, 0x377e,
+ 0x946d, 0x34ed,
+ 0x946e, 0x34ec,
+ 0x946f, 0x34ee,
+ 0x9470, 0x174c,
+ 0x9471, 0x34ef,
+ 0x9472, 0x174b,
+ 0x9473, 0x34f0,
+ 0x9474, 0x350c,
+ 0x9475, 0x350f,
+ 0x9476, 0x350e,
+ 0x9477, 0x1755,
+ 0x9478, 0x350d,
+ 0x9479, 0x47ab,
+ 0x947b, 0x419b,
+ 0x947c, 0x175f,
+ 0x947d, 0x175d,
+ 0x947f, 0x1764,
+ 0x9480, 0x3539,
+ 0x9482, 0x3538,
+ 0x9483, 0x3540,
+ 0x9485, 0x4507,
+ 0x949f, 0x4885,
+ 0x94a2, 0x451b,
+ 0x94c1, 0x47e1,
+ 0x94c3, 0x47df,
+ 0x94dc, 0x47d7,
+ 0x94f6, 0x47d2,
+ 0x952d, 0x47ac,
+ 0x9547, 0x48bf,
+ 0x9577, 0x0697,
+ 0x9578, 0x4508,
+ 0x957a, 0x20a1,
+ 0x957b, 0x234a,
+ 0x957c, 0x2ab1,
+ 0x957d, 0x3162,
+ 0x957f, 0x4509,
+ 0x9580, 0x0698,
+ 0x9582, 0x0821,
+ 0x9583, 0x09ea,
+ 0x9585, 0x38a1,
+ 0x9586, 0x20a2,
+ 0x9588, 0x20a3,
+ 0x9589, 0x0bd0,
+ 0x958b, 0x0d9a,
+ 0x958c, 0x234c,
+ 0x958d, 0x234b,
+ 0x958e, 0x0d9e,
+ 0x958f, 0x0d99,
+ 0x9590, 0x234d,
+ 0x9591, 0x0d9b,
+ 0x9592, 0x0d9d,
+ 0x9593, 0x0d9c,
+ 0x9594, 0x0d98,
+ 0x9596, 0x3bd5,
+ 0x9597, 0x3bd4,
+ 0x9598, 0x0f5c,
+ 0x9599, 0x3bd2,
+ 0x959b, 0x25f3,
+ 0x959c, 0x25f1,
+ 0x959e, 0x25f2,
+ 0x959f, 0x25f0,
+ 0x95a0, 0x38a4,
+ 0x95a1, 0x10df,
+ 0x95a2, 0x47ad,
+ 0x95a3, 0x10e2,
+ 0x95a4, 0x10e4,
+ 0x95a5, 0x10e3,
+ 0x95a6, 0x38a2,
+ 0x95a7, 0x3bd3,
+ 0x95a8, 0x10e0,
+ 0x95aa, 0x4395,
+ 0x95ab, 0x2ab3,
+ 0x95ac, 0x2ab2,
+ 0x95ad, 0x1260,
+ 0x95ae, 0x2ab4,
+ 0x95b0, 0x2ab5,
+ 0x95b1, 0x1261,
+ 0x95b5, 0x2cf0,
+ 0x95b6, 0x2cee,
+ 0x95b7, 0x2ead,
+ 0x95b9, 0x2cec,
+ 0x95bb, 0x1385,
+ 0x95bc, 0x2ce9,
+ 0x95bd, 0x2cf1,
+ 0x95be, 0x2ceb,
+ 0x95bf, 0x2cef,
+ 0x95c0, 0x2ea9,
+ 0x95c3, 0x2eab,
+ 0x95c5, 0x2eac,
+ 0x95c6, 0x14ae,
+ 0x95c7, 0x2ea8,
+ 0x95c8, 0x14ad,
+ 0x95c9, 0x2eaa,
+ 0x95ca, 0x14aa,
+ 0x95cd, 0x2cea,
+ 0x95d0, 0x154c,
+ 0x95d1, 0x301f,
+ 0x95d2, 0x301d,
+ 0x95d4, 0x154a,
+ 0x95d5, 0x154d,
+ 0x95d6, 0x154b,
+ 0x95da, 0x3163,
+ 0x95dc, 0x15eb,
+ 0x95de, 0x326c,
+ 0x95df, 0x326e,
+ 0x95e0, 0x326d,
+ 0x95e1, 0x1655,
+ 0x95e2, 0x16a0,
+ 0x95e3, 0x3330,
+ 0x95e4, 0x332f,
+ 0x95e5, 0x332e,
+ 0x95e8, 0x450a,
+ 0x95f4, 0x47af,
+ 0x961c, 0x0699,
+ 0x961d, 0x4519,
+ 0x961e, 0x17b4,
+ 0x9620, 0x1821,
+ 0x9621, 0x0414,
+ 0x9622, 0x181f,
+ 0x9623, 0x1822,
+ 0x9624, 0x1820,
+ 0x9628, 0x18f1,
+ 0x962a, 0x0526,
+ 0x962c, 0x0527,
+ 0x962d, 0x18f3,
+ 0x962e, 0x0524,
+ 0x962f, 0x18f2,
+ 0x9630, 0x18f0,
+ 0x9631, 0x0525,
+ 0x9632, 0x0523,
+ 0x9633, 0x47b0,
+ 0x9638, 0x3fd1,
+ 0x9639, 0x1a55,
+ 0x963a, 0x1a58,
+ 0x963b, 0x069c,
+ 0x963c, 0x1a57,
+ 0x963d, 0x1a56,
+ 0x963f, 0x069b,
+ 0x9640, 0x069a,
+ 0x9641, 0x3f3d,
+ 0x9642, 0x069e,
+ 0x9643, 0x1a59,
+ 0x9644, 0x069d,
+ 0x9645, 0x4772,
+ 0x964a, 0x1c1a,
+ 0x964b, 0x0823,
+ 0x964e, 0x1c1b,
+ 0x964f, 0x1c17,
+ 0x9650, 0x0822,
+ 0x9651, 0x1c18,
+ 0x9653, 0x1c19,
+ 0x9654, 0x1c16,
+ 0x9656, 0x3de7,
+ 0x9658, 0x09f1,
+ 0x965b, 0x09ee,
+ 0x965c, 0x1e2f,
+ 0x965d, 0x09ef,
+ 0x965e, 0x09f2,
+ 0x965f, 0x1e30,
+ 0x9661, 0x09ed,
+ 0x9662, 0x09eb,
+ 0x9664, 0x09f0,
+ 0x9669, 0x475e,
+ 0x966a, 0x0bd1,
+ 0x966b, 0x20a6,
+ 0x966c, 0x0bd9,
+ 0x966d, 0x20a5,
+ 0x966f, 0x20a8,
+ 0x9670, 0x0bd5,
+ 0x9671, 0x20a7,
+ 0x9672, 0x0da6,
+ 0x9673, 0x0bd3,
+ 0x9674, 0x0bd6,
+ 0x9675, 0x0bd2,
+ 0x9676, 0x0bd7,
+ 0x9678, 0x0bd4,
+ 0x967b, 0x38ac,
+ 0x967c, 0x20a4,
+ 0x967d, 0x0da2,
+ 0x967e, 0x234f,
+ 0x9680, 0x2353,
+ 0x9681, 0x3f46,
+ 0x9683, 0x2352,
+ 0x9684, 0x0da7,
+ 0x9685, 0x0da3,
+ 0x9687, 0x234e,
+ 0x9688, 0x2350,
+ 0x968a, 0x0d9f,
+ 0x968b, 0x0da1,
+ 0x968d, 0x0da5,
+ 0x968e, 0x0da0,
+ 0x968f, 0x3bde,
+ 0x9691, 0x25f6,
+ 0x9692, 0x25f4,
+ 0x9694, 0x0f5e,
+ 0x9696, 0x38ad,
+ 0x9697, 0x25f7,
+ 0x9698, 0x0f5d,
+ 0x9699, 0x10e5,
+ 0x969b, 0x10e7,
+ 0x969c, 0x10e6,
+ 0x969e, 0x2852,
+ 0x96a1, 0x2853,
+ 0x96a2, 0x2ab7,
+ 0x96a3, 0x38af,
+ 0x96a4, 0x2ab6,
+ 0x96a5, 0x42ef,
+ 0x96a7, 0x1386,
+ 0x96a9, 0x2cf2,
+ 0x96aa, 0x1388,
+ 0x96ac, 0x2eb0,
+ 0x96ae, 0x2eae,
+ 0x96b0, 0x2eaf,
+ 0x96b1, 0x14af,
+ 0x96b3, 0x3020,
+ 0x96b4, 0x15ec,
+ 0x96b6, 0x0231,
+ 0x96b8, 0x14b0,
+ 0x96b9, 0x069f,
+ 0x96bb, 0x09f3,
+ 0x96bc, 0x1e31,
+ 0x96bd, 0x38b5,
+ 0x96bf, 0x20a9,
+ 0x96c0, 0x0bda,
+ 0x96c1, 0x0da8,
+ 0x96c2, 0x2354,
+ 0x96c3, 0x2356,
+ 0x96c4, 0x0daa,
+ 0x96c5, 0x0da9,
+ 0x96c6, 0x0dab,
+ 0x96c8, 0x2355,
+ 0x96c9, 0x0f62,
+ 0x96cb, 0x0f61,
+ 0x96cc, 0x10e8,
+ 0x96cd, 0x0f60,
+ 0x96ce, 0x25f8,
+ 0x96d2, 0x10e9,
+ 0x96d3, 0x2ab8,
+ 0x96d4, 0x2cf3,
+ 0x96d5, 0x1389,
+ 0x96d6, 0x14b1,
+ 0x96d7, 0x3021,
+ 0x96d8, 0x3025,
+ 0x96d9, 0x1550,
+ 0x96da, 0x3022,
+ 0x96db, 0x1551,
+ 0x96dc, 0x154f,
+ 0x96dd, 0x3026,
+ 0x96de, 0x1552,
+ 0x96df, 0x3024,
+ 0x96e1, 0x3165,
+ 0x96e2, 0x154e,
+ 0x96e3, 0x15ed,
+ 0x96e5, 0x34a8,
+ 0x96e8, 0x06a0,
+ 0x96e9, 0x0bdc,
+ 0x96ea, 0x0bdb,
+ 0x96ef, 0x0dad,
+ 0x96f0, 0x2358,
+ 0x96f1, 0x2357,
+ 0x96f2, 0x0dae,
+ 0x96f4, 0x3a04,
+ 0x96f5, 0x25fc,
+ 0x96f6, 0x0f67,
+ 0x96f7, 0x0f64,
+ 0x96f8, 0x25fb,
+ 0x96f9, 0x0f66,
+ 0x96fa, 0x25f9,
+ 0x96fb, 0x0f65,
+ 0x96fd, 0x25fa,
+ 0x96ff, 0x2854,
+ 0x9700, 0x10ea,
+ 0x9702, 0x2abb,
+ 0x9703, 0x3f0d,
+ 0x9704, 0x1262,
+ 0x9705, 0x2ab9,
+ 0x9706, 0x1263,
+ 0x9708, 0x2aba,
+ 0x9709, 0x1265,
+ 0x970b, 0x2cf4,
+ 0x970d, 0x138d,
+ 0x970e, 0x138a,
+ 0x970f, 0x138f,
+ 0x9710, 0x2cf6,
+ 0x9711, 0x138b,
+ 0x9712, 0x2cf5,
+ 0x9713, 0x138e,
+ 0x9716, 0x138c,
+ 0x9718, 0x2eb3,
+ 0x9719, 0x2eb5,
+ 0x971b, 0x38c9,
+ 0x971c, 0x14b2,
+ 0x971d, 0x2eb4,
+ 0x971e, 0x14b3,
+ 0x971f, 0x2eb2,
+ 0x9720, 0x2eb1,
+ 0x9721, 0x3fb3,
+ 0x9722, 0x3028,
+ 0x9723, 0x3027,
+ 0x9724, 0x1553,
+ 0x9725, 0x3029,
+ 0x9726, 0x316a,
+ 0x9727, 0x15ef,
+ 0x9728, 0x3169,
+ 0x9729, 0x3166,
+ 0x972a, 0x15ee,
+ 0x972b, 0x3167,
+ 0x972e, 0x326f,
+ 0x9730, 0x1656,
+ 0x9731, 0x38c0,
+ 0x9732, 0x16a3,
+ 0x9735, 0x3331,
+ 0x9736, 0x38c2,
+ 0x9738, 0x16a1,
+ 0x973a, 0x3332,
+ 0x973d, 0x16e2,
+ 0x973f, 0x33d1,
+ 0x9740, 0x47b3,
+ 0x9741, 0x3be9,
+ 0x9742, 0x1732,
+ 0x9743, 0x34aa,
+ 0x9744, 0x1734,
+ 0x9746, 0x34a9,
+ 0x9747, 0x34ab,
+ 0x9748, 0x1733,
+ 0x9749, 0x34f1,
+ 0x974b, 0x3526,
+ 0x9751, 0x44e3,
+ 0x9752, 0x06a1,
+ 0x9756, 0x0f68,
+ 0x9757, 0x38cc,
+ 0x9758, 0x2855,
+ 0x975a, 0x2abc,
+ 0x975b, 0x1390,
+ 0x975d, 0x3bef,
+ 0x975e, 0x06a2,
+ 0x975f, 0x38cf,
+ 0x9760, 0x1266,
+ 0x9761, 0x15f0,
+ 0x9762, 0x0826,
+ 0x9766, 0x1392,
+ 0x9768, 0x1710,
+ 0x9769, 0x0827,
+ 0x976a, 0x20aa,
+ 0x976c, 0x2359,
+ 0x976d, 0x3e97,
+ 0x976e, 0x235b,
+ 0x9770, 0x235a,
+ 0x9771, 0x3bfc,
+ 0x9772, 0x2600,
+ 0x9773, 0x25fd,
+ 0x9774, 0x0f69,
+ 0x9776, 0x0f6a,
+ 0x9777, 0x25fe,
+ 0x977a, 0x2857,
+ 0x977b, 0x285c,
+ 0x977c, 0x10eb,
+ 0x977d, 0x2856,
+ 0x977e, 0x2858,
+ 0x977f, 0x285f,
+ 0x9780, 0x285a,
+ 0x9781, 0x285e,
+ 0x9782, 0x285b,
+ 0x9783, 0x2859,
+ 0x9784, 0x285d,
+ 0x9785, 0x10ec,
+ 0x9787, 0x40c0,
+ 0x9788, 0x2abf,
+ 0x9789, 0x38d4,
+ 0x978a, 0x2abd,
+ 0x978b, 0x1268,
+ 0x978d, 0x1267,
+ 0x978e, 0x2abe,
+ 0x978f, 0x1269,
+ 0x9794, 0x2cf9,
+ 0x9797, 0x2cf8,
+ 0x9798, 0x1393,
+ 0x9799, 0x2cf7,
+ 0x979a, 0x2eb6,
+ 0x979b, 0x3bfb,
+ 0x979c, 0x2eb8,
+ 0x979d, 0x2eba,
+ 0x979e, 0x2eb9,
+ 0x979f, 0x38d5,
+ 0x97a0, 0x14b4,
+ 0x97a1, 0x2eb7,
+ 0x97a2, 0x3030,
+ 0x97a3, 0x1554,
+ 0x97a4, 0x302e,
+ 0x97a5, 0x3031,
+ 0x97a6, 0x1555,
+ 0x97a8, 0x302c,
+ 0x97aa, 0x302f,
+ 0x97ab, 0x302d,
+ 0x97ac, 0x302a,
+ 0x97ad, 0x1556,
+ 0x97ae, 0x302b,
+ 0x97b1, 0x38d6,
+ 0x97b2, 0x47b5,
+ 0x97b3, 0x316b,
+ 0x97b4, 0x3f33,
+ 0x97b6, 0x316d,
+ 0x97b7, 0x316c,
+ 0x97b8, 0x3d95,
+ 0x97b9, 0x3271,
+ 0x97ba, 0x3f35,
+ 0x97bb, 0x3272,
+ 0x97bd, 0x494e,
+ 0x97be, 0x38d7,
+ 0x97bf, 0x3333,
+ 0x97c0, 0x38d8,
+ 0x97c1, 0x16e5,
+ 0x97c2, 0x47b6,
+ 0x97c3, 0x16e4,
+ 0x97c4, 0x344c,
+ 0x97c6, 0x1735,
+ 0x97c7, 0x34ac,
+ 0x97c8, 0x3f2f,
+ 0x97c9, 0x1756,
+ 0x97cb, 0x0828,
+ 0x97cc, 0x0daf,
+ 0x97cd, 0x2861,
+ 0x97ce, 0x2860,
+ 0x97cf, 0x2ac1,
+ 0x97d0, 0x2ac0,
+ 0x97d2, 0x38d9,
+ 0x97d3, 0x14b5,
+ 0x97d4, 0x2ebc,
+ 0x97d5, 0x2ebb,
+ 0x97d6, 0x3034,
+ 0x97d7, 0x3032,
+ 0x97d8, 0x3035,
+ 0x97d9, 0x3033,
+ 0x97dc, 0x15f1,
+ 0x97dd, 0x316e,
+ 0x97e0, 0x38da,
+ 0x97e1, 0x3334,
+ 0x97e3, 0x33d2,
+ 0x97e5, 0x34ad,
+ 0x97e6, 0x450c,
+ 0x97ed, 0x0829,
+ 0x97ee, 0x38dc,
+ 0x97f0, 0x2cfa,
+ 0x97f1, 0x2ebd,
+ 0x97f2, 0x394d,
+ 0x97f3, 0x082a,
+ 0x97f5, 0x38e0,
+ 0x97f6, 0x10ed,
+ 0x97f8, 0x2cfb,
+ 0x97f9, 0x1557,
+ 0x97fa, 0x3036,
+ 0x97fb, 0x15f2,
+ 0x97fd, 0x3273,
+ 0x97ff, 0x16a4,
+ 0x9800, 0x344e,
+ 0x9801, 0x082b,
+ 0x9802, 0x0bdf,
+ 0x9804, 0x20ab,
+ 0x9805, 0x0db0,
+ 0x9807, 0x235c,
+ 0x9808, 0x0db2,
+ 0x980a, 0x0f6e,
+ 0x980c, 0x0f70,
+ 0x980d, 0x2602,
+ 0x980f, 0x2601,
+ 0x9810, 0x0f6b,
+ 0x9812, 0x0f6f,
+ 0x9813, 0x0f6d,
+ 0x9814, 0x4952,
+ 0x9815, 0x433c,
+ 0x9816, 0x2862,
+ 0x9817, 0x10ee,
+ 0x981b, 0x2ac8,
+ 0x981c, 0x126c,
+ 0x981d, 0x2ac3,
+ 0x981e, 0x2ac2,
+ 0x981f, 0x3c02,
+ 0x9820, 0x2ac7,
+ 0x9821, 0x126a,
+ 0x9823, 0x3e37,
+ 0x9824, 0x139a,
+ 0x9826, 0x2ac4,
+ 0x9827, 0x2ac9,
+ 0x9828, 0x2ac6,
+ 0x9829, 0x2ac5,
+ 0x982b, 0x126b,
+ 0x982d, 0x1398,
+ 0x982e, 0x3f72,
+ 0x982f, 0x2cfd,
+ 0x9830, 0x1394,
+ 0x9832, 0x2cfe,
+ 0x9833, 0x38e5,
+ 0x9834, 0x38e4,
+ 0x9835, 0x2cfc,
+ 0x9837, 0x1397,
+ 0x9838, 0x1395,
+ 0x9839, 0x1399,
+ 0x983b, 0x1396,
+ 0x9841, 0x2ebe,
+ 0x9843, 0x2ec3,
+ 0x9844, 0x2ebf,
+ 0x9845, 0x2ec2,
+ 0x9846, 0x14b6,
+ 0x9847, 0x3d96,
+ 0x9848, 0x2df2,
+ 0x9849, 0x2ec1,
+ 0x984a, 0x2ec0,
+ 0x984b, 0x38e6,
+ 0x984c, 0x155a,
+ 0x984d, 0x1558,
+ 0x984e, 0x155b,
+ 0x984f, 0x1559,
+ 0x9850, 0x3037,
+ 0x9853, 0x155c,
+ 0x9857, 0x3174,
+ 0x9858, 0x15f4,
+ 0x9859, 0x3172,
+ 0x985b, 0x15f5,
+ 0x985c, 0x3171,
+ 0x985d, 0x3173,
+ 0x985e, 0x15f3,
+ 0x985f, 0x3278,
+ 0x9860, 0x3275,
+ 0x9862, 0x3276,
+ 0x9864, 0x3335,
+ 0x9865, 0x16a6,
+ 0x9866, 0x38e7,
+ 0x9867, 0x16a5,
+ 0x9869, 0x33d4,
+ 0x986a, 0x33d3,
+ 0x986b, 0x16e6,
+ 0x986c, 0x4035,
+ 0x986f, 0x1711,
+ 0x9870, 0x1736,
+ 0x9871, 0x174d,
+ 0x9872, 0x34f2,
+ 0x9873, 0x3527,
+ 0x9875, 0x450d,
+ 0x98a8, 0x082c,
+ 0x98a9, 0x235d,
+ 0x98ac, 0x2604,
+ 0x98ad, 0x2863,
+ 0x98af, 0x10f0,
+ 0x98b1, 0x10f1,
+ 0x98b2, 0x2aca,
+ 0x98b3, 0x126d,
+ 0x98b4, 0x3f73,
+ 0x98b6, 0x14b7,
+ 0x98b7, 0x38ef,
+ 0x98b8, 0x303a,
+ 0x98b9, 0x47b8,
+ 0x98ba, 0x155d,
+ 0x98bb, 0x3177,
+ 0x98bc, 0x15f6,
+ 0x98bd, 0x3176,
+ 0x98be, 0x3178,
+ 0x98bf, 0x3175,
+ 0x98c0, 0x3338,
+ 0x98c1, 0x3279,
+ 0x98c3, 0x3b78,
+ 0x98c4, 0x1657,
+ 0x98c6, 0x3337,
+ 0x98c7, 0x38f1,
+ 0x98c8, 0x38f0,
+ 0x98c9, 0x3336,
+ 0x98ca, 0x38ee,
+ 0x98cb, 0x33d5,
+ 0x98cc, 0x3529,
+ 0x98ce, 0x450e,
+ 0x98db, 0x082d,
+ 0x98dc, 0x3c0b,
+ 0x98de, 0x450f,
+ 0x98df, 0x082e,
+ 0x98e0, 0x4792,
+ 0x98e1, 0x38f6,
+ 0x98e2, 0x09f4,
+ 0x98e3, 0x1e32,
+ 0x98e5, 0x20ac,
+ 0x98e6, 0x38f7,
+ 0x98e7, 0x0db3,
+ 0x98e9, 0x0db6,
+ 0x98ea, 0x0db4,
+ 0x98eb, 0x235e,
+ 0x98ec, 0x38f8,
+ 0x98ed, 0x0db8,
+ 0x98ef, 0x0db5,
+ 0x98f1, 0x47ba,
+ 0x98f2, 0x0db7,
+ 0x98f4, 0x0f72,
+ 0x98f5, 0x4365,
+ 0x98f6, 0x2605,
+ 0x98f9, 0x2606,
+ 0x98fa, 0x2acc,
+ 0x98fc, 0x0f71,
+ 0x98fd, 0x0f73,
+ 0x9900, 0x2866,
+ 0x9902, 0x2865,
+ 0x9903, 0x10f2,
+ 0x9905, 0x10f3,
+ 0x9907, 0x2867,
+ 0x9908, 0x2acb,
+ 0x9909, 0x10f5,
+ 0x990a, 0x126e,
+ 0x990c, 0x10f4,
+ 0x990e, 0x43ed,
+ 0x9910, 0x139b,
+ 0x9911, 0x2acd,
+ 0x9912, 0x1270,
+ 0x9913, 0x126f,
+ 0x9914, 0x2ace,
+ 0x9915, 0x2ad1,
+ 0x9916, 0x2acf,
+ 0x9918, 0x1271,
+ 0x9919, 0x47bc,
+ 0x991a, 0x13a0,
+ 0x991b, 0x139e,
+ 0x991c, 0x43ee,
+ 0x991e, 0x139d,
+ 0x991f, 0x2d00,
+ 0x9921, 0x139f,
+ 0x9924, 0x2cff,
+ 0x9925, 0x2ec4,
+ 0x9927, 0x2d01,
+ 0x9928, 0x139c,
+ 0x9929, 0x2d02,
+ 0x992a, 0x2ec7,
+ 0x992b, 0x2ec5,
+ 0x992d, 0x2ecb,
+ 0x992e, 0x1561,
+ 0x992f, 0x2eca,
+ 0x9930, 0x2ecd,
+ 0x9931, 0x2ecc,
+ 0x9932, 0x2ec9,
+ 0x9933, 0x2ec8,
+ 0x9935, 0x14b8,
+ 0x9937, 0x47bd,
+ 0x9938, 0x3bfd,
+ 0x9939, 0x38fa,
+ 0x993a, 0x303d,
+ 0x993b, 0x3c11,
+ 0x993c, 0x303c,
+ 0x993d, 0x1560,
+ 0x993e, 0x155e,
+ 0x9940, 0x3f34,
+ 0x9941, 0x303b,
+ 0x9942, 0x43ff,
+ 0x9943, 0x317b,
+ 0x9945, 0x15f7,
+ 0x9947, 0x317a,
+ 0x9948, 0x3179,
+ 0x9949, 0x15f8,
+ 0x994a, 0x3fb9,
+ 0x994b, 0x327f,
+ 0x994c, 0x327e,
+ 0x994d, 0x3c12,
+ 0x994e, 0x327c,
+ 0x9950, 0x327b,
+ 0x9951, 0x1659,
+ 0x9952, 0x1658,
+ 0x9953, 0x3280,
+ 0x9954, 0x33d6,
+ 0x9955, 0x16e7,
+ 0x9956, 0x333a,
+ 0x9957, 0x16a7,
+ 0x9958, 0x3339,
+ 0x9959, 0x327d,
+ 0x995b, 0x33d7,
+ 0x995c, 0x1712,
+ 0x995d, 0x47be,
+ 0x995e, 0x174e,
+ 0x995f, 0x34f3,
+ 0x9961, 0x352a,
+ 0x9962, 0x43ef,
+ 0x9963, 0x4510,
+ 0x9996, 0x082f,
+ 0x9997, 0x20ad,
+ 0x9998, 0x2ece,
+ 0x9999, 0x0830,
+ 0x999b, 0x3c15,
+ 0x999c, 0x2869,
+ 0x999d, 0x2868,
+ 0x999e, 0x2d03,
+ 0x99a1, 0x2ed0,
+ 0x99a3, 0x2ecf,
+ 0x99a4, 0x41c3,
+ 0x99a5, 0x1562,
+ 0x99a6, 0x317c,
+ 0x99a8, 0x165a,
+ 0x99aa, 0x3c17,
+ 0x99ab, 0x352b,
+ 0x99ac, 0x09f5,
+ 0x99ad, 0x0dba,
+ 0x99ae, 0x0db9,
+ 0x99af, 0x2607,
+ 0x99b0, 0x2609,
+ 0x99b1, 0x0f76,
+ 0x99b2, 0x2608,
+ 0x99b3, 0x0f75,
+ 0x99b4, 0x0f77,
+ 0x99b5, 0x260a,
+ 0x99b8, 0x394b,
+ 0x99b9, 0x286b,
+ 0x99ba, 0x286d,
+ 0x99bb, 0x286c,
+ 0x99bc, 0x3c22,
+ 0x99bd, 0x286f,
+ 0x99c1, 0x10f6,
+ 0x99c2, 0x286e,
+ 0x99c3, 0x286a,
+ 0x99c4, 0x3d77,
+ 0x99c5, 0x47c1,
+ 0x99c7, 0x2870,
+ 0x99c9, 0x2ad8,
+ 0x99cb, 0x2adb,
+ 0x99cc, 0x2add,
+ 0x99cd, 0x2ad3,
+ 0x99ce, 0x2ad7,
+ 0x99cf, 0x2ad4,
+ 0x99d0, 0x1273,
+ 0x99d1, 0x1276,
+ 0x99d2, 0x1278,
+ 0x99d3, 0x2ad5,
+ 0x99d5, 0x1277,
+ 0x99d6, 0x2ad9,
+ 0x99d7, 0x2adc,
+ 0x99d8, 0x2ada,
+ 0x99d9, 0x1279,
+ 0x99da, 0x3f42,
+ 0x99db, 0x1275,
+ 0x99dc, 0x2ad2,
+ 0x99dd, 0x1272,
+ 0x99df, 0x1274,
+ 0x99e1, 0x3785,
+ 0x99e2, 0x13a2,
+ 0x99e3, 0x2d09,
+ 0x99e4, 0x2d07,
+ 0x99e5, 0x2d06,
+ 0x99e6, 0x3b65,
+ 0x99e7, 0x2d0c,
+ 0x99e9, 0x2d0b,
+ 0x99ea, 0x2d0a,
+ 0x99ec, 0x2d05,
+ 0x99ed, 0x13a1,
+ 0x99ee, 0x2d04,
+ 0x99f0, 0x2d08,
+ 0x99f1, 0x13a3,
+ 0x99f4, 0x2ed3,
+ 0x99f5, 0x38ff,
+ 0x99f6, 0x2ed7,
+ 0x99f7, 0x2ed4,
+ 0x99f8, 0x2ed6,
+ 0x99f9, 0x2ed5,
+ 0x99fa, 0x2ed2,
+ 0x99fb, 0x2ed8,
+ 0x99fc, 0x2edb,
+ 0x99fd, 0x2ed9,
+ 0x99ff, 0x14ba,
+ 0x9a01, 0x14b9,
+ 0x9a02, 0x2ed1,
+ 0x9a03, 0x2edc,
+ 0x9a04, 0x3042,
+ 0x9a05, 0x3045,
+ 0x9a06, 0x3047,
+ 0x9a07, 0x3046,
+ 0x9a09, 0x3040,
+ 0x9a0a, 0x3044,
+ 0x9a0b, 0x303f,
+ 0x9a0c, 0x3900,
+ 0x9a0d, 0x3041,
+ 0x9a0e, 0x1563,
+ 0x9a0f, 0x303e,
+ 0x9a10, 0x3902,
+ 0x9a11, 0x3043,
+ 0x9a14, 0x318a,
+ 0x9a15, 0x317f,
+ 0x9a16, 0x15f9,
+ 0x9a19, 0x15fa,
+ 0x9a1a, 0x317e,
+ 0x9a1b, 0x3183,
+ 0x9a1c, 0x3189,
+ 0x9a1d, 0x3181,
+ 0x9a1e, 0x3188,
+ 0x9a1f, 0x3b6c,
+ 0x9a20, 0x3185,
+ 0x9a21, 0x3c1c,
+ 0x9a22, 0x3184,
+ 0x9a23, 0x3187,
+ 0x9a24, 0x3182,
+ 0x9a25, 0x3180,
+ 0x9a26, 0x3df2,
+ 0x9a27, 0x3186,
+ 0x9a29, 0x3287,
+ 0x9a2a, 0x3285,
+ 0x9a2b, 0x165b,
+ 0x9a2c, 0x3284,
+ 0x9a2d, 0x328a,
+ 0x9a2e, 0x3288,
+ 0x9a2f, 0x3c1e,
+ 0x9a30, 0x165c,
+ 0x9a31, 0x3283,
+ 0x9a32, 0x3281,
+ 0x9a34, 0x3282,
+ 0x9a35, 0x165e,
+ 0x9a36, 0x3286,
+ 0x9a37, 0x165d,
+ 0x9a38, 0x3289,
+ 0x9a39, 0x333b,
+ 0x9a3a, 0x3341,
+ 0x9a3b, 0x3901,
+ 0x9a3c, 0x47c3,
+ 0x9a3d, 0x333c,
+ 0x9a3e, 0x16ab,
+ 0x9a3f, 0x3342,
+ 0x9a40, 0x16aa,
+ 0x9a41, 0x3340,
+ 0x9a42, 0x333f,
+ 0x9a43, 0x16a9,
+ 0x9a44, 0x333e,
+ 0x9a45, 0x16a8,
+ 0x9a46, 0x333d,
+ 0x9a48, 0x33dd,
+ 0x9a49, 0x33df,
+ 0x9a4a, 0x33de,
+ 0x9a4c, 0x33db,
+ 0x9a4d, 0x16e9,
+ 0x9a4e, 0x33d8,
+ 0x9a4f, 0x33dc,
+ 0x9a50, 0x33e1,
+ 0x9a52, 0x33e0,
+ 0x9a53, 0x33d9,
+ 0x9a55, 0x16e8,
+ 0x9a56, 0x344f,
+ 0x9a57, 0x1715,
+ 0x9a58, 0x3903,
+ 0x9a59, 0x3450,
+ 0x9a5a, 0x1713,
+ 0x9a5c, 0x3c18,
+ 0x9a5e, 0x34ae,
+ 0x9a5f, 0x1737,
+ 0x9a60, 0x3510,
+ 0x9a62, 0x1757,
+ 0x9a63, 0x3b67,
+ 0x9a64, 0x352c,
+ 0x9a65, 0x1758,
+ 0x9a66, 0x352d,
+ 0x9a68, 0x353c,
+ 0x9a69, 0x353b,
+ 0x9a6a, 0x1767,
+ 0x9a6b, 0x3544,
+ 0x9a6c, 0x4585,
+ 0x9a8f, 0x4586,
+ 0x9aa8, 0x09f6,
+ 0x9aab, 0x260c,
+ 0x9aad, 0x260b,
+ 0x9aaf, 0x10f7,
+ 0x9ab1, 0x2871,
+ 0x9ab2, 0x4332,
+ 0x9ab3, 0x2ade,
+ 0x9ab4, 0x2d0f,
+ 0x9ab6, 0x43f0,
+ 0x9ab7, 0x127a,
+ 0x9ab8, 0x13a4,
+ 0x9ab9, 0x2d0d,
+ 0x9aba, 0x3f74,
+ 0x9abb, 0x2d10,
+ 0x9abc, 0x13a5,
+ 0x9abd, 0x3d97,
+ 0x9abe, 0x2edd,
+ 0x9abf, 0x2d0e,
+ 0x9ac0, 0x3048,
+ 0x9ac1, 0x1564,
+ 0x9ac2, 0x318b,
+ 0x9ac6, 0x328d,
+ 0x9ac7, 0x328b,
+ 0x9aca, 0x328c,
+ 0x9acd, 0x3343,
+ 0x9acf, 0x16ac,
+ 0x9ad0, 0x33e2,
+ 0x9ad1, 0x1718,
+ 0x9ad2, 0x16ea,
+ 0x9ad3, 0x1716,
+ 0x9ad5, 0x34af,
+ 0x9ad6, 0x174f,
+ 0x9ad7, 0x3faa,
+ 0x9ad8, 0x09f7,
+ 0x9adc, 0x3049,
+ 0x9adf, 0x1e33,
+ 0x9ae0, 0x3908,
+ 0x9ae1, 0x0f78,
+ 0x9ae2, 0x3909,
+ 0x9ae3, 0x2872,
+ 0x9ae6, 0x10f9,
+ 0x9ae7, 0x2873,
+ 0x9aeb, 0x2ae0,
+ 0x9aec, 0x2adf,
+ 0x9aed, 0x13a7,
+ 0x9aee, 0x127b,
+ 0x9af1, 0x2ae3,
+ 0x9af2, 0x2ae2,
+ 0x9af3, 0x2ae1,
+ 0x9af4, 0x390b,
+ 0x9af6, 0x2d11,
+ 0x9af7, 0x2d14,
+ 0x9af9, 0x2d13,
+ 0x9afa, 0x2d12,
+ 0x9afb, 0x13a6,
+ 0x9afc, 0x2ee1,
+ 0x9afd, 0x2edf,
+ 0x9afe, 0x2ede,
+ 0x9aff, 0x3f17,
+ 0x9b01, 0x2ee0,
+ 0x9b02, 0x3f12,
+ 0x9b03, 0x1565,
+ 0x9b04, 0x304b,
+ 0x9b06, 0x1566,
+ 0x9b08, 0x304a,
+ 0x9b09, 0x3f20,
+ 0x9b0a, 0x318d,
+ 0x9b0b, 0x318c,
+ 0x9b0c, 0x318f,
+ 0x9b0d, 0x15fb,
+ 0x9b0e, 0x318e,
+ 0x9b0f, 0x47c4,
+ 0x9b10, 0x328e,
+ 0x9b11, 0x3290,
+ 0x9b12, 0x328f,
+ 0x9b14, 0x390d,
+ 0x9b15, 0x3344,
+ 0x9b16, 0x3347,
+ 0x9b17, 0x3345,
+ 0x9b19, 0x33e3,
+ 0x9b1a, 0x16eb,
+ 0x9b1e, 0x3451,
+ 0x9b22, 0x1738,
+ 0x9b23, 0x1750,
+ 0x9b24, 0x352f,
+ 0x9b25, 0x09f8,
+ 0x9b27, 0x127d,
+ 0x9b28, 0x13a8,
+ 0x9b29, 0x304d,
+ 0x9b2a, 0x3f19,
+ 0x9b2b, 0x33e4,
+ 0x9b2d, 0x390e,
+ 0x9b2e, 0x3511,
+ 0x9b2f, 0x1e34,
+ 0x9b31, 0x1768,
+ 0x9b32, 0x09f9,
+ 0x9b33, 0x2d15,
+ 0x9b34, 0x3911,
+ 0x9b35, 0x304e,
+ 0x9b37, 0x3190,
+ 0x9b39, 0x3f00,
+ 0x9b3a, 0x3348,
+ 0x9b3b, 0x33e5,
+ 0x9b3c, 0x09fa,
+ 0x9b3e, 0x2874,
+ 0x9b40, 0x3915,
+ 0x9b41, 0x10fa,
+ 0x9b43, 0x2ae5,
+ 0x9b44, 0x127f,
+ 0x9b45, 0x127e,
+ 0x9b46, 0x2ae4,
+ 0x9b48, 0x2ee2,
+ 0x9b4a, 0x304f,
+ 0x9b4b, 0x3051,
+ 0x9b4c, 0x3050,
+ 0x9b4d, 0x1569,
+ 0x9b4e, 0x1568,
+ 0x9b4f, 0x1567,
+ 0x9b50, 0x3914,
+ 0x9b51, 0x16ae,
+ 0x9b52, 0x3349,
+ 0x9b54, 0x16ad,
+ 0x9b55, 0x33e7,
+ 0x9b56, 0x33e6,
+ 0x9b58, 0x1739,
+ 0x9b59, 0x34b0,
+ 0x9b5a, 0x0be1,
+ 0x9b5b, 0x260d,
+ 0x9b5f, 0x2878,
+ 0x9b60, 0x2876,
+ 0x9b64, 0x2aee,
+ 0x9b66, 0x2ae9,
+ 0x9b67, 0x2ae6,
+ 0x9b68, 0x2aed,
+ 0x9b69, 0x47c5,
+ 0x9b6c, 0x2aef,
+ 0x9b6f, 0x1281,
+ 0x9b70, 0x2aec,
+ 0x9b71, 0x2ae8,
+ 0x9b74, 0x2ae7,
+ 0x9b75, 0x2aeb,
+ 0x9b76, 0x2aea,
+ 0x9b77, 0x1280,
+ 0x9b7a, 0x2d20,
+ 0x9b7b, 0x2d1b,
+ 0x9b7c, 0x2d19,
+ 0x9b7d, 0x2d22,
+ 0x9b7e, 0x2d1a,
+ 0x9b7f, 0x3c3b,
+ 0x9b80, 0x2d16,
+ 0x9b81, 0x43f1,
+ 0x9b82, 0x2d1c,
+ 0x9b83, 0x4219,
+ 0x9b85, 0x2d17,
+ 0x9b86, 0x2eeb,
+ 0x9b87, 0x2d18,
+ 0x9b88, 0x2d23,
+ 0x9b8b, 0x3eee,
+ 0x9b8d, 0x4623,
+ 0x9b8e, 0x3919,
+ 0x9b8f, 0x3fad,
+ 0x9b90, 0x2d1f,
+ 0x9b91, 0x13a9,
+ 0x9b92, 0x2d1e,
+ 0x9b93, 0x2d1d,
+ 0x9b95, 0x2d21,
+ 0x9b97, 0x3f71,
+ 0x9b9a, 0x2ee3,
+ 0x9b9b, 0x2ee6,
+ 0x9b9d, 0x3f56,
+ 0x9b9e, 0x2ee5,
+ 0x9b9f, 0x3c3e,
+ 0x9ba0, 0x2eed,
+ 0x9ba1, 0x2ee8,
+ 0x9ba2, 0x2eec,
+ 0x9ba4, 0x2eea,
+ 0x9ba5, 0x2ee9,
+ 0x9ba6, 0x2ee7,
+ 0x9ba8, 0x2ee4,
+ 0x9baa, 0x14bd,
+ 0x9bab, 0x14bc,
+ 0x9bad, 0x14be,
+ 0x9bae, 0x14bb,
+ 0x9baf, 0x2eee,
+ 0x9bb0, 0x3fb4,
+ 0x9bb5, 0x3057,
+ 0x9bb6, 0x305a,
+ 0x9bb8, 0x3058,
+ 0x9bb9, 0x305c,
+ 0x9bbd, 0x305d,
+ 0x9bbf, 0x3055,
+ 0x9bc0, 0x156e,
+ 0x9bc1, 0x3056,
+ 0x9bc3, 0x3054,
+ 0x9bc4, 0x305b,
+ 0x9bc6, 0x3053,
+ 0x9bc7, 0x3052,
+ 0x9bc8, 0x156d,
+ 0x9bc9, 0x156b,
+ 0x9bca, 0x156a,
+ 0x9bcf, 0x3c3c,
+ 0x9bd3, 0x3059,
+ 0x9bd4, 0x3199,
+ 0x9bd5, 0x319f,
+ 0x9bd6, 0x15fe,
+ 0x9bd7, 0x319a,
+ 0x9bd9, 0x319d,
+ 0x9bda, 0x31a1,
+ 0x9bdb, 0x15ff,
+ 0x9bdc, 0x319c,
+ 0x9bdd, 0x47c6,
+ 0x9bde, 0x3194,
+ 0x9be0, 0x3193,
+ 0x9be1, 0x31a0,
+ 0x9be2, 0x3197,
+ 0x9be4, 0x3195,
+ 0x9be5, 0x319e,
+ 0x9be6, 0x3196,
+ 0x9be7, 0x15fd,
+ 0x9be8, 0x15fc,
+ 0x9be9, 0x3bc1,
+ 0x9bea, 0x3191,
+ 0x9bec, 0x319b,
+ 0x9bed, 0x3ed7,
+ 0x9bf0, 0x3198,
+ 0x9bf1, 0x47c7,
+ 0x9bf4, 0x47c8,
+ 0x9bf7, 0x3293,
+ 0x9bf8, 0x3296,
+ 0x9bfd, 0x156c,
+ 0x9bff, 0x391b,
+ 0x9c02, 0x391a,
+ 0x9c05, 0x3294,
+ 0x9c06, 0x329a,
+ 0x9c07, 0x3298,
+ 0x9c08, 0x3292,
+ 0x9c09, 0x329d,
+ 0x9c0a, 0x3f3a,
+ 0x9c0b, 0x3291,
+ 0x9c0c, 0x391c,
+ 0x9c0d, 0x1660,
+ 0x9c0e, 0x3299,
+ 0x9c10, 0x3c3a,
+ 0x9c12, 0x3295,
+ 0x9c13, 0x165f,
+ 0x9c14, 0x329c,
+ 0x9c15, 0x3f1e,
+ 0x9c17, 0x329b,
+ 0x9c1b, 0x491b,
+ 0x9c1c, 0x334c,
+ 0x9c1d, 0x334b,
+ 0x9c1f, 0x4622,
+ 0x9c20, 0x47ca,
+ 0x9c21, 0x3352,
+ 0x9c23, 0x334e,
+ 0x9c24, 0x3351,
+ 0x9c25, 0x16b0,
+ 0x9c26, 0x45e6,
+ 0x9c28, 0x334f,
+ 0x9c2b, 0x334a,
+ 0x9c2c, 0x334d,
+ 0x9c2d, 0x16af,
+ 0x9c2e, 0x3f22,
+ 0x9c2f, 0x3d87,
+ 0x9c31, 0x16ed,
+ 0x9c32, 0x33f2,
+ 0x9c33, 0x33ed,
+ 0x9c34, 0x33f1,
+ 0x9c35, 0x3c39,
+ 0x9c36, 0x33f4,
+ 0x9c37, 0x33f0,
+ 0x9c39, 0x33ec,
+ 0x9c3a, 0x3d7e,
+ 0x9c3b, 0x16ef,
+ 0x9c3c, 0x33ef,
+ 0x9c3d, 0x33f3,
+ 0x9c3e, 0x16ee,
+ 0x9c3f, 0x33ea,
+ 0x9c40, 0x3297,
+ 0x9c41, 0x33ee,
+ 0x9c44, 0x33eb,
+ 0x9c45, 0x3e71,
+ 0x9c46, 0x33e8,
+ 0x9c48, 0x33e9,
+ 0x9c49, 0x16ec,
+ 0x9c4a, 0x3457,
+ 0x9c4b, 0x3459,
+ 0x9c4c, 0x345c,
+ 0x9c4d, 0x3458,
+ 0x9c4e, 0x345d,
+ 0x9c4f, 0x3c36,
+ 0x9c50, 0x3456,
+ 0x9c52, 0x3454,
+ 0x9c53, 0x3c37,
+ 0x9c54, 0x1719,
+ 0x9c55, 0x345a,
+ 0x9c56, 0x171b,
+ 0x9c57, 0x171a,
+ 0x9c58, 0x3455,
+ 0x9c59, 0x345b,
+ 0x9c5d, 0x3ebf,
+ 0x9c5e, 0x34b5,
+ 0x9c5f, 0x173a,
+ 0x9c60, 0x34b6,
+ 0x9c62, 0x34b4,
+ 0x9c63, 0x34b1,
+ 0x9c66, 0x34b3,
+ 0x9c67, 0x34b2,
+ 0x9c68, 0x34f4,
+ 0x9c6d, 0x34f6,
+ 0x9c6e, 0x34f5,
+ 0x9c71, 0x3514,
+ 0x9c72, 0x3ea1,
+ 0x9c73, 0x3513,
+ 0x9c74, 0x3512,
+ 0x9c75, 0x3515,
+ 0x9c77, 0x1760,
+ 0x9c79, 0x3541,
+ 0x9c7a, 0x3545,
+ 0x9c7b, 0x3c38,
+ 0x9c7c, 0x4512,
+ 0x9ce5, 0x0be2,
+ 0x9ce6, 0x235f,
+ 0x9ce7, 0x2610,
+ 0x9ce9, 0x0f79,
+ 0x9cea, 0x260e,
+ 0x9ced, 0x260f,
+ 0x9cf1, 0x2879,
+ 0x9cf3, 0x10fe,
+ 0x9cf4, 0x10fc,
+ 0x9cf5, 0x287b,
+ 0x9cf6, 0x10fd,
+ 0x9cf7, 0x2af4,
+ 0x9cf9, 0x2af7,
+ 0x9cfa, 0x2af1,
+ 0x9cfb, 0x2af8,
+ 0x9cfc, 0x2af0,
+ 0x9cfd, 0x2af2,
+ 0x9cff, 0x2af3,
+ 0x9d00, 0x2af6,
+ 0x9d02, 0x3f3b,
+ 0x9d03, 0x1284,
+ 0x9d04, 0x2afb,
+ 0x9d05, 0x2afa,
+ 0x9d06, 0x1282,
+ 0x9d07, 0x2af5,
+ 0x9d08, 0x2af9,
+ 0x9d09, 0x1283,
+ 0x9d0c, 0x3c46,
+ 0x9d10, 0x2d2d,
+ 0x9d12, 0x13ae,
+ 0x9d14, 0x2d28,
+ 0x9d15, 0x13aa,
+ 0x9d16, 0x3c7c,
+ 0x9d17, 0x2d25,
+ 0x9d18, 0x2d2b,
+ 0x9d19, 0x2d2e,
+ 0x9d1b, 0x13af,
+ 0x9d1d, 0x2d2a,
+ 0x9d1e, 0x2d27,
+ 0x9d1f, 0x2d2f,
+ 0x9d20, 0x2d26,
+ 0x9d21, 0x3c41,
+ 0x9d22, 0x2d2c,
+ 0x9d23, 0x13ab,
+ 0x9d25, 0x2d24,
+ 0x9d26, 0x13ac,
+ 0x9d28, 0x13ad,
+ 0x9d29, 0x2d29,
+ 0x9d2d, 0x2f00,
+ 0x9d2e, 0x2ef3,
+ 0x9d30, 0x2ef7,
+ 0x9d31, 0x2ef5,
+ 0x9d33, 0x2eef,
+ 0x9d34, 0x404a,
+ 0x9d36, 0x2ef2,
+ 0x9d37, 0x2efc,
+ 0x9d38, 0x2ef6,
+ 0x9d39, 0x392e,
+ 0x9d3b, 0x14bf,
+ 0x9d3d, 0x2efe,
+ 0x9d3e, 0x2efb,
+ 0x9d3f, 0x14c0,
+ 0x9d40, 0x2efd,
+ 0x9d41, 0x2ef0,
+ 0x9d42, 0x2ef9,
+ 0x9d44, 0x3fab,
+ 0x9d45, 0x2ef8,
+ 0x9d49, 0x47cd,
+ 0x9d4a, 0x3061,
+ 0x9d4b, 0x3063,
+ 0x9d4c, 0x3066,
+ 0x9d4e, 0x4539,
+ 0x9d4f, 0x3060,
+ 0x9d50, 0x3eca,
+ 0x9d51, 0x156f,
+ 0x9d52, 0x3068,
+ 0x9d53, 0x305f,
+ 0x9d54, 0x3069,
+ 0x9d56, 0x3065,
+ 0x9d57, 0x3067,
+ 0x9d58, 0x306b,
+ 0x9d59, 0x3064,
+ 0x9d5a, 0x306c,
+ 0x9d5b, 0x3062,
+ 0x9d5c, 0x305e,
+ 0x9d5d, 0x1570,
+ 0x9d5e, 0x3e6e,
+ 0x9d5f, 0x306a,
+ 0x9d60, 0x1571,
+ 0x9d61, 0x1601,
+ 0x9d67, 0x2ef1,
+ 0x9d68, 0x31bb,
+ 0x9d69, 0x31b2,
+ 0x9d6a, 0x1603,
+ 0x9d6b, 0x31ae,
+ 0x9d6c, 0x1604,
+ 0x9d6d, 0x3bac,
+ 0x9d6e, 0x433b,
+ 0x9d6f, 0x31b7,
+ 0x9d70, 0x31b1,
+ 0x9d71, 0x31a7,
+ 0x9d72, 0x1602,
+ 0x9d73, 0x31b4,
+ 0x9d74, 0x31af,
+ 0x9d77, 0x31a2,
+ 0x9d78, 0x31a9,
+ 0x9d79, 0x31b8,
+ 0x9d7b, 0x31b5,
+ 0x9d7c, 0x3efe,
+ 0x9d7d, 0x31ad,
+ 0x9d7e, 0x3925,
+ 0x9d7f, 0x31b9,
+ 0x9d80, 0x31a8,
+ 0x9d81, 0x31a3,
+ 0x9d82, 0x31b6,
+ 0x9d83, 0x3926,
+ 0x9d84, 0x31a5,
+ 0x9d85, 0x31b3,
+ 0x9d86, 0x31aa,
+ 0x9d87, 0x31ba,
+ 0x9d88, 0x31a6,
+ 0x9d89, 0x1600,
+ 0x9d8a, 0x31a4,
+ 0x9d8b, 0x31ab,
+ 0x9d90, 0x32a4,
+ 0x9d92, 0x32a2,
+ 0x9d93, 0x43f3,
+ 0x9d94, 0x32a7,
+ 0x9d96, 0x32b3,
+ 0x9d97, 0x32aa,
+ 0x9d98, 0x32a3,
+ 0x9d99, 0x329f,
+ 0x9d9a, 0x32ac,
+ 0x9d9b, 0x32a5,
+ 0x9d9c, 0x32a8,
+ 0x9d9d, 0x32a1,
+ 0x9d9e, 0x32af,
+ 0x9d9f, 0x329e,
+ 0x9da0, 0x32a6,
+ 0x9da1, 0x32ab,
+ 0x9da2, 0x32ad,
+ 0x9da3, 0x32b0,
+ 0x9da4, 0x32a0,
+ 0x9da5, 0x3c4b,
+ 0x9da6, 0x32b4,
+ 0x9da8, 0x32ae,
+ 0x9da9, 0x32b2,
+ 0x9daa, 0x32a9,
+ 0x9dab, 0x3f30,
+ 0x9dac, 0x3362,
+ 0x9dad, 0x3365,
+ 0x9daf, 0x16b1,
+ 0x9db1, 0x3364,
+ 0x9db2, 0x3369,
+ 0x9db3, 0x3367,
+ 0x9db4, 0x16b2,
+ 0x9db5, 0x335e,
+ 0x9db6, 0x3354,
+ 0x9db7, 0x3353,
+ 0x9db8, 0x16b4,
+ 0x9db9, 0x3360,
+ 0x9dbb, 0x335d,
+ 0x9dbc, 0x3355,
+ 0x9dbd, 0x47d0,
+ 0x9dbe, 0x335a,
+ 0x9dbf, 0x32b1,
+ 0x9dc0, 0x43f2,
+ 0x9dc1, 0x3356,
+ 0x9dc2, 0x16b3,
+ 0x9dc3, 0x335c,
+ 0x9dc4, 0x3929,
+ 0x9dc5, 0x335b,
+ 0x9dc7, 0x3357,
+ 0x9dc8, 0x3363,
+ 0x9dc9, 0x4579,
+ 0x9dca, 0x3358,
+ 0x9dcb, 0x33f9,
+ 0x9dcc, 0x3366,
+ 0x9dcd, 0x3368,
+ 0x9dce, 0x335f,
+ 0x9dcf, 0x3359,
+ 0x9dd0, 0x33fa,
+ 0x9dd1, 0x33fc,
+ 0x9dd2, 0x33f6,
+ 0x9dd3, 0x16f0,
+ 0x9dd4, 0x391e,
+ 0x9dd5, 0x3403,
+ 0x9dd6, 0x3401,
+ 0x9dd7, 0x16f1,
+ 0x9dd8, 0x3400,
+ 0x9dd9, 0x33ff,
+ 0x9dda, 0x33f8,
+ 0x9ddb, 0x33f5,
+ 0x9ddc, 0x33fb,
+ 0x9ddd, 0x3404,
+ 0x9dde, 0x33f7,
+ 0x9ddf, 0x33fd,
+ 0x9de1, 0x3466,
+ 0x9de2, 0x346b,
+ 0x9de3, 0x3461,
+ 0x9de4, 0x3464,
+ 0x9de5, 0x171c,
+ 0x9de6, 0x3468,
+ 0x9de8, 0x346f,
+ 0x9de9, 0x33fe,
+ 0x9deb, 0x3462,
+ 0x9dec, 0x346c,
+ 0x9ded, 0x3470,
+ 0x9dee, 0x3467,
+ 0x9def, 0x3460,
+ 0x9df0, 0x346a,
+ 0x9df2, 0x3469,
+ 0x9df3, 0x346e,
+ 0x9df4, 0x346d,
+ 0x9df5, 0x3402,
+ 0x9df6, 0x3465,
+ 0x9df7, 0x345f,
+ 0x9df8, 0x3463,
+ 0x9df9, 0x173b,
+ 0x9dfb, 0x345e,
+ 0x9dfc, 0x47d1,
+ 0x9dfd, 0x34c1,
+ 0x9dfe, 0x34b8,
+ 0x9dff, 0x34c0,
+ 0x9e00, 0x34bd,
+ 0x9e02, 0x34b7,
+ 0x9e03, 0x34ba,
+ 0x9e04, 0x34c2,
+ 0x9e05, 0x34bc,
+ 0x9e06, 0x34bb,
+ 0x9e07, 0x34b9,
+ 0x9e09, 0x34bf,
+ 0x9e0a, 0x457e,
+ 0x9e0b, 0x34f7,
+ 0x9e0c, 0x457a,
+ 0x9e0d, 0x34f8,
+ 0x9e0e, 0x3928,
+ 0x9e0f, 0x34fa,
+ 0x9e10, 0x34f9,
+ 0x9e11, 0x34fc,
+ 0x9e12, 0x34fb,
+ 0x9e13, 0x3517,
+ 0x9e14, 0x3516,
+ 0x9e15, 0x3530,
+ 0x9e17, 0x3531,
+ 0x9e18, 0x3c44,
+ 0x9e19, 0x353d,
+ 0x9e1a, 0x1765,
+ 0x9e1b, 0x1769,
+ 0x9e1c, 0x3f84,
+ 0x9e1d, 0x3546,
+ 0x9e1e, 0x176a,
+ 0x9e1f, 0x4513,
+ 0x9e75, 0x0be3,
+ 0x9e79, 0x1661,
+ 0x9e7a, 0x336a,
+ 0x9e7b, 0x43f8,
+ 0x9e7c, 0x173d,
+ 0x9e7f, 0x0be4,
+ 0x9e80, 0x2611,
+ 0x9e81, 0x3f0f,
+ 0x9e82, 0x0f7a,
+ 0x9e83, 0x2afc,
+ 0x9e84, 0x3f76,
+ 0x9e85, 0x3ef2,
+ 0x9e86, 0x2d31,
+ 0x9e88, 0x2d30,
+ 0x9e89, 0x2f02,
+ 0x9e8a, 0x2f01,
+ 0x9e8b, 0x14c1,
+ 0x9e8c, 0x306e,
+ 0x9e8d, 0x2f03,
+ 0x9e8e, 0x306d,
+ 0x9e90, 0x3931,
+ 0x9e91, 0x31bd,
+ 0x9e92, 0x1605,
+ 0x9e93, 0x1607,
+ 0x9e94, 0x31bc,
+ 0x9e95, 0x3932,
+ 0x9e96, 0x3fbc,
+ 0x9e97, 0x1606,
+ 0x9e98, 0x3f27,
+ 0x9e99, 0x32b6,
+ 0x9e9a, 0x32b8,
+ 0x9e9b, 0x32b7,
+ 0x9e9c, 0x336b,
+ 0x9e9d, 0x16b5,
+ 0x9e9e, 0x3933,
+ 0x9e9f, 0x171d,
+ 0x9ea0, 0x34c3,
+ 0x9ea1, 0x34fd,
+ 0x9ea2, 0x3934,
+ 0x9ea4, 0x354a,
+ 0x9ea5, 0x0be5,
+ 0x9ea6, 0x4944,
+ 0x9ea7, 0x287c,
+ 0x9ea8, 0x3f75,
+ 0x9ea9, 0x1285,
+ 0x9eaa, 0x3936,
+ 0x9eab, 0x3e92,
+ 0x9eac, 0x43f4,
+ 0x9ead, 0x2d34,
+ 0x9eae, 0x2d33,
+ 0x9eaf, 0x3937,
+ 0x9eb0, 0x2f04,
+ 0x9eb1, 0x47d4,
+ 0x9eb4, 0x1608,
+ 0x9eb5, 0x1662,
+ 0x9eb6, 0x3405,
+ 0x9eb7, 0x3542,
+ 0x9ebb, 0x0be6,
+ 0x9ebc, 0x10ff,
+ 0x9ebd, 0x47d5,
+ 0x9ebe, 0x1286,
+ 0x9ebf, 0x3d78,
+ 0x9ec0, 0x31be,
+ 0x9ec1, 0x3939,
+ 0x9ec2, 0x3471,
+ 0x9ec3, 0x0dbb,
+ 0x9ec4, 0x4514,
+ 0x9ec6, 0x47d6,
+ 0x9ec7, 0x4577,
+ 0x9ec8, 0x2f05,
+ 0x9ecc, 0x1751,
+ 0x9ecd, 0x0dbc,
+ 0x9ece, 0x1287,
+ 0x9ecf, 0x14c2,
+ 0x9ed0, 0x3472,
+ 0x9ed1, 0x0dbd,
+ 0x9ed3, 0x2afd,
+ 0x9ed4, 0x13b1,
+ 0x9ed5, 0x2d35,
+ 0x9ed8, 0x13b0,
+ 0x9eda, 0x2f06,
+ 0x9edb, 0x14c6,
+ 0x9edc, 0x14c4,
+ 0x9ede, 0x14c3,
+ 0x9edf, 0x306f,
+ 0x9ee0, 0x1572,
+ 0x9ee2, 0x47d8,
+ 0x9ee4, 0x32ba,
+ 0x9ee5, 0x32b9,
+ 0x9ee6, 0x32bc,
+ 0x9ee7, 0x32bb,
+ 0x9ee8, 0x1663,
+ 0x9eeb, 0x336c,
+ 0x9eed, 0x336e,
+ 0x9eee, 0x336d,
+ 0x9eef, 0x16b6,
+ 0x9ef0, 0x3406,
+ 0x9ef1, 0x47d9,
+ 0x9ef2, 0x3473,
+ 0x9ef4, 0x171e,
+ 0x9ef5, 0x34fe,
+ 0x9ef6, 0x3518,
+ 0x9ef7, 0x1762,
+ 0x9ef8, 0x47da,
+ 0x9ef9, 0x2360,
+ 0x9efa, 0x2d37,
+ 0x9efb, 0x2f07,
+ 0x9efc, 0x31bf,
+ 0x9efd, 0x2612,
+ 0x9efe, 0x47ce,
+ 0x9eff, 0x2f08,
+ 0x9f00, 0x3071,
+ 0x9f01, 0x3070,
+ 0x9f02, 0x3940,
+ 0x9f06, 0x3475,
+ 0x9f07, 0x173f,
+ 0x9f08, 0x3941,
+ 0x9f09, 0x34ff,
+ 0x9f0a, 0x3519,
+ 0x9f0e, 0x0f7b,
+ 0x9f0f, 0x2afe,
+ 0x9f12, 0x2d38,
+ 0x9f13, 0x0f7c,
+ 0x9f15, 0x1573,
+ 0x9f16, 0x3072,
+ 0x9f17, 0x3945,
+ 0x9f18, 0x3370,
+ 0x9f19, 0x16b7,
+ 0x9f1a, 0x3371,
+ 0x9f1b, 0x336f,
+ 0x9f1c, 0x3476,
+ 0x9f1e, 0x34c4,
+ 0x9f20, 0x0f7d,
+ 0x9f22, 0x2f0b,
+ 0x9f23, 0x2f0a,
+ 0x9f24, 0x2f09,
+ 0x9f25, 0x3073,
+ 0x9f26, 0x3f90,
+ 0x9f27, 0x4620,
+ 0x9f28, 0x3077,
+ 0x9f29, 0x3076,
+ 0x9f2a, 0x3075,
+ 0x9f2b, 0x3074,
+ 0x9f2c, 0x1574,
+ 0x9f2d, 0x31c0,
+ 0x9f2e, 0x32be,
+ 0x9f2f, 0x1664,
+ 0x9f30, 0x32bd,
+ 0x9f31, 0x3372,
+ 0x9f32, 0x3409,
+ 0x9f33, 0x3408,
+ 0x9f34, 0x16f2,
+ 0x9f35, 0x3407,
+ 0x9f36, 0x3479,
+ 0x9f37, 0x3478,
+ 0x9f38, 0x3477,
+ 0x9f39, 0x3947,
+ 0x9f3b, 0x1100,
+ 0x9f3d, 0x2d39,
+ 0x9f3e, 0x14c7,
+ 0x9f40, 0x31c1,
+ 0x9f42, 0x340a,
+ 0x9f43, 0x347a,
+ 0x9f44, 0x47db,
+ 0x9f45, 0x394a,
+ 0x9f46, 0x34c5,
+ 0x9f47, 0x3500,
+ 0x9f48, 0x3532,
+ 0x9f49, 0x354c,
+ 0x9f4a, 0x1101,
+ 0x9f4b, 0x14c8,
+ 0x9f4c, 0x3078,
+ 0x9f4d, 0x31c3,
+ 0x9f4e, 0x3373,
+ 0x9f4f, 0x347b,
+ 0x9f50, 0x4943,
+ 0x9f52, 0x1289,
+ 0x9f53, 0x3f80,
+ 0x9f54, 0x2f0c,
+ 0x9f55, 0x3079,
+ 0x9f56, 0x31c4,
+ 0x9f59, 0x32c3,
+ 0x9f5a, 0x3f23,
+ 0x9f5b, 0x32bf,
+ 0x9f5c, 0x16b8,
+ 0x9f5d, 0x32c2,
+ 0x9f5e, 0x32c1,
+ 0x9f5f, 0x1665,
+ 0x9f60, 0x32c0,
+ 0x9f61, 0x1667,
+ 0x9f62, 0x394f,
+ 0x9f63, 0x1666,
+ 0x9f64, 0x3375,
+ 0x9f65, 0x3374,
+ 0x9f66, 0x16b9,
+ 0x9f69, 0x3950,
+ 0x9f6a, 0x16f4,
+ 0x9f6b, 0x340b,
+ 0x9f6c, 0x16f3,
+ 0x9f6e, 0x347e,
+ 0x9f70, 0x347d,
+ 0x9f71, 0x347c,
+ 0x9f72, 0x1741,
+ 0x9f74, 0x34c6,
+ 0x9f77, 0x1740,
+ 0x9f78, 0x3501,
+ 0x9f79, 0x3504,
+ 0x9f7a, 0x3503,
+ 0x9f7b, 0x3502,
+ 0x9f7e, 0x354b,
+ 0x9f7f, 0x4680,
+ 0x9f8d, 0x13b2,
+ 0x9f8e, 0x3952,
+ 0x9f90, 0x157c,
+ 0x9f91, 0x32c4,
+ 0x9f92, 0x3376,
+ 0x9f94, 0x16f5,
+ 0x9f95, 0x340c,
+ 0x9f98, 0x354d,
+ 0x9f99, 0x4587,
+ 0x9f9c, 0x13b3,
+ 0x9f9f, 0x4646,
+ 0x9fa0, 0x2f0d,
+ 0x9fa2, 0x340d,
+ 0x9fa4, 0x351a,
+ 0x9fa5, 0x3f70,
+ 0xfa0c, 0x0274,
+ 0xfa0d, 0x2381,
+ 0xfe30, 0x006d,
+ 0xfe31, 0x007a,
+ 0xfe33, 0x35af,
+ 0xfe34, 0x35b1,
+ 0xfe35, 0x0082,
+ 0xfe37, 0x0086,
+ 0xfe39, 0x008a,
+ 0xfe3b, 0x008e,
+ 0xfe3d, 0x0092,
+ 0xfe3f, 0x0096,
+ 0xfe41, 0x009a,
+ 0xfe43, 0x009e,
+ 0xfe49, 0x00c7,
+ 0xfe4b, 0x00cb,
+ 0xfe4d, 0x00c9,
+ 0xfe4f, 0x35b2,
+ 0xfe50, 0x0070,
+ 0xfe52, 0x0072,
+ 0xfe54, 0x0074,
+ 0xfe59, 0x00a0,
+ 0xfe5f, 0x00cd,
+ 0xfe62, 0x00df,
+ 0xfe69, 0x010c,
+ 0xff01, 0x006c,
+ 0xff02, 0x36e4,
+ 0xff03, 0x00ae,
+ 0xff04, 0x0103,
+ 0xff05, 0x0108,
+ 0xff06, 0x00af,
+ 0xff07, 0x36e3,
+ 0xff08, 0x0080,
+ 0xff0a, 0x00b0,
+ 0xff0b, 0x00d0,
+ 0xff0c, 0x0064,
+ 0xff0d, 0x00d1,
+ 0xff0e, 0x0067,
+ 0xff0f, 0x0101,
+ 0xff10, 0x014d,
+ 0xff1a, 0x006a,
+ 0xff1b, 0x0069,
+ 0xff1c, 0x00d6,
+ 0xff1d, 0x00d8,
+ 0xff1e, 0x00d7,
+ 0xff1f, 0x006b,
+ 0xff20, 0x0109,
+ 0xff21, 0x016d,
+ 0xff3b, 0x35be,
+ 0xff3c, 0x0102,
+ 0xff3d, 0x35bf,
+ 0xff3e, 0x35b4,
+ 0xff3f, 0x00c5,
+ 0xff41, 0x0187,
+ 0xff5b, 0x0084,
+ 0xff5c, 0x0078,
+ 0xff5d, 0x0085,
+ 0xff64, 0x0071,
+ 0xffe2, 0x36e1,
+ 0xffe4, 0x36e2,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 cns13UniCNSUCS2HEnc16 = {
+ 0,
+ { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ cns13UniCNSUCS2HMap2, 15455
+};
+
+static Gushort cns13UniCNSUCS2VMap2[30936] = {
+ 0x0000, 0x0000,
+ 0x0020, 0x0001,
+ 0x00a2, 0x0106,
+ 0x00a5, 0x0104,
+ 0x00a7, 0x00b2,
+ 0x00a8, 0x35b3,
+ 0x00ac, 0x36e1,
+ 0x00b0, 0x0118,
+ 0x00b1, 0x00d4,
+ 0x00b7, 0x0073,
+ 0x00c0, 0x4964,
+ 0x00c1, 0x4962,
+ 0x00c8, 0x4968,
+ 0x00c9, 0x4966,
+ 0x00ca, 0x4971,
+ 0x00d2, 0x496c,
+ 0x00d3, 0x496a,
+ 0x00d7, 0x00d2,
+ 0x00e0, 0x4975,
+ 0x00e1, 0x4973,
+ 0x00e8, 0x497a,
+ 0x00e9, 0x4978,
+ 0x00ea, 0x4990,
+ 0x00ec, 0x497e,
+ 0x00ed, 0x497c,
+ 0x00f2, 0x4982,
+ 0x00f3, 0x4980,
+ 0x00f7, 0x00d3,
+ 0x00f8, 0x4998,
+ 0x00f9, 0x4986,
+ 0x00fa, 0x4984,
+ 0x00fc, 0x498b,
+ 0x0100, 0x4961,
+ 0x0101, 0x4972,
+ 0x0112, 0x4965,
+ 0x0113, 0x4977,
+ 0x011a, 0x4967,
+ 0x011b, 0x4979,
+ 0x012b, 0x497b,
+ 0x014b, 0x4999,
+ 0x014c, 0x4969,
+ 0x014d, 0x497f,
+ 0x0153, 0x4997,
+ 0x016b, 0x4983,
+ 0x01cd, 0x4963,
+ 0x01ce, 0x4974,
+ 0x01d0, 0x497d,
+ 0x01d1, 0x496b,
+ 0x01d2, 0x4981,
+ 0x01d4, 0x4985,
+ 0x01d6, 0x4987,
+ 0x01d8, 0x4988,
+ 0x01da, 0x4989,
+ 0x01dc, 0x498a,
+ 0x0250, 0x4993,
+ 0x0251, 0x4976,
+ 0x0254, 0x4995,
+ 0x025b, 0x4994,
+ 0x0261, 0x4991,
+ 0x026a, 0x499b,
+ 0x0275, 0x4996,
+ 0x0283, 0x4992,
+ 0x028a, 0x499a,
+ 0x02c6, 0x35b4,
+ 0x02c7, 0x01f8,
+ 0x02ca, 0x01f7,
+ 0x02cb, 0x01f9,
+ 0x02d9, 0x01f6,
+ 0x0308, 0x35b3,
+ 0x0391, 0x01a1,
+ 0x03a3, 0x01b2,
+ 0x03b1, 0x01b9,
+ 0x03c3, 0x01ca,
+ 0x0401, 0x3670,
+ 0x0410, 0x366a,
+ 0x0416, 0x3671,
+ 0x0436, 0x3692,
+ 0x0451, 0x3691,
+ 0x1ebe, 0x496e,
+ 0x1ebf, 0x498d,
+ 0x1ec0, 0x4970,
+ 0x1ec1, 0x498f,
+ 0x2013, 0x0079,
+ 0x2014, 0x007b,
+ 0x2018, 0x00a6,
+ 0x201c, 0x00a8,
+ 0x2022, 0x0068,
+ 0x2025, 0x006f,
+ 0x2026, 0x006e,
+ 0x2032, 0x00ad,
+ 0x2035, 0x00ac,
+ 0x203b, 0x00b1,
+ 0x203e, 0x00c3,
+ 0x20ac, 0x44c1,
+ 0x2103, 0x010a,
+ 0x2105, 0x00c2,
+ 0x2109, 0x010b,
+ 0x2116, 0x36e6,
+ 0x2121, 0x36e7,
+ 0x2160, 0x0157,
+ 0x2170, 0x020e,
+ 0x2190, 0x00f8,
+ 0x2191, 0x00f5,
+ 0x2192, 0x00f7,
+ 0x2193, 0x00f6,
+ 0x2196, 0x00f9,
+ 0x2198, 0x00fc,
+ 0x2199, 0x00fb,
+ 0x21b8, 0x36ad,
+ 0x21e7, 0x36ac,
+ 0x221a, 0x00d5,
+ 0x221e, 0x00dc,
+ 0x221f, 0x00e9,
+ 0x2220, 0x00e8,
+ 0x2223, 0x00fe,
+ 0x2225, 0x00fd,
+ 0x2229, 0x00e5,
+ 0x222b, 0x00ed,
+ 0x222e, 0x00ee,
+ 0x2234, 0x00f0,
+ 0x2235, 0x00ef,
+ 0x223c, 0x00e4,
+ 0x2252, 0x00dd,
+ 0x2260, 0x00db,
+ 0x2261, 0x00de,
+ 0x2266, 0x00d9,
+ 0x22a5, 0x00e7,
+ 0x22bf, 0x00ea,
+ 0x2400, 0x0232,
+ 0x2421, 0x0252,
+ 0x2460, 0x01fa,
+ 0x2474, 0x0204,
+ 0x2500, 0x0137,
+ 0x2502, 0x0138,
+ 0x250c, 0x013a,
+ 0x2510, 0x013b,
+ 0x2514, 0x013c,
+ 0x2518, 0x013d,
+ 0x251c, 0x0135,
+ 0x2524, 0x0134,
+ 0x252c, 0x0133,
+ 0x2534, 0x0132,
+ 0x253c, 0x0131,
+ 0x2550, 0x0142,
+ 0x2551, 0x370a,
+ 0x2552, 0x36f8,
+ 0x2553, 0x3701,
+ 0x2554, 0x36ef,
+ 0x2555, 0x36fa,
+ 0x2556, 0x3703,
+ 0x2557, 0x36f1,
+ 0x2558, 0x36fe,
+ 0x2559, 0x3707,
+ 0x255a, 0x36f5,
+ 0x255b, 0x3700,
+ 0x255c, 0x3709,
+ 0x255d, 0x36f7,
+ 0x255e, 0x0143,
+ 0x255f, 0x3704,
+ 0x2560, 0x36f2,
+ 0x2561, 0x0145,
+ 0x2562, 0x3706,
+ 0x2563, 0x36f4,
+ 0x2564, 0x36f9,
+ 0x2565, 0x3702,
+ 0x2566, 0x36f0,
+ 0x2567, 0x36ff,
+ 0x2568, 0x3708,
+ 0x2569, 0x36f6,
+ 0x256a, 0x0144,
+ 0x256b, 0x3705,
+ 0x256c, 0x36f3,
+ 0x256d, 0x013e,
+ 0x256f, 0x0141,
+ 0x2570, 0x0140,
+ 0x2571, 0x014a,
+ 0x2581, 0x0122,
+ 0x2589, 0x0130,
+ 0x258a, 0x012f,
+ 0x258b, 0x012e,
+ 0x258c, 0x012d,
+ 0x258d, 0x012c,
+ 0x258e, 0x012b,
+ 0x258f, 0x012a,
+ 0x2593, 0x3710,
+ 0x2594, 0x0136,
+ 0x2595, 0x0139,
+ 0x25a0, 0x00be,
+ 0x25a1, 0x00bd,
+ 0x25b2, 0x00b7,
+ 0x25b3, 0x00b6,
+ 0x25bc, 0x00c0,
+ 0x25bd, 0x00bf,
+ 0x25c6, 0x00bc,
+ 0x25c7, 0x00bb,
+ 0x25cb, 0x00b4,
+ 0x25ce, 0x00b8,
+ 0x25cf, 0x00b5,
+ 0x25e2, 0x0146,
+ 0x25e4, 0x0149,
+ 0x25e5, 0x0148,
+ 0x2605, 0x00ba,
+ 0x2606, 0x00b9,
+ 0x2609, 0x00f4,
+ 0x2640, 0x00f1,
+ 0x2641, 0x00f3,
+ 0x2642, 0x00f2,
+ 0x273d, 0x35c0,
+ 0x2e80, 0x44c8,
+ 0x2e84, 0x451c,
+ 0x2e86, 0x451d,
+ 0x2e8a, 0x4520,
+ 0x2e8c, 0x4521,
+ 0x2e95, 0x4523,
+ 0x2e9c, 0x4524,
+ 0x2e9d, 0x02dc,
+ 0x2ea5, 0x4525,
+ 0x2ea7, 0x4526,
+ 0x2eaa, 0x4527,
+ 0x2eac, 0x4528,
+ 0x2eae, 0x4529,
+ 0x2eb6, 0x452a,
+ 0x2ebc, 0x452b,
+ 0x2ebe, 0x452c,
+ 0x2ec6, 0x0509,
+ 0x2eca, 0x452d,
+ 0x2ecc, 0x452e,
+ 0x2ecf, 0x4530,
+ 0x2ed6, 0x4531,
+ 0x2ede, 0x4533,
+ 0x2ee3, 0x09f6,
+ 0x2f33, 0x0227,
+ 0x3000, 0x0063,
+ 0x3001, 0x0065,
+ 0x3003, 0x00b3,
+ 0x3005, 0x35ba,
+ 0x3008, 0x0094,
+ 0x300a, 0x0090,
+ 0x300c, 0x0098,
+ 0x300e, 0x009c,
+ 0x3010, 0x008c,
+ 0x3012, 0x0105,
+ 0x3014, 0x0088,
+ 0x301d, 0x00aa,
+ 0x3021, 0x0161,
+ 0x3041, 0x35c1,
+ 0x309b, 0x44c6,
+ 0x309d, 0x35b7,
+ 0x30a1, 0x3614,
+ 0x30fc, 0x35bd,
+ 0x30fd, 0x35b5,
+ 0x3105, 0x01d1,
+ 0x3231, 0x36e5,
+ 0x32a3, 0x00c1,
+ 0x338e, 0x0115,
+ 0x339c, 0x0110,
+ 0x33a1, 0x0114,
+ 0x33c4, 0x0117,
+ 0x33ce, 0x0113,
+ 0x33d1, 0x00ec,
+ 0x33d2, 0x00eb,
+ 0x33d5, 0x010f,
+ 0x3435, 0x39bd,
+ 0x3440, 0x3c67,
+ 0x344c, 0x4593,
+ 0x3464, 0x3a85,
+ 0x3473, 0x3dc5,
+ 0x347a, 0x4033,
+ 0x347d, 0x4597,
+ 0x347e, 0x46a3,
+ 0x3493, 0x439e,
+ 0x3496, 0x37dc,
+ 0x34a5, 0x4598,
+ 0x34af, 0x3c7f,
+ 0x34bc, 0x4380,
+ 0x34c1, 0x44fb,
+ 0x34c8, 0x3d00,
+ 0x34df, 0x3ea4,
+ 0x34e4, 0x3e54,
+ 0x34fb, 0x3dca,
+ 0x3506, 0x4336,
+ 0x353e, 0x44e7,
+ 0x3551, 0x45a1,
+ 0x3553, 0x43a5,
+ 0x3561, 0x40d8,
+ 0x356d, 0x45a4,
+ 0x3570, 0x3b2f,
+ 0x3572, 0x45a5,
+ 0x3577, 0x3ecb,
+ 0x3578, 0x4379,
+ 0x3584, 0x39fb,
+ 0x3597, 0x3b2d,
+ 0x3598, 0x45b0,
+ 0x35a1, 0x40e2,
+ 0x35a5, 0x45b1,
+ 0x35ad, 0x3efc,
+ 0x35bf, 0x45b2,
+ 0x35c1, 0x4580,
+ 0x35c5, 0x45b4,
+ 0x35c7, 0x459f,
+ 0x35ca, 0x3e43,
+ 0x35ce, 0x3e81,
+ 0x35d2, 0x3fc9,
+ 0x35d6, 0x3fb5,
+ 0x35db, 0x470d,
+ 0x35dd, 0x43ac,
+ 0x35f1, 0x4696,
+ 0x35f2, 0x4627,
+ 0x35f3, 0x3f6c,
+ 0x35fb, 0x45c8,
+ 0x35fe, 0x3f6a,
+ 0x3609, 0x45f5,
+ 0x3618, 0x4871,
+ 0x361a, 0x461a,
+ 0x3623, 0x40c6,
+ 0x362d, 0x3e86,
+ 0x3635, 0x492e,
+ 0x3639, 0x4165,
+ 0x363e, 0x3a08,
+ 0x3647, 0x4806,
+ 0x3648, 0x3806,
+ 0x3649, 0x4013,
+ 0x364e, 0x4698,
+ 0x365f, 0x3df3,
+ 0x367a, 0x3ee3,
+ 0x3681, 0x45a6,
+ 0x369a, 0x3c71,
+ 0x36a5, 0x4902,
+ 0x36aa, 0x3b30,
+ 0x36ac, 0x4900,
+ 0x36b0, 0x3cdf,
+ 0x36b1, 0x40cd,
+ 0x36b5, 0x3bc2,
+ 0x36b9, 0x4887,
+ 0x36bc, 0x3cff,
+ 0x36c1, 0x37c5,
+ 0x36c3, 0x40e5,
+ 0x36c4, 0x3905,
+ 0x36c5, 0x4296,
+ 0x36c7, 0x3d3a,
+ 0x36c8, 0x4820,
+ 0x36d3, 0x3a38,
+ 0x36d4, 0x3bb3,
+ 0x36d6, 0x3d0c,
+ 0x36dd, 0x3a36,
+ 0x36e1, 0x397c,
+ 0x36e2, 0x3cdd,
+ 0x36e5, 0x4216,
+ 0x36e6, 0x40fc,
+ 0x36f5, 0x3a18,
+ 0x3701, 0x3a34,
+ 0x3703, 0x460f,
+ 0x3708, 0x40ff,
+ 0x370a, 0x3cd5,
+ 0x370d, 0x4238,
+ 0x371c, 0x3dfe,
+ 0x3722, 0x3979,
+ 0x3723, 0x3980,
+ 0x3725, 0x3849,
+ 0x372c, 0x3c8c,
+ 0x372d, 0x3d37,
+ 0x3730, 0x495c,
+ 0x3732, 0x4106,
+ 0x3733, 0x3997,
+ 0x373a, 0x3e56,
+ 0x3740, 0x4202,
+ 0x3743, 0x4036,
+ 0x3762, 0x3db6,
+ 0x376f, 0x47cb,
+ 0x3797, 0x45ed,
+ 0x37a0, 0x3a28,
+ 0x37b9, 0x43b7,
+ 0x37be, 0x393e,
+ 0x37f2, 0x3ba1,
+ 0x37f8, 0x42d2,
+ 0x37fb, 0x3ef5,
+ 0x380f, 0x462c,
+ 0x3819, 0x39af,
+ 0x3820, 0x462f,
+ 0x382d, 0x412e,
+ 0x3836, 0x4133,
+ 0x3838, 0x43bb,
+ 0x3863, 0x46c3,
+ 0x38a0, 0x4145,
+ 0x38c3, 0x3912,
+ 0x38cc, 0x4076,
+ 0x38d1, 0x3a95,
+ 0x38fa, 0x44eb,
+ 0x3908, 0x4632,
+ 0x3914, 0x43be,
+ 0x3927, 0x3c31,
+ 0x3932, 0x4182,
+ 0x393f, 0x4633,
+ 0x394d, 0x4634,
+ 0x3963, 0x4163,
+ 0x3980, 0x3874,
+ 0x3989, 0x4638,
+ 0x398a, 0x3ce8,
+ 0x3992, 0x4376,
+ 0x3999, 0x39ba,
+ 0x399b, 0x3db3,
+ 0x39a1, 0x3e19,
+ 0x39a4, 0x3e0f,
+ 0x39b8, 0x463b,
+ 0x39dc, 0x3ece,
+ 0x39e2, 0x46c8,
+ 0x39e5, 0x393b,
+ 0x39ec, 0x4310,
+ 0x39f8, 0x463e,
+ 0x39fb, 0x4345,
+ 0x39fe, 0x4368,
+ 0x3a01, 0x41e0,
+ 0x3a03, 0x4640,
+ 0x3a06, 0x4377,
+ 0x3a17, 0x4190,
+ 0x3a18, 0x438f,
+ 0x3a29, 0x3a5e,
+ 0x3a2a, 0x3edf,
+ 0x3a34, 0x4319,
+ 0x3a4b, 0x4644,
+ 0x3a52, 0x3ed3,
+ 0x3a57, 0x419e,
+ 0x3a5c, 0x3fc4,
+ 0x3a5e, 0x3b07,
+ 0x3a66, 0x419c,
+ 0x3a67, 0x4333,
+ 0x3a97, 0x4647,
+ 0x3aab, 0x4091,
+ 0x3abd, 0x4649,
+ 0x3ade, 0x414c,
+ 0x3ae0, 0x3a7a,
+ 0x3af0, 0x46b2,
+ 0x3af2, 0x464c,
+ 0x3afb, 0x3af2,
+ 0x3b0e, 0x38e8,
+ 0x3b19, 0x46c5,
+ 0x3b22, 0x464e,
+ 0x3b2b, 0x4956,
+ 0x3b39, 0x474b,
+ 0x3b42, 0x4650,
+ 0x3b58, 0x4652,
+ 0x3b60, 0x393a,
+ 0x3b71, 0x4656,
+ 0x3b72, 0x4655,
+ 0x3b7b, 0x4657,
+ 0x3b7c, 0x385a,
+ 0x3b80, 0x41e2,
+ 0x3b96, 0x3a9c,
+ 0x3b99, 0x3a98,
+ 0x3ba1, 0x41e9,
+ 0x3bbc, 0x43c8,
+ 0x3bbe, 0x3db1,
+ 0x3bc2, 0x4134,
+ 0x3bc4, 0x3aa0,
+ 0x3bd7, 0x3aac,
+ 0x3bdd, 0x465f,
+ 0x3bec, 0x4664,
+ 0x3bf2, 0x4666,
+ 0x3bf3, 0x41f3,
+ 0x3bf4, 0x3a6e,
+ 0x3c0d, 0x41f7,
+ 0x3c11, 0x3e40,
+ 0x3c15, 0x3998,
+ 0x3c54, 0x3e00,
+ 0x3ccb, 0x4670,
+ 0x3ccd, 0x3ce5,
+ 0x3cd1, 0x4003,
+ 0x3cd6, 0x3cf7,
+ 0x3cdc, 0x404e,
+ 0x3ceb, 0x4217,
+ 0x3cef, 0x4675,
+ 0x3d13, 0x3773,
+ 0x3d1d, 0x393c,
+ 0x3d32, 0x4957,
+ 0x3d3b, 0x4245,
+ 0x3d46, 0x4685,
+ 0x3d4c, 0x3ceb,
+ 0x3d4e, 0x4242,
+ 0x3d51, 0x38ea,
+ 0x3d5f, 0x4159,
+ 0x3d62, 0x3c5e,
+ 0x3d69, 0x3cea,
+ 0x3d6a, 0x4689,
+ 0x3d6f, 0x3cfc,
+ 0x3d75, 0x468a,
+ 0x3d7d, 0x3c2f,
+ 0x3d85, 0x494b,
+ 0x3d8a, 0x468d,
+ 0x3d8f, 0x3abd,
+ 0x3d91, 0x468f,
+ 0x3da5, 0x3d56,
+ 0x3dad, 0x4699,
+ 0x3db4, 0x40a6,
+ 0x3dbf, 0x37d0,
+ 0x3dc6, 0x48de,
+ 0x3dc7, 0x4164,
+ 0x3dcc, 0x3d6f,
+ 0x3dcd, 0x3af3,
+ 0x3dd3, 0x37e1,
+ 0x3ddb, 0x3fff,
+ 0x3de7, 0x3999,
+ 0x3de8, 0x425d,
+ 0x3deb, 0x3e5a,
+ 0x3df3, 0x46d4,
+ 0x3df7, 0x48ab,
+ 0x3dfc, 0x462b,
+ 0x3dfd, 0x3c14,
+ 0x3e06, 0x491d,
+ 0x3e40, 0x4169,
+ 0x3e43, 0x436d,
+ 0x3e48, 0x4595,
+ 0x3e55, 0x427f,
+ 0x3e74, 0x3ee2,
+ 0x3ea8, 0x4304,
+ 0x3ea9, 0x46ed,
+ 0x3eaa, 0x4075,
+ 0x3ead, 0x3b9d,
+ 0x3eb1, 0x3ad8,
+ 0x3eb8, 0x3a4b,
+ 0x3ebf, 0x3b0b,
+ 0x3ec2, 0x3bd8,
+ 0x3ec7, 0x3975,
+ 0x3eca, 0x46f1,
+ 0x3ecc, 0x3be2,
+ 0x3ed0, 0x3854,
+ 0x3ed1, 0x46f2,
+ 0x3ed6, 0x3cad,
+ 0x3ed7, 0x429f,
+ 0x3eda, 0x3d02,
+ 0x3ede, 0x39f2,
+ 0x3ee1, 0x3ca8,
+ 0x3ee2, 0x46f6,
+ 0x3ee7, 0x3bdc,
+ 0x3ee9, 0x3ca4,
+ 0x3eeb, 0x396a,
+ 0x3ef0, 0x46f7,
+ 0x3ef3, 0x3add,
+ 0x3ef4, 0x46f8,
+ 0x3efa, 0x46f9,
+ 0x3efc, 0x3be8,
+ 0x3eff, 0x3af5,
+ 0x3f00, 0x3c0d,
+ 0x3f04, 0x42c3,
+ 0x3f06, 0x3ad7,
+ 0x3f0e, 0x46fb,
+ 0x3f53, 0x46fc,
+ 0x3f58, 0x3ae9,
+ 0x3f59, 0x4089,
+ 0x3f63, 0x3ae6,
+ 0x3f7c, 0x4700,
+ 0x3f93, 0x45cd,
+ 0x3fc0, 0x43cf,
+ 0x3fd7, 0x43d1,
+ 0x3fdc, 0x4704,
+ 0x3fe5, 0x46df,
+ 0x3fed, 0x4335,
+ 0x3ff9, 0x45d7,
+ 0x3ffa, 0x4354,
+ 0x4004, 0x410e,
+ 0x401d, 0x4709,
+ 0x4039, 0x470b,
+ 0x4045, 0x470c,
+ 0x4053, 0x45b6,
+ 0x4057, 0x399d,
+ 0x4062, 0x3bcb,
+ 0x4065, 0x3fd3,
+ 0x406a, 0x470f,
+ 0x406f, 0x4710,
+ 0x40a8, 0x43d5,
+ 0x40bb, 0x45c0,
+ 0x40bf, 0x3eec,
+ 0x40c8, 0x3b0e,
+ 0x40d8, 0x41ab,
+ 0x40df, 0x3e17,
+ 0x40fa, 0x3ebe,
+ 0x4103, 0x43d7,
+ 0x4104, 0x425c,
+ 0x4109, 0x471c,
+ 0x410e, 0x3b1b,
+ 0x4132, 0x3b25,
+ 0x4167, 0x471f,
+ 0x416c, 0x38ae,
+ 0x416e, 0x3b23,
+ 0x417f, 0x3b82,
+ 0x4190, 0x46c0,
+ 0x41b2, 0x4720,
+ 0x41c4, 0x4723,
+ 0x41ca, 0x373f,
+ 0x41cf, 0x4726,
+ 0x41db, 0x37bf,
+ 0x41ef, 0x3743,
+ 0x41f9, 0x3b3e,
+ 0x4211, 0x3b41,
+ 0x4240, 0x37f1,
+ 0x4260, 0x472b,
+ 0x426a, 0x3b55,
+ 0x427a, 0x472c,
+ 0x428c, 0x472f,
+ 0x4294, 0x4731,
+ 0x42b5, 0x4010,
+ 0x42b9, 0x38a6,
+ 0x42bc, 0x3c8a,
+ 0x42f4, 0x3bb9,
+ 0x42fb, 0x3cee,
+ 0x42fc, 0x41e6,
+ 0x432b, 0x377d,
+ 0x436e, 0x46ca,
+ 0x4397, 0x473b,
+ 0x43ba, 0x435f,
+ 0x43c1, 0x4695,
+ 0x43d9, 0x433e,
+ 0x43df, 0x3e49,
+ 0x43ed, 0x4745,
+ 0x43f2, 0x3e48,
+ 0x4401, 0x474a,
+ 0x4402, 0x3b73,
+ 0x4413, 0x474f,
+ 0x4425, 0x4751,
+ 0x442d, 0x4752,
+ 0x447a, 0x37af,
+ 0x448f, 0x4758,
+ 0x449f, 0x3ae2,
+ 0x44a0, 0x37ed,
+ 0x44a2, 0x4079,
+ 0x44b0, 0x475c,
+ 0x44b7, 0x3fa1,
+ 0x44c0, 0x3c07,
+ 0x44c5, 0x4210,
+ 0x44ce, 0x3d23,
+ 0x44dd, 0x39dd,
+ 0x44df, 0x3d22,
+ 0x44e4, 0x37e2,
+ 0x44e9, 0x41cf,
+ 0x44ea, 0x3b71,
+ 0x44eb, 0x3cf2,
+ 0x44ec, 0x3eb4,
+ 0x44f4, 0x3992,
+ 0x4503, 0x469f,
+ 0x4504, 0x4763,
+ 0x4509, 0x3e50,
+ 0x450b, 0x37d4,
+ 0x4516, 0x37f9,
+ 0x451d, 0x3767,
+ 0x4527, 0x37f7,
+ 0x452e, 0x3cd3,
+ 0x4533, 0x3c51,
+ 0x453b, 0x476a,
+ 0x453d, 0x38c4,
+ 0x453f, 0x3e12,
+ 0x4543, 0x37f3,
+ 0x4551, 0x3ae4,
+ 0x4552, 0x40b3,
+ 0x4555, 0x423e,
+ 0x455c, 0x378b,
+ 0x4562, 0x4940,
+ 0x456a, 0x3804,
+ 0x4577, 0x476e,
+ 0x4585, 0x38c5,
+ 0x45e9, 0x3ee4,
+ 0x4606, 0x4773,
+ 0x460f, 0x3815,
+ 0x4615, 0x3843,
+ 0x4617, 0x4774,
+ 0x465b, 0x381d,
+ 0x467a, 0x39e9,
+ 0x4680, 0x3d01,
+ 0x46cf, 0x3ba0,
+ 0x46d0, 0x3dfa,
+ 0x46f5, 0x3b9f,
+ 0x4713, 0x3833,
+ 0x4718, 0x3dc7,
+ 0x474e, 0x3ebc,
+ 0x477c, 0x3dcd,
+ 0x4798, 0x4781,
+ 0x47a6, 0x40a3,
+ 0x47b6, 0x3eea,
+ 0x47d5, 0x431a,
+ 0x47ed, 0x4783,
+ 0x47f4, 0x432f,
+ 0x4800, 0x461e,
+ 0x480b, 0x4352,
+ 0x4837, 0x4787,
+ 0x485d, 0x410f,
+ 0x4871, 0x3d03,
+ 0x489b, 0x3bbd,
+ 0x48ad, 0x4791,
+ 0x48ae, 0x494d,
+ 0x48d0, 0x3da7,
+ 0x48dd, 0x4120,
+ 0x48ed, 0x4288,
+ 0x48f3, 0x3ec1,
+ 0x48fa, 0x3e44,
+ 0x4906, 0x3bc7,
+ 0x4911, 0x4584,
+ 0x491e, 0x4794,
+ 0x4925, 0x3c0f,
+ 0x492a, 0x46ae,
+ 0x492d, 0x46cd,
+ 0x4935, 0x3cc3,
+ 0x493c, 0x3bf8,
+ 0x493e, 0x3d06,
+ 0x4945, 0x47a3,
+ 0x4951, 0x47a4,
+ 0x4953, 0x42ad,
+ 0x4965, 0x3899,
+ 0x496a, 0x47a9,
+ 0x4972, 0x3a24,
+ 0x4989, 0x379b,
+ 0x49a1, 0x38b7,
+ 0x49a7, 0x47ae,
+ 0x49df, 0x38aa,
+ 0x49e5, 0x47b1,
+ 0x49e7, 0x4621,
+ 0x4a0f, 0x38c3,
+ 0x4a1d, 0x3bec,
+ 0x4a24, 0x47b2,
+ 0x4a35, 0x47b4,
+ 0x4a96, 0x3ce7,
+ 0x4ab4, 0x4361,
+ 0x4ab8, 0x3da8,
+ 0x4ad1, 0x38e3,
+ 0x4ae4, 0x47b7,
+ 0x4aff, 0x38f2,
+ 0x4b19, 0x47b9,
+ 0x4b2c, 0x461f,
+ 0x4b37, 0x41a9,
+ 0x4b6f, 0x3c16,
+ 0x4b70, 0x47c0,
+ 0x4b72, 0x38fc,
+ 0x4b7b, 0x3c8d,
+ 0x4b7e, 0x400a,
+ 0x4b8e, 0x39f7,
+ 0x4b90, 0x3c20,
+ 0x4b93, 0x3a8c,
+ 0x4b96, 0x3942,
+ 0x4b97, 0x3c24,
+ 0x4b9d, 0x47c2,
+ 0x4bbd, 0x3c23,
+ 0x4bbe, 0x3954,
+ 0x4bc0, 0x3ddc,
+ 0x4c04, 0x3fbb,
+ 0x4c07, 0x3fb7,
+ 0x4c0e, 0x390c,
+ 0x4c3b, 0x3f3c,
+ 0x4c3e, 0x457b,
+ 0x4c5b, 0x3ed9,
+ 0x4c6d, 0x47c9,
+ 0x4c7d, 0x3e66,
+ 0x4ca4, 0x48be,
+ 0x4cae, 0x3c42,
+ 0x4cb0, 0x3c45,
+ 0x4cb7, 0x3e21,
+ 0x4ccd, 0x4578,
+ 0x4ce1, 0x3ef3,
+ 0x4ced, 0x40ab,
+ 0x4d09, 0x3ed6,
+ 0x4d10, 0x4117,
+ 0x4d34, 0x3935,
+ 0x4d91, 0x43f5,
+ 0x4d9c, 0x48c4,
+ 0x4e00, 0x0253,
+ 0x4e01, 0x0255,
+ 0x4e03, 0x0256,
+ 0x4e04, 0x48fe,
+ 0x4e07, 0x1771,
+ 0x4e08, 0x0269,
+ 0x4e09, 0x0267,
+ 0x4e0a, 0x026a,
+ 0x4e0b, 0x0268,
+ 0x4e0c, 0x1772,
+ 0x4e0d, 0x0294,
+ 0x4e0e, 0x177a,
+ 0x4e0f, 0x1778,
+ 0x4e10, 0x0293,
+ 0x4e11, 0x0292,
+ 0x4e14, 0x02f2,
+ 0x4e15, 0x02f1,
+ 0x4e16, 0x02f0,
+ 0x4e18, 0x02f3,
+ 0x4e19, 0x02ef,
+ 0x4e1a, 0x48fd,
+ 0x4e1c, 0x48e0,
+ 0x4e1e, 0x036e,
+ 0x4e21, 0x3d6d,
+ 0x4e24, 0x458d,
+ 0x4e26, 0x0528,
+ 0x4e28, 0x0218,
+ 0x4e2a, 0x3f57,
+ 0x4e2b, 0x026b,
+ 0x4e2c, 0x44f3,
+ 0x4e2d, 0x0295,
+ 0x4e2e, 0x177b,
+ 0x4e30, 0x0296,
+ 0x4e31, 0x178e,
+ 0x4e32, 0x0415,
+ 0x4e33, 0x18f4,
+ 0x4e36, 0x0219,
+ 0x4e37, 0x4517,
+ 0x4e38, 0x026c,
+ 0x4e39, 0x0297,
+ 0x4e3b, 0x02f4,
+ 0x4e3c, 0x178f,
+ 0x4e3d, 0x4537,
+ 0x4e3f, 0x021a,
+ 0x4e41, 0x36af,
+ 0x4e42, 0x176c,
+ 0x4e43, 0x0257,
+ 0x4e45, 0x026e,
+ 0x4e47, 0x1773,
+ 0x4e48, 0x026f,
+ 0x4e49, 0x408e,
+ 0x4e4b, 0x0298,
+ 0x4e4d, 0x02f5,
+ 0x4e4e, 0x02f7,
+ 0x4e4f, 0x02f6,
+ 0x4e52, 0x0370,
+ 0x4e56, 0x0529,
+ 0x4e58, 0x0831,
+ 0x4e59, 0x0254,
+ 0x4e5a, 0x36b1,
+ 0x4e5b, 0x44e5,
+ 0x4e5c, 0x176d,
+ 0x4e5d, 0x0258,
+ 0x4e5e, 0x0271,
+ 0x4e5f, 0x0270,
+ 0x4e69, 0x0372,
+ 0x4e6a, 0x3de5,
+ 0x4e73, 0x052a,
+ 0x4e78, 0x3d8e,
+ 0x4e7e, 0x09fb,
+ 0x4e7f, 0x1e35,
+ 0x4e80, 0x458e,
+ 0x4e81, 0x43bc,
+ 0x4e82, 0x0dbe,
+ 0x4e83, 0x2361,
+ 0x4e85, 0x021b,
+ 0x4e86, 0x0259,
+ 0x4e87, 0x458f,
+ 0x4e88, 0x029a,
+ 0x4e89, 0x459c,
+ 0x4e8b, 0x052b,
+ 0x4e8c, 0x025a,
+ 0x4e8d, 0x1774,
+ 0x4e8e, 0x0272,
+ 0x4e91, 0x029b,
+ 0x4e92, 0x029d,
+ 0x4e93, 0x177c,
+ 0x4e94, 0x029e,
+ 0x4e95, 0x029c,
+ 0x4e98, 0x39c4,
+ 0x4e99, 0x0373,
+ 0x4e9a, 0x48d5,
+ 0x4e9b, 0x052c,
+ 0x4e9e, 0x052d,
+ 0x4e9f, 0x06a3,
+ 0x4ea0, 0x021c,
+ 0x4ea1, 0x0273,
+ 0x4ea2, 0x029f,
+ 0x4ea4, 0x0374,
+ 0x4ea5, 0x0376,
+ 0x4ea6, 0x0375,
+ 0x4ea8, 0x0416,
+ 0x4eab, 0x052e,
+ 0x4ead, 0x06a4,
+ 0x4eb3, 0x0832,
+ 0x4eb6, 0x2363,
+ 0x4eb7, 0x413c,
+ 0x4eb9, 0x3377,
+ 0x4eba, 0x025b,
+ 0x4ebb, 0x44e6,
+ 0x4ebc, 0x39b1,
+ 0x4ebf, 0x4590,
+ 0x4ec0, 0x02a1,
+ 0x4ec1, 0x02a0,
+ 0x4ec2, 0x177d,
+ 0x4ec3, 0x02a2,
+ 0x4ec4, 0x02a8,
+ 0x4ec6, 0x02a3,
+ 0x4ec8, 0x177f,
+ 0x4ec9, 0x177e,
+ 0x4eca, 0x02a6,
+ 0x4ecd, 0x02a5,
+ 0x4ece, 0x3f62,
+ 0x4ed4, 0x02fa,
+ 0x4ed8, 0x02f9,
+ 0x4ed9, 0x0300,
+ 0x4eda, 0x1795,
+ 0x4edc, 0x1791,
+ 0x4edd, 0x1794,
+ 0x4ede, 0x0301,
+ 0x4edf, 0x0311,
+ 0x4ee1, 0x1793,
+ 0x4ee3, 0x02fe,
+ 0x4ee5, 0x02f8,
+ 0x4ee8, 0x1790,
+ 0x4ee9, 0x1792,
+ 0x4eea, 0x48cb,
+ 0x4eeb, 0x4591,
+ 0x4eee, 0x3d76,
+ 0x4ef0, 0x0383,
+ 0x4ef1, 0x17ba,
+ 0x4ef2, 0x0380,
+ 0x4ef3, 0x0384,
+ 0x4ef4, 0x17c4,
+ 0x4ef5, 0x17b8,
+ 0x4ef6, 0x0381,
+ 0x4ef7, 0x17bc,
+ 0x4ef8, 0x39ad,
+ 0x4efb, 0x0382,
+ 0x4efd, 0x0385,
+ 0x4eff, 0x0377,
+ 0x4f00, 0x17bb,
+ 0x4f01, 0x0386,
+ 0x4f02, 0x17bf,
+ 0x4f03, 0x39c8,
+ 0x4f04, 0x17c3,
+ 0x4f05, 0x17c0,
+ 0x4f08, 0x17bd,
+ 0x4f09, 0x0378,
+ 0x4f0a, 0x037a,
+ 0x4f0b, 0x0387,
+ 0x4f0d, 0x037c,
+ 0x4f0e, 0x17b5,
+ 0x4f0f, 0x037f,
+ 0x4f10, 0x037d,
+ 0x4f12, 0x17c5,
+ 0x4f13, 0x17c2,
+ 0x4f14, 0x17b9,
+ 0x4f15, 0x037b,
+ 0x4f18, 0x17b6,
+ 0x4f19, 0x0379,
+ 0x4f1a, 0x453c,
+ 0x4f1d, 0x17be,
+ 0x4f22, 0x17c1,
+ 0x4f28, 0x453d,
+ 0x4f29, 0x39be,
+ 0x4f2c, 0x17b7,
+ 0x4f2d, 0x182f,
+ 0x4f2f, 0x042c,
+ 0x4f30, 0x041f,
+ 0x4f32, 0x393d,
+ 0x4f33, 0x1830,
+ 0x4f34, 0x041c,
+ 0x4f36, 0x042e,
+ 0x4f37, 0x4592,
+ 0x4f38, 0x0424,
+ 0x4f39, 0x3f65,
+ 0x4f3a, 0x0423,
+ 0x4f3b, 0x1824,
+ 0x4f3c, 0x0427,
+ 0x4f3d, 0x0422,
+ 0x4f3e, 0x1829,
+ 0x4f3f, 0x1831,
+ 0x4f41, 0x182d,
+ 0x4f42, 0x39cb,
+ 0x4f43, 0x0425,
+ 0x4f45, 0x3b8f,
+ 0x4f46, 0x0428,
+ 0x4f47, 0x0419,
+ 0x4f48, 0x0431,
+ 0x4f49, 0x1826,
+ 0x4f4b, 0x39b4,
+ 0x4f4c, 0x1900,
+ 0x4f4d, 0x0417,
+ 0x4f4e, 0x042d,
+ 0x4f4f, 0x0418,
+ 0x4f50, 0x0420,
+ 0x4f52, 0x182b,
+ 0x4f53, 0x1827,
+ 0x4f54, 0x0426,
+ 0x4f55, 0x041e,
+ 0x4f56, 0x1823,
+ 0x4f57, 0x041a,
+ 0x4f58, 0x182e,
+ 0x4f59, 0x042f,
+ 0x4f5a, 0x0432,
+ 0x4f5b, 0x041d,
+ 0x4f5c, 0x042a,
+ 0x4f5d, 0x0430,
+ 0x4f5e, 0x041b,
+ 0x4f5f, 0x182c,
+ 0x4f60, 0x042b,
+ 0x4f61, 0x1832,
+ 0x4f62, 0x1825,
+ 0x4f63, 0x0429,
+ 0x4f64, 0x1828,
+ 0x4f67, 0x182a,
+ 0x4f69, 0x053d,
+ 0x4f6a, 0x1902,
+ 0x4f6b, 0x190e,
+ 0x4f6c, 0x0535,
+ 0x4f6e, 0x190f,
+ 0x4f6f, 0x0530,
+ 0x4f70, 0x053a,
+ 0x4f72, 0x3c72,
+ 0x4f73, 0x0533,
+ 0x4f74, 0x18fc,
+ 0x4f75, 0x053b,
+ 0x4f76, 0x18fb,
+ 0x4f77, 0x18ff,
+ 0x4f78, 0x1906,
+ 0x4f79, 0x1904,
+ 0x4f7a, 0x0543,
+ 0x4f7b, 0x053e,
+ 0x4f7c, 0x18f6,
+ 0x4f7d, 0x18f8,
+ 0x4f7e, 0x0540,
+ 0x4f7f, 0x0534,
+ 0x4f80, 0x18f9,
+ 0x4f81, 0x1905,
+ 0x4f82, 0x190c,
+ 0x4f83, 0x0539,
+ 0x4f84, 0x18fe,
+ 0x4f85, 0x18f7,
+ 0x4f86, 0x0538,
+ 0x4f87, 0x18fa,
+ 0x4f88, 0x053c,
+ 0x4f89, 0x18fd,
+ 0x4f8a, 0x39b5,
+ 0x4f8b, 0x0537,
+ 0x4f8d, 0x0532,
+ 0x4f8f, 0x0541,
+ 0x4f90, 0x1907,
+ 0x4f91, 0x0542,
+ 0x4f92, 0x190b,
+ 0x4f94, 0x1909,
+ 0x4f95, 0x190d,
+ 0x4f96, 0x053f,
+ 0x4f97, 0x1901,
+ 0x4f98, 0x18f5,
+ 0x4f9a, 0x1903,
+ 0x4f9b, 0x0536,
+ 0x4f9c, 0x1908,
+ 0x4f9d, 0x0531,
+ 0x4f9e, 0x190a,
+ 0x4fa2, 0x39c7,
+ 0x4fa8, 0x453e,
+ 0x4fab, 0x4022,
+ 0x4fae, 0x06b4,
+ 0x4faf, 0x06a8,
+ 0x4fb0, 0x3d4a,
+ 0x4fb2, 0x1a5d,
+ 0x4fb3, 0x1a65,
+ 0x4fb5, 0x06a7,
+ 0x4fb6, 0x06af,
+ 0x4fb7, 0x06bb,
+ 0x4fb9, 0x1a6b,
+ 0x4fba, 0x1a69,
+ 0x4fbb, 0x1a64,
+ 0x4fbd, 0x4594,
+ 0x4fbf, 0x06a9,
+ 0x4fc0, 0x1a6a,
+ 0x4fc1, 0x1a60,
+ 0x4fc2, 0x06b7,
+ 0x4fc3, 0x06ae,
+ 0x4fc4, 0x06b6,
+ 0x4fc5, 0x1a5b,
+ 0x4fc7, 0x1a67,
+ 0x4fc8, 0x46e8,
+ 0x4fc9, 0x1a5e,
+ 0x4fca, 0x06b2,
+ 0x4fcb, 0x1a5f,
+ 0x4fcc, 0x39cf,
+ 0x4fcd, 0x1a5a,
+ 0x4fce, 0x06b9,
+ 0x4fcf, 0x06ac,
+ 0x4fd0, 0x06b5,
+ 0x4fd1, 0x06ab,
+ 0x4fd3, 0x1a5c,
+ 0x4fd4, 0x1a61,
+ 0x4fd6, 0x1a68,
+ 0x4fd7, 0x06b3,
+ 0x4fd8, 0x06b0,
+ 0x4fd9, 0x1a63,
+ 0x4fda, 0x06b8,
+ 0x4fdb, 0x1a66,
+ 0x4fdc, 0x1a62,
+ 0x4fdd, 0x06ad,
+ 0x4fde, 0x06ba,
+ 0x4fdf, 0x06b1,
+ 0x4fe0, 0x06aa,
+ 0x4fe1, 0x06a6,
+ 0x4fe4, 0x3c66,
+ 0x4fe5, 0x39d0,
+ 0x4fec, 0x1a6c,
+ 0x4fee, 0x084c,
+ 0x4fef, 0x0836,
+ 0x4ff1, 0x0846,
+ 0x4ff2, 0x3f28,
+ 0x4ff3, 0x084b,
+ 0x4ff4, 0x1c24,
+ 0x4ff5, 0x1c23,
+ 0x4ff6, 0x1c28,
+ 0x4ff8, 0x0839,
+ 0x4ff9, 0x37b3,
+ 0x4ffa, 0x0842,
+ 0x4ffd, 0x3f26,
+ 0x4ffe, 0x084f,
+ 0x5000, 0x0843,
+ 0x5003, 0x4596,
+ 0x5005, 0x1c1d,
+ 0x5006, 0x083c,
+ 0x5007, 0x1c1e,
+ 0x5008, 0x4024,
+ 0x5009, 0x0851,
+ 0x500b, 0x0848,
+ 0x500c, 0x0833,
+ 0x500e, 0x1c31,
+ 0x500f, 0x0a0c,
+ 0x5011, 0x0841,
+ 0x5012, 0x0840,
+ 0x5013, 0x1c1f,
+ 0x5014, 0x0844,
+ 0x5015, 0x1e45,
+ 0x5016, 0x083b,
+ 0x5017, 0x1c2a,
+ 0x5018, 0x084a,
+ 0x5019, 0x0849,
+ 0x501a, 0x083f,
+ 0x501b, 0x1c22,
+ 0x501c, 0x1c2b,
+ 0x501e, 0x1c1c,
+ 0x501f, 0x083e,
+ 0x5020, 0x1c2c,
+ 0x5021, 0x0847,
+ 0x5022, 0x1c20,
+ 0x5023, 0x0835,
+ 0x5025, 0x0838,
+ 0x5026, 0x0837,
+ 0x5027, 0x1c2d,
+ 0x5028, 0x0845,
+ 0x5029, 0x083a,
+ 0x502a, 0x084e,
+ 0x502b, 0x0850,
+ 0x502c, 0x1c27,
+ 0x502d, 0x084d,
+ 0x502e, 0x39cc,
+ 0x502f, 0x1c2f,
+ 0x5030, 0x1c21,
+ 0x5031, 0x1c30,
+ 0x5033, 0x1c25,
+ 0x5034, 0x3910,
+ 0x5035, 0x1c2e,
+ 0x5037, 0x1c26,
+ 0x503c, 0x083d,
+ 0x5040, 0x1e4d,
+ 0x5041, 0x1e41,
+ 0x5043, 0x0a00,
+ 0x5045, 0x1e46,
+ 0x5046, 0x1e4c,
+ 0x5047, 0x09ff,
+ 0x5048, 0x1e3f,
+ 0x5049, 0x0a03,
+ 0x504a, 0x1e43,
+ 0x504b, 0x1e3c,
+ 0x504c, 0x0a01,
+ 0x504d, 0x1e40,
+ 0x504e, 0x0a06,
+ 0x504f, 0x0a0b,
+ 0x5051, 0x1e51,
+ 0x5053, 0x1e3b,
+ 0x5055, 0x0a07,
+ 0x5056, 0x3f2c,
+ 0x5057, 0x1e50,
+ 0x5058, 0x39d1,
+ 0x505a, 0x0a02,
+ 0x505b, 0x1e42,
+ 0x505c, 0x09fe,
+ 0x505d, 0x1e3d,
+ 0x505e, 0x1e39,
+ 0x505f, 0x1e47,
+ 0x5060, 0x1e3a,
+ 0x5061, 0x1e38,
+ 0x5062, 0x1e44,
+ 0x5063, 0x1e4a,
+ 0x5065, 0x0a04,
+ 0x5066, 0x3dc9,
+ 0x5068, 0x20b8,
+ 0x5069, 0x1e48,
+ 0x506a, 0x1e37,
+ 0x506b, 0x1e49,
+ 0x506c, 0x39cd,
+ 0x506d, 0x0a0e,
+ 0x506e, 0x1e4e,
+ 0x506f, 0x0a0d,
+ 0x5070, 0x1e36,
+ 0x5072, 0x1e3e,
+ 0x5073, 0x1e4f,
+ 0x5074, 0x0a09,
+ 0x5075, 0x0a08,
+ 0x5076, 0x0a05,
+ 0x5077, 0x0a0a,
+ 0x507a, 0x09fc,
+ 0x507d, 0x09fd,
+ 0x5080, 0x0bec,
+ 0x5081, 0x39ce,
+ 0x5082, 0x20bb,
+ 0x5083, 0x20b4,
+ 0x5085, 0x0be9,
+ 0x5087, 0x20bc,
+ 0x5088, 0x439c,
+ 0x508b, 0x20b2,
+ 0x508c, 0x20b5,
+ 0x508d, 0x0be8,
+ 0x508e, 0x20b6,
+ 0x5090, 0x41ec,
+ 0x5091, 0x0beb,
+ 0x5092, 0x20ba,
+ 0x5094, 0x20b0,
+ 0x5095, 0x20af,
+ 0x5096, 0x0bed,
+ 0x5098, 0x0bee,
+ 0x5099, 0x0bea,
+ 0x509a, 0x0bef,
+ 0x509b, 0x20ae,
+ 0x509c, 0x20b9,
+ 0x509d, 0x20b7,
+ 0x509e, 0x20b1,
+ 0x50a2, 0x0be7,
+ 0x50a3, 0x20b3,
+ 0x50a6, 0x3f3f,
+ 0x50ac, 0x0dc5,
+ 0x50ad, 0x0dbf,
+ 0x50ae, 0x2367,
+ 0x50af, 0x0dc8,
+ 0x50b0, 0x236d,
+ 0x50b1, 0x2370,
+ 0x50b2, 0x0dc1,
+ 0x50b4, 0x236a,
+ 0x50b5, 0x0dc0,
+ 0x50b6, 0x2373,
+ 0x50b7, 0x0dc6,
+ 0x50b8, 0x2374,
+ 0x50ba, 0x236f,
+ 0x50bb, 0x0dc7,
+ 0x50bd, 0x2364,
+ 0x50be, 0x0dc4,
+ 0x50bf, 0x2365,
+ 0x50c1, 0x236e,
+ 0x50c2, 0x236c,
+ 0x50c4, 0x2368,
+ 0x50c5, 0x0dc3,
+ 0x50c6, 0x2366,
+ 0x50c7, 0x0dc9,
+ 0x50c8, 0x236b,
+ 0x50c9, 0x2372,
+ 0x50ca, 0x2369,
+ 0x50cb, 0x2371,
+ 0x50cd, 0x39c5,
+ 0x50ce, 0x0f88,
+ 0x50cf, 0x0f85,
+ 0x50d0, 0x38d1,
+ 0x50d1, 0x0f86,
+ 0x50d3, 0x261c,
+ 0x50d4, 0x2614,
+ 0x50d5, 0x0f84,
+ 0x50d6, 0x0f81,
+ 0x50d7, 0x2615,
+ 0x50d9, 0x3fce,
+ 0x50da, 0x0f83,
+ 0x50db, 0x2618,
+ 0x50dd, 0x261a,
+ 0x50de, 0x4031,
+ 0x50df, 0x3afd,
+ 0x50e0, 0x2621,
+ 0x50e1, 0x4171,
+ 0x50e3, 0x2620,
+ 0x50e4, 0x261b,
+ 0x50e5, 0x0f80,
+ 0x50e6, 0x2613,
+ 0x50e7, 0x0f7e,
+ 0x50e8, 0x2616,
+ 0x50e9, 0x0f89,
+ 0x50ea, 0x2619,
+ 0x50ec, 0x261d,
+ 0x50ed, 0x0f82,
+ 0x50ee, 0x0f7f,
+ 0x50ef, 0x261f,
+ 0x50f0, 0x261e,
+ 0x50f1, 0x0f87,
+ 0x50f3, 0x2617,
+ 0x50f4, 0x3ce9,
+ 0x50f5, 0x1105,
+ 0x50f6, 0x2883,
+ 0x50f8, 0x2880,
+ 0x50f9, 0x1106,
+ 0x50fb, 0x1104,
+ 0x50fc, 0x39d2,
+ 0x50fd, 0x2887,
+ 0x50fe, 0x2884,
+ 0x50ff, 0x287d,
+ 0x5100, 0x1103,
+ 0x5101, 0x4032,
+ 0x5102, 0x1107,
+ 0x5103, 0x287e,
+ 0x5104, 0x1102,
+ 0x5105, 0x110a,
+ 0x5106, 0x2881,
+ 0x5108, 0x1108,
+ 0x510a, 0x2888,
+ 0x510b, 0x2885,
+ 0x510d, 0x39c6,
+ 0x510e, 0x4034,
+ 0x5110, 0x128d,
+ 0x5111, 0x2b04,
+ 0x5112, 0x128a,
+ 0x5113, 0x2b01,
+ 0x5114, 0x128c,
+ 0x5115, 0x128e,
+ 0x5117, 0x2b02,
+ 0x5118, 0x128b,
+ 0x511a, 0x2b03,
+ 0x511c, 0x2b00,
+ 0x511f, 0x13b5,
+ 0x5120, 0x2d3e,
+ 0x5121, 0x13b6,
+ 0x5122, 0x2d3c,
+ 0x5124, 0x2d3d,
+ 0x5125, 0x2d3b,
+ 0x5126, 0x2d3a,
+ 0x5129, 0x2d3f,
+ 0x512a, 0x13b4,
+ 0x512b, 0x39ae,
+ 0x512d, 0x2f0f,
+ 0x5130, 0x287f,
+ 0x5131, 0x2f0e,
+ 0x5132, 0x13b7,
+ 0x5133, 0x1575,
+ 0x5134, 0x307a,
+ 0x5137, 0x1668,
+ 0x5139, 0x32c6,
+ 0x513a, 0x32c5,
+ 0x513b, 0x16bc,
+ 0x513c, 0x16bb,
+ 0x513d, 0x340e,
+ 0x513f, 0x025c,
+ 0x5140, 0x0274,
+ 0x5141, 0x02aa,
+ 0x5143, 0x02a9,
+ 0x5144, 0x0303,
+ 0x5145, 0x0302,
+ 0x5146, 0x038a,
+ 0x5147, 0x0389,
+ 0x5148, 0x038b,
+ 0x5149, 0x0388,
+ 0x514b, 0x0434,
+ 0x514c, 0x0433,
+ 0x514d, 0x0435,
+ 0x5152, 0x0545,
+ 0x5154, 0x0544,
+ 0x5155, 0x0546,
+ 0x5156, 0x439a,
+ 0x5157, 0x06bc,
+ 0x5159, 0x0119,
+ 0x515a, 0x1c32,
+ 0x515b, 0x011a,
+ 0x515c, 0x0a0f,
+ 0x515d, 0x011c,
+ 0x515e, 0x011b,
+ 0x515f, 0x20bd,
+ 0x5160, 0x403a,
+ 0x5161, 0x011d,
+ 0x5162, 0x0f8a,
+ 0x5163, 0x011e,
+ 0x5165, 0x025d,
+ 0x5167, 0x02ab,
+ 0x5168, 0x038c,
+ 0x5169, 0x0547,
+ 0x516a, 0x403c,
+ 0x516b, 0x025e,
+ 0x516c, 0x02ae,
+ 0x516d, 0x02ac,
+ 0x5171, 0x038d,
+ 0x5174, 0x453f,
+ 0x5175, 0x0436,
+ 0x5176, 0x0549,
+ 0x5177, 0x0548,
+ 0x5178, 0x054a,
+ 0x5179, 0x3ace,
+ 0x517c, 0x0852,
+ 0x5180, 0x128f,
+ 0x5182, 0x021d,
+ 0x5186, 0x439f,
+ 0x5187, 0x1779,
+ 0x5188, 0x36b6,
+ 0x5189, 0x0304,
+ 0x518d, 0x038e,
+ 0x518f, 0x1833,
+ 0x5191, 0x06be,
+ 0x5192, 0x06bd,
+ 0x5193, 0x1c34,
+ 0x5194, 0x1c33,
+ 0x5195, 0x0a10,
+ 0x5196, 0x021e,
+ 0x5197, 0x02af,
+ 0x5198, 0x1780,
+ 0x519a, 0x3ea3,
+ 0x519c, 0x4540,
+ 0x519e, 0x1910,
+ 0x51a0, 0x06bf,
+ 0x51a2, 0x0855,
+ 0x51a4, 0x0853,
+ 0x51a7, 0x3ea6,
+ 0x51a8, 0x39da,
+ 0x51aa, 0x1290,
+ 0x51ab, 0x021f,
+ 0x51ac, 0x0306,
+ 0x51b0, 0x038f,
+ 0x51b1, 0x17c6,
+ 0x51b2, 0x4048,
+ 0x51b3, 0x4051,
+ 0x51b4, 0x3d7c,
+ 0x51b5, 0x4012,
+ 0x51b6, 0x0437,
+ 0x51b8, 0x4049,
+ 0x51b9, 0x1834,
+ 0x51bc, 0x1911,
+ 0x51bd, 0x054b,
+ 0x51be, 0x1912,
+ 0x51c3, 0x39db,
+ 0x51c4, 0x1c36,
+ 0x51c6, 0x0858,
+ 0x51c7, 0x422a,
+ 0x51c8, 0x1c38,
+ 0x51c9, 0x404b,
+ 0x51ca, 0x1c35,
+ 0x51cb, 0x0859,
+ 0x51cc, 0x0857,
+ 0x51cd, 0x0856,
+ 0x51ce, 0x1c39,
+ 0x51cf, 0x404c,
+ 0x51d0, 0x1e52,
+ 0x51d1, 0x404d,
+ 0x51d2, 0x3dad,
+ 0x51d3, 0x404f,
+ 0x51d4, 0x20be,
+ 0x51d7, 0x2375,
+ 0x51d8, 0x2622,
+ 0x51db, 0x459a,
+ 0x51dc, 0x110b,
+ 0x51dd, 0x1291,
+ 0x51de, 0x2b05,
+ 0x51df, 0x424f,
+ 0x51e0, 0x025f,
+ 0x51e1, 0x026d,
+ 0x51e2, 0x4052,
+ 0x51e4, 0x4541,
+ 0x51ed, 0x4054,
+ 0x51f0, 0x0a11,
+ 0x51f1, 0x0bf1,
+ 0x51f3, 0x0f8b,
+ 0x51f4, 0x4178,
+ 0x51f5, 0x176e,
+ 0x51f6, 0x02b0,
+ 0x51f8, 0x0309,
+ 0x51f9, 0x0307,
+ 0x51fc, 0x459b,
+ 0x51fd, 0x054c,
+ 0x51fe, 0x3f0a,
+ 0x5200, 0x0260,
+ 0x5202, 0x36b3,
+ 0x5203, 0x0275,
+ 0x5205, 0x43a1,
+ 0x5206, 0x02b1,
+ 0x5209, 0x1797,
+ 0x520a, 0x030a,
+ 0x520b, 0x4059,
+ 0x520c, 0x1796,
+ 0x520e, 0x0393,
+ 0x5210, 0x17c8,
+ 0x5211, 0x0391,
+ 0x5213, 0x17c7,
+ 0x5216, 0x0394,
+ 0x5217, 0x0390,
+ 0x521c, 0x1835,
+ 0x521d, 0x068b,
+ 0x521e, 0x1836,
+ 0x521f, 0x3f60,
+ 0x5220, 0x4930,
+ 0x5221, 0x1837,
+ 0x5224, 0x043a,
+ 0x5225, 0x0439,
+ 0x5226, 0x405a,
+ 0x5227, 0x43a2,
+ 0x5228, 0x043d,
+ 0x5229, 0x043b,
+ 0x522e, 0x0552,
+ 0x5230, 0x0551,
+ 0x5231, 0x1917,
+ 0x5232, 0x1914,
+ 0x5234, 0x3efb,
+ 0x5235, 0x1913,
+ 0x5236, 0x0553,
+ 0x5237, 0x054f,
+ 0x5238, 0x054e,
+ 0x523a, 0x0550,
+ 0x523b, 0x054d,
+ 0x523c, 0x405b,
+ 0x5241, 0x0554,
+ 0x5243, 0x06c1,
+ 0x5244, 0x1a6d,
+ 0x5246, 0x1916,
+ 0x5247, 0x06c6,
+ 0x5249, 0x1a6e,
+ 0x524a, 0x06c2,
+ 0x524b, 0x06c5,
+ 0x524c, 0x06c4,
+ 0x524d, 0x06c3,
+ 0x524e, 0x06c0,
+ 0x5252, 0x1c3c,
+ 0x5254, 0x085c,
+ 0x5255, 0x1c3f,
+ 0x5256, 0x085a,
+ 0x5257, 0x405d,
+ 0x5259, 0x39e4,
+ 0x525a, 0x1c3b,
+ 0x525b, 0x085d,
+ 0x525c, 0x085b,
+ 0x525d, 0x085e,
+ 0x525e, 0x1c3d,
+ 0x5260, 0x3f29,
+ 0x5261, 0x1c3a,
+ 0x5262, 0x1c40,
+ 0x5268, 0x4619,
+ 0x5269, 0x0bf5,
+ 0x526a, 0x0a12,
+ 0x526b, 0x1e53,
+ 0x526c, 0x1e55,
+ 0x526d, 0x1e54,
+ 0x526e, 0x1e56,
+ 0x526f, 0x0a13,
+ 0x5272, 0x0bf2,
+ 0x5273, 0x3f43,
+ 0x5274, 0x0bf3,
+ 0x5277, 0x0dcb,
+ 0x5278, 0x2377,
+ 0x5279, 0x43a3,
+ 0x527a, 0x2376,
+ 0x527b, 0x2378,
+ 0x527d, 0x0dcc,
+ 0x527f, 0x0dca,
+ 0x5280, 0x2623,
+ 0x5282, 0x0f8d,
+ 0x5283, 0x0f8c,
+ 0x5284, 0x2776,
+ 0x5287, 0x110c,
+ 0x528a, 0x1110,
+ 0x528b, 0x2889,
+ 0x528d, 0x110f,
+ 0x528f, 0x3dbf,
+ 0x5290, 0x459d,
+ 0x5291, 0x1292,
+ 0x5293, 0x1293,
+ 0x5294, 0x405e,
+ 0x5296, 0x307c,
+ 0x5297, 0x32c8,
+ 0x5298, 0x32c7,
+ 0x5299, 0x340f,
+ 0x529a, 0x3f68,
+ 0x529b, 0x0262,
+ 0x529f, 0x030c,
+ 0x52a0, 0x030b,
+ 0x52a1, 0x4542,
+ 0x52a3, 0x0395,
+ 0x52a4, 0x39e5,
+ 0x52a6, 0x17c9,
+ 0x52a8, 0x4543,
+ 0x52a9, 0x043f,
+ 0x52ab, 0x043e,
+ 0x52ac, 0x0441,
+ 0x52ad, 0x1838,
+ 0x52b5, 0x405c,
+ 0x52b9, 0x405f,
+ 0x52bb, 0x0556,
+ 0x52bc, 0x1918,
+ 0x52be, 0x0555,
+ 0x52c0, 0x1a6f,
+ 0x52c1, 0x06ca,
+ 0x52c2, 0x1a70,
+ 0x52c3, 0x06c9,
+ 0x52c5, 0x4060,
+ 0x52c7, 0x06c7,
+ 0x52c9, 0x06c8,
+ 0x52cc, 0x3ee1,
+ 0x52cd, 0x1c41,
+ 0x52d0, 0x4109,
+ 0x52d1, 0x3f2a,
+ 0x52d2, 0x0a14,
+ 0x52d3, 0x1e58,
+ 0x52d5, 0x0a17,
+ 0x52d6, 0x1e57,
+ 0x52d7, 0x0acf,
+ 0x52d8, 0x0a16,
+ 0x52d9, 0x0a15,
+ 0x52db, 0x0bf8,
+ 0x52dd, 0x0bf7,
+ 0x52de, 0x0bf6,
+ 0x52df, 0x0dcd,
+ 0x52e0, 0x4063,
+ 0x52e1, 0x39e7,
+ 0x52e2, 0x0dd0,
+ 0x52e4, 0x0dcf,
+ 0x52e6, 0x0dce,
+ 0x52e9, 0x2625,
+ 0x52eb, 0x2626,
+ 0x52ef, 0x288c,
+ 0x52f0, 0x1111,
+ 0x52f1, 0x288b,
+ 0x52f3, 0x1294,
+ 0x52f4, 0x2d40,
+ 0x52f5, 0x13b8,
+ 0x52f7, 0x307d,
+ 0x52f8, 0x1609,
+ 0x52f9, 0x0220,
+ 0x52fa, 0x0276,
+ 0x52fb, 0x02b4,
+ 0x52fc, 0x1781,
+ 0x52fe, 0x02b5,
+ 0x5301, 0x3d79,
+ 0x5305, 0x030d,
+ 0x5308, 0x0396,
+ 0x5309, 0x183a,
+ 0x530a, 0x1919,
+ 0x530d, 0x06cb,
+ 0x530e, 0x1c42,
+ 0x530f, 0x0a19,
+ 0x5310, 0x0a18,
+ 0x5311, 0x20c0,
+ 0x5312, 0x20bf,
+ 0x5315, 0x0263,
+ 0x5316, 0x02b7,
+ 0x5317, 0x030f,
+ 0x5319, 0x0a1a,
+ 0x531a, 0x176f,
+ 0x531c, 0x1798,
+ 0x531d, 0x0310,
+ 0x531f, 0x17cb,
+ 0x5320, 0x0398,
+ 0x5321, 0x0397,
+ 0x5322, 0x17ca,
+ 0x5323, 0x0442,
+ 0x5327, 0x459e,
+ 0x532a, 0x085f,
+ 0x532c, 0x3f36,
+ 0x532d, 0x1e59,
+ 0x532f, 0x0dd2,
+ 0x5330, 0x2627,
+ 0x5331, 0x0f8e,
+ 0x5332, 0x3fd0,
+ 0x5333, 0x406d,
+ 0x5334, 0x2b06,
+ 0x5337, 0x31c7,
+ 0x5338, 0x0221,
+ 0x5339, 0x02b8,
+ 0x533b, 0x4544,
+ 0x533c, 0x191b,
+ 0x533d, 0x1a71,
+ 0x533e, 0x0a1d,
+ 0x533f, 0x0a1b,
+ 0x5341, 0x0264,
+ 0x5342, 0x4947,
+ 0x5343, 0x0277,
+ 0x5344, 0x016b,
+ 0x5345, 0x02bb,
+ 0x5347, 0x02ba,
+ 0x5348, 0x02b9,
+ 0x5349, 0x0313,
+ 0x534a, 0x0312,
+ 0x534c, 0x1799,
+ 0x534d, 0x17cc,
+ 0x534e, 0x4545,
+ 0x5351, 0x055a,
+ 0x5352, 0x0557,
+ 0x5353, 0x0559,
+ 0x5354, 0x0558,
+ 0x5357, 0x06cc,
+ 0x535a, 0x0bf9,
+ 0x535c, 0x0265,
+ 0x535d, 0x4501,
+ 0x535e, 0x02bc,
+ 0x535f, 0x43a7,
+ 0x5360, 0x0315,
+ 0x5361, 0x0314,
+ 0x5363, 0x183b,
+ 0x5364, 0x480a,
+ 0x5366, 0x055b,
+ 0x5367, 0x3ecd,
+ 0x5369, 0x0222,
+ 0x536c, 0x1782,
+ 0x536d, 0x407a,
+ 0x536e, 0x0317,
+ 0x536f, 0x0316,
+ 0x5370, 0x0399,
+ 0x5372, 0x183c,
+ 0x5373, 0x0443,
+ 0x5374, 0x407b,
+ 0x5375, 0x0444,
+ 0x5377, 0x055c,
+ 0x537b, 0x06cd,
+ 0x537c, 0x1a72,
+ 0x537d, 0x4901,
+ 0x537e, 0x407d,
+ 0x537f, 0x0860,
+ 0x5382, 0x1770,
+ 0x5384, 0x02bd,
+ 0x538a, 0x17cd,
+ 0x538e, 0x183d,
+ 0x5392, 0x191c,
+ 0x5393, 0x4082,
+ 0x5394, 0x191d,
+ 0x5396, 0x1a74,
+ 0x5397, 0x1a73,
+ 0x5398, 0x1a76,
+ 0x5399, 0x1a75,
+ 0x539a, 0x06ce,
+ 0x539c, 0x1e5a,
+ 0x539d, 0x0862,
+ 0x539e, 0x1c43,
+ 0x539f, 0x0861,
+ 0x53a0, 0x4084,
+ 0x53a2, 0x3e2b,
+ 0x53a4, 0x20c1,
+ 0x53a5, 0x0bfa,
+ 0x53a6, 0x413b,
+ 0x53a7, 0x20c2,
+ 0x53a8, 0x413e,
+ 0x53a9, 0x45a0,
+ 0x53aa, 0x3fc6,
+ 0x53ab, 0x4085,
+ 0x53ac, 0x2628,
+ 0x53ad, 0x0f8f,
+ 0x53ae, 0x4086,
+ 0x53b0, 0x45a2,
+ 0x53b2, 0x1112,
+ 0x53b4, 0x307e,
+ 0x53b6, 0x0223,
+ 0x53b9, 0x1783,
+ 0x53bb, 0x0318,
+ 0x53c1, 0x408b,
+ 0x53c2, 0x43a6,
+ 0x53c3, 0x0a1e,
+ 0x53c5, 0x408c,
+ 0x53c8, 0x0266,
+ 0x53c9, 0x0278,
+ 0x53ca, 0x02bf,
+ 0x53cb, 0x02be,
+ 0x53cc, 0x38b6,
+ 0x53cd, 0x02c0,
+ 0x53d0, 0x39fa,
+ 0x53d1, 0x4546,
+ 0x53d2, 0x3e3d,
+ 0x53d4, 0x0560,
+ 0x53d6, 0x055f,
+ 0x53d7, 0x0561,
+ 0x53d8, 0x4547,
+ 0x53d9, 0x4090,
+ 0x53da, 0x3f39,
+ 0x53db, 0x06cf,
+ 0x53df, 0x0863,
+ 0x53e0, 0x4093,
+ 0x53e1, 0x2b07,
+ 0x53e2, 0x14c9,
+ 0x53e3, 0x0279,
+ 0x53e4, 0x031a,
+ 0x53e5, 0x0329,
+ 0x53e6, 0x0324,
+ 0x53e8, 0x031f,
+ 0x53e9, 0x031e,
+ 0x53ea, 0x0325,
+ 0x53eb, 0x0323,
+ 0x53ec, 0x031c,
+ 0x53ed, 0x032a,
+ 0x53ee, 0x031d,
+ 0x53ef, 0x0319,
+ 0x53f0, 0x0328,
+ 0x53f1, 0x0327,
+ 0x53f2, 0x0326,
+ 0x53f3, 0x031b,
+ 0x53f5, 0x0322,
+ 0x53f6, 0x4096,
+ 0x53f7, 0x3808,
+ 0x53f8, 0x0321,
+ 0x53fb, 0x032b,
+ 0x53fc, 0x0320,
+ 0x53fe, 0x40c1,
+ 0x5401, 0x03a0,
+ 0x5403, 0x03a6,
+ 0x5404, 0x03a2,
+ 0x5406, 0x03a8,
+ 0x5407, 0x17ce,
+ 0x5408, 0x03a5,
+ 0x5409, 0x039b,
+ 0x540a, 0x039e,
+ 0x540b, 0x03a1,
+ 0x540c, 0x039d,
+ 0x540d, 0x03a4,
+ 0x540e, 0x03a7,
+ 0x540f, 0x039c,
+ 0x5410, 0x039f,
+ 0x5411, 0x03a3,
+ 0x5412, 0x03a9,
+ 0x5413, 0x4098,
+ 0x5414, 0x3c77,
+ 0x5416, 0x3e7f,
+ 0x5418, 0x1847,
+ 0x5419, 0x1844,
+ 0x541a, 0x3e64,
+ 0x541b, 0x0451,
+ 0x541c, 0x1845,
+ 0x541d, 0x0445,
+ 0x541e, 0x0447,
+ 0x541f, 0x045f,
+ 0x5420, 0x045a,
+ 0x5421, 0x4203,
+ 0x5423, 0x45a3,
+ 0x5424, 0x184c,
+ 0x5425, 0x1846,
+ 0x5426, 0x0449,
+ 0x5427, 0x044b,
+ 0x5428, 0x184b,
+ 0x5429, 0x0452,
+ 0x542a, 0x1841,
+ 0x542b, 0x045e,
+ 0x542c, 0x0460,
+ 0x542d, 0x0446,
+ 0x542e, 0x0457,
+ 0x542f, 0x40ac,
+ 0x5430, 0x183f,
+ 0x5431, 0x045d,
+ 0x5432, 0x3e75,
+ 0x5433, 0x044e,
+ 0x5435, 0x0458,
+ 0x5437, 0x1840,
+ 0x5438, 0x0456,
+ 0x5439, 0x0454,
+ 0x543b, 0x0455,
+ 0x543c, 0x045b,
+ 0x543d, 0x1848,
+ 0x543e, 0x0448,
+ 0x5440, 0x045c,
+ 0x5441, 0x184a,
+ 0x5442, 0x0450,
+ 0x5443, 0x044d,
+ 0x5445, 0x1843,
+ 0x5446, 0x044c,
+ 0x5447, 0x184d,
+ 0x5448, 0x044f,
+ 0x544a, 0x0453,
+ 0x544b, 0x3ed1,
+ 0x544d, 0x3ea7,
+ 0x544e, 0x044a,
+ 0x544f, 0x1849,
+ 0x5454, 0x1842,
+ 0x5460, 0x192e,
+ 0x5461, 0x192d,
+ 0x5462, 0x0573,
+ 0x5463, 0x1930,
+ 0x5464, 0x1932,
+ 0x5465, 0x1927,
+ 0x5466, 0x192a,
+ 0x5467, 0x1931,
+ 0x5468, 0x0574,
+ 0x5469, 0x3f32,
+ 0x546a, 0x3d83,
+ 0x546b, 0x1924,
+ 0x546c, 0x1928,
+ 0x546d, 0x409d,
+ 0x546f, 0x192c,
+ 0x5470, 0x1a85,
+ 0x5471, 0x056f,
+ 0x5472, 0x1a89,
+ 0x5473, 0x0562,
+ 0x5474, 0x1929,
+ 0x5475, 0x0563,
+ 0x5476, 0x0570,
+ 0x5477, 0x0569,
+ 0x5478, 0x0565,
+ 0x547a, 0x1925,
+ 0x547b, 0x0568,
+ 0x547c, 0x056d,
+ 0x547d, 0x0576,
+ 0x547e, 0x1926,
+ 0x547f, 0x191f,
+ 0x5480, 0x0567,
+ 0x5481, 0x1920,
+ 0x5482, 0x1922,
+ 0x5484, 0x056a,
+ 0x5485, 0x46d9,
+ 0x5486, 0x056c,
+ 0x5487, 0x191e,
+ 0x5488, 0x1923,
+ 0x548b, 0x0575,
+ 0x548c, 0x0571,
+ 0x548d, 0x192b,
+ 0x548e, 0x0577,
+ 0x548f, 0x40a1,
+ 0x5490, 0x056e,
+ 0x5491, 0x1921,
+ 0x5492, 0x056b,
+ 0x5493, 0x45a7,
+ 0x5494, 0x3e98,
+ 0x5495, 0x0566,
+ 0x5496, 0x0564,
+ 0x5497, 0x3e8a,
+ 0x5498, 0x192f,
+ 0x549a, 0x0572,
+ 0x549c, 0x3f66,
+ 0x549e, 0x47ed,
+ 0x54a0, 0x1a84,
+ 0x54a1, 0x1a78,
+ 0x54a2, 0x1a87,
+ 0x54a3, 0x45a8,
+ 0x54a4, 0x40a2,
+ 0x54a5, 0x1a7a,
+ 0x54a6, 0x06d6,
+ 0x54a7, 0x06e4,
+ 0x54a8, 0x06d2,
+ 0x54a9, 0x06e3,
+ 0x54aa, 0x06db,
+ 0x54ab, 0x06e0,
+ 0x54ac, 0x06d0,
+ 0x54ad, 0x1a79,
+ 0x54ae, 0x1a7f,
+ 0x54af, 0x06df,
+ 0x54b0, 0x1a8b,
+ 0x54b1, 0x06e1,
+ 0x54b2, 0x3744,
+ 0x54b3, 0x06d7,
+ 0x54b4, 0x45a9,
+ 0x54b6, 0x1a81,
+ 0x54b7, 0x1a7e,
+ 0x54b8, 0x06d5,
+ 0x54b9, 0x45aa,
+ 0x54ba, 0x1a77,
+ 0x54bb, 0x06e2,
+ 0x54bc, 0x1a86,
+ 0x54bd, 0x06da,
+ 0x54be, 0x1a88,
+ 0x54bf, 0x06e5,
+ 0x54c0, 0x06d1,
+ 0x54c1, 0x06dc,
+ 0x54c2, 0x06d9,
+ 0x54c3, 0x1a7c,
+ 0x54c4, 0x06dd,
+ 0x54c5, 0x1a82,
+ 0x54c7, 0x06d8,
+ 0x54c8, 0x06de,
+ 0x54c9, 0x06d4,
+ 0x54cb, 0x39a3,
+ 0x54cc, 0x43a8,
+ 0x54cd, 0x3a00,
+ 0x54ce, 0x06d3,
+ 0x54cf, 0x1a7b,
+ 0x54d0, 0x45ab,
+ 0x54d6, 0x1a80,
+ 0x54da, 0x4923,
+ 0x54de, 0x1a8a,
+ 0x54e0, 0x1c57,
+ 0x54e1, 0x0870,
+ 0x54e2, 0x1c45,
+ 0x54e3, 0x4341,
+ 0x54e4, 0x1c4a,
+ 0x54e5, 0x0869,
+ 0x54e6, 0x0874,
+ 0x54e7, 0x1c48,
+ 0x54e8, 0x0864,
+ 0x54e9, 0x086e,
+ 0x54ea, 0x0873,
+ 0x54eb, 0x1c4f,
+ 0x54ed, 0x086f,
+ 0x54ee, 0x0872,
+ 0x54ef, 0x45ac,
+ 0x54f1, 0x1c52,
+ 0x54f2, 0x086a,
+ 0x54f3, 0x1c49,
+ 0x54f7, 0x1c55,
+ 0x54fa, 0x086c,
+ 0x54fb, 0x1c54,
+ 0x54fc, 0x0868,
+ 0x54fd, 0x0877,
+ 0x54ff, 0x1c4c,
+ 0x5501, 0x0866,
+ 0x5502, 0x3ccc,
+ 0x5503, 0x1c59,
+ 0x5504, 0x1c4d,
+ 0x5505, 0x1c51,
+ 0x5506, 0x086b,
+ 0x5507, 0x0876,
+ 0x5508, 0x1c4e,
+ 0x5509, 0x0871,
+ 0x550a, 0x1c53,
+ 0x550b, 0x1c5a,
+ 0x550c, 0x1e69,
+ 0x550d, 0x3a73,
+ 0x550e, 0x1c58,
+ 0x550f, 0x0878,
+ 0x5510, 0x0865,
+ 0x5511, 0x1c50,
+ 0x5512, 0x1c47,
+ 0x5513, 0x3ea9,
+ 0x5514, 0x086d,
+ 0x5517, 0x1c46,
+ 0x5518, 0x45ad,
+ 0x551a, 0x1c4b,
+ 0x551e, 0x3ea8,
+ 0x5523, 0x45ae,
+ 0x5525, 0x4309,
+ 0x5526, 0x1c44,
+ 0x5527, 0x0875,
+ 0x5528, 0x45af,
+ 0x552a, 0x1e61,
+ 0x552b, 0x409a,
+ 0x552c, 0x0a31,
+ 0x552d, 0x1e6f,
+ 0x552e, 0x0a2f,
+ 0x552f, 0x0a2c,
+ 0x5530, 0x1e66,
+ 0x5531, 0x0a28,
+ 0x5532, 0x1e6a,
+ 0x5533, 0x0a33,
+ 0x5534, 0x1e60,
+ 0x5535, 0x1e65,
+ 0x5536, 0x1e64,
+ 0x5537, 0x0867,
+ 0x5538, 0x0a2e,
+ 0x5539, 0x1e6d,
+ 0x553b, 0x1e70,
+ 0x553c, 0x1e5d,
+ 0x553e, 0x0c0c,
+ 0x553f, 0x43a9,
+ 0x5540, 0x1e71,
+ 0x5541, 0x0a34,
+ 0x5543, 0x0a26,
+ 0x5544, 0x0a23,
+ 0x5545, 0x1e68,
+ 0x5546, 0x0a20,
+ 0x5547, 0x40aa,
+ 0x5548, 0x1e6e,
+ 0x5549, 0x4068,
+ 0x554a, 0x0a27,
+ 0x554b, 0x1e72,
+ 0x554d, 0x1e5e,
+ 0x554e, 0x1e6c,
+ 0x554f, 0x0a2a,
+ 0x5550, 0x1e5f,
+ 0x5551, 0x1e62,
+ 0x5552, 0x1e67,
+ 0x5553, 0x43ae,
+ 0x5555, 0x0a2b,
+ 0x5556, 0x0a29,
+ 0x5557, 0x0a35,
+ 0x555c, 0x0a30,
+ 0x555d, 0x40a0,
+ 0x555e, 0x0a24,
+ 0x555f, 0x0abc,
+ 0x5561, 0x0a25,
+ 0x5562, 0x1e63,
+ 0x5563, 0x0a32,
+ 0x5564, 0x0a2d,
+ 0x5565, 0x1e6b,
+ 0x5566, 0x0a22,
+ 0x5569, 0x3e9f,
+ 0x556a, 0x0a21,
+ 0x556b, 0x3b2e,
+ 0x5571, 0x3bc6,
+ 0x5572, 0x3e8b,
+ 0x5573, 0x3f24,
+ 0x5575, 0x1e5b,
+ 0x5577, 0x20c7,
+ 0x5579, 0x435d,
+ 0x557b, 0x0bfb,
+ 0x557c, 0x0bfe,
+ 0x557d, 0x20d2,
+ 0x557e, 0x0c12,
+ 0x557f, 0x20d5,
+ 0x5580, 0x0bfc,
+ 0x5581, 0x20ce,
+ 0x5582, 0x0c02,
+ 0x5583, 0x0c08,
+ 0x5584, 0x0d1b,
+ 0x5586, 0x40ae,
+ 0x5587, 0x0c06,
+ 0x5588, 0x20cb,
+ 0x5589, 0x0c13,
+ 0x558a, 0x0bff,
+ 0x558b, 0x0c07,
+ 0x558c, 0x20d3,
+ 0x558d, 0x2387,
+ 0x558e, 0x20d8,
+ 0x558f, 0x20cc,
+ 0x5590, 0x430e,
+ 0x5591, 0x20c3,
+ 0x5592, 0x20d0,
+ 0x5593, 0x20ca,
+ 0x5594, 0x0c05,
+ 0x5595, 0x20d6,
+ 0x5598, 0x0c01,
+ 0x5599, 0x0c15,
+ 0x559a, 0x0c0e,
+ 0x559c, 0x0c03,
+ 0x559d, 0x0c00,
+ 0x559f, 0x0c0b,
+ 0x55a1, 0x20d7,
+ 0x55a2, 0x20c9,
+ 0x55a3, 0x20cf,
+ 0x55a4, 0x20d1,
+ 0x55a5, 0x20c5,
+ 0x55a6, 0x20d4,
+ 0x55a7, 0x0bfd,
+ 0x55a8, 0x20c4,
+ 0x55a9, 0x40af,
+ 0x55aa, 0x0c04,
+ 0x55ab, 0x0c14,
+ 0x55ac, 0x0c10,
+ 0x55ad, 0x20c6,
+ 0x55ae, 0x0c0a,
+ 0x55b0, 0x38f5,
+ 0x55b1, 0x0c11,
+ 0x55b2, 0x0c0d,
+ 0x55b3, 0x0c09,
+ 0x55b4, 0x39fe,
+ 0x55b5, 0x20cd,
+ 0x55b9, 0x43aa,
+ 0x55ba, 0x3e89,
+ 0x55bb, 0x0c0f,
+ 0x55bc, 0x3dc3,
+ 0x55bf, 0x2385,
+ 0x55c0, 0x2381,
+ 0x55c1, 0x3e4f,
+ 0x55c2, 0x2390,
+ 0x55c3, 0x237a,
+ 0x55c4, 0x2383,
+ 0x55c5, 0x0de0,
+ 0x55c7, 0x0dd9,
+ 0x55c8, 0x238c,
+ 0x55c9, 0x0de3,
+ 0x55ca, 0x237f,
+ 0x55cb, 0x237e,
+ 0x55cc, 0x237c,
+ 0x55cd, 0x238e,
+ 0x55ce, 0x0dd7,
+ 0x55cf, 0x2388,
+ 0x55d0, 0x237d,
+ 0x55d1, 0x0dda,
+ 0x55d2, 0x2386,
+ 0x55d3, 0x0dd5,
+ 0x55d4, 0x2382,
+ 0x55d5, 0x2389,
+ 0x55d6, 0x238b,
+ 0x55d7, 0x45b3,
+ 0x55d8, 0x43ab,
+ 0x55d9, 0x238f,
+ 0x55da, 0x0dde,
+ 0x55db, 0x237b,
+ 0x55dc, 0x0dd8,
+ 0x55dd, 0x2380,
+ 0x55de, 0x3e94,
+ 0x55df, 0x0dd3,
+ 0x55e1, 0x0ddf,
+ 0x55e2, 0x238a,
+ 0x55e3, 0x0ddb,
+ 0x55e5, 0x0de2,
+ 0x55e6, 0x0dd6,
+ 0x55e7, 0x011f,
+ 0x55e8, 0x0dd4,
+ 0x55e9, 0x2384,
+ 0x55ea, 0x3e7c,
+ 0x55ec, 0x37d2,
+ 0x55ef, 0x0ddd,
+ 0x55f0, 0x3e88,
+ 0x55f1, 0x3e83,
+ 0x55f2, 0x238d,
+ 0x55f5, 0x4786,
+ 0x55f6, 0x0f9f,
+ 0x55f7, 0x0f9a,
+ 0x55f9, 0x2637,
+ 0x55fa, 0x2633,
+ 0x55fb, 0x4626,
+ 0x55fc, 0x262d,
+ 0x55fd, 0x0f94,
+ 0x55fe, 0x0f90,
+ 0x55ff, 0x2636,
+ 0x5600, 0x0f91,
+ 0x5601, 0x2630,
+ 0x5602, 0x2632,
+ 0x5604, 0x2635,
+ 0x5605, 0x3e82,
+ 0x5606, 0x0f96,
+ 0x5608, 0x0f9d,
+ 0x5609, 0x0f97,
+ 0x560c, 0x262b,
+ 0x560d, 0x0f98,
+ 0x560f, 0x262e,
+ 0x5610, 0x0f9e,
+ 0x5611, 0x3f4d,
+ 0x5612, 0x262c,
+ 0x5613, 0x2631,
+ 0x5614, 0x0f95,
+ 0x5615, 0x262a,
+ 0x5616, 0x0f9b,
+ 0x5617, 0x0f93,
+ 0x561b, 0x0f92,
+ 0x561c, 0x262f,
+ 0x561d, 0x2634,
+ 0x561e, 0x3e68,
+ 0x561f, 0x0f9c,
+ 0x5620, 0x3f7d,
+ 0x5621, 0x43ad,
+ 0x5622, 0x3e67,
+ 0x5623, 0x4707,
+ 0x5625, 0x3e78,
+ 0x5627, 0x2629,
+ 0x5629, 0x1119,
+ 0x562a, 0x289d,
+ 0x562c, 0x289a,
+ 0x562d, 0x3e63,
+ 0x562e, 0x1113,
+ 0x562f, 0x111f,
+ 0x5632, 0x1116,
+ 0x5633, 0x2898,
+ 0x5634, 0x1118,
+ 0x5635, 0x2890,
+ 0x5636, 0x111e,
+ 0x5637, 0x40b7,
+ 0x5638, 0x289c,
+ 0x5639, 0x1115,
+ 0x563a, 0x289e,
+ 0x563b, 0x1114,
+ 0x563d, 0x2899,
+ 0x563e, 0x289b,
+ 0x563f, 0x1117,
+ 0x5640, 0x2897,
+ 0x5641, 0x2891,
+ 0x5642, 0x288e,
+ 0x5643, 0x3e7e,
+ 0x5645, 0x20c8,
+ 0x5646, 0x2894,
+ 0x5648, 0x288d,
+ 0x5649, 0x2893,
+ 0x564a, 0x2892,
+ 0x564c, 0x288f,
+ 0x564d, 0x40bc,
+ 0x564e, 0x111b,
+ 0x564f, 0x40bd,
+ 0x5650, 0x47cf,
+ 0x5652, 0x45c2,
+ 0x5653, 0x111a,
+ 0x5654, 0x43af,
+ 0x5657, 0x111c,
+ 0x5658, 0x2895,
+ 0x5659, 0x1295,
+ 0x565a, 0x2896,
+ 0x565d, 0x3ef9,
+ 0x565e, 0x2b10,
+ 0x5660, 0x2b09,
+ 0x5661, 0x3812,
+ 0x5662, 0x12a1,
+ 0x5663, 0x2b0d,
+ 0x5664, 0x1299,
+ 0x5665, 0x129d,
+ 0x5666, 0x2b0c,
+ 0x5668, 0x129c,
+ 0x5669, 0x1298,
+ 0x566a, 0x129b,
+ 0x566b, 0x1296,
+ 0x566c, 0x12a0,
+ 0x566d, 0x2b0e,
+ 0x566e, 0x2b0a,
+ 0x566f, 0x129f,
+ 0x5670, 0x2b08,
+ 0x5671, 0x129e,
+ 0x5672, 0x2b0f,
+ 0x5673, 0x2b0b,
+ 0x5674, 0x111d,
+ 0x5676, 0x12a2,
+ 0x5677, 0x2b11,
+ 0x5678, 0x129a,
+ 0x5679, 0x1297,
+ 0x567a, 0x3d85,
+ 0x567b, 0x3eb7,
+ 0x567c, 0x3eed,
+ 0x567e, 0x2d47,
+ 0x567f, 0x2d49,
+ 0x5680, 0x13ba,
+ 0x5681, 0x2d4a,
+ 0x5682, 0x2d48,
+ 0x5683, 0x2d46,
+ 0x5684, 0x2d45,
+ 0x5685, 0x13bc,
+ 0x5686, 0x2d44,
+ 0x5687, 0x13bd,
+ 0x5689, 0x4628,
+ 0x568a, 0x3949,
+ 0x568b, 0x3e4c,
+ 0x568c, 0x2d42,
+ 0x568e, 0x13b9,
+ 0x568f, 0x13be,
+ 0x5690, 0x13bb,
+ 0x5692, 0x39a6,
+ 0x5693, 0x2d41,
+ 0x5695, 0x14ca,
+ 0x5697, 0x2f13,
+ 0x5698, 0x2f11,
+ 0x5699, 0x2f16,
+ 0x569a, 0x2f14,
+ 0x569c, 0x2f12,
+ 0x569d, 0x2f15,
+ 0x569e, 0x39a4,
+ 0x569f, 0x3948,
+ 0x56a1, 0x436b,
+ 0x56a4, 0x3cc8,
+ 0x56a5, 0x1576,
+ 0x56a6, 0x3081,
+ 0x56a8, 0x1577,
+ 0x56aa, 0x3083,
+ 0x56ab, 0x307f,
+ 0x56ac, 0x3084,
+ 0x56ad, 0x3080,
+ 0x56ae, 0x14cb,
+ 0x56af, 0x45f7,
+ 0x56b1, 0x463f,
+ 0x56b2, 0x31c8,
+ 0x56b3, 0x31ca,
+ 0x56b4, 0x160c,
+ 0x56b5, 0x31c9,
+ 0x56b6, 0x160b,
+ 0x56b7, 0x160a,
+ 0x56b9, 0x486f,
+ 0x56bc, 0x160d,
+ 0x56bd, 0x32ca,
+ 0x56bf, 0x3e5d,
+ 0x56c0, 0x166b,
+ 0x56c1, 0x166a,
+ 0x56c2, 0x166c,
+ 0x56c3, 0x32c9,
+ 0x56c5, 0x3379,
+ 0x56c6, 0x3378,
+ 0x56c8, 0x16bd,
+ 0x56c9, 0x16bf,
+ 0x56ca, 0x16be,
+ 0x56cb, 0x337a,
+ 0x56cc, 0x16f6,
+ 0x56cd, 0x3481,
+ 0x56d1, 0x171f,
+ 0x56d3, 0x3480,
+ 0x56d4, 0x34c9,
+ 0x56d6, 0x488a,
+ 0x56d7, 0x1775,
+ 0x56da, 0x032d,
+ 0x56db, 0x032c,
+ 0x56dd, 0x03ac,
+ 0x56de, 0x03ab,
+ 0x56df, 0x17d0,
+ 0x56e0, 0x03aa,
+ 0x56e1, 0x17cf,
+ 0x56e2, 0x4548,
+ 0x56e4, 0x0463,
+ 0x56e5, 0x1850,
+ 0x56e7, 0x184f,
+ 0x56ea, 0x0461,
+ 0x56eb, 0x0464,
+ 0x56ed, 0x40c4,
+ 0x56ee, 0x184e,
+ 0x56ef, 0x40c3,
+ 0x56f0, 0x0462,
+ 0x56f1, 0x40bf,
+ 0x56f7, 0x1933,
+ 0x56f9, 0x1934,
+ 0x56fa, 0x0578,
+ 0x56fd, 0x3d64,
+ 0x56ff, 0x06e6,
+ 0x5700, 0x40c2,
+ 0x5701, 0x1c5b,
+ 0x5703, 0x0879,
+ 0x5707, 0x1e74,
+ 0x5708, 0x0a36,
+ 0x5709, 0x0a38,
+ 0x570a, 0x1e73,
+ 0x570b, 0x0a37,
+ 0x570c, 0x20d9,
+ 0x570d, 0x0c16,
+ 0x5712, 0x0de4,
+ 0x5714, 0x2391,
+ 0x5715, 0x3e36,
+ 0x5716, 0x0fa1,
+ 0x5718, 0x0fa0,
+ 0x571a, 0x289f,
+ 0x571b, 0x2b13,
+ 0x571c, 0x2b12,
+ 0x571d, 0x3a02,
+ 0x571e, 0x3505,
+ 0x571f, 0x027a,
+ 0x5720, 0x1784,
+ 0x5722, 0x179a,
+ 0x5728, 0x03af,
+ 0x5729, 0x03b3,
+ 0x572a, 0x17d2,
+ 0x572c, 0x03b1,
+ 0x572d, 0x03b0,
+ 0x572e, 0x17d1,
+ 0x572f, 0x03b2,
+ 0x5730, 0x03ae,
+ 0x5732, 0x3af9,
+ 0x5733, 0x03ad,
+ 0x5734, 0x17d3,
+ 0x573b, 0x046e,
+ 0x573e, 0x046b,
+ 0x573f, 0x4855,
+ 0x5740, 0x0467,
+ 0x5741, 0x1851,
+ 0x5742, 0x40cc,
+ 0x5743, 0x40de,
+ 0x5745, 0x1852,
+ 0x5746, 0x40c8,
+ 0x5747, 0x0469,
+ 0x5749, 0x1854,
+ 0x574a, 0x0465,
+ 0x574b, 0x1855,
+ 0x574c, 0x1853,
+ 0x574d, 0x0468,
+ 0x574e, 0x046a,
+ 0x574f, 0x046d,
+ 0x5750, 0x046c,
+ 0x5751, 0x0466,
+ 0x5752, 0x1856,
+ 0x5754, 0x4785,
+ 0x5757, 0x47e6,
+ 0x575b, 0x3982,
+ 0x575f, 0x3fbf,
+ 0x5761, 0x057d,
+ 0x5762, 0x1941,
+ 0x5764, 0x057f,
+ 0x5766, 0x057e,
+ 0x5767, 0x3f2b,
+ 0x5768, 0x1942,
+ 0x5769, 0x057c,
+ 0x576a, 0x057b,
+ 0x576b, 0x1938,
+ 0x576d, 0x1937,
+ 0x576f, 0x1935,
+ 0x5770, 0x193a,
+ 0x5771, 0x1939,
+ 0x5772, 0x1936,
+ 0x5773, 0x193f,
+ 0x5775, 0x193d,
+ 0x5776, 0x193b,
+ 0x5777, 0x057a,
+ 0x577a, 0x3f5f,
+ 0x577b, 0x193e,
+ 0x577c, 0x0580,
+ 0x577d, 0x1943,
+ 0x577e, 0x46dc,
+ 0x577f, 0x3a07,
+ 0x5780, 0x193c,
+ 0x5782, 0x06e7,
+ 0x5783, 0x0579,
+ 0x5788, 0x484b,
+ 0x578a, 0x3c7b,
+ 0x578b, 0x06e8,
+ 0x578c, 0x1a90,
+ 0x578d, 0x3a06,
+ 0x578f, 0x1a96,
+ 0x5790, 0x4166,
+ 0x5793, 0x06ee,
+ 0x5794, 0x1a94,
+ 0x5795, 0x1a9a,
+ 0x5797, 0x1a91,
+ 0x5798, 0x1a95,
+ 0x5799, 0x1a97,
+ 0x579a, 0x1a99,
+ 0x579b, 0x1a93,
+ 0x579c, 0x4608,
+ 0x579d, 0x1a92,
+ 0x579e, 0x1a8d,
+ 0x57a0, 0x06e9,
+ 0x57a1, 0x4864,
+ 0x57a2, 0x06eb,
+ 0x57a3, 0x06ea,
+ 0x57a4, 0x1a8f,
+ 0x57a5, 0x1a98,
+ 0x57a7, 0x4914,
+ 0x57aa, 0x4905,
+ 0x57ae, 0x06ed,
+ 0x57b4, 0x4741,
+ 0x57b5, 0x1a8c,
+ 0x57b6, 0x1c66,
+ 0x57b8, 0x1c65,
+ 0x57b9, 0x1c6a,
+ 0x57ba, 0x1c61,
+ 0x57bb, 0x3c79,
+ 0x57bc, 0x1c64,
+ 0x57bd, 0x1c63,
+ 0x57be, 0x372c,
+ 0x57bf, 0x1c67,
+ 0x57c1, 0x1c6b,
+ 0x57c2, 0x087b,
+ 0x57c3, 0x087e,
+ 0x57c4, 0x3b5b,
+ 0x57c6, 0x1c62,
+ 0x57c7, 0x1c68,
+ 0x57c8, 0x3d0b,
+ 0x57cb, 0x087d,
+ 0x57cc, 0x1c5d,
+ 0x57ce, 0x06ec,
+ 0x57cf, 0x1e82,
+ 0x57d0, 0x1c69,
+ 0x57d2, 0x1c60,
+ 0x57d4, 0x087c,
+ 0x57d5, 0x1c5f,
+ 0x57d7, 0x3c7d,
+ 0x57dc, 0x1e79,
+ 0x57dd, 0x3a05,
+ 0x57de, 0x3f01,
+ 0x57df, 0x0a39,
+ 0x57e0, 0x0a3d,
+ 0x57e1, 0x1e89,
+ 0x57e2, 0x1e77,
+ 0x57e3, 0x1e85,
+ 0x57e4, 0x0a3e,
+ 0x57e5, 0x1e87,
+ 0x57e6, 0x40cf,
+ 0x57e7, 0x1e8d,
+ 0x57e9, 0x1e91,
+ 0x57ec, 0x1e88,
+ 0x57ed, 0x1e7c,
+ 0x57ee, 0x1e84,
+ 0x57ef, 0x4754,
+ 0x57f0, 0x1e92,
+ 0x57f1, 0x1e90,
+ 0x57f2, 0x1e86,
+ 0x57f3, 0x1e81,
+ 0x57f4, 0x1e7a,
+ 0x57f5, 0x20e1,
+ 0x57f6, 0x1e78,
+ 0x57f7, 0x0a42,
+ 0x57f8, 0x1e7f,
+ 0x57f9, 0x0a43,
+ 0x57fa, 0x0a3f,
+ 0x57fb, 0x1e75,
+ 0x57fc, 0x1e8b,
+ 0x57fd, 0x1e7d,
+ 0x57fe, 0x408f,
+ 0x5800, 0x1e7b,
+ 0x5801, 0x1e8e,
+ 0x5802, 0x0a40,
+ 0x5803, 0x40d1,
+ 0x5804, 0x1e94,
+ 0x5805, 0x0a3a,
+ 0x5806, 0x0a3c,
+ 0x5807, 0x1e83,
+ 0x5808, 0x1e7e,
+ 0x5809, 0x087f,
+ 0x580a, 0x0a3b,
+ 0x580b, 0x1e80,
+ 0x580c, 0x1e8f,
+ 0x580d, 0x1e93,
+ 0x580e, 0x1e8a,
+ 0x5810, 0x1e8c,
+ 0x5812, 0x3d0a,
+ 0x5814, 0x1e76,
+ 0x5819, 0x20dc,
+ 0x581b, 0x20e5,
+ 0x581c, 0x20e4,
+ 0x581d, 0x0c1e,
+ 0x581e, 0x20dd,
+ 0x5820, 0x0c1f,
+ 0x5821, 0x0c1d,
+ 0x5822, 0x3c28,
+ 0x5823, 0x20df,
+ 0x5824, 0x0c1a,
+ 0x5825, 0x20e3,
+ 0x5826, 0x40d4,
+ 0x5827, 0x20de,
+ 0x5828, 0x20e0,
+ 0x5829, 0x20da,
+ 0x582a, 0x0c18,
+ 0x582c, 0x20ed,
+ 0x582d, 0x20ec,
+ 0x582e, 0x20e9,
+ 0x582f, 0x0c17,
+ 0x5830, 0x0c1b,
+ 0x5832, 0x1c5e,
+ 0x5833, 0x20e6,
+ 0x5834, 0x0c19,
+ 0x5835, 0x0a41,
+ 0x5836, 0x20e8,
+ 0x5837, 0x20db,
+ 0x5838, 0x20eb,
+ 0x5839, 0x20ea,
+ 0x583a, 0x3d72,
+ 0x583b, 0x20ee,
+ 0x583d, 0x239f,
+ 0x583f, 0x20e7,
+ 0x5840, 0x3d82,
+ 0x5844, 0x47bb,
+ 0x5847, 0x3ac2,
+ 0x5848, 0x20e2,
+ 0x5849, 0x2397,
+ 0x584a, 0x0def,
+ 0x584b, 0x0df2,
+ 0x584c, 0x0ded,
+ 0x584d, 0x2396,
+ 0x584e, 0x239a,
+ 0x584f, 0x2395,
+ 0x5851, 0x0de7,
+ 0x5852, 0x0df1,
+ 0x5853, 0x2392,
+ 0x5854, 0x0deb,
+ 0x5855, 0x2399,
+ 0x5857, 0x0de9,
+ 0x5858, 0x0de8,
+ 0x5859, 0x239c,
+ 0x585a, 0x0dea,
+ 0x585b, 0x239e,
+ 0x585c, 0x4949,
+ 0x585d, 0x239b,
+ 0x585e, 0x0de6,
+ 0x585f, 0x43df,
+ 0x5862, 0x0df0,
+ 0x5863, 0x23a0,
+ 0x5864, 0x2394,
+ 0x5865, 0x239d,
+ 0x5868, 0x2393,
+ 0x5869, 0x3d65,
+ 0x586b, 0x0dec,
+ 0x586c, 0x399a,
+ 0x586d, 0x0dee,
+ 0x586f, 0x2398,
+ 0x5871, 0x23a1,
+ 0x5872, 0x3c26,
+ 0x5873, 0x4355,
+ 0x5874, 0x263f,
+ 0x5875, 0x0fa2,
+ 0x5876, 0x2645,
+ 0x5879, 0x0fa7,
+ 0x587a, 0x2641,
+ 0x587b, 0x2648,
+ 0x587c, 0x2639,
+ 0x587d, 0x0fa9,
+ 0x587e, 0x0fa3,
+ 0x587f, 0x263e,
+ 0x5880, 0x1121,
+ 0x5881, 0x263d,
+ 0x5882, 0x2646,
+ 0x5883, 0x0fa4,
+ 0x5885, 0x0fa8,
+ 0x5886, 0x263c,
+ 0x5887, 0x2642,
+ 0x5888, 0x2647,
+ 0x5889, 0x2638,
+ 0x588a, 0x0fa6,
+ 0x588b, 0x2640,
+ 0x588e, 0x2644,
+ 0x588f, 0x264a,
+ 0x5890, 0x263a,
+ 0x5891, 0x2643,
+ 0x5893, 0x0fa5,
+ 0x5894, 0x2649,
+ 0x5898, 0x263b,
+ 0x5899, 0x4618,
+ 0x589a, 0x4903,
+ 0x589c, 0x1125,
+ 0x589d, 0x28a1,
+ 0x589e, 0x1123,
+ 0x589f, 0x1122,
+ 0x58a0, 0x28a3,
+ 0x58a1, 0x28a8,
+ 0x58a3, 0x28a4,
+ 0x58a5, 0x28a7,
+ 0x58a6, 0x1128,
+ 0x58a7, 0x3eeb,
+ 0x58a8, 0x1288,
+ 0x58a9, 0x1127,
+ 0x58aa, 0x40d7,
+ 0x58ab, 0x28a0,
+ 0x58ac, 0x28a6,
+ 0x58ae, 0x1126,
+ 0x58af, 0x28a5,
+ 0x58b0, 0x37a4,
+ 0x58b1, 0x28a2,
+ 0x58b3, 0x1124,
+ 0x58b5, 0x4840,
+ 0x58b6, 0x3dfd,
+ 0x58ba, 0x2b18,
+ 0x58bb, 0x36eb,
+ 0x58bc, 0x2b1a,
+ 0x58bd, 0x2b15,
+ 0x58be, 0x12a4,
+ 0x58bf, 0x2b17,
+ 0x58c1, 0x12a3,
+ 0x58c2, 0x2b19,
+ 0x58c5, 0x12a6,
+ 0x58c6, 0x2b1b,
+ 0x58c7, 0x12a5,
+ 0x58c8, 0x2b14,
+ 0x58c9, 0x2b16,
+ 0x58cb, 0x3a09,
+ 0x58ce, 0x13c2,
+ 0x58cf, 0x2d4d,
+ 0x58d1, 0x13c1,
+ 0x58d2, 0x2d4e,
+ 0x58d3, 0x13c0,
+ 0x58d4, 0x2d4c,
+ 0x58d5, 0x13bf,
+ 0x58d6, 0x2d4b,
+ 0x58d8, 0x14cd,
+ 0x58d9, 0x14cc,
+ 0x58da, 0x3085,
+ 0x58db, 0x3087,
+ 0x58dc, 0x40da,
+ 0x58dd, 0x3086,
+ 0x58de, 0x1578,
+ 0x58e0, 0x40d9,
+ 0x58e2, 0x157a,
+ 0x58e3, 0x31cb,
+ 0x58e4, 0x160e,
+ 0x58e7, 0x3411,
+ 0x58e8, 0x3410,
+ 0x58e9, 0x1720,
+ 0x58eb, 0x027b,
+ 0x58ec, 0x02c1,
+ 0x58ef, 0x046f,
+ 0x58f0, 0x4549,
+ 0x58f2, 0x3d68,
+ 0x58f3, 0x3c7a,
+ 0x58f4, 0x1a9b,
+ 0x58f9, 0x0c20,
+ 0x58fb, 0x40dc,
+ 0x58fc, 0x23a2,
+ 0x58fd, 0x0faa,
+ 0x58fe, 0x264b,
+ 0x58ff, 0x28a9,
+ 0x5902, 0x0224,
+ 0x5903, 0x1785,
+ 0x5904, 0x454a,
+ 0x5905, 0x4599,
+ 0x5906, 0x1857,
+ 0x5907, 0x454b,
+ 0x590a, 0x0224,
+ 0x590c, 0x1944,
+ 0x590d, 0x1a9c,
+ 0x590e, 0x1c6c,
+ 0x590f, 0x0880,
+ 0x5911, 0x4274,
+ 0x5912, 0x3088,
+ 0x5914, 0x166d,
+ 0x5915, 0x027c,
+ 0x5916, 0x032e,
+ 0x5917, 0x179c,
+ 0x5919, 0x03b4,
+ 0x591c, 0x0581,
+ 0x591f, 0x40e3,
+ 0x5920, 0x0a44,
+ 0x5922, 0x0fac,
+ 0x5924, 0x0fad,
+ 0x5925, 0x0fab,
+ 0x5927, 0x027d,
+ 0x5929, 0x02c2,
+ 0x592a, 0x02c4,
+ 0x592b, 0x02c3,
+ 0x592c, 0x1786,
+ 0x592d, 0x02c5,
+ 0x592e, 0x032f,
+ 0x592f, 0x179d,
+ 0x5931, 0x0330,
+ 0x5932, 0x454c,
+ 0x5934, 0x454d,
+ 0x5937, 0x03b6,
+ 0x593c, 0x17d4,
+ 0x593e, 0x0470,
+ 0x5940, 0x1858,
+ 0x5944, 0x0585,
+ 0x5945, 0x1945,
+ 0x5947, 0x0583,
+ 0x5949, 0x0582,
+ 0x594a, 0x1c6d,
+ 0x594e, 0x06f2,
+ 0x594f, 0x06f1,
+ 0x5950, 0x06f3,
+ 0x5951, 0x06f0,
+ 0x5953, 0x1a9d,
+ 0x5954, 0x0586,
+ 0x5955, 0x06ef,
+ 0x5957, 0x0881,
+ 0x595a, 0x0883,
+ 0x595c, 0x1e95,
+ 0x5960, 0x0c22,
+ 0x5961, 0x20ef,
+ 0x5962, 0x0a45,
+ 0x5965, 0x4852,
+ 0x5967, 0x0df3,
+ 0x5969, 0x0faf,
+ 0x596a, 0x0fae,
+ 0x596b, 0x264c,
+ 0x596d, 0x1129,
+ 0x596e, 0x12a7,
+ 0x5970, 0x2f17,
+ 0x5971, 0x337b,
+ 0x5972, 0x3412,
+ 0x5973, 0x027e,
+ 0x5974, 0x0331,
+ 0x5975, 0x3e6a,
+ 0x5976, 0x0332,
+ 0x5977, 0x17da,
+ 0x5978, 0x03b9,
+ 0x5979, 0x03bc,
+ 0x597b, 0x17d8,
+ 0x597c, 0x17d6,
+ 0x597d, 0x03bb,
+ 0x597e, 0x17d9,
+ 0x597f, 0x17db,
+ 0x5980, 0x17d5,
+ 0x5981, 0x03be,
+ 0x5982, 0x03bd,
+ 0x5983, 0x03ba,
+ 0x5984, 0x03b8,
+ 0x5985, 0x17d7,
+ 0x5989, 0x3d30,
+ 0x598a, 0x047b,
+ 0x598d, 0x0478,
+ 0x598e, 0x185d,
+ 0x598f, 0x1860,
+ 0x5990, 0x185f,
+ 0x5992, 0x0472,
+ 0x5993, 0x047a,
+ 0x5994, 0x3c99,
+ 0x5996, 0x0477,
+ 0x5997, 0x185c,
+ 0x5998, 0x185a,
+ 0x5999, 0x0476,
+ 0x599a, 0x3bb0,
+ 0x599d, 0x0471,
+ 0x599e, 0x0474,
+ 0x599f, 0x3daf,
+ 0x59a0, 0x185b,
+ 0x59a1, 0x1862,
+ 0x59a2, 0x185e,
+ 0x59a3, 0x0475,
+ 0x59a4, 0x0479,
+ 0x59a5, 0x047c,
+ 0x59a6, 0x1859,
+ 0x59a7, 0x1861,
+ 0x59a8, 0x0473,
+ 0x59ac, 0x3d81,
+ 0x59ae, 0x058b,
+ 0x59af, 0x0593,
+ 0x59b0, 0x3cd8,
+ 0x59b1, 0x1951,
+ 0x59b2, 0x194a,
+ 0x59b3, 0x0594,
+ 0x59b4, 0x1955,
+ 0x59b5, 0x1946,
+ 0x59b6, 0x194d,
+ 0x59b7, 0x3f2d,
+ 0x59b8, 0x3a10,
+ 0x59b9, 0x058a,
+ 0x59ba, 0x1947,
+ 0x59bb, 0x0588,
+ 0x59bc, 0x194e,
+ 0x59bd, 0x1952,
+ 0x59be, 0x0587,
+ 0x59c0, 0x1953,
+ 0x59c1, 0x194c,
+ 0x59c3, 0x194f,
+ 0x59c4, 0x3d04,
+ 0x59c5, 0x0596,
+ 0x59c6, 0x058d,
+ 0x59c7, 0x1956,
+ 0x59c8, 0x1954,
+ 0x59c9, 0x40ec,
+ 0x59ca, 0x0592,
+ 0x59cb, 0x0590,
+ 0x59cc, 0x194b,
+ 0x59cd, 0x058f,
+ 0x59ce, 0x1949,
+ 0x59cf, 0x1948,
+ 0x59d0, 0x058e,
+ 0x59d1, 0x058c,
+ 0x59d2, 0x0595,
+ 0x59d3, 0x0591,
+ 0x59d4, 0x0589,
+ 0x59d6, 0x1950,
+ 0x59d8, 0x06f5,
+ 0x59d9, 0x40f1,
+ 0x59da, 0x06fc,
+ 0x59db, 0x1aab,
+ 0x59dc, 0x06f4,
+ 0x59dd, 0x1aa3,
+ 0x59de, 0x1a9f,
+ 0x59e0, 0x1aaf,
+ 0x59e1, 0x1a9e,
+ 0x59e3, 0x06f7,
+ 0x59e4, 0x1aa8,
+ 0x59e5, 0x06fa,
+ 0x59e6, 0x06fd,
+ 0x59e8, 0x06f8,
+ 0x59e9, 0x1aac,
+ 0x59ea, 0x06fb,
+ 0x59eb, 0x3d59,
+ 0x59ec, 0x088a,
+ 0x59ed, 0x1ab2,
+ 0x59ee, 0x1aa0,
+ 0x59ef, 0x3d38,
+ 0x59f0, 0x3bb2,
+ 0x59f1, 0x1aa2,
+ 0x59f2, 0x1aa9,
+ 0x59f3, 0x1aad,
+ 0x59f4, 0x1ab1,
+ 0x59f5, 0x1aae,
+ 0x59f6, 0x1aa7,
+ 0x59f7, 0x1aaa,
+ 0x59f8, 0x3e4a,
+ 0x59f9, 0x40f8,
+ 0x59fa, 0x1aa4,
+ 0x59fb, 0x06ff,
+ 0x59fc, 0x1aa6,
+ 0x59fd, 0x1aa5,
+ 0x59fe, 0x1ab0,
+ 0x59ff, 0x06f6,
+ 0x5a00, 0x1aa1,
+ 0x5a01, 0x06fe,
+ 0x5a02, 0x3b8d,
+ 0x5a03, 0x06f9,
+ 0x5a09, 0x0890,
+ 0x5a0a, 0x1c75,
+ 0x5a0b, 0x3c89,
+ 0x5a0c, 0x088f,
+ 0x5a0d, 0x3b38,
+ 0x5a0f, 0x1c73,
+ 0x5a11, 0x0884,
+ 0x5a12, 0x3a13,
+ 0x5a13, 0x0889,
+ 0x5a15, 0x1c72,
+ 0x5a16, 0x1c6f,
+ 0x5a17, 0x1c74,
+ 0x5a18, 0x0885,
+ 0x5a19, 0x1c6e,
+ 0x5a1b, 0x0888,
+ 0x5a1c, 0x0886,
+ 0x5a1e, 0x1c76,
+ 0x5a1f, 0x0887,
+ 0x5a20, 0x088b,
+ 0x5a21, 0x3a1b,
+ 0x5a23, 0x088c,
+ 0x5a24, 0x40e8,
+ 0x5a25, 0x088e,
+ 0x5a27, 0x3de1,
+ 0x5a29, 0x088d,
+ 0x5a2a, 0x3b3b,
+ 0x5a2b, 0x3d40,
+ 0x5a2c, 0x3a0f,
+ 0x5a2d, 0x1c70,
+ 0x5a33, 0x1c77,
+ 0x5a35, 0x1e9c,
+ 0x5a36, 0x0a46,
+ 0x5a37, 0x20fd,
+ 0x5a38, 0x1e9b,
+ 0x5a39, 0x1eae,
+ 0x5a3c, 0x0a4c,
+ 0x5a3d, 0x3ac0,
+ 0x5a3e, 0x1eac,
+ 0x5a40, 0x0a4b,
+ 0x5a41, 0x0a47,
+ 0x5a42, 0x1eb5,
+ 0x5a43, 0x1ea5,
+ 0x5a44, 0x1ea8,
+ 0x5a45, 0x3917,
+ 0x5a46, 0x0a4f,
+ 0x5a47, 0x1eb2,
+ 0x5a48, 0x1eaa,
+ 0x5a49, 0x0a48,
+ 0x5a4a, 0x0a50,
+ 0x5a4c, 0x1eaf,
+ 0x5a4d, 0x1ead,
+ 0x5a50, 0x1e9e,
+ 0x5a51, 0x1eb3,
+ 0x5a52, 0x1ea7,
+ 0x5a53, 0x1ea2,
+ 0x5a54, 0x4603,
+ 0x5a55, 0x1e98,
+ 0x5a56, 0x1eb4,
+ 0x5a57, 0x1ea4,
+ 0x5a58, 0x1e97,
+ 0x5a59, 0x3b34,
+ 0x5a5a, 0x0a4e,
+ 0x5a5b, 0x1ea9,
+ 0x5a5c, 0x1eb6,
+ 0x5a5d, 0x1ea6,
+ 0x5a5e, 0x1e9a,
+ 0x5a5f, 0x1e9f,
+ 0x5a60, 0x1e96,
+ 0x5a61, 0x3d33,
+ 0x5a62, 0x0a4d,
+ 0x5a63, 0x40fb,
+ 0x5a64, 0x1ea3,
+ 0x5a65, 0x1ea0,
+ 0x5a66, 0x0a49,
+ 0x5a67, 0x1e99,
+ 0x5a68, 0x39b7,
+ 0x5a69, 0x1eb1,
+ 0x5a6a, 0x0a4a,
+ 0x5a6b, 0x3a42,
+ 0x5a6c, 0x1ea1,
+ 0x5a6d, 0x1e9d,
+ 0x5a6e, 0x3d3f,
+ 0x5a70, 0x1eb0,
+ 0x5a71, 0x3d34,
+ 0x5a77, 0x0c23,
+ 0x5a78, 0x20f6,
+ 0x5a79, 0x3ce1,
+ 0x5a7a, 0x20f3,
+ 0x5a7b, 0x2104,
+ 0x5a7c, 0x20f8,
+ 0x5a7d, 0x2105,
+ 0x5a7e, 0x3a11,
+ 0x5a7f, 0x0c25,
+ 0x5a81, 0x3a1d,
+ 0x5a82, 0x3d31,
+ 0x5a83, 0x2101,
+ 0x5a84, 0x20fe,
+ 0x5a86, 0x3b81,
+ 0x5a88, 0x4263,
+ 0x5a8a, 0x20ff,
+ 0x5a8b, 0x2102,
+ 0x5a8c, 0x2106,
+ 0x5a8e, 0x1eab,
+ 0x5a8f, 0x2108,
+ 0x5a90, 0x23b6,
+ 0x5a91, 0x4235,
+ 0x5a92, 0x0c26,
+ 0x5a93, 0x2109,
+ 0x5a94, 0x20f1,
+ 0x5a95, 0x20fb,
+ 0x5a96, 0x4100,
+ 0x5a97, 0x2100,
+ 0x5a99, 0x3a0a,
+ 0x5a9a, 0x0c24,
+ 0x5a9b, 0x0c27,
+ 0x5a9c, 0x2107,
+ 0x5a9d, 0x210a,
+ 0x5a9e, 0x20f5,
+ 0x5a9f, 0x20f2,
+ 0x5aa0, 0x4172,
+ 0x5aa1, 0x3cdc,
+ 0x5aa2, 0x20f4,
+ 0x5aa5, 0x20f9,
+ 0x5aa6, 0x20f7,
+ 0x5aa7, 0x0c28,
+ 0x5aa9, 0x2103,
+ 0x5aab, 0x40fa,
+ 0x5aac, 0x20fa,
+ 0x5aae, 0x20fc,
+ 0x5aaf, 0x20f0,
+ 0x5ab0, 0x23aa,
+ 0x5ab1, 0x23a8,
+ 0x5ab2, 0x0dfc,
+ 0x5ab3, 0x0dfa,
+ 0x5ab4, 0x23b2,
+ 0x5ab5, 0x23a9,
+ 0x5ab6, 0x23b3,
+ 0x5ab7, 0x23af,
+ 0x5ab8, 0x23a7,
+ 0x5ab9, 0x23b5,
+ 0x5aba, 0x23a6,
+ 0x5abb, 0x23ad,
+ 0x5abc, 0x0df9,
+ 0x5abd, 0x0df8,
+ 0x5abe, 0x0df7,
+ 0x5abf, 0x23ab,
+ 0x5ac0, 0x23b0,
+ 0x5ac1, 0x0df4,
+ 0x5ac2, 0x0dfb,
+ 0x5ac3, 0x3896,
+ 0x5ac4, 0x23a4,
+ 0x5ac6, 0x23ae,
+ 0x5ac7, 0x23a3,
+ 0x5ac8, 0x23ac,
+ 0x5ac9, 0x0df5,
+ 0x5aca, 0x23b1,
+ 0x5acb, 0x23a5,
+ 0x5acc, 0x0df6,
+ 0x5acd, 0x23b4,
+ 0x5ace, 0x3c88,
+ 0x5acf, 0x43b5,
+ 0x5ad3, 0x4102,
+ 0x5ad5, 0x2650,
+ 0x5ad6, 0x0fb4,
+ 0x5ad7, 0x0fb3,
+ 0x5ad8, 0x0fb5,
+ 0x5ad9, 0x265c,
+ 0x5ada, 0x2652,
+ 0x5adb, 0x2658,
+ 0x5adc, 0x264d,
+ 0x5add, 0x265b,
+ 0x5ade, 0x265a,
+ 0x5adf, 0x265e,
+ 0x5ae0, 0x2657,
+ 0x5ae1, 0x0fb0,
+ 0x5ae2, 0x2656,
+ 0x5ae3, 0x0fb6,
+ 0x5ae4, 0x3b86,
+ 0x5ae5, 0x264f,
+ 0x5ae6, 0x0fb1,
+ 0x5ae8, 0x265d,
+ 0x5ae9, 0x0fb2,
+ 0x5aea, 0x2651,
+ 0x5aeb, 0x2654,
+ 0x5aec, 0x2659,
+ 0x5aed, 0x2653,
+ 0x5aee, 0x264e,
+ 0x5af0, 0x3ee7,
+ 0x5af2, 0x37f5,
+ 0x5af3, 0x2655,
+ 0x5af4, 0x28ab,
+ 0x5af5, 0x112d,
+ 0x5af6, 0x28ae,
+ 0x5af7, 0x28ad,
+ 0x5af8, 0x28b0,
+ 0x5af9, 0x28b2,
+ 0x5afa, 0x36ee,
+ 0x5afb, 0x112b,
+ 0x5afd, 0x28ac,
+ 0x5afe, 0x3c1d,
+ 0x5aff, 0x28aa,
+ 0x5b01, 0x28b3,
+ 0x5b02, 0x28b1,
+ 0x5b03, 0x28af,
+ 0x5b05, 0x28b5,
+ 0x5b07, 0x28b4,
+ 0x5b08, 0x112f,
+ 0x5b09, 0x112a,
+ 0x5b0b, 0x112c,
+ 0x5b0c, 0x112e,
+ 0x5b0d, 0x48ff,
+ 0x5b0f, 0x28b6,
+ 0x5b10, 0x2b22,
+ 0x5b11, 0x3bf6,
+ 0x5b13, 0x2b21,
+ 0x5b14, 0x2b20,
+ 0x5b16, 0x2b23,
+ 0x5b17, 0x2b1c,
+ 0x5b19, 0x2b1d,
+ 0x5b1a, 0x2b25,
+ 0x5b1b, 0x2b1e,
+ 0x5b1d, 0x12a8,
+ 0x5b1e, 0x2b27,
+ 0x5b1f, 0x4941,
+ 0x5b20, 0x2b26,
+ 0x5b21, 0x2b1f,
+ 0x5b23, 0x2d52,
+ 0x5b24, 0x13c5,
+ 0x5b25, 0x2d50,
+ 0x5b26, 0x2d55,
+ 0x5b27, 0x2d54,
+ 0x5b28, 0x2b24,
+ 0x5b2a, 0x13c4,
+ 0x5b2b, 0x3b84,
+ 0x5b2c, 0x2d53,
+ 0x5b2d, 0x2d4f,
+ 0x5b2e, 0x2d57,
+ 0x5b2f, 0x2d56,
+ 0x5b30, 0x13c3,
+ 0x5b32, 0x2d51,
+ 0x5b34, 0x12a9,
+ 0x5b38, 0x14ce,
+ 0x5b3c, 0x2f18,
+ 0x5b3d, 0x3089,
+ 0x5b40, 0x160f,
+ 0x5b41, 0x38c8,
+ 0x5b43, 0x1610,
+ 0x5b44, 0x3a44,
+ 0x5b45, 0x31cc,
+ 0x5b46, 0x42b2,
+ 0x5b47, 0x32cd,
+ 0x5b48, 0x32cc,
+ 0x5b4a, 0x38cd,
+ 0x5b4b, 0x337c,
+ 0x5b4d, 0x3413,
+ 0x5b4e, 0x3482,
+ 0x5b4f, 0x3a31,
+ 0x5b50, 0x027f,
+ 0x5b53, 0x0281,
+ 0x5b54, 0x02c6,
+ 0x5b55, 0x0333,
+ 0x5b56, 0x17dc,
+ 0x5b57, 0x03bf,
+ 0x5b5a, 0x047f,
+ 0x5b5c, 0x047e,
+ 0x5b5d, 0x047d,
+ 0x5b5f, 0x0597,
+ 0x5b62, 0x1957,
+ 0x5b63, 0x0599,
+ 0x5b64, 0x0598,
+ 0x5b65, 0x1958,
+ 0x5b66, 0x454e,
+ 0x5b68, 0x461d,
+ 0x5b69, 0x0700,
+ 0x5b6b, 0x0891,
+ 0x5b6c, 0x1c78,
+ 0x5b6d, 0x3e5f,
+ 0x5b6e, 0x1eb8,
+ 0x5b70, 0x0a51,
+ 0x5b71, 0x0c2a,
+ 0x5b72, 0x1eb7,
+ 0x5b73, 0x0c29,
+ 0x5b74, 0x3732,
+ 0x5b75, 0x0fb7,
+ 0x5b76, 0x410a,
+ 0x5b77, 0x265f,
+ 0x5b78, 0x12aa,
+ 0x5b7a, 0x13c6,
+ 0x5b7b, 0x2d58,
+ 0x5b7c, 0x410c,
+ 0x5b7d, 0x1611,
+ 0x5b7f, 0x16c0,
+ 0x5b80, 0x0225,
+ 0x5b81, 0x179e,
+ 0x5b82, 0x4044,
+ 0x5b83, 0x0334,
+ 0x5b84, 0x179f,
+ 0x5b85, 0x03c3,
+ 0x5b87, 0x03c1,
+ 0x5b89, 0x03c4,
+ 0x5b8b, 0x0482,
+ 0x5b8c, 0x0481,
+ 0x5b8e, 0x1863,
+ 0x5b8f, 0x0483,
+ 0x5b90, 0x48e9,
+ 0x5b92, 0x1864,
+ 0x5b93, 0x1959,
+ 0x5b95, 0x195a,
+ 0x5b97, 0x059a,
+ 0x5b98, 0x059c,
+ 0x5b99, 0x059e,
+ 0x5b9a, 0x059b,
+ 0x5b9b, 0x059f,
+ 0x5b9c, 0x059d,
+ 0x5b9d, 0x4116,
+ 0x5b9e, 0x454f,
+ 0x5ba2, 0x0704,
+ 0x5ba3, 0x0701,
+ 0x5ba4, 0x0703,
+ 0x5ba5, 0x0705,
+ 0x5ba6, 0x0702,
+ 0x5ba7, 0x1c79,
+ 0x5ba8, 0x1ab3,
+ 0x5baa, 0x417b,
+ 0x5bac, 0x1c7b,
+ 0x5bad, 0x1c7a,
+ 0x5bae, 0x0897,
+ 0x5bb0, 0x0893,
+ 0x5bb3, 0x0894,
+ 0x5bb4, 0x0896,
+ 0x5bb5, 0x0898,
+ 0x5bb6, 0x0895,
+ 0x5bb8, 0x089a,
+ 0x5bb9, 0x0899,
+ 0x5bbf, 0x0a56,
+ 0x5bc0, 0x1eba,
+ 0x5bc1, 0x1eb9,
+ 0x5bc2, 0x0a55,
+ 0x5bc3, 0x3f25,
+ 0x5bc4, 0x0a54,
+ 0x5bc5, 0x0a53,
+ 0x5bc6, 0x0a57,
+ 0x5bc7, 0x0a52,
+ 0x5bca, 0x2110,
+ 0x5bcb, 0x210d,
+ 0x5bcc, 0x0c2c,
+ 0x5bcd, 0x210c,
+ 0x5bce, 0x2111,
+ 0x5bd0, 0x0c2e,
+ 0x5bd1, 0x210f,
+ 0x5bd2, 0x0c2b,
+ 0x5bd3, 0x0c2d,
+ 0x5bd4, 0x210e,
+ 0x5bd5, 0x4111,
+ 0x5bd6, 0x23b7,
+ 0x5bd7, 0x42bb,
+ 0x5bd8, 0x23b8,
+ 0x5bde, 0x0fb8,
+ 0x5bdf, 0x0fc0,
+ 0x5be0, 0x2660,
+ 0x5be1, 0x0fba,
+ 0x5be2, 0x0fbe,
+ 0x5be3, 0x2661,
+ 0x5be4, 0x0fbf,
+ 0x5be5, 0x0fbb,
+ 0x5be7, 0x0fb9,
+ 0x5be8, 0x0fbd,
+ 0x5be9, 0x1132,
+ 0x5bea, 0x210b,
+ 0x5beb, 0x1133,
+ 0x5bec, 0x1131,
+ 0x5bee, 0x1130,
+ 0x5bef, 0x2b28,
+ 0x5bf0, 0x12ab,
+ 0x5bf1, 0x2d59,
+ 0x5bf3, 0x4115,
+ 0x5bf5, 0x157b,
+ 0x5bf6, 0x1612,
+ 0x5bf8, 0x0282,
+ 0x5bfa, 0x03c5,
+ 0x5bff, 0x40dd,
+ 0x5c01, 0x0706,
+ 0x5c03, 0x1c7c,
+ 0x5c04, 0x089b,
+ 0x5c05, 0x4118,
+ 0x5c07, 0x0a5a,
+ 0x5c08, 0x0a59,
+ 0x5c09, 0x0a58,
+ 0x5c0a, 0x0c2f,
+ 0x5c0c, 0x2112,
+ 0x5c0d, 0x0fc1,
+ 0x5c0e, 0x12ac,
+ 0x5c0f, 0x0283,
+ 0x5c10, 0x1787,
+ 0x5c11, 0x02c7,
+ 0x5c12, 0x17a0,
+ 0x5c13, 0x411a,
+ 0x5c14, 0x411c,
+ 0x5c15, 0x17dd,
+ 0x5c16, 0x03c6,
+ 0x5c1a, 0x05a0,
+ 0x5c1c, 0x45ea,
+ 0x5c1e, 0x3a29,
+ 0x5c1f, 0x23ba,
+ 0x5c20, 0x3d89,
+ 0x5c22, 0x0284,
+ 0x5c23, 0x44e8,
+ 0x5c24, 0x02c8,
+ 0x5c25, 0x17de,
+ 0x5c28, 0x1865,
+ 0x5c2a, 0x1866,
+ 0x5c2c, 0x0484,
+ 0x5c30, 0x2113,
+ 0x5c31, 0x0c31,
+ 0x5c33, 0x23bb,
+ 0x5c37, 0x13c7,
+ 0x5c38, 0x0285,
+ 0x5c39, 0x0299,
+ 0x5c3a, 0x02c9,
+ 0x5c3b, 0x17a1,
+ 0x5c3c, 0x0335,
+ 0x5c3e, 0x0488,
+ 0x5c3f, 0x0487,
+ 0x5c40, 0x0485,
+ 0x5c44, 0x195b,
+ 0x5c45, 0x05a2,
+ 0x5c47, 0x195c,
+ 0x5c48, 0x05a1,
+ 0x5c49, 0x411f,
+ 0x5c4a, 0x3f5c,
+ 0x5c4b, 0x070a,
+ 0x5c4c, 0x1ab4,
+ 0x5c4d, 0x0709,
+ 0x5c4e, 0x0707,
+ 0x5c50, 0x089e,
+ 0x5c51, 0x089c,
+ 0x5c53, 0x3f02,
+ 0x5c54, 0x1c7e,
+ 0x5c55, 0x089d,
+ 0x5c56, 0x1c7d,
+ 0x5c58, 0x0892,
+ 0x5c59, 0x1ebb,
+ 0x5c5c, 0x0a5c,
+ 0x5c5e, 0x3d67,
+ 0x5c60, 0x0a5b,
+ 0x5c62, 0x0fc2,
+ 0x5c63, 0x2662,
+ 0x5c64, 0x1134,
+ 0x5c67, 0x28b7,
+ 0x5c68, 0x13c8,
+ 0x5c69, 0x2f19,
+ 0x5c6c, 0x166e,
+ 0x5c6d, 0x3483,
+ 0x5c6e, 0x1776,
+ 0x5c6f, 0x02ca,
+ 0x5c71, 0x0286,
+ 0x5c73, 0x17a3,
+ 0x5c74, 0x17a2,
+ 0x5c79, 0x03c7,
+ 0x5c7a, 0x17e0,
+ 0x5c7c, 0x17df,
+ 0x5c7e, 0x17e2,
+ 0x5c85, 0x4121,
+ 0x5c86, 0x186e,
+ 0x5c88, 0x1869,
+ 0x5c89, 0x186b,
+ 0x5c8a, 0x186d,
+ 0x5c8b, 0x186a,
+ 0x5c8c, 0x048c,
+ 0x5c8d, 0x1867,
+ 0x5c8f, 0x1868,
+ 0x5c90, 0x0489,
+ 0x5c92, 0x186c,
+ 0x5c93, 0x186f,
+ 0x5c94, 0x048b,
+ 0x5c95, 0x1870,
+ 0x5c99, 0x468c,
+ 0x5c9a, 0x4551,
+ 0x5c9c, 0x495a,
+ 0x5c9d, 0x196a,
+ 0x5c9e, 0x3a2a,
+ 0x5c9f, 0x1964,
+ 0x5ca0, 0x195f,
+ 0x5ca1, 0x05a5,
+ 0x5ca2, 0x1967,
+ 0x5ca3, 0x1965,
+ 0x5ca4, 0x195e,
+ 0x5ca5, 0x196b,
+ 0x5ca6, 0x196e,
+ 0x5ca7, 0x1969,
+ 0x5ca8, 0x1962,
+ 0x5ca9, 0x05a7,
+ 0x5caa, 0x1968,
+ 0x5cab, 0x05a8,
+ 0x5cac, 0x1963,
+ 0x5cad, 0x1966,
+ 0x5cae, 0x195d,
+ 0x5caf, 0x1961,
+ 0x5cb0, 0x196d,
+ 0x5cb1, 0x05a9,
+ 0x5cb3, 0x05aa,
+ 0x5cb5, 0x1960,
+ 0x5cb6, 0x196c,
+ 0x5cb7, 0x05a4,
+ 0x5cb8, 0x05a6,
+ 0x5cba, 0x412b,
+ 0x5cc1, 0x43b8,
+ 0x5cc2, 0x3d4c,
+ 0x5cc6, 0x1ac5,
+ 0x5cc7, 0x1abe,
+ 0x5cc8, 0x1ac4,
+ 0x5cc9, 0x1abd,
+ 0x5cca, 0x1abf,
+ 0x5ccb, 0x1ab9,
+ 0x5ccc, 0x1ab7,
+ 0x5cce, 0x1ac6,
+ 0x5ccf, 0x1ac3,
+ 0x5cd0, 0x1ab5,
+ 0x5cd1, 0x3f13,
+ 0x5cd2, 0x070c,
+ 0x5cd3, 0x1ac1,
+ 0x5cd6, 0x1ac0,
+ 0x5cd7, 0x1ab8,
+ 0x5cd8, 0x1ab6,
+ 0x5cd9, 0x070b,
+ 0x5cda, 0x1abc,
+ 0x5cdb, 0x1aba,
+ 0x5cde, 0x1abb,
+ 0x5cdf, 0x1ac7,
+ 0x5ce5, 0x4637,
+ 0x5ce8, 0x08a3,
+ 0x5ce9, 0x4122,
+ 0x5cea, 0x08a2,
+ 0x5cec, 0x1c7f,
+ 0x5ced, 0x089f,
+ 0x5cee, 0x1c81,
+ 0x5cef, 0x4123,
+ 0x5cf0, 0x08a4,
+ 0x5cf1, 0x1c82,
+ 0x5cf4, 0x08a7,
+ 0x5cf6, 0x08a5,
+ 0x5cf7, 0x1c83,
+ 0x5cf8, 0x1ac8,
+ 0x5cf9, 0x1c85,
+ 0x5cfb, 0x08a1,
+ 0x5cfd, 0x08a0,
+ 0x5cff, 0x1c80,
+ 0x5d00, 0x1c84,
+ 0x5d01, 0x08a6,
+ 0x5d06, 0x0a5f,
+ 0x5d07, 0x0a5e,
+ 0x5d0b, 0x1ebd,
+ 0x5d0c, 0x1ec1,
+ 0x5d0d, 0x1ec3,
+ 0x5d0e, 0x0a60,
+ 0x5d0f, 0x1ec6,
+ 0x5d10, 0x4127,
+ 0x5d11, 0x0a64,
+ 0x5d12, 0x1ec8,
+ 0x5d14, 0x0a66,
+ 0x5d15, 0x43b9,
+ 0x5d16, 0x0a62,
+ 0x5d17, 0x0a6a,
+ 0x5d18, 0x4128,
+ 0x5d19, 0x0a67,
+ 0x5d1a, 0x1ebf,
+ 0x5d1b, 0x0a61,
+ 0x5d1d, 0x1ebe,
+ 0x5d1e, 0x1ebc,
+ 0x5d1f, 0x1eca,
+ 0x5d20, 0x1ec0,
+ 0x5d22, 0x0a63,
+ 0x5d23, 0x1ec9,
+ 0x5d24, 0x0a68,
+ 0x5d25, 0x1ec5,
+ 0x5d26, 0x1ec4,
+ 0x5d27, 0x0a69,
+ 0x5d28, 0x1ec2,
+ 0x5d29, 0x0a65,
+ 0x5d2c, 0x3df7,
+ 0x5d2e, 0x1ecb,
+ 0x5d2f, 0x46d3,
+ 0x5d30, 0x1ec7,
+ 0x5d31, 0x2122,
+ 0x5d32, 0x2129,
+ 0x5d33, 0x211e,
+ 0x5d34, 0x0c34,
+ 0x5d35, 0x211a,
+ 0x5d36, 0x212a,
+ 0x5d37, 0x2114,
+ 0x5d38, 0x2127,
+ 0x5d39, 0x2125,
+ 0x5d3a, 0x211f,
+ 0x5d3c, 0x2128,
+ 0x5d3d, 0x2121,
+ 0x5d3e, 0x4629,
+ 0x5d3f, 0x2119,
+ 0x5d40, 0x212b,
+ 0x5d41, 0x2117,
+ 0x5d42, 0x2124,
+ 0x5d43, 0x2115,
+ 0x5d45, 0x212c,
+ 0x5d46, 0x4129,
+ 0x5d47, 0x0c35,
+ 0x5d48, 0x462a,
+ 0x5d49, 0x2126,
+ 0x5d4a, 0x23be,
+ 0x5d4b, 0x2118,
+ 0x5d4c, 0x0c32,
+ 0x5d4e, 0x211c,
+ 0x5d50, 0x0c33,
+ 0x5d51, 0x211b,
+ 0x5d52, 0x2120,
+ 0x5d55, 0x211d,
+ 0x5d56, 0x43ba,
+ 0x5d57, 0x3fca,
+ 0x5d59, 0x2123,
+ 0x5d5b, 0x3dd5,
+ 0x5d5e, 0x23c2,
+ 0x5d62, 0x23c5,
+ 0x5d63, 0x23bd,
+ 0x5d65, 0x23bf,
+ 0x5d67, 0x23c4,
+ 0x5d68, 0x23c3,
+ 0x5d69, 0x0dfd,
+ 0x5d6b, 0x2116,
+ 0x5d6c, 0x23c1,
+ 0x5d6f, 0x0dfe,
+ 0x5d70, 0x46e4,
+ 0x5d71, 0x23bc,
+ 0x5d72, 0x23c0,
+ 0x5d74, 0x3eef,
+ 0x5d77, 0x2669,
+ 0x5d79, 0x2670,
+ 0x5d7a, 0x2667,
+ 0x5d7c, 0x266e,
+ 0x5d7d, 0x2665,
+ 0x5d7e, 0x266d,
+ 0x5d7f, 0x2671,
+ 0x5d80, 0x2664,
+ 0x5d81, 0x2668,
+ 0x5d82, 0x2663,
+ 0x5d84, 0x0fc3,
+ 0x5d85, 0x3e34,
+ 0x5d86, 0x2666,
+ 0x5d87, 0x0fc4,
+ 0x5d88, 0x266c,
+ 0x5d89, 0x266b,
+ 0x5d8a, 0x266a,
+ 0x5d8b, 0x4124,
+ 0x5d8d, 0x266f,
+ 0x5d8e, 0x3f0c,
+ 0x5d92, 0x28bb,
+ 0x5d93, 0x28bd,
+ 0x5d94, 0x1137,
+ 0x5d95, 0x28be,
+ 0x5d97, 0x28b9,
+ 0x5d99, 0x28b8,
+ 0x5d9a, 0x28c2,
+ 0x5d9c, 0x28c0,
+ 0x5d9d, 0x1136,
+ 0x5d9e, 0x28c3,
+ 0x5d9f, 0x28ba,
+ 0x5da0, 0x28bf,
+ 0x5da1, 0x28c1,
+ 0x5da2, 0x28bc,
+ 0x5da4, 0x462d,
+ 0x5da7, 0x2b2c,
+ 0x5da8, 0x2b31,
+ 0x5da9, 0x2b2b,
+ 0x5daa, 0x2b30,
+ 0x5dab, 0x3e39,
+ 0x5dac, 0x2b29,
+ 0x5dad, 0x2b33,
+ 0x5dae, 0x2b2f,
+ 0x5daf, 0x2b34,
+ 0x5db0, 0x2b2e,
+ 0x5db1, 0x2b2a,
+ 0x5db2, 0x2b32,
+ 0x5db4, 0x2b35,
+ 0x5db5, 0x2b2d,
+ 0x5db6, 0x4158,
+ 0x5db7, 0x2d5b,
+ 0x5db8, 0x13cc,
+ 0x5db9, 0x462e,
+ 0x5dba, 0x13ca,
+ 0x5dbc, 0x13c9,
+ 0x5dbd, 0x13cb,
+ 0x5dc0, 0x2f1b,
+ 0x5dc1, 0x3bff,
+ 0x5dc2, 0x3023,
+ 0x5dc3, 0x308c,
+ 0x5dc6, 0x31cd,
+ 0x5dc9, 0x1613,
+ 0x5dcb, 0x32ce,
+ 0x5dcd, 0x166f,
+ 0x5dcf, 0x32cf,
+ 0x5dd1, 0x337f,
+ 0x5dd2, 0x16c2,
+ 0x5dd4, 0x16c1,
+ 0x5dd5, 0x337e,
+ 0x5dd6, 0x16f7,
+ 0x5dd7, 0x412c,
+ 0x5dd8, 0x3414,
+ 0x5ddb, 0x0226,
+ 0x5ddd, 0x0287,
+ 0x5dde, 0x03c8,
+ 0x5ddf, 0x17e3,
+ 0x5de0, 0x1871,
+ 0x5de1, 0x051a,
+ 0x5de2, 0x0a6b,
+ 0x5de5, 0x0288,
+ 0x5de6, 0x0338,
+ 0x5de7, 0x0337,
+ 0x5de8, 0x0336,
+ 0x5deb, 0x048d,
+ 0x5dee, 0x08a8,
+ 0x5df0, 0x23c6,
+ 0x5df1, 0x0289,
+ 0x5df4, 0x02cb,
+ 0x5df5, 0x3f61,
+ 0x5df7, 0x070d,
+ 0x5df9, 0x1ac9,
+ 0x5dfd, 0x0c36,
+ 0x5dfe, 0x028c,
+ 0x5dff, 0x1788,
+ 0x5e02, 0x0339,
+ 0x5e04, 0x17a4,
+ 0x5e06, 0x03c9,
+ 0x5e09, 0x4140,
+ 0x5e0a, 0x1872,
+ 0x5e0b, 0x3d8a,
+ 0x5e0c, 0x048e,
+ 0x5e0e, 0x1873,
+ 0x5e11, 0x05b0,
+ 0x5e12, 0x3f2e,
+ 0x5e14, 0x1970,
+ 0x5e15, 0x05ae,
+ 0x5e16, 0x05ad,
+ 0x5e17, 0x196f,
+ 0x5e18, 0x05ab,
+ 0x5e19, 0x1971,
+ 0x5e1a, 0x05ac,
+ 0x5e1b, 0x05af,
+ 0x5e1d, 0x070e,
+ 0x5e1f, 0x0710,
+ 0x5e20, 0x1acd,
+ 0x5e21, 0x1aca,
+ 0x5e24, 0x1ace,
+ 0x5e25, 0x070f,
+ 0x5e28, 0x1c87,
+ 0x5e29, 0x1c86,
+ 0x5e2b, 0x08aa,
+ 0x5e2d, 0x08a9,
+ 0x5e2e, 0x4135,
+ 0x5e33, 0x0a6e,
+ 0x5e34, 0x1ecd,
+ 0x5e36, 0x0a6d,
+ 0x5e37, 0x0a6f,
+ 0x5e38, 0x0a6c,
+ 0x5e3d, 0x0c38,
+ 0x5e3e, 0x1ecc,
+ 0x5e40, 0x0c39,
+ 0x5e41, 0x212e,
+ 0x5e42, 0x43a0,
+ 0x5e43, 0x0c3a,
+ 0x5e44, 0x212d,
+ 0x5e45, 0x0c37,
+ 0x5e48, 0x3a2c,
+ 0x5e4a, 0x23c9,
+ 0x5e4b, 0x23cb,
+ 0x5e4c, 0x0dff,
+ 0x5e4d, 0x23ca,
+ 0x5e4e, 0x23c8,
+ 0x5e4f, 0x23c7,
+ 0x5e53, 0x2674,
+ 0x5e54, 0x0fc9,
+ 0x5e55, 0x0fc7,
+ 0x5e57, 0x0fc8,
+ 0x5e58, 0x2672,
+ 0x5e5b, 0x0fc5,
+ 0x5e5c, 0x28c7,
+ 0x5e5d, 0x28c5,
+ 0x5e5e, 0x3a2b,
+ 0x5e5f, 0x1139,
+ 0x5e60, 0x28c6,
+ 0x5e61, 0x113a,
+ 0x5e62, 0x1138,
+ 0x5e63, 0x0fc6,
+ 0x5e66, 0x2b38,
+ 0x5e67, 0x2b36,
+ 0x5e69, 0x28c4,
+ 0x5e6a, 0x2d5d,
+ 0x5e6b, 0x13cd,
+ 0x5e6c, 0x2d5c,
+ 0x5e6d, 0x2f1c,
+ 0x5e6f, 0x2b39,
+ 0x5e70, 0x308d,
+ 0x5e72, 0x028d,
+ 0x5e73, 0x033b,
+ 0x5e74, 0x03cb,
+ 0x5e75, 0x17e4,
+ 0x5e76, 0x03ca,
+ 0x5e78, 0x05b1,
+ 0x5e79, 0x0e00,
+ 0x5e7a, 0x0227,
+ 0x5e7b, 0x02cc,
+ 0x5e7c, 0x033c,
+ 0x5e7d, 0x0711,
+ 0x5e7e, 0x0c3b,
+ 0x5e7f, 0x0228,
+ 0x5e80, 0x17a5,
+ 0x5e82, 0x17a6,
+ 0x5e83, 0x4108,
+ 0x5e84, 0x17e5,
+ 0x5e86, 0x4552,
+ 0x5e87, 0x0490,
+ 0x5e88, 0x1877,
+ 0x5e89, 0x1875,
+ 0x5e8a, 0x0491,
+ 0x5e8b, 0x1874,
+ 0x5e8c, 0x1876,
+ 0x5e8d, 0x1878,
+ 0x5e8f, 0x048f,
+ 0x5e95, 0x05b5,
+ 0x5e97, 0x05b3,
+ 0x5e9a, 0x05b2,
+ 0x5e9b, 0x1ad2,
+ 0x5e9c, 0x05b4,
+ 0x5ea0, 0x0712,
+ 0x5ea2, 0x1ad1,
+ 0x5ea3, 0x1ad3,
+ 0x5ea4, 0x1ad0,
+ 0x5ea5, 0x1ad4,
+ 0x5ea6, 0x0713,
+ 0x5ea7, 0x08ad,
+ 0x5ea8, 0x1c88,
+ 0x5eaa, 0x1c8a,
+ 0x5eab, 0x08ab,
+ 0x5eac, 0x1c8b,
+ 0x5ead, 0x08ac,
+ 0x5eae, 0x1c89,
+ 0x5eb0, 0x1acf,
+ 0x5eb1, 0x1ece,
+ 0x5eb2, 0x1ed1,
+ 0x5eb4, 0x1ecf,
+ 0x5eb5, 0x0a73,
+ 0x5eb6, 0x0a72,
+ 0x5eb7, 0x0a70,
+ 0x5eb9, 0x1ed0,
+ 0x5ebd, 0x43bd,
+ 0x5ebe, 0x0a74,
+ 0x5ec1, 0x0c3d,
+ 0x5ec4, 0x0c3f,
+ 0x5ec5, 0x23cc,
+ 0x5ec6, 0x23ce,
+ 0x5ec7, 0x23d0,
+ 0x5ec8, 0x0e02,
+ 0x5ec9, 0x0e01,
+ 0x5eca, 0x0c3c,
+ 0x5ecb, 0x23cf,
+ 0x5ecc, 0x23cd,
+ 0x5ecd, 0x3a30,
+ 0x5ece, 0x2678,
+ 0x5ed0, 0x413d,
+ 0x5ed1, 0x2676,
+ 0x5ed2, 0x267c,
+ 0x5ed3, 0x0fca,
+ 0x5ed4, 0x267d,
+ 0x5ed5, 0x267a,
+ 0x5ed6, 0x0fcb,
+ 0x5ed7, 0x2677,
+ 0x5ed8, 0x2675,
+ 0x5ed9, 0x267b,
+ 0x5eda, 0x113c,
+ 0x5edb, 0x28c9,
+ 0x5edc, 0x2679,
+ 0x5edd, 0x113e,
+ 0x5ede, 0x28ca,
+ 0x5edf, 0x113d,
+ 0x5ee0, 0x1140,
+ 0x5ee1, 0x28cb,
+ 0x5ee2, 0x113b,
+ 0x5ee3, 0x113f,
+ 0x5ee5, 0x2b3e,
+ 0x5ee6, 0x2b3c,
+ 0x5ee7, 0x2b3b,
+ 0x5ee8, 0x2b3d,
+ 0x5ee9, 0x2b3a,
+ 0x5eec, 0x157d,
+ 0x5eee, 0x31cf,
+ 0x5ef1, 0x32d0,
+ 0x5ef2, 0x3380,
+ 0x5ef3, 0x1742,
+ 0x5ef4, 0x0229,
+ 0x5ef6, 0x05b7,
+ 0x5ef7, 0x0492,
+ 0x5ef8, 0x386f,
+ 0x5ef9, 0x4143,
+ 0x5efa, 0x0714,
+ 0x5efb, 0x4144,
+ 0x5efc, 0x4146,
+ 0x5efe, 0x028e,
+ 0x5eff, 0x02cd,
+ 0x5f01, 0x033d,
+ 0x5f02, 0x17e6,
+ 0x5f04, 0x0493,
+ 0x5f05, 0x1879,
+ 0x5f07, 0x1ad5,
+ 0x5f08, 0x0715,
+ 0x5f0a, 0x0fcc,
+ 0x5f0b, 0x028f,
+ 0x5f0c, 0x3a3e,
+ 0x5f0d, 0x4149,
+ 0x5f0e, 0x3a3f,
+ 0x5f0f, 0x03cc,
+ 0x5f12, 0x0e03,
+ 0x5f13, 0x0290,
+ 0x5f14, 0x02ce,
+ 0x5f17, 0x033f,
+ 0x5f18, 0x033e,
+ 0x5f1a, 0x17e7,
+ 0x5f1b, 0x03cd,
+ 0x5f1d, 0x187a,
+ 0x5f1f, 0x0494,
+ 0x5f22, 0x1973,
+ 0x5f25, 0x4630,
+ 0x5f26, 0x05b8,
+ 0x5f28, 0x1972,
+ 0x5f29, 0x05ba,
+ 0x5f2d, 0x0716,
+ 0x5f2e, 0x1ad6,
+ 0x5f30, 0x1c8d,
+ 0x5f31, 0x08ae,
+ 0x5f33, 0x1c8c,
+ 0x5f35, 0x0a75,
+ 0x5f36, 0x1ed3,
+ 0x5f37, 0x0a76,
+ 0x5f38, 0x1ed4,
+ 0x5f3a, 0x414e,
+ 0x5f3c, 0x0c40,
+ 0x5f40, 0x23d1,
+ 0x5f43, 0x267f,
+ 0x5f44, 0x267e,
+ 0x5f46, 0x0fcd,
+ 0x5f48, 0x1141,
+ 0x5f49, 0x28cc,
+ 0x5f4a, 0x12ad,
+ 0x5f4b, 0x2b3f,
+ 0x5f4c, 0x13ce,
+ 0x5f4d, 0x3ba5,
+ 0x5f4e, 0x16c3,
+ 0x5f4f, 0x3416,
+ 0x5f50, 0x022a,
+ 0x5f51, 0x44e9,
+ 0x5f54, 0x1976,
+ 0x5f56, 0x1ad7,
+ 0x5f57, 0x0a77,
+ 0x5f58, 0x212f,
+ 0x5f59, 0x0e04,
+ 0x5f5c, 0x3d5a,
+ 0x5f5d, 0x14cf,
+ 0x5f61, 0x022b,
+ 0x5f62, 0x0496,
+ 0x5f63, 0x4152,
+ 0x5f64, 0x0495,
+ 0x5f65, 0x0717,
+ 0x5f67, 0x1c8e,
+ 0x5f69, 0x0a79,
+ 0x5f6a, 0x0b89,
+ 0x5f6b, 0x0a7a,
+ 0x5f6c, 0x0a78,
+ 0x5f6d, 0x0c41,
+ 0x5f6f, 0x2680,
+ 0x5f70, 0x0fce,
+ 0x5f71, 0x1142,
+ 0x5f72, 0x4154,
+ 0x5f73, 0x1777,
+ 0x5f74, 0x17e8,
+ 0x5f76, 0x187c,
+ 0x5f77, 0x0497,
+ 0x5f78, 0x187b,
+ 0x5f79, 0x0498,
+ 0x5f7b, 0x4058,
+ 0x5f7c, 0x05be,
+ 0x5f7d, 0x1979,
+ 0x5f7e, 0x1978,
+ 0x5f7f, 0x05bd,
+ 0x5f80, 0x05bb,
+ 0x5f82, 0x1977,
+ 0x5f83, 0x4631,
+ 0x5f85, 0x0719,
+ 0x5f86, 0x1ad8,
+ 0x5f87, 0x071c,
+ 0x5f88, 0x0718,
+ 0x5f89, 0x071e,
+ 0x5f8a, 0x071a,
+ 0x5f8c, 0x071d,
+ 0x5f90, 0x08b1,
+ 0x5f91, 0x08b0,
+ 0x5f92, 0x08af,
+ 0x5f96, 0x1ed6,
+ 0x5f97, 0x0a7b,
+ 0x5f98, 0x0a7e,
+ 0x5f99, 0x0a7c,
+ 0x5f9b, 0x1ed5,
+ 0x5f9c, 0x0a81,
+ 0x5f9e, 0x0a7d,
+ 0x5f9f, 0x1ed7,
+ 0x5fa0, 0x0a80,
+ 0x5fa1, 0x0a7f,
+ 0x5fa4, 0x402c,
+ 0x5fa5, 0x2131,
+ 0x5fa6, 0x2130,
+ 0x5fa7, 0x4157,
+ 0x5fa8, 0x0c44,
+ 0x5fa9, 0x0c42,
+ 0x5fab, 0x2132,
+ 0x5fac, 0x0e05,
+ 0x5fad, 0x23d3,
+ 0x5fae, 0x0e06,
+ 0x5faf, 0x23d2,
+ 0x5fb1, 0x3d98,
+ 0x5fb2, 0x28cd,
+ 0x5fb5, 0x1144,
+ 0x5fb6, 0x2681,
+ 0x5fb7, 0x1143,
+ 0x5fb9, 0x0fcf,
+ 0x5fba, 0x3f9f,
+ 0x5fbb, 0x2b41,
+ 0x5fbc, 0x2b40,
+ 0x5fbd, 0x13cf,
+ 0x5fbe, 0x2d5e,
+ 0x5fbf, 0x308e,
+ 0x5fc0, 0x31d1,
+ 0x5fc3, 0x02d0,
+ 0x5fc4, 0x44ea,
+ 0x5fc5, 0x0340,
+ 0x5fc9, 0x17a7,
+ 0x5fcc, 0x049a,
+ 0x5fcd, 0x049c,
+ 0x5fcf, 0x17eb,
+ 0x5fd0, 0x187f,
+ 0x5fd1, 0x187e,
+ 0x5fd2, 0x187d,
+ 0x5fd4, 0x17ea,
+ 0x5fd5, 0x17e9,
+ 0x5fd6, 0x03cf,
+ 0x5fd7, 0x049b,
+ 0x5fd8, 0x0499,
+ 0x5fd9, 0x03ce,
+ 0x5fdb, 0x3a4a,
+ 0x5fdd, 0x05bf,
+ 0x5fde, 0x197a,
+ 0x5fdf, 0x41af,
+ 0x5fe0, 0x05c0,
+ 0x5fe1, 0x1884,
+ 0x5fe3, 0x1886,
+ 0x5fe4, 0x1885,
+ 0x5fe5, 0x197b,
+ 0x5fe8, 0x1881,
+ 0x5fea, 0x04a0,
+ 0x5feb, 0x049e,
+ 0x5fed, 0x1880,
+ 0x5fee, 0x1882,
+ 0x5fef, 0x1888,
+ 0x5ff1, 0x049d,
+ 0x5ff3, 0x1883,
+ 0x5ff4, 0x188c,
+ 0x5ff5, 0x05c2,
+ 0x5ff7, 0x1889,
+ 0x5ff8, 0x049f,
+ 0x5ffa, 0x1887,
+ 0x5ffb, 0x188a,
+ 0x5ffd, 0x05c1,
+ 0x5fff, 0x05c3,
+ 0x6000, 0x188b,
+ 0x6009, 0x198f,
+ 0x600a, 0x1982,
+ 0x600b, 0x1980,
+ 0x600c, 0x198e,
+ 0x600d, 0x1989,
+ 0x600e, 0x0723,
+ 0x600f, 0x05c4,
+ 0x6010, 0x198a,
+ 0x6011, 0x198d,
+ 0x6012, 0x071f,
+ 0x6013, 0x198c,
+ 0x6014, 0x05c5,
+ 0x6015, 0x05ca,
+ 0x6016, 0x05c8,
+ 0x6017, 0x1983,
+ 0x6019, 0x197e,
+ 0x601a, 0x1985,
+ 0x601b, 0x05cf,
+ 0x601c, 0x1990,
+ 0x601d, 0x0720,
+ 0x601e, 0x1986,
+ 0x6020, 0x0721,
+ 0x6021, 0x05cb,
+ 0x6022, 0x1988,
+ 0x6023, 0x4185,
+ 0x6024, 0x1ae7,
+ 0x6025, 0x0722,
+ 0x6026, 0x197d,
+ 0x6027, 0x05cc,
+ 0x6028, 0x0724,
+ 0x6029, 0x05cd,
+ 0x602a, 0x05c9,
+ 0x602b, 0x05ce,
+ 0x602c, 0x1987,
+ 0x602d, 0x197c,
+ 0x602e, 0x198b,
+ 0x602f, 0x05c6,
+ 0x6031, 0x4161,
+ 0x6032, 0x197f,
+ 0x6033, 0x1984,
+ 0x6034, 0x1981,
+ 0x6035, 0x05c7,
+ 0x6037, 0x1ad9,
+ 0x6039, 0x1ada,
+ 0x603b, 0x4553,
+ 0x6040, 0x1ae4,
+ 0x6041, 0x1c92,
+ 0x6042, 0x1ae5,
+ 0x6043, 0x072a,
+ 0x6044, 0x1ae8,
+ 0x6045, 0x1ade,
+ 0x6046, 0x0729,
+ 0x6047, 0x1ae0,
+ 0x6049, 0x1ae1,
+ 0x604a, 0x4074,
+ 0x604c, 0x1ae3,
+ 0x604d, 0x0725,
+ 0x6050, 0x08b5,
+ 0x6052, 0x36ec,
+ 0x6053, 0x1adf,
+ 0x6054, 0x1adb,
+ 0x6055, 0x08b6,
+ 0x6058, 0x1ae9,
+ 0x6059, 0x08b2,
+ 0x605a, 0x1c90,
+ 0x605b, 0x1ae2,
+ 0x605d, 0x1c8f,
+ 0x605e, 0x1add,
+ 0x605f, 0x1ae6,
+ 0x6062, 0x0728,
+ 0x6063, 0x08b3,
+ 0x6064, 0x072e,
+ 0x6065, 0x08b4,
+ 0x6066, 0x1aea,
+ 0x6067, 0x1c91,
+ 0x6068, 0x0727,
+ 0x6069, 0x08b8,
+ 0x606a, 0x072d,
+ 0x606b, 0x072c,
+ 0x606c, 0x072b,
+ 0x606d, 0x08b7,
+ 0x606e, 0x1aeb,
+ 0x606f, 0x08b9,
+ 0x6070, 0x0726,
+ 0x6072, 0x1adc,
+ 0x6075, 0x3a56,
+ 0x6077, 0x4005,
+ 0x607e, 0x3a47,
+ 0x607f, 0x0a82,
+ 0x6080, 0x1c95,
+ 0x6081, 0x1c97,
+ 0x6083, 0x1c99,
+ 0x6084, 0x08ba,
+ 0x6085, 0x08c0,
+ 0x6086, 0x1eda,
+ 0x6087, 0x1c9d,
+ 0x6088, 0x1c94,
+ 0x6089, 0x0a84,
+ 0x608a, 0x1ed8,
+ 0x608c, 0x08bf,
+ 0x608d, 0x08bd,
+ 0x608e, 0x1c9f,
+ 0x6090, 0x1ed9,
+ 0x6092, 0x1c96,
+ 0x6094, 0x08be,
+ 0x6095, 0x1c9a,
+ 0x6096, 0x08c1,
+ 0x6097, 0x1c9c,
+ 0x609a, 0x08bc,
+ 0x609b, 0x1c9b,
+ 0x609c, 0x1c9e,
+ 0x609d, 0x1c98,
+ 0x609e, 0x416a,
+ 0x609f, 0x08bb,
+ 0x60a0, 0x0a85,
+ 0x60a2, 0x1c93,
+ 0x60a3, 0x0a83,
+ 0x60a4, 0x4001,
+ 0x60a7, 0x3adc,
+ 0x60a8, 0x0a86,
+ 0x60b0, 0x1edc,
+ 0x60b1, 0x1ee5,
+ 0x60b2, 0x0c47,
+ 0x60b3, 0x416c,
+ 0x60b4, 0x0a88,
+ 0x60b5, 0x0a8d,
+ 0x60b6, 0x0c48,
+ 0x60b7, 0x1ee7,
+ 0x60b8, 0x0a94,
+ 0x60b9, 0x2134,
+ 0x60ba, 0x1edd,
+ 0x60bb, 0x0a8c,
+ 0x60bc, 0x0a8f,
+ 0x60bd, 0x0a8a,
+ 0x60be, 0x1edb,
+ 0x60bf, 0x1ee9,
+ 0x60c0, 0x1eec,
+ 0x60c1, 0x2143,
+ 0x60c3, 0x1eea,
+ 0x60c4, 0x2138,
+ 0x60c5, 0x0a8b,
+ 0x60c6, 0x0a92,
+ 0x60c7, 0x0a96,
+ 0x60c8, 0x1ee4,
+ 0x60c9, 0x2133,
+ 0x60ca, 0x1ee8,
+ 0x60cb, 0x0a87,
+ 0x60cc, 0x2135,
+ 0x60cd, 0x1eeb,
+ 0x60ce, 0x2137,
+ 0x60cf, 0x1ee0,
+ 0x60d1, 0x0c45,
+ 0x60d3, 0x1ede,
+ 0x60d5, 0x0a91,
+ 0x60d7, 0x4635,
+ 0x60d8, 0x0a90,
+ 0x60d9, 0x1ee2,
+ 0x60da, 0x0a95,
+ 0x60db, 0x1ee6,
+ 0x60dc, 0x0a8e,
+ 0x60dd, 0x1ee3,
+ 0x60de, 0x3dcc,
+ 0x60df, 0x0a93,
+ 0x60e0, 0x0c49,
+ 0x60e1, 0x0c46,
+ 0x60e2, 0x2136,
+ 0x60e3, 0x3d75,
+ 0x60e4, 0x1ee1,
+ 0x60e6, 0x0a89,
+ 0x60e7, 0x3d84,
+ 0x60e8, 0x3d7b,
+ 0x60e9, 0x4009,
+ 0x60f0, 0x0c4e,
+ 0x60f1, 0x0c52,
+ 0x60f2, 0x213a,
+ 0x60f3, 0x0e0b,
+ 0x60f4, 0x0c50,
+ 0x60f5, 0x213e,
+ 0x60f6, 0x0c54,
+ 0x60f7, 0x23d4,
+ 0x60f8, 0x2140,
+ 0x60f9, 0x0e0d,
+ 0x60fa, 0x0c4c,
+ 0x60fb, 0x0c4f,
+ 0x60fc, 0x2141,
+ 0x60fd, 0x3fa8,
+ 0x60fe, 0x2142,
+ 0x60ff, 0x2148,
+ 0x6100, 0x0c56,
+ 0x6101, 0x0e0e,
+ 0x6103, 0x2144,
+ 0x6104, 0x2149,
+ 0x6105, 0x213d,
+ 0x6106, 0x0e18,
+ 0x6107, 0x3c35,
+ 0x6108, 0x0e0f,
+ 0x6109, 0x0c55,
+ 0x610a, 0x213b,
+ 0x610b, 0x214a,
+ 0x610c, 0x3c87,
+ 0x610d, 0x0e17,
+ 0x610e, 0x0c53,
+ 0x610f, 0x0e08,
+ 0x6110, 0x2147,
+ 0x6112, 0x0c57,
+ 0x6113, 0x213f,
+ 0x6114, 0x2139,
+ 0x6115, 0x0c4d,
+ 0x6116, 0x213c,
+ 0x6118, 0x2145,
+ 0x6119, 0x3ef6,
+ 0x611a, 0x0e07,
+ 0x611b, 0x0e0c,
+ 0x611c, 0x0c4a,
+ 0x611d, 0x2146,
+ 0x611f, 0x0e0a,
+ 0x6123, 0x0c4b,
+ 0x6127, 0x0e16,
+ 0x6128, 0x2683,
+ 0x6129, 0x23df,
+ 0x612b, 0x23d7,
+ 0x612c, 0x2682,
+ 0x612e, 0x23db,
+ 0x612f, 0x23dd,
+ 0x6130, 0x3f37,
+ 0x6132, 0x23da,
+ 0x6134, 0x0e15,
+ 0x6136, 0x23d9,
+ 0x6137, 0x0e19,
+ 0x613b, 0x2692,
+ 0x613d, 0x4636,
+ 0x613e, 0x0e14,
+ 0x613f, 0x0fd1,
+ 0x6140, 0x23e0,
+ 0x6141, 0x2684,
+ 0x6142, 0x4174,
+ 0x6144, 0x0e12,
+ 0x6145, 0x23d8,
+ 0x6146, 0x23dc,
+ 0x6147, 0x0fd0,
+ 0x6148, 0x0e09,
+ 0x6149, 0x23d5,
+ 0x614b, 0x0fd2,
+ 0x614c, 0x0e11,
+ 0x614d, 0x0e13,
+ 0x614e, 0x0e10,
+ 0x614f, 0x23de,
+ 0x6150, 0x3c32,
+ 0x6152, 0x2688,
+ 0x6154, 0x268e,
+ 0x6155, 0x1149,
+ 0x6156, 0x2695,
+ 0x6158, 0x0fd8,
+ 0x6159, 0x3fba,
+ 0x615a, 0x0fd7,
+ 0x615b, 0x2690,
+ 0x615c, 0x4186,
+ 0x615d, 0x1148,
+ 0x615e, 0x2685,
+ 0x615f, 0x0fd6,
+ 0x6160, 0x494c,
+ 0x6161, 0x2694,
+ 0x6162, 0x0fd4,
+ 0x6164, 0x4173,
+ 0x6165, 0x2691,
+ 0x6166, 0x28de,
+ 0x6167, 0x1146,
+ 0x6168, 0x0c51,
+ 0x616a, 0x2693,
+ 0x616b, 0x114d,
+ 0x616c, 0x268b,
+ 0x616e, 0x1147,
+ 0x616f, 0x3fc0,
+ 0x6170, 0x114c,
+ 0x6171, 0x2686,
+ 0x6172, 0x268a,
+ 0x6173, 0x2687,
+ 0x6174, 0x268d,
+ 0x6175, 0x0fd9,
+ 0x6176, 0x1145,
+ 0x6177, 0x0fd3,
+ 0x6179, 0x28d0,
+ 0x617a, 0x268f,
+ 0x617c, 0x114b,
+ 0x617d, 0x3fbd,
+ 0x617e, 0x114e,
+ 0x6180, 0x268c,
+ 0x6181, 0x4177,
+ 0x6182, 0x114a,
+ 0x6183, 0x28cf,
+ 0x6187, 0x417a,
+ 0x6189, 0x28d4,
+ 0x618a, 0x12b1,
+ 0x618b, 0x28ce,
+ 0x618c, 0x2b4d,
+ 0x618d, 0x28dd,
+ 0x618e, 0x1152,
+ 0x6190, 0x1150,
+ 0x6191, 0x12af,
+ 0x6192, 0x28da,
+ 0x6193, 0x28d6,
+ 0x6194, 0x1156,
+ 0x6195, 0x3de0,
+ 0x6196, 0x2b44,
+ 0x6198, 0x3a55,
+ 0x6199, 0x3a54,
+ 0x619a, 0x1154,
+ 0x619b, 0x28d5,
+ 0x619c, 0x4002,
+ 0x619d, 0x2b42,
+ 0x619f, 0x28d9,
+ 0x61a1, 0x28dc,
+ 0x61a2, 0x28d3,
+ 0x61a4, 0x1155,
+ 0x61a7, 0x114f,
+ 0x61a8, 0x2b43,
+ 0x61a9, 0x12b0,
+ 0x61aa, 0x28db,
+ 0x61ab, 0x1151,
+ 0x61ac, 0x1153,
+ 0x61ad, 0x28d8,
+ 0x61ae, 0x1157,
+ 0x61af, 0x28d7,
+ 0x61b0, 0x28d2,
+ 0x61b1, 0x28d1,
+ 0x61b2, 0x12ae,
+ 0x61b3, 0x28df,
+ 0x61b4, 0x2b46,
+ 0x61b5, 0x2d60,
+ 0x61b6, 0x12b3,
+ 0x61b7, 0x4639,
+ 0x61b8, 0x2b4c,
+ 0x61b9, 0x43bf,
+ 0x61ba, 0x2b4a,
+ 0x61bc, 0x2d61,
+ 0x61be, 0x12b4,
+ 0x61bf, 0x2b4b,
+ 0x61c0, 0x3a50,
+ 0x61c1, 0x2b48,
+ 0x61c2, 0x13d1,
+ 0x61c3, 0x2d5f,
+ 0x61c5, 0x2b45,
+ 0x61c6, 0x2b47,
+ 0x61c7, 0x13d2,
+ 0x61c8, 0x12b6,
+ 0x61c9, 0x13d0,
+ 0x61ca, 0x12b5,
+ 0x61cb, 0x13d4,
+ 0x61cc, 0x2b49,
+ 0x61cd, 0x12b2,
+ 0x61cf, 0x463a,
+ 0x61d0, 0x4181,
+ 0x61d3, 0x417e,
+ 0x61d6, 0x2f26,
+ 0x61d8, 0x2f1e,
+ 0x61da, 0x38b1,
+ 0x61de, 0x2d67,
+ 0x61df, 0x2f1f,
+ 0x61e0, 0x2d63,
+ 0x61e2, 0x3fc5,
+ 0x61e3, 0x14d0,
+ 0x61e4, 0x2d65,
+ 0x61e5, 0x2d64,
+ 0x61e6, 0x13d3,
+ 0x61e7, 0x2d62,
+ 0x61e8, 0x2d66,
+ 0x61e9, 0x2f27,
+ 0x61ea, 0x2f23,
+ 0x61eb, 0x2f25,
+ 0x61ed, 0x2f20,
+ 0x61f0, 0x2f24,
+ 0x61f1, 0x2f22,
+ 0x61f2, 0x157e,
+ 0x61f5, 0x1581,
+ 0x61f6, 0x1580,
+ 0x61f7, 0x157f,
+ 0x61f8, 0x1614,
+ 0x61f9, 0x31d3,
+ 0x61fa, 0x1615,
+ 0x61fb, 0x308f,
+ 0x61fc, 0x1670,
+ 0x61fd, 0x32d1,
+ 0x61fe, 0x1671,
+ 0x61ff, 0x16c4,
+ 0x6200, 0x16f8,
+ 0x6201, 0x3417,
+ 0x6203, 0x3418,
+ 0x6207, 0x3533,
+ 0x6208, 0x02d1,
+ 0x6209, 0x17a8,
+ 0x620a, 0x0341,
+ 0x620c, 0x03d1,
+ 0x620e, 0x03d0,
+ 0x6210, 0x03d3,
+ 0x6211, 0x04a2,
+ 0x6212, 0x04a1,
+ 0x6214, 0x1991,
+ 0x6215, 0x05d1,
+ 0x6216, 0x05d0,
+ 0x6219, 0x1ca0,
+ 0x621a, 0x0a97,
+ 0x621f, 0x0c58,
+ 0x6220, 0x23e1,
+ 0x6221, 0x0e1a,
+ 0x6223, 0x23e3,
+ 0x6224, 0x23e5,
+ 0x6225, 0x23e4,
+ 0x6227, 0x2697,
+ 0x6229, 0x2696,
+ 0x622a, 0x0fda,
+ 0x622b, 0x2698,
+ 0x622c, 0x463c,
+ 0x622d, 0x28e0,
+ 0x622e, 0x1158,
+ 0x6230, 0x12b7,
+ 0x6232, 0x13d5,
+ 0x6233, 0x14d1,
+ 0x6234, 0x13d6,
+ 0x6236, 0x02d2,
+ 0x6237, 0x451a,
+ 0x6239, 0x3fc2,
+ 0x623a, 0x188d,
+ 0x623d, 0x1992,
+ 0x623e, 0x05d3,
+ 0x623f, 0x05d2,
+ 0x6240, 0x05d4,
+ 0x6241, 0x072f,
+ 0x6242, 0x1aec,
+ 0x6246, 0x1ca1,
+ 0x6247, 0x08c2,
+ 0x6248, 0x0a99,
+ 0x6249, 0x0c59,
+ 0x624a, 0x214b,
+ 0x624b, 0x02d3,
+ 0x624c, 0x44ec,
+ 0x624d, 0x0291,
+ 0x624e, 0x02d4,
+ 0x6250, 0x17a9,
+ 0x6251, 0x0345,
+ 0x6252, 0x0344,
+ 0x6253, 0x0342,
+ 0x6258, 0x03d6,
+ 0x6259, 0x17f2,
+ 0x625a, 0x17f4,
+ 0x625b, 0x03d5,
+ 0x625c, 0x17ec,
+ 0x625e, 0x17ed,
+ 0x6260, 0x17f3,
+ 0x6261, 0x17ef,
+ 0x6262, 0x17f1,
+ 0x6263, 0x03d4,
+ 0x6264, 0x17ee,
+ 0x6265, 0x17f5,
+ 0x6266, 0x17f0,
+ 0x6268, 0x3f15,
+ 0x626d, 0x04a9,
+ 0x626e, 0x04b2,
+ 0x626f, 0x04b0,
+ 0x6270, 0x1897,
+ 0x6271, 0x1894,
+ 0x6272, 0x189c,
+ 0x6273, 0x04ae,
+ 0x6274, 0x189d,
+ 0x6276, 0x04a7,
+ 0x6277, 0x189a,
+ 0x6279, 0x04ad,
+ 0x627a, 0x1896,
+ 0x627b, 0x1895,
+ 0x627c, 0x04ab,
+ 0x627d, 0x189b,
+ 0x627e, 0x04ac,
+ 0x627f, 0x05d5,
+ 0x6280, 0x04a6,
+ 0x6281, 0x1898,
+ 0x6282, 0x3f86,
+ 0x6283, 0x188e,
+ 0x6284, 0x04a3,
+ 0x6285, 0x3f50,
+ 0x6286, 0x04b6,
+ 0x6287, 0x1893,
+ 0x6288, 0x1899,
+ 0x6289, 0x04a8,
+ 0x628a, 0x04aa,
+ 0x628c, 0x188f,
+ 0x628e, 0x1890,
+ 0x6290, 0x43c0,
+ 0x6291, 0x04b5,
+ 0x6292, 0x04af,
+ 0x6293, 0x04b4,
+ 0x6294, 0x1892,
+ 0x6295, 0x04b3,
+ 0x6296, 0x04a5,
+ 0x6297, 0x04a4,
+ 0x6298, 0x04b1,
+ 0x629d, 0x3e96,
+ 0x62a4, 0x3a69,
+ 0x62a6, 0x3fc1,
+ 0x62a8, 0x05e3,
+ 0x62a9, 0x199e,
+ 0x62aa, 0x1997,
+ 0x62ab, 0x05de,
+ 0x62ac, 0x05f1,
+ 0x62ad, 0x1993,
+ 0x62ae, 0x199a,
+ 0x62af, 0x199c,
+ 0x62b0, 0x199f,
+ 0x62b1, 0x05ec,
+ 0x62b3, 0x199b,
+ 0x62b4, 0x1994,
+ 0x62b5, 0x05ea,
+ 0x62b6, 0x1998,
+ 0x62b8, 0x19a0,
+ 0x62b9, 0x05db,
+ 0x62bb, 0x199d,
+ 0x62bc, 0x05e5,
+ 0x62bd, 0x05e4,
+ 0x62be, 0x1996,
+ 0x62bf, 0x05d9,
+ 0x62c2, 0x05da,
+ 0x62c3, 0x3d8f,
+ 0x62c4, 0x05d8,
+ 0x62c5, 0x418a,
+ 0x62c6, 0x05f0,
+ 0x62c7, 0x05e8,
+ 0x62c8, 0x05e2,
+ 0x62c9, 0x05d6,
+ 0x62ca, 0x1999,
+ 0x62cb, 0x05e1,
+ 0x62cc, 0x05d7,
+ 0x62cd, 0x05e9,
+ 0x62ce, 0x05f2,
+ 0x62cf, 0x1aee,
+ 0x62d0, 0x05e6,
+ 0x62d1, 0x1995,
+ 0x62d2, 0x05dc,
+ 0x62d3, 0x05df,
+ 0x62d5, 0x418c,
+ 0x62d6, 0x05ee,
+ 0x62d8, 0x05ed,
+ 0x62d9, 0x05e7,
+ 0x62da, 0x05eb,
+ 0x62db, 0x05dd,
+ 0x62dc, 0x0730,
+ 0x62df, 0x401c,
+ 0x62e5, 0x463d,
+ 0x62eb, 0x1af4,
+ 0x62ec, 0x073c,
+ 0x62ed, 0x0734,
+ 0x62ee, 0x0736,
+ 0x62ef, 0x073b,
+ 0x62f0, 0x1b00,
+ 0x62f1, 0x0739,
+ 0x62f2, 0x1ca2,
+ 0x62f3, 0x08c3,
+ 0x62f4, 0x073e,
+ 0x62f5, 0x1af1,
+ 0x62f6, 0x1af9,
+ 0x62f7, 0x073a,
+ 0x62f8, 0x1af8,
+ 0x62f9, 0x1af5,
+ 0x62fa, 0x1afd,
+ 0x62fb, 0x1aff,
+ 0x62fc, 0x0733,
+ 0x62fd, 0x0737,
+ 0x62fe, 0x073d,
+ 0x62ff, 0x08c5,
+ 0x6300, 0x1afa,
+ 0x6301, 0x0735,
+ 0x6302, 0x0740,
+ 0x6303, 0x1af3,
+ 0x6307, 0x0738,
+ 0x6308, 0x08c4,
+ 0x6309, 0x0732,
+ 0x630b, 0x1af0,
+ 0x630c, 0x1af7,
+ 0x630d, 0x1aef,
+ 0x630e, 0x1af2,
+ 0x630f, 0x1af6,
+ 0x6310, 0x1ca3,
+ 0x6311, 0x073f,
+ 0x6313, 0x1afb,
+ 0x6315, 0x1afe,
+ 0x6316, 0x0731,
+ 0x6318, 0x43c1,
+ 0x6328, 0x08d3,
+ 0x6329, 0x1caf,
+ 0x632a, 0x08d1,
+ 0x632c, 0x1ca5,
+ 0x632d, 0x1cb5,
+ 0x632e, 0x3edd,
+ 0x632f, 0x08c8,
+ 0x6331, 0x3a65,
+ 0x6332, 0x1eed,
+ 0x6333, 0x1cb7,
+ 0x6334, 0x1cb1,
+ 0x6335, 0x3f16,
+ 0x6336, 0x1ca8,
+ 0x6337, 0x3a63,
+ 0x6338, 0x1cba,
+ 0x6339, 0x1cab,
+ 0x633a, 0x08ce,
+ 0x633b, 0x1f04,
+ 0x633c, 0x1cae,
+ 0x633d, 0x08d0,
+ 0x633e, 0x08c7,
+ 0x6340, 0x1cbc,
+ 0x6341, 0x1cb0,
+ 0x6342, 0x08ca,
+ 0x6343, 0x1ca9,
+ 0x6344, 0x1ca6,
+ 0x6346, 0x08cb,
+ 0x6347, 0x1cb6,
+ 0x6348, 0x1cbd,
+ 0x6349, 0x08cd,
+ 0x634a, 0x1cad,
+ 0x634b, 0x1cac,
+ 0x634c, 0x08d5,
+ 0x634d, 0x08d4,
+ 0x634e, 0x08c6,
+ 0x634f, 0x08cc,
+ 0x6350, 0x08cf,
+ 0x6351, 0x1cb9,
+ 0x6354, 0x1cb3,
+ 0x6355, 0x08c9,
+ 0x6356, 0x1ca4,
+ 0x6357, 0x1cbb,
+ 0x6358, 0x1cb2,
+ 0x6359, 0x1cb4,
+ 0x635a, 0x1cb8,
+ 0x6364, 0x3fc7,
+ 0x6365, 0x1eee,
+ 0x6367, 0x0aa1,
+ 0x6368, 0x0ab5,
+ 0x6369, 0x0ab4,
+ 0x636b, 0x0aa9,
+ 0x636c, 0x418e,
+ 0x636d, 0x1f00,
+ 0x636e, 0x1efc,
+ 0x636f, 0x1ef9,
+ 0x6370, 0x1f0b,
+ 0x6371, 0x0aa4,
+ 0x6372, 0x0a9c,
+ 0x6375, 0x1efe,
+ 0x6376, 0x0c69,
+ 0x6377, 0x0aa0,
+ 0x6378, 0x1f06,
+ 0x6379, 0x4367,
+ 0x637a, 0x0ab6,
+ 0x637b, 0x0ab3,
+ 0x637c, 0x1f02,
+ 0x637d, 0x1ef1,
+ 0x637f, 0x3f4b,
+ 0x6380, 0x0ab2,
+ 0x6381, 0x1f08,
+ 0x6382, 0x1ef0,
+ 0x6383, 0x0aa7,
+ 0x6384, 0x0aab,
+ 0x6385, 0x1f07,
+ 0x6387, 0x1efa,
+ 0x6388, 0x0aac,
+ 0x6389, 0x0aa6,
+ 0x638a, 0x1eef,
+ 0x638b, 0x4188,
+ 0x638c, 0x0c5b,
+ 0x638d, 0x1f0a,
+ 0x638e, 0x1ef8,
+ 0x638f, 0x0ab1,
+ 0x6390, 0x1efb,
+ 0x6391, 0x1f09,
+ 0x6392, 0x0ab0,
+ 0x6394, 0x214c,
+ 0x6396, 0x0a9d,
+ 0x6397, 0x1ef6,
+ 0x6398, 0x0aa2,
+ 0x6399, 0x0aad,
+ 0x639b, 0x0aa8,
+ 0x639c, 0x1eff,
+ 0x639d, 0x1ef5,
+ 0x639e, 0x1ef3,
+ 0x639f, 0x1f05,
+ 0x63a0, 0x0a9a,
+ 0x63a1, 0x0aae,
+ 0x63a2, 0x0a9e,
+ 0x63a3, 0x0c5a,
+ 0x63a4, 0x1f03,
+ 0x63a5, 0x0a9f,
+ 0x63a7, 0x0a9b,
+ 0x63a8, 0x0aaa,
+ 0x63a9, 0x0aa5,
+ 0x63aa, 0x0aa3,
+ 0x63ab, 0x1ef7,
+ 0x63ac, 0x0aaf,
+ 0x63ad, 0x1ef4,
+ 0x63ae, 0x1f01,
+ 0x63af, 0x1efd,
+ 0x63b0, 0x214e,
+ 0x63b1, 0x214d,
+ 0x63b9, 0x3e9d,
+ 0x63bd, 0x1ef2,
+ 0x63be, 0x215e,
+ 0x63c0, 0x0c5d,
+ 0x63c1, 0x46a8,
+ 0x63c2, 0x2164,
+ 0x63c3, 0x2153,
+ 0x63c4, 0x2161,
+ 0x63c5, 0x23e6,
+ 0x63c6, 0x0c60,
+ 0x63c7, 0x2165,
+ 0x63c8, 0x2168,
+ 0x63c9, 0x0c5f,
+ 0x63ca, 0x2156,
+ 0x63cb, 0x2167,
+ 0x63cc, 0x2166,
+ 0x63cd, 0x0c61,
+ 0x63ce, 0x214f,
+ 0x63cf, 0x0c5c,
+ 0x63d0, 0x0c64,
+ 0x63d1, 0x3a66,
+ 0x63d2, 0x0c62,
+ 0x63d3, 0x2163,
+ 0x63d5, 0x2159,
+ 0x63d6, 0x0c66,
+ 0x63d7, 0x216a,
+ 0x63d8, 0x2162,
+ 0x63d9, 0x216b,
+ 0x63da, 0x0c6e,
+ 0x63db, 0x0c6c,
+ 0x63dc, 0x2160,
+ 0x63dd, 0x215f,
+ 0x63de, 0x3e60,
+ 0x63df, 0x215d,
+ 0x63e0, 0x2157,
+ 0x63e1, 0x0c65,
+ 0x63e2, 0x4641,
+ 0x63e3, 0x0c63,
+ 0x63e4, 0x1caa,
+ 0x63e5, 0x2150,
+ 0x63e6, 0x489f,
+ 0x63e7, 0x2404,
+ 0x63e8, 0x2151,
+ 0x63e9, 0x0c5e,
+ 0x63ea, 0x0c6b,
+ 0x63eb, 0x23e8,
+ 0x63ed, 0x0c67,
+ 0x63ef, 0x2152,
+ 0x63f0, 0x2169,
+ 0x63f1, 0x23e7,
+ 0x63f2, 0x215a,
+ 0x63f3, 0x2155,
+ 0x63f4, 0x0c6a,
+ 0x63f5, 0x215b,
+ 0x63f6, 0x2158,
+ 0x63f8, 0x4192,
+ 0x63f9, 0x0c6f,
+ 0x63fb, 0x4642,
+ 0x63fc, 0x3e9c,
+ 0x63fe, 0x3e9e,
+ 0x6406, 0x0e2a,
+ 0x6407, 0x4643,
+ 0x6409, 0x23eb,
+ 0x640a, 0x23fe,
+ 0x640b, 0x2403,
+ 0x640c, 0x23f7,
+ 0x640d, 0x0e26,
+ 0x640e, 0x2408,
+ 0x640f, 0x0e23,
+ 0x6410, 0x23e9,
+ 0x6412, 0x23ea,
+ 0x6413, 0x0e1c,
+ 0x6414, 0x0e25,
+ 0x6415, 0x23f1,
+ 0x6416, 0x0e28,
+ 0x6418, 0x23f2,
+ 0x641a, 0x23ff,
+ 0x641b, 0x2405,
+ 0x641c, 0x0e24,
+ 0x641e, 0x0e1e,
+ 0x641f, 0x23f0,
+ 0x6420, 0x23ec,
+ 0x6421, 0x2407,
+ 0x6422, 0x23f5,
+ 0x6424, 0x23ed,
+ 0x6425, 0x2401,
+ 0x6426, 0x23f8,
+ 0x6427, 0x2402,
+ 0x6428, 0x23fa,
+ 0x642a, 0x0e1f,
+ 0x642b, 0x2699,
+ 0x642c, 0x0e22,
+ 0x642d, 0x0e20,
+ 0x642e, 0x2406,
+ 0x642f, 0x23fd,
+ 0x6430, 0x23f9,
+ 0x6432, 0x45d9,
+ 0x6433, 0x23ee,
+ 0x6434, 0x0fe4,
+ 0x6435, 0x23fc,
+ 0x6436, 0x0e27,
+ 0x6437, 0x23f4,
+ 0x6438, 0x4191,
+ 0x6439, 0x23f3,
+ 0x643a, 0x419d,
+ 0x643b, 0x3a6b,
+ 0x643d, 0x0e21,
+ 0x643e, 0x0e1d,
+ 0x643f, 0x26ae,
+ 0x6440, 0x2400,
+ 0x6441, 0x23fb,
+ 0x6443, 0x23ef,
+ 0x644b, 0x26a9,
+ 0x644d, 0x269a,
+ 0x644e, 0x26a5,
+ 0x6450, 0x26ac,
+ 0x6451, 0x0fe2,
+ 0x6452, 0x0c6d,
+ 0x6453, 0x26aa,
+ 0x6454, 0x0fdd,
+ 0x6458, 0x0fdc,
+ 0x6459, 0x26b1,
+ 0x645a, 0x43c2,
+ 0x645b, 0x269b,
+ 0x645c, 0x26a8,
+ 0x645d, 0x269c,
+ 0x645e, 0x26a7,
+ 0x645f, 0x0fe0,
+ 0x6460, 0x26ab,
+ 0x6461, 0x215c,
+ 0x6465, 0x26b2,
+ 0x6466, 0x26a3,
+ 0x6467, 0x0fe3,
+ 0x6468, 0x28ee,
+ 0x6469, 0x1159,
+ 0x646b, 0x26b0,
+ 0x646c, 0x26af,
+ 0x646d, 0x0fe5,
+ 0x646e, 0x28e1,
+ 0x646f, 0x115a,
+ 0x6470, 0x28e2,
+ 0x6471, 0x3a5b,
+ 0x6472, 0x269f,
+ 0x6474, 0x269d,
+ 0x6475, 0x26a2,
+ 0x6476, 0x269e,
+ 0x6477, 0x26b3,
+ 0x6478, 0x0fdf,
+ 0x6479, 0x115b,
+ 0x647a, 0x0fe1,
+ 0x647b, 0x0fe6,
+ 0x647c, 0x436c,
+ 0x647d, 0x26a1,
+ 0x647f, 0x26ad,
+ 0x6482, 0x26a6,
+ 0x6485, 0x28e5,
+ 0x6487, 0x0fdb,
+ 0x6488, 0x115e,
+ 0x6489, 0x2b54,
+ 0x648a, 0x28ea,
+ 0x648b, 0x28e9,
+ 0x648c, 0x28eb,
+ 0x648d, 0x4323,
+ 0x648f, 0x28e8,
+ 0x6490, 0x115f,
+ 0x6491, 0x43c3,
+ 0x6492, 0x1165,
+ 0x6493, 0x1162,
+ 0x6495, 0x1163,
+ 0x6496, 0x28e3,
+ 0x6497, 0x28e6,
+ 0x6498, 0x28f0,
+ 0x6499, 0x116b,
+ 0x649a, 0x1169,
+ 0x649c, 0x28e7,
+ 0x649d, 0x2154,
+ 0x649e, 0x115c,
+ 0x649f, 0x28ed,
+ 0x64a0, 0x28e4,
+ 0x64a2, 0x116c,
+ 0x64a3, 0x28ec,
+ 0x64a4, 0x0fde,
+ 0x64a5, 0x1161,
+ 0x64a6, 0x26a4,
+ 0x64a9, 0x1164,
+ 0x64ab, 0x1168,
+ 0x64ac, 0x116a,
+ 0x64ad, 0x1167,
+ 0x64ae, 0x1166,
+ 0x64af, 0x42e1,
+ 0x64b0, 0x1160,
+ 0x64b1, 0x28ef,
+ 0x64b2, 0x115d,
+ 0x64b3, 0x116d,
+ 0x64b4, 0x4340,
+ 0x64b6, 0x3a64,
+ 0x64bb, 0x12bb,
+ 0x64bd, 0x2b53,
+ 0x64be, 0x12c5,
+ 0x64bf, 0x12c2,
+ 0x64c0, 0x4645,
+ 0x64c1, 0x12b9,
+ 0x64c2, 0x12c0,
+ 0x64c3, 0x2b55,
+ 0x64c4, 0x12be,
+ 0x64c5, 0x12b8,
+ 0x64c7, 0x12bf,
+ 0x64c9, 0x2b52,
+ 0x64ca, 0x13d8,
+ 0x64cb, 0x12ba,
+ 0x64cd, 0x12c1,
+ 0x64ce, 0x13d7,
+ 0x64cf, 0x2b51,
+ 0x64d0, 0x2b50,
+ 0x64d2, 0x12c3,
+ 0x64d3, 0x3f03,
+ 0x64d4, 0x12c4,
+ 0x64d6, 0x2b4f,
+ 0x64d7, 0x2b4e,
+ 0x64d8, 0x13d9,
+ 0x64d9, 0x2b58,
+ 0x64da, 0x12bd,
+ 0x64db, 0x2b56,
+ 0x64dd, 0x431e,
+ 0x64e0, 0x13da,
+ 0x64e1, 0x4199,
+ 0x64e2, 0x13df,
+ 0x64e3, 0x2d6a,
+ 0x64e4, 0x2d6c,
+ 0x64e5, 0x419a,
+ 0x64e6, 0x13dc,
+ 0x64e7, 0x37a8,
+ 0x64e8, 0x2d6d,
+ 0x64e9, 0x2d69,
+ 0x64ea, 0x434a,
+ 0x64eb, 0x2d6b,
+ 0x64ec, 0x13dd,
+ 0x64ed, 0x13e0,
+ 0x64ef, 0x2d68,
+ 0x64f0, 0x13db,
+ 0x64f1, 0x13de,
+ 0x64f2, 0x14d3,
+ 0x64f3, 0x2b57,
+ 0x64f4, 0x14d2,
+ 0x64f7, 0x14d8,
+ 0x64f8, 0x2f2b,
+ 0x64fa, 0x14d6,
+ 0x64fc, 0x2f2e,
+ 0x64fd, 0x2f2a,
+ 0x64fe, 0x14d4,
+ 0x64ff, 0x2f28,
+ 0x6500, 0x1582,
+ 0x6501, 0x2f2c,
+ 0x6503, 0x2f2d,
+ 0x6504, 0x2f29,
+ 0x6506, 0x14d5,
+ 0x6507, 0x3090,
+ 0x6509, 0x3093,
+ 0x650a, 0x4536,
+ 0x650c, 0x3094,
+ 0x650d, 0x3092,
+ 0x650e, 0x3095,
+ 0x650f, 0x1583,
+ 0x6510, 0x3091,
+ 0x6511, 0x3aa9,
+ 0x6513, 0x31d7,
+ 0x6514, 0x1617,
+ 0x6515, 0x31d6,
+ 0x6516, 0x31d5,
+ 0x6517, 0x31d4,
+ 0x6518, 0x1616,
+ 0x6519, 0x1618,
+ 0x651b, 0x32d2,
+ 0x651c, 0x1673,
+ 0x651d, 0x1672,
+ 0x651e, 0x4187,
+ 0x651f, 0x3ec0,
+ 0x6520, 0x3382,
+ 0x6521, 0x3381,
+ 0x6522, 0x3384,
+ 0x6523, 0x16f9,
+ 0x6524, 0x16c5,
+ 0x6525, 0x341b,
+ 0x6526, 0x3383,
+ 0x6529, 0x341a,
+ 0x652a, 0x16fb,
+ 0x652b, 0x16fa,
+ 0x652c, 0x1721,
+ 0x652d, 0x3484,
+ 0x652e, 0x34ca,
+ 0x652f, 0x02d5,
+ 0x6530, 0x3e62,
+ 0x6532, 0x216c,
+ 0x6533, 0x2b59,
+ 0x6534, 0x022c,
+ 0x6535, 0x44ed,
+ 0x6536, 0x03d7,
+ 0x6537, 0x17f6,
+ 0x6538, 0x04b9,
+ 0x6539, 0x04b7,
+ 0x653b, 0x04b8,
+ 0x653d, 0x19a1,
+ 0x653e, 0x05f3,
+ 0x653f, 0x0741,
+ 0x6541, 0x1b01,
+ 0x6543, 0x1b02,
+ 0x6545, 0x0742,
+ 0x6546, 0x1cbf,
+ 0x6548, 0x08d6,
+ 0x654a, 0x1cbe,
+ 0x654d, 0x419f,
+ 0x654f, 0x0abd,
+ 0x6551, 0x0ab9,
+ 0x6553, 0x1f0c,
+ 0x6554, 0x0ac0,
+ 0x6555, 0x0abf,
+ 0x6556, 0x0ab8,
+ 0x6557, 0x0abb,
+ 0x6558, 0x0abe,
+ 0x6559, 0x0aba,
+ 0x655c, 0x2170,
+ 0x655d, 0x0ab7,
+ 0x655e, 0x0c70,
+ 0x655f, 0x41a5,
+ 0x6562, 0x0c72,
+ 0x6564, 0x216f,
+ 0x6565, 0x2172,
+ 0x6566, 0x0c71,
+ 0x6567, 0x216d,
+ 0x6568, 0x2171,
+ 0x656a, 0x216e,
+ 0x656b, 0x3a6c,
+ 0x656c, 0x0e2b,
+ 0x656d, 0x41a4,
+ 0x656f, 0x2409,
+ 0x6572, 0x0fe7,
+ 0x6573, 0x26b4,
+ 0x6574, 0x12c6,
+ 0x6575, 0x116e,
+ 0x6576, 0x28f1,
+ 0x6577, 0x116f,
+ 0x6579, 0x28f3,
+ 0x657a, 0x28f2,
+ 0x657b, 0x28f4,
+ 0x657c, 0x2b5b,
+ 0x657f, 0x2b5a,
+ 0x6580, 0x2d6f,
+ 0x6581, 0x2d6e,
+ 0x6582, 0x13e1,
+ 0x6584, 0x3096,
+ 0x6585, 0x41a3,
+ 0x6586, 0x4648,
+ 0x6587, 0x02d6,
+ 0x6588, 0x410b,
+ 0x6589, 0x4554,
+ 0x658c, 0x2173,
+ 0x6590, 0x0c75,
+ 0x6591, 0x0c74,
+ 0x6592, 0x240a,
+ 0x6594, 0x2f2f,
+ 0x6595, 0x1674,
+ 0x6596, 0x341c,
+ 0x6597, 0x02d7,
+ 0x6599, 0x08d8,
+ 0x659b, 0x0ac2,
+ 0x659c, 0x0ac1,
+ 0x659d, 0x2174,
+ 0x659f, 0x0e2c,
+ 0x65a0, 0x26b5,
+ 0x65a1, 0x0fe8,
+ 0x65a2, 0x2b5c,
+ 0x65a4, 0x02d8,
+ 0x65a5, 0x0346,
+ 0x65a7, 0x05f4,
+ 0x65a8, 0x19a2,
+ 0x65aa, 0x1b03,
+ 0x65ab, 0x0743,
+ 0x65ac, 0x0ac3,
+ 0x65ae, 0x2176,
+ 0x65af, 0x0c76,
+ 0x65b0, 0x0e2d,
+ 0x65b2, 0x28f5,
+ 0x65b5, 0x41a7,
+ 0x65b6, 0x2d70,
+ 0x65b7, 0x14d9,
+ 0x65b8, 0x34cb,
+ 0x65b9, 0x02d9,
+ 0x65bb, 0x19a3,
+ 0x65bc, 0x05f5,
+ 0x65bd, 0x0744,
+ 0x65be, 0x3e3b,
+ 0x65bf, 0x1b04,
+ 0x65c1, 0x08d9,
+ 0x65c2, 0x1cc3,
+ 0x65c3, 0x1cc1,
+ 0x65c5, 0x08da,
+ 0x65c6, 0x1cc0,
+ 0x65cb, 0x0ac5,
+ 0x65cd, 0x1f0d,
+ 0x65ce, 0x0ac7,
+ 0x65cf, 0x0ac4,
+ 0x65d0, 0x2177,
+ 0x65d1, 0x41aa,
+ 0x65d2, 0x2178,
+ 0x65d3, 0x240b,
+ 0x65d4, 0x3ba8,
+ 0x65d6, 0x0fea,
+ 0x65d7, 0x0fe9,
+ 0x65da, 0x2d71,
+ 0x65db, 0x2f30,
+ 0x65dd, 0x3098,
+ 0x65de, 0x3097,
+ 0x65df, 0x31d8,
+ 0x65e0, 0x022d,
+ 0x65e1, 0x1789,
+ 0x65e2, 0x0745,
+ 0x65e3, 0x41ae,
+ 0x65e5, 0x02da,
+ 0x65e6, 0x0347,
+ 0x65e8, 0x03d9,
+ 0x65e9, 0x03d8,
+ 0x65ec, 0x03da,
+ 0x65ee, 0x17f8,
+ 0x65ef, 0x17f7,
+ 0x65f0, 0x189e,
+ 0x65f1, 0x04ba,
+ 0x65f2, 0x18a1,
+ 0x65f3, 0x18a0,
+ 0x65f4, 0x189f,
+ 0x65f5, 0x18a2,
+ 0x65fa, 0x05f6,
+ 0x65fb, 0x19a9,
+ 0x65fc, 0x19a5,
+ 0x65fd, 0x19ae,
+ 0x65ff, 0x464a,
+ 0x6600, 0x05fd,
+ 0x6602, 0x05fb,
+ 0x6603, 0x19aa,
+ 0x6604, 0x19a6,
+ 0x6605, 0x19ad,
+ 0x6606, 0x05fa,
+ 0x6607, 0x0601,
+ 0x6608, 0x19a8,
+ 0x6609, 0x19a4,
+ 0x660a, 0x0600,
+ 0x660b, 0x19ab,
+ 0x660c, 0x05f9,
+ 0x660d, 0x19ac,
+ 0x660e, 0x05fc,
+ 0x660f, 0x05fe,
+ 0x6610, 0x19b0,
+ 0x6611, 0x19af,
+ 0x6612, 0x19a7,
+ 0x6613, 0x05f8,
+ 0x6614, 0x05f7,
+ 0x6615, 0x05ff,
+ 0x6618, 0x41b1,
+ 0x661c, 0x1b09,
+ 0x661d, 0x1b0f,
+ 0x661e, 0x3a93,
+ 0x661f, 0x074b,
+ 0x6620, 0x0748,
+ 0x6621, 0x1b06,
+ 0x6622, 0x1b0b,
+ 0x6623, 0x4295,
+ 0x6624, 0x074e,
+ 0x6625, 0x0746,
+ 0x6626, 0x1b0a,
+ 0x6627, 0x0749,
+ 0x6628, 0x074c,
+ 0x662b, 0x1b0d,
+ 0x662d, 0x0747,
+ 0x662e, 0x1b12,
+ 0x662f, 0x074a,
+ 0x6630, 0x3a8d,
+ 0x6631, 0x074d,
+ 0x6632, 0x1b07,
+ 0x6633, 0x1b0c,
+ 0x6634, 0x1b10,
+ 0x6635, 0x1b08,
+ 0x6636, 0x1b05,
+ 0x6639, 0x1b11,
+ 0x663a, 0x1b0e,
+ 0x6641, 0x08e2,
+ 0x6642, 0x08db,
+ 0x6643, 0x08de,
+ 0x6644, 0x41b4,
+ 0x6645, 0x08e1,
+ 0x6647, 0x1cc6,
+ 0x6648, 0x3d99,
+ 0x6649, 0x08dc,
+ 0x664a, 0x1cc4,
+ 0x664b, 0x41b7,
+ 0x664c, 0x08e0,
+ 0x664f, 0x08dd,
+ 0x6651, 0x1cc7,
+ 0x6652, 0x08df,
+ 0x6653, 0x464b,
+ 0x6657, 0x409b,
+ 0x6659, 0x1f11,
+ 0x665a, 0x0ac9,
+ 0x665b, 0x1f10,
+ 0x665c, 0x1f12,
+ 0x665d, 0x0ac8,
+ 0x665e, 0x0acd,
+ 0x665f, 0x1cc5,
+ 0x6661, 0x1f0f,
+ 0x6662, 0x1f13,
+ 0x6663, 0x3a90,
+ 0x6664, 0x0aca,
+ 0x6665, 0x1f0e,
+ 0x6666, 0x0acc,
+ 0x6667, 0x41b9,
+ 0x6668, 0x0acb,
+ 0x666a, 0x217f,
+ 0x666b, 0x3a8b,
+ 0x666c, 0x217a,
+ 0x666e, 0x0c77,
+ 0x666f, 0x0c7b,
+ 0x6670, 0x0c78,
+ 0x6671, 0x217d,
+ 0x6672, 0x2180,
+ 0x6673, 0x41bb,
+ 0x6674, 0x0c79,
+ 0x6676, 0x0c7a,
+ 0x6677, 0x0c7f,
+ 0x6678, 0x2414,
+ 0x6679, 0x217e,
+ 0x667a, 0x0c7d,
+ 0x667b, 0x217b,
+ 0x667c, 0x2179,
+ 0x667d, 0x469b,
+ 0x667e, 0x0c7e,
+ 0x6680, 0x217c,
+ 0x6684, 0x0e33,
+ 0x6685, 0x4162,
+ 0x6686, 0x240c,
+ 0x6687, 0x0e30,
+ 0x6689, 0x0e2f,
+ 0x668a, 0x2411,
+ 0x668b, 0x2410,
+ 0x668c, 0x240d,
+ 0x668d, 0x0e35,
+ 0x668e, 0x3a89,
+ 0x6690, 0x240f,
+ 0x6691, 0x0c7c,
+ 0x6692, 0x464d,
+ 0x6694, 0x2413,
+ 0x6695, 0x240e,
+ 0x6696, 0x0e32,
+ 0x6697, 0x0e2e,
+ 0x6698, 0x0e34,
+ 0x6699, 0x2412,
+ 0x669a, 0x3d3d,
+ 0x669d, 0x0fed,
+ 0x669f, 0x26b8,
+ 0x66a0, 0x26b7,
+ 0x66a1, 0x26b6,
+ 0x66a2, 0x0feb,
+ 0x66a4, 0x40ba,
+ 0x66a8, 0x0fec,
+ 0x66a9, 0x28f9,
+ 0x66aa, 0x28fc,
+ 0x66ab, 0x1172,
+ 0x66ad, 0x4948,
+ 0x66ae, 0x1171,
+ 0x66af, 0x28fd,
+ 0x66b0, 0x28f8,
+ 0x66b1, 0x1174,
+ 0x66b2, 0x28fa,
+ 0x66b3, 0x40b5,
+ 0x66b4, 0x1173,
+ 0x66b5, 0x28f7,
+ 0x66b6, 0x3e13,
+ 0x66b7, 0x28fb,
+ 0x66b8, 0x12cc,
+ 0x66b9, 0x12c9,
+ 0x66ba, 0x2b65,
+ 0x66bb, 0x2b64,
+ 0x66bd, 0x2b63,
+ 0x66be, 0x2b5e,
+ 0x66bf, 0x3d9a,
+ 0x66c0, 0x2b5f,
+ 0x66c4, 0x12ca,
+ 0x66c6, 0x12c7,
+ 0x66c7, 0x12cb,
+ 0x66c8, 0x2b5d,
+ 0x66c9, 0x12c8,
+ 0x66ca, 0x2b60,
+ 0x66cc, 0x2b66,
+ 0x66cd, 0x40b8,
+ 0x66ce, 0x3a77,
+ 0x66cf, 0x2b62,
+ 0x66d2, 0x2d72,
+ 0x66d6, 0x13e4,
+ 0x66d8, 0x2f33,
+ 0x66d9, 0x13e3,
+ 0x66da, 0x2f31,
+ 0x66dc, 0x14da,
+ 0x66dd, 0x1585,
+ 0x66de, 0x3099,
+ 0x66e0, 0x1584,
+ 0x66e3, 0x31da,
+ 0x66e6, 0x1619,
+ 0x66e8, 0x31d9,
+ 0x66e9, 0x1675,
+ 0x66eb, 0x341d,
+ 0x66ec, 0x16fc,
+ 0x66ed, 0x3485,
+ 0x66f0, 0x02db,
+ 0x66f1, 0x3e84,
+ 0x66f2, 0x03dc,
+ 0x66f4, 0x04bb,
+ 0x66f6, 0x19b1,
+ 0x66f7, 0x074f,
+ 0x66f8, 0x08e3,
+ 0x66f9, 0x0ace,
+ 0x66fc, 0x0a1f,
+ 0x66fe, 0x0c80,
+ 0x6700, 0x0bf0,
+ 0x6701, 0x2181,
+ 0x6702, 0x41c4,
+ 0x6703, 0x0e36,
+ 0x6704, 0x26ba,
+ 0x6705, 0x26b9,
+ 0x6708, 0x02dc,
+ 0x6709, 0x03de,
+ 0x670a, 0x19b2,
+ 0x670b, 0x0603,
+ 0x670c, 0x3fe2,
+ 0x670d, 0x0602,
+ 0x670e, 0x3da1,
+ 0x670f, 0x1b13,
+ 0x6712, 0x1cc8,
+ 0x6714, 0x08e4,
+ 0x6716, 0x464f,
+ 0x6717, 0x08e6,
+ 0x6718, 0x1f14,
+ 0x671b, 0x0ad0,
+ 0x671d, 0x0c83,
+ 0x671e, 0x3d8b,
+ 0x671f, 0x0c82,
+ 0x6720, 0x2415,
+ 0x6721, 0x2522,
+ 0x6722, 0x26bb,
+ 0x6723, 0x2b67,
+ 0x6725, 0x379f,
+ 0x6726, 0x14db,
+ 0x6727, 0x161a,
+ 0x6728, 0x02dd,
+ 0x672a, 0x034a,
+ 0x672c, 0x0349,
+ 0x672d, 0x034c,
+ 0x672e, 0x0348,
+ 0x6731, 0x03e1,
+ 0x6733, 0x1800,
+ 0x6734, 0x03e0,
+ 0x6735, 0x03e2,
+ 0x6736, 0x3e41,
+ 0x6738, 0x17fb,
+ 0x6739, 0x17fa,
+ 0x673a, 0x17fd,
+ 0x673b, 0x17fc,
+ 0x673c, 0x17ff,
+ 0x673d, 0x03df,
+ 0x673e, 0x17f9,
+ 0x673f, 0x17fe,
+ 0x6744, 0x401b,
+ 0x6745, 0x18a3,
+ 0x6746, 0x04c5,
+ 0x6747, 0x18a4,
+ 0x6748, 0x18a8,
+ 0x6749, 0x04c4,
+ 0x674b, 0x18ac,
+ 0x674c, 0x18a7,
+ 0x674d, 0x18aa,
+ 0x674e, 0x04bd,
+ 0x6753, 0x04c7,
+ 0x6755, 0x18a6,
+ 0x6756, 0x04c2,
+ 0x6757, 0x04c8,
+ 0x6759, 0x18a5,
+ 0x675a, 0x18ab,
+ 0x675c, 0x04c1,
+ 0x675d, 0x18a9,
+ 0x675e, 0x04c3,
+ 0x675f, 0x04bc,
+ 0x6760, 0x04c6,
+ 0x6761, 0x3d66,
+ 0x6762, 0x41cb,
+ 0x6767, 0x41ca,
+ 0x676a, 0x0618,
+ 0x676c, 0x19b4,
+ 0x676d, 0x0604,
+ 0x676f, 0x060e,
+ 0x6771, 0x0607,
+ 0x6772, 0x0619,
+ 0x6773, 0x0609,
+ 0x6774, 0x19bc,
+ 0x6775, 0x0614,
+ 0x6776, 0x19b7,
+ 0x6777, 0x060a,
+ 0x6778, 0x19c6,
+ 0x677a, 0x19bf,
+ 0x677b, 0x19b8,
+ 0x677c, 0x0617,
+ 0x677d, 0x19c4,
+ 0x677e, 0x0612,
+ 0x677f, 0x0610,
+ 0x6781, 0x19c5,
+ 0x6783, 0x19c3,
+ 0x6784, 0x19bb,
+ 0x6785, 0x19b3,
+ 0x6786, 0x19ba,
+ 0x6787, 0x060b,
+ 0x6789, 0x0611,
+ 0x678b, 0x0605,
+ 0x678c, 0x19be,
+ 0x678d, 0x19bd,
+ 0x678e, 0x19b5,
+ 0x678f, 0x46c1,
+ 0x6790, 0x0613,
+ 0x6791, 0x19c1,
+ 0x6792, 0x19b6,
+ 0x6793, 0x0616,
+ 0x6794, 0x19c8,
+ 0x6795, 0x0606,
+ 0x6797, 0x060d,
+ 0x6798, 0x19b9,
+ 0x6799, 0x19c2,
+ 0x679a, 0x0615,
+ 0x679c, 0x0608,
+ 0x679d, 0x060c,
+ 0x679f, 0x19c0,
+ 0x67a0, 0x3d7a,
+ 0x67a4, 0x4651,
+ 0x67ac, 0x41e3,
+ 0x67ae, 0x1b34,
+ 0x67af, 0x0757,
+ 0x67b0, 0x0764,
+ 0x67b1, 0x41f4,
+ 0x67b2, 0x1b2f,
+ 0x67b3, 0x1b25,
+ 0x67b4, 0x075d,
+ 0x67b5, 0x1b23,
+ 0x67b6, 0x0756,
+ 0x67b7, 0x1b1e,
+ 0x67b8, 0x0760,
+ 0x67b9, 0x1b2b,
+ 0x67ba, 0x1b18,
+ 0x67bb, 0x1b1a,
+ 0x67bf, 0x37fa,
+ 0x67c0, 0x1b1d,
+ 0x67c1, 0x1b15,
+ 0x67c2, 0x1b2a,
+ 0x67c3, 0x1b3a,
+ 0x67c4, 0x075b,
+ 0x67c5, 0x1b1f,
+ 0x67c6, 0x1b31,
+ 0x67c8, 0x1b17,
+ 0x67c9, 0x1b38,
+ 0x67cb, 0x1b3c,
+ 0x67cc, 0x1b33,
+ 0x67cd, 0x1b24,
+ 0x67ce, 0x1b2c,
+ 0x67cf, 0x0761,
+ 0x67d0, 0x0754,
+ 0x67d1, 0x075c,
+ 0x67d2, 0x0768,
+ 0x67d3, 0x0751,
+ 0x67d4, 0x0753,
+ 0x67d6, 0x3b58,
+ 0x67d7, 0x41ce,
+ 0x67d8, 0x1b1c,
+ 0x67d9, 0x0765,
+ 0x67da, 0x075e,
+ 0x67db, 0x1b36,
+ 0x67dc, 0x1b19,
+ 0x67dd, 0x0767,
+ 0x67de, 0x0762,
+ 0x67df, 0x1b22,
+ 0x67e2, 0x0766,
+ 0x67e3, 0x1b29,
+ 0x67e4, 0x1b21,
+ 0x67e5, 0x075f,
+ 0x67e6, 0x1b35,
+ 0x67e7, 0x1b2d,
+ 0x67e9, 0x0759,
+ 0x67ea, 0x1b3b,
+ 0x67eb, 0x1b20,
+ 0x67ec, 0x0755,
+ 0x67ed, 0x1b32,
+ 0x67ee, 0x1b28,
+ 0x67ef, 0x075a,
+ 0x67f0, 0x1b2e,
+ 0x67f1, 0x0752,
+ 0x67f2, 0x1b16,
+ 0x67f3, 0x0763,
+ 0x67f4, 0x08f5,
+ 0x67f5, 0x0758,
+ 0x67f6, 0x1b27,
+ 0x67f7, 0x1b26,
+ 0x67f8, 0x1b1b,
+ 0x67f9, 0x3996,
+ 0x67fa, 0x1b37,
+ 0x67fc, 0x1b30,
+ 0x67fe, 0x4555,
+ 0x67ff, 0x0750,
+ 0x6800, 0x43c7,
+ 0x6801, 0x41d3,
+ 0x6802, 0x3fc8,
+ 0x6803, 0x3d6a,
+ 0x6804, 0x4556,
+ 0x680d, 0x4281,
+ 0x6810, 0x399c,
+ 0x6812, 0x1cdd,
+ 0x6813, 0x08fc,
+ 0x6814, 0x1cde,
+ 0x6816, 0x1cd2,
+ 0x6817, 0x08f1,
+ 0x6818, 0x08fd,
+ 0x681a, 0x1ccb,
+ 0x681b, 0x4072,
+ 0x681c, 0x1cd4,
+ 0x681d, 0x1cdc,
+ 0x681e, 0x46c2,
+ 0x681f, 0x1cca,
+ 0x6820, 0x1ce5,
+ 0x6821, 0x08e7,
+ 0x6822, 0x41d0,
+ 0x6825, 0x1ce4,
+ 0x6826, 0x1cdf,
+ 0x6828, 0x1ce0,
+ 0x6829, 0x08ef,
+ 0x682a, 0x08fa,
+ 0x682b, 0x1cd6,
+ 0x682d, 0x1cd7,
+ 0x682e, 0x1ce1,
+ 0x682f, 0x1cd8,
+ 0x6831, 0x1cd3,
+ 0x6832, 0x1ccd,
+ 0x6834, 0x1cdb,
+ 0x6835, 0x1cd5,
+ 0x6836, 0x3e2e,
+ 0x6837, 0x421d,
+ 0x6838, 0x08e8,
+ 0x6839, 0x08ec,
+ 0x683a, 0x1ce3,
+ 0x683b, 0x1ccf,
+ 0x683c, 0x08f8,
+ 0x683d, 0x08f4,
+ 0x683e, 0x4147,
+ 0x6840, 0x08f7,
+ 0x6841, 0x08fe,
+ 0x6842, 0x08ed,
+ 0x6843, 0x08f9,
+ 0x6844, 0x1cda,
+ 0x6845, 0x08fb,
+ 0x6846, 0x08ea,
+ 0x6847, 0x3beb,
+ 0x6848, 0x08e9,
+ 0x6849, 0x1ccc,
+ 0x684a, 0x4653,
+ 0x684b, 0x1cd0,
+ 0x684c, 0x08f2,
+ 0x684d, 0x1ce2,
+ 0x684e, 0x1cd9,
+ 0x684f, 0x1cd1,
+ 0x6850, 0x08f6,
+ 0x6851, 0x08f3,
+ 0x6853, 0x08eb,
+ 0x6854, 0x08ee,
+ 0x6855, 0x3d90,
+ 0x6856, 0x3814,
+ 0x685d, 0x41d6,
+ 0x6865, 0x4557,
+ 0x686b, 0x1f29,
+ 0x686d, 0x1f19,
+ 0x686f, 0x1f1e,
+ 0x6871, 0x1f2d,
+ 0x6872, 0x1f2a,
+ 0x6874, 0x1f23,
+ 0x6875, 0x1f22,
+ 0x6876, 0x0ad7,
+ 0x6877, 0x1f26,
+ 0x6878, 0x1f35,
+ 0x6879, 0x1f15,
+ 0x687b, 0x1f36,
+ 0x687c, 0x1f28,
+ 0x687d, 0x1f3a,
+ 0x687e, 0x1f2e,
+ 0x687f, 0x0ad6,
+ 0x6880, 0x1f2c,
+ 0x6881, 0x0ad1,
+ 0x6882, 0x0ae6,
+ 0x6883, 0x0adc,
+ 0x6884, 0x4654,
+ 0x6885, 0x0ae0,
+ 0x6886, 0x0adf,
+ 0x6887, 0x1f16,
+ 0x6888, 0x46b7,
+ 0x6889, 0x1f33,
+ 0x688a, 0x1f39,
+ 0x688b, 0x1f31,
+ 0x688c, 0x1f38,
+ 0x688f, 0x1f25,
+ 0x6890, 0x1f17,
+ 0x6891, 0x1f37,
+ 0x6892, 0x1f27,
+ 0x6893, 0x0ad4,
+ 0x6894, 0x0ae1,
+ 0x6896, 0x1f30,
+ 0x6897, 0x0ada,
+ 0x6898, 0x3aaa,
+ 0x689b, 0x1f2f,
+ 0x689c, 0x1f18,
+ 0x689d, 0x0ae2,
+ 0x689f, 0x0ae4,
+ 0x68a0, 0x1f32,
+ 0x68a1, 0x0ae5,
+ 0x68a2, 0x0ad3,
+ 0x68a3, 0x1f1f,
+ 0x68a4, 0x1f34,
+ 0x68a6, 0x40e4,
+ 0x68a7, 0x0ad9,
+ 0x68a8, 0x0ae3,
+ 0x68a9, 0x1f21,
+ 0x68aa, 0x1f2b,
+ 0x68ab, 0x1f1c,
+ 0x68ac, 0x1f20,
+ 0x68ad, 0x0ade,
+ 0x68ae, 0x1f1b,
+ 0x68af, 0x0ad2,
+ 0x68b0, 0x0adb,
+ 0x68b1, 0x0ad8,
+ 0x68b2, 0x1f24,
+ 0x68b3, 0x08f0,
+ 0x68b4, 0x2198,
+ 0x68b5, 0x0ad5,
+ 0x68b6, 0x3a9e,
+ 0x68b9, 0x3d14,
+ 0x68bd, 0x427c,
+ 0x68c3, 0x41dc,
+ 0x68c4, 0x0add,
+ 0x68c5, 0x3c2e,
+ 0x68c6, 0x219b,
+ 0x68c7, 0x21b1,
+ 0x68c8, 0x21a6,
+ 0x68c9, 0x0c97,
+ 0x68ca, 0x42eb,
+ 0x68cb, 0x0c92,
+ 0x68cc, 0x2195,
+ 0x68cd, 0x0c93,
+ 0x68ce, 0x21a5,
+ 0x68d0, 0x219e,
+ 0x68d1, 0x21ab,
+ 0x68d2, 0x0c8f,
+ 0x68d3, 0x2183,
+ 0x68d4, 0x21ad,
+ 0x68d5, 0x0c85,
+ 0x68d6, 0x218b,
+ 0x68d7, 0x0c88,
+ 0x68d8, 0x0c87,
+ 0x68da, 0x0c98,
+ 0x68dc, 0x2185,
+ 0x68dd, 0x21a7,
+ 0x68df, 0x0c8a,
+ 0x68e0, 0x0c86,
+ 0x68e1, 0x2193,
+ 0x68e3, 0x0c91,
+ 0x68e4, 0x218e,
+ 0x68e6, 0x21a9,
+ 0x68e7, 0x0c8d,
+ 0x68e8, 0x21a1,
+ 0x68e9, 0x21ae,
+ 0x68ea, 0x2188,
+ 0x68eb, 0x218d,
+ 0x68ec, 0x2187,
+ 0x68ee, 0x0c8c,
+ 0x68ef, 0x219a,
+ 0x68f0, 0x242b,
+ 0x68f1, 0x2189,
+ 0x68f2, 0x0c90,
+ 0x68f3, 0x2192,
+ 0x68f4, 0x21aa,
+ 0x68f5, 0x0c8b,
+ 0x68f6, 0x218f,
+ 0x68f7, 0x218c,
+ 0x68f8, 0x219d,
+ 0x68f9, 0x0c8e,
+ 0x68fa, 0x0c84,
+ 0x68fb, 0x0c9a,
+ 0x68fc, 0x21a0,
+ 0x68fd, 0x219f,
+ 0x6900, 0x41df,
+ 0x6901, 0x41de,
+ 0x6902, 0x42fb,
+ 0x6903, 0x429c,
+ 0x6904, 0x2184,
+ 0x6905, 0x0c89,
+ 0x6906, 0x21ac,
+ 0x6907, 0x2194,
+ 0x6908, 0x2196,
+ 0x6909, 0x4658,
+ 0x690a, 0x21a3,
+ 0x690b, 0x21a2,
+ 0x690c, 0x2182,
+ 0x690d, 0x0c94,
+ 0x690e, 0x0c96,
+ 0x690f, 0x218a,
+ 0x6910, 0x2191,
+ 0x6911, 0x2199,
+ 0x6912, 0x0c95,
+ 0x6913, 0x2190,
+ 0x6914, 0x219c,
+ 0x6915, 0x21af,
+ 0x6917, 0x21a4,
+ 0x6918, 0x3da2,
+ 0x691a, 0x3d80,
+ 0x691b, 0x37bd,
+ 0x6925, 0x21b0,
+ 0x692a, 0x2186,
+ 0x692c, 0x3f38,
+ 0x692f, 0x243f,
+ 0x6930, 0x0e3e,
+ 0x6932, 0x243d,
+ 0x6933, 0x2428,
+ 0x6934, 0x242d,
+ 0x6935, 0x2426,
+ 0x6936, 0x41e7,
+ 0x6937, 0x2439,
+ 0x6938, 0x2418,
+ 0x6939, 0x241f,
+ 0x693b, 0x2437,
+ 0x693c, 0x2441,
+ 0x693d, 0x2429,
+ 0x693e, 0x4056,
+ 0x693f, 0x241c,
+ 0x6940, 0x242f,
+ 0x6941, 0x2434,
+ 0x6942, 0x2420,
+ 0x6943, 0x4659,
+ 0x6944, 0x2431,
+ 0x6945, 0x241d,
+ 0x6946, 0x456f,
+ 0x6948, 0x2424,
+ 0x694a, 0x0e40,
+ 0x694b, 0x2438,
+ 0x694c, 0x2436,
+ 0x694e, 0x2419,
+ 0x694f, 0x243b,
+ 0x6951, 0x243c,
+ 0x6952, 0x243e,
+ 0x6953, 0x0e44,
+ 0x6954, 0x0e3c,
+ 0x6955, 0x3d86,
+ 0x6956, 0x1f1d,
+ 0x6957, 0x2421,
+ 0x6958, 0x2433,
+ 0x6959, 0x2422,
+ 0x695a, 0x0e39,
+ 0x695b, 0x0e49,
+ 0x695c, 0x243a,
+ 0x695d, 0x0e47,
+ 0x695e, 0x0e43,
+ 0x695f, 0x2417,
+ 0x6960, 0x0e3b,
+ 0x6961, 0x41e4,
+ 0x6962, 0x241a,
+ 0x6963, 0x0e48,
+ 0x6964, 0x465b,
+ 0x6965, 0x242a,
+ 0x6966, 0x2416,
+ 0x6967, 0x3d15,
+ 0x6968, 0x0e41,
+ 0x6969, 0x242e,
+ 0x696a, 0x241e,
+ 0x696b, 0x0e42,
+ 0x696c, 0x2427,
+ 0x696d, 0x0e38,
+ 0x696e, 0x0c99,
+ 0x696f, 0x2430,
+ 0x6970, 0x2197,
+ 0x6971, 0x241b,
+ 0x6972, 0x3a6d,
+ 0x6973, 0x41db,
+ 0x6974, 0x2435,
+ 0x6975, 0x0e3d,
+ 0x6976, 0x2432,
+ 0x6977, 0x0e3a,
+ 0x6978, 0x242c,
+ 0x6979, 0x0e45,
+ 0x697a, 0x2423,
+ 0x697b, 0x2440,
+ 0x6980, 0x3f3e,
+ 0x6982, 0x0e3f,
+ 0x6983, 0x24af,
+ 0x6985, 0x465d,
+ 0x6986, 0x0e46,
+ 0x698a, 0x3d74,
+ 0x698d, 0x26c9,
+ 0x698e, 0x26c7,
+ 0x6990, 0x26dd,
+ 0x6991, 0x26c5,
+ 0x6993, 0x26d7,
+ 0x6994, 0x0e37,
+ 0x6995, 0x0ff0,
+ 0x6996, 0x26c1,
+ 0x6997, 0x26dc,
+ 0x6998, 0x41e8,
+ 0x6999, 0x26c6,
+ 0x699a, 0x26d4,
+ 0x699b, 0x0ff5,
+ 0x699c, 0x0fee,
+ 0x699e, 0x26da,
+ 0x699f, 0x465c,
+ 0x69a0, 0x26bf,
+ 0x69a1, 0x26d9,
+ 0x69a2, 0x3730,
+ 0x69a3, 0x1000,
+ 0x69a4, 0x26d0,
+ 0x69a5, 0x26e0,
+ 0x69a6, 0x0ffe,
+ 0x69a7, 0x26c8,
+ 0x69a8, 0x0fef,
+ 0x69a9, 0x26ca,
+ 0x69aa, 0x26d8,
+ 0x69ab, 0x0ff8,
+ 0x69ac, 0x26c3,
+ 0x69ad, 0x0ffc,
+ 0x69ae, 0x0ff2,
+ 0x69af, 0x26cc,
+ 0x69b0, 0x26c2,
+ 0x69b1, 0x26bc,
+ 0x69b2, 0x3ff6,
+ 0x69b3, 0x26d6,
+ 0x69b4, 0x0ff9,
+ 0x69b5, 0x26df,
+ 0x69b6, 0x26bd,
+ 0x69b7, 0x0ff6,
+ 0x69b9, 0x26d2,
+ 0x69bb, 0x0ff7,
+ 0x69bc, 0x26c4,
+ 0x69bd, 0x26cf,
+ 0x69be, 0x26cb,
+ 0x69bf, 0x26cd,
+ 0x69c0, 0x3f5d,
+ 0x69c1, 0x0ff1,
+ 0x69c2, 0x26de,
+ 0x69c3, 0x0fff,
+ 0x69c4, 0x26ce,
+ 0x69c6, 0x26e1,
+ 0x69c9, 0x26be,
+ 0x69ca, 0x26d3,
+ 0x69cb, 0x0ff4,
+ 0x69cc, 0x0ffd,
+ 0x69cd, 0x0ffb,
+ 0x69ce, 0x26c0,
+ 0x69cf, 0x26d5,
+ 0x69d0, 0x0ffa,
+ 0x69d1, 0x39ef,
+ 0x69d3, 0x0ff3,
+ 0x69d4, 0x26d1,
+ 0x69d5, 0x3e3c,
+ 0x69d6, 0x465e,
+ 0x69d9, 0x26db,
+ 0x69e1, 0x41d8,
+ 0x69e2, 0x2909,
+ 0x69e4, 0x2905,
+ 0x69e5, 0x2901,
+ 0x69e6, 0x2915,
+ 0x69e7, 0x2912,
+ 0x69e8, 0x1177,
+ 0x69e9, 0x3d91,
+ 0x69eb, 0x2919,
+ 0x69ec, 0x2908,
+ 0x69ed, 0x1182,
+ 0x69ee, 0x290f,
+ 0x69f1, 0x2904,
+ 0x69f2, 0x290e,
+ 0x69f3, 0x117f,
+ 0x69f4, 0x2922,
+ 0x69f6, 0x291f,
+ 0x69f7, 0x2911,
+ 0x69f8, 0x2902,
+ 0x69f9, 0x41ed,
+ 0x69fa, 0x41c7,
+ 0x69fb, 0x2916,
+ 0x69fc, 0x2918,
+ 0x69fd, 0x117b,
+ 0x69fe, 0x290c,
+ 0x69ff, 0x2907,
+ 0x6a00, 0x28fe,
+ 0x6a01, 0x1178,
+ 0x6a02, 0x1180,
+ 0x6a03, 0x3e29,
+ 0x6a04, 0x291b,
+ 0x6a05, 0x1181,
+ 0x6a06, 0x28ff,
+ 0x6a07, 0x2921,
+ 0x6a08, 0x2914,
+ 0x6a09, 0x291a,
+ 0x6a0a, 0x117e,
+ 0x6a0b, 0x41d9,
+ 0x6a0c, 0x3d50,
+ 0x6a0d, 0x2917,
+ 0x6a0f, 0x291e,
+ 0x6a11, 0x1183,
+ 0x6a13, 0x117d,
+ 0x6a14, 0x2910,
+ 0x6a15, 0x2903,
+ 0x6a16, 0x2923,
+ 0x6a17, 0x2900,
+ 0x6a18, 0x291c,
+ 0x6a19, 0x117a,
+ 0x6a1a, 0x3d1e,
+ 0x6a1b, 0x290a,
+ 0x6a1c, 0x3b68,
+ 0x6a1d, 0x290b,
+ 0x6a1e, 0x1179,
+ 0x6a1f, 0x1176,
+ 0x6a20, 0x2906,
+ 0x6a21, 0x117c,
+ 0x6a23, 0x1175,
+ 0x6a25, 0x291d,
+ 0x6a26, 0x2920,
+ 0x6a27, 0x290d,
+ 0x6a28, 0x2b74,
+ 0x6a2b, 0x3d42,
+ 0x6a2c, 0x42ab,
+ 0x6a2d, 0x3b1f,
+ 0x6a32, 0x2b6c,
+ 0x6a33, 0x3aa4,
+ 0x6a34, 0x2b68,
+ 0x6a35, 0x12d9,
+ 0x6a38, 0x12ce,
+ 0x6a39, 0x12d3,
+ 0x6a3a, 0x12cf,
+ 0x6a3b, 0x2b76,
+ 0x6a3c, 0x2b81,
+ 0x6a3d, 0x12cd,
+ 0x6a3e, 0x2b6e,
+ 0x6a3f, 0x2b77,
+ 0x6a40, 0x2913,
+ 0x6a41, 0x2b78,
+ 0x6a44, 0x12d4,
+ 0x6a45, 0x41f0,
+ 0x6a46, 0x2b87,
+ 0x6a47, 0x12d8,
+ 0x6a48, 0x12db,
+ 0x6a49, 0x2b6a,
+ 0x6a4b, 0x12d7,
+ 0x6a4c, 0x3aab,
+ 0x6a4d, 0x2b85,
+ 0x6a4f, 0x2b7c,
+ 0x6a50, 0x2b7b,
+ 0x6a51, 0x2b73,
+ 0x6a52, 0x3aa5,
+ 0x6a53, 0x37ac,
+ 0x6a54, 0x2b7d,
+ 0x6a55, 0x2b84,
+ 0x6a56, 0x2b83,
+ 0x6a57, 0x37da,
+ 0x6a58, 0x12d2,
+ 0x6a59, 0x12d0,
+ 0x6a5a, 0x2b75,
+ 0x6a5b, 0x2b72,
+ 0x6a5d, 0x2b6f,
+ 0x6a5e, 0x2b82,
+ 0x6a5f, 0x12da,
+ 0x6a60, 0x2b80,
+ 0x6a61, 0x12d6,
+ 0x6a62, 0x12d5,
+ 0x6a64, 0x2b7a,
+ 0x6a65, 0x4660,
+ 0x6a66, 0x2b69,
+ 0x6a67, 0x2b6b,
+ 0x6a68, 0x2b6d,
+ 0x6a69, 0x2b7f,
+ 0x6a6a, 0x2b79,
+ 0x6a6b, 0x12d1,
+ 0x6a6d, 0x2b70,
+ 0x6a6f, 0x2b7e,
+ 0x6a71, 0x4662,
+ 0x6a74, 0x4661,
+ 0x6a76, 0x2b71,
+ 0x6a7a, 0x3aad,
+ 0x6a7e, 0x13ec,
+ 0x6a7f, 0x2d84,
+ 0x6a80, 0x13e5,
+ 0x6a81, 0x2d75,
+ 0x6a82, 0x4663,
+ 0x6a83, 0x2d80,
+ 0x6a84, 0x13e7,
+ 0x6a85, 0x2d87,
+ 0x6a87, 0x2d7c,
+ 0x6a89, 0x2d77,
+ 0x6a8a, 0x4136,
+ 0x6a8c, 0x2d88,
+ 0x6a8d, 0x2d73,
+ 0x6a8e, 0x2d7e,
+ 0x6a8f, 0x3c1b,
+ 0x6a90, 0x13ee,
+ 0x6a91, 0x2d83,
+ 0x6a92, 0x2d89,
+ 0x6a93, 0x2d7d,
+ 0x6a94, 0x13e6,
+ 0x6a95, 0x2d7f,
+ 0x6a96, 0x2d74,
+ 0x6a97, 0x13ed,
+ 0x6a99, 0x4665,
+ 0x6a9a, 0x2d86,
+ 0x6a9b, 0x2d79,
+ 0x6a9c, 0x13e9,
+ 0x6a9d, 0x41f2,
+ 0x6a9e, 0x2d7b,
+ 0x6a9f, 0x2d78,
+ 0x6aa0, 0x13ef,
+ 0x6aa1, 0x2d7a,
+ 0x6aa2, 0x13e8,
+ 0x6aa3, 0x13eb,
+ 0x6aa4, 0x2d82,
+ 0x6aa5, 0x2d76,
+ 0x6aa6, 0x2d85,
+ 0x6aa7, 0x37e3,
+ 0x6aa8, 0x2d81,
+ 0x6aab, 0x4667,
+ 0x6aac, 0x14dd,
+ 0x6aad, 0x2f3e,
+ 0x6aae, 0x14e2,
+ 0x6ab1, 0x3e53,
+ 0x6ab2, 0x3b4b,
+ 0x6ab3, 0x14dc,
+ 0x6ab4, 0x2f3d,
+ 0x6ab5, 0x4668,
+ 0x6ab6, 0x2f3a,
+ 0x6ab8, 0x14e0,
+ 0x6ab9, 0x2f35,
+ 0x6aba, 0x2f39,
+ 0x6abb, 0x14df,
+ 0x6abd, 0x2f36,
+ 0x6abe, 0x3aa1,
+ 0x6ac2, 0x14e1,
+ 0x6ac3, 0x14de,
+ 0x6ac5, 0x2f34,
+ 0x6ac6, 0x2f38,
+ 0x6ac7, 0x2f3c,
+ 0x6ac8, 0x41f5,
+ 0x6ac9, 0x3aa6,
+ 0x6aca, 0x3f4c,
+ 0x6acb, 0x309f,
+ 0x6acc, 0x309c,
+ 0x6acd, 0x30a5,
+ 0x6acf, 0x30a4,
+ 0x6ad0, 0x30a2,
+ 0x6ad1, 0x309d,
+ 0x6ad3, 0x1589,
+ 0x6ad4, 0x4669,
+ 0x6ad8, 0x3caa,
+ 0x6ad9, 0x309e,
+ 0x6ada, 0x1588,
+ 0x6adb, 0x13ea,
+ 0x6adc, 0x30a1,
+ 0x6add, 0x1587,
+ 0x6ade, 0x30a6,
+ 0x6adf, 0x30a0,
+ 0x6ae0, 0x309b,
+ 0x6ae1, 0x2f37,
+ 0x6ae5, 0x1586,
+ 0x6ae7, 0x309a,
+ 0x6ae8, 0x31df,
+ 0x6aea, 0x31de,
+ 0x6aeb, 0x30a3,
+ 0x6aec, 0x161b,
+ 0x6aee, 0x31e2,
+ 0x6af0, 0x31dd,
+ 0x6af1, 0x31e1,
+ 0x6af3, 0x31dc,
+ 0x6af6, 0x466a,
+ 0x6af8, 0x32d6,
+ 0x6af9, 0x31e0,
+ 0x6afa, 0x1678,
+ 0x6afb, 0x1676,
+ 0x6afc, 0x32d4,
+ 0x6b00, 0x32d7,
+ 0x6b02, 0x32d3,
+ 0x6b03, 0x32d5,
+ 0x6b04, 0x1677,
+ 0x6b05, 0x3aa7,
+ 0x6b08, 0x3386,
+ 0x6b0a, 0x16c6,
+ 0x6b0b, 0x3385,
+ 0x6b0f, 0x3420,
+ 0x6b10, 0x16fd,
+ 0x6b11, 0x341e,
+ 0x6b13, 0x3487,
+ 0x6b16, 0x1743,
+ 0x6b17, 0x34ce,
+ 0x6b18, 0x34cc,
+ 0x6b1a, 0x34cf,
+ 0x6b1d, 0x41f8,
+ 0x6b1e, 0x3534,
+ 0x6b20, 0x02de,
+ 0x6b21, 0x03e3,
+ 0x6b23, 0x061a,
+ 0x6b25, 0x19c9,
+ 0x6b28, 0x1b3d,
+ 0x6b2c, 0x1ce6,
+ 0x6b2d, 0x1ce8,
+ 0x6b2f, 0x1ce7,
+ 0x6b31, 0x1ce9,
+ 0x6b32, 0x0ae7,
+ 0x6b33, 0x1f3c,
+ 0x6b34, 0x1cea,
+ 0x6b35, 0x41fb,
+ 0x6b36, 0x1f3b,
+ 0x6b37, 0x1f3d,
+ 0x6b39, 0x21b2,
+ 0x6b3a, 0x0c9c,
+ 0x6b3b, 0x21b3,
+ 0x6b3c, 0x21b5,
+ 0x6b3d, 0x0c9d,
+ 0x6b3e, 0x0c9b,
+ 0x6b3f, 0x21b4,
+ 0x6b41, 0x2447,
+ 0x6b42, 0x2445,
+ 0x6b43, 0x2444,
+ 0x6b45, 0x2443,
+ 0x6b46, 0x2442,
+ 0x6b47, 0x0e4a,
+ 0x6b48, 0x2446,
+ 0x6b49, 0x1001,
+ 0x6b4a, 0x26e2,
+ 0x6b4b, 0x26e4,
+ 0x6b4c, 0x1002,
+ 0x6b4d, 0x26e3,
+ 0x6b4e, 0x1185,
+ 0x6b50, 0x1184,
+ 0x6b51, 0x2924,
+ 0x6b52, 0x3f6e,
+ 0x6b54, 0x2b89,
+ 0x6b55, 0x2b88,
+ 0x6b56, 0x2b8a,
+ 0x6b57, 0x3aae,
+ 0x6b59, 0x12dc,
+ 0x6b5b, 0x2d8a,
+ 0x6b5c, 0x13f0,
+ 0x6b5e, 0x2f3f,
+ 0x6b5f, 0x14e4,
+ 0x6b60, 0x30a7,
+ 0x6b61, 0x16c7,
+ 0x6b62, 0x02df,
+ 0x6b63, 0x034d,
+ 0x6b64, 0x03e4,
+ 0x6b65, 0x04c9,
+ 0x6b66, 0x061b,
+ 0x6b6a, 0x0769,
+ 0x6b6d, 0x1ceb,
+ 0x6b6f, 0x4515,
+ 0x6b72, 0x0e4b,
+ 0x6b74, 0x41fc,
+ 0x6b76, 0x29a2,
+ 0x6b77, 0x12dd,
+ 0x6b78, 0x14e5,
+ 0x6b79, 0x02e0,
+ 0x6b7a, 0x44ee,
+ 0x6b7b, 0x03e5,
+ 0x6b7e, 0x19cb,
+ 0x6b7f, 0x061d,
+ 0x6b80, 0x19ca,
+ 0x6b81, 0x466b,
+ 0x6b82, 0x1b3e,
+ 0x6b83, 0x076a,
+ 0x6b84, 0x1b3f,
+ 0x6b86, 0x076b,
+ 0x6b88, 0x1ced,
+ 0x6b89, 0x0900,
+ 0x6b8a, 0x08ff,
+ 0x6b8c, 0x1f43,
+ 0x6b8d, 0x1f41,
+ 0x6b8f, 0x1f40,
+ 0x6b91, 0x1f3f,
+ 0x6b94, 0x21b6,
+ 0x6b95, 0x21b9,
+ 0x6b96, 0x0c9f,
+ 0x6b97, 0x21b7,
+ 0x6b98, 0x0c9e,
+ 0x6b99, 0x21b8,
+ 0x6b9b, 0x2448,
+ 0x6b9e, 0x26e5,
+ 0x6ba2, 0x2927,
+ 0x6ba3, 0x2926,
+ 0x6ba4, 0x1186,
+ 0x6ba5, 0x2925,
+ 0x6ba6, 0x2928,
+ 0x6ba7, 0x2b8b,
+ 0x6baa, 0x2b8c,
+ 0x6bad, 0x2d8b,
+ 0x6bae, 0x13f1,
+ 0x6baf, 0x14e6,
+ 0x6bb0, 0x30a8,
+ 0x6bb2, 0x1679,
+ 0x6bb3, 0x178a,
+ 0x6bb5, 0x076c,
+ 0x6bb6, 0x1b40,
+ 0x6bb7, 0x0901,
+ 0x6bba, 0x0ae8,
+ 0x6bbc, 0x0ca0,
+ 0x6bbd, 0x21ba,
+ 0x6bbf, 0x0e4d,
+ 0x6bc0, 0x0e4c,
+ 0x6bc1, 0x466c,
+ 0x6bc3, 0x26e8,
+ 0x6bc5, 0x1187,
+ 0x6bc7, 0x2b8f,
+ 0x6bc8, 0x2b8e,
+ 0x6bc9, 0x2f40,
+ 0x6bca, 0x3421,
+ 0x6bcb, 0x02e1,
+ 0x6bcc, 0x178b,
+ 0x6bcd, 0x034e,
+ 0x6bcf, 0x04ca,
+ 0x6bd0, 0x18ad,
+ 0x6bd2, 0x076d,
+ 0x6bd3, 0x0e4e,
+ 0x6bd4, 0x02e2,
+ 0x6bd6, 0x1b41,
+ 0x6bd7, 0x076e,
+ 0x6bd8, 0x1b42,
+ 0x6bda, 0x13f2,
+ 0x6bdb, 0x02e3,
+ 0x6bdc, 0x4207,
+ 0x6bde, 0x19cc,
+ 0x6be0, 0x1b43,
+ 0x6be1, 0x4205,
+ 0x6be2, 0x1cf2,
+ 0x6be3, 0x1cf1,
+ 0x6be4, 0x1cef,
+ 0x6be6, 0x1cee,
+ 0x6be7, 0x1cf3,
+ 0x6be8, 0x1cf0,
+ 0x6bea, 0x466d,
+ 0x6beb, 0x0ae9,
+ 0x6bef, 0x0ca1,
+ 0x6bf0, 0x21bb,
+ 0x6bf2, 0x21bc,
+ 0x6bf7, 0x244c,
+ 0x6bf9, 0x244b,
+ 0x6bfa, 0x3f79,
+ 0x6bfb, 0x2449,
+ 0x6bfd, 0x0e4f,
+ 0x6bfe, 0x26ea,
+ 0x6bff, 0x292b,
+ 0x6c00, 0x292a,
+ 0x6c01, 0x2929,
+ 0x6c02, 0x292c,
+ 0x6c03, 0x2b91,
+ 0x6c04, 0x2b90,
+ 0x6c05, 0x12de,
+ 0x6c06, 0x2b92,
+ 0x6c08, 0x13f3,
+ 0x6c09, 0x2d8c,
+ 0x6c0b, 0x2f41,
+ 0x6c0c, 0x30a9,
+ 0x6c0d, 0x3388,
+ 0x6c0f, 0x02e4,
+ 0x6c10, 0x0350,
+ 0x6c11, 0x034f,
+ 0x6c13, 0x061e,
+ 0x6c14, 0x178c,
+ 0x6c15, 0x17aa,
+ 0x6c16, 0x03e6,
+ 0x6c18, 0x1801,
+ 0x6c19, 0x18ae,
+ 0x6c1b, 0x061f,
+ 0x6c1c, 0x38ab,
+ 0x6c1d, 0x19cd,
+ 0x6c1f, 0x076f,
+ 0x6c20, 0x1b44,
+ 0x6c23, 0x0902,
+ 0x6c24, 0x0906,
+ 0x6c25, 0x1cf4,
+ 0x6c26, 0x0905,
+ 0x6c27, 0x0903,
+ 0x6c2a, 0x1f44,
+ 0x6c2b, 0x0aeb,
+ 0x6c2c, 0x0ca4,
+ 0x6c2e, 0x0ca2,
+ 0x6c30, 0x21be,
+ 0x6c31, 0x3f63,
+ 0x6c33, 0x1003,
+ 0x6c34, 0x02e5,
+ 0x6c35, 0x44ef,
+ 0x6c36, 0x17ab,
+ 0x6c37, 0x4208,
+ 0x6c38, 0x0351,
+ 0x6c39, 0x3e05,
+ 0x6c3a, 0x44f0,
+ 0x6c3b, 0x17ae,
+ 0x6c3d, 0x4381,
+ 0x6c3e, 0x0354,
+ 0x6c3f, 0x17ad,
+ 0x6c40, 0x0353,
+ 0x6c41, 0x0352,
+ 0x6c42, 0x04cb,
+ 0x6c43, 0x17ac,
+ 0x6c46, 0x1802,
+ 0x6c49, 0x408d,
+ 0x6c4a, 0x1806,
+ 0x6c4b, 0x1808,
+ 0x6c4d, 0x03f0,
+ 0x6c4f, 0x1805,
+ 0x6c50, 0x03ec,
+ 0x6c52, 0x1803,
+ 0x6c54, 0x1807,
+ 0x6c55, 0x03ed,
+ 0x6c57, 0x03e8,
+ 0x6c58, 0x3bba,
+ 0x6c59, 0x03e9,
+ 0x6c5a, 0x420c,
+ 0x6c5b, 0x03ef,
+ 0x6c5c, 0x1804,
+ 0x6c5d, 0x03e7,
+ 0x6c5e, 0x04cc,
+ 0x6c5f, 0x03ea,
+ 0x6c61, 0x03ee,
+ 0x6c65, 0x18c0,
+ 0x6c66, 0x18be,
+ 0x6c67, 0x18b1,
+ 0x6c68, 0x04d8,
+ 0x6c69, 0x18b8,
+ 0x6c6a, 0x04d3,
+ 0x6c6b, 0x18b2,
+ 0x6c6d, 0x18ba,
+ 0x6c6e, 0x40ca,
+ 0x6c6f, 0x18b7,
+ 0x6c70, 0x04d6,
+ 0x6c71, 0x18b6,
+ 0x6c72, 0x04dd,
+ 0x6c73, 0x18bf,
+ 0x6c74, 0x04df,
+ 0x6c75, 0x466e,
+ 0x6c76, 0x04e1,
+ 0x6c78, 0x18b0,
+ 0x6c79, 0x420e,
+ 0x6c7a, 0x04d4,
+ 0x6c7b, 0x18c1,
+ 0x6c7d, 0x04db,
+ 0x6c7e, 0x04de,
+ 0x6c7f, 0x37a6,
+ 0x6c80, 0x19e4,
+ 0x6c81, 0x04ce,
+ 0x6c82, 0x04e5,
+ 0x6c83, 0x04dc,
+ 0x6c84, 0x18b3,
+ 0x6c85, 0x04d1,
+ 0x6c86, 0x04e0,
+ 0x6c87, 0x18bb,
+ 0x6c88, 0x04cf,
+ 0x6c8a, 0x19e2,
+ 0x6c8b, 0x18b4,
+ 0x6c8c, 0x04d7,
+ 0x6c8d, 0x04e2,
+ 0x6c8e, 0x18c2,
+ 0x6c8f, 0x18b5,
+ 0x6c90, 0x04d5,
+ 0x6c92, 0x04da,
+ 0x6c93, 0x19ce,
+ 0x6c94, 0x04e3,
+ 0x6c95, 0x18bc,
+ 0x6c96, 0x04d9,
+ 0x6c98, 0x04e4,
+ 0x6c99, 0x04cd,
+ 0x6c9a, 0x18b9,
+ 0x6c9b, 0x04d2,
+ 0x6c9c, 0x18bd,
+ 0x6c9d, 0x19e3,
+ 0x6c9f, 0x3889,
+ 0x6ca2, 0x3d63,
+ 0x6caa, 0x466f,
+ 0x6cab, 0x062b,
+ 0x6cac, 0x063b,
+ 0x6cad, 0x19d5,
+ 0x6cae, 0x0632,
+ 0x6caf, 0x3cf6,
+ 0x6cb0, 0x19ea,
+ 0x6cb1, 0x0623,
+ 0x6cb2, 0x3ecc,
+ 0x6cb3, 0x0626,
+ 0x6cb4, 0x19e1,
+ 0x6cb6, 0x19d3,
+ 0x6cb7, 0x19d7,
+ 0x6cb8, 0x062e,
+ 0x6cb9, 0x0630,
+ 0x6cba, 0x19da,
+ 0x6cbb, 0x0637,
+ 0x6cbc, 0x0629,
+ 0x6cbd, 0x0627,
+ 0x6cbf, 0x0636,
+ 0x6cc0, 0x19e6,
+ 0x6cc1, 0x0631,
+ 0x6cc2, 0x19d9,
+ 0x6cc3, 0x19db,
+ 0x6cc4, 0x062f,
+ 0x6cc5, 0x0634,
+ 0x6cc6, 0x19dc,
+ 0x6cc7, 0x19e9,
+ 0x6cc9, 0x0770,
+ 0x6cca, 0x063a,
+ 0x6ccb, 0x4070,
+ 0x6ccc, 0x0624,
+ 0x6ccd, 0x19e8,
+ 0x6cce, 0x3f91,
+ 0x6ccf, 0x19ec,
+ 0x6cd0, 0x19d8,
+ 0x6cd1, 0x19ee,
+ 0x6cd2, 0x19df,
+ 0x6cd3, 0x062d,
+ 0x6cd4, 0x19d4,
+ 0x6cd5, 0x062c,
+ 0x6cd6, 0x063e,
+ 0x6cd7, 0x0633,
+ 0x6cd9, 0x19d2,
+ 0x6cda, 0x1b4e,
+ 0x6cdb, 0x0639,
+ 0x6cdc, 0x063d,
+ 0x6cdd, 0x19e0,
+ 0x6cde, 0x19e5,
+ 0x6cdf, 0x3d57,
+ 0x6ce0, 0x063f,
+ 0x6ce1, 0x0638,
+ 0x6ce2, 0x062a,
+ 0x6ce3, 0x0620,
+ 0x6ce5, 0x0625,
+ 0x6ce7, 0x19d6,
+ 0x6ce8, 0x0621,
+ 0x6ce9, 0x19ed,
+ 0x6cea, 0x3f8d,
+ 0x6ceb, 0x19d0,
+ 0x6cec, 0x19cf,
+ 0x6ced, 0x19dd,
+ 0x6cee, 0x19d1,
+ 0x6cef, 0x063c,
+ 0x6cf0, 0x0907,
+ 0x6cf1, 0x0635,
+ 0x6cf2, 0x19de,
+ 0x6cf3, 0x0622,
+ 0x6cf5, 0x077f,
+ 0x6cf9, 0x19eb,
+ 0x6d00, 0x1b55,
+ 0x6d01, 0x1b58,
+ 0x6d02, 0x4671,
+ 0x6d03, 0x1b5b,
+ 0x6d04, 0x1b50,
+ 0x6d05, 0x3a19,
+ 0x6d06, 0x4672,
+ 0x6d07, 0x1b5e,
+ 0x6d08, 0x1b61,
+ 0x6d09, 0x1b63,
+ 0x6d0a, 0x1b4d,
+ 0x6d0b, 0x0771,
+ 0x6d0c, 0x0776,
+ 0x6d0d, 0x1cf9,
+ 0x6d0e, 0x0786,
+ 0x6d0f, 0x1b5c,
+ 0x6d10, 0x1b64,
+ 0x6d11, 0x1b54,
+ 0x6d12, 0x1b4c,
+ 0x6d16, 0x1d14,
+ 0x6d17, 0x0779,
+ 0x6d18, 0x1b59,
+ 0x6d19, 0x1b51,
+ 0x6d1a, 0x1b53,
+ 0x6d1b, 0x077e,
+ 0x6d1d, 0x1b56,
+ 0x6d1e, 0x0778,
+ 0x6d1f, 0x1b49,
+ 0x6d20, 0x1b5f,
+ 0x6d22, 0x1b62,
+ 0x6d24, 0x3ac3,
+ 0x6d25, 0x0775,
+ 0x6d26, 0x4673,
+ 0x6d27, 0x0781,
+ 0x6d28, 0x1b46,
+ 0x6d29, 0x0783,
+ 0x6d2a, 0x0773,
+ 0x6d2b, 0x0787,
+ 0x6d2c, 0x1b60,
+ 0x6d2d, 0x1b48,
+ 0x6d2e, 0x0784,
+ 0x6d2f, 0x1d0e,
+ 0x6d30, 0x19e7,
+ 0x6d31, 0x0777,
+ 0x6d32, 0x0772,
+ 0x6d33, 0x1b4f,
+ 0x6d34, 0x1b47,
+ 0x6d35, 0x0785,
+ 0x6d36, 0x077d,
+ 0x6d37, 0x1b5a,
+ 0x6d38, 0x0782,
+ 0x6d39, 0x0780,
+ 0x6d3a, 0x1b52,
+ 0x6d3b, 0x077a,
+ 0x6d3c, 0x1b4a,
+ 0x6d3d, 0x077b,
+ 0x6d3f, 0x1b4b,
+ 0x6d40, 0x1b5d,
+ 0x6d41, 0x0774,
+ 0x6d42, 0x1b57,
+ 0x6d4e, 0x4558,
+ 0x6d57, 0x3cf3,
+ 0x6d58, 0x1cfc,
+ 0x6d59, 0x090f,
+ 0x6d5a, 0x0914,
+ 0x6d5b, 0x409c,
+ 0x6d5c, 0x4222,
+ 0x6d5e, 0x1d05,
+ 0x6d5f, 0x1d0b,
+ 0x6d60, 0x1d07,
+ 0x6d61, 0x1cfa,
+ 0x6d62, 0x1cfd,
+ 0x6d63, 0x1cf6,
+ 0x6d65, 0x091b,
+ 0x6d66, 0x090c,
+ 0x6d67, 0x1d06,
+ 0x6d68, 0x1d0f,
+ 0x6d69, 0x0916,
+ 0x6d6a, 0x0908,
+ 0x6d6c, 0x0911,
+ 0x6d6d, 0x1cfe,
+ 0x6d6e, 0x0913,
+ 0x6d6f, 0x1cff,
+ 0x6d70, 0x1d09,
+ 0x6d71, 0x40f5,
+ 0x6d72, 0x39d7,
+ 0x6d74, 0x0915,
+ 0x6d75, 0x1d18,
+ 0x6d76, 0x1cf8,
+ 0x6d77, 0x090e,
+ 0x6d78, 0x090d,
+ 0x6d79, 0x0919,
+ 0x6d7a, 0x1cf5,
+ 0x6d7b, 0x1d16,
+ 0x6d7c, 0x1d0a,
+ 0x6d7d, 0x1d17,
+ 0x6d7e, 0x1d11,
+ 0x6d7f, 0x1d03,
+ 0x6d80, 0x1d12,
+ 0x6d81, 0x4674,
+ 0x6d82, 0x1d0c,
+ 0x6d83, 0x1d15,
+ 0x6d84, 0x1d13,
+ 0x6d85, 0x091a,
+ 0x6d86, 0x1d04,
+ 0x6d87, 0x090b,
+ 0x6d88, 0x090a,
+ 0x6d89, 0x0912,
+ 0x6d8a, 0x0918,
+ 0x6d8b, 0x1d10,
+ 0x6d8c, 0x0917,
+ 0x6d8d, 0x1d01,
+ 0x6d8e, 0x0aec,
+ 0x6d8f, 0x3de8,
+ 0x6d90, 0x1d19,
+ 0x6d91, 0x1d00,
+ 0x6d92, 0x1cfb,
+ 0x6d93, 0x0910,
+ 0x6d94, 0x091c,
+ 0x6d95, 0x0909,
+ 0x6d96, 0x4221,
+ 0x6d97, 0x1d08,
+ 0x6d98, 0x1d0d,
+ 0x6da4, 0x4676,
+ 0x6da5, 0x3ab9,
+ 0x6daa, 0x0b0e,
+ 0x6dab, 0x1f46,
+ 0x6dac, 0x1f4a,
+ 0x6dae, 0x0afb,
+ 0x6daf, 0x0af9,
+ 0x6db1, 0x4677,
+ 0x6db2, 0x0af0,
+ 0x6db3, 0x1f48,
+ 0x6db4, 0x1f47,
+ 0x6db5, 0x0b04,
+ 0x6db7, 0x1f4d,
+ 0x6db8, 0x0afe,
+ 0x6db9, 0x3ffb,
+ 0x6dba, 0x1f5f,
+ 0x6dbb, 0x1f6b,
+ 0x6dbc, 0x0aed,
+ 0x6dbd, 0x1f5c,
+ 0x6dbe, 0x1f55,
+ 0x6dbf, 0x0b10,
+ 0x6dc0, 0x1f45,
+ 0x6dc2, 0x1f61,
+ 0x6dc4, 0x0b0d,
+ 0x6dc5, 0x0b01,
+ 0x6dc6, 0x0b0c,
+ 0x6dc7, 0x0af7,
+ 0x6dc8, 0x1f51,
+ 0x6dc9, 0x1f63,
+ 0x6dca, 0x1f5b,
+ 0x6dcb, 0x0af8,
+ 0x6dcc, 0x0af2,
+ 0x6dcd, 0x1f69,
+ 0x6dcf, 0x1f62,
+ 0x6dd0, 0x1f64,
+ 0x6dd1, 0x0afa,
+ 0x6dd2, 0x0b02,
+ 0x6dd3, 0x1f66,
+ 0x6dd4, 0x1f4f,
+ 0x6dd5, 0x1f60,
+ 0x6dd6, 0x1f54,
+ 0x6dd7, 0x1f68,
+ 0x6dd8, 0x0b07,
+ 0x6dd9, 0x0aef,
+ 0x6dda, 0x0b05,
+ 0x6ddb, 0x1f59,
+ 0x6ddc, 0x1f57,
+ 0x6dde, 0x0afc,
+ 0x6ddf, 0x1f53,
+ 0x6de0, 0x1f52,
+ 0x6de1, 0x0af1,
+ 0x6de2, 0x1f4c,
+ 0x6de3, 0x1f6a,
+ 0x6de4, 0x0af3,
+ 0x6de5, 0x1f56,
+ 0x6de6, 0x0b11,
+ 0x6de8, 0x0b0b,
+ 0x6de9, 0x1f4b,
+ 0x6dea, 0x0b08,
+ 0x6deb, 0x0b06,
+ 0x6dec, 0x0b0f,
+ 0x6ded, 0x1f5d,
+ 0x6dee, 0x0b0a,
+ 0x6def, 0x1d02,
+ 0x6df0, 0x1f5e,
+ 0x6df1, 0x0b09,
+ 0x6df2, 0x1f65,
+ 0x6df3, 0x0aee,
+ 0x6df4, 0x1f5a,
+ 0x6df5, 0x0b00,
+ 0x6df6, 0x1f4e,
+ 0x6df7, 0x0aff,
+ 0x6df9, 0x0afd,
+ 0x6dfa, 0x0af5,
+ 0x6dfb, 0x0af4,
+ 0x6dfc, 0x21bf,
+ 0x6dfd, 0x1f67,
+ 0x6e00, 0x1f50,
+ 0x6e02, 0x3cfa,
+ 0x6e03, 0x21d4,
+ 0x6e04, 0x3abe,
+ 0x6e05, 0x0af6,
+ 0x6e0a, 0x3ac1,
+ 0x6e0f, 0x3cf0,
+ 0x6e15, 0x4678,
+ 0x6e18, 0x4679,
+ 0x6e19, 0x0cc1,
+ 0x6e1a, 0x0b03,
+ 0x6e1b, 0x0caf,
+ 0x6e1c, 0x21ce,
+ 0x6e1d, 0x0cbd,
+ 0x6e1f, 0x21c2,
+ 0x6e20, 0x0cac,
+ 0x6e21, 0x0ca8,
+ 0x6e22, 0x21e0,
+ 0x6e23, 0x0cae,
+ 0x6e24, 0x0cb2,
+ 0x6e25, 0x0cad,
+ 0x6e26, 0x0cb6,
+ 0x6e27, 0x21e4,
+ 0x6e28, 0x21db,
+ 0x6e29, 0x467a,
+ 0x6e2a, 0x4302,
+ 0x6e2b, 0x21c9,
+ 0x6e2c, 0x0cbb,
+ 0x6e2d, 0x0cb5,
+ 0x6e2e, 0x21d5,
+ 0x6e2f, 0x0ca5,
+ 0x6e30, 0x21e1,
+ 0x6e31, 0x21da,
+ 0x6e32, 0x0ca9,
+ 0x6e33, 0x21cf,
+ 0x6e34, 0x0cb8,
+ 0x6e35, 0x21ec,
+ 0x6e38, 0x0ca6,
+ 0x6e39, 0x21df,
+ 0x6e3a, 0x0cba,
+ 0x6e3b, 0x21d3,
+ 0x6e3c, 0x21c5,
+ 0x6e3e, 0x0cbe,
+ 0x6e3f, 0x21ca,
+ 0x6e40, 0x21d1,
+ 0x6e41, 0x21cb,
+ 0x6e43, 0x0cbc,
+ 0x6e44, 0x0cc4,
+ 0x6e45, 0x21c7,
+ 0x6e46, 0x21c0,
+ 0x6e49, 0x21c3,
+ 0x6e4a, 0x0cab,
+ 0x6e4b, 0x21d0,
+ 0x6e4d, 0x0cb9,
+ 0x6e4e, 0x0cc2,
+ 0x6e4f, 0x4234,
+ 0x6e50, 0x41d1,
+ 0x6e51, 0x21d2,
+ 0x6e52, 0x21ea,
+ 0x6e53, 0x21e2,
+ 0x6e54, 0x0ca7,
+ 0x6e55, 0x21e8,
+ 0x6e56, 0x0cb3,
+ 0x6e58, 0x0cb1,
+ 0x6e59, 0x40e6,
+ 0x6e5a, 0x21ee,
+ 0x6e5b, 0x0cb0,
+ 0x6e5c, 0x21d8,
+ 0x6e5d, 0x21cc,
+ 0x6e5e, 0x21d6,
+ 0x6e5f, 0x0cc7,
+ 0x6e60, 0x21dc,
+ 0x6e61, 0x21d9,
+ 0x6e62, 0x21c8,
+ 0x6e63, 0x0cc3,
+ 0x6e64, 0x21e6,
+ 0x6e65, 0x21e3,
+ 0x6e66, 0x21eb,
+ 0x6e67, 0x0caa,
+ 0x6e68, 0x21d7,
+ 0x6e69, 0x0cc6,
+ 0x6e6b, 0x21de,
+ 0x6e6e, 0x0cb4,
+ 0x6e6f, 0x0cb7,
+ 0x6e71, 0x21dd,
+ 0x6e72, 0x0cc5,
+ 0x6e73, 0x21cd,
+ 0x6e74, 0x1f49,
+ 0x6e76, 0x39d3,
+ 0x6e77, 0x21e7,
+ 0x6e78, 0x21e5,
+ 0x6e79, 0x21e9,
+ 0x6e7c, 0x4223,
+ 0x6e86, 0x467b,
+ 0x6e88, 0x21c4,
+ 0x6e89, 0x0cc0,
+ 0x6e8b, 0x3bbf,
+ 0x6e8d, 0x246c,
+ 0x6e8e, 0x246b,
+ 0x6e8f, 0x2451,
+ 0x6e90, 0x0e55,
+ 0x6e92, 0x246a,
+ 0x6e93, 0x2454,
+ 0x6e96, 0x0e5f,
+ 0x6e97, 0x2473,
+ 0x6e98, 0x0e5a,
+ 0x6e99, 0x2469,
+ 0x6e9a, 0x4581,
+ 0x6e9b, 0x244e,
+ 0x6e9c, 0x0e60,
+ 0x6e9d, 0x0e56,
+ 0x6e9e, 0x245d,
+ 0x6e9f, 0x2453,
+ 0x6ea0, 0x2456,
+ 0x6ea1, 0x246e,
+ 0x6ea2, 0x0e50,
+ 0x6ea3, 0x2475,
+ 0x6ea4, 0x246d,
+ 0x6ea5, 0x0e59,
+ 0x6ea6, 0x2462,
+ 0x6ea7, 0x0e64,
+ 0x6eaa, 0x0e63,
+ 0x6eab, 0x0e5d,
+ 0x6eae, 0x2474,
+ 0x6eaf, 0x0e51,
+ 0x6eb0, 0x2460,
+ 0x6eb1, 0x2457,
+ 0x6eb2, 0x2464,
+ 0x6eb3, 0x2470,
+ 0x6eb4, 0x0e65,
+ 0x6eb5, 0x41fe,
+ 0x6eb6, 0x0e53,
+ 0x6eb7, 0x245f,
+ 0x6eb8, 0x3e0c,
+ 0x6eb9, 0x2458,
+ 0x6eba, 0x0e5c,
+ 0x6ebb, 0x467d,
+ 0x6ebc, 0x0e5b,
+ 0x6ebd, 0x245b,
+ 0x6ebe, 0x2465,
+ 0x6ebf, 0x246f,
+ 0x6ec0, 0x2452,
+ 0x6ec1, 0x245c,
+ 0x6ec2, 0x0e54,
+ 0x6ec3, 0x2466,
+ 0x6ec4, 0x0e61,
+ 0x6ec5, 0x0e58,
+ 0x6ec6, 0x2459,
+ 0x6ec7, 0x0e57,
+ 0x6ec8, 0x2450,
+ 0x6ec9, 0x245e,
+ 0x6eca, 0x2472,
+ 0x6ecb, 0x0cbf,
+ 0x6ecc, 0x101f,
+ 0x6ecd, 0x2461,
+ 0x6ece, 0x26eb,
+ 0x6ecf, 0x2463,
+ 0x6ed0, 0x2471,
+ 0x6ed1, 0x0e5e,
+ 0x6ed2, 0x245a,
+ 0x6ed3, 0x0e52,
+ 0x6ed4, 0x0e62,
+ 0x6ed5, 0x119a,
+ 0x6ed6, 0x244f,
+ 0x6ed8, 0x2468,
+ 0x6ed9, 0x4069,
+ 0x6eda, 0x467f,
+ 0x6edb, 0x402f,
+ 0x6edc, 0x2467,
+ 0x6edd, 0x4538,
+ 0x6ee2, 0x467e,
+ 0x6ee8, 0x4681,
+ 0x6eeb, 0x2707,
+ 0x6eec, 0x101c,
+ 0x6eed, 0x26fc,
+ 0x6eee, 0x2701,
+ 0x6eef, 0x1011,
+ 0x6ef1, 0x26ed,
+ 0x6ef2, 0x101e,
+ 0x6ef4, 0x1008,
+ 0x6ef5, 0x26ec,
+ 0x6ef6, 0x270d,
+ 0x6ef7, 0x1020,
+ 0x6ef8, 0x26f0,
+ 0x6ef9, 0x2700,
+ 0x6efa, 0x423b,
+ 0x6efb, 0x26f2,
+ 0x6efc, 0x2710,
+ 0x6efd, 0x270c,
+ 0x6efe, 0x1006,
+ 0x6eff, 0x1010,
+ 0x6f00, 0x2946,
+ 0x6f01, 0x101d,
+ 0x6f02, 0x100e,
+ 0x6f03, 0x26ee,
+ 0x6f04, 0x4224,
+ 0x6f05, 0x270b,
+ 0x6f06, 0x1012,
+ 0x6f07, 0x2708,
+ 0x6f08, 0x2715,
+ 0x6f09, 0x26f4,
+ 0x6f0a, 0x26fd,
+ 0x6f0b, 0x3aba,
+ 0x6f0c, 0x3cfb,
+ 0x6f0d, 0x2713,
+ 0x6f0e, 0x2709,
+ 0x6f0f, 0x100d,
+ 0x6f12, 0x26fb,
+ 0x6f13, 0x1007,
+ 0x6f14, 0x1005,
+ 0x6f15, 0x1017,
+ 0x6f16, 0x41a0,
+ 0x6f17, 0x46ce,
+ 0x6f18, 0x26f9,
+ 0x6f19, 0x26f6,
+ 0x6f1c, 0x270f,
+ 0x6f1e, 0x2714,
+ 0x6f1f, 0x2712,
+ 0x6f20, 0x100b,
+ 0x6f21, 0x2716,
+ 0x6f22, 0x100f,
+ 0x6f23, 0x1016,
+ 0x6f24, 0x4683,
+ 0x6f25, 0x26ef,
+ 0x6f26, 0x292e,
+ 0x6f27, 0x26f8,
+ 0x6f29, 0x1009,
+ 0x6f2a, 0x101b,
+ 0x6f2b, 0x1018,
+ 0x6f2c, 0x100c,
+ 0x6f2d, 0x2702,
+ 0x6f2e, 0x26f3,
+ 0x6f2f, 0x1019,
+ 0x6f30, 0x2704,
+ 0x6f31, 0x1013,
+ 0x6f32, 0x1015,
+ 0x6f33, 0x1004,
+ 0x6f34, 0x4684,
+ 0x6f35, 0x2706,
+ 0x6f36, 0x26fe,
+ 0x6f37, 0x26f1,
+ 0x6f38, 0x1014,
+ 0x6f39, 0x270e,
+ 0x6f3a, 0x2711,
+ 0x6f3b, 0x26fa,
+ 0x6f3c, 0x2705,
+ 0x6f3d, 0x4282,
+ 0x6f3e, 0x100a,
+ 0x6f3f, 0x1189,
+ 0x6f40, 0x2703,
+ 0x6f41, 0x292d,
+ 0x6f43, 0x270a,
+ 0x6f44, 0x4240,
+ 0x6f4e, 0x26f5,
+ 0x6f4f, 0x2937,
+ 0x6f50, 0x2941,
+ 0x6f51, 0x118c,
+ 0x6f52, 0x2940,
+ 0x6f53, 0x294c,
+ 0x6f54, 0x118e,
+ 0x6f55, 0x293e,
+ 0x6f56, 0x3e52,
+ 0x6f57, 0x2942,
+ 0x6f58, 0x1199,
+ 0x6f5a, 0x2939,
+ 0x6f5b, 0x1191,
+ 0x6f5c, 0x4241,
+ 0x6f5d, 0x2945,
+ 0x6f5e, 0x2b9a,
+ 0x6f5f, 0x119d,
+ 0x6f60, 0x119c,
+ 0x6f61, 0x2947,
+ 0x6f62, 0x2936,
+ 0x6f63, 0x2951,
+ 0x6f64, 0x1197,
+ 0x6f66, 0x118d,
+ 0x6f67, 0x294a,
+ 0x6f69, 0x294e,
+ 0x6f6a, 0x2953,
+ 0x6f6b, 0x2948,
+ 0x6f6c, 0x293c,
+ 0x6f6d, 0x1190,
+ 0x6f6e, 0x1193,
+ 0x6f6f, 0x119b,
+ 0x6f70, 0x1196,
+ 0x6f72, 0x293f,
+ 0x6f73, 0x26ff,
+ 0x6f74, 0x4243,
+ 0x6f76, 0x293b,
+ 0x6f77, 0x2952,
+ 0x6f78, 0x1192,
+ 0x6f79, 0x3bbe,
+ 0x6f7a, 0x1195,
+ 0x6f7b, 0x2954,
+ 0x6f7c, 0x118a,
+ 0x6f7d, 0x2949,
+ 0x6f7e, 0x292f,
+ 0x6f7f, 0x294f,
+ 0x6f80, 0x13fc,
+ 0x6f81, 0x4687,
+ 0x6f82, 0x293d,
+ 0x6f84, 0x118b,
+ 0x6f85, 0x2938,
+ 0x6f86, 0x118f,
+ 0x6f87, 0x2930,
+ 0x6f88, 0x101a,
+ 0x6f89, 0x2934,
+ 0x6f8a, 0x4195,
+ 0x6f8b, 0x294d,
+ 0x6f8c, 0x2935,
+ 0x6f8d, 0x2933,
+ 0x6f8e, 0x1194,
+ 0x6f90, 0x294b,
+ 0x6f92, 0x2932,
+ 0x6f93, 0x2944,
+ 0x6f94, 0x2943,
+ 0x6f95, 0x2950,
+ 0x6f96, 0x293a,
+ 0x6f97, 0x1198,
+ 0x6f9d, 0x4239,
+ 0x6f9e, 0x2b9d,
+ 0x6f9f, 0x4246,
+ 0x6fa0, 0x12eb,
+ 0x6fa1, 0x12e1,
+ 0x6fa2, 0x2ba9,
+ 0x6fa3, 0x2b95,
+ 0x6fa4, 0x12e3,
+ 0x6fa5, 0x2ba1,
+ 0x6fa6, 0x12ea,
+ 0x6fa7, 0x12e5,
+ 0x6fa8, 0x2b9f,
+ 0x6fa9, 0x2d8e,
+ 0x6faa, 0x2ba5,
+ 0x6fab, 0x2bab,
+ 0x6fac, 0x2ba4,
+ 0x6fad, 0x2b93,
+ 0x6fae, 0x2ba2,
+ 0x6faf, 0x2bad,
+ 0x6fb0, 0x2baf,
+ 0x6fb1, 0x12e0,
+ 0x6fb2, 0x2bae,
+ 0x6fb3, 0x12e6,
+ 0x6fb4, 0x12ec,
+ 0x6fb5, 0x3e27,
+ 0x6fb6, 0x12e9,
+ 0x6fb8, 0x2ba8,
+ 0x6fb9, 0x12e8,
+ 0x6fba, 0x2ba3,
+ 0x6fbb, 0x3bbb,
+ 0x6fbc, 0x2b97,
+ 0x6fbd, 0x2b9c,
+ 0x6fbe, 0x4688,
+ 0x6fbf, 0x2ba7,
+ 0x6fc0, 0x12e7,
+ 0x6fc1, 0x12e4,
+ 0x6fc2, 0x12df,
+ 0x6fc3, 0x12e2,
+ 0x6fc4, 0x2b9b,
+ 0x6fc6, 0x2931,
+ 0x6fc7, 0x2b96,
+ 0x6fc8, 0x2b99,
+ 0x6fc9, 0x2baa,
+ 0x6fca, 0x2b9e,
+ 0x6fcb, 0x2b94,
+ 0x6fcc, 0x2d8d,
+ 0x6fcd, 0x2bac,
+ 0x6fce, 0x2b98,
+ 0x6fcf, 0x2ba6,
+ 0x6fd3, 0x4248,
+ 0x6fd4, 0x2d90,
+ 0x6fd5, 0x1400,
+ 0x6fd8, 0x13f4,
+ 0x6fd9, 0x3c74,
+ 0x6fda, 0x3c73,
+ 0x6fdb, 0x13f8,
+ 0x6fdc, 0x2d92,
+ 0x6fdd, 0x2d98,
+ 0x6fde, 0x2d96,
+ 0x6fdf, 0x13f6,
+ 0x6fe1, 0x13fe,
+ 0x6fe2, 0x2d99,
+ 0x6fe3, 0x2d91,
+ 0x6fe4, 0x13f9,
+ 0x6fe6, 0x2d95,
+ 0x6fe7, 0x2d94,
+ 0x6fe8, 0x2d9a,
+ 0x6fe9, 0x13ff,
+ 0x6feb, 0x13fa,
+ 0x6fec, 0x13fd,
+ 0x6fed, 0x2d93,
+ 0x6fee, 0x1401,
+ 0x6fef, 0x13fb,
+ 0x6ff0, 0x1402,
+ 0x6ff1, 0x13f5,
+ 0x6ff2, 0x2d97,
+ 0x6ff4, 0x2d8f,
+ 0x6ff6, 0x38a5,
+ 0x6ff7, 0x2f4e,
+ 0x6ff8, 0x4237,
+ 0x6ffa, 0x14eb,
+ 0x6ffb, 0x2f4b,
+ 0x6ffc, 0x2f4d,
+ 0x6ffe, 0x14e9,
+ 0x6fff, 0x2f49,
+ 0x7000, 0x2f4a,
+ 0x7001, 0x2f45,
+ 0x7003, 0x46e2,
+ 0x7004, 0x2ba0,
+ 0x7005, 0x2f46,
+ 0x7006, 0x14ea,
+ 0x7007, 0x2f42,
+ 0x7009, 0x14e7,
+ 0x700a, 0x2f4f,
+ 0x700b, 0x14e8,
+ 0x700c, 0x2f43,
+ 0x700e, 0x2f48,
+ 0x700f, 0x14ed,
+ 0x7011, 0x14ec,
+ 0x7014, 0x2f47,
+ 0x7015, 0x158f,
+ 0x7016, 0x30ad,
+ 0x7017, 0x30b3,
+ 0x7018, 0x1590,
+ 0x7019, 0x30aa,
+ 0x701a, 0x158d,
+ 0x701b, 0x158a,
+ 0x701c, 0x30b5,
+ 0x701d, 0x158e,
+ 0x701e, 0x3c76,
+ 0x701f, 0x158b,
+ 0x7020, 0x30ac,
+ 0x7021, 0x30af,
+ 0x7024, 0x30b4,
+ 0x7026, 0x2f4c,
+ 0x7027, 0x30ab,
+ 0x7028, 0x158c,
+ 0x7029, 0x30b2,
+ 0x702a, 0x31ef,
+ 0x702b, 0x30ae,
+ 0x702c, 0x468e,
+ 0x702f, 0x31e6,
+ 0x7030, 0x161d,
+ 0x7031, 0x31e9,
+ 0x7032, 0x161e,
+ 0x7033, 0x31f2,
+ 0x7034, 0x31e8,
+ 0x7035, 0x31e5,
+ 0x7037, 0x31e7,
+ 0x7038, 0x31eb,
+ 0x7039, 0x31ee,
+ 0x703a, 0x31ed,
+ 0x703b, 0x31f1,
+ 0x703c, 0x31e4,
+ 0x703e, 0x161c,
+ 0x703f, 0x31ec,
+ 0x7040, 0x31f0,
+ 0x7041, 0x31f3,
+ 0x7042, 0x31ea,
+ 0x7043, 0x32d8,
+ 0x7045, 0x32dd,
+ 0x7048, 0x32db,
+ 0x704a, 0x32da,
+ 0x704b, 0x4254,
+ 0x704c, 0x167a,
+ 0x7050, 0x4690,
+ 0x7051, 0x16c8,
+ 0x7052, 0x338c,
+ 0x7054, 0x4691,
+ 0x7055, 0x3389,
+ 0x7058, 0x16c9,
+ 0x705a, 0x3423,
+ 0x705b, 0x3422,
+ 0x705c, 0x3852,
+ 0x705d, 0x348a,
+ 0x705e, 0x1722,
+ 0x705f, 0x3488,
+ 0x7060, 0x348b,
+ 0x7061, 0x3489,
+ 0x7062, 0x34d0,
+ 0x7063, 0x1744,
+ 0x7064, 0x1752,
+ 0x7065, 0x351c,
+ 0x7066, 0x3506,
+ 0x7067, 0x3cf5,
+ 0x7068, 0x351b,
+ 0x7069, 0x3547,
+ 0x706b, 0x02e6,
+ 0x706c, 0x44f1,
+ 0x706f, 0x4692,
+ 0x7070, 0x03f2,
+ 0x7071, 0x180a,
+ 0x7074, 0x18c3,
+ 0x7075, 0x38c7,
+ 0x7076, 0x04e6,
+ 0x7078, 0x04e9,
+ 0x7079, 0x4099,
+ 0x707a, 0x18c4,
+ 0x707c, 0x04e7,
+ 0x707e, 0x4255,
+ 0x707f, 0x4693,
+ 0x7081, 0x4959,
+ 0x7082, 0x19f7,
+ 0x7083, 0x19f9,
+ 0x7084, 0x19f4,
+ 0x7085, 0x19f1,
+ 0x7086, 0x19f3,
+ 0x7089, 0x43f9,
+ 0x708a, 0x0643,
+ 0x708b, 0x40cb,
+ 0x708e, 0x0641,
+ 0x708f, 0x46b3,
+ 0x7091, 0x19f5,
+ 0x7092, 0x0642,
+ 0x7093, 0x19f2,
+ 0x7094, 0x19ef,
+ 0x7095, 0x0640,
+ 0x7096, 0x19f6,
+ 0x7098, 0x19f0,
+ 0x7099, 0x0644,
+ 0x709a, 0x19f8,
+ 0x709f, 0x1b66,
+ 0x70a0, 0x4742,
+ 0x70a1, 0x1b6a,
+ 0x70a3, 0x3972,
+ 0x70a4, 0x0790,
+ 0x70a5, 0x3cb7,
+ 0x70a6, 0x3d53,
+ 0x70a7, 0x4256,
+ 0x70a9, 0x1b6d,
+ 0x70ab, 0x0788,
+ 0x70ac, 0x078b,
+ 0x70ad, 0x078d,
+ 0x70ae, 0x078f,
+ 0x70af, 0x078c,
+ 0x70b0, 0x1b69,
+ 0x70b1, 0x1b68,
+ 0x70b3, 0x078a,
+ 0x70b4, 0x1b6b,
+ 0x70b7, 0x1b65,
+ 0x70b8, 0x078e,
+ 0x70b9, 0x3d69,
+ 0x70ba, 0x0789,
+ 0x70bb, 0x4812,
+ 0x70bc, 0x4559,
+ 0x70bd, 0x4270,
+ 0x70be, 0x1b67,
+ 0x70c0, 0x4733,
+ 0x70c4, 0x3baa,
+ 0x70c5, 0x1d27,
+ 0x70c8, 0x0921,
+ 0x70ca, 0x091d,
+ 0x70cb, 0x1d1e,
+ 0x70cc, 0x4258,
+ 0x70cd, 0x1d26,
+ 0x70ce, 0x1d2b,
+ 0x70cf, 0x0922,
+ 0x70d0, 0x396d,
+ 0x70d1, 0x1d1c,
+ 0x70d2, 0x1d22,
+ 0x70d3, 0x1d1b,
+ 0x70d4, 0x1d25,
+ 0x70d5, 0x4259,
+ 0x70d7, 0x1d21,
+ 0x70d8, 0x091e,
+ 0x70d9, 0x0920,
+ 0x70da, 0x1d2a,
+ 0x70dc, 0x1d1a,
+ 0x70dd, 0x1d1d,
+ 0x70de, 0x1d23,
+ 0x70df, 0x425b,
+ 0x70e0, 0x1d24,
+ 0x70e1, 0x1d2c,
+ 0x70e2, 0x1d20,
+ 0x70e4, 0x091f,
+ 0x70ef, 0x0b16,
+ 0x70f0, 0x1f72,
+ 0x70f1, 0x3ac8,
+ 0x70f3, 0x1f74,
+ 0x70f4, 0x1f70,
+ 0x70f5, 0x4760,
+ 0x70f6, 0x1f7c,
+ 0x70f7, 0x1f6e,
+ 0x70f8, 0x1f7b,
+ 0x70f9, 0x0b12,
+ 0x70fa, 0x1f6c,
+ 0x70fb, 0x21f2,
+ 0x70fc, 0x1f76,
+ 0x70fd, 0x0b15,
+ 0x70fe, 0x3d0e,
+ 0x70ff, 0x1f77,
+ 0x7100, 0x1f7a,
+ 0x7102, 0x1f7e,
+ 0x7104, 0x1f73,
+ 0x7105, 0x3a23,
+ 0x7106, 0x1f78,
+ 0x7109, 0x0b13,
+ 0x710b, 0x1f7d,
+ 0x710c, 0x1f71,
+ 0x710d, 0x1f6d,
+ 0x710e, 0x1f7f,
+ 0x7110, 0x1f75,
+ 0x7113, 0x1f79,
+ 0x7117, 0x1f6f,
+ 0x7119, 0x0cc8,
+ 0x711b, 0x21fc,
+ 0x711c, 0x0ccf,
+ 0x711d, 0x3d47,
+ 0x711e, 0x21f0,
+ 0x711f, 0x21f9,
+ 0x7120, 0x21ef,
+ 0x7121, 0x0ccc,
+ 0x7122, 0x21f7,
+ 0x7123, 0x21f5,
+ 0x7125, 0x21f6,
+ 0x7126, 0x0cca,
+ 0x7128, 0x21fa,
+ 0x7129, 0x3ba9,
+ 0x712b, 0x4261,
+ 0x712c, 0x426a,
+ 0x712e, 0x21f3,
+ 0x712f, 0x21f1,
+ 0x7130, 0x0ccb,
+ 0x7131, 0x21f4,
+ 0x7132, 0x21f8,
+ 0x7133, 0x3d54,
+ 0x7134, 0x3c7e,
+ 0x7135, 0x376d,
+ 0x7136, 0x0ccd,
+ 0x713a, 0x21fb,
+ 0x713b, 0x3ac5,
+ 0x713e, 0x372e,
+ 0x7140, 0x4398,
+ 0x7141, 0x247b,
+ 0x7142, 0x2482,
+ 0x7143, 0x2484,
+ 0x7144, 0x248a,
+ 0x7145, 0x4262,
+ 0x7146, 0x0e72,
+ 0x7147, 0x2476,
+ 0x7149, 0x0e6a,
+ 0x714a, 0x4264,
+ 0x714b, 0x2485,
+ 0x714c, 0x0e6f,
+ 0x714d, 0x248b,
+ 0x714e, 0x0e66,
+ 0x714f, 0x4267,
+ 0x7150, 0x2488,
+ 0x7151, 0x4865,
+ 0x7152, 0x2478,
+ 0x7153, 0x2489,
+ 0x7154, 0x2477,
+ 0x7156, 0x0e74,
+ 0x7158, 0x2483,
+ 0x7159, 0x0e67,
+ 0x715a, 0x248c,
+ 0x715c, 0x0e6c,
+ 0x715d, 0x247c,
+ 0x715e, 0x0e71,
+ 0x715f, 0x2487,
+ 0x7160, 0x247a,
+ 0x7161, 0x2481,
+ 0x7162, 0x247d,
+ 0x7163, 0x2479,
+ 0x7164, 0x0e69,
+ 0x7165, 0x0e70,
+ 0x7166, 0x0e6e,
+ 0x7167, 0x0e6b,
+ 0x7168, 0x0e73,
+ 0x7169, 0x0e68,
+ 0x716a, 0x2480,
+ 0x716b, 0x3cc5,
+ 0x716c, 0x0e6d,
+ 0x716e, 0x0cce,
+ 0x7170, 0x2486,
+ 0x7171, 0x3dc0,
+ 0x7172, 0x247e,
+ 0x7173, 0x47e7,
+ 0x7175, 0x3ced,
+ 0x7176, 0x4000,
+ 0x7177, 0x3957,
+ 0x7178, 0x247f,
+ 0x717a, 0x4924,
+ 0x717b, 0x271e,
+ 0x717c, 0x3835,
+ 0x717d, 0x1023,
+ 0x717e, 0x3970,
+ 0x7180, 0x271a,
+ 0x7181, 0x2720,
+ 0x7182, 0x271c,
+ 0x7184, 0x1025,
+ 0x7185, 0x271b,
+ 0x7186, 0x271f,
+ 0x7187, 0x2717,
+ 0x7188, 0x4706,
+ 0x7189, 0x2719,
+ 0x718a, 0x1024,
+ 0x718c, 0x39ea,
+ 0x718e, 0x3d3b,
+ 0x718f, 0x271d,
+ 0x7190, 0x2718,
+ 0x7192, 0x1026,
+ 0x7194, 0x1021,
+ 0x7196, 0x425f,
+ 0x7197, 0x2721,
+ 0x7198, 0x481d,
+ 0x7199, 0x1022,
+ 0x719a, 0x295a,
+ 0x719b, 0x2957,
+ 0x719c, 0x2963,
+ 0x719d, 0x295d,
+ 0x719e, 0x295f,
+ 0x719f, 0x119e,
+ 0x71a0, 0x2959,
+ 0x71a1, 0x2961,
+ 0x71a2, 0x48c1,
+ 0x71a3, 0x3ec8,
+ 0x71a4, 0x2960,
+ 0x71a5, 0x295e,
+ 0x71a7, 0x2964,
+ 0x71a8, 0x11a1,
+ 0x71a9, 0x295b,
+ 0x71aa, 0x2962,
+ 0x71ac, 0x119f,
+ 0x71ad, 0x3e1d,
+ 0x71af, 0x2956,
+ 0x71b0, 0x2958,
+ 0x71b1, 0x11a0,
+ 0x71b2, 0x2955,
+ 0x71b3, 0x2965,
+ 0x71b4, 0x425e,
+ 0x71b5, 0x295c,
+ 0x71b7, 0x468b,
+ 0x71b8, 0x2bb3,
+ 0x71b9, 0x12f3,
+ 0x71ba, 0x426e,
+ 0x71bc, 0x2bbe,
+ 0x71bd, 0x2bbc,
+ 0x71be, 0x12ed,
+ 0x71bf, 0x2bb2,
+ 0x71c0, 0x2bb5,
+ 0x71c2, 0x2bb1,
+ 0x71c3, 0x12f7,
+ 0x71c5, 0x2bb0,
+ 0x71c6, 0x2bbf,
+ 0x71c7, 0x2bba,
+ 0x71c8, 0x12f1,
+ 0x71c9, 0x12ee,
+ 0x71ca, 0x2bb9,
+ 0x71cb, 0x2bb7,
+ 0x71ce, 0x12f4,
+ 0x71cf, 0x2bbb,
+ 0x71d0, 0x12ef,
+ 0x71d1, 0x373d,
+ 0x71d2, 0x12f0,
+ 0x71d4, 0x2bb8,
+ 0x71d5, 0x12f2,
+ 0x71d6, 0x2bb4,
+ 0x71d8, 0x2bbd,
+ 0x71d9, 0x12f5,
+ 0x71da, 0x2bc0,
+ 0x71dc, 0x12f6,
+ 0x71dd, 0x4078,
+ 0x71df, 0x1404,
+ 0x71e0, 0x140b,
+ 0x71e1, 0x2d9b,
+ 0x71e2, 0x2da1,
+ 0x71e4, 0x2d9f,
+ 0x71e5, 0x1407,
+ 0x71e6, 0x1406,
+ 0x71e7, 0x1403,
+ 0x71e8, 0x2d9d,
+ 0x71eb, 0x3c81,
+ 0x71ec, 0x1409,
+ 0x71ed, 0x1408,
+ 0x71ee, 0x1405,
+ 0x71f0, 0x2da0,
+ 0x71f1, 0x2d9c,
+ 0x71f2, 0x2d9e,
+ 0x71f4, 0x140a,
+ 0x71f5, 0x46ee,
+ 0x71f6, 0x3e9a,
+ 0x71f8, 0x14f1,
+ 0x71f9, 0x2f52,
+ 0x71fb, 0x14ee,
+ 0x71fd, 0x2f54,
+ 0x71fe, 0x14f0,
+ 0x71ff, 0x2f51,
+ 0x7201, 0x2f50,
+ 0x7202, 0x30b9,
+ 0x7203, 0x2f53,
+ 0x7205, 0x30ba,
+ 0x7206, 0x1591,
+ 0x7207, 0x30b8,
+ 0x7209, 0x3dbb,
+ 0x720a, 0x30b7,
+ 0x720c, 0x30b6,
+ 0x720d, 0x1592,
+ 0x720e, 0x4271,
+ 0x720f, 0x39fc,
+ 0x7210, 0x161f,
+ 0x7213, 0x31f4,
+ 0x7215, 0x4273,
+ 0x7216, 0x3953,
+ 0x7217, 0x3969,
+ 0x7219, 0x32e1,
+ 0x721a, 0x32e0,
+ 0x721b, 0x167b,
+ 0x721d, 0x32df,
+ 0x721e, 0x338d,
+ 0x7222, 0x3424,
+ 0x7223, 0x348c,
+ 0x7224, 0x4276,
+ 0x7226, 0x34d1,
+ 0x7227, 0x3535,
+ 0x7228, 0x1766,
+ 0x7229, 0x3549,
+ 0x722a, 0x02e7,
+ 0x722b, 0x44f2,
+ 0x722c, 0x0645,
+ 0x722e, 0x4279,
+ 0x7230, 0x0791,
+ 0x7235, 0x140c,
+ 0x7236, 0x02e8,
+ 0x7238, 0x0647,
+ 0x7239, 0x0923,
+ 0x723a, 0x0e75,
+ 0x723b, 0x02e9,
+ 0x723d, 0x0b17,
+ 0x723e, 0x1027,
+ 0x723f, 0x178d,
+ 0x7240, 0x427a,
+ 0x7241, 0x1b6e,
+ 0x7242, 0x1d2d,
+ 0x7244, 0x2722,
+ 0x7246, 0x140d,
+ 0x7247, 0x02ea,
+ 0x7248, 0x0648,
+ 0x7249, 0x1b6f,
+ 0x724b, 0x21fd,
+ 0x724c, 0x0cd0,
+ 0x724f, 0x248d,
+ 0x7250, 0x3ac9,
+ 0x7252, 0x0e76,
+ 0x7253, 0x2723,
+ 0x7255, 0x427d,
+ 0x7256, 0x11a2,
+ 0x7257, 0x427e,
+ 0x7258, 0x1593,
+ 0x7259, 0x02eb,
+ 0x725a, 0x21fe,
+ 0x725b, 0x02ec,
+ 0x725c, 0x465a,
+ 0x725d, 0x03f4,
+ 0x725e, 0x180b,
+ 0x725f, 0x03f3,
+ 0x7260, 0x04ec,
+ 0x7261, 0x04eb,
+ 0x7262, 0x04ea,
+ 0x7263, 0x18c5,
+ 0x7266, 0x3ebb,
+ 0x7267, 0x0649,
+ 0x7269, 0x064a,
+ 0x726a, 0x19fa,
+ 0x726c, 0x1b71,
+ 0x726e, 0x1b74,
+ 0x726f, 0x0793,
+ 0x7270, 0x1b72,
+ 0x7272, 0x0792,
+ 0x7273, 0x1b73,
+ 0x7274, 0x0794,
+ 0x7276, 0x1d30,
+ 0x7277, 0x1d2f,
+ 0x7278, 0x1d2e,
+ 0x7279, 0x0924,
+ 0x727b, 0x1f81,
+ 0x727d, 0x0b18,
+ 0x727e, 0x1f80,
+ 0x727f, 0x1f83,
+ 0x7280, 0x0cd2,
+ 0x7281, 0x0b19,
+ 0x7282, 0x4283,
+ 0x7284, 0x0cd1,
+ 0x7285, 0x2202,
+ 0x7286, 0x2201,
+ 0x7287, 0x3aca,
+ 0x7288, 0x21ff,
+ 0x728b, 0x2203,
+ 0x728c, 0x248f,
+ 0x728d, 0x248e,
+ 0x728e, 0x2492,
+ 0x728f, 0x43c9,
+ 0x7290, 0x2491,
+ 0x7291, 0x2490,
+ 0x7292, 0x1028,
+ 0x7293, 0x2726,
+ 0x7294, 0x3acb,
+ 0x7295, 0x2725,
+ 0x7296, 0x1029,
+ 0x7297, 0x2724,
+ 0x7298, 0x2966,
+ 0x729a, 0x2967,
+ 0x729b, 0x11a3,
+ 0x729d, 0x2bc2,
+ 0x729f, 0x473a,
+ 0x72a1, 0x30bf,
+ 0x72a2, 0x1594,
+ 0x72a3, 0x30be,
+ 0x72a4, 0x30bd,
+ 0x72a5, 0x30bb,
+ 0x72a7, 0x167c,
+ 0x72a8, 0x31f6,
+ 0x72a9, 0x338f,
+ 0x72aa, 0x34d2,
+ 0x72ac, 0x02ed,
+ 0x72ad, 0x44f4,
+ 0x72ae, 0x17af,
+ 0x72af, 0x0355,
+ 0x72b0, 0x17b0,
+ 0x72b2, 0x3fb6,
+ 0x72b4, 0x180c,
+ 0x72ba, 0x18cb,
+ 0x72bd, 0x18c7,
+ 0x72bf, 0x18c6,
+ 0x72c0, 0x064b,
+ 0x72c1, 0x18ca,
+ 0x72c2, 0x04ee,
+ 0x72c3, 0x18c8,
+ 0x72c4, 0x04ed,
+ 0x72c5, 0x18cc,
+ 0x72c6, 0x18c9,
+ 0x72c9, 0x19fe,
+ 0x72ca, 0x1b75,
+ 0x72cb, 0x19fc,
+ 0x72cc, 0x1a03,
+ 0x72cd, 0x43ca,
+ 0x72ce, 0x064c,
+ 0x72d0, 0x064f,
+ 0x72d1, 0x1a04,
+ 0x72d2, 0x1a00,
+ 0x72d4, 0x1a01,
+ 0x72d6, 0x19fb,
+ 0x72d7, 0x064e,
+ 0x72d8, 0x19fd,
+ 0x72d9, 0x064d,
+ 0x72da, 0x1a02,
+ 0x72dc, 0x19ff,
+ 0x72df, 0x1b79,
+ 0x72e0, 0x0796,
+ 0x72e2, 0x3f97,
+ 0x72e3, 0x1b7c,
+ 0x72e4, 0x1b76,
+ 0x72e6, 0x1b7b,
+ 0x72e8, 0x1b77,
+ 0x72e9, 0x0795,
+ 0x72ea, 0x1b7a,
+ 0x72eb, 0x1b78,
+ 0x72f3, 0x1d36,
+ 0x72f4, 0x1d33,
+ 0x72f6, 0x1d35,
+ 0x72f7, 0x0929,
+ 0x72f8, 0x0928,
+ 0x72f9, 0x0926,
+ 0x72fa, 0x1d32,
+ 0x72fb, 0x1d37,
+ 0x72fc, 0x0925,
+ 0x72fd, 0x0927,
+ 0x72fe, 0x1d34,
+ 0x72ff, 0x1f8b,
+ 0x7300, 0x1d31,
+ 0x7301, 0x1d38,
+ 0x7302, 0x3f9a,
+ 0x7304, 0x3eb5,
+ 0x7307, 0x1f86,
+ 0x7308, 0x1f8a,
+ 0x730a, 0x1f89,
+ 0x730b, 0x2205,
+ 0x730c, 0x2210,
+ 0x730f, 0x1f8c,
+ 0x7310, 0x46ea,
+ 0x7311, 0x1f87,
+ 0x7312, 0x2204,
+ 0x7313, 0x0b1d,
+ 0x7316, 0x0b1c,
+ 0x7317, 0x1f85,
+ 0x7318, 0x1f88,
+ 0x7319, 0x0b1e,
+ 0x731b, 0x0b1b,
+ 0x731c, 0x0b1a,
+ 0x731d, 0x1f84,
+ 0x731e, 0x1f8d,
+ 0x7322, 0x2207,
+ 0x7323, 0x220e,
+ 0x7325, 0x0cd4,
+ 0x7326, 0x220d,
+ 0x7327, 0x220a,
+ 0x7328, 0x428a,
+ 0x7329, 0x0cd6,
+ 0x732a, 0x3d70,
+ 0x732b, 0x4285,
+ 0x732c, 0x3fb2,
+ 0x732d, 0x220c,
+ 0x732e, 0x428b,
+ 0x7330, 0x2206,
+ 0x7331, 0x2208,
+ 0x7332, 0x220b,
+ 0x7333, 0x2209,
+ 0x7334, 0x0cd5,
+ 0x7335, 0x220f,
+ 0x7336, 0x0cd3,
+ 0x7337, 0x0e77,
+ 0x7338, 0x46eb,
+ 0x7339, 0x43cc,
+ 0x733a, 0x2496,
+ 0x733b, 0x2495,
+ 0x733c, 0x2493,
+ 0x733e, 0x0e7a,
+ 0x733f, 0x0e79,
+ 0x7340, 0x2497,
+ 0x7341, 0x46ec,
+ 0x7342, 0x2494,
+ 0x7343, 0x2727,
+ 0x7344, 0x102a,
+ 0x7345, 0x0e78,
+ 0x7348, 0x43fa,
+ 0x7349, 0x2499,
+ 0x734a, 0x2498,
+ 0x734c, 0x272a,
+ 0x734d, 0x2728,
+ 0x734e, 0x11a4,
+ 0x734f, 0x3f51,
+ 0x7350, 0x102b,
+ 0x7351, 0x2729,
+ 0x7352, 0x2969,
+ 0x7357, 0x11a5,
+ 0x7358, 0x2968,
+ 0x7359, 0x2971,
+ 0x735a, 0x2970,
+ 0x735b, 0x296e,
+ 0x735d, 0x296d,
+ 0x735e, 0x296a,
+ 0x7361, 0x296f,
+ 0x7362, 0x2972,
+ 0x7365, 0x2bc8,
+ 0x7366, 0x2bc5,
+ 0x7368, 0x12f9,
+ 0x7369, 0x2bc4,
+ 0x736a, 0x2bca,
+ 0x736b, 0x2bc9,
+ 0x736c, 0x2bc7,
+ 0x736e, 0x2da3,
+ 0x7370, 0x140e,
+ 0x7371, 0x3f98,
+ 0x7372, 0x140f,
+ 0x7373, 0x2da2,
+ 0x7374, 0x3ed4,
+ 0x7375, 0x14f3,
+ 0x7376, 0x2f55,
+ 0x7377, 0x14f2,
+ 0x7378, 0x1595,
+ 0x737a, 0x1596,
+ 0x737b, 0x1620,
+ 0x737c, 0x31f8,
+ 0x737d, 0x31f7,
+ 0x737e, 0x32e2,
+ 0x737f, 0x3390,
+ 0x7380, 0x16ca,
+ 0x7381, 0x3426,
+ 0x7382, 0x3425,
+ 0x7383, 0x3427,
+ 0x7384, 0x0356,
+ 0x7385, 0x1b7d,
+ 0x7386, 0x092a,
+ 0x7387, 0x0b1f,
+ 0x7388, 0x1f8e,
+ 0x7389, 0x0357,
+ 0x738a, 0x17b1,
+ 0x738b, 0x02ee,
+ 0x738e, 0x180e,
+ 0x738f, 0x46e5,
+ 0x7392, 0x18d1,
+ 0x7393, 0x18cf,
+ 0x7395, 0x18cd,
+ 0x7396, 0x04ef,
+ 0x7397, 0x18ce,
+ 0x7398, 0x39f6,
+ 0x739c, 0x408a,
+ 0x739d, 0x1a0c,
+ 0x739e, 0x395b,
+ 0x739f, 0x0652,
+ 0x73a0, 0x1a0a,
+ 0x73a1, 0x1a06,
+ 0x73a2, 0x1a09,
+ 0x73a4, 0x1a05,
+ 0x73a5, 0x0654,
+ 0x73a6, 0x1a08,
+ 0x73a7, 0x4087,
+ 0x73a8, 0x0651,
+ 0x73a9, 0x0650,
+ 0x73aa, 0x428d,
+ 0x73ab, 0x0653,
+ 0x73ac, 0x1a0b,
+ 0x73ad, 0x1a07,
+ 0x73b2, 0x079b,
+ 0x73b3, 0x079e,
+ 0x73b4, 0x1b85,
+ 0x73b5, 0x1b84,
+ 0x73b6, 0x1b83,
+ 0x73b7, 0x0798,
+ 0x73b8, 0x1b8c,
+ 0x73b9, 0x1b82,
+ 0x73bb, 0x079a,
+ 0x73bc, 0x1d3d,
+ 0x73be, 0x1b89,
+ 0x73bf, 0x1b87,
+ 0x73c0, 0x079d,
+ 0x73c2, 0x1b7f,
+ 0x73c3, 0x1b8a,
+ 0x73c5, 0x1b81,
+ 0x73c6, 0x1b8b,
+ 0x73c7, 0x1b88,
+ 0x73c8, 0x1b80,
+ 0x73c9, 0x4290,
+ 0x73ca, 0x0799,
+ 0x73cb, 0x1b8d,
+ 0x73cc, 0x1b7e,
+ 0x73cd, 0x079c,
+ 0x73ce, 0x411b,
+ 0x73cf, 0x428c,
+ 0x73d0, 0x3b17,
+ 0x73d2, 0x1d42,
+ 0x73d3, 0x1d39,
+ 0x73d4, 0x1d44,
+ 0x73d5, 0x4073,
+ 0x73d6, 0x1d3c,
+ 0x73d7, 0x1d47,
+ 0x73d9, 0x1d3a,
+ 0x73da, 0x1d46,
+ 0x73db, 0x1d43,
+ 0x73dc, 0x1d41,
+ 0x73dd, 0x1d45,
+ 0x73de, 0x0930,
+ 0x73e0, 0x092e,
+ 0x73e1, 0x46f0,
+ 0x73e2, 0x3ca3,
+ 0x73e3, 0x1d3f,
+ 0x73e4, 0x42a5,
+ 0x73e5, 0x1d3b,
+ 0x73e6, 0x3cba,
+ 0x73e7, 0x1d3e,
+ 0x73e8, 0x1d49,
+ 0x73e9, 0x1d40,
+ 0x73ea, 0x092f,
+ 0x73eb, 0x1b86,
+ 0x73ed, 0x092b,
+ 0x73ee, 0x092d,
+ 0x73ef, 0x4011,
+ 0x73f3, 0x3cab,
+ 0x73f4, 0x1f9c,
+ 0x73f5, 0x1f91,
+ 0x73f6, 0x1f8f,
+ 0x73f7, 0x429a,
+ 0x73f8, 0x1f90,
+ 0x73f9, 0x3bf9,
+ 0x73fa, 0x1f97,
+ 0x73fb, 0x3cac,
+ 0x73fc, 0x1f98,
+ 0x73fd, 0x1f94,
+ 0x73fe, 0x0b24,
+ 0x73ff, 0x1f99,
+ 0x7400, 0x1f96,
+ 0x7401, 0x1f93,
+ 0x7403, 0x0b22,
+ 0x7404, 0x1f92,
+ 0x7405, 0x0b20,
+ 0x7406, 0x0b23,
+ 0x7407, 0x1f95,
+ 0x7408, 0x1f9d,
+ 0x7409, 0x092c,
+ 0x740a, 0x0b21,
+ 0x740b, 0x1f9b,
+ 0x740c, 0x1f9a,
+ 0x740d, 0x0b25,
+ 0x7411, 0x456c,
+ 0x7412, 0x3be6,
+ 0x7414, 0x39f4,
+ 0x7415, 0x429b,
+ 0x7416, 0x2215,
+ 0x7417, 0x40ad,
+ 0x7419, 0x46f3,
+ 0x741a, 0x2216,
+ 0x741b, 0x0ce0,
+ 0x741c, 0x38dd,
+ 0x741d, 0x221c,
+ 0x741e, 0x46f4,
+ 0x7420, 0x221e,
+ 0x7421, 0x2217,
+ 0x7422, 0x0cda,
+ 0x7423, 0x221b,
+ 0x7424, 0x221a,
+ 0x7425, 0x0cdb,
+ 0x7426, 0x0ce1,
+ 0x7428, 0x0ce2,
+ 0x7429, 0x221d,
+ 0x742a, 0x0cd8,
+ 0x742b, 0x2214,
+ 0x742c, 0x2212,
+ 0x742d, 0x2218,
+ 0x742e, 0x2211,
+ 0x742f, 0x0cdf,
+ 0x7430, 0x2213,
+ 0x7431, 0x2219,
+ 0x7432, 0x221f,
+ 0x7433, 0x0cd9,
+ 0x7434, 0x0cde,
+ 0x7435, 0x0cdc,
+ 0x7437, 0x3ae1,
+ 0x7438, 0x3b09,
+ 0x7439, 0x429e,
+ 0x743a, 0x0cd7,
+ 0x743c, 0x3adf,
+ 0x743f, 0x0e81,
+ 0x7440, 0x24a0,
+ 0x7441, 0x0e80,
+ 0x7442, 0x24a4,
+ 0x7443, 0x3a1a,
+ 0x7444, 0x249a,
+ 0x7445, 0x3bd7,
+ 0x7446, 0x24a5,
+ 0x7447, 0x42a4,
+ 0x7448, 0x3cb5,
+ 0x7449, 0x4291,
+ 0x744a, 0x249b,
+ 0x744d, 0x24a6,
+ 0x744e, 0x24a3,
+ 0x744f, 0x24a1,
+ 0x7451, 0x249e,
+ 0x7452, 0x249d,
+ 0x7453, 0x4231,
+ 0x7454, 0x24a7,
+ 0x7455, 0x0e7d,
+ 0x7456, 0x39f5,
+ 0x7457, 0x249f,
+ 0x7459, 0x0e82,
+ 0x745a, 0x0e7c,
+ 0x745b, 0x0e83,
+ 0x745d, 0x42c6,
+ 0x745e, 0x0e7f,
+ 0x745f, 0x0e7e,
+ 0x7460, 0x42a2,
+ 0x7462, 0x272b,
+ 0x7463, 0x102d,
+ 0x7464, 0x102c,
+ 0x7465, 0x4101,
+ 0x7467, 0x2730,
+ 0x7468, 0x3aee,
+ 0x7469, 0x11a6,
+ 0x746a, 0x102e,
+ 0x746b, 0x3be7,
+ 0x746c, 0x42a8,
+ 0x746d, 0x1030,
+ 0x746e, 0x2731,
+ 0x746f, 0x0e7b,
+ 0x7470, 0x102f,
+ 0x7471, 0x272d,
+ 0x7472, 0x272f,
+ 0x7473, 0x272c,
+ 0x7474, 0x42a9,
+ 0x7475, 0x272e,
+ 0x7476, 0x42a6,
+ 0x7479, 0x297c,
+ 0x747a, 0x3ad1,
+ 0x747c, 0x297b,
+ 0x747d, 0x2978,
+ 0x747e, 0x11a9,
+ 0x747f, 0x2bcb,
+ 0x7480, 0x11aa,
+ 0x7481, 0x2977,
+ 0x7482, 0x42ac,
+ 0x7483, 0x11a8,
+ 0x7485, 0x2979,
+ 0x7486, 0x2976,
+ 0x7487, 0x2973,
+ 0x7488, 0x297a,
+ 0x7489, 0x2974,
+ 0x748b, 0x11a7,
+ 0x748c, 0x3a21,
+ 0x748d, 0x469d,
+ 0x7490, 0x2da8,
+ 0x7492, 0x2bcf,
+ 0x7494, 0x2bce,
+ 0x7495, 0x2bd0,
+ 0x7497, 0x2da5,
+ 0x7498, 0x12fc,
+ 0x7499, 0x39f3,
+ 0x749a, 0x2bcc,
+ 0x749b, 0x3b0a,
+ 0x749c, 0x12fa,
+ 0x749e, 0x12fe,
+ 0x749f, 0x12fd,
+ 0x74a0, 0x2bcd,
+ 0x74a1, 0x2bd1,
+ 0x74a3, 0x12fb,
+ 0x74a4, 0x4170,
+ 0x74a5, 0x2dac,
+ 0x74a6, 0x1412,
+ 0x74a7, 0x14f4,
+ 0x74a8, 0x1413,
+ 0x74a9, 0x1410,
+ 0x74aa, 0x2da9,
+ 0x74ab, 0x2da7,
+ 0x74ad, 0x2daa,
+ 0x74af, 0x2dad,
+ 0x74b0, 0x1411,
+ 0x74b1, 0x2dab,
+ 0x74b2, 0x2da6,
+ 0x74b4, 0x3ca5,
+ 0x74b5, 0x2f58,
+ 0x74b6, 0x2f5b,
+ 0x74b7, 0x30c2,
+ 0x74b8, 0x2f56,
+ 0x74ba, 0x31f9,
+ 0x74bb, 0x2f5c,
+ 0x74bd, 0x1597,
+ 0x74be, 0x2f5a,
+ 0x74bf, 0x14f5,
+ 0x74c0, 0x2f57,
+ 0x74c1, 0x2f59,
+ 0x74c2, 0x2f5d,
+ 0x74c3, 0x30c3,
+ 0x74c5, 0x30c1,
+ 0x74c8, 0x42b5,
+ 0x74ca, 0x1598,
+ 0x74cb, 0x30c0,
+ 0x74cc, 0x3ade,
+ 0x74cf, 0x1621,
+ 0x74d0, 0x3a9b,
+ 0x74d3, 0x46fa,
+ 0x74d4, 0x167e,
+ 0x74d5, 0x3392,
+ 0x74d6, 0x167d,
+ 0x74d7, 0x3394,
+ 0x74d8, 0x3391,
+ 0x74d9, 0x3393,
+ 0x74da, 0x16fe,
+ 0x74db, 0x348d,
+ 0x74dc, 0x0358,
+ 0x74dd, 0x1a0d,
+ 0x74de, 0x1d4a,
+ 0x74e0, 0x0b26,
+ 0x74e1, 0x24a8,
+ 0x74e2, 0x12ff,
+ 0x74e3, 0x1599,
+ 0x74e4, 0x16cb,
+ 0x74e5, 0x348e,
+ 0x74e6, 0x0359,
+ 0x74e7, 0x3ffe,
+ 0x74e8, 0x1a0e,
+ 0x74e9, 0x0120,
+ 0x74ec, 0x1b8e,
+ 0x74ee, 0x1b8f,
+ 0x74f0, 0x3fe6,
+ 0x74f1, 0x3f9b,
+ 0x74f2, 0x3fdf,
+ 0x74f4, 0x1d4c,
+ 0x74f6, 0x0b27,
+ 0x74f8, 0x3ff4,
+ 0x74fb, 0x2220,
+ 0x74fd, 0x24ab,
+ 0x74fe, 0x24aa,
+ 0x74ff, 0x24a9,
+ 0x7500, 0x2732,
+ 0x7502, 0x2733,
+ 0x7504, 0x1031,
+ 0x7505, 0x3fde,
+ 0x7507, 0x297e,
+ 0x7508, 0x297d,
+ 0x750b, 0x2bd2,
+ 0x750c, 0x1300,
+ 0x750e, 0x42b7,
+ 0x750f, 0x2db1,
+ 0x7510, 0x2dae,
+ 0x7513, 0x2f5f,
+ 0x7514, 0x2f5e,
+ 0x7515, 0x14f6,
+ 0x7516, 0x30c4,
+ 0x7517, 0x32e3,
+ 0x7518, 0x035a,
+ 0x7519, 0x4583,
+ 0x751a, 0x079f,
+ 0x751c, 0x0b29,
+ 0x751d, 0x24ac,
+ 0x751e, 0x42b8,
+ 0x751f, 0x035b,
+ 0x7521, 0x1d4e,
+ 0x7522, 0x0b2a,
+ 0x7525, 0x0ce3,
+ 0x7528, 0x035c,
+ 0x752a, 0x180f,
+ 0x752b, 0x04f1,
+ 0x752c, 0x04f0,
+ 0x752d, 0x07a0,
+ 0x752e, 0x1b90,
+ 0x752f, 0x2221,
+ 0x7530, 0x035e,
+ 0x7534, 0x3e87,
+ 0x7535, 0x455a,
+ 0x7537, 0x04f2,
+ 0x7539, 0x18d3,
+ 0x753a, 0x18d2,
+ 0x753b, 0x3dfb,
+ 0x753d, 0x0655,
+ 0x753e, 0x1a11,
+ 0x753f, 0x1a0f,
+ 0x7542, 0x43cd,
+ 0x7546, 0x3f40,
+ 0x7547, 0x1b91,
+ 0x754a, 0x42bf,
+ 0x754b, 0x07a4,
+ 0x754c, 0x07a2,
+ 0x754d, 0x42be,
+ 0x754e, 0x07a3,
+ 0x754f, 0x07a1,
+ 0x7551, 0x3cfe,
+ 0x7553, 0x3feb,
+ 0x7554, 0x0931,
+ 0x7555, 0x3aea,
+ 0x7559, 0x0935,
+ 0x755a, 0x0934,
+ 0x755b, 0x1d4f,
+ 0x755c, 0x0933,
+ 0x755d, 0x0932,
+ 0x755f, 0x1d50,
+ 0x7560, 0x3d71,
+ 0x7562, 0x0b2d,
+ 0x7563, 0x1f9f,
+ 0x7564, 0x1f9e,
+ 0x7565, 0x0b2b,
+ 0x7567, 0x42c0,
+ 0x756a, 0x0ce6,
+ 0x756b, 0x0ce5,
+ 0x756c, 0x2223,
+ 0x756d, 0x46fd,
+ 0x756e, 0x42c1,
+ 0x756f, 0x2222,
+ 0x7570, 0x0b2e,
+ 0x7572, 0x46fe,
+ 0x7576, 0x0e85,
+ 0x7577, 0x24ae,
+ 0x7578, 0x0e86,
+ 0x7579, 0x24ad,
+ 0x757a, 0x3f4f,
+ 0x757d, 0x2735,
+ 0x757e, 0x297f,
+ 0x757f, 0x11ab,
+ 0x7580, 0x2bd3,
+ 0x7583, 0x3ae5,
+ 0x7584, 0x2db2,
+ 0x7586, 0x159b,
+ 0x7587, 0x159a,
+ 0x758a, 0x16cc,
+ 0x758b, 0x0362,
+ 0x758c, 0x1a12,
+ 0x758d, 0x46ff,
+ 0x758e, 0x42c5,
+ 0x758f, 0x0b2f,
+ 0x7590, 0x2736,
+ 0x7591, 0x1032,
+ 0x7592, 0x022e,
+ 0x7594, 0x18d4,
+ 0x7598, 0x1a13,
+ 0x7599, 0x0657,
+ 0x759d, 0x0656,
+ 0x759e, 0x42c7,
+ 0x75a2, 0x07a8,
+ 0x75a4, 0x07a6,
+ 0x75a7, 0x1b93,
+ 0x75aa, 0x1b94,
+ 0x75ab, 0x07a5,
+ 0x75b0, 0x1d51,
+ 0x75b1, 0x3ead,
+ 0x75b2, 0x0939,
+ 0x75b4, 0x42c8,
+ 0x75b5, 0x0b32,
+ 0x75b6, 0x1d57,
+ 0x75b8, 0x093f,
+ 0x75b9, 0x093d,
+ 0x75ba, 0x1d58,
+ 0x75bb, 0x1d53,
+ 0x75bc, 0x093c,
+ 0x75bd, 0x093b,
+ 0x75be, 0x0936,
+ 0x75bf, 0x1d56,
+ 0x75c0, 0x1d55,
+ 0x75c1, 0x1d52,
+ 0x75c2, 0x093e,
+ 0x75c3, 0x3f93,
+ 0x75c4, 0x1d54,
+ 0x75c5, 0x0937,
+ 0x75c7, 0x0938,
+ 0x75c8, 0x4701,
+ 0x75ca, 0x0b33,
+ 0x75cb, 0x1fa3,
+ 0x75cd, 0x0b34,
+ 0x75ce, 0x1fa0,
+ 0x75cf, 0x1fa2,
+ 0x75d0, 0x1fa6,
+ 0x75d1, 0x1fa5,
+ 0x75d2, 0x1fa1,
+ 0x75d4, 0x0b30,
+ 0x75d7, 0x222b,
+ 0x75d8, 0x0ceb,
+ 0x75d9, 0x0cea,
+ 0x75da, 0x2225,
+ 0x75db, 0x0ce8,
+ 0x75dc, 0x43ce,
+ 0x75dd, 0x2228,
+ 0x75de, 0x0cec,
+ 0x75df, 0x2229,
+ 0x75e0, 0x0ced,
+ 0x75e1, 0x2226,
+ 0x75e2, 0x0ce7,
+ 0x75e3, 0x0ce9,
+ 0x75e4, 0x222a,
+ 0x75e6, 0x2227,
+ 0x75e7, 0x2224,
+ 0x75ed, 0x24bb,
+ 0x75ef, 0x24b0,
+ 0x75f0, 0x0e88,
+ 0x75f1, 0x0e8b,
+ 0x75f2, 0x0e8a,
+ 0x75f3, 0x0e8f,
+ 0x75f4, 0x0e8e,
+ 0x75f5, 0x24bc,
+ 0x75f6, 0x24ba,
+ 0x75f7, 0x24b3,
+ 0x75f8, 0x24b7,
+ 0x75f9, 0x24b6,
+ 0x75fa, 0x0e8c,
+ 0x75fb, 0x24b9,
+ 0x75fc, 0x24b5,
+ 0x75fd, 0x24bd,
+ 0x75fe, 0x24b4,
+ 0x75ff, 0x0e8d,
+ 0x7600, 0x0e87,
+ 0x7601, 0x0e89,
+ 0x7602, 0x42c9,
+ 0x7603, 0x24b2,
+ 0x7607, 0x3f8f,
+ 0x7608, 0x2738,
+ 0x7609, 0x1036,
+ 0x760a, 0x273c,
+ 0x760b, 0x1035,
+ 0x760c, 0x2739,
+ 0x760d, 0x1034,
+ 0x760f, 0x24b1,
+ 0x7610, 0x24b8,
+ 0x7611, 0x273b,
+ 0x7613, 0x1037,
+ 0x7614, 0x273d,
+ 0x7615, 0x273a,
+ 0x7616, 0x2737,
+ 0x7619, 0x2982,
+ 0x761a, 0x2986,
+ 0x761b, 0x2988,
+ 0x761c, 0x2984,
+ 0x761d, 0x2983,
+ 0x761e, 0x2981,
+ 0x761f, 0x11ae,
+ 0x7620, 0x11ac,
+ 0x7621, 0x11b1,
+ 0x7623, 0x2985,
+ 0x7624, 0x11af,
+ 0x7625, 0x2980,
+ 0x7626, 0x11b0,
+ 0x7627, 0x1033,
+ 0x7628, 0x2987,
+ 0x7629, 0x11ad,
+ 0x762c, 0x42ca,
+ 0x762d, 0x2bd5,
+ 0x762f, 0x2bd4,
+ 0x7630, 0x2bdc,
+ 0x7631, 0x2bd6,
+ 0x7632, 0x2bdb,
+ 0x7633, 0x2bd8,
+ 0x7634, 0x1302,
+ 0x7635, 0x2bda,
+ 0x7638, 0x1303,
+ 0x763a, 0x1304,
+ 0x763b, 0x3e70,
+ 0x763c, 0x2bd9,
+ 0x763d, 0x2bd7,
+ 0x7640, 0x3ee6,
+ 0x7642, 0x1415,
+ 0x7643, 0x2db3,
+ 0x7646, 0x1414,
+ 0x7647, 0x2db6,
+ 0x7648, 0x2db4,
+ 0x764c, 0x1416,
+ 0x764d, 0x4702,
+ 0x764e, 0x3e72,
+ 0x764f, 0x42cc,
+ 0x7650, 0x2f63,
+ 0x7651, 0x42cb,
+ 0x7652, 0x14f9,
+ 0x7653, 0x2f64,
+ 0x7654, 0x3ef0,
+ 0x7656, 0x14f7,
+ 0x7657, 0x2f65,
+ 0x7658, 0x14f8,
+ 0x7659, 0x2f62,
+ 0x765a, 0x2f66,
+ 0x765c, 0x2f60,
+ 0x765f, 0x159c,
+ 0x7660, 0x30c5,
+ 0x7661, 0x159d,
+ 0x7662, 0x1622,
+ 0x7664, 0x2f61,
+ 0x7665, 0x1623,
+ 0x7666, 0x3eaa,
+ 0x7667, 0x3fa9,
+ 0x7669, 0x167f,
+ 0x766a, 0x32e4,
+ 0x766c, 0x16ce,
+ 0x766d, 0x3395,
+ 0x766e, 0x16cd,
+ 0x766f, 0x42cd,
+ 0x7670, 0x3428,
+ 0x7671, 0x1723,
+ 0x7673, 0x3aeb,
+ 0x7674, 0x4703,
+ 0x7675, 0x3543,
+ 0x7676, 0x022f,
+ 0x7678, 0x07aa,
+ 0x7679, 0x1b95,
+ 0x767a, 0x4705,
+ 0x767b, 0x0cee,
+ 0x767d, 0x0363,
+ 0x767e, 0x03f5,
+ 0x767f, 0x1810,
+ 0x7680, 0x43d3,
+ 0x7681, 0x18d6,
+ 0x7682, 0x04f4,
+ 0x7684, 0x0659,
+ 0x7686, 0x07ab,
+ 0x7689, 0x1fa8,
+ 0x768a, 0x1d59,
+ 0x768b, 0x0940,
+ 0x768c, 0x43d4,
+ 0x768e, 0x0b35,
+ 0x768f, 0x1fa7,
+ 0x7690, 0x42d0,
+ 0x7692, 0x222d,
+ 0x7693, 0x0cf1,
+ 0x7695, 0x222c,
+ 0x7696, 0x0cf0,
+ 0x7699, 0x24be,
+ 0x769a, 0x11b3,
+ 0x769b, 0x298c,
+ 0x769c, 0x2989,
+ 0x76a1, 0x42d5,
+ 0x76a4, 0x2db7,
+ 0x76a5, 0x42d6,
+ 0x76a6, 0x2f67,
+ 0x76aa, 0x31fb,
+ 0x76ab, 0x31fa,
+ 0x76ad, 0x3396,
+ 0x76ae, 0x0364,
+ 0x76af, 0x1a14,
+ 0x76b0, 0x0941,
+ 0x76b4, 0x0cf2,
+ 0x76b5, 0x24bf,
+ 0x76b7, 0x42d7,
+ 0x76b8, 0x273e,
+ 0x76ba, 0x11b4,
+ 0x76bb, 0x2bdd,
+ 0x76bd, 0x2f68,
+ 0x76be, 0x31fc,
+ 0x76bf, 0x0365,
+ 0x76c2, 0x065a,
+ 0x76c3, 0x07b0,
+ 0x76c4, 0x1b96,
+ 0x76c5, 0x07b1,
+ 0x76c6, 0x07af,
+ 0x76c8, 0x07ae,
+ 0x76c9, 0x1d5a,
+ 0x76ca, 0x0942,
+ 0x76cc, 0x42d8,
+ 0x76cd, 0x0943,
+ 0x76d2, 0x0b37,
+ 0x76d3, 0x1fa9,
+ 0x76d4, 0x0b36,
+ 0x76d6, 0x3f55,
+ 0x76da, 0x222e,
+ 0x76db, 0x0b38,
+ 0x76dc, 0x0cf3,
+ 0x76dd, 0x24c0,
+ 0x76de, 0x0e90,
+ 0x76e1, 0x1038,
+ 0x76e3, 0x1039,
+ 0x76e4, 0x11b5,
+ 0x76e5, 0x1306,
+ 0x76e6, 0x2bde,
+ 0x76e7, 0x1305,
+ 0x76e9, 0x2db8,
+ 0x76ea, 0x1417,
+ 0x76ec, 0x2f69,
+ 0x76ed, 0x31fd,
+ 0x76ee, 0x0366,
+ 0x76ef, 0x04f5,
+ 0x76f0, 0x1a17,
+ 0x76f1, 0x1a16,
+ 0x76f2, 0x065b,
+ 0x76f3, 0x1a15,
+ 0x76f4, 0x065c,
+ 0x76f5, 0x1a18,
+ 0x76f7, 0x1b9c,
+ 0x76f8, 0x07b4,
+ 0x76f9, 0x07b3,
+ 0x76fa, 0x1b9e,
+ 0x76fb, 0x1b9d,
+ 0x76fc, 0x07b8,
+ 0x76fe, 0x07b7,
+ 0x7701, 0x07b2,
+ 0x7703, 0x1b98,
+ 0x7707, 0x07b9,
+ 0x7708, 0x1b97,
+ 0x7709, 0x07b5,
+ 0x770a, 0x1b9b,
+ 0x770b, 0x07b6,
+ 0x770c, 0x3d62,
+ 0x770e, 0x3b02,
+ 0x7710, 0x1d5d,
+ 0x7711, 0x1d61,
+ 0x7712, 0x1d5f,
+ 0x7713, 0x1d5e,
+ 0x7715, 0x1d62,
+ 0x7719, 0x1d63,
+ 0x771b, 0x1d5c,
+ 0x771d, 0x1d5b,
+ 0x771e, 0x42de,
+ 0x771f, 0x0946,
+ 0x7722, 0x1d65,
+ 0x7723, 0x1d60,
+ 0x7724, 0x3fe8,
+ 0x7725, 0x1fb2,
+ 0x7726, 0x42df,
+ 0x7727, 0x1d66,
+ 0x7728, 0x0948,
+ 0x7729, 0x0945,
+ 0x772b, 0x3ff3,
+ 0x772d, 0x1fac,
+ 0x772f, 0x1fab,
+ 0x7731, 0x1fad,
+ 0x7733, 0x1fb0,
+ 0x7734, 0x1faf,
+ 0x7735, 0x1fb4,
+ 0x7736, 0x0b3c,
+ 0x7737, 0x0b39,
+ 0x7738, 0x0b3d,
+ 0x7739, 0x1faa,
+ 0x773a, 0x0b3e,
+ 0x773b, 0x1fb3,
+ 0x773c, 0x0b3b,
+ 0x773d, 0x1fb1,
+ 0x773e, 0x0b3a,
+ 0x7740, 0x42e0,
+ 0x7743, 0x470a,
+ 0x7744, 0x2231,
+ 0x7745, 0x2233,
+ 0x7746, 0x222f,
+ 0x774a, 0x2234,
+ 0x774b, 0x2236,
+ 0x774d, 0x2232,
+ 0x774e, 0x2235,
+ 0x774f, 0x0cf4,
+ 0x7752, 0x24c4,
+ 0x7754, 0x24c9,
+ 0x7755, 0x24c1,
+ 0x7756, 0x24c5,
+ 0x7758, 0x42e3,
+ 0x7759, 0x24ca,
+ 0x775a, 0x24c6,
+ 0x775b, 0x0e92,
+ 0x775c, 0x0e9a,
+ 0x775e, 0x0e95,
+ 0x775f, 0x24c2,
+ 0x7761, 0x103d,
+ 0x7762, 0x0e9d,
+ 0x7763, 0x0e96,
+ 0x7765, 0x0e9b,
+ 0x7766, 0x0e94,
+ 0x7767, 0x24c8,
+ 0x7768, 0x0e9c,
+ 0x7769, 0x24c7,
+ 0x776a, 0x0e98,
+ 0x776b, 0x0e93,
+ 0x776c, 0x0e99,
+ 0x776d, 0x24cb,
+ 0x776e, 0x2743,
+ 0x776f, 0x2745,
+ 0x7772, 0x396b,
+ 0x7777, 0x46a9,
+ 0x7778, 0x3b00,
+ 0x7779, 0x0e97,
+ 0x777a, 0x4317,
+ 0x777b, 0x3b04,
+ 0x777c, 0x2740,
+ 0x777d, 0x103b,
+ 0x777e, 0x2746,
+ 0x777f, 0x103c,
+ 0x7780, 0x2744,
+ 0x7781, 0x273f,
+ 0x7782, 0x2742,
+ 0x7783, 0x2747,
+ 0x7784, 0x103a,
+ 0x7785, 0x2741,
+ 0x7787, 0x11b7,
+ 0x7788, 0x2990,
+ 0x7789, 0x298f,
+ 0x778b, 0x11ba,
+ 0x778c, 0x11b8,
+ 0x778d, 0x298d,
+ 0x778e, 0x11b6,
+ 0x778f, 0x298e,
+ 0x7791, 0x11b9,
+ 0x7793, 0x382d,
+ 0x7795, 0x2be6,
+ 0x7797, 0x2be8,
+ 0x7798, 0x470e,
+ 0x7799, 0x2be7,
+ 0x779a, 0x2bdf,
+ 0x779b, 0x2be3,
+ 0x779c, 0x2be2,
+ 0x779d, 0x2be0,
+ 0x779e, 0x1308,
+ 0x77a0, 0x1307,
+ 0x77a1, 0x2be1,
+ 0x77a2, 0x2be4,
+ 0x77a5, 0x130a,
+ 0x77a7, 0x141c,
+ 0x77a8, 0x2dc0,
+ 0x77aa, 0x1419,
+ 0x77ab, 0x2dba,
+ 0x77ac, 0x141b,
+ 0x77ad, 0x141d,
+ 0x77af, 0x42e5,
+ 0x77b0, 0x141a,
+ 0x77b1, 0x2dbf,
+ 0x77b2, 0x2dbb,
+ 0x77b3, 0x1418,
+ 0x77b4, 0x2dbe,
+ 0x77b5, 0x2db9,
+ 0x77b6, 0x2dbd,
+ 0x77b7, 0x2dbc,
+ 0x77b9, 0x3e73,
+ 0x77ba, 0x2f6b,
+ 0x77bb, 0x14fc,
+ 0x77bd, 0x14fa,
+ 0x77be, 0x4711,
+ 0x77bf, 0x14fb,
+ 0x77c2, 0x2f6a,
+ 0x77c3, 0x3bb1,
+ 0x77c4, 0x30c8,
+ 0x77c5, 0x41c1,
+ 0x77c7, 0x159e,
+ 0x77c9, 0x30c6,
+ 0x77cb, 0x4712,
+ 0x77cc, 0x31fe,
+ 0x77cd, 0x3201,
+ 0x77ce, 0x31ff,
+ 0x77d0, 0x32e5,
+ 0x77d3, 0x1680,
+ 0x77d4, 0x3429,
+ 0x77d5, 0x348f,
+ 0x77d7, 0x1725,
+ 0x77d8, 0x34d3,
+ 0x77da, 0x1753,
+ 0x77db, 0x0367,
+ 0x77dc, 0x07ba,
+ 0x77de, 0x2238,
+ 0x77e0, 0x24cc,
+ 0x77e2, 0x0368,
+ 0x77e3, 0x04f6,
+ 0x77e5, 0x065d,
+ 0x77e6, 0x4081,
+ 0x77e7, 0x1b9f,
+ 0x77e9, 0x0949,
+ 0x77ec, 0x2239,
+ 0x77ed, 0x0cf5,
+ 0x77ee, 0x0e9e,
+ 0x77ef, 0x141e,
+ 0x77f0, 0x2dc1,
+ 0x77f1, 0x30c9,
+ 0x77f2, 0x3202,
+ 0x77f3, 0x0369,
+ 0x77f4, 0x42e9,
+ 0x77f7, 0x1a1e,
+ 0x77f8, 0x1a19,
+ 0x77f9, 0x1a1b,
+ 0x77fa, 0x1a1d,
+ 0x77fb, 0x1a1c,
+ 0x77fc, 0x1a1a,
+ 0x77fd, 0x065e,
+ 0x77fe, 0x3fd5,
+ 0x7802, 0x07bb,
+ 0x7803, 0x1ba9,
+ 0x7805, 0x1ba4,
+ 0x7806, 0x1ba1,
+ 0x7808, 0x3e46,
+ 0x7809, 0x1ba8,
+ 0x780c, 0x07bd,
+ 0x780e, 0x1ba7,
+ 0x780f, 0x1ba6,
+ 0x7810, 0x1ba5,
+ 0x7811, 0x1ba2,
+ 0x7813, 0x1baa,
+ 0x7814, 0x07bc,
+ 0x7818, 0x4713,
+ 0x781c, 0x4714,
+ 0x781d, 0x094d,
+ 0x781e, 0x3b13,
+ 0x781f, 0x0953,
+ 0x7820, 0x0952,
+ 0x7821, 0x1d6f,
+ 0x7822, 0x1d69,
+ 0x7823, 0x1d67,
+ 0x7825, 0x0950,
+ 0x7826, 0x1fbb,
+ 0x7827, 0x094b,
+ 0x7828, 0x1d6c,
+ 0x7829, 0x1d70,
+ 0x782a, 0x1d72,
+ 0x782b, 0x1d6e,
+ 0x782c, 0x1d68,
+ 0x782d, 0x0951,
+ 0x782e, 0x1d6d,
+ 0x782f, 0x1d6b,
+ 0x7830, 0x094a,
+ 0x7831, 0x1d73,
+ 0x7832, 0x0954,
+ 0x7833, 0x1d71,
+ 0x7834, 0x094e,
+ 0x7835, 0x1d6a,
+ 0x7837, 0x094f,
+ 0x7838, 0x094c,
+ 0x7839, 0x43d6,
+ 0x783c, 0x401a,
+ 0x783d, 0x3c6a,
+ 0x7842, 0x3ac4,
+ 0x7843, 0x0b40,
+ 0x7844, 0x3c2b,
+ 0x7845, 0x1fbc,
+ 0x7847, 0x4715,
+ 0x7848, 0x1fb5,
+ 0x7849, 0x1fb7,
+ 0x784a, 0x1fb9,
+ 0x784b, 0x3c6d,
+ 0x784c, 0x1fba,
+ 0x784d, 0x1fb8,
+ 0x784e, 0x0b41,
+ 0x7850, 0x1fbd,
+ 0x7851, 0x4716,
+ 0x7852, 0x1fb6,
+ 0x7853, 0x3f95,
+ 0x7854, 0x3c6b,
+ 0x785c, 0x223d,
+ 0x785d, 0x0cf6,
+ 0x785e, 0x2245,
+ 0x7860, 0x223a,
+ 0x7862, 0x2246,
+ 0x7864, 0x223b,
+ 0x7866, 0x4717,
+ 0x7868, 0x2244,
+ 0x7869, 0x2243,
+ 0x786a, 0x2240,
+ 0x786b, 0x0b3f,
+ 0x786c, 0x0cf7,
+ 0x786d, 0x223e,
+ 0x786e, 0x2241,
+ 0x786f, 0x0cf8,
+ 0x7870, 0x2242,
+ 0x7871, 0x223f,
+ 0x7879, 0x24d7,
+ 0x787a, 0x3ee9,
+ 0x787b, 0x24db,
+ 0x787c, 0x0ea5,
+ 0x787e, 0x274d,
+ 0x787f, 0x0ea8,
+ 0x7880, 0x24d9,
+ 0x7881, 0x36e8,
+ 0x7883, 0x24d6,
+ 0x7884, 0x24d1,
+ 0x7885, 0x24d3,
+ 0x7887, 0x24cd,
+ 0x7888, 0x3b15,
+ 0x7889, 0x0ea4,
+ 0x788c, 0x0ea3,
+ 0x788d, 0x3b14,
+ 0x788e, 0x0e9f,
+ 0x788f, 0x24d0,
+ 0x7891, 0x0ea6,
+ 0x7893, 0x0ea7,
+ 0x7894, 0x24cf,
+ 0x7895, 0x24d2,
+ 0x7896, 0x24da,
+ 0x7897, 0x0ea1,
+ 0x7899, 0x24d8,
+ 0x789a, 0x24ce,
+ 0x789e, 0x274f,
+ 0x789f, 0x103f,
+ 0x78a0, 0x2751,
+ 0x78a1, 0x24d5,
+ 0x78a2, 0x2753,
+ 0x78a3, 0x1043,
+ 0x78a4, 0x2754,
+ 0x78a5, 0x2750,
+ 0x78a7, 0x1040,
+ 0x78a8, 0x274c,
+ 0x78a9, 0x1042,
+ 0x78aa, 0x2749,
+ 0x78ab, 0x274e,
+ 0x78ac, 0x2752,
+ 0x78ad, 0x274b,
+ 0x78af, 0x42ec,
+ 0x78b0, 0x0ea0,
+ 0x78b1, 0x42f4,
+ 0x78b2, 0x2748,
+ 0x78b3, 0x1041,
+ 0x78b4, 0x274a,
+ 0x78b6, 0x3c6c,
+ 0x78b8, 0x4571,
+ 0x78b9, 0x3c63,
+ 0x78ba, 0x11bd,
+ 0x78bb, 0x2992,
+ 0x78bc, 0x11c1,
+ 0x78be, 0x11bf,
+ 0x78c1, 0x103e,
+ 0x78c3, 0x2999,
+ 0x78c5, 0x11bc,
+ 0x78c7, 0x42ed,
+ 0x78c8, 0x2998,
+ 0x78c9, 0x299b,
+ 0x78ca, 0x11be,
+ 0x78cb, 0x11bb,
+ 0x78cc, 0x2994,
+ 0x78cd, 0x2991,
+ 0x78ce, 0x2996,
+ 0x78cf, 0x2993,
+ 0x78d0, 0x11c2,
+ 0x78d1, 0x2995,
+ 0x78d2, 0x3b16,
+ 0x78d3, 0x42ee,
+ 0x78d4, 0x2997,
+ 0x78d5, 0x11c0,
+ 0x78d7, 0x42f2,
+ 0x78d8, 0x3f8c,
+ 0x78da, 0x130c,
+ 0x78db, 0x2bef,
+ 0x78dd, 0x2be9,
+ 0x78de, 0x2bed,
+ 0x78df, 0x2bf3,
+ 0x78e1, 0x2bf0,
+ 0x78e3, 0x2bee,
+ 0x78e5, 0x2beb,
+ 0x78e7, 0x130e,
+ 0x78e8, 0x130b,
+ 0x78e9, 0x2bea,
+ 0x78ea, 0x2bec,
+ 0x78ec, 0x130d,
+ 0x78ed, 0x2bf2,
+ 0x78ee, 0x3a81,
+ 0x78ef, 0x1422,
+ 0x78f0, 0x3b3a,
+ 0x78f1, 0x40be,
+ 0x78f2, 0x2dc8,
+ 0x78f3, 0x2dc2,
+ 0x78f4, 0x1421,
+ 0x78f5, 0x38b3,
+ 0x78f7, 0x141f,
+ 0x78f9, 0x2dca,
+ 0x78fa, 0x1420,
+ 0x78fb, 0x2dc5,
+ 0x78fd, 0x2dc3,
+ 0x78fe, 0x2dcb,
+ 0x78ff, 0x2dc7,
+ 0x7901, 0x1423,
+ 0x7902, 0x2dc4,
+ 0x7904, 0x2dcc,
+ 0x7905, 0x2dc9,
+ 0x7906, 0x3fcf,
+ 0x7909, 0x2f6f,
+ 0x790c, 0x2f6c,
+ 0x790e, 0x14fe,
+ 0x7910, 0x2f70,
+ 0x7911, 0x2f72,
+ 0x7912, 0x2f71,
+ 0x7913, 0x2f6d,
+ 0x7917, 0x30ce,
+ 0x7919, 0x159f,
+ 0x791b, 0x30cb,
+ 0x791c, 0x30cd,
+ 0x791d, 0x30ca,
+ 0x791e, 0x30cf,
+ 0x7921, 0x30cc,
+ 0x7923, 0x3204,
+ 0x7924, 0x3207,
+ 0x7925, 0x3203,
+ 0x7926, 0x1624,
+ 0x7927, 0x3205,
+ 0x7929, 0x3208,
+ 0x792a, 0x1625,
+ 0x792b, 0x1627,
+ 0x792c, 0x1626,
+ 0x792d, 0x32e6,
+ 0x792e, 0x42f0,
+ 0x792f, 0x32e8,
+ 0x7931, 0x32e7,
+ 0x7932, 0x471b,
+ 0x7933, 0x471a,
+ 0x7934, 0x42f3,
+ 0x7935, 0x3397,
+ 0x7936, 0x3783,
+ 0x7938, 0x3490,
+ 0x7939, 0x34d5,
+ 0x793a, 0x036a,
+ 0x793b, 0x44f7,
+ 0x793c, 0x4300,
+ 0x793d, 0x18d7,
+ 0x793e, 0x065f,
+ 0x793f, 0x1a20,
+ 0x7940, 0x0660,
+ 0x7942, 0x1a1f,
+ 0x7944, 0x1baf,
+ 0x7945, 0x1bae,
+ 0x7946, 0x07bf,
+ 0x7947, 0x07c2,
+ 0x7948, 0x07c1,
+ 0x7949, 0x07c0,
+ 0x794a, 0x1bab,
+ 0x794b, 0x1bad,
+ 0x794c, 0x1bac,
+ 0x794f, 0x1d76,
+ 0x7950, 0x0956,
+ 0x7951, 0x1d7a,
+ 0x7952, 0x1d79,
+ 0x7953, 0x1d78,
+ 0x7954, 0x1d74,
+ 0x7955, 0x0955,
+ 0x7956, 0x0959,
+ 0x7957, 0x095c,
+ 0x7958, 0x37e5,
+ 0x7959, 0x3b18,
+ 0x795a, 0x095d,
+ 0x795b, 0x1d75,
+ 0x795c, 0x1d77,
+ 0x795d, 0x095b,
+ 0x795e, 0x095a,
+ 0x795f, 0x0958,
+ 0x7960, 0x0957,
+ 0x7961, 0x1fc4,
+ 0x7962, 0x3e7d,
+ 0x7963, 0x1fc2,
+ 0x7964, 0x1fbe,
+ 0x7965, 0x0b42,
+ 0x7967, 0x1fbf,
+ 0x7968, 0x0b43,
+ 0x7969, 0x1fc0,
+ 0x796b, 0x1fc3,
+ 0x796d, 0x0b44,
+ 0x7970, 0x224a,
+ 0x7971, 0x4168,
+ 0x7972, 0x2249,
+ 0x7973, 0x2248,
+ 0x7974, 0x2247,
+ 0x7979, 0x24df,
+ 0x797a, 0x0ea9,
+ 0x797c, 0x24dc,
+ 0x797d, 0x24de,
+ 0x797e, 0x3e26,
+ 0x797f, 0x0eaa,
+ 0x7980, 0x42fc,
+ 0x7981, 0x0eab,
+ 0x7982, 0x24dd,
+ 0x7983, 0x3df6,
+ 0x7986, 0x42f9,
+ 0x7987, 0x4588,
+ 0x7988, 0x275d,
+ 0x798a, 0x2756,
+ 0x798d, 0x1046,
+ 0x798e, 0x1044,
+ 0x7990, 0x275f,
+ 0x7991, 0x471d,
+ 0x7992, 0x275e,
+ 0x7993, 0x275b,
+ 0x7994, 0x275a,
+ 0x7995, 0x2759,
+ 0x7996, 0x2758,
+ 0x7997, 0x275c,
+ 0x7998, 0x2755,
+ 0x7999, 0x43fc,
+ 0x799a, 0x299c,
+ 0x799b, 0x29a1,
+ 0x799c, 0x299f,
+ 0x799d, 0x42fe,
+ 0x799f, 0x395e,
+ 0x79a0, 0x299e,
+ 0x79a1, 0x299d,
+ 0x79a2, 0x29a0,
+ 0x79a4, 0x2bf5,
+ 0x79a5, 0x3b1e,
+ 0x79a6, 0x130f,
+ 0x79a7, 0x1424,
+ 0x79a8, 0x2dce,
+ 0x79a9, 0x4301,
+ 0x79aa, 0x1425,
+ 0x79ab, 0x2dcd,
+ 0x79ac, 0x2f74,
+ 0x79ad, 0x2f73,
+ 0x79ae, 0x14ff,
+ 0x79b0, 0x30d0,
+ 0x79b1, 0x15a0,
+ 0x79b2, 0x3209,
+ 0x79b3, 0x16cf,
+ 0x79b4, 0x3398,
+ 0x79b6, 0x3492,
+ 0x79b7, 0x3491,
+ 0x79b8, 0x17b2,
+ 0x79b9, 0x07c3,
+ 0x79bb, 0x1fc5,
+ 0x79bd, 0x0ead,
+ 0x79be, 0x036b,
+ 0x79bf, 0x04f9,
+ 0x79c0, 0x04f8,
+ 0x79c1, 0x04f7,
+ 0x79c4, 0x3ccd,
+ 0x79c5, 0x1a21,
+ 0x79c6, 0x4305,
+ 0x79c8, 0x0663,
+ 0x79c9, 0x0662,
+ 0x79cb, 0x07c7,
+ 0x79cc, 0x4233,
+ 0x79cd, 0x1bb1,
+ 0x79ce, 0x1bb4,
+ 0x79cf, 0x1bb2,
+ 0x79d1, 0x07c5,
+ 0x79d4, 0x4307,
+ 0x79d5, 0x1bb0,
+ 0x79d6, 0x1bb3,
+ 0x79d8, 0x0964,
+ 0x79dc, 0x1d81,
+ 0x79dd, 0x1d83,
+ 0x79de, 0x1d82,
+ 0x79df, 0x0961,
+ 0x79e0, 0x1d7d,
+ 0x79e2, 0x3c5a,
+ 0x79e3, 0x095f,
+ 0x79e4, 0x095e,
+ 0x79e6, 0x0962,
+ 0x79e7, 0x0960,
+ 0x79e9, 0x0963,
+ 0x79ea, 0x1d80,
+ 0x79eb, 0x1d7b,
+ 0x79ed, 0x1d7f,
+ 0x79ee, 0x1d7e,
+ 0x79f1, 0x3b27,
+ 0x79f4, 0x3b22,
+ 0x79f6, 0x1fc8,
+ 0x79f8, 0x1fc7,
+ 0x79fa, 0x1fc6,
+ 0x79fb, 0x0b45,
+ 0x7a00, 0x0cfd,
+ 0x7a02, 0x224b,
+ 0x7a03, 0x224d,
+ 0x7a04, 0x224f,
+ 0x7a05, 0x0cfc,
+ 0x7a06, 0x471e,
+ 0x7a08, 0x0cfa,
+ 0x7a0a, 0x224c,
+ 0x7a0b, 0x0cfb,
+ 0x7a0c, 0x224e,
+ 0x7a0d, 0x0cf9,
+ 0x7a10, 0x24e9,
+ 0x7a11, 0x24e0,
+ 0x7a12, 0x24e3,
+ 0x7a13, 0x24e7,
+ 0x7a14, 0x0eb1,
+ 0x7a15, 0x24e5,
+ 0x7a17, 0x24e4,
+ 0x7a18, 0x24e1,
+ 0x7a1a, 0x0eaf,
+ 0x7a1b, 0x24e8,
+ 0x7a1c, 0x0eae,
+ 0x7a1e, 0x0eb3,
+ 0x7a1f, 0x0eb2,
+ 0x7a20, 0x0eb0,
+ 0x7a22, 0x24e6,
+ 0x7a26, 0x2765,
+ 0x7a28, 0x2764,
+ 0x7a2b, 0x2760,
+ 0x7a2d, 0x3fda,
+ 0x7a2e, 0x1047,
+ 0x7a2f, 0x2763,
+ 0x7a30, 0x2762,
+ 0x7a31, 0x1048,
+ 0x7a37, 0x11c7,
+ 0x7a39, 0x29a3,
+ 0x7a3a, 0x3b21,
+ 0x7a3b, 0x11c8,
+ 0x7a3c, 0x11c4,
+ 0x7a3d, 0x11c6,
+ 0x7a3e, 0x3f8b,
+ 0x7a3f, 0x11c3,
+ 0x7a40, 0x11c5,
+ 0x7a43, 0x396c,
+ 0x7a44, 0x2bf6,
+ 0x7a45, 0x3df1,
+ 0x7a46, 0x1312,
+ 0x7a47, 0x2bf8,
+ 0x7a48, 0x2bf7,
+ 0x7a49, 0x3733,
+ 0x7a4a, 0x2761,
+ 0x7a4b, 0x1314,
+ 0x7a4c, 0x1313,
+ 0x7a4d, 0x1310,
+ 0x7a54, 0x2dd3,
+ 0x7a56, 0x2dd1,
+ 0x7a57, 0x1426,
+ 0x7a58, 0x2dd2,
+ 0x7a5a, 0x2dd4,
+ 0x7a5b, 0x2dd0,
+ 0x7a5c, 0x2dcf,
+ 0x7a5f, 0x2f75,
+ 0x7a60, 0x1502,
+ 0x7a61, 0x1500,
+ 0x7a65, 0x3736,
+ 0x7a67, 0x30d1,
+ 0x7a69, 0x15a2,
+ 0x7a6b, 0x15a1,
+ 0x7a6c, 0x320b,
+ 0x7a6e, 0x320a,
+ 0x7a70, 0x3399,
+ 0x7a74, 0x036c,
+ 0x7a75, 0x1811,
+ 0x7a76, 0x04fa,
+ 0x7a78, 0x1a22,
+ 0x7a79, 0x0665,
+ 0x7a7a, 0x0664,
+ 0x7a7b, 0x1a23,
+ 0x7a7d, 0x3737,
+ 0x7a7e, 0x1bb6,
+ 0x7a7f, 0x07c8,
+ 0x7a80, 0x1bb5,
+ 0x7a81, 0x07c9,
+ 0x7a83, 0x3d7d,
+ 0x7a84, 0x0965,
+ 0x7a85, 0x1d86,
+ 0x7a86, 0x1d84,
+ 0x7a87, 0x1d8a,
+ 0x7a88, 0x0966,
+ 0x7a89, 0x1d85,
+ 0x7a8a, 0x1d89,
+ 0x7a8b, 0x1d87,
+ 0x7a8f, 0x1fca,
+ 0x7a90, 0x1fcc,
+ 0x7a91, 0x43d8,
+ 0x7a92, 0x0b46,
+ 0x7a94, 0x1fcb,
+ 0x7a95, 0x0b47,
+ 0x7a96, 0x0d00,
+ 0x7a97, 0x0cff,
+ 0x7a98, 0x0cfe,
+ 0x7a99, 0x2250,
+ 0x7a9e, 0x24ec,
+ 0x7a9f, 0x0eb4,
+ 0x7aa2, 0x24eb,
+ 0x7aa3, 0x24ea,
+ 0x7aa8, 0x2766,
+ 0x7aa9, 0x104a,
+ 0x7aaa, 0x1049,
+ 0x7aab, 0x2767,
+ 0x7aae, 0x11ca,
+ 0x7aaf, 0x11c9,
+ 0x7ab0, 0x373a,
+ 0x7ab1, 0x2bfc,
+ 0x7ab2, 0x29a4,
+ 0x7ab3, 0x29a6,
+ 0x7ab4, 0x29a5,
+ 0x7ab5, 0x2bfb,
+ 0x7ab6, 0x2bf9,
+ 0x7ab7, 0x2bfd,
+ 0x7ab8, 0x2bfa,
+ 0x7aba, 0x1315,
+ 0x7abb, 0x3739,
+ 0x7abc, 0x4721,
+ 0x7abe, 0x2dd5,
+ 0x7abf, 0x1427,
+ 0x7ac0, 0x2dd6,
+ 0x7ac2, 0x373b,
+ 0x7ac4, 0x1503,
+ 0x7ac7, 0x1628,
+ 0x7ac8, 0x3d7f,
+ 0x7ac9, 0x4570,
+ 0x7aca, 0x16ff,
+ 0x7acb, 0x036d,
+ 0x7acf, 0x4724,
+ 0x7ad1, 0x1bb7,
+ 0x7ad3, 0x3f8a,
+ 0x7ad8, 0x1d8b,
+ 0x7ad9, 0x0967,
+ 0x7ada, 0x3740,
+ 0x7adb, 0x4725,
+ 0x7adc, 0x3951,
+ 0x7add, 0x3741,
+ 0x7adf, 0x0bde,
+ 0x7ae0, 0x0bdd,
+ 0x7ae2, 0x3b33,
+ 0x7ae3, 0x0d02,
+ 0x7ae4, 0x2252,
+ 0x7ae5, 0x0d01,
+ 0x7ae6, 0x2251,
+ 0x7ae7, 0x385d,
+ 0x7ae9, 0x3831,
+ 0x7aea, 0x3742,
+ 0x7aeb, 0x24ed,
+ 0x7aed, 0x104b,
+ 0x7aee, 0x2769,
+ 0x7aef, 0x104c,
+ 0x7af6, 0x1629,
+ 0x7af7, 0x320d,
+ 0x7af9, 0x03f6,
+ 0x7afa, 0x0666,
+ 0x7afb, 0x1a24,
+ 0x7afd, 0x07cb,
+ 0x7afe, 0x3b3d,
+ 0x7aff, 0x07ca,
+ 0x7b00, 0x1bb8,
+ 0x7b04, 0x1d8d,
+ 0x7b05, 0x1d8f,
+ 0x7b06, 0x0968,
+ 0x7b08, 0x1d91,
+ 0x7b09, 0x1d94,
+ 0x7b0a, 0x1d92,
+ 0x7b0b, 0x3746,
+ 0x7b0c, 0x3b63,
+ 0x7b0e, 0x1d93,
+ 0x7b0f, 0x1d90,
+ 0x7b10, 0x1d8c,
+ 0x7b11, 0x0969,
+ 0x7b12, 0x1d95,
+ 0x7b13, 0x1d8e,
+ 0x7b14, 0x3f77,
+ 0x7b18, 0x1fd5,
+ 0x7b19, 0x0b4d,
+ 0x7b1a, 0x1fde,
+ 0x7b1b, 0x0b4a,
+ 0x7b1d, 0x1fd7,
+ 0x7b1e, 0x0b4e,
+ 0x7b1f, 0x3f11,
+ 0x7b20, 0x0b48,
+ 0x7b22, 0x1fd2,
+ 0x7b23, 0x1fdf,
+ 0x7b24, 0x1fd3,
+ 0x7b25, 0x1fd0,
+ 0x7b26, 0x0b4c,
+ 0x7b27, 0x3b5f,
+ 0x7b28, 0x0b49,
+ 0x7b29, 0x3748,
+ 0x7b2a, 0x1fd6,
+ 0x7b2b, 0x1fd9,
+ 0x7b2c, 0x0b4b,
+ 0x7b2d, 0x1fda,
+ 0x7b2e, 0x0b4f,
+ 0x7b2f, 0x1fdb,
+ 0x7b30, 0x1fd1,
+ 0x7b31, 0x1fd8,
+ 0x7b32, 0x1fdc,
+ 0x7b33, 0x1fd4,
+ 0x7b34, 0x1fcf,
+ 0x7b35, 0x1fcd,
+ 0x7b38, 0x1fdd,
+ 0x7b39, 0x3d6e,
+ 0x7b3b, 0x1fce,
+ 0x7b40, 0x2259,
+ 0x7b42, 0x3ded,
+ 0x7b43, 0x3e25,
+ 0x7b44, 0x2255,
+ 0x7b45, 0x225b,
+ 0x7b46, 0x0d05,
+ 0x7b47, 0x2254,
+ 0x7b48, 0x2256,
+ 0x7b49, 0x0d03,
+ 0x7b4a, 0x2253,
+ 0x7b4b, 0x0d0a,
+ 0x7b4c, 0x2257,
+ 0x7b4d, 0x0d09,
+ 0x7b4e, 0x2258,
+ 0x7b4f, 0x0d0b,
+ 0x7b50, 0x0d06,
+ 0x7b51, 0x0d0c,
+ 0x7b52, 0x0d07,
+ 0x7b54, 0x0d08,
+ 0x7b55, 0x3747,
+ 0x7b56, 0x0d04,
+ 0x7b58, 0x225a,
+ 0x7b60, 0x0eb8,
+ 0x7b61, 0x24f8,
+ 0x7b62, 0x4727,
+ 0x7b63, 0x24fb,
+ 0x7b64, 0x24ef,
+ 0x7b65, 0x24f4,
+ 0x7b66, 0x24ee,
+ 0x7b67, 0x0eba,
+ 0x7b69, 0x24f2,
+ 0x7b6c, 0x4728,
+ 0x7b6d, 0x24f0,
+ 0x7b6e, 0x0eb9,
+ 0x7b6f, 0x374c,
+ 0x7b70, 0x24f7,
+ 0x7b71, 0x24f6,
+ 0x7b72, 0x24f3,
+ 0x7b73, 0x24f5,
+ 0x7b74, 0x24f1,
+ 0x7b75, 0x1050,
+ 0x7b76, 0x24fa,
+ 0x7b77, 0x0eb6,
+ 0x7b78, 0x24f9,
+ 0x7b7b, 0x4729,
+ 0x7b82, 0x2779,
+ 0x7b84, 0x1057,
+ 0x7b85, 0x2774,
+ 0x7b87, 0x1056,
+ 0x7b88, 0x276a,
+ 0x7b8a, 0x276c,
+ 0x7b8b, 0x104f,
+ 0x7b8c, 0x2771,
+ 0x7b8d, 0x2770,
+ 0x7b8e, 0x2773,
+ 0x7b8f, 0x1054,
+ 0x7b90, 0x276e,
+ 0x7b91, 0x276d,
+ 0x7b92, 0x3752,
+ 0x7b94, 0x1053,
+ 0x7b95, 0x104e,
+ 0x7b96, 0x276f,
+ 0x7b97, 0x1051,
+ 0x7b98, 0x2775,
+ 0x7b99, 0x2777,
+ 0x7b9b, 0x2772,
+ 0x7b9c, 0x276b,
+ 0x7b9d, 0x1052,
+ 0x7ba0, 0x11d2,
+ 0x7ba1, 0x104d,
+ 0x7ba2, 0x374b,
+ 0x7ba3, 0x3f14,
+ 0x7ba4, 0x2778,
+ 0x7bac, 0x29aa,
+ 0x7bad, 0x11cb,
+ 0x7baf, 0x29ac,
+ 0x7bb1, 0x11cc,
+ 0x7bb2, 0x461c,
+ 0x7bb4, 0x11ce,
+ 0x7bb5, 0x29af,
+ 0x7bb7, 0x29a7,
+ 0x7bb8, 0x1055,
+ 0x7bb9, 0x29ad,
+ 0x7bbe, 0x29a9,
+ 0x7bc0, 0x0eb7,
+ 0x7bc1, 0x11d1,
+ 0x7bc4, 0x11cd,
+ 0x7bc6, 0x11cf,
+ 0x7bc9, 0x1318,
+ 0x7bca, 0x29ae,
+ 0x7bcb, 0x29a8,
+ 0x7bcc, 0x11d3,
+ 0x7bce, 0x29ab,
+ 0x7bcf, 0x3f18,
+ 0x7bd0, 0x3750,
+ 0x7bd4, 0x2c07,
+ 0x7bd5, 0x2c02,
+ 0x7bd8, 0x2c0c,
+ 0x7bd9, 0x1316,
+ 0x7bda, 0x2c04,
+ 0x7bdb, 0x131a,
+ 0x7bdc, 0x2c0a,
+ 0x7bdd, 0x2c01,
+ 0x7bde, 0x2bfe,
+ 0x7bdf, 0x2c0d,
+ 0x7be0, 0x142d,
+ 0x7be1, 0x131b,
+ 0x7be2, 0x2c09,
+ 0x7be3, 0x2bff,
+ 0x7be4, 0x1319,
+ 0x7be5, 0x2c03,
+ 0x7be6, 0x131d,
+ 0x7be7, 0x2c00,
+ 0x7be8, 0x2c05,
+ 0x7be9, 0x131c,
+ 0x7bea, 0x2c08,
+ 0x7beb, 0x2c0b,
+ 0x7bf0, 0x2de9,
+ 0x7bf2, 0x2dda,
+ 0x7bf3, 0x2de1,
+ 0x7bf4, 0x2ddf,
+ 0x7bf7, 0x142b,
+ 0x7bf8, 0x2de6,
+ 0x7bf9, 0x2c06,
+ 0x7bfa, 0x3757,
+ 0x7bfb, 0x2ddd,
+ 0x7bfc, 0x3f1f,
+ 0x7bfd, 0x2de7,
+ 0x7bfe, 0x142a,
+ 0x7bff, 0x2ddc,
+ 0x7c00, 0x2ddb,
+ 0x7c01, 0x2de5,
+ 0x7c02, 0x2de2,
+ 0x7c03, 0x2de4,
+ 0x7c05, 0x2dd8,
+ 0x7c06, 0x2de8,
+ 0x7c07, 0x1428,
+ 0x7c09, 0x2de3,
+ 0x7c0a, 0x2dec,
+ 0x7c0b, 0x2de0,
+ 0x7c0c, 0x142c,
+ 0x7c0d, 0x1429,
+ 0x7c0e, 0x2dde,
+ 0x7c0f, 0x2dd9,
+ 0x7c10, 0x2deb,
+ 0x7c11, 0x1317,
+ 0x7c12, 0x472a,
+ 0x7c15, 0x4061,
+ 0x7c19, 0x2f78,
+ 0x7c1b, 0x43d9,
+ 0x7c1c, 0x2f76,
+ 0x7c1d, 0x2f7c,
+ 0x7c1e, 0x1508,
+ 0x7c1f, 0x2f7a,
+ 0x7c20, 0x2f79,
+ 0x7c21, 0x150a,
+ 0x7c22, 0x2f7f,
+ 0x7c23, 0x1509,
+ 0x7c25, 0x2f80,
+ 0x7c26, 0x2f7d,
+ 0x7c27, 0x1506,
+ 0x7c28, 0x2f7e,
+ 0x7c29, 0x2f77,
+ 0x7c2a, 0x1507,
+ 0x7c2b, 0x1505,
+ 0x7c2c, 0x30d6,
+ 0x7c2d, 0x2f7b,
+ 0x7c30, 0x2f81,
+ 0x7c33, 0x30d3,
+ 0x7c35, 0x3759,
+ 0x7c37, 0x15a7,
+ 0x7c38, 0x15a5,
+ 0x7c39, 0x30d5,
+ 0x7c3b, 0x30d7,
+ 0x7c3c, 0x30d4,
+ 0x7c3d, 0x15a6,
+ 0x7c3e, 0x15a3,
+ 0x7c40, 0x15a8,
+ 0x7c42, 0x3f1c,
+ 0x7c43, 0x162b,
+ 0x7c44, 0x375b,
+ 0x7c45, 0x3212,
+ 0x7c47, 0x3211,
+ 0x7c48, 0x320f,
+ 0x7c49, 0x320e,
+ 0x7c4a, 0x3210,
+ 0x7c4c, 0x162a,
+ 0x7c4d, 0x162c,
+ 0x7c50, 0x1681,
+ 0x7c51, 0x3fb8,
+ 0x7c53, 0x32ea,
+ 0x7c54, 0x32e9,
+ 0x7c56, 0x3eff,
+ 0x7c57, 0x339b,
+ 0x7c59, 0x339d,
+ 0x7c5a, 0x339f,
+ 0x7c5b, 0x339e,
+ 0x7c5c, 0x339c,
+ 0x7c5d, 0x3b3f,
+ 0x7c5f, 0x16d1,
+ 0x7c60, 0x16d0,
+ 0x7c63, 0x1701,
+ 0x7c64, 0x1700,
+ 0x7c65, 0x1702,
+ 0x7c66, 0x342b,
+ 0x7c67, 0x342a,
+ 0x7c69, 0x34d6,
+ 0x7c6a, 0x3493,
+ 0x7c6b, 0x34d7,
+ 0x7c6c, 0x1745,
+ 0x7c6d, 0x3b40,
+ 0x7c6e, 0x1746,
+ 0x7c6f, 0x3507,
+ 0x7c70, 0x3f52,
+ 0x7c72, 0x176b,
+ 0x7c73, 0x03f7,
+ 0x7c74, 0x469c,
+ 0x7c75, 0x1a25,
+ 0x7c78, 0x1bbb,
+ 0x7c7a, 0x1bba,
+ 0x7c7b, 0x472d,
+ 0x7c7c, 0x3b49,
+ 0x7c7d, 0x07cc,
+ 0x7c7e, 0x3f1a,
+ 0x7c7f, 0x1bbd,
+ 0x7c83, 0x375c,
+ 0x7c84, 0x1d96,
+ 0x7c85, 0x1d9c,
+ 0x7c86, 0x3f1d,
+ 0x7c88, 0x1d9a,
+ 0x7c89, 0x096a,
+ 0x7c8a, 0x1d98,
+ 0x7c8c, 0x1d99,
+ 0x7c8d, 0x1d9b,
+ 0x7c8e, 0x3b48,
+ 0x7c91, 0x1d97,
+ 0x7c92, 0x0b50,
+ 0x7c94, 0x1fe0,
+ 0x7c95, 0x0b52,
+ 0x7c96, 0x1fe2,
+ 0x7c97, 0x0b51,
+ 0x7c98, 0x1fe1,
+ 0x7c9c, 0x472e,
+ 0x7c9e, 0x225d,
+ 0x7c9f, 0x0d0d,
+ 0x7ca1, 0x225f,
+ 0x7ca2, 0x225c,
+ 0x7ca3, 0x1fe3,
+ 0x7ca5, 0x0d0e,
+ 0x7ca6, 0x375e,
+ 0x7ca7, 0x36ed,
+ 0x7ca8, 0x225e,
+ 0x7cac, 0x3885,
+ 0x7cae, 0x3b4a,
+ 0x7caf, 0x24fe,
+ 0x7cb1, 0x0ebb,
+ 0x7cb2, 0x24fc,
+ 0x7cb3, 0x0ebc,
+ 0x7cb4, 0x24fd,
+ 0x7cb5, 0x0ebd,
+ 0x7cb8, 0x4730,
+ 0x7cb9, 0x1058,
+ 0x7cba, 0x277d,
+ 0x7cbb, 0x277a,
+ 0x7cbc, 0x277c,
+ 0x7cbd, 0x1059,
+ 0x7cbf, 0x277b,
+ 0x7cc2, 0x3fd7,
+ 0x7cc5, 0x29b0,
+ 0x7cc7, 0x3761,
+ 0x7cc8, 0x29b1,
+ 0x7cc9, 0x3760,
+ 0x7cca, 0x11d4,
+ 0x7ccb, 0x29b3,
+ 0x7ccc, 0x29b2,
+ 0x7ccd, 0x3b45,
+ 0x7cce, 0x0121,
+ 0x7cd0, 0x2c11,
+ 0x7cd2, 0x2c0e,
+ 0x7cd3, 0x3d5c,
+ 0x7cd4, 0x2c0f,
+ 0x7cd5, 0x131e,
+ 0x7cd7, 0x2c10,
+ 0x7cd9, 0x1433,
+ 0x7cda, 0x3fd9,
+ 0x7cdc, 0x142f,
+ 0x7cdd, 0x1434,
+ 0x7cde, 0x1430,
+ 0x7cdf, 0x1432,
+ 0x7ce0, 0x142e,
+ 0x7ce2, 0x1431,
+ 0x7ce6, 0x3762,
+ 0x7ce7, 0x150b,
+ 0x7ce8, 0x2ded,
+ 0x7cea, 0x30d9,
+ 0x7cec, 0x30d8,
+ 0x7ced, 0x43da,
+ 0x7cee, 0x3213,
+ 0x7cef, 0x162d,
+ 0x7cf1, 0x33a1,
+ 0x7cf2, 0x32eb,
+ 0x7cf3, 0x3764,
+ 0x7cf4, 0x33a0,
+ 0x7cf5, 0x3765,
+ 0x7cf6, 0x34d8,
+ 0x7cf7, 0x351d,
+ 0x7cf8, 0x03f8,
+ 0x7cf9, 0x44f8,
+ 0x7cfb, 0x04fb,
+ 0x7cfc, 0x456d,
+ 0x7cfd, 0x1a26,
+ 0x7cfe, 0x0667,
+ 0x7d00, 0x07cf,
+ 0x7d01, 0x1bc2,
+ 0x7d02, 0x07cd,
+ 0x7d03, 0x1bc0,
+ 0x7d04, 0x07d2,
+ 0x7d05, 0x07ce,
+ 0x7d06, 0x07d3,
+ 0x7d07, 0x07d1,
+ 0x7d08, 0x1bc1,
+ 0x7d09, 0x07d0,
+ 0x7d0a, 0x096e,
+ 0x7d0b, 0x096d,
+ 0x7d0c, 0x1da7,
+ 0x7d0d, 0x0976,
+ 0x7d0e, 0x1da0,
+ 0x7d0f, 0x1da6,
+ 0x7d10, 0x0972,
+ 0x7d11, 0x1d9f,
+ 0x7d12, 0x1da5,
+ 0x7d13, 0x1da3,
+ 0x7d14, 0x0971,
+ 0x7d15, 0x0973,
+ 0x7d16, 0x1da2,
+ 0x7d17, 0x096c,
+ 0x7d18, 0x1da1,
+ 0x7d19, 0x0977,
+ 0x7d1a, 0x0974,
+ 0x7d1b, 0x0978,
+ 0x7d1c, 0x0975,
+ 0x7d1d, 0x1d9e,
+ 0x7d1e, 0x1d9d,
+ 0x7d1f, 0x1da4,
+ 0x7d20, 0x096f,
+ 0x7d21, 0x096b,
+ 0x7d22, 0x0970,
+ 0x7d25, 0x3ede,
+ 0x7d28, 0x1ff2,
+ 0x7d29, 0x1feb,
+ 0x7d2b, 0x0d13,
+ 0x7d2c, 0x1fea,
+ 0x7d2e, 0x0b56,
+ 0x7d2f, 0x0b5d,
+ 0x7d30, 0x0b5a,
+ 0x7d31, 0x0b60,
+ 0x7d32, 0x0b5f,
+ 0x7d33, 0x0b5b,
+ 0x7d35, 0x1fe4,
+ 0x7d36, 0x1fe7,
+ 0x7d38, 0x1fe6,
+ 0x7d39, 0x0b57,
+ 0x7d3a, 0x1fe8,
+ 0x7d3b, 0x1ff1,
+ 0x7d3c, 0x0b58,
+ 0x7d3d, 0x1fe5,
+ 0x7d3e, 0x1fee,
+ 0x7d40, 0x0b59,
+ 0x7d41, 0x1fec,
+ 0x7d42, 0x0b5e,
+ 0x7d43, 0x0b54,
+ 0x7d44, 0x0b5c,
+ 0x7d45, 0x1fe9,
+ 0x7d46, 0x0b53,
+ 0x7d47, 0x1fed,
+ 0x7d4a, 0x1ff0,
+ 0x7d4d, 0x3fdd,
+ 0x7d4e, 0x2270,
+ 0x7d4f, 0x2267,
+ 0x7d50, 0x0d10,
+ 0x7d51, 0x226e,
+ 0x7d52, 0x226b,
+ 0x7d53, 0x2263,
+ 0x7d54, 0x226c,
+ 0x7d55, 0x0d12,
+ 0x7d56, 0x2264,
+ 0x7d58, 0x2260,
+ 0x7d5a, 0x3e93,
+ 0x7d5b, 0x0ec3,
+ 0x7d5c, 0x2269,
+ 0x7d5d, 0x3769,
+ 0x7d5e, 0x0d0f,
+ 0x7d5f, 0x226f,
+ 0x7d61, 0x0d16,
+ 0x7d62, 0x0d18,
+ 0x7d63, 0x2262,
+ 0x7d66, 0x0d17,
+ 0x7d67, 0x2265,
+ 0x7d68, 0x0d11,
+ 0x7d69, 0x226d,
+ 0x7d6a, 0x2266,
+ 0x7d6b, 0x226a,
+ 0x7d6d, 0x2268,
+ 0x7d6e, 0x0d14,
+ 0x7d6f, 0x2261,
+ 0x7d70, 0x0d19,
+ 0x7d71, 0x0b55,
+ 0x7d72, 0x0d15,
+ 0x7d73, 0x0d1a,
+ 0x7d79, 0x0ebf,
+ 0x7d7a, 0x2505,
+ 0x7d7b, 0x2507,
+ 0x7d7c, 0x2509,
+ 0x7d7d, 0x250d,
+ 0x7d7f, 0x2503,
+ 0x7d80, 0x2501,
+ 0x7d81, 0x0ec1,
+ 0x7d83, 0x2508,
+ 0x7d84, 0x250c,
+ 0x7d85, 0x2504,
+ 0x7d86, 0x2500,
+ 0x7d88, 0x24ff,
+ 0x7d89, 0x376b,
+ 0x7d8c, 0x250a,
+ 0x7d8d, 0x2502,
+ 0x7d8e, 0x2506,
+ 0x7d8f, 0x0ec2,
+ 0x7d91, 0x0ec0,
+ 0x7d92, 0x250e,
+ 0x7d93, 0x0ebe,
+ 0x7d94, 0x250b,
+ 0x7d96, 0x278e,
+ 0x7d97, 0x3b53,
+ 0x7d9c, 0x105d,
+ 0x7d9d, 0x2786,
+ 0x7d9e, 0x11e1,
+ 0x7d9f, 0x2790,
+ 0x7da0, 0x1060,
+ 0x7da1, 0x2794,
+ 0x7da2, 0x1066,
+ 0x7da3, 0x2781,
+ 0x7da4, 0x46d7,
+ 0x7da6, 0x2791,
+ 0x7da7, 0x277e,
+ 0x7da8, 0x3c9c,
+ 0x7da9, 0x2793,
+ 0x7daa, 0x2782,
+ 0x7dab, 0x376c,
+ 0x7dac, 0x106d,
+ 0x7dad, 0x106a,
+ 0x7dae, 0x2792,
+ 0x7daf, 0x278c,
+ 0x7db0, 0x105c,
+ 0x7db1, 0x1064,
+ 0x7db2, 0x1063,
+ 0x7db3, 0x376e,
+ 0x7db4, 0x1062,
+ 0x7db5, 0x1068,
+ 0x7db7, 0x277f,
+ 0x7db8, 0x1069,
+ 0x7db9, 0x278d,
+ 0x7dba, 0x1065,
+ 0x7dbb, 0x105b,
+ 0x7dbc, 0x278f,
+ 0x7dbd, 0x105e,
+ 0x7dbf, 0x1067,
+ 0x7dc0, 0x2784,
+ 0x7dc1, 0x2783,
+ 0x7dc2, 0x2780,
+ 0x7dc4, 0x2788,
+ 0x7dc5, 0x2785,
+ 0x7dc6, 0x2789,
+ 0x7dc7, 0x106c,
+ 0x7dc9, 0x2795,
+ 0x7dca, 0x1061,
+ 0x7dcb, 0x278a,
+ 0x7dcd, 0x456e,
+ 0x7dce, 0x2787,
+ 0x7dcf, 0x4735,
+ 0x7dd0, 0x4737,
+ 0x7dd2, 0x106b,
+ 0x7dd3, 0x3b4e,
+ 0x7dd4, 0x4736,
+ 0x7dd6, 0x376f,
+ 0x7dd7, 0x29b8,
+ 0x7dd8, 0x11d9,
+ 0x7dd9, 0x11e2,
+ 0x7dda, 0x11de,
+ 0x7ddb, 0x29b5,
+ 0x7ddc, 0x3b4c,
+ 0x7ddd, 0x11db,
+ 0x7dde, 0x11df,
+ 0x7ddf, 0x29c1,
+ 0x7de0, 0x11d5,
+ 0x7de1, 0x29b9,
+ 0x7de3, 0x11dd,
+ 0x7de4, 0x3772,
+ 0x7de5, 0x3776,
+ 0x7de6, 0x29bc,
+ 0x7de7, 0x29b7,
+ 0x7de8, 0x11dc,
+ 0x7de9, 0x11e0,
+ 0x7dea, 0x29b6,
+ 0x7dec, 0x11da,
+ 0x7dee, 0x29c0,
+ 0x7def, 0x11d7,
+ 0x7df0, 0x29bf,
+ 0x7df1, 0x29be,
+ 0x7df2, 0x11e3,
+ 0x7df3, 0x28c8,
+ 0x7df4, 0x11d6,
+ 0x7df5, 0x3774,
+ 0x7df6, 0x29bd,
+ 0x7df7, 0x29b4,
+ 0x7df9, 0x11e4,
+ 0x7dfa, 0x29bb,
+ 0x7dfb, 0x11d8,
+ 0x7dfd, 0x4738,
+ 0x7dfe, 0x3ccf,
+ 0x7e03, 0x29ba,
+ 0x7e07, 0x3b4d,
+ 0x7e08, 0x1322,
+ 0x7e09, 0x1327,
+ 0x7e0a, 0x1320,
+ 0x7e0b, 0x2c1f,
+ 0x7e0c, 0x2c16,
+ 0x7e0d, 0x2c22,
+ 0x7e0e, 0x2c1a,
+ 0x7e0f, 0x2c20,
+ 0x7e10, 0x1328,
+ 0x7e11, 0x1321,
+ 0x7e12, 0x2c13,
+ 0x7e13, 0x2c19,
+ 0x7e14, 0x2c23,
+ 0x7e15, 0x2c1c,
+ 0x7e16, 0x2c21,
+ 0x7e17, 0x2c15,
+ 0x7e1a, 0x2c1d,
+ 0x7e1b, 0x1323,
+ 0x7e1c, 0x2c1b,
+ 0x7e1d, 0x1326,
+ 0x7e1e, 0x1325,
+ 0x7e1f, 0x2c17,
+ 0x7e21, 0x2c14,
+ 0x7e22, 0x2c1e,
+ 0x7e23, 0x1324,
+ 0x7e24, 0x2c25,
+ 0x7e25, 0x2c24,
+ 0x7e27, 0x377f,
+ 0x7e29, 0x2df8,
+ 0x7e2a, 0x2df4,
+ 0x7e2b, 0x143b,
+ 0x7e2d, 0x2dee,
+ 0x7e2e, 0x1435,
+ 0x7e2f, 0x1445,
+ 0x7e30, 0x2dfa,
+ 0x7e31, 0x143d,
+ 0x7e32, 0x1439,
+ 0x7e33, 0x2df1,
+ 0x7e34, 0x1440,
+ 0x7e35, 0x1443,
+ 0x7e36, 0x2dfc,
+ 0x7e37, 0x1438,
+ 0x7e38, 0x2df3,
+ 0x7e39, 0x1441,
+ 0x7e3a, 0x2dfe,
+ 0x7e3b, 0x2dfb,
+ 0x7e3c, 0x2def,
+ 0x7e3d, 0x143c,
+ 0x7e3e, 0x1436,
+ 0x7e3f, 0x1444,
+ 0x7e40, 0x2df6,
+ 0x7e41, 0x143f,
+ 0x7e42, 0x2df0,
+ 0x7e43, 0x143a,
+ 0x7e44, 0x2dfd,
+ 0x7e45, 0x143e,
+ 0x7e46, 0x1437,
+ 0x7e47, 0x2df7,
+ 0x7e48, 0x1442,
+ 0x7e49, 0x2df5,
+ 0x7e4c, 0x2df9,
+ 0x7e50, 0x2f83,
+ 0x7e51, 0x2f89,
+ 0x7e52, 0x1511,
+ 0x7e53, 0x2f8c,
+ 0x7e54, 0x150c,
+ 0x7e56, 0x2f84,
+ 0x7e57, 0x2f8b,
+ 0x7e58, 0x2f86,
+ 0x7e59, 0x1512,
+ 0x7e5a, 0x150f,
+ 0x7e5c, 0x2f82,
+ 0x7e5e, 0x150e,
+ 0x7e5f, 0x2f88,
+ 0x7e60, 0x2f8a,
+ 0x7e61, 0x1510,
+ 0x7e62, 0x2f87,
+ 0x7e63, 0x2f85,
+ 0x7e65, 0x46d2,
+ 0x7e67, 0x3766,
+ 0x7e68, 0x30e3,
+ 0x7e69, 0x15ac,
+ 0x7e6b, 0x15a9,
+ 0x7e6d, 0x15aa,
+ 0x7e6e, 0x377b,
+ 0x7e6f, 0x30df,
+ 0x7e70, 0x30dd,
+ 0x7e72, 0x30e1,
+ 0x7e73, 0x15ae,
+ 0x7e74, 0x30e2,
+ 0x7e75, 0x30db,
+ 0x7e76, 0x30da,
+ 0x7e77, 0x30de,
+ 0x7e78, 0x30dc,
+ 0x7e79, 0x15ab,
+ 0x7e7a, 0x30e0,
+ 0x7e7b, 0x3214,
+ 0x7e7c, 0x1631,
+ 0x7e7d, 0x1630,
+ 0x7e7e, 0x3215,
+ 0x7e7f, 0x3e51,
+ 0x7e80, 0x3217,
+ 0x7e81, 0x3216,
+ 0x7e82, 0x1632,
+ 0x7e86, 0x32f0,
+ 0x7e87, 0x32ed,
+ 0x7e8a, 0x32ec,
+ 0x7e8b, 0x32ef,
+ 0x7e8c, 0x1683,
+ 0x7e8d, 0x32f1,
+ 0x7e8e, 0x3ec9,
+ 0x7e8f, 0x1682,
+ 0x7e91, 0x33a2,
+ 0x7e92, 0x469e,
+ 0x7e93, 0x1703,
+ 0x7e94, 0x1705,
+ 0x7e95, 0x342c,
+ 0x7e96, 0x1704,
+ 0x7e97, 0x3494,
+ 0x7e98, 0x34da,
+ 0x7e99, 0x34dc,
+ 0x7e9a, 0x34d9,
+ 0x7e9b, 0x34db,
+ 0x7e9c, 0x1759,
+ 0x7e9f, 0x48bb,
+ 0x7ea4, 0x455b,
+ 0x7eac, 0x455c,
+ 0x7eba, 0x455d,
+ 0x7ec7, 0x455e,
+ 0x7ecf, 0x455f,
+ 0x7edf, 0x4560,
+ 0x7f06, 0x4561,
+ 0x7f36, 0x03f9,
+ 0x7f37, 0x4562,
+ 0x7f38, 0x07d4,
+ 0x7f39, 0x1d1f,
+ 0x7f3a, 0x0979,
+ 0x7f3d, 0x0b61,
+ 0x7f3e, 0x2271,
+ 0x7f40, 0x3780,
+ 0x7f43, 0x2c26,
+ 0x7f44, 0x1446,
+ 0x7f45, 0x2dff,
+ 0x7f47, 0x3782,
+ 0x7f48, 0x1513,
+ 0x7f49, 0x3e69,
+ 0x7f4a, 0x30e5,
+ 0x7f4b, 0x30e4,
+ 0x7f4c, 0x1633,
+ 0x7f4d, 0x32f2,
+ 0x7f4e, 0x3b4f,
+ 0x7f4f, 0x33a3,
+ 0x7f50, 0x1726,
+ 0x7f51, 0x1812,
+ 0x7f52, 0x44f6,
+ 0x7f53, 0x44f9,
+ 0x7f54, 0x0668,
+ 0x7f55, 0x04fc,
+ 0x7f58, 0x1bc3,
+ 0x7f5b, 0x1dad,
+ 0x7f5c, 0x1da8,
+ 0x7f5d, 0x1dac,
+ 0x7f5e, 0x1daa,
+ 0x7f5f, 0x097a,
+ 0x7f60, 0x1dab,
+ 0x7f61, 0x1da9,
+ 0x7f63, 0x1ff3,
+ 0x7f65, 0x2273,
+ 0x7f67, 0x2511,
+ 0x7f69, 0x0ec5,
+ 0x7f6b, 0x2510,
+ 0x7f6c, 0x2513,
+ 0x7f6d, 0x250f,
+ 0x7f6e, 0x0ec4,
+ 0x7f70, 0x106e,
+ 0x7f71, 0x4007,
+ 0x7f72, 0x0ec7,
+ 0x7f73, 0x2796,
+ 0x7f75, 0x11e5,
+ 0x7f76, 0x29c2,
+ 0x7f77, 0x11e6,
+ 0x7f78, 0x3f7b,
+ 0x7f79, 0x1329,
+ 0x7f7a, 0x2c29,
+ 0x7f7b, 0x2c27,
+ 0x7f7d, 0x2e02,
+ 0x7f7e, 0x2e01,
+ 0x7f7f, 0x2e00,
+ 0x7f83, 0x30e6,
+ 0x7f85, 0x15af,
+ 0x7f86, 0x30e7,
+ 0x7f87, 0x33a4,
+ 0x7f88, 0x1727,
+ 0x7f89, 0x3495,
+ 0x7f8a, 0x03fa,
+ 0x7f8b, 0x066a,
+ 0x7f8c, 0x0669,
+ 0x7f8d, 0x1bc5,
+ 0x7f8e, 0x07d5,
+ 0x7f8f, 0x421c,
+ 0x7f91, 0x1bc4,
+ 0x7f92, 0x1daf,
+ 0x7f93, 0x43db,
+ 0x7f94, 0x097b,
+ 0x7f95, 0x1ff4,
+ 0x7f96, 0x1dae,
+ 0x7f97, 0x3786,
+ 0x7f9a, 0x0b63,
+ 0x7f9b, 0x1ff7,
+ 0x7f9c, 0x1ff5,
+ 0x7f9e, 0x0b62,
+ 0x7fa0, 0x2276,
+ 0x7fa2, 0x2275,
+ 0x7fa3, 0x3788,
+ 0x7fa4, 0x0eca,
+ 0x7fa5, 0x2515,
+ 0x7fa6, 0x2514,
+ 0x7fa7, 0x2516,
+ 0x7fa8, 0x0ec9,
+ 0x7fa9, 0x0ec8,
+ 0x7fac, 0x29c3,
+ 0x7fad, 0x29c5,
+ 0x7fae, 0x43dc,
+ 0x7faf, 0x11e7,
+ 0x7fb0, 0x29c4,
+ 0x7fb1, 0x2c2a,
+ 0x7fb2, 0x132a,
+ 0x7fb3, 0x2f8e,
+ 0x7fb4, 0x4739,
+ 0x7fb5, 0x2f8d,
+ 0x7fb6, 0x15b0,
+ 0x7fb7, 0x30e8,
+ 0x7fb8, 0x15b2,
+ 0x7fb9, 0x15b1,
+ 0x7fba, 0x3218,
+ 0x7fbb, 0x32f3,
+ 0x7fbc, 0x1684,
+ 0x7fbd, 0x03fb,
+ 0x7fbe, 0x1bc6,
+ 0x7fbf, 0x07d6,
+ 0x7fc0, 0x1db2,
+ 0x7fc1, 0x097d,
+ 0x7fc2, 0x1db1,
+ 0x7fc3, 0x1db0,
+ 0x7fc5, 0x097c,
+ 0x7fc7, 0x1ffd,
+ 0x7fc9, 0x1fff,
+ 0x7fca, 0x1ff8,
+ 0x7fcc, 0x0b64,
+ 0x7fcd, 0x1ffa,
+ 0x7fce, 0x0b65,
+ 0x7fcf, 0x1ffe,
+ 0x7fd0, 0x1ffb,
+ 0x7fd2, 0x0b66,
+ 0x7fd4, 0x0d1c,
+ 0x7fd7, 0x2278,
+ 0x7fdb, 0x2517,
+ 0x7fdd, 0x3b5e,
+ 0x7fde, 0x279a,
+ 0x7fdf, 0x1071,
+ 0x7fe0, 0x106f,
+ 0x7fe2, 0x2797,
+ 0x7fe5, 0x2799,
+ 0x7fe6, 0x29ca,
+ 0x7fe7, 0x46e9,
+ 0x7fe8, 0x29cb,
+ 0x7fe9, 0x11e8,
+ 0x7fea, 0x29c8,
+ 0x7feb, 0x29c7,
+ 0x7fec, 0x29c9,
+ 0x7fed, 0x29c6,
+ 0x7fee, 0x132d,
+ 0x7fef, 0x2c2b,
+ 0x7ff0, 0x132b,
+ 0x7ff2, 0x2e04,
+ 0x7ff3, 0x1447,
+ 0x7ff4, 0x2e03,
+ 0x7ff5, 0x2eff,
+ 0x7ff7, 0x2f8f,
+ 0x7ff9, 0x1514,
+ 0x7ffa, 0x378e,
+ 0x7ffb, 0x1515,
+ 0x7ffc, 0x1448,
+ 0x7ffd, 0x30e9,
+ 0x7fff, 0x3219,
+ 0x8000, 0x1634,
+ 0x8001, 0x03fc,
+ 0x8002, 0x44fd,
+ 0x8003, 0x03fd,
+ 0x8004, 0x097f,
+ 0x8005, 0x066b,
+ 0x8006, 0x097e,
+ 0x8007, 0x1bc7,
+ 0x8008, 0x3791,
+ 0x800b, 0x0d1e,
+ 0x800c, 0x03fe,
+ 0x800d, 0x07d8,
+ 0x800e, 0x1bc8,
+ 0x8010, 0x07d7,
+ 0x8011, 0x07d9,
+ 0x8012, 0x03ff,
+ 0x8014, 0x1bca,
+ 0x8015, 0x0981,
+ 0x8016, 0x1db3,
+ 0x8017, 0x0983,
+ 0x8018, 0x0980,
+ 0x8019, 0x0982,
+ 0x801b, 0x2002,
+ 0x801c, 0x0b67,
+ 0x801d, 0x3792,
+ 0x801e, 0x2001,
+ 0x801f, 0x2000,
+ 0x8020, 0x473c,
+ 0x8021, 0x2519,
+ 0x8024, 0x279b,
+ 0x8025, 0x473d,
+ 0x8026, 0x11e9,
+ 0x8028, 0x132e,
+ 0x8029, 0x2c2d,
+ 0x802a, 0x2c2c,
+ 0x802c, 0x2e05,
+ 0x802e, 0x473e,
+ 0x802f, 0x3794,
+ 0x8030, 0x32f4,
+ 0x8031, 0x473f,
+ 0x8033, 0x0400,
+ 0x8034, 0x18d8,
+ 0x8035, 0x1a27,
+ 0x8036, 0x07da,
+ 0x8037, 0x1bcb,
+ 0x8039, 0x1db5,
+ 0x803b, 0x3797,
+ 0x803d, 0x0984,
+ 0x803e, 0x1db4,
+ 0x803f, 0x0985,
+ 0x8043, 0x2004,
+ 0x8046, 0x0b69,
+ 0x8047, 0x2003,
+ 0x8048, 0x2005,
+ 0x804a, 0x0b68,
+ 0x804f, 0x227a,
+ 0x8051, 0x2279,
+ 0x8052, 0x0d1f,
+ 0x8054, 0x4740,
+ 0x8056, 0x0ecb,
+ 0x8058, 0x0ecc,
+ 0x805a, 0x1073,
+ 0x805b, 0x3fe5,
+ 0x805c, 0x279d,
+ 0x805d, 0x279c,
+ 0x805e, 0x1072,
+ 0x8061, 0x3799,
+ 0x8062, 0x3fe3,
+ 0x8063, 0x3fdc,
+ 0x8064, 0x29cc,
+ 0x8066, 0x3fdb,
+ 0x8067, 0x29cd,
+ 0x806c, 0x2c2e,
+ 0x806f, 0x144c,
+ 0x8070, 0x144b,
+ 0x8071, 0x1449,
+ 0x8073, 0x144d,
+ 0x8075, 0x2f91,
+ 0x8076, 0x1517,
+ 0x8077, 0x1516,
+ 0x8078, 0x30eb,
+ 0x8079, 0x321a,
+ 0x807d, 0x16d3,
+ 0x807e, 0x16d2,
+ 0x807f, 0x0401,
+ 0x8080, 0x44fe,
+ 0x8082, 0x1cec,
+ 0x8084, 0x0ece,
+ 0x8085, 0x0d20,
+ 0x8086, 0x0ecd,
+ 0x8087, 0x1074,
+ 0x8089, 0x0402,
+ 0x808a, 0x17b3,
+ 0x808b, 0x0403,
+ 0x808f, 0x1a28,
+ 0x8090, 0x18db,
+ 0x8092, 0x18dc,
+ 0x8093, 0x04fe,
+ 0x8095, 0x18d9,
+ 0x8096, 0x04fd,
+ 0x8098, 0x0500,
+ 0x8099, 0x18da,
+ 0x809a, 0x0502,
+ 0x809b, 0x0501,
+ 0x809c, 0x18dd,
+ 0x809d, 0x04ff,
+ 0x809f, 0x4576,
+ 0x80a1, 0x0670,
+ 0x80a2, 0x066e,
+ 0x80a3, 0x1a2a,
+ 0x80a5, 0x066d,
+ 0x80a7, 0x37a0,
+ 0x80a9, 0x0672,
+ 0x80aa, 0x0674,
+ 0x80ab, 0x0671,
+ 0x80ad, 0x1a2d,
+ 0x80ae, 0x1a29,
+ 0x80af, 0x0675,
+ 0x80b1, 0x066f,
+ 0x80b2, 0x0503,
+ 0x80b4, 0x0673,
+ 0x80b5, 0x1a2c,
+ 0x80b6, 0x3eae,
+ 0x80b7, 0x4743,
+ 0x80b8, 0x1a2b,
+ 0x80ba, 0x066c,
+ 0x80bc, 0x4572,
+ 0x80bd, 0x3e7b,
+ 0x80c2, 0x1bd1,
+ 0x80c3, 0x07de,
+ 0x80c5, 0x1bd3,
+ 0x80c6, 0x3b74,
+ 0x80c7, 0x1bcd,
+ 0x80c8, 0x1bd0,
+ 0x80c9, 0x1bd9,
+ 0x80ca, 0x1bd7,
+ 0x80cc, 0x07e0,
+ 0x80cd, 0x1bdd,
+ 0x80ce, 0x07e3,
+ 0x80cf, 0x1bda,
+ 0x80d0, 0x1bd2,
+ 0x80d1, 0x1bcf,
+ 0x80d4, 0x227d,
+ 0x80d5, 0x1bd8,
+ 0x80d6, 0x07db,
+ 0x80d7, 0x1bdb,
+ 0x80d8, 0x1bcc,
+ 0x80d9, 0x1bd5,
+ 0x80da, 0x07dd,
+ 0x80db, 0x07e2,
+ 0x80dc, 0x1bd6,
+ 0x80dd, 0x07e6,
+ 0x80de, 0x07e4,
+ 0x80e0, 0x1bce,
+ 0x80e1, 0x07e1,
+ 0x80e3, 0x1bd4,
+ 0x80e4, 0x07e5,
+ 0x80e5, 0x07dc,
+ 0x80e6, 0x1bdc,
+ 0x80e9, 0x4744,
+ 0x80ec, 0x45e9,
+ 0x80ed, 0x098a,
+ 0x80ef, 0x0993,
+ 0x80f0, 0x0988,
+ 0x80f1, 0x0986,
+ 0x80f2, 0x1db7,
+ 0x80f3, 0x098e,
+ 0x80f4, 0x098b,
+ 0x80f5, 0x1db9,
+ 0x80f6, 0x4574,
+ 0x80f8, 0x098d,
+ 0x80f9, 0x1db8,
+ 0x80fa, 0x1db6,
+ 0x80fb, 0x1dbb,
+ 0x80fc, 0x0992,
+ 0x80fd, 0x0990,
+ 0x80fe, 0x227c,
+ 0x8100, 0x1dbc,
+ 0x8101, 0x1dba,
+ 0x8102, 0x0987,
+ 0x8103, 0x3fe7,
+ 0x8105, 0x0989,
+ 0x8106, 0x098c,
+ 0x8107, 0x37a2,
+ 0x8108, 0x098f,
+ 0x8109, 0x3b75,
+ 0x810a, 0x0991,
+ 0x810c, 0x4746,
+ 0x810e, 0x4747,
+ 0x8112, 0x4748,
+ 0x8114, 0x4749,
+ 0x8115, 0x200f,
+ 0x8116, 0x0b6b,
+ 0x8117, 0x3e6d,
+ 0x8118, 0x2006,
+ 0x8119, 0x2008,
+ 0x811a, 0x37a3,
+ 0x811b, 0x2009,
+ 0x811d, 0x2011,
+ 0x811e, 0x200d,
+ 0x811f, 0x200b,
+ 0x8121, 0x200e,
+ 0x8122, 0x2012,
+ 0x8123, 0x0b6c,
+ 0x8124, 0x0b70,
+ 0x8125, 0x2007,
+ 0x8127, 0x2010,
+ 0x8129, 0x0b6e,
+ 0x812a, 0x3a39,
+ 0x812b, 0x0b6d,
+ 0x812c, 0x200c,
+ 0x812d, 0x200a,
+ 0x812f, 0x0b6a,
+ 0x8130, 0x0b6f,
+ 0x8132, 0x3e79,
+ 0x8134, 0x45ec,
+ 0x8137, 0x3b72,
+ 0x8139, 0x0d26,
+ 0x813a, 0x2285,
+ 0x813d, 0x2283,
+ 0x813e, 0x0d28,
+ 0x8142, 0x3b76,
+ 0x8143, 0x227e,
+ 0x8144, 0x2527,
+ 0x8146, 0x0d27,
+ 0x8147, 0x2282,
+ 0x8148, 0x3e76,
+ 0x814a, 0x227f,
+ 0x814b, 0x0d23,
+ 0x814c, 0x0d29,
+ 0x814d, 0x2284,
+ 0x814e, 0x0d25,
+ 0x814f, 0x2281,
+ 0x8150, 0x1075,
+ 0x8151, 0x0d24,
+ 0x8152, 0x2280,
+ 0x8153, 0x0d2a,
+ 0x8154, 0x0d22,
+ 0x8155, 0x0d21,
+ 0x8156, 0x474c,
+ 0x8159, 0x474d,
+ 0x815b, 0x251f,
+ 0x815c, 0x251d,
+ 0x815e, 0x2523,
+ 0x8160, 0x251b,
+ 0x8161, 0x2528,
+ 0x8162, 0x2520,
+ 0x8164, 0x251a,
+ 0x8165, 0x0ed2,
+ 0x8166, 0x0ed8,
+ 0x8167, 0x2525,
+ 0x8169, 0x251e,
+ 0x816b, 0x0ed5,
+ 0x816d, 0x43c4,
+ 0x816e, 0x0ed3,
+ 0x816f, 0x2526,
+ 0x8170, 0x0ed0,
+ 0x8171, 0x0ecf,
+ 0x8172, 0x2521,
+ 0x8173, 0x0ed4,
+ 0x8174, 0x0d2b,
+ 0x8176, 0x2524,
+ 0x8177, 0x251c,
+ 0x8178, 0x0ed1,
+ 0x8179, 0x0ed6,
+ 0x817c, 0x4750,
+ 0x817f, 0x107a,
+ 0x8180, 0x1076,
+ 0x8182, 0x107b,
+ 0x8183, 0x27a0,
+ 0x8184, 0x43c5,
+ 0x8186, 0x279f,
+ 0x8187, 0x27a1,
+ 0x8188, 0x1078,
+ 0x8189, 0x279e,
+ 0x818a, 0x1079,
+ 0x818b, 0x27a4,
+ 0x818c, 0x27a3,
+ 0x818d, 0x27a2,
+ 0x818f, 0x1077,
+ 0x8193, 0x43c6,
+ 0x8195, 0x29d1,
+ 0x8197, 0x29d4,
+ 0x8198, 0x11ef,
+ 0x8199, 0x29d3,
+ 0x819a, 0x11ee,
+ 0x819b, 0x11ea,
+ 0x819e, 0x29d0,
+ 0x819f, 0x29cf,
+ 0x81a0, 0x11ed,
+ 0x81a2, 0x29d2,
+ 0x81a3, 0x29ce,
+ 0x81a5, 0x4753,
+ 0x81a6, 0x2c30,
+ 0x81a7, 0x2c3a,
+ 0x81a8, 0x1331,
+ 0x81a9, 0x1330,
+ 0x81aa, 0x4364,
+ 0x81ab, 0x2c34,
+ 0x81ac, 0x2c36,
+ 0x81ae, 0x2c31,
+ 0x81b0, 0x2c35,
+ 0x81b1, 0x2c2f,
+ 0x81b2, 0x2c38,
+ 0x81b3, 0x132f,
+ 0x81b4, 0x2c37,
+ 0x81b5, 0x2c33,
+ 0x81b6, 0x3eb2,
+ 0x81b7, 0x2c39,
+ 0x81b9, 0x2c32,
+ 0x81ba, 0x1450,
+ 0x81bb, 0x2e06,
+ 0x81bc, 0x2e0c,
+ 0x81bd, 0x1454,
+ 0x81be, 0x1456,
+ 0x81bf, 0x1453,
+ 0x81c0, 0x1452,
+ 0x81c1, 0x4755,
+ 0x81c2, 0x1451,
+ 0x81c3, 0x144f,
+ 0x81c4, 0x2e07,
+ 0x81c5, 0x2e0a,
+ 0x81c6, 0x144e,
+ 0x81c7, 0x2e0b,
+ 0x81c8, 0x3fee,
+ 0x81c9, 0x1455,
+ 0x81ca, 0x2e09,
+ 0x81cc, 0x2e08,
+ 0x81cd, 0x1518,
+ 0x81cf, 0x1519,
+ 0x81d0, 0x2f94,
+ 0x81d1, 0x2f92,
+ 0x81d5, 0x30ed,
+ 0x81d7, 0x30ec,
+ 0x81d8, 0x15b3,
+ 0x81d9, 0x321c,
+ 0x81da, 0x1635,
+ 0x81db, 0x321b,
+ 0x81dd, 0x32f5,
+ 0x81de, 0x33a5,
+ 0x81df, 0x16d4,
+ 0x81e0, 0x34dd,
+ 0x81e2, 0x1706,
+ 0x81e3, 0x0405,
+ 0x81e4, 0x4756,
+ 0x81e5, 0x0676,
+ 0x81e6, 0x2286,
+ 0x81e7, 0x107c,
+ 0x81e8, 0x1457,
+ 0x81e9, 0x2e0d,
+ 0x81ea, 0x0406,
+ 0x81ec, 0x0995,
+ 0x81ed, 0x0994,
+ 0x81ee, 0x2287,
+ 0x81ef, 0x42d1,
+ 0x81f2, 0x2c3b,
+ 0x81f3, 0x0407,
+ 0x81f4, 0x07e7,
+ 0x81f6, 0x3d61,
+ 0x81f7, 0x2288,
+ 0x81fa, 0x107d,
+ 0x81fb, 0x1332,
+ 0x81fc, 0x0408,
+ 0x81fe, 0x0677,
+ 0x81ff, 0x1bde,
+ 0x8200, 0x0996,
+ 0x8201, 0x1dbd,
+ 0x8202, 0x0b71,
+ 0x8204, 0x228b,
+ 0x8205, 0x0ed9,
+ 0x8207, 0x107e,
+ 0x8208, 0x1333,
+ 0x8209, 0x1458,
+ 0x820a, 0x151a,
+ 0x820b, 0x30ee,
+ 0x820c, 0x0409,
+ 0x820d, 0x0678,
+ 0x8210, 0x0997,
+ 0x8211, 0x2013,
+ 0x8212, 0x0d2c,
+ 0x8214, 0x107f,
+ 0x8215, 0x27a5,
+ 0x8216, 0x29d5,
+ 0x8218, 0x37aa,
+ 0x821a, 0x3fe1,
+ 0x821b, 0x040a,
+ 0x821c, 0x0d2d,
+ 0x821d, 0x2529,
+ 0x821e, 0x1080,
+ 0x821f, 0x040b,
+ 0x8220, 0x1a2e,
+ 0x8221, 0x1bdf,
+ 0x8222, 0x07e8,
+ 0x8225, 0x1dbf,
+ 0x8226, 0x420d,
+ 0x8228, 0x099a,
+ 0x8229, 0x37b0,
+ 0x822a, 0x0998,
+ 0x822c, 0x099b,
+ 0x822d, 0x3ed0,
+ 0x822f, 0x1dbe,
+ 0x8232, 0x2018,
+ 0x8233, 0x2015,
+ 0x8234, 0x2017,
+ 0x8235, 0x0b72,
+ 0x8236, 0x0b74,
+ 0x8237, 0x0b73,
+ 0x8238, 0x2014,
+ 0x8239, 0x0b75,
+ 0x823a, 0x2016,
+ 0x823c, 0x228c,
+ 0x823e, 0x4582,
+ 0x823f, 0x228e,
+ 0x8240, 0x252c,
+ 0x8242, 0x252d,
+ 0x8244, 0x252b,
+ 0x8245, 0x252e,
+ 0x8247, 0x0eda,
+ 0x8249, 0x252a,
+ 0x824b, 0x1081,
+ 0x824e, 0x29da,
+ 0x824f, 0x29d6,
+ 0x8250, 0x29d9,
+ 0x8251, 0x29db,
+ 0x8252, 0x29d8,
+ 0x8253, 0x29d7,
+ 0x8254, 0x4757,
+ 0x8255, 0x2c3c,
+ 0x8258, 0x1334,
+ 0x825a, 0x2e0f,
+ 0x825b, 0x2e0e,
+ 0x825c, 0x2e10,
+ 0x825e, 0x2f96,
+ 0x825f, 0x2f95,
+ 0x8261, 0x30f0,
+ 0x8262, 0x3b7a,
+ 0x8263, 0x30f1,
+ 0x8264, 0x30ef,
+ 0x8265, 0x3b7b,
+ 0x8266, 0x1636,
+ 0x8268, 0x321d,
+ 0x826b, 0x33a6,
+ 0x826c, 0x342d,
+ 0x826d, 0x3496,
+ 0x826e, 0x040c,
+ 0x826f, 0x0504,
+ 0x8271, 0x1459,
+ 0x8272, 0x040d,
+ 0x8274, 0x2019,
+ 0x8275, 0x228f,
+ 0x8276, 0x4759,
+ 0x8277, 0x172e,
+ 0x8278, 0x1813,
+ 0x8279, 0x4722,
+ 0x827a, 0x4563,
+ 0x827b, 0x37c8,
+ 0x827c, 0x1814,
+ 0x827d, 0x1816,
+ 0x827e, 0x040e,
+ 0x827f, 0x1817,
+ 0x8280, 0x1815,
+ 0x8283, 0x18e5,
+ 0x8285, 0x18e0,
+ 0x8287, 0x4132,
+ 0x828a, 0x18e4,
+ 0x828b, 0x0506,
+ 0x828d, 0x0507,
+ 0x828e, 0x18e1,
+ 0x828f, 0x18df,
+ 0x8290, 0x18de,
+ 0x8291, 0x18e2,
+ 0x8292, 0x0505,
+ 0x8293, 0x18e3,
+ 0x8294, 0x1be0,
+ 0x8298, 0x1a33,
+ 0x8299, 0x067b,
+ 0x829a, 0x1a32,
+ 0x829b, 0x1a34,
+ 0x829d, 0x067a,
+ 0x829e, 0x1a39,
+ 0x829f, 0x067e,
+ 0x82a0, 0x1a2f,
+ 0x82a1, 0x1a3d,
+ 0x82a2, 0x1a43,
+ 0x82a3, 0x0685,
+ 0x82a4, 0x1a40,
+ 0x82a5, 0x0682,
+ 0x82a6, 0x3d73,
+ 0x82a7, 0x1a36,
+ 0x82a8, 0x1a3c,
+ 0x82a9, 0x1a3e,
+ 0x82aa, 0x37bc,
+ 0x82ab, 0x1a31,
+ 0x82ac, 0x0681,
+ 0x82ad, 0x067c,
+ 0x82ae, 0x1a37,
+ 0x82af, 0x0683,
+ 0x82b0, 0x0686,
+ 0x82b1, 0x0680,
+ 0x82b3, 0x0679,
+ 0x82b4, 0x1a3b,
+ 0x82b5, 0x1a35,
+ 0x82b6, 0x1a42,
+ 0x82b7, 0x0688,
+ 0x82b8, 0x0684,
+ 0x82b9, 0x067f,
+ 0x82ba, 0x1a3a,
+ 0x82bb, 0x099c,
+ 0x82bc, 0x1a38,
+ 0x82bd, 0x067d,
+ 0x82be, 0x0687,
+ 0x82c0, 0x1a30,
+ 0x82c2, 0x1a3f,
+ 0x82c3, 0x1a41,
+ 0x82c4, 0x45e3,
+ 0x82ca, 0x475a,
+ 0x82cf, 0x4564,
+ 0x82d0, 0x37c1,
+ 0x82d1, 0x07f9,
+ 0x82d2, 0x07f3,
+ 0x82d3, 0x07fb,
+ 0x82d4, 0x07f8,
+ 0x82d5, 0x1be7,
+ 0x82d6, 0x1bea,
+ 0x82d7, 0x07f4,
+ 0x82d8, 0x475b,
+ 0x82d9, 0x1be1,
+ 0x82db, 0x07ed,
+ 0x82dc, 0x07f7,
+ 0x82de, 0x07fa,
+ 0x82df, 0x07fc,
+ 0x82e0, 0x1bf6,
+ 0x82e1, 0x1bed,
+ 0x82e2, 0x37c9,
+ 0x82e3, 0x07ec,
+ 0x82e4, 0x1bf5,
+ 0x82e5, 0x07f0,
+ 0x82e6, 0x07ee,
+ 0x82e7, 0x07e9,
+ 0x82e8, 0x1be5,
+ 0x82ea, 0x1bf4,
+ 0x82eb, 0x1be9,
+ 0x82ec, 0x1bec,
+ 0x82ed, 0x1bf9,
+ 0x82ee, 0x4018,
+ 0x82ef, 0x07fd,
+ 0x82f0, 0x1bf3,
+ 0x82f1, 0x07f5,
+ 0x82f2, 0x1bee,
+ 0x82f3, 0x1bf8,
+ 0x82f4, 0x1beb,
+ 0x82f5, 0x1bef,
+ 0x82f6, 0x1bf2,
+ 0x82f7, 0x3e77,
+ 0x82f9, 0x1be3,
+ 0x82fa, 0x1bf7,
+ 0x82fb, 0x1bf1,
+ 0x82fc, 0x412d,
+ 0x82fd, 0x3d92,
+ 0x82fe, 0x1be2,
+ 0x82ff, 0x43de,
+ 0x8300, 0x1be6,
+ 0x8301, 0x07f6,
+ 0x8302, 0x07f1,
+ 0x8303, 0x07ea,
+ 0x8304, 0x07ef,
+ 0x8305, 0x07eb,
+ 0x8306, 0x07fe,
+ 0x8307, 0x1be4,
+ 0x8308, 0x1dd0,
+ 0x8309, 0x07f2,
+ 0x830b, 0x3eb6,
+ 0x830c, 0x1bf0,
+ 0x830d, 0x1a7d,
+ 0x8316, 0x1dd3,
+ 0x8317, 0x09aa,
+ 0x8318, 0x37ca,
+ 0x8319, 0x1dc3,
+ 0x831a, 0x37c2,
+ 0x831b, 0x1dce,
+ 0x831c, 0x1dca,
+ 0x831d, 0x37d1,
+ 0x831e, 0x1ddd,
+ 0x8320, 0x1dd5,
+ 0x8322, 0x1dcb,
+ 0x8324, 0x1dd4,
+ 0x8325, 0x1dc5,
+ 0x8326, 0x1dc9,
+ 0x8327, 0x1de0,
+ 0x8328, 0x09ad,
+ 0x8329, 0x1dd8,
+ 0x832a, 0x1dcf,
+ 0x832b, 0x099d,
+ 0x832c, 0x1dde,
+ 0x832d, 0x1dc1,
+ 0x832f, 0x1dd7,
+ 0x8331, 0x09ac,
+ 0x8332, 0x09a7,
+ 0x8333, 0x1dc0,
+ 0x8334, 0x09a5,
+ 0x8335, 0x09a4,
+ 0x8336, 0x09a9,
+ 0x8337, 0x1dd6,
+ 0x8338, 0x09a1,
+ 0x8339, 0x09a8,
+ 0x833a, 0x1be8,
+ 0x833b, 0x2290,
+ 0x833c, 0x1dd1,
+ 0x833d, 0x3d2a,
+ 0x833f, 0x1dc7,
+ 0x8340, 0x09ab,
+ 0x8341, 0x1dc8,
+ 0x8342, 0x1dcc,
+ 0x8343, 0x09ae,
+ 0x8344, 0x1dc2,
+ 0x8345, 0x1dda,
+ 0x8347, 0x1dd9,
+ 0x8348, 0x1de1,
+ 0x8349, 0x09a3,
+ 0x834a, 0x09a0,
+ 0x834b, 0x1ddf,
+ 0x834c, 0x1ddb,
+ 0x834d, 0x1dd2,
+ 0x834e, 0x1dcd,
+ 0x834f, 0x09a6,
+ 0x8350, 0x09a2,
+ 0x8351, 0x1dc4,
+ 0x8352, 0x099e,
+ 0x8353, 0x1ddc,
+ 0x8354, 0x099f,
+ 0x8356, 0x1dc6,
+ 0x8357, 0x475d,
+ 0x8362, 0x37b6,
+ 0x8363, 0x41eb,
+ 0x8366, 0x3e1e,
+ 0x836f, 0x4565,
+ 0x8373, 0x201f,
+ 0x8374, 0x2021,
+ 0x8375, 0x2026,
+ 0x8376, 0x203a,
+ 0x8377, 0x0b83,
+ 0x8378, 0x0b79,
+ 0x837a, 0x201e,
+ 0x837b, 0x0b84,
+ 0x837d, 0x2029,
+ 0x837e, 0x2030,
+ 0x837f, 0x2036,
+ 0x8381, 0x2023,
+ 0x8383, 0x202a,
+ 0x8385, 0x37d3,
+ 0x8386, 0x0b86,
+ 0x8387, 0x2038,
+ 0x8388, 0x2033,
+ 0x8389, 0x0b81,
+ 0x838a, 0x0b7f,
+ 0x838b, 0x202f,
+ 0x838c, 0x202b,
+ 0x838d, 0x201d,
+ 0x838e, 0x0b76,
+ 0x838f, 0x2022,
+ 0x8390, 0x201a,
+ 0x8391, 0x37ec,
+ 0x8392, 0x0b7e,
+ 0x8393, 0x0b80,
+ 0x8394, 0x2027,
+ 0x8395, 0x2024,
+ 0x8396, 0x0b7b,
+ 0x8397, 0x2034,
+ 0x8398, 0x0b78,
+ 0x8399, 0x2025,
+ 0x839a, 0x22b9,
+ 0x839b, 0x202d,
+ 0x839c, 0x374d,
+ 0x839d, 0x202c,
+ 0x839e, 0x0b77,
+ 0x83a0, 0x0b82,
+ 0x83a2, 0x0b7a,
+ 0x83a3, 0x201b,
+ 0x83a4, 0x2020,
+ 0x83a5, 0x2031,
+ 0x83a6, 0x2037,
+ 0x83a7, 0x0b87,
+ 0x83a8, 0x201c,
+ 0x83a9, 0x2028,
+ 0x83aa, 0x202e,
+ 0x83ab, 0x0b7d,
+ 0x83ac, 0x37d6,
+ 0x83ae, 0x2039,
+ 0x83af, 0x2032,
+ 0x83b0, 0x2035,
+ 0x83b9, 0x42a7,
+ 0x83bd, 0x0b7c,
+ 0x83be, 0x3f59,
+ 0x83bf, 0x22a0,
+ 0x83c0, 0x2294,
+ 0x83c1, 0x0d35,
+ 0x83c2, 0x22b1,
+ 0x83c3, 0x22ba,
+ 0x83c4, 0x22bd,
+ 0x83c5, 0x0d33,
+ 0x83c6, 0x229c,
+ 0x83c7, 0x22b5,
+ 0x83c8, 0x229d,
+ 0x83c9, 0x22ab,
+ 0x83ca, 0x0d40,
+ 0x83cb, 0x22a7,
+ 0x83cc, 0x0d3d,
+ 0x83cd, 0x4055,
+ 0x83ce, 0x22a8,
+ 0x83cf, 0x2291,
+ 0x83d1, 0x22b6,
+ 0x83d3, 0x37d8,
+ 0x83d4, 0x0d46,
+ 0x83d5, 0x22b3,
+ 0x83d6, 0x22a9,
+ 0x83d7, 0x22bf,
+ 0x83d8, 0x22a4,
+ 0x83d9, 0x254e,
+ 0x83db, 0x22c2,
+ 0x83dc, 0x0d44,
+ 0x83dd, 0x22a2,
+ 0x83de, 0x22ae,
+ 0x83df, 0x0d47,
+ 0x83e0, 0x0d32,
+ 0x83e1, 0x22a6,
+ 0x83e2, 0x22c0,
+ 0x83e3, 0x229f,
+ 0x83e4, 0x2298,
+ 0x83e5, 0x22a3,
+ 0x83e7, 0x2297,
+ 0x83e8, 0x2295,
+ 0x83e9, 0x0d2e,
+ 0x83ea, 0x22b7,
+ 0x83eb, 0x229e,
+ 0x83ec, 0x22bb,
+ 0x83ed, 0x3d2c,
+ 0x83ee, 0x22bc,
+ 0x83ef, 0x0d36,
+ 0x83f0, 0x0d3b,
+ 0x83f1, 0x0d37,
+ 0x83f2, 0x0d3f,
+ 0x83f3, 0x22b2,
+ 0x83f4, 0x0d38,
+ 0x83f5, 0x22aa,
+ 0x83f6, 0x229a,
+ 0x83f8, 0x0d30,
+ 0x83f9, 0x2292,
+ 0x83fa, 0x22b4,
+ 0x83fb, 0x22be,
+ 0x83fc, 0x2299,
+ 0x83fd, 0x0d3e,
+ 0x83fe, 0x22c3,
+ 0x83ff, 0x22a5,
+ 0x8401, 0x22a1,
+ 0x8403, 0x0d2f,
+ 0x8404, 0x0d43,
+ 0x8405, 0x475f,
+ 0x8406, 0x22b0,
+ 0x8407, 0x0d45,
+ 0x8409, 0x22ac,
+ 0x840a, 0x0d3a,
+ 0x840b, 0x0d34,
+ 0x840c, 0x0d3c,
+ 0x840d, 0x0d31,
+ 0x840e, 0x0d42,
+ 0x840f, 0x22ad,
+ 0x8410, 0x229b,
+ 0x8411, 0x22af,
+ 0x8412, 0x2296,
+ 0x8413, 0x22b8,
+ 0x8414, 0x3c10,
+ 0x8416, 0x4037,
+ 0x8418, 0x3e7a,
+ 0x841b, 0x22c1,
+ 0x841c, 0x3eb3,
+ 0x8420, 0x3c55,
+ 0x8421, 0x3751,
+ 0x8423, 0x2293,
+ 0x8424, 0x4951,
+ 0x8426, 0x46d8,
+ 0x8429, 0x254d,
+ 0x842b, 0x2563,
+ 0x842c, 0x0eac,
+ 0x842d, 0x2552,
+ 0x842e, 0x422d,
+ 0x842f, 0x2550,
+ 0x8430, 0x253b,
+ 0x8431, 0x0ede,
+ 0x8432, 0x254b,
+ 0x8433, 0x255f,
+ 0x8434, 0x2547,
+ 0x8435, 0x0ee6,
+ 0x8436, 0x255e,
+ 0x8437, 0x2545,
+ 0x8438, 0x0d41,
+ 0x8439, 0x2555,
+ 0x843a, 0x2546,
+ 0x843b, 0x255c,
+ 0x843c, 0x0ee5,
+ 0x843d, 0x0edd,
+ 0x843e, 0x3d21,
+ 0x843f, 0x2530,
+ 0x8440, 0x2538,
+ 0x8442, 0x2551,
+ 0x8443, 0x2549,
+ 0x8444, 0x2562,
+ 0x8445, 0x254c,
+ 0x8446, 0x0eeb,
+ 0x8447, 0x255d,
+ 0x8448, 0x4718,
+ 0x8449, 0x0ee2,
+ 0x844a, 0x37e4,
+ 0x844b, 0x254f,
+ 0x844c, 0x2557,
+ 0x844d, 0x253c,
+ 0x844e, 0x2556,
+ 0x8450, 0x2567,
+ 0x8451, 0x2537,
+ 0x8452, 0x2558,
+ 0x8453, 0x3b7d,
+ 0x8454, 0x2565,
+ 0x8455, 0x398b,
+ 0x8456, 0x2531,
+ 0x8457, 0x0d39,
+ 0x8458, 0x37de,
+ 0x8459, 0x253f,
+ 0x845a, 0x253e,
+ 0x845b, 0x0ee4,
+ 0x845c, 0x3edb,
+ 0x845d, 0x2542,
+ 0x845e, 0x2544,
+ 0x845f, 0x2553,
+ 0x8460, 0x2564,
+ 0x8461, 0x0ee7,
+ 0x8462, 0x42da,
+ 0x8463, 0x0ee8,
+ 0x8464, 0x4761,
+ 0x8465, 0x2536,
+ 0x8466, 0x0ee0,
+ 0x8467, 0x253a,
+ 0x8468, 0x2560,
+ 0x8469, 0x0ee9,
+ 0x846b, 0x0ee1,
+ 0x846c, 0x0ee3,
+ 0x846d, 0x0eea,
+ 0x846e, 0x2566,
+ 0x846f, 0x2559,
+ 0x8470, 0x2554,
+ 0x8471, 0x37e0,
+ 0x8472, 0x3c93,
+ 0x8473, 0x2541,
+ 0x8474, 0x2540,
+ 0x8475, 0x0edf,
+ 0x8476, 0x2532,
+ 0x8477, 0x0edc,
+ 0x8478, 0x254a,
+ 0x8479, 0x2533,
+ 0x847a, 0x2548,
+ 0x847d, 0x253d,
+ 0x847e, 0x2561,
+ 0x847f, 0x394e,
+ 0x8480, 0x3b6e,
+ 0x8482, 0x0edb,
+ 0x8486, 0x2539,
+ 0x8488, 0x4762,
+ 0x848d, 0x2535,
+ 0x848e, 0x255b,
+ 0x848f, 0x2534,
+ 0x8490, 0x108e,
+ 0x8491, 0x27cd,
+ 0x8492, 0x3756,
+ 0x8493, 0x37ee,
+ 0x8494, 0x27bc,
+ 0x8496, 0x3b1d,
+ 0x8497, 0x27a6,
+ 0x8498, 0x27c4,
+ 0x8499, 0x1086,
+ 0x849a, 0x27b5,
+ 0x849b, 0x27bf,
+ 0x849c, 0x1089,
+ 0x849d, 0x27b8,
+ 0x849e, 0x1087,
+ 0x849f, 0x27a9,
+ 0x84a0, 0x27c7,
+ 0x84a1, 0x27a8,
+ 0x84a2, 0x27bb,
+ 0x84a3, 0x3b9e,
+ 0x84a4, 0x27a7,
+ 0x84a7, 0x27b9,
+ 0x84a8, 0x27c2,
+ 0x84a9, 0x27c0,
+ 0x84aa, 0x27b4,
+ 0x84ab, 0x27af,
+ 0x84ac, 0x27ad,
+ 0x84ad, 0x3d8c,
+ 0x84ae, 0x27ae,
+ 0x84af, 0x27c1,
+ 0x84b0, 0x27cc,
+ 0x84b1, 0x27b6,
+ 0x84b2, 0x1088,
+ 0x84b4, 0x27b1,
+ 0x84b6, 0x27c5,
+ 0x84b8, 0x108b,
+ 0x84b9, 0x27b0,
+ 0x84ba, 0x27aa,
+ 0x84bb, 0x27ba,
+ 0x84bc, 0x108f,
+ 0x84bd, 0x3c4c,
+ 0x84be, 0x4764,
+ 0x84bf, 0x1083,
+ 0x84c0, 0x108c,
+ 0x84c1, 0x27b2,
+ 0x84c2, 0x27ac,
+ 0x84c4, 0x1085,
+ 0x84c5, 0x255a,
+ 0x84c6, 0x1084,
+ 0x84c7, 0x27bd,
+ 0x84c9, 0x1082,
+ 0x84ca, 0x1091,
+ 0x84cb, 0x108a,
+ 0x84cc, 0x27be,
+ 0x84cd, 0x27b3,
+ 0x84ce, 0x27ab,
+ 0x84cf, 0x27c6,
+ 0x84d0, 0x27b7,
+ 0x84d1, 0x1090,
+ 0x84d2, 0x27ca,
+ 0x84d3, 0x108d,
+ 0x84d4, 0x27c9,
+ 0x84d6, 0x27c3,
+ 0x84d7, 0x27c8,
+ 0x84da, 0x3ff5,
+ 0x84db, 0x27cb,
+ 0x84de, 0x37ea,
+ 0x84e1, 0x4765,
+ 0x84e2, 0x37b5,
+ 0x84e4, 0x37ef,
+ 0x84e5, 0x3bd0,
+ 0x84e7, 0x2a03,
+ 0x84e9, 0x29f7,
+ 0x84ea, 0x29f6,
+ 0x84eb, 0x29f2,
+ 0x84ec, 0x11fb,
+ 0x84ee, 0x11f3,
+ 0x84ef, 0x2a06,
+ 0x84f0, 0x2a05,
+ 0x84f1, 0x252f,
+ 0x84f2, 0x29ef,
+ 0x84f3, 0x29f3,
+ 0x84f4, 0x29ed,
+ 0x84f6, 0x2a00,
+ 0x84f7, 0x29f1,
+ 0x84f8, 0x4766,
+ 0x84f9, 0x2a07,
+ 0x84fa, 0x29ea,
+ 0x84fb, 0x29e8,
+ 0x84fc, 0x29f4,
+ 0x84fd, 0x29fe,
+ 0x84fe, 0x29f9,
+ 0x84ff, 0x11fd,
+ 0x8500, 0x29df,
+ 0x8502, 0x29fd,
+ 0x8503, 0x398a,
+ 0x8505, 0x40eb,
+ 0x8506, 0x11fe,
+ 0x8507, 0x2543,
+ 0x8508, 0x29eb,
+ 0x8509, 0x29e2,
+ 0x850a, 0x29e5,
+ 0x850b, 0x2a0b,
+ 0x850c, 0x29ec,
+ 0x850d, 0x29e3,
+ 0x850e, 0x29e1,
+ 0x850f, 0x29de,
+ 0x8510, 0x4767,
+ 0x8511, 0x11f7,
+ 0x8512, 0x29f5,
+ 0x8513, 0x11f6,
+ 0x8514, 0x11fa,
+ 0x8515, 0x29f0,
+ 0x8516, 0x29f8,
+ 0x8517, 0x11f0,
+ 0x8518, 0x2a08,
+ 0x8519, 0x2a0c,
+ 0x851a, 0x11f2,
+ 0x851c, 0x29e7,
+ 0x851d, 0x29fb,
+ 0x851e, 0x29ff,
+ 0x851f, 0x29e4,
+ 0x8520, 0x2a09,
+ 0x8521, 0x11f9,
+ 0x8523, 0x11f8,
+ 0x8524, 0x29dc,
+ 0x8525, 0x11fc,
+ 0x8526, 0x2a02,
+ 0x8527, 0x29e6,
+ 0x8528, 0x29fa,
+ 0x8529, 0x29e0,
+ 0x852a, 0x29ee,
+ 0x852b, 0x29e9,
+ 0x852c, 0x11f4,
+ 0x852e, 0x29fc,
+ 0x852f, 0x2a0d,
+ 0x8530, 0x2a0a,
+ 0x8531, 0x2a01,
+ 0x8533, 0x4228,
+ 0x8534, 0x37f4,
+ 0x8538, 0x4768,
+ 0x853b, 0x29dd,
+ 0x853d, 0x11f1,
+ 0x853e, 0x2c4f,
+ 0x8540, 0x2c46,
+ 0x8541, 0x2c49,
+ 0x8542, 0x4062,
+ 0x8543, 0x133b,
+ 0x8544, 0x2c4b,
+ 0x8545, 0x2c40,
+ 0x8546, 0x2c47,
+ 0x8547, 0x2c4d,
+ 0x8548, 0x1338,
+ 0x8549, 0x133c,
+ 0x854a, 0x1336,
+ 0x854b, 0x37c0,
+ 0x854c, 0x400f,
+ 0x854d, 0x2c42,
+ 0x854e, 0x2c52,
+ 0x8551, 0x2c4c,
+ 0x8552, 0x4769,
+ 0x8553, 0x2c43,
+ 0x8554, 0x2c5b,
+ 0x8555, 0x2c55,
+ 0x8556, 0x2c3f,
+ 0x8557, 0x2e23,
+ 0x8558, 0x2c45,
+ 0x8559, 0x1337,
+ 0x855a, 0x37db,
+ 0x855b, 0x2c50,
+ 0x855d, 0x2c5a,
+ 0x855e, 0x133f,
+ 0x8560, 0x2c57,
+ 0x8561, 0x2c44,
+ 0x8562, 0x2c4a,
+ 0x8563, 0x2c4e,
+ 0x8564, 0x2c48,
+ 0x8565, 0x2c5c,
+ 0x8566, 0x2c59,
+ 0x8567, 0x2c56,
+ 0x8568, 0x1339,
+ 0x856a, 0x133e,
+ 0x856b, 0x2c41,
+ 0x856c, 0x2c5d,
+ 0x856d, 0x133d,
+ 0x856e, 0x2c53,
+ 0x856f, 0x476b,
+ 0x8571, 0x2c51,
+ 0x8573, 0x37f8,
+ 0x8575, 0x2c54,
+ 0x8576, 0x2e30,
+ 0x8577, 0x2e1d,
+ 0x8578, 0x2e22,
+ 0x8579, 0x2e2f,
+ 0x857a, 0x2e21,
+ 0x857b, 0x2e19,
+ 0x857c, 0x2e1e,
+ 0x857e, 0x145c,
+ 0x8580, 0x2e12,
+ 0x8581, 0x2e2a,
+ 0x8582, 0x2e2c,
+ 0x8583, 0x2e11,
+ 0x8584, 0x145b,
+ 0x8585, 0x2e2e,
+ 0x8586, 0x2e26,
+ 0x8587, 0x1462,
+ 0x8588, 0x2e2d,
+ 0x8589, 0x2e1f,
+ 0x858a, 0x1464,
+ 0x858b, 0x2e17,
+ 0x858c, 0x2c58,
+ 0x858d, 0x2e27,
+ 0x858e, 0x2e24,
+ 0x858f, 0x2e13,
+ 0x8590, 0x2e32,
+ 0x8591, 0x145e,
+ 0x8594, 0x145f,
+ 0x8595, 0x2e15,
+ 0x8596, 0x2e25,
+ 0x8598, 0x2e31,
+ 0x8599, 0x2e28,
+ 0x859a, 0x2e1b,
+ 0x859b, 0x1461,
+ 0x859c, 0x145d,
+ 0x859d, 0x2e29,
+ 0x859e, 0x2e1c,
+ 0x859f, 0x2e33,
+ 0x85a0, 0x2e16,
+ 0x85a1, 0x2e20,
+ 0x85a2, 0x2e2b,
+ 0x85a3, 0x2e18,
+ 0x85a4, 0x2e1a,
+ 0x85a6, 0x1465,
+ 0x85a7, 0x2e14,
+ 0x85a8, 0x1463,
+ 0x85a9, 0x151c,
+ 0x85aa, 0x145a,
+ 0x85af, 0x1460,
+ 0x85b0, 0x1520,
+ 0x85b1, 0x2fa6,
+ 0x85b3, 0x2f9c,
+ 0x85b4, 0x2f97,
+ 0x85b5, 0x2f9d,
+ 0x85b6, 0x2fa7,
+ 0x85b7, 0x2fab,
+ 0x85b8, 0x2faa,
+ 0x85b9, 0x1522,
+ 0x85ba, 0x1521,
+ 0x85bd, 0x2f9e,
+ 0x85be, 0x2fac,
+ 0x85bf, 0x2fa1,
+ 0x85c0, 0x2f99,
+ 0x85c1, 0x37fe,
+ 0x85c2, 0x2f9b,
+ 0x85c3, 0x2f9a,
+ 0x85c4, 0x2fa0,
+ 0x85c5, 0x2fa5,
+ 0x85c6, 0x2f98,
+ 0x85c7, 0x2f9f,
+ 0x85c8, 0x2fa4,
+ 0x85c9, 0x151f,
+ 0x85cb, 0x2fa2,
+ 0x85cd, 0x151d,
+ 0x85ce, 0x2fa3,
+ 0x85cf, 0x151b,
+ 0x85d0, 0x151e,
+ 0x85d1, 0x3101,
+ 0x85d2, 0x2fa8,
+ 0x85d5, 0x15b7,
+ 0x85d7, 0x30f9,
+ 0x85d8, 0x30fd,
+ 0x85d9, 0x30f5,
+ 0x85da, 0x30f8,
+ 0x85dc, 0x3100,
+ 0x85dd, 0x15b5,
+ 0x85de, 0x3105,
+ 0x85df, 0x30fe,
+ 0x85e0, 0x476d,
+ 0x85e1, 0x30f6,
+ 0x85e2, 0x3106,
+ 0x85e3, 0x30ff,
+ 0x85e4, 0x15b8,
+ 0x85e6, 0x3103,
+ 0x85e8, 0x30f7,
+ 0x85e9, 0x15b4,
+ 0x85ea, 0x15b6,
+ 0x85eb, 0x30f2,
+ 0x85ec, 0x30fa,
+ 0x85ed, 0x30f4,
+ 0x85ee, 0x3c56,
+ 0x85ef, 0x3104,
+ 0x85f0, 0x3102,
+ 0x85f1, 0x30f3,
+ 0x85f2, 0x30fb,
+ 0x85f6, 0x3225,
+ 0x85f7, 0x15ba,
+ 0x85f8, 0x30fc,
+ 0x85f9, 0x1638,
+ 0x85fa, 0x163a,
+ 0x85fb, 0x1637,
+ 0x85fc, 0x3c50,
+ 0x85fd, 0x322a,
+ 0x85fe, 0x3222,
+ 0x85ff, 0x3220,
+ 0x8600, 0x3224,
+ 0x8601, 0x3221,
+ 0x8602, 0x3800,
+ 0x8604, 0x3226,
+ 0x8605, 0x3228,
+ 0x8606, 0x163b,
+ 0x8607, 0x163d,
+ 0x8609, 0x3227,
+ 0x860a, 0x163e,
+ 0x860b, 0x163c,
+ 0x860c, 0x3229,
+ 0x860d, 0x4064,
+ 0x8610, 0x3b7f,
+ 0x8611, 0x1639,
+ 0x8614, 0x46be,
+ 0x8616, 0x37fb,
+ 0x8617, 0x1685,
+ 0x8618, 0x32f6,
+ 0x8619, 0x32fc,
+ 0x861a, 0x1687,
+ 0x861b, 0x3223,
+ 0x861c, 0x32fb,
+ 0x861e, 0x3302,
+ 0x861f, 0x32f9,
+ 0x8620, 0x3300,
+ 0x8621, 0x32ff,
+ 0x8622, 0x321f,
+ 0x8623, 0x32fa,
+ 0x8624, 0x2fa9,
+ 0x8625, 0x3303,
+ 0x8626, 0x32f8,
+ 0x8627, 0x32fd,
+ 0x8628, 0x3805,
+ 0x8629, 0x3301,
+ 0x862a, 0x32f7,
+ 0x862c, 0x33aa,
+ 0x862d, 0x1686,
+ 0x862e, 0x32fe,
+ 0x862f, 0x3f9e,
+ 0x8631, 0x3432,
+ 0x8632, 0x33ab,
+ 0x8633, 0x33a9,
+ 0x8634, 0x33a7,
+ 0x8636, 0x33ac,
+ 0x8638, 0x1707,
+ 0x8639, 0x3430,
+ 0x863a, 0x342e,
+ 0x863b, 0x3433,
+ 0x863c, 0x3431,
+ 0x863e, 0x3434,
+ 0x863f, 0x1708,
+ 0x8640, 0x342f,
+ 0x8642, 0x38c1,
+ 0x8643, 0x3497,
+ 0x8645, 0x3b66,
+ 0x8646, 0x34df,
+ 0x864b, 0x353e,
+ 0x864c, 0x3536,
+ 0x864d, 0x1818,
+ 0x864e, 0x0689,
+ 0x8650, 0x07ff,
+ 0x8652, 0x1de3,
+ 0x8653, 0x1de2,
+ 0x8654, 0x09af,
+ 0x8655, 0x0b88,
+ 0x8656, 0x203c,
+ 0x8659, 0x203b,
+ 0x865b, 0x0d48,
+ 0x865c, 0x0eed,
+ 0x865e, 0x0eec,
+ 0x865f, 0x0eee,
+ 0x8661, 0x27ce,
+ 0x8662, 0x2a0e,
+ 0x8663, 0x2c5e,
+ 0x8664, 0x2c60,
+ 0x8665, 0x2c5f,
+ 0x8667, 0x1466,
+ 0x8668, 0x2e34,
+ 0x8669, 0x2fad,
+ 0x866a, 0x351e,
+ 0x866b, 0x040f,
+ 0x866c, 0x3813,
+ 0x866d, 0x1a46,
+ 0x866f, 0x1a45,
+ 0x8670, 0x1a44,
+ 0x8671, 0x068a,
+ 0x8672, 0x476f,
+ 0x8673, 0x1bfd,
+ 0x8674, 0x1bfb,
+ 0x8677, 0x1bfa,
+ 0x8679, 0x0800,
+ 0x867a, 0x0802,
+ 0x867b, 0x0801,
+ 0x867c, 0x1bfc,
+ 0x867e, 0x380a,
+ 0x8685, 0x1def,
+ 0x8686, 0x1dec,
+ 0x8687, 0x1dea,
+ 0x868a, 0x09b0,
+ 0x868b, 0x1ded,
+ 0x868c, 0x09b5,
+ 0x868d, 0x1de7,
+ 0x868e, 0x1df6,
+ 0x8690, 0x1df8,
+ 0x8691, 0x1de8,
+ 0x8692, 0x4770,
+ 0x8693, 0x09b2,
+ 0x8694, 0x1df9,
+ 0x8695, 0x1df4,
+ 0x8696, 0x1de6,
+ 0x8697, 0x1deb,
+ 0x8698, 0x1df5,
+ 0x8699, 0x1df1,
+ 0x869a, 0x1dee,
+ 0x869c, 0x09b7,
+ 0x869d, 0x1df7,
+ 0x869e, 0x1de9,
+ 0x86a0, 0x3b88,
+ 0x86a1, 0x1df2,
+ 0x86a2, 0x1de4,
+ 0x86a3, 0x09b6,
+ 0x86a4, 0x09b3,
+ 0x86a5, 0x1df0,
+ 0x86a7, 0x1df3,
+ 0x86a8, 0x1de5,
+ 0x86a9, 0x09b4,
+ 0x86aa, 0x09b1,
+ 0x86ad, 0x3f06,
+ 0x86af, 0x0b92,
+ 0x86b0, 0x2043,
+ 0x86b1, 0x0b91,
+ 0x86b2, 0x43e0,
+ 0x86b3, 0x2046,
+ 0x86b4, 0x2049,
+ 0x86b5, 0x0b8e,
+ 0x86b6, 0x0b8c,
+ 0x86b7, 0x203e,
+ 0x86b8, 0x2047,
+ 0x86b9, 0x2045,
+ 0x86ba, 0x2042,
+ 0x86bb, 0x204a,
+ 0x86bd, 0x204d,
+ 0x86bf, 0x203d,
+ 0x86c0, 0x0b8b,
+ 0x86c1, 0x2040,
+ 0x86c2, 0x203f,
+ 0x86c3, 0x204c,
+ 0x86c4, 0x0b8d,
+ 0x86c5, 0x2041,
+ 0x86c6, 0x0b8f,
+ 0x86c7, 0x0b8a,
+ 0x86c8, 0x2044,
+ 0x86c9, 0x0b93,
+ 0x86cb, 0x0b90,
+ 0x86cc, 0x2048,
+ 0x86d0, 0x0d4f,
+ 0x86d1, 0x22d2,
+ 0x86d3, 0x22c7,
+ 0x86d4, 0x0d4c,
+ 0x86d6, 0x256d,
+ 0x86d7, 0x22d0,
+ 0x86d8, 0x22c4,
+ 0x86d9, 0x0d4a,
+ 0x86da, 0x22c9,
+ 0x86db, 0x0d4d,
+ 0x86dc, 0x22cd,
+ 0x86dd, 0x22cb,
+ 0x86de, 0x0d50,
+ 0x86df, 0x0d49,
+ 0x86e2, 0x22c5,
+ 0x86e3, 0x22c8,
+ 0x86e4, 0x0d4e,
+ 0x86e6, 0x22c6,
+ 0x86e8, 0x22d1,
+ 0x86e9, 0x22cf,
+ 0x86ea, 0x22ca,
+ 0x86eb, 0x22cc,
+ 0x86ec, 0x22ce,
+ 0x86ed, 0x0d4b,
+ 0x86ef, 0x4771,
+ 0x86f5, 0x256e,
+ 0x86f6, 0x2574,
+ 0x86f7, 0x256a,
+ 0x86f8, 0x2570,
+ 0x86f9, 0x0eef,
+ 0x86fa, 0x256c,
+ 0x86fb, 0x0ef5,
+ 0x86fe, 0x0ef4,
+ 0x8700, 0x0ef3,
+ 0x8701, 0x2573,
+ 0x8702, 0x0ef6,
+ 0x8704, 0x2569,
+ 0x8705, 0x2576,
+ 0x8706, 0x0ef8,
+ 0x8707, 0x0ef2,
+ 0x8708, 0x0ef1,
+ 0x8709, 0x2572,
+ 0x870a, 0x0ef9,
+ 0x870b, 0x2568,
+ 0x870c, 0x256b,
+ 0x870d, 0x2575,
+ 0x870e, 0x2571,
+ 0x8711, 0x27ee,
+ 0x8712, 0x27e3,
+ 0x8713, 0x0ef0,
+ 0x8718, 0x1098,
+ 0x8719, 0x27d7,
+ 0x871a, 0x27ec,
+ 0x871b, 0x27d8,
+ 0x871c, 0x1093,
+ 0x871e, 0x27d5,
+ 0x8720, 0x27de,
+ 0x8721, 0x27d6,
+ 0x8722, 0x1095,
+ 0x8723, 0x27d0,
+ 0x8724, 0x27eb,
+ 0x8725, 0x1096,
+ 0x8726, 0x27e8,
+ 0x8728, 0x27d1,
+ 0x8729, 0x109b,
+ 0x872a, 0x27e0,
+ 0x872c, 0x27da,
+ 0x872d, 0x27e1,
+ 0x872e, 0x27d4,
+ 0x8730, 0x27ed,
+ 0x8731, 0x27e5,
+ 0x8732, 0x27df,
+ 0x8733, 0x27cf,
+ 0x8734, 0x1097,
+ 0x8735, 0x27e6,
+ 0x8737, 0x109a,
+ 0x8738, 0x27ea,
+ 0x873a, 0x27e4,
+ 0x873b, 0x1094,
+ 0x873c, 0x27e2,
+ 0x873e, 0x27dc,
+ 0x873f, 0x1092,
+ 0x8740, 0x27d3,
+ 0x8741, 0x27db,
+ 0x8742, 0x27e7,
+ 0x8743, 0x27d9,
+ 0x8746, 0x27dd,
+ 0x874c, 0x1208,
+ 0x874d, 0x256f,
+ 0x874e, 0x2a20,
+ 0x874f, 0x2a29,
+ 0x8750, 0x2a1f,
+ 0x8751, 0x2a1b,
+ 0x8752, 0x2a18,
+ 0x8753, 0x1209,
+ 0x8754, 0x2a16,
+ 0x8755, 0x1099,
+ 0x8756, 0x2a0f,
+ 0x8757, 0x1207,
+ 0x8758, 0x2a15,
+ 0x8759, 0x1206,
+ 0x875a, 0x2a1a,
+ 0x875b, 0x2a17,
+ 0x875c, 0x2a27,
+ 0x875d, 0x2a22,
+ 0x875e, 0x2a1c,
+ 0x875f, 0x2a21,
+ 0x8760, 0x1202,
+ 0x8761, 0x2a19,
+ 0x8762, 0x2a2c,
+ 0x8763, 0x2a10,
+ 0x8765, 0x2a28,
+ 0x8766, 0x1203,
+ 0x8767, 0x2a2d,
+ 0x8768, 0x1205,
+ 0x8769, 0x2a2e,
+ 0x876a, 0x2a1e,
+ 0x876b, 0x27d2,
+ 0x876c, 0x2a24,
+ 0x876d, 0x2a1d,
+ 0x876e, 0x2a26,
+ 0x876f, 0x2a23,
+ 0x8770, 0x3e6c,
+ 0x8771, 0x380b,
+ 0x8773, 0x2a14,
+ 0x8774, 0x1200,
+ 0x8775, 0x2a2b,
+ 0x8776, 0x1201,
+ 0x8777, 0x2a12,
+ 0x8778, 0x1204,
+ 0x8779, 0x2c6b,
+ 0x877a, 0x2a25,
+ 0x877b, 0x2a2a,
+ 0x877d, 0x4045,
+ 0x8781, 0x2c68,
+ 0x8782, 0x11ff,
+ 0x8783, 0x1340,
+ 0x8784, 0x2c72,
+ 0x8785, 0x2c6e,
+ 0x8786, 0x3eb0,
+ 0x8787, 0x2c6c,
+ 0x8788, 0x2c67,
+ 0x8789, 0x2c76,
+ 0x878b, 0x43e2,
+ 0x878c, 0x3fef,
+ 0x878d, 0x1344,
+ 0x878f, 0x2c63,
+ 0x8790, 0x2c6f,
+ 0x8792, 0x2c66,
+ 0x8793, 0x2c65,
+ 0x8794, 0x2c73,
+ 0x8796, 0x2c69,
+ 0x8797, 0x2c64,
+ 0x8798, 0x2c6a,
+ 0x879a, 0x2c75,
+ 0x879b, 0x2c62,
+ 0x879c, 0x2c74,
+ 0x879d, 0x2c71,
+ 0x879e, 0x1342,
+ 0x879f, 0x1341,
+ 0x87a2, 0x1343,
+ 0x87a3, 0x2c6d,
+ 0x87a4, 0x2c61,
+ 0x87a5, 0x3d88,
+ 0x87a9, 0x3fec,
+ 0x87aa, 0x2e36,
+ 0x87ab, 0x146c,
+ 0x87ac, 0x2e3a,
+ 0x87ad, 0x2e37,
+ 0x87ae, 0x2e3e,
+ 0x87af, 0x2e44,
+ 0x87b0, 0x2e39,
+ 0x87b1, 0x380f,
+ 0x87b2, 0x2e4d,
+ 0x87b3, 0x1469,
+ 0x87b4, 0x2e47,
+ 0x87b5, 0x2e3c,
+ 0x87b6, 0x2e48,
+ 0x87b7, 0x2e43,
+ 0x87b8, 0x2e4a,
+ 0x87b9, 0x2e3b,
+ 0x87ba, 0x146e,
+ 0x87bb, 0x146d,
+ 0x87bc, 0x2e3d,
+ 0x87bd, 0x2e4b,
+ 0x87be, 0x2e35,
+ 0x87bf, 0x2e49,
+ 0x87c0, 0x1467,
+ 0x87c1, 0x3ffc,
+ 0x87c2, 0x2e41,
+ 0x87c3, 0x2e40,
+ 0x87c4, 0x2e45,
+ 0x87c5, 0x2e38,
+ 0x87c6, 0x146b,
+ 0x87c8, 0x146f,
+ 0x87c9, 0x2e3f,
+ 0x87ca, 0x2e46,
+ 0x87cb, 0x1470,
+ 0x87cc, 0x2e42,
+ 0x87ce, 0x3fed,
+ 0x87d1, 0x1468,
+ 0x87d2, 0x146a,
+ 0x87d3, 0x2fba,
+ 0x87d4, 0x2fb8,
+ 0x87d6, 0x3f92,
+ 0x87d7, 0x2fbe,
+ 0x87d8, 0x2fbc,
+ 0x87d9, 0x2fbf,
+ 0x87da, 0x3810,
+ 0x87db, 0x2fb1,
+ 0x87dc, 0x2fb9,
+ 0x87dd, 0x2fc3,
+ 0x87de, 0x2e4c,
+ 0x87df, 0x2fb5,
+ 0x87e0, 0x1526,
+ 0x87e1, 0x2a13,
+ 0x87e2, 0x2fb0,
+ 0x87e3, 0x2fbd,
+ 0x87e4, 0x2fb7,
+ 0x87e5, 0x2fb4,
+ 0x87e6, 0x2faf,
+ 0x87e7, 0x2fae,
+ 0x87e8, 0x2fc2,
+ 0x87ea, 0x2fb3,
+ 0x87eb, 0x2fb2,
+ 0x87ec, 0x1524,
+ 0x87ed, 0x2fbb,
+ 0x87ee, 0x380d,
+ 0x87ef, 0x1523,
+ 0x87f2, 0x1525,
+ 0x87f3, 0x2fb6,
+ 0x87f4, 0x2fc1,
+ 0x87f5, 0x3fae,
+ 0x87f6, 0x310a,
+ 0x87f9, 0x15be,
+ 0x87fa, 0x3108,
+ 0x87fb, 0x15bb,
+ 0x87fc, 0x3110,
+ 0x87fe, 0x15bf,
+ 0x87ff, 0x3112,
+ 0x8800, 0x3107,
+ 0x8801, 0x2fc0,
+ 0x8802, 0x3114,
+ 0x8803, 0x3109,
+ 0x8804, 0x3eaf,
+ 0x8805, 0x15bc,
+ 0x8806, 0x310f,
+ 0x8808, 0x3111,
+ 0x8809, 0x310c,
+ 0x880a, 0x3113,
+ 0x880b, 0x310e,
+ 0x880c, 0x310d,
+ 0x880d, 0x15bd,
+ 0x880f, 0x3811,
+ 0x8810, 0x322c,
+ 0x8813, 0x322f,
+ 0x8814, 0x163f,
+ 0x8816, 0x3230,
+ 0x8817, 0x322e,
+ 0x8818, 0x3f7a,
+ 0x8819, 0x322b,
+ 0x881b, 0x3306,
+ 0x881c, 0x3309,
+ 0x881d, 0x3305,
+ 0x881f, 0x168b,
+ 0x8820, 0x3307,
+ 0x8821, 0x168a,
+ 0x8822, 0x1689,
+ 0x8823, 0x1688,
+ 0x8824, 0x3308,
+ 0x8825, 0x33b1,
+ 0x8826, 0x33af,
+ 0x8827, 0x3e07,
+ 0x8828, 0x33ae,
+ 0x8829, 0x3304,
+ 0x882a, 0x33b0,
+ 0x882b, 0x330a,
+ 0x882c, 0x33ad,
+ 0x882d, 0x3b8b,
+ 0x882e, 0x3437,
+ 0x882f, 0x3415,
+ 0x8830, 0x3435,
+ 0x8831, 0x1709,
+ 0x8832, 0x3436,
+ 0x8833, 0x3438,
+ 0x8835, 0x349a,
+ 0x8836, 0x1728,
+ 0x8837, 0x3499,
+ 0x8838, 0x3498,
+ 0x8839, 0x1729,
+ 0x883b, 0x1747,
+ 0x883c, 0x3508,
+ 0x883d, 0x3520,
+ 0x883e, 0x351f,
+ 0x883f, 0x3521,
+ 0x8840, 0x0410,
+ 0x8841, 0x1bfe,
+ 0x8842, 0x3f5a,
+ 0x8843, 0x1dfa,
+ 0x8845, 0x3816,
+ 0x8848, 0x22d3,
+ 0x884a, 0x330b,
+ 0x884b, 0x349b,
+ 0x884c, 0x0411,
+ 0x884d, 0x0803,
+ 0x884e, 0x1bff,
+ 0x884f, 0x3844,
+ 0x8852, 0x204f,
+ 0x8853, 0x0b94,
+ 0x8855, 0x22d5,
+ 0x8856, 0x22d4,
+ 0x8857, 0x0d51,
+ 0x8859, 0x0efa,
+ 0x885a, 0x2a2f,
+ 0x885b, 0x120a,
+ 0x885d, 0x120b,
+ 0x885e, 0x381b,
+ 0x8860, 0x3a46,
+ 0x8861, 0x1345,
+ 0x8862, 0x172a,
+ 0x8863, 0x0412,
+ 0x8864, 0x4502,
+ 0x8865, 0x3dfc,
+ 0x8867, 0x1c00,
+ 0x8868, 0x068c,
+ 0x8869, 0x1c02,
+ 0x886a, 0x1c01,
+ 0x886b, 0x0804,
+ 0x886d, 0x1dfc,
+ 0x886e, 0x3b8e,
+ 0x886f, 0x1e03,
+ 0x8870, 0x09b8,
+ 0x8871, 0x1e01,
+ 0x8872, 0x1dff,
+ 0x8874, 0x1e06,
+ 0x8875, 0x1dfd,
+ 0x8877, 0x09b9,
+ 0x8879, 0x09bd,
+ 0x887c, 0x1e07,
+ 0x887d, 0x09bc,
+ 0x887e, 0x1e05,
+ 0x887f, 0x1e02,
+ 0x8880, 0x1e00,
+ 0x8881, 0x09ba,
+ 0x8883, 0x1e04,
+ 0x8884, 0x42f7,
+ 0x8887, 0x3b90,
+ 0x8888, 0x0b96,
+ 0x8889, 0x2050,
+ 0x888b, 0x0b9b,
+ 0x888c, 0x2060,
+ 0x888d, 0x0b9a,
+ 0x888e, 0x2062,
+ 0x8891, 0x2056,
+ 0x8892, 0x0b98,
+ 0x8893, 0x2061,
+ 0x8895, 0x2051,
+ 0x8896, 0x0b99,
+ 0x8897, 0x205d,
+ 0x8898, 0x2059,
+ 0x8899, 0x205b,
+ 0x889a, 0x2055,
+ 0x889b, 0x205c,
+ 0x889c, 0x381c,
+ 0x889e, 0x0b95,
+ 0x889f, 0x2058,
+ 0x88a0, 0x3fa0,
+ 0x88a1, 0x2057,
+ 0x88a2, 0x2053,
+ 0x88a4, 0x205e,
+ 0x88a7, 0x205a,
+ 0x88a8, 0x2052,
+ 0x88aa, 0x2054,
+ 0x88ab, 0x0b97,
+ 0x88ac, 0x205f,
+ 0x88ae, 0x4775,
+ 0x88b1, 0x0d54,
+ 0x88b2, 0x22e0,
+ 0x88b4, 0x381e,
+ 0x88b6, 0x22dc,
+ 0x88b7, 0x22de,
+ 0x88b8, 0x22d9,
+ 0x88b9, 0x22d8,
+ 0x88ba, 0x22d6,
+ 0x88bc, 0x22dd,
+ 0x88bd, 0x22df,
+ 0x88be, 0x22db,
+ 0x88bf, 0x3b91,
+ 0x88c0, 0x22da,
+ 0x88c1, 0x0d52,
+ 0x88c5, 0x3820,
+ 0x88c7, 0x3eb1,
+ 0x88c9, 0x22e2,
+ 0x88ca, 0x0f02,
+ 0x88cb, 0x2578,
+ 0x88cc, 0x257e,
+ 0x88cd, 0x2579,
+ 0x88cf, 0x36ea,
+ 0x88d0, 0x257f,
+ 0x88d2, 0x0f04,
+ 0x88d4, 0x0efc,
+ 0x88d5, 0x0f03,
+ 0x88d6, 0x2577,
+ 0x88d7, 0x22d7,
+ 0x88d8, 0x0eff,
+ 0x88d9, 0x0efd,
+ 0x88da, 0x257d,
+ 0x88db, 0x257c,
+ 0x88dc, 0x0efe,
+ 0x88dd, 0x0f00,
+ 0x88de, 0x257b,
+ 0x88df, 0x0efb,
+ 0x88e1, 0x0f01,
+ 0x88e6, 0x3b92,
+ 0x88e7, 0x27f0,
+ 0x88e8, 0x10a2,
+ 0x88eb, 0x27fb,
+ 0x88ec, 0x27fa,
+ 0x88ee, 0x27f5,
+ 0x88ef, 0x10a4,
+ 0x88f0, 0x27f9,
+ 0x88f1, 0x27f1,
+ 0x88f3, 0x109c,
+ 0x88f4, 0x109e,
+ 0x88f5, 0x3e08,
+ 0x88f6, 0x27f7,
+ 0x88f7, 0x27ef,
+ 0x88f8, 0x10a0,
+ 0x88f9, 0x109f,
+ 0x88fa, 0x27f3,
+ 0x88fb, 0x27f8,
+ 0x88fc, 0x27f6,
+ 0x88fd, 0x10a1,
+ 0x88fe, 0x27f4,
+ 0x88ff, 0x4776,
+ 0x8900, 0x42fa,
+ 0x8901, 0x22e1,
+ 0x8902, 0x109d,
+ 0x8905, 0x2a30,
+ 0x8906, 0x2a37,
+ 0x8907, 0x120d,
+ 0x8909, 0x2a3b,
+ 0x890a, 0x1211,
+ 0x890b, 0x2a33,
+ 0x890c, 0x2a31,
+ 0x890e, 0x2a3a,
+ 0x8910, 0x120c,
+ 0x8911, 0x2a39,
+ 0x8912, 0x120e,
+ 0x8914, 0x2a32,
+ 0x8915, 0x1210,
+ 0x8916, 0x2a38,
+ 0x8917, 0x2a34,
+ 0x891a, 0x10a3,
+ 0x891e, 0x2c77,
+ 0x891f, 0x2c83,
+ 0x8921, 0x134a,
+ 0x8922, 0x2c7e,
+ 0x8923, 0x2c80,
+ 0x8924, 0x4777,
+ 0x8925, 0x1348,
+ 0x8926, 0x2c78,
+ 0x8927, 0x2c7c,
+ 0x8929, 0x2c7f,
+ 0x892a, 0x1346,
+ 0x892b, 0x1349,
+ 0x892c, 0x2c82,
+ 0x892d, 0x2c7a,
+ 0x892f, 0x2c81,
+ 0x8930, 0x2c79,
+ 0x8931, 0x2c7d,
+ 0x8932, 0x1347,
+ 0x8933, 0x2e4f,
+ 0x8935, 0x2e4e,
+ 0x8936, 0x1472,
+ 0x8937, 0x2e54,
+ 0x8938, 0x1474,
+ 0x893b, 0x1471,
+ 0x893c, 0x2e50,
+ 0x893d, 0x1475,
+ 0x893e, 0x2e51,
+ 0x8941, 0x2e52,
+ 0x8942, 0x2e55,
+ 0x8943, 0x3e16,
+ 0x8944, 0x1473,
+ 0x8946, 0x2fc8,
+ 0x8947, 0x43e3,
+ 0x8949, 0x2fcb,
+ 0x894b, 0x2fc5,
+ 0x894c, 0x2fc7,
+ 0x894d, 0x3b94,
+ 0x894f, 0x2fc6,
+ 0x8950, 0x2fc9,
+ 0x8952, 0x2e53,
+ 0x8953, 0x2fc4,
+ 0x8954, 0x3b96,
+ 0x8956, 0x15c2,
+ 0x8957, 0x3118,
+ 0x8958, 0x311b,
+ 0x8959, 0x311d,
+ 0x895a, 0x3116,
+ 0x895c, 0x311a,
+ 0x895d, 0x311c,
+ 0x895e, 0x15c3,
+ 0x895f, 0x15c1,
+ 0x8960, 0x15c0,
+ 0x8961, 0x3119,
+ 0x8962, 0x3115,
+ 0x8963, 0x3231,
+ 0x8964, 0x1641,
+ 0x8965, 0x3b93,
+ 0x8966, 0x3232,
+ 0x8969, 0x330d,
+ 0x896a, 0x168c,
+ 0x896b, 0x330f,
+ 0x896c, 0x168d,
+ 0x896d, 0x330c,
+ 0x896e, 0x330e,
+ 0x896f, 0x16d6,
+ 0x8971, 0x33b2,
+ 0x8972, 0x16d5,
+ 0x8973, 0x343b,
+ 0x8974, 0x343a,
+ 0x8976, 0x3439,
+ 0x8977, 0x3dea,
+ 0x8979, 0x34e2,
+ 0x897b, 0x34e5,
+ 0x897c, 0x34e4,
+ 0x897e, 0x1819,
+ 0x897f, 0x0413,
+ 0x8980, 0x4708,
+ 0x8981, 0x0805,
+ 0x8982, 0x2063,
+ 0x8983, 0x0d55,
+ 0x8985, 0x2580,
+ 0x8986, 0x1527,
+ 0x8987, 0x3822,
+ 0x8988, 0x311e,
+ 0x8989, 0x3fe9,
+ 0x898a, 0x3823,
+ 0x898b, 0x0508,
+ 0x898f, 0x0b9d,
+ 0x8991, 0x4778,
+ 0x8993, 0x0b9c,
+ 0x8994, 0x3fe0,
+ 0x8995, 0x22e3,
+ 0x8996, 0x0d56,
+ 0x8997, 0x22e5,
+ 0x8998, 0x22e4,
+ 0x899b, 0x2581,
+ 0x899c, 0x0f05,
+ 0x899d, 0x27fc,
+ 0x899e, 0x27ff,
+ 0x899f, 0x27fe,
+ 0x89a1, 0x27fd,
+ 0x89a2, 0x2a3c,
+ 0x89a3, 0x2a3e,
+ 0x89a4, 0x2a3d,
+ 0x89a5, 0x3d93,
+ 0x89a6, 0x134c,
+ 0x89a7, 0x3826,
+ 0x89a9, 0x3825,
+ 0x89aa, 0x134b,
+ 0x89ac, 0x1476,
+ 0x89ad, 0x2e56,
+ 0x89ae, 0x2e58,
+ 0x89af, 0x2e57,
+ 0x89b2, 0x1528,
+ 0x89b6, 0x3120,
+ 0x89b7, 0x311f,
+ 0x89b9, 0x3233,
+ 0x89ba, 0x1642,
+ 0x89bc, 0x3827,
+ 0x89bd, 0x168e,
+ 0x89be, 0x33b4,
+ 0x89bf, 0x33b3,
+ 0x89c0, 0x1748,
+ 0x89c1, 0x4503,
+ 0x89c6, 0x4566,
+ 0x89d2, 0x0509,
+ 0x89d3, 0x1c03,
+ 0x89d4, 0x0806,
+ 0x89d5, 0x2066,
+ 0x89d6, 0x2064,
+ 0x89d9, 0x2065,
+ 0x89da, 0x22e7,
+ 0x89dc, 0x2588,
+ 0x89dd, 0x22e6,
+ 0x89df, 0x2582,
+ 0x89e0, 0x2586,
+ 0x89e1, 0x2585,
+ 0x89e2, 0x2587,
+ 0x89e3, 0x0f06,
+ 0x89e4, 0x2584,
+ 0x89e5, 0x2583,
+ 0x89e6, 0x2589,
+ 0x89e7, 0x3829,
+ 0x89e8, 0x2802,
+ 0x89e9, 0x2800,
+ 0x89eb, 0x2801,
+ 0x89ec, 0x2a41,
+ 0x89ed, 0x2a3f,
+ 0x89f0, 0x2a40,
+ 0x89f1, 0x2c84,
+ 0x89f2, 0x2e59,
+ 0x89f4, 0x1529,
+ 0x89f6, 0x3121,
+ 0x89f7, 0x3234,
+ 0x89f8, 0x1643,
+ 0x89fa, 0x3310,
+ 0x89fb, 0x33b5,
+ 0x89fc, 0x16d7,
+ 0x89fe, 0x343c,
+ 0x89ff, 0x34e6,
+ 0x8a00, 0x050a,
+ 0x8a02, 0x0808,
+ 0x8a04, 0x1c04,
+ 0x8a07, 0x1c05,
+ 0x8a08, 0x0807,
+ 0x8a0a, 0x09c3,
+ 0x8a0c, 0x09c1,
+ 0x8a0e, 0x09c0,
+ 0x8a0f, 0x09c7,
+ 0x8a10, 0x09bf,
+ 0x8a11, 0x09c8,
+ 0x8a12, 0x1e08,
+ 0x8a13, 0x09c5,
+ 0x8a15, 0x09c2,
+ 0x8a16, 0x09c6,
+ 0x8a17, 0x09c4,
+ 0x8a18, 0x09be,
+ 0x8a1b, 0x0ba5,
+ 0x8a1c, 0x3ba3,
+ 0x8a1d, 0x0b9f,
+ 0x8a1e, 0x206a,
+ 0x8a1f, 0x0ba4,
+ 0x8a22, 0x0ba6,
+ 0x8a23, 0x0ba0,
+ 0x8a25, 0x0ba1,
+ 0x8a27, 0x2068,
+ 0x8a29, 0x43e5,
+ 0x8a2a, 0x0b9e,
+ 0x8a2b, 0x3bd1,
+ 0x8a2c, 0x2069,
+ 0x8a2d, 0x0ba3,
+ 0x8a30, 0x2067,
+ 0x8a31, 0x0ba2,
+ 0x8a34, 0x0d61,
+ 0x8a36, 0x0d63,
+ 0x8a38, 0x477a,
+ 0x8a39, 0x22eb,
+ 0x8a3a, 0x0d62,
+ 0x8a3b, 0x0d57,
+ 0x8a3c, 0x0d5b,
+ 0x8a3d, 0x3ba2,
+ 0x8a3e, 0x0f19,
+ 0x8a3f, 0x258e,
+ 0x8a40, 0x22ed,
+ 0x8a41, 0x0d5c,
+ 0x8a44, 0x22f0,
+ 0x8a46, 0x0d60,
+ 0x8a48, 0x22f3,
+ 0x8a49, 0x3ff0,
+ 0x8a4a, 0x22f5,
+ 0x8a4c, 0x22f6,
+ 0x8a4d, 0x22ea,
+ 0x8a4e, 0x22e9,
+ 0x8a4f, 0x22f7,
+ 0x8a50, 0x0d5f,
+ 0x8a51, 0x22f4,
+ 0x8a52, 0x22f2,
+ 0x8a54, 0x0d5d,
+ 0x8a55, 0x0d59,
+ 0x8a56, 0x0d64,
+ 0x8a57, 0x22ee,
+ 0x8a59, 0x22ec,
+ 0x8a5b, 0x0d5e,
+ 0x8a5e, 0x0d5a,
+ 0x8a60, 0x0d58,
+ 0x8a61, 0x258d,
+ 0x8a62, 0x0f14,
+ 0x8a63, 0x0f0f,
+ 0x8a66, 0x0f0a,
+ 0x8a67, 0x3f8e,
+ 0x8a68, 0x0f1a,
+ 0x8a69, 0x0f0b,
+ 0x8a6b, 0x0f07,
+ 0x8a6c, 0x0f16,
+ 0x8a6d, 0x0f13,
+ 0x8a6e, 0x0f15,
+ 0x8a70, 0x0f0c,
+ 0x8a71, 0x0f11,
+ 0x8a72, 0x0f08,
+ 0x8a74, 0x2595,
+ 0x8a75, 0x2592,
+ 0x8a76, 0x258a,
+ 0x8a77, 0x258f,
+ 0x8a79, 0x0f17,
+ 0x8a7a, 0x2596,
+ 0x8a7b, 0x0f18,
+ 0x8a7c, 0x0f0e,
+ 0x8a7e, 0x3fa5,
+ 0x8a7f, 0x258c,
+ 0x8a81, 0x2594,
+ 0x8a82, 0x2590,
+ 0x8a83, 0x2593,
+ 0x8a84, 0x2591,
+ 0x8a85, 0x0f12,
+ 0x8a86, 0x258b,
+ 0x8a87, 0x0f0d,
+ 0x8a8b, 0x2805,
+ 0x8a8c, 0x10a6,
+ 0x8a8d, 0x10a9,
+ 0x8a8f, 0x2807,
+ 0x8a90, 0x382f,
+ 0x8a91, 0x10b1,
+ 0x8a92, 0x2806,
+ 0x8a93, 0x10ab,
+ 0x8a94, 0x477b,
+ 0x8a95, 0x1216,
+ 0x8a96, 0x2808,
+ 0x8a98, 0x10b0,
+ 0x8a99, 0x2804,
+ 0x8a9a, 0x10b2,
+ 0x8a9c, 0x382c,
+ 0x8a9e, 0x10a7,
+ 0x8aa0, 0x0f10,
+ 0x8aa1, 0x10aa,
+ 0x8aa3, 0x10a8,
+ 0x8aa4, 0x10ac,
+ 0x8aa5, 0x10ae,
+ 0x8aa6, 0x10a5,
+ 0x8aa7, 0x10b3,
+ 0x8aa8, 0x10af,
+ 0x8aa9, 0x383d,
+ 0x8aaa, 0x10ad,
+ 0x8aab, 0x2803,
+ 0x8aaf, 0x3841,
+ 0x8ab0, 0x121d,
+ 0x8ab2, 0x1219,
+ 0x8ab4, 0x477c,
+ 0x8ab6, 0x1220,
+ 0x8ab8, 0x2a44,
+ 0x8ab9, 0x1221,
+ 0x8aba, 0x2a50,
+ 0x8abb, 0x2a49,
+ 0x8abc, 0x1212,
+ 0x8abd, 0x2a51,
+ 0x8abe, 0x2a4b,
+ 0x8abf, 0x121c,
+ 0x8ac0, 0x2a4c,
+ 0x8ac2, 0x121b,
+ 0x8ac3, 0x2a4f,
+ 0x8ac4, 0x1215,
+ 0x8ac5, 0x2a4d,
+ 0x8ac6, 0x2a43,
+ 0x8ac7, 0x1214,
+ 0x8ac8, 0x2c8f,
+ 0x8ac9, 0x121a,
+ 0x8acb, 0x1217,
+ 0x8acd, 0x121f,
+ 0x8acf, 0x2a42,
+ 0x8ad1, 0x2a46,
+ 0x8ad2, 0x1213,
+ 0x8ad3, 0x2a45,
+ 0x8ad4, 0x2a47,
+ 0x8ad6, 0x121e,
+ 0x8ad7, 0x2a4a,
+ 0x8ad8, 0x2a4e,
+ 0x8ad9, 0x2a52,
+ 0x8ada, 0x39c2,
+ 0x8adb, 0x1222,
+ 0x8adc, 0x1352,
+ 0x8add, 0x2c8a,
+ 0x8ade, 0x2c90,
+ 0x8adf, 0x2c8d,
+ 0x8ae0, 0x2c85,
+ 0x8ae1, 0x2c91,
+ 0x8ae2, 0x2c86,
+ 0x8ae4, 0x2c8c,
+ 0x8ae6, 0x134d,
+ 0x8ae7, 0x1353,
+ 0x8ae8, 0x2c92,
+ 0x8aea, 0x3dd9,
+ 0x8aeb, 0x134f,
+ 0x8aed, 0x1359,
+ 0x8aee, 0x1354,
+ 0x8aef, 0x2c94,
+ 0x8af0, 0x2c8e,
+ 0x8af1, 0x1350,
+ 0x8af2, 0x2c87,
+ 0x8af3, 0x135a,
+ 0x8af4, 0x2c88,
+ 0x8af6, 0x135b,
+ 0x8af7, 0x1358,
+ 0x8af8, 0x1218,
+ 0x8afa, 0x134e,
+ 0x8afb, 0x2c95,
+ 0x8afc, 0x135c,
+ 0x8afe, 0x1355,
+ 0x8aff, 0x2c93,
+ 0x8b00, 0x1351,
+ 0x8b01, 0x1356,
+ 0x8b04, 0x147e,
+ 0x8b05, 0x2e5f,
+ 0x8b06, 0x2e68,
+ 0x8b07, 0x2e65,
+ 0x8b08, 0x2e67,
+ 0x8b0a, 0x147b,
+ 0x8b0b, 0x2e60,
+ 0x8b0c, 0x3836,
+ 0x8b0d, 0x2e66,
+ 0x8b0e, 0x1477,
+ 0x8b0f, 0x2e62,
+ 0x8b10, 0x147f,
+ 0x8b11, 0x2e5e,
+ 0x8b12, 0x2e63,
+ 0x8b13, 0x2e6a,
+ 0x8b14, 0x2c8b,
+ 0x8b15, 0x2e64,
+ 0x8b16, 0x2e5d,
+ 0x8b17, 0x1478,
+ 0x8b18, 0x2e5c,
+ 0x8b19, 0x1479,
+ 0x8b1a, 0x2e6b,
+ 0x8b1b, 0x147a,
+ 0x8b1c, 0x2e69,
+ 0x8b1d, 0x147d,
+ 0x8b1e, 0x2e5b,
+ 0x8b1f, 0x3837,
+ 0x8b20, 0x147c,
+ 0x8b22, 0x2e61,
+ 0x8b23, 0x2fce,
+ 0x8b24, 0x2fdc,
+ 0x8b25, 0x2fd7,
+ 0x8b26, 0x2fd9,
+ 0x8b27, 0x2fcd,
+ 0x8b28, 0x152a,
+ 0x8b2a, 0x2fcc,
+ 0x8b2b, 0x152d,
+ 0x8b2c, 0x152c,
+ 0x8b2d, 0x3f99,
+ 0x8b2e, 0x2fdb,
+ 0x8b2f, 0x2fd3,
+ 0x8b30, 0x2fd0,
+ 0x8b31, 0x2fd6,
+ 0x8b33, 0x2fcf,
+ 0x8b35, 0x2fd1,
+ 0x8b36, 0x2fda,
+ 0x8b37, 0x2fd8,
+ 0x8b39, 0x152b,
+ 0x8b3a, 0x2fdf,
+ 0x8b3b, 0x2fdd,
+ 0x8b3c, 0x2fd4,
+ 0x8b3d, 0x2fde,
+ 0x8b3e, 0x2fd5,
+ 0x8b3f, 0x383a,
+ 0x8b40, 0x3125,
+ 0x8b41, 0x15c4,
+ 0x8b42, 0x312c,
+ 0x8b43, 0x3ff2,
+ 0x8b45, 0x3313,
+ 0x8b46, 0x15cb,
+ 0x8b47, 0x2fd2,
+ 0x8b48, 0x3123,
+ 0x8b49, 0x15c7,
+ 0x8b4a, 0x3124,
+ 0x8b4b, 0x3129,
+ 0x8b4c, 0x383b,
+ 0x8b4e, 0x15c9,
+ 0x8b50, 0x3122,
+ 0x8b51, 0x312b,
+ 0x8b52, 0x312d,
+ 0x8b53, 0x3126,
+ 0x8b54, 0x3128,
+ 0x8b55, 0x312a,
+ 0x8b56, 0x3127,
+ 0x8b57, 0x312e,
+ 0x8b58, 0x15c6,
+ 0x8b59, 0x15cc,
+ 0x8b5a, 0x15c8,
+ 0x8b5c, 0x15c5,
+ 0x8b5d, 0x3237,
+ 0x8b5e, 0x3db8,
+ 0x8b5f, 0x1648,
+ 0x8b60, 0x3235,
+ 0x8b62, 0x3dd4,
+ 0x8b63, 0x3239,
+ 0x8b65, 0x323a,
+ 0x8b66, 0x1646,
+ 0x8b67, 0x323b,
+ 0x8b68, 0x3238,
+ 0x8b69, 0x3bf7,
+ 0x8b6a, 0x3236,
+ 0x8b6b, 0x1649,
+ 0x8b6c, 0x1645,
+ 0x8b6d, 0x323c,
+ 0x8b6f, 0x1647,
+ 0x8b70, 0x1644,
+ 0x8b74, 0x168f,
+ 0x8b77, 0x1690,
+ 0x8b78, 0x3312,
+ 0x8b79, 0x3311,
+ 0x8b7a, 0x3314,
+ 0x8b7d, 0x1691,
+ 0x8b7e, 0x33b6,
+ 0x8b7f, 0x33bb,
+ 0x8b80, 0x16d8,
+ 0x8b81, 0x3d8d,
+ 0x8b82, 0x33b8,
+ 0x8b84, 0x33b7,
+ 0x8b85, 0x33ba,
+ 0x8b86, 0x33b9,
+ 0x8b88, 0x3440,
+ 0x8b8a, 0x170a,
+ 0x8b8b, 0x343f,
+ 0x8b8c, 0x343d,
+ 0x8b8e, 0x343e,
+ 0x8b90, 0x383f,
+ 0x8b92, 0x172c,
+ 0x8b93, 0x172b,
+ 0x8b94, 0x349c,
+ 0x8b96, 0x172d,
+ 0x8b98, 0x34e7,
+ 0x8b9a, 0x1754,
+ 0x8b9b, 0x3840,
+ 0x8b9c, 0x175a,
+ 0x8b9e, 0x3522,
+ 0x8b9f, 0x353f,
+ 0x8ba0, 0x4505,
+ 0x8bbe, 0x4567,
+ 0x8be2, 0x4568,
+ 0x8c37, 0x050b,
+ 0x8c39, 0x206b,
+ 0x8c3b, 0x206c,
+ 0x8c3c, 0x2597,
+ 0x8c3d, 0x2809,
+ 0x8c3e, 0x2a53,
+ 0x8c3f, 0x1481,
+ 0x8c41, 0x1480,
+ 0x8c42, 0x2fe0,
+ 0x8c43, 0x312f,
+ 0x8c45, 0x3441,
+ 0x8c46, 0x050c,
+ 0x8c47, 0x1e09,
+ 0x8c48, 0x09c9,
+ 0x8c49, 0x0ba7,
+ 0x8c4a, 0x2599,
+ 0x8c4b, 0x2598,
+ 0x8c4c, 0x1223,
+ 0x8c4d, 0x2a54,
+ 0x8c4e, 0x1224,
+ 0x8c4f, 0x2e6c,
+ 0x8c50, 0x152e,
+ 0x8c51, 0x477d,
+ 0x8c54, 0x1763,
+ 0x8c55, 0x050d,
+ 0x8c56, 0x1a48,
+ 0x8c57, 0x1e0a,
+ 0x8c5a, 0x0ba8,
+ 0x8c5c, 0x206d,
+ 0x8c5f, 0x22f8,
+ 0x8c61, 0x0d65,
+ 0x8c62, 0x0f1b,
+ 0x8c64, 0x259b,
+ 0x8c65, 0x259a,
+ 0x8c66, 0x259c,
+ 0x8c68, 0x280a,
+ 0x8c6a, 0x10b4,
+ 0x8c6b, 0x135d,
+ 0x8c6c, 0x1225,
+ 0x8c6d, 0x135e,
+ 0x8c6f, 0x2e70,
+ 0x8c70, 0x2e6d,
+ 0x8c71, 0x2e6f,
+ 0x8c72, 0x2e6e,
+ 0x8c73, 0x1482,
+ 0x8c75, 0x2fe1,
+ 0x8c76, 0x3131,
+ 0x8c77, 0x3130,
+ 0x8c78, 0x18e7,
+ 0x8c79, 0x09cb,
+ 0x8c7a, 0x09ca,
+ 0x8c7b, 0x1e0b,
+ 0x8c7d, 0x206f,
+ 0x8c80, 0x22fa,
+ 0x8c81, 0x22f9,
+ 0x8c82, 0x0d66,
+ 0x8c84, 0x259e,
+ 0x8c86, 0x259d,
+ 0x8c89, 0x0f1d,
+ 0x8c8a, 0x0f1c,
+ 0x8c8c, 0x10b6,
+ 0x8c8d, 0x10b5,
+ 0x8c8f, 0x2a55,
+ 0x8c90, 0x2c98,
+ 0x8c91, 0x2c96,
+ 0x8c93, 0x135f,
+ 0x8c94, 0x2e72,
+ 0x8c95, 0x2e71,
+ 0x8c97, 0x2fe4,
+ 0x8c98, 0x2fe3,
+ 0x8c99, 0x2fe2,
+ 0x8c9a, 0x3132,
+ 0x8c9b, 0x3845,
+ 0x8c9c, 0x3523,
+ 0x8c9d, 0x050e,
+ 0x8c9e, 0x080a,
+ 0x8c9f, 0x3bad,
+ 0x8ca0, 0x080b,
+ 0x8ca1, 0x09cc,
+ 0x8ca3, 0x1e0d,
+ 0x8ca4, 0x1e0c,
+ 0x8ca5, 0x2070,
+ 0x8ca7, 0x0bae,
+ 0x8ca8, 0x0bac,
+ 0x8ca9, 0x0ba9,
+ 0x8caa, 0x0bad,
+ 0x8cab, 0x0bab,
+ 0x8cac, 0x0baa,
+ 0x8cad, 0x3ff1,
+ 0x8caf, 0x0d67,
+ 0x8cb0, 0x22fd,
+ 0x8cb2, 0x0f22,
+ 0x8cb3, 0x0d69,
+ 0x8cb4, 0x0d6e,
+ 0x8cb5, 0x22ff,
+ 0x8cb6, 0x0d70,
+ 0x8cb7, 0x0d6f,
+ 0x8cb8, 0x0d72,
+ 0x8cb9, 0x22fe,
+ 0x8cba, 0x22fb,
+ 0x8cbb, 0x0d6c,
+ 0x8cbc, 0x0d68,
+ 0x8cbd, 0x0d6a,
+ 0x8cbe, 0x22fc,
+ 0x8cbf, 0x0d71,
+ 0x8cc0, 0x0d6d,
+ 0x8cc1, 0x0d6b,
+ 0x8cc2, 0x0f24,
+ 0x8cc3, 0x0f23,
+ 0x8cc4, 0x0f21,
+ 0x8cc5, 0x0f25,
+ 0x8cc7, 0x0f1f,
+ 0x8cca, 0x0f1e,
+ 0x8ccc, 0x25a0,
+ 0x8ccd, 0x3e99,
+ 0x8ccf, 0x280d,
+ 0x8cd1, 0x10b8,
+ 0x8cd3, 0x10b7,
+ 0x8cd4, 0x477e,
+ 0x8cd5, 0x280c,
+ 0x8cd6, 0x384b,
+ 0x8cd7, 0x280e,
+ 0x8cd9, 0x2a58,
+ 0x8cda, 0x2a5a,
+ 0x8cdb, 0x3851,
+ 0x8cdc, 0x122e,
+ 0x8cdd, 0x2a5b,
+ 0x8cde, 0x1227,
+ 0x8cdf, 0x2a57,
+ 0x8ce0, 0x1226,
+ 0x8ce1, 0x1230,
+ 0x8ce2, 0x122c,
+ 0x8ce4, 0x1229,
+ 0x8ce5, 0x2a56,
+ 0x8ce6, 0x1228,
+ 0x8ce7, 0x2a5c,
+ 0x8ce8, 0x2a59,
+ 0x8ce9, 0x3bae,
+ 0x8cea, 0x122f,
+ 0x8ceb, 0x3f9c,
+ 0x8cec, 0x122a,
+ 0x8cee, 0x2c9a,
+ 0x8cf0, 0x2c9c,
+ 0x8cf1, 0x2c9b,
+ 0x8cf2, 0x477f,
+ 0x8cf3, 0x2c9d,
+ 0x8cf4, 0x1360,
+ 0x8cf5, 0x2c99,
+ 0x8cf7, 0x3fb1,
+ 0x8cf8, 0x1486,
+ 0x8cf9, 0x2e73,
+ 0x8cfa, 0x1483,
+ 0x8cfb, 0x1487,
+ 0x8cfc, 0x1485,
+ 0x8cfd, 0x1484,
+ 0x8cfe, 0x2fe5,
+ 0x8d00, 0x2fe8,
+ 0x8d02, 0x2fe7,
+ 0x8d03, 0x384f,
+ 0x8d04, 0x2fe6,
+ 0x8d05, 0x152f,
+ 0x8d06, 0x3133,
+ 0x8d08, 0x15cd,
+ 0x8d09, 0x3135,
+ 0x8d0a, 0x15ce,
+ 0x8d0b, 0x4573,
+ 0x8d0c, 0x3f96,
+ 0x8d0d, 0x164b,
+ 0x8d0f, 0x164a,
+ 0x8d10, 0x3316,
+ 0x8d11, 0x3853,
+ 0x8d12, 0x384e,
+ 0x8d13, 0x1692,
+ 0x8d14, 0x3317,
+ 0x8d15, 0x33bc,
+ 0x8d16, 0x16d9,
+ 0x8d18, 0x3e6f,
+ 0x8d19, 0x3442,
+ 0x8d1b, 0x172f,
+ 0x8d1c, 0x4780,
+ 0x8d1d, 0x4506,
+ 0x8d64, 0x050f,
+ 0x8d66, 0x0bb0,
+ 0x8d67, 0x0baf,
+ 0x8d68, 0x25a1,
+ 0x8d6b, 0x10ba,
+ 0x8d6c, 0x2c9e,
+ 0x8d6d, 0x1231,
+ 0x8d6e, 0x2c9f,
+ 0x8d6f, 0x2e74,
+ 0x8d70, 0x0510,
+ 0x8d72, 0x1c06,
+ 0x8d73, 0x080d,
+ 0x8d74, 0x080c,
+ 0x8d76, 0x1e0e,
+ 0x8d77, 0x09ce,
+ 0x8d78, 0x1e0f,
+ 0x8d79, 0x2073,
+ 0x8d7a, 0x39e1,
+ 0x8d7b, 0x2072,
+ 0x8d7d, 0x2071,
+ 0x8d80, 0x2301,
+ 0x8d81, 0x0d75,
+ 0x8d82, 0x3f69,
+ 0x8d84, 0x2300,
+ 0x8d85, 0x0d74,
+ 0x8d89, 0x2302,
+ 0x8d8a, 0x0d73,
+ 0x8d8c, 0x25a4,
+ 0x8d8d, 0x25a7,
+ 0x8d8e, 0x25a5,
+ 0x8d90, 0x25aa,
+ 0x8d91, 0x25a3,
+ 0x8d92, 0x25ab,
+ 0x8d93, 0x25a8,
+ 0x8d95, 0x10bc,
+ 0x8d96, 0x280f,
+ 0x8d99, 0x10bb,
+ 0x8d9b, 0x2a60,
+ 0x8d9c, 0x2a5e,
+ 0x8d9f, 0x1232,
+ 0x8da0, 0x2a5d,
+ 0x8da1, 0x2a5f,
+ 0x8da3, 0x1233,
+ 0x8da5, 0x2ca0,
+ 0x8da6, 0x3ff7,
+ 0x8da7, 0x2ca1,
+ 0x8da8, 0x1488,
+ 0x8da9, 0x3856,
+ 0x8daa, 0x3137,
+ 0x8dab, 0x3139,
+ 0x8dac, 0x3136,
+ 0x8dad, 0x3138,
+ 0x8dae, 0x323d,
+ 0x8daf, 0x3318,
+ 0x8db2, 0x3509,
+ 0x8db3, 0x0511,
+ 0x8db4, 0x080e,
+ 0x8db5, 0x1e10,
+ 0x8db6, 0x1e12,
+ 0x8db7, 0x1e11,
+ 0x8db9, 0x2076,
+ 0x8dba, 0x0bb2,
+ 0x8dbc, 0x2074,
+ 0x8dbe, 0x0bb1,
+ 0x8dbf, 0x2077,
+ 0x8dc0, 0x436a,
+ 0x8dc1, 0x2078,
+ 0x8dc2, 0x2075,
+ 0x8dc3, 0x4782,
+ 0x8dc5, 0x230e,
+ 0x8dc6, 0x0d7d,
+ 0x8dc7, 0x2306,
+ 0x8dc8, 0x230c,
+ 0x8dcb, 0x0d78,
+ 0x8dcc, 0x0d7b,
+ 0x8dcd, 0x2305,
+ 0x8dce, 0x0d76,
+ 0x8dcf, 0x2309,
+ 0x8dd0, 0x25b1,
+ 0x8dd1, 0x0d7a,
+ 0x8dd3, 0x2304,
+ 0x8dd4, 0x3f82,
+ 0x8dd5, 0x230a,
+ 0x8dd6, 0x2307,
+ 0x8dd7, 0x230d,
+ 0x8dd8, 0x2303,
+ 0x8dd9, 0x230b,
+ 0x8dda, 0x0d79,
+ 0x8ddb, 0x0d7c,
+ 0x8ddc, 0x2308,
+ 0x8ddd, 0x0d77,
+ 0x8ddf, 0x0f27,
+ 0x8de0, 0x25ad,
+ 0x8de1, 0x0f26,
+ 0x8de2, 0x25b4,
+ 0x8de3, 0x25b3,
+ 0x8de4, 0x0f2d,
+ 0x8de6, 0x0f2e,
+ 0x8de7, 0x25b5,
+ 0x8de8, 0x0f28,
+ 0x8de9, 0x25b2,
+ 0x8dea, 0x0f2c,
+ 0x8deb, 0x25b7,
+ 0x8dec, 0x25ae,
+ 0x8dee, 0x25b0,
+ 0x8def, 0x0f29,
+ 0x8df0, 0x25ac,
+ 0x8df1, 0x25af,
+ 0x8df2, 0x25b6,
+ 0x8df3, 0x0f2a,
+ 0x8df4, 0x25b8,
+ 0x8dfa, 0x0f2b,
+ 0x8dfc, 0x10bd,
+ 0x8dfd, 0x2814,
+ 0x8dfe, 0x281a,
+ 0x8dff, 0x2812,
+ 0x8e00, 0x281b,
+ 0x8e01, 0x3f85,
+ 0x8e02, 0x2811,
+ 0x8e03, 0x2816,
+ 0x8e04, 0x281c,
+ 0x8e05, 0x2819,
+ 0x8e06, 0x2818,
+ 0x8e07, 0x2817,
+ 0x8e09, 0x2810,
+ 0x8e0a, 0x2815,
+ 0x8e0d, 0x2813,
+ 0x8e0e, 0x3e5e,
+ 0x8e0f, 0x1238,
+ 0x8e10, 0x1235,
+ 0x8e11, 0x2a69,
+ 0x8e12, 0x2a6e,
+ 0x8e13, 0x2a70,
+ 0x8e14, 0x2a6d,
+ 0x8e15, 0x2a66,
+ 0x8e16, 0x2a68,
+ 0x8e17, 0x2a72,
+ 0x8e18, 0x2a6f,
+ 0x8e19, 0x2a6a,
+ 0x8e1a, 0x2a73,
+ 0x8e1b, 0x2a67,
+ 0x8e1c, 0x2a71,
+ 0x8e1d, 0x1236,
+ 0x8e1e, 0x123c,
+ 0x8e1f, 0x123a,
+ 0x8e20, 0x2a61,
+ 0x8e21, 0x123b,
+ 0x8e22, 0x1237,
+ 0x8e23, 0x2a62,
+ 0x8e24, 0x2a64,
+ 0x8e25, 0x2a63,
+ 0x8e26, 0x2a6b,
+ 0x8e28, 0x3f88,
+ 0x8e29, 0x1239,
+ 0x8e2a, 0x3bb4,
+ 0x8e2b, 0x1234,
+ 0x8e2d, 0x3eab,
+ 0x8e2e, 0x2a65,
+ 0x8e30, 0x2cab,
+ 0x8e31, 0x1362,
+ 0x8e33, 0x2ca2,
+ 0x8e34, 0x1363,
+ 0x8e35, 0x1366,
+ 0x8e36, 0x2ca7,
+ 0x8e38, 0x2ca4,
+ 0x8e39, 0x1365,
+ 0x8e3a, 0x4784,
+ 0x8e3c, 0x2ca8,
+ 0x8e3e, 0x2ca3,
+ 0x8e3f, 0x2cac,
+ 0x8e40, 0x2ca5,
+ 0x8e41, 0x2caa,
+ 0x8e42, 0x1364,
+ 0x8e44, 0x1361,
+ 0x8e45, 0x2ca6,
+ 0x8e46, 0x4312,
+ 0x8e47, 0x2e7a,
+ 0x8e48, 0x148b,
+ 0x8e49, 0x1489,
+ 0x8e4a, 0x148c,
+ 0x8e4b, 0x148a,
+ 0x8e4c, 0x2e79,
+ 0x8e4d, 0x2e76,
+ 0x8e4e, 0x2e75,
+ 0x8e4f, 0x3f83,
+ 0x8e50, 0x2e78,
+ 0x8e53, 0x2e77,
+ 0x8e54, 0x2ff6,
+ 0x8e55, 0x1535,
+ 0x8e56, 0x2fed,
+ 0x8e57, 0x2fec,
+ 0x8e59, 0x1530,
+ 0x8e5a, 0x2ff2,
+ 0x8e5b, 0x2ff1,
+ 0x8e5c, 0x2fe9,
+ 0x8e5d, 0x2ff4,
+ 0x8e5e, 0x2fee,
+ 0x8e5f, 0x1534,
+ 0x8e60, 0x2feb,
+ 0x8e61, 0x2ff3,
+ 0x8e62, 0x2fea,
+ 0x8e63, 0x1531,
+ 0x8e64, 0x1533,
+ 0x8e65, 0x2fef,
+ 0x8e66, 0x1532,
+ 0x8e67, 0x2ff0,
+ 0x8e68, 0x434d,
+ 0x8e69, 0x2ff5,
+ 0x8e6a, 0x313d,
+ 0x8e6c, 0x15d3,
+ 0x8e6d, 0x313a,
+ 0x8e6f, 0x313e,
+ 0x8e71, 0x43e7,
+ 0x8e72, 0x15d0,
+ 0x8e73, 0x313c,
+ 0x8e74, 0x15d5,
+ 0x8e75, 0x3f89,
+ 0x8e76, 0x15d2,
+ 0x8e77, 0x3f7f,
+ 0x8e78, 0x313b,
+ 0x8e7a, 0x15d4,
+ 0x8e7b, 0x313f,
+ 0x8e7c, 0x15cf,
+ 0x8e7e, 0x4324,
+ 0x8e80, 0x3e57,
+ 0x8e81, 0x164d,
+ 0x8e82, 0x164f,
+ 0x8e84, 0x3240,
+ 0x8e85, 0x164e,
+ 0x8e86, 0x323e,
+ 0x8e87, 0x15d1,
+ 0x8e88, 0x323f,
+ 0x8e89, 0x164c,
+ 0x8e8a, 0x1693,
+ 0x8e8b, 0x1695,
+ 0x8e8c, 0x331a,
+ 0x8e8d, 0x1694,
+ 0x8e8e, 0x3319,
+ 0x8e90, 0x33c1,
+ 0x8e91, 0x16db,
+ 0x8e92, 0x33c0,
+ 0x8e93, 0x16dc,
+ 0x8e94, 0x33be,
+ 0x8e95, 0x33bd,
+ 0x8e96, 0x33c2,
+ 0x8e98, 0x3443,
+ 0x8e9a, 0x33bf,
+ 0x8e9d, 0x34a1,
+ 0x8e9e, 0x349e,
+ 0x8ea1, 0x1749,
+ 0x8ea3, 0x34eb,
+ 0x8ea4, 0x34ea,
+ 0x8ea5, 0x34e9,
+ 0x8ea6, 0x350a,
+ 0x8ea7, 0x3bb5,
+ 0x8ea8, 0x3537,
+ 0x8ea9, 0x3524,
+ 0x8eaa, 0x175b,
+ 0x8eab, 0x0512,
+ 0x8eac, 0x09cf,
+ 0x8ead, 0x385e,
+ 0x8eb0, 0x43e9,
+ 0x8eb2, 0x0f2f,
+ 0x8eb6, 0x385f,
+ 0x8eba, 0x123d,
+ 0x8ebc, 0x38a0,
+ 0x8ebd, 0x2cad,
+ 0x8ec0, 0x1536,
+ 0x8ec2, 0x3140,
+ 0x8ec3, 0x3860,
+ 0x8ec9, 0x3525,
+ 0x8eca, 0x0513,
+ 0x8ecb, 0x068d,
+ 0x8ecc, 0x0810,
+ 0x8ecd, 0x080f,
+ 0x8ece, 0x4788,
+ 0x8ecf, 0x09d2,
+ 0x8ed1, 0x1e13,
+ 0x8ed2, 0x09d0,
+ 0x8ed3, 0x1e14,
+ 0x8ed4, 0x09d1,
+ 0x8ed7, 0x207d,
+ 0x8ed8, 0x2079,
+ 0x8eda, 0x3dbe,
+ 0x8edb, 0x0bb3,
+ 0x8edc, 0x207c,
+ 0x8edd, 0x207b,
+ 0x8ede, 0x207a,
+ 0x8edf, 0x0bb4,
+ 0x8ee0, 0x207e,
+ 0x8ee2, 0x4789,
+ 0x8ee4, 0x478a,
+ 0x8ee5, 0x2315,
+ 0x8ee6, 0x2313,
+ 0x8ee7, 0x2317,
+ 0x8ee9, 0x231e,
+ 0x8eeb, 0x231a,
+ 0x8eec, 0x231c,
+ 0x8eed, 0x478b,
+ 0x8eee, 0x2314,
+ 0x8eef, 0x230f,
+ 0x8ef1, 0x231b,
+ 0x8ef2, 0x478c,
+ 0x8ef4, 0x231d,
+ 0x8ef5, 0x2316,
+ 0x8ef6, 0x2319,
+ 0x8ef7, 0x2310,
+ 0x8ef8, 0x0d7f,
+ 0x8ef9, 0x2312,
+ 0x8efa, 0x2311,
+ 0x8efb, 0x0d7e,
+ 0x8efc, 0x0d80,
+ 0x8efe, 0x0f32,
+ 0x8eff, 0x25ba,
+ 0x8f00, 0x25bc,
+ 0x8f01, 0x25bb,
+ 0x8f02, 0x25c0,
+ 0x8f03, 0x0f30,
+ 0x8f05, 0x25bd,
+ 0x8f06, 0x25b9,
+ 0x8f07, 0x25be,
+ 0x8f09, 0x0f31,
+ 0x8f0a, 0x0f33,
+ 0x8f0b, 0x25c1,
+ 0x8f0d, 0x2820,
+ 0x8f0e, 0x281f,
+ 0x8f10, 0x281d,
+ 0x8f12, 0x10bf,
+ 0x8f13, 0x10c1,
+ 0x8f14, 0x10be,
+ 0x8f15, 0x10c0,
+ 0x8f16, 0x2a7a,
+ 0x8f18, 0x2a76,
+ 0x8f19, 0x3862,
+ 0x8f1a, 0x2a77,
+ 0x8f1b, 0x123f,
+ 0x8f1c, 0x1244,
+ 0x8f1d, 0x123e,
+ 0x8f1e, 0x1245,
+ 0x8f1f, 0x1240,
+ 0x8f20, 0x2a78,
+ 0x8f23, 0x2a79,
+ 0x8f24, 0x2a75,
+ 0x8f25, 0x1246,
+ 0x8f26, 0x1242,
+ 0x8f29, 0x1241,
+ 0x8f2a, 0x1243,
+ 0x8f2c, 0x2a74,
+ 0x8f2d, 0x3863,
+ 0x8f2e, 0x2caf,
+ 0x8f2f, 0x1368,
+ 0x8f30, 0x3bb7,
+ 0x8f32, 0x2cb1,
+ 0x8f33, 0x136a,
+ 0x8f34, 0x2cb4,
+ 0x8f35, 0x2cb0,
+ 0x8f36, 0x2cae,
+ 0x8f37, 0x2cb3,
+ 0x8f38, 0x1369,
+ 0x8f39, 0x2cb2,
+ 0x8f3b, 0x1367,
+ 0x8f3e, 0x148e,
+ 0x8f3f, 0x1491,
+ 0x8f40, 0x2e7c,
+ 0x8f41, 0x3d07,
+ 0x8f42, 0x148f,
+ 0x8f43, 0x2e7b,
+ 0x8f44, 0x148d,
+ 0x8f45, 0x1490,
+ 0x8f46, 0x2ff7,
+ 0x8f49, 0x1537,
+ 0x8f4a, 0x3bb8,
+ 0x8f4b, 0x2ffa,
+ 0x8f4d, 0x1538,
+ 0x8f4e, 0x15d7,
+ 0x8f4f, 0x3143,
+ 0x8f51, 0x3142,
+ 0x8f52, 0x3141,
+ 0x8f53, 0x3145,
+ 0x8f54, 0x15d6,
+ 0x8f55, 0x3244,
+ 0x8f56, 0x3242,
+ 0x8f58, 0x3245,
+ 0x8f59, 0x3241,
+ 0x8f5a, 0x3246,
+ 0x8f5b, 0x331c,
+ 0x8f5c, 0x3f31,
+ 0x8f5d, 0x331d,
+ 0x8f5e, 0x331b,
+ 0x8f5f, 0x1696,
+ 0x8f60, 0x33c4,
+ 0x8f61, 0x16dd,
+ 0x8f62, 0x33c5,
+ 0x8f63, 0x3445,
+ 0x8f64, 0x3444,
+ 0x8f66, 0x4569,
+ 0x8f6e, 0x456b,
+ 0x8f93, 0x4732,
+ 0x8f9b, 0x0514,
+ 0x8f9c, 0x0d81,
+ 0x8f9f, 0x0f34,
+ 0x8fa0, 0x3d94,
+ 0x8fa3, 0x10c2,
+ 0x8fa5, 0x3866,
+ 0x8fa6, 0x136c,
+ 0x8fa8, 0x136b,
+ 0x8fad, 0x15d8,
+ 0x8fae, 0x162f,
+ 0x8faf, 0x1697,
+ 0x8fb0, 0x0515,
+ 0x8fb1, 0x09d3,
+ 0x8fb2, 0x0f35,
+ 0x8fb3, 0x386a,
+ 0x8fb4, 0x3146,
+ 0x8fb5, 0x0230,
+ 0x8fb6, 0x47d3,
+ 0x8fb7, 0x43fd,
+ 0x8fb8, 0x42f6,
+ 0x8fb9, 0x48c9,
+ 0x8fba, 0x48c7,
+ 0x8fbb, 0x3d6b,
+ 0x8fbe, 0x48c6,
+ 0x8fbf, 0x18e9,
+ 0x8fc1, 0x478d,
+ 0x8fc2, 0x0516,
+ 0x8fc4, 0x0519,
+ 0x8fc5, 0x0518,
+ 0x8fc6, 0x0517,
+ 0x8fc9, 0x18e8,
+ 0x8fca, 0x478e,
+ 0x8fcb, 0x1a4a,
+ 0x8fcc, 0x478f,
+ 0x8fcd, 0x1a4c,
+ 0x8fce, 0x068e,
+ 0x8fd0, 0x48ae,
+ 0x8fd1, 0x0690,
+ 0x8fd2, 0x1a49,
+ 0x8fd3, 0x1a4b,
+ 0x8fd4, 0x068f,
+ 0x8fd5, 0x1a4e,
+ 0x8fd6, 0x1a4d,
+ 0x8fd7, 0x1a4f,
+ 0x8fda, 0x3fcb,
+ 0x8fe0, 0x1c0a,
+ 0x8fe1, 0x1c08,
+ 0x8fe2, 0x0813,
+ 0x8fe3, 0x1c07,
+ 0x8fe4, 0x0818,
+ 0x8fe5, 0x0815,
+ 0x8fe6, 0x0812,
+ 0x8fe8, 0x0819,
+ 0x8fea, 0x0814,
+ 0x8feb, 0x0817,
+ 0x8fed, 0x0816,
+ 0x8fee, 0x1c09,
+ 0x8ff0, 0x0811,
+ 0x8ff4, 0x09d9,
+ 0x8ff5, 0x1e16,
+ 0x8ff6, 0x1e1c,
+ 0x8ff7, 0x09d6,
+ 0x8ff8, 0x09dd,
+ 0x8ff9, 0x3871,
+ 0x8ffa, 0x09d8,
+ 0x8ffb, 0x1e19,
+ 0x8ffc, 0x1e1b,
+ 0x8ffd, 0x09db,
+ 0x8ffe, 0x1e15,
+ 0x8fff, 0x1e18,
+ 0x9000, 0x09d7,
+ 0x9001, 0x09d4,
+ 0x9002, 0x1e17,
+ 0x9003, 0x09da,
+ 0x9004, 0x1e1a,
+ 0x9005, 0x09dc,
+ 0x9006, 0x09d5,
+ 0x9008, 0x3ee0,
+ 0x900b, 0x2081,
+ 0x900c, 0x2084,
+ 0x900d, 0x0bb6,
+ 0x900f, 0x0bc0,
+ 0x9010, 0x0bbc,
+ 0x9011, 0x2082,
+ 0x9012, 0x3e4e,
+ 0x9014, 0x0bc4,
+ 0x9015, 0x0bbd,
+ 0x9016, 0x0bc2,
+ 0x9017, 0x0bb8,
+ 0x9019, 0x0bb5,
+ 0x901a, 0x0bb7,
+ 0x901b, 0x0bc3,
+ 0x901c, 0x2083,
+ 0x901d, 0x0bbb,
+ 0x901e, 0x0bbe,
+ 0x901f, 0x0bba,
+ 0x9020, 0x0bbf,
+ 0x9021, 0x2085,
+ 0x9022, 0x0bc1,
+ 0x9023, 0x0bb9,
+ 0x9024, 0x2080,
+ 0x902d, 0x231f,
+ 0x902e, 0x0d82,
+ 0x902f, 0x2321,
+ 0x9031, 0x0d84,
+ 0x9032, 0x0d86,
+ 0x9033, 0x4790,
+ 0x9034, 0x2320,
+ 0x9035, 0x0d83,
+ 0x9036, 0x0d87,
+ 0x9037, 0x3876,
+ 0x9038, 0x0d85,
+ 0x903c, 0x0f3b,
+ 0x903d, 0x25c6,
+ 0x903e, 0x0f43,
+ 0x903f, 0x25c3,
+ 0x9041, 0x0f44,
+ 0x9042, 0x0f39,
+ 0x9044, 0x25c4,
+ 0x9047, 0x0f3e,
+ 0x9049, 0x25c5,
+ 0x904a, 0x0f37,
+ 0x904b, 0x0f36,
+ 0x904c, 0x3f10,
+ 0x904d, 0x0f41,
+ 0x904e, 0x0f40,
+ 0x904f, 0x0f3f,
+ 0x9050, 0x0f3d,
+ 0x9051, 0x0f42,
+ 0x9052, 0x25c2,
+ 0x9053, 0x0f38,
+ 0x9054, 0x0f3a,
+ 0x9055, 0x0f3c,
+ 0x9056, 0x3dd2,
+ 0x9058, 0x10c4,
+ 0x9059, 0x10c7,
+ 0x905b, 0x10cb,
+ 0x905c, 0x10c5,
+ 0x905d, 0x10ca,
+ 0x905e, 0x10c8,
+ 0x9060, 0x10c3,
+ 0x9061, 0x3879,
+ 0x9062, 0x10c9,
+ 0x9063, 0x10c6,
+ 0x9064, 0x3c68,
+ 0x9067, 0x2a7f,
+ 0x9068, 0x1249,
+ 0x9069, 0x1247,
+ 0x906b, 0x2a80,
+ 0x906c, 0x3d60,
+ 0x906d, 0x124a,
+ 0x906e, 0x1248,
+ 0x906f, 0x2a7e,
+ 0x9070, 0x2a7d,
+ 0x9072, 0x1370,
+ 0x9073, 0x2a7c,
+ 0x9074, 0x136e,
+ 0x9075, 0x136d,
+ 0x9076, 0x2cb5,
+ 0x9077, 0x124b,
+ 0x9078, 0x136f,
+ 0x9079, 0x2cb6,
+ 0x907a, 0x1372,
+ 0x907b, 0x2cb7,
+ 0x907c, 0x1371,
+ 0x907d, 0x1493,
+ 0x907e, 0x2e7e,
+ 0x907f, 0x1492,
+ 0x9080, 0x1497,
+ 0x9081, 0x1495,
+ 0x9083, 0x153a,
+ 0x9084, 0x1494,
+ 0x9085, 0x2e7d,
+ 0x9086, 0x2cb8,
+ 0x9087, 0x1539,
+ 0x9088, 0x153b,
+ 0x908a, 0x15d9,
+ 0x908d, 0x3247,
+ 0x908f, 0x170c,
+ 0x9090, 0x170b,
+ 0x9091, 0x051b,
+ 0x9094, 0x181e,
+ 0x9095, 0x09de,
+ 0x9097, 0x181b,
+ 0x9099, 0x181a,
+ 0x909b, 0x181d,
+ 0x909e, 0x18ed,
+ 0x909f, 0x18ea,
+ 0x90a0, 0x18ef,
+ 0x90a1, 0x18eb,
+ 0x90a2, 0x051c,
+ 0x90a3, 0x051f,
+ 0x90a5, 0x18ec,
+ 0x90a6, 0x051e,
+ 0x90a7, 0x18ee,
+ 0x90a8, 0x387c,
+ 0x90aa, 0x051d,
+ 0x90ae, 0x3880,
+ 0x90af, 0x1a52,
+ 0x90b0, 0x1a54,
+ 0x90b1, 0x0693,
+ 0x90b2, 0x1a50,
+ 0x90b3, 0x1a53,
+ 0x90b4, 0x1a51,
+ 0x90b5, 0x0691,
+ 0x90b6, 0x0694,
+ 0x90b8, 0x0692,
+ 0x90bb, 0x3bc4,
+ 0x90bd, 0x1c0c,
+ 0x90be, 0x1c10,
+ 0x90bf, 0x1c0d,
+ 0x90c1, 0x081c,
+ 0x90c3, 0x081d,
+ 0x90c4, 0x387e,
+ 0x90c5, 0x1c0f,
+ 0x90c7, 0x1c11,
+ 0x90c8, 0x1c13,
+ 0x90ca, 0x081a,
+ 0x90cb, 0x1c12,
+ 0x90ce, 0x081b,
+ 0x90d4, 0x208c,
+ 0x90d5, 0x1c0e,
+ 0x90d6, 0x1e1d,
+ 0x90d7, 0x1e26,
+ 0x90d8, 0x1e24,
+ 0x90d9, 0x1e1f,
+ 0x90db, 0x1e25,
+ 0x90dc, 0x1e27,
+ 0x90dd, 0x09e0,
+ 0x90df, 0x1e22,
+ 0x90e0, 0x1e1e,
+ 0x90e1, 0x09df,
+ 0x90e2, 0x09e1,
+ 0x90e3, 0x1e21,
+ 0x90e4, 0x1e28,
+ 0x90e5, 0x1e23,
+ 0x90e8, 0x0bc5,
+ 0x90e9, 0x208f,
+ 0x90ea, 0x2087,
+ 0x90eb, 0x208d,
+ 0x90ed, 0x0bc6,
+ 0x90ef, 0x2086,
+ 0x90f0, 0x2088,
+ 0x90f1, 0x1c0b,
+ 0x90f2, 0x208a,
+ 0x90f4, 0x2089,
+ 0x90f5, 0x0d89,
+ 0x90f9, 0x2328,
+ 0x90fa, 0x2cb9,
+ 0x90fb, 0x2329,
+ 0x90fc, 0x2326,
+ 0x90fd, 0x0bc7,
+ 0x90fe, 0x0d8b,
+ 0x90ff, 0x2325,
+ 0x9100, 0x232b,
+ 0x9101, 0x232a,
+ 0x9102, 0x0d88,
+ 0x9103, 0x232e,
+ 0x9104, 0x2324,
+ 0x9105, 0x232d,
+ 0x9106, 0x2322,
+ 0x9107, 0x232c,
+ 0x9108, 0x2327,
+ 0x9109, 0x0d8a,
+ 0x910b, 0x25cd,
+ 0x910d, 0x25c8,
+ 0x910e, 0x25ce,
+ 0x910f, 0x25c9,
+ 0x9110, 0x25c7,
+ 0x9111, 0x25ca,
+ 0x9112, 0x0f45,
+ 0x9114, 0x25cc,
+ 0x9116, 0x25cb,
+ 0x9117, 0x0f46,
+ 0x9118, 0x10cd,
+ 0x9119, 0x10cc,
+ 0x911a, 0x2827,
+ 0x911b, 0x282a,
+ 0x911c, 0x2822,
+ 0x911d, 0x2826,
+ 0x911e, 0x10ce,
+ 0x911f, 0x2825,
+ 0x9120, 0x2823,
+ 0x9121, 0x2829,
+ 0x9122, 0x2824,
+ 0x9123, 0x2821,
+ 0x9124, 0x2828,
+ 0x9126, 0x2a86,
+ 0x9127, 0x124e,
+ 0x9128, 0x2ffb,
+ 0x9129, 0x2a83,
+ 0x912b, 0x2a82,
+ 0x912c, 0x2323,
+ 0x912d, 0x124d,
+ 0x912e, 0x2a87,
+ 0x912f, 0x2a81,
+ 0x9130, 0x124c,
+ 0x9131, 0x124f,
+ 0x9132, 0x2a85,
+ 0x9133, 0x2cba,
+ 0x9134, 0x1373,
+ 0x9135, 0x2cbb,
+ 0x9138, 0x2e7f,
+ 0x9139, 0x1498,
+ 0x913a, 0x2ffc,
+ 0x913e, 0x2ffe,
+ 0x913f, 0x3148,
+ 0x9140, 0x3147,
+ 0x9141, 0x3249,
+ 0x9143, 0x3248,
+ 0x9144, 0x331f,
+ 0x9146, 0x331e,
+ 0x9147, 0x33c6,
+ 0x9148, 0x16de,
+ 0x9149, 0x0520,
+ 0x914a, 0x081f,
+ 0x914b, 0x081e,
+ 0x914c, 0x09e4,
+ 0x914d, 0x09e3,
+ 0x914e, 0x1e2a,
+ 0x9150, 0x1e29,
+ 0x9151, 0x3f49,
+ 0x9152, 0x09e2,
+ 0x9153, 0x2093,
+ 0x9155, 0x2094,
+ 0x9156, 0x2090,
+ 0x9157, 0x0bc8,
+ 0x9158, 0x2091,
+ 0x9159, 0x3f45,
+ 0x915a, 0x2092,
+ 0x915c, 0x3f47,
+ 0x915e, 0x43eb,
+ 0x915f, 0x2331,
+ 0x9160, 0x2333,
+ 0x9161, 0x232f,
+ 0x9162, 0x2332,
+ 0x9163, 0x0d8c,
+ 0x9164, 0x2330,
+ 0x9165, 0x0d8d,
+ 0x9167, 0x3882,
+ 0x9168, 0x23e2,
+ 0x9169, 0x0f49,
+ 0x916a, 0x0f48,
+ 0x916c, 0x0f47,
+ 0x916e, 0x25cf,
+ 0x9170, 0x3eb8,
+ 0x9172, 0x282c,
+ 0x9173, 0x282e,
+ 0x9174, 0x10d2,
+ 0x9175, 0x10cf,
+ 0x9176, 0x3e9b,
+ 0x9177, 0x10d1,
+ 0x9178, 0x10d0,
+ 0x9179, 0x282d,
+ 0x917a, 0x282b,
+ 0x917c, 0x3f6f,
+ 0x9180, 0x2a8e,
+ 0x9181, 0x2a8b,
+ 0x9183, 0x1253,
+ 0x9184, 0x2a8d,
+ 0x9185, 0x2a88,
+ 0x9187, 0x1250,
+ 0x9189, 0x1251,
+ 0x918a, 0x2a8a,
+ 0x918b, 0x1252,
+ 0x918c, 0x43ec,
+ 0x918d, 0x2cc0,
+ 0x918e, 0x3f4e,
+ 0x918f, 0x2cc1,
+ 0x9190, 0x2cbe,
+ 0x9192, 0x1374,
+ 0x9193, 0x2cbd,
+ 0x9199, 0x2e83,
+ 0x919a, 0x2e80,
+ 0x919b, 0x2e82,
+ 0x919c, 0x149b,
+ 0x919d, 0x2e86,
+ 0x919e, 0x149a,
+ 0x919f, 0x2e84,
+ 0x91a0, 0x2e87,
+ 0x91a1, 0x2e85,
+ 0x91a2, 0x2e81,
+ 0x91a3, 0x1499,
+ 0x91a5, 0x3000,
+ 0x91a7, 0x3001,
+ 0x91a8, 0x2fff,
+ 0x91a9, 0x3883,
+ 0x91aa, 0x3003,
+ 0x91ab, 0x153c,
+ 0x91ad, 0x314a,
+ 0x91ae, 0x15dc,
+ 0x91af, 0x3002,
+ 0x91b0, 0x3149,
+ 0x91b1, 0x15db,
+ 0x91b2, 0x324c,
+ 0x91b4, 0x1650,
+ 0x91b5, 0x324b,
+ 0x91b6, 0x45ef,
+ 0x91b7, 0x324a,
+ 0x91b9, 0x3321,
+ 0x91ba, 0x1698,
+ 0x91bb, 0x3bc8,
+ 0x91bc, 0x3446,
+ 0x91bd, 0x34a3,
+ 0x91be, 0x34a2,
+ 0x91c0, 0x1730,
+ 0x91c1, 0x174a,
+ 0x91c2, 0x34a4,
+ 0x91c3, 0x350b,
+ 0x91c4, 0x3884,
+ 0x91c5, 0x175c,
+ 0x91c6, 0x0521,
+ 0x91c7, 0x0695,
+ 0x91c9, 0x0f4a,
+ 0x91cb, 0x1651,
+ 0x91cc, 0x0522,
+ 0x91cd, 0x0820,
+ 0x91ce, 0x0bc9,
+ 0x91cf, 0x0d8e,
+ 0x91d0, 0x153e,
+ 0x91d1, 0x0696,
+ 0x91d3, 0x1c15,
+ 0x91d4, 0x1c14,
+ 0x91d5, 0x1e2c,
+ 0x91d6, 0x415e,
+ 0x91d7, 0x09e7,
+ 0x91d8, 0x09e5,
+ 0x91d9, 0x09e9,
+ 0x91da, 0x1e2e,
+ 0x91dc, 0x09e8,
+ 0x91dd, 0x09e6,
+ 0x91df, 0x453a,
+ 0x91e2, 0x1e2d,
+ 0x91e3, 0x0bcc,
+ 0x91e4, 0x209a,
+ 0x91e5, 0x3c06,
+ 0x91e6, 0x0bcb,
+ 0x91e7, 0x0bcd,
+ 0x91e8, 0x209f,
+ 0x91e9, 0x0bcf,
+ 0x91ea, 0x209c,
+ 0x91ec, 0x2095,
+ 0x91ed, 0x0bce,
+ 0x91ee, 0x20a0,
+ 0x91f1, 0x2097,
+ 0x91f3, 0x2098,
+ 0x91f4, 0x2096,
+ 0x91f5, 0x0bca,
+ 0x91f7, 0x209e,
+ 0x91f8, 0x2099,
+ 0x91f9, 0x209b,
+ 0x91fa, 0x3af8,
+ 0x91fd, 0x233f,
+ 0x91fe, 0x382e,
+ 0x91ff, 0x233e,
+ 0x9200, 0x233c,
+ 0x9201, 0x2334,
+ 0x9202, 0x2343,
+ 0x9203, 0x2337,
+ 0x9204, 0x2341,
+ 0x9205, 0x2348,
+ 0x9206, 0x2340,
+ 0x9207, 0x0d96,
+ 0x9208, 0x3eb9,
+ 0x9209, 0x0d92,
+ 0x920a, 0x2335,
+ 0x920c, 0x233b,
+ 0x920d, 0x0d94,
+ 0x920e, 0x3888,
+ 0x920f, 0x233a,
+ 0x9210, 0x0d95,
+ 0x9211, 0x0d97,
+ 0x9212, 0x233d,
+ 0x9213, 0x4793,
+ 0x9214, 0x0d8f,
+ 0x9216, 0x2349,
+ 0x9217, 0x2347,
+ 0x9219, 0x2346,
+ 0x921a, 0x2338,
+ 0x921c, 0x2344,
+ 0x921e, 0x0d93,
+ 0x9223, 0x0d91,
+ 0x9224, 0x2345,
+ 0x9225, 0x2336,
+ 0x9226, 0x2339,
+ 0x9227, 0x2342,
+ 0x9228, 0x4795,
+ 0x922a, 0x3c0e,
+ 0x922b, 0x3ba6,
+ 0x922d, 0x2851,
+ 0x922e, 0x25da,
+ 0x9230, 0x25d3,
+ 0x9231, 0x25e6,
+ 0x9232, 0x25ef,
+ 0x9233, 0x25d6,
+ 0x9234, 0x0f55,
+ 0x9235, 0x3b26,
+ 0x9236, 0x25e3,
+ 0x9237, 0x0f4b,
+ 0x9238, 0x0f4d,
+ 0x9239, 0x0f59,
+ 0x923a, 0x25d4,
+ 0x923c, 0x41d2,
+ 0x923d, 0x0f4e,
+ 0x923e, 0x0f50,
+ 0x923f, 0x0f5a,
+ 0x9240, 0x0f4f,
+ 0x9241, 0x388a,
+ 0x9244, 0x389a,
+ 0x9245, 0x0f58,
+ 0x9246, 0x25dc,
+ 0x9248, 0x25d1,
+ 0x9249, 0x0f56,
+ 0x924a, 0x25db,
+ 0x924b, 0x0f52,
+ 0x924c, 0x25ed,
+ 0x924d, 0x0f57,
+ 0x924e, 0x25eb,
+ 0x924f, 0x25df,
+ 0x9250, 0x25e9,
+ 0x9251, 0x0f54,
+ 0x9252, 0x25d2,
+ 0x9253, 0x25ec,
+ 0x9254, 0x25e7,
+ 0x9255, 0x3e47,
+ 0x9256, 0x25ee,
+ 0x9257, 0x0f4c,
+ 0x9258, 0x4796,
+ 0x925a, 0x0f5b,
+ 0x925b, 0x0f51,
+ 0x925d, 0x3a03,
+ 0x925e, 0x25d8,
+ 0x925f, 0x3ce0,
+ 0x9260, 0x25e0,
+ 0x9261, 0x25e4,
+ 0x9262, 0x388b,
+ 0x9263, 0x25e8,
+ 0x9264, 0x0f53,
+ 0x9265, 0x25d7,
+ 0x9266, 0x25d5,
+ 0x9267, 0x25e1,
+ 0x926b, 0x4797,
+ 0x926c, 0x25de,
+ 0x926d, 0x25dd,
+ 0x926e, 0x3d05,
+ 0x926f, 0x25e2,
+ 0x9270, 0x25e5,
+ 0x9272, 0x25ea,
+ 0x9276, 0x2831,
+ 0x9277, 0x3c64,
+ 0x9278, 0x10d3,
+ 0x9279, 0x283b,
+ 0x927a, 0x2833,
+ 0x927b, 0x10d9,
+ 0x927c, 0x10dd,
+ 0x927d, 0x2844,
+ 0x927e, 0x284c,
+ 0x927f, 0x283d,
+ 0x9280, 0x10d5,
+ 0x9281, 0x3e01,
+ 0x9282, 0x2841,
+ 0x9283, 0x25d9,
+ 0x9284, 0x3cb9,
+ 0x9285, 0x10d6,
+ 0x9286, 0x2848,
+ 0x9287, 0x284d,
+ 0x9288, 0x2845,
+ 0x9289, 0x3ab5,
+ 0x928a, 0x2847,
+ 0x928b, 0x2850,
+ 0x928c, 0x2849,
+ 0x928d, 0x2837,
+ 0x928e, 0x2840,
+ 0x928f, 0x46bd,
+ 0x9291, 0x10de,
+ 0x9293, 0x10da,
+ 0x9294, 0x2835,
+ 0x9295, 0x2842,
+ 0x9296, 0x10d8,
+ 0x9297, 0x283c,
+ 0x9298, 0x10d7,
+ 0x9299, 0x284a,
+ 0x929a, 0x2839,
+ 0x929b, 0x2832,
+ 0x929c, 0x10db,
+ 0x929d, 0x284f,
+ 0x92a0, 0x2834,
+ 0x92a1, 0x2846,
+ 0x92a2, 0x2843,
+ 0x92a3, 0x283e,
+ 0x92a4, 0x2830,
+ 0x92a5, 0x282f,
+ 0x92a6, 0x2838,
+ 0x92a7, 0x284b,
+ 0x92a8, 0x10dc,
+ 0x92a9, 0x284e,
+ 0x92aa, 0x2836,
+ 0x92ab, 0x283a,
+ 0x92ac, 0x10d4,
+ 0x92ae, 0x4799,
+ 0x92b1, 0x4798,
+ 0x92b2, 0x125f,
+ 0x92b3, 0x125a,
+ 0x92b4, 0x2ab0,
+ 0x92b5, 0x2aac,
+ 0x92b6, 0x2a94,
+ 0x92b7, 0x1256,
+ 0x92b9, 0x36e9,
+ 0x92ba, 0x3bf5,
+ 0x92bb, 0x1255,
+ 0x92bc, 0x125b,
+ 0x92be, 0x3c60,
+ 0x92bf, 0x479a,
+ 0x92c0, 0x2a92,
+ 0x92c1, 0x1259,
+ 0x92c2, 0x2a9e,
+ 0x92c3, 0x2a90,
+ 0x92c5, 0x1254,
+ 0x92c6, 0x2aaf,
+ 0x92c7, 0x125d,
+ 0x92c8, 0x2aa1,
+ 0x92c9, 0x2aa6,
+ 0x92ca, 0x2aa0,
+ 0x92cb, 0x2cd3,
+ 0x92cc, 0x2a9c,
+ 0x92cd, 0x2aa4,
+ 0x92ce, 0x2aa2,
+ 0x92cf, 0x2a95,
+ 0x92d0, 0x2a8f,
+ 0x92d1, 0x2aaa,
+ 0x92d2, 0x125c,
+ 0x92d3, 0x2aab,
+ 0x92d4, 0x3861,
+ 0x92d5, 0x2aa5,
+ 0x92d7, 0x2a9a,
+ 0x92d8, 0x2a98,
+ 0x92d9, 0x2a93,
+ 0x92db, 0x400c,
+ 0x92dd, 0x2a9b,
+ 0x92de, 0x2aa8,
+ 0x92df, 0x2a97,
+ 0x92e0, 0x2aa7,
+ 0x92e1, 0x2aad,
+ 0x92e3, 0x479b,
+ 0x92e4, 0x1258,
+ 0x92e5, 0x3ca2,
+ 0x92e6, 0x2aa3,
+ 0x92e7, 0x2aa9,
+ 0x92e8, 0x2a9f,
+ 0x92e9, 0x2a99,
+ 0x92ea, 0x1257,
+ 0x92eb, 0x479c,
+ 0x92ec, 0x3964,
+ 0x92ee, 0x283f,
+ 0x92ef, 0x2a9d,
+ 0x92f0, 0x125e,
+ 0x92f1, 0x2a96,
+ 0x92f2, 0x3ab2,
+ 0x92f3, 0x479d,
+ 0x92f6, 0x3c04,
+ 0x92f7, 0x2cd8,
+ 0x92f8, 0x1377,
+ 0x92f9, 0x2cd7,
+ 0x92fa, 0x2cd5,
+ 0x92fb, 0x2ce7,
+ 0x92fc, 0x137b,
+ 0x92fd, 0x479f,
+ 0x92fe, 0x2ce4,
+ 0x92ff, 0x2cdc,
+ 0x9300, 0x2ce6,
+ 0x9301, 0x2cce,
+ 0x9302, 0x2cda,
+ 0x9303, 0x3867,
+ 0x9304, 0x137d,
+ 0x9306, 0x2cc6,
+ 0x9307, 0x3b11,
+ 0x9308, 0x2cc4,
+ 0x9309, 0x2ce5,
+ 0x930b, 0x2ce3,
+ 0x930c, 0x2ce2,
+ 0x930d, 0x2cd2,
+ 0x930e, 0x2cd1,
+ 0x930f, 0x2cc7,
+ 0x9310, 0x137f,
+ 0x9312, 0x2ccd,
+ 0x9313, 0x2cd6,
+ 0x9314, 0x2ce1,
+ 0x9315, 0x1382,
+ 0x9316, 0x2ce8,
+ 0x9318, 0x14a3,
+ 0x9319, 0x1384,
+ 0x931a, 0x137e,
+ 0x931b, 0x2ccb,
+ 0x931d, 0x2cd4,
+ 0x931e, 0x2cc3,
+ 0x931f, 0x2cc5,
+ 0x9320, 0x1375,
+ 0x9321, 0x1381,
+ 0x9322, 0x137a,
+ 0x9323, 0x2ccc,
+ 0x9324, 0x2cdb,
+ 0x9325, 0x2aae,
+ 0x9326, 0x1380,
+ 0x9327, 0x2cc2,
+ 0x9328, 0x149e,
+ 0x9329, 0x2cdd,
+ 0x932a, 0x2ce0,
+ 0x932b, 0x137c,
+ 0x932c, 0x3892,
+ 0x932d, 0x2cd0,
+ 0x932e, 0x1383,
+ 0x932f, 0x1379,
+ 0x9330, 0x3e03,
+ 0x9331, 0x3cbd,
+ 0x9333, 0x1378,
+ 0x9334, 0x2cd9,
+ 0x9335, 0x2cdf,
+ 0x9336, 0x1376,
+ 0x9338, 0x2cc9,
+ 0x9339, 0x2cde,
+ 0x933c, 0x2cca,
+ 0x9340, 0x4155,
+ 0x9341, 0x4277,
+ 0x9342, 0x3afa,
+ 0x9343, 0x47a0,
+ 0x9344, 0x4016,
+ 0x9345, 0x3e74,
+ 0x9346, 0x2ccf,
+ 0x9347, 0x2e8d,
+ 0x9348, 0x3c61,
+ 0x9349, 0x2e92,
+ 0x934a, 0x14a0,
+ 0x934b, 0x14a2,
+ 0x934c, 0x2e98,
+ 0x934d, 0x149c,
+ 0x934e, 0x2ea6,
+ 0x934f, 0x2e9e,
+ 0x9350, 0x2e93,
+ 0x9352, 0x2e9d,
+ 0x9354, 0x14a9,
+ 0x9355, 0x2e9c,
+ 0x9356, 0x2e8c,
+ 0x9357, 0x2e9b,
+ 0x9358, 0x2e8f,
+ 0x9359, 0x2ea7,
+ 0x935a, 0x14a8,
+ 0x935b, 0x14a6,
+ 0x935c, 0x2e90,
+ 0x935e, 0x2ea3,
+ 0x935f, 0x3cbb,
+ 0x9360, 0x2e95,
+ 0x9361, 0x2ea2,
+ 0x9362, 0x4268,
+ 0x9363, 0x2ea4,
+ 0x9364, 0x2e8b,
+ 0x9365, 0x14a1,
+ 0x9366, 0x46bc,
+ 0x9367, 0x2ea5,
+ 0x9368, 0x3bf0,
+ 0x9369, 0x3961,
+ 0x936a, 0x2e99,
+ 0x936b, 0x3893,
+ 0x936c, 0x14a5,
+ 0x936d, 0x2e96,
+ 0x936e, 0x39e8,
+ 0x9370, 0x14a7,
+ 0x9371, 0x2e9f,
+ 0x9373, 0x389e,
+ 0x9374, 0x3ce4,
+ 0x9375, 0x149f,
+ 0x9376, 0x2e91,
+ 0x9377, 0x2ea0,
+ 0x9378, 0x38f9,
+ 0x9379, 0x2e9a,
+ 0x937a, 0x2cc8,
+ 0x937b, 0x2ea1,
+ 0x937c, 0x2e8e,
+ 0x937d, 0x3c25,
+ 0x937e, 0x14a4,
+ 0x9380, 0x3014,
+ 0x9381, 0x3965,
+ 0x9382, 0x149d,
+ 0x9383, 0x2e89,
+ 0x9384, 0x47a1,
+ 0x9385, 0x42bd,
+ 0x9386, 0x3cc0,
+ 0x9387, 0x3ae0,
+ 0x9388, 0x3011,
+ 0x9389, 0x300a,
+ 0x938a, 0x1540,
+ 0x938c, 0x3005,
+ 0x938d, 0x3015,
+ 0x938e, 0x300c,
+ 0x938f, 0x2e97,
+ 0x9390, 0x3d3c,
+ 0x9391, 0x3017,
+ 0x9392, 0x3006,
+ 0x9394, 0x153f,
+ 0x9395, 0x3010,
+ 0x9396, 0x1541,
+ 0x9397, 0x1549,
+ 0x9398, 0x1547,
+ 0x9399, 0x3012,
+ 0x939a, 0x1548,
+ 0x939b, 0x3008,
+ 0x939c, 0x39ac,
+ 0x939d, 0x3009,
+ 0x939e, 0x300e,
+ 0x939f, 0x3013,
+ 0x93a0, 0x3ab1,
+ 0x93a1, 0x2e88,
+ 0x93a2, 0x1542,
+ 0x93a3, 0x301c,
+ 0x93a4, 0x3019,
+ 0x93a5, 0x3160,
+ 0x93a6, 0x300f,
+ 0x93a7, 0x300b,
+ 0x93a8, 0x301a,
+ 0x93a9, 0x3155,
+ 0x93aa, 0x300d,
+ 0x93ac, 0x1545,
+ 0x93ad, 0x47a2,
+ 0x93ae, 0x1544,
+ 0x93af, 0x2e8a,
+ 0x93b0, 0x1546,
+ 0x93b1, 0x3016,
+ 0x93b2, 0x3018,
+ 0x93b3, 0x1543,
+ 0x93b4, 0x301b,
+ 0x93b5, 0x3004,
+ 0x93b7, 0x3007,
+ 0x93b8, 0x3c90,
+ 0x93ba, 0x43f7,
+ 0x93bb, 0x3c8f,
+ 0x93bd, 0x3a27,
+ 0x93bf, 0x3e2d,
+ 0x93c0, 0x315e,
+ 0x93c2, 0x314e,
+ 0x93c3, 0x15e0,
+ 0x93c4, 0x315c,
+ 0x93c6, 0x39aa,
+ 0x93c7, 0x314c,
+ 0x93c8, 0x15e1,
+ 0x93ca, 0x3157,
+ 0x93cb, 0x3966,
+ 0x93cc, 0x3153,
+ 0x93cd, 0x15e6,
+ 0x93ce, 0x315d,
+ 0x93cf, 0x314d,
+ 0x93d0, 0x3150,
+ 0x93d1, 0x15de,
+ 0x93d2, 0x315f,
+ 0x93d3, 0x40e1,
+ 0x93d4, 0x3158,
+ 0x93d5, 0x315b,
+ 0x93d6, 0x15e4,
+ 0x93d7, 0x15e9,
+ 0x93d8, 0x15e7,
+ 0x93d9, 0x3154,
+ 0x93da, 0x314f,
+ 0x93db, 0x3c5f,
+ 0x93dc, 0x15e2,
+ 0x93de, 0x314b,
+ 0x93df, 0x15df,
+ 0x93e0, 0x3a20,
+ 0x93e1, 0x15dd,
+ 0x93e2, 0x15e5,
+ 0x93e3, 0x315a,
+ 0x93e4, 0x15e8,
+ 0x93e6, 0x3156,
+ 0x93e7, 0x3161,
+ 0x93e8, 0x15ea,
+ 0x93ec, 0x3152,
+ 0x93ee, 0x3159,
+ 0x93f0, 0x423f,
+ 0x93f1, 0x42aa,
+ 0x93f3, 0x3962,
+ 0x93f5, 0x325a,
+ 0x93f6, 0x3269,
+ 0x93f7, 0x325c,
+ 0x93f8, 0x3263,
+ 0x93f9, 0x3151,
+ 0x93fa, 0x3261,
+ 0x93fb, 0x3250,
+ 0x93fc, 0x3267,
+ 0x93fd, 0x1654,
+ 0x93fe, 0x3254,
+ 0x93ff, 0x3266,
+ 0x9400, 0x325b,
+ 0x9401, 0x3cd4,
+ 0x9403, 0x1653,
+ 0x9404, 0x3bc9,
+ 0x9406, 0x326b,
+ 0x9407, 0x325d,
+ 0x9408, 0x3a25,
+ 0x9409, 0x3262,
+ 0x940a, 0x3265,
+ 0x940b, 0x324e,
+ 0x940c, 0x3268,
+ 0x940d, 0x3259,
+ 0x940e, 0x325e,
+ 0x940f, 0x3252,
+ 0x9410, 0x3256,
+ 0x9411, 0x326a,
+ 0x9412, 0x3260,
+ 0x9413, 0x324f,
+ 0x9414, 0x3253,
+ 0x9415, 0x3255,
+ 0x9416, 0x325f,
+ 0x9417, 0x47a5,
+ 0x9418, 0x1652,
+ 0x9419, 0x3258,
+ 0x941b, 0x4148,
+ 0x941d, 0x47a6,
+ 0x9420, 0x3251,
+ 0x9424, 0x3943,
+ 0x9425, 0x38d0,
+ 0x9426, 0x38a3,
+ 0x9427, 0x3bcd,
+ 0x9428, 0x3257,
+ 0x9429, 0x3325,
+ 0x942a, 0x3329,
+ 0x942b, 0x169f,
+ 0x942c, 0x332b,
+ 0x942d, 0x47a7,
+ 0x942e, 0x1699,
+ 0x9430, 0x3327,
+ 0x9431, 0x332d,
+ 0x9432, 0x169e,
+ 0x9433, 0x169a,
+ 0x9435, 0x169b,
+ 0x9436, 0x3324,
+ 0x9437, 0x332a,
+ 0x9438, 0x169d,
+ 0x9439, 0x3328,
+ 0x943a, 0x169c,
+ 0x943b, 0x3323,
+ 0x943c, 0x3264,
+ 0x943d, 0x3326,
+ 0x943e, 0x47a8,
+ 0x943f, 0x3322,
+ 0x9440, 0x332c,
+ 0x9442, 0x4272,
+ 0x9443, 0x4275,
+ 0x9444, 0x16df,
+ 0x9445, 0x33cd,
+ 0x9446, 0x33d0,
+ 0x9447, 0x33cc,
+ 0x9448, 0x33ce,
+ 0x944a, 0x33c9,
+ 0x944c, 0x33c7,
+ 0x944d, 0x3c65,
+ 0x944f, 0x33cb,
+ 0x9450, 0x33c8,
+ 0x9451, 0x16e0,
+ 0x9454, 0x47aa,
+ 0x9455, 0x3448,
+ 0x9457, 0x344a,
+ 0x9458, 0x3c30,
+ 0x945b, 0x389f,
+ 0x945d, 0x3449,
+ 0x945e, 0x344b,
+ 0x9460, 0x170e,
+ 0x9462, 0x3447,
+ 0x9463, 0x170d,
+ 0x9464, 0x170f,
+ 0x9465, 0x3dde,
+ 0x9467, 0x3ab8,
+ 0x9468, 0x34a6,
+ 0x946a, 0x1731,
+ 0x946b, 0x34a5,
+ 0x946c, 0x377e,
+ 0x946d, 0x34ed,
+ 0x946e, 0x34ec,
+ 0x946f, 0x34ee,
+ 0x9470, 0x174c,
+ 0x9471, 0x34ef,
+ 0x9472, 0x174b,
+ 0x9473, 0x34f0,
+ 0x9474, 0x350c,
+ 0x9475, 0x350f,
+ 0x9476, 0x350e,
+ 0x9477, 0x1755,
+ 0x9478, 0x350d,
+ 0x9479, 0x47ab,
+ 0x947b, 0x419b,
+ 0x947c, 0x175f,
+ 0x947d, 0x175d,
+ 0x947f, 0x1764,
+ 0x9480, 0x3539,
+ 0x9482, 0x3538,
+ 0x9483, 0x3540,
+ 0x9485, 0x4507,
+ 0x949f, 0x4885,
+ 0x94a2, 0x451b,
+ 0x94c1, 0x47e1,
+ 0x94c3, 0x47df,
+ 0x94dc, 0x47d7,
+ 0x94f6, 0x47d2,
+ 0x952d, 0x47ac,
+ 0x9547, 0x48bf,
+ 0x9577, 0x0697,
+ 0x9578, 0x4508,
+ 0x957a, 0x20a1,
+ 0x957b, 0x234a,
+ 0x957c, 0x2ab1,
+ 0x957d, 0x3162,
+ 0x957f, 0x4509,
+ 0x9580, 0x0698,
+ 0x9582, 0x0821,
+ 0x9583, 0x09ea,
+ 0x9585, 0x38a1,
+ 0x9586, 0x20a2,
+ 0x9588, 0x20a3,
+ 0x9589, 0x0bd0,
+ 0x958b, 0x0d9a,
+ 0x958c, 0x234c,
+ 0x958d, 0x234b,
+ 0x958e, 0x0d9e,
+ 0x958f, 0x0d99,
+ 0x9590, 0x234d,
+ 0x9591, 0x0d9b,
+ 0x9592, 0x0d9d,
+ 0x9593, 0x0d9c,
+ 0x9594, 0x0d98,
+ 0x9596, 0x3bd5,
+ 0x9597, 0x3bd4,
+ 0x9598, 0x0f5c,
+ 0x9599, 0x3bd2,
+ 0x959b, 0x25f3,
+ 0x959c, 0x25f1,
+ 0x959e, 0x25f2,
+ 0x959f, 0x25f0,
+ 0x95a0, 0x38a4,
+ 0x95a1, 0x10df,
+ 0x95a2, 0x47ad,
+ 0x95a3, 0x10e2,
+ 0x95a4, 0x10e4,
+ 0x95a5, 0x10e3,
+ 0x95a6, 0x38a2,
+ 0x95a7, 0x3bd3,
+ 0x95a8, 0x10e0,
+ 0x95aa, 0x4395,
+ 0x95ab, 0x2ab3,
+ 0x95ac, 0x2ab2,
+ 0x95ad, 0x1260,
+ 0x95ae, 0x2ab4,
+ 0x95b0, 0x2ab5,
+ 0x95b1, 0x1261,
+ 0x95b5, 0x2cf0,
+ 0x95b6, 0x2cee,
+ 0x95b7, 0x2ead,
+ 0x95b9, 0x2cec,
+ 0x95bb, 0x1385,
+ 0x95bc, 0x2ce9,
+ 0x95bd, 0x2cf1,
+ 0x95be, 0x2ceb,
+ 0x95bf, 0x2cef,
+ 0x95c0, 0x2ea9,
+ 0x95c3, 0x2eab,
+ 0x95c5, 0x2eac,
+ 0x95c6, 0x14ae,
+ 0x95c7, 0x2ea8,
+ 0x95c8, 0x14ad,
+ 0x95c9, 0x2eaa,
+ 0x95ca, 0x14aa,
+ 0x95cd, 0x2cea,
+ 0x95d0, 0x154c,
+ 0x95d1, 0x301f,
+ 0x95d2, 0x301d,
+ 0x95d4, 0x154a,
+ 0x95d5, 0x154d,
+ 0x95d6, 0x154b,
+ 0x95da, 0x3163,
+ 0x95dc, 0x15eb,
+ 0x95de, 0x326c,
+ 0x95df, 0x326e,
+ 0x95e0, 0x326d,
+ 0x95e1, 0x1655,
+ 0x95e2, 0x16a0,
+ 0x95e3, 0x3330,
+ 0x95e4, 0x332f,
+ 0x95e5, 0x332e,
+ 0x95e8, 0x450a,
+ 0x95f4, 0x47af,
+ 0x961c, 0x0699,
+ 0x961d, 0x4519,
+ 0x961e, 0x17b4,
+ 0x9620, 0x1821,
+ 0x9621, 0x0414,
+ 0x9622, 0x181f,
+ 0x9623, 0x1822,
+ 0x9624, 0x1820,
+ 0x9628, 0x18f1,
+ 0x962a, 0x0526,
+ 0x962c, 0x0527,
+ 0x962d, 0x18f3,
+ 0x962e, 0x0524,
+ 0x962f, 0x18f2,
+ 0x9630, 0x18f0,
+ 0x9631, 0x0525,
+ 0x9632, 0x0523,
+ 0x9633, 0x47b0,
+ 0x9638, 0x3fd1,
+ 0x9639, 0x1a55,
+ 0x963a, 0x1a58,
+ 0x963b, 0x069c,
+ 0x963c, 0x1a57,
+ 0x963d, 0x1a56,
+ 0x963f, 0x069b,
+ 0x9640, 0x069a,
+ 0x9641, 0x3f3d,
+ 0x9642, 0x069e,
+ 0x9643, 0x1a59,
+ 0x9644, 0x069d,
+ 0x9645, 0x4772,
+ 0x964a, 0x1c1a,
+ 0x964b, 0x0823,
+ 0x964e, 0x1c1b,
+ 0x964f, 0x1c17,
+ 0x9650, 0x0822,
+ 0x9651, 0x1c18,
+ 0x9653, 0x1c19,
+ 0x9654, 0x1c16,
+ 0x9656, 0x3de7,
+ 0x9658, 0x09f1,
+ 0x965b, 0x09ee,
+ 0x965c, 0x1e2f,
+ 0x965d, 0x09ef,
+ 0x965e, 0x09f2,
+ 0x965f, 0x1e30,
+ 0x9661, 0x09ed,
+ 0x9662, 0x09eb,
+ 0x9664, 0x09f0,
+ 0x9669, 0x475e,
+ 0x966a, 0x0bd1,
+ 0x966b, 0x20a6,
+ 0x966c, 0x0bd9,
+ 0x966d, 0x20a5,
+ 0x966f, 0x20a8,
+ 0x9670, 0x0bd5,
+ 0x9671, 0x20a7,
+ 0x9672, 0x0da6,
+ 0x9673, 0x0bd3,
+ 0x9674, 0x0bd6,
+ 0x9675, 0x0bd2,
+ 0x9676, 0x0bd7,
+ 0x9678, 0x0bd4,
+ 0x967b, 0x38ac,
+ 0x967c, 0x20a4,
+ 0x967d, 0x0da2,
+ 0x967e, 0x234f,
+ 0x9680, 0x2353,
+ 0x9681, 0x3f46,
+ 0x9683, 0x2352,
+ 0x9684, 0x0da7,
+ 0x9685, 0x0da3,
+ 0x9687, 0x234e,
+ 0x9688, 0x2350,
+ 0x968a, 0x0d9f,
+ 0x968b, 0x0da1,
+ 0x968d, 0x0da5,
+ 0x968e, 0x0da0,
+ 0x968f, 0x3bde,
+ 0x9691, 0x25f6,
+ 0x9692, 0x25f4,
+ 0x9694, 0x0f5e,
+ 0x9696, 0x38ad,
+ 0x9697, 0x25f7,
+ 0x9698, 0x0f5d,
+ 0x9699, 0x10e5,
+ 0x969b, 0x10e7,
+ 0x969c, 0x10e6,
+ 0x969e, 0x2852,
+ 0x96a1, 0x2853,
+ 0x96a2, 0x2ab7,
+ 0x96a3, 0x38af,
+ 0x96a4, 0x2ab6,
+ 0x96a5, 0x42ef,
+ 0x96a7, 0x1386,
+ 0x96a9, 0x2cf2,
+ 0x96aa, 0x1388,
+ 0x96ac, 0x2eb0,
+ 0x96ae, 0x2eae,
+ 0x96b0, 0x2eaf,
+ 0x96b1, 0x14af,
+ 0x96b3, 0x3020,
+ 0x96b4, 0x15ec,
+ 0x96b6, 0x0231,
+ 0x96b8, 0x14b0,
+ 0x96b9, 0x069f,
+ 0x96bb, 0x09f3,
+ 0x96bc, 0x1e31,
+ 0x96bd, 0x38b5,
+ 0x96bf, 0x20a9,
+ 0x96c0, 0x0bda,
+ 0x96c1, 0x0da8,
+ 0x96c2, 0x2354,
+ 0x96c3, 0x2356,
+ 0x96c4, 0x0daa,
+ 0x96c5, 0x0da9,
+ 0x96c6, 0x0dab,
+ 0x96c8, 0x2355,
+ 0x96c9, 0x0f62,
+ 0x96cb, 0x0f61,
+ 0x96cc, 0x10e8,
+ 0x96cd, 0x0f60,
+ 0x96ce, 0x25f8,
+ 0x96d2, 0x10e9,
+ 0x96d3, 0x2ab8,
+ 0x96d4, 0x2cf3,
+ 0x96d5, 0x1389,
+ 0x96d6, 0x14b1,
+ 0x96d7, 0x3021,
+ 0x96d8, 0x3025,
+ 0x96d9, 0x1550,
+ 0x96da, 0x3022,
+ 0x96db, 0x1551,
+ 0x96dc, 0x154f,
+ 0x96dd, 0x3026,
+ 0x96de, 0x1552,
+ 0x96df, 0x3024,
+ 0x96e1, 0x3165,
+ 0x96e2, 0x154e,
+ 0x96e3, 0x15ed,
+ 0x96e5, 0x34a8,
+ 0x96e8, 0x06a0,
+ 0x96e9, 0x0bdc,
+ 0x96ea, 0x0bdb,
+ 0x96ef, 0x0dad,
+ 0x96f0, 0x2358,
+ 0x96f1, 0x2357,
+ 0x96f2, 0x0dae,
+ 0x96f4, 0x3a04,
+ 0x96f5, 0x25fc,
+ 0x96f6, 0x0f67,
+ 0x96f7, 0x0f64,
+ 0x96f8, 0x25fb,
+ 0x96f9, 0x0f66,
+ 0x96fa, 0x25f9,
+ 0x96fb, 0x0f65,
+ 0x96fd, 0x25fa,
+ 0x96ff, 0x2854,
+ 0x9700, 0x10ea,
+ 0x9702, 0x2abb,
+ 0x9703, 0x3f0d,
+ 0x9704, 0x1262,
+ 0x9705, 0x2ab9,
+ 0x9706, 0x1263,
+ 0x9708, 0x2aba,
+ 0x9709, 0x1265,
+ 0x970b, 0x2cf4,
+ 0x970d, 0x138d,
+ 0x970e, 0x138a,
+ 0x970f, 0x138f,
+ 0x9710, 0x2cf6,
+ 0x9711, 0x138b,
+ 0x9712, 0x2cf5,
+ 0x9713, 0x138e,
+ 0x9716, 0x138c,
+ 0x9718, 0x2eb3,
+ 0x9719, 0x2eb5,
+ 0x971b, 0x38c9,
+ 0x971c, 0x14b2,
+ 0x971d, 0x2eb4,
+ 0x971e, 0x14b3,
+ 0x971f, 0x2eb2,
+ 0x9720, 0x2eb1,
+ 0x9721, 0x3fb3,
+ 0x9722, 0x3028,
+ 0x9723, 0x3027,
+ 0x9724, 0x1553,
+ 0x9725, 0x3029,
+ 0x9726, 0x316a,
+ 0x9727, 0x15ef,
+ 0x9728, 0x3169,
+ 0x9729, 0x3166,
+ 0x972a, 0x15ee,
+ 0x972b, 0x3167,
+ 0x972e, 0x326f,
+ 0x9730, 0x1656,
+ 0x9731, 0x38c0,
+ 0x9732, 0x16a3,
+ 0x9735, 0x3331,
+ 0x9736, 0x38c2,
+ 0x9738, 0x16a1,
+ 0x973a, 0x3332,
+ 0x973d, 0x16e2,
+ 0x973f, 0x33d1,
+ 0x9740, 0x47b3,
+ 0x9741, 0x3be9,
+ 0x9742, 0x1732,
+ 0x9743, 0x34aa,
+ 0x9744, 0x1734,
+ 0x9746, 0x34a9,
+ 0x9747, 0x34ab,
+ 0x9748, 0x1733,
+ 0x9749, 0x34f1,
+ 0x974b, 0x3526,
+ 0x9751, 0x44e3,
+ 0x9752, 0x06a1,
+ 0x9756, 0x0f68,
+ 0x9757, 0x38cc,
+ 0x9758, 0x2855,
+ 0x975a, 0x2abc,
+ 0x975b, 0x1390,
+ 0x975d, 0x3bef,
+ 0x975e, 0x06a2,
+ 0x975f, 0x38cf,
+ 0x9760, 0x1266,
+ 0x9761, 0x15f0,
+ 0x9762, 0x0826,
+ 0x9766, 0x1392,
+ 0x9768, 0x1710,
+ 0x9769, 0x0827,
+ 0x976a, 0x20aa,
+ 0x976c, 0x2359,
+ 0x976d, 0x3e97,
+ 0x976e, 0x235b,
+ 0x9770, 0x235a,
+ 0x9771, 0x3bfc,
+ 0x9772, 0x2600,
+ 0x9773, 0x25fd,
+ 0x9774, 0x0f69,
+ 0x9776, 0x0f6a,
+ 0x9777, 0x25fe,
+ 0x977a, 0x2857,
+ 0x977b, 0x285c,
+ 0x977c, 0x10eb,
+ 0x977d, 0x2856,
+ 0x977e, 0x2858,
+ 0x977f, 0x285f,
+ 0x9780, 0x285a,
+ 0x9781, 0x285e,
+ 0x9782, 0x285b,
+ 0x9783, 0x2859,
+ 0x9784, 0x285d,
+ 0x9785, 0x10ec,
+ 0x9787, 0x40c0,
+ 0x9788, 0x2abf,
+ 0x9789, 0x38d4,
+ 0x978a, 0x2abd,
+ 0x978b, 0x1268,
+ 0x978d, 0x1267,
+ 0x978e, 0x2abe,
+ 0x978f, 0x1269,
+ 0x9794, 0x2cf9,
+ 0x9797, 0x2cf8,
+ 0x9798, 0x1393,
+ 0x9799, 0x2cf7,
+ 0x979a, 0x2eb6,
+ 0x979b, 0x3bfb,
+ 0x979c, 0x2eb8,
+ 0x979d, 0x2eba,
+ 0x979e, 0x2eb9,
+ 0x979f, 0x38d5,
+ 0x97a0, 0x14b4,
+ 0x97a1, 0x2eb7,
+ 0x97a2, 0x3030,
+ 0x97a3, 0x1554,
+ 0x97a4, 0x302e,
+ 0x97a5, 0x3031,
+ 0x97a6, 0x1555,
+ 0x97a8, 0x302c,
+ 0x97aa, 0x302f,
+ 0x97ab, 0x302d,
+ 0x97ac, 0x302a,
+ 0x97ad, 0x1556,
+ 0x97ae, 0x302b,
+ 0x97b1, 0x38d6,
+ 0x97b2, 0x47b5,
+ 0x97b3, 0x316b,
+ 0x97b4, 0x3f33,
+ 0x97b6, 0x316d,
+ 0x97b7, 0x316c,
+ 0x97b8, 0x3d95,
+ 0x97b9, 0x3271,
+ 0x97ba, 0x3f35,
+ 0x97bb, 0x3272,
+ 0x97bd, 0x494e,
+ 0x97be, 0x38d7,
+ 0x97bf, 0x3333,
+ 0x97c0, 0x38d8,
+ 0x97c1, 0x16e5,
+ 0x97c2, 0x47b6,
+ 0x97c3, 0x16e4,
+ 0x97c4, 0x344c,
+ 0x97c6, 0x1735,
+ 0x97c7, 0x34ac,
+ 0x97c8, 0x3f2f,
+ 0x97c9, 0x1756,
+ 0x97cb, 0x0828,
+ 0x97cc, 0x0daf,
+ 0x97cd, 0x2861,
+ 0x97ce, 0x2860,
+ 0x97cf, 0x2ac1,
+ 0x97d0, 0x2ac0,
+ 0x97d2, 0x38d9,
+ 0x97d3, 0x14b5,
+ 0x97d4, 0x2ebc,
+ 0x97d5, 0x2ebb,
+ 0x97d6, 0x3034,
+ 0x97d7, 0x3032,
+ 0x97d8, 0x3035,
+ 0x97d9, 0x3033,
+ 0x97dc, 0x15f1,
+ 0x97dd, 0x316e,
+ 0x97e0, 0x38da,
+ 0x97e1, 0x3334,
+ 0x97e3, 0x33d2,
+ 0x97e5, 0x34ad,
+ 0x97e6, 0x450c,
+ 0x97ed, 0x0829,
+ 0x97ee, 0x38dc,
+ 0x97f0, 0x2cfa,
+ 0x97f1, 0x2ebd,
+ 0x97f2, 0x394d,
+ 0x97f3, 0x082a,
+ 0x97f5, 0x38e0,
+ 0x97f6, 0x10ed,
+ 0x97f8, 0x2cfb,
+ 0x97f9, 0x1557,
+ 0x97fa, 0x3036,
+ 0x97fb, 0x15f2,
+ 0x97fd, 0x3273,
+ 0x97ff, 0x16a4,
+ 0x9800, 0x344e,
+ 0x9801, 0x082b,
+ 0x9802, 0x0bdf,
+ 0x9804, 0x20ab,
+ 0x9805, 0x0db0,
+ 0x9807, 0x235c,
+ 0x9808, 0x0db2,
+ 0x980a, 0x0f6e,
+ 0x980c, 0x0f70,
+ 0x980d, 0x2602,
+ 0x980f, 0x2601,
+ 0x9810, 0x0f6b,
+ 0x9812, 0x0f6f,
+ 0x9813, 0x0f6d,
+ 0x9814, 0x4952,
+ 0x9815, 0x433c,
+ 0x9816, 0x2862,
+ 0x9817, 0x10ee,
+ 0x981b, 0x2ac8,
+ 0x981c, 0x126c,
+ 0x981d, 0x2ac3,
+ 0x981e, 0x2ac2,
+ 0x981f, 0x3c02,
+ 0x9820, 0x2ac7,
+ 0x9821, 0x126a,
+ 0x9823, 0x3e37,
+ 0x9824, 0x139a,
+ 0x9826, 0x2ac4,
+ 0x9827, 0x2ac9,
+ 0x9828, 0x2ac6,
+ 0x9829, 0x2ac5,
+ 0x982b, 0x126b,
+ 0x982d, 0x1398,
+ 0x982e, 0x3f72,
+ 0x982f, 0x2cfd,
+ 0x9830, 0x1394,
+ 0x9832, 0x2cfe,
+ 0x9833, 0x38e5,
+ 0x9834, 0x38e4,
+ 0x9835, 0x2cfc,
+ 0x9837, 0x1397,
+ 0x9838, 0x1395,
+ 0x9839, 0x1399,
+ 0x983b, 0x1396,
+ 0x9841, 0x2ebe,
+ 0x9843, 0x2ec3,
+ 0x9844, 0x2ebf,
+ 0x9845, 0x2ec2,
+ 0x9846, 0x14b6,
+ 0x9847, 0x3d96,
+ 0x9848, 0x2df2,
+ 0x9849, 0x2ec1,
+ 0x984a, 0x2ec0,
+ 0x984b, 0x38e6,
+ 0x984c, 0x155a,
+ 0x984d, 0x1558,
+ 0x984e, 0x155b,
+ 0x984f, 0x1559,
+ 0x9850, 0x3037,
+ 0x9853, 0x155c,
+ 0x9857, 0x3174,
+ 0x9858, 0x15f4,
+ 0x9859, 0x3172,
+ 0x985b, 0x15f5,
+ 0x985c, 0x3171,
+ 0x985d, 0x3173,
+ 0x985e, 0x15f3,
+ 0x985f, 0x3278,
+ 0x9860, 0x3275,
+ 0x9862, 0x3276,
+ 0x9864, 0x3335,
+ 0x9865, 0x16a6,
+ 0x9866, 0x38e7,
+ 0x9867, 0x16a5,
+ 0x9869, 0x33d4,
+ 0x986a, 0x33d3,
+ 0x986b, 0x16e6,
+ 0x986c, 0x4035,
+ 0x986f, 0x1711,
+ 0x9870, 0x1736,
+ 0x9871, 0x174d,
+ 0x9872, 0x34f2,
+ 0x9873, 0x3527,
+ 0x9875, 0x450d,
+ 0x98a8, 0x082c,
+ 0x98a9, 0x235d,
+ 0x98ac, 0x2604,
+ 0x98ad, 0x2863,
+ 0x98af, 0x10f0,
+ 0x98b1, 0x10f1,
+ 0x98b2, 0x2aca,
+ 0x98b3, 0x126d,
+ 0x98b4, 0x3f73,
+ 0x98b6, 0x14b7,
+ 0x98b7, 0x38ef,
+ 0x98b8, 0x303a,
+ 0x98b9, 0x47b8,
+ 0x98ba, 0x155d,
+ 0x98bb, 0x3177,
+ 0x98bc, 0x15f6,
+ 0x98bd, 0x3176,
+ 0x98be, 0x3178,
+ 0x98bf, 0x3175,
+ 0x98c0, 0x3338,
+ 0x98c1, 0x3279,
+ 0x98c3, 0x3b78,
+ 0x98c4, 0x1657,
+ 0x98c6, 0x3337,
+ 0x98c7, 0x38f1,
+ 0x98c8, 0x38f0,
+ 0x98c9, 0x3336,
+ 0x98ca, 0x38ee,
+ 0x98cb, 0x33d5,
+ 0x98cc, 0x3529,
+ 0x98ce, 0x450e,
+ 0x98db, 0x082d,
+ 0x98dc, 0x3c0b,
+ 0x98de, 0x450f,
+ 0x98df, 0x082e,
+ 0x98e0, 0x4792,
+ 0x98e1, 0x38f6,
+ 0x98e2, 0x09f4,
+ 0x98e3, 0x1e32,
+ 0x98e5, 0x20ac,
+ 0x98e6, 0x38f7,
+ 0x98e7, 0x0db3,
+ 0x98e9, 0x0db6,
+ 0x98ea, 0x0db4,
+ 0x98eb, 0x235e,
+ 0x98ec, 0x38f8,
+ 0x98ed, 0x0db8,
+ 0x98ef, 0x0db5,
+ 0x98f1, 0x47ba,
+ 0x98f2, 0x0db7,
+ 0x98f4, 0x0f72,
+ 0x98f5, 0x4365,
+ 0x98f6, 0x2605,
+ 0x98f9, 0x2606,
+ 0x98fa, 0x2acc,
+ 0x98fc, 0x0f71,
+ 0x98fd, 0x0f73,
+ 0x9900, 0x2866,
+ 0x9902, 0x2865,
+ 0x9903, 0x10f2,
+ 0x9905, 0x10f3,
+ 0x9907, 0x2867,
+ 0x9908, 0x2acb,
+ 0x9909, 0x10f5,
+ 0x990a, 0x126e,
+ 0x990c, 0x10f4,
+ 0x990e, 0x43ed,
+ 0x9910, 0x139b,
+ 0x9911, 0x2acd,
+ 0x9912, 0x1270,
+ 0x9913, 0x126f,
+ 0x9914, 0x2ace,
+ 0x9915, 0x2ad1,
+ 0x9916, 0x2acf,
+ 0x9918, 0x1271,
+ 0x9919, 0x47bc,
+ 0x991a, 0x13a0,
+ 0x991b, 0x139e,
+ 0x991c, 0x43ee,
+ 0x991e, 0x139d,
+ 0x991f, 0x2d00,
+ 0x9921, 0x139f,
+ 0x9924, 0x2cff,
+ 0x9925, 0x2ec4,
+ 0x9927, 0x2d01,
+ 0x9928, 0x139c,
+ 0x9929, 0x2d02,
+ 0x992a, 0x2ec7,
+ 0x992b, 0x2ec5,
+ 0x992d, 0x2ecb,
+ 0x992e, 0x1561,
+ 0x992f, 0x2eca,
+ 0x9930, 0x2ecd,
+ 0x9931, 0x2ecc,
+ 0x9932, 0x2ec9,
+ 0x9933, 0x2ec8,
+ 0x9935, 0x14b8,
+ 0x9937, 0x47bd,
+ 0x9938, 0x3bfd,
+ 0x9939, 0x38fa,
+ 0x993a, 0x303d,
+ 0x993b, 0x3c11,
+ 0x993c, 0x303c,
+ 0x993d, 0x1560,
+ 0x993e, 0x155e,
+ 0x9940, 0x3f34,
+ 0x9941, 0x303b,
+ 0x9942, 0x43ff,
+ 0x9943, 0x317b,
+ 0x9945, 0x15f7,
+ 0x9947, 0x317a,
+ 0x9948, 0x3179,
+ 0x9949, 0x15f8,
+ 0x994a, 0x3fb9,
+ 0x994b, 0x327f,
+ 0x994c, 0x327e,
+ 0x994d, 0x3c12,
+ 0x994e, 0x327c,
+ 0x9950, 0x327b,
+ 0x9951, 0x1659,
+ 0x9952, 0x1658,
+ 0x9953, 0x3280,
+ 0x9954, 0x33d6,
+ 0x9955, 0x16e7,
+ 0x9956, 0x333a,
+ 0x9957, 0x16a7,
+ 0x9958, 0x3339,
+ 0x9959, 0x327d,
+ 0x995b, 0x33d7,
+ 0x995c, 0x1712,
+ 0x995d, 0x47be,
+ 0x995e, 0x174e,
+ 0x995f, 0x34f3,
+ 0x9961, 0x352a,
+ 0x9962, 0x43ef,
+ 0x9963, 0x4510,
+ 0x9996, 0x082f,
+ 0x9997, 0x20ad,
+ 0x9998, 0x2ece,
+ 0x9999, 0x0830,
+ 0x999b, 0x3c15,
+ 0x999c, 0x2869,
+ 0x999d, 0x2868,
+ 0x999e, 0x2d03,
+ 0x99a1, 0x2ed0,
+ 0x99a3, 0x2ecf,
+ 0x99a4, 0x41c3,
+ 0x99a5, 0x1562,
+ 0x99a6, 0x317c,
+ 0x99a8, 0x165a,
+ 0x99aa, 0x3c17,
+ 0x99ab, 0x352b,
+ 0x99ac, 0x09f5,
+ 0x99ad, 0x0dba,
+ 0x99ae, 0x0db9,
+ 0x99af, 0x2607,
+ 0x99b0, 0x2609,
+ 0x99b1, 0x0f76,
+ 0x99b2, 0x2608,
+ 0x99b3, 0x0f75,
+ 0x99b4, 0x0f77,
+ 0x99b5, 0x260a,
+ 0x99b8, 0x394b,
+ 0x99b9, 0x286b,
+ 0x99ba, 0x286d,
+ 0x99bb, 0x286c,
+ 0x99bc, 0x3c22,
+ 0x99bd, 0x286f,
+ 0x99c1, 0x10f6,
+ 0x99c2, 0x286e,
+ 0x99c3, 0x286a,
+ 0x99c4, 0x3d77,
+ 0x99c5, 0x47c1,
+ 0x99c7, 0x2870,
+ 0x99c9, 0x2ad8,
+ 0x99cb, 0x2adb,
+ 0x99cc, 0x2add,
+ 0x99cd, 0x2ad3,
+ 0x99ce, 0x2ad7,
+ 0x99cf, 0x2ad4,
+ 0x99d0, 0x1273,
+ 0x99d1, 0x1276,
+ 0x99d2, 0x1278,
+ 0x99d3, 0x2ad5,
+ 0x99d5, 0x1277,
+ 0x99d6, 0x2ad9,
+ 0x99d7, 0x2adc,
+ 0x99d8, 0x2ada,
+ 0x99d9, 0x1279,
+ 0x99da, 0x3f42,
+ 0x99db, 0x1275,
+ 0x99dc, 0x2ad2,
+ 0x99dd, 0x1272,
+ 0x99df, 0x1274,
+ 0x99e1, 0x3785,
+ 0x99e2, 0x13a2,
+ 0x99e3, 0x2d09,
+ 0x99e4, 0x2d07,
+ 0x99e5, 0x2d06,
+ 0x99e6, 0x3b65,
+ 0x99e7, 0x2d0c,
+ 0x99e9, 0x2d0b,
+ 0x99ea, 0x2d0a,
+ 0x99ec, 0x2d05,
+ 0x99ed, 0x13a1,
+ 0x99ee, 0x2d04,
+ 0x99f0, 0x2d08,
+ 0x99f1, 0x13a3,
+ 0x99f4, 0x2ed3,
+ 0x99f5, 0x38ff,
+ 0x99f6, 0x2ed7,
+ 0x99f7, 0x2ed4,
+ 0x99f8, 0x2ed6,
+ 0x99f9, 0x2ed5,
+ 0x99fa, 0x2ed2,
+ 0x99fb, 0x2ed8,
+ 0x99fc, 0x2edb,
+ 0x99fd, 0x2ed9,
+ 0x99ff, 0x14ba,
+ 0x9a01, 0x14b9,
+ 0x9a02, 0x2ed1,
+ 0x9a03, 0x2edc,
+ 0x9a04, 0x3042,
+ 0x9a05, 0x3045,
+ 0x9a06, 0x3047,
+ 0x9a07, 0x3046,
+ 0x9a09, 0x3040,
+ 0x9a0a, 0x3044,
+ 0x9a0b, 0x303f,
+ 0x9a0c, 0x3900,
+ 0x9a0d, 0x3041,
+ 0x9a0e, 0x1563,
+ 0x9a0f, 0x303e,
+ 0x9a10, 0x3902,
+ 0x9a11, 0x3043,
+ 0x9a14, 0x318a,
+ 0x9a15, 0x317f,
+ 0x9a16, 0x15f9,
+ 0x9a19, 0x15fa,
+ 0x9a1a, 0x317e,
+ 0x9a1b, 0x3183,
+ 0x9a1c, 0x3189,
+ 0x9a1d, 0x3181,
+ 0x9a1e, 0x3188,
+ 0x9a1f, 0x3b6c,
+ 0x9a20, 0x3185,
+ 0x9a21, 0x3c1c,
+ 0x9a22, 0x3184,
+ 0x9a23, 0x3187,
+ 0x9a24, 0x3182,
+ 0x9a25, 0x3180,
+ 0x9a26, 0x3df2,
+ 0x9a27, 0x3186,
+ 0x9a29, 0x3287,
+ 0x9a2a, 0x3285,
+ 0x9a2b, 0x165b,
+ 0x9a2c, 0x3284,
+ 0x9a2d, 0x328a,
+ 0x9a2e, 0x3288,
+ 0x9a2f, 0x3c1e,
+ 0x9a30, 0x165c,
+ 0x9a31, 0x3283,
+ 0x9a32, 0x3281,
+ 0x9a34, 0x3282,
+ 0x9a35, 0x165e,
+ 0x9a36, 0x3286,
+ 0x9a37, 0x165d,
+ 0x9a38, 0x3289,
+ 0x9a39, 0x333b,
+ 0x9a3a, 0x3341,
+ 0x9a3b, 0x3901,
+ 0x9a3c, 0x47c3,
+ 0x9a3d, 0x333c,
+ 0x9a3e, 0x16ab,
+ 0x9a3f, 0x3342,
+ 0x9a40, 0x16aa,
+ 0x9a41, 0x3340,
+ 0x9a42, 0x333f,
+ 0x9a43, 0x16a9,
+ 0x9a44, 0x333e,
+ 0x9a45, 0x16a8,
+ 0x9a46, 0x333d,
+ 0x9a48, 0x33dd,
+ 0x9a49, 0x33df,
+ 0x9a4a, 0x33de,
+ 0x9a4c, 0x33db,
+ 0x9a4d, 0x16e9,
+ 0x9a4e, 0x33d8,
+ 0x9a4f, 0x33dc,
+ 0x9a50, 0x33e1,
+ 0x9a52, 0x33e0,
+ 0x9a53, 0x33d9,
+ 0x9a55, 0x16e8,
+ 0x9a56, 0x344f,
+ 0x9a57, 0x1715,
+ 0x9a58, 0x3903,
+ 0x9a59, 0x3450,
+ 0x9a5a, 0x1713,
+ 0x9a5c, 0x3c18,
+ 0x9a5e, 0x34ae,
+ 0x9a5f, 0x1737,
+ 0x9a60, 0x3510,
+ 0x9a62, 0x1757,
+ 0x9a63, 0x3b67,
+ 0x9a64, 0x352c,
+ 0x9a65, 0x1758,
+ 0x9a66, 0x352d,
+ 0x9a68, 0x353c,
+ 0x9a69, 0x353b,
+ 0x9a6a, 0x1767,
+ 0x9a6b, 0x3544,
+ 0x9a6c, 0x4585,
+ 0x9a8f, 0x4586,
+ 0x9aa8, 0x09f6,
+ 0x9aab, 0x260c,
+ 0x9aad, 0x260b,
+ 0x9aaf, 0x10f7,
+ 0x9ab1, 0x2871,
+ 0x9ab2, 0x4332,
+ 0x9ab3, 0x2ade,
+ 0x9ab4, 0x2d0f,
+ 0x9ab6, 0x43f0,
+ 0x9ab7, 0x127a,
+ 0x9ab8, 0x13a4,
+ 0x9ab9, 0x2d0d,
+ 0x9aba, 0x3f74,
+ 0x9abb, 0x2d10,
+ 0x9abc, 0x13a5,
+ 0x9abd, 0x3d97,
+ 0x9abe, 0x2edd,
+ 0x9abf, 0x2d0e,
+ 0x9ac0, 0x3048,
+ 0x9ac1, 0x1564,
+ 0x9ac2, 0x318b,
+ 0x9ac6, 0x328d,
+ 0x9ac7, 0x328b,
+ 0x9aca, 0x328c,
+ 0x9acd, 0x3343,
+ 0x9acf, 0x16ac,
+ 0x9ad0, 0x33e2,
+ 0x9ad1, 0x1718,
+ 0x9ad2, 0x16ea,
+ 0x9ad3, 0x1716,
+ 0x9ad5, 0x34af,
+ 0x9ad6, 0x174f,
+ 0x9ad7, 0x3faa,
+ 0x9ad8, 0x09f7,
+ 0x9adc, 0x3049,
+ 0x9adf, 0x1e33,
+ 0x9ae0, 0x3908,
+ 0x9ae1, 0x0f78,
+ 0x9ae2, 0x3909,
+ 0x9ae3, 0x2872,
+ 0x9ae6, 0x10f9,
+ 0x9ae7, 0x2873,
+ 0x9aeb, 0x2ae0,
+ 0x9aec, 0x2adf,
+ 0x9aed, 0x13a7,
+ 0x9aee, 0x127b,
+ 0x9af1, 0x2ae3,
+ 0x9af2, 0x2ae2,
+ 0x9af3, 0x2ae1,
+ 0x9af4, 0x390b,
+ 0x9af6, 0x2d11,
+ 0x9af7, 0x2d14,
+ 0x9af9, 0x2d13,
+ 0x9afa, 0x2d12,
+ 0x9afb, 0x13a6,
+ 0x9afc, 0x2ee1,
+ 0x9afd, 0x2edf,
+ 0x9afe, 0x2ede,
+ 0x9aff, 0x3f17,
+ 0x9b01, 0x2ee0,
+ 0x9b02, 0x3f12,
+ 0x9b03, 0x1565,
+ 0x9b04, 0x304b,
+ 0x9b06, 0x1566,
+ 0x9b08, 0x304a,
+ 0x9b09, 0x3f20,
+ 0x9b0a, 0x318d,
+ 0x9b0b, 0x318c,
+ 0x9b0c, 0x318f,
+ 0x9b0d, 0x15fb,
+ 0x9b0e, 0x318e,
+ 0x9b0f, 0x47c4,
+ 0x9b10, 0x328e,
+ 0x9b11, 0x3290,
+ 0x9b12, 0x328f,
+ 0x9b14, 0x390d,
+ 0x9b15, 0x3344,
+ 0x9b16, 0x3347,
+ 0x9b17, 0x3345,
+ 0x9b19, 0x33e3,
+ 0x9b1a, 0x16eb,
+ 0x9b1e, 0x3451,
+ 0x9b22, 0x1738,
+ 0x9b23, 0x1750,
+ 0x9b24, 0x352f,
+ 0x9b25, 0x09f8,
+ 0x9b27, 0x127d,
+ 0x9b28, 0x13a8,
+ 0x9b29, 0x304d,
+ 0x9b2a, 0x3f19,
+ 0x9b2b, 0x33e4,
+ 0x9b2d, 0x390e,
+ 0x9b2e, 0x3511,
+ 0x9b2f, 0x1e34,
+ 0x9b31, 0x1768,
+ 0x9b32, 0x09f9,
+ 0x9b33, 0x2d15,
+ 0x9b34, 0x3911,
+ 0x9b35, 0x304e,
+ 0x9b37, 0x3190,
+ 0x9b39, 0x3f00,
+ 0x9b3a, 0x3348,
+ 0x9b3b, 0x33e5,
+ 0x9b3c, 0x09fa,
+ 0x9b3e, 0x2874,
+ 0x9b40, 0x3915,
+ 0x9b41, 0x10fa,
+ 0x9b43, 0x2ae5,
+ 0x9b44, 0x127f,
+ 0x9b45, 0x127e,
+ 0x9b46, 0x2ae4,
+ 0x9b48, 0x2ee2,
+ 0x9b4a, 0x304f,
+ 0x9b4b, 0x3051,
+ 0x9b4c, 0x3050,
+ 0x9b4d, 0x1569,
+ 0x9b4e, 0x1568,
+ 0x9b4f, 0x1567,
+ 0x9b50, 0x3914,
+ 0x9b51, 0x16ae,
+ 0x9b52, 0x3349,
+ 0x9b54, 0x16ad,
+ 0x9b55, 0x33e7,
+ 0x9b56, 0x33e6,
+ 0x9b58, 0x1739,
+ 0x9b59, 0x34b0,
+ 0x9b5a, 0x0be1,
+ 0x9b5b, 0x260d,
+ 0x9b5f, 0x2878,
+ 0x9b60, 0x2876,
+ 0x9b64, 0x2aee,
+ 0x9b66, 0x2ae9,
+ 0x9b67, 0x2ae6,
+ 0x9b68, 0x2aed,
+ 0x9b69, 0x47c5,
+ 0x9b6c, 0x2aef,
+ 0x9b6f, 0x1281,
+ 0x9b70, 0x2aec,
+ 0x9b71, 0x2ae8,
+ 0x9b74, 0x2ae7,
+ 0x9b75, 0x2aeb,
+ 0x9b76, 0x2aea,
+ 0x9b77, 0x1280,
+ 0x9b7a, 0x2d20,
+ 0x9b7b, 0x2d1b,
+ 0x9b7c, 0x2d19,
+ 0x9b7d, 0x2d22,
+ 0x9b7e, 0x2d1a,
+ 0x9b7f, 0x3c3b,
+ 0x9b80, 0x2d16,
+ 0x9b81, 0x43f1,
+ 0x9b82, 0x2d1c,
+ 0x9b83, 0x4219,
+ 0x9b85, 0x2d17,
+ 0x9b86, 0x2eeb,
+ 0x9b87, 0x2d18,
+ 0x9b88, 0x2d23,
+ 0x9b8b, 0x3eee,
+ 0x9b8d, 0x4623,
+ 0x9b8e, 0x3919,
+ 0x9b8f, 0x3fad,
+ 0x9b90, 0x2d1f,
+ 0x9b91, 0x13a9,
+ 0x9b92, 0x2d1e,
+ 0x9b93, 0x2d1d,
+ 0x9b95, 0x2d21,
+ 0x9b97, 0x3f71,
+ 0x9b9a, 0x2ee3,
+ 0x9b9b, 0x2ee6,
+ 0x9b9d, 0x3f56,
+ 0x9b9e, 0x2ee5,
+ 0x9b9f, 0x3c3e,
+ 0x9ba0, 0x2eed,
+ 0x9ba1, 0x2ee8,
+ 0x9ba2, 0x2eec,
+ 0x9ba4, 0x2eea,
+ 0x9ba5, 0x2ee9,
+ 0x9ba6, 0x2ee7,
+ 0x9ba8, 0x2ee4,
+ 0x9baa, 0x14bd,
+ 0x9bab, 0x14bc,
+ 0x9bad, 0x14be,
+ 0x9bae, 0x14bb,
+ 0x9baf, 0x2eee,
+ 0x9bb0, 0x3fb4,
+ 0x9bb5, 0x3057,
+ 0x9bb6, 0x305a,
+ 0x9bb8, 0x3058,
+ 0x9bb9, 0x305c,
+ 0x9bbd, 0x305d,
+ 0x9bbf, 0x3055,
+ 0x9bc0, 0x156e,
+ 0x9bc1, 0x3056,
+ 0x9bc3, 0x3054,
+ 0x9bc4, 0x305b,
+ 0x9bc6, 0x3053,
+ 0x9bc7, 0x3052,
+ 0x9bc8, 0x156d,
+ 0x9bc9, 0x156b,
+ 0x9bca, 0x156a,
+ 0x9bcf, 0x3c3c,
+ 0x9bd3, 0x3059,
+ 0x9bd4, 0x3199,
+ 0x9bd5, 0x319f,
+ 0x9bd6, 0x15fe,
+ 0x9bd7, 0x319a,
+ 0x9bd9, 0x319d,
+ 0x9bda, 0x31a1,
+ 0x9bdb, 0x15ff,
+ 0x9bdc, 0x319c,
+ 0x9bdd, 0x47c6,
+ 0x9bde, 0x3194,
+ 0x9be0, 0x3193,
+ 0x9be1, 0x31a0,
+ 0x9be2, 0x3197,
+ 0x9be4, 0x3195,
+ 0x9be5, 0x319e,
+ 0x9be6, 0x3196,
+ 0x9be7, 0x15fd,
+ 0x9be8, 0x15fc,
+ 0x9be9, 0x3bc1,
+ 0x9bea, 0x3191,
+ 0x9bec, 0x319b,
+ 0x9bed, 0x3ed7,
+ 0x9bf0, 0x3198,
+ 0x9bf1, 0x47c7,
+ 0x9bf4, 0x47c8,
+ 0x9bf7, 0x3293,
+ 0x9bf8, 0x3296,
+ 0x9bfd, 0x156c,
+ 0x9bff, 0x391b,
+ 0x9c02, 0x391a,
+ 0x9c05, 0x3294,
+ 0x9c06, 0x329a,
+ 0x9c07, 0x3298,
+ 0x9c08, 0x3292,
+ 0x9c09, 0x329d,
+ 0x9c0a, 0x3f3a,
+ 0x9c0b, 0x3291,
+ 0x9c0c, 0x391c,
+ 0x9c0d, 0x1660,
+ 0x9c0e, 0x3299,
+ 0x9c10, 0x3c3a,
+ 0x9c12, 0x3295,
+ 0x9c13, 0x165f,
+ 0x9c14, 0x329c,
+ 0x9c15, 0x3f1e,
+ 0x9c17, 0x329b,
+ 0x9c1b, 0x491b,
+ 0x9c1c, 0x334c,
+ 0x9c1d, 0x334b,
+ 0x9c1f, 0x4622,
+ 0x9c20, 0x47ca,
+ 0x9c21, 0x3352,
+ 0x9c23, 0x334e,
+ 0x9c24, 0x3351,
+ 0x9c25, 0x16b0,
+ 0x9c26, 0x45e6,
+ 0x9c28, 0x334f,
+ 0x9c2b, 0x334a,
+ 0x9c2c, 0x334d,
+ 0x9c2d, 0x16af,
+ 0x9c2e, 0x3f22,
+ 0x9c2f, 0x3d87,
+ 0x9c31, 0x16ed,
+ 0x9c32, 0x33f2,
+ 0x9c33, 0x33ed,
+ 0x9c34, 0x33f1,
+ 0x9c35, 0x3c39,
+ 0x9c36, 0x33f4,
+ 0x9c37, 0x33f0,
+ 0x9c39, 0x33ec,
+ 0x9c3a, 0x3d7e,
+ 0x9c3b, 0x16ef,
+ 0x9c3c, 0x33ef,
+ 0x9c3d, 0x33f3,
+ 0x9c3e, 0x16ee,
+ 0x9c3f, 0x33ea,
+ 0x9c40, 0x3297,
+ 0x9c41, 0x33ee,
+ 0x9c44, 0x33eb,
+ 0x9c45, 0x3e71,
+ 0x9c46, 0x33e8,
+ 0x9c48, 0x33e9,
+ 0x9c49, 0x16ec,
+ 0x9c4a, 0x3457,
+ 0x9c4b, 0x3459,
+ 0x9c4c, 0x345c,
+ 0x9c4d, 0x3458,
+ 0x9c4e, 0x345d,
+ 0x9c4f, 0x3c36,
+ 0x9c50, 0x3456,
+ 0x9c52, 0x3454,
+ 0x9c53, 0x3c37,
+ 0x9c54, 0x1719,
+ 0x9c55, 0x345a,
+ 0x9c56, 0x171b,
+ 0x9c57, 0x171a,
+ 0x9c58, 0x3455,
+ 0x9c59, 0x345b,
+ 0x9c5d, 0x3ebf,
+ 0x9c5e, 0x34b5,
+ 0x9c5f, 0x173a,
+ 0x9c60, 0x34b6,
+ 0x9c62, 0x34b4,
+ 0x9c63, 0x34b1,
+ 0x9c66, 0x34b3,
+ 0x9c67, 0x34b2,
+ 0x9c68, 0x34f4,
+ 0x9c6d, 0x34f6,
+ 0x9c6e, 0x34f5,
+ 0x9c71, 0x3514,
+ 0x9c72, 0x3ea1,
+ 0x9c73, 0x3513,
+ 0x9c74, 0x3512,
+ 0x9c75, 0x3515,
+ 0x9c77, 0x1760,
+ 0x9c79, 0x3541,
+ 0x9c7a, 0x3545,
+ 0x9c7b, 0x3c38,
+ 0x9c7c, 0x4512,
+ 0x9ce5, 0x0be2,
+ 0x9ce6, 0x235f,
+ 0x9ce7, 0x2610,
+ 0x9ce9, 0x0f79,
+ 0x9cea, 0x260e,
+ 0x9ced, 0x260f,
+ 0x9cf1, 0x2879,
+ 0x9cf3, 0x10fe,
+ 0x9cf4, 0x10fc,
+ 0x9cf5, 0x287b,
+ 0x9cf6, 0x10fd,
+ 0x9cf7, 0x2af4,
+ 0x9cf9, 0x2af7,
+ 0x9cfa, 0x2af1,
+ 0x9cfb, 0x2af8,
+ 0x9cfc, 0x2af0,
+ 0x9cfd, 0x2af2,
+ 0x9cff, 0x2af3,
+ 0x9d00, 0x2af6,
+ 0x9d02, 0x3f3b,
+ 0x9d03, 0x1284,
+ 0x9d04, 0x2afb,
+ 0x9d05, 0x2afa,
+ 0x9d06, 0x1282,
+ 0x9d07, 0x2af5,
+ 0x9d08, 0x2af9,
+ 0x9d09, 0x1283,
+ 0x9d0c, 0x3c46,
+ 0x9d10, 0x2d2d,
+ 0x9d12, 0x13ae,
+ 0x9d14, 0x2d28,
+ 0x9d15, 0x13aa,
+ 0x9d16, 0x3c7c,
+ 0x9d17, 0x2d25,
+ 0x9d18, 0x2d2b,
+ 0x9d19, 0x2d2e,
+ 0x9d1b, 0x13af,
+ 0x9d1d, 0x2d2a,
+ 0x9d1e, 0x2d27,
+ 0x9d1f, 0x2d2f,
+ 0x9d20, 0x2d26,
+ 0x9d21, 0x3c41,
+ 0x9d22, 0x2d2c,
+ 0x9d23, 0x13ab,
+ 0x9d25, 0x2d24,
+ 0x9d26, 0x13ac,
+ 0x9d28, 0x13ad,
+ 0x9d29, 0x2d29,
+ 0x9d2d, 0x2f00,
+ 0x9d2e, 0x2ef3,
+ 0x9d30, 0x2ef7,
+ 0x9d31, 0x2ef5,
+ 0x9d33, 0x2eef,
+ 0x9d34, 0x404a,
+ 0x9d36, 0x2ef2,
+ 0x9d37, 0x2efc,
+ 0x9d38, 0x2ef6,
+ 0x9d39, 0x392e,
+ 0x9d3b, 0x14bf,
+ 0x9d3d, 0x2efe,
+ 0x9d3e, 0x2efb,
+ 0x9d3f, 0x14c0,
+ 0x9d40, 0x2efd,
+ 0x9d41, 0x2ef0,
+ 0x9d42, 0x2ef9,
+ 0x9d44, 0x3fab,
+ 0x9d45, 0x2ef8,
+ 0x9d49, 0x47cd,
+ 0x9d4a, 0x3061,
+ 0x9d4b, 0x3063,
+ 0x9d4c, 0x3066,
+ 0x9d4e, 0x4539,
+ 0x9d4f, 0x3060,
+ 0x9d50, 0x3eca,
+ 0x9d51, 0x156f,
+ 0x9d52, 0x3068,
+ 0x9d53, 0x305f,
+ 0x9d54, 0x3069,
+ 0x9d56, 0x3065,
+ 0x9d57, 0x3067,
+ 0x9d58, 0x306b,
+ 0x9d59, 0x3064,
+ 0x9d5a, 0x306c,
+ 0x9d5b, 0x3062,
+ 0x9d5c, 0x305e,
+ 0x9d5d, 0x1570,
+ 0x9d5e, 0x3e6e,
+ 0x9d5f, 0x306a,
+ 0x9d60, 0x1571,
+ 0x9d61, 0x1601,
+ 0x9d67, 0x2ef1,
+ 0x9d68, 0x31bb,
+ 0x9d69, 0x31b2,
+ 0x9d6a, 0x1603,
+ 0x9d6b, 0x31ae,
+ 0x9d6c, 0x1604,
+ 0x9d6d, 0x3bac,
+ 0x9d6e, 0x433b,
+ 0x9d6f, 0x31b7,
+ 0x9d70, 0x31b1,
+ 0x9d71, 0x31a7,
+ 0x9d72, 0x1602,
+ 0x9d73, 0x31b4,
+ 0x9d74, 0x31af,
+ 0x9d77, 0x31a2,
+ 0x9d78, 0x31a9,
+ 0x9d79, 0x31b8,
+ 0x9d7b, 0x31b5,
+ 0x9d7c, 0x3efe,
+ 0x9d7d, 0x31ad,
+ 0x9d7e, 0x3925,
+ 0x9d7f, 0x31b9,
+ 0x9d80, 0x31a8,
+ 0x9d81, 0x31a3,
+ 0x9d82, 0x31b6,
+ 0x9d83, 0x3926,
+ 0x9d84, 0x31a5,
+ 0x9d85, 0x31b3,
+ 0x9d86, 0x31aa,
+ 0x9d87, 0x31ba,
+ 0x9d88, 0x31a6,
+ 0x9d89, 0x1600,
+ 0x9d8a, 0x31a4,
+ 0x9d8b, 0x31ab,
+ 0x9d90, 0x32a4,
+ 0x9d92, 0x32a2,
+ 0x9d93, 0x43f3,
+ 0x9d94, 0x32a7,
+ 0x9d96, 0x32b3,
+ 0x9d97, 0x32aa,
+ 0x9d98, 0x32a3,
+ 0x9d99, 0x329f,
+ 0x9d9a, 0x32ac,
+ 0x9d9b, 0x32a5,
+ 0x9d9c, 0x32a8,
+ 0x9d9d, 0x32a1,
+ 0x9d9e, 0x32af,
+ 0x9d9f, 0x329e,
+ 0x9da0, 0x32a6,
+ 0x9da1, 0x32ab,
+ 0x9da2, 0x32ad,
+ 0x9da3, 0x32b0,
+ 0x9da4, 0x32a0,
+ 0x9da5, 0x3c4b,
+ 0x9da6, 0x32b4,
+ 0x9da8, 0x32ae,
+ 0x9da9, 0x32b2,
+ 0x9daa, 0x32a9,
+ 0x9dab, 0x3f30,
+ 0x9dac, 0x3362,
+ 0x9dad, 0x3365,
+ 0x9daf, 0x16b1,
+ 0x9db1, 0x3364,
+ 0x9db2, 0x3369,
+ 0x9db3, 0x3367,
+ 0x9db4, 0x16b2,
+ 0x9db5, 0x335e,
+ 0x9db6, 0x3354,
+ 0x9db7, 0x3353,
+ 0x9db8, 0x16b4,
+ 0x9db9, 0x3360,
+ 0x9dbb, 0x335d,
+ 0x9dbc, 0x3355,
+ 0x9dbd, 0x47d0,
+ 0x9dbe, 0x335a,
+ 0x9dbf, 0x32b1,
+ 0x9dc0, 0x43f2,
+ 0x9dc1, 0x3356,
+ 0x9dc2, 0x16b3,
+ 0x9dc3, 0x335c,
+ 0x9dc4, 0x3929,
+ 0x9dc5, 0x335b,
+ 0x9dc7, 0x3357,
+ 0x9dc8, 0x3363,
+ 0x9dc9, 0x4579,
+ 0x9dca, 0x3358,
+ 0x9dcb, 0x33f9,
+ 0x9dcc, 0x3366,
+ 0x9dcd, 0x3368,
+ 0x9dce, 0x335f,
+ 0x9dcf, 0x3359,
+ 0x9dd0, 0x33fa,
+ 0x9dd1, 0x33fc,
+ 0x9dd2, 0x33f6,
+ 0x9dd3, 0x16f0,
+ 0x9dd4, 0x391e,
+ 0x9dd5, 0x3403,
+ 0x9dd6, 0x3401,
+ 0x9dd7, 0x16f1,
+ 0x9dd8, 0x3400,
+ 0x9dd9, 0x33ff,
+ 0x9dda, 0x33f8,
+ 0x9ddb, 0x33f5,
+ 0x9ddc, 0x33fb,
+ 0x9ddd, 0x3404,
+ 0x9dde, 0x33f7,
+ 0x9ddf, 0x33fd,
+ 0x9de1, 0x3466,
+ 0x9de2, 0x346b,
+ 0x9de3, 0x3461,
+ 0x9de4, 0x3464,
+ 0x9de5, 0x171c,
+ 0x9de6, 0x3468,
+ 0x9de8, 0x346f,
+ 0x9de9, 0x33fe,
+ 0x9deb, 0x3462,
+ 0x9dec, 0x346c,
+ 0x9ded, 0x3470,
+ 0x9dee, 0x3467,
+ 0x9def, 0x3460,
+ 0x9df0, 0x346a,
+ 0x9df2, 0x3469,
+ 0x9df3, 0x346e,
+ 0x9df4, 0x346d,
+ 0x9df5, 0x3402,
+ 0x9df6, 0x3465,
+ 0x9df7, 0x345f,
+ 0x9df8, 0x3463,
+ 0x9df9, 0x173b,
+ 0x9dfb, 0x345e,
+ 0x9dfc, 0x47d1,
+ 0x9dfd, 0x34c1,
+ 0x9dfe, 0x34b8,
+ 0x9dff, 0x34c0,
+ 0x9e00, 0x34bd,
+ 0x9e02, 0x34b7,
+ 0x9e03, 0x34ba,
+ 0x9e04, 0x34c2,
+ 0x9e05, 0x34bc,
+ 0x9e06, 0x34bb,
+ 0x9e07, 0x34b9,
+ 0x9e09, 0x34bf,
+ 0x9e0a, 0x457e,
+ 0x9e0b, 0x34f7,
+ 0x9e0c, 0x457a,
+ 0x9e0d, 0x34f8,
+ 0x9e0e, 0x3928,
+ 0x9e0f, 0x34fa,
+ 0x9e10, 0x34f9,
+ 0x9e11, 0x34fc,
+ 0x9e12, 0x34fb,
+ 0x9e13, 0x3517,
+ 0x9e14, 0x3516,
+ 0x9e15, 0x3530,
+ 0x9e17, 0x3531,
+ 0x9e18, 0x3c44,
+ 0x9e19, 0x353d,
+ 0x9e1a, 0x1765,
+ 0x9e1b, 0x1769,
+ 0x9e1c, 0x3f84,
+ 0x9e1d, 0x3546,
+ 0x9e1e, 0x176a,
+ 0x9e1f, 0x4513,
+ 0x9e75, 0x0be3,
+ 0x9e79, 0x1661,
+ 0x9e7a, 0x336a,
+ 0x9e7b, 0x43f8,
+ 0x9e7c, 0x173d,
+ 0x9e7f, 0x0be4,
+ 0x9e80, 0x2611,
+ 0x9e81, 0x3f0f,
+ 0x9e82, 0x0f7a,
+ 0x9e83, 0x2afc,
+ 0x9e84, 0x3f76,
+ 0x9e85, 0x3ef2,
+ 0x9e86, 0x2d31,
+ 0x9e88, 0x2d30,
+ 0x9e89, 0x2f02,
+ 0x9e8a, 0x2f01,
+ 0x9e8b, 0x14c1,
+ 0x9e8c, 0x306e,
+ 0x9e8d, 0x2f03,
+ 0x9e8e, 0x306d,
+ 0x9e90, 0x3931,
+ 0x9e91, 0x31bd,
+ 0x9e92, 0x1605,
+ 0x9e93, 0x1607,
+ 0x9e94, 0x31bc,
+ 0x9e95, 0x3932,
+ 0x9e96, 0x3fbc,
+ 0x9e97, 0x1606,
+ 0x9e98, 0x3f27,
+ 0x9e99, 0x32b6,
+ 0x9e9a, 0x32b8,
+ 0x9e9b, 0x32b7,
+ 0x9e9c, 0x336b,
+ 0x9e9d, 0x16b5,
+ 0x9e9e, 0x3933,
+ 0x9e9f, 0x171d,
+ 0x9ea0, 0x34c3,
+ 0x9ea1, 0x34fd,
+ 0x9ea2, 0x3934,
+ 0x9ea4, 0x354a,
+ 0x9ea5, 0x0be5,
+ 0x9ea6, 0x4944,
+ 0x9ea7, 0x287c,
+ 0x9ea8, 0x3f75,
+ 0x9ea9, 0x1285,
+ 0x9eaa, 0x3936,
+ 0x9eab, 0x3e92,
+ 0x9eac, 0x43f4,
+ 0x9ead, 0x2d34,
+ 0x9eae, 0x2d33,
+ 0x9eaf, 0x3937,
+ 0x9eb0, 0x2f04,
+ 0x9eb1, 0x47d4,
+ 0x9eb4, 0x1608,
+ 0x9eb5, 0x1662,
+ 0x9eb6, 0x3405,
+ 0x9eb7, 0x3542,
+ 0x9ebb, 0x0be6,
+ 0x9ebc, 0x10ff,
+ 0x9ebd, 0x47d5,
+ 0x9ebe, 0x1286,
+ 0x9ebf, 0x3d78,
+ 0x9ec0, 0x31be,
+ 0x9ec1, 0x3939,
+ 0x9ec2, 0x3471,
+ 0x9ec3, 0x0dbb,
+ 0x9ec4, 0x4514,
+ 0x9ec6, 0x47d6,
+ 0x9ec7, 0x4577,
+ 0x9ec8, 0x2f05,
+ 0x9ecc, 0x1751,
+ 0x9ecd, 0x0dbc,
+ 0x9ece, 0x1287,
+ 0x9ecf, 0x14c2,
+ 0x9ed0, 0x3472,
+ 0x9ed1, 0x0dbd,
+ 0x9ed3, 0x2afd,
+ 0x9ed4, 0x13b1,
+ 0x9ed5, 0x2d35,
+ 0x9ed8, 0x13b0,
+ 0x9eda, 0x2f06,
+ 0x9edb, 0x14c6,
+ 0x9edc, 0x14c4,
+ 0x9ede, 0x14c3,
+ 0x9edf, 0x306f,
+ 0x9ee0, 0x1572,
+ 0x9ee2, 0x47d8,
+ 0x9ee4, 0x32ba,
+ 0x9ee5, 0x32b9,
+ 0x9ee6, 0x32bc,
+ 0x9ee7, 0x32bb,
+ 0x9ee8, 0x1663,
+ 0x9eeb, 0x336c,
+ 0x9eed, 0x336e,
+ 0x9eee, 0x336d,
+ 0x9eef, 0x16b6,
+ 0x9ef0, 0x3406,
+ 0x9ef1, 0x47d9,
+ 0x9ef2, 0x3473,
+ 0x9ef4, 0x171e,
+ 0x9ef5, 0x34fe,
+ 0x9ef6, 0x3518,
+ 0x9ef7, 0x1762,
+ 0x9ef8, 0x47da,
+ 0x9ef9, 0x2360,
+ 0x9efa, 0x2d37,
+ 0x9efb, 0x2f07,
+ 0x9efc, 0x31bf,
+ 0x9efd, 0x2612,
+ 0x9efe, 0x47ce,
+ 0x9eff, 0x2f08,
+ 0x9f00, 0x3071,
+ 0x9f01, 0x3070,
+ 0x9f02, 0x3940,
+ 0x9f06, 0x3475,
+ 0x9f07, 0x173f,
+ 0x9f08, 0x3941,
+ 0x9f09, 0x34ff,
+ 0x9f0a, 0x3519,
+ 0x9f0e, 0x0f7b,
+ 0x9f0f, 0x2afe,
+ 0x9f12, 0x2d38,
+ 0x9f13, 0x0f7c,
+ 0x9f15, 0x1573,
+ 0x9f16, 0x3072,
+ 0x9f17, 0x3945,
+ 0x9f18, 0x3370,
+ 0x9f19, 0x16b7,
+ 0x9f1a, 0x3371,
+ 0x9f1b, 0x336f,
+ 0x9f1c, 0x3476,
+ 0x9f1e, 0x34c4,
+ 0x9f20, 0x0f7d,
+ 0x9f22, 0x2f0b,
+ 0x9f23, 0x2f0a,
+ 0x9f24, 0x2f09,
+ 0x9f25, 0x3073,
+ 0x9f26, 0x3f90,
+ 0x9f27, 0x4620,
+ 0x9f28, 0x3077,
+ 0x9f29, 0x3076,
+ 0x9f2a, 0x3075,
+ 0x9f2b, 0x3074,
+ 0x9f2c, 0x1574,
+ 0x9f2d, 0x31c0,
+ 0x9f2e, 0x32be,
+ 0x9f2f, 0x1664,
+ 0x9f30, 0x32bd,
+ 0x9f31, 0x3372,
+ 0x9f32, 0x3409,
+ 0x9f33, 0x3408,
+ 0x9f34, 0x16f2,
+ 0x9f35, 0x3407,
+ 0x9f36, 0x3479,
+ 0x9f37, 0x3478,
+ 0x9f38, 0x3477,
+ 0x9f39, 0x3947,
+ 0x9f3b, 0x1100,
+ 0x9f3d, 0x2d39,
+ 0x9f3e, 0x14c7,
+ 0x9f40, 0x31c1,
+ 0x9f42, 0x340a,
+ 0x9f43, 0x347a,
+ 0x9f44, 0x47db,
+ 0x9f45, 0x394a,
+ 0x9f46, 0x34c5,
+ 0x9f47, 0x3500,
+ 0x9f48, 0x3532,
+ 0x9f49, 0x354c,
+ 0x9f4a, 0x1101,
+ 0x9f4b, 0x14c8,
+ 0x9f4c, 0x3078,
+ 0x9f4d, 0x31c3,
+ 0x9f4e, 0x3373,
+ 0x9f4f, 0x347b,
+ 0x9f50, 0x4943,
+ 0x9f52, 0x1289,
+ 0x9f53, 0x3f80,
+ 0x9f54, 0x2f0c,
+ 0x9f55, 0x3079,
+ 0x9f56, 0x31c4,
+ 0x9f59, 0x32c3,
+ 0x9f5a, 0x3f23,
+ 0x9f5b, 0x32bf,
+ 0x9f5c, 0x16b8,
+ 0x9f5d, 0x32c2,
+ 0x9f5e, 0x32c1,
+ 0x9f5f, 0x1665,
+ 0x9f60, 0x32c0,
+ 0x9f61, 0x1667,
+ 0x9f62, 0x394f,
+ 0x9f63, 0x1666,
+ 0x9f64, 0x3375,
+ 0x9f65, 0x3374,
+ 0x9f66, 0x16b9,
+ 0x9f69, 0x3950,
+ 0x9f6a, 0x16f4,
+ 0x9f6b, 0x340b,
+ 0x9f6c, 0x16f3,
+ 0x9f6e, 0x347e,
+ 0x9f70, 0x347d,
+ 0x9f71, 0x347c,
+ 0x9f72, 0x1741,
+ 0x9f74, 0x34c6,
+ 0x9f77, 0x1740,
+ 0x9f78, 0x3501,
+ 0x9f79, 0x3504,
+ 0x9f7a, 0x3503,
+ 0x9f7b, 0x3502,
+ 0x9f7e, 0x354b,
+ 0x9f7f, 0x4680,
+ 0x9f8d, 0x13b2,
+ 0x9f8e, 0x3952,
+ 0x9f90, 0x157c,
+ 0x9f91, 0x32c4,
+ 0x9f92, 0x3376,
+ 0x9f94, 0x16f5,
+ 0x9f95, 0x340c,
+ 0x9f98, 0x354d,
+ 0x9f99, 0x4587,
+ 0x9f9c, 0x13b3,
+ 0x9f9f, 0x4646,
+ 0x9fa0, 0x2f0d,
+ 0x9fa2, 0x340d,
+ 0x9fa4, 0x351a,
+ 0x9fa5, 0x3f70,
+ 0xfa0c, 0x0274,
+ 0xfa0d, 0x2381,
+ 0xfe30, 0x006d,
+ 0xfe31, 0x007a,
+ 0xfe33, 0x35af,
+ 0xfe34, 0x35b1,
+ 0xfe35, 0x0082,
+ 0xfe37, 0x0086,
+ 0xfe39, 0x008a,
+ 0xfe3b, 0x008e,
+ 0xfe3d, 0x0092,
+ 0xfe3f, 0x0096,
+ 0xfe41, 0x009a,
+ 0xfe43, 0x009e,
+ 0xfe49, 0x00c7,
+ 0xfe4b, 0x00cb,
+ 0xfe4d, 0x00c9,
+ 0xfe4f, 0x35b2,
+ 0xfe50, 0x0070,
+ 0xfe52, 0x0072,
+ 0xfe54, 0x0074,
+ 0xfe59, 0x00a0,
+ 0xfe5f, 0x00cd,
+ 0xfe62, 0x00df,
+ 0xfe69, 0x010c,
+ 0xff01, 0x006c,
+ 0xff02, 0x36e4,
+ 0xff03, 0x00ae,
+ 0xff04, 0x0103,
+ 0xff05, 0x0108,
+ 0xff06, 0x00af,
+ 0xff07, 0x36e3,
+ 0xff08, 0x0080,
+ 0xff0a, 0x00b0,
+ 0xff0b, 0x00d0,
+ 0xff0c, 0x0064,
+ 0xff0d, 0x00d1,
+ 0xff0e, 0x0067,
+ 0xff0f, 0x0101,
+ 0xff10, 0x014d,
+ 0xff1a, 0x006a,
+ 0xff1b, 0x0069,
+ 0xff1c, 0x00d6,
+ 0xff1d, 0x00d8,
+ 0xff1e, 0x00d7,
+ 0xff1f, 0x006b,
+ 0xff20, 0x0109,
+ 0xff21, 0x016d,
+ 0xff3b, 0x35be,
+ 0xff3c, 0x0102,
+ 0xff3d, 0x35bf,
+ 0xff3e, 0x35b4,
+ 0xff3f, 0x00c5,
+ 0xff41, 0x0187,
+ 0xff5b, 0x0084,
+ 0xff5c, 0x0078,
+ 0xff5d, 0x0085,
+ 0xff64, 0x0071,
+ 0xffe2, 0x36e1,
+ 0xffe4, 0x36e2,
+ 0x2013, 0x0078,
+ 0x2014, 0x007a,
+ 0x2025, 0x006d,
+ 0x300a, 0x0092,
+ 0x3008, 0x0096,
+ 0x300c, 0x009a,
+ 0x300e, 0x009e,
+ 0x3010, 0x008e,
+ 0x3014, 0x008a,
+ 0xfe4f, 0x35b1,
+ 0xff08, 0x0082,
+ 0xff5b, 0x0086,
+ 0xff5d, 0x0087,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 cns13UniCNSUCS2VEnc16 = {
+ 1,
+ { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ cns13UniCNSUCS2VMap2, 15468
+};
+
+static Gushort cns13AdobeCNS13VMap2[152] = {
+ 0x0000, 0x0000,
+ 0x0000, 0x0000,
+ 0x0100, 0x0100,
+ 0x0200, 0x0200,
+ 0x0300, 0x0300,
+ 0x0400, 0x0400,
+ 0x0500, 0x0500,
+ 0x0600, 0x0600,
+ 0x0700, 0x0700,
+ 0x0800, 0x0800,
+ 0x0900, 0x0900,
+ 0x0a00, 0x0a00,
+ 0x0b00, 0x0b00,
+ 0x0c00, 0x0c00,
+ 0x0d00, 0x0d00,
+ 0x0e00, 0x0e00,
+ 0x0f00, 0x0f00,
+ 0x1000, 0x1000,
+ 0x1100, 0x1100,
+ 0x1200, 0x1200,
+ 0x1300, 0x1300,
+ 0x1400, 0x1400,
+ 0x1500, 0x1500,
+ 0x1600, 0x1600,
+ 0x1700, 0x1700,
+ 0x1800, 0x1800,
+ 0x1900, 0x1900,
+ 0x1a00, 0x1a00,
+ 0x1b00, 0x1b00,
+ 0x1c00, 0x1c00,
+ 0x1d00, 0x1d00,
+ 0x1e00, 0x1e00,
+ 0x1f00, 0x1f00,
+ 0x2000, 0x2000,
+ 0x2100, 0x2100,
+ 0x2200, 0x2200,
+ 0x2300, 0x2300,
+ 0x2400, 0x2400,
+ 0x2500, 0x2500,
+ 0x2600, 0x2600,
+ 0x2700, 0x2700,
+ 0x2800, 0x2800,
+ 0x2900, 0x2900,
+ 0x2a00, 0x2a00,
+ 0x2b00, 0x2b00,
+ 0x2c00, 0x2c00,
+ 0x2d00, 0x2d00,
+ 0x2e00, 0x2e00,
+ 0x2f00, 0x2f00,
+ 0x3000, 0x3000,
+ 0x3100, 0x3100,
+ 0x3200, 0x3200,
+ 0x3300, 0x3300,
+ 0x3400, 0x3400,
+ 0x3500, 0x3500,
+ 0x3600, 0x3600,
+ 0x3700, 0x3700,
+ 0x3800, 0x3800,
+ 0x3900, 0x3900,
+ 0x3a00, 0x3a00,
+ 0x3b00, 0x3b00,
+ 0x3c00, 0x3c00,
+ 0x3d00, 0x3d00,
+ 0x3e00, 0x3e00,
+ 0x3f00, 0x3f00,
+ 0x4000, 0x4000,
+ 0x4100, 0x4100,
+ 0x4200, 0x4200,
+ 0x4300, 0x4300,
+ 0x4400, 0x4400,
+ 0x4500, 0x4500,
+ 0x4600, 0x4600,
+ 0x4700, 0x4700,
+ 0x4800, 0x4800,
+ 0x4900, 0x4900,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 cns13AdobeCNS13VEnc16 = {
+ 1,
+ { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ cns13AdobeCNS13VMap2, 76
+};
+
+static struct {
+ char *name;
+ GfxFontEncoding16 *enc;
+} gfxCNS13Tab[] = {
+ { "Adobe-CNS1-0", &cns13AdobeCNS10Enc16 },
+ { "Adobe-CNS1-1", &cns13AdobeCNS11Enc16 },
+ { "Adobe-CNS1-2", &cns13AdobeCNS12Enc16 },
+ { "Adobe-CNS1-3", &cns13AdobeCNS13Enc16 },
+ { "B5-H", &cns13B5HEnc16 },
+ { "B5-V", &cns13B5VEnc16 },
+ { "B5pc-H", &cns13B5pcHEnc16 },
+ { "B5pc-V", &cns13B5pcVEnc16 },
+ { "CNS1-H", &cns13CNS1HEnc16 },
+ { "CNS1-V", &cns13CNS1VEnc16 },
+ { "CNS2-H", &cns13CNS2HEnc16 },
+ { "CNS2-V", &cns13CNS2VEnc16 },
+ { "ETHK-B5-H", &cns13ETHKB5HEnc16 },
+ { "ETHK-B5-V", &cns13ETHKB5VEnc16 },
+ { "ETen-B5-H", &cns13ETenB5HEnc16 },
+ { "ETen-B5-V", &cns13ETenB5VEnc16 },
+ { "ETenms-B5-H", &cns13ETenmsB5HEnc16 },
+ { "ETenms-B5-V", &cns13ETenmsB5VEnc16 },
+ { "HKdla-B5-H", &cns13HKdlaB5HEnc16 },
+ { "HKdla-B5-V", &cns13HKdlaB5VEnc16 },
+ { "HKdlb-B5-H", &cns13HKdlbB5HEnc16 },
+ { "HKdlb-B5-V", &cns13HKdlbB5VEnc16 },
+ { "HKgccs-B5-H", &cns13HKgccsB5HEnc16 },
+ { "HKgccs-B5-V", &cns13HKgccsB5VEnc16 },
+ { "HKm314-B5-H", &cns13HKm314B5HEnc16 },
+ { "HKm314-B5-V", &cns13HKm314B5VEnc16 },
+ { "HKm471-B5-H", &cns13HKm471B5HEnc16 },
+ { "HKm471-B5-V", &cns13HKm471B5VEnc16 },
+ { "HKscs-B5-H", &cns13HKscsB5HEnc16 },
+ { "HKscs-B5-V", &cns13HKscsB5VEnc16 },
+ { "UniCNS-UCS2-H", &cns13UniCNSUCS2HEnc16 },
+ { "UniCNS-UCS2-V", &cns13UniCNSUCS2VEnc16 },
+ { "Identity-H", &cns13AdobeCNS13Enc16 },
+ { "Identity-V", &cns13AdobeCNS13VEnc16 },
+ { NULL, NULL }
+};
+
+#endif
diff --git a/pdftops/COPYING b/pdftops/COPYING
new file mode 100644
index 000000000..a43ea2126
--- /dev/null
+++ b/pdftops/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, 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
+
+ 0. 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.
+
+ 1. 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.
+
+ 2. 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:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) 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.
+
+ c) 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.
+
+ 3. 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:
+
+ a) 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,
+
+ b) 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,
+
+ c) 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.
+
+ 4. 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.
+
+ 5. 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.
+
+ 6. 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.
+
+ 7. 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.
+
+ 8. 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.
+
+ 9. 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.
+
+ 10. 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
+
+ 11. 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.
+
+ 12. 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
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/pdftops/Catalog.cxx b/pdftops/Catalog.cxx
new file mode 100644
index 000000000..fadb4763b
--- /dev/null
+++ b/pdftops/Catalog.cxx
@@ -0,0 +1,308 @@
+//========================================================================
+//
+// Catalog.cc
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#include <stddef.h>
+#include "gmem.h"
+#include "Object.h"
+#include "XRef.h"
+#include "Array.h"
+#include "Dict.h"
+#include "Page.h"
+#include "Error.h"
+#include "Link.h"
+#include "Catalog.h"
+
+//------------------------------------------------------------------------
+// Catalog
+//------------------------------------------------------------------------
+
+Catalog::Catalog(XRef *xrefA, GBool printCommands) {
+ Object catDict, pagesDict;
+ Object obj, obj2;
+ int numPages0;
+ int i;
+
+ ok = gTrue;
+ xref = xrefA;
+ pages = NULL;
+ pageRefs = NULL;
+ numPages = pagesSize = 0;
+ baseURI = NULL;
+
+ xref->getCatalog(&catDict);
+ if (!catDict.isDict()) {
+ error(-1, "Catalog object is wrong type (%s)", catDict.getTypeName());
+ goto err1;
+ }
+
+ // read page tree
+ catDict.dictLookup("Pages", &pagesDict);
+ // This should really be isDict("Pages"), but I've seen at least one
+ // PDF file where the /Type entry is missing.
+ if (!pagesDict.isDict()) {
+ error(-1, "Top-level pages object is wrong type (%s)",
+ pagesDict.getTypeName());
+ goto err2;
+ }
+ pagesDict.dictLookup("Count", &obj);
+ if (!obj.isInt()) {
+ error(-1, "Page count in top-level pages object is wrong type (%s)",
+ obj.getTypeName());
+ goto err3;
+ }
+ pagesSize = numPages0 = obj.getInt();
+ obj.free();
+ pages = (Page **)gmalloc(pagesSize * sizeof(Page *));
+ pageRefs = (Ref *)gmalloc(pagesSize * sizeof(Ref));
+ for (i = 0; i < pagesSize; ++i) {
+ pages[i] = NULL;
+ pageRefs[i].num = -1;
+ pageRefs[i].gen = -1;
+ }
+ numPages = readPageTree(pagesDict.getDict(), NULL, 0, printCommands);
+ if (numPages != numPages0) {
+ error(-1, "Page count in top-level pages object is incorrect");
+ }
+ pagesDict.free();
+
+ // read named destination dictionary
+ catDict.dictLookup("Dests", &dests);
+
+ // read root of named destination tree
+ if (catDict.dictLookup("Names", &obj)->isDict())
+ obj.dictLookup("Dests", &nameTree);
+ else
+ nameTree.initNull();
+ obj.free();
+
+ // read base URI
+ if (catDict.dictLookup("URI", &obj)->isDict()) {
+ if (obj.dictLookup("Base", &obj2)->isString()) {
+ baseURI = obj2.getString()->copy();
+ }
+ obj2.free();
+ }
+ obj.free();
+
+ catDict.free();
+ return;
+
+ err3:
+ obj.free();
+ err2:
+ pagesDict.free();
+ err1:
+ catDict.free();
+ dests.initNull();
+ nameTree.initNull();
+ ok = gFalse;
+}
+
+Catalog::~Catalog() {
+ int i;
+
+ if (pages) {
+ for (i = 0; i < pagesSize; ++i) {
+ if (pages[i]) {
+ delete pages[i];
+ }
+ }
+ gfree(pages);
+ gfree(pageRefs);
+ }
+ dests.free();
+ nameTree.free();
+ if (baseURI) {
+ delete baseURI;
+ }
+}
+
+int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start,
+ GBool printCommands) {
+ Object kids;
+ Object kid;
+ Object kidRef;
+ PageAttrs *attrs1, *attrs2;
+ Page *page;
+ int i, j;
+
+ attrs1 = new PageAttrs(attrs, pagesDict);
+ pagesDict->lookup("Kids", &kids);
+ if (!kids.isArray()) {
+ error(-1, "Kids object (page %d) is wrong type (%s)",
+ start+1, kids.getTypeName());
+ goto err1;
+ }
+ for (i = 0; i < kids.arrayGetLength(); ++i) {
+ kids.arrayGet(i, &kid);
+ if (kid.isDict("Page")) {
+ attrs2 = new PageAttrs(attrs1, kid.getDict());
+ page = new Page(xref, start+1, kid.getDict(), attrs2, printCommands);
+ if (!page->isOk()) {
+ ++start;
+ goto err3;
+ }
+ if (start >= pagesSize) {
+ pagesSize += 32;
+ pages = (Page **)grealloc(pages, pagesSize * sizeof(Page *));
+ pageRefs = (Ref *)grealloc(pageRefs, pagesSize * sizeof(Ref));
+ for (j = pagesSize - 32; j < pagesSize; ++j) {
+ pages[j] = NULL;
+ pageRefs[j].num = -1;
+ pageRefs[j].gen = -1;
+ }
+ }
+ pages[start] = page;
+ kids.arrayGetNF(i, &kidRef);
+ if (kidRef.isRef()) {
+ pageRefs[start].num = kidRef.getRefNum();
+ pageRefs[start].gen = kidRef.getRefGen();
+ }
+ kidRef.free();
+ ++start;
+ // This should really be isDict("Pages"), but I've seen at least one
+ // PDF file where the /Type entry is missing.
+ } else if (kid.isDict()) {
+ if ((start = readPageTree(kid.getDict(), attrs1, start, printCommands))
+ < 0)
+ goto err2;
+ } else {
+ error(-1, "Kid object (page %d) is wrong type (%s)",
+ start+1, kid.getTypeName());
+ goto err2;
+ }
+ kid.free();
+ }
+ delete attrs1;
+ kids.free();
+ return start;
+
+ err3:
+ delete page;
+ err2:
+ kid.free();
+ err1:
+ kids.free();
+ delete attrs1;
+ ok = gFalse;
+ return -1;
+}
+
+int Catalog::findPage(int num, int gen) {
+ int i;
+
+ for (i = 0; i < numPages; ++i) {
+ if (pageRefs[i].num == num && pageRefs[i].gen == gen)
+ return i + 1;
+ }
+ return 0;
+}
+
+LinkDest *Catalog::findDest(GString *name) {
+ LinkDest *dest;
+ Object obj1, obj2;
+ GBool found;
+
+ // try named destination dictionary then name tree
+ found = gFalse;
+ if (dests.isDict()) {
+ if (!dests.dictLookup(name->getCString(), &obj1)->isNull())
+ found = gTrue;
+ else
+ obj1.free();
+ }
+ if (!found && nameTree.isDict()) {
+ if (!findDestInTree(&nameTree, name, &obj1)->isNull())
+ found = gTrue;
+ else
+ obj1.free();
+ }
+ if (!found)
+ return NULL;
+
+ // construct LinkDest
+ dest = NULL;
+ if (obj1.isArray()) {
+ dest = new LinkDest(obj1.getArray(), gTrue);
+ } else if (obj1.isDict()) {
+ if (obj1.dictLookup("D", &obj2)->isArray())
+ dest = new LinkDest(obj2.getArray(), gTrue);
+ else
+ error(-1, "Bad named destination value");
+ obj2.free();
+ } else {
+ error(-1, "Bad named destination value");
+ }
+ obj1.free();
+
+ return dest;
+}
+
+Object *Catalog::findDestInTree(Object *tree, GString *name, Object *obj) {
+ Object names, name1;
+ Object kids, kid, limits, low, high;
+ GBool done, found;
+ int cmp, i;
+
+ // leaf node
+ if (tree->dictLookup("Names", &names)->isArray()) {
+ done = found = gFalse;
+ for (i = 0; !done && i < names.arrayGetLength(); i += 2) {
+ if (names.arrayGet(i, &name1)->isString()) {
+ cmp = name->cmp(name1.getString());
+ if (cmp == 0) {
+ names.arrayGet(i+1, obj);
+ found = gTrue;
+ done = gTrue;
+ } else if (cmp < 0) {
+ done = gTrue;
+ }
+ name1.free();
+ }
+ }
+ names.free();
+ if (!found)
+ obj->initNull();
+ return obj;
+ }
+ names.free();
+
+ // root or intermediate node
+ done = gFalse;
+ if (tree->dictLookup("Kids", &kids)->isArray()) {
+ for (i = 0; !done && i < kids.arrayGetLength(); ++i) {
+ if (kids.arrayGet(i, &kid)->isDict()) {
+ if (kid.dictLookup("Limits", &limits)->isArray()) {
+ if (limits.arrayGet(0, &low)->isString() &&
+ name->cmp(low.getString()) >= 0) {
+ if (limits.arrayGet(1, &high)->isString() &&
+ name->cmp(high.getString()) <= 0) {
+ findDestInTree(&kid, name, obj);
+ done = gTrue;
+ }
+ high.free();
+ }
+ low.free();
+ }
+ limits.free();
+ }
+ kid.free();
+ }
+ }
+ kids.free();
+
+ // name was outside of ranges of all kids
+ if (!done)
+ obj->initNull();
+
+ return obj;
+}
diff --git a/pdftops/Catalog.h b/pdftops/Catalog.h
new file mode 100644
index 000000000..5bf0c74a7
--- /dev/null
+++ b/pdftops/Catalog.h
@@ -0,0 +1,76 @@
+//========================================================================
+//
+// Catalog.h
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifndef CATALOG_H
+#define CATALOG_H
+
+#ifdef __GNUC__
+#pragma interface
+#endif
+
+class XRef;
+class Object;
+class Page;
+class PageAttrs;
+struct Ref;
+class LinkDest;
+
+//------------------------------------------------------------------------
+// Catalog
+//------------------------------------------------------------------------
+
+class Catalog {
+public:
+
+ // Constructor.
+ Catalog(XRef *xrefA, GBool printCommands = gFalse);
+
+ // Destructor.
+ ~Catalog();
+
+ // Is catalog valid?
+ GBool isOk() { return ok; }
+
+ // Get number of pages.
+ int getNumPages() { return numPages; }
+
+ // Get a page.
+ Page *getPage(int i) { return pages[i-1]; }
+
+ // Get the reference for a page object.
+ Ref *getPageRef(int i) { return &pageRefs[i-1]; }
+
+ // Return base URI, or NULL if none.
+ GString *getBaseURI() { return baseURI; }
+
+ // Find a page, given its object ID. Returns page number, or 0 if
+ // not found.
+ int findPage(int num, int gen);
+
+ // Find a named destination. Returns the link destination, or
+ // NULL if <name> is not a destination.
+ LinkDest *findDest(GString *name);
+
+private:
+
+ XRef *xref; // the xref table for this PDF file
+ Page **pages; // array of pages
+ Ref *pageRefs; // object ID for each page
+ int numPages; // number of pages
+ int pagesSize; // size of pages array
+ Object dests; // named destination dictionary
+ Object nameTree; // name tree
+ GString *baseURI; // base URI for URI-type links
+ GBool ok; // true if catalog is valid
+
+ int readPageTree(Dict *pages, PageAttrs *attrs, int start,
+ GBool printCommands);
+ Object *findDestInTree(Object *tree, GString *name, Object *obj);
+};
+
+#endif
diff --git a/pdftops/CompactFontInfo.h b/pdftops/CompactFontInfo.h
new file mode 100644
index 000000000..c64266029
--- /dev/null
+++ b/pdftops/CompactFontInfo.h
@@ -0,0 +1,464 @@
+//========================================================================
+//
+// CompactFontInfo.h
+//
+// Copyright 1999 Derek B. Noonburg
+//
+//========================================================================
+
+#ifndef COMPACTFONTINFO_H
+#define COMPACTFONTINFO_H
+
+static char *type1CStdStrings[391] = {
+ ".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",
+ "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",
+ "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",
+ "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",
+ "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",
+ "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",
+ "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",
+ "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"
+};
+
+static Gushort type1CISOAdobeCharset[229] = {
+ 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, 96, 97, 98, 99,
+ 100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
+ 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
+ 120, 121, 122, 123, 124, 125, 126, 127, 128, 129,
+ 130, 131, 132, 133, 134, 135, 136, 137, 138, 139,
+ 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
+ 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+ 160, 161, 162, 163, 164, 165, 166, 167, 168, 169,
+ 170, 171, 172, 173, 174, 175, 176, 177, 178, 179,
+ 180, 181, 182, 183, 184, 185, 186, 187, 188, 189,
+ 190, 191, 192, 193, 194, 195, 196, 197, 198, 199,
+ 200, 201, 202, 203, 204, 205, 206, 207, 208, 209,
+ 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
+ 220, 221, 222, 223, 224, 225, 226, 227, 228
+};
+
+static Gushort type1CExpertCharset[166] = {
+ 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
+};
+
+static Gushort type1CExpertSubsetCharset[87] = {
+ 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
+};
+
+#endif
diff --git a/pdftops/Decrypt.cxx b/pdftops/Decrypt.cxx
new file mode 100644
index 000000000..623f59417
--- /dev/null
+++ b/pdftops/Decrypt.cxx
@@ -0,0 +1,384 @@
+//========================================================================
+//
+// Decrypt.cc
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#include "gmem.h"
+#include "Decrypt.h"
+
+static void rc4InitKey(Guchar *key, int keyLen, Guchar *state);
+static Guchar rc4DecryptByte(Guchar *state, Guchar *x, Guchar *y, Guchar c);
+static void md5(Guchar *msg, int msgLen, Guchar *digest);
+
+static Guchar passwordPad[32] = {
+ 0x28, 0xbf, 0x4e, 0x5e, 0x4e, 0x75, 0x8a, 0x41,
+ 0x64, 0x00, 0x4e, 0x56, 0xff, 0xfa, 0x01, 0x08,
+ 0x2e, 0x2e, 0x00, 0xb6, 0xd0, 0x68, 0x3e, 0x80,
+ 0x2f, 0x0c, 0xa9, 0xfe, 0x64, 0x53, 0x69, 0x7a
+};
+
+//------------------------------------------------------------------------
+// Decrypt
+//------------------------------------------------------------------------
+
+Decrypt::Decrypt(Guchar *fileKey, int keyLength, int objNum, int objGen) {
+ int i;
+
+ // construct object key
+ for (i = 0; i < keyLength; ++i) {
+ objKey[i] = fileKey[i];
+ }
+ objKey[keyLength] = objNum & 0xff;
+ objKey[keyLength + 1] = (objNum >> 8) & 0xff;
+ objKey[keyLength + 2] = (objNum >> 16) & 0xff;
+ objKey[keyLength + 3] = objGen & 0xff;
+ objKey[keyLength + 4] = (objGen >> 8) & 0xff;
+ md5(objKey, keyLength + 5, objKey);
+
+ // set up for decryption
+ x = y = 0;
+ if ((objKeyLength = keyLength + 5) > 16) {
+ objKeyLength = 16;
+ }
+ rc4InitKey(objKey, objKeyLength, state);
+}
+
+void Decrypt::reset() {
+ x = y = 0;
+ rc4InitKey(objKey, objKeyLength, state);
+}
+
+Guchar Decrypt::decryptByte(Guchar c) {
+ return rc4DecryptByte(state, &x, &y, c);
+}
+
+GBool Decrypt::makeFileKey(int encVersion, int encRevision, int keyLength,
+ GString *ownerKey, GString *userKey,
+ int permissions, GString *fileID,
+ GString *ownerPassword, GString *userPassword,
+ Guchar *fileKey, GBool *ownerPasswordOk) {
+ Guchar test[32];
+ GString *userPassword2;
+ Guchar fState[256];
+ Guchar fx, fy;
+ int len, i;
+
+ // try using the supplied owner password to generate the user password
+ if (ownerPassword) {
+ len = ownerPassword->getLength();
+ if (len < 32) {
+ memcpy(test, ownerPassword->getCString(), len);
+ memcpy(test + len, passwordPad, 32 - len);
+ } else {
+ memcpy(test, ownerPassword->getCString(), 32);
+ }
+ } else {
+ memcpy(test, passwordPad, 32);
+ }
+ md5(test, 32, test);
+ if (encRevision == 3) {
+ for (i = 0; i < 50; ++i) {
+ md5(test, 16, test);
+ }
+ }
+ rc4InitKey(test, keyLength, fState);
+ fx = fy = 0;
+ for (i = 0; i < 32; ++i) {
+ test[i] = rc4DecryptByte(fState, &fx, &fy, ownerKey->getChar(i));
+ }
+ userPassword2 = new GString((char *)test, 32);
+ if (makeFileKey2(encVersion, encRevision, keyLength, ownerKey, userKey,
+ permissions, fileID, userPassword2, fileKey)) {
+ *ownerPasswordOk = gTrue;
+ delete userPassword2;
+ return gTrue;
+ }
+ *ownerPasswordOk = gFalse;
+ delete userPassword2;
+
+ // try using the supplied user password
+ return makeFileKey2(encVersion, encRevision, keyLength, ownerKey, userKey,
+ permissions, fileID, userPassword, fileKey);
+}
+
+GBool Decrypt::makeFileKey2(int encVersion, int encRevision, int keyLength,
+ GString *ownerKey, GString *userKey,
+ int permissions, GString *fileID,
+ GString *userPassword, Guchar *fileKey) {
+ Guchar *buf;
+ Guchar test[32];
+ Guchar fState[256];
+ Guchar tmpKey[16];
+ Guchar fx, fy;
+ int len, i, j;
+ GBool ok;
+
+ // generate file key
+ buf = (Guchar *)gmalloc(68 + fileID->getLength());
+ if (userPassword) {
+ len = userPassword->getLength();
+ if (len < 32) {
+ memcpy(buf, userPassword->getCString(), len);
+ memcpy(buf + len, passwordPad, 32 - len);
+ } else {
+ memcpy(buf, userPassword->getCString(), 32);
+ }
+ } else {
+ memcpy(buf, passwordPad, 32);
+ }
+ memcpy(buf + 32, ownerKey->getCString(), 32);
+ buf[64] = permissions & 0xff;
+ buf[65] = (permissions >> 8) & 0xff;
+ buf[66] = (permissions >> 16) & 0xff;
+ buf[67] = (permissions >> 24) & 0xff;
+ memcpy(buf + 68, fileID->getCString(), fileID->getLength());
+ md5(buf, 68 + fileID->getLength(), fileKey);
+ if (encRevision == 3) {
+ for (i = 0; i < 50; ++i) {
+ md5(fileKey, 16, fileKey);
+ }
+ }
+
+ // test user password
+ if (encRevision == 2) {
+ rc4InitKey(fileKey, keyLength, fState);
+ fx = fy = 0;
+ for (i = 0; i < 32; ++i) {
+ test[i] = rc4DecryptByte(fState, &fx, &fy, userKey->getChar(i));
+ }
+ ok = memcmp(test, passwordPad, 32) == 0;
+ } else if (encRevision == 3) {
+ memcpy(test, userKey->getCString(), 32);
+ for (i = 19; i >= 0; --i) {
+ for (j = 0; j < keyLength; ++j) {
+ tmpKey[j] = fileKey[j] ^ i;
+ }
+ rc4InitKey(tmpKey, keyLength, fState);
+ fx = fy = 0;
+ for (j = 0; j < 32; ++j) {
+ test[j] = rc4DecryptByte(fState, &fx, &fy, test[j]);
+ }
+ }
+ memcpy(buf, passwordPad, 32);
+ memcpy(buf + 32, fileID->getCString(), fileID->getLength());
+ md5(buf, 32 + fileID->getLength(), buf);
+ ok = memcmp(test, buf, 16) == 0;
+ } else {
+ ok = gFalse;
+ }
+
+ gfree(buf);
+ return ok;
+}
+
+//------------------------------------------------------------------------
+// RC4-compatible decryption
+//------------------------------------------------------------------------
+
+static void rc4InitKey(Guchar *key, int keyLen, Guchar *state) {
+ Guchar index1, index2;
+ Guchar t;
+ int i;
+
+ for (i = 0; i < 256; ++i)
+ state[i] = i;
+ index1 = index2 = 0;
+ for (i = 0; i < 256; ++i) {
+ index2 = (key[index1] + state[i] + index2) % 256;
+ t = state[i];
+ state[i] = state[index2];
+ state[index2] = t;
+ index1 = (index1 + 1) % keyLen;
+ }
+}
+
+static Guchar rc4DecryptByte(Guchar *state, Guchar *x, Guchar *y, Guchar c) {
+ Guchar x1, y1, tx, ty;
+
+ x1 = *x = (*x + 1) % 256;
+ y1 = *y = (state[*x] + *y) % 256;
+ tx = state[x1];
+ ty = state[y1];
+ state[x1] = ty;
+ state[y1] = tx;
+ return c ^ state[(tx + ty) % 256];
+}
+
+//------------------------------------------------------------------------
+// MD5 message digest
+//------------------------------------------------------------------------
+
+// this works around a bug in older Sun compilers
+static inline Gulong rotateLeft(Gulong x, int r) {
+ x &= 0xffffffff;
+ return ((x << r) | (x >> (32 - r))) & 0xffffffff;
+}
+
+static inline Gulong md5Round1(Gulong a, Gulong b, Gulong c, Gulong d,
+ Gulong Xk, Gulong s, Gulong Ti) {
+ return b + rotateLeft((a + ((b & c) | (~b & d)) + Xk + Ti), s);
+}
+
+static inline Gulong md5Round2(Gulong a, Gulong b, Gulong c, Gulong d,
+ Gulong Xk, Gulong s, Gulong Ti) {
+ return b + rotateLeft((a + ((b & d) | (c & ~d)) + Xk + Ti), s);
+}
+
+static inline Gulong md5Round3(Gulong a, Gulong b, Gulong c, Gulong d,
+ Gulong Xk, Gulong s, Gulong Ti) {
+ return b + rotateLeft((a + (b ^ c ^ d) + Xk + Ti), s);
+}
+
+static inline Gulong md5Round4(Gulong a, Gulong b, Gulong c, Gulong d,
+ Gulong Xk, Gulong s, Gulong Ti) {
+ return b + rotateLeft((a + (c ^ (b | ~d)) + Xk + Ti), s);
+}
+
+static void md5(Guchar *msg, int msgLen, Guchar *digest) {
+ Gulong x[16];
+ Gulong a, b, c, d, aa, bb, cc, dd;
+ int n64;
+ int i, j, k;
+
+ // compute number of 64-byte blocks
+ // (length + pad byte (0x80) + 8 bytes for length)
+ n64 = (msgLen + 1 + 8 + 63) / 64;
+
+ // initialize a, b, c, d
+ a = 0x67452301;
+ b = 0xefcdab89;
+ c = 0x98badcfe;
+ d = 0x10325476;
+
+ // loop through blocks
+ k = 0;
+ for (i = 0; i < n64; ++i) {
+
+ // grab a 64-byte block
+ for (j = 0; j < 16 && k < msgLen - 3; ++j, k += 4)
+ x[j] = (((((msg[k+3] << 8) + msg[k+2]) << 8) + msg[k+1]) << 8) + msg[k];
+ if (i == n64 - 1) {
+ if (k == msgLen - 3)
+ x[j] = 0x80000000 + (((msg[k+2] << 8) + msg[k+1]) << 8) + msg[k];
+ else if (k == msgLen - 2)
+ x[j] = 0x800000 + (msg[k+1] << 8) + msg[k];
+ else if (k == msgLen - 1)
+ x[j] = 0x8000 + msg[k];
+ else
+ x[j] = 0x80;
+ ++j;
+ while (j < 16)
+ x[j++] = 0;
+ x[14] = msgLen << 3;
+ }
+
+ // save a, b, c, d
+ aa = a;
+ bb = b;
+ cc = c;
+ dd = d;
+
+ // round 1
+ a = md5Round1(a, b, c, d, x[0], 7, 0xd76aa478);
+ d = md5Round1(d, a, b, c, x[1], 12, 0xe8c7b756);
+ c = md5Round1(c, d, a, b, x[2], 17, 0x242070db);
+ b = md5Round1(b, c, d, a, x[3], 22, 0xc1bdceee);
+ a = md5Round1(a, b, c, d, x[4], 7, 0xf57c0faf);
+ d = md5Round1(d, a, b, c, x[5], 12, 0x4787c62a);
+ c = md5Round1(c, d, a, b, x[6], 17, 0xa8304613);
+ b = md5Round1(b, c, d, a, x[7], 22, 0xfd469501);
+ a = md5Round1(a, b, c, d, x[8], 7, 0x698098d8);
+ d = md5Round1(d, a, b, c, x[9], 12, 0x8b44f7af);
+ c = md5Round1(c, d, a, b, x[10], 17, 0xffff5bb1);
+ b = md5Round1(b, c, d, a, x[11], 22, 0x895cd7be);
+ a = md5Round1(a, b, c, d, x[12], 7, 0x6b901122);
+ d = md5Round1(d, a, b, c, x[13], 12, 0xfd987193);
+ c = md5Round1(c, d, a, b, x[14], 17, 0xa679438e);
+ b = md5Round1(b, c, d, a, x[15], 22, 0x49b40821);
+
+ // round 2
+ a = md5Round2(a, b, c, d, x[1], 5, 0xf61e2562);
+ d = md5Round2(d, a, b, c, x[6], 9, 0xc040b340);
+ c = md5Round2(c, d, a, b, x[11], 14, 0x265e5a51);
+ b = md5Round2(b, c, d, a, x[0], 20, 0xe9b6c7aa);
+ a = md5Round2(a, b, c, d, x[5], 5, 0xd62f105d);
+ d = md5Round2(d, a, b, c, x[10], 9, 0x02441453);
+ c = md5Round2(c, d, a, b, x[15], 14, 0xd8a1e681);
+ b = md5Round2(b, c, d, a, x[4], 20, 0xe7d3fbc8);
+ a = md5Round2(a, b, c, d, x[9], 5, 0x21e1cde6);
+ d = md5Round2(d, a, b, c, x[14], 9, 0xc33707d6);
+ c = md5Round2(c, d, a, b, x[3], 14, 0xf4d50d87);
+ b = md5Round2(b, c, d, a, x[8], 20, 0x455a14ed);
+ a = md5Round2(a, b, c, d, x[13], 5, 0xa9e3e905);
+ d = md5Round2(d, a, b, c, x[2], 9, 0xfcefa3f8);
+ c = md5Round2(c, d, a, b, x[7], 14, 0x676f02d9);
+ b = md5Round2(b, c, d, a, x[12], 20, 0x8d2a4c8a);
+
+ // round 3
+ a = md5Round3(a, b, c, d, x[5], 4, 0xfffa3942);
+ d = md5Round3(d, a, b, c, x[8], 11, 0x8771f681);
+ c = md5Round3(c, d, a, b, x[11], 16, 0x6d9d6122);
+ b = md5Round3(b, c, d, a, x[14], 23, 0xfde5380c);
+ a = md5Round3(a, b, c, d, x[1], 4, 0xa4beea44);
+ d = md5Round3(d, a, b, c, x[4], 11, 0x4bdecfa9);
+ c = md5Round3(c, d, a, b, x[7], 16, 0xf6bb4b60);
+ b = md5Round3(b, c, d, a, x[10], 23, 0xbebfbc70);
+ a = md5Round3(a, b, c, d, x[13], 4, 0x289b7ec6);
+ d = md5Round3(d, a, b, c, x[0], 11, 0xeaa127fa);
+ c = md5Round3(c, d, a, b, x[3], 16, 0xd4ef3085);
+ b = md5Round3(b, c, d, a, x[6], 23, 0x04881d05);
+ a = md5Round3(a, b, c, d, x[9], 4, 0xd9d4d039);
+ d = md5Round3(d, a, b, c, x[12], 11, 0xe6db99e5);
+ c = md5Round3(c, d, a, b, x[15], 16, 0x1fa27cf8);
+ b = md5Round3(b, c, d, a, x[2], 23, 0xc4ac5665);
+
+ // round 4
+ a = md5Round4(a, b, c, d, x[0], 6, 0xf4292244);
+ d = md5Round4(d, a, b, c, x[7], 10, 0x432aff97);
+ c = md5Round4(c, d, a, b, x[14], 15, 0xab9423a7);
+ b = md5Round4(b, c, d, a, x[5], 21, 0xfc93a039);
+ a = md5Round4(a, b, c, d, x[12], 6, 0x655b59c3);
+ d = md5Round4(d, a, b, c, x[3], 10, 0x8f0ccc92);
+ c = md5Round4(c, d, a, b, x[10], 15, 0xffeff47d);
+ b = md5Round4(b, c, d, a, x[1], 21, 0x85845dd1);
+ a = md5Round4(a, b, c, d, x[8], 6, 0x6fa87e4f);
+ d = md5Round4(d, a, b, c, x[15], 10, 0xfe2ce6e0);
+ c = md5Round4(c, d, a, b, x[6], 15, 0xa3014314);
+ b = md5Round4(b, c, d, a, x[13], 21, 0x4e0811a1);
+ a = md5Round4(a, b, c, d, x[4], 6, 0xf7537e82);
+ d = md5Round4(d, a, b, c, x[11], 10, 0xbd3af235);
+ c = md5Round4(c, d, a, b, x[2], 15, 0x2ad7d2bb);
+ b = md5Round4(b, c, d, a, x[9], 21, 0xeb86d391);
+
+ // increment a, b, c, d
+ a += aa;
+ b += bb;
+ c += cc;
+ d += dd;
+ }
+
+ // break digest into bytes
+ digest[0] = a & 0xff;
+ digest[1] = (a >>= 8) & 0xff;
+ digest[2] = (a >>= 8) & 0xff;
+ digest[3] = (a >>= 8) & 0xff;
+ digest[4] = b & 0xff;
+ digest[5] = (b >>= 8) & 0xff;
+ digest[6] = (b >>= 8) & 0xff;
+ digest[7] = (b >>= 8) & 0xff;
+ digest[8] = c & 0xff;
+ digest[9] = (c >>= 8) & 0xff;
+ digest[10] = (c >>= 8) & 0xff;
+ digest[11] = (c >>= 8) & 0xff;
+ digest[12] = d & 0xff;
+ digest[13] = (d >>= 8) & 0xff;
+ digest[14] = (d >>= 8) & 0xff;
+ digest[15] = (d >>= 8) & 0xff;
+}
diff --git a/pdftops/Decrypt.h b/pdftops/Decrypt.h
new file mode 100644
index 000000000..1bdb2b7ec
--- /dev/null
+++ b/pdftops/Decrypt.h
@@ -0,0 +1,59 @@
+//========================================================================
+//
+// Decrypt.h
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifndef DECRYPT_H
+#define DECRYPT_H
+
+#ifdef __GNUC__
+#pragma interface
+#endif
+
+#include "gtypes.h"
+#include "GString.h"
+
+//------------------------------------------------------------------------
+// Decrypt
+//------------------------------------------------------------------------
+
+class Decrypt {
+public:
+
+ // Initialize the decryptor object.
+ Decrypt(Guchar *fileKey, int keyLength, int objNum, int objGen);
+
+ // Reset decryption.
+ void reset();
+
+ // Decrypt one byte.
+ Guchar decryptByte(Guchar c);
+
+ // Generate a file key. The <fileKey> buffer must have space for at
+ // least 16 bytes. Checks <ownerPassword> and then <userPassword>
+ // and returns true if either is correct. Sets <ownerPasswordOk> if
+ // the owner password was correct. Either or both of the passwords
+ // may be NULL, which is treated as an empty string.
+ static GBool makeFileKey(int encVersion, int encRevision, int keyLength,
+ GString *ownerKey, GString *userKey,
+ int permissions, GString *fileID,
+ GString *ownerPassword, GString *userPassword,
+ Guchar *fileKey, GBool *ownerPasswordOk);
+
+private:
+
+ static GBool makeFileKey2(int encVersion, int encRevision, int keyLength,
+ GString *ownerKey, GString *userKey,
+ int permissions, GString *fileID,
+ GString *userPassword, Guchar *fileKey);
+
+ int objKeyLength;
+ Guchar objKey[21];
+ Guchar state[256];
+ Guchar x, y;
+};
+
+#endif
diff --git a/pdftops/Dict.cxx b/pdftops/Dict.cxx
new file mode 100644
index 000000000..1ebadfce0
--- /dev/null
+++ b/pdftops/Dict.cxx
@@ -0,0 +1,89 @@
+//========================================================================
+//
+// Dict.cc
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#include <stddef.h>
+#include <string.h>
+#include "gmem.h"
+#include "Object.h"
+#include "XRef.h"
+#include "Dict.h"
+
+//------------------------------------------------------------------------
+// Dict
+//------------------------------------------------------------------------
+
+Dict::Dict(XRef *xrefA) {
+ xref = xrefA;
+ entries = NULL;
+ size = length = 0;
+ ref = 1;
+}
+
+Dict::~Dict() {
+ int i;
+
+ for (i = 0; i < length; ++i) {
+ gfree(entries[i].key);
+ entries[i].val.free();
+ }
+ gfree(entries);
+}
+
+void Dict::add(char *key, Object *val) {
+ if (length + 1 > size) {
+ size += 8;
+ entries = (DictEntry *)grealloc(entries, size * sizeof(DictEntry));
+ }
+ entries[length].key = key;
+ entries[length].val = *val;
+ ++length;
+}
+
+inline DictEntry *Dict::find(char *key) {
+ int i;
+
+ for (i = 0; i < length; ++i) {
+ if (!strcmp(key, entries[i].key))
+ return &entries[i];
+ }
+ return NULL;
+}
+
+GBool Dict::is(char *type) {
+ DictEntry *e;
+
+ return (e = find("Type")) && e->val.isName(type);
+}
+
+Object *Dict::lookup(char *key, Object *obj) {
+ DictEntry *e;
+
+ return (e = find(key)) ? e->val.fetch(xref, obj) : obj->initNull();
+}
+
+Object *Dict::lookupNF(char *key, Object *obj) {
+ DictEntry *e;
+
+ return (e = find(key)) ? e->val.copy(obj) : obj->initNull();
+}
+
+char *Dict::getKey(int i) {
+ return entries[i].key;
+}
+
+Object *Dict::getVal(int i, Object *obj) {
+ return entries[i].val.fetch(xref, obj);
+}
+
+Object *Dict::getValNF(int i, Object *obj) {
+ return entries[i].val.copy(obj);
+}
diff --git a/pdftops/Dict.h b/pdftops/Dict.h
new file mode 100644
index 000000000..c4f1ea58d
--- /dev/null
+++ b/pdftops/Dict.h
@@ -0,0 +1,75 @@
+//========================================================================
+//
+// Dict.h
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifndef DICT_H
+#define DICT_H
+
+#ifdef __GNUC__
+#pragma interface
+#endif
+
+#include "Object.h"
+
+//------------------------------------------------------------------------
+// Dict
+//------------------------------------------------------------------------
+
+struct DictEntry {
+ char *key;
+ Object val;
+};
+
+class Dict {
+public:
+
+ // Constructor.
+ Dict(XRef *xrefA);
+
+ // Destructor.
+ ~Dict();
+
+ // Reference counting.
+ int incRef() { return ++ref; }
+ int decRef() { return --ref; }
+
+ // Get number of entries.
+ int getLength() { return length; }
+
+ // Add an entry. NB: does not copy key.
+ void add(char *key, Object *val);
+
+ // Check if dictionary is of specified type.
+ GBool is(char *type);
+
+ // Look up an entry and return the value. Returns a null object
+ // if <key> is not in the dictionary.
+ Object *lookup(char *key, Object *obj);
+ Object *lookupNF(char *key, Object *obj);
+
+ // Iterative accessors.
+ char *getKey(int i);
+ Object *getVal(int i, Object *obj);
+ Object *getValNF(int i, Object *obj);
+
+ // Set the xref pointer. This is only used in one special case: the
+ // trailer dictionary, which is read before the xref table is
+ // parsed.
+ void setXRef(XRef *xrefA) { xref = xrefA; }
+
+private:
+
+ XRef *xref; // the xref table for this PDF file
+ DictEntry *entries; // array of entries
+ int size; // size of <entries> array
+ int length; // number of entries in dictionary
+ int ref; // reference count
+
+ DictEntry *find(char *key);
+};
+
+#endif
diff --git a/pdftops/Error.cxx b/pdftops/Error.cxx
new file mode 100644
index 000000000..81010e019
--- /dev/null
+++ b/pdftops/Error.cxx
@@ -0,0 +1,47 @@
+//========================================================================
+//
+// Error.cc
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include "gtypes.h"
+#include "Params.h"
+#include "Error.h"
+
+FILE *errFile;
+GBool errQuiet;
+
+void errorInit() {
+ if (errQuiet) {
+ errFile = NULL;
+ } else {
+ errFile = stderr;
+ }
+}
+
+void CDECL error(int pos, const char *msg, ...) {
+ va_list args;
+
+ if (errQuiet) {
+ return;
+ }
+ if (pos >= 0) {
+ fprintf(errFile, "Error (%d): ", pos);
+ } else {
+ fprintf(errFile, "Error: ");
+ }
+ va_start(args, msg);
+ vfprintf(errFile, msg, args);
+ va_end(args);
+ fprintf(errFile, "\n");
+ fflush(errFile);
+}
diff --git a/pdftops/Error.h b/pdftops/Error.h
new file mode 100644
index 000000000..926abcd5a
--- /dev/null
+++ b/pdftops/Error.h
@@ -0,0 +1,26 @@
+//========================================================================
+//
+// Error.h
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifndef ERROR_H
+#define ERROR_H
+
+#ifdef __GNUC__
+#pragma interface
+#endif
+
+#include <stdio.h>
+#include "config.h"
+
+// File to send error (and other) messages to.
+extern FILE *errFile;
+
+extern void errorInit();
+
+extern void CDECL error(int pos, const char *msg, ...);
+
+#endif
diff --git a/pdftops/FontEncoding.cxx b/pdftops/FontEncoding.cxx
new file mode 100644
index 000000000..3d084cc9d
--- /dev/null
+++ b/pdftops/FontEncoding.cxx
@@ -0,0 +1,143 @@
+//========================================================================
+//
+// FontEncoding.cc
+//
+// Copyright 1999 Derek B. Noonburg
+//
+//========================================================================
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include "gmem.h"
+#include "FontEncoding.h"
+
+//------------------------------------------------------------------------
+// FontEncoding
+//------------------------------------------------------------------------
+
+inline int FontEncoding::hash(char *name) {
+ Guint h;
+
+ h = (Guint)name[0] & 0xff;
+ if (h && name[1])
+ h = h * 61 + ((Guint)name[1] & 0xff);
+ return (int)(h % (Guint)fontEncHashSize);
+}
+
+FontEncoding::FontEncoding() {
+ int i;
+
+ encoding = (char **)gmalloc(256 * sizeof(char *));
+ size = 256;
+ freeEnc = gTrue;
+ for (i = 0; i < 256; ++i)
+ encoding[i] = NULL;
+ for (i = 0; i < fontEncHashSize; ++i)
+ hashTab[i] = -1;
+}
+
+FontEncoding::FontEncoding(char **encodingA, int sizeA) {
+ int i;
+
+ encoding = encodingA;
+ size = sizeA;
+ freeEnc = gFalse;
+ for (i = 0; i < fontEncHashSize; ++i)
+ hashTab[i] = -1;
+ for (i = 0; i < size; ++i) {
+ if (encoding[i])
+ addChar1(i, encoding[i]);
+ }
+}
+
+FontEncoding::FontEncoding(FontEncoding *fontEnc) {
+ int i;
+
+ encoding = (char **)gmalloc(fontEnc->size * sizeof(char *));
+ size = fontEnc->size;
+ freeEnc = gTrue;
+ for (i = 0; i < size; ++i) {
+ encoding[i] =
+ fontEnc->encoding[i] ? copyString(fontEnc->encoding[i]) : (char *)NULL;
+ }
+ memcpy(hashTab, fontEnc->hashTab, fontEncHashSize * sizeof(short));
+}
+
+void FontEncoding::addChar(int code, char *name) {
+ int h, i;
+
+ // replace character associated with code
+ if (encoding[code]) {
+ h = hash(encoding[code]);
+ for (i = 0; i < fontEncHashSize; ++i) {
+ if (hashTab[h] == code) {
+ hashTab[h] = -2;
+ break;
+ }
+ if (++h == fontEncHashSize)
+ h = 0;
+ }
+ gfree(encoding[code]);
+ }
+
+ // associate name with code
+ encoding[code] = name;
+
+ // insert name in hash table
+ addChar1(code, name);
+}
+
+void FontEncoding::addChar1(int code, char *name) {
+ int h, i, code2;
+
+ // insert name in hash table
+ h = hash(name);
+ for (i = 0; i < fontEncHashSize; ++i) {
+ code2 = hashTab[h];
+ if (code2 < 0) {
+ hashTab[h] = code;
+ break;
+ } else if (encoding[code2] && !strcmp(encoding[code2], name)) {
+ // keep the highest code for each char -- this is needed because
+ // X won't display chars with codes < 32
+ if (code > code2)
+ hashTab[h] = code;
+ break;
+ }
+ if (++h == fontEncHashSize)
+ h = 0;
+ }
+}
+
+FontEncoding::~FontEncoding() {
+ int i;
+
+ if (freeEnc) {
+ for (i = 0; i < size; ++i) {
+ if (encoding[i])
+ gfree(encoding[i]);
+ }
+ gfree(encoding);
+ }
+}
+
+int FontEncoding::getCharCode(char *name) {
+ int h, i, code;
+
+ h = hash(name);
+ for (i = 0; i < fontEncHashSize; ++i) {
+ code = hashTab[h];
+ if (code == -1 ||
+ (code >= 0 && encoding[code] && !strcmp(encoding[code], name)))
+ return code;
+ if (++h >= fontEncHashSize)
+ h = 0;
+ }
+ return -1;
+}
diff --git a/pdftops/FontEncoding.h b/pdftops/FontEncoding.h
new file mode 100644
index 000000000..9a5695dbe
--- /dev/null
+++ b/pdftops/FontEncoding.h
@@ -0,0 +1,64 @@
+//========================================================================
+//
+// FontEncoding.h
+//
+// Copyright 1999 Derek B. Noonburg
+//
+//========================================================================
+
+#ifndef FONTENCODING_H
+#define FONTENCODING_H
+
+#ifdef __GNUC__
+#pragma interface
+#endif
+
+#include "gtypes.h"
+
+//------------------------------------------------------------------------
+// FontEncoding
+//------------------------------------------------------------------------
+
+#define fontEncHashSize 419
+
+class FontEncoding {
+public:
+
+ // Construct an empty encoding.
+ FontEncoding();
+
+ // Construct an encoding from an array of char names.
+ FontEncoding(char **encodingA, int sizeA);
+
+ // Destructor.
+ ~FontEncoding();
+
+ // Create a copy of the encoding.
+ FontEncoding *copy() { return new FontEncoding(this); }
+
+ // Return number of codes in encoding, i.e., max code + 1.
+ int getSize() { return size; }
+
+ // Add a char to the encoding.
+ void addChar(int code, char *name);
+
+ // Return the character name associated with <code>.
+ char *getCharName(int code) { return encoding[code]; }
+
+ // Return the code associated with <name>.
+ int getCharCode(char *name);
+
+private:
+
+ FontEncoding(FontEncoding *fontEnc);
+ int hash(char *name);
+ void addChar1(int code, char *name);
+
+ char **encoding; // code --> name mapping
+ int size; // number of codes
+ GBool freeEnc; // should we free the encoding array?
+ short // name --> code hash table
+ hashTab[fontEncHashSize];
+};
+
+#endif
diff --git a/pdftops/FontFile.cxx b/pdftops/FontFile.cxx
new file mode 100644
index 000000000..4054db7cd
--- /dev/null
+++ b/pdftops/FontFile.cxx
@@ -0,0 +1,2530 @@
+//========================================================================
+//
+// FontFile.cc
+//
+// Copyright 1999 Derek B. Noonburg
+//
+//========================================================================
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#include <math.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <ctype.h>
+#include "gmem.h"
+#include "Error.h"
+#include "FontFile.h"
+
+#include "StdFontInfo.h"
+#include "CompactFontInfo.h"
+
+//------------------------------------------------------------------------
+
+static Guint getWord(Guchar *ptr, int size);
+static double getNum(Guchar **ptr, GBool *fp);
+static char *getString(int sid, Guchar *stringIdxPtr,
+ Guchar *stringStartPtr, int stringOffSize,
+ char *buf);
+
+//------------------------------------------------------------------------
+
+static inline char *nextLine(char *line, char *end) {
+ while (line < end && *line != '\n' && *line != '\r')
+ ++line;
+ while (line < end && *line == '\n' || *line == '\r')
+ ++line;
+ return line;
+}
+
+static char hexChars[17] = "0123456789ABCDEF";
+
+//------------------------------------------------------------------------
+// FontFile
+//------------------------------------------------------------------------
+
+FontFile::FontFile() {
+}
+
+FontFile::~FontFile() {
+}
+
+//------------------------------------------------------------------------
+// Type1FontFile
+//------------------------------------------------------------------------
+
+Type1FontFile::Type1FontFile(char *file, int len) {
+ char *line, *line1, *p, *p2;
+ char buf[256];
+ char c;
+ int n, code, i;
+
+ name = NULL;
+ encoding = NULL;
+ freeEnc = gTrue;
+
+ for (i = 1, line = file; i <= 100 && line < file + len && !encoding; ++i) {
+
+ // get font name
+ if (!strncmp(line, "/FontName", 9)) {
+ strncpy(buf, line, 255);
+ buf[255] = '\0';
+ if ((p = strchr(buf+9, '/')) &&
+ (p = strtok(p+1, " \t\n\r")))
+ name = copyString(p);
+ line = nextLine(line, file + len);
+
+ // get encoding
+ } else if (!strncmp(line, "/Encoding StandardEncoding def", 30)) {
+ encoding = type1StdEncoding.copy();
+ } else if (!strncmp(line, "/Encoding 256 array", 19)) {
+ encoding = new FontEncoding();
+ for (i = 0; i < 300; ++i) {
+ line1 = nextLine(line, file + len);
+ if ((n = line1 - line) > 255)
+ n = 255;
+ strncpy(buf, line, n);
+ buf[n] = '\0';
+ for (p = buf; *p == ' ' || *p == '\t'; ++p) ;
+ if (!strncmp(p, "dup", 3)) {
+ for (p += 3; *p == ' ' || *p == '\t'; ++p) ;
+ for (p2 = p; *p2 >= '0' && *p2 <= '9'; ++p2) ;
+ if (*p2) {
+ c = *p2;
+ *p2 = '\0';
+ if ((code = atoi(p)) < 256) {
+ *p2 = c;
+ for (p = p2; *p == ' ' || *p == '\t'; ++p) ;
+ if (*p == '/') {
+ ++p;
+ for (p2 = p; *p2 && *p2 != ' ' && *p2 != '\t'; ++p2) ;
+ *p2 = '\0';
+ encoding->addChar(code, copyString(p));
+ }
+ }
+ }
+ } else {
+ if (strtok(buf, " \t") &&
+ (p = strtok(NULL, " \t\n\r")) && !strcmp(p, "def")) {
+ break;
+ }
+ }
+ line = line1;
+ }
+ //~ check for getinterval/putinterval junk
+
+ } else {
+ line = nextLine(line, file + len);
+ }
+ }
+}
+
+Type1FontFile::~Type1FontFile() {
+ if (name)
+ gfree(name);
+ if (encoding && freeEnc)
+ delete encoding;
+}
+
+FontEncoding *Type1FontFile::getEncoding(GBool taken) {
+ if (taken)
+ freeEnc = gFalse;
+ return encoding;
+}
+
+//------------------------------------------------------------------------
+// Type1CFontFile
+//------------------------------------------------------------------------
+
+Type1CFontFile::Type1CFontFile(char *file, int len) {
+ char buf[256];
+ Guchar *topPtr, *idxStartPtr, *idxPtr0, *idxPtr1;
+ Guchar *stringIdxPtr, *stringStartPtr;
+ int topOffSize, idxOffSize, stringOffSize;
+ int nFonts, nStrings, nGlyphs;
+ int nCodes, nRanges, nLeft, nSups;
+ Gushort *glyphNames;
+ int charset, enc, charstrings;
+ int charsetFormat, encFormat;
+ int c, sid;
+ double op[48];
+ double x;
+ GBool isFP;
+ int key;
+ int i, j, n;
+
+ name = NULL;
+ encoding = NULL;
+ freeEnc = gTrue;
+
+ // read header
+ topPtr = (Guchar *)file + (file[2] & 0xff);
+ topOffSize = file[3] & 0xff;
+
+ // read name index (first font only)
+ nFonts = getWord(topPtr, 2);
+ idxOffSize = topPtr[2];
+ topPtr += 3;
+ idxStartPtr = topPtr + (nFonts + 1) * idxOffSize - 1;
+ idxPtr0 = idxStartPtr + getWord(topPtr, idxOffSize);
+ idxPtr1 = idxStartPtr + getWord(topPtr + idxOffSize, idxOffSize);
+ if ((n = idxPtr1 - idxPtr0) > 255)
+ n = 255;
+ strncpy(buf, (char *)idxPtr0, n);
+ buf[n] = '\0';
+ name = copyString(buf);
+ topPtr = idxStartPtr + getWord(topPtr + nFonts * idxOffSize, idxOffSize);
+
+ // read top dict index (first font only)
+ nFonts = getWord(topPtr, 2);
+ idxOffSize = topPtr[2];
+ topPtr += 3;
+ idxStartPtr = topPtr + (nFonts + 1) * idxOffSize - 1;
+ idxPtr0 = idxStartPtr + getWord(topPtr, idxOffSize);
+ idxPtr1 = idxStartPtr + getWord(topPtr + idxOffSize, idxOffSize);
+ charset = 0;
+ enc = 0;
+ charstrings = 0;
+ i = 0;
+ while (idxPtr0 < idxPtr1) {
+ if (*idxPtr0 <= 27 || *idxPtr0 == 31) {
+ key = *idxPtr0++;
+ if (key == 0x0c)
+ key = (key << 8) | *idxPtr0++;
+ if (key == 0x0f) { // charset
+ charset = (int)op[0];
+ } else if (key == 0x10) { // encoding
+ enc = (int)op[0];
+ } else if (key == 0x11) { // charstrings
+ charstrings = (int)op[0];
+ }
+ i = 0;
+ } else {
+ x = getNum(&idxPtr0, &isFP);
+ if (i < 48)
+ op[i++] = x;
+ }
+ }
+ topPtr = idxStartPtr + getWord(topPtr + nFonts * idxOffSize, idxOffSize);
+
+ // read string index
+ nStrings = getWord(topPtr, 2);
+ stringOffSize = topPtr[2];
+ topPtr += 3;
+ stringIdxPtr = topPtr;
+ stringStartPtr = topPtr + (nStrings + 1) * stringOffSize - 1;
+ topPtr = stringStartPtr + getWord(topPtr + nStrings * stringOffSize,
+ stringOffSize);
+
+ // get number of glyphs from charstrings index
+ topPtr = (Guchar *)file + charstrings;
+ nGlyphs = getWord(topPtr, 2);
+
+ // read charset
+ if (charset == 0) {
+ glyphNames = type1CISOAdobeCharset;
+ } else if (charset == 1) {
+ glyphNames = type1CExpertCharset;
+ } else if (charset == 2) {
+ glyphNames = type1CExpertSubsetCharset;
+ } else {
+ glyphNames = (Gushort *)gmalloc(nGlyphs * sizeof(Gushort));
+ glyphNames[0] = 0;
+ topPtr = (Guchar *)file + charset;
+ charsetFormat = *topPtr++;
+ if (charsetFormat == 0) {
+ for (i = 1; i < nGlyphs; ++i) {
+ glyphNames[i] = getWord(topPtr, 2);
+ topPtr += 2;
+ }
+ } else if (charsetFormat == 1) {
+ i = 1;
+ while (i < nGlyphs) {
+ c = getWord(topPtr, 2);
+ topPtr += 2;
+ nLeft = *topPtr++;
+ for (j = 0; j <= nLeft; ++j)
+ glyphNames[i++] = c++;
+ }
+ } else if (charsetFormat == 2) {
+ i = 1;
+ while (i < nGlyphs) {
+ c = getWord(topPtr, 2);
+ topPtr += 2;
+ nLeft = getWord(topPtr, 2);
+ topPtr += 2;
+ for (j = 0; j <= nLeft; ++j)
+ glyphNames[i++] = c++;
+ }
+ }
+ }
+
+ // read encoding (glyph -> code mapping)
+ if (enc == 0) {
+ encoding = type1StdEncoding.copy();
+ } else if (enc == 1) {
+ encoding = type1ExpertEncoding.copy();
+ } else {
+ encoding = new FontEncoding();
+ topPtr = (Guchar *)file + enc;
+ encFormat = *topPtr++;
+ if ((encFormat & 0x7f) == 0) {
+ nCodes = 1 + *topPtr++;
+ if (nCodes > nGlyphs) {
+ nCodes = nGlyphs;
+ }
+ for (i = 1; i < nCodes; ++i) {
+ c = *topPtr++;
+ getString(glyphNames[i], stringIdxPtr, stringStartPtr,
+ stringOffSize, buf);
+ encoding->addChar(c, copyString(buf));
+ }
+ } else if ((encFormat & 0x7f) == 1) {
+ nRanges = *topPtr++;
+ nCodes = 1;
+ for (i = 0; i < nRanges; ++i) {
+ c = *topPtr++;
+ nLeft = *topPtr++;
+ for (j = 0; j <= nLeft && nCodes < nGlyphs; ++j) {
+ getString(glyphNames[nCodes], stringIdxPtr, stringStartPtr,
+ stringOffSize, buf);
+ encoding->addChar(c, copyString(buf));
+ ++nCodes;
+ ++c;
+ }
+ }
+ }
+ if (encFormat & 0x80) {
+ nSups = *topPtr++;
+ for (i = 0; i < nSups; ++i) {
+ c = *topPtr++;
+ sid = getWord(topPtr, 2);
+ topPtr += 2;
+ getString(sid, stringIdxPtr, stringStartPtr,
+ stringOffSize, buf);
+ encoding->addChar(c, copyString(buf));
+ }
+ }
+ }
+
+ if (charset > 2)
+ gfree(glyphNames);
+}
+
+Type1CFontFile::~Type1CFontFile() {
+ if (name)
+ gfree(name);
+ if (encoding && freeEnc)
+ delete encoding;
+}
+
+FontEncoding *Type1CFontFile::getEncoding(GBool taken) {
+ if (taken)
+ freeEnc = gFalse;
+ return encoding;
+}
+
+static Guint getWord(Guchar *ptr, int size) {
+ Guint x;
+ int i;
+
+ x = 0;
+ for (i = 0; i < size; ++i)
+ x = (x << 8) + *ptr++;
+ return x;
+}
+
+static double getNum(Guchar **ptr, GBool *fp) {
+ static char nybChars[16] = "0123456789.ee -";
+ int b0, b, nyb0, nyb1;
+ double x;
+ char buf[65];
+ int i;
+
+ x = 0;
+ *fp = gFalse;
+ b0 = (*ptr)[0];
+ if (b0 < 28) {
+ x = 0;
+ } else if (b0 == 28) {
+ x = ((*ptr)[1] << 8) + (*ptr)[2];
+ *ptr += 3;
+ } else if (b0 == 29) {
+ x = ((*ptr)[1] << 24) + ((*ptr)[2] << 16) + ((*ptr)[3] << 8) + (*ptr)[4];
+ *ptr += 5;
+ } else if (b0 == 30) {
+ *ptr += 1;
+ i = 0;
+ do {
+ b = *(*ptr)++;
+ nyb0 = b >> 4;
+ nyb1 = b & 0x0f;
+ if (nyb0 == 0xf)
+ break;
+ buf[i++] = nybChars[nyb0];
+ if (i == 64)
+ break;
+ if (nyb0 == 0xc)
+ buf[i++] = '-';
+ if (i == 64)
+ break;
+ if (nyb1 == 0xf)
+ break;
+ buf[i++] = nybChars[nyb1];
+ if (i == 64)
+ break;
+ if (nyb1 == 0xc)
+ buf[i++] = '-';
+ } while (i < 64);
+ buf[i] = '\0';
+ x = atof(buf);
+ *fp = gTrue;
+ } else if (b0 == 31) {
+ x = 0;
+ } else if (b0 < 247) {
+ x = b0 - 139;
+ *ptr += 1;
+ } else if (b0 < 251) {
+ x = ((b0 - 247) << 8) + (*ptr)[1] + 108;
+ *ptr += 2;
+ } else {
+ x = -((b0 - 251) << 8) - (*ptr)[1] - 108;
+ *ptr += 2;
+ }
+ return x;
+}
+
+static char *getString(int sid, Guchar *stringIdxPtr,
+ Guchar *stringStartPtr, int stringOffSize,
+ char *buf) {
+ Guchar *idxPtr0, *idxPtr1;
+ int len;
+
+ if (sid < 391) {
+ strcpy(buf, type1CStdStrings[sid]);
+ } else {
+ sid -= 391;
+ idxPtr0 = stringStartPtr + getWord(stringIdxPtr + sid * stringOffSize,
+ stringOffSize);
+ idxPtr1 = stringStartPtr + getWord(stringIdxPtr + (sid+1) * stringOffSize,
+ stringOffSize);
+ if ((len = idxPtr1 - idxPtr0) > 255)
+ len = 255;
+ strncpy(buf, (char *)idxPtr0, len);
+ buf[len] = '\0';
+ }
+ return buf;
+}
+
+//------------------------------------------------------------------------
+// Type1CFontConverter
+//------------------------------------------------------------------------
+
+Type1CFontConverter::Type1CFontConverter(char *fileA, int lenA, FILE *outA) {
+ file = fileA;
+ len = lenA;
+ out = outA;
+ r1 = 55665;
+ line = 0;
+}
+
+Type1CFontConverter::~Type1CFontConverter() {
+}
+
+void Type1CFontConverter::convert() {
+ char *fontName;
+ struct {
+ int version;
+ int notice;
+ int copyright;
+ int fullName;
+ int familyName;
+ int weight;
+ int isFixedPitch;
+ double italicAngle;
+ double underlinePosition;
+ double underlineThickness;
+ int paintType;
+ int charstringType; //~ ???
+ double fontMatrix[6];
+ int uniqueID;
+ double fontBBox[4];
+ double strokeWidth; //~ ???
+ int charset;
+ int encoding;
+ int charStrings;
+ int privateSize;
+ int privateOffset;
+ } dict;
+ char buf[256], eBuf[256];
+ Guchar *topPtr, *idxStartPtr, *idxPtr0, *idxPtr1;
+ Guchar *stringIdxPtr, *stringStartPtr;
+ int topOffSize, idxOffSize, stringOffSize;
+ int nFonts, nStrings, nGlyphs;
+ int nCodes, nRanges, nLeft, nSups;
+ Gushort *glyphNames;
+ int charsetFormat, encFormat;
+ int subrsOffset, nSubrs;
+ int nCharStrings;
+ int c, sid;
+ double x;
+ GBool isFP;
+ int key;
+ int i, j, n;
+
+ // read header
+ topPtr = (Guchar *)file + (file[2] & 0xff);
+ topOffSize = file[3] & 0xff;
+
+ // read name (first font only)
+ nFonts = getWord(topPtr, 2);
+ idxOffSize = topPtr[2];
+ topPtr += 3;
+ idxStartPtr = topPtr + (nFonts + 1) * idxOffSize - 1;
+ idxPtr0 = idxStartPtr + getWord(topPtr, idxOffSize);
+ idxPtr1 = idxStartPtr + getWord(topPtr + idxOffSize, idxOffSize);
+ if ((n = idxPtr1 - idxPtr0) > 255)
+ n = 255;
+ strncpy(buf, (char *)idxPtr0, n);
+ buf[n] = '\0';
+ fontName = copyString(buf);
+ topPtr = idxStartPtr + getWord(topPtr + nFonts * idxOffSize, idxOffSize);
+
+ // read top dict (first font only)
+ nFonts = getWord(topPtr, 2);
+ idxOffSize = topPtr[2];
+ topPtr += 3;
+ idxStartPtr = topPtr + (nFonts + 1) * idxOffSize - 1;
+ idxPtr0 = idxStartPtr + getWord(topPtr, idxOffSize);
+ idxPtr1 = idxStartPtr + getWord(topPtr + idxOffSize, idxOffSize);
+ dict.version = 0;
+ dict.notice = 0;
+ dict.copyright = 0;
+ dict.fullName = 0;
+ dict.familyName = 0;
+ dict.weight = 0;
+ dict.isFixedPitch = 0;
+ dict.italicAngle = 0;
+ dict.underlinePosition = -100;
+ dict.underlineThickness = 50;
+ dict.paintType = 0;
+ dict.charstringType = 2;
+ dict.fontMatrix[0] = 0.001;
+ dict.fontMatrix[1] = 0;
+ dict.fontMatrix[2] = 0;
+ dict.fontMatrix[3] = 0.001;
+ dict.fontMatrix[4] = 0;
+ dict.fontMatrix[5] = 0;
+ dict.uniqueID = 0;
+ dict.fontBBox[0] = 0;
+ dict.fontBBox[1] = 0;
+ dict.fontBBox[2] = 0;
+ dict.fontBBox[3] = 0;
+ dict.strokeWidth = 0;
+ dict.charset = 0;
+ dict.encoding = 0;
+ dict.charStrings = 0;
+ dict.privateSize = 0;
+ dict.privateOffset = 0;
+ i = 0;
+ while (idxPtr0 < idxPtr1) {
+ if (*idxPtr0 <= 27 || *idxPtr0 == 31) {
+ key = *idxPtr0++;
+ if (key == 0x0c)
+ key = (key << 8) | *idxPtr0++;
+ switch (key) {
+ case 0x0000: dict.version = (int)op[0]; break;
+ case 0x0001: dict.notice = (int)op[0]; break;
+ case 0x0c00: dict.copyright = (int)op[0]; break;
+ case 0x0002: dict.fullName = (int)op[0]; break;
+ case 0x0003: dict.familyName = (int)op[0]; break;
+ case 0x0004: dict.weight = (int)op[0]; break;
+ case 0x0c01: dict.isFixedPitch = (int)op[0]; break;
+ case 0x0c02: dict.italicAngle = op[0]; break;
+ case 0x0c03: dict.underlinePosition = op[0]; break;
+ case 0x0c04: dict.underlineThickness = op[0]; break;
+ case 0x0c05: dict.paintType = (int)op[0]; break;
+ case 0x0c06: dict.charstringType = (int)op[0]; break;
+ case 0x0c07: dict.fontMatrix[0] = op[0];
+ dict.fontMatrix[1] = op[1];
+ dict.fontMatrix[2] = op[2];
+ dict.fontMatrix[3] = op[3];
+ dict.fontMatrix[4] = op[4];
+ dict.fontMatrix[5] = op[5]; break;
+ case 0x000d: dict.uniqueID = (int)op[0]; break;
+ case 0x0005: dict.fontBBox[0] = op[0];
+ dict.fontBBox[1] = op[1];
+ dict.fontBBox[2] = op[2];
+ dict.fontBBox[3] = op[3]; break;
+ case 0x0c08: dict.strokeWidth = op[0]; break;
+ case 0x000f: dict.charset = (int)op[0]; break;
+ case 0x0010: dict.encoding = (int)op[0]; break;
+ case 0x0011: dict.charStrings = (int)op[0]; break;
+ case 0x0012: dict.privateSize = (int)op[0];
+ dict.privateOffset = (int)op[1]; break;
+ }
+ i = 0;
+ } else {
+ x = getNum(&idxPtr0, &isFP);
+ if (i < 48) {
+ op[i] = x;
+ fp[i++] = isFP;
+ }
+ }
+ }
+ topPtr = idxStartPtr + getWord(topPtr + nFonts * idxOffSize, idxOffSize);
+
+ // read string index
+ nStrings = getWord(topPtr, 2);
+ stringOffSize = topPtr[2];
+ topPtr += 3;
+ stringIdxPtr = topPtr;
+ stringStartPtr = topPtr + (nStrings + 1) * stringOffSize - 1;
+ topPtr = stringStartPtr + getWord(topPtr + nStrings * stringOffSize,
+ stringOffSize);
+
+#if 1 //~
+ // get global subrs
+ int nGSubrs;
+ int gSubrOffSize;
+
+ nGSubrs = getWord(topPtr, 2);
+ gSubrOffSize = topPtr[2];
+ topPtr += 3;
+#endif
+
+ // write header and font dictionary, up to encoding
+ fprintf(out, "%%!FontType1-1.0: %s", fontName);
+ if (dict.version != 0) {
+ fprintf(out, "%s",
+ getString(dict.version, stringIdxPtr, stringStartPtr,
+ stringOffSize, buf));
+ }
+ fprintf(out, "\n");
+ fprintf(out, "11 dict begin\n");
+ fprintf(out, "/FontInfo 10 dict dup begin\n");
+ if (dict.version != 0) {
+ fprintf(out, "/version (%s) readonly def\n",
+ getString(dict.version, stringIdxPtr, stringStartPtr,
+ stringOffSize, buf));
+ }
+ if (dict.notice != 0) {
+ fprintf(out, "/Notice (%s) readonly def\n",
+ getString(dict.notice, stringIdxPtr, stringStartPtr,
+ stringOffSize, buf));
+ }
+ if (dict.copyright != 0) {
+ fprintf(out, "/Copyright (%s) readonly def\n",
+ getString(dict.copyright, stringIdxPtr, stringStartPtr,
+ stringOffSize, buf));
+ }
+ if (dict.fullName != 0) {
+ fprintf(out, "/FullName (%s) readonly def\n",
+ getString(dict.fullName, stringIdxPtr, stringStartPtr,
+ stringOffSize, buf));
+ }
+ if (dict.familyName != 0) {
+ fprintf(out, "/FamilyName (%s) readonly def\n",
+ getString(dict.familyName, stringIdxPtr, stringStartPtr,
+ stringOffSize, buf));
+ }
+ if (dict.weight != 0) {
+ fprintf(out, "/Weight (%s) readonly def\n",
+ getString(dict.weight, stringIdxPtr, stringStartPtr,
+ stringOffSize, buf));
+ }
+ fprintf(out, "/isFixedPitch %s def\n", dict.isFixedPitch ? "true" : "false");
+ fprintf(out, "/ItalicAngle %g def\n", dict.italicAngle);
+ fprintf(out, "/UnderlinePosition %g def\n", dict.underlinePosition);
+ fprintf(out, "/UnderlineThickness %g def\n", dict.underlineThickness);
+ fprintf(out, "end readonly def\n");
+ fprintf(out, "/FontName /%s def\n", fontName);
+ fprintf(out, "/PaintType %d def\n", dict.paintType);
+ fprintf(out, "/FontType 1 def\n");
+ fprintf(out, "/FontMatrix [%g %g %g %g %g %g] readonly def\n",
+ dict.fontMatrix[0], dict.fontMatrix[1], dict.fontMatrix[2],
+ dict.fontMatrix[3], dict.fontMatrix[4], dict.fontMatrix[5]);
+ fprintf(out, "/FontBBox [%g %g %g %g] readonly def\n",
+ dict.fontBBox[0], dict.fontBBox[1],
+ dict.fontBBox[2], dict.fontBBox[3]);
+ if (dict.uniqueID != 0) {
+ fprintf(out, "/UniqueID %d def\n", dict.uniqueID);
+ }
+
+ // get number of glyphs from charstrings index
+ topPtr = (Guchar *)file + dict.charStrings;
+ nGlyphs = getWord(topPtr, 2);
+
+ // read charset
+ if (dict.charset == 0) {
+ glyphNames = type1CISOAdobeCharset;
+ } else if (dict.charset == 1) {
+ glyphNames = type1CExpertCharset;
+ } else if (dict.charset == 2) {
+ glyphNames = type1CExpertSubsetCharset;
+ } else {
+ glyphNames = (Gushort *)gmalloc(nGlyphs * sizeof(Gushort));
+ glyphNames[0] = 0;
+ topPtr = (Guchar *)file + dict.charset;
+ charsetFormat = *topPtr++;
+ if (charsetFormat == 0) {
+ for (i = 1; i < nGlyphs; ++i) {
+ glyphNames[i] = getWord(topPtr, 2);
+ topPtr += 2;
+ }
+ } else if (charsetFormat == 1) {
+ i = 1;
+ while (i < nGlyphs) {
+ c = getWord(topPtr, 2);
+ topPtr += 2;
+ nLeft = *topPtr++;
+ for (j = 0; j <= nLeft; ++j)
+ glyphNames[i++] = c++;
+ }
+ } else if (charsetFormat == 2) {
+ i = 1;
+ while (i < nGlyphs) {
+ c = getWord(topPtr, 2);
+ topPtr += 2;
+ nLeft = getWord(topPtr, 2);
+ topPtr += 2;
+ for (j = 0; j <= nLeft; ++j)
+ glyphNames[i++] = c++;
+ }
+ }
+ }
+
+ // read encoding (glyph -> code mapping), write Type 1 encoding
+ fprintf(out, "/Encoding ");
+ if (dict.encoding == 0) {
+ fprintf(out, "StandardEncoding def\n");
+ } else {
+ fprintf(out, "256 array\n");
+ fprintf(out, "0 1 255 {1 index exch /.notdef put} for\n");
+ if (dict.encoding == 1) {
+ for (i = 0; i < 256; ++i) {
+ if (type1ExpertEncodingNames[i])
+ fprintf(out, "dup %d /%s put\n", i, type1ExpertEncodingNames[i]);
+ }
+ } else {
+ topPtr = (Guchar *)file + dict.encoding;
+ encFormat = *topPtr++;
+ if ((encFormat & 0x7f) == 0) {
+ nCodes = 1 + *topPtr++;
+ if (nCodes > nGlyphs) {
+ nCodes = nGlyphs;
+ }
+ for (i = 1; i < nCodes; ++i) {
+ c = *topPtr++;
+ fprintf(out, "dup %d /%s put\n", c,
+ getString(glyphNames[i], stringIdxPtr, stringStartPtr,
+ stringOffSize, buf));
+ }
+ } else if ((encFormat & 0x7f) == 1) {
+ nRanges = *topPtr++;
+ nCodes = 1;
+ for (i = 0; i < nRanges; ++i) {
+ c = *topPtr++;
+ nLeft = *topPtr++;
+ for (j = 0; j <= nLeft && nCodes < nGlyphs; ++j) {
+ fprintf(out, "dup %d /%s put\n", c,
+ getString(glyphNames[nCodes], stringIdxPtr, stringStartPtr,
+ stringOffSize, buf));
+ ++nCodes;
+ ++c;
+ }
+ }
+ }
+ if (encFormat & 0x80) {
+ nSups = *topPtr++;
+ for (i = 0; i < nSups; ++i) {
+ c = *topPtr++;
+ sid = getWord(topPtr, 2);
+ topPtr += 2;
+ fprintf(out, "dup %d /%s put\n", c,
+ getString(sid, stringIdxPtr, stringStartPtr,
+ stringOffSize, buf));
+ }
+ }
+ }
+ fprintf(out, "readonly def\n");
+ }
+ fprintf(out, "currentdict end\n");
+ fprintf(out, "currentfile eexec\n");
+
+ // get private dictionary
+ eexecWrite("\x83\xca\x73\xd5");
+ eexecWrite("dup /Private 32 dict dup begin\n");
+ eexecWrite("/RD {string currentfile exch readstring pop} executeonly def\n");
+ eexecWrite("/ND {noaccess def} executeonly def\n");
+ eexecWrite("/NP {noaccess put} executeonly def\n");
+ eexecWrite("/MinFeature {16 16} ND\n");
+ eexecWrite("/password 5839 def\n");
+ subrsOffset = 0;
+ defaultWidthX = 0;
+ nominalWidthX = 0;
+ topPtr = (Guchar *)file + dict.privateOffset;
+ idxPtr0 = topPtr;
+ idxPtr1 = idxPtr0 + dict.privateSize;
+ i = 0;
+ while (idxPtr0 < idxPtr1) {
+ if (*idxPtr0 <= 27 || *idxPtr0 == 31) {
+ key = *idxPtr0++;
+ if (key == 0x0c)
+ key = (key << 8) | *idxPtr0++;
+ switch (key) {
+ case 0x0006:
+ getDeltaInt(eBuf, "BlueValues", op, i);
+ eexecWrite(eBuf);
+ break;
+ case 0x0007:
+ getDeltaInt(eBuf, "OtherBlues", op, i);
+ eexecWrite(eBuf);
+ break;
+ case 0x0008:
+ getDeltaInt(eBuf, "FamilyBlues", op, i);
+ eexecWrite(eBuf);
+ break;
+ case 0x0009:
+ getDeltaInt(eBuf, "FamilyOtherBlues", op, i);
+ eexecWrite(eBuf);
+ break;
+ case 0x0c09:
+ sprintf(eBuf, "/BlueScale %g def\n", op[0]);
+ eexecWrite(eBuf);
+ break;
+ case 0x0c0a:
+ sprintf(eBuf, "/BlueShift %d def\n", (int)op[0]);
+ eexecWrite(eBuf);
+ break;
+ case 0x0c0b:
+ sprintf(eBuf, "/BlueFuzz %d def\n", (int)op[0]);
+ eexecWrite(eBuf);
+ break;
+ case 0x000a:
+ sprintf(eBuf, "/StdHW [%g] def\n", op[0]);
+ eexecWrite(eBuf);
+ break;
+ case 0x000b:
+ sprintf(eBuf, "/StdVW [%g] def\n", op[0]);
+ eexecWrite(eBuf);
+ break;
+ case 0x0c0c:
+ getDeltaReal(eBuf, "StemSnapH", op, i);
+ eexecWrite(eBuf);
+ break;
+ case 0x0c0d:
+ getDeltaReal(eBuf, "StemSnapV", op, i);
+ eexecWrite(eBuf);
+ break;
+ case 0x0c0e:
+ sprintf(eBuf, "/ForceBold %s def\n", op[0] ? "true" : "false");
+ eexecWrite(eBuf);
+ break;
+ case 0x0c0f:
+ sprintf(eBuf, "/ForceBoldThreshold %g def\n", op[0]);
+ eexecWrite(eBuf);
+ break;
+ case 0x0c11:
+ sprintf(eBuf, "/LanguageGroup %d def\n", (int)op[0]);
+ eexecWrite(eBuf);
+ break;
+ case 0x0c12:
+ sprintf(eBuf, "/ExpansionFactor %g def\n", op[0]);
+ eexecWrite(eBuf);
+ break;
+ case 0x0c13:
+ error(-1, "Got Type 1C InitialRandomSeed");
+ break;
+ case 0x0013:
+ subrsOffset = (int)op[0];
+ break;
+ case 0x0014:
+ defaultWidthX = op[0];
+ defaultWidthXFP = fp[0];
+ break;
+ case 0x0015:
+ nominalWidthX = op[0];
+ nominalWidthXFP = fp[0];
+ break;
+ default:
+ error(-1, "Unknown Type 1C private dict entry %04x", key);
+ break;
+ }
+ i = 0;
+ } else {
+ x = getNum(&idxPtr0, &isFP);
+ if (i < 48) {
+ op[i] = x;
+ fp[i++] = isFP;
+ }
+ }
+ }
+
+ // get subrs
+ if (subrsOffset != 0) {
+ topPtr += subrsOffset;
+ nSubrs = getWord(topPtr, 2);
+ idxOffSize = topPtr[2];
+ topPtr += 3;
+ sprintf(eBuf, "/Subrs %d array\n", nSubrs);
+ eexecWrite(eBuf);
+ idxStartPtr = topPtr + (nSubrs + 1) * idxOffSize - 1;
+ idxPtr1 = idxStartPtr + getWord(topPtr, idxOffSize);
+ for (i = 0; i < nSubrs; ++i) {
+ idxPtr0 = idxPtr1;
+ idxPtr1 = idxStartPtr + getWord(topPtr + (i+1)*idxOffSize, idxOffSize);
+ n = idxPtr1 - idxPtr0;
+#if 1 //~
+ error(-1, "Unimplemented Type 2 subrs");
+#else
+ sprintf(eBuf, "dup %d %d RD ", i, n);
+ eexecWrite(eBuf);
+ cvtGlyph(idxPtr0, n);
+ eexecWrite(" NP\n");
+#endif
+ }
+ eexecWrite("ND\n");
+ }
+
+ // get CharStrings
+ topPtr = (Guchar *)file + dict.charStrings;
+ nCharStrings = getWord(topPtr, 2);
+ idxOffSize = topPtr[2];
+ topPtr += 3;
+ sprintf(eBuf, "2 index /CharStrings %d dict dup begin\n", nCharStrings);
+ eexecWrite(eBuf);
+ idxStartPtr = topPtr + (nCharStrings + 1) * idxOffSize - 1;
+ idxPtr1 = idxStartPtr + getWord(topPtr, idxOffSize);
+ for (i = 0; i < nCharStrings; ++i) {
+ idxPtr0 = idxPtr1;
+ idxPtr1 = idxStartPtr + getWord(topPtr + (i+1)*idxOffSize, idxOffSize);
+ n = idxPtr1 - idxPtr0;
+ cvtGlyph(getString(glyphNames[i], stringIdxPtr, stringStartPtr,
+ stringOffSize, buf),
+ idxPtr0, n);
+ }
+ eexecWrite("end\n");
+ eexecWrite("end\n");
+ eexecWrite("readonly put\n");
+ eexecWrite("noaccess put\n");
+ eexecWrite("dup /FontName get exch definefont pop\n");
+ eexecWrite("mark currentfile closefile\n");
+
+ // trailer
+ if (line > 0)
+ fputc('\n', out);
+ for (i = 0; i < 8; ++i) {
+ fprintf(out, "0000000000000000000000000000000000000000000000000000000000000000\n");
+ }
+ fprintf(out, "cleartomark\n");
+
+ // clean up
+ if (dict.charset > 2)
+ gfree(glyphNames);
+ gfree(fontName);
+}
+
+void Type1CFontConverter::eexecWrite(char *s) {
+ Guchar *p;
+ Guchar x;
+
+ for (p = (Guchar *)s; *p; ++p) {
+ x = *p ^ (r1 >> 8);
+ r1 = (x + r1) * 52845 + 22719;
+ fputc(hexChars[x >> 4], out);
+ fputc(hexChars[x & 0x0f], out);
+ line += 2;
+ if (line == 64) {
+ fputc('\n', out);
+ line = 0;
+ }
+ }
+}
+
+void Type1CFontConverter::cvtGlyph(char *name, Guchar *s, int n) {
+ int nHints;
+ int x;
+ GBool first = gTrue;
+ char eBuf[256];
+ double d, dx, dy;
+ GBool dFP;
+ int i, k;
+
+ charBuf = new GString();
+ charBuf->append((char)73);
+ charBuf->append((char)58);
+ charBuf->append((char)147);
+ charBuf->append((char)134);
+
+ i = 0;
+ nOps = 0;
+ nHints = 0;
+ while (i < n) {
+ if (s[i] == 12) {
+ switch (s[i+1]) {
+ case 0: // dotsection (should be Type 1 only?)
+ //~ ignored
+ break;
+ case 34: // hflex
+ if (nOps != 7) {
+ error(-1, "Wrong number of args (%d) to Type 2 hflex", nOps);
+ }
+ eexecDumpNum(op[0], fp[0]);
+ eexecDumpNum(0, gFalse);
+ eexecDumpNum(op[1], fp[1]);
+ eexecDumpNum(op[2], fp[2]);
+ eexecDumpNum(op[3], fp[3]);
+ eexecDumpNum(0, gFalse);
+ eexecDumpOp1(8);
+ eexecDumpNum(op[4], fp[4]);
+ eexecDumpNum(0, gFalse);
+ eexecDumpNum(op[5], fp[5]);
+ eexecDumpNum(-op[2], fp[2]);
+ eexecDumpNum(op[6], fp[6]);
+ eexecDumpNum(0, gFalse);
+ eexecDumpOp1(8);
+ break;
+ case 35: // flex
+ if (nOps != 13) {
+ error(-1, "Wrong number of args (%d) to Type 2 flex", nOps);
+ }
+ eexecDumpNum(op[0], fp[0]);
+ eexecDumpNum(op[1], fp[1]);
+ eexecDumpNum(op[2], fp[2]);
+ eexecDumpNum(op[3], fp[3]);
+ eexecDumpNum(op[4], fp[4]);
+ eexecDumpNum(op[5], fp[5]);
+ eexecDumpOp1(8);
+ eexecDumpNum(op[6], fp[6]);
+ eexecDumpNum(op[7], fp[7]);
+ eexecDumpNum(op[8], fp[8]);
+ eexecDumpNum(op[9], fp[9]);
+ eexecDumpNum(op[10], fp[10]);
+ eexecDumpNum(op[11], fp[11]);
+ eexecDumpOp1(8);
+ break;
+ case 36: // hflex1
+ if (nOps != 9) {
+ error(-1, "Wrong number of args (%d) to Type 2 hflex1", nOps);
+ }
+ eexecDumpNum(op[0], fp[0]);
+ eexecDumpNum(op[1], fp[1]);
+ eexecDumpNum(op[2], fp[2]);
+ eexecDumpNum(op[3], fp[3]);
+ eexecDumpNum(op[4], fp[4]);
+ eexecDumpNum(0, gFalse);
+ eexecDumpOp1(8);
+ eexecDumpNum(op[5], fp[5]);
+ eexecDumpNum(0, gFalse);
+ eexecDumpNum(op[6], fp[6]);
+ eexecDumpNum(op[7], fp[7]);
+ eexecDumpNum(op[8], fp[8]);
+ eexecDumpNum(-(op[1] + op[3] + op[7]), fp[1] | fp[3] | fp[7]);
+ eexecDumpOp1(8);
+ break;
+ case 37: // flex1
+ if (nOps != 11) {
+ error(-1, "Wrong number of args (%d) to Type 2 flex1", nOps);
+ }
+ eexecDumpNum(op[0], fp[0]);
+ eexecDumpNum(op[1], fp[1]);
+ eexecDumpNum(op[2], fp[2]);
+ eexecDumpNum(op[3], fp[3]);
+ eexecDumpNum(op[4], fp[4]);
+ eexecDumpNum(op[5], fp[5]);
+ eexecDumpOp1(8);
+ eexecDumpNum(op[6], fp[6]);
+ eexecDumpNum(op[7], fp[7]);
+ eexecDumpNum(op[8], fp[8]);
+ eexecDumpNum(op[9], fp[9]);
+ dx = op[0] + op[2] + op[4] + op[6] + op[8];
+ dy = op[1] + op[3] + op[5] + op[7] + op[9];
+ if (fabs(dx) > fabs(dy)) {
+ eexecDumpNum(op[10], fp[10]);
+ eexecDumpNum(-dy, fp[1] | fp[3] | fp[5] | fp[7] | fp[9]);
+ } else {
+ eexecDumpNum(-dx, fp[0] | fp[2] | fp[4] | fp[6] | fp[8]);
+ eexecDumpNum(op[10], fp[10]);
+ }
+ eexecDumpOp1(8);
+ break;
+ case 3: // and
+ case 4: // or
+ case 5: // not
+ case 8: // store
+ case 9: // abs
+ case 10: // add
+ case 11: // sub
+ case 12: // div
+ case 13: // load
+ case 14: // neg
+ case 15: // eq
+ case 18: // drop
+ case 20: // put
+ case 21: // get
+ case 22: // ifelse
+ case 23: // random
+ case 24: // mul
+ case 26: // sqrt
+ case 27: // dup
+ case 28: // exch
+ case 29: // index
+ case 30: // roll
+ error(-1, "Unimplemented Type 2 charstring op: 12.%d", s[i+1]);
+ break;
+ default:
+ error(-1, "Illegal Type 2 charstring op: 12.%d", s[i+1]);
+ break;
+ }
+ i += 2;
+ nOps = 0;
+ } else if (s[i] == 19) { // hintmask
+ //~ ignored
+ if (first) {
+ cvtGlyphWidth(nOps == 1);
+ first = gFalse;
+ }
+ if (nOps > 0) {
+ if (nOps & 1) {
+ error(-1, "Wrong number of args (%d) to Type 2 hintmask/vstemhm",
+ nOps);
+ }
+ nHints += nOps / 2;
+ }
+ i += 1 + ((nHints + 7) >> 3);
+ nOps = 0;
+ } else if (s[i] == 20) { // cntrmask
+ //~ ignored
+ if (first) {
+ cvtGlyphWidth(nOps == 1);
+ first = gFalse;
+ }
+ if (nOps > 0) {
+ if (nOps & 1) {
+ error(-1, "Wrong number of args (%d) to Type 2 cntrmask/vstemhm",
+ nOps);
+ }
+ nHints += nOps / 2;
+ }
+ i += 1 + ((nHints + 7) >> 3);
+ nOps = 0;
+ } else if (s[i] == 28) {
+ x = (s[i+1] << 8) + s[i+2];
+ if (x & 0x8000)
+ x |= -1 << 15;
+ if (nOps < 48) {
+ fp[nOps] = gFalse;
+ op[nOps++] = x;
+ }
+ i += 3;
+ } else if (s[i] <= 31) {
+ switch (s[i]) {
+ case 4: // vmoveto
+ if (first) {
+ cvtGlyphWidth(nOps == 2);
+ first = gFalse;
+ }
+ if (nOps != 1)
+ error(-1, "Wrong number of args (%d) to Type 2 vmoveto", nOps);
+ eexecDumpNum(op[0], fp[0]);
+ eexecDumpOp1(4);
+ break;
+ case 5: // rlineto
+ if (nOps < 2 || nOps % 2 != 0)
+ error(-1, "Wrong number of args (%d) to Type 2 rlineto", nOps);
+ for (k = 0; k < nOps; k += 2) {
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpNum(op[k+1], fp[k+1]);
+ eexecDumpOp1(5);
+ }
+ break;
+ case 6: // hlineto
+ if (nOps < 1)
+ error(-1, "Wrong number of args (%d) to Type 2 hlineto", nOps);
+ for (k = 0; k < nOps; ++k) {
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpOp1((k & 1) ? 7 : 6);
+ }
+ break;
+ case 7: // vlineto
+ if (nOps < 1)
+ error(-1, "Wrong number of args (%d) to Type 2 vlineto", nOps);
+ for (k = 0; k < nOps; ++k) {
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpOp1((k & 1) ? 6 : 7);
+ }
+ break;
+ case 8: // rrcurveto
+ if (nOps < 6 || nOps % 6 != 0)
+ error(-1, "Wrong number of args (%d) to Type 2 rrcurveto", nOps);
+ for (k = 0; k < nOps; k += 6) {
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpNum(op[k+1], fp[k+1]);
+ eexecDumpNum(op[k+2], fp[k+2]);
+ eexecDumpNum(op[k+3], fp[k+3]);
+ eexecDumpNum(op[k+4], fp[k+4]);
+ eexecDumpNum(op[k+5], fp[k+5]);
+ eexecDumpOp1(8);
+ }
+ break;
+ case 14: // endchar / seac
+ if (first) {
+ cvtGlyphWidth(nOps == 1 || nOps == 5);
+ first = gFalse;
+ }
+ if (nOps == 4) {
+ eexecDumpNum(0, 0);
+ eexecDumpNum(op[0], fp[0]);
+ eexecDumpNum(op[1], fp[1]);
+ eexecDumpNum(op[2], fp[2]);
+ eexecDumpNum(op[3], fp[3]);
+ eexecDumpOp2(6);
+ } else if (nOps == 0) {
+ eexecDumpOp1(14);
+ } else {
+ error(-1, "Wrong number of args (%d) to Type 2 endchar", nOps);
+ }
+ break;
+ case 21: // rmoveto
+ if (first) {
+ cvtGlyphWidth(nOps == 3);
+ first = gFalse;
+ }
+ if (nOps != 2)
+ error(-1, "Wrong number of args (%d) to Type 2 rmoveto", nOps);
+ eexecDumpNum(op[0], fp[0]);
+ eexecDumpNum(op[1], fp[1]);
+ eexecDumpOp1(21);
+ break;
+ case 22: // hmoveto
+ if (first) {
+ cvtGlyphWidth(nOps == 2);
+ first = gFalse;
+ }
+ if (nOps != 1)
+ error(-1, "Wrong number of args (%d) to Type 2 hmoveto", nOps);
+ eexecDumpNum(op[0], fp[0]);
+ eexecDumpOp1(22);
+ break;
+ case 24: // rcurveline
+ if (nOps < 8 || (nOps - 2) % 6 != 0)
+ error(-1, "Wrong number of args (%d) to Type 2 rcurveline", nOps);
+ for (k = 0; k < nOps - 2; k += 6) {
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpNum(op[k+1], fp[k+1]);
+ eexecDumpNum(op[k+2], fp[k+2]);
+ eexecDumpNum(op[k+3], fp[k+3]);
+ eexecDumpNum(op[k+4], fp[k+4]);
+ eexecDumpNum(op[k+5], fp[k+5]);
+ eexecDumpOp1(8);
+ }
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpNum(op[k+1], fp[k]);
+ eexecDumpOp1(5);
+ break;
+ case 25: // rlinecurve
+ if (nOps < 8 || (nOps - 6) % 2 != 0)
+ error(-1, "Wrong number of args (%d) to Type 2 rlinecurve", nOps);
+ for (k = 0; k < nOps - 6; k += 2) {
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpNum(op[k+1], fp[k]);
+ eexecDumpOp1(5);
+ }
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpNum(op[k+1], fp[k+1]);
+ eexecDumpNum(op[k+2], fp[k+2]);
+ eexecDumpNum(op[k+3], fp[k+3]);
+ eexecDumpNum(op[k+4], fp[k+4]);
+ eexecDumpNum(op[k+5], fp[k+5]);
+ eexecDumpOp1(8);
+ break;
+ case 26: // vvcurveto
+ if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0))
+ error(-1, "Wrong number of args (%d) to Type 2 vvcurveto", nOps);
+ if (nOps % 2 == 1) {
+ eexecDumpNum(op[0], fp[0]);
+ eexecDumpNum(op[1], fp[1]);
+ eexecDumpNum(op[2], fp[2]);
+ eexecDumpNum(op[3], fp[3]);
+ eexecDumpNum(0, gFalse);
+ eexecDumpNum(op[4], fp[4]);
+ eexecDumpOp1(8);
+ k = 5;
+ } else {
+ k = 0;
+ }
+ for (; k < nOps; k += 4) {
+ eexecDumpNum(0, gFalse);
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpNum(op[k+1], fp[k+1]);
+ eexecDumpNum(op[k+2], fp[k+2]);
+ eexecDumpNum(0, gFalse);
+ eexecDumpNum(op[k+3], fp[k+3]);
+ eexecDumpOp1(8);
+ }
+ break;
+ case 27: // hhcurveto
+ if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0))
+ error(-1, "Wrong number of args (%d) to Type 2 hhcurveto", nOps);
+ if (nOps % 2 == 1) {
+ eexecDumpNum(op[1], fp[1]);
+ eexecDumpNum(op[0], fp[0]);
+ eexecDumpNum(op[2], fp[2]);
+ eexecDumpNum(op[3], fp[3]);
+ eexecDumpNum(op[4], fp[4]);
+ eexecDumpNum(0, gFalse);
+ eexecDumpOp1(8);
+ k = 5;
+ } else {
+ k = 0;
+ }
+ for (; k < nOps; k += 4) {
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpNum(0, gFalse);
+ eexecDumpNum(op[k+1], fp[k+1]);
+ eexecDumpNum(op[k+2], fp[k+2]);
+ eexecDumpNum(op[k+3], fp[k+3]);
+ eexecDumpNum(0, gFalse);
+ eexecDumpOp1(8);
+ }
+ break;
+ case 30: // vhcurveto
+ if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0))
+ error(-1, "Wrong number of args (%d) to Type 2 vhcurveto", nOps);
+ for (k = 0; k < nOps && k != nOps-5; k += 4) {
+ if (k % 8 == 0) {
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpNum(op[k+1], fp[k+1]);
+ eexecDumpNum(op[k+2], fp[k+2]);
+ eexecDumpNum(op[k+3], fp[k+3]);
+ eexecDumpOp1(30);
+ } else {
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpNum(op[k+1], fp[k+1]);
+ eexecDumpNum(op[k+2], fp[k+2]);
+ eexecDumpNum(op[k+3], fp[k+3]);
+ eexecDumpOp1(31);
+ }
+ }
+ if (k == nOps-5) {
+ if (k % 8 == 0) {
+ eexecDumpNum(0, gFalse);
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpNum(op[k+1], fp[k+1]);
+ eexecDumpNum(op[k+2], fp[k+2]);
+ eexecDumpNum(op[k+3], fp[k+3]);
+ eexecDumpNum(op[k+4], fp[k+4]);
+ } else {
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpNum(0, gFalse);
+ eexecDumpNum(op[k+1], fp[k+1]);
+ eexecDumpNum(op[k+2], fp[k+2]);
+ eexecDumpNum(op[k+4], fp[k+4]);
+ eexecDumpNum(op[k+3], fp[k+3]);
+ }
+ eexecDumpOp1(8);
+ }
+ break;
+ case 31: // hvcurveto
+ if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0))
+ error(-1, "Wrong number of args (%d) to Type 2 hvcurveto", nOps);
+ for (k = 0; k < nOps && k != nOps-5; k += 4) {
+ if (k % 8 == 0) {
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpNum(op[k+1], fp[k+1]);
+ eexecDumpNum(op[k+2], fp[k+2]);
+ eexecDumpNum(op[k+3], fp[k+3]);
+ eexecDumpOp1(31);
+ } else {
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpNum(op[k+1], fp[k+1]);
+ eexecDumpNum(op[k+2], fp[k+2]);
+ eexecDumpNum(op[k+3], fp[k+3]);
+ eexecDumpOp1(30);
+ }
+ }
+ if (k == nOps-5) {
+ if (k % 8 == 0) {
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpNum(0, gFalse);
+ eexecDumpNum(op[k+1], fp[k+1]);
+ eexecDumpNum(op[k+2], fp[k+2]);
+ eexecDumpNum(op[k+4], fp[k+4]);
+ eexecDumpNum(op[k+3], fp[k+3]);
+ } else {
+ eexecDumpNum(0, gFalse);
+ eexecDumpNum(op[k], fp[k]);
+ eexecDumpNum(op[k+1], fp[k+1]);
+ eexecDumpNum(op[k+2], fp[k+2]);
+ eexecDumpNum(op[k+3], fp[k+3]);
+ eexecDumpNum(op[k+4], fp[k+4]);
+ }
+ eexecDumpOp1(8);
+ }
+ break;
+ case 1: // hstem
+ if (first) {
+ cvtGlyphWidth(nOps & 1);
+ first = gFalse;
+ }
+ if (nOps & 1) {
+ error(-1, "Wrong number of args (%d) to Type 2 hstem", nOps);
+ }
+ d = 0;
+ dFP = gFalse;
+ for (k = 0; k < nOps; k += 2) {
+ if (op[k+1] < 0) {
+ d += op[k] + op[k+1];
+ dFP |= fp[k] | fp[k+1];
+ eexecDumpNum(d, dFP);
+ eexecDumpNum(-op[k+1], fp[k+1]);
+ } else {
+ d += op[k];
+ dFP |= fp[k];
+ eexecDumpNum(d, dFP);
+ eexecDumpNum(op[k+1], fp[k+1]);
+ d += op[k+1];
+ dFP |= fp[k+1];
+ }
+ eexecDumpOp1(1);
+ }
+ nHints += nOps / 2;
+ break;
+ case 3: // vstem
+ if (first) {
+ cvtGlyphWidth(nOps & 1);
+ first = gFalse;
+ }
+ if (nOps & 1) {
+ error(-1, "Wrong number of args (%d) to Type 2 vstem", nOps);
+ }
+ d = 0;
+ dFP = gFalse;
+ for (k = 0; k < nOps; k += 2) {
+ if (op[k+1] < 0) {
+ d += op[k] + op[k+1];
+ dFP |= fp[k] | fp[k+1];
+ eexecDumpNum(d, dFP);
+ eexecDumpNum(-op[k+1], fp[k+1]);
+ } else {
+ d += op[k];
+ dFP |= fp[k];
+ eexecDumpNum(d, dFP);
+ eexecDumpNum(op[k+1], fp[k+1]);
+ d += op[k+1];
+ dFP |= fp[k+1];
+ }
+ eexecDumpOp1(3);
+ }
+ nHints += nOps / 2;
+ break;
+ case 18: // hstemhm
+ //~ ignored
+ if (first) {
+ cvtGlyphWidth(nOps & 1);
+ first = gFalse;
+ }
+ if (nOps & 1) {
+ error(-1, "Wrong number of args (%d) to Type 2 hstemhm", nOps);
+ }
+ nHints += nOps / 2;
+ break;
+ case 23: // vstemhm
+ //~ ignored
+ if (first) {
+ cvtGlyphWidth(nOps & 1);
+ first = gFalse;
+ }
+ if (nOps & 1) {
+ error(-1, "Wrong number of args (%d) to Type 2 vstemhm", nOps);
+ }
+ nHints += nOps / 2;
+ break;
+ case 10: // callsubr
+ case 11: // return
+ case 16: // blend
+ case 29: // callgsubr
+ error(-1, "Unimplemented Type 2 charstring op: %d", s[i]);
+ break;
+ default:
+ error(-1, "Illegal Type 2 charstring op: %d", s[i]);
+ break;
+ }
+ ++i;
+ nOps = 0;
+ } else if (s[i] <= 246) {
+ if (nOps < 48) {
+ fp[nOps] = gFalse;
+ op[nOps++] = (int)s[i] - 139;
+ }
+ ++i;
+ } else if (s[i] <= 250) {
+ if (nOps < 48) {
+ fp[nOps] = gFalse;
+ op[nOps++] = (((int)s[i] - 247) << 8) + (int)s[i+1] + 108;
+ }
+ i += 2;
+ } else if (s[i] <= 254) {
+ if (nOps < 48) {
+ fp[nOps] = gFalse;
+ op[nOps++] = -(((int)s[i] - 251) << 8) - (int)s[i+1] - 108;
+ }
+ i += 2;
+ } else {
+ x = (s[i+1] << 24) | (s[i+2] << 16) | (s[i+3] << 8) | s[i+4];
+ if (x & 0x80000000)
+ x |= -1 << 31;
+ if (nOps < 48) {
+ fp[nOps] = gTrue;
+ op[nOps++] = (double)x / 65536.0;
+ }
+ i += 5;
+ }
+ }
+
+ sprintf(eBuf, "/%s %d RD ", name, charBuf->getLength());
+ eexecWrite(eBuf);
+ eexecWriteCharstring((Guchar *)charBuf->getCString(), charBuf->getLength());
+ eexecWrite(" ND\n");
+ delete charBuf;
+}
+
+void Type1CFontConverter::cvtGlyphWidth(GBool useOp) {
+ double w;
+ GBool wFP;
+ int i;
+
+ if (useOp) {
+ w = nominalWidthX + op[0];
+ wFP = nominalWidthXFP | fp[0];
+ for (i = 1; i < nOps; ++i) {
+ op[i-1] = op[i];
+ fp[i-1] = fp[i];
+ }
+ --nOps;
+ } else {
+ w = defaultWidthX;
+ wFP = defaultWidthXFP;
+ }
+ eexecDumpNum(0, gFalse);
+ eexecDumpNum(w, wFP);
+ eexecDumpOp1(13);
+}
+
+void Type1CFontConverter::eexecDumpNum(double x, GBool fpA) {
+ Guchar buf[12];
+ int y, n;
+
+ n = 0;
+ if (fpA) {
+ if (x >= -32768 && x < 32768) {
+ y = (int)(x * 256.0);
+ buf[0] = 255;
+ buf[1] = (Guchar)(y >> 24);
+ buf[2] = (Guchar)(y >> 16);
+ buf[3] = (Guchar)(y >> 8);
+ buf[4] = (Guchar)y;
+ buf[5] = 255;
+ buf[6] = 0;
+ buf[7] = 0;
+ buf[8] = 1;
+ buf[9] = 0;
+ buf[10] = 12;
+ buf[11] = 12;
+ n = 12;
+ } else {
+ error(-1, "Type 2 fixed point constant out of range");
+ }
+ } else {
+ y = (int)x;
+ if (y >= -107 && y <= 107) {
+ buf[0] = (Guchar)(y + 139);
+ n = 1;
+ } else if (y > 107 && y <= 1131) {
+ y -= 108;
+ buf[0] = (Guchar)((y >> 8) + 247);
+ buf[1] = (Guchar)(y & 0xff);
+ n = 2;
+ } else if (y < -107 && y >= -1131) {
+ y = -y - 108;
+ buf[0] = (Guchar)((y >> 8) + 251);
+ buf[1] = (Guchar)(y & 0xff);
+ n = 2;
+ } else {
+ buf[0] = 255;
+ buf[1] = (Guchar)(y >> 24);
+ buf[2] = (Guchar)(y >> 16);
+ buf[3] = (Guchar)(y >> 8);
+ buf[4] = (Guchar)y;
+ n = 5;
+ }
+ }
+ charBuf->append((char *)buf, n);
+}
+
+void Type1CFontConverter::eexecDumpOp1(int opA) {
+ charBuf->append((char)opA);
+}
+
+void Type1CFontConverter::eexecDumpOp2(int opA) {
+ charBuf->append((char)12);
+ charBuf->append((char)opA);
+}
+
+void Type1CFontConverter::eexecWriteCharstring(Guchar *s, int n) {
+ Gushort r2;
+ Guchar x;
+ int i;
+
+ r2 = 4330;
+
+ for (i = 0; i < n; ++i) {
+ // charstring encryption
+ x = s[i];
+ x ^= (r2 >> 8);
+ r2 = (x + r2) * 52845 + 22719;
+
+ // eexec encryption
+ x ^= (r1 >> 8);
+ r1 = (x + r1) * 52845 + 22719;
+ fputc(hexChars[x >> 4], out);
+ fputc(hexChars[x & 0x0f], out);
+ line += 2;
+ if (line == 64) {
+ fputc('\n', out);
+ line = 0;
+ }
+ }
+}
+
+void Type1CFontConverter::getDeltaInt(char *buf, char *name, double *opA,
+ int n) {
+ int x, i;
+
+ sprintf(buf, "/%s [", name);
+ buf += strlen(buf);
+ x = 0;
+ for (i = 0; i < n; ++i) {
+ x += (int)opA[i];
+ sprintf(buf, "%s%d", i > 0 ? " " : "", x);
+ buf += strlen(buf);
+ }
+ sprintf(buf, "] def\n");
+}
+
+void Type1CFontConverter::getDeltaReal(char *buf, char *name, double *opA,
+ int n) {
+ double x;
+ int i;
+
+ sprintf(buf, "/%s [", name);
+ buf += strlen(buf);
+ x = 0;
+ for (i = 0; i < n; ++i) {
+ x += opA[i];
+ sprintf(buf, "%s%g", i > 0 ? " " : "", x);
+ buf += strlen(buf);
+ }
+ sprintf(buf, "] def\n");
+}
+
+//------------------------------------------------------------------------
+// TrueTypeFontFile
+//------------------------------------------------------------------------
+
+//
+// Terminology
+// -----------
+//
+// character code = number used as an element of a text string
+//
+// character name = glyph name = name for a particular glyph within a
+// font
+//
+// glyph index = position (within some internal table in the font)
+// where the instructions to draw a particular glyph are
+// stored
+//
+// Type 1 fonts
+// ------------
+//
+// Type 1 fonts contain:
+//
+// Encoding: array of glyph names, maps char codes to glyph names
+//
+// Encoding[charCode] = charName
+//
+// CharStrings: dictionary of instructions, keyed by character names,
+// maps character name to glyph data
+//
+// CharStrings[charName] = glyphData
+//
+// TrueType fonts
+// --------------
+//
+// TrueType fonts contain:
+//
+// 'cmap' table: mapping from character code to glyph index; there may
+// be multiple cmaps in a TrueType font
+//
+// cmap[charCode] = glyphIdx
+//
+// 'post' table: mapping from glyph index to glyph name
+//
+// post[glyphIdx] = glyphName
+//
+// Type 42 fonts
+// -------------
+//
+// Type 42 fonts contain:
+//
+// Encoding: array of glyph names, maps char codes to glyph names
+//
+// Encoding[charCode] = charName
+//
+// CharStrings: dictionary of glyph indexes, keyed by character names,
+// maps character name to glyph index
+//
+// CharStrings[charName] = glyphIdx
+//
+
+struct TTFontTableHdr {
+ char tag[4];
+ Guint checksum;
+ Guint offset;
+ Guint length;
+};
+
+// TrueType tables required by the Type 42 spec.
+static char *t42ReqTables[9] = {
+ "head",
+ "hhea",
+ "loca",
+ "maxp",
+ "cvt ",
+ "prep",
+ "glyf",
+ "hmtx",
+ "fpgm"
+};
+
+// Glyph names in some arbitrary standard that Apple uses for their
+// TrueType fonts.
+static char *macGlyphNames[258] = {
+ ".notdef",
+ "null",
+ "CR",
+ "space",
+ "exclam",
+ "quotedbl",
+ "numbersign",
+ "dollar",
+ "percent",
+ "ampersand",
+ "quotesingle",
+ "parenleft",
+ "parenright",
+ "asterisk",
+ "plus",
+ "comma",
+ "hyphen",
+ "period",
+ "slash",
+ "zero",
+ "one",
+ "two",
+ "three",
+ "four",
+ "five",
+ "six",
+ "seven",
+ "eight",
+ "nine",
+ "colon",
+ "semicolon",
+ "less",
+ "equal",
+ "greater",
+ "question",
+ "at",
+ "A",
+ "B",
+ "C",
+ "D",
+ "E",
+ "F",
+ "G",
+ "H",
+ "I",
+ "J",
+ "K",
+ "L",
+ "M",
+ "N",
+ "O",
+ "P",
+ "Q",
+ "R",
+ "S",
+ "T",
+ "U",
+ "V",
+ "W",
+ "X",
+ "Y",
+ "Z",
+ "bracketleft",
+ "backslash",
+ "bracketright",
+ "asciicircum",
+ "underscore",
+ "grave",
+ "a",
+ "b",
+ "c",
+ "d",
+ "e",
+ "f",
+ "g",
+ "h",
+ "i",
+ "j",
+ "k",
+ "l",
+ "m",
+ "n",
+ "o",
+ "p",
+ "q",
+ "r",
+ "s",
+ "t",
+ "u",
+ "v",
+ "w",
+ "x",
+ "y",
+ "z",
+ "braceleft",
+ "bar",
+ "braceright",
+ "asciitilde",
+ "Adieresis",
+ "Aring",
+ "Ccedilla",
+ "Eacute",
+ "Ntilde",
+ "Odieresis",
+ "Udieresis",
+ "aacute",
+ "agrave",
+ "acircumflex",
+ "adieresis",
+ "atilde",
+ "aring",
+ "ccedilla",
+ "eacute",
+ "egrave",
+ "ecircumflex",
+ "edieresis",
+ "iacute",
+ "igrave",
+ "icircumflex",
+ "idieresis",
+ "ntilde",
+ "oacute",
+ "ograve",
+ "ocircumflex",
+ "odieresis",
+ "otilde",
+ "uacute",
+ "ugrave",
+ "ucircumflex",
+ "udieresis",
+ "dagger",
+ "degree",
+ "cent",
+ "sterling",
+ "section",
+ "bullet",
+ "paragraph",
+ "germandbls",
+ "registered",
+ "copyright",
+ "trademark",
+ "acute",
+ "dieresis",
+ "notequal",
+ "AE",
+ "Oslash",
+ "infinity",
+ "plusminus",
+ "lessequal",
+ "greaterequal",
+ "yen",
+ "mu1",
+ "partialdiff",
+ "summation",
+ "product",
+ "pi",
+ "integral",
+ "ordfeminine",
+ "ordmasculine",
+ "Ohm",
+ "ae",
+ "oslash",
+ "questiondown",
+ "exclamdown",
+ "logicalnot",
+ "radical",
+ "florin",
+ "approxequal",
+ "increment",
+ "guillemotleft",
+ "guillemotright",
+ "ellipsis",
+ "nbspace",
+ "Agrave",
+ "Atilde",
+ "Otilde",
+ "OE",
+ "oe",
+ "endash",
+ "emdash",
+ "quotedblleft",
+ "quotedblright",
+ "quoteleft",
+ "quoteright",
+ "divide",
+ "lozenge",
+ "ydieresis",
+ "Ydieresis",
+ "fraction",
+ "currency",
+ "guilsinglleft",
+ "guilsinglright",
+ "fi",
+ "fl",
+ "daggerdbl",
+ "periodcentered",
+ "quotesinglbase",
+ "quotedblbase",
+ "perthousand",
+ "Acircumflex",
+ "Ecircumflex",
+ "Aacute",
+ "Edieresis",
+ "Egrave",
+ "Iacute",
+ "Icircumflex",
+ "Idieresis",
+ "Igrave",
+ "Oacute",
+ "Ocircumflex",
+ "applelogo",
+ "Ograve",
+ "Uacute",
+ "Ucircumflex",
+ "Ugrave",
+ "dotlessi",
+ "circumflex",
+ "tilde",
+ "overscore",
+ "breve",
+ "dotaccent",
+ "ring",
+ "cedilla",
+ "hungarumlaut",
+ "ogonek",
+ "caron",
+ "Lslash",
+ "lslash",
+ "Scaron",
+ "scaron",
+ "Zcaron",
+ "zcaron",
+ "brokenbar",
+ "Eth",
+ "eth",
+ "Yacute",
+ "yacute",
+ "Thorn",
+ "thorn",
+ "minus",
+ "multiply",
+ "onesuperior",
+ "twosuperior",
+ "threesuperior",
+ "onehalf",
+ "onequarter",
+ "threequarters",
+ "franc",
+ "Gbreve",
+ "gbreve",
+ "Idot",
+ "Scedilla",
+ "scedilla",
+ "Cacute",
+ "cacute",
+ "Ccaron",
+ "ccaron",
+ "dmacron"
+};
+
+TrueTypeFontFile::TrueTypeFontFile(char *fileA, int lenA) {
+ int pos, i;
+
+ file = fileA;
+ len = lenA;
+
+ encoding = NULL;
+ freeEnc = gTrue;
+
+ // read table directory
+ nTables = getUShort(4);
+ tableHdrs = (TTFontTableHdr *)gmalloc(nTables * sizeof(TTFontTableHdr));
+ pos = 12;
+ for (i = 0; i < nTables; ++i) {
+ tableHdrs[i].tag[0] = getByte(pos+0);
+ tableHdrs[i].tag[1] = getByte(pos+1);
+ tableHdrs[i].tag[2] = getByte(pos+2);
+ tableHdrs[i].tag[3] = getByte(pos+3);
+ tableHdrs[i].checksum = getULong(pos+4);
+ tableHdrs[i].offset = getULong(pos+8);
+ tableHdrs[i].length = getULong(pos+12);
+ pos += 16;
+ }
+
+ // check for tables that are required by both the TrueType spec
+ // and the Type 42 spec
+ if (seekTable("head") < 0 ||
+ seekTable("hhea") < 0 ||
+ seekTable("loca") < 0 ||
+ seekTable("maxp") < 0 ||
+ seekTable("glyf") < 0 ||
+ seekTable("hmtx") < 0) {
+ error(-1, "TrueType font file is missing a required table");
+ return;
+ }
+
+ // read the 'head' table
+ pos = seekTable("head");
+ bbox[0] = getShort(pos + 36);
+ bbox[1] = getShort(pos + 38);
+ bbox[2] = getShort(pos + 40);
+ bbox[3] = getShort(pos + 42);
+ locaFmt = getShort(pos + 50);
+
+ // read the 'maxp' table
+ pos = seekTable("maxp");
+ nGlyphs = getUShort(pos + 4);
+}
+
+TrueTypeFontFile::~TrueTypeFontFile() {
+ if (encoding && freeEnc) {
+ delete encoding;
+ }
+ gfree(tableHdrs);
+}
+
+char *TrueTypeFontFile::getName() {
+ return NULL;
+}
+
+FontEncoding *TrueTypeFontFile::getEncoding(GBool taken) {
+ int cmap[256];
+ int nCmaps, cmapPlatform, cmapEncoding, cmapFmt, cmapLen, cmapOffset;
+ int segCnt, segStart, segEnd, segDelta, segOffset;
+ int pos, i, j, k;
+ Guint fmt;
+ GString *s;
+ int stringIdx, stringPos, n;
+
+ //----- construct the (char code) -> (glyph idx) mapping
+
+ // map everything to the missing glyph
+ for (i = 0; i < 256; ++i) {
+ cmap[i] = 0;
+ }
+
+ // look for the 'cmap' table
+ if ((pos = seekTable("cmap")) >= 0) {
+ nCmaps = getUShort(pos+2);
+
+ // if the font has a Windows-symbol cmap, use it;
+ // otherwise, use the first cmap in the table
+ for (i = 0; i < nCmaps; ++i) {
+ cmapPlatform = getUShort(pos + 4 + 8*i);
+ cmapEncoding = getUShort(pos + 4 + 8*i + 2);
+ if (cmapPlatform == 3 && cmapEncoding == 0) {
+ break;
+ }
+ }
+ if (i >= nCmaps) {
+ i = 0;
+ cmapPlatform = getUShort(pos + 4);
+ cmapEncoding = getUShort(pos + 4 + 2);
+ }
+ pos += getULong(pos + 4 + 8*i + 4);
+
+ // read the cmap
+ cmapFmt = getUShort(pos);
+ switch (cmapFmt) {
+ case 0: // byte encoding table (Apple standard)
+ cmapLen = getUShort(pos + 2);
+ for (i = 0; i < cmapLen && i < 256; ++i) {
+ cmap[i] = getByte(pos + 6 + i);
+ }
+ break;
+ case 4: // segment mapping to delta values (Microsoft standard)
+ if (cmapPlatform == 3 && cmapEncoding == 0) {
+ // Windows-symbol uses char codes 0xf000 - 0xf0ff
+ cmapOffset = 0xf000;
+ } else {
+ cmapOffset = 0;
+ }
+ segCnt = getUShort(pos + 6) / 2;
+ for (i = 0; i < segCnt; ++i) {
+ segEnd = getUShort(pos + 14 + 2*i);
+ segStart = getUShort(pos + 16 + 2*segCnt + 2*i);
+ segDelta = getUShort(pos + 16 + 4*segCnt + 2*i);
+ segOffset = getUShort(pos + 16 + 6*segCnt + 2*i);
+ if (segStart - cmapOffset <= 0xff &&
+ segEnd - cmapOffset >= 0) {
+ for (j = (segStart - cmapOffset >= 0) ? segStart : cmapOffset;
+ j <= segEnd && j - cmapOffset <= 0xff;
+ ++j) {
+ if (segOffset == 0) {
+ k = (j + segDelta) & 0xffff;
+ } else {
+ k = getUShort(pos + 16 + 6*segCnt + 2*i +
+ segOffset + 2 * (j - segStart));
+ if (k != 0) {
+ k = (k + segDelta) & 0xffff;
+ }
+ }
+ cmap[j - cmapOffset] = k;
+ }
+ }
+ }
+ break;
+ default:
+ error(-1, "Unimplemented cmap type (%d) in TrueType font file",
+ cmapFmt);
+ break;
+ }
+ }
+
+ //----- construct the (glyph idx) -> (glyph name) mapping
+ //----- and compute the (char code) -> (glyph name) mapping
+
+ encoding = new FontEncoding();
+
+ if ((pos = seekTable("post")) >= 0) {
+ fmt = getULong(pos);
+
+ // Apple font
+ if (fmt == 0x00010000) {
+ for (i = 0; i < 256; ++i) {
+ j = (cmap[i] < 258) ? cmap[i] : 0;
+ encoding->addChar(i, copyString(macGlyphNames[j]));
+ }
+
+ // Microsoft font
+ } else if (fmt == 0x00020000) {
+ stringIdx = 0;
+ stringPos = pos + 34 + 2*nGlyphs;
+ for (i = 0; i < 256; ++i) {
+ if (cmap[i] < nGlyphs) {
+ j = getUShort(pos + 34 + 2 * cmap[i]);
+ if (j < 258) {
+ encoding->addChar(i, copyString(macGlyphNames[j]));
+ } else {
+ j -= 258;
+ if (j != stringIdx) {
+ for (stringIdx = 0, stringPos = pos + 34 + 2*nGlyphs;
+ stringIdx < j;
+ ++stringIdx, stringPos += 1 + getByte(stringPos)) ;
+ }
+ n = getByte(stringPos);
+ s = new GString(file + stringPos + 1, n);
+ encoding->addChar(i, copyString(s->getCString()));
+ delete s;
+ ++stringIdx;
+ stringPos += 1 + n;
+ }
+ } else {
+ encoding->addChar(i, copyString(macGlyphNames[0]));
+ }
+ }
+
+ // Apple subset
+ } else if (fmt == 0x000280000) {
+ for (i = 0; i < 256; ++i) {
+ if (cmap[i] < nGlyphs) {
+ j = i + getChar(pos + 32 + cmap[i]);
+ } else {
+ j = 0;
+ }
+ encoding->addChar(i, copyString(macGlyphNames[j]));
+ }
+
+ // Ugh, just assume the Apple glyph set
+ } else {
+ for (i = 0; i < 256; ++i) {
+ j = (cmap[i] < 258) ? cmap[i] : 0;
+ encoding->addChar(i, copyString(macGlyphNames[j]));
+ }
+ }
+
+ // no "post" table: assume the Apple glyph set
+ } else {
+ for (i = 0; i < 256; ++i) {
+ j = (cmap[i] < 258) ? cmap[i] : 0;
+ encoding->addChar(i, copyString(macGlyphNames[j]));
+ }
+ }
+
+ if (taken) {
+ freeEnc = gFalse;
+ }
+ return encoding;
+}
+
+void TrueTypeFontFile::convertToType42(char *name, FontEncoding *encodingA,
+ FILE *out) {
+ // write the header
+ fprintf(out, "%%!PS-TrueTypeFont-%g\n", getFixed(0));
+
+ // begin the font dictionary
+ fprintf(out, "10 dict begin\n");
+ fprintf(out, "/FontName /%s def\n", name);
+ fprintf(out, "/FontType 42 def\n");
+ fprintf(out, "/FontMatrix [1 0 0 1 0 0] def\n");
+ fprintf(out, "/FontBBox [%d %d %d %d] def\n",
+ bbox[0], bbox[1], bbox[2], bbox[3]);
+ fprintf(out, "/PaintType 0 def\n");
+
+ // write the guts of the dictionary
+ cvtEncoding(encodingA, out);
+ cvtCharStrings(encodingA, out);
+ cvtSfnts(out);
+
+ // end the dictionary and define the font
+ fprintf(out, "FontName currentdict end definefont pop\n");
+}
+
+int TrueTypeFontFile::getByte(int pos) {
+ return file[pos] & 0xff;
+}
+
+int TrueTypeFontFile::getChar(int pos) {
+ int x;
+
+ x = file[pos] & 0xff;
+ if (x & 0x80)
+ x |= 0xffffff00;
+ return x;
+}
+
+int TrueTypeFontFile::getUShort(int pos) {
+ int x;
+
+ x = file[pos] & 0xff;
+ x = (x << 8) + (file[pos+1] & 0xff);
+ return x;
+}
+
+int TrueTypeFontFile::getShort(int pos) {
+ int x;
+
+ x = file[pos] & 0xff;
+ x = (x << 8) + (file[pos+1] & 0xff);
+ if (x & 0x8000)
+ x |= 0xffff0000;
+ return x;
+}
+
+Guint TrueTypeFontFile::getULong(int pos) {
+ int x;
+
+ x = file[pos] & 0xff;
+ x = (x << 8) + (file[pos+1] & 0xff);
+ x = (x << 8) + (file[pos+2] & 0xff);
+ x = (x << 8) + (file[pos+3] & 0xff);
+ return x;
+}
+
+double TrueTypeFontFile::getFixed(int pos) {
+ int x, y;
+
+ x = getShort(pos);
+ y = getUShort(pos+2);
+ return (double)x + (double)y / 65536;
+}
+
+int TrueTypeFontFile::seekTable(char *tag) {
+ int i;
+
+ for (i = 0; i < nTables; ++i) {
+ if (!strncmp(tableHdrs[i].tag, tag, 4))
+ return tableHdrs[i].offset;
+ }
+ return -1;
+}
+
+void TrueTypeFontFile::cvtEncoding(FontEncoding *encodingA, FILE *out) {
+ char *name;
+ int i;
+
+ fprintf(out, "/Encoding 256 array\n");
+ for (i = 0; i < 256; ++i) {
+ if (!(name = encodingA->getCharName(i))) {
+ name = ".notdef";
+ }
+ fprintf(out, "dup %d /%s put\n", i, name);
+ }
+ fprintf(out, "readonly def\n");
+}
+
+void TrueTypeFontFile::cvtCharStrings(FontEncoding *encodingA, FILE *out) {
+ int cmap[256];
+ int nCmaps, cmapPlatform, cmapEncoding, cmapFmt, cmapLen, cmapOffset;
+ int segCnt, segStart, segEnd, segDelta, segOffset;
+ char *name;
+ int pos, i, j, k;
+
+ //----- read the cmap: construct the (char code) -> (glyph idx) mapping
+
+ // map everything to the missing glyph
+ for (i = 0; i < 256; ++i) {
+ cmap[i] = 0;
+ }
+
+ // look for the 'cmap' table
+ if ((pos = seekTable("cmap")) >= 0) {
+ nCmaps = getUShort(pos+2);
+
+ // if the font has a Windows-symbol cmap, use it;
+ // otherwise, use the first cmap in the table
+ for (i = 0; i < nCmaps; ++i) {
+ cmapPlatform = getUShort(pos + 4 + 8*i);
+ cmapEncoding = getUShort(pos + 4 + 8*i + 2);
+ if (cmapPlatform == 3 && cmapEncoding == 0) {
+ break;
+ }
+ }
+ if (i >= nCmaps) {
+ i = 0;
+ cmapPlatform = getUShort(pos + 4);
+ cmapEncoding = getUShort(pos + 4 + 2);
+ }
+ pos += getULong(pos + 4 + 8*i + 4);
+
+ // read the cmap
+ cmapFmt = getUShort(pos);
+ switch (cmapFmt) {
+ case 0: // byte encoding table (Apple standard)
+ cmapLen = getUShort(pos + 2);
+ for (i = 0; i < cmapLen && i < 256; ++i) {
+ cmap[i] = getByte(pos + 6 + i);
+ }
+ break;
+ case 4: // segment mapping to delta values (Microsoft standard)
+ if (cmapPlatform == 3 && cmapEncoding == 0) {
+ // Windows-symbol uses char codes 0xf000 - 0xf0ff
+ cmapOffset = 0xf000;
+ } else {
+ cmapOffset = 0;
+ }
+ segCnt = getUShort(pos + 6) / 2;
+ for (i = 0; i < segCnt; ++i) {
+ segEnd = getUShort(pos + 14 + 2*i);
+ segStart = getUShort(pos + 16 + 2*segCnt + 2*i);
+ segDelta = getUShort(pos + 16 + 4*segCnt + 2*i);
+ segOffset = getUShort(pos + 16 + 6*segCnt + 2*i);
+ if (segStart - cmapOffset <= 0xff &&
+ segEnd - cmapOffset >= 0) {
+ for (j = (segStart - cmapOffset >= 0) ? segStart : cmapOffset;
+ j <= segEnd && j - cmapOffset <= 0xff;
+ ++j) {
+ if (segOffset == 0) {
+ k = (j + segDelta) & 0xffff;
+ } else {
+ k = getUShort(pos + 16 + 6*segCnt + 2*i +
+ segOffset + 2 * (j - segStart));
+ if (k != 0) {
+ k = (k + segDelta) & 0xffff;
+ }
+ }
+ cmap[j - cmapOffset] = k;
+ }
+ }
+ }
+ break;
+ default:
+ error(-1, "Unimplemented cmap type (%d) in TrueType font file",
+ cmapFmt);
+ break;
+ }
+ }
+
+ //----- map char code to glyph index
+
+ // 1. use encoding to map name to char code
+ // 2. use cmap to map char code to glyph index
+
+ fprintf(out, "/CharStrings 256 dict dup begin\n");
+ fprintf(out, "/.notdef 0 def\n");
+
+ // kludge: this loop goes backward because the WinAnsi and MacRoman
+ // encodings define certain chars multiple times (space, hyphen,
+ // etc.), and we want the lowest-numbered definition to "stick"
+ // (because the higher-numbered defn(s) may not have valid cmap
+ // entries)
+ i = encodingA->getSize();
+ if (i > 255) {
+ i = 255;
+ }
+ for (; i >= 0; --i) {
+ name = encodingA->getCharName(i);
+ if (name && strcmp(name, ".notdef")) {
+ fprintf(out, "/%s %d def\n", name, cmap[i]);
+ }
+ }
+
+ fprintf(out, "end readonly def\n");
+}
+
+void TrueTypeFontFile::cvtSfnts(FILE *out) {
+ char tableDir[12 + 9*16];
+ int *list;
+ int nTablesOut, pos, destPos, i, j, k1, k2;
+
+ fprintf(out, "/sfnts [\n");
+
+ // count tables
+ nTablesOut = 0;
+ for (i = 0; i < 9; ++i) {
+ for (j = 0; j < nTables; ++j) {
+ if (!strncmp(t42ReqTables[i], tableHdrs[j].tag, 4)) {
+ ++nTablesOut;
+ break;
+ }
+ }
+ }
+
+ // header
+ tableDir[0] = 0x00; // sfnt version
+ tableDir[1] = 0x01;
+ tableDir[2] = 0x00;
+ tableDir[3] = 0x00;
+ tableDir[4] = (nTablesOut >> 8) & 0xff; // numTables
+ tableDir[5] = nTablesOut & 0xff;
+ tableDir[6] = 0; // searchRange
+ tableDir[7] = (char)128;
+ tableDir[8] = 0; // entrySelector
+ tableDir[9] = 3;
+ tableDir[10] = 0; // rangeShift
+ tableDir[11] = 16;
+
+ // table directory
+ pos = 12;
+ destPos = 12 + 16 * nTablesOut;
+ for (i = 0; i < 9; ++i) {
+ for (j = 0; j < nTables; ++j) {
+ if (!strncmp(t42ReqTables[i], tableHdrs[j].tag, 4)) {
+ break;
+ }
+ }
+ if (j < nTables) {
+ memcpy(&tableDir[pos], t42ReqTables[i], 4);
+ tableDir[pos+4] = (tableHdrs[j].checksum >> 24) & 0xff;
+ tableDir[pos+5] = (tableHdrs[j].checksum >> 16) & 0xff;
+ tableDir[pos+6] = (tableHdrs[j].checksum >> 8) & 0xff;
+ tableDir[pos+7] = tableHdrs[j].checksum & 0xff;
+ tableDir[pos+8] = (destPos >> 24) & 0xff;
+ tableDir[pos+9] = (destPos >> 16) & 0xff;
+ tableDir[pos+10] = (destPos >> 8) & 0xff;
+ tableDir[pos+11] = destPos & 0xff;
+ tableDir[pos+12] = (tableHdrs[j].length >> 24) & 0xff;
+ tableDir[pos+13] = (tableHdrs[j].length >> 16) & 0xff;
+ tableDir[pos+14] = (tableHdrs[j].length >> 8) & 0xff;
+ tableDir[pos+15] = tableHdrs[j].length & 0xff;
+ pos += 16;
+ destPos += tableHdrs[j].length;
+ if (tableHdrs[j].length & 3) {
+ destPos += 4 - (tableHdrs[j].length & 3);
+ }
+ }
+ }
+
+ dumpString(tableDir, 12 + 16 * nTablesOut, out);
+
+ for (i = 0; i < 9; ++i) {
+ for (j = 0; j < nTables; ++j) {
+ if (!strncmp(t42ReqTables[i], tableHdrs[j].tag, 4)) {
+ break;
+ }
+ }
+ if (j < nTables) {
+ if (!strcmp(t42ReqTables[i], "glyf") && tableHdrs[j].length > 65532) {
+ // the 'glyf' table won't fit in a single string, and we're only
+ // allowed to break at glyph boundaries
+ list = (int *)gmalloc((nGlyphs + 1) * sizeof(int));
+ pos = seekTable("loca");
+ for (k1 = 0; k1 <= nGlyphs; ++k1) {
+ if (locaFmt) {
+ list[k1] = getULong(pos + 4*k1);
+ } else {
+ list[k1] = 2 * getUShort(pos + 2*k1);
+ }
+ }
+ k1 = 0;
+ while (k1 < nGlyphs) {
+ for (k2 = k1 + 1;
+ k2 < nGlyphs && list[k2+1] - list[k1] <= 65532;
+ ++k2) ;
+ // ghostscript is unhappy if we break at anything other
+ // than a multiple of four bytes
+ while (((list[k2] - list[k1]) & 3) && k2 > k1 + 1) {
+ --k2;
+ }
+ dumpString(file + tableHdrs[j].offset + list[k1],
+ list[k2] - list[k1], out);
+ k1 = k2;
+ }
+ gfree(list);
+ } else {
+ dumpString(file + tableHdrs[j].offset, tableHdrs[j].length, out);
+ }
+ }
+ }
+
+ fprintf(out, "] def\n");
+}
+
+void TrueTypeFontFile::dumpString(char *s, int n, FILE *out) {
+ int i, j;
+
+ fprintf(out, "<");
+ for (i = 0; i < n; i += 32) {
+ for (j = 0; j < 32 && i+j < n; ++j) {
+ fprintf(out, "%02X", s[i+j] & 0xff);
+ }
+ if (i+32 < n) {
+ fprintf(out, "\n");
+ }
+ }
+ if (n & 3) {
+ for (i = 0; i < 4 - (n & 3); ++i) {
+ fprintf(out, "00");
+ }
+ }
+ // append an extra mystery zero byte because the Type 42 spec says so
+ fprintf(out, "00>\n");
+}
diff --git a/pdftops/FontFile.h b/pdftops/FontFile.h
new file mode 100644
index 000000000..b64d827eb
--- /dev/null
+++ b/pdftops/FontFile.h
@@ -0,0 +1,170 @@
+//========================================================================
+//
+// FontFile.h
+//
+// Copyright 1999 Derek B. Noonburg
+//
+//========================================================================
+
+#ifndef FONTFILE_H
+#define FONTFILE_H
+
+#ifdef __GNUC__
+#pragma interface
+#endif
+
+#include <stdio.h>
+#include "gtypes.h"
+#include "GString.h"
+#include "FontEncoding.h"
+
+//------------------------------------------------------------------------
+// FontFile
+//------------------------------------------------------------------------
+
+class FontFile {
+public:
+
+ FontFile();
+ virtual ~FontFile();
+
+ // Returns the font name, as specified internally by the font file.
+ // Returns NULL if no name is available.
+ virtual char *getName() = 0;
+
+ // Returns the custom font encoding, or NULL if the encoding is
+ // not available. If <taken> is set, the caller of this function
+ // will be responsible for freeing the encoding object.
+ virtual FontEncoding *getEncoding(GBool taken) = 0;
+};
+
+//------------------------------------------------------------------------
+// Type1FontFile
+//------------------------------------------------------------------------
+
+class Type1FontFile: public FontFile {
+public:
+
+ Type1FontFile(char *file, int len);
+ virtual ~Type1FontFile();
+ virtual char *getName() { return name; }
+ virtual FontEncoding *getEncoding(GBool taken);
+
+private:
+
+ char *name;
+ FontEncoding *encoding;
+ GBool freeEnc;
+};
+
+//------------------------------------------------------------------------
+// Type1CFontFile
+//------------------------------------------------------------------------
+
+class Type1CFontFile: public FontFile {
+public:
+
+ Type1CFontFile(char *file, int len);
+ virtual ~Type1CFontFile();
+ virtual char *getName() { return name; }
+ virtual FontEncoding *getEncoding(GBool taken);
+
+private:
+
+ char *name;
+ FontEncoding *encoding;
+ GBool freeEnc;
+};
+
+//------------------------------------------------------------------------
+// Type1CFontConverter
+//------------------------------------------------------------------------
+
+class Type1CFontConverter {
+public:
+
+ Type1CFontConverter(char *fileA, int lenA, FILE *outA);
+ ~Type1CFontConverter();
+ void convert();
+
+private:
+
+ void eexecWrite(char *s);
+ void cvtGlyph(char *name, Guchar *s, int n);
+ void cvtGlyphWidth(GBool useOp);
+ void eexecDumpNum(double x, GBool fpA);
+ void eexecDumpOp1(int opA);
+ void eexecDumpOp2(int opA);
+ void eexecWriteCharstring(Guchar *s, int n);
+ void getDeltaInt(char *buf, char *name, double *opA, int n);
+ void getDeltaReal(char *buf, char *name, double *opA, int n);
+
+ char *file;
+ int len;
+ FILE *out;
+ double op[48]; // operands
+ GBool fp[48]; // true if operand is fixed point
+ int nOps; // number of operands
+ double defaultWidthX; // default glyph width
+ double nominalWidthX; // nominal glyph width
+ GBool defaultWidthXFP; // true if defaultWidthX is fixed point
+ GBool nominalWidthXFP; // true if nominalWidthX is fixed point
+ Gushort r1; // eexec encryption key
+ GString *charBuf; // charstring output buffer
+ int line; // number of eexec chars on current line
+};
+
+//------------------------------------------------------------------------
+// TrueTypeFontFile
+//------------------------------------------------------------------------
+
+struct TTFontTableHdr;
+
+class TrueTypeFontFile: public FontFile {
+public:
+
+ TrueTypeFontFile(char *fileA, int lenA);
+ ~TrueTypeFontFile();
+
+ // This always returns NULL, since it's probably better to trust the
+ // font name in the PDF file rather than the one in the TrueType
+ // font file.
+ virtual char *getName();
+
+ virtual FontEncoding *getEncoding(GBool taken);
+
+ // Convert to a Type 42 font, suitable for embedding in a PostScript
+ // file. The name will be used as the PostScript font name (so we
+ // don't need to depend on the 'name' table in the font). The
+ // encoding is needed because the PDF Font object can modify the
+ // encoding.
+ void convertToType42(char *name, FontEncoding *encodingA, FILE *out);
+
+private:
+
+ char *file;
+ int len;
+
+ FontEncoding *encoding;
+ GBool freeEnc;
+
+ TTFontTableHdr *tableHdrs;
+ int nTables;
+ int bbox[4];
+ int locaFmt;
+ int nGlyphs;
+
+ int getByte(int pos);
+ int getChar(int pos);
+ int getUShort(int pos);
+ int getShort(int pos);
+ Guint getULong(int pos);
+ double getFixed(int pos);
+ int seekTable(char *tag);
+ void cvtEncoding(FontEncoding *encodingA, FILE *out);
+ void cvtCharStrings(FontEncoding *encodingA, FILE *out);
+ void cvtSfnts(FILE *out);
+ void dumpString(char *s, int n, FILE *out);
+};
+
+#endif
diff --git a/pdftops/FontInfo.h b/pdftops/FontInfo.h
new file mode 100644
index 000000000..a5b4cced3
--- /dev/null
+++ b/pdftops/FontInfo.h
@@ -0,0 +1,2070 @@
+//========================================================================
+//
+// FontInfo.h
+//
+// This file was automatically generated by makeFontInfo.
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifndef FONTINFO_H
+#define FONTINFO_H
+
+//------------------------------------------------------------------------
+// Character encodings.
+//------------------------------------------------------------------------
+
+#define standardEncodingSize 335
+static char *standardEncodingNames[standardEncodingSize] = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "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",
+ "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",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "exclamdown",
+ "cent",
+ "sterling",
+ "fraction",
+ "yen",
+ "florin",
+ "section",
+ "currency",
+ "quotesingle",
+ "quotedblleft",
+ "guillemotleft",
+ "guilsinglleft",
+ "guilsinglright",
+ "fi",
+ "fl",
+ NULL,
+ "endash",
+ "dagger",
+ "daggerdbl",
+ "periodcentered",
+ NULL,
+ "paragraph",
+ "bullet",
+ "quotesinglbase",
+ "quotedblbase",
+ "quotedblright",
+ "guillemotright",
+ "ellipsis",
+ "perthousand",
+ NULL,
+ "questiondown",
+ NULL,
+ "grave",
+ "acute",
+ "circumflex",
+ "tilde",
+ "macron",
+ "breve",
+ "dotaccent",
+ "dieresis",
+ NULL,
+ "ring",
+ "cedilla",
+ NULL,
+ "hungarumlaut",
+ "ogonek",
+ "caron",
+ "emdash",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "AE",
+ NULL,
+ "ordfeminine",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Lslash",
+ "Oslash",
+ "OE",
+ "ordmasculine",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "ae",
+ NULL,
+ NULL,
+ NULL,
+ "dotlessi",
+ NULL,
+ NULL,
+ "lslash",
+ "oslash",
+ "oe",
+ "germandbls",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Aacute",
+ "Acircumflex",
+ "Adieresis",
+ "Agrave",
+ "Aring",
+ "Atilde",
+ "Ccedilla",
+ "Eacute",
+ "Ecircumflex",
+ "Edieresis",
+ "Egrave",
+ "Eth",
+ "Iacute",
+ "Icircumflex",
+ "Idieresis",
+ "Igrave",
+ "Ntilde",
+ "Oacute",
+ "Ocircumflex",
+ "Odieresis",
+ "Ograve",
+ "Otilde",
+ "Scaron",
+ "Thorn",
+ "Uacute",
+ "Ucircumflex",
+ "Udieresis",
+ "Ugrave",
+ "Yacute",
+ "Ydieresis",
+ "Zcaron",
+ "aacute",
+ "acircumflex",
+ "adieresis",
+ "agrave",
+ "aring",
+ "atilde",
+ "brokenbar",
+ "ccedilla",
+ "copyright",
+ "degree",
+ "divide",
+ "eacute",
+ "ecircumflex",
+ "edieresis",
+ "egrave",
+ "eth",
+ "iacute",
+ "icircumflex",
+ "idieresis",
+ "igrave",
+ "logicalnot",
+ "minus",
+ "mu",
+ "multiply",
+ "ntilde",
+ "oacute",
+ "ocircumflex",
+ "odieresis",
+ "ograve",
+ "onehalf",
+ "onequarter",
+ "onesuperior",
+ "otilde",
+ "plusminus",
+ "registered",
+ "scaron",
+ "thorn",
+ "threequarters",
+ "threesuperior",
+ "trademark",
+ "twosuperior",
+ "uacute",
+ "ucircumflex",
+ "udieresis",
+ "ugrave",
+ "yacute",
+ "ydieresis",
+ "zcaron"
+};
+static FontEncoding standardEncoding(standardEncodingNames,
+ standardEncodingSize);
+
+#define symbolEncodingSize 257
+static char *symbolEncodingNames[symbolEncodingSize] = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "space",
+ "exclam",
+ "universal",
+ "numbersign",
+ "existential",
+ "percent",
+ "ampersand",
+ "suchthat",
+ "parenleft",
+ "parenright",
+ "asteriskmath",
+ "plus",
+ "comma",
+ "minus",
+ "period",
+ "slash",
+ "zero",
+ "one",
+ "two",
+ "three",
+ "four",
+ "five",
+ "six",
+ "seven",
+ "eight",
+ "nine",
+ "colon",
+ "semicolon",
+ "less",
+ "equal",
+ "greater",
+ "question",
+ "congruent",
+ "Alpha",
+ "Beta",
+ "Chi",
+ "Delta",
+ "Epsilon",
+ "Phi",
+ "Gamma",
+ "Eta",
+ "Iota",
+ "theta1",
+ "Kappa",
+ "Lambda",
+ "Mu",
+ "Nu",
+ "Omicron",
+ "Pi",
+ "Theta",
+ "Rho",
+ "Sigma",
+ "Tau",
+ "Upsilon",
+ "sigma1",
+ "Omega",
+ "Xi",
+ "Psi",
+ "Zeta",
+ "bracketleft",
+ "therefore",
+ "bracketright",
+ "perpendicular",
+ "underscore",
+ "radicalex",
+ "alpha",
+ "beta",
+ "chi",
+ "delta",
+ "epsilon",
+ "phi",
+ "gamma",
+ "eta",
+ "iota",
+ "phi1",
+ "kappa",
+ "lambda",
+ "mu",
+ "nu",
+ "omicron",
+ "pi",
+ "theta",
+ "rho",
+ "sigma",
+ "tau",
+ "upsilon",
+ "omega1",
+ "omega",
+ "xi",
+ "psi",
+ "zeta",
+ "braceleft",
+ "bar",
+ "braceright",
+ "similar",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Upsilon1",
+ "minute",
+ "lessequal",
+ "fraction",
+ "infinity",
+ "florin",
+ "club",
+ "diamond",
+ "heart",
+ "spade",
+ "arrowboth",
+ "arrowleft",
+ "arrowup",
+ "arrowright",
+ "arrowdown",
+ "degree",
+ "plusminus",
+ "second",
+ "greaterequal",
+ "multiply",
+ "proportional",
+ "partialdiff",
+ "bullet",
+ "divide",
+ "notequal",
+ "equivalence",
+ "approxequal",
+ "ellipsis",
+ "arrowvertex",
+ "arrowhorizex",
+ "carriagereturn",
+ "aleph",
+ "Ifraktur",
+ "Rfraktur",
+ "weierstrass",
+ "circlemultiply",
+ "circleplus",
+ "emptyset",
+ "intersection",
+ "union",
+ "propersuperset",
+ "reflexsuperset",
+ "notsubset",
+ "propersubset",
+ "reflexsubset",
+ "element",
+ "notelement",
+ "angle",
+ "gradient",
+ "registerserif",
+ "copyrightserif",
+ "trademarkserif",
+ "product",
+ "radical",
+ "dotmath",
+ "logicalnot",
+ "logicaland",
+ "logicalor",
+ "arrowdblboth",
+ "arrowdblleft",
+ "arrowdblup",
+ "arrowdblright",
+ "arrowdbldown",
+ "lozenge",
+ "angleleft",
+ "registersans",
+ "copyrightsans",
+ "trademarksans",
+ "summation",
+ "parenlefttp",
+ "parenleftex",
+ "parenleftbt",
+ "bracketlefttp",
+ "bracketleftex",
+ "bracketleftbt",
+ "bracelefttp",
+ "braceleftmid",
+ "braceleftbt",
+ "braceex",
+ NULL,
+ "angleright",
+ "integral",
+ "integraltp",
+ "integralex",
+ "integralbt",
+ "parenrighttp",
+ "parenrightex",
+ "parenrightbt",
+ "bracketrighttp",
+ "bracketrightex",
+ "bracketrightbt",
+ "bracerighttp",
+ "bracerightmid",
+ "bracerightbt",
+ NULL,
+ "apple"
+};
+static FontEncoding symbolEncoding(symbolEncodingNames,
+ symbolEncodingSize);
+
+#define zapfDingbatsEncodingSize 270
+static char *zapfDingbatsEncodingNames[zapfDingbatsEncodingSize] = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "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",
+ "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",
+ "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",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "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",
+ "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",
+ "a171",
+ "a172",
+ "a173",
+ "a162",
+ "a174",
+ "a175",
+ "a176",
+ "a177",
+ "a178",
+ "a179",
+ "a193",
+ "a180",
+ "a199",
+ "a181",
+ "a200",
+ "a182",
+ NULL,
+ "a201",
+ "a183",
+ "a184",
+ "a197",
+ "a185",
+ "a194",
+ "a198",
+ "a186",
+ "a195",
+ "a187",
+ "a188",
+ "a189",
+ "a190",
+ "a191",
+ NULL,
+ "a205",
+ "a206",
+ "a85",
+ "a86",
+ "a87",
+ "a88",
+ "a89",
+ "a90",
+ "a91",
+ "a92",
+ "a93",
+ "a94",
+ "a95",
+ "a96"
+};
+static FontEncoding zapfDingbatsEncoding(zapfDingbatsEncodingNames,
+ zapfDingbatsEncodingSize);
+
+#define macRomanEncodingSize 256
+static char *macRomanEncodingNames[macRomanEncodingSize] = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "space",
+ "exclam",
+ "quotedbl",
+ "numbersign",
+ "dollar",
+ "percent",
+ "ampersand",
+ "quotesingle",
+ "parenleft",
+ "parenright",
+ "asterisk",
+ "plus",
+ "comma",
+ "hyphen",
+ "period",
+ "slash",
+ "zero",
+ "one",
+ "two",
+ "three",
+ "four",
+ "five",
+ "six",
+ "seven",
+ "eight",
+ "nine",
+ "colon",
+ "semicolon",
+ "less",
+ "equal",
+ "greater",
+ "question",
+ "at",
+ "A",
+ "B",
+ "C",
+ "D",
+ "E",
+ "F",
+ "G",
+ "H",
+ "I",
+ "J",
+ "K",
+ "L",
+ "M",
+ "N",
+ "O",
+ "P",
+ "Q",
+ "R",
+ "S",
+ "T",
+ "U",
+ "V",
+ "W",
+ "X",
+ "Y",
+ "Z",
+ "bracketleft",
+ "backslash",
+ "bracketright",
+ "asciicircum",
+ "underscore",
+ "grave",
+ "a",
+ "b",
+ "c",
+ "d",
+ "e",
+ "f",
+ "g",
+ "h",
+ "i",
+ "j",
+ "k",
+ "l",
+ "m",
+ "n",
+ "o",
+ "p",
+ "q",
+ "r",
+ "s",
+ "t",
+ "u",
+ "v",
+ "w",
+ "x",
+ "y",
+ "z",
+ "braceleft",
+ "bar",
+ "braceright",
+ "asciitilde",
+ NULL,
+ "Adieresis",
+ "Aring",
+ "Ccedilla",
+ "Eacute",
+ "Ntilde",
+ "Odieresis",
+ "Udieresis",
+ "aacute",
+ "agrave",
+ "acircumflex",
+ "adieresis",
+ "atilde",
+ "aring",
+ "ccedilla",
+ "eacute",
+ "egrave",
+ "ecircumflex",
+ "edieresis",
+ "iacute",
+ "igrave",
+ "icircumflex",
+ "idieresis",
+ "ntilde",
+ "oacute",
+ "ograve",
+ "ocircumflex",
+ "odieresis",
+ "otilde",
+ "uacute",
+ "ugrave",
+ "ucircumflex",
+ "udieresis",
+ "dagger",
+ "degree",
+ "cent",
+ "sterling",
+ "section",
+ "bullet",
+ "paragraph",
+ "germandbls",
+ "registered",
+ "copyright",
+ "trademark",
+ "acute",
+ "dieresis",
+ NULL,
+ "AE",
+ "Oslash",
+ NULL,
+ "plusminus",
+ NULL,
+ NULL,
+ "yen",
+ "mu",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "ordfeminine",
+ "ordmasculine",
+ NULL,
+ "ae",
+ "oslash",
+ "questiondown",
+ "exclamdown",
+ "logicalnot",
+ NULL,
+ "florin",
+ NULL,
+ NULL,
+ "guillemotleft",
+ "guillemotright",
+ "ellipsis",
+ "space",
+ "Agrave",
+ "Atilde",
+ "Otilde",
+ "OE",
+ "oe",
+ "endash",
+ "emdash",
+ "quotedblleft",
+ "quotedblright",
+ "quoteleft",
+ "quoteright",
+ "divide",
+ NULL,
+ "ydieresis",
+ "Ydieresis",
+ "fraction",
+ "currency",
+ "guilsinglleft",
+ "guilsinglright",
+ "fi",
+ "fl",
+ "daggerdbl",
+ "periodcentered",
+ "quotesinglbase",
+ "quotedblbase",
+ "perthousand",
+ "Acircumflex",
+ "Ecircumflex",
+ "Aacute",
+ "Edieresis",
+ "Egrave",
+ "Iacute",
+ "Icircumflex",
+ "Idieresis",
+ "Igrave",
+ "Oacute",
+ "Ocircumflex",
+ NULL,
+ "Ograve",
+ "Uacute",
+ "Ucircumflex",
+ "Ugrave",
+ "dotlessi",
+ "circumflex",
+ "tilde",
+ "macron",
+ "breve",
+ "dotaccent",
+ "ring",
+ "cedilla",
+ "hungarumlaut",
+ "ogonek",
+ "caron"
+};
+static FontEncoding macRomanEncoding(macRomanEncodingNames,
+ macRomanEncodingSize);
+
+#define winAnsiEncodingSize 256
+static char *winAnsiEncodingNames[winAnsiEncodingSize] = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "space",
+ "exclam",
+ "quotedbl",
+ "numbersign",
+ "dollar",
+ "percent",
+ "ampersand",
+ "quotesingle",
+ "parenleft",
+ "parenright",
+ "asterisk",
+ "plus",
+ "comma",
+ "hyphen",
+ "period",
+ "slash",
+ "zero",
+ "one",
+ "two",
+ "three",
+ "four",
+ "five",
+ "six",
+ "seven",
+ "eight",
+ "nine",
+ "colon",
+ "semicolon",
+ "less",
+ "equal",
+ "greater",
+ "question",
+ "at",
+ "A",
+ "B",
+ "C",
+ "D",
+ "E",
+ "F",
+ "G",
+ "H",
+ "I",
+ "J",
+ "K",
+ "L",
+ "M",
+ "N",
+ "O",
+ "P",
+ "Q",
+ "R",
+ "S",
+ "T",
+ "U",
+ "V",
+ "W",
+ "X",
+ "Y",
+ "Z",
+ "bracketleft",
+ "backslash",
+ "bracketright",
+ "asciicircum",
+ "underscore",
+ "grave",
+ "a",
+ "b",
+ "c",
+ "d",
+ "e",
+ "f",
+ "g",
+ "h",
+ "i",
+ "j",
+ "k",
+ "l",
+ "m",
+ "n",
+ "o",
+ "p",
+ "q",
+ "r",
+ "s",
+ "t",
+ "u",
+ "v",
+ "w",
+ "x",
+ "y",
+ "z",
+ "braceleft",
+ "bar",
+ "braceright",
+ "asciitilde",
+ "bullet",
+ "Euro",
+ "bullet",
+ "quotesinglbase",
+ "florin",
+ "quotedblbase",
+ "ellipsis",
+ "dagger",
+ "daggerdbl",
+ "circumflex",
+ "perthousand",
+ "Scaron",
+ "guilsinglleft",
+ "OE",
+ "bullet",
+ "bullet",
+ "bullet",
+ "bullet",
+ "quoteleft",
+ "quoteright",
+ "quotedblleft",
+ "quotedblright",
+ "bullet",
+ "endash",
+ "emdash",
+ "tilde",
+ "trademark",
+ "scaron",
+ "guilsinglright",
+ "oe",
+ "bullet",
+ "bullet",
+ "Ydieresis",
+ "space",
+ "exclamdown",
+ "cent",
+ "sterling",
+ "currency",
+ "yen",
+ "brokenbar",
+ "section",
+ "dieresis",
+ "copyright",
+ "ordfeminine",
+ "guillemotleft",
+ "logicalnot",
+ "hyphen",
+ "registered",
+ "macron",
+ "degree",
+ "plusminus",
+ "twosuperior",
+ "threesuperior",
+ "acute",
+ "mu",
+ "paragraph",
+ "periodcentered",
+ "cedilla",
+ "onesuperior",
+ "ordmasculine",
+ "guillemotright",
+ "onequarter",
+ "onehalf",
+ "threequarters",
+ "questiondown",
+ "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",
+ "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"
+};
+static FontEncoding winAnsiEncoding(winAnsiEncodingNames,
+ winAnsiEncodingSize);
+
+//------------------------------------------------------------------------
+// Character widths for built-in fonts.
+//------------------------------------------------------------------------
+
+static Gushort courierWidths[335] = {
+ 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,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 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, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 0, 600, 600, 600, 600, 0, 600, 600,
+ 600, 600, 600, 600, 600, 600, 0, 600,
+ 0, 600, 600, 600, 600, 600, 600, 600,
+ 600, 0, 600, 600, 0, 600, 600, 600,
+ 600, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 600, 0, 600, 0, 0, 0, 0,
+ 600, 600, 600, 600, 0, 0, 0, 0,
+ 0, 600, 0, 0, 0, 600, 0, 0,
+ 600, 600, 600, 600, 0, 0, 0, 0,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600
+};
+
+static Gushort courierBoldWidths[335] = {
+ 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,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 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, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 0, 600, 600, 600, 600, 0, 600, 600,
+ 600, 600, 600, 600, 600, 600, 0, 600,
+ 0, 600, 600, 600, 600, 600, 600, 600,
+ 600, 0, 600, 600, 0, 600, 600, 600,
+ 600, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 600, 0, 600, 0, 0, 0, 0,
+ 600, 600, 600, 600, 0, 0, 0, 0,
+ 0, 600, 0, 0, 0, 600, 0, 0,
+ 600, 600, 600, 600, 0, 0, 0, 0,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600
+};
+
+static Gushort courierBoldObliqueWidths[335] = {
+ 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,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 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, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 0, 600, 600, 600, 600, 0, 600, 600,
+ 600, 600, 600, 600, 600, 600, 0, 600,
+ 0, 600, 600, 600, 600, 600, 600, 600,
+ 600, 0, 600, 600, 0, 600, 600, 600,
+ 600, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 600, 0, 600, 0, 0, 0, 0,
+ 600, 600, 600, 600, 0, 0, 0, 0,
+ 0, 600, 0, 0, 0, 600, 0, 0,
+ 600, 600, 600, 600, 0, 0, 0, 0,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600
+};
+
+static Gushort courierObliqueWidths[335] = {
+ 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,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 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, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 0, 600, 600, 600, 600, 0, 600, 600,
+ 600, 600, 600, 600, 600, 600, 0, 600,
+ 0, 600, 600, 600, 600, 600, 600, 600,
+ 600, 0, 600, 600, 0, 600, 600, 600,
+ 600, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 600, 0, 600, 0, 0, 0, 0,
+ 600, 600, 600, 600, 0, 0, 0, 0,
+ 0, 600, 0, 0, 0, 600, 0, 0,
+ 600, 600, 600, 600, 0, 0, 0, 0,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600
+};
+
+static Gushort helveticaWidths[335] = {
+ 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,
+ 278, 278, 355, 556, 556, 889, 667, 222,
+ 333, 333, 389, 584, 278, 333, 278, 278,
+ 556, 556, 556, 556, 556, 556, 556, 556,
+ 556, 556, 278, 278, 584, 584, 584, 556,
+ 1015, 667, 667, 722, 722, 667, 611, 778,
+ 722, 278, 500, 667, 556, 833, 722, 778,
+ 667, 778, 722, 667, 611, 722, 667, 944,
+ 667, 667, 611, 278, 278, 278, 469, 556,
+ 222, 556, 556, 500, 556, 556, 278, 556,
+ 556, 222, 222, 500, 222, 833, 556, 556,
+ 556, 556, 333, 500, 278, 556, 500, 722,
+ 500, 500, 500, 334, 260, 334, 584, 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, 333, 556, 556, 167, 556, 556, 556,
+ 556, 191, 333, 556, 333, 333, 500, 500,
+ 0, 556, 556, 556, 278, 0, 537, 350,
+ 222, 333, 333, 556, 1000, 1000, 0, 611,
+ 0, 333, 333, 333, 333, 333, 333, 333,
+ 333, 0, 333, 333, 0, 333, 333, 333,
+ 1000, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1000, 0, 370, 0, 0, 0, 0,
+ 556, 778, 1000, 365, 0, 0, 0, 0,
+ 0, 889, 0, 0, 0, 278, 0, 0,
+ 222, 611, 944, 611, 0, 0, 0, 0,
+ 667, 667, 667, 667, 667, 667, 722, 667,
+ 667, 667, 667, 722, 278, 278, 278, 278,
+ 722, 778, 778, 778, 778, 778, 667, 667,
+ 722, 722, 722, 722, 667, 667, 611, 556,
+ 556, 556, 556, 556, 556, 260, 500, 737,
+ 400, 584, 556, 556, 556, 556, 556, 278,
+ 278, 278, 278, 584, 584, 556, 584, 556,
+ 556, 556, 556, 556, 834, 834, 333, 556,
+ 584, 737, 500, 556, 834, 333, 1000, 333,
+ 556, 556, 556, 556, 500, 500, 500
+};
+
+static Gushort helveticaBoldWidths[335] = {
+ 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,
+ 278, 333, 474, 556, 556, 889, 722, 278,
+ 333, 333, 389, 584, 278, 333, 278, 278,
+ 556, 556, 556, 556, 556, 556, 556, 556,
+ 556, 556, 333, 333, 584, 584, 584, 611,
+ 975, 722, 722, 722, 722, 667, 611, 778,
+ 722, 278, 556, 722, 611, 833, 722, 778,
+ 667, 778, 722, 667, 611, 722, 667, 944,
+ 667, 667, 611, 333, 278, 333, 584, 556,
+ 278, 556, 611, 556, 611, 556, 333, 611,
+ 611, 278, 278, 556, 278, 889, 611, 611,
+ 611, 611, 389, 556, 333, 611, 556, 778,
+ 556, 556, 500, 389, 280, 389, 584, 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, 333, 556, 556, 167, 556, 556, 556,
+ 556, 238, 500, 556, 333, 333, 611, 611,
+ 0, 556, 556, 556, 278, 0, 556, 350,
+ 278, 500, 500, 556, 1000, 1000, 0, 611,
+ 0, 333, 333, 333, 333, 333, 333, 333,
+ 333, 0, 333, 333, 0, 333, 333, 333,
+ 1000, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1000, 0, 370, 0, 0, 0, 0,
+ 611, 778, 1000, 365, 0, 0, 0, 0,
+ 0, 889, 0, 0, 0, 278, 0, 0,
+ 278, 611, 944, 611, 0, 0, 0, 0,
+ 722, 722, 722, 722, 722, 722, 722, 667,
+ 667, 667, 667, 722, 278, 278, 278, 278,
+ 722, 778, 778, 778, 778, 778, 667, 667,
+ 722, 722, 722, 722, 667, 667, 611, 556,
+ 556, 556, 556, 556, 556, 280, 556, 737,
+ 400, 584, 556, 556, 556, 556, 611, 278,
+ 278, 278, 278, 584, 584, 611, 584, 611,
+ 611, 611, 611, 611, 834, 834, 333, 611,
+ 584, 737, 556, 611, 834, 333, 1000, 333,
+ 611, 611, 611, 611, 556, 556, 500
+};
+
+static Gushort helveticaBoldObliqueWidths[335] = {
+ 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,
+ 278, 333, 474, 556, 556, 889, 722, 278,
+ 333, 333, 389, 584, 278, 333, 278, 278,
+ 556, 556, 556, 556, 556, 556, 556, 556,
+ 556, 556, 333, 333, 584, 584, 584, 611,
+ 975, 722, 722, 722, 722, 667, 611, 778,
+ 722, 278, 556, 722, 611, 833, 722, 778,
+ 667, 778, 722, 667, 611, 722, 667, 944,
+ 667, 667, 611, 333, 278, 333, 584, 556,
+ 278, 556, 611, 556, 611, 556, 333, 611,
+ 611, 278, 278, 556, 278, 889, 611, 611,
+ 611, 611, 389, 556, 333, 611, 556, 778,
+ 556, 556, 500, 389, 280, 389, 584, 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, 333, 556, 556, 167, 556, 556, 556,
+ 556, 238, 500, 556, 333, 333, 611, 611,
+ 0, 556, 556, 556, 278, 0, 556, 350,
+ 278, 500, 500, 556, 1000, 1000, 0, 611,
+ 0, 333, 333, 333, 333, 333, 333, 333,
+ 333, 0, 333, 333, 0, 333, 333, 333,
+ 1000, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1000, 0, 370, 0, 0, 0, 0,
+ 611, 778, 1000, 365, 0, 0, 0, 0,
+ 0, 889, 0, 0, 0, 278, 0, 0,
+ 278, 611, 944, 611, 0, 0, 0, 0,
+ 722, 722, 722, 722, 722, 722, 722, 667,
+ 667, 667, 667, 722, 278, 278, 278, 278,
+ 722, 778, 778, 778, 778, 778, 667, 667,
+ 722, 722, 722, 722, 667, 667, 611, 556,
+ 556, 556, 556, 556, 556, 280, 556, 737,
+ 400, 584, 556, 556, 556, 556, 611, 278,
+ 278, 278, 278, 584, 584, 611, 584, 611,
+ 611, 611, 611, 611, 834, 834, 333, 611,
+ 584, 737, 556, 611, 834, 333, 1000, 333,
+ 611, 611, 611, 611, 556, 556, 500
+};
+
+static Gushort helveticaObliqueWidths[335] = {
+ 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,
+ 278, 278, 355, 556, 556, 889, 667, 222,
+ 333, 333, 389, 584, 278, 333, 278, 278,
+ 556, 556, 556, 556, 556, 556, 556, 556,
+ 556, 556, 278, 278, 584, 584, 584, 556,
+ 1015, 667, 667, 722, 722, 667, 611, 778,
+ 722, 278, 500, 667, 556, 833, 722, 778,
+ 667, 778, 722, 667, 611, 722, 667, 944,
+ 667, 667, 611, 278, 278, 278, 469, 556,
+ 222, 556, 556, 500, 556, 556, 278, 556,
+ 556, 222, 222, 500, 222, 833, 556, 556,
+ 556, 556, 333, 500, 278, 556, 500, 722,
+ 500, 500, 500, 334, 260, 334, 584, 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, 333, 556, 556, 167, 556, 556, 556,
+ 556, 191, 333, 556, 333, 333, 500, 500,
+ 0, 556, 556, 556, 278, 0, 537, 350,
+ 222, 333, 333, 556, 1000, 1000, 0, 611,
+ 0, 333, 333, 333, 333, 333, 333, 333,
+ 333, 0, 333, 333, 0, 333, 333, 333,
+ 1000, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1000, 0, 370, 0, 0, 0, 0,
+ 556, 778, 1000, 365, 0, 0, 0, 0,
+ 0, 889, 0, 0, 0, 278, 0, 0,
+ 222, 611, 944, 611, 0, 0, 0, 0,
+ 667, 667, 667, 667, 667, 667, 722, 667,
+ 667, 667, 667, 722, 278, 278, 278, 278,
+ 722, 778, 778, 778, 778, 778, 667, 667,
+ 722, 722, 722, 722, 667, 667, 611, 556,
+ 556, 556, 556, 556, 556, 260, 500, 737,
+ 400, 584, 556, 556, 556, 556, 556, 278,
+ 278, 278, 278, 584, 584, 556, 584, 556,
+ 556, 556, 556, 556, 834, 834, 333, 556,
+ 584, 737, 500, 556, 834, 333, 1000, 333,
+ 556, 556, 556, 556, 500, 500, 500
+};
+
+static Gushort symbolWidths[257] = {
+ 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,
+ 250, 333, 713, 500, 549, 833, 778, 439,
+ 333, 333, 500, 549, 250, 549, 250, 278,
+ 500, 500, 500, 500, 500, 500, 500, 500,
+ 500, 500, 278, 278, 549, 549, 549, 444,
+ 549, 722, 667, 722, 612, 611, 763, 603,
+ 722, 333, 631, 722, 686, 889, 722, 722,
+ 768, 741, 556, 592, 611, 690, 439, 768,
+ 645, 795, 611, 333, 863, 333, 658, 500,
+ 500, 631, 549, 549, 494, 439, 521, 411,
+ 603, 329, 603, 549, 549, 576, 521, 549,
+ 549, 521, 549, 603, 439, 576, 713, 686,
+ 493, 686, 494, 480, 200, 480, 549, 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, 620, 247, 549, 167, 713, 500, 753,
+ 753, 753, 753, 1042, 987, 603, 987, 603,
+ 400, 549, 411, 549, 549, 713, 494, 460,
+ 549, 549, 549, 549, 1000, 603, 1000, 658,
+ 823, 686, 795, 987, 768, 768, 823, 768,
+ 768, 713, 713, 713, 713, 713, 713, 713,
+ 768, 713, 790, 790, 890, 823, 549, 250,
+ 713, 603, 603, 1042, 987, 603, 987, 603,
+ 494, 329, 790, 790, 786, 713, 384, 384,
+ 384, 384, 384, 384, 494, 494, 494, 494,
+ 0, 329, 274, 686, 686, 686, 384, 384,
+ 384, 384, 384, 384, 494, 494, 494, 0,
+ 790
+};
+
+static Gushort timesBoldWidths[335] = {
+ 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,
+ 250, 333, 555, 500, 500, 1000, 833, 333,
+ 333, 333, 500, 570, 250, 333, 250, 278,
+ 500, 500, 500, 500, 500, 500, 500, 500,
+ 500, 500, 333, 333, 570, 570, 570, 500,
+ 930, 722, 667, 722, 722, 667, 611, 778,
+ 778, 389, 500, 778, 667, 944, 722, 778,
+ 611, 778, 722, 556, 667, 722, 722, 1000,
+ 722, 722, 667, 333, 278, 333, 581, 500,
+ 333, 500, 556, 444, 556, 444, 333, 500,
+ 556, 278, 333, 556, 278, 833, 556, 500,
+ 556, 556, 444, 389, 333, 556, 500, 722,
+ 500, 500, 444, 394, 220, 394, 520, 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, 333, 500, 500, 167, 500, 500, 500,
+ 500, 278, 500, 500, 333, 333, 556, 556,
+ 0, 500, 500, 500, 250, 0, 540, 350,
+ 333, 500, 500, 500, 1000, 1000, 0, 500,
+ 0, 333, 333, 333, 333, 333, 333, 333,
+ 333, 0, 333, 333, 0, 333, 333, 333,
+ 1000, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1000, 0, 300, 0, 0, 0, 0,
+ 667, 778, 1000, 330, 0, 0, 0, 0,
+ 0, 722, 0, 0, 0, 278, 0, 0,
+ 278, 500, 722, 556, 0, 0, 0, 0,
+ 722, 722, 722, 722, 722, 722, 722, 667,
+ 667, 667, 667, 722, 389, 389, 389, 389,
+ 722, 778, 778, 778, 778, 778, 556, 611,
+ 722, 722, 722, 722, 722, 722, 667, 500,
+ 500, 500, 500, 500, 500, 220, 444, 747,
+ 400, 570, 444, 444, 444, 444, 500, 278,
+ 278, 278, 278, 570, 570, 556, 570, 556,
+ 500, 500, 500, 500, 750, 750, 300, 500,
+ 570, 747, 389, 556, 750, 300, 1000, 300,
+ 556, 556, 556, 556, 500, 500, 444
+};
+
+static Gushort timesBoldItalicWidths[335] = {
+ 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,
+ 250, 389, 555, 500, 500, 833, 778, 333,
+ 333, 333, 500, 570, 250, 333, 250, 278,
+ 500, 500, 500, 500, 500, 500, 500, 500,
+ 500, 500, 333, 333, 570, 570, 570, 500,
+ 832, 667, 667, 667, 722, 667, 667, 722,
+ 778, 389, 500, 667, 611, 889, 722, 722,
+ 611, 722, 667, 556, 611, 722, 667, 889,
+ 667, 611, 611, 333, 278, 333, 570, 500,
+ 333, 500, 500, 444, 500, 444, 333, 500,
+ 556, 278, 278, 500, 278, 778, 556, 500,
+ 500, 500, 389, 389, 278, 556, 444, 667,
+ 500, 444, 389, 348, 220, 348, 570, 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, 389, 500, 500, 167, 500, 500, 500,
+ 500, 278, 500, 500, 333, 333, 556, 556,
+ 0, 500, 500, 500, 250, 0, 500, 350,
+ 333, 500, 500, 500, 1000, 1000, 0, 500,
+ 0, 333, 333, 333, 333, 333, 333, 333,
+ 333, 0, 333, 333, 0, 333, 333, 333,
+ 1000, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 944, 0, 266, 0, 0, 0, 0,
+ 611, 722, 944, 300, 0, 0, 0, 0,
+ 0, 722, 0, 0, 0, 278, 0, 0,
+ 278, 500, 722, 500, 0, 0, 0, 0,
+ 667, 667, 667, 667, 667, 667, 667, 667,
+ 667, 667, 667, 722, 389, 389, 389, 389,
+ 722, 722, 722, 722, 722, 722, 556, 611,
+ 722, 722, 722, 722, 611, 611, 611, 500,
+ 500, 500, 500, 500, 500, 220, 444, 747,
+ 400, 570, 444, 444, 444, 444, 500, 278,
+ 278, 278, 278, 606, 606, 576, 570, 556,
+ 500, 500, 500, 500, 750, 750, 300, 500,
+ 570, 747, 389, 500, 750, 300, 1000, 300,
+ 556, 556, 556, 556, 444, 444, 389
+};
+
+static Gushort timesItalicWidths[335] = {
+ 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,
+ 250, 333, 420, 500, 500, 833, 778, 333,
+ 333, 333, 500, 675, 250, 333, 250, 278,
+ 500, 500, 500, 500, 500, 500, 500, 500,
+ 500, 500, 333, 333, 675, 675, 675, 500,
+ 920, 611, 611, 667, 722, 611, 611, 722,
+ 722, 333, 444, 667, 556, 833, 667, 722,
+ 611, 722, 611, 500, 556, 722, 611, 833,
+ 611, 556, 556, 389, 278, 389, 422, 500,
+ 333, 500, 500, 444, 500, 444, 278, 500,
+ 500, 278, 278, 444, 278, 722, 500, 500,
+ 500, 500, 389, 389, 278, 500, 444, 667,
+ 444, 444, 389, 400, 275, 400, 541, 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, 389, 500, 500, 167, 500, 500, 500,
+ 500, 214, 556, 500, 333, 333, 500, 500,
+ 0, 500, 500, 500, 250, 0, 523, 350,
+ 333, 556, 556, 500, 889, 1000, 0, 500,
+ 0, 333, 333, 333, 333, 333, 333, 333,
+ 333, 0, 333, 333, 0, 333, 333, 333,
+ 889, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 889, 0, 276, 0, 0, 0, 0,
+ 556, 722, 944, 310, 0, 0, 0, 0,
+ 0, 667, 0, 0, 0, 278, 0, 0,
+ 278, 500, 667, 500, 0, 0, 0, 0,
+ 611, 611, 611, 611, 611, 611, 667, 611,
+ 611, 611, 611, 722, 333, 333, 333, 333,
+ 667, 722, 722, 722, 722, 722, 500, 611,
+ 722, 722, 722, 722, 556, 556, 556, 500,
+ 500, 500, 500, 500, 500, 275, 444, 760,
+ 400, 675, 444, 444, 444, 444, 500, 278,
+ 278, 278, 278, 675, 675, 500, 675, 500,
+ 500, 500, 500, 500, 750, 750, 300, 500,
+ 675, 760, 389, 500, 750, 300, 980, 300,
+ 500, 500, 500, 500, 444, 444, 389
+};
+
+static Gushort timesRomanWidths[335] = {
+ 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,
+ 250, 333, 408, 500, 500, 833, 778, 333,
+ 333, 333, 500, 564, 250, 333, 250, 278,
+ 500, 500, 500, 500, 500, 500, 500, 500,
+ 500, 500, 278, 278, 564, 564, 564, 444,
+ 921, 722, 667, 667, 722, 611, 556, 722,
+ 722, 333, 389, 722, 611, 889, 722, 722,
+ 556, 722, 667, 556, 611, 722, 722, 944,
+ 722, 722, 611, 333, 278, 333, 469, 500,
+ 333, 444, 500, 444, 500, 444, 333, 500,
+ 500, 278, 278, 500, 278, 778, 500, 500,
+ 500, 500, 333, 389, 278, 500, 500, 722,
+ 500, 500, 444, 480, 200, 480, 541, 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, 333, 500, 500, 167, 500, 500, 500,
+ 500, 180, 444, 500, 333, 333, 556, 556,
+ 0, 500, 500, 500, 250, 0, 453, 350,
+ 333, 444, 444, 500, 1000, 1000, 0, 444,
+ 0, 333, 333, 333, 333, 333, 333, 333,
+ 333, 0, 333, 333, 0, 333, 333, 333,
+ 1000, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 889, 0, 276, 0, 0, 0, 0,
+ 611, 722, 889, 310, 0, 0, 0, 0,
+ 0, 667, 0, 0, 0, 278, 0, 0,
+ 278, 500, 722, 500, 0, 0, 0, 0,
+ 722, 722, 722, 722, 722, 722, 667, 611,
+ 611, 611, 611, 722, 333, 333, 333, 333,
+ 722, 722, 722, 722, 722, 722, 556, 556,
+ 722, 722, 722, 722, 722, 722, 611, 444,
+ 444, 444, 444, 444, 444, 200, 444, 760,
+ 400, 564, 444, 444, 444, 444, 500, 278,
+ 278, 278, 278, 564, 564, 500, 564, 500,
+ 500, 500, 500, 500, 750, 750, 300, 500,
+ 564, 760, 389, 500, 750, 300, 980, 300,
+ 500, 500, 500, 500, 500, 500, 444
+};
+
+static Gushort zapfDingbatsWidths[270] = {
+ 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,
+ 278, 974, 961, 974, 980, 719, 789, 790,
+ 791, 690, 960, 939, 549, 855, 911, 933,
+ 911, 945, 974, 755, 846, 762, 761, 571,
+ 677, 763, 760, 759, 754, 494, 552, 537,
+ 577, 692, 786, 788, 788, 790, 793, 794,
+ 816, 823, 789, 841, 823, 833, 816, 831,
+ 923, 744, 723, 749, 790, 792, 695, 776,
+ 768, 792, 759, 707, 708, 682, 701, 826,
+ 815, 789, 789, 707, 687, 696, 689, 786,
+ 787, 713, 791, 785, 791, 873, 761, 762,
+ 762, 759, 759, 892, 892, 788, 784, 438,
+ 138, 277, 415, 392, 392, 668, 668, 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, 732, 544, 544, 910, 667, 760, 760,
+ 776, 595, 694, 626, 788, 788, 788, 788,
+ 788, 788, 788, 788, 788, 788, 788, 788,
+ 788, 788, 788, 788, 788, 788, 788, 788,
+ 788, 788, 788, 788, 788, 788, 788, 788,
+ 788, 788, 788, 788, 788, 788, 788, 788,
+ 788, 788, 788, 788, 894, 838, 1016, 458,
+ 748, 924, 748, 918, 927, 928, 928, 834,
+ 873, 828, 924, 924, 917, 930, 931, 463,
+ 883, 836, 836, 867, 867, 696, 696, 874,
+ 0, 874, 760, 946, 771, 865, 771, 888,
+ 967, 888, 831, 873, 927, 970, 918, 0,
+ 509, 410, 509, 410, 234, 234, 390, 390,
+ 276, 276, 317, 317, 334, 334
+};
+
+//------------------------------------------------------------------------
+// Built-in font table.
+//------------------------------------------------------------------------
+
+struct BuiltinFont {
+ char *name;
+ Gushort *widths;
+ FontEncoding *encoding;
+ short ascent;
+ short descent;
+};
+
+#define numBuiltinFonts ((int)(sizeof(builtinFonts)/sizeof(BuiltinFont)))
+
+static BuiltinFont builtinFonts[] = {
+ {"Courier", courierWidths, &standardEncoding, 624, -207},
+ {"Courier-Bold", courierBoldWidths, &standardEncoding, 674, -257},
+ {"Courier-BoldOblique", courierBoldObliqueWidths, &standardEncoding, 674, -257},
+ {"Courier-Oblique", courierObliqueWidths, &standardEncoding, 624, -207},
+ {"Helvetica", helveticaWidths, &standardEncoding, 729, -219},
+ {"Helvetica-Bold", helveticaBoldWidths, &standardEncoding, 729, -219},
+ {"Helvetica-BoldOblique", helveticaBoldObliqueWidths, &standardEncoding, 729, -219},
+ {"Helvetica-Oblique", helveticaObliqueWidths, &standardEncoding, 729, -219},
+ {"Symbol", symbolWidths, &symbolEncoding, 1010, -293},
+ {"Times-Bold", timesBoldWidths, &standardEncoding, 670, -210},
+ {"Times-BoldItalic", timesBoldItalicWidths, &standardEncoding, 682, -203},
+ {"Times-Italic", timesItalicWidths, &standardEncoding, 684, -206},
+ {"Times-Roman", timesRomanWidths, &standardEncoding, 682, -217},
+ {"ZapfDingbats", zapfDingbatsWidths, &zapfDingbatsEncoding, 820, -143}
+};
+
+#endif
diff --git a/pdftops/FormWidget.cxx b/pdftops/FormWidget.cxx
new file mode 100644
index 000000000..a9f8c0693
--- /dev/null
+++ b/pdftops/FormWidget.cxx
@@ -0,0 +1,130 @@
+//========================================================================
+//
+// FormWidget.cc
+//
+// Copyright 2000 Derek B. Noonburg
+//
+//========================================================================
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#include "gmem.h"
+#include "Object.h"
+#include "Gfx.h"
+#include "FormWidget.h"
+
+//------------------------------------------------------------------------
+// FormWidget
+//------------------------------------------------------------------------
+
+FormWidget::FormWidget(XRef *xrefA, Dict *dict) {
+ Object obj1, obj2;
+ double t;
+
+ ok = gFalse;
+ xref = xrefA;
+
+ if (dict->lookup("AP", &obj1)->isDict()) {
+ obj1.dictLookupNF("N", &obj2);
+ //~ this doesn't handle appearances with multiple states --
+ //~ need to look at AS key to get state and then get the
+ //~ corresponding entry from the N dict
+ if (obj2.isRef()) {
+ obj2.copy(&appearance);
+ ok = gTrue;
+ }
+ obj2.free();
+ }
+ obj1.free();
+
+ if (dict->lookup("Rect", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 4) {
+ //~ should check object types here
+ obj1.arrayGet(0, &obj2);
+ xMin = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(1, &obj2);
+ yMin = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(2, &obj2);
+ xMax = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(3, &obj2);
+ yMax = obj2.getNum();
+ obj2.free();
+ if (xMin > xMax) {
+ t = xMin; xMin = xMax; xMax = t;
+ }
+ if (yMin > yMax) {
+ t = yMin; yMin = yMax; yMax = t;
+ }
+ } else {
+ //~ this should return an error
+ xMin = yMin = 0;
+ xMax = yMax = 1;
+ }
+ obj1.free();
+}
+
+FormWidget::~FormWidget() {
+ appearance.free();
+}
+
+void FormWidget::draw(Gfx *gfx) {
+ Object obj;
+
+ if (appearance.fetch(xref, &obj)->isStream()) {
+ gfx->doWidgetForm(&obj, xMin, yMin, xMax, yMax);
+ }
+ obj.free();
+}
+
+//------------------------------------------------------------------------
+// FormWidgets
+//------------------------------------------------------------------------
+
+FormWidgets::FormWidgets(XRef *xref, Object *annots) {
+ FormWidget *widget;
+ Object obj1, obj2;
+ int size;
+ int i;
+
+ widgets = NULL;
+ size = 0;
+ nWidgets = 0;
+
+ if (annots->isArray()) {
+ for (i = 0; i < annots->arrayGetLength(); ++i) {
+ if (annots->arrayGet(i, &obj1)->isDict()) {
+ obj1.dictLookup("Subtype", &obj2);
+ if (obj2.isName("Widget") ||
+ obj2.isName("Stamp")) {
+ widget = new FormWidget(xref, obj1.getDict());
+ if (widget->isOk()) {
+ if (nWidgets >= size) {
+ size += 16;
+ widgets = (FormWidget **)grealloc(widgets,
+ size * sizeof(FormWidget *));
+ }
+ widgets[nWidgets++] = widget;
+ } else {
+ delete widget;
+ }
+ }
+ obj2.free();
+ }
+ obj1.free();
+ }
+ }
+}
+
+FormWidgets::~FormWidgets() {
+ int i;
+
+ for (i = 0; i < nWidgets; ++i) {
+ delete widgets[i];
+ }
+ gfree(widgets);
+}
diff --git a/pdftops/FormWidget.h b/pdftops/FormWidget.h
new file mode 100644
index 000000000..c14421e81
--- /dev/null
+++ b/pdftops/FormWidget.h
@@ -0,0 +1,67 @@
+//========================================================================
+//
+// FormWidget.h
+//
+// Copyright 2000 Derek B. Noonburg
+//
+//========================================================================
+
+#ifndef FORMWIDGET_H
+#define FORMWIDGET_H
+
+#ifdef __GNUC__
+#pragma interface
+#endif
+
+class XRef;
+class Gfx;
+
+//------------------------------------------------------------------------
+// FormWidget
+//------------------------------------------------------------------------
+
+class FormWidget {
+public:
+
+ FormWidget(XRef *xrefA, Dict *dict);
+ ~FormWidget();
+ GBool isOk() { return ok; }
+
+ void draw(Gfx *gfx);
+
+ // Get appearance object.
+ Object *getAppearance(Object *obj) { return appearance.fetch(xref, obj); }
+
+private:
+
+ XRef *xref; // the xref table for this PDF file
+ Object appearance; // a reference to the Form XObject stream
+ // for the normal appearance
+ double xMin, yMin, // widget rectangle
+ xMax, yMax;
+ GBool ok;
+};
+
+//------------------------------------------------------------------------
+// FormWidgets
+//------------------------------------------------------------------------
+
+class FormWidgets {
+public:
+
+ // Extract widgets from array of annotations.
+ FormWidgets(XRef *xref, Object *annots);
+
+ ~FormWidgets();
+
+ // Iterate through list of widgets.
+ int getNumWidgets() { return nWidgets; }
+ FormWidget *getWidget(int i) { return widgets[i]; }
+
+private:
+
+ FormWidget **widgets;
+ int nWidgets;
+};
+
+#endif
diff --git a/pdftops/Function.cxx b/pdftops/Function.cxx
new file mode 100644
index 000000000..d52088808
--- /dev/null
+++ b/pdftops/Function.cxx
@@ -0,0 +1,1373 @@
+//========================================================================
+//
+// Function.cc
+//
+// Copyright 2001 Derek B. Noonburg
+//
+//========================================================================
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include "gmem.h"
+#include "Object.h"
+#include "Dict.h"
+#include "Stream.h"
+#include "Error.h"
+#include "Function.h"
+
+//------------------------------------------------------------------------
+// Function
+//------------------------------------------------------------------------
+
+Function::Function() {
+}
+
+Function::~Function() {
+}
+
+Function *Function::parse(Object *funcObj) {
+ Function *func;
+ Dict *dict;
+ int funcType;
+ Object obj1;
+
+ if (funcObj->isStream()) {
+ dict = funcObj->streamGetDict();
+ } else if (funcObj->isDict()) {
+ dict = funcObj->getDict();
+ } else if (funcObj->isName("Identity")) {
+ return new IdentityFunction();
+ } else {
+ error(-1, "Expected function dictionary or stream");
+ return NULL;
+ }
+
+ if (!dict->lookup("FunctionType", &obj1)->isInt()) {
+ error(-1, "Function type is missing or wrong type");
+ obj1.free();
+ return NULL;
+ }
+ funcType = obj1.getInt();
+ obj1.free();
+
+ if (funcType == 0) {
+ func = new SampledFunction(funcObj, dict);
+ } else if (funcType == 2) {
+ func = new ExponentialFunction(funcObj, dict);
+ } else if (funcType == 4) {
+ func = new PostScriptFunction(funcObj, dict);
+ } else {
+ error(-1, "Unimplemented function type (%d)", funcType);
+ return NULL;
+ }
+ if (!func->isOk()) {
+ delete func;
+ return NULL;
+ }
+
+ return func;
+}
+
+GBool Function::init(Dict *dict) {
+ Object obj1, obj2;
+ int i;
+
+ //----- Domain
+ if (!dict->lookup("Domain", &obj1)->isArray()) {
+ error(-1, "Function is missing domain");
+ goto err2;
+ }
+ m = obj1.arrayGetLength() / 2;
+ if (m > funcMaxInputs) {
+ error(-1, "Functions with more than %d inputs are unsupported",
+ funcMaxInputs);
+ goto err2;
+ }
+ for (i = 0; i < m; ++i) {
+ obj1.arrayGet(2*i, &obj2);
+ if (!obj2.isNum()) {
+ error(-1, "Illegal value in function domain array");
+ goto err1;
+ }
+ domain[i][0] = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(2*i+1, &obj2);
+ if (!obj2.isNum()) {
+ error(-1, "Illegal value in function domain array");
+ goto err1;
+ }
+ domain[i][1] = obj2.getNum();
+ obj2.free();
+ }
+ obj1.free();
+
+ //----- Range
+ hasRange = gFalse;
+ n = 0;
+ if (dict->lookup("Range", &obj1)->isArray()) {
+ hasRange = gTrue;
+ n = obj1.arrayGetLength() / 2;
+ if (n > funcMaxOutputs) {
+ error(-1, "Functions with more than %d outputs are unsupported",
+ funcMaxOutputs);
+ goto err2;
+ }
+ for (i = 0; i < n; ++i) {
+ obj1.arrayGet(2*i, &obj2);
+ if (!obj2.isNum()) {
+ error(-1, "Illegal value in function range array");
+ goto err1;
+ }
+ range[i][0] = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(2*i+1, &obj2);
+ if (!obj2.isNum()) {
+ error(-1, "Illegal value in function range array");
+ goto err1;
+ }
+ range[i][1] = obj2.getNum();
+ obj2.free();
+ }
+ }
+ obj1.free();
+
+ return gTrue;
+
+ err1:
+ obj2.free();
+ err2:
+ obj1.free();
+ return gFalse;
+}
+
+//------------------------------------------------------------------------
+// IdentityFunction
+//------------------------------------------------------------------------
+
+IdentityFunction::IdentityFunction() {
+ int i;
+
+ // fill these in with arbitrary values just in case they get used
+ // somewhere
+ m = funcMaxInputs;
+ n = funcMaxOutputs;
+ for (i = 0; i < funcMaxInputs; ++i) {
+ domain[i][0] = 0;
+ domain[i][1] = 1;
+ }
+ hasRange = gFalse;
+}
+
+IdentityFunction::~IdentityFunction() {
+}
+
+void IdentityFunction::transform(double *in, double *out) {
+ int i;
+
+ for (i = 0; i < funcMaxOutputs; ++i) {
+ out[i] = in[i];
+ }
+}
+
+//------------------------------------------------------------------------
+// SampledFunction
+//------------------------------------------------------------------------
+
+SampledFunction::SampledFunction(Object *funcObj, Dict *dict) {
+ Stream *str;
+ int nSamples, sampleBits;
+ double sampleMul;
+ Object obj1, obj2;
+ Guint buf, bitMask;
+ int bits;
+ int s;
+ int i;
+
+ samples = NULL;
+ ok = gFalse;
+
+ //----- initialize the generic stuff
+ if (!init(dict)) {
+ goto err1;
+ }
+ if (!hasRange) {
+ error(-1, "Type 0 function is missing range");
+ goto err1;
+ }
+
+ //----- get the stream
+ if (!funcObj->isStream()) {
+ error(-1, "Type 0 function isn't a stream");
+ goto err1;
+ }
+ str = funcObj->getStream();
+
+ //----- Size
+ if (!dict->lookup("Size", &obj1)->isArray() ||
+ obj1.arrayGetLength() != m) {
+ error(-1, "Function has missing or invalid size array");
+ goto err2;
+ }
+ for (i = 0; i < m; ++i) {
+ obj1.arrayGet(i, &obj2);
+ if (!obj2.isInt()) {
+ error(-1, "Illegal value in function size array");
+ goto err3;
+ }
+ sampleSize[i] = obj2.getInt();
+ obj2.free();
+ }
+ obj1.free();
+
+ //----- BitsPerSample
+ if (!dict->lookup("BitsPerSample", &obj1)->isInt()) {
+ error(-1, "Function has missing or invalid BitsPerSample");
+ goto err2;
+ }
+ sampleBits = obj1.getInt();
+ sampleMul = 1.0 / (double)((1 << sampleBits) - 1);
+ obj1.free();
+
+ //----- Encode
+ if (dict->lookup("Encode", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 2*m) {
+ for (i = 0; i < m; ++i) {
+ obj1.arrayGet(2*i, &obj2);
+ if (!obj2.isNum()) {
+ error(-1, "Illegal value in function encode array");
+ goto err3;
+ }
+ encode[i][0] = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(2*i+1, &obj2);
+ if (!obj2.isNum()) {
+ error(-1, "Illegal value in function encode array");
+ goto err3;
+ }
+ encode[i][1] = obj2.getNum();
+ obj2.free();
+ }
+ } else {
+ for (i = 0; i < m; ++i) {
+ encode[i][0] = 0;
+ encode[i][1] = sampleSize[i] - 1;
+ }
+ }
+ obj1.free();
+
+ //----- Decode
+ if (dict->lookup("Decode", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 2*n) {
+ for (i = 0; i < n; ++i) {
+ obj1.arrayGet(2*i, &obj2);
+ if (!obj2.isNum()) {
+ error(-1, "Illegal value in function decode array");
+ goto err3;
+ }
+ decode[i][0] = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(2*i+1, &obj2);
+ if (!obj2.isNum()) {
+ error(-1, "Illegal value in function decode array");
+ goto err3;
+ }
+ decode[i][1] = obj2.getNum();
+ obj2.free();
+ }
+ } else {
+ for (i = 0; i < n; ++i) {
+ decode[i][0] = range[i][0];
+ decode[i][1] = range[i][1];
+ }
+ }
+ obj1.free();
+
+ //----- samples
+ nSamples = n;
+ for (i = 0; i < m; ++i)
+ nSamples *= sampleSize[i];
+ samples = (double *)gmalloc(nSamples * sizeof(double));
+ buf = 0;
+ bits = 0;
+ bitMask = (1 << sampleBits) - 1;
+ str->reset();
+ for (i = 0; i < nSamples; ++i) {
+ if (sampleBits == 8) {
+ s = str->getChar();
+ } else if (sampleBits == 16) {
+ s = str->getChar();
+ s = (s << 8) + str->getChar();
+ } else if (sampleBits == 32) {
+ s = str->getChar();
+ s = (s << 8) + str->getChar();
+ s = (s << 8) + str->getChar();
+ s = (s << 8) + str->getChar();
+ } else {
+ while (bits < sampleBits) {
+ buf = (buf << 8) | (str->getChar() & 0xff);
+ bits += 8;
+ }
+ s = (buf >> (bits - sampleBits)) & bitMask;
+ bits -= sampleBits;
+ }
+ samples[i] = (double)s * sampleMul;
+ }
+ str->close();
+
+ ok = gTrue;
+ return;
+
+ err3:
+ obj2.free();
+ err2:
+ obj1.free();
+ err1:
+ return;
+}
+
+SampledFunction::~SampledFunction() {
+ if (samples) {
+ gfree(samples);
+ }
+}
+
+SampledFunction::SampledFunction(SampledFunction *func) {
+ int nSamples, i;
+
+ memcpy(this, func, sizeof(SampledFunction));
+
+ nSamples = n;
+ for (i = 0; i < m; ++i) {
+ nSamples *= sampleSize[i];
+ }
+ samples = (double *)gmalloc(nSamples * sizeof(double));
+ memcpy(samples, func->samples, nSamples * sizeof(double));
+}
+
+void SampledFunction::transform(double *in, double *out) {
+ double x;
+ int e[2][funcMaxInputs];
+ double efrac[funcMaxInputs];
+ double s0[1 << funcMaxInputs], s1[1 << funcMaxInputs];
+ int i, j, k, idx;
+
+ // map input values into sample array
+ for (i = 0; i < m; ++i) {
+ x = ((in[i] - domain[i][0]) / (domain[i][1] - domain[i][0])) *
+ (encode[i][1] - encode[i][0]) + encode[i][0];
+ if (x < 0) {
+ x = 0;
+ } else if (x > sampleSize[i] - 1) {
+ x = sampleSize[i] - 1;
+ }
+ e[0][i] = (int)floor(x);
+ e[1][i] = (int)ceil(x);
+ efrac[i] = x - e[0][i];
+ }
+
+ // for each output, do m-linear interpolation
+ for (i = 0; i < n; ++i) {
+
+ // pull 2^m values out of the sample array
+ for (j = 0; j < (1<<m); ++j) {
+ idx = e[j & 1][m - 1];
+ for (k = m - 2; k >= 0; --k) {
+ idx = idx * sampleSize[k] + e[(j >> k) & 1][k];
+ }
+ idx = idx * n + i;
+ s0[j] = samples[idx];
+ }
+
+ // do m sets of interpolations
+ for (j = 0; j < m; ++j) {
+ for (k = 0; k < (1 << (m - j)); k += 2) {
+ s1[k >> 1] = (1 - efrac[j]) * s0[k] + efrac[j] * s0[k+1];
+ }
+ memcpy(s0, s1, (1 << (m - j - 1)) * sizeof(double));
+ }
+
+ // map output value to range
+ out[i] = s0[0] * (decode[i][1] - decode[i][0]) + decode[i][0];
+ if (out[i] < range[i][0]) {
+ out[i] = range[i][0];
+ } else if (out[i] > range[i][1]) {
+ out[i] = range[i][1];
+ }
+ }
+}
+
+//------------------------------------------------------------------------
+// ExponentialFunction
+//------------------------------------------------------------------------
+
+ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) {
+ Object obj1, obj2;
+ GBool hasN;
+ int i;
+
+ ok = gFalse;
+ hasN = gFalse;
+
+ //----- initialize the generic stuff
+ if (!init(dict)) {
+ goto err1;
+ }
+ if (m != 1) {
+ error(-1, "Exponential function with more than one input");
+ goto err1;
+ }
+
+ //----- default values
+ for (i = 0; i < funcMaxOutputs; ++i) {
+ c0[i] = 0;
+ c1[i] = 1;
+ }
+
+ //----- C0
+ if (dict->lookup("C0", &obj1)->isArray()) {
+ if (!hasN) {
+ n = obj1.arrayGetLength();
+ } else if (obj1.arrayGetLength() != n) {
+ error(-1, "Function's C0 array is wrong length");
+ goto err2;
+ }
+ for (i = 0; i < n; ++i) {
+ obj1.arrayGet(i, &obj2);
+ if (!obj2.isNum()) {
+ error(-1, "Illegal value in function C0 array");
+ goto err3;
+ }
+ c0[i] = obj2.getNum();
+ obj2.free();
+ }
+ }
+ obj1.free();
+
+ //----- C1
+ if (dict->lookup("C1", &obj1)->isArray()) {
+ if (!hasN) {
+ n = obj1.arrayGetLength();
+ } else if (obj1.arrayGetLength() != n) {
+ error(-1, "Function's C1 array is wrong length");
+ goto err2;
+ }
+ for (i = 0; i < n; ++i) {
+ obj1.arrayGet(i, &obj2);
+ if (!obj2.isNum()) {
+ error(-1, "Illegal value in function C1 array");
+ goto err3;
+ }
+ c1[i] = obj2.getNum();
+ obj2.free();
+ }
+ }
+ obj1.free();
+
+ //----- N (exponent)
+ if (!dict->lookup("N", &obj1)->isNum()) {
+ error(-1, "Function has missing or invalid N");
+ goto err2;
+ }
+ e = obj1.getNum();
+ obj1.free();
+
+ ok = gTrue;
+ return;
+
+ err3:
+ obj2.free();
+ err2:
+ obj1.free();
+ err1:
+ return;
+}
+
+ExponentialFunction::~ExponentialFunction() {
+}
+
+ExponentialFunction::ExponentialFunction(ExponentialFunction *func) {
+ memcpy(this, func, sizeof(ExponentialFunction));
+}
+
+void ExponentialFunction::transform(double *in, double *out) {
+ double x;
+ int i;
+
+ if (in[0] < domain[0][0]) {
+ x = domain[0][0];
+ } else if (in[0] > domain[0][1]) {
+ x = domain[0][1];
+ } else {
+ x = in[0];
+ }
+ for (i = 0; i < n; ++i) {
+ out[i] = c0[i] + pow(x, e) * (c1[i] - c0[i]);
+ if (hasRange) {
+ if (out[i] < range[i][0]) {
+ out[i] = range[i][0];
+ } else if (out[i] > range[i][1]) {
+ out[i] = range[i][1];
+ }
+ }
+ }
+ return;
+}
+
+//------------------------------------------------------------------------
+// PostScriptFunction
+//------------------------------------------------------------------------
+
+enum PSOp {
+ psOpAbs,
+ psOpAdd,
+ psOpAnd,
+ psOpAtan,
+ psOpBitshift,
+ psOpCeiling,
+ psOpCopy,
+ psOpCos,
+ psOpCvi,
+ psOpCvr,
+ psOpDiv,
+ psOpDup,
+ psOpEq,
+ psOpExch,
+ psOpExp,
+ psOpFalse,
+ psOpFloor,
+ psOpGe,
+ psOpGt,
+ psOpIdiv,
+ psOpIndex,
+ psOpLe,
+ psOpLn,
+ psOpLog,
+ psOpLt,
+ psOpMod,
+ psOpMul,
+ psOpNe,
+ psOpNeg,
+ psOpNot,
+ psOpOr,
+ psOpPop,
+ psOpRoll,
+ psOpRound,
+ psOpSin,
+ psOpSqrt,
+ psOpSub,
+ psOpTrue,
+ psOpTruncate,
+ psOpXor,
+ psOpIf,
+ psOpIfelse,
+ psOpReturn
+};
+
+// Note: 'if' and 'ifelse' are parsed separately.
+// The rest are listed here in alphabetical order.
+// The index in this table is equivalent to the entry in PSOp.
+char *psOpNames[] = {
+ "abs",
+ "add",
+ "and",
+ "atan",
+ "bitshift",
+ "ceiling",
+ "copy",
+ "cos",
+ "cvi",
+ "cvr",
+ "div",
+ "dup",
+ "eq",
+ "exch",
+ "exp",
+ "false",
+ "floor",
+ "ge",
+ "gt",
+ "idiv",
+ "index",
+ "le",
+ "ln",
+ "log",
+ "lt",
+ "mod",
+ "mul",
+ "ne",
+ "neg",
+ "not",
+ "or",
+ "pop",
+ "roll",
+ "round",
+ "sin",
+ "sqrt",
+ "sub",
+ "true",
+ "truncate",
+ "xor"
+};
+
+#define nPSOps (sizeof(psOpNames) / sizeof(char *))
+
+enum PSObjectType {
+ psBool,
+ psInt,
+ psReal,
+ psOperator,
+ psBlock
+};
+
+// In the code array, 'if'/'ifelse' operators take up three slots
+// plus space for the code in the subclause(s).
+//
+// +---------------------------------+
+// | psOperator: psOpIf / psOpIfelse |
+// +---------------------------------+
+// | psBlock: ptr=<A> |
+// +---------------------------------+
+// | psBlock: ptr=<B> |
+// +---------------------------------+
+// | if clause |
+// | ... |
+// | psOperator: psOpReturn |
+// +---------------------------------+
+// <A> | else clause |
+// | ... |
+// | psOperator: psOpReturn |
+// +---------------------------------+
+// <B> | ... |
+//
+// For 'if', pointer <A> is present in the code stream but unused.
+
+struct PSObject {
+ PSObjectType type;
+ union {
+ GBool booln; // boolean (stack only)
+ int intg; // integer (stack and code)
+ double real; // real (stack and code)
+ PSOp op; // operator (code only)
+ int blk; // if/ifelse block pointer (code only)
+ };
+};
+
+#define psStackSize 100
+
+class PSStack {
+public:
+
+ PSStack() { sp = psStackSize; }
+ void pushBool(GBool booln);
+ void pushInt(int intg);
+ void pushReal(double real);
+ GBool popBool();
+ int popInt();
+ double popNum();
+ GBool empty() { return sp == psStackSize; }
+ GBool topIsInt() { return sp < psStackSize && stack[sp].type == psInt; }
+ GBool topTwoAreInts()
+ { return sp < psStackSize - 1 &&
+ stack[sp].type == psInt &&
+ stack[sp+1].type == psInt; }
+ GBool topIsReal() { return sp < psStackSize && stack[sp].type == psReal; }
+ GBool topTwoAreNums()
+ { return sp < psStackSize - 1 &&
+ (stack[sp].type == psInt || stack[sp].type == psReal) &&
+ (stack[sp+1].type == psInt || stack[sp+1].type == psReal); }
+ void copy(int n);
+ void roll(int n, int j);
+ void index(int i);
+ void pop();
+
+private:
+
+ GBool checkOverflow(int n = 1);
+ GBool checkUnderflow();
+ GBool checkType(PSObjectType t1, PSObjectType t2);
+
+ PSObject stack[psStackSize];
+ int sp;
+};
+
+GBool PSStack::checkOverflow(int n) {
+ if (sp - n < 0) {
+ error(-1, "Stack overflow in PostScript function");
+ return gFalse;
+ }
+ return gTrue;
+}
+
+GBool PSStack::checkUnderflow() {
+ if (sp == psStackSize) {
+ error(-1, "Stack underflow in PostScript function");
+ return gFalse;
+ }
+ return gTrue;
+}
+
+GBool PSStack::checkType(PSObjectType t1, PSObjectType t2) {
+ if (stack[sp].type != t1 && stack[sp].type != t2) {
+ error(-1, "Type mismatch in PostScript function");
+ return gFalse;
+ }
+ return gTrue;
+}
+
+void PSStack::pushBool(GBool booln) {
+ if (checkOverflow()) {
+ stack[--sp].type = psBool;
+ stack[sp].booln = booln;
+ }
+}
+
+void PSStack::pushInt(int intg) {
+ if (checkOverflow()) {
+ stack[--sp].type = psInt;
+ stack[sp].intg = intg;
+ }
+}
+
+void PSStack::pushReal(double real) {
+ if (checkOverflow()) {
+ stack[--sp].type = psReal;
+ stack[sp].real = real;
+ }
+}
+
+GBool PSStack::popBool() {
+ if (checkUnderflow() && checkType(psBool, psBool)) {
+ return stack[sp++].booln;
+ }
+ return gFalse;
+}
+
+int PSStack::popInt() {
+ if (checkUnderflow() && checkType(psInt, psInt)) {
+ return stack[sp++].intg;
+ }
+ return 0;
+}
+
+double PSStack::popNum() {
+ double ret;
+
+ if (checkUnderflow() && checkType(psInt, psReal)) {
+ ret = (stack[sp].type == psInt) ? (double)stack[sp].intg : stack[sp].real;
+ ++sp;
+ return ret;
+ }
+ return 0;
+}
+
+void PSStack::copy(int n) {
+ int i;
+
+ if (!checkOverflow(n)) {
+ return;
+ }
+ for (i = sp + n - 1; i <= sp; ++i) {
+ stack[i - n] = stack[i];
+ }
+ sp -= n;
+}
+
+void PSStack::roll(int n, int j) {
+ PSObject obj;
+ int i, k;
+
+ if (j >= 0) {
+ j %= n;
+ } else {
+ j = -j % n;
+ if (j != 0) {
+ j = n - j;
+ }
+ }
+ if (n <= 0 || j == 0) {
+ return;
+ }
+ for (i = 0; i < j; ++i) {
+ obj = stack[sp];
+ for (k = sp; k < sp + n - 1; ++k) {
+ stack[k] = stack[k+1];
+ }
+ stack[sp + n - 1] = obj;
+ }
+}
+
+void PSStack::index(int i) {
+ if (!checkOverflow()) {
+ return;
+ }
+ --sp;
+ stack[sp] = stack[sp + 1 + i];
+}
+
+void PSStack::pop() {
+ if (!checkUnderflow()) {
+ return;
+ }
+ ++sp;
+}
+
+PostScriptFunction::PostScriptFunction(Object *funcObj, Dict *dict) {
+ Stream *str;
+ int codePtr;
+ GString *tok;
+
+ code = NULL;
+ codeSize = 0;
+ ok = gFalse;
+
+ //----- initialize the generic stuff
+ if (!init(dict)) {
+ goto err1;
+ }
+ if (!hasRange) {
+ error(-1, "Type 4 function is missing range");
+ goto err1;
+ }
+
+ //----- get the stream
+ if (!funcObj->isStream()) {
+ error(-1, "Type 4 function isn't a stream");
+ goto err1;
+ }
+ str = funcObj->getStream();
+
+ //----- parse the function
+ str->reset();
+ if (!(tok = getToken(str)) || tok->cmp("{")) {
+ error(-1, "Expected '{' at start of PostScript function");
+ if (tok) {
+ delete tok;
+ }
+ goto err1;
+ }
+ delete tok;
+ codePtr = 0;
+ if (!parseCode(str, &codePtr)) {
+ goto err2;
+ }
+ str->close();
+
+ ok = gTrue;
+
+ err2:
+ str->close();
+ err1:
+ return;
+}
+
+PostScriptFunction::PostScriptFunction(PostScriptFunction *func) {
+ memcpy(this, func, sizeof(PostScriptFunction));
+ code = (PSObject *)gmalloc(codeSize * sizeof(PSObject));
+ memcpy(code, func->code, codeSize * sizeof(PSObject));
+}
+
+PostScriptFunction::~PostScriptFunction() {
+ gfree(code);
+}
+
+void PostScriptFunction::transform(double *in, double *out) {
+ PSStack *stack;
+ int i;
+
+ stack = new PSStack();
+ for (i = 0; i < m; ++i) {
+ //~ may need to check for integers here
+ stack->pushReal(in[i]);
+ }
+ exec(stack, 0);
+ for (i = n - 1; i >= 0; --i) {
+ out[i] = stack->popNum();
+ if (out[i] < range[i][0]) {
+ out[i] = range[i][0];
+ } else if (out[i] > range[i][1]) {
+ out[i] = range[i][1];
+ }
+ }
+ // if (!stack->empty()) {
+ // error(-1, "Extra values on stack at end of PostScript function");
+ // }
+ delete stack;
+}
+
+GBool PostScriptFunction::parseCode(Stream *str, int *codePtr) {
+ GString *tok;
+ char *p;
+ GBool isReal;
+ int opPtr, elsePtr;
+ int a, b, mid, cmp;
+
+ while (1) {
+ if (!(tok = getToken(str))) {
+ error(-1, "Unexpected end of PostScript function stream");
+ return gFalse;
+ }
+ p = tok->getCString();
+ if (isdigit(*p) || *p == '.' || *p == '-') {
+ isReal = gFalse;
+ for (++p; *p; ++p) {
+ if (*p == '.') {
+ isReal = gTrue;
+ break;
+ }
+ }
+ resizeCode(*codePtr);
+ if (isReal) {
+ code[*codePtr].type = psReal;
+ code[*codePtr].real = atof(tok->getCString());
+ } else {
+ code[*codePtr].type = psInt;
+ code[*codePtr].intg = atoi(tok->getCString());
+ }
+ ++*codePtr;
+ delete tok;
+ } else if (!tok->cmp("{")) {
+ delete tok;
+ opPtr = *codePtr;
+ *codePtr += 3;
+ resizeCode(opPtr + 2);
+ if (!parseCode(str, codePtr)) {
+ return gFalse;
+ }
+ if (!(tok = getToken(str))) {
+ error(-1, "Unexpected end of PostScript function stream");
+ return gFalse;
+ }
+ if (!tok->cmp("{")) {
+ elsePtr = *codePtr;
+ if (!parseCode(str, codePtr)) {
+ return gFalse;
+ }
+ } else {
+ elsePtr = -1;
+ }
+ delete tok;
+ if (!(tok = getToken(str))) {
+ error(-1, "Unexpected end of PostScript function stream");
+ return gFalse;
+ }
+ if (!tok->cmp("if")) {
+ if (elsePtr >= 0) {
+ error(-1, "Got 'if' operator with two blocks in PostScript function");
+ return gFalse;
+ }
+ code[opPtr].type = psOperator;
+ code[opPtr].op = psOpIf;
+ code[opPtr+2].type = psBlock;
+ code[opPtr+2].blk = *codePtr;
+ } else if (!tok->cmp("ifelse")) {
+ if (elsePtr < 0) {
+ error(-1, "Got 'ifelse' operator with one blocks in PostScript function");
+ return gFalse;
+ }
+ code[opPtr].type = psOperator;
+ code[opPtr].op = psOpIfelse;
+ code[opPtr+1].type = psBlock;
+ code[opPtr+1].blk = elsePtr;
+ code[opPtr+2].type = psBlock;
+ code[opPtr+2].blk = *codePtr;
+ } else {
+ error(-1, "Expected if/ifelse operator in PostScript function");
+ delete tok;
+ return gFalse;
+ }
+ delete tok;
+ } else if (!tok->cmp("}")) {
+ delete tok;
+ resizeCode(*codePtr);
+ code[*codePtr].type = psOperator;
+ code[*codePtr].op = psOpReturn;
+ ++*codePtr;
+ break;
+ } else {
+ a = -1;
+ b = nPSOps;
+ // invariant: psOpNames[a] < tok < psOpNames[b]
+ while (b - a > 1) {
+ mid = (a + b) / 2;
+ cmp = tok->cmp(psOpNames[mid]);
+ if (cmp > 0) {
+ a = mid;
+ } else if (cmp < 0) {
+ b = mid;
+ } else {
+ a = b = mid;
+ }
+ }
+ if (cmp != 0) {
+ error(-1, "Unknown operator '%s' in PostScript function",
+ tok->getCString());
+ delete tok;
+ return gFalse;
+ }
+ delete tok;
+ resizeCode(*codePtr);
+ code[*codePtr].type = psOperator;
+ code[*codePtr].op = (PSOp)a;
+ ++*codePtr;
+ }
+ }
+ return gTrue;
+}
+
+GString *PostScriptFunction::getToken(Stream *str) {
+ GString *s;
+ int c;
+
+ s = new GString();
+ do {
+ c = str->getChar();
+ } while (c != EOF && isspace(c));
+ if (c == '{' || c == '}') {
+ s->append((char)c);
+ } else if (isdigit(c) || c == '.' || c == '-') {
+ while (1) {
+ s->append((char)c);
+ c = str->lookChar();
+ if (c == EOF || !(isdigit(c) || c == '.' || c == '-')) {
+ break;
+ }
+ str->getChar();
+ }
+ } else {
+ while (1) {
+ s->append((char)c);
+ c = str->lookChar();
+ if (c == EOF || !isalnum(c)) {
+ break;
+ }
+ str->getChar();
+ }
+ }
+ return s;
+}
+
+void PostScriptFunction::resizeCode(int newSize) {
+ if (newSize >= codeSize) {
+ codeSize += 64;
+ code = (PSObject *)grealloc(code, codeSize * sizeof(PSObject));
+ }
+}
+
+void PostScriptFunction::exec(PSStack *stack, int codePtr) {
+ int i1, i2;
+ double r1, r2;
+ GBool b1, b2;
+
+ while (1) {
+ switch (code[codePtr].type) {
+ case psInt:
+ stack->pushInt(code[codePtr++].intg);
+ break;
+ case psReal:
+ stack->pushReal(code[codePtr++].real);
+ break;
+ case psOperator:
+ switch (code[codePtr++].op) {
+ case psOpAbs:
+ if (stack->topIsInt()) {
+ stack->pushInt(abs(stack->popInt()));
+ } else {
+ stack->pushReal(fabs(stack->popNum()));
+ }
+ break;
+ case psOpAdd:
+ if (stack->topTwoAreInts()) {
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ stack->pushInt(i1 + i2);
+ } else {
+ r2 = stack->popNum();
+ r1 = stack->popNum();
+ stack->pushReal(r1 + r2);
+ }
+ break;
+ case psOpAnd:
+ if (stack->topTwoAreInts()) {
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ stack->pushInt(i1 & i2);
+ } else {
+ b2 = stack->popBool();
+ b1 = stack->popBool();
+ stack->pushReal(b1 && b2);
+ }
+ break;
+ case psOpAtan:
+ r2 = stack->popNum();
+ r1 = stack->popNum();
+ stack->pushReal(atan2(r1, r2));
+ break;
+ case psOpBitshift:
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ if (i2 > 0) {
+ stack->pushInt(i1 << i2);
+ } else if (i2 < 0) {
+ stack->pushInt((int)((Guint)i1 >> i2));
+ } else {
+ stack->pushInt(i1);
+ }
+ break;
+ case psOpCeiling:
+ if (!stack->topIsInt()) {
+ stack->pushReal(ceil(stack->popNum()));
+ }
+ break;
+ case psOpCopy:
+ stack->copy(stack->popInt());
+ break;
+ case psOpCos:
+ stack->pushReal(cos(stack->popNum()));
+ break;
+ case psOpCvi:
+ if (!stack->topIsInt()) {
+ stack->pushInt((int)stack->popNum());
+ }
+ break;
+ case psOpCvr:
+ if (!stack->topIsReal()) {
+ stack->pushReal(stack->popNum());
+ }
+ break;
+ case psOpDiv:
+ r2 = stack->popNum();
+ r1 = stack->popNum();
+ stack->pushReal(r1 / r2);
+ break;
+ case psOpDup:
+ stack->copy(1);
+ break;
+ case psOpEq:
+ if (stack->topTwoAreInts()) {
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ stack->pushBool(i1 == i2);
+ } else if (stack->topTwoAreNums()) {
+ r2 = stack->popNum();
+ r1 = stack->popNum();
+ stack->pushBool(r1 == r2);
+ } else {
+ b2 = stack->popBool();
+ b1 = stack->popBool();
+ stack->pushBool(b1 == b2);
+ }
+ break;
+ case psOpExch:
+ stack->roll(2, 1);
+ break;
+ case psOpExp:
+ r2 = stack->popInt();
+ r1 = stack->popInt();
+ stack->pushReal(pow(r1, r2));
+ break;
+ case psOpFalse:
+ stack->pushBool(gFalse);
+ break;
+ case psOpFloor:
+ if (!stack->topIsInt()) {
+ stack->pushReal(floor(stack->popNum()));
+ }
+ break;
+ case psOpGe:
+ if (stack->topTwoAreInts()) {
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ stack->pushBool(i1 >= i2);
+ } else {
+ r2 = stack->popNum();
+ r1 = stack->popNum();
+ stack->pushBool(r1 >= r2);
+ }
+ break;
+ case psOpGt:
+ if (stack->topTwoAreInts()) {
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ stack->pushBool(i1 > i2);
+ } else {
+ r2 = stack->popNum();
+ r1 = stack->popNum();
+ stack->pushBool(r1 > r2);
+ }
+ break;
+ case psOpIdiv:
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ stack->pushInt(i1 / i2);
+ break;
+ case psOpIndex:
+ stack->index(stack->popInt());
+ break;
+ case psOpLe:
+ if (stack->topTwoAreInts()) {
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ stack->pushBool(i1 <= i2);
+ } else {
+ r2 = stack->popNum();
+ r1 = stack->popNum();
+ stack->pushBool(r1 <= r2);
+ }
+ break;
+ case psOpLn:
+ stack->pushReal(log(stack->popNum()));
+ break;
+ case psOpLog:
+ stack->pushReal(log10(stack->popNum()));
+ break;
+ case psOpLt:
+ if (stack->topTwoAreInts()) {
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ stack->pushBool(i1 < i2);
+ } else {
+ r2 = stack->popNum();
+ r1 = stack->popNum();
+ stack->pushBool(r1 < r2);
+ }
+ break;
+ case psOpMod:
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ stack->pushInt(i1 % i2);
+ break;
+ case psOpMul:
+ if (stack->topTwoAreInts()) {
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ //~ should check for out-of-range, and push a real instead
+ stack->pushInt(i1 * i2);
+ } else {
+ r2 = stack->popNum();
+ r1 = stack->popNum();
+ stack->pushReal(r1 * r2);
+ }
+ break;
+ case psOpNe:
+ if (stack->topTwoAreInts()) {
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ stack->pushBool(i1 != i2);
+ } else if (stack->topTwoAreNums()) {
+ r2 = stack->popNum();
+ r1 = stack->popNum();
+ stack->pushBool(r1 != r2);
+ } else {
+ b2 = stack->popBool();
+ b1 = stack->popBool();
+ stack->pushBool(b1 != b2);
+ }
+ break;
+ case psOpNeg:
+ if (stack->topIsInt()) {
+ stack->pushInt(-stack->popInt());
+ } else {
+ stack->pushReal(-stack->popNum());
+ }
+ break;
+ case psOpNot:
+ if (stack->topIsInt()) {
+ stack->pushInt(~stack->popInt());
+ } else {
+ stack->pushReal(!stack->popBool());
+ }
+ break;
+ case psOpOr:
+ if (stack->topTwoAreInts()) {
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ stack->pushInt(i1 | i2);
+ } else {
+ b2 = stack->popBool();
+ b1 = stack->popBool();
+ stack->pushReal(b1 || b2);
+ }
+ break;
+ case psOpPop:
+ stack->pop();
+ break;
+ case psOpRoll:
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ stack->roll(i1, i2);
+ break;
+ case psOpRound:
+ if (!stack->topIsInt()) {
+ r1 = stack->popNum();
+ stack->pushReal((r1 >= 0) ? floor(r1 + 0.5) : ceil(r1 - 0.5));
+ }
+ break;
+ case psOpSin:
+ stack->pushReal(cos(stack->popNum()));
+ break;
+ case psOpSqrt:
+ stack->pushReal(sqrt(stack->popNum()));
+ break;
+ case psOpSub:
+ if (stack->topTwoAreInts()) {
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ stack->pushInt(i1 - i2);
+ } else {
+ r2 = stack->popNum();
+ r1 = stack->popNum();
+ stack->pushReal(r1 - r2);
+ }
+ break;
+ case psOpTrue:
+ stack->pushBool(gTrue);
+ break;
+ case psOpTruncate:
+ if (!stack->topIsInt()) {
+ r1 = stack->popNum();
+ stack->pushReal((r1 >= 0) ? floor(r1) : ceil(r1));
+ }
+ break;
+ case psOpXor:
+ if (stack->topTwoAreInts()) {
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ stack->pushInt(i1 ^ i2);
+ } else {
+ b2 = stack->popBool();
+ b1 = stack->popBool();
+ stack->pushReal(b1 ^ b2);
+ }
+ break;
+ case psOpIf:
+ b1 = stack->popBool();
+ if (b1) {
+ exec(stack, codePtr + 2);
+ }
+ codePtr = code[codePtr + 1].blk;
+ break;
+ case psOpIfelse:
+ b1 = stack->popBool();
+ if (b1) {
+ exec(stack, codePtr + 2);
+ } else {
+ exec(stack, code[codePtr].blk);
+ }
+ codePtr = code[codePtr + 1].blk;
+ break;
+ case psOpReturn:
+ return;
+ }
+ break;
+ default:
+ error(-1, "Internal: bad object in PostScript function code");
+ break;
+ }
+ }
+}
diff --git a/pdftops/Function.h b/pdftops/Function.h
new file mode 100644
index 000000000..76903488d
--- /dev/null
+++ b/pdftops/Function.h
@@ -0,0 +1,157 @@
+//========================================================================
+//
+// Function.h
+//
+// Copyright 2001 Derek B. Noonburg
+//
+//========================================================================
+
+#ifndef FUNCTION_H
+#define FUNCTION_H
+
+#ifdef __GNUC__
+#pragma interface
+#endif
+
+#include "gtypes.h"
+#include "Object.h"
+
+class Dict;
+class Stream;
+struct PSObject;
+class PSStack;
+
+//------------------------------------------------------------------------
+// Function
+//------------------------------------------------------------------------
+
+#define funcMaxInputs 8
+#define funcMaxOutputs 8
+
+class Function {
+public:
+
+ Function();
+
+ virtual ~Function();
+
+ // Construct a function. Returns NULL if unsuccessful.
+ static Function *parse(Object *funcObj);
+
+ // Initialize the entries common to all function types.
+ GBool init(Dict *dict);
+
+ virtual Function *copy() = 0;
+
+ // Return size of input and output tuples.
+ int getInputSize() { return m; }
+ int getOutputSize() { return n; }
+
+ // Transform an input tuple into an output tuple.
+ virtual void transform(double *in, double *out) = 0;
+
+ virtual GBool isOk() = 0;
+
+protected:
+
+ int m, n; // size of input and output tuples
+ double // min and max values for function domain
+ domain[funcMaxInputs][2];
+ double // min and max values for function range
+ range[funcMaxOutputs][2];
+ GBool hasRange; // set if range is defined
+};
+
+//------------------------------------------------------------------------
+// IdentityFunction
+//------------------------------------------------------------------------
+
+class IdentityFunction: public Function {
+public:
+
+ IdentityFunction();
+ virtual ~IdentityFunction();
+ virtual Function *copy() { return new IdentityFunction(); }
+ virtual void transform(double *in, double *out);
+ virtual GBool isOk() { return gTrue; }
+
+private:
+};
+
+//------------------------------------------------------------------------
+// SampledFunction
+//------------------------------------------------------------------------
+
+class SampledFunction: public Function {
+public:
+
+ SampledFunction(Object *funcObj, Dict *dict);
+ virtual ~SampledFunction();
+ virtual Function *copy() { return new SampledFunction(this); }
+ virtual void transform(double *in, double *out);
+ virtual GBool isOk() { return ok; }
+
+private:
+
+ SampledFunction(SampledFunction *func);
+
+ int // number of samples for each domain element
+ sampleSize[funcMaxInputs];
+ double // min and max values for domain encoder
+ encode[funcMaxInputs][2];
+ double // min and max values for range decoder
+ decode[funcMaxOutputs][2];
+ double *samples; // the samples
+ GBool ok;
+};
+
+//------------------------------------------------------------------------
+// ExponentialFunction
+//------------------------------------------------------------------------
+
+class ExponentialFunction: public Function {
+public:
+
+ ExponentialFunction(Object *funcObj, Dict *dict);
+ virtual ~ExponentialFunction();
+ virtual Function *copy() { return new ExponentialFunction(this); }
+ virtual void transform(double *in, double *out);
+ virtual GBool isOk() { return ok; }
+
+private:
+
+ ExponentialFunction(ExponentialFunction *func);
+
+ double c0[funcMaxOutputs];
+ double c1[funcMaxOutputs];
+ double e;
+ GBool ok;
+};
+
+//------------------------------------------------------------------------
+// PostScriptFunction
+//------------------------------------------------------------------------
+
+class PostScriptFunction: public Function {
+public:
+
+ PostScriptFunction(Object *funcObj, Dict *dict);
+ virtual ~PostScriptFunction();
+ virtual Function *copy() { return new PostScriptFunction(this); }
+ virtual void transform(double *in, double *out);
+ virtual GBool isOk() { return ok; }
+
+private:
+
+ PostScriptFunction(PostScriptFunction *func);
+ GBool parseCode(Stream *str, int *codePtr);
+ GString *getToken(Stream *str);
+ void resizeCode(int newSize);
+ void exec(PSStack *stack, int codePtr);
+
+ PSObject *code;
+ int codeSize;
+ GBool ok;
+};
+
+#endif
diff --git a/pdftops/GB12CMapInfo.h b/pdftops/GB12CMapInfo.h
new file mode 100644
index 000000000..880375737
--- /dev/null
+++ b/pdftops/GB12CMapInfo.h
@@ -0,0 +1,50880 @@
+//========================================================================
+//
+// GB12CMapInfo.h
+//
+// This file was automatically generated by makeCMapInfo.
+//
+// Copyright 1998 Derek B. Noonburg
+//
+//========================================================================
+
+#ifndef GB12CMAPINFO_H
+#define GB12CMAPINFO_H
+
+static Gushort gb12AdobeGB10Map2[66] = {
+ 0x0000, 0x0000,
+ 0x0000, 0x0000,
+ 0x0100, 0x0100,
+ 0x0200, 0x0200,
+ 0x0300, 0x0300,
+ 0x0400, 0x0400,
+ 0x0500, 0x0500,
+ 0x0600, 0x0600,
+ 0x0700, 0x0700,
+ 0x0800, 0x0800,
+ 0x0900, 0x0900,
+ 0x0a00, 0x0a00,
+ 0x0b00, 0x0b00,
+ 0x0c00, 0x0c00,
+ 0x0d00, 0x0d00,
+ 0x0e00, 0x0e00,
+ 0x0f00, 0x0f00,
+ 0x1000, 0x1000,
+ 0x1100, 0x1100,
+ 0x1200, 0x1200,
+ 0x1300, 0x1300,
+ 0x1400, 0x1400,
+ 0x1500, 0x1500,
+ 0x1600, 0x1600,
+ 0x1700, 0x1700,
+ 0x1800, 0x1800,
+ 0x1900, 0x1900,
+ 0x1a00, 0x1a00,
+ 0x1b00, 0x1b00,
+ 0x1c00, 0x1c00,
+ 0x1d00, 0x1d00,
+ 0x1e00, 0x1e00,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 gb12AdobeGB10Enc16 = {
+ 0,
+ { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ gb12AdobeGB10Map2, 33
+};
+
+static Gushort gb12AdobeGB11Map2[82] = {
+ 0x0000, 0x0000,
+ 0x0000, 0x0000,
+ 0x0100, 0x0100,
+ 0x0200, 0x0200,
+ 0x0300, 0x0300,
+ 0x0400, 0x0400,
+ 0x0500, 0x0500,
+ 0x0600, 0x0600,
+ 0x0700, 0x0700,
+ 0x0800, 0x0800,
+ 0x0900, 0x0900,
+ 0x0a00, 0x0a00,
+ 0x0b00, 0x0b00,
+ 0x0c00, 0x0c00,
+ 0x0d00, 0x0d00,
+ 0x0e00, 0x0e00,
+ 0x0f00, 0x0f00,
+ 0x1000, 0x1000,
+ 0x1100, 0x1100,
+ 0x1200, 0x1200,
+ 0x1300, 0x1300,
+ 0x1400, 0x1400,
+ 0x1500, 0x1500,
+ 0x1600, 0x1600,
+ 0x1700, 0x1700,
+ 0x1800, 0x1800,
+ 0x1900, 0x1900,
+ 0x1a00, 0x1a00,
+ 0x1b00, 0x1b00,
+ 0x1c00, 0x1c00,
+ 0x1d00, 0x1d00,
+ 0x1e00, 0x1e00,
+ 0x1f00, 0x1f00,
+ 0x2000, 0x2000,
+ 0x2100, 0x2100,
+ 0x2200, 0x2200,
+ 0x2300, 0x2300,
+ 0x2400, 0x2400,
+ 0x2500, 0x2500,
+ 0x2600, 0x2600,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 gb12AdobeGB11Enc16 = {
+ 0,
+ { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ gb12AdobeGB11Map2, 41
+};
+
+static Gushort gb12AdobeGB12Map2[178] = {
+ 0x0000, 0x0000,
+ 0x0000, 0x0000,
+ 0x0100, 0x0100,
+ 0x0200, 0x0200,
+ 0x0300, 0x0300,
+ 0x0400, 0x0400,
+ 0x0500, 0x0500,
+ 0x0600, 0x0600,
+ 0x0700, 0x0700,
+ 0x0800, 0x0800,
+ 0x0900, 0x0900,
+ 0x0a00, 0x0a00,
+ 0x0b00, 0x0b00,
+ 0x0c00, 0x0c00,
+ 0x0d00, 0x0d00,
+ 0x0e00, 0x0e00,
+ 0x0f00, 0x0f00,
+ 0x1000, 0x1000,
+ 0x1100, 0x1100,
+ 0x1200, 0x1200,
+ 0x1300, 0x1300,
+ 0x1400, 0x1400,
+ 0x1500, 0x1500,
+ 0x1600, 0x1600,
+ 0x1700, 0x1700,
+ 0x1800, 0x1800,
+ 0x1900, 0x1900,
+ 0x1a00, 0x1a00,
+ 0x1b00, 0x1b00,
+ 0x1c00, 0x1c00,
+ 0x1d00, 0x1d00,
+ 0x1e00, 0x1e00,
+ 0x1f00, 0x1f00,
+ 0x2000, 0x2000,
+ 0x2100, 0x2100,
+ 0x2200, 0x2200,
+ 0x2300, 0x2300,
+ 0x2400, 0x2400,
+ 0x2500, 0x2500,
+ 0x2600, 0x2600,
+ 0x2700, 0x2700,
+ 0x2800, 0x2800,
+ 0x2900, 0x2900,
+ 0x2a00, 0x2a00,
+ 0x2b00, 0x2b00,
+ 0x2c00, 0x2c00,
+ 0x2d00, 0x2d00,
+ 0x2e00, 0x2e00,
+ 0x2f00, 0x2f00,
+ 0x3000, 0x3000,
+ 0x3100, 0x3100,
+ 0x3200, 0x3200,
+ 0x3300, 0x3300,
+ 0x3400, 0x3400,
+ 0x3500, 0x3500,
+ 0x3600, 0x3600,
+ 0x3700, 0x3700,
+ 0x3800, 0x3800,
+ 0x3900, 0x3900,
+ 0x3a00, 0x3a00,
+ 0x3b00, 0x3b00,
+ 0x3c00, 0x3c00,
+ 0x3d00, 0x3d00,
+ 0x3e00, 0x3e00,
+ 0x3f00, 0x3f00,
+ 0x4000, 0x4000,
+ 0x4100, 0x4100,
+ 0x4200, 0x4200,
+ 0x4300, 0x4300,
+ 0x4400, 0x4400,
+ 0x4500, 0x4500,
+ 0x4600, 0x4600,
+ 0x4700, 0x4700,
+ 0x4800, 0x4800,
+ 0x4900, 0x4900,
+ 0x4a00, 0x4a00,
+ 0x4b00, 0x4b00,
+ 0x4c00, 0x4c00,
+ 0x4d00, 0x4d00,
+ 0x4e00, 0x4e00,
+ 0x4f00, 0x4f00,
+ 0x5000, 0x5000,
+ 0x5100, 0x5100,
+ 0x5200, 0x5200,
+ 0x5300, 0x5300,
+ 0x5400, 0x5400,
+ 0x5500, 0x5500,
+ 0x5600, 0x5600,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 gb12AdobeGB12Enc16 = {
+ 0,
+ { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ gb12AdobeGB12Map2, 89
+};
+
+static Gushort gb12GBEUCHMap2[180] = {
+ 0x0000, 0x0000,
+ 0xa1a1, 0x0060,
+ 0xa2b1, 0x00be,
+ 0xa2e5, 0x00f0,
+ 0xa2f1, 0x00fa,
+ 0xa3a1, 0x0106,
+ 0xa4a1, 0x0164,
+ 0xa5a1, 0x01b7,
+ 0xa6a1, 0x020d,
+ 0xa6c1, 0x0225,
+ 0xa7a1, 0x025a,
+ 0xa7d1, 0x027b,
+ 0xa8a1, 0x029c,
+ 0xa8c5, 0x02bc,
+ 0xa9a4, 0x02e2,
+ 0xaaa1, 0x032e,
+ 0xaba1, 0x038c,
+ 0xb0a1, 0x03ac,
+ 0xb1a1, 0x040a,
+ 0xb2a1, 0x0468,
+ 0xb3a1, 0x04c6,
+ 0xb4a1, 0x0524,
+ 0xb5a1, 0x0582,
+ 0xb6a1, 0x05e0,
+ 0xb7a1, 0x063e,
+ 0xb8a1, 0x069c,
+ 0xb9a1, 0x06fa,
+ 0xbaa1, 0x0758,
+ 0xbba1, 0x07b6,
+ 0xbca1, 0x0814,
+ 0xbda1, 0x0872,
+ 0xbea1, 0x08d0,
+ 0xbfa1, 0x092e,
+ 0xc0a1, 0x098c,
+ 0xc1a1, 0x09ea,
+ 0xc2a1, 0x0a48,
+ 0xc3a1, 0x0aa6,
+ 0xc4a1, 0x0b04,
+ 0xc5a1, 0x0b62,
+ 0xc6a1, 0x0bc0,
+ 0xc7a1, 0x0c1e,
+ 0xc8a1, 0x0c7c,
+ 0xc9a1, 0x0cda,
+ 0xcaa1, 0x0d38,
+ 0xcba1, 0x0d96,
+ 0xcca1, 0x0df4,
+ 0xcda1, 0x0e52,
+ 0xcea1, 0x0eb0,
+ 0xcfa1, 0x0f0e,
+ 0xd0a1, 0x0f6c,
+ 0xd1a1, 0x0fca,
+ 0xd2a1, 0x1028,
+ 0xd3a1, 0x1086,
+ 0xd4a1, 0x10e4,
+ 0xd5a1, 0x1142,
+ 0xd6a1, 0x11a0,
+ 0xd7a1, 0x11fe,
+ 0xd8a1, 0x1257,
+ 0xd9a1, 0x12b5,
+ 0xdaa1, 0x1313,
+ 0xdba1, 0x1371,
+ 0xdca1, 0x13cf,
+ 0xdda1, 0x142d,
+ 0xdea1, 0x148b,
+ 0xdfa1, 0x14e9,
+ 0xe0a1, 0x1547,
+ 0xe1a1, 0x15a5,
+ 0xe2a1, 0x1603,
+ 0xe3a1, 0x1661,
+ 0xe4a1, 0x16bf,
+ 0xe5a1, 0x171d,
+ 0xe6a1, 0x177b,
+ 0xe7a1, 0x17d9,
+ 0xe8a1, 0x1837,
+ 0xe9a1, 0x1895,
+ 0xeaa1, 0x18f3,
+ 0xeba1, 0x1951,
+ 0xeca1, 0x19af,
+ 0xeda1, 0x1a0d,
+ 0xeea1, 0x1a6b,
+ 0xefa1, 0x1ac9,
+ 0xf0a1, 0x1b27,
+ 0xf1a1, 0x1b85,
+ 0xf2a1, 0x1be3,
+ 0xf3a1, 0x1c41,
+ 0xf4a1, 0x1c9f,
+ 0xf5a1, 0x1cfd,
+ 0xf6a1, 0x1d5b,
+ 0xf7a1, 0x1db9,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 gb12GBEUCHEnc16 = {
+ 0,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x1e24, 0x032e, 0x032f, 0x0330, 0x0331, 0x0332, 0x0333, 0x0334,
+ 0x0335, 0x0336, 0x0337, 0x0338, 0x0339, 0x033a, 0x033b, 0x033c,
+ 0x033d, 0x033e, 0x033f, 0x0340, 0x0341, 0x0342, 0x0343, 0x0344,
+ 0x0345, 0x0346, 0x0347, 0x0348, 0x0349, 0x034a, 0x034b, 0x034c,
+ 0x034d, 0x034e, 0x034f, 0x0350, 0x0351, 0x0352, 0x0353, 0x0354,
+ 0x0355, 0x0356, 0x0357, 0x0358, 0x0359, 0x035a, 0x035b, 0x035c,
+ 0x035d, 0x035e, 0x035f, 0x0360, 0x0361, 0x0362, 0x0363, 0x0364,
+ 0x0365, 0x0366, 0x0367, 0x0368, 0x0369, 0x036a, 0x036b, 0x036c,
+ 0x036d, 0x036e, 0x036f, 0x0370, 0x0371, 0x0372, 0x0373, 0x0374,
+ 0x0375, 0x0376, 0x0377, 0x0378, 0x0379, 0x037a, 0x037b, 0x037c,
+ 0x037d, 0x037e, 0x037f, 0x0380, 0x0381, 0x0382, 0x0383, 0x0384,
+ 0x0385, 0x0386, 0x0387, 0x0388, 0x0389, 0x038a, 0x038b, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ gb12GBEUCHMap2, 90
+};
+
+static Gushort gb12GBEUCVMap2[220] = {
+ 0x0000, 0x0000,
+ 0xa1a1, 0x0060,
+ 0xa2b1, 0x00be,
+ 0xa2e5, 0x00f0,
+ 0xa2f1, 0x00fa,
+ 0xa3a1, 0x0106,
+ 0xa4a1, 0x0164,
+ 0xa5a1, 0x01b7,
+ 0xa6a1, 0x020d,
+ 0xa6c1, 0x0225,
+ 0xa7a1, 0x025a,
+ 0xa7d1, 0x027b,
+ 0xa8a1, 0x029c,
+ 0xa8c5, 0x02bc,
+ 0xa9a4, 0x02e2,
+ 0xaaa1, 0x032e,
+ 0xaba1, 0x038c,
+ 0xb0a1, 0x03ac,
+ 0xb1a1, 0x040a,
+ 0xb2a1, 0x0468,
+ 0xb3a1, 0x04c6,
+ 0xb4a1, 0x0524,
+ 0xb5a1, 0x0582,
+ 0xb6a1, 0x05e0,
+ 0xb7a1, 0x063e,
+ 0xb8a1, 0x069c,
+ 0xb9a1, 0x06fa,
+ 0xbaa1, 0x0758,
+ 0xbba1, 0x07b6,
+ 0xbca1, 0x0814,
+ 0xbda1, 0x0872,
+ 0xbea1, 0x08d0,
+ 0xbfa1, 0x092e,
+ 0xc0a1, 0x098c,
+ 0xc1a1, 0x09ea,
+ 0xc2a1, 0x0a48,
+ 0xc3a1, 0x0aa6,
+ 0xc4a1, 0x0b04,
+ 0xc5a1, 0x0b62,
+ 0xc6a1, 0x0bc0,
+ 0xc7a1, 0x0c1e,
+ 0xc8a1, 0x0c7c,
+ 0xc9a1, 0x0cda,
+ 0xcaa1, 0x0d38,
+ 0xcba1, 0x0d96,
+ 0xcca1, 0x0df4,
+ 0xcda1, 0x0e52,
+ 0xcea1, 0x0eb0,
+ 0xcfa1, 0x0f0e,
+ 0xd0a1, 0x0f6c,
+ 0xd1a1, 0x0fca,
+ 0xd2a1, 0x1028,
+ 0xd3a1, 0x1086,
+ 0xd4a1, 0x10e4,
+ 0xd5a1, 0x1142,
+ 0xd6a1, 0x11a0,
+ 0xd7a1, 0x11fe,
+ 0xd8a1, 0x1257,
+ 0xd9a1, 0x12b5,
+ 0xdaa1, 0x1313,
+ 0xdba1, 0x1371,
+ 0xdca1, 0x13cf,
+ 0xdda1, 0x142d,
+ 0xdea1, 0x148b,
+ 0xdfa1, 0x14e9,
+ 0xe0a1, 0x1547,
+ 0xe1a1, 0x15a5,
+ 0xe2a1, 0x1603,
+ 0xe3a1, 0x1661,
+ 0xe4a1, 0x16bf,
+ 0xe5a1, 0x171d,
+ 0xe6a1, 0x177b,
+ 0xe7a1, 0x17d9,
+ 0xe8a1, 0x1837,
+ 0xe9a1, 0x1895,
+ 0xeaa1, 0x18f3,
+ 0xeba1, 0x1951,
+ 0xeca1, 0x19af,
+ 0xeda1, 0x1a0d,
+ 0xeea1, 0x1a6b,
+ 0xefa1, 0x1ac9,
+ 0xf0a1, 0x1b27,
+ 0xf1a1, 0x1b85,
+ 0xf2a1, 0x1be3,
+ 0xf3a1, 0x1c41,
+ 0xf4a1, 0x1c9f,
+ 0xf5a1, 0x1cfd,
+ 0xf6a1, 0x1d5b,
+ 0xf7a1, 0x1db9,
+ 0xa1a2, 0x023f,
+ 0xa1a3, 0x023e,
+ 0xa1aa, 0x0256,
+ 0xa1ab, 0x1e18,
+ 0xa1ad, 0x0257,
+ 0xa1b2, 0x0246,
+ 0xa1fe, 0x1e1a,
+ 0xa3a1, 0x0242,
+ 0xa3a8, 0x0244,
+ 0xa3ac, 0x023d,
+ 0xa3ae, 0x1e1b,
+ 0xa3ba, 0x0240,
+ 0xa3bd, 0x1e1c,
+ 0xa3bf, 0x0243,
+ 0xa3db, 0x1e1d,
+ 0xa3dd, 0x1e1e,
+ 0xa3df, 0x0258,
+ 0xa3fb, 0x0254,
+ 0xa3fd, 0x0255,
+ 0xa3fe, 0x1e1f,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 gb12GBEUCVEnc16 = {
+ 1,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x1e24, 0x032e, 0x032f, 0x0330, 0x0331, 0x0332, 0x0333, 0x0334,
+ 0x0335, 0x0336, 0x0337, 0x0338, 0x0339, 0x033a, 0x033b, 0x033c,
+ 0x033d, 0x033e, 0x033f, 0x0340, 0x0341, 0x0342, 0x0343, 0x0344,
+ 0x0345, 0x0346, 0x0347, 0x0348, 0x0349, 0x034a, 0x034b, 0x034c,
+ 0x034d, 0x034e, 0x034f, 0x0350, 0x0351, 0x0352, 0x0353, 0x0354,
+ 0x0355, 0x0356, 0x0357, 0x0358, 0x0359, 0x035a, 0x035b, 0x035c,
+ 0x035d, 0x035e, 0x035f, 0x0360, 0x0361, 0x0362, 0x0363, 0x0364,
+ 0x0365, 0x0366, 0x0367, 0x0368, 0x0369, 0x036a, 0x036b, 0x036c,
+ 0x036d, 0x036e, 0x036f, 0x0370, 0x0371, 0x0372, 0x0373, 0x0374,
+ 0x0375, 0x0376, 0x0377, 0x0378, 0x0379, 0x037a, 0x037b, 0x037c,
+ 0x037d, 0x037e, 0x037f, 0x0380, 0x0381, 0x0382, 0x0383, 0x0384,
+ 0x0385, 0x0386, 0x0387, 0x0388, 0x0389, 0x038a, 0x038b, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ gb12GBEUCVMap2, 110
+};
+
+static Gushort gb12GBHMap2[180] = {
+ 0x0000, 0x0000,
+ 0x2121, 0x0060,
+ 0x2231, 0x00be,
+ 0x2265, 0x00f0,
+ 0x2271, 0x00fa,
+ 0x2321, 0x0106,
+ 0x2421, 0x0164,
+ 0x2521, 0x01b7,
+ 0x2621, 0x020d,
+ 0x2641, 0x0225,
+ 0x2721, 0x025a,
+ 0x2751, 0x027b,
+ 0x2821, 0x029c,
+ 0x2845, 0x02bc,
+ 0x2924, 0x02e2,
+ 0x2a21, 0x032e,
+ 0x2b21, 0x038c,
+ 0x3021, 0x03ac,
+ 0x3121, 0x040a,
+ 0x3221, 0x0468,
+ 0x3321, 0x04c6,
+ 0x3421, 0x0524,
+ 0x3521, 0x0582,
+ 0x3621, 0x05e0,
+ 0x3721, 0x063e,
+ 0x3821, 0x069c,
+ 0x3921, 0x06fa,
+ 0x3a21, 0x0758,
+ 0x3b21, 0x07b6,
+ 0x3c21, 0x0814,
+ 0x3d21, 0x0872,
+ 0x3e21, 0x08d0,
+ 0x3f21, 0x092e,
+ 0x4021, 0x098c,
+ 0x4121, 0x09ea,
+ 0x4221, 0x0a48,
+ 0x4321, 0x0aa6,
+ 0x4421, 0x0b04,
+ 0x4521, 0x0b62,
+ 0x4621, 0x0bc0,
+ 0x4721, 0x0c1e,
+ 0x4821, 0x0c7c,
+ 0x4921, 0x0cda,
+ 0x4a21, 0x0d38,
+ 0x4b21, 0x0d96,
+ 0x4c21, 0x0df4,
+ 0x4d21, 0x0e52,
+ 0x4e21, 0x0eb0,
+ 0x4f21, 0x0f0e,
+ 0x5021, 0x0f6c,
+ 0x5121, 0x0fca,
+ 0x5221, 0x1028,
+ 0x5321, 0x1086,
+ 0x5421, 0x10e4,
+ 0x5521, 0x1142,
+ 0x5621, 0x11a0,
+ 0x5721, 0x11fe,
+ 0x5821, 0x1257,
+ 0x5921, 0x12b5,
+ 0x5a21, 0x1313,
+ 0x5b21, 0x1371,
+ 0x5c21, 0x13cf,
+ 0x5d21, 0x142d,
+ 0x5e21, 0x148b,
+ 0x5f21, 0x14e9,
+ 0x6021, 0x1547,
+ 0x6121, 0x15a5,
+ 0x6221, 0x1603,
+ 0x6321, 0x1661,
+ 0x6421, 0x16bf,
+ 0x6521, 0x171d,
+ 0x6621, 0x177b,
+ 0x6721, 0x17d9,
+ 0x6821, 0x1837,
+ 0x6921, 0x1895,
+ 0x6a21, 0x18f3,
+ 0x6b21, 0x1951,
+ 0x6c21, 0x19af,
+ 0x6d21, 0x1a0d,
+ 0x6e21, 0x1a6b,
+ 0x6f21, 0x1ac9,
+ 0x7021, 0x1b27,
+ 0x7121, 0x1b85,
+ 0x7221, 0x1be3,
+ 0x7321, 0x1c41,
+ 0x7421, 0x1c9f,
+ 0x7521, 0x1cfd,
+ 0x7621, 0x1d5b,
+ 0x7721, 0x1db9,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 gb12GBHEnc16 = {
+ 0,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ gb12GBHMap2, 90
+};
+
+static Gushort gb12GBVMap2[220] = {
+ 0x0000, 0x0000,
+ 0x2121, 0x0060,
+ 0x2231, 0x00be,
+ 0x2265, 0x00f0,
+ 0x2271, 0x00fa,
+ 0x2321, 0x0106,
+ 0x2421, 0x0164,
+ 0x2521, 0x01b7,
+ 0x2621, 0x020d,
+ 0x2641, 0x0225,
+ 0x2721, 0x025a,
+ 0x2751, 0x027b,
+ 0x2821, 0x029c,
+ 0x2845, 0x02bc,
+ 0x2924, 0x02e2,
+ 0x2a21, 0x032e,
+ 0x2b21, 0x038c,
+ 0x3021, 0x03ac,
+ 0x3121, 0x040a,
+ 0x3221, 0x0468,
+ 0x3321, 0x04c6,
+ 0x3421, 0x0524,
+ 0x3521, 0x0582,
+ 0x3621, 0x05e0,
+ 0x3721, 0x063e,
+ 0x3821, 0x069c,
+ 0x3921, 0x06fa,
+ 0x3a21, 0x0758,
+ 0x3b21, 0x07b6,
+ 0x3c21, 0x0814,
+ 0x3d21, 0x0872,
+ 0x3e21, 0x08d0,
+ 0x3f21, 0x092e,
+ 0x4021, 0x098c,
+ 0x4121, 0x09ea,
+ 0x4221, 0x0a48,
+ 0x4321, 0x0aa6,
+ 0x4421, 0x0b04,
+ 0x4521, 0x0b62,
+ 0x4621, 0x0bc0,
+ 0x4721, 0x0c1e,
+ 0x4821, 0x0c7c,
+ 0x4921, 0x0cda,
+ 0x4a21, 0x0d38,
+ 0x4b21, 0x0d96,
+ 0x4c21, 0x0df4,
+ 0x4d21, 0x0e52,
+ 0x4e21, 0x0eb0,
+ 0x4f21, 0x0f0e,
+ 0x5021, 0x0f6c,
+ 0x5121, 0x0fca,
+ 0x5221, 0x1028,
+ 0x5321, 0x1086,
+ 0x5421, 0x10e4,
+ 0x5521, 0x1142,
+ 0x5621, 0x11a0,
+ 0x5721, 0x11fe,
+ 0x5821, 0x1257,
+ 0x5921, 0x12b5,
+ 0x5a21, 0x1313,
+ 0x5b21, 0x1371,
+ 0x5c21, 0x13cf,
+ 0x5d21, 0x142d,
+ 0x5e21, 0x148b,
+ 0x5f21, 0x14e9,
+ 0x6021, 0x1547,
+ 0x6121, 0x15a5,
+ 0x6221, 0x1603,
+ 0x6321, 0x1661,
+ 0x6421, 0x16bf,
+ 0x6521, 0x171d,
+ 0x6621, 0x177b,
+ 0x6721, 0x17d9,
+ 0x6821, 0x1837,
+ 0x6921, 0x1895,
+ 0x6a21, 0x18f3,
+ 0x6b21, 0x1951,
+ 0x6c21, 0x19af,
+ 0x6d21, 0x1a0d,
+ 0x6e21, 0x1a6b,
+ 0x6f21, 0x1ac9,
+ 0x7021, 0x1b27,
+ 0x7121, 0x1b85,
+ 0x7221, 0x1be3,
+ 0x7321, 0x1c41,
+ 0x7421, 0x1c9f,
+ 0x7521, 0x1cfd,
+ 0x7621, 0x1d5b,
+ 0x7721, 0x1db9,
+ 0x2122, 0x023f,
+ 0x2123, 0x023e,
+ 0x212a, 0x0256,
+ 0x212b, 0x1e18,
+ 0x212d, 0x0257,
+ 0x2132, 0x0246,
+ 0x217e, 0x1e1a,
+ 0x2321, 0x0242,
+ 0x2328, 0x0244,
+ 0x232c, 0x023d,
+ 0x232e, 0x1e1b,
+ 0x233a, 0x0240,
+ 0x233d, 0x1e1c,
+ 0x233f, 0x0243,
+ 0x235b, 0x1e1d,
+ 0x235d, 0x1e1e,
+ 0x235f, 0x0258,
+ 0x237b, 0x0254,
+ 0x237d, 0x0255,
+ 0x237e, 0x1e1f,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 gb12GBVEnc16 = {
+ 1,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ gb12GBVMap2, 110
+};
+
+static Gushort gb12GBKEUCHMap2[8142] = {
+ 0x0000, 0x0000,
+ 0x8140, 0x2758,
+ 0x8179, 0x2059,
+ 0x817a, 0x2791,
+ 0x8180, 0x2796,
+ 0x8186, 0x21f1,
+ 0x8187, 0x279c,
+ 0x81ed, 0x1ff2,
+ 0x81ee, 0x2802,
+ 0x81f6, 0x205d,
+ 0x81f7, 0x280a,
+ 0x8240, 0x2812,
+ 0x8253, 0x269c,
+ 0x8254, 0x2825,
+ 0x8262, 0x21b5,
+ 0x8263, 0x2833,
+ 0x8274, 0x22cc,
+ 0x8275, 0x2844,
+ 0x827a, 0x2016,
+ 0x827b, 0x2849,
+ 0x827d, 0x1e62,
+ 0x827e, 0x284b,
+ 0x8280, 0x1f20,
+ 0x8281, 0x284c,
+ 0x8283, 0x207f,
+ 0x8284, 0x284e,
+ 0x8290, 0x205c,
+ 0x8291, 0x285a,
+ 0x82a5, 0x2194,
+ 0x82a6, 0x286e,
+ 0x82c8, 0x1e65,
+ 0x82c9, 0x2281,
+ 0x82ca, 0x2890,
+ 0x82e1, 0x22cd,
+ 0x82e2, 0x28a7,
+ 0x82e3, 0x210a,
+ 0x82e4, 0x1e3e,
+ 0x82e5, 0x28a8,
+ 0x82ed, 0x267f,
+ 0x82ee, 0x28b0,
+ 0x82f2, 0x222e,
+ 0x82f3, 0x28b4,
+ 0x82f7, 0x1e96,
+ 0x82f8, 0x22cb,
+ 0x82f9, 0x226c,
+ 0x82fa, 0x28b8,
+ 0x82fb, 0x2117,
+ 0x82fc, 0x28b9,
+ 0x8340, 0x28bc,
+ 0x8341, 0x20e8,
+ 0x8342, 0x28bd,
+ 0x8345, 0x22d4,
+ 0x8346, 0x28c0,
+ 0x8348, 0x1fb9,
+ 0x8349, 0x28c2,
+ 0x834c, 0x22d8,
+ 0x834d, 0x28c5,
+ 0x8353, 0x20df,
+ 0x8354, 0x28cb,
+ 0x8357, 0x20c2,
+ 0x8358, 0x28ce,
+ 0x835e, 0x2195,
+ 0x835f, 0x28d4,
+ 0x8365, 0x1fac,
+ 0x8366, 0x22d3,
+ 0x8367, 0x28da,
+ 0x8372, 0x1f81,
+ 0x8373, 0x28e5,
+ 0x8378, 0x2210,
+ 0x8379, 0x28ea,
+ 0x837a, 0x22cf,
+ 0x837b, 0x28eb,
+ 0x837c, 0x2213,
+ 0x837d, 0x28ec,
+ 0x837e, 0x1fe4,
+ 0x8380, 0x1f90,
+ 0x8381, 0x28ed,
+ 0x8386, 0x22d6,
+ 0x8387, 0x28f2,
+ 0x8389, 0x22d0,
+ 0x838a, 0x22ce,
+ 0x838b, 0x28f4,
+ 0x838d, 0x2681,
+ 0x838e, 0x28f6,
+ 0x8394, 0x1e76,
+ 0x8395, 0x28fc,
+ 0x839e, 0x2231,
+ 0x839f, 0x2905,
+ 0x83a6, 0x1e93,
+ 0x83a7, 0x290c,
+ 0x83ab, 0x22d2,
+ 0x83ac, 0x2910,
+ 0x83ae, 0x22d7,
+ 0x83af, 0x22d5,
+ 0x83b0, 0x22d1,
+ 0x83b1, 0x2912,
+ 0x83ba, 0x1ee5,
+ 0x83bb, 0x291b,
+ 0x83c9, 0x2025,
+ 0x83ca, 0x2929,
+ 0x83f6, 0x1ecf,
+ 0x83f7, 0x2955,
+ 0x8440, 0x295d,
+ 0x8450, 0x1fd9,
+ 0x8451, 0x296d,
+ 0x8471, 0x22c8,
+ 0x8472, 0x298d,
+ 0x8474, 0x2263,
+ 0x8475, 0x298f,
+ 0x8477, 0x2683,
+ 0x8478, 0x2991,
+ 0x8480, 0x2998,
+ 0x8482, 0x1f17,
+ 0x8483, 0x299a,
+ 0x848e, 0x1f2b,
+ 0x848f, 0x29a5,
+ 0x8492, 0x22ca,
+ 0x8493, 0x1e99,
+ 0x8494, 0x29a8,
+ 0x849d, 0x1f4f,
+ 0x849e, 0x29b1,
+ 0x84a1, 0x1fcf,
+ 0x84a2, 0x2036,
+ 0x84a3, 0x1f3a,
+ 0x84a4, 0x29b4,
+ 0x84a5, 0x22c9,
+ 0x84a6, 0x1f99,
+ 0x84a7, 0x29b5,
+ 0x84a9, 0x1f75,
+ 0x84aa, 0x29b7,
+ 0x84c5, 0x1fbe,
+ 0x84c6, 0x29d2,
+ 0x84d3, 0x1ecd,
+ 0x84d4, 0x29df,
+ 0x84d5, 0x21a9,
+ 0x84d6, 0x29e0,
+ 0x84d7, 0x21e6,
+ 0x84d8, 0x29e1,
+ 0x84d9, 0x2127,
+ 0x84da, 0x2003,
+ 0x84db, 0x29e2,
+ 0x84dd, 0x2132,
+ 0x84de, 0x29e4,
+ 0x84ea, 0x2323,
+ 0x84eb, 0x29f0,
+ 0x84ee, 0x2011,
+ 0x84ef, 0x29f3,
+ 0x84f1, 0x20f5,
+ 0x84f2, 0x29f5,
+ 0x8540, 0x2a02,
+ 0x8551, 0x22c5,
+ 0x8552, 0x1f5e,
+ 0x8553, 0x2a13,
+ 0x8554, 0x22c6,
+ 0x8555, 0x2a14,
+ 0x855e, 0x20ef,
+ 0x855f, 0x2a1d,
+ 0x8566, 0x21d0,
+ 0x8567, 0x2a24,
+ 0x8580, 0x2a3c,
+ 0x8587, 0x22c1,
+ 0x8588, 0x2a43,
+ 0x858b, 0x1e64,
+ 0x858c, 0x2a46,
+ 0x8592, 0x21f9,
+ 0x8593, 0x2a4c,
+ 0x8596, 0x2010,
+ 0x8597, 0x2a4f,
+ 0x8598, 0x22c2,
+ 0x8599, 0x2a50,
+ 0x85a2, 0x1e5a,
+ 0x85a3, 0x2a59,
+ 0x85b2, 0x1ea2,
+ 0x85b3, 0x2a68,
+ 0x8640, 0x2ab4,
+ 0x864a, 0x236d,
+ 0x864b, 0x2abe,
+ 0x8654, 0x2247,
+ 0x8655, 0x2ac7,
+ 0x8668, 0x236c,
+ 0x8669, 0x2ada,
+ 0x8680, 0x2af0,
+ 0x8696, 0x219c,
+ 0x8697, 0x2b06,
+ 0x8699, 0x20c9,
+ 0x869a, 0x2b08,
+ 0x86a1, 0x21f0,
+ 0x86a2, 0x2b0f,
+ 0x86ca, 0x210b,
+ 0x86cb, 0x2b37,
+ 0x86cc, 0x20de,
+ 0x86cd, 0x2b38,
+ 0x86ce, 0x1eaa,
+ 0x86cf, 0x2b39,
+ 0x86d1, 0x222c,
+ 0x86d2, 0x2b3b,
+ 0x86dc, 0x20d8,
+ 0x86dd, 0x22c0,
+ 0x86de, 0x2b45,
+ 0x86e1, 0x206f,
+ 0x86e2, 0x2b48,
+ 0x86e8, 0x21a1,
+ 0x86e9, 0x2b4e,
+ 0x86ee, 0x2379,
+ 0x86ef, 0x2b53,
+ 0x86f4, 0x2372,
+ 0x86f5, 0x2b58,
+ 0x8740, 0x216a,
+ 0x8741, 0x2b62,
+ 0x8744, 0x237c,
+ 0x8745, 0x2b65,
+ 0x8749, 0x20b0,
+ 0x874a, 0x2b69,
+ 0x874b, 0x237a,
+ 0x874c, 0x1e74,
+ 0x874d, 0x2b6a,
+ 0x874f, 0x2377,
+ 0x8750, 0x2b6c,
+ 0x8757, 0x1f4c,
+ 0x8758, 0x2b73,
+ 0x875a, 0x2378,
+ 0x875b, 0x21cf,
+ 0x875c, 0x2368,
+ 0x875d, 0x2b75,
+ 0x875e, 0x2371,
+ 0x875f, 0x2b76,
+ 0x8760, 0x2369,
+ 0x8761, 0x2b77,
+ 0x8766, 0x2674,
+ 0x8767, 0x2b7c,
+ 0x877a, 0x236f,
+ 0x877b, 0x2b8f,
+ 0x877d, 0x2370,
+ 0x877e, 0x2b91,
+ 0x8780, 0x2b92,
+ 0x8781, 0x2376,
+ 0x8782, 0x2373,
+ 0x8783, 0x2b93,
+ 0x8786, 0x237f,
+ 0x8787, 0x2b96,
+ 0x8788, 0x2374,
+ 0x8789, 0x2b97,
+ 0x878a, 0x20b5,
+ 0x878b, 0x2b98,
+ 0x878d, 0x1edb,
+ 0x878e, 0x2672,
+ 0x878f, 0x2b9a,
+ 0x8793, 0x236e,
+ 0x8794, 0x2b9e,
+ 0x8798, 0x21b7,
+ 0x8799, 0x2ba2,
+ 0x879d, 0x2375,
+ 0x879e, 0x2ba6,
+ 0x87a3, 0x2382,
+ 0x87a4, 0x2bab,
+ 0x87a7, 0x209e,
+ 0x87a8, 0x2bae,
+ 0x87b3, 0x236b,
+ 0x87b4, 0x2bb9,
+ 0x87b5, 0x2039,
+ 0x87b6, 0x2bba,
+ 0x87bb, 0x269f,
+ 0x87bc, 0x2bbf,
+ 0x87bf, 0x237d,
+ 0x87c0, 0x21f5,
+ 0x87c1, 0x2bc2,
+ 0x87c2, 0x2381,
+ 0x87c3, 0x2bc3,
+ 0x87ca, 0x237b,
+ 0x87cb, 0x237e,
+ 0x87cc, 0x21cc,
+ 0x87cd, 0x2bca,
+ 0x87cf, 0x22db,
+ 0x87d0, 0x2bcc,
+ 0x87d2, 0x236a,
+ 0x87d3, 0x2689,
+ 0x87d4, 0x2bce,
+ 0x87d5, 0x2697,
+ 0x87d6, 0x2bcf,
+ 0x87da, 0x22a1,
+ 0x87db, 0x2bd3,
+ 0x87f7, 0x2383,
+ 0x87f8, 0x1f3d,
+ 0x87f9, 0x2bef,
+ 0x87fa, 0x218f,
+ 0x87fb, 0x2bf0,
+ 0x8840, 0x2246,
+ 0x8841, 0x2248,
+ 0x8842, 0x2bf4,
+ 0x8844, 0x217e,
+ 0x8845, 0x2bf6,
+ 0x8846, 0x2180,
+ 0x8847, 0x2bf7,
+ 0x8880, 0x2c2f,
+ 0x88ba, 0x232a,
+ 0x88bb, 0x2c69,
+ 0x88cc, 0x228b,
+ 0x88cd, 0x2c7a,
+ 0x88d4, 0x1f85,
+ 0x88d5, 0x2c81,
+ 0x88d7, 0x2325,
+ 0x88d8, 0x2c83,
+ 0x88df, 0x232c,
+ 0x88e0, 0x2c8a,
+ 0x88e5, 0x232e,
+ 0x88e6, 0x2c8f,
+ 0x88f2, 0x2205,
+ 0x88f3, 0x1e38,
+ 0x88f4, 0x2c9b,
+ 0x88f6, 0x1e73,
+ 0x88f7, 0x2c9d,
+ 0x8940, 0x2ca5,
+ 0x894b, 0x1fe3,
+ 0x894c, 0x2339,
+ 0x894d, 0x2cb0,
+ 0x894e, 0x232b,
+ 0x894f, 0x2cb1,
+ 0x8950, 0x232d,
+ 0x8951, 0x2cb2,
+ 0x8954, 0x217f,
+ 0x8955, 0x2cb5,
+ 0x895d, 0x21a7,
+ 0x895e, 0x2cbd,
+ 0x895f, 0x232f,
+ 0x8960, 0x2cbe,
+ 0x896d, 0x1e7d,
+ 0x896e, 0x2ccb,
+ 0x8971, 0x20d6,
+ 0x8972, 0x2cce,
+ 0x897c, 0x1ec2,
+ 0x897d, 0x2cd8,
+ 0x8980, 0x2cda,
+ 0x898b, 0x22b2,
+ 0x898c, 0x2ce5,
+ 0x8999, 0x1edf,
+ 0x899a, 0x2cf2,
+ 0x899e, 0x1ef9,
+ 0x899f, 0x2cf6,
+ 0x89a6, 0x20d9,
+ 0x89a7, 0x2cfd,
+ 0x89a8, 0x1fdd,
+ 0x89a9, 0x2cfe,
+ 0x89af, 0x2167,
+ 0x89b0, 0x2d04,
+ 0x89ba, 0x21ed,
+ 0x89bb, 0x2d0e,
+ 0x89be, 0x2007,
+ 0x89bf, 0x2326,
+ 0x89c0, 0x2329,
+ 0x89c1, 0x2d11,
+ 0x89c4, 0x1f52,
+ 0x89c5, 0x203b,
+ 0x89c6, 0x2328,
+ 0x89c7, 0x2d14,
+ 0x89c8, 0x2327,
+ 0x89c9, 0x2d15,
+ 0x89ce, 0x1e2b,
+ 0x89cf, 0x2d1a,
+ 0x89d1, 0x22ae,
+ 0x89d2, 0x2d1c,
+ 0x89d8, 0x1f49,
+ 0x89d9, 0x2d22,
+ 0x89db, 0x2138,
+ 0x89dc, 0x2d24,
+ 0x89f4, 0x2081,
+ 0x89f5, 0x2d3c,
+ 0x8a40, 0x2d46,
+ 0x8a41, 0x1f7c,
+ 0x8a42, 0x2d47,
+ 0x8a59, 0x235b,
+ 0x8a5a, 0x1ede,
+ 0x8a5b, 0x2d5e,
+ 0x8a5c, 0x1fa2,
+ 0x8a5d, 0x2d5f,
+ 0x8a5e, 0x1efa,
+ 0x8a5f, 0x2d60,
+ 0x8a79, 0x22ad,
+ 0x8a7a, 0x2d7a,
+ 0x8a80, 0x2d7f,
+ 0x8ae4, 0x203f,
+ 0x8ae5, 0x2de3,
+ 0x8b40, 0x2dfd,
+ 0x8b44, 0x1f0e,
+ 0x8b45, 0x2e01,
+ 0x8b49, 0x23f9,
+ 0x8b4a, 0x2e05,
+ 0x8b7a, 0x23fc,
+ 0x8b7b, 0x2e35,
+ 0x8b80, 0x2e39,
+ 0x8b8c, 0x2069,
+ 0x8b8d, 0x2e45,
+ 0x8b9e, 0x23f7,
+ 0x8b9f, 0x2e56,
+ 0x8bb3, 0x23f6,
+ 0x8bb4, 0x2e6a,
+ 0x8bb9, 0x23fd,
+ 0x8bba, 0x2e6f,
+ 0x8bbe, 0x23f8,
+ 0x8bbf, 0x2e73,
+ 0x8bc6, 0x23fa,
+ 0x8bc7, 0x2e7a,
+ 0x8bc8, 0x23fe,
+ 0x8bc9, 0x1fa8,
+ 0x8bca, 0x2e7b,
+ 0x8bd4, 0x2401,
+ 0x8bd5, 0x2e85,
+ 0x8bdc, 0x23ff,
+ 0x8bdd, 0x2e8c,
+ 0x8be5, 0x2400,
+ 0x8be6, 0x2e94,
+ 0x8beb, 0x2221,
+ 0x8bec, 0x2e99,
+ 0x8bf0, 0x2122,
+ 0x8bf1, 0x2e9d,
+ 0x8c40, 0x2eab,
+ 0x8c44, 0x23fb,
+ 0x8c45, 0x2eaf,
+ 0x8c4f, 0x215a,
+ 0x8c50, 0x2eb9,
+ 0x8c57, 0x21e5,
+ 0x8c58, 0x2ec0,
+ 0x8c5c, 0x2057,
+ 0x8c5d, 0x2ec4,
+ 0x8c80, 0x2ee6,
+ 0x8c8b, 0x20e5,
+ 0x8c8c, 0x2ef1,
+ 0x8c8d, 0x212f,
+ 0x8c8e, 0x20a3,
+ 0x8c8f, 0x2121,
+ 0x8c90, 0x2ef2,
+ 0x8c91, 0x21d4,
+ 0x8c92, 0x1fe5,
+ 0x8c93, 0x2ef3,
+ 0x8c99, 0x1e8a,
+ 0x8c9a, 0x1e37,
+ 0x8c9b, 0x2ef9,
+ 0x8ca2, 0x1f9e,
+ 0x8ca3, 0x22a6,
+ 0x8ca4, 0x21e8,
+ 0x8ca5, 0x2f00,
+ 0x8ca6, 0x1eda,
+ 0x8ca7, 0x1eb9,
+ 0x8ca8, 0x2f01,
+ 0x8cc0, 0x235c,
+ 0x8cc1, 0x2f19,
+ 0x8cd2, 0x2050,
+ 0x8cd3, 0x1e67,
+ 0x8cd4, 0x2f2a,
+ 0x8cd5, 0x23f4,
+ 0x8cd6, 0x2f2b,
+ 0x8cd9, 0x213e,
+ 0x8cda, 0x2f2e,
+ 0x8cf9, 0x1f16,
+ 0x8cfa, 0x2f4d,
+ 0x8d40, 0x2f52,
+ 0x8d73, 0x2389,
+ 0x8d74, 0x2f85,
+ 0x8d75, 0x1eb7,
+ 0x8d76, 0x2f86,
+ 0x8d7b, 0x21b4,
+ 0x8d7c, 0x2f8b,
+ 0x8d80, 0x2f8e,
+ 0x8d88, 0x238f,
+ 0x8d89, 0x2f96,
+ 0x8d8f, 0x1f1a,
+ 0x8d90, 0x2f9c,
+ 0x8d9e, 0x238b,
+ 0x8d9f, 0x2faa,
+ 0x8db9, 0x238a,
+ 0x8dba, 0x2fc4,
+ 0x8de2, 0x2391,
+ 0x8de3, 0x2fec,
+ 0x8de4, 0x2271,
+ 0x8de5, 0x2fed,
+ 0x8de7, 0x2388,
+ 0x8de8, 0x2fef,
+ 0x8df7, 0x238e,
+ 0x8df8, 0x2ffe,
+ 0x8dfe, 0x238d,
+ 0x8e40, 0x3004,
+ 0x8e46, 0x238c,
+ 0x8e47, 0x300a,
+ 0x8e56, 0x2390,
+ 0x8e57, 0x3019,
+ 0x8e58, 0x2033,
+ 0x8e59, 0x301a,
+ 0x8e5a, 0x223c,
+ 0x8e5b, 0x301b,
+ 0x8e68, 0x1fe9,
+ 0x8e69, 0x3028,
+ 0x8e6e, 0x2055,
+ 0x8e6f, 0x302d,
+ 0x8e70, 0x2392,
+ 0x8e71, 0x302e,
+ 0x8e80, 0x2324,
+ 0x8e81, 0x303c,
+ 0x8e9b, 0x2143,
+ 0x8e9c, 0x3056,
+ 0x8e9f, 0x2129,
+ 0x8ea0, 0x3059,
+ 0x8ea4, 0x2277,
+ 0x8ea5, 0x305d,
+ 0x8ea7, 0x1ea7,
+ 0x8ea8, 0x305f,
+ 0x8eac, 0x2285,
+ 0x8ead, 0x3063,
+ 0x8eae, 0x2384,
+ 0x8eaf, 0x3064,
+ 0x8ebd, 0x2387,
+ 0x8ebe, 0x2386,
+ 0x8ebf, 0x3072,
+ 0x8ec3, 0x2290,
+ 0x8ec4, 0x3076,
+ 0x8ec5, 0x1e44,
+ 0x8ec6, 0x3077,
+ 0x8ecd, 0x1e32,
+ 0x8ece, 0x2385,
+ 0x8ecf, 0x307e,
+ 0x8ed6, 0x1f13,
+ 0x8ed7, 0x1f73,
+ 0x8ed8, 0x3085,
+ 0x8eec, 0x1fe0,
+ 0x8eed, 0x3099,
+ 0x8f40, 0x30ab,
+ 0x8f52, 0x2087,
+ 0x8f53, 0x1e78,
+ 0x8f54, 0x23ae,
+ 0x8f55, 0x1ef6,
+ 0x8f56, 0x1f31,
+ 0x8f57, 0x30bd,
+ 0x8f5d, 0x2045,
+ 0x8f5e, 0x30c3,
+ 0x8f64, 0x2178,
+ 0x8f65, 0x30c9,
+ 0x8f80, 0x30e3,
+ 0x8f86, 0x23f5,
+ 0x8f87, 0x30e9,
+ 0x8f88, 0x2275,
+ 0x8f89, 0x30ea,
+ 0x8f95, 0x266e,
+ 0x8f96, 0x30f6,
+ 0x8f97, 0x1eb0,
+ 0x8f98, 0x30f7,
+ 0x8f9b, 0x2083,
+ 0x8f9c, 0x30fa,
+ 0x8f9d, 0x2188,
+ 0x8f9e, 0x30fb,
+ 0x8fa1, 0x267c,
+ 0x8fa2, 0x30fe,
+ 0x8fbd, 0x1fc5,
+ 0x8fbe, 0x3119,
+ 0x8fc4, 0x1ea1,
+ 0x8fc5, 0x311f,
+ 0x8fc6, 0x2393,
+ 0x8fc7, 0x3120,
+ 0x8fcd, 0x1f0b,
+ 0x8fce, 0x3126,
+ 0x8fd8, 0x1e7c,
+ 0x8fd9, 0x3130,
+ 0x9040, 0x3156,
+ 0x9080, 0x3195,
+ 0x909d, 0x23b4,
+ 0x909e, 0x207e,
+ 0x909f, 0x31b2,
+ 0x90ba, 0x1ee3,
+ 0x90bb, 0x31cd,
+ 0x90c0, 0x2095,
+ 0x90c1, 0x23bb,
+ 0x90c2, 0x31d2,
+ 0x90c5, 0x23b9,
+ 0x90c6, 0x31d5,
+ 0x90db, 0x1e28,
+ 0x90dc, 0x23bd,
+ 0x90dd, 0x31ea,
+ 0x90ed, 0x23b5,
+ 0x90ee, 0x31fa,
+ 0x90f0, 0x23ba,
+ 0x90f1, 0x31fc,
+ 0x90f7, 0x23b3,
+ 0x90f8, 0x3202,
+ 0x9140, 0x3209,
+ 0x9142, 0x2162,
+ 0x9143, 0x320b,
+ 0x914b, 0x1e5e,
+ 0x914c, 0x3213,
+ 0x914d, 0x1e5d,
+ 0x914e, 0x3214,
+ 0x9151, 0x23b7,
+ 0x9152, 0x3217,
+ 0x9154, 0x1f2f,
+ 0x9155, 0x24df,
+ 0x9156, 0x3219,
+ 0x9159, 0x23b2,
+ 0x915a, 0x214e,
+ 0x915b, 0x321c,
+ 0x915d, 0x2052,
+ 0x915e, 0x321e,
+ 0x9161, 0x23bc,
+ 0x9162, 0x3221,
+ 0x9163, 0x20eb,
+ 0x9164, 0x3222,
+ 0x916e, 0x2232,
+ 0x916f, 0x322c,
+ 0x9176, 0x1e3f,
+ 0x9177, 0x3233,
+ 0x917a, 0x201b,
+ 0x917b, 0x20bc,
+ 0x917c, 0x23be,
+ 0x917d, 0x3236,
+ 0x9180, 0x3238,
+ 0x9184, 0x1eae,
+ 0x9185, 0x323c,
+ 0x918d, 0x1efb,
+ 0x918e, 0x3244,
+ 0x9191, 0x2089,
+ 0x9192, 0x3247,
+ 0x9193, 0x23b1,
+ 0x9194, 0x3248,
+ 0x9197, 0x21c4,
+ 0x9198, 0x324b,
+ 0x919b, 0x2214,
+ 0x919c, 0x324e,
+ 0x91a9, 0x1fde,
+ 0x91aa, 0x2223,
+ 0x91ab, 0x23b6,
+ 0x91ac, 0x325b,
+ 0x91ba, 0x268c,
+ 0x91bb, 0x24de,
+ 0x91bc, 0x3269,
+ 0x91bf, 0x24e0,
+ 0x91c0, 0x326c,
+ 0x91c3, 0x23b8,
+ 0x91c4, 0x326f,
+ 0x91cd, 0x1e81,
+ 0x91ce, 0x3278,
+ 0x91d0, 0x1ffe,
+ 0x91d1, 0x1f51,
+ 0x91d2, 0x21e1,
+ 0x91d3, 0x327a,
+ 0x91d4, 0x23b0,
+ 0x91d5, 0x327b,
+ 0x91d6, 0x1fce,
+ 0x91d7, 0x327c,
+ 0x91d8, 0x211e,
+ 0x91d9, 0x2021,
+ 0x91da, 0x327d,
+ 0x91df, 0x24e1,
+ 0x91e0, 0x3282,
+ 0x91e2, 0x24a3,
+ 0x91e3, 0x3284,
+ 0x91ea, 0x24a4,
+ 0x91eb, 0x328b,
+ 0x91f0, 0x2273,
+ 0x91f1, 0x3290,
+ 0x91f2, 0x21b0,
+ 0x91f3, 0x3291,
+ 0x9240, 0x329d,
+ 0x9280, 0x32dc,
+ 0x92b6, 0x21d1,
+ 0x92b7, 0x3312,
+ 0x92ce, 0x211c,
+ 0x92cf, 0x3329,
+ 0x92d0, 0x235d,
+ 0x92d1, 0x332a,
+ 0x92d4, 0x2682,
+ 0x92d5, 0x332d,
+ 0x92df, 0x210d,
+ 0x92e0, 0x205a,
+ 0x92e1, 0x3337,
+ 0x92fe, 0x1f8d,
+ 0x9340, 0x3354,
+ 0x9350, 0x21ff,
+ 0x9351, 0x3364,
+ 0x935d, 0x1f58,
+ 0x935e, 0x3370,
+ 0x9370, 0x215b,
+ 0x9371, 0x3382,
+ 0x9376, 0x1eb6,
+ 0x9377, 0x3387,
+ 0x9380, 0x338f,
+ 0x938c, 0x20db,
+ 0x938d, 0x339b,
+ 0x939d, 0x2360,
+ 0x939e, 0x33ab,
+ 0x93a5, 0x2361,
+ 0x93a6, 0x33b2,
+ 0x93a7, 0x2040,
+ 0x93a8, 0x33b3,
+ 0x93b4, 0x228e,
+ 0x93b5, 0x33bf,
+ 0x93b8, 0x1fdf,
+ 0x93b9, 0x33c2,
+ 0x93bb, 0x235e,
+ 0x93bc, 0x33c4,
+ 0x93bd, 0x1e6a,
+ 0x93be, 0x33c5,
+ 0x93c6, 0x2002,
+ 0x93c7, 0x33cd,
+ 0x93cf, 0x2093,
+ 0x93d0, 0x33d5,
+ 0x93d7, 0x235f,
+ 0x93d8, 0x33dc,
+ 0x93db, 0x1eac,
+ 0x93dc, 0x1e54,
+ 0x93dd, 0x33df,
+ 0x93e1, 0x1f08,
+ 0x93e2, 0x33e3,
+ 0x93e4, 0x20c0,
+ 0x93e5, 0x2362,
+ 0x93e6, 0x33e5,
+ 0x93e9, 0x2160,
+ 0x93ea, 0x33e8,
+ 0x93eb, 0x219d,
+ 0x93ec, 0x1f8e,
+ 0x93ed, 0x222d,
+ 0x93ee, 0x33e9,
+ 0x93ef, 0x2047,
+ 0x93f0, 0x33ea,
+ 0x93f1, 0x2262,
+ 0x93f2, 0x33eb,
+ 0x93f4, 0x1f67,
+ 0x93f5, 0x1eb2,
+ 0x93f6, 0x33ed,
+ 0x93fa, 0x1ea9,
+ 0x93fb, 0x33f1,
+ 0x93fe, 0x1fcc,
+ 0x9440, 0x33f4,
+ 0x9444, 0x1f72,
+ 0x9445, 0x33f8,
+ 0x944d, 0x2098,
+ 0x944e, 0x3400,
+ 0x9450, 0x1e52,
+ 0x9451, 0x20a4,
+ 0x9452, 0x1f1c,
+ 0x9453, 0x228f,
+ 0x9454, 0x3402,
+ 0x9455, 0x1fed,
+ 0x9456, 0x3403,
+ 0x9458, 0x2365,
+ 0x9459, 0x3405,
+ 0x945b, 0x1e2d,
+ 0x945c, 0x2152,
+ 0x945d, 0x2366,
+ 0x945e, 0x3407,
+ 0x945f, 0x20fa,
+ 0x9460, 0x3408,
+ 0x9464, 0x2363,
+ 0x9465, 0x340c,
+ 0x9466, 0x209a,
+ 0x9467, 0x340d,
+ 0x946e, 0x203c,
+ 0x946f, 0x3414,
+ 0x9472, 0x1ff6,
+ 0x9473, 0x3417,
+ 0x9474, 0x2364,
+ 0x9475, 0x3418,
+ 0x9476, 0x1e69,
+ 0x9477, 0x3419,
+ 0x9478, 0x2367,
+ 0x9479, 0x341a,
+ 0x947a, 0x211d,
+ 0x947b, 0x341b,
+ 0x9480, 0x2259,
+ 0x9481, 0x2056,
+ 0x9482, 0x2163,
+ 0x9483, 0x341f,
+ 0x9487, 0x1fa9,
+ 0x9488, 0x1ffc,
+ 0x9489, 0x3423,
+ 0x94a1, 0x1e2e,
+ 0x94a2, 0x343b,
+ 0x94b3, 0x1ebc,
+ 0x94b4, 0x344c,
+ 0x94b5, 0x2142,
+ 0x94b6, 0x344d,
+ 0x94bf, 0x201e,
+ 0x94c0, 0x1e43,
+ 0x94c1, 0x3456,
+ 0x94cc, 0x24d4,
+ 0x94cd, 0x3461,
+ 0x94d8, 0x226f,
+ 0x94d9, 0x346c,
+ 0x94e0, 0x1ed7,
+ 0x94e1, 0x3473,
+ 0x9540, 0x3491,
+ 0x9572, 0x212d,
+ 0x9573, 0x34c3,
+ 0x9580, 0x34cf,
+ 0x9583, 0x229b,
+ 0x9584, 0x34d2,
+ 0x959e, 0x2256,
+ 0x959f, 0x24a8,
+ 0x95a0, 0x34ec,
+ 0x95b3, 0x1e79,
+ 0x95b4, 0x34ff,
+ 0x95ba, 0x225a,
+ 0x95bb, 0x3505,
+ 0x95cf, 0x24a7,
+ 0x95d0, 0x3519,
+ 0x95d1, 0x2686,
+ 0x95d2, 0x24a6,
+ 0x95d3, 0x351a,
+ 0x95d4, 0x21ce,
+ 0x95d5, 0x351b,
+ 0x95e1, 0x24a9,
+ 0x95e2, 0x3527,
+ 0x95e7, 0x1fe7,
+ 0x95e8, 0x352c,
+ 0x95f1, 0x2112,
+ 0x95f2, 0x3535,
+ 0x95f8, 0x213c,
+ 0x95f9, 0x353b,
+ 0x95fe, 0x1f5c,
+ 0x9640, 0x3540,
+ 0x9656, 0x24c4,
+ 0x9657, 0x3556,
+ 0x967c, 0x1ecc,
+ 0x967d, 0x357b,
+ 0x9680, 0x357d,
+ 0x9740, 0x35fc,
+ 0x9767, 0x246a,
+ 0x9768, 0x3623,
+ 0x976c, 0x2175,
+ 0x976d, 0x3627,
+ 0x976e, 0x246d,
+ 0x976f, 0x3628,
+ 0x9780, 0x3638,
+ 0x9796, 0x246b,
+ 0x9797, 0x225f,
+ 0x9798, 0x364e,
+ 0x979d, 0x1ece,
+ 0x979e, 0x3653,
+ 0x97a3, 0x2272,
+ 0x97a4, 0x3658,
+ 0x97bf, 0x2473,
+ 0x97c0, 0x3673,
+ 0x97ee, 0x21fe,
+ 0x97ef, 0x36a1,
+ 0x97f7, 0x1efe,
+ 0x97f8, 0x36a9,
+ 0x9840, 0x36b0,
+ 0x9845, 0x2475,
+ 0x9846, 0x36b5,
+ 0x9849, 0x220a,
+ 0x984a, 0x36b8,
+ 0x984f, 0x1f6f,
+ 0x9850, 0x36bd,
+ 0x9871, 0x2468,
+ 0x9872, 0x36de,
+ 0x9873, 0x2100,
+ 0x9874, 0x36df,
+ 0x9880, 0x36ea,
+ 0x9881, 0x2476,
+ 0x9882, 0x36eb,
+ 0x988b, 0x1f27,
+ 0x988c, 0x20d7,
+ 0x988d, 0x36f4,
+ 0x98a0, 0x247c,
+ 0x98a1, 0x3707,
+ 0x98aa, 0x1fa1,
+ 0x98ab, 0x3710,
+ 0x98b6, 0x22aa,
+ 0x98b7, 0x2005,
+ 0x98b8, 0x371b,
+ 0x98ba, 0x246c,
+ 0x98bb, 0x371d,
+ 0x98c7, 0x203e,
+ 0x98c8, 0x3729,
+ 0x98cb, 0x1e4c,
+ 0x98cc, 0x372c,
+ 0x98d0, 0x213a,
+ 0x98d1, 0x3730,
+ 0x98d3, 0x2204,
+ 0x98d4, 0x3732,
+ 0x98e3, 0x20c3,
+ 0x98e4, 0x2140,
+ 0x98e5, 0x2477,
+ 0x98e6, 0x3741,
+ 0x98ef, 0x2474,
+ 0x98f0, 0x374a,
+ 0x98f2, 0x20dd,
+ 0x98f3, 0x374c,
+ 0x9940, 0x3758,
+ 0x9943, 0x1f68,
+ 0x9944, 0x375b,
+ 0x9945, 0x2185,
+ 0x9946, 0x375c,
+ 0x9966, 0x2472,
+ 0x9967, 0x377c,
+ 0x996e, 0x1eb5,
+ 0x996f, 0x3783,
+ 0x9975, 0x2478,
+ 0x9976, 0x3789,
+ 0x997a, 0x1f8b,
+ 0x997b, 0x2484,
+ 0x997c, 0x378d,
+ 0x9980, 0x3790,
+ 0x9985, 0x2699,
+ 0x9986, 0x3795,
+ 0x9989, 0x2482,
+ 0x998a, 0x3798,
+ 0x998e, 0x20a1,
+ 0x998f, 0x379c,
+ 0x9991, 0x1f92,
+ 0x9992, 0x379e,
+ 0x9999, 0x1f38,
+ 0x999a, 0x37a5,
+ 0x99a9, 0x2485,
+ 0x99aa, 0x37b4,
+ 0x99b0, 0x2480,
+ 0x99b1, 0x246e,
+ 0x99b2, 0x37ba,
+ 0x99b3, 0x247b,
+ 0x99b4, 0x2486,
+ 0x99b5, 0x2471,
+ 0x99b6, 0x37bb,
+ 0x99bd, 0x2483,
+ 0x99be, 0x2470,
+ 0x99bf, 0x37c2,
+ 0x99c0, 0x2469,
+ 0x99c1, 0x37c3,
+ 0x99c2, 0x247f,
+ 0x99c3, 0x37c4,
+ 0x99c9, 0x246f,
+ 0x99ca, 0x37ca,
+ 0x99ce, 0x2481,
+ 0x99cf, 0x37ce,
+ 0x99d1, 0x2220,
+ 0x99d2, 0x37d0,
+ 0x99da, 0x1ff5,
+ 0x99db, 0x37d8,
+ 0x99e0, 0x20f4,
+ 0x99e1, 0x37dd,
+ 0x99e5, 0x247d,
+ 0x99e6, 0x37e1,
+ 0x99e8, 0x2479,
+ 0x99e9, 0x37e3,
+ 0x99ec, 0x247e,
+ 0x99ed, 0x37e6,
+ 0x99f4, 0x247a,
+ 0x99f5, 0x37ed,
+ 0x9a40, 0x37f7,
+ 0x9a4a, 0x20e3,
+ 0x9a4b, 0x3801,
+ 0x9a57, 0x20ad,
+ 0x9a58, 0x380d,
+ 0x9a65, 0x24cb,
+ 0x9a66, 0x381a,
+ 0x9a67, 0x1f53,
+ 0x9a68, 0x381b,
+ 0x9a71, 0x2159,
+ 0x9a72, 0x3824,
+ 0x9a76, 0x2013,
+ 0x9a77, 0x1f33,
+ 0x9a78, 0x3828,
+ 0x9a80, 0x382f,
+ 0x9a88, 0x1e5c,
+ 0x9a89, 0x3837,
+ 0x9a8c, 0x2488,
+ 0x9a8d, 0x383a,
+ 0x9a91, 0x2487,
+ 0x9a92, 0x383e,
+ 0x9a97, 0x248a,
+ 0x9a98, 0x3843,
+ 0x9a9a, 0x2489,
+ 0x9a9b, 0x248b,
+ 0x9a9c, 0x3845,
+ 0x9a9e, 0x1f83,
+ 0x9a9f, 0x3847,
+ 0x9aa2, 0x210f,
+ 0x9aa3, 0x1fdb,
+ 0x9aa4, 0x384a,
+ 0x9aaa, 0x20af,
+ 0x9aab, 0x3850,
+ 0x9ad0, 0x24c0,
+ 0x9ad1, 0x3875,
+ 0x9ad6, 0x226d,
+ 0x9ad7, 0x387a,
+ 0x9ada, 0x24c1,
+ 0x9adb, 0x387d,
+ 0x9ae2, 0x20ca,
+ 0x9ae3, 0x3884,
+ 0x9ae4, 0x20e7,
+ 0x9ae5, 0x24c2,
+ 0x9ae6, 0x3885,
+ 0x9b40, 0x389e,
+ 0x9b80, 0x38dd,
+ 0x9bd1, 0x23dc,
+ 0x9bd2, 0x392e,
+ 0x9bdc, 0x23db,
+ 0x9bdd, 0x3938,
+ 0x9c40, 0x395a,
+ 0x9c53, 0x205e,
+ 0x9c54, 0x396d,
+ 0x9c59, 0x2244,
+ 0x9c5a, 0x23e2,
+ 0x9c5b, 0x3972,
+ 0x9c5c, 0x20d4,
+ 0x9c5d, 0x3973,
+ 0x9c75, 0x219f,
+ 0x9c76, 0x398b,
+ 0x9c79, 0x1e66,
+ 0x9c7a, 0x398e,
+ 0x9c80, 0x3993,
+ 0x9c86, 0x1f63,
+ 0x9c87, 0x3999,
+ 0x9c9d, 0x23dd,
+ 0x9c9e, 0x39af,
+ 0x9cab, 0x216b,
+ 0x9cac, 0x39bc,
+ 0x9cca, 0x22b5,
+ 0x9ccb, 0x39da,
+ 0x9ccf, 0x1f26,
+ 0x9cd0, 0x39de,
+ 0x9ce6, 0x1e63,
+ 0x9ce7, 0x2088,
+ 0x9ce8, 0x39f4,
+ 0x9cec, 0x1ebd,
+ 0x9ced, 0x39f8,
+ 0x9cee, 0x2341,
+ 0x9cef, 0x39f9,
+ 0x9cfb, 0x1f4b,
+ 0x9cfc, 0x3a05,
+ 0x9cfe, 0x2292,
+ 0x9d40, 0x3a07,
+ 0x9d42, 0x2124,
+ 0x9d43, 0x3a09,
+ 0x9d46, 0x2048,
+ 0x9d47, 0x23e0,
+ 0x9d48, 0x3a0c,
+ 0x9d4d, 0x2077,
+ 0x9d4e, 0x3a11,
+ 0x9d4f, 0x223a,
+ 0x9d50, 0x3a12,
+ 0x9d61, 0x20b1,
+ 0x9d62, 0x3a23,
+ 0x9d68, 0x1f41,
+ 0x9d69, 0x201c,
+ 0x9d6a, 0x3a29,
+ 0x9d6e, 0x22b8,
+ 0x9d6f, 0x3a2d,
+ 0x9d71, 0x2276,
+ 0x9d72, 0x3a2f,
+ 0x9d75, 0x1f9b,
+ 0x9d76, 0x3a32,
+ 0x9d7b, 0x1f9f,
+ 0x9d7c, 0x3a37,
+ 0x9d7d, 0x25ca,
+ 0x9d7e, 0x3a38,
+ 0x9d80, 0x3a39,
+ 0x9d8a, 0x20be,
+ 0x9d8b, 0x3a43,
+ 0x9d8d, 0x1fb4,
+ 0x9d8e, 0x3a45,
+ 0x9d91, 0x23d7,
+ 0x9d92, 0x3a48,
+ 0x9d99, 0x2105,
+ 0x9d9a, 0x3a4f,
+ 0x9da1, 0x23e1,
+ 0x9da2, 0x1fec,
+ 0x9da3, 0x3a56,
+ 0x9da7, 0x23ea,
+ 0x9da8, 0x3a5a,
+ 0x9dac, 0x23e3,
+ 0x9dad, 0x210e,
+ 0x9dae, 0x3a5e,
+ 0x9db2, 0x1fa6,
+ 0x9db3, 0x2004,
+ 0x9db4, 0x3a62,
+ 0x9dbe, 0x1f9d,
+ 0x9dbf, 0x3a6c,
+ 0x9dc6, 0x23e5,
+ 0x9dc7, 0x3a73,
+ 0x9dc9, 0x2264,
+ 0x9dca, 0x3a75,
+ 0x9dcd, 0x24e2,
+ 0x9dce, 0x3a78,
+ 0x9dd2, 0x23de,
+ 0x9dd3, 0x3a7c,
+ 0x9dd5, 0x1ec4,
+ 0x9dd6, 0x3a7e,
+ 0x9de1, 0x22b6,
+ 0x9de2, 0x20a9,
+ 0x9de3, 0x3a89,
+ 0x9df1, 0x212b,
+ 0x9df2, 0x3a97,
+ 0x9df4, 0x20a5,
+ 0x9df5, 0x3a99,
+ 0x9df7, 0x268b,
+ 0x9df8, 0x3a9b,
+ 0x9dfa, 0x1f76,
+ 0x9dfb, 0x3a9d,
+ 0x9dfd, 0x216d,
+ 0x9dfe, 0x3a9f,
+ 0x9e40, 0x3aa0,
+ 0x9e45, 0x2001,
+ 0x9e46, 0x3aa5,
+ 0x9e48, 0x2191,
+ 0x9e49, 0x1e50,
+ 0x9e4a, 0x3aa7,
+ 0x9e52, 0x1f9c,
+ 0x9e53, 0x3aaf,
+ 0x9e54, 0x23da,
+ 0x9e55, 0x3ab0,
+ 0x9e56, 0x2053,
+ 0x9e57, 0x3ab1,
+ 0x9e5d, 0x23e9,
+ 0x9e5e, 0x23e4,
+ 0x9e5f, 0x3ab7,
+ 0x9e61, 0x21d5,
+ 0x9e62, 0x3ab9,
+ 0x9e63, 0x23e6,
+ 0x9e64, 0x3aba,
+ 0x9e67, 0x23df,
+ 0x9e68, 0x3abd,
+ 0x9e6c, 0x1e4f,
+ 0x9e6d, 0x3ac1,
+ 0x9e6f, 0x23d9,
+ 0x9e70, 0x3ac3,
+ 0x9e72, 0x2014,
+ 0x9e73, 0x3ac5,
+ 0x9e74, 0x23ec,
+ 0x9e75, 0x23eb,
+ 0x9e76, 0x3ac6,
+ 0x9e7b, 0x23d8,
+ 0x9e7c, 0x23ee,
+ 0x9e7d, 0x3acb,
+ 0x9e80, 0x3acd,
+ 0x9e85, 0x268e,
+ 0x9e86, 0x3ad2,
+ 0x9e87, 0x23ed,
+ 0x9e88, 0x3ad3,
+ 0x9e91, 0x1ffa,
+ 0x9e92, 0x3adc,
+ 0x9e96, 0x23d6,
+ 0x9e97, 0x23e8,
+ 0x9e98, 0x3ae0,
+ 0x9ea2, 0x2106,
+ 0x9ea3, 0x3aea,
+ 0x9ea6, 0x200b,
+ 0x9ea7, 0x3aed,
+ 0x9ea9, 0x2166,
+ 0x9eaa, 0x3aef,
+ 0x9eae, 0x23ef,
+ 0x9eaf, 0x3af3,
+ 0x9eb3, 0x2189,
+ 0x9eb4, 0x2058,
+ 0x9eb5, 0x3af7,
+ 0x9eb7, 0x23e7,
+ 0x9eb8, 0x3af9,
+ 0x9ef5, 0x21a3,
+ 0x9ef6, 0x3b36,
+ 0x9f40, 0x3b3f,
+ 0x9f4e, 0x217a,
+ 0x9f4f, 0x3b4d,
+ 0x9f6f, 0x21a5,
+ 0x9f70, 0x3b6d,
+ 0x9f80, 0x3b7c,
+ 0x9f92, 0x2022,
+ 0x9f93, 0x3b8e,
+ 0x9f98, 0x24d6,
+ 0x9f99, 0x3b93,
+ 0x9fa6, 0x233a,
+ 0x9fa7, 0x3ba0,
+ 0x9fa9, 0x1eee,
+ 0x9faa, 0x3ba2,
+ 0x9fac, 0x24d5,
+ 0x9fad, 0x3ba4,
+ 0x9fc9, 0x2228,
+ 0x9fca, 0x3bc0,
+ 0x9fcd, 0x24d7,
+ 0x9fce, 0x3bc3,
+ 0x9fe1, 0x20fc,
+ 0x9fe2, 0x3bd6,
+ 0x9feb, 0x1e87,
+ 0x9fec, 0x3bdf,
+ 0x9fee, 0x24d8,
+ 0x9fef, 0x3be1,
+ 0x9ff4, 0x1eba,
+ 0x9ff5, 0x3be6,
+ 0x9ffd, 0x2119,
+ 0x9ffe, 0x3bee,
+ 0xa040, 0x3bef,
+ 0xa043, 0x216c,
+ 0xa044, 0x3bf2,
+ 0xa046, 0x24d9,
+ 0xa047, 0x3bf4,
+ 0xa049, 0x2227,
+ 0xa04a, 0x3bf6,
+ 0xa04e, 0x1e5f,
+ 0xa04f, 0x3bfa,
+ 0xa054, 0x229f,
+ 0xa055, 0x3bff,
+ 0xa05a, 0x1f5d,
+ 0xa05b, 0x3c04,
+ 0xa061, 0x1fbc,
+ 0xa062, 0x3c0a,
+ 0xa063, 0x24da,
+ 0xa064, 0x3c0b,
+ 0xa071, 0x2149,
+ 0xa072, 0x3c18,
+ 0xa074, 0x2046,
+ 0xa075, 0x3c1a,
+ 0xa080, 0x2000,
+ 0xa081, 0x3c24,
+ 0xa091, 0x2190,
+ 0xa092, 0x3c34,
+ 0xa094, 0x2208,
+ 0xa095, 0x3c36,
+ 0xa096, 0x1ee6,
+ 0xa097, 0x3c37,
+ 0xa0a9, 0x24c3,
+ 0xa0aa, 0x3c49,
+ 0xa0bf, 0x20cc,
+ 0xa0c0, 0x3c5e,
+ 0xa0ce, 0x2340,
+ 0xa0cf, 0x3c6c,
+ 0xa0d9, 0x1ed1,
+ 0xa0da, 0x3c76,
+ 0xa0de, 0x21ac,
+ 0xa0df, 0x3c7a,
+ 0xa0ee, 0x22af,
+ 0xa0ef, 0x3c89,
+ 0xa1a1, 0x0060,
+ 0xa2a1, 0x26a9,
+ 0xa2b1, 0x00be,
+ 0xa2e5, 0x00f0,
+ 0xa2f1, 0x00fa,
+ 0xa3a1, 0x0106,
+ 0xa4a1, 0x0164,
+ 0xa5a1, 0x01b7,
+ 0xa6a1, 0x020d,
+ 0xa6c1, 0x0225,
+ 0xa7a1, 0x025a,
+ 0xa7d1, 0x027b,
+ 0xa840, 0x26b3,
+ 0xa880, 0x26f2,
+ 0xa8a1, 0x029c,
+ 0xa8c5, 0x02bc,
+ 0xa940, 0x2708,
+ 0xa959, 0x2720,
+ 0xa95c, 0x2722,
+ 0xa960, 0x2723,
+ 0xa980, 0x2742,
+ 0xa996, 0x1e17,
+ 0xa9a4, 0x02e2,
+ 0xaa40, 0x3c99,
+ 0xaa4d, 0x21b6,
+ 0xaa4e, 0x1e3d,
+ 0xaa4f, 0x3ca6,
+ 0xaa71, 0x2235,
+ 0xaa72, 0x3cc8,
+ 0xaa73, 0x2397,
+ 0xaa74, 0x3cc9,
+ 0xaa77, 0x2395,
+ 0xaa78, 0x3ccc,
+ 0xaa7a, 0x223f,
+ 0xaa7b, 0x212a,
+ 0xaa7c, 0x3cce,
+ 0xaa80, 0x3cd1,
+ 0xaa9a, 0x1ed2,
+ 0xaa9b, 0x3ceb,
+ 0xaa9c, 0x2396,
+ 0xaa9d, 0x2398,
+ 0xaa9e, 0x3cec,
+ 0xaa9f, 0x20a2,
+ 0xaaa0, 0x3ced,
+ 0xaaa1, 0x032e,
+ 0xab40, 0x1f64,
+ 0xab41, 0x3cee,
+ 0xab43, 0x202b,
+ 0xab44, 0x3cf0,
+ 0xab45, 0x2394,
+ 0xab46, 0x2139,
+ 0xab47, 0x3cf1,
+ 0xab48, 0x215f,
+ 0xab49, 0x21c1,
+ 0xab4a, 0x239a,
+ 0xab4b, 0x3cf2,
+ 0xab4d, 0x2399,
+ 0xab4e, 0x3cf4,
+ 0xab80, 0x3d25,
+ 0xaba1, 0x038c,
+ 0xac40, 0x3d46,
+ 0xac46, 0x21c0,
+ 0xac47, 0x3d4c,
+ 0xac71, 0x2460,
+ 0xac72, 0x3d76,
+ 0xac7c, 0x245c,
+ 0xac7d, 0x3d80,
+ 0xac80, 0x3d82,
+ 0xac8d, 0x215d,
+ 0xac8e, 0x3d8f,
+ 0xac93, 0x2225,
+ 0xac94, 0x206a,
+ 0xac95, 0x3d94,
+ 0xad40, 0x3da0,
+ 0xad49, 0x2461,
+ 0xad4a, 0x3da9,
+ 0xad5e, 0x245b,
+ 0xad5f, 0x3dbd,
+ 0xad61, 0x2462,
+ 0xad62, 0x3dbf,
+ 0xad68, 0x1f54,
+ 0xad69, 0x3dc5,
+ 0xad74, 0x245f,
+ 0xad75, 0x3dd0,
+ 0xad80, 0x3dda,
+ 0xad82, 0x20ec,
+ 0xad83, 0x3ddc,
+ 0xad87, 0x245d,
+ 0xad88, 0x3de0,
+ 0xad8b, 0x2463,
+ 0xad8c, 0x3de3,
+ 0xad91, 0x2464,
+ 0xad92, 0x3de8,
+ 0xae40, 0x3df7,
+ 0xae54, 0x24a5,
+ 0xae55, 0x3e0b,
+ 0xae62, 0x1e70,
+ 0xae63, 0x3e18,
+ 0xae80, 0x208f,
+ 0xae81, 0x3e34,
+ 0xae85, 0x1e42,
+ 0xae86, 0x3e38,
+ 0xae8b, 0x1f4e,
+ 0xae8c, 0x3e3d,
+ 0xae94, 0x1eb1,
+ 0xae95, 0x3e45,
+ 0xaea0, 0x1e8b,
+ 0xaf40, 0x3e50,
+ 0xaf64, 0x1fc6,
+ 0xaf65, 0x3e74,
+ 0xaf7b, 0x25ae,
+ 0xaf7c, 0x3e8a,
+ 0xaf80, 0x3e8d,
+ 0xaf82, 0x1f01,
+ 0xaf83, 0x2200,
+ 0xaf84, 0x3e8f,
+ 0xaf8e, 0x25b2,
+ 0xaf8f, 0x1e97,
+ 0xaf90, 0x3e99,
+ 0xaf91, 0x20ab,
+ 0xaf92, 0x3e9a,
+ 0xaf9c, 0x25b3,
+ 0xaf9d, 0x3ea4,
+ 0xaf9f, 0x2028,
+ 0xafa0, 0x3ea6,
+ 0xb040, 0x3ea7,
+ 0xb041, 0x25af,
+ 0xb043, 0x3ea8,
+ 0xb044, 0x25b1,
+ 0xb045, 0x3ea9,
+ 0xb04f, 0x25ac,
+ 0xb050, 0x3eb3,
+ 0xb054, 0x1e4e,
+ 0xb055, 0x3eb7,
+ 0xb057, 0x2202,
+ 0xb058, 0x25ab,
+ 0xb059, 0x2286,
+ 0xb05a, 0x3eb9,
+ 0xb05b, 0x25ad,
+ 0xb05c, 0x3eba,
+ 0xb05d, 0x25b6,
+ 0xb05e, 0x3ebb,
+ 0xb05f, 0x21e3,
+ 0xb060, 0x25b4,
+ 0xb062, 0x222f,
+ 0xb063, 0x2165,
+ 0xb064, 0x25b7,
+ 0xb065, 0x3ebc,
+ 0xb06c, 0x1ee9,
+ 0xb06d, 0x3ec3,
+ 0xb07d, 0x1e25,
+ 0xb07e, 0x3ed3,
+ 0xb080, 0x3ed4,
+ 0xb097, 0x25c0,
+ 0xb098, 0x3eeb,
+ 0xb099, 0x229a,
+ 0xb09a, 0x3eec,
+ 0xb0a1, 0x03ac,
+ 0xb140, 0x3ef3,
+ 0xb14b, 0x226e,
+ 0xb14c, 0x3efe,
+ 0xb14d, 0x1fbd,
+ 0xb14e, 0x3eff,
+ 0xb14f, 0x1f84,
+ 0xb150, 0x20b2,
+ 0xb151, 0x3f00,
+ 0xb152, 0x2043,
+ 0xb153, 0x3f01,
+ 0xb180, 0x3f2d,
+ 0xb197, 0x2684,
+ 0xb198, 0x3f44,
+ 0xb1a1, 0x040a,
+ 0xb240, 0x3f4d,
+ 0xb241, 0x24ef,
+ 0xb242, 0x3f4e,
+ 0xb267, 0x24ee,
+ 0xb268, 0x3f73,
+ 0xb26d, 0x2074,
+ 0xb26e, 0x3f78,
+ 0xb274, 0x2687,
+ 0xb275, 0x3f7e,
+ 0xb280, 0x24f0,
+ 0xb281, 0x3f88,
+ 0xb289, 0x268d,
+ 0xb28a, 0x3f90,
+ 0xb29a, 0x22a0,
+ 0xb29b, 0x3fa0,
+ 0xb2a1, 0x0468,
+ 0xb340, 0x3fa6,
+ 0xb343, 0x1fab,
+ 0xb344, 0x3fa9,
+ 0xb370, 0x26a8,
+ 0xb371, 0x3fd5,
+ 0xb380, 0x3fe3,
+ 0xb388, 0x24e9,
+ 0xb389, 0x3feb,
+ 0xb38c, 0x24e5,
+ 0xb38d, 0x3fee,
+ 0xb38e, 0x21fa,
+ 0xb38f, 0x3fef,
+ 0xb3a1, 0x04c6,
+ 0xb440, 0x4001,
+ 0xb454, 0x2148,
+ 0xb455, 0x4015,
+ 0xb458, 0x24e4,
+ 0xb459, 0x4018,
+ 0xb45e, 0x24e6,
+ 0xb45f, 0x20f7,
+ 0xb460, 0x401d,
+ 0xb461, 0x206b,
+ 0xb462, 0x401e,
+ 0xb475, 0x22a7,
+ 0xb476, 0x4031,
+ 0xb47e, 0x24ec,
+ 0xb480, 0x4039,
+ 0xb483, 0x24eb,
+ 0xb484, 0x403c,
+ 0xb489, 0x24e3,
+ 0xb48a, 0x4041,
+ 0xb493, 0x24ea,
+ 0xb494, 0x404a,
+ 0xb4a1, 0x0524,
+ 0xb540, 0x4057,
+ 0xb541, 0x1e92,
+ 0xb542, 0x4058,
+ 0xb54b, 0x1e27,
+ 0xb54c, 0x4061,
+ 0xb556, 0x1fe6,
+ 0xb557, 0x406b,
+ 0xb55a, 0x24e7,
+ 0xb55b, 0x2012,
+ 0xb55c, 0x1eec,
+ 0xb55d, 0x406e,
+ 0xb561, 0x24e8,
+ 0xb562, 0x4072,
+ 0xb580, 0x408f,
+ 0xb59c, 0x1f66,
+ 0xb59d, 0x24dc,
+ 0xb59e, 0x40ab,
+ 0xb5a1, 0x0582,
+ 0xb640, 0x40ae,
+ 0xb652, 0x26a2,
+ 0xb653, 0x40c0,
+ 0xb655, 0x24dd,
+ 0xb656, 0x40c2,
+ 0xb659, 0x200e,
+ 0xb65a, 0x40c5,
+ 0xb65b, 0x24db,
+ 0xb65c, 0x1eb8,
+ 0xb65d, 0x40c6,
+ 0xb680, 0x40e8,
+ 0xb6a1, 0x05e0,
+ 0xb740, 0x4109,
+ 0xb74e, 0x2295,
+ 0xb74f, 0x4117,
+ 0xb751, 0x1e80,
+ 0xb752, 0x4119,
+ 0xb759, 0x2677,
+ 0xb75a, 0x4120,
+ 0xb764, 0x2624,
+ 0xb765, 0x1f69,
+ 0xb766, 0x222b,
+ 0xb767, 0x412a,
+ 0xb777, 0x257f,
+ 0xb778, 0x1f5b,
+ 0xb779, 0x413a,
+ 0xb780, 0x219b,
+ 0xb781, 0x4140,
+ 0xb782, 0x267d,
+ 0xb783, 0x4141,
+ 0xb7a1, 0x063e,
+ 0xb840, 0x415f,
+ 0xb843, 0x21a0,
+ 0xb844, 0x2186,
+ 0xb845, 0x4162,
+ 0xb846, 0x20ed,
+ 0xb847, 0x4163,
+ 0xb84d, 0x25b9,
+ 0xb84e, 0x4169,
+ 0xb851, 0x1fea,
+ 0xb852, 0x416c,
+ 0xb85a, 0x1ea4,
+ 0xb85b, 0x20e1,
+ 0xb85c, 0x4174,
+ 0xb85d, 0x25b8,
+ 0xb85e, 0x2260,
+ 0xb85f, 0x4175,
+ 0xb860, 0x20e2,
+ 0xb861, 0x4176,
+ 0xb877, 0x2141,
+ 0xb878, 0x418c,
+ 0xb880, 0x4193,
+ 0xb882, 0x1fc7,
+ 0xb883, 0x4195,
+ 0xb8a1, 0x069c,
+ 0xb940, 0x41b3,
+ 0xb950, 0x1e41,
+ 0xb951, 0x41c3,
+ 0xb961, 0x25e4,
+ 0xb962, 0x41d3,
+ 0xb97b, 0x1f86,
+ 0xb97c, 0x41ec,
+ 0xb980, 0x41ef,
+ 0xb99d, 0x1fb3,
+ 0xb99e, 0x420c,
+ 0xb9a0, 0x1eef,
+ 0xb9a1, 0x06fa,
+ 0xba40, 0x420e,
+ 0xba42, 0x22a4,
+ 0xba43, 0x4210,
+ 0xba44, 0x25e8,
+ 0xba45, 0x4211,
+ 0xba56, 0x25e3,
+ 0xba57, 0x4222,
+ 0xba59, 0x2111,
+ 0xba5a, 0x4224,
+ 0xba60, 0x25e6,
+ 0xba61, 0x422a,
+ 0xba6a, 0x25e7,
+ 0xba6b, 0x4233,
+ 0xba74, 0x2041,
+ 0xba75, 0x423c,
+ 0xba80, 0x4246,
+ 0xba84, 0x25ea,
+ 0xba85, 0x424a,
+ 0xba86, 0x1f8f,
+ 0xba87, 0x424b,
+ 0xba88, 0x25ec,
+ 0xba89, 0x424c,
+ 0xba8d, 0x25eb,
+ 0xba8e, 0x4250,
+ 0xba9e, 0x20d0,
+ 0xba9f, 0x201d,
+ 0xbaa0, 0x4260,
+ 0xbaa1, 0x0758,
+ 0xbb40, 0x1ff7,
+ 0xbb41, 0x4261,
+ 0xbb49, 0x1e8d,
+ 0xbb4a, 0x4269,
+ 0xbb58, 0x25e9,
+ 0xbb59, 0x4277,
+ 0xbb5b, 0x25ee,
+ 0xbb5c, 0x203a,
+ 0xbb5d, 0x4279,
+ 0xbb60, 0x2693,
+ 0xbb61, 0x427c,
+ 0xbb65, 0x25e5,
+ 0xbb66, 0x25ed,
+ 0xbb67, 0x4280,
+ 0xbb68, 0x2009,
+ 0xbb69, 0x4281,
+ 0xbb6a, 0x2065,
+ 0xbb6b, 0x4282,
+ 0xbb6e, 0x26a3,
+ 0xbb6f, 0x4285,
+ 0xbb80, 0x4295,
+ 0xbba1, 0x07b6,
+ 0xbc40, 0x42b6,
+ 0xbc52, 0x25f5,
+ 0xbc53, 0x1efc,
+ 0xbc54, 0x42c8,
+ 0xbc5a, 0x2024,
+ 0xbc5b, 0x42ce,
+ 0xbc61, 0x269b,
+ 0xbc62, 0x42d4,
+ 0xbc63, 0x25f3,
+ 0xbc64, 0x42d5,
+ 0xbc65, 0x22d9,
+ 0xbc66, 0x42d6,
+ 0xbc67, 0x25f4,
+ 0xbc68, 0x42d7,
+ 0xbc69, 0x241b,
+ 0xbc6a, 0x42d8,
+ 0xbc6d, 0x1fc8,
+ 0xbc6e, 0x42db,
+ 0xbc6f, 0x1f7b,
+ 0xbc70, 0x42dc,
+ 0xbc71, 0x241d,
+ 0xbc72, 0x42dd,
+ 0xbc73, 0x224c,
+ 0xbc74, 0x1f48,
+ 0xbc75, 0x241c,
+ 0xbc76, 0x241e,
+ 0xbc78, 0x20ff,
+ 0xbc79, 0x219a,
+ 0xbc7a, 0x42de,
+ 0xbc7b, 0x2091,
+ 0xbc7c, 0x42df,
+ 0xbc7e, 0x20a7,
+ 0xbc80, 0x42e1,
+ 0xbc82, 0x2423,
+ 0xbc83, 0x1e9b,
+ 0xbc84, 0x2422,
+ 0xbc85, 0x42e3,
+ 0xbc86, 0x2110,
+ 0xbc87, 0x42e4,
+ 0xbc88, 0x228d,
+ 0xbc89, 0x1f71,
+ 0xbc8a, 0x1ef8,
+ 0xbc8b, 0x2421,
+ 0xbc8c, 0x42e5,
+ 0xbc8f, 0x1ef3,
+ 0xbc90, 0x42e8,
+ 0xbc9a, 0x21b1,
+ 0xbc9b, 0x2426,
+ 0xbc9c, 0x2425,
+ 0xbc9d, 0x2120,
+ 0xbc9e, 0x42f2,
+ 0xbca1, 0x0814,
+ 0xbd40, 0x42f5,
+ 0xbd42, 0x211a,
+ 0xbd43, 0x2424,
+ 0xbd44, 0x42f7,
+ 0xbd45, 0x2428,
+ 0xbd46, 0x42f8,
+ 0xbd48, 0x242a,
+ 0xbd49, 0x2429,
+ 0xbd4a, 0x42fa,
+ 0xbd4b, 0x2294,
+ 0xbd4c, 0x42fb,
+ 0xbd4d, 0x22be,
+ 0xbd4e, 0x42fc,
+ 0xbd4f, 0x1e31,
+ 0xbd50, 0x42fd,
+ 0xbd57, 0x242c,
+ 0xbd58, 0x4304,
+ 0xbd59, 0x1fb5,
+ 0xbd5a, 0x4305,
+ 0xbd66, 0x242b,
+ 0xbd67, 0x1faf,
+ 0xbd68, 0x4311,
+ 0xbd6a, 0x2068,
+ 0xbd6b, 0x21e4,
+ 0xbd6c, 0x4313,
+ 0xbd6f, 0x1f21,
+ 0xbd70, 0x4316,
+ 0xbd71, 0x2101,
+ 0xbd72, 0x4317,
+ 0xbd79, 0x217c,
+ 0xbd7a, 0x214a,
+ 0xbd7b, 0x242d,
+ 0xbd7c, 0x431e,
+ 0xbd7e, 0x1fd4,
+ 0xbd80, 0x4320,
+ 0xbd81, 0x1fd1,
+ 0xbd82, 0x4321,
+ 0xbd89, 0x1e33,
+ 0xbd8a, 0x4328,
+ 0xbd8b, 0x242f,
+ 0xbd8c, 0x4329,
+ 0xbd8e, 0x242e,
+ 0xbd8f, 0x432b,
+ 0xbd90, 0x2430,
+ 0xbd91, 0x21db,
+ 0xbd92, 0x432c,
+ 0xbd97, 0x2158,
+ 0xbd98, 0x4331,
+ 0xbd9b, 0x1fc2,
+ 0xbd9c, 0x4334,
+ 0xbda1, 0x0872,
+ 0xbe40, 0x4339,
+ 0xbe43, 0x22b9,
+ 0xbe44, 0x433c,
+ 0xbe45, 0x2436,
+ 0xbe46, 0x433d,
+ 0xbe49, 0x1e8e,
+ 0xbe4a, 0x2439,
+ 0xbe4b, 0x4340,
+ 0xbe51, 0x21c5,
+ 0xbe52, 0x2437,
+ 0xbe53, 0x2192,
+ 0xbe54, 0x4346,
+ 0xbe55, 0x243a,
+ 0xbe56, 0x1f19,
+ 0xbe57, 0x218c,
+ 0xbe58, 0x1e40,
+ 0xbe59, 0x22b3,
+ 0xbe5a, 0x4347,
+ 0xbe5d, 0x205f,
+ 0xbe5e, 0x2438,
+ 0xbe5f, 0x2432,
+ 0xbe60, 0x2274,
+ 0xbe61, 0x434a,
+ 0xbe62, 0x1e9c,
+ 0xbe63, 0x2431,
+ 0xbe64, 0x2085,
+ 0xbe65, 0x434b,
+ 0xbe69, 0x2435,
+ 0xbe6a, 0x434f,
+ 0xbe6c, 0x243b,
+ 0xbe6d, 0x4351,
+ 0xbe6f, 0x1fb7,
+ 0xbe70, 0x2433,
+ 0xbe71, 0x4353,
+ 0xbe76, 0x2054,
+ 0xbe77, 0x21de,
+ 0xbe78, 0x4358,
+ 0xbe79, 0x2434,
+ 0xbe7a, 0x4359,
+ 0xbe7c, 0x243d,
+ 0xbe7d, 0x1f89,
+ 0xbe7e, 0x243c,
+ 0xbe80, 0x435b,
+ 0xbe83, 0x1f6e,
+ 0xbe84, 0x1ed8,
+ 0xbe85, 0x435e,
+ 0xbe86, 0x1ebf,
+ 0xbe87, 0x2445,
+ 0xbe88, 0x435f,
+ 0xbe89, 0x2249,
+ 0xbe8a, 0x4360,
+ 0xbe8c, 0x2441,
+ 0xbe8d, 0x4362,
+ 0xbe8e, 0x1e47,
+ 0xbe8f, 0x1f56,
+ 0xbe90, 0x4363,
+ 0xbe92, 0x2086,
+ 0xbe93, 0x4365,
+ 0xbe95, 0x2196,
+ 0xbe96, 0x4367,
+ 0xbe97, 0x2443,
+ 0xbe98, 0x243f,
+ 0xbe99, 0x4368,
+ 0xbe9a, 0x2023,
+ 0xbe9b, 0x4369,
+ 0xbe9c, 0x2442,
+ 0xbe9d, 0x436a,
+ 0xbe9f, 0x243e,
+ 0xbea0, 0x436c,
+ 0xbea1, 0x08d0,
+ 0xbf40, 0x26a6,
+ 0xbf41, 0x436d,
+ 0xbf4d, 0x234e,
+ 0xbf4e, 0x2446,
+ 0xbf4f, 0x244b,
+ 0xbf50, 0x2444,
+ 0xbf51, 0x4379,
+ 0xbf55, 0x2427,
+ 0xbf56, 0x244c,
+ 0xbf57, 0x437d,
+ 0xbf60, 0x1f0f,
+ 0xbf61, 0x4386,
+ 0xbf62, 0x2447,
+ 0xbf63, 0x2449,
+ 0xbf64, 0x2448,
+ 0xbf65, 0x4387,
+ 0xbf68, 0x21c2,
+ 0xbf69, 0x438a,
+ 0xbf6c, 0x216e,
+ 0xbf6d, 0x438d,
+ 0xbf70, 0x1f03,
+ 0xbf71, 0x4390,
+ 0xbf72, 0x244a,
+ 0xbf73, 0x215c,
+ 0xbf74, 0x4391,
+ 0xbf76, 0x22bb,
+ 0xbf77, 0x2450,
+ 0xbf78, 0x4393,
+ 0xbf79, 0x2694,
+ 0xbf7a, 0x244f,
+ 0xbf7b, 0x25f6,
+ 0xbf7c, 0x2051,
+ 0xbf7d, 0x4394,
+ 0xbf7e, 0x244e,
+ 0xbf80, 0x4395,
+ 0xbf82, 0x22ba,
+ 0xbf83, 0x1f6d,
+ 0xbf84, 0x4397,
+ 0xbf89, 0x2452,
+ 0xbf8a, 0x2451,
+ 0xbf8b, 0x439c,
+ 0xbf95, 0x2455,
+ 0xbf96, 0x43a6,
+ 0xbf97, 0x2289,
+ 0xbf98, 0x2116,
+ 0xbf99, 0x43a7,
+ 0xbf9d, 0x2454,
+ 0xbf9e, 0x43ab,
+ 0xbfa1, 0x092e,
+ 0xc040, 0x20fb,
+ 0xc041, 0x43ae,
+ 0xc044, 0x2440,
+ 0xc045, 0x43b1,
+ 0xc04b, 0x2126,
+ 0xc04c, 0x1f61,
+ 0xc04d, 0x269d,
+ 0xc04e, 0x43b7,
+ 0xc04f, 0x1f8a,
+ 0xc050, 0x2456,
+ 0xc051, 0x2459,
+ 0xc052, 0x2458,
+ 0xc053, 0x43b8,
+ 0xc055, 0x1fae,
+ 0xc056, 0x43ba,
+ 0xc05b, 0x221a,
+ 0xc05c, 0x43bf,
+ 0xc05e, 0x1f7a,
+ 0xc05f, 0x244d,
+ 0xc060, 0x2457,
+ 0xc061, 0x43c1,
+ 0xc069, 0x2453,
+ 0xc06a, 0x43c9,
+ 0xc06b, 0x2420,
+ 0xc06c, 0x43ca,
+ 0xc06d, 0x21df,
+ 0xc06e, 0x2685,
+ 0xc06f, 0x43cb,
+ 0xc070, 0x1e6e,
+ 0xc071, 0x43cc,
+ 0xc074, 0x2224,
+ 0xc075, 0x2670,
+ 0xc076, 0x43cf,
+ 0xc077, 0x21ba,
+ 0xc078, 0x43d0,
+ 0xc079, 0x245a,
+ 0xc07a, 0x43d1,
+ 0xc07c, 0x1fff,
+ 0xc07d, 0x43d3,
+ 0xc080, 0x43d5,
+ 0xc09b, 0x25e2,
+ 0xc09c, 0x43f0,
+ 0xc09d, 0x269a,
+ 0xc09e, 0x43f1,
+ 0xc0a1, 0x098c,
+ 0xc140, 0x43f4,
+ 0xc150, 0x1eea,
+ 0xc151, 0x4404,
+ 0xc154, 0x1e2c,
+ 0xc155, 0x4407,
+ 0xc15f, 0x2062,
+ 0xc160, 0x24f1,
+ 0xc161, 0x4411,
+ 0xc162, 0x24f2,
+ 0xc163, 0x4412,
+ 0xc175, 0x25f2,
+ 0xc176, 0x4424,
+ 0xc178, 0x2215,
+ 0xc179, 0x4426,
+ 0xc180, 0x442c,
+ 0xc195, 0x21ae,
+ 0xc196, 0x4441,
+ 0xc1a1, 0x09ea,
+ 0xc240, 0x444c,
+ 0xc24e, 0x20e0,
+ 0xc24f, 0x445a,
+ 0xc265, 0x25c2,
+ 0xc266, 0x4470,
+ 0xc267, 0x25c1,
+ 0xc268, 0x4471,
+ 0xc27d, 0x2128,
+ 0xc27e, 0x4486,
+ 0xc280, 0x4487,
+ 0xc284, 0x2199,
+ 0xc285, 0x448b,
+ 0xc293, 0x2017,
+ 0xc294, 0x1ea0,
+ 0xc295, 0x2125,
+ 0xc296, 0x214d,
+ 0xc297, 0x4499,
+ 0xc298, 0x25c4,
+ 0xc299, 0x209d,
+ 0xc29a, 0x228a,
+ 0xc29b, 0x449a,
+ 0xc29c, 0x25c3,
+ 0xc29d, 0x449b,
+ 0xc2a0, 0x2179,
+ 0xc2a1, 0x0a48,
+ 0xc340, 0x2038,
+ 0xc341, 0x449e,
+ 0xc343, 0x2155,
+ 0xc344, 0x44a0,
+ 0xc37b, 0x21d2,
+ 0xc37c, 0x44d7,
+ 0xc380, 0x44da,
+ 0xc384, 0x24c7,
+ 0xc385, 0x44de,
+ 0xc39b, 0x2279,
+ 0xc39c, 0x44f4,
+ 0xc3a1, 0x0aa6,
+ 0xc440, 0x44f9,
+ 0xc449, 0x2123,
+ 0xc44a, 0x4502,
+ 0xc44c, 0x24c5,
+ 0xc44d, 0x4504,
+ 0xc454, 0x24c9,
+ 0xc455, 0x450b,
+ 0xc458, 0x2094,
+ 0xc459, 0x450e,
+ 0xc45b, 0x2296,
+ 0xc45c, 0x4510,
+ 0xc463, 0x1e77,
+ 0xc464, 0x4517,
+ 0xc477, 0x1f06,
+ 0xc478, 0x452a,
+ 0xc47a, 0x1fa5,
+ 0xc47b, 0x452c,
+ 0xc480, 0x4530,
+ 0xc481, 0x2099,
+ 0xc482, 0x4531,
+ 0xc491, 0x1ead,
+ 0xc492, 0x24c8,
+ 0xc493, 0x20a8,
+ 0xc494, 0x4540,
+ 0xc498, 0x201f,
+ 0xc499, 0x4544,
+ 0xc49a, 0x20c5,
+ 0xc49b, 0x4545,
+ 0xc49c, 0x24ca,
+ 0xc49d, 0x4546,
+ 0xc4a1, 0x0b04,
+ 0xc540, 0x454a,
+ 0xc544, 0x1ff0,
+ 0xc545, 0x454e,
+ 0xc546, 0x24c6,
+ 0xc547, 0x454f,
+ 0xc54b, 0x225d,
+ 0xc54c, 0x22de,
+ 0xc54d, 0x4553,
+ 0xc552, 0x202c,
+ 0xc553, 0x4558,
+ 0xc55f, 0x2161,
+ 0xc560, 0x4564,
+ 0xc563, 0x223b,
+ 0xc564, 0x21d9,
+ 0xc565, 0x1fcb,
+ 0xc566, 0x1fc9,
+ 0xc567, 0x4567,
+ 0xc580, 0x457f,
+ 0xc593, 0x1e61,
+ 0xc594, 0x4592,
+ 0xc59c, 0x25ef,
+ 0xc59d, 0x459a,
+ 0xc59e, 0x1f98,
+ 0xc59f, 0x459b,
+ 0xc5a1, 0x0b62,
+ 0xc640, 0x459d,
+ 0xc641, 0x25f0,
+ 0xc642, 0x459e,
+ 0xc644, 0x1f88,
+ 0xc645, 0x45a0,
+ 0xc647, 0x21f8,
+ 0xc648, 0x45a2,
+ 0xc663, 0x2322,
+ 0xc664, 0x45bd,
+ 0xc672, 0x2336,
+ 0xc673, 0x45cb,
+ 0xc680, 0x45d7,
+ 0xc6a1, 0x0bc0,
+ 0xc740, 0x45f8,
+ 0xc766, 0x22ab,
+ 0xc767, 0x461e,
+ 0xc76f, 0x1fbf,
+ 0xc770, 0x4626,
+ 0xc776, 0x1f7d,
+ 0xc777, 0x462c,
+ 0xc77b, 0x2333,
+ 0xc77c, 0x4630,
+ 0xc780, 0x4633,
+ 0xc7a1, 0x0c1e,
+ 0xc840, 0x4654,
+ 0xc841, 0x1f4d,
+ 0xc842, 0x4655,
+ 0xc84f, 0x2334,
+ 0xc850, 0x4662,
+ 0xc852, 0x1ff1,
+ 0xc853, 0x4664,
+ 0xc866, 0x218b,
+ 0xc867, 0x4677,
+ 0xc86e, 0x2349,
+ 0xc86f, 0x467e,
+ 0xc87e, 0x220b,
+ 0xc880, 0x468d,
+ 0xc887, 0x2346,
+ 0xc888, 0x4694,
+ 0xc892, 0x2347,
+ 0xc893, 0x469e,
+ 0xc894, 0x2193,
+ 0xc895, 0x469f,
+ 0xc899, 0x26a1,
+ 0xc89a, 0x46a3,
+ 0xc89d, 0x1f62,
+ 0xc89e, 0x46a6,
+ 0xc8a1, 0x0c7c,
+ 0xc940, 0x46a9,
+ 0xc94f, 0x234d,
+ 0xc950, 0x2348,
+ 0xc951, 0x46b8,
+ 0xc96e, 0x1e60,
+ 0xc96f, 0x46d5,
+ 0xc970, 0x2345,
+ 0xc971, 0x46d6,
+ 0xc977, 0x1f12,
+ 0xc978, 0x46dc,
+ 0xc980, 0x46e3,
+ 0xc98f, 0x2018,
+ 0xc990, 0x2335,
+ 0xc991, 0x46f2,
+ 0xc99c, 0x233c,
+ 0xc99d, 0x46fd,
+ 0xc9a1, 0x0cda,
+ 0xca40, 0x4701,
+ 0xca4e, 0x266f,
+ 0xca4f, 0x470f,
+ 0xca56, 0x2351,
+ 0xca57, 0x4716,
+ 0xca59, 0x1fa0,
+ 0xca5a, 0x4718,
+ 0xca5c, 0x2338,
+ 0xca5d, 0x471a,
+ 0xca61, 0x221b,
+ 0xca62, 0x471e,
+ 0xca6e, 0x2342,
+ 0xca6f, 0x472a,
+ 0xca72, 0x234f,
+ 0xca73, 0x472d,
+ 0xca77, 0x233d,
+ 0xca78, 0x4731,
+ 0xca7b, 0x2344,
+ 0xca7c, 0x2331,
+ 0xca7d, 0x4734,
+ 0xca7e, 0x234b,
+ 0xca80, 0x4735,
+ 0xca81, 0x233b,
+ 0xca82, 0x4736,
+ 0xca89, 0x2350,
+ 0xca8a, 0x473d,
+ 0xca8e, 0x1eb4,
+ 0xca8f, 0x21a6,
+ 0xca90, 0x4741,
+ 0xca92, 0x21cb,
+ 0xca93, 0x4743,
+ 0xca9a, 0x2355,
+ 0xca9b, 0x474a,
+ 0xcaa1, 0x0d38,
+ 0xcb40, 0x4750,
+ 0xcb43, 0x233e,
+ 0xcb44, 0x4753,
+ 0xcb45, 0x1f74,
+ 0xcb46, 0x4754,
+ 0xcb47, 0x2330,
+ 0xcb48, 0x4755,
+ 0xcb4b, 0x2680,
+ 0xcb4c, 0x4758,
+ 0xcb4e, 0x20da,
+ 0xcb4f, 0x475a,
+ 0xcb57, 0x234a,
+ 0xcb58, 0x4762,
+ 0xcb5d, 0x1f91,
+ 0xcb5e, 0x4767,
+ 0xcb5f, 0x2107,
+ 0xcb60, 0x4768,
+ 0xcb6a, 0x233f,
+ 0xcb6b, 0x4772,
+ 0xcb7b, 0x1ff4,
+ 0xcb7c, 0x2343,
+ 0xcb7d, 0x4782,
+ 0xcb80, 0x4784,
+ 0xcb87, 0x2212,
+ 0xcb88, 0x478b,
+ 0xcb8e, 0x2207,
+ 0xcb8f, 0x4791,
+ 0xcb92, 0x2359,
+ 0xcb93, 0x4794,
+ 0xcb9c, 0x2254,
+ 0xcb9d, 0x479d,
+ 0xcb9e, 0x2332,
+ 0xcb9f, 0x479e,
+ 0xcba1, 0x0d96,
+ 0xcc40, 0x1e26,
+ 0xcc41, 0x2357,
+ 0xcc42, 0x47a0,
+ 0xcc49, 0x2358,
+ 0xcc4a, 0x2042,
+ 0xcc4b, 0x2153,
+ 0xcc4c, 0x47a7,
+ 0xcc4f, 0x20bb,
+ 0xcc50, 0x47aa,
+ 0xcc5c, 0x235a,
+ 0xcc5d, 0x47b6,
+ 0xcc60, 0x2356,
+ 0xcc61, 0x47b9,
+ 0xcc64, 0x2337,
+ 0xcc65, 0x47bc,
+ 0xcc6d, 0x1ff9,
+ 0xcc6e, 0x47c4,
+ 0xcc79, 0x2353,
+ 0xcc7a, 0x47cf,
+ 0xcc7d, 0x2061,
+ 0xcc7e, 0x47d2,
+ 0xcc80, 0x47d3,
+ 0xcc8e, 0x1e95,
+ 0xcc8f, 0x47e1,
+ 0xcc94, 0x2049,
+ 0xcc95, 0x47e6,
+ 0xcc96, 0x1f42,
+ 0xcc97, 0x47e7,
+ 0xcc9d, 0x1fe8,
+ 0xcc9e, 0x47ed,
+ 0xcca1, 0x0df4,
+ 0xcd40, 0x47f0,
+ 0xcd80, 0x482f,
+ 0xcd90, 0x25da,
+ 0xcd91, 0x483f,
+ 0xcd98, 0x25d7,
+ 0xcd99, 0x4846,
+ 0xcda1, 0x0e52,
+ 0xce40, 0x484e,
+ 0xce67, 0x212e,
+ 0xce68, 0x4875,
+ 0xce72, 0x21b2,
+ 0xce73, 0x487f,
+ 0xce80, 0x488b,
+ 0xce81, 0x219e,
+ 0xce82, 0x488c,
+ 0xce87, 0x25dc,
+ 0xce88, 0x4891,
+ 0xce9b, 0x206c,
+ 0xce9c, 0x48a4,
+ 0xce9e, 0x2226,
+ 0xce9f, 0x48a6,
+ 0xcea1, 0x0eb0,
+ 0xcf40, 0x48a8,
+ 0xcf4e, 0x25e0,
+ 0xcf4f, 0x48b6,
+ 0xcf55, 0x227b,
+ 0xcf56, 0x48bc,
+ 0xcf58, 0x25de,
+ 0xcf59, 0x48be,
+ 0xcf5c, 0x25e1,
+ 0xcf5d, 0x48c1,
+ 0xcf6c, 0x25d5,
+ 0xcf6d, 0x48d0,
+ 0xcf73, 0x1e6b,
+ 0xcf74, 0x48d6,
+ 0xcf75, 0x25db,
+ 0xcf76, 0x48d7,
+ 0xcf78, 0x1e89,
+ 0xcf79, 0x48d9,
+ 0xcf7c, 0x25d9,
+ 0xcf7d, 0x48dc,
+ 0xcf80, 0x48de,
+ 0xcf81, 0x2211,
+ 0xcf82, 0x48df,
+ 0xcf89, 0x2229,
+ 0xcf8a, 0x25d6,
+ 0xcf8b, 0x48e6,
+ 0xcf93, 0x25dd,
+ 0xcf94, 0x25df,
+ 0xcf95, 0x48ee,
+ 0xcf9e, 0x1fef,
+ 0xcf9f, 0x48f7,
+ 0xcfa0, 0x25d8,
+ 0xcfa1, 0x0f0e,
+ 0xd040, 0x48f8,
+ 0xd04d, 0x1f29,
+ 0xd04e, 0x4905,
+ 0xd051, 0x1e5b,
+ 0xd052, 0x4908,
+ 0xd055, 0x2076,
+ 0xd056, 0x490b,
+ 0xd05c, 0x2297,
+ 0xd05d, 0x4911,
+ 0xd060, 0x2690,
+ 0xd061, 0x4914,
+ 0xd067, 0x213f,
+ 0xd068, 0x491a,
+ 0xd06c, 0x2198,
+ 0xd06d, 0x491e,
+ 0xd06e, 0x1e88,
+ 0xd06f, 0x491f,
+ 0xd07d, 0x228c,
+ 0xd07e, 0x492d,
+ 0xd080, 0x492e,
+ 0xd0a1, 0x0f6c,
+ 0xd140, 0x494f,
+ 0xd155, 0x25f1,
+ 0xd156, 0x4964,
+ 0xd159, 0x200c,
+ 0xd15a, 0x4967,
+ 0xd161, 0x1e58,
+ 0xd162, 0x22ac,
+ 0xd163, 0x496e,
+ 0xd175, 0x26a7,
+ 0xd176, 0x4980,
+ 0xd17d, 0x2676,
+ 0xd17e, 0x4987,
+ 0xd180, 0x4988,
+ 0xd19d, 0x1fe1,
+ 0xd19e, 0x25bb,
+ 0xd19f, 0x49a5,
+ 0xd1a1, 0x0fca,
+ 0xd240, 0x25be,
+ 0xd241, 0x49a7,
+ 0xd243, 0x22dd,
+ 0xd244, 0x49a9,
+ 0xd24d, 0x25bd,
+ 0xd24e, 0x49b2,
+ 0xd25c, 0x1e2a,
+ 0xd25d, 0x49c0,
+ 0xd263, 0x25bc,
+ 0xd264, 0x25ba,
+ 0xd265, 0x49c6,
+ 0xd268, 0x25bf,
+ 0xd269, 0x49c9,
+ 0xd26d, 0x2187,
+ 0xd26e, 0x49cd,
+ 0xd26f, 0x266b,
+ 0xd270, 0x49ce,
+ 0xd272, 0x1e7f,
+ 0xd273, 0x49d0,
+ 0xd275, 0x21ad,
+ 0xd276, 0x49d2,
+ 0xd280, 0x49db,
+ 0xd28a, 0x1f96,
+ 0xd28b, 0x49e5,
+ 0xd28e, 0x1f32,
+ 0xd28f, 0x49e8,
+ 0xd292, 0x2084,
+ 0xd293, 0x49eb,
+ 0xd295, 0x2136,
+ 0xd296, 0x49ed,
+ 0xd297, 0x24b8,
+ 0xd298, 0x49ee,
+ 0xd2a0, 0x24ba,
+ 0xd2a1, 0x1028,
+ 0xd340, 0x49f6,
+ 0xd344, 0x24bc,
+ 0xd345, 0x49fa,
+ 0xd348, 0x20e4,
+ 0xd349, 0x49fd,
+ 0xd34a, 0x24b9,
+ 0xd34b, 0x49fe,
+ 0xd34d, 0x24bd,
+ 0xd34e, 0x4a00,
+ 0xd350, 0x24be,
+ 0xd351, 0x4a02,
+ 0xd355, 0x24bf,
+ 0xd356, 0x4a06,
+ 0xd358, 0x1fd2,
+ 0xd359, 0x4a08,
+ 0xd35b, 0x1ffd,
+ 0xd35c, 0x4a0a,
+ 0xd35d, 0x24bb,
+ 0xd35e, 0x1f2d,
+ 0xd35f, 0x4a0b,
+ 0xd378, 0x2609,
+ 0xd379, 0x4a24,
+ 0xd37a, 0x260a,
+ 0xd37b, 0x4a25,
+ 0xd37c, 0x1e94,
+ 0xd37d, 0x4a26,
+ 0xd380, 0x4a28,
+ 0xd385, 0x22df,
+ 0xd386, 0x1ecb,
+ 0xd387, 0x1f0d,
+ 0xd388, 0x4a2d,
+ 0xd38b, 0x1f77,
+ 0xd38c, 0x4a30,
+ 0xd38d, 0x21eb,
+ 0xd38e, 0x4a31,
+ 0xd38f, 0x22e1,
+ 0xd390, 0x4a32,
+ 0xd391, 0x216f,
+ 0xd392, 0x4a33,
+ 0xd393, 0x22e0,
+ 0xd394, 0x4a34,
+ 0xd396, 0x21ea,
+ 0xd397, 0x4a36,
+ 0xd398, 0x22e2,
+ 0xd399, 0x20cb,
+ 0xd39a, 0x4a37,
+ 0xd39b, 0x1f78,
+ 0xd39c, 0x4a38,
+ 0xd39e, 0x1ee2,
+ 0xd39f, 0x4a3a,
+ 0xd3a0, 0x21f2,
+ 0xd3a1, 0x1086,
+ 0xd440, 0x4a3b,
+ 0xd441, 0x2150,
+ 0xd442, 0x4a3c,
+ 0xd445, 0x1fd3,
+ 0xd446, 0x4a3f,
+ 0xd447, 0x22e5,
+ 0xd448, 0x4a40,
+ 0xd44c, 0x1ef2,
+ 0xd44d, 0x4a44,
+ 0xd44f, 0x211f,
+ 0xd450, 0x4a46,
+ 0xd453, 0x21dd,
+ 0xd454, 0x4a49,
+ 0xd456, 0x2154,
+ 0xd457, 0x4a4b,
+ 0xd458, 0x22e7,
+ 0xd459, 0x4a4c,
+ 0xd45c, 0x2282,
+ 0xd45d, 0x4a4f,
+ 0xd462, 0x22e6,
+ 0xd463, 0x4a54,
+ 0xd467, 0x22e8,
+ 0xd468, 0x4a58,
+ 0xd46e, 0x22e4,
+ 0xd46f, 0x4a5e,
+ 0xd470, 0x226a,
+ 0xd471, 0x4a5f,
+ 0xd472, 0x22eb,
+ 0xd473, 0x4a60,
+ 0xd474, 0x22e9,
+ 0xd475, 0x20bd,
+ 0xd476, 0x4a61,
+ 0xd478, 0x22ea,
+ 0xd479, 0x4a63,
+ 0xd47b, 0x22bd,
+ 0xd47c, 0x4a65,
+ 0xd47e, 0x1e9e,
+ 0xd480, 0x4a67,
+ 0xd482, 0x22f6,
+ 0xd483, 0x21e7,
+ 0xd484, 0x2216,
+ 0xd485, 0x4a69,
+ 0xd487, 0x2137,
+ 0xd488, 0x4a6b,
+ 0xd48a, 0x212c,
+ 0xd48b, 0x4a6d,
+ 0xd48c, 0x1e68,
+ 0xd48d, 0x22f2,
+ 0xd48e, 0x1f37,
+ 0xd48f, 0x22f3,
+ 0xd490, 0x4a6e,
+ 0xd491, 0x22ef,
+ 0xd492, 0x1f50,
+ 0xd493, 0x1f10,
+ 0xd494, 0x21c8,
+ 0xd495, 0x4a6f,
+ 0xd496, 0x22f1,
+ 0xd497, 0x4a70,
+ 0xd49c, 0x22f0,
+ 0xd49d, 0x4a75,
+ 0xd49f, 0x22ee,
+ 0xd4a0, 0x4a77,
+ 0xd4a1, 0x10e4,
+ 0xd540, 0x4a78,
+ 0xd543, 0x22ed,
+ 0xd544, 0x229e,
+ 0xd545, 0x22ec,
+ 0xd546, 0x1fe2,
+ 0xd547, 0x4a7b,
+ 0xd54a, 0x20fe,
+ 0xd54b, 0x4a7e,
+ 0xd54e, 0x22f9,
+ 0xd550, 0x4a81,
+ 0xd551, 0x1eaf,
+ 0xd552, 0x4a82,
+ 0xd554, 0x2236,
+ 0xd555, 0x4a84,
+ 0xd556, 0x22f7,
+ 0xd557, 0x4a85,
+ 0xd55a, 0x223d,
+ 0xd55b, 0x4a88,
+ 0xd55c, 0x1e82,
+ 0xd55d, 0x1fb6,
+ 0xd55e, 0x4a89,
+ 0xd55f, 0x21a4,
+ 0xd560, 0x21aa,
+ 0xd561, 0x22f8,
+ 0xd562, 0x2151,
+ 0xd563, 0x4a8a,
+ 0xd564, 0x1f60,
+ 0xd565, 0x4a8b,
+ 0xd568, 0x2147,
+ 0xd569, 0x4a8e,
+ 0xd56c, 0x2145,
+ 0xd56d, 0x4a91,
+ 0xd56e, 0x1fdc,
+ 0xd56f, 0x4a92,
+ 0xd572, 0x2301,
+ 0xd573, 0x4a95,
+ 0xd575, 0x1ef5,
+ 0xd576, 0x4a97,
+ 0xd578, 0x2218,
+ 0xd579, 0x4a99,
+ 0xd57b, 0x1ec6,
+ 0xd57c, 0x4a9b,
+ 0xd57e, 0x2300,
+ 0xd580, 0x4a9d,
+ 0xd581, 0x22b4,
+ 0xd582, 0x4a9e,
+ 0xd584, 0x2169,
+ 0xd585, 0x4aa0,
+ 0xd586, 0x22fd,
+ 0xd587, 0x4aa1,
+ 0xd588, 0x20ea,
+ 0xd589, 0x4aa2,
+ 0xd58a, 0x22f4,
+ 0xd58b, 0x4aa3,
+ 0xd58c, 0x22fb,
+ 0xd58d, 0x4aa4,
+ 0xd58e, 0x22fc,
+ 0xd58f, 0x2027,
+ 0xd590, 0x4aa5,
+ 0xd593, 0x2060,
+ 0xd594, 0x22ff,
+ 0xd595, 0x4aa8,
+ 0xd598, 0x22fe,
+ 0xd599, 0x1ec7,
+ 0xd59a, 0x4aab,
+ 0xd59b, 0x230c,
+ 0xd59c, 0x4aac,
+ 0xd59f, 0x22f5,
+ 0xd5a0, 0x4aaf,
+ 0xd5a1, 0x1142,
+ 0xd640, 0x2306,
+ 0xd641, 0x4ab0,
+ 0xd642, 0x230a,
+ 0xd643, 0x21d3,
+ 0xd644, 0x4ab1,
+ 0xd647, 0x2303,
+ 0xd648, 0x4ab4,
+ 0xd649, 0x2307,
+ 0xd64a, 0x230b,
+ 0xd64b, 0x4ab5,
+ 0xd64d, 0x1f5f,
+ 0xd64e, 0x4ab7,
+ 0xd64f, 0x2309,
+ 0xd650, 0x4ab8,
+ 0xd652, 0x2302,
+ 0xd653, 0x1f04,
+ 0xd654, 0x229d,
+ 0xd655, 0x4aba,
+ 0xd656, 0x21fb,
+ 0xd657, 0x4abb,
+ 0xd658, 0x2308,
+ 0xd659, 0x4abc,
+ 0xd65a, 0x20ac,
+ 0xd65b, 0x4abd,
+ 0xd65c, 0x208e,
+ 0xd65d, 0x2305,
+ 0xd65e, 0x2197,
+ 0xd65f, 0x4abe,
+ 0xd660, 0x2171,
+ 0xd661, 0x2298,
+ 0xd662, 0x4abf,
+ 0xd665, 0x1f57,
+ 0xd666, 0x4ac2,
+ 0xd669, 0x2082,
+ 0xd66a, 0x4ac5,
+ 0xd66b, 0x2311,
+ 0xd66c, 0x4ac6,
+ 0xd66f, 0x2304,
+ 0xd670, 0x4ac9,
+ 0xd671, 0x230f,
+ 0xd672, 0x1e35,
+ 0xd673, 0x4aca,
+ 0xd674, 0x20d1,
+ 0xd675, 0x2310,
+ 0xd676, 0x1fa3,
+ 0xd677, 0x4acb,
+ 0xd678, 0x21d6,
+ 0xd679, 0x4acc,
+ 0xd67c, 0x2206,
+ 0xd67d, 0x4acf,
+ 0xd680, 0x4ad1,
+ 0xd683, 0x230d,
+ 0xd684, 0x4ad4,
+ 0xd686, 0x2312,
+ 0xd687, 0x208d,
+ 0xd688, 0x2313,
+ 0xd689, 0x4ad6,
+ 0xd68e, 0x22e3,
+ 0xd68f, 0x4adb,
+ 0xd694, 0x1fba,
+ 0xd695, 0x4ae0,
+ 0xd699, 0x2078,
+ 0xd69a, 0x4ae4,
+ 0xd6a1, 0x11a0,
+ 0xd740, 0x4aeb,
+ 0xd743, 0x2288,
+ 0xd744, 0x4aee,
+ 0xd748, 0x2316,
+ 0xd749, 0x1f6b,
+ 0xd74a, 0x4af2,
+ 0xd750, 0x2314,
+ 0xd751, 0x4af8,
+ 0xd752, 0x2130,
+ 0xd753, 0x2315,
+ 0xd754, 0x2168,
+ 0xd755, 0x4af9,
+ 0xd756, 0x20c4,
+ 0xd757, 0x4afa,
+ 0xd764, 0x2318,
+ 0xd765, 0x4b07,
+ 0xd767, 0x2219,
+ 0xd768, 0x2217,
+ 0xd769, 0x4b09,
+ 0xd76c, 0x20d5,
+ 0xd76d, 0x4b0c,
+ 0xd76f, 0x1f4a,
+ 0xd770, 0x4b0e,
+ 0xd775, 0x2240,
+ 0xd776, 0x4b13,
+ 0xd778, 0x1ed3,
+ 0xd779, 0x4b15,
+ 0xd780, 0x4b1b,
+ 0xd783, 0x1e49,
+ 0xd784, 0x4b1e,
+ 0xd787, 0x261b,
+ 0xd788, 0x4b21,
+ 0xd78b, 0x1e6d,
+ 0xd78c, 0x20f8,
+ 0xd78d, 0x4b24,
+ 0xd78e, 0x1ffb,
+ 0xd78f, 0x2319,
+ 0xd790, 0x4b25,
+ 0xd795, 0x230e,
+ 0xd796, 0x4b2a,
+ 0xd797, 0x2317,
+ 0xd798, 0x4b2b,
+ 0xd7a1, 0x11fe,
+ 0xd840, 0x4b34,
+ 0xd84d, 0x20c8,
+ 0xd84e, 0x4b41,
+ 0xd853, 0x1efd,
+ 0xd854, 0x4b46,
+ 0xd880, 0x4b71,
+ 0xd890, 0x1e3b,
+ 0xd891, 0x227f,
+ 0xd892, 0x4b81,
+ 0xd893, 0x1f0c,
+ 0xd894, 0x1e59,
+ 0xd895, 0x1f24,
+ 0xd896, 0x4b82,
+ 0xd89a, 0x20ba,
+ 0xd89b, 0x1f65,
+ 0xd89c, 0x1ef0,
+ 0xd89d, 0x2164,
+ 0xd89e, 0x1f30,
+ 0xd89f, 0x2261,
+ 0xd8a0, 0x4b86,
+ 0xd8a1, 0x1257,
+ 0xd940, 0x4b87,
+ 0xd941, 0x22a2,
+ 0xd942, 0x24ab,
+ 0xd943, 0x4b88,
+ 0xd944, 0x24af,
+ 0xd945, 0x1ee8,
+ 0xd946, 0x1f39,
+ 0xd947, 0x4b89,
+ 0xd948, 0x1e48,
+ 0xd949, 0x2070,
+ 0xd94a, 0x1ea8,
+ 0xd94b, 0x4b8a,
+ 0xd94c, 0x24ac,
+ 0xd94d, 0x1ef7,
+ 0xd94e, 0x2176,
+ 0xd94f, 0x24ad,
+ 0xd950, 0x4b8b,
+ 0xd951, 0x207b,
+ 0xd952, 0x1f45,
+ 0xd953, 0x24aa,
+ 0xd954, 0x204b,
+ 0xd955, 0x202f,
+ 0xd956, 0x1f5a,
+ 0xd957, 0x24b0,
+ 0xd958, 0x4b8c,
+ 0xd959, 0x22b7,
+ 0xd95a, 0x1f7f,
+ 0xd95b, 0x4b8d,
+ 0xd95c, 0x2265,
+ 0xd95d, 0x4b8e,
+ 0xd963, 0x24b2,
+ 0xd964, 0x211b,
+ 0xd965, 0x1e51,
+ 0xd966, 0x4b94,
+ 0xd967, 0x24b4,
+ 0xd968, 0x4b95,
+ 0xd96c, 0x24b3,
+ 0xd96d, 0x4b99,
+ 0xd96e, 0x1e9f,
+ 0xd96f, 0x4b9a,
+ 0xd970, 0x2118,
+ 0xd971, 0x4b9b,
+ 0xd972, 0x20b4,
+ 0xd973, 0x23af,
+ 0xd974, 0x21bb,
+ 0xd975, 0x2072,
+ 0xd976, 0x1f95,
+ 0xd977, 0x4b9c,
+ 0xd978, 0x1f0a,
+ 0xd979, 0x24b6,
+ 0xd97a, 0x4b9d,
+ 0xd97c, 0x2291,
+ 0xd97d, 0x24b5,
+ 0xd97e, 0x2278,
+ 0xd980, 0x1ed4,
+ 0xd981, 0x4b9f,
+ 0xd987, 0x1ff3,
+ 0xd988, 0x4ba5,
+ 0xd98d, 0x22a9,
+ 0xd98e, 0x24b7,
+ 0xd98f, 0x1f28,
+ 0xd990, 0x2109,
+ 0xd991, 0x22c7,
+ 0xd992, 0x4baa,
+ 0xd997, 0x24ae,
+ 0xd998, 0x22b1,
+ 0xd999, 0x4baf,
+ 0xd99b, 0x2266,
+ 0xd99c, 0x4bb1,
+ 0xd99d, 0x225b,
+ 0xd99e, 0x22c4,
+ 0xd99f, 0x4bb2,
+ 0xd9a0, 0x2115,
+ 0xd9a1, 0x12b5,
+ 0xda40, 0x4bb3,
+ 0xda41, 0x222a,
+ 0xda42, 0x24b1,
+ 0xda43, 0x4bb4,
+ 0xda48, 0x213d,
+ 0xda49, 0x4bb9,
+ 0xda4d, 0x1f15,
+ 0xda4e, 0x225c,
+ 0xda4f, 0x4bbd,
+ 0xda73, 0x1f14,
+ 0xda74, 0x4be1,
+ 0xda77, 0x227a,
+ 0xda78, 0x4be4,
+ 0xda80, 0x4beb,
+ 0xda85, 0x20ee,
+ 0xda86, 0x4bf0,
+ 0xda8e, 0x25f8,
+ 0xda8f, 0x4bf8,
+ 0xdaa1, 0x1313,
+ 0xdb40, 0x4c0a,
+ 0xdb60, 0x1f94,
+ 0xdb61, 0x4c2a,
+ 0xdb78, 0x2230,
+ 0xdb79, 0x4c41,
+ 0xdb80, 0x4c47,
+ 0xdb84, 0x25fd,
+ 0xdb85, 0x4c4b,
+ 0xdb8b, 0x2600,
+ 0xdb8c, 0x4c51,
+ 0xdb98, 0x2606,
+ 0xdb99, 0x4c5d,
+ 0xdba1, 0x1371,
+ 0xdc40, 0x4c65,
+ 0xdc45, 0x25ff,
+ 0xdc46, 0x4c6a,
+ 0xdc4f, 0x25fc,
+ 0xdc50, 0x1e8c,
+ 0xdc51, 0x2602,
+ 0xdc52, 0x4c73,
+ 0xdc53, 0x224d,
+ 0xdc54, 0x4c74,
+ 0xdc55, 0x2604,
+ 0xdc56, 0x25fe,
+ 0xdc57, 0x2603,
+ 0xdc58, 0x4c75,
+ 0xdc5d, 0x2601,
+ 0xdc5e, 0x4c7a,
+ 0xdc62, 0x2605,
+ 0xdc63, 0x4c7e,
+ 0xdc66, 0x1ea3,
+ 0xdc67, 0x2608,
+ 0xdc68, 0x4c81,
+ 0xdc6b, 0x2607,
+ 0xdc6c, 0x4c84,
+ 0xdc7c, 0x20f0,
+ 0xdc7d, 0x4c94,
+ 0xdc80, 0x4c96,
+ 0xdc87, 0x1e7b,
+ 0xdc88, 0x2267,
+ 0xdc89, 0x1f36,
+ 0xdc8a, 0x1fd6,
+ 0xdc8b, 0x4c9d,
+ 0xdc8e, 0x21e0,
+ 0xdc8f, 0x4ca0,
+ 0xdc90, 0x248c,
+ 0xdc91, 0x4ca1,
+ 0xdc97, 0x248d,
+ 0xdc98, 0x4ca7,
+ 0xdc9b, 0x2102,
+ 0xdc9c, 0x4caa,
+ 0xdca0, 0x2494,
+ 0xdca1, 0x13cf,
+ 0xdd40, 0x4cae,
+ 0xdd46, 0x2493,
+ 0xdd47, 0x4cb4,
+ 0xdd4d, 0x248e,
+ 0xdd4e, 0x4cba,
+ 0xdd53, 0x2299,
+ 0xdd54, 0x2491,
+ 0xdd55, 0x2496,
+ 0xdd56, 0x248f,
+ 0xdd57, 0x2492,
+ 0xdd58, 0x4cbf,
+ 0xdd59, 0x2497,
+ 0xdd5a, 0x4cc0,
+ 0xdd5e, 0x1fb1,
+ 0xdd5f, 0x4cc4,
+ 0xdd60, 0x249a,
+ 0xdd61, 0x4cc5,
+ 0xdd62, 0x2499,
+ 0xdd63, 0x4cc6,
+ 0xdd64, 0x2258,
+ 0xdd65, 0x2498,
+ 0xdd66, 0x4cc7,
+ 0xdd6d, 0x249b,
+ 0xdd6e, 0x4cce,
+ 0xdd6f, 0x1f09,
+ 0xdd70, 0x20e6,
+ 0xdd71, 0x4ccf,
+ 0xdd76, 0x2026,
+ 0xdd77, 0x249f,
+ 0xdd78, 0x1f59,
+ 0xdd79, 0x249d,
+ 0xdd7b, 0x4cd4,
+ 0xdd80, 0x4cd8,
+ 0xdd81, 0x1f3b,
+ 0xdd82, 0x249c,
+ 0xdd83, 0x4cd9,
+ 0xdd85, 0x1e3a,
+ 0xdd86, 0x205b,
+ 0xdd87, 0x4cdb,
+ 0xdd8b, 0x1f70,
+ 0xdd8c, 0x4cdf,
+ 0xdd8f, 0x24a0,
+ 0xdd90, 0x4ce2,
+ 0xdd94, 0x213b,
+ 0xdd95, 0x4ce6,
+ 0xdd97, 0x1f07,
+ 0xdd98, 0x4ce8,
+ 0xdd9a, 0x2270,
+ 0xdd9b, 0x2237,
+ 0xdd9c, 0x4cea,
+ 0xdd9e, 0x24d2,
+ 0xdd9f, 0x4cec,
+ 0xdda0, 0x21b3,
+ 0xdda1, 0x142d,
+ 0xde40, 0x2245,
+ 0xde41, 0x24a1,
+ 0xde42, 0x4ced,
+ 0xde44, 0x22a8,
+ 0xde45, 0x4cef,
+ 0xde48, 0x227c,
+ 0xde49, 0x1fb0,
+ 0xde4a, 0x4cf2,
+ 0xde4f, 0x24a2,
+ 0xde50, 0x4cf7,
+ 0xde5a, 0x1f46,
+ 0xde5b, 0x4d01,
+ 0xde5c, 0x2380,
+ 0xde5d, 0x2495,
+ 0xde5e, 0x4d02,
+ 0xde5f, 0x2490,
+ 0xde60, 0x4d03,
+ 0xde6b, 0x1e30,
+ 0xde6c, 0x4d0e,
+ 0xde6f, 0x1e9d,
+ 0xde70, 0x1e4b,
+ 0xde71, 0x1e4a,
+ 0xde72, 0x20aa,
+ 0xde73, 0x4d11,
+ 0xde80, 0x4d1d,
+ 0xde92, 0x267b,
+ 0xde93, 0x4d2f,
+ 0xde9f, 0x23f2,
+ 0xdea0, 0x4d3b,
+ 0xdea1, 0x148b,
+ 0xdf40, 0x227e,
+ 0xdf41, 0x4d3c,
+ 0xdf42, 0x2019,
+ 0xdf43, 0x4d3d,
+ 0xdf4d, 0x1fbb,
+ 0xdf4e, 0x4d47,
+ 0xdf5c, 0x2253,
+ 0xdf5d, 0x4d55,
+ 0xdf5e, 0x1f3e,
+ 0xdf5f, 0x1ea6,
+ 0xdf60, 0x218e,
+ 0xdf61, 0x4d56,
+ 0xdf64, 0x21ec,
+ 0xdf65, 0x4d59,
+ 0xdf66, 0x1ebe,
+ 0xdf67, 0x4d5a,
+ 0xdf68, 0x224a,
+ 0xdf69, 0x4d5b,
+ 0xdf6d, 0x2133,
+ 0xdf6e, 0x4d5f,
+ 0xdf74, 0x1e84,
+ 0xdf75, 0x4d65,
+ 0xdf77, 0x20cf,
+ 0xdf78, 0x21e2,
+ 0xdf79, 0x4d67,
+ 0xdf7a, 0x220f,
+ 0xdf7b, 0x4d68,
+ 0xdf7c, 0x2029,
+ 0xdf7d, 0x4d69,
+ 0xdf7e, 0x2073,
+ 0xdf80, 0x1f55,
+ 0xdf81, 0x4d6a,
+ 0xdf83, 0x23f1,
+ 0xdf84, 0x4d6c,
+ 0xdf85, 0x1e46,
+ 0xdf86, 0x4d6d,
+ 0xdf89, 0x2063,
+ 0xdf8a, 0x23f3,
+ 0xdf8b, 0x4d70,
+ 0xdfa1, 0x14e9,
+ 0xe040, 0x4d86,
+ 0xe050, 0x231e,
+ 0xe051, 0x4d96,
+ 0xe05d, 0x2233,
+ 0xe05e, 0x4da2,
+ 0xe069, 0x2320,
+ 0xe06a, 0x4dad,
+ 0xe06c, 0x21c7,
+ 0xe06d, 0x4daf,
+ 0xe075, 0x22bc,
+ 0xe076, 0x4db7,
+ 0xe077, 0x231c,
+ 0xe078, 0x4db8,
+ 0xe079, 0x2251,
+ 0xe07a, 0x4db9,
+ 0xe080, 0x4dbe,
+ 0xe087, 0x1ebb,
+ 0xe088, 0x4dc5,
+ 0xe08d, 0x2287,
+ 0xe08e, 0x4dca,
+ 0xe08f, 0x202d,
+ 0xe090, 0x1eab,
+ 0xe091, 0x4dcb,
+ 0xe092, 0x231d,
+ 0xe093, 0x4dcc,
+ 0xe094, 0x231f,
+ 0xe095, 0x4dcd,
+ 0xe097, 0x231b,
+ 0xe098, 0x4dcf,
+ 0xe0a1, 0x1547,
+ 0xe140, 0x4dd8,
+ 0xe142, 0x2321,
+ 0xe143, 0x4dda,
+ 0xe164, 0x2255,
+ 0xe165, 0x4dfb,
+ 0xe168, 0x1e8f,
+ 0xe169, 0x4dfe,
+ 0xe174, 0x220c,
+ 0xe175, 0x1fa4,
+ 0xe176, 0x4e09,
+ 0xe180, 0x4e12,
+ 0xe184, 0x209b,
+ 0xe185, 0x21d8,
+ 0xe186, 0x4e16,
+ 0xe187, 0x25fa,
+ 0xe188, 0x4e17,
+ 0xe189, 0x25f9,
+ 0xe18a, 0x4e18,
+ 0xe18c, 0x2134,
+ 0xe18d, 0x4e1a,
+ 0xe18e, 0x24f3,
+ 0xe191, 0x24f8,
+ 0xe192, 0x4e1b,
+ 0xe193, 0x24f7,
+ 0xe194, 0x1ec8,
+ 0xe195, 0x24f6,
+ 0xe196, 0x4e1c,
+ 0xe198, 0x2280,
+ 0xe199, 0x4e1e,
+ 0xe19e, 0x1ec5,
+ 0xe19f, 0x24fb,
+ 0xe1a0, 0x4e23,
+ 0xe1a1, 0x15a5,
+ 0xe240, 0x4e24,
+ 0xe241, 0x24fa,
+ 0xe242, 0x4e25,
+ 0xe243, 0x1eed,
+ 0xe244, 0x4e26,
+ 0xe24f, 0x24fd,
+ 0xe250, 0x4e31,
+ 0xe251, 0x24f9,
+ 0xe252, 0x4e32,
+ 0xe253, 0x24fe,
+ 0xe254, 0x20cd,
+ 0xe255, 0x4e33,
+ 0xe25a, 0x2508,
+ 0xe25b, 0x2504,
+ 0xe25c, 0x4e38,
+ 0xe25e, 0x2506,
+ 0xe25f, 0x4e3a,
+ 0xe262, 0x24ff,
+ 0xe263, 0x2090,
+ 0xe264, 0x4e3d,
+ 0xe267, 0x1edd,
+ 0xe268, 0x1f25,
+ 0xe269, 0x4e40,
+ 0xe26a, 0x2503,
+ 0xe26b, 0x2502,
+ 0xe26c, 0x4e41,
+ 0xe26e, 0x1e7a,
+ 0xe26f, 0x20a6,
+ 0xe270, 0x4e43,
+ 0xe278, 0x1fd5,
+ 0xe279, 0x4e4b,
+ 0xe27d, 0x1f11,
+ 0xe27e, 0x4e4f,
+ 0xe280, 0x2507,
+ 0xe281, 0x2500,
+ 0xe282, 0x2505,
+ 0xe283, 0x4e50,
+ 0xe289, 0x2519,
+ 0xe28a, 0x4e56,
+ 0xe28b, 0x2515,
+ 0xe28c, 0x4e57,
+ 0xe28e, 0x250c,
+ 0xe28f, 0x2031,
+ 0xe290, 0x4e59,
+ 0xe292, 0x250b,
+ 0xe293, 0x250f,
+ 0xe294, 0x251a,
+ 0xe295, 0x2509,
+ 0xe296, 0x4e5b,
+ 0xe298, 0x250e,
+ 0xe299, 0x2234,
+ 0xe29a, 0x2513,
+ 0xe29b, 0x1f80,
+ 0xe29c, 0x4e5d,
+ 0xe2a0, 0x2501,
+ 0xe2a1, 0x1603,
+ 0xe340, 0x4e61,
+ 0xe342, 0x2517,
+ 0xe343, 0x2516,
+ 0xe344, 0x4e63,
+ 0xe347, 0x2518,
+ 0xe348, 0x4e66,
+ 0xe34b, 0x1e56,
+ 0xe34c, 0x4e69,
+ 0xe34f, 0x250d,
+ 0xe350, 0x4e6c,
+ 0xe351, 0x20d3,
+ 0xe352, 0x4e6d,
+ 0xe354, 0x207a,
+ 0xe355, 0x20ce,
+ 0xe356, 0x4e6f,
+ 0xe358, 0x2510,
+ 0xe359, 0x4e71,
+ 0xe35c, 0x1e55,
+ 0xe35d, 0x4e74,
+ 0xe360, 0x250a,
+ 0xe361, 0x4e77,
+ 0xe366, 0x2511,
+ 0xe368, 0x4e7c,
+ 0xe371, 0x1faa,
+ 0xe372, 0x4e85,
+ 0xe373, 0x251e,
+ 0xe374, 0x1f1f,
+ 0xe375, 0x4e86,
+ 0xe378, 0x252d,
+ 0xe379, 0x221d,
+ 0xe37a, 0x4e89,
+ 0xe37c, 0x2532,
+ 0xe37d, 0x4e8b,
+ 0xe37e, 0x217b,
+ 0xe380, 0x4e8c,
+ 0xe38a, 0x21af,
+ 0xe38b, 0x4e96,
+ 0xe38c, 0x252c,
+ 0xe38d, 0x4e97,
+ 0xe38f, 0x2528,
+ 0xe390, 0x4e99,
+ 0xe391, 0x208c,
+ 0xe392, 0x4e9a,
+ 0xe393, 0x252f,
+ 0xe394, 0x4e9b,
+ 0xe395, 0x21bc,
+ 0xe396, 0x4e9c,
+ 0xe399, 0x251d,
+ 0xe39a, 0x4e9f,
+ 0xe39c, 0x2535,
+ 0xe39d, 0x4ea1,
+ 0xe39e, 0x220d,
+ 0xe39f, 0x2526,
+ 0xe3a0, 0x4ea2,
+ 0xe3a1, 0x1661,
+ 0xe440, 0x2534,
+ 0xe441, 0x252a,
+ 0xe442, 0x251f,
+ 0xe443, 0x2531,
+ 0xe444, 0x251c,
+ 0xe445, 0x4ea3,
+ 0xe448, 0x2525,
+ 0xe449, 0x4ea6,
+ 0xe44e, 0x21cd,
+ 0xe44f, 0x4eab,
+ 0xe450, 0x21da,
+ 0xe451, 0x4eac,
+ 0xe452, 0x2172,
+ 0xe453, 0x253e,
+ 0xe454, 0x4ead,
+ 0xe458, 0x204f,
+ 0xe459, 0x4eb1,
+ 0xe45a, 0x2543,
+ 0xe45b, 0x4eb2,
+ 0xe45c, 0x21d7,
+ 0xe45d, 0x4eb3,
+ 0xe45e, 0x1e3c,
+ 0xe45f, 0x4eb4,
+ 0xe462, 0x2529,
+ 0xe463, 0x4eb7,
+ 0xe465, 0x2521,
+ 0xe466, 0x4eb9,
+ 0xe468, 0x1eff,
+ 0xe469, 0x4ebb,
+ 0xe473, 0x253f,
+ 0xe474, 0x4ec5,
+ 0xe475, 0x2544,
+ 0xe476, 0x4ec6,
+ 0xe479, 0x2523,
+ 0xe47a, 0x1e90,
+ 0xe47b, 0x253a,
+ 0xe47c, 0x2545,
+ 0xe47d, 0x4ec9,
+ 0xe47e, 0x253d,
+ 0xe480, 0x4eca,
+ 0xe481, 0x20c1,
+ 0xe482, 0x4ecb,
+ 0xe484, 0x2103,
+ 0xe485, 0x2520,
+ 0xe486, 0x253c,
+ 0xe487, 0x253b,
+ 0xe488, 0x2538,
+ 0xe489, 0x4ecd,
+ 0xe48d, 0x2540,
+ 0xe48e, 0x4ed1,
+ 0xe48f, 0x1fcd,
+ 0xe490, 0x4ed2,
+ 0xe493, 0x1f18,
+ 0xe494, 0x4ed5,
+ 0xe498, 0x254b,
+ 0xe499, 0x4ed9,
+ 0xe49d, 0x2547,
+ 0xe49e, 0x254f,
+ 0xe4a0, 0x4edd,
+ 0xe4a1, 0x16bf,
+ 0xe540, 0x4ede,
+ 0xe546, 0x22b0,
+ 0xe547, 0x4ee4,
+ 0xe548, 0x2546,
+ 0xe549, 0x4ee5,
+ 0xe54b, 0x254c,
+ 0xe54c, 0x4ee7,
+ 0xe54e, 0x1e9a,
+ 0xe54f, 0x2552,
+ 0xe550, 0x2530,
+ 0xe551, 0x2549,
+ 0xe552, 0x4ee9,
+ 0xe555, 0x2551,
+ 0xe556, 0x1eca,
+ 0xe557, 0x4eec,
+ 0xe558, 0x20d2,
+ 0xe559, 0x4eed,
+ 0xe55c, 0x1fb8,
+ 0xe55d, 0x4ef0,
+ 0xe55e, 0x2079,
+ 0xe55f, 0x4ef1,
+ 0xe561, 0x21ab,
+ 0xe562, 0x4ef3,
+ 0xe564, 0x254d,
+ 0xe565, 0x1ea5,
+ 0xe566, 0x4ef5,
+ 0xe568, 0x204c,
+ 0xe569, 0x2080,
+ 0xe56a, 0x4ef7,
+ 0xe56c, 0x266d,
+ 0xe56d, 0x4ef9,
+ 0xe56e, 0x2537,
+ 0xe56f, 0x4efa,
+ 0xe575, 0x254a,
+ 0xe576, 0x21b8,
+ 0xe577, 0x4f00,
+ 0xe578, 0x254e,
+ 0xe579, 0x4f01,
+ 0xe57b, 0x24fc,
+ 0xe57c, 0x2554,
+ 0xe57d, 0x4f03,
+ 0xe580, 0x4f05,
+ 0xe581, 0x1f3c,
+ 0xe582, 0x4f06,
+ 0xe583, 0x1ed5,
+ 0xe584, 0x4f07,
+ 0xe58a, 0x2556,
+ 0xe58b, 0x4f0d,
+ 0xe58e, 0x2268,
+ 0xe58f, 0x4f10,
+ 0xe591, 0x1ed6,
+ 0xe592, 0x4f12,
+ 0xe59a, 0x2557,
+ 0xe59b, 0x2553,
+ 0xe59c, 0x4f1a,
+ 0xe59f, 0x2548,
+ 0xe5a0, 0x4f1d,
+ 0xe5a1, 0x171d,
+ 0xe640, 0x20dc,
+ 0xe641, 0x4f1e,
+ 0xe644, 0x2559,
+ 0xe645, 0x4f21,
+ 0xe649, 0x1f97,
+ 0xe64a, 0x2555,
+ 0xe64b, 0x4f25,
+ 0xe64e, 0x227d,
+ 0xe64f, 0x4f28,
+ 0xe652, 0x257e,
+ 0xe653, 0x4f2b,
+ 0xe656, 0x207c,
+ 0xe657, 0x4f2e,
+ 0xe658, 0x255a,
+ 0xe659, 0x4f2f,
+ 0xe65b, 0x255e,
+ 0xe65c, 0x4f31,
+ 0xe65e, 0x1e34,
+ 0xe65f, 0x4f33,
+ 0xe669, 0x215e,
+ 0xe66a, 0x4f3d,
+ 0xe66b, 0x2560,
+ 0xe66c, 0x4f3e,
+ 0xe675, 0x21a2,
+ 0xe676, 0x2354,
+ 0xe677, 0x4f47,
+ 0xe679, 0x2563,
+ 0xe67a, 0x2527,
+ 0xe67b, 0x4f49,
+ 0xe67c, 0x252e,
+ 0xe67d, 0x2558,
+ 0xe67e, 0x4f4a,
+ 0xe680, 0x1f1b,
+ 0xe681, 0x4f4b,
+ 0xe682, 0x2283,
+ 0xe683, 0x4f4c,
+ 0xe684, 0x2564,
+ 0xe685, 0x4f4d,
+ 0xe687, 0x20a0,
+ 0xe688, 0x4f4f,
+ 0xe689, 0x2565,
+ 0xe68a, 0x4f50,
+ 0xe68c, 0x2561,
+ 0xe68d, 0x4f52,
+ 0xe693, 0x2562,
+ 0xe694, 0x4f58,
+ 0xe697, 0x256c,
+ 0xe698, 0x4f5b,
+ 0xe69b, 0x256d,
+ 0xe69c, 0x2020,
+ 0xe69d, 0x4f5e,
+ 0xe69f, 0x255f,
+ 0xe6a0, 0x256a,
+ 0xe6a1, 0x177b,
+ 0xe740, 0x4f60,
+ 0xe743, 0x256e,
+ 0xe744, 0x4f63,
+ 0xe748, 0x2539,
+ 0xe749, 0x255c,
+ 0xe74a, 0x4f67,
+ 0xe74d, 0x2568,
+ 0xe74f, 0x256b,
+ 0xe750, 0x1e6f,
+ 0xe751, 0x4f6a,
+ 0xe752, 0x1fc4,
+ 0xe753, 0x2567,
+ 0xe754, 0x4f6b,
+ 0xe755, 0x255b,
+ 0xe756, 0x4f6c,
+ 0xe759, 0x261d,
+ 0xe75a, 0x4f6f,
+ 0xe766, 0x252b,
+ 0xe767, 0x4f7b,
+ 0xe768, 0x2571,
+ 0xe769, 0x4f7c,
+ 0xe76a, 0x2577,
+ 0xe76b, 0x4f7d,
+ 0xe774, 0x2522,
+ 0xe775, 0x4f86,
+ 0xe77c, 0x2533,
+ 0xe77d, 0x4f8d,
+ 0xe780, 0x4f8f,
+ 0xe782, 0x202a,
+ 0xe783, 0x4f91,
+ 0xe784, 0x2536,
+ 0xe785, 0x2573,
+ 0xe786, 0x256f,
+ 0xe787, 0x4f92,
+ 0xe78a, 0x2293,
+ 0xe78b, 0x2578,
+ 0xe78c, 0x4f95,
+ 0xe78f, 0x2570,
+ 0xe790, 0x4f98,
+ 0xe792, 0x2575,
+ 0xe793, 0x4f9a,
+ 0xe798, 0x2541,
+ 0xe79a, 0x255d,
+ 0xe79b, 0x4f9f,
+ 0xe7a0, 0x201a,
+ 0xe7a1, 0x17d9,
+ 0xe840, 0x4fa4,
+ 0xe843, 0x257a,
+ 0xe844, 0x2006,
+ 0xe845, 0x4fa7,
+ 0xe846, 0x2177,
+ 0xe847, 0x4fa8,
+ 0xe849, 0x251b,
+ 0xe84a, 0x4faa,
+ 0xe84b, 0x2524,
+ 0xe84c, 0x4fab,
+ 0xe84f, 0x257b,
+ 0xe850, 0x4fae,
+ 0xe854, 0x22a3,
+ 0xe855, 0x4fb2,
+ 0xe85a, 0x2579,
+ 0xe85b, 0x4fb7,
+ 0xe85c, 0x2566,
+ 0xe85d, 0x4fb8,
+ 0xe862, 0x1f93,
+ 0xe863, 0x4fbd,
+ 0xe864, 0x257c,
+ 0xe865, 0x4fbe,
+ 0xe870, 0x2514,
+ 0xe871, 0x4fc9,
+ 0xe873, 0x257d,
+ 0xe874, 0x4fcb,
+ 0xe875, 0x2572,
+ 0xe876, 0x4fcc,
+ 0xe87c, 0x2574,
+ 0xe87d, 0x4fd2,
+ 0xe880, 0x224e,
+ 0xe881, 0x4fd4,
+ 0xe882, 0x21c6,
+ 0xe883, 0x4fd5,
+ 0xe887, 0x209f,
+ 0xe888, 0x4fd9,
+ 0xe889, 0x2576,
+ 0xe88a, 0x4fda,
+ 0xe88c, 0x2064,
+ 0xe88d, 0x22bf,
+ 0xe88e, 0x261c,
+ 0xe88f, 0x225e,
+ 0xe890, 0x4fdc,
+ 0xe8a1, 0x1837,
+ 0xe940, 0x4fed,
+ 0xe94c, 0x1e75,
+ 0xe94d, 0x4ff9,
+ 0xe954, 0x207d,
+ 0xe955, 0x5000,
+ 0xe956, 0x23bf,
+ 0xe957, 0x2113,
+ 0xe958, 0x5001,
+ 0xe95a, 0x23c0,
+ 0xe95b, 0x5003,
+ 0xe95d, 0x1e45,
+ 0xe95e, 0x5005,
+ 0xe95f, 0x1fd8,
+ 0xe960, 0x23c4,
+ 0xe961, 0x5006,
+ 0xe962, 0x23c2,
+ 0xe963, 0x2104,
+ 0xe964, 0x5007,
+ 0xe965, 0x21bd,
+ 0xe966, 0x5008,
+ 0xe967, 0x1f87,
+ 0xe968, 0x23c3,
+ 0xe969, 0x5009,
+ 0xe96c, 0x2269,
+ 0xe96d, 0x500c,
+ 0xe975, 0x1f43,
+ 0xe976, 0x5014,
+ 0xe977, 0x1f1e,
+ 0xe978, 0x2679,
+ 0xe979, 0x1eeb,
+ 0xe97a, 0x5015,
+ 0xe97c, 0x1f35,
+ 0xe97d, 0x208a,
+ 0xe97e, 0x5017,
+ 0xe980, 0x23c7,
+ 0xe981, 0x23c9,
+ 0xe982, 0x23c6,
+ 0xe983, 0x5018,
+ 0xe987, 0x224f,
+ 0xe988, 0x501c,
+ 0xe98b, 0x23cb,
+ 0xe98c, 0x501f,
+ 0xe98e, 0x21f3,
+ 0xe98f, 0x5021,
+ 0xe990, 0x21f7,
+ 0xe991, 0x23cf,
+ 0xe992, 0x23ce,
+ 0xe993, 0x23ca,
+ 0xe994, 0x23cd,
+ 0xe995, 0x5022,
+ 0xe998, 0x23d0,
+ 0xe999, 0x5025,
+ 0xe99b, 0x266c,
+ 0xe99c, 0x5027,
+ 0xe99d, 0x23c1,
+ 0xe99e, 0x5028,
+ 0xe99f, 0x1fee,
+ 0xe9a0, 0x23d1,
+ 0xe9a1, 0x1895,
+ 0xea40, 0x1ff8,
+ 0xea41, 0x5029,
+ 0xea44, 0x23d3,
+ 0xea45, 0x502c,
+ 0xea48, 0x23d2,
+ 0xea49, 0x23d4,
+ 0xea4a, 0x1e98,
+ 0xea4b, 0x502f,
+ 0xea50, 0x1f2c,
+ 0xea51, 0x5034,
+ 0xea52, 0x23d5,
+ 0xea53, 0x5035,
+ 0xea55, 0x1e71,
+ 0xea56, 0x2691,
+ 0xea57, 0x5037,
+ 0xea59, 0x23c5,
+ 0xea5a, 0x5039,
+ 0xea80, 0x231a,
+ 0xea81, 0x505e,
+ 0xea84, 0x2114,
+ 0xea85, 0x5061,
+ 0xea87, 0x2284,
+ 0xea88, 0x5063,
+ 0xea8e, 0x221c,
+ 0xea8f, 0x5069,
+ 0xea90, 0x1e7e,
+ 0xea91, 0x204d,
+ 0xea92, 0x506a,
+ 0xea96, 0x2201,
+ 0xea97, 0x506e,
+ 0xeaa0, 0x1ed9,
+ 0xeaa1, 0x18f3,
+ 0xeb40, 0x5077,
+ 0xeb41, 0x1fb2,
+ 0xeb42, 0x5078,
+ 0xeb45, 0x2252,
+ 0xeb46, 0x507b,
+ 0xeb48, 0x1f79,
+ 0xeb49, 0x507d,
+ 0xeb53, 0x2157,
+ 0xeb54, 0x5087,
+ 0xeb55, 0x21bf,
+ 0xeb56, 0x5088,
+ 0xeb5b, 0x221f,
+ 0xeb5c, 0x508d,
+ 0xeb5d, 0x203d,
+ 0xeb5e, 0x508e,
+ 0xeb60, 0x2015,
+ 0xeb61, 0x5090,
+ 0xeb62, 0x26a5,
+ 0xeb63, 0x5091,
+ 0xeb6d, 0x2156,
+ 0xeb6e, 0x509b,
+ 0xeb70, 0x2144,
+ 0xeb71, 0x509d,
+ 0xeb72, 0x1e91,
+ 0xeb73, 0x2257,
+ 0xeb74, 0x509e,
+ 0xeb78, 0x200a,
+ 0xeb79, 0x2092,
+ 0xeb7a, 0x50a2,
+ 0xeb80, 0x50a7,
+ 0xeb85, 0x2250,
+ 0xeb86, 0x50ac,
+ 0xeb8a, 0x1ec3,
+ 0xeb8b, 0x50b0,
+ 0xeba1, 0x1951,
+ 0xec40, 0x50c6,
+ 0xec46, 0x21a8,
+ 0xec47, 0x50cc,
+ 0xec56, 0x260d,
+ 0xec57, 0x50db,
+ 0xec5a, 0x260c,
+ 0xec5b, 0x50de,
+ 0xec5c, 0x260e,
+ 0xec5d, 0x50df,
+ 0xec60, 0x2032,
+ 0xec61, 0x50e2,
+ 0xec6e, 0x260b,
+ 0xec6f, 0x50ef,
+ 0xec76, 0x22c3,
+ 0xec77, 0x50f6,
+ 0xec80, 0x50fe,
+ 0xec96, 0x1f23,
+ 0xec97, 0x5114,
+ 0xeca1, 0x19af,
+ 0xed40, 0x511e,
+ 0xed46, 0x2695,
+ 0xed47, 0x5124,
+ 0xed58, 0x265e,
+ 0xed59, 0x5135,
+ 0xed5e, 0x265d,
+ 0xed5f, 0x513a,
+ 0xed61, 0x2692,
+ 0xed62, 0x513c,
+ 0xed64, 0x265f,
+ 0xed65, 0x513e,
+ 0xed66, 0x218d,
+ 0xed67, 0x20fd,
+ 0xed68, 0x513f,
+ 0xed6e, 0x1f40,
+ 0xed6f, 0x5145,
+ 0xed74, 0x2465,
+ 0xed75, 0x514a,
+ 0xed77, 0x2467,
+ 0xed78, 0x514c,
+ 0xed79, 0x2466,
+ 0xed7a, 0x514d,
+ 0xed80, 0x5152,
+ 0xed91, 0x21c9,
+ 0xed92, 0x5163,
+ 0xed93, 0x2209,
+ 0xed94, 0x1ec9,
+ 0xed95, 0x20e9,
+ 0xed96, 0x5164,
+ 0xed97, 0x21ca,
+ 0xed98, 0x2146,
+ 0xed99, 0x25c5,
+ 0xed9a, 0x21dc,
+ 0xed9b, 0x5165,
+ 0xed9c, 0x245e,
+ 0xed9d, 0x5166,
+ 0xed9e, 0x214f,
+ 0xed9f, 0x5167,
+ 0xeda0, 0x25c6,
+ 0xeda1, 0x1a0d,
+ 0xee40, 0x25c7,
+ 0xee41, 0x2241,
+ 0xee42, 0x218a,
+ 0xee43, 0x1e2f,
+ 0xee44, 0x1edc,
+ 0xee45, 0x5168,
+ 0xee48, 0x20bf,
+ 0xee49, 0x2034,
+ 0xee4a, 0x516b,
+ 0xee4d, 0x25c9,
+ 0xee4e, 0x516e,
+ 0xee52, 0x25c8,
+ 0xee53, 0x5172,
+ 0xee55, 0x220e,
+ 0xee56, 0x5174,
+ 0xee57, 0x25cb,
+ 0xee58, 0x5175,
+ 0xee5e, 0x217d,
+ 0xee5f, 0x517b,
+ 0xee61, 0x1f7e,
+ 0xee62, 0x517d,
+ 0xee68, 0x25cc,
+ 0xee69, 0x1fc3,
+ 0xee6a, 0x5183,
+ 0xee6c, 0x20b9,
+ 0xee6d, 0x5185,
+ 0xee6e, 0x2181,
+ 0xee6f, 0x5186,
+ 0xee77, 0x1fda,
+ 0xee78, 0x518e,
+ 0xee7d, 0x2173,
+ 0xee7e, 0x1ee1,
+ 0xee80, 0x25cd,
+ 0xee81, 0x5193,
+ 0xee85, 0x25ce,
+ 0xee86, 0x21f6,
+ 0xee87, 0x5197,
+ 0xee8a, 0x224b,
+ 0xee8b, 0x25d1,
+ 0xee8c, 0x519a,
+ 0xee8d, 0x1ec0,
+ 0xee8e, 0x519b,
+ 0xee90, 0x2008,
+ 0xee91, 0x519d,
+ 0xee94, 0x25d0,
+ 0xee95, 0x51a0,
+ 0xee97, 0x25d2,
+ 0xee98, 0x51a2,
+ 0xee99, 0x1f2a,
+ 0xee9a, 0x51a3,
+ 0xee9d, 0x1e72,
+ 0xee9e, 0x25d3,
+ 0xee9f, 0x51a6,
+ 0xeea1, 0x1a6b,
+ 0xef40, 0x21be,
+ 0xef41, 0x25d4,
+ 0xef42, 0x2044,
+ 0xef43, 0x51a8,
+ 0xef44, 0x25cf,
+ 0xef45, 0x20f3,
+ 0xef46, 0x51a9,
+ 0xef4c, 0x1f00,
+ 0xef4d, 0x51af,
+ 0xef52, 0x24cc,
+ 0xef54, 0x51b4,
+ 0xef55, 0x2698,
+ 0xef56, 0x51b5,
+ 0xef57, 0x2678,
+ 0xef58, 0x51b6,
+ 0xef5a, 0x24ce,
+ 0xef5b, 0x51b8,
+ 0xef60, 0x24cf,
+ 0xef61, 0x51bd,
+ 0xef68, 0x20b8,
+ 0xef69, 0x51c4,
+ 0xef6a, 0x24d0,
+ 0xef6b, 0x51c5,
+ 0xef6c, 0x24d1,
+ 0xef6d, 0x51c6,
+ 0xef77, 0x1ef4,
+ 0xef78, 0x51d0,
+ 0xef7a, 0x239b,
+ 0xef7b, 0x51d2,
+ 0xef7c, 0x267e,
+ 0xef7d, 0x51d3,
+ 0xef80, 0x51d5,
+ 0xef82, 0x239d,
+ 0xef83, 0x239f,
+ 0xef85, 0x51d7,
+ 0xef86, 0x23a1,
+ 0xef87, 0x51d8,
+ 0xef88, 0x1ef1,
+ 0xef89, 0x51d9,
+ 0xef8b, 0x221e,
+ 0xef8c, 0x51db,
+ 0xef8d, 0x23a2,
+ 0xef8e, 0x51dc,
+ 0xef95, 0x214b,
+ 0xef96, 0x1e36,
+ 0xef97, 0x2135,
+ 0xef98, 0x51e3,
+ 0xef9c, 0x1fad,
+ 0xef9d, 0x51e7,
+ 0xef9e, 0x1e53,
+ 0xef9f, 0x51e8,
+ 0xefa1, 0x1ac9,
+ 0xf040, 0x51ea,
+ 0xf041, 0x23a3,
+ 0xf042, 0x2203,
+ 0xf043, 0x51eb,
+ 0xf044, 0x1ee7,
+ 0xf045, 0x51ec,
+ 0xf047, 0x23a4,
+ 0xf048, 0x2097,
+ 0xf049, 0x1ee4,
+ 0xf04a, 0x51ee,
+ 0xf04e, 0x2238,
+ 0xf04f, 0x51f2,
+ 0xf051, 0x23a5,
+ 0xf052, 0x51f4,
+ 0xf054, 0x1f9a,
+ 0xf055, 0x51f6,
+ 0xf057, 0x21c3,
+ 0xf058, 0x51f8,
+ 0xf05e, 0x1f2e,
+ 0xf05f, 0x51fe,
+ 0xf068, 0x239c,
+ 0xf069, 0x5207,
+ 0xf06c, 0x23a6,
+ 0xf06d, 0x520a,
+ 0xf071, 0x239e,
+ 0xf072, 0x520e,
+ 0xf073, 0x2035,
+ 0xf074, 0x23a7,
+ 0xf075, 0x520f,
+ 0xf078, 0x23a8,
+ 0xf079, 0x5212,
+ 0xf07a, 0x2075,
+ 0xf07b, 0x5213,
+ 0xf07d, 0x23a9,
+ 0xf080, 0x23ab,
+ 0xf081, 0x1feb,
+ 0xf082, 0x23ac,
+ 0xf083, 0x5215,
+ 0xf087, 0x1f6a,
+ 0xf088, 0x20f9,
+ 0xf089, 0x5219,
+ 0xf08b, 0x2666,
+ 0xf08c, 0x521b,
+ 0xf090, 0x2667,
+ 0xf091, 0x521f,
+ 0xf092, 0x1e6c,
+ 0xf093, 0x5220,
+ 0xf096, 0x23ad,
+ 0xf097, 0x5223,
+ 0xf0a1, 0x1b27,
+ 0xf140, 0x522d,
+ 0xf152, 0x206d,
+ 0xf153, 0x2242,
+ 0xf154, 0x1f02,
+ 0xf155, 0x523f,
+ 0xf157, 0x2183,
+ 0xf158, 0x5241,
+ 0xf159, 0x1e85,
+ 0xf15a, 0x21e9,
+ 0xf15b, 0x5242,
+ 0xf167, 0x1e57,
+ 0xf168, 0x524e,
+ 0xf176, 0x22a5,
+ 0xf177, 0x2407,
+ 0xf178, 0x1fca,
+ 0xf179, 0x525c,
+ 0xf17a, 0x2402,
+ 0xf17b, 0x1f82,
+ 0xf17c, 0x525d,
+ 0xf17e, 0x2408,
+ 0xf180, 0x2404,
+ 0xf181, 0x525f,
+ 0xf182, 0x2131,
+ 0xf183, 0x5260,
+ 0xf184, 0x2184,
+ 0xf185, 0x5261,
+ 0xf186, 0x2403,
+ 0xf187, 0x5262,
+ 0xf188, 0x206e,
+ 0xf189, 0x240b,
+ 0xf18a, 0x5263,
+ 0xf194, 0x1f3f,
+ 0xf195, 0x526d,
+ 0xf198, 0x2067,
+ 0xf199, 0x5270,
+ 0xf1a1, 0x1b85,
+ 0xf240, 0x5278,
+ 0xf245, 0x1fd7,
+ 0xf246, 0x527d,
+ 0xf247, 0x1e83,
+ 0xf248, 0x527e,
+ 0xf24b, 0x240f,
+ 0xf24c, 0x5281,
+ 0xf253, 0x240e,
+ 0xf254, 0x20c7,
+ 0xf255, 0x240d,
+ 0xf256, 0x5288,
+ 0xf25c, 0x2412,
+ 0xf25d, 0x528e,
+ 0xf25f, 0x20b7,
+ 0xf260, 0x5290,
+ 0xf271, 0x23f0,
+ 0xf272, 0x52a1,
+ 0xf273, 0x2411,
+ 0xf274, 0x2414,
+ 0xf275, 0x52a2,
+ 0xf276, 0x2170,
+ 0xf277, 0x52a3,
+ 0xf27c, 0x2405,
+ 0xf27d, 0x210c,
+ 0xf27e, 0x2415,
+ 0xf280, 0x52a8,
+ 0xf285, 0x2066,
+ 0xf286, 0x52ad,
+ 0xf287, 0x2352,
+ 0xf288, 0x2413,
+ 0xf289, 0x2410,
+ 0xf28a, 0x2416,
+ 0xf28c, 0x20f1,
+ 0xf28d, 0x52ae,
+ 0xf291, 0x240a,
+ 0xf292, 0x52b2,
+ 0xf294, 0x2409,
+ 0xf295, 0x52b4,
+ 0xf296, 0x2418,
+ 0xf297, 0x52b5,
+ 0xf29c, 0x1fa7,
+ 0xf29d, 0x52ba,
+ 0xf29e, 0x21fc,
+ 0xf29f, 0x52bb,
+ 0xf2a1, 0x1be3,
+ 0xf340, 0x1fc1,
+ 0xf341, 0x2406,
+ 0xf342, 0x52bd,
+ 0xf345, 0x229c,
+ 0xf346, 0x52c0,
+ 0xf348, 0x204e,
+ 0xf349, 0x52c2,
+ 0xf34a, 0x241a,
+ 0xf34b, 0x2419,
+ 0xf34c, 0x52c3,
+ 0xf350, 0x240c,
+ 0xf351, 0x52c7,
+ 0xf361, 0x1e29,
+ 0xf362, 0x52d7,
+ 0xf374, 0x2661,
+ 0xf375, 0x52e9,
+ 0xf376, 0x26a4,
+ 0xf377, 0x2174,
+ 0xf378, 0x2663,
+ 0xf379, 0x2662,
+ 0xf37a, 0x52ea,
+ 0xf380, 0x52ef,
+ 0xf38c, 0x2675,
+ 0xf38d, 0x52fb,
+ 0xf3a0, 0x214c,
+ 0xf3a1, 0x1c41,
+ 0xf440, 0x530e,
+ 0xf445, 0x267a,
+ 0xf446, 0x5313,
+ 0xf450, 0x26a0,
+ 0xf451, 0x531d,
+ 0xf457, 0x2668,
+ 0xf458, 0x5323,
+ 0xf459, 0x1ed0,
+ 0xf45a, 0x5324,
+ 0xf45b, 0x2096,
+ 0xf45c, 0x5325,
+ 0xf45d, 0x23cc,
+ 0xf45e, 0x5326,
+ 0xf462, 0x23c8,
+ 0xf463, 0x532a,
+ 0xf464, 0x223e,
+ 0xf465, 0x532b,
+ 0xf475, 0x2665,
+ 0xf476, 0x533b,
+ 0xf47c, 0x2664,
+ 0xf47d, 0x5341,
+ 0xf47e, 0x2239,
+ 0xf480, 0x5342,
+ 0xf494, 0x204a,
+ 0xf495, 0x5356,
+ 0xf499, 0x261f,
+ 0xf49a, 0x535a,
+ 0xf49c, 0x261e,
+ 0xf49d, 0x535c,
+ 0xf4a1, 0x1c9f,
+ 0xf540, 0x5360,
+ 0xf545, 0x2620,
+ 0xf546, 0x5365,
+ 0xf547, 0x2621,
+ 0xf548, 0x5366,
+ 0xf552, 0x2622,
+ 0xf553, 0x5370,
+ 0xf554, 0x2627,
+ 0xf555, 0x1e39,
+ 0xf556, 0x2625,
+ 0xf557, 0x5371,
+ 0xf55e, 0x2629,
+ 0xf55f, 0x5378,
+ 0xf561, 0x262e,
+ 0xf562, 0x262b,
+ 0xf563, 0x537a,
+ 0xf56e, 0x262a,
+ 0xf56f, 0x262d,
+ 0xf570, 0x5385,
+ 0xf571, 0x2628,
+ 0xf572, 0x21b9,
+ 0xf573, 0x5386,
+ 0xf580, 0x5392,
+ 0xf585, 0x2636,
+ 0xf586, 0x2630,
+ 0xf587, 0x5397,
+ 0xf58c, 0x2638,
+ 0xf58d, 0x539c,
+ 0xf58e, 0x200d,
+ 0xf58f, 0x2637,
+ 0xf590, 0x539d,
+ 0xf599, 0x2645,
+ 0xf59a, 0x53a6,
+ 0xf59b, 0x263a,
+ 0xf59c, 0x53a7,
+ 0xf5a0, 0x2643,
+ 0xf5a1, 0x1cfd,
+ 0xf640, 0x53ab,
+ 0xf641, 0x2640,
+ 0xf642, 0x53ac,
+ 0xf645, 0x263d,
+ 0xf646, 0x2641,
+ 0xf647, 0x53af,
+ 0xf648, 0x263e,
+ 0xf649, 0x53b0,
+ 0xf64b, 0x263f,
+ 0xf64c, 0x1fc0,
+ 0xf64d, 0x53b2,
+ 0xf64e, 0x263b,
+ 0xf650, 0x53b3,
+ 0xf654, 0x2642,
+ 0xf655, 0x53b7,
+ 0xf658, 0x2644,
+ 0xf659, 0x53ba,
+ 0xf661, 0x2639,
+ 0xf662, 0x53c2,
+ 0xf663, 0x264c,
+ 0xf664, 0x53c3,
+ 0xf66c, 0x2647,
+ 0xf66d, 0x264b,
+ 0xf66e, 0x53cb,
+ 0xf671, 0x2649,
+ 0xf672, 0x53ce,
+ 0xf674, 0x2648,
+ 0xf675, 0x53d0,
+ 0xf676, 0x264a,
+ 0xf677, 0x2108,
+ 0xf678, 0x53d1,
+ 0xf680, 0x53d8,
+ 0xf685, 0x264d,
+ 0xf686, 0x53dd,
+ 0xf688, 0x2634,
+ 0xf689, 0x53df,
+ 0xf68a, 0x2651,
+ 0xf68b, 0x53e0,
+ 0xf68d, 0x2650,
+ 0xf68e, 0x2652,
+ 0xf68f, 0x53e2,
+ 0xf692, 0x264f,
+ 0xf693, 0x53e5,
+ 0xf696, 0x2632,
+ 0xf697, 0x264e,
+ 0xf698, 0x2653,
+ 0xf699, 0x53e8,
+ 0xf69a, 0x2657,
+ 0xf69b, 0x53e9,
+ 0xf69c, 0x2635,
+ 0xf69d, 0x53ea,
+ 0xf69e, 0x2633,
+ 0xf69f, 0x53eb,
+ 0xf6a0, 0x2656,
+ 0xf6a1, 0x1d5b,
+ 0xf740, 0x53ec,
+ 0xf742, 0x2654,
+ 0xf743, 0x53ee,
+ 0xf749, 0x2658,
+ 0xf74a, 0x53f4,
+ 0xf74c, 0x2655,
+ 0xf74d, 0x1e4d,
+ 0xf74e, 0x53f6,
+ 0xf756, 0x265b,
+ 0xf757, 0x53fe,
+ 0xf758, 0x265a,
+ 0xf759, 0x53ff,
+ 0xf75a, 0x2659,
+ 0xf75b, 0x202e,
+ 0xf75c, 0x262f,
+ 0xf75d, 0x5400,
+ 0xf761, 0x2646,
+ 0xf762, 0x5404,
+ 0xf763, 0x2626,
+ 0xf764, 0x5405,
+ 0xf76b, 0x265c,
+ 0xf76c, 0x540c,
+ 0xf771, 0x262c,
+ 0xf772, 0x5411,
+ 0xf77c, 0x2623,
+ 0xf77d, 0x541b,
+ 0xf77e, 0x2631,
+ 0xf780, 0x541c,
+ 0xf7a1, 0x1db9,
+ 0xf840, 0x543d,
+ 0xf842, 0x209c,
+ 0xf843, 0x543f,
+ 0xf846, 0x2580,
+ 0xf847, 0x5442,
+ 0xf849, 0x22dc,
+ 0xf84a, 0x5444,
+ 0xf850, 0x1f05,
+ 0xf851, 0x208b,
+ 0xf852, 0x544a,
+ 0xf853, 0x2581,
+ 0xf854, 0x544b,
+ 0xf863, 0x2583,
+ 0xf864, 0x2582,
+ 0xf865, 0x545a,
+ 0xf866, 0x21ee,
+ 0xf867, 0x545b,
+ 0xf872, 0x2182,
+ 0xf873, 0x5466,
+ 0xf878, 0x2243,
+ 0xf879, 0x546b,
+ 0xf87a, 0x2587,
+ 0xf87b, 0x546c,
+ 0xf87c, 0x2588,
+ 0xf87d, 0x546d,
+ 0xf880, 0x546f,
+ 0xf881, 0x2584,
+ 0xf882, 0x5470,
+ 0xf884, 0x21fd,
+ 0xf885, 0x5472,
+ 0xf886, 0x21ef,
+ 0xf887, 0x5473,
+ 0xf88d, 0x258a,
+ 0xf88e, 0x258c,
+ 0xf88f, 0x5479,
+ 0xf899, 0x1f47,
+ 0xf89a, 0x5483,
+ 0xf89d, 0x1f1d,
+ 0xf89e, 0x5486,
+ 0xf8a0, 0x258d,
+ 0xf940, 0x5488,
+ 0xf94e, 0x1fd0,
+ 0xf94f, 0x2592,
+ 0xf950, 0x258f,
+ 0xf951, 0x5496,
+ 0xf959, 0x2594,
+ 0xf95a, 0x1ee0,
+ 0xf95b, 0x549e,
+ 0xf95d, 0x2591,
+ 0xf95e, 0x2595,
+ 0xf95f, 0x54a0,
+ 0xf967, 0x2597,
+ 0xf968, 0x54a8,
+ 0xf969, 0x20b6,
+ 0xf96a, 0x54a9,
+ 0xf96c, 0x2598,
+ 0xf96d, 0x54ab,
+ 0xf96f, 0x20f6,
+ 0xf970, 0x54ad,
+ 0xf980, 0x54bc,
+ 0xf985, 0x2585,
+ 0xf986, 0x54c1,
+ 0xf987, 0x2599,
+ 0xf988, 0x54c2,
+ 0xf991, 0x2596,
+ 0xf992, 0x54cb,
+ 0xf996, 0x259a,
+ 0xf997, 0x54cf,
+ 0xf998, 0x259b,
+ 0xf999, 0x54d0,
+ 0xfa40, 0x54d8,
+ 0xfa42, 0x259d,
+ 0xfa43, 0x54da,
+ 0xfa46, 0x259e,
+ 0xfa47, 0x54dd,
+ 0xfa4c, 0x234c,
+ 0xfa4d, 0x54e2,
+ 0xfa51, 0x1f44,
+ 0xfa52, 0x54e6,
+ 0xfa58, 0x2660,
+ 0xfa59, 0x25a0,
+ 0xfa5a, 0x54ec,
+ 0xfa5d, 0x259c,
+ 0xfa5e, 0x54ef,
+ 0xfa5f, 0x259f,
+ 0xfa60, 0x54f0,
+ 0xfa61, 0x1f6c,
+ 0xfa62, 0x54f1,
+ 0xfa70, 0x25a2,
+ 0xfa71, 0x54ff,
+ 0xfa74, 0x20ae,
+ 0xfa75, 0x5502,
+ 0xfa76, 0x258b,
+ 0xfa77, 0x25a3,
+ 0xfa78, 0x5503,
+ 0xfa80, 0x550a,
+ 0xfa83, 0x2589,
+ 0xfa84, 0x25a5,
+ 0xfa85, 0x550d,
+ 0xfa8d, 0x25a4,
+ 0xfa8e, 0x5515,
+ 0xfa90, 0x25a6,
+ 0xfa91, 0x2593,
+ 0xfa92, 0x5517,
+ 0xfa96, 0x25a7,
+ 0xfa97, 0x2222,
+ 0xfa98, 0x25a9,
+ 0xfa99, 0x551b,
+ 0xfb40, 0x5523,
+ 0xfb49, 0x25a8,
+ 0xfb4a, 0x552c,
+ 0xfb52, 0x2586,
+ 0xfb53, 0x5534,
+ 0xfb57, 0x25a1,
+ 0xfb58, 0x25aa,
+ 0xfb59, 0x5538,
+ 0xfb5a, 0x2590,
+ 0xfb5b, 0x258e,
+ 0xfb5c, 0x5539,
+ 0xfb75, 0x2688,
+ 0xfb76, 0x5552,
+ 0xfb79, 0x269e,
+ 0xfb7a, 0x25fb,
+ 0xfb7b, 0x5555,
+ 0xfb7c, 0x1f8c,
+ 0xfb7d, 0x21f4,
+ 0xfb7e, 0x5556,
+ 0xfb80, 0x5557,
+ 0xfb90, 0x200f,
+ 0xfb91, 0x5567,
+ 0xfb9c, 0x2071,
+ 0xfb9d, 0x5572,
+ 0xfb9f, 0x25f7,
+ 0xfba0, 0x5574,
+ 0xfc40, 0x5575,
+ 0xfc44, 0x2696,
+ 0xfc45, 0x5579,
+ 0xfc49, 0x268f,
+ 0xfc4a, 0x557d,
+ 0xfc5a, 0x22da,
+ 0xfc5b, 0x558d,
+ 0xfc63, 0x1ec1,
+ 0xfc64, 0x5595,
+ 0xfc68, 0x1eb3,
+ 0xfc69, 0x5599,
+ 0xfc6f, 0x266a,
+ 0xfc70, 0x559f,
+ 0xfc71, 0x268a,
+ 0xfc72, 0x55a0,
+ 0xfc74, 0x2669,
+ 0xfc75, 0x55a2,
+ 0xfc77, 0x2618,
+ 0xfc79, 0x55a4,
+ 0xfc80, 0x55aa,
+ 0xfc83, 0x261a,
+ 0xfc84, 0x55ad,
+ 0xfc8a, 0x2673,
+ 0xfc8b, 0x55b3,
+ 0xfd40, 0x55c9,
+ 0xfd52, 0x20c6,
+ 0xfd53, 0x226b,
+ 0xfd54, 0x55db,
+ 0xfd57, 0x24d3,
+ 0xfd58, 0x1e86,
+ 0xfd59, 0x55de,
+ 0xfd5a, 0x260f,
+ 0xfd5b, 0x55df,
+ 0xfd5f, 0x2611,
+ 0xfd60, 0x55e3,
+ 0xfd62, 0x2613,
+ 0xfd63, 0x55e5,
+ 0xfd65, 0x2610,
+ 0xfd66, 0x2612,
+ 0xfd67, 0x2030,
+ 0xfd68, 0x55e7,
+ 0xfd69, 0x2671,
+ 0xfd6a, 0x55e8,
+ 0xfd6c, 0x2614,
+ 0xfd6d, 0x55ea,
+ 0xfd70, 0x2616,
+ 0xfd71, 0x55ed,
+ 0xfd72, 0x2615,
+ 0xfd73, 0x55ee,
+ 0xfd78, 0x20f2,
+ 0xfd79, 0x55f3,
+ 0xfd7d, 0x2617,
+ 0xfd7e, 0x55f7,
+ 0xfd80, 0x55f8,
+ 0xfd88, 0x2037,
+ 0xfd89, 0x5600,
+ 0xfd8b, 0x20b3,
+ 0xfd8c, 0x5602,
+ 0xfd8f, 0x1f22,
+ 0xfd90, 0x24ed,
+ 0xfd91, 0x5605,
+ 0xfd94, 0x1f34,
+ 0xfd95, 0x5608,
+ 0xfd9d, 0x0a02,
+ 0xfd9e, 0x40d3,
+ 0xfd9f, 0x200c,
+ 0xfda0, 0x5083,
+ 0xfe40, 0x1259,
+ 0xfe41, 0x5610,
+ 0xfe80, 0x564e,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 gb12GBKEUCHEnc16 = {
+ 0,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x1e24, 0x032e, 0x032f, 0x0330, 0x0331, 0x0332, 0x0333, 0x0334,
+ 0x0335, 0x0336, 0x0337, 0x0338, 0x0339, 0x033a, 0x033b, 0x033c,
+ 0x033d, 0x033e, 0x033f, 0x0340, 0x0341, 0x0342, 0x0343, 0x0344,
+ 0x0345, 0x0346, 0x0347, 0x0348, 0x0349, 0x034a, 0x034b, 0x034c,
+ 0x034d, 0x034e, 0x034f, 0x0350, 0x0351, 0x0352, 0x0353, 0x0354,
+ 0x0355, 0x0356, 0x0357, 0x0358, 0x0359, 0x035a, 0x035b, 0x035c,
+ 0x035d, 0x035e, 0x035f, 0x0360, 0x0361, 0x0362, 0x0363, 0x0364,
+ 0x0365, 0x0366, 0x0367, 0x0368, 0x0369, 0x036a, 0x036b, 0x036c,
+ 0x036d, 0x036e, 0x036f, 0x0370, 0x0371, 0x0372, 0x0373, 0x0374,
+ 0x0375, 0x0376, 0x0377, 0x0378, 0x0379, 0x037a, 0x037b, 0x037c,
+ 0x037d, 0x037e, 0x037f, 0x0380, 0x0381, 0x0382, 0x0383, 0x0384,
+ 0x0385, 0x0386, 0x0387, 0x0388, 0x0389, 0x038a, 0x038b, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ gb12GBKEUCHMap2, 4071
+};
+
+static Gushort gb12GBKEUCVMap2[8182] = {
+ 0x0000, 0x0000,
+ 0x8140, 0x2758,
+ 0x8179, 0x2059,
+ 0x817a, 0x2791,
+ 0x8180, 0x2796,
+ 0x8186, 0x21f1,
+ 0x8187, 0x279c,
+ 0x81ed, 0x1ff2,
+ 0x81ee, 0x2802,
+ 0x81f6, 0x205d,
+ 0x81f7, 0x280a,
+ 0x8240, 0x2812,
+ 0x8253, 0x269c,
+ 0x8254, 0x2825,
+ 0x8262, 0x21b5,
+ 0x8263, 0x2833,
+ 0x8274, 0x22cc,
+ 0x8275, 0x2844,
+ 0x827a, 0x2016,
+ 0x827b, 0x2849,
+ 0x827d, 0x1e62,
+ 0x827e, 0x284b,
+ 0x8280, 0x1f20,
+ 0x8281, 0x284c,
+ 0x8283, 0x207f,
+ 0x8284, 0x284e,
+ 0x8290, 0x205c,
+ 0x8291, 0x285a,
+ 0x82a5, 0x2194,
+ 0x82a6, 0x286e,
+ 0x82c8, 0x1e65,
+ 0x82c9, 0x2281,
+ 0x82ca, 0x2890,
+ 0x82e1, 0x22cd,
+ 0x82e2, 0x28a7,
+ 0x82e3, 0x210a,
+ 0x82e4, 0x1e3e,
+ 0x82e5, 0x28a8,
+ 0x82ed, 0x267f,
+ 0x82ee, 0x28b0,
+ 0x82f2, 0x222e,
+ 0x82f3, 0x28b4,
+ 0x82f7, 0x1e96,
+ 0x82f8, 0x22cb,
+ 0x82f9, 0x226c,
+ 0x82fa, 0x28b8,
+ 0x82fb, 0x2117,
+ 0x82fc, 0x28b9,
+ 0x8340, 0x28bc,
+ 0x8341, 0x20e8,
+ 0x8342, 0x28bd,
+ 0x8345, 0x22d4,
+ 0x8346, 0x28c0,
+ 0x8348, 0x1fb9,
+ 0x8349, 0x28c2,
+ 0x834c, 0x22d8,
+ 0x834d, 0x28c5,
+ 0x8353, 0x20df,
+ 0x8354, 0x28cb,
+ 0x8357, 0x20c2,
+ 0x8358, 0x28ce,
+ 0x835e, 0x2195,
+ 0x835f, 0x28d4,
+ 0x8365, 0x1fac,
+ 0x8366, 0x22d3,
+ 0x8367, 0x28da,
+ 0x8372, 0x1f81,
+ 0x8373, 0x28e5,
+ 0x8378, 0x2210,
+ 0x8379, 0x28ea,
+ 0x837a, 0x22cf,
+ 0x837b, 0x28eb,
+ 0x837c, 0x2213,
+ 0x837d, 0x28ec,
+ 0x837e, 0x1fe4,
+ 0x8380, 0x1f90,
+ 0x8381, 0x28ed,
+ 0x8386, 0x22d6,
+ 0x8387, 0x28f2,
+ 0x8389, 0x22d0,
+ 0x838a, 0x22ce,
+ 0x838b, 0x28f4,
+ 0x838d, 0x2681,
+ 0x838e, 0x28f6,
+ 0x8394, 0x1e76,
+ 0x8395, 0x28fc,
+ 0x839e, 0x2231,
+ 0x839f, 0x2905,
+ 0x83a6, 0x1e93,
+ 0x83a7, 0x290c,
+ 0x83ab, 0x22d2,
+ 0x83ac, 0x2910,
+ 0x83ae, 0x22d7,
+ 0x83af, 0x22d5,
+ 0x83b0, 0x22d1,
+ 0x83b1, 0x2912,
+ 0x83ba, 0x1ee5,
+ 0x83bb, 0x291b,
+ 0x83c9, 0x2025,
+ 0x83ca, 0x2929,
+ 0x83f6, 0x1ecf,
+ 0x83f7, 0x2955,
+ 0x8440, 0x295d,
+ 0x8450, 0x1fd9,
+ 0x8451, 0x296d,
+ 0x8471, 0x22c8,
+ 0x8472, 0x298d,
+ 0x8474, 0x2263,
+ 0x8475, 0x298f,
+ 0x8477, 0x2683,
+ 0x8478, 0x2991,
+ 0x8480, 0x2998,
+ 0x8482, 0x1f17,
+ 0x8483, 0x299a,
+ 0x848e, 0x1f2b,
+ 0x848f, 0x29a5,
+ 0x8492, 0x22ca,
+ 0x8493, 0x1e99,
+ 0x8494, 0x29a8,
+ 0x849d, 0x1f4f,
+ 0x849e, 0x29b1,
+ 0x84a1, 0x1fcf,
+ 0x84a2, 0x2036,
+ 0x84a3, 0x1f3a,
+ 0x84a4, 0x29b4,
+ 0x84a5, 0x22c9,
+ 0x84a6, 0x1f99,
+ 0x84a7, 0x29b5,
+ 0x84a9, 0x1f75,
+ 0x84aa, 0x29b7,
+ 0x84c5, 0x1fbe,
+ 0x84c6, 0x29d2,
+ 0x84d3, 0x1ecd,
+ 0x84d4, 0x29df,
+ 0x84d5, 0x21a9,
+ 0x84d6, 0x29e0,
+ 0x84d7, 0x21e6,
+ 0x84d8, 0x29e1,
+ 0x84d9, 0x2127,
+ 0x84da, 0x2003,
+ 0x84db, 0x29e2,
+ 0x84dd, 0x2132,
+ 0x84de, 0x29e4,
+ 0x84ea, 0x2323,
+ 0x84eb, 0x29f0,
+ 0x84ee, 0x2011,
+ 0x84ef, 0x29f3,
+ 0x84f1, 0x20f5,
+ 0x84f2, 0x29f5,
+ 0x8540, 0x2a02,
+ 0x8551, 0x22c5,
+ 0x8552, 0x1f5e,
+ 0x8553, 0x2a13,
+ 0x8554, 0x22c6,
+ 0x8555, 0x2a14,
+ 0x855e, 0x20ef,
+ 0x855f, 0x2a1d,
+ 0x8566, 0x21d0,
+ 0x8567, 0x2a24,
+ 0x8580, 0x2a3c,
+ 0x8587, 0x22c1,
+ 0x8588, 0x2a43,
+ 0x858b, 0x1e64,
+ 0x858c, 0x2a46,
+ 0x8592, 0x21f9,
+ 0x8593, 0x2a4c,
+ 0x8596, 0x2010,
+ 0x8597, 0x2a4f,
+ 0x8598, 0x22c2,
+ 0x8599, 0x2a50,
+ 0x85a2, 0x1e5a,
+ 0x85a3, 0x2a59,
+ 0x85b2, 0x1ea2,
+ 0x85b3, 0x2a68,
+ 0x8640, 0x2ab4,
+ 0x864a, 0x236d,
+ 0x864b, 0x2abe,
+ 0x8654, 0x2247,
+ 0x8655, 0x2ac7,
+ 0x8668, 0x236c,
+ 0x8669, 0x2ada,
+ 0x8680, 0x2af0,
+ 0x8696, 0x219c,
+ 0x8697, 0x2b06,
+ 0x8699, 0x20c9,
+ 0x869a, 0x2b08,
+ 0x86a1, 0x21f0,
+ 0x86a2, 0x2b0f,
+ 0x86ca, 0x210b,
+ 0x86cb, 0x2b37,
+ 0x86cc, 0x20de,
+ 0x86cd, 0x2b38,
+ 0x86ce, 0x1eaa,
+ 0x86cf, 0x2b39,
+ 0x86d1, 0x222c,
+ 0x86d2, 0x2b3b,
+ 0x86dc, 0x20d8,
+ 0x86dd, 0x22c0,
+ 0x86de, 0x2b45,
+ 0x86e1, 0x206f,
+ 0x86e2, 0x2b48,
+ 0x86e8, 0x21a1,
+ 0x86e9, 0x2b4e,
+ 0x86ee, 0x2379,
+ 0x86ef, 0x2b53,
+ 0x86f4, 0x2372,
+ 0x86f5, 0x2b58,
+ 0x8740, 0x216a,
+ 0x8741, 0x2b62,
+ 0x8744, 0x237c,
+ 0x8745, 0x2b65,
+ 0x8749, 0x20b0,
+ 0x874a, 0x2b69,
+ 0x874b, 0x237a,
+ 0x874c, 0x1e74,
+ 0x874d, 0x2b6a,
+ 0x874f, 0x2377,
+ 0x8750, 0x2b6c,
+ 0x8757, 0x1f4c,
+ 0x8758, 0x2b73,
+ 0x875a, 0x2378,
+ 0x875b, 0x21cf,
+ 0x875c, 0x2368,
+ 0x875d, 0x2b75,
+ 0x875e, 0x2371,
+ 0x875f, 0x2b76,
+ 0x8760, 0x2369,
+ 0x8761, 0x2b77,
+ 0x8766, 0x2674,
+ 0x8767, 0x2b7c,
+ 0x877a, 0x236f,
+ 0x877b, 0x2b8f,
+ 0x877d, 0x2370,
+ 0x877e, 0x2b91,
+ 0x8780, 0x2b92,
+ 0x8781, 0x2376,
+ 0x8782, 0x2373,
+ 0x8783, 0x2b93,
+ 0x8786, 0x237f,
+ 0x8787, 0x2b96,
+ 0x8788, 0x2374,
+ 0x8789, 0x2b97,
+ 0x878a, 0x20b5,
+ 0x878b, 0x2b98,
+ 0x878d, 0x1edb,
+ 0x878e, 0x2672,
+ 0x878f, 0x2b9a,
+ 0x8793, 0x236e,
+ 0x8794, 0x2b9e,
+ 0x8798, 0x21b7,
+ 0x8799, 0x2ba2,
+ 0x879d, 0x2375,
+ 0x879e, 0x2ba6,
+ 0x87a3, 0x2382,
+ 0x87a4, 0x2bab,
+ 0x87a7, 0x209e,
+ 0x87a8, 0x2bae,
+ 0x87b3, 0x236b,
+ 0x87b4, 0x2bb9,
+ 0x87b5, 0x2039,
+ 0x87b6, 0x2bba,
+ 0x87bb, 0x269f,
+ 0x87bc, 0x2bbf,
+ 0x87bf, 0x237d,
+ 0x87c0, 0x21f5,
+ 0x87c1, 0x2bc2,
+ 0x87c2, 0x2381,
+ 0x87c3, 0x2bc3,
+ 0x87ca, 0x237b,
+ 0x87cb, 0x237e,
+ 0x87cc, 0x21cc,
+ 0x87cd, 0x2bca,
+ 0x87cf, 0x22db,
+ 0x87d0, 0x2bcc,
+ 0x87d2, 0x236a,
+ 0x87d3, 0x2689,
+ 0x87d4, 0x2bce,
+ 0x87d5, 0x2697,
+ 0x87d6, 0x2bcf,
+ 0x87da, 0x22a1,
+ 0x87db, 0x2bd3,
+ 0x87f7, 0x2383,
+ 0x87f8, 0x1f3d,
+ 0x87f9, 0x2bef,
+ 0x87fa, 0x218f,
+ 0x87fb, 0x2bf0,
+ 0x8840, 0x2246,
+ 0x8841, 0x2248,
+ 0x8842, 0x2bf4,
+ 0x8844, 0x217e,
+ 0x8845, 0x2bf6,
+ 0x8846, 0x2180,
+ 0x8847, 0x2bf7,
+ 0x8880, 0x2c2f,
+ 0x88ba, 0x232a,
+ 0x88bb, 0x2c69,
+ 0x88cc, 0x228b,
+ 0x88cd, 0x2c7a,
+ 0x88d4, 0x1f85,
+ 0x88d5, 0x2c81,
+ 0x88d7, 0x2325,
+ 0x88d8, 0x2c83,
+ 0x88df, 0x232c,
+ 0x88e0, 0x2c8a,
+ 0x88e5, 0x232e,
+ 0x88e6, 0x2c8f,
+ 0x88f2, 0x2205,
+ 0x88f3, 0x1e38,
+ 0x88f4, 0x2c9b,
+ 0x88f6, 0x1e73,
+ 0x88f7, 0x2c9d,
+ 0x8940, 0x2ca5,
+ 0x894b, 0x1fe3,
+ 0x894c, 0x2339,
+ 0x894d, 0x2cb0,
+ 0x894e, 0x232b,
+ 0x894f, 0x2cb1,
+ 0x8950, 0x232d,
+ 0x8951, 0x2cb2,
+ 0x8954, 0x217f,
+ 0x8955, 0x2cb5,
+ 0x895d, 0x21a7,
+ 0x895e, 0x2cbd,
+ 0x895f, 0x232f,
+ 0x8960, 0x2cbe,
+ 0x896d, 0x1e7d,
+ 0x896e, 0x2ccb,
+ 0x8971, 0x20d6,
+ 0x8972, 0x2cce,
+ 0x897c, 0x1ec2,
+ 0x897d, 0x2cd8,
+ 0x8980, 0x2cda,
+ 0x898b, 0x22b2,
+ 0x898c, 0x2ce5,
+ 0x8999, 0x1edf,
+ 0x899a, 0x2cf2,
+ 0x899e, 0x1ef9,
+ 0x899f, 0x2cf6,
+ 0x89a6, 0x20d9,
+ 0x89a7, 0x2cfd,
+ 0x89a8, 0x1fdd,
+ 0x89a9, 0x2cfe,
+ 0x89af, 0x2167,
+ 0x89b0, 0x2d04,
+ 0x89ba, 0x21ed,
+ 0x89bb, 0x2d0e,
+ 0x89be, 0x2007,
+ 0x89bf, 0x2326,
+ 0x89c0, 0x2329,
+ 0x89c1, 0x2d11,
+ 0x89c4, 0x1f52,
+ 0x89c5, 0x203b,
+ 0x89c6, 0x2328,
+ 0x89c7, 0x2d14,
+ 0x89c8, 0x2327,
+ 0x89c9, 0x2d15,
+ 0x89ce, 0x1e2b,
+ 0x89cf, 0x2d1a,
+ 0x89d1, 0x22ae,
+ 0x89d2, 0x2d1c,
+ 0x89d8, 0x1f49,
+ 0x89d9, 0x2d22,
+ 0x89db, 0x2138,
+ 0x89dc, 0x2d24,
+ 0x89f4, 0x2081,
+ 0x89f5, 0x2d3c,
+ 0x8a40, 0x2d46,
+ 0x8a41, 0x1f7c,
+ 0x8a42, 0x2d47,
+ 0x8a59, 0x235b,
+ 0x8a5a, 0x1ede,
+ 0x8a5b, 0x2d5e,
+ 0x8a5c, 0x1fa2,
+ 0x8a5d, 0x2d5f,
+ 0x8a5e, 0x1efa,
+ 0x8a5f, 0x2d60,
+ 0x8a79, 0x22ad,
+ 0x8a7a, 0x2d7a,
+ 0x8a80, 0x2d7f,
+ 0x8ae4, 0x203f,
+ 0x8ae5, 0x2de3,
+ 0x8b40, 0x2dfd,
+ 0x8b44, 0x1f0e,
+ 0x8b45, 0x2e01,
+ 0x8b49, 0x23f9,
+ 0x8b4a, 0x2e05,
+ 0x8b7a, 0x23fc,
+ 0x8b7b, 0x2e35,
+ 0x8b80, 0x2e39,
+ 0x8b8c, 0x2069,
+ 0x8b8d, 0x2e45,
+ 0x8b9e, 0x23f7,
+ 0x8b9f, 0x2e56,
+ 0x8bb3, 0x23f6,
+ 0x8bb4, 0x2e6a,
+ 0x8bb9, 0x23fd,
+ 0x8bba, 0x2e6f,
+ 0x8bbe, 0x23f8,
+ 0x8bbf, 0x2e73,
+ 0x8bc6, 0x23fa,
+ 0x8bc7, 0x2e7a,
+ 0x8bc8, 0x23fe,
+ 0x8bc9, 0x1fa8,
+ 0x8bca, 0x2e7b,
+ 0x8bd4, 0x2401,
+ 0x8bd5, 0x2e85,
+ 0x8bdc, 0x23ff,
+ 0x8bdd, 0x2e8c,
+ 0x8be5, 0x2400,
+ 0x8be6, 0x2e94,
+ 0x8beb, 0x2221,
+ 0x8bec, 0x2e99,
+ 0x8bf0, 0x2122,
+ 0x8bf1, 0x2e9d,
+ 0x8c40, 0x2eab,
+ 0x8c44, 0x23fb,
+ 0x8c45, 0x2eaf,
+ 0x8c4f, 0x215a,
+ 0x8c50, 0x2eb9,
+ 0x8c57, 0x21e5,
+ 0x8c58, 0x2ec0,
+ 0x8c5c, 0x2057,
+ 0x8c5d, 0x2ec4,
+ 0x8c80, 0x2ee6,
+ 0x8c8b, 0x20e5,
+ 0x8c8c, 0x2ef1,
+ 0x8c8d, 0x212f,
+ 0x8c8e, 0x20a3,
+ 0x8c8f, 0x2121,
+ 0x8c90, 0x2ef2,
+ 0x8c91, 0x21d4,
+ 0x8c92, 0x1fe5,
+ 0x8c93, 0x2ef3,
+ 0x8c99, 0x1e8a,
+ 0x8c9a, 0x1e37,
+ 0x8c9b, 0x2ef9,
+ 0x8ca2, 0x1f9e,
+ 0x8ca3, 0x22a6,
+ 0x8ca4, 0x21e8,
+ 0x8ca5, 0x2f00,
+ 0x8ca6, 0x1eda,
+ 0x8ca7, 0x1eb9,
+ 0x8ca8, 0x2f01,
+ 0x8cc0, 0x235c,
+ 0x8cc1, 0x2f19,
+ 0x8cd2, 0x2050,
+ 0x8cd3, 0x1e67,
+ 0x8cd4, 0x2f2a,
+ 0x8cd5, 0x23f4,
+ 0x8cd6, 0x2f2b,
+ 0x8cd9, 0x213e,
+ 0x8cda, 0x2f2e,
+ 0x8cf9, 0x1f16,
+ 0x8cfa, 0x2f4d,
+ 0x8d40, 0x2f52,
+ 0x8d73, 0x2389,
+ 0x8d74, 0x2f85,
+ 0x8d75, 0x1eb7,
+ 0x8d76, 0x2f86,
+ 0x8d7b, 0x21b4,
+ 0x8d7c, 0x2f8b,
+ 0x8d80, 0x2f8e,
+ 0x8d88, 0x238f,
+ 0x8d89, 0x2f96,
+ 0x8d8f, 0x1f1a,
+ 0x8d90, 0x2f9c,
+ 0x8d9e, 0x238b,
+ 0x8d9f, 0x2faa,
+ 0x8db9, 0x238a,
+ 0x8dba, 0x2fc4,
+ 0x8de2, 0x2391,
+ 0x8de3, 0x2fec,
+ 0x8de4, 0x2271,
+ 0x8de5, 0x2fed,
+ 0x8de7, 0x2388,
+ 0x8de8, 0x2fef,
+ 0x8df7, 0x238e,
+ 0x8df8, 0x2ffe,
+ 0x8dfe, 0x238d,
+ 0x8e40, 0x3004,
+ 0x8e46, 0x238c,
+ 0x8e47, 0x300a,
+ 0x8e56, 0x2390,
+ 0x8e57, 0x3019,
+ 0x8e58, 0x2033,
+ 0x8e59, 0x301a,
+ 0x8e5a, 0x223c,
+ 0x8e5b, 0x301b,
+ 0x8e68, 0x1fe9,
+ 0x8e69, 0x3028,
+ 0x8e6e, 0x2055,
+ 0x8e6f, 0x302d,
+ 0x8e70, 0x2392,
+ 0x8e71, 0x302e,
+ 0x8e80, 0x2324,
+ 0x8e81, 0x303c,
+ 0x8e9b, 0x2143,
+ 0x8e9c, 0x3056,
+ 0x8e9f, 0x2129,
+ 0x8ea0, 0x3059,
+ 0x8ea4, 0x2277,
+ 0x8ea5, 0x305d,
+ 0x8ea7, 0x1ea7,
+ 0x8ea8, 0x305f,
+ 0x8eac, 0x2285,
+ 0x8ead, 0x3063,
+ 0x8eae, 0x2384,
+ 0x8eaf, 0x3064,
+ 0x8ebd, 0x2387,
+ 0x8ebe, 0x2386,
+ 0x8ebf, 0x3072,
+ 0x8ec3, 0x2290,
+ 0x8ec4, 0x3076,
+ 0x8ec5, 0x1e44,
+ 0x8ec6, 0x3077,
+ 0x8ecd, 0x1e32,
+ 0x8ece, 0x2385,
+ 0x8ecf, 0x307e,
+ 0x8ed6, 0x1f13,
+ 0x8ed7, 0x1f73,
+ 0x8ed8, 0x3085,
+ 0x8eec, 0x1fe0,
+ 0x8eed, 0x3099,
+ 0x8f40, 0x30ab,
+ 0x8f52, 0x2087,
+ 0x8f53, 0x1e78,
+ 0x8f54, 0x23ae,
+ 0x8f55, 0x1ef6,
+ 0x8f56, 0x1f31,
+ 0x8f57, 0x30bd,
+ 0x8f5d, 0x2045,
+ 0x8f5e, 0x30c3,
+ 0x8f64, 0x2178,
+ 0x8f65, 0x30c9,
+ 0x8f80, 0x30e3,
+ 0x8f86, 0x23f5,
+ 0x8f87, 0x30e9,
+ 0x8f88, 0x2275,
+ 0x8f89, 0x30ea,
+ 0x8f95, 0x266e,
+ 0x8f96, 0x30f6,
+ 0x8f97, 0x1eb0,
+ 0x8f98, 0x30f7,
+ 0x8f9b, 0x2083,
+ 0x8f9c, 0x30fa,
+ 0x8f9d, 0x2188,
+ 0x8f9e, 0x30fb,
+ 0x8fa1, 0x267c,
+ 0x8fa2, 0x30fe,
+ 0x8fbd, 0x1fc5,
+ 0x8fbe, 0x3119,
+ 0x8fc4, 0x1ea1,
+ 0x8fc5, 0x311f,
+ 0x8fc6, 0x2393,
+ 0x8fc7, 0x3120,
+ 0x8fcd, 0x1f0b,
+ 0x8fce, 0x3126,
+ 0x8fd8, 0x1e7c,
+ 0x8fd9, 0x3130,
+ 0x9040, 0x3156,
+ 0x9080, 0x3195,
+ 0x909d, 0x23b4,
+ 0x909e, 0x207e,
+ 0x909f, 0x31b2,
+ 0x90ba, 0x1ee3,
+ 0x90bb, 0x31cd,
+ 0x90c0, 0x2095,
+ 0x90c1, 0x23bb,
+ 0x90c2, 0x31d2,
+ 0x90c5, 0x23b9,
+ 0x90c6, 0x31d5,
+ 0x90db, 0x1e28,
+ 0x90dc, 0x23bd,
+ 0x90dd, 0x31ea,
+ 0x90ed, 0x23b5,
+ 0x90ee, 0x31fa,
+ 0x90f0, 0x23ba,
+ 0x90f1, 0x31fc,
+ 0x90f7, 0x23b3,
+ 0x90f8, 0x3202,
+ 0x9140, 0x3209,
+ 0x9142, 0x2162,
+ 0x9143, 0x320b,
+ 0x914b, 0x1e5e,
+ 0x914c, 0x3213,
+ 0x914d, 0x1e5d,
+ 0x914e, 0x3214,
+ 0x9151, 0x23b7,
+ 0x9152, 0x3217,
+ 0x9154, 0x1f2f,
+ 0x9155, 0x24df,
+ 0x9156, 0x3219,
+ 0x9159, 0x23b2,
+ 0x915a, 0x214e,
+ 0x915b, 0x321c,
+ 0x915d, 0x2052,
+ 0x915e, 0x321e,
+ 0x9161, 0x23bc,
+ 0x9162, 0x3221,
+ 0x9163, 0x20eb,
+ 0x9164, 0x3222,
+ 0x916e, 0x2232,
+ 0x916f, 0x322c,
+ 0x9176, 0x1e3f,
+ 0x9177, 0x3233,
+ 0x917a, 0x201b,
+ 0x917b, 0x20bc,
+ 0x917c, 0x23be,
+ 0x917d, 0x3236,
+ 0x9180, 0x3238,
+ 0x9184, 0x1eae,
+ 0x9185, 0x323c,
+ 0x918d, 0x1efb,
+ 0x918e, 0x3244,
+ 0x9191, 0x2089,
+ 0x9192, 0x3247,
+ 0x9193, 0x23b1,
+ 0x9194, 0x3248,
+ 0x9197, 0x21c4,
+ 0x9198, 0x324b,
+ 0x919b, 0x2214,
+ 0x919c, 0x324e,
+ 0x91a9, 0x1fde,
+ 0x91aa, 0x2223,
+ 0x91ab, 0x23b6,
+ 0x91ac, 0x325b,
+ 0x91ba, 0x268c,
+ 0x91bb, 0x24de,
+ 0x91bc, 0x3269,
+ 0x91bf, 0x24e0,
+ 0x91c0, 0x326c,
+ 0x91c3, 0x23b8,
+ 0x91c4, 0x326f,
+ 0x91cd, 0x1e81,
+ 0x91ce, 0x3278,
+ 0x91d0, 0x1ffe,
+ 0x91d1, 0x1f51,
+ 0x91d2, 0x21e1,
+ 0x91d3, 0x327a,
+ 0x91d4, 0x23b0,
+ 0x91d5, 0x327b,
+ 0x91d6, 0x1fce,
+ 0x91d7, 0x327c,
+ 0x91d8, 0x211e,
+ 0x91d9, 0x2021,
+ 0x91da, 0x327d,
+ 0x91df, 0x24e1,
+ 0x91e0, 0x3282,
+ 0x91e2, 0x24a3,
+ 0x91e3, 0x3284,
+ 0x91ea, 0x24a4,
+ 0x91eb, 0x328b,
+ 0x91f0, 0x2273,
+ 0x91f1, 0x3290,
+ 0x91f2, 0x21b0,
+ 0x91f3, 0x3291,
+ 0x9240, 0x329d,
+ 0x9280, 0x32dc,
+ 0x92b6, 0x21d1,
+ 0x92b7, 0x3312,
+ 0x92ce, 0x211c,
+ 0x92cf, 0x3329,
+ 0x92d0, 0x235d,
+ 0x92d1, 0x332a,
+ 0x92d4, 0x2682,
+ 0x92d5, 0x332d,
+ 0x92df, 0x210d,
+ 0x92e0, 0x205a,
+ 0x92e1, 0x3337,
+ 0x92fe, 0x1f8d,
+ 0x9340, 0x3354,
+ 0x9350, 0x21ff,
+ 0x9351, 0x3364,
+ 0x935d, 0x1f58,
+ 0x935e, 0x3370,
+ 0x9370, 0x215b,
+ 0x9371, 0x3382,
+ 0x9376, 0x1eb6,
+ 0x9377, 0x3387,
+ 0x9380, 0x338f,
+ 0x938c, 0x20db,
+ 0x938d, 0x339b,
+ 0x939d, 0x2360,
+ 0x939e, 0x33ab,
+ 0x93a5, 0x2361,
+ 0x93a6, 0x33b2,
+ 0x93a7, 0x2040,
+ 0x93a8, 0x33b3,
+ 0x93b4, 0x228e,
+ 0x93b5, 0x33bf,
+ 0x93b8, 0x1fdf,
+ 0x93b9, 0x33c2,
+ 0x93bb, 0x235e,
+ 0x93bc, 0x33c4,
+ 0x93bd, 0x1e6a,
+ 0x93be, 0x33c5,
+ 0x93c6, 0x2002,
+ 0x93c7, 0x33cd,
+ 0x93cf, 0x2093,
+ 0x93d0, 0x33d5,
+ 0x93d7, 0x235f,
+ 0x93d8, 0x33dc,
+ 0x93db, 0x1eac,
+ 0x93dc, 0x1e54,
+ 0x93dd, 0x33df,
+ 0x93e1, 0x1f08,
+ 0x93e2, 0x33e3,
+ 0x93e4, 0x20c0,
+ 0x93e5, 0x2362,
+ 0x93e6, 0x33e5,
+ 0x93e9, 0x2160,
+ 0x93ea, 0x33e8,
+ 0x93eb, 0x219d,
+ 0x93ec, 0x1f8e,
+ 0x93ed, 0x222d,
+ 0x93ee, 0x33e9,
+ 0x93ef, 0x2047,
+ 0x93f0, 0x33ea,
+ 0x93f1, 0x2262,
+ 0x93f2, 0x33eb,
+ 0x93f4, 0x1f67,
+ 0x93f5, 0x1eb2,
+ 0x93f6, 0x33ed,
+ 0x93fa, 0x1ea9,
+ 0x93fb, 0x33f1,
+ 0x93fe, 0x1fcc,
+ 0x9440, 0x33f4,
+ 0x9444, 0x1f72,
+ 0x9445, 0x33f8,
+ 0x944d, 0x2098,
+ 0x944e, 0x3400,
+ 0x9450, 0x1e52,
+ 0x9451, 0x20a4,
+ 0x9452, 0x1f1c,
+ 0x9453, 0x228f,
+ 0x9454, 0x3402,
+ 0x9455, 0x1fed,
+ 0x9456, 0x3403,
+ 0x9458, 0x2365,
+ 0x9459, 0x3405,
+ 0x945b, 0x1e2d,
+ 0x945c, 0x2152,
+ 0x945d, 0x2366,
+ 0x945e, 0x3407,
+ 0x945f, 0x20fa,
+ 0x9460, 0x3408,
+ 0x9464, 0x2363,
+ 0x9465, 0x340c,
+ 0x9466, 0x209a,
+ 0x9467, 0x340d,
+ 0x946e, 0x203c,
+ 0x946f, 0x3414,
+ 0x9472, 0x1ff6,
+ 0x9473, 0x3417,
+ 0x9474, 0x2364,
+ 0x9475, 0x3418,
+ 0x9476, 0x1e69,
+ 0x9477, 0x3419,
+ 0x9478, 0x2367,
+ 0x9479, 0x341a,
+ 0x947a, 0x211d,
+ 0x947b, 0x341b,
+ 0x9480, 0x2259,
+ 0x9481, 0x2056,
+ 0x9482, 0x2163,
+ 0x9483, 0x341f,
+ 0x9487, 0x1fa9,
+ 0x9488, 0x1ffc,
+ 0x9489, 0x3423,
+ 0x94a1, 0x1e2e,
+ 0x94a2, 0x343b,
+ 0x94b3, 0x1ebc,
+ 0x94b4, 0x344c,
+ 0x94b5, 0x2142,
+ 0x94b6, 0x344d,
+ 0x94bf, 0x201e,
+ 0x94c0, 0x1e43,
+ 0x94c1, 0x3456,
+ 0x94cc, 0x24d4,
+ 0x94cd, 0x3461,
+ 0x94d8, 0x226f,
+ 0x94d9, 0x346c,
+ 0x94e0, 0x1ed7,
+ 0x94e1, 0x3473,
+ 0x9540, 0x3491,
+ 0x9572, 0x212d,
+ 0x9573, 0x34c3,
+ 0x9580, 0x34cf,
+ 0x9583, 0x229b,
+ 0x9584, 0x34d2,
+ 0x959e, 0x2256,
+ 0x959f, 0x24a8,
+ 0x95a0, 0x34ec,
+ 0x95b3, 0x1e79,
+ 0x95b4, 0x34ff,
+ 0x95ba, 0x225a,
+ 0x95bb, 0x3505,
+ 0x95cf, 0x24a7,
+ 0x95d0, 0x3519,
+ 0x95d1, 0x2686,
+ 0x95d2, 0x24a6,
+ 0x95d3, 0x351a,
+ 0x95d4, 0x21ce,
+ 0x95d5, 0x351b,
+ 0x95e1, 0x24a9,
+ 0x95e2, 0x3527,
+ 0x95e7, 0x1fe7,
+ 0x95e8, 0x352c,
+ 0x95f1, 0x2112,
+ 0x95f2, 0x3535,
+ 0x95f8, 0x213c,
+ 0x95f9, 0x353b,
+ 0x95fe, 0x1f5c,
+ 0x9640, 0x3540,
+ 0x9656, 0x24c4,
+ 0x9657, 0x3556,
+ 0x967c, 0x1ecc,
+ 0x967d, 0x357b,
+ 0x9680, 0x357d,
+ 0x9740, 0x35fc,
+ 0x9767, 0x246a,
+ 0x9768, 0x3623,
+ 0x976c, 0x2175,
+ 0x976d, 0x3627,
+ 0x976e, 0x246d,
+ 0x976f, 0x3628,
+ 0x9780, 0x3638,
+ 0x9796, 0x246b,
+ 0x9797, 0x225f,
+ 0x9798, 0x364e,
+ 0x979d, 0x1ece,
+ 0x979e, 0x3653,
+ 0x97a3, 0x2272,
+ 0x97a4, 0x3658,
+ 0x97bf, 0x2473,
+ 0x97c0, 0x3673,
+ 0x97ee, 0x21fe,
+ 0x97ef, 0x36a1,
+ 0x97f7, 0x1efe,
+ 0x97f8, 0x36a9,
+ 0x9840, 0x36b0,
+ 0x9845, 0x2475,
+ 0x9846, 0x36b5,
+ 0x9849, 0x220a,
+ 0x984a, 0x36b8,
+ 0x984f, 0x1f6f,
+ 0x9850, 0x36bd,
+ 0x9871, 0x2468,
+ 0x9872, 0x36de,
+ 0x9873, 0x2100,
+ 0x9874, 0x36df,
+ 0x9880, 0x36ea,
+ 0x9881, 0x2476,
+ 0x9882, 0x36eb,
+ 0x988b, 0x1f27,
+ 0x988c, 0x20d7,
+ 0x988d, 0x36f4,
+ 0x98a0, 0x247c,
+ 0x98a1, 0x3707,
+ 0x98aa, 0x1fa1,
+ 0x98ab, 0x3710,
+ 0x98b6, 0x22aa,
+ 0x98b7, 0x2005,
+ 0x98b8, 0x371b,
+ 0x98ba, 0x246c,
+ 0x98bb, 0x371d,
+ 0x98c7, 0x203e,
+ 0x98c8, 0x3729,
+ 0x98cb, 0x1e4c,
+ 0x98cc, 0x372c,
+ 0x98d0, 0x213a,
+ 0x98d1, 0x3730,
+ 0x98d3, 0x2204,
+ 0x98d4, 0x3732,
+ 0x98e3, 0x20c3,
+ 0x98e4, 0x2140,
+ 0x98e5, 0x2477,
+ 0x98e6, 0x3741,
+ 0x98ef, 0x2474,
+ 0x98f0, 0x374a,
+ 0x98f2, 0x20dd,
+ 0x98f3, 0x374c,
+ 0x9940, 0x3758,
+ 0x9943, 0x1f68,
+ 0x9944, 0x375b,
+ 0x9945, 0x2185,
+ 0x9946, 0x375c,
+ 0x9966, 0x2472,
+ 0x9967, 0x377c,
+ 0x996e, 0x1eb5,
+ 0x996f, 0x3783,
+ 0x9975, 0x2478,
+ 0x9976, 0x3789,
+ 0x997a, 0x1f8b,
+ 0x997b, 0x2484,
+ 0x997c, 0x378d,
+ 0x9980, 0x3790,
+ 0x9985, 0x2699,
+ 0x9986, 0x3795,
+ 0x9989, 0x2482,
+ 0x998a, 0x3798,
+ 0x998e, 0x20a1,
+ 0x998f, 0x379c,
+ 0x9991, 0x1f92,
+ 0x9992, 0x379e,
+ 0x9999, 0x1f38,
+ 0x999a, 0x37a5,
+ 0x99a9, 0x2485,
+ 0x99aa, 0x37b4,
+ 0x99b0, 0x2480,
+ 0x99b1, 0x246e,
+ 0x99b2, 0x37ba,
+ 0x99b3, 0x247b,
+ 0x99b4, 0x2486,
+ 0x99b5, 0x2471,
+ 0x99b6, 0x37bb,
+ 0x99bd, 0x2483,
+ 0x99be, 0x2470,
+ 0x99bf, 0x37c2,
+ 0x99c0, 0x2469,
+ 0x99c1, 0x37c3,
+ 0x99c2, 0x247f,
+ 0x99c3, 0x37c4,
+ 0x99c9, 0x246f,
+ 0x99ca, 0x37ca,
+ 0x99ce, 0x2481,
+ 0x99cf, 0x37ce,
+ 0x99d1, 0x2220,
+ 0x99d2, 0x37d0,
+ 0x99da, 0x1ff5,
+ 0x99db, 0x37d8,
+ 0x99e0, 0x20f4,
+ 0x99e1, 0x37dd,
+ 0x99e5, 0x247d,
+ 0x99e6, 0x37e1,
+ 0x99e8, 0x2479,
+ 0x99e9, 0x37e3,
+ 0x99ec, 0x247e,
+ 0x99ed, 0x37e6,
+ 0x99f4, 0x247a,
+ 0x99f5, 0x37ed,
+ 0x9a40, 0x37f7,
+ 0x9a4a, 0x20e3,
+ 0x9a4b, 0x3801,
+ 0x9a57, 0x20ad,
+ 0x9a58, 0x380d,
+ 0x9a65, 0x24cb,
+ 0x9a66, 0x381a,
+ 0x9a67, 0x1f53,
+ 0x9a68, 0x381b,
+ 0x9a71, 0x2159,
+ 0x9a72, 0x3824,
+ 0x9a76, 0x2013,
+ 0x9a77, 0x1f33,
+ 0x9a78, 0x3828,
+ 0x9a80, 0x382f,
+ 0x9a88, 0x1e5c,
+ 0x9a89, 0x3837,
+ 0x9a8c, 0x2488,
+ 0x9a8d, 0x383a,
+ 0x9a91, 0x2487,
+ 0x9a92, 0x383e,
+ 0x9a97, 0x248a,
+ 0x9a98, 0x3843,
+ 0x9a9a, 0x2489,
+ 0x9a9b, 0x248b,
+ 0x9a9c, 0x3845,
+ 0x9a9e, 0x1f83,
+ 0x9a9f, 0x3847,
+ 0x9aa2, 0x210f,
+ 0x9aa3, 0x1fdb,
+ 0x9aa4, 0x384a,
+ 0x9aaa, 0x20af,
+ 0x9aab, 0x3850,
+ 0x9ad0, 0x24c0,
+ 0x9ad1, 0x3875,
+ 0x9ad6, 0x226d,
+ 0x9ad7, 0x387a,
+ 0x9ada, 0x24c1,
+ 0x9adb, 0x387d,
+ 0x9ae2, 0x20ca,
+ 0x9ae3, 0x3884,
+ 0x9ae4, 0x20e7,
+ 0x9ae5, 0x24c2,
+ 0x9ae6, 0x3885,
+ 0x9b40, 0x389e,
+ 0x9b80, 0x38dd,
+ 0x9bd1, 0x23dc,
+ 0x9bd2, 0x392e,
+ 0x9bdc, 0x23db,
+ 0x9bdd, 0x3938,
+ 0x9c40, 0x395a,
+ 0x9c53, 0x205e,
+ 0x9c54, 0x396d,
+ 0x9c59, 0x2244,
+ 0x9c5a, 0x23e2,
+ 0x9c5b, 0x3972,
+ 0x9c5c, 0x20d4,
+ 0x9c5d, 0x3973,
+ 0x9c75, 0x219f,
+ 0x9c76, 0x398b,
+ 0x9c79, 0x1e66,
+ 0x9c7a, 0x398e,
+ 0x9c80, 0x3993,
+ 0x9c86, 0x1f63,
+ 0x9c87, 0x3999,
+ 0x9c9d, 0x23dd,
+ 0x9c9e, 0x39af,
+ 0x9cab, 0x216b,
+ 0x9cac, 0x39bc,
+ 0x9cca, 0x22b5,
+ 0x9ccb, 0x39da,
+ 0x9ccf, 0x1f26,
+ 0x9cd0, 0x39de,
+ 0x9ce6, 0x1e63,
+ 0x9ce7, 0x2088,
+ 0x9ce8, 0x39f4,
+ 0x9cec, 0x1ebd,
+ 0x9ced, 0x39f8,
+ 0x9cee, 0x2341,
+ 0x9cef, 0x39f9,
+ 0x9cfb, 0x1f4b,
+ 0x9cfc, 0x3a05,
+ 0x9cfe, 0x2292,
+ 0x9d40, 0x3a07,
+ 0x9d42, 0x2124,
+ 0x9d43, 0x3a09,
+ 0x9d46, 0x2048,
+ 0x9d47, 0x23e0,
+ 0x9d48, 0x3a0c,
+ 0x9d4d, 0x2077,
+ 0x9d4e, 0x3a11,
+ 0x9d4f, 0x223a,
+ 0x9d50, 0x3a12,
+ 0x9d61, 0x20b1,
+ 0x9d62, 0x3a23,
+ 0x9d68, 0x1f41,
+ 0x9d69, 0x201c,
+ 0x9d6a, 0x3a29,
+ 0x9d6e, 0x22b8,
+ 0x9d6f, 0x3a2d,
+ 0x9d71, 0x2276,
+ 0x9d72, 0x3a2f,
+ 0x9d75, 0x1f9b,
+ 0x9d76, 0x3a32,
+ 0x9d7b, 0x1f9f,
+ 0x9d7c, 0x3a37,
+ 0x9d7d, 0x25ca,
+ 0x9d7e, 0x3a38,
+ 0x9d80, 0x3a39,
+ 0x9d8a, 0x20be,
+ 0x9d8b, 0x3a43,
+ 0x9d8d, 0x1fb4,
+ 0x9d8e, 0x3a45,
+ 0x9d91, 0x23d7,
+ 0x9d92, 0x3a48,
+ 0x9d99, 0x2105,
+ 0x9d9a, 0x3a4f,
+ 0x9da1, 0x23e1,
+ 0x9da2, 0x1fec,
+ 0x9da3, 0x3a56,
+ 0x9da7, 0x23ea,
+ 0x9da8, 0x3a5a,
+ 0x9dac, 0x23e3,
+ 0x9dad, 0x210e,
+ 0x9dae, 0x3a5e,
+ 0x9db2, 0x1fa6,
+ 0x9db3, 0x2004,
+ 0x9db4, 0x3a62,
+ 0x9dbe, 0x1f9d,
+ 0x9dbf, 0x3a6c,
+ 0x9dc6, 0x23e5,
+ 0x9dc7, 0x3a73,
+ 0x9dc9, 0x2264,
+ 0x9dca, 0x3a75,
+ 0x9dcd, 0x24e2,
+ 0x9dce, 0x3a78,
+ 0x9dd2, 0x23de,
+ 0x9dd3, 0x3a7c,
+ 0x9dd5, 0x1ec4,
+ 0x9dd6, 0x3a7e,
+ 0x9de1, 0x22b6,
+ 0x9de2, 0x20a9,
+ 0x9de3, 0x3a89,
+ 0x9df1, 0x212b,
+ 0x9df2, 0x3a97,
+ 0x9df4, 0x20a5,
+ 0x9df5, 0x3a99,
+ 0x9df7, 0x268b,
+ 0x9df8, 0x3a9b,
+ 0x9dfa, 0x1f76,
+ 0x9dfb, 0x3a9d,
+ 0x9dfd, 0x216d,
+ 0x9dfe, 0x3a9f,
+ 0x9e40, 0x3aa0,
+ 0x9e45, 0x2001,
+ 0x9e46, 0x3aa5,
+ 0x9e48, 0x2191,
+ 0x9e49, 0x1e50,
+ 0x9e4a, 0x3aa7,
+ 0x9e52, 0x1f9c,
+ 0x9e53, 0x3aaf,
+ 0x9e54, 0x23da,
+ 0x9e55, 0x3ab0,
+ 0x9e56, 0x2053,
+ 0x9e57, 0x3ab1,
+ 0x9e5d, 0x23e9,
+ 0x9e5e, 0x23e4,
+ 0x9e5f, 0x3ab7,
+ 0x9e61, 0x21d5,
+ 0x9e62, 0x3ab9,
+ 0x9e63, 0x23e6,
+ 0x9e64, 0x3aba,
+ 0x9e67, 0x23df,
+ 0x9e68, 0x3abd,
+ 0x9e6c, 0x1e4f,
+ 0x9e6d, 0x3ac1,
+ 0x9e6f, 0x23d9,
+ 0x9e70, 0x3ac3,
+ 0x9e72, 0x2014,
+ 0x9e73, 0x3ac5,
+ 0x9e74, 0x23ec,
+ 0x9e75, 0x23eb,
+ 0x9e76, 0x3ac6,
+ 0x9e7b, 0x23d8,
+ 0x9e7c, 0x23ee,
+ 0x9e7d, 0x3acb,
+ 0x9e80, 0x3acd,
+ 0x9e85, 0x268e,
+ 0x9e86, 0x3ad2,
+ 0x9e87, 0x23ed,
+ 0x9e88, 0x3ad3,
+ 0x9e91, 0x1ffa,
+ 0x9e92, 0x3adc,
+ 0x9e96, 0x23d6,
+ 0x9e97, 0x23e8,
+ 0x9e98, 0x3ae0,
+ 0x9ea2, 0x2106,
+ 0x9ea3, 0x3aea,
+ 0x9ea6, 0x200b,
+ 0x9ea7, 0x3aed,
+ 0x9ea9, 0x2166,
+ 0x9eaa, 0x3aef,
+ 0x9eae, 0x23ef,
+ 0x9eaf, 0x3af3,
+ 0x9eb3, 0x2189,
+ 0x9eb4, 0x2058,
+ 0x9eb5, 0x3af7,
+ 0x9eb7, 0x23e7,
+ 0x9eb8, 0x3af9,
+ 0x9ef5, 0x21a3,
+ 0x9ef6, 0x3b36,
+ 0x9f40, 0x3b3f,
+ 0x9f4e, 0x217a,
+ 0x9f4f, 0x3b4d,
+ 0x9f6f, 0x21a5,
+ 0x9f70, 0x3b6d,
+ 0x9f80, 0x3b7c,
+ 0x9f92, 0x2022,
+ 0x9f93, 0x3b8e,
+ 0x9f98, 0x24d6,
+ 0x9f99, 0x3b93,
+ 0x9fa6, 0x233a,
+ 0x9fa7, 0x3ba0,
+ 0x9fa9, 0x1eee,
+ 0x9faa, 0x3ba2,
+ 0x9fac, 0x24d5,
+ 0x9fad, 0x3ba4,
+ 0x9fc9, 0x2228,
+ 0x9fca, 0x3bc0,
+ 0x9fcd, 0x24d7,
+ 0x9fce, 0x3bc3,
+ 0x9fe1, 0x20fc,
+ 0x9fe2, 0x3bd6,
+ 0x9feb, 0x1e87,
+ 0x9fec, 0x3bdf,
+ 0x9fee, 0x24d8,
+ 0x9fef, 0x3be1,
+ 0x9ff4, 0x1eba,
+ 0x9ff5, 0x3be6,
+ 0x9ffd, 0x2119,
+ 0x9ffe, 0x3bee,
+ 0xa040, 0x3bef,
+ 0xa043, 0x216c,
+ 0xa044, 0x3bf2,
+ 0xa046, 0x24d9,
+ 0xa047, 0x3bf4,
+ 0xa049, 0x2227,
+ 0xa04a, 0x3bf6,
+ 0xa04e, 0x1e5f,
+ 0xa04f, 0x3bfa,
+ 0xa054, 0x229f,
+ 0xa055, 0x3bff,
+ 0xa05a, 0x1f5d,
+ 0xa05b, 0x3c04,
+ 0xa061, 0x1fbc,
+ 0xa062, 0x3c0a,
+ 0xa063, 0x24da,
+ 0xa064, 0x3c0b,
+ 0xa071, 0x2149,
+ 0xa072, 0x3c18,
+ 0xa074, 0x2046,
+ 0xa075, 0x3c1a,
+ 0xa080, 0x2000,
+ 0xa081, 0x3c24,
+ 0xa091, 0x2190,
+ 0xa092, 0x3c34,
+ 0xa094, 0x2208,
+ 0xa095, 0x3c36,
+ 0xa096, 0x1ee6,
+ 0xa097, 0x3c37,
+ 0xa0a9, 0x24c3,
+ 0xa0aa, 0x3c49,
+ 0xa0bf, 0x20cc,
+ 0xa0c0, 0x3c5e,
+ 0xa0ce, 0x2340,
+ 0xa0cf, 0x3c6c,
+ 0xa0d9, 0x1ed1,
+ 0xa0da, 0x3c76,
+ 0xa0de, 0x21ac,
+ 0xa0df, 0x3c7a,
+ 0xa0ee, 0x22af,
+ 0xa0ef, 0x3c89,
+ 0xa1a1, 0x0060,
+ 0xa2a1, 0x26a9,
+ 0xa2b1, 0x00be,
+ 0xa2e5, 0x00f0,
+ 0xa2f1, 0x00fa,
+ 0xa3a1, 0x0106,
+ 0xa4a1, 0x0164,
+ 0xa5a1, 0x01b7,
+ 0xa6a1, 0x020d,
+ 0xa6c1, 0x0225,
+ 0xa7a1, 0x025a,
+ 0xa7d1, 0x027b,
+ 0xa840, 0x26b3,
+ 0xa880, 0x26f2,
+ 0xa8a1, 0x029c,
+ 0xa8c5, 0x02bc,
+ 0xa940, 0x2708,
+ 0xa959, 0x2720,
+ 0xa95c, 0x2722,
+ 0xa960, 0x2723,
+ 0xa980, 0x2742,
+ 0xa996, 0x1e17,
+ 0xa9a4, 0x02e2,
+ 0xaa40, 0x3c99,
+ 0xaa4d, 0x21b6,
+ 0xaa4e, 0x1e3d,
+ 0xaa4f, 0x3ca6,
+ 0xaa71, 0x2235,
+ 0xaa72, 0x3cc8,
+ 0xaa73, 0x2397,
+ 0xaa74, 0x3cc9,
+ 0xaa77, 0x2395,
+ 0xaa78, 0x3ccc,
+ 0xaa7a, 0x223f,
+ 0xaa7b, 0x212a,
+ 0xaa7c, 0x3cce,
+ 0xaa80, 0x3cd1,
+ 0xaa9a, 0x1ed2,
+ 0xaa9b, 0x3ceb,
+ 0xaa9c, 0x2396,
+ 0xaa9d, 0x2398,
+ 0xaa9e, 0x3cec,
+ 0xaa9f, 0x20a2,
+ 0xaaa0, 0x3ced,
+ 0xaaa1, 0x032e,
+ 0xab40, 0x1f64,
+ 0xab41, 0x3cee,
+ 0xab43, 0x202b,
+ 0xab44, 0x3cf0,
+ 0xab45, 0x2394,
+ 0xab46, 0x2139,
+ 0xab47, 0x3cf1,
+ 0xab48, 0x215f,
+ 0xab49, 0x21c1,
+ 0xab4a, 0x239a,
+ 0xab4b, 0x3cf2,
+ 0xab4d, 0x2399,
+ 0xab4e, 0x3cf4,
+ 0xab80, 0x3d25,
+ 0xaba1, 0x038c,
+ 0xac40, 0x3d46,
+ 0xac46, 0x21c0,
+ 0xac47, 0x3d4c,
+ 0xac71, 0x2460,
+ 0xac72, 0x3d76,
+ 0xac7c, 0x245c,
+ 0xac7d, 0x3d80,
+ 0xac80, 0x3d82,
+ 0xac8d, 0x215d,
+ 0xac8e, 0x3d8f,
+ 0xac93, 0x2225,
+ 0xac94, 0x206a,
+ 0xac95, 0x3d94,
+ 0xad40, 0x3da0,
+ 0xad49, 0x2461,
+ 0xad4a, 0x3da9,
+ 0xad5e, 0x245b,
+ 0xad5f, 0x3dbd,
+ 0xad61, 0x2462,
+ 0xad62, 0x3dbf,
+ 0xad68, 0x1f54,
+ 0xad69, 0x3dc5,
+ 0xad74, 0x245f,
+ 0xad75, 0x3dd0,
+ 0xad80, 0x3dda,
+ 0xad82, 0x20ec,
+ 0xad83, 0x3ddc,
+ 0xad87, 0x245d,
+ 0xad88, 0x3de0,
+ 0xad8b, 0x2463,
+ 0xad8c, 0x3de3,
+ 0xad91, 0x2464,
+ 0xad92, 0x3de8,
+ 0xae40, 0x3df7,
+ 0xae54, 0x24a5,
+ 0xae55, 0x3e0b,
+ 0xae62, 0x1e70,
+ 0xae63, 0x3e18,
+ 0xae80, 0x208f,
+ 0xae81, 0x3e34,
+ 0xae85, 0x1e42,
+ 0xae86, 0x3e38,
+ 0xae8b, 0x1f4e,
+ 0xae8c, 0x3e3d,
+ 0xae94, 0x1eb1,
+ 0xae95, 0x3e45,
+ 0xaea0, 0x1e8b,
+ 0xaf40, 0x3e50,
+ 0xaf64, 0x1fc6,
+ 0xaf65, 0x3e74,
+ 0xaf7b, 0x25ae,
+ 0xaf7c, 0x3e8a,
+ 0xaf80, 0x3e8d,
+ 0xaf82, 0x1f01,
+ 0xaf83, 0x2200,
+ 0xaf84, 0x3e8f,
+ 0xaf8e, 0x25b2,
+ 0xaf8f, 0x1e97,
+ 0xaf90, 0x3e99,
+ 0xaf91, 0x20ab,
+ 0xaf92, 0x3e9a,
+ 0xaf9c, 0x25b3,
+ 0xaf9d, 0x3ea4,
+ 0xaf9f, 0x2028,
+ 0xafa0, 0x3ea6,
+ 0xb040, 0x3ea7,
+ 0xb041, 0x25af,
+ 0xb043, 0x3ea8,
+ 0xb044, 0x25b1,
+ 0xb045, 0x3ea9,
+ 0xb04f, 0x25ac,
+ 0xb050, 0x3eb3,
+ 0xb054, 0x1e4e,
+ 0xb055, 0x3eb7,
+ 0xb057, 0x2202,
+ 0xb058, 0x25ab,
+ 0xb059, 0x2286,
+ 0xb05a, 0x3eb9,
+ 0xb05b, 0x25ad,
+ 0xb05c, 0x3eba,
+ 0xb05d, 0x25b6,
+ 0xb05e, 0x3ebb,
+ 0xb05f, 0x21e3,
+ 0xb060, 0x25b4,
+ 0xb062, 0x222f,
+ 0xb063, 0x2165,
+ 0xb064, 0x25b7,
+ 0xb065, 0x3ebc,
+ 0xb06c, 0x1ee9,
+ 0xb06d, 0x3ec3,
+ 0xb07d, 0x1e25,
+ 0xb07e, 0x3ed3,
+ 0xb080, 0x3ed4,
+ 0xb097, 0x25c0,
+ 0xb098, 0x3eeb,
+ 0xb099, 0x229a,
+ 0xb09a, 0x3eec,
+ 0xb0a1, 0x03ac,
+ 0xb140, 0x3ef3,
+ 0xb14b, 0x226e,
+ 0xb14c, 0x3efe,
+ 0xb14d, 0x1fbd,
+ 0xb14e, 0x3eff,
+ 0xb14f, 0x1f84,
+ 0xb150, 0x20b2,
+ 0xb151, 0x3f00,
+ 0xb152, 0x2043,
+ 0xb153, 0x3f01,
+ 0xb180, 0x3f2d,
+ 0xb197, 0x2684,
+ 0xb198, 0x3f44,
+ 0xb1a1, 0x040a,
+ 0xb240, 0x3f4d,
+ 0xb241, 0x24ef,
+ 0xb242, 0x3f4e,
+ 0xb267, 0x24ee,
+ 0xb268, 0x3f73,
+ 0xb26d, 0x2074,
+ 0xb26e, 0x3f78,
+ 0xb274, 0x2687,
+ 0xb275, 0x3f7e,
+ 0xb280, 0x24f0,
+ 0xb281, 0x3f88,
+ 0xb289, 0x268d,
+ 0xb28a, 0x3f90,
+ 0xb29a, 0x22a0,
+ 0xb29b, 0x3fa0,
+ 0xb2a1, 0x0468,
+ 0xb340, 0x3fa6,
+ 0xb343, 0x1fab,
+ 0xb344, 0x3fa9,
+ 0xb370, 0x26a8,
+ 0xb371, 0x3fd5,
+ 0xb380, 0x3fe3,
+ 0xb388, 0x24e9,
+ 0xb389, 0x3feb,
+ 0xb38c, 0x24e5,
+ 0xb38d, 0x3fee,
+ 0xb38e, 0x21fa,
+ 0xb38f, 0x3fef,
+ 0xb3a1, 0x04c6,
+ 0xb440, 0x4001,
+ 0xb454, 0x2148,
+ 0xb455, 0x4015,
+ 0xb458, 0x24e4,
+ 0xb459, 0x4018,
+ 0xb45e, 0x24e6,
+ 0xb45f, 0x20f7,
+ 0xb460, 0x401d,
+ 0xb461, 0x206b,
+ 0xb462, 0x401e,
+ 0xb475, 0x22a7,
+ 0xb476, 0x4031,
+ 0xb47e, 0x24ec,
+ 0xb480, 0x4039,
+ 0xb483, 0x24eb,
+ 0xb484, 0x403c,
+ 0xb489, 0x24e3,
+ 0xb48a, 0x4041,
+ 0xb493, 0x24ea,
+ 0xb494, 0x404a,
+ 0xb4a1, 0x0524,
+ 0xb540, 0x4057,
+ 0xb541, 0x1e92,
+ 0xb542, 0x4058,
+ 0xb54b, 0x1e27,
+ 0xb54c, 0x4061,
+ 0xb556, 0x1fe6,
+ 0xb557, 0x406b,
+ 0xb55a, 0x24e7,
+ 0xb55b, 0x2012,
+ 0xb55c, 0x1eec,
+ 0xb55d, 0x406e,
+ 0xb561, 0x24e8,
+ 0xb562, 0x4072,
+ 0xb580, 0x408f,
+ 0xb59c, 0x1f66,
+ 0xb59d, 0x24dc,
+ 0xb59e, 0x40ab,
+ 0xb5a1, 0x0582,
+ 0xb640, 0x40ae,
+ 0xb652, 0x26a2,
+ 0xb653, 0x40c0,
+ 0xb655, 0x24dd,
+ 0xb656, 0x40c2,
+ 0xb659, 0x200e,
+ 0xb65a, 0x40c5,
+ 0xb65b, 0x24db,
+ 0xb65c, 0x1eb8,
+ 0xb65d, 0x40c6,
+ 0xb680, 0x40e8,
+ 0xb6a1, 0x05e0,
+ 0xb740, 0x4109,
+ 0xb74e, 0x2295,
+ 0xb74f, 0x4117,
+ 0xb751, 0x1e80,
+ 0xb752, 0x4119,
+ 0xb759, 0x2677,
+ 0xb75a, 0x4120,
+ 0xb764, 0x2624,
+ 0xb765, 0x1f69,
+ 0xb766, 0x222b,
+ 0xb767, 0x412a,
+ 0xb777, 0x257f,
+ 0xb778, 0x1f5b,
+ 0xb779, 0x413a,
+ 0xb780, 0x219b,
+ 0xb781, 0x4140,
+ 0xb782, 0x267d,
+ 0xb783, 0x4141,
+ 0xb7a1, 0x063e,
+ 0xb840, 0x415f,
+ 0xb843, 0x21a0,
+ 0xb844, 0x2186,
+ 0xb845, 0x4162,
+ 0xb846, 0x20ed,
+ 0xb847, 0x4163,
+ 0xb84d, 0x25b9,
+ 0xb84e, 0x4169,
+ 0xb851, 0x1fea,
+ 0xb852, 0x416c,
+ 0xb85a, 0x1ea4,
+ 0xb85b, 0x20e1,
+ 0xb85c, 0x4174,
+ 0xb85d, 0x25b8,
+ 0xb85e, 0x2260,
+ 0xb85f, 0x4175,
+ 0xb860, 0x20e2,
+ 0xb861, 0x4176,
+ 0xb877, 0x2141,
+ 0xb878, 0x418c,
+ 0xb880, 0x4193,
+ 0xb882, 0x1fc7,
+ 0xb883, 0x4195,
+ 0xb8a1, 0x069c,
+ 0xb940, 0x41b3,
+ 0xb950, 0x1e41,
+ 0xb951, 0x41c3,
+ 0xb961, 0x25e4,
+ 0xb962, 0x41d3,
+ 0xb97b, 0x1f86,
+ 0xb97c, 0x41ec,
+ 0xb980, 0x41ef,
+ 0xb99d, 0x1fb3,
+ 0xb99e, 0x420c,
+ 0xb9a0, 0x1eef,
+ 0xb9a1, 0x06fa,
+ 0xba40, 0x420e,
+ 0xba42, 0x22a4,
+ 0xba43, 0x4210,
+ 0xba44, 0x25e8,
+ 0xba45, 0x4211,
+ 0xba56, 0x25e3,
+ 0xba57, 0x4222,
+ 0xba59, 0x2111,
+ 0xba5a, 0x4224,
+ 0xba60, 0x25e6,
+ 0xba61, 0x422a,
+ 0xba6a, 0x25e7,
+ 0xba6b, 0x4233,
+ 0xba74, 0x2041,
+ 0xba75, 0x423c,
+ 0xba80, 0x4246,
+ 0xba84, 0x25ea,
+ 0xba85, 0x424a,
+ 0xba86, 0x1f8f,
+ 0xba87, 0x424b,
+ 0xba88, 0x25ec,
+ 0xba89, 0x424c,
+ 0xba8d, 0x25eb,
+ 0xba8e, 0x4250,
+ 0xba9e, 0x20d0,
+ 0xba9f, 0x201d,
+ 0xbaa0, 0x4260,
+ 0xbaa1, 0x0758,
+ 0xbb40, 0x1ff7,
+ 0xbb41, 0x4261,
+ 0xbb49, 0x1e8d,
+ 0xbb4a, 0x4269,
+ 0xbb58, 0x25e9,
+ 0xbb59, 0x4277,
+ 0xbb5b, 0x25ee,
+ 0xbb5c, 0x203a,
+ 0xbb5d, 0x4279,
+ 0xbb60, 0x2693,
+ 0xbb61, 0x427c,
+ 0xbb65, 0x25e5,
+ 0xbb66, 0x25ed,
+ 0xbb67, 0x4280,
+ 0xbb68, 0x2009,
+ 0xbb69, 0x4281,
+ 0xbb6a, 0x2065,
+ 0xbb6b, 0x4282,
+ 0xbb6e, 0x26a3,
+ 0xbb6f, 0x4285,
+ 0xbb80, 0x4295,
+ 0xbba1, 0x07b6,
+ 0xbc40, 0x42b6,
+ 0xbc52, 0x25f5,
+ 0xbc53, 0x1efc,
+ 0xbc54, 0x42c8,
+ 0xbc5a, 0x2024,
+ 0xbc5b, 0x42ce,
+ 0xbc61, 0x269b,
+ 0xbc62, 0x42d4,
+ 0xbc63, 0x25f3,
+ 0xbc64, 0x42d5,
+ 0xbc65, 0x22d9,
+ 0xbc66, 0x42d6,
+ 0xbc67, 0x25f4,
+ 0xbc68, 0x42d7,
+ 0xbc69, 0x241b,
+ 0xbc6a, 0x42d8,
+ 0xbc6d, 0x1fc8,
+ 0xbc6e, 0x42db,
+ 0xbc6f, 0x1f7b,
+ 0xbc70, 0x42dc,
+ 0xbc71, 0x241d,
+ 0xbc72, 0x42dd,
+ 0xbc73, 0x224c,
+ 0xbc74, 0x1f48,
+ 0xbc75, 0x241c,
+ 0xbc76, 0x241e,
+ 0xbc78, 0x20ff,
+ 0xbc79, 0x219a,
+ 0xbc7a, 0x42de,
+ 0xbc7b, 0x2091,
+ 0xbc7c, 0x42df,
+ 0xbc7e, 0x20a7,
+ 0xbc80, 0x42e1,
+ 0xbc82, 0x2423,
+ 0xbc83, 0x1e9b,
+ 0xbc84, 0x2422,
+ 0xbc85, 0x42e3,
+ 0xbc86, 0x2110,
+ 0xbc87, 0x42e4,
+ 0xbc88, 0x228d,
+ 0xbc89, 0x1f71,
+ 0xbc8a, 0x1ef8,
+ 0xbc8b, 0x2421,
+ 0xbc8c, 0x42e5,
+ 0xbc8f, 0x1ef3,
+ 0xbc90, 0x42e8,
+ 0xbc9a, 0x21b1,
+ 0xbc9b, 0x2426,
+ 0xbc9c, 0x2425,
+ 0xbc9d, 0x2120,
+ 0xbc9e, 0x42f2,
+ 0xbca1, 0x0814,
+ 0xbd40, 0x42f5,
+ 0xbd42, 0x211a,
+ 0xbd43, 0x2424,
+ 0xbd44, 0x42f7,
+ 0xbd45, 0x2428,
+ 0xbd46, 0x42f8,
+ 0xbd48, 0x242a,
+ 0xbd49, 0x2429,
+ 0xbd4a, 0x42fa,
+ 0xbd4b, 0x2294,
+ 0xbd4c, 0x42fb,
+ 0xbd4d, 0x22be,
+ 0xbd4e, 0x42fc,
+ 0xbd4f, 0x1e31,
+ 0xbd50, 0x42fd,
+ 0xbd57, 0x242c,
+ 0xbd58, 0x4304,
+ 0xbd59, 0x1fb5,
+ 0xbd5a, 0x4305,
+ 0xbd66, 0x242b,
+ 0xbd67, 0x1faf,
+ 0xbd68, 0x4311,
+ 0xbd6a, 0x2068,
+ 0xbd6b, 0x21e4,
+ 0xbd6c, 0x4313,
+ 0xbd6f, 0x1f21,
+ 0xbd70, 0x4316,
+ 0xbd71, 0x2101,
+ 0xbd72, 0x4317,
+ 0xbd79, 0x217c,
+ 0xbd7a, 0x214a,
+ 0xbd7b, 0x242d,
+ 0xbd7c, 0x431e,
+ 0xbd7e, 0x1fd4,
+ 0xbd80, 0x4320,
+ 0xbd81, 0x1fd1,
+ 0xbd82, 0x4321,
+ 0xbd89, 0x1e33,
+ 0xbd8a, 0x4328,
+ 0xbd8b, 0x242f,
+ 0xbd8c, 0x4329,
+ 0xbd8e, 0x242e,
+ 0xbd8f, 0x432b,
+ 0xbd90, 0x2430,
+ 0xbd91, 0x21db,
+ 0xbd92, 0x432c,
+ 0xbd97, 0x2158,
+ 0xbd98, 0x4331,
+ 0xbd9b, 0x1fc2,
+ 0xbd9c, 0x4334,
+ 0xbda1, 0x0872,
+ 0xbe40, 0x4339,
+ 0xbe43, 0x22b9,
+ 0xbe44, 0x433c,
+ 0xbe45, 0x2436,
+ 0xbe46, 0x433d,
+ 0xbe49, 0x1e8e,
+ 0xbe4a, 0x2439,
+ 0xbe4b, 0x4340,
+ 0xbe51, 0x21c5,
+ 0xbe52, 0x2437,
+ 0xbe53, 0x2192,
+ 0xbe54, 0x4346,
+ 0xbe55, 0x243a,
+ 0xbe56, 0x1f19,
+ 0xbe57, 0x218c,
+ 0xbe58, 0x1e40,
+ 0xbe59, 0x22b3,
+ 0xbe5a, 0x4347,
+ 0xbe5d, 0x205f,
+ 0xbe5e, 0x2438,
+ 0xbe5f, 0x2432,
+ 0xbe60, 0x2274,
+ 0xbe61, 0x434a,
+ 0xbe62, 0x1e9c,
+ 0xbe63, 0x2431,
+ 0xbe64, 0x2085,
+ 0xbe65, 0x434b,
+ 0xbe69, 0x2435,
+ 0xbe6a, 0x434f,
+ 0xbe6c, 0x243b,
+ 0xbe6d, 0x4351,
+ 0xbe6f, 0x1fb7,
+ 0xbe70, 0x2433,
+ 0xbe71, 0x4353,
+ 0xbe76, 0x2054,
+ 0xbe77, 0x21de,
+ 0xbe78, 0x4358,
+ 0xbe79, 0x2434,
+ 0xbe7a, 0x4359,
+ 0xbe7c, 0x243d,
+ 0xbe7d, 0x1f89,
+ 0xbe7e, 0x243c,
+ 0xbe80, 0x435b,
+ 0xbe83, 0x1f6e,
+ 0xbe84, 0x1ed8,
+ 0xbe85, 0x435e,
+ 0xbe86, 0x1ebf,
+ 0xbe87, 0x2445,
+ 0xbe88, 0x435f,
+ 0xbe89, 0x2249,
+ 0xbe8a, 0x4360,
+ 0xbe8c, 0x2441,
+ 0xbe8d, 0x4362,
+ 0xbe8e, 0x1e47,
+ 0xbe8f, 0x1f56,
+ 0xbe90, 0x4363,
+ 0xbe92, 0x2086,
+ 0xbe93, 0x4365,
+ 0xbe95, 0x2196,
+ 0xbe96, 0x4367,
+ 0xbe97, 0x2443,
+ 0xbe98, 0x243f,
+ 0xbe99, 0x4368,
+ 0xbe9a, 0x2023,
+ 0xbe9b, 0x4369,
+ 0xbe9c, 0x2442,
+ 0xbe9d, 0x436a,
+ 0xbe9f, 0x243e,
+ 0xbea0, 0x436c,
+ 0xbea1, 0x08d0,
+ 0xbf40, 0x26a6,
+ 0xbf41, 0x436d,
+ 0xbf4d, 0x234e,
+ 0xbf4e, 0x2446,
+ 0xbf4f, 0x244b,
+ 0xbf50, 0x2444,
+ 0xbf51, 0x4379,
+ 0xbf55, 0x2427,
+ 0xbf56, 0x244c,
+ 0xbf57, 0x437d,
+ 0xbf60, 0x1f0f,
+ 0xbf61, 0x4386,
+ 0xbf62, 0x2447,
+ 0xbf63, 0x2449,
+ 0xbf64, 0x2448,
+ 0xbf65, 0x4387,
+ 0xbf68, 0x21c2,
+ 0xbf69, 0x438a,
+ 0xbf6c, 0x216e,
+ 0xbf6d, 0x438d,
+ 0xbf70, 0x1f03,
+ 0xbf71, 0x4390,
+ 0xbf72, 0x244a,
+ 0xbf73, 0x215c,
+ 0xbf74, 0x4391,
+ 0xbf76, 0x22bb,
+ 0xbf77, 0x2450,
+ 0xbf78, 0x4393,
+ 0xbf79, 0x2694,
+ 0xbf7a, 0x244f,
+ 0xbf7b, 0x25f6,
+ 0xbf7c, 0x2051,
+ 0xbf7d, 0x4394,
+ 0xbf7e, 0x244e,
+ 0xbf80, 0x4395,
+ 0xbf82, 0x22ba,
+ 0xbf83, 0x1f6d,
+ 0xbf84, 0x4397,
+ 0xbf89, 0x2452,
+ 0xbf8a, 0x2451,
+ 0xbf8b, 0x439c,
+ 0xbf95, 0x2455,
+ 0xbf96, 0x43a6,
+ 0xbf97, 0x2289,
+ 0xbf98, 0x2116,
+ 0xbf99, 0x43a7,
+ 0xbf9d, 0x2454,
+ 0xbf9e, 0x43ab,
+ 0xbfa1, 0x092e,
+ 0xc040, 0x20fb,
+ 0xc041, 0x43ae,
+ 0xc044, 0x2440,
+ 0xc045, 0x43b1,
+ 0xc04b, 0x2126,
+ 0xc04c, 0x1f61,
+ 0xc04d, 0x269d,
+ 0xc04e, 0x43b7,
+ 0xc04f, 0x1f8a,
+ 0xc050, 0x2456,
+ 0xc051, 0x2459,
+ 0xc052, 0x2458,
+ 0xc053, 0x43b8,
+ 0xc055, 0x1fae,
+ 0xc056, 0x43ba,
+ 0xc05b, 0x221a,
+ 0xc05c, 0x43bf,
+ 0xc05e, 0x1f7a,
+ 0xc05f, 0x244d,
+ 0xc060, 0x2457,
+ 0xc061, 0x43c1,
+ 0xc069, 0x2453,
+ 0xc06a, 0x43c9,
+ 0xc06b, 0x2420,
+ 0xc06c, 0x43ca,
+ 0xc06d, 0x21df,
+ 0xc06e, 0x2685,
+ 0xc06f, 0x43cb,
+ 0xc070, 0x1e6e,
+ 0xc071, 0x43cc,
+ 0xc074, 0x2224,
+ 0xc075, 0x2670,
+ 0xc076, 0x43cf,
+ 0xc077, 0x21ba,
+ 0xc078, 0x43d0,
+ 0xc079, 0x245a,
+ 0xc07a, 0x43d1,
+ 0xc07c, 0x1fff,
+ 0xc07d, 0x43d3,
+ 0xc080, 0x43d5,
+ 0xc09b, 0x25e2,
+ 0xc09c, 0x43f0,
+ 0xc09d, 0x269a,
+ 0xc09e, 0x43f1,
+ 0xc0a1, 0x098c,
+ 0xc140, 0x43f4,
+ 0xc150, 0x1eea,
+ 0xc151, 0x4404,
+ 0xc154, 0x1e2c,
+ 0xc155, 0x4407,
+ 0xc15f, 0x2062,
+ 0xc160, 0x24f1,
+ 0xc161, 0x4411,
+ 0xc162, 0x24f2,
+ 0xc163, 0x4412,
+ 0xc175, 0x25f2,
+ 0xc176, 0x4424,
+ 0xc178, 0x2215,
+ 0xc179, 0x4426,
+ 0xc180, 0x442c,
+ 0xc195, 0x21ae,
+ 0xc196, 0x4441,
+ 0xc1a1, 0x09ea,
+ 0xc240, 0x444c,
+ 0xc24e, 0x20e0,
+ 0xc24f, 0x445a,
+ 0xc265, 0x25c2,
+ 0xc266, 0x4470,
+ 0xc267, 0x25c1,
+ 0xc268, 0x4471,
+ 0xc27d, 0x2128,
+ 0xc27e, 0x4486,
+ 0xc280, 0x4487,
+ 0xc284, 0x2199,
+ 0xc285, 0x448b,
+ 0xc293, 0x2017,
+ 0xc294, 0x1ea0,
+ 0xc295, 0x2125,
+ 0xc296, 0x214d,
+ 0xc297, 0x4499,
+ 0xc298, 0x25c4,
+ 0xc299, 0x209d,
+ 0xc29a, 0x228a,
+ 0xc29b, 0x449a,
+ 0xc29c, 0x25c3,
+ 0xc29d, 0x449b,
+ 0xc2a0, 0x2179,
+ 0xc2a1, 0x0a48,
+ 0xc340, 0x2038,
+ 0xc341, 0x449e,
+ 0xc343, 0x2155,
+ 0xc344, 0x44a0,
+ 0xc37b, 0x21d2,
+ 0xc37c, 0x44d7,
+ 0xc380, 0x44da,
+ 0xc384, 0x24c7,
+ 0xc385, 0x44de,
+ 0xc39b, 0x2279,
+ 0xc39c, 0x44f4,
+ 0xc3a1, 0x0aa6,
+ 0xc440, 0x44f9,
+ 0xc449, 0x2123,
+ 0xc44a, 0x4502,
+ 0xc44c, 0x24c5,
+ 0xc44d, 0x4504,
+ 0xc454, 0x24c9,
+ 0xc455, 0x450b,
+ 0xc458, 0x2094,
+ 0xc459, 0x450e,
+ 0xc45b, 0x2296,
+ 0xc45c, 0x4510,
+ 0xc463, 0x1e77,
+ 0xc464, 0x4517,
+ 0xc477, 0x1f06,
+ 0xc478, 0x452a,
+ 0xc47a, 0x1fa5,
+ 0xc47b, 0x452c,
+ 0xc480, 0x4530,
+ 0xc481, 0x2099,
+ 0xc482, 0x4531,
+ 0xc491, 0x1ead,
+ 0xc492, 0x24c8,
+ 0xc493, 0x20a8,
+ 0xc494, 0x4540,
+ 0xc498, 0x201f,
+ 0xc499, 0x4544,
+ 0xc49a, 0x20c5,
+ 0xc49b, 0x4545,
+ 0xc49c, 0x24ca,
+ 0xc49d, 0x4546,
+ 0xc4a1, 0x0b04,
+ 0xc540, 0x454a,
+ 0xc544, 0x1ff0,
+ 0xc545, 0x454e,
+ 0xc546, 0x24c6,
+ 0xc547, 0x454f,
+ 0xc54b, 0x225d,
+ 0xc54c, 0x22de,
+ 0xc54d, 0x4553,
+ 0xc552, 0x202c,
+ 0xc553, 0x4558,
+ 0xc55f, 0x2161,
+ 0xc560, 0x4564,
+ 0xc563, 0x223b,
+ 0xc564, 0x21d9,
+ 0xc565, 0x1fcb,
+ 0xc566, 0x1fc9,
+ 0xc567, 0x4567,
+ 0xc580, 0x457f,
+ 0xc593, 0x1e61,
+ 0xc594, 0x4592,
+ 0xc59c, 0x25ef,
+ 0xc59d, 0x459a,
+ 0xc59e, 0x1f98,
+ 0xc59f, 0x459b,
+ 0xc5a1, 0x0b62,
+ 0xc640, 0x459d,
+ 0xc641, 0x25f0,
+ 0xc642, 0x459e,
+ 0xc644, 0x1f88,
+ 0xc645, 0x45a0,
+ 0xc647, 0x21f8,
+ 0xc648, 0x45a2,
+ 0xc663, 0x2322,
+ 0xc664, 0x45bd,
+ 0xc672, 0x2336,
+ 0xc673, 0x45cb,
+ 0xc680, 0x45d7,
+ 0xc6a1, 0x0bc0,
+ 0xc740, 0x45f8,
+ 0xc766, 0x22ab,
+ 0xc767, 0x461e,
+ 0xc76f, 0x1fbf,
+ 0xc770, 0x4626,
+ 0xc776, 0x1f7d,
+ 0xc777, 0x462c,
+ 0xc77b, 0x2333,
+ 0xc77c, 0x4630,
+ 0xc780, 0x4633,
+ 0xc7a1, 0x0c1e,
+ 0xc840, 0x4654,
+ 0xc841, 0x1f4d,
+ 0xc842, 0x4655,
+ 0xc84f, 0x2334,
+ 0xc850, 0x4662,
+ 0xc852, 0x1ff1,
+ 0xc853, 0x4664,
+ 0xc866, 0x218b,
+ 0xc867, 0x4677,
+ 0xc86e, 0x2349,
+ 0xc86f, 0x467e,
+ 0xc87e, 0x220b,
+ 0xc880, 0x468d,
+ 0xc887, 0x2346,
+ 0xc888, 0x4694,
+ 0xc892, 0x2347,
+ 0xc893, 0x469e,
+ 0xc894, 0x2193,
+ 0xc895, 0x469f,
+ 0xc899, 0x26a1,
+ 0xc89a, 0x46a3,
+ 0xc89d, 0x1f62,
+ 0xc89e, 0x46a6,
+ 0xc8a1, 0x0c7c,
+ 0xc940, 0x46a9,
+ 0xc94f, 0x234d,
+ 0xc950, 0x2348,
+ 0xc951, 0x46b8,
+ 0xc96e, 0x1e60,
+ 0xc96f, 0x46d5,
+ 0xc970, 0x2345,
+ 0xc971, 0x46d6,
+ 0xc977, 0x1f12,
+ 0xc978, 0x46dc,
+ 0xc980, 0x46e3,
+ 0xc98f, 0x2018,
+ 0xc990, 0x2335,
+ 0xc991, 0x46f2,
+ 0xc99c, 0x233c,
+ 0xc99d, 0x46fd,
+ 0xc9a1, 0x0cda,
+ 0xca40, 0x4701,
+ 0xca4e, 0x266f,
+ 0xca4f, 0x470f,
+ 0xca56, 0x2351,
+ 0xca57, 0x4716,
+ 0xca59, 0x1fa0,
+ 0xca5a, 0x4718,
+ 0xca5c, 0x2338,
+ 0xca5d, 0x471a,
+ 0xca61, 0x221b,
+ 0xca62, 0x471e,
+ 0xca6e, 0x2342,
+ 0xca6f, 0x472a,
+ 0xca72, 0x234f,
+ 0xca73, 0x472d,
+ 0xca77, 0x233d,
+ 0xca78, 0x4731,
+ 0xca7b, 0x2344,
+ 0xca7c, 0x2331,
+ 0xca7d, 0x4734,
+ 0xca7e, 0x234b,
+ 0xca80, 0x4735,
+ 0xca81, 0x233b,
+ 0xca82, 0x4736,
+ 0xca89, 0x2350,
+ 0xca8a, 0x473d,
+ 0xca8e, 0x1eb4,
+ 0xca8f, 0x21a6,
+ 0xca90, 0x4741,
+ 0xca92, 0x21cb,
+ 0xca93, 0x4743,
+ 0xca9a, 0x2355,
+ 0xca9b, 0x474a,
+ 0xcaa1, 0x0d38,
+ 0xcb40, 0x4750,
+ 0xcb43, 0x233e,
+ 0xcb44, 0x4753,
+ 0xcb45, 0x1f74,
+ 0xcb46, 0x4754,
+ 0xcb47, 0x2330,
+ 0xcb48, 0x4755,
+ 0xcb4b, 0x2680,
+ 0xcb4c, 0x4758,
+ 0xcb4e, 0x20da,
+ 0xcb4f, 0x475a,
+ 0xcb57, 0x234a,
+ 0xcb58, 0x4762,
+ 0xcb5d, 0x1f91,
+ 0xcb5e, 0x4767,
+ 0xcb5f, 0x2107,
+ 0xcb60, 0x4768,
+ 0xcb6a, 0x233f,
+ 0xcb6b, 0x4772,
+ 0xcb7b, 0x1ff4,
+ 0xcb7c, 0x2343,
+ 0xcb7d, 0x4782,
+ 0xcb80, 0x4784,
+ 0xcb87, 0x2212,
+ 0xcb88, 0x478b,
+ 0xcb8e, 0x2207,
+ 0xcb8f, 0x4791,
+ 0xcb92, 0x2359,
+ 0xcb93, 0x4794,
+ 0xcb9c, 0x2254,
+ 0xcb9d, 0x479d,
+ 0xcb9e, 0x2332,
+ 0xcb9f, 0x479e,
+ 0xcba1, 0x0d96,
+ 0xcc40, 0x1e26,
+ 0xcc41, 0x2357,
+ 0xcc42, 0x47a0,
+ 0xcc49, 0x2358,
+ 0xcc4a, 0x2042,
+ 0xcc4b, 0x2153,
+ 0xcc4c, 0x47a7,
+ 0xcc4f, 0x20bb,
+ 0xcc50, 0x47aa,
+ 0xcc5c, 0x235a,
+ 0xcc5d, 0x47b6,
+ 0xcc60, 0x2356,
+ 0xcc61, 0x47b9,
+ 0xcc64, 0x2337,
+ 0xcc65, 0x47bc,
+ 0xcc6d, 0x1ff9,
+ 0xcc6e, 0x47c4,
+ 0xcc79, 0x2353,
+ 0xcc7a, 0x47cf,
+ 0xcc7d, 0x2061,
+ 0xcc7e, 0x47d2,
+ 0xcc80, 0x47d3,
+ 0xcc8e, 0x1e95,
+ 0xcc8f, 0x47e1,
+ 0xcc94, 0x2049,
+ 0xcc95, 0x47e6,
+ 0xcc96, 0x1f42,
+ 0xcc97, 0x47e7,
+ 0xcc9d, 0x1fe8,
+ 0xcc9e, 0x47ed,
+ 0xcca1, 0x0df4,
+ 0xcd40, 0x47f0,
+ 0xcd80, 0x482f,
+ 0xcd90, 0x25da,
+ 0xcd91, 0x483f,
+ 0xcd98, 0x25d7,
+ 0xcd99, 0x4846,
+ 0xcda1, 0x0e52,
+ 0xce40, 0x484e,
+ 0xce67, 0x212e,
+ 0xce68, 0x4875,
+ 0xce72, 0x21b2,
+ 0xce73, 0x487f,
+ 0xce80, 0x488b,
+ 0xce81, 0x219e,
+ 0xce82, 0x488c,
+ 0xce87, 0x25dc,
+ 0xce88, 0x4891,
+ 0xce9b, 0x206c,
+ 0xce9c, 0x48a4,
+ 0xce9e, 0x2226,
+ 0xce9f, 0x48a6,
+ 0xcea1, 0x0eb0,
+ 0xcf40, 0x48a8,
+ 0xcf4e, 0x25e0,
+ 0xcf4f, 0x48b6,
+ 0xcf55, 0x227b,
+ 0xcf56, 0x48bc,
+ 0xcf58, 0x25de,
+ 0xcf59, 0x48be,
+ 0xcf5c, 0x25e1,
+ 0xcf5d, 0x48c1,
+ 0xcf6c, 0x25d5,
+ 0xcf6d, 0x48d0,
+ 0xcf73, 0x1e6b,
+ 0xcf74, 0x48d6,
+ 0xcf75, 0x25db,
+ 0xcf76, 0x48d7,
+ 0xcf78, 0x1e89,
+ 0xcf79, 0x48d9,
+ 0xcf7c, 0x25d9,
+ 0xcf7d, 0x48dc,
+ 0xcf80, 0x48de,
+ 0xcf81, 0x2211,
+ 0xcf82, 0x48df,
+ 0xcf89, 0x2229,
+ 0xcf8a, 0x25d6,
+ 0xcf8b, 0x48e6,
+ 0xcf93, 0x25dd,
+ 0xcf94, 0x25df,
+ 0xcf95, 0x48ee,
+ 0xcf9e, 0x1fef,
+ 0xcf9f, 0x48f7,
+ 0xcfa0, 0x25d8,
+ 0xcfa1, 0x0f0e,
+ 0xd040, 0x48f8,
+ 0xd04d, 0x1f29,
+ 0xd04e, 0x4905,
+ 0xd051, 0x1e5b,
+ 0xd052, 0x4908,
+ 0xd055, 0x2076,
+ 0xd056, 0x490b,
+ 0xd05c, 0x2297,
+ 0xd05d, 0x4911,
+ 0xd060, 0x2690,
+ 0xd061, 0x4914,
+ 0xd067, 0x213f,
+ 0xd068, 0x491a,
+ 0xd06c, 0x2198,
+ 0xd06d, 0x491e,
+ 0xd06e, 0x1e88,
+ 0xd06f, 0x491f,
+ 0xd07d, 0x228c,
+ 0xd07e, 0x492d,
+ 0xd080, 0x492e,
+ 0xd0a1, 0x0f6c,
+ 0xd140, 0x494f,
+ 0xd155, 0x25f1,
+ 0xd156, 0x4964,
+ 0xd159, 0x200c,
+ 0xd15a, 0x4967,
+ 0xd161, 0x1e58,
+ 0xd162, 0x22ac,
+ 0xd163, 0x496e,
+ 0xd175, 0x26a7,
+ 0xd176, 0x4980,
+ 0xd17d, 0x2676,
+ 0xd17e, 0x4987,
+ 0xd180, 0x4988,
+ 0xd19d, 0x1fe1,
+ 0xd19e, 0x25bb,
+ 0xd19f, 0x49a5,
+ 0xd1a1, 0x0fca,
+ 0xd240, 0x25be,
+ 0xd241, 0x49a7,
+ 0xd243, 0x22dd,
+ 0xd244, 0x49a9,
+ 0xd24d, 0x25bd,
+ 0xd24e, 0x49b2,
+ 0xd25c, 0x1e2a,
+ 0xd25d, 0x49c0,
+ 0xd263, 0x25bc,
+ 0xd264, 0x25ba,
+ 0xd265, 0x49c6,
+ 0xd268, 0x25bf,
+ 0xd269, 0x49c9,
+ 0xd26d, 0x2187,
+ 0xd26e, 0x49cd,
+ 0xd26f, 0x266b,
+ 0xd270, 0x49ce,
+ 0xd272, 0x1e7f,
+ 0xd273, 0x49d0,
+ 0xd275, 0x21ad,
+ 0xd276, 0x49d2,
+ 0xd280, 0x49db,
+ 0xd28a, 0x1f96,
+ 0xd28b, 0x49e5,
+ 0xd28e, 0x1f32,
+ 0xd28f, 0x49e8,
+ 0xd292, 0x2084,
+ 0xd293, 0x49eb,
+ 0xd295, 0x2136,
+ 0xd296, 0x49ed,
+ 0xd297, 0x24b8,
+ 0xd298, 0x49ee,
+ 0xd2a0, 0x24ba,
+ 0xd2a1, 0x1028,
+ 0xd340, 0x49f6,
+ 0xd344, 0x24bc,
+ 0xd345, 0x49fa,
+ 0xd348, 0x20e4,
+ 0xd349, 0x49fd,
+ 0xd34a, 0x24b9,
+ 0xd34b, 0x49fe,
+ 0xd34d, 0x24bd,
+ 0xd34e, 0x4a00,
+ 0xd350, 0x24be,
+ 0xd351, 0x4a02,
+ 0xd355, 0x24bf,
+ 0xd356, 0x4a06,
+ 0xd358, 0x1fd2,
+ 0xd359, 0x4a08,
+ 0xd35b, 0x1ffd,
+ 0xd35c, 0x4a0a,
+ 0xd35d, 0x24bb,
+ 0xd35e, 0x1f2d,
+ 0xd35f, 0x4a0b,
+ 0xd378, 0x2609,
+ 0xd379, 0x4a24,
+ 0xd37a, 0x260a,
+ 0xd37b, 0x4a25,
+ 0xd37c, 0x1e94,
+ 0xd37d, 0x4a26,
+ 0xd380, 0x4a28,
+ 0xd385, 0x22df,
+ 0xd386, 0x1ecb,
+ 0xd387, 0x1f0d,
+ 0xd388, 0x4a2d,
+ 0xd38b, 0x1f77,
+ 0xd38c, 0x4a30,
+ 0xd38d, 0x21eb,
+ 0xd38e, 0x4a31,
+ 0xd38f, 0x22e1,
+ 0xd390, 0x4a32,
+ 0xd391, 0x216f,
+ 0xd392, 0x4a33,
+ 0xd393, 0x22e0,
+ 0xd394, 0x4a34,
+ 0xd396, 0x21ea,
+ 0xd397, 0x4a36,
+ 0xd398, 0x22e2,
+ 0xd399, 0x20cb,
+ 0xd39a, 0x4a37,
+ 0xd39b, 0x1f78,
+ 0xd39c, 0x4a38,
+ 0xd39e, 0x1ee2,
+ 0xd39f, 0x4a3a,
+ 0xd3a0, 0x21f2,
+ 0xd3a1, 0x1086,
+ 0xd440, 0x4a3b,
+ 0xd441, 0x2150,
+ 0xd442, 0x4a3c,
+ 0xd445, 0x1fd3,
+ 0xd446, 0x4a3f,
+ 0xd447, 0x22e5,
+ 0xd448, 0x4a40,
+ 0xd44c, 0x1ef2,
+ 0xd44d, 0x4a44,
+ 0xd44f, 0x211f,
+ 0xd450, 0x4a46,
+ 0xd453, 0x21dd,
+ 0xd454, 0x4a49,
+ 0xd456, 0x2154,
+ 0xd457, 0x4a4b,
+ 0xd458, 0x22e7,
+ 0xd459, 0x4a4c,
+ 0xd45c, 0x2282,
+ 0xd45d, 0x4a4f,
+ 0xd462, 0x22e6,
+ 0xd463, 0x4a54,
+ 0xd467, 0x22e8,
+ 0xd468, 0x4a58,
+ 0xd46e, 0x22e4,
+ 0xd46f, 0x4a5e,
+ 0xd470, 0x226a,
+ 0xd471, 0x4a5f,
+ 0xd472, 0x22eb,
+ 0xd473, 0x4a60,
+ 0xd474, 0x22e9,
+ 0xd475, 0x20bd,
+ 0xd476, 0x4a61,
+ 0xd478, 0x22ea,
+ 0xd479, 0x4a63,
+ 0xd47b, 0x22bd,
+ 0xd47c, 0x4a65,
+ 0xd47e, 0x1e9e,
+ 0xd480, 0x4a67,
+ 0xd482, 0x22f6,
+ 0xd483, 0x21e7,
+ 0xd484, 0x2216,
+ 0xd485, 0x4a69,
+ 0xd487, 0x2137,
+ 0xd488, 0x4a6b,
+ 0xd48a, 0x212c,
+ 0xd48b, 0x4a6d,
+ 0xd48c, 0x1e68,
+ 0xd48d, 0x22f2,
+ 0xd48e, 0x1f37,
+ 0xd48f, 0x22f3,
+ 0xd490, 0x4a6e,
+ 0xd491, 0x22ef,
+ 0xd492, 0x1f50,
+ 0xd493, 0x1f10,
+ 0xd494, 0x21c8,
+ 0xd495, 0x4a6f,
+ 0xd496, 0x22f1,
+ 0xd497, 0x4a70,
+ 0xd49c, 0x22f0,
+ 0xd49d, 0x4a75,
+ 0xd49f, 0x22ee,
+ 0xd4a0, 0x4a77,
+ 0xd4a1, 0x10e4,
+ 0xd540, 0x4a78,
+ 0xd543, 0x22ed,
+ 0xd544, 0x229e,
+ 0xd545, 0x22ec,
+ 0xd546, 0x1fe2,
+ 0xd547, 0x4a7b,
+ 0xd54a, 0x20fe,
+ 0xd54b, 0x4a7e,
+ 0xd54e, 0x22f9,
+ 0xd550, 0x4a81,
+ 0xd551, 0x1eaf,
+ 0xd552, 0x4a82,
+ 0xd554, 0x2236,
+ 0xd555, 0x4a84,
+ 0xd556, 0x22f7,
+ 0xd557, 0x4a85,
+ 0xd55a, 0x223d,
+ 0xd55b, 0x4a88,
+ 0xd55c, 0x1e82,
+ 0xd55d, 0x1fb6,
+ 0xd55e, 0x4a89,
+ 0xd55f, 0x21a4,
+ 0xd560, 0x21aa,
+ 0xd561, 0x22f8,
+ 0xd562, 0x2151,
+ 0xd563, 0x4a8a,
+ 0xd564, 0x1f60,
+ 0xd565, 0x4a8b,
+ 0xd568, 0x2147,
+ 0xd569, 0x4a8e,
+ 0xd56c, 0x2145,
+ 0xd56d, 0x4a91,
+ 0xd56e, 0x1fdc,
+ 0xd56f, 0x4a92,
+ 0xd572, 0x2301,
+ 0xd573, 0x4a95,
+ 0xd575, 0x1ef5,
+ 0xd576, 0x4a97,
+ 0xd578, 0x2218,
+ 0xd579, 0x4a99,
+ 0xd57b, 0x1ec6,
+ 0xd57c, 0x4a9b,
+ 0xd57e, 0x2300,
+ 0xd580, 0x4a9d,
+ 0xd581, 0x22b4,
+ 0xd582, 0x4a9e,
+ 0xd584, 0x2169,
+ 0xd585, 0x4aa0,
+ 0xd586, 0x22fd,
+ 0xd587, 0x4aa1,
+ 0xd588, 0x20ea,
+ 0xd589, 0x4aa2,
+ 0xd58a, 0x22f4,
+ 0xd58b, 0x4aa3,
+ 0xd58c, 0x22fb,
+ 0xd58d, 0x4aa4,
+ 0xd58e, 0x22fc,
+ 0xd58f, 0x2027,
+ 0xd590, 0x4aa5,
+ 0xd593, 0x2060,
+ 0xd594, 0x22ff,
+ 0xd595, 0x4aa8,
+ 0xd598, 0x22fe,
+ 0xd599, 0x1ec7,
+ 0xd59a, 0x4aab,
+ 0xd59b, 0x230c,
+ 0xd59c, 0x4aac,
+ 0xd59f, 0x22f5,
+ 0xd5a0, 0x4aaf,
+ 0xd5a1, 0x1142,
+ 0xd640, 0x2306,
+ 0xd641, 0x4ab0,
+ 0xd642, 0x230a,
+ 0xd643, 0x21d3,
+ 0xd644, 0x4ab1,
+ 0xd647, 0x2303,
+ 0xd648, 0x4ab4,
+ 0xd649, 0x2307,
+ 0xd64a, 0x230b,
+ 0xd64b, 0x4ab5,
+ 0xd64d, 0x1f5f,
+ 0xd64e, 0x4ab7,
+ 0xd64f, 0x2309,
+ 0xd650, 0x4ab8,
+ 0xd652, 0x2302,
+ 0xd653, 0x1f04,
+ 0xd654, 0x229d,
+ 0xd655, 0x4aba,
+ 0xd656, 0x21fb,
+ 0xd657, 0x4abb,
+ 0xd658, 0x2308,
+ 0xd659, 0x4abc,
+ 0xd65a, 0x20ac,
+ 0xd65b, 0x4abd,
+ 0xd65c, 0x208e,
+ 0xd65d, 0x2305,
+ 0xd65e, 0x2197,
+ 0xd65f, 0x4abe,
+ 0xd660, 0x2171,
+ 0xd661, 0x2298,
+ 0xd662, 0x4abf,
+ 0xd665, 0x1f57,
+ 0xd666, 0x4ac2,
+ 0xd669, 0x2082,
+ 0xd66a, 0x4ac5,
+ 0xd66b, 0x2311,
+ 0xd66c, 0x4ac6,
+ 0xd66f, 0x2304,
+ 0xd670, 0x4ac9,
+ 0xd671, 0x230f,
+ 0xd672, 0x1e35,
+ 0xd673, 0x4aca,
+ 0xd674, 0x20d1,
+ 0xd675, 0x2310,
+ 0xd676, 0x1fa3,
+ 0xd677, 0x4acb,
+ 0xd678, 0x21d6,
+ 0xd679, 0x4acc,
+ 0xd67c, 0x2206,
+ 0xd67d, 0x4acf,
+ 0xd680, 0x4ad1,
+ 0xd683, 0x230d,
+ 0xd684, 0x4ad4,
+ 0xd686, 0x2312,
+ 0xd687, 0x208d,
+ 0xd688, 0x2313,
+ 0xd689, 0x4ad6,
+ 0xd68e, 0x22e3,
+ 0xd68f, 0x4adb,
+ 0xd694, 0x1fba,
+ 0xd695, 0x4ae0,
+ 0xd699, 0x2078,
+ 0xd69a, 0x4ae4,
+ 0xd6a1, 0x11a0,
+ 0xd740, 0x4aeb,
+ 0xd743, 0x2288,
+ 0xd744, 0x4aee,
+ 0xd748, 0x2316,
+ 0xd749, 0x1f6b,
+ 0xd74a, 0x4af2,
+ 0xd750, 0x2314,
+ 0xd751, 0x4af8,
+ 0xd752, 0x2130,
+ 0xd753, 0x2315,
+ 0xd754, 0x2168,
+ 0xd755, 0x4af9,
+ 0xd756, 0x20c4,
+ 0xd757, 0x4afa,
+ 0xd764, 0x2318,
+ 0xd765, 0x4b07,
+ 0xd767, 0x2219,
+ 0xd768, 0x2217,
+ 0xd769, 0x4b09,
+ 0xd76c, 0x20d5,
+ 0xd76d, 0x4b0c,
+ 0xd76f, 0x1f4a,
+ 0xd770, 0x4b0e,
+ 0xd775, 0x2240,
+ 0xd776, 0x4b13,
+ 0xd778, 0x1ed3,
+ 0xd779, 0x4b15,
+ 0xd780, 0x4b1b,
+ 0xd783, 0x1e49,
+ 0xd784, 0x4b1e,
+ 0xd787, 0x261b,
+ 0xd788, 0x4b21,
+ 0xd78b, 0x1e6d,
+ 0xd78c, 0x20f8,
+ 0xd78d, 0x4b24,
+ 0xd78e, 0x1ffb,
+ 0xd78f, 0x2319,
+ 0xd790, 0x4b25,
+ 0xd795, 0x230e,
+ 0xd796, 0x4b2a,
+ 0xd797, 0x2317,
+ 0xd798, 0x4b2b,
+ 0xd7a1, 0x11fe,
+ 0xd840, 0x4b34,
+ 0xd84d, 0x20c8,
+ 0xd84e, 0x4b41,
+ 0xd853, 0x1efd,
+ 0xd854, 0x4b46,
+ 0xd880, 0x4b71,
+ 0xd890, 0x1e3b,
+ 0xd891, 0x227f,
+ 0xd892, 0x4b81,
+ 0xd893, 0x1f0c,
+ 0xd894, 0x1e59,
+ 0xd895, 0x1f24,
+ 0xd896, 0x4b82,
+ 0xd89a, 0x20ba,
+ 0xd89b, 0x1f65,
+ 0xd89c, 0x1ef0,
+ 0xd89d, 0x2164,
+ 0xd89e, 0x1f30,
+ 0xd89f, 0x2261,
+ 0xd8a0, 0x4b86,
+ 0xd8a1, 0x1257,
+ 0xd940, 0x4b87,
+ 0xd941, 0x22a2,
+ 0xd942, 0x24ab,
+ 0xd943, 0x4b88,
+ 0xd944, 0x24af,
+ 0xd945, 0x1ee8,
+ 0xd946, 0x1f39,
+ 0xd947, 0x4b89,
+ 0xd948, 0x1e48,
+ 0xd949, 0x2070,
+ 0xd94a, 0x1ea8,
+ 0xd94b, 0x4b8a,
+ 0xd94c, 0x24ac,
+ 0xd94d, 0x1ef7,
+ 0xd94e, 0x2176,
+ 0xd94f, 0x24ad,
+ 0xd950, 0x4b8b,
+ 0xd951, 0x207b,
+ 0xd952, 0x1f45,
+ 0xd953, 0x24aa,
+ 0xd954, 0x204b,
+ 0xd955, 0x202f,
+ 0xd956, 0x1f5a,
+ 0xd957, 0x24b0,
+ 0xd958, 0x4b8c,
+ 0xd959, 0x22b7,
+ 0xd95a, 0x1f7f,
+ 0xd95b, 0x4b8d,
+ 0xd95c, 0x2265,
+ 0xd95d, 0x4b8e,
+ 0xd963, 0x24b2,
+ 0xd964, 0x211b,
+ 0xd965, 0x1e51,
+ 0xd966, 0x4b94,
+ 0xd967, 0x24b4,
+ 0xd968, 0x4b95,
+ 0xd96c, 0x24b3,
+ 0xd96d, 0x4b99,
+ 0xd96e, 0x1e9f,
+ 0xd96f, 0x4b9a,
+ 0xd970, 0x2118,
+ 0xd971, 0x4b9b,
+ 0xd972, 0x20b4,
+ 0xd973, 0x23af,
+ 0xd974, 0x21bb,
+ 0xd975, 0x2072,
+ 0xd976, 0x1f95,
+ 0xd977, 0x4b9c,
+ 0xd978, 0x1f0a,
+ 0xd979, 0x24b6,
+ 0xd97a, 0x4b9d,
+ 0xd97c, 0x2291,
+ 0xd97d, 0x24b5,
+ 0xd97e, 0x2278,
+ 0xd980, 0x1ed4,
+ 0xd981, 0x4b9f,
+ 0xd987, 0x1ff3,
+ 0xd988, 0x4ba5,
+ 0xd98d, 0x22a9,
+ 0xd98e, 0x24b7,
+ 0xd98f, 0x1f28,
+ 0xd990, 0x2109,
+ 0xd991, 0x22c7,
+ 0xd992, 0x4baa,
+ 0xd997, 0x24ae,
+ 0xd998, 0x22b1,
+ 0xd999, 0x4baf,
+ 0xd99b, 0x2266,
+ 0xd99c, 0x4bb1,
+ 0xd99d, 0x225b,
+ 0xd99e, 0x22c4,
+ 0xd99f, 0x4bb2,
+ 0xd9a0, 0x2115,
+ 0xd9a1, 0x12b5,
+ 0xda40, 0x4bb3,
+ 0xda41, 0x222a,
+ 0xda42, 0x24b1,
+ 0xda43, 0x4bb4,
+ 0xda48, 0x213d,
+ 0xda49, 0x4bb9,
+ 0xda4d, 0x1f15,
+ 0xda4e, 0x225c,
+ 0xda4f, 0x4bbd,
+ 0xda73, 0x1f14,
+ 0xda74, 0x4be1,
+ 0xda77, 0x227a,
+ 0xda78, 0x4be4,
+ 0xda80, 0x4beb,
+ 0xda85, 0x20ee,
+ 0xda86, 0x4bf0,
+ 0xda8e, 0x25f8,
+ 0xda8f, 0x4bf8,
+ 0xdaa1, 0x1313,
+ 0xdb40, 0x4c0a,
+ 0xdb60, 0x1f94,
+ 0xdb61, 0x4c2a,
+ 0xdb78, 0x2230,
+ 0xdb79, 0x4c41,
+ 0xdb80, 0x4c47,
+ 0xdb84, 0x25fd,
+ 0xdb85, 0x4c4b,
+ 0xdb8b, 0x2600,
+ 0xdb8c, 0x4c51,
+ 0xdb98, 0x2606,
+ 0xdb99, 0x4c5d,
+ 0xdba1, 0x1371,
+ 0xdc40, 0x4c65,
+ 0xdc45, 0x25ff,
+ 0xdc46, 0x4c6a,
+ 0xdc4f, 0x25fc,
+ 0xdc50, 0x1e8c,
+ 0xdc51, 0x2602,
+ 0xdc52, 0x4c73,
+ 0xdc53, 0x224d,
+ 0xdc54, 0x4c74,
+ 0xdc55, 0x2604,
+ 0xdc56, 0x25fe,
+ 0xdc57, 0x2603,
+ 0xdc58, 0x4c75,
+ 0xdc5d, 0x2601,
+ 0xdc5e, 0x4c7a,
+ 0xdc62, 0x2605,
+ 0xdc63, 0x4c7e,
+ 0xdc66, 0x1ea3,
+ 0xdc67, 0x2608,
+ 0xdc68, 0x4c81,
+ 0xdc6b, 0x2607,
+ 0xdc6c, 0x4c84,
+ 0xdc7c, 0x20f0,
+ 0xdc7d, 0x4c94,
+ 0xdc80, 0x4c96,
+ 0xdc87, 0x1e7b,
+ 0xdc88, 0x2267,
+ 0xdc89, 0x1f36,
+ 0xdc8a, 0x1fd6,
+ 0xdc8b, 0x4c9d,
+ 0xdc8e, 0x21e0,
+ 0xdc8f, 0x4ca0,
+ 0xdc90, 0x248c,
+ 0xdc91, 0x4ca1,
+ 0xdc97, 0x248d,
+ 0xdc98, 0x4ca7,
+ 0xdc9b, 0x2102,
+ 0xdc9c, 0x4caa,
+ 0xdca0, 0x2494,
+ 0xdca1, 0x13cf,
+ 0xdd40, 0x4cae,
+ 0xdd46, 0x2493,
+ 0xdd47, 0x4cb4,
+ 0xdd4d, 0x248e,
+ 0xdd4e, 0x4cba,
+ 0xdd53, 0x2299,
+ 0xdd54, 0x2491,
+ 0xdd55, 0x2496,
+ 0xdd56, 0x248f,
+ 0xdd57, 0x2492,
+ 0xdd58, 0x4cbf,
+ 0xdd59, 0x2497,
+ 0xdd5a, 0x4cc0,
+ 0xdd5e, 0x1fb1,
+ 0xdd5f, 0x4cc4,
+ 0xdd60, 0x249a,
+ 0xdd61, 0x4cc5,
+ 0xdd62, 0x2499,
+ 0xdd63, 0x4cc6,
+ 0xdd64, 0x2258,
+ 0xdd65, 0x2498,
+ 0xdd66, 0x4cc7,
+ 0xdd6d, 0x249b,
+ 0xdd6e, 0x4cce,
+ 0xdd6f, 0x1f09,
+ 0xdd70, 0x20e6,
+ 0xdd71, 0x4ccf,
+ 0xdd76, 0x2026,
+ 0xdd77, 0x249f,
+ 0xdd78, 0x1f59,
+ 0xdd79, 0x249d,
+ 0xdd7b, 0x4cd4,
+ 0xdd80, 0x4cd8,
+ 0xdd81, 0x1f3b,
+ 0xdd82, 0x249c,
+ 0xdd83, 0x4cd9,
+ 0xdd85, 0x1e3a,
+ 0xdd86, 0x205b,
+ 0xdd87, 0x4cdb,
+ 0xdd8b, 0x1f70,
+ 0xdd8c, 0x4cdf,
+ 0xdd8f, 0x24a0,
+ 0xdd90, 0x4ce2,
+ 0xdd94, 0x213b,
+ 0xdd95, 0x4ce6,
+ 0xdd97, 0x1f07,
+ 0xdd98, 0x4ce8,
+ 0xdd9a, 0x2270,
+ 0xdd9b, 0x2237,
+ 0xdd9c, 0x4cea,
+ 0xdd9e, 0x24d2,
+ 0xdd9f, 0x4cec,
+ 0xdda0, 0x21b3,
+ 0xdda1, 0x142d,
+ 0xde40, 0x2245,
+ 0xde41, 0x24a1,
+ 0xde42, 0x4ced,
+ 0xde44, 0x22a8,
+ 0xde45, 0x4cef,
+ 0xde48, 0x227c,
+ 0xde49, 0x1fb0,
+ 0xde4a, 0x4cf2,
+ 0xde4f, 0x24a2,
+ 0xde50, 0x4cf7,
+ 0xde5a, 0x1f46,
+ 0xde5b, 0x4d01,
+ 0xde5c, 0x2380,
+ 0xde5d, 0x2495,
+ 0xde5e, 0x4d02,
+ 0xde5f, 0x2490,
+ 0xde60, 0x4d03,
+ 0xde6b, 0x1e30,
+ 0xde6c, 0x4d0e,
+ 0xde6f, 0x1e9d,
+ 0xde70, 0x1e4b,
+ 0xde71, 0x1e4a,
+ 0xde72, 0x20aa,
+ 0xde73, 0x4d11,
+ 0xde80, 0x4d1d,
+ 0xde92, 0x267b,
+ 0xde93, 0x4d2f,
+ 0xde9f, 0x23f2,
+ 0xdea0, 0x4d3b,
+ 0xdea1, 0x148b,
+ 0xdf40, 0x227e,
+ 0xdf41, 0x4d3c,
+ 0xdf42, 0x2019,
+ 0xdf43, 0x4d3d,
+ 0xdf4d, 0x1fbb,
+ 0xdf4e, 0x4d47,
+ 0xdf5c, 0x2253,
+ 0xdf5d, 0x4d55,
+ 0xdf5e, 0x1f3e,
+ 0xdf5f, 0x1ea6,
+ 0xdf60, 0x218e,
+ 0xdf61, 0x4d56,
+ 0xdf64, 0x21ec,
+ 0xdf65, 0x4d59,
+ 0xdf66, 0x1ebe,
+ 0xdf67, 0x4d5a,
+ 0xdf68, 0x224a,
+ 0xdf69, 0x4d5b,
+ 0xdf6d, 0x2133,
+ 0xdf6e, 0x4d5f,
+ 0xdf74, 0x1e84,
+ 0xdf75, 0x4d65,
+ 0xdf77, 0x20cf,
+ 0xdf78, 0x21e2,
+ 0xdf79, 0x4d67,
+ 0xdf7a, 0x220f,
+ 0xdf7b, 0x4d68,
+ 0xdf7c, 0x2029,
+ 0xdf7d, 0x4d69,
+ 0xdf7e, 0x2073,
+ 0xdf80, 0x1f55,
+ 0xdf81, 0x4d6a,
+ 0xdf83, 0x23f1,
+ 0xdf84, 0x4d6c,
+ 0xdf85, 0x1e46,
+ 0xdf86, 0x4d6d,
+ 0xdf89, 0x2063,
+ 0xdf8a, 0x23f3,
+ 0xdf8b, 0x4d70,
+ 0xdfa1, 0x14e9,
+ 0xe040, 0x4d86,
+ 0xe050, 0x231e,
+ 0xe051, 0x4d96,
+ 0xe05d, 0x2233,
+ 0xe05e, 0x4da2,
+ 0xe069, 0x2320,
+ 0xe06a, 0x4dad,
+ 0xe06c, 0x21c7,
+ 0xe06d, 0x4daf,
+ 0xe075, 0x22bc,
+ 0xe076, 0x4db7,
+ 0xe077, 0x231c,
+ 0xe078, 0x4db8,
+ 0xe079, 0x2251,
+ 0xe07a, 0x4db9,
+ 0xe080, 0x4dbe,
+ 0xe087, 0x1ebb,
+ 0xe088, 0x4dc5,
+ 0xe08d, 0x2287,
+ 0xe08e, 0x4dca,
+ 0xe08f, 0x202d,
+ 0xe090, 0x1eab,
+ 0xe091, 0x4dcb,
+ 0xe092, 0x231d,
+ 0xe093, 0x4dcc,
+ 0xe094, 0x231f,
+ 0xe095, 0x4dcd,
+ 0xe097, 0x231b,
+ 0xe098, 0x4dcf,
+ 0xe0a1, 0x1547,
+ 0xe140, 0x4dd8,
+ 0xe142, 0x2321,
+ 0xe143, 0x4dda,
+ 0xe164, 0x2255,
+ 0xe165, 0x4dfb,
+ 0xe168, 0x1e8f,
+ 0xe169, 0x4dfe,
+ 0xe174, 0x220c,
+ 0xe175, 0x1fa4,
+ 0xe176, 0x4e09,
+ 0xe180, 0x4e12,
+ 0xe184, 0x209b,
+ 0xe185, 0x21d8,
+ 0xe186, 0x4e16,
+ 0xe187, 0x25fa,
+ 0xe188, 0x4e17,
+ 0xe189, 0x25f9,
+ 0xe18a, 0x4e18,
+ 0xe18c, 0x2134,
+ 0xe18d, 0x4e1a,
+ 0xe18e, 0x24f3,
+ 0xe191, 0x24f8,
+ 0xe192, 0x4e1b,
+ 0xe193, 0x24f7,
+ 0xe194, 0x1ec8,
+ 0xe195, 0x24f6,
+ 0xe196, 0x4e1c,
+ 0xe198, 0x2280,
+ 0xe199, 0x4e1e,
+ 0xe19e, 0x1ec5,
+ 0xe19f, 0x24fb,
+ 0xe1a0, 0x4e23,
+ 0xe1a1, 0x15a5,
+ 0xe240, 0x4e24,
+ 0xe241, 0x24fa,
+ 0xe242, 0x4e25,
+ 0xe243, 0x1eed,
+ 0xe244, 0x4e26,
+ 0xe24f, 0x24fd,
+ 0xe250, 0x4e31,
+ 0xe251, 0x24f9,
+ 0xe252, 0x4e32,
+ 0xe253, 0x24fe,
+ 0xe254, 0x20cd,
+ 0xe255, 0x4e33,
+ 0xe25a, 0x2508,
+ 0xe25b, 0x2504,
+ 0xe25c, 0x4e38,
+ 0xe25e, 0x2506,
+ 0xe25f, 0x4e3a,
+ 0xe262, 0x24ff,
+ 0xe263, 0x2090,
+ 0xe264, 0x4e3d,
+ 0xe267, 0x1edd,
+ 0xe268, 0x1f25,
+ 0xe269, 0x4e40,
+ 0xe26a, 0x2503,
+ 0xe26b, 0x2502,
+ 0xe26c, 0x4e41,
+ 0xe26e, 0x1e7a,
+ 0xe26f, 0x20a6,
+ 0xe270, 0x4e43,
+ 0xe278, 0x1fd5,
+ 0xe279, 0x4e4b,
+ 0xe27d, 0x1f11,
+ 0xe27e, 0x4e4f,
+ 0xe280, 0x2507,
+ 0xe281, 0x2500,
+ 0xe282, 0x2505,
+ 0xe283, 0x4e50,
+ 0xe289, 0x2519,
+ 0xe28a, 0x4e56,
+ 0xe28b, 0x2515,
+ 0xe28c, 0x4e57,
+ 0xe28e, 0x250c,
+ 0xe28f, 0x2031,
+ 0xe290, 0x4e59,
+ 0xe292, 0x250b,
+ 0xe293, 0x250f,
+ 0xe294, 0x251a,
+ 0xe295, 0x2509,
+ 0xe296, 0x4e5b,
+ 0xe298, 0x250e,
+ 0xe299, 0x2234,
+ 0xe29a, 0x2513,
+ 0xe29b, 0x1f80,
+ 0xe29c, 0x4e5d,
+ 0xe2a0, 0x2501,
+ 0xe2a1, 0x1603,
+ 0xe340, 0x4e61,
+ 0xe342, 0x2517,
+ 0xe343, 0x2516,
+ 0xe344, 0x4e63,
+ 0xe347, 0x2518,
+ 0xe348, 0x4e66,
+ 0xe34b, 0x1e56,
+ 0xe34c, 0x4e69,
+ 0xe34f, 0x250d,
+ 0xe350, 0x4e6c,
+ 0xe351, 0x20d3,
+ 0xe352, 0x4e6d,
+ 0xe354, 0x207a,
+ 0xe355, 0x20ce,
+ 0xe356, 0x4e6f,
+ 0xe358, 0x2510,
+ 0xe359, 0x4e71,
+ 0xe35c, 0x1e55,
+ 0xe35d, 0x4e74,
+ 0xe360, 0x250a,
+ 0xe361, 0x4e77,
+ 0xe366, 0x2511,
+ 0xe368, 0x4e7c,
+ 0xe371, 0x1faa,
+ 0xe372, 0x4e85,
+ 0xe373, 0x251e,
+ 0xe374, 0x1f1f,
+ 0xe375, 0x4e86,
+ 0xe378, 0x252d,
+ 0xe379, 0x221d,
+ 0xe37a, 0x4e89,
+ 0xe37c, 0x2532,
+ 0xe37d, 0x4e8b,
+ 0xe37e, 0x217b,
+ 0xe380, 0x4e8c,
+ 0xe38a, 0x21af,
+ 0xe38b, 0x4e96,
+ 0xe38c, 0x252c,
+ 0xe38d, 0x4e97,
+ 0xe38f, 0x2528,
+ 0xe390, 0x4e99,
+ 0xe391, 0x208c,
+ 0xe392, 0x4e9a,
+ 0xe393, 0x252f,
+ 0xe394, 0x4e9b,
+ 0xe395, 0x21bc,
+ 0xe396, 0x4e9c,
+ 0xe399, 0x251d,
+ 0xe39a, 0x4e9f,
+ 0xe39c, 0x2535,
+ 0xe39d, 0x4ea1,
+ 0xe39e, 0x220d,
+ 0xe39f, 0x2526,
+ 0xe3a0, 0x4ea2,
+ 0xe3a1, 0x1661,
+ 0xe440, 0x2534,
+ 0xe441, 0x252a,
+ 0xe442, 0x251f,
+ 0xe443, 0x2531,
+ 0xe444, 0x251c,
+ 0xe445, 0x4ea3,
+ 0xe448, 0x2525,
+ 0xe449, 0x4ea6,
+ 0xe44e, 0x21cd,
+ 0xe44f, 0x4eab,
+ 0xe450, 0x21da,
+ 0xe451, 0x4eac,
+ 0xe452, 0x2172,
+ 0xe453, 0x253e,
+ 0xe454, 0x4ead,
+ 0xe458, 0x204f,
+ 0xe459, 0x4eb1,
+ 0xe45a, 0x2543,
+ 0xe45b, 0x4eb2,
+ 0xe45c, 0x21d7,
+ 0xe45d, 0x4eb3,
+ 0xe45e, 0x1e3c,
+ 0xe45f, 0x4eb4,
+ 0xe462, 0x2529,
+ 0xe463, 0x4eb7,
+ 0xe465, 0x2521,
+ 0xe466, 0x4eb9,
+ 0xe468, 0x1eff,
+ 0xe469, 0x4ebb,
+ 0xe473, 0x253f,
+ 0xe474, 0x4ec5,
+ 0xe475, 0x2544,
+ 0xe476, 0x4ec6,
+ 0xe479, 0x2523,
+ 0xe47a, 0x1e90,
+ 0xe47b, 0x253a,
+ 0xe47c, 0x2545,
+ 0xe47d, 0x4ec9,
+ 0xe47e, 0x253d,
+ 0xe480, 0x4eca,
+ 0xe481, 0x20c1,
+ 0xe482, 0x4ecb,
+ 0xe484, 0x2103,
+ 0xe485, 0x2520,
+ 0xe486, 0x253c,
+ 0xe487, 0x253b,
+ 0xe488, 0x2538,
+ 0xe489, 0x4ecd,
+ 0xe48d, 0x2540,
+ 0xe48e, 0x4ed1,
+ 0xe48f, 0x1fcd,
+ 0xe490, 0x4ed2,
+ 0xe493, 0x1f18,
+ 0xe494, 0x4ed5,
+ 0xe498, 0x254b,
+ 0xe499, 0x4ed9,
+ 0xe49d, 0x2547,
+ 0xe49e, 0x254f,
+ 0xe4a0, 0x4edd,
+ 0xe4a1, 0x16bf,
+ 0xe540, 0x4ede,
+ 0xe546, 0x22b0,
+ 0xe547, 0x4ee4,
+ 0xe548, 0x2546,
+ 0xe549, 0x4ee5,
+ 0xe54b, 0x254c,
+ 0xe54c, 0x4ee7,
+ 0xe54e, 0x1e9a,
+ 0xe54f, 0x2552,
+ 0xe550, 0x2530,
+ 0xe551, 0x2549,
+ 0xe552, 0x4ee9,
+ 0xe555, 0x2551,
+ 0xe556, 0x1eca,
+ 0xe557, 0x4eec,
+ 0xe558, 0x20d2,
+ 0xe559, 0x4eed,
+ 0xe55c, 0x1fb8,
+ 0xe55d, 0x4ef0,
+ 0xe55e, 0x2079,
+ 0xe55f, 0x4ef1,
+ 0xe561, 0x21ab,
+ 0xe562, 0x4ef3,
+ 0xe564, 0x254d,
+ 0xe565, 0x1ea5,
+ 0xe566, 0x4ef5,
+ 0xe568, 0x204c,
+ 0xe569, 0x2080,
+ 0xe56a, 0x4ef7,
+ 0xe56c, 0x266d,
+ 0xe56d, 0x4ef9,
+ 0xe56e, 0x2537,
+ 0xe56f, 0x4efa,
+ 0xe575, 0x254a,
+ 0xe576, 0x21b8,
+ 0xe577, 0x4f00,
+ 0xe578, 0x254e,
+ 0xe579, 0x4f01,
+ 0xe57b, 0x24fc,
+ 0xe57c, 0x2554,
+ 0xe57d, 0x4f03,
+ 0xe580, 0x4f05,
+ 0xe581, 0x1f3c,
+ 0xe582, 0x4f06,
+ 0xe583, 0x1ed5,
+ 0xe584, 0x4f07,
+ 0xe58a, 0x2556,
+ 0xe58b, 0x4f0d,
+ 0xe58e, 0x2268,
+ 0xe58f, 0x4f10,
+ 0xe591, 0x1ed6,
+ 0xe592, 0x4f12,
+ 0xe59a, 0x2557,
+ 0xe59b, 0x2553,
+ 0xe59c, 0x4f1a,
+ 0xe59f, 0x2548,
+ 0xe5a0, 0x4f1d,
+ 0xe5a1, 0x171d,
+ 0xe640, 0x20dc,
+ 0xe641, 0x4f1e,
+ 0xe644, 0x2559,
+ 0xe645, 0x4f21,
+ 0xe649, 0x1f97,
+ 0xe64a, 0x2555,
+ 0xe64b, 0x4f25,
+ 0xe64e, 0x227d,
+ 0xe64f, 0x4f28,
+ 0xe652, 0x257e,
+ 0xe653, 0x4f2b,
+ 0xe656, 0x207c,
+ 0xe657, 0x4f2e,
+ 0xe658, 0x255a,
+ 0xe659, 0x4f2f,
+ 0xe65b, 0x255e,
+ 0xe65c, 0x4f31,
+ 0xe65e, 0x1e34,
+ 0xe65f, 0x4f33,
+ 0xe669, 0x215e,
+ 0xe66a, 0x4f3d,
+ 0xe66b, 0x2560,
+ 0xe66c, 0x4f3e,
+ 0xe675, 0x21a2,
+ 0xe676, 0x2354,
+ 0xe677, 0x4f47,
+ 0xe679, 0x2563,
+ 0xe67a, 0x2527,
+ 0xe67b, 0x4f49,
+ 0xe67c, 0x252e,
+ 0xe67d, 0x2558,
+ 0xe67e, 0x4f4a,
+ 0xe680, 0x1f1b,
+ 0xe681, 0x4f4b,
+ 0xe682, 0x2283,
+ 0xe683, 0x4f4c,
+ 0xe684, 0x2564,
+ 0xe685, 0x4f4d,
+ 0xe687, 0x20a0,
+ 0xe688, 0x4f4f,
+ 0xe689, 0x2565,
+ 0xe68a, 0x4f50,
+ 0xe68c, 0x2561,
+ 0xe68d, 0x4f52,
+ 0xe693, 0x2562,
+ 0xe694, 0x4f58,
+ 0xe697, 0x256c,
+ 0xe698, 0x4f5b,
+ 0xe69b, 0x256d,
+ 0xe69c, 0x2020,
+ 0xe69d, 0x4f5e,
+ 0xe69f, 0x255f,
+ 0xe6a0, 0x256a,
+ 0xe6a1, 0x177b,
+ 0xe740, 0x4f60,
+ 0xe743, 0x256e,
+ 0xe744, 0x4f63,
+ 0xe748, 0x2539,
+ 0xe749, 0x255c,
+ 0xe74a, 0x4f67,
+ 0xe74d, 0x2568,
+ 0xe74f, 0x256b,
+ 0xe750, 0x1e6f,
+ 0xe751, 0x4f6a,
+ 0xe752, 0x1fc4,
+ 0xe753, 0x2567,
+ 0xe754, 0x4f6b,
+ 0xe755, 0x255b,
+ 0xe756, 0x4f6c,
+ 0xe759, 0x261d,
+ 0xe75a, 0x4f6f,
+ 0xe766, 0x252b,
+ 0xe767, 0x4f7b,
+ 0xe768, 0x2571,
+ 0xe769, 0x4f7c,
+ 0xe76a, 0x2577,
+ 0xe76b, 0x4f7d,
+ 0xe774, 0x2522,
+ 0xe775, 0x4f86,
+ 0xe77c, 0x2533,
+ 0xe77d, 0x4f8d,
+ 0xe780, 0x4f8f,
+ 0xe782, 0x202a,
+ 0xe783, 0x4f91,
+ 0xe784, 0x2536,
+ 0xe785, 0x2573,
+ 0xe786, 0x256f,
+ 0xe787, 0x4f92,
+ 0xe78a, 0x2293,
+ 0xe78b, 0x2578,
+ 0xe78c, 0x4f95,
+ 0xe78f, 0x2570,
+ 0xe790, 0x4f98,
+ 0xe792, 0x2575,
+ 0xe793, 0x4f9a,
+ 0xe798, 0x2541,
+ 0xe79a, 0x255d,
+ 0xe79b, 0x4f9f,
+ 0xe7a0, 0x201a,
+ 0xe7a1, 0x17d9,
+ 0xe840, 0x4fa4,
+ 0xe843, 0x257a,
+ 0xe844, 0x2006,
+ 0xe845, 0x4fa7,
+ 0xe846, 0x2177,
+ 0xe847, 0x4fa8,
+ 0xe849, 0x251b,
+ 0xe84a, 0x4faa,
+ 0xe84b, 0x2524,
+ 0xe84c, 0x4fab,
+ 0xe84f, 0x257b,
+ 0xe850, 0x4fae,
+ 0xe854, 0x22a3,
+ 0xe855, 0x4fb2,
+ 0xe85a, 0x2579,
+ 0xe85b, 0x4fb7,
+ 0xe85c, 0x2566,
+ 0xe85d, 0x4fb8,
+ 0xe862, 0x1f93,
+ 0xe863, 0x4fbd,
+ 0xe864, 0x257c,
+ 0xe865, 0x4fbe,
+ 0xe870, 0x2514,
+ 0xe871, 0x4fc9,
+ 0xe873, 0x257d,
+ 0xe874, 0x4fcb,
+ 0xe875, 0x2572,
+ 0xe876, 0x4fcc,
+ 0xe87c, 0x2574,
+ 0xe87d, 0x4fd2,
+ 0xe880, 0x224e,
+ 0xe881, 0x4fd4,
+ 0xe882, 0x21c6,
+ 0xe883, 0x4fd5,
+ 0xe887, 0x209f,
+ 0xe888, 0x4fd9,
+ 0xe889, 0x2576,
+ 0xe88a, 0x4fda,
+ 0xe88c, 0x2064,
+ 0xe88d, 0x22bf,
+ 0xe88e, 0x261c,
+ 0xe88f, 0x225e,
+ 0xe890, 0x4fdc,
+ 0xe8a1, 0x1837,
+ 0xe940, 0x4fed,
+ 0xe94c, 0x1e75,
+ 0xe94d, 0x4ff9,
+ 0xe954, 0x207d,
+ 0xe955, 0x5000,
+ 0xe956, 0x23bf,
+ 0xe957, 0x2113,
+ 0xe958, 0x5001,
+ 0xe95a, 0x23c0,
+ 0xe95b, 0x5003,
+ 0xe95d, 0x1e45,
+ 0xe95e, 0x5005,
+ 0xe95f, 0x1fd8,
+ 0xe960, 0x23c4,
+ 0xe961, 0x5006,
+ 0xe962, 0x23c2,
+ 0xe963, 0x2104,
+ 0xe964, 0x5007,
+ 0xe965, 0x21bd,
+ 0xe966, 0x5008,
+ 0xe967, 0x1f87,
+ 0xe968, 0x23c3,
+ 0xe969, 0x5009,
+ 0xe96c, 0x2269,
+ 0xe96d, 0x500c,
+ 0xe975, 0x1f43,
+ 0xe976, 0x5014,
+ 0xe977, 0x1f1e,
+ 0xe978, 0x2679,
+ 0xe979, 0x1eeb,
+ 0xe97a, 0x5015,
+ 0xe97c, 0x1f35,
+ 0xe97d, 0x208a,
+ 0xe97e, 0x5017,
+ 0xe980, 0x23c7,
+ 0xe981, 0x23c9,
+ 0xe982, 0x23c6,
+ 0xe983, 0x5018,
+ 0xe987, 0x224f,
+ 0xe988, 0x501c,
+ 0xe98b, 0x23cb,
+ 0xe98c, 0x501f,
+ 0xe98e, 0x21f3,
+ 0xe98f, 0x5021,
+ 0xe990, 0x21f7,
+ 0xe991, 0x23cf,
+ 0xe992, 0x23ce,
+ 0xe993, 0x23ca,
+ 0xe994, 0x23cd,
+ 0xe995, 0x5022,
+ 0xe998, 0x23d0,
+ 0xe999, 0x5025,
+ 0xe99b, 0x266c,
+ 0xe99c, 0x5027,
+ 0xe99d, 0x23c1,
+ 0xe99e, 0x5028,
+ 0xe99f, 0x1fee,
+ 0xe9a0, 0x23d1,
+ 0xe9a1, 0x1895,
+ 0xea40, 0x1ff8,
+ 0xea41, 0x5029,
+ 0xea44, 0x23d3,
+ 0xea45, 0x502c,
+ 0xea48, 0x23d2,
+ 0xea49, 0x23d4,
+ 0xea4a, 0x1e98,
+ 0xea4b, 0x502f,
+ 0xea50, 0x1f2c,
+ 0xea51, 0x5034,
+ 0xea52, 0x23d5,
+ 0xea53, 0x5035,
+ 0xea55, 0x1e71,
+ 0xea56, 0x2691,
+ 0xea57, 0x5037,
+ 0xea59, 0x23c5,
+ 0xea5a, 0x5039,
+ 0xea80, 0x231a,
+ 0xea81, 0x505e,
+ 0xea84, 0x2114,
+ 0xea85, 0x5061,
+ 0xea87, 0x2284,
+ 0xea88, 0x5063,
+ 0xea8e, 0x221c,
+ 0xea8f, 0x5069,
+ 0xea90, 0x1e7e,
+ 0xea91, 0x204d,
+ 0xea92, 0x506a,
+ 0xea96, 0x2201,
+ 0xea97, 0x506e,
+ 0xeaa0, 0x1ed9,
+ 0xeaa1, 0x18f3,
+ 0xeb40, 0x5077,
+ 0xeb41, 0x1fb2,
+ 0xeb42, 0x5078,
+ 0xeb45, 0x2252,
+ 0xeb46, 0x507b,
+ 0xeb48, 0x1f79,
+ 0xeb49, 0x507d,
+ 0xeb53, 0x2157,
+ 0xeb54, 0x5087,
+ 0xeb55, 0x21bf,
+ 0xeb56, 0x5088,
+ 0xeb5b, 0x221f,
+ 0xeb5c, 0x508d,
+ 0xeb5d, 0x203d,
+ 0xeb5e, 0x508e,
+ 0xeb60, 0x2015,
+ 0xeb61, 0x5090,
+ 0xeb62, 0x26a5,
+ 0xeb63, 0x5091,
+ 0xeb6d, 0x2156,
+ 0xeb6e, 0x509b,
+ 0xeb70, 0x2144,
+ 0xeb71, 0x509d,
+ 0xeb72, 0x1e91,
+ 0xeb73, 0x2257,
+ 0xeb74, 0x509e,
+ 0xeb78, 0x200a,
+ 0xeb79, 0x2092,
+ 0xeb7a, 0x50a2,
+ 0xeb80, 0x50a7,
+ 0xeb85, 0x2250,
+ 0xeb86, 0x50ac,
+ 0xeb8a, 0x1ec3,
+ 0xeb8b, 0x50b0,
+ 0xeba1, 0x1951,
+ 0xec40, 0x50c6,
+ 0xec46, 0x21a8,
+ 0xec47, 0x50cc,
+ 0xec56, 0x260d,
+ 0xec57, 0x50db,
+ 0xec5a, 0x260c,
+ 0xec5b, 0x50de,
+ 0xec5c, 0x260e,
+ 0xec5d, 0x50df,
+ 0xec60, 0x2032,
+ 0xec61, 0x50e2,
+ 0xec6e, 0x260b,
+ 0xec6f, 0x50ef,
+ 0xec76, 0x22c3,
+ 0xec77, 0x50f6,
+ 0xec80, 0x50fe,
+ 0xec96, 0x1f23,
+ 0xec97, 0x5114,
+ 0xeca1, 0x19af,
+ 0xed40, 0x511e,
+ 0xed46, 0x2695,
+ 0xed47, 0x5124,
+ 0xed58, 0x265e,
+ 0xed59, 0x5135,
+ 0xed5e, 0x265d,
+ 0xed5f, 0x513a,
+ 0xed61, 0x2692,
+ 0xed62, 0x513c,
+ 0xed64, 0x265f,
+ 0xed65, 0x513e,
+ 0xed66, 0x218d,
+ 0xed67, 0x20fd,
+ 0xed68, 0x513f,
+ 0xed6e, 0x1f40,
+ 0xed6f, 0x5145,
+ 0xed74, 0x2465,
+ 0xed75, 0x514a,
+ 0xed77, 0x2467,
+ 0xed78, 0x514c,
+ 0xed79, 0x2466,
+ 0xed7a, 0x514d,
+ 0xed80, 0x5152,
+ 0xed91, 0x21c9,
+ 0xed92, 0x5163,
+ 0xed93, 0x2209,
+ 0xed94, 0x1ec9,
+ 0xed95, 0x20e9,
+ 0xed96, 0x5164,
+ 0xed97, 0x21ca,
+ 0xed98, 0x2146,
+ 0xed99, 0x25c5,
+ 0xed9a, 0x21dc,
+ 0xed9b, 0x5165,
+ 0xed9c, 0x245e,
+ 0xed9d, 0x5166,
+ 0xed9e, 0x214f,
+ 0xed9f, 0x5167,
+ 0xeda0, 0x25c6,
+ 0xeda1, 0x1a0d,
+ 0xee40, 0x25c7,
+ 0xee41, 0x2241,
+ 0xee42, 0x218a,
+ 0xee43, 0x1e2f,
+ 0xee44, 0x1edc,
+ 0xee45, 0x5168,
+ 0xee48, 0x20bf,
+ 0xee49, 0x2034,
+ 0xee4a, 0x516b,
+ 0xee4d, 0x25c9,
+ 0xee4e, 0x516e,
+ 0xee52, 0x25c8,
+ 0xee53, 0x5172,
+ 0xee55, 0x220e,
+ 0xee56, 0x5174,
+ 0xee57, 0x25cb,
+ 0xee58, 0x5175,
+ 0xee5e, 0x217d,
+ 0xee5f, 0x517b,
+ 0xee61, 0x1f7e,
+ 0xee62, 0x517d,
+ 0xee68, 0x25cc,
+ 0xee69, 0x1fc3,
+ 0xee6a, 0x5183,
+ 0xee6c, 0x20b9,
+ 0xee6d, 0x5185,
+ 0xee6e, 0x2181,
+ 0xee6f, 0x5186,
+ 0xee77, 0x1fda,
+ 0xee78, 0x518e,
+ 0xee7d, 0x2173,
+ 0xee7e, 0x1ee1,
+ 0xee80, 0x25cd,
+ 0xee81, 0x5193,
+ 0xee85, 0x25ce,
+ 0xee86, 0x21f6,
+ 0xee87, 0x5197,
+ 0xee8a, 0x224b,
+ 0xee8b, 0x25d1,
+ 0xee8c, 0x519a,
+ 0xee8d, 0x1ec0,
+ 0xee8e, 0x519b,
+ 0xee90, 0x2008,
+ 0xee91, 0x519d,
+ 0xee94, 0x25d0,
+ 0xee95, 0x51a0,
+ 0xee97, 0x25d2,
+ 0xee98, 0x51a2,
+ 0xee99, 0x1f2a,
+ 0xee9a, 0x51a3,
+ 0xee9d, 0x1e72,
+ 0xee9e, 0x25d3,
+ 0xee9f, 0x51a6,
+ 0xeea1, 0x1a6b,
+ 0xef40, 0x21be,
+ 0xef41, 0x25d4,
+ 0xef42, 0x2044,
+ 0xef43, 0x51a8,
+ 0xef44, 0x25cf,
+ 0xef45, 0x20f3,
+ 0xef46, 0x51a9,
+ 0xef4c, 0x1f00,
+ 0xef4d, 0x51af,
+ 0xef52, 0x24cc,
+ 0xef54, 0x51b4,
+ 0xef55, 0x2698,
+ 0xef56, 0x51b5,
+ 0xef57, 0x2678,
+ 0xef58, 0x51b6,
+ 0xef5a, 0x24ce,
+ 0xef5b, 0x51b8,
+ 0xef60, 0x24cf,
+ 0xef61, 0x51bd,
+ 0xef68, 0x20b8,
+ 0xef69, 0x51c4,
+ 0xef6a, 0x24d0,
+ 0xef6b, 0x51c5,
+ 0xef6c, 0x24d1,
+ 0xef6d, 0x51c6,
+ 0xef77, 0x1ef4,
+ 0xef78, 0x51d0,
+ 0xef7a, 0x239b,
+ 0xef7b, 0x51d2,
+ 0xef7c, 0x267e,
+ 0xef7d, 0x51d3,
+ 0xef80, 0x51d5,
+ 0xef82, 0x239d,
+ 0xef83, 0x239f,
+ 0xef85, 0x51d7,
+ 0xef86, 0x23a1,
+ 0xef87, 0x51d8,
+ 0xef88, 0x1ef1,
+ 0xef89, 0x51d9,
+ 0xef8b, 0x221e,
+ 0xef8c, 0x51db,
+ 0xef8d, 0x23a2,
+ 0xef8e, 0x51dc,
+ 0xef95, 0x214b,
+ 0xef96, 0x1e36,
+ 0xef97, 0x2135,
+ 0xef98, 0x51e3,
+ 0xef9c, 0x1fad,
+ 0xef9d, 0x51e7,
+ 0xef9e, 0x1e53,
+ 0xef9f, 0x51e8,
+ 0xefa1, 0x1ac9,
+ 0xf040, 0x51ea,
+ 0xf041, 0x23a3,
+ 0xf042, 0x2203,
+ 0xf043, 0x51eb,
+ 0xf044, 0x1ee7,
+ 0xf045, 0x51ec,
+ 0xf047, 0x23a4,
+ 0xf048, 0x2097,
+ 0xf049, 0x1ee4,
+ 0xf04a, 0x51ee,
+ 0xf04e, 0x2238,
+ 0xf04f, 0x51f2,
+ 0xf051, 0x23a5,
+ 0xf052, 0x51f4,
+ 0xf054, 0x1f9a,
+ 0xf055, 0x51f6,
+ 0xf057, 0x21c3,
+ 0xf058, 0x51f8,
+ 0xf05e, 0x1f2e,
+ 0xf05f, 0x51fe,
+ 0xf068, 0x239c,
+ 0xf069, 0x5207,
+ 0xf06c, 0x23a6,
+ 0xf06d, 0x520a,
+ 0xf071, 0x239e,
+ 0xf072, 0x520e,
+ 0xf073, 0x2035,
+ 0xf074, 0x23a7,
+ 0xf075, 0x520f,
+ 0xf078, 0x23a8,
+ 0xf079, 0x5212,
+ 0xf07a, 0x2075,
+ 0xf07b, 0x5213,
+ 0xf07d, 0x23a9,
+ 0xf080, 0x23ab,
+ 0xf081, 0x1feb,
+ 0xf082, 0x23ac,
+ 0xf083, 0x5215,
+ 0xf087, 0x1f6a,
+ 0xf088, 0x20f9,
+ 0xf089, 0x5219,
+ 0xf08b, 0x2666,
+ 0xf08c, 0x521b,
+ 0xf090, 0x2667,
+ 0xf091, 0x521f,
+ 0xf092, 0x1e6c,
+ 0xf093, 0x5220,
+ 0xf096, 0x23ad,
+ 0xf097, 0x5223,
+ 0xf0a1, 0x1b27,
+ 0xf140, 0x522d,
+ 0xf152, 0x206d,
+ 0xf153, 0x2242,
+ 0xf154, 0x1f02,
+ 0xf155, 0x523f,
+ 0xf157, 0x2183,
+ 0xf158, 0x5241,
+ 0xf159, 0x1e85,
+ 0xf15a, 0x21e9,
+ 0xf15b, 0x5242,
+ 0xf167, 0x1e57,
+ 0xf168, 0x524e,
+ 0xf176, 0x22a5,
+ 0xf177, 0x2407,
+ 0xf178, 0x1fca,
+ 0xf179, 0x525c,
+ 0xf17a, 0x2402,
+ 0xf17b, 0x1f82,
+ 0xf17c, 0x525d,
+ 0xf17e, 0x2408,
+ 0xf180, 0x2404,
+ 0xf181, 0x525f,
+ 0xf182, 0x2131,
+ 0xf183, 0x5260,
+ 0xf184, 0x2184,
+ 0xf185, 0x5261,
+ 0xf186, 0x2403,
+ 0xf187, 0x5262,
+ 0xf188, 0x206e,
+ 0xf189, 0x240b,
+ 0xf18a, 0x5263,
+ 0xf194, 0x1f3f,
+ 0xf195, 0x526d,
+ 0xf198, 0x2067,
+ 0xf199, 0x5270,
+ 0xf1a1, 0x1b85,
+ 0xf240, 0x5278,
+ 0xf245, 0x1fd7,
+ 0xf246, 0x527d,
+ 0xf247, 0x1e83,
+ 0xf248, 0x527e,
+ 0xf24b, 0x240f,
+ 0xf24c, 0x5281,
+ 0xf253, 0x240e,
+ 0xf254, 0x20c7,
+ 0xf255, 0x240d,
+ 0xf256, 0x5288,
+ 0xf25c, 0x2412,
+ 0xf25d, 0x528e,
+ 0xf25f, 0x20b7,
+ 0xf260, 0x5290,
+ 0xf271, 0x23f0,
+ 0xf272, 0x52a1,
+ 0xf273, 0x2411,
+ 0xf274, 0x2414,
+ 0xf275, 0x52a2,
+ 0xf276, 0x2170,
+ 0xf277, 0x52a3,
+ 0xf27c, 0x2405,
+ 0xf27d, 0x210c,
+ 0xf27e, 0x2415,
+ 0xf280, 0x52a8,
+ 0xf285, 0x2066,
+ 0xf286, 0x52ad,
+ 0xf287, 0x2352,
+ 0xf288, 0x2413,
+ 0xf289, 0x2410,
+ 0xf28a, 0x2416,
+ 0xf28c, 0x20f1,
+ 0xf28d, 0x52ae,
+ 0xf291, 0x240a,
+ 0xf292, 0x52b2,
+ 0xf294, 0x2409,
+ 0xf295, 0x52b4,
+ 0xf296, 0x2418,
+ 0xf297, 0x52b5,
+ 0xf29c, 0x1fa7,
+ 0xf29d, 0x52ba,
+ 0xf29e, 0x21fc,
+ 0xf29f, 0x52bb,
+ 0xf2a1, 0x1be3,
+ 0xf340, 0x1fc1,
+ 0xf341, 0x2406,
+ 0xf342, 0x52bd,
+ 0xf345, 0x229c,
+ 0xf346, 0x52c0,
+ 0xf348, 0x204e,
+ 0xf349, 0x52c2,
+ 0xf34a, 0x241a,
+ 0xf34b, 0x2419,
+ 0xf34c, 0x52c3,
+ 0xf350, 0x240c,
+ 0xf351, 0x52c7,
+ 0xf361, 0x1e29,
+ 0xf362, 0x52d7,
+ 0xf374, 0x2661,
+ 0xf375, 0x52e9,
+ 0xf376, 0x26a4,
+ 0xf377, 0x2174,
+ 0xf378, 0x2663,
+ 0xf379, 0x2662,
+ 0xf37a, 0x52ea,
+ 0xf380, 0x52ef,
+ 0xf38c, 0x2675,
+ 0xf38d, 0x52fb,
+ 0xf3a0, 0x214c,
+ 0xf3a1, 0x1c41,
+ 0xf440, 0x530e,
+ 0xf445, 0x267a,
+ 0xf446, 0x5313,
+ 0xf450, 0x26a0,
+ 0xf451, 0x531d,
+ 0xf457, 0x2668,
+ 0xf458, 0x5323,
+ 0xf459, 0x1ed0,
+ 0xf45a, 0x5324,
+ 0xf45b, 0x2096,
+ 0xf45c, 0x5325,
+ 0xf45d, 0x23cc,
+ 0xf45e, 0x5326,
+ 0xf462, 0x23c8,
+ 0xf463, 0x532a,
+ 0xf464, 0x223e,
+ 0xf465, 0x532b,
+ 0xf475, 0x2665,
+ 0xf476, 0x533b,
+ 0xf47c, 0x2664,
+ 0xf47d, 0x5341,
+ 0xf47e, 0x2239,
+ 0xf480, 0x5342,
+ 0xf494, 0x204a,
+ 0xf495, 0x5356,
+ 0xf499, 0x261f,
+ 0xf49a, 0x535a,
+ 0xf49c, 0x261e,
+ 0xf49d, 0x535c,
+ 0xf4a1, 0x1c9f,
+ 0xf540, 0x5360,
+ 0xf545, 0x2620,
+ 0xf546, 0x5365,
+ 0xf547, 0x2621,
+ 0xf548, 0x5366,
+ 0xf552, 0x2622,
+ 0xf553, 0x5370,
+ 0xf554, 0x2627,
+ 0xf555, 0x1e39,
+ 0xf556, 0x2625,
+ 0xf557, 0x5371,
+ 0xf55e, 0x2629,
+ 0xf55f, 0x5378,
+ 0xf561, 0x262e,
+ 0xf562, 0x262b,
+ 0xf563, 0x537a,
+ 0xf56e, 0x262a,
+ 0xf56f, 0x262d,
+ 0xf570, 0x5385,
+ 0xf571, 0x2628,
+ 0xf572, 0x21b9,
+ 0xf573, 0x5386,
+ 0xf580, 0x5392,
+ 0xf585, 0x2636,
+ 0xf586, 0x2630,
+ 0xf587, 0x5397,
+ 0xf58c, 0x2638,
+ 0xf58d, 0x539c,
+ 0xf58e, 0x200d,
+ 0xf58f, 0x2637,
+ 0xf590, 0x539d,
+ 0xf599, 0x2645,
+ 0xf59a, 0x53a6,
+ 0xf59b, 0x263a,
+ 0xf59c, 0x53a7,
+ 0xf5a0, 0x2643,
+ 0xf5a1, 0x1cfd,
+ 0xf640, 0x53ab,
+ 0xf641, 0x2640,
+ 0xf642, 0x53ac,
+ 0xf645, 0x263d,
+ 0xf646, 0x2641,
+ 0xf647, 0x53af,
+ 0xf648, 0x263e,
+ 0xf649, 0x53b0,
+ 0xf64b, 0x263f,
+ 0xf64c, 0x1fc0,
+ 0xf64d, 0x53b2,
+ 0xf64e, 0x263b,
+ 0xf650, 0x53b3,
+ 0xf654, 0x2642,
+ 0xf655, 0x53b7,
+ 0xf658, 0x2644,
+ 0xf659, 0x53ba,
+ 0xf661, 0x2639,
+ 0xf662, 0x53c2,
+ 0xf663, 0x264c,
+ 0xf664, 0x53c3,
+ 0xf66c, 0x2647,
+ 0xf66d, 0x264b,
+ 0xf66e, 0x53cb,
+ 0xf671, 0x2649,
+ 0xf672, 0x53ce,
+ 0xf674, 0x2648,
+ 0xf675, 0x53d0,
+ 0xf676, 0x264a,
+ 0xf677, 0x2108,
+ 0xf678, 0x53d1,
+ 0xf680, 0x53d8,
+ 0xf685, 0x264d,
+ 0xf686, 0x53dd,
+ 0xf688, 0x2634,
+ 0xf689, 0x53df,
+ 0xf68a, 0x2651,
+ 0xf68b, 0x53e0,
+ 0xf68d, 0x2650,
+ 0xf68e, 0x2652,
+ 0xf68f, 0x53e2,
+ 0xf692, 0x264f,
+ 0xf693, 0x53e5,
+ 0xf696, 0x2632,
+ 0xf697, 0x264e,
+ 0xf698, 0x2653,
+ 0xf699, 0x53e8,
+ 0xf69a, 0x2657,
+ 0xf69b, 0x53e9,
+ 0xf69c, 0x2635,
+ 0xf69d, 0x53ea,
+ 0xf69e, 0x2633,
+ 0xf69f, 0x53eb,
+ 0xf6a0, 0x2656,
+ 0xf6a1, 0x1d5b,
+ 0xf740, 0x53ec,
+ 0xf742, 0x2654,
+ 0xf743, 0x53ee,
+ 0xf749, 0x2658,
+ 0xf74a, 0x53f4,
+ 0xf74c, 0x2655,
+ 0xf74d, 0x1e4d,
+ 0xf74e, 0x53f6,
+ 0xf756, 0x265b,
+ 0xf757, 0x53fe,
+ 0xf758, 0x265a,
+ 0xf759, 0x53ff,
+ 0xf75a, 0x2659,
+ 0xf75b, 0x202e,
+ 0xf75c, 0x262f,
+ 0xf75d, 0x5400,
+ 0xf761, 0x2646,
+ 0xf762, 0x5404,
+ 0xf763, 0x2626,
+ 0xf764, 0x5405,
+ 0xf76b, 0x265c,
+ 0xf76c, 0x540c,
+ 0xf771, 0x262c,
+ 0xf772, 0x5411,
+ 0xf77c, 0x2623,
+ 0xf77d, 0x541b,
+ 0xf77e, 0x2631,
+ 0xf780, 0x541c,
+ 0xf7a1, 0x1db9,
+ 0xf840, 0x543d,
+ 0xf842, 0x209c,
+ 0xf843, 0x543f,
+ 0xf846, 0x2580,
+ 0xf847, 0x5442,
+ 0xf849, 0x22dc,
+ 0xf84a, 0x5444,
+ 0xf850, 0x1f05,
+ 0xf851, 0x208b,
+ 0xf852, 0x544a,
+ 0xf853, 0x2581,
+ 0xf854, 0x544b,
+ 0xf863, 0x2583,
+ 0xf864, 0x2582,
+ 0xf865, 0x545a,
+ 0xf866, 0x21ee,
+ 0xf867, 0x545b,
+ 0xf872, 0x2182,
+ 0xf873, 0x5466,
+ 0xf878, 0x2243,
+ 0xf879, 0x546b,
+ 0xf87a, 0x2587,
+ 0xf87b, 0x546c,
+ 0xf87c, 0x2588,
+ 0xf87d, 0x546d,
+ 0xf880, 0x546f,
+ 0xf881, 0x2584,
+ 0xf882, 0x5470,
+ 0xf884, 0x21fd,
+ 0xf885, 0x5472,
+ 0xf886, 0x21ef,
+ 0xf887, 0x5473,
+ 0xf88d, 0x258a,
+ 0xf88e, 0x258c,
+ 0xf88f, 0x5479,
+ 0xf899, 0x1f47,
+ 0xf89a, 0x5483,
+ 0xf89d, 0x1f1d,
+ 0xf89e, 0x5486,
+ 0xf8a0, 0x258d,
+ 0xf940, 0x5488,
+ 0xf94e, 0x1fd0,
+ 0xf94f, 0x2592,
+ 0xf950, 0x258f,
+ 0xf951, 0x5496,
+ 0xf959, 0x2594,
+ 0xf95a, 0x1ee0,
+ 0xf95b, 0x549e,
+ 0xf95d, 0x2591,
+ 0xf95e, 0x2595,
+ 0xf95f, 0x54a0,
+ 0xf967, 0x2597,
+ 0xf968, 0x54a8,
+ 0xf969, 0x20b6,
+ 0xf96a, 0x54a9,
+ 0xf96c, 0x2598,
+ 0xf96d, 0x54ab,
+ 0xf96f, 0x20f6,
+ 0xf970, 0x54ad,
+ 0xf980, 0x54bc,
+ 0xf985, 0x2585,
+ 0xf986, 0x54c1,
+ 0xf987, 0x2599,
+ 0xf988, 0x54c2,
+ 0xf991, 0x2596,
+ 0xf992, 0x54cb,
+ 0xf996, 0x259a,
+ 0xf997, 0x54cf,
+ 0xf998, 0x259b,
+ 0xf999, 0x54d0,
+ 0xfa40, 0x54d8,
+ 0xfa42, 0x259d,
+ 0xfa43, 0x54da,
+ 0xfa46, 0x259e,
+ 0xfa47, 0x54dd,
+ 0xfa4c, 0x234c,
+ 0xfa4d, 0x54e2,
+ 0xfa51, 0x1f44,
+ 0xfa52, 0x54e6,
+ 0xfa58, 0x2660,
+ 0xfa59, 0x25a0,
+ 0xfa5a, 0x54ec,
+ 0xfa5d, 0x259c,
+ 0xfa5e, 0x54ef,
+ 0xfa5f, 0x259f,
+ 0xfa60, 0x54f0,
+ 0xfa61, 0x1f6c,
+ 0xfa62, 0x54f1,
+ 0xfa70, 0x25a2,
+ 0xfa71, 0x54ff,
+ 0xfa74, 0x20ae,
+ 0xfa75, 0x5502,
+ 0xfa76, 0x258b,
+ 0xfa77, 0x25a3,
+ 0xfa78, 0x5503,
+ 0xfa80, 0x550a,
+ 0xfa83, 0x2589,
+ 0xfa84, 0x25a5,
+ 0xfa85, 0x550d,
+ 0xfa8d, 0x25a4,
+ 0xfa8e, 0x5515,
+ 0xfa90, 0x25a6,
+ 0xfa91, 0x2593,
+ 0xfa92, 0x5517,
+ 0xfa96, 0x25a7,
+ 0xfa97, 0x2222,
+ 0xfa98, 0x25a9,
+ 0xfa99, 0x551b,
+ 0xfb40, 0x5523,
+ 0xfb49, 0x25a8,
+ 0xfb4a, 0x552c,
+ 0xfb52, 0x2586,
+ 0xfb53, 0x5534,
+ 0xfb57, 0x25a1,
+ 0xfb58, 0x25aa,
+ 0xfb59, 0x5538,
+ 0xfb5a, 0x2590,
+ 0xfb5b, 0x258e,
+ 0xfb5c, 0x5539,
+ 0xfb75, 0x2688,
+ 0xfb76, 0x5552,
+ 0xfb79, 0x269e,
+ 0xfb7a, 0x25fb,
+ 0xfb7b, 0x5555,
+ 0xfb7c, 0x1f8c,
+ 0xfb7d, 0x21f4,
+ 0xfb7e, 0x5556,
+ 0xfb80, 0x5557,
+ 0xfb90, 0x200f,
+ 0xfb91, 0x5567,
+ 0xfb9c, 0x2071,
+ 0xfb9d, 0x5572,
+ 0xfb9f, 0x25f7,
+ 0xfba0, 0x5574,
+ 0xfc40, 0x5575,
+ 0xfc44, 0x2696,
+ 0xfc45, 0x5579,
+ 0xfc49, 0x268f,
+ 0xfc4a, 0x557d,
+ 0xfc5a, 0x22da,
+ 0xfc5b, 0x558d,
+ 0xfc63, 0x1ec1,
+ 0xfc64, 0x5595,
+ 0xfc68, 0x1eb3,
+ 0xfc69, 0x5599,
+ 0xfc6f, 0x266a,
+ 0xfc70, 0x559f,
+ 0xfc71, 0x268a,
+ 0xfc72, 0x55a0,
+ 0xfc74, 0x2669,
+ 0xfc75, 0x55a2,
+ 0xfc77, 0x2618,
+ 0xfc79, 0x55a4,
+ 0xfc80, 0x55aa,
+ 0xfc83, 0x261a,
+ 0xfc84, 0x55ad,
+ 0xfc8a, 0x2673,
+ 0xfc8b, 0x55b3,
+ 0xfd40, 0x55c9,
+ 0xfd52, 0x20c6,
+ 0xfd53, 0x226b,
+ 0xfd54, 0x55db,
+ 0xfd57, 0x24d3,
+ 0xfd58, 0x1e86,
+ 0xfd59, 0x55de,
+ 0xfd5a, 0x260f,
+ 0xfd5b, 0x55df,
+ 0xfd5f, 0x2611,
+ 0xfd60, 0x55e3,
+ 0xfd62, 0x2613,
+ 0xfd63, 0x55e5,
+ 0xfd65, 0x2610,
+ 0xfd66, 0x2612,
+ 0xfd67, 0x2030,
+ 0xfd68, 0x55e7,
+ 0xfd69, 0x2671,
+ 0xfd6a, 0x55e8,
+ 0xfd6c, 0x2614,
+ 0xfd6d, 0x55ea,
+ 0xfd70, 0x2616,
+ 0xfd71, 0x55ed,
+ 0xfd72, 0x2615,
+ 0xfd73, 0x55ee,
+ 0xfd78, 0x20f2,
+ 0xfd79, 0x55f3,
+ 0xfd7d, 0x2617,
+ 0xfd7e, 0x55f7,
+ 0xfd80, 0x55f8,
+ 0xfd88, 0x2037,
+ 0xfd89, 0x5600,
+ 0xfd8b, 0x20b3,
+ 0xfd8c, 0x5602,
+ 0xfd8f, 0x1f22,
+ 0xfd90, 0x24ed,
+ 0xfd91, 0x5605,
+ 0xfd94, 0x1f34,
+ 0xfd95, 0x5608,
+ 0xfd9d, 0x0a02,
+ 0xfd9e, 0x40d3,
+ 0xfd9f, 0x200c,
+ 0xfda0, 0x5083,
+ 0xfe40, 0x1259,
+ 0xfe41, 0x5610,
+ 0xfe80, 0x564e,
+ 0xa1a2, 0x023f,
+ 0xa1a3, 0x023e,
+ 0xa1aa, 0x0256,
+ 0xa1ab, 0x1e18,
+ 0xa1ad, 0x0257,
+ 0xa1b2, 0x0246,
+ 0xa1fe, 0x1e1a,
+ 0xa3a1, 0x0242,
+ 0xa3a8, 0x0244,
+ 0xa3ac, 0x023d,
+ 0xa3ae, 0x1e1b,
+ 0xa3ba, 0x0240,
+ 0xa3bd, 0x1e1c,
+ 0xa3bf, 0x0243,
+ 0xa3db, 0x1e1d,
+ 0xa3dd, 0x1e1e,
+ 0xa3df, 0x0258,
+ 0xa3fb, 0x0254,
+ 0xa3fd, 0x0255,
+ 0xa3fe, 0x1e1f,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 gb12GBKEUCVEnc16 = {
+ 1,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x1e24, 0x032e, 0x032f, 0x0330, 0x0331, 0x0332, 0x0333, 0x0334,
+ 0x0335, 0x0336, 0x0337, 0x0338, 0x0339, 0x033a, 0x033b, 0x033c,
+ 0x033d, 0x033e, 0x033f, 0x0340, 0x0341, 0x0342, 0x0343, 0x0344,
+ 0x0345, 0x0346, 0x0347, 0x0348, 0x0349, 0x034a, 0x034b, 0x034c,
+ 0x034d, 0x034e, 0x034f, 0x0350, 0x0351, 0x0352, 0x0353, 0x0354,
+ 0x0355, 0x0356, 0x0357, 0x0358, 0x0359, 0x035a, 0x035b, 0x035c,
+ 0x035d, 0x035e, 0x035f, 0x0360, 0x0361, 0x0362, 0x0363, 0x0364,
+ 0x0365, 0x0366, 0x0367, 0x0368, 0x0369, 0x036a, 0x036b, 0x036c,
+ 0x036d, 0x036e, 0x036f, 0x0370, 0x0371, 0x0372, 0x0373, 0x0374,
+ 0x0375, 0x0376, 0x0377, 0x0378, 0x0379, 0x037a, 0x037b, 0x037c,
+ 0x037d, 0x037e, 0x037f, 0x0380, 0x0381, 0x0382, 0x0383, 0x0384,
+ 0x0385, 0x0386, 0x0387, 0x0388, 0x0389, 0x038a, 0x038b, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ gb12GBKEUCVMap2, 4091
+};
+
+static Gushort gb12GBTEUCHMap2[4566] = {
+ 0x0000, 0x0000,
+ 0xa1a1, 0x0060,
+ 0xa2b1, 0x00be,
+ 0xa2e5, 0x00f0,
+ 0xa2f1, 0x00fa,
+ 0xa3a1, 0x0106,
+ 0xa4a1, 0x0164,
+ 0xa5a1, 0x01b7,
+ 0xa6a1, 0x020d,
+ 0xa6c1, 0x0225,
+ 0xa7a1, 0x025a,
+ 0xa7d1, 0x027b,
+ 0xa8a1, 0x029c,
+ 0xa8c5, 0x02bc,
+ 0xa9a4, 0x02e2,
+ 0xaaa1, 0x032e,
+ 0xaba1, 0x038c,
+ 0xb0a1, 0x03ac,
+ 0xb0a8, 0x1e25,
+ 0xb0a9, 0x03b4,
+ 0xb0aa, 0x1e26,
+ 0xb0ab, 0x03b6,
+ 0xb0ad, 0x1e27,
+ 0xb0af, 0x03ba,
+ 0xb0b9, 0x1e29,
+ 0xb0ba, 0x03c5,
+ 0xb0c0, 0x1e2a,
+ 0xb0c1, 0x03cc,
+ 0xb0d3, 0x1e2b,
+ 0xb0d4, 0x03df,
+ 0xb0d5, 0x1e2c,
+ 0xb0d6, 0x03e1,
+ 0xb0da, 0x1e2d,
+ 0xb0db, 0x03e6,
+ 0xb0dc, 0x1e2e,
+ 0xb0dd, 0x03e8,
+ 0xb0e4, 0x1e2f,
+ 0xb0e5, 0x03f0,
+ 0xb0ec, 0x1e30,
+ 0xb0ee, 0x03f9,
+ 0xb0ef, 0x1e32,
+ 0xb0f0, 0x03fb,
+ 0xb0f3, 0x1e33,
+ 0xb0f4, 0x03ff,
+ 0xb0f7, 0x1e34,
+ 0xb0f8, 0x0403,
+ 0xb0f9, 0x1e35,
+ 0xb0fa, 0x0405,
+ 0xb1a1, 0x040a,
+ 0xb1a5, 0x1e36,
+ 0xb1a7, 0x0410,
+ 0xb1a8, 0x1e38,
+ 0xb1a9, 0x0412,
+ 0xb1ab, 0x1e39,
+ 0xb1ac, 0x0415,
+ 0xb1b2, 0x1e3a,
+ 0xb1b3, 0x041c,
+ 0xb1b4, 0x1e3b,
+ 0xb1b6, 0x041f,
+ 0xb1b7, 0x1e3d,
+ 0xb1ba, 0x0423,
+ 0xb1c1, 0x1e40,
+ 0xb1c2, 0x042b,
+ 0xb1ca, 0x1e41,
+ 0xb1cb, 0x0434,
+ 0xb1cf, 0x1e42,
+ 0xb1d1, 0x043a,
+ 0xb1d2, 0x1e44,
+ 0xb1d3, 0x043c,
+ 0xb1d5, 0x1e45,
+ 0xb1d6, 0x043f,
+ 0xb1df, 0x1e46,
+ 0xb1e2, 0x044b,
+ 0xb1e4, 0x1e49,
+ 0xb1e5, 0x044e,
+ 0xb1e7, 0x1e4a,
+ 0xb1e9, 0x0452,
+ 0xb1ea, 0x1e4c,
+ 0xb1eb, 0x0454,
+ 0xb1ee, 0x1e4d,
+ 0xb1ef, 0x0458,
+ 0xb1f1, 0x1e4e,
+ 0xb1f2, 0x045b,
+ 0xb1f4, 0x1e4f,
+ 0xb1f8, 0x0461,
+ 0xb1fd, 0x1e53,
+ 0xb1fe, 0x0467,
+ 0xb2a1, 0x0468,
+ 0xb2a6, 0x1e54,
+ 0xb2a8, 0x046f,
+ 0xb2ac, 0x1e56,
+ 0xb2ad, 0x0474,
+ 0xb2b5, 0x1e57,
+ 0xb2b6, 0x047d,
+ 0xb2b9, 0x1e58,
+ 0xb2ba, 0x0481,
+ 0xb2c6, 0x1e59,
+ 0xb2c7, 0x048e,
+ 0xb2ce, 0x1e5a,
+ 0xb2d8, 0x049f,
+ 0xb2de, 0x1e64,
+ 0xb2df, 0x04a6,
+ 0xb2e0, 0x1e65,
+ 0xb2e1, 0x04a8,
+ 0xb2e2, 0x1e66,
+ 0xb2e4, 0x04ab,
+ 0xb2ef, 0x1e68,
+ 0xb2f0, 0x04b7,
+ 0xb2f3, 0x1e69,
+ 0xb2fd, 0x04c4,
+ 0xb3a1, 0x1e73,
+ 0xb3a3, 0x04c8,
+ 0xb3a4, 0x1e75,
+ 0xb3a8, 0x04cd,
+ 0xb3a9, 0x1e79,
+ 0xb3aa, 0x04cf,
+ 0xb3ae, 0x1e7a,
+ 0xb3af, 0x04d4,
+ 0xb3b5, 0x1e7b,
+ 0xb3b6, 0x04db,
+ 0xb3b9, 0x1e7c,
+ 0xb3ba, 0x04df,
+ 0xb3be, 0x1e7d,
+ 0xb3bf, 0x04e4,
+ 0xb3c2, 0x1e7e,
+ 0xb3c3, 0x04e8,
+ 0xb3c4, 0x1e7f,
+ 0xb3c5, 0x04ea,
+ 0xb3c6, 0x1e80,
+ 0xb3c7, 0x04ec,
+ 0xb3cd, 0x1e81,
+ 0xb3ce, 0x04f3,
+ 0xb3cf, 0x1e82,
+ 0xb3d0, 0x04f5,
+ 0xb3d2, 0x1e83,
+ 0xb3d3, 0x04f8,
+ 0xb3d9, 0x1e84,
+ 0xb3da, 0x04ff,
+ 0xb3db, 0x1e85,
+ 0xb3dc, 0x0501,
+ 0xb3dd, 0x1e86,
+ 0xb3de, 0x0503,
+ 0xb3e3, 0x1e87,
+ 0xb3e4, 0x0509,
+ 0xb3e5, 0x1e88,
+ 0xb3e7, 0x050c,
+ 0xb3e8, 0x1e8a,
+ 0xb3e9, 0x050e,
+ 0xb3eb, 0x1e8b,
+ 0xb3ed, 0x0512,
+ 0xb3ef, 0x1e8d,
+ 0xb3f0, 0x0515,
+ 0xb3f1, 0x1e8e,
+ 0xb3f2, 0x0517,
+ 0xb3f3, 0x1e8f,
+ 0xb3f4, 0x0519,
+ 0xb3fa, 0x1e90,
+ 0xb3fc, 0x0521,
+ 0xb4a1, 0x1e92,
+ 0xb4a3, 0x0526,
+ 0xb4a5, 0x1e94,
+ 0xb4a7, 0x052a,
+ 0xb4ab, 0x1e96,
+ 0xb4ac, 0x052f,
+ 0xb4af, 0x1e97,
+ 0xb4b0, 0x0533,
+ 0xb4b3, 0x1e98,
+ 0xb4b5, 0x0538,
+ 0xb4b8, 0x1e9a,
+ 0xb4b9, 0x053c,
+ 0xb4bf, 0x1e9b,
+ 0xb4c0, 0x0543,
+ 0xb4c2, 0x1e9c,
+ 0xb4c3, 0x0546,
+ 0xb4c7, 0x1e9d,
+ 0xb4c8, 0x054b,
+ 0xb4ca, 0x1e9e,
+ 0xb4cb, 0x054e,
+ 0xb4cd, 0x1e9f,
+ 0xb4ce, 0x0551,
+ 0xb4cf, 0x1ea0,
+ 0xb4d0, 0x0553,
+ 0xb4d3, 0x1ea1,
+ 0xb4d5, 0x0558,
+ 0xb4da, 0x1ea3,
+ 0xb4db, 0x055e,
+ 0xb4dc, 0x1ea4,
+ 0xb4dd, 0x0560,
+ 0xb4ed, 0x1ea5,
+ 0xb4ee, 0x0571,
+ 0xb4ef, 0x1ea6,
+ 0xb4f0, 0x0573,
+ 0xb4f8, 0x1ea7,
+ 0xb4f9, 0x057c,
+ 0xb4fb, 0x1ea8,
+ 0xb4fc, 0x057f,
+ 0xb5a1, 0x0582,
+ 0xb5a3, 0x1ea9,
+ 0xb5a4, 0x0585,
+ 0xb5a5, 0x1eaa,
+ 0xb5a9, 0x058a,
+ 0xb5ac, 0x1eae,
+ 0xb5ad, 0x058e,
+ 0xb5ae, 0x1eaf,
+ 0xb5b0, 0x0591,
+ 0xb5b1, 0x1eb1,
+ 0xb5b6, 0x0597,
+ 0xb5b7, 0x1eb6,
+ 0xb5b8, 0x0599,
+ 0xb5ba, 0x1eb7,
+ 0xb5bd, 0x059e,
+ 0xb5c6, 0x1eba,
+ 0xb5c7, 0x05a8,
+ 0xb5cb, 0x1ebb,
+ 0xb5cc, 0x05ad,
+ 0xb5d0, 0x1ebc,
+ 0xb5d1, 0x05b2,
+ 0xb5d3, 0x1ebd,
+ 0xb5d4, 0x05b5,
+ 0xb5dd, 0x1ebe,
+ 0xb5e0, 0x05c1,
+ 0xb5e3, 0x1ec1,
+ 0xb5e4, 0x05c5,
+ 0xb5e6, 0x1ec2,
+ 0xb5e8, 0x05c9,
+ 0xb5ed, 0x1ec4,
+ 0xb5ee, 0x05cf,
+ 0xb5f6, 0x1ec5,
+ 0xb5f8, 0x05d9,
+ 0xb5fd, 0x1ec7,
+ 0xb5fe, 0x05df,
+ 0xb6a1, 0x05e0,
+ 0xb6a4, 0x1ec8,
+ 0xb6a6, 0x05e5,
+ 0xb6a7, 0x1eca,
+ 0xb6a8, 0x05e7,
+ 0xb6a9, 0x1ecb,
+ 0xb6aa, 0x05e9,
+ 0xb6ab, 0x1ecc,
+ 0xb6ac, 0x05eb,
+ 0xb6af, 0x1ecd,
+ 0xb6b1, 0x05f0,
+ 0xb6b3, 0x1ecf,
+ 0xb6b4, 0x05f3,
+ 0xb6b7, 0x1ed0,
+ 0xb6b8, 0x05f7,
+ 0xb6bf, 0x1ed1,
+ 0xb6c2, 0x0601,
+ 0xb6c4, 0x1ed4,
+ 0xb6c5, 0x0604,
+ 0xb6c6, 0x1ed5,
+ 0xb6c7, 0x0606,
+ 0xb6cd, 0x1ed6,
+ 0xb6ce, 0x060d,
+ 0xb6cf, 0x1ed7,
+ 0xb6d1, 0x0610,
+ 0xb6d3, 0x1ed9,
+ 0xb6d5, 0x0614,
+ 0xb6d6, 0x1edb,
+ 0xb6d7, 0x0616,
+ 0xb6d9, 0x1edc,
+ 0xb6da, 0x0619,
+ 0xb6db, 0x1edd,
+ 0xb6dc, 0x061b,
+ 0xb6e1, 0x1ede,
+ 0xb6e2, 0x0621,
+ 0xb6e9, 0x1edf,
+ 0xb6ea, 0x0629,
+ 0xb6ec, 0x1ee0,
+ 0xb6ed, 0x062c,
+ 0xb6ee, 0x1ee1,
+ 0xb6f0, 0x062f,
+ 0xb6f1, 0x1ee3,
+ 0xb6f2, 0x0631,
+ 0xb6f6, 0x1ee4,
+ 0xb6f7, 0x0636,
+ 0xb6f9, 0x1ee5,
+ 0xb6fa, 0x0639,
+ 0xb6fb, 0x1ee6,
+ 0xb6fd, 0x063c,
+ 0xb7a1, 0x1ee8,
+ 0xb7a4, 0x0641,
+ 0xb7a7, 0x1eeb,
+ 0xb7a8, 0x0645,
+ 0xb7af, 0x1eec,
+ 0xb7b1, 0x064e,
+ 0xb7b3, 0x1eee,
+ 0xb7b4, 0x0651,
+ 0xb7b6, 0x1eef,
+ 0xb7b8, 0x0655,
+ 0xb7b9, 0x1ef1,
+ 0xb7ba, 0x0657,
+ 0xb7c3, 0x1ef2,
+ 0xb7c5, 0x0662,
+ 0xb7c9, 0x1ef4,
+ 0xb7ca, 0x0667,
+ 0xb7cc, 0x1ef5,
+ 0xb7cd, 0x066a,
+ 0xb7cf, 0x1ef6,
+ 0xb7d0, 0x066d,
+ 0xb7d1, 0x1ef7,
+ 0xb7d2, 0x066f,
+ 0xb7d7, 0x1ef8,
+ 0xb7d9, 0x0676,
+ 0xb7dc, 0x1efa,
+ 0xb7dd, 0x067a,
+ 0xb7df, 0x1efb,
+ 0xb7e2, 0x067f,
+ 0xb7e3, 0x1efe,
+ 0xb7e4, 0x0681,
+ 0xb7e6, 0x1eff,
+ 0xb7e9, 0x0686,
+ 0xb7eb, 0x1f02,
+ 0xb7ee, 0x068b,
+ 0xb7ef, 0x1f05,
+ 0xb7f0, 0x068d,
+ 0xb7f4, 0x1f06,
+ 0xb7f5, 0x0692,
+ 0xb7f8, 0x1f07,
+ 0xb7f9, 0x0696,
+ 0xb8a1, 0x069c,
+ 0xb8a7, 0x1f08,
+ 0xb8a9, 0x06a4,
+ 0xb8b3, 0x1f0a,
+ 0xb8b5, 0x06b0,
+ 0xb8ba, 0x1f0c,
+ 0xb8bb, 0x06b6,
+ 0xb8bc, 0x1f0d,
+ 0xb8bd, 0x06b8,
+ 0xb8be, 0x1f0e,
+ 0xb8c0, 0x06bb,
+ 0xb8c3, 0x1f10,
+ 0xb8c4, 0x06bf,
+ 0xb8c6, 0x1f11,
+ 0xb8c8, 0x06c3,
+ 0xb8c9, 0x1f13,
+ 0xb8ca, 0x06c5,
+ 0xb8cf, 0x1f14,
+ 0xb8d0, 0x06cb,
+ 0xb8d3, 0x1f15,
+ 0xb8d7, 0x06d2,
+ 0xb8d9, 0x1f19,
+ 0xb8db, 0x06d6,
+ 0xb8e4, 0x1f1b,
+ 0xb8e5, 0x06e0,
+ 0xb8e9, 0x1f1c,
+ 0xb8ea, 0x06e5,
+ 0xb8eb, 0x1f1d,
+ 0xb8ec, 0x06e7,
+ 0xb8f3, 0x1f1e,
+ 0xb8f4, 0x06ef,
+ 0xb8f5, 0x1f1f,
+ 0xb8f7, 0x06f2,
+ 0xb8f8, 0x1f21,
+ 0xb8f9, 0x06f4,
+ 0xb9a1, 0x06fa,
+ 0xb9a8, 0x1f22,
+ 0xb9a9, 0x0702,
+ 0xb9ae, 0x1f23,
+ 0xb9af, 0x0708,
+ 0xb9b1, 0x1f24,
+ 0xb9b2, 0x070b,
+ 0xb9b3, 0x1f25,
+ 0xb9b4, 0x070d,
+ 0xb9b5, 0x1f26,
+ 0xb9b6, 0x070f,
+ 0xb9b9, 0x1f27,
+ 0xb9bb, 0x0714,
+ 0xb9c6, 0x1f29,
+ 0xb9c7, 0x0720,
+ 0xb9cb, 0x1f2a,
+ 0xb9cc, 0x0725,
+ 0xb9d0, 0x1f2b,
+ 0xb9d1, 0x072a,
+ 0xb9d8, 0x1f2c,
+ 0xb9d9, 0x0732,
+ 0xb9db, 0x1f2d,
+ 0xb9dc, 0x0735,
+ 0xb9dd, 0x1f2e,
+ 0xb9de, 0x0737,
+ 0xb9df, 0x1f2f,
+ 0xb9e0, 0x0739,
+ 0xb9e1, 0x1f30,
+ 0xb9e2, 0x073b,
+ 0xb9e3, 0x1f31,
+ 0xb9e4, 0x073d,
+ 0xb9e6, 0x1f32,
+ 0xb9e7, 0x0740,
+ 0xb9e9, 0x1f33,
+ 0xb9ed, 0x0746,
+ 0xb9ee, 0x1f37,
+ 0xb9ef, 0x0748,
+ 0xb9f1, 0x1f38,
+ 0xb9f2, 0x074b,
+ 0xb9f3, 0x1f39,
+ 0xb9f6, 0x074f,
+ 0xb9f8, 0x1f3c,
+ 0xb9f9, 0x0752,
+ 0xb9fa, 0x1f3d,
+ 0xb9fb, 0x0754,
+ 0xb9fd, 0x1f3e,
+ 0xb9fe, 0x0757,
+ 0xbaa1, 0x0758,
+ 0xbaa7, 0x1f3f,
+ 0xbaa8, 0x075f,
+ 0xbaab, 0x1f40,
+ 0xbaac, 0x0763,
+ 0xbaba, 0x1f41,
+ 0xbabb, 0x0772,
+ 0xbac5, 0x1f42,
+ 0xbac6, 0x077d,
+ 0xbad2, 0x1f43,
+ 0xbad3, 0x078a,
+ 0xbad7, 0x1f44,
+ 0xbad9, 0x0790,
+ 0xbae4, 0x1f46,
+ 0xbae5, 0x079c,
+ 0xbae8, 0x1f47,
+ 0xbae9, 0x07a0,
+ 0xbaec, 0x1f48,
+ 0xbaed, 0x07a4,
+ 0xbaf3, 0x15e5,
+ 0xbaf4, 0x07ab,
+ 0xbaf8, 0x1f49,
+ 0xbaf9, 0x07b0,
+ 0xbba1, 0x07b6,
+ 0xbba4, 0x1f4a,
+ 0xbba5, 0x07ba,
+ 0xbba6, 0x1f4b,
+ 0xbba7, 0x07bc,
+ 0xbba9, 0x1f4c,
+ 0xbbab, 0x07c0,
+ 0xbbad, 0x1f4e,
+ 0xbbaf, 0x07c4,
+ 0xbbb0, 0x1f50,
+ 0xbbb1, 0x07c6,
+ 0xbbb3, 0x1f51,
+ 0xbbb4, 0x07c9,
+ 0xbbb5, 0x1f52,
+ 0xbbb8, 0x07cd,
+ 0xbbb9, 0x1f55,
+ 0xbbbb, 0x07d0,
+ 0xbbd1, 0x1f57,
+ 0xbbd2, 0x07e7,
+ 0xbbd3, 0x1f58,
+ 0xbbd5, 0x07ea,
+ 0xbbdf, 0x1f5a,
+ 0xbbe8, 0x07fd,
+ 0xbbeb, 0x1f63,
+ 0xbbec, 0x0801,
+ 0xbbf1, 0x1f64,
+ 0xbbf2, 0x0807,
+ 0xbbf5, 0x1f65,
+ 0xbbf8, 0x080d,
+ 0xbbfa, 0x1f68,
+ 0xbbfb, 0x0810,
+ 0xbbfd, 0x1f69,
+ 0xbbfe, 0x0813,
+ 0xbca1, 0x0814,
+ 0xbca2, 0x1f6a,
+ 0xbca3, 0x0816,
+ 0xbca5, 0x1f6b,
+ 0xbca7, 0x081a,
+ 0xbca8, 0x1f6d,
+ 0xbcaa, 0x081d,
+ 0xbcab, 0x1f6f,
+ 0xbcac, 0x081f,
+ 0xbcad, 0x1f70,
+ 0xbcae, 0x0821,
+ 0xbcb6, 0x1f71,
+ 0xbcb9, 0x082c,
+ 0xbcbb, 0x1f74,
+ 0xbcbc, 0x082f,
+ 0xbcc1, 0x1f75,
+ 0xbcc2, 0x0835,
+ 0xbcc3, 0x1f76,
+ 0xbcc4, 0x0837,
+ 0xbcc6, 0x1f77,
+ 0xbcc8, 0x083b,
+ 0xbcca, 0x1f79,
+ 0xbccb, 0x083e,
+ 0xbccc, 0x1f7a,
+ 0xbcce, 0x0841,
+ 0xbcd0, 0x1f7c,
+ 0xbcd1, 0x0844,
+ 0xbcd4, 0x1f7d,
+ 0xbcd7, 0x084a,
+ 0xbcd8, 0x1f80,
+ 0xbcd9, 0x084c,
+ 0xbcdb, 0x1f81,
+ 0xbcdc, 0x084f,
+ 0xbcdd, 0x1f82,
+ 0xbcde, 0x0851,
+ 0xbcdf, 0x1f83,
+ 0xbce2, 0x0855,
+ 0xbce3, 0x1f86,
+ 0xbce5, 0x0858,
+ 0xbce8, 0x1f88,
+ 0xbce9, 0x085c,
+ 0xbcea, 0x1f89,
+ 0xbced, 0x0860,
+ 0xbcef, 0x1f8c,
+ 0xbcf4, 0x0867,
+ 0xbcf6, 0x1f91,
+ 0xbcfd, 0x0870,
+ 0xbda1, 0x0872,
+ 0xbda2, 0x1f98,
+ 0xbda8, 0x0879,
+ 0xbdab, 0x1f9e,
+ 0xbdad, 0x087e,
+ 0xbdaf, 0x1fa0,
+ 0xbdb3, 0x0884,
+ 0xbdb4, 0x1fa4,
+ 0xbdb5, 0x0886,
+ 0xbdba, 0x1fa5,
+ 0xbdbb, 0x088c,
+ 0xbdbd, 0x1fa6,
+ 0xbdc0, 0x0891,
+ 0xbdc1, 0x1fa9,
+ 0xbdc5, 0x0896,
+ 0xbdc8, 0x1fad,
+ 0xbdcb, 0x089c,
+ 0xbdce, 0x1fb0,
+ 0xbdd0, 0x08a1,
+ 0xbdd7, 0x1fb2,
+ 0xbdd8, 0x08a9,
+ 0xbdda, 0x1fb3,
+ 0xbddb, 0x08ac,
+ 0xbde0, 0x1fb4,
+ 0xbde2, 0x08b3,
+ 0xbdeb, 0x1fb6,
+ 0xbdec, 0x08bd,
+ 0xbdf4, 0x1fb7,
+ 0xbdf9, 0x08ca,
+ 0xbdfd, 0x1fbc,
+ 0xbdfe, 0x08cf,
+ 0xbea1, 0x1fbd,
+ 0xbea3, 0x08d2,
+ 0xbea5, 0x1fbf,
+ 0xbea6, 0x08d5,
+ 0xbea8, 0x1fc0,
+ 0xbea9, 0x08d8,
+ 0xbeaa, 0x1fc1,
+ 0xbeab, 0x08da,
+ 0xbead, 0x1fc2,
+ 0xbeae, 0x08dd,
+ 0xbeb1, 0x1fc3,
+ 0xbeb2, 0x08e1,
+ 0xbeb5, 0x1fc4,
+ 0xbeb8, 0x08e7,
+ 0xbeba, 0x1fc7,
+ 0xbebb, 0x08ea,
+ 0xbec0, 0x1fc8,
+ 0xbec1, 0x08f0,
+ 0xbec9, 0x1fc9,
+ 0xbeca, 0x08f9,
+ 0xbed4, 0x1fca,
+ 0xbed5, 0x0904,
+ 0xbed9, 0x1fcb,
+ 0xbeda, 0x0909,
+ 0xbedd, 0x1fcc,
+ 0xbede, 0x090d,
+ 0xbee2, 0x1fcd,
+ 0xbee3, 0x0912,
+ 0xbee5, 0x1fce,
+ 0xbee6, 0x0915,
+ 0xbee7, 0x1fcf,
+ 0xbee8, 0x0917,
+ 0xbee9, 0x1fd0,
+ 0xbeea, 0x0919,
+ 0xbeee, 0x1fd1,
+ 0xbeef, 0x091e,
+ 0xbef5, 0x1fd2,
+ 0xbef6, 0x0925,
+ 0xbef7, 0x1fd3,
+ 0xbef9, 0x0928,
+ 0xbefb, 0x1fd5,
+ 0xbefd, 0x092c,
+ 0xbfa1, 0x092e,
+ 0xbfa5, 0x1fd7,
+ 0xbfa6, 0x0933,
+ 0xbfaa, 0x1fd8,
+ 0xbfab, 0x0938,
+ 0xbfad, 0x1fd9,
+ 0xbfae, 0x093b,
+ 0xbfc5, 0x1fda,
+ 0xbfc6, 0x0953,
+ 0xbfc7, 0x1fdb,
+ 0xbfc8, 0x0955,
+ 0xbfce, 0x1fdc,
+ 0xbfcf, 0x095c,
+ 0xbfd1, 0x1fdd,
+ 0xbfd3, 0x0960,
+ 0xbfd9, 0x1fdf,
+ 0xbfda, 0x0967,
+ 0xbfe2, 0x1fe0,
+ 0xbfe5, 0x0972,
+ 0xbfe9, 0x1fe3,
+ 0xbfea, 0x0977,
+ 0xbfeb, 0x1fe4,
+ 0xbfec, 0x0979,
+ 0xbfed, 0x1fe5,
+ 0xbfee, 0x097b,
+ 0xbff3, 0x1fe6,
+ 0xbff4, 0x0981,
+ 0xbff5, 0x1fe7,
+ 0xbff6, 0x0983,
+ 0xbff7, 0x1fe8,
+ 0xbff8, 0x0985,
+ 0xbff9, 0x1fe9,
+ 0xbffb, 0x0988,
+ 0xc0a1, 0x1feb,
+ 0xc0a2, 0x098d,
+ 0xc0a3, 0x1fec,
+ 0xc0a4, 0x098f,
+ 0xc0a9, 0x1fed,
+ 0xc0aa, 0x0995,
+ 0xc0ab, 0x1fee,
+ 0xc0ac, 0x0997,
+ 0xc0af, 0x1fef,
+ 0xc0b1, 0x099c,
+ 0xc0b3, 0x1ff1,
+ 0xc0b7, 0x09a2,
+ 0xc0b8, 0x1ff5,
+ 0xc0c5, 0x09b0,
+ 0xc0cc, 0x2002,
+ 0xc0ce, 0x09b9,
+ 0xc0d4, 0x2004,
+ 0xc0d5, 0x09c0,
+ 0xc0d6, 0x2005,
+ 0xc0d7, 0x09c2,
+ 0xc0d8, 0x2006,
+ 0xc0d9, 0x09c4,
+ 0xc0dd, 0x2007,
+ 0xc0de, 0x09c9,
+ 0xc0e0, 0x2008,
+ 0xc0e1, 0x09cc,
+ 0xc0e9, 0x2009,
+ 0xc0ea, 0x09d5,
+ 0xc0eb, 0x200a,
+ 0xc0ed, 0x09d8,
+ 0xc0ef, 0x200c,
+ 0xc0f2, 0x09dd,
+ 0xc0f6, 0x200f,
+ 0xc0fb, 0x09e6,
+ 0xc1a1, 0x09ea,
+ 0xc1a4, 0x2014,
+ 0xc1a6, 0x09ef,
+ 0xc1a9, 0x2016,
+ 0xc1ae, 0x09f7,
+ 0xc1af, 0x201b,
+ 0xc1b9, 0x0a02,
+ 0xc1bd, 0x2025,
+ 0xc1bf, 0x0a08,
+ 0xc1c2, 0x2027,
+ 0xc1c3, 0x0a0c,
+ 0xc1c6, 0x2028,
+ 0xc1c7, 0x0a10,
+ 0xc1c9, 0x2029,
+ 0xc1ca, 0x0a13,
+ 0xc1cd, 0x202a,
+ 0xc1ce, 0x0a17,
+ 0xc1d4, 0x202b,
+ 0xc1d5, 0x0a1e,
+ 0xc1d9, 0x202c,
+ 0xc1dc, 0x0a25,
+ 0xc1de, 0x202f,
+ 0xc1df, 0x0a28,
+ 0xc1e4, 0x2030,
+ 0xc1e6, 0x0a2f,
+ 0xc1e9, 0x2032,
+ 0xc1ea, 0x0a33,
+ 0xc1eb, 0x2033,
+ 0xc1ed, 0x0a36,
+ 0xc1f3, 0x2035,
+ 0xc1f4, 0x0a3d,
+ 0xc1f5, 0x2036,
+ 0xc1f6, 0x0a3f,
+ 0xc1fa, 0x2037,
+ 0xc1fe, 0x0a47,
+ 0xc2a1, 0x0a48,
+ 0xc2a2, 0x203b,
+ 0xc2a9, 0x0a50,
+ 0xc2ab, 0x2042,
+ 0xc2b4, 0x0a5b,
+ 0xc2b8, 0x204b,
+ 0xc2b9, 0x0a60,
+ 0xc2bc, 0x204c,
+ 0xc2be, 0x0a65,
+ 0xc2bf, 0x204e,
+ 0xc2c0, 0x0a67,
+ 0xc2c1, 0x204f,
+ 0xc2c2, 0x0a69,
+ 0xc2c5, 0x2050,
+ 0xc2c8, 0x0a6f,
+ 0xc2cb, 0x2053,
+ 0xc2d1, 0x0a78,
+ 0xc2d2, 0x2059,
+ 0xc2d3, 0x0a7a,
+ 0xc2d5, 0x205a,
+ 0xc2dd, 0x0a84,
+ 0xc2de, 0x2062,
+ 0xc2e3, 0x0a8a,
+ 0xc2e6, 0x2067,
+ 0xc2e9, 0x0a90,
+ 0xc2ea, 0x206a,
+ 0xc2ef, 0x0a96,
+ 0xc2f0, 0x206f,
+ 0xc2f1, 0x0a98,
+ 0xc2f2, 0x2070,
+ 0xc2f6, 0x0a9d,
+ 0xc2f7, 0x2074,
+ 0xc2fb, 0x0aa2,
+ 0xc3a1, 0x2078,
+ 0xc3a2, 0x0aa7,
+ 0xc3aa, 0x2079,
+ 0xc3ab, 0x0ab0,
+ 0xc3ad, 0x207a,
+ 0xc3ae, 0x0ab3,
+ 0xc3b3, 0x207b,
+ 0xc3b4, 0x1df9,
+ 0xc3b5, 0x0aba,
+ 0xc3be, 0x207c,
+ 0xc3bf, 0x0ac4,
+ 0xc3c5, 0x207d,
+ 0xc3c8, 0x0acd,
+ 0xc3cc, 0x2080,
+ 0xc3cd, 0x0ad2,
+ 0xc3ce, 0x2081,
+ 0xc3cf, 0x0ad4,
+ 0xc3d5, 0x2082,
+ 0xc3d7, 0x0adc,
+ 0xc3d9, 0x2084,
+ 0xc3da, 0x0adf,
+ 0xc3e0, 0x2085,
+ 0xc3e1, 0x0ae6,
+ 0xc3e5, 0x2086,
+ 0xc3e6, 0x0aeb,
+ 0xc3ed, 0x2087,
+ 0xc3ee, 0x0af3,
+ 0xc3f0, 0x2088,
+ 0xc3f1, 0x0af6,
+ 0xc3f5, 0x2089,
+ 0xc3f7, 0x0afc,
+ 0xc3f9, 0x208b,
+ 0xc3fb, 0x0b00,
+ 0xc3fd, 0x208d,
+ 0xc3fe, 0x0b03,
+ 0xc4a1, 0x0b04,
+ 0xc4b1, 0x208e,
+ 0xc4b2, 0x0b15,
+ 0xc4b6, 0x208f,
+ 0xc4b7, 0x0b1a,
+ 0xc4c6, 0x2090,
+ 0xc4c7, 0x0b2a,
+ 0xc4c9, 0x2091,
+ 0xc4ca, 0x0b2d,
+ 0xc4d1, 0x2092,
+ 0xc4d2, 0x0b35,
+ 0xc4d3, 0x2093,
+ 0xc4d7, 0x0b3a,
+ 0xc4d9, 0x2097,
+ 0xc4da, 0x0b3d,
+ 0xc4e2, 0x2098,
+ 0xc4e3, 0x0b46,
+ 0xc4e5, 0x2099,
+ 0xc4e6, 0x0b49,
+ 0xc4ec, 0x209a,
+ 0xc4ed, 0x0b50,
+ 0xc4f0, 0x209b,
+ 0xc4f2, 0x0b55,
+ 0xc4f4, 0x209d,
+ 0xc4f5, 0x0b58,
+ 0xc4f6, 0x209e,
+ 0xc4f9, 0x0b5c,
+ 0xc4fb, 0x20a1,
+ 0xc4fd, 0x0b60,
+ 0xc4fe, 0x20a3,
+ 0xc5a1, 0x20a4,
+ 0xc5a3, 0x0b64,
+ 0xc5a5, 0x20a6,
+ 0xc5aa, 0x0b6b,
+ 0xc5b1, 0x20ab,
+ 0xc5b2, 0x0b73,
+ 0xc5b5, 0x20ac,
+ 0xc5b6, 0x0b77,
+ 0xc5b7, 0x20ad,
+ 0xc5ba, 0x0b7b,
+ 0xc5bb, 0x20b0,
+ 0xc5bc, 0x0b7d,
+ 0xc5bd, 0x20b1,
+ 0xc5be, 0x0b7f,
+ 0xc5cc, 0x20b2,
+ 0xc5cd, 0x0b8e,
+ 0xc5d3, 0x20b3,
+ 0xc5d4, 0x0b95,
+ 0xc5e2, 0x20b4,
+ 0xc5e3, 0x0ba4,
+ 0xc5e7, 0x20b5,
+ 0xc5e8, 0x0ba9,
+ 0xc5f4, 0x20b6,
+ 0xc5f5, 0x0bb6,
+ 0xc6a1, 0x0bc0,
+ 0xc6ad, 0x20b7,
+ 0xc6af, 0x0bce,
+ 0xc6b5, 0x20b9,
+ 0xc6b7, 0x0bd6,
+ 0xc6bb, 0x20bb,
+ 0xc6bc, 0x0bdb,
+ 0xc6be, 0x20bc,
+ 0xc6bf, 0x0bde,
+ 0xc6c0, 0x20bd,
+ 0xc6c1, 0x0be0,
+ 0xc6c3, 0x20be,
+ 0xc6c5, 0x0be4,
+ 0xc6cb, 0x20c0,
+ 0xc6ce, 0x0bed,
+ 0xc6d3, 0x20c3,
+ 0xc6d4, 0x0bf3,
+ 0xc6d7, 0x20c4,
+ 0xc6d8, 0x0bf7,
+ 0xc6ea, 0x20c5,
+ 0xc6ec, 0x0c0b,
+ 0xc6ef, 0x20c7,
+ 0xc6f0, 0x0c0f,
+ 0xc6f1, 0x20c8,
+ 0xc6f2, 0x0c11,
+ 0xc6f4, 0x20c9,
+ 0xc6f5, 0x0c14,
+ 0xc6f8, 0x20ca,
+ 0xc6f9, 0x0c18,
+ 0xc6fd, 0x20cb,
+ 0xc6fe, 0x0c1d,
+ 0xc7a1, 0x0c1e,
+ 0xc7a3, 0x20cc,
+ 0xc7a4, 0x0c21,
+ 0xc7a5, 0x20cd,
+ 0xc7a7, 0x0c24,
+ 0xc7a8, 0x20cf,
+ 0xc7aa, 0x0c27,
+ 0xc7ab, 0x20d1,
+ 0xc7ac, 0x0c29,
+ 0xc7ae, 0x20d2,
+ 0xc7b0, 0x0c2d,
+ 0xc7b3, 0x20d4,
+ 0xc7b6, 0x0c33,
+ 0xc7b9, 0x20d7,
+ 0xc7bb, 0x0c38,
+ 0xc7bd, 0x20d9,
+ 0xc7bf, 0x0c3c,
+ 0xc7c0, 0x20db,
+ 0xc7c1, 0x0c3e,
+ 0xc7c2, 0x20dc,
+ 0xc7c3, 0x0c40,
+ 0xc7c5, 0x20dd,
+ 0xc7c6, 0x0c43,
+ 0xc7c7, 0x20de,
+ 0xc7c9, 0x0c46,
+ 0xc7cc, 0x20e0,
+ 0xc7cd, 0x0c4a,
+ 0xc7cf, 0x20e1,
+ 0xc7d0, 0x0c4d,
+ 0xc7d4, 0x20e2,
+ 0xc7d6, 0x0c53,
+ 0xc7d7, 0x20e4,
+ 0xc7d8, 0x0c55,
+ 0xc7de, 0x20e5,
+ 0xc7df, 0x0c5c,
+ 0xc7e1, 0x20e6,
+ 0xc7e4, 0x0c61,
+ 0xc7ea, 0x20e9,
+ 0xc7ef, 0x0c6c,
+ 0xc7f7, 0x20ee,
+ 0xc7f9, 0x0c76,
+ 0xc7fb, 0x20f0,
+ 0xc7fc, 0x0c79,
+ 0xc7fd, 0x20f1,
+ 0xc7fe, 0x0c7b,
+ 0xc8a1, 0x0c7c,
+ 0xc8a3, 0x20f2,
+ 0xc8a4, 0x0c7f,
+ 0xc8a7, 0x20f3,
+ 0xc8a9, 0x0c84,
+ 0xc8b0, 0x20f5,
+ 0xc8b1, 0x0c8c,
+ 0xc8b5, 0x20f6,
+ 0xc8b6, 0x0c91,
+ 0xc8b7, 0x20f7,
+ 0xc8b8, 0x0c93,
+ 0xc8c3, 0x20f8,
+ 0xc8c7, 0x0ca2,
+ 0xc8c8, 0x20fc,
+ 0xc8c9, 0x0ca4,
+ 0xc8cd, 0x20fd,
+ 0xc8ce, 0x0ca9,
+ 0xc8cf, 0x20fe,
+ 0xc8d0, 0x0cab,
+ 0xc8d2, 0x20ff,
+ 0xc8d3, 0x0cae,
+ 0xc8d9, 0x2100,
+ 0xc8da, 0x0cb5,
+ 0xc8de, 0x2101,
+ 0xc8df, 0x0cba,
+ 0xc8ed, 0x2102,
+ 0xc8ee, 0x0cc9,
+ 0xc8f1, 0x2103,
+ 0xc8f4, 0x0ccf,
+ 0xc8f7, 0x2106,
+ 0xc8f9, 0x0cd4,
+ 0xc8fa, 0x2108,
+ 0xc8fb, 0x0cd6,
+ 0xc8fc, 0x2109,
+ 0xc8fd, 0x0cd8,
+ 0xc9a1, 0x210a,
+ 0xc9a2, 0x0cdb,
+ 0xc9a5, 0x210b,
+ 0xc9a6, 0x0cdf,
+ 0xc9a7, 0x210c,
+ 0xc9a9, 0x0ce2,
+ 0xc9ac, 0x210e,
+ 0xc9ad, 0x0ce6,
+ 0xc9b1, 0x210f,
+ 0xc9b2, 0x0ceb,
+ 0xc9b4, 0x2110,
+ 0xc9b5, 0x0cee,
+ 0xc9b8, 0x2111,
+ 0xc9ba, 0x0cf3,
+ 0xc9c1, 0x2113,
+ 0xc9c3, 0x0cfc,
+ 0xc9c4, 0x2115,
+ 0xc9c5, 0x0cfe,
+ 0xc9c9, 0x2116,
+ 0xc9ca, 0x0d03,
+ 0xc9cb, 0x2117,
+ 0xc9cc, 0x0d05,
+ 0xc9cd, 0x2118,
+ 0xc9ce, 0x0d07,
+ 0xc9d5, 0x2119,
+ 0xc9d6, 0x0d0f,
+ 0xc9dc, 0x211a,
+ 0xc9dd, 0x0d16,
+ 0xc9de, 0x211b,
+ 0xc9df, 0x0d18,
+ 0xc9e1, 0x211c,
+ 0xc9e2, 0x0d1b,
+ 0xc9e3, 0x211d,
+ 0xc9e4, 0x0d1d,
+ 0xc9e5, 0x211e,
+ 0xc9e6, 0x0d1f,
+ 0xc9e8, 0x211f,
+ 0xc9e9, 0x0d22,
+ 0xc9f0, 0x2120,
+ 0xc9f1, 0x0d2a,
+ 0xc9f3, 0x2121,
+ 0xc9f5, 0x0d2e,
+ 0xc9f6, 0x2123,
+ 0xc9f7, 0x0d30,
+ 0xc9f8, 0x2124,
+ 0xc9fa, 0x0d33,
+ 0xc9fe, 0x2126,
+ 0xcaa1, 0x0d38,
+ 0xcaa4, 0x2127,
+ 0xcaa7, 0x0d3e,
+ 0xcaa8, 0x212a,
+ 0xcaa9, 0x0d40,
+ 0xcaaa, 0x212b,
+ 0xcaac, 0x0d43,
+ 0xcab1, 0x212d,
+ 0xcab2, 0x0d49,
+ 0xcab4, 0x212e,
+ 0xcab7, 0x0d4e,
+ 0xcabb, 0x2131,
+ 0xcabc, 0x0d53,
+ 0xcac6, 0x2132,
+ 0xcac7, 0x0d5e,
+ 0xcaca, 0x2133,
+ 0xcacb, 0x0d62,
+ 0xcacd, 0x2134,
+ 0xcacf, 0x0d66,
+ 0xcad3, 0x2136,
+ 0xcad5, 0x0d6c,
+ 0xcad9, 0x2138,
+ 0xcada, 0x0d71,
+ 0xcade, 0x2139,
+ 0xcadf, 0x0d76,
+ 0xcae0, 0x213a,
+ 0xcae1, 0x0d78,
+ 0xcae4, 0x213b,
+ 0xcae5, 0x0d7c,
+ 0xcae9, 0x213c,
+ 0xcaeb, 0x0d82,
+ 0xcaf4, 0x213e,
+ 0xcaf6, 0x0d8d,
+ 0xcaf7, 0x2140,
+ 0xcaf8, 0x0d8f,
+ 0xcafa, 0x2141,
+ 0xcafb, 0x0d92,
+ 0xcafd, 0x2142,
+ 0xcafe, 0x0d95,
+ 0xcba1, 0x0d96,
+ 0xcba7, 0x2143,
+ 0xcba8, 0x0d9d,
+ 0xcbab, 0x2144,
+ 0xcbac, 0x0da1,
+ 0xcbad, 0x2145,
+ 0xcbae, 0x0da3,
+ 0xcbb3, 0x2146,
+ 0xcbb4, 0x0da9,
+ 0xcbb5, 0x2147,
+ 0xcbb7, 0x0dac,
+ 0xcbb8, 0x2149,
+ 0xcbb9, 0x0dae,
+ 0xcbbf, 0x214a,
+ 0xcbc0, 0x0db5,
+ 0xcbc7, 0x214b,
+ 0xcbc8, 0x0dbd,
+ 0xcbc9, 0x214c,
+ 0xcbcd, 0x0dc2,
+ 0xcbcf, 0x2150,
+ 0xcbd1, 0x0dc6,
+ 0xcbd3, 0x2152,
+ 0xcbd4, 0x0dc9,
+ 0xcbd5, 0x2153,
+ 0xcbd6, 0x0dcb,
+ 0xcbdf, 0x2154,
+ 0xcbe1, 0x0dd6,
+ 0xcbe4, 0x2156,
+ 0xcbe5, 0x0dda,
+ 0xcbe6, 0x2157,
+ 0xcbe8, 0x0ddd,
+ 0xcbea, 0x2159,
+ 0xcbeb, 0x0de0,
+ 0xcbef, 0x215a,
+ 0xcbf1, 0x0de6,
+ 0xcbf5, 0x215c,
+ 0xcbf7, 0x0dec,
+ 0xcbf8, 0x215e,
+ 0xcbf9, 0x0dee,
+ 0xcca1, 0x215f,
+ 0xcca3, 0x0df6,
+ 0xcca8, 0x2161,
+ 0xcca9, 0x0dfc,
+ 0xccac, 0x2162,
+ 0xccad, 0x0e00,
+ 0xccaf, 0x2163,
+ 0xccb4, 0x0e07,
+ 0xccb7, 0x2168,
+ 0xccb9, 0x0e0c,
+ 0xccbe, 0x216a,
+ 0xccbf, 0x0e12,
+ 0xccc0, 0x216b,
+ 0xccc1, 0x0e14,
+ 0xcccc, 0x216c,
+ 0xcccd, 0x0e20,
+ 0xccce, 0x216d,
+ 0xcccf, 0x0e22,
+ 0xccd0, 0x216e,
+ 0xccd1, 0x0e24,
+ 0xccd6, 0x216f,
+ 0xccd7, 0x0e2a,
+ 0xccda, 0x2170,
+ 0xccdb, 0x0e2e,
+ 0xccdc, 0x2171,
+ 0xccdd, 0x0e30,
+ 0xcce0, 0x2172,
+ 0xcce1, 0x0e34,
+ 0xcce2, 0x2173,
+ 0xcce3, 0x0e36,
+ 0xcce5, 0x2174,
+ 0xcce6, 0x0e39,
+ 0xccf5, 0x2175,
+ 0xccf6, 0x0e49,
+ 0xccf9, 0x2176,
+ 0xccfb, 0x0e4e,
+ 0xccfc, 0x2178,
+ 0xcda1, 0x0e52,
+ 0xcdad, 0x217b,
+ 0xcdae, 0x0e5f,
+ 0xcdb3, 0x217c,
+ 0xcdb4, 0x0e65,
+ 0xcdb7, 0x217d,
+ 0xcdb8, 0x0e69,
+ 0xcdbc, 0x217e,
+ 0xcdbd, 0x0e6e,
+ 0xcdbf, 0x217f,
+ 0xcdc0, 0x0e71,
+ 0xcdc5, 0x2180,
+ 0xcdc6, 0x0e77,
+ 0xcdc7, 0x2181,
+ 0xcdc8, 0x0e79,
+ 0xcdd2, 0x2182,
+ 0xcdd3, 0x0e84,
+ 0xcdd4, 0x2183,
+ 0xcdd7, 0x0e88,
+ 0xcddd, 0x2186,
+ 0xcdde, 0x0e8f,
+ 0xcde0, 0x2187,
+ 0xcde1, 0x0e92,
+ 0xcde4, 0x2188,
+ 0xcde6, 0x0e97,
+ 0xcde7, 0x218a,
+ 0xcde8, 0x0e99,
+ 0xcdf2, 0x218b,
+ 0xcdf3, 0x0ea4,
+ 0xcdf8, 0x218c,
+ 0xcdf9, 0x0eaa,
+ 0xcea1, 0x0eb0,
+ 0xcea4, 0x218d,
+ 0xcea6, 0x0eb5,
+ 0xcea7, 0x218f,
+ 0xcea8, 0x0eb7,
+ 0xceaa, 0x2190,
+ 0xceae, 0x0ebd,
+ 0xceb0, 0x2194,
+ 0xceb2, 0x0ec1,
+ 0xceb3, 0x2196,
+ 0xceb4, 0x0ec3,
+ 0xcebd, 0x2197,
+ 0xcebe, 0x0ecd,
+ 0xcec0, 0x2198,
+ 0xcec1, 0x0ed0,
+ 0xcec5, 0x2199,
+ 0xcec7, 0x0ed6,
+ 0xcec8, 0x219b,
+ 0xcec9, 0x0ed8,
+ 0xceca, 0x219c,
+ 0xcecb, 0x0eda,
+ 0xcece, 0x219d,
+ 0xced2, 0x0ee1,
+ 0xced8, 0x21a1,
+ 0xcedb, 0x0eea,
+ 0xcedc, 0x21a4,
+ 0xcedd, 0x0eec,
+ 0xcede, 0x21a5,
+ 0xcee0, 0x0eef,
+ 0xceeb, 0x21a7,
+ 0xceec, 0x0efb,
+ 0xceed, 0x21a8,
+ 0xceee, 0x0efd,
+ 0xcef1, 0x21a9,
+ 0xcef2, 0x0f01,
+ 0xcef3, 0x21aa,
+ 0xcef4, 0x0f03,
+ 0xcefd, 0x21ab,
+ 0xcfa1, 0x0f0e,
+ 0xcfae, 0x21ad,
+ 0xcfaf, 0x0f1c,
+ 0xcfb0, 0x21ae,
+ 0xcfb1, 0x0f1e,
+ 0xcfb3, 0x21af,
+ 0xcfb4, 0x0f21,
+ 0xcfb7, 0x21b0,
+ 0xcfb9, 0x0f26,
+ 0xcfba, 0x21b2,
+ 0xcfbb, 0x0f28,
+ 0xcfbd, 0x21b3,
+ 0xcfbe, 0x0f2b,
+ 0xcfbf, 0x21b4,
+ 0xcfc2, 0x0f2f,
+ 0xcfc5, 0x21b7,
+ 0xcfc6, 0x0f33,
+ 0xcfc7, 0x21b8,
+ 0xcfc8, 0x0f35,
+ 0xcfca, 0x21b9,
+ 0xcfcc, 0x0f39,
+ 0xcfcd, 0x21bb,
+ 0xcfcf, 0x0f3c,
+ 0xcfd0, 0x21bd,
+ 0xcfd1, 0x0f3e,
+ 0xcfd4, 0x21be,
+ 0xcfd9, 0x0f46,
+ 0xcfda, 0x21c3,
+ 0xcfdb, 0x0f48,
+ 0xcfdc, 0x21c4,
+ 0xcfdd, 0x0f4a,
+ 0xcfdf, 0x21c5,
+ 0xcfe0, 0x0f4d,
+ 0xcfe2, 0x21c6,
+ 0xcfe3, 0x0f50,
+ 0xcfe7, 0x21c7,
+ 0xcfe8, 0x0f55,
+ 0xcfea, 0x21c8,
+ 0xcfeb, 0x0f58,
+ 0xcfec, 0x21c9,
+ 0xcfed, 0x0f5a,
+ 0xcfee, 0x21ca,
+ 0xcfef, 0x0f5c,
+ 0xcff4, 0x21cb,
+ 0xcff5, 0x0f62,
+ 0xcff9, 0x21cc,
+ 0xcffb, 0x0f68,
+ 0xcffe, 0x21ce,
+ 0xd0a1, 0x0f6c,
+ 0xd0a5, 0x21cf,
+ 0xd0a6, 0x0f71,
+ 0xd0ad, 0x21d0,
+ 0xd0af, 0x0f7a,
+ 0xd0b2, 0x21d2,
+ 0xd0b5, 0x0f80,
+ 0xd0ba, 0x21d5,
+ 0xd0bc, 0x0f87,
+ 0xd0bf, 0x21d7,
+ 0xd0c0, 0x0f8b,
+ 0xd0c6, 0x21d8,
+ 0xd0c7, 0x0f92,
+ 0xd0cb, 0x21d9,
+ 0xd0cc, 0x0f97,
+ 0xd0e2, 0x21da,
+ 0xd0e3, 0x0fae,
+ 0xd0e5, 0x21db,
+ 0xd0e6, 0x0fb1,
+ 0xd0eb, 0x21dc,
+ 0xd0ec, 0x0fb7,
+ 0xd0ed, 0x21dd,
+ 0xd0ee, 0x0fb9,
+ 0xd0f7, 0x21de,
+ 0xd0fa, 0x0fc5,
+ 0xd0fc, 0x21e1,
+ 0xd0fd, 0x0fc8,
+ 0xd1a1, 0x21e2,
+ 0xd1a3, 0x0fcc,
+ 0xd1a4, 0x21e4,
+ 0xd1a5, 0x0fce,
+ 0xd1a7, 0x21e5,
+ 0xd1a8, 0x0fd1,
+ 0xd1ab, 0x21e6,
+ 0xd1ac, 0x0fd5,
+ 0xd1af, 0x21e7,
+ 0xd1b2, 0x0fdb,
+ 0xd1b5, 0x21ea,
+ 0xd1b8, 0x0fe1,
+ 0xd1b9, 0x21ed,
+ 0xd1ba, 0x0fe3,
+ 0xd1bb, 0x21ee,
+ 0xd1bd, 0x0fe6,
+ 0xd1c6, 0x21f0,
+ 0xd1c9, 0x0ff2,
+ 0xd1cb, 0x21f3,
+ 0xd1cc, 0x0ff5,
+ 0xd1ce, 0x21f4,
+ 0xd1d0, 0x0ff9,
+ 0xd1d5, 0x21f6,
+ 0xd1d7, 0x1000,
+ 0xd1de, 0x21f8,
+ 0xd1df, 0x1008,
+ 0xd1e1, 0x21f9,
+ 0xd1e3, 0x100c,
+ 0xd1e8, 0x21fb,
+ 0xd1ea, 0x1013,
+ 0xd1ec, 0x21fd,
+ 0xd1ed, 0x1016,
+ 0xd1ee, 0x21fe,
+ 0xd1f0, 0x1019,
+ 0xd1f1, 0x2200,
+ 0xd1f2, 0x101b,
+ 0xd1f4, 0x2201,
+ 0xd1f5, 0x101e,
+ 0xd1f7, 0x2202,
+ 0xd1fa, 0x1023,
+ 0xd2a1, 0x1028,
+ 0xd2a2, 0x2205,
+ 0xd2a3, 0x102a,
+ 0xd2a5, 0x2206,
+ 0xd2a6, 0x102d,
+ 0xd2a9, 0x2207,
+ 0xd2aa, 0x1031,
+ 0xd2af, 0x2208,
+ 0xd2b0, 0x1037,
+ 0xd2b3, 0x2209,
+ 0xd2b4, 0x103b,
+ 0xd2b5, 0x220a,
+ 0xd2b7, 0x103e,
+ 0xd2bd, 0x220c,
+ 0xd2be, 0x1045,
+ 0xd2bf, 0x220d,
+ 0xd2c0, 0x1047,
+ 0xd2c3, 0x220e,
+ 0xd2c4, 0x104b,
+ 0xd2c5, 0x220f,
+ 0xd2c6, 0x104d,
+ 0xd2c7, 0x2210,
+ 0xd2c8, 0x104f,
+ 0xd2cf, 0x2211,
+ 0xd2d0, 0x1057,
+ 0xd2d5, 0x2212,
+ 0xd2d6, 0x105d,
+ 0xd2da, 0x2213,
+ 0xd2db, 0x1062,
+ 0xd2e4, 0x2214,
+ 0xd2e6, 0x106d,
+ 0xd2e8, 0x2216,
+ 0xd2ec, 0x1073,
+ 0xd2ef, 0x221a,
+ 0xd2f0, 0x1077,
+ 0xd2f1, 0x221b,
+ 0xd2f2, 0x1079,
+ 0xd2f5, 0x221c,
+ 0xd2f6, 0x107d,
+ 0xd2f8, 0x221d,
+ 0xd2f9, 0x1080,
+ 0xd2fb, 0x221e,
+ 0xd2fc, 0x1083,
+ 0xd2fe, 0x221f,
+ 0xd3a1, 0x1086,
+ 0xd3a3, 0x2220,
+ 0xd3ad, 0x1092,
+ 0xd3ae, 0x222a,
+ 0xd3af, 0x1094,
+ 0xd3b1, 0x222b,
+ 0xd3b2, 0x1097,
+ 0xd3b4, 0x222c,
+ 0xd3b7, 0x109c,
+ 0xd3b8, 0x222f,
+ 0xd3b9, 0x109e,
+ 0xd3bb, 0x2230,
+ 0xd3bc, 0x10a1,
+ 0xd3c5, 0x2231,
+ 0xd3c6, 0x10ab,
+ 0xd3c7, 0x2232,
+ 0xd3c8, 0x10ad,
+ 0xd3ca, 0x2233,
+ 0xd3cd, 0x10b2,
+ 0xd3d5, 0x2236,
+ 0xd3d6, 0x10bb,
+ 0xd3df, 0x2237,
+ 0xd3e1, 0x10c6,
+ 0xd3e3, 0x2239,
+ 0xd3e4, 0x10c9,
+ 0xd3e6, 0x223a,
+ 0xd3e7, 0x10cc,
+ 0xd3eb, 0x223b,
+ 0xd3ed, 0x10d2,
+ 0xd3ef, 0x223d,
+ 0xd3f0, 0x10d5,
+ 0xd3f4, 0x223e,
+ 0xd3f5, 0x10da,
+ 0xd3fc, 0x223f,
+ 0xd3fd, 0x10e2,
+ 0xd3fe, 0x2240,
+ 0xd4a1, 0x10e4,
+ 0xd4a4, 0x2241,
+ 0xd4a5, 0x10e8,
+ 0xd4a6, 0x2242,
+ 0xd4a9, 0x10ec,
+ 0xd4af, 0x2245,
+ 0xd4b3, 0x10f6,
+ 0xd4b5, 0x2249,
+ 0xd4b7, 0x10fa,
+ 0xd4b8, 0x224b,
+ 0xd4b9, 0x10fc,
+ 0xd4bc, 0x224c,
+ 0xd4bd, 0x1100,
+ 0xd4be, 0x224d,
+ 0xd4c0, 0x1103,
+ 0xd4c4, 0x224f,
+ 0xd4c5, 0x1108,
+ 0xd4c6, 0x2250,
+ 0xd4c8, 0x110b,
+ 0xd4c9, 0x2252,
+ 0xd4ca, 0x110d,
+ 0xd4cb, 0x2253,
+ 0xd4cf, 0x1112,
+ 0xd4d3, 0x2257,
+ 0xd4d4, 0x1117,
+ 0xd4d8, 0x2258,
+ 0xd4d9, 0x111c,
+ 0xd4dc, 0x2259,
+ 0xd4e1, 0x1124,
+ 0xd4e4, 0x225e,
+ 0xd4e5, 0x1128,
+ 0xd4e6, 0x225f,
+ 0xd4e7, 0x112a,
+ 0xd4ee, 0x2260,
+ 0xd4ef, 0x1132,
+ 0xd4f0, 0x2261,
+ 0xd4f5, 0x1138,
+ 0xd4f9, 0x2266,
+ 0xd4fa, 0x113d,
+ 0xd4fe, 0x2267,
+ 0xd5a1, 0x2268,
+ 0xd5a3, 0x1144,
+ 0xd5a9, 0x226a,
+ 0xd5aa, 0x114b,
+ 0xd5ab, 0x226b,
+ 0xd5ac, 0x114d,
+ 0xd5ae, 0x226c,
+ 0xd5af, 0x1150,
+ 0xd5b1, 0x226d,
+ 0xd5b2, 0x1153,
+ 0xd5b5, 0x226e,
+ 0xd5b9, 0x115a,
+ 0xd5bb, 0x2272,
+ 0xd5bc, 0x115d,
+ 0xd5bd, 0x2273,
+ 0xd5be, 0x115f,
+ 0xd5c0, 0x2274,
+ 0xd5c1, 0x1162,
+ 0xd5c5, 0x2275,
+ 0xd5c6, 0x1167,
+ 0xd5c7, 0x2276,
+ 0xd5c8, 0x1169,
+ 0xd5ca, 0x2277,
+ 0xd5cc, 0x116d,
+ 0xd5cd, 0x2279,
+ 0xd5ce, 0x116f,
+ 0xd5d4, 0x227a,
+ 0xd5d5, 0x1176,
+ 0xd5dd, 0x227b,
+ 0xd5df, 0x1180,
+ 0xd5e0, 0x227d,
+ 0xd5e1, 0x1182,
+ 0xd5e2, 0x227e,
+ 0xd5e3, 0x1184,
+ 0xd5ea, 0x227f,
+ 0xd5ed, 0x118e,
+ 0xd5ef, 0x2282,
+ 0xd5f0, 0x1191,
+ 0xd5f2, 0x2283,
+ 0xd5f4, 0x1195,
+ 0xd5f7, 0x15eb,
+ 0xd5f8, 0x1199,
+ 0xd6a1, 0x2285,
+ 0xd6a5, 0x11a4,
+ 0xd6af, 0x2289,
+ 0xd6b1, 0x11b0,
+ 0xd6b4, 0x228b,
+ 0xd6b5, 0x11b4,
+ 0xd6bb, 0x228c,
+ 0xd6bc, 0x11bb,
+ 0xd6bd, 0x228d,
+ 0xd6be, 0x11bd,
+ 0xd6bf, 0x228e,
+ 0xd6c1, 0x11c0,
+ 0xd6c4, 0x2290,
+ 0xd6c5, 0x11c4,
+ 0xd6ca, 0x2291,
+ 0xd6cb, 0x11ca,
+ 0xd6cd, 0x2292,
+ 0xd6ce, 0x11cd,
+ 0xd6d3, 0x2293,
+ 0xd6d4, 0x11d3,
+ 0xd6d5, 0x2294,
+ 0xd6d8, 0x11d7,
+ 0xd6da, 0x2297,
+ 0xd6db, 0x11da,
+ 0xd6df, 0x2298,
+ 0xd6e0, 0x11df,
+ 0xd6e1, 0x2299,
+ 0xd6e2, 0x11e1,
+ 0xd6e5, 0x229a,
+ 0xd6e6, 0x11e5,
+ 0xd6e7, 0x229b,
+ 0xd6e9, 0x11e8,
+ 0xd6ee, 0x229d,
+ 0xd6f0, 0x11ef,
+ 0xd6f2, 0x229f,
+ 0xd6f3, 0x11f2,
+ 0xd6f5, 0x22a0,
+ 0xd6f7, 0x11f6,
+ 0xd6fc, 0x22a2,
+ 0xd7a1, 0x11fe,
+ 0xd7a4, 0x22a5,
+ 0xd7a5, 0x1202,
+ 0xd7a8, 0x22a6,
+ 0xd7ab, 0x1208,
+ 0xd7ac, 0x22a9,
+ 0xd7ad, 0x120a,
+ 0xd7ae, 0x22aa,
+ 0xd7b2, 0x120f,
+ 0xd7b3, 0x22ae,
+ 0xd7b5, 0x1212,
+ 0xd7b6, 0x22b0,
+ 0xd7b7, 0x1214,
+ 0xd7b8, 0x22b1,
+ 0xd7bd, 0x121a,
+ 0xd7c7, 0x22b6,
+ 0xd7c8, 0x1225,
+ 0xd7ca, 0x22b7,
+ 0xd7cb, 0x1228,
+ 0xd7d5, 0x22b8,
+ 0xd7d6, 0x1233,
+ 0xd7db, 0x22b9,
+ 0xd7df, 0x123c,
+ 0xd7e7, 0x22bd,
+ 0xd7e8, 0x1245,
+ 0xd7e9, 0x22be,
+ 0xd7eb, 0x1248,
+ 0xd8a1, 0x1257,
+ 0xd8c4, 0x22c0,
+ 0xd8c5, 0x127b,
+ 0xd8c7, 0x22c1,
+ 0xd8c8, 0x127e,
+ 0xd8c9, 0x22c2,
+ 0xd8ca, 0x1280,
+ 0xd8cc, 0x22c3,
+ 0xd8ce, 0x1284,
+ 0xd8d0, 0x22c5,
+ 0xd8d2, 0x1288,
+ 0xd8d3, 0x22c7,
+ 0xd8d4, 0x128a,
+ 0xd8d9, 0x22c8,
+ 0xd8da, 0x1290,
+ 0xd8db, 0x22c9,
+ 0xd8dd, 0x1293,
+ 0xd8f1, 0x22cb,
+ 0xd8f2, 0x12a8,
+ 0xd8f6, 0x22cc,
+ 0xd8f8, 0x12ae,
+ 0xd9a1, 0x12b5,
+ 0xd9ad, 0x22ce,
+ 0xd9ae, 0x12c2,
+ 0xd9af, 0x22cf,
+ 0xd9b0, 0x12c4,
+ 0xd9b1, 0x22d0,
+ 0xd9b4, 0x12c8,
+ 0xd9c7, 0x22d3,
+ 0xd9c8, 0x12dc,
+ 0xd9cd, 0x22d4,
+ 0xd9d1, 0x12e5,
+ 0xd9dd, 0x22d8,
+ 0xd9de, 0x12f2,
+ 0xd9e1, 0x22d9,
+ 0xd9e2, 0x12f6,
+ 0xd9e4, 0x22da,
+ 0xd9e5, 0x12f9,
+ 0xd9e6, 0x22db,
+ 0xd9e7, 0x12fb,
+ 0xd9ec, 0x22dc,
+ 0xd9ed, 0x1301,
+ 0xd9f4, 0x22dd,
+ 0xd9f6, 0x130a,
+ 0xdaa1, 0x1313,
+ 0xdaa5, 0x22df,
+ 0xdae0, 0x1352,
+ 0xdaea, 0x231a,
+ 0xdaeb, 0x135d,
+ 0xdaf7, 0x231b,
+ 0xdaf8, 0x136a,
+ 0xdaf9, 0x231c,
+ 0xdafa, 0x136c,
+ 0xdafe, 0x231d,
+ 0xdba1, 0x1371,
+ 0xdba3, 0x231e,
+ 0xdba4, 0x1374,
+ 0xdba6, 0x231f,
+ 0xdba7, 0x1377,
+ 0xdba9, 0x2320,
+ 0xdbab, 0x137b,
+ 0xdbbb, 0x2322,
+ 0xdbbc, 0x138c,
+ 0xdbbd, 0x2323,
+ 0xdbbe, 0x138e,
+ 0xdbcf, 0x2324,
+ 0xdbd0, 0x13a0,
+ 0xdbd1, 0x2325,
+ 0xdbd2, 0x13a2,
+ 0xdbdb, 0x2326,
+ 0xdbdc, 0x13ac,
+ 0xdbde, 0x2327,
+ 0xdbdf, 0x13af,
+ 0xdbe2, 0x2328,
+ 0xdbe3, 0x13b3,
+ 0xdbe4, 0x2329,
+ 0xdbe5, 0x13b5,
+ 0xdbeb, 0x232a,
+ 0xdbec, 0x13bc,
+ 0xdbee, 0x232b,
+ 0xdbef, 0x13bf,
+ 0xdbf1, 0x232c,
+ 0xdbf2, 0x13c2,
+ 0xdbf5, 0x232d,
+ 0xdbf8, 0x13c8,
+ 0xdca1, 0x13cf,
+ 0xdcbc, 0x2330,
+ 0xdcbd, 0x13eb,
+ 0xdcbf, 0x2331,
+ 0xdcc0, 0x13ee,
+ 0xdcc2, 0x2332,
+ 0xdcc3, 0x13f1,
+ 0xdcc8, 0x2333,
+ 0xdccb, 0x13f9,
+ 0xdcd1, 0x2336,
+ 0xdcd2, 0x1400,
+ 0xdcd7, 0x2337,
+ 0xdcd8, 0x1406,
+ 0xdce0, 0x2338,
+ 0xdce1, 0x140f,
+ 0xdce3, 0x2339,
+ 0xdce5, 0x1413,
+ 0xdce9, 0x233b,
+ 0xdceb, 0x1419,
+ 0xdcf1, 0x233d,
+ 0xdcf2, 0x1420,
+ 0xdcf6, 0x233e,
+ 0xdcf7, 0x1425,
+ 0xdcf9, 0x233f,
+ 0xdcfa, 0x1428,
+ 0xdcfd, 0x2340,
+ 0xdda1, 0x2342,
+ 0xdda2, 0x142e,
+ 0xdda3, 0x2343,
+ 0xdda8, 0x1434,
+ 0xddaa, 0x2348,
+ 0xddac, 0x1438,
+ 0xddb2, 0x234a,
+ 0xddb3, 0x143f,
+ 0xddb5, 0x234b,
+ 0xddb6, 0x1442,
+ 0xddba, 0x234c,
+ 0xddbc, 0x1448,
+ 0xddd3, 0x234e,
+ 0xddd4, 0x1460,
+ 0xdddb, 0x234f,
+ 0xdddc, 0x1468,
+ 0xddde, 0x2350,
+ 0xdddf, 0x146b,
+ 0xdde4, 0x2351,
+ 0xdde5, 0x1471,
+ 0xddeb, 0x2352,
+ 0xddec, 0x1478,
+ 0xddf1, 0x2353,
+ 0xddf2, 0x147e,
+ 0xddf6, 0x2354,
+ 0xddf8, 0x1484,
+ 0xddfc, 0x2356,
+ 0xddfd, 0x1489,
+ 0xddfe, 0x2357,
+ 0xdea1, 0x148b,
+ 0xdead, 0x2358,
+ 0xdeae, 0x1498,
+ 0xdeb4, 0x2359,
+ 0xdeb5, 0x149f,
+ 0xdeba, 0x235a,
+ 0xdebb, 0x14a5,
+ 0xdec6, 0x235b,
+ 0xdec7, 0x14b1,
+ 0xdecf, 0x235c,
+ 0xded0, 0x14ba,
+ 0xded1, 0x235d,
+ 0xded3, 0x14bd,
+ 0xded8, 0x235f,
+ 0xded9, 0x14c3,
+ 0xdee2, 0x2360,
+ 0xdee3, 0x14cd,
+ 0xdee8, 0x2361,
+ 0xdee9, 0x14d3,
+ 0xdeec, 0x2362,
+ 0xdeed, 0x14d7,
+ 0xdef3, 0x2363,
+ 0xdef4, 0x14de,
+ 0xdefc, 0x2364,
+ 0xdefd, 0x14e7,
+ 0xdfa1, 0x14e9,
+ 0xdfa2, 0x2365,
+ 0xdfa4, 0x14ec,
+ 0xdfa5, 0x2367,
+ 0xdfa6, 0x14ee,
+ 0xdfb4, 0x2368,
+ 0xdfb5, 0x14fd,
+ 0xdfbc, 0x2369,
+ 0xdfbe, 0x1506,
+ 0xdfbf, 0x236b,
+ 0xdfc0, 0x1508,
+ 0xdfc2, 0x236c,
+ 0xdfc4, 0x150c,
+ 0xdfcc, 0x236e,
+ 0xdfcd, 0x1515,
+ 0xdfd0, 0x236f,
+ 0xdfd1, 0x1519,
+ 0xdfd5, 0x2370,
+ 0xdfd6, 0x151e,
+ 0xdfd8, 0x2371,
+ 0xdfda, 0x1522,
+ 0xdfdc, 0x2373,
+ 0xdfdd, 0x1525,
+ 0xdfe0, 0x2374,
+ 0xdfe1, 0x1529,
+ 0xdfe2, 0x2375,
+ 0xdfe3, 0x152b,
+ 0xdfe6, 0x2376,
+ 0xdfe7, 0x152f,
+ 0xdfe9, 0x2377,
+ 0xdfea, 0x1532,
+ 0xdfeb, 0x2378,
+ 0xdfec, 0x1534,
+ 0xdfef, 0x2379,
+ 0xdff0, 0x1538,
+ 0xdff5, 0x237a,
+ 0xdff6, 0x153e,
+ 0xdff9, 0x237b,
+ 0xdffa, 0x1542,
+ 0xe0a1, 0x1547,
+ 0xe0b6, 0x237c,
+ 0xe0b8, 0x155e,
+ 0xe0bf, 0x237e,
+ 0xe0c0, 0x1566,
+ 0xe0c8, 0x237f,
+ 0xe0c9, 0x156f,
+ 0xe0ce, 0x2380,
+ 0xe0cf, 0x1575,
+ 0xe0d3, 0x2381,
+ 0xe0d4, 0x157a,
+ 0xe0e0, 0x2382,
+ 0xe0e1, 0x1587,
+ 0xe0f0, 0x2383,
+ 0xe0f1, 0x1597,
+ 0xe0f8, 0x2384,
+ 0xe0f9, 0x159f,
+ 0xe0fc, 0x2385,
+ 0xe1a1, 0x15a5,
+ 0xe1ab, 0x2388,
+ 0xe1ac, 0x15b0,
+ 0xe1ad, 0x2389,
+ 0xe1ae, 0x15b2,
+ 0xe1b0, 0x238a,
+ 0xe1b1, 0x15b5,
+ 0xe1b4, 0x238b,
+ 0xe1b5, 0x15b9,
+ 0xe1bb, 0x238c,
+ 0xe1bc, 0x15c0,
+ 0xe1bd, 0x238d,
+ 0xe1be, 0x15c2,
+ 0xe1c0, 0x238e,
+ 0xe1c2, 0x15c6,
+ 0xe1c9, 0x2390,
+ 0xe1ca, 0x15ce,
+ 0xe1d0, 0x2391,
+ 0xe1d1, 0x15d5,
+ 0xe1db, 0x2392,
+ 0xe1dc, 0x15e0,
+ 0xe1e1, 0x07aa,
+ 0xe1e2, 0x2393,
+ 0xe1e3, 0x15e7,
+ 0xe1e7, 0x1198,
+ 0xe1e8, 0x15ec,
+ 0xe1ee, 0x2394,
+ 0xe1f0, 0x15f4,
+ 0xe1f6, 0x2396,
+ 0xe1f7, 0x15fb,
+ 0xe1f8, 0x2397,
+ 0xe1f9, 0x15fd,
+ 0xe1fd, 0x2398,
+ 0xe1fe, 0x1602,
+ 0xe2a1, 0x1603,
+ 0xe2a4, 0x2399,
+ 0xe2a5, 0x1607,
+ 0xe2a8, 0x239a,
+ 0xe2a9, 0x160b,
+ 0xe2bb, 0x239b,
+ 0xe2c5, 0x10c5,
+ 0xe2c6, 0x23a5,
+ 0xe2cf, 0x1631,
+ 0xe2d0, 0x23ae,
+ 0xe2d1, 0x1633,
+ 0xe2d9, 0x23af,
+ 0xe2da, 0x163c,
+ 0xe2e3, 0x23b0,
+ 0xe2e5, 0x1647,
+ 0xe2e6, 0x23b2,
+ 0xe2e7, 0x1649,
+ 0xe2e9, 0x23b3,
+ 0xe2ec, 0x164e,
+ 0xe2f8, 0x23b6,
+ 0xe2f9, 0x165b,
+ 0xe2fa, 0x23b7,
+ 0xe2fe, 0x1660,
+ 0xe3a1, 0x1661,
+ 0xe3a2, 0x23bb,
+ 0xe3a3, 0x1663,
+ 0xe3a5, 0x23bc,
+ 0xe3a6, 0x1666,
+ 0xe3ab, 0x23bd,
+ 0xe3ac, 0x166c,
+ 0xe3b4, 0x23be,
+ 0xe3b5, 0x1675,
+ 0xe3c5, 0x23bf,
+ 0xe3dc, 0x169c,
+ 0xe3e3, 0x23d6,
+ 0xe3e4, 0x16a4,
+ 0xe3ed, 0x23d7,
+ 0xe3ee, 0x16ae,
+ 0xe3f1, 0x23d8,
+ 0xe3f3, 0x16b3,
+ 0xe3f8, 0x23da,
+ 0xe3f9, 0x16b9,
+ 0xe3fe, 0x23db,
+ 0xe4a1, 0x16bf,
+ 0xe4a4, 0x23dc,
+ 0xe4a6, 0x16c4,
+ 0xe4ab, 0x23de,
+ 0xe4ac, 0x16ca,
+ 0xe4af, 0x23df,
+ 0xe4b2, 0x16d0,
+ 0xe4b5, 0x23e2,
+ 0xe4b7, 0x16d5,
+ 0xe4c2, 0x23e4,
+ 0xe4c3, 0x16e1,
+ 0xe4c5, 0x23e5,
+ 0xe4c6, 0x16e4,
+ 0xe4c9, 0x23e6,
+ 0xe4ca, 0x16e8,
+ 0xe4d9, 0x23e7,
+ 0xe4da, 0x16f8,
+ 0xe4dc, 0x23e8,
+ 0xe4dd, 0x16fb,
+ 0xe4de, 0x23e9,
+ 0xe4df, 0x16fd,
+ 0xe4e4, 0x23ea,
+ 0xe4e5, 0x1703,
+ 0xe4eb, 0x23eb,
+ 0xe4ed, 0x170b,
+ 0xe4f2, 0x23ed,
+ 0xe4f3, 0x1711,
+ 0xe4fe, 0x23ee,
+ 0xe5a1, 0x171d,
+ 0xe5b0, 0x23ef,
+ 0xe5b1, 0x172d,
+ 0xe5b9, 0x23f0,
+ 0xe5ba, 0x1736,
+ 0xe5c7, 0x23f1,
+ 0xe5c8, 0x1744,
+ 0xe5c9, 0x23f2,
+ 0xe5ca, 0x1746,
+ 0xe5ce, 0x23f3,
+ 0xe5cf, 0x174b,
+ 0xe5f0, 0x23f4,
+ 0xe5f1, 0x176d,
+ 0xe5f2, 0x23f5,
+ 0xe5f3, 0x176f,
+ 0xe5fc, 0x23f6,
+ 0xe5fe, 0x177a,
+ 0xe6a1, 0x177b,
+ 0xe6a3, 0x23f8,
+ 0xe6a4, 0x177e,
+ 0xe6ab, 0x23f9,
+ 0xe6ad, 0x1787,
+ 0xe6ae, 0x23fb,
+ 0xe6af, 0x1789,
+ 0xe6b4, 0x23fc,
+ 0xe6b6, 0x1790,
+ 0xe6bf, 0x23fe,
+ 0xe6c0, 0x179a,
+ 0xe6c8, 0x23ff,
+ 0xe6ca, 0x17a4,
+ 0xe6cd, 0x2401,
+ 0xe6ce, 0x17a8,
+ 0xe6e0, 0x2402,
+ 0xe7a1, 0x2421,
+ 0xe7db, 0x1813,
+ 0xe7e1, 0x245b,
+ 0xe7e3, 0x181b,
+ 0xe7e7, 0x245d,
+ 0xe7e8, 0x1820,
+ 0xe7ef, 0x245e,
+ 0xe7f0, 0x1828,
+ 0xe7f4, 0x245f,
+ 0xe7f7, 0x182f,
+ 0xe8a1, 0x1837,
+ 0xe8a8, 0x2462,
+ 0xe8a9, 0x183f,
+ 0xe8ac, 0x2463,
+ 0xe8ad, 0x1843,
+ 0xe8b6, 0x2464,
+ 0xe8b7, 0x184d,
+ 0xe8b8, 0x2465,
+ 0xe8bb, 0x1851,
+ 0xe8bf, 0x2468,
+ 0xe8c1, 0x1857,
+ 0xe8c5, 0x246a,
+ 0xe8c6, 0x185c,
+ 0xe8c7, 0x246b,
+ 0xe8ca, 0x1860,
+ 0xe8ce, 0x246e,
+ 0xe8cf, 0x1865,
+ 0xe8d0, 0x246f,
+ 0xe8d1, 0x1867,
+ 0xe8d3, 0x2470,
+ 0xe8d4, 0x186a,
+ 0xe8dd, 0x2471,
+ 0xe8de, 0x1874,
+ 0xe8df, 0x2472,
+ 0xe8e0, 0x1876,
+ 0xe8e2, 0x2473,
+ 0xe8e4, 0x187a,
+ 0xe8e5, 0x2475,
+ 0xe8e6, 0x187c,
+ 0xe8e7, 0x2476,
+ 0xe8e8, 0x187e,
+ 0xe8eb, 0x2477,
+ 0xe8ec, 0x1882,
+ 0xe8ed, 0x2478,
+ 0xe8ee, 0x1884,
+ 0xe8ef, 0x2479,
+ 0xe8f0, 0x1886,
+ 0xe8f9, 0x247a,
+ 0xe8fa, 0x1890,
+ 0xe8fc, 0x247b,
+ 0xe8fe, 0x1894,
+ 0xe9a1, 0x247d,
+ 0xe9a2, 0x1896,
+ 0xe9ad, 0x247e,
+ 0xe9ae, 0x18a2,
+ 0xe9b4, 0x247f,
+ 0xe9b6, 0x18aa,
+ 0xe9b7, 0x2481,
+ 0xe9b8, 0x18ac,
+ 0xe9c4, 0x2482,
+ 0xe9c5, 0x18b9,
+ 0xe9c6, 0x2483,
+ 0xe9c7, 0x18bb,
+ 0xe9c9, 0x2484,
+ 0xe9ca, 0x18be,
+ 0xe9d6, 0x2485,
+ 0xe9d7, 0x18cb,
+ 0xe9da, 0x2486,
+ 0xe9db, 0x18cf,
+ 0xe9e4, 0x2487,
+ 0xe9e5, 0x18d9,
+ 0xe9e6, 0x2488,
+ 0xe9e8, 0x18dc,
+ 0xe9e9, 0x248a,
+ 0xe9ea, 0x18de,
+ 0xe9eb, 0x248b,
+ 0xe9ec, 0x18e0,
+ 0xe9ed, 0x248c,
+ 0xeaa1, 0x249e,
+ 0xeaa6, 0x18f8,
+ 0xeaa7, 0x24a3,
+ 0xeaa9, 0x18fb,
+ 0xeab1, 0x24a5,
+ 0xeab2, 0x1904,
+ 0xeabc, 0x24a6,
+ 0xeabd, 0x190f,
+ 0xeaca, 0x24a7,
+ 0xeacb, 0x191d,
+ 0xeacd, 0x24a8,
+ 0xeace, 0x1920,
+ 0xead3, 0x24a9,
+ 0xead4, 0x1926,
+ 0xeada, 0x24aa,
+ 0xeaf0, 0x1942,
+ 0xeba1, 0x1951,
+ 0xeba7, 0x24c0,
+ 0xeba8, 0x1958,
+ 0xebaa, 0x24c1,
+ 0xebab, 0x195b,
+ 0xebb2, 0x24c2,
+ 0xebb3, 0x1963,
+ 0xebb9, 0x24c3,
+ 0xebba, 0x196a,
+ 0xebca, 0x24c4,
+ 0xebcc, 0x197c,
+ 0xebcd, 0x24c6,
+ 0xebce, 0x197e,
+ 0xebd6, 0x24c7,
+ 0xebd7, 0x1987,
+ 0xebda, 0x24c8,
+ 0xebdb, 0x198b,
+ 0xebe1, 0x24c9,
+ 0xebe2, 0x1992,
+ 0xebf7, 0x24ca,
+ 0xebf8, 0x19a8,
+ 0xeca1, 0x19af,
+ 0xeca3, 0x24cb,
+ 0xeca4, 0x19b2,
+ 0xeca9, 0x24cc,
+ 0xecaf, 0x19bd,
+ 0xecb1, 0x24d2,
+ 0xecb2, 0x19c0,
+ 0xecb4, 0x24d3,
+ 0xecb6, 0x19c4,
+ 0xecbe, 0x24d5,
+ 0xecc0, 0x19ce,
+ 0xecc1, 0x24d7,
+ 0xecc2, 0x19d0,
+ 0xecc7, 0x24d8,
+ 0xecc8, 0x19d6,
+ 0xeccb, 0x24d9,
+ 0xeccc, 0x19da,
+ 0xece2, 0x24da,
+ 0xece3, 0x19f1,
+ 0xecf2, 0x24db,
+ 0xecf3, 0x1a01,
+ 0xecf5, 0x24dc,
+ 0xecf6, 0x1a04,
+ 0xecf8, 0x24dd,
+ 0xecf9, 0x1a07,
+ 0xeda1, 0x24de,
+ 0xeda2, 0x1a0e,
+ 0xeda8, 0x24df,
+ 0xeda9, 0x1a15,
+ 0xedaf, 0x24e0,
+ 0xedb1, 0x1a1d,
+ 0xedb4, 0x24e2,
+ 0xedb5, 0x1a21,
+ 0xedb6, 0x24e3,
+ 0xedb7, 0x1a23,
+ 0xedb8, 0x24e4,
+ 0xedb9, 0x1a25,
+ 0xedba, 0x24e5,
+ 0xedbb, 0x1a27,
+ 0xedbf, 0x24e6,
+ 0xedc0, 0x1a2c,
+ 0xedc2, 0x24e7,
+ 0xedc4, 0x1a30,
+ 0xedcc, 0x24e9,
+ 0xedce, 0x1a3a,
+ 0xedd3, 0x24eb,
+ 0xedd4, 0x1a40,
+ 0xedd7, 0x24ec,
+ 0xedd8, 0x1a44,
+ 0xede8, 0x24ed,
+ 0xede9, 0x1a55,
+ 0xedee, 0x24ee,
+ 0xedef, 0x1a5b,
+ 0xedf9, 0x24ef,
+ 0xedfb, 0x1a67,
+ 0xeea1, 0x1a6b,
+ 0xeebc, 0x24f1,
+ 0xeebd, 0x1a87,
+ 0xeebf, 0x24f2,
+ 0xeec0, 0x1a8a,
+ 0xeec4, 0x24f3,
+ 0xefa1, 0x252e,
+ 0xeff2, 0x1b1a,
+ 0xf0a1, 0x1b27,
+ 0xf0a3, 0x257f,
+ 0xf0a4, 0x1b2a,
+ 0xf0af, 0x2580,
+ 0xf0da, 0x1b60,
+ 0xf0dc, 0x25ab,
+ 0xf0de, 0x1b64,
+ 0xf0df, 0x25ad,
+ 0xf0e0, 0x1b66,
+ 0xf0e9, 0x25ae,
+ 0xf0ea, 0x1b70,
+ 0xf0ec, 0x25af,
+ 0xf0ed, 0x1b73,
+ 0xf0ef, 0x25b0,
+ 0xf0f0, 0x1b76,
+ 0xf0f7, 0x25b1,
+ 0xf0f8, 0x1b7e,
+ 0xf0f9, 0x25b2,
+ 0xf0fa, 0x1b80,
+ 0xf0fc, 0x25b3,
+ 0xf0fd, 0x1b83,
+ 0xf1a1, 0x1b85,
+ 0xf1a8, 0x25b4,
+ 0xf1a9, 0x1b8d,
+ 0xf1ab, 0x25b5,
+ 0xf1ac, 0x1b90,
+ 0xf1ae, 0x25b6,
+ 0xf1af, 0x1b93,
+ 0xf1b2, 0x25b7,
+ 0xf1b3, 0x1b97,
+ 0xf1bc, 0x25b8,
+ 0xf1bd, 0x1ba1,
+ 0xf1c0, 0x25b9,
+ 0xf1c1, 0x1ba5,
+ 0xf1c9, 0x25ba,
+ 0xf1ca, 0x1bae,
+ 0xf1cd, 0x25bb,
+ 0xf1ce, 0x1bb2,
+ 0xf1cf, 0x25bc,
+ 0xf1d1, 0x1bb5,
+ 0xf1da, 0x25be,
+ 0xf1db, 0x1bbf,
+ 0xf1dc, 0x25bf,
+ 0xf1dd, 0x1bc1,
+ 0xf1e4, 0x25c0,
+ 0xf1e5, 0x1bc9,
+ 0xf1ec, 0x25c1,
+ 0xf1ed, 0x1bd1,
+ 0xf1ef, 0x25c2,
+ 0xf1f0, 0x1bd4,
+ 0xf1f7, 0x25c3,
+ 0xf1f8, 0x1bdc,
+ 0xf1f9, 0x25c4,
+ 0xf1fa, 0x1bde,
+ 0xf1fc, 0x25c5,
+ 0xf2a1, 0x25c8,
+ 0xf2ae, 0x1bf0,
+ 0xf2b1, 0x25d5,
+ 0xf2b3, 0x1bf5,
+ 0xf2b9, 0x25d7,
+ 0xf2ba, 0x1bfc,
+ 0xf2c3, 0x25d8,
+ 0xf2c4, 0x1c06,
+ 0xf2c9, 0x25d9,
+ 0xf2ca, 0x1c0c,
+ 0xf2cc, 0x25da,
+ 0xf2ce, 0x1c10,
+ 0xf2cf, 0x25dc,
+ 0xf2d0, 0x1c12,
+ 0xf2d3, 0x25dd,
+ 0xf2d4, 0x1c16,
+ 0xf2e5, 0x25de,
+ 0xf2e6, 0x1c28,
+ 0xf2ee, 0x25df,
+ 0xf2ef, 0x1c31,
+ 0xf2f7, 0x25e0,
+ 0xf2f8, 0x1c3a,
+ 0xf2fd, 0x25e1,
+ 0xf2fe, 0x1c40,
+ 0xf3a1, 0x1c41,
+ 0xf3bf, 0x25e2,
+ 0xf3c0, 0x1c60,
+ 0xf3c6, 0x25e3,
+ 0xf3c7, 0x1c67,
+ 0xf3c8, 0x25e4,
+ 0xf3c9, 0x1c69,
+ 0xf3d6, 0x25e5,
+ 0xf3d7, 0x1c77,
+ 0xf3d9, 0x25e6,
+ 0xf3da, 0x1c7a,
+ 0xf3e5, 0x25e7,
+ 0xf3e7, 0x1c87,
+ 0xf3ea, 0x25e9,
+ 0xf3eb, 0x1c8b,
+ 0xf3ec, 0x25ea,
+ 0xf3ed, 0x1c8d,
+ 0xf3ef, 0x25eb,
+ 0xf3f0, 0x1c90,
+ 0xf3f1, 0x25ec,
+ 0xf3f2, 0x1c92,
+ 0xf3fd, 0x25ed,
+ 0xf3fe, 0x1c9e,
+ 0xf4a1, 0x1c9f,
+ 0xf4a5, 0x25ee,
+ 0xf4a6, 0x1ca4,
+ 0xf4af, 0x25ef,
+ 0xf4b0, 0x1cae,
+ 0xf4b5, 0x25f0,
+ 0xf4b6, 0x1cb4,
+ 0xf4c1, 0x25f1,
+ 0xf4c2, 0x1cc0,
+ 0xf4c7, 0x25f2,
+ 0xf4c8, 0x1cc6,
+ 0xf4cf, 0x25f3,
+ 0xf4d1, 0x1ccf,
+ 0xf4d6, 0x25f5,
+ 0xf4d7, 0x1cd5,
+ 0xf4ea, 0x25f6,
+ 0xf4eb, 0x1ce9,
+ 0xf4ef, 0x25f7,
+ 0xf4f0, 0x1cee,
+ 0xf4f5, 0x25f8,
+ 0xf4f6, 0x1cf4,
+ 0xf5a1, 0x1cfd,
+ 0xf5a6, 0x25f9,
+ 0xf5a8, 0x1d04,
+ 0xf5ba, 0x25fb,
+ 0xf5bc, 0x1d18,
+ 0xf5c4, 0x25fd,
+ 0xf5c5, 0x1d21,
+ 0xf5c8, 0x25fe,
+ 0xf5c9, 0x1d25,
+ 0xf5ce, 0x25ff,
+ 0xf5d0, 0x1d2c,
+ 0xf5d1, 0x2601,
+ 0xf5d3, 0x1d2f,
+ 0xf5d9, 0x2603,
+ 0xf5da, 0x1d36,
+ 0xf5dc, 0x2604,
+ 0xf5dd, 0x1d39,
+ 0xf5e6, 0x2605,
+ 0xf5e8, 0x1d44,
+ 0xf5ef, 0x2607,
+ 0xf5f0, 0x1d4c,
+ 0xf5f2, 0x2608,
+ 0xf5f3, 0x1d4f,
+ 0xf5fc, 0x2609,
+ 0xf5fd, 0x1d59,
+ 0xf6a1, 0x1d5b,
+ 0xf6a3, 0x260a,
+ 0xf6a4, 0x1d5e,
+ 0xf6a6, 0x260b,
+ 0xf6a7, 0x1d61,
+ 0xf6a8, 0x260c,
+ 0xf6a9, 0x1d63,
+ 0xf6ab, 0x260d,
+ 0xf6ac, 0x1d66,
+ 0xf6b0, 0x260e,
+ 0xf6b1, 0x1d6b,
+ 0xf6b3, 0x260f,
+ 0xf6bf, 0x1d79,
+ 0xf6c5, 0x261b,
+ 0xf6c6, 0x1d80,
+ 0xf6c7, 0x261c,
+ 0xf6c8, 0x1d82,
+ 0xf6c9, 0x261d,
+ 0xf6ca, 0x1d84,
+ 0xf6cf, 0x261e,
+ 0xf7a1, 0x264e,
+ 0xf7b0, 0x1dc8,
+ 0xf7b2, 0x265d,
+ 0xf7b4, 0x1dcc,
+ 0xf7b5, 0x265f,
+ 0xf7b6, 0x1dce,
+ 0xf7bd, 0x2660,
+ 0xf7be, 0x1dd6,
+ 0xf7c3, 0x2661,
+ 0xf7c4, 0x1ddc,
+ 0xf7c5, 0x2662,
+ 0xf7c7, 0x1ddf,
+ 0xf7ca, 0x2664,
+ 0xf7cc, 0x1de4,
+ 0xf7cf, 0x2666,
+ 0xf7d1, 0x1de9,
+ 0xf7de, 0x2668,
+ 0xf7df, 0x1df7,
+ 0xf7e1, 0x0ab9,
+ 0xf7e2, 0x1dfa,
+ 0xf7f2, 0x2669,
+ 0xf7f3, 0x1e0b,
+ 0xf7f5, 0x266a,
+ 0xf7f6, 0x1e0e,
+ 0xf8a1, 0x266b,
+ 0xf8a7, 0x04cc,
+ 0xf8a8, 0x050a,
+ 0xf8a9, 0x0518,
+ 0xf8aa, 0x2671,
+ 0xf8ac, 0x0594,
+ 0xf8ad, 0x05ce,
+ 0xf8ae, 0x2673,
+ 0xf8af, 0x05f6,
+ 0xf8b0, 0x2674,
+ 0xf8b2, 0x0653,
+ 0xf8b3, 0x067e,
+ 0xf8b4, 0x2676,
+ 0xf8b5, 0x06c4,
+ 0xf8b6, 0x2677,
+ 0xf8b8, 0x073c,
+ 0xf8b9, 0x2679,
+ 0xf8bb, 0x07c3,
+ 0xf8bc, 0x267b,
+ 0xf8c0, 0x082b,
+ 0xf8c1, 0x267f,
+ 0xf8c2, 0x084e,
+ 0xf8c3, 0x0869,
+ 0xf8c4, 0x2680,
+ 0xf8c6, 0x090c,
+ 0xf8c7, 0x2682,
+ 0xf8c9, 0x0971,
+ 0xf8ca, 0x2684,
+ 0xf8cb, 0x099a,
+ 0xf8cd, 0x2685,
+ 0xf8ce, 0x09da,
+ 0xf8cf, 0x2686,
+ 0xf8d0, 0x09fa,
+ 0xf8d1, 0x2687,
+ 0xf8dc, 0x0bda,
+ 0xf8dd, 0x0bdd,
+ 0xf8de, 0x0bea,
+ 0xf8df, 0x0bec,
+ 0xf8e0, 0x0bf2,
+ 0xf8e1, 0x2692,
+ 0xf8e6, 0x0c92,
+ 0xf8e7, 0x0d1a,
+ 0xf8e8, 0x0d8c,
+ 0xf8e9, 0x0dbe,
+ 0xf8ea, 0x2697,
+ 0xf8eb, 0x0dfb,
+ 0xf8ec, 0x2698,
+ 0xf8ef, 0x0e70,
+ 0xf8f0, 0x269b,
+ 0xf8f1, 0x0ea3,
+ 0xf8f2, 0x269c,
+ 0xf8f8, 0x103d,
+ 0xf8f9, 0x10d9,
+ 0xf8fa, 0x26a2,
+ 0xf8fc, 0x10fb,
+ 0xf8fd, 0x1109,
+ 0xf8fe, 0x26a4,
+ 0xf9a1, 0x11a1,
+ 0xf9a2, 0x26a5,
+ 0xf9a3, 0x11ba,
+ 0xf9a4, 0x26a6,
+ 0xf9a6, 0x11d5,
+ 0xf9a7, 0x26a8,
+ 0xf9a8, 0x11fd,
+ 0xf9a9, 0x1219,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 gb12GBTEUCHEnc16 = {
+ 0,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x1e24, 0x032e, 0x032f, 0x0330, 0x0331, 0x0332, 0x0333, 0x0334,
+ 0x0335, 0x0336, 0x0337, 0x0338, 0x0339, 0x033a, 0x033b, 0x033c,
+ 0x033d, 0x033e, 0x033f, 0x0340, 0x0341, 0x0342, 0x0343, 0x0344,
+ 0x0345, 0x0346, 0x0347, 0x0348, 0x0349, 0x034a, 0x034b, 0x034c,
+ 0x034d, 0x034e, 0x034f, 0x0350, 0x0351, 0x0352, 0x0353, 0x0354,
+ 0x0355, 0x0356, 0x0357, 0x0358, 0x0359, 0x035a, 0x035b, 0x035c,
+ 0x035d, 0x035e, 0x035f, 0x0360, 0x0361, 0x0362, 0x0363, 0x0364,
+ 0x0365, 0x0366, 0x0367, 0x0368, 0x0369, 0x036a, 0x036b, 0x036c,
+ 0x036d, 0x036e, 0x036f, 0x0370, 0x0371, 0x0372, 0x0373, 0x0374,
+ 0x0375, 0x0376, 0x0377, 0x0378, 0x0379, 0x037a, 0x037b, 0x037c,
+ 0x037d, 0x037e, 0x037f, 0x0380, 0x0381, 0x0382, 0x0383, 0x0384,
+ 0x0385, 0x0386, 0x0387, 0x0388, 0x0389, 0x038a, 0x038b, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ gb12GBTEUCHMap2, 2283
+};
+
+static Gushort gb12GBTEUCVMap2[4606] = {
+ 0x0000, 0x0000,
+ 0xa1a1, 0x0060,
+ 0xa2b1, 0x00be,
+ 0xa2e5, 0x00f0,
+ 0xa2f1, 0x00fa,
+ 0xa3a1, 0x0106,
+ 0xa4a1, 0x0164,
+ 0xa5a1, 0x01b7,
+ 0xa6a1, 0x020d,
+ 0xa6c1, 0x0225,
+ 0xa7a1, 0x025a,
+ 0xa7d1, 0x027b,
+ 0xa8a1, 0x029c,
+ 0xa8c5, 0x02bc,
+ 0xa9a4, 0x02e2,
+ 0xaaa1, 0x032e,
+ 0xaba1, 0x038c,
+ 0xb0a1, 0x03ac,
+ 0xb0a8, 0x1e25,
+ 0xb0a9, 0x03b4,
+ 0xb0aa, 0x1e26,
+ 0xb0ab, 0x03b6,
+ 0xb0ad, 0x1e27,
+ 0xb0af, 0x03ba,
+ 0xb0b9, 0x1e29,
+ 0xb0ba, 0x03c5,
+ 0xb0c0, 0x1e2a,
+ 0xb0c1, 0x03cc,
+ 0xb0d3, 0x1e2b,
+ 0xb0d4, 0x03df,
+ 0xb0d5, 0x1e2c,
+ 0xb0d6, 0x03e1,
+ 0xb0da, 0x1e2d,
+ 0xb0db, 0x03e6,
+ 0xb0dc, 0x1e2e,
+ 0xb0dd, 0x03e8,
+ 0xb0e4, 0x1e2f,
+ 0xb0e5, 0x03f0,
+ 0xb0ec, 0x1e30,
+ 0xb0ee, 0x03f9,
+ 0xb0ef, 0x1e32,
+ 0xb0f0, 0x03fb,
+ 0xb0f3, 0x1e33,
+ 0xb0f4, 0x03ff,
+ 0xb0f7, 0x1e34,
+ 0xb0f8, 0x0403,
+ 0xb0f9, 0x1e35,
+ 0xb0fa, 0x0405,
+ 0xb1a1, 0x040a,
+ 0xb1a5, 0x1e36,
+ 0xb1a7, 0x0410,
+ 0xb1a8, 0x1e38,
+ 0xb1a9, 0x0412,
+ 0xb1ab, 0x1e39,
+ 0xb1ac, 0x0415,
+ 0xb1b2, 0x1e3a,
+ 0xb1b3, 0x041c,
+ 0xb1b4, 0x1e3b,
+ 0xb1b6, 0x041f,
+ 0xb1b7, 0x1e3d,
+ 0xb1ba, 0x0423,
+ 0xb1c1, 0x1e40,
+ 0xb1c2, 0x042b,
+ 0xb1ca, 0x1e41,
+ 0xb1cb, 0x0434,
+ 0xb1cf, 0x1e42,
+ 0xb1d1, 0x043a,
+ 0xb1d2, 0x1e44,
+ 0xb1d3, 0x043c,
+ 0xb1d5, 0x1e45,
+ 0xb1d6, 0x043f,
+ 0xb1df, 0x1e46,
+ 0xb1e2, 0x044b,
+ 0xb1e4, 0x1e49,
+ 0xb1e5, 0x044e,
+ 0xb1e7, 0x1e4a,
+ 0xb1e9, 0x0452,
+ 0xb1ea, 0x1e4c,
+ 0xb1eb, 0x0454,
+ 0xb1ee, 0x1e4d,
+ 0xb1ef, 0x0458,
+ 0xb1f1, 0x1e4e,
+ 0xb1f2, 0x045b,
+ 0xb1f4, 0x1e4f,
+ 0xb1f8, 0x0461,
+ 0xb1fd, 0x1e53,
+ 0xb1fe, 0x0467,
+ 0xb2a1, 0x0468,
+ 0xb2a6, 0x1e54,
+ 0xb2a8, 0x046f,
+ 0xb2ac, 0x1e56,
+ 0xb2ad, 0x0474,
+ 0xb2b5, 0x1e57,
+ 0xb2b6, 0x047d,
+ 0xb2b9, 0x1e58,
+ 0xb2ba, 0x0481,
+ 0xb2c6, 0x1e59,
+ 0xb2c7, 0x048e,
+ 0xb2ce, 0x1e5a,
+ 0xb2d8, 0x049f,
+ 0xb2de, 0x1e64,
+ 0xb2df, 0x04a6,
+ 0xb2e0, 0x1e65,
+ 0xb2e1, 0x04a8,
+ 0xb2e2, 0x1e66,
+ 0xb2e4, 0x04ab,
+ 0xb2ef, 0x1e68,
+ 0xb2f0, 0x04b7,
+ 0xb2f3, 0x1e69,
+ 0xb2fd, 0x04c4,
+ 0xb3a1, 0x1e73,
+ 0xb3a3, 0x04c8,
+ 0xb3a4, 0x1e75,
+ 0xb3a8, 0x04cd,
+ 0xb3a9, 0x1e79,
+ 0xb3aa, 0x04cf,
+ 0xb3ae, 0x1e7a,
+ 0xb3af, 0x04d4,
+ 0xb3b5, 0x1e7b,
+ 0xb3b6, 0x04db,
+ 0xb3b9, 0x1e7c,
+ 0xb3ba, 0x04df,
+ 0xb3be, 0x1e7d,
+ 0xb3bf, 0x04e4,
+ 0xb3c2, 0x1e7e,
+ 0xb3c3, 0x04e8,
+ 0xb3c4, 0x1e7f,
+ 0xb3c5, 0x04ea,
+ 0xb3c6, 0x1e80,
+ 0xb3c7, 0x04ec,
+ 0xb3cd, 0x1e81,
+ 0xb3ce, 0x04f3,
+ 0xb3cf, 0x1e82,
+ 0xb3d0, 0x04f5,
+ 0xb3d2, 0x1e83,
+ 0xb3d3, 0x04f8,
+ 0xb3d9, 0x1e84,
+ 0xb3da, 0x04ff,
+ 0xb3db, 0x1e85,
+ 0xb3dc, 0x0501,
+ 0xb3dd, 0x1e86,
+ 0xb3de, 0x0503,
+ 0xb3e3, 0x1e87,
+ 0xb3e4, 0x0509,
+ 0xb3e5, 0x1e88,
+ 0xb3e7, 0x050c,
+ 0xb3e8, 0x1e8a,
+ 0xb3e9, 0x050e,
+ 0xb3eb, 0x1e8b,
+ 0xb3ed, 0x0512,
+ 0xb3ef, 0x1e8d,
+ 0xb3f0, 0x0515,
+ 0xb3f1, 0x1e8e,
+ 0xb3f2, 0x0517,
+ 0xb3f3, 0x1e8f,
+ 0xb3f4, 0x0519,
+ 0xb3fa, 0x1e90,
+ 0xb3fc, 0x0521,
+ 0xb4a1, 0x1e92,
+ 0xb4a3, 0x0526,
+ 0xb4a5, 0x1e94,
+ 0xb4a7, 0x052a,
+ 0xb4ab, 0x1e96,
+ 0xb4ac, 0x052f,
+ 0xb4af, 0x1e97,
+ 0xb4b0, 0x0533,
+ 0xb4b3, 0x1e98,
+ 0xb4b5, 0x0538,
+ 0xb4b8, 0x1e9a,
+ 0xb4b9, 0x053c,
+ 0xb4bf, 0x1e9b,
+ 0xb4c0, 0x0543,
+ 0xb4c2, 0x1e9c,
+ 0xb4c3, 0x0546,
+ 0xb4c7, 0x1e9d,
+ 0xb4c8, 0x054b,
+ 0xb4ca, 0x1e9e,
+ 0xb4cb, 0x054e,
+ 0xb4cd, 0x1e9f,
+ 0xb4ce, 0x0551,
+ 0xb4cf, 0x1ea0,
+ 0xb4d0, 0x0553,
+ 0xb4d3, 0x1ea1,
+ 0xb4d5, 0x0558,
+ 0xb4da, 0x1ea3,
+ 0xb4db, 0x055e,
+ 0xb4dc, 0x1ea4,
+ 0xb4dd, 0x0560,
+ 0xb4ed, 0x1ea5,
+ 0xb4ee, 0x0571,
+ 0xb4ef, 0x1ea6,
+ 0xb4f0, 0x0573,
+ 0xb4f8, 0x1ea7,
+ 0xb4f9, 0x057c,
+ 0xb4fb, 0x1ea8,
+ 0xb4fc, 0x057f,
+ 0xb5a1, 0x0582,
+ 0xb5a3, 0x1ea9,
+ 0xb5a4, 0x0585,
+ 0xb5a5, 0x1eaa,
+ 0xb5a9, 0x058a,
+ 0xb5ac, 0x1eae,
+ 0xb5ad, 0x058e,
+ 0xb5ae, 0x1eaf,
+ 0xb5b0, 0x0591,
+ 0xb5b1, 0x1eb1,
+ 0xb5b6, 0x0597,
+ 0xb5b7, 0x1eb6,
+ 0xb5b8, 0x0599,
+ 0xb5ba, 0x1eb7,
+ 0xb5bd, 0x059e,
+ 0xb5c6, 0x1eba,
+ 0xb5c7, 0x05a8,
+ 0xb5cb, 0x1ebb,
+ 0xb5cc, 0x05ad,
+ 0xb5d0, 0x1ebc,
+ 0xb5d1, 0x05b2,
+ 0xb5d3, 0x1ebd,
+ 0xb5d4, 0x05b5,
+ 0xb5dd, 0x1ebe,
+ 0xb5e0, 0x05c1,
+ 0xb5e3, 0x1ec1,
+ 0xb5e4, 0x05c5,
+ 0xb5e6, 0x1ec2,
+ 0xb5e8, 0x05c9,
+ 0xb5ed, 0x1ec4,
+ 0xb5ee, 0x05cf,
+ 0xb5f6, 0x1ec5,
+ 0xb5f8, 0x05d9,
+ 0xb5fd, 0x1ec7,
+ 0xb5fe, 0x05df,
+ 0xb6a1, 0x05e0,
+ 0xb6a4, 0x1ec8,
+ 0xb6a6, 0x05e5,
+ 0xb6a7, 0x1eca,
+ 0xb6a8, 0x05e7,
+ 0xb6a9, 0x1ecb,
+ 0xb6aa, 0x05e9,
+ 0xb6ab, 0x1ecc,
+ 0xb6ac, 0x05eb,
+ 0xb6af, 0x1ecd,
+ 0xb6b1, 0x05f0,
+ 0xb6b3, 0x1ecf,
+ 0xb6b4, 0x05f3,
+ 0xb6b7, 0x1ed0,
+ 0xb6b8, 0x05f7,
+ 0xb6bf, 0x1ed1,
+ 0xb6c2, 0x0601,
+ 0xb6c4, 0x1ed4,
+ 0xb6c5, 0x0604,
+ 0xb6c6, 0x1ed5,
+ 0xb6c7, 0x0606,
+ 0xb6cd, 0x1ed6,
+ 0xb6ce, 0x060d,
+ 0xb6cf, 0x1ed7,
+ 0xb6d1, 0x0610,
+ 0xb6d3, 0x1ed9,
+ 0xb6d5, 0x0614,
+ 0xb6d6, 0x1edb,
+ 0xb6d7, 0x0616,
+ 0xb6d9, 0x1edc,
+ 0xb6da, 0x0619,
+ 0xb6db, 0x1edd,
+ 0xb6dc, 0x061b,
+ 0xb6e1, 0x1ede,
+ 0xb6e2, 0x0621,
+ 0xb6e9, 0x1edf,
+ 0xb6ea, 0x0629,
+ 0xb6ec, 0x1ee0,
+ 0xb6ed, 0x062c,
+ 0xb6ee, 0x1ee1,
+ 0xb6f0, 0x062f,
+ 0xb6f1, 0x1ee3,
+ 0xb6f2, 0x0631,
+ 0xb6f6, 0x1ee4,
+ 0xb6f7, 0x0636,
+ 0xb6f9, 0x1ee5,
+ 0xb6fa, 0x0639,
+ 0xb6fb, 0x1ee6,
+ 0xb6fd, 0x063c,
+ 0xb7a1, 0x1ee8,
+ 0xb7a4, 0x0641,
+ 0xb7a7, 0x1eeb,
+ 0xb7a8, 0x0645,
+ 0xb7af, 0x1eec,
+ 0xb7b1, 0x064e,
+ 0xb7b3, 0x1eee,
+ 0xb7b4, 0x0651,
+ 0xb7b6, 0x1eef,
+ 0xb7b8, 0x0655,
+ 0xb7b9, 0x1ef1,
+ 0xb7ba, 0x0657,
+ 0xb7c3, 0x1ef2,
+ 0xb7c5, 0x0662,
+ 0xb7c9, 0x1ef4,
+ 0xb7ca, 0x0667,
+ 0xb7cc, 0x1ef5,
+ 0xb7cd, 0x066a,
+ 0xb7cf, 0x1ef6,
+ 0xb7d0, 0x066d,
+ 0xb7d1, 0x1ef7,
+ 0xb7d2, 0x066f,
+ 0xb7d7, 0x1ef8,
+ 0xb7d9, 0x0676,
+ 0xb7dc, 0x1efa,
+ 0xb7dd, 0x067a,
+ 0xb7df, 0x1efb,
+ 0xb7e2, 0x067f,
+ 0xb7e3, 0x1efe,
+ 0xb7e4, 0x0681,
+ 0xb7e6, 0x1eff,
+ 0xb7e9, 0x0686,
+ 0xb7eb, 0x1f02,
+ 0xb7ee, 0x068b,
+ 0xb7ef, 0x1f05,
+ 0xb7f0, 0x068d,
+ 0xb7f4, 0x1f06,
+ 0xb7f5, 0x0692,
+ 0xb7f8, 0x1f07,
+ 0xb7f9, 0x0696,
+ 0xb8a1, 0x069c,
+ 0xb8a7, 0x1f08,
+ 0xb8a9, 0x06a4,
+ 0xb8b3, 0x1f0a,
+ 0xb8b5, 0x06b0,
+ 0xb8ba, 0x1f0c,
+ 0xb8bb, 0x06b6,
+ 0xb8bc, 0x1f0d,
+ 0xb8bd, 0x06b8,
+ 0xb8be, 0x1f0e,
+ 0xb8c0, 0x06bb,
+ 0xb8c3, 0x1f10,
+ 0xb8c4, 0x06bf,
+ 0xb8c6, 0x1f11,
+ 0xb8c8, 0x06c3,
+ 0xb8c9, 0x1f13,
+ 0xb8ca, 0x06c5,
+ 0xb8cf, 0x1f14,
+ 0xb8d0, 0x06cb,
+ 0xb8d3, 0x1f15,
+ 0xb8d7, 0x06d2,
+ 0xb8d9, 0x1f19,
+ 0xb8db, 0x06d6,
+ 0xb8e4, 0x1f1b,
+ 0xb8e5, 0x06e0,
+ 0xb8e9, 0x1f1c,
+ 0xb8ea, 0x06e5,
+ 0xb8eb, 0x1f1d,
+ 0xb8ec, 0x06e7,
+ 0xb8f3, 0x1f1e,
+ 0xb8f4, 0x06ef,
+ 0xb8f5, 0x1f1f,
+ 0xb8f7, 0x06f2,
+ 0xb8f8, 0x1f21,
+ 0xb8f9, 0x06f4,
+ 0xb9a1, 0x06fa,
+ 0xb9a8, 0x1f22,
+ 0xb9a9, 0x0702,
+ 0xb9ae, 0x1f23,
+ 0xb9af, 0x0708,
+ 0xb9b1, 0x1f24,
+ 0xb9b2, 0x070b,
+ 0xb9b3, 0x1f25,
+ 0xb9b4, 0x070d,
+ 0xb9b5, 0x1f26,
+ 0xb9b6, 0x070f,
+ 0xb9b9, 0x1f27,
+ 0xb9bb, 0x0714,
+ 0xb9c6, 0x1f29,
+ 0xb9c7, 0x0720,
+ 0xb9cb, 0x1f2a,
+ 0xb9cc, 0x0725,
+ 0xb9d0, 0x1f2b,
+ 0xb9d1, 0x072a,
+ 0xb9d8, 0x1f2c,
+ 0xb9d9, 0x0732,
+ 0xb9db, 0x1f2d,
+ 0xb9dc, 0x0735,
+ 0xb9dd, 0x1f2e,
+ 0xb9de, 0x0737,
+ 0xb9df, 0x1f2f,
+ 0xb9e0, 0x0739,
+ 0xb9e1, 0x1f30,
+ 0xb9e2, 0x073b,
+ 0xb9e3, 0x1f31,
+ 0xb9e4, 0x073d,
+ 0xb9e6, 0x1f32,
+ 0xb9e7, 0x0740,
+ 0xb9e9, 0x1f33,
+ 0xb9ed, 0x0746,
+ 0xb9ee, 0x1f37,
+ 0xb9ef, 0x0748,
+ 0xb9f1, 0x1f38,
+ 0xb9f2, 0x074b,
+ 0xb9f3, 0x1f39,
+ 0xb9f6, 0x074f,
+ 0xb9f8, 0x1f3c,
+ 0xb9f9, 0x0752,
+ 0xb9fa, 0x1f3d,
+ 0xb9fb, 0x0754,
+ 0xb9fd, 0x1f3e,
+ 0xb9fe, 0x0757,
+ 0xbaa1, 0x0758,
+ 0xbaa7, 0x1f3f,
+ 0xbaa8, 0x075f,
+ 0xbaab, 0x1f40,
+ 0xbaac, 0x0763,
+ 0xbaba, 0x1f41,
+ 0xbabb, 0x0772,
+ 0xbac5, 0x1f42,
+ 0xbac6, 0x077d,
+ 0xbad2, 0x1f43,
+ 0xbad3, 0x078a,
+ 0xbad7, 0x1f44,
+ 0xbad9, 0x0790,
+ 0xbae4, 0x1f46,
+ 0xbae5, 0x079c,
+ 0xbae8, 0x1f47,
+ 0xbae9, 0x07a0,
+ 0xbaec, 0x1f48,
+ 0xbaed, 0x07a4,
+ 0xbaf3, 0x15e5,
+ 0xbaf4, 0x07ab,
+ 0xbaf8, 0x1f49,
+ 0xbaf9, 0x07b0,
+ 0xbba1, 0x07b6,
+ 0xbba4, 0x1f4a,
+ 0xbba5, 0x07ba,
+ 0xbba6, 0x1f4b,
+ 0xbba7, 0x07bc,
+ 0xbba9, 0x1f4c,
+ 0xbbab, 0x07c0,
+ 0xbbad, 0x1f4e,
+ 0xbbaf, 0x07c4,
+ 0xbbb0, 0x1f50,
+ 0xbbb1, 0x07c6,
+ 0xbbb3, 0x1f51,
+ 0xbbb4, 0x07c9,
+ 0xbbb5, 0x1f52,
+ 0xbbb8, 0x07cd,
+ 0xbbb9, 0x1f55,
+ 0xbbbb, 0x07d0,
+ 0xbbd1, 0x1f57,
+ 0xbbd2, 0x07e7,
+ 0xbbd3, 0x1f58,
+ 0xbbd5, 0x07ea,
+ 0xbbdf, 0x1f5a,
+ 0xbbe8, 0x07fd,
+ 0xbbeb, 0x1f63,
+ 0xbbec, 0x0801,
+ 0xbbf1, 0x1f64,
+ 0xbbf2, 0x0807,
+ 0xbbf5, 0x1f65,
+ 0xbbf8, 0x080d,
+ 0xbbfa, 0x1f68,
+ 0xbbfb, 0x0810,
+ 0xbbfd, 0x1f69,
+ 0xbbfe, 0x0813,
+ 0xbca1, 0x0814,
+ 0xbca2, 0x1f6a,
+ 0xbca3, 0x0816,
+ 0xbca5, 0x1f6b,
+ 0xbca7, 0x081a,
+ 0xbca8, 0x1f6d,
+ 0xbcaa, 0x081d,
+ 0xbcab, 0x1f6f,
+ 0xbcac, 0x081f,
+ 0xbcad, 0x1f70,
+ 0xbcae, 0x0821,
+ 0xbcb6, 0x1f71,
+ 0xbcb9, 0x082c,
+ 0xbcbb, 0x1f74,
+ 0xbcbc, 0x082f,
+ 0xbcc1, 0x1f75,
+ 0xbcc2, 0x0835,
+ 0xbcc3, 0x1f76,
+ 0xbcc4, 0x0837,
+ 0xbcc6, 0x1f77,
+ 0xbcc8, 0x083b,
+ 0xbcca, 0x1f79,
+ 0xbccb, 0x083e,
+ 0xbccc, 0x1f7a,
+ 0xbcce, 0x0841,
+ 0xbcd0, 0x1f7c,
+ 0xbcd1, 0x0844,
+ 0xbcd4, 0x1f7d,
+ 0xbcd7, 0x084a,
+ 0xbcd8, 0x1f80,
+ 0xbcd9, 0x084c,
+ 0xbcdb, 0x1f81,
+ 0xbcdc, 0x084f,
+ 0xbcdd, 0x1f82,
+ 0xbcde, 0x0851,
+ 0xbcdf, 0x1f83,
+ 0xbce2, 0x0855,
+ 0xbce3, 0x1f86,
+ 0xbce5, 0x0858,
+ 0xbce8, 0x1f88,
+ 0xbce9, 0x085c,
+ 0xbcea, 0x1f89,
+ 0xbced, 0x0860,
+ 0xbcef, 0x1f8c,
+ 0xbcf4, 0x0867,
+ 0xbcf6, 0x1f91,
+ 0xbcfd, 0x0870,
+ 0xbda1, 0x0872,
+ 0xbda2, 0x1f98,
+ 0xbda8, 0x0879,
+ 0xbdab, 0x1f9e,
+ 0xbdad, 0x087e,
+ 0xbdaf, 0x1fa0,
+ 0xbdb3, 0x0884,
+ 0xbdb4, 0x1fa4,
+ 0xbdb5, 0x0886,
+ 0xbdba, 0x1fa5,
+ 0xbdbb, 0x088c,
+ 0xbdbd, 0x1fa6,
+ 0xbdc0, 0x0891,
+ 0xbdc1, 0x1fa9,
+ 0xbdc5, 0x0896,
+ 0xbdc8, 0x1fad,
+ 0xbdcb, 0x089c,
+ 0xbdce, 0x1fb0,
+ 0xbdd0, 0x08a1,
+ 0xbdd7, 0x1fb2,
+ 0xbdd8, 0x08a9,
+ 0xbdda, 0x1fb3,
+ 0xbddb, 0x08ac,
+ 0xbde0, 0x1fb4,
+ 0xbde2, 0x08b3,
+ 0xbdeb, 0x1fb6,
+ 0xbdec, 0x08bd,
+ 0xbdf4, 0x1fb7,
+ 0xbdf9, 0x08ca,
+ 0xbdfd, 0x1fbc,
+ 0xbdfe, 0x08cf,
+ 0xbea1, 0x1fbd,
+ 0xbea3, 0x08d2,
+ 0xbea5, 0x1fbf,
+ 0xbea6, 0x08d5,
+ 0xbea8, 0x1fc0,
+ 0xbea9, 0x08d8,
+ 0xbeaa, 0x1fc1,
+ 0xbeab, 0x08da,
+ 0xbead, 0x1fc2,
+ 0xbeae, 0x08dd,
+ 0xbeb1, 0x1fc3,
+ 0xbeb2, 0x08e1,
+ 0xbeb5, 0x1fc4,
+ 0xbeb8, 0x08e7,
+ 0xbeba, 0x1fc7,
+ 0xbebb, 0x08ea,
+ 0xbec0, 0x1fc8,
+ 0xbec1, 0x08f0,
+ 0xbec9, 0x1fc9,
+ 0xbeca, 0x08f9,
+ 0xbed4, 0x1fca,
+ 0xbed5, 0x0904,
+ 0xbed9, 0x1fcb,
+ 0xbeda, 0x0909,
+ 0xbedd, 0x1fcc,
+ 0xbede, 0x090d,
+ 0xbee2, 0x1fcd,
+ 0xbee3, 0x0912,
+ 0xbee5, 0x1fce,
+ 0xbee6, 0x0915,
+ 0xbee7, 0x1fcf,
+ 0xbee8, 0x0917,
+ 0xbee9, 0x1fd0,
+ 0xbeea, 0x0919,
+ 0xbeee, 0x1fd1,
+ 0xbeef, 0x091e,
+ 0xbef5, 0x1fd2,
+ 0xbef6, 0x0925,
+ 0xbef7, 0x1fd3,
+ 0xbef9, 0x0928,
+ 0xbefb, 0x1fd5,
+ 0xbefd, 0x092c,
+ 0xbfa1, 0x092e,
+ 0xbfa5, 0x1fd7,
+ 0xbfa6, 0x0933,
+ 0xbfaa, 0x1fd8,
+ 0xbfab, 0x0938,
+ 0xbfad, 0x1fd9,
+ 0xbfae, 0x093b,
+ 0xbfc5, 0x1fda,
+ 0xbfc6, 0x0953,
+ 0xbfc7, 0x1fdb,
+ 0xbfc8, 0x0955,
+ 0xbfce, 0x1fdc,
+ 0xbfcf, 0x095c,
+ 0xbfd1, 0x1fdd,
+ 0xbfd3, 0x0960,
+ 0xbfd9, 0x1fdf,
+ 0xbfda, 0x0967,
+ 0xbfe2, 0x1fe0,
+ 0xbfe5, 0x0972,
+ 0xbfe9, 0x1fe3,
+ 0xbfea, 0x0977,
+ 0xbfeb, 0x1fe4,
+ 0xbfec, 0x0979,
+ 0xbfed, 0x1fe5,
+ 0xbfee, 0x097b,
+ 0xbff3, 0x1fe6,
+ 0xbff4, 0x0981,
+ 0xbff5, 0x1fe7,
+ 0xbff6, 0x0983,
+ 0xbff7, 0x1fe8,
+ 0xbff8, 0x0985,
+ 0xbff9, 0x1fe9,
+ 0xbffb, 0x0988,
+ 0xc0a1, 0x1feb,
+ 0xc0a2, 0x098d,
+ 0xc0a3, 0x1fec,
+ 0xc0a4, 0x098f,
+ 0xc0a9, 0x1fed,
+ 0xc0aa, 0x0995,
+ 0xc0ab, 0x1fee,
+ 0xc0ac, 0x0997,
+ 0xc0af, 0x1fef,
+ 0xc0b1, 0x099c,
+ 0xc0b3, 0x1ff1,
+ 0xc0b7, 0x09a2,
+ 0xc0b8, 0x1ff5,
+ 0xc0c5, 0x09b0,
+ 0xc0cc, 0x2002,
+ 0xc0ce, 0x09b9,
+ 0xc0d4, 0x2004,
+ 0xc0d5, 0x09c0,
+ 0xc0d6, 0x2005,
+ 0xc0d7, 0x09c2,
+ 0xc0d8, 0x2006,
+ 0xc0d9, 0x09c4,
+ 0xc0dd, 0x2007,
+ 0xc0de, 0x09c9,
+ 0xc0e0, 0x2008,
+ 0xc0e1, 0x09cc,
+ 0xc0e9, 0x2009,
+ 0xc0ea, 0x09d5,
+ 0xc0eb, 0x200a,
+ 0xc0ed, 0x09d8,
+ 0xc0ef, 0x200c,
+ 0xc0f2, 0x09dd,
+ 0xc0f6, 0x200f,
+ 0xc0fb, 0x09e6,
+ 0xc1a1, 0x09ea,
+ 0xc1a4, 0x2014,
+ 0xc1a6, 0x09ef,
+ 0xc1a9, 0x2016,
+ 0xc1ae, 0x09f7,
+ 0xc1af, 0x201b,
+ 0xc1b9, 0x0a02,
+ 0xc1bd, 0x2025,
+ 0xc1bf, 0x0a08,
+ 0xc1c2, 0x2027,
+ 0xc1c3, 0x0a0c,
+ 0xc1c6, 0x2028,
+ 0xc1c7, 0x0a10,
+ 0xc1c9, 0x2029,
+ 0xc1ca, 0x0a13,
+ 0xc1cd, 0x202a,
+ 0xc1ce, 0x0a17,
+ 0xc1d4, 0x202b,
+ 0xc1d5, 0x0a1e,
+ 0xc1d9, 0x202c,
+ 0xc1dc, 0x0a25,
+ 0xc1de, 0x202f,
+ 0xc1df, 0x0a28,
+ 0xc1e4, 0x2030,
+ 0xc1e6, 0x0a2f,
+ 0xc1e9, 0x2032,
+ 0xc1ea, 0x0a33,
+ 0xc1eb, 0x2033,
+ 0xc1ed, 0x0a36,
+ 0xc1f3, 0x2035,
+ 0xc1f4, 0x0a3d,
+ 0xc1f5, 0x2036,
+ 0xc1f6, 0x0a3f,
+ 0xc1fa, 0x2037,
+ 0xc1fe, 0x0a47,
+ 0xc2a1, 0x0a48,
+ 0xc2a2, 0x203b,
+ 0xc2a9, 0x0a50,
+ 0xc2ab, 0x2042,
+ 0xc2b4, 0x0a5b,
+ 0xc2b8, 0x204b,
+ 0xc2b9, 0x0a60,
+ 0xc2bc, 0x204c,
+ 0xc2be, 0x0a65,
+ 0xc2bf, 0x204e,
+ 0xc2c0, 0x0a67,
+ 0xc2c1, 0x204f,
+ 0xc2c2, 0x0a69,
+ 0xc2c5, 0x2050,
+ 0xc2c8, 0x0a6f,
+ 0xc2cb, 0x2053,
+ 0xc2d1, 0x0a78,
+ 0xc2d2, 0x2059,
+ 0xc2d3, 0x0a7a,
+ 0xc2d5, 0x205a,
+ 0xc2dd, 0x0a84,
+ 0xc2de, 0x2062,
+ 0xc2e3, 0x0a8a,
+ 0xc2e6, 0x2067,
+ 0xc2e9, 0x0a90,
+ 0xc2ea, 0x206a,
+ 0xc2ef, 0x0a96,
+ 0xc2f0, 0x206f,
+ 0xc2f1, 0x0a98,
+ 0xc2f2, 0x2070,
+ 0xc2f6, 0x0a9d,
+ 0xc2f7, 0x2074,
+ 0xc2fb, 0x0aa2,
+ 0xc3a1, 0x2078,
+ 0xc3a2, 0x0aa7,
+ 0xc3aa, 0x2079,
+ 0xc3ab, 0x0ab0,
+ 0xc3ad, 0x207a,
+ 0xc3ae, 0x0ab3,
+ 0xc3b3, 0x207b,
+ 0xc3b4, 0x1df9,
+ 0xc3b5, 0x0aba,
+ 0xc3be, 0x207c,
+ 0xc3bf, 0x0ac4,
+ 0xc3c5, 0x207d,
+ 0xc3c8, 0x0acd,
+ 0xc3cc, 0x2080,
+ 0xc3cd, 0x0ad2,
+ 0xc3ce, 0x2081,
+ 0xc3cf, 0x0ad4,
+ 0xc3d5, 0x2082,
+ 0xc3d7, 0x0adc,
+ 0xc3d9, 0x2084,
+ 0xc3da, 0x0adf,
+ 0xc3e0, 0x2085,
+ 0xc3e1, 0x0ae6,
+ 0xc3e5, 0x2086,
+ 0xc3e6, 0x0aeb,
+ 0xc3ed, 0x2087,
+ 0xc3ee, 0x0af3,
+ 0xc3f0, 0x2088,
+ 0xc3f1, 0x0af6,
+ 0xc3f5, 0x2089,
+ 0xc3f7, 0x0afc,
+ 0xc3f9, 0x208b,
+ 0xc3fb, 0x0b00,
+ 0xc3fd, 0x208d,
+ 0xc3fe, 0x0b03,
+ 0xc4a1, 0x0b04,
+ 0xc4b1, 0x208e,
+ 0xc4b2, 0x0b15,
+ 0xc4b6, 0x208f,
+ 0xc4b7, 0x0b1a,
+ 0xc4c6, 0x2090,
+ 0xc4c7, 0x0b2a,
+ 0xc4c9, 0x2091,
+ 0xc4ca, 0x0b2d,
+ 0xc4d1, 0x2092,
+ 0xc4d2, 0x0b35,
+ 0xc4d3, 0x2093,
+ 0xc4d7, 0x0b3a,
+ 0xc4d9, 0x2097,
+ 0xc4da, 0x0b3d,
+ 0xc4e2, 0x2098,
+ 0xc4e3, 0x0b46,
+ 0xc4e5, 0x2099,
+ 0xc4e6, 0x0b49,
+ 0xc4ec, 0x209a,
+ 0xc4ed, 0x0b50,
+ 0xc4f0, 0x209b,
+ 0xc4f2, 0x0b55,
+ 0xc4f4, 0x209d,
+ 0xc4f5, 0x0b58,
+ 0xc4f6, 0x209e,
+ 0xc4f9, 0x0b5c,
+ 0xc4fb, 0x20a1,
+ 0xc4fd, 0x0b60,
+ 0xc4fe, 0x20a3,
+ 0xc5a1, 0x20a4,
+ 0xc5a3, 0x0b64,
+ 0xc5a5, 0x20a6,
+ 0xc5aa, 0x0b6b,
+ 0xc5b1, 0x20ab,
+ 0xc5b2, 0x0b73,
+ 0xc5b5, 0x20ac,
+ 0xc5b6, 0x0b77,
+ 0xc5b7, 0x20ad,
+ 0xc5ba, 0x0b7b,
+ 0xc5bb, 0x20b0,
+ 0xc5bc, 0x0b7d,
+ 0xc5bd, 0x20b1,
+ 0xc5be, 0x0b7f,
+ 0xc5cc, 0x20b2,
+ 0xc5cd, 0x0b8e,
+ 0xc5d3, 0x20b3,
+ 0xc5d4, 0x0b95,
+ 0xc5e2, 0x20b4,
+ 0xc5e3, 0x0ba4,
+ 0xc5e7, 0x20b5,
+ 0xc5e8, 0x0ba9,
+ 0xc5f4, 0x20b6,
+ 0xc5f5, 0x0bb6,
+ 0xc6a1, 0x0bc0,
+ 0xc6ad, 0x20b7,
+ 0xc6af, 0x0bce,
+ 0xc6b5, 0x20b9,
+ 0xc6b7, 0x0bd6,
+ 0xc6bb, 0x20bb,
+ 0xc6bc, 0x0bdb,
+ 0xc6be, 0x20bc,
+ 0xc6bf, 0x0bde,
+ 0xc6c0, 0x20bd,
+ 0xc6c1, 0x0be0,
+ 0xc6c3, 0x20be,
+ 0xc6c5, 0x0be4,
+ 0xc6cb, 0x20c0,
+ 0xc6ce, 0x0bed,
+ 0xc6d3, 0x20c3,
+ 0xc6d4, 0x0bf3,
+ 0xc6d7, 0x20c4,
+ 0xc6d8, 0x0bf7,
+ 0xc6ea, 0x20c5,
+ 0xc6ec, 0x0c0b,
+ 0xc6ef, 0x20c7,
+ 0xc6f0, 0x0c0f,
+ 0xc6f1, 0x20c8,
+ 0xc6f2, 0x0c11,
+ 0xc6f4, 0x20c9,
+ 0xc6f5, 0x0c14,
+ 0xc6f8, 0x20ca,
+ 0xc6f9, 0x0c18,
+ 0xc6fd, 0x20cb,
+ 0xc6fe, 0x0c1d,
+ 0xc7a1, 0x0c1e,
+ 0xc7a3, 0x20cc,
+ 0xc7a4, 0x0c21,
+ 0xc7a5, 0x20cd,
+ 0xc7a7, 0x0c24,
+ 0xc7a8, 0x20cf,
+ 0xc7aa, 0x0c27,
+ 0xc7ab, 0x20d1,
+ 0xc7ac, 0x0c29,
+ 0xc7ae, 0x20d2,
+ 0xc7b0, 0x0c2d,
+ 0xc7b3, 0x20d4,
+ 0xc7b6, 0x0c33,
+ 0xc7b9, 0x20d7,
+ 0xc7bb, 0x0c38,
+ 0xc7bd, 0x20d9,
+ 0xc7bf, 0x0c3c,
+ 0xc7c0, 0x20db,
+ 0xc7c1, 0x0c3e,
+ 0xc7c2, 0x20dc,
+ 0xc7c3, 0x0c40,
+ 0xc7c5, 0x20dd,
+ 0xc7c6, 0x0c43,
+ 0xc7c7, 0x20de,
+ 0xc7c9, 0x0c46,
+ 0xc7cc, 0x20e0,
+ 0xc7cd, 0x0c4a,
+ 0xc7cf, 0x20e1,
+ 0xc7d0, 0x0c4d,
+ 0xc7d4, 0x20e2,
+ 0xc7d6, 0x0c53,
+ 0xc7d7, 0x20e4,
+ 0xc7d8, 0x0c55,
+ 0xc7de, 0x20e5,
+ 0xc7df, 0x0c5c,
+ 0xc7e1, 0x20e6,
+ 0xc7e4, 0x0c61,
+ 0xc7ea, 0x20e9,
+ 0xc7ef, 0x0c6c,
+ 0xc7f7, 0x20ee,
+ 0xc7f9, 0x0c76,
+ 0xc7fb, 0x20f0,
+ 0xc7fc, 0x0c79,
+ 0xc7fd, 0x20f1,
+ 0xc7fe, 0x0c7b,
+ 0xc8a1, 0x0c7c,
+ 0xc8a3, 0x20f2,
+ 0xc8a4, 0x0c7f,
+ 0xc8a7, 0x20f3,
+ 0xc8a9, 0x0c84,
+ 0xc8b0, 0x20f5,
+ 0xc8b1, 0x0c8c,
+ 0xc8b5, 0x20f6,
+ 0xc8b6, 0x0c91,
+ 0xc8b7, 0x20f7,
+ 0xc8b8, 0x0c93,
+ 0xc8c3, 0x20f8,
+ 0xc8c7, 0x0ca2,
+ 0xc8c8, 0x20fc,
+ 0xc8c9, 0x0ca4,
+ 0xc8cd, 0x20fd,
+ 0xc8ce, 0x0ca9,
+ 0xc8cf, 0x20fe,
+ 0xc8d0, 0x0cab,
+ 0xc8d2, 0x20ff,
+ 0xc8d3, 0x0cae,
+ 0xc8d9, 0x2100,
+ 0xc8da, 0x0cb5,
+ 0xc8de, 0x2101,
+ 0xc8df, 0x0cba,
+ 0xc8ed, 0x2102,
+ 0xc8ee, 0x0cc9,
+ 0xc8f1, 0x2103,
+ 0xc8f4, 0x0ccf,
+ 0xc8f7, 0x2106,
+ 0xc8f9, 0x0cd4,
+ 0xc8fa, 0x2108,
+ 0xc8fb, 0x0cd6,
+ 0xc8fc, 0x2109,
+ 0xc8fd, 0x0cd8,
+ 0xc9a1, 0x210a,
+ 0xc9a2, 0x0cdb,
+ 0xc9a5, 0x210b,
+ 0xc9a6, 0x0cdf,
+ 0xc9a7, 0x210c,
+ 0xc9a9, 0x0ce2,
+ 0xc9ac, 0x210e,
+ 0xc9ad, 0x0ce6,
+ 0xc9b1, 0x210f,
+ 0xc9b2, 0x0ceb,
+ 0xc9b4, 0x2110,
+ 0xc9b5, 0x0cee,
+ 0xc9b8, 0x2111,
+ 0xc9ba, 0x0cf3,
+ 0xc9c1, 0x2113,
+ 0xc9c3, 0x0cfc,
+ 0xc9c4, 0x2115,
+ 0xc9c5, 0x0cfe,
+ 0xc9c9, 0x2116,
+ 0xc9ca, 0x0d03,
+ 0xc9cb, 0x2117,
+ 0xc9cc, 0x0d05,
+ 0xc9cd, 0x2118,
+ 0xc9ce, 0x0d07,
+ 0xc9d5, 0x2119,
+ 0xc9d6, 0x0d0f,
+ 0xc9dc, 0x211a,
+ 0xc9dd, 0x0d16,
+ 0xc9de, 0x211b,
+ 0xc9df, 0x0d18,
+ 0xc9e1, 0x211c,
+ 0xc9e2, 0x0d1b,
+ 0xc9e3, 0x211d,
+ 0xc9e4, 0x0d1d,
+ 0xc9e5, 0x211e,
+ 0xc9e6, 0x0d1f,
+ 0xc9e8, 0x211f,
+ 0xc9e9, 0x0d22,
+ 0xc9f0, 0x2120,
+ 0xc9f1, 0x0d2a,
+ 0xc9f3, 0x2121,
+ 0xc9f5, 0x0d2e,
+ 0xc9f6, 0x2123,
+ 0xc9f7, 0x0d30,
+ 0xc9f8, 0x2124,
+ 0xc9fa, 0x0d33,
+ 0xc9fe, 0x2126,
+ 0xcaa1, 0x0d38,
+ 0xcaa4, 0x2127,
+ 0xcaa7, 0x0d3e,
+ 0xcaa8, 0x212a,
+ 0xcaa9, 0x0d40,
+ 0xcaaa, 0x212b,
+ 0xcaac, 0x0d43,
+ 0xcab1, 0x212d,
+ 0xcab2, 0x0d49,
+ 0xcab4, 0x212e,
+ 0xcab7, 0x0d4e,
+ 0xcabb, 0x2131,
+ 0xcabc, 0x0d53,
+ 0xcac6, 0x2132,
+ 0xcac7, 0x0d5e,
+ 0xcaca, 0x2133,
+ 0xcacb, 0x0d62,
+ 0xcacd, 0x2134,
+ 0xcacf, 0x0d66,
+ 0xcad3, 0x2136,
+ 0xcad5, 0x0d6c,
+ 0xcad9, 0x2138,
+ 0xcada, 0x0d71,
+ 0xcade, 0x2139,
+ 0xcadf, 0x0d76,
+ 0xcae0, 0x213a,
+ 0xcae1, 0x0d78,
+ 0xcae4, 0x213b,
+ 0xcae5, 0x0d7c,
+ 0xcae9, 0x213c,
+ 0xcaeb, 0x0d82,
+ 0xcaf4, 0x213e,
+ 0xcaf6, 0x0d8d,
+ 0xcaf7, 0x2140,
+ 0xcaf8, 0x0d8f,
+ 0xcafa, 0x2141,
+ 0xcafb, 0x0d92,
+ 0xcafd, 0x2142,
+ 0xcafe, 0x0d95,
+ 0xcba1, 0x0d96,
+ 0xcba7, 0x2143,
+ 0xcba8, 0x0d9d,
+ 0xcbab, 0x2144,
+ 0xcbac, 0x0da1,
+ 0xcbad, 0x2145,
+ 0xcbae, 0x0da3,
+ 0xcbb3, 0x2146,
+ 0xcbb4, 0x0da9,
+ 0xcbb5, 0x2147,
+ 0xcbb7, 0x0dac,
+ 0xcbb8, 0x2149,
+ 0xcbb9, 0x0dae,
+ 0xcbbf, 0x214a,
+ 0xcbc0, 0x0db5,
+ 0xcbc7, 0x214b,
+ 0xcbc8, 0x0dbd,
+ 0xcbc9, 0x214c,
+ 0xcbcd, 0x0dc2,
+ 0xcbcf, 0x2150,
+ 0xcbd1, 0x0dc6,
+ 0xcbd3, 0x2152,
+ 0xcbd4, 0x0dc9,
+ 0xcbd5, 0x2153,
+ 0xcbd6, 0x0dcb,
+ 0xcbdf, 0x2154,
+ 0xcbe1, 0x0dd6,
+ 0xcbe4, 0x2156,
+ 0xcbe5, 0x0dda,
+ 0xcbe6, 0x2157,
+ 0xcbe8, 0x0ddd,
+ 0xcbea, 0x2159,
+ 0xcbeb, 0x0de0,
+ 0xcbef, 0x215a,
+ 0xcbf1, 0x0de6,
+ 0xcbf5, 0x215c,
+ 0xcbf7, 0x0dec,
+ 0xcbf8, 0x215e,
+ 0xcbf9, 0x0dee,
+ 0xcca1, 0x215f,
+ 0xcca3, 0x0df6,
+ 0xcca8, 0x2161,
+ 0xcca9, 0x0dfc,
+ 0xccac, 0x2162,
+ 0xccad, 0x0e00,
+ 0xccaf, 0x2163,
+ 0xccb4, 0x0e07,
+ 0xccb7, 0x2168,
+ 0xccb9, 0x0e0c,
+ 0xccbe, 0x216a,
+ 0xccbf, 0x0e12,
+ 0xccc0, 0x216b,
+ 0xccc1, 0x0e14,
+ 0xcccc, 0x216c,
+ 0xcccd, 0x0e20,
+ 0xccce, 0x216d,
+ 0xcccf, 0x0e22,
+ 0xccd0, 0x216e,
+ 0xccd1, 0x0e24,
+ 0xccd6, 0x216f,
+ 0xccd7, 0x0e2a,
+ 0xccda, 0x2170,
+ 0xccdb, 0x0e2e,
+ 0xccdc, 0x2171,
+ 0xccdd, 0x0e30,
+ 0xcce0, 0x2172,
+ 0xcce1, 0x0e34,
+ 0xcce2, 0x2173,
+ 0xcce3, 0x0e36,
+ 0xcce5, 0x2174,
+ 0xcce6, 0x0e39,
+ 0xccf5, 0x2175,
+ 0xccf6, 0x0e49,
+ 0xccf9, 0x2176,
+ 0xccfb, 0x0e4e,
+ 0xccfc, 0x2178,
+ 0xcda1, 0x0e52,
+ 0xcdad, 0x217b,
+ 0xcdae, 0x0e5f,
+ 0xcdb3, 0x217c,
+ 0xcdb4, 0x0e65,
+ 0xcdb7, 0x217d,
+ 0xcdb8, 0x0e69,
+ 0xcdbc, 0x217e,
+ 0xcdbd, 0x0e6e,
+ 0xcdbf, 0x217f,
+ 0xcdc0, 0x0e71,
+ 0xcdc5, 0x2180,
+ 0xcdc6, 0x0e77,
+ 0xcdc7, 0x2181,
+ 0xcdc8, 0x0e79,
+ 0xcdd2, 0x2182,
+ 0xcdd3, 0x0e84,
+ 0xcdd4, 0x2183,
+ 0xcdd7, 0x0e88,
+ 0xcddd, 0x2186,
+ 0xcdde, 0x0e8f,
+ 0xcde0, 0x2187,
+ 0xcde1, 0x0e92,
+ 0xcde4, 0x2188,
+ 0xcde6, 0x0e97,
+ 0xcde7, 0x218a,
+ 0xcde8, 0x0e99,
+ 0xcdf2, 0x218b,
+ 0xcdf3, 0x0ea4,
+ 0xcdf8, 0x218c,
+ 0xcdf9, 0x0eaa,
+ 0xcea1, 0x0eb0,
+ 0xcea4, 0x218d,
+ 0xcea6, 0x0eb5,
+ 0xcea7, 0x218f,
+ 0xcea8, 0x0eb7,
+ 0xceaa, 0x2190,
+ 0xceae, 0x0ebd,
+ 0xceb0, 0x2194,
+ 0xceb2, 0x0ec1,
+ 0xceb3, 0x2196,
+ 0xceb4, 0x0ec3,
+ 0xcebd, 0x2197,
+ 0xcebe, 0x0ecd,
+ 0xcec0, 0x2198,
+ 0xcec1, 0x0ed0,
+ 0xcec5, 0x2199,
+ 0xcec7, 0x0ed6,
+ 0xcec8, 0x219b,
+ 0xcec9, 0x0ed8,
+ 0xceca, 0x219c,
+ 0xcecb, 0x0eda,
+ 0xcece, 0x219d,
+ 0xced2, 0x0ee1,
+ 0xced8, 0x21a1,
+ 0xcedb, 0x0eea,
+ 0xcedc, 0x21a4,
+ 0xcedd, 0x0eec,
+ 0xcede, 0x21a5,
+ 0xcee0, 0x0eef,
+ 0xceeb, 0x21a7,
+ 0xceec, 0x0efb,
+ 0xceed, 0x21a8,
+ 0xceee, 0x0efd,
+ 0xcef1, 0x21a9,
+ 0xcef2, 0x0f01,
+ 0xcef3, 0x21aa,
+ 0xcef4, 0x0f03,
+ 0xcefd, 0x21ab,
+ 0xcfa1, 0x0f0e,
+ 0xcfae, 0x21ad,
+ 0xcfaf, 0x0f1c,
+ 0xcfb0, 0x21ae,
+ 0xcfb1, 0x0f1e,
+ 0xcfb3, 0x21af,
+ 0xcfb4, 0x0f21,
+ 0xcfb7, 0x21b0,
+ 0xcfb9, 0x0f26,
+ 0xcfba, 0x21b2,
+ 0xcfbb, 0x0f28,
+ 0xcfbd, 0x21b3,
+ 0xcfbe, 0x0f2b,
+ 0xcfbf, 0x21b4,
+ 0xcfc2, 0x0f2f,
+ 0xcfc5, 0x21b7,
+ 0xcfc6, 0x0f33,
+ 0xcfc7, 0x21b8,
+ 0xcfc8, 0x0f35,
+ 0xcfca, 0x21b9,
+ 0xcfcc, 0x0f39,
+ 0xcfcd, 0x21bb,
+ 0xcfcf, 0x0f3c,
+ 0xcfd0, 0x21bd,
+ 0xcfd1, 0x0f3e,
+ 0xcfd4, 0x21be,
+ 0xcfd9, 0x0f46,
+ 0xcfda, 0x21c3,
+ 0xcfdb, 0x0f48,
+ 0xcfdc, 0x21c4,
+ 0xcfdd, 0x0f4a,
+ 0xcfdf, 0x21c5,
+ 0xcfe0, 0x0f4d,
+ 0xcfe2, 0x21c6,
+ 0xcfe3, 0x0f50,
+ 0xcfe7, 0x21c7,
+ 0xcfe8, 0x0f55,
+ 0xcfea, 0x21c8,
+ 0xcfeb, 0x0f58,
+ 0xcfec, 0x21c9,
+ 0xcfed, 0x0f5a,
+ 0xcfee, 0x21ca,
+ 0xcfef, 0x0f5c,
+ 0xcff4, 0x21cb,
+ 0xcff5, 0x0f62,
+ 0xcff9, 0x21cc,
+ 0xcffb, 0x0f68,
+ 0xcffe, 0x21ce,
+ 0xd0a1, 0x0f6c,
+ 0xd0a5, 0x21cf,
+ 0xd0a6, 0x0f71,
+ 0xd0ad, 0x21d0,
+ 0xd0af, 0x0f7a,
+ 0xd0b2, 0x21d2,
+ 0xd0b5, 0x0f80,
+ 0xd0ba, 0x21d5,
+ 0xd0bc, 0x0f87,
+ 0xd0bf, 0x21d7,
+ 0xd0c0, 0x0f8b,
+ 0xd0c6, 0x21d8,
+ 0xd0c7, 0x0f92,
+ 0xd0cb, 0x21d9,
+ 0xd0cc, 0x0f97,
+ 0xd0e2, 0x21da,
+ 0xd0e3, 0x0fae,
+ 0xd0e5, 0x21db,
+ 0xd0e6, 0x0fb1,
+ 0xd0eb, 0x21dc,
+ 0xd0ec, 0x0fb7,
+ 0xd0ed, 0x21dd,
+ 0xd0ee, 0x0fb9,
+ 0xd0f7, 0x21de,
+ 0xd0fa, 0x0fc5,
+ 0xd0fc, 0x21e1,
+ 0xd0fd, 0x0fc8,
+ 0xd1a1, 0x21e2,
+ 0xd1a3, 0x0fcc,
+ 0xd1a4, 0x21e4,
+ 0xd1a5, 0x0fce,
+ 0xd1a7, 0x21e5,
+ 0xd1a8, 0x0fd1,
+ 0xd1ab, 0x21e6,
+ 0xd1ac, 0x0fd5,
+ 0xd1af, 0x21e7,
+ 0xd1b2, 0x0fdb,
+ 0xd1b5, 0x21ea,
+ 0xd1b8, 0x0fe1,
+ 0xd1b9, 0x21ed,
+ 0xd1ba, 0x0fe3,
+ 0xd1bb, 0x21ee,
+ 0xd1bd, 0x0fe6,
+ 0xd1c6, 0x21f0,
+ 0xd1c9, 0x0ff2,
+ 0xd1cb, 0x21f3,
+ 0xd1cc, 0x0ff5,
+ 0xd1ce, 0x21f4,
+ 0xd1d0, 0x0ff9,
+ 0xd1d5, 0x21f6,
+ 0xd1d7, 0x1000,
+ 0xd1de, 0x21f8,
+ 0xd1df, 0x1008,
+ 0xd1e1, 0x21f9,
+ 0xd1e3, 0x100c,
+ 0xd1e8, 0x21fb,
+ 0xd1ea, 0x1013,
+ 0xd1ec, 0x21fd,
+ 0xd1ed, 0x1016,
+ 0xd1ee, 0x21fe,
+ 0xd1f0, 0x1019,
+ 0xd1f1, 0x2200,
+ 0xd1f2, 0x101b,
+ 0xd1f4, 0x2201,
+ 0xd1f5, 0x101e,
+ 0xd1f7, 0x2202,
+ 0xd1fa, 0x1023,
+ 0xd2a1, 0x1028,
+ 0xd2a2, 0x2205,
+ 0xd2a3, 0x102a,
+ 0xd2a5, 0x2206,
+ 0xd2a6, 0x102d,
+ 0xd2a9, 0x2207,
+ 0xd2aa, 0x1031,
+ 0xd2af, 0x2208,
+ 0xd2b0, 0x1037,
+ 0xd2b3, 0x2209,
+ 0xd2b4, 0x103b,
+ 0xd2b5, 0x220a,
+ 0xd2b7, 0x103e,
+ 0xd2bd, 0x220c,
+ 0xd2be, 0x1045,
+ 0xd2bf, 0x220d,
+ 0xd2c0, 0x1047,
+ 0xd2c3, 0x220e,
+ 0xd2c4, 0x104b,
+ 0xd2c5, 0x220f,
+ 0xd2c6, 0x104d,
+ 0xd2c7, 0x2210,
+ 0xd2c8, 0x104f,
+ 0xd2cf, 0x2211,
+ 0xd2d0, 0x1057,
+ 0xd2d5, 0x2212,
+ 0xd2d6, 0x105d,
+ 0xd2da, 0x2213,
+ 0xd2db, 0x1062,
+ 0xd2e4, 0x2214,
+ 0xd2e6, 0x106d,
+ 0xd2e8, 0x2216,
+ 0xd2ec, 0x1073,
+ 0xd2ef, 0x221a,
+ 0xd2f0, 0x1077,
+ 0xd2f1, 0x221b,
+ 0xd2f2, 0x1079,
+ 0xd2f5, 0x221c,
+ 0xd2f6, 0x107d,
+ 0xd2f8, 0x221d,
+ 0xd2f9, 0x1080,
+ 0xd2fb, 0x221e,
+ 0xd2fc, 0x1083,
+ 0xd2fe, 0x221f,
+ 0xd3a1, 0x1086,
+ 0xd3a3, 0x2220,
+ 0xd3ad, 0x1092,
+ 0xd3ae, 0x222a,
+ 0xd3af, 0x1094,
+ 0xd3b1, 0x222b,
+ 0xd3b2, 0x1097,
+ 0xd3b4, 0x222c,
+ 0xd3b7, 0x109c,
+ 0xd3b8, 0x222f,
+ 0xd3b9, 0x109e,
+ 0xd3bb, 0x2230,
+ 0xd3bc, 0x10a1,
+ 0xd3c5, 0x2231,
+ 0xd3c6, 0x10ab,
+ 0xd3c7, 0x2232,
+ 0xd3c8, 0x10ad,
+ 0xd3ca, 0x2233,
+ 0xd3cd, 0x10b2,
+ 0xd3d5, 0x2236,
+ 0xd3d6, 0x10bb,
+ 0xd3df, 0x2237,
+ 0xd3e1, 0x10c6,
+ 0xd3e3, 0x2239,
+ 0xd3e4, 0x10c9,
+ 0xd3e6, 0x223a,
+ 0xd3e7, 0x10cc,
+ 0xd3eb, 0x223b,
+ 0xd3ed, 0x10d2,
+ 0xd3ef, 0x223d,
+ 0xd3f0, 0x10d5,
+ 0xd3f4, 0x223e,
+ 0xd3f5, 0x10da,
+ 0xd3fc, 0x223f,
+ 0xd3fd, 0x10e2,
+ 0xd3fe, 0x2240,
+ 0xd4a1, 0x10e4,
+ 0xd4a4, 0x2241,
+ 0xd4a5, 0x10e8,
+ 0xd4a6, 0x2242,
+ 0xd4a9, 0x10ec,
+ 0xd4af, 0x2245,
+ 0xd4b3, 0x10f6,
+ 0xd4b5, 0x2249,
+ 0xd4b7, 0x10fa,
+ 0xd4b8, 0x224b,
+ 0xd4b9, 0x10fc,
+ 0xd4bc, 0x224c,
+ 0xd4bd, 0x1100,
+ 0xd4be, 0x224d,
+ 0xd4c0, 0x1103,
+ 0xd4c4, 0x224f,
+ 0xd4c5, 0x1108,
+ 0xd4c6, 0x2250,
+ 0xd4c8, 0x110b,
+ 0xd4c9, 0x2252,
+ 0xd4ca, 0x110d,
+ 0xd4cb, 0x2253,
+ 0xd4cf, 0x1112,
+ 0xd4d3, 0x2257,
+ 0xd4d4, 0x1117,
+ 0xd4d8, 0x2258,
+ 0xd4d9, 0x111c,
+ 0xd4dc, 0x2259,
+ 0xd4e1, 0x1124,
+ 0xd4e4, 0x225e,
+ 0xd4e5, 0x1128,
+ 0xd4e6, 0x225f,
+ 0xd4e7, 0x112a,
+ 0xd4ee, 0x2260,
+ 0xd4ef, 0x1132,
+ 0xd4f0, 0x2261,
+ 0xd4f5, 0x1138,
+ 0xd4f9, 0x2266,
+ 0xd4fa, 0x113d,
+ 0xd4fe, 0x2267,
+ 0xd5a1, 0x2268,
+ 0xd5a3, 0x1144,
+ 0xd5a9, 0x226a,
+ 0xd5aa, 0x114b,
+ 0xd5ab, 0x226b,
+ 0xd5ac, 0x114d,
+ 0xd5ae, 0x226c,
+ 0xd5af, 0x1150,
+ 0xd5b1, 0x226d,
+ 0xd5b2, 0x1153,
+ 0xd5b5, 0x226e,
+ 0xd5b9, 0x115a,
+ 0xd5bb, 0x2272,
+ 0xd5bc, 0x115d,
+ 0xd5bd, 0x2273,
+ 0xd5be, 0x115f,
+ 0xd5c0, 0x2274,
+ 0xd5c1, 0x1162,
+ 0xd5c5, 0x2275,
+ 0xd5c6, 0x1167,
+ 0xd5c7, 0x2276,
+ 0xd5c8, 0x1169,
+ 0xd5ca, 0x2277,
+ 0xd5cc, 0x116d,
+ 0xd5cd, 0x2279,
+ 0xd5ce, 0x116f,
+ 0xd5d4, 0x227a,
+ 0xd5d5, 0x1176,
+ 0xd5dd, 0x227b,
+ 0xd5df, 0x1180,
+ 0xd5e0, 0x227d,
+ 0xd5e1, 0x1182,
+ 0xd5e2, 0x227e,
+ 0xd5e3, 0x1184,
+ 0xd5ea, 0x227f,
+ 0xd5ed, 0x118e,
+ 0xd5ef, 0x2282,
+ 0xd5f0, 0x1191,
+ 0xd5f2, 0x2283,
+ 0xd5f4, 0x1195,
+ 0xd5f7, 0x15eb,
+ 0xd5f8, 0x1199,
+ 0xd6a1, 0x2285,
+ 0xd6a5, 0x11a4,
+ 0xd6af, 0x2289,
+ 0xd6b1, 0x11b0,
+ 0xd6b4, 0x228b,
+ 0xd6b5, 0x11b4,
+ 0xd6bb, 0x228c,
+ 0xd6bc, 0x11bb,
+ 0xd6bd, 0x228d,
+ 0xd6be, 0x11bd,
+ 0xd6bf, 0x228e,
+ 0xd6c1, 0x11c0,
+ 0xd6c4, 0x2290,
+ 0xd6c5, 0x11c4,
+ 0xd6ca, 0x2291,
+ 0xd6cb, 0x11ca,
+ 0xd6cd, 0x2292,
+ 0xd6ce, 0x11cd,
+ 0xd6d3, 0x2293,
+ 0xd6d4, 0x11d3,
+ 0xd6d5, 0x2294,
+ 0xd6d8, 0x11d7,
+ 0xd6da, 0x2297,
+ 0xd6db, 0x11da,
+ 0xd6df, 0x2298,
+ 0xd6e0, 0x11df,
+ 0xd6e1, 0x2299,
+ 0xd6e2, 0x11e1,
+ 0xd6e5, 0x229a,
+ 0xd6e6, 0x11e5,
+ 0xd6e7, 0x229b,
+ 0xd6e9, 0x11e8,
+ 0xd6ee, 0x229d,
+ 0xd6f0, 0x11ef,
+ 0xd6f2, 0x229f,
+ 0xd6f3, 0x11f2,
+ 0xd6f5, 0x22a0,
+ 0xd6f7, 0x11f6,
+ 0xd6fc, 0x22a2,
+ 0xd7a1, 0x11fe,
+ 0xd7a4, 0x22a5,
+ 0xd7a5, 0x1202,
+ 0xd7a8, 0x22a6,
+ 0xd7ab, 0x1208,
+ 0xd7ac, 0x22a9,
+ 0xd7ad, 0x120a,
+ 0xd7ae, 0x22aa,
+ 0xd7b2, 0x120f,
+ 0xd7b3, 0x22ae,
+ 0xd7b5, 0x1212,
+ 0xd7b6, 0x22b0,
+ 0xd7b7, 0x1214,
+ 0xd7b8, 0x22b1,
+ 0xd7bd, 0x121a,
+ 0xd7c7, 0x22b6,
+ 0xd7c8, 0x1225,
+ 0xd7ca, 0x22b7,
+ 0xd7cb, 0x1228,
+ 0xd7d5, 0x22b8,
+ 0xd7d6, 0x1233,
+ 0xd7db, 0x22b9,
+ 0xd7df, 0x123c,
+ 0xd7e7, 0x22bd,
+ 0xd7e8, 0x1245,
+ 0xd7e9, 0x22be,
+ 0xd7eb, 0x1248,
+ 0xd8a1, 0x1257,
+ 0xd8c4, 0x22c0,
+ 0xd8c5, 0x127b,
+ 0xd8c7, 0x22c1,
+ 0xd8c8, 0x127e,
+ 0xd8c9, 0x22c2,
+ 0xd8ca, 0x1280,
+ 0xd8cc, 0x22c3,
+ 0xd8ce, 0x1284,
+ 0xd8d0, 0x22c5,
+ 0xd8d2, 0x1288,
+ 0xd8d3, 0x22c7,
+ 0xd8d4, 0x128a,
+ 0xd8d9, 0x22c8,
+ 0xd8da, 0x1290,
+ 0xd8db, 0x22c9,
+ 0xd8dd, 0x1293,
+ 0xd8f1, 0x22cb,
+ 0xd8f2, 0x12a8,
+ 0xd8f6, 0x22cc,
+ 0xd8f8, 0x12ae,
+ 0xd9a1, 0x12b5,
+ 0xd9ad, 0x22ce,
+ 0xd9ae, 0x12c2,
+ 0xd9af, 0x22cf,
+ 0xd9b0, 0x12c4,
+ 0xd9b1, 0x22d0,
+ 0xd9b4, 0x12c8,
+ 0xd9c7, 0x22d3,
+ 0xd9c8, 0x12dc,
+ 0xd9cd, 0x22d4,
+ 0xd9d1, 0x12e5,
+ 0xd9dd, 0x22d8,
+ 0xd9de, 0x12f2,
+ 0xd9e1, 0x22d9,
+ 0xd9e2, 0x12f6,
+ 0xd9e4, 0x22da,
+ 0xd9e5, 0x12f9,
+ 0xd9e6, 0x22db,
+ 0xd9e7, 0x12fb,
+ 0xd9ec, 0x22dc,
+ 0xd9ed, 0x1301,
+ 0xd9f4, 0x22dd,
+ 0xd9f6, 0x130a,
+ 0xdaa1, 0x1313,
+ 0xdaa5, 0x22df,
+ 0xdae0, 0x1352,
+ 0xdaea, 0x231a,
+ 0xdaeb, 0x135d,
+ 0xdaf7, 0x231b,
+ 0xdaf8, 0x136a,
+ 0xdaf9, 0x231c,
+ 0xdafa, 0x136c,
+ 0xdafe, 0x231d,
+ 0xdba1, 0x1371,
+ 0xdba3, 0x231e,
+ 0xdba4, 0x1374,
+ 0xdba6, 0x231f,
+ 0xdba7, 0x1377,
+ 0xdba9, 0x2320,
+ 0xdbab, 0x137b,
+ 0xdbbb, 0x2322,
+ 0xdbbc, 0x138c,
+ 0xdbbd, 0x2323,
+ 0xdbbe, 0x138e,
+ 0xdbcf, 0x2324,
+ 0xdbd0, 0x13a0,
+ 0xdbd1, 0x2325,
+ 0xdbd2, 0x13a2,
+ 0xdbdb, 0x2326,
+ 0xdbdc, 0x13ac,
+ 0xdbde, 0x2327,
+ 0xdbdf, 0x13af,
+ 0xdbe2, 0x2328,
+ 0xdbe3, 0x13b3,
+ 0xdbe4, 0x2329,
+ 0xdbe5, 0x13b5,
+ 0xdbeb, 0x232a,
+ 0xdbec, 0x13bc,
+ 0xdbee, 0x232b,
+ 0xdbef, 0x13bf,
+ 0xdbf1, 0x232c,
+ 0xdbf2, 0x13c2,
+ 0xdbf5, 0x232d,
+ 0xdbf8, 0x13c8,
+ 0xdca1, 0x13cf,
+ 0xdcbc, 0x2330,
+ 0xdcbd, 0x13eb,
+ 0xdcbf, 0x2331,
+ 0xdcc0, 0x13ee,
+ 0xdcc2, 0x2332,
+ 0xdcc3, 0x13f1,
+ 0xdcc8, 0x2333,
+ 0xdccb, 0x13f9,
+ 0xdcd1, 0x2336,
+ 0xdcd2, 0x1400,
+ 0xdcd7, 0x2337,
+ 0xdcd8, 0x1406,
+ 0xdce0, 0x2338,
+ 0xdce1, 0x140f,
+ 0xdce3, 0x2339,
+ 0xdce5, 0x1413,
+ 0xdce9, 0x233b,
+ 0xdceb, 0x1419,
+ 0xdcf1, 0x233d,
+ 0xdcf2, 0x1420,
+ 0xdcf6, 0x233e,
+ 0xdcf7, 0x1425,
+ 0xdcf9, 0x233f,
+ 0xdcfa, 0x1428,
+ 0xdcfd, 0x2340,
+ 0xdda1, 0x2342,
+ 0xdda2, 0x142e,
+ 0xdda3, 0x2343,
+ 0xdda8, 0x1434,
+ 0xddaa, 0x2348,
+ 0xddac, 0x1438,
+ 0xddb2, 0x234a,
+ 0xddb3, 0x143f,
+ 0xddb5, 0x234b,
+ 0xddb6, 0x1442,
+ 0xddba, 0x234c,
+ 0xddbc, 0x1448,
+ 0xddd3, 0x234e,
+ 0xddd4, 0x1460,
+ 0xdddb, 0x234f,
+ 0xdddc, 0x1468,
+ 0xddde, 0x2350,
+ 0xdddf, 0x146b,
+ 0xdde4, 0x2351,
+ 0xdde5, 0x1471,
+ 0xddeb, 0x2352,
+ 0xddec, 0x1478,
+ 0xddf1, 0x2353,
+ 0xddf2, 0x147e,
+ 0xddf6, 0x2354,
+ 0xddf8, 0x1484,
+ 0xddfc, 0x2356,
+ 0xddfd, 0x1489,
+ 0xddfe, 0x2357,
+ 0xdea1, 0x148b,
+ 0xdead, 0x2358,
+ 0xdeae, 0x1498,
+ 0xdeb4, 0x2359,
+ 0xdeb5, 0x149f,
+ 0xdeba, 0x235a,
+ 0xdebb, 0x14a5,
+ 0xdec6, 0x235b,
+ 0xdec7, 0x14b1,
+ 0xdecf, 0x235c,
+ 0xded0, 0x14ba,
+ 0xded1, 0x235d,
+ 0xded3, 0x14bd,
+ 0xded8, 0x235f,
+ 0xded9, 0x14c3,
+ 0xdee2, 0x2360,
+ 0xdee3, 0x14cd,
+ 0xdee8, 0x2361,
+ 0xdee9, 0x14d3,
+ 0xdeec, 0x2362,
+ 0xdeed, 0x14d7,
+ 0xdef3, 0x2363,
+ 0xdef4, 0x14de,
+ 0xdefc, 0x2364,
+ 0xdefd, 0x14e7,
+ 0xdfa1, 0x14e9,
+ 0xdfa2, 0x2365,
+ 0xdfa4, 0x14ec,
+ 0xdfa5, 0x2367,
+ 0xdfa6, 0x14ee,
+ 0xdfb4, 0x2368,
+ 0xdfb5, 0x14fd,
+ 0xdfbc, 0x2369,
+ 0xdfbe, 0x1506,
+ 0xdfbf, 0x236b,
+ 0xdfc0, 0x1508,
+ 0xdfc2, 0x236c,
+ 0xdfc4, 0x150c,
+ 0xdfcc, 0x236e,
+ 0xdfcd, 0x1515,
+ 0xdfd0, 0x236f,
+ 0xdfd1, 0x1519,
+ 0xdfd5, 0x2370,
+ 0xdfd6, 0x151e,
+ 0xdfd8, 0x2371,
+ 0xdfda, 0x1522,
+ 0xdfdc, 0x2373,
+ 0xdfdd, 0x1525,
+ 0xdfe0, 0x2374,
+ 0xdfe1, 0x1529,
+ 0xdfe2, 0x2375,
+ 0xdfe3, 0x152b,
+ 0xdfe6, 0x2376,
+ 0xdfe7, 0x152f,
+ 0xdfe9, 0x2377,
+ 0xdfea, 0x1532,
+ 0xdfeb, 0x2378,
+ 0xdfec, 0x1534,
+ 0xdfef, 0x2379,
+ 0xdff0, 0x1538,
+ 0xdff5, 0x237a,
+ 0xdff6, 0x153e,
+ 0xdff9, 0x237b,
+ 0xdffa, 0x1542,
+ 0xe0a1, 0x1547,
+ 0xe0b6, 0x237c,
+ 0xe0b8, 0x155e,
+ 0xe0bf, 0x237e,
+ 0xe0c0, 0x1566,
+ 0xe0c8, 0x237f,
+ 0xe0c9, 0x156f,
+ 0xe0ce, 0x2380,
+ 0xe0cf, 0x1575,
+ 0xe0d3, 0x2381,
+ 0xe0d4, 0x157a,
+ 0xe0e0, 0x2382,
+ 0xe0e1, 0x1587,
+ 0xe0f0, 0x2383,
+ 0xe0f1, 0x1597,
+ 0xe0f8, 0x2384,
+ 0xe0f9, 0x159f,
+ 0xe0fc, 0x2385,
+ 0xe1a1, 0x15a5,
+ 0xe1ab, 0x2388,
+ 0xe1ac, 0x15b0,
+ 0xe1ad, 0x2389,
+ 0xe1ae, 0x15b2,
+ 0xe1b0, 0x238a,
+ 0xe1b1, 0x15b5,
+ 0xe1b4, 0x238b,
+ 0xe1b5, 0x15b9,
+ 0xe1bb, 0x238c,
+ 0xe1bc, 0x15c0,
+ 0xe1bd, 0x238d,
+ 0xe1be, 0x15c2,
+ 0xe1c0, 0x238e,
+ 0xe1c2, 0x15c6,
+ 0xe1c9, 0x2390,
+ 0xe1ca, 0x15ce,
+ 0xe1d0, 0x2391,
+ 0xe1d1, 0x15d5,
+ 0xe1db, 0x2392,
+ 0xe1dc, 0x15e0,
+ 0xe1e1, 0x07aa,
+ 0xe1e2, 0x2393,
+ 0xe1e3, 0x15e7,
+ 0xe1e7, 0x1198,
+ 0xe1e8, 0x15ec,
+ 0xe1ee, 0x2394,
+ 0xe1f0, 0x15f4,
+ 0xe1f6, 0x2396,
+ 0xe1f7, 0x15fb,
+ 0xe1f8, 0x2397,
+ 0xe1f9, 0x15fd,
+ 0xe1fd, 0x2398,
+ 0xe1fe, 0x1602,
+ 0xe2a1, 0x1603,
+ 0xe2a4, 0x2399,
+ 0xe2a5, 0x1607,
+ 0xe2a8, 0x239a,
+ 0xe2a9, 0x160b,
+ 0xe2bb, 0x239b,
+ 0xe2c5, 0x10c5,
+ 0xe2c6, 0x23a5,
+ 0xe2cf, 0x1631,
+ 0xe2d0, 0x23ae,
+ 0xe2d1, 0x1633,
+ 0xe2d9, 0x23af,
+ 0xe2da, 0x163c,
+ 0xe2e3, 0x23b0,
+ 0xe2e5, 0x1647,
+ 0xe2e6, 0x23b2,
+ 0xe2e7, 0x1649,
+ 0xe2e9, 0x23b3,
+ 0xe2ec, 0x164e,
+ 0xe2f8, 0x23b6,
+ 0xe2f9, 0x165b,
+ 0xe2fa, 0x23b7,
+ 0xe2fe, 0x1660,
+ 0xe3a1, 0x1661,
+ 0xe3a2, 0x23bb,
+ 0xe3a3, 0x1663,
+ 0xe3a5, 0x23bc,
+ 0xe3a6, 0x1666,
+ 0xe3ab, 0x23bd,
+ 0xe3ac, 0x166c,
+ 0xe3b4, 0x23be,
+ 0xe3b5, 0x1675,
+ 0xe3c5, 0x23bf,
+ 0xe3dc, 0x169c,
+ 0xe3e3, 0x23d6,
+ 0xe3e4, 0x16a4,
+ 0xe3ed, 0x23d7,
+ 0xe3ee, 0x16ae,
+ 0xe3f1, 0x23d8,
+ 0xe3f3, 0x16b3,
+ 0xe3f8, 0x23da,
+ 0xe3f9, 0x16b9,
+ 0xe3fe, 0x23db,
+ 0xe4a1, 0x16bf,
+ 0xe4a4, 0x23dc,
+ 0xe4a6, 0x16c4,
+ 0xe4ab, 0x23de,
+ 0xe4ac, 0x16ca,
+ 0xe4af, 0x23df,
+ 0xe4b2, 0x16d0,
+ 0xe4b5, 0x23e2,
+ 0xe4b7, 0x16d5,
+ 0xe4c2, 0x23e4,
+ 0xe4c3, 0x16e1,
+ 0xe4c5, 0x23e5,
+ 0xe4c6, 0x16e4,
+ 0xe4c9, 0x23e6,
+ 0xe4ca, 0x16e8,
+ 0xe4d9, 0x23e7,
+ 0xe4da, 0x16f8,
+ 0xe4dc, 0x23e8,
+ 0xe4dd, 0x16fb,
+ 0xe4de, 0x23e9,
+ 0xe4df, 0x16fd,
+ 0xe4e4, 0x23ea,
+ 0xe4e5, 0x1703,
+ 0xe4eb, 0x23eb,
+ 0xe4ed, 0x170b,
+ 0xe4f2, 0x23ed,
+ 0xe4f3, 0x1711,
+ 0xe4fe, 0x23ee,
+ 0xe5a1, 0x171d,
+ 0xe5b0, 0x23ef,
+ 0xe5b1, 0x172d,
+ 0xe5b9, 0x23f0,
+ 0xe5ba, 0x1736,
+ 0xe5c7, 0x23f1,
+ 0xe5c8, 0x1744,
+ 0xe5c9, 0x23f2,
+ 0xe5ca, 0x1746,
+ 0xe5ce, 0x23f3,
+ 0xe5cf, 0x174b,
+ 0xe5f0, 0x23f4,
+ 0xe5f1, 0x176d,
+ 0xe5f2, 0x23f5,
+ 0xe5f3, 0x176f,
+ 0xe5fc, 0x23f6,
+ 0xe5fe, 0x177a,
+ 0xe6a1, 0x177b,
+ 0xe6a3, 0x23f8,
+ 0xe6a4, 0x177e,
+ 0xe6ab, 0x23f9,
+ 0xe6ad, 0x1787,
+ 0xe6ae, 0x23fb,
+ 0xe6af, 0x1789,
+ 0xe6b4, 0x23fc,
+ 0xe6b6, 0x1790,
+ 0xe6bf, 0x23fe,
+ 0xe6c0, 0x179a,
+ 0xe6c8, 0x23ff,
+ 0xe6ca, 0x17a4,
+ 0xe6cd, 0x2401,
+ 0xe6ce, 0x17a8,
+ 0xe6e0, 0x2402,
+ 0xe7a1, 0x2421,
+ 0xe7db, 0x1813,
+ 0xe7e1, 0x245b,
+ 0xe7e3, 0x181b,
+ 0xe7e7, 0x245d,
+ 0xe7e8, 0x1820,
+ 0xe7ef, 0x245e,
+ 0xe7f0, 0x1828,
+ 0xe7f4, 0x245f,
+ 0xe7f7, 0x182f,
+ 0xe8a1, 0x1837,
+ 0xe8a8, 0x2462,
+ 0xe8a9, 0x183f,
+ 0xe8ac, 0x2463,
+ 0xe8ad, 0x1843,
+ 0xe8b6, 0x2464,
+ 0xe8b7, 0x184d,
+ 0xe8b8, 0x2465,
+ 0xe8bb, 0x1851,
+ 0xe8bf, 0x2468,
+ 0xe8c1, 0x1857,
+ 0xe8c5, 0x246a,
+ 0xe8c6, 0x185c,
+ 0xe8c7, 0x246b,
+ 0xe8ca, 0x1860,
+ 0xe8ce, 0x246e,
+ 0xe8cf, 0x1865,
+ 0xe8d0, 0x246f,
+ 0xe8d1, 0x1867,
+ 0xe8d3, 0x2470,
+ 0xe8d4, 0x186a,
+ 0xe8dd, 0x2471,
+ 0xe8de, 0x1874,
+ 0xe8df, 0x2472,
+ 0xe8e0, 0x1876,
+ 0xe8e2, 0x2473,
+ 0xe8e4, 0x187a,
+ 0xe8e5, 0x2475,
+ 0xe8e6, 0x187c,
+ 0xe8e7, 0x2476,
+ 0xe8e8, 0x187e,
+ 0xe8eb, 0x2477,
+ 0xe8ec, 0x1882,
+ 0xe8ed, 0x2478,
+ 0xe8ee, 0x1884,
+ 0xe8ef, 0x2479,
+ 0xe8f0, 0x1886,
+ 0xe8f9, 0x247a,
+ 0xe8fa, 0x1890,
+ 0xe8fc, 0x247b,
+ 0xe8fe, 0x1894,
+ 0xe9a1, 0x247d,
+ 0xe9a2, 0x1896,
+ 0xe9ad, 0x247e,
+ 0xe9ae, 0x18a2,
+ 0xe9b4, 0x247f,
+ 0xe9b6, 0x18aa,
+ 0xe9b7, 0x2481,
+ 0xe9b8, 0x18ac,
+ 0xe9c4, 0x2482,
+ 0xe9c5, 0x18b9,
+ 0xe9c6, 0x2483,
+ 0xe9c7, 0x18bb,
+ 0xe9c9, 0x2484,
+ 0xe9ca, 0x18be,
+ 0xe9d6, 0x2485,
+ 0xe9d7, 0x18cb,
+ 0xe9da, 0x2486,
+ 0xe9db, 0x18cf,
+ 0xe9e4, 0x2487,
+ 0xe9e5, 0x18d9,
+ 0xe9e6, 0x2488,
+ 0xe9e8, 0x18dc,
+ 0xe9e9, 0x248a,
+ 0xe9ea, 0x18de,
+ 0xe9eb, 0x248b,
+ 0xe9ec, 0x18e0,
+ 0xe9ed, 0x248c,
+ 0xeaa1, 0x249e,
+ 0xeaa6, 0x18f8,
+ 0xeaa7, 0x24a3,
+ 0xeaa9, 0x18fb,
+ 0xeab1, 0x24a5,
+ 0xeab2, 0x1904,
+ 0xeabc, 0x24a6,
+ 0xeabd, 0x190f,
+ 0xeaca, 0x24a7,
+ 0xeacb, 0x191d,
+ 0xeacd, 0x24a8,
+ 0xeace, 0x1920,
+ 0xead3, 0x24a9,
+ 0xead4, 0x1926,
+ 0xeada, 0x24aa,
+ 0xeaf0, 0x1942,
+ 0xeba1, 0x1951,
+ 0xeba7, 0x24c0,
+ 0xeba8, 0x1958,
+ 0xebaa, 0x24c1,
+ 0xebab, 0x195b,
+ 0xebb2, 0x24c2,
+ 0xebb3, 0x1963,
+ 0xebb9, 0x24c3,
+ 0xebba, 0x196a,
+ 0xebca, 0x24c4,
+ 0xebcc, 0x197c,
+ 0xebcd, 0x24c6,
+ 0xebce, 0x197e,
+ 0xebd6, 0x24c7,
+ 0xebd7, 0x1987,
+ 0xebda, 0x24c8,
+ 0xebdb, 0x198b,
+ 0xebe1, 0x24c9,
+ 0xebe2, 0x1992,
+ 0xebf7, 0x24ca,
+ 0xebf8, 0x19a8,
+ 0xeca1, 0x19af,
+ 0xeca3, 0x24cb,
+ 0xeca4, 0x19b2,
+ 0xeca9, 0x24cc,
+ 0xecaf, 0x19bd,
+ 0xecb1, 0x24d2,
+ 0xecb2, 0x19c0,
+ 0xecb4, 0x24d3,
+ 0xecb6, 0x19c4,
+ 0xecbe, 0x24d5,
+ 0xecc0, 0x19ce,
+ 0xecc1, 0x24d7,
+ 0xecc2, 0x19d0,
+ 0xecc7, 0x24d8,
+ 0xecc8, 0x19d6,
+ 0xeccb, 0x24d9,
+ 0xeccc, 0x19da,
+ 0xece2, 0x24da,
+ 0xece3, 0x19f1,
+ 0xecf2, 0x24db,
+ 0xecf3, 0x1a01,
+ 0xecf5, 0x24dc,
+ 0xecf6, 0x1a04,
+ 0xecf8, 0x24dd,
+ 0xecf9, 0x1a07,
+ 0xeda1, 0x24de,
+ 0xeda2, 0x1a0e,
+ 0xeda8, 0x24df,
+ 0xeda9, 0x1a15,
+ 0xedaf, 0x24e0,
+ 0xedb1, 0x1a1d,
+ 0xedb4, 0x24e2,
+ 0xedb5, 0x1a21,
+ 0xedb6, 0x24e3,
+ 0xedb7, 0x1a23,
+ 0xedb8, 0x24e4,
+ 0xedb9, 0x1a25,
+ 0xedba, 0x24e5,
+ 0xedbb, 0x1a27,
+ 0xedbf, 0x24e6,
+ 0xedc0, 0x1a2c,
+ 0xedc2, 0x24e7,
+ 0xedc4, 0x1a30,
+ 0xedcc, 0x24e9,
+ 0xedce, 0x1a3a,
+ 0xedd3, 0x24eb,
+ 0xedd4, 0x1a40,
+ 0xedd7, 0x24ec,
+ 0xedd8, 0x1a44,
+ 0xede8, 0x24ed,
+ 0xede9, 0x1a55,
+ 0xedee, 0x24ee,
+ 0xedef, 0x1a5b,
+ 0xedf9, 0x24ef,
+ 0xedfb, 0x1a67,
+ 0xeea1, 0x1a6b,
+ 0xeebc, 0x24f1,
+ 0xeebd, 0x1a87,
+ 0xeebf, 0x24f2,
+ 0xeec0, 0x1a8a,
+ 0xeec4, 0x24f3,
+ 0xefa1, 0x252e,
+ 0xeff2, 0x1b1a,
+ 0xf0a1, 0x1b27,
+ 0xf0a3, 0x257f,
+ 0xf0a4, 0x1b2a,
+ 0xf0af, 0x2580,
+ 0xf0da, 0x1b60,
+ 0xf0dc, 0x25ab,
+ 0xf0de, 0x1b64,
+ 0xf0df, 0x25ad,
+ 0xf0e0, 0x1b66,
+ 0xf0e9, 0x25ae,
+ 0xf0ea, 0x1b70,
+ 0xf0ec, 0x25af,
+ 0xf0ed, 0x1b73,
+ 0xf0ef, 0x25b0,
+ 0xf0f0, 0x1b76,
+ 0xf0f7, 0x25b1,
+ 0xf0f8, 0x1b7e,
+ 0xf0f9, 0x25b2,
+ 0xf0fa, 0x1b80,
+ 0xf0fc, 0x25b3,
+ 0xf0fd, 0x1b83,
+ 0xf1a1, 0x1b85,
+ 0xf1a8, 0x25b4,
+ 0xf1a9, 0x1b8d,
+ 0xf1ab, 0x25b5,
+ 0xf1ac, 0x1b90,
+ 0xf1ae, 0x25b6,
+ 0xf1af, 0x1b93,
+ 0xf1b2, 0x25b7,
+ 0xf1b3, 0x1b97,
+ 0xf1bc, 0x25b8,
+ 0xf1bd, 0x1ba1,
+ 0xf1c0, 0x25b9,
+ 0xf1c1, 0x1ba5,
+ 0xf1c9, 0x25ba,
+ 0xf1ca, 0x1bae,
+ 0xf1cd, 0x25bb,
+ 0xf1ce, 0x1bb2,
+ 0xf1cf, 0x25bc,
+ 0xf1d1, 0x1bb5,
+ 0xf1da, 0x25be,
+ 0xf1db, 0x1bbf,
+ 0xf1dc, 0x25bf,
+ 0xf1dd, 0x1bc1,
+ 0xf1e4, 0x25c0,
+ 0xf1e5, 0x1bc9,
+ 0xf1ec, 0x25c1,
+ 0xf1ed, 0x1bd1,
+ 0xf1ef, 0x25c2,
+ 0xf1f0, 0x1bd4,
+ 0xf1f7, 0x25c3,
+ 0xf1f8, 0x1bdc,
+ 0xf1f9, 0x25c4,
+ 0xf1fa, 0x1bde,
+ 0xf1fc, 0x25c5,
+ 0xf2a1, 0x25c8,
+ 0xf2ae, 0x1bf0,
+ 0xf2b1, 0x25d5,
+ 0xf2b3, 0x1bf5,
+ 0xf2b9, 0x25d7,
+ 0xf2ba, 0x1bfc,
+ 0xf2c3, 0x25d8,
+ 0xf2c4, 0x1c06,
+ 0xf2c9, 0x25d9,
+ 0xf2ca, 0x1c0c,
+ 0xf2cc, 0x25da,
+ 0xf2ce, 0x1c10,
+ 0xf2cf, 0x25dc,
+ 0xf2d0, 0x1c12,
+ 0xf2d3, 0x25dd,
+ 0xf2d4, 0x1c16,
+ 0xf2e5, 0x25de,
+ 0xf2e6, 0x1c28,
+ 0xf2ee, 0x25df,
+ 0xf2ef, 0x1c31,
+ 0xf2f7, 0x25e0,
+ 0xf2f8, 0x1c3a,
+ 0xf2fd, 0x25e1,
+ 0xf2fe, 0x1c40,
+ 0xf3a1, 0x1c41,
+ 0xf3bf, 0x25e2,
+ 0xf3c0, 0x1c60,
+ 0xf3c6, 0x25e3,
+ 0xf3c7, 0x1c67,
+ 0xf3c8, 0x25e4,
+ 0xf3c9, 0x1c69,
+ 0xf3d6, 0x25e5,
+ 0xf3d7, 0x1c77,
+ 0xf3d9, 0x25e6,
+ 0xf3da, 0x1c7a,
+ 0xf3e5, 0x25e7,
+ 0xf3e7, 0x1c87,
+ 0xf3ea, 0x25e9,
+ 0xf3eb, 0x1c8b,
+ 0xf3ec, 0x25ea,
+ 0xf3ed, 0x1c8d,
+ 0xf3ef, 0x25eb,
+ 0xf3f0, 0x1c90,
+ 0xf3f1, 0x25ec,
+ 0xf3f2, 0x1c92,
+ 0xf3fd, 0x25ed,
+ 0xf3fe, 0x1c9e,
+ 0xf4a1, 0x1c9f,
+ 0xf4a5, 0x25ee,
+ 0xf4a6, 0x1ca4,
+ 0xf4af, 0x25ef,
+ 0xf4b0, 0x1cae,
+ 0xf4b5, 0x25f0,
+ 0xf4b6, 0x1cb4,
+ 0xf4c1, 0x25f1,
+ 0xf4c2, 0x1cc0,
+ 0xf4c7, 0x25f2,
+ 0xf4c8, 0x1cc6,
+ 0xf4cf, 0x25f3,
+ 0xf4d1, 0x1ccf,
+ 0xf4d6, 0x25f5,
+ 0xf4d7, 0x1cd5,
+ 0xf4ea, 0x25f6,
+ 0xf4eb, 0x1ce9,
+ 0xf4ef, 0x25f7,
+ 0xf4f0, 0x1cee,
+ 0xf4f5, 0x25f8,
+ 0xf4f6, 0x1cf4,
+ 0xf5a1, 0x1cfd,
+ 0xf5a6, 0x25f9,
+ 0xf5a8, 0x1d04,
+ 0xf5ba, 0x25fb,
+ 0xf5bc, 0x1d18,
+ 0xf5c4, 0x25fd,
+ 0xf5c5, 0x1d21,
+ 0xf5c8, 0x25fe,
+ 0xf5c9, 0x1d25,
+ 0xf5ce, 0x25ff,
+ 0xf5d0, 0x1d2c,
+ 0xf5d1, 0x2601,
+ 0xf5d3, 0x1d2f,
+ 0xf5d9, 0x2603,
+ 0xf5da, 0x1d36,
+ 0xf5dc, 0x2604,
+ 0xf5dd, 0x1d39,
+ 0xf5e6, 0x2605,
+ 0xf5e8, 0x1d44,
+ 0xf5ef, 0x2607,
+ 0xf5f0, 0x1d4c,
+ 0xf5f2, 0x2608,
+ 0xf5f3, 0x1d4f,
+ 0xf5fc, 0x2609,
+ 0xf5fd, 0x1d59,
+ 0xf6a1, 0x1d5b,
+ 0xf6a3, 0x260a,
+ 0xf6a4, 0x1d5e,
+ 0xf6a6, 0x260b,
+ 0xf6a7, 0x1d61,
+ 0xf6a8, 0x260c,
+ 0xf6a9, 0x1d63,
+ 0xf6ab, 0x260d,
+ 0xf6ac, 0x1d66,
+ 0xf6b0, 0x260e,
+ 0xf6b1, 0x1d6b,
+ 0xf6b3, 0x260f,
+ 0xf6bf, 0x1d79,
+ 0xf6c5, 0x261b,
+ 0xf6c6, 0x1d80,
+ 0xf6c7, 0x261c,
+ 0xf6c8, 0x1d82,
+ 0xf6c9, 0x261d,
+ 0xf6ca, 0x1d84,
+ 0xf6cf, 0x261e,
+ 0xf7a1, 0x264e,
+ 0xf7b0, 0x1dc8,
+ 0xf7b2, 0x265d,
+ 0xf7b4, 0x1dcc,
+ 0xf7b5, 0x265f,
+ 0xf7b6, 0x1dce,
+ 0xf7bd, 0x2660,
+ 0xf7be, 0x1dd6,
+ 0xf7c3, 0x2661,
+ 0xf7c4, 0x1ddc,
+ 0xf7c5, 0x2662,
+ 0xf7c7, 0x1ddf,
+ 0xf7ca, 0x2664,
+ 0xf7cc, 0x1de4,
+ 0xf7cf, 0x2666,
+ 0xf7d1, 0x1de9,
+ 0xf7de, 0x2668,
+ 0xf7df, 0x1df7,
+ 0xf7e1, 0x0ab9,
+ 0xf7e2, 0x1dfa,
+ 0xf7f2, 0x2669,
+ 0xf7f3, 0x1e0b,
+ 0xf7f5, 0x266a,
+ 0xf7f6, 0x1e0e,
+ 0xf8a1, 0x266b,
+ 0xf8a7, 0x04cc,
+ 0xf8a8, 0x050a,
+ 0xf8a9, 0x0518,
+ 0xf8aa, 0x2671,
+ 0xf8ac, 0x0594,
+ 0xf8ad, 0x05ce,
+ 0xf8ae, 0x2673,
+ 0xf8af, 0x05f6,
+ 0xf8b0, 0x2674,
+ 0xf8b2, 0x0653,
+ 0xf8b3, 0x067e,
+ 0xf8b4, 0x2676,
+ 0xf8b5, 0x06c4,
+ 0xf8b6, 0x2677,
+ 0xf8b8, 0x073c,
+ 0xf8b9, 0x2679,
+ 0xf8bb, 0x07c3,
+ 0xf8bc, 0x267b,
+ 0xf8c0, 0x082b,
+ 0xf8c1, 0x267f,
+ 0xf8c2, 0x084e,
+ 0xf8c3, 0x0869,
+ 0xf8c4, 0x2680,
+ 0xf8c6, 0x090c,
+ 0xf8c7, 0x2682,
+ 0xf8c9, 0x0971,
+ 0xf8ca, 0x2684,
+ 0xf8cb, 0x099a,
+ 0xf8cd, 0x2685,
+ 0xf8ce, 0x09da,
+ 0xf8cf, 0x2686,
+ 0xf8d0, 0x09fa,
+ 0xf8d1, 0x2687,
+ 0xf8dc, 0x0bda,
+ 0xf8dd, 0x0bdd,
+ 0xf8de, 0x0bea,
+ 0xf8df, 0x0bec,
+ 0xf8e0, 0x0bf2,
+ 0xf8e1, 0x2692,
+ 0xf8e6, 0x0c92,
+ 0xf8e7, 0x0d1a,
+ 0xf8e8, 0x0d8c,
+ 0xf8e9, 0x0dbe,
+ 0xf8ea, 0x2697,
+ 0xf8eb, 0x0dfb,
+ 0xf8ec, 0x2698,
+ 0xf8ef, 0x0e70,
+ 0xf8f0, 0x269b,
+ 0xf8f1, 0x0ea3,
+ 0xf8f2, 0x269c,
+ 0xf8f8, 0x103d,
+ 0xf8f9, 0x10d9,
+ 0xf8fa, 0x26a2,
+ 0xf8fc, 0x10fb,
+ 0xf8fd, 0x1109,
+ 0xf8fe, 0x26a4,
+ 0xf9a1, 0x11a1,
+ 0xf9a2, 0x26a5,
+ 0xf9a3, 0x11ba,
+ 0xf9a4, 0x26a6,
+ 0xf9a6, 0x11d5,
+ 0xf9a7, 0x26a8,
+ 0xf9a8, 0x11fd,
+ 0xf9a9, 0x1219,
+ 0xa1a2, 0x023f,
+ 0xa1a3, 0x023e,
+ 0xa1aa, 0x0256,
+ 0xa1ab, 0x1e18,
+ 0xa1ad, 0x0257,
+ 0xa1b2, 0x0246,
+ 0xa1fe, 0x1e1a,
+ 0xa3a1, 0x0242,
+ 0xa3a8, 0x0244,
+ 0xa3ac, 0x023d,
+ 0xa3ae, 0x1e1b,
+ 0xa3ba, 0x0240,
+ 0xa3bd, 0x1e1c,
+ 0xa3bf, 0x0243,
+ 0xa3db, 0x1e1d,
+ 0xa3dd, 0x1e1e,
+ 0xa3df, 0x0258,
+ 0xa3fb, 0x0254,
+ 0xa3fd, 0x0255,
+ 0xa3fe, 0x1e1f,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 gb12GBTEUCVEnc16 = {
+ 1,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x1e24, 0x032e, 0x032f, 0x0330, 0x0331, 0x0332, 0x0333, 0x0334,
+ 0x0335, 0x0336, 0x0337, 0x0338, 0x0339, 0x033a, 0x033b, 0x033c,
+ 0x033d, 0x033e, 0x033f, 0x0340, 0x0341, 0x0342, 0x0343, 0x0344,
+ 0x0345, 0x0346, 0x0347, 0x0348, 0x0349, 0x034a, 0x034b, 0x034c,
+ 0x034d, 0x034e, 0x034f, 0x0350, 0x0351, 0x0352, 0x0353, 0x0354,
+ 0x0355, 0x0356, 0x0357, 0x0358, 0x0359, 0x035a, 0x035b, 0x035c,
+ 0x035d, 0x035e, 0x035f, 0x0360, 0x0361, 0x0362, 0x0363, 0x0364,
+ 0x0365, 0x0366, 0x0367, 0x0368, 0x0369, 0x036a, 0x036b, 0x036c,
+ 0x036d, 0x036e, 0x036f, 0x0370, 0x0371, 0x0372, 0x0373, 0x0374,
+ 0x0375, 0x0376, 0x0377, 0x0378, 0x0379, 0x037a, 0x037b, 0x037c,
+ 0x037d, 0x037e, 0x037f, 0x0380, 0x0381, 0x0382, 0x0383, 0x0384,
+ 0x0385, 0x0386, 0x0387, 0x0388, 0x0389, 0x038a, 0x038b, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ gb12GBTEUCVMap2, 2303
+};
+
+static Gushort gb12GBTHMap2[4566] = {
+ 0x0000, 0x0000,
+ 0x2121, 0x0060,
+ 0x2231, 0x00be,
+ 0x2265, 0x00f0,
+ 0x2271, 0x00fa,
+ 0x2321, 0x0106,
+ 0x2421, 0x0164,
+ 0x2521, 0x01b7,
+ 0x2621, 0x020d,
+ 0x2641, 0x0225,
+ 0x2721, 0x025a,
+ 0x2751, 0x027b,
+ 0x2821, 0x029c,
+ 0x2845, 0x02bc,
+ 0x2924, 0x02e2,
+ 0x2a21, 0x032e,
+ 0x2b21, 0x038c,
+ 0x3021, 0x03ac,
+ 0x3028, 0x1e25,
+ 0x3029, 0x03b4,
+ 0x302a, 0x1e26,
+ 0x302b, 0x03b6,
+ 0x302d, 0x1e27,
+ 0x302f, 0x03ba,
+ 0x3039, 0x1e29,
+ 0x303a, 0x03c5,
+ 0x3040, 0x1e2a,
+ 0x3041, 0x03cc,
+ 0x3053, 0x1e2b,
+ 0x3054, 0x03df,
+ 0x3055, 0x1e2c,
+ 0x3056, 0x03e1,
+ 0x305a, 0x1e2d,
+ 0x305b, 0x03e6,
+ 0x305c, 0x1e2e,
+ 0x305d, 0x03e8,
+ 0x3064, 0x1e2f,
+ 0x3065, 0x03f0,
+ 0x306c, 0x1e30,
+ 0x306e, 0x03f9,
+ 0x306f, 0x1e32,
+ 0x3070, 0x03fb,
+ 0x3073, 0x1e33,
+ 0x3074, 0x03ff,
+ 0x3077, 0x1e34,
+ 0x3078, 0x0403,
+ 0x3079, 0x1e35,
+ 0x307a, 0x0405,
+ 0x3121, 0x040a,
+ 0x3125, 0x1e36,
+ 0x3127, 0x0410,
+ 0x3128, 0x1e38,
+ 0x3129, 0x0412,
+ 0x312b, 0x1e39,
+ 0x312c, 0x0415,
+ 0x3132, 0x1e3a,
+ 0x3133, 0x041c,
+ 0x3134, 0x1e3b,
+ 0x3136, 0x041f,
+ 0x3137, 0x1e3d,
+ 0x313a, 0x0423,
+ 0x3141, 0x1e40,
+ 0x3142, 0x042b,
+ 0x314a, 0x1e41,
+ 0x314b, 0x0434,
+ 0x314f, 0x1e42,
+ 0x3151, 0x043a,
+ 0x3152, 0x1e44,
+ 0x3153, 0x043c,
+ 0x3155, 0x1e45,
+ 0x3156, 0x043f,
+ 0x315f, 0x1e46,
+ 0x3162, 0x044b,
+ 0x3164, 0x1e49,
+ 0x3165, 0x044e,
+ 0x3167, 0x1e4a,
+ 0x3169, 0x0452,
+ 0x316a, 0x1e4c,
+ 0x316b, 0x0454,
+ 0x316e, 0x1e4d,
+ 0x316f, 0x0458,
+ 0x3171, 0x1e4e,
+ 0x3172, 0x045b,
+ 0x3174, 0x1e4f,
+ 0x3178, 0x0461,
+ 0x317d, 0x1e53,
+ 0x317e, 0x0467,
+ 0x3221, 0x0468,
+ 0x3226, 0x1e54,
+ 0x3228, 0x046f,
+ 0x322c, 0x1e56,
+ 0x322d, 0x0474,
+ 0x3235, 0x1e57,
+ 0x3236, 0x047d,
+ 0x3239, 0x1e58,
+ 0x323a, 0x0481,
+ 0x3246, 0x1e59,
+ 0x3247, 0x048e,
+ 0x324e, 0x1e5a,
+ 0x3258, 0x049f,
+ 0x325e, 0x1e64,
+ 0x325f, 0x04a6,
+ 0x3260, 0x1e65,
+ 0x3261, 0x04a8,
+ 0x3262, 0x1e66,
+ 0x3264, 0x04ab,
+ 0x326f, 0x1e68,
+ 0x3270, 0x04b7,
+ 0x3273, 0x1e69,
+ 0x327d, 0x04c4,
+ 0x3321, 0x1e73,
+ 0x3323, 0x04c8,
+ 0x3324, 0x1e75,
+ 0x3328, 0x04cd,
+ 0x3329, 0x1e79,
+ 0x332a, 0x04cf,
+ 0x332e, 0x1e7a,
+ 0x332f, 0x04d4,
+ 0x3335, 0x1e7b,
+ 0x3336, 0x04db,
+ 0x3339, 0x1e7c,
+ 0x333a, 0x04df,
+ 0x333e, 0x1e7d,
+ 0x333f, 0x04e4,
+ 0x3342, 0x1e7e,
+ 0x3343, 0x04e8,
+ 0x3344, 0x1e7f,
+ 0x3345, 0x04ea,
+ 0x3346, 0x1e80,
+ 0x3347, 0x04ec,
+ 0x334d, 0x1e81,
+ 0x334e, 0x04f3,
+ 0x334f, 0x1e82,
+ 0x3350, 0x04f5,
+ 0x3352, 0x1e83,
+ 0x3353, 0x04f8,
+ 0x3359, 0x1e84,
+ 0x335a, 0x04ff,
+ 0x335b, 0x1e85,
+ 0x335c, 0x0501,
+ 0x335d, 0x1e86,
+ 0x335e, 0x0503,
+ 0x3363, 0x1e87,
+ 0x3364, 0x0509,
+ 0x3365, 0x1e88,
+ 0x3367, 0x050c,
+ 0x3368, 0x1e8a,
+ 0x3369, 0x050e,
+ 0x336b, 0x1e8b,
+ 0x336d, 0x0512,
+ 0x336f, 0x1e8d,
+ 0x3370, 0x0515,
+ 0x3371, 0x1e8e,
+ 0x3372, 0x0517,
+ 0x3373, 0x1e8f,
+ 0x3374, 0x0519,
+ 0x337a, 0x1e90,
+ 0x337c, 0x0521,
+ 0x3421, 0x1e92,
+ 0x3423, 0x0526,
+ 0x3425, 0x1e94,
+ 0x3427, 0x052a,
+ 0x342b, 0x1e96,
+ 0x342c, 0x052f,
+ 0x342f, 0x1e97,
+ 0x3430, 0x0533,
+ 0x3433, 0x1e98,
+ 0x3435, 0x0538,
+ 0x3438, 0x1e9a,
+ 0x3439, 0x053c,
+ 0x343f, 0x1e9b,
+ 0x3440, 0x0543,
+ 0x3442, 0x1e9c,
+ 0x3443, 0x0546,
+ 0x3447, 0x1e9d,
+ 0x3448, 0x054b,
+ 0x344a, 0x1e9e,
+ 0x344b, 0x054e,
+ 0x344d, 0x1e9f,
+ 0x344e, 0x0551,
+ 0x344f, 0x1ea0,
+ 0x3450, 0x0553,
+ 0x3453, 0x1ea1,
+ 0x3455, 0x0558,
+ 0x345a, 0x1ea3,
+ 0x345b, 0x055e,
+ 0x345c, 0x1ea4,
+ 0x345d, 0x0560,
+ 0x346d, 0x1ea5,
+ 0x346e, 0x0571,
+ 0x346f, 0x1ea6,
+ 0x3470, 0x0573,
+ 0x3478, 0x1ea7,
+ 0x3479, 0x057c,
+ 0x347b, 0x1ea8,
+ 0x347c, 0x057f,
+ 0x3521, 0x0582,
+ 0x3523, 0x1ea9,
+ 0x3524, 0x0585,
+ 0x3525, 0x1eaa,
+ 0x3529, 0x058a,
+ 0x352c, 0x1eae,
+ 0x352d, 0x058e,
+ 0x352e, 0x1eaf,
+ 0x3530, 0x0591,
+ 0x3531, 0x1eb1,
+ 0x3536, 0x0597,
+ 0x3537, 0x1eb6,
+ 0x3538, 0x0599,
+ 0x353a, 0x1eb7,
+ 0x353d, 0x059e,
+ 0x3546, 0x1eba,
+ 0x3547, 0x05a8,
+ 0x354b, 0x1ebb,
+ 0x354c, 0x05ad,
+ 0x3550, 0x1ebc,
+ 0x3551, 0x05b2,
+ 0x3553, 0x1ebd,
+ 0x3554, 0x05b5,
+ 0x355d, 0x1ebe,
+ 0x3560, 0x05c1,
+ 0x3563, 0x1ec1,
+ 0x3564, 0x05c5,
+ 0x3566, 0x1ec2,
+ 0x3568, 0x05c9,
+ 0x356d, 0x1ec4,
+ 0x356e, 0x05cf,
+ 0x3576, 0x1ec5,
+ 0x3578, 0x05d9,
+ 0x357d, 0x1ec7,
+ 0x357e, 0x05df,
+ 0x3621, 0x05e0,
+ 0x3624, 0x1ec8,
+ 0x3626, 0x05e5,
+ 0x3627, 0x1eca,
+ 0x3628, 0x05e7,
+ 0x3629, 0x1ecb,
+ 0x362a, 0x05e9,
+ 0x362b, 0x1ecc,
+ 0x362c, 0x05eb,
+ 0x362f, 0x1ecd,
+ 0x3631, 0x05f0,
+ 0x3633, 0x1ecf,
+ 0x3634, 0x05f3,
+ 0x3637, 0x1ed0,
+ 0x3638, 0x05f7,
+ 0x363f, 0x1ed1,
+ 0x3642, 0x0601,
+ 0x3644, 0x1ed4,
+ 0x3645, 0x0604,
+ 0x3646, 0x1ed5,
+ 0x3647, 0x0606,
+ 0x364d, 0x1ed6,
+ 0x364e, 0x060d,
+ 0x364f, 0x1ed7,
+ 0x3651, 0x0610,
+ 0x3653, 0x1ed9,
+ 0x3655, 0x0614,
+ 0x3656, 0x1edb,
+ 0x3657, 0x0616,
+ 0x3659, 0x1edc,
+ 0x365a, 0x0619,
+ 0x365b, 0x1edd,
+ 0x365c, 0x061b,
+ 0x3661, 0x1ede,
+ 0x3662, 0x0621,
+ 0x3669, 0x1edf,
+ 0x366a, 0x0629,
+ 0x366c, 0x1ee0,
+ 0x366d, 0x062c,
+ 0x366e, 0x1ee1,
+ 0x3670, 0x062f,
+ 0x3671, 0x1ee3,
+ 0x3672, 0x0631,
+ 0x3676, 0x1ee4,
+ 0x3677, 0x0636,
+ 0x3679, 0x1ee5,
+ 0x367a, 0x0639,
+ 0x367b, 0x1ee6,
+ 0x367d, 0x063c,
+ 0x3721, 0x1ee8,
+ 0x3724, 0x0641,
+ 0x3727, 0x1eeb,
+ 0x3728, 0x0645,
+ 0x372f, 0x1eec,
+ 0x3731, 0x064e,
+ 0x3733, 0x1eee,
+ 0x3734, 0x0651,
+ 0x3736, 0x1eef,
+ 0x3738, 0x0655,
+ 0x3739, 0x1ef1,
+ 0x373a, 0x0657,
+ 0x3743, 0x1ef2,
+ 0x3745, 0x0662,
+ 0x3749, 0x1ef4,
+ 0x374a, 0x0667,
+ 0x374c, 0x1ef5,
+ 0x374d, 0x066a,
+ 0x374f, 0x1ef6,
+ 0x3750, 0x066d,
+ 0x3751, 0x1ef7,
+ 0x3752, 0x066f,
+ 0x3757, 0x1ef8,
+ 0x3759, 0x0676,
+ 0x375c, 0x1efa,
+ 0x375d, 0x067a,
+ 0x375f, 0x1efb,
+ 0x3762, 0x067f,
+ 0x3763, 0x1efe,
+ 0x3764, 0x0681,
+ 0x3766, 0x1eff,
+ 0x3769, 0x0686,
+ 0x376b, 0x1f02,
+ 0x376e, 0x068b,
+ 0x376f, 0x1f05,
+ 0x3770, 0x068d,
+ 0x3774, 0x1f06,
+ 0x3775, 0x0692,
+ 0x3778, 0x1f07,
+ 0x3779, 0x0696,
+ 0x3821, 0x069c,
+ 0x3827, 0x1f08,
+ 0x3829, 0x06a4,
+ 0x3833, 0x1f0a,
+ 0x3835, 0x06b0,
+ 0x383a, 0x1f0c,
+ 0x383b, 0x06b6,
+ 0x383c, 0x1f0d,
+ 0x383d, 0x06b8,
+ 0x383e, 0x1f0e,
+ 0x3840, 0x06bb,
+ 0x3843, 0x1f10,
+ 0x3844, 0x06bf,
+ 0x3846, 0x1f11,
+ 0x3848, 0x06c3,
+ 0x3849, 0x1f13,
+ 0x384a, 0x06c5,
+ 0x384f, 0x1f14,
+ 0x3850, 0x06cb,
+ 0x3853, 0x1f15,
+ 0x3857, 0x06d2,
+ 0x3859, 0x1f19,
+ 0x385b, 0x06d6,
+ 0x3864, 0x1f1b,
+ 0x3865, 0x06e0,
+ 0x3869, 0x1f1c,
+ 0x386a, 0x06e5,
+ 0x386b, 0x1f1d,
+ 0x386c, 0x06e7,
+ 0x3873, 0x1f1e,
+ 0x3874, 0x06ef,
+ 0x3875, 0x1f1f,
+ 0x3877, 0x06f2,
+ 0x3878, 0x1f21,
+ 0x3879, 0x06f4,
+ 0x3921, 0x06fa,
+ 0x3928, 0x1f22,
+ 0x3929, 0x0702,
+ 0x392e, 0x1f23,
+ 0x392f, 0x0708,
+ 0x3931, 0x1f24,
+ 0x3932, 0x070b,
+ 0x3933, 0x1f25,
+ 0x3934, 0x070d,
+ 0x3935, 0x1f26,
+ 0x3936, 0x070f,
+ 0x3939, 0x1f27,
+ 0x393b, 0x0714,
+ 0x3946, 0x1f29,
+ 0x3947, 0x0720,
+ 0x394b, 0x1f2a,
+ 0x394c, 0x0725,
+ 0x3950, 0x1f2b,
+ 0x3951, 0x072a,
+ 0x3958, 0x1f2c,
+ 0x3959, 0x0732,
+ 0x395b, 0x1f2d,
+ 0x395c, 0x0735,
+ 0x395d, 0x1f2e,
+ 0x395e, 0x0737,
+ 0x395f, 0x1f2f,
+ 0x3960, 0x0739,
+ 0x3961, 0x1f30,
+ 0x3962, 0x073b,
+ 0x3963, 0x1f31,
+ 0x3964, 0x073d,
+ 0x3966, 0x1f32,
+ 0x3967, 0x0740,
+ 0x3969, 0x1f33,
+ 0x396d, 0x0746,
+ 0x396e, 0x1f37,
+ 0x396f, 0x0748,
+ 0x3971, 0x1f38,
+ 0x3972, 0x074b,
+ 0x3973, 0x1f39,
+ 0x3976, 0x074f,
+ 0x3978, 0x1f3c,
+ 0x3979, 0x0752,
+ 0x397a, 0x1f3d,
+ 0x397b, 0x0754,
+ 0x397d, 0x1f3e,
+ 0x397e, 0x0757,
+ 0x3a21, 0x0758,
+ 0x3a27, 0x1f3f,
+ 0x3a28, 0x075f,
+ 0x3a2b, 0x1f40,
+ 0x3a2c, 0x0763,
+ 0x3a3a, 0x1f41,
+ 0x3a3b, 0x0772,
+ 0x3a45, 0x1f42,
+ 0x3a46, 0x077d,
+ 0x3a52, 0x1f43,
+ 0x3a53, 0x078a,
+ 0x3a57, 0x1f44,
+ 0x3a59, 0x0790,
+ 0x3a64, 0x1f46,
+ 0x3a65, 0x079c,
+ 0x3a68, 0x1f47,
+ 0x3a69, 0x07a0,
+ 0x3a6c, 0x1f48,
+ 0x3a6d, 0x07a4,
+ 0x3a73, 0x15e5,
+ 0x3a74, 0x07ab,
+ 0x3a78, 0x1f49,
+ 0x3a79, 0x07b0,
+ 0x3b21, 0x07b6,
+ 0x3b24, 0x1f4a,
+ 0x3b25, 0x07ba,
+ 0x3b26, 0x1f4b,
+ 0x3b27, 0x07bc,
+ 0x3b29, 0x1f4c,
+ 0x3b2b, 0x07c0,
+ 0x3b2d, 0x1f4e,
+ 0x3b2f, 0x07c4,
+ 0x3b30, 0x1f50,
+ 0x3b31, 0x07c6,
+ 0x3b33, 0x1f51,
+ 0x3b34, 0x07c9,
+ 0x3b35, 0x1f52,
+ 0x3b38, 0x07cd,
+ 0x3b39, 0x1f55,
+ 0x3b3b, 0x07d0,
+ 0x3b51, 0x1f57,
+ 0x3b52, 0x07e7,
+ 0x3b53, 0x1f58,
+ 0x3b55, 0x07ea,
+ 0x3b5f, 0x1f5a,
+ 0x3b68, 0x07fd,
+ 0x3b6b, 0x1f63,
+ 0x3b6c, 0x0801,
+ 0x3b71, 0x1f64,
+ 0x3b72, 0x0807,
+ 0x3b75, 0x1f65,
+ 0x3b78, 0x080d,
+ 0x3b7a, 0x1f68,
+ 0x3b7b, 0x0810,
+ 0x3b7d, 0x1f69,
+ 0x3b7e, 0x0813,
+ 0x3c21, 0x0814,
+ 0x3c22, 0x1f6a,
+ 0x3c23, 0x0816,
+ 0x3c25, 0x1f6b,
+ 0x3c27, 0x081a,
+ 0x3c28, 0x1f6d,
+ 0x3c2a, 0x081d,
+ 0x3c2b, 0x1f6f,
+ 0x3c2c, 0x081f,
+ 0x3c2d, 0x1f70,
+ 0x3c2e, 0x0821,
+ 0x3c36, 0x1f71,
+ 0x3c39, 0x082c,
+ 0x3c3b, 0x1f74,
+ 0x3c3c, 0x082f,
+ 0x3c41, 0x1f75,
+ 0x3c42, 0x0835,
+ 0x3c43, 0x1f76,
+ 0x3c44, 0x0837,
+ 0x3c46, 0x1f77,
+ 0x3c48, 0x083b,
+ 0x3c4a, 0x1f79,
+ 0x3c4b, 0x083e,
+ 0x3c4c, 0x1f7a,
+ 0x3c4e, 0x0841,
+ 0x3c50, 0x1f7c,
+ 0x3c51, 0x0844,
+ 0x3c54, 0x1f7d,
+ 0x3c57, 0x084a,
+ 0x3c58, 0x1f80,
+ 0x3c59, 0x084c,
+ 0x3c5b, 0x1f81,
+ 0x3c5c, 0x084f,
+ 0x3c5d, 0x1f82,
+ 0x3c5e, 0x0851,
+ 0x3c5f, 0x1f83,
+ 0x3c62, 0x0855,
+ 0x3c63, 0x1f86,
+ 0x3c65, 0x0858,
+ 0x3c68, 0x1f88,
+ 0x3c69, 0x085c,
+ 0x3c6a, 0x1f89,
+ 0x3c6d, 0x0860,
+ 0x3c6f, 0x1f8c,
+ 0x3c74, 0x0867,
+ 0x3c76, 0x1f91,
+ 0x3c7d, 0x0870,
+ 0x3d21, 0x0872,
+ 0x3d22, 0x1f98,
+ 0x3d28, 0x0879,
+ 0x3d2b, 0x1f9e,
+ 0x3d2d, 0x087e,
+ 0x3d2f, 0x1fa0,
+ 0x3d33, 0x0884,
+ 0x3d34, 0x1fa4,
+ 0x3d35, 0x0886,
+ 0x3d3a, 0x1fa5,
+ 0x3d3b, 0x088c,
+ 0x3d3d, 0x1fa6,
+ 0x3d40, 0x0891,
+ 0x3d41, 0x1fa9,
+ 0x3d45, 0x0896,
+ 0x3d48, 0x1fad,
+ 0x3d4b, 0x089c,
+ 0x3d4e, 0x1fb0,
+ 0x3d50, 0x08a1,
+ 0x3d57, 0x1fb2,
+ 0x3d58, 0x08a9,
+ 0x3d5a, 0x1fb3,
+ 0x3d5b, 0x08ac,
+ 0x3d60, 0x1fb4,
+ 0x3d62, 0x08b3,
+ 0x3d6b, 0x1fb6,
+ 0x3d6c, 0x08bd,
+ 0x3d74, 0x1fb7,
+ 0x3d79, 0x08ca,
+ 0x3d7d, 0x1fbc,
+ 0x3d7e, 0x08cf,
+ 0x3e21, 0x1fbd,
+ 0x3e23, 0x08d2,
+ 0x3e25, 0x1fbf,
+ 0x3e26, 0x08d5,
+ 0x3e28, 0x1fc0,
+ 0x3e29, 0x08d8,
+ 0x3e2a, 0x1fc1,
+ 0x3e2b, 0x08da,
+ 0x3e2d, 0x1fc2,
+ 0x3e2e, 0x08dd,
+ 0x3e31, 0x1fc3,
+ 0x3e32, 0x08e1,
+ 0x3e35, 0x1fc4,
+ 0x3e38, 0x08e7,
+ 0x3e3a, 0x1fc7,
+ 0x3e3b, 0x08ea,
+ 0x3e40, 0x1fc8,
+ 0x3e41, 0x08f0,
+ 0x3e49, 0x1fc9,
+ 0x3e4a, 0x08f9,
+ 0x3e54, 0x1fca,
+ 0x3e55, 0x0904,
+ 0x3e59, 0x1fcb,
+ 0x3e5a, 0x0909,
+ 0x3e5d, 0x1fcc,
+ 0x3e5e, 0x090d,
+ 0x3e62, 0x1fcd,
+ 0x3e63, 0x0912,
+ 0x3e65, 0x1fce,
+ 0x3e66, 0x0915,
+ 0x3e67, 0x1fcf,
+ 0x3e68, 0x0917,
+ 0x3e69, 0x1fd0,
+ 0x3e6a, 0x0919,
+ 0x3e6e, 0x1fd1,
+ 0x3e6f, 0x091e,
+ 0x3e75, 0x1fd2,
+ 0x3e76, 0x0925,
+ 0x3e77, 0x1fd3,
+ 0x3e79, 0x0928,
+ 0x3e7b, 0x1fd5,
+ 0x3e7d, 0x092c,
+ 0x3f21, 0x092e,
+ 0x3f25, 0x1fd7,
+ 0x3f26, 0x0933,
+ 0x3f2a, 0x1fd8,
+ 0x3f2b, 0x0938,
+ 0x3f2d, 0x1fd9,
+ 0x3f2e, 0x093b,
+ 0x3f45, 0x1fda,
+ 0x3f46, 0x0953,
+ 0x3f47, 0x1fdb,
+ 0x3f48, 0x0955,
+ 0x3f4e, 0x1fdc,
+ 0x3f4f, 0x095c,
+ 0x3f51, 0x1fdd,
+ 0x3f53, 0x0960,
+ 0x3f59, 0x1fdf,
+ 0x3f5a, 0x0967,
+ 0x3f62, 0x1fe0,
+ 0x3f65, 0x0972,
+ 0x3f69, 0x1fe3,
+ 0x3f6a, 0x0977,
+ 0x3f6b, 0x1fe4,
+ 0x3f6c, 0x0979,
+ 0x3f6d, 0x1fe5,
+ 0x3f6e, 0x097b,
+ 0x3f73, 0x1fe6,
+ 0x3f74, 0x0981,
+ 0x3f75, 0x1fe7,
+ 0x3f76, 0x0983,
+ 0x3f77, 0x1fe8,
+ 0x3f78, 0x0985,
+ 0x3f79, 0x1fe9,
+ 0x3f7b, 0x0988,
+ 0x4021, 0x1feb,
+ 0x4022, 0x098d,
+ 0x4023, 0x1fec,
+ 0x4024, 0x098f,
+ 0x4029, 0x1fed,
+ 0x402a, 0x0995,
+ 0x402b, 0x1fee,
+ 0x402c, 0x0997,
+ 0x402f, 0x1fef,
+ 0x4031, 0x099c,
+ 0x4033, 0x1ff1,
+ 0x4037, 0x09a2,
+ 0x4038, 0x1ff5,
+ 0x4045, 0x09b0,
+ 0x404c, 0x2002,
+ 0x404e, 0x09b9,
+ 0x4054, 0x2004,
+ 0x4055, 0x09c0,
+ 0x4056, 0x2005,
+ 0x4057, 0x09c2,
+ 0x4058, 0x2006,
+ 0x4059, 0x09c4,
+ 0x405d, 0x2007,
+ 0x405e, 0x09c9,
+ 0x4060, 0x2008,
+ 0x4061, 0x09cc,
+ 0x4069, 0x2009,
+ 0x406a, 0x09d5,
+ 0x406b, 0x200a,
+ 0x406d, 0x09d8,
+ 0x406f, 0x200c,
+ 0x4072, 0x09dd,
+ 0x4076, 0x200f,
+ 0x407b, 0x09e6,
+ 0x4121, 0x09ea,
+ 0x4124, 0x2014,
+ 0x4126, 0x09ef,
+ 0x4129, 0x2016,
+ 0x412e, 0x09f7,
+ 0x412f, 0x201b,
+ 0x4139, 0x0a02,
+ 0x413d, 0x2025,
+ 0x413f, 0x0a08,
+ 0x4142, 0x2027,
+ 0x4143, 0x0a0c,
+ 0x4146, 0x2028,
+ 0x4147, 0x0a10,
+ 0x4149, 0x2029,
+ 0x414a, 0x0a13,
+ 0x414d, 0x202a,
+ 0x414e, 0x0a17,
+ 0x4154, 0x202b,
+ 0x4155, 0x0a1e,
+ 0x4159, 0x202c,
+ 0x415c, 0x0a25,
+ 0x415e, 0x202f,
+ 0x415f, 0x0a28,
+ 0x4164, 0x2030,
+ 0x4166, 0x0a2f,
+ 0x4169, 0x2032,
+ 0x416a, 0x0a33,
+ 0x416b, 0x2033,
+ 0x416d, 0x0a36,
+ 0x4173, 0x2035,
+ 0x4174, 0x0a3d,
+ 0x4175, 0x2036,
+ 0x4176, 0x0a3f,
+ 0x417a, 0x2037,
+ 0x417e, 0x0a47,
+ 0x4221, 0x0a48,
+ 0x4222, 0x203b,
+ 0x4229, 0x0a50,
+ 0x422b, 0x2042,
+ 0x4234, 0x0a5b,
+ 0x4238, 0x204b,
+ 0x4239, 0x0a60,
+ 0x423c, 0x204c,
+ 0x423e, 0x0a65,
+ 0x423f, 0x204e,
+ 0x4240, 0x0a67,
+ 0x4241, 0x204f,
+ 0x4242, 0x0a69,
+ 0x4245, 0x2050,
+ 0x4248, 0x0a6f,
+ 0x424b, 0x2053,
+ 0x4251, 0x0a78,
+ 0x4252, 0x2059,
+ 0x4253, 0x0a7a,
+ 0x4255, 0x205a,
+ 0x425d, 0x0a84,
+ 0x425e, 0x2062,
+ 0x4263, 0x0a8a,
+ 0x4266, 0x2067,
+ 0x4269, 0x0a90,
+ 0x426a, 0x206a,
+ 0x426f, 0x0a96,
+ 0x4270, 0x206f,
+ 0x4271, 0x0a98,
+ 0x4272, 0x2070,
+ 0x4276, 0x0a9d,
+ 0x4277, 0x2074,
+ 0x427b, 0x0aa2,
+ 0x4321, 0x2078,
+ 0x4322, 0x0aa7,
+ 0x432a, 0x2079,
+ 0x432b, 0x0ab0,
+ 0x432d, 0x207a,
+ 0x432e, 0x0ab3,
+ 0x4333, 0x207b,
+ 0x4334, 0x1df9,
+ 0x4335, 0x0aba,
+ 0x433e, 0x207c,
+ 0x433f, 0x0ac4,
+ 0x4345, 0x207d,
+ 0x4348, 0x0acd,
+ 0x434c, 0x2080,
+ 0x434d, 0x0ad2,
+ 0x434e, 0x2081,
+ 0x434f, 0x0ad4,
+ 0x4355, 0x2082,
+ 0x4357, 0x0adc,
+ 0x4359, 0x2084,
+ 0x435a, 0x0adf,
+ 0x4360, 0x2085,
+ 0x4361, 0x0ae6,
+ 0x4365, 0x2086,
+ 0x4366, 0x0aeb,
+ 0x436d, 0x2087,
+ 0x436e, 0x0af3,
+ 0x4370, 0x2088,
+ 0x4371, 0x0af6,
+ 0x4375, 0x2089,
+ 0x4377, 0x0afc,
+ 0x4379, 0x208b,
+ 0x437b, 0x0b00,
+ 0x437d, 0x208d,
+ 0x437e, 0x0b03,
+ 0x4421, 0x0b04,
+ 0x4431, 0x208e,
+ 0x4432, 0x0b15,
+ 0x4436, 0x208f,
+ 0x4437, 0x0b1a,
+ 0x4446, 0x2090,
+ 0x4447, 0x0b2a,
+ 0x4449, 0x2091,
+ 0x444a, 0x0b2d,
+ 0x4451, 0x2092,
+ 0x4452, 0x0b35,
+ 0x4453, 0x2093,
+ 0x4457, 0x0b3a,
+ 0x4459, 0x2097,
+ 0x445a, 0x0b3d,
+ 0x4462, 0x2098,
+ 0x4463, 0x0b46,
+ 0x4465, 0x2099,
+ 0x4466, 0x0b49,
+ 0x446c, 0x209a,
+ 0x446d, 0x0b50,
+ 0x4470, 0x209b,
+ 0x4472, 0x0b55,
+ 0x4474, 0x209d,
+ 0x4475, 0x0b58,
+ 0x4476, 0x209e,
+ 0x4479, 0x0b5c,
+ 0x447b, 0x20a1,
+ 0x447d, 0x0b60,
+ 0x447e, 0x20a3,
+ 0x4521, 0x20a4,
+ 0x4523, 0x0b64,
+ 0x4525, 0x20a6,
+ 0x452a, 0x0b6b,
+ 0x4531, 0x20ab,
+ 0x4532, 0x0b73,
+ 0x4535, 0x20ac,
+ 0x4536, 0x0b77,
+ 0x4537, 0x20ad,
+ 0x453a, 0x0b7b,
+ 0x453b, 0x20b0,
+ 0x453c, 0x0b7d,
+ 0x453d, 0x20b1,
+ 0x453e, 0x0b7f,
+ 0x454c, 0x20b2,
+ 0x454d, 0x0b8e,
+ 0x4553, 0x20b3,
+ 0x4554, 0x0b95,
+ 0x4562, 0x20b4,
+ 0x4563, 0x0ba4,
+ 0x4567, 0x20b5,
+ 0x4568, 0x0ba9,
+ 0x4574, 0x20b6,
+ 0x4575, 0x0bb6,
+ 0x4621, 0x0bc0,
+ 0x462d, 0x20b7,
+ 0x462f, 0x0bce,
+ 0x4635, 0x20b9,
+ 0x4637, 0x0bd6,
+ 0x463b, 0x20bb,
+ 0x463c, 0x0bdb,
+ 0x463e, 0x20bc,
+ 0x463f, 0x0bde,
+ 0x4640, 0x20bd,
+ 0x4641, 0x0be0,
+ 0x4643, 0x20be,
+ 0x4645, 0x0be4,
+ 0x464b, 0x20c0,
+ 0x464e, 0x0bed,
+ 0x4653, 0x20c3,
+ 0x4654, 0x0bf3,
+ 0x4657, 0x20c4,
+ 0x4658, 0x0bf7,
+ 0x466a, 0x20c5,
+ 0x466c, 0x0c0b,
+ 0x466f, 0x20c7,
+ 0x4670, 0x0c0f,
+ 0x4671, 0x20c8,
+ 0x4672, 0x0c11,
+ 0x4674, 0x20c9,
+ 0x4675, 0x0c14,
+ 0x4678, 0x20ca,
+ 0x4679, 0x0c18,
+ 0x467d, 0x20cb,
+ 0x467e, 0x0c1d,
+ 0x4721, 0x0c1e,
+ 0x4723, 0x20cc,
+ 0x4724, 0x0c21,
+ 0x4725, 0x20cd,
+ 0x4727, 0x0c24,
+ 0x4728, 0x20cf,
+ 0x472a, 0x0c27,
+ 0x472b, 0x20d1,
+ 0x472c, 0x0c29,
+ 0x472e, 0x20d2,
+ 0x4730, 0x0c2d,
+ 0x4733, 0x20d4,
+ 0x4736, 0x0c33,
+ 0x4739, 0x20d7,
+ 0x473b, 0x0c38,
+ 0x473d, 0x20d9,
+ 0x473f, 0x0c3c,
+ 0x4740, 0x20db,
+ 0x4741, 0x0c3e,
+ 0x4742, 0x20dc,
+ 0x4743, 0x0c40,
+ 0x4745, 0x20dd,
+ 0x4746, 0x0c43,
+ 0x4747, 0x20de,
+ 0x4749, 0x0c46,
+ 0x474c, 0x20e0,
+ 0x474d, 0x0c4a,
+ 0x474f, 0x20e1,
+ 0x4750, 0x0c4d,
+ 0x4754, 0x20e2,
+ 0x4756, 0x0c53,
+ 0x4757, 0x20e4,
+ 0x4758, 0x0c55,
+ 0x475e, 0x20e5,
+ 0x475f, 0x0c5c,
+ 0x4761, 0x20e6,
+ 0x4764, 0x0c61,
+ 0x476a, 0x20e9,
+ 0x476f, 0x0c6c,
+ 0x4777, 0x20ee,
+ 0x4779, 0x0c76,
+ 0x477b, 0x20f0,
+ 0x477c, 0x0c79,
+ 0x477d, 0x20f1,
+ 0x477e, 0x0c7b,
+ 0x4821, 0x0c7c,
+ 0x4823, 0x20f2,
+ 0x4824, 0x0c7f,
+ 0x4827, 0x20f3,
+ 0x4829, 0x0c84,
+ 0x4830, 0x20f5,
+ 0x4831, 0x0c8c,
+ 0x4835, 0x20f6,
+ 0x4836, 0x0c91,
+ 0x4837, 0x20f7,
+ 0x4838, 0x0c93,
+ 0x4843, 0x20f8,
+ 0x4847, 0x0ca2,
+ 0x4848, 0x20fc,
+ 0x4849, 0x0ca4,
+ 0x484d, 0x20fd,
+ 0x484e, 0x0ca9,
+ 0x484f, 0x20fe,
+ 0x4850, 0x0cab,
+ 0x4852, 0x20ff,
+ 0x4853, 0x0cae,
+ 0x4859, 0x2100,
+ 0x485a, 0x0cb5,
+ 0x485e, 0x2101,
+ 0x485f, 0x0cba,
+ 0x486d, 0x2102,
+ 0x486e, 0x0cc9,
+ 0x4871, 0x2103,
+ 0x4874, 0x0ccf,
+ 0x4877, 0x2106,
+ 0x4879, 0x0cd4,
+ 0x487a, 0x2108,
+ 0x487b, 0x0cd6,
+ 0x487c, 0x2109,
+ 0x487d, 0x0cd8,
+ 0x4921, 0x210a,
+ 0x4922, 0x0cdb,
+ 0x4925, 0x210b,
+ 0x4926, 0x0cdf,
+ 0x4927, 0x210c,
+ 0x4929, 0x0ce2,
+ 0x492c, 0x210e,
+ 0x492d, 0x0ce6,
+ 0x4931, 0x210f,
+ 0x4932, 0x0ceb,
+ 0x4934, 0x2110,
+ 0x4935, 0x0cee,
+ 0x4938, 0x2111,
+ 0x493a, 0x0cf3,
+ 0x4941, 0x2113,
+ 0x4943, 0x0cfc,
+ 0x4944, 0x2115,
+ 0x4945, 0x0cfe,
+ 0x4949, 0x2116,
+ 0x494a, 0x0d03,
+ 0x494b, 0x2117,
+ 0x494c, 0x0d05,
+ 0x494d, 0x2118,
+ 0x494e, 0x0d07,
+ 0x4955, 0x2119,
+ 0x4956, 0x0d0f,
+ 0x495c, 0x211a,
+ 0x495d, 0x0d16,
+ 0x495e, 0x211b,
+ 0x495f, 0x0d18,
+ 0x4961, 0x211c,
+ 0x4962, 0x0d1b,
+ 0x4963, 0x211d,
+ 0x4964, 0x0d1d,
+ 0x4965, 0x211e,
+ 0x4966, 0x0d1f,
+ 0x4968, 0x211f,
+ 0x4969, 0x0d22,
+ 0x4970, 0x2120,
+ 0x4971, 0x0d2a,
+ 0x4973, 0x2121,
+ 0x4975, 0x0d2e,
+ 0x4976, 0x2123,
+ 0x4977, 0x0d30,
+ 0x4978, 0x2124,
+ 0x497a, 0x0d33,
+ 0x497e, 0x2126,
+ 0x4a21, 0x0d38,
+ 0x4a24, 0x2127,
+ 0x4a27, 0x0d3e,
+ 0x4a28, 0x212a,
+ 0x4a29, 0x0d40,
+ 0x4a2a, 0x212b,
+ 0x4a2c, 0x0d43,
+ 0x4a31, 0x212d,
+ 0x4a32, 0x0d49,
+ 0x4a34, 0x212e,
+ 0x4a37, 0x0d4e,
+ 0x4a3b, 0x2131,
+ 0x4a3c, 0x0d53,
+ 0x4a46, 0x2132,
+ 0x4a47, 0x0d5e,
+ 0x4a4a, 0x2133,
+ 0x4a4b, 0x0d62,
+ 0x4a4d, 0x2134,
+ 0x4a4f, 0x0d66,
+ 0x4a53, 0x2136,
+ 0x4a55, 0x0d6c,
+ 0x4a59, 0x2138,
+ 0x4a5a, 0x0d71,
+ 0x4a5e, 0x2139,
+ 0x4a5f, 0x0d76,
+ 0x4a60, 0x213a,
+ 0x4a61, 0x0d78,
+ 0x4a64, 0x213b,
+ 0x4a65, 0x0d7c,
+ 0x4a69, 0x213c,
+ 0x4a6b, 0x0d82,
+ 0x4a74, 0x213e,
+ 0x4a76, 0x0d8d,
+ 0x4a77, 0x2140,
+ 0x4a78, 0x0d8f,
+ 0x4a7a, 0x2141,
+ 0x4a7b, 0x0d92,
+ 0x4a7d, 0x2142,
+ 0x4a7e, 0x0d95,
+ 0x4b21, 0x0d96,
+ 0x4b27, 0x2143,
+ 0x4b28, 0x0d9d,
+ 0x4b2b, 0x2144,
+ 0x4b2c, 0x0da1,
+ 0x4b2d, 0x2145,
+ 0x4b2e, 0x0da3,
+ 0x4b33, 0x2146,
+ 0x4b34, 0x0da9,
+ 0x4b35, 0x2147,
+ 0x4b37, 0x0dac,
+ 0x4b38, 0x2149,
+ 0x4b39, 0x0dae,
+ 0x4b3f, 0x214a,
+ 0x4b40, 0x0db5,
+ 0x4b47, 0x214b,
+ 0x4b48, 0x0dbd,
+ 0x4b49, 0x214c,
+ 0x4b4d, 0x0dc2,
+ 0x4b4f, 0x2150,
+ 0x4b51, 0x0dc6,
+ 0x4b53, 0x2152,
+ 0x4b54, 0x0dc9,
+ 0x4b55, 0x2153,
+ 0x4b56, 0x0dcb,
+ 0x4b5f, 0x2154,
+ 0x4b61, 0x0dd6,
+ 0x4b64, 0x2156,
+ 0x4b65, 0x0dda,
+ 0x4b66, 0x2157,
+ 0x4b68, 0x0ddd,
+ 0x4b6a, 0x2159,
+ 0x4b6b, 0x0de0,
+ 0x4b6f, 0x215a,
+ 0x4b71, 0x0de6,
+ 0x4b75, 0x215c,
+ 0x4b77, 0x0dec,
+ 0x4b78, 0x215e,
+ 0x4b79, 0x0dee,
+ 0x4c21, 0x215f,
+ 0x4c23, 0x0df6,
+ 0x4c28, 0x2161,
+ 0x4c29, 0x0dfc,
+ 0x4c2c, 0x2162,
+ 0x4c2d, 0x0e00,
+ 0x4c2f, 0x2163,
+ 0x4c34, 0x0e07,
+ 0x4c37, 0x2168,
+ 0x4c39, 0x0e0c,
+ 0x4c3e, 0x216a,
+ 0x4c3f, 0x0e12,
+ 0x4c40, 0x216b,
+ 0x4c41, 0x0e14,
+ 0x4c4c, 0x216c,
+ 0x4c4d, 0x0e20,
+ 0x4c4e, 0x216d,
+ 0x4c4f, 0x0e22,
+ 0x4c50, 0x216e,
+ 0x4c51, 0x0e24,
+ 0x4c56, 0x216f,
+ 0x4c57, 0x0e2a,
+ 0x4c5a, 0x2170,
+ 0x4c5b, 0x0e2e,
+ 0x4c5c, 0x2171,
+ 0x4c5d, 0x0e30,
+ 0x4c60, 0x2172,
+ 0x4c61, 0x0e34,
+ 0x4c62, 0x2173,
+ 0x4c63, 0x0e36,
+ 0x4c65, 0x2174,
+ 0x4c66, 0x0e39,
+ 0x4c75, 0x2175,
+ 0x4c76, 0x0e49,
+ 0x4c79, 0x2176,
+ 0x4c7b, 0x0e4e,
+ 0x4c7c, 0x2178,
+ 0x4d21, 0x0e52,
+ 0x4d2d, 0x217b,
+ 0x4d2e, 0x0e5f,
+ 0x4d33, 0x217c,
+ 0x4d34, 0x0e65,
+ 0x4d37, 0x217d,
+ 0x4d38, 0x0e69,
+ 0x4d3c, 0x217e,
+ 0x4d3d, 0x0e6e,
+ 0x4d3f, 0x217f,
+ 0x4d40, 0x0e71,
+ 0x4d45, 0x2180,
+ 0x4d46, 0x0e77,
+ 0x4d47, 0x2181,
+ 0x4d48, 0x0e79,
+ 0x4d52, 0x2182,
+ 0x4d53, 0x0e84,
+ 0x4d54, 0x2183,
+ 0x4d57, 0x0e88,
+ 0x4d5d, 0x2186,
+ 0x4d5e, 0x0e8f,
+ 0x4d60, 0x2187,
+ 0x4d61, 0x0e92,
+ 0x4d64, 0x2188,
+ 0x4d66, 0x0e97,
+ 0x4d67, 0x218a,
+ 0x4d68, 0x0e99,
+ 0x4d72, 0x218b,
+ 0x4d73, 0x0ea4,
+ 0x4d78, 0x218c,
+ 0x4d79, 0x0eaa,
+ 0x4e21, 0x0eb0,
+ 0x4e24, 0x218d,
+ 0x4e26, 0x0eb5,
+ 0x4e27, 0x218f,
+ 0x4e28, 0x0eb7,
+ 0x4e2a, 0x2190,
+ 0x4e2e, 0x0ebd,
+ 0x4e30, 0x2194,
+ 0x4e32, 0x0ec1,
+ 0x4e33, 0x2196,
+ 0x4e34, 0x0ec3,
+ 0x4e3d, 0x2197,
+ 0x4e3e, 0x0ecd,
+ 0x4e40, 0x2198,
+ 0x4e41, 0x0ed0,
+ 0x4e45, 0x2199,
+ 0x4e47, 0x0ed6,
+ 0x4e48, 0x219b,
+ 0x4e49, 0x0ed8,
+ 0x4e4a, 0x219c,
+ 0x4e4b, 0x0eda,
+ 0x4e4e, 0x219d,
+ 0x4e52, 0x0ee1,
+ 0x4e58, 0x21a1,
+ 0x4e5b, 0x0eea,
+ 0x4e5c, 0x21a4,
+ 0x4e5d, 0x0eec,
+ 0x4e5e, 0x21a5,
+ 0x4e60, 0x0eef,
+ 0x4e6b, 0x21a7,
+ 0x4e6c, 0x0efb,
+ 0x4e6d, 0x21a8,
+ 0x4e6e, 0x0efd,
+ 0x4e71, 0x21a9,
+ 0x4e72, 0x0f01,
+ 0x4e73, 0x21aa,
+ 0x4e74, 0x0f03,
+ 0x4e7d, 0x21ab,
+ 0x4f21, 0x0f0e,
+ 0x4f2e, 0x21ad,
+ 0x4f2f, 0x0f1c,
+ 0x4f30, 0x21ae,
+ 0x4f31, 0x0f1e,
+ 0x4f33, 0x21af,
+ 0x4f34, 0x0f21,
+ 0x4f37, 0x21b0,
+ 0x4f39, 0x0f26,
+ 0x4f3a, 0x21b2,
+ 0x4f3b, 0x0f28,
+ 0x4f3d, 0x21b3,
+ 0x4f3e, 0x0f2b,
+ 0x4f3f, 0x21b4,
+ 0x4f42, 0x0f2f,
+ 0x4f45, 0x21b7,
+ 0x4f46, 0x0f33,
+ 0x4f47, 0x21b8,
+ 0x4f48, 0x0f35,
+ 0x4f4a, 0x21b9,
+ 0x4f4c, 0x0f39,
+ 0x4f4d, 0x21bb,
+ 0x4f4f, 0x0f3c,
+ 0x4f50, 0x21bd,
+ 0x4f51, 0x0f3e,
+ 0x4f54, 0x21be,
+ 0x4f59, 0x0f46,
+ 0x4f5a, 0x21c3,
+ 0x4f5b, 0x0f48,
+ 0x4f5c, 0x21c4,
+ 0x4f5d, 0x0f4a,
+ 0x4f5f, 0x21c5,
+ 0x4f60, 0x0f4d,
+ 0x4f62, 0x21c6,
+ 0x4f63, 0x0f50,
+ 0x4f67, 0x21c7,
+ 0x4f68, 0x0f55,
+ 0x4f6a, 0x21c8,
+ 0x4f6b, 0x0f58,
+ 0x4f6c, 0x21c9,
+ 0x4f6d, 0x0f5a,
+ 0x4f6e, 0x21ca,
+ 0x4f6f, 0x0f5c,
+ 0x4f74, 0x21cb,
+ 0x4f75, 0x0f62,
+ 0x4f79, 0x21cc,
+ 0x4f7b, 0x0f68,
+ 0x4f7e, 0x21ce,
+ 0x5021, 0x0f6c,
+ 0x5025, 0x21cf,
+ 0x5026, 0x0f71,
+ 0x502d, 0x21d0,
+ 0x502f, 0x0f7a,
+ 0x5032, 0x21d2,
+ 0x5035, 0x0f80,
+ 0x503a, 0x21d5,
+ 0x503c, 0x0f87,
+ 0x503f, 0x21d7,
+ 0x5040, 0x0f8b,
+ 0x5046, 0x21d8,
+ 0x5047, 0x0f92,
+ 0x504b, 0x21d9,
+ 0x504c, 0x0f97,
+ 0x5062, 0x21da,
+ 0x5063, 0x0fae,
+ 0x5065, 0x21db,
+ 0x5066, 0x0fb1,
+ 0x506b, 0x21dc,
+ 0x506c, 0x0fb7,
+ 0x506d, 0x21dd,
+ 0x506e, 0x0fb9,
+ 0x5077, 0x21de,
+ 0x507a, 0x0fc5,
+ 0x507c, 0x21e1,
+ 0x507d, 0x0fc8,
+ 0x5121, 0x21e2,
+ 0x5123, 0x0fcc,
+ 0x5124, 0x21e4,
+ 0x5125, 0x0fce,
+ 0x5127, 0x21e5,
+ 0x5128, 0x0fd1,
+ 0x512b, 0x21e6,
+ 0x512c, 0x0fd5,
+ 0x512f, 0x21e7,
+ 0x5132, 0x0fdb,
+ 0x5135, 0x21ea,
+ 0x5138, 0x0fe1,
+ 0x5139, 0x21ed,
+ 0x513a, 0x0fe3,
+ 0x513b, 0x21ee,
+ 0x513d, 0x0fe6,
+ 0x5146, 0x21f0,
+ 0x5149, 0x0ff2,
+ 0x514b, 0x21f3,
+ 0x514c, 0x0ff5,
+ 0x514e, 0x21f4,
+ 0x5150, 0x0ff9,
+ 0x5155, 0x21f6,
+ 0x5157, 0x1000,
+ 0x515e, 0x21f8,
+ 0x515f, 0x1008,
+ 0x5161, 0x21f9,
+ 0x5163, 0x100c,
+ 0x5168, 0x21fb,
+ 0x516a, 0x1013,
+ 0x516c, 0x21fd,
+ 0x516d, 0x1016,
+ 0x516e, 0x21fe,
+ 0x5170, 0x1019,
+ 0x5171, 0x2200,
+ 0x5172, 0x101b,
+ 0x5174, 0x2201,
+ 0x5175, 0x101e,
+ 0x5177, 0x2202,
+ 0x517a, 0x1023,
+ 0x5221, 0x1028,
+ 0x5222, 0x2205,
+ 0x5223, 0x102a,
+ 0x5225, 0x2206,
+ 0x5226, 0x102d,
+ 0x5229, 0x2207,
+ 0x522a, 0x1031,
+ 0x522f, 0x2208,
+ 0x5230, 0x1037,
+ 0x5233, 0x2209,
+ 0x5234, 0x103b,
+ 0x5235, 0x220a,
+ 0x5237, 0x103e,
+ 0x523d, 0x220c,
+ 0x523e, 0x1045,
+ 0x523f, 0x220d,
+ 0x5240, 0x1047,
+ 0x5243, 0x220e,
+ 0x5244, 0x104b,
+ 0x5245, 0x220f,
+ 0x5246, 0x104d,
+ 0x5247, 0x2210,
+ 0x5248, 0x104f,
+ 0x524f, 0x2211,
+ 0x5250, 0x1057,
+ 0x5255, 0x2212,
+ 0x5256, 0x105d,
+ 0x525a, 0x2213,
+ 0x525b, 0x1062,
+ 0x5264, 0x2214,
+ 0x5266, 0x106d,
+ 0x5268, 0x2216,
+ 0x526c, 0x1073,
+ 0x526f, 0x221a,
+ 0x5270, 0x1077,
+ 0x5271, 0x221b,
+ 0x5272, 0x1079,
+ 0x5275, 0x221c,
+ 0x5276, 0x107d,
+ 0x5278, 0x221d,
+ 0x5279, 0x1080,
+ 0x527b, 0x221e,
+ 0x527c, 0x1083,
+ 0x527e, 0x221f,
+ 0x5321, 0x1086,
+ 0x5323, 0x2220,
+ 0x532d, 0x1092,
+ 0x532e, 0x222a,
+ 0x532f, 0x1094,
+ 0x5331, 0x222b,
+ 0x5332, 0x1097,
+ 0x5334, 0x222c,
+ 0x5337, 0x109c,
+ 0x5338, 0x222f,
+ 0x5339, 0x109e,
+ 0x533b, 0x2230,
+ 0x533c, 0x10a1,
+ 0x5345, 0x2231,
+ 0x5346, 0x10ab,
+ 0x5347, 0x2232,
+ 0x5348, 0x10ad,
+ 0x534a, 0x2233,
+ 0x534d, 0x10b2,
+ 0x5355, 0x2236,
+ 0x5356, 0x10bb,
+ 0x535f, 0x2237,
+ 0x5361, 0x10c6,
+ 0x5363, 0x2239,
+ 0x5364, 0x10c9,
+ 0x5366, 0x223a,
+ 0x5367, 0x10cc,
+ 0x536b, 0x223b,
+ 0x536d, 0x10d2,
+ 0x536f, 0x223d,
+ 0x5370, 0x10d5,
+ 0x5374, 0x223e,
+ 0x5375, 0x10da,
+ 0x537c, 0x223f,
+ 0x537d, 0x10e2,
+ 0x537e, 0x2240,
+ 0x5421, 0x10e4,
+ 0x5424, 0x2241,
+ 0x5425, 0x10e8,
+ 0x5426, 0x2242,
+ 0x5429, 0x10ec,
+ 0x542f, 0x2245,
+ 0x5433, 0x10f6,
+ 0x5435, 0x2249,
+ 0x5437, 0x10fa,
+ 0x5438, 0x224b,
+ 0x5439, 0x10fc,
+ 0x543c, 0x224c,
+ 0x543d, 0x1100,
+ 0x543e, 0x224d,
+ 0x5440, 0x1103,
+ 0x5444, 0x224f,
+ 0x5445, 0x1108,
+ 0x5446, 0x2250,
+ 0x5448, 0x110b,
+ 0x5449, 0x2252,
+ 0x544a, 0x110d,
+ 0x544b, 0x2253,
+ 0x544f, 0x1112,
+ 0x5453, 0x2257,
+ 0x5454, 0x1117,
+ 0x5458, 0x2258,
+ 0x5459, 0x111c,
+ 0x545c, 0x2259,
+ 0x5461, 0x1124,
+ 0x5464, 0x225e,
+ 0x5465, 0x1128,
+ 0x5466, 0x225f,
+ 0x5467, 0x112a,
+ 0x546e, 0x2260,
+ 0x546f, 0x1132,
+ 0x5470, 0x2261,
+ 0x5475, 0x1138,
+ 0x5479, 0x2266,
+ 0x547a, 0x113d,
+ 0x547e, 0x2267,
+ 0x5521, 0x2268,
+ 0x5523, 0x1144,
+ 0x5529, 0x226a,
+ 0x552a, 0x114b,
+ 0x552b, 0x226b,
+ 0x552c, 0x114d,
+ 0x552e, 0x226c,
+ 0x552f, 0x1150,
+ 0x5531, 0x226d,
+ 0x5532, 0x1153,
+ 0x5535, 0x226e,
+ 0x5539, 0x115a,
+ 0x553b, 0x2272,
+ 0x553c, 0x115d,
+ 0x553d, 0x2273,
+ 0x553e, 0x115f,
+ 0x5540, 0x2274,
+ 0x5541, 0x1162,
+ 0x5545, 0x2275,
+ 0x5546, 0x1167,
+ 0x5547, 0x2276,
+ 0x5548, 0x1169,
+ 0x554a, 0x2277,
+ 0x554c, 0x116d,
+ 0x554d, 0x2279,
+ 0x554e, 0x116f,
+ 0x5554, 0x227a,
+ 0x5555, 0x1176,
+ 0x555d, 0x227b,
+ 0x555f, 0x1180,
+ 0x5560, 0x227d,
+ 0x5561, 0x1182,
+ 0x5562, 0x227e,
+ 0x5563, 0x1184,
+ 0x556a, 0x227f,
+ 0x556d, 0x118e,
+ 0x556f, 0x2282,
+ 0x5570, 0x1191,
+ 0x5572, 0x2283,
+ 0x5574, 0x1195,
+ 0x5577, 0x15eb,
+ 0x5578, 0x1199,
+ 0x5621, 0x2285,
+ 0x5625, 0x11a4,
+ 0x562f, 0x2289,
+ 0x5631, 0x11b0,
+ 0x5634, 0x228b,
+ 0x5635, 0x11b4,
+ 0x563b, 0x228c,
+ 0x563c, 0x11bb,
+ 0x563d, 0x228d,
+ 0x563e, 0x11bd,
+ 0x563f, 0x228e,
+ 0x5641, 0x11c0,
+ 0x5644, 0x2290,
+ 0x5645, 0x11c4,
+ 0x564a, 0x2291,
+ 0x564b, 0x11ca,
+ 0x564d, 0x2292,
+ 0x564e, 0x11cd,
+ 0x5653, 0x2293,
+ 0x5654, 0x11d3,
+ 0x5655, 0x2294,
+ 0x5658, 0x11d7,
+ 0x565a, 0x2297,
+ 0x565b, 0x11da,
+ 0x565f, 0x2298,
+ 0x5660, 0x11df,
+ 0x5661, 0x2299,
+ 0x5662, 0x11e1,
+ 0x5665, 0x229a,
+ 0x5666, 0x11e5,
+ 0x5667, 0x229b,
+ 0x5669, 0x11e8,
+ 0x566e, 0x229d,
+ 0x5670, 0x11ef,
+ 0x5672, 0x229f,
+ 0x5673, 0x11f2,
+ 0x5675, 0x22a0,
+ 0x5677, 0x11f6,
+ 0x567c, 0x22a2,
+ 0x5721, 0x11fe,
+ 0x5724, 0x22a5,
+ 0x5725, 0x1202,
+ 0x5728, 0x22a6,
+ 0x572b, 0x1208,
+ 0x572c, 0x22a9,
+ 0x572d, 0x120a,
+ 0x572e, 0x22aa,
+ 0x5732, 0x120f,
+ 0x5733, 0x22ae,
+ 0x5735, 0x1212,
+ 0x5736, 0x22b0,
+ 0x5737, 0x1214,
+ 0x5738, 0x22b1,
+ 0x573d, 0x121a,
+ 0x5747, 0x22b6,
+ 0x5748, 0x1225,
+ 0x574a, 0x22b7,
+ 0x574b, 0x1228,
+ 0x5755, 0x22b8,
+ 0x5756, 0x1233,
+ 0x575b, 0x22b9,
+ 0x575f, 0x123c,
+ 0x5767, 0x22bd,
+ 0x5768, 0x1245,
+ 0x5769, 0x22be,
+ 0x576b, 0x1248,
+ 0x5821, 0x1257,
+ 0x5844, 0x22c0,
+ 0x5845, 0x127b,
+ 0x5847, 0x22c1,
+ 0x5848, 0x127e,
+ 0x5849, 0x22c2,
+ 0x584a, 0x1280,
+ 0x584c, 0x22c3,
+ 0x584e, 0x1284,
+ 0x5850, 0x22c5,
+ 0x5852, 0x1288,
+ 0x5853, 0x22c7,
+ 0x5854, 0x128a,
+ 0x5859, 0x22c8,
+ 0x585a, 0x1290,
+ 0x585b, 0x22c9,
+ 0x585d, 0x1293,
+ 0x5871, 0x22cb,
+ 0x5872, 0x12a8,
+ 0x5876, 0x22cc,
+ 0x5878, 0x12ae,
+ 0x5921, 0x12b5,
+ 0x592d, 0x22ce,
+ 0x592e, 0x12c2,
+ 0x592f, 0x22cf,
+ 0x5930, 0x12c4,
+ 0x5931, 0x22d0,
+ 0x5934, 0x12c8,
+ 0x5947, 0x22d3,
+ 0x5948, 0x12dc,
+ 0x594d, 0x22d4,
+ 0x5951, 0x12e5,
+ 0x595d, 0x22d8,
+ 0x595e, 0x12f2,
+ 0x5961, 0x22d9,
+ 0x5962, 0x12f6,
+ 0x5964, 0x22da,
+ 0x5965, 0x12f9,
+ 0x5966, 0x22db,
+ 0x5967, 0x12fb,
+ 0x596c, 0x22dc,
+ 0x596d, 0x1301,
+ 0x5974, 0x22dd,
+ 0x5976, 0x130a,
+ 0x5a21, 0x1313,
+ 0x5a25, 0x22df,
+ 0x5a60, 0x1352,
+ 0x5a6a, 0x231a,
+ 0x5a6b, 0x135d,
+ 0x5a77, 0x231b,
+ 0x5a78, 0x136a,
+ 0x5a79, 0x231c,
+ 0x5a7a, 0x136c,
+ 0x5a7e, 0x231d,
+ 0x5b21, 0x1371,
+ 0x5b23, 0x231e,
+ 0x5b24, 0x1374,
+ 0x5b26, 0x231f,
+ 0x5b27, 0x1377,
+ 0x5b29, 0x2320,
+ 0x5b2b, 0x137b,
+ 0x5b3b, 0x2322,
+ 0x5b3c, 0x138c,
+ 0x5b3d, 0x2323,
+ 0x5b3e, 0x138e,
+ 0x5b4f, 0x2324,
+ 0x5b50, 0x13a0,
+ 0x5b51, 0x2325,
+ 0x5b52, 0x13a2,
+ 0x5b5b, 0x2326,
+ 0x5b5c, 0x13ac,
+ 0x5b5e, 0x2327,
+ 0x5b5f, 0x13af,
+ 0x5b62, 0x2328,
+ 0x5b63, 0x13b3,
+ 0x5b64, 0x2329,
+ 0x5b65, 0x13b5,
+ 0x5b6b, 0x232a,
+ 0x5b6c, 0x13bc,
+ 0x5b6e, 0x232b,
+ 0x5b6f, 0x13bf,
+ 0x5b71, 0x232c,
+ 0x5b72, 0x13c2,
+ 0x5b75, 0x232d,
+ 0x5b78, 0x13c8,
+ 0x5c21, 0x13cf,
+ 0x5c3c, 0x2330,
+ 0x5c3d, 0x13eb,
+ 0x5c3f, 0x2331,
+ 0x5c40, 0x13ee,
+ 0x5c42, 0x2332,
+ 0x5c43, 0x13f1,
+ 0x5c48, 0x2333,
+ 0x5c4b, 0x13f9,
+ 0x5c51, 0x2336,
+ 0x5c52, 0x1400,
+ 0x5c57, 0x2337,
+ 0x5c58, 0x1406,
+ 0x5c60, 0x2338,
+ 0x5c61, 0x140f,
+ 0x5c63, 0x2339,
+ 0x5c65, 0x1413,
+ 0x5c69, 0x233b,
+ 0x5c6b, 0x1419,
+ 0x5c71, 0x233d,
+ 0x5c72, 0x1420,
+ 0x5c76, 0x233e,
+ 0x5c77, 0x1425,
+ 0x5c79, 0x233f,
+ 0x5c7a, 0x1428,
+ 0x5c7d, 0x2340,
+ 0x5d21, 0x2342,
+ 0x5d22, 0x142e,
+ 0x5d23, 0x2343,
+ 0x5d28, 0x1434,
+ 0x5d2a, 0x2348,
+ 0x5d2c, 0x1438,
+ 0x5d32, 0x234a,
+ 0x5d33, 0x143f,
+ 0x5d35, 0x234b,
+ 0x5d36, 0x1442,
+ 0x5d3a, 0x234c,
+ 0x5d3c, 0x1448,
+ 0x5d53, 0x234e,
+ 0x5d54, 0x1460,
+ 0x5d5b, 0x234f,
+ 0x5d5c, 0x1468,
+ 0x5d5e, 0x2350,
+ 0x5d5f, 0x146b,
+ 0x5d64, 0x2351,
+ 0x5d65, 0x1471,
+ 0x5d6b, 0x2352,
+ 0x5d6c, 0x1478,
+ 0x5d71, 0x2353,
+ 0x5d72, 0x147e,
+ 0x5d76, 0x2354,
+ 0x5d78, 0x1484,
+ 0x5d7c, 0x2356,
+ 0x5d7d, 0x1489,
+ 0x5d7e, 0x2357,
+ 0x5e21, 0x148b,
+ 0x5e2d, 0x2358,
+ 0x5e2e, 0x1498,
+ 0x5e34, 0x2359,
+ 0x5e35, 0x149f,
+ 0x5e3a, 0x235a,
+ 0x5e3b, 0x14a5,
+ 0x5e46, 0x235b,
+ 0x5e47, 0x14b1,
+ 0x5e4f, 0x235c,
+ 0x5e50, 0x14ba,
+ 0x5e51, 0x235d,
+ 0x5e53, 0x14bd,
+ 0x5e58, 0x235f,
+ 0x5e59, 0x14c3,
+ 0x5e62, 0x2360,
+ 0x5e63, 0x14cd,
+ 0x5e68, 0x2361,
+ 0x5e69, 0x14d3,
+ 0x5e6c, 0x2362,
+ 0x5e6d, 0x14d7,
+ 0x5e73, 0x2363,
+ 0x5e74, 0x14de,
+ 0x5e7c, 0x2364,
+ 0x5e7d, 0x14e7,
+ 0x5f21, 0x14e9,
+ 0x5f22, 0x2365,
+ 0x5f24, 0x14ec,
+ 0x5f25, 0x2367,
+ 0x5f26, 0x14ee,
+ 0x5f34, 0x2368,
+ 0x5f35, 0x14fd,
+ 0x5f3c, 0x2369,
+ 0x5f3e, 0x1506,
+ 0x5f3f, 0x236b,
+ 0x5f40, 0x1508,
+ 0x5f42, 0x236c,
+ 0x5f44, 0x150c,
+ 0x5f4c, 0x236e,
+ 0x5f4d, 0x1515,
+ 0x5f50, 0x236f,
+ 0x5f51, 0x1519,
+ 0x5f55, 0x2370,
+ 0x5f56, 0x151e,
+ 0x5f58, 0x2371,
+ 0x5f5a, 0x1522,
+ 0x5f5c, 0x2373,
+ 0x5f5d, 0x1525,
+ 0x5f60, 0x2374,
+ 0x5f61, 0x1529,
+ 0x5f62, 0x2375,
+ 0x5f63, 0x152b,
+ 0x5f66, 0x2376,
+ 0x5f67, 0x152f,
+ 0x5f69, 0x2377,
+ 0x5f6a, 0x1532,
+ 0x5f6b, 0x2378,
+ 0x5f6c, 0x1534,
+ 0x5f6f, 0x2379,
+ 0x5f70, 0x1538,
+ 0x5f75, 0x237a,
+ 0x5f76, 0x153e,
+ 0x5f79, 0x237b,
+ 0x5f7a, 0x1542,
+ 0x6021, 0x1547,
+ 0x6036, 0x237c,
+ 0x6038, 0x155e,
+ 0x603f, 0x237e,
+ 0x6040, 0x1566,
+ 0x6048, 0x237f,
+ 0x6049, 0x156f,
+ 0x604e, 0x2380,
+ 0x604f, 0x1575,
+ 0x6053, 0x2381,
+ 0x6054, 0x157a,
+ 0x6060, 0x2382,
+ 0x6061, 0x1587,
+ 0x6070, 0x2383,
+ 0x6071, 0x1597,
+ 0x6078, 0x2384,
+ 0x6079, 0x159f,
+ 0x607c, 0x2385,
+ 0x6121, 0x15a5,
+ 0x612b, 0x2388,
+ 0x612c, 0x15b0,
+ 0x612d, 0x2389,
+ 0x612e, 0x15b2,
+ 0x6130, 0x238a,
+ 0x6131, 0x15b5,
+ 0x6134, 0x238b,
+ 0x6135, 0x15b9,
+ 0x613b, 0x238c,
+ 0x613c, 0x15c0,
+ 0x613d, 0x238d,
+ 0x613e, 0x15c2,
+ 0x6140, 0x238e,
+ 0x6142, 0x15c6,
+ 0x6149, 0x2390,
+ 0x614a, 0x15ce,
+ 0x6150, 0x2391,
+ 0x6151, 0x15d5,
+ 0x615b, 0x2392,
+ 0x615c, 0x15e0,
+ 0x6161, 0x07aa,
+ 0x6162, 0x2393,
+ 0x6163, 0x15e7,
+ 0x6167, 0x1198,
+ 0x6168, 0x15ec,
+ 0x616e, 0x2394,
+ 0x6170, 0x15f4,
+ 0x6176, 0x2396,
+ 0x6177, 0x15fb,
+ 0x6178, 0x2397,
+ 0x6179, 0x15fd,
+ 0x617d, 0x2398,
+ 0x617e, 0x1602,
+ 0x6221, 0x1603,
+ 0x6224, 0x2399,
+ 0x6225, 0x1607,
+ 0x6228, 0x239a,
+ 0x6229, 0x160b,
+ 0x623b, 0x239b,
+ 0x6245, 0x10c5,
+ 0x6246, 0x23a5,
+ 0x624f, 0x1631,
+ 0x6250, 0x23ae,
+ 0x6251, 0x1633,
+ 0x6259, 0x23af,
+ 0x625a, 0x163c,
+ 0x6263, 0x23b0,
+ 0x6265, 0x1647,
+ 0x6266, 0x23b2,
+ 0x6267, 0x1649,
+ 0x6269, 0x23b3,
+ 0x626c, 0x164e,
+ 0x6278, 0x23b6,
+ 0x6279, 0x165b,
+ 0x627a, 0x23b7,
+ 0x627e, 0x1660,
+ 0x6321, 0x1661,
+ 0x6322, 0x23bb,
+ 0x6323, 0x1663,
+ 0x6325, 0x23bc,
+ 0x6326, 0x1666,
+ 0x632b, 0x23bd,
+ 0x632c, 0x166c,
+ 0x6334, 0x23be,
+ 0x6335, 0x1675,
+ 0x6345, 0x23bf,
+ 0x635c, 0x169c,
+ 0x6363, 0x23d6,
+ 0x6364, 0x16a4,
+ 0x636d, 0x23d7,
+ 0x636e, 0x16ae,
+ 0x6371, 0x23d8,
+ 0x6373, 0x16b3,
+ 0x6378, 0x23da,
+ 0x6379, 0x16b9,
+ 0x637e, 0x23db,
+ 0x6421, 0x16bf,
+ 0x6424, 0x23dc,
+ 0x6426, 0x16c4,
+ 0x642b, 0x23de,
+ 0x642c, 0x16ca,
+ 0x642f, 0x23df,
+ 0x6432, 0x16d0,
+ 0x6435, 0x23e2,
+ 0x6437, 0x16d5,
+ 0x6442, 0x23e4,
+ 0x6443, 0x16e1,
+ 0x6445, 0x23e5,
+ 0x6446, 0x16e4,
+ 0x6449, 0x23e6,
+ 0x644a, 0x16e8,
+ 0x6459, 0x23e7,
+ 0x645a, 0x16f8,
+ 0x645c, 0x23e8,
+ 0x645d, 0x16fb,
+ 0x645e, 0x23e9,
+ 0x645f, 0x16fd,
+ 0x6464, 0x23ea,
+ 0x6465, 0x1703,
+ 0x646b, 0x23eb,
+ 0x646d, 0x170b,
+ 0x6472, 0x23ed,
+ 0x6473, 0x1711,
+ 0x647e, 0x23ee,
+ 0x6521, 0x171d,
+ 0x6530, 0x23ef,
+ 0x6531, 0x172d,
+ 0x6539, 0x23f0,
+ 0x653a, 0x1736,
+ 0x6547, 0x23f1,
+ 0x6548, 0x1744,
+ 0x6549, 0x23f2,
+ 0x654a, 0x1746,
+ 0x654e, 0x23f3,
+ 0x654f, 0x174b,
+ 0x6570, 0x23f4,
+ 0x6571, 0x176d,
+ 0x6572, 0x23f5,
+ 0x6573, 0x176f,
+ 0x657c, 0x23f6,
+ 0x657e, 0x177a,
+ 0x6621, 0x177b,
+ 0x6623, 0x23f8,
+ 0x6624, 0x177e,
+ 0x662b, 0x23f9,
+ 0x662d, 0x1787,
+ 0x662e, 0x23fb,
+ 0x662f, 0x1789,
+ 0x6634, 0x23fc,
+ 0x6636, 0x1790,
+ 0x663f, 0x23fe,
+ 0x6640, 0x179a,
+ 0x6648, 0x23ff,
+ 0x664a, 0x17a4,
+ 0x664d, 0x2401,
+ 0x664e, 0x17a8,
+ 0x6660, 0x2402,
+ 0x6721, 0x2421,
+ 0x675b, 0x1813,
+ 0x6761, 0x245b,
+ 0x6763, 0x181b,
+ 0x6767, 0x245d,
+ 0x6768, 0x1820,
+ 0x676f, 0x245e,
+ 0x6770, 0x1828,
+ 0x6774, 0x245f,
+ 0x6777, 0x182f,
+ 0x6821, 0x1837,
+ 0x6828, 0x2462,
+ 0x6829, 0x183f,
+ 0x682c, 0x2463,
+ 0x682d, 0x1843,
+ 0x6836, 0x2464,
+ 0x6837, 0x184d,
+ 0x6838, 0x2465,
+ 0x683b, 0x1851,
+ 0x683f, 0x2468,
+ 0x6841, 0x1857,
+ 0x6845, 0x246a,
+ 0x6846, 0x185c,
+ 0x6847, 0x246b,
+ 0x684a, 0x1860,
+ 0x684e, 0x246e,
+ 0x684f, 0x1865,
+ 0x6850, 0x246f,
+ 0x6851, 0x1867,
+ 0x6853, 0x2470,
+ 0x6854, 0x186a,
+ 0x685d, 0x2471,
+ 0x685e, 0x1874,
+ 0x685f, 0x2472,
+ 0x6860, 0x1876,
+ 0x6862, 0x2473,
+ 0x6864, 0x187a,
+ 0x6865, 0x2475,
+ 0x6866, 0x187c,
+ 0x6867, 0x2476,
+ 0x6868, 0x187e,
+ 0x686b, 0x2477,
+ 0x686c, 0x1882,
+ 0x686d, 0x2478,
+ 0x686e, 0x1884,
+ 0x686f, 0x2479,
+ 0x6870, 0x1886,
+ 0x6879, 0x247a,
+ 0x687a, 0x1890,
+ 0x687c, 0x247b,
+ 0x687e, 0x1894,
+ 0x6921, 0x247d,
+ 0x6922, 0x1896,
+ 0x692d, 0x247e,
+ 0x692e, 0x18a2,
+ 0x6934, 0x247f,
+ 0x6936, 0x18aa,
+ 0x6937, 0x2481,
+ 0x6938, 0x18ac,
+ 0x6944, 0x2482,
+ 0x6945, 0x18b9,
+ 0x6946, 0x2483,
+ 0x6947, 0x18bb,
+ 0x6949, 0x2484,
+ 0x694a, 0x18be,
+ 0x6956, 0x2485,
+ 0x6957, 0x18cb,
+ 0x695a, 0x2486,
+ 0x695b, 0x18cf,
+ 0x6964, 0x2487,
+ 0x6965, 0x18d9,
+ 0x6966, 0x2488,
+ 0x6968, 0x18dc,
+ 0x6969, 0x248a,
+ 0x696a, 0x18de,
+ 0x696b, 0x248b,
+ 0x696c, 0x18e0,
+ 0x696d, 0x248c,
+ 0x6a21, 0x249e,
+ 0x6a26, 0x18f8,
+ 0x6a27, 0x24a3,
+ 0x6a29, 0x18fb,
+ 0x6a31, 0x24a5,
+ 0x6a32, 0x1904,
+ 0x6a3c, 0x24a6,
+ 0x6a3d, 0x190f,
+ 0x6a4a, 0x24a7,
+ 0x6a4b, 0x191d,
+ 0x6a4d, 0x24a8,
+ 0x6a4e, 0x1920,
+ 0x6a53, 0x24a9,
+ 0x6a54, 0x1926,
+ 0x6a5a, 0x24aa,
+ 0x6a70, 0x1942,
+ 0x6b21, 0x1951,
+ 0x6b27, 0x24c0,
+ 0x6b28, 0x1958,
+ 0x6b2a, 0x24c1,
+ 0x6b2b, 0x195b,
+ 0x6b32, 0x24c2,
+ 0x6b33, 0x1963,
+ 0x6b39, 0x24c3,
+ 0x6b3a, 0x196a,
+ 0x6b4a, 0x24c4,
+ 0x6b4c, 0x197c,
+ 0x6b4d, 0x24c6,
+ 0x6b4e, 0x197e,
+ 0x6b56, 0x24c7,
+ 0x6b57, 0x1987,
+ 0x6b5a, 0x24c8,
+ 0x6b5b, 0x198b,
+ 0x6b61, 0x24c9,
+ 0x6b62, 0x1992,
+ 0x6b77, 0x24ca,
+ 0x6b78, 0x19a8,
+ 0x6c21, 0x19af,
+ 0x6c23, 0x24cb,
+ 0x6c24, 0x19b2,
+ 0x6c29, 0x24cc,
+ 0x6c2f, 0x19bd,
+ 0x6c31, 0x24d2,
+ 0x6c32, 0x19c0,
+ 0x6c34, 0x24d3,
+ 0x6c36, 0x19c4,
+ 0x6c3e, 0x24d5,
+ 0x6c40, 0x19ce,
+ 0x6c41, 0x24d7,
+ 0x6c42, 0x19d0,
+ 0x6c47, 0x24d8,
+ 0x6c48, 0x19d6,
+ 0x6c4b, 0x24d9,
+ 0x6c4c, 0x19da,
+ 0x6c62, 0x24da,
+ 0x6c63, 0x19f1,
+ 0x6c72, 0x24db,
+ 0x6c73, 0x1a01,
+ 0x6c75, 0x24dc,
+ 0x6c76, 0x1a04,
+ 0x6c78, 0x24dd,
+ 0x6c79, 0x1a07,
+ 0x6d21, 0x24de,
+ 0x6d22, 0x1a0e,
+ 0x6d28, 0x24df,
+ 0x6d29, 0x1a15,
+ 0x6d2f, 0x24e0,
+ 0x6d31, 0x1a1d,
+ 0x6d34, 0x24e2,
+ 0x6d35, 0x1a21,
+ 0x6d36, 0x24e3,
+ 0x6d37, 0x1a23,
+ 0x6d38, 0x24e4,
+ 0x6d39, 0x1a25,
+ 0x6d3a, 0x24e5,
+ 0x6d3b, 0x1a27,
+ 0x6d3f, 0x24e6,
+ 0x6d40, 0x1a2c,
+ 0x6d42, 0x24e7,
+ 0x6d44, 0x1a30,
+ 0x6d4c, 0x24e9,
+ 0x6d4e, 0x1a3a,
+ 0x6d53, 0x24eb,
+ 0x6d54, 0x1a40,
+ 0x6d57, 0x24ec,
+ 0x6d58, 0x1a44,
+ 0x6d68, 0x24ed,
+ 0x6d69, 0x1a55,
+ 0x6d6e, 0x24ee,
+ 0x6d6f, 0x1a5b,
+ 0x6d79, 0x24ef,
+ 0x6d7b, 0x1a67,
+ 0x6e21, 0x1a6b,
+ 0x6e3c, 0x24f1,
+ 0x6e3d, 0x1a87,
+ 0x6e3f, 0x24f2,
+ 0x6e40, 0x1a8a,
+ 0x6e44, 0x24f3,
+ 0x6f21, 0x252e,
+ 0x6f72, 0x1b1a,
+ 0x7021, 0x1b27,
+ 0x7023, 0x257f,
+ 0x7024, 0x1b2a,
+ 0x702f, 0x2580,
+ 0x705a, 0x1b60,
+ 0x705c, 0x25ab,
+ 0x705e, 0x1b64,
+ 0x705f, 0x25ad,
+ 0x7060, 0x1b66,
+ 0x7069, 0x25ae,
+ 0x706a, 0x1b70,
+ 0x706c, 0x25af,
+ 0x706d, 0x1b73,
+ 0x706f, 0x25b0,
+ 0x7070, 0x1b76,
+ 0x7077, 0x25b1,
+ 0x7078, 0x1b7e,
+ 0x7079, 0x25b2,
+ 0x707a, 0x1b80,
+ 0x707c, 0x25b3,
+ 0x707d, 0x1b83,
+ 0x7121, 0x1b85,
+ 0x7128, 0x25b4,
+ 0x7129, 0x1b8d,
+ 0x712b, 0x25b5,
+ 0x712c, 0x1b90,
+ 0x712e, 0x25b6,
+ 0x712f, 0x1b93,
+ 0x7132, 0x25b7,
+ 0x7133, 0x1b97,
+ 0x713c, 0x25b8,
+ 0x713d, 0x1ba1,
+ 0x7140, 0x25b9,
+ 0x7141, 0x1ba5,
+ 0x7149, 0x25ba,
+ 0x714a, 0x1bae,
+ 0x714d, 0x25bb,
+ 0x714e, 0x1bb2,
+ 0x714f, 0x25bc,
+ 0x7151, 0x1bb5,
+ 0x715a, 0x25be,
+ 0x715b, 0x1bbf,
+ 0x715c, 0x25bf,
+ 0x715d, 0x1bc1,
+ 0x7164, 0x25c0,
+ 0x7165, 0x1bc9,
+ 0x716c, 0x25c1,
+ 0x716d, 0x1bd1,
+ 0x716f, 0x25c2,
+ 0x7170, 0x1bd4,
+ 0x7177, 0x25c3,
+ 0x7178, 0x1bdc,
+ 0x7179, 0x25c4,
+ 0x717a, 0x1bde,
+ 0x717c, 0x25c5,
+ 0x7221, 0x25c8,
+ 0x722e, 0x1bf0,
+ 0x7231, 0x25d5,
+ 0x7233, 0x1bf5,
+ 0x7239, 0x25d7,
+ 0x723a, 0x1bfc,
+ 0x7243, 0x25d8,
+ 0x7244, 0x1c06,
+ 0x7249, 0x25d9,
+ 0x724a, 0x1c0c,
+ 0x724c, 0x25da,
+ 0x724e, 0x1c10,
+ 0x724f, 0x25dc,
+ 0x7250, 0x1c12,
+ 0x7253, 0x25dd,
+ 0x7254, 0x1c16,
+ 0x7265, 0x25de,
+ 0x7266, 0x1c28,
+ 0x726e, 0x25df,
+ 0x726f, 0x1c31,
+ 0x7277, 0x25e0,
+ 0x7278, 0x1c3a,
+ 0x727d, 0x25e1,
+ 0x727e, 0x1c40,
+ 0x7321, 0x1c41,
+ 0x733f, 0x25e2,
+ 0x7340, 0x1c60,
+ 0x7346, 0x25e3,
+ 0x7347, 0x1c67,
+ 0x7348, 0x25e4,
+ 0x7349, 0x1c69,
+ 0x7356, 0x25e5,
+ 0x7357, 0x1c77,
+ 0x7359, 0x25e6,
+ 0x735a, 0x1c7a,
+ 0x7365, 0x25e7,
+ 0x7367, 0x1c87,
+ 0x736a, 0x25e9,
+ 0x736b, 0x1c8b,
+ 0x736c, 0x25ea,
+ 0x736d, 0x1c8d,
+ 0x736f, 0x25eb,
+ 0x7370, 0x1c90,
+ 0x7371, 0x25ec,
+ 0x7372, 0x1c92,
+ 0x737d, 0x25ed,
+ 0x737e, 0x1c9e,
+ 0x7421, 0x1c9f,
+ 0x7425, 0x25ee,
+ 0x7426, 0x1ca4,
+ 0x742f, 0x25ef,
+ 0x7430, 0x1cae,
+ 0x7435, 0x25f0,
+ 0x7436, 0x1cb4,
+ 0x7441, 0x25f1,
+ 0x7442, 0x1cc0,
+ 0x7447, 0x25f2,
+ 0x7448, 0x1cc6,
+ 0x744f, 0x25f3,
+ 0x7451, 0x1ccf,
+ 0x7456, 0x25f5,
+ 0x7457, 0x1cd5,
+ 0x746a, 0x25f6,
+ 0x746b, 0x1ce9,
+ 0x746f, 0x25f7,
+ 0x7470, 0x1cee,
+ 0x7475, 0x25f8,
+ 0x7476, 0x1cf4,
+ 0x7521, 0x1cfd,
+ 0x7526, 0x25f9,
+ 0x7528, 0x1d04,
+ 0x753a, 0x25fb,
+ 0x753c, 0x1d18,
+ 0x7544, 0x25fd,
+ 0x7545, 0x1d21,
+ 0x7548, 0x25fe,
+ 0x7549, 0x1d25,
+ 0x754e, 0x25ff,
+ 0x7550, 0x1d2c,
+ 0x7551, 0x2601,
+ 0x7553, 0x1d2f,
+ 0x7559, 0x2603,
+ 0x755a, 0x1d36,
+ 0x755c, 0x2604,
+ 0x755d, 0x1d39,
+ 0x7566, 0x2605,
+ 0x7568, 0x1d44,
+ 0x756f, 0x2607,
+ 0x7570, 0x1d4c,
+ 0x7572, 0x2608,
+ 0x7573, 0x1d4f,
+ 0x757c, 0x2609,
+ 0x757d, 0x1d59,
+ 0x7621, 0x1d5b,
+ 0x7623, 0x260a,
+ 0x7624, 0x1d5e,
+ 0x7626, 0x260b,
+ 0x7627, 0x1d61,
+ 0x7628, 0x260c,
+ 0x7629, 0x1d63,
+ 0x762b, 0x260d,
+ 0x762c, 0x1d66,
+ 0x7630, 0x260e,
+ 0x7631, 0x1d6b,
+ 0x7633, 0x260f,
+ 0x763f, 0x1d79,
+ 0x7645, 0x261b,
+ 0x7646, 0x1d80,
+ 0x7647, 0x261c,
+ 0x7648, 0x1d82,
+ 0x7649, 0x261d,
+ 0x764a, 0x1d84,
+ 0x764f, 0x261e,
+ 0x7721, 0x264e,
+ 0x7730, 0x1dc8,
+ 0x7732, 0x265d,
+ 0x7734, 0x1dcc,
+ 0x7735, 0x265f,
+ 0x7736, 0x1dce,
+ 0x773d, 0x2660,
+ 0x773e, 0x1dd6,
+ 0x7743, 0x2661,
+ 0x7744, 0x1ddc,
+ 0x7745, 0x2662,
+ 0x7747, 0x1ddf,
+ 0x774a, 0x2664,
+ 0x774c, 0x1de4,
+ 0x774f, 0x2666,
+ 0x7751, 0x1de9,
+ 0x775e, 0x2668,
+ 0x775f, 0x1df7,
+ 0x7761, 0x0ab9,
+ 0x7762, 0x1dfa,
+ 0x7772, 0x2669,
+ 0x7773, 0x1e0b,
+ 0x7775, 0x266a,
+ 0x7776, 0x1e0e,
+ 0x7821, 0x266b,
+ 0x7827, 0x04cc,
+ 0x7828, 0x050a,
+ 0x7829, 0x0518,
+ 0x782a, 0x2671,
+ 0x782c, 0x0594,
+ 0x782d, 0x05ce,
+ 0x782e, 0x2673,
+ 0x782f, 0x05f6,
+ 0x7830, 0x2674,
+ 0x7832, 0x0653,
+ 0x7833, 0x067e,
+ 0x7834, 0x2676,
+ 0x7835, 0x06c4,
+ 0x7836, 0x2677,
+ 0x7838, 0x073c,
+ 0x7839, 0x2679,
+ 0x783b, 0x07c3,
+ 0x783c, 0x267b,
+ 0x7840, 0x082b,
+ 0x7841, 0x267f,
+ 0x7842, 0x084e,
+ 0x7843, 0x0869,
+ 0x7844, 0x2680,
+ 0x7846, 0x090c,
+ 0x7847, 0x2682,
+ 0x7849, 0x0971,
+ 0x784a, 0x2684,
+ 0x784b, 0x099a,
+ 0x784d, 0x2685,
+ 0x784e, 0x09da,
+ 0x784f, 0x2686,
+ 0x7850, 0x09fa,
+ 0x7851, 0x2687,
+ 0x785c, 0x0bda,
+ 0x785d, 0x0bdd,
+ 0x785e, 0x0bea,
+ 0x785f, 0x0bec,
+ 0x7860, 0x0bf2,
+ 0x7861, 0x2692,
+ 0x7866, 0x0c92,
+ 0x7867, 0x0d1a,
+ 0x7868, 0x0d8c,
+ 0x7869, 0x0dbe,
+ 0x786a, 0x2697,
+ 0x786b, 0x0dfb,
+ 0x786c, 0x2698,
+ 0x786f, 0x0e70,
+ 0x7870, 0x269b,
+ 0x7871, 0x0ea3,
+ 0x7872, 0x269c,
+ 0x7878, 0x103d,
+ 0x7879, 0x10d9,
+ 0x787a, 0x26a2,
+ 0x787c, 0x10fb,
+ 0x787d, 0x1109,
+ 0x787e, 0x26a4,
+ 0x7921, 0x11a1,
+ 0x7922, 0x26a5,
+ 0x7923, 0x11ba,
+ 0x7924, 0x26a6,
+ 0x7926, 0x11d5,
+ 0x7927, 0x26a8,
+ 0x7928, 0x11fd,
+ 0x7929, 0x1219,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 gb12GBTHEnc16 = {
+ 0,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ gb12GBTHMap2, 2283
+};
+
+static Gushort gb12GBTVMap2[4606] = {
+ 0x0000, 0x0000,
+ 0x2121, 0x0060,
+ 0x2231, 0x00be,
+ 0x2265, 0x00f0,
+ 0x2271, 0x00fa,
+ 0x2321, 0x0106,
+ 0x2421, 0x0164,
+ 0x2521, 0x01b7,
+ 0x2621, 0x020d,
+ 0x2641, 0x0225,
+ 0x2721, 0x025a,
+ 0x2751, 0x027b,
+ 0x2821, 0x029c,
+ 0x2845, 0x02bc,
+ 0x2924, 0x02e2,
+ 0x2a21, 0x032e,
+ 0x2b21, 0x038c,
+ 0x3021, 0x03ac,
+ 0x3028, 0x1e25,
+ 0x3029, 0x03b4,
+ 0x302a, 0x1e26,
+ 0x302b, 0x03b6,
+ 0x302d, 0x1e27,
+ 0x302f, 0x03ba,
+ 0x3039, 0x1e29,
+ 0x303a, 0x03c5,
+ 0x3040, 0x1e2a,
+ 0x3041, 0x03cc,
+ 0x3053, 0x1e2b,
+ 0x3054, 0x03df,
+ 0x3055, 0x1e2c,
+ 0x3056, 0x03e1,
+ 0x305a, 0x1e2d,
+ 0x305b, 0x03e6,
+ 0x305c, 0x1e2e,
+ 0x305d, 0x03e8,
+ 0x3064, 0x1e2f,
+ 0x3065, 0x03f0,
+ 0x306c, 0x1e30,
+ 0x306e, 0x03f9,
+ 0x306f, 0x1e32,
+ 0x3070, 0x03fb,
+ 0x3073, 0x1e33,
+ 0x3074, 0x03ff,
+ 0x3077, 0x1e34,
+ 0x3078, 0x0403,
+ 0x3079, 0x1e35,
+ 0x307a, 0x0405,
+ 0x3121, 0x040a,
+ 0x3125, 0x1e36,
+ 0x3127, 0x0410,
+ 0x3128, 0x1e38,
+ 0x3129, 0x0412,
+ 0x312b, 0x1e39,
+ 0x312c, 0x0415,
+ 0x3132, 0x1e3a,
+ 0x3133, 0x041c,
+ 0x3134, 0x1e3b,
+ 0x3136, 0x041f,
+ 0x3137, 0x1e3d,
+ 0x313a, 0x0423,
+ 0x3141, 0x1e40,
+ 0x3142, 0x042b,
+ 0x314a, 0x1e41,
+ 0x314b, 0x0434,
+ 0x314f, 0x1e42,
+ 0x3151, 0x043a,
+ 0x3152, 0x1e44,
+ 0x3153, 0x043c,
+ 0x3155, 0x1e45,
+ 0x3156, 0x043f,
+ 0x315f, 0x1e46,
+ 0x3162, 0x044b,
+ 0x3164, 0x1e49,
+ 0x3165, 0x044e,
+ 0x3167, 0x1e4a,
+ 0x3169, 0x0452,
+ 0x316a, 0x1e4c,
+ 0x316b, 0x0454,
+ 0x316e, 0x1e4d,
+ 0x316f, 0x0458,
+ 0x3171, 0x1e4e,
+ 0x3172, 0x045b,
+ 0x3174, 0x1e4f,
+ 0x3178, 0x0461,
+ 0x317d, 0x1e53,
+ 0x317e, 0x0467,
+ 0x3221, 0x0468,
+ 0x3226, 0x1e54,
+ 0x3228, 0x046f,
+ 0x322c, 0x1e56,
+ 0x322d, 0x0474,
+ 0x3235, 0x1e57,
+ 0x3236, 0x047d,
+ 0x3239, 0x1e58,
+ 0x323a, 0x0481,
+ 0x3246, 0x1e59,
+ 0x3247, 0x048e,
+ 0x324e, 0x1e5a,
+ 0x3258, 0x049f,
+ 0x325e, 0x1e64,
+ 0x325f, 0x04a6,
+ 0x3260, 0x1e65,
+ 0x3261, 0x04a8,
+ 0x3262, 0x1e66,
+ 0x3264, 0x04ab,
+ 0x326f, 0x1e68,
+ 0x3270, 0x04b7,
+ 0x3273, 0x1e69,
+ 0x327d, 0x04c4,
+ 0x3321, 0x1e73,
+ 0x3323, 0x04c8,
+ 0x3324, 0x1e75,
+ 0x3328, 0x04cd,
+ 0x3329, 0x1e79,
+ 0x332a, 0x04cf,
+ 0x332e, 0x1e7a,
+ 0x332f, 0x04d4,
+ 0x3335, 0x1e7b,
+ 0x3336, 0x04db,
+ 0x3339, 0x1e7c,
+ 0x333a, 0x04df,
+ 0x333e, 0x1e7d,
+ 0x333f, 0x04e4,
+ 0x3342, 0x1e7e,
+ 0x3343, 0x04e8,
+ 0x3344, 0x1e7f,
+ 0x3345, 0x04ea,
+ 0x3346, 0x1e80,
+ 0x3347, 0x04ec,
+ 0x334d, 0x1e81,
+ 0x334e, 0x04f3,
+ 0x334f, 0x1e82,
+ 0x3350, 0x04f5,
+ 0x3352, 0x1e83,
+ 0x3353, 0x04f8,
+ 0x3359, 0x1e84,
+ 0x335a, 0x04ff,
+ 0x335b, 0x1e85,
+ 0x335c, 0x0501,
+ 0x335d, 0x1e86,
+ 0x335e, 0x0503,
+ 0x3363, 0x1e87,
+ 0x3364, 0x0509,
+ 0x3365, 0x1e88,
+ 0x3367, 0x050c,
+ 0x3368, 0x1e8a,
+ 0x3369, 0x050e,
+ 0x336b, 0x1e8b,
+ 0x336d, 0x0512,
+ 0x336f, 0x1e8d,
+ 0x3370, 0x0515,
+ 0x3371, 0x1e8e,
+ 0x3372, 0x0517,
+ 0x3373, 0x1e8f,
+ 0x3374, 0x0519,
+ 0x337a, 0x1e90,
+ 0x337c, 0x0521,
+ 0x3421, 0x1e92,
+ 0x3423, 0x0526,
+ 0x3425, 0x1e94,
+ 0x3427, 0x052a,
+ 0x342b, 0x1e96,
+ 0x342c, 0x052f,
+ 0x342f, 0x1e97,
+ 0x3430, 0x0533,
+ 0x3433, 0x1e98,
+ 0x3435, 0x0538,
+ 0x3438, 0x1e9a,
+ 0x3439, 0x053c,
+ 0x343f, 0x1e9b,
+ 0x3440, 0x0543,
+ 0x3442, 0x1e9c,
+ 0x3443, 0x0546,
+ 0x3447, 0x1e9d,
+ 0x3448, 0x054b,
+ 0x344a, 0x1e9e,
+ 0x344b, 0x054e,
+ 0x344d, 0x1e9f,
+ 0x344e, 0x0551,
+ 0x344f, 0x1ea0,
+ 0x3450, 0x0553,
+ 0x3453, 0x1ea1,
+ 0x3455, 0x0558,
+ 0x345a, 0x1ea3,
+ 0x345b, 0x055e,
+ 0x345c, 0x1ea4,
+ 0x345d, 0x0560,
+ 0x346d, 0x1ea5,
+ 0x346e, 0x0571,
+ 0x346f, 0x1ea6,
+ 0x3470, 0x0573,
+ 0x3478, 0x1ea7,
+ 0x3479, 0x057c,
+ 0x347b, 0x1ea8,
+ 0x347c, 0x057f,
+ 0x3521, 0x0582,
+ 0x3523, 0x1ea9,
+ 0x3524, 0x0585,
+ 0x3525, 0x1eaa,
+ 0x3529, 0x058a,
+ 0x352c, 0x1eae,
+ 0x352d, 0x058e,
+ 0x352e, 0x1eaf,
+ 0x3530, 0x0591,
+ 0x3531, 0x1eb1,
+ 0x3536, 0x0597,
+ 0x3537, 0x1eb6,
+ 0x3538, 0x0599,
+ 0x353a, 0x1eb7,
+ 0x353d, 0x059e,
+ 0x3546, 0x1eba,
+ 0x3547, 0x05a8,
+ 0x354b, 0x1ebb,
+ 0x354c, 0x05ad,
+ 0x3550, 0x1ebc,
+ 0x3551, 0x05b2,
+ 0x3553, 0x1ebd,
+ 0x3554, 0x05b5,
+ 0x355d, 0x1ebe,
+ 0x3560, 0x05c1,
+ 0x3563, 0x1ec1,
+ 0x3564, 0x05c5,
+ 0x3566, 0x1ec2,
+ 0x3568, 0x05c9,
+ 0x356d, 0x1ec4,
+ 0x356e, 0x05cf,
+ 0x3576, 0x1ec5,
+ 0x3578, 0x05d9,
+ 0x357d, 0x1ec7,
+ 0x357e, 0x05df,
+ 0x3621, 0x05e0,
+ 0x3624, 0x1ec8,
+ 0x3626, 0x05e5,
+ 0x3627, 0x1eca,
+ 0x3628, 0x05e7,
+ 0x3629, 0x1ecb,
+ 0x362a, 0x05e9,
+ 0x362b, 0x1ecc,
+ 0x362c, 0x05eb,
+ 0x362f, 0x1ecd,
+ 0x3631, 0x05f0,
+ 0x3633, 0x1ecf,
+ 0x3634, 0x05f3,
+ 0x3637, 0x1ed0,
+ 0x3638, 0x05f7,
+ 0x363f, 0x1ed1,
+ 0x3642, 0x0601,
+ 0x3644, 0x1ed4,
+ 0x3645, 0x0604,
+ 0x3646, 0x1ed5,
+ 0x3647, 0x0606,
+ 0x364d, 0x1ed6,
+ 0x364e, 0x060d,
+ 0x364f, 0x1ed7,
+ 0x3651, 0x0610,
+ 0x3653, 0x1ed9,
+ 0x3655, 0x0614,
+ 0x3656, 0x1edb,
+ 0x3657, 0x0616,
+ 0x3659, 0x1edc,
+ 0x365a, 0x0619,
+ 0x365b, 0x1edd,
+ 0x365c, 0x061b,
+ 0x3661, 0x1ede,
+ 0x3662, 0x0621,
+ 0x3669, 0x1edf,
+ 0x366a, 0x0629,
+ 0x366c, 0x1ee0,
+ 0x366d, 0x062c,
+ 0x366e, 0x1ee1,
+ 0x3670, 0x062f,
+ 0x3671, 0x1ee3,
+ 0x3672, 0x0631,
+ 0x3676, 0x1ee4,
+ 0x3677, 0x0636,
+ 0x3679, 0x1ee5,
+ 0x367a, 0x0639,
+ 0x367b, 0x1ee6,
+ 0x367d, 0x063c,
+ 0x3721, 0x1ee8,
+ 0x3724, 0x0641,
+ 0x3727, 0x1eeb,
+ 0x3728, 0x0645,
+ 0x372f, 0x1eec,
+ 0x3731, 0x064e,
+ 0x3733, 0x1eee,
+ 0x3734, 0x0651,
+ 0x3736, 0x1eef,
+ 0x3738, 0x0655,
+ 0x3739, 0x1ef1,
+ 0x373a, 0x0657,
+ 0x3743, 0x1ef2,
+ 0x3745, 0x0662,
+ 0x3749, 0x1ef4,
+ 0x374a, 0x0667,
+ 0x374c, 0x1ef5,
+ 0x374d, 0x066a,
+ 0x374f, 0x1ef6,
+ 0x3750, 0x066d,
+ 0x3751, 0x1ef7,
+ 0x3752, 0x066f,
+ 0x3757, 0x1ef8,
+ 0x3759, 0x0676,
+ 0x375c, 0x1efa,
+ 0x375d, 0x067a,
+ 0x375f, 0x1efb,
+ 0x3762, 0x067f,
+ 0x3763, 0x1efe,
+ 0x3764, 0x0681,
+ 0x3766, 0x1eff,
+ 0x3769, 0x0686,
+ 0x376b, 0x1f02,
+ 0x376e, 0x068b,
+ 0x376f, 0x1f05,
+ 0x3770, 0x068d,
+ 0x3774, 0x1f06,
+ 0x3775, 0x0692,
+ 0x3778, 0x1f07,
+ 0x3779, 0x0696,
+ 0x3821, 0x069c,
+ 0x3827, 0x1f08,
+ 0x3829, 0x06a4,
+ 0x3833, 0x1f0a,
+ 0x3835, 0x06b0,
+ 0x383a, 0x1f0c,
+ 0x383b, 0x06b6,
+ 0x383c, 0x1f0d,
+ 0x383d, 0x06b8,
+ 0x383e, 0x1f0e,
+ 0x3840, 0x06bb,
+ 0x3843, 0x1f10,
+ 0x3844, 0x06bf,
+ 0x3846, 0x1f11,
+ 0x3848, 0x06c3,
+ 0x3849, 0x1f13,
+ 0x384a, 0x06c5,
+ 0x384f, 0x1f14,
+ 0x3850, 0x06cb,
+ 0x3853, 0x1f15,
+ 0x3857, 0x06d2,
+ 0x3859, 0x1f19,
+ 0x385b, 0x06d6,
+ 0x3864, 0x1f1b,
+ 0x3865, 0x06e0,
+ 0x3869, 0x1f1c,
+ 0x386a, 0x06e5,
+ 0x386b, 0x1f1d,
+ 0x386c, 0x06e7,
+ 0x3873, 0x1f1e,
+ 0x3874, 0x06ef,
+ 0x3875, 0x1f1f,
+ 0x3877, 0x06f2,
+ 0x3878, 0x1f21,
+ 0x3879, 0x06f4,
+ 0x3921, 0x06fa,
+ 0x3928, 0x1f22,
+ 0x3929, 0x0702,
+ 0x392e, 0x1f23,
+ 0x392f, 0x0708,
+ 0x3931, 0x1f24,
+ 0x3932, 0x070b,
+ 0x3933, 0x1f25,
+ 0x3934, 0x070d,
+ 0x3935, 0x1f26,
+ 0x3936, 0x070f,
+ 0x3939, 0x1f27,
+ 0x393b, 0x0714,
+ 0x3946, 0x1f29,
+ 0x3947, 0x0720,
+ 0x394b, 0x1f2a,
+ 0x394c, 0x0725,
+ 0x3950, 0x1f2b,
+ 0x3951, 0x072a,
+ 0x3958, 0x1f2c,
+ 0x3959, 0x0732,
+ 0x395b, 0x1f2d,
+ 0x395c, 0x0735,
+ 0x395d, 0x1f2e,
+ 0x395e, 0x0737,
+ 0x395f, 0x1f2f,
+ 0x3960, 0x0739,
+ 0x3961, 0x1f30,
+ 0x3962, 0x073b,
+ 0x3963, 0x1f31,
+ 0x3964, 0x073d,
+ 0x3966, 0x1f32,
+ 0x3967, 0x0740,
+ 0x3969, 0x1f33,
+ 0x396d, 0x0746,
+ 0x396e, 0x1f37,
+ 0x396f, 0x0748,
+ 0x3971, 0x1f38,
+ 0x3972, 0x074b,
+ 0x3973, 0x1f39,
+ 0x3976, 0x074f,
+ 0x3978, 0x1f3c,
+ 0x3979, 0x0752,
+ 0x397a, 0x1f3d,
+ 0x397b, 0x0754,
+ 0x397d, 0x1f3e,
+ 0x397e, 0x0757,
+ 0x3a21, 0x0758,
+ 0x3a27, 0x1f3f,
+ 0x3a28, 0x075f,
+ 0x3a2b, 0x1f40,
+ 0x3a2c, 0x0763,
+ 0x3a3a, 0x1f41,
+ 0x3a3b, 0x0772,
+ 0x3a45, 0x1f42,
+ 0x3a46, 0x077d,
+ 0x3a52, 0x1f43,
+ 0x3a53, 0x078a,
+ 0x3a57, 0x1f44,
+ 0x3a59, 0x0790,
+ 0x3a64, 0x1f46,
+ 0x3a65, 0x079c,
+ 0x3a68, 0x1f47,
+ 0x3a69, 0x07a0,
+ 0x3a6c, 0x1f48,
+ 0x3a6d, 0x07a4,
+ 0x3a73, 0x15e5,
+ 0x3a74, 0x07ab,
+ 0x3a78, 0x1f49,
+ 0x3a79, 0x07b0,
+ 0x3b21, 0x07b6,
+ 0x3b24, 0x1f4a,
+ 0x3b25, 0x07ba,
+ 0x3b26, 0x1f4b,
+ 0x3b27, 0x07bc,
+ 0x3b29, 0x1f4c,
+ 0x3b2b, 0x07c0,
+ 0x3b2d, 0x1f4e,
+ 0x3b2f, 0x07c4,
+ 0x3b30, 0x1f50,
+ 0x3b31, 0x07c6,
+ 0x3b33, 0x1f51,
+ 0x3b34, 0x07c9,
+ 0x3b35, 0x1f52,
+ 0x3b38, 0x07cd,
+ 0x3b39, 0x1f55,
+ 0x3b3b, 0x07d0,
+ 0x3b51, 0x1f57,
+ 0x3b52, 0x07e7,
+ 0x3b53, 0x1f58,
+ 0x3b55, 0x07ea,
+ 0x3b5f, 0x1f5a,
+ 0x3b68, 0x07fd,
+ 0x3b6b, 0x1f63,
+ 0x3b6c, 0x0801,
+ 0x3b71, 0x1f64,
+ 0x3b72, 0x0807,
+ 0x3b75, 0x1f65,
+ 0x3b78, 0x080d,
+ 0x3b7a, 0x1f68,
+ 0x3b7b, 0x0810,
+ 0x3b7d, 0x1f69,
+ 0x3b7e, 0x0813,
+ 0x3c21, 0x0814,
+ 0x3c22, 0x1f6a,
+ 0x3c23, 0x0816,
+ 0x3c25, 0x1f6b,
+ 0x3c27, 0x081a,
+ 0x3c28, 0x1f6d,
+ 0x3c2a, 0x081d,
+ 0x3c2b, 0x1f6f,
+ 0x3c2c, 0x081f,
+ 0x3c2d, 0x1f70,
+ 0x3c2e, 0x0821,
+ 0x3c36, 0x1f71,
+ 0x3c39, 0x082c,
+ 0x3c3b, 0x1f74,
+ 0x3c3c, 0x082f,
+ 0x3c41, 0x1f75,
+ 0x3c42, 0x0835,
+ 0x3c43, 0x1f76,
+ 0x3c44, 0x0837,
+ 0x3c46, 0x1f77,
+ 0x3c48, 0x083b,
+ 0x3c4a, 0x1f79,
+ 0x3c4b, 0x083e,
+ 0x3c4c, 0x1f7a,
+ 0x3c4e, 0x0841,
+ 0x3c50, 0x1f7c,
+ 0x3c51, 0x0844,
+ 0x3c54, 0x1f7d,
+ 0x3c57, 0x084a,
+ 0x3c58, 0x1f80,
+ 0x3c59, 0x084c,
+ 0x3c5b, 0x1f81,
+ 0x3c5c, 0x084f,
+ 0x3c5d, 0x1f82,
+ 0x3c5e, 0x0851,
+ 0x3c5f, 0x1f83,
+ 0x3c62, 0x0855,
+ 0x3c63, 0x1f86,
+ 0x3c65, 0x0858,
+ 0x3c68, 0x1f88,
+ 0x3c69, 0x085c,
+ 0x3c6a, 0x1f89,
+ 0x3c6d, 0x0860,
+ 0x3c6f, 0x1f8c,
+ 0x3c74, 0x0867,
+ 0x3c76, 0x1f91,
+ 0x3c7d, 0x0870,
+ 0x3d21, 0x0872,
+ 0x3d22, 0x1f98,
+ 0x3d28, 0x0879,
+ 0x3d2b, 0x1f9e,
+ 0x3d2d, 0x087e,
+ 0x3d2f, 0x1fa0,
+ 0x3d33, 0x0884,
+ 0x3d34, 0x1fa4,
+ 0x3d35, 0x0886,
+ 0x3d3a, 0x1fa5,
+ 0x3d3b, 0x088c,
+ 0x3d3d, 0x1fa6,
+ 0x3d40, 0x0891,
+ 0x3d41, 0x1fa9,
+ 0x3d45, 0x0896,
+ 0x3d48, 0x1fad,
+ 0x3d4b, 0x089c,
+ 0x3d4e, 0x1fb0,
+ 0x3d50, 0x08a1,
+ 0x3d57, 0x1fb2,
+ 0x3d58, 0x08a9,
+ 0x3d5a, 0x1fb3,
+ 0x3d5b, 0x08ac,
+ 0x3d60, 0x1fb4,
+ 0x3d62, 0x08b3,
+ 0x3d6b, 0x1fb6,
+ 0x3d6c, 0x08bd,
+ 0x3d74, 0x1fb7,
+ 0x3d79, 0x08ca,
+ 0x3d7d, 0x1fbc,
+ 0x3d7e, 0x08cf,
+ 0x3e21, 0x1fbd,
+ 0x3e23, 0x08d2,
+ 0x3e25, 0x1fbf,
+ 0x3e26, 0x08d5,
+ 0x3e28, 0x1fc0,
+ 0x3e29, 0x08d8,
+ 0x3e2a, 0x1fc1,
+ 0x3e2b, 0x08da,
+ 0x3e2d, 0x1fc2,
+ 0x3e2e, 0x08dd,
+ 0x3e31, 0x1fc3,
+ 0x3e32, 0x08e1,
+ 0x3e35, 0x1fc4,
+ 0x3e38, 0x08e7,
+ 0x3e3a, 0x1fc7,
+ 0x3e3b, 0x08ea,
+ 0x3e40, 0x1fc8,
+ 0x3e41, 0x08f0,
+ 0x3e49, 0x1fc9,
+ 0x3e4a, 0x08f9,
+ 0x3e54, 0x1fca,
+ 0x3e55, 0x0904,
+ 0x3e59, 0x1fcb,
+ 0x3e5a, 0x0909,
+ 0x3e5d, 0x1fcc,
+ 0x3e5e, 0x090d,
+ 0x3e62, 0x1fcd,
+ 0x3e63, 0x0912,
+ 0x3e65, 0x1fce,
+ 0x3e66, 0x0915,
+ 0x3e67, 0x1fcf,
+ 0x3e68, 0x0917,
+ 0x3e69, 0x1fd0,
+ 0x3e6a, 0x0919,
+ 0x3e6e, 0x1fd1,
+ 0x3e6f, 0x091e,
+ 0x3e75, 0x1fd2,
+ 0x3e76, 0x0925,
+ 0x3e77, 0x1fd3,
+ 0x3e79, 0x0928,
+ 0x3e7b, 0x1fd5,
+ 0x3e7d, 0x092c,
+ 0x3f21, 0x092e,
+ 0x3f25, 0x1fd7,
+ 0x3f26, 0x0933,
+ 0x3f2a, 0x1fd8,
+ 0x3f2b, 0x0938,
+ 0x3f2d, 0x1fd9,
+ 0x3f2e, 0x093b,
+ 0x3f45, 0x1fda,
+ 0x3f46, 0x0953,
+ 0x3f47, 0x1fdb,
+ 0x3f48, 0x0955,
+ 0x3f4e, 0x1fdc,
+ 0x3f4f, 0x095c,
+ 0x3f51, 0x1fdd,
+ 0x3f53, 0x0960,
+ 0x3f59, 0x1fdf,
+ 0x3f5a, 0x0967,
+ 0x3f62, 0x1fe0,
+ 0x3f65, 0x0972,
+ 0x3f69, 0x1fe3,
+ 0x3f6a, 0x0977,
+ 0x3f6b, 0x1fe4,
+ 0x3f6c, 0x0979,
+ 0x3f6d, 0x1fe5,
+ 0x3f6e, 0x097b,
+ 0x3f73, 0x1fe6,
+ 0x3f74, 0x0981,
+ 0x3f75, 0x1fe7,
+ 0x3f76, 0x0983,
+ 0x3f77, 0x1fe8,
+ 0x3f78, 0x0985,
+ 0x3f79, 0x1fe9,
+ 0x3f7b, 0x0988,
+ 0x4021, 0x1feb,
+ 0x4022, 0x098d,
+ 0x4023, 0x1fec,
+ 0x4024, 0x098f,
+ 0x4029, 0x1fed,
+ 0x402a, 0x0995,
+ 0x402b, 0x1fee,
+ 0x402c, 0x0997,
+ 0x402f, 0x1fef,
+ 0x4031, 0x099c,
+ 0x4033, 0x1ff1,
+ 0x4037, 0x09a2,
+ 0x4038, 0x1ff5,
+ 0x4045, 0x09b0,
+ 0x404c, 0x2002,
+ 0x404e, 0x09b9,
+ 0x4054, 0x2004,
+ 0x4055, 0x09c0,
+ 0x4056, 0x2005,
+ 0x4057, 0x09c2,
+ 0x4058, 0x2006,
+ 0x4059, 0x09c4,
+ 0x405d, 0x2007,
+ 0x405e, 0x09c9,
+ 0x4060, 0x2008,
+ 0x4061, 0x09cc,
+ 0x4069, 0x2009,
+ 0x406a, 0x09d5,
+ 0x406b, 0x200a,
+ 0x406d, 0x09d8,
+ 0x406f, 0x200c,
+ 0x4072, 0x09dd,
+ 0x4076, 0x200f,
+ 0x407b, 0x09e6,
+ 0x4121, 0x09ea,
+ 0x4124, 0x2014,
+ 0x4126, 0x09ef,
+ 0x4129, 0x2016,
+ 0x412e, 0x09f7,
+ 0x412f, 0x201b,
+ 0x4139, 0x0a02,
+ 0x413d, 0x2025,
+ 0x413f, 0x0a08,
+ 0x4142, 0x2027,
+ 0x4143, 0x0a0c,
+ 0x4146, 0x2028,
+ 0x4147, 0x0a10,
+ 0x4149, 0x2029,
+ 0x414a, 0x0a13,
+ 0x414d, 0x202a,
+ 0x414e, 0x0a17,
+ 0x4154, 0x202b,
+ 0x4155, 0x0a1e,
+ 0x4159, 0x202c,
+ 0x415c, 0x0a25,
+ 0x415e, 0x202f,
+ 0x415f, 0x0a28,
+ 0x4164, 0x2030,
+ 0x4166, 0x0a2f,
+ 0x4169, 0x2032,
+ 0x416a, 0x0a33,
+ 0x416b, 0x2033,
+ 0x416d, 0x0a36,
+ 0x4173, 0x2035,
+ 0x4174, 0x0a3d,
+ 0x4175, 0x2036,
+ 0x4176, 0x0a3f,
+ 0x417a, 0x2037,
+ 0x417e, 0x0a47,
+ 0x4221, 0x0a48,
+ 0x4222, 0x203b,
+ 0x4229, 0x0a50,
+ 0x422b, 0x2042,
+ 0x4234, 0x0a5b,
+ 0x4238, 0x204b,
+ 0x4239, 0x0a60,
+ 0x423c, 0x204c,
+ 0x423e, 0x0a65,
+ 0x423f, 0x204e,
+ 0x4240, 0x0a67,
+ 0x4241, 0x204f,
+ 0x4242, 0x0a69,
+ 0x4245, 0x2050,
+ 0x4248, 0x0a6f,
+ 0x424b, 0x2053,
+ 0x4251, 0x0a78,
+ 0x4252, 0x2059,
+ 0x4253, 0x0a7a,
+ 0x4255, 0x205a,
+ 0x425d, 0x0a84,
+ 0x425e, 0x2062,
+ 0x4263, 0x0a8a,
+ 0x4266, 0x2067,
+ 0x4269, 0x0a90,
+ 0x426a, 0x206a,
+ 0x426f, 0x0a96,
+ 0x4270, 0x206f,
+ 0x4271, 0x0a98,
+ 0x4272, 0x2070,
+ 0x4276, 0x0a9d,
+ 0x4277, 0x2074,
+ 0x427b, 0x0aa2,
+ 0x4321, 0x2078,
+ 0x4322, 0x0aa7,
+ 0x432a, 0x2079,
+ 0x432b, 0x0ab0,
+ 0x432d, 0x207a,
+ 0x432e, 0x0ab3,
+ 0x4333, 0x207b,
+ 0x4334, 0x1df9,
+ 0x4335, 0x0aba,
+ 0x433e, 0x207c,
+ 0x433f, 0x0ac4,
+ 0x4345, 0x207d,
+ 0x4348, 0x0acd,
+ 0x434c, 0x2080,
+ 0x434d, 0x0ad2,
+ 0x434e, 0x2081,
+ 0x434f, 0x0ad4,
+ 0x4355, 0x2082,
+ 0x4357, 0x0adc,
+ 0x4359, 0x2084,
+ 0x435a, 0x0adf,
+ 0x4360, 0x2085,
+ 0x4361, 0x0ae6,
+ 0x4365, 0x2086,
+ 0x4366, 0x0aeb,
+ 0x436d, 0x2087,
+ 0x436e, 0x0af3,
+ 0x4370, 0x2088,
+ 0x4371, 0x0af6,
+ 0x4375, 0x2089,
+ 0x4377, 0x0afc,
+ 0x4379, 0x208b,
+ 0x437b, 0x0b00,
+ 0x437d, 0x208d,
+ 0x437e, 0x0b03,
+ 0x4421, 0x0b04,
+ 0x4431, 0x208e,
+ 0x4432, 0x0b15,
+ 0x4436, 0x208f,
+ 0x4437, 0x0b1a,
+ 0x4446, 0x2090,
+ 0x4447, 0x0b2a,
+ 0x4449, 0x2091,
+ 0x444a, 0x0b2d,
+ 0x4451, 0x2092,
+ 0x4452, 0x0b35,
+ 0x4453, 0x2093,
+ 0x4457, 0x0b3a,
+ 0x4459, 0x2097,
+ 0x445a, 0x0b3d,
+ 0x4462, 0x2098,
+ 0x4463, 0x0b46,
+ 0x4465, 0x2099,
+ 0x4466, 0x0b49,
+ 0x446c, 0x209a,
+ 0x446d, 0x0b50,
+ 0x4470, 0x209b,
+ 0x4472, 0x0b55,
+ 0x4474, 0x209d,
+ 0x4475, 0x0b58,
+ 0x4476, 0x209e,
+ 0x4479, 0x0b5c,
+ 0x447b, 0x20a1,
+ 0x447d, 0x0b60,
+ 0x447e, 0x20a3,
+ 0x4521, 0x20a4,
+ 0x4523, 0x0b64,
+ 0x4525, 0x20a6,
+ 0x452a, 0x0b6b,
+ 0x4531, 0x20ab,
+ 0x4532, 0x0b73,
+ 0x4535, 0x20ac,
+ 0x4536, 0x0b77,
+ 0x4537, 0x20ad,
+ 0x453a, 0x0b7b,
+ 0x453b, 0x20b0,
+ 0x453c, 0x0b7d,
+ 0x453d, 0x20b1,
+ 0x453e, 0x0b7f,
+ 0x454c, 0x20b2,
+ 0x454d, 0x0b8e,
+ 0x4553, 0x20b3,
+ 0x4554, 0x0b95,
+ 0x4562, 0x20b4,
+ 0x4563, 0x0ba4,
+ 0x4567, 0x20b5,
+ 0x4568, 0x0ba9,
+ 0x4574, 0x20b6,
+ 0x4575, 0x0bb6,
+ 0x4621, 0x0bc0,
+ 0x462d, 0x20b7,
+ 0x462f, 0x0bce,
+ 0x4635, 0x20b9,
+ 0x4637, 0x0bd6,
+ 0x463b, 0x20bb,
+ 0x463c, 0x0bdb,
+ 0x463e, 0x20bc,
+ 0x463f, 0x0bde,
+ 0x4640, 0x20bd,
+ 0x4641, 0x0be0,
+ 0x4643, 0x20be,
+ 0x4645, 0x0be4,
+ 0x464b, 0x20c0,
+ 0x464e, 0x0bed,
+ 0x4653, 0x20c3,
+ 0x4654, 0x0bf3,
+ 0x4657, 0x20c4,
+ 0x4658, 0x0bf7,
+ 0x466a, 0x20c5,
+ 0x466c, 0x0c0b,
+ 0x466f, 0x20c7,
+ 0x4670, 0x0c0f,
+ 0x4671, 0x20c8,
+ 0x4672, 0x0c11,
+ 0x4674, 0x20c9,
+ 0x4675, 0x0c14,
+ 0x4678, 0x20ca,
+ 0x4679, 0x0c18,
+ 0x467d, 0x20cb,
+ 0x467e, 0x0c1d,
+ 0x4721, 0x0c1e,
+ 0x4723, 0x20cc,
+ 0x4724, 0x0c21,
+ 0x4725, 0x20cd,
+ 0x4727, 0x0c24,
+ 0x4728, 0x20cf,
+ 0x472a, 0x0c27,
+ 0x472b, 0x20d1,
+ 0x472c, 0x0c29,
+ 0x472e, 0x20d2,
+ 0x4730, 0x0c2d,
+ 0x4733, 0x20d4,
+ 0x4736, 0x0c33,
+ 0x4739, 0x20d7,
+ 0x473b, 0x0c38,
+ 0x473d, 0x20d9,
+ 0x473f, 0x0c3c,
+ 0x4740, 0x20db,
+ 0x4741, 0x0c3e,
+ 0x4742, 0x20dc,
+ 0x4743, 0x0c40,
+ 0x4745, 0x20dd,
+ 0x4746, 0x0c43,
+ 0x4747, 0x20de,
+ 0x4749, 0x0c46,
+ 0x474c, 0x20e0,
+ 0x474d, 0x0c4a,
+ 0x474f, 0x20e1,
+ 0x4750, 0x0c4d,
+ 0x4754, 0x20e2,
+ 0x4756, 0x0c53,
+ 0x4757, 0x20e4,
+ 0x4758, 0x0c55,
+ 0x475e, 0x20e5,
+ 0x475f, 0x0c5c,
+ 0x4761, 0x20e6,
+ 0x4764, 0x0c61,
+ 0x476a, 0x20e9,
+ 0x476f, 0x0c6c,
+ 0x4777, 0x20ee,
+ 0x4779, 0x0c76,
+ 0x477b, 0x20f0,
+ 0x477c, 0x0c79,
+ 0x477d, 0x20f1,
+ 0x477e, 0x0c7b,
+ 0x4821, 0x0c7c,
+ 0x4823, 0x20f2,
+ 0x4824, 0x0c7f,
+ 0x4827, 0x20f3,
+ 0x4829, 0x0c84,
+ 0x4830, 0x20f5,
+ 0x4831, 0x0c8c,
+ 0x4835, 0x20f6,
+ 0x4836, 0x0c91,
+ 0x4837, 0x20f7,
+ 0x4838, 0x0c93,
+ 0x4843, 0x20f8,
+ 0x4847, 0x0ca2,
+ 0x4848, 0x20fc,
+ 0x4849, 0x0ca4,
+ 0x484d, 0x20fd,
+ 0x484e, 0x0ca9,
+ 0x484f, 0x20fe,
+ 0x4850, 0x0cab,
+ 0x4852, 0x20ff,
+ 0x4853, 0x0cae,
+ 0x4859, 0x2100,
+ 0x485a, 0x0cb5,
+ 0x485e, 0x2101,
+ 0x485f, 0x0cba,
+ 0x486d, 0x2102,
+ 0x486e, 0x0cc9,
+ 0x4871, 0x2103,
+ 0x4874, 0x0ccf,
+ 0x4877, 0x2106,
+ 0x4879, 0x0cd4,
+ 0x487a, 0x2108,
+ 0x487b, 0x0cd6,
+ 0x487c, 0x2109,
+ 0x487d, 0x0cd8,
+ 0x4921, 0x210a,
+ 0x4922, 0x0cdb,
+ 0x4925, 0x210b,
+ 0x4926, 0x0cdf,
+ 0x4927, 0x210c,
+ 0x4929, 0x0ce2,
+ 0x492c, 0x210e,
+ 0x492d, 0x0ce6,
+ 0x4931, 0x210f,
+ 0x4932, 0x0ceb,
+ 0x4934, 0x2110,
+ 0x4935, 0x0cee,
+ 0x4938, 0x2111,
+ 0x493a, 0x0cf3,
+ 0x4941, 0x2113,
+ 0x4943, 0x0cfc,
+ 0x4944, 0x2115,
+ 0x4945, 0x0cfe,
+ 0x4949, 0x2116,
+ 0x494a, 0x0d03,
+ 0x494b, 0x2117,
+ 0x494c, 0x0d05,
+ 0x494d, 0x2118,
+ 0x494e, 0x0d07,
+ 0x4955, 0x2119,
+ 0x4956, 0x0d0f,
+ 0x495c, 0x211a,
+ 0x495d, 0x0d16,
+ 0x495e, 0x211b,
+ 0x495f, 0x0d18,
+ 0x4961, 0x211c,
+ 0x4962, 0x0d1b,
+ 0x4963, 0x211d,
+ 0x4964, 0x0d1d,
+ 0x4965, 0x211e,
+ 0x4966, 0x0d1f,
+ 0x4968, 0x211f,
+ 0x4969, 0x0d22,
+ 0x4970, 0x2120,
+ 0x4971, 0x0d2a,
+ 0x4973, 0x2121,
+ 0x4975, 0x0d2e,
+ 0x4976, 0x2123,
+ 0x4977, 0x0d30,
+ 0x4978, 0x2124,
+ 0x497a, 0x0d33,
+ 0x497e, 0x2126,
+ 0x4a21, 0x0d38,
+ 0x4a24, 0x2127,
+ 0x4a27, 0x0d3e,
+ 0x4a28, 0x212a,
+ 0x4a29, 0x0d40,
+ 0x4a2a, 0x212b,
+ 0x4a2c, 0x0d43,
+ 0x4a31, 0x212d,
+ 0x4a32, 0x0d49,
+ 0x4a34, 0x212e,
+ 0x4a37, 0x0d4e,
+ 0x4a3b, 0x2131,
+ 0x4a3c, 0x0d53,
+ 0x4a46, 0x2132,
+ 0x4a47, 0x0d5e,
+ 0x4a4a, 0x2133,
+ 0x4a4b, 0x0d62,
+ 0x4a4d, 0x2134,
+ 0x4a4f, 0x0d66,
+ 0x4a53, 0x2136,
+ 0x4a55, 0x0d6c,
+ 0x4a59, 0x2138,
+ 0x4a5a, 0x0d71,
+ 0x4a5e, 0x2139,
+ 0x4a5f, 0x0d76,
+ 0x4a60, 0x213a,
+ 0x4a61, 0x0d78,
+ 0x4a64, 0x213b,
+ 0x4a65, 0x0d7c,
+ 0x4a69, 0x213c,
+ 0x4a6b, 0x0d82,
+ 0x4a74, 0x213e,
+ 0x4a76, 0x0d8d,
+ 0x4a77, 0x2140,
+ 0x4a78, 0x0d8f,
+ 0x4a7a, 0x2141,
+ 0x4a7b, 0x0d92,
+ 0x4a7d, 0x2142,
+ 0x4a7e, 0x0d95,
+ 0x4b21, 0x0d96,
+ 0x4b27, 0x2143,
+ 0x4b28, 0x0d9d,
+ 0x4b2b, 0x2144,
+ 0x4b2c, 0x0da1,
+ 0x4b2d, 0x2145,
+ 0x4b2e, 0x0da3,
+ 0x4b33, 0x2146,
+ 0x4b34, 0x0da9,
+ 0x4b35, 0x2147,
+ 0x4b37, 0x0dac,
+ 0x4b38, 0x2149,
+ 0x4b39, 0x0dae,
+ 0x4b3f, 0x214a,
+ 0x4b40, 0x0db5,
+ 0x4b47, 0x214b,
+ 0x4b48, 0x0dbd,
+ 0x4b49, 0x214c,
+ 0x4b4d, 0x0dc2,
+ 0x4b4f, 0x2150,
+ 0x4b51, 0x0dc6,
+ 0x4b53, 0x2152,
+ 0x4b54, 0x0dc9,
+ 0x4b55, 0x2153,
+ 0x4b56, 0x0dcb,
+ 0x4b5f, 0x2154,
+ 0x4b61, 0x0dd6,
+ 0x4b64, 0x2156,
+ 0x4b65, 0x0dda,
+ 0x4b66, 0x2157,
+ 0x4b68, 0x0ddd,
+ 0x4b6a, 0x2159,
+ 0x4b6b, 0x0de0,
+ 0x4b6f, 0x215a,
+ 0x4b71, 0x0de6,
+ 0x4b75, 0x215c,
+ 0x4b77, 0x0dec,
+ 0x4b78, 0x215e,
+ 0x4b79, 0x0dee,
+ 0x4c21, 0x215f,
+ 0x4c23, 0x0df6,
+ 0x4c28, 0x2161,
+ 0x4c29, 0x0dfc,
+ 0x4c2c, 0x2162,
+ 0x4c2d, 0x0e00,
+ 0x4c2f, 0x2163,
+ 0x4c34, 0x0e07,
+ 0x4c37, 0x2168,
+ 0x4c39, 0x0e0c,
+ 0x4c3e, 0x216a,
+ 0x4c3f, 0x0e12,
+ 0x4c40, 0x216b,
+ 0x4c41, 0x0e14,
+ 0x4c4c, 0x216c,
+ 0x4c4d, 0x0e20,
+ 0x4c4e, 0x216d,
+ 0x4c4f, 0x0e22,
+ 0x4c50, 0x216e,
+ 0x4c51, 0x0e24,
+ 0x4c56, 0x216f,
+ 0x4c57, 0x0e2a,
+ 0x4c5a, 0x2170,
+ 0x4c5b, 0x0e2e,
+ 0x4c5c, 0x2171,
+ 0x4c5d, 0x0e30,
+ 0x4c60, 0x2172,
+ 0x4c61, 0x0e34,
+ 0x4c62, 0x2173,
+ 0x4c63, 0x0e36,
+ 0x4c65, 0x2174,
+ 0x4c66, 0x0e39,
+ 0x4c75, 0x2175,
+ 0x4c76, 0x0e49,
+ 0x4c79, 0x2176,
+ 0x4c7b, 0x0e4e,
+ 0x4c7c, 0x2178,
+ 0x4d21, 0x0e52,
+ 0x4d2d, 0x217b,
+ 0x4d2e, 0x0e5f,
+ 0x4d33, 0x217c,
+ 0x4d34, 0x0e65,
+ 0x4d37, 0x217d,
+ 0x4d38, 0x0e69,
+ 0x4d3c, 0x217e,
+ 0x4d3d, 0x0e6e,
+ 0x4d3f, 0x217f,
+ 0x4d40, 0x0e71,
+ 0x4d45, 0x2180,
+ 0x4d46, 0x0e77,
+ 0x4d47, 0x2181,
+ 0x4d48, 0x0e79,
+ 0x4d52, 0x2182,
+ 0x4d53, 0x0e84,
+ 0x4d54, 0x2183,
+ 0x4d57, 0x0e88,
+ 0x4d5d, 0x2186,
+ 0x4d5e, 0x0e8f,
+ 0x4d60, 0x2187,
+ 0x4d61, 0x0e92,
+ 0x4d64, 0x2188,
+ 0x4d66, 0x0e97,
+ 0x4d67, 0x218a,
+ 0x4d68, 0x0e99,
+ 0x4d72, 0x218b,
+ 0x4d73, 0x0ea4,
+ 0x4d78, 0x218c,
+ 0x4d79, 0x0eaa,
+ 0x4e21, 0x0eb0,
+ 0x4e24, 0x218d,
+ 0x4e26, 0x0eb5,
+ 0x4e27, 0x218f,
+ 0x4e28, 0x0eb7,
+ 0x4e2a, 0x2190,
+ 0x4e2e, 0x0ebd,
+ 0x4e30, 0x2194,
+ 0x4e32, 0x0ec1,
+ 0x4e33, 0x2196,
+ 0x4e34, 0x0ec3,
+ 0x4e3d, 0x2197,
+ 0x4e3e, 0x0ecd,
+ 0x4e40, 0x2198,
+ 0x4e41, 0x0ed0,
+ 0x4e45, 0x2199,
+ 0x4e47, 0x0ed6,
+ 0x4e48, 0x219b,
+ 0x4e49, 0x0ed8,
+ 0x4e4a, 0x219c,
+ 0x4e4b, 0x0eda,
+ 0x4e4e, 0x219d,
+ 0x4e52, 0x0ee1,
+ 0x4e58, 0x21a1,
+ 0x4e5b, 0x0eea,
+ 0x4e5c, 0x21a4,
+ 0x4e5d, 0x0eec,
+ 0x4e5e, 0x21a5,
+ 0x4e60, 0x0eef,
+ 0x4e6b, 0x21a7,
+ 0x4e6c, 0x0efb,
+ 0x4e6d, 0x21a8,
+ 0x4e6e, 0x0efd,
+ 0x4e71, 0x21a9,
+ 0x4e72, 0x0f01,
+ 0x4e73, 0x21aa,
+ 0x4e74, 0x0f03,
+ 0x4e7d, 0x21ab,
+ 0x4f21, 0x0f0e,
+ 0x4f2e, 0x21ad,
+ 0x4f2f, 0x0f1c,
+ 0x4f30, 0x21ae,
+ 0x4f31, 0x0f1e,
+ 0x4f33, 0x21af,
+ 0x4f34, 0x0f21,
+ 0x4f37, 0x21b0,
+ 0x4f39, 0x0f26,
+ 0x4f3a, 0x21b2,
+ 0x4f3b, 0x0f28,
+ 0x4f3d, 0x21b3,
+ 0x4f3e, 0x0f2b,
+ 0x4f3f, 0x21b4,
+ 0x4f42, 0x0f2f,
+ 0x4f45, 0x21b7,
+ 0x4f46, 0x0f33,
+ 0x4f47, 0x21b8,
+ 0x4f48, 0x0f35,
+ 0x4f4a, 0x21b9,
+ 0x4f4c, 0x0f39,
+ 0x4f4d, 0x21bb,
+ 0x4f4f, 0x0f3c,
+ 0x4f50, 0x21bd,
+ 0x4f51, 0x0f3e,
+ 0x4f54, 0x21be,
+ 0x4f59, 0x0f46,
+ 0x4f5a, 0x21c3,
+ 0x4f5b, 0x0f48,
+ 0x4f5c, 0x21c4,
+ 0x4f5d, 0x0f4a,
+ 0x4f5f, 0x21c5,
+ 0x4f60, 0x0f4d,
+ 0x4f62, 0x21c6,
+ 0x4f63, 0x0f50,
+ 0x4f67, 0x21c7,
+ 0x4f68, 0x0f55,
+ 0x4f6a, 0x21c8,
+ 0x4f6b, 0x0f58,
+ 0x4f6c, 0x21c9,
+ 0x4f6d, 0x0f5a,
+ 0x4f6e, 0x21ca,
+ 0x4f6f, 0x0f5c,
+ 0x4f74, 0x21cb,
+ 0x4f75, 0x0f62,
+ 0x4f79, 0x21cc,
+ 0x4f7b, 0x0f68,
+ 0x4f7e, 0x21ce,
+ 0x5021, 0x0f6c,
+ 0x5025, 0x21cf,
+ 0x5026, 0x0f71,
+ 0x502d, 0x21d0,
+ 0x502f, 0x0f7a,
+ 0x5032, 0x21d2,
+ 0x5035, 0x0f80,
+ 0x503a, 0x21d5,
+ 0x503c, 0x0f87,
+ 0x503f, 0x21d7,
+ 0x5040, 0x0f8b,
+ 0x5046, 0x21d8,
+ 0x5047, 0x0f92,
+ 0x504b, 0x21d9,
+ 0x504c, 0x0f97,
+ 0x5062, 0x21da,
+ 0x5063, 0x0fae,
+ 0x5065, 0x21db,
+ 0x5066, 0x0fb1,
+ 0x506b, 0x21dc,
+ 0x506c, 0x0fb7,
+ 0x506d, 0x21dd,
+ 0x506e, 0x0fb9,
+ 0x5077, 0x21de,
+ 0x507a, 0x0fc5,
+ 0x507c, 0x21e1,
+ 0x507d, 0x0fc8,
+ 0x5121, 0x21e2,
+ 0x5123, 0x0fcc,
+ 0x5124, 0x21e4,
+ 0x5125, 0x0fce,
+ 0x5127, 0x21e5,
+ 0x5128, 0x0fd1,
+ 0x512b, 0x21e6,
+ 0x512c, 0x0fd5,
+ 0x512f, 0x21e7,
+ 0x5132, 0x0fdb,
+ 0x5135, 0x21ea,
+ 0x5138, 0x0fe1,
+ 0x5139, 0x21ed,
+ 0x513a, 0x0fe3,
+ 0x513b, 0x21ee,
+ 0x513d, 0x0fe6,
+ 0x5146, 0x21f0,
+ 0x5149, 0x0ff2,
+ 0x514b, 0x21f3,
+ 0x514c, 0x0ff5,
+ 0x514e, 0x21f4,
+ 0x5150, 0x0ff9,
+ 0x5155, 0x21f6,
+ 0x5157, 0x1000,
+ 0x515e, 0x21f8,
+ 0x515f, 0x1008,
+ 0x5161, 0x21f9,
+ 0x5163, 0x100c,
+ 0x5168, 0x21fb,
+ 0x516a, 0x1013,
+ 0x516c, 0x21fd,
+ 0x516d, 0x1016,
+ 0x516e, 0x21fe,
+ 0x5170, 0x1019,
+ 0x5171, 0x2200,
+ 0x5172, 0x101b,
+ 0x5174, 0x2201,
+ 0x5175, 0x101e,
+ 0x5177, 0x2202,
+ 0x517a, 0x1023,
+ 0x5221, 0x1028,
+ 0x5222, 0x2205,
+ 0x5223, 0x102a,
+ 0x5225, 0x2206,
+ 0x5226, 0x102d,
+ 0x5229, 0x2207,
+ 0x522a, 0x1031,
+ 0x522f, 0x2208,
+ 0x5230, 0x1037,
+ 0x5233, 0x2209,
+ 0x5234, 0x103b,
+ 0x5235, 0x220a,
+ 0x5237, 0x103e,
+ 0x523d, 0x220c,
+ 0x523e, 0x1045,
+ 0x523f, 0x220d,
+ 0x5240, 0x1047,
+ 0x5243, 0x220e,
+ 0x5244, 0x104b,
+ 0x5245, 0x220f,
+ 0x5246, 0x104d,
+ 0x5247, 0x2210,
+ 0x5248, 0x104f,
+ 0x524f, 0x2211,
+ 0x5250, 0x1057,
+ 0x5255, 0x2212,
+ 0x5256, 0x105d,
+ 0x525a, 0x2213,
+ 0x525b, 0x1062,
+ 0x5264, 0x2214,
+ 0x5266, 0x106d,
+ 0x5268, 0x2216,
+ 0x526c, 0x1073,
+ 0x526f, 0x221a,
+ 0x5270, 0x1077,
+ 0x5271, 0x221b,
+ 0x5272, 0x1079,
+ 0x5275, 0x221c,
+ 0x5276, 0x107d,
+ 0x5278, 0x221d,
+ 0x5279, 0x1080,
+ 0x527b, 0x221e,
+ 0x527c, 0x1083,
+ 0x527e, 0x221f,
+ 0x5321, 0x1086,
+ 0x5323, 0x2220,
+ 0x532d, 0x1092,
+ 0x532e, 0x222a,
+ 0x532f, 0x1094,
+ 0x5331, 0x222b,
+ 0x5332, 0x1097,
+ 0x5334, 0x222c,
+ 0x5337, 0x109c,
+ 0x5338, 0x222f,
+ 0x5339, 0x109e,
+ 0x533b, 0x2230,
+ 0x533c, 0x10a1,
+ 0x5345, 0x2231,
+ 0x5346, 0x10ab,
+ 0x5347, 0x2232,
+ 0x5348, 0x10ad,
+ 0x534a, 0x2233,
+ 0x534d, 0x10b2,
+ 0x5355, 0x2236,
+ 0x5356, 0x10bb,
+ 0x535f, 0x2237,
+ 0x5361, 0x10c6,
+ 0x5363, 0x2239,
+ 0x5364, 0x10c9,
+ 0x5366, 0x223a,
+ 0x5367, 0x10cc,
+ 0x536b, 0x223b,
+ 0x536d, 0x10d2,
+ 0x536f, 0x223d,
+ 0x5370, 0x10d5,
+ 0x5374, 0x223e,
+ 0x5375, 0x10da,
+ 0x537c, 0x223f,
+ 0x537d, 0x10e2,
+ 0x537e, 0x2240,
+ 0x5421, 0x10e4,
+ 0x5424, 0x2241,
+ 0x5425, 0x10e8,
+ 0x5426, 0x2242,
+ 0x5429, 0x10ec,
+ 0x542f, 0x2245,
+ 0x5433, 0x10f6,
+ 0x5435, 0x2249,
+ 0x5437, 0x10fa,
+ 0x5438, 0x224b,
+ 0x5439, 0x10fc,
+ 0x543c, 0x224c,
+ 0x543d, 0x1100,
+ 0x543e, 0x224d,
+ 0x5440, 0x1103,
+ 0x5444, 0x224f,
+ 0x5445, 0x1108,
+ 0x5446, 0x2250,
+ 0x5448, 0x110b,
+ 0x5449, 0x2252,
+ 0x544a, 0x110d,
+ 0x544b, 0x2253,
+ 0x544f, 0x1112,
+ 0x5453, 0x2257,
+ 0x5454, 0x1117,
+ 0x5458, 0x2258,
+ 0x5459, 0x111c,
+ 0x545c, 0x2259,
+ 0x5461, 0x1124,
+ 0x5464, 0x225e,
+ 0x5465, 0x1128,
+ 0x5466, 0x225f,
+ 0x5467, 0x112a,
+ 0x546e, 0x2260,
+ 0x546f, 0x1132,
+ 0x5470, 0x2261,
+ 0x5475, 0x1138,
+ 0x5479, 0x2266,
+ 0x547a, 0x113d,
+ 0x547e, 0x2267,
+ 0x5521, 0x2268,
+ 0x5523, 0x1144,
+ 0x5529, 0x226a,
+ 0x552a, 0x114b,
+ 0x552b, 0x226b,
+ 0x552c, 0x114d,
+ 0x552e, 0x226c,
+ 0x552f, 0x1150,
+ 0x5531, 0x226d,
+ 0x5532, 0x1153,
+ 0x5535, 0x226e,
+ 0x5539, 0x115a,
+ 0x553b, 0x2272,
+ 0x553c, 0x115d,
+ 0x553d, 0x2273,
+ 0x553e, 0x115f,
+ 0x5540, 0x2274,
+ 0x5541, 0x1162,
+ 0x5545, 0x2275,
+ 0x5546, 0x1167,
+ 0x5547, 0x2276,
+ 0x5548, 0x1169,
+ 0x554a, 0x2277,
+ 0x554c, 0x116d,
+ 0x554d, 0x2279,
+ 0x554e, 0x116f,
+ 0x5554, 0x227a,
+ 0x5555, 0x1176,
+ 0x555d, 0x227b,
+ 0x555f, 0x1180,
+ 0x5560, 0x227d,
+ 0x5561, 0x1182,
+ 0x5562, 0x227e,
+ 0x5563, 0x1184,
+ 0x556a, 0x227f,
+ 0x556d, 0x118e,
+ 0x556f, 0x2282,
+ 0x5570, 0x1191,
+ 0x5572, 0x2283,
+ 0x5574, 0x1195,
+ 0x5577, 0x15eb,
+ 0x5578, 0x1199,
+ 0x5621, 0x2285,
+ 0x5625, 0x11a4,
+ 0x562f, 0x2289,
+ 0x5631, 0x11b0,
+ 0x5634, 0x228b,
+ 0x5635, 0x11b4,
+ 0x563b, 0x228c,
+ 0x563c, 0x11bb,
+ 0x563d, 0x228d,
+ 0x563e, 0x11bd,
+ 0x563f, 0x228e,
+ 0x5641, 0x11c0,
+ 0x5644, 0x2290,
+ 0x5645, 0x11c4,
+ 0x564a, 0x2291,
+ 0x564b, 0x11ca,
+ 0x564d, 0x2292,
+ 0x564e, 0x11cd,
+ 0x5653, 0x2293,
+ 0x5654, 0x11d3,
+ 0x5655, 0x2294,
+ 0x5658, 0x11d7,
+ 0x565a, 0x2297,
+ 0x565b, 0x11da,
+ 0x565f, 0x2298,
+ 0x5660, 0x11df,
+ 0x5661, 0x2299,
+ 0x5662, 0x11e1,
+ 0x5665, 0x229a,
+ 0x5666, 0x11e5,
+ 0x5667, 0x229b,
+ 0x5669, 0x11e8,
+ 0x566e, 0x229d,
+ 0x5670, 0x11ef,
+ 0x5672, 0x229f,
+ 0x5673, 0x11f2,
+ 0x5675, 0x22a0,
+ 0x5677, 0x11f6,
+ 0x567c, 0x22a2,
+ 0x5721, 0x11fe,
+ 0x5724, 0x22a5,
+ 0x5725, 0x1202,
+ 0x5728, 0x22a6,
+ 0x572b, 0x1208,
+ 0x572c, 0x22a9,
+ 0x572d, 0x120a,
+ 0x572e, 0x22aa,
+ 0x5732, 0x120f,
+ 0x5733, 0x22ae,
+ 0x5735, 0x1212,
+ 0x5736, 0x22b0,
+ 0x5737, 0x1214,
+ 0x5738, 0x22b1,
+ 0x573d, 0x121a,
+ 0x5747, 0x22b6,
+ 0x5748, 0x1225,
+ 0x574a, 0x22b7,
+ 0x574b, 0x1228,
+ 0x5755, 0x22b8,
+ 0x5756, 0x1233,
+ 0x575b, 0x22b9,
+ 0x575f, 0x123c,
+ 0x5767, 0x22bd,
+ 0x5768, 0x1245,
+ 0x5769, 0x22be,
+ 0x576b, 0x1248,
+ 0x5821, 0x1257,
+ 0x5844, 0x22c0,
+ 0x5845, 0x127b,
+ 0x5847, 0x22c1,
+ 0x5848, 0x127e,
+ 0x5849, 0x22c2,
+ 0x584a, 0x1280,
+ 0x584c, 0x22c3,
+ 0x584e, 0x1284,
+ 0x5850, 0x22c5,
+ 0x5852, 0x1288,
+ 0x5853, 0x22c7,
+ 0x5854, 0x128a,
+ 0x5859, 0x22c8,
+ 0x585a, 0x1290,
+ 0x585b, 0x22c9,
+ 0x585d, 0x1293,
+ 0x5871, 0x22cb,
+ 0x5872, 0x12a8,
+ 0x5876, 0x22cc,
+ 0x5878, 0x12ae,
+ 0x5921, 0x12b5,
+ 0x592d, 0x22ce,
+ 0x592e, 0x12c2,
+ 0x592f, 0x22cf,
+ 0x5930, 0x12c4,
+ 0x5931, 0x22d0,
+ 0x5934, 0x12c8,
+ 0x5947, 0x22d3,
+ 0x5948, 0x12dc,
+ 0x594d, 0x22d4,
+ 0x5951, 0x12e5,
+ 0x595d, 0x22d8,
+ 0x595e, 0x12f2,
+ 0x5961, 0x22d9,
+ 0x5962, 0x12f6,
+ 0x5964, 0x22da,
+ 0x5965, 0x12f9,
+ 0x5966, 0x22db,
+ 0x5967, 0x12fb,
+ 0x596c, 0x22dc,
+ 0x596d, 0x1301,
+ 0x5974, 0x22dd,
+ 0x5976, 0x130a,
+ 0x5a21, 0x1313,
+ 0x5a25, 0x22df,
+ 0x5a60, 0x1352,
+ 0x5a6a, 0x231a,
+ 0x5a6b, 0x135d,
+ 0x5a77, 0x231b,
+ 0x5a78, 0x136a,
+ 0x5a79, 0x231c,
+ 0x5a7a, 0x136c,
+ 0x5a7e, 0x231d,
+ 0x5b21, 0x1371,
+ 0x5b23, 0x231e,
+ 0x5b24, 0x1374,
+ 0x5b26, 0x231f,
+ 0x5b27, 0x1377,
+ 0x5b29, 0x2320,
+ 0x5b2b, 0x137b,
+ 0x5b3b, 0x2322,
+ 0x5b3c, 0x138c,
+ 0x5b3d, 0x2323,
+ 0x5b3e, 0x138e,
+ 0x5b4f, 0x2324,
+ 0x5b50, 0x13a0,
+ 0x5b51, 0x2325,
+ 0x5b52, 0x13a2,
+ 0x5b5b, 0x2326,
+ 0x5b5c, 0x13ac,
+ 0x5b5e, 0x2327,
+ 0x5b5f, 0x13af,
+ 0x5b62, 0x2328,
+ 0x5b63, 0x13b3,
+ 0x5b64, 0x2329,
+ 0x5b65, 0x13b5,
+ 0x5b6b, 0x232a,
+ 0x5b6c, 0x13bc,
+ 0x5b6e, 0x232b,
+ 0x5b6f, 0x13bf,
+ 0x5b71, 0x232c,
+ 0x5b72, 0x13c2,
+ 0x5b75, 0x232d,
+ 0x5b78, 0x13c8,
+ 0x5c21, 0x13cf,
+ 0x5c3c, 0x2330,
+ 0x5c3d, 0x13eb,
+ 0x5c3f, 0x2331,
+ 0x5c40, 0x13ee,
+ 0x5c42, 0x2332,
+ 0x5c43, 0x13f1,
+ 0x5c48, 0x2333,
+ 0x5c4b, 0x13f9,
+ 0x5c51, 0x2336,
+ 0x5c52, 0x1400,
+ 0x5c57, 0x2337,
+ 0x5c58, 0x1406,
+ 0x5c60, 0x2338,
+ 0x5c61, 0x140f,
+ 0x5c63, 0x2339,
+ 0x5c65, 0x1413,
+ 0x5c69, 0x233b,
+ 0x5c6b, 0x1419,
+ 0x5c71, 0x233d,
+ 0x5c72, 0x1420,
+ 0x5c76, 0x233e,
+ 0x5c77, 0x1425,
+ 0x5c79, 0x233f,
+ 0x5c7a, 0x1428,
+ 0x5c7d, 0x2340,
+ 0x5d21, 0x2342,
+ 0x5d22, 0x142e,
+ 0x5d23, 0x2343,
+ 0x5d28, 0x1434,
+ 0x5d2a, 0x2348,
+ 0x5d2c, 0x1438,
+ 0x5d32, 0x234a,
+ 0x5d33, 0x143f,
+ 0x5d35, 0x234b,
+ 0x5d36, 0x1442,
+ 0x5d3a, 0x234c,
+ 0x5d3c, 0x1448,
+ 0x5d53, 0x234e,
+ 0x5d54, 0x1460,
+ 0x5d5b, 0x234f,
+ 0x5d5c, 0x1468,
+ 0x5d5e, 0x2350,
+ 0x5d5f, 0x146b,
+ 0x5d64, 0x2351,
+ 0x5d65, 0x1471,
+ 0x5d6b, 0x2352,
+ 0x5d6c, 0x1478,
+ 0x5d71, 0x2353,
+ 0x5d72, 0x147e,
+ 0x5d76, 0x2354,
+ 0x5d78, 0x1484,
+ 0x5d7c, 0x2356,
+ 0x5d7d, 0x1489,
+ 0x5d7e, 0x2357,
+ 0x5e21, 0x148b,
+ 0x5e2d, 0x2358,
+ 0x5e2e, 0x1498,
+ 0x5e34, 0x2359,
+ 0x5e35, 0x149f,
+ 0x5e3a, 0x235a,
+ 0x5e3b, 0x14a5,
+ 0x5e46, 0x235b,
+ 0x5e47, 0x14b1,
+ 0x5e4f, 0x235c,
+ 0x5e50, 0x14ba,
+ 0x5e51, 0x235d,
+ 0x5e53, 0x14bd,
+ 0x5e58, 0x235f,
+ 0x5e59, 0x14c3,
+ 0x5e62, 0x2360,
+ 0x5e63, 0x14cd,
+ 0x5e68, 0x2361,
+ 0x5e69, 0x14d3,
+ 0x5e6c, 0x2362,
+ 0x5e6d, 0x14d7,
+ 0x5e73, 0x2363,
+ 0x5e74, 0x14de,
+ 0x5e7c, 0x2364,
+ 0x5e7d, 0x14e7,
+ 0x5f21, 0x14e9,
+ 0x5f22, 0x2365,
+ 0x5f24, 0x14ec,
+ 0x5f25, 0x2367,
+ 0x5f26, 0x14ee,
+ 0x5f34, 0x2368,
+ 0x5f35, 0x14fd,
+ 0x5f3c, 0x2369,
+ 0x5f3e, 0x1506,
+ 0x5f3f, 0x236b,
+ 0x5f40, 0x1508,
+ 0x5f42, 0x236c,
+ 0x5f44, 0x150c,
+ 0x5f4c, 0x236e,
+ 0x5f4d, 0x1515,
+ 0x5f50, 0x236f,
+ 0x5f51, 0x1519,
+ 0x5f55, 0x2370,
+ 0x5f56, 0x151e,
+ 0x5f58, 0x2371,
+ 0x5f5a, 0x1522,
+ 0x5f5c, 0x2373,
+ 0x5f5d, 0x1525,
+ 0x5f60, 0x2374,
+ 0x5f61, 0x1529,
+ 0x5f62, 0x2375,
+ 0x5f63, 0x152b,
+ 0x5f66, 0x2376,
+ 0x5f67, 0x152f,
+ 0x5f69, 0x2377,
+ 0x5f6a, 0x1532,
+ 0x5f6b, 0x2378,
+ 0x5f6c, 0x1534,
+ 0x5f6f, 0x2379,
+ 0x5f70, 0x1538,
+ 0x5f75, 0x237a,
+ 0x5f76, 0x153e,
+ 0x5f79, 0x237b,
+ 0x5f7a, 0x1542,
+ 0x6021, 0x1547,
+ 0x6036, 0x237c,
+ 0x6038, 0x155e,
+ 0x603f, 0x237e,
+ 0x6040, 0x1566,
+ 0x6048, 0x237f,
+ 0x6049, 0x156f,
+ 0x604e, 0x2380,
+ 0x604f, 0x1575,
+ 0x6053, 0x2381,
+ 0x6054, 0x157a,
+ 0x6060, 0x2382,
+ 0x6061, 0x1587,
+ 0x6070, 0x2383,
+ 0x6071, 0x1597,
+ 0x6078, 0x2384,
+ 0x6079, 0x159f,
+ 0x607c, 0x2385,
+ 0x6121, 0x15a5,
+ 0x612b, 0x2388,
+ 0x612c, 0x15b0,
+ 0x612d, 0x2389,
+ 0x612e, 0x15b2,
+ 0x6130, 0x238a,
+ 0x6131, 0x15b5,
+ 0x6134, 0x238b,
+ 0x6135, 0x15b9,
+ 0x613b, 0x238c,
+ 0x613c, 0x15c0,
+ 0x613d, 0x238d,
+ 0x613e, 0x15c2,
+ 0x6140, 0x238e,
+ 0x6142, 0x15c6,
+ 0x6149, 0x2390,
+ 0x614a, 0x15ce,
+ 0x6150, 0x2391,
+ 0x6151, 0x15d5,
+ 0x615b, 0x2392,
+ 0x615c, 0x15e0,
+ 0x6161, 0x07aa,
+ 0x6162, 0x2393,
+ 0x6163, 0x15e7,
+ 0x6167, 0x1198,
+ 0x6168, 0x15ec,
+ 0x616e, 0x2394,
+ 0x6170, 0x15f4,
+ 0x6176, 0x2396,
+ 0x6177, 0x15fb,
+ 0x6178, 0x2397,
+ 0x6179, 0x15fd,
+ 0x617d, 0x2398,
+ 0x617e, 0x1602,
+ 0x6221, 0x1603,
+ 0x6224, 0x2399,
+ 0x6225, 0x1607,
+ 0x6228, 0x239a,
+ 0x6229, 0x160b,
+ 0x623b, 0x239b,
+ 0x6245, 0x10c5,
+ 0x6246, 0x23a5,
+ 0x624f, 0x1631,
+ 0x6250, 0x23ae,
+ 0x6251, 0x1633,
+ 0x6259, 0x23af,
+ 0x625a, 0x163c,
+ 0x6263, 0x23b0,
+ 0x6265, 0x1647,
+ 0x6266, 0x23b2,
+ 0x6267, 0x1649,
+ 0x6269, 0x23b3,
+ 0x626c, 0x164e,
+ 0x6278, 0x23b6,
+ 0x6279, 0x165b,
+ 0x627a, 0x23b7,
+ 0x627e, 0x1660,
+ 0x6321, 0x1661,
+ 0x6322, 0x23bb,
+ 0x6323, 0x1663,
+ 0x6325, 0x23bc,
+ 0x6326, 0x1666,
+ 0x632b, 0x23bd,
+ 0x632c, 0x166c,
+ 0x6334, 0x23be,
+ 0x6335, 0x1675,
+ 0x6345, 0x23bf,
+ 0x635c, 0x169c,
+ 0x6363, 0x23d6,
+ 0x6364, 0x16a4,
+ 0x636d, 0x23d7,
+ 0x636e, 0x16ae,
+ 0x6371, 0x23d8,
+ 0x6373, 0x16b3,
+ 0x6378, 0x23da,
+ 0x6379, 0x16b9,
+ 0x637e, 0x23db,
+ 0x6421, 0x16bf,
+ 0x6424, 0x23dc,
+ 0x6426, 0x16c4,
+ 0x642b, 0x23de,
+ 0x642c, 0x16ca,
+ 0x642f, 0x23df,
+ 0x6432, 0x16d0,
+ 0x6435, 0x23e2,
+ 0x6437, 0x16d5,
+ 0x6442, 0x23e4,
+ 0x6443, 0x16e1,
+ 0x6445, 0x23e5,
+ 0x6446, 0x16e4,
+ 0x6449, 0x23e6,
+ 0x644a, 0x16e8,
+ 0x6459, 0x23e7,
+ 0x645a, 0x16f8,
+ 0x645c, 0x23e8,
+ 0x645d, 0x16fb,
+ 0x645e, 0x23e9,
+ 0x645f, 0x16fd,
+ 0x6464, 0x23ea,
+ 0x6465, 0x1703,
+ 0x646b, 0x23eb,
+ 0x646d, 0x170b,
+ 0x6472, 0x23ed,
+ 0x6473, 0x1711,
+ 0x647e, 0x23ee,
+ 0x6521, 0x171d,
+ 0x6530, 0x23ef,
+ 0x6531, 0x172d,
+ 0x6539, 0x23f0,
+ 0x653a, 0x1736,
+ 0x6547, 0x23f1,
+ 0x6548, 0x1744,
+ 0x6549, 0x23f2,
+ 0x654a, 0x1746,
+ 0x654e, 0x23f3,
+ 0x654f, 0x174b,
+ 0x6570, 0x23f4,
+ 0x6571, 0x176d,
+ 0x6572, 0x23f5,
+ 0x6573, 0x176f,
+ 0x657c, 0x23f6,
+ 0x657e, 0x177a,
+ 0x6621, 0x177b,
+ 0x6623, 0x23f8,
+ 0x6624, 0x177e,
+ 0x662b, 0x23f9,
+ 0x662d, 0x1787,
+ 0x662e, 0x23fb,
+ 0x662f, 0x1789,
+ 0x6634, 0x23fc,
+ 0x6636, 0x1790,
+ 0x663f, 0x23fe,
+ 0x6640, 0x179a,
+ 0x6648, 0x23ff,
+ 0x664a, 0x17a4,
+ 0x664d, 0x2401,
+ 0x664e, 0x17a8,
+ 0x6660, 0x2402,
+ 0x6721, 0x2421,
+ 0x675b, 0x1813,
+ 0x6761, 0x245b,
+ 0x6763, 0x181b,
+ 0x6767, 0x245d,
+ 0x6768, 0x1820,
+ 0x676f, 0x245e,
+ 0x6770, 0x1828,
+ 0x6774, 0x245f,
+ 0x6777, 0x182f,
+ 0x6821, 0x1837,
+ 0x6828, 0x2462,
+ 0x6829, 0x183f,
+ 0x682c, 0x2463,
+ 0x682d, 0x1843,
+ 0x6836, 0x2464,
+ 0x6837, 0x184d,
+ 0x6838, 0x2465,
+ 0x683b, 0x1851,
+ 0x683f, 0x2468,
+ 0x6841, 0x1857,
+ 0x6845, 0x246a,
+ 0x6846, 0x185c,
+ 0x6847, 0x246b,
+ 0x684a, 0x1860,
+ 0x684e, 0x246e,
+ 0x684f, 0x1865,
+ 0x6850, 0x246f,
+ 0x6851, 0x1867,
+ 0x6853, 0x2470,
+ 0x6854, 0x186a,
+ 0x685d, 0x2471,
+ 0x685e, 0x1874,
+ 0x685f, 0x2472,
+ 0x6860, 0x1876,
+ 0x6862, 0x2473,
+ 0x6864, 0x187a,
+ 0x6865, 0x2475,
+ 0x6866, 0x187c,
+ 0x6867, 0x2476,
+ 0x6868, 0x187e,
+ 0x686b, 0x2477,
+ 0x686c, 0x1882,
+ 0x686d, 0x2478,
+ 0x686e, 0x1884,
+ 0x686f, 0x2479,
+ 0x6870, 0x1886,
+ 0x6879, 0x247a,
+ 0x687a, 0x1890,
+ 0x687c, 0x247b,
+ 0x687e, 0x1894,
+ 0x6921, 0x247d,
+ 0x6922, 0x1896,
+ 0x692d, 0x247e,
+ 0x692e, 0x18a2,
+ 0x6934, 0x247f,
+ 0x6936, 0x18aa,
+ 0x6937, 0x2481,
+ 0x6938, 0x18ac,
+ 0x6944, 0x2482,
+ 0x6945, 0x18b9,
+ 0x6946, 0x2483,
+ 0x6947, 0x18bb,
+ 0x6949, 0x2484,
+ 0x694a, 0x18be,
+ 0x6956, 0x2485,
+ 0x6957, 0x18cb,
+ 0x695a, 0x2486,
+ 0x695b, 0x18cf,
+ 0x6964, 0x2487,
+ 0x6965, 0x18d9,
+ 0x6966, 0x2488,
+ 0x6968, 0x18dc,
+ 0x6969, 0x248a,
+ 0x696a, 0x18de,
+ 0x696b, 0x248b,
+ 0x696c, 0x18e0,
+ 0x696d, 0x248c,
+ 0x6a21, 0x249e,
+ 0x6a26, 0x18f8,
+ 0x6a27, 0x24a3,
+ 0x6a29, 0x18fb,
+ 0x6a31, 0x24a5,
+ 0x6a32, 0x1904,
+ 0x6a3c, 0x24a6,
+ 0x6a3d, 0x190f,
+ 0x6a4a, 0x24a7,
+ 0x6a4b, 0x191d,
+ 0x6a4d, 0x24a8,
+ 0x6a4e, 0x1920,
+ 0x6a53, 0x24a9,
+ 0x6a54, 0x1926,
+ 0x6a5a, 0x24aa,
+ 0x6a70, 0x1942,
+ 0x6b21, 0x1951,
+ 0x6b27, 0x24c0,
+ 0x6b28, 0x1958,
+ 0x6b2a, 0x24c1,
+ 0x6b2b, 0x195b,
+ 0x6b32, 0x24c2,
+ 0x6b33, 0x1963,
+ 0x6b39, 0x24c3,
+ 0x6b3a, 0x196a,
+ 0x6b4a, 0x24c4,
+ 0x6b4c, 0x197c,
+ 0x6b4d, 0x24c6,
+ 0x6b4e, 0x197e,
+ 0x6b56, 0x24c7,
+ 0x6b57, 0x1987,
+ 0x6b5a, 0x24c8,
+ 0x6b5b, 0x198b,
+ 0x6b61, 0x24c9,
+ 0x6b62, 0x1992,
+ 0x6b77, 0x24ca,
+ 0x6b78, 0x19a8,
+ 0x6c21, 0x19af,
+ 0x6c23, 0x24cb,
+ 0x6c24, 0x19b2,
+ 0x6c29, 0x24cc,
+ 0x6c2f, 0x19bd,
+ 0x6c31, 0x24d2,
+ 0x6c32, 0x19c0,
+ 0x6c34, 0x24d3,
+ 0x6c36, 0x19c4,
+ 0x6c3e, 0x24d5,
+ 0x6c40, 0x19ce,
+ 0x6c41, 0x24d7,
+ 0x6c42, 0x19d0,
+ 0x6c47, 0x24d8,
+ 0x6c48, 0x19d6,
+ 0x6c4b, 0x24d9,
+ 0x6c4c, 0x19da,
+ 0x6c62, 0x24da,
+ 0x6c63, 0x19f1,
+ 0x6c72, 0x24db,
+ 0x6c73, 0x1a01,
+ 0x6c75, 0x24dc,
+ 0x6c76, 0x1a04,
+ 0x6c78, 0x24dd,
+ 0x6c79, 0x1a07,
+ 0x6d21, 0x24de,
+ 0x6d22, 0x1a0e,
+ 0x6d28, 0x24df,
+ 0x6d29, 0x1a15,
+ 0x6d2f, 0x24e0,
+ 0x6d31, 0x1a1d,
+ 0x6d34, 0x24e2,
+ 0x6d35, 0x1a21,
+ 0x6d36, 0x24e3,
+ 0x6d37, 0x1a23,
+ 0x6d38, 0x24e4,
+ 0x6d39, 0x1a25,
+ 0x6d3a, 0x24e5,
+ 0x6d3b, 0x1a27,
+ 0x6d3f, 0x24e6,
+ 0x6d40, 0x1a2c,
+ 0x6d42, 0x24e7,
+ 0x6d44, 0x1a30,
+ 0x6d4c, 0x24e9,
+ 0x6d4e, 0x1a3a,
+ 0x6d53, 0x24eb,
+ 0x6d54, 0x1a40,
+ 0x6d57, 0x24ec,
+ 0x6d58, 0x1a44,
+ 0x6d68, 0x24ed,
+ 0x6d69, 0x1a55,
+ 0x6d6e, 0x24ee,
+ 0x6d6f, 0x1a5b,
+ 0x6d79, 0x24ef,
+ 0x6d7b, 0x1a67,
+ 0x6e21, 0x1a6b,
+ 0x6e3c, 0x24f1,
+ 0x6e3d, 0x1a87,
+ 0x6e3f, 0x24f2,
+ 0x6e40, 0x1a8a,
+ 0x6e44, 0x24f3,
+ 0x6f21, 0x252e,
+ 0x6f72, 0x1b1a,
+ 0x7021, 0x1b27,
+ 0x7023, 0x257f,
+ 0x7024, 0x1b2a,
+ 0x702f, 0x2580,
+ 0x705a, 0x1b60,
+ 0x705c, 0x25ab,
+ 0x705e, 0x1b64,
+ 0x705f, 0x25ad,
+ 0x7060, 0x1b66,
+ 0x7069, 0x25ae,
+ 0x706a, 0x1b70,
+ 0x706c, 0x25af,
+ 0x706d, 0x1b73,
+ 0x706f, 0x25b0,
+ 0x7070, 0x1b76,
+ 0x7077, 0x25b1,
+ 0x7078, 0x1b7e,
+ 0x7079, 0x25b2,
+ 0x707a, 0x1b80,
+ 0x707c, 0x25b3,
+ 0x707d, 0x1b83,
+ 0x7121, 0x1b85,
+ 0x7128, 0x25b4,
+ 0x7129, 0x1b8d,
+ 0x712b, 0x25b5,
+ 0x712c, 0x1b90,
+ 0x712e, 0x25b6,
+ 0x712f, 0x1b93,
+ 0x7132, 0x25b7,
+ 0x7133, 0x1b97,
+ 0x713c, 0x25b8,
+ 0x713d, 0x1ba1,
+ 0x7140, 0x25b9,
+ 0x7141, 0x1ba5,
+ 0x7149, 0x25ba,
+ 0x714a, 0x1bae,
+ 0x714d, 0x25bb,
+ 0x714e, 0x1bb2,
+ 0x714f, 0x25bc,
+ 0x7151, 0x1bb5,
+ 0x715a, 0x25be,
+ 0x715b, 0x1bbf,
+ 0x715c, 0x25bf,
+ 0x715d, 0x1bc1,
+ 0x7164, 0x25c0,
+ 0x7165, 0x1bc9,
+ 0x716c, 0x25c1,
+ 0x716d, 0x1bd1,
+ 0x716f, 0x25c2,
+ 0x7170, 0x1bd4,
+ 0x7177, 0x25c3,
+ 0x7178, 0x1bdc,
+ 0x7179, 0x25c4,
+ 0x717a, 0x1bde,
+ 0x717c, 0x25c5,
+ 0x7221, 0x25c8,
+ 0x722e, 0x1bf0,
+ 0x7231, 0x25d5,
+ 0x7233, 0x1bf5,
+ 0x7239, 0x25d7,
+ 0x723a, 0x1bfc,
+ 0x7243, 0x25d8,
+ 0x7244, 0x1c06,
+ 0x7249, 0x25d9,
+ 0x724a, 0x1c0c,
+ 0x724c, 0x25da,
+ 0x724e, 0x1c10,
+ 0x724f, 0x25dc,
+ 0x7250, 0x1c12,
+ 0x7253, 0x25dd,
+ 0x7254, 0x1c16,
+ 0x7265, 0x25de,
+ 0x7266, 0x1c28,
+ 0x726e, 0x25df,
+ 0x726f, 0x1c31,
+ 0x7277, 0x25e0,
+ 0x7278, 0x1c3a,
+ 0x727d, 0x25e1,
+ 0x727e, 0x1c40,
+ 0x7321, 0x1c41,
+ 0x733f, 0x25e2,
+ 0x7340, 0x1c60,
+ 0x7346, 0x25e3,
+ 0x7347, 0x1c67,
+ 0x7348, 0x25e4,
+ 0x7349, 0x1c69,
+ 0x7356, 0x25e5,
+ 0x7357, 0x1c77,
+ 0x7359, 0x25e6,
+ 0x735a, 0x1c7a,
+ 0x7365, 0x25e7,
+ 0x7367, 0x1c87,
+ 0x736a, 0x25e9,
+ 0x736b, 0x1c8b,
+ 0x736c, 0x25ea,
+ 0x736d, 0x1c8d,
+ 0x736f, 0x25eb,
+ 0x7370, 0x1c90,
+ 0x7371, 0x25ec,
+ 0x7372, 0x1c92,
+ 0x737d, 0x25ed,
+ 0x737e, 0x1c9e,
+ 0x7421, 0x1c9f,
+ 0x7425, 0x25ee,
+ 0x7426, 0x1ca4,
+ 0x742f, 0x25ef,
+ 0x7430, 0x1cae,
+ 0x7435, 0x25f0,
+ 0x7436, 0x1cb4,
+ 0x7441, 0x25f1,
+ 0x7442, 0x1cc0,
+ 0x7447, 0x25f2,
+ 0x7448, 0x1cc6,
+ 0x744f, 0x25f3,
+ 0x7451, 0x1ccf,
+ 0x7456, 0x25f5,
+ 0x7457, 0x1cd5,
+ 0x746a, 0x25f6,
+ 0x746b, 0x1ce9,
+ 0x746f, 0x25f7,
+ 0x7470, 0x1cee,
+ 0x7475, 0x25f8,
+ 0x7476, 0x1cf4,
+ 0x7521, 0x1cfd,
+ 0x7526, 0x25f9,
+ 0x7528, 0x1d04,
+ 0x753a, 0x25fb,
+ 0x753c, 0x1d18,
+ 0x7544, 0x25fd,
+ 0x7545, 0x1d21,
+ 0x7548, 0x25fe,
+ 0x7549, 0x1d25,
+ 0x754e, 0x25ff,
+ 0x7550, 0x1d2c,
+ 0x7551, 0x2601,
+ 0x7553, 0x1d2f,
+ 0x7559, 0x2603,
+ 0x755a, 0x1d36,
+ 0x755c, 0x2604,
+ 0x755d, 0x1d39,
+ 0x7566, 0x2605,
+ 0x7568, 0x1d44,
+ 0x756f, 0x2607,
+ 0x7570, 0x1d4c,
+ 0x7572, 0x2608,
+ 0x7573, 0x1d4f,
+ 0x757c, 0x2609,
+ 0x757d, 0x1d59,
+ 0x7621, 0x1d5b,
+ 0x7623, 0x260a,
+ 0x7624, 0x1d5e,
+ 0x7626, 0x260b,
+ 0x7627, 0x1d61,
+ 0x7628, 0x260c,
+ 0x7629, 0x1d63,
+ 0x762b, 0x260d,
+ 0x762c, 0x1d66,
+ 0x7630, 0x260e,
+ 0x7631, 0x1d6b,
+ 0x7633, 0x260f,
+ 0x763f, 0x1d79,
+ 0x7645, 0x261b,
+ 0x7646, 0x1d80,
+ 0x7647, 0x261c,
+ 0x7648, 0x1d82,
+ 0x7649, 0x261d,
+ 0x764a, 0x1d84,
+ 0x764f, 0x261e,
+ 0x7721, 0x264e,
+ 0x7730, 0x1dc8,
+ 0x7732, 0x265d,
+ 0x7734, 0x1dcc,
+ 0x7735, 0x265f,
+ 0x7736, 0x1dce,
+ 0x773d, 0x2660,
+ 0x773e, 0x1dd6,
+ 0x7743, 0x2661,
+ 0x7744, 0x1ddc,
+ 0x7745, 0x2662,
+ 0x7747, 0x1ddf,
+ 0x774a, 0x2664,
+ 0x774c, 0x1de4,
+ 0x774f, 0x2666,
+ 0x7751, 0x1de9,
+ 0x775e, 0x2668,
+ 0x775f, 0x1df7,
+ 0x7761, 0x0ab9,
+ 0x7762, 0x1dfa,
+ 0x7772, 0x2669,
+ 0x7773, 0x1e0b,
+ 0x7775, 0x266a,
+ 0x7776, 0x1e0e,
+ 0x7821, 0x266b,
+ 0x7827, 0x04cc,
+ 0x7828, 0x050a,
+ 0x7829, 0x0518,
+ 0x782a, 0x2671,
+ 0x782c, 0x0594,
+ 0x782d, 0x05ce,
+ 0x782e, 0x2673,
+ 0x782f, 0x05f6,
+ 0x7830, 0x2674,
+ 0x7832, 0x0653,
+ 0x7833, 0x067e,
+ 0x7834, 0x2676,
+ 0x7835, 0x06c4,
+ 0x7836, 0x2677,
+ 0x7838, 0x073c,
+ 0x7839, 0x2679,
+ 0x783b, 0x07c3,
+ 0x783c, 0x267b,
+ 0x7840, 0x082b,
+ 0x7841, 0x267f,
+ 0x7842, 0x084e,
+ 0x7843, 0x0869,
+ 0x7844, 0x2680,
+ 0x7846, 0x090c,
+ 0x7847, 0x2682,
+ 0x7849, 0x0971,
+ 0x784a, 0x2684,
+ 0x784b, 0x099a,
+ 0x784d, 0x2685,
+ 0x784e, 0x09da,
+ 0x784f, 0x2686,
+ 0x7850, 0x09fa,
+ 0x7851, 0x2687,
+ 0x785c, 0x0bda,
+ 0x785d, 0x0bdd,
+ 0x785e, 0x0bea,
+ 0x785f, 0x0bec,
+ 0x7860, 0x0bf2,
+ 0x7861, 0x2692,
+ 0x7866, 0x0c92,
+ 0x7867, 0x0d1a,
+ 0x7868, 0x0d8c,
+ 0x7869, 0x0dbe,
+ 0x786a, 0x2697,
+ 0x786b, 0x0dfb,
+ 0x786c, 0x2698,
+ 0x786f, 0x0e70,
+ 0x7870, 0x269b,
+ 0x7871, 0x0ea3,
+ 0x7872, 0x269c,
+ 0x7878, 0x103d,
+ 0x7879, 0x10d9,
+ 0x787a, 0x26a2,
+ 0x787c, 0x10fb,
+ 0x787d, 0x1109,
+ 0x787e, 0x26a4,
+ 0x7921, 0x11a1,
+ 0x7922, 0x26a5,
+ 0x7923, 0x11ba,
+ 0x7924, 0x26a6,
+ 0x7926, 0x11d5,
+ 0x7927, 0x26a8,
+ 0x7928, 0x11fd,
+ 0x7929, 0x1219,
+ 0x2122, 0x023f,
+ 0x2123, 0x023e,
+ 0x212a, 0x0256,
+ 0x212b, 0x1e18,
+ 0x212d, 0x0257,
+ 0x2132, 0x0246,
+ 0x217e, 0x1e1a,
+ 0x2321, 0x0242,
+ 0x2328, 0x0244,
+ 0x232c, 0x023d,
+ 0x232e, 0x1e1b,
+ 0x233a, 0x0240,
+ 0x233d, 0x1e1c,
+ 0x233f, 0x0243,
+ 0x235b, 0x1e1d,
+ 0x235d, 0x1e1e,
+ 0x235f, 0x0258,
+ 0x237b, 0x0254,
+ 0x237d, 0x0255,
+ 0x237e, 0x1e1f,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 gb12GBTVEnc16 = {
+ 1,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ gb12GBTVMap2, 2303
+};
+
+static Gushort gb12GBTpcEUCHMap2[4566] = {
+ 0x0000, 0x0000,
+ 0xa1a1, 0x0060,
+ 0xa2b1, 0x00be,
+ 0xa2e5, 0x00f0,
+ 0xa2f1, 0x00fa,
+ 0xa3a1, 0x0106,
+ 0xa4a1, 0x0164,
+ 0xa5a1, 0x01b7,
+ 0xa6a1, 0x020d,
+ 0xa6c1, 0x0225,
+ 0xa7a1, 0x025a,
+ 0xa7d1, 0x027b,
+ 0xa8a1, 0x029c,
+ 0xa8c5, 0x02bc,
+ 0xa9a4, 0x02e2,
+ 0xaaa1, 0x032e,
+ 0xaba1, 0x038c,
+ 0xb0a1, 0x03ac,
+ 0xb0a8, 0x1e25,
+ 0xb0a9, 0x03b4,
+ 0xb0aa, 0x1e26,
+ 0xb0ab, 0x03b6,
+ 0xb0ad, 0x1e27,
+ 0xb0af, 0x03ba,
+ 0xb0b9, 0x1e29,
+ 0xb0ba, 0x03c5,
+ 0xb0c0, 0x1e2a,
+ 0xb0c1, 0x03cc,
+ 0xb0d3, 0x1e2b,
+ 0xb0d4, 0x03df,
+ 0xb0d5, 0x1e2c,
+ 0xb0d6, 0x03e1,
+ 0xb0da, 0x1e2d,
+ 0xb0db, 0x03e6,
+ 0xb0dc, 0x1e2e,
+ 0xb0dd, 0x03e8,
+ 0xb0e4, 0x1e2f,
+ 0xb0e5, 0x03f0,
+ 0xb0ec, 0x1e30,
+ 0xb0ee, 0x03f9,
+ 0xb0ef, 0x1e32,
+ 0xb0f0, 0x03fb,
+ 0xb0f3, 0x1e33,
+ 0xb0f4, 0x03ff,
+ 0xb0f7, 0x1e34,
+ 0xb0f8, 0x0403,
+ 0xb0f9, 0x1e35,
+ 0xb0fa, 0x0405,
+ 0xb1a1, 0x040a,
+ 0xb1a5, 0x1e36,
+ 0xb1a7, 0x0410,
+ 0xb1a8, 0x1e38,
+ 0xb1a9, 0x0412,
+ 0xb1ab, 0x1e39,
+ 0xb1ac, 0x0415,
+ 0xb1b2, 0x1e3a,
+ 0xb1b3, 0x041c,
+ 0xb1b4, 0x1e3b,
+ 0xb1b6, 0x041f,
+ 0xb1b7, 0x1e3d,
+ 0xb1ba, 0x0423,
+ 0xb1c1, 0x1e40,
+ 0xb1c2, 0x042b,
+ 0xb1ca, 0x1e41,
+ 0xb1cb, 0x0434,
+ 0xb1cf, 0x1e42,
+ 0xb1d1, 0x043a,
+ 0xb1d2, 0x1e44,
+ 0xb1d3, 0x043c,
+ 0xb1d5, 0x1e45,
+ 0xb1d6, 0x043f,
+ 0xb1df, 0x1e46,
+ 0xb1e2, 0x044b,
+ 0xb1e4, 0x1e49,
+ 0xb1e5, 0x044e,
+ 0xb1e7, 0x1e4a,
+ 0xb1e9, 0x0452,
+ 0xb1ea, 0x1e4c,
+ 0xb1eb, 0x0454,
+ 0xb1ee, 0x1e4d,
+ 0xb1ef, 0x0458,
+ 0xb1f1, 0x1e4e,
+ 0xb1f2, 0x045b,
+ 0xb1f4, 0x1e4f,
+ 0xb1f8, 0x0461,
+ 0xb1fd, 0x1e53,
+ 0xb1fe, 0x0467,
+ 0xb2a1, 0x0468,
+ 0xb2a6, 0x1e54,
+ 0xb2a8, 0x046f,
+ 0xb2ac, 0x1e56,
+ 0xb2ad, 0x0474,
+ 0xb2b5, 0x1e57,
+ 0xb2b6, 0x047d,
+ 0xb2b9, 0x1e58,
+ 0xb2ba, 0x0481,
+ 0xb2c6, 0x1e59,
+ 0xb2c7, 0x048e,
+ 0xb2ce, 0x1e5a,
+ 0xb2d8, 0x049f,
+ 0xb2de, 0x1e64,
+ 0xb2df, 0x04a6,
+ 0xb2e0, 0x1e65,
+ 0xb2e1, 0x04a8,
+ 0xb2e2, 0x1e66,
+ 0xb2e4, 0x04ab,
+ 0xb2ef, 0x1e68,
+ 0xb2f0, 0x04b7,
+ 0xb2f3, 0x1e69,
+ 0xb2fd, 0x04c4,
+ 0xb3a1, 0x1e73,
+ 0xb3a3, 0x04c8,
+ 0xb3a4, 0x1e75,
+ 0xb3a8, 0x04cd,
+ 0xb3a9, 0x1e79,
+ 0xb3aa, 0x04cf,
+ 0xb3ae, 0x1e7a,
+ 0xb3af, 0x04d4,
+ 0xb3b5, 0x1e7b,
+ 0xb3b6, 0x04db,
+ 0xb3b9, 0x1e7c,
+ 0xb3ba, 0x04df,
+ 0xb3be, 0x1e7d,
+ 0xb3bf, 0x04e4,
+ 0xb3c2, 0x1e7e,
+ 0xb3c3, 0x04e8,
+ 0xb3c4, 0x1e7f,
+ 0xb3c5, 0x04ea,
+ 0xb3c6, 0x1e80,
+ 0xb3c7, 0x04ec,
+ 0xb3cd, 0x1e81,
+ 0xb3ce, 0x04f3,
+ 0xb3cf, 0x1e82,
+ 0xb3d0, 0x04f5,
+ 0xb3d2, 0x1e83,
+ 0xb3d3, 0x04f8,
+ 0xb3d9, 0x1e84,
+ 0xb3da, 0x04ff,
+ 0xb3db, 0x1e85,
+ 0xb3dc, 0x0501,
+ 0xb3dd, 0x1e86,
+ 0xb3de, 0x0503,
+ 0xb3e3, 0x1e87,
+ 0xb3e4, 0x0509,
+ 0xb3e5, 0x1e88,
+ 0xb3e7, 0x050c,
+ 0xb3e8, 0x1e8a,
+ 0xb3e9, 0x050e,
+ 0xb3eb, 0x1e8b,
+ 0xb3ed, 0x0512,
+ 0xb3ef, 0x1e8d,
+ 0xb3f0, 0x0515,
+ 0xb3f1, 0x1e8e,
+ 0xb3f2, 0x0517,
+ 0xb3f3, 0x1e8f,
+ 0xb3f4, 0x0519,
+ 0xb3fa, 0x1e90,
+ 0xb3fc, 0x0521,
+ 0xb4a1, 0x1e92,
+ 0xb4a3, 0x0526,
+ 0xb4a5, 0x1e94,
+ 0xb4a7, 0x052a,
+ 0xb4ab, 0x1e96,
+ 0xb4ac, 0x052f,
+ 0xb4af, 0x1e97,
+ 0xb4b0, 0x0533,
+ 0xb4b3, 0x1e98,
+ 0xb4b5, 0x0538,
+ 0xb4b8, 0x1e9a,
+ 0xb4b9, 0x053c,
+ 0xb4bf, 0x1e9b,
+ 0xb4c0, 0x0543,
+ 0xb4c2, 0x1e9c,
+ 0xb4c3, 0x0546,
+ 0xb4c7, 0x1e9d,
+ 0xb4c8, 0x054b,
+ 0xb4ca, 0x1e9e,
+ 0xb4cb, 0x054e,
+ 0xb4cd, 0x1e9f,
+ 0xb4ce, 0x0551,
+ 0xb4cf, 0x1ea0,
+ 0xb4d0, 0x0553,
+ 0xb4d3, 0x1ea1,
+ 0xb4d5, 0x0558,
+ 0xb4da, 0x1ea3,
+ 0xb4db, 0x055e,
+ 0xb4dc, 0x1ea4,
+ 0xb4dd, 0x0560,
+ 0xb4ed, 0x1ea5,
+ 0xb4ee, 0x0571,
+ 0xb4ef, 0x1ea6,
+ 0xb4f0, 0x0573,
+ 0xb4f8, 0x1ea7,
+ 0xb4f9, 0x057c,
+ 0xb4fb, 0x1ea8,
+ 0xb4fc, 0x057f,
+ 0xb5a1, 0x0582,
+ 0xb5a3, 0x1ea9,
+ 0xb5a4, 0x0585,
+ 0xb5a5, 0x1eaa,
+ 0xb5a9, 0x058a,
+ 0xb5ac, 0x1eae,
+ 0xb5ad, 0x058e,
+ 0xb5ae, 0x1eaf,
+ 0xb5b0, 0x0591,
+ 0xb5b1, 0x1eb1,
+ 0xb5b6, 0x0597,
+ 0xb5b7, 0x1eb6,
+ 0xb5b8, 0x0599,
+ 0xb5ba, 0x1eb7,
+ 0xb5bd, 0x059e,
+ 0xb5c6, 0x1eba,
+ 0xb5c7, 0x05a8,
+ 0xb5cb, 0x1ebb,
+ 0xb5cc, 0x05ad,
+ 0xb5d0, 0x1ebc,
+ 0xb5d1, 0x05b2,
+ 0xb5d3, 0x1ebd,
+ 0xb5d4, 0x05b5,
+ 0xb5dd, 0x1ebe,
+ 0xb5e0, 0x05c1,
+ 0xb5e3, 0x1ec1,
+ 0xb5e4, 0x05c5,
+ 0xb5e6, 0x1ec2,
+ 0xb5e8, 0x05c9,
+ 0xb5ed, 0x1ec4,
+ 0xb5ee, 0x05cf,
+ 0xb5f6, 0x1ec5,
+ 0xb5f8, 0x05d9,
+ 0xb5fd, 0x1ec7,
+ 0xb5fe, 0x05df,
+ 0xb6a1, 0x05e0,
+ 0xb6a4, 0x1ec8,
+ 0xb6a6, 0x05e5,
+ 0xb6a7, 0x1eca,
+ 0xb6a8, 0x05e7,
+ 0xb6a9, 0x1ecb,
+ 0xb6aa, 0x05e9,
+ 0xb6ab, 0x1ecc,
+ 0xb6ac, 0x05eb,
+ 0xb6af, 0x1ecd,
+ 0xb6b1, 0x05f0,
+ 0xb6b3, 0x1ecf,
+ 0xb6b4, 0x05f3,
+ 0xb6b7, 0x1ed0,
+ 0xb6b8, 0x05f7,
+ 0xb6bf, 0x1ed1,
+ 0xb6c2, 0x0601,
+ 0xb6c4, 0x1ed4,
+ 0xb6c5, 0x0604,
+ 0xb6c6, 0x1ed5,
+ 0xb6c7, 0x0606,
+ 0xb6cd, 0x1ed6,
+ 0xb6ce, 0x060d,
+ 0xb6cf, 0x1ed7,
+ 0xb6d1, 0x0610,
+ 0xb6d3, 0x1ed9,
+ 0xb6d5, 0x0614,
+ 0xb6d6, 0x1edb,
+ 0xb6d7, 0x0616,
+ 0xb6d9, 0x1edc,
+ 0xb6da, 0x0619,
+ 0xb6db, 0x1edd,
+ 0xb6dc, 0x061b,
+ 0xb6e1, 0x1ede,
+ 0xb6e2, 0x0621,
+ 0xb6e9, 0x1edf,
+ 0xb6ea, 0x0629,
+ 0xb6ec, 0x1ee0,
+ 0xb6ed, 0x062c,
+ 0xb6ee, 0x1ee1,
+ 0xb6f0, 0x062f,
+ 0xb6f1, 0x1ee3,
+ 0xb6f2, 0x0631,
+ 0xb6f6, 0x1ee4,
+ 0xb6f7, 0x0636,
+ 0xb6f9, 0x1ee5,
+ 0xb6fa, 0x0639,
+ 0xb6fb, 0x1ee6,
+ 0xb6fd, 0x063c,
+ 0xb7a1, 0x1ee8,
+ 0xb7a4, 0x0641,
+ 0xb7a7, 0x1eeb,
+ 0xb7a8, 0x0645,
+ 0xb7af, 0x1eec,
+ 0xb7b1, 0x064e,
+ 0xb7b3, 0x1eee,
+ 0xb7b4, 0x0651,
+ 0xb7b6, 0x1eef,
+ 0xb7b8, 0x0655,
+ 0xb7b9, 0x1ef1,
+ 0xb7ba, 0x0657,
+ 0xb7c3, 0x1ef2,
+ 0xb7c5, 0x0662,
+ 0xb7c9, 0x1ef4,
+ 0xb7ca, 0x0667,
+ 0xb7cc, 0x1ef5,
+ 0xb7cd, 0x066a,
+ 0xb7cf, 0x1ef6,
+ 0xb7d0, 0x066d,
+ 0xb7d1, 0x1ef7,
+ 0xb7d2, 0x066f,
+ 0xb7d7, 0x1ef8,
+ 0xb7d9, 0x0676,
+ 0xb7dc, 0x1efa,
+ 0xb7dd, 0x067a,
+ 0xb7df, 0x1efb,
+ 0xb7e2, 0x067f,
+ 0xb7e3, 0x1efe,
+ 0xb7e4, 0x0681,
+ 0xb7e6, 0x1eff,
+ 0xb7e9, 0x0686,
+ 0xb7eb, 0x1f02,
+ 0xb7ee, 0x068b,
+ 0xb7ef, 0x1f05,
+ 0xb7f0, 0x068d,
+ 0xb7f4, 0x1f06,
+ 0xb7f5, 0x0692,
+ 0xb7f8, 0x1f07,
+ 0xb7f9, 0x0696,
+ 0xb8a1, 0x069c,
+ 0xb8a7, 0x1f08,
+ 0xb8a9, 0x06a4,
+ 0xb8b3, 0x1f0a,
+ 0xb8b5, 0x06b0,
+ 0xb8ba, 0x1f0c,
+ 0xb8bb, 0x06b6,
+ 0xb8bc, 0x1f0d,
+ 0xb8bd, 0x06b8,
+ 0xb8be, 0x1f0e,
+ 0xb8c0, 0x06bb,
+ 0xb8c3, 0x1f10,
+ 0xb8c4, 0x06bf,
+ 0xb8c6, 0x1f11,
+ 0xb8c8, 0x06c3,
+ 0xb8c9, 0x1f13,
+ 0xb8ca, 0x06c5,
+ 0xb8cf, 0x1f14,
+ 0xb8d0, 0x06cb,
+ 0xb8d3, 0x1f15,
+ 0xb8d7, 0x06d2,
+ 0xb8d9, 0x1f19,
+ 0xb8db, 0x06d6,
+ 0xb8e4, 0x1f1b,
+ 0xb8e5, 0x06e0,
+ 0xb8e9, 0x1f1c,
+ 0xb8ea, 0x06e5,
+ 0xb8eb, 0x1f1d,
+ 0xb8ec, 0x06e7,
+ 0xb8f3, 0x1f1e,
+ 0xb8f4, 0x06ef,
+ 0xb8f5, 0x1f1f,
+ 0xb8f7, 0x06f2,
+ 0xb8f8, 0x1f21,
+ 0xb8f9, 0x06f4,
+ 0xb9a1, 0x06fa,
+ 0xb9a8, 0x1f22,
+ 0xb9a9, 0x0702,
+ 0xb9ae, 0x1f23,
+ 0xb9af, 0x0708,
+ 0xb9b1, 0x1f24,
+ 0xb9b2, 0x070b,
+ 0xb9b3, 0x1f25,
+ 0xb9b4, 0x070d,
+ 0xb9b5, 0x1f26,
+ 0xb9b6, 0x070f,
+ 0xb9b9, 0x1f27,
+ 0xb9bb, 0x0714,
+ 0xb9c6, 0x1f29,
+ 0xb9c7, 0x0720,
+ 0xb9cb, 0x1f2a,
+ 0xb9cc, 0x0725,
+ 0xb9d0, 0x1f2b,
+ 0xb9d1, 0x072a,
+ 0xb9d8, 0x1f2c,
+ 0xb9d9, 0x0732,
+ 0xb9db, 0x1f2d,
+ 0xb9dc, 0x0735,
+ 0xb9dd, 0x1f2e,
+ 0xb9de, 0x0737,
+ 0xb9df, 0x1f2f,
+ 0xb9e0, 0x0739,
+ 0xb9e1, 0x1f30,
+ 0xb9e2, 0x073b,
+ 0xb9e3, 0x1f31,
+ 0xb9e4, 0x073d,
+ 0xb9e6, 0x1f32,
+ 0xb9e7, 0x0740,
+ 0xb9e9, 0x1f33,
+ 0xb9ed, 0x0746,
+ 0xb9ee, 0x1f37,
+ 0xb9ef, 0x0748,
+ 0xb9f1, 0x1f38,
+ 0xb9f2, 0x074b,
+ 0xb9f3, 0x1f39,
+ 0xb9f6, 0x074f,
+ 0xb9f8, 0x1f3c,
+ 0xb9f9, 0x0752,
+ 0xb9fa, 0x1f3d,
+ 0xb9fb, 0x0754,
+ 0xb9fd, 0x1f3e,
+ 0xb9fe, 0x0757,
+ 0xbaa1, 0x0758,
+ 0xbaa7, 0x1f3f,
+ 0xbaa8, 0x075f,
+ 0xbaab, 0x1f40,
+ 0xbaac, 0x0763,
+ 0xbaba, 0x1f41,
+ 0xbabb, 0x0772,
+ 0xbac5, 0x1f42,
+ 0xbac6, 0x077d,
+ 0xbad2, 0x1f43,
+ 0xbad3, 0x078a,
+ 0xbad7, 0x1f44,
+ 0xbad9, 0x0790,
+ 0xbae4, 0x1f46,
+ 0xbae5, 0x079c,
+ 0xbae8, 0x1f47,
+ 0xbae9, 0x07a0,
+ 0xbaec, 0x1f48,
+ 0xbaed, 0x07a4,
+ 0xbaf3, 0x15e5,
+ 0xbaf4, 0x07ab,
+ 0xbaf8, 0x1f49,
+ 0xbaf9, 0x07b0,
+ 0xbba1, 0x07b6,
+ 0xbba4, 0x1f4a,
+ 0xbba5, 0x07ba,
+ 0xbba6, 0x1f4b,
+ 0xbba7, 0x07bc,
+ 0xbba9, 0x1f4c,
+ 0xbbab, 0x07c0,
+ 0xbbad, 0x1f4e,
+ 0xbbaf, 0x07c4,
+ 0xbbb0, 0x1f50,
+ 0xbbb1, 0x07c6,
+ 0xbbb3, 0x1f51,
+ 0xbbb4, 0x07c9,
+ 0xbbb5, 0x1f52,
+ 0xbbb8, 0x07cd,
+ 0xbbb9, 0x1f55,
+ 0xbbbb, 0x07d0,
+ 0xbbd1, 0x1f57,
+ 0xbbd2, 0x07e7,
+ 0xbbd3, 0x1f58,
+ 0xbbd5, 0x07ea,
+ 0xbbdf, 0x1f5a,
+ 0xbbe8, 0x07fd,
+ 0xbbeb, 0x1f63,
+ 0xbbec, 0x0801,
+ 0xbbf1, 0x1f64,
+ 0xbbf2, 0x0807,
+ 0xbbf5, 0x1f65,
+ 0xbbf8, 0x080d,
+ 0xbbfa, 0x1f68,
+ 0xbbfb, 0x0810,
+ 0xbbfd, 0x1f69,
+ 0xbbfe, 0x0813,
+ 0xbca1, 0x0814,
+ 0xbca2, 0x1f6a,
+ 0xbca3, 0x0816,
+ 0xbca5, 0x1f6b,
+ 0xbca7, 0x081a,
+ 0xbca8, 0x1f6d,
+ 0xbcaa, 0x081d,
+ 0xbcab, 0x1f6f,
+ 0xbcac, 0x081f,
+ 0xbcad, 0x1f70,
+ 0xbcae, 0x0821,
+ 0xbcb6, 0x1f71,
+ 0xbcb9, 0x082c,
+ 0xbcbb, 0x1f74,
+ 0xbcbc, 0x082f,
+ 0xbcc1, 0x1f75,
+ 0xbcc2, 0x0835,
+ 0xbcc3, 0x1f76,
+ 0xbcc4, 0x0837,
+ 0xbcc6, 0x1f77,
+ 0xbcc8, 0x083b,
+ 0xbcca, 0x1f79,
+ 0xbccb, 0x083e,
+ 0xbccc, 0x1f7a,
+ 0xbcce, 0x0841,
+ 0xbcd0, 0x1f7c,
+ 0xbcd1, 0x0844,
+ 0xbcd4, 0x1f7d,
+ 0xbcd7, 0x084a,
+ 0xbcd8, 0x1f80,
+ 0xbcd9, 0x084c,
+ 0xbcdb, 0x1f81,
+ 0xbcdc, 0x084f,
+ 0xbcdd, 0x1f82,
+ 0xbcde, 0x0851,
+ 0xbcdf, 0x1f83,
+ 0xbce2, 0x0855,
+ 0xbce3, 0x1f86,
+ 0xbce5, 0x0858,
+ 0xbce8, 0x1f88,
+ 0xbce9, 0x085c,
+ 0xbcea, 0x1f89,
+ 0xbced, 0x0860,
+ 0xbcef, 0x1f8c,
+ 0xbcf4, 0x0867,
+ 0xbcf6, 0x1f91,
+ 0xbcfd, 0x0870,
+ 0xbda1, 0x0872,
+ 0xbda2, 0x1f98,
+ 0xbda8, 0x0879,
+ 0xbdab, 0x1f9e,
+ 0xbdad, 0x087e,
+ 0xbdaf, 0x1fa0,
+ 0xbdb3, 0x0884,
+ 0xbdb4, 0x1fa4,
+ 0xbdb5, 0x0886,
+ 0xbdba, 0x1fa5,
+ 0xbdbb, 0x088c,
+ 0xbdbd, 0x1fa6,
+ 0xbdc0, 0x0891,
+ 0xbdc1, 0x1fa9,
+ 0xbdc5, 0x0896,
+ 0xbdc8, 0x1fad,
+ 0xbdcb, 0x089c,
+ 0xbdce, 0x1fb0,
+ 0xbdd0, 0x08a1,
+ 0xbdd7, 0x1fb2,
+ 0xbdd8, 0x08a9,
+ 0xbdda, 0x1fb3,
+ 0xbddb, 0x08ac,
+ 0xbde0, 0x1fb4,
+ 0xbde2, 0x08b3,
+ 0xbdeb, 0x1fb6,
+ 0xbdec, 0x08bd,
+ 0xbdf4, 0x1fb7,
+ 0xbdf9, 0x08ca,
+ 0xbdfd, 0x1fbc,
+ 0xbdfe, 0x08cf,
+ 0xbea1, 0x1fbd,
+ 0xbea3, 0x08d2,
+ 0xbea5, 0x1fbf,
+ 0xbea6, 0x08d5,
+ 0xbea8, 0x1fc0,
+ 0xbea9, 0x08d8,
+ 0xbeaa, 0x1fc1,
+ 0xbeab, 0x08da,
+ 0xbead, 0x1fc2,
+ 0xbeae, 0x08dd,
+ 0xbeb1, 0x1fc3,
+ 0xbeb2, 0x08e1,
+ 0xbeb5, 0x1fc4,
+ 0xbeb8, 0x08e7,
+ 0xbeba, 0x1fc7,
+ 0xbebb, 0x08ea,
+ 0xbec0, 0x1fc8,
+ 0xbec1, 0x08f0,
+ 0xbec9, 0x1fc9,
+ 0xbeca, 0x08f9,
+ 0xbed4, 0x1fca,
+ 0xbed5, 0x0904,
+ 0xbed9, 0x1fcb,
+ 0xbeda, 0x0909,
+ 0xbedd, 0x1fcc,
+ 0xbede, 0x090d,
+ 0xbee2, 0x1fcd,
+ 0xbee3, 0x0912,
+ 0xbee5, 0x1fce,
+ 0xbee6, 0x0915,
+ 0xbee7, 0x1fcf,
+ 0xbee8, 0x0917,
+ 0xbee9, 0x1fd0,
+ 0xbeea, 0x0919,
+ 0xbeee, 0x1fd1,
+ 0xbeef, 0x091e,
+ 0xbef5, 0x1fd2,
+ 0xbef6, 0x0925,
+ 0xbef7, 0x1fd3,
+ 0xbef9, 0x0928,
+ 0xbefb, 0x1fd5,
+ 0xbefd, 0x092c,
+ 0xbfa1, 0x092e,
+ 0xbfa5, 0x1fd7,
+ 0xbfa6, 0x0933,
+ 0xbfaa, 0x1fd8,
+ 0xbfab, 0x0938,
+ 0xbfad, 0x1fd9,
+ 0xbfae, 0x093b,
+ 0xbfc5, 0x1fda,
+ 0xbfc6, 0x0953,
+ 0xbfc7, 0x1fdb,
+ 0xbfc8, 0x0955,
+ 0xbfce, 0x1fdc,
+ 0xbfcf, 0x095c,
+ 0xbfd1, 0x1fdd,
+ 0xbfd3, 0x0960,
+ 0xbfd9, 0x1fdf,
+ 0xbfda, 0x0967,
+ 0xbfe2, 0x1fe0,
+ 0xbfe5, 0x0972,
+ 0xbfe9, 0x1fe3,
+ 0xbfea, 0x0977,
+ 0xbfeb, 0x1fe4,
+ 0xbfec, 0x0979,
+ 0xbfed, 0x1fe5,
+ 0xbfee, 0x097b,
+ 0xbff3, 0x1fe6,
+ 0xbff4, 0x0981,
+ 0xbff5, 0x1fe7,
+ 0xbff6, 0x0983,
+ 0xbff7, 0x1fe8,
+ 0xbff8, 0x0985,
+ 0xbff9, 0x1fe9,
+ 0xbffb, 0x0988,
+ 0xc0a1, 0x1feb,
+ 0xc0a2, 0x098d,
+ 0xc0a3, 0x1fec,
+ 0xc0a4, 0x098f,
+ 0xc0a9, 0x1fed,
+ 0xc0aa, 0x0995,
+ 0xc0ab, 0x1fee,
+ 0xc0ac, 0x0997,
+ 0xc0af, 0x1fef,
+ 0xc0b1, 0x099c,
+ 0xc0b3, 0x1ff1,
+ 0xc0b7, 0x09a2,
+ 0xc0b8, 0x1ff5,
+ 0xc0c5, 0x09b0,
+ 0xc0cc, 0x2002,
+ 0xc0ce, 0x09b9,
+ 0xc0d4, 0x2004,
+ 0xc0d5, 0x09c0,
+ 0xc0d6, 0x2005,
+ 0xc0d7, 0x09c2,
+ 0xc0d8, 0x2006,
+ 0xc0d9, 0x09c4,
+ 0xc0dd, 0x2007,
+ 0xc0de, 0x09c9,
+ 0xc0e0, 0x2008,
+ 0xc0e1, 0x09cc,
+ 0xc0e9, 0x2009,
+ 0xc0ea, 0x09d5,
+ 0xc0eb, 0x200a,
+ 0xc0ed, 0x09d8,
+ 0xc0ef, 0x200c,
+ 0xc0f2, 0x09dd,
+ 0xc0f6, 0x200f,
+ 0xc0fb, 0x09e6,
+ 0xc1a1, 0x09ea,
+ 0xc1a4, 0x2014,
+ 0xc1a6, 0x09ef,
+ 0xc1a9, 0x2016,
+ 0xc1ae, 0x09f7,
+ 0xc1af, 0x201b,
+ 0xc1b9, 0x0a02,
+ 0xc1bd, 0x2025,
+ 0xc1bf, 0x0a08,
+ 0xc1c2, 0x2027,
+ 0xc1c3, 0x0a0c,
+ 0xc1c6, 0x2028,
+ 0xc1c7, 0x0a10,
+ 0xc1c9, 0x2029,
+ 0xc1ca, 0x0a13,
+ 0xc1cd, 0x202a,
+ 0xc1ce, 0x0a17,
+ 0xc1d4, 0x202b,
+ 0xc1d5, 0x0a1e,
+ 0xc1d9, 0x202c,
+ 0xc1dc, 0x0a25,
+ 0xc1de, 0x202f,
+ 0xc1df, 0x0a28,
+ 0xc1e4, 0x2030,
+ 0xc1e6, 0x0a2f,
+ 0xc1e9, 0x2032,
+ 0xc1ea, 0x0a33,
+ 0xc1eb, 0x2033,
+ 0xc1ed, 0x0a36,
+ 0xc1f3, 0x2035,
+ 0xc1f4, 0x0a3d,
+ 0xc1f5, 0x2036,
+ 0xc1f6, 0x0a3f,
+ 0xc1fa, 0x2037,
+ 0xc1fe, 0x0a47,
+ 0xc2a1, 0x0a48,
+ 0xc2a2, 0x203b,
+ 0xc2a9, 0x0a50,
+ 0xc2ab, 0x2042,
+ 0xc2b4, 0x0a5b,
+ 0xc2b8, 0x204b,
+ 0xc2b9, 0x0a60,
+ 0xc2bc, 0x204c,
+ 0xc2be, 0x0a65,
+ 0xc2bf, 0x204e,
+ 0xc2c0, 0x0a67,
+ 0xc2c1, 0x204f,
+ 0xc2c2, 0x0a69,
+ 0xc2c5, 0x2050,
+ 0xc2c8, 0x0a6f,
+ 0xc2cb, 0x2053,
+ 0xc2d1, 0x0a78,
+ 0xc2d2, 0x2059,
+ 0xc2d3, 0x0a7a,
+ 0xc2d5, 0x205a,
+ 0xc2dd, 0x0a84,
+ 0xc2de, 0x2062,
+ 0xc2e3, 0x0a8a,
+ 0xc2e6, 0x2067,
+ 0xc2e9, 0x0a90,
+ 0xc2ea, 0x206a,
+ 0xc2ef, 0x0a96,
+ 0xc2f0, 0x206f,
+ 0xc2f1, 0x0a98,
+ 0xc2f2, 0x2070,
+ 0xc2f6, 0x0a9d,
+ 0xc2f7, 0x2074,
+ 0xc2fb, 0x0aa2,
+ 0xc3a1, 0x2078,
+ 0xc3a2, 0x0aa7,
+ 0xc3aa, 0x2079,
+ 0xc3ab, 0x0ab0,
+ 0xc3ad, 0x207a,
+ 0xc3ae, 0x0ab3,
+ 0xc3b3, 0x207b,
+ 0xc3b4, 0x1df9,
+ 0xc3b5, 0x0aba,
+ 0xc3be, 0x207c,
+ 0xc3bf, 0x0ac4,
+ 0xc3c5, 0x207d,
+ 0xc3c8, 0x0acd,
+ 0xc3cc, 0x2080,
+ 0xc3cd, 0x0ad2,
+ 0xc3ce, 0x2081,
+ 0xc3cf, 0x0ad4,
+ 0xc3d5, 0x2082,
+ 0xc3d7, 0x0adc,
+ 0xc3d9, 0x2084,
+ 0xc3da, 0x0adf,
+ 0xc3e0, 0x2085,
+ 0xc3e1, 0x0ae6,
+ 0xc3e5, 0x2086,
+ 0xc3e6, 0x0aeb,
+ 0xc3ed, 0x2087,
+ 0xc3ee, 0x0af3,
+ 0xc3f0, 0x2088,
+ 0xc3f1, 0x0af6,
+ 0xc3f5, 0x2089,
+ 0xc3f7, 0x0afc,
+ 0xc3f9, 0x208b,
+ 0xc3fb, 0x0b00,
+ 0xc3fd, 0x208d,
+ 0xc3fe, 0x0b03,
+ 0xc4a1, 0x0b04,
+ 0xc4b1, 0x208e,
+ 0xc4b2, 0x0b15,
+ 0xc4b6, 0x208f,
+ 0xc4b7, 0x0b1a,
+ 0xc4c6, 0x2090,
+ 0xc4c7, 0x0b2a,
+ 0xc4c9, 0x2091,
+ 0xc4ca, 0x0b2d,
+ 0xc4d1, 0x2092,
+ 0xc4d2, 0x0b35,
+ 0xc4d3, 0x2093,
+ 0xc4d7, 0x0b3a,
+ 0xc4d9, 0x2097,
+ 0xc4da, 0x0b3d,
+ 0xc4e2, 0x2098,
+ 0xc4e3, 0x0b46,
+ 0xc4e5, 0x2099,
+ 0xc4e6, 0x0b49,
+ 0xc4ec, 0x209a,
+ 0xc4ed, 0x0b50,
+ 0xc4f0, 0x209b,
+ 0xc4f2, 0x0b55,
+ 0xc4f4, 0x209d,
+ 0xc4f5, 0x0b58,
+ 0xc4f6, 0x209e,
+ 0xc4f9, 0x0b5c,
+ 0xc4fb, 0x20a1,
+ 0xc4fd, 0x0b60,
+ 0xc4fe, 0x20a3,
+ 0xc5a1, 0x20a4,
+ 0xc5a3, 0x0b64,
+ 0xc5a5, 0x20a6,
+ 0xc5aa, 0x0b6b,
+ 0xc5b1, 0x20ab,
+ 0xc5b2, 0x0b73,
+ 0xc5b5, 0x20ac,
+ 0xc5b6, 0x0b77,
+ 0xc5b7, 0x20ad,
+ 0xc5ba, 0x0b7b,
+ 0xc5bb, 0x20b0,
+ 0xc5bc, 0x0b7d,
+ 0xc5bd, 0x20b1,
+ 0xc5be, 0x0b7f,
+ 0xc5cc, 0x20b2,
+ 0xc5cd, 0x0b8e,
+ 0xc5d3, 0x20b3,
+ 0xc5d4, 0x0b95,
+ 0xc5e2, 0x20b4,
+ 0xc5e3, 0x0ba4,
+ 0xc5e7, 0x20b5,
+ 0xc5e8, 0x0ba9,
+ 0xc5f4, 0x20b6,
+ 0xc5f5, 0x0bb6,
+ 0xc6a1, 0x0bc0,
+ 0xc6ad, 0x20b7,
+ 0xc6af, 0x0bce,
+ 0xc6b5, 0x20b9,
+ 0xc6b7, 0x0bd6,
+ 0xc6bb, 0x20bb,
+ 0xc6bc, 0x0bdb,
+ 0xc6be, 0x20bc,
+ 0xc6bf, 0x0bde,
+ 0xc6c0, 0x20bd,
+ 0xc6c1, 0x0be0,
+ 0xc6c3, 0x20be,
+ 0xc6c5, 0x0be4,
+ 0xc6cb, 0x20c0,
+ 0xc6ce, 0x0bed,
+ 0xc6d3, 0x20c3,
+ 0xc6d4, 0x0bf3,
+ 0xc6d7, 0x20c4,
+ 0xc6d8, 0x0bf7,
+ 0xc6ea, 0x20c5,
+ 0xc6ec, 0x0c0b,
+ 0xc6ef, 0x20c7,
+ 0xc6f0, 0x0c0f,
+ 0xc6f1, 0x20c8,
+ 0xc6f2, 0x0c11,
+ 0xc6f4, 0x20c9,
+ 0xc6f5, 0x0c14,
+ 0xc6f8, 0x20ca,
+ 0xc6f9, 0x0c18,
+ 0xc6fd, 0x20cb,
+ 0xc6fe, 0x0c1d,
+ 0xc7a1, 0x0c1e,
+ 0xc7a3, 0x20cc,
+ 0xc7a4, 0x0c21,
+ 0xc7a5, 0x20cd,
+ 0xc7a7, 0x0c24,
+ 0xc7a8, 0x20cf,
+ 0xc7aa, 0x0c27,
+ 0xc7ab, 0x20d1,
+ 0xc7ac, 0x0c29,
+ 0xc7ae, 0x20d2,
+ 0xc7b0, 0x0c2d,
+ 0xc7b3, 0x20d4,
+ 0xc7b6, 0x0c33,
+ 0xc7b9, 0x20d7,
+ 0xc7bb, 0x0c38,
+ 0xc7bd, 0x20d9,
+ 0xc7bf, 0x0c3c,
+ 0xc7c0, 0x20db,
+ 0xc7c1, 0x0c3e,
+ 0xc7c2, 0x20dc,
+ 0xc7c3, 0x0c40,
+ 0xc7c5, 0x20dd,
+ 0xc7c6, 0x0c43,
+ 0xc7c7, 0x20de,
+ 0xc7c9, 0x0c46,
+ 0xc7cc, 0x20e0,
+ 0xc7cd, 0x0c4a,
+ 0xc7cf, 0x20e1,
+ 0xc7d0, 0x0c4d,
+ 0xc7d4, 0x20e2,
+ 0xc7d6, 0x0c53,
+ 0xc7d7, 0x20e4,
+ 0xc7d8, 0x0c55,
+ 0xc7de, 0x20e5,
+ 0xc7df, 0x0c5c,
+ 0xc7e1, 0x20e6,
+ 0xc7e4, 0x0c61,
+ 0xc7ea, 0x20e9,
+ 0xc7ef, 0x0c6c,
+ 0xc7f7, 0x20ee,
+ 0xc7f9, 0x0c76,
+ 0xc7fb, 0x20f0,
+ 0xc7fc, 0x0c79,
+ 0xc7fd, 0x20f1,
+ 0xc7fe, 0x0c7b,
+ 0xc8a1, 0x0c7c,
+ 0xc8a3, 0x20f2,
+ 0xc8a4, 0x0c7f,
+ 0xc8a7, 0x20f3,
+ 0xc8a9, 0x0c84,
+ 0xc8b0, 0x20f5,
+ 0xc8b1, 0x0c8c,
+ 0xc8b5, 0x20f6,
+ 0xc8b6, 0x0c91,
+ 0xc8b7, 0x20f7,
+ 0xc8b8, 0x0c93,
+ 0xc8c3, 0x20f8,
+ 0xc8c7, 0x0ca2,
+ 0xc8c8, 0x20fc,
+ 0xc8c9, 0x0ca4,
+ 0xc8cd, 0x20fd,
+ 0xc8ce, 0x0ca9,
+ 0xc8cf, 0x20fe,
+ 0xc8d0, 0x0cab,
+ 0xc8d2, 0x20ff,
+ 0xc8d3, 0x0cae,
+ 0xc8d9, 0x2100,
+ 0xc8da, 0x0cb5,
+ 0xc8de, 0x2101,
+ 0xc8df, 0x0cba,
+ 0xc8ed, 0x2102,
+ 0xc8ee, 0x0cc9,
+ 0xc8f1, 0x2103,
+ 0xc8f4, 0x0ccf,
+ 0xc8f7, 0x2106,
+ 0xc8f9, 0x0cd4,
+ 0xc8fa, 0x2108,
+ 0xc8fb, 0x0cd6,
+ 0xc8fc, 0x2109,
+ 0xc8fd, 0x0cd8,
+ 0xc9a1, 0x210a,
+ 0xc9a2, 0x0cdb,
+ 0xc9a5, 0x210b,
+ 0xc9a6, 0x0cdf,
+ 0xc9a7, 0x210c,
+ 0xc9a9, 0x0ce2,
+ 0xc9ac, 0x210e,
+ 0xc9ad, 0x0ce6,
+ 0xc9b1, 0x210f,
+ 0xc9b2, 0x0ceb,
+ 0xc9b4, 0x2110,
+ 0xc9b5, 0x0cee,
+ 0xc9b8, 0x2111,
+ 0xc9ba, 0x0cf3,
+ 0xc9c1, 0x2113,
+ 0xc9c3, 0x0cfc,
+ 0xc9c4, 0x2115,
+ 0xc9c5, 0x0cfe,
+ 0xc9c9, 0x2116,
+ 0xc9ca, 0x0d03,
+ 0xc9cb, 0x2117,
+ 0xc9cc, 0x0d05,
+ 0xc9cd, 0x2118,
+ 0xc9ce, 0x0d07,
+ 0xc9d5, 0x2119,
+ 0xc9d6, 0x0d0f,
+ 0xc9dc, 0x211a,
+ 0xc9dd, 0x0d16,
+ 0xc9de, 0x211b,
+ 0xc9df, 0x0d18,
+ 0xc9e1, 0x211c,
+ 0xc9e2, 0x0d1b,
+ 0xc9e3, 0x211d,
+ 0xc9e4, 0x0d1d,
+ 0xc9e5, 0x211e,
+ 0xc9e6, 0x0d1f,
+ 0xc9e8, 0x211f,
+ 0xc9e9, 0x0d22,
+ 0xc9f0, 0x2120,
+ 0xc9f1, 0x0d2a,
+ 0xc9f3, 0x2121,
+ 0xc9f5, 0x0d2e,
+ 0xc9f6, 0x2123,
+ 0xc9f7, 0x0d30,
+ 0xc9f8, 0x2124,
+ 0xc9fa, 0x0d33,
+ 0xc9fe, 0x2126,
+ 0xcaa1, 0x0d38,
+ 0xcaa4, 0x2127,
+ 0xcaa7, 0x0d3e,
+ 0xcaa8, 0x212a,
+ 0xcaa9, 0x0d40,
+ 0xcaaa, 0x212b,
+ 0xcaac, 0x0d43,
+ 0xcab1, 0x212d,
+ 0xcab2, 0x0d49,
+ 0xcab4, 0x212e,
+ 0xcab7, 0x0d4e,
+ 0xcabb, 0x2131,
+ 0xcabc, 0x0d53,
+ 0xcac6, 0x2132,
+ 0xcac7, 0x0d5e,
+ 0xcaca, 0x2133,
+ 0xcacb, 0x0d62,
+ 0xcacd, 0x2134,
+ 0xcacf, 0x0d66,
+ 0xcad3, 0x2136,
+ 0xcad5, 0x0d6c,
+ 0xcad9, 0x2138,
+ 0xcada, 0x0d71,
+ 0xcade, 0x2139,
+ 0xcadf, 0x0d76,
+ 0xcae0, 0x213a,
+ 0xcae1, 0x0d78,
+ 0xcae4, 0x213b,
+ 0xcae5, 0x0d7c,
+ 0xcae9, 0x213c,
+ 0xcaeb, 0x0d82,
+ 0xcaf4, 0x213e,
+ 0xcaf6, 0x0d8d,
+ 0xcaf7, 0x2140,
+ 0xcaf8, 0x0d8f,
+ 0xcafa, 0x2141,
+ 0xcafb, 0x0d92,
+ 0xcafd, 0x2142,
+ 0xcafe, 0x0d95,
+ 0xcba1, 0x0d96,
+ 0xcba7, 0x2143,
+ 0xcba8, 0x0d9d,
+ 0xcbab, 0x2144,
+ 0xcbac, 0x0da1,
+ 0xcbad, 0x2145,
+ 0xcbae, 0x0da3,
+ 0xcbb3, 0x2146,
+ 0xcbb4, 0x0da9,
+ 0xcbb5, 0x2147,
+ 0xcbb7, 0x0dac,
+ 0xcbb8, 0x2149,
+ 0xcbb9, 0x0dae,
+ 0xcbbf, 0x214a,
+ 0xcbc0, 0x0db5,
+ 0xcbc7, 0x214b,
+ 0xcbc8, 0x0dbd,
+ 0xcbc9, 0x214c,
+ 0xcbcd, 0x0dc2,
+ 0xcbcf, 0x2150,
+ 0xcbd1, 0x0dc6,
+ 0xcbd3, 0x2152,
+ 0xcbd4, 0x0dc9,
+ 0xcbd5, 0x2153,
+ 0xcbd6, 0x0dcb,
+ 0xcbdf, 0x2154,
+ 0xcbe1, 0x0dd6,
+ 0xcbe4, 0x2156,
+ 0xcbe5, 0x0dda,
+ 0xcbe6, 0x2157,
+ 0xcbe8, 0x0ddd,
+ 0xcbea, 0x2159,
+ 0xcbeb, 0x0de0,
+ 0xcbef, 0x215a,
+ 0xcbf1, 0x0de6,
+ 0xcbf5, 0x215c,
+ 0xcbf7, 0x0dec,
+ 0xcbf8, 0x215e,
+ 0xcbf9, 0x0dee,
+ 0xcca1, 0x215f,
+ 0xcca3, 0x0df6,
+ 0xcca8, 0x2161,
+ 0xcca9, 0x0dfc,
+ 0xccac, 0x2162,
+ 0xccad, 0x0e00,
+ 0xccaf, 0x2163,
+ 0xccb4, 0x0e07,
+ 0xccb7, 0x2168,
+ 0xccb9, 0x0e0c,
+ 0xccbe, 0x216a,
+ 0xccbf, 0x0e12,
+ 0xccc0, 0x216b,
+ 0xccc1, 0x0e14,
+ 0xcccc, 0x216c,
+ 0xcccd, 0x0e20,
+ 0xccce, 0x216d,
+ 0xcccf, 0x0e22,
+ 0xccd0, 0x216e,
+ 0xccd1, 0x0e24,
+ 0xccd6, 0x216f,
+ 0xccd7, 0x0e2a,
+ 0xccda, 0x2170,
+ 0xccdb, 0x0e2e,
+ 0xccdc, 0x2171,
+ 0xccdd, 0x0e30,
+ 0xcce0, 0x2172,
+ 0xcce1, 0x0e34,
+ 0xcce2, 0x2173,
+ 0xcce3, 0x0e36,
+ 0xcce5, 0x2174,
+ 0xcce6, 0x0e39,
+ 0xccf5, 0x2175,
+ 0xccf6, 0x0e49,
+ 0xccf9, 0x2176,
+ 0xccfb, 0x0e4e,
+ 0xccfc, 0x2178,
+ 0xcda1, 0x0e52,
+ 0xcdad, 0x217b,
+ 0xcdae, 0x0e5f,
+ 0xcdb3, 0x217c,
+ 0xcdb4, 0x0e65,
+ 0xcdb7, 0x217d,
+ 0xcdb8, 0x0e69,
+ 0xcdbc, 0x217e,
+ 0xcdbd, 0x0e6e,
+ 0xcdbf, 0x217f,
+ 0xcdc0, 0x0e71,
+ 0xcdc5, 0x2180,
+ 0xcdc6, 0x0e77,
+ 0xcdc7, 0x2181,
+ 0xcdc8, 0x0e79,
+ 0xcdd2, 0x2182,
+ 0xcdd3, 0x0e84,
+ 0xcdd4, 0x2183,
+ 0xcdd7, 0x0e88,
+ 0xcddd, 0x2186,
+ 0xcdde, 0x0e8f,
+ 0xcde0, 0x2187,
+ 0xcde1, 0x0e92,
+ 0xcde4, 0x2188,
+ 0xcde6, 0x0e97,
+ 0xcde7, 0x218a,
+ 0xcde8, 0x0e99,
+ 0xcdf2, 0x218b,
+ 0xcdf3, 0x0ea4,
+ 0xcdf8, 0x218c,
+ 0xcdf9, 0x0eaa,
+ 0xcea1, 0x0eb0,
+ 0xcea4, 0x218d,
+ 0xcea6, 0x0eb5,
+ 0xcea7, 0x218f,
+ 0xcea8, 0x0eb7,
+ 0xceaa, 0x2190,
+ 0xceae, 0x0ebd,
+ 0xceb0, 0x2194,
+ 0xceb2, 0x0ec1,
+ 0xceb3, 0x2196,
+ 0xceb4, 0x0ec3,
+ 0xcebd, 0x2197,
+ 0xcebe, 0x0ecd,
+ 0xcec0, 0x2198,
+ 0xcec1, 0x0ed0,
+ 0xcec5, 0x2199,
+ 0xcec7, 0x0ed6,
+ 0xcec8, 0x219b,
+ 0xcec9, 0x0ed8,
+ 0xceca, 0x219c,
+ 0xcecb, 0x0eda,
+ 0xcece, 0x219d,
+ 0xced2, 0x0ee1,
+ 0xced8, 0x21a1,
+ 0xcedb, 0x0eea,
+ 0xcedc, 0x21a4,
+ 0xcedd, 0x0eec,
+ 0xcede, 0x21a5,
+ 0xcee0, 0x0eef,
+ 0xceeb, 0x21a7,
+ 0xceec, 0x0efb,
+ 0xceed, 0x21a8,
+ 0xceee, 0x0efd,
+ 0xcef1, 0x21a9,
+ 0xcef2, 0x0f01,
+ 0xcef3, 0x21aa,
+ 0xcef4, 0x0f03,
+ 0xcefd, 0x21ab,
+ 0xcfa1, 0x0f0e,
+ 0xcfae, 0x21ad,
+ 0xcfaf, 0x0f1c,
+ 0xcfb0, 0x21ae,
+ 0xcfb1, 0x0f1e,
+ 0xcfb3, 0x21af,
+ 0xcfb4, 0x0f21,
+ 0xcfb7, 0x21b0,
+ 0xcfb9, 0x0f26,
+ 0xcfba, 0x21b2,
+ 0xcfbb, 0x0f28,
+ 0xcfbd, 0x21b3,
+ 0xcfbe, 0x0f2b,
+ 0xcfbf, 0x21b4,
+ 0xcfc2, 0x0f2f,
+ 0xcfc5, 0x21b7,
+ 0xcfc6, 0x0f33,
+ 0xcfc7, 0x21b8,
+ 0xcfc8, 0x0f35,
+ 0xcfca, 0x21b9,
+ 0xcfcc, 0x0f39,
+ 0xcfcd, 0x21bb,
+ 0xcfcf, 0x0f3c,
+ 0xcfd0, 0x21bd,
+ 0xcfd1, 0x0f3e,
+ 0xcfd4, 0x21be,
+ 0xcfd9, 0x0f46,
+ 0xcfda, 0x21c3,
+ 0xcfdb, 0x0f48,
+ 0xcfdc, 0x21c4,
+ 0xcfdd, 0x0f4a,
+ 0xcfdf, 0x21c5,
+ 0xcfe0, 0x0f4d,
+ 0xcfe2, 0x21c6,
+ 0xcfe3, 0x0f50,
+ 0xcfe7, 0x21c7,
+ 0xcfe8, 0x0f55,
+ 0xcfea, 0x21c8,
+ 0xcfeb, 0x0f58,
+ 0xcfec, 0x21c9,
+ 0xcfed, 0x0f5a,
+ 0xcfee, 0x21ca,
+ 0xcfef, 0x0f5c,
+ 0xcff4, 0x21cb,
+ 0xcff5, 0x0f62,
+ 0xcff9, 0x21cc,
+ 0xcffb, 0x0f68,
+ 0xcffe, 0x21ce,
+ 0xd0a1, 0x0f6c,
+ 0xd0a5, 0x21cf,
+ 0xd0a6, 0x0f71,
+ 0xd0ad, 0x21d0,
+ 0xd0af, 0x0f7a,
+ 0xd0b2, 0x21d2,
+ 0xd0b5, 0x0f80,
+ 0xd0ba, 0x21d5,
+ 0xd0bc, 0x0f87,
+ 0xd0bf, 0x21d7,
+ 0xd0c0, 0x0f8b,
+ 0xd0c6, 0x21d8,
+ 0xd0c7, 0x0f92,
+ 0xd0cb, 0x21d9,
+ 0xd0cc, 0x0f97,
+ 0xd0e2, 0x21da,
+ 0xd0e3, 0x0fae,
+ 0xd0e5, 0x21db,
+ 0xd0e6, 0x0fb1,
+ 0xd0eb, 0x21dc,
+ 0xd0ec, 0x0fb7,
+ 0xd0ed, 0x21dd,
+ 0xd0ee, 0x0fb9,
+ 0xd0f7, 0x21de,
+ 0xd0fa, 0x0fc5,
+ 0xd0fc, 0x21e1,
+ 0xd0fd, 0x0fc8,
+ 0xd1a1, 0x21e2,
+ 0xd1a3, 0x0fcc,
+ 0xd1a4, 0x21e4,
+ 0xd1a5, 0x0fce,
+ 0xd1a7, 0x21e5,
+ 0xd1a8, 0x0fd1,
+ 0xd1ab, 0x21e6,
+ 0xd1ac, 0x0fd5,
+ 0xd1af, 0x21e7,
+ 0xd1b2, 0x0fdb,
+ 0xd1b5, 0x21ea,
+ 0xd1b8, 0x0fe1,
+ 0xd1b9, 0x21ed,
+ 0xd1ba, 0x0fe3,
+ 0xd1bb, 0x21ee,
+ 0xd1bd, 0x0fe6,
+ 0xd1c6, 0x21f0,
+ 0xd1c9, 0x0ff2,
+ 0xd1cb, 0x21f3,
+ 0xd1cc, 0x0ff5,
+ 0xd1ce, 0x21f4,
+ 0xd1d0, 0x0ff9,
+ 0xd1d5, 0x21f6,
+ 0xd1d7, 0x1000,
+ 0xd1de, 0x21f8,
+ 0xd1df, 0x1008,
+ 0xd1e1, 0x21f9,
+ 0xd1e3, 0x100c,
+ 0xd1e8, 0x21fb,
+ 0xd1ea, 0x1013,
+ 0xd1ec, 0x21fd,
+ 0xd1ed, 0x1016,
+ 0xd1ee, 0x21fe,
+ 0xd1f0, 0x1019,
+ 0xd1f1, 0x2200,
+ 0xd1f2, 0x101b,
+ 0xd1f4, 0x2201,
+ 0xd1f5, 0x101e,
+ 0xd1f7, 0x2202,
+ 0xd1fa, 0x1023,
+ 0xd2a1, 0x1028,
+ 0xd2a2, 0x2205,
+ 0xd2a3, 0x102a,
+ 0xd2a5, 0x2206,
+ 0xd2a6, 0x102d,
+ 0xd2a9, 0x2207,
+ 0xd2aa, 0x1031,
+ 0xd2af, 0x2208,
+ 0xd2b0, 0x1037,
+ 0xd2b3, 0x2209,
+ 0xd2b4, 0x103b,
+ 0xd2b5, 0x220a,
+ 0xd2b7, 0x103e,
+ 0xd2bd, 0x220c,
+ 0xd2be, 0x1045,
+ 0xd2bf, 0x220d,
+ 0xd2c0, 0x1047,
+ 0xd2c3, 0x220e,
+ 0xd2c4, 0x104b,
+ 0xd2c5, 0x220f,
+ 0xd2c6, 0x104d,
+ 0xd2c7, 0x2210,
+ 0xd2c8, 0x104f,
+ 0xd2cf, 0x2211,
+ 0xd2d0, 0x1057,
+ 0xd2d5, 0x2212,
+ 0xd2d6, 0x105d,
+ 0xd2da, 0x2213,
+ 0xd2db, 0x1062,
+ 0xd2e4, 0x2214,
+ 0xd2e6, 0x106d,
+ 0xd2e8, 0x2216,
+ 0xd2ec, 0x1073,
+ 0xd2ef, 0x221a,
+ 0xd2f0, 0x1077,
+ 0xd2f1, 0x221b,
+ 0xd2f2, 0x1079,
+ 0xd2f5, 0x221c,
+ 0xd2f6, 0x107d,
+ 0xd2f8, 0x221d,
+ 0xd2f9, 0x1080,
+ 0xd2fb, 0x221e,
+ 0xd2fc, 0x1083,
+ 0xd2fe, 0x221f,
+ 0xd3a1, 0x1086,
+ 0xd3a3, 0x2220,
+ 0xd3ad, 0x1092,
+ 0xd3ae, 0x222a,
+ 0xd3af, 0x1094,
+ 0xd3b1, 0x222b,
+ 0xd3b2, 0x1097,
+ 0xd3b4, 0x222c,
+ 0xd3b7, 0x109c,
+ 0xd3b8, 0x222f,
+ 0xd3b9, 0x109e,
+ 0xd3bb, 0x2230,
+ 0xd3bc, 0x10a1,
+ 0xd3c5, 0x2231,
+ 0xd3c6, 0x10ab,
+ 0xd3c7, 0x2232,
+ 0xd3c8, 0x10ad,
+ 0xd3ca, 0x2233,
+ 0xd3cd, 0x10b2,
+ 0xd3d5, 0x2236,
+ 0xd3d6, 0x10bb,
+ 0xd3df, 0x2237,
+ 0xd3e1, 0x10c6,
+ 0xd3e3, 0x2239,
+ 0xd3e4, 0x10c9,
+ 0xd3e6, 0x223a,
+ 0xd3e7, 0x10cc,
+ 0xd3eb, 0x223b,
+ 0xd3ed, 0x10d2,
+ 0xd3ef, 0x223d,
+ 0xd3f0, 0x10d5,
+ 0xd3f4, 0x223e,
+ 0xd3f5, 0x10da,
+ 0xd3fc, 0x223f,
+ 0xd3fd, 0x10e2,
+ 0xd3fe, 0x2240,
+ 0xd4a1, 0x10e4,
+ 0xd4a4, 0x2241,
+ 0xd4a5, 0x10e8,
+ 0xd4a6, 0x2242,
+ 0xd4a9, 0x10ec,
+ 0xd4af, 0x2245,
+ 0xd4b3, 0x10f6,
+ 0xd4b5, 0x2249,
+ 0xd4b7, 0x10fa,
+ 0xd4b8, 0x224b,
+ 0xd4b9, 0x10fc,
+ 0xd4bc, 0x224c,
+ 0xd4bd, 0x1100,
+ 0xd4be, 0x224d,
+ 0xd4c0, 0x1103,
+ 0xd4c4, 0x224f,
+ 0xd4c5, 0x1108,
+ 0xd4c6, 0x2250,
+ 0xd4c8, 0x110b,
+ 0xd4c9, 0x2252,
+ 0xd4ca, 0x110d,
+ 0xd4cb, 0x2253,
+ 0xd4cf, 0x1112,
+ 0xd4d3, 0x2257,
+ 0xd4d4, 0x1117,
+ 0xd4d8, 0x2258,
+ 0xd4d9, 0x111c,
+ 0xd4dc, 0x2259,
+ 0xd4e1, 0x1124,
+ 0xd4e4, 0x225e,
+ 0xd4e5, 0x1128,
+ 0xd4e6, 0x225f,
+ 0xd4e7, 0x112a,
+ 0xd4ee, 0x2260,
+ 0xd4ef, 0x1132,
+ 0xd4f0, 0x2261,
+ 0xd4f5, 0x1138,
+ 0xd4f9, 0x2266,
+ 0xd4fa, 0x113d,
+ 0xd4fe, 0x2267,
+ 0xd5a1, 0x2268,
+ 0xd5a3, 0x1144,
+ 0xd5a9, 0x226a,
+ 0xd5aa, 0x114b,
+ 0xd5ab, 0x226b,
+ 0xd5ac, 0x114d,
+ 0xd5ae, 0x226c,
+ 0xd5af, 0x1150,
+ 0xd5b1, 0x226d,
+ 0xd5b2, 0x1153,
+ 0xd5b5, 0x226e,
+ 0xd5b9, 0x115a,
+ 0xd5bb, 0x2272,
+ 0xd5bc, 0x115d,
+ 0xd5bd, 0x2273,
+ 0xd5be, 0x115f,
+ 0xd5c0, 0x2274,
+ 0xd5c1, 0x1162,
+ 0xd5c5, 0x2275,
+ 0xd5c6, 0x1167,
+ 0xd5c7, 0x2276,
+ 0xd5c8, 0x1169,
+ 0xd5ca, 0x2277,
+ 0xd5cc, 0x116d,
+ 0xd5cd, 0x2279,
+ 0xd5ce, 0x116f,
+ 0xd5d4, 0x227a,
+ 0xd5d5, 0x1176,
+ 0xd5dd, 0x227b,
+ 0xd5df, 0x1180,
+ 0xd5e0, 0x227d,
+ 0xd5e1, 0x1182,
+ 0xd5e2, 0x227e,
+ 0xd5e3, 0x1184,
+ 0xd5ea, 0x227f,
+ 0xd5ed, 0x118e,
+ 0xd5ef, 0x2282,
+ 0xd5f0, 0x1191,
+ 0xd5f2, 0x2283,
+ 0xd5f4, 0x1195,
+ 0xd5f7, 0x15eb,
+ 0xd5f8, 0x1199,
+ 0xd6a1, 0x2285,
+ 0xd6a5, 0x11a4,
+ 0xd6af, 0x2289,
+ 0xd6b1, 0x11b0,
+ 0xd6b4, 0x228b,
+ 0xd6b5, 0x11b4,
+ 0xd6bb, 0x228c,
+ 0xd6bc, 0x11bb,
+ 0xd6bd, 0x228d,
+ 0xd6be, 0x11bd,
+ 0xd6bf, 0x228e,
+ 0xd6c1, 0x11c0,
+ 0xd6c4, 0x2290,
+ 0xd6c5, 0x11c4,
+ 0xd6ca, 0x2291,
+ 0xd6cb, 0x11ca,
+ 0xd6cd, 0x2292,
+ 0xd6ce, 0x11cd,
+ 0xd6d3, 0x2293,
+ 0xd6d4, 0x11d3,
+ 0xd6d5, 0x2294,
+ 0xd6d8, 0x11d7,
+ 0xd6da, 0x2297,
+ 0xd6db, 0x11da,
+ 0xd6df, 0x2298,
+ 0xd6e0, 0x11df,
+ 0xd6e1, 0x2299,
+ 0xd6e2, 0x11e1,
+ 0xd6e5, 0x229a,
+ 0xd6e6, 0x11e5,
+ 0xd6e7, 0x229b,
+ 0xd6e9, 0x11e8,
+ 0xd6ee, 0x229d,
+ 0xd6f0, 0x11ef,
+ 0xd6f2, 0x229f,
+ 0xd6f3, 0x11f2,
+ 0xd6f5, 0x22a0,
+ 0xd6f7, 0x11f6,
+ 0xd6fc, 0x22a2,
+ 0xd7a1, 0x11fe,
+ 0xd7a4, 0x22a5,
+ 0xd7a5, 0x1202,
+ 0xd7a8, 0x22a6,
+ 0xd7ab, 0x1208,
+ 0xd7ac, 0x22a9,
+ 0xd7ad, 0x120a,
+ 0xd7ae, 0x22aa,
+ 0xd7b2, 0x120f,
+ 0xd7b3, 0x22ae,
+ 0xd7b5, 0x1212,
+ 0xd7b6, 0x22b0,
+ 0xd7b7, 0x1214,
+ 0xd7b8, 0x22b1,
+ 0xd7bd, 0x121a,
+ 0xd7c7, 0x22b6,
+ 0xd7c8, 0x1225,
+ 0xd7ca, 0x22b7,
+ 0xd7cb, 0x1228,
+ 0xd7d5, 0x22b8,
+ 0xd7d6, 0x1233,
+ 0xd7db, 0x22b9,
+ 0xd7df, 0x123c,
+ 0xd7e7, 0x22bd,
+ 0xd7e8, 0x1245,
+ 0xd7e9, 0x22be,
+ 0xd7eb, 0x1248,
+ 0xd8a1, 0x1257,
+ 0xd8c4, 0x22c0,
+ 0xd8c5, 0x127b,
+ 0xd8c7, 0x22c1,
+ 0xd8c8, 0x127e,
+ 0xd8c9, 0x22c2,
+ 0xd8ca, 0x1280,
+ 0xd8cc, 0x22c3,
+ 0xd8ce, 0x1284,
+ 0xd8d0, 0x22c5,
+ 0xd8d2, 0x1288,
+ 0xd8d3, 0x22c7,
+ 0xd8d4, 0x128a,
+ 0xd8d9, 0x22c8,
+ 0xd8da, 0x1290,
+ 0xd8db, 0x22c9,
+ 0xd8dd, 0x1293,
+ 0xd8f1, 0x22cb,
+ 0xd8f2, 0x12a8,
+ 0xd8f6, 0x22cc,
+ 0xd8f8, 0x12ae,
+ 0xd9a1, 0x12b5,
+ 0xd9ad, 0x22ce,
+ 0xd9ae, 0x12c2,
+ 0xd9af, 0x22cf,
+ 0xd9b0, 0x12c4,
+ 0xd9b1, 0x22d0,
+ 0xd9b4, 0x12c8,
+ 0xd9c7, 0x22d3,
+ 0xd9c8, 0x12dc,
+ 0xd9cd, 0x22d4,
+ 0xd9d1, 0x12e5,
+ 0xd9dd, 0x22d8,
+ 0xd9de, 0x12f2,
+ 0xd9e1, 0x22d9,
+ 0xd9e2, 0x12f6,
+ 0xd9e4, 0x22da,
+ 0xd9e5, 0x12f9,
+ 0xd9e6, 0x22db,
+ 0xd9e7, 0x12fb,
+ 0xd9ec, 0x22dc,
+ 0xd9ed, 0x1301,
+ 0xd9f4, 0x22dd,
+ 0xd9f6, 0x130a,
+ 0xdaa1, 0x1313,
+ 0xdaa5, 0x22df,
+ 0xdae0, 0x1352,
+ 0xdaea, 0x231a,
+ 0xdaeb, 0x135d,
+ 0xdaf7, 0x231b,
+ 0xdaf8, 0x136a,
+ 0xdaf9, 0x231c,
+ 0xdafa, 0x136c,
+ 0xdafe, 0x231d,
+ 0xdba1, 0x1371,
+ 0xdba3, 0x231e,
+ 0xdba4, 0x1374,
+ 0xdba6, 0x231f,
+ 0xdba7, 0x1377,
+ 0xdba9, 0x2320,
+ 0xdbab, 0x137b,
+ 0xdbbb, 0x2322,
+ 0xdbbc, 0x138c,
+ 0xdbbd, 0x2323,
+ 0xdbbe, 0x138e,
+ 0xdbcf, 0x2324,
+ 0xdbd0, 0x13a0,
+ 0xdbd1, 0x2325,
+ 0xdbd2, 0x13a2,
+ 0xdbdb, 0x2326,
+ 0xdbdc, 0x13ac,
+ 0xdbde, 0x2327,
+ 0xdbdf, 0x13af,
+ 0xdbe2, 0x2328,
+ 0xdbe3, 0x13b3,
+ 0xdbe4, 0x2329,
+ 0xdbe5, 0x13b5,
+ 0xdbeb, 0x232a,
+ 0xdbec, 0x13bc,
+ 0xdbee, 0x232b,
+ 0xdbef, 0x13bf,
+ 0xdbf1, 0x232c,
+ 0xdbf2, 0x13c2,
+ 0xdbf5, 0x232d,
+ 0xdbf8, 0x13c8,
+ 0xdca1, 0x13cf,
+ 0xdcbc, 0x2330,
+ 0xdcbd, 0x13eb,
+ 0xdcbf, 0x2331,
+ 0xdcc0, 0x13ee,
+ 0xdcc2, 0x2332,
+ 0xdcc3, 0x13f1,
+ 0xdcc8, 0x2333,
+ 0xdccb, 0x13f9,
+ 0xdcd1, 0x2336,
+ 0xdcd2, 0x1400,
+ 0xdcd7, 0x2337,
+ 0xdcd8, 0x1406,
+ 0xdce0, 0x2338,
+ 0xdce1, 0x140f,
+ 0xdce3, 0x2339,
+ 0xdce5, 0x1413,
+ 0xdce9, 0x233b,
+ 0xdceb, 0x1419,
+ 0xdcf1, 0x233d,
+ 0xdcf2, 0x1420,
+ 0xdcf6, 0x233e,
+ 0xdcf7, 0x1425,
+ 0xdcf9, 0x233f,
+ 0xdcfa, 0x1428,
+ 0xdcfd, 0x2340,
+ 0xdda1, 0x2342,
+ 0xdda2, 0x142e,
+ 0xdda3, 0x2343,
+ 0xdda8, 0x1434,
+ 0xddaa, 0x2348,
+ 0xddac, 0x1438,
+ 0xddb2, 0x234a,
+ 0xddb3, 0x143f,
+ 0xddb5, 0x234b,
+ 0xddb6, 0x1442,
+ 0xddba, 0x234c,
+ 0xddbc, 0x1448,
+ 0xddd3, 0x234e,
+ 0xddd4, 0x1460,
+ 0xdddb, 0x234f,
+ 0xdddc, 0x1468,
+ 0xddde, 0x2350,
+ 0xdddf, 0x146b,
+ 0xdde4, 0x2351,
+ 0xdde5, 0x1471,
+ 0xddeb, 0x2352,
+ 0xddec, 0x1478,
+ 0xddf1, 0x2353,
+ 0xddf2, 0x147e,
+ 0xddf6, 0x2354,
+ 0xddf8, 0x1484,
+ 0xddfc, 0x2356,
+ 0xddfd, 0x1489,
+ 0xddfe, 0x2357,
+ 0xdea1, 0x148b,
+ 0xdead, 0x2358,
+ 0xdeae, 0x1498,
+ 0xdeb4, 0x2359,
+ 0xdeb5, 0x149f,
+ 0xdeba, 0x235a,
+ 0xdebb, 0x14a5,
+ 0xdec6, 0x235b,
+ 0xdec7, 0x14b1,
+ 0xdecf, 0x235c,
+ 0xded0, 0x14ba,
+ 0xded1, 0x235d,
+ 0xded3, 0x14bd,
+ 0xded8, 0x235f,
+ 0xded9, 0x14c3,
+ 0xdee2, 0x2360,
+ 0xdee3, 0x14cd,
+ 0xdee8, 0x2361,
+ 0xdee9, 0x14d3,
+ 0xdeec, 0x2362,
+ 0xdeed, 0x14d7,
+ 0xdef3, 0x2363,
+ 0xdef4, 0x14de,
+ 0xdefc, 0x2364,
+ 0xdefd, 0x14e7,
+ 0xdfa1, 0x14e9,
+ 0xdfa2, 0x2365,
+ 0xdfa4, 0x14ec,
+ 0xdfa5, 0x2367,
+ 0xdfa6, 0x14ee,
+ 0xdfb4, 0x2368,
+ 0xdfb5, 0x14fd,
+ 0xdfbc, 0x2369,
+ 0xdfbe, 0x1506,
+ 0xdfbf, 0x236b,
+ 0xdfc0, 0x1508,
+ 0xdfc2, 0x236c,
+ 0xdfc4, 0x150c,
+ 0xdfcc, 0x236e,
+ 0xdfcd, 0x1515,
+ 0xdfd0, 0x236f,
+ 0xdfd1, 0x1519,
+ 0xdfd5, 0x2370,
+ 0xdfd6, 0x151e,
+ 0xdfd8, 0x2371,
+ 0xdfda, 0x1522,
+ 0xdfdc, 0x2373,
+ 0xdfdd, 0x1525,
+ 0xdfe0, 0x2374,
+ 0xdfe1, 0x1529,
+ 0xdfe2, 0x2375,
+ 0xdfe3, 0x152b,
+ 0xdfe6, 0x2376,
+ 0xdfe7, 0x152f,
+ 0xdfe9, 0x2377,
+ 0xdfea, 0x1532,
+ 0xdfeb, 0x2378,
+ 0xdfec, 0x1534,
+ 0xdfef, 0x2379,
+ 0xdff0, 0x1538,
+ 0xdff5, 0x237a,
+ 0xdff6, 0x153e,
+ 0xdff9, 0x237b,
+ 0xdffa, 0x1542,
+ 0xe0a1, 0x1547,
+ 0xe0b6, 0x237c,
+ 0xe0b8, 0x155e,
+ 0xe0bf, 0x237e,
+ 0xe0c0, 0x1566,
+ 0xe0c8, 0x237f,
+ 0xe0c9, 0x156f,
+ 0xe0ce, 0x2380,
+ 0xe0cf, 0x1575,
+ 0xe0d3, 0x2381,
+ 0xe0d4, 0x157a,
+ 0xe0e0, 0x2382,
+ 0xe0e1, 0x1587,
+ 0xe0f0, 0x2383,
+ 0xe0f1, 0x1597,
+ 0xe0f8, 0x2384,
+ 0xe0f9, 0x159f,
+ 0xe0fc, 0x2385,
+ 0xe1a1, 0x15a5,
+ 0xe1ab, 0x2388,
+ 0xe1ac, 0x15b0,
+ 0xe1ad, 0x2389,
+ 0xe1ae, 0x15b2,
+ 0xe1b0, 0x238a,
+ 0xe1b1, 0x15b5,
+ 0xe1b4, 0x238b,
+ 0xe1b5, 0x15b9,
+ 0xe1bb, 0x238c,
+ 0xe1bc, 0x15c0,
+ 0xe1bd, 0x238d,
+ 0xe1be, 0x15c2,
+ 0xe1c0, 0x238e,
+ 0xe1c2, 0x15c6,
+ 0xe1c9, 0x2390,
+ 0xe1ca, 0x15ce,
+ 0xe1d0, 0x2391,
+ 0xe1d1, 0x15d5,
+ 0xe1db, 0x2392,
+ 0xe1dc, 0x15e0,
+ 0xe1e1, 0x07aa,
+ 0xe1e2, 0x2393,
+ 0xe1e3, 0x15e7,
+ 0xe1e7, 0x1198,
+ 0xe1e8, 0x15ec,
+ 0xe1ee, 0x2394,
+ 0xe1f0, 0x15f4,
+ 0xe1f6, 0x2396,
+ 0xe1f7, 0x15fb,
+ 0xe1f8, 0x2397,
+ 0xe1f9, 0x15fd,
+ 0xe1fd, 0x2398,
+ 0xe1fe, 0x1602,
+ 0xe2a1, 0x1603,
+ 0xe2a4, 0x2399,
+ 0xe2a5, 0x1607,
+ 0xe2a8, 0x239a,
+ 0xe2a9, 0x160b,
+ 0xe2bb, 0x239b,
+ 0xe2c5, 0x10c5,
+ 0xe2c6, 0x23a5,
+ 0xe2cf, 0x1631,
+ 0xe2d0, 0x23ae,
+ 0xe2d1, 0x1633,
+ 0xe2d9, 0x23af,
+ 0xe2da, 0x163c,
+ 0xe2e3, 0x23b0,
+ 0xe2e5, 0x1647,
+ 0xe2e6, 0x23b2,
+ 0xe2e7, 0x1649,
+ 0xe2e9, 0x23b3,
+ 0xe2ec, 0x164e,
+ 0xe2f8, 0x23b6,
+ 0xe2f9, 0x165b,
+ 0xe2fa, 0x23b7,
+ 0xe2fe, 0x1660,
+ 0xe3a1, 0x1661,
+ 0xe3a2, 0x23bb,
+ 0xe3a3, 0x1663,
+ 0xe3a5, 0x23bc,
+ 0xe3a6, 0x1666,
+ 0xe3ab, 0x23bd,
+ 0xe3ac, 0x166c,
+ 0xe3b4, 0x23be,
+ 0xe3b5, 0x1675,
+ 0xe3c5, 0x23bf,
+ 0xe3dc, 0x169c,
+ 0xe3e3, 0x23d6,
+ 0xe3e4, 0x16a4,
+ 0xe3ed, 0x23d7,
+ 0xe3ee, 0x16ae,
+ 0xe3f1, 0x23d8,
+ 0xe3f3, 0x16b3,
+ 0xe3f8, 0x23da,
+ 0xe3f9, 0x16b9,
+ 0xe3fe, 0x23db,
+ 0xe4a1, 0x16bf,
+ 0xe4a4, 0x23dc,
+ 0xe4a6, 0x16c4,
+ 0xe4ab, 0x23de,
+ 0xe4ac, 0x16ca,
+ 0xe4af, 0x23df,
+ 0xe4b2, 0x16d0,
+ 0xe4b5, 0x23e2,
+ 0xe4b7, 0x16d5,
+ 0xe4c2, 0x23e4,
+ 0xe4c3, 0x16e1,
+ 0xe4c5, 0x23e5,
+ 0xe4c6, 0x16e4,
+ 0xe4c9, 0x23e6,
+ 0xe4ca, 0x16e8,
+ 0xe4d9, 0x23e7,
+ 0xe4da, 0x16f8,
+ 0xe4dc, 0x23e8,
+ 0xe4dd, 0x16fb,
+ 0xe4de, 0x23e9,
+ 0xe4df, 0x16fd,
+ 0xe4e4, 0x23ea,
+ 0xe4e5, 0x1703,
+ 0xe4eb, 0x23eb,
+ 0xe4ed, 0x170b,
+ 0xe4f2, 0x23ed,
+ 0xe4f3, 0x1711,
+ 0xe4fe, 0x23ee,
+ 0xe5a1, 0x171d,
+ 0xe5b0, 0x23ef,
+ 0xe5b1, 0x172d,
+ 0xe5b9, 0x23f0,
+ 0xe5ba, 0x1736,
+ 0xe5c7, 0x23f1,
+ 0xe5c8, 0x1744,
+ 0xe5c9, 0x23f2,
+ 0xe5ca, 0x1746,
+ 0xe5ce, 0x23f3,
+ 0xe5cf, 0x174b,
+ 0xe5f0, 0x23f4,
+ 0xe5f1, 0x176d,
+ 0xe5f2, 0x23f5,
+ 0xe5f3, 0x176f,
+ 0xe5fc, 0x23f6,
+ 0xe5fe, 0x177a,
+ 0xe6a1, 0x177b,
+ 0xe6a3, 0x23f8,
+ 0xe6a4, 0x177e,
+ 0xe6ab, 0x23f9,
+ 0xe6ad, 0x1787,
+ 0xe6ae, 0x23fb,
+ 0xe6af, 0x1789,
+ 0xe6b4, 0x23fc,
+ 0xe6b6, 0x1790,
+ 0xe6bf, 0x23fe,
+ 0xe6c0, 0x179a,
+ 0xe6c8, 0x23ff,
+ 0xe6ca, 0x17a4,
+ 0xe6cd, 0x2401,
+ 0xe6ce, 0x17a8,
+ 0xe6e0, 0x2402,
+ 0xe7a1, 0x2421,
+ 0xe7db, 0x1813,
+ 0xe7e1, 0x245b,
+ 0xe7e3, 0x181b,
+ 0xe7e7, 0x245d,
+ 0xe7e8, 0x1820,
+ 0xe7ef, 0x245e,
+ 0xe7f0, 0x1828,
+ 0xe7f4, 0x245f,
+ 0xe7f7, 0x182f,
+ 0xe8a1, 0x1837,
+ 0xe8a8, 0x2462,
+ 0xe8a9, 0x183f,
+ 0xe8ac, 0x2463,
+ 0xe8ad, 0x1843,
+ 0xe8b6, 0x2464,
+ 0xe8b7, 0x184d,
+ 0xe8b8, 0x2465,
+ 0xe8bb, 0x1851,
+ 0xe8bf, 0x2468,
+ 0xe8c1, 0x1857,
+ 0xe8c5, 0x246a,
+ 0xe8c6, 0x185c,
+ 0xe8c7, 0x246b,
+ 0xe8ca, 0x1860,
+ 0xe8ce, 0x246e,
+ 0xe8cf, 0x1865,
+ 0xe8d0, 0x246f,
+ 0xe8d1, 0x1867,
+ 0xe8d3, 0x2470,
+ 0xe8d4, 0x186a,
+ 0xe8dd, 0x2471,
+ 0xe8de, 0x1874,
+ 0xe8df, 0x2472,
+ 0xe8e0, 0x1876,
+ 0xe8e2, 0x2473,
+ 0xe8e4, 0x187a,
+ 0xe8e5, 0x2475,
+ 0xe8e6, 0x187c,
+ 0xe8e7, 0x2476,
+ 0xe8e8, 0x187e,
+ 0xe8eb, 0x2477,
+ 0xe8ec, 0x1882,
+ 0xe8ed, 0x2478,
+ 0xe8ee, 0x1884,
+ 0xe8ef, 0x2479,
+ 0xe8f0, 0x1886,
+ 0xe8f9, 0x247a,
+ 0xe8fa, 0x1890,
+ 0xe8fc, 0x247b,
+ 0xe8fe, 0x1894,
+ 0xe9a1, 0x247d,
+ 0xe9a2, 0x1896,
+ 0xe9ad, 0x247e,
+ 0xe9ae, 0x18a2,
+ 0xe9b4, 0x247f,
+ 0xe9b6, 0x18aa,
+ 0xe9b7, 0x2481,
+ 0xe9b8, 0x18ac,
+ 0xe9c4, 0x2482,
+ 0xe9c5, 0x18b9,
+ 0xe9c6, 0x2483,
+ 0xe9c7, 0x18bb,
+ 0xe9c9, 0x2484,
+ 0xe9ca, 0x18be,
+ 0xe9d6, 0x2485,
+ 0xe9d7, 0x18cb,
+ 0xe9da, 0x2486,
+ 0xe9db, 0x18cf,
+ 0xe9e4, 0x2487,
+ 0xe9e5, 0x18d9,
+ 0xe9e6, 0x2488,
+ 0xe9e8, 0x18dc,
+ 0xe9e9, 0x248a,
+ 0xe9ea, 0x18de,
+ 0xe9eb, 0x248b,
+ 0xe9ec, 0x18e0,
+ 0xe9ed, 0x248c,
+ 0xeaa1, 0x249e,
+ 0xeaa6, 0x18f8,
+ 0xeaa7, 0x24a3,
+ 0xeaa9, 0x18fb,
+ 0xeab1, 0x24a5,
+ 0xeab2, 0x1904,
+ 0xeabc, 0x24a6,
+ 0xeabd, 0x190f,
+ 0xeaca, 0x24a7,
+ 0xeacb, 0x191d,
+ 0xeacd, 0x24a8,
+ 0xeace, 0x1920,
+ 0xead3, 0x24a9,
+ 0xead4, 0x1926,
+ 0xeada, 0x24aa,
+ 0xeaf0, 0x1942,
+ 0xeba1, 0x1951,
+ 0xeba7, 0x24c0,
+ 0xeba8, 0x1958,
+ 0xebaa, 0x24c1,
+ 0xebab, 0x195b,
+ 0xebb2, 0x24c2,
+ 0xebb3, 0x1963,
+ 0xebb9, 0x24c3,
+ 0xebba, 0x196a,
+ 0xebca, 0x24c4,
+ 0xebcc, 0x197c,
+ 0xebcd, 0x24c6,
+ 0xebce, 0x197e,
+ 0xebd6, 0x24c7,
+ 0xebd7, 0x1987,
+ 0xebda, 0x24c8,
+ 0xebdb, 0x198b,
+ 0xebe1, 0x24c9,
+ 0xebe2, 0x1992,
+ 0xebf7, 0x24ca,
+ 0xebf8, 0x19a8,
+ 0xeca1, 0x19af,
+ 0xeca3, 0x24cb,
+ 0xeca4, 0x19b2,
+ 0xeca9, 0x24cc,
+ 0xecaf, 0x19bd,
+ 0xecb1, 0x24d2,
+ 0xecb2, 0x19c0,
+ 0xecb4, 0x24d3,
+ 0xecb6, 0x19c4,
+ 0xecbe, 0x24d5,
+ 0xecc0, 0x19ce,
+ 0xecc1, 0x24d7,
+ 0xecc2, 0x19d0,
+ 0xecc7, 0x24d8,
+ 0xecc8, 0x19d6,
+ 0xeccb, 0x24d9,
+ 0xeccc, 0x19da,
+ 0xece2, 0x24da,
+ 0xece3, 0x19f1,
+ 0xecf2, 0x24db,
+ 0xecf3, 0x1a01,
+ 0xecf5, 0x24dc,
+ 0xecf6, 0x1a04,
+ 0xecf8, 0x24dd,
+ 0xecf9, 0x1a07,
+ 0xeda1, 0x24de,
+ 0xeda2, 0x1a0e,
+ 0xeda8, 0x24df,
+ 0xeda9, 0x1a15,
+ 0xedaf, 0x24e0,
+ 0xedb1, 0x1a1d,
+ 0xedb4, 0x24e2,
+ 0xedb5, 0x1a21,
+ 0xedb6, 0x24e3,
+ 0xedb7, 0x1a23,
+ 0xedb8, 0x24e4,
+ 0xedb9, 0x1a25,
+ 0xedba, 0x24e5,
+ 0xedbb, 0x1a27,
+ 0xedbf, 0x24e6,
+ 0xedc0, 0x1a2c,
+ 0xedc2, 0x24e7,
+ 0xedc4, 0x1a30,
+ 0xedcc, 0x24e9,
+ 0xedce, 0x1a3a,
+ 0xedd3, 0x24eb,
+ 0xedd4, 0x1a40,
+ 0xedd7, 0x24ec,
+ 0xedd8, 0x1a44,
+ 0xede8, 0x24ed,
+ 0xede9, 0x1a55,
+ 0xedee, 0x24ee,
+ 0xedef, 0x1a5b,
+ 0xedf9, 0x24ef,
+ 0xedfb, 0x1a67,
+ 0xeea1, 0x1a6b,
+ 0xeebc, 0x24f1,
+ 0xeebd, 0x1a87,
+ 0xeebf, 0x24f2,
+ 0xeec0, 0x1a8a,
+ 0xeec4, 0x24f3,
+ 0xefa1, 0x252e,
+ 0xeff2, 0x1b1a,
+ 0xf0a1, 0x1b27,
+ 0xf0a3, 0x257f,
+ 0xf0a4, 0x1b2a,
+ 0xf0af, 0x2580,
+ 0xf0da, 0x1b60,
+ 0xf0dc, 0x25ab,
+ 0xf0de, 0x1b64,
+ 0xf0df, 0x25ad,
+ 0xf0e0, 0x1b66,
+ 0xf0e9, 0x25ae,
+ 0xf0ea, 0x1b70,
+ 0xf0ec, 0x25af,
+ 0xf0ed, 0x1b73,
+ 0xf0ef, 0x25b0,
+ 0xf0f0, 0x1b76,
+ 0xf0f7, 0x25b1,
+ 0xf0f8, 0x1b7e,
+ 0xf0f9, 0x25b2,
+ 0xf0fa, 0x1b80,
+ 0xf0fc, 0x25b3,
+ 0xf0fd, 0x1b83,
+ 0xf1a1, 0x1b85,
+ 0xf1a8, 0x25b4,
+ 0xf1a9, 0x1b8d,
+ 0xf1ab, 0x25b5,
+ 0xf1ac, 0x1b90,
+ 0xf1ae, 0x25b6,
+ 0xf1af, 0x1b93,
+ 0xf1b2, 0x25b7,
+ 0xf1b3, 0x1b97,
+ 0xf1bc, 0x25b8,
+ 0xf1bd, 0x1ba1,
+ 0xf1c0, 0x25b9,
+ 0xf1c1, 0x1ba5,
+ 0xf1c9, 0x25ba,
+ 0xf1ca, 0x1bae,
+ 0xf1cd, 0x25bb,
+ 0xf1ce, 0x1bb2,
+ 0xf1cf, 0x25bc,
+ 0xf1d1, 0x1bb5,
+ 0xf1da, 0x25be,
+ 0xf1db, 0x1bbf,
+ 0xf1dc, 0x25bf,
+ 0xf1dd, 0x1bc1,
+ 0xf1e4, 0x25c0,
+ 0xf1e5, 0x1bc9,
+ 0xf1ec, 0x25c1,
+ 0xf1ed, 0x1bd1,
+ 0xf1ef, 0x25c2,
+ 0xf1f0, 0x1bd4,
+ 0xf1f7, 0x25c3,
+ 0xf1f8, 0x1bdc,
+ 0xf1f9, 0x25c4,
+ 0xf1fa, 0x1bde,
+ 0xf1fc, 0x25c5,
+ 0xf2a1, 0x25c8,
+ 0xf2ae, 0x1bf0,
+ 0xf2b1, 0x25d5,
+ 0xf2b3, 0x1bf5,
+ 0xf2b9, 0x25d7,
+ 0xf2ba, 0x1bfc,
+ 0xf2c3, 0x25d8,
+ 0xf2c4, 0x1c06,
+ 0xf2c9, 0x25d9,
+ 0xf2ca, 0x1c0c,
+ 0xf2cc, 0x25da,
+ 0xf2ce, 0x1c10,
+ 0xf2cf, 0x25dc,
+ 0xf2d0, 0x1c12,
+ 0xf2d3, 0x25dd,
+ 0xf2d4, 0x1c16,
+ 0xf2e5, 0x25de,
+ 0xf2e6, 0x1c28,
+ 0xf2ee, 0x25df,
+ 0xf2ef, 0x1c31,
+ 0xf2f7, 0x25e0,
+ 0xf2f8, 0x1c3a,
+ 0xf2fd, 0x25e1,
+ 0xf2fe, 0x1c40,
+ 0xf3a1, 0x1c41,
+ 0xf3bf, 0x25e2,
+ 0xf3c0, 0x1c60,
+ 0xf3c6, 0x25e3,
+ 0xf3c7, 0x1c67,
+ 0xf3c8, 0x25e4,
+ 0xf3c9, 0x1c69,
+ 0xf3d6, 0x25e5,
+ 0xf3d7, 0x1c77,
+ 0xf3d9, 0x25e6,
+ 0xf3da, 0x1c7a,
+ 0xf3e5, 0x25e7,
+ 0xf3e7, 0x1c87,
+ 0xf3ea, 0x25e9,
+ 0xf3eb, 0x1c8b,
+ 0xf3ec, 0x25ea,
+ 0xf3ed, 0x1c8d,
+ 0xf3ef, 0x25eb,
+ 0xf3f0, 0x1c90,
+ 0xf3f1, 0x25ec,
+ 0xf3f2, 0x1c92,
+ 0xf3fd, 0x25ed,
+ 0xf3fe, 0x1c9e,
+ 0xf4a1, 0x1c9f,
+ 0xf4a5, 0x25ee,
+ 0xf4a6, 0x1ca4,
+ 0xf4af, 0x25ef,
+ 0xf4b0, 0x1cae,
+ 0xf4b5, 0x25f0,
+ 0xf4b6, 0x1cb4,
+ 0xf4c1, 0x25f1,
+ 0xf4c2, 0x1cc0,
+ 0xf4c7, 0x25f2,
+ 0xf4c8, 0x1cc6,
+ 0xf4cf, 0x25f3,
+ 0xf4d1, 0x1ccf,
+ 0xf4d6, 0x25f5,
+ 0xf4d7, 0x1cd5,
+ 0xf4ea, 0x25f6,
+ 0xf4eb, 0x1ce9,
+ 0xf4ef, 0x25f7,
+ 0xf4f0, 0x1cee,
+ 0xf4f5, 0x25f8,
+ 0xf4f6, 0x1cf4,
+ 0xf5a1, 0x1cfd,
+ 0xf5a6, 0x25f9,
+ 0xf5a8, 0x1d04,
+ 0xf5ba, 0x25fb,
+ 0xf5bc, 0x1d18,
+ 0xf5c4, 0x25fd,
+ 0xf5c5, 0x1d21,
+ 0xf5c8, 0x25fe,
+ 0xf5c9, 0x1d25,
+ 0xf5ce, 0x25ff,
+ 0xf5d0, 0x1d2c,
+ 0xf5d1, 0x2601,
+ 0xf5d3, 0x1d2f,
+ 0xf5d9, 0x2603,
+ 0xf5da, 0x1d36,
+ 0xf5dc, 0x2604,
+ 0xf5dd, 0x1d39,
+ 0xf5e6, 0x2605,
+ 0xf5e8, 0x1d44,
+ 0xf5ef, 0x2607,
+ 0xf5f0, 0x1d4c,
+ 0xf5f2, 0x2608,
+ 0xf5f3, 0x1d4f,
+ 0xf5fc, 0x2609,
+ 0xf5fd, 0x1d59,
+ 0xf6a1, 0x1d5b,
+ 0xf6a3, 0x260a,
+ 0xf6a4, 0x1d5e,
+ 0xf6a6, 0x260b,
+ 0xf6a7, 0x1d61,
+ 0xf6a8, 0x260c,
+ 0xf6a9, 0x1d63,
+ 0xf6ab, 0x260d,
+ 0xf6ac, 0x1d66,
+ 0xf6b0, 0x260e,
+ 0xf6b1, 0x1d6b,
+ 0xf6b3, 0x260f,
+ 0xf6bf, 0x1d79,
+ 0xf6c5, 0x261b,
+ 0xf6c6, 0x1d80,
+ 0xf6c7, 0x261c,
+ 0xf6c8, 0x1d82,
+ 0xf6c9, 0x261d,
+ 0xf6ca, 0x1d84,
+ 0xf6cf, 0x261e,
+ 0xf7a1, 0x264e,
+ 0xf7b0, 0x1dc8,
+ 0xf7b2, 0x265d,
+ 0xf7b4, 0x1dcc,
+ 0xf7b5, 0x265f,
+ 0xf7b6, 0x1dce,
+ 0xf7bd, 0x2660,
+ 0xf7be, 0x1dd6,
+ 0xf7c3, 0x2661,
+ 0xf7c4, 0x1ddc,
+ 0xf7c5, 0x2662,
+ 0xf7c7, 0x1ddf,
+ 0xf7ca, 0x2664,
+ 0xf7cc, 0x1de4,
+ 0xf7cf, 0x2666,
+ 0xf7d1, 0x1de9,
+ 0xf7de, 0x2668,
+ 0xf7df, 0x1df7,
+ 0xf7e1, 0x0ab9,
+ 0xf7e2, 0x1dfa,
+ 0xf7f2, 0x2669,
+ 0xf7f3, 0x1e0b,
+ 0xf7f5, 0x266a,
+ 0xf7f6, 0x1e0e,
+ 0xf8a1, 0x266b,
+ 0xf8a7, 0x04cc,
+ 0xf8a8, 0x050a,
+ 0xf8a9, 0x0518,
+ 0xf8aa, 0x2671,
+ 0xf8ac, 0x0594,
+ 0xf8ad, 0x05ce,
+ 0xf8ae, 0x2673,
+ 0xf8af, 0x05f6,
+ 0xf8b0, 0x2674,
+ 0xf8b2, 0x0653,
+ 0xf8b3, 0x067e,
+ 0xf8b4, 0x2676,
+ 0xf8b5, 0x06c4,
+ 0xf8b6, 0x2677,
+ 0xf8b8, 0x073c,
+ 0xf8b9, 0x2679,
+ 0xf8bb, 0x07c3,
+ 0xf8bc, 0x267b,
+ 0xf8c0, 0x082b,
+ 0xf8c1, 0x267f,
+ 0xf8c2, 0x084e,
+ 0xf8c3, 0x0869,
+ 0xf8c4, 0x2680,
+ 0xf8c6, 0x090c,
+ 0xf8c7, 0x2682,
+ 0xf8c9, 0x0971,
+ 0xf8ca, 0x2684,
+ 0xf8cb, 0x099a,
+ 0xf8cd, 0x2685,
+ 0xf8ce, 0x09da,
+ 0xf8cf, 0x2686,
+ 0xf8d0, 0x09fa,
+ 0xf8d1, 0x2687,
+ 0xf8dc, 0x0bda,
+ 0xf8dd, 0x0bdd,
+ 0xf8de, 0x0bea,
+ 0xf8df, 0x0bec,
+ 0xf8e0, 0x0bf2,
+ 0xf8e1, 0x2692,
+ 0xf8e6, 0x0c92,
+ 0xf8e7, 0x0d1a,
+ 0xf8e8, 0x0d8c,
+ 0xf8e9, 0x0dbe,
+ 0xf8ea, 0x2697,
+ 0xf8eb, 0x0dfb,
+ 0xf8ec, 0x2698,
+ 0xf8ef, 0x0e70,
+ 0xf8f0, 0x269b,
+ 0xf8f1, 0x0ea3,
+ 0xf8f2, 0x269c,
+ 0xf8f8, 0x103d,
+ 0xf8f9, 0x10d9,
+ 0xf8fa, 0x26a2,
+ 0xf8fc, 0x10fb,
+ 0xf8fd, 0x1109,
+ 0xf8fe, 0x26a4,
+ 0xf9a1, 0x11a1,
+ 0xf9a2, 0x26a5,
+ 0xf9a3, 0x11ba,
+ 0xf9a4, 0x26a6,
+ 0xf9a6, 0x11d5,
+ 0xf9a7, 0x26a8,
+ 0xf9a8, 0x11fd,
+ 0xf9a9, 0x1219,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 gb12GBTpcEUCHEnc16 = {
+ 0,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
+ 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010,
+ 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018,
+ 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020,
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028,
+ 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030,
+ 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038,
+ 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040,
+ 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048,
+ 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050,
+ 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
+ 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0000,
+ 0x1e20, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1e21, 0x1e22, 0x1e23 },
+ gb12GBTpcEUCHMap2, 2283
+};
+
+static Gushort gb12GBTpcEUCVMap2[4606] = {
+ 0x0000, 0x0000,
+ 0xa1a1, 0x0060,
+ 0xa2b1, 0x00be,
+ 0xa2e5, 0x00f0,
+ 0xa2f1, 0x00fa,
+ 0xa3a1, 0x0106,
+ 0xa4a1, 0x0164,
+ 0xa5a1, 0x01b7,
+ 0xa6a1, 0x020d,
+ 0xa6c1, 0x0225,
+ 0xa7a1, 0x025a,
+ 0xa7d1, 0x027b,
+ 0xa8a1, 0x029c,
+ 0xa8c5, 0x02bc,
+ 0xa9a4, 0x02e2,
+ 0xaaa1, 0x032e,
+ 0xaba1, 0x038c,
+ 0xb0a1, 0x03ac,
+ 0xb0a8, 0x1e25,
+ 0xb0a9, 0x03b4,
+ 0xb0aa, 0x1e26,
+ 0xb0ab, 0x03b6,
+ 0xb0ad, 0x1e27,
+ 0xb0af, 0x03ba,
+ 0xb0b9, 0x1e29,
+ 0xb0ba, 0x03c5,
+ 0xb0c0, 0x1e2a,
+ 0xb0c1, 0x03cc,
+ 0xb0d3, 0x1e2b,
+ 0xb0d4, 0x03df,
+ 0xb0d5, 0x1e2c,
+ 0xb0d6, 0x03e1,
+ 0xb0da, 0x1e2d,
+ 0xb0db, 0x03e6,
+ 0xb0dc, 0x1e2e,
+ 0xb0dd, 0x03e8,
+ 0xb0e4, 0x1e2f,
+ 0xb0e5, 0x03f0,
+ 0xb0ec, 0x1e30,
+ 0xb0ee, 0x03f9,
+ 0xb0ef, 0x1e32,
+ 0xb0f0, 0x03fb,
+ 0xb0f3, 0x1e33,
+ 0xb0f4, 0x03ff,
+ 0xb0f7, 0x1e34,
+ 0xb0f8, 0x0403,
+ 0xb0f9, 0x1e35,
+ 0xb0fa, 0x0405,
+ 0xb1a1, 0x040a,
+ 0xb1a5, 0x1e36,
+ 0xb1a7, 0x0410,
+ 0xb1a8, 0x1e38,
+ 0xb1a9, 0x0412,
+ 0xb1ab, 0x1e39,
+ 0xb1ac, 0x0415,
+ 0xb1b2, 0x1e3a,
+ 0xb1b3, 0x041c,
+ 0xb1b4, 0x1e3b,
+ 0xb1b6, 0x041f,
+ 0xb1b7, 0x1e3d,
+ 0xb1ba, 0x0423,
+ 0xb1c1, 0x1e40,
+ 0xb1c2, 0x042b,
+ 0xb1ca, 0x1e41,
+ 0xb1cb, 0x0434,
+ 0xb1cf, 0x1e42,
+ 0xb1d1, 0x043a,
+ 0xb1d2, 0x1e44,
+ 0xb1d3, 0x043c,
+ 0xb1d5, 0x1e45,
+ 0xb1d6, 0x043f,
+ 0xb1df, 0x1e46,
+ 0xb1e2, 0x044b,
+ 0xb1e4, 0x1e49,
+ 0xb1e5, 0x044e,
+ 0xb1e7, 0x1e4a,
+ 0xb1e9, 0x0452,
+ 0xb1ea, 0x1e4c,
+ 0xb1eb, 0x0454,
+ 0xb1ee, 0x1e4d,
+ 0xb1ef, 0x0458,
+ 0xb1f1, 0x1e4e,
+ 0xb1f2, 0x045b,
+ 0xb1f4, 0x1e4f,
+ 0xb1f8, 0x0461,
+ 0xb1fd, 0x1e53,
+ 0xb1fe, 0x0467,
+ 0xb2a1, 0x0468,
+ 0xb2a6, 0x1e54,
+ 0xb2a8, 0x046f,
+ 0xb2ac, 0x1e56,
+ 0xb2ad, 0x0474,
+ 0xb2b5, 0x1e57,
+ 0xb2b6, 0x047d,
+ 0xb2b9, 0x1e58,
+ 0xb2ba, 0x0481,
+ 0xb2c6, 0x1e59,
+ 0xb2c7, 0x048e,
+ 0xb2ce, 0x1e5a,
+ 0xb2d8, 0x049f,
+ 0xb2de, 0x1e64,
+ 0xb2df, 0x04a6,
+ 0xb2e0, 0x1e65,
+ 0xb2e1, 0x04a8,
+ 0xb2e2, 0x1e66,
+ 0xb2e4, 0x04ab,
+ 0xb2ef, 0x1e68,
+ 0xb2f0, 0x04b7,
+ 0xb2f3, 0x1e69,
+ 0xb2fd, 0x04c4,
+ 0xb3a1, 0x1e73,
+ 0xb3a3, 0x04c8,
+ 0xb3a4, 0x1e75,
+ 0xb3a8, 0x04cd,
+ 0xb3a9, 0x1e79,
+ 0xb3aa, 0x04cf,
+ 0xb3ae, 0x1e7a,
+ 0xb3af, 0x04d4,
+ 0xb3b5, 0x1e7b,
+ 0xb3b6, 0x04db,
+ 0xb3b9, 0x1e7c,
+ 0xb3ba, 0x04df,
+ 0xb3be, 0x1e7d,
+ 0xb3bf, 0x04e4,
+ 0xb3c2, 0x1e7e,
+ 0xb3c3, 0x04e8,
+ 0xb3c4, 0x1e7f,
+ 0xb3c5, 0x04ea,
+ 0xb3c6, 0x1e80,
+ 0xb3c7, 0x04ec,
+ 0xb3cd, 0x1e81,
+ 0xb3ce, 0x04f3,
+ 0xb3cf, 0x1e82,
+ 0xb3d0, 0x04f5,
+ 0xb3d2, 0x1e83,
+ 0xb3d3, 0x04f8,
+ 0xb3d9, 0x1e84,
+ 0xb3da, 0x04ff,
+ 0xb3db, 0x1e85,
+ 0xb3dc, 0x0501,
+ 0xb3dd, 0x1e86,
+ 0xb3de, 0x0503,
+ 0xb3e3, 0x1e87,
+ 0xb3e4, 0x0509,
+ 0xb3e5, 0x1e88,
+ 0xb3e7, 0x050c,
+ 0xb3e8, 0x1e8a,
+ 0xb3e9, 0x050e,
+ 0xb3eb, 0x1e8b,
+ 0xb3ed, 0x0512,
+ 0xb3ef, 0x1e8d,
+ 0xb3f0, 0x0515,
+ 0xb3f1, 0x1e8e,
+ 0xb3f2, 0x0517,
+ 0xb3f3, 0x1e8f,
+ 0xb3f4, 0x0519,
+ 0xb3fa, 0x1e90,
+ 0xb3fc, 0x0521,
+ 0xb4a1, 0x1e92,
+ 0xb4a3, 0x0526,
+ 0xb4a5, 0x1e94,
+ 0xb4a7, 0x052a,
+ 0xb4ab, 0x1e96,
+ 0xb4ac, 0x052f,
+ 0xb4af, 0x1e97,
+ 0xb4b0, 0x0533,
+ 0xb4b3, 0x1e98,
+ 0xb4b5, 0x0538,
+ 0xb4b8, 0x1e9a,
+ 0xb4b9, 0x053c,
+ 0xb4bf, 0x1e9b,
+ 0xb4c0, 0x0543,
+ 0xb4c2, 0x1e9c,
+ 0xb4c3, 0x0546,
+ 0xb4c7, 0x1e9d,
+ 0xb4c8, 0x054b,
+ 0xb4ca, 0x1e9e,
+ 0xb4cb, 0x054e,
+ 0xb4cd, 0x1e9f,
+ 0xb4ce, 0x0551,
+ 0xb4cf, 0x1ea0,
+ 0xb4d0, 0x0553,
+ 0xb4d3, 0x1ea1,
+ 0xb4d5, 0x0558,
+ 0xb4da, 0x1ea3,
+ 0xb4db, 0x055e,
+ 0xb4dc, 0x1ea4,
+ 0xb4dd, 0x0560,
+ 0xb4ed, 0x1ea5,
+ 0xb4ee, 0x0571,
+ 0xb4ef, 0x1ea6,
+ 0xb4f0, 0x0573,
+ 0xb4f8, 0x1ea7,
+ 0xb4f9, 0x057c,
+ 0xb4fb, 0x1ea8,
+ 0xb4fc, 0x057f,
+ 0xb5a1, 0x0582,
+ 0xb5a3, 0x1ea9,
+ 0xb5a4, 0x0585,
+ 0xb5a5, 0x1eaa,
+ 0xb5a9, 0x058a,
+ 0xb5ac, 0x1eae,
+ 0xb5ad, 0x058e,
+ 0xb5ae, 0x1eaf,
+ 0xb5b0, 0x0591,
+ 0xb5b1, 0x1eb1,
+ 0xb5b6, 0x0597,
+ 0xb5b7, 0x1eb6,
+ 0xb5b8, 0x0599,
+ 0xb5ba, 0x1eb7,
+ 0xb5bd, 0x059e,
+ 0xb5c6, 0x1eba,
+ 0xb5c7, 0x05a8,
+ 0xb5cb, 0x1ebb,
+ 0xb5cc, 0x05ad,
+ 0xb5d0, 0x1ebc,
+ 0xb5d1, 0x05b2,
+ 0xb5d3, 0x1ebd,
+ 0xb5d4, 0x05b5,
+ 0xb5dd, 0x1ebe,
+ 0xb5e0, 0x05c1,
+ 0xb5e3, 0x1ec1,
+ 0xb5e4, 0x05c5,
+ 0xb5e6, 0x1ec2,
+ 0xb5e8, 0x05c9,
+ 0xb5ed, 0x1ec4,
+ 0xb5ee, 0x05cf,
+ 0xb5f6, 0x1ec5,
+ 0xb5f8, 0x05d9,
+ 0xb5fd, 0x1ec7,
+ 0xb5fe, 0x05df,
+ 0xb6a1, 0x05e0,
+ 0xb6a4, 0x1ec8,
+ 0xb6a6, 0x05e5,
+ 0xb6a7, 0x1eca,
+ 0xb6a8, 0x05e7,
+ 0xb6a9, 0x1ecb,
+ 0xb6aa, 0x05e9,
+ 0xb6ab, 0x1ecc,
+ 0xb6ac, 0x05eb,
+ 0xb6af, 0x1ecd,
+ 0xb6b1, 0x05f0,
+ 0xb6b3, 0x1ecf,
+ 0xb6b4, 0x05f3,
+ 0xb6b7, 0x1ed0,
+ 0xb6b8, 0x05f7,
+ 0xb6bf, 0x1ed1,
+ 0xb6c2, 0x0601,
+ 0xb6c4, 0x1ed4,
+ 0xb6c5, 0x0604,
+ 0xb6c6, 0x1ed5,
+ 0xb6c7, 0x0606,
+ 0xb6cd, 0x1ed6,
+ 0xb6ce, 0x060d,
+ 0xb6cf, 0x1ed7,
+ 0xb6d1, 0x0610,
+ 0xb6d3, 0x1ed9,
+ 0xb6d5, 0x0614,
+ 0xb6d6, 0x1edb,
+ 0xb6d7, 0x0616,
+ 0xb6d9, 0x1edc,
+ 0xb6da, 0x0619,
+ 0xb6db, 0x1edd,
+ 0xb6dc, 0x061b,
+ 0xb6e1, 0x1ede,
+ 0xb6e2, 0x0621,
+ 0xb6e9, 0x1edf,
+ 0xb6ea, 0x0629,
+ 0xb6ec, 0x1ee0,
+ 0xb6ed, 0x062c,
+ 0xb6ee, 0x1ee1,
+ 0xb6f0, 0x062f,
+ 0xb6f1, 0x1ee3,
+ 0xb6f2, 0x0631,
+ 0xb6f6, 0x1ee4,
+ 0xb6f7, 0x0636,
+ 0xb6f9, 0x1ee5,
+ 0xb6fa, 0x0639,
+ 0xb6fb, 0x1ee6,
+ 0xb6fd, 0x063c,
+ 0xb7a1, 0x1ee8,
+ 0xb7a4, 0x0641,
+ 0xb7a7, 0x1eeb,
+ 0xb7a8, 0x0645,
+ 0xb7af, 0x1eec,
+ 0xb7b1, 0x064e,
+ 0xb7b3, 0x1eee,
+ 0xb7b4, 0x0651,
+ 0xb7b6, 0x1eef,
+ 0xb7b8, 0x0655,
+ 0xb7b9, 0x1ef1,
+ 0xb7ba, 0x0657,
+ 0xb7c3, 0x1ef2,
+ 0xb7c5, 0x0662,
+ 0xb7c9, 0x1ef4,
+ 0xb7ca, 0x0667,
+ 0xb7cc, 0x1ef5,
+ 0xb7cd, 0x066a,
+ 0xb7cf, 0x1ef6,
+ 0xb7d0, 0x066d,
+ 0xb7d1, 0x1ef7,
+ 0xb7d2, 0x066f,
+ 0xb7d7, 0x1ef8,
+ 0xb7d9, 0x0676,
+ 0xb7dc, 0x1efa,
+ 0xb7dd, 0x067a,
+ 0xb7df, 0x1efb,
+ 0xb7e2, 0x067f,
+ 0xb7e3, 0x1efe,
+ 0xb7e4, 0x0681,
+ 0xb7e6, 0x1eff,
+ 0xb7e9, 0x0686,
+ 0xb7eb, 0x1f02,
+ 0xb7ee, 0x068b,
+ 0xb7ef, 0x1f05,
+ 0xb7f0, 0x068d,
+ 0xb7f4, 0x1f06,
+ 0xb7f5, 0x0692,
+ 0xb7f8, 0x1f07,
+ 0xb7f9, 0x0696,
+ 0xb8a1, 0x069c,
+ 0xb8a7, 0x1f08,
+ 0xb8a9, 0x06a4,
+ 0xb8b3, 0x1f0a,
+ 0xb8b5, 0x06b0,
+ 0xb8ba, 0x1f0c,
+ 0xb8bb, 0x06b6,
+ 0xb8bc, 0x1f0d,
+ 0xb8bd, 0x06b8,
+ 0xb8be, 0x1f0e,
+ 0xb8c0, 0x06bb,
+ 0xb8c3, 0x1f10,
+ 0xb8c4, 0x06bf,
+ 0xb8c6, 0x1f11,
+ 0xb8c8, 0x06c3,
+ 0xb8c9, 0x1f13,
+ 0xb8ca, 0x06c5,
+ 0xb8cf, 0x1f14,
+ 0xb8d0, 0x06cb,
+ 0xb8d3, 0x1f15,
+ 0xb8d7, 0x06d2,
+ 0xb8d9, 0x1f19,
+ 0xb8db, 0x06d6,
+ 0xb8e4, 0x1f1b,
+ 0xb8e5, 0x06e0,
+ 0xb8e9, 0x1f1c,
+ 0xb8ea, 0x06e5,
+ 0xb8eb, 0x1f1d,
+ 0xb8ec, 0x06e7,
+ 0xb8f3, 0x1f1e,
+ 0xb8f4, 0x06ef,
+ 0xb8f5, 0x1f1f,
+ 0xb8f7, 0x06f2,
+ 0xb8f8, 0x1f21,
+ 0xb8f9, 0x06f4,
+ 0xb9a1, 0x06fa,
+ 0xb9a8, 0x1f22,
+ 0xb9a9, 0x0702,
+ 0xb9ae, 0x1f23,
+ 0xb9af, 0x0708,
+ 0xb9b1, 0x1f24,
+ 0xb9b2, 0x070b,
+ 0xb9b3, 0x1f25,
+ 0xb9b4, 0x070d,
+ 0xb9b5, 0x1f26,
+ 0xb9b6, 0x070f,
+ 0xb9b9, 0x1f27,
+ 0xb9bb, 0x0714,
+ 0xb9c6, 0x1f29,
+ 0xb9c7, 0x0720,
+ 0xb9cb, 0x1f2a,
+ 0xb9cc, 0x0725,
+ 0xb9d0, 0x1f2b,
+ 0xb9d1, 0x072a,
+ 0xb9d8, 0x1f2c,
+ 0xb9d9, 0x0732,
+ 0xb9db, 0x1f2d,
+ 0xb9dc, 0x0735,
+ 0xb9dd, 0x1f2e,
+ 0xb9de, 0x0737,
+ 0xb9df, 0x1f2f,
+ 0xb9e0, 0x0739,
+ 0xb9e1, 0x1f30,
+ 0xb9e2, 0x073b,
+ 0xb9e3, 0x1f31,
+ 0xb9e4, 0x073d,
+ 0xb9e6, 0x1f32,
+ 0xb9e7, 0x0740,
+ 0xb9e9, 0x1f33,
+ 0xb9ed, 0x0746,
+ 0xb9ee, 0x1f37,
+ 0xb9ef, 0x0748,
+ 0xb9f1, 0x1f38,
+ 0xb9f2, 0x074b,
+ 0xb9f3, 0x1f39,
+ 0xb9f6, 0x074f,
+ 0xb9f8, 0x1f3c,
+ 0xb9f9, 0x0752,
+ 0xb9fa, 0x1f3d,
+ 0xb9fb, 0x0754,
+ 0xb9fd, 0x1f3e,
+ 0xb9fe, 0x0757,
+ 0xbaa1, 0x0758,
+ 0xbaa7, 0x1f3f,
+ 0xbaa8, 0x075f,
+ 0xbaab, 0x1f40,
+ 0xbaac, 0x0763,
+ 0xbaba, 0x1f41,
+ 0xbabb, 0x0772,
+ 0xbac5, 0x1f42,
+ 0xbac6, 0x077d,
+ 0xbad2, 0x1f43,
+ 0xbad3, 0x078a,
+ 0xbad7, 0x1f44,
+ 0xbad9, 0x0790,
+ 0xbae4, 0x1f46,
+ 0xbae5, 0x079c,
+ 0xbae8, 0x1f47,
+ 0xbae9, 0x07a0,
+ 0xbaec, 0x1f48,
+ 0xbaed, 0x07a4,
+ 0xbaf3, 0x15e5,
+ 0xbaf4, 0x07ab,
+ 0xbaf8, 0x1f49,
+ 0xbaf9, 0x07b0,
+ 0xbba1, 0x07b6,
+ 0xbba4, 0x1f4a,
+ 0xbba5, 0x07ba,
+ 0xbba6, 0x1f4b,
+ 0xbba7, 0x07bc,
+ 0xbba9, 0x1f4c,
+ 0xbbab, 0x07c0,
+ 0xbbad, 0x1f4e,
+ 0xbbaf, 0x07c4,
+ 0xbbb0, 0x1f50,
+ 0xbbb1, 0x07c6,
+ 0xbbb3, 0x1f51,
+ 0xbbb4, 0x07c9,
+ 0xbbb5, 0x1f52,
+ 0xbbb8, 0x07cd,
+ 0xbbb9, 0x1f55,
+ 0xbbbb, 0x07d0,
+ 0xbbd1, 0x1f57,
+ 0xbbd2, 0x07e7,
+ 0xbbd3, 0x1f58,
+ 0xbbd5, 0x07ea,
+ 0xbbdf, 0x1f5a,
+ 0xbbe8, 0x07fd,
+ 0xbbeb, 0x1f63,
+ 0xbbec, 0x0801,
+ 0xbbf1, 0x1f64,
+ 0xbbf2, 0x0807,
+ 0xbbf5, 0x1f65,
+ 0xbbf8, 0x080d,
+ 0xbbfa, 0x1f68,
+ 0xbbfb, 0x0810,
+ 0xbbfd, 0x1f69,
+ 0xbbfe, 0x0813,
+ 0xbca1, 0x0814,
+ 0xbca2, 0x1f6a,
+ 0xbca3, 0x0816,
+ 0xbca5, 0x1f6b,
+ 0xbca7, 0x081a,
+ 0xbca8, 0x1f6d,
+ 0xbcaa, 0x081d,
+ 0xbcab, 0x1f6f,
+ 0xbcac, 0x081f,
+ 0xbcad, 0x1f70,
+ 0xbcae, 0x0821,
+ 0xbcb6, 0x1f71,
+ 0xbcb9, 0x082c,
+ 0xbcbb, 0x1f74,
+ 0xbcbc, 0x082f,
+ 0xbcc1, 0x1f75,
+ 0xbcc2, 0x0835,
+ 0xbcc3, 0x1f76,
+ 0xbcc4, 0x0837,
+ 0xbcc6, 0x1f77,
+ 0xbcc8, 0x083b,
+ 0xbcca, 0x1f79,
+ 0xbccb, 0x083e,
+ 0xbccc, 0x1f7a,
+ 0xbcce, 0x0841,
+ 0xbcd0, 0x1f7c,
+ 0xbcd1, 0x0844,
+ 0xbcd4, 0x1f7d,
+ 0xbcd7, 0x084a,
+ 0xbcd8, 0x1f80,
+ 0xbcd9, 0x084c,
+ 0xbcdb, 0x1f81,
+ 0xbcdc, 0x084f,
+ 0xbcdd, 0x1f82,
+ 0xbcde, 0x0851,
+ 0xbcdf, 0x1f83,
+ 0xbce2, 0x0855,
+ 0xbce3, 0x1f86,
+ 0xbce5, 0x0858,
+ 0xbce8, 0x1f88,
+ 0xbce9, 0x085c,
+ 0xbcea, 0x1f89,
+ 0xbced, 0x0860,
+ 0xbcef, 0x1f8c,
+ 0xbcf4, 0x0867,
+ 0xbcf6, 0x1f91,
+ 0xbcfd, 0x0870,
+ 0xbda1, 0x0872,
+ 0xbda2, 0x1f98,
+ 0xbda8, 0x0879,
+ 0xbdab, 0x1f9e,
+ 0xbdad, 0x087e,
+ 0xbdaf, 0x1fa0,
+ 0xbdb3, 0x0884,
+ 0xbdb4, 0x1fa4,
+ 0xbdb5, 0x0886,
+ 0xbdba, 0x1fa5,
+ 0xbdbb, 0x088c,
+ 0xbdbd, 0x1fa6,
+ 0xbdc0, 0x0891,
+ 0xbdc1, 0x1fa9,
+ 0xbdc5, 0x0896,
+ 0xbdc8, 0x1fad,
+ 0xbdcb, 0x089c,
+ 0xbdce, 0x1fb0,
+ 0xbdd0, 0x08a1,
+ 0xbdd7, 0x1fb2,
+ 0xbdd8, 0x08a9,
+ 0xbdda, 0x1fb3,
+ 0xbddb, 0x08ac,
+ 0xbde0, 0x1fb4,
+ 0xbde2, 0x08b3,
+ 0xbdeb, 0x1fb6,
+ 0xbdec, 0x08bd,
+ 0xbdf4, 0x1fb7,
+ 0xbdf9, 0x08ca,
+ 0xbdfd, 0x1fbc,
+ 0xbdfe, 0x08cf,
+ 0xbea1, 0x1fbd,
+ 0xbea3, 0x08d2,
+ 0xbea5, 0x1fbf,
+ 0xbea6, 0x08d5,
+ 0xbea8, 0x1fc0,
+ 0xbea9, 0x08d8,
+ 0xbeaa, 0x1fc1,
+ 0xbeab, 0x08da,
+ 0xbead, 0x1fc2,
+ 0xbeae, 0x08dd,
+ 0xbeb1, 0x1fc3,
+ 0xbeb2, 0x08e1,
+ 0xbeb5, 0x1fc4,
+ 0xbeb8, 0x08e7,
+ 0xbeba, 0x1fc7,
+ 0xbebb, 0x08ea,
+ 0xbec0, 0x1fc8,
+ 0xbec1, 0x08f0,
+ 0xbec9, 0x1fc9,
+ 0xbeca, 0x08f9,
+ 0xbed4, 0x1fca,
+ 0xbed5, 0x0904,
+ 0xbed9, 0x1fcb,
+ 0xbeda, 0x0909,
+ 0xbedd, 0x1fcc,
+ 0xbede, 0x090d,
+ 0xbee2, 0x1fcd,
+ 0xbee3, 0x0912,
+ 0xbee5, 0x1fce,
+ 0xbee6, 0x0915,
+ 0xbee7, 0x1fcf,
+ 0xbee8, 0x0917,
+ 0xbee9, 0x1fd0,
+ 0xbeea, 0x0919,
+ 0xbeee, 0x1fd1,
+ 0xbeef, 0x091e,
+ 0xbef5, 0x1fd2,
+ 0xbef6, 0x0925,
+ 0xbef7, 0x1fd3,
+ 0xbef9, 0x0928,
+ 0xbefb, 0x1fd5,
+ 0xbefd, 0x092c,
+ 0xbfa1, 0x092e,
+ 0xbfa5, 0x1fd7,
+ 0xbfa6, 0x0933,
+ 0xbfaa, 0x1fd8,
+ 0xbfab, 0x0938,
+ 0xbfad, 0x1fd9,
+ 0xbfae, 0x093b,
+ 0xbfc5, 0x1fda,
+ 0xbfc6, 0x0953,
+ 0xbfc7, 0x1fdb,
+ 0xbfc8, 0x0955,
+ 0xbfce, 0x1fdc,
+ 0xbfcf, 0x095c,
+ 0xbfd1, 0x1fdd,
+ 0xbfd3, 0x0960,
+ 0xbfd9, 0x1fdf,
+ 0xbfda, 0x0967,
+ 0xbfe2, 0x1fe0,
+ 0xbfe5, 0x0972,
+ 0xbfe9, 0x1fe3,
+ 0xbfea, 0x0977,
+ 0xbfeb, 0x1fe4,
+ 0xbfec, 0x0979,
+ 0xbfed, 0x1fe5,
+ 0xbfee, 0x097b,
+ 0xbff3, 0x1fe6,
+ 0xbff4, 0x0981,
+ 0xbff5, 0x1fe7,
+ 0xbff6, 0x0983,
+ 0xbff7, 0x1fe8,
+ 0xbff8, 0x0985,
+ 0xbff9, 0x1fe9,
+ 0xbffb, 0x0988,
+ 0xc0a1, 0x1feb,
+ 0xc0a2, 0x098d,
+ 0xc0a3, 0x1fec,
+ 0xc0a4, 0x098f,
+ 0xc0a9, 0x1fed,
+ 0xc0aa, 0x0995,
+ 0xc0ab, 0x1fee,
+ 0xc0ac, 0x0997,
+ 0xc0af, 0x1fef,
+ 0xc0b1, 0x099c,
+ 0xc0b3, 0x1ff1,
+ 0xc0b7, 0x09a2,
+ 0xc0b8, 0x1ff5,
+ 0xc0c5, 0x09b0,
+ 0xc0cc, 0x2002,
+ 0xc0ce, 0x09b9,
+ 0xc0d4, 0x2004,
+ 0xc0d5, 0x09c0,
+ 0xc0d6, 0x2005,
+ 0xc0d7, 0x09c2,
+ 0xc0d8, 0x2006,
+ 0xc0d9, 0x09c4,
+ 0xc0dd, 0x2007,
+ 0xc0de, 0x09c9,
+ 0xc0e0, 0x2008,
+ 0xc0e1, 0x09cc,
+ 0xc0e9, 0x2009,
+ 0xc0ea, 0x09d5,
+ 0xc0eb, 0x200a,
+ 0xc0ed, 0x09d8,
+ 0xc0ef, 0x200c,
+ 0xc0f2, 0x09dd,
+ 0xc0f6, 0x200f,
+ 0xc0fb, 0x09e6,
+ 0xc1a1, 0x09ea,
+ 0xc1a4, 0x2014,
+ 0xc1a6, 0x09ef,
+ 0xc1a9, 0x2016,
+ 0xc1ae, 0x09f7,
+ 0xc1af, 0x201b,
+ 0xc1b9, 0x0a02,
+ 0xc1bd, 0x2025,
+ 0xc1bf, 0x0a08,
+ 0xc1c2, 0x2027,
+ 0xc1c3, 0x0a0c,
+ 0xc1c6, 0x2028,
+ 0xc1c7, 0x0a10,
+ 0xc1c9, 0x2029,
+ 0xc1ca, 0x0a13,
+ 0xc1cd, 0x202a,
+ 0xc1ce, 0x0a17,
+ 0xc1d4, 0x202b,
+ 0xc1d5, 0x0a1e,
+ 0xc1d9, 0x202c,
+ 0xc1dc, 0x0a25,
+ 0xc1de, 0x202f,
+ 0xc1df, 0x0a28,
+ 0xc1e4, 0x2030,
+ 0xc1e6, 0x0a2f,
+ 0xc1e9, 0x2032,
+ 0xc1ea, 0x0a33,
+ 0xc1eb, 0x2033,
+ 0xc1ed, 0x0a36,
+ 0xc1f3, 0x2035,
+ 0xc1f4, 0x0a3d,
+ 0xc1f5, 0x2036,
+ 0xc1f6, 0x0a3f,
+ 0xc1fa, 0x2037,
+ 0xc1fe, 0x0a47,
+ 0xc2a1, 0x0a48,
+ 0xc2a2, 0x203b,
+ 0xc2a9, 0x0a50,
+ 0xc2ab, 0x2042,
+ 0xc2b4, 0x0a5b,
+ 0xc2b8, 0x204b,
+ 0xc2b9, 0x0a60,
+ 0xc2bc, 0x204c,
+ 0xc2be, 0x0a65,
+ 0xc2bf, 0x204e,
+ 0xc2c0, 0x0a67,
+ 0xc2c1, 0x204f,
+ 0xc2c2, 0x0a69,
+ 0xc2c5, 0x2050,
+ 0xc2c8, 0x0a6f,
+ 0xc2cb, 0x2053,
+ 0xc2d1, 0x0a78,
+ 0xc2d2, 0x2059,
+ 0xc2d3, 0x0a7a,
+ 0xc2d5, 0x205a,
+ 0xc2dd, 0x0a84,
+ 0xc2de, 0x2062,
+ 0xc2e3, 0x0a8a,
+ 0xc2e6, 0x2067,
+ 0xc2e9, 0x0a90,
+ 0xc2ea, 0x206a,
+ 0xc2ef, 0x0a96,
+ 0xc2f0, 0x206f,
+ 0xc2f1, 0x0a98,
+ 0xc2f2, 0x2070,
+ 0xc2f6, 0x0a9d,
+ 0xc2f7, 0x2074,
+ 0xc2fb, 0x0aa2,
+ 0xc3a1, 0x2078,
+ 0xc3a2, 0x0aa7,
+ 0xc3aa, 0x2079,
+ 0xc3ab, 0x0ab0,
+ 0xc3ad, 0x207a,
+ 0xc3ae, 0x0ab3,
+ 0xc3b3, 0x207b,
+ 0xc3b4, 0x1df9,
+ 0xc3b5, 0x0aba,
+ 0xc3be, 0x207c,
+ 0xc3bf, 0x0ac4,
+ 0xc3c5, 0x207d,
+ 0xc3c8, 0x0acd,
+ 0xc3cc, 0x2080,
+ 0xc3cd, 0x0ad2,
+ 0xc3ce, 0x2081,
+ 0xc3cf, 0x0ad4,
+ 0xc3d5, 0x2082,
+ 0xc3d7, 0x0adc,
+ 0xc3d9, 0x2084,
+ 0xc3da, 0x0adf,
+ 0xc3e0, 0x2085,
+ 0xc3e1, 0x0ae6,
+ 0xc3e5, 0x2086,
+ 0xc3e6, 0x0aeb,
+ 0xc3ed, 0x2087,
+ 0xc3ee, 0x0af3,
+ 0xc3f0, 0x2088,
+ 0xc3f1, 0x0af6,
+ 0xc3f5, 0x2089,
+ 0xc3f7, 0x0afc,
+ 0xc3f9, 0x208b,
+ 0xc3fb, 0x0b00,
+ 0xc3fd, 0x208d,
+ 0xc3fe, 0x0b03,
+ 0xc4a1, 0x0b04,
+ 0xc4b1, 0x208e,
+ 0xc4b2, 0x0b15,
+ 0xc4b6, 0x208f,
+ 0xc4b7, 0x0b1a,
+ 0xc4c6, 0x2090,
+ 0xc4c7, 0x0b2a,
+ 0xc4c9, 0x2091,
+ 0xc4ca, 0x0b2d,
+ 0xc4d1, 0x2092,
+ 0xc4d2, 0x0b35,
+ 0xc4d3, 0x2093,
+ 0xc4d7, 0x0b3a,
+ 0xc4d9, 0x2097,
+ 0xc4da, 0x0b3d,
+ 0xc4e2, 0x2098,
+ 0xc4e3, 0x0b46,
+ 0xc4e5, 0x2099,
+ 0xc4e6, 0x0b49,
+ 0xc4ec, 0x209a,
+ 0xc4ed, 0x0b50,
+ 0xc4f0, 0x209b,
+ 0xc4f2, 0x0b55,
+ 0xc4f4, 0x209d,
+ 0xc4f5, 0x0b58,
+ 0xc4f6, 0x209e,
+ 0xc4f9, 0x0b5c,
+ 0xc4fb, 0x20a1,
+ 0xc4fd, 0x0b60,
+ 0xc4fe, 0x20a3,
+ 0xc5a1, 0x20a4,
+ 0xc5a3, 0x0b64,
+ 0xc5a5, 0x20a6,
+ 0xc5aa, 0x0b6b,
+ 0xc5b1, 0x20ab,
+ 0xc5b2, 0x0b73,
+ 0xc5b5, 0x20ac,
+ 0xc5b6, 0x0b77,
+ 0xc5b7, 0x20ad,
+ 0xc5ba, 0x0b7b,
+ 0xc5bb, 0x20b0,
+ 0xc5bc, 0x0b7d,
+ 0xc5bd, 0x20b1,
+ 0xc5be, 0x0b7f,
+ 0xc5cc, 0x20b2,
+ 0xc5cd, 0x0b8e,
+ 0xc5d3, 0x20b3,
+ 0xc5d4, 0x0b95,
+ 0xc5e2, 0x20b4,
+ 0xc5e3, 0x0ba4,
+ 0xc5e7, 0x20b5,
+ 0xc5e8, 0x0ba9,
+ 0xc5f4, 0x20b6,
+ 0xc5f5, 0x0bb6,
+ 0xc6a1, 0x0bc0,
+ 0xc6ad, 0x20b7,
+ 0xc6af, 0x0bce,
+ 0xc6b5, 0x20b9,
+ 0xc6b7, 0x0bd6,
+ 0xc6bb, 0x20bb,
+ 0xc6bc, 0x0bdb,
+ 0xc6be, 0x20bc,
+ 0xc6bf, 0x0bde,
+ 0xc6c0, 0x20bd,
+ 0xc6c1, 0x0be0,
+ 0xc6c3, 0x20be,
+ 0xc6c5, 0x0be4,
+ 0xc6cb, 0x20c0,
+ 0xc6ce, 0x0bed,
+ 0xc6d3, 0x20c3,
+ 0xc6d4, 0x0bf3,
+ 0xc6d7, 0x20c4,
+ 0xc6d8, 0x0bf7,
+ 0xc6ea, 0x20c5,
+ 0xc6ec, 0x0c0b,
+ 0xc6ef, 0x20c7,
+ 0xc6f0, 0x0c0f,
+ 0xc6f1, 0x20c8,
+ 0xc6f2, 0x0c11,
+ 0xc6f4, 0x20c9,
+ 0xc6f5, 0x0c14,
+ 0xc6f8, 0x20ca,
+ 0xc6f9, 0x0c18,
+ 0xc6fd, 0x20cb,
+ 0xc6fe, 0x0c1d,
+ 0xc7a1, 0x0c1e,
+ 0xc7a3, 0x20cc,
+ 0xc7a4, 0x0c21,
+ 0xc7a5, 0x20cd,
+ 0xc7a7, 0x0c24,
+ 0xc7a8, 0x20cf,
+ 0xc7aa, 0x0c27,
+ 0xc7ab, 0x20d1,
+ 0xc7ac, 0x0c29,
+ 0xc7ae, 0x20d2,
+ 0xc7b0, 0x0c2d,
+ 0xc7b3, 0x20d4,
+ 0xc7b6, 0x0c33,
+ 0xc7b9, 0x20d7,
+ 0xc7bb, 0x0c38,
+ 0xc7bd, 0x20d9,
+ 0xc7bf, 0x0c3c,
+ 0xc7c0, 0x20db,
+ 0xc7c1, 0x0c3e,
+ 0xc7c2, 0x20dc,
+ 0xc7c3, 0x0c40,
+ 0xc7c5, 0x20dd,
+ 0xc7c6, 0x0c43,
+ 0xc7c7, 0x20de,
+ 0xc7c9, 0x0c46,
+ 0xc7cc, 0x20e0,
+ 0xc7cd, 0x0c4a,
+ 0xc7cf, 0x20e1,
+ 0xc7d0, 0x0c4d,
+ 0xc7d4, 0x20e2,
+ 0xc7d6, 0x0c53,
+ 0xc7d7, 0x20e4,
+ 0xc7d8, 0x0c55,
+ 0xc7de, 0x20e5,
+ 0xc7df, 0x0c5c,
+ 0xc7e1, 0x20e6,
+ 0xc7e4, 0x0c61,
+ 0xc7ea, 0x20e9,
+ 0xc7ef, 0x0c6c,
+ 0xc7f7, 0x20ee,
+ 0xc7f9, 0x0c76,
+ 0xc7fb, 0x20f0,
+ 0xc7fc, 0x0c79,
+ 0xc7fd, 0x20f1,
+ 0xc7fe, 0x0c7b,
+ 0xc8a1, 0x0c7c,
+ 0xc8a3, 0x20f2,
+ 0xc8a4, 0x0c7f,
+ 0xc8a7, 0x20f3,
+ 0xc8a9, 0x0c84,
+ 0xc8b0, 0x20f5,
+ 0xc8b1, 0x0c8c,
+ 0xc8b5, 0x20f6,
+ 0xc8b6, 0x0c91,
+ 0xc8b7, 0x20f7,
+ 0xc8b8, 0x0c93,
+ 0xc8c3, 0x20f8,
+ 0xc8c7, 0x0ca2,
+ 0xc8c8, 0x20fc,
+ 0xc8c9, 0x0ca4,
+ 0xc8cd, 0x20fd,
+ 0xc8ce, 0x0ca9,
+ 0xc8cf, 0x20fe,
+ 0xc8d0, 0x0cab,
+ 0xc8d2, 0x20ff,
+ 0xc8d3, 0x0cae,
+ 0xc8d9, 0x2100,
+ 0xc8da, 0x0cb5,
+ 0xc8de, 0x2101,
+ 0xc8df, 0x0cba,
+ 0xc8ed, 0x2102,
+ 0xc8ee, 0x0cc9,
+ 0xc8f1, 0x2103,
+ 0xc8f4, 0x0ccf,
+ 0xc8f7, 0x2106,
+ 0xc8f9, 0x0cd4,
+ 0xc8fa, 0x2108,
+ 0xc8fb, 0x0cd6,
+ 0xc8fc, 0x2109,
+ 0xc8fd, 0x0cd8,
+ 0xc9a1, 0x210a,
+ 0xc9a2, 0x0cdb,
+ 0xc9a5, 0x210b,
+ 0xc9a6, 0x0cdf,
+ 0xc9a7, 0x210c,
+ 0xc9a9, 0x0ce2,
+ 0xc9ac, 0x210e,
+ 0xc9ad, 0x0ce6,
+ 0xc9b1, 0x210f,
+ 0xc9b2, 0x0ceb,
+ 0xc9b4, 0x2110,
+ 0xc9b5, 0x0cee,
+ 0xc9b8, 0x2111,
+ 0xc9ba, 0x0cf3,
+ 0xc9c1, 0x2113,
+ 0xc9c3, 0x0cfc,
+ 0xc9c4, 0x2115,
+ 0xc9c5, 0x0cfe,
+ 0xc9c9, 0x2116,
+ 0xc9ca, 0x0d03,
+ 0xc9cb, 0x2117,
+ 0xc9cc, 0x0d05,
+ 0xc9cd, 0x2118,
+ 0xc9ce, 0x0d07,
+ 0xc9d5, 0x2119,
+ 0xc9d6, 0x0d0f,
+ 0xc9dc, 0x211a,
+ 0xc9dd, 0x0d16,
+ 0xc9de, 0x211b,
+ 0xc9df, 0x0d18,
+ 0xc9e1, 0x211c,
+ 0xc9e2, 0x0d1b,
+ 0xc9e3, 0x211d,
+ 0xc9e4, 0x0d1d,
+ 0xc9e5, 0x211e,
+ 0xc9e6, 0x0d1f,
+ 0xc9e8, 0x211f,
+ 0xc9e9, 0x0d22,
+ 0xc9f0, 0x2120,
+ 0xc9f1, 0x0d2a,
+ 0xc9f3, 0x2121,
+ 0xc9f5, 0x0d2e,
+ 0xc9f6, 0x2123,
+ 0xc9f7, 0x0d30,
+ 0xc9f8, 0x2124,
+ 0xc9fa, 0x0d33,
+ 0xc9fe, 0x2126,
+ 0xcaa1, 0x0d38,
+ 0xcaa4, 0x2127,
+ 0xcaa7, 0x0d3e,
+ 0xcaa8, 0x212a,
+ 0xcaa9, 0x0d40,
+ 0xcaaa, 0x212b,
+ 0xcaac, 0x0d43,
+ 0xcab1, 0x212d,
+ 0xcab2, 0x0d49,
+ 0xcab4, 0x212e,
+ 0xcab7, 0x0d4e,
+ 0xcabb, 0x2131,
+ 0xcabc, 0x0d53,
+ 0xcac6, 0x2132,
+ 0xcac7, 0x0d5e,
+ 0xcaca, 0x2133,
+ 0xcacb, 0x0d62,
+ 0xcacd, 0x2134,
+ 0xcacf, 0x0d66,
+ 0xcad3, 0x2136,
+ 0xcad5, 0x0d6c,
+ 0xcad9, 0x2138,
+ 0xcada, 0x0d71,
+ 0xcade, 0x2139,
+ 0xcadf, 0x0d76,
+ 0xcae0, 0x213a,
+ 0xcae1, 0x0d78,
+ 0xcae4, 0x213b,
+ 0xcae5, 0x0d7c,
+ 0xcae9, 0x213c,
+ 0xcaeb, 0x0d82,
+ 0xcaf4, 0x213e,
+ 0xcaf6, 0x0d8d,
+ 0xcaf7, 0x2140,
+ 0xcaf8, 0x0d8f,
+ 0xcafa, 0x2141,
+ 0xcafb, 0x0d92,
+ 0xcafd, 0x2142,
+ 0xcafe, 0x0d95,
+ 0xcba1, 0x0d96,
+ 0xcba7, 0x2143,
+ 0xcba8, 0x0d9d,
+ 0xcbab, 0x2144,
+ 0xcbac, 0x0da1,
+ 0xcbad, 0x2145,
+ 0xcbae, 0x0da3,
+ 0xcbb3, 0x2146,
+ 0xcbb4, 0x0da9,
+ 0xcbb5, 0x2147,
+ 0xcbb7, 0x0dac,
+ 0xcbb8, 0x2149,
+ 0xcbb9, 0x0dae,
+ 0xcbbf, 0x214a,
+ 0xcbc0, 0x0db5,
+ 0xcbc7, 0x214b,
+ 0xcbc8, 0x0dbd,
+ 0xcbc9, 0x214c,
+ 0xcbcd, 0x0dc2,
+ 0xcbcf, 0x2150,
+ 0xcbd1, 0x0dc6,
+ 0xcbd3, 0x2152,
+ 0xcbd4, 0x0dc9,
+ 0xcbd5, 0x2153,
+ 0xcbd6, 0x0dcb,
+ 0xcbdf, 0x2154,
+ 0xcbe1, 0x0dd6,
+ 0xcbe4, 0x2156,
+ 0xcbe5, 0x0dda,
+ 0xcbe6, 0x2157,
+ 0xcbe8, 0x0ddd,
+ 0xcbea, 0x2159,
+ 0xcbeb, 0x0de0,
+ 0xcbef, 0x215a,
+ 0xcbf1, 0x0de6,
+ 0xcbf5, 0x215c,
+ 0xcbf7, 0x0dec,
+ 0xcbf8, 0x215e,
+ 0xcbf9, 0x0dee,
+ 0xcca1, 0x215f,
+ 0xcca3, 0x0df6,
+ 0xcca8, 0x2161,
+ 0xcca9, 0x0dfc,
+ 0xccac, 0x2162,
+ 0xccad, 0x0e00,
+ 0xccaf, 0x2163,
+ 0xccb4, 0x0e07,
+ 0xccb7, 0x2168,
+ 0xccb9, 0x0e0c,
+ 0xccbe, 0x216a,
+ 0xccbf, 0x0e12,
+ 0xccc0, 0x216b,
+ 0xccc1, 0x0e14,
+ 0xcccc, 0x216c,
+ 0xcccd, 0x0e20,
+ 0xccce, 0x216d,
+ 0xcccf, 0x0e22,
+ 0xccd0, 0x216e,
+ 0xccd1, 0x0e24,
+ 0xccd6, 0x216f,
+ 0xccd7, 0x0e2a,
+ 0xccda, 0x2170,
+ 0xccdb, 0x0e2e,
+ 0xccdc, 0x2171,
+ 0xccdd, 0x0e30,
+ 0xcce0, 0x2172,
+ 0xcce1, 0x0e34,
+ 0xcce2, 0x2173,
+ 0xcce3, 0x0e36,
+ 0xcce5, 0x2174,
+ 0xcce6, 0x0e39,
+ 0xccf5, 0x2175,
+ 0xccf6, 0x0e49,
+ 0xccf9, 0x2176,
+ 0xccfb, 0x0e4e,
+ 0xccfc, 0x2178,
+ 0xcda1, 0x0e52,
+ 0xcdad, 0x217b,
+ 0xcdae, 0x0e5f,
+ 0xcdb3, 0x217c,
+ 0xcdb4, 0x0e65,
+ 0xcdb7, 0x217d,
+ 0xcdb8, 0x0e69,
+ 0xcdbc, 0x217e,
+ 0xcdbd, 0x0e6e,
+ 0xcdbf, 0x217f,
+ 0xcdc0, 0x0e71,
+ 0xcdc5, 0x2180,
+ 0xcdc6, 0x0e77,
+ 0xcdc7, 0x2181,
+ 0xcdc8, 0x0e79,
+ 0xcdd2, 0x2182,
+ 0xcdd3, 0x0e84,
+ 0xcdd4, 0x2183,
+ 0xcdd7, 0x0e88,
+ 0xcddd, 0x2186,
+ 0xcdde, 0x0e8f,
+ 0xcde0, 0x2187,
+ 0xcde1, 0x0e92,
+ 0xcde4, 0x2188,
+ 0xcde6, 0x0e97,
+ 0xcde7, 0x218a,
+ 0xcde8, 0x0e99,
+ 0xcdf2, 0x218b,
+ 0xcdf3, 0x0ea4,
+ 0xcdf8, 0x218c,
+ 0xcdf9, 0x0eaa,
+ 0xcea1, 0x0eb0,
+ 0xcea4, 0x218d,
+ 0xcea6, 0x0eb5,
+ 0xcea7, 0x218f,
+ 0xcea8, 0x0eb7,
+ 0xceaa, 0x2190,
+ 0xceae, 0x0ebd,
+ 0xceb0, 0x2194,
+ 0xceb2, 0x0ec1,
+ 0xceb3, 0x2196,
+ 0xceb4, 0x0ec3,
+ 0xcebd, 0x2197,
+ 0xcebe, 0x0ecd,
+ 0xcec0, 0x2198,
+ 0xcec1, 0x0ed0,
+ 0xcec5, 0x2199,
+ 0xcec7, 0x0ed6,
+ 0xcec8, 0x219b,
+ 0xcec9, 0x0ed8,
+ 0xceca, 0x219c,
+ 0xcecb, 0x0eda,
+ 0xcece, 0x219d,
+ 0xced2, 0x0ee1,
+ 0xced8, 0x21a1,
+ 0xcedb, 0x0eea,
+ 0xcedc, 0x21a4,
+ 0xcedd, 0x0eec,
+ 0xcede, 0x21a5,
+ 0xcee0, 0x0eef,
+ 0xceeb, 0x21a7,
+ 0xceec, 0x0efb,
+ 0xceed, 0x21a8,
+ 0xceee, 0x0efd,
+ 0xcef1, 0x21a9,
+ 0xcef2, 0x0f01,
+ 0xcef3, 0x21aa,
+ 0xcef4, 0x0f03,
+ 0xcefd, 0x21ab,
+ 0xcfa1, 0x0f0e,
+ 0xcfae, 0x21ad,
+ 0xcfaf, 0x0f1c,
+ 0xcfb0, 0x21ae,
+ 0xcfb1, 0x0f1e,
+ 0xcfb3, 0x21af,
+ 0xcfb4, 0x0f21,
+ 0xcfb7, 0x21b0,
+ 0xcfb9, 0x0f26,
+ 0xcfba, 0x21b2,
+ 0xcfbb, 0x0f28,
+ 0xcfbd, 0x21b3,
+ 0xcfbe, 0x0f2b,
+ 0xcfbf, 0x21b4,
+ 0xcfc2, 0x0f2f,
+ 0xcfc5, 0x21b7,
+ 0xcfc6, 0x0f33,
+ 0xcfc7, 0x21b8,
+ 0xcfc8, 0x0f35,
+ 0xcfca, 0x21b9,
+ 0xcfcc, 0x0f39,
+ 0xcfcd, 0x21bb,
+ 0xcfcf, 0x0f3c,
+ 0xcfd0, 0x21bd,
+ 0xcfd1, 0x0f3e,
+ 0xcfd4, 0x21be,
+ 0xcfd9, 0x0f46,
+ 0xcfda, 0x21c3,
+ 0xcfdb, 0x0f48,
+ 0xcfdc, 0x21c4,
+ 0xcfdd, 0x0f4a,
+ 0xcfdf, 0x21c5,
+ 0xcfe0, 0x0f4d,
+ 0xcfe2, 0x21c6,
+ 0xcfe3, 0x0f50,
+ 0xcfe7, 0x21c7,
+ 0xcfe8, 0x0f55,
+ 0xcfea, 0x21c8,
+ 0xcfeb, 0x0f58,
+ 0xcfec, 0x21c9,
+ 0xcfed, 0x0f5a,
+ 0xcfee, 0x21ca,
+ 0xcfef, 0x0f5c,
+ 0xcff4, 0x21cb,
+ 0xcff5, 0x0f62,
+ 0xcff9, 0x21cc,
+ 0xcffb, 0x0f68,
+ 0xcffe, 0x21ce,
+ 0xd0a1, 0x0f6c,
+ 0xd0a5, 0x21cf,
+ 0xd0a6, 0x0f71,
+ 0xd0ad, 0x21d0,
+ 0xd0af, 0x0f7a,
+ 0xd0b2, 0x21d2,
+ 0xd0b5, 0x0f80,
+ 0xd0ba, 0x21d5,
+ 0xd0bc, 0x0f87,
+ 0xd0bf, 0x21d7,
+ 0xd0c0, 0x0f8b,
+ 0xd0c6, 0x21d8,
+ 0xd0c7, 0x0f92,
+ 0xd0cb, 0x21d9,
+ 0xd0cc, 0x0f97,
+ 0xd0e2, 0x21da,
+ 0xd0e3, 0x0fae,
+ 0xd0e5, 0x21db,
+ 0xd0e6, 0x0fb1,
+ 0xd0eb, 0x21dc,
+ 0xd0ec, 0x0fb7,
+ 0xd0ed, 0x21dd,
+ 0xd0ee, 0x0fb9,
+ 0xd0f7, 0x21de,
+ 0xd0fa, 0x0fc5,
+ 0xd0fc, 0x21e1,
+ 0xd0fd, 0x0fc8,
+ 0xd1a1, 0x21e2,
+ 0xd1a3, 0x0fcc,
+ 0xd1a4, 0x21e4,
+ 0xd1a5, 0x0fce,
+ 0xd1a7, 0x21e5,
+ 0xd1a8, 0x0fd1,
+ 0xd1ab, 0x21e6,
+ 0xd1ac, 0x0fd5,
+ 0xd1af, 0x21e7,
+ 0xd1b2, 0x0fdb,
+ 0xd1b5, 0x21ea,
+ 0xd1b8, 0x0fe1,
+ 0xd1b9, 0x21ed,
+ 0xd1ba, 0x0fe3,
+ 0xd1bb, 0x21ee,
+ 0xd1bd, 0x0fe6,
+ 0xd1c6, 0x21f0,
+ 0xd1c9, 0x0ff2,
+ 0xd1cb, 0x21f3,
+ 0xd1cc, 0x0ff5,
+ 0xd1ce, 0x21f4,
+ 0xd1d0, 0x0ff9,
+ 0xd1d5, 0x21f6,
+ 0xd1d7, 0x1000,
+ 0xd1de, 0x21f8,
+ 0xd1df, 0x1008,
+ 0xd1e1, 0x21f9,
+ 0xd1e3, 0x100c,
+ 0xd1e8, 0x21fb,
+ 0xd1ea, 0x1013,
+ 0xd1ec, 0x21fd,
+ 0xd1ed, 0x1016,
+ 0xd1ee, 0x21fe,
+ 0xd1f0, 0x1019,
+ 0xd1f1, 0x2200,
+ 0xd1f2, 0x101b,
+ 0xd1f4, 0x2201,
+ 0xd1f5, 0x101e,
+ 0xd1f7, 0x2202,
+ 0xd1fa, 0x1023,
+ 0xd2a1, 0x1028,
+ 0xd2a2, 0x2205,
+ 0xd2a3, 0x102a,
+ 0xd2a5, 0x2206,
+ 0xd2a6, 0x102d,
+ 0xd2a9, 0x2207,
+ 0xd2aa, 0x1031,
+ 0xd2af, 0x2208,
+ 0xd2b0, 0x1037,
+ 0xd2b3, 0x2209,
+ 0xd2b4, 0x103b,
+ 0xd2b5, 0x220a,
+ 0xd2b7, 0x103e,
+ 0xd2bd, 0x220c,
+ 0xd2be, 0x1045,
+ 0xd2bf, 0x220d,
+ 0xd2c0, 0x1047,
+ 0xd2c3, 0x220e,
+ 0xd2c4, 0x104b,
+ 0xd2c5, 0x220f,
+ 0xd2c6, 0x104d,
+ 0xd2c7, 0x2210,
+ 0xd2c8, 0x104f,
+ 0xd2cf, 0x2211,
+ 0xd2d0, 0x1057,
+ 0xd2d5, 0x2212,
+ 0xd2d6, 0x105d,
+ 0xd2da, 0x2213,
+ 0xd2db, 0x1062,
+ 0xd2e4, 0x2214,
+ 0xd2e6, 0x106d,
+ 0xd2e8, 0x2216,
+ 0xd2ec, 0x1073,
+ 0xd2ef, 0x221a,
+ 0xd2f0, 0x1077,
+ 0xd2f1, 0x221b,
+ 0xd2f2, 0x1079,
+ 0xd2f5, 0x221c,
+ 0xd2f6, 0x107d,
+ 0xd2f8, 0x221d,
+ 0xd2f9, 0x1080,
+ 0xd2fb, 0x221e,
+ 0xd2fc, 0x1083,
+ 0xd2fe, 0x221f,
+ 0xd3a1, 0x1086,
+ 0xd3a3, 0x2220,
+ 0xd3ad, 0x1092,
+ 0xd3ae, 0x222a,
+ 0xd3af, 0x1094,
+ 0xd3b1, 0x222b,
+ 0xd3b2, 0x1097,
+ 0xd3b4, 0x222c,
+ 0xd3b7, 0x109c,
+ 0xd3b8, 0x222f,
+ 0xd3b9, 0x109e,
+ 0xd3bb, 0x2230,
+ 0xd3bc, 0x10a1,
+ 0xd3c5, 0x2231,
+ 0xd3c6, 0x10ab,
+ 0xd3c7, 0x2232,
+ 0xd3c8, 0x10ad,
+ 0xd3ca, 0x2233,
+ 0xd3cd, 0x10b2,
+ 0xd3d5, 0x2236,
+ 0xd3d6, 0x10bb,
+ 0xd3df, 0x2237,
+ 0xd3e1, 0x10c6,
+ 0xd3e3, 0x2239,
+ 0xd3e4, 0x10c9,
+ 0xd3e6, 0x223a,
+ 0xd3e7, 0x10cc,
+ 0xd3eb, 0x223b,
+ 0xd3ed, 0x10d2,
+ 0xd3ef, 0x223d,
+ 0xd3f0, 0x10d5,
+ 0xd3f4, 0x223e,
+ 0xd3f5, 0x10da,
+ 0xd3fc, 0x223f,
+ 0xd3fd, 0x10e2,
+ 0xd3fe, 0x2240,
+ 0xd4a1, 0x10e4,
+ 0xd4a4, 0x2241,
+ 0xd4a5, 0x10e8,
+ 0xd4a6, 0x2242,
+ 0xd4a9, 0x10ec,
+ 0xd4af, 0x2245,
+ 0xd4b3, 0x10f6,
+ 0xd4b5, 0x2249,
+ 0xd4b7, 0x10fa,
+ 0xd4b8, 0x224b,
+ 0xd4b9, 0x10fc,
+ 0xd4bc, 0x224c,
+ 0xd4bd, 0x1100,
+ 0xd4be, 0x224d,
+ 0xd4c0, 0x1103,
+ 0xd4c4, 0x224f,
+ 0xd4c5, 0x1108,
+ 0xd4c6, 0x2250,
+ 0xd4c8, 0x110b,
+ 0xd4c9, 0x2252,
+ 0xd4ca, 0x110d,
+ 0xd4cb, 0x2253,
+ 0xd4cf, 0x1112,
+ 0xd4d3, 0x2257,
+ 0xd4d4, 0x1117,
+ 0xd4d8, 0x2258,
+ 0xd4d9, 0x111c,
+ 0xd4dc, 0x2259,
+ 0xd4e1, 0x1124,
+ 0xd4e4, 0x225e,
+ 0xd4e5, 0x1128,
+ 0xd4e6, 0x225f,
+ 0xd4e7, 0x112a,
+ 0xd4ee, 0x2260,
+ 0xd4ef, 0x1132,
+ 0xd4f0, 0x2261,
+ 0xd4f5, 0x1138,
+ 0xd4f9, 0x2266,
+ 0xd4fa, 0x113d,
+ 0xd4fe, 0x2267,
+ 0xd5a1, 0x2268,
+ 0xd5a3, 0x1144,
+ 0xd5a9, 0x226a,
+ 0xd5aa, 0x114b,
+ 0xd5ab, 0x226b,
+ 0xd5ac, 0x114d,
+ 0xd5ae, 0x226c,
+ 0xd5af, 0x1150,
+ 0xd5b1, 0x226d,
+ 0xd5b2, 0x1153,
+ 0xd5b5, 0x226e,
+ 0xd5b9, 0x115a,
+ 0xd5bb, 0x2272,
+ 0xd5bc, 0x115d,
+ 0xd5bd, 0x2273,
+ 0xd5be, 0x115f,
+ 0xd5c0, 0x2274,
+ 0xd5c1, 0x1162,
+ 0xd5c5, 0x2275,
+ 0xd5c6, 0x1167,
+ 0xd5c7, 0x2276,
+ 0xd5c8, 0x1169,
+ 0xd5ca, 0x2277,
+ 0xd5cc, 0x116d,
+ 0xd5cd, 0x2279,
+ 0xd5ce, 0x116f,
+ 0xd5d4, 0x227a,
+ 0xd5d5, 0x1176,
+ 0xd5dd, 0x227b,
+ 0xd5df, 0x1180,
+ 0xd5e0, 0x227d,
+ 0xd5e1, 0x1182,
+ 0xd5e2, 0x227e,
+ 0xd5e3, 0x1184,
+ 0xd5ea, 0x227f,
+ 0xd5ed, 0x118e,
+ 0xd5ef, 0x2282,
+ 0xd5f0, 0x1191,
+ 0xd5f2, 0x2283,
+ 0xd5f4, 0x1195,
+ 0xd5f7, 0x15eb,
+ 0xd5f8, 0x1199,
+ 0xd6a1, 0x2285,
+ 0xd6a5, 0x11a4,
+ 0xd6af, 0x2289,
+ 0xd6b1, 0x11b0,
+ 0xd6b4, 0x228b,
+ 0xd6b5, 0x11b4,
+ 0xd6bb, 0x228c,
+ 0xd6bc, 0x11bb,
+ 0xd6bd, 0x228d,
+ 0xd6be, 0x11bd,
+ 0xd6bf, 0x228e,
+ 0xd6c1, 0x11c0,
+ 0xd6c4, 0x2290,
+ 0xd6c5, 0x11c4,
+ 0xd6ca, 0x2291,
+ 0xd6cb, 0x11ca,
+ 0xd6cd, 0x2292,
+ 0xd6ce, 0x11cd,
+ 0xd6d3, 0x2293,
+ 0xd6d4, 0x11d3,
+ 0xd6d5, 0x2294,
+ 0xd6d8, 0x11d7,
+ 0xd6da, 0x2297,
+ 0xd6db, 0x11da,
+ 0xd6df, 0x2298,
+ 0xd6e0, 0x11df,
+ 0xd6e1, 0x2299,
+ 0xd6e2, 0x11e1,
+ 0xd6e5, 0x229a,
+ 0xd6e6, 0x11e5,
+ 0xd6e7, 0x229b,
+ 0xd6e9, 0x11e8,
+ 0xd6ee, 0x229d,
+ 0xd6f0, 0x11ef,
+ 0xd6f2, 0x229f,
+ 0xd6f3, 0x11f2,
+ 0xd6f5, 0x22a0,
+ 0xd6f7, 0x11f6,
+ 0xd6fc, 0x22a2,
+ 0xd7a1, 0x11fe,
+ 0xd7a4, 0x22a5,
+ 0xd7a5, 0x1202,
+ 0xd7a8, 0x22a6,
+ 0xd7ab, 0x1208,
+ 0xd7ac, 0x22a9,
+ 0xd7ad, 0x120a,
+ 0xd7ae, 0x22aa,
+ 0xd7b2, 0x120f,
+ 0xd7b3, 0x22ae,
+ 0xd7b5, 0x1212,
+ 0xd7b6, 0x22b0,
+ 0xd7b7, 0x1214,
+ 0xd7b8, 0x22b1,
+ 0xd7bd, 0x121a,
+ 0xd7c7, 0x22b6,
+ 0xd7c8, 0x1225,
+ 0xd7ca, 0x22b7,
+ 0xd7cb, 0x1228,
+ 0xd7d5, 0x22b8,
+ 0xd7d6, 0x1233,
+ 0xd7db, 0x22b9,
+ 0xd7df, 0x123c,
+ 0xd7e7, 0x22bd,
+ 0xd7e8, 0x1245,
+ 0xd7e9, 0x22be,
+ 0xd7eb, 0x1248,
+ 0xd8a1, 0x1257,
+ 0xd8c4, 0x22c0,
+ 0xd8c5, 0x127b,
+ 0xd8c7, 0x22c1,
+ 0xd8c8, 0x127e,
+ 0xd8c9, 0x22c2,
+ 0xd8ca, 0x1280,
+ 0xd8cc, 0x22c3,
+ 0xd8ce, 0x1284,
+ 0xd8d0, 0x22c5,
+ 0xd8d2, 0x1288,
+ 0xd8d3, 0x22c7,
+ 0xd8d4, 0x128a,
+ 0xd8d9, 0x22c8,
+ 0xd8da, 0x1290,
+ 0xd8db, 0x22c9,
+ 0xd8dd, 0x1293,
+ 0xd8f1, 0x22cb,
+ 0xd8f2, 0x12a8,
+ 0xd8f6, 0x22cc,
+ 0xd8f8, 0x12ae,
+ 0xd9a1, 0x12b5,
+ 0xd9ad, 0x22ce,
+ 0xd9ae, 0x12c2,
+ 0xd9af, 0x22cf,
+ 0xd9b0, 0x12c4,
+ 0xd9b1, 0x22d0,
+ 0xd9b4, 0x12c8,
+ 0xd9c7, 0x22d3,
+ 0xd9c8, 0x12dc,
+ 0xd9cd, 0x22d4,
+ 0xd9d1, 0x12e5,
+ 0xd9dd, 0x22d8,
+ 0xd9de, 0x12f2,
+ 0xd9e1, 0x22d9,
+ 0xd9e2, 0x12f6,
+ 0xd9e4, 0x22da,
+ 0xd9e5, 0x12f9,
+ 0xd9e6, 0x22db,
+ 0xd9e7, 0x12fb,
+ 0xd9ec, 0x22dc,
+ 0xd9ed, 0x1301,
+ 0xd9f4, 0x22dd,
+ 0xd9f6, 0x130a,
+ 0xdaa1, 0x1313,
+ 0xdaa5, 0x22df,
+ 0xdae0, 0x1352,
+ 0xdaea, 0x231a,
+ 0xdaeb, 0x135d,
+ 0xdaf7, 0x231b,
+ 0xdaf8, 0x136a,
+ 0xdaf9, 0x231c,
+ 0xdafa, 0x136c,
+ 0xdafe, 0x231d,
+ 0xdba1, 0x1371,
+ 0xdba3, 0x231e,
+ 0xdba4, 0x1374,
+ 0xdba6, 0x231f,
+ 0xdba7, 0x1377,
+ 0xdba9, 0x2320,
+ 0xdbab, 0x137b,
+ 0xdbbb, 0x2322,
+ 0xdbbc, 0x138c,
+ 0xdbbd, 0x2323,
+ 0xdbbe, 0x138e,
+ 0xdbcf, 0x2324,
+ 0xdbd0, 0x13a0,
+ 0xdbd1, 0x2325,
+ 0xdbd2, 0x13a2,
+ 0xdbdb, 0x2326,
+ 0xdbdc, 0x13ac,
+ 0xdbde, 0x2327,
+ 0xdbdf, 0x13af,
+ 0xdbe2, 0x2328,
+ 0xdbe3, 0x13b3,
+ 0xdbe4, 0x2329,
+ 0xdbe5, 0x13b5,
+ 0xdbeb, 0x232a,
+ 0xdbec, 0x13bc,
+ 0xdbee, 0x232b,
+ 0xdbef, 0x13bf,
+ 0xdbf1, 0x232c,
+ 0xdbf2, 0x13c2,
+ 0xdbf5, 0x232d,
+ 0xdbf8, 0x13c8,
+ 0xdca1, 0x13cf,
+ 0xdcbc, 0x2330,
+ 0xdcbd, 0x13eb,
+ 0xdcbf, 0x2331,
+ 0xdcc0, 0x13ee,
+ 0xdcc2, 0x2332,
+ 0xdcc3, 0x13f1,
+ 0xdcc8, 0x2333,
+ 0xdccb, 0x13f9,
+ 0xdcd1, 0x2336,
+ 0xdcd2, 0x1400,
+ 0xdcd7, 0x2337,
+ 0xdcd8, 0x1406,
+ 0xdce0, 0x2338,
+ 0xdce1, 0x140f,
+ 0xdce3, 0x2339,
+ 0xdce5, 0x1413,
+ 0xdce9, 0x233b,
+ 0xdceb, 0x1419,
+ 0xdcf1, 0x233d,
+ 0xdcf2, 0x1420,
+ 0xdcf6, 0x233e,
+ 0xdcf7, 0x1425,
+ 0xdcf9, 0x233f,
+ 0xdcfa, 0x1428,
+ 0xdcfd, 0x2340,
+ 0xdda1, 0x2342,
+ 0xdda2, 0x142e,
+ 0xdda3, 0x2343,
+ 0xdda8, 0x1434,
+ 0xddaa, 0x2348,
+ 0xddac, 0x1438,
+ 0xddb2, 0x234a,
+ 0xddb3, 0x143f,
+ 0xddb5, 0x234b,
+ 0xddb6, 0x1442,
+ 0xddba, 0x234c,
+ 0xddbc, 0x1448,
+ 0xddd3, 0x234e,
+ 0xddd4, 0x1460,
+ 0xdddb, 0x234f,
+ 0xdddc, 0x1468,
+ 0xddde, 0x2350,
+ 0xdddf, 0x146b,
+ 0xdde4, 0x2351,
+ 0xdde5, 0x1471,
+ 0xddeb, 0x2352,
+ 0xddec, 0x1478,
+ 0xddf1, 0x2353,
+ 0xddf2, 0x147e,
+ 0xddf6, 0x2354,
+ 0xddf8, 0x1484,
+ 0xddfc, 0x2356,
+ 0xddfd, 0x1489,
+ 0xddfe, 0x2357,
+ 0xdea1, 0x148b,
+ 0xdead, 0x2358,
+ 0xdeae, 0x1498,
+ 0xdeb4, 0x2359,
+ 0xdeb5, 0x149f,
+ 0xdeba, 0x235a,
+ 0xdebb, 0x14a5,
+ 0xdec6, 0x235b,
+ 0xdec7, 0x14b1,
+ 0xdecf, 0x235c,
+ 0xded0, 0x14ba,
+ 0xded1, 0x235d,
+ 0xded3, 0x14bd,
+ 0xded8, 0x235f,
+ 0xded9, 0x14c3,
+ 0xdee2, 0x2360,
+ 0xdee3, 0x14cd,
+ 0xdee8, 0x2361,
+ 0xdee9, 0x14d3,
+ 0xdeec, 0x2362,
+ 0xdeed, 0x14d7,
+ 0xdef3, 0x2363,
+ 0xdef4, 0x14de,
+ 0xdefc, 0x2364,
+ 0xdefd, 0x14e7,
+ 0xdfa1, 0x14e9,
+ 0xdfa2, 0x2365,
+ 0xdfa4, 0x14ec,
+ 0xdfa5, 0x2367,
+ 0xdfa6, 0x14ee,
+ 0xdfb4, 0x2368,
+ 0xdfb5, 0x14fd,
+ 0xdfbc, 0x2369,
+ 0xdfbe, 0x1506,
+ 0xdfbf, 0x236b,
+ 0xdfc0, 0x1508,
+ 0xdfc2, 0x236c,
+ 0xdfc4, 0x150c,
+ 0xdfcc, 0x236e,
+ 0xdfcd, 0x1515,
+ 0xdfd0, 0x236f,
+ 0xdfd1, 0x1519,
+ 0xdfd5, 0x2370,
+ 0xdfd6, 0x151e,
+ 0xdfd8, 0x2371,
+ 0xdfda, 0x1522,
+ 0xdfdc, 0x2373,
+ 0xdfdd, 0x1525,
+ 0xdfe0, 0x2374,
+ 0xdfe1, 0x1529,
+ 0xdfe2, 0x2375,
+ 0xdfe3, 0x152b,
+ 0xdfe6, 0x2376,
+ 0xdfe7, 0x152f,
+ 0xdfe9, 0x2377,
+ 0xdfea, 0x1532,
+ 0xdfeb, 0x2378,
+ 0xdfec, 0x1534,
+ 0xdfef, 0x2379,
+ 0xdff0, 0x1538,
+ 0xdff5, 0x237a,
+ 0xdff6, 0x153e,
+ 0xdff9, 0x237b,
+ 0xdffa, 0x1542,
+ 0xe0a1, 0x1547,
+ 0xe0b6, 0x237c,
+ 0xe0b8, 0x155e,
+ 0xe0bf, 0x237e,
+ 0xe0c0, 0x1566,
+ 0xe0c8, 0x237f,
+ 0xe0c9, 0x156f,
+ 0xe0ce, 0x2380,
+ 0xe0cf, 0x1575,
+ 0xe0d3, 0x2381,
+ 0xe0d4, 0x157a,
+ 0xe0e0, 0x2382,
+ 0xe0e1, 0x1587,
+ 0xe0f0, 0x2383,
+ 0xe0f1, 0x1597,
+ 0xe0f8, 0x2384,
+ 0xe0f9, 0x159f,
+ 0xe0fc, 0x2385,
+ 0xe1a1, 0x15a5,
+ 0xe1ab, 0x2388,
+ 0xe1ac, 0x15b0,
+ 0xe1ad, 0x2389,
+ 0xe1ae, 0x15b2,
+ 0xe1b0, 0x238a,
+ 0xe1b1, 0x15b5,
+ 0xe1b4, 0x238b,
+ 0xe1b5, 0x15b9,
+ 0xe1bb, 0x238c,
+ 0xe1bc, 0x15c0,
+ 0xe1bd, 0x238d,
+ 0xe1be, 0x15c2,
+ 0xe1c0, 0x238e,
+ 0xe1c2, 0x15c6,
+ 0xe1c9, 0x2390,
+ 0xe1ca, 0x15ce,
+ 0xe1d0, 0x2391,
+ 0xe1d1, 0x15d5,
+ 0xe1db, 0x2392,
+ 0xe1dc, 0x15e0,
+ 0xe1e1, 0x07aa,
+ 0xe1e2, 0x2393,
+ 0xe1e3, 0x15e7,
+ 0xe1e7, 0x1198,
+ 0xe1e8, 0x15ec,
+ 0xe1ee, 0x2394,
+ 0xe1f0, 0x15f4,
+ 0xe1f6, 0x2396,
+ 0xe1f7, 0x15fb,
+ 0xe1f8, 0x2397,
+ 0xe1f9, 0x15fd,
+ 0xe1fd, 0x2398,
+ 0xe1fe, 0x1602,
+ 0xe2a1, 0x1603,
+ 0xe2a4, 0x2399,
+ 0xe2a5, 0x1607,
+ 0xe2a8, 0x239a,
+ 0xe2a9, 0x160b,
+ 0xe2bb, 0x239b,
+ 0xe2c5, 0x10c5,
+ 0xe2c6, 0x23a5,
+ 0xe2cf, 0x1631,
+ 0xe2d0, 0x23ae,
+ 0xe2d1, 0x1633,
+ 0xe2d9, 0x23af,
+ 0xe2da, 0x163c,
+ 0xe2e3, 0x23b0,
+ 0xe2e5, 0x1647,
+ 0xe2e6, 0x23b2,
+ 0xe2e7, 0x1649,
+ 0xe2e9, 0x23b3,
+ 0xe2ec, 0x164e,
+ 0xe2f8, 0x23b6,
+ 0xe2f9, 0x165b,
+ 0xe2fa, 0x23b7,
+ 0xe2fe, 0x1660,
+ 0xe3a1, 0x1661,
+ 0xe3a2, 0x23bb,
+ 0xe3a3, 0x1663,
+ 0xe3a5, 0x23bc,
+ 0xe3a6, 0x1666,
+ 0xe3ab, 0x23bd,
+ 0xe3ac, 0x166c,
+ 0xe3b4, 0x23be,
+ 0xe3b5, 0x1675,
+ 0xe3c5, 0x23bf,
+ 0xe3dc, 0x169c,
+ 0xe3e3, 0x23d6,
+ 0xe3e4, 0x16a4,
+ 0xe3ed, 0x23d7,
+ 0xe3ee, 0x16ae,
+ 0xe3f1, 0x23d8,
+ 0xe3f3, 0x16b3,
+ 0xe3f8, 0x23da,
+ 0xe3f9, 0x16b9,
+ 0xe3fe, 0x23db,
+ 0xe4a1, 0x16bf,
+ 0xe4a4, 0x23dc,
+ 0xe4a6, 0x16c4,
+ 0xe4ab, 0x23de,
+ 0xe4ac, 0x16ca,
+ 0xe4af, 0x23df,
+ 0xe4b2, 0x16d0,
+ 0xe4b5, 0x23e2,
+ 0xe4b7, 0x16d5,
+ 0xe4c2, 0x23e4,
+ 0xe4c3, 0x16e1,
+ 0xe4c5, 0x23e5,
+ 0xe4c6, 0x16e4,
+ 0xe4c9, 0x23e6,
+ 0xe4ca, 0x16e8,
+ 0xe4d9, 0x23e7,
+ 0xe4da, 0x16f8,
+ 0xe4dc, 0x23e8,
+ 0xe4dd, 0x16fb,
+ 0xe4de, 0x23e9,
+ 0xe4df, 0x16fd,
+ 0xe4e4, 0x23ea,
+ 0xe4e5, 0x1703,
+ 0xe4eb, 0x23eb,
+ 0xe4ed, 0x170b,
+ 0xe4f2, 0x23ed,
+ 0xe4f3, 0x1711,
+ 0xe4fe, 0x23ee,
+ 0xe5a1, 0x171d,
+ 0xe5b0, 0x23ef,
+ 0xe5b1, 0x172d,
+ 0xe5b9, 0x23f0,
+ 0xe5ba, 0x1736,
+ 0xe5c7, 0x23f1,
+ 0xe5c8, 0x1744,
+ 0xe5c9, 0x23f2,
+ 0xe5ca, 0x1746,
+ 0xe5ce, 0x23f3,
+ 0xe5cf, 0x174b,
+ 0xe5f0, 0x23f4,
+ 0xe5f1, 0x176d,
+ 0xe5f2, 0x23f5,
+ 0xe5f3, 0x176f,
+ 0xe5fc, 0x23f6,
+ 0xe5fe, 0x177a,
+ 0xe6a1, 0x177b,
+ 0xe6a3, 0x23f8,
+ 0xe6a4, 0x177e,
+ 0xe6ab, 0x23f9,
+ 0xe6ad, 0x1787,
+ 0xe6ae, 0x23fb,
+ 0xe6af, 0x1789,
+ 0xe6b4, 0x23fc,
+ 0xe6b6, 0x1790,
+ 0xe6bf, 0x23fe,
+ 0xe6c0, 0x179a,
+ 0xe6c8, 0x23ff,
+ 0xe6ca, 0x17a4,
+ 0xe6cd, 0x2401,
+ 0xe6ce, 0x17a8,
+ 0xe6e0, 0x2402,
+ 0xe7a1, 0x2421,
+ 0xe7db, 0x1813,
+ 0xe7e1, 0x245b,
+ 0xe7e3, 0x181b,
+ 0xe7e7, 0x245d,
+ 0xe7e8, 0x1820,
+ 0xe7ef, 0x245e,
+ 0xe7f0, 0x1828,
+ 0xe7f4, 0x245f,
+ 0xe7f7, 0x182f,
+ 0xe8a1, 0x1837,
+ 0xe8a8, 0x2462,
+ 0xe8a9, 0x183f,
+ 0xe8ac, 0x2463,
+ 0xe8ad, 0x1843,
+ 0xe8b6, 0x2464,
+ 0xe8b7, 0x184d,
+ 0xe8b8, 0x2465,
+ 0xe8bb, 0x1851,
+ 0xe8bf, 0x2468,
+ 0xe8c1, 0x1857,
+ 0xe8c5, 0x246a,
+ 0xe8c6, 0x185c,
+ 0xe8c7, 0x246b,
+ 0xe8ca, 0x1860,
+ 0xe8ce, 0x246e,
+ 0xe8cf, 0x1865,
+ 0xe8d0, 0x246f,
+ 0xe8d1, 0x1867,
+ 0xe8d3, 0x2470,
+ 0xe8d4, 0x186a,
+ 0xe8dd, 0x2471,
+ 0xe8de, 0x1874,
+ 0xe8df, 0x2472,
+ 0xe8e0, 0x1876,
+ 0xe8e2, 0x2473,
+ 0xe8e4, 0x187a,
+ 0xe8e5, 0x2475,
+ 0xe8e6, 0x187c,
+ 0xe8e7, 0x2476,
+ 0xe8e8, 0x187e,
+ 0xe8eb, 0x2477,
+ 0xe8ec, 0x1882,
+ 0xe8ed, 0x2478,
+ 0xe8ee, 0x1884,
+ 0xe8ef, 0x2479,
+ 0xe8f0, 0x1886,
+ 0xe8f9, 0x247a,
+ 0xe8fa, 0x1890,
+ 0xe8fc, 0x247b,
+ 0xe8fe, 0x1894,
+ 0xe9a1, 0x247d,
+ 0xe9a2, 0x1896,
+ 0xe9ad, 0x247e,
+ 0xe9ae, 0x18a2,
+ 0xe9b4, 0x247f,
+ 0xe9b6, 0x18aa,
+ 0xe9b7, 0x2481,
+ 0xe9b8, 0x18ac,
+ 0xe9c4, 0x2482,
+ 0xe9c5, 0x18b9,
+ 0xe9c6, 0x2483,
+ 0xe9c7, 0x18bb,
+ 0xe9c9, 0x2484,
+ 0xe9ca, 0x18be,
+ 0xe9d6, 0x2485,
+ 0xe9d7, 0x18cb,
+ 0xe9da, 0x2486,
+ 0xe9db, 0x18cf,
+ 0xe9e4, 0x2487,
+ 0xe9e5, 0x18d9,
+ 0xe9e6, 0x2488,
+ 0xe9e8, 0x18dc,
+ 0xe9e9, 0x248a,
+ 0xe9ea, 0x18de,
+ 0xe9eb, 0x248b,
+ 0xe9ec, 0x18e0,
+ 0xe9ed, 0x248c,
+ 0xeaa1, 0x249e,
+ 0xeaa6, 0x18f8,
+ 0xeaa7, 0x24a3,
+ 0xeaa9, 0x18fb,
+ 0xeab1, 0x24a5,
+ 0xeab2, 0x1904,
+ 0xeabc, 0x24a6,
+ 0xeabd, 0x190f,
+ 0xeaca, 0x24a7,
+ 0xeacb, 0x191d,
+ 0xeacd, 0x24a8,
+ 0xeace, 0x1920,
+ 0xead3, 0x24a9,
+ 0xead4, 0x1926,
+ 0xeada, 0x24aa,
+ 0xeaf0, 0x1942,
+ 0xeba1, 0x1951,
+ 0xeba7, 0x24c0,
+ 0xeba8, 0x1958,
+ 0xebaa, 0x24c1,
+ 0xebab, 0x195b,
+ 0xebb2, 0x24c2,
+ 0xebb3, 0x1963,
+ 0xebb9, 0x24c3,
+ 0xebba, 0x196a,
+ 0xebca, 0x24c4,
+ 0xebcc, 0x197c,
+ 0xebcd, 0x24c6,
+ 0xebce, 0x197e,
+ 0xebd6, 0x24c7,
+ 0xebd7, 0x1987,
+ 0xebda, 0x24c8,
+ 0xebdb, 0x198b,
+ 0xebe1, 0x24c9,
+ 0xebe2, 0x1992,
+ 0xebf7, 0x24ca,
+ 0xebf8, 0x19a8,
+ 0xeca1, 0x19af,
+ 0xeca3, 0x24cb,
+ 0xeca4, 0x19b2,
+ 0xeca9, 0x24cc,
+ 0xecaf, 0x19bd,
+ 0xecb1, 0x24d2,
+ 0xecb2, 0x19c0,
+ 0xecb4, 0x24d3,
+ 0xecb6, 0x19c4,
+ 0xecbe, 0x24d5,
+ 0xecc0, 0x19ce,
+ 0xecc1, 0x24d7,
+ 0xecc2, 0x19d0,
+ 0xecc7, 0x24d8,
+ 0xecc8, 0x19d6,
+ 0xeccb, 0x24d9,
+ 0xeccc, 0x19da,
+ 0xece2, 0x24da,
+ 0xece3, 0x19f1,
+ 0xecf2, 0x24db,
+ 0xecf3, 0x1a01,
+ 0xecf5, 0x24dc,
+ 0xecf6, 0x1a04,
+ 0xecf8, 0x24dd,
+ 0xecf9, 0x1a07,
+ 0xeda1, 0x24de,
+ 0xeda2, 0x1a0e,
+ 0xeda8, 0x24df,
+ 0xeda9, 0x1a15,
+ 0xedaf, 0x24e0,
+ 0xedb1, 0x1a1d,
+ 0xedb4, 0x24e2,
+ 0xedb5, 0x1a21,
+ 0xedb6, 0x24e3,
+ 0xedb7, 0x1a23,
+ 0xedb8, 0x24e4,
+ 0xedb9, 0x1a25,
+ 0xedba, 0x24e5,
+ 0xedbb, 0x1a27,
+ 0xedbf, 0x24e6,
+ 0xedc0, 0x1a2c,
+ 0xedc2, 0x24e7,
+ 0xedc4, 0x1a30,
+ 0xedcc, 0x24e9,
+ 0xedce, 0x1a3a,
+ 0xedd3, 0x24eb,
+ 0xedd4, 0x1a40,
+ 0xedd7, 0x24ec,
+ 0xedd8, 0x1a44,
+ 0xede8, 0x24ed,
+ 0xede9, 0x1a55,
+ 0xedee, 0x24ee,
+ 0xedef, 0x1a5b,
+ 0xedf9, 0x24ef,
+ 0xedfb, 0x1a67,
+ 0xeea1, 0x1a6b,
+ 0xeebc, 0x24f1,
+ 0xeebd, 0x1a87,
+ 0xeebf, 0x24f2,
+ 0xeec0, 0x1a8a,
+ 0xeec4, 0x24f3,
+ 0xefa1, 0x252e,
+ 0xeff2, 0x1b1a,
+ 0xf0a1, 0x1b27,
+ 0xf0a3, 0x257f,
+ 0xf0a4, 0x1b2a,
+ 0xf0af, 0x2580,
+ 0xf0da, 0x1b60,
+ 0xf0dc, 0x25ab,
+ 0xf0de, 0x1b64,
+ 0xf0df, 0x25ad,
+ 0xf0e0, 0x1b66,
+ 0xf0e9, 0x25ae,
+ 0xf0ea, 0x1b70,
+ 0xf0ec, 0x25af,
+ 0xf0ed, 0x1b73,
+ 0xf0ef, 0x25b0,
+ 0xf0f0, 0x1b76,
+ 0xf0f7, 0x25b1,
+ 0xf0f8, 0x1b7e,
+ 0xf0f9, 0x25b2,
+ 0xf0fa, 0x1b80,
+ 0xf0fc, 0x25b3,
+ 0xf0fd, 0x1b83,
+ 0xf1a1, 0x1b85,
+ 0xf1a8, 0x25b4,
+ 0xf1a9, 0x1b8d,
+ 0xf1ab, 0x25b5,
+ 0xf1ac, 0x1b90,
+ 0xf1ae, 0x25b6,
+ 0xf1af, 0x1b93,
+ 0xf1b2, 0x25b7,
+ 0xf1b3, 0x1b97,
+ 0xf1bc, 0x25b8,
+ 0xf1bd, 0x1ba1,
+ 0xf1c0, 0x25b9,
+ 0xf1c1, 0x1ba5,
+ 0xf1c9, 0x25ba,
+ 0xf1ca, 0x1bae,
+ 0xf1cd, 0x25bb,
+ 0xf1ce, 0x1bb2,
+ 0xf1cf, 0x25bc,
+ 0xf1d1, 0x1bb5,
+ 0xf1da, 0x25be,
+ 0xf1db, 0x1bbf,
+ 0xf1dc, 0x25bf,
+ 0xf1dd, 0x1bc1,
+ 0xf1e4, 0x25c0,
+ 0xf1e5, 0x1bc9,
+ 0xf1ec, 0x25c1,
+ 0xf1ed, 0x1bd1,
+ 0xf1ef, 0x25c2,
+ 0xf1f0, 0x1bd4,
+ 0xf1f7, 0x25c3,
+ 0xf1f8, 0x1bdc,
+ 0xf1f9, 0x25c4,
+ 0xf1fa, 0x1bde,
+ 0xf1fc, 0x25c5,
+ 0xf2a1, 0x25c8,
+ 0xf2ae, 0x1bf0,
+ 0xf2b1, 0x25d5,
+ 0xf2b3, 0x1bf5,
+ 0xf2b9, 0x25d7,
+ 0xf2ba, 0x1bfc,
+ 0xf2c3, 0x25d8,
+ 0xf2c4, 0x1c06,
+ 0xf2c9, 0x25d9,
+ 0xf2ca, 0x1c0c,
+ 0xf2cc, 0x25da,
+ 0xf2ce, 0x1c10,
+ 0xf2cf, 0x25dc,
+ 0xf2d0, 0x1c12,
+ 0xf2d3, 0x25dd,
+ 0xf2d4, 0x1c16,
+ 0xf2e5, 0x25de,
+ 0xf2e6, 0x1c28,
+ 0xf2ee, 0x25df,
+ 0xf2ef, 0x1c31,
+ 0xf2f7, 0x25e0,
+ 0xf2f8, 0x1c3a,
+ 0xf2fd, 0x25e1,
+ 0xf2fe, 0x1c40,
+ 0xf3a1, 0x1c41,
+ 0xf3bf, 0x25e2,
+ 0xf3c0, 0x1c60,
+ 0xf3c6, 0x25e3,
+ 0xf3c7, 0x1c67,
+ 0xf3c8, 0x25e4,
+ 0xf3c9, 0x1c69,
+ 0xf3d6, 0x25e5,
+ 0xf3d7, 0x1c77,
+ 0xf3d9, 0x25e6,
+ 0xf3da, 0x1c7a,
+ 0xf3e5, 0x25e7,
+ 0xf3e7, 0x1c87,
+ 0xf3ea, 0x25e9,
+ 0xf3eb, 0x1c8b,
+ 0xf3ec, 0x25ea,
+ 0xf3ed, 0x1c8d,
+ 0xf3ef, 0x25eb,
+ 0xf3f0, 0x1c90,
+ 0xf3f1, 0x25ec,
+ 0xf3f2, 0x1c92,
+ 0xf3fd, 0x25ed,
+ 0xf3fe, 0x1c9e,
+ 0xf4a1, 0x1c9f,
+ 0xf4a5, 0x25ee,
+ 0xf4a6, 0x1ca4,
+ 0xf4af, 0x25ef,
+ 0xf4b0, 0x1cae,
+ 0xf4b5, 0x25f0,
+ 0xf4b6, 0x1cb4,
+ 0xf4c1, 0x25f1,
+ 0xf4c2, 0x1cc0,
+ 0xf4c7, 0x25f2,
+ 0xf4c8, 0x1cc6,
+ 0xf4cf, 0x25f3,
+ 0xf4d1, 0x1ccf,
+ 0xf4d6, 0x25f5,
+ 0xf4d7, 0x1cd5,
+ 0xf4ea, 0x25f6,
+ 0xf4eb, 0x1ce9,
+ 0xf4ef, 0x25f7,
+ 0xf4f0, 0x1cee,
+ 0xf4f5, 0x25f8,
+ 0xf4f6, 0x1cf4,
+ 0xf5a1, 0x1cfd,
+ 0xf5a6, 0x25f9,
+ 0xf5a8, 0x1d04,
+ 0xf5ba, 0x25fb,
+ 0xf5bc, 0x1d18,
+ 0xf5c4, 0x25fd,
+ 0xf5c5, 0x1d21,
+ 0xf5c8, 0x25fe,
+ 0xf5c9, 0x1d25,
+ 0xf5ce, 0x25ff,
+ 0xf5d0, 0x1d2c,
+ 0xf5d1, 0x2601,
+ 0xf5d3, 0x1d2f,
+ 0xf5d9, 0x2603,
+ 0xf5da, 0x1d36,
+ 0xf5dc, 0x2604,
+ 0xf5dd, 0x1d39,
+ 0xf5e6, 0x2605,
+ 0xf5e8, 0x1d44,
+ 0xf5ef, 0x2607,
+ 0xf5f0, 0x1d4c,
+ 0xf5f2, 0x2608,
+ 0xf5f3, 0x1d4f,
+ 0xf5fc, 0x2609,
+ 0xf5fd, 0x1d59,
+ 0xf6a1, 0x1d5b,
+ 0xf6a3, 0x260a,
+ 0xf6a4, 0x1d5e,
+ 0xf6a6, 0x260b,
+ 0xf6a7, 0x1d61,
+ 0xf6a8, 0x260c,
+ 0xf6a9, 0x1d63,
+ 0xf6ab, 0x260d,
+ 0xf6ac, 0x1d66,
+ 0xf6b0, 0x260e,
+ 0xf6b1, 0x1d6b,
+ 0xf6b3, 0x260f,
+ 0xf6bf, 0x1d79,
+ 0xf6c5, 0x261b,
+ 0xf6c6, 0x1d80,
+ 0xf6c7, 0x261c,
+ 0xf6c8, 0x1d82,
+ 0xf6c9, 0x261d,
+ 0xf6ca, 0x1d84,
+ 0xf6cf, 0x261e,
+ 0xf7a1, 0x264e,
+ 0xf7b0, 0x1dc8,
+ 0xf7b2, 0x265d,
+ 0xf7b4, 0x1dcc,
+ 0xf7b5, 0x265f,
+ 0xf7b6, 0x1dce,
+ 0xf7bd, 0x2660,
+ 0xf7be, 0x1dd6,
+ 0xf7c3, 0x2661,
+ 0xf7c4, 0x1ddc,
+ 0xf7c5, 0x2662,
+ 0xf7c7, 0x1ddf,
+ 0xf7ca, 0x2664,
+ 0xf7cc, 0x1de4,
+ 0xf7cf, 0x2666,
+ 0xf7d1, 0x1de9,
+ 0xf7de, 0x2668,
+ 0xf7df, 0x1df7,
+ 0xf7e1, 0x0ab9,
+ 0xf7e2, 0x1dfa,
+ 0xf7f2, 0x2669,
+ 0xf7f3, 0x1e0b,
+ 0xf7f5, 0x266a,
+ 0xf7f6, 0x1e0e,
+ 0xf8a1, 0x266b,
+ 0xf8a7, 0x04cc,
+ 0xf8a8, 0x050a,
+ 0xf8a9, 0x0518,
+ 0xf8aa, 0x2671,
+ 0xf8ac, 0x0594,
+ 0xf8ad, 0x05ce,
+ 0xf8ae, 0x2673,
+ 0xf8af, 0x05f6,
+ 0xf8b0, 0x2674,
+ 0xf8b2, 0x0653,
+ 0xf8b3, 0x067e,
+ 0xf8b4, 0x2676,
+ 0xf8b5, 0x06c4,
+ 0xf8b6, 0x2677,
+ 0xf8b8, 0x073c,
+ 0xf8b9, 0x2679,
+ 0xf8bb, 0x07c3,
+ 0xf8bc, 0x267b,
+ 0xf8c0, 0x082b,
+ 0xf8c1, 0x267f,
+ 0xf8c2, 0x084e,
+ 0xf8c3, 0x0869,
+ 0xf8c4, 0x2680,
+ 0xf8c6, 0x090c,
+ 0xf8c7, 0x2682,
+ 0xf8c9, 0x0971,
+ 0xf8ca, 0x2684,
+ 0xf8cb, 0x099a,
+ 0xf8cd, 0x2685,
+ 0xf8ce, 0x09da,
+ 0xf8cf, 0x2686,
+ 0xf8d0, 0x09fa,
+ 0xf8d1, 0x2687,
+ 0xf8dc, 0x0bda,
+ 0xf8dd, 0x0bdd,
+ 0xf8de, 0x0bea,
+ 0xf8df, 0x0bec,
+ 0xf8e0, 0x0bf2,
+ 0xf8e1, 0x2692,
+ 0xf8e6, 0x0c92,
+ 0xf8e7, 0x0d1a,
+ 0xf8e8, 0x0d8c,
+ 0xf8e9, 0x0dbe,
+ 0xf8ea, 0x2697,
+ 0xf8eb, 0x0dfb,
+ 0xf8ec, 0x2698,
+ 0xf8ef, 0x0e70,
+ 0xf8f0, 0x269b,
+ 0xf8f1, 0x0ea3,
+ 0xf8f2, 0x269c,
+ 0xf8f8, 0x103d,
+ 0xf8f9, 0x10d9,
+ 0xf8fa, 0x26a2,
+ 0xf8fc, 0x10fb,
+ 0xf8fd, 0x1109,
+ 0xf8fe, 0x26a4,
+ 0xf9a1, 0x11a1,
+ 0xf9a2, 0x26a5,
+ 0xf9a3, 0x11ba,
+ 0xf9a4, 0x26a6,
+ 0xf9a6, 0x11d5,
+ 0xf9a7, 0x26a8,
+ 0xf9a8, 0x11fd,
+ 0xf9a9, 0x1219,
+ 0xa1a2, 0x023f,
+ 0xa1a3, 0x023e,
+ 0xa1aa, 0x0256,
+ 0xa1ab, 0x1e18,
+ 0xa1ad, 0x0257,
+ 0xa1b2, 0x0246,
+ 0xa1fe, 0x1e1a,
+ 0xa3a1, 0x0242,
+ 0xa3a8, 0x0244,
+ 0xa3ac, 0x023d,
+ 0xa3ae, 0x1e1b,
+ 0xa3ba, 0x0240,
+ 0xa3bd, 0x1e1c,
+ 0xa3bf, 0x0243,
+ 0xa3db, 0x1e1d,
+ 0xa3dd, 0x1e1e,
+ 0xa3df, 0x0258,
+ 0xa3fb, 0x0254,
+ 0xa3fd, 0x0255,
+ 0xa3fe, 0x1e1f,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 gb12GBTpcEUCVEnc16 = {
+ 1,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
+ 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010,
+ 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018,
+ 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020,
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028,
+ 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030,
+ 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038,
+ 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040,
+ 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048,
+ 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050,
+ 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
+ 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0000,
+ 0x1e20, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1e21, 0x1e22, 0x1e23 },
+ gb12GBTpcEUCVMap2, 2303
+};
+
+static Gushort gb12GBpcEUCHMap2[180] = {
+ 0x0000, 0x0000,
+ 0xa1a1, 0x0060,
+ 0xa2b1, 0x00be,
+ 0xa2e5, 0x00f0,
+ 0xa2f1, 0x00fa,
+ 0xa3a1, 0x0106,
+ 0xa4a1, 0x0164,
+ 0xa5a1, 0x01b7,
+ 0xa6a1, 0x020d,
+ 0xa6c1, 0x0225,
+ 0xa7a1, 0x025a,
+ 0xa7d1, 0x027b,
+ 0xa8a1, 0x029c,
+ 0xa8c5, 0x02bc,
+ 0xa9a4, 0x02e2,
+ 0xaaa1, 0x032e,
+ 0xaba1, 0x038c,
+ 0xb0a1, 0x03ac,
+ 0xb1a1, 0x040a,
+ 0xb2a1, 0x0468,
+ 0xb3a1, 0x04c6,
+ 0xb4a1, 0x0524,
+ 0xb5a1, 0x0582,
+ 0xb6a1, 0x05e0,
+ 0xb7a1, 0x063e,
+ 0xb8a1, 0x069c,
+ 0xb9a1, 0x06fa,
+ 0xbaa1, 0x0758,
+ 0xbba1, 0x07b6,
+ 0xbca1, 0x0814,
+ 0xbda1, 0x0872,
+ 0xbea1, 0x08d0,
+ 0xbfa1, 0x092e,
+ 0xc0a1, 0x098c,
+ 0xc1a1, 0x09ea,
+ 0xc2a1, 0x0a48,
+ 0xc3a1, 0x0aa6,
+ 0xc4a1, 0x0b04,
+ 0xc5a1, 0x0b62,
+ 0xc6a1, 0x0bc0,
+ 0xc7a1, 0x0c1e,
+ 0xc8a1, 0x0c7c,
+ 0xc9a1, 0x0cda,
+ 0xcaa1, 0x0d38,
+ 0xcba1, 0x0d96,
+ 0xcca1, 0x0df4,
+ 0xcda1, 0x0e52,
+ 0xcea1, 0x0eb0,
+ 0xcfa1, 0x0f0e,
+ 0xd0a1, 0x0f6c,
+ 0xd1a1, 0x0fca,
+ 0xd2a1, 0x1028,
+ 0xd3a1, 0x1086,
+ 0xd4a1, 0x10e4,
+ 0xd5a1, 0x1142,
+ 0xd6a1, 0x11a0,
+ 0xd7a1, 0x11fe,
+ 0xd8a1, 0x1257,
+ 0xd9a1, 0x12b5,
+ 0xdaa1, 0x1313,
+ 0xdba1, 0x1371,
+ 0xdca1, 0x13cf,
+ 0xdda1, 0x142d,
+ 0xdea1, 0x148b,
+ 0xdfa1, 0x14e9,
+ 0xe0a1, 0x1547,
+ 0xe1a1, 0x15a5,
+ 0xe2a1, 0x1603,
+ 0xe3a1, 0x1661,
+ 0xe4a1, 0x16bf,
+ 0xe5a1, 0x171d,
+ 0xe6a1, 0x177b,
+ 0xe7a1, 0x17d9,
+ 0xe8a1, 0x1837,
+ 0xe9a1, 0x1895,
+ 0xeaa1, 0x18f3,
+ 0xeba1, 0x1951,
+ 0xeca1, 0x19af,
+ 0xeda1, 0x1a0d,
+ 0xeea1, 0x1a6b,
+ 0xefa1, 0x1ac9,
+ 0xf0a1, 0x1b27,
+ 0xf1a1, 0x1b85,
+ 0xf2a1, 0x1be3,
+ 0xf3a1, 0x1c41,
+ 0xf4a1, 0x1c9f,
+ 0xf5a1, 0x1cfd,
+ 0xf6a1, 0x1d5b,
+ 0xf7a1, 0x1db9,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 gb12GBpcEUCHEnc16 = {
+ 0,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
+ 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010,
+ 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018,
+ 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020,
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028,
+ 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030,
+ 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038,
+ 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040,
+ 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048,
+ 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050,
+ 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
+ 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0000,
+ 0x1e20, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1e21, 0x1e22, 0x1e23 },
+ gb12GBpcEUCHMap2, 90
+};
+
+static Gushort gb12GBpcEUCVMap2[220] = {
+ 0x0000, 0x0000,
+ 0xa1a1, 0x0060,
+ 0xa2b1, 0x00be,
+ 0xa2e5, 0x00f0,
+ 0xa2f1, 0x00fa,
+ 0xa3a1, 0x0106,
+ 0xa4a1, 0x0164,
+ 0xa5a1, 0x01b7,
+ 0xa6a1, 0x020d,
+ 0xa6c1, 0x0225,
+ 0xa7a1, 0x025a,
+ 0xa7d1, 0x027b,
+ 0xa8a1, 0x029c,
+ 0xa8c5, 0x02bc,
+ 0xa9a4, 0x02e2,
+ 0xaaa1, 0x032e,
+ 0xaba1, 0x038c,
+ 0xb0a1, 0x03ac,
+ 0xb1a1, 0x040a,
+ 0xb2a1, 0x0468,
+ 0xb3a1, 0x04c6,
+ 0xb4a1, 0x0524,
+ 0xb5a1, 0x0582,
+ 0xb6a1, 0x05e0,
+ 0xb7a1, 0x063e,
+ 0xb8a1, 0x069c,
+ 0xb9a1, 0x06fa,
+ 0xbaa1, 0x0758,
+ 0xbba1, 0x07b6,
+ 0xbca1, 0x0814,
+ 0xbda1, 0x0872,
+ 0xbea1, 0x08d0,
+ 0xbfa1, 0x092e,
+ 0xc0a1, 0x098c,
+ 0xc1a1, 0x09ea,
+ 0xc2a1, 0x0a48,
+ 0xc3a1, 0x0aa6,
+ 0xc4a1, 0x0b04,
+ 0xc5a1, 0x0b62,
+ 0xc6a1, 0x0bc0,
+ 0xc7a1, 0x0c1e,
+ 0xc8a1, 0x0c7c,
+ 0xc9a1, 0x0cda,
+ 0xcaa1, 0x0d38,
+ 0xcba1, 0x0d96,
+ 0xcca1, 0x0df4,
+ 0xcda1, 0x0e52,
+ 0xcea1, 0x0eb0,
+ 0xcfa1, 0x0f0e,
+ 0xd0a1, 0x0f6c,
+ 0xd1a1, 0x0fca,
+ 0xd2a1, 0x1028,
+ 0xd3a1, 0x1086,
+ 0xd4a1, 0x10e4,
+ 0xd5a1, 0x1142,
+ 0xd6a1, 0x11a0,
+ 0xd7a1, 0x11fe,
+ 0xd8a1, 0x1257,
+ 0xd9a1, 0x12b5,
+ 0xdaa1, 0x1313,
+ 0xdba1, 0x1371,
+ 0xdca1, 0x13cf,
+ 0xdda1, 0x142d,
+ 0xdea1, 0x148b,
+ 0xdfa1, 0x14e9,
+ 0xe0a1, 0x1547,
+ 0xe1a1, 0x15a5,
+ 0xe2a1, 0x1603,
+ 0xe3a1, 0x1661,
+ 0xe4a1, 0x16bf,
+ 0xe5a1, 0x171d,
+ 0xe6a1, 0x177b,
+ 0xe7a1, 0x17d9,
+ 0xe8a1, 0x1837,
+ 0xe9a1, 0x1895,
+ 0xeaa1, 0x18f3,
+ 0xeba1, 0x1951,
+ 0xeca1, 0x19af,
+ 0xeda1, 0x1a0d,
+ 0xeea1, 0x1a6b,
+ 0xefa1, 0x1ac9,
+ 0xf0a1, 0x1b27,
+ 0xf1a1, 0x1b85,
+ 0xf2a1, 0x1be3,
+ 0xf3a1, 0x1c41,
+ 0xf4a1, 0x1c9f,
+ 0xf5a1, 0x1cfd,
+ 0xf6a1, 0x1d5b,
+ 0xf7a1, 0x1db9,
+ 0xa1a2, 0x023f,
+ 0xa1a3, 0x023e,
+ 0xa1aa, 0x0256,
+ 0xa1ab, 0x1e18,
+ 0xa1ad, 0x0257,
+ 0xa1b2, 0x0246,
+ 0xa1fe, 0x1e1a,
+ 0xa3a1, 0x0242,
+ 0xa3a8, 0x0244,
+ 0xa3ac, 0x023d,
+ 0xa3ae, 0x1e1b,
+ 0xa3ba, 0x0240,
+ 0xa3bd, 0x1e1c,
+ 0xa3bf, 0x0243,
+ 0xa3db, 0x1e1d,
+ 0xa3dd, 0x1e1e,
+ 0xa3df, 0x0258,
+ 0xa3fb, 0x0254,
+ 0xa3fd, 0x0255,
+ 0xa3fe, 0x1e1f,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 gb12GBpcEUCVEnc16 = {
+ 1,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
+ 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010,
+ 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018,
+ 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020,
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028,
+ 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030,
+ 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038,
+ 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040,
+ 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048,
+ 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050,
+ 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
+ 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0000,
+ 0x1e20, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1e21, 0x1e22, 0x1e23 },
+ gb12GBpcEUCVMap2, 110
+};
+
+static Gushort gb12UniGBUCS2HMap2[26922] = {
+ 0x0000, 0x0000,
+ 0x0020, 0x0001,
+ 0x00a4, 0x00a7,
+ 0x00a7, 0x00ab,
+ 0x00a8, 0x0066,
+ 0x00b0, 0x00a2,
+ 0x00b1, 0x007f,
+ 0x00d7, 0x0080,
+ 0x00e0, 0x029f,
+ 0x00e1, 0x029d,
+ 0x00e8, 0x02a3,
+ 0x00e9, 0x02a1,
+ 0x00ea, 0x02b5,
+ 0x00ec, 0x02a7,
+ 0x00ed, 0x02a5,
+ 0x00f2, 0x02ab,
+ 0x00f3, 0x02a9,
+ 0x00f7, 0x0081,
+ 0x00f9, 0x02af,
+ 0x00fa, 0x02ad,
+ 0x00fc, 0x02b4,
+ 0x0101, 0x029c,
+ 0x0113, 0x02a0,
+ 0x011b, 0x02a2,
+ 0x012b, 0x02a4,
+ 0x014d, 0x02a8,
+ 0x016b, 0x02ac,
+ 0x01ce, 0x029e,
+ 0x01d0, 0x02a6,
+ 0x01d2, 0x02aa,
+ 0x01d4, 0x02ae,
+ 0x01d6, 0x02b0,
+ 0x01d8, 0x02b1,
+ 0x01da, 0x02b2,
+ 0x01dc, 0x02b3,
+ 0x02c7, 0x0065,
+ 0x02c9, 0x0064,
+ 0x02ca, 0x26b3,
+ 0x02d9, 0x26b5,
+ 0x0391, 0x020d,
+ 0x03a3, 0x021e,
+ 0x03b1, 0x0225,
+ 0x03c3, 0x0236,
+ 0x0401, 0x0260,
+ 0x0410, 0x025a,
+ 0x0416, 0x0261,
+ 0x0436, 0x0282,
+ 0x0451, 0x0281,
+ 0x1e3f, 0x02b7,
+ 0x2010, 0x2722,
+ 0x2013, 0x26b6,
+ 0x2014, 0x0069,
+ 0x2015, 0x26b7,
+ 0x2016, 0x006b,
+ 0x2018, 0x006d,
+ 0x201c, 0x006f,
+ 0x2025, 0x26b8,
+ 0x2026, 0x006c,
+ 0x2030, 0x00aa,
+ 0x2032, 0x00a3,
+ 0x2035, 0x26b9,
+ 0x203b, 0x00b8,
+ 0x2103, 0x00a5,
+ 0x2105, 0x26ba,
+ 0x2109, 0x26bb,
+ 0x2116, 0x00ac,
+ 0x2121, 0x2720,
+ 0x2160, 0x00fa,
+ 0x2170, 0x26a9,
+ 0x2190, 0x00ba,
+ 0x2192, 0x00b9,
+ 0x2193, 0x00bc,
+ 0x2196, 0x26bc,
+ 0x2208, 0x0089,
+ 0x220f, 0x0086,
+ 0x2211, 0x0085,
+ 0x2215, 0x26c0,
+ 0x221a, 0x008b,
+ 0x221d, 0x0097,
+ 0x221e, 0x009d,
+ 0x221f, 0x26c1,
+ 0x2220, 0x008e,
+ 0x2223, 0x26c2,
+ 0x2225, 0x008d,
+ 0x2227, 0x0083,
+ 0x2229, 0x0088,
+ 0x222a, 0x0087,
+ 0x222b, 0x0091,
+ 0x222e, 0x0092,
+ 0x2234, 0x009f,
+ 0x2235, 0x009e,
+ 0x2236, 0x0082,
+ 0x2237, 0x008a,
+ 0x223d, 0x0096,
+ 0x2248, 0x0095,
+ 0x224c, 0x0094,
+ 0x2252, 0x26c3,
+ 0x2260, 0x0098,
+ 0x2261, 0x0093,
+ 0x2264, 0x009b,
+ 0x2266, 0x26c4,
+ 0x226e, 0x0099,
+ 0x2295, 0x2704,
+ 0x2299, 0x0090,
+ 0x22a5, 0x008c,
+ 0x22bf, 0x26c6,
+ 0x22ef, 0x006c,
+ 0x2312, 0x008f,
+ 0x2460, 0x00e6,
+ 0x2474, 0x00d2,
+ 0x2488, 0x00be,
+ 0x2500, 0x02e2,
+ 0x2550, 0x26c7,
+ 0x2581, 0x26eb,
+ 0x2593, 0x26fa,
+ 0x25a0, 0x00b5,
+ 0x25a1, 0x00b4,
+ 0x25b2, 0x00b7,
+ 0x25b3, 0x00b6,
+ 0x25bc, 0x26fd,
+ 0x25c6, 0x00b3,
+ 0x25c7, 0x00b2,
+ 0x25cb, 0x00af,
+ 0x25ce, 0x00b1,
+ 0x25cf, 0x00b0,
+ 0x25e2, 0x26ff,
+ 0x2605, 0x00ae,
+ 0x2606, 0x00ad,
+ 0x2609, 0x2703,
+ 0x2640, 0x00a1,
+ 0x2642, 0x00a0,
+ 0x3000, 0x0060,
+ 0x3003, 0x0067,
+ 0x3005, 0x0068,
+ 0x3006, 0x2728,
+ 0x3007, 0x1e17,
+ 0x3008, 0x0073,
+ 0x3010, 0x007d,
+ 0x3012, 0x2705,
+ 0x3013, 0x00bd,
+ 0x3014, 0x0071,
+ 0x3016, 0x007b,
+ 0x301d, 0x2706,
+ 0x3021, 0x2708,
+ 0x3041, 0x0164,
+ 0x309b, 0x2724,
+ 0x309d, 0x2729,
+ 0x30a1, 0x01b7,
+ 0x30fb, 0x0063,
+ 0x30fc, 0x2723,
+ 0x30fd, 0x2726,
+ 0x3105, 0x02bc,
+ 0x3220, 0x00f0,
+ 0x3231, 0x2721,
+ 0x32a3, 0x2711,
+ 0x338e, 0x2712,
+ 0x339c, 0x2714,
+ 0x33a1, 0x2717,
+ 0x33c4, 0x2718,
+ 0x33ce, 0x2719,
+ 0x33d1, 0x271a,
+ 0x33d5, 0x271c,
+ 0x4e00, 0x1042,
+ 0x4e01, 0x05e0,
+ 0x4e02, 0x2758,
+ 0x4e03, 0x0bfe,
+ 0x4e04, 0x2759,
+ 0x4e07, 0x0ea3,
+ 0x4e08, 0x116a,
+ 0x4e09, 0x0cd8,
+ 0x4e0a, 0x0d08,
+ 0x4e0b, 0x0f2f,
+ 0x4e0c, 0x1258,
+ 0x4e0d, 0x0482,
+ 0x4e0e, 0x10d0,
+ 0x4e0f, 0x275c,
+ 0x4e10, 0x125a,
+ 0x4e11, 0x0518,
+ 0x4e12, 0x275d,
+ 0x4e13, 0x1205,
+ 0x4e14, 0x0c4f,
+ 0x4e15, 0x125d,
+ 0x4e16, 0x0d57,
+ 0x4e17, 0x275e,
+ 0x4e18, 0x0c6d,
+ 0x4e19, 0x0464,
+ 0x4e1a, 0x103c,
+ 0x4e1b, 0x0557,
+ 0x4e1c, 0x05ea,
+ 0x4e1d, 0x0db4,
+ 0x4e1e, 0x125f,
+ 0x4e1f, 0x275f,
+ 0x4e22, 0x05e9,
+ 0x4e23, 0x2762,
+ 0x4e24, 0x0a06,
+ 0x4e25, 0x0ff8,
+ 0x4e26, 0x2763,
+ 0x4e27, 0x0cde,
+ 0x4e28, 0x1263,
+ 0x4e29, 0x2764,
+ 0x4e2a, 0x06f1,
+ 0x4e2b, 0x0fe7,
+ 0x4e2c, 0x169c,
+ 0x4e2d, 0x11cf,
+ 0x4e2e, 0x2765,
+ 0x4e30, 0x067e,
+ 0x4e31, 0x2767,
+ 0x4e32, 0x0531,
+ 0x4e33, 0x2768,
+ 0x4e34, 0x0a22,
+ 0x4e35, 0x2769,
+ 0x4e36, 0x1272,
+ 0x4e37, 0x276a,
+ 0x4e38, 0x0e99,
+ 0x4e39, 0x0585,
+ 0x4e3a, 0x0eb9,
+ 0x4e3b, 0x11f6,
+ 0x4e3c, 0x276b,
+ 0x4e3d, 0x09e1,
+ 0x4e3e, 0x0908,
+ 0x4e3f, 0x1265,
+ 0x4e40, 0x276c,
+ 0x4e43, 0x0b2e,
+ 0x4e44, 0x276f,
+ 0x4e45, 0x08f2,
+ 0x4e46, 0x2770,
+ 0x4e47, 0x1267,
+ 0x4e48, 0x0ab9,
+ 0x4e49, 0x106c,
+ 0x4e4a, 0x2771,
+ 0x4e4b, 0x11ad,
+ 0x4e4c, 0x0ee9,
+ 0x4e4d, 0x1148,
+ 0x4e4e, 0x07ac,
+ 0x4e4f, 0x0643,
+ 0x4e50, 0x09c1,
+ 0x4e51, 0x2772,
+ 0x4e52, 0x0bd8,
+ 0x4e53, 0x0b93,
+ 0x4e54, 0x0c44,
+ 0x4e55, 0x2773,
+ 0x4e56, 0x072d,
+ 0x4e57, 0x2774,
+ 0x4e58, 0x04f0,
+ 0x4e59, 0x1059,
+ 0x4e5a, 0x2775,
+ 0x4e5c, 0x1275,
+ 0x4e5d, 0x08f4,
+ 0x4e5e, 0x0c11,
+ 0x4e5f, 0x1039,
+ 0x4e60, 0x0f1d,
+ 0x4e61, 0x0f54,
+ 0x4e62, 0x2777,
+ 0x4e66, 0x0d80,
+ 0x4e67, 0x277b,
+ 0x4e69, 0x1276,
+ 0x4e6a, 0x277d,
+ 0x4e70, 0x0a99,
+ 0x4e71, 0x0a79,
+ 0x4e72, 0x2783,
+ 0x4e73, 0x0cc4,
+ 0x4e74, 0x2784,
+ 0x4e7e, 0x0c29,
+ 0x4e7f, 0x278e,
+ 0x4e82, 0x2059,
+ 0x4e83, 0x2791,
+ 0x4e86, 0x0a14,
+ 0x4e87, 0x2794,
+ 0x4e88, 0x10cd,
+ 0x4e89, 0x119a,
+ 0x4e8a, 0x2795,
+ 0x4e8b, 0x0d59,
+ 0x4e8c, 0x063d,
+ 0x4e8d, 0x1257,
+ 0x4e8e, 0x10bf,
+ 0x4e8f, 0x0984,
+ 0x4e90, 0x2796,
+ 0x4e91, 0x1109,
+ 0x4e92, 0x07ba,
+ 0x4e93, 0x1277,
+ 0x4e94, 0x0ef4,
+ 0x4e95, 0x08dd,
+ 0x4e96, 0x2797,
+ 0x4e98, 0x125e,
+ 0x4e99, 0x2799,
+ 0x4e9a, 0x0ff0,
+ 0x4e9b, 0x0f74,
+ 0x4e9c, 0x279a,
+ 0x4e9e, 0x21f1,
+ 0x4e9f, 0x1273,
+ 0x4ea0, 0x1303,
+ 0x4ea1, 0x0ea7,
+ 0x4ea2, 0x0947,
+ 0x4ea3, 0x279c,
+ 0x4ea4, 0x088c,
+ 0x4ea5, 0x075c,
+ 0x4ea6, 0x1067,
+ 0x4ea7, 0x04c1,
+ 0x4ea8, 0x0797,
+ 0x4ea9, 0x0b19,
+ 0x4eaa, 0x279d,
+ 0x4eab, 0x0f5a,
+ 0x4eac, 0x08d8,
+ 0x4ead, 0x0e55,
+ 0x4eae, 0x0a0a,
+ 0x4eaf, 0x279e,
+ 0x4eb2, 0x0c54,
+ 0x4eb3, 0x1305,
+ 0x4eb4, 0x27a1,
+ 0x4eb5, 0x1308,
+ 0x4eb6, 0x27a2,
+ 0x4eba, 0x0ca6,
+ 0x4ebb, 0x129f,
+ 0x4ebc, 0x27a6,
+ 0x4ebf, 0x1061,
+ 0x4ec0, 0x0d49,
+ 0x4ec1, 0x0ca5,
+ 0x4ec2, 0x12a2,
+ 0x4ec3, 0x12a0,
+ 0x4ec4, 0x127c,
+ 0x4ec5, 0x08c7,
+ 0x4ec6, 0x0bec,
+ 0x4ec7, 0x0515,
+ 0x4ec8, 0x27a9,
+ 0x4ec9, 0x12a1,
+ 0x4eca, 0x08c2,
+ 0x4ecb, 0x08ba,
+ 0x4ecc, 0x27aa,
+ 0x4ecd, 0x0caf,
+ 0x4ece, 0x0556,
+ 0x4ecf, 0x27ab,
+ 0x4ed1, 0x0a7f,
+ 0x4ed2, 0x27ad,
+ 0x4ed3, 0x049d,
+ 0x4ed4, 0x122d,
+ 0x4ed5, 0x0d62,
+ 0x4ed6, 0x0df0,
+ 0x4ed7, 0x116d,
+ 0x4ed8, 0x06b1,
+ 0x4ed9, 0x0f36,
+ 0x4eda, 0x27ae,
+ 0x4edd, 0x12ee,
+ 0x4ede, 0x12a6,
+ 0x4edf, 0x0c27,
+ 0x4ee0, 0x27b1,
+ 0x4ee1, 0x12a4,
+ 0x4ee2, 0x27b2,
+ 0x4ee3, 0x057d,
+ 0x4ee4, 0x0a37,
+ 0x4ee5, 0x105b,
+ 0x4ee6, 0x27b3,
+ 0x4ee8, 0x12a3,
+ 0x4ee9, 0x27b5,
+ 0x4eea, 0x104e,
+ 0x4eeb, 0x12a5,
+ 0x4eec, 0x0acc,
+ 0x4eed, 0x27b6,
+ 0x4ef0, 0x101f,
+ 0x4ef1, 0x27b9,
+ 0x4ef2, 0x11d8,
+ 0x4ef3, 0x12a8,
+ 0x4ef4, 0x27ba,
+ 0x4ef5, 0x12ab,
+ 0x4ef6, 0x0871,
+ 0x4ef7, 0x084e,
+ 0x4ef8, 0x27bb,
+ 0x4efb, 0x0ca9,
+ 0x4efc, 0x27be,
+ 0x4efd, 0x067a,
+ 0x4efe, 0x27bf,
+ 0x4eff, 0x065f,
+ 0x4f00, 0x27c0,
+ 0x4f01, 0x0c12,
+ 0x4f02, 0x27c1,
+ 0x4f09, 0x12ae,
+ 0x4f0a, 0x1048,
+ 0x4f0b, 0x27c8,
+ 0x4f0d, 0x0ef8,
+ 0x4f0e, 0x0832,
+ 0x4f0f, 0x0699,
+ 0x4f10, 0x0642,
+ 0x4f11, 0x0fa8,
+ 0x4f12, 0x27ca,
+ 0x4f17, 0x11d9,
+ 0x4f18, 0x10aa,
+ 0x4f19, 0x0804,
+ 0x4f1a, 0x07f6,
+ 0x4f1b, 0x12a7,
+ 0x4f1c, 0x27cf,
+ 0x4f1e, 0x0cda,
+ 0x4f1f, 0x0ebf,
+ 0x4f20, 0x052e,
+ 0x4f21, 0x27d1,
+ 0x4f22, 0x12a9,
+ 0x4f23, 0x27d2,
+ 0x4f24, 0x0d04,
+ 0x4f25, 0x12ac,
+ 0x4f26, 0x0a7e,
+ 0x4f27, 0x12ad,
+ 0x4f28, 0x27d3,
+ 0x4f2a, 0x0ec0,
+ 0x4f2b, 0x12af,
+ 0x4f2c, 0x27d5,
+ 0x4f2f, 0x0475,
+ 0x4f30, 0x0719,
+ 0x4f31, 0x27d8,
+ 0x4f32, 0x12b7,
+ 0x4f33, 0x27d9,
+ 0x4f34, 0x03f4,
+ 0x4f35, 0x27da,
+ 0x4f36, 0x0a2f,
+ 0x4f37, 0x27db,
+ 0x4f38, 0x0d25,
+ 0x4f39, 0x27dc,
+ 0x4f3a, 0x0dba,
+ 0x4f3b, 0x27dd,
+ 0x4f3c, 0x0dbb,
+ 0x4f3d, 0x12b8,
+ 0x4f3e, 0x27de,
+ 0x4f43, 0x05c9,
+ 0x4f44, 0x27e3,
+ 0x4f46, 0x058c,
+ 0x4f47, 0x27e5,
+ 0x4f4d, 0x0eca,
+ 0x4f4e, 0x05ae,
+ 0x4f4f, 0x11fe,
+ 0x4f50, 0x1251,
+ 0x4f51, 0x10b8,
+ 0x4f52, 0x27eb,
+ 0x4f53, 0x0e38,
+ 0x4f54, 0x27ec,
+ 0x4f55, 0x0785,
+ 0x4f56, 0x27ed,
+ 0x4f57, 0x12b6,
+ 0x4f58, 0x12f0,
+ 0x4f59, 0x10c5,
+ 0x4f5a, 0x12b3,
+ 0x4f5b, 0x068d,
+ 0x4f5c, 0x1254,
+ 0x4f5d, 0x12b4,
+ 0x4f5e, 0x12b0,
+ 0x4f5f, 0x12b5,
+ 0x4f60, 0x0b46,
+ 0x4f61, 0x27ee,
+ 0x4f63, 0x109b,
+ 0x4f64, 0x12aa,
+ 0x4f65, 0x12f1,
+ 0x4f66, 0x27f0,
+ 0x4f67, 0x12b1,
+ 0x4f68, 0x27f1,
+ 0x4f69, 0x0ba6,
+ 0x4f6a, 0x27f2,
+ 0x4f6c, 0x09bb,
+ 0x4f6d, 0x27f4,
+ 0x4f6f, 0x1019,
+ 0x4f70, 0x03e6,
+ 0x4f71, 0x27f6,
+ 0x4f73, 0x0844,
+ 0x4f74, 0x12ba,
+ 0x4f75, 0x27f8,
+ 0x4f76, 0x12b9,
+ 0x4f77, 0x27f9,
+ 0x4f7b, 0x12c0,
+ 0x4f7c, 0x12c2,
+ 0x4f7d, 0x27fd,
+ 0x4f7e, 0x12bf,
+ 0x4f7f, 0x0d50,
+ 0x4f80, 0x27fe,
+ 0x4f83, 0x12bd,
+ 0x4f84, 0x11b5,
+ 0x4f85, 0x2801,
+ 0x4f86, 0x1ff2,
+ 0x4f87, 0x2802,
+ 0x4f88, 0x0503,
+ 0x4f89, 0x12bc,
+ 0x4f8a, 0x2803,
+ 0x4f8b, 0x09e8,
+ 0x4f8c, 0x2804,
+ 0x4f8d, 0x0d63,
+ 0x4f8e, 0x2805,
+ 0x4f8f, 0x12be,
+ 0x4f90, 0x2806,
+ 0x4f91, 0x12bb,
+ 0x4f92, 0x2807,
+ 0x4f94, 0x12c4,
+ 0x4f95, 0x2809,
+ 0x4f96, 0x205d,
+ 0x4f97, 0x05f0,
+ 0x4f98, 0x280a,
+ 0x4f9b, 0x0702,
+ 0x4f9c, 0x280d,
+ 0x4f9d, 0x1047,
+ 0x4f9e, 0x280e,
+ 0x4fa0, 0x0f2d,
+ 0x4fa1, 0x2810,
+ 0x4fa3, 0x0a69,
+ 0x4fa4, 0x2812,
+ 0x4fa5, 0x0895,
+ 0x4fa6, 0x118d,
+ 0x4fa7, 0x04a7,
+ 0x4fa8, 0x0c45,
+ 0x4fa9, 0x0978,
+ 0x4faa, 0x12c1,
+ 0x4fab, 0x2813,
+ 0x4fac, 0x12c3,
+ 0x4fad, 0x2814,
+ 0x4fae, 0x0ef9,
+ 0x4faf, 0x07a5,
+ 0x4fb0, 0x2815,
+ 0x4fb5, 0x0c53,
+ 0x4fb6, 0x281a,
+ 0x4fbf, 0x044c,
+ 0x4fc0, 0x2823,
+ 0x4fc2, 0x269c,
+ 0x4fc3, 0x055c,
+ 0x4fc4, 0x062c,
+ 0x4fc5, 0x12c8,
+ 0x4fc6, 0x2825,
+ 0x4fca, 0x092e,
+ 0x4fcb, 0x2829,
+ 0x4fce, 0x12f2,
+ 0x4fcf, 0x0c4b,
+ 0x4fd0, 0x09e9,
+ 0x4fd1, 0x12cc,
+ 0x4fd2, 0x282c,
+ 0x4fd7, 0x0dcc,
+ 0x4fd8, 0x069a,
+ 0x4fd9, 0x2831,
+ 0x4fda, 0x12c9,
+ 0x4fdb, 0x2832,
+ 0x4fdc, 0x12cb,
+ 0x4fdd, 0x040c,
+ 0x4fde, 0x10c6,
+ 0x4fdf, 0x12cd,
+ 0x4fe0, 0x21b5,
+ 0x4fe1, 0x0f90,
+ 0x4fe2, 0x2833,
+ 0x4fe3, 0x12ca,
+ 0x4fe4, 0x2834,
+ 0x4fe6, 0x12c5,
+ 0x4fe7, 0x2836,
+ 0x4fe8, 0x12c6,
+ 0x4fe9, 0x09f2,
+ 0x4fea, 0x12c7,
+ 0x4feb, 0x2837,
+ 0x4fed, 0x0866,
+ 0x4fee, 0x0fa9,
+ 0x4fef, 0x06a4,
+ 0x4ff0, 0x2839,
+ 0x4ff1, 0x0912,
+ 0x4ff2, 0x283a,
+ 0x4ff3, 0x12d1,
+ 0x4ff4, 0x283b,
+ 0x4ff8, 0x12ce,
+ 0x4ff9, 0x283f,
+ 0x4ffa, 0x03be,
+ 0x4ffb, 0x2840,
+ 0x4ffe, 0x12d6,
+ 0x4fff, 0x2843,
+ 0x5000, 0x22cc,
+ 0x5001, 0x2844,
+ 0x5006, 0x2016,
+ 0x5007, 0x2849,
+ 0x5009, 0x1e62,
+ 0x500a, 0x284b,
+ 0x500b, 0x1f20,
+ 0x500c, 0x12d8,
+ 0x500d, 0x041f,
+ 0x500e, 0x284c,
+ 0x500f, 0x12d3,
+ 0x5010, 0x284d,
+ 0x5011, 0x207f,
+ 0x5012, 0x059a,
+ 0x5013, 0x284e,
+ 0x5014, 0x0922,
+ 0x5015, 0x284f,
+ 0x5018, 0x0e1b,
+ 0x5019, 0x07a9,
+ 0x501a, 0x1057,
+ 0x501b, 0x2852,
+ 0x501c, 0x12d7,
+ 0x501d, 0x2853,
+ 0x501f, 0x08b9,
+ 0x5020, 0x2855,
+ 0x5021, 0x04d0,
+ 0x5022, 0x2856,
+ 0x5025, 0x12d9,
+ 0x5026, 0x091a,
+ 0x5027, 0x2859,
+ 0x5028, 0x12da,
+ 0x5029, 0x12cf,
+ 0x502a, 0x0b42,
+ 0x502b, 0x205c,
+ 0x502c, 0x12d2,
+ 0x502d, 0x12d5,
+ 0x502e, 0x12d4,
+ 0x502f, 0x285a,
+ 0x503a, 0x114f,
+ 0x503b, 0x2865,
+ 0x503c, 0x11b4,
+ 0x503d, 0x2866,
+ 0x503e, 0x0c60,
+ 0x503f, 0x2867,
+ 0x5043, 0x12dc,
+ 0x5044, 0x286b,
+ 0x5047, 0x084c,
+ 0x5048, 0x12de,
+ 0x5049, 0x2194,
+ 0x504a, 0x286e,
+ 0x504c, 0x12d0,
+ 0x504d, 0x2870,
+ 0x504e, 0x12df,
+ 0x504f, 0x0bca,
+ 0x5050, 0x2871,
+ 0x5055, 0x12dd,
+ 0x5056, 0x2876,
+ 0x505a, 0x1253,
+ 0x505b, 0x287a,
+ 0x505c, 0x0e54,
+ 0x505d, 0x287b,
+ 0x5065, 0x0872,
+ 0x5066, 0x2883,
+ 0x506c, 0x12e0,
+ 0x506d, 0x2889,
+ 0x5074, 0x1e65,
+ 0x5075, 0x2281,
+ 0x5076, 0x0b7d,
+ 0x5077, 0x0e66,
+ 0x5078, 0x2890,
+ 0x507b, 0x12e1,
+ 0x507c, 0x2893,
+ 0x507e, 0x12db,
+ 0x507f, 0x04ca,
+ 0x5080, 0x098b,
+ 0x5081, 0x2895,
+ 0x5085, 0x06b0,
+ 0x5086, 0x2899,
+ 0x5088, 0x09e7,
+ 0x5089, 0x289b,
+ 0x508d, 0x0403,
+ 0x508e, 0x289f,
+ 0x5096, 0x22cd,
+ 0x5097, 0x28a7,
+ 0x5098, 0x210a,
+ 0x5099, 0x1e3e,
+ 0x509a, 0x28a8,
+ 0x50a2, 0x267f,
+ 0x50a3, 0x0579,
+ 0x50a4, 0x28b0,
+ 0x50a5, 0x12e2,
+ 0x50a6, 0x28b1,
+ 0x50a7, 0x12e3,
+ 0x50a8, 0x0525,
+ 0x50a9, 0x12e4,
+ 0x50aa, 0x28b2,
+ 0x50ac, 0x0562,
+ 0x50ad, 0x222e,
+ 0x50ae, 0x28b4,
+ 0x50b2, 0x03cc,
+ 0x50b3, 0x1e96,
+ 0x50b4, 0x22cb,
+ 0x50b5, 0x226c,
+ 0x50b6, 0x28b8,
+ 0x50b7, 0x2117,
+ 0x50b8, 0x28b9,
+ 0x50ba, 0x12e5,
+ 0x50bb, 0x0cee,
+ 0x50bc, 0x28bb,
+ 0x50be, 0x20e8,
+ 0x50bf, 0x28bd,
+ 0x50c2, 0x22d4,
+ 0x50c3, 0x28c0,
+ 0x50c5, 0x1fb9,
+ 0x50c6, 0x28c2,
+ 0x50c9, 0x22d8,
+ 0x50ca, 0x28c5,
+ 0x50cf, 0x0f5e,
+ 0x50d0, 0x28ca,
+ 0x50d1, 0x20df,
+ 0x50d2, 0x28cb,
+ 0x50d5, 0x20c2,
+ 0x50d6, 0x12e6,
+ 0x50d7, 0x28ce,
+ 0x50da, 0x0a0e,
+ 0x50db, 0x28d1,
+ 0x50de, 0x2195,
+ 0x50df, 0x28d4,
+ 0x50e5, 0x1fac,
+ 0x50e6, 0x12ea,
+ 0x50e7, 0x0ce7,
+ 0x50e8, 0x22d3,
+ 0x50e9, 0x28da,
+ 0x50ec, 0x12e9,
+ 0x50ed, 0x12e8,
+ 0x50ee, 0x12eb,
+ 0x50ef, 0x28dd,
+ 0x50f3, 0x0dd0,
+ 0x50f4, 0x28e1,
+ 0x50f5, 0x087a,
+ 0x50f6, 0x28e2,
+ 0x50f9, 0x1f81,
+ 0x50fa, 0x28e5,
+ 0x50fb, 0x0bc6,
+ 0x50fc, 0x28e6,
+ 0x5100, 0x2210,
+ 0x5101, 0x28ea,
+ 0x5102, 0x22cf,
+ 0x5103, 0x28eb,
+ 0x5104, 0x2213,
+ 0x5105, 0x28ec,
+ 0x5106, 0x12e7,
+ 0x5107, 0x12ec,
+ 0x5108, 0x1fe4,
+ 0x5109, 0x1f90,
+ 0x510a, 0x28ed,
+ 0x510b, 0x12ed,
+ 0x510c, 0x28ee,
+ 0x5110, 0x22d6,
+ 0x5111, 0x28f2,
+ 0x5112, 0x0cc0,
+ 0x5113, 0x28f3,
+ 0x5114, 0x22d0,
+ 0x5115, 0x22ce,
+ 0x5116, 0x28f4,
+ 0x5118, 0x2681,
+ 0x5119, 0x28f6,
+ 0x511f, 0x1e76,
+ 0x5120, 0x28fc,
+ 0x5121, 0x09c7,
+ 0x5122, 0x28fd,
+ 0x512a, 0x2231,
+ 0x512b, 0x2905,
+ 0x5132, 0x1e93,
+ 0x5133, 0x290c,
+ 0x5137, 0x22d2,
+ 0x5138, 0x2910,
+ 0x513a, 0x22d7,
+ 0x513b, 0x22d5,
+ 0x513c, 0x22d1,
+ 0x513d, 0x2912,
+ 0x513f, 0x0638,
+ 0x5140, 0x1259,
+ 0x5141, 0x110d,
+ 0x5142, 0x2914,
+ 0x5143, 0x10ed,
+ 0x5144, 0x0fa1,
+ 0x5145, 0x0509,
+ 0x5146, 0x1178,
+ 0x5147, 0x2915,
+ 0x5148, 0x0f35,
+ 0x5149, 0x073b,
+ 0x514a, 0x2916,
+ 0x514b, 0x0958,
+ 0x514c, 0x2917,
+ 0x514d, 0x0ae7,
+ 0x514e, 0x2918,
+ 0x5151, 0x0611,
+ 0x5152, 0x1ee5,
+ 0x5153, 0x291b,
+ 0x5154, 0x0e74,
+ 0x5155, 0x1302,
+ 0x5156, 0x1304,
+ 0x5157, 0x291c,
+ 0x515a, 0x0594,
+ 0x515b, 0x291f,
+ 0x515c, 0x05f4,
+ 0x515d, 0x2920,
+ 0x5162, 0x08d3,
+ 0x5163, 0x2925,
+ 0x5165, 0x0cc6,
+ 0x5166, 0x2927,
+ 0x5168, 0x0c86,
+ 0x5169, 0x2025,
+ 0x516a, 0x2929,
+ 0x516b, 0x03d6,
+ 0x516c, 0x0704,
+ 0x516d, 0x0a42,
+ 0x516e, 0x12f6,
+ 0x516f, 0x292a,
+ 0x5170, 0x09a7,
+ 0x5171, 0x070b,
+ 0x5172, 0x292b,
+ 0x5173, 0x0731,
+ 0x5174, 0x0f96,
+ 0x5175, 0x0461,
+ 0x5176, 0x0c03,
+ 0x5177, 0x090e,
+ 0x5178, 0x05c5,
+ 0x5179, 0x1225,
+ 0x517a, 0x292c,
+ 0x517b, 0x1021,
+ 0x517c, 0x0859,
+ 0x517d, 0x0d75,
+ 0x517e, 0x292d,
+ 0x5180, 0x0830,
+ 0x5181, 0x12fa,
+ 0x5182, 0x129d,
+ 0x5183, 0x292f,
+ 0x5185, 0x0b3d,
+ 0x5186, 0x2931,
+ 0x5188, 0x06cf,
+ 0x5189, 0x0c98,
+ 0x518a, 0x2933,
+ 0x518c, 0x04a8,
+ 0x518d, 0x111c,
+ 0x518e, 0x2935,
+ 0x5192, 0x0ab5,
+ 0x5193, 0x2939,
+ 0x5195, 0x0ae6,
+ 0x5196, 0x1314,
+ 0x5197, 0x0cba,
+ 0x5198, 0x293b,
+ 0x5199, 0x0f7f,
+ 0x519a, 0x293c,
+ 0x519b, 0x092b,
+ 0x519c, 0x0b6a,
+ 0x519d, 0x293d,
+ 0x51a0, 0x0733,
+ 0x51a1, 0x2940,
+ 0x51a2, 0x1315,
+ 0x51a3, 0x2941,
+ 0x51a4, 0x10ec,
+ 0x51a5, 0x1316,
+ 0x51a6, 0x2942,
+ 0x51ab, 0x130f,
+ 0x51ac, 0x05eb,
+ 0x51ad, 0x2947,
+ 0x51af, 0x0688,
+ 0x51b0, 0x0462,
+ 0x51b1, 0x1310,
+ 0x51b2, 0x050a,
+ 0x51b3, 0x0925,
+ 0x51b4, 0x2949,
+ 0x51b5, 0x0983,
+ 0x51b6, 0x1038,
+ 0x51b7, 0x09cf,
+ 0x51b8, 0x294a,
+ 0x51bb, 0x05f2,
+ 0x51bc, 0x1312,
+ 0x51bd, 0x1311,
+ 0x51be, 0x294d,
+ 0x51c0, 0x08ea,
+ 0x51c1, 0x294f,
+ 0x51c4, 0x0bff,
+ 0x51c5, 0x2952,
+ 0x51c6, 0x1219,
+ 0x51c7, 0x1313,
+ 0x51c8, 0x2953,
+ 0x51c9, 0x0a02,
+ 0x51ca, 0x2954,
+ 0x51cb, 0x05d3,
+ 0x51cc, 0x0a31,
+ 0x51cd, 0x1ecf,
+ 0x51ce, 0x2955,
+ 0x51cf, 0x0868,
+ 0x51d0, 0x2956,
+ 0x51d1, 0x0558,
+ 0x51d2, 0x2957,
+ 0x51db, 0x0a26,
+ 0x51dc, 0x2960,
+ 0x51dd, 0x0b60,
+ 0x51de, 0x2961,
+ 0x51e0, 0x082b,
+ 0x51e1, 0x064f,
+ 0x51e2, 0x2963,
+ 0x51e4, 0x068c,
+ 0x51e5, 0x2965,
+ 0x51eb, 0x1300,
+ 0x51ec, 0x296b,
+ 0x51ed, 0x0bdd,
+ 0x51ee, 0x296c,
+ 0x51ef, 0x093a,
+ 0x51f0, 0x07e0,
+ 0x51f1, 0x1fd9,
+ 0x51f2, 0x296d,
+ 0x51f3, 0x05ab,
+ 0x51f4, 0x296e,
+ 0x51f5, 0x1399,
+ 0x51f6, 0x0fa2,
+ 0x51f7, 0x296f,
+ 0x51f8, 0x0e6a,
+ 0x51f9, 0x03c7,
+ 0x51fa, 0x051b,
+ 0x51fb, 0x080c,
+ 0x51fc, 0x139a,
+ 0x51fd, 0x0766,
+ 0x51fe, 0x2970,
+ 0x51ff, 0x1127,
+ 0x5200, 0x0597,
+ 0x5201, 0x05d4,
+ 0x5202, 0x128c,
+ 0x5203, 0x0cab,
+ 0x5204, 0x2971,
+ 0x5206, 0x0673,
+ 0x5207, 0x0c4d,
+ 0x5208, 0x128d,
+ 0x5209, 0x2973,
+ 0x520a, 0x093c,
+ 0x520b, 0x2974,
+ 0x520d, 0x138b,
+ 0x520e, 0x128e,
+ 0x520f, 0x2976,
+ 0x5211, 0x0f97,
+ 0x5212, 0x07c3,
+ 0x5213, 0x2978,
+ 0x5216, 0x196e,
+ 0x5217, 0x0a19,
+ 0x5218, 0x0a3e,
+ 0x5219, 0x1135,
+ 0x521a, 0x06d0,
+ 0x521b, 0x0537,
+ 0x521c, 0x297b,
+ 0x521d, 0x051a,
+ 0x521e, 0x297c,
+ 0x5220, 0x0cf7,
+ 0x5221, 0x297e,
+ 0x5224, 0x0b91,
+ 0x5225, 0x2981,
+ 0x5228, 0x0b9a,
+ 0x5229, 0x09e6,
+ 0x522a, 0x2984,
+ 0x522b, 0x0459,
+ 0x522c, 0x2985,
+ 0x522d, 0x128f,
+ 0x522e, 0x0727,
+ 0x522f, 0x2986,
+ 0x5230, 0x059e,
+ 0x5231, 0x2987,
+ 0x5233, 0x1290,
+ 0x5234, 0x2989,
+ 0x5236, 0x11c5,
+ 0x5237, 0x0d97,
+ 0x5238, 0x0c8a,
+ 0x5239, 0x0ceb,
+ 0x523a, 0x054f,
+ 0x523b, 0x0959,
+ 0x523c, 0x298b,
+ 0x523d, 0x074d,
+ 0x523e, 0x298c,
+ 0x523f, 0x1291,
+ 0x5241, 0x0626,
+ 0x5242, 0x0834,
+ 0x5243, 0x0e3d,
+ 0x5244, 0x22c8,
+ 0x5245, 0x298d,
+ 0x5247, 0x2263,
+ 0x5248, 0x298f,
+ 0x524a, 0x0f64,
+ 0x524b, 0x2683,
+ 0x524c, 0x1293,
+ 0x524d, 0x0c2d,
+ 0x524e, 0x2991,
+ 0x5250, 0x0729,
+ 0x5251, 0x0874,
+ 0x5252, 0x2993,
+ 0x5254, 0x0e31,
+ 0x5255, 0x2995,
+ 0x5256, 0x0be9,
+ 0x5257, 0x2996,
+ 0x525b, 0x1f17,
+ 0x525c, 0x1296,
+ 0x525d, 0x299a,
+ 0x525e, 0x1294,
+ 0x525f, 0x299b,
+ 0x5261, 0x1295,
+ 0x5262, 0x299d,
+ 0x5265, 0x0409,
+ 0x5266, 0x29a0,
+ 0x5267, 0x0916,
+ 0x5268, 0x29a1,
+ 0x5269, 0x0d3a,
+ 0x526a, 0x0867,
+ 0x526b, 0x29a2,
+ 0x526e, 0x1f2b,
+ 0x526f, 0x06ac,
+ 0x5270, 0x29a5,
+ 0x5272, 0x06e9,
+ 0x5273, 0x29a7,
+ 0x5274, 0x22ca,
+ 0x5275, 0x1e99,
+ 0x5276, 0x29a8,
+ 0x527d, 0x1298,
+ 0x527e, 0x29af,
+ 0x527f, 0x089c,
+ 0x5280, 0x29b0,
+ 0x5281, 0x129a,
+ 0x5282, 0x1299,
+ 0x5283, 0x1f4f,
+ 0x5284, 0x29b1,
+ 0x5287, 0x1fcf,
+ 0x5288, 0x0bbd,
+ 0x5289, 0x2036,
+ 0x528a, 0x1f3a,
+ 0x528b, 0x29b4,
+ 0x528c, 0x22c9,
+ 0x528d, 0x1f99,
+ 0x528e, 0x29b5,
+ 0x5290, 0x129b,
+ 0x5291, 0x1f75,
+ 0x5292, 0x29b7,
+ 0x5293, 0x129c,
+ 0x5294, 0x29b8,
+ 0x529b, 0x09ef,
+ 0x529c, 0x29bf,
+ 0x529d, 0x0c8b,
+ 0x529e, 0x03f7,
+ 0x529f, 0x06ff,
+ 0x52a0, 0x0846,
+ 0x52a1, 0x0f00,
+ 0x52a2, 0x138d,
+ 0x52a3, 0x0a1c,
+ 0x52a4, 0x29c0,
+ 0x52a8, 0x05ee,
+ 0x52a9, 0x11f9,
+ 0x52aa, 0x0b6d,
+ 0x52ab, 0x08aa,
+ 0x52ac, 0x138e,
+ 0x52ae, 0x29c4,
+ 0x52b1, 0x09e3,
+ 0x52b2, 0x08d1,
+ 0x52b3, 0x09b8,
+ 0x52b4, 0x29c7,
+ 0x52be, 0x1390,
+ 0x52bf, 0x0d5d,
+ 0x52c0, 0x29d1,
+ 0x52c1, 0x1fbe,
+ 0x52c2, 0x29d2,
+ 0x52c3, 0x0471,
+ 0x52c4, 0x29d3,
+ 0x52c7, 0x10a7,
+ 0x52c8, 0x29d6,
+ 0x52c9, 0x0ae8,
+ 0x52ca, 0x29d7,
+ 0x52cb, 0x0fd4,
+ 0x52cc, 0x29d8,
+ 0x52d0, 0x1392,
+ 0x52d1, 0x29dc,
+ 0x52d2, 0x09c0,
+ 0x52d3, 0x29dd,
+ 0x52d5, 0x1ecd,
+ 0x52d6, 0x1393,
+ 0x52d7, 0x29df,
+ 0x52d8, 0x093e,
+ 0x52d9, 0x21a9,
+ 0x52da, 0x29e0,
+ 0x52db, 0x21e6,
+ 0x52dc, 0x29e1,
+ 0x52dd, 0x2127,
+ 0x52de, 0x2003,
+ 0x52df, 0x0b1f,
+ 0x52e0, 0x29e2,
+ 0x52e2, 0x2132,
+ 0x52e3, 0x29e4,
+ 0x52e4, 0x0c57,
+ 0x52e5, 0x29e5,
+ 0x52f0, 0x1394,
+ 0x52f1, 0x2323,
+ 0x52f2, 0x29f0,
+ 0x52f5, 0x2011,
+ 0x52f6, 0x29f3,
+ 0x52f8, 0x20f5,
+ 0x52f9, 0x12fc,
+ 0x52fa, 0x0d10,
+ 0x52fb, 0x29f5,
+ 0x52fe, 0x070d,
+ 0x52ff, 0x0eff,
+ 0x5300, 0x110b,
+ 0x5301, 0x29f8,
+ 0x5305, 0x0407,
+ 0x5306, 0x0555,
+ 0x5307, 0x29fc,
+ 0x5308, 0x0fa4,
+ 0x5309, 0x29fd,
+ 0x530d, 0x12fd,
+ 0x530e, 0x2a01,
+ 0x530f, 0x14b5,
+ 0x5310, 0x12ff,
+ 0x5311, 0x2a02,
+ 0x5315, 0x1266,
+ 0x5316, 0x07c4,
+ 0x5317, 0x041a,
+ 0x5318, 0x2a06,
+ 0x5319, 0x04fc,
+ 0x531a, 0x1284,
+ 0x531b, 0x2a07,
+ 0x531d, 0x1114,
+ 0x531e, 0x2a09,
+ 0x5320, 0x0884,
+ 0x5321, 0x097c,
+ 0x5322, 0x2a0b,
+ 0x5323, 0x0f28,
+ 0x5324, 0x2a0c,
+ 0x5326, 0x1286,
+ 0x5327, 0x2a0e,
+ 0x532a, 0x0668,
+ 0x532b, 0x2a11,
+ 0x532d, 0x22c5,
+ 0x532e, 0x1287,
+ 0x532f, 0x1f5e,
+ 0x5330, 0x2a13,
+ 0x5331, 0x22c6,
+ 0x5332, 0x2a14,
+ 0x5339, 0x0bc4,
+ 0x533a, 0x0c75,
+ 0x533b, 0x1044,
+ 0x533c, 0x2a1b,
+ 0x533e, 0x1288,
+ 0x533f, 0x0b47,
+ 0x5340, 0x20ef,
+ 0x5341, 0x0d45,
+ 0x5342, 0x2a1d,
+ 0x5343, 0x0c24,
+ 0x5344, 0x2a1e,
+ 0x5345, 0x125c,
+ 0x5346, 0x2a1f,
+ 0x5347, 0x0d36,
+ 0x5348, 0x0ef6,
+ 0x5349, 0x07f1,
+ 0x534a, 0x03f6,
+ 0x534b, 0x2a20,
+ 0x534e, 0x07bf,
+ 0x534f, 0x0f78,
+ 0x5350, 0x2a23,
+ 0x5351, 0x0419,
+ 0x5352, 0x1241,
+ 0x5353, 0x121c,
+ 0x5354, 0x21d0,
+ 0x5355, 0x0586,
+ 0x5356, 0x0a9b,
+ 0x5357, 0x0b32,
+ 0x5358, 0x2a24,
+ 0x535a, 0x0470,
+ 0x535b, 0x2a26,
+ 0x535c, 0x047e,
+ 0x535d, 0x2a27,
+ 0x535e, 0x044e,
+ 0x535f, 0x14fa,
+ 0x5360, 0x115d,
+ 0x5361, 0x0935,
+ 0x5362, 0x0a53,
+ 0x5363, 0x128b,
+ 0x5364, 0x0a58,
+ 0x5365, 0x2a28,
+ 0x5366, 0x128a,
+ 0x5367, 0x0ee3,
+ 0x5368, 0x2a29,
+ 0x5369, 0x1352,
+ 0x536a, 0x2a2a,
+ 0x536b, 0x0ecf,
+ 0x536c, 0x2a2b,
+ 0x536e, 0x126a,
+ 0x536f, 0x0ab3,
+ 0x5370, 0x1086,
+ 0x5371, 0x0eb2,
+ 0x5372, 0x2a2d,
+ 0x5373, 0x0827,
+ 0x5374, 0x0c8f,
+ 0x5375, 0x0a78,
+ 0x5376, 0x2a2e,
+ 0x5377, 0x091c,
+ 0x5378, 0x0f81,
+ 0x5379, 0x2a2f,
+ 0x537a, 0x1353,
+ 0x537b, 0x2a30,
+ 0x537f, 0x0c61,
+ 0x5380, 0x2a34,
+ 0x5382, 0x04cc,
+ 0x5383, 0x2a36,
+ 0x5384, 0x0631,
+ 0x5385, 0x0e4f,
+ 0x5386, 0x09e5,
+ 0x5387, 0x2a37,
+ 0x5389, 0x09e2,
+ 0x538a, 0x2a39,
+ 0x538b, 0x0fe2,
+ 0x538c, 0x100a,
+ 0x538d, 0x127d,
+ 0x538e, 0x2a3a,
+ 0x5395, 0x04a5,
+ 0x5396, 0x2a41,
+ 0x5398, 0x09d0,
+ 0x5399, 0x22c1,
+ 0x539a, 0x07a8,
+ 0x539b, 0x2a43,
+ 0x539d, 0x127e,
+ 0x539e, 0x2a45,
+ 0x539f, 0x10f0,
+ 0x53a0, 0x1e64,
+ 0x53a1, 0x2a46,
+ 0x53a2, 0x0f4e,
+ 0x53a3, 0x127f,
+ 0x53a4, 0x2a47,
+ 0x53a5, 0x1280,
+ 0x53a6, 0x0f30,
+ 0x53a7, 0x2a48,
+ 0x53a8, 0x051d,
+ 0x53a9, 0x08f6,
+ 0x53aa, 0x2a49,
+ 0x53ad, 0x21f9,
+ 0x53ae, 0x1281,
+ 0x53af, 0x2a4c,
+ 0x53b2, 0x2010,
+ 0x53b3, 0x2a4f,
+ 0x53b4, 0x22c2,
+ 0x53b5, 0x2a50,
+ 0x53b6, 0x139c,
+ 0x53b7, 0x2a51,
+ 0x53bb, 0x0c80,
+ 0x53bc, 0x2a55,
+ 0x53bf, 0x0f45,
+ 0x53c0, 0x2a58,
+ 0x53c1, 0x0cd9,
+ 0x53c2, 0x0495,
+ 0x53c3, 0x1e5a,
+ 0x53c4, 0x2a59,
+ 0x53c8, 0x10bb,
+ 0x53c9, 0x04ad,
+ 0x53ca, 0x0823,
+ 0x53cb, 0x10b6,
+ 0x53cc, 0x0da0,
+ 0x53cd, 0x0651,
+ 0x53ce, 0x2a5d,
+ 0x53d1, 0x063f,
+ 0x53d2, 0x2a60,
+ 0x53d4, 0x0d7c,
+ 0x53d5, 0x2a62,
+ 0x53d6, 0x0c7c,
+ 0x53d7, 0x0d73,
+ 0x53d8, 0x044d,
+ 0x53d9, 0x0fbb,
+ 0x53da, 0x2a63,
+ 0x53db, 0x0b92,
+ 0x53dc, 0x2a64,
+ 0x53df, 0x1395,
+ 0x53e0, 0x05df,
+ 0x53e1, 0x2a67,
+ 0x53e2, 0x1ea2,
+ 0x53e3, 0x0967,
+ 0x53e4, 0x071e,
+ 0x53e5, 0x0913,
+ 0x53e6, 0x0a36,
+ 0x53e7, 0x2a68,
+ 0x53e8, 0x14fe,
+ 0x53e9, 0x14fd,
+ 0x53ea, 0x11ba,
+ 0x53eb, 0x08a1,
+ 0x53ec, 0x117a,
+ 0x53ed, 0x03d3,
+ 0x53ee, 0x05e2,
+ 0x53ef, 0x0956,
+ 0x53f0, 0x0dfb,
+ 0x53f1, 0x14fb,
+ 0x53f2, 0x0d4e,
+ 0x53f3, 0x10b7,
+ 0x53f4, 0x2a69,
+ 0x53f5, 0x1285,
+ 0x53f6, 0x103d,
+ 0x53f7, 0x077c,
+ 0x53f8, 0x0db3,
+ 0x53f9, 0x0e11,
+ 0x53fa, 0x2a6a,
+ 0x53fb, 0x14ff,
+ 0x53fc, 0x05d1,
+ 0x53fd, 0x14fc,
+ 0x53fe, 0x2a6b,
+ 0x5400, 0x2a6d,
+ 0x5401, 0x10da,
+ 0x5402, 0x2a6e,
+ 0x5403, 0x04f9,
+ 0x5404, 0x06f2,
+ 0x5405, 0x2a6f,
+ 0x5406, 0x1502,
+ 0x5407, 0x2a70,
+ 0x5408, 0x0786,
+ 0x5409, 0x081d,
+ 0x540a, 0x05d6,
+ 0x540b, 0x2a71,
+ 0x540c, 0x0e5d,
+ 0x540d, 0x0b00,
+ 0x540e, 0x07aa,
+ 0x540f, 0x09df,
+ 0x5410, 0x0e73,
+ 0x5411, 0x0f5f,
+ 0x5412, 0x1500,
+ 0x5413, 0x0f32,
+ 0x5414, 0x2a72,
+ 0x5415, 0x0a67,
+ 0x5416, 0x1501,
+ 0x5417, 0x0a97,
+ 0x5418, 0x2a73,
+ 0x541b, 0x092c,
+ 0x541c, 0x2a76,
+ 0x541d, 0x0a28,
+ 0x541e, 0x0e7d,
+ 0x541f, 0x107e,
+ 0x5420, 0x066a,
+ 0x5421, 0x1509,
+ 0x5422, 0x2a77,
+ 0x5423, 0x150c,
+ 0x5424, 0x2a78,
+ 0x5426, 0x068e,
+ 0x5427, 0x03d4,
+ 0x5428, 0x0615,
+ 0x5429, 0x0671,
+ 0x542a, 0x2a7a,
+ 0x542b, 0x0763,
+ 0x542c, 0x0e50,
+ 0x542d, 0x0961,
+ 0x542e, 0x0da6,
+ 0x542f, 0x0c13,
+ 0x5430, 0x2a7b,
+ 0x5431, 0x11a7,
+ 0x5432, 0x150d,
+ 0x5433, 0x2a7c,
+ 0x5434, 0x0ef1,
+ 0x5435, 0x04d8,
+ 0x5436, 0x2a7d,
+ 0x5438, 0x0f0b,
+ 0x5439, 0x0538,
+ 0x543a, 0x2a7f,
+ 0x543b, 0x0ed6,
+ 0x543c, 0x07a7,
+ 0x543d, 0x2a80,
+ 0x543e, 0x0ef0,
+ 0x543f, 0x2a81,
+ 0x5440, 0x0fe6,
+ 0x5441, 0x2a82,
+ 0x5443, 0x1508,
+ 0x5444, 0x2a84,
+ 0x5446, 0x0577,
+ 0x5447, 0x2a86,
+ 0x5448, 0x04ef,
+ 0x5449, 0x2a87,
+ 0x544a, 0x06e1,
+ 0x544b, 0x1503,
+ 0x544c, 0x2a88,
+ 0x5450, 0x0b28,
+ 0x5451, 0x2a8c,
+ 0x5452, 0x1504,
+ 0x5455, 0x0b7c,
+ 0x5456, 0x1507,
+ 0x5457, 0x150a,
+ 0x5458, 0x10f4,
+ 0x5459, 0x150b,
+ 0x545a, 0x2a8d,
+ 0x545b, 0x0c37,
+ 0x545c, 0x0ee7,
+ 0x545d, 0x2a8e,
+ 0x5462, 0x0b3b,
+ 0x5463, 0x2a93,
+ 0x5464, 0x1512,
+ 0x5465, 0x2a94,
+ 0x5466, 0x1517,
+ 0x5467, 0x2a95,
+ 0x5468, 0x11db,
+ 0x5469, 0x2a96,
+ 0x5471, 0x1511,
+ 0x5472, 0x1522,
+ 0x5473, 0x0ec5,
+ 0x5474, 0x2a9e,
+ 0x5475, 0x077e,
+ 0x5476, 0x1516,
+ 0x5477, 0x1510,
+ 0x5478, 0x0b9f,
+ 0x5479, 0x2a9f,
+ 0x547b, 0x0d24,
+ 0x547c, 0x07ab,
+ 0x547d, 0x0b01,
+ 0x547e, 0x2aa1,
+ 0x5480, 0x0906,
+ 0x5481, 0x2aa3,
+ 0x5482, 0x150e,
+ 0x5483, 0x2aa4,
+ 0x5484, 0x1515,
+ 0x5485, 0x2aa5,
+ 0x5486, 0x0b99,
+ 0x5487, 0x2aa6,
+ 0x548b, 0x1147,
+ 0x548c, 0x0784,
+ 0x548d, 0x2aaa,
+ 0x548e, 0x08fb,
+ 0x548f, 0x10a2,
+ 0x5490, 0x06bb,
+ 0x5491, 0x2aab,
+ 0x5492, 0x11e3,
+ 0x5493, 0x2aac,
+ 0x5494, 0x150f,
+ 0x5495, 0x0717,
+ 0x5496, 0x0934,
+ 0x5497, 0x2aad,
+ 0x5499, 0x0a45,
+ 0x549a, 0x1513,
+ 0x549c, 0x2aaf,
+ 0x549d, 0x1518,
+ 0x549e, 0x2ab0,
+ 0x54a3, 0x1523,
+ 0x54a4, 0x152d,
+ 0x54a5, 0x2ab5,
+ 0x54a6, 0x151f,
+ 0x54a7, 0x151e,
+ 0x54a8, 0x1226,
+ 0x54a9, 0x152b,
+ 0x54ab, 0x1767,
+ 0x54ac, 0x102e,
+ 0x54ad, 0x151a,
+ 0x54ae, 0x2ab6,
+ 0x54af, 0x0936,
+ 0x54b0, 0x2ab7,
+ 0x54b1, 0x111e,
+ 0x54b2, 0x2ab8,
+ 0x54b3, 0x0955,
+ 0x54b4, 0x151c,
+ 0x54b5, 0x2ab9,
+ 0x54b8, 0x0f39,
+ 0x54b9, 0x2abc,
+ 0x54bb, 0x1525,
+ 0x54bc, 0x236d,
+ 0x54bd, 0x0ff3,
+ 0x54be, 0x2abe,
+ 0x54bf, 0x1526,
+ 0x54c0, 0x03b2,
+ 0x54c1, 0x0bd6,
+ 0x54c2, 0x151b,
+ 0x54c3, 0x2abf,
+ 0x54c4, 0x079c,
+ 0x54c5, 0x2ac0,
+ 0x54c6, 0x061e,
+ 0x54c7, 0x0e8c,
+ 0x54c8, 0x0757,
+ 0x54c9, 0x1118,
+ 0x54ca, 0x2ac1,
+ 0x54cc, 0x1527,
+ 0x54cd, 0x0f59,
+ 0x54ce, 0x03b0,
+ 0x54cf, 0x152f,
+ 0x54d0, 0x1519,
+ 0x54d1, 0x0fef,
+ 0x54d2, 0x151d,
+ 0x54d3, 0x1520,
+ 0x54d5, 0x1524,
+ 0x54d6, 0x2ac3,
+ 0x54d7, 0x07be,
+ 0x54d8, 0x2ac4,
+ 0x54d9, 0x1528,
+ 0x54db, 0x2ac5,
+ 0x54dc, 0x152a,
+ 0x54dd, 0x152e,
+ 0x54de, 0x1530,
+ 0x54df, 0x1099,
+ 0x54e0, 0x2ac6,
+ 0x54e1, 0x2247,
+ 0x54e2, 0x2ac7,
+ 0x54e5, 0x06e2,
+ 0x54e6, 0x0b77,
+ 0x54e7, 0x1532,
+ 0x54e8, 0x0d13,
+ 0x54e9, 0x09f1,
+ 0x54ea, 0x0b27,
+ 0x54eb, 0x2aca,
+ 0x54ed, 0x096b,
+ 0x54ee, 0x0f65,
+ 0x54ef, 0x2acc,
+ 0x54f2, 0x117d,
+ 0x54f3, 0x1536,
+ 0x54f4, 0x2acf,
+ 0x54fa, 0x047f,
+ 0x54fb, 0x2ad5,
+ 0x54fc, 0x0796,
+ 0x54fd, 0x1534,
+ 0x54fe, 0x2ad6,
+ 0x54ff, 0x1391,
+ 0x5500, 0x2ad7,
+ 0x5501, 0x100d,
+ 0x5502, 0x2ad8,
+ 0x5504, 0x236c,
+ 0x5505, 0x2ada,
+ 0x5506, 0x0de9,
+ 0x5507, 0x0540,
+ 0x5508, 0x2adb,
+ 0x5509, 0x03b1,
+ 0x550a, 0x2adc,
+ 0x550f, 0x1539,
+ 0x5510, 0x0e19,
+ 0x5511, 0x153a,
+ 0x5512, 0x2ae1,
+ 0x5514, 0x1535,
+ 0x5515, 0x2ae3,
+ 0x551b, 0x1531,
+ 0x551c, 0x2ae9,
+ 0x5520, 0x1533,
+ 0x5521, 0x2aed,
+ 0x5522, 0x1537,
+ 0x5524, 0x07d2,
+ 0x5525, 0x2aee,
+ 0x5527, 0x153b,
+ 0x5528, 0x2af0,
+ 0x552a, 0x153c,
+ 0x552b, 0x2af2,
+ 0x552c, 0x07b8,
+ 0x552d, 0x2af3,
+ 0x552e, 0x0d72,
+ 0x552f, 0x0eb7,
+ 0x5530, 0x154d,
+ 0x5531, 0x04cf,
+ 0x5532, 0x2af4,
+ 0x5533, 0x154c,
+ 0x5534, 0x2af5,
+ 0x5537, 0x1547,
+ 0x5538, 0x2af8,
+ 0x553c, 0x1546,
+ 0x553d, 0x2afc,
+ 0x553e, 0x0e8a,
+ 0x553f, 0x1544,
+ 0x5540, 0x2afd,
+ 0x5541, 0x1542,
+ 0x5542, 0x2afe,
+ 0x5543, 0x095d,
+ 0x5544, 0x1221,
+ 0x5545, 0x2aff,
+ 0x5546, 0x0d05,
+ 0x5547, 0x2b00,
+ 0x5549, 0x1540,
+ 0x554a, 0x03ac,
+ 0x554b, 0x2b02,
+ 0x554f, 0x219c,
+ 0x5550, 0x1545,
+ 0x5551, 0x2b06,
+ 0x5553, 0x20c9,
+ 0x5554, 0x2b08,
+ 0x5555, 0x1543,
+ 0x5556, 0x1548,
+ 0x5557, 0x2b09,
+ 0x555c, 0x154e,
+ 0x555d, 0x2b0e,
+ 0x555e, 0x21f0,
+ 0x555f, 0x2b0f,
+ 0x5561, 0x0665,
+ 0x5562, 0x2b11,
+ 0x5564, 0x0bc0,
+ 0x5565, 0x0cef,
+ 0x5566, 0x099d,
+ 0x5567, 0x153d,
+ 0x5568, 0x2b13,
+ 0x556a, 0x0b7f,
+ 0x556b, 0x2b15,
+ 0x556c, 0x127a,
+ 0x556d, 0x1541,
+ 0x556e, 0x0b59,
+ 0x556f, 0x2b16,
+ 0x5575, 0x1549,
+ 0x5578, 0x0f70,
+ 0x5579, 0x2b1c,
+ 0x557b, 0x155a,
+ 0x557c, 0x0e37,
+ 0x557d, 0x2b1e,
+ 0x557e, 0x1557,
+ 0x557f, 0x2b1f,
+ 0x5580, 0x0933,
+ 0x5581, 0x1555,
+ 0x5582, 0x0ec8,
+ 0x5583, 0x1551,
+ 0x5584, 0x0cff,
+ 0x5585, 0x2b20,
+ 0x5587, 0x0999,
+ 0x5588, 0x1554,
+ 0x5589, 0x07a4,
+ 0x558a, 0x0767,
+ 0x558b, 0x154f,
+ 0x558c, 0x2b22,
+ 0x558f, 0x153e,
+ 0x5590, 0x2b25,
+ 0x5591, 0x1559,
+ 0x5592, 0x2b26,
+ 0x5594, 0x155e,
+ 0x5595, 0x2b28,
+ 0x5598, 0x0530,
+ 0x5599, 0x155f,
+ 0x559a, 0x2b2b,
+ 0x559c, 0x0f1f,
+ 0x559d, 0x077f,
+ 0x559e, 0x2b2d,
+ 0x559f, 0x1556,
+ 0x55a0, 0x2b2e,
+ 0x55a7, 0x0fc5,
+ 0x55a8, 0x2b35,
+ 0x55aa, 0x210b,
+ 0x55ab, 0x2b37,
+ 0x55ac, 0x20de,
+ 0x55ad, 0x2b38,
+ 0x55ae, 0x1eaa,
+ 0x55af, 0x2b39,
+ 0x55b1, 0x1552,
+ 0x55b2, 0x222c,
+ 0x55b3, 0x113e,
+ 0x55b4, 0x2b3b,
+ 0x55b5, 0x153f,
+ 0x55b6, 0x2b3c,
+ 0x55b7, 0x0ba8,
+ 0x55b8, 0x2b3d,
+ 0x55b9, 0x1553,
+ 0x55ba, 0x2b3e,
+ 0x55bb, 0x10dc,
+ 0x55bc, 0x2b3f,
+ 0x55bd, 0x155c,
+ 0x55bf, 0x2b40,
+ 0x55c4, 0x156a,
+ 0x55c5, 0x0fac,
+ 0x55c6, 0x20d8,
+ 0x55c7, 0x22c0,
+ 0x55c8, 0x2b45,
+ 0x55c9, 0x1562,
+ 0x55ca, 0x2b46,
+ 0x55cc, 0x156f,
+ 0x55ce, 0x206f,
+ 0x55cf, 0x2b48,
+ 0x55d1, 0x1564,
+ 0x55d2, 0x1550,
+ 0x55d3, 0x0cdd,
+ 0x55d4, 0x1567,
+ 0x55d5, 0x2b4a,
+ 0x55d6, 0x1558,
+ 0x55d7, 0x2b4b,
+ 0x55da, 0x21a1,
+ 0x55db, 0x2b4e,
+ 0x55dc, 0x0d5f,
+ 0x55dd, 0x1569,
+ 0x55de, 0x2b4f,
+ 0x55df, 0x155b,
+ 0x55e0, 0x2b50,
+ 0x55e1, 0x0eda,
+ 0x55e2, 0x2b51,
+ 0x55e3, 0x0db8,
+ 0x55e4, 0x1573,
+ 0x55e5, 0x156c,
+ 0x55e6, 0x1568,
+ 0x55e7, 0x2b52,
+ 0x55e8, 0x1571,
+ 0x55e9, 0x2379,
+ 0x55ea, 0x1560,
+ 0x55eb, 0x1565,
+ 0x55ed, 0x2b53,
+ 0x55ef, 0x156b,
+ 0x55f0, 0x2b55,
+ 0x55f2, 0x156d,
+ 0x55f4, 0x2b57,
+ 0x55f5, 0x1572,
+ 0x55f6, 0x2372,
+ 0x55f7, 0x1561,
+ 0x55f8, 0x2b58,
+ 0x55fd, 0x0dc9,
+ 0x55fe, 0x157b,
+ 0x55ff, 0x2b5d,
+ 0x5600, 0x157c,
+ 0x5601, 0x1578,
+ 0x5602, 0x2b5e,
+ 0x5606, 0x216a,
+ 0x5607, 0x2b62,
+ 0x5608, 0x1576,
+ 0x5609, 0x0841,
+ 0x560a, 0x2b63,
+ 0x560c, 0x1577,
+ 0x560d, 0x237c,
+ 0x560e, 0x06bd,
+ 0x560f, 0x127b,
+ 0x5610, 0x2b65,
+ 0x5614, 0x20b0,
+ 0x5615, 0x2b69,
+ 0x5616, 0x237a,
+ 0x5617, 0x1e74,
+ 0x5618, 0x0fb5,
+ 0x5619, 0x2b6a,
+ 0x561b, 0x0a96,
+ 0x561c, 0x2377,
+ 0x561d, 0x2b6c,
+ 0x561e, 0x1575,
+ 0x561f, 0x1563,
+ 0x5620, 0x2b6d,
+ 0x5623, 0x157a,
+ 0x5624, 0x1579,
+ 0x5625, 0x2b70,
+ 0x5627, 0x157d,
+ 0x5628, 0x2b72,
+ 0x5629, 0x1f4c,
+ 0x562a, 0x2b73,
+ 0x562c, 0x1582,
+ 0x562d, 0x157e,
+ 0x562e, 0x2378,
+ 0x562f, 0x21cf,
+ 0x5630, 0x2368,
+ 0x5631, 0x11f5,
+ 0x5632, 0x04d5,
+ 0x5633, 0x2b75,
+ 0x5634, 0x1249,
+ 0x5635, 0x2371,
+ 0x5636, 0x0db0,
+ 0x5637, 0x2b76,
+ 0x5638, 0x2369,
+ 0x5639, 0x1580,
+ 0x563a, 0x2b77,
+ 0x563b, 0x0f0a,
+ 0x563c, 0x2b78,
+ 0x563f, 0x0790,
+ 0x5640, 0x2b7b,
+ 0x5641, 0x2674,
+ 0x5642, 0x2b7c,
+ 0x564c, 0x1587,
+ 0x564d, 0x1583,
+ 0x564e, 0x1034,
+ 0x564f, 0x2b86,
+ 0x5654, 0x1588,
+ 0x5655, 0x2b8b,
+ 0x5657, 0x1581,
+ 0x5658, 0x157f,
+ 0x5659, 0x1585,
+ 0x565a, 0x2b8d,
+ 0x565c, 0x1586,
+ 0x565d, 0x236f,
+ 0x565e, 0x2b8f,
+ 0x5660, 0x2370,
+ 0x5661, 0x2b91,
+ 0x5662, 0x1584,
+ 0x5663, 0x2b92,
+ 0x5664, 0x158a,
+ 0x5665, 0x2376,
+ 0x5666, 0x2373,
+ 0x5667, 0x2b93,
+ 0x5668, 0x0c16,
+ 0x5669, 0x1262,
+ 0x566a, 0x112e,
+ 0x566b, 0x158c,
+ 0x566c, 0x0d60,
+ 0x566d, 0x2b94,
+ 0x566f, 0x237f,
+ 0x5670, 0x2b96,
+ 0x5671, 0x158b,
+ 0x5672, 0x2374,
+ 0x5673, 0x2b97,
+ 0x5674, 0x20b5,
+ 0x5675, 0x2b98,
+ 0x5676, 0x06bc,
+ 0x5677, 0x2b99,
+ 0x5678, 0x1edb,
+ 0x5679, 0x2672,
+ 0x567a, 0x2b9a,
+ 0x567b, 0x158d,
+ 0x567d, 0x2b9b,
+ 0x5680, 0x236e,
+ 0x5681, 0x2b9e,
+ 0x5685, 0x158f,
+ 0x5686, 0x1589,
+ 0x5687, 0x21b7,
+ 0x5688, 0x2ba2,
+ 0x568c, 0x2375,
+ 0x568d, 0x2ba6,
+ 0x568e, 0x0776,
+ 0x568f, 0x0e3a,
+ 0x5690, 0x2ba7,
+ 0x5693, 0x1590,
+ 0x5694, 0x2baa,
+ 0x5695, 0x2382,
+ 0x5696, 0x2bab,
+ 0x5699, 0x209e,
+ 0x569a, 0x2bae,
+ 0x56a3, 0x0f66,
+ 0x56a4, 0x2bb7,
+ 0x56a6, 0x236b,
+ 0x56a7, 0x2bb9,
+ 0x56a8, 0x2039,
+ 0x56a9, 0x2bba,
+ 0x56ae, 0x269f,
+ 0x56af, 0x1591,
+ 0x56b0, 0x2bbf,
+ 0x56b3, 0x237d,
+ 0x56b4, 0x21f5,
+ 0x56b5, 0x2bc2,
+ 0x56b6, 0x2381,
+ 0x56b7, 0x0c9d,
+ 0x56b8, 0x2bc3,
+ 0x56bc, 0x0891,
+ 0x56bd, 0x2bc7,
+ 0x56c0, 0x237b,
+ 0x56c1, 0x237e,
+ 0x56c2, 0x21cc,
+ 0x56c3, 0x2bca,
+ 0x56c5, 0x22db,
+ 0x56c6, 0x2bcc,
+ 0x56c8, 0x236a,
+ 0x56c9, 0x2689,
+ 0x56ca, 0x0b35,
+ 0x56cb, 0x2bce,
+ 0x56cc, 0x2697,
+ 0x56cd, 0x2bcf,
+ 0x56d1, 0x22a1,
+ 0x56d2, 0x2bd3,
+ 0x56d4, 0x1592,
+ 0x56d5, 0x2bd5,
+ 0x56d7, 0x1593,
+ 0x56d8, 0x2bd7,
+ 0x56da, 0x0c71,
+ 0x56db, 0x0db9,
+ 0x56dc, 0x2bd9,
+ 0x56dd, 0x1594,
+ 0x56de, 0x07ed,
+ 0x56df, 0x126c,
+ 0x56e0, 0x1079,
+ 0x56e1, 0x1595,
+ 0x56e2, 0x0e76,
+ 0x56e3, 0x2bda,
+ 0x56e4, 0x0619,
+ 0x56e5, 0x2bdb,
+ 0x56eb, 0x1597,
+ 0x56ec, 0x2be1,
+ 0x56ed, 0x10f3,
+ 0x56ee, 0x2be2,
+ 0x56f0, 0x0992,
+ 0x56f1, 0x0554,
+ 0x56f2, 0x2be4,
+ 0x56f4, 0x0eb6,
+ 0x56f5, 0x1596,
+ 0x56f6, 0x2be6,
+ 0x56f9, 0x1598,
+ 0x56fa, 0x0725,
+ 0x56fb, 0x2be9,
+ 0x56fd, 0x0753,
+ 0x56fe, 0x0e6d,
+ 0x56ff, 0x1599,
+ 0x5700, 0x2beb,
+ 0x5703, 0x0bf3,
+ 0x5704, 0x159a,
+ 0x5705, 0x2bee,
+ 0x5706, 0x10f5,
+ 0x5707, 0x2383,
+ 0x5708, 0x0c81,
+ 0x5709, 0x159c,
+ 0x570a, 0x159b,
+ 0x570b, 0x1f3d,
+ 0x570c, 0x2bef,
+ 0x570d, 0x218f,
+ 0x570e, 0x2bf0,
+ 0x5712, 0x2246,
+ 0x5713, 0x2248,
+ 0x5714, 0x2bf4,
+ 0x5716, 0x217e,
+ 0x5717, 0x2bf6,
+ 0x5718, 0x2180,
+ 0x5719, 0x2bf7,
+ 0x571c, 0x159d,
+ 0x571d, 0x2bfa,
+ 0x571f, 0x0e72,
+ 0x5720, 0x2bfc,
+ 0x5723, 0x0d3c,
+ 0x5724, 0x2bff,
+ 0x5728, 0x111d,
+ 0x5729, 0x13a7,
+ 0x572a, 0x13a9,
+ 0x572b, 0x2c03,
+ 0x572c, 0x13a8,
+ 0x572d, 0x0740,
+ 0x572e, 0x13ac,
+ 0x5730, 0x05b9,
+ 0x5731, 0x2c04,
+ 0x5733, 0x13aa,
+ 0x5734, 0x2c06,
+ 0x5739, 0x13ab,
+ 0x573a, 0x04c6,
+ 0x573b, 0x13af,
+ 0x573c, 0x2c0b,
+ 0x573e, 0x080d,
+ 0x573f, 0x2c0d,
+ 0x5740, 0x11b6,
+ 0x5741, 0x2c0e,
+ 0x5742, 0x13b0,
+ 0x5743, 0x2c0f,
+ 0x5747, 0x0928,
+ 0x5748, 0x2c13,
+ 0x574a, 0x0658,
+ 0x574b, 0x2c15,
+ 0x574c, 0x13a0,
+ 0x574d, 0x0e01,
+ 0x574e, 0x093f,
+ 0x574f, 0x07ca,
+ 0x5750, 0x1255,
+ 0x5751, 0x0960,
+ 0x5752, 0x2c16,
+ 0x5757, 0x0976,
+ 0x5758, 0x2c1b,
+ 0x575a, 0x0854,
+ 0x575b, 0x0e06,
+ 0x575c, 0x13ae,
+ 0x575d, 0x03de,
+ 0x575e, 0x0efa,
+ 0x575f, 0x0675,
+ 0x5760, 0x1216,
+ 0x5761, 0x0be1,
+ 0x5762, 0x2c1d,
+ 0x5764, 0x098f,
+ 0x5765, 0x2c1f,
+ 0x5766, 0x0e0c,
+ 0x5767, 0x2c20,
+ 0x5768, 0x13b7,
+ 0x5769, 0x13b1,
+ 0x576a, 0x0bd9,
+ 0x576b, 0x13b3,
+ 0x576c, 0x2c21,
+ 0x576d, 0x13b8,
+ 0x576e, 0x2c22,
+ 0x576f, 0x0bb8,
+ 0x5770, 0x2c23,
+ 0x5773, 0x13ba,
+ 0x5774, 0x2c26,
+ 0x5776, 0x13b9,
+ 0x5777, 0x094d,
+ 0x5778, 0x2c28,
+ 0x577b, 0x13b6,
+ 0x577c, 0x13b5,
+ 0x577d, 0x2c2b,
+ 0x5782, 0x053c,
+ 0x5783, 0x0997,
+ 0x5784, 0x0a49,
+ 0x5785, 0x13b2,
+ 0x5786, 0x13b4,
+ 0x5787, 0x2c30,
+ 0x578b, 0x0f98,
+ 0x578c, 0x13bd,
+ 0x578d, 0x2c34,
+ 0x5792, 0x09c8,
+ 0x5793, 0x13c2,
+ 0x5794, 0x2c39,
+ 0x579b, 0x0621,
+ 0x579c, 0x2c40,
+ 0x57a0, 0x13c3,
+ 0x57a1, 0x13a2,
+ 0x57a2, 0x0711,
+ 0x57a3, 0x10ee,
+ 0x57a4, 0x13bc,
+ 0x57a5, 0x2c44,
+ 0x57a6, 0x095e,
+ 0x57a7, 0x13c0,
+ 0x57a8, 0x2c45,
+ 0x57a9, 0x13a1,
+ 0x57aa, 0x2c46,
+ 0x57ab, 0x05c7,
+ 0x57ac, 0x2c47,
+ 0x57ad, 0x13bb,
+ 0x57ae, 0x0972,
+ 0x57af, 0x2c48,
+ 0x57b2, 0x13be,
+ 0x57b3, 0x2c4b,
+ 0x57b4, 0x13c1,
+ 0x57b5, 0x2c4c,
+ 0x57b8, 0x13c9,
+ 0x57b9, 0x2c4f,
+ 0x57c2, 0x06fa,
+ 0x57c3, 0x03ae,
+ 0x57c4, 0x2c58,
+ 0x57cb, 0x0a98,
+ 0x57cc, 0x2c5f,
+ 0x57ce, 0x04ec,
+ 0x57cf, 0x13bf,
+ 0x57d0, 0x2c61,
+ 0x57d2, 0x13c8,
+ 0x57d3, 0x2c63,
+ 0x57d4, 0x0bf1,
+ 0x57d5, 0x13c4,
+ 0x57d6, 0x2c64,
+ 0x57d8, 0x13c5,
+ 0x57d9, 0x13c7,
+ 0x57da, 0x13c6,
+ 0x57db, 0x2c66,
+ 0x57dd, 0x13ce,
+ 0x57de, 0x2c68,
+ 0x57df, 0x10d7,
+ 0x57e0, 0x0481,
+ 0x57e1, 0x232a,
+ 0x57e2, 0x2c69,
+ 0x57e4, 0x13cd,
+ 0x57e5, 0x2c6b,
+ 0x57ed, 0x13d2,
+ 0x57ee, 0x2c73,
+ 0x57ef, 0x13cb,
+ 0x57f0, 0x2c74,
+ 0x57f4, 0x13ca,
+ 0x57f5, 0x2c78,
+ 0x57f7, 0x228b,
+ 0x57f8, 0x13cc,
+ 0x57f9, 0x0ba1,
+ 0x57fa, 0x080e,
+ 0x57fb, 0x2c7a,
+ 0x57fd, 0x13d1,
+ 0x57fe, 0x2c7c,
+ 0x5800, 0x13d3,
+ 0x5801, 0x2c7e,
+ 0x5802, 0x0e16,
+ 0x5803, 0x2c7f,
+ 0x5805, 0x1f85,
+ 0x5806, 0x0610,
+ 0x5807, 0x144c,
+ 0x5808, 0x2c81,
+ 0x580a, 0x2325,
+ 0x580b, 0x13cf,
+ 0x580c, 0x2c83,
+ 0x580d, 0x13d0,
+ 0x580e, 0x2c84,
+ 0x5811, 0x0c32,
+ 0x5812, 0x2c87,
+ 0x5815, 0x0628,
+ 0x5816, 0x232c,
+ 0x5817, 0x2c8a,
+ 0x5819, 0x13d5,
+ 0x581a, 0x2c8c,
+ 0x581d, 0x232e,
+ 0x581e, 0x13d4,
+ 0x581f, 0x2c8f,
+ 0x5820, 0x13d7,
+ 0x5821, 0x040d,
+ 0x5822, 0x2c90,
+ 0x5824, 0x05ad,
+ 0x5825, 0x2c92,
+ 0x582a, 0x093d,
+ 0x582b, 0x2c97,
+ 0x582f, 0x2205,
+ 0x5830, 0x1008,
+ 0x5831, 0x1e38,
+ 0x5832, 0x2c9b,
+ 0x5834, 0x1e73,
+ 0x5835, 0x0601,
+ 0x5836, 0x2c9d,
+ 0x5844, 0x13d6,
+ 0x5845, 0x2cab,
+ 0x584a, 0x1fe3,
+ 0x584b, 0x2339,
+ 0x584c, 0x0def,
+ 0x584d, 0x19a3,
+ 0x584e, 0x2cb0,
+ 0x584f, 0x232b,
+ 0x5850, 0x2cb1,
+ 0x5851, 0x0dd1,
+ 0x5852, 0x232d,
+ 0x5853, 0x2cb2,
+ 0x5854, 0x0df3,
+ 0x5855, 0x2cb3,
+ 0x5857, 0x217f,
+ 0x5858, 0x0e14,
+ 0x5859, 0x2cb5,
+ 0x585e, 0x0cd6,
+ 0x585f, 0x2cba,
+ 0x5862, 0x21a7,
+ 0x5863, 0x2cbd,
+ 0x5864, 0x232f,
+ 0x5865, 0x13d8,
+ 0x5866, 0x2cbe,
+ 0x586b, 0x0e41,
+ 0x586c, 0x13d9,
+ 0x586d, 0x2cc3,
+ 0x5875, 0x1e7d,
+ 0x5876, 0x2ccb,
+ 0x5879, 0x20d6,
+ 0x587a, 0x2cce,
+ 0x587e, 0x13a3,
+ 0x587f, 0x2cd2,
+ 0x5880, 0x13dd,
+ 0x5881, 0x13da,
+ 0x5882, 0x2cd3,
+ 0x5883, 0x08e2,
+ 0x5884, 0x2cd4,
+ 0x5885, 0x0d92,
+ 0x5886, 0x2cd5,
+ 0x5889, 0x13db,
+ 0x588a, 0x1ec2,
+ 0x588b, 0x2cd8,
+ 0x5892, 0x0d03,
+ 0x5893, 0x0b1c,
+ 0x5894, 0x2cdf,
+ 0x5899, 0x0c3a,
+ 0x589a, 0x13dc,
+ 0x589b, 0x2ce4,
+ 0x589c, 0x22b2,
+ 0x589d, 0x2ce5,
+ 0x589e, 0x1139,
+ 0x589f, 0x0fb1,
+ 0x58a0, 0x2ce6,
+ 0x58a8, 0x0b0e,
+ 0x58a9, 0x0614,
+ 0x58aa, 0x2cee,
+ 0x58ae, 0x1edf,
+ 0x58af, 0x2cf2,
+ 0x58b3, 0x1ef9,
+ 0x58b4, 0x2cf6,
+ 0x58bb, 0x20d9,
+ 0x58bc, 0x13a4,
+ 0x58bd, 0x2cfd,
+ 0x58be, 0x1fdd,
+ 0x58bf, 0x2cfe,
+ 0x58c1, 0x0443,
+ 0x58c2, 0x2d00,
+ 0x58c5, 0x13a5,
+ 0x58c6, 0x2d03,
+ 0x58c7, 0x2167,
+ 0x58c8, 0x2d04,
+ 0x58d1, 0x13a6,
+ 0x58d2, 0x2d0d,
+ 0x58d3, 0x21ed,
+ 0x58d4, 0x2d0e,
+ 0x58d5, 0x0775,
+ 0x58d6, 0x2d0f,
+ 0x58d8, 0x2007,
+ 0x58d9, 0x2326,
+ 0x58da, 0x2329,
+ 0x58db, 0x2d11,
+ 0x58de, 0x1f52,
+ 0x58df, 0x203b,
+ 0x58e0, 0x2328,
+ 0x58e1, 0x2d14,
+ 0x58e2, 0x2327,
+ 0x58e3, 0x2d15,
+ 0x58e4, 0x0c9b,
+ 0x58e5, 0x2d16,
+ 0x58e9, 0x1e2b,
+ 0x58ea, 0x2d1a,
+ 0x58eb, 0x0d56,
+ 0x58ec, 0x0ca4,
+ 0x58ed, 0x2d1b,
+ 0x58ee, 0x1210,
+ 0x58ef, 0x22ae,
+ 0x58f0, 0x0d32,
+ 0x58f1, 0x2d1c,
+ 0x58f3, 0x0954,
+ 0x58f4, 0x2d1e,
+ 0x58f6, 0x07af,
+ 0x58f7, 0x2d20,
+ 0x58f9, 0x1043,
+ 0x58fa, 0x1f49,
+ 0x58fb, 0x2d22,
+ 0x58fd, 0x2138,
+ 0x58fe, 0x2d24,
+ 0x5900, 0x2d26,
+ 0x5902, 0x161c,
+ 0x5903, 0x2d28,
+ 0x5904, 0x0529,
+ 0x5905, 0x2d29,
+ 0x5907, 0x0421,
+ 0x5908, 0x2d2b,
+ 0x590d, 0x06af,
+ 0x590e, 0x2d30,
+ 0x590f, 0x0f31,
+ 0x5910, 0x2d31,
+ 0x5914, 0x12fb,
+ 0x5915, 0x0f13,
+ 0x5916, 0x0e93,
+ 0x5917, 0x2d35,
+ 0x5919, 0x1301,
+ 0x591a, 0x061f,
+ 0x591b, 0x2d37,
+ 0x591c, 0x1040,
+ 0x591d, 0x2d38,
+ 0x591f, 0x0714,
+ 0x5920, 0x2d3a,
+ 0x5922, 0x2081,
+ 0x5923, 0x2d3c,
+ 0x5924, 0x161b,
+ 0x5925, 0x1619,
+ 0x5926, 0x2d3d,
+ 0x5927, 0x0576,
+ 0x5928, 0x2d3e,
+ 0x5929, 0x0e3f,
+ 0x592a, 0x0dfe,
+ 0x592b, 0x068f,
+ 0x592c, 0x2d3f,
+ 0x592d, 0x1268,
+ 0x592e, 0x1014,
+ 0x592f, 0x0772,
+ 0x5930, 0x2d40,
+ 0x5931, 0x0d3e,
+ 0x5932, 0x2d41,
+ 0x5934, 0x0e68,
+ 0x5935, 0x2d43,
+ 0x5937, 0x104b,
+ 0x5938, 0x0971,
+ 0x5939, 0x0843,
+ 0x593a, 0x0620,
+ 0x593b, 0x2d45,
+ 0x593c, 0x14af,
+ 0x593d, 0x2d46,
+ 0x593e, 0x1f7c,
+ 0x593f, 0x2d47,
+ 0x5941, 0x14b0,
+ 0x5942, 0x138c,
+ 0x5943, 0x2d49,
+ 0x5944, 0x1002,
+ 0x5945, 0x2d4a,
+ 0x5947, 0x0c05,
+ 0x5948, 0x0b31,
+ 0x5949, 0x068b,
+ 0x594a, 0x2d4c,
+ 0x594b, 0x0679,
+ 0x594c, 0x2d4d,
+ 0x594e, 0x0989,
+ 0x594f, 0x123d,
+ 0x5950, 0x2d4f,
+ 0x5951, 0x0c14,
+ 0x5952, 0x2d50,
+ 0x5954, 0x0425,
+ 0x5955, 0x14b2,
+ 0x5956, 0x0882,
+ 0x5957, 0x0e2a,
+ 0x5958, 0x14b4,
+ 0x5959, 0x2d52,
+ 0x595a, 0x14b3,
+ 0x595b, 0x2d53,
+ 0x5960, 0x05cd,
+ 0x5961, 0x2d58,
+ 0x5962, 0x0d16,
+ 0x5963, 0x2d59,
+ 0x5965, 0x03cd,
+ 0x5966, 0x2d5b,
+ 0x5969, 0x235b,
+ 0x596a, 0x1ede,
+ 0x596b, 0x2d5e,
+ 0x596c, 0x1fa2,
+ 0x596d, 0x2d5f,
+ 0x596e, 0x1efa,
+ 0x596f, 0x2d60,
+ 0x5973, 0x0b6f,
+ 0x5974, 0x0b6c,
+ 0x5975, 0x2d64,
+ 0x5976, 0x0b2f,
+ 0x5977, 0x2d65,
+ 0x5978, 0x085c,
+ 0x5979, 0x0df2,
+ 0x597a, 0x2d66,
+ 0x597d, 0x077a,
+ 0x597e, 0x2d69,
+ 0x5981, 0x1775,
+ 0x5982, 0x0cc2,
+ 0x5983, 0x1776,
+ 0x5984, 0x0eae,
+ 0x5985, 0x2d6c,
+ 0x5986, 0x120e,
+ 0x5987, 0x06b9,
+ 0x5988, 0x0a8f,
+ 0x5989, 0x2d6d,
+ 0x598a, 0x0cac,
+ 0x598b, 0x2d6e,
+ 0x598d, 0x1777,
+ 0x598e, 0x2d70,
+ 0x5992, 0x0609,
+ 0x5993, 0x083e,
+ 0x5994, 0x2d74,
+ 0x5996, 0x1026,
+ 0x5997, 0x177b,
+ 0x5998, 0x2d76,
+ 0x5999, 0x0af3,
+ 0x599a, 0x2d77,
+ 0x599d, 0x22ad,
+ 0x599e, 0x177e,
+ 0x599f, 0x2d7a,
+ 0x59a3, 0x177a,
+ 0x59a4, 0x177f,
+ 0x59a5, 0x0e88,
+ 0x59a6, 0x2d7e,
+ 0x59a8, 0x065e,
+ 0x59a9, 0x1778,
+ 0x59ab, 0x177d,
+ 0x59ac, 0x2d80,
+ 0x59ae, 0x0b40,
+ 0x59af, 0x1782,
+ 0x59b0, 0x2d82,
+ 0x59b2, 0x1781,
+ 0x59b3, 0x2d84,
+ 0x59b9, 0x0ac8,
+ 0x59ba, 0x2d8a,
+ 0x59bb, 0x0bfd,
+ 0x59bc, 0x2d8b,
+ 0x59be, 0x1784,
+ 0x59bf, 0x2d8d,
+ 0x59c6, 0x0b1a,
+ 0x59c7, 0x2d94,
+ 0x59ca, 0x177c,
+ 0x59cb, 0x0d53,
+ 0x59cc, 0x2d97,
+ 0x59d0, 0x08b4,
+ 0x59d1, 0x071c,
+ 0x59d2, 0x1780,
+ 0x59d3, 0x0fa0,
+ 0x59d4, 0x0ebe,
+ 0x59d5, 0x2d9b,
+ 0x59d7, 0x1783,
+ 0x59d8, 0x178a,
+ 0x59d9, 0x2d9d,
+ 0x59da, 0x102d,
+ 0x59db, 0x2d9e,
+ 0x59dc, 0x087b,
+ 0x59dd, 0x1787,
+ 0x59de, 0x2d9f,
+ 0x59e3, 0x1789,
+ 0x59e4, 0x2da4,
+ 0x59e5, 0x09bc,
+ 0x59e6, 0x2da5,
+ 0x59e8, 0x1053,
+ 0x59e9, 0x2da7,
+ 0x59ec, 0x081a,
+ 0x59ed, 0x2daa,
+ 0x59f9, 0x178b,
+ 0x59fa, 0x2db6,
+ 0x59fb, 0x107d,
+ 0x59fc, 0x2db7,
+ 0x59ff, 0x1228,
+ 0x5a00, 0x2dba,
+ 0x5a01, 0x0eaf,
+ 0x5a02, 0x2dbb,
+ 0x5a03, 0x0e8f,
+ 0x5a04, 0x0a4d,
+ 0x5a05, 0x1785,
+ 0x5a07, 0x0890,
+ 0x5a08, 0x1788,
+ 0x5a09, 0x178d,
+ 0x5a0a, 0x2dbc,
+ 0x5a0c, 0x178c,
+ 0x5a0d, 0x2dbe,
+ 0x5a11, 0x1790,
+ 0x5a12, 0x2dc2,
+ 0x5a13, 0x1792,
+ 0x5a14, 0x2dc3,
+ 0x5a18, 0x0b52,
+ 0x5a19, 0x2dc7,
+ 0x5a1c, 0x0b2b,
+ 0x5a1d, 0x2dca,
+ 0x5a1f, 0x0919,
+ 0x5a20, 0x0d28,
+ 0x5a21, 0x2dcc,
+ 0x5a23, 0x1791,
+ 0x5a24, 0x2dce,
+ 0x5a25, 0x062f,
+ 0x5a26, 0x2dcf,
+ 0x5a29, 0x0ae9,
+ 0x5a2a, 0x2dd2,
+ 0x5a31, 0x10ce,
+ 0x5a32, 0x178e,
+ 0x5a33, 0x2dd9,
+ 0x5a34, 0x178f,
+ 0x5a35, 0x2dda,
+ 0x5a36, 0x0c7d,
+ 0x5a37, 0x2ddb,
+ 0x5a3c, 0x1797,
+ 0x5a3d, 0x2de0,
+ 0x5a40, 0x1793,
+ 0x5a41, 0x203f,
+ 0x5a42, 0x2de3,
+ 0x5a46, 0x0be4,
+ 0x5a47, 0x2de7,
+ 0x5a49, 0x0ea2,
+ 0x5a4a, 0x1795,
+ 0x5a4b, 0x2de9,
+ 0x5a55, 0x1796,
+ 0x5a56, 0x2df3,
+ 0x5a5a, 0x07fe,
+ 0x5a5b, 0x2df7,
+ 0x5a62, 0x1798,
+ 0x5a63, 0x2dfe,
+ 0x5a66, 0x1f0e,
+ 0x5a67, 0x1794,
+ 0x5a68, 0x2e01,
+ 0x5a6a, 0x09a2,
+ 0x5a6b, 0x2e03,
+ 0x5a6d, 0x23f9,
+ 0x5a6e, 0x2e05,
+ 0x5a74, 0x1089,
+ 0x5a75, 0x1799,
+ 0x5a76, 0x0d2d,
+ 0x5a77, 0x179d,
+ 0x5a78, 0x2e0b,
+ 0x5a7a, 0x179e,
+ 0x5a7b, 0x2e0d,
+ 0x5a7f, 0x0fc1,
+ 0x5a80, 0x2e11,
+ 0x5a92, 0x0ac2,
+ 0x5a93, 0x2e23,
+ 0x5a9a, 0x0ac9,
+ 0x5a9b, 0x179c,
+ 0x5a9c, 0x2e2a,
+ 0x5aa7, 0x23fc,
+ 0x5aa8, 0x2e35,
+ 0x5aaa, 0x179b,
+ 0x5aab, 0x2e37,
+ 0x5ab2, 0x17a1,
+ 0x5ab3, 0x0f1e,
+ 0x5ab4, 0x2e3e,
+ 0x5ab5, 0x19a4,
+ 0x5ab6, 0x2e3f,
+ 0x5ab8, 0x17a4,
+ 0x5ab9, 0x2e41,
+ 0x5abd, 0x2069,
+ 0x5abe, 0x179f,
+ 0x5abf, 0x2e45,
+ 0x5ac1, 0x0851,
+ 0x5ac2, 0x0ce2,
+ 0x5ac3, 0x2e47,
+ 0x5ac9, 0x0828,
+ 0x5aca, 0x2e4d,
+ 0x5acc, 0x0f40,
+ 0x5acd, 0x2e4f,
+ 0x5ad2, 0x17a2,
+ 0x5ad3, 0x2e54,
+ 0x5ad4, 0x17a3,
+ 0x5ad5, 0x2e55,
+ 0x5ad6, 0x17a8,
+ 0x5ad7, 0x23f7,
+ 0x5ad8, 0x17aa,
+ 0x5ad9, 0x2e56,
+ 0x5adc, 0x17ab,
+ 0x5add, 0x2e59,
+ 0x5ae0, 0x17a5,
+ 0x5ae1, 0x05b6,
+ 0x5ae2, 0x2e5c,
+ 0x5ae3, 0x17a6,
+ 0x5ae4, 0x2e5d,
+ 0x5ae6, 0x17a9,
+ 0x5ae7, 0x2e5f,
+ 0x5ae9, 0x0b3e,
+ 0x5aea, 0x2e61,
+ 0x5aeb, 0x17a0,
+ 0x5aec, 0x2e62,
+ 0x5af1, 0x17a7,
+ 0x5af2, 0x2e67,
+ 0x5af5, 0x23f6,
+ 0x5af6, 0x2e6a,
+ 0x5afb, 0x23fd,
+ 0x5afc, 0x2e6f,
+ 0x5b00, 0x23f8,
+ 0x5b01, 0x2e73,
+ 0x5b08, 0x23fa,
+ 0x5b09, 0x17ac,
+ 0x5b0a, 0x2e7a,
+ 0x5b0b, 0x23fe,
+ 0x5b0c, 0x1fa8,
+ 0x5b0d, 0x2e7b,
+ 0x5b16, 0x17ae,
+ 0x5b17, 0x17ad,
+ 0x5b18, 0x2e84,
+ 0x5b19, 0x2401,
+ 0x5b1a, 0x2e85,
+ 0x5b21, 0x23ff,
+ 0x5b22, 0x2e8c,
+ 0x5b2a, 0x2400,
+ 0x5b2b, 0x2e94,
+ 0x5b30, 0x2221,
+ 0x5b31, 0x2e99,
+ 0x5b32, 0x17af,
+ 0x5b33, 0x2e9a,
+ 0x5b34, 0x130c,
+ 0x5b35, 0x2e9b,
+ 0x5b37, 0x17b0,
+ 0x5b38, 0x2122,
+ 0x5b39, 0x2e9d,
+ 0x5b40, 0x17b1,
+ 0x5b41, 0x2ea4,
+ 0x5b4c, 0x23fb,
+ 0x5b4d, 0x2eaf,
+ 0x5b50, 0x1230,
+ 0x5b51, 0x17b7,
+ 0x5b52, 0x2eb2,
+ 0x5b53, 0x17b8,
+ 0x5b54, 0x0964,
+ 0x5b55, 0x1113,
+ 0x5b56, 0x2eb3,
+ 0x5b57, 0x1233,
+ 0x5b58, 0x0569,
+ 0x5b59, 0x0de4,
+ 0x5b5a, 0x17b4,
+ 0x5b5b, 0x1279,
+ 0x5b5c, 0x122b,
+ 0x5b5d, 0x0f6d,
+ 0x5b5e, 0x2eb4,
+ 0x5b5f, 0x0ad4,
+ 0x5b60, 0x2eb5,
+ 0x5b62, 0x17b9,
+ 0x5b63, 0x0831,
+ 0x5b64, 0x071b,
+ 0x5b65, 0x17b5,
+ 0x5b66, 0x0fd0,
+ 0x5b67, 0x2eb7,
+ 0x5b69, 0x0759,
+ 0x5b6a, 0x0a76,
+ 0x5b6b, 0x215a,
+ 0x5b6c, 0x1261,
+ 0x5b6d, 0x2eb9,
+ 0x5b70, 0x0d82,
+ 0x5b71, 0x176a,
+ 0x5b72, 0x2ebc,
+ 0x5b73, 0x17b6,
+ 0x5b74, 0x2ebd,
+ 0x5b75, 0x0692,
+ 0x5b76, 0x2ebe,
+ 0x5b78, 0x21e5,
+ 0x5b79, 0x2ec0,
+ 0x5b7a, 0x0cc1,
+ 0x5b7b, 0x2ec1,
+ 0x5b7d, 0x0b58,
+ 0x5b7e, 0x2ec3,
+ 0x5b7f, 0x2057,
+ 0x5b80, 0x172e,
+ 0x5b81, 0x0b61,
+ 0x5b82, 0x2ec4,
+ 0x5b83, 0x0df1,
+ 0x5b84, 0x172f,
+ 0x5b85, 0x114d,
+ 0x5b86, 0x2ec5,
+ 0x5b87, 0x10d3,
+ 0x5b88, 0x0d6f,
+ 0x5b89, 0x03bd,
+ 0x5b8a, 0x2ec6,
+ 0x5b8b, 0x0dc3,
+ 0x5b8c, 0x0e9b,
+ 0x5b8d, 0x2ec7,
+ 0x5b8f, 0x07a1,
+ 0x5b90, 0x2ec9,
+ 0x5b93, 0x1731,
+ 0x5b94, 0x2ecc,
+ 0x5b95, 0x1730,
+ 0x5b96, 0x2ecd,
+ 0x5b97, 0x1237,
+ 0x5b98, 0x0732,
+ 0x5b99, 0x11e5,
+ 0x5b9a, 0x05e7,
+ 0x5b9b, 0x0ea1,
+ 0x5b9c, 0x1052,
+ 0x5b9d, 0x040f,
+ 0x5b9e, 0x0d4c,
+ 0x5b9f, 0x2ece,
+ 0x5ba0, 0x050d,
+ 0x5ba1, 0x0d2c,
+ 0x5ba2, 0x095a,
+ 0x5ba3, 0x0fc6,
+ 0x5ba4, 0x0d69,
+ 0x5ba5, 0x1732,
+ 0x5ba6, 0x07d7,
+ 0x5ba7, 0x2ecf,
+ 0x5baa, 0x0f49,
+ 0x5bab, 0x0705,
+ 0x5bac, 0x2ed2,
+ 0x5bb0, 0x111a,
+ 0x5bb1, 0x2ed6,
+ 0x5bb3, 0x075d,
+ 0x5bb4, 0x1010,
+ 0x5bb5, 0x0f69,
+ 0x5bb6, 0x0845,
+ 0x5bb7, 0x2ed8,
+ 0x5bb8, 0x1733,
+ 0x5bb9, 0x0cb8,
+ 0x5bba, 0x2ed9,
+ 0x5bbd, 0x097a,
+ 0x5bbe, 0x045f,
+ 0x5bbf, 0x0dd3,
+ 0x5bc0, 0x2edc,
+ 0x5bc2, 0x0838,
+ 0x5bc3, 0x2ede,
+ 0x5bc4, 0x0837,
+ 0x5bc5, 0x1081,
+ 0x5bc6, 0x0ae1,
+ 0x5bc7, 0x0969,
+ 0x5bc8, 0x2edf,
+ 0x5bcc, 0x06b6,
+ 0x5bcd, 0x2ee3,
+ 0x5bd0, 0x0ac7,
+ 0x5bd1, 0x2ee6,
+ 0x5bd2, 0x0765,
+ 0x5bd3, 0x10e5,
+ 0x5bd4, 0x2ee7,
+ 0x5bdd, 0x0c5b,
+ 0x5bde, 0x0b12,
+ 0x5bdf, 0x04b3,
+ 0x5be0, 0x2ef0,
+ 0x5be1, 0x072a,
+ 0x5be2, 0x20e5,
+ 0x5be3, 0x2ef1,
+ 0x5be4, 0x1737,
+ 0x5be5, 0x0a11,
+ 0x5be6, 0x212f,
+ 0x5be7, 0x20a3,
+ 0x5be8, 0x1150,
+ 0x5be9, 0x2121,
+ 0x5bea, 0x2ef2,
+ 0x5beb, 0x21d4,
+ 0x5bec, 0x1fe5,
+ 0x5bed, 0x2ef3,
+ 0x5bee, 0x1738,
+ 0x5bef, 0x2ef4,
+ 0x5bf0, 0x173a,
+ 0x5bf1, 0x2ef5,
+ 0x5bf5, 0x1e8a,
+ 0x5bf6, 0x1e37,
+ 0x5bf7, 0x2ef9,
+ 0x5bf8, 0x056a,
+ 0x5bf9, 0x0613,
+ 0x5bfa, 0x0db7,
+ 0x5bfb, 0x0fd9,
+ 0x5bfc, 0x059d,
+ 0x5bfd, 0x2efa,
+ 0x5bff, 0x0d70,
+ 0x5c00, 0x2efc,
+ 0x5c01, 0x067f,
+ 0x5c02, 0x2efd,
+ 0x5c04, 0x0d1d,
+ 0x5c05, 0x2eff,
+ 0x5c06, 0x087c,
+ 0x5c07, 0x1f9e,
+ 0x5c08, 0x22a6,
+ 0x5c09, 0x0ecd,
+ 0x5c0a, 0x124d,
+ 0x5c0b, 0x21e8,
+ 0x5c0c, 0x2f00,
+ 0x5c0d, 0x1eda,
+ 0x5c0e, 0x1eb9,
+ 0x5c0f, 0x0f6c,
+ 0x5c10, 0x2f01,
+ 0x5c11, 0x0d12,
+ 0x5c12, 0x2f02,
+ 0x5c14, 0x063a,
+ 0x5c15, 0x17b2,
+ 0x5c16, 0x0855,
+ 0x5c17, 0x2f04,
+ 0x5c18, 0x04e3,
+ 0x5c19, 0x2f05,
+ 0x5c1a, 0x0d09,
+ 0x5c1b, 0x2f06,
+ 0x5c1c, 0x17b3,
+ 0x5c1d, 0x04c7,
+ 0x5c1e, 0x2f07,
+ 0x5c22, 0x14b6,
+ 0x5c23, 0x2f0b,
+ 0x5c24, 0x10ad,
+ 0x5c25, 0x14b7,
+ 0x5c26, 0x2f0c,
+ 0x5c27, 0x1029,
+ 0x5c28, 0x2f0d,
+ 0x5c2c, 0x14b8,
+ 0x5c2d, 0x2f11,
+ 0x5c31, 0x08fc,
+ 0x5c32, 0x2f15,
+ 0x5c34, 0x14b9,
+ 0x5c35, 0x2f17,
+ 0x5c37, 0x235c,
+ 0x5c38, 0x0d43,
+ 0x5c39, 0x1083,
+ 0x5c3a, 0x0504,
+ 0x5c3b, 0x1766,
+ 0x5c3c, 0x0b44,
+ 0x5c3d, 0x08d0,
+ 0x5c3e, 0x0ec1,
+ 0x5c3f, 0x0b55,
+ 0x5c40, 0x0905,
+ 0x5c41, 0x0bc7,
+ 0x5c42, 0x04aa,
+ 0x5c43, 0x2f19,
+ 0x5c45, 0x0902,
+ 0x5c46, 0x2f1b,
+ 0x5c48, 0x0c79,
+ 0x5c49, 0x0e3e,
+ 0x5c4a, 0x08bd,
+ 0x5c4b, 0x0eec,
+ 0x5c4c, 0x2f1d,
+ 0x5c4e, 0x0d51,
+ 0x5c4f, 0x0be0,
+ 0x5c50, 0x1768,
+ 0x5c51, 0x0f87,
+ 0x5c52, 0x2f1f,
+ 0x5c55, 0x115a,
+ 0x5c56, 0x2f22,
+ 0x5c59, 0x1769,
+ 0x5c5a, 0x2f25,
+ 0x5c5e, 0x0d8b,
+ 0x5c5f, 0x2f29,
+ 0x5c60, 0x0e71,
+ 0x5c61, 0x0a6c,
+ 0x5c62, 0x2050,
+ 0x5c63, 0x176b,
+ 0x5c64, 0x1e67,
+ 0x5c65, 0x0a6b,
+ 0x5c66, 0x176c,
+ 0x5c67, 0x2f2a,
+ 0x5c68, 0x23f4,
+ 0x5c69, 0x2f2b,
+ 0x5c6c, 0x213e,
+ 0x5c6d, 0x2f2e,
+ 0x5c6e, 0x1774,
+ 0x5c6f, 0x0e7e,
+ 0x5c70, 0x2f2f,
+ 0x5c71, 0x0cf6,
+ 0x5c72, 0x2f30,
+ 0x5c79, 0x1060,
+ 0x5c7a, 0x15ac,
+ 0x5c7b, 0x2f37,
+ 0x5c7f, 0x10d1,
+ 0x5c80, 0x2f3b,
+ 0x5c81, 0x0ddf,
+ 0x5c82, 0x0c10,
+ 0x5c83, 0x2f3c,
+ 0x5c88, 0x15b0,
+ 0x5c89, 0x2f41,
+ 0x5c8c, 0x15ab,
+ 0x5c8d, 0x15ad,
+ 0x5c8e, 0x2f44,
+ 0x5c90, 0x15ae,
+ 0x5c91, 0x15b3,
+ 0x5c92, 0x2f46,
+ 0x5c94, 0x04b4,
+ 0x5c95, 0x2f48,
+ 0x5c96, 0x15af,
+ 0x5c97, 0x06d5,
+ 0x5c98, 0x15b1,
+ 0x5c9a, 0x15b4,
+ 0x5c9b, 0x059b,
+ 0x5c9c, 0x15b5,
+ 0x5c9d, 0x2f49,
+ 0x5ca1, 0x1f16,
+ 0x5ca2, 0x15b7,
+ 0x5ca3, 0x15bc,
+ 0x5ca4, 0x2f4d,
+ 0x5ca9, 0x0ffb,
+ 0x5caa, 0x2f52,
+ 0x5cab, 0x15ba,
+ 0x5cac, 0x15b9,
+ 0x5cad, 0x0a34,
+ 0x5cae, 0x2f53,
+ 0x5cb1, 0x15bb,
+ 0x5cb2, 0x2f56,
+ 0x5cb3, 0x1103,
+ 0x5cb4, 0x2f57,
+ 0x5cb5, 0x15b6,
+ 0x5cb6, 0x2f58,
+ 0x5cb7, 0x15be,
+ 0x5cb8, 0x03c1,
+ 0x5cb9, 0x2f59,
+ 0x5cbd, 0x15b8,
+ 0x5cbe, 0x2f5d,
+ 0x5cbf, 0x0986,
+ 0x5cc0, 0x2f5e,
+ 0x5cc1, 0x15bd,
+ 0x5cc2, 0x2f5f,
+ 0x5cc4, 0x15bf,
+ 0x5cc5, 0x2f61,
+ 0x5ccb, 0x15c2,
+ 0x5ccc, 0x2f67,
+ 0x5cd2, 0x15c0,
+ 0x5cd3, 0x2f6d,
+ 0x5cd9, 0x11c4,
+ 0x5cda, 0x2f73,
+ 0x5ce1, 0x0f2c,
+ 0x5ce2, 0x2f7a,
+ 0x5ce4, 0x15c1,
+ 0x5ce5, 0x15c3,
+ 0x5ce6, 0x0a74,
+ 0x5ce7, 0x2f7c,
+ 0x5ce8, 0x062a,
+ 0x5ce9, 0x2f7d,
+ 0x5cea, 0x10dd,
+ 0x5ceb, 0x2f7e,
+ 0x5ced, 0x0c4a,
+ 0x5cee, 0x2f80,
+ 0x5cf0, 0x0682,
+ 0x5cf1, 0x2f82,
+ 0x5cf4, 0x2389,
+ 0x5cf5, 0x2f85,
+ 0x5cf6, 0x1eb7,
+ 0x5cf7, 0x2f86,
+ 0x5cfb, 0x092d,
+ 0x5cfc, 0x2f8a,
+ 0x5cfd, 0x21b4,
+ 0x5cfe, 0x2f8b,
+ 0x5d00, 0x2f8d,
+ 0x5d02, 0x15c4,
+ 0x5d04, 0x2f8f,
+ 0x5d06, 0x15cb,
+ 0x5d07, 0x050c,
+ 0x5d08, 0x2f91,
+ 0x5d0d, 0x238f,
+ 0x5d0e, 0x0c08,
+ 0x5d0f, 0x2f96,
+ 0x5d14, 0x0561,
+ 0x5d15, 0x2f9b,
+ 0x5d16, 0x0feb,
+ 0x5d17, 0x1f1a,
+ 0x5d18, 0x2f9c,
+ 0x5d1b, 0x15cc,
+ 0x5d1c, 0x2f9f,
+ 0x5d1e, 0x15ca,
+ 0x5d1f, 0x2fa1,
+ 0x5d24, 0x15c9,
+ 0x5d25, 0x2fa6,
+ 0x5d26, 0x15c7,
+ 0x5d27, 0x15c6,
+ 0x5d28, 0x2fa7,
+ 0x5d29, 0x0429,
+ 0x5d2a, 0x2fa8,
+ 0x5d2c, 0x238b,
+ 0x5d2d, 0x1159,
+ 0x5d2e, 0x15c8,
+ 0x5d2f, 0x2faa,
+ 0x5d34, 0x15cf,
+ 0x5d35, 0x2faf,
+ 0x5d3d, 0x15d0,
+ 0x5d3e, 0x15ce,
+ 0x5d3f, 0x2fb7,
+ 0x5d47, 0x1b22,
+ 0x5d48, 0x2fbf,
+ 0x5d4a, 0x15d7,
+ 0x5d4b, 0x15d6,
+ 0x5d4c, 0x0c33,
+ 0x5d4d, 0x2fc1,
+ 0x5d50, 0x238a,
+ 0x5d51, 0x2fc4,
+ 0x5d58, 0x15cd,
+ 0x5d59, 0x2fcb,
+ 0x5d5b, 0x15d2,
+ 0x5d5c, 0x2fcd,
+ 0x5d5d, 0x15d4,
+ 0x5d5e, 0x2fce,
+ 0x5d69, 0x15d8,
+ 0x5d6a, 0x2fd9,
+ 0x5d6b, 0x15d5,
+ 0x5d6c, 0x15d1,
+ 0x5d6d, 0x2fda,
+ 0x5d6f, 0x15d3,
+ 0x5d70, 0x2fdc,
+ 0x5d74, 0x15d9,
+ 0x5d75, 0x2fe0,
+ 0x5d81, 0x2391,
+ 0x5d82, 0x15da,
+ 0x5d83, 0x2fec,
+ 0x5d84, 0x2271,
+ 0x5d85, 0x2fed,
+ 0x5d87, 0x2388,
+ 0x5d88, 0x2fef,
+ 0x5d97, 0x238e,
+ 0x5d98, 0x2ffe,
+ 0x5d99, 0x15db,
+ 0x5d9a, 0x2fff,
+ 0x5d9d, 0x15dc,
+ 0x5d9e, 0x3002,
+ 0x5da0, 0x238d,
+ 0x5da1, 0x3004,
+ 0x5da7, 0x238c,
+ 0x5da8, 0x300a,
+ 0x5db7, 0x15de,
+ 0x5db8, 0x2390,
+ 0x5db9, 0x3019,
+ 0x5dba, 0x2033,
+ 0x5dbb, 0x301a,
+ 0x5dbc, 0x223c,
+ 0x5dbd, 0x301b,
+ 0x5dc5, 0x15df,
+ 0x5dc6, 0x3023,
+ 0x5dcb, 0x1fe9,
+ 0x5dcc, 0x3028,
+ 0x5dcd, 0x0eb0,
+ 0x5dce, 0x3029,
+ 0x5dd2, 0x2055,
+ 0x5dd3, 0x302d,
+ 0x5dd4, 0x2392,
+ 0x5dd5, 0x302e,
+ 0x5ddb, 0x1815,
+ 0x5ddc, 0x3034,
+ 0x5ddd, 0x052b,
+ 0x5dde, 0x11dc,
+ 0x5ddf, 0x3035,
+ 0x5de1, 0x0fdb,
+ 0x5de2, 0x04d7,
+ 0x5de3, 0x3037,
+ 0x5de5, 0x06fd,
+ 0x5de6, 0x1250,
+ 0x5de7, 0x0c46,
+ 0x5de8, 0x090d,
+ 0x5de9, 0x0707,
+ 0x5dea, 0x3039,
+ 0x5deb, 0x0ee6,
+ 0x5dec, 0x303a,
+ 0x5dee, 0x04b5,
+ 0x5def, 0x139f,
+ 0x5df0, 0x2324,
+ 0x5df1, 0x082d,
+ 0x5df2, 0x1058,
+ 0x5df3, 0x0dbd,
+ 0x5df4, 0x03d8,
+ 0x5df5, 0x303c,
+ 0x5df7, 0x0f5c,
+ 0x5df8, 0x303e,
+ 0x5dfd, 0x12f7,
+ 0x5dfe, 0x08be,
+ 0x5dff, 0x3043,
+ 0x5e00, 0x3044,
+ 0x5e01, 0x043b,
+ 0x5e02, 0x0d67,
+ 0x5e03, 0x0483,
+ 0x5e04, 0x3045,
+ 0x5e05, 0x0d9c,
+ 0x5e06, 0x0648,
+ 0x5e07, 0x3046,
+ 0x5e08, 0x0d3d,
+ 0x5e09, 0x3047,
+ 0x5e0c, 0x0f10,
+ 0x5e0d, 0x304a,
+ 0x5e0f, 0x159e,
+ 0x5e10, 0x116b,
+ 0x5e11, 0x15a1,
+ 0x5e12, 0x304c,
+ 0x5e14, 0x15a0,
+ 0x5e15, 0x0b82,
+ 0x5e16, 0x0e4e,
+ 0x5e17, 0x304e,
+ 0x5e18, 0x09fa,
+ 0x5e19, 0x159f,
+ 0x5e1a, 0x11e2,
+ 0x5e1b, 0x0476,
+ 0x5e1c, 0x11c3,
+ 0x5e1d, 0x05bc,
+ 0x5e1e, 0x304f,
+ 0x5e25, 0x2143,
+ 0x5e26, 0x057b,
+ 0x5e27, 0x11a0,
+ 0x5e28, 0x3056,
+ 0x5e2b, 0x2129,
+ 0x5e2c, 0x3059,
+ 0x5e2d, 0x0f1c,
+ 0x5e2e, 0x03fa,
+ 0x5e2f, 0x305a,
+ 0x5e31, 0x15a2,
+ 0x5e32, 0x305c,
+ 0x5e33, 0x2277,
+ 0x5e34, 0x305d,
+ 0x5e36, 0x1ea7,
+ 0x5e37, 0x15a5,
+ 0x5e38, 0x04c8,
+ 0x5e39, 0x305f,
+ 0x5e3b, 0x15a3,
+ 0x5e3d, 0x0ab6,
+ 0x5e3e, 0x3061,
+ 0x5e40, 0x2285,
+ 0x5e41, 0x3063,
+ 0x5e42, 0x0ae2,
+ 0x5e43, 0x2384,
+ 0x5e44, 0x15a6,
+ 0x5e45, 0x0696,
+ 0x5e46, 0x3064,
+ 0x5e4c, 0x07e4,
+ 0x5e4d, 0x306a,
+ 0x5e54, 0x15a7,
+ 0x5e55, 0x0b1e,
+ 0x5e56, 0x3071,
+ 0x5e57, 0x2387,
+ 0x5e58, 0x2386,
+ 0x5e59, 0x3072,
+ 0x5e5b, 0x15a8,
+ 0x5e5c, 0x3074,
+ 0x5e5e, 0x15a9,
+ 0x5e5f, 0x2290,
+ 0x5e60, 0x3076,
+ 0x5e61, 0x15aa,
+ 0x5e62, 0x0534,
+ 0x5e63, 0x1e44,
+ 0x5e64, 0x3077,
+ 0x5e6b, 0x1e32,
+ 0x5e6c, 0x2385,
+ 0x5e6d, 0x307e,
+ 0x5e72, 0x06c4,
+ 0x5e73, 0x0bdc,
+ 0x5e74, 0x0b4d,
+ 0x5e75, 0x3083,
+ 0x5e76, 0x0469,
+ 0x5e77, 0x3084,
+ 0x5e78, 0x0f9d,
+ 0x5e79, 0x1f13,
+ 0x5e7a, 0x1813,
+ 0x5e7b, 0x07d8,
+ 0x5e7c, 0x10bc,
+ 0x5e7d, 0x10a9,
+ 0x5e7e, 0x1f73,
+ 0x5e7f, 0x073c,
+ 0x5e80, 0x1631,
+ 0x5e81, 0x3085,
+ 0x5e84, 0x120c,
+ 0x5e85, 0x3088,
+ 0x5e86, 0x0c69,
+ 0x5e87, 0x043c,
+ 0x5e88, 0x3089,
+ 0x5e8a, 0x0535,
+ 0x5e8b, 0x1633,
+ 0x5e8c, 0x308b,
+ 0x5e8f, 0x0fbd,
+ 0x5e90, 0x0a55,
+ 0x5e91, 0x1632,
+ 0x5e92, 0x308e,
+ 0x5e93, 0x096f,
+ 0x5e94, 0x108b,
+ 0x5e95, 0x05b8,
+ 0x5e96, 0x1634,
+ 0x5e97, 0x05cb,
+ 0x5e98, 0x308f,
+ 0x5e99, 0x0af2,
+ 0x5e9a, 0x06f8,
+ 0x5e9b, 0x3090,
+ 0x5e9c, 0x06a9,
+ 0x5e9d, 0x3091,
+ 0x5e9e, 0x0b94,
+ 0x5e9f, 0x066c,
+ 0x5ea0, 0x1636,
+ 0x5ea1, 0x3092,
+ 0x5ea5, 0x1635,
+ 0x5ea6, 0x0607,
+ 0x5ea7, 0x1256,
+ 0x5ea8, 0x3096,
+ 0x5eab, 0x1fe0,
+ 0x5eac, 0x3099,
+ 0x5ead, 0x0e56,
+ 0x5eae, 0x309a,
+ 0x5eb3, 0x163a,
+ 0x5eb4, 0x309f,
+ 0x5eb5, 0x1638,
+ 0x5eb6, 0x0d93,
+ 0x5eb7, 0x0942,
+ 0x5eb8, 0x109e,
+ 0x5eb9, 0x1637,
+ 0x5eba, 0x30a0,
+ 0x5ebe, 0x1639,
+ 0x5ebf, 0x30a4,
+ 0x5ec9, 0x09f7,
+ 0x5eca, 0x09b3,
+ 0x5ecb, 0x30ae,
+ 0x5ed1, 0x163d,
+ 0x5ed2, 0x163c,
+ 0x5ed3, 0x0995,
+ 0x5ed4, 0x30b4,
+ 0x5ed6, 0x0a17,
+ 0x5ed7, 0x30b6,
+ 0x5edb, 0x163e,
+ 0x5edc, 0x30ba,
+ 0x5edf, 0x2087,
+ 0x5ee0, 0x1e78,
+ 0x5ee1, 0x23ae,
+ 0x5ee2, 0x1ef6,
+ 0x5ee3, 0x1f31,
+ 0x5ee4, 0x30bd,
+ 0x5ee8, 0x163f,
+ 0x5ee9, 0x30c1,
+ 0x5eea, 0x1640,
+ 0x5eeb, 0x30c2,
+ 0x5eec, 0x2045,
+ 0x5eed, 0x30c3,
+ 0x5ef3, 0x2178,
+ 0x5ef4, 0x1398,
+ 0x5ef5, 0x30c9,
+ 0x5ef6, 0x0ffc,
+ 0x5ef7, 0x0e53,
+ 0x5ef8, 0x30ca,
+ 0x5efa, 0x0879,
+ 0x5efb, 0x30cc,
+ 0x5efe, 0x14ad,
+ 0x5eff, 0x125b,
+ 0x5f00, 0x0937,
+ 0x5f01, 0x139d,
+ 0x5f02, 0x1073,
+ 0x5f03, 0x0c19,
+ 0x5f04, 0x0b6b,
+ 0x5f05, 0x30cf,
+ 0x5f08, 0x14ae,
+ 0x5f09, 0x30d2,
+ 0x5f0a, 0x0440,
+ 0x5f0b, 0x14f6,
+ 0x5f0c, 0x30d3,
+ 0x5f0f, 0x0d54,
+ 0x5f10, 0x30d6,
+ 0x5f11, 0x14f9,
+ 0x5f12, 0x30d7,
+ 0x5f13, 0x0706,
+ 0x5f14, 0x30d8,
+ 0x5f15, 0x1084,
+ 0x5f16, 0x30d9,
+ 0x5f17, 0x06a0,
+ 0x5f18, 0x07a2,
+ 0x5f19, 0x30da,
+ 0x5f1b, 0x04ff,
+ 0x5f1c, 0x30dc,
+ 0x5f1f, 0x05bd,
+ 0x5f20, 0x1166,
+ 0x5f21, 0x30df,
+ 0x5f25, 0x0adb,
+ 0x5f26, 0x0f3f,
+ 0x5f27, 0x07b6,
+ 0x5f28, 0x30e3,
+ 0x5f29, 0x176f,
+ 0x5f2a, 0x176e,
+ 0x5f2b, 0x30e4,
+ 0x5f2d, 0x1770,
+ 0x5f2e, 0x30e6,
+ 0x5f2f, 0x0e95,
+ 0x5f30, 0x30e7,
+ 0x5f31, 0x0cd0,
+ 0x5f32, 0x30e8,
+ 0x5f33, 0x23f5,
+ 0x5f34, 0x30e9,
+ 0x5f35, 0x2275,
+ 0x5f36, 0x30ea,
+ 0x5f39, 0x0590,
+ 0x5f3a, 0x0c3c,
+ 0x5f3b, 0x30ed,
+ 0x5f3c, 0x1772,
+ 0x5f3d, 0x30ee,
+ 0x5f40, 0x19be,
+ 0x5f41, 0x30f1,
+ 0x5f46, 0x266e,
+ 0x5f47, 0x30f6,
+ 0x5f48, 0x1eb0,
+ 0x5f49, 0x30f7,
+ 0x5f4c, 0x2083,
+ 0x5f4d, 0x30fa,
+ 0x5f4e, 0x2188,
+ 0x5f4f, 0x30fb,
+ 0x5f50, 0x1762,
+ 0x5f51, 0x30fc,
+ 0x5f52, 0x0742,
+ 0x5f53, 0x0592,
+ 0x5f54, 0x30fd,
+ 0x5f55, 0x0a63,
+ 0x5f56, 0x1764,
+ 0x5f57, 0x1763,
+ 0x5f58, 0x1765,
+ 0x5f59, 0x267c,
+ 0x5f5a, 0x30fe,
+ 0x5f5d, 0x1054,
+ 0x5f5e, 0x3101,
+ 0x5f61, 0x15ee,
+ 0x5f62, 0x0f99,
+ 0x5f63, 0x3104,
+ 0x5f64, 0x0e5f,
+ 0x5f65, 0x3105,
+ 0x5f66, 0x100e,
+ 0x5f67, 0x3106,
+ 0x5f69, 0x0491,
+ 0x5f6a, 0x0454,
+ 0x5f6b, 0x3108,
+ 0x5f6c, 0x045b,
+ 0x5f6d, 0x0bae,
+ 0x5f6e, 0x3109,
+ 0x5f70, 0x1164,
+ 0x5f71, 0x1095,
+ 0x5f72, 0x310b,
+ 0x5f73, 0x15e0,
+ 0x5f74, 0x310c,
+ 0x5f77, 0x15e1,
+ 0x5f78, 0x310f,
+ 0x5f79, 0x1062,
+ 0x5f7a, 0x3110,
+ 0x5f7b, 0x04de,
+ 0x5f7c, 0x0434,
+ 0x5f7d, 0x3111,
+ 0x5f80, 0x0eaa,
+ 0x5f81, 0x1198,
+ 0x5f82, 0x15e2,
+ 0x5f83, 0x3114,
+ 0x5f84, 0x08e5,
+ 0x5f85, 0x0580,
+ 0x5f86, 0x3115,
+ 0x5f87, 0x15e3,
+ 0x5f88, 0x0793,
+ 0x5f89, 0x15e4,
+ 0x5f8a, 0x07c7,
+ 0x5f8b, 0x0a70,
+ 0x5f8c, 0x15e5,
+ 0x5f8d, 0x3116,
+ 0x5f90, 0x0fb7,
+ 0x5f91, 0x1fc5,
+ 0x5f92, 0x0e6e,
+ 0x5f93, 0x3119,
+ 0x5f95, 0x15e6,
+ 0x5f96, 0x311b,
+ 0x5f97, 0x05a4,
+ 0x5f98, 0x0b88,
+ 0x5f99, 0x15e7,
+ 0x5f9a, 0x311c,
+ 0x5f9c, 0x15e8,
+ 0x5f9d, 0x311e,
+ 0x5f9e, 0x1ea1,
+ 0x5f9f, 0x311f,
+ 0x5fa0, 0x2393,
+ 0x5fa1, 0x10de,
+ 0x5fa2, 0x3120,
+ 0x5fa8, 0x15e9,
+ 0x5fa9, 0x1f0b,
+ 0x5faa, 0x0fd6,
+ 0x5fab, 0x3126,
+ 0x5fad, 0x15ea,
+ 0x5fae, 0x0eb1,
+ 0x5faf, 0x3128,
+ 0x5fb5, 0x15eb,
+ 0x5fb6, 0x312e,
+ 0x5fb7, 0x05a3,
+ 0x5fb8, 0x312f,
+ 0x5fb9, 0x1e7c,
+ 0x5fba, 0x3130,
+ 0x5fbc, 0x15ec,
+ 0x5fbd, 0x07ea,
+ 0x5fbe, 0x3132,
+ 0x5fc3, 0x0f8f,
+ 0x5fc4, 0x1642,
+ 0x5fc5, 0x0441,
+ 0x5fc6, 0x106b,
+ 0x5fc7, 0x3137,
+ 0x5fc9, 0x1643,
+ 0x5fca, 0x3139,
+ 0x5fcc, 0x083c,
+ 0x5fcd, 0x0ca7,
+ 0x5fce, 0x313b,
+ 0x5fcf, 0x1645,
+ 0x5fd0, 0x1a0c,
+ 0x5fd1, 0x1a0b,
+ 0x5fd2, 0x14f7,
+ 0x5fd3, 0x313c,
+ 0x5fd6, 0x1644,
+ 0x5fd7, 0x11bd,
+ 0x5fd8, 0x0ead,
+ 0x5fd9, 0x0aab,
+ 0x5fda, 0x313f,
+ 0x5fdd, 0x1683,
+ 0x5fde, 0x3142,
+ 0x5fe0, 0x11d1,
+ 0x5fe1, 0x1649,
+ 0x5fe2, 0x3144,
+ 0x5fe4, 0x164a,
+ 0x5fe5, 0x3146,
+ 0x5fe7, 0x10ac,
+ 0x5fe8, 0x3148,
+ 0x5fea, 0x164e,
+ 0x5feb, 0x0979,
+ 0x5fec, 0x314a,
+ 0x5fed, 0x164f,
+ 0x5fee, 0x1647,
+ 0x5fef, 0x314b,
+ 0x5ff1, 0x04e5,
+ 0x5ff2, 0x314d,
+ 0x5ff5, 0x0b51,
+ 0x5ff6, 0x3150,
+ 0x5ff8, 0x1650,
+ 0x5ff9, 0x3152,
+ 0x5ffb, 0x0f8e,
+ 0x5ffc, 0x3154,
+ 0x5ffd, 0x07ad,
+ 0x5ffe, 0x164b,
+ 0x5fff, 0x067b,
+ 0x6000, 0x07c8,
+ 0x6001, 0x0dff,
+ 0x6002, 0x0dc0,
+ 0x6003, 0x1646,
+ 0x6004, 0x1648,
+ 0x6005, 0x164c,
+ 0x6007, 0x3155,
+ 0x600a, 0x1659,
+ 0x600b, 0x3158,
+ 0x600d, 0x1656,
+ 0x600e, 0x1138,
+ 0x600f, 0x1655,
+ 0x6010, 0x315a,
+ 0x6012, 0x0b6e,
+ 0x6013, 0x315c,
+ 0x6014, 0x119b,
+ 0x6015, 0x0b83,
+ 0x6016, 0x0487,
+ 0x6017, 0x315d,
+ 0x6019, 0x1651,
+ 0x601a, 0x315f,
+ 0x601b, 0x1654,
+ 0x601c, 0x09f8,
+ 0x601d, 0x0db1,
+ 0x601e, 0x3160,
+ 0x6020, 0x0582,
+ 0x6021, 0x165b,
+ 0x6022, 0x3162,
+ 0x6025, 0x0824,
+ 0x6026, 0x1653,
+ 0x6027, 0x0f9f,
+ 0x6028, 0x10fc,
+ 0x6029, 0x1657,
+ 0x602a, 0x072f,
+ 0x602b, 0x1658,
+ 0x602c, 0x3165,
+ 0x602f, 0x0c50,
+ 0x6030, 0x3168,
+ 0x6035, 0x1652,
+ 0x6036, 0x316d,
+ 0x603b, 0x1239,
+ 0x603c, 0x1a0d,
+ 0x603d, 0x3172,
+ 0x603f, 0x165a,
+ 0x6040, 0x3174,
+ 0x6041, 0x1a11,
+ 0x6042, 0x1660,
+ 0x6043, 0x0d68,
+ 0x6044, 0x3175,
+ 0x604b, 0x09fe,
+ 0x604c, 0x317c,
+ 0x604d, 0x07e5,
+ 0x604e, 0x317d,
+ 0x6050, 0x0963,
+ 0x6051, 0x317f,
+ 0x6052, 0x079a,
+ 0x6053, 0x3180,
+ 0x6055, 0x0d96,
+ 0x6056, 0x3182,
+ 0x6059, 0x1a12,
+ 0x605a, 0x1a0f,
+ 0x605b, 0x3185,
+ 0x605d, 0x1a0e,
+ 0x605e, 0x3187,
+ 0x6062, 0x07eb,
+ 0x6063, 0x1a13,
+ 0x6064, 0x0fbf,
+ 0x6065, 0x318b,
+ 0x6067, 0x1a10,
+ 0x6068, 0x0795,
+ 0x6069, 0x0636,
+ 0x606a, 0x1661,
+ 0x606b, 0x05f1,
+ 0x606c, 0x0e44,
+ 0x606d, 0x0700,
+ 0x606e, 0x318d,
+ 0x606f, 0x0f0f,
+ 0x6070, 0x0c1e,
+ 0x6071, 0x318e,
+ 0x6073, 0x095f,
+ 0x6074, 0x3190,
+ 0x6076, 0x0630,
+ 0x6077, 0x3192,
+ 0x6078, 0x165c,
+ 0x607a, 0x165f,
+ 0x607b, 0x165e,
+ 0x607c, 0x0b38,
+ 0x607d, 0x1662,
+ 0x607e, 0x3193,
+ 0x607f, 0x10a6,
+ 0x6080, 0x3194,
+ 0x6083, 0x1667,
+ 0x6084, 0x0c41,
+ 0x6085, 0x3197,
+ 0x6089, 0x0f11,
+ 0x608a, 0x319b,
+ 0x608c, 0x1669,
+ 0x608d, 0x076e,
+ 0x608e, 0x319d,
+ 0x6092, 0x1668,
+ 0x6093, 0x31a1,
+ 0x6094, 0x07ef,
+ 0x6095, 0x31a2,
+ 0x6096, 0x1663,
+ 0x6097, 0x31a3,
+ 0x609a, 0x1664,
+ 0x609b, 0x166a,
+ 0x609c, 0x31a6,
+ 0x609d, 0x1666,
+ 0x609e, 0x31a7,
+ 0x609f, 0x0f01,
+ 0x60a0, 0x10ab,
+ 0x60a1, 0x31a8,
+ 0x60a3, 0x07d1,
+ 0x60a4, 0x31aa,
+ 0x60a6, 0x1106,
+ 0x60a7, 0x31ac,
+ 0x60a8, 0x0b5d,
+ 0x60a9, 0x31ad,
+ 0x60ab, 0x1a14,
+ 0x60ac, 0x0fc7,
+ 0x60ad, 0x1665,
+ 0x60ae, 0x31af,
+ 0x60af, 0x0afa,
+ 0x60b0, 0x31b0,
+ 0x60b1, 0x166d,
+ 0x60b2, 0x0418,
+ 0x60b3, 0x31b1,
+ 0x60b4, 0x1672,
+ 0x60b5, 0x23b4,
+ 0x60b6, 0x207e,
+ 0x60b7, 0x31b2,
+ 0x60b8, 0x0835,
+ 0x60b9, 0x31b3,
+ 0x60bb, 0x166c,
+ 0x60bc, 0x05a0,
+ 0x60bd, 0x31b5,
+ 0x60c5, 0x0c66,
+ 0x60c6, 0x1670,
+ 0x60c7, 0x31bd,
+ 0x60ca, 0x08d9,
+ 0x60cb, 0x0ea0,
+ 0x60cc, 0x31c0,
+ 0x60d1, 0x0808,
+ 0x60d2, 0x31c5,
+ 0x60d5, 0x0e3b,
+ 0x60d6, 0x31c8,
+ 0x60d8, 0x166f,
+ 0x60d9, 0x31ca,
+ 0x60da, 0x1671,
+ 0x60db, 0x31cb,
+ 0x60dc, 0x0f14,
+ 0x60dd, 0x166e,
+ 0x60de, 0x31cc,
+ 0x60df, 0x0eb8,
+ 0x60e0, 0x07f2,
+ 0x60e1, 0x1ee3,
+ 0x60e2, 0x31cd,
+ 0x60e6, 0x05cc,
+ 0x60e7, 0x0914,
+ 0x60e8, 0x0499,
+ 0x60e9, 0x04f2,
+ 0x60ea, 0x31d1,
+ 0x60eb, 0x0422,
+ 0x60ec, 0x166b,
+ 0x60ed, 0x0498,
+ 0x60ee, 0x058d,
+ 0x60ef, 0x0738,
+ 0x60f0, 0x0627,
+ 0x60f1, 0x2095,
+ 0x60f2, 0x23bb,
+ 0x60f3, 0x0f58,
+ 0x60f4, 0x1677,
+ 0x60f5, 0x31d2,
+ 0x60f6, 0x07e1,
+ 0x60f7, 0x31d3,
+ 0x60f9, 0x0ca2,
+ 0x60fa, 0x0f95,
+ 0x60fb, 0x23b9,
+ 0x60fc, 0x31d5,
+ 0x6100, 0x1678,
+ 0x6101, 0x0513,
+ 0x6102, 0x31d9,
+ 0x6106, 0x1a15,
+ 0x6107, 0x31dd,
+ 0x6108, 0x10df,
+ 0x6109, 0x10c9,
+ 0x610a, 0x31de,
+ 0x610d, 0x1a16,
+ 0x610e, 0x1679,
+ 0x610f, 0x1069,
+ 0x6110, 0x31e1,
+ 0x6115, 0x1675,
+ 0x6116, 0x31e6,
+ 0x611a, 0x10c3,
+ 0x611b, 0x1e28,
+ 0x611c, 0x23bd,
+ 0x611d, 0x31ea,
+ 0x611f, 0x06cb,
+ 0x6120, 0x1673,
+ 0x6121, 0x31ec,
+ 0x6123, 0x1676,
+ 0x6124, 0x067c,
+ 0x6125, 0x31ee,
+ 0x6126, 0x1674,
+ 0x6127, 0x098d,
+ 0x6128, 0x31ef,
+ 0x612b, 0x167a,
+ 0x612c, 0x31f2,
+ 0x6134, 0x23b5,
+ 0x6135, 0x31fa,
+ 0x6137, 0x23ba,
+ 0x6138, 0x31fc,
+ 0x613e, 0x23b3,
+ 0x613f, 0x10fb,
+ 0x6140, 0x3202,
+ 0x6148, 0x054b,
+ 0x6149, 0x320a,
+ 0x614a, 0x167b,
+ 0x614b, 0x2162,
+ 0x614c, 0x07da,
+ 0x614d, 0x320b,
+ 0x614e, 0x0d30,
+ 0x614f, 0x320c,
+ 0x6151, 0x0d1e,
+ 0x6152, 0x320e,
+ 0x6155, 0x0b20,
+ 0x6156, 0x3211,
+ 0x6158, 0x1e5e,
+ 0x6159, 0x3213,
+ 0x615a, 0x1e5d,
+ 0x615b, 0x3214,
+ 0x615d, 0x1a17,
+ 0x615e, 0x3216,
+ 0x615f, 0x23b7,
+ 0x6160, 0x3217,
+ 0x6162, 0x0aa4,
+ 0x6163, 0x1f2f,
+ 0x6164, 0x24df,
+ 0x6165, 0x3219,
+ 0x6167, 0x07f0,
+ 0x6168, 0x093b,
+ 0x6169, 0x321b,
+ 0x616a, 0x23b2,
+ 0x616b, 0x214e,
+ 0x616c, 0x321c,
+ 0x616e, 0x2052,
+ 0x616f, 0x321e,
+ 0x6170, 0x0ece,
+ 0x6171, 0x321f,
+ 0x6173, 0x23bc,
+ 0x6174, 0x3221,
+ 0x6175, 0x167c,
+ 0x6176, 0x20eb,
+ 0x6177, 0x0943,
+ 0x6178, 0x3222,
+ 0x6182, 0x2232,
+ 0x6183, 0x322c,
+ 0x618a, 0x1e3f,
+ 0x618b, 0x0458,
+ 0x618c, 0x3233,
+ 0x618e, 0x113a,
+ 0x618f, 0x3235,
+ 0x6190, 0x201b,
+ 0x6191, 0x20bc,
+ 0x6192, 0x23be,
+ 0x6193, 0x3236,
+ 0x6194, 0x167e,
+ 0x6195, 0x3237,
+ 0x619a, 0x1eae,
+ 0x619b, 0x323c,
+ 0x619d, 0x1a19,
+ 0x619e, 0x323e,
+ 0x61a4, 0x1efb,
+ 0x61a5, 0x3244,
+ 0x61a7, 0x167f,
+ 0x61a8, 0x0760,
+ 0x61a9, 0x1a18,
+ 0x61aa, 0x3246,
+ 0x61ab, 0x2089,
+ 0x61ac, 0x167d,
+ 0x61ad, 0x3247,
+ 0x61ae, 0x23b1,
+ 0x61af, 0x3248,
+ 0x61b2, 0x21c4,
+ 0x61b3, 0x324b,
+ 0x61b6, 0x2214,
+ 0x61b7, 0x1680,
+ 0x61b8, 0x324e,
+ 0x61be, 0x076d,
+ 0x61bf, 0x3254,
+ 0x61c2, 0x05ed,
+ 0x61c3, 0x3257,
+ 0x61c7, 0x1fde,
+ 0x61c8, 0x0f83,
+ 0x61c9, 0x2223,
+ 0x61ca, 0x03ce,
+ 0x61cb, 0x1a1a,
+ 0x61cc, 0x23b6,
+ 0x61cd, 0x325b,
+ 0x61d1, 0x1a1b,
+ 0x61d2, 0x09ac,
+ 0x61d3, 0x325f,
+ 0x61d4, 0x1681,
+ 0x61d5, 0x3260,
+ 0x61de, 0x268c,
+ 0x61df, 0x24de,
+ 0x61e0, 0x3269,
+ 0x61e3, 0x24e0,
+ 0x61e4, 0x326c,
+ 0x61e6, 0x0b74,
+ 0x61e7, 0x326e,
+ 0x61e8, 0x23b8,
+ 0x61e9, 0x326f,
+ 0x61f2, 0x1e81,
+ 0x61f3, 0x3278,
+ 0x61f5, 0x1682,
+ 0x61f6, 0x1ffe,
+ 0x61f7, 0x1f51,
+ 0x61f8, 0x21e1,
+ 0x61f9, 0x327a,
+ 0x61fa, 0x23b0,
+ 0x61fb, 0x327b,
+ 0x61fc, 0x1fce,
+ 0x61fd, 0x327c,
+ 0x61fe, 0x211e,
+ 0x61ff, 0x13e0,
+ 0x6200, 0x2021,
+ 0x6201, 0x327d,
+ 0x6206, 0x1a1c,
+ 0x6207, 0x24e1,
+ 0x6208, 0x06e5,
+ 0x6209, 0x3282,
+ 0x620a, 0x0efb,
+ 0x620b, 0x18f9,
+ 0x620c, 0x0fb2,
+ 0x620d, 0x0d90,
+ 0x620e, 0x0cb1,
+ 0x620f, 0x0f24,
+ 0x6210, 0x04ee,
+ 0x6211, 0x0ee1,
+ 0x6212, 0x08b5,
+ 0x6213, 0x3283,
+ 0x6214, 0x24a3,
+ 0x6215, 0x169e,
+ 0x6216, 0x0807,
+ 0x6217, 0x18fa,
+ 0x6218, 0x115e,
+ 0x6219, 0x3284,
+ 0x621a, 0x0bfc,
+ 0x621b, 0x18fb,
+ 0x621c, 0x3285,
+ 0x621f, 0x18fc,
+ 0x6220, 0x3288,
+ 0x6221, 0x18fe,
+ 0x6222, 0x18fd,
+ 0x6223, 0x3289,
+ 0x6224, 0x1900,
+ 0x6225, 0x18ff,
+ 0x6226, 0x328a,
+ 0x6227, 0x24a4,
+ 0x6228, 0x328b,
+ 0x622a, 0x08a9,
+ 0x622b, 0x328d,
+ 0x622c, 0x1901,
+ 0x622d, 0x328e,
+ 0x622e, 0x0a65,
+ 0x622f, 0x328f,
+ 0x6230, 0x2273,
+ 0x6231, 0x3290,
+ 0x6232, 0x21b0,
+ 0x6233, 0x0544,
+ 0x6234, 0x057a,
+ 0x6235, 0x3291,
+ 0x6237, 0x07bc,
+ 0x6238, 0x3293,
+ 0x623d, 0x19f4,
+ 0x623e, 0x19f3,
+ 0x623f, 0x065c,
+ 0x6240, 0x0dee,
+ 0x6241, 0x044b,
+ 0x6242, 0x3298,
+ 0x6243, 0x19f5,
+ 0x6244, 0x3299,
+ 0x6247, 0x0d01,
+ 0x6248, 0x19f6,
+ 0x624a, 0x329c,
+ 0x624b, 0x0d6d,
+ 0x624c, 0x14ba,
+ 0x624d, 0x048c,
+ 0x624e, 0x113d,
+ 0x624f, 0x329d,
+ 0x6251, 0x0bea,
+ 0x6252, 0x03d2,
+ 0x6253, 0x0575,
+ 0x6254, 0x0cae,
+ 0x6255, 0x329f,
+ 0x6258, 0x0e81,
+ 0x6259, 0x32a2,
+ 0x625b, 0x0945,
+ 0x625c, 0x32a4,
+ 0x6263, 0x0968,
+ 0x6264, 0x32ab,
+ 0x6266, 0x0c21,
+ 0x6267, 0x11b3,
+ 0x6268, 0x32ad,
+ 0x6269, 0x0994,
+ 0x626a, 0x14bb,
+ 0x626b, 0x0ce1,
+ 0x626c, 0x1018,
+ 0x626d, 0x0b65,
+ 0x626e, 0x03f2,
+ 0x626f, 0x04db,
+ 0x6270, 0x0ca0,
+ 0x6271, 0x32ae,
+ 0x6273, 0x03ed,
+ 0x6274, 0x32b0,
+ 0x6276, 0x0693,
+ 0x6277, 0x32b2,
+ 0x6279, 0x0bbb,
+ 0x627a, 0x32b4,
+ 0x627c, 0x0632,
+ 0x627d, 0x32b6,
+ 0x627e, 0x1173,
+ 0x627f, 0x04f5,
+ 0x6280, 0x082f,
+ 0x6281, 0x32b7,
+ 0x6284, 0x04d2,
+ 0x6285, 0x32ba,
+ 0x6289, 0x0920,
+ 0x628a, 0x03dc,
+ 0x628b, 0x32be,
+ 0x6291, 0x105d,
+ 0x6292, 0x0d7a,
+ 0x6293, 0x1202,
+ 0x6294, 0x32c4,
+ 0x6295, 0x0e67,
+ 0x6296, 0x05f5,
+ 0x6297, 0x0946,
+ 0x6298, 0x117c,
+ 0x6299, 0x32c5,
+ 0x629a, 0x06a2,
+ 0x629b, 0x0b98,
+ 0x629c, 0x32c6,
+ 0x629f, 0x14bc,
+ 0x62a0, 0x0966,
+ 0x62a1, 0x0a7c,
+ 0x62a2, 0x0c3d,
+ 0x62a3, 0x32c9,
+ 0x62a4, 0x07b9,
+ 0x62a5, 0x0411,
+ 0x62a6, 0x32ca,
+ 0x62a8, 0x0bab,
+ 0x62a9, 0x32cc,
+ 0x62ab, 0x0bbc,
+ 0x62ac, 0x0dfa,
+ 0x62ad, 0x32ce,
+ 0x62b1, 0x0410,
+ 0x62b2, 0x32d2,
+ 0x62b5, 0x05b7,
+ 0x62b6, 0x32d5,
+ 0x62b9, 0x0b0b,
+ 0x62ba, 0x32d8,
+ 0x62bb, 0x14bd,
+ 0x62bc, 0x0fe3,
+ 0x62bd, 0x050e,
+ 0x62be, 0x32d9,
+ 0x62bf, 0x0af7,
+ 0x62c0, 0x32da,
+ 0x62c2, 0x0694,
+ 0x62c3, 0x32dc,
+ 0x62c4, 0x11f3,
+ 0x62c5, 0x0584,
+ 0x62c6, 0x04b7,
+ 0x62c7, 0x0b17,
+ 0x62c8, 0x0b4c,
+ 0x62c9, 0x0998,
+ 0x62ca, 0x14be,
+ 0x62cb, 0x32dd,
+ 0x62cc, 0x03f3,
+ 0x62cd, 0x0b85,
+ 0x62ce, 0x0a29,
+ 0x62cf, 0x32de,
+ 0x62d0, 0x072e,
+ 0x62d1, 0x32df,
+ 0x62d2, 0x090b,
+ 0x62d3, 0x0e89,
+ 0x62d4, 0x03d9,
+ 0x62d5, 0x32e0,
+ 0x62d6, 0x0e80,
+ 0x62d7, 0x14c0,
+ 0x62d8, 0x08ff,
+ 0x62d9, 0x121b,
+ 0x62da, 0x14bf,
+ 0x62db, 0x1171,
+ 0x62dc, 0x03e8,
+ 0x62dd, 0x32e1,
+ 0x62df, 0x0b45,
+ 0x62e0, 0x32e3,
+ 0x62e2, 0x0a4a,
+ 0x62e3, 0x0863,
+ 0x62e4, 0x32e5,
+ 0x62e5, 0x109a,
+ 0x62e6, 0x09a4,
+ 0x62e7, 0x0b62,
+ 0x62e8, 0x046d,
+ 0x62e9, 0x1134,
+ 0x62ea, 0x32e6,
+ 0x62ec, 0x0993,
+ 0x62ed, 0x0d5a,
+ 0x62ee, 0x14c1,
+ 0x62ef, 0x119d,
+ 0x62f0, 0x32e8,
+ 0x62f1, 0x0709,
+ 0x62f2, 0x32e9,
+ 0x62f3, 0x0c88,
+ 0x62f4, 0x0d9e,
+ 0x62f5, 0x32ea,
+ 0x62f6, 0x14c3,
+ 0x62f7, 0x094a,
+ 0x62f8, 0x32eb,
+ 0x62fc, 0x0bd3,
+ 0x62fd, 0x1204,
+ 0x62fe, 0x0d47,
+ 0x62ff, 0x0b26,
+ 0x6300, 0x32ef,
+ 0x6301, 0x04fb,
+ 0x6302, 0x072b,
+ 0x6303, 0x32f0,
+ 0x6307, 0x11b7,
+ 0x6308, 0x194e,
+ 0x6309, 0x03bf,
+ 0x630a, 0x32f4,
+ 0x630e, 0x0973,
+ 0x630f, 0x32f8,
+ 0x6311, 0x0e47,
+ 0x6312, 0x32fa,
+ 0x6316, 0x0e8b,
+ 0x6317, 0x32fe,
+ 0x631a, 0x11be,
+ 0x631b, 0x0a75,
+ 0x631c, 0x3301,
+ 0x631d, 0x0edd,
+ 0x631e, 0x0df5,
+ 0x631f, 0x0f79,
+ 0x6320, 0x0b36,
+ 0x6321, 0x0593,
+ 0x6322, 0x14c2,
+ 0x6323, 0x1196,
+ 0x6324, 0x082a,
+ 0x6325, 0x07e8,
+ 0x6326, 0x3302,
+ 0x6328, 0x03af,
+ 0x6329, 0x3304,
+ 0x632a, 0x0b73,
+ 0x632b, 0x056f,
+ 0x632c, 0x3305,
+ 0x632f, 0x1192,
+ 0x6330, 0x3308,
+ 0x6332, 0x194f,
+ 0x6333, 0x330a,
+ 0x6339, 0x14c4,
+ 0x633a, 0x0e57,
+ 0x633b, 0x3310,
+ 0x633d, 0x0e9d,
+ 0x633e, 0x21d1,
+ 0x633f, 0x3312,
+ 0x6342, 0x0ef5,
+ 0x6343, 0x14c6,
+ 0x6344, 0x3315,
+ 0x6345, 0x0e62,
+ 0x6346, 0x0991,
+ 0x6347, 0x3316,
+ 0x6349, 0x121a,
+ 0x634a, 0x3318,
+ 0x634b, 0x14c5,
+ 0x634c, 0x03d1,
+ 0x634d, 0x076b,
+ 0x634e, 0x0d0c,
+ 0x634f, 0x0b56,
+ 0x6350, 0x0917,
+ 0x6351, 0x3319,
+ 0x6355, 0x047d,
+ 0x6356, 0x331d,
+ 0x635e, 0x09b7,
+ 0x635f, 0x0de5,
+ 0x6360, 0x3325,
+ 0x6361, 0x0864,
+ 0x6362, 0x07d0,
+ 0x6363, 0x0598,
+ 0x6364, 0x3326,
+ 0x6367, 0x0bb6,
+ 0x6368, 0x211c,
+ 0x6369, 0x14d0,
+ 0x636a, 0x3329,
+ 0x636b, 0x235d,
+ 0x636c, 0x332a,
+ 0x636d, 0x14cd,
+ 0x636e, 0x090c,
+ 0x636f, 0x332b,
+ 0x6371, 0x14c9,
+ 0x6372, 0x2682,
+ 0x6373, 0x332d,
+ 0x6376, 0x053a,
+ 0x6377, 0x08ae,
+ 0x6378, 0x3330,
+ 0x637a, 0x14ca,
+ 0x637b, 0x0b50,
+ 0x637c, 0x3332,
+ 0x6380, 0x0f33,
+ 0x6381, 0x3336,
+ 0x6382, 0x05c1,
+ 0x6383, 0x210d,
+ 0x6384, 0x205a,
+ 0x6385, 0x3337,
+ 0x6387, 0x061d,
+ 0x6388, 0x0d71,
+ 0x6389, 0x05d5,
+ 0x638a, 0x14cf,
+ 0x638b, 0x3339,
+ 0x638c, 0x1167,
+ 0x638d, 0x333a,
+ 0x638e, 0x14cb,
+ 0x638f, 0x0e20,
+ 0x6390, 0x0c1d,
+ 0x6391, 0x333b,
+ 0x6392, 0x0b86,
+ 0x6393, 0x333c,
+ 0x6396, 0x103b,
+ 0x6397, 0x333f,
+ 0x6398, 0x0921,
+ 0x6399, 0x3340,
+ 0x63a0, 0x0a7a,
+ 0x63a1, 0x3347,
+ 0x63a2, 0x0e10,
+ 0x63a3, 0x04dd,
+ 0x63a4, 0x3348,
+ 0x63a5, 0x08a4,
+ 0x63a6, 0x3349,
+ 0x63a7, 0x0965,
+ 0x63a8, 0x0e77,
+ 0x63a9, 0x1003,
+ 0x63aa, 0x056e,
+ 0x63ab, 0x334a,
+ 0x63ac, 0x14ce,
+ 0x63ad, 0x14c7,
+ 0x63ae, 0x14d1,
+ 0x63af, 0x334b,
+ 0x63b0, 0x1950,
+ 0x63b1, 0x334c,
+ 0x63b3, 0x0a57,
+ 0x63b4, 0x14cc,
+ 0x63b5, 0x334e,
+ 0x63b7, 0x11bf,
+ 0x63b8, 0x0588,
+ 0x63b9, 0x3350,
+ 0x63ba, 0x04bb,
+ 0x63bb, 0x3351,
+ 0x63bc, 0x14d2,
+ 0x63bd, 0x3352,
+ 0x63be, 0x14dc,
+ 0x63bf, 0x3353,
+ 0x63c0, 0x1f8d,
+ 0x63c1, 0x3354,
+ 0x63c4, 0x14d7,
+ 0x63c5, 0x3357,
+ 0x63c6, 0x14db,
+ 0x63c7, 0x3358,
+ 0x63c9, 0x0cbb,
+ 0x63ca, 0x335a,
+ 0x63cd, 0x123e,
+ 0x63ce, 0x14d9,
+ 0x63cf, 0x0aed,
+ 0x63d0, 0x0e34,
+ 0x63d1, 0x335d,
+ 0x63d2, 0x04ac,
+ 0x63d3, 0x335e,
+ 0x63d6, 0x1045,
+ 0x63d7, 0x3361,
+ 0x63da, 0x21ff,
+ 0x63db, 0x3364,
+ 0x63de, 0x14d8,
+ 0x63df, 0x3367,
+ 0x63e0, 0x14d5,
+ 0x63e1, 0x0ee4,
+ 0x63e2, 0x3368,
+ 0x63e3, 0x052a,
+ 0x63e4, 0x3369,
+ 0x63e9, 0x0938,
+ 0x63ea, 0x08ed,
+ 0x63eb, 0x336e,
+ 0x63ed, 0x08a3,
+ 0x63ee, 0x1f58,
+ 0x63ef, 0x3370,
+ 0x63f2, 0x14d3,
+ 0x63f3, 0x3373,
+ 0x63f4, 0x10f1,
+ 0x63f5, 0x3374,
+ 0x63f6, 0x14c8,
+ 0x63f7, 0x3375,
+ 0x63f8, 0x14d4,
+ 0x63f9, 0x3376,
+ 0x63fd, 0x09aa,
+ 0x63fe, 0x337a,
+ 0x63ff, 0x14d6,
+ 0x6400, 0x04ba,
+ 0x6401, 0x06e4,
+ 0x6402, 0x0a4e,
+ 0x6403, 0x337b,
+ 0x6405, 0x0892,
+ 0x6406, 0x337d,
+ 0x640b, 0x14df,
+ 0x640c, 0x14e2,
+ 0x640d, 0x215b,
+ 0x640e, 0x3382,
+ 0x640f, 0x0472,
+ 0x6410, 0x0527,
+ 0x6411, 0x3383,
+ 0x6413, 0x056d,
+ 0x6414, 0x0cdf,
+ 0x6415, 0x3385,
+ 0x6417, 0x1eb6,
+ 0x6418, 0x3387,
+ 0x641b, 0x14e0,
+ 0x641c, 0x0dc6,
+ 0x641d, 0x338a,
+ 0x641e, 0x06de,
+ 0x641f, 0x338b,
+ 0x6420, 0x14e1,
+ 0x6421, 0x14e4,
+ 0x6422, 0x338c,
+ 0x6426, 0x14e3,
+ 0x6427, 0x3390,
+ 0x642a, 0x0e15,
+ 0x642b, 0x3393,
+ 0x642c, 0x03ec,
+ 0x642d, 0x0571,
+ 0x642e, 0x3394,
+ 0x6434, 0x1736,
+ 0x6435, 0x339a,
+ 0x6436, 0x20db,
+ 0x6437, 0x339b,
+ 0x643a, 0x0f7a,
+ 0x643b, 0x339e,
+ 0x643d, 0x04b2,
+ 0x643e, 0x33a0,
+ 0x643f, 0x1951,
+ 0x6440, 0x33a1,
+ 0x6441, 0x14de,
+ 0x6442, 0x33a2,
+ 0x6444, 0x0d1c,
+ 0x6445, 0x14dd,
+ 0x6446, 0x03e5,
+ 0x6447, 0x1028,
+ 0x6448, 0x0460,
+ 0x6449, 0x33a4,
+ 0x644a, 0x0e02,
+ 0x644b, 0x33a5,
+ 0x6451, 0x2360,
+ 0x6452, 0x14da,
+ 0x6453, 0x33ab,
+ 0x6454, 0x0d99,
+ 0x6455, 0x33ac,
+ 0x6458, 0x114b,
+ 0x6459, 0x33af,
+ 0x645c, 0x2361,
+ 0x645d, 0x33b2,
+ 0x645e, 0x14e5,
+ 0x645f, 0x2040,
+ 0x6460, 0x33b3,
+ 0x6467, 0x0560,
+ 0x6468, 0x33ba,
+ 0x6469, 0x0b09,
+ 0x646a, 0x33bb,
+ 0x646d, 0x14e7,
+ 0x646e, 0x33be,
+ 0x646f, 0x228e,
+ 0x6470, 0x33bf,
+ 0x6473, 0x1fdf,
+ 0x6474, 0x33c2,
+ 0x6476, 0x235e,
+ 0x6477, 0x33c4,
+ 0x6478, 0x0b03,
+ 0x647a, 0x14e9,
+ 0x647b, 0x1e6a,
+ 0x647c, 0x33c5,
+ 0x6482, 0x0a15,
+ 0x6483, 0x33cb,
+ 0x6484, 0x14e6,
+ 0x6485, 0x091e,
+ 0x6486, 0x33cc,
+ 0x6487, 0x0bd1,
+ 0x6488, 0x2002,
+ 0x6489, 0x33cd,
+ 0x6491, 0x04ea,
+ 0x6492, 0x0cd1,
+ 0x6493, 0x2093,
+ 0x6494, 0x33d5,
+ 0x6495, 0x0daf,
+ 0x6496, 0x14e8,
+ 0x6497, 0x33d6,
+ 0x6499, 0x14ec,
+ 0x649a, 0x33d8,
+ 0x649e, 0x120f,
+ 0x649f, 0x235f,
+ 0x64a0, 0x33dc,
+ 0x64a3, 0x1eac,
+ 0x64a4, 0x04dc,
+ 0x64a5, 0x1e54,
+ 0x64a6, 0x33df,
+ 0x64a9, 0x0a0c,
+ 0x64aa, 0x33e2,
+ 0x64ab, 0x1f08,
+ 0x64ac, 0x0c48,
+ 0x64ad, 0x046c,
+ 0x64ae, 0x056c,
+ 0x64af, 0x33e3,
+ 0x64b0, 0x1208,
+ 0x64b1, 0x33e4,
+ 0x64b2, 0x20c0,
+ 0x64b3, 0x2362,
+ 0x64b4, 0x33e5,
+ 0x64b5, 0x0b4f,
+ 0x64b6, 0x33e6,
+ 0x64b7, 0x14ea,
+ 0x64b9, 0x33e7,
+ 0x64ba, 0x14ed,
+ 0x64bb, 0x2160,
+ 0x64bc, 0x076a,
+ 0x64bd, 0x33e8,
+ 0x64be, 0x219d,
+ 0x64bf, 0x1f8e,
+ 0x64c0, 0x14ee,
+ 0x64c1, 0x222d,
+ 0x64c2, 0x09c9,
+ 0x64c3, 0x33e9,
+ 0x64c4, 0x2047,
+ 0x64c5, 0x0cfc,
+ 0x64c6, 0x33ea,
+ 0x64c7, 0x2262,
+ 0x64c8, 0x33eb,
+ 0x64ca, 0x1f67,
+ 0x64cb, 0x1eb2,
+ 0x64cc, 0x33ed,
+ 0x64cd, 0x04a0,
+ 0x64ce, 0x0c63,
+ 0x64cf, 0x33ee,
+ 0x64d0, 0x14ef,
+ 0x64d1, 0x33ef,
+ 0x64d2, 0x0c59,
+ 0x64d3, 0x33f0,
+ 0x64d4, 0x1ea9,
+ 0x64d5, 0x33f1,
+ 0x64d7, 0x14f0,
+ 0x64d8, 0x1952,
+ 0x64d9, 0x33f3,
+ 0x64da, 0x1fcc,
+ 0x64db, 0x33f4,
+ 0x64de, 0x0dc8,
+ 0x64df, 0x33f7,
+ 0x64e0, 0x1f72,
+ 0x64e1, 0x33f8,
+ 0x64e2, 0x14f2,
+ 0x64e3, 0x33f9,
+ 0x64e4, 0x14f1,
+ 0x64e5, 0x33fa,
+ 0x64e6, 0x0488,
+ 0x64e7, 0x33fb,
+ 0x64ec, 0x2098,
+ 0x64ed, 0x3400,
+ 0x64ef, 0x1e52,
+ 0x64f0, 0x20a4,
+ 0x64f1, 0x1f1c,
+ 0x64f2, 0x228f,
+ 0x64f3, 0x3402,
+ 0x64f4, 0x1fed,
+ 0x64f5, 0x3403,
+ 0x64f7, 0x2365,
+ 0x64f8, 0x3405,
+ 0x64fa, 0x1e2d,
+ 0x64fb, 0x2152,
+ 0x64fc, 0x2366,
+ 0x64fd, 0x3407,
+ 0x64fe, 0x20fa,
+ 0x64ff, 0x3408,
+ 0x6500, 0x0b8b,
+ 0x6501, 0x3409,
+ 0x6504, 0x2363,
+ 0x6505, 0x340c,
+ 0x6506, 0x209a,
+ 0x6507, 0x340d,
+ 0x6509, 0x14f3,
+ 0x650a, 0x340f,
+ 0x650f, 0x203c,
+ 0x6510, 0x3414,
+ 0x6512, 0x111f,
+ 0x6513, 0x3416,
+ 0x6514, 0x1ff6,
+ 0x6515, 0x3417,
+ 0x6516, 0x2364,
+ 0x6517, 0x3418,
+ 0x6518, 0x0c9c,
+ 0x6519, 0x1e69,
+ 0x651a, 0x3419,
+ 0x651b, 0x2367,
+ 0x651c, 0x341a,
+ 0x651d, 0x211d,
+ 0x651e, 0x341b,
+ 0x6522, 0x2259,
+ 0x6523, 0x2056,
+ 0x6524, 0x2163,
+ 0x6525, 0x14f4,
+ 0x6526, 0x341f,
+ 0x652a, 0x1fa9,
+ 0x652b, 0x091f,
+ 0x652c, 0x1ffc,
+ 0x652d, 0x3423,
+ 0x652e, 0x14f5,
+ 0x652f, 0x11a6,
+ 0x6530, 0x3424,
+ 0x6534, 0x1909,
+ 0x6535, 0x1966,
+ 0x6536, 0x0d6c,
+ 0x6537, 0x3428,
+ 0x6538, 0x12b2,
+ 0x6539, 0x06bf,
+ 0x653a, 0x3429,
+ 0x653b, 0x06fe,
+ 0x653c, 0x342a,
+ 0x653e, 0x0662,
+ 0x653f, 0x119f,
+ 0x6540, 0x342c,
+ 0x6545, 0x0723,
+ 0x6546, 0x3431,
+ 0x6548, 0x0f72,
+ 0x6549, 0x1ccb,
+ 0x654a, 0x3433,
+ 0x654c, 0x05b1,
+ 0x654d, 0x3435,
+ 0x654f, 0x0af9,
+ 0x6550, 0x3437,
+ 0x6551, 0x08f7,
+ 0x6552, 0x3438,
+ 0x6555, 0x1967,
+ 0x6556, 0x03c8,
+ 0x6557, 0x1e2e,
+ 0x6558, 0x343b,
+ 0x6559, 0x089d,
+ 0x655a, 0x343c,
+ 0x655b, 0x09fb,
+ 0x655c, 0x343d,
+ 0x655d, 0x043f,
+ 0x655e, 0x04cd,
+ 0x655f, 0x343e,
+ 0x6562, 0x06cd,
+ 0x6563, 0x0cdb,
+ 0x6564, 0x3441,
+ 0x6566, 0x0617,
+ 0x6567, 0x3443,
+ 0x656b, 0x1968,
+ 0x656c, 0x08e3,
+ 0x656d, 0x3447,
+ 0x6570, 0x0d94,
+ 0x6571, 0x344a,
+ 0x6572, 0x0c40,
+ 0x6573, 0x344b,
+ 0x6574, 0x119c,
+ 0x6575, 0x1ebc,
+ 0x6576, 0x344c,
+ 0x6577, 0x0690,
+ 0x6578, 0x2142,
+ 0x6579, 0x344d,
+ 0x6582, 0x201e,
+ 0x6583, 0x1e43,
+ 0x6584, 0x3456,
+ 0x6587, 0x0ed3,
+ 0x6588, 0x3459,
+ 0x658b, 0x114c,
+ 0x658c, 0x045c,
+ 0x658d, 0x345c,
+ 0x6590, 0x19c1,
+ 0x6591, 0x03ea,
+ 0x6592, 0x345f,
+ 0x6593, 0x19c3,
+ 0x6594, 0x3460,
+ 0x6595, 0x24d4,
+ 0x6596, 0x3461,
+ 0x6597, 0x05f6,
+ 0x6598, 0x3462,
+ 0x6599, 0x0a18,
+ 0x659a, 0x3463,
+ 0x659b, 0x1d56,
+ 0x659c, 0x0f7c,
+ 0x659d, 0x3464,
+ 0x659f, 0x1186,
+ 0x65a0, 0x3466,
+ 0x65a1, 0x0ee2,
+ 0x65a2, 0x3467,
+ 0x65a4, 0x08c0,
+ 0x65a5, 0x0507,
+ 0x65a6, 0x3469,
+ 0x65a7, 0x06a6,
+ 0x65a8, 0x346a,
+ 0x65a9, 0x1157,
+ 0x65aa, 0x346b,
+ 0x65ab, 0x1a29,
+ 0x65ac, 0x226f,
+ 0x65ad, 0x060e,
+ 0x65ae, 0x346c,
+ 0x65af, 0x0dae,
+ 0x65b0, 0x0f8d,
+ 0x65b1, 0x346d,
+ 0x65b7, 0x1ed7,
+ 0x65b8, 0x3473,
+ 0x65b9, 0x065a,
+ 0x65ba, 0x3474,
+ 0x65bc, 0x19c4,
+ 0x65bd, 0x0d40,
+ 0x65be, 0x3476,
+ 0x65c1, 0x0b95,
+ 0x65c2, 0x3479,
+ 0x65c3, 0x19c7,
+ 0x65c4, 0x19c6,
+ 0x65c5, 0x0a6a,
+ 0x65c6, 0x19c5,
+ 0x65c7, 0x347a,
+ 0x65cb, 0x0fc8,
+ 0x65cc, 0x19c8,
+ 0x65cd, 0x347e,
+ 0x65ce, 0x19c9,
+ 0x65cf, 0x1242,
+ 0x65d0, 0x347f,
+ 0x65d2, 0x19ca,
+ 0x65d3, 0x3481,
+ 0x65d6, 0x19cb,
+ 0x65d7, 0x0c0b,
+ 0x65d8, 0x3484,
+ 0x65e0, 0x0eed,
+ 0x65e1, 0x348c,
+ 0x65e2, 0x083b,
+ 0x65e3, 0x348d,
+ 0x65e5, 0x0cb0,
+ 0x65e6, 0x058a,
+ 0x65e7, 0x08f8,
+ 0x65e8, 0x11bb,
+ 0x65e9, 0x112a,
+ 0x65ea, 0x348f,
+ 0x65ec, 0x0fd7,
+ 0x65ed, 0x0fbc,
+ 0x65ee, 0x190a,
+ 0x65f1, 0x076c,
+ 0x65f2, 0x3491,
+ 0x65f6, 0x0d48,
+ 0x65f7, 0x0982,
+ 0x65f8, 0x3495,
+ 0x65fa, 0x0eab,
+ 0x65fb, 0x3497,
+ 0x6600, 0x1912,
+ 0x6601, 0x349c,
+ 0x6602, 0x03c5,
+ 0x6603, 0x1910,
+ 0x6604, 0x349d,
+ 0x6606, 0x0990,
+ 0x6607, 0x349f,
+ 0x660a, 0x190d,
+ 0x660b, 0x34a2,
+ 0x660c, 0x04c4,
+ 0x660d, 0x34a3,
+ 0x660e, 0x0afc,
+ 0x660f, 0x07fd,
+ 0x6610, 0x34a4,
+ 0x6613, 0x105e,
+ 0x6614, 0x0f03,
+ 0x6615, 0x1911,
+ 0x6616, 0x34a7,
+ 0x6619, 0x190e,
+ 0x661a, 0x34aa,
+ 0x661d, 0x1915,
+ 0x661e, 0x34ad,
+ 0x661f, 0x0f92,
+ 0x6620, 0x1098,
+ 0x6621, 0x34ae,
+ 0x6625, 0x053d,
+ 0x6626, 0x34b2,
+ 0x6627, 0x0ac6,
+ 0x6628, 0x124f,
+ 0x6629, 0x34b3,
+ 0x662d, 0x1172,
+ 0x662e, 0x34b7,
+ 0x662f, 0x0d5e,
+ 0x6630, 0x34b8,
+ 0x6631, 0x1917,
+ 0x6632, 0x34b9,
+ 0x6634, 0x1916,
+ 0x6635, 0x1919,
+ 0x6636, 0x1918,
+ 0x6637, 0x34bb,
+ 0x663c, 0x11e6,
+ 0x663d, 0x34c0,
+ 0x663e, 0x0f41,
+ 0x663f, 0x34c1,
+ 0x6641, 0x191d,
+ 0x6642, 0x212d,
+ 0x6643, 0x07e3,
+ 0x6644, 0x34c3,
+ 0x664b, 0x08cb,
+ 0x664c, 0x0d07,
+ 0x664d, 0x34ca,
+ 0x664f, 0x191e,
+ 0x6650, 0x34cc,
+ 0x6652, 0x0cf2,
+ 0x6653, 0x0f6b,
+ 0x6654, 0x191c,
+ 0x6655, 0x1111,
+ 0x6656, 0x191f,
+ 0x6657, 0x1921,
+ 0x6658, 0x34ce,
+ 0x665a, 0x0e9e,
+ 0x665b, 0x34d0,
+ 0x665d, 0x229b,
+ 0x665e, 0x34d2,
+ 0x665f, 0x191b,
+ 0x6660, 0x34d3,
+ 0x6661, 0x1920,
+ 0x6662, 0x34d4,
+ 0x6664, 0x0efd,
+ 0x6665, 0x34d6,
+ 0x6666, 0x07f3,
+ 0x6667, 0x34d7,
+ 0x6668, 0x04e4,
+ 0x6669, 0x34d8,
+ 0x666e, 0x0bf4,
+ 0x666f, 0x08df,
+ 0x6670, 0x0f09,
+ 0x6671, 0x34dd,
+ 0x6674, 0x0c64,
+ 0x6675, 0x34e0,
+ 0x6676, 0x08d6,
+ 0x6677, 0x1922,
+ 0x6678, 0x34e1,
+ 0x667a, 0x11c6,
+ 0x667b, 0x34e3,
+ 0x667e, 0x0a09,
+ 0x667f, 0x34e6,
+ 0x6682, 0x1120,
+ 0x6683, 0x34e9,
+ 0x6684, 0x1923,
+ 0x6685, 0x34ea,
+ 0x6687, 0x0f2b,
+ 0x6688, 0x2256,
+ 0x6689, 0x24a8,
+ 0x668a, 0x34ec,
+ 0x668c, 0x1924,
+ 0x668d, 0x34ee,
+ 0x6691, 0x0d85,
+ 0x6692, 0x34f2,
+ 0x6696, 0x0b70,
+ 0x6697, 0x03c0,
+ 0x6698, 0x34f6,
+ 0x669d, 0x1926,
+ 0x669e, 0x34fb,
+ 0x66a2, 0x1e79,
+ 0x66a3, 0x34ff,
+ 0x66a7, 0x1925,
+ 0x66a8, 0x1cdd,
+ 0x66a9, 0x3503,
+ 0x66ab, 0x225a,
+ 0x66ac, 0x3505,
+ 0x66ae, 0x0b1d,
+ 0x66af, 0x3507,
+ 0x66b4, 0x0412,
+ 0x66b5, 0x350c,
+ 0x66b9, 0x175b,
+ 0x66ba, 0x3510,
+ 0x66be, 0x1927,
+ 0x66bf, 0x3514,
+ 0x66c4, 0x24a7,
+ 0x66c5, 0x3519,
+ 0x66c6, 0x2686,
+ 0x66c7, 0x24a6,
+ 0x66c8, 0x351a,
+ 0x66c9, 0x21ce,
+ 0x66ca, 0x351b,
+ 0x66d6, 0x24a9,
+ 0x66d7, 0x3527,
+ 0x66d9, 0x0d86,
+ 0x66da, 0x3529,
+ 0x66db, 0x1928,
+ 0x66dd, 0x0bf7,
+ 0x66de, 0x352a,
+ 0x66e0, 0x1fe7,
+ 0x66e1, 0x352c,
+ 0x66e6, 0x192a,
+ 0x66e7, 0x3531,
+ 0x66e9, 0x192b,
+ 0x66ea, 0x3533,
+ 0x66ec, 0x2112,
+ 0x66ed, 0x3535,
+ 0x66f0, 0x10fe,
+ 0x66f1, 0x3538,
+ 0x66f2, 0x0c77,
+ 0x66f3, 0x103e,
+ 0x66f4, 0x06f7,
+ 0x66f5, 0x3539,
+ 0x66f7, 0x1914,
+ 0x66f8, 0x213c,
+ 0x66f9, 0x04a3,
+ 0x66fa, 0x353b,
+ 0x66fc, 0x0aa3,
+ 0x66fd, 0x353d,
+ 0x66fe, 0x113b,
+ 0x66ff, 0x0e39,
+ 0x6700, 0x124b,
+ 0x6701, 0x353e,
+ 0x6703, 0x1f5c,
+ 0x6704, 0x3540,
+ 0x6708, 0x1105,
+ 0x6709, 0x10b5,
+ 0x670a, 0x1973,
+ 0x670b, 0x0bb4,
+ 0x670c, 0x3544,
+ 0x670d, 0x069b,
+ 0x670e, 0x3545,
+ 0x6710, 0x1984,
+ 0x6711, 0x3547,
+ 0x6714, 0x0dac,
+ 0x6715, 0x198e,
+ 0x6716, 0x354a,
+ 0x6717, 0x09b5,
+ 0x6718, 0x354b,
+ 0x671b, 0x0eac,
+ 0x671c, 0x354e,
+ 0x671d, 0x04d4,
+ 0x671e, 0x354f,
+ 0x671f, 0x0bf9,
+ 0x6720, 0x3550,
+ 0x6726, 0x19ac,
+ 0x6727, 0x24c4,
+ 0x6728, 0x0b21,
+ 0x6729, 0x3556,
+ 0x672a, 0x0ec3,
+ 0x672b, 0x0b0c,
+ 0x672c, 0x0427,
+ 0x672d, 0x1140,
+ 0x672e, 0x3557,
+ 0x672f, 0x0d8c,
+ 0x6730, 0x3558,
+ 0x6731, 0x11eb,
+ 0x6732, 0x3559,
+ 0x6734, 0x0bf2,
+ 0x6735, 0x0623,
+ 0x6736, 0x355b,
+ 0x673a, 0x080f,
+ 0x673b, 0x355f,
+ 0x673d, 0x0fab,
+ 0x673e, 0x3561,
+ 0x6740, 0x0cea,
+ 0x6741, 0x3563,
+ 0x6742, 0x1116,
+ 0x6743, 0x0c83,
+ 0x6744, 0x3564,
+ 0x6746, 0x06c6,
+ 0x6747, 0x3566,
+ 0x6748, 0x1854,
+ 0x6749, 0x0cf5,
+ 0x674a, 0x3567,
+ 0x674c, 0x1851,
+ 0x674d, 0x3569,
+ 0x674e, 0x09d9,
+ 0x674f, 0x0f9e,
+ 0x6750, 0x048b,
+ 0x6751, 0x0568,
+ 0x6752, 0x356a,
+ 0x6753, 0x1852,
+ 0x6754, 0x356b,
+ 0x6756, 0x1169,
+ 0x6757, 0x356d,
+ 0x675c, 0x0604,
+ 0x675d, 0x3572,
+ 0x675e, 0x1853,
+ 0x675f, 0x0d8f,
+ 0x6760, 0x06d7,
+ 0x6761, 0x0e48,
+ 0x6762, 0x3573,
+ 0x6765, 0x099f,
+ 0x6766, 0x3576,
+ 0x6768, 0x1017,
+ 0x6769, 0x1855,
+ 0x676a, 0x1858,
+ 0x676b, 0x3578,
+ 0x676d, 0x0773,
+ 0x676e, 0x357a,
+ 0x676f, 0x0416,
+ 0x6770, 0x08ad,
+ 0x6771, 0x1ecc,
+ 0x6772, 0x190f,
+ 0x6773, 0x1859,
+ 0x6774, 0x357b,
+ 0x6775, 0x185c,
+ 0x6776, 0x357c,
+ 0x6777, 0x1861,
+ 0x6778, 0x357d,
+ 0x677c, 0x1862,
+ 0x677d, 0x3581,
+ 0x677e, 0x0dbe,
+ 0x677f, 0x03f0,
+ 0x6780, 0x3582,
+ 0x6781, 0x081e,
+ 0x6782, 0x3583,
+ 0x6784, 0x0712,
+ 0x6785, 0x3585,
+ 0x6787, 0x1857,
+ 0x6788, 0x3587,
+ 0x6789, 0x0ea8,
+ 0x678a, 0x3588,
+ 0x678b, 0x1860,
+ 0x678c, 0x3589,
+ 0x6790, 0x0f05,
+ 0x6791, 0x358d,
+ 0x6795, 0x118e,
+ 0x6796, 0x3591,
+ 0x6797, 0x0a1f,
+ 0x6798, 0x185a,
+ 0x6799, 0x3592,
+ 0x679a, 0x0abb,
+ 0x679b, 0x3593,
+ 0x679c, 0x0754,
+ 0x679d, 0x11a5,
+ 0x679e, 0x185e,
+ 0x679f, 0x3594,
+ 0x67a2, 0x0d77,
+ 0x67a3, 0x1129,
+ 0x67a4, 0x3597,
+ 0x67a5, 0x1856,
+ 0x67a6, 0x3598,
+ 0x67a7, 0x185b,
+ 0x67a8, 0x185d,
+ 0x67a9, 0x3599,
+ 0x67aa, 0x0c36,
+ 0x67ab, 0x0680,
+ 0x67ac, 0x359a,
+ 0x67ad, 0x185f,
+ 0x67ae, 0x359b,
+ 0x67af, 0x096a,
+ 0x67b0, 0x1868,
+ 0x67b1, 0x359c,
+ 0x67b3, 0x186d,
+ 0x67b4, 0x359e,
+ 0x67b5, 0x186b,
+ 0x67b6, 0x084f,
+ 0x67b7, 0x0842,
+ 0x67b8, 0x1871,
+ 0x67b9, 0x359f,
+ 0x67c1, 0x1874,
+ 0x67c2, 0x35a7,
+ 0x67c3, 0x1870,
+ 0x67c4, 0x0463,
+ 0x67c5, 0x35a8,
+ 0x67cf, 0x03e3,
+ 0x67d0, 0x0b16,
+ 0x67d1, 0x06c7,
+ 0x67d2, 0x0c01,
+ 0x67d3, 0x0c99,
+ 0x67d4, 0x0cbc,
+ 0x67d5, 0x35b2,
+ 0x67d8, 0x1865,
+ 0x67d9, 0x186a,
+ 0x67da, 0x186c,
+ 0x67db, 0x35b5,
+ 0x67dc, 0x074a,
+ 0x67dd, 0x186e,
+ 0x67de, 0x1252,
+ 0x67df, 0x35b6,
+ 0x67e0, 0x0b5e,
+ 0x67e1, 0x35b7,
+ 0x67e2, 0x1872,
+ 0x67e3, 0x35b8,
+ 0x67e5, 0x04b0,
+ 0x67e6, 0x35ba,
+ 0x67e9, 0x1867,
+ 0x67ea, 0x35bd,
+ 0x67ec, 0x0860,
+ 0x67ed, 0x35bf,
+ 0x67ef, 0x094f,
+ 0x67f0, 0x1863,
+ 0x67f1, 0x11f8,
+ 0x67f2, 0x35c1,
+ 0x67f3, 0x0a41,
+ 0x67f4, 0x04b8,
+ 0x67f5, 0x35c2,
+ 0x67fd, 0x1875,
+ 0x67fe, 0x35ca,
+ 0x67ff, 0x0d58,
+ 0x6800, 0x186f,
+ 0x6801, 0x35cb,
+ 0x6805, 0x1145,
+ 0x6806, 0x35cf,
+ 0x6807, 0x0453,
+ 0x6808, 0x115c,
+ 0x6809, 0x1864,
+ 0x680a, 0x1866,
+ 0x680b, 0x05ef,
+ 0x680c, 0x1869,
+ 0x680d, 0x35d0,
+ 0x680e, 0x1873,
+ 0x680f, 0x09a3,
+ 0x6810, 0x35d1,
+ 0x6811, 0x0d8e,
+ 0x6812, 0x35d2,
+ 0x6813, 0x0d9d,
+ 0x6814, 0x35d3,
+ 0x6816, 0x0bfb,
+ 0x6817, 0x09e0,
+ 0x6818, 0x35d5,
+ 0x681d, 0x187f,
+ 0x681e, 0x35da,
+ 0x6821, 0x0f6e,
+ 0x6822, 0x35dd,
+ 0x6829, 0x1888,
+ 0x682a, 0x11e9,
+ 0x682b, 0x35e4,
+ 0x6832, 0x1876,
+ 0x6834, 0x35eb,
+ 0x6837, 0x1022,
+ 0x6838, 0x0782,
+ 0x6839, 0x06f4,
+ 0x683a, 0x35ee,
+ 0x683c, 0x06ec,
+ 0x683d, 0x1117,
+ 0x683e, 0x1885,
+ 0x683f, 0x35f0,
+ 0x6840, 0x1884,
+ 0x6841, 0x1882,
+ 0x6842, 0x0749,
+ 0x6843, 0x0e25,
+ 0x6844, 0x187c,
+ 0x6845, 0x0eb5,
+ 0x6846, 0x097f,
+ 0x6847, 0x35f1,
+ 0x6848, 0x03c3,
+ 0x6849, 0x1887,
+ 0x684a, 0x1886,
+ 0x684b, 0x35f2,
+ 0x684c, 0x121d,
+ 0x684d, 0x35f3,
+ 0x684e, 0x187a,
+ 0x684f, 0x35f4,
+ 0x6850, 0x0e5a,
+ 0x6851, 0x0cdc,
+ 0x6852, 0x35f5,
+ 0x6853, 0x07cd,
+ 0x6854, 0x08ac,
+ 0x6855, 0x1880,
+ 0x6856, 0x35f6,
+ 0x6860, 0x1878,
+ 0x6862, 0x187b,
+ 0x6863, 0x0596,
+ 0x6864, 0x187d,
+ 0x6865, 0x0c42,
+ 0x6866, 0x1881,
+ 0x6867, 0x1883,
+ 0x6868, 0x0881,
+ 0x6869, 0x120b,
+ 0x686a, 0x3600,
+ 0x686b, 0x188e,
+ 0x686c, 0x3601,
+ 0x6874, 0x188b,
+ 0x6875, 0x3609,
+ 0x6876, 0x0e61,
+ 0x6877, 0x188c,
+ 0x6878, 0x360a,
+ 0x6881, 0x0a03,
+ 0x6882, 0x3613,
+ 0x6883, 0x187e,
+ 0x6884, 0x3614,
+ 0x6885, 0x0abc,
+ 0x6886, 0x03fb,
+ 0x6887, 0x3615,
+ 0x688f, 0x188a,
+ 0x6890, 0x361d,
+ 0x6893, 0x188d,
+ 0x6894, 0x3620,
+ 0x6897, 0x06fc,
+ 0x6898, 0x246a,
+ 0x6899, 0x3623,
+ 0x689d, 0x2175,
+ 0x689e, 0x3627,
+ 0x689f, 0x246d,
+ 0x68a0, 0x3628,
+ 0x68a2, 0x0d0b,
+ 0x68a3, 0x362a,
+ 0x68a6, 0x0ad3,
+ 0x68a7, 0x0eef,
+ 0x68a8, 0x09d1,
+ 0x68a9, 0x362d,
+ 0x68ad, 0x0de8,
+ 0x68ae, 0x3631,
+ 0x68af, 0x0e30,
+ 0x68b0, 0x0f80,
+ 0x68b1, 0x3632,
+ 0x68b3, 0x0d78,
+ 0x68b4, 0x3634,
+ 0x68b5, 0x1889,
+ 0x68b6, 0x3635,
+ 0x68c0, 0x085f,
+ 0x68c1, 0x363f,
+ 0x68c2, 0x188f,
+ 0x68c3, 0x3640,
+ 0x68c9, 0x0ae3,
+ 0x68ca, 0x3646,
+ 0x68cb, 0x0c04,
+ 0x68cc, 0x3647,
+ 0x68cd, 0x0750,
+ 0x68ce, 0x3648,
+ 0x68d2, 0x03ff,
+ 0x68d3, 0x364c,
+ 0x68d5, 0x1235,
+ 0x68d6, 0x246b,
+ 0x68d7, 0x225f,
+ 0x68d8, 0x081f,
+ 0x68d9, 0x364e,
+ 0x68da, 0x0bb0,
+ 0x68db, 0x364f,
+ 0x68df, 0x1ece,
+ 0x68e0, 0x0e17,
+ 0x68e1, 0x3653,
+ 0x68e3, 0x189a,
+ 0x68e4, 0x3655,
+ 0x68e7, 0x2272,
+ 0x68e8, 0x3658,
+ 0x68ee, 0x0ce6,
+ 0x68ef, 0x365e,
+ 0x68f0, 0x1896,
+ 0x68f1, 0x09cd,
+ 0x68f2, 0x365f,
+ 0x68f5, 0x0950,
+ 0x68f6, 0x3662,
+ 0x68f9, 0x1894,
+ 0x68fa, 0x0730,
+ 0x68fb, 0x3665,
+ 0x68fc, 0x1891,
+ 0x68fd, 0x3666,
+ 0x6900, 0x3669,
+ 0x6901, 0x1898,
+ 0x6902, 0x366a,
+ 0x6905, 0x1055,
+ 0x6906, 0x366d,
+ 0x690b, 0x1897,
+ 0x690c, 0x3672,
+ 0x690d, 0x11b1,
+ 0x690e, 0x1212,
+ 0x690f, 0x2473,
+ 0x6910, 0x189b,
+ 0x6911, 0x3673,
+ 0x6912, 0x0888,
+ 0x6913, 0x3674,
+ 0x691f, 0x1892,
+ 0x6921, 0x3680,
+ 0x6924, 0x1895,
+ 0x6925, 0x3683,
+ 0x692d, 0x0e87,
+ 0x692e, 0x368b,
+ 0x6930, 0x1033,
+ 0x6931, 0x368d,
+ 0x6934, 0x18a6,
+ 0x6935, 0x3690,
+ 0x6939, 0x189d,
+ 0x693a, 0x3694,
+ 0x693d, 0x052d,
+ 0x693e, 0x3697,
+ 0x693f, 0x053e,
+ 0x6940, 0x3698,
+ 0x6942, 0x189f,
+ 0x6943, 0x369a,
+ 0x694a, 0x21fe,
+ 0x694b, 0x36a1,
+ 0x6953, 0x1efe,
+ 0x6954, 0x0f73,
+ 0x6955, 0x36a9,
+ 0x6957, 0x1899,
+ 0x6958, 0x36ab,
+ 0x695a, 0x0523,
+ 0x695b, 0x36ad,
+ 0x695d, 0x18a0,
+ 0x695e, 0x09ce,
+ 0x695f, 0x36af,
+ 0x6960, 0x189e,
+ 0x6961, 0x36b0,
+ 0x6963, 0x18ad,
+ 0x6964, 0x36b2,
+ 0x6966, 0x18ac,
+ 0x6967, 0x36b4,
+ 0x6968, 0x2475,
+ 0x6969, 0x36b5,
+ 0x696b, 0x18a2,
+ 0x696c, 0x36b7,
+ 0x696d, 0x220a,
+ 0x696e, 0x1890,
+ 0x696f, 0x36b8,
+ 0x6971, 0x189c,
+ 0x6972, 0x36ba,
+ 0x6975, 0x1f6f,
+ 0x6976, 0x36bd,
+ 0x6977, 0x0939,
+ 0x6978, 0x18a5,
+ 0x6979, 0x18ae,
+ 0x697a, 0x36be,
+ 0x697c, 0x0a4c,
+ 0x697d, 0x36c0,
+ 0x6980, 0x18a3,
+ 0x6981, 0x36c3,
+ 0x6982, 0x06c0,
+ 0x6983, 0x36c4,
+ 0x6984, 0x18a1,
+ 0x6985, 0x36c5,
+ 0x6986, 0x10c1,
+ 0x6987, 0x18a8,
+ 0x6989, 0x18ab,
+ 0x698a, 0x36c6,
+ 0x698d, 0x18bb,
+ 0x698e, 0x36c9,
+ 0x6994, 0x09b1,
+ 0x6995, 0x18b9,
+ 0x6996, 0x36cf,
+ 0x6998, 0x18a4,
+ 0x6999, 0x36d1,
+ 0x699b, 0x18af,
+ 0x699c, 0x03fc,
+ 0x699d, 0x36d3,
+ 0x69a7, 0x18b0,
+ 0x69a8, 0x1146,
+ 0x69a9, 0x36dd,
+ 0x69aa, 0x2468,
+ 0x69ab, 0x18b2,
+ 0x69ac, 0x36de,
+ 0x69ad, 0x18b3,
+ 0x69ae, 0x2100,
+ 0x69af, 0x36df,
+ 0x69b1, 0x18b5,
+ 0x69b2, 0x36e1,
+ 0x69b4, 0x0a3a,
+ 0x69b5, 0x36e3,
+ 0x69b7, 0x0c91,
+ 0x69b8, 0x36e5,
+ 0x69bb, 0x18b1,
+ 0x69bc, 0x36e8,
+ 0x69bf, 0x2476,
+ 0x69c0, 0x36eb,
+ 0x69c1, 0x18b6,
+ 0x69c2, 0x36ec,
+ 0x69ca, 0x18b7,
+ 0x69cb, 0x1f27,
+ 0x69cc, 0x18a7,
+ 0x69cd, 0x20d7,
+ 0x69ce, 0x18aa,
+ 0x69cf, 0x36f4,
+ 0x69d0, 0x07c6,
+ 0x69d1, 0x36f5,
+ 0x69d4, 0x18b4,
+ 0x69d5, 0x36f8,
+ 0x69db, 0x086a,
+ 0x69dc, 0x36fe,
+ 0x69df, 0x18b8,
+ 0x69e0, 0x18ba,
+ 0x69e1, 0x3701,
+ 0x69e7, 0x247c,
+ 0x69e8, 0x3707,
+ 0x69ed, 0x18be,
+ 0x69ee, 0x370c,
+ 0x69f2, 0x18c2,
+ 0x69f3, 0x1fa1,
+ 0x69f4, 0x3710,
+ 0x69fd, 0x04a2,
+ 0x69fe, 0x3719,
+ 0x69ff, 0x18bc,
+ 0x6a00, 0x371a,
+ 0x6a01, 0x22aa,
+ 0x6a02, 0x2005,
+ 0x6a03, 0x371b,
+ 0x6a05, 0x246c,
+ 0x6a06, 0x371d,
+ 0x6a0a, 0x064b,
+ 0x6a0b, 0x3721,
+ 0x6a13, 0x203e,
+ 0x6a14, 0x3729,
+ 0x6a17, 0x18bf,
+ 0x6a19, 0x1e4c,
+ 0x6a1a, 0x372c,
+ 0x6a1e, 0x213a,
+ 0x6a1f, 0x1162,
+ 0x6a20, 0x3730,
+ 0x6a21, 0x0b06,
+ 0x6a22, 0x3731,
+ 0x6a23, 0x2204,
+ 0x6a24, 0x3732,
+ 0x6a28, 0x18cc,
+ 0x6a29, 0x3736,
+ 0x6a2a, 0x0798,
+ 0x6a2b, 0x3737,
+ 0x6a2f, 0x18bd,
+ 0x6a30, 0x373b,
+ 0x6a31, 0x1088,
+ 0x6a32, 0x373c,
+ 0x6a35, 0x18c8,
+ 0x6a36, 0x373f,
+ 0x6a38, 0x20c3,
+ 0x6a39, 0x2140,
+ 0x6a3a, 0x2477,
+ 0x6a3b, 0x3741,
+ 0x6a3d, 0x18cb,
+ 0x6a3e, 0x18c4,
+ 0x6a3f, 0x3743,
+ 0x6a44, 0x18c3,
+ 0x6a45, 0x3748,
+ 0x6a47, 0x0c3e,
+ 0x6a48, 0x2474,
+ 0x6a49, 0x374a,
+ 0x6a4b, 0x20dd,
+ 0x6a4c, 0x374c,
+ 0x6a50, 0x18c6,
+ 0x6a51, 0x3750,
+ 0x6a58, 0x18cd,
+ 0x6a59, 0x04ed,
+ 0x6a5a, 0x3757,
+ 0x6a5b, 0x18c7,
+ 0x6a5c, 0x3758,
+ 0x6a5f, 0x1f68,
+ 0x6a60, 0x375b,
+ 0x6a61, 0x0f5d,
+ 0x6a62, 0x2185,
+ 0x6a63, 0x375c,
+ 0x6a65, 0x18c1,
+ 0x6a66, 0x375e,
+ 0x6a71, 0x051c,
+ 0x6a72, 0x3769,
+ 0x6a79, 0x18ca,
+ 0x6a7a, 0x3770,
+ 0x6a7c, 0x18ce,
+ 0x6a7d, 0x3772,
+ 0x6a80, 0x0e07,
+ 0x6a81, 0x3775,
+ 0x6a84, 0x0f1a,
+ 0x6a85, 0x3778,
+ 0x6a89, 0x2472,
+ 0x6a8a, 0x377c,
+ 0x6a8e, 0x18c9,
+ 0x6a8f, 0x3780,
+ 0x6a90, 0x18d0,
+ 0x6a91, 0x18cf,
+ 0x6a92, 0x3781,
+ 0x6a94, 0x1eb5,
+ 0x6a95, 0x3783,
+ 0x6a97, 0x18d2,
+ 0x6a98, 0x3785,
+ 0x6a9c, 0x2478,
+ 0x6a9d, 0x3789,
+ 0x6aa0, 0x18c5,
+ 0x6aa1, 0x378c,
+ 0x6aa2, 0x1f8b,
+ 0x6aa3, 0x2484,
+ 0x6aa4, 0x378d,
+ 0x6aa9, 0x18d1,
+ 0x6aaa, 0x3792,
+ 0x6aab, 0x18d3,
+ 0x6aac, 0x0acf,
+ 0x6aad, 0x3793,
+ 0x6aaf, 0x2699,
+ 0x6ab0, 0x3795,
+ 0x6ab3, 0x2482,
+ 0x6ab4, 0x3798,
+ 0x6ab8, 0x20a1,
+ 0x6ab9, 0x379c,
+ 0x6abb, 0x1f92,
+ 0x6abc, 0x379e,
+ 0x6ac3, 0x1f38,
+ 0x6ac4, 0x37a5,
+ 0x6ad3, 0x2485,
+ 0x6ad4, 0x37b4,
+ 0x6ada, 0x2480,
+ 0x6adb, 0x246e,
+ 0x6adc, 0x37ba,
+ 0x6add, 0x247b,
+ 0x6ade, 0x2486,
+ 0x6adf, 0x2471,
+ 0x6ae0, 0x37bb,
+ 0x6ae7, 0x2483,
+ 0x6ae8, 0x2470,
+ 0x6ae9, 0x37c2,
+ 0x6aea, 0x2469,
+ 0x6aeb, 0x37c3,
+ 0x6aec, 0x247f,
+ 0x6aed, 0x37c4,
+ 0x6af3, 0x246f,
+ 0x6af4, 0x37ca,
+ 0x6af8, 0x2481,
+ 0x6af9, 0x37ce,
+ 0x6afb, 0x2220,
+ 0x6afc, 0x37d0,
+ 0x6b00, 0x37d4,
+ 0x6b04, 0x1ff5,
+ 0x6b05, 0x37d8,
+ 0x6b0a, 0x20f4,
+ 0x6b0b, 0x37dd,
+ 0x6b0f, 0x247d,
+ 0x6b10, 0x37e1,
+ 0x6b12, 0x2479,
+ 0x6b13, 0x37e3,
+ 0x6b16, 0x247e,
+ 0x6b17, 0x37e6,
+ 0x6b1e, 0x247a,
+ 0x6b1f, 0x37ed,
+ 0x6b20, 0x0c34,
+ 0x6b21, 0x0551,
+ 0x6b22, 0x07cb,
+ 0x6b23, 0x0f8b,
+ 0x6b24, 0x19b1,
+ 0x6b25, 0x37ee,
+ 0x6b27, 0x0b78,
+ 0x6b28, 0x37f0,
+ 0x6b32, 0x10e0,
+ 0x6b33, 0x37fa,
+ 0x6b37, 0x19b2,
+ 0x6b38, 0x37fe,
+ 0x6b39, 0x19b3,
+ 0x6b3a, 0x0bfa,
+ 0x6b3b, 0x37ff,
+ 0x6b3d, 0x20e3,
+ 0x6b3e, 0x097b,
+ 0x6b3f, 0x3801,
+ 0x6b43, 0x19b4,
+ 0x6b44, 0x3805,
+ 0x6b46, 0x19b5,
+ 0x6b47, 0x0f75,
+ 0x6b48, 0x3807,
+ 0x6b49, 0x0c35,
+ 0x6b4a, 0x3808,
+ 0x6b4c, 0x06e3,
+ 0x6b4d, 0x380a,
+ 0x6b50, 0x20ad,
+ 0x6b51, 0x380d,
+ 0x6b59, 0x19b6,
+ 0x6b5a, 0x3815,
+ 0x6b5f, 0x24cb,
+ 0x6b60, 0x381a,
+ 0x6b61, 0x1f53,
+ 0x6b62, 0x11b8,
+ 0x6b63, 0x119e,
+ 0x6b64, 0x054e,
+ 0x6b65, 0x0484,
+ 0x6b66, 0x0ef3,
+ 0x6b67, 0x0c06,
+ 0x6b68, 0x381b,
+ 0x6b6a, 0x0e92,
+ 0x6b6b, 0x381d,
+ 0x6b72, 0x2159,
+ 0x6b73, 0x3824,
+ 0x6b77, 0x2013,
+ 0x6b78, 0x1f33,
+ 0x6b79, 0x0578,
+ 0x6b7a, 0x3828,
+ 0x6b7b, 0x0db5,
+ 0x6b7c, 0x0852,
+ 0x6b7d, 0x3829,
+ 0x6b81, 0x18d6,
+ 0x6b83, 0x1013,
+ 0x6b84, 0x18d9,
+ 0x6b85, 0x382d,
+ 0x6b86, 0x057c,
+ 0x6b87, 0x18d8,
+ 0x6b88, 0x382e,
+ 0x6b89, 0x0fdc,
+ 0x6b8a, 0x0d79,
+ 0x6b8b, 0x0497,
+ 0x6b8c, 0x382f,
+ 0x6b8d, 0x18dc,
+ 0x6b8e, 0x3830,
+ 0x6b92, 0x18da,
+ 0x6b94, 0x3834,
+ 0x6b96, 0x11b2,
+ 0x6b97, 0x3836,
+ 0x6b98, 0x1e5c,
+ 0x6b99, 0x3837,
+ 0x6b9a, 0x18dd,
+ 0x6b9c, 0x3838,
+ 0x6b9e, 0x2488,
+ 0x6b9f, 0x383a,
+ 0x6ba1, 0x18df,
+ 0x6ba2, 0x383c,
+ 0x6ba4, 0x2487,
+ 0x6ba5, 0x383e,
+ 0x6baa, 0x18e0,
+ 0x6bab, 0x248a,
+ 0x6bac, 0x3843,
+ 0x6bae, 0x2489,
+ 0x6baf, 0x248b,
+ 0x6bb0, 0x3845,
+ 0x6bb2, 0x1f83,
+ 0x6bb3, 0x19bd,
+ 0x6bb4, 0x0b7a,
+ 0x6bb5, 0x060d,
+ 0x6bb6, 0x3847,
+ 0x6bb7, 0x107a,
+ 0x6bb8, 0x3848,
+ 0x6bba, 0x210f,
+ 0x6bbb, 0x1fdb,
+ 0x6bbc, 0x384a,
+ 0x6bbf, 0x05cf,
+ 0x6bc0, 0x384d,
+ 0x6bc1, 0x07ee,
+ 0x6bc2, 0x19bf,
+ 0x6bc3, 0x384e,
+ 0x6bc5, 0x106a,
+ 0x6bc6, 0x20af,
+ 0x6bc7, 0x3850,
+ 0x6bcb, 0x0ef2,
+ 0x6bcc, 0x3854,
+ 0x6bcd, 0x0b1b,
+ 0x6bce, 0x3855,
+ 0x6bcf, 0x0ac4,
+ 0x6bd0, 0x3856,
+ 0x6bd2, 0x05fd,
+ 0x6bd3, 0x126f,
+ 0x6bd4, 0x0431,
+ 0x6bd5, 0x0438,
+ 0x6bd6, 0x043a,
+ 0x6bd7, 0x0bbf,
+ 0x6bd8, 0x3858,
+ 0x6bd9, 0x0439,
+ 0x6bda, 0x3859,
+ 0x6bdb, 0x0ab0,
+ 0x6bdc, 0x385a,
+ 0x6be1, 0x1152,
+ 0x6be2, 0x385f,
+ 0x6bea, 0x1954,
+ 0x6beb, 0x0778,
+ 0x6bec, 0x3867,
+ 0x6bef, 0x0e0d,
+ 0x6bf0, 0x386a,
+ 0x6bf3, 0x1955,
+ 0x6bf4, 0x386d,
+ 0x6bf5, 0x1957,
+ 0x6bf6, 0x386e,
+ 0x6bf9, 0x1958,
+ 0x6bfa, 0x3871,
+ 0x6bfd, 0x1956,
+ 0x6bfe, 0x3874,
+ 0x6bff, 0x24c0,
+ 0x6c00, 0x3875,
+ 0x6c05, 0x1959,
+ 0x6c06, 0x195b,
+ 0x6c07, 0x195a,
+ 0x6c08, 0x226d,
+ 0x6c09, 0x387a,
+ 0x6c0c, 0x24c1,
+ 0x6c0d, 0x195c,
+ 0x6c0e, 0x387d,
+ 0x6c0f, 0x0d66,
+ 0x6c10, 0x126b,
+ 0x6c11, 0x0af6,
+ 0x6c12, 0x387e,
+ 0x6c13, 0x0aaa,
+ 0x6c14, 0x0c17,
+ 0x6c15, 0x195d,
+ 0x6c16, 0x0b2d,
+ 0x6c17, 0x387f,
+ 0x6c18, 0x195e,
+ 0x6c1b, 0x0672,
+ 0x6c1c, 0x3880,
+ 0x6c1f, 0x0697,
+ 0x6c20, 0x3883,
+ 0x6c21, 0x1961,
+ 0x6c22, 0x0c5f,
+ 0x6c23, 0x20ca,
+ 0x6c24, 0x1963,
+ 0x6c25, 0x3884,
+ 0x6c26, 0x075b,
+ 0x6c27, 0x101e,
+ 0x6c28, 0x03bc,
+ 0x6c29, 0x1962,
+ 0x6c2a, 0x1964,
+ 0x6c2b, 0x20e7,
+ 0x6c2c, 0x24c2,
+ 0x6c2d, 0x3885,
+ 0x6c2e, 0x058b,
+ 0x6c2f, 0x0a6f,
+ 0x6c30, 0x0c65,
+ 0x6c31, 0x3886,
+ 0x6c32, 0x1965,
+ 0x6c33, 0x3887,
+ 0x6c34, 0x0da3,
+ 0x6c35, 0x169f,
+ 0x6c36, 0x3888,
+ 0x6c38, 0x10a5,
+ 0x6c39, 0x388a,
+ 0x6c3d, 0x12ef,
+ 0x6c3e, 0x388e,
+ 0x6c40, 0x0e52,
+ 0x6c41, 0x11ac,
+ 0x6c42, 0x0c70,
+ 0x6c43, 0x3890,
+ 0x6c46, 0x12f4,
+ 0x6c47, 0x07f8,
+ 0x6c48, 0x3893,
+ 0x6c49, 0x0771,
+ 0x6c4a, 0x16a2,
+ 0x6c4b, 0x3894,
+ 0x6c50, 0x0f18,
+ 0x6c51, 0x3899,
+ 0x6c54, 0x16a0,
+ 0x6c55, 0x0d00,
+ 0x6c56, 0x389c,
+ 0x6c57, 0x0770,
+ 0x6c58, 0x389d,
+ 0x6c5b, 0x0fdd,
+ 0x6c5c, 0x16a1,
+ 0x6c5d, 0x0cc5,
+ 0x6c5e, 0x0708,
+ 0x6c5f, 0x087e,
+ 0x6c60, 0x04fd,
+ 0x6c61, 0x0eea,
+ 0x6c62, 0x38a0,
+ 0x6c64, 0x0e13,
+ 0x6c65, 0x38a2,
+ 0x6c68, 0x16a8,
+ 0x6c6a, 0x0ea5,
+ 0x6c6b, 0x38a5,
+ 0x6c70, 0x0e00,
+ 0x6c71, 0x38aa,
+ 0x6c72, 0x0826,
+ 0x6c73, 0x38ab,
+ 0x6c74, 0x16aa,
+ 0x6c75, 0x38ac,
+ 0x6c76, 0x16ab,
+ 0x6c77, 0x38ad,
+ 0x6c79, 0x0fa5,
+ 0x6c7a, 0x38af,
+ 0x6c7d, 0x0c1a,
+ 0x6c7e, 0x0677,
+ 0x6c7f, 0x38b2,
+ 0x6c81, 0x0c5c,
+ 0x6c82, 0x1051,
+ 0x6c83, 0x0ee5,
+ 0x6c84, 0x38b4,
+ 0x6c85, 0x16a4,
+ 0x6c86, 0x16ac,
+ 0x6c87, 0x38b5,
+ 0x6c88, 0x0d2b,
+ 0x6c89, 0x04e6,
+ 0x6c8a, 0x38b6,
+ 0x6c8c, 0x16a7,
+ 0x6c8d, 0x38b8,
+ 0x6c8f, 0x0c02,
+ 0x6c90, 0x16a5,
+ 0x6c91, 0x38ba,
+ 0x6c93, 0x1a1f,
+ 0x6c94, 0x16a6,
+ 0x6c95, 0x38bc,
+ 0x6c99, 0x0cec,
+ 0x6c9a, 0x38c0,
+ 0x6c9b, 0x0ba7,
+ 0x6c9c, 0x38c1,
+ 0x6c9f, 0x070e,
+ 0x6ca0, 0x38c4,
+ 0x6ca1, 0x0ac0,
+ 0x6ca2, 0x38c5,
+ 0x6ca3, 0x16a3,
+ 0x6ca4, 0x0b7e,
+ 0x6ca5, 0x09ed,
+ 0x6ca6, 0x0a80,
+ 0x6ca7, 0x049e,
+ 0x6ca8, 0x38c6,
+ 0x6ca9, 0x16ad,
+ 0x6caa, 0x07bb,
+ 0x6cab, 0x0b10,
+ 0x6cac, 0x38c7,
+ 0x6cad, 0x16b0,
+ 0x6cae, 0x0909,
+ 0x6caf, 0x38c8,
+ 0x6cb1, 0x16bb,
+ 0x6cb2, 0x16b5,
+ 0x6cb3, 0x078a,
+ 0x6cb4, 0x38ca,
+ 0x6cb8, 0x066d,
+ 0x6cb9, 0x10b2,
+ 0x6cba, 0x38ce,
+ 0x6cbb, 0x11cd,
+ 0x6cbc, 0x1174,
+ 0x6cbd, 0x071a,
+ 0x6cbe, 0x1155,
+ 0x6cbf, 0x1001,
+ 0x6cc0, 0x38cf,
+ 0x6cc4, 0x0f84,
+ 0x6cc5, 0x0c73,
+ 0x6cc6, 0x38d3,
+ 0x6cc9, 0x0c85,
+ 0x6cca, 0x047b,
+ 0x6ccb, 0x38d6,
+ 0x6ccc, 0x0adf,
+ 0x6ccd, 0x38d7,
+ 0x6cd0, 0x16ae,
+ 0x6cd1, 0x38da,
+ 0x6cd3, 0x16bc,
+ 0x6cd4, 0x16af,
+ 0x6cd5, 0x0645,
+ 0x6cd6, 0x16b7,
+ 0x6cd7, 0x16b4,
+ 0x6cd8, 0x38dc,
+ 0x6cdb, 0x0657,
+ 0x6cdc, 0x38df,
+ 0x6cde, 0x0b63,
+ 0x6cdf, 0x38e1,
+ 0x6ce0, 0x16b6,
+ 0x6ce1, 0x0b9e,
+ 0x6ce2, 0x046f,
+ 0x6ce3, 0x0c1b,
+ 0x6ce4, 0x38e2,
+ 0x6ce5, 0x0b43,
+ 0x6ce6, 0x38e3,
+ 0x6ce8, 0x11ff,
+ 0x6ce9, 0x38e5,
+ 0x6cea, 0x09cc,
+ 0x6ceb, 0x16b9,
+ 0x6cec, 0x38e6,
+ 0x6cee, 0x16ba,
+ 0x6cef, 0x16bd,
+ 0x6cf0, 0x0dfc,
+ 0x6cf1, 0x16b3,
+ 0x6cf2, 0x38e8,
+ 0x6cf3, 0x10a3,
+ 0x6cf4, 0x38e9,
+ 0x6cf5, 0x042c,
+ 0x6cf6, 0x1a20,
+ 0x6cf7, 0x16b1,
+ 0x6cf9, 0x38ea,
+ 0x6cfa, 0x16b8,
+ 0x6cfb, 0x0f85,
+ 0x6cfc, 0x0be2,
+ 0x6cfd, 0x1136,
+ 0x6cfe, 0x16be,
+ 0x6cff, 0x38eb,
+ 0x6d00, 0x38ec,
+ 0x6d01, 0x08b1,
+ 0x6d02, 0x38ed,
+ 0x6d04, 0x16c5,
+ 0x6d05, 0x38ef,
+ 0x6d07, 0x16c4,
+ 0x6d08, 0x38f1,
+ 0x6d0b, 0x101c,
+ 0x6d0c, 0x16c1,
+ 0x6d0d, 0x38f4,
+ 0x6d0e, 0x16c7,
+ 0x6d0f, 0x38f5,
+ 0x6d12, 0x0cd2,
+ 0x6d13, 0x38f8,
+ 0x6d17, 0x0f21,
+ 0x6d18, 0x38fc,
+ 0x6d19, 0x16c6,
+ 0x6d1a, 0x16cc,
+ 0x6d1b, 0x0a8c,
+ 0x6d1c, 0x38fd,
+ 0x6d1e, 0x05f3,
+ 0x6d1f, 0x38ff,
+ 0x6d25, 0x08c3,
+ 0x6d26, 0x3905,
+ 0x6d27, 0x16c0,
+ 0x6d28, 0x3906,
+ 0x6d2a, 0x07a0,
+ 0x6d2b, 0x16c8,
+ 0x6d2c, 0x3908,
+ 0x6d2e, 0x16ca,
+ 0x6d2f, 0x390a,
+ 0x6d31, 0x063c,
+ 0x6d32, 0x11dd,
+ 0x6d33, 0x16d0,
+ 0x6d34, 0x390c,
+ 0x6d35, 0x16cb,
+ 0x6d36, 0x390d,
+ 0x6d39, 0x16bf,
+ 0x6d3a, 0x3910,
+ 0x6d3b, 0x0803,
+ 0x6d3c, 0x0e8e,
+ 0x6d3d, 0x0c1f,
+ 0x6d3e, 0x0b8a,
+ 0x6d3f, 0x3911,
+ 0x6d41, 0x0a40,
+ 0x6d42, 0x3913,
+ 0x6d43, 0x16c2,
+ 0x6d44, 0x3914,
+ 0x6d45, 0x0c30,
+ 0x6d46, 0x087d,
+ 0x6d47, 0x088e,
+ 0x6d48, 0x16c3,
+ 0x6d49, 0x3915,
+ 0x6d4a, 0x1224,
+ 0x6d4b, 0x04a9,
+ 0x6d4c, 0x3916,
+ 0x6d4d, 0x16c9,
+ 0x6d4e, 0x0836,
+ 0x6d4f, 0x16cd,
+ 0x6d50, 0x3917,
+ 0x6d51, 0x0800,
+ 0x6d52, 0x16ce,
+ 0x6d53, 0x0b69,
+ 0x6d54, 0x16cf,
+ 0x6d55, 0x3918,
+ 0x6d59, 0x1184,
+ 0x6d5a, 0x0930,
+ 0x6d5b, 0x391c,
+ 0x6d5c, 0x16d8,
+ 0x6d5d, 0x391d,
+ 0x6d5e, 0x16d5,
+ 0x6d5f, 0x391e,
+ 0x6d60, 0x16d9,
+ 0x6d61, 0x391f,
+ 0x6d63, 0x16db,
+ 0x6d64, 0x3921,
+ 0x6d66, 0x0bf5,
+ 0x6d67, 0x3923,
+ 0x6d69, 0x077d,
+ 0x6d6a, 0x09b6,
+ 0x6d6b, 0x3925,
+ 0x6d6e, 0x069c,
+ 0x6d6f, 0x16d2,
+ 0x6d70, 0x3928,
+ 0x6d74, 0x10e4,
+ 0x6d75, 0x392c,
+ 0x6d77, 0x075a,
+ 0x6d78, 0x08cf,
+ 0x6d79, 0x23dc,
+ 0x6d7a, 0x392e,
+ 0x6d7c, 0x16da,
+ 0x6d7d, 0x3930,
+ 0x6d82, 0x0e70,
+ 0x6d83, 0x3935,
+ 0x6d85, 0x0b5c,
+ 0x6d86, 0x3937,
+ 0x6d87, 0x23db,
+ 0x6d88, 0x0f68,
+ 0x6d89, 0x0d1f,
+ 0x6d8a, 0x3938,
+ 0x6d8c, 0x10a4,
+ 0x6d8d, 0x393a,
+ 0x6d8e, 0x0f3e,
+ 0x6d8f, 0x393b,
+ 0x6d91, 0x16d1,
+ 0x6d92, 0x393d,
+ 0x6d93, 0x16d6,
+ 0x6d95, 0x0e3c,
+ 0x6d96, 0x393e,
+ 0x6d9b, 0x0e21,
+ 0x6d9c, 0x3943,
+ 0x6d9d, 0x09bf,
+ 0x6d9e, 0x16d3,
+ 0x6d9f, 0x09f9,
+ 0x6da0, 0x16d4,
+ 0x6da1, 0x0edf,
+ 0x6da2, 0x3944,
+ 0x6da3, 0x07d6,
+ 0x6da4, 0x05b4,
+ 0x6da5, 0x3945,
+ 0x6da6, 0x0cce,
+ 0x6da7, 0x0878,
+ 0x6da8, 0x1168,
+ 0x6da9, 0x0ce5,
+ 0x6daa, 0x069d,
+ 0x6dab, 0x16e8,
+ 0x6dac, 0x3946,
+ 0x6dae, 0x16ea,
+ 0x6daf, 0x0fed,
+ 0x6db0, 0x3948,
+ 0x6db2, 0x1041,
+ 0x6db3, 0x394a,
+ 0x6db5, 0x0764,
+ 0x6db6, 0x394c,
+ 0x6db8, 0x078b,
+ 0x6db9, 0x394e,
+ 0x6dbf, 0x16e1,
+ 0x6dc0, 0x05ce,
+ 0x6dc1, 0x3954,
+ 0x6dc4, 0x122a,
+ 0x6dc5, 0x16de,
+ 0x6dc6, 0x0f6a,
+ 0x6dc7, 0x16dd,
+ 0x6dc8, 0x3957,
+ 0x6dcb, 0x0a25,
+ 0x6dcc, 0x0e1d,
+ 0x6dcd, 0x395a,
+ 0x6dd1, 0x0d7e,
+ 0x6dd2, 0x395e,
+ 0x6dd6, 0x0b3a,
+ 0x6dd7, 0x3962,
+ 0x6dd8, 0x0e27,
+ 0x6dd9, 0x16e6,
+ 0x6dda, 0x3963,
+ 0x6ddd, 0x16e5,
+ 0x6dde, 0x16df,
+ 0x6ddf, 0x3966,
+ 0x6de0, 0x16e2,
+ 0x6de1, 0x058e,
+ 0x6de2, 0x3967,
+ 0x6de4, 0x10be,
+ 0x6de5, 0x3969,
+ 0x6de6, 0x16e4,
+ 0x6de7, 0x396a,
+ 0x6dea, 0x205e,
+ 0x6deb, 0x1080,
+ 0x6dec, 0x0566,
+ 0x6ded, 0x396d,
+ 0x6dee, 0x07c9,
+ 0x6def, 0x396e,
+ 0x6df1, 0x0d27,
+ 0x6df2, 0x3970,
+ 0x6df3, 0x0541,
+ 0x6df4, 0x3971,
+ 0x6df5, 0x2244,
+ 0x6df6, 0x23e2,
+ 0x6df7, 0x0801,
+ 0x6df8, 0x3972,
+ 0x6df9, 0x0ff6,
+ 0x6dfa, 0x20d4,
+ 0x6dfb, 0x0e40,
+ 0x6dfc, 0x1a21,
+ 0x6dfd, 0x3973,
+ 0x6e00, 0x3976,
+ 0x6e05, 0x0c62,
+ 0x6e06, 0x397b,
+ 0x6e0a, 0x10eb,
+ 0x6e0b, 0x397f,
+ 0x6e0c, 0x16e9,
+ 0x6e0d, 0x1232,
+ 0x6e0e, 0x16e0,
+ 0x6e0f, 0x3980,
+ 0x6e10, 0x0876,
+ 0x6e11, 0x16e3,
+ 0x6e12, 0x3981,
+ 0x6e14, 0x10cb,
+ 0x6e15, 0x3983,
+ 0x6e16, 0x16e7,
+ 0x6e17, 0x0d31,
+ 0x6e18, 0x3984,
+ 0x6e1a, 0x16dc,
+ 0x6e1b, 0x3986,
+ 0x6e1d, 0x10ca,
+ 0x6e1e, 0x3988,
+ 0x6e20, 0x0c7b,
+ 0x6e21, 0x0608,
+ 0x6e22, 0x398a,
+ 0x6e23, 0x113f,
+ 0x6e24, 0x047a,
+ 0x6e25, 0x16f5,
+ 0x6e26, 0x219f,
+ 0x6e27, 0x398b,
+ 0x6e29, 0x0ed1,
+ 0x6e2a, 0x398d,
+ 0x6e2b, 0x16eb,
+ 0x6e2c, 0x1e66,
+ 0x6e2d, 0x0ecb,
+ 0x6e2e, 0x398e,
+ 0x6e2f, 0x06d6,
+ 0x6e30, 0x398f,
+ 0x6e32, 0x16f4,
+ 0x6e33, 0x3991,
+ 0x6e34, 0x0957,
+ 0x6e35, 0x3992,
+ 0x6e38, 0x10b3,
+ 0x6e39, 0x3995,
+ 0x6e3a, 0x0af1,
+ 0x6e3b, 0x3996,
+ 0x6e3e, 0x1f63,
+ 0x6e3f, 0x3999,
+ 0x6e43, 0x0b89,
+ 0x6e44, 0x16f6,
+ 0x6e45, 0x399d,
+ 0x6e4d, 0x0e75,
+ 0x6e4e, 0x16ed,
+ 0x6e4f, 0x39a5,
+ 0x6e53, 0x16f2,
+ 0x6e55, 0x39a9,
+ 0x6e56, 0x07b5,
+ 0x6e57, 0x39aa,
+ 0x6e58, 0x0f53,
+ 0x6e59, 0x39ab,
+ 0x6e5b, 0x1160,
+ 0x6e5c, 0x39ad,
+ 0x6e5e, 0x23dd,
+ 0x6e5f, 0x16f0,
+ 0x6e60, 0x39af,
+ 0x6e6b, 0x16ee,
+ 0x6e6c, 0x39ba,
+ 0x6e6e, 0x16ec,
+ 0x6e6f, 0x216b,
+ 0x6e70, 0x39bc,
+ 0x6e7e, 0x0e96,
+ 0x6e7f, 0x0d41,
+ 0x6e80, 0x39ca,
+ 0x6e83, 0x098e,
+ 0x6e84, 0x39cd,
+ 0x6e85, 0x0877,
+ 0x6e86, 0x16f1,
+ 0x6e87, 0x39ce,
+ 0x6e89, 0x06c3,
+ 0x6e8a, 0x39d0,
+ 0x6e8f, 0x1705,
+ 0x6e90, 0x10f7,
+ 0x6e91, 0x39d5,
+ 0x6e96, 0x22b5,
+ 0x6e97, 0x39da,
+ 0x6e98, 0x16f9,
+ 0x6e99, 0x39db,
+ 0x6e9c, 0x0a38,
+ 0x6e9d, 0x1f26,
+ 0x6e9e, 0x39de,
+ 0x6e9f, 0x1707,
+ 0x6ea0, 0x39df,
+ 0x6ea2, 0x106e,
+ 0x6ea3, 0x39e1,
+ 0x6ea5, 0x16fd,
+ 0x6ea6, 0x39e3,
+ 0x6ea7, 0x16fe,
+ 0x6ea8, 0x39e4,
+ 0x6eaa, 0x0f17,
+ 0x6eab, 0x39e6,
+ 0x6eaf, 0x0dd2,
+ 0x6eb0, 0x39ea,
+ 0x6eb1, 0x16f8,
+ 0x6eb2, 0x16ef,
+ 0x6eb3, 0x39eb,
+ 0x6eb4, 0x1703,
+ 0x6eb5, 0x39ec,
+ 0x6eb6, 0x0cb7,
+ 0x6eb7, 0x1701,
+ 0x6eb8, 0x39ed,
+ 0x6eba, 0x0b4a,
+ 0x6ebb, 0x1700,
+ 0x6ebc, 0x39ef,
+ 0x6ebd, 0x16ff,
+ 0x6ebe, 0x39f0,
+ 0x6ec1, 0x0521,
+ 0x6ec2, 0x1706,
+ 0x6ec3, 0x39f3,
+ 0x6ec4, 0x1e63,
+ 0x6ec5, 0x2088,
+ 0x6ec6, 0x39f4,
+ 0x6ec7, 0x05c2,
+ 0x6ec8, 0x39f5,
+ 0x6ecb, 0x1229,
+ 0x6ecc, 0x1ebd,
+ 0x6ecd, 0x39f8,
+ 0x6ece, 0x2341,
+ 0x6ecf, 0x1704,
+ 0x6ed0, 0x39f9,
+ 0x6ed1, 0x07c1,
+ 0x6ed2, 0x39fa,
+ 0x6ed3, 0x122f,
+ 0x6ed4, 0x0e22,
+ 0x6ed5, 0x19a8,
+ 0x6ed6, 0x39fb,
+ 0x6ed7, 0x1702,
+ 0x6ed8, 0x39fc,
+ 0x6eda, 0x074f,
+ 0x6edb, 0x39fe,
+ 0x6ede, 0x11cc,
+ 0x6edf, 0x16f7,
+ 0x6ee0, 0x16fa,
+ 0x6ee1, 0x0aa1,
+ 0x6ee2, 0x16fc,
+ 0x6ee3, 0x3a01,
+ 0x6ee4, 0x0a72,
+ 0x6ee5, 0x09af,
+ 0x6ee6, 0x0a77,
+ 0x6ee7, 0x3a02,
+ 0x6ee8, 0x045e,
+ 0x6ee9, 0x0e05,
+ 0x6eea, 0x3a03,
+ 0x6eec, 0x1f4b,
+ 0x6eed, 0x3a05,
+ 0x6eef, 0x2292,
+ 0x6ef0, 0x3a07,
+ 0x6ef2, 0x2124,
+ 0x6ef3, 0x3a09,
+ 0x6ef4, 0x05af,
+ 0x6ef5, 0x3a0a,
+ 0x6ef7, 0x2048,
+ 0x6ef8, 0x23e0,
+ 0x6ef9, 0x170d,
+ 0x6efa, 0x3a0c,
+ 0x6eff, 0x2077,
+ 0x6f00, 0x3a11,
+ 0x6f01, 0x223a,
+ 0x6f02, 0x0bce,
+ 0x6f03, 0x3a12,
+ 0x6f06, 0x0c00,
+ 0x6f07, 0x3a15,
+ 0x6f09, 0x1713,
+ 0x6f0a, 0x3a17,
+ 0x6f0f, 0x0a50,
+ 0x6f10, 0x3a1c,
+ 0x6f13, 0x09d7,
+ 0x6f14, 0x1006,
+ 0x6f15, 0x170c,
+ 0x6f16, 0x3a1f,
+ 0x6f1a, 0x20b1,
+ 0x6f1b, 0x3a23,
+ 0x6f20, 0x0b11,
+ 0x6f21, 0x3a28,
+ 0x6f22, 0x1f41,
+ 0x6f23, 0x201c,
+ 0x6f24, 0x170b,
+ 0x6f25, 0x3a29,
+ 0x6f29, 0x1714,
+ 0x6f2a, 0x1712,
+ 0x6f2b, 0x0aa5,
+ 0x6f2c, 0x22b8,
+ 0x6f2d, 0x16fb,
+ 0x6f2e, 0x3a2d,
+ 0x6f2f, 0x170e,
+ 0x6f30, 0x3a2e,
+ 0x6f31, 0x0d95,
+ 0x6f32, 0x2276,
+ 0x6f33, 0x1165,
+ 0x6f34, 0x3a2f,
+ 0x6f36, 0x170f,
+ 0x6f37, 0x3a31,
+ 0x6f38, 0x1f9b,
+ 0x6f39, 0x3a32,
+ 0x6f3e, 0x1023,
+ 0x6f3f, 0x1f9f,
+ 0x6f40, 0x3a37,
+ 0x6f41, 0x25ca,
+ 0x6f42, 0x3a38,
+ 0x6f46, 0x1709,
+ 0x6f48, 0x3a3c,
+ 0x6f4b, 0x1710,
+ 0x6f4c, 0x3a3f,
+ 0x6f4d, 0x0eba,
+ 0x6f4e, 0x3a40,
+ 0x6f51, 0x20be,
+ 0x6f52, 0x3a43,
+ 0x6f54, 0x1fb4,
+ 0x6f55, 0x3a45,
+ 0x6f58, 0x0b8c,
+ 0x6f59, 0x23d7,
+ 0x6f5a, 0x3a48,
+ 0x6f5c, 0x0c2e,
+ 0x6f5d, 0x3a4a,
+ 0x6f5e, 0x0a61,
+ 0x6f5f, 0x3a4b,
+ 0x6f62, 0x1708,
+ 0x6f63, 0x3a4e,
+ 0x6f64, 0x2105,
+ 0x6f65, 0x3a4f,
+ 0x6f66, 0x0a13,
+ 0x6f67, 0x3a50,
+ 0x6f6d, 0x0e09,
+ 0x6f6e, 0x04d6,
+ 0x6f6f, 0x23e1,
+ 0x6f70, 0x1fec,
+ 0x6f71, 0x3a56,
+ 0x6f72, 0x1719,
+ 0x6f73, 0x3a57,
+ 0x6f74, 0x1711,
+ 0x6f75, 0x3a58,
+ 0x6f77, 0x23ea,
+ 0x6f78, 0x1718,
+ 0x6f79, 0x3a5a,
+ 0x6f7a, 0x171b,
+ 0x6f7b, 0x3a5b,
+ 0x6f7c, 0x171a,
+ 0x6f7d, 0x3a5c,
+ 0x6f7f, 0x23e3,
+ 0x6f80, 0x210e,
+ 0x6f81, 0x3a5e,
+ 0x6f84, 0x04f3,
+ 0x6f85, 0x3a61,
+ 0x6f86, 0x1fa6,
+ 0x6f87, 0x2004,
+ 0x6f88, 0x04df,
+ 0x6f89, 0x1715,
+ 0x6f8a, 0x3a62,
+ 0x6f8c, 0x1717,
+ 0x6f8d, 0x1716,
+ 0x6f8e, 0x0bad,
+ 0x6f8f, 0x3a64,
+ 0x6f97, 0x1f9d,
+ 0x6f98, 0x3a6c,
+ 0x6f9c, 0x09a8,
+ 0x6f9d, 0x3a70,
+ 0x6fa0, 0x23e5,
+ 0x6fa1, 0x112b,
+ 0x6fa2, 0x3a73,
+ 0x6fa4, 0x2264,
+ 0x6fa5, 0x3a75,
+ 0x6fa7, 0x171e,
+ 0x6fa8, 0x3a77,
+ 0x6fa9, 0x24e2,
+ 0x6faa, 0x3a78,
+ 0x6fae, 0x23de,
+ 0x6faf, 0x3a7c,
+ 0x6fb1, 0x1ec4,
+ 0x6fb2, 0x3a7e,
+ 0x6fb3, 0x03cf,
+ 0x6fb4, 0x3a7f,
+ 0x6fb6, 0x1720,
+ 0x6fb7, 0x3a81,
+ 0x6fb9, 0x171f,
+ 0x6fba, 0x3a83,
+ 0x6fc0, 0x0817,
+ 0x6fc1, 0x22b6,
+ 0x6fc2, 0x1721,
+ 0x6fc3, 0x20a9,
+ 0x6fc4, 0x3a89,
+ 0x6fc9, 0x171d,
+ 0x6fca, 0x3a8e,
+ 0x6fd1, 0x171c,
+ 0x6fd2, 0x045d,
+ 0x6fd3, 0x3a95,
+ 0x6fd5, 0x212b,
+ 0x6fd6, 0x3a97,
+ 0x6fd8, 0x20a5,
+ 0x6fd9, 0x3a99,
+ 0x6fdb, 0x268b,
+ 0x6fdc, 0x3a9b,
+ 0x6fde, 0x1724,
+ 0x6fdf, 0x1f76,
+ 0x6fe0, 0x1725,
+ 0x6fe1, 0x1722,
+ 0x6fe2, 0x3a9d,
+ 0x6fe4, 0x216d,
+ 0x6fe5, 0x3a9f,
+ 0x6feb, 0x2001,
+ 0x6fec, 0x3aa5,
+ 0x6fee, 0x1723,
+ 0x6fef, 0x1726,
+ 0x6ff0, 0x2191,
+ 0x6ff1, 0x1e50,
+ 0x6ff2, 0x3aa7,
+ 0x6ffa, 0x1f9c,
+ 0x6ffb, 0x3aaf,
+ 0x6ffc, 0x23da,
+ 0x6ffd, 0x3ab0,
+ 0x6ffe, 0x2053,
+ 0x6fff, 0x3ab1,
+ 0x7000, 0x3ab2,
+ 0x7005, 0x23e9,
+ 0x7006, 0x23e4,
+ 0x7007, 0x3ab7,
+ 0x7009, 0x21d5,
+ 0x700a, 0x3ab9,
+ 0x700b, 0x23e6,
+ 0x700c, 0x3aba,
+ 0x700f, 0x23df,
+ 0x7010, 0x3abd,
+ 0x7011, 0x0bf8,
+ 0x7012, 0x3abe,
+ 0x7015, 0x1e4f,
+ 0x7016, 0x3ac1,
+ 0x7018, 0x23d9,
+ 0x7019, 0x3ac3,
+ 0x701a, 0x1727,
+ 0x701b, 0x1729,
+ 0x701c, 0x3ac4,
+ 0x701d, 0x2014,
+ 0x701e, 0x3ac5,
+ 0x701f, 0x23ec,
+ 0x7020, 0x23eb,
+ 0x7021, 0x3ac6,
+ 0x7023, 0x1728,
+ 0x7024, 0x3ac8,
+ 0x7027, 0x23d8,
+ 0x7028, 0x23ee,
+ 0x7029, 0x3acb,
+ 0x7030, 0x268e,
+ 0x7031, 0x3ad2,
+ 0x7032, 0x23ed,
+ 0x7033, 0x3ad3,
+ 0x7035, 0x172b,
+ 0x7036, 0x3ad5,
+ 0x7039, 0x172a,
+ 0x703a, 0x3ad8,
+ 0x703e, 0x1ffa,
+ 0x703f, 0x3adc,
+ 0x7043, 0x23d6,
+ 0x7044, 0x23e8,
+ 0x7045, 0x3ae0,
+ 0x704c, 0x0739,
+ 0x704d, 0x3ae7,
+ 0x704f, 0x172c,
+ 0x7050, 0x3ae9,
+ 0x7051, 0x2106,
+ 0x7052, 0x3aea,
+ 0x7055, 0x200b,
+ 0x7056, 0x3aed,
+ 0x7058, 0x2166,
+ 0x7059, 0x3aef,
+ 0x705d, 0x23ef,
+ 0x705e, 0x172d,
+ 0x705f, 0x3af3,
+ 0x7063, 0x2189,
+ 0x7064, 0x2058,
+ 0x7065, 0x3af7,
+ 0x7067, 0x23e7,
+ 0x7068, 0x3af9,
+ 0x706b, 0x0805,
+ 0x706c, 0x19ef,
+ 0x706d, 0x0af5,
+ 0x706e, 0x3afc,
+ 0x706f, 0x05a7,
+ 0x7070, 0x07e7,
+ 0x7071, 0x3afd,
+ 0x7075, 0x0a32,
+ 0x7076, 0x1131,
+ 0x7077, 0x3b01,
+ 0x7078, 0x08f3,
+ 0x7079, 0x3b02,
+ 0x707c, 0x1223,
+ 0x707d, 0x3b05,
+ 0x707e, 0x1119,
+ 0x707f, 0x049a,
+ 0x7080, 0x19cc,
+ 0x7081, 0x3b06,
+ 0x7085, 0x1913,
+ 0x7086, 0x3b0a,
+ 0x7089, 0x0a56,
+ 0x708a, 0x0539,
+ 0x708b, 0x3b0d,
+ 0x708e, 0x1000,
+ 0x708f, 0x3b10,
+ 0x7092, 0x04d9,
+ 0x7093, 0x3b13,
+ 0x7094, 0x0c8d,
+ 0x7095, 0x0948,
+ 0x7096, 0x19ce,
+ 0x7097, 0x3b14,
+ 0x7099, 0x11ca,
+ 0x709a, 0x3b16,
+ 0x709c, 0x19cd,
+ 0x709d, 0x19cf,
+ 0x709e, 0x3b18,
+ 0x70ab, 0x19d3,
+ 0x70ac, 0x0915,
+ 0x70ad, 0x0e12,
+ 0x70ae, 0x0b9b,
+ 0x70af, 0x08eb,
+ 0x70b0, 0x3b25,
+ 0x70b1, 0x19d4,
+ 0x70b2, 0x3b26,
+ 0x70b3, 0x0467,
+ 0x70b4, 0x3b27,
+ 0x70b7, 0x19d2,
+ 0x70b8, 0x1149,
+ 0x70b9, 0x05c4,
+ 0x70ba, 0x3b2a,
+ 0x70bb, 0x19d0,
+ 0x70bc, 0x09ff,
+ 0x70bd, 0x0508,
+ 0x70be, 0x3b2b,
+ 0x70c0, 0x19d1,
+ 0x70c1, 0x0dad,
+ 0x70c2, 0x09ae,
+ 0x70c3, 0x0e51,
+ 0x70c4, 0x3b2d,
+ 0x70c8, 0x0a1b,
+ 0x70c9, 0x3b31,
+ 0x70ca, 0x19d6,
+ 0x70cb, 0x3b32,
+ 0x70cf, 0x21a3,
+ 0x70d0, 0x3b36,
+ 0x70d8, 0x079d,
+ 0x70d9, 0x09be,
+ 0x70da, 0x3b3e,
+ 0x70db, 0x11f1,
+ 0x70dc, 0x3b3f,
+ 0x70df, 0x0ff5,
+ 0x70e0, 0x3b42,
+ 0x70e4, 0x094b,
+ 0x70e5, 0x3b46,
+ 0x70e6, 0x0650,
+ 0x70e7, 0x0d0e,
+ 0x70e8, 0x19d5,
+ 0x70e9, 0x07f7,
+ 0x70ea, 0x3b47,
+ 0x70eb, 0x0e1f,
+ 0x70ec, 0x08ce,
+ 0x70ed, 0x0ca3,
+ 0x70ee, 0x3b48,
+ 0x70ef, 0x0f16,
+ 0x70f0, 0x3b49,
+ 0x70f4, 0x217a,
+ 0x70f5, 0x3b4d,
+ 0x70f7, 0x0e9a,
+ 0x70f8, 0x3b4f,
+ 0x70f9, 0x0bac,
+ 0x70fa, 0x3b50,
+ 0x70fd, 0x0686,
+ 0x70fe, 0x3b53,
+ 0x7100, 0x3b55,
+ 0x7109, 0x0ff2,
+ 0x710a, 0x076f,
+ 0x710b, 0x3b5e,
+ 0x7110, 0x19d7,
+ 0x7111, 0x3b63,
+ 0x7113, 0x19d8,
+ 0x7114, 0x3b65,
+ 0x7115, 0x07d5,
+ 0x7116, 0x19d9,
+ 0x7117, 0x3b66,
+ 0x7118, 0x19f0,
+ 0x7119, 0x0423,
+ 0x711a, 0x0676,
+ 0x711b, 0x3b67,
+ 0x7121, 0x21a5,
+ 0x7122, 0x3b6d,
+ 0x7126, 0x088a,
+ 0x7127, 0x3b71,
+ 0x712f, 0x19da,
+ 0x7130, 0x100f,
+ 0x7131, 0x19db,
+ 0x7132, 0x3b79,
+ 0x7136, 0x0c96,
+ 0x7137, 0x3b7d,
+ 0x7145, 0x19df,
+ 0x7146, 0x3b8b,
+ 0x7149, 0x2022,
+ 0x714a, 0x19e1,
+ 0x714b, 0x3b8e,
+ 0x714c, 0x07e2,
+ 0x714d, 0x3b8f,
+ 0x714e, 0x0858,
+ 0x714f, 0x3b90,
+ 0x7152, 0x24d6,
+ 0x7153, 0x3b93,
+ 0x715c, 0x19dd,
+ 0x715d, 0x3b9c,
+ 0x715e, 0x0cf0,
+ 0x715f, 0x3b9d,
+ 0x7162, 0x233a,
+ 0x7163, 0x3ba0,
+ 0x7164, 0x0abf,
+ 0x7165, 0x3ba1,
+ 0x7166, 0x19f1,
+ 0x7167, 0x1176,
+ 0x7168, 0x19de,
+ 0x7169, 0x1eee,
+ 0x716a, 0x3ba2,
+ 0x716c, 0x24d5,
+ 0x716d, 0x3ba4,
+ 0x716e, 0x11f2,
+ 0x716f, 0x3ba5,
+ 0x7172, 0x19e0,
+ 0x7173, 0x19dc,
+ 0x7174, 0x3ba8,
+ 0x7178, 0x19e2,
+ 0x7179, 0x3bac,
+ 0x717a, 0x19e3,
+ 0x717b, 0x3bad,
+ 0x717d, 0x0cf8,
+ 0x717e, 0x3baf,
+ 0x7184, 0x0f15,
+ 0x7185, 0x3bb5,
+ 0x718a, 0x0fa7,
+ 0x718b, 0x3bba,
+ 0x718f, 0x0fd5,
+ 0x7190, 0x3bbe,
+ 0x7192, 0x2228,
+ 0x7193, 0x3bc0,
+ 0x7194, 0x0cb6,
+ 0x7195, 0x3bc1,
+ 0x7197, 0x24d7,
+ 0x7198, 0x19e4,
+ 0x7199, 0x0f04,
+ 0x719a, 0x3bc3,
+ 0x719f, 0x0d83,
+ 0x71a0, 0x19e8,
+ 0x71a1, 0x3bc8,
+ 0x71a8, 0x19e7,
+ 0x71a9, 0x3bcf,
+ 0x71ac, 0x03c9,
+ 0x71ad, 0x3bd2,
+ 0x71b1, 0x20fc,
+ 0x71b2, 0x3bd6,
+ 0x71b3, 0x19e5,
+ 0x71b4, 0x3bd7,
+ 0x71b5, 0x19e6,
+ 0x71b6, 0x3bd8,
+ 0x71b9, 0x19f2,
+ 0x71ba, 0x3bdb,
+ 0x71be, 0x1e87,
+ 0x71bf, 0x3bdf,
+ 0x71c1, 0x24d8,
+ 0x71c2, 0x3be1,
+ 0x71c3, 0x0c97,
+ 0x71c4, 0x3be2,
+ 0x71c8, 0x1eba,
+ 0x71c9, 0x3be6,
+ 0x71ce, 0x0a10,
+ 0x71cf, 0x3beb,
+ 0x71d2, 0x2119,
+ 0x71d3, 0x3bee,
+ 0x71d4, 0x19ea,
+ 0x71d5, 0x1009,
+ 0x71d6, 0x3bef,
+ 0x71d9, 0x216c,
+ 0x71da, 0x3bf2,
+ 0x71dc, 0x24d9,
+ 0x71dd, 0x3bf4,
+ 0x71df, 0x2227,
+ 0x71e0, 0x19e9,
+ 0x71e1, 0x3bf6,
+ 0x71e5, 0x1132,
+ 0x71e6, 0x1e5f,
+ 0x71e7, 0x19eb,
+ 0x71e8, 0x3bfa,
+ 0x71ed, 0x229f,
+ 0x71ee, 0x1396,
+ 0x71ef, 0x3bff,
+ 0x71f4, 0x1f5d,
+ 0x71f5, 0x3c04,
+ 0x71f9, 0x19ec,
+ 0x71fa, 0x3c08,
+ 0x71fc, 0x1fbc,
+ 0x71fd, 0x3c0a,
+ 0x71fe, 0x24da,
+ 0x71ff, 0x3c0b,
+ 0x7200, 0x3c0c,
+ 0x7206, 0x0415,
+ 0x7207, 0x3c12,
+ 0x720d, 0x2149,
+ 0x720e, 0x3c18,
+ 0x7210, 0x2046,
+ 0x7211, 0x3c1a,
+ 0x721b, 0x2000,
+ 0x721c, 0x3c24,
+ 0x721d, 0x19ed,
+ 0x721e, 0x3c25,
+ 0x7228, 0x19ee,
+ 0x7229, 0x3c2f,
+ 0x722a, 0x1203,
+ 0x722b, 0x3c30,
+ 0x722c, 0x0b81,
+ 0x722d, 0x3c31,
+ 0x7230, 0x196c,
+ 0x7231, 0x03b9,
+ 0x7232, 0x2190,
+ 0x7233, 0x3c34,
+ 0x7235, 0x0923,
+ 0x7236, 0x06b3,
+ 0x7237, 0x1036,
+ 0x7238, 0x03e1,
+ 0x7239, 0x05da,
+ 0x723a, 0x2208,
+ 0x723b, 0x1269,
+ 0x723c, 0x3c36,
+ 0x723d, 0x0da1,
+ 0x723e, 0x1ee6,
+ 0x723f, 0x169d,
+ 0x7240, 0x3c37,
+ 0x7247, 0x0bcb,
+ 0x7248, 0x03f1,
+ 0x7249, 0x3c3e,
+ 0x724c, 0x0b87,
+ 0x724d, 0x1969,
+ 0x724e, 0x3c41,
+ 0x7252, 0x196a,
+ 0x7253, 0x3c45,
+ 0x7256, 0x196b,
+ 0x7257, 0x3c48,
+ 0x7258, 0x24c3,
+ 0x7259, 0x0fe9,
+ 0x725a, 0x3c49,
+ 0x725b, 0x0b64,
+ 0x725c, 0x3c4a,
+ 0x725d, 0x1944,
+ 0x725e, 0x3c4b,
+ 0x725f, 0x0b15,
+ 0x7260, 0x3c4c,
+ 0x7261, 0x0b18,
+ 0x7262, 0x09b9,
+ 0x7263, 0x3c4d,
+ 0x7266, 0x1945,
+ 0x7267, 0x0b24,
+ 0x7268, 0x3c50,
+ 0x7269, 0x0efe,
+ 0x726a, 0x3c51,
+ 0x726e, 0x1942,
+ 0x726f, 0x1946,
+ 0x7270, 0x3c55,
+ 0x7272, 0x0d35,
+ 0x7273, 0x3c57,
+ 0x7275, 0x0c20,
+ 0x7276, 0x3c59,
+ 0x7279, 0x0e2b,
+ 0x727a, 0x0f0d,
+ 0x727b, 0x3c5c,
+ 0x727d, 0x20cc,
+ 0x727e, 0x1947,
+ 0x7280, 0x0f19,
+ 0x7281, 0x09d2,
+ 0x7282, 0x3c5e,
+ 0x7284, 0x1949,
+ 0x7285, 0x3c60,
+ 0x728a, 0x05fe,
+ 0x728b, 0x194a,
+ 0x728c, 0x3c65,
+ 0x728d, 0x194b,
+ 0x728e, 0x3c66,
+ 0x728f, 0x194c,
+ 0x7290, 0x3c67,
+ 0x7292, 0x194d,
+ 0x7293, 0x3c69,
+ 0x7296, 0x2340,
+ 0x7297, 0x3c6c,
+ 0x729f, 0x1943,
+ 0x72a0, 0x3c74,
+ 0x72a2, 0x1ed1,
+ 0x72a3, 0x3c76,
+ 0x72a7, 0x21ac,
+ 0x72a8, 0x3c7a,
+ 0x72ac, 0x0c89,
+ 0x72ad, 0x15ef,
+ 0x72ae, 0x3c7e,
+ 0x72af, 0x0655,
+ 0x72b0, 0x15f0,
+ 0x72b1, 0x3c7f,
+ 0x72b4, 0x15f1,
+ 0x72b5, 0x3c82,
+ 0x72b6, 0x1211,
+ 0x72b7, 0x15f2,
+ 0x72b9, 0x10b1,
+ 0x72ba, 0x3c83,
+ 0x72c0, 0x22af,
+ 0x72c1, 0x15f5,
+ 0x72c2, 0x097e,
+ 0x72c3, 0x15f4,
+ 0x72c4, 0x05b3,
+ 0x72c5, 0x3c89,
+ 0x72c8, 0x0420,
+ 0x72c9, 0x3c8c,
+ 0x72cd, 0x15f7,
+ 0x72ce, 0x15f6,
+ 0x72cf, 0x3c90,
+ 0x72d0, 0x07b3,
+ 0x72d1, 0x3c91,
+ 0x72d2, 0x15f8,
+ 0x72d3, 0x3c92,
+ 0x72d7, 0x0710,
+ 0x72d8, 0x3c96,
+ 0x72d9, 0x0900,
+ 0x72da, 0x3c97,
+ 0x72de, 0x0b5f,
+ 0x72df, 0x3c9b,
+ 0x72e0, 0x0794,
+ 0x72e1, 0x0897,
+ 0x72e2, 0x3c9c,
+ 0x72e8, 0x15f9,
+ 0x72e9, 0x15fb,
+ 0x72ea, 0x3ca2,
+ 0x72ec, 0x05ff,
+ 0x72ed, 0x0f2e,
+ 0x72ee, 0x0d3f,
+ 0x72ef, 0x15fa,
+ 0x72f0, 0x1199,
+ 0x72f1, 0x10e1,
+ 0x72f2, 0x15fc,
+ 0x72f3, 0x1600,
+ 0x72f4, 0x15fd,
+ 0x72f5, 0x3ca4,
+ 0x72f7, 0x15fe,
+ 0x72f8, 0x09d5,
+ 0x72f9, 0x21b6,
+ 0x72fa, 0x1602,
+ 0x72fc, 0x09b2,
+ 0x72fd, 0x1e3d,
+ 0x72fe, 0x3ca6,
+ 0x7300, 0x3ca8,
+ 0x7301, 0x15ff,
+ 0x7302, 0x3ca9,
+ 0x7303, 0x1601,
+ 0x7304, 0x3caa,
+ 0x730a, 0x1607,
+ 0x730b, 0x3cb0,
+ 0x730e, 0x0a1d,
+ 0x730f, 0x3cb3,
+ 0x7313, 0x1605,
+ 0x7314, 0x3cb7,
+ 0x7315, 0x160a,
+ 0x7316, 0x04c5,
+ 0x7317, 0x1604,
+ 0x7318, 0x3cb8,
+ 0x731b, 0x0ad2,
+ 0x731c, 0x0489,
+ 0x731d, 0x1609,
+ 0x731e, 0x1608,
+ 0x731f, 0x3cbb,
+ 0x7321, 0x1606,
+ 0x7322, 0x160b,
+ 0x7323, 0x3cbd,
+ 0x7325, 0x160d,
+ 0x7326, 0x3cbf,
+ 0x7329, 0x0f94,
+ 0x732a, 0x11ec,
+ 0x732b, 0x0aad,
+ 0x732c, 0x160e,
+ 0x732d, 0x3cc2,
+ 0x732e, 0x0f44,
+ 0x732f, 0x3cc3,
+ 0x7331, 0x1610,
+ 0x7332, 0x3cc5,
+ 0x7334, 0x07a6,
+ 0x7335, 0x3cc7,
+ 0x7336, 0x2235,
+ 0x7337, 0x18d4,
+ 0x7338, 0x160f,
+ 0x7339, 0x160c,
+ 0x733a, 0x3cc8,
+ 0x733b, 0x2397,
+ 0x733c, 0x3cc9,
+ 0x733e, 0x07c0,
+ 0x733f, 0x10f6,
+ 0x7340, 0x3ccb,
+ 0x7341, 0x2395,
+ 0x7342, 0x3ccc,
+ 0x7344, 0x223f,
+ 0x7345, 0x212a,
+ 0x7346, 0x3cce,
+ 0x734d, 0x1612,
+ 0x734e, 0x3cd5,
+ 0x7350, 0x1611,
+ 0x7351, 0x3cd7,
+ 0x7352, 0x18d5,
+ 0x7353, 0x3cd8,
+ 0x7357, 0x1613,
+ 0x7358, 0x3cdc,
+ 0x7360, 0x1614,
+ 0x7361, 0x3ce4,
+ 0x7368, 0x1ed2,
+ 0x7369, 0x3ceb,
+ 0x736a, 0x2396,
+ 0x736b, 0x2398,
+ 0x736c, 0x1615,
+ 0x736d, 0x0df4,
+ 0x736e, 0x3cec,
+ 0x736f, 0x1616,
+ 0x7370, 0x20a2,
+ 0x7371, 0x3ced,
+ 0x7372, 0x1f64,
+ 0x7373, 0x3cee,
+ 0x7375, 0x202b,
+ 0x7376, 0x3cf0,
+ 0x7377, 0x2394,
+ 0x7378, 0x2139,
+ 0x7379, 0x3cf1,
+ 0x737a, 0x215f,
+ 0x737b, 0x21c1,
+ 0x737c, 0x239a,
+ 0x737d, 0x3cf2,
+ 0x737e, 0x1617,
+ 0x737f, 0x3cf3,
+ 0x7380, 0x2399,
+ 0x7381, 0x3cf4,
+ 0x7384, 0x0fc9,
+ 0x7385, 0x3cf7,
+ 0x7387, 0x0a71,
+ 0x7388, 0x3cf9,
+ 0x7389, 0x10d6,
+ 0x738a, 0x3cfa,
+ 0x738b, 0x0ea6,
+ 0x738c, 0x3cfb,
+ 0x738e, 0x1818,
+ 0x738f, 0x3cfd,
+ 0x7391, 0x1819,
+ 0x7392, 0x3cff,
+ 0x7396, 0x08f0,
+ 0x7397, 0x3d03,
+ 0x739b, 0x0a91,
+ 0x739c, 0x3d07,
+ 0x739f, 0x181c,
+ 0x73a0, 0x3d0a,
+ 0x73a2, 0x181b,
+ 0x73a3, 0x3d0c,
+ 0x73a9, 0x0e97,
+ 0x73aa, 0x3d12,
+ 0x73ab, 0x0aba,
+ 0x73ac, 0x3d13,
+ 0x73ae, 0x181a,
+ 0x73af, 0x07cc,
+ 0x73b0, 0x0f43,
+ 0x73b1, 0x3d15,
+ 0x73b2, 0x0a2a,
+ 0x73b3, 0x1821,
+ 0x73b4, 0x3d16,
+ 0x73b7, 0x1820,
+ 0x73b8, 0x3d19,
+ 0x73ba, 0x182c,
+ 0x73bb, 0x046a,
+ 0x73bc, 0x3d1b,
+ 0x73c0, 0x1822,
+ 0x73c1, 0x3d1f,
+ 0x73c2, 0x181e,
+ 0x73c3, 0x3d20,
+ 0x73c8, 0x1824,
+ 0x73c9, 0x1823,
+ 0x73ca, 0x0cf3,
+ 0x73cb, 0x3d25,
+ 0x73cd, 0x1185,
+ 0x73ce, 0x3d27,
+ 0x73cf, 0x181d,
+ 0x73d0, 0x0646,
+ 0x73d1, 0x181f,
+ 0x73d2, 0x3d28,
+ 0x73d9, 0x1826,
+ 0x73da, 0x3d2f,
+ 0x73de, 0x182b,
+ 0x73df, 0x3d33,
+ 0x73e0, 0x11e8,
+ 0x73e1, 0x3d34,
+ 0x73e5, 0x1825,
+ 0x73e6, 0x3d38,
+ 0x73e7, 0x182a,
+ 0x73e8, 0x3d39,
+ 0x73e9, 0x1829,
+ 0x73ea, 0x3d3a,
+ 0x73ed, 0x03eb,
+ 0x73ee, 0x3d3d,
+ 0x73f2, 0x182d,
+ 0x73f3, 0x3d41,
+ 0x73fe, 0x21c0,
+ 0x73ff, 0x3d4c,
+ 0x7400, 0x3d4d,
+ 0x7403, 0x0c6f,
+ 0x7404, 0x3d50,
+ 0x7405, 0x09b0,
+ 0x7406, 0x09d8,
+ 0x7407, 0x3d51,
+ 0x7409, 0x0a39,
+ 0x740a, 0x1828,
+ 0x740b, 0x3d53,
+ 0x740f, 0x182e,
+ 0x7410, 0x0deb,
+ 0x7411, 0x3d57,
+ 0x741a, 0x1838,
+ 0x741b, 0x1837,
+ 0x741c, 0x3d60,
+ 0x7422, 0x121e,
+ 0x7423, 0x3d66,
+ 0x7425, 0x1832,
+ 0x7426, 0x1831,
+ 0x7427, 0x3d68,
+ 0x7428, 0x1833,
+ 0x7429, 0x3d69,
+ 0x742a, 0x182f,
+ 0x742b, 0x3d6a,
+ 0x742c, 0x1836,
+ 0x742d, 0x3d6b,
+ 0x742e, 0x1835,
+ 0x742f, 0x3d6c,
+ 0x7430, 0x1834,
+ 0x7431, 0x3d6d,
+ 0x7433, 0x0a1e,
+ 0x7434, 0x0c56,
+ 0x7435, 0x0bbe,
+ 0x7436, 0x0b84,
+ 0x7437, 0x3d6f,
+ 0x743c, 0x0c6a,
+ 0x743d, 0x3d74,
+ 0x743f, 0x2460,
+ 0x7440, 0x3d76,
+ 0x7441, 0x1839,
+ 0x7442, 0x3d77,
+ 0x744b, 0x245c,
+ 0x744c, 0x3d80,
+ 0x7455, 0x183c,
+ 0x7456, 0x3d89,
+ 0x7457, 0x183b,
+ 0x7458, 0x3d8a,
+ 0x7459, 0x183d,
+ 0x745a, 0x07ae,
+ 0x745b, 0x1830,
+ 0x745c, 0x183a,
+ 0x745d, 0x3d8b,
+ 0x745e, 0x0ccb,
+ 0x745f, 0x0ce3,
+ 0x7460, 0x3d8c,
+ 0x7463, 0x215d,
+ 0x7464, 0x3d8f,
+ 0x7469, 0x2225,
+ 0x746a, 0x206a,
+ 0x746b, 0x3d94,
+ 0x746d, 0x183f,
+ 0x746e, 0x3d96,
+ 0x7470, 0x073e,
+ 0x7471, 0x3d98,
+ 0x7476, 0x1027,
+ 0x7477, 0x183e,
+ 0x7478, 0x3d9d,
+ 0x747e, 0x1840,
+ 0x747f, 0x3da3,
+ 0x7480, 0x1843,
+ 0x7482, 0x3da4,
+ 0x7483, 0x09f0,
+ 0x7484, 0x3da5,
+ 0x7487, 0x1845,
+ 0x7488, 0x3da8,
+ 0x7489, 0x2461,
+ 0x748a, 0x3da9,
+ 0x748b, 0x1846,
+ 0x748c, 0x3daa,
+ 0x748e, 0x1842,
+ 0x748f, 0x3dac,
+ 0x7490, 0x184a,
+ 0x7491, 0x3dad,
+ 0x749c, 0x1841,
+ 0x749d, 0x3db8,
+ 0x749e, 0x1847,
+ 0x749f, 0x3db9,
+ 0x74a3, 0x245b,
+ 0x74a4, 0x3dbd,
+ 0x74a6, 0x2462,
+ 0x74a7, 0x184b,
+ 0x74a8, 0x1848,
+ 0x74aa, 0x3dbf,
+ 0x74b0, 0x1f54,
+ 0x74b1, 0x3dc5,
+ 0x74ba, 0x184d,
+ 0x74bb, 0x3dce,
+ 0x74bd, 0x245f,
+ 0x74be, 0x3dd0,
+ 0x74ca, 0x20ec,
+ 0x74cb, 0x3ddc,
+ 0x74cf, 0x245d,
+ 0x74d0, 0x3de0,
+ 0x74d2, 0x184c,
+ 0x74d3, 0x3de2,
+ 0x74d4, 0x2463,
+ 0x74d5, 0x3de3,
+ 0x74da, 0x2464,
+ 0x74db, 0x3de8,
+ 0x74dc, 0x0728,
+ 0x74dd, 0x3de9,
+ 0x74de, 0x1b32,
+ 0x74df, 0x3dea,
+ 0x74e0, 0x1b33,
+ 0x74e1, 0x3deb,
+ 0x74e2, 0x0bcf,
+ 0x74e3, 0x03f5,
+ 0x74e4, 0x0c9a,
+ 0x74e5, 0x3dec,
+ 0x74e6, 0x0e90,
+ 0x74e7, 0x3ded,
+ 0x74ee, 0x0edc,
+ 0x74ef, 0x1903,
+ 0x74f0, 0x3df4,
+ 0x74f4, 0x1904,
+ 0x74f5, 0x3df8,
+ 0x74f6, 0x0bde,
+ 0x74f7, 0x054c,
+ 0x74f8, 0x3df9,
+ 0x74ff, 0x1905,
+ 0x7500, 0x3e00,
+ 0x7504, 0x1188,
+ 0x7505, 0x3e04,
+ 0x750c, 0x24a5,
+ 0x750d, 0x1485,
+ 0x750e, 0x3e0b,
+ 0x750f, 0x1906,
+ 0x7510, 0x3e0c,
+ 0x7511, 0x1907,
+ 0x7512, 0x3e0d,
+ 0x7513, 0x1908,
+ 0x7514, 0x3e0e,
+ 0x7518, 0x06c5,
+ 0x7519, 0x14f8,
+ 0x751a, 0x0d2e,
+ 0x751b, 0x3e12,
+ 0x751c, 0x0e43,
+ 0x751d, 0x3e13,
+ 0x751f, 0x0d33,
+ 0x7520, 0x3e15,
+ 0x7523, 0x1e70,
+ 0x7524, 0x3e18,
+ 0x7525, 0x0d34,
+ 0x7526, 0x3e19,
+ 0x7528, 0x10a8,
+ 0x7529, 0x0d9b,
+ 0x752a, 0x3e1b,
+ 0x752b, 0x06a1,
+ 0x752c, 0x1b34,
+ 0x752d, 0x042b,
+ 0x752e, 0x3e1c,
+ 0x752f, 0x1734,
+ 0x7530, 0x0e42,
+ 0x7531, 0x10ae,
+ 0x7532, 0x084a,
+ 0x7533, 0x0d23,
+ 0x7534, 0x3e1d,
+ 0x7535, 0x05c8,
+ 0x7536, 0x3e1e,
+ 0x7537, 0x0b33,
+ 0x7538, 0x05ca,
+ 0x7539, 0x3e1f,
+ 0x753a, 0x1a78,
+ 0x753b, 0x07c2,
+ 0x753c, 0x3e20,
+ 0x753e, 0x1816,
+ 0x753f, 0x3e22,
+ 0x7540, 0x1a79,
+ 0x7541, 0x3e23,
+ 0x7545, 0x04ce,
+ 0x7546, 0x3e27,
+ 0x7548, 0x1a7c,
+ 0x7549, 0x3e29,
+ 0x754b, 0x1a7b,
+ 0x754c, 0x08b8,
+ 0x754d, 0x3e2b,
+ 0x754e, 0x1a7a,
+ 0x754f, 0x0ec6,
+ 0x7550, 0x3e2c,
+ 0x7554, 0x0b90,
+ 0x7555, 0x3e30,
+ 0x7559, 0x0a3d,
+ 0x755a, 0x139e,
+ 0x755b, 0x1a7d,
+ 0x755c, 0x0fbe,
+ 0x755d, 0x208f,
+ 0x755e, 0x3e34,
+ 0x7562, 0x1e42,
+ 0x7563, 0x3e38,
+ 0x7565, 0x0a7b,
+ 0x7566, 0x0c07,
+ 0x7567, 0x3e3a,
+ 0x756a, 0x0649,
+ 0x756b, 0x1f4e,
+ 0x756c, 0x3e3d,
+ 0x7572, 0x1a7e,
+ 0x7573, 0x3e43,
+ 0x7574, 0x0510,
+ 0x7575, 0x3e44,
+ 0x7576, 0x1eb1,
+ 0x7577, 0x3e45,
+ 0x7578, 0x0810,
+ 0x7579, 0x1a7f,
+ 0x757a, 0x3e46,
+ 0x757f, 0x1814,
+ 0x7580, 0x3e4b,
+ 0x7583, 0x1a80,
+ 0x7584, 0x3e4e,
+ 0x7586, 0x087f,
+ 0x7587, 0x1e8b,
+ 0x7588, 0x3e50,
+ 0x758b, 0x1bc6,
+ 0x758c, 0x3e53,
+ 0x758f, 0x0d7f,
+ 0x7590, 0x3e56,
+ 0x7591, 0x1050,
+ 0x7592, 0x1b60,
+ 0x7593, 0x3e57,
+ 0x7594, 0x1b61,
+ 0x7595, 0x3e58,
+ 0x7596, 0x1b62,
+ 0x7597, 0x0a0f,
+ 0x7598, 0x3e59,
+ 0x7599, 0x06e8,
+ 0x759a, 0x08fd,
+ 0x759b, 0x3e5a,
+ 0x759d, 0x1b64,
+ 0x759e, 0x3e5c,
+ 0x759f, 0x0b72,
+ 0x75a0, 0x1b63,
+ 0x75a1, 0x101a,
+ 0x75a2, 0x3e5d,
+ 0x75a3, 0x1b66,
+ 0x75a4, 0x03d7,
+ 0x75a5, 0x08bb,
+ 0x75a6, 0x3e5e,
+ 0x75ab, 0x1066,
+ 0x75ac, 0x1b65,
+ 0x75ad, 0x3e63,
+ 0x75ae, 0x0532,
+ 0x75af, 0x0685,
+ 0x75b0, 0x1b6c,
+ 0x75b1, 0x1b6b,
+ 0x75b2, 0x0bc2,
+ 0x75b3, 0x1b67,
+ 0x75b5, 0x0546,
+ 0x75b6, 0x3e64,
+ 0x75b8, 0x1b69,
+ 0x75b9, 0x118f,
+ 0x75ba, 0x3e66,
+ 0x75bc, 0x0e2e,
+ 0x75bd, 0x0901,
+ 0x75be, 0x0825,
+ 0x75bf, 0x3e68,
+ 0x75c2, 0x1b6e,
+ 0x75c3, 0x1b6d,
+ 0x75c4, 0x1b6a,
+ 0x75c5, 0x0468,
+ 0x75c6, 0x3e6b,
+ 0x75c7, 0x11a1,
+ 0x75c8, 0x109d,
+ 0x75c9, 0x08e6,
+ 0x75ca, 0x0c87,
+ 0x75cb, 0x3e6c,
+ 0x75cd, 0x1b70,
+ 0x75ce, 0x3e6e,
+ 0x75d2, 0x1020,
+ 0x75d3, 0x3e72,
+ 0x75d4, 0x11cb,
+ 0x75d5, 0x0792,
+ 0x75d6, 0x1b6f,
+ 0x75d7, 0x3e73,
+ 0x75d8, 0x05fa,
+ 0x75d9, 0x1fc6,
+ 0x75da, 0x3e74,
+ 0x75db, 0x0e65,
+ 0x75dc, 0x3e75,
+ 0x75de, 0x0bc5,
+ 0x75df, 0x3e77,
+ 0x75e2, 0x09ea,
+ 0x75e3, 0x1b71,
+ 0x75e4, 0x1b74,
+ 0x75e5, 0x3e7a,
+ 0x75e6, 0x1b73,
+ 0x75e7, 0x1b76,
+ 0x75e8, 0x1b72,
+ 0x75e9, 0x3e7b,
+ 0x75ea, 0x07d3,
+ 0x75eb, 0x1b75,
+ 0x75ec, 0x3e7c,
+ 0x75f0, 0x0e08,
+ 0x75f1, 0x1b78,
+ 0x75f2, 0x3e80,
+ 0x75f4, 0x04fa,
+ 0x75f5, 0x3e82,
+ 0x75f9, 0x043d,
+ 0x75fa, 0x3e86,
+ 0x75fc, 0x1b79,
+ 0x75fd, 0x3e88,
+ 0x75ff, 0x1b7a,
+ 0x7600, 0x1b7c,
+ 0x7601, 0x0564,
+ 0x7602, 0x25ae,
+ 0x7603, 0x1b77,
+ 0x7604, 0x3e8a,
+ 0x7605, 0x1b7d,
+ 0x7606, 0x3e8b,
+ 0x760a, 0x1b80,
+ 0x760b, 0x1f01,
+ 0x760c, 0x1b7e,
+ 0x760d, 0x2200,
+ 0x760e, 0x3e8f,
+ 0x7610, 0x1b7b,
+ 0x7611, 0x3e91,
+ 0x7615, 0x1b83,
+ 0x7616, 0x3e95,
+ 0x7617, 0x1b7f,
+ 0x7618, 0x1b82,
+ 0x7619, 0x1b84,
+ 0x761a, 0x3e96,
+ 0x761b, 0x1b85,
+ 0x761c, 0x3e97,
+ 0x761e, 0x25b2,
+ 0x761f, 0x0ed0,
+ 0x7620, 0x1b88,
+ 0x7621, 0x1e97,
+ 0x7622, 0x1b87,
+ 0x7623, 0x3e99,
+ 0x7624, 0x0a3f,
+ 0x7625, 0x1b81,
+ 0x7626, 0x0d74,
+ 0x7627, 0x20ab,
+ 0x7628, 0x3e9a,
+ 0x7629, 0x0574,
+ 0x762a, 0x045a,
+ 0x762b, 0x0e04,
+ 0x762c, 0x3e9b,
+ 0x762d, 0x1b8a,
+ 0x762e, 0x3e9c,
+ 0x7630, 0x1b8b,
+ 0x7631, 0x3e9e,
+ 0x7633, 0x1b90,
+ 0x7634, 0x116f,
+ 0x7635, 0x1b8d,
+ 0x7636, 0x3ea0,
+ 0x7638, 0x0c8e,
+ 0x7639, 0x3ea2,
+ 0x763b, 0x25b3,
+ 0x763c, 0x1b86,
+ 0x763d, 0x3ea4,
+ 0x763e, 0x1b8f,
+ 0x763f, 0x1b8c,
+ 0x7640, 0x1b89,
+ 0x7641, 0x3ea5,
+ 0x7642, 0x2028,
+ 0x7643, 0x1b8e,
+ 0x7644, 0x3ea6,
+ 0x7646, 0x25af,
+ 0x7648, 0x3ea8,
+ 0x7649, 0x25b1,
+ 0x764a, 0x3ea9,
+ 0x764c, 0x03b4,
+ 0x764d, 0x1b91,
+ 0x764e, 0x3eab,
+ 0x7654, 0x1b93,
+ 0x7655, 0x3eb1,
+ 0x7656, 0x1b95,
+ 0x7657, 0x3eb2,
+ 0x7658, 0x25ac,
+ 0x7659, 0x3eb3,
+ 0x765c, 0x1b94,
+ 0x765d, 0x3eb6,
+ 0x765e, 0x1b92,
+ 0x765f, 0x1e4e,
+ 0x7660, 0x3eb7,
+ 0x7662, 0x2202,
+ 0x7663, 0x0fcb,
+ 0x7664, 0x25ab,
+ 0x7665, 0x2286,
+ 0x7666, 0x3eb9,
+ 0x7667, 0x25ad,
+ 0x7668, 0x3eba,
+ 0x7669, 0x25b6,
+ 0x766a, 0x3ebb,
+ 0x766b, 0x1b96,
+ 0x766c, 0x21e3,
+ 0x766d, 0x25b4,
+ 0x766f, 0x1b97,
+ 0x7670, 0x222f,
+ 0x7671, 0x2165,
+ 0x7672, 0x25b7,
+ 0x7673, 0x3ebc,
+ 0x7678, 0x0748,
+ 0x7679, 0x3ec1,
+ 0x767b, 0x05a8,
+ 0x767c, 0x1ee9,
+ 0x767d, 0x03e2,
+ 0x767e, 0x03e4,
+ 0x767f, 0x3ec3,
+ 0x7682, 0x1130,
+ 0x7683, 0x3ec6,
+ 0x7684, 0x05a5,
+ 0x7685, 0x3ec7,
+ 0x7686, 0x08a5,
+ 0x7687, 0x07df,
+ 0x7688, 0x1b2d,
+ 0x7689, 0x3ec8,
+ 0x768b, 0x06d9,
+ 0x768c, 0x3eca,
+ 0x768e, 0x1b2e,
+ 0x768f, 0x3ecc,
+ 0x7691, 0x03b3,
+ 0x7692, 0x3ece,
+ 0x7693, 0x1b2f,
+ 0x7694, 0x3ecf,
+ 0x7696, 0x0e9f,
+ 0x7697, 0x3ed1,
+ 0x7699, 0x1b30,
+ 0x769a, 0x1e25,
+ 0x769b, 0x3ed3,
+ 0x76a4, 0x1b31,
+ 0x76a5, 0x3edc,
+ 0x76ae, 0x0bc3,
+ 0x76af, 0x3ee5,
+ 0x76b1, 0x11e4,
+ 0x76b2, 0x1bc8,
+ 0x76b3, 0x3ee7,
+ 0x76b4, 0x1bc9,
+ 0x76b5, 0x3ee8,
+ 0x76b8, 0x25c0,
+ 0x76b9, 0x3eeb,
+ 0x76ba, 0x229a,
+ 0x76bb, 0x3eec,
+ 0x76bf, 0x0af8,
+ 0x76c0, 0x3ef0,
+ 0x76c2, 0x10c0,
+ 0x76c3, 0x3ef2,
+ 0x76c5, 0x11d0,
+ 0x76c6, 0x0ba9,
+ 0x76c7, 0x3ef4,
+ 0x76c8, 0x1094,
+ 0x76c9, 0x3ef5,
+ 0x76ca, 0x106d,
+ 0x76cb, 0x3ef6,
+ 0x76cd, 0x1a8b,
+ 0x76ce, 0x03c6,
+ 0x76cf, 0x1156,
+ 0x76d0, 0x0ff7,
+ 0x76d1, 0x0853,
+ 0x76d2, 0x0787,
+ 0x76d3, 0x3ef8,
+ 0x76d4, 0x0985,
+ 0x76d5, 0x3ef9,
+ 0x76d6, 0x06c2,
+ 0x76d7, 0x05a2,
+ 0x76d8, 0x0b8d,
+ 0x76d9, 0x3efa,
+ 0x76db, 0x0d39,
+ 0x76dc, 0x3efc,
+ 0x76de, 0x226e,
+ 0x76df, 0x0ad0,
+ 0x76e0, 0x3efe,
+ 0x76e1, 0x1fbd,
+ 0x76e2, 0x3eff,
+ 0x76e3, 0x1f84,
+ 0x76e4, 0x20b2,
+ 0x76e5, 0x1a8c,
+ 0x76e6, 0x3f00,
+ 0x76e7, 0x2043,
+ 0x76e8, 0x3f01,
+ 0x76ee, 0x0b22,
+ 0x76ef, 0x05e1,
+ 0x76f0, 0x3f07,
+ 0x76f1, 0x1a58,
+ 0x76f2, 0x0aa9,
+ 0x76f3, 0x3f08,
+ 0x76f4, 0x11b0,
+ 0x76f5, 0x3f09,
+ 0x76f8, 0x0f4d,
+ 0x76f9, 0x1a5b,
+ 0x76fa, 0x3f0c,
+ 0x76fc, 0x0b8f,
+ 0x76fd, 0x3f0e,
+ 0x76fe, 0x061b,
+ 0x76ff, 0x3f0f,
+ 0x7700, 0x3f10,
+ 0x7701, 0x0d38,
+ 0x7702, 0x3f11,
+ 0x7704, 0x1a59,
+ 0x7705, 0x3f13,
+ 0x7707, 0x1a5c,
+ 0x7709, 0x0ac1,
+ 0x770a, 0x3f15,
+ 0x770b, 0x0941,
+ 0x770c, 0x3f16,
+ 0x770d, 0x1a5a,
+ 0x770e, 0x3f17,
+ 0x7719, 0x1a60,
+ 0x771a, 0x1a5e,
+ 0x771b, 0x3f22,
+ 0x771f, 0x1187,
+ 0x7720, 0x0ae4,
+ 0x7721, 0x3f26,
+ 0x7722, 0x1a5f,
+ 0x7723, 0x3f27,
+ 0x7726, 0x1a62,
+ 0x7727, 0x3f2a,
+ 0x7728, 0x1144,
+ 0x7729, 0x0fcc,
+ 0x772a, 0x3f2b,
+ 0x772d, 0x1a61,
+ 0x772e, 0x3f2e,
+ 0x772f, 0x0ad5,
+ 0x7730, 0x3f2f,
+ 0x7735, 0x1a63,
+ 0x7736, 0x0981,
+ 0x7737, 0x091b,
+ 0x7738, 0x1a64,
+ 0x7739, 0x3f34,
+ 0x773a, 0x0e4a,
+ 0x773b, 0x3f35,
+ 0x773c, 0x1004,
+ 0x773d, 0x3f36,
+ 0x7740, 0x1222,
+ 0x7741, 0x1197,
+ 0x7742, 0x3f39,
+ 0x7743, 0x1a68,
+ 0x7744, 0x3f3a,
+ 0x7747, 0x1a67,
+ 0x7748, 0x3f3d,
+ 0x774f, 0x2684,
+ 0x7750, 0x1a65,
+ 0x7752, 0x3f44,
+ 0x775a, 0x1a69,
+ 0x775b, 0x08d5,
+ 0x775c, 0x3f4c,
+ 0x775e, 0x24ef,
+ 0x775f, 0x3f4e,
+ 0x7761, 0x0da4,
+ 0x7762, 0x1a6b,
+ 0x7763, 0x05fc,
+ 0x7764, 0x3f50,
+ 0x7765, 0x1a6c,
+ 0x7766, 0x0b23,
+ 0x7767, 0x3f51,
+ 0x7768, 0x1a6a,
+ 0x7769, 0x3f52,
+ 0x776b, 0x08af,
+ 0x776c, 0x048e,
+ 0x776d, 0x3f54,
+ 0x7779, 0x0602,
+ 0x777a, 0x3f60,
+ 0x777d, 0x1a6f,
+ 0x777e, 0x1270,
+ 0x777f, 0x1a6d,
+ 0x7780, 0x1a70,
+ 0x7781, 0x3f63,
+ 0x7784, 0x0aee,
+ 0x7785, 0x0517,
+ 0x7786, 0x3f66,
+ 0x778c, 0x1a71,
+ 0x778d, 0x1a6e,
+ 0x778e, 0x0f26,
+ 0x778f, 0x3f6c,
+ 0x7791, 0x1a72,
+ 0x7792, 0x0a9e,
+ 0x7793, 0x3f6e,
+ 0x7798, 0x24ee,
+ 0x7799, 0x3f73,
+ 0x779e, 0x2074,
+ 0x779f, 0x1a73,
+ 0x77a1, 0x3f78,
+ 0x77a2, 0x1495,
+ 0x77a3, 0x3f79,
+ 0x77a5, 0x0bd2,
+ 0x77a6, 0x3f7b,
+ 0x77a7, 0x0c43,
+ 0x77a8, 0x3f7c,
+ 0x77a9, 0x11f4,
+ 0x77aa, 0x05aa,
+ 0x77ab, 0x3f7d,
+ 0x77ac, 0x0da7,
+ 0x77ad, 0x2687,
+ 0x77ae, 0x3f7e,
+ 0x77b0, 0x1a75,
+ 0x77b1, 0x3f80,
+ 0x77b3, 0x0e5c,
+ 0x77b4, 0x3f82,
+ 0x77b5, 0x1a76,
+ 0x77b6, 0x3f83,
+ 0x77bb, 0x1151,
+ 0x77bc, 0x24f0,
+ 0x77bd, 0x1a77,
+ 0x77be, 0x3f88,
+ 0x77bf, 0x1d7e,
+ 0x77c0, 0x3f89,
+ 0x77c7, 0x268d,
+ 0x77c8, 0x3f90,
+ 0x77cd, 0x1397,
+ 0x77ce, 0x3f95,
+ 0x77d7, 0x0526,
+ 0x77d8, 0x3f9e,
+ 0x77da, 0x22a0,
+ 0x77db, 0x0ab1,
+ 0x77dc, 0x1bca,
+ 0x77dd, 0x3fa0,
+ 0x77e2, 0x0d4f,
+ 0x77e3, 0x105a,
+ 0x77e4, 0x3fa5,
+ 0x77e5, 0x11a9,
+ 0x77e6, 0x3fa6,
+ 0x77e7, 0x1b1a,
+ 0x77e8, 0x3fa7,
+ 0x77e9, 0x0907,
+ 0x77ea, 0x3fa8,
+ 0x77eb, 0x0894,
+ 0x77ec, 0x1b1b,
+ 0x77ed, 0x060b,
+ 0x77ee, 0x03b6,
+ 0x77ef, 0x1fab,
+ 0x77f0, 0x3fa9,
+ 0x77f3, 0x0d46,
+ 0x77f4, 0x3fac,
+ 0x77f6, 0x1a22,
+ 0x77f7, 0x3fae,
+ 0x77f8, 0x1a23,
+ 0x77f9, 0x3faf,
+ 0x77fd, 0x0f08,
+ 0x77fe, 0x064c,
+ 0x77ff, 0x0980,
+ 0x7800, 0x1a24,
+ 0x7801, 0x0a92,
+ 0x7802, 0x0ce9,
+ 0x7803, 0x3fb3,
+ 0x7809, 0x1a25,
+ 0x780a, 0x3fb9,
+ 0x780c, 0x0c15,
+ 0x780d, 0x0940,
+ 0x780e, 0x3fbb,
+ 0x7811, 0x1a28,
+ 0x7812, 0x0bb9,
+ 0x7813, 0x3fbe,
+ 0x7814, 0x0ff9,
+ 0x7815, 0x3fbf,
+ 0x7816, 0x1206,
+ 0x7817, 0x1a26,
+ 0x7819, 0x3fc0,
+ 0x781a, 0x100b,
+ 0x781b, 0x3fc1,
+ 0x781c, 0x1a2b,
+ 0x781e, 0x3fc2,
+ 0x781f, 0x1a30,
+ 0x7820, 0x3fc3,
+ 0x7823, 0x1a34,
+ 0x7824, 0x3fc6,
+ 0x7825, 0x1a32,
+ 0x7826, 0x1a3a,
+ 0x7827, 0x1189,
+ 0x7828, 0x3fc7,
+ 0x7829, 0x1a35,
+ 0x782a, 0x3fc8,
+ 0x782c, 0x1a33,
+ 0x782d, 0x1a2a,
+ 0x782e, 0x3fca,
+ 0x7830, 0x0baa,
+ 0x7831, 0x3fcc,
+ 0x7834, 0x0be5,
+ 0x7835, 0x3fcf,
+ 0x7837, 0x0d22,
+ 0x7838, 0x1115,
+ 0x7839, 0x1a2d,
+ 0x783c, 0x1a31,
+ 0x783d, 0x3fd1,
+ 0x783e, 0x09e4,
+ 0x783f, 0x3fd2,
+ 0x7840, 0x0524,
+ 0x7841, 0x3fd3,
+ 0x7843, 0x26a8,
+ 0x7844, 0x3fd5,
+ 0x7845, 0x0741,
+ 0x7846, 0x3fd6,
+ 0x7847, 0x1a3c,
+ 0x7848, 0x3fd7,
+ 0x784c, 0x1a3d,
+ 0x784d, 0x3fdb,
+ 0x784e, 0x1a36,
+ 0x784f, 0x3fdc,
+ 0x7850, 0x1a3b,
+ 0x7851, 0x3fdd,
+ 0x7852, 0x0f07,
+ 0x7853, 0x3fde,
+ 0x7855, 0x0dab,
+ 0x7856, 0x1a38,
+ 0x7858, 0x3fe0,
+ 0x785d, 0x0f62,
+ 0x785e, 0x3fe5,
+ 0x7864, 0x24e9,
+ 0x7865, 0x3feb,
+ 0x7868, 0x24e5,
+ 0x7869, 0x3fee,
+ 0x786a, 0x1a3e,
+ 0x786b, 0x0a3b,
+ 0x786c, 0x1097,
+ 0x786d, 0x1a37,
+ 0x786e, 0x0c92,
+ 0x786f, 0x21fa,
+ 0x7870, 0x3fef,
+ 0x7877, 0x0862,
+ 0x7878, 0x3ff6,
+ 0x787c, 0x0bb1,
+ 0x787d, 0x3ffa,
+ 0x7887, 0x1a42,
+ 0x7888, 0x4004,
+ 0x7889, 0x05d0,
+ 0x788a, 0x4005,
+ 0x788c, 0x0a5c,
+ 0x788d, 0x03b8,
+ 0x788e, 0x0dde,
+ 0x788f, 0x4007,
+ 0x7891, 0x0417,
+ 0x7892, 0x4009,
+ 0x7893, 0x1a40,
+ 0x7894, 0x400a,
+ 0x7897, 0x0e9c,
+ 0x7898, 0x05c3,
+ 0x7899, 0x400d,
+ 0x789a, 0x1a41,
+ 0x789b, 0x1a3f,
+ 0x789c, 0x1a43,
+ 0x789d, 0x400e,
+ 0x789f, 0x05db,
+ 0x78a0, 0x4010,
+ 0x78a1, 0x1a44,
+ 0x78a2, 0x4011,
+ 0x78a3, 0x1a45,
+ 0x78a4, 0x4012,
+ 0x78a5, 0x1a48,
+ 0x78a6, 0x4013,
+ 0x78a7, 0x0435,
+ 0x78a8, 0x4014,
+ 0x78a9, 0x2148,
+ 0x78aa, 0x4015,
+ 0x78ad, 0x24e4,
+ 0x78ae, 0x4018,
+ 0x78b0, 0x0bb7,
+ 0x78b1, 0x0861,
+ 0x78b2, 0x1a46,
+ 0x78b3, 0x0e0f,
+ 0x78b4, 0x04b1,
+ 0x78b5, 0x401a,
+ 0x78b8, 0x24e6,
+ 0x78b9, 0x1a47,
+ 0x78ba, 0x20f7,
+ 0x78bb, 0x401d,
+ 0x78bc, 0x206b,
+ 0x78bd, 0x401e,
+ 0x78be, 0x0b4e,
+ 0x78bf, 0x401f,
+ 0x78c1, 0x0548,
+ 0x78c2, 0x4021,
+ 0x78c5, 0x0400,
+ 0x78c6, 0x4024,
+ 0x78c9, 0x1a4b,
+ 0x78ca, 0x09c5,
+ 0x78cb, 0x056b,
+ 0x78cc, 0x4027,
+ 0x78d0, 0x0b8e,
+ 0x78d1, 0x402b,
+ 0x78d4, 0x1a49,
+ 0x78d5, 0x0951,
+ 0x78d6, 0x402e,
+ 0x78d9, 0x1a4a,
+ 0x78da, 0x22a7,
+ 0x78db, 0x4031,
+ 0x78e3, 0x24ec,
+ 0x78e4, 0x4039,
+ 0x78e7, 0x24eb,
+ 0x78e8, 0x0b08,
+ 0x78e9, 0x403c,
+ 0x78ec, 0x1a4c,
+ 0x78ed, 0x403f,
+ 0x78ef, 0x24e3,
+ 0x78f0, 0x4041,
+ 0x78f2, 0x1a4d,
+ 0x78f3, 0x4043,
+ 0x78f4, 0x1a4f,
+ 0x78f5, 0x4044,
+ 0x78f7, 0x0a20,
+ 0x78f8, 0x4046,
+ 0x78fa, 0x07dc,
+ 0x78fb, 0x4048,
+ 0x78fd, 0x24ea,
+ 0x78fe, 0x404a,
+ 0x7900, 0x404c,
+ 0x7901, 0x0889,
+ 0x7902, 0x404d,
+ 0x7905, 0x1a4e,
+ 0x7906, 0x4050,
+ 0x790e, 0x1e92,
+ 0x790f, 0x4058,
+ 0x7913, 0x1a50,
+ 0x7914, 0x405c,
+ 0x7919, 0x1e27,
+ 0x791a, 0x4061,
+ 0x791e, 0x1a52,
+ 0x791f, 0x4065,
+ 0x7924, 0x1a51,
+ 0x7925, 0x406a,
+ 0x7926, 0x1fe6,
+ 0x7927, 0x406b,
+ 0x792a, 0x24e7,
+ 0x792b, 0x2012,
+ 0x792c, 0x1eec,
+ 0x792d, 0x406e,
+ 0x7931, 0x24e8,
+ 0x7932, 0x4072,
+ 0x7934, 0x1a53,
+ 0x7935, 0x4074,
+ 0x793a, 0x0d55,
+ 0x793b, 0x19f8,
+ 0x793c, 0x09dc,
+ 0x793d, 0x4079,
+ 0x793e, 0x0d20,
+ 0x793f, 0x407a,
+ 0x7940, 0x19f9,
+ 0x7941, 0x0c0d,
+ 0x7942, 0x407b,
+ 0x7946, 0x19fa,
+ 0x7947, 0x407f,
+ 0x7948, 0x0c0c,
+ 0x7949, 0x19fb,
+ 0x794a, 0x4080,
+ 0x7953, 0x19fe,
+ 0x7954, 0x4089,
+ 0x7956, 0x1243,
+ 0x7957, 0x1a01,
+ 0x7958, 0x408b,
+ 0x795a, 0x19ff,
+ 0x795b, 0x19fc,
+ 0x795d, 0x1200,
+ 0x795e, 0x0d2a,
+ 0x795f, 0x0de3,
+ 0x7960, 0x1a02,
+ 0x7961, 0x408d,
+ 0x7962, 0x1a00,
+ 0x7963, 0x408e,
+ 0x7965, 0x0f56,
+ 0x7966, 0x4090,
+ 0x7967, 0x1a04,
+ 0x7968, 0x0bd0,
+ 0x7969, 0x4091,
+ 0x796d, 0x0833,
+ 0x796e, 0x4095,
+ 0x796f, 0x1a03,
+ 0x7970, 0x4096,
+ 0x7977, 0x059c,
+ 0x7978, 0x080b,
+ 0x7979, 0x409d,
+ 0x797a, 0x1a05,
+ 0x797b, 0x409e,
+ 0x7980, 0x130b,
+ 0x7981, 0x08cc,
+ 0x7982, 0x40a3,
+ 0x7984, 0x0a62,
+ 0x7985, 0x1a06,
+ 0x7986, 0x40a5,
+ 0x798a, 0x1a07,
+ 0x798b, 0x40a9,
+ 0x798d, 0x1f66,
+ 0x798e, 0x24dc,
+ 0x798f, 0x069e,
+ 0x7990, 0x40ab,
+ 0x799a, 0x1a08,
+ 0x799b, 0x40b5,
+ 0x79a6, 0x26a2,
+ 0x79a7, 0x1a09,
+ 0x79a8, 0x40c0,
+ 0x79aa, 0x24dd,
+ 0x79ab, 0x40c2,
+ 0x79ae, 0x200e,
+ 0x79af, 0x40c5,
+ 0x79b0, 0x24db,
+ 0x79b1, 0x1eb8,
+ 0x79b2, 0x40c6,
+ 0x79b3, 0x1a0a,
+ 0x79b4, 0x40c7,
+ 0x79b9, 0x10d2,
+ 0x79ba, 0x1264,
+ 0x79bb, 0x09d6,
+ 0x79bc, 0x40cc,
+ 0x79bd, 0x0c5a,
+ 0x79be, 0x0783,
+ 0x79bf, 0x40cd,
+ 0x79c0, 0x0fae,
+ 0x79c1, 0x0db2,
+ 0x79c2, 0x40ce,
+ 0x79c3, 0x0e6b,
+ 0x79c4, 0x40cf,
+ 0x79c6, 0x06cc,
+ 0x79c7, 0x40d1,
+ 0x79c9, 0x0465,
+ 0x79ca, 0x40d3,
+ 0x79cb, 0x0c6c,
+ 0x79cc, 0x40d4,
+ 0x79cd, 0x11d5,
+ 0x79ce, 0x40d5,
+ 0x79d1, 0x0953,
+ 0x79d2, 0x0af0,
+ 0x79d3, 0x40d8,
+ 0x79d5, 0x1b1d,
+ 0x79d6, 0x40da,
+ 0x79d8, 0x0add,
+ 0x79d9, 0x40dc,
+ 0x79df, 0x123f,
+ 0x79e0, 0x40e2,
+ 0x79e3, 0x1b1f,
+ 0x79e4, 0x04f8,
+ 0x79e5, 0x40e5,
+ 0x79e6, 0x0c55,
+ 0x79e7, 0x1016,
+ 0x79e8, 0x40e6,
+ 0x79e9, 0x11c7,
+ 0x79ea, 0x40e7,
+ 0x79eb, 0x1b20,
+ 0x79ec, 0x40e8,
+ 0x79ed, 0x1b1e,
+ 0x79ee, 0x40e9,
+ 0x79ef, 0x0812,
+ 0x79f0, 0x04eb,
+ 0x79f1, 0x40ea,
+ 0x79f8, 0x08a6,
+ 0x79f9, 0x40f1,
+ 0x79fb, 0x104d,
+ 0x79fc, 0x40f3,
+ 0x79fd, 0x07f5,
+ 0x79fe, 0x40f4,
+ 0x7a00, 0x0f0e,
+ 0x7a01, 0x40f6,
+ 0x7a02, 0x1b24,
+ 0x7a03, 0x1b23,
+ 0x7a04, 0x40f7,
+ 0x7a06, 0x1b21,
+ 0x7a07, 0x40f9,
+ 0x7a0b, 0x04f1,
+ 0x7a0c, 0x40fd,
+ 0x7a0d, 0x0d0d,
+ 0x7a0e, 0x0da5,
+ 0x7a0f, 0x40fe,
+ 0x7a14, 0x1b26,
+ 0x7a15, 0x4103,
+ 0x7a17, 0x03e9,
+ 0x7a18, 0x4105,
+ 0x7a1a, 0x11c8,
+ 0x7a1b, 0x4107,
+ 0x7a1e, 0x1b25,
+ 0x7a1f, 0x410a,
+ 0x7a20, 0x0512,
+ 0x7a21, 0x410b,
+ 0x7a23, 0x1d8f,
+ 0x7a24, 0x410d,
+ 0x7a2e, 0x2295,
+ 0x7a2f, 0x4117,
+ 0x7a31, 0x1e80,
+ 0x7a32, 0x4119,
+ 0x7a33, 0x0ed7,
+ 0x7a34, 0x411a,
+ 0x7a37, 0x1b28,
+ 0x7a38, 0x411d,
+ 0x7a39, 0x1b27,
+ 0x7a3a, 0x411e,
+ 0x7a3b, 0x059f,
+ 0x7a3c, 0x084d,
+ 0x7a3d, 0x0811,
+ 0x7a3e, 0x411f,
+ 0x7a3f, 0x06e0,
+ 0x7a40, 0x2677,
+ 0x7a41, 0x4120,
+ 0x7a46, 0x0b25,
+ 0x7a47, 0x4125,
+ 0x7a4c, 0x2624,
+ 0x7a4d, 0x1f69,
+ 0x7a4e, 0x222b,
+ 0x7a4f, 0x412a,
+ 0x7a51, 0x1b29,
+ 0x7a52, 0x412c,
+ 0x7a57, 0x0de0,
+ 0x7a58, 0x4131,
+ 0x7a61, 0x257f,
+ 0x7a62, 0x1f5b,
+ 0x7a63, 0x413a,
+ 0x7a69, 0x219b,
+ 0x7a6a, 0x4140,
+ 0x7a6b, 0x267d,
+ 0x7a6c, 0x4141,
+ 0x7a70, 0x1b2c,
+ 0x7a71, 0x4145,
+ 0x7a74, 0x0fd1,
+ 0x7a75, 0x4148,
+ 0x7a76, 0x08ee,
+ 0x7a77, 0x0c6b,
+ 0x7a78, 0x1b9a,
+ 0x7a7a, 0x0962,
+ 0x7a7b, 0x4149,
+ 0x7a7f, 0x052c,
+ 0x7a80, 0x1b9c,
+ 0x7a81, 0x0e6c,
+ 0x7a82, 0x414d,
+ 0x7a83, 0x0c51,
+ 0x7a84, 0x114e,
+ 0x7a85, 0x414e,
+ 0x7a86, 0x1b9d,
+ 0x7a87, 0x414f,
+ 0x7a88, 0x1b9e,
+ 0x7a89, 0x4150,
+ 0x7a8d, 0x0c4c,
+ 0x7a8e, 0x4154,
+ 0x7a91, 0x102b,
+ 0x7a92, 0x11ce,
+ 0x7a93, 0x4157,
+ 0x7a95, 0x1b9f,
+ 0x7a96, 0x08a2,
+ 0x7a97, 0x0533,
+ 0x7a98, 0x08ec,
+ 0x7a99, 0x4159,
+ 0x7a9c, 0x055f,
+ 0x7a9d, 0x0ee0,
+ 0x7a9e, 0x415c,
+ 0x7a9f, 0x096c,
+ 0x7aa0, 0x1ba1,
+ 0x7aa1, 0x415d,
+ 0x7aa5, 0x0987,
+ 0x7aa6, 0x1ba0,
+ 0x7aa7, 0x4161,
+ 0x7aa8, 0x1ba3,
+ 0x7aa9, 0x21a0,
+ 0x7aaa, 0x2186,
+ 0x7aab, 0x4162,
+ 0x7aac, 0x1ba2,
+ 0x7aad, 0x1ba4,
+ 0x7aae, 0x20ed,
+ 0x7aaf, 0x4163,
+ 0x7ab3, 0x1ba5,
+ 0x7ab4, 0x4167,
+ 0x7ab6, 0x25b9,
+ 0x7ab7, 0x4169,
+ 0x7aba, 0x1fea,
+ 0x7abb, 0x416c,
+ 0x7abf, 0x0a47,
+ 0x7ac0, 0x4170,
+ 0x7ac4, 0x1ea4,
+ 0x7ac5, 0x20e1,
+ 0x7ac6, 0x4174,
+ 0x7ac7, 0x25b8,
+ 0x7ac8, 0x2260,
+ 0x7ac9, 0x4175,
+ 0x7aca, 0x20e2,
+ 0x7acb, 0x09eb,
+ 0x7acc, 0x4176,
+ 0x7ad6, 0x0d91,
+ 0x7ad7, 0x4180,
+ 0x7ad9, 0x115f,
+ 0x7ada, 0x4182,
+ 0x7ade, 0x08e9,
+ 0x7adf, 0x08e8,
+ 0x7ae0, 0x1163,
+ 0x7ae1, 0x4186,
+ 0x7ae3, 0x092f,
+ 0x7ae4, 0x4188,
+ 0x7ae5, 0x0e60,
+ 0x7ae6, 0x1b99,
+ 0x7ae7, 0x4189,
+ 0x7aea, 0x2141,
+ 0x7aeb, 0x418c,
+ 0x7aed, 0x08b0,
+ 0x7aee, 0x418e,
+ 0x7aef, 0x060a,
+ 0x7af0, 0x418f,
+ 0x7af6, 0x1fc7,
+ 0x7af7, 0x4195,
+ 0x7af9, 0x11f0,
+ 0x7afa, 0x1c63,
+ 0x7afb, 0x4197,
+ 0x7afd, 0x1c64,
+ 0x7afe, 0x4199,
+ 0x7aff, 0x06c8,
+ 0x7b00, 0x419a,
+ 0x7b03, 0x1c66,
+ 0x7b05, 0x419d,
+ 0x7b06, 0x03d5,
+ 0x7b07, 0x419e,
+ 0x7b08, 0x1c65,
+ 0x7b09, 0x419f,
+ 0x7b0a, 0x1c69,
+ 0x7b0b, 0x0de6,
+ 0x7b0c, 0x41a0,
+ 0x7b0f, 0x1c6b,
+ 0x7b10, 0x41a3,
+ 0x7b11, 0x0f71,
+ 0x7b12, 0x41a4,
+ 0x7b14, 0x0433,
+ 0x7b15, 0x1c68,
+ 0x7b16, 0x41a6,
+ 0x7b19, 0x1c6f,
+ 0x7b1a, 0x41a9,
+ 0x7b1b, 0x05b2,
+ 0x7b1c, 0x41aa,
+ 0x7b1e, 0x1c77,
+ 0x7b1f, 0x41ac,
+ 0x7b20, 0x1c72,
+ 0x7b21, 0x41ad,
+ 0x7b24, 0x1c74,
+ 0x7b25, 0x1c73,
+ 0x7b26, 0x0698,
+ 0x7b27, 0x41b0,
+ 0x7b28, 0x0428,
+ 0x7b29, 0x41b1,
+ 0x7b2a, 0x1c6e,
+ 0x7b2b, 0x1c6a,
+ 0x7b2c, 0x05bb,
+ 0x7b2d, 0x41b2,
+ 0x7b2e, 0x1c70,
+ 0x7b2f, 0x41b3,
+ 0x7b31, 0x1c71,
+ 0x7b32, 0x41b5,
+ 0x7b33, 0x1c75,
+ 0x7b34, 0x41b6,
+ 0x7b38, 0x1c6d,
+ 0x7b39, 0x41ba,
+ 0x7b3a, 0x0856,
+ 0x7b3b, 0x41bb,
+ 0x7b3c, 0x0a46,
+ 0x7b3d, 0x41bc,
+ 0x7b3e, 0x1c76,
+ 0x7b3f, 0x41bd,
+ 0x7b45, 0x1c7a,
+ 0x7b46, 0x1e41,
+ 0x7b47, 0x1c6c,
+ 0x7b48, 0x41c3,
+ 0x7b49, 0x05a9,
+ 0x7b4a, 0x41c4,
+ 0x7b4b, 0x08bf,
+ 0x7b4c, 0x1c7c,
+ 0x7b4d, 0x41c5,
+ 0x7b4f, 0x0641,
+ 0x7b50, 0x097d,
+ 0x7b51, 0x11fd,
+ 0x7b52, 0x0e63,
+ 0x7b53, 0x41c7,
+ 0x7b54, 0x0573,
+ 0x7b55, 0x41c8,
+ 0x7b56, 0x04a6,
+ 0x7b57, 0x41c9,
+ 0x7b58, 0x1c78,
+ 0x7b59, 0x41ca,
+ 0x7b5a, 0x1c79,
+ 0x7b5b, 0x0cf1,
+ 0x7b5c, 0x41cb,
+ 0x7b5d, 0x1c7d,
+ 0x7b5e, 0x41cc,
+ 0x7b60, 0x1c7e,
+ 0x7b61, 0x41ce,
+ 0x7b62, 0x1c81,
+ 0x7b63, 0x41cf,
+ 0x7b67, 0x25e4,
+ 0x7b68, 0x41d3,
+ 0x7b6e, 0x1c7f,
+ 0x7b6f, 0x41d9,
+ 0x7b71, 0x1c83,
+ 0x7b72, 0x1c82,
+ 0x7b73, 0x41db,
+ 0x7b75, 0x1c7b,
+ 0x7b76, 0x41dd,
+ 0x7b77, 0x0977,
+ 0x7b78, 0x41de,
+ 0x7b79, 0x0514,
+ 0x7b7a, 0x41df,
+ 0x7b7b, 0x1c80,
+ 0x7b7c, 0x41e0,
+ 0x7b7e, 0x0c26,
+ 0x7b7f, 0x41e2,
+ 0x7b80, 0x0865,
+ 0x7b81, 0x41e3,
+ 0x7b85, 0x1c8b,
+ 0x7b86, 0x41e7,
+ 0x7b8b, 0x1f86,
+ 0x7b8c, 0x41ec,
+ 0x7b8d, 0x0718,
+ 0x7b8e, 0x41ed,
+ 0x7b90, 0x1c84,
+ 0x7b91, 0x41ef,
+ 0x7b94, 0x0474,
+ 0x7b95, 0x0813,
+ 0x7b96, 0x41f2,
+ 0x7b97, 0x0dd8,
+ 0x7b98, 0x41f3,
+ 0x7b9c, 0x1c8d,
+ 0x7b9d, 0x1c89,
+ 0x7b9e, 0x41f7,
+ 0x7ba1, 0x0735,
+ 0x7ba2, 0x1c8e,
+ 0x7ba3, 0x41fa,
+ 0x7ba6, 0x1c85,
+ 0x7ba8, 0x1c8a,
+ 0x7ba9, 0x0a88,
+ 0x7baa, 0x1c8c,
+ 0x7bab, 0x1c8f,
+ 0x7bac, 0x1c88,
+ 0x7bad, 0x0870,
+ 0x7bae, 0x41fd,
+ 0x7bb1, 0x0f51,
+ 0x7bb2, 0x4200,
+ 0x7bb4, 0x1c90,
+ 0x7bb5, 0x4202,
+ 0x7bb8, 0x1c87,
+ 0x7bb9, 0x4205,
+ 0x7bc0, 0x1fb3,
+ 0x7bc1, 0x1c92,
+ 0x7bc2, 0x420c,
+ 0x7bc4, 0x1eef,
+ 0x7bc5, 0x420e,
+ 0x7bc6, 0x120a,
+ 0x7bc7, 0x0bc9,
+ 0x7bc8, 0x420f,
+ 0x7bc9, 0x22a4,
+ 0x7bca, 0x4210,
+ 0x7bcb, 0x25e8,
+ 0x7bcc, 0x1c93,
+ 0x7bcd, 0x4211,
+ 0x7bd1, 0x1c91,
+ 0x7bd2, 0x4215,
+ 0x7bd3, 0x0a4f,
+ 0x7bd4, 0x4216,
+ 0x7bd9, 0x06d8,
+ 0x7bda, 0x1c95,
+ 0x7bdb, 0x421b,
+ 0x7bdd, 0x1c94,
+ 0x7bde, 0x421d,
+ 0x7be1, 0x055e,
+ 0x7be2, 0x4220,
+ 0x7be4, 0x25e3,
+ 0x7be5, 0x1c96,
+ 0x7be7, 0x4222,
+ 0x7be9, 0x2111,
+ 0x7bea, 0x1c98,
+ 0x7beb, 0x4224,
+ 0x7bee, 0x09a5,
+ 0x7bef, 0x4227,
+ 0x7bf1, 0x09d4,
+ 0x7bf2, 0x4229,
+ 0x7bf3, 0x25e6,
+ 0x7bf4, 0x422a,
+ 0x7bf7, 0x0bb2,
+ 0x7bf8, 0x422d,
+ 0x7bfc, 0x1c9b,
+ 0x7bfd, 0x4231,
+ 0x7bfe, 0x1c9a,
+ 0x7bff, 0x4232,
+ 0x7c00, 0x25e7,
+ 0x7c01, 0x4233,
+ 0x7c07, 0x055b,
+ 0x7c08, 0x4239,
+ 0x7c0b, 0x1c9e,
+ 0x7c0c, 0x1c99,
+ 0x7c0d, 0x2041,
+ 0x7c0e, 0x423c,
+ 0x7c0f, 0x1c9c,
+ 0x7c10, 0x423d,
+ 0x7c16, 0x1c9d,
+ 0x7c17, 0x4243,
+ 0x7c1e, 0x25ea,
+ 0x7c1f, 0x1c9f,
+ 0x7c20, 0x424a,
+ 0x7c21, 0x1f8f,
+ 0x7c22, 0x424b,
+ 0x7c23, 0x25ec,
+ 0x7c24, 0x424c,
+ 0x7c26, 0x1ca1,
+ 0x7c27, 0x07de,
+ 0x7c28, 0x424e,
+ 0x7c2a, 0x1ca0,
+ 0x7c2b, 0x25eb,
+ 0x7c2c, 0x4250,
+ 0x7c38, 0x1ca2,
+ 0x7c39, 0x425c,
+ 0x7c3d, 0x20d0,
+ 0x7c3e, 0x201d,
+ 0x7c3f, 0x0485,
+ 0x7c40, 0x1ca4,
+ 0x7c41, 0x1ca3,
+ 0x7c42, 0x4260,
+ 0x7c43, 0x1ff7,
+ 0x7c44, 0x4261,
+ 0x7c4c, 0x1e8d,
+ 0x7c4d, 0x0821,
+ 0x7c4e, 0x4269,
+ 0x7c5c, 0x25e9,
+ 0x7c5d, 0x4277,
+ 0x7c5f, 0x25ee,
+ 0x7c60, 0x203a,
+ 0x7c61, 0x4279,
+ 0x7c64, 0x2693,
+ 0x7c65, 0x427c,
+ 0x7c69, 0x25e5,
+ 0x7c6a, 0x25ed,
+ 0x7c6b, 0x4280,
+ 0x7c6c, 0x2009,
+ 0x7c6d, 0x4281,
+ 0x7c6e, 0x2065,
+ 0x7c6f, 0x4282,
+ 0x7c72, 0x26a3,
+ 0x7c73, 0x0adc,
+ 0x7c74, 0x12f5,
+ 0x7c75, 0x4285,
+ 0x7c7b, 0x09cb,
+ 0x7c7c, 0x1cca,
+ 0x7c7d, 0x122e,
+ 0x7c7e, 0x428b,
+ 0x7c89, 0x0678,
+ 0x7c8a, 0x4296,
+ 0x7c91, 0x1ccc,
+ 0x7c92, 0x09ec,
+ 0x7c93, 0x429d,
+ 0x7c95, 0x0be8,
+ 0x7c96, 0x429f,
+ 0x7c97, 0x0559,
+ 0x7c98, 0x1154,
+ 0x7c99, 0x42a0,
+ 0x7c9c, 0x1cce,
+ 0x7c9d, 0x1ccd,
+ 0x7c9e, 0x1ccf,
+ 0x7c9f, 0x0dcf,
+ 0x7ca0, 0x42a3,
+ 0x7ca2, 0x1cd0,
+ 0x7ca3, 0x42a5,
+ 0x7ca4, 0x1104,
+ 0x7ca5, 0x11df,
+ 0x7ca6, 0x42a6,
+ 0x7caa, 0x067d,
+ 0x7cab, 0x42aa,
+ 0x7cae, 0x0a01,
+ 0x7caf, 0x42ad,
+ 0x7cb1, 0x0a04,
+ 0x7cb2, 0x1cd1,
+ 0x7cb3, 0x08db,
+ 0x7cb4, 0x42af,
+ 0x7cb9, 0x0565,
+ 0x7cba, 0x42b4,
+ 0x7cbc, 0x1cd2,
+ 0x7cbe, 0x08da,
+ 0x7cbf, 0x42b6,
+ 0x7cc1, 0x1cd4,
+ 0x7cc2, 0x42b8,
+ 0x7cc5, 0x1cd9,
+ 0x7cc6, 0x42bb,
+ 0x7cc7, 0x1cd5,
+ 0x7cc8, 0x1cd8,
+ 0x7cc9, 0x42bc,
+ 0x7cca, 0x07b4,
+ 0x7ccb, 0x42bd,
+ 0x7ccc, 0x1cd6,
+ 0x7cce, 0x42be,
+ 0x7cd5, 0x06dd,
+ 0x7cd6, 0x0e1a,
+ 0x7cd7, 0x1cda,
+ 0x7cd8, 0x42c5,
+ 0x7cd9, 0x04a1,
+ 0x7cda, 0x42c6,
+ 0x7cdc, 0x0ad8,
+ 0x7cdd, 0x25f5,
+ 0x7cde, 0x1efc,
+ 0x7cdf, 0x1126,
+ 0x7ce0, 0x0944,
+ 0x7ce1, 0x42c8,
+ 0x7ce7, 0x2024,
+ 0x7ce8, 0x1cdb,
+ 0x7ce9, 0x42ce,
+ 0x7cef, 0x0b75,
+ 0x7cf0, 0x269b,
+ 0x7cf1, 0x42d4,
+ 0x7cf2, 0x25f3,
+ 0x7cf3, 0x42d5,
+ 0x7cf4, 0x22d9,
+ 0x7cf5, 0x42d6,
+ 0x7cf6, 0x25f4,
+ 0x7cf7, 0x42d7,
+ 0x7cf8, 0x1ce7,
+ 0x7cf9, 0x241b,
+ 0x7cfa, 0x42d8,
+ 0x7cfb, 0x0f22,
+ 0x7cfc, 0x42d9,
+ 0x7cfe, 0x1fc8,
+ 0x7cff, 0x42db,
+ 0x7d00, 0x1f7b,
+ 0x7d01, 0x42dc,
+ 0x7d02, 0x241d,
+ 0x7d03, 0x42dd,
+ 0x7d04, 0x224c,
+ 0x7d05, 0x1f48,
+ 0x7d06, 0x241c,
+ 0x7d07, 0x241e,
+ 0x7d09, 0x20ff,
+ 0x7d0a, 0x0ed8,
+ 0x7d0b, 0x219a,
+ 0x7d0c, 0x42de,
+ 0x7d0d, 0x2091,
+ 0x7d0e, 0x42df,
+ 0x7d10, 0x20a7,
+ 0x7d11, 0x42e1,
+ 0x7d13, 0x2423,
+ 0x7d14, 0x1e9b,
+ 0x7d15, 0x2422,
+ 0x7d16, 0x42e3,
+ 0x7d17, 0x2110,
+ 0x7d18, 0x42e4,
+ 0x7d19, 0x228d,
+ 0x7d1a, 0x1f71,
+ 0x7d1b, 0x1ef8,
+ 0x7d1c, 0x2421,
+ 0x7d1d, 0x42e5,
+ 0x7d20, 0x0dcd,
+ 0x7d21, 0x1ef3,
+ 0x7d22, 0x0dec,
+ 0x7d23, 0x42e8,
+ 0x7d27, 0x08c5,
+ 0x7d28, 0x42ec,
+ 0x7d2b, 0x122c,
+ 0x7d2c, 0x42ef,
+ 0x7d2f, 0x09c6,
+ 0x7d30, 0x21b1,
+ 0x7d31, 0x2426,
+ 0x7d32, 0x2425,
+ 0x7d33, 0x2120,
+ 0x7d34, 0x42f2,
+ 0x7d39, 0x211a,
+ 0x7d3a, 0x2424,
+ 0x7d3b, 0x42f7,
+ 0x7d3c, 0x2428,
+ 0x7d3d, 0x42f8,
+ 0x7d3f, 0x242a,
+ 0x7d40, 0x2429,
+ 0x7d41, 0x42fa,
+ 0x7d42, 0x2294,
+ 0x7d43, 0x42fb,
+ 0x7d44, 0x22be,
+ 0x7d45, 0x42fc,
+ 0x7d46, 0x1e31,
+ 0x7d47, 0x42fd,
+ 0x7d4e, 0x242c,
+ 0x7d4f, 0x4304,
+ 0x7d50, 0x1fb5,
+ 0x7d51, 0x4305,
+ 0x7d5d, 0x242b,
+ 0x7d5e, 0x1faf,
+ 0x7d5f, 0x4311,
+ 0x7d61, 0x2068,
+ 0x7d62, 0x21e4,
+ 0x7d63, 0x4313,
+ 0x7d66, 0x1f21,
+ 0x7d67, 0x4316,
+ 0x7d68, 0x2101,
+ 0x7d69, 0x4317,
+ 0x7d6e, 0x0fc0,
+ 0x7d6f, 0x431c,
+ 0x7d71, 0x217c,
+ 0x7d72, 0x214a,
+ 0x7d73, 0x242d,
+ 0x7d74, 0x431e,
+ 0x7d76, 0x1fd4,
+ 0x7d77, 0x1ce8,
+ 0x7d78, 0x4320,
+ 0x7d79, 0x1fd1,
+ 0x7d7a, 0x4321,
+ 0x7d81, 0x1e33,
+ 0x7d82, 0x4328,
+ 0x7d83, 0x242f,
+ 0x7d84, 0x4329,
+ 0x7d86, 0x242e,
+ 0x7d87, 0x432b,
+ 0x7d88, 0x2430,
+ 0x7d89, 0x21db,
+ 0x7d8a, 0x432c,
+ 0x7d8f, 0x2158,
+ 0x7d90, 0x4331,
+ 0x7d93, 0x1fc2,
+ 0x7d94, 0x4334,
+ 0x7d9c, 0x22b9,
+ 0x7d9d, 0x433c,
+ 0x7d9e, 0x2436,
+ 0x7d9f, 0x433d,
+ 0x7da2, 0x1e8e,
+ 0x7da3, 0x2439,
+ 0x7da4, 0x4340,
+ 0x7da6, 0x1ce9,
+ 0x7da7, 0x4342,
+ 0x7dab, 0x21c5,
+ 0x7dac, 0x2437,
+ 0x7dad, 0x2192,
+ 0x7dae, 0x1cea,
+ 0x7daf, 0x4346,
+ 0x7db0, 0x243a,
+ 0x7db1, 0x1f19,
+ 0x7db2, 0x218c,
+ 0x7db3, 0x1e40,
+ 0x7db4, 0x22b3,
+ 0x7db5, 0x4347,
+ 0x7db8, 0x205f,
+ 0x7db9, 0x2438,
+ 0x7dba, 0x2432,
+ 0x7dbb, 0x2274,
+ 0x7dbc, 0x434a,
+ 0x7dbd, 0x1e9c,
+ 0x7dbe, 0x2431,
+ 0x7dbf, 0x2085,
+ 0x7dc0, 0x434b,
+ 0x7dc4, 0x2435,
+ 0x7dc5, 0x434f,
+ 0x7dc7, 0x243b,
+ 0x7dc8, 0x4351,
+ 0x7dca, 0x1fb7,
+ 0x7dcb, 0x2433,
+ 0x7dcc, 0x4353,
+ 0x7dd1, 0x2054,
+ 0x7dd2, 0x21de,
+ 0x7dd3, 0x4358,
+ 0x7dd4, 0x2434,
+ 0x7dd5, 0x4359,
+ 0x7dd7, 0x243d,
+ 0x7dd8, 0x1f89,
+ 0x7dd9, 0x243c,
+ 0x7dda, 0x435b,
+ 0x7ddd, 0x1f6e,
+ 0x7dde, 0x1ed8,
+ 0x7ddf, 0x435e,
+ 0x7de0, 0x1ebf,
+ 0x7de1, 0x2445,
+ 0x7de2, 0x435f,
+ 0x7de3, 0x2249,
+ 0x7de4, 0x4360,
+ 0x7de6, 0x2441,
+ 0x7de7, 0x4362,
+ 0x7de8, 0x1e47,
+ 0x7de9, 0x1f56,
+ 0x7dea, 0x4363,
+ 0x7dec, 0x2086,
+ 0x7ded, 0x4365,
+ 0x7def, 0x2196,
+ 0x7df0, 0x4367,
+ 0x7df1, 0x2443,
+ 0x7df2, 0x243f,
+ 0x7df3, 0x4368,
+ 0x7df4, 0x2023,
+ 0x7df5, 0x4369,
+ 0x7df6, 0x2442,
+ 0x7df7, 0x436a,
+ 0x7df9, 0x243e,
+ 0x7dfa, 0x436c,
+ 0x7dfb, 0x26a6,
+ 0x7dfc, 0x436d,
+ 0x7e00, 0x4371,
+ 0x7e08, 0x234e,
+ 0x7e09, 0x2446,
+ 0x7e0a, 0x244b,
+ 0x7e0b, 0x2444,
+ 0x7e0c, 0x4379,
+ 0x7e10, 0x2427,
+ 0x7e11, 0x244c,
+ 0x7e12, 0x437d,
+ 0x7e1b, 0x1f0f,
+ 0x7e1c, 0x4386,
+ 0x7e1d, 0x2447,
+ 0x7e1e, 0x2449,
+ 0x7e1f, 0x2448,
+ 0x7e20, 0x4387,
+ 0x7e23, 0x21c2,
+ 0x7e24, 0x438a,
+ 0x7e27, 0x216e,
+ 0x7e28, 0x438d,
+ 0x7e2b, 0x1f03,
+ 0x7e2c, 0x4390,
+ 0x7e2d, 0x244a,
+ 0x7e2e, 0x215c,
+ 0x7e2f, 0x4391,
+ 0x7e31, 0x22bb,
+ 0x7e32, 0x2450,
+ 0x7e33, 0x4393,
+ 0x7e34, 0x2694,
+ 0x7e35, 0x244f,
+ 0x7e36, 0x25f6,
+ 0x7e37, 0x2051,
+ 0x7e38, 0x4394,
+ 0x7e39, 0x244e,
+ 0x7e3a, 0x4395,
+ 0x7e3b, 0x1dfb,
+ 0x7e3c, 0x4396,
+ 0x7e3d, 0x22ba,
+ 0x7e3e, 0x1f6d,
+ 0x7e3f, 0x4397,
+ 0x7e41, 0x064e,
+ 0x7e42, 0x4399,
+ 0x7e45, 0x2452,
+ 0x7e46, 0x2451,
+ 0x7e47, 0x1ceb,
+ 0x7e48, 0x439c,
+ 0x7e52, 0x2455,
+ 0x7e53, 0x43a6,
+ 0x7e54, 0x2289,
+ 0x7e55, 0x2116,
+ 0x7e56, 0x43a7,
+ 0x7e5a, 0x2454,
+ 0x7e5b, 0x43ab,
+ 0x7e5e, 0x20fb,
+ 0x7e5f, 0x43ae,
+ 0x7e62, 0x2440,
+ 0x7e63, 0x43b1,
+ 0x7e69, 0x2126,
+ 0x7e6a, 0x1f61,
+ 0x7e6b, 0x269d,
+ 0x7e6c, 0x43b7,
+ 0x7e6d, 0x1f8a,
+ 0x7e6e, 0x2456,
+ 0x7e6f, 0x2459,
+ 0x7e70, 0x2458,
+ 0x7e71, 0x43b8,
+ 0x7e73, 0x1fae,
+ 0x7e74, 0x43ba,
+ 0x7e79, 0x221a,
+ 0x7e7a, 0x43bf,
+ 0x7e7c, 0x1f7a,
+ 0x7e7d, 0x244d,
+ 0x7e7e, 0x2457,
+ 0x7e7f, 0x43c1,
+ 0x7e82, 0x1248,
+ 0x7e83, 0x43c4,
+ 0x7e88, 0x2453,
+ 0x7e89, 0x43c9,
+ 0x7e8a, 0x2420,
+ 0x7e8b, 0x43ca,
+ 0x7e8c, 0x21df,
+ 0x7e8d, 0x2685,
+ 0x7e8e, 0x43cb,
+ 0x7e8f, 0x1e6e,
+ 0x7e90, 0x43cc,
+ 0x7e93, 0x2224,
+ 0x7e94, 0x2670,
+ 0x7e95, 0x43cf,
+ 0x7e96, 0x21ba,
+ 0x7e97, 0x43d0,
+ 0x7e98, 0x245a,
+ 0x7e99, 0x43d1,
+ 0x7e9b, 0x1cec,
+ 0x7e9c, 0x1fff,
+ 0x7e9d, 0x43d3,
+ 0x7e9f, 0x17d3,
+ 0x7ea0, 0x08ef,
+ 0x7ea1, 0x17d4,
+ 0x7ea2, 0x07a3,
+ 0x7ea3, 0x17d5,
+ 0x7ea4, 0x0f38,
+ 0x7ea5, 0x17d6,
+ 0x7ea6, 0x10ff,
+ 0x7ea7, 0x0829,
+ 0x7ea8, 0x17d7,
+ 0x7eaa, 0x0840,
+ 0x7eab, 0x0cad,
+ 0x7eac, 0x0ec2,
+ 0x7ead, 0x17d9,
+ 0x7eae, 0x43d5,
+ 0x7eaf, 0x0542,
+ 0x7eb0, 0x17da,
+ 0x7eb1, 0x0ced,
+ 0x7eb2, 0x06d4,
+ 0x7eb3, 0x0b2c,
+ 0x7eb4, 0x43d6,
+ 0x7eb5, 0x123a,
+ 0x7eb6, 0x0a81,
+ 0x7eb7, 0x0674,
+ 0x7eb8, 0x11bc,
+ 0x7eb9, 0x0ed5,
+ 0x7eba, 0x0661,
+ 0x7ebb, 0x43d7,
+ 0x7ebd, 0x0b67,
+ 0x7ebe, 0x17db,
+ 0x7ebf, 0x0f4c,
+ 0x7ec0, 0x17dc,
+ 0x7ec3, 0x0a00,
+ 0x7ec4, 0x1246,
+ 0x7ec5, 0x0d29,
+ 0x7ec6, 0x0f25,
+ 0x7ec7, 0x11ae,
+ 0x7ec8, 0x11d4,
+ 0x7ec9, 0x17df,
+ 0x7eca, 0x03f8,
+ 0x7ecb, 0x17e0,
+ 0x7ecd, 0x0d15,
+ 0x7ece, 0x1076,
+ 0x7ecf, 0x08dc,
+ 0x7ed0, 0x17e2,
+ 0x7ed1, 0x03fe,
+ 0x7ed2, 0x0cb9,
+ 0x7ed3, 0x08b2,
+ 0x7ed4, 0x17e3,
+ 0x7ed5, 0x0ca1,
+ 0x7ed6, 0x43d9,
+ 0x7ed7, 0x17e4,
+ 0x7ed8, 0x07fb,
+ 0x7ed9, 0x06f3,
+ 0x7eda, 0x0fcd,
+ 0x7edb, 0x17e5,
+ 0x7edc, 0x0a8e,
+ 0x7edd, 0x0927,
+ 0x7ede, 0x089b,
+ 0x7edf, 0x0e64,
+ 0x7ee0, 0x17e6,
+ 0x7ee2, 0x091d,
+ 0x7ee3, 0x0fb0,
+ 0x7ee4, 0x43da,
+ 0x7ee5, 0x0ddc,
+ 0x7ee6, 0x0e23,
+ 0x7ee7, 0x083f,
+ 0x7ee8, 0x17e8,
+ 0x7ee9, 0x081b,
+ 0x7eea, 0x0fc2,
+ 0x7eeb, 0x17e9,
+ 0x7eec, 0x43db,
+ 0x7eed, 0x0fc3,
+ 0x7eee, 0x17ea,
+ 0x7ef0, 0x0545,
+ 0x7ef1, 0x17ec,
+ 0x7ef3, 0x0d37,
+ 0x7ef4, 0x0ebb,
+ 0x7ef5, 0x0ae5,
+ 0x7ef6, 0x17ef,
+ 0x7ef7, 0x042a,
+ 0x7ef8, 0x0516,
+ 0x7ef9, 0x43dc,
+ 0x7efa, 0x17f0,
+ 0x7efc, 0x1238,
+ 0x7efd, 0x1161,
+ 0x7efe, 0x17f2,
+ 0x7eff, 0x0a73,
+ 0x7f00, 0x1217,
+ 0x7f01, 0x17f3,
+ 0x7f04, 0x085d,
+ 0x7f05, 0x0aea,
+ 0x7f06, 0x09ad,
+ 0x7f07, 0x17f6,
+ 0x7f09, 0x081c,
+ 0x7f0a, 0x43dd,
+ 0x7f0b, 0x17f8,
+ 0x7f0d, 0x17ee,
+ 0x7f0e, 0x060f,
+ 0x7f0f, 0x17fa,
+ 0x7f10, 0x43de,
+ 0x7f11, 0x17fb,
+ 0x7f13, 0x07cf,
+ 0x7f14, 0x05bf,
+ 0x7f15, 0x0a6d,
+ 0x7f16, 0x0449,
+ 0x7f17, 0x17fd,
+ 0x7f18, 0x10f8,
+ 0x7f19, 0x17fe,
+ 0x7f1a, 0x06ba,
+ 0x7f1b, 0x1800,
+ 0x7f1c, 0x17ff,
+ 0x7f1d, 0x0689,
+ 0x7f1e, 0x43df,
+ 0x7f1f, 0x1801,
+ 0x7f20, 0x04bf,
+ 0x7f21, 0x1802,
+ 0x7f28, 0x108c,
+ 0x7f29, 0x0dea,
+ 0x7f2a, 0x1809,
+ 0x7f2e, 0x0d02,
+ 0x7f2f, 0x180d,
+ 0x7f34, 0x089a,
+ 0x7f35, 0x1812,
+ 0x7f36, 0x1c5e,
+ 0x7f37, 0x43e0,
+ 0x7f38, 0x06d2,
+ 0x7f39, 0x43e1,
+ 0x7f3a, 0x0c8c,
+ 0x7f3b, 0x43e2,
+ 0x7f42, 0x1c5f,
+ 0x7f43, 0x43e9,
+ 0x7f44, 0x1c60,
+ 0x7f46, 0x43ea,
+ 0x7f4c, 0x25e2,
+ 0x7f4d, 0x43f0,
+ 0x7f4e, 0x269a,
+ 0x7f4f, 0x43f1,
+ 0x7f50, 0x0737,
+ 0x7f51, 0x0ea9,
+ 0x7f52, 0x43f2,
+ 0x7f54, 0x129e,
+ 0x7f55, 0x0768,
+ 0x7f56, 0x43f4,
+ 0x7f57, 0x0a85,
+ 0x7f58, 0x1a81,
+ 0x7f59, 0x43f5,
+ 0x7f5a, 0x0640,
+ 0x7f5b, 0x43f6,
+ 0x7f5f, 0x1a83,
+ 0x7f60, 0x43fa,
+ 0x7f61, 0x1a82,
+ 0x7f62, 0x03e0,
+ 0x7f63, 0x43fb,
+ 0x7f68, 0x1a85,
+ 0x7f69, 0x1177,
+ 0x7f6a, 0x124c,
+ 0x7f6b, 0x4400,
+ 0x7f6e, 0x11c2,
+ 0x7f6f, 0x4403,
+ 0x7f70, 0x1eea,
+ 0x7f71, 0x1a87,
+ 0x7f72, 0x0d87,
+ 0x7f73, 0x4404,
+ 0x7f74, 0x1a86,
+ 0x7f75, 0x4405,
+ 0x7f77, 0x1e2c,
+ 0x7f78, 0x4407,
+ 0x7f79, 0x1a88,
+ 0x7f7a, 0x4408,
+ 0x7f7e, 0x1a8a,
+ 0x7f7f, 0x440c,
+ 0x7f81, 0x1a89,
+ 0x7f82, 0x440e,
+ 0x7f85, 0x2062,
+ 0x7f86, 0x24f1,
+ 0x7f87, 0x4411,
+ 0x7f88, 0x24f2,
+ 0x7f89, 0x4412,
+ 0x7f8a, 0x101b,
+ 0x7f8b, 0x4413,
+ 0x7f8c, 0x0c39,
+ 0x7f8d, 0x4414,
+ 0x7f8e, 0x0ac5,
+ 0x7f8f, 0x4415,
+ 0x7f94, 0x06dc,
+ 0x7f95, 0x441a,
+ 0x7f9a, 0x0a30,
+ 0x7f9b, 0x441f,
+ 0x7f9d, 0x1cc4,
+ 0x7f9e, 0x0faa,
+ 0x7f9f, 0x1cc5,
+ 0x7fa0, 0x4421,
+ 0x7fa1, 0x0f48,
+ 0x7fa2, 0x4422,
+ 0x7fa4, 0x0c95,
+ 0x7fa5, 0x25f2,
+ 0x7fa6, 0x4424,
+ 0x7fa7, 0x1cc6,
+ 0x7fa8, 0x4425,
+ 0x7fa9, 0x2215,
+ 0x7faa, 0x4426,
+ 0x7faf, 0x1cc7,
+ 0x7fb1, 0x442b,
+ 0x7fb2, 0x1cc9,
+ 0x7fb3, 0x442c,
+ 0x7fb8, 0x130e,
+ 0x7fb9, 0x06f9,
+ 0x7fba, 0x4431,
+ 0x7fbc, 0x176d,
+ 0x7fbd, 0x10d5,
+ 0x7fbe, 0x4433,
+ 0x7fbf, 0x1cde,
+ 0x7fc0, 0x4434,
+ 0x7fc1, 0x0edb,
+ 0x7fc2, 0x4435,
+ 0x7fc5, 0x0506,
+ 0x7fc6, 0x4438,
+ 0x7fca, 0x1b98,
+ 0x7fcb, 0x443c,
+ 0x7fcc, 0x1075,
+ 0x7fcd, 0x443d,
+ 0x7fce, 0x1cdf,
+ 0x7fcf, 0x443e,
+ 0x7fd2, 0x21ae,
+ 0x7fd3, 0x4441,
+ 0x7fd4, 0x0f55,
+ 0x7fd5, 0x1ce0,
+ 0x7fd6, 0x4442,
+ 0x7fd8, 0x0c49,
+ 0x7fd9, 0x4444,
+ 0x7fdf, 0x05b5,
+ 0x7fe0, 0x0567,
+ 0x7fe1, 0x1ce2,
+ 0x7fe2, 0x444a,
+ 0x7fe5, 0x1ce1,
+ 0x7fe6, 0x1ce3,
+ 0x7fe7, 0x444d,
+ 0x7fe9, 0x1ce4,
+ 0x7fea, 0x444f,
+ 0x7fee, 0x1ce5,
+ 0x7fef, 0x4453,
+ 0x7ff0, 0x0769,
+ 0x7ff1, 0x03ca,
+ 0x7ff2, 0x4454,
+ 0x7ff3, 0x1ce6,
+ 0x7ff4, 0x4455,
+ 0x7ff9, 0x20e0,
+ 0x7ffa, 0x445a,
+ 0x7ffb, 0x064a,
+ 0x7ffc, 0x1074,
+ 0x7ffd, 0x445b,
+ 0x8000, 0x1032,
+ 0x8001, 0x09ba,
+ 0x8002, 0x445e,
+ 0x8003, 0x0949,
+ 0x8004, 0x1953,
+ 0x8005, 0x1180,
+ 0x8006, 0x191a,
+ 0x8007, 0x445f,
+ 0x800b, 0x1bd7,
+ 0x800c, 0x0637,
+ 0x800d, 0x0d98,
+ 0x800e, 0x4463,
+ 0x8010, 0x0b30,
+ 0x8011, 0x4465,
+ 0x8012, 0x1bcb,
+ 0x8013, 0x4466,
+ 0x8014, 0x1bcc,
+ 0x8015, 0x06f6,
+ 0x8016, 0x1bcd,
+ 0x8017, 0x077b,
+ 0x8018, 0x1108,
+ 0x8019, 0x03dd,
+ 0x801a, 0x4467,
+ 0x801c, 0x1bce,
+ 0x801d, 0x4469,
+ 0x8020, 0x1bcf,
+ 0x8021, 0x446c,
+ 0x8022, 0x1bd0,
+ 0x8023, 0x446d,
+ 0x8025, 0x1bd1,
+ 0x8028, 0x1bd5,
+ 0x8029, 0x1bd4,
+ 0x802a, 0x0b96,
+ 0x802b, 0x446f,
+ 0x802c, 0x25c2,
+ 0x802d, 0x4470,
+ 0x802e, 0x25c1,
+ 0x802f, 0x4471,
+ 0x8031, 0x1bd6,
+ 0x8032, 0x4473,
+ 0x8033, 0x0639,
+ 0x8034, 0x4474,
+ 0x8035, 0x1bd8,
+ 0x8036, 0x1035,
+ 0x8037, 0x14b1,
+ 0x8038, 0x0dbf,
+ 0x8039, 0x4475,
+ 0x803b, 0x0501,
+ 0x803c, 0x4477,
+ 0x803d, 0x0583,
+ 0x803e, 0x4478,
+ 0x803f, 0x06fb,
+ 0x8040, 0x4479,
+ 0x8042, 0x0b57,
+ 0x8043, 0x1bd9,
+ 0x8044, 0x447b,
+ 0x8046, 0x1bda,
+ 0x8047, 0x447d,
+ 0x804a, 0x0a0d,
+ 0x804b, 0x0a44,
+ 0x804c, 0x11af,
+ 0x804d, 0x1bdb,
+ 0x804e, 0x4480,
+ 0x8052, 0x1bdc,
+ 0x8053, 0x4484,
+ 0x8054, 0x09f3,
+ 0x8055, 0x4485,
+ 0x8056, 0x2128,
+ 0x8057, 0x4486,
+ 0x8058, 0x0bd7,
+ 0x8059, 0x4487,
+ 0x805a, 0x090a,
+ 0x805b, 0x4488,
+ 0x805e, 0x2199,
+ 0x805f, 0x448b,
+ 0x8069, 0x1bdd,
+ 0x806a, 0x0552,
+ 0x806b, 0x4495,
+ 0x806f, 0x2017,
+ 0x8070, 0x1ea0,
+ 0x8071, 0x1bde,
+ 0x8072, 0x2125,
+ 0x8073, 0x214d,
+ 0x8074, 0x4499,
+ 0x8075, 0x25c4,
+ 0x8076, 0x209d,
+ 0x8077, 0x228a,
+ 0x8078, 0x449a,
+ 0x8079, 0x25c3,
+ 0x807a, 0x449b,
+ 0x807d, 0x2179,
+ 0x807e, 0x2038,
+ 0x807f, 0x1a1e,
+ 0x8080, 0x1a1d,
+ 0x8081, 0x449e,
+ 0x8083, 0x0dd5,
+ 0x8084, 0x1065,
+ 0x8085, 0x2155,
+ 0x8086, 0x0db6,
+ 0x8087, 0x1179,
+ 0x8088, 0x44a0,
+ 0x8089, 0x0cbd,
+ 0x808a, 0x44a1,
+ 0x808b, 0x09ca,
+ 0x808c, 0x0814,
+ 0x808d, 0x44a2,
+ 0x8093, 0x1971,
+ 0x8094, 0x44a8,
+ 0x8096, 0x0f6f,
+ 0x8097, 0x44aa,
+ 0x8098, 0x11e1,
+ 0x8099, 0x44ab,
+ 0x809a, 0x0606,
+ 0x809b, 0x06d3,
+ 0x809c, 0x1970,
+ 0x809d, 0x06c9,
+ 0x809e, 0x44ac,
+ 0x809f, 0x196f,
+ 0x80a0, 0x04cb,
+ 0x80a1, 0x0722,
+ 0x80a2, 0x11aa,
+ 0x80a3, 0x44ad,
+ 0x80a4, 0x0691,
+ 0x80a5, 0x0667,
+ 0x80a6, 0x44ae,
+ 0x80a9, 0x085a,
+ 0x80aa, 0x065b,
+ 0x80ab, 0x1976,
+ 0x80ac, 0x44b1,
+ 0x80ad, 0x1977,
+ 0x80ae, 0x03c4,
+ 0x80af, 0x095c,
+ 0x80b0, 0x44b2,
+ 0x80b1, 0x1975,
+ 0x80b2, 0x10e2,
+ 0x80b3, 0x44b3,
+ 0x80b4, 0x1978,
+ 0x80b5, 0x44b4,
+ 0x80b7, 0x1979,
+ 0x80b8, 0x44b6,
+ 0x80ba, 0x066b,
+ 0x80bb, 0x44b8,
+ 0x80bc, 0x1972,
+ 0x80bd, 0x1974,
+ 0x80be, 0x0d2f,
+ 0x80bf, 0x11d6,
+ 0x80c0, 0x116e,
+ 0x80c1, 0x0f7d,
+ 0x80c2, 0x197f,
+ 0x80c3, 0x0ec7,
+ 0x80c4, 0x1980,
+ 0x80c5, 0x44b9,
+ 0x80c6, 0x0589,
+ 0x80c7, 0x44ba,
+ 0x80cc, 0x041c,
+ 0x80cd, 0x1982,
+ 0x80ce, 0x0df8,
+ 0x80cf, 0x44bf,
+ 0x80d6, 0x0b97,
+ 0x80d7, 0x1983,
+ 0x80d8, 0x44c6,
+ 0x80d9, 0x1981,
+ 0x80da, 0x0ba0,
+ 0x80db, 0x197e,
+ 0x80dc, 0x0d3b,
+ 0x80dd, 0x1985,
+ 0x80de, 0x0406,
+ 0x80df, 0x44c7,
+ 0x80e1, 0x07b1,
+ 0x80e2, 0x44c9,
+ 0x80e4, 0x126d,
+ 0x80e5, 0x1bc7,
+ 0x80e6, 0x44cb,
+ 0x80e7, 0x197a,
+ 0x80eb, 0x1986,
+ 0x80ec, 0x179a,
+ 0x80ed, 0x1989,
+ 0x80ee, 0x44cc,
+ 0x80ef, 0x0975,
+ 0x80f0, 0x104f,
+ 0x80f1, 0x1987,
+ 0x80f2, 0x198c,
+ 0x80f3, 0x06e7,
+ 0x80f4, 0x1988,
+ 0x80f5, 0x44cd,
+ 0x80f6, 0x088b,
+ 0x80f7, 0x44ce,
+ 0x80f8, 0x0fa3,
+ 0x80f9, 0x44cf,
+ 0x80fa, 0x03c2,
+ 0x80fb, 0x44d0,
+ 0x80fc, 0x198d,
+ 0x80fd, 0x0b3f,
+ 0x80fe, 0x44d1,
+ 0x8100, 0x44d3,
+ 0x8102, 0x11ab,
+ 0x8103, 0x44d5,
+ 0x8105, 0x21d2,
+ 0x8106, 0x0563,
+ 0x8107, 0x44d7,
+ 0x8109, 0x0a9d,
+ 0x810a, 0x082c,
+ 0x810b, 0x44d9,
+ 0x810d, 0x198a,
+ 0x810f, 0x1123,
+ 0x8110, 0x0c09,
+ 0x8111, 0x0b37,
+ 0x8112, 0x198f,
+ 0x8113, 0x0b68,
+ 0x8114, 0x1309,
+ 0x8115, 0x44db,
+ 0x8116, 0x0478,
+ 0x8117, 0x44dc,
+ 0x8118, 0x1994,
+ 0x8119, 0x44dd,
+ 0x811a, 0x0896,
+ 0x811b, 0x24c7,
+ 0x811c, 0x44de,
+ 0x811e, 0x1992,
+ 0x811f, 0x44e0,
+ 0x812c, 0x1993,
+ 0x812d, 0x44ed,
+ 0x812f, 0x06a7,
+ 0x8130, 0x44ef,
+ 0x8131, 0x0e82,
+ 0x8132, 0x1995,
+ 0x8133, 0x44f0,
+ 0x8136, 0x1991,
+ 0x8137, 0x44f3,
+ 0x8138, 0x09fc,
+ 0x8139, 0x2279,
+ 0x813a, 0x44f4,
+ 0x813e, 0x0bc1,
+ 0x813f, 0x44f8,
+ 0x8146, 0x0e46,
+ 0x8147, 0x44ff,
+ 0x8148, 0x1996,
+ 0x8149, 0x4500,
+ 0x814a, 0x099b,
+ 0x814b, 0x103f,
+ 0x814c, 0x1997,
+ 0x814d, 0x4501,
+ 0x814e, 0x2123,
+ 0x814f, 0x4502,
+ 0x8150, 0x06aa,
+ 0x8151, 0x06a8,
+ 0x8152, 0x4503,
+ 0x8153, 0x1998,
+ 0x8154, 0x0c38,
+ 0x8155, 0x0ea4,
+ 0x8156, 0x24c5,
+ 0x8157, 0x4504,
+ 0x8159, 0x199a,
+ 0x815b, 0x4506,
+ 0x8160, 0x199d,
+ 0x8161, 0x24c9,
+ 0x8162, 0x450b,
+ 0x8165, 0x0f93,
+ 0x8166, 0x2094,
+ 0x8167, 0x19a2,
+ 0x8168, 0x450e,
+ 0x8169, 0x199e,
+ 0x816a, 0x450f,
+ 0x816b, 0x2296,
+ 0x816c, 0x4510,
+ 0x816d, 0x19a1,
+ 0x816e, 0x0cd4,
+ 0x816f, 0x4511,
+ 0x8170, 0x1025,
+ 0x8171, 0x199c,
+ 0x8172, 0x4512,
+ 0x8174, 0x1999,
+ 0x8175, 0x4514,
+ 0x8178, 0x1e77,
+ 0x8179, 0x06b4,
+ 0x817a, 0x0f46,
+ 0x817b, 0x0b48,
+ 0x817c, 0x199f,
+ 0x817e, 0x0e2d,
+ 0x817f, 0x0e79,
+ 0x8180, 0x03fd,
+ 0x8181, 0x4517,
+ 0x8182, 0x19a6,
+ 0x8183, 0x4518,
+ 0x8188, 0x19a5,
+ 0x8189, 0x451d,
+ 0x818a, 0x0479,
+ 0x818b, 0x451e,
+ 0x818f, 0x06db,
+ 0x8190, 0x4522,
+ 0x8191, 0x19a7,
+ 0x8192, 0x4523,
+ 0x8198, 0x0455,
+ 0x8199, 0x4529,
+ 0x819a, 0x1f06,
+ 0x819b, 0x0e18,
+ 0x819c, 0x0b07,
+ 0x819d, 0x0f12,
+ 0x819e, 0x452a,
+ 0x81a0, 0x1fa5,
+ 0x81a1, 0x452c,
+ 0x81a3, 0x19a9,
+ 0x81a4, 0x452e,
+ 0x81a6, 0x19b0,
+ 0x81a7, 0x4530,
+ 0x81a8, 0x0bb3,
+ 0x81a9, 0x2099,
+ 0x81aa, 0x19aa,
+ 0x81ab, 0x4531,
+ 0x81b3, 0x0cfe,
+ 0x81b4, 0x4539,
+ 0x81ba, 0x1641,
+ 0x81bb, 0x19ae,
+ 0x81bc, 0x453f,
+ 0x81bd, 0x1ead,
+ 0x81be, 0x24c8,
+ 0x81bf, 0x20a8,
+ 0x81c0, 0x0e7f,
+ 0x81c1, 0x19af,
+ 0x81c2, 0x0444,
+ 0x81c3, 0x109c,
+ 0x81c4, 0x4540,
+ 0x81c6, 0x1063,
+ 0x81c7, 0x4542,
+ 0x81c9, 0x201f,
+ 0x81ca, 0x19ad,
+ 0x81cb, 0x4544,
+ 0x81cc, 0x19ab,
+ 0x81cd, 0x20c5,
+ 0x81ce, 0x4545,
+ 0x81cf, 0x24ca,
+ 0x81d0, 0x4546,
+ 0x81d8, 0x1ff0,
+ 0x81d9, 0x454e,
+ 0x81da, 0x24c6,
+ 0x81db, 0x454f,
+ 0x81df, 0x225d,
+ 0x81e0, 0x22de,
+ 0x81e1, 0x4553,
+ 0x81e3, 0x04e1,
+ 0x81e4, 0x4555,
+ 0x81e7, 0x1902,
+ 0x81e8, 0x202c,
+ 0x81e9, 0x4558,
+ 0x81ea, 0x1231,
+ 0x81eb, 0x4559,
+ 0x81ec, 0x1ca9,
+ 0x81ed, 0x0519,
+ 0x81ee, 0x455a,
+ 0x81f3, 0x11c0,
+ 0x81f5, 0x455f,
+ 0x81fa, 0x2161,
+ 0x81fb, 0x118a,
+ 0x81fc, 0x08f9,
+ 0x81fd, 0x4564,
+ 0x81fe, 0x1ca5,
+ 0x81ff, 0x4565,
+ 0x8200, 0x102f,
+ 0x8201, 0x1ca6,
+ 0x8203, 0x4566,
+ 0x8204, 0x1ca8,
+ 0x8205, 0x08fa,
+ 0x8206, 0x10c4,
+ 0x8207, 0x223b,
+ 0x8208, 0x21d9,
+ 0x8209, 0x1fcb,
+ 0x820a, 0x1fc9,
+ 0x820b, 0x4567,
+ 0x820c, 0x0d19,
+ 0x820e, 0x4568,
+ 0x8210, 0x1c62,
+ 0x8211, 0x456a,
+ 0x8212, 0x0d7d,
+ 0x8213, 0x456b,
+ 0x8214, 0x0e45,
+ 0x8215, 0x456c,
+ 0x821b, 0x1618,
+ 0x821c, 0x0da9,
+ 0x821d, 0x4572,
+ 0x821e, 0x0ef7,
+ 0x821f, 0x11da,
+ 0x8220, 0x4573,
+ 0x8221, 0x1cab,
+ 0x8224, 0x4574,
+ 0x8228, 0x1cb0,
+ 0x8229, 0x4578,
+ 0x822a, 0x0774,
+ 0x822b, 0x1cb1,
+ 0x822c, 0x03ee,
+ 0x822d, 0x1cae,
+ 0x822e, 0x4579,
+ 0x822f, 0x1caf,
+ 0x8230, 0x0873,
+ 0x8231, 0x049c,
+ 0x8232, 0x457a,
+ 0x8233, 0x1cb4,
+ 0x8235, 0x0625,
+ 0x8236, 0x0477,
+ 0x8237, 0x0f3c,
+ 0x8238, 0x1cb2,
+ 0x8239, 0x052f,
+ 0x823a, 0x457b,
+ 0x823b, 0x1cb3,
+ 0x823c, 0x457c,
+ 0x823e, 0x1cb6,
+ 0x823f, 0x457e,
+ 0x8244, 0x1cb7,
+ 0x8245, 0x4583,
+ 0x8247, 0x0e58,
+ 0x8248, 0x4585,
+ 0x8249, 0x1cb8,
+ 0x824a, 0x4586,
+ 0x824b, 0x1cb9,
+ 0x824c, 0x4587,
+ 0x824f, 0x1cba,
+ 0x8250, 0x458a,
+ 0x8258, 0x0dc7,
+ 0x8259, 0x1e61,
+ 0x825a, 0x1cbb,
+ 0x825b, 0x4592,
+ 0x825f, 0x1cbc,
+ 0x8260, 0x4596,
+ 0x8264, 0x25ef,
+ 0x8265, 0x459a,
+ 0x8266, 0x1f98,
+ 0x8267, 0x459b,
+ 0x8268, 0x1cbd,
+ 0x8269, 0x459c,
+ 0x826b, 0x25f0,
+ 0x826c, 0x459e,
+ 0x826e, 0x1cdc,
+ 0x826f, 0x0a05,
+ 0x8270, 0x085b,
+ 0x8271, 0x1f88,
+ 0x8272, 0x0ce4,
+ 0x8273, 0x1007,
+ 0x8274, 0x1771,
+ 0x8275, 0x45a0,
+ 0x8277, 0x21f8,
+ 0x8278, 0x45a2,
+ 0x8279, 0x13e1,
+ 0x827a, 0x105c,
+ 0x827b, 0x45a3,
+ 0x827d, 0x13e2,
+ 0x827e, 0x03b7,
+ 0x827f, 0x13e3,
+ 0x8280, 0x45a5,
+ 0x8282, 0x08ab,
+ 0x8283, 0x45a7,
+ 0x8284, 0x13e7,
+ 0x8285, 0x45a8,
+ 0x8288, 0x1278,
+ 0x8289, 0x45ab,
+ 0x828a, 0x13e5,
+ 0x828b, 0x10d8,
+ 0x828c, 0x45ac,
+ 0x828d, 0x0d0f,
+ 0x828e, 0x13e8,
+ 0x828f, 0x13e4,
+ 0x8290, 0x45ad,
+ 0x8291, 0x13e9,
+ 0x8292, 0x0aa7,
+ 0x8293, 0x45ae,
+ 0x8297, 0x13ea,
+ 0x8298, 0x13f3,
+ 0x8299, 0x13eb,
+ 0x829a, 0x45b2,
+ 0x829c, 0x0eee,
+ 0x829d, 0x11a4,
+ 0x829e, 0x45b4,
+ 0x829f, 0x13fd,
+ 0x82a0, 0x45b5,
+ 0x82a1, 0x13fb,
+ 0x82a2, 0x45b6,
+ 0x82a4, 0x1400,
+ 0x82a5, 0x08b7,
+ 0x82a6, 0x0a52,
+ 0x82a7, 0x45b8,
+ 0x82a8, 0x13e6,
+ 0x82a9, 0x13f9,
+ 0x82aa, 0x13fc,
+ 0x82ab, 0x13ec,
+ 0x82ac, 0x066f,
+ 0x82ad, 0x03d0,
+ 0x82ae, 0x13f5,
+ 0x82af, 0x0f89,
+ 0x82b0, 0x13ef,
+ 0x82b1, 0x07bd,
+ 0x82b2, 0x45b9,
+ 0x82b3, 0x0659,
+ 0x82b4, 0x13fa,
+ 0x82b5, 0x45ba,
+ 0x82b7, 0x13f4,
+ 0x82b8, 0x13ed,
+ 0x82b9, 0x0c58,
+ 0x82ba, 0x45bc,
+ 0x82bb, 0x2322,
+ 0x82bc, 0x45bd,
+ 0x82bd, 0x0fe8,
+ 0x82be, 0x13ee,
+ 0x82bf, 0x45be,
+ 0x82c1, 0x13f8,
+ 0x82c2, 0x45c0,
+ 0x82c4, 0x13fe,
+ 0x82c5, 0x45c2,
+ 0x82c7, 0x0ebc,
+ 0x82c8, 0x13f0,
+ 0x82c9, 0x45c4,
+ 0x82ca, 0x13f1,
+ 0x82cb, 0x13f6,
+ 0x82cd, 0x049b,
+ 0x82ce, 0x13ff,
+ 0x82cf, 0x0dca,
+ 0x82d0, 0x45c5,
+ 0x82d1, 0x10fa,
+ 0x82d2, 0x1409,
+ 0x82d3, 0x140d,
+ 0x82d4, 0x0df9,
+ 0x82d5, 0x1414,
+ 0x82d6, 0x45c6,
+ 0x82d7, 0x0aec,
+ 0x82d8, 0x140a,
+ 0x82d9, 0x45c7,
+ 0x82db, 0x094e,
+ 0x82dc, 0x1407,
+ 0x82dd, 0x45c9,
+ 0x82de, 0x0405,
+ 0x82df, 0x070f,
+ 0x82e0, 0x1413,
+ 0x82e1, 0x1401,
+ 0x82e2, 0x45ca,
+ 0x82e3, 0x13f2,
+ 0x82e4, 0x1404,
+ 0x82e5, 0x0ccf,
+ 0x82e6, 0x096d,
+ 0x82e7, 0x2336,
+ 0x82e8, 0x45cb,
+ 0x82eb, 0x0cf4,
+ 0x82ec, 0x45ce,
+ 0x82ef, 0x0426,
+ 0x82f0, 0x45d1,
+ 0x82f1, 0x1087,
+ 0x82f2, 0x45d2,
+ 0x82f4, 0x1408,
+ 0x82f5, 0x45d4,
+ 0x82f7, 0x1403,
+ 0x82f8, 0x45d6,
+ 0x82f9, 0x0bda,
+ 0x82fa, 0x45d7,
+ 0x82fb, 0x140c,
+ 0x82fc, 0x45d8,
+ 0x8300, 0x45dc,
+ 0x8301, 0x121f,
+ 0x8302, 0x0ab4,
+ 0x8303, 0x0653,
+ 0x8304, 0x0c4e,
+ 0x8305, 0x0aae,
+ 0x8306, 0x1410,
+ 0x8307, 0x1406,
+ 0x8308, 0x1419,
+ 0x8309, 0x1402,
+ 0x830a, 0x45dd,
+ 0x830c, 0x140b,
+ 0x830d, 0x45df,
+ 0x830e, 0x08d4,
+ 0x830f, 0x1405,
+ 0x8310, 0x45e0,
+ 0x8311, 0x140e,
+ 0x8312, 0x45e1,
+ 0x8314, 0x1411,
+ 0x8316, 0x45e3,
+ 0x8317, 0x1426,
+ 0x8318, 0x45e4,
+ 0x831a, 0x140f,
+ 0x831b, 0x142e,
+ 0x831c, 0x1415,
+ 0x831d, 0x45e6,
+ 0x8327, 0x085e,
+ 0x8328, 0x0547,
+ 0x8329, 0x45f0,
+ 0x832b, 0x0aa8,
+ 0x832c, 0x04ae,
+ 0x832d, 0x1428,
+ 0x832e, 0x45f2,
+ 0x832f, 0x1420,
+ 0x8330, 0x45f3,
+ 0x8331, 0x141d,
+ 0x8332, 0x45f4,
+ 0x8333, 0x142a,
+ 0x8334, 0x141c,
+ 0x8335, 0x1077,
+ 0x8336, 0x04af,
+ 0x8337, 0x45f5,
+ 0x8338, 0x0cb2,
+ 0x8339, 0x0cbe,
+ 0x833a, 0x1429,
+ 0x833b, 0x45f6,
+ 0x833c, 0x141b,
+ 0x833d, 0x45f7,
+ 0x8340, 0x1425,
+ 0x8341, 0x45fa,
+ 0x8343, 0x1423,
+ 0x8344, 0x45fc,
+ 0x8346, 0x08d2,
+ 0x8347, 0x1422,
+ 0x8348, 0x45fe,
+ 0x8349, 0x04a4,
+ 0x834a, 0x45ff,
+ 0x834f, 0x1421,
+ 0x8350, 0x0869,
+ 0x8351, 0x1416,
+ 0x8352, 0x07d9,
+ 0x8353, 0x4604,
+ 0x8354, 0x09de,
+ 0x8355, 0x4605,
+ 0x835a, 0x0847,
+ 0x835b, 0x1417,
+ 0x835d, 0x460a,
+ 0x835e, 0x141f,
+ 0x835f, 0x1424,
+ 0x8360, 0x1427,
+ 0x8361, 0x0595,
+ 0x8362, 0x460b,
+ 0x8363, 0x0cb4,
+ 0x8364, 0x07fc,
+ 0x8365, 0x142c,
+ 0x8366, 0x142b,
+ 0x8367, 0x1090,
+ 0x8368, 0x142d,
+ 0x8369, 0x142f,
+ 0x836a, 0x1431,
+ 0x836b, 0x1078,
+ 0x836c, 0x1430,
+ 0x836d, 0x1432,
+ 0x836f, 0x1030,
+ 0x8370, 0x460c,
+ 0x8377, 0x0780,
+ 0x8378, 0x1435,
+ 0x8379, 0x4613,
+ 0x837b, 0x1442,
+ 0x837c, 0x143d,
+ 0x837d, 0x1440,
+ 0x837e, 0x4615,
+ 0x8385, 0x143c,
+ 0x8386, 0x0bed,
+ 0x8387, 0x461c,
+ 0x8389, 0x09dd,
+ 0x838a, 0x22ab,
+ 0x838b, 0x461e,
+ 0x838e, 0x0ce8,
+ 0x838f, 0x4621,
+ 0x8392, 0x141a,
+ 0x8393, 0x143a,
+ 0x8394, 0x4624,
+ 0x8396, 0x1fbf,
+ 0x8397, 0x4626,
+ 0x8398, 0x1443,
+ 0x8399, 0x4627,
+ 0x839b, 0x141e,
+ 0x839c, 0x143b,
+ 0x839d, 0x4629,
+ 0x839e, 0x1444,
+ 0x839f, 0x462a,
+ 0x83a0, 0x1438,
+ 0x83a1, 0x462b,
+ 0x83a2, 0x1f7d,
+ 0x83a3, 0x462c,
+ 0x83a7, 0x2333,
+ 0x83a8, 0x1445,
+ 0x83a9, 0x143f,
+ 0x83aa, 0x1439,
+ 0x83ab, 0x0b0d,
+ 0x83ac, 0x4630,
+ 0x83b0, 0x1434,
+ 0x83b1, 0x099e,
+ 0x83b2, 0x09f4,
+ 0x83b3, 0x1436,
+ 0x83b5, 0x4634,
+ 0x83b6, 0x143e,
+ 0x83b7, 0x0806,
+ 0x83b8, 0x1441,
+ 0x83b9, 0x108d,
+ 0x83ba, 0x1446,
+ 0x83bb, 0x4635,
+ 0x83bc, 0x1447,
+ 0x83bd, 0x0aac,
+ 0x83be, 0x4636,
+ 0x83c0, 0x145e,
+ 0x83c1, 0x1448,
+ 0x83c2, 0x4638,
+ 0x83c5, 0x145d,
+ 0x83c6, 0x463b,
+ 0x83c7, 0x0716,
+ 0x83c8, 0x463c,
+ 0x83ca, 0x0904,
+ 0x83cb, 0x463e,
+ 0x83cc, 0x0929,
+ 0x83cd, 0x463f,
+ 0x83cf, 0x0781,
+ 0x83d0, 0x4641,
+ 0x83d4, 0x1456,
+ 0x83d5, 0x4645,
+ 0x83d6, 0x1451,
+ 0x83d7, 0x4646,
+ 0x83d8, 0x144b,
+ 0x83d9, 0x4647,
+ 0x83dc, 0x0492,
+ 0x83dd, 0x144f,
+ 0x83de, 0x464a,
+ 0x83df, 0x1457,
+ 0x83e0, 0x046b,
+ 0x83e1, 0x1461,
+ 0x83e2, 0x464b,
+ 0x83e5, 0x144a,
+ 0x83e6, 0x464e,
+ 0x83e9, 0x0bef,
+ 0x83ea, 0x145c,
+ 0x83eb, 0x4651,
+ 0x83ef, 0x1f4d,
+ 0x83f0, 0x1460,
+ 0x83f1, 0x0a2b,
+ 0x83f2, 0x0663,
+ 0x83f3, 0x4655,
+ 0x83f8, 0x145a,
+ 0x83fa, 0x465a,
+ 0x83fd, 0x1450,
+ 0x83fe, 0x465d,
+ 0x8400, 0x465f,
+ 0x8401, 0x1449,
+ 0x8402, 0x4660,
+ 0x8403, 0x1459,
+ 0x8404, 0x0e24,
+ 0x8405, 0x4661,
+ 0x8406, 0x1455,
+ 0x8407, 0x2334,
+ 0x8408, 0x4662,
+ 0x840a, 0x1ff1,
+ 0x840b, 0x144e,
+ 0x840c, 0x0acd,
+ 0x840d, 0x0bdb,
+ 0x840e, 0x0ebd,
+ 0x840f, 0x1458,
+ 0x8410, 0x4664,
+ 0x8411, 0x1454,
+ 0x8412, 0x4665,
+ 0x8418, 0x144d,
+ 0x8419, 0x466b,
+ 0x841c, 0x1452,
+ 0x841d, 0x0a83,
+ 0x841e, 0x466e,
+ 0x8424, 0x108e,
+ 0x8426, 0x145f,
+ 0x8427, 0x0f61,
+ 0x8428, 0x0cd3,
+ 0x8429, 0x4674,
+ 0x842c, 0x218b,
+ 0x842d, 0x4677,
+ 0x8431, 0x1472,
+ 0x8432, 0x467b,
+ 0x8435, 0x2349,
+ 0x8436, 0x467e,
+ 0x8438, 0x1453,
+ 0x8439, 0x4680,
+ 0x843c, 0x146c,
+ 0x843d, 0x0a8b,
+ 0x843e, 0x4683,
+ 0x8446, 0x146d,
+ 0x8447, 0x468b,
+ 0x8449, 0x220b,
+ 0x844a, 0x468d,
+ 0x8451, 0x1463,
+ 0x8452, 0x2346,
+ 0x8453, 0x4694,
+ 0x8457, 0x11f7,
+ 0x8458, 0x4698,
+ 0x8459, 0x1465,
+ 0x845a, 0x1464,
+ 0x845b, 0x06eb,
+ 0x845c, 0x1462,
+ 0x845d, 0x4699,
+ 0x8461, 0x0bee,
+ 0x8462, 0x469d,
+ 0x8463, 0x05ec,
+ 0x8464, 0x2347,
+ 0x8465, 0x469e,
+ 0x8466, 0x2193,
+ 0x8467, 0x469f,
+ 0x8469, 0x146e,
+ 0x846a, 0x46a1,
+ 0x846b, 0x07b0,
+ 0x846c, 0x1124,
+ 0x846d, 0x1473,
+ 0x846e, 0x46a2,
+ 0x846f, 0x26a1,
+ 0x8470, 0x46a3,
+ 0x8471, 0x0553,
+ 0x8472, 0x46a4,
+ 0x8473, 0x1466,
+ 0x8474, 0x46a5,
+ 0x8475, 0x0988,
+ 0x8476, 0x146f,
+ 0x8477, 0x1f62,
+ 0x8478, 0x146b,
+ 0x8479, 0x46a6,
+ 0x847a, 0x1469,
+ 0x847b, 0x46a7,
+ 0x8482, 0x05ba,
+ 0x8483, 0x46ae,
+ 0x8487, 0x1467,
+ 0x8489, 0x146a,
+ 0x848a, 0x46b2,
+ 0x848b, 0x0880,
+ 0x848c, 0x1470,
+ 0x848d, 0x46b3,
+ 0x848e, 0x1471,
+ 0x848f, 0x46b4,
+ 0x8493, 0x234d,
+ 0x8494, 0x2348,
+ 0x8495, 0x46b8,
+ 0x8497, 0x1481,
+ 0x8498, 0x46ba,
+ 0x8499, 0x0ace,
+ 0x849a, 0x46bb,
+ 0x849c, 0x0dd7,
+ 0x849d, 0x46bd,
+ 0x84a1, 0x147e,
+ 0x84a2, 0x46c1,
+ 0x84af, 0x1297,
+ 0x84b0, 0x46ce,
+ 0x84b2, 0x0bf0,
+ 0x84b3, 0x46d0,
+ 0x84b4, 0x1480,
+ 0x84b5, 0x46d1,
+ 0x84b8, 0x1195,
+ 0x84b9, 0x147f,
+ 0x84ba, 0x147c,
+ 0x84bb, 0x46d4,
+ 0x84bc, 0x1e60,
+ 0x84bd, 0x1478,
+ 0x84be, 0x46d5,
+ 0x84bf, 0x147b,
+ 0x84c0, 0x2345,
+ 0x84c1, 0x1474,
+ 0x84c2, 0x46d6,
+ 0x84c4, 0x0fb9,
+ 0x84c5, 0x46d8,
+ 0x84c9, 0x0cb3,
+ 0x84ca, 0x147a,
+ 0x84cb, 0x1f12,
+ 0x84cc, 0x46dc,
+ 0x84cd, 0x1475,
+ 0x84ce, 0x46dd,
+ 0x84d0, 0x1476,
+ 0x84d1, 0x0de7,
+ 0x84d2, 0x46df,
+ 0x84d3, 0x1479,
+ 0x84d4, 0x46e0,
+ 0x84d6, 0x0436,
+ 0x84d7, 0x46e2,
+ 0x84dd, 0x09a1,
+ 0x84de, 0x46e8,
+ 0x84df, 0x082e,
+ 0x84e0, 0x147d,
+ 0x84e1, 0x46e9,
+ 0x84e3, 0x1483,
+ 0x84e4, 0x46eb,
+ 0x84e5, 0x1482,
+ 0x84e6, 0x1477,
+ 0x84e7, 0x46ec,
+ 0x84ec, 0x0baf,
+ 0x84ed, 0x46f1,
+ 0x84ee, 0x2018,
+ 0x84ef, 0x2335,
+ 0x84f0, 0x1487,
+ 0x84f1, 0x46f2,
+ 0x84fc, 0x148e,
+ 0x84fd, 0x233c,
+ 0x84fe, 0x46fd,
+ 0x84ff, 0x148d,
+ 0x8500, 0x46fe,
+ 0x850c, 0x1484,
+ 0x850d, 0x470a,
+ 0x8511, 0x0af4,
+ 0x8512, 0x470e,
+ 0x8513, 0x0aa2,
+ 0x8514, 0x266f,
+ 0x8515, 0x470f,
+ 0x8517, 0x1182,
+ 0x8518, 0x4711,
+ 0x851a, 0x0ec4,
+ 0x851b, 0x4713,
+ 0x851e, 0x2351,
+ 0x851f, 0x1489,
+ 0x8520, 0x4716,
+ 0x8521, 0x0493,
+ 0x8522, 0x4717,
+ 0x8523, 0x1fa0,
+ 0x8524, 0x4718,
+ 0x8526, 0x2338,
+ 0x8527, 0x471a,
+ 0x852b, 0x0b4b,
+ 0x852c, 0x0d76,
+ 0x852d, 0x221b,
+ 0x852e, 0x471e,
+ 0x8537, 0x0c3b,
+ 0x8538, 0x1486,
+ 0x8539, 0x1488,
+ 0x853a, 0x148a,
+ 0x853b, 0x148c,
+ 0x853c, 0x03b5,
+ 0x853d, 0x0437,
+ 0x853e, 0x4727,
+ 0x8541, 0x2342,
+ 0x8542, 0x472a,
+ 0x8543, 0x1496,
+ 0x8544, 0x472b,
+ 0x8546, 0x234f,
+ 0x8547, 0x472d,
+ 0x8548, 0x1490,
+ 0x8549, 0x0887,
+ 0x854a, 0x0cca,
+ 0x854b, 0x472e,
+ 0x854e, 0x233d,
+ 0x854f, 0x4731,
+ 0x8552, 0x2344,
+ 0x8553, 0x2331,
+ 0x8554, 0x4734,
+ 0x8555, 0x234b,
+ 0x8556, 0x148b,
+ 0x8557, 0x4735,
+ 0x8558, 0x233b,
+ 0x8559, 0x148f,
+ 0x855a, 0x4736,
+ 0x855e, 0x1493,
+ 0x855f, 0x473a,
+ 0x8562, 0x2350,
+ 0x8563, 0x473d,
+ 0x8564, 0x1492,
+ 0x8565, 0x473e,
+ 0x8568, 0x1491,
+ 0x8569, 0x1eb4,
+ 0x856a, 0x21a6,
+ 0x856b, 0x4741,
+ 0x856d, 0x21cb,
+ 0x856e, 0x4743,
+ 0x8572, 0x1497,
+ 0x8573, 0x4747,
+ 0x8574, 0x110f,
+ 0x8575, 0x4748,
+ 0x8577, 0x2355,
+ 0x8578, 0x474a,
+ 0x8579, 0x149d,
+ 0x857a, 0x1494,
+ 0x857b, 0x1498,
+ 0x857c, 0x474b,
+ 0x857e, 0x09c4,
+ 0x857f, 0x474d,
+ 0x8584, 0x040a,
+ 0x8585, 0x14a0,
+ 0x8586, 0x4752,
+ 0x8587, 0x149b,
+ 0x8588, 0x233e,
+ 0x8589, 0x4753,
+ 0x858a, 0x1f74,
+ 0x858b, 0x4754,
+ 0x858c, 0x2330,
+ 0x858d, 0x4755,
+ 0x858f, 0x149c,
+ 0x8590, 0x4757,
+ 0x8591, 0x2680,
+ 0x8592, 0x4758,
+ 0x8594, 0x20da,
+ 0x8595, 0x475a,
+ 0x859b, 0x0fcf,
+ 0x859c, 0x149f,
+ 0x859d, 0x4760,
+ 0x859f, 0x234a,
+ 0x85a0, 0x4762,
+ 0x85a4, 0x1499,
+ 0x85a5, 0x4766,
+ 0x85a6, 0x1f91,
+ 0x85a7, 0x4767,
+ 0x85a8, 0x149a,
+ 0x85a9, 0x2107,
+ 0x85aa, 0x0f88,
+ 0x85ab, 0x4768,
+ 0x85ae, 0x149e,
+ 0x85af, 0x0d84,
+ 0x85b0, 0x14a3,
+ 0x85b1, 0x476b,
+ 0x85b7, 0x14a2,
+ 0x85b8, 0x4771,
+ 0x85b9, 0x14a1,
+ 0x85ba, 0x233f,
+ 0x85bb, 0x4772,
+ 0x85c1, 0x14a5,
+ 0x85c2, 0x4778,
+ 0x85c9, 0x08b6,
+ 0x85ca, 0x477f,
+ 0x85cd, 0x1ff4,
+ 0x85ce, 0x2343,
+ 0x85cf, 0x049f,
+ 0x85d0, 0x0aef,
+ 0x85d1, 0x4782,
+ 0x85d3, 0x14a4,
+ 0x85d4, 0x4784,
+ 0x85d5, 0x0b7b,
+ 0x85d6, 0x4785,
+ 0x85dc, 0x14a6,
+ 0x85dd, 0x2212,
+ 0x85de, 0x478b,
+ 0x85e4, 0x0e2c,
+ 0x85e5, 0x2207,
+ 0x85e6, 0x4791,
+ 0x85e9, 0x0647,
+ 0x85ea, 0x2359,
+ 0x85eb, 0x4794,
+ 0x85f4, 0x2254,
+ 0x85f5, 0x479d,
+ 0x85f6, 0x2332,
+ 0x85f7, 0x479e,
+ 0x85f9, 0x1e26,
+ 0x85fa, 0x2357,
+ 0x85fb, 0x1128,
+ 0x85fc, 0x47a0,
+ 0x85ff, 0x14a7,
+ 0x8600, 0x47a3,
+ 0x8604, 0x2358,
+ 0x8605, 0x14a9,
+ 0x8606, 0x2042,
+ 0x8607, 0x2153,
+ 0x8608, 0x47a7,
+ 0x860b, 0x20bb,
+ 0x860c, 0x47aa,
+ 0x8611, 0x0b05,
+ 0x8612, 0x47af,
+ 0x8616, 0x14ab,
+ 0x8617, 0x47b3,
+ 0x861a, 0x235a,
+ 0x861b, 0x47b6,
+ 0x861e, 0x2356,
+ 0x861f, 0x47b9,
+ 0x8622, 0x2337,
+ 0x8623, 0x47bc,
+ 0x8627, 0x14a8,
+ 0x8628, 0x47c0,
+ 0x8629, 0x14aa,
+ 0x862a, 0x47c1,
+ 0x862d, 0x1ff9,
+ 0x862e, 0x47c4,
+ 0x8638, 0x115b,
+ 0x8639, 0x47ce,
+ 0x863a, 0x2353,
+ 0x863b, 0x47cf,
+ 0x863c, 0x14ac,
+ 0x863d, 0x47d0,
+ 0x863f, 0x2061,
+ 0x8640, 0x47d2,
+ 0x864d, 0x1bf0,
+ 0x864e, 0x07b7,
+ 0x864f, 0x0a59,
+ 0x8650, 0x0b71,
+ 0x8651, 0x0a6e,
+ 0x8652, 0x47df,
+ 0x8654, 0x1bf1,
+ 0x8655, 0x1e95,
+ 0x8656, 0x47e1,
+ 0x865a, 0x0fb4,
+ 0x865b, 0x47e5,
+ 0x865c, 0x2049,
+ 0x865d, 0x47e6,
+ 0x865e, 0x10c2,
+ 0x865f, 0x1f42,
+ 0x8660, 0x47e7,
+ 0x8662, 0x196d,
+ 0x8663, 0x47e9,
+ 0x8667, 0x1fe8,
+ 0x8668, 0x47ed,
+ 0x866b, 0x050b,
+ 0x866c, 0x1bf2,
+ 0x866d, 0x47f0,
+ 0x866e, 0x1bf3,
+ 0x866f, 0x47f1,
+ 0x8671, 0x0d44,
+ 0x8672, 0x47f3,
+ 0x8679, 0x079e,
+ 0x867a, 0x1bf5,
+ 0x867b, 0x1bf7,
+ 0x867c, 0x1bf6,
+ 0x867d, 0x0dd9,
+ 0x867e, 0x0f27,
+ 0x867f, 0x1bf4,
+ 0x8680, 0x0d4b,
+ 0x8681, 0x1056,
+ 0x8682, 0x0a93,
+ 0x8683, 0x47fa,
+ 0x868a, 0x0ed2,
+ 0x868b, 0x1bfa,
+ 0x868c, 0x0401,
+ 0x868d, 0x1bf9,
+ 0x868e, 0x4801,
+ 0x8693, 0x1c00,
+ 0x8694, 0x4806,
+ 0x8695, 0x0496,
+ 0x8696, 0x4807,
+ 0x869c, 0x0fea,
+ 0x869d, 0x1bfc,
+ 0x869e, 0x480d,
+ 0x86a3, 0x1bfe,
+ 0x86a4, 0x112c,
+ 0x86a5, 0x4812,
+ 0x86a7, 0x1bfd,
+ 0x86a8, 0x1bf8,
+ 0x86a9, 0x1c01,
+ 0x86aa, 0x1bff,
+ 0x86ab, 0x4814,
+ 0x86ac, 0x1bfb,
+ 0x86ad, 0x4815,
+ 0x86af, 0x1c09,
+ 0x86b0, 0x1c06,
+ 0x86b1, 0x1c08,
+ 0x86b2, 0x4817,
+ 0x86b4, 0x1c0c,
+ 0x86b5, 0x1c04,
+ 0x86b6, 0x1c02,
+ 0x86b7, 0x4819,
+ 0x86ba, 0x1c07,
+ 0x86bb, 0x481c,
+ 0x86c0, 0x11fa,
+ 0x86c1, 0x4821,
+ 0x86c4, 0x1c03,
+ 0x86c5, 0x4824,
+ 0x86c6, 0x0c76,
+ 0x86c7, 0x0d18,
+ 0x86c8, 0x4825,
+ 0x86c9, 0x1c0a,
+ 0x86ca, 0x071f,
+ 0x86cb, 0x0591,
+ 0x86cc, 0x4826,
+ 0x86ce, 0x1c05,
+ 0x86cf, 0x1c0b,
+ 0x86d0, 0x1c12,
+ 0x86d1, 0x1c18,
+ 0x86d2, 0x4828,
+ 0x86d4, 0x07ec,
+ 0x86d5, 0x482a,
+ 0x86d8, 0x1c17,
+ 0x86d9, 0x0e8d,
+ 0x86da, 0x482d,
+ 0x86db, 0x11ea,
+ 0x86dc, 0x482e,
+ 0x86de, 0x1c14,
+ 0x86df, 0x1c16,
+ 0x86e0, 0x4830,
+ 0x86e4, 0x06ed,
+ 0x86e5, 0x4834,
+ 0x86e9, 0x1c0d,
+ 0x86ea, 0x4838,
+ 0x86ed, 0x1c10,
+ 0x86ee, 0x0aa0,
+ 0x86ef, 0x483b,
+ 0x86f0, 0x117e,
+ 0x86f1, 0x1c0e,
+ 0x86f3, 0x1c11,
+ 0x86f4, 0x1c15,
+ 0x86f5, 0x483c,
+ 0x86f8, 0x1c1b,
+ 0x86f9, 0x10a1,
+ 0x86fa, 0x25da,
+ 0x86fb, 0x483f,
+ 0x86fe, 0x0629,
+ 0x86ff, 0x4842,
+ 0x8700, 0x0d88,
+ 0x8701, 0x4843,
+ 0x8702, 0x0681,
+ 0x8703, 0x1c19,
+ 0x8704, 0x4844,
+ 0x8706, 0x25d7,
+ 0x8707, 0x1c1a,
+ 0x8708, 0x1c1c,
+ 0x8709, 0x1c1f,
+ 0x870a, 0x1c1d,
+ 0x870b, 0x4846,
+ 0x870d, 0x1c1e,
+ 0x870e, 0x4848,
+ 0x8712, 0x0ffa,
+ 0x8713, 0x1c13,
+ 0x8714, 0x484c,
+ 0x8715, 0x0e7a,
+ 0x8716, 0x484d,
+ 0x8717, 0x0ede,
+ 0x8718, 0x11a8,
+ 0x8719, 0x484e,
+ 0x871a, 0x1c25,
+ 0x871b, 0x484f,
+ 0x871c, 0x0ae0,
+ 0x871d, 0x4850,
+ 0x871e, 0x1c22,
+ 0x871f, 0x4851,
+ 0x8721, 0x099a,
+ 0x8722, 0x1c2e,
+ 0x8723, 0x1c20,
+ 0x8724, 0x4853,
+ 0x8725, 0x1c23,
+ 0x8726, 0x4854,
+ 0x8729, 0x1c2a,
+ 0x872a, 0x4857,
+ 0x872e, 0x1c24,
+ 0x872f, 0x485b,
+ 0x8731, 0x1c29,
+ 0x8732, 0x485d,
+ 0x8734, 0x1c28,
+ 0x8735, 0x485f,
+ 0x8737, 0x1c2b,
+ 0x8738, 0x4861,
+ 0x873b, 0x1c21,
+ 0x873c, 0x4864,
+ 0x873e, 0x1c26,
+ 0x873f, 0x1c2c,
+ 0x8740, 0x4866,
+ 0x8747, 0x1091,
+ 0x8748, 0x1c27,
+ 0x8749, 0x04bc,
+ 0x874a, 0x486d,
+ 0x874c, 0x1c34,
+ 0x874d, 0x486f,
+ 0x874e, 0x0f76,
+ 0x874f, 0x4870,
+ 0x8753, 0x1c37,
+ 0x8754, 0x4874,
+ 0x8755, 0x212e,
+ 0x8756, 0x4875,
+ 0x8757, 0x07dd,
+ 0x8758, 0x4876,
+ 0x8759, 0x1c3b,
+ 0x875a, 0x4877,
+ 0x8760, 0x1c32,
+ 0x8761, 0x487d,
+ 0x8763, 0x1c38,
+ 0x8764, 0x1c3a,
+ 0x8765, 0x1c3c,
+ 0x8766, 0x21b2,
+ 0x8767, 0x487f,
+ 0x876e, 0x1c35,
+ 0x876f, 0x4886,
+ 0x8770, 0x1c33,
+ 0x8771, 0x4887,
+ 0x8774, 0x07b2,
+ 0x8775, 0x488a,
+ 0x8776, 0x05dc,
+ 0x8777, 0x488b,
+ 0x8778, 0x219e,
+ 0x8779, 0x488c,
+ 0x877b, 0x1c31,
+ 0x877c, 0x1c39,
+ 0x877d, 0x1c2f,
+ 0x877f, 0x488e,
+ 0x8782, 0x1c2d,
+ 0x8783, 0x1c46,
+ 0x8784, 0x25dc,
+ 0x8785, 0x1c43,
+ 0x8786, 0x4891,
+ 0x8788, 0x1c42,
+ 0x8789, 0x4893,
+ 0x878b, 0x1c36,
+ 0x878c, 0x4895,
+ 0x878d, 0x0cb5,
+ 0x878e, 0x4896,
+ 0x8793, 0x1c3d,
+ 0x8794, 0x489b,
+ 0x8797, 0x1c45,
+ 0x8798, 0x489e,
+ 0x879e, 0x206c,
+ 0x879f, 0x0afd,
+ 0x87a0, 0x48a4,
+ 0x87a2, 0x2226,
+ 0x87a3, 0x48a6,
+ 0x87a8, 0x1c3f,
+ 0x87a9, 0x48ab,
+ 0x87ab, 0x1c47,
+ 0x87ac, 0x1c49,
+ 0x87ad, 0x1c44,
+ 0x87ae, 0x48ad,
+ 0x87af, 0x1c3e,
+ 0x87b0, 0x48ae,
+ 0x87b3, 0x1c4b,
+ 0x87b4, 0x48b1,
+ 0x87b5, 0x1c4a,
+ 0x87b6, 0x48b2,
+ 0x87ba, 0x0a84,
+ 0x87bb, 0x25e0,
+ 0x87bc, 0x48b6,
+ 0x87bd, 0x1c4e,
+ 0x87be, 0x48b7,
+ 0x87c0, 0x1c50,
+ 0x87c1, 0x48b9,
+ 0x87c4, 0x227b,
+ 0x87c5, 0x48bc,
+ 0x87c6, 0x1c41,
+ 0x87c7, 0x48bd,
+ 0x87c8, 0x25de,
+ 0x87c9, 0x48be,
+ 0x87ca, 0x1c51,
+ 0x87cb, 0x1c4c,
+ 0x87cc, 0x48bf,
+ 0x87ce, 0x25e1,
+ 0x87cf, 0x48c1,
+ 0x87d1, 0x1c4f,
+ 0x87d2, 0x1c40,
+ 0x87d3, 0x1c4d,
+ 0x87d4, 0x48c3,
+ 0x87db, 0x1c52,
+ 0x87dc, 0x48ca,
+ 0x87e0, 0x1c54,
+ 0x87e1, 0x48ce,
+ 0x87e3, 0x25d5,
+ 0x87e4, 0x48d0,
+ 0x87e5, 0x1c48,
+ 0x87e6, 0x48d1,
+ 0x87ea, 0x1c53,
+ 0x87eb, 0x48d5,
+ 0x87ec, 0x1e6b,
+ 0x87ed, 0x48d6,
+ 0x87ee, 0x1c55,
+ 0x87ef, 0x25db,
+ 0x87f0, 0x48d7,
+ 0x87f2, 0x1e89,
+ 0x87f3, 0x48d9,
+ 0x87f6, 0x25d9,
+ 0x87f7, 0x48dc,
+ 0x87f9, 0x0f82,
+ 0x87fa, 0x48de,
+ 0x87fb, 0x2211,
+ 0x87fc, 0x48df,
+ 0x87fe, 0x1c58,
+ 0x87ff, 0x48e1,
+ 0x8800, 0x48e2,
+ 0x8803, 0x130d,
+ 0x8804, 0x48e5,
+ 0x8805, 0x2229,
+ 0x8806, 0x25d6,
+ 0x8807, 0x48e6,
+ 0x880a, 0x1c59,
+ 0x880b, 0x48e9,
+ 0x8810, 0x25dd,
+ 0x8811, 0x25df,
+ 0x8812, 0x48ee,
+ 0x8813, 0x1c57,
+ 0x8814, 0x48ef,
+ 0x8815, 0x0cbf,
+ 0x8816, 0x1c56,
+ 0x8817, 0x48f0,
+ 0x881b, 0x1c5a,
+ 0x881c, 0x48f4,
+ 0x881f, 0x1fef,
+ 0x8820, 0x48f7,
+ 0x8821, 0x1c5b,
+ 0x8822, 0x0543,
+ 0x8823, 0x25d8,
+ 0x8824, 0x48f8,
+ 0x8831, 0x1f29,
+ 0x8832, 0x1a8d,
+ 0x8833, 0x4905,
+ 0x8836, 0x1e5b,
+ 0x8837, 0x4908,
+ 0x8839, 0x1c5c,
+ 0x883a, 0x490a,
+ 0x883b, 0x2076,
+ 0x883c, 0x1c5d,
+ 0x883d, 0x490b,
+ 0x8840, 0x0fd3,
+ 0x8841, 0x490e,
+ 0x8844, 0x1caa,
+ 0x8845, 0x0f91,
+ 0x8846, 0x2297,
+ 0x8847, 0x4911,
+ 0x884a, 0x2690,
+ 0x884b, 0x4914,
+ 0x884c, 0x0f9b,
+ 0x884d, 0x1005,
+ 0x884e, 0x4915,
+ 0x8853, 0x213f,
+ 0x8854, 0x0f3b,
+ 0x8855, 0x491a,
+ 0x8857, 0x08a7,
+ 0x8858, 0x491c,
+ 0x8859, 0x0fec,
+ 0x885a, 0x491d,
+ 0x885b, 0x2198,
+ 0x885c, 0x491e,
+ 0x885d, 0x1e88,
+ 0x885e, 0x491f,
+ 0x8861, 0x0799,
+ 0x8862, 0x15ed,
+ 0x8863, 0x1049,
+ 0x8864, 0x1ba6,
+ 0x8865, 0x0480,
+ 0x8866, 0x4922,
+ 0x8868, 0x0456,
+ 0x8869, 0x1ba7,
+ 0x886a, 0x4924,
+ 0x886b, 0x0cf9,
+ 0x886c, 0x04e9,
+ 0x886d, 0x4925,
+ 0x886e, 0x1306,
+ 0x886f, 0x4926,
+ 0x8870, 0x0d9a,
+ 0x8871, 0x4927,
+ 0x8872, 0x1ba8,
+ 0x8873, 0x4928,
+ 0x8877, 0x11d3,
+ 0x8878, 0x492c,
+ 0x8879, 0x228c,
+ 0x887a, 0x492d,
+ 0x887d, 0x1ba9,
+ 0x887e, 0x1cbe,
+ 0x887f, 0x1baa,
+ 0x8880, 0x4930,
+ 0x8881, 0x10ef,
+ 0x8882, 0x1bab,
+ 0x8883, 0x4931,
+ 0x8884, 0x03cb,
+ 0x8885, 0x1cbf,
+ 0x8886, 0x4932,
+ 0x8888, 0x1cc0,
+ 0x8889, 0x4934,
+ 0x888b, 0x057f,
+ 0x888c, 0x4936,
+ 0x888d, 0x0b9c,
+ 0x888e, 0x4937,
+ 0x8892, 0x0e0e,
+ 0x8893, 0x493b,
+ 0x8896, 0x0faf,
+ 0x8897, 0x493e,
+ 0x889c, 0x0e91,
+ 0x889d, 0x4943,
+ 0x88a2, 0x1bac,
+ 0x88a3, 0x4948,
+ 0x88a4, 0x1307,
+ 0x88a5, 0x4949,
+ 0x88ab, 0x0424,
+ 0x88ac, 0x494f,
+ 0x88ad, 0x0f1b,
+ 0x88ae, 0x4950,
+ 0x88b1, 0x069f,
+ 0x88b2, 0x4953,
+ 0x88b7, 0x1bae,
+ 0x88b8, 0x4958,
+ 0x88bc, 0x1baf,
+ 0x88bd, 0x495c,
+ 0x88c1, 0x048a,
+ 0x88c2, 0x0a1a,
+ 0x88c3, 0x4960,
+ 0x88c5, 0x120d,
+ 0x88c6, 0x1bad,
+ 0x88c7, 0x4962,
+ 0x88c9, 0x1bb0,
+ 0x88ca, 0x25f1,
+ 0x88cb, 0x4964,
+ 0x88ce, 0x1bb2,
+ 0x88cf, 0x200c,
+ 0x88d0, 0x4967,
+ 0x88d2, 0x130a,
+ 0x88d3, 0x4969,
+ 0x88d4, 0x1068,
+ 0x88d5, 0x10e6,
+ 0x88d6, 0x496a,
+ 0x88d8, 0x1cc1,
+ 0x88d9, 0x0c94,
+ 0x88da, 0x496c,
+ 0x88dc, 0x1e58,
+ 0x88dd, 0x22ac,
+ 0x88de, 0x496e,
+ 0x88df, 0x1cc2,
+ 0x88e0, 0x496f,
+ 0x88e2, 0x1bb1,
+ 0x88e3, 0x1bb3,
+ 0x88e4, 0x0970,
+ 0x88e5, 0x1bb4,
+ 0x88e6, 0x4971,
+ 0x88e8, 0x1bb8,
+ 0x88e9, 0x4973,
+ 0x88f0, 0x1bba,
+ 0x88f1, 0x1bb5,
+ 0x88f2, 0x497a,
+ 0x88f3, 0x0d0a,
+ 0x88f4, 0x0ba2,
+ 0x88f5, 0x497b,
+ 0x88f8, 0x0a8a,
+ 0x88f9, 0x0755,
+ 0x88fa, 0x497e,
+ 0x88fc, 0x1bb7,
+ 0x88fd, 0x26a7,
+ 0x88fe, 0x1bb9,
+ 0x88ff, 0x4980,
+ 0x8900, 0x4981,
+ 0x8902, 0x072c,
+ 0x8903, 0x4983,
+ 0x8907, 0x2676,
+ 0x8908, 0x4987,
+ 0x890a, 0x1bbf,
+ 0x890b, 0x4989,
+ 0x8910, 0x078d,
+ 0x8911, 0x498e,
+ 0x8912, 0x0408,
+ 0x8913, 0x1bbd,
+ 0x8914, 0x498f,
+ 0x8919, 0x1bbc,
+ 0x891a, 0x1bb6,
+ 0x891b, 0x1bbe,
+ 0x891c, 0x4994,
+ 0x8921, 0x1bbb,
+ 0x8922, 0x4999,
+ 0x8925, 0x0cc7,
+ 0x8926, 0x499c,
+ 0x892a, 0x0e7b,
+ 0x892b, 0x1bc1,
+ 0x892c, 0x49a0,
+ 0x8930, 0x1739,
+ 0x8931, 0x49a4,
+ 0x8932, 0x1fe1,
+ 0x8933, 0x25bb,
+ 0x8934, 0x1bc0,
+ 0x8935, 0x49a5,
+ 0x8936, 0x1bc2,
+ 0x8937, 0x49a6,
+ 0x8938, 0x25be,
+ 0x8939, 0x49a7,
+ 0x893b, 0x22dd,
+ 0x893c, 0x49a9,
+ 0x8941, 0x1bc3,
+ 0x8942, 0x49ae,
+ 0x8944, 0x0f52,
+ 0x8945, 0x49b0,
+ 0x8947, 0x25bd,
+ 0x8948, 0x49b2,
+ 0x8956, 0x1e2a,
+ 0x8957, 0x49c0,
+ 0x895d, 0x25bc,
+ 0x895e, 0x1cc3,
+ 0x895f, 0x08c4,
+ 0x8960, 0x25ba,
+ 0x8961, 0x49c6,
+ 0x8964, 0x25bf,
+ 0x8965, 0x49c9,
+ 0x8966, 0x1bc4,
+ 0x8967, 0x49ca,
+ 0x896a, 0x2187,
+ 0x896b, 0x49cd,
+ 0x896c, 0x266b,
+ 0x896d, 0x49ce,
+ 0x896f, 0x1e7f,
+ 0x8970, 0x49d0,
+ 0x8972, 0x21ad,
+ 0x8973, 0x49d2,
+ 0x897b, 0x1bc5,
+ 0x897c, 0x49da,
+ 0x897f, 0x0f06,
+ 0x8980, 0x49dd,
+ 0x8981, 0x1031,
+ 0x8982, 0x49de,
+ 0x8983, 0x1bdf,
+ 0x8984, 0x49df,
+ 0x8986, 0x06ad,
+ 0x8987, 0x49e1,
+ 0x898b, 0x1f96,
+ 0x898c, 0x49e5,
+ 0x898f, 0x1f32,
+ 0x8990, 0x49e8,
+ 0x8993, 0x2084,
+ 0x8994, 0x49eb,
+ 0x8996, 0x2136,
+ 0x8997, 0x49ed,
+ 0x8998, 0x24b8,
+ 0x8999, 0x49ee,
+ 0x89a1, 0x24ba,
+ 0x89a2, 0x49f6,
+ 0x89a6, 0x24bc,
+ 0x89a7, 0x49fa,
+ 0x89aa, 0x20e4,
+ 0x89ab, 0x49fd,
+ 0x89ac, 0x24b9,
+ 0x89ad, 0x49fe,
+ 0x89af, 0x24bd,
+ 0x89b0, 0x4a00,
+ 0x89b2, 0x24be,
+ 0x89b3, 0x4a02,
+ 0x89b7, 0x24bf,
+ 0x89b8, 0x4a06,
+ 0x89ba, 0x1fd2,
+ 0x89bb, 0x4a08,
+ 0x89bd, 0x1ffd,
+ 0x89be, 0x4a0a,
+ 0x89bf, 0x24bb,
+ 0x89c0, 0x1f2d,
+ 0x89c1, 0x086e,
+ 0x89c2, 0x0734,
+ 0x89c3, 0x4a0b,
+ 0x89c4, 0x073f,
+ 0x89c5, 0x0ade,
+ 0x89c6, 0x0d6a,
+ 0x89c7, 0x193a,
+ 0x89c8, 0x09ab,
+ 0x89c9, 0x0924,
+ 0x89ca, 0x193b,
+ 0x89cd, 0x4a0c,
+ 0x89ce, 0x193e,
+ 0x89d2, 0x0898,
+ 0x89d3, 0x4a0d,
+ 0x89d6, 0x1d57,
+ 0x89d7, 0x4a10,
+ 0x89da, 0x1d59,
+ 0x89db, 0x4a13,
+ 0x89dc, 0x1d5a,
+ 0x89dd, 0x4a14,
+ 0x89de, 0x1d58,
+ 0x89df, 0x4a15,
+ 0x89e3, 0x08b3,
+ 0x89e4, 0x4a19,
+ 0x89e5, 0x1d5b,
+ 0x89e6, 0x0528,
+ 0x89e7, 0x4a1a,
+ 0x89eb, 0x1d5c,
+ 0x89ec, 0x4a1e,
+ 0x89ef, 0x1d5d,
+ 0x89f0, 0x4a21,
+ 0x89f3, 0x19c0,
+ 0x89f4, 0x2609,
+ 0x89f5, 0x4a24,
+ 0x89f6, 0x260a,
+ 0x89f7, 0x4a25,
+ 0x89f8, 0x1e94,
+ 0x89f9, 0x4a26,
+ 0x8a00, 0x0ffd,
+ 0x8a01, 0x22df,
+ 0x8a02, 0x1ecb,
+ 0x8a03, 0x1f0d,
+ 0x8a04, 0x4a2d,
+ 0x8a07, 0x12fe,
+ 0x8a08, 0x1f77,
+ 0x8a09, 0x4a30,
+ 0x8a0a, 0x21eb,
+ 0x8a0b, 0x4a31,
+ 0x8a0c, 0x22e1,
+ 0x8a0d, 0x4a32,
+ 0x8a0e, 0x216f,
+ 0x8a0f, 0x4a33,
+ 0x8a10, 0x22e0,
+ 0x8a11, 0x4a34,
+ 0x8a13, 0x21ea,
+ 0x8a14, 0x4a36,
+ 0x8a15, 0x22e2,
+ 0x8a16, 0x20cb,
+ 0x8a17, 0x4a37,
+ 0x8a18, 0x1f78,
+ 0x8a19, 0x4a38,
+ 0x8a1b, 0x1ee2,
+ 0x8a1c, 0x4a3a,
+ 0x8a1d, 0x21f2,
+ 0x8a1e, 0x4a3b,
+ 0x8a1f, 0x2150,
+ 0x8a20, 0x4a3c,
+ 0x8a23, 0x1fd3,
+ 0x8a24, 0x4a3f,
+ 0x8a25, 0x22e5,
+ 0x8a26, 0x4a40,
+ 0x8a2a, 0x1ef2,
+ 0x8a2b, 0x4a44,
+ 0x8a2d, 0x211f,
+ 0x8a2e, 0x4a46,
+ 0x8a31, 0x21dd,
+ 0x8a32, 0x4a49,
+ 0x8a34, 0x2154,
+ 0x8a35, 0x4a4b,
+ 0x8a36, 0x22e7,
+ 0x8a37, 0x4a4c,
+ 0x8a3a, 0x2282,
+ 0x8a3b, 0x4a4f,
+ 0x8a3e, 0x1d5e,
+ 0x8a3f, 0x4a52,
+ 0x8a41, 0x22e6,
+ 0x8a42, 0x4a54,
+ 0x8a46, 0x22e8,
+ 0x8a47, 0x4a58,
+ 0x8a48, 0x1a84,
+ 0x8a49, 0x4a59,
+ 0x8a4e, 0x22e4,
+ 0x8a4f, 0x4a5e,
+ 0x8a50, 0x226a,
+ 0x8a51, 0x4a5f,
+ 0x8a52, 0x22eb,
+ 0x8a53, 0x4a60,
+ 0x8a54, 0x22e9,
+ 0x8a55, 0x20bd,
+ 0x8a56, 0x4a61,
+ 0x8a58, 0x22ea,
+ 0x8a59, 0x4a63,
+ 0x8a5b, 0x22bd,
+ 0x8a5c, 0x4a65,
+ 0x8a5e, 0x1e9e,
+ 0x8a5f, 0x4a67,
+ 0x8a61, 0x22f6,
+ 0x8a62, 0x21e7,
+ 0x8a63, 0x2216,
+ 0x8a64, 0x4a69,
+ 0x8a66, 0x2137,
+ 0x8a67, 0x4a6b,
+ 0x8a69, 0x212c,
+ 0x8a6a, 0x4a6d,
+ 0x8a6b, 0x1e68,
+ 0x8a6c, 0x22f2,
+ 0x8a6d, 0x1f37,
+ 0x8a6e, 0x22f3,
+ 0x8a6f, 0x4a6e,
+ 0x8a70, 0x22ef,
+ 0x8a71, 0x1f50,
+ 0x8a72, 0x1f10,
+ 0x8a73, 0x21c8,
+ 0x8a74, 0x4a6f,
+ 0x8a75, 0x22f1,
+ 0x8a76, 0x4a70,
+ 0x8a79, 0x1153,
+ 0x8a7a, 0x4a73,
+ 0x8a7c, 0x22f0,
+ 0x8a7d, 0x4a75,
+ 0x8a7f, 0x22ee,
+ 0x8a80, 0x4a77,
+ 0x8a84, 0x22ed,
+ 0x8a85, 0x229e,
+ 0x8a86, 0x22ec,
+ 0x8a87, 0x1fe2,
+ 0x8a88, 0x4a7b,
+ 0x8a89, 0x10e3,
+ 0x8a8a, 0x0e2f,
+ 0x8a8b, 0x4a7c,
+ 0x8a8d, 0x20fe,
+ 0x8a8e, 0x4a7e,
+ 0x8a91, 0x22f9,
+ 0x8a93, 0x0d5b,
+ 0x8a94, 0x4a81,
+ 0x8a95, 0x1eaf,
+ 0x8a96, 0x4a82,
+ 0x8a98, 0x2236,
+ 0x8a99, 0x4a84,
+ 0x8a9a, 0x22f7,
+ 0x8a9b, 0x4a85,
+ 0x8a9e, 0x223d,
+ 0x8a9f, 0x4a88,
+ 0x8aa0, 0x1e82,
+ 0x8aa1, 0x1fb6,
+ 0x8aa2, 0x4a89,
+ 0x8aa3, 0x21a4,
+ 0x8aa4, 0x21aa,
+ 0x8aa5, 0x22f8,
+ 0x8aa6, 0x2151,
+ 0x8aa7, 0x4a8a,
+ 0x8aa8, 0x1f60,
+ 0x8aa9, 0x4a8b,
+ 0x8aac, 0x2147,
+ 0x8aad, 0x4a8e,
+ 0x8ab0, 0x2145,
+ 0x8ab1, 0x4a91,
+ 0x8ab2, 0x1fdc,
+ 0x8ab3, 0x4a92,
+ 0x8ab6, 0x2301,
+ 0x8ab7, 0x4a95,
+ 0x8ab9, 0x1ef5,
+ 0x8aba, 0x4a97,
+ 0x8abc, 0x2218,
+ 0x8abd, 0x4a99,
+ 0x8abf, 0x1ec6,
+ 0x8ac0, 0x4a9b,
+ 0x8ac2, 0x2300,
+ 0x8ac3, 0x4a9d,
+ 0x8ac4, 0x22b4,
+ 0x8ac5, 0x4a9e,
+ 0x8ac7, 0x2169,
+ 0x8ac8, 0x4aa0,
+ 0x8ac9, 0x22fd,
+ 0x8aca, 0x4aa1,
+ 0x8acb, 0x20ea,
+ 0x8acc, 0x4aa2,
+ 0x8acd, 0x22f4,
+ 0x8ace, 0x4aa3,
+ 0x8acf, 0x22fb,
+ 0x8ad0, 0x4aa4,
+ 0x8ad1, 0x22fc,
+ 0x8ad2, 0x2027,
+ 0x8ad3, 0x4aa5,
+ 0x8ad6, 0x2060,
+ 0x8ad7, 0x22ff,
+ 0x8ad8, 0x4aa8,
+ 0x8adb, 0x22fe,
+ 0x8adc, 0x1ec7,
+ 0x8add, 0x4aab,
+ 0x8ade, 0x230c,
+ 0x8adf, 0x4aac,
+ 0x8ae2, 0x22f5,
+ 0x8ae3, 0x4aaf,
+ 0x8ae4, 0x2306,
+ 0x8ae5, 0x4ab0,
+ 0x8ae6, 0x230a,
+ 0x8ae7, 0x21d3,
+ 0x8ae8, 0x4ab1,
+ 0x8aeb, 0x2303,
+ 0x8aec, 0x4ab4,
+ 0x8aed, 0x2307,
+ 0x8aee, 0x230b,
+ 0x8aef, 0x4ab5,
+ 0x8af1, 0x1f5f,
+ 0x8af2, 0x4ab7,
+ 0x8af3, 0x2309,
+ 0x8af4, 0x4ab8,
+ 0x8af6, 0x2302,
+ 0x8af7, 0x1f04,
+ 0x8af8, 0x229d,
+ 0x8af9, 0x4aba,
+ 0x8afa, 0x21fb,
+ 0x8afb, 0x4abb,
+ 0x8afc, 0x2308,
+ 0x8afd, 0x4abc,
+ 0x8afe, 0x20ac,
+ 0x8aff, 0x4abd,
+ 0x8b00, 0x208e,
+ 0x8b01, 0x2305,
+ 0x8b02, 0x2197,
+ 0x8b03, 0x4abe,
+ 0x8b04, 0x2171,
+ 0x8b05, 0x2298,
+ 0x8b06, 0x4abf,
+ 0x8b07, 0x173c,
+ 0x8b08, 0x4ac0,
+ 0x8b0a, 0x1f57,
+ 0x8b0b, 0x4ac2,
+ 0x8b0e, 0x2082,
+ 0x8b0f, 0x4ac5,
+ 0x8b10, 0x2311,
+ 0x8b11, 0x4ac6,
+ 0x8b14, 0x2304,
+ 0x8b15, 0x4ac9,
+ 0x8b16, 0x230f,
+ 0x8b17, 0x1e35,
+ 0x8b18, 0x4aca,
+ 0x8b19, 0x20d1,
+ 0x8b1a, 0x2310,
+ 0x8b1b, 0x1fa3,
+ 0x8b1c, 0x4acb,
+ 0x8b1d, 0x21d6,
+ 0x8b1e, 0x4acc,
+ 0x8b21, 0x2206,
+ 0x8b22, 0x4acf,
+ 0x8b26, 0x1d5f,
+ 0x8b27, 0x4ad3,
+ 0x8b28, 0x230d,
+ 0x8b29, 0x4ad4,
+ 0x8b2b, 0x2312,
+ 0x8b2c, 0x208d,
+ 0x8b2d, 0x2313,
+ 0x8b2e, 0x4ad6,
+ 0x8b33, 0x22e3,
+ 0x8b34, 0x4adb,
+ 0x8b39, 0x1fba,
+ 0x8b3a, 0x4ae0,
+ 0x8b3e, 0x2078,
+ 0x8b3f, 0x4ae4,
+ 0x8b49, 0x2288,
+ 0x8b4a, 0x4aee,
+ 0x8b4e, 0x2316,
+ 0x8b4f, 0x1f6b,
+ 0x8b50, 0x4af2,
+ 0x8b56, 0x2314,
+ 0x8b57, 0x4af8,
+ 0x8b58, 0x2130,
+ 0x8b59, 0x2315,
+ 0x8b5a, 0x2168,
+ 0x8b5b, 0x4af9,
+ 0x8b5c, 0x20c4,
+ 0x8b5d, 0x4afa,
+ 0x8b66, 0x08de,
+ 0x8b67, 0x4b03,
+ 0x8b6b, 0x2318,
+ 0x8b6c, 0x0bc8,
+ 0x8b6d, 0x4b07,
+ 0x8b6f, 0x2219,
+ 0x8b70, 0x2217,
+ 0x8b71, 0x4b09,
+ 0x8b74, 0x20d5,
+ 0x8b75, 0x4b0c,
+ 0x8b77, 0x1f4a,
+ 0x8b78, 0x4b0e,
+ 0x8b7d, 0x2240,
+ 0x8b7e, 0x4b13,
+ 0x8b80, 0x1ed3,
+ 0x8b81, 0x4b15,
+ 0x8b8a, 0x1e49,
+ 0x8b8b, 0x4b1e,
+ 0x8b8e, 0x261b,
+ 0x8b8f, 0x4b21,
+ 0x8b92, 0x1e6d,
+ 0x8b93, 0x20f8,
+ 0x8b94, 0x4b24,
+ 0x8b95, 0x1ffb,
+ 0x8b96, 0x2319,
+ 0x8b97, 0x4b25,
+ 0x8b9c, 0x230e,
+ 0x8b9d, 0x4b2a,
+ 0x8b9e, 0x2317,
+ 0x8b9f, 0x4b2b,
+ 0x8ba0, 0x1317,
+ 0x8ba1, 0x0839,
+ 0x8ba2, 0x05e8,
+ 0x8ba3, 0x06b7,
+ 0x8ba4, 0x0caa,
+ 0x8ba5, 0x0818,
+ 0x8ba6, 0x1318,
+ 0x8ba8, 0x0e29,
+ 0x8ba9, 0x0c9e,
+ 0x8baa, 0x131a,
+ 0x8bab, 0x0c1c,
+ 0x8bac, 0x4b2c,
+ 0x8bad, 0x0fde,
+ 0x8bae, 0x1070,
+ 0x8baf, 0x0fdf,
+ 0x8bb0, 0x083a,
+ 0x8bb1, 0x4b2d,
+ 0x8bb2, 0x0883,
+ 0x8bb3, 0x07f9,
+ 0x8bb4, 0x131b,
+ 0x8bb6, 0x0ff1,
+ 0x8bb7, 0x131d,
+ 0x8bb8, 0x0fb8,
+ 0x8bb9, 0x062e,
+ 0x8bba, 0x0a82,
+ 0x8bbb, 0x4b2e,
+ 0x8bbc, 0x0dc4,
+ 0x8bbd, 0x068a,
+ 0x8bbe, 0x0d21,
+ 0x8bbf, 0x0660,
+ 0x8bc0, 0x0926,
+ 0x8bc1, 0x11a3,
+ 0x8bc2, 0x131e,
+ 0x8bc4, 0x0bdf,
+ 0x8bc5, 0x1244,
+ 0x8bc6, 0x0d4d,
+ 0x8bc7, 0x4b2f,
+ 0x8bc8, 0x114a,
+ 0x8bc9, 0x0dd4,
+ 0x8bca, 0x1190,
+ 0x8bcb, 0x1320,
+ 0x8bcc, 0x11de,
+ 0x8bcd, 0x054d,
+ 0x8bce, 0x1322,
+ 0x8bcf, 0x1321,
+ 0x8bd0, 0x4b30,
+ 0x8bd1, 0x1072,
+ 0x8bd2, 0x1323,
+ 0x8bd5, 0x0d6b,
+ 0x8bd6, 0x1326,
+ 0x8bd7, 0x0d42,
+ 0x8bd8, 0x1327,
+ 0x8bda, 0x04f4,
+ 0x8bdb, 0x11ee,
+ 0x8bdc, 0x1329,
+ 0x8bdd, 0x07c5,
+ 0x8bde, 0x058f,
+ 0x8bdf, 0x132a,
+ 0x8be1, 0x0747,
+ 0x8be2, 0x0fd8,
+ 0x8be3, 0x106f,
+ 0x8be4, 0x132c,
+ 0x8be5, 0x06be,
+ 0x8be6, 0x0f57,
+ 0x8be7, 0x04b6,
+ 0x8be8, 0x132d,
+ 0x8bea, 0x4b31,
+ 0x8beb, 0x08bc,
+ 0x8bec, 0x0eeb,
+ 0x8bed, 0x10d4,
+ 0x8bee, 0x132f,
+ 0x8bef, 0x0f02,
+ 0x8bf0, 0x1330,
+ 0x8bf1, 0x10ba,
+ 0x8bf2, 0x07fa,
+ 0x8bf3, 0x1331,
+ 0x8bf4, 0x0daa,
+ 0x8bf5, 0x0dc5,
+ 0x8bf6, 0x1332,
+ 0x8bf7, 0x0c68,
+ 0x8bf8, 0x11ed,
+ 0x8bf9, 0x1333,
+ 0x8bfa, 0x0b76,
+ 0x8bfb, 0x0600,
+ 0x8bfc, 0x1334,
+ 0x8bfd, 0x0669,
+ 0x8bfe, 0x095b,
+ 0x8bff, 0x1335,
+ 0x8c00, 0x1336,
+ 0x8c01, 0x0da2,
+ 0x8c02, 0x1337,
+ 0x8c03, 0x05d8,
+ 0x8c04, 0x1338,
+ 0x8c05, 0x0a0b,
+ 0x8c06, 0x1218,
+ 0x8c07, 0x1339,
+ 0x8c08, 0x0e0b,
+ 0x8c09, 0x4b32,
+ 0x8c0a, 0x1071,
+ 0x8c0b, 0x0b14,
+ 0x8c0c, 0x133a,
+ 0x8c0d, 0x05de,
+ 0x8c0e, 0x07e6,
+ 0x8c0f, 0x133b,
+ 0x8c10, 0x0f7e,
+ 0x8c11, 0x133c,
+ 0x8c13, 0x0ecc,
+ 0x8c14, 0x133e,
+ 0x8c17, 0x04be,
+ 0x8c18, 0x1343,
+ 0x8c19, 0x1341,
+ 0x8c1a, 0x1011,
+ 0x8c1b, 0x1342,
+ 0x8c1c, 0x0ada,
+ 0x8c1d, 0x1344,
+ 0x8c1e, 0x4b33,
+ 0x8c1f, 0x1345,
+ 0x8c22, 0x0f86,
+ 0x8c23, 0x102c,
+ 0x8c24, 0x0404,
+ 0x8c25, 0x1348,
+ 0x8c26, 0x0c28,
+ 0x8c27, 0x1349,
+ 0x8c28, 0x08c8,
+ 0x8c29, 0x0aa6,
+ 0x8c2a, 0x134a,
+ 0x8c2c, 0x0b02,
+ 0x8c2d, 0x0e0a,
+ 0x8c2e, 0x134c,
+ 0x8c30, 0x09a9,
+ 0x8c31, 0x0bf6,
+ 0x8c32, 0x134e,
+ 0x8c34, 0x0c31,
+ 0x8c35, 0x1350,
+ 0x8c37, 0x0721,
+ 0x8c38, 0x4b34,
+ 0x8c41, 0x0802,
+ 0x8c42, 0x4b3d,
+ 0x8c46, 0x05f8,
+ 0x8c47, 0x1cf6,
+ 0x8c48, 0x20c8,
+ 0x8c49, 0x1cf7,
+ 0x8c4a, 0x4b41,
+ 0x8c4c, 0x0e94,
+ 0x8c4d, 0x4b43,
+ 0x8c50, 0x1efd,
+ 0x8c51, 0x4b46,
+ 0x8c55, 0x1d15,
+ 0x8c56, 0x4b4a,
+ 0x8c5a, 0x1990,
+ 0x8c5b, 0x4b4e,
+ 0x8c61, 0x0f60,
+ 0x8c62, 0x07d4,
+ 0x8c63, 0x4b54,
+ 0x8c6a, 0x0777,
+ 0x8c6b, 0x10e8,
+ 0x8c6c, 0x4b5b,
+ 0x8c73, 0x15dd,
+ 0x8c74, 0x4b62,
+ 0x8c78, 0x1d50,
+ 0x8c79, 0x0413,
+ 0x8c7a, 0x04b9,
+ 0x8c7b, 0x4b66,
+ 0x8c82, 0x1d51,
+ 0x8c83, 0x4b6d,
+ 0x8c85, 0x1d53,
+ 0x8c86, 0x4b6f,
+ 0x8c89, 0x0788,
+ 0x8c8a, 0x1d52,
+ 0x8c8b, 0x4b72,
+ 0x8c8c, 0x0ab7,
+ 0x8c8d, 0x4b73,
+ 0x8c94, 0x1d55,
+ 0x8c95, 0x4b7a,
+ 0x8c98, 0x1d54,
+ 0x8c99, 0x4b7d,
+ 0x8c9d, 0x1e3b,
+ 0x8c9e, 0x227f,
+ 0x8c9f, 0x4b81,
+ 0x8ca0, 0x1f0c,
+ 0x8ca1, 0x1e59,
+ 0x8ca2, 0x1f24,
+ 0x8ca3, 0x4b82,
+ 0x8ca7, 0x20ba,
+ 0x8ca8, 0x1f65,
+ 0x8ca9, 0x1ef0,
+ 0x8caa, 0x2164,
+ 0x8cab, 0x1f30,
+ 0x8cac, 0x2261,
+ 0x8cad, 0x4b86,
+ 0x8caf, 0x22a2,
+ 0x8cb0, 0x24ab,
+ 0x8cb1, 0x4b88,
+ 0x8cb2, 0x24af,
+ 0x8cb3, 0x1ee8,
+ 0x8cb4, 0x1f39,
+ 0x8cb5, 0x4b89,
+ 0x8cb6, 0x1e48,
+ 0x8cb7, 0x2070,
+ 0x8cb8, 0x1ea8,
+ 0x8cb9, 0x4b8a,
+ 0x8cba, 0x24ac,
+ 0x8cbb, 0x1ef7,
+ 0x8cbc, 0x2176,
+ 0x8cbd, 0x24ad,
+ 0x8cbe, 0x4b8b,
+ 0x8cbf, 0x207b,
+ 0x8cc0, 0x1f45,
+ 0x8cc1, 0x24aa,
+ 0x8cc2, 0x204b,
+ 0x8cc3, 0x202f,
+ 0x8cc4, 0x1f5a,
+ 0x8cc5, 0x24b0,
+ 0x8cc6, 0x4b8c,
+ 0x8cc7, 0x22b7,
+ 0x8cc8, 0x1f7f,
+ 0x8cc9, 0x4b8d,
+ 0x8cca, 0x2265,
+ 0x8ccb, 0x4b8e,
+ 0x8cd1, 0x24b2,
+ 0x8cd2, 0x211b,
+ 0x8cd3, 0x1e51,
+ 0x8cd4, 0x4b94,
+ 0x8cd5, 0x24b4,
+ 0x8cd6, 0x4b95,
+ 0x8cda, 0x24b3,
+ 0x8cdb, 0x4b99,
+ 0x8cdc, 0x1e9f,
+ 0x8cdd, 0x4b9a,
+ 0x8cde, 0x2118,
+ 0x8cdf, 0x4b9b,
+ 0x8ce0, 0x20b4,
+ 0x8ce1, 0x23af,
+ 0x8ce2, 0x21bb,
+ 0x8ce3, 0x2072,
+ 0x8ce4, 0x1f95,
+ 0x8ce5, 0x4b9c,
+ 0x8ce6, 0x1f0a,
+ 0x8ce7, 0x24b6,
+ 0x8ce8, 0x4b9d,
+ 0x8cea, 0x2291,
+ 0x8ceb, 0x24b5,
+ 0x8cec, 0x2278,
+ 0x8ced, 0x1ed4,
+ 0x8cee, 0x4b9f,
+ 0x8cf4, 0x1ff3,
+ 0x8cf5, 0x4ba5,
+ 0x8cfa, 0x22a9,
+ 0x8cfb, 0x24b7,
+ 0x8cfc, 0x1f28,
+ 0x8cfd, 0x2109,
+ 0x8cfe, 0x22c7,
+ 0x8cff, 0x4baa,
+ 0x8d00, 0x4bab,
+ 0x8d04, 0x24ae,
+ 0x8d05, 0x22b1,
+ 0x8d06, 0x4baf,
+ 0x8d08, 0x2266,
+ 0x8d09, 0x4bb1,
+ 0x8d0a, 0x225b,
+ 0x8d0b, 0x22c4,
+ 0x8d0c, 0x4bb2,
+ 0x8d0d, 0x2115,
+ 0x8d0e, 0x4bb3,
+ 0x8d0f, 0x222a,
+ 0x8d10, 0x24b1,
+ 0x8d11, 0x4bb4,
+ 0x8d16, 0x213d,
+ 0x8d17, 0x4bb9,
+ 0x8d1b, 0x1f15,
+ 0x8d1c, 0x225c,
+ 0x8d1d, 0x041d,
+ 0x8d1e, 0x118b,
+ 0x8d1f, 0x06b5,
+ 0x8d20, 0x4bbd,
+ 0x8d21, 0x070a,
+ 0x8d22, 0x048d,
+ 0x8d23, 0x1133,
+ 0x8d24, 0x0f3a,
+ 0x8d25, 0x03e7,
+ 0x8d26, 0x116c,
+ 0x8d27, 0x080a,
+ 0x8d28, 0x11c9,
+ 0x8d29, 0x0654,
+ 0x8d2a, 0x0e03,
+ 0x8d2b, 0x0bd5,
+ 0x8d2c, 0x044a,
+ 0x8d2d, 0x0713,
+ 0x8d2e, 0x11fb,
+ 0x8d2f, 0x073a,
+ 0x8d30, 0x063e,
+ 0x8d31, 0x086d,
+ 0x8d32, 0x192c,
+ 0x8d34, 0x0e4c,
+ 0x8d35, 0x074c,
+ 0x8d36, 0x192e,
+ 0x8d37, 0x057e,
+ 0x8d38, 0x0ab8,
+ 0x8d39, 0x066e,
+ 0x8d3a, 0x078f,
+ 0x8d3b, 0x192f,
+ 0x8d3c, 0x1137,
+ 0x8d3d, 0x1930,
+ 0x8d3e, 0x0849,
+ 0x8d3f, 0x07f4,
+ 0x8d40, 0x1931,
+ 0x8d41, 0x0a27,
+ 0x8d42, 0x0a5f,
+ 0x8d43, 0x1122,
+ 0x8d44, 0x1227,
+ 0x8d45, 0x1932,
+ 0x8d47, 0x1936,
+ 0x8d48, 0x1934,
+ 0x8d4a, 0x0d17,
+ 0x8d4b, 0x06ae,
+ 0x8d4c, 0x0603,
+ 0x8d4d, 0x1937,
+ 0x8d4e, 0x0d81,
+ 0x8d4f, 0x0d06,
+ 0x8d50, 0x0550,
+ 0x8d51, 0x4bbe,
+ 0x8d53, 0x163b,
+ 0x8d54, 0x0ba3,
+ 0x8d55, 0x1938,
+ 0x8d56, 0x09a0,
+ 0x8d57, 0x4bc0,
+ 0x8d58, 0x1215,
+ 0x8d59, 0x1939,
+ 0x8d5a, 0x1209,
+ 0x8d5b, 0x0cd7,
+ 0x8d5c, 0x1289,
+ 0x8d5d, 0x1283,
+ 0x8d5e, 0x1121,
+ 0x8d5f, 0x4bc1,
+ 0x8d60, 0x113c,
+ 0x8d61, 0x0cfd,
+ 0x8d62, 0x1093,
+ 0x8d63, 0x06ce,
+ 0x8d64, 0x0505,
+ 0x8d65, 0x4bc2,
+ 0x8d66, 0x0d1b,
+ 0x8d67, 0x1cf4,
+ 0x8d68, 0x4bc3,
+ 0x8d6b, 0x078c,
+ 0x8d6c, 0x4bc6,
+ 0x8d6d, 0x1cf5,
+ 0x8d6e, 0x4bc7,
+ 0x8d70, 0x123c,
+ 0x8d71, 0x4bc9,
+ 0x8d73, 0x1cef,
+ 0x8d74, 0x06ab,
+ 0x8d75, 0x1175,
+ 0x8d76, 0x06ca,
+ 0x8d77, 0x0c0f,
+ 0x8d78, 0x4bcb,
+ 0x8d81, 0x04e8,
+ 0x8d82, 0x4bd4,
+ 0x8d84, 0x1cf0,
+ 0x8d85, 0x04d1,
+ 0x8d86, 0x4bd6,
+ 0x8d8a, 0x1100,
+ 0x8d8b, 0x0c74,
+ 0x8d8c, 0x4bda,
+ 0x8d91, 0x1cf2,
+ 0x8d92, 0x4bdf,
+ 0x8d94, 0x1cf1,
+ 0x8d95, 0x1f14,
+ 0x8d96, 0x4be1,
+ 0x8d99, 0x227a,
+ 0x8d9a, 0x4be4,
+ 0x8d9f, 0x0e1e,
+ 0x8da0, 0x4be9,
+ 0x8da3, 0x0c7f,
+ 0x8da4, 0x4bec,
+ 0x8da8, 0x20ee,
+ 0x8da9, 0x4bf0,
+ 0x8db1, 0x1cf3,
+ 0x8db2, 0x25f8,
+ 0x8db3, 0x1240,
+ 0x8db4, 0x0b80,
+ 0x8db5, 0x1d1c,
+ 0x8db6, 0x4bf8,
+ 0x8db8, 0x1d17,
+ 0x8db9, 0x4bfa,
+ 0x8dba, 0x1d1f,
+ 0x8dbb, 0x4bfb,
+ 0x8dbc, 0x1d1e,
+ 0x8dbd, 0x4bfc,
+ 0x8dbe, 0x11b9,
+ 0x8dbf, 0x1d1d,
+ 0x8dc0, 0x4bfd,
+ 0x8dc3, 0x1101,
+ 0x8dc4, 0x1d20,
+ 0x8dc5, 0x4c00,
+ 0x8dc6, 0x1d28,
+ 0x8dc7, 0x4c01,
+ 0x8dcb, 0x03da,
+ 0x8dcc, 0x05d9,
+ 0x8dcd, 0x4c05,
+ 0x8dce, 0x1d25,
+ 0x8dd0, 0x4c06,
+ 0x8dd1, 0x0b9d,
+ 0x8dd2, 0x4c07,
+ 0x8dd6, 0x1d21,
+ 0x8dd8, 0x4c0b,
+ 0x8dda, 0x1d23,
+ 0x8ddb, 0x1d27,
+ 0x8ddc, 0x4c0d,
+ 0x8ddd, 0x090f,
+ 0x8dde, 0x1d24,
+ 0x8ddf, 0x06f5,
+ 0x8de0, 0x4c0e,
+ 0x8de3, 0x1d2c,
+ 0x8de4, 0x1d2f,
+ 0x8de5, 0x4c11,
+ 0x8de8, 0x0974,
+ 0x8de9, 0x4c14,
+ 0x8dea, 0x074b,
+ 0x8deb, 0x1d18,
+ 0x8dec, 0x1d29,
+ 0x8ded, 0x4c15,
+ 0x8def, 0x0a5e,
+ 0x8df0, 0x4c17,
+ 0x8df3, 0x0e4b,
+ 0x8df4, 0x4c1a,
+ 0x8df5, 0x086c,
+ 0x8df6, 0x4c1b,
+ 0x8df7, 0x1d2a,
+ 0x8df9, 0x1d2d,
+ 0x8dfa, 0x0624,
+ 0x8dfb, 0x1d2e,
+ 0x8dfc, 0x4c1c,
+ 0x8dfd, 0x1d31,
+ 0x8dfe, 0x4c1d,
+ 0x8e00, 0x4c1f,
+ 0x8e05, 0x1d19,
+ 0x8e06, 0x4c24,
+ 0x8e09, 0x1d30,
+ 0x8e0a, 0x10a0,
+ 0x8e0b, 0x4c27,
+ 0x8e0c, 0x0511,
+ 0x8e0d, 0x4c28,
+ 0x8e0f, 0x0df7,
+ 0x8e10, 0x1f94,
+ 0x8e11, 0x4c2a,
+ 0x8e14, 0x1d32,
+ 0x8e15, 0x4c2d,
+ 0x8e1d, 0x1d33,
+ 0x8e1e, 0x0910,
+ 0x8e1f, 0x1d34,
+ 0x8e20, 0x4c35,
+ 0x8e22, 0x0e32,
+ 0x8e23, 0x1d37,
+ 0x8e24, 0x4c37,
+ 0x8e29, 0x048f,
+ 0x8e2a, 0x1236,
+ 0x8e2b, 0x4c3c,
+ 0x8e2c, 0x1d35,
+ 0x8e2d, 0x4c3d,
+ 0x8e2e, 0x1d36,
+ 0x8e2f, 0x1d38,
+ 0x8e30, 0x4c3e,
+ 0x8e31, 0x1d3e,
+ 0x8e32, 0x4c3f,
+ 0x8e34, 0x2230,
+ 0x8e35, 0x1d3c,
+ 0x8e36, 0x4c41,
+ 0x8e39, 0x1d3b,
+ 0x8e3a, 0x1d39,
+ 0x8e3b, 0x4c44,
+ 0x8e3d, 0x1d3d,
+ 0x8e3e, 0x4c46,
+ 0x8e40, 0x1d3a,
+ 0x8e41, 0x1d40,
+ 0x8e43, 0x4c48,
+ 0x8e44, 0x0e36,
+ 0x8e45, 0x4c49,
+ 0x8e47, 0x173b,
+ 0x8e48, 0x0599,
+ 0x8e49, 0x1d3f,
+ 0x8e4a, 0x1d44,
+ 0x8e4b, 0x0df6,
+ 0x8e4c, 0x25fd,
+ 0x8e4d, 0x4c4b,
+ 0x8e51, 0x1d42,
+ 0x8e53, 0x4c4f,
+ 0x8e55, 0x2600,
+ 0x8e56, 0x4c51,
+ 0x8e59, 0x1d1a,
+ 0x8e5a, 0x4c54,
+ 0x8e63, 0x2606,
+ 0x8e64, 0x4c5d,
+ 0x8e66, 0x042d,
+ 0x8e67, 0x4c5f,
+ 0x8e69, 0x1d1b,
+ 0x8e6a, 0x4c61,
+ 0x8e6c, 0x05a6,
+ 0x8e6d, 0x04ab,
+ 0x8e6e, 0x4c63,
+ 0x8e6f, 0x1d48,
+ 0x8e70, 0x1d45,
+ 0x8e71, 0x4c64,
+ 0x8e72, 0x0616,
+ 0x8e73, 0x4c65,
+ 0x8e74, 0x1d49,
+ 0x8e75, 0x4c66,
+ 0x8e76, 0x1d46,
+ 0x8e77, 0x4c67,
+ 0x8e7a, 0x25ff,
+ 0x8e7b, 0x4c6a,
+ 0x8e7c, 0x1d47,
+ 0x8e7d, 0x4c6b,
+ 0x8e7f, 0x055d,
+ 0x8e80, 0x4c6d,
+ 0x8e81, 0x112d,
+ 0x8e82, 0x4c6e,
+ 0x8e85, 0x1d4a,
+ 0x8e86, 0x4c71,
+ 0x8e87, 0x051e,
+ 0x8e88, 0x4c72,
+ 0x8e89, 0x25fc,
+ 0x8e8a, 0x1e8c,
+ 0x8e8b, 0x2602,
+ 0x8e8c, 0x4c73,
+ 0x8e8d, 0x224d,
+ 0x8e8e, 0x4c74,
+ 0x8e8f, 0x1d4b,
+ 0x8e90, 0x1d4d,
+ 0x8e91, 0x2604,
+ 0x8e92, 0x25fe,
+ 0x8e93, 0x2603,
+ 0x8e94, 0x1d4c,
+ 0x8e95, 0x4c75,
+ 0x8e9a, 0x2601,
+ 0x8e9b, 0x4c7a,
+ 0x8e9c, 0x1d4e,
+ 0x8e9d, 0x4c7b,
+ 0x8e9e, 0x1d4f,
+ 0x8e9f, 0x4c7c,
+ 0x8ea1, 0x2605,
+ 0x8ea2, 0x4c7e,
+ 0x8ea5, 0x1ea3,
+ 0x8ea6, 0x2608,
+ 0x8ea7, 0x4c81,
+ 0x8eaa, 0x2607,
+ 0x8eab, 0x0d26,
+ 0x8eac, 0x0703,
+ 0x8ead, 0x4c84,
+ 0x8eaf, 0x0c78,
+ 0x8eb0, 0x4c86,
+ 0x8eb2, 0x0622,
+ 0x8eb3, 0x4c88,
+ 0x8eba, 0x0e1c,
+ 0x8ebb, 0x4c8f,
+ 0x8ec0, 0x20f0,
+ 0x8ec1, 0x4c94,
+ 0x8eca, 0x1e7b,
+ 0x8ecb, 0x2267,
+ 0x8ecc, 0x1f36,
+ 0x8ecd, 0x1fd6,
+ 0x8ece, 0x18f8,
+ 0x8ecf, 0x4c9d,
+ 0x8ed2, 0x21e0,
+ 0x8ed3, 0x4ca0,
+ 0x8ed4, 0x248c,
+ 0x8ed5, 0x4ca1,
+ 0x8edb, 0x248d,
+ 0x8edc, 0x4ca7,
+ 0x8edf, 0x2102,
+ 0x8ee0, 0x4caa,
+ 0x8ee4, 0x2494,
+ 0x8ee5, 0x4cae,
+ 0x8eeb, 0x2493,
+ 0x8eec, 0x4cb4,
+ 0x8ef2, 0x248e,
+ 0x8ef3, 0x4cba,
+ 0x8ef8, 0x2299,
+ 0x8ef9, 0x2491,
+ 0x8efa, 0x2496,
+ 0x8efb, 0x248f,
+ 0x8efc, 0x2492,
+ 0x8efd, 0x4cbf,
+ 0x8efe, 0x2497,
+ 0x8eff, 0x4cc0,
+ 0x8f00, 0x4cc1,
+ 0x8f03, 0x1fb1,
+ 0x8f04, 0x4cc4,
+ 0x8f05, 0x249a,
+ 0x8f06, 0x4cc5,
+ 0x8f07, 0x2499,
+ 0x8f08, 0x4cc6,
+ 0x8f09, 0x2258,
+ 0x8f0a, 0x2498,
+ 0x8f0b, 0x4cc7,
+ 0x8f12, 0x249b,
+ 0x8f13, 0x4cce,
+ 0x8f14, 0x1f09,
+ 0x8f15, 0x20e6,
+ 0x8f16, 0x4ccf,
+ 0x8f1b, 0x2026,
+ 0x8f1c, 0x249f,
+ 0x8f1d, 0x1f59,
+ 0x8f1e, 0x249d,
+ 0x8f20, 0x4cd4,
+ 0x8f25, 0x1f3b,
+ 0x8f26, 0x249c,
+ 0x8f27, 0x4cd9,
+ 0x8f29, 0x1e3a,
+ 0x8f2a, 0x205b,
+ 0x8f2b, 0x4cdb,
+ 0x8f2f, 0x1f70,
+ 0x8f30, 0x4cdf,
+ 0x8f33, 0x24a0,
+ 0x8f34, 0x4ce2,
+ 0x8f38, 0x213b,
+ 0x8f39, 0x4ce6,
+ 0x8f3b, 0x1f07,
+ 0x8f3c, 0x4ce8,
+ 0x8f3e, 0x2270,
+ 0x8f3f, 0x2237,
+ 0x8f40, 0x4cea,
+ 0x8f42, 0x24d2,
+ 0x8f43, 0x4cec,
+ 0x8f44, 0x21b3,
+ 0x8f45, 0x2245,
+ 0x8f46, 0x24a1,
+ 0x8f47, 0x4ced,
+ 0x8f49, 0x22a8,
+ 0x8f4a, 0x4cef,
+ 0x8f4d, 0x227c,
+ 0x8f4e, 0x1fb0,
+ 0x8f4f, 0x4cf2,
+ 0x8f54, 0x24a2,
+ 0x8f55, 0x4cf7,
+ 0x8f5f, 0x1f46,
+ 0x8f60, 0x4d01,
+ 0x8f61, 0x2380,
+ 0x8f62, 0x2495,
+ 0x8f63, 0x4d02,
+ 0x8f64, 0x2490,
+ 0x8f65, 0x4d03,
+ 0x8f66, 0x04da,
+ 0x8f67, 0x1141,
+ 0x8f68, 0x0745,
+ 0x8f69, 0x0fc4,
+ 0x8f6a, 0x4d04,
+ 0x8f6b, 0x18e1,
+ 0x8f6c, 0x1207,
+ 0x8f6d, 0x18e2,
+ 0x8f6e, 0x0a7d,
+ 0x8f6f, 0x0cc8,
+ 0x8f70, 0x079b,
+ 0x8f71, 0x18e3,
+ 0x8f74, 0x11e0,
+ 0x8f75, 0x18e6,
+ 0x8f77, 0x18e9,
+ 0x8f78, 0x18e8,
+ 0x8f79, 0x18ea,
+ 0x8f7b, 0x0c5e,
+ 0x8f7c, 0x18ec,
+ 0x8f7d, 0x111b,
+ 0x8f7e, 0x18ed,
+ 0x8f7f, 0x089f,
+ 0x8f80, 0x4d05,
+ 0x8f81, 0x18ee,
+ 0x8f83, 0x08a0,
+ 0x8f84, 0x18f0,
+ 0x8f85, 0x06a3,
+ 0x8f86, 0x0a07,
+ 0x8f87, 0x18f1,
+ 0x8f88, 0x041b,
+ 0x8f89, 0x07e9,
+ 0x8f8a, 0x074e,
+ 0x8f8b, 0x18f2,
+ 0x8f8c, 0x4d06,
+ 0x8f8d, 0x18f3,
+ 0x8f90, 0x0695,
+ 0x8f91, 0x0820,
+ 0x8f92, 0x4d07,
+ 0x8f93, 0x0d7b,
+ 0x8f94, 0x1574,
+ 0x8f95, 0x10f2,
+ 0x8f96, 0x0f2a,
+ 0x8f97, 0x1158,
+ 0x8f98, 0x18f6,
+ 0x8f99, 0x117f,
+ 0x8f9a, 0x18f7,
+ 0x8f9b, 0x0f8c,
+ 0x8f9c, 0x0715,
+ 0x8f9d, 0x4d08,
+ 0x8f9e, 0x054a,
+ 0x8f9f, 0x0442,
+ 0x8fa0, 0x4d09,
+ 0x8fa3, 0x099c,
+ 0x8fa4, 0x4d0c,
+ 0x8fa6, 0x1e30,
+ 0x8fa7, 0x4d0e,
+ 0x8fa8, 0x044f,
+ 0x8faa, 0x4d0f,
+ 0x8fab, 0x0451,
+ 0x8fac, 0x4d10,
+ 0x8fad, 0x1e9d,
+ 0x8fae, 0x1e4b,
+ 0x8faf, 0x1e4a,
+ 0x8fb0, 0x04e2,
+ 0x8fb1, 0x0cc3,
+ 0x8fb2, 0x20aa,
+ 0x8fb3, 0x4d11,
+ 0x8fb6, 0x173d,
+ 0x8fb7, 0x4d14,
+ 0x8fb9, 0x0448,
+ 0x8fba, 0x4d16,
+ 0x8fbd, 0x0a12,
+ 0x8fbe, 0x0572,
+ 0x8fbf, 0x4d19,
+ 0x8fc1, 0x0c25,
+ 0x8fc2, 0x10bd,
+ 0x8fc3, 0x4d1b,
+ 0x8fc4, 0x0c18,
+ 0x8fc5, 0x0fe1,
+ 0x8fc6, 0x4d1c,
+ 0x8fc7, 0x0756,
+ 0x8fc8, 0x0a9c,
+ 0x8fc9, 0x4d1d,
+ 0x8fce, 0x1092,
+ 0x8fcf, 0x4d22,
+ 0x8fd0, 0x110e,
+ 0x8fd1, 0x08cd,
+ 0x8fd2, 0x4d23,
+ 0x8fd3, 0x173e,
+ 0x8fd4, 0x0652,
+ 0x8fd5, 0x173f,
+ 0x8fd6, 0x4d24,
+ 0x8fd8, 0x07ce,
+ 0x8fd9, 0x1183,
+ 0x8fda, 0x4d26,
+ 0x8fdb, 0x08c9,
+ 0x8fdc, 0x10f9,
+ 0x8fdd, 0x0eb4,
+ 0x8fde, 0x09f5,
+ 0x8fdf, 0x04fe,
+ 0x8fe0, 0x4d27,
+ 0x8fe2, 0x0e49,
+ 0x8fe3, 0x4d29,
+ 0x8fe4, 0x1742,
+ 0x8fe5, 0x1740,
+ 0x8fe6, 0x1744,
+ 0x8fe7, 0x4d2a,
+ 0x8fe8, 0x1746,
+ 0x8fe9, 0x1743,
+ 0x8fea, 0x05b0,
+ 0x8feb, 0x0be7,
+ 0x8fec, 0x4d2b,
+ 0x8fed, 0x05dd,
+ 0x8fee, 0x1741,
+ 0x8fef, 0x4d2c,
+ 0x8ff0, 0x0d8d,
+ 0x8ff1, 0x4d2d,
+ 0x8ff3, 0x1745,
+ 0x8ff4, 0x267b,
+ 0x8ff5, 0x4d2f,
+ 0x8ff7, 0x0ad9,
+ 0x8ff8, 0x042e,
+ 0x8ff9, 0x0816,
+ 0x8ffa, 0x4d31,
+ 0x8ffd, 0x1214,
+ 0x8ffe, 0x4d34,
+ 0x9000, 0x0e7c,
+ 0x9001, 0x0dc2,
+ 0x9002, 0x0d61,
+ 0x9003, 0x0e26,
+ 0x9004, 0x1748,
+ 0x9005, 0x1747,
+ 0x9006, 0x0b49,
+ 0x9007, 0x4d36,
+ 0x9009, 0x0fca,
+ 0x900a, 0x0fe0,
+ 0x900b, 0x1749,
+ 0x900c, 0x4d38,
+ 0x900d, 0x174c,
+ 0x900e, 0x4d39,
+ 0x900f, 0x0e69,
+ 0x9010, 0x11ef,
+ 0x9011, 0x174b,
+ 0x9012, 0x05be,
+ 0x9013, 0x4d3a,
+ 0x9014, 0x0e6f,
+ 0x9015, 0x23f2,
+ 0x9016, 0x174d,
+ 0x9017, 0x05f9,
+ 0x9018, 0x4d3b,
+ 0x9019, 0x227e,
+ 0x901a, 0x0e59,
+ 0x901b, 0x073d,
+ 0x901c, 0x4d3c,
+ 0x901d, 0x0d5c,
+ 0x901e, 0x04f6,
+ 0x901f, 0x0dce,
+ 0x9020, 0x112f,
+ 0x9021, 0x174e,
+ 0x9022, 0x0687,
+ 0x9023, 0x2019,
+ 0x9024, 0x4d3d,
+ 0x9026, 0x174a,
+ 0x9027, 0x4d3f,
+ 0x902d, 0x1751,
+ 0x902e, 0x0581,
+ 0x902f, 0x1752,
+ 0x9030, 0x4d45,
+ 0x9032, 0x1fbb,
+ 0x9033, 0x4d47,
+ 0x9035, 0x174f,
+ 0x9037, 0x4d49,
+ 0x9038, 0x1064,
+ 0x9039, 0x4d4a,
+ 0x903b, 0x0a86,
+ 0x903c, 0x042f,
+ 0x903d, 0x4d4c,
+ 0x903e, 0x10c7,
+ 0x903f, 0x4d4d,
+ 0x9041, 0x061c,
+ 0x9042, 0x0de1,
+ 0x9043, 0x4d4f,
+ 0x9044, 0x1753,
+ 0x9045, 0x4d50,
+ 0x9047, 0x10db,
+ 0x9048, 0x4d52,
+ 0x904b, 0x2253,
+ 0x904c, 0x4d55,
+ 0x904d, 0x0452,
+ 0x904e, 0x1f3e,
+ 0x904f, 0x0633,
+ 0x9050, 0x1756,
+ 0x9051, 0x1754,
+ 0x9053, 0x05a1,
+ 0x9054, 0x1ea6,
+ 0x9055, 0x218e,
+ 0x9056, 0x4d56,
+ 0x9057, 0x104c,
+ 0x9058, 0x1758,
+ 0x9059, 0x4d57,
+ 0x905b, 0x175a,
+ 0x905c, 0x21ec,
+ 0x905d, 0x4d59,
+ 0x905e, 0x1ebe,
+ 0x905f, 0x4d5a,
+ 0x9060, 0x224a,
+ 0x9061, 0x4d5b,
+ 0x9062, 0x1759,
+ 0x9063, 0x0c2f,
+ 0x9064, 0x4d5c,
+ 0x9065, 0x102a,
+ 0x9066, 0x4d5d,
+ 0x9068, 0x1757,
+ 0x9069, 0x2133,
+ 0x906a, 0x4d5f,
+ 0x906d, 0x1125,
+ 0x906e, 0x117b,
+ 0x906f, 0x4d62,
+ 0x9072, 0x1e84,
+ 0x9073, 0x4d65,
+ 0x9074, 0x175c,
+ 0x9075, 0x124e,
+ 0x9076, 0x4d66,
+ 0x9077, 0x20cf,
+ 0x9078, 0x21e2,
+ 0x9079, 0x4d67,
+ 0x907a, 0x220f,
+ 0x907b, 0x4d68,
+ 0x907c, 0x2029,
+ 0x907d, 0x175d,
+ 0x907e, 0x4d69,
+ 0x907f, 0x0445,
+ 0x9080, 0x1024,
+ 0x9081, 0x2073,
+ 0x9082, 0x175e,
+ 0x9083, 0x1760,
+ 0x9084, 0x1f55,
+ 0x9085, 0x4d6a,
+ 0x9087, 0x23f1,
+ 0x9088, 0x175f,
+ 0x9089, 0x4d6c,
+ 0x908a, 0x1e46,
+ 0x908b, 0x1761,
+ 0x908c, 0x4d6d,
+ 0x908f, 0x2063,
+ 0x9090, 0x23f3,
+ 0x9091, 0x105f,
+ 0x9092, 0x4d70,
+ 0x9093, 0x05ac,
+ 0x9094, 0x4d71,
+ 0x9095, 0x1817,
+ 0x9096, 0x4d72,
+ 0x9097, 0x1367,
+ 0x9098, 0x4d73,
+ 0x9099, 0x136a,
+ 0x909a, 0x4d74,
+ 0x909b, 0x1368,
+ 0x909c, 0x4d75,
+ 0x909d, 0x1369,
+ 0x909e, 0x4d76,
+ 0x90a1, 0x136c,
+ 0x90a2, 0x0f9a,
+ 0x90a3, 0x0b2a,
+ 0x90a4, 0x4d79,
+ 0x90a6, 0x03f9,
+ 0x90a7, 0x4d7b,
+ 0x90aa, 0x0f7b,
+ 0x90ab, 0x4d7e,
+ 0x90ac, 0x136b,
+ 0x90ad, 0x4d7f,
+ 0x90ae, 0x10af,
+ 0x90af, 0x0761,
+ 0x90b0, 0x1372,
+ 0x90b1, 0x0c6e,
+ 0x90b2, 0x4d80,
+ 0x90b3, 0x136e,
+ 0x90b4, 0x136d,
+ 0x90b5, 0x0d14,
+ 0x90b6, 0x136f,
+ 0x90b7, 0x4d81,
+ 0x90b8, 0x1371,
+ 0x90b9, 0x123b,
+ 0x90ba, 0x1370,
+ 0x90bb, 0x0a23,
+ 0x90bc, 0x4d82,
+ 0x90be, 0x1375,
+ 0x90bf, 0x4d84,
+ 0x90c1, 0x10d9,
+ 0x90c2, 0x4d86,
+ 0x90c4, 0x1377,
+ 0x90c5, 0x1374,
+ 0x90c6, 0x4d88,
+ 0x90c7, 0x1378,
+ 0x90c8, 0x4d89,
+ 0x90ca, 0x088d,
+ 0x90cb, 0x4d8b,
+ 0x90ce, 0x09b4,
+ 0x90cf, 0x1373,
+ 0x90d0, 0x1376,
+ 0x90d1, 0x11a2,
+ 0x90d2, 0x4d8e,
+ 0x90d3, 0x1379,
+ 0x90d4, 0x4d8f,
+ 0x90d7, 0x137d,
+ 0x90d8, 0x4d92,
+ 0x90db, 0x137e,
+ 0x90dc, 0x137c,
+ 0x90dd, 0x0779,
+ 0x90de, 0x4d95,
+ 0x90df, 0x231e,
+ 0x90e0, 0x4d96,
+ 0x90e1, 0x0931,
+ 0x90e2, 0x137b,
+ 0x90e3, 0x4d97,
+ 0x90e6, 0x137a,
+ 0x90e7, 0x110a,
+ 0x90e8, 0x0486,
+ 0x90e9, 0x4d9a,
+ 0x90eb, 0x137f,
+ 0x90ec, 0x4d9c,
+ 0x90ed, 0x0752,
+ 0x90ee, 0x4d9d,
+ 0x90ef, 0x1380,
+ 0x90f0, 0x4d9e,
+ 0x90f4, 0x04e0,
+ 0x90f5, 0x2233,
+ 0x90f6, 0x4da2,
+ 0x90f8, 0x0587,
+ 0x90f9, 0x4da4,
+ 0x90fd, 0x05fb,
+ 0x90fe, 0x1381,
+ 0x90ff, 0x4da8,
+ 0x9100, 0x4da9,
+ 0x9102, 0x0634,
+ 0x9103, 0x4dab,
+ 0x9104, 0x1382,
+ 0x9105, 0x4dac,
+ 0x9106, 0x2320,
+ 0x9107, 0x4dad,
+ 0x9109, 0x21c7,
+ 0x910a, 0x4daf,
+ 0x9112, 0x22bc,
+ 0x9113, 0x4db7,
+ 0x9114, 0x231c,
+ 0x9115, 0x4db8,
+ 0x9116, 0x2251,
+ 0x9117, 0x4db9,
+ 0x9119, 0x0432,
+ 0x911a, 0x4dbb,
+ 0x911e, 0x1384,
+ 0x911f, 0x4dbf,
+ 0x9122, 0x1383,
+ 0x9123, 0x1385,
+ 0x9124, 0x4dc2,
+ 0x9127, 0x1ebb,
+ 0x9128, 0x4dc5,
+ 0x912d, 0x2287,
+ 0x912e, 0x4dca,
+ 0x912f, 0x1387,
+ 0x9130, 0x202d,
+ 0x9131, 0x1386,
+ 0x9132, 0x1eab,
+ 0x9133, 0x4dcb,
+ 0x9134, 0x231d,
+ 0x9135, 0x4dcc,
+ 0x9136, 0x231f,
+ 0x9137, 0x4dcd,
+ 0x9139, 0x1388,
+ 0x913a, 0x231b,
+ 0x913b, 0x4dcf,
+ 0x9143, 0x1389,
+ 0x9144, 0x4dd7,
+ 0x9146, 0x138a,
+ 0x9147, 0x4dd9,
+ 0x9148, 0x2321,
+ 0x9149, 0x10b4,
+ 0x914a, 0x1cf8,
+ 0x914b, 0x0c72,
+ 0x914c, 0x1220,
+ 0x914d, 0x0ba5,
+ 0x914e, 0x1cfa,
+ 0x9150, 0x1cf9,
+ 0x9151, 0x4dda,
+ 0x9152, 0x08f5,
+ 0x9153, 0x4ddb,
+ 0x9157, 0x0fba,
+ 0x9158, 0x4ddf,
+ 0x915a, 0x0670,
+ 0x915b, 0x4de1,
+ 0x915d, 0x1110,
+ 0x915e, 0x0dfd,
+ 0x915f, 0x4de3,
+ 0x9161, 0x1cfe,
+ 0x9162, 0x1cfd,
+ 0x9163, 0x075f,
+ 0x9164, 0x1cfc,
+ 0x9165, 0x0dcb,
+ 0x9166, 0x4de5,
+ 0x9169, 0x1d00,
+ 0x916a, 0x09bd,
+ 0x916b, 0x4de8,
+ 0x916c, 0x050f,
+ 0x916d, 0x4de9,
+ 0x916e, 0x0e5b,
+ 0x916f, 0x1d01,
+ 0x9170, 0x1cff,
+ 0x9171, 0x0885,
+ 0x9172, 0x1d04,
+ 0x9173, 0x4dea,
+ 0x9174, 0x1d05,
+ 0x9175, 0x089e,
+ 0x9176, 0x0abd,
+ 0x9177, 0x096e,
+ 0x9178, 0x0dd6,
+ 0x9179, 0x1d06,
+ 0x917a, 0x4deb,
+ 0x917d, 0x1d02,
+ 0x917f, 0x0b53,
+ 0x9180, 0x4dee,
+ 0x9185, 0x1d08,
+ 0x9186, 0x4df3,
+ 0x9187, 0x053f,
+ 0x9188, 0x4df4,
+ 0x9189, 0x124a,
+ 0x918a, 0x4df5,
+ 0x918b, 0x055a,
+ 0x918c, 0x1d07,
+ 0x918d, 0x1d0a,
+ 0x918e, 0x4df6,
+ 0x9190, 0x1d09,
+ 0x9191, 0x1d0b,
+ 0x9192, 0x0f9c,
+ 0x9193, 0x4df8,
+ 0x9196, 0x2255,
+ 0x9197, 0x4dfb,
+ 0x919a, 0x0ad6,
+ 0x919b, 0x0c84,
+ 0x919c, 0x1e8f,
+ 0x919d, 0x4dfe,
+ 0x91a2, 0x1d0c,
+ 0x91a4, 0x4e03,
+ 0x91aa, 0x1d0e,
+ 0x91ab, 0x220c,
+ 0x91ac, 0x1fa4,
+ 0x91ad, 0x1d0f,
+ 0x91b0, 0x4e09,
+ 0x91b4, 0x1d13,
+ 0x91b5, 0x1d12,
+ 0x91b6, 0x4e0d,
+ 0x91ba, 0x1d14,
+ 0x91bb, 0x4e11,
+ 0x91c0, 0x209b,
+ 0x91c1, 0x21d8,
+ 0x91c2, 0x4e16,
+ 0x91c3, 0x25fa,
+ 0x91c4, 0x4e17,
+ 0x91c5, 0x25f9,
+ 0x91c6, 0x4e18,
+ 0x91c7, 0x0490,
+ 0x91c8, 0x4e19,
+ 0x91c9, 0x10b9,
+ 0x91ca, 0x0d64,
+ 0x91cb, 0x2134,
+ 0x91cc, 0x09da,
+ 0x91cd, 0x11d7,
+ 0x91ce, 0x1037,
+ 0x91cf, 0x0a08,
+ 0x91d0, 0x4e1a,
+ 0x91d1, 0x08c1,
+ 0x91d2, 0x24f3,
+ 0x91d5, 0x24f8,
+ 0x91d6, 0x4e1b,
+ 0x91d7, 0x24f7,
+ 0x91d8, 0x1ec8,
+ 0x91d9, 0x24f6,
+ 0x91da, 0x4e1c,
+ 0x91dc, 0x06a5,
+ 0x91dd, 0x2280,
+ 0x91de, 0x4e1e,
+ 0x91e3, 0x1ec5,
+ 0x91e4, 0x24fb,
+ 0x91e5, 0x4e23,
+ 0x91e7, 0x24fa,
+ 0x91e8, 0x4e25,
+ 0x91e9, 0x1eed,
+ 0x91ea, 0x4e26,
+ 0x91f5, 0x24fd,
+ 0x91f6, 0x4e31,
+ 0x91f7, 0x24f9,
+ 0x91f8, 0x4e32,
+ 0x91f9, 0x24fe,
+ 0x91fa, 0x20cd,
+ 0x91fb, 0x4e33,
+ 0x9200, 0x2508,
+ 0x9201, 0x2504,
+ 0x9202, 0x4e38,
+ 0x9204, 0x2506,
+ 0x9205, 0x4e3a,
+ 0x9208, 0x24ff,
+ 0x9209, 0x2090,
+ 0x920a, 0x4e3d,
+ 0x920d, 0x1edd,
+ 0x920e, 0x1f25,
+ 0x920f, 0x4e40,
+ 0x9210, 0x2503,
+ 0x9211, 0x2502,
+ 0x9212, 0x4e41,
+ 0x9214, 0x1e7a,
+ 0x9215, 0x20a6,
+ 0x9216, 0x4e43,
+ 0x921e, 0x1fd5,
+ 0x921f, 0x4e4b,
+ 0x9223, 0x1f11,
+ 0x9224, 0x4e4f,
+ 0x9225, 0x2507,
+ 0x9226, 0x2500,
+ 0x9227, 0x2505,
+ 0x9228, 0x4e50,
+ 0x922e, 0x2519,
+ 0x922f, 0x4e56,
+ 0x9230, 0x2515,
+ 0x9231, 0x4e57,
+ 0x9233, 0x250c,
+ 0x9234, 0x2031,
+ 0x9235, 0x4e59,
+ 0x9237, 0x250b,
+ 0x9238, 0x250f,
+ 0x9239, 0x251a,
+ 0x923a, 0x2509,
+ 0x923b, 0x4e5b,
+ 0x923d, 0x250e,
+ 0x923e, 0x2234,
+ 0x923f, 0x2513,
+ 0x9240, 0x1f80,
+ 0x9241, 0x4e5d,
+ 0x9245, 0x2501,
+ 0x9246, 0x4e61,
+ 0x9248, 0x2517,
+ 0x9249, 0x2516,
+ 0x924a, 0x4e63,
+ 0x924d, 0x2518,
+ 0x924e, 0x4e66,
+ 0x9251, 0x1e56,
+ 0x9252, 0x4e69,
+ 0x9255, 0x250d,
+ 0x9256, 0x4e6c,
+ 0x9257, 0x20d3,
+ 0x9258, 0x4e6d,
+ 0x925a, 0x207a,
+ 0x925b, 0x20ce,
+ 0x925c, 0x4e6f,
+ 0x925e, 0x2510,
+ 0x925f, 0x4e71,
+ 0x9262, 0x1e55,
+ 0x9263, 0x4e74,
+ 0x9266, 0x250a,
+ 0x9267, 0x4e77,
+ 0x926c, 0x2511,
+ 0x926e, 0x4e7c,
+ 0x9274, 0x086b,
+ 0x9275, 0x4e82,
+ 0x9278, 0x1faa,
+ 0x9279, 0x4e85,
+ 0x927a, 0x251e,
+ 0x927b, 0x1f1f,
+ 0x927c, 0x4e86,
+ 0x927f, 0x252d,
+ 0x9280, 0x221d,
+ 0x9281, 0x4e89,
+ 0x9283, 0x2532,
+ 0x9284, 0x4e8b,
+ 0x9285, 0x217b,
+ 0x9286, 0x4e8c,
+ 0x928e, 0x1d80,
+ 0x928f, 0x4e94,
+ 0x9291, 0x21af,
+ 0x9292, 0x4e96,
+ 0x9293, 0x252c,
+ 0x9294, 0x4e97,
+ 0x9296, 0x2528,
+ 0x9297, 0x4e99,
+ 0x9298, 0x208c,
+ 0x9299, 0x4e9a,
+ 0x929a, 0x252f,
+ 0x929b, 0x4e9b,
+ 0x929c, 0x21bc,
+ 0x929d, 0x4e9c,
+ 0x92a0, 0x251d,
+ 0x92a1, 0x4e9f,
+ 0x92a3, 0x2535,
+ 0x92a4, 0x4ea1,
+ 0x92a5, 0x220d,
+ 0x92a6, 0x2526,
+ 0x92a7, 0x4ea2,
+ 0x92a8, 0x2534,
+ 0x92a9, 0x252a,
+ 0x92aa, 0x251f,
+ 0x92ab, 0x2531,
+ 0x92ac, 0x251c,
+ 0x92ad, 0x4ea3,
+ 0x92ae, 0x1d81,
+ 0x92af, 0x4ea4,
+ 0x92b1, 0x2525,
+ 0x92b2, 0x4ea6,
+ 0x92b7, 0x21cd,
+ 0x92b8, 0x4eab,
+ 0x92b9, 0x21da,
+ 0x92ba, 0x4eac,
+ 0x92bb, 0x2172,
+ 0x92bc, 0x253e,
+ 0x92bd, 0x4ead,
+ 0x92c1, 0x204f,
+ 0x92c2, 0x4eb1,
+ 0x92c3, 0x2543,
+ 0x92c4, 0x4eb2,
+ 0x92c5, 0x21d7,
+ 0x92c6, 0x4eb3,
+ 0x92c7, 0x1e3c,
+ 0x92c8, 0x1d82,
+ 0x92c9, 0x4eb4,
+ 0x92cc, 0x2529,
+ 0x92cd, 0x4eb7,
+ 0x92cf, 0x2521,
+ 0x92d0, 0x4eb9,
+ 0x92d2, 0x1eff,
+ 0x92d3, 0x4ebb,
+ 0x92dd, 0x253f,
+ 0x92de, 0x4ec5,
+ 0x92df, 0x2544,
+ 0x92e0, 0x4ec6,
+ 0x92e3, 0x2523,
+ 0x92e4, 0x1e90,
+ 0x92e5, 0x253a,
+ 0x92e6, 0x2545,
+ 0x92e7, 0x4ec9,
+ 0x92e8, 0x253d,
+ 0x92e9, 0x4eca,
+ 0x92ea, 0x20c1,
+ 0x92eb, 0x4ecb,
+ 0x92ed, 0x2103,
+ 0x92ee, 0x2520,
+ 0x92ef, 0x253c,
+ 0x92f0, 0x253b,
+ 0x92f1, 0x2538,
+ 0x92f2, 0x4ecd,
+ 0x92f6, 0x2540,
+ 0x92f7, 0x4ed1,
+ 0x92f8, 0x1fcd,
+ 0x92f9, 0x4ed2,
+ 0x92fc, 0x1f18,
+ 0x92fd, 0x4ed5,
+ 0x9300, 0x4ed8,
+ 0x9301, 0x254b,
+ 0x9302, 0x4ed9,
+ 0x9306, 0x2547,
+ 0x9307, 0x254f,
+ 0x9309, 0x4edd,
+ 0x9310, 0x22b0,
+ 0x9311, 0x4ee4,
+ 0x9312, 0x2546,
+ 0x9313, 0x4ee5,
+ 0x9315, 0x254c,
+ 0x9316, 0x4ee7,
+ 0x9318, 0x1e9a,
+ 0x9319, 0x2552,
+ 0x931a, 0x2530,
+ 0x931b, 0x2549,
+ 0x931c, 0x4ee9,
+ 0x931f, 0x2551,
+ 0x9320, 0x1eca,
+ 0x9321, 0x4eec,
+ 0x9322, 0x20d2,
+ 0x9323, 0x4eed,
+ 0x9326, 0x1fb8,
+ 0x9327, 0x4ef0,
+ 0x9328, 0x2079,
+ 0x9329, 0x4ef1,
+ 0x932b, 0x21ab,
+ 0x932c, 0x4ef3,
+ 0x932e, 0x254d,
+ 0x932f, 0x1ea5,
+ 0x9330, 0x4ef5,
+ 0x9332, 0x204c,
+ 0x9333, 0x2080,
+ 0x9334, 0x4ef7,
+ 0x9336, 0x266d,
+ 0x9337, 0x4ef9,
+ 0x9338, 0x2537,
+ 0x9339, 0x4efa,
+ 0x933e, 0x1d83,
+ 0x933f, 0x4eff,
+ 0x9340, 0x254a,
+ 0x9341, 0x21b8,
+ 0x9342, 0x4f00,
+ 0x9343, 0x254e,
+ 0x9344, 0x4f01,
+ 0x9346, 0x24fc,
+ 0x9347, 0x2554,
+ 0x9348, 0x4f03,
+ 0x934b, 0x1f3c,
+ 0x934c, 0x4f06,
+ 0x934d, 0x1ed5,
+ 0x934e, 0x4f07,
+ 0x9354, 0x2556,
+ 0x9355, 0x4f0d,
+ 0x9358, 0x2268,
+ 0x9359, 0x4f10,
+ 0x935b, 0x1ed6,
+ 0x935c, 0x4f12,
+ 0x9364, 0x2557,
+ 0x9365, 0x2553,
+ 0x9366, 0x4f1a,
+ 0x9369, 0x2548,
+ 0x936a, 0x1d84,
+ 0x936b, 0x4f1d,
+ 0x936c, 0x20dc,
+ 0x936d, 0x4f1e,
+ 0x9370, 0x2559,
+ 0x9371, 0x4f21,
+ 0x9375, 0x1f97,
+ 0x9376, 0x2555,
+ 0x9377, 0x4f25,
+ 0x937a, 0x227d,
+ 0x937b, 0x4f28,
+ 0x937e, 0x257e,
+ 0x937f, 0x4f2b,
+ 0x9382, 0x207c,
+ 0x9383, 0x4f2e,
+ 0x9384, 0x255a,
+ 0x9385, 0x4f2f,
+ 0x9387, 0x255e,
+ 0x9388, 0x4f31,
+ 0x938a, 0x1e34,
+ 0x938b, 0x4f33,
+ 0x938f, 0x1d86,
+ 0x9390, 0x4f37,
+ 0x9396, 0x215e,
+ 0x9397, 0x4f3d,
+ 0x9398, 0x2560,
+ 0x9399, 0x4f3e,
+ 0x93a2, 0x21a2,
+ 0x93a3, 0x2354,
+ 0x93a4, 0x4f47,
+ 0x93a6, 0x2563,
+ 0x93a7, 0x2527,
+ 0x93a8, 0x4f49,
+ 0x93a9, 0x252e,
+ 0x93aa, 0x2558,
+ 0x93ab, 0x4f4a,
+ 0x93ac, 0x1f1b,
+ 0x93ad, 0x4f4b,
+ 0x93ae, 0x2283,
+ 0x93af, 0x4f4c,
+ 0x93b0, 0x2564,
+ 0x93b1, 0x4f4d,
+ 0x93b3, 0x20a0,
+ 0x93b4, 0x4f4f,
+ 0x93b5, 0x2565,
+ 0x93b6, 0x4f50,
+ 0x93b8, 0x2561,
+ 0x93b9, 0x4f52,
+ 0x93bf, 0x2562,
+ 0x93c0, 0x4f58,
+ 0x93c3, 0x256c,
+ 0x93c4, 0x4f5b,
+ 0x93c7, 0x256d,
+ 0x93c8, 0x2020,
+ 0x93c9, 0x4f5e,
+ 0x93ca, 0x1d85,
+ 0x93cb, 0x4f5f,
+ 0x93cc, 0x255f,
+ 0x93cd, 0x256a,
+ 0x93ce, 0x4f60,
+ 0x93d1, 0x256e,
+ 0x93d2, 0x4f63,
+ 0x93d6, 0x1e01,
+ 0x93d7, 0x2539,
+ 0x93d8, 0x255c,
+ 0x93d9, 0x4f67,
+ 0x93dc, 0x2568,
+ 0x93de, 0x256b,
+ 0x93df, 0x1e6f,
+ 0x93e0, 0x4f6a,
+ 0x93e1, 0x1fc4,
+ 0x93e2, 0x2567,
+ 0x93e3, 0x4f6b,
+ 0x93e4, 0x255b,
+ 0x93e5, 0x4f6c,
+ 0x93e8, 0x261d,
+ 0x93e9, 0x4f6f,
+ 0x93f5, 0x252b,
+ 0x93f6, 0x4f7b,
+ 0x93f7, 0x2571,
+ 0x93f8, 0x4f7c,
+ 0x93f9, 0x2577,
+ 0x93fa, 0x4f7d,
+ 0x9400, 0x4f83,
+ 0x9403, 0x2522,
+ 0x9404, 0x4f86,
+ 0x940b, 0x2533,
+ 0x940c, 0x4f8d,
+ 0x9410, 0x202a,
+ 0x9411, 0x4f91,
+ 0x9412, 0x2536,
+ 0x9413, 0x2573,
+ 0x9414, 0x256f,
+ 0x9415, 0x4f92,
+ 0x9418, 0x2293,
+ 0x9419, 0x2578,
+ 0x941a, 0x4f95,
+ 0x941d, 0x2570,
+ 0x941e, 0x4f98,
+ 0x9420, 0x2575,
+ 0x9421, 0x4f9a,
+ 0x9426, 0x2541,
+ 0x9428, 0x255d,
+ 0x9429, 0x4f9f,
+ 0x942e, 0x201a,
+ 0x942f, 0x4fa4,
+ 0x9432, 0x257a,
+ 0x9433, 0x2006,
+ 0x9434, 0x4fa7,
+ 0x9435, 0x2177,
+ 0x9436, 0x4fa8,
+ 0x9438, 0x251b,
+ 0x9439, 0x4faa,
+ 0x943a, 0x2524,
+ 0x943b, 0x4fab,
+ 0x943e, 0x1d87,
+ 0x943f, 0x257b,
+ 0x9440, 0x4fae,
+ 0x9444, 0x22a3,
+ 0x9445, 0x4fb2,
+ 0x944a, 0x2579,
+ 0x944b, 0x4fb7,
+ 0x944c, 0x2566,
+ 0x944d, 0x4fb8,
+ 0x9452, 0x1f93,
+ 0x9453, 0x4fbd,
+ 0x9454, 0x257c,
+ 0x9455, 0x4fbe,
+ 0x9460, 0x2514,
+ 0x9461, 0x4fc9,
+ 0x9463, 0x257d,
+ 0x9464, 0x4fcb,
+ 0x9465, 0x2572,
+ 0x9466, 0x4fcc,
+ 0x946b, 0x1d88,
+ 0x946c, 0x4fd1,
+ 0x946d, 0x2574,
+ 0x946e, 0x4fd2,
+ 0x9470, 0x224e,
+ 0x9471, 0x4fd4,
+ 0x9472, 0x21c6,
+ 0x9473, 0x4fd5,
+ 0x9477, 0x209f,
+ 0x9478, 0x4fd9,
+ 0x9479, 0x2576,
+ 0x947a, 0x4fda,
+ 0x947c, 0x2064,
+ 0x947d, 0x22bf,
+ 0x947e, 0x261c,
+ 0x947f, 0x225e,
+ 0x9480, 0x4fdc,
+ 0x9485, 0x1a8e,
+ 0x9488, 0x118c,
+ 0x9489, 0x05e3,
+ 0x948a, 0x1a92,
+ 0x948b, 0x1a91,
+ 0x948c, 0x1a93,
+ 0x948e, 0x0c22,
+ 0x948f, 0x1a95,
+ 0x9491, 0x4fe1,
+ 0x9492, 0x064d,
+ 0x9493, 0x05d7,
+ 0x9494, 0x1a97,
+ 0x9495, 0x1a99,
+ 0x9496, 0x4fe2,
+ 0x9497, 0x1a98,
+ 0x9498, 0x4fe3,
+ 0x9499, 0x06c1,
+ 0x949a, 0x1a9a,
+ 0x949d, 0x061a,
+ 0x949e, 0x04d3,
+ 0x949f, 0x11d2,
+ 0x94a0, 0x0b29,
+ 0x94a1, 0x041e,
+ 0x94a2, 0x06d1,
+ 0x94a3, 0x1a9d,
+ 0x94a5, 0x1102,
+ 0x94a6, 0x0c52,
+ 0x94a7, 0x092a,
+ 0x94a8, 0x0ee8,
+ 0x94a9, 0x070c,
+ 0x94aa, 0x1aa0,
+ 0x94ab, 0x1a9f,
+ 0x94ac, 0x1aa2,
+ 0x94ad, 0x1aa1,
+ 0x94ae, 0x0b66,
+ 0x94af, 0x1aa3,
+ 0x94b1, 0x0c2b,
+ 0x94b2, 0x1aa5,
+ 0x94b3, 0x0c2c,
+ 0x94b4, 0x1aa6,
+ 0x94b5, 0x046e,
+ 0x94b6, 0x1aa7,
+ 0x94bb, 0x1247,
+ 0x94bc, 0x1aac,
+ 0x94be, 0x084b,
+ 0x94bf, 0x1aae,
+ 0x94c0, 0x10b0,
+ 0x94c1, 0x0e4d,
+ 0x94c2, 0x0473,
+ 0x94c3, 0x0a2e,
+ 0x94c4, 0x1aaf,
+ 0x94c5, 0x0c23,
+ 0x94c6, 0x0ab2,
+ 0x94c7, 0x4fe4,
+ 0x94c8, 0x1ab0,
+ 0x94cf, 0x4fe5,
+ 0x94d0, 0x1ab7,
+ 0x94d3, 0x4fe6,
+ 0x94d5, 0x1aba,
+ 0x94d8, 0x1abe,
+ 0x94d9, 0x1abd,
+ 0x94da, 0x4fe8,
+ 0x94db, 0x1abf,
+ 0x94dc, 0x0e5e,
+ 0x94dd, 0x0a68,
+ 0x94de, 0x1ac0,
+ 0x94e1, 0x1142,
+ 0x94e2, 0x1ac3,
+ 0x94e3, 0x0f20,
+ 0x94e4, 0x1ac4,
+ 0x94e6, 0x4fe9,
+ 0x94e7, 0x1ac6,
+ 0x94e9, 0x1ac9,
+ 0x94ea, 0x1ac8,
+ 0x94eb, 0x1aca,
+ 0x94ec, 0x06f0,
+ 0x94ed, 0x0aff,
+ 0x94ee, 0x1acb,
+ 0x94f0, 0x0893,
+ 0x94f1, 0x1046,
+ 0x94f2, 0x04c0,
+ 0x94f3, 0x1acd,
+ 0x94f6, 0x107f,
+ 0x94f7, 0x1ad0,
+ 0x94f8, 0x11fc,
+ 0x94f9, 0x1ad1,
+ 0x94fa, 0x0beb,
+ 0x94fb, 0x4fea,
+ 0x94fc, 0x1ad2,
+ 0x94fe, 0x09fd,
+ 0x94ff, 0x1ad4,
+ 0x9500, 0x0f67,
+ 0x9501, 0x0ded,
+ 0x9502, 0x1ad6,
+ 0x9503, 0x1ad5,
+ 0x9504, 0x051f,
+ 0x9505, 0x0751,
+ 0x9506, 0x1ad7,
+ 0x9508, 0x0fad,
+ 0x9509, 0x1ad9,
+ 0x950b, 0x0683,
+ 0x950c, 0x0f8a,
+ 0x950d, 0x1adb,
+ 0x9510, 0x0ccc,
+ 0x9511, 0x0e33,
+ 0x9512, 0x1ade,
+ 0x9517, 0x1181,
+ 0x9518, 0x1ae3,
+ 0x9519, 0x0570,
+ 0x951a, 0x0aaf,
+ 0x951b, 0x1ae4,
+ 0x951c, 0x4feb,
+ 0x951d, 0x1ae5,
+ 0x9520, 0x4fec,
+ 0x9521, 0x0f0c,
+ 0x9522, 0x1ae8,
+ 0x9523, 0x0a87,
+ 0x9524, 0x053b,
+ 0x9525, 0x1213,
+ 0x9526, 0x08c6,
+ 0x9527, 0x4fed,
+ 0x9528, 0x0f34,
+ 0x9529, 0x1aeb,
+ 0x952a, 0x1ae9,
+ 0x952c, 0x1aec,
+ 0x952d, 0x05e6,
+ 0x952e, 0x086f,
+ 0x952f, 0x0911,
+ 0x9530, 0x0ad1,
+ 0x9531, 0x1aed,
+ 0x9533, 0x4fee,
+ 0x9534, 0x1aef,
+ 0x9535, 0x1af7,
+ 0x9536, 0x1af0,
+ 0x9539, 0x0c3f,
+ 0x953a, 0x1b19,
+ 0x953b, 0x060c,
+ 0x953c, 0x1af3,
+ 0x953d, 0x4fef,
+ 0x953e, 0x1af4,
+ 0x9540, 0x0605,
+ 0x9541, 0x0ac3,
+ 0x9542, 0x1af6,
+ 0x9543, 0x4ff0,
+ 0x9544, 0x1af8,
+ 0x9547, 0x1193,
+ 0x9548, 0x4ff1,
+ 0x9549, 0x1afb,
+ 0x954a, 0x0b5a,
+ 0x954b, 0x4ff2,
+ 0x954c, 0x1afc,
+ 0x954d, 0x0b5b,
+ 0x954e, 0x1afd,
+ 0x9550, 0x06df,
+ 0x9551, 0x0402,
+ 0x9552, 0x1aff,
+ 0x9555, 0x4ff3,
+ 0x9556, 0x1b02,
+ 0x955a, 0x4ff4,
+ 0x955b, 0x1b06,
+ 0x955c, 0x08e4,
+ 0x955d, 0x1b09,
+ 0x955e, 0x1b07,
+ 0x9560, 0x4ff5,
+ 0x9561, 0x1b0a,
+ 0x9563, 0x0a16,
+ 0x9564, 0x1b0c,
+ 0x956d, 0x09c3,
+ 0x956e, 0x4ff6,
+ 0x956f, 0x1b15,
+ 0x9570, 0x09f6,
+ 0x9571, 0x1b16,
+ 0x9574, 0x4ff7,
+ 0x9576, 0x0f4f,
+ 0x9577, 0x1e75,
+ 0x9578, 0x4ff9,
+ 0x957f, 0x04c9,
+ 0x9580, 0x207d,
+ 0x9581, 0x5000,
+ 0x9582, 0x23bf,
+ 0x9583, 0x2113,
+ 0x9584, 0x5001,
+ 0x9586, 0x23c0,
+ 0x9587, 0x5003,
+ 0x9589, 0x1e45,
+ 0x958a, 0x5005,
+ 0x958b, 0x1fd8,
+ 0x958c, 0x23c4,
+ 0x958d, 0x5006,
+ 0x958e, 0x23c2,
+ 0x958f, 0x2104,
+ 0x9590, 0x5007,
+ 0x9591, 0x21bd,
+ 0x9592, 0x5008,
+ 0x9593, 0x1f87,
+ 0x9594, 0x23c3,
+ 0x9595, 0x5009,
+ 0x9598, 0x2269,
+ 0x9599, 0x500c,
+ 0x95a1, 0x1f43,
+ 0x95a2, 0x5014,
+ 0x95a3, 0x1f1e,
+ 0x95a4, 0x2679,
+ 0x95a5, 0x1eeb,
+ 0x95a6, 0x5015,
+ 0x95a8, 0x1f35,
+ 0x95a9, 0x208a,
+ 0x95aa, 0x5017,
+ 0x95ab, 0x23c7,
+ 0x95ac, 0x23c9,
+ 0x95ad, 0x23c6,
+ 0x95ae, 0x5018,
+ 0x95b2, 0x224f,
+ 0x95b3, 0x501c,
+ 0x95b6, 0x23cb,
+ 0x95b7, 0x501f,
+ 0x95b9, 0x21f3,
+ 0x95ba, 0x5021,
+ 0x95bb, 0x21f7,
+ 0x95bc, 0x23cf,
+ 0x95bd, 0x23ce,
+ 0x95be, 0x23ca,
+ 0x95bf, 0x23cd,
+ 0x95c0, 0x5022,
+ 0x95c3, 0x23d0,
+ 0x95c4, 0x5025,
+ 0x95c6, 0x266c,
+ 0x95c7, 0x5027,
+ 0x95c8, 0x23c1,
+ 0x95c9, 0x5028,
+ 0x95ca, 0x1fee,
+ 0x95cb, 0x23d1,
+ 0x95cc, 0x1ff8,
+ 0x95cd, 0x5029,
+ 0x95d0, 0x23d3,
+ 0x95d1, 0x502c,
+ 0x95d4, 0x23d2,
+ 0x95d5, 0x23d4,
+ 0x95d6, 0x1e98,
+ 0x95d7, 0x502f,
+ 0x95dc, 0x1f2c,
+ 0x95dd, 0x5034,
+ 0x95de, 0x23d5,
+ 0x95df, 0x5035,
+ 0x95e1, 0x1e71,
+ 0x95e2, 0x2691,
+ 0x95e3, 0x5037,
+ 0x95e5, 0x23c5,
+ 0x95e6, 0x5039,
+ 0x95e8, 0x0aca,
+ 0x95e9, 0x1685,
+ 0x95ea, 0x0cfa,
+ 0x95eb, 0x1686,
+ 0x95ec, 0x503b,
+ 0x95ed, 0x043e,
+ 0x95ee, 0x0ed9,
+ 0x95ef, 0x0536,
+ 0x95f0, 0x0ccd,
+ 0x95f1, 0x1687,
+ 0x95f2, 0x0f3d,
+ 0x95f3, 0x1688,
+ 0x95f4, 0x0857,
+ 0x95f5, 0x1689,
+ 0x95f7, 0x0acb,
+ 0x95f8, 0x1143,
+ 0x95f9, 0x0b39,
+ 0x95fa, 0x0744,
+ 0x95fb, 0x0ed4,
+ 0x95fc, 0x168b,
+ 0x95fd, 0x0afb,
+ 0x95fe, 0x168c,
+ 0x95ff, 0x503c,
+ 0x9600, 0x0644,
+ 0x9601, 0x06ee,
+ 0x9602, 0x0789,
+ 0x9603, 0x168d,
+ 0x9605, 0x1107,
+ 0x9606, 0x168f,
+ 0x9607, 0x503d,
+ 0x9608, 0x1690,
+ 0x9609, 0x0ff4,
+ 0x960a, 0x1691,
+ 0x960e, 0x0fff,
+ 0x960f, 0x1695,
+ 0x9610, 0x04c2,
+ 0x9611, 0x09a6,
+ 0x9612, 0x1696,
+ 0x9613, 0x503e,
+ 0x9614, 0x0996,
+ 0x9615, 0x1697,
+ 0x9618, 0x503f,
+ 0x9619, 0x169a,
+ 0x961b, 0x5040,
+ 0x961c, 0x06b2,
+ 0x961d, 0x1354,
+ 0x961e, 0x5041,
+ 0x961f, 0x0612,
+ 0x9620, 0x5042,
+ 0x9621, 0x1356,
+ 0x9622, 0x1355,
+ 0x9623, 0x5043,
+ 0x962a, 0x1358,
+ 0x962b, 0x504a,
+ 0x962e, 0x0cc9,
+ 0x962f, 0x504d,
+ 0x9631, 0x1357,
+ 0x9632, 0x065d,
+ 0x9633, 0x101d,
+ 0x9634, 0x107c,
+ 0x9635, 0x1194,
+ 0x9636, 0x08a8,
+ 0x9637, 0x504f,
+ 0x963b, 0x1245,
+ 0x963c, 0x135a,
+ 0x963d, 0x1359,
+ 0x963e, 0x5053,
+ 0x963f, 0x03ad,
+ 0x9640, 0x0e84,
+ 0x9641, 0x5054,
+ 0x9642, 0x135b,
+ 0x9643, 0x5055,
+ 0x9644, 0x06b8,
+ 0x9645, 0x083d,
+ 0x9646, 0x0a64,
+ 0x9647, 0x0a4b,
+ 0x9648, 0x04e7,
+ 0x9649, 0x135c,
+ 0x964a, 0x5056,
+ 0x964b, 0x0a51,
+ 0x964c, 0x0b13,
+ 0x964d, 0x0886,
+ 0x964e, 0x5057,
+ 0x9650, 0x0f4b,
+ 0x9651, 0x5059,
+ 0x9654, 0x135d,
+ 0x9655, 0x0cfb,
+ 0x9656, 0x505c,
+ 0x9658, 0x231a,
+ 0x9659, 0x505e,
+ 0x965b, 0x0446,
+ 0x965c, 0x5060,
+ 0x965d, 0x2114,
+ 0x965e, 0x5061,
+ 0x965f, 0x135e,
+ 0x9660, 0x5062,
+ 0x9661, 0x05f7,
+ 0x9662, 0x10fd,
+ 0x9663, 0x2284,
+ 0x9664, 0x0522,
+ 0x9665, 0x5063,
+ 0x9667, 0x135f,
+ 0x9668, 0x110c,
+ 0x9669, 0x0f42,
+ 0x966a, 0x0ba4,
+ 0x966b, 0x5065,
+ 0x966c, 0x1360,
+ 0x966d, 0x5066,
+ 0x9670, 0x221c,
+ 0x9671, 0x5069,
+ 0x9672, 0x1361,
+ 0x9673, 0x1e7e,
+ 0x9674, 0x1362,
+ 0x9675, 0x0a33,
+ 0x9676, 0x0e28,
+ 0x9677, 0x0f4a,
+ 0x9678, 0x204d,
+ 0x9679, 0x506a,
+ 0x967d, 0x2201,
+ 0x967e, 0x506e,
+ 0x9685, 0x10cc,
+ 0x9686, 0x0a48,
+ 0x9687, 0x5075,
+ 0x9688, 0x1363,
+ 0x9689, 0x5076,
+ 0x968a, 0x1ed9,
+ 0x968b, 0x0dda,
+ 0x968c, 0x5077,
+ 0x968d, 0x1364,
+ 0x968e, 0x1fb2,
+ 0x968f, 0x0ddb,
+ 0x9690, 0x1085,
+ 0x9691, 0x5078,
+ 0x9694, 0x06ef,
+ 0x9695, 0x2252,
+ 0x9696, 0x507b,
+ 0x9697, 0x1365,
+ 0x9698, 0x03ba,
+ 0x9699, 0x0f23,
+ 0x969a, 0x507c,
+ 0x969b, 0x1f79,
+ 0x969c, 0x1170,
+ 0x969d, 0x507d,
+ 0x96a7, 0x0de2,
+ 0x96a8, 0x2157,
+ 0x96a9, 0x5087,
+ 0x96aa, 0x21bf,
+ 0x96ab, 0x5088,
+ 0x96b0, 0x1366,
+ 0x96b1, 0x221f,
+ 0x96b2, 0x508d,
+ 0x96b3, 0x1684,
+ 0x96b4, 0x203d,
+ 0x96b5, 0x508e,
+ 0x96b6, 0x09ee,
+ 0x96b7, 0x508f,
+ 0x96b8, 0x2015,
+ 0x96b9, 0x1d79,
+ 0x96ba, 0x5090,
+ 0x96bb, 0x26a5,
+ 0x96bc, 0x1d7a,
+ 0x96be, 0x0b34,
+ 0x96bf, 0x5091,
+ 0x96c0, 0x0c93,
+ 0x96c1, 0x100c,
+ 0x96c2, 0x5092,
+ 0x96c4, 0x0fa6,
+ 0x96c5, 0x0fee,
+ 0x96c6, 0x0822,
+ 0x96c7, 0x0726,
+ 0x96c8, 0x5094,
+ 0x96c9, 0x1b1c,
+ 0x96ca, 0x5095,
+ 0x96cc, 0x0549,
+ 0x96cd, 0x109f,
+ 0x96ce, 0x1d7c,
+ 0x96cf, 0x0520,
+ 0x96d0, 0x5097,
+ 0x96d2, 0x1d7d,
+ 0x96d3, 0x5099,
+ 0x96d5, 0x05d2,
+ 0x96d6, 0x2156,
+ 0x96d7, 0x509b,
+ 0x96d9, 0x2144,
+ 0x96da, 0x509d,
+ 0x96db, 0x1e91,
+ 0x96dc, 0x2257,
+ 0x96dd, 0x509e,
+ 0x96e0, 0x1d7f,
+ 0x96e1, 0x50a1,
+ 0x96e2, 0x200a,
+ 0x96e3, 0x2092,
+ 0x96e4, 0x50a2,
+ 0x96e8, 0x10cf,
+ 0x96e9, 0x1d61,
+ 0x96ea, 0x0fd2,
+ 0x96eb, 0x50a6,
+ 0x96ef, 0x1d63,
+ 0x96f0, 0x50aa,
+ 0x96f2, 0x2250,
+ 0x96f3, 0x1d62,
+ 0x96f4, 0x50ac,
+ 0x96f6, 0x0a2c,
+ 0x96f7, 0x09c2,
+ 0x96f8, 0x50ae,
+ 0x96f9, 0x040b,
+ 0x96fa, 0x50af,
+ 0x96fb, 0x1ec3,
+ 0x96fc, 0x50b0,
+ 0x96fe, 0x0efc,
+ 0x96ff, 0x50b2,
+ 0x9700, 0x0fb3,
+ 0x9701, 0x1d65,
+ 0x9702, 0x50b3,
+ 0x9704, 0x0f63,
+ 0x9705, 0x50b5,
+ 0x9706, 0x1d64,
+ 0x9707, 0x1191,
+ 0x9708, 0x1d66,
+ 0x9709, 0x0abe,
+ 0x970a, 0x50b6,
+ 0x970d, 0x0809,
+ 0x970e, 0x1d68,
+ 0x970f, 0x1d67,
+ 0x9710, 0x50b9,
+ 0x9713, 0x0b41,
+ 0x9714, 0x50bc,
+ 0x9716, 0x0a21,
+ 0x9717, 0x50be,
+ 0x971c, 0x0d9f,
+ 0x971d, 0x50c3,
+ 0x971e, 0x0f29,
+ 0x971f, 0x50c4,
+ 0x9727, 0x21a8,
+ 0x9728, 0x50cc,
+ 0x972a, 0x1d69,
+ 0x972b, 0x50ce,
+ 0x972d, 0x1d6a,
+ 0x972e, 0x50d0,
+ 0x9730, 0x1d6b,
+ 0x9731, 0x50d2,
+ 0x9732, 0x0a5d,
+ 0x9733, 0x50d3,
+ 0x9738, 0x03df,
+ 0x9739, 0x0bba,
+ 0x973a, 0x50d8,
+ 0x973d, 0x260d,
+ 0x973e, 0x1d6c,
+ 0x973f, 0x50db,
+ 0x9742, 0x260c,
+ 0x9743, 0x50de,
+ 0x9744, 0x260e,
+ 0x9745, 0x50df,
+ 0x9748, 0x2032,
+ 0x9749, 0x50e2,
+ 0x9752, 0x0c5d,
+ 0x9753, 0x1d60,
+ 0x9754, 0x50eb,
+ 0x9756, 0x08e7,
+ 0x9757, 0x50ed,
+ 0x9759, 0x08e1,
+ 0x975a, 0x260b,
+ 0x975b, 0x05c6,
+ 0x975c, 0x50ef,
+ 0x975e, 0x0664,
+ 0x975f, 0x50f1,
+ 0x9760, 0x094c,
+ 0x9761, 0x0ad7,
+ 0x9762, 0x0aeb,
+ 0x9763, 0x50f2,
+ 0x9765, 0x1282,
+ 0x9766, 0x50f4,
+ 0x9768, 0x22c3,
+ 0x9769, 0x06ea,
+ 0x976a, 0x50f6,
+ 0x9773, 0x08ca,
+ 0x9774, 0x0fce,
+ 0x9775, 0x50ff,
+ 0x9776, 0x03db,
+ 0x9777, 0x5100,
+ 0x977c, 0x1dc8,
+ 0x977d, 0x5105,
+ 0x9785, 0x1dc9,
+ 0x9786, 0x510d,
+ 0x978b, 0x0f77,
+ 0x978c, 0x5112,
+ 0x978d, 0x03bb,
+ 0x978e, 0x5113,
+ 0x978f, 0x1f23,
+ 0x9790, 0x5114,
+ 0x9791, 0x1dca,
+ 0x9793, 0x5115,
+ 0x9794, 0x1dcc,
+ 0x9795, 0x5116,
+ 0x9798, 0x0c47,
+ 0x9799, 0x5119,
+ 0x97a0, 0x08fe,
+ 0x97a1, 0x5120,
+ 0x97a3, 0x1dcf,
+ 0x97a4, 0x5122,
+ 0x97a6, 0x2695,
+ 0x97a7, 0x5124,
+ 0x97ab, 0x1dce,
+ 0x97ac, 0x5128,
+ 0x97ad, 0x0447,
+ 0x97ae, 0x5129,
+ 0x97af, 0x1dcd,
+ 0x97b0, 0x512a,
+ 0x97b2, 0x1dd0,
+ 0x97b3, 0x512c,
+ 0x97b4, 0x1dd1,
+ 0x97b5, 0x512d,
+ 0x97bd, 0x265e,
+ 0x97be, 0x5135,
+ 0x97c3, 0x265d,
+ 0x97c4, 0x513a,
+ 0x97c6, 0x2692,
+ 0x97c7, 0x513c,
+ 0x97c9, 0x265f,
+ 0x97ca, 0x513e,
+ 0x97cb, 0x218d,
+ 0x97cc, 0x20fd,
+ 0x97cd, 0x513f,
+ 0x97d3, 0x1f40,
+ 0x97d4, 0x5145,
+ 0x97d9, 0x2465,
+ 0x97da, 0x514a,
+ 0x97dc, 0x2467,
+ 0x97dd, 0x514c,
+ 0x97de, 0x2466,
+ 0x97df, 0x514d,
+ 0x97e6, 0x0eb3,
+ 0x97e7, 0x0ca8,
+ 0x97e8, 0x5154,
+ 0x97e9, 0x0762,
+ 0x97ea, 0x184e,
+ 0x97ed, 0x08f1,
+ 0x97ee, 0x5155,
+ 0x97f3, 0x107b,
+ 0x97f4, 0x515a,
+ 0x97f5, 0x1112,
+ 0x97f6, 0x0d11,
+ 0x97f7, 0x515b,
+ 0x97ff, 0x21c9,
+ 0x9800, 0x5163,
+ 0x9801, 0x2209,
+ 0x9802, 0x1ec9,
+ 0x9803, 0x20e9,
+ 0x9804, 0x5164,
+ 0x9805, 0x21ca,
+ 0x9806, 0x2146,
+ 0x9807, 0x25c5,
+ 0x9808, 0x21dc,
+ 0x9809, 0x5165,
+ 0x980a, 0x245e,
+ 0x980b, 0x5166,
+ 0x980c, 0x214f,
+ 0x980d, 0x5167,
+ 0x980e, 0x25c6,
+ 0x9810, 0x2241,
+ 0x9811, 0x218a,
+ 0x9812, 0x1e2f,
+ 0x9813, 0x1edc,
+ 0x9814, 0x5168,
+ 0x9817, 0x20bf,
+ 0x9818, 0x2034,
+ 0x9819, 0x516b,
+ 0x981c, 0x25c9,
+ 0x981d, 0x516e,
+ 0x9821, 0x25c8,
+ 0x9822, 0x5172,
+ 0x9824, 0x220e,
+ 0x9825, 0x5174,
+ 0x9826, 0x25cb,
+ 0x9827, 0x5175,
+ 0x982d, 0x217d,
+ 0x982e, 0x517b,
+ 0x9830, 0x1f7e,
+ 0x9831, 0x517d,
+ 0x9837, 0x25cc,
+ 0x9838, 0x1fc3,
+ 0x9839, 0x5183,
+ 0x983b, 0x20b9,
+ 0x983c, 0x5185,
+ 0x983d, 0x2181,
+ 0x983e, 0x5186,
+ 0x9846, 0x1fda,
+ 0x9847, 0x518e,
+ 0x984c, 0x2173,
+ 0x984d, 0x1ee1,
+ 0x984e, 0x25cd,
+ 0x984f, 0x5193,
+ 0x9853, 0x25ce,
+ 0x9854, 0x21f6,
+ 0x9855, 0x5197,
+ 0x9858, 0x224b,
+ 0x9859, 0x25d1,
+ 0x985a, 0x519a,
+ 0x985b, 0x1ec0,
+ 0x985c, 0x519b,
+ 0x985e, 0x2008,
+ 0x985f, 0x519d,
+ 0x9862, 0x25d0,
+ 0x9863, 0x51a0,
+ 0x9865, 0x25d2,
+ 0x9866, 0x51a2,
+ 0x9867, 0x1f2a,
+ 0x9868, 0x51a3,
+ 0x986b, 0x1e72,
+ 0x986c, 0x25d3,
+ 0x986d, 0x51a6,
+ 0x986f, 0x21be,
+ 0x9870, 0x25d4,
+ 0x9871, 0x2044,
+ 0x9872, 0x51a8,
+ 0x9873, 0x25cf,
+ 0x9874, 0x20f3,
+ 0x9875, 0x103a,
+ 0x9876, 0x05e4,
+ 0x9877, 0x0c67,
+ 0x9878, 0x1be0,
+ 0x9879, 0x0f5b,
+ 0x987a, 0x0da8,
+ 0x987b, 0x0fb6,
+ 0x987c, 0x1827,
+ 0x987d, 0x0e98,
+ 0x987e, 0x0724,
+ 0x987f, 0x0618,
+ 0x9880, 0x1be1,
+ 0x9881, 0x03ef,
+ 0x9882, 0x0dc1,
+ 0x9883, 0x1be2,
+ 0x9884, 0x10e7,
+ 0x9885, 0x0a54,
+ 0x9886, 0x0a35,
+ 0x9887, 0x0be3,
+ 0x9888, 0x08e0,
+ 0x9889, 0x1be3,
+ 0x988a, 0x0848,
+ 0x988b, 0x51a9,
+ 0x988c, 0x1be4,
+ 0x988e, 0x51aa,
+ 0x988f, 0x1be6,
+ 0x9890, 0x104a,
+ 0x9891, 0x0bd4,
+ 0x9892, 0x51ab,
+ 0x9893, 0x0e78,
+ 0x9894, 0x1be7,
+ 0x9895, 0x51ac,
+ 0x9896, 0x1096,
+ 0x9897, 0x0952,
+ 0x9898, 0x0e35,
+ 0x9899, 0x51ad,
+ 0x989a, 0x1be8,
+ 0x989c, 0x0ffe,
+ 0x989d, 0x062d,
+ 0x989e, 0x1bea,
+ 0x98a0, 0x05c0,
+ 0x98a1, 0x1bec,
+ 0x98a3, 0x51ae,
+ 0x98a4, 0x04c3,
+ 0x98a5, 0x1bee,
+ 0x98a7, 0x0c82,
+ 0x98a8, 0x1f00,
+ 0x98a9, 0x51af,
+ 0x98ae, 0x24cc,
+ 0x98b0, 0x51b4,
+ 0x98b1, 0x2698,
+ 0x98b2, 0x51b5,
+ 0x98b3, 0x2678,
+ 0x98b4, 0x51b6,
+ 0x98b6, 0x24ce,
+ 0x98b7, 0x51b8,
+ 0x98bc, 0x24cf,
+ 0x98bd, 0x51bd,
+ 0x98c4, 0x20b8,
+ 0x98c5, 0x51c4,
+ 0x98c6, 0x24d0,
+ 0x98c7, 0x51c5,
+ 0x98c8, 0x24d1,
+ 0x98c9, 0x51c6,
+ 0x98ce, 0x0684,
+ 0x98cf, 0x51cb,
+ 0x98d1, 0x19b7,
+ 0x98d4, 0x51cd,
+ 0x98d5, 0x19ba,
+ 0x98d6, 0x51ce,
+ 0x98d8, 0x0bcd,
+ 0x98d9, 0x19bb,
+ 0x98db, 0x1ef4,
+ 0x98dc, 0x51d0,
+ 0x98de, 0x0666,
+ 0x98df, 0x0d4a,
+ 0x98e0, 0x239b,
+ 0x98e1, 0x51d2,
+ 0x98e2, 0x267e,
+ 0x98e3, 0x51d3,
+ 0x98e7, 0x161a,
+ 0x98e8, 0x1de7,
+ 0x98e9, 0x239d,
+ 0x98ea, 0x239f,
+ 0x98ec, 0x51d7,
+ 0x98ed, 0x23a1,
+ 0x98ee, 0x51d8,
+ 0x98ef, 0x1ef1,
+ 0x98f0, 0x51d9,
+ 0x98f2, 0x221e,
+ 0x98f3, 0x51db,
+ 0x98f4, 0x23a2,
+ 0x98f5, 0x51dc,
+ 0x98fc, 0x214b,
+ 0x98fd, 0x1e36,
+ 0x98fe, 0x2135,
+ 0x98ff, 0x51e3,
+ 0x9900, 0x51e4,
+ 0x9903, 0x1fad,
+ 0x9904, 0x51e7,
+ 0x9905, 0x1e53,
+ 0x9906, 0x51e8,
+ 0x9909, 0x23a3,
+ 0x990a, 0x2203,
+ 0x990b, 0x51eb,
+ 0x990c, 0x1ee7,
+ 0x990d, 0x1de8,
+ 0x990e, 0x51ec,
+ 0x9910, 0x0494,
+ 0x9911, 0x23a4,
+ 0x9912, 0x2097,
+ 0x9913, 0x1ee4,
+ 0x9914, 0x51ee,
+ 0x9918, 0x2238,
+ 0x9919, 0x51f2,
+ 0x991b, 0x23a5,
+ 0x991c, 0x51f4,
+ 0x991e, 0x1f9a,
+ 0x991f, 0x51f6,
+ 0x9921, 0x21c3,
+ 0x9922, 0x51f8,
+ 0x9928, 0x1f2e,
+ 0x9929, 0x51fe,
+ 0x992e, 0x1de9,
+ 0x992f, 0x5203,
+ 0x9933, 0x239c,
+ 0x9934, 0x5207,
+ 0x9937, 0x23a6,
+ 0x9938, 0x520a,
+ 0x993c, 0x239e,
+ 0x993d, 0x520e,
+ 0x993e, 0x2035,
+ 0x993f, 0x23a7,
+ 0x9940, 0x520f,
+ 0x9943, 0x23a8,
+ 0x9944, 0x5212,
+ 0x9945, 0x2075,
+ 0x9946, 0x5213,
+ 0x9948, 0x23a9,
+ 0x994b, 0x1feb,
+ 0x994c, 0x23ac,
+ 0x994d, 0x5215,
+ 0x9951, 0x1f6a,
+ 0x9952, 0x20f9,
+ 0x9953, 0x5219,
+ 0x9954, 0x1deb,
+ 0x9955, 0x1dea,
+ 0x9956, 0x521a,
+ 0x9957, 0x2666,
+ 0x9958, 0x521b,
+ 0x995c, 0x2667,
+ 0x995d, 0x521f,
+ 0x995e, 0x1e6c,
+ 0x995f, 0x5220,
+ 0x9962, 0x23ad,
+ 0x9963, 0x161d,
+ 0x9964, 0x5223,
+ 0x9965, 0x0815,
+ 0x9966, 0x5224,
+ 0x9967, 0x161e,
+ 0x996d, 0x0656,
+ 0x996e, 0x1082,
+ 0x996f, 0x0875,
+ 0x9970, 0x0d65,
+ 0x9971, 0x040e,
+ 0x9972, 0x0dbc,
+ 0x9973, 0x5225,
+ 0x9974, 0x1624,
+ 0x9975, 0x063b,
+ 0x9976, 0x0c9f,
+ 0x9977, 0x1625,
+ 0x9978, 0x5226,
+ 0x997a, 0x0899,
+ 0x997b, 0x5228,
+ 0x997c, 0x0466,
+ 0x997d, 0x1626,
+ 0x997e, 0x5229,
+ 0x997f, 0x0635,
+ 0x9980, 0x1627,
+ 0x9981, 0x0b3c,
+ 0x9982, 0x522a,
+ 0x9984, 0x1628,
+ 0x9985, 0x0f47,
+ 0x9986, 0x0736,
+ 0x9987, 0x1629,
+ 0x9988, 0x098c,
+ 0x9989, 0x522c,
+ 0x998a, 0x162a,
+ 0x998b, 0x04bd,
+ 0x998c, 0x522d,
+ 0x998d, 0x162b,
+ 0x998e, 0x522e,
+ 0x998f, 0x0a3c,
+ 0x9990, 0x162c,
+ 0x9992, 0x0a9f,
+ 0x9993, 0x162e,
+ 0x9996, 0x0d6e,
+ 0x9997, 0x126e,
+ 0x9998, 0x12f9,
+ 0x9999, 0x0f50,
+ 0x999a, 0x522f,
+ 0x99a5, 0x1b2b,
+ 0x99a6, 0x523a,
+ 0x99a8, 0x13de,
+ 0x99a9, 0x523c,
+ 0x99ac, 0x206d,
+ 0x99ad, 0x2242,
+ 0x99ae, 0x1f02,
+ 0x99af, 0x523f,
+ 0x99b1, 0x2183,
+ 0x99b2, 0x5241,
+ 0x99b3, 0x1e85,
+ 0x99b4, 0x21e9,
+ 0x99b5, 0x5242,
+ 0x99c1, 0x1e57,
+ 0x99c2, 0x524e,
+ 0x99d0, 0x22a5,
+ 0x99d1, 0x2407,
+ 0x99d2, 0x1fca,
+ 0x99d3, 0x525c,
+ 0x99d4, 0x2402,
+ 0x99d5, 0x1f82,
+ 0x99d6, 0x525d,
+ 0x99d8, 0x2408,
+ 0x99d9, 0x2404,
+ 0x99da, 0x525f,
+ 0x99db, 0x2131,
+ 0x99dc, 0x5260,
+ 0x99dd, 0x2184,
+ 0x99de, 0x5261,
+ 0x99df, 0x2403,
+ 0x99e0, 0x5262,
+ 0x99e1, 0x206e,
+ 0x99e2, 0x240b,
+ 0x99e3, 0x5263,
+ 0x99ed, 0x1f3f,
+ 0x99ee, 0x526d,
+ 0x99f1, 0x2067,
+ 0x99f2, 0x5270,
+ 0x99ff, 0x1fd7,
+ 0x9a00, 0x527d,
+ 0x9a01, 0x1e83,
+ 0x9a02, 0x527e,
+ 0x9a05, 0x240f,
+ 0x9a06, 0x5281,
+ 0x9a0d, 0x240e,
+ 0x9a0e, 0x20c7,
+ 0x9a0f, 0x240d,
+ 0x9a10, 0x5288,
+ 0x9a16, 0x2412,
+ 0x9a17, 0x528e,
+ 0x9a19, 0x20b7,
+ 0x9a1a, 0x5290,
+ 0x9a2b, 0x23f0,
+ 0x9a2c, 0x52a1,
+ 0x9a2d, 0x2411,
+ 0x9a2e, 0x2414,
+ 0x9a2f, 0x52a2,
+ 0x9a30, 0x2170,
+ 0x9a31, 0x52a3,
+ 0x9a36, 0x2405,
+ 0x9a37, 0x210c,
+ 0x9a38, 0x2415,
+ 0x9a39, 0x52a8,
+ 0x9a3e, 0x2066,
+ 0x9a3f, 0x52ad,
+ 0x9a40, 0x2352,
+ 0x9a41, 0x2413,
+ 0x9a42, 0x2410,
+ 0x9a43, 0x2416,
+ 0x9a45, 0x20f1,
+ 0x9a46, 0x52ae,
+ 0x9a4a, 0x240a,
+ 0x9a4b, 0x52b2,
+ 0x9a4d, 0x2409,
+ 0x9a4e, 0x52b4,
+ 0x9a4f, 0x2418,
+ 0x9a50, 0x52b5,
+ 0x9a55, 0x1fa7,
+ 0x9a56, 0x52ba,
+ 0x9a57, 0x21fc,
+ 0x9a58, 0x52bb,
+ 0x9a5a, 0x1fc1,
+ 0x9a5b, 0x2406,
+ 0x9a5c, 0x52bd,
+ 0x9a5f, 0x229c,
+ 0x9a60, 0x52c0,
+ 0x9a62, 0x204e,
+ 0x9a63, 0x52c2,
+ 0x9a64, 0x241a,
+ 0x9a65, 0x2419,
+ 0x9a66, 0x52c3,
+ 0x9a6a, 0x240c,
+ 0x9a6b, 0x52c7,
+ 0x9a6c, 0x0a94,
+ 0x9a6d, 0x10e9,
+ 0x9a6e, 0x0e85,
+ 0x9a6f, 0x0fda,
+ 0x9a70, 0x0500,
+ 0x9a71, 0x0c7a,
+ 0x9a72, 0x52c8,
+ 0x9a73, 0x047c,
+ 0x9a74, 0x0a66,
+ 0x9a75, 0x17ba,
+ 0x9a76, 0x0d52,
+ 0x9a77, 0x17bb,
+ 0x9a79, 0x0903,
+ 0x9a7a, 0x17bd,
+ 0x9a7b, 0x1201,
+ 0x9a7c, 0x0e86,
+ 0x9a7d, 0x17bf,
+ 0x9a7e, 0x0850,
+ 0x9a7f, 0x17be,
+ 0x9a80, 0x17c0,
+ 0x9a82, 0x0a95,
+ 0x9a83, 0x52c9,
+ 0x9a84, 0x088f,
+ 0x9a85, 0x17c2,
+ 0x9a86, 0x0a8d,
+ 0x9a87, 0x075e,
+ 0x9a88, 0x17c3,
+ 0x9a89, 0x52ca,
+ 0x9a8a, 0x17c4,
+ 0x9a8b, 0x04f7,
+ 0x9a8c, 0x1012,
+ 0x9a8d, 0x52cb,
+ 0x9a8f, 0x0932,
+ 0x9a90, 0x17c5,
+ 0x9a91, 0x0c0e,
+ 0x9a92, 0x17c6,
+ 0x9a94, 0x52cd,
+ 0x9a96, 0x17c8,
+ 0x9a97, 0x0bcc,
+ 0x9a98, 0x17c9,
+ 0x9a99, 0x52cf,
+ 0x9a9a, 0x0ce0,
+ 0x9a9b, 0x17ca,
+ 0x9a9e, 0x1735,
+ 0x9a9f, 0x17cd,
+ 0x9aa1, 0x0a89,
+ 0x9aa2, 0x17cf,
+ 0x9aa4, 0x11e7,
+ 0x9aa5, 0x17d1,
+ 0x9aa6, 0x52d0,
+ 0x9aa7, 0x17d2,
+ 0x9aa8, 0x0720,
+ 0x9aa9, 0x52d1,
+ 0x9aaf, 0x1e29,
+ 0x9ab0, 0x1dd3,
+ 0x9ab1, 0x1dd2,
+ 0x9ab2, 0x52d7,
+ 0x9ab6, 0x1dd6,
+ 0x9ab7, 0x1dd4,
+ 0x9ab8, 0x0758,
+ 0x9ab9, 0x52db,
+ 0x9aba, 0x1dd7,
+ 0x9abb, 0x52dc,
+ 0x9abc, 0x1dd8,
+ 0x9abd, 0x52dd,
+ 0x9ac0, 0x1dda,
+ 0x9ac1, 0x1dd9,
+ 0x9ac2, 0x1ddc,
+ 0x9ac3, 0x52e0,
+ 0x9ac5, 0x1ddb,
+ 0x9ac6, 0x52e2,
+ 0x9acb, 0x1ddd,
+ 0x9acd, 0x52e7,
+ 0x9acf, 0x2661,
+ 0x9ad0, 0x52e9,
+ 0x9ad1, 0x1ddf,
+ 0x9ad2, 0x26a4,
+ 0x9ad3, 0x0ddd,
+ 0x9ad4, 0x2174,
+ 0x9ad5, 0x2663,
+ 0x9ad6, 0x2662,
+ 0x9ad7, 0x52ea,
+ 0x9ad8, 0x06da,
+ 0x9ad9, 0x52eb,
+ 0x9adf, 0x1dec,
+ 0x9ae0, 0x52f1,
+ 0x9ae1, 0x1ded,
+ 0x9ae2, 0x52f2,
+ 0x9ae6, 0x1dee,
+ 0x9ae7, 0x52f6,
+ 0x9aeb, 0x1df0,
+ 0x9aec, 0x52fa,
+ 0x9aed, 0x1df2,
+ 0x9aee, 0x2675,
+ 0x9aef, 0x1def,
+ 0x9af0, 0x52fb,
+ 0x9af9, 0x1df3,
+ 0x9afa, 0x5304,
+ 0x9afb, 0x1df1,
+ 0x9afc, 0x5305,
+ 0x9b00, 0x5309,
+ 0x9b03, 0x1234,
+ 0x9b04, 0x530c,
+ 0x9b06, 0x214c,
+ 0x9b07, 0x530e,
+ 0x9b08, 0x1df4,
+ 0x9b09, 0x530f,
+ 0x9b0d, 0x267a,
+ 0x9b0e, 0x5313,
+ 0x9b0f, 0x1df5,
+ 0x9b10, 0x5314,
+ 0x9b13, 0x1df6,
+ 0x9b14, 0x5317,
+ 0x9b1a, 0x26a0,
+ 0x9b1b, 0x531d,
+ 0x9b1f, 0x1df7,
+ 0x9b20, 0x5321,
+ 0x9b22, 0x2668,
+ 0x9b23, 0x1df8,
+ 0x9b24, 0x5323,
+ 0x9b25, 0x1ed0,
+ 0x9b26, 0x5324,
+ 0x9b27, 0x2096,
+ 0x9b28, 0x5325,
+ 0x9b29, 0x23cc,
+ 0x9b2a, 0x5326,
+ 0x9b2e, 0x23c8,
+ 0x9b2f, 0x139b,
+ 0x9b30, 0x532a,
+ 0x9b31, 0x223e,
+ 0x9b32, 0x1260,
+ 0x9b33, 0x532b,
+ 0x9b3b, 0x1773,
+ 0x9b3c, 0x0746,
+ 0x9b3d, 0x5333,
+ 0x9b41, 0x098a,
+ 0x9b42, 0x07ff,
+ 0x9b43, 0x1de1,
+ 0x9b44, 0x0be6,
+ 0x9b45, 0x1de0,
+ 0x9b46, 0x5337,
+ 0x9b47, 0x1de2,
+ 0x9b48, 0x1de4,
+ 0x9b49, 0x1de3,
+ 0x9b4a, 0x5338,
+ 0x9b4d, 0x1de5,
+ 0x9b4e, 0x2665,
+ 0x9b4f, 0x0ec9,
+ 0x9b50, 0x533b,
+ 0x9b51, 0x1de6,
+ 0x9b52, 0x533c,
+ 0x9b54, 0x0b0a,
+ 0x9b55, 0x533e,
+ 0x9b58, 0x2664,
+ 0x9b59, 0x5341,
+ 0x9b5a, 0x2239,
+ 0x9b5b, 0x5342,
+ 0x9b6f, 0x204a,
+ 0x9b70, 0x5356,
+ 0x9b74, 0x261f,
+ 0x9b75, 0x535a,
+ 0x9b77, 0x261e,
+ 0x9b78, 0x535c,
+ 0x9b81, 0x2620,
+ 0x9b82, 0x5365,
+ 0x9b83, 0x2621,
+ 0x9b84, 0x5366,
+ 0x9b8e, 0x2622,
+ 0x9b8f, 0x5370,
+ 0x9b90, 0x2627,
+ 0x9b91, 0x1e39,
+ 0x9b92, 0x2625,
+ 0x9b93, 0x5371,
+ 0x9b9a, 0x2629,
+ 0x9b9b, 0x5378,
+ 0x9b9d, 0x262e,
+ 0x9b9e, 0x262b,
+ 0x9b9f, 0x537a,
+ 0x9baa, 0x262a,
+ 0x9bab, 0x262d,
+ 0x9bac, 0x5385,
+ 0x9bad, 0x2628,
+ 0x9bae, 0x21b9,
+ 0x9baf, 0x5386,
+ 0x9bc0, 0x2636,
+ 0x9bc1, 0x2630,
+ 0x9bc2, 0x5397,
+ 0x9bc7, 0x2638,
+ 0x9bc8, 0x539c,
+ 0x9bc9, 0x200d,
+ 0x9bca, 0x2637,
+ 0x9bcb, 0x539d,
+ 0x9bd4, 0x2645,
+ 0x9bd5, 0x53a6,
+ 0x9bd6, 0x263a,
+ 0x9bd7, 0x53a7,
+ 0x9bdb, 0x2643,
+ 0x9bdc, 0x53ab,
+ 0x9bdd, 0x2640,
+ 0x9bde, 0x53ac,
+ 0x9be1, 0x263d,
+ 0x9be2, 0x2641,
+ 0x9be3, 0x53af,
+ 0x9be4, 0x263e,
+ 0x9be5, 0x53b0,
+ 0x9be7, 0x263f,
+ 0x9be8, 0x1fc0,
+ 0x9be9, 0x53b2,
+ 0x9bea, 0x263b,
+ 0x9bec, 0x53b3,
+ 0x9bf0, 0x2642,
+ 0x9bf1, 0x53b7,
+ 0x9bf4, 0x2644,
+ 0x9bf5, 0x53ba,
+ 0x9bfd, 0x2639,
+ 0x9bfe, 0x53c2,
+ 0x9bff, 0x264c,
+ 0x9c00, 0x53c3,
+ 0x9c08, 0x2647,
+ 0x9c09, 0x264b,
+ 0x9c0a, 0x53cb,
+ 0x9c0d, 0x2649,
+ 0x9c0e, 0x53ce,
+ 0x9c10, 0x2648,
+ 0x9c11, 0x53d0,
+ 0x9c12, 0x264a,
+ 0x9c13, 0x2108,
+ 0x9c14, 0x53d1,
+ 0x9c20, 0x264d,
+ 0x9c21, 0x53dd,
+ 0x9c23, 0x2634,
+ 0x9c24, 0x53df,
+ 0x9c25, 0x2651,
+ 0x9c26, 0x53e0,
+ 0x9c28, 0x2650,
+ 0x9c29, 0x2652,
+ 0x9c2a, 0x53e2,
+ 0x9c2d, 0x264f,
+ 0x9c2e, 0x53e5,
+ 0x9c31, 0x2632,
+ 0x9c32, 0x264e,
+ 0x9c33, 0x2653,
+ 0x9c34, 0x53e8,
+ 0x9c35, 0x2657,
+ 0x9c36, 0x53e9,
+ 0x9c37, 0x2635,
+ 0x9c38, 0x53ea,
+ 0x9c39, 0x2633,
+ 0x9c3a, 0x53eb,
+ 0x9c3b, 0x2656,
+ 0x9c3c, 0x53ec,
+ 0x9c3e, 0x2654,
+ 0x9c3f, 0x53ee,
+ 0x9c45, 0x2658,
+ 0x9c46, 0x53f4,
+ 0x9c48, 0x2655,
+ 0x9c49, 0x1e4d,
+ 0x9c4a, 0x53f6,
+ 0x9c52, 0x265b,
+ 0x9c53, 0x53fe,
+ 0x9c54, 0x265a,
+ 0x9c55, 0x53ff,
+ 0x9c56, 0x2659,
+ 0x9c57, 0x202e,
+ 0x9c58, 0x262f,
+ 0x9c59, 0x5400,
+ 0x9c5d, 0x2646,
+ 0x9c5e, 0x5404,
+ 0x9c5f, 0x2626,
+ 0x9c60, 0x5405,
+ 0x9c67, 0x265c,
+ 0x9c68, 0x540c,
+ 0x9c6d, 0x262c,
+ 0x9c6e, 0x5411,
+ 0x9c78, 0x2623,
+ 0x9c79, 0x541b,
+ 0x9c7a, 0x2631,
+ 0x9c7b, 0x541c,
+ 0x9c7c, 0x10c8,
+ 0x9c7d, 0x541d,
+ 0x9c7f, 0x1d89,
+ 0x9c80, 0x541f,
+ 0x9c81, 0x0a5a,
+ 0x9c82, 0x1d8a,
+ 0x9c83, 0x5420,
+ 0x9c85, 0x1d8b,
+ 0x9c89, 0x5422,
+ 0x9c8b, 0x1d90,
+ 0x9c8c, 0x5424,
+ 0x9c8d, 0x0414,
+ 0x9c8e, 0x1d91,
+ 0x9c8f, 0x5425,
+ 0x9c90, 0x1d92,
+ 0x9c93, 0x5426,
+ 0x9c94, 0x1d95,
+ 0x9c96, 0x5427,
+ 0x9c9a, 0x1d97,
+ 0x9c9c, 0x0f37,
+ 0x9c9d, 0x542b,
+ 0x9c9e, 0x1d99,
+ 0x9ca4, 0x09db,
+ 0x9ca5, 0x1d9f,
+ 0x9caa, 0x542c,
+ 0x9cab, 0x1da4,
+ 0x9cac, 0x542d,
+ 0x9cad, 0x1da5,
+ 0x9caf, 0x542e,
+ 0x9cb0, 0x1da7,
+ 0x9cb8, 0x08d7,
+ 0x9cb9, 0x542f,
+ 0x9cba, 0x1daf,
+ 0x9cbe, 0x5430,
+ 0x9cc3, 0x0cd5,
+ 0x9cc4, 0x1db3,
+ 0x9cc8, 0x5435,
+ 0x9cca, 0x1db7,
+ 0x9cd1, 0x5437,
+ 0x9cd3, 0x1dbe,
+ 0x9cd6, 0x0457,
+ 0x9cd7, 0x1dc1,
+ 0x9cda, 0x5439,
+ 0x9cdc, 0x1dc4,
+ 0x9cde, 0x0a24,
+ 0x9cdf, 0x1dc6,
+ 0x9ce0, 0x543b,
+ 0x9ce2, 0x1dc7,
+ 0x9ce3, 0x543d,
+ 0x9ce5, 0x209c,
+ 0x9ce6, 0x543f,
+ 0x9ce9, 0x2580,
+ 0x9cea, 0x5442,
+ 0x9cec, 0x22dc,
+ 0x9ced, 0x5444,
+ 0x9cf3, 0x1f05,
+ 0x9cf4, 0x208b,
+ 0x9cf5, 0x544a,
+ 0x9cf6, 0x2581,
+ 0x9cf7, 0x544b,
+ 0x9d00, 0x5454,
+ 0x9d06, 0x2583,
+ 0x9d07, 0x2582,
+ 0x9d08, 0x545a,
+ 0x9d09, 0x21ee,
+ 0x9d0a, 0x545b,
+ 0x9d15, 0x2182,
+ 0x9d16, 0x5466,
+ 0x9d1b, 0x2243,
+ 0x9d1c, 0x546b,
+ 0x9d1d, 0x2587,
+ 0x9d1e, 0x546c,
+ 0x9d1f, 0x2588,
+ 0x9d20, 0x546d,
+ 0x9d23, 0x2584,
+ 0x9d24, 0x5470,
+ 0x9d26, 0x21fd,
+ 0x9d27, 0x5472,
+ 0x9d28, 0x21ef,
+ 0x9d29, 0x5473,
+ 0x9d2f, 0x258a,
+ 0x9d30, 0x258c,
+ 0x9d31, 0x5479,
+ 0x9d3b, 0x1f47,
+ 0x9d3c, 0x5483,
+ 0x9d3f, 0x1f1d,
+ 0x9d40, 0x5486,
+ 0x9d42, 0x258d,
+ 0x9d43, 0x5488,
+ 0x9d51, 0x1fd0,
+ 0x9d52, 0x2592,
+ 0x9d53, 0x258f,
+ 0x9d54, 0x5496,
+ 0x9d5c, 0x2594,
+ 0x9d5d, 0x1ee0,
+ 0x9d5e, 0x549e,
+ 0x9d60, 0x2591,
+ 0x9d61, 0x2595,
+ 0x9d62, 0x54a0,
+ 0x9d6a, 0x2597,
+ 0x9d6b, 0x54a8,
+ 0x9d6c, 0x20b6,
+ 0x9d6d, 0x54a9,
+ 0x9d6f, 0x2598,
+ 0x9d70, 0x54ab,
+ 0x9d72, 0x20f6,
+ 0x9d73, 0x54ad,
+ 0x9d87, 0x2585,
+ 0x9d88, 0x54c1,
+ 0x9d89, 0x2599,
+ 0x9d8a, 0x54c2,
+ 0x9d93, 0x2596,
+ 0x9d94, 0x54cb,
+ 0x9d98, 0x259a,
+ 0x9d99, 0x54cf,
+ 0x9d9a, 0x259b,
+ 0x9d9b, 0x54d0,
+ 0x9da5, 0x259d,
+ 0x9da6, 0x54da,
+ 0x9da9, 0x259e,
+ 0x9daa, 0x54dd,
+ 0x9daf, 0x234c,
+ 0x9db0, 0x54e2,
+ 0x9db4, 0x1f44,
+ 0x9db5, 0x54e6,
+ 0x9dbb, 0x2660,
+ 0x9dbc, 0x25a0,
+ 0x9dbd, 0x54ec,
+ 0x9dc0, 0x259c,
+ 0x9dc1, 0x54ef,
+ 0x9dc2, 0x259f,
+ 0x9dc3, 0x54f0,
+ 0x9dc4, 0x1f6c,
+ 0x9dc5, 0x54f1,
+ 0x9dd3, 0x25a2,
+ 0x9dd4, 0x54ff,
+ 0x9dd7, 0x20ae,
+ 0x9dd8, 0x5502,
+ 0x9dd9, 0x258b,
+ 0x9dda, 0x25a3,
+ 0x9ddb, 0x5503,
+ 0x9de5, 0x2589,
+ 0x9de6, 0x25a5,
+ 0x9de7, 0x550d,
+ 0x9def, 0x25a4,
+ 0x9df0, 0x5515,
+ 0x9df2, 0x25a6,
+ 0x9df3, 0x2593,
+ 0x9df4, 0x5517,
+ 0x9df8, 0x25a7,
+ 0x9df9, 0x2222,
+ 0x9dfa, 0x25a9,
+ 0x9dfb, 0x551b,
+ 0x9e00, 0x5520,
+ 0x9e0c, 0x25a8,
+ 0x9e0d, 0x552c,
+ 0x9e15, 0x2586,
+ 0x9e16, 0x5534,
+ 0x9e1a, 0x25a1,
+ 0x9e1b, 0x25aa,
+ 0x9e1c, 0x5538,
+ 0x9e1d, 0x2590,
+ 0x9e1e, 0x258e,
+ 0x9e1f, 0x0b54,
+ 0x9e20, 0x1b35,
+ 0x9e21, 0x0819,
+ 0x9e22, 0x1b36,
+ 0x9e23, 0x0afe,
+ 0x9e24, 0x5539,
+ 0x9e25, 0x0b79,
+ 0x9e26, 0x0fe4,
+ 0x9e27, 0x553a,
+ 0x9e28, 0x1b37,
+ 0x9e2d, 0x0fe5,
+ 0x9e2e, 0x553b,
+ 0x9e2f, 0x1015,
+ 0x9e30, 0x553c,
+ 0x9e31, 0x1b3d,
+ 0x9e32, 0x1b3c,
+ 0x9e33, 0x10ea,
+ 0x9e34, 0x553d,
+ 0x9e35, 0x0e83,
+ 0x9e36, 0x1b3e,
+ 0x9e37, 0x1b40,
+ 0x9e38, 0x1b3f,
+ 0x9e39, 0x1b41,
+ 0x9e3b, 0x553e,
+ 0x9e3d, 0x06e6,
+ 0x9e3e, 0x1b43,
+ 0x9e3f, 0x079f,
+ 0x9e40, 0x5540,
+ 0x9e41, 0x1b44,
+ 0x9e43, 0x0918,
+ 0x9e44, 0x1b46,
+ 0x9e45, 0x062b,
+ 0x9e46, 0x1b47,
+ 0x9e4a, 0x0c90,
+ 0x9e4b, 0x1b4b,
+ 0x9e4d, 0x5541,
+ 0x9e4e, 0x1b4d,
+ 0x9e4f, 0x0bb5,
+ 0x9e50, 0x5542,
+ 0x9e51, 0x1b4e,
+ 0x9e52, 0x5543,
+ 0x9e55, 0x1b4f,
+ 0x9e56, 0x5546,
+ 0x9e57, 0x1b50,
+ 0x9e58, 0x1dd5,
+ 0x9e59, 0x5547,
+ 0x9e5a, 0x1b51,
+ 0x9e5d, 0x5548,
+ 0x9e5e, 0x1b54,
+ 0x9e5f, 0x5549,
+ 0x9e63, 0x1b55,
+ 0x9e64, 0x078e,
+ 0x9e65, 0x554d,
+ 0x9e66, 0x1b56,
+ 0x9e6d, 0x1b5e,
+ 0x9e6e, 0x554e,
+ 0x9e70, 0x108a,
+ 0x9e71, 0x1b5d,
+ 0x9e72, 0x5550,
+ 0x9e73, 0x1b5f,
+ 0x9e74, 0x5551,
+ 0x9e75, 0x2688,
+ 0x9e76, 0x5552,
+ 0x9e79, 0x269e,
+ 0x9e7a, 0x25fb,
+ 0x9e7b, 0x5555,
+ 0x9e7c, 0x1f8c,
+ 0x9e7d, 0x21f4,
+ 0x9e7e, 0x1d16,
+ 0x9e7f, 0x0a60,
+ 0x9e80, 0x5556,
+ 0x9e82, 0x1dfc,
+ 0x9e83, 0x5558,
+ 0x9e87, 0x1dfd,
+ 0x9e89, 0x555c,
+ 0x9e8b, 0x1dff,
+ 0x9e8c, 0x555e,
+ 0x9e92, 0x1e00,
+ 0x9e93, 0x0a5b,
+ 0x9e94, 0x5564,
+ 0x9e97, 0x200f,
+ 0x9e98, 0x5567,
+ 0x9e9d, 0x1e02,
+ 0x9e9e, 0x556c,
+ 0x9e9f, 0x1e03,
+ 0x9ea0, 0x556d,
+ 0x9ea5, 0x2071,
+ 0x9ea6, 0x0a9a,
+ 0x9ea7, 0x5572,
+ 0x9ea9, 0x25f7,
+ 0x9eaa, 0x5574,
+ 0x9eaf, 0x2696,
+ 0x9eb0, 0x5579,
+ 0x9eb4, 0x1cee,
+ 0x9eb5, 0x268f,
+ 0x9eb6, 0x557d,
+ 0x9eb8, 0x1ced,
+ 0x9eb9, 0x557f,
+ 0x9ebb, 0x0a90,
+ 0x9ebc, 0x5581,
+ 0x9ebd, 0x1df9,
+ 0x9ebf, 0x5582,
+ 0x9ec4, 0x07db,
+ 0x9ec5, 0x5587,
+ 0x9ec9, 0x12f8,
+ 0x9eca, 0x558b,
+ 0x9ecc, 0x22da,
+ 0x9ecd, 0x0d89,
+ 0x9ece, 0x09d3,
+ 0x9ecf, 0x1b2a,
+ 0x9ed0, 0x558d,
+ 0x9ed1, 0x0791,
+ 0x9ed2, 0x558e,
+ 0x9ed4, 0x0c2a,
+ 0x9ed5, 0x5590,
+ 0x9ed8, 0x0b0f,
+ 0x9ed9, 0x5593,
+ 0x9edb, 0x1e04,
+ 0x9ede, 0x1ec1,
+ 0x9edf, 0x1e08,
+ 0x9ee0, 0x1e07,
+ 0x9ee1, 0x5595,
+ 0x9ee2, 0x1e09,
+ 0x9ee3, 0x5596,
+ 0x9ee5, 0x1e0c,
+ 0x9ee6, 0x5598,
+ 0x9ee7, 0x1e0b,
+ 0x9ee8, 0x1eb3,
+ 0x9ee9, 0x1e0a,
+ 0x9eea, 0x1e0d,
+ 0x9eeb, 0x5599,
+ 0x9eef, 0x1e0e,
+ 0x9ef0, 0x559d,
+ 0x9ef2, 0x266a,
+ 0x9ef3, 0x559f,
+ 0x9ef4, 0x268a,
+ 0x9ef5, 0x55a0,
+ 0x9ef7, 0x2669,
+ 0x9ef8, 0x55a2,
+ 0x9ef9, 0x1a55,
+ 0x9efa, 0x55a3,
+ 0x9efb, 0x1a56,
+ 0x9efd, 0x2618,
+ 0x9efe, 0x1d76,
+ 0x9eff, 0x2619,
+ 0x9f00, 0x55a4,
+ 0x9f09, 0x261a,
+ 0x9f0a, 0x55ad,
+ 0x9f0b, 0x1d77,
+ 0x9f0c, 0x55ae,
+ 0x9f0d, 0x1d78,
+ 0x9f0e, 0x05e5,
+ 0x9f0f, 0x55af,
+ 0x9f10, 0x1274,
+ 0x9f11, 0x55b0,
+ 0x9f13, 0x071d,
+ 0x9f14, 0x55b2,
+ 0x9f15, 0x2673,
+ 0x9f16, 0x55b3,
+ 0x9f17, 0x1271,
+ 0x9f18, 0x55b4,
+ 0x9f19, 0x13df,
+ 0x9f1a, 0x55b5,
+ 0x9f20, 0x0d8a,
+ 0x9f21, 0x55bb,
+ 0x9f22, 0x1e0f,
+ 0x9f23, 0x55bc,
+ 0x9f2c, 0x1e10,
+ 0x9f2d, 0x55c5,
+ 0x9f2f, 0x1e11,
+ 0x9f30, 0x55c7,
+ 0x9f37, 0x1e13,
+ 0x9f38, 0x55ce,
+ 0x9f39, 0x1e12,
+ 0x9f3a, 0x55cf,
+ 0x9f3b, 0x0430,
+ 0x9f3c, 0x55d0,
+ 0x9f3d, 0x1e14,
+ 0x9f3f, 0x55d1,
+ 0x9f44, 0x1e16,
+ 0x9f45, 0x55d6,
+ 0x9f4a, 0x20c6,
+ 0x9f4b, 0x226b,
+ 0x9f4c, 0x55db,
+ 0x9f4f, 0x24d3,
+ 0x9f50, 0x0c0a,
+ 0x9f51, 0x19c2,
+ 0x9f52, 0x1e86,
+ 0x9f53, 0x55de,
+ 0x9f54, 0x260f,
+ 0x9f55, 0x55df,
+ 0x9f59, 0x2611,
+ 0x9f5a, 0x55e3,
+ 0x9f5c, 0x2613,
+ 0x9f5d, 0x55e5,
+ 0x9f5f, 0x2610,
+ 0x9f60, 0x2612,
+ 0x9f61, 0x2030,
+ 0x9f62, 0x55e7,
+ 0x9f63, 0x2671,
+ 0x9f64, 0x55e8,
+ 0x9f66, 0x2614,
+ 0x9f67, 0x55ea,
+ 0x9f6a, 0x2616,
+ 0x9f6b, 0x55ed,
+ 0x9f6c, 0x2615,
+ 0x9f6d, 0x55ee,
+ 0x9f72, 0x20f2,
+ 0x9f73, 0x55f3,
+ 0x9f77, 0x2617,
+ 0x9f78, 0x55f7,
+ 0x9f7f, 0x0502,
+ 0x9f80, 0x1d6d,
+ 0x9f81, 0x55fe,
+ 0x9f83, 0x1d6e,
+ 0x9f84, 0x0a2d,
+ 0x9f85, 0x1d6f,
+ 0x9f8b, 0x0c7e,
+ 0x9f8c, 0x1d75,
+ 0x9f8d, 0x2037,
+ 0x9f8e, 0x5600,
+ 0x9f90, 0x20b3,
+ 0x9f91, 0x5602,
+ 0x9f94, 0x1f22,
+ 0x9f95, 0x24ed,
+ 0x9f96, 0x5605,
+ 0x9f99, 0x0a43,
+ 0x9f9a, 0x0701,
+ 0x9f9b, 0x1a54,
+ 0x9f9c, 0x1f34,
+ 0x9f9d, 0x5608,
+ 0x9f9f, 0x0743,
+ 0x9fa0, 0x12f3,
+ 0x9fa1, 0x560a,
+ 0xe7e7, 0x274b,
+ 0xe815, 0x561f,
+ 0xf92c, 0x560f,
+ 0xfa0d, 0x5610,
+ 0xfa11, 0x5613,
+ 0xfa13, 0x5614,
+ 0xfa18, 0x5616,
+ 0xfa1f, 0x5617,
+ 0xfa23, 0x561a,
+ 0xfa27, 0x561c,
+ 0xfe30, 0x271d,
+ 0xfe49, 0x272b,
+ 0xfe54, 0x2735,
+ 0xfe59, 0x2739,
+ 0xfe68, 0x2747,
+ 0xff01, 0x0106,
+ 0xff04, 0x00a6,
+ 0xff05, 0x010a,
+ 0xff5e, 0x006a,
+ 0xffe0, 0x00a8,
+ 0xffe2, 0x271e,
+ 0xffe3, 0x0163,
+ 0xffe4, 0x271f,
+ 0xffe5, 0x0109,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 gb12UniGBUCS2HEnc16 = {
+ 0,
+ { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ gb12UniGBUCS2HMap2, 13461
+};
+
+static Gushort gb12UniGBUCS2VMap2[26970] = {
+ 0x0000, 0x0000,
+ 0x0020, 0x0001,
+ 0x00a4, 0x00a7,
+ 0x00a7, 0x00ab,
+ 0x00a8, 0x0066,
+ 0x00b0, 0x00a2,
+ 0x00b1, 0x007f,
+ 0x00d7, 0x0080,
+ 0x00e0, 0x029f,
+ 0x00e1, 0x029d,
+ 0x00e8, 0x02a3,
+ 0x00e9, 0x02a1,
+ 0x00ea, 0x02b5,
+ 0x00ec, 0x02a7,
+ 0x00ed, 0x02a5,
+ 0x00f2, 0x02ab,
+ 0x00f3, 0x02a9,
+ 0x00f7, 0x0081,
+ 0x00f9, 0x02af,
+ 0x00fa, 0x02ad,
+ 0x00fc, 0x02b4,
+ 0x0101, 0x029c,
+ 0x0113, 0x02a0,
+ 0x011b, 0x02a2,
+ 0x012b, 0x02a4,
+ 0x014d, 0x02a8,
+ 0x016b, 0x02ac,
+ 0x01ce, 0x029e,
+ 0x01d0, 0x02a6,
+ 0x01d2, 0x02aa,
+ 0x01d4, 0x02ae,
+ 0x01d6, 0x02b0,
+ 0x01d8, 0x02b1,
+ 0x01da, 0x02b2,
+ 0x01dc, 0x02b3,
+ 0x02c7, 0x0065,
+ 0x02c9, 0x0064,
+ 0x02ca, 0x26b3,
+ 0x02d9, 0x26b5,
+ 0x0391, 0x020d,
+ 0x03a3, 0x021e,
+ 0x03b1, 0x0225,
+ 0x03c3, 0x0236,
+ 0x0401, 0x0260,
+ 0x0410, 0x025a,
+ 0x0416, 0x0261,
+ 0x0436, 0x0282,
+ 0x0451, 0x0281,
+ 0x1e3f, 0x02b7,
+ 0x2010, 0x2722,
+ 0x2013, 0x26b6,
+ 0x2014, 0x0069,
+ 0x2015, 0x26b7,
+ 0x2016, 0x006b,
+ 0x2018, 0x006d,
+ 0x201c, 0x006f,
+ 0x2025, 0x26b8,
+ 0x2026, 0x006c,
+ 0x2030, 0x00aa,
+ 0x2032, 0x00a3,
+ 0x2035, 0x26b9,
+ 0x203b, 0x00b8,
+ 0x2103, 0x00a5,
+ 0x2105, 0x26ba,
+ 0x2109, 0x26bb,
+ 0x2116, 0x00ac,
+ 0x2121, 0x2720,
+ 0x2160, 0x00fa,
+ 0x2170, 0x26a9,
+ 0x2190, 0x00ba,
+ 0x2192, 0x00b9,
+ 0x2193, 0x00bc,
+ 0x2196, 0x26bc,
+ 0x2208, 0x0089,
+ 0x220f, 0x0086,
+ 0x2211, 0x0085,
+ 0x2215, 0x26c0,
+ 0x221a, 0x008b,
+ 0x221d, 0x0097,
+ 0x221e, 0x009d,
+ 0x221f, 0x26c1,
+ 0x2220, 0x008e,
+ 0x2223, 0x26c2,
+ 0x2225, 0x008d,
+ 0x2227, 0x0083,
+ 0x2229, 0x0088,
+ 0x222a, 0x0087,
+ 0x222b, 0x0091,
+ 0x222e, 0x0092,
+ 0x2234, 0x009f,
+ 0x2235, 0x009e,
+ 0x2236, 0x0082,
+ 0x2237, 0x008a,
+ 0x223d, 0x0096,
+ 0x2248, 0x0095,
+ 0x224c, 0x0094,
+ 0x2252, 0x26c3,
+ 0x2260, 0x0098,
+ 0x2261, 0x0093,
+ 0x2264, 0x009b,
+ 0x2266, 0x26c4,
+ 0x226e, 0x0099,
+ 0x2295, 0x2704,
+ 0x2299, 0x0090,
+ 0x22a5, 0x008c,
+ 0x22bf, 0x26c6,
+ 0x22ef, 0x006c,
+ 0x2312, 0x008f,
+ 0x2460, 0x00e6,
+ 0x2474, 0x00d2,
+ 0x2488, 0x00be,
+ 0x2500, 0x02e2,
+ 0x2550, 0x26c7,
+ 0x2581, 0x26eb,
+ 0x2593, 0x26fa,
+ 0x25a0, 0x00b5,
+ 0x25a1, 0x00b4,
+ 0x25b2, 0x00b7,
+ 0x25b3, 0x00b6,
+ 0x25bc, 0x26fd,
+ 0x25c6, 0x00b3,
+ 0x25c7, 0x00b2,
+ 0x25cb, 0x00af,
+ 0x25ce, 0x00b1,
+ 0x25cf, 0x00b0,
+ 0x25e2, 0x26ff,
+ 0x2605, 0x00ae,
+ 0x2606, 0x00ad,
+ 0x2609, 0x2703,
+ 0x2640, 0x00a1,
+ 0x2642, 0x00a0,
+ 0x3000, 0x0060,
+ 0x3003, 0x0067,
+ 0x3005, 0x0068,
+ 0x3006, 0x2728,
+ 0x3007, 0x1e17,
+ 0x3008, 0x0073,
+ 0x3010, 0x007d,
+ 0x3012, 0x2705,
+ 0x3013, 0x00bd,
+ 0x3014, 0x0071,
+ 0x3016, 0x007b,
+ 0x301d, 0x2706,
+ 0x3021, 0x2708,
+ 0x3041, 0x0164,
+ 0x309b, 0x2724,
+ 0x309d, 0x2729,
+ 0x30a1, 0x01b7,
+ 0x30fb, 0x0063,
+ 0x30fc, 0x2723,
+ 0x30fd, 0x2726,
+ 0x3105, 0x02bc,
+ 0x3220, 0x00f0,
+ 0x3231, 0x2721,
+ 0x32a3, 0x2711,
+ 0x338e, 0x2712,
+ 0x339c, 0x2714,
+ 0x33a1, 0x2717,
+ 0x33c4, 0x2718,
+ 0x33ce, 0x2719,
+ 0x33d1, 0x271a,
+ 0x33d5, 0x271c,
+ 0x4e00, 0x1042,
+ 0x4e01, 0x05e0,
+ 0x4e02, 0x2758,
+ 0x4e03, 0x0bfe,
+ 0x4e04, 0x2759,
+ 0x4e07, 0x0ea3,
+ 0x4e08, 0x116a,
+ 0x4e09, 0x0cd8,
+ 0x4e0a, 0x0d08,
+ 0x4e0b, 0x0f2f,
+ 0x4e0c, 0x1258,
+ 0x4e0d, 0x0482,
+ 0x4e0e, 0x10d0,
+ 0x4e0f, 0x275c,
+ 0x4e10, 0x125a,
+ 0x4e11, 0x0518,
+ 0x4e12, 0x275d,
+ 0x4e13, 0x1205,
+ 0x4e14, 0x0c4f,
+ 0x4e15, 0x125d,
+ 0x4e16, 0x0d57,
+ 0x4e17, 0x275e,
+ 0x4e18, 0x0c6d,
+ 0x4e19, 0x0464,
+ 0x4e1a, 0x103c,
+ 0x4e1b, 0x0557,
+ 0x4e1c, 0x05ea,
+ 0x4e1d, 0x0db4,
+ 0x4e1e, 0x125f,
+ 0x4e1f, 0x275f,
+ 0x4e22, 0x05e9,
+ 0x4e23, 0x2762,
+ 0x4e24, 0x0a06,
+ 0x4e25, 0x0ff8,
+ 0x4e26, 0x2763,
+ 0x4e27, 0x0cde,
+ 0x4e28, 0x1263,
+ 0x4e29, 0x2764,
+ 0x4e2a, 0x06f1,
+ 0x4e2b, 0x0fe7,
+ 0x4e2c, 0x169c,
+ 0x4e2d, 0x11cf,
+ 0x4e2e, 0x2765,
+ 0x4e30, 0x067e,
+ 0x4e31, 0x2767,
+ 0x4e32, 0x0531,
+ 0x4e33, 0x2768,
+ 0x4e34, 0x0a22,
+ 0x4e35, 0x2769,
+ 0x4e36, 0x1272,
+ 0x4e37, 0x276a,
+ 0x4e38, 0x0e99,
+ 0x4e39, 0x0585,
+ 0x4e3a, 0x0eb9,
+ 0x4e3b, 0x11f6,
+ 0x4e3c, 0x276b,
+ 0x4e3d, 0x09e1,
+ 0x4e3e, 0x0908,
+ 0x4e3f, 0x1265,
+ 0x4e40, 0x276c,
+ 0x4e43, 0x0b2e,
+ 0x4e44, 0x276f,
+ 0x4e45, 0x08f2,
+ 0x4e46, 0x2770,
+ 0x4e47, 0x1267,
+ 0x4e48, 0x0ab9,
+ 0x4e49, 0x106c,
+ 0x4e4a, 0x2771,
+ 0x4e4b, 0x11ad,
+ 0x4e4c, 0x0ee9,
+ 0x4e4d, 0x1148,
+ 0x4e4e, 0x07ac,
+ 0x4e4f, 0x0643,
+ 0x4e50, 0x09c1,
+ 0x4e51, 0x2772,
+ 0x4e52, 0x0bd8,
+ 0x4e53, 0x0b93,
+ 0x4e54, 0x0c44,
+ 0x4e55, 0x2773,
+ 0x4e56, 0x072d,
+ 0x4e57, 0x2774,
+ 0x4e58, 0x04f0,
+ 0x4e59, 0x1059,
+ 0x4e5a, 0x2775,
+ 0x4e5c, 0x1275,
+ 0x4e5d, 0x08f4,
+ 0x4e5e, 0x0c11,
+ 0x4e5f, 0x1039,
+ 0x4e60, 0x0f1d,
+ 0x4e61, 0x0f54,
+ 0x4e62, 0x2777,
+ 0x4e66, 0x0d80,
+ 0x4e67, 0x277b,
+ 0x4e69, 0x1276,
+ 0x4e6a, 0x277d,
+ 0x4e70, 0x0a99,
+ 0x4e71, 0x0a79,
+ 0x4e72, 0x2783,
+ 0x4e73, 0x0cc4,
+ 0x4e74, 0x2784,
+ 0x4e7e, 0x0c29,
+ 0x4e7f, 0x278e,
+ 0x4e82, 0x2059,
+ 0x4e83, 0x2791,
+ 0x4e86, 0x0a14,
+ 0x4e87, 0x2794,
+ 0x4e88, 0x10cd,
+ 0x4e89, 0x119a,
+ 0x4e8a, 0x2795,
+ 0x4e8b, 0x0d59,
+ 0x4e8c, 0x063d,
+ 0x4e8d, 0x1257,
+ 0x4e8e, 0x10bf,
+ 0x4e8f, 0x0984,
+ 0x4e90, 0x2796,
+ 0x4e91, 0x1109,
+ 0x4e92, 0x07ba,
+ 0x4e93, 0x1277,
+ 0x4e94, 0x0ef4,
+ 0x4e95, 0x08dd,
+ 0x4e96, 0x2797,
+ 0x4e98, 0x125e,
+ 0x4e99, 0x2799,
+ 0x4e9a, 0x0ff0,
+ 0x4e9b, 0x0f74,
+ 0x4e9c, 0x279a,
+ 0x4e9e, 0x21f1,
+ 0x4e9f, 0x1273,
+ 0x4ea0, 0x1303,
+ 0x4ea1, 0x0ea7,
+ 0x4ea2, 0x0947,
+ 0x4ea3, 0x279c,
+ 0x4ea4, 0x088c,
+ 0x4ea5, 0x075c,
+ 0x4ea6, 0x1067,
+ 0x4ea7, 0x04c1,
+ 0x4ea8, 0x0797,
+ 0x4ea9, 0x0b19,
+ 0x4eaa, 0x279d,
+ 0x4eab, 0x0f5a,
+ 0x4eac, 0x08d8,
+ 0x4ead, 0x0e55,
+ 0x4eae, 0x0a0a,
+ 0x4eaf, 0x279e,
+ 0x4eb2, 0x0c54,
+ 0x4eb3, 0x1305,
+ 0x4eb4, 0x27a1,
+ 0x4eb5, 0x1308,
+ 0x4eb6, 0x27a2,
+ 0x4eba, 0x0ca6,
+ 0x4ebb, 0x129f,
+ 0x4ebc, 0x27a6,
+ 0x4ebf, 0x1061,
+ 0x4ec0, 0x0d49,
+ 0x4ec1, 0x0ca5,
+ 0x4ec2, 0x12a2,
+ 0x4ec3, 0x12a0,
+ 0x4ec4, 0x127c,
+ 0x4ec5, 0x08c7,
+ 0x4ec6, 0x0bec,
+ 0x4ec7, 0x0515,
+ 0x4ec8, 0x27a9,
+ 0x4ec9, 0x12a1,
+ 0x4eca, 0x08c2,
+ 0x4ecb, 0x08ba,
+ 0x4ecc, 0x27aa,
+ 0x4ecd, 0x0caf,
+ 0x4ece, 0x0556,
+ 0x4ecf, 0x27ab,
+ 0x4ed1, 0x0a7f,
+ 0x4ed2, 0x27ad,
+ 0x4ed3, 0x049d,
+ 0x4ed4, 0x122d,
+ 0x4ed5, 0x0d62,
+ 0x4ed6, 0x0df0,
+ 0x4ed7, 0x116d,
+ 0x4ed8, 0x06b1,
+ 0x4ed9, 0x0f36,
+ 0x4eda, 0x27ae,
+ 0x4edd, 0x12ee,
+ 0x4ede, 0x12a6,
+ 0x4edf, 0x0c27,
+ 0x4ee0, 0x27b1,
+ 0x4ee1, 0x12a4,
+ 0x4ee2, 0x27b2,
+ 0x4ee3, 0x057d,
+ 0x4ee4, 0x0a37,
+ 0x4ee5, 0x105b,
+ 0x4ee6, 0x27b3,
+ 0x4ee8, 0x12a3,
+ 0x4ee9, 0x27b5,
+ 0x4eea, 0x104e,
+ 0x4eeb, 0x12a5,
+ 0x4eec, 0x0acc,
+ 0x4eed, 0x27b6,
+ 0x4ef0, 0x101f,
+ 0x4ef1, 0x27b9,
+ 0x4ef2, 0x11d8,
+ 0x4ef3, 0x12a8,
+ 0x4ef4, 0x27ba,
+ 0x4ef5, 0x12ab,
+ 0x4ef6, 0x0871,
+ 0x4ef7, 0x084e,
+ 0x4ef8, 0x27bb,
+ 0x4efb, 0x0ca9,
+ 0x4efc, 0x27be,
+ 0x4efd, 0x067a,
+ 0x4efe, 0x27bf,
+ 0x4eff, 0x065f,
+ 0x4f00, 0x27c0,
+ 0x4f01, 0x0c12,
+ 0x4f02, 0x27c1,
+ 0x4f09, 0x12ae,
+ 0x4f0a, 0x1048,
+ 0x4f0b, 0x27c8,
+ 0x4f0d, 0x0ef8,
+ 0x4f0e, 0x0832,
+ 0x4f0f, 0x0699,
+ 0x4f10, 0x0642,
+ 0x4f11, 0x0fa8,
+ 0x4f12, 0x27ca,
+ 0x4f17, 0x11d9,
+ 0x4f18, 0x10aa,
+ 0x4f19, 0x0804,
+ 0x4f1a, 0x07f6,
+ 0x4f1b, 0x12a7,
+ 0x4f1c, 0x27cf,
+ 0x4f1e, 0x0cda,
+ 0x4f1f, 0x0ebf,
+ 0x4f20, 0x052e,
+ 0x4f21, 0x27d1,
+ 0x4f22, 0x12a9,
+ 0x4f23, 0x27d2,
+ 0x4f24, 0x0d04,
+ 0x4f25, 0x12ac,
+ 0x4f26, 0x0a7e,
+ 0x4f27, 0x12ad,
+ 0x4f28, 0x27d3,
+ 0x4f2a, 0x0ec0,
+ 0x4f2b, 0x12af,
+ 0x4f2c, 0x27d5,
+ 0x4f2f, 0x0475,
+ 0x4f30, 0x0719,
+ 0x4f31, 0x27d8,
+ 0x4f32, 0x12b7,
+ 0x4f33, 0x27d9,
+ 0x4f34, 0x03f4,
+ 0x4f35, 0x27da,
+ 0x4f36, 0x0a2f,
+ 0x4f37, 0x27db,
+ 0x4f38, 0x0d25,
+ 0x4f39, 0x27dc,
+ 0x4f3a, 0x0dba,
+ 0x4f3b, 0x27dd,
+ 0x4f3c, 0x0dbb,
+ 0x4f3d, 0x12b8,
+ 0x4f3e, 0x27de,
+ 0x4f43, 0x05c9,
+ 0x4f44, 0x27e3,
+ 0x4f46, 0x058c,
+ 0x4f47, 0x27e5,
+ 0x4f4d, 0x0eca,
+ 0x4f4e, 0x05ae,
+ 0x4f4f, 0x11fe,
+ 0x4f50, 0x1251,
+ 0x4f51, 0x10b8,
+ 0x4f52, 0x27eb,
+ 0x4f53, 0x0e38,
+ 0x4f54, 0x27ec,
+ 0x4f55, 0x0785,
+ 0x4f56, 0x27ed,
+ 0x4f57, 0x12b6,
+ 0x4f58, 0x12f0,
+ 0x4f59, 0x10c5,
+ 0x4f5a, 0x12b3,
+ 0x4f5b, 0x068d,
+ 0x4f5c, 0x1254,
+ 0x4f5d, 0x12b4,
+ 0x4f5e, 0x12b0,
+ 0x4f5f, 0x12b5,
+ 0x4f60, 0x0b46,
+ 0x4f61, 0x27ee,
+ 0x4f63, 0x109b,
+ 0x4f64, 0x12aa,
+ 0x4f65, 0x12f1,
+ 0x4f66, 0x27f0,
+ 0x4f67, 0x12b1,
+ 0x4f68, 0x27f1,
+ 0x4f69, 0x0ba6,
+ 0x4f6a, 0x27f2,
+ 0x4f6c, 0x09bb,
+ 0x4f6d, 0x27f4,
+ 0x4f6f, 0x1019,
+ 0x4f70, 0x03e6,
+ 0x4f71, 0x27f6,
+ 0x4f73, 0x0844,
+ 0x4f74, 0x12ba,
+ 0x4f75, 0x27f8,
+ 0x4f76, 0x12b9,
+ 0x4f77, 0x27f9,
+ 0x4f7b, 0x12c0,
+ 0x4f7c, 0x12c2,
+ 0x4f7d, 0x27fd,
+ 0x4f7e, 0x12bf,
+ 0x4f7f, 0x0d50,
+ 0x4f80, 0x27fe,
+ 0x4f83, 0x12bd,
+ 0x4f84, 0x11b5,
+ 0x4f85, 0x2801,
+ 0x4f86, 0x1ff2,
+ 0x4f87, 0x2802,
+ 0x4f88, 0x0503,
+ 0x4f89, 0x12bc,
+ 0x4f8a, 0x2803,
+ 0x4f8b, 0x09e8,
+ 0x4f8c, 0x2804,
+ 0x4f8d, 0x0d63,
+ 0x4f8e, 0x2805,
+ 0x4f8f, 0x12be,
+ 0x4f90, 0x2806,
+ 0x4f91, 0x12bb,
+ 0x4f92, 0x2807,
+ 0x4f94, 0x12c4,
+ 0x4f95, 0x2809,
+ 0x4f96, 0x205d,
+ 0x4f97, 0x05f0,
+ 0x4f98, 0x280a,
+ 0x4f9b, 0x0702,
+ 0x4f9c, 0x280d,
+ 0x4f9d, 0x1047,
+ 0x4f9e, 0x280e,
+ 0x4fa0, 0x0f2d,
+ 0x4fa1, 0x2810,
+ 0x4fa3, 0x0a69,
+ 0x4fa4, 0x2812,
+ 0x4fa5, 0x0895,
+ 0x4fa6, 0x118d,
+ 0x4fa7, 0x04a7,
+ 0x4fa8, 0x0c45,
+ 0x4fa9, 0x0978,
+ 0x4faa, 0x12c1,
+ 0x4fab, 0x2813,
+ 0x4fac, 0x12c3,
+ 0x4fad, 0x2814,
+ 0x4fae, 0x0ef9,
+ 0x4faf, 0x07a5,
+ 0x4fb0, 0x2815,
+ 0x4fb5, 0x0c53,
+ 0x4fb6, 0x281a,
+ 0x4fbf, 0x044c,
+ 0x4fc0, 0x2823,
+ 0x4fc2, 0x269c,
+ 0x4fc3, 0x055c,
+ 0x4fc4, 0x062c,
+ 0x4fc5, 0x12c8,
+ 0x4fc6, 0x2825,
+ 0x4fca, 0x092e,
+ 0x4fcb, 0x2829,
+ 0x4fce, 0x12f2,
+ 0x4fcf, 0x0c4b,
+ 0x4fd0, 0x09e9,
+ 0x4fd1, 0x12cc,
+ 0x4fd2, 0x282c,
+ 0x4fd7, 0x0dcc,
+ 0x4fd8, 0x069a,
+ 0x4fd9, 0x2831,
+ 0x4fda, 0x12c9,
+ 0x4fdb, 0x2832,
+ 0x4fdc, 0x12cb,
+ 0x4fdd, 0x040c,
+ 0x4fde, 0x10c6,
+ 0x4fdf, 0x12cd,
+ 0x4fe0, 0x21b5,
+ 0x4fe1, 0x0f90,
+ 0x4fe2, 0x2833,
+ 0x4fe3, 0x12ca,
+ 0x4fe4, 0x2834,
+ 0x4fe6, 0x12c5,
+ 0x4fe7, 0x2836,
+ 0x4fe8, 0x12c6,
+ 0x4fe9, 0x09f2,
+ 0x4fea, 0x12c7,
+ 0x4feb, 0x2837,
+ 0x4fed, 0x0866,
+ 0x4fee, 0x0fa9,
+ 0x4fef, 0x06a4,
+ 0x4ff0, 0x2839,
+ 0x4ff1, 0x0912,
+ 0x4ff2, 0x283a,
+ 0x4ff3, 0x12d1,
+ 0x4ff4, 0x283b,
+ 0x4ff8, 0x12ce,
+ 0x4ff9, 0x283f,
+ 0x4ffa, 0x03be,
+ 0x4ffb, 0x2840,
+ 0x4ffe, 0x12d6,
+ 0x4fff, 0x2843,
+ 0x5000, 0x22cc,
+ 0x5001, 0x2844,
+ 0x5006, 0x2016,
+ 0x5007, 0x2849,
+ 0x5009, 0x1e62,
+ 0x500a, 0x284b,
+ 0x500b, 0x1f20,
+ 0x500c, 0x12d8,
+ 0x500d, 0x041f,
+ 0x500e, 0x284c,
+ 0x500f, 0x12d3,
+ 0x5010, 0x284d,
+ 0x5011, 0x207f,
+ 0x5012, 0x059a,
+ 0x5013, 0x284e,
+ 0x5014, 0x0922,
+ 0x5015, 0x284f,
+ 0x5018, 0x0e1b,
+ 0x5019, 0x07a9,
+ 0x501a, 0x1057,
+ 0x501b, 0x2852,
+ 0x501c, 0x12d7,
+ 0x501d, 0x2853,
+ 0x501f, 0x08b9,
+ 0x5020, 0x2855,
+ 0x5021, 0x04d0,
+ 0x5022, 0x2856,
+ 0x5025, 0x12d9,
+ 0x5026, 0x091a,
+ 0x5027, 0x2859,
+ 0x5028, 0x12da,
+ 0x5029, 0x12cf,
+ 0x502a, 0x0b42,
+ 0x502b, 0x205c,
+ 0x502c, 0x12d2,
+ 0x502d, 0x12d5,
+ 0x502e, 0x12d4,
+ 0x502f, 0x285a,
+ 0x503a, 0x114f,
+ 0x503b, 0x2865,
+ 0x503c, 0x11b4,
+ 0x503d, 0x2866,
+ 0x503e, 0x0c60,
+ 0x503f, 0x2867,
+ 0x5043, 0x12dc,
+ 0x5044, 0x286b,
+ 0x5047, 0x084c,
+ 0x5048, 0x12de,
+ 0x5049, 0x2194,
+ 0x504a, 0x286e,
+ 0x504c, 0x12d0,
+ 0x504d, 0x2870,
+ 0x504e, 0x12df,
+ 0x504f, 0x0bca,
+ 0x5050, 0x2871,
+ 0x5055, 0x12dd,
+ 0x5056, 0x2876,
+ 0x505a, 0x1253,
+ 0x505b, 0x287a,
+ 0x505c, 0x0e54,
+ 0x505d, 0x287b,
+ 0x5065, 0x0872,
+ 0x5066, 0x2883,
+ 0x506c, 0x12e0,
+ 0x506d, 0x2889,
+ 0x5074, 0x1e65,
+ 0x5075, 0x2281,
+ 0x5076, 0x0b7d,
+ 0x5077, 0x0e66,
+ 0x5078, 0x2890,
+ 0x507b, 0x12e1,
+ 0x507c, 0x2893,
+ 0x507e, 0x12db,
+ 0x507f, 0x04ca,
+ 0x5080, 0x098b,
+ 0x5081, 0x2895,
+ 0x5085, 0x06b0,
+ 0x5086, 0x2899,
+ 0x5088, 0x09e7,
+ 0x5089, 0x289b,
+ 0x508d, 0x0403,
+ 0x508e, 0x289f,
+ 0x5096, 0x22cd,
+ 0x5097, 0x28a7,
+ 0x5098, 0x210a,
+ 0x5099, 0x1e3e,
+ 0x509a, 0x28a8,
+ 0x50a2, 0x267f,
+ 0x50a3, 0x0579,
+ 0x50a4, 0x28b0,
+ 0x50a5, 0x12e2,
+ 0x50a6, 0x28b1,
+ 0x50a7, 0x12e3,
+ 0x50a8, 0x0525,
+ 0x50a9, 0x12e4,
+ 0x50aa, 0x28b2,
+ 0x50ac, 0x0562,
+ 0x50ad, 0x222e,
+ 0x50ae, 0x28b4,
+ 0x50b2, 0x03cc,
+ 0x50b3, 0x1e96,
+ 0x50b4, 0x22cb,
+ 0x50b5, 0x226c,
+ 0x50b6, 0x28b8,
+ 0x50b7, 0x2117,
+ 0x50b8, 0x28b9,
+ 0x50ba, 0x12e5,
+ 0x50bb, 0x0cee,
+ 0x50bc, 0x28bb,
+ 0x50be, 0x20e8,
+ 0x50bf, 0x28bd,
+ 0x50c2, 0x22d4,
+ 0x50c3, 0x28c0,
+ 0x50c5, 0x1fb9,
+ 0x50c6, 0x28c2,
+ 0x50c9, 0x22d8,
+ 0x50ca, 0x28c5,
+ 0x50cf, 0x0f5e,
+ 0x50d0, 0x28ca,
+ 0x50d1, 0x20df,
+ 0x50d2, 0x28cb,
+ 0x50d5, 0x20c2,
+ 0x50d6, 0x12e6,
+ 0x50d7, 0x28ce,
+ 0x50da, 0x0a0e,
+ 0x50db, 0x28d1,
+ 0x50de, 0x2195,
+ 0x50df, 0x28d4,
+ 0x50e5, 0x1fac,
+ 0x50e6, 0x12ea,
+ 0x50e7, 0x0ce7,
+ 0x50e8, 0x22d3,
+ 0x50e9, 0x28da,
+ 0x50ec, 0x12e9,
+ 0x50ed, 0x12e8,
+ 0x50ee, 0x12eb,
+ 0x50ef, 0x28dd,
+ 0x50f3, 0x0dd0,
+ 0x50f4, 0x28e1,
+ 0x50f5, 0x087a,
+ 0x50f6, 0x28e2,
+ 0x50f9, 0x1f81,
+ 0x50fa, 0x28e5,
+ 0x50fb, 0x0bc6,
+ 0x50fc, 0x28e6,
+ 0x5100, 0x2210,
+ 0x5101, 0x28ea,
+ 0x5102, 0x22cf,
+ 0x5103, 0x28eb,
+ 0x5104, 0x2213,
+ 0x5105, 0x28ec,
+ 0x5106, 0x12e7,
+ 0x5107, 0x12ec,
+ 0x5108, 0x1fe4,
+ 0x5109, 0x1f90,
+ 0x510a, 0x28ed,
+ 0x510b, 0x12ed,
+ 0x510c, 0x28ee,
+ 0x5110, 0x22d6,
+ 0x5111, 0x28f2,
+ 0x5112, 0x0cc0,
+ 0x5113, 0x28f3,
+ 0x5114, 0x22d0,
+ 0x5115, 0x22ce,
+ 0x5116, 0x28f4,
+ 0x5118, 0x2681,
+ 0x5119, 0x28f6,
+ 0x511f, 0x1e76,
+ 0x5120, 0x28fc,
+ 0x5121, 0x09c7,
+ 0x5122, 0x28fd,
+ 0x512a, 0x2231,
+ 0x512b, 0x2905,
+ 0x5132, 0x1e93,
+ 0x5133, 0x290c,
+ 0x5137, 0x22d2,
+ 0x5138, 0x2910,
+ 0x513a, 0x22d7,
+ 0x513b, 0x22d5,
+ 0x513c, 0x22d1,
+ 0x513d, 0x2912,
+ 0x513f, 0x0638,
+ 0x5140, 0x1259,
+ 0x5141, 0x110d,
+ 0x5142, 0x2914,
+ 0x5143, 0x10ed,
+ 0x5144, 0x0fa1,
+ 0x5145, 0x0509,
+ 0x5146, 0x1178,
+ 0x5147, 0x2915,
+ 0x5148, 0x0f35,
+ 0x5149, 0x073b,
+ 0x514a, 0x2916,
+ 0x514b, 0x0958,
+ 0x514c, 0x2917,
+ 0x514d, 0x0ae7,
+ 0x514e, 0x2918,
+ 0x5151, 0x0611,
+ 0x5152, 0x1ee5,
+ 0x5153, 0x291b,
+ 0x5154, 0x0e74,
+ 0x5155, 0x1302,
+ 0x5156, 0x1304,
+ 0x5157, 0x291c,
+ 0x515a, 0x0594,
+ 0x515b, 0x291f,
+ 0x515c, 0x05f4,
+ 0x515d, 0x2920,
+ 0x5162, 0x08d3,
+ 0x5163, 0x2925,
+ 0x5165, 0x0cc6,
+ 0x5166, 0x2927,
+ 0x5168, 0x0c86,
+ 0x5169, 0x2025,
+ 0x516a, 0x2929,
+ 0x516b, 0x03d6,
+ 0x516c, 0x0704,
+ 0x516d, 0x0a42,
+ 0x516e, 0x12f6,
+ 0x516f, 0x292a,
+ 0x5170, 0x09a7,
+ 0x5171, 0x070b,
+ 0x5172, 0x292b,
+ 0x5173, 0x0731,
+ 0x5174, 0x0f96,
+ 0x5175, 0x0461,
+ 0x5176, 0x0c03,
+ 0x5177, 0x090e,
+ 0x5178, 0x05c5,
+ 0x5179, 0x1225,
+ 0x517a, 0x292c,
+ 0x517b, 0x1021,
+ 0x517c, 0x0859,
+ 0x517d, 0x0d75,
+ 0x517e, 0x292d,
+ 0x5180, 0x0830,
+ 0x5181, 0x12fa,
+ 0x5182, 0x129d,
+ 0x5183, 0x292f,
+ 0x5185, 0x0b3d,
+ 0x5186, 0x2931,
+ 0x5188, 0x06cf,
+ 0x5189, 0x0c98,
+ 0x518a, 0x2933,
+ 0x518c, 0x04a8,
+ 0x518d, 0x111c,
+ 0x518e, 0x2935,
+ 0x5192, 0x0ab5,
+ 0x5193, 0x2939,
+ 0x5195, 0x0ae6,
+ 0x5196, 0x1314,
+ 0x5197, 0x0cba,
+ 0x5198, 0x293b,
+ 0x5199, 0x0f7f,
+ 0x519a, 0x293c,
+ 0x519b, 0x092b,
+ 0x519c, 0x0b6a,
+ 0x519d, 0x293d,
+ 0x51a0, 0x0733,
+ 0x51a1, 0x2940,
+ 0x51a2, 0x1315,
+ 0x51a3, 0x2941,
+ 0x51a4, 0x10ec,
+ 0x51a5, 0x1316,
+ 0x51a6, 0x2942,
+ 0x51ab, 0x130f,
+ 0x51ac, 0x05eb,
+ 0x51ad, 0x2947,
+ 0x51af, 0x0688,
+ 0x51b0, 0x0462,
+ 0x51b1, 0x1310,
+ 0x51b2, 0x050a,
+ 0x51b3, 0x0925,
+ 0x51b4, 0x2949,
+ 0x51b5, 0x0983,
+ 0x51b6, 0x1038,
+ 0x51b7, 0x09cf,
+ 0x51b8, 0x294a,
+ 0x51bb, 0x05f2,
+ 0x51bc, 0x1312,
+ 0x51bd, 0x1311,
+ 0x51be, 0x294d,
+ 0x51c0, 0x08ea,
+ 0x51c1, 0x294f,
+ 0x51c4, 0x0bff,
+ 0x51c5, 0x2952,
+ 0x51c6, 0x1219,
+ 0x51c7, 0x1313,
+ 0x51c8, 0x2953,
+ 0x51c9, 0x0a02,
+ 0x51ca, 0x2954,
+ 0x51cb, 0x05d3,
+ 0x51cc, 0x0a31,
+ 0x51cd, 0x1ecf,
+ 0x51ce, 0x2955,
+ 0x51cf, 0x0868,
+ 0x51d0, 0x2956,
+ 0x51d1, 0x0558,
+ 0x51d2, 0x2957,
+ 0x51db, 0x0a26,
+ 0x51dc, 0x2960,
+ 0x51dd, 0x0b60,
+ 0x51de, 0x2961,
+ 0x51e0, 0x082b,
+ 0x51e1, 0x064f,
+ 0x51e2, 0x2963,
+ 0x51e4, 0x068c,
+ 0x51e5, 0x2965,
+ 0x51eb, 0x1300,
+ 0x51ec, 0x296b,
+ 0x51ed, 0x0bdd,
+ 0x51ee, 0x296c,
+ 0x51ef, 0x093a,
+ 0x51f0, 0x07e0,
+ 0x51f1, 0x1fd9,
+ 0x51f2, 0x296d,
+ 0x51f3, 0x05ab,
+ 0x51f4, 0x296e,
+ 0x51f5, 0x1399,
+ 0x51f6, 0x0fa2,
+ 0x51f7, 0x296f,
+ 0x51f8, 0x0e6a,
+ 0x51f9, 0x03c7,
+ 0x51fa, 0x051b,
+ 0x51fb, 0x080c,
+ 0x51fc, 0x139a,
+ 0x51fd, 0x0766,
+ 0x51fe, 0x2970,
+ 0x51ff, 0x1127,
+ 0x5200, 0x0597,
+ 0x5201, 0x05d4,
+ 0x5202, 0x128c,
+ 0x5203, 0x0cab,
+ 0x5204, 0x2971,
+ 0x5206, 0x0673,
+ 0x5207, 0x0c4d,
+ 0x5208, 0x128d,
+ 0x5209, 0x2973,
+ 0x520a, 0x093c,
+ 0x520b, 0x2974,
+ 0x520d, 0x138b,
+ 0x520e, 0x128e,
+ 0x520f, 0x2976,
+ 0x5211, 0x0f97,
+ 0x5212, 0x07c3,
+ 0x5213, 0x2978,
+ 0x5216, 0x196e,
+ 0x5217, 0x0a19,
+ 0x5218, 0x0a3e,
+ 0x5219, 0x1135,
+ 0x521a, 0x06d0,
+ 0x521b, 0x0537,
+ 0x521c, 0x297b,
+ 0x521d, 0x051a,
+ 0x521e, 0x297c,
+ 0x5220, 0x0cf7,
+ 0x5221, 0x297e,
+ 0x5224, 0x0b91,
+ 0x5225, 0x2981,
+ 0x5228, 0x0b9a,
+ 0x5229, 0x09e6,
+ 0x522a, 0x2984,
+ 0x522b, 0x0459,
+ 0x522c, 0x2985,
+ 0x522d, 0x128f,
+ 0x522e, 0x0727,
+ 0x522f, 0x2986,
+ 0x5230, 0x059e,
+ 0x5231, 0x2987,
+ 0x5233, 0x1290,
+ 0x5234, 0x2989,
+ 0x5236, 0x11c5,
+ 0x5237, 0x0d97,
+ 0x5238, 0x0c8a,
+ 0x5239, 0x0ceb,
+ 0x523a, 0x054f,
+ 0x523b, 0x0959,
+ 0x523c, 0x298b,
+ 0x523d, 0x074d,
+ 0x523e, 0x298c,
+ 0x523f, 0x1291,
+ 0x5241, 0x0626,
+ 0x5242, 0x0834,
+ 0x5243, 0x0e3d,
+ 0x5244, 0x22c8,
+ 0x5245, 0x298d,
+ 0x5247, 0x2263,
+ 0x5248, 0x298f,
+ 0x524a, 0x0f64,
+ 0x524b, 0x2683,
+ 0x524c, 0x1293,
+ 0x524d, 0x0c2d,
+ 0x524e, 0x2991,
+ 0x5250, 0x0729,
+ 0x5251, 0x0874,
+ 0x5252, 0x2993,
+ 0x5254, 0x0e31,
+ 0x5255, 0x2995,
+ 0x5256, 0x0be9,
+ 0x5257, 0x2996,
+ 0x525b, 0x1f17,
+ 0x525c, 0x1296,
+ 0x525d, 0x299a,
+ 0x525e, 0x1294,
+ 0x525f, 0x299b,
+ 0x5261, 0x1295,
+ 0x5262, 0x299d,
+ 0x5265, 0x0409,
+ 0x5266, 0x29a0,
+ 0x5267, 0x0916,
+ 0x5268, 0x29a1,
+ 0x5269, 0x0d3a,
+ 0x526a, 0x0867,
+ 0x526b, 0x29a2,
+ 0x526e, 0x1f2b,
+ 0x526f, 0x06ac,
+ 0x5270, 0x29a5,
+ 0x5272, 0x06e9,
+ 0x5273, 0x29a7,
+ 0x5274, 0x22ca,
+ 0x5275, 0x1e99,
+ 0x5276, 0x29a8,
+ 0x527d, 0x1298,
+ 0x527e, 0x29af,
+ 0x527f, 0x089c,
+ 0x5280, 0x29b0,
+ 0x5281, 0x129a,
+ 0x5282, 0x1299,
+ 0x5283, 0x1f4f,
+ 0x5284, 0x29b1,
+ 0x5287, 0x1fcf,
+ 0x5288, 0x0bbd,
+ 0x5289, 0x2036,
+ 0x528a, 0x1f3a,
+ 0x528b, 0x29b4,
+ 0x528c, 0x22c9,
+ 0x528d, 0x1f99,
+ 0x528e, 0x29b5,
+ 0x5290, 0x129b,
+ 0x5291, 0x1f75,
+ 0x5292, 0x29b7,
+ 0x5293, 0x129c,
+ 0x5294, 0x29b8,
+ 0x529b, 0x09ef,
+ 0x529c, 0x29bf,
+ 0x529d, 0x0c8b,
+ 0x529e, 0x03f7,
+ 0x529f, 0x06ff,
+ 0x52a0, 0x0846,
+ 0x52a1, 0x0f00,
+ 0x52a2, 0x138d,
+ 0x52a3, 0x0a1c,
+ 0x52a4, 0x29c0,
+ 0x52a8, 0x05ee,
+ 0x52a9, 0x11f9,
+ 0x52aa, 0x0b6d,
+ 0x52ab, 0x08aa,
+ 0x52ac, 0x138e,
+ 0x52ae, 0x29c4,
+ 0x52b1, 0x09e3,
+ 0x52b2, 0x08d1,
+ 0x52b3, 0x09b8,
+ 0x52b4, 0x29c7,
+ 0x52be, 0x1390,
+ 0x52bf, 0x0d5d,
+ 0x52c0, 0x29d1,
+ 0x52c1, 0x1fbe,
+ 0x52c2, 0x29d2,
+ 0x52c3, 0x0471,
+ 0x52c4, 0x29d3,
+ 0x52c7, 0x10a7,
+ 0x52c8, 0x29d6,
+ 0x52c9, 0x0ae8,
+ 0x52ca, 0x29d7,
+ 0x52cb, 0x0fd4,
+ 0x52cc, 0x29d8,
+ 0x52d0, 0x1392,
+ 0x52d1, 0x29dc,
+ 0x52d2, 0x09c0,
+ 0x52d3, 0x29dd,
+ 0x52d5, 0x1ecd,
+ 0x52d6, 0x1393,
+ 0x52d7, 0x29df,
+ 0x52d8, 0x093e,
+ 0x52d9, 0x21a9,
+ 0x52da, 0x29e0,
+ 0x52db, 0x21e6,
+ 0x52dc, 0x29e1,
+ 0x52dd, 0x2127,
+ 0x52de, 0x2003,
+ 0x52df, 0x0b1f,
+ 0x52e0, 0x29e2,
+ 0x52e2, 0x2132,
+ 0x52e3, 0x29e4,
+ 0x52e4, 0x0c57,
+ 0x52e5, 0x29e5,
+ 0x52f0, 0x1394,
+ 0x52f1, 0x2323,
+ 0x52f2, 0x29f0,
+ 0x52f5, 0x2011,
+ 0x52f6, 0x29f3,
+ 0x52f8, 0x20f5,
+ 0x52f9, 0x12fc,
+ 0x52fa, 0x0d10,
+ 0x52fb, 0x29f5,
+ 0x52fe, 0x070d,
+ 0x52ff, 0x0eff,
+ 0x5300, 0x110b,
+ 0x5301, 0x29f8,
+ 0x5305, 0x0407,
+ 0x5306, 0x0555,
+ 0x5307, 0x29fc,
+ 0x5308, 0x0fa4,
+ 0x5309, 0x29fd,
+ 0x530d, 0x12fd,
+ 0x530e, 0x2a01,
+ 0x530f, 0x14b5,
+ 0x5310, 0x12ff,
+ 0x5311, 0x2a02,
+ 0x5315, 0x1266,
+ 0x5316, 0x07c4,
+ 0x5317, 0x041a,
+ 0x5318, 0x2a06,
+ 0x5319, 0x04fc,
+ 0x531a, 0x1284,
+ 0x531b, 0x2a07,
+ 0x531d, 0x1114,
+ 0x531e, 0x2a09,
+ 0x5320, 0x0884,
+ 0x5321, 0x097c,
+ 0x5322, 0x2a0b,
+ 0x5323, 0x0f28,
+ 0x5324, 0x2a0c,
+ 0x5326, 0x1286,
+ 0x5327, 0x2a0e,
+ 0x532a, 0x0668,
+ 0x532b, 0x2a11,
+ 0x532d, 0x22c5,
+ 0x532e, 0x1287,
+ 0x532f, 0x1f5e,
+ 0x5330, 0x2a13,
+ 0x5331, 0x22c6,
+ 0x5332, 0x2a14,
+ 0x5339, 0x0bc4,
+ 0x533a, 0x0c75,
+ 0x533b, 0x1044,
+ 0x533c, 0x2a1b,
+ 0x533e, 0x1288,
+ 0x533f, 0x0b47,
+ 0x5340, 0x20ef,
+ 0x5341, 0x0d45,
+ 0x5342, 0x2a1d,
+ 0x5343, 0x0c24,
+ 0x5344, 0x2a1e,
+ 0x5345, 0x125c,
+ 0x5346, 0x2a1f,
+ 0x5347, 0x0d36,
+ 0x5348, 0x0ef6,
+ 0x5349, 0x07f1,
+ 0x534a, 0x03f6,
+ 0x534b, 0x2a20,
+ 0x534e, 0x07bf,
+ 0x534f, 0x0f78,
+ 0x5350, 0x2a23,
+ 0x5351, 0x0419,
+ 0x5352, 0x1241,
+ 0x5353, 0x121c,
+ 0x5354, 0x21d0,
+ 0x5355, 0x0586,
+ 0x5356, 0x0a9b,
+ 0x5357, 0x0b32,
+ 0x5358, 0x2a24,
+ 0x535a, 0x0470,
+ 0x535b, 0x2a26,
+ 0x535c, 0x047e,
+ 0x535d, 0x2a27,
+ 0x535e, 0x044e,
+ 0x535f, 0x14fa,
+ 0x5360, 0x115d,
+ 0x5361, 0x0935,
+ 0x5362, 0x0a53,
+ 0x5363, 0x128b,
+ 0x5364, 0x0a58,
+ 0x5365, 0x2a28,
+ 0x5366, 0x128a,
+ 0x5367, 0x0ee3,
+ 0x5368, 0x2a29,
+ 0x5369, 0x1352,
+ 0x536a, 0x2a2a,
+ 0x536b, 0x0ecf,
+ 0x536c, 0x2a2b,
+ 0x536e, 0x126a,
+ 0x536f, 0x0ab3,
+ 0x5370, 0x1086,
+ 0x5371, 0x0eb2,
+ 0x5372, 0x2a2d,
+ 0x5373, 0x0827,
+ 0x5374, 0x0c8f,
+ 0x5375, 0x0a78,
+ 0x5376, 0x2a2e,
+ 0x5377, 0x091c,
+ 0x5378, 0x0f81,
+ 0x5379, 0x2a2f,
+ 0x537a, 0x1353,
+ 0x537b, 0x2a30,
+ 0x537f, 0x0c61,
+ 0x5380, 0x2a34,
+ 0x5382, 0x04cc,
+ 0x5383, 0x2a36,
+ 0x5384, 0x0631,
+ 0x5385, 0x0e4f,
+ 0x5386, 0x09e5,
+ 0x5387, 0x2a37,
+ 0x5389, 0x09e2,
+ 0x538a, 0x2a39,
+ 0x538b, 0x0fe2,
+ 0x538c, 0x100a,
+ 0x538d, 0x127d,
+ 0x538e, 0x2a3a,
+ 0x5395, 0x04a5,
+ 0x5396, 0x2a41,
+ 0x5398, 0x09d0,
+ 0x5399, 0x22c1,
+ 0x539a, 0x07a8,
+ 0x539b, 0x2a43,
+ 0x539d, 0x127e,
+ 0x539e, 0x2a45,
+ 0x539f, 0x10f0,
+ 0x53a0, 0x1e64,
+ 0x53a1, 0x2a46,
+ 0x53a2, 0x0f4e,
+ 0x53a3, 0x127f,
+ 0x53a4, 0x2a47,
+ 0x53a5, 0x1280,
+ 0x53a6, 0x0f30,
+ 0x53a7, 0x2a48,
+ 0x53a8, 0x051d,
+ 0x53a9, 0x08f6,
+ 0x53aa, 0x2a49,
+ 0x53ad, 0x21f9,
+ 0x53ae, 0x1281,
+ 0x53af, 0x2a4c,
+ 0x53b2, 0x2010,
+ 0x53b3, 0x2a4f,
+ 0x53b4, 0x22c2,
+ 0x53b5, 0x2a50,
+ 0x53b6, 0x139c,
+ 0x53b7, 0x2a51,
+ 0x53bb, 0x0c80,
+ 0x53bc, 0x2a55,
+ 0x53bf, 0x0f45,
+ 0x53c0, 0x2a58,
+ 0x53c1, 0x0cd9,
+ 0x53c2, 0x0495,
+ 0x53c3, 0x1e5a,
+ 0x53c4, 0x2a59,
+ 0x53c8, 0x10bb,
+ 0x53c9, 0x04ad,
+ 0x53ca, 0x0823,
+ 0x53cb, 0x10b6,
+ 0x53cc, 0x0da0,
+ 0x53cd, 0x0651,
+ 0x53ce, 0x2a5d,
+ 0x53d1, 0x063f,
+ 0x53d2, 0x2a60,
+ 0x53d4, 0x0d7c,
+ 0x53d5, 0x2a62,
+ 0x53d6, 0x0c7c,
+ 0x53d7, 0x0d73,
+ 0x53d8, 0x044d,
+ 0x53d9, 0x0fbb,
+ 0x53da, 0x2a63,
+ 0x53db, 0x0b92,
+ 0x53dc, 0x2a64,
+ 0x53df, 0x1395,
+ 0x53e0, 0x05df,
+ 0x53e1, 0x2a67,
+ 0x53e2, 0x1ea2,
+ 0x53e3, 0x0967,
+ 0x53e4, 0x071e,
+ 0x53e5, 0x0913,
+ 0x53e6, 0x0a36,
+ 0x53e7, 0x2a68,
+ 0x53e8, 0x14fe,
+ 0x53e9, 0x14fd,
+ 0x53ea, 0x11ba,
+ 0x53eb, 0x08a1,
+ 0x53ec, 0x117a,
+ 0x53ed, 0x03d3,
+ 0x53ee, 0x05e2,
+ 0x53ef, 0x0956,
+ 0x53f0, 0x0dfb,
+ 0x53f1, 0x14fb,
+ 0x53f2, 0x0d4e,
+ 0x53f3, 0x10b7,
+ 0x53f4, 0x2a69,
+ 0x53f5, 0x1285,
+ 0x53f6, 0x103d,
+ 0x53f7, 0x077c,
+ 0x53f8, 0x0db3,
+ 0x53f9, 0x0e11,
+ 0x53fa, 0x2a6a,
+ 0x53fb, 0x14ff,
+ 0x53fc, 0x05d1,
+ 0x53fd, 0x14fc,
+ 0x53fe, 0x2a6b,
+ 0x5400, 0x2a6d,
+ 0x5401, 0x10da,
+ 0x5402, 0x2a6e,
+ 0x5403, 0x04f9,
+ 0x5404, 0x06f2,
+ 0x5405, 0x2a6f,
+ 0x5406, 0x1502,
+ 0x5407, 0x2a70,
+ 0x5408, 0x0786,
+ 0x5409, 0x081d,
+ 0x540a, 0x05d6,
+ 0x540b, 0x2a71,
+ 0x540c, 0x0e5d,
+ 0x540d, 0x0b00,
+ 0x540e, 0x07aa,
+ 0x540f, 0x09df,
+ 0x5410, 0x0e73,
+ 0x5411, 0x0f5f,
+ 0x5412, 0x1500,
+ 0x5413, 0x0f32,
+ 0x5414, 0x2a72,
+ 0x5415, 0x0a67,
+ 0x5416, 0x1501,
+ 0x5417, 0x0a97,
+ 0x5418, 0x2a73,
+ 0x541b, 0x092c,
+ 0x541c, 0x2a76,
+ 0x541d, 0x0a28,
+ 0x541e, 0x0e7d,
+ 0x541f, 0x107e,
+ 0x5420, 0x066a,
+ 0x5421, 0x1509,
+ 0x5422, 0x2a77,
+ 0x5423, 0x150c,
+ 0x5424, 0x2a78,
+ 0x5426, 0x068e,
+ 0x5427, 0x03d4,
+ 0x5428, 0x0615,
+ 0x5429, 0x0671,
+ 0x542a, 0x2a7a,
+ 0x542b, 0x0763,
+ 0x542c, 0x0e50,
+ 0x542d, 0x0961,
+ 0x542e, 0x0da6,
+ 0x542f, 0x0c13,
+ 0x5430, 0x2a7b,
+ 0x5431, 0x11a7,
+ 0x5432, 0x150d,
+ 0x5433, 0x2a7c,
+ 0x5434, 0x0ef1,
+ 0x5435, 0x04d8,
+ 0x5436, 0x2a7d,
+ 0x5438, 0x0f0b,
+ 0x5439, 0x0538,
+ 0x543a, 0x2a7f,
+ 0x543b, 0x0ed6,
+ 0x543c, 0x07a7,
+ 0x543d, 0x2a80,
+ 0x543e, 0x0ef0,
+ 0x543f, 0x2a81,
+ 0x5440, 0x0fe6,
+ 0x5441, 0x2a82,
+ 0x5443, 0x1508,
+ 0x5444, 0x2a84,
+ 0x5446, 0x0577,
+ 0x5447, 0x2a86,
+ 0x5448, 0x04ef,
+ 0x5449, 0x2a87,
+ 0x544a, 0x06e1,
+ 0x544b, 0x1503,
+ 0x544c, 0x2a88,
+ 0x5450, 0x0b28,
+ 0x5451, 0x2a8c,
+ 0x5452, 0x1504,
+ 0x5455, 0x0b7c,
+ 0x5456, 0x1507,
+ 0x5457, 0x150a,
+ 0x5458, 0x10f4,
+ 0x5459, 0x150b,
+ 0x545a, 0x2a8d,
+ 0x545b, 0x0c37,
+ 0x545c, 0x0ee7,
+ 0x545d, 0x2a8e,
+ 0x5462, 0x0b3b,
+ 0x5463, 0x2a93,
+ 0x5464, 0x1512,
+ 0x5465, 0x2a94,
+ 0x5466, 0x1517,
+ 0x5467, 0x2a95,
+ 0x5468, 0x11db,
+ 0x5469, 0x2a96,
+ 0x5471, 0x1511,
+ 0x5472, 0x1522,
+ 0x5473, 0x0ec5,
+ 0x5474, 0x2a9e,
+ 0x5475, 0x077e,
+ 0x5476, 0x1516,
+ 0x5477, 0x1510,
+ 0x5478, 0x0b9f,
+ 0x5479, 0x2a9f,
+ 0x547b, 0x0d24,
+ 0x547c, 0x07ab,
+ 0x547d, 0x0b01,
+ 0x547e, 0x2aa1,
+ 0x5480, 0x0906,
+ 0x5481, 0x2aa3,
+ 0x5482, 0x150e,
+ 0x5483, 0x2aa4,
+ 0x5484, 0x1515,
+ 0x5485, 0x2aa5,
+ 0x5486, 0x0b99,
+ 0x5487, 0x2aa6,
+ 0x548b, 0x1147,
+ 0x548c, 0x0784,
+ 0x548d, 0x2aaa,
+ 0x548e, 0x08fb,
+ 0x548f, 0x10a2,
+ 0x5490, 0x06bb,
+ 0x5491, 0x2aab,
+ 0x5492, 0x11e3,
+ 0x5493, 0x2aac,
+ 0x5494, 0x150f,
+ 0x5495, 0x0717,
+ 0x5496, 0x0934,
+ 0x5497, 0x2aad,
+ 0x5499, 0x0a45,
+ 0x549a, 0x1513,
+ 0x549c, 0x2aaf,
+ 0x549d, 0x1518,
+ 0x549e, 0x2ab0,
+ 0x54a3, 0x1523,
+ 0x54a4, 0x152d,
+ 0x54a5, 0x2ab5,
+ 0x54a6, 0x151f,
+ 0x54a7, 0x151e,
+ 0x54a8, 0x1226,
+ 0x54a9, 0x152b,
+ 0x54ab, 0x1767,
+ 0x54ac, 0x102e,
+ 0x54ad, 0x151a,
+ 0x54ae, 0x2ab6,
+ 0x54af, 0x0936,
+ 0x54b0, 0x2ab7,
+ 0x54b1, 0x111e,
+ 0x54b2, 0x2ab8,
+ 0x54b3, 0x0955,
+ 0x54b4, 0x151c,
+ 0x54b5, 0x2ab9,
+ 0x54b8, 0x0f39,
+ 0x54b9, 0x2abc,
+ 0x54bb, 0x1525,
+ 0x54bc, 0x236d,
+ 0x54bd, 0x0ff3,
+ 0x54be, 0x2abe,
+ 0x54bf, 0x1526,
+ 0x54c0, 0x03b2,
+ 0x54c1, 0x0bd6,
+ 0x54c2, 0x151b,
+ 0x54c3, 0x2abf,
+ 0x54c4, 0x079c,
+ 0x54c5, 0x2ac0,
+ 0x54c6, 0x061e,
+ 0x54c7, 0x0e8c,
+ 0x54c8, 0x0757,
+ 0x54c9, 0x1118,
+ 0x54ca, 0x2ac1,
+ 0x54cc, 0x1527,
+ 0x54cd, 0x0f59,
+ 0x54ce, 0x03b0,
+ 0x54cf, 0x152f,
+ 0x54d0, 0x1519,
+ 0x54d1, 0x0fef,
+ 0x54d2, 0x151d,
+ 0x54d3, 0x1520,
+ 0x54d5, 0x1524,
+ 0x54d6, 0x2ac3,
+ 0x54d7, 0x07be,
+ 0x54d8, 0x2ac4,
+ 0x54d9, 0x1528,
+ 0x54db, 0x2ac5,
+ 0x54dc, 0x152a,
+ 0x54dd, 0x152e,
+ 0x54de, 0x1530,
+ 0x54df, 0x1099,
+ 0x54e0, 0x2ac6,
+ 0x54e1, 0x2247,
+ 0x54e2, 0x2ac7,
+ 0x54e5, 0x06e2,
+ 0x54e6, 0x0b77,
+ 0x54e7, 0x1532,
+ 0x54e8, 0x0d13,
+ 0x54e9, 0x09f1,
+ 0x54ea, 0x0b27,
+ 0x54eb, 0x2aca,
+ 0x54ed, 0x096b,
+ 0x54ee, 0x0f65,
+ 0x54ef, 0x2acc,
+ 0x54f2, 0x117d,
+ 0x54f3, 0x1536,
+ 0x54f4, 0x2acf,
+ 0x54fa, 0x047f,
+ 0x54fb, 0x2ad5,
+ 0x54fc, 0x0796,
+ 0x54fd, 0x1534,
+ 0x54fe, 0x2ad6,
+ 0x54ff, 0x1391,
+ 0x5500, 0x2ad7,
+ 0x5501, 0x100d,
+ 0x5502, 0x2ad8,
+ 0x5504, 0x236c,
+ 0x5505, 0x2ada,
+ 0x5506, 0x0de9,
+ 0x5507, 0x0540,
+ 0x5508, 0x2adb,
+ 0x5509, 0x03b1,
+ 0x550a, 0x2adc,
+ 0x550f, 0x1539,
+ 0x5510, 0x0e19,
+ 0x5511, 0x153a,
+ 0x5512, 0x2ae1,
+ 0x5514, 0x1535,
+ 0x5515, 0x2ae3,
+ 0x551b, 0x1531,
+ 0x551c, 0x2ae9,
+ 0x5520, 0x1533,
+ 0x5521, 0x2aed,
+ 0x5522, 0x1537,
+ 0x5524, 0x07d2,
+ 0x5525, 0x2aee,
+ 0x5527, 0x153b,
+ 0x5528, 0x2af0,
+ 0x552a, 0x153c,
+ 0x552b, 0x2af2,
+ 0x552c, 0x07b8,
+ 0x552d, 0x2af3,
+ 0x552e, 0x0d72,
+ 0x552f, 0x0eb7,
+ 0x5530, 0x154d,
+ 0x5531, 0x04cf,
+ 0x5532, 0x2af4,
+ 0x5533, 0x154c,
+ 0x5534, 0x2af5,
+ 0x5537, 0x1547,
+ 0x5538, 0x2af8,
+ 0x553c, 0x1546,
+ 0x553d, 0x2afc,
+ 0x553e, 0x0e8a,
+ 0x553f, 0x1544,
+ 0x5540, 0x2afd,
+ 0x5541, 0x1542,
+ 0x5542, 0x2afe,
+ 0x5543, 0x095d,
+ 0x5544, 0x1221,
+ 0x5545, 0x2aff,
+ 0x5546, 0x0d05,
+ 0x5547, 0x2b00,
+ 0x5549, 0x1540,
+ 0x554a, 0x03ac,
+ 0x554b, 0x2b02,
+ 0x554f, 0x219c,
+ 0x5550, 0x1545,
+ 0x5551, 0x2b06,
+ 0x5553, 0x20c9,
+ 0x5554, 0x2b08,
+ 0x5555, 0x1543,
+ 0x5556, 0x1548,
+ 0x5557, 0x2b09,
+ 0x555c, 0x154e,
+ 0x555d, 0x2b0e,
+ 0x555e, 0x21f0,
+ 0x555f, 0x2b0f,
+ 0x5561, 0x0665,
+ 0x5562, 0x2b11,
+ 0x5564, 0x0bc0,
+ 0x5565, 0x0cef,
+ 0x5566, 0x099d,
+ 0x5567, 0x153d,
+ 0x5568, 0x2b13,
+ 0x556a, 0x0b7f,
+ 0x556b, 0x2b15,
+ 0x556c, 0x127a,
+ 0x556d, 0x1541,
+ 0x556e, 0x0b59,
+ 0x556f, 0x2b16,
+ 0x5575, 0x1549,
+ 0x5578, 0x0f70,
+ 0x5579, 0x2b1c,
+ 0x557b, 0x155a,
+ 0x557c, 0x0e37,
+ 0x557d, 0x2b1e,
+ 0x557e, 0x1557,
+ 0x557f, 0x2b1f,
+ 0x5580, 0x0933,
+ 0x5581, 0x1555,
+ 0x5582, 0x0ec8,
+ 0x5583, 0x1551,
+ 0x5584, 0x0cff,
+ 0x5585, 0x2b20,
+ 0x5587, 0x0999,
+ 0x5588, 0x1554,
+ 0x5589, 0x07a4,
+ 0x558a, 0x0767,
+ 0x558b, 0x154f,
+ 0x558c, 0x2b22,
+ 0x558f, 0x153e,
+ 0x5590, 0x2b25,
+ 0x5591, 0x1559,
+ 0x5592, 0x2b26,
+ 0x5594, 0x155e,
+ 0x5595, 0x2b28,
+ 0x5598, 0x0530,
+ 0x5599, 0x155f,
+ 0x559a, 0x2b2b,
+ 0x559c, 0x0f1f,
+ 0x559d, 0x077f,
+ 0x559e, 0x2b2d,
+ 0x559f, 0x1556,
+ 0x55a0, 0x2b2e,
+ 0x55a7, 0x0fc5,
+ 0x55a8, 0x2b35,
+ 0x55aa, 0x210b,
+ 0x55ab, 0x2b37,
+ 0x55ac, 0x20de,
+ 0x55ad, 0x2b38,
+ 0x55ae, 0x1eaa,
+ 0x55af, 0x2b39,
+ 0x55b1, 0x1552,
+ 0x55b2, 0x222c,
+ 0x55b3, 0x113e,
+ 0x55b4, 0x2b3b,
+ 0x55b5, 0x153f,
+ 0x55b6, 0x2b3c,
+ 0x55b7, 0x0ba8,
+ 0x55b8, 0x2b3d,
+ 0x55b9, 0x1553,
+ 0x55ba, 0x2b3e,
+ 0x55bb, 0x10dc,
+ 0x55bc, 0x2b3f,
+ 0x55bd, 0x155c,
+ 0x55bf, 0x2b40,
+ 0x55c4, 0x156a,
+ 0x55c5, 0x0fac,
+ 0x55c6, 0x20d8,
+ 0x55c7, 0x22c0,
+ 0x55c8, 0x2b45,
+ 0x55c9, 0x1562,
+ 0x55ca, 0x2b46,
+ 0x55cc, 0x156f,
+ 0x55ce, 0x206f,
+ 0x55cf, 0x2b48,
+ 0x55d1, 0x1564,
+ 0x55d2, 0x1550,
+ 0x55d3, 0x0cdd,
+ 0x55d4, 0x1567,
+ 0x55d5, 0x2b4a,
+ 0x55d6, 0x1558,
+ 0x55d7, 0x2b4b,
+ 0x55da, 0x21a1,
+ 0x55db, 0x2b4e,
+ 0x55dc, 0x0d5f,
+ 0x55dd, 0x1569,
+ 0x55de, 0x2b4f,
+ 0x55df, 0x155b,
+ 0x55e0, 0x2b50,
+ 0x55e1, 0x0eda,
+ 0x55e2, 0x2b51,
+ 0x55e3, 0x0db8,
+ 0x55e4, 0x1573,
+ 0x55e5, 0x156c,
+ 0x55e6, 0x1568,
+ 0x55e7, 0x2b52,
+ 0x55e8, 0x1571,
+ 0x55e9, 0x2379,
+ 0x55ea, 0x1560,
+ 0x55eb, 0x1565,
+ 0x55ed, 0x2b53,
+ 0x55ef, 0x156b,
+ 0x55f0, 0x2b55,
+ 0x55f2, 0x156d,
+ 0x55f4, 0x2b57,
+ 0x55f5, 0x1572,
+ 0x55f6, 0x2372,
+ 0x55f7, 0x1561,
+ 0x55f8, 0x2b58,
+ 0x55fd, 0x0dc9,
+ 0x55fe, 0x157b,
+ 0x55ff, 0x2b5d,
+ 0x5600, 0x157c,
+ 0x5601, 0x1578,
+ 0x5602, 0x2b5e,
+ 0x5606, 0x216a,
+ 0x5607, 0x2b62,
+ 0x5608, 0x1576,
+ 0x5609, 0x0841,
+ 0x560a, 0x2b63,
+ 0x560c, 0x1577,
+ 0x560d, 0x237c,
+ 0x560e, 0x06bd,
+ 0x560f, 0x127b,
+ 0x5610, 0x2b65,
+ 0x5614, 0x20b0,
+ 0x5615, 0x2b69,
+ 0x5616, 0x237a,
+ 0x5617, 0x1e74,
+ 0x5618, 0x0fb5,
+ 0x5619, 0x2b6a,
+ 0x561b, 0x0a96,
+ 0x561c, 0x2377,
+ 0x561d, 0x2b6c,
+ 0x561e, 0x1575,
+ 0x561f, 0x1563,
+ 0x5620, 0x2b6d,
+ 0x5623, 0x157a,
+ 0x5624, 0x1579,
+ 0x5625, 0x2b70,
+ 0x5627, 0x157d,
+ 0x5628, 0x2b72,
+ 0x5629, 0x1f4c,
+ 0x562a, 0x2b73,
+ 0x562c, 0x1582,
+ 0x562d, 0x157e,
+ 0x562e, 0x2378,
+ 0x562f, 0x21cf,
+ 0x5630, 0x2368,
+ 0x5631, 0x11f5,
+ 0x5632, 0x04d5,
+ 0x5633, 0x2b75,
+ 0x5634, 0x1249,
+ 0x5635, 0x2371,
+ 0x5636, 0x0db0,
+ 0x5637, 0x2b76,
+ 0x5638, 0x2369,
+ 0x5639, 0x1580,
+ 0x563a, 0x2b77,
+ 0x563b, 0x0f0a,
+ 0x563c, 0x2b78,
+ 0x563f, 0x0790,
+ 0x5640, 0x2b7b,
+ 0x5641, 0x2674,
+ 0x5642, 0x2b7c,
+ 0x564c, 0x1587,
+ 0x564d, 0x1583,
+ 0x564e, 0x1034,
+ 0x564f, 0x2b86,
+ 0x5654, 0x1588,
+ 0x5655, 0x2b8b,
+ 0x5657, 0x1581,
+ 0x5658, 0x157f,
+ 0x5659, 0x1585,
+ 0x565a, 0x2b8d,
+ 0x565c, 0x1586,
+ 0x565d, 0x236f,
+ 0x565e, 0x2b8f,
+ 0x5660, 0x2370,
+ 0x5661, 0x2b91,
+ 0x5662, 0x1584,
+ 0x5663, 0x2b92,
+ 0x5664, 0x158a,
+ 0x5665, 0x2376,
+ 0x5666, 0x2373,
+ 0x5667, 0x2b93,
+ 0x5668, 0x0c16,
+ 0x5669, 0x1262,
+ 0x566a, 0x112e,
+ 0x566b, 0x158c,
+ 0x566c, 0x0d60,
+ 0x566d, 0x2b94,
+ 0x566f, 0x237f,
+ 0x5670, 0x2b96,
+ 0x5671, 0x158b,
+ 0x5672, 0x2374,
+ 0x5673, 0x2b97,
+ 0x5674, 0x20b5,
+ 0x5675, 0x2b98,
+ 0x5676, 0x06bc,
+ 0x5677, 0x2b99,
+ 0x5678, 0x1edb,
+ 0x5679, 0x2672,
+ 0x567a, 0x2b9a,
+ 0x567b, 0x158d,
+ 0x567d, 0x2b9b,
+ 0x5680, 0x236e,
+ 0x5681, 0x2b9e,
+ 0x5685, 0x158f,
+ 0x5686, 0x1589,
+ 0x5687, 0x21b7,
+ 0x5688, 0x2ba2,
+ 0x568c, 0x2375,
+ 0x568d, 0x2ba6,
+ 0x568e, 0x0776,
+ 0x568f, 0x0e3a,
+ 0x5690, 0x2ba7,
+ 0x5693, 0x1590,
+ 0x5694, 0x2baa,
+ 0x5695, 0x2382,
+ 0x5696, 0x2bab,
+ 0x5699, 0x209e,
+ 0x569a, 0x2bae,
+ 0x56a3, 0x0f66,
+ 0x56a4, 0x2bb7,
+ 0x56a6, 0x236b,
+ 0x56a7, 0x2bb9,
+ 0x56a8, 0x2039,
+ 0x56a9, 0x2bba,
+ 0x56ae, 0x269f,
+ 0x56af, 0x1591,
+ 0x56b0, 0x2bbf,
+ 0x56b3, 0x237d,
+ 0x56b4, 0x21f5,
+ 0x56b5, 0x2bc2,
+ 0x56b6, 0x2381,
+ 0x56b7, 0x0c9d,
+ 0x56b8, 0x2bc3,
+ 0x56bc, 0x0891,
+ 0x56bd, 0x2bc7,
+ 0x56c0, 0x237b,
+ 0x56c1, 0x237e,
+ 0x56c2, 0x21cc,
+ 0x56c3, 0x2bca,
+ 0x56c5, 0x22db,
+ 0x56c6, 0x2bcc,
+ 0x56c8, 0x236a,
+ 0x56c9, 0x2689,
+ 0x56ca, 0x0b35,
+ 0x56cb, 0x2bce,
+ 0x56cc, 0x2697,
+ 0x56cd, 0x2bcf,
+ 0x56d1, 0x22a1,
+ 0x56d2, 0x2bd3,
+ 0x56d4, 0x1592,
+ 0x56d5, 0x2bd5,
+ 0x56d7, 0x1593,
+ 0x56d8, 0x2bd7,
+ 0x56da, 0x0c71,
+ 0x56db, 0x0db9,
+ 0x56dc, 0x2bd9,
+ 0x56dd, 0x1594,
+ 0x56de, 0x07ed,
+ 0x56df, 0x126c,
+ 0x56e0, 0x1079,
+ 0x56e1, 0x1595,
+ 0x56e2, 0x0e76,
+ 0x56e3, 0x2bda,
+ 0x56e4, 0x0619,
+ 0x56e5, 0x2bdb,
+ 0x56eb, 0x1597,
+ 0x56ec, 0x2be1,
+ 0x56ed, 0x10f3,
+ 0x56ee, 0x2be2,
+ 0x56f0, 0x0992,
+ 0x56f1, 0x0554,
+ 0x56f2, 0x2be4,
+ 0x56f4, 0x0eb6,
+ 0x56f5, 0x1596,
+ 0x56f6, 0x2be6,
+ 0x56f9, 0x1598,
+ 0x56fa, 0x0725,
+ 0x56fb, 0x2be9,
+ 0x56fd, 0x0753,
+ 0x56fe, 0x0e6d,
+ 0x56ff, 0x1599,
+ 0x5700, 0x2beb,
+ 0x5703, 0x0bf3,
+ 0x5704, 0x159a,
+ 0x5705, 0x2bee,
+ 0x5706, 0x10f5,
+ 0x5707, 0x2383,
+ 0x5708, 0x0c81,
+ 0x5709, 0x159c,
+ 0x570a, 0x159b,
+ 0x570b, 0x1f3d,
+ 0x570c, 0x2bef,
+ 0x570d, 0x218f,
+ 0x570e, 0x2bf0,
+ 0x5712, 0x2246,
+ 0x5713, 0x2248,
+ 0x5714, 0x2bf4,
+ 0x5716, 0x217e,
+ 0x5717, 0x2bf6,
+ 0x5718, 0x2180,
+ 0x5719, 0x2bf7,
+ 0x571c, 0x159d,
+ 0x571d, 0x2bfa,
+ 0x571f, 0x0e72,
+ 0x5720, 0x2bfc,
+ 0x5723, 0x0d3c,
+ 0x5724, 0x2bff,
+ 0x5728, 0x111d,
+ 0x5729, 0x13a7,
+ 0x572a, 0x13a9,
+ 0x572b, 0x2c03,
+ 0x572c, 0x13a8,
+ 0x572d, 0x0740,
+ 0x572e, 0x13ac,
+ 0x5730, 0x05b9,
+ 0x5731, 0x2c04,
+ 0x5733, 0x13aa,
+ 0x5734, 0x2c06,
+ 0x5739, 0x13ab,
+ 0x573a, 0x04c6,
+ 0x573b, 0x13af,
+ 0x573c, 0x2c0b,
+ 0x573e, 0x080d,
+ 0x573f, 0x2c0d,
+ 0x5740, 0x11b6,
+ 0x5741, 0x2c0e,
+ 0x5742, 0x13b0,
+ 0x5743, 0x2c0f,
+ 0x5747, 0x0928,
+ 0x5748, 0x2c13,
+ 0x574a, 0x0658,
+ 0x574b, 0x2c15,
+ 0x574c, 0x13a0,
+ 0x574d, 0x0e01,
+ 0x574e, 0x093f,
+ 0x574f, 0x07ca,
+ 0x5750, 0x1255,
+ 0x5751, 0x0960,
+ 0x5752, 0x2c16,
+ 0x5757, 0x0976,
+ 0x5758, 0x2c1b,
+ 0x575a, 0x0854,
+ 0x575b, 0x0e06,
+ 0x575c, 0x13ae,
+ 0x575d, 0x03de,
+ 0x575e, 0x0efa,
+ 0x575f, 0x0675,
+ 0x5760, 0x1216,
+ 0x5761, 0x0be1,
+ 0x5762, 0x2c1d,
+ 0x5764, 0x098f,
+ 0x5765, 0x2c1f,
+ 0x5766, 0x0e0c,
+ 0x5767, 0x2c20,
+ 0x5768, 0x13b7,
+ 0x5769, 0x13b1,
+ 0x576a, 0x0bd9,
+ 0x576b, 0x13b3,
+ 0x576c, 0x2c21,
+ 0x576d, 0x13b8,
+ 0x576e, 0x2c22,
+ 0x576f, 0x0bb8,
+ 0x5770, 0x2c23,
+ 0x5773, 0x13ba,
+ 0x5774, 0x2c26,
+ 0x5776, 0x13b9,
+ 0x5777, 0x094d,
+ 0x5778, 0x2c28,
+ 0x577b, 0x13b6,
+ 0x577c, 0x13b5,
+ 0x577d, 0x2c2b,
+ 0x5782, 0x053c,
+ 0x5783, 0x0997,
+ 0x5784, 0x0a49,
+ 0x5785, 0x13b2,
+ 0x5786, 0x13b4,
+ 0x5787, 0x2c30,
+ 0x578b, 0x0f98,
+ 0x578c, 0x13bd,
+ 0x578d, 0x2c34,
+ 0x5792, 0x09c8,
+ 0x5793, 0x13c2,
+ 0x5794, 0x2c39,
+ 0x579b, 0x0621,
+ 0x579c, 0x2c40,
+ 0x57a0, 0x13c3,
+ 0x57a1, 0x13a2,
+ 0x57a2, 0x0711,
+ 0x57a3, 0x10ee,
+ 0x57a4, 0x13bc,
+ 0x57a5, 0x2c44,
+ 0x57a6, 0x095e,
+ 0x57a7, 0x13c0,
+ 0x57a8, 0x2c45,
+ 0x57a9, 0x13a1,
+ 0x57aa, 0x2c46,
+ 0x57ab, 0x05c7,
+ 0x57ac, 0x2c47,
+ 0x57ad, 0x13bb,
+ 0x57ae, 0x0972,
+ 0x57af, 0x2c48,
+ 0x57b2, 0x13be,
+ 0x57b3, 0x2c4b,
+ 0x57b4, 0x13c1,
+ 0x57b5, 0x2c4c,
+ 0x57b8, 0x13c9,
+ 0x57b9, 0x2c4f,
+ 0x57c2, 0x06fa,
+ 0x57c3, 0x03ae,
+ 0x57c4, 0x2c58,
+ 0x57cb, 0x0a98,
+ 0x57cc, 0x2c5f,
+ 0x57ce, 0x04ec,
+ 0x57cf, 0x13bf,
+ 0x57d0, 0x2c61,
+ 0x57d2, 0x13c8,
+ 0x57d3, 0x2c63,
+ 0x57d4, 0x0bf1,
+ 0x57d5, 0x13c4,
+ 0x57d6, 0x2c64,
+ 0x57d8, 0x13c5,
+ 0x57d9, 0x13c7,
+ 0x57da, 0x13c6,
+ 0x57db, 0x2c66,
+ 0x57dd, 0x13ce,
+ 0x57de, 0x2c68,
+ 0x57df, 0x10d7,
+ 0x57e0, 0x0481,
+ 0x57e1, 0x232a,
+ 0x57e2, 0x2c69,
+ 0x57e4, 0x13cd,
+ 0x57e5, 0x2c6b,
+ 0x57ed, 0x13d2,
+ 0x57ee, 0x2c73,
+ 0x57ef, 0x13cb,
+ 0x57f0, 0x2c74,
+ 0x57f4, 0x13ca,
+ 0x57f5, 0x2c78,
+ 0x57f7, 0x228b,
+ 0x57f8, 0x13cc,
+ 0x57f9, 0x0ba1,
+ 0x57fa, 0x080e,
+ 0x57fb, 0x2c7a,
+ 0x57fd, 0x13d1,
+ 0x57fe, 0x2c7c,
+ 0x5800, 0x13d3,
+ 0x5801, 0x2c7e,
+ 0x5802, 0x0e16,
+ 0x5803, 0x2c7f,
+ 0x5805, 0x1f85,
+ 0x5806, 0x0610,
+ 0x5807, 0x144c,
+ 0x5808, 0x2c81,
+ 0x580a, 0x2325,
+ 0x580b, 0x13cf,
+ 0x580c, 0x2c83,
+ 0x580d, 0x13d0,
+ 0x580e, 0x2c84,
+ 0x5811, 0x0c32,
+ 0x5812, 0x2c87,
+ 0x5815, 0x0628,
+ 0x5816, 0x232c,
+ 0x5817, 0x2c8a,
+ 0x5819, 0x13d5,
+ 0x581a, 0x2c8c,
+ 0x581d, 0x232e,
+ 0x581e, 0x13d4,
+ 0x581f, 0x2c8f,
+ 0x5820, 0x13d7,
+ 0x5821, 0x040d,
+ 0x5822, 0x2c90,
+ 0x5824, 0x05ad,
+ 0x5825, 0x2c92,
+ 0x582a, 0x093d,
+ 0x582b, 0x2c97,
+ 0x582f, 0x2205,
+ 0x5830, 0x1008,
+ 0x5831, 0x1e38,
+ 0x5832, 0x2c9b,
+ 0x5834, 0x1e73,
+ 0x5835, 0x0601,
+ 0x5836, 0x2c9d,
+ 0x5844, 0x13d6,
+ 0x5845, 0x2cab,
+ 0x584a, 0x1fe3,
+ 0x584b, 0x2339,
+ 0x584c, 0x0def,
+ 0x584d, 0x19a3,
+ 0x584e, 0x2cb0,
+ 0x584f, 0x232b,
+ 0x5850, 0x2cb1,
+ 0x5851, 0x0dd1,
+ 0x5852, 0x232d,
+ 0x5853, 0x2cb2,
+ 0x5854, 0x0df3,
+ 0x5855, 0x2cb3,
+ 0x5857, 0x217f,
+ 0x5858, 0x0e14,
+ 0x5859, 0x2cb5,
+ 0x585e, 0x0cd6,
+ 0x585f, 0x2cba,
+ 0x5862, 0x21a7,
+ 0x5863, 0x2cbd,
+ 0x5864, 0x232f,
+ 0x5865, 0x13d8,
+ 0x5866, 0x2cbe,
+ 0x586b, 0x0e41,
+ 0x586c, 0x13d9,
+ 0x586d, 0x2cc3,
+ 0x5875, 0x1e7d,
+ 0x5876, 0x2ccb,
+ 0x5879, 0x20d6,
+ 0x587a, 0x2cce,
+ 0x587e, 0x13a3,
+ 0x587f, 0x2cd2,
+ 0x5880, 0x13dd,
+ 0x5881, 0x13da,
+ 0x5882, 0x2cd3,
+ 0x5883, 0x08e2,
+ 0x5884, 0x2cd4,
+ 0x5885, 0x0d92,
+ 0x5886, 0x2cd5,
+ 0x5889, 0x13db,
+ 0x588a, 0x1ec2,
+ 0x588b, 0x2cd8,
+ 0x5892, 0x0d03,
+ 0x5893, 0x0b1c,
+ 0x5894, 0x2cdf,
+ 0x5899, 0x0c3a,
+ 0x589a, 0x13dc,
+ 0x589b, 0x2ce4,
+ 0x589c, 0x22b2,
+ 0x589d, 0x2ce5,
+ 0x589e, 0x1139,
+ 0x589f, 0x0fb1,
+ 0x58a0, 0x2ce6,
+ 0x58a8, 0x0b0e,
+ 0x58a9, 0x0614,
+ 0x58aa, 0x2cee,
+ 0x58ae, 0x1edf,
+ 0x58af, 0x2cf2,
+ 0x58b3, 0x1ef9,
+ 0x58b4, 0x2cf6,
+ 0x58bb, 0x20d9,
+ 0x58bc, 0x13a4,
+ 0x58bd, 0x2cfd,
+ 0x58be, 0x1fdd,
+ 0x58bf, 0x2cfe,
+ 0x58c1, 0x0443,
+ 0x58c2, 0x2d00,
+ 0x58c5, 0x13a5,
+ 0x58c6, 0x2d03,
+ 0x58c7, 0x2167,
+ 0x58c8, 0x2d04,
+ 0x58d1, 0x13a6,
+ 0x58d2, 0x2d0d,
+ 0x58d3, 0x21ed,
+ 0x58d4, 0x2d0e,
+ 0x58d5, 0x0775,
+ 0x58d6, 0x2d0f,
+ 0x58d8, 0x2007,
+ 0x58d9, 0x2326,
+ 0x58da, 0x2329,
+ 0x58db, 0x2d11,
+ 0x58de, 0x1f52,
+ 0x58df, 0x203b,
+ 0x58e0, 0x2328,
+ 0x58e1, 0x2d14,
+ 0x58e2, 0x2327,
+ 0x58e3, 0x2d15,
+ 0x58e4, 0x0c9b,
+ 0x58e5, 0x2d16,
+ 0x58e9, 0x1e2b,
+ 0x58ea, 0x2d1a,
+ 0x58eb, 0x0d56,
+ 0x58ec, 0x0ca4,
+ 0x58ed, 0x2d1b,
+ 0x58ee, 0x1210,
+ 0x58ef, 0x22ae,
+ 0x58f0, 0x0d32,
+ 0x58f1, 0x2d1c,
+ 0x58f3, 0x0954,
+ 0x58f4, 0x2d1e,
+ 0x58f6, 0x07af,
+ 0x58f7, 0x2d20,
+ 0x58f9, 0x1043,
+ 0x58fa, 0x1f49,
+ 0x58fb, 0x2d22,
+ 0x58fd, 0x2138,
+ 0x58fe, 0x2d24,
+ 0x5900, 0x2d26,
+ 0x5902, 0x161c,
+ 0x5903, 0x2d28,
+ 0x5904, 0x0529,
+ 0x5905, 0x2d29,
+ 0x5907, 0x0421,
+ 0x5908, 0x2d2b,
+ 0x590d, 0x06af,
+ 0x590e, 0x2d30,
+ 0x590f, 0x0f31,
+ 0x5910, 0x2d31,
+ 0x5914, 0x12fb,
+ 0x5915, 0x0f13,
+ 0x5916, 0x0e93,
+ 0x5917, 0x2d35,
+ 0x5919, 0x1301,
+ 0x591a, 0x061f,
+ 0x591b, 0x2d37,
+ 0x591c, 0x1040,
+ 0x591d, 0x2d38,
+ 0x591f, 0x0714,
+ 0x5920, 0x2d3a,
+ 0x5922, 0x2081,
+ 0x5923, 0x2d3c,
+ 0x5924, 0x161b,
+ 0x5925, 0x1619,
+ 0x5926, 0x2d3d,
+ 0x5927, 0x0576,
+ 0x5928, 0x2d3e,
+ 0x5929, 0x0e3f,
+ 0x592a, 0x0dfe,
+ 0x592b, 0x068f,
+ 0x592c, 0x2d3f,
+ 0x592d, 0x1268,
+ 0x592e, 0x1014,
+ 0x592f, 0x0772,
+ 0x5930, 0x2d40,
+ 0x5931, 0x0d3e,
+ 0x5932, 0x2d41,
+ 0x5934, 0x0e68,
+ 0x5935, 0x2d43,
+ 0x5937, 0x104b,
+ 0x5938, 0x0971,
+ 0x5939, 0x0843,
+ 0x593a, 0x0620,
+ 0x593b, 0x2d45,
+ 0x593c, 0x14af,
+ 0x593d, 0x2d46,
+ 0x593e, 0x1f7c,
+ 0x593f, 0x2d47,
+ 0x5941, 0x14b0,
+ 0x5942, 0x138c,
+ 0x5943, 0x2d49,
+ 0x5944, 0x1002,
+ 0x5945, 0x2d4a,
+ 0x5947, 0x0c05,
+ 0x5948, 0x0b31,
+ 0x5949, 0x068b,
+ 0x594a, 0x2d4c,
+ 0x594b, 0x0679,
+ 0x594c, 0x2d4d,
+ 0x594e, 0x0989,
+ 0x594f, 0x123d,
+ 0x5950, 0x2d4f,
+ 0x5951, 0x0c14,
+ 0x5952, 0x2d50,
+ 0x5954, 0x0425,
+ 0x5955, 0x14b2,
+ 0x5956, 0x0882,
+ 0x5957, 0x0e2a,
+ 0x5958, 0x14b4,
+ 0x5959, 0x2d52,
+ 0x595a, 0x14b3,
+ 0x595b, 0x2d53,
+ 0x5960, 0x05cd,
+ 0x5961, 0x2d58,
+ 0x5962, 0x0d16,
+ 0x5963, 0x2d59,
+ 0x5965, 0x03cd,
+ 0x5966, 0x2d5b,
+ 0x5969, 0x235b,
+ 0x596a, 0x1ede,
+ 0x596b, 0x2d5e,
+ 0x596c, 0x1fa2,
+ 0x596d, 0x2d5f,
+ 0x596e, 0x1efa,
+ 0x596f, 0x2d60,
+ 0x5973, 0x0b6f,
+ 0x5974, 0x0b6c,
+ 0x5975, 0x2d64,
+ 0x5976, 0x0b2f,
+ 0x5977, 0x2d65,
+ 0x5978, 0x085c,
+ 0x5979, 0x0df2,
+ 0x597a, 0x2d66,
+ 0x597d, 0x077a,
+ 0x597e, 0x2d69,
+ 0x5981, 0x1775,
+ 0x5982, 0x0cc2,
+ 0x5983, 0x1776,
+ 0x5984, 0x0eae,
+ 0x5985, 0x2d6c,
+ 0x5986, 0x120e,
+ 0x5987, 0x06b9,
+ 0x5988, 0x0a8f,
+ 0x5989, 0x2d6d,
+ 0x598a, 0x0cac,
+ 0x598b, 0x2d6e,
+ 0x598d, 0x1777,
+ 0x598e, 0x2d70,
+ 0x5992, 0x0609,
+ 0x5993, 0x083e,
+ 0x5994, 0x2d74,
+ 0x5996, 0x1026,
+ 0x5997, 0x177b,
+ 0x5998, 0x2d76,
+ 0x5999, 0x0af3,
+ 0x599a, 0x2d77,
+ 0x599d, 0x22ad,
+ 0x599e, 0x177e,
+ 0x599f, 0x2d7a,
+ 0x59a3, 0x177a,
+ 0x59a4, 0x177f,
+ 0x59a5, 0x0e88,
+ 0x59a6, 0x2d7e,
+ 0x59a8, 0x065e,
+ 0x59a9, 0x1778,
+ 0x59ab, 0x177d,
+ 0x59ac, 0x2d80,
+ 0x59ae, 0x0b40,
+ 0x59af, 0x1782,
+ 0x59b0, 0x2d82,
+ 0x59b2, 0x1781,
+ 0x59b3, 0x2d84,
+ 0x59b9, 0x0ac8,
+ 0x59ba, 0x2d8a,
+ 0x59bb, 0x0bfd,
+ 0x59bc, 0x2d8b,
+ 0x59be, 0x1784,
+ 0x59bf, 0x2d8d,
+ 0x59c6, 0x0b1a,
+ 0x59c7, 0x2d94,
+ 0x59ca, 0x177c,
+ 0x59cb, 0x0d53,
+ 0x59cc, 0x2d97,
+ 0x59d0, 0x08b4,
+ 0x59d1, 0x071c,
+ 0x59d2, 0x1780,
+ 0x59d3, 0x0fa0,
+ 0x59d4, 0x0ebe,
+ 0x59d5, 0x2d9b,
+ 0x59d7, 0x1783,
+ 0x59d8, 0x178a,
+ 0x59d9, 0x2d9d,
+ 0x59da, 0x102d,
+ 0x59db, 0x2d9e,
+ 0x59dc, 0x087b,
+ 0x59dd, 0x1787,
+ 0x59de, 0x2d9f,
+ 0x59e3, 0x1789,
+ 0x59e4, 0x2da4,
+ 0x59e5, 0x09bc,
+ 0x59e6, 0x2da5,
+ 0x59e8, 0x1053,
+ 0x59e9, 0x2da7,
+ 0x59ec, 0x081a,
+ 0x59ed, 0x2daa,
+ 0x59f9, 0x178b,
+ 0x59fa, 0x2db6,
+ 0x59fb, 0x107d,
+ 0x59fc, 0x2db7,
+ 0x59ff, 0x1228,
+ 0x5a00, 0x2dba,
+ 0x5a01, 0x0eaf,
+ 0x5a02, 0x2dbb,
+ 0x5a03, 0x0e8f,
+ 0x5a04, 0x0a4d,
+ 0x5a05, 0x1785,
+ 0x5a07, 0x0890,
+ 0x5a08, 0x1788,
+ 0x5a09, 0x178d,
+ 0x5a0a, 0x2dbc,
+ 0x5a0c, 0x178c,
+ 0x5a0d, 0x2dbe,
+ 0x5a11, 0x1790,
+ 0x5a12, 0x2dc2,
+ 0x5a13, 0x1792,
+ 0x5a14, 0x2dc3,
+ 0x5a18, 0x0b52,
+ 0x5a19, 0x2dc7,
+ 0x5a1c, 0x0b2b,
+ 0x5a1d, 0x2dca,
+ 0x5a1f, 0x0919,
+ 0x5a20, 0x0d28,
+ 0x5a21, 0x2dcc,
+ 0x5a23, 0x1791,
+ 0x5a24, 0x2dce,
+ 0x5a25, 0x062f,
+ 0x5a26, 0x2dcf,
+ 0x5a29, 0x0ae9,
+ 0x5a2a, 0x2dd2,
+ 0x5a31, 0x10ce,
+ 0x5a32, 0x178e,
+ 0x5a33, 0x2dd9,
+ 0x5a34, 0x178f,
+ 0x5a35, 0x2dda,
+ 0x5a36, 0x0c7d,
+ 0x5a37, 0x2ddb,
+ 0x5a3c, 0x1797,
+ 0x5a3d, 0x2de0,
+ 0x5a40, 0x1793,
+ 0x5a41, 0x203f,
+ 0x5a42, 0x2de3,
+ 0x5a46, 0x0be4,
+ 0x5a47, 0x2de7,
+ 0x5a49, 0x0ea2,
+ 0x5a4a, 0x1795,
+ 0x5a4b, 0x2de9,
+ 0x5a55, 0x1796,
+ 0x5a56, 0x2df3,
+ 0x5a5a, 0x07fe,
+ 0x5a5b, 0x2df7,
+ 0x5a62, 0x1798,
+ 0x5a63, 0x2dfe,
+ 0x5a66, 0x1f0e,
+ 0x5a67, 0x1794,
+ 0x5a68, 0x2e01,
+ 0x5a6a, 0x09a2,
+ 0x5a6b, 0x2e03,
+ 0x5a6d, 0x23f9,
+ 0x5a6e, 0x2e05,
+ 0x5a74, 0x1089,
+ 0x5a75, 0x1799,
+ 0x5a76, 0x0d2d,
+ 0x5a77, 0x179d,
+ 0x5a78, 0x2e0b,
+ 0x5a7a, 0x179e,
+ 0x5a7b, 0x2e0d,
+ 0x5a7f, 0x0fc1,
+ 0x5a80, 0x2e11,
+ 0x5a92, 0x0ac2,
+ 0x5a93, 0x2e23,
+ 0x5a9a, 0x0ac9,
+ 0x5a9b, 0x179c,
+ 0x5a9c, 0x2e2a,
+ 0x5aa7, 0x23fc,
+ 0x5aa8, 0x2e35,
+ 0x5aaa, 0x179b,
+ 0x5aab, 0x2e37,
+ 0x5ab2, 0x17a1,
+ 0x5ab3, 0x0f1e,
+ 0x5ab4, 0x2e3e,
+ 0x5ab5, 0x19a4,
+ 0x5ab6, 0x2e3f,
+ 0x5ab8, 0x17a4,
+ 0x5ab9, 0x2e41,
+ 0x5abd, 0x2069,
+ 0x5abe, 0x179f,
+ 0x5abf, 0x2e45,
+ 0x5ac1, 0x0851,
+ 0x5ac2, 0x0ce2,
+ 0x5ac3, 0x2e47,
+ 0x5ac9, 0x0828,
+ 0x5aca, 0x2e4d,
+ 0x5acc, 0x0f40,
+ 0x5acd, 0x2e4f,
+ 0x5ad2, 0x17a2,
+ 0x5ad3, 0x2e54,
+ 0x5ad4, 0x17a3,
+ 0x5ad5, 0x2e55,
+ 0x5ad6, 0x17a8,
+ 0x5ad7, 0x23f7,
+ 0x5ad8, 0x17aa,
+ 0x5ad9, 0x2e56,
+ 0x5adc, 0x17ab,
+ 0x5add, 0x2e59,
+ 0x5ae0, 0x17a5,
+ 0x5ae1, 0x05b6,
+ 0x5ae2, 0x2e5c,
+ 0x5ae3, 0x17a6,
+ 0x5ae4, 0x2e5d,
+ 0x5ae6, 0x17a9,
+ 0x5ae7, 0x2e5f,
+ 0x5ae9, 0x0b3e,
+ 0x5aea, 0x2e61,
+ 0x5aeb, 0x17a0,
+ 0x5aec, 0x2e62,
+ 0x5af1, 0x17a7,
+ 0x5af2, 0x2e67,
+ 0x5af5, 0x23f6,
+ 0x5af6, 0x2e6a,
+ 0x5afb, 0x23fd,
+ 0x5afc, 0x2e6f,
+ 0x5b00, 0x23f8,
+ 0x5b01, 0x2e73,
+ 0x5b08, 0x23fa,
+ 0x5b09, 0x17ac,
+ 0x5b0a, 0x2e7a,
+ 0x5b0b, 0x23fe,
+ 0x5b0c, 0x1fa8,
+ 0x5b0d, 0x2e7b,
+ 0x5b16, 0x17ae,
+ 0x5b17, 0x17ad,
+ 0x5b18, 0x2e84,
+ 0x5b19, 0x2401,
+ 0x5b1a, 0x2e85,
+ 0x5b21, 0x23ff,
+ 0x5b22, 0x2e8c,
+ 0x5b2a, 0x2400,
+ 0x5b2b, 0x2e94,
+ 0x5b30, 0x2221,
+ 0x5b31, 0x2e99,
+ 0x5b32, 0x17af,
+ 0x5b33, 0x2e9a,
+ 0x5b34, 0x130c,
+ 0x5b35, 0x2e9b,
+ 0x5b37, 0x17b0,
+ 0x5b38, 0x2122,
+ 0x5b39, 0x2e9d,
+ 0x5b40, 0x17b1,
+ 0x5b41, 0x2ea4,
+ 0x5b4c, 0x23fb,
+ 0x5b4d, 0x2eaf,
+ 0x5b50, 0x1230,
+ 0x5b51, 0x17b7,
+ 0x5b52, 0x2eb2,
+ 0x5b53, 0x17b8,
+ 0x5b54, 0x0964,
+ 0x5b55, 0x1113,
+ 0x5b56, 0x2eb3,
+ 0x5b57, 0x1233,
+ 0x5b58, 0x0569,
+ 0x5b59, 0x0de4,
+ 0x5b5a, 0x17b4,
+ 0x5b5b, 0x1279,
+ 0x5b5c, 0x122b,
+ 0x5b5d, 0x0f6d,
+ 0x5b5e, 0x2eb4,
+ 0x5b5f, 0x0ad4,
+ 0x5b60, 0x2eb5,
+ 0x5b62, 0x17b9,
+ 0x5b63, 0x0831,
+ 0x5b64, 0x071b,
+ 0x5b65, 0x17b5,
+ 0x5b66, 0x0fd0,
+ 0x5b67, 0x2eb7,
+ 0x5b69, 0x0759,
+ 0x5b6a, 0x0a76,
+ 0x5b6b, 0x215a,
+ 0x5b6c, 0x1261,
+ 0x5b6d, 0x2eb9,
+ 0x5b70, 0x0d82,
+ 0x5b71, 0x176a,
+ 0x5b72, 0x2ebc,
+ 0x5b73, 0x17b6,
+ 0x5b74, 0x2ebd,
+ 0x5b75, 0x0692,
+ 0x5b76, 0x2ebe,
+ 0x5b78, 0x21e5,
+ 0x5b79, 0x2ec0,
+ 0x5b7a, 0x0cc1,
+ 0x5b7b, 0x2ec1,
+ 0x5b7d, 0x0b58,
+ 0x5b7e, 0x2ec3,
+ 0x5b7f, 0x2057,
+ 0x5b80, 0x172e,
+ 0x5b81, 0x0b61,
+ 0x5b82, 0x2ec4,
+ 0x5b83, 0x0df1,
+ 0x5b84, 0x172f,
+ 0x5b85, 0x114d,
+ 0x5b86, 0x2ec5,
+ 0x5b87, 0x10d3,
+ 0x5b88, 0x0d6f,
+ 0x5b89, 0x03bd,
+ 0x5b8a, 0x2ec6,
+ 0x5b8b, 0x0dc3,
+ 0x5b8c, 0x0e9b,
+ 0x5b8d, 0x2ec7,
+ 0x5b8f, 0x07a1,
+ 0x5b90, 0x2ec9,
+ 0x5b93, 0x1731,
+ 0x5b94, 0x2ecc,
+ 0x5b95, 0x1730,
+ 0x5b96, 0x2ecd,
+ 0x5b97, 0x1237,
+ 0x5b98, 0x0732,
+ 0x5b99, 0x11e5,
+ 0x5b9a, 0x05e7,
+ 0x5b9b, 0x0ea1,
+ 0x5b9c, 0x1052,
+ 0x5b9d, 0x040f,
+ 0x5b9e, 0x0d4c,
+ 0x5b9f, 0x2ece,
+ 0x5ba0, 0x050d,
+ 0x5ba1, 0x0d2c,
+ 0x5ba2, 0x095a,
+ 0x5ba3, 0x0fc6,
+ 0x5ba4, 0x0d69,
+ 0x5ba5, 0x1732,
+ 0x5ba6, 0x07d7,
+ 0x5ba7, 0x2ecf,
+ 0x5baa, 0x0f49,
+ 0x5bab, 0x0705,
+ 0x5bac, 0x2ed2,
+ 0x5bb0, 0x111a,
+ 0x5bb1, 0x2ed6,
+ 0x5bb3, 0x075d,
+ 0x5bb4, 0x1010,
+ 0x5bb5, 0x0f69,
+ 0x5bb6, 0x0845,
+ 0x5bb7, 0x2ed8,
+ 0x5bb8, 0x1733,
+ 0x5bb9, 0x0cb8,
+ 0x5bba, 0x2ed9,
+ 0x5bbd, 0x097a,
+ 0x5bbe, 0x045f,
+ 0x5bbf, 0x0dd3,
+ 0x5bc0, 0x2edc,
+ 0x5bc2, 0x0838,
+ 0x5bc3, 0x2ede,
+ 0x5bc4, 0x0837,
+ 0x5bc5, 0x1081,
+ 0x5bc6, 0x0ae1,
+ 0x5bc7, 0x0969,
+ 0x5bc8, 0x2edf,
+ 0x5bcc, 0x06b6,
+ 0x5bcd, 0x2ee3,
+ 0x5bd0, 0x0ac7,
+ 0x5bd1, 0x2ee6,
+ 0x5bd2, 0x0765,
+ 0x5bd3, 0x10e5,
+ 0x5bd4, 0x2ee7,
+ 0x5bdd, 0x0c5b,
+ 0x5bde, 0x0b12,
+ 0x5bdf, 0x04b3,
+ 0x5be0, 0x2ef0,
+ 0x5be1, 0x072a,
+ 0x5be2, 0x20e5,
+ 0x5be3, 0x2ef1,
+ 0x5be4, 0x1737,
+ 0x5be5, 0x0a11,
+ 0x5be6, 0x212f,
+ 0x5be7, 0x20a3,
+ 0x5be8, 0x1150,
+ 0x5be9, 0x2121,
+ 0x5bea, 0x2ef2,
+ 0x5beb, 0x21d4,
+ 0x5bec, 0x1fe5,
+ 0x5bed, 0x2ef3,
+ 0x5bee, 0x1738,
+ 0x5bef, 0x2ef4,
+ 0x5bf0, 0x173a,
+ 0x5bf1, 0x2ef5,
+ 0x5bf5, 0x1e8a,
+ 0x5bf6, 0x1e37,
+ 0x5bf7, 0x2ef9,
+ 0x5bf8, 0x056a,
+ 0x5bf9, 0x0613,
+ 0x5bfa, 0x0db7,
+ 0x5bfb, 0x0fd9,
+ 0x5bfc, 0x059d,
+ 0x5bfd, 0x2efa,
+ 0x5bff, 0x0d70,
+ 0x5c00, 0x2efc,
+ 0x5c01, 0x067f,
+ 0x5c02, 0x2efd,
+ 0x5c04, 0x0d1d,
+ 0x5c05, 0x2eff,
+ 0x5c06, 0x087c,
+ 0x5c07, 0x1f9e,
+ 0x5c08, 0x22a6,
+ 0x5c09, 0x0ecd,
+ 0x5c0a, 0x124d,
+ 0x5c0b, 0x21e8,
+ 0x5c0c, 0x2f00,
+ 0x5c0d, 0x1eda,
+ 0x5c0e, 0x1eb9,
+ 0x5c0f, 0x0f6c,
+ 0x5c10, 0x2f01,
+ 0x5c11, 0x0d12,
+ 0x5c12, 0x2f02,
+ 0x5c14, 0x063a,
+ 0x5c15, 0x17b2,
+ 0x5c16, 0x0855,
+ 0x5c17, 0x2f04,
+ 0x5c18, 0x04e3,
+ 0x5c19, 0x2f05,
+ 0x5c1a, 0x0d09,
+ 0x5c1b, 0x2f06,
+ 0x5c1c, 0x17b3,
+ 0x5c1d, 0x04c7,
+ 0x5c1e, 0x2f07,
+ 0x5c22, 0x14b6,
+ 0x5c23, 0x2f0b,
+ 0x5c24, 0x10ad,
+ 0x5c25, 0x14b7,
+ 0x5c26, 0x2f0c,
+ 0x5c27, 0x1029,
+ 0x5c28, 0x2f0d,
+ 0x5c2c, 0x14b8,
+ 0x5c2d, 0x2f11,
+ 0x5c31, 0x08fc,
+ 0x5c32, 0x2f15,
+ 0x5c34, 0x14b9,
+ 0x5c35, 0x2f17,
+ 0x5c37, 0x235c,
+ 0x5c38, 0x0d43,
+ 0x5c39, 0x1083,
+ 0x5c3a, 0x0504,
+ 0x5c3b, 0x1766,
+ 0x5c3c, 0x0b44,
+ 0x5c3d, 0x08d0,
+ 0x5c3e, 0x0ec1,
+ 0x5c3f, 0x0b55,
+ 0x5c40, 0x0905,
+ 0x5c41, 0x0bc7,
+ 0x5c42, 0x04aa,
+ 0x5c43, 0x2f19,
+ 0x5c45, 0x0902,
+ 0x5c46, 0x2f1b,
+ 0x5c48, 0x0c79,
+ 0x5c49, 0x0e3e,
+ 0x5c4a, 0x08bd,
+ 0x5c4b, 0x0eec,
+ 0x5c4c, 0x2f1d,
+ 0x5c4e, 0x0d51,
+ 0x5c4f, 0x0be0,
+ 0x5c50, 0x1768,
+ 0x5c51, 0x0f87,
+ 0x5c52, 0x2f1f,
+ 0x5c55, 0x115a,
+ 0x5c56, 0x2f22,
+ 0x5c59, 0x1769,
+ 0x5c5a, 0x2f25,
+ 0x5c5e, 0x0d8b,
+ 0x5c5f, 0x2f29,
+ 0x5c60, 0x0e71,
+ 0x5c61, 0x0a6c,
+ 0x5c62, 0x2050,
+ 0x5c63, 0x176b,
+ 0x5c64, 0x1e67,
+ 0x5c65, 0x0a6b,
+ 0x5c66, 0x176c,
+ 0x5c67, 0x2f2a,
+ 0x5c68, 0x23f4,
+ 0x5c69, 0x2f2b,
+ 0x5c6c, 0x213e,
+ 0x5c6d, 0x2f2e,
+ 0x5c6e, 0x1774,
+ 0x5c6f, 0x0e7e,
+ 0x5c70, 0x2f2f,
+ 0x5c71, 0x0cf6,
+ 0x5c72, 0x2f30,
+ 0x5c79, 0x1060,
+ 0x5c7a, 0x15ac,
+ 0x5c7b, 0x2f37,
+ 0x5c7f, 0x10d1,
+ 0x5c80, 0x2f3b,
+ 0x5c81, 0x0ddf,
+ 0x5c82, 0x0c10,
+ 0x5c83, 0x2f3c,
+ 0x5c88, 0x15b0,
+ 0x5c89, 0x2f41,
+ 0x5c8c, 0x15ab,
+ 0x5c8d, 0x15ad,
+ 0x5c8e, 0x2f44,
+ 0x5c90, 0x15ae,
+ 0x5c91, 0x15b3,
+ 0x5c92, 0x2f46,
+ 0x5c94, 0x04b4,
+ 0x5c95, 0x2f48,
+ 0x5c96, 0x15af,
+ 0x5c97, 0x06d5,
+ 0x5c98, 0x15b1,
+ 0x5c9a, 0x15b4,
+ 0x5c9b, 0x059b,
+ 0x5c9c, 0x15b5,
+ 0x5c9d, 0x2f49,
+ 0x5ca1, 0x1f16,
+ 0x5ca2, 0x15b7,
+ 0x5ca3, 0x15bc,
+ 0x5ca4, 0x2f4d,
+ 0x5ca9, 0x0ffb,
+ 0x5caa, 0x2f52,
+ 0x5cab, 0x15ba,
+ 0x5cac, 0x15b9,
+ 0x5cad, 0x0a34,
+ 0x5cae, 0x2f53,
+ 0x5cb1, 0x15bb,
+ 0x5cb2, 0x2f56,
+ 0x5cb3, 0x1103,
+ 0x5cb4, 0x2f57,
+ 0x5cb5, 0x15b6,
+ 0x5cb6, 0x2f58,
+ 0x5cb7, 0x15be,
+ 0x5cb8, 0x03c1,
+ 0x5cb9, 0x2f59,
+ 0x5cbd, 0x15b8,
+ 0x5cbe, 0x2f5d,
+ 0x5cbf, 0x0986,
+ 0x5cc0, 0x2f5e,
+ 0x5cc1, 0x15bd,
+ 0x5cc2, 0x2f5f,
+ 0x5cc4, 0x15bf,
+ 0x5cc5, 0x2f61,
+ 0x5ccb, 0x15c2,
+ 0x5ccc, 0x2f67,
+ 0x5cd2, 0x15c0,
+ 0x5cd3, 0x2f6d,
+ 0x5cd9, 0x11c4,
+ 0x5cda, 0x2f73,
+ 0x5ce1, 0x0f2c,
+ 0x5ce2, 0x2f7a,
+ 0x5ce4, 0x15c1,
+ 0x5ce5, 0x15c3,
+ 0x5ce6, 0x0a74,
+ 0x5ce7, 0x2f7c,
+ 0x5ce8, 0x062a,
+ 0x5ce9, 0x2f7d,
+ 0x5cea, 0x10dd,
+ 0x5ceb, 0x2f7e,
+ 0x5ced, 0x0c4a,
+ 0x5cee, 0x2f80,
+ 0x5cf0, 0x0682,
+ 0x5cf1, 0x2f82,
+ 0x5cf4, 0x2389,
+ 0x5cf5, 0x2f85,
+ 0x5cf6, 0x1eb7,
+ 0x5cf7, 0x2f86,
+ 0x5cfb, 0x092d,
+ 0x5cfc, 0x2f8a,
+ 0x5cfd, 0x21b4,
+ 0x5cfe, 0x2f8b,
+ 0x5d00, 0x2f8d,
+ 0x5d02, 0x15c4,
+ 0x5d04, 0x2f8f,
+ 0x5d06, 0x15cb,
+ 0x5d07, 0x050c,
+ 0x5d08, 0x2f91,
+ 0x5d0d, 0x238f,
+ 0x5d0e, 0x0c08,
+ 0x5d0f, 0x2f96,
+ 0x5d14, 0x0561,
+ 0x5d15, 0x2f9b,
+ 0x5d16, 0x0feb,
+ 0x5d17, 0x1f1a,
+ 0x5d18, 0x2f9c,
+ 0x5d1b, 0x15cc,
+ 0x5d1c, 0x2f9f,
+ 0x5d1e, 0x15ca,
+ 0x5d1f, 0x2fa1,
+ 0x5d24, 0x15c9,
+ 0x5d25, 0x2fa6,
+ 0x5d26, 0x15c7,
+ 0x5d27, 0x15c6,
+ 0x5d28, 0x2fa7,
+ 0x5d29, 0x0429,
+ 0x5d2a, 0x2fa8,
+ 0x5d2c, 0x238b,
+ 0x5d2d, 0x1159,
+ 0x5d2e, 0x15c8,
+ 0x5d2f, 0x2faa,
+ 0x5d34, 0x15cf,
+ 0x5d35, 0x2faf,
+ 0x5d3d, 0x15d0,
+ 0x5d3e, 0x15ce,
+ 0x5d3f, 0x2fb7,
+ 0x5d47, 0x1b22,
+ 0x5d48, 0x2fbf,
+ 0x5d4a, 0x15d7,
+ 0x5d4b, 0x15d6,
+ 0x5d4c, 0x0c33,
+ 0x5d4d, 0x2fc1,
+ 0x5d50, 0x238a,
+ 0x5d51, 0x2fc4,
+ 0x5d58, 0x15cd,
+ 0x5d59, 0x2fcb,
+ 0x5d5b, 0x15d2,
+ 0x5d5c, 0x2fcd,
+ 0x5d5d, 0x15d4,
+ 0x5d5e, 0x2fce,
+ 0x5d69, 0x15d8,
+ 0x5d6a, 0x2fd9,
+ 0x5d6b, 0x15d5,
+ 0x5d6c, 0x15d1,
+ 0x5d6d, 0x2fda,
+ 0x5d6f, 0x15d3,
+ 0x5d70, 0x2fdc,
+ 0x5d74, 0x15d9,
+ 0x5d75, 0x2fe0,
+ 0x5d81, 0x2391,
+ 0x5d82, 0x15da,
+ 0x5d83, 0x2fec,
+ 0x5d84, 0x2271,
+ 0x5d85, 0x2fed,
+ 0x5d87, 0x2388,
+ 0x5d88, 0x2fef,
+ 0x5d97, 0x238e,
+ 0x5d98, 0x2ffe,
+ 0x5d99, 0x15db,
+ 0x5d9a, 0x2fff,
+ 0x5d9d, 0x15dc,
+ 0x5d9e, 0x3002,
+ 0x5da0, 0x238d,
+ 0x5da1, 0x3004,
+ 0x5da7, 0x238c,
+ 0x5da8, 0x300a,
+ 0x5db7, 0x15de,
+ 0x5db8, 0x2390,
+ 0x5db9, 0x3019,
+ 0x5dba, 0x2033,
+ 0x5dbb, 0x301a,
+ 0x5dbc, 0x223c,
+ 0x5dbd, 0x301b,
+ 0x5dc5, 0x15df,
+ 0x5dc6, 0x3023,
+ 0x5dcb, 0x1fe9,
+ 0x5dcc, 0x3028,
+ 0x5dcd, 0x0eb0,
+ 0x5dce, 0x3029,
+ 0x5dd2, 0x2055,
+ 0x5dd3, 0x302d,
+ 0x5dd4, 0x2392,
+ 0x5dd5, 0x302e,
+ 0x5ddb, 0x1815,
+ 0x5ddc, 0x3034,
+ 0x5ddd, 0x052b,
+ 0x5dde, 0x11dc,
+ 0x5ddf, 0x3035,
+ 0x5de1, 0x0fdb,
+ 0x5de2, 0x04d7,
+ 0x5de3, 0x3037,
+ 0x5de5, 0x06fd,
+ 0x5de6, 0x1250,
+ 0x5de7, 0x0c46,
+ 0x5de8, 0x090d,
+ 0x5de9, 0x0707,
+ 0x5dea, 0x3039,
+ 0x5deb, 0x0ee6,
+ 0x5dec, 0x303a,
+ 0x5dee, 0x04b5,
+ 0x5def, 0x139f,
+ 0x5df0, 0x2324,
+ 0x5df1, 0x082d,
+ 0x5df2, 0x1058,
+ 0x5df3, 0x0dbd,
+ 0x5df4, 0x03d8,
+ 0x5df5, 0x303c,
+ 0x5df7, 0x0f5c,
+ 0x5df8, 0x303e,
+ 0x5dfd, 0x12f7,
+ 0x5dfe, 0x08be,
+ 0x5dff, 0x3043,
+ 0x5e00, 0x3044,
+ 0x5e01, 0x043b,
+ 0x5e02, 0x0d67,
+ 0x5e03, 0x0483,
+ 0x5e04, 0x3045,
+ 0x5e05, 0x0d9c,
+ 0x5e06, 0x0648,
+ 0x5e07, 0x3046,
+ 0x5e08, 0x0d3d,
+ 0x5e09, 0x3047,
+ 0x5e0c, 0x0f10,
+ 0x5e0d, 0x304a,
+ 0x5e0f, 0x159e,
+ 0x5e10, 0x116b,
+ 0x5e11, 0x15a1,
+ 0x5e12, 0x304c,
+ 0x5e14, 0x15a0,
+ 0x5e15, 0x0b82,
+ 0x5e16, 0x0e4e,
+ 0x5e17, 0x304e,
+ 0x5e18, 0x09fa,
+ 0x5e19, 0x159f,
+ 0x5e1a, 0x11e2,
+ 0x5e1b, 0x0476,
+ 0x5e1c, 0x11c3,
+ 0x5e1d, 0x05bc,
+ 0x5e1e, 0x304f,
+ 0x5e25, 0x2143,
+ 0x5e26, 0x057b,
+ 0x5e27, 0x11a0,
+ 0x5e28, 0x3056,
+ 0x5e2b, 0x2129,
+ 0x5e2c, 0x3059,
+ 0x5e2d, 0x0f1c,
+ 0x5e2e, 0x03fa,
+ 0x5e2f, 0x305a,
+ 0x5e31, 0x15a2,
+ 0x5e32, 0x305c,
+ 0x5e33, 0x2277,
+ 0x5e34, 0x305d,
+ 0x5e36, 0x1ea7,
+ 0x5e37, 0x15a5,
+ 0x5e38, 0x04c8,
+ 0x5e39, 0x305f,
+ 0x5e3b, 0x15a3,
+ 0x5e3d, 0x0ab6,
+ 0x5e3e, 0x3061,
+ 0x5e40, 0x2285,
+ 0x5e41, 0x3063,
+ 0x5e42, 0x0ae2,
+ 0x5e43, 0x2384,
+ 0x5e44, 0x15a6,
+ 0x5e45, 0x0696,
+ 0x5e46, 0x3064,
+ 0x5e4c, 0x07e4,
+ 0x5e4d, 0x306a,
+ 0x5e54, 0x15a7,
+ 0x5e55, 0x0b1e,
+ 0x5e56, 0x3071,
+ 0x5e57, 0x2387,
+ 0x5e58, 0x2386,
+ 0x5e59, 0x3072,
+ 0x5e5b, 0x15a8,
+ 0x5e5c, 0x3074,
+ 0x5e5e, 0x15a9,
+ 0x5e5f, 0x2290,
+ 0x5e60, 0x3076,
+ 0x5e61, 0x15aa,
+ 0x5e62, 0x0534,
+ 0x5e63, 0x1e44,
+ 0x5e64, 0x3077,
+ 0x5e6b, 0x1e32,
+ 0x5e6c, 0x2385,
+ 0x5e6d, 0x307e,
+ 0x5e72, 0x06c4,
+ 0x5e73, 0x0bdc,
+ 0x5e74, 0x0b4d,
+ 0x5e75, 0x3083,
+ 0x5e76, 0x0469,
+ 0x5e77, 0x3084,
+ 0x5e78, 0x0f9d,
+ 0x5e79, 0x1f13,
+ 0x5e7a, 0x1813,
+ 0x5e7b, 0x07d8,
+ 0x5e7c, 0x10bc,
+ 0x5e7d, 0x10a9,
+ 0x5e7e, 0x1f73,
+ 0x5e7f, 0x073c,
+ 0x5e80, 0x1631,
+ 0x5e81, 0x3085,
+ 0x5e84, 0x120c,
+ 0x5e85, 0x3088,
+ 0x5e86, 0x0c69,
+ 0x5e87, 0x043c,
+ 0x5e88, 0x3089,
+ 0x5e8a, 0x0535,
+ 0x5e8b, 0x1633,
+ 0x5e8c, 0x308b,
+ 0x5e8f, 0x0fbd,
+ 0x5e90, 0x0a55,
+ 0x5e91, 0x1632,
+ 0x5e92, 0x308e,
+ 0x5e93, 0x096f,
+ 0x5e94, 0x108b,
+ 0x5e95, 0x05b8,
+ 0x5e96, 0x1634,
+ 0x5e97, 0x05cb,
+ 0x5e98, 0x308f,
+ 0x5e99, 0x0af2,
+ 0x5e9a, 0x06f8,
+ 0x5e9b, 0x3090,
+ 0x5e9c, 0x06a9,
+ 0x5e9d, 0x3091,
+ 0x5e9e, 0x0b94,
+ 0x5e9f, 0x066c,
+ 0x5ea0, 0x1636,
+ 0x5ea1, 0x3092,
+ 0x5ea5, 0x1635,
+ 0x5ea6, 0x0607,
+ 0x5ea7, 0x1256,
+ 0x5ea8, 0x3096,
+ 0x5eab, 0x1fe0,
+ 0x5eac, 0x3099,
+ 0x5ead, 0x0e56,
+ 0x5eae, 0x309a,
+ 0x5eb3, 0x163a,
+ 0x5eb4, 0x309f,
+ 0x5eb5, 0x1638,
+ 0x5eb6, 0x0d93,
+ 0x5eb7, 0x0942,
+ 0x5eb8, 0x109e,
+ 0x5eb9, 0x1637,
+ 0x5eba, 0x30a0,
+ 0x5ebe, 0x1639,
+ 0x5ebf, 0x30a4,
+ 0x5ec9, 0x09f7,
+ 0x5eca, 0x09b3,
+ 0x5ecb, 0x30ae,
+ 0x5ed1, 0x163d,
+ 0x5ed2, 0x163c,
+ 0x5ed3, 0x0995,
+ 0x5ed4, 0x30b4,
+ 0x5ed6, 0x0a17,
+ 0x5ed7, 0x30b6,
+ 0x5edb, 0x163e,
+ 0x5edc, 0x30ba,
+ 0x5edf, 0x2087,
+ 0x5ee0, 0x1e78,
+ 0x5ee1, 0x23ae,
+ 0x5ee2, 0x1ef6,
+ 0x5ee3, 0x1f31,
+ 0x5ee4, 0x30bd,
+ 0x5ee8, 0x163f,
+ 0x5ee9, 0x30c1,
+ 0x5eea, 0x1640,
+ 0x5eeb, 0x30c2,
+ 0x5eec, 0x2045,
+ 0x5eed, 0x30c3,
+ 0x5ef3, 0x2178,
+ 0x5ef4, 0x1398,
+ 0x5ef5, 0x30c9,
+ 0x5ef6, 0x0ffc,
+ 0x5ef7, 0x0e53,
+ 0x5ef8, 0x30ca,
+ 0x5efa, 0x0879,
+ 0x5efb, 0x30cc,
+ 0x5efe, 0x14ad,
+ 0x5eff, 0x125b,
+ 0x5f00, 0x0937,
+ 0x5f01, 0x139d,
+ 0x5f02, 0x1073,
+ 0x5f03, 0x0c19,
+ 0x5f04, 0x0b6b,
+ 0x5f05, 0x30cf,
+ 0x5f08, 0x14ae,
+ 0x5f09, 0x30d2,
+ 0x5f0a, 0x0440,
+ 0x5f0b, 0x14f6,
+ 0x5f0c, 0x30d3,
+ 0x5f0f, 0x0d54,
+ 0x5f10, 0x30d6,
+ 0x5f11, 0x14f9,
+ 0x5f12, 0x30d7,
+ 0x5f13, 0x0706,
+ 0x5f14, 0x30d8,
+ 0x5f15, 0x1084,
+ 0x5f16, 0x30d9,
+ 0x5f17, 0x06a0,
+ 0x5f18, 0x07a2,
+ 0x5f19, 0x30da,
+ 0x5f1b, 0x04ff,
+ 0x5f1c, 0x30dc,
+ 0x5f1f, 0x05bd,
+ 0x5f20, 0x1166,
+ 0x5f21, 0x30df,
+ 0x5f25, 0x0adb,
+ 0x5f26, 0x0f3f,
+ 0x5f27, 0x07b6,
+ 0x5f28, 0x30e3,
+ 0x5f29, 0x176f,
+ 0x5f2a, 0x176e,
+ 0x5f2b, 0x30e4,
+ 0x5f2d, 0x1770,
+ 0x5f2e, 0x30e6,
+ 0x5f2f, 0x0e95,
+ 0x5f30, 0x30e7,
+ 0x5f31, 0x0cd0,
+ 0x5f32, 0x30e8,
+ 0x5f33, 0x23f5,
+ 0x5f34, 0x30e9,
+ 0x5f35, 0x2275,
+ 0x5f36, 0x30ea,
+ 0x5f39, 0x0590,
+ 0x5f3a, 0x0c3c,
+ 0x5f3b, 0x30ed,
+ 0x5f3c, 0x1772,
+ 0x5f3d, 0x30ee,
+ 0x5f40, 0x19be,
+ 0x5f41, 0x30f1,
+ 0x5f46, 0x266e,
+ 0x5f47, 0x30f6,
+ 0x5f48, 0x1eb0,
+ 0x5f49, 0x30f7,
+ 0x5f4c, 0x2083,
+ 0x5f4d, 0x30fa,
+ 0x5f4e, 0x2188,
+ 0x5f4f, 0x30fb,
+ 0x5f50, 0x1762,
+ 0x5f51, 0x30fc,
+ 0x5f52, 0x0742,
+ 0x5f53, 0x0592,
+ 0x5f54, 0x30fd,
+ 0x5f55, 0x0a63,
+ 0x5f56, 0x1764,
+ 0x5f57, 0x1763,
+ 0x5f58, 0x1765,
+ 0x5f59, 0x267c,
+ 0x5f5a, 0x30fe,
+ 0x5f5d, 0x1054,
+ 0x5f5e, 0x3101,
+ 0x5f61, 0x15ee,
+ 0x5f62, 0x0f99,
+ 0x5f63, 0x3104,
+ 0x5f64, 0x0e5f,
+ 0x5f65, 0x3105,
+ 0x5f66, 0x100e,
+ 0x5f67, 0x3106,
+ 0x5f69, 0x0491,
+ 0x5f6a, 0x0454,
+ 0x5f6b, 0x3108,
+ 0x5f6c, 0x045b,
+ 0x5f6d, 0x0bae,
+ 0x5f6e, 0x3109,
+ 0x5f70, 0x1164,
+ 0x5f71, 0x1095,
+ 0x5f72, 0x310b,
+ 0x5f73, 0x15e0,
+ 0x5f74, 0x310c,
+ 0x5f77, 0x15e1,
+ 0x5f78, 0x310f,
+ 0x5f79, 0x1062,
+ 0x5f7a, 0x3110,
+ 0x5f7b, 0x04de,
+ 0x5f7c, 0x0434,
+ 0x5f7d, 0x3111,
+ 0x5f80, 0x0eaa,
+ 0x5f81, 0x1198,
+ 0x5f82, 0x15e2,
+ 0x5f83, 0x3114,
+ 0x5f84, 0x08e5,
+ 0x5f85, 0x0580,
+ 0x5f86, 0x3115,
+ 0x5f87, 0x15e3,
+ 0x5f88, 0x0793,
+ 0x5f89, 0x15e4,
+ 0x5f8a, 0x07c7,
+ 0x5f8b, 0x0a70,
+ 0x5f8c, 0x15e5,
+ 0x5f8d, 0x3116,
+ 0x5f90, 0x0fb7,
+ 0x5f91, 0x1fc5,
+ 0x5f92, 0x0e6e,
+ 0x5f93, 0x3119,
+ 0x5f95, 0x15e6,
+ 0x5f96, 0x311b,
+ 0x5f97, 0x05a4,
+ 0x5f98, 0x0b88,
+ 0x5f99, 0x15e7,
+ 0x5f9a, 0x311c,
+ 0x5f9c, 0x15e8,
+ 0x5f9d, 0x311e,
+ 0x5f9e, 0x1ea1,
+ 0x5f9f, 0x311f,
+ 0x5fa0, 0x2393,
+ 0x5fa1, 0x10de,
+ 0x5fa2, 0x3120,
+ 0x5fa8, 0x15e9,
+ 0x5fa9, 0x1f0b,
+ 0x5faa, 0x0fd6,
+ 0x5fab, 0x3126,
+ 0x5fad, 0x15ea,
+ 0x5fae, 0x0eb1,
+ 0x5faf, 0x3128,
+ 0x5fb5, 0x15eb,
+ 0x5fb6, 0x312e,
+ 0x5fb7, 0x05a3,
+ 0x5fb8, 0x312f,
+ 0x5fb9, 0x1e7c,
+ 0x5fba, 0x3130,
+ 0x5fbc, 0x15ec,
+ 0x5fbd, 0x07ea,
+ 0x5fbe, 0x3132,
+ 0x5fc3, 0x0f8f,
+ 0x5fc4, 0x1642,
+ 0x5fc5, 0x0441,
+ 0x5fc6, 0x106b,
+ 0x5fc7, 0x3137,
+ 0x5fc9, 0x1643,
+ 0x5fca, 0x3139,
+ 0x5fcc, 0x083c,
+ 0x5fcd, 0x0ca7,
+ 0x5fce, 0x313b,
+ 0x5fcf, 0x1645,
+ 0x5fd0, 0x1a0c,
+ 0x5fd1, 0x1a0b,
+ 0x5fd2, 0x14f7,
+ 0x5fd3, 0x313c,
+ 0x5fd6, 0x1644,
+ 0x5fd7, 0x11bd,
+ 0x5fd8, 0x0ead,
+ 0x5fd9, 0x0aab,
+ 0x5fda, 0x313f,
+ 0x5fdd, 0x1683,
+ 0x5fde, 0x3142,
+ 0x5fe0, 0x11d1,
+ 0x5fe1, 0x1649,
+ 0x5fe2, 0x3144,
+ 0x5fe4, 0x164a,
+ 0x5fe5, 0x3146,
+ 0x5fe7, 0x10ac,
+ 0x5fe8, 0x3148,
+ 0x5fea, 0x164e,
+ 0x5feb, 0x0979,
+ 0x5fec, 0x314a,
+ 0x5fed, 0x164f,
+ 0x5fee, 0x1647,
+ 0x5fef, 0x314b,
+ 0x5ff1, 0x04e5,
+ 0x5ff2, 0x314d,
+ 0x5ff5, 0x0b51,
+ 0x5ff6, 0x3150,
+ 0x5ff8, 0x1650,
+ 0x5ff9, 0x3152,
+ 0x5ffb, 0x0f8e,
+ 0x5ffc, 0x3154,
+ 0x5ffd, 0x07ad,
+ 0x5ffe, 0x164b,
+ 0x5fff, 0x067b,
+ 0x6000, 0x07c8,
+ 0x6001, 0x0dff,
+ 0x6002, 0x0dc0,
+ 0x6003, 0x1646,
+ 0x6004, 0x1648,
+ 0x6005, 0x164c,
+ 0x6007, 0x3155,
+ 0x600a, 0x1659,
+ 0x600b, 0x3158,
+ 0x600d, 0x1656,
+ 0x600e, 0x1138,
+ 0x600f, 0x1655,
+ 0x6010, 0x315a,
+ 0x6012, 0x0b6e,
+ 0x6013, 0x315c,
+ 0x6014, 0x119b,
+ 0x6015, 0x0b83,
+ 0x6016, 0x0487,
+ 0x6017, 0x315d,
+ 0x6019, 0x1651,
+ 0x601a, 0x315f,
+ 0x601b, 0x1654,
+ 0x601c, 0x09f8,
+ 0x601d, 0x0db1,
+ 0x601e, 0x3160,
+ 0x6020, 0x0582,
+ 0x6021, 0x165b,
+ 0x6022, 0x3162,
+ 0x6025, 0x0824,
+ 0x6026, 0x1653,
+ 0x6027, 0x0f9f,
+ 0x6028, 0x10fc,
+ 0x6029, 0x1657,
+ 0x602a, 0x072f,
+ 0x602b, 0x1658,
+ 0x602c, 0x3165,
+ 0x602f, 0x0c50,
+ 0x6030, 0x3168,
+ 0x6035, 0x1652,
+ 0x6036, 0x316d,
+ 0x603b, 0x1239,
+ 0x603c, 0x1a0d,
+ 0x603d, 0x3172,
+ 0x603f, 0x165a,
+ 0x6040, 0x3174,
+ 0x6041, 0x1a11,
+ 0x6042, 0x1660,
+ 0x6043, 0x0d68,
+ 0x6044, 0x3175,
+ 0x604b, 0x09fe,
+ 0x604c, 0x317c,
+ 0x604d, 0x07e5,
+ 0x604e, 0x317d,
+ 0x6050, 0x0963,
+ 0x6051, 0x317f,
+ 0x6052, 0x079a,
+ 0x6053, 0x3180,
+ 0x6055, 0x0d96,
+ 0x6056, 0x3182,
+ 0x6059, 0x1a12,
+ 0x605a, 0x1a0f,
+ 0x605b, 0x3185,
+ 0x605d, 0x1a0e,
+ 0x605e, 0x3187,
+ 0x6062, 0x07eb,
+ 0x6063, 0x1a13,
+ 0x6064, 0x0fbf,
+ 0x6065, 0x318b,
+ 0x6067, 0x1a10,
+ 0x6068, 0x0795,
+ 0x6069, 0x0636,
+ 0x606a, 0x1661,
+ 0x606b, 0x05f1,
+ 0x606c, 0x0e44,
+ 0x606d, 0x0700,
+ 0x606e, 0x318d,
+ 0x606f, 0x0f0f,
+ 0x6070, 0x0c1e,
+ 0x6071, 0x318e,
+ 0x6073, 0x095f,
+ 0x6074, 0x3190,
+ 0x6076, 0x0630,
+ 0x6077, 0x3192,
+ 0x6078, 0x165c,
+ 0x607a, 0x165f,
+ 0x607b, 0x165e,
+ 0x607c, 0x0b38,
+ 0x607d, 0x1662,
+ 0x607e, 0x3193,
+ 0x607f, 0x10a6,
+ 0x6080, 0x3194,
+ 0x6083, 0x1667,
+ 0x6084, 0x0c41,
+ 0x6085, 0x3197,
+ 0x6089, 0x0f11,
+ 0x608a, 0x319b,
+ 0x608c, 0x1669,
+ 0x608d, 0x076e,
+ 0x608e, 0x319d,
+ 0x6092, 0x1668,
+ 0x6093, 0x31a1,
+ 0x6094, 0x07ef,
+ 0x6095, 0x31a2,
+ 0x6096, 0x1663,
+ 0x6097, 0x31a3,
+ 0x609a, 0x1664,
+ 0x609b, 0x166a,
+ 0x609c, 0x31a6,
+ 0x609d, 0x1666,
+ 0x609e, 0x31a7,
+ 0x609f, 0x0f01,
+ 0x60a0, 0x10ab,
+ 0x60a1, 0x31a8,
+ 0x60a3, 0x07d1,
+ 0x60a4, 0x31aa,
+ 0x60a6, 0x1106,
+ 0x60a7, 0x31ac,
+ 0x60a8, 0x0b5d,
+ 0x60a9, 0x31ad,
+ 0x60ab, 0x1a14,
+ 0x60ac, 0x0fc7,
+ 0x60ad, 0x1665,
+ 0x60ae, 0x31af,
+ 0x60af, 0x0afa,
+ 0x60b0, 0x31b0,
+ 0x60b1, 0x166d,
+ 0x60b2, 0x0418,
+ 0x60b3, 0x31b1,
+ 0x60b4, 0x1672,
+ 0x60b5, 0x23b4,
+ 0x60b6, 0x207e,
+ 0x60b7, 0x31b2,
+ 0x60b8, 0x0835,
+ 0x60b9, 0x31b3,
+ 0x60bb, 0x166c,
+ 0x60bc, 0x05a0,
+ 0x60bd, 0x31b5,
+ 0x60c5, 0x0c66,
+ 0x60c6, 0x1670,
+ 0x60c7, 0x31bd,
+ 0x60ca, 0x08d9,
+ 0x60cb, 0x0ea0,
+ 0x60cc, 0x31c0,
+ 0x60d1, 0x0808,
+ 0x60d2, 0x31c5,
+ 0x60d5, 0x0e3b,
+ 0x60d6, 0x31c8,
+ 0x60d8, 0x166f,
+ 0x60d9, 0x31ca,
+ 0x60da, 0x1671,
+ 0x60db, 0x31cb,
+ 0x60dc, 0x0f14,
+ 0x60dd, 0x166e,
+ 0x60de, 0x31cc,
+ 0x60df, 0x0eb8,
+ 0x60e0, 0x07f2,
+ 0x60e1, 0x1ee3,
+ 0x60e2, 0x31cd,
+ 0x60e6, 0x05cc,
+ 0x60e7, 0x0914,
+ 0x60e8, 0x0499,
+ 0x60e9, 0x04f2,
+ 0x60ea, 0x31d1,
+ 0x60eb, 0x0422,
+ 0x60ec, 0x166b,
+ 0x60ed, 0x0498,
+ 0x60ee, 0x058d,
+ 0x60ef, 0x0738,
+ 0x60f0, 0x0627,
+ 0x60f1, 0x2095,
+ 0x60f2, 0x23bb,
+ 0x60f3, 0x0f58,
+ 0x60f4, 0x1677,
+ 0x60f5, 0x31d2,
+ 0x60f6, 0x07e1,
+ 0x60f7, 0x31d3,
+ 0x60f9, 0x0ca2,
+ 0x60fa, 0x0f95,
+ 0x60fb, 0x23b9,
+ 0x60fc, 0x31d5,
+ 0x6100, 0x1678,
+ 0x6101, 0x0513,
+ 0x6102, 0x31d9,
+ 0x6106, 0x1a15,
+ 0x6107, 0x31dd,
+ 0x6108, 0x10df,
+ 0x6109, 0x10c9,
+ 0x610a, 0x31de,
+ 0x610d, 0x1a16,
+ 0x610e, 0x1679,
+ 0x610f, 0x1069,
+ 0x6110, 0x31e1,
+ 0x6115, 0x1675,
+ 0x6116, 0x31e6,
+ 0x611a, 0x10c3,
+ 0x611b, 0x1e28,
+ 0x611c, 0x23bd,
+ 0x611d, 0x31ea,
+ 0x611f, 0x06cb,
+ 0x6120, 0x1673,
+ 0x6121, 0x31ec,
+ 0x6123, 0x1676,
+ 0x6124, 0x067c,
+ 0x6125, 0x31ee,
+ 0x6126, 0x1674,
+ 0x6127, 0x098d,
+ 0x6128, 0x31ef,
+ 0x612b, 0x167a,
+ 0x612c, 0x31f2,
+ 0x6134, 0x23b5,
+ 0x6135, 0x31fa,
+ 0x6137, 0x23ba,
+ 0x6138, 0x31fc,
+ 0x613e, 0x23b3,
+ 0x613f, 0x10fb,
+ 0x6140, 0x3202,
+ 0x6148, 0x054b,
+ 0x6149, 0x320a,
+ 0x614a, 0x167b,
+ 0x614b, 0x2162,
+ 0x614c, 0x07da,
+ 0x614d, 0x320b,
+ 0x614e, 0x0d30,
+ 0x614f, 0x320c,
+ 0x6151, 0x0d1e,
+ 0x6152, 0x320e,
+ 0x6155, 0x0b20,
+ 0x6156, 0x3211,
+ 0x6158, 0x1e5e,
+ 0x6159, 0x3213,
+ 0x615a, 0x1e5d,
+ 0x615b, 0x3214,
+ 0x615d, 0x1a17,
+ 0x615e, 0x3216,
+ 0x615f, 0x23b7,
+ 0x6160, 0x3217,
+ 0x6162, 0x0aa4,
+ 0x6163, 0x1f2f,
+ 0x6164, 0x24df,
+ 0x6165, 0x3219,
+ 0x6167, 0x07f0,
+ 0x6168, 0x093b,
+ 0x6169, 0x321b,
+ 0x616a, 0x23b2,
+ 0x616b, 0x214e,
+ 0x616c, 0x321c,
+ 0x616e, 0x2052,
+ 0x616f, 0x321e,
+ 0x6170, 0x0ece,
+ 0x6171, 0x321f,
+ 0x6173, 0x23bc,
+ 0x6174, 0x3221,
+ 0x6175, 0x167c,
+ 0x6176, 0x20eb,
+ 0x6177, 0x0943,
+ 0x6178, 0x3222,
+ 0x6182, 0x2232,
+ 0x6183, 0x322c,
+ 0x618a, 0x1e3f,
+ 0x618b, 0x0458,
+ 0x618c, 0x3233,
+ 0x618e, 0x113a,
+ 0x618f, 0x3235,
+ 0x6190, 0x201b,
+ 0x6191, 0x20bc,
+ 0x6192, 0x23be,
+ 0x6193, 0x3236,
+ 0x6194, 0x167e,
+ 0x6195, 0x3237,
+ 0x619a, 0x1eae,
+ 0x619b, 0x323c,
+ 0x619d, 0x1a19,
+ 0x619e, 0x323e,
+ 0x61a4, 0x1efb,
+ 0x61a5, 0x3244,
+ 0x61a7, 0x167f,
+ 0x61a8, 0x0760,
+ 0x61a9, 0x1a18,
+ 0x61aa, 0x3246,
+ 0x61ab, 0x2089,
+ 0x61ac, 0x167d,
+ 0x61ad, 0x3247,
+ 0x61ae, 0x23b1,
+ 0x61af, 0x3248,
+ 0x61b2, 0x21c4,
+ 0x61b3, 0x324b,
+ 0x61b6, 0x2214,
+ 0x61b7, 0x1680,
+ 0x61b8, 0x324e,
+ 0x61be, 0x076d,
+ 0x61bf, 0x3254,
+ 0x61c2, 0x05ed,
+ 0x61c3, 0x3257,
+ 0x61c7, 0x1fde,
+ 0x61c8, 0x0f83,
+ 0x61c9, 0x2223,
+ 0x61ca, 0x03ce,
+ 0x61cb, 0x1a1a,
+ 0x61cc, 0x23b6,
+ 0x61cd, 0x325b,
+ 0x61d1, 0x1a1b,
+ 0x61d2, 0x09ac,
+ 0x61d3, 0x325f,
+ 0x61d4, 0x1681,
+ 0x61d5, 0x3260,
+ 0x61de, 0x268c,
+ 0x61df, 0x24de,
+ 0x61e0, 0x3269,
+ 0x61e3, 0x24e0,
+ 0x61e4, 0x326c,
+ 0x61e6, 0x0b74,
+ 0x61e7, 0x326e,
+ 0x61e8, 0x23b8,
+ 0x61e9, 0x326f,
+ 0x61f2, 0x1e81,
+ 0x61f3, 0x3278,
+ 0x61f5, 0x1682,
+ 0x61f6, 0x1ffe,
+ 0x61f7, 0x1f51,
+ 0x61f8, 0x21e1,
+ 0x61f9, 0x327a,
+ 0x61fa, 0x23b0,
+ 0x61fb, 0x327b,
+ 0x61fc, 0x1fce,
+ 0x61fd, 0x327c,
+ 0x61fe, 0x211e,
+ 0x61ff, 0x13e0,
+ 0x6200, 0x2021,
+ 0x6201, 0x327d,
+ 0x6206, 0x1a1c,
+ 0x6207, 0x24e1,
+ 0x6208, 0x06e5,
+ 0x6209, 0x3282,
+ 0x620a, 0x0efb,
+ 0x620b, 0x18f9,
+ 0x620c, 0x0fb2,
+ 0x620d, 0x0d90,
+ 0x620e, 0x0cb1,
+ 0x620f, 0x0f24,
+ 0x6210, 0x04ee,
+ 0x6211, 0x0ee1,
+ 0x6212, 0x08b5,
+ 0x6213, 0x3283,
+ 0x6214, 0x24a3,
+ 0x6215, 0x169e,
+ 0x6216, 0x0807,
+ 0x6217, 0x18fa,
+ 0x6218, 0x115e,
+ 0x6219, 0x3284,
+ 0x621a, 0x0bfc,
+ 0x621b, 0x18fb,
+ 0x621c, 0x3285,
+ 0x621f, 0x18fc,
+ 0x6220, 0x3288,
+ 0x6221, 0x18fe,
+ 0x6222, 0x18fd,
+ 0x6223, 0x3289,
+ 0x6224, 0x1900,
+ 0x6225, 0x18ff,
+ 0x6226, 0x328a,
+ 0x6227, 0x24a4,
+ 0x6228, 0x328b,
+ 0x622a, 0x08a9,
+ 0x622b, 0x328d,
+ 0x622c, 0x1901,
+ 0x622d, 0x328e,
+ 0x622e, 0x0a65,
+ 0x622f, 0x328f,
+ 0x6230, 0x2273,
+ 0x6231, 0x3290,
+ 0x6232, 0x21b0,
+ 0x6233, 0x0544,
+ 0x6234, 0x057a,
+ 0x6235, 0x3291,
+ 0x6237, 0x07bc,
+ 0x6238, 0x3293,
+ 0x623d, 0x19f4,
+ 0x623e, 0x19f3,
+ 0x623f, 0x065c,
+ 0x6240, 0x0dee,
+ 0x6241, 0x044b,
+ 0x6242, 0x3298,
+ 0x6243, 0x19f5,
+ 0x6244, 0x3299,
+ 0x6247, 0x0d01,
+ 0x6248, 0x19f6,
+ 0x624a, 0x329c,
+ 0x624b, 0x0d6d,
+ 0x624c, 0x14ba,
+ 0x624d, 0x048c,
+ 0x624e, 0x113d,
+ 0x624f, 0x329d,
+ 0x6251, 0x0bea,
+ 0x6252, 0x03d2,
+ 0x6253, 0x0575,
+ 0x6254, 0x0cae,
+ 0x6255, 0x329f,
+ 0x6258, 0x0e81,
+ 0x6259, 0x32a2,
+ 0x625b, 0x0945,
+ 0x625c, 0x32a4,
+ 0x6263, 0x0968,
+ 0x6264, 0x32ab,
+ 0x6266, 0x0c21,
+ 0x6267, 0x11b3,
+ 0x6268, 0x32ad,
+ 0x6269, 0x0994,
+ 0x626a, 0x14bb,
+ 0x626b, 0x0ce1,
+ 0x626c, 0x1018,
+ 0x626d, 0x0b65,
+ 0x626e, 0x03f2,
+ 0x626f, 0x04db,
+ 0x6270, 0x0ca0,
+ 0x6271, 0x32ae,
+ 0x6273, 0x03ed,
+ 0x6274, 0x32b0,
+ 0x6276, 0x0693,
+ 0x6277, 0x32b2,
+ 0x6279, 0x0bbb,
+ 0x627a, 0x32b4,
+ 0x627c, 0x0632,
+ 0x627d, 0x32b6,
+ 0x627e, 0x1173,
+ 0x627f, 0x04f5,
+ 0x6280, 0x082f,
+ 0x6281, 0x32b7,
+ 0x6284, 0x04d2,
+ 0x6285, 0x32ba,
+ 0x6289, 0x0920,
+ 0x628a, 0x03dc,
+ 0x628b, 0x32be,
+ 0x6291, 0x105d,
+ 0x6292, 0x0d7a,
+ 0x6293, 0x1202,
+ 0x6294, 0x32c4,
+ 0x6295, 0x0e67,
+ 0x6296, 0x05f5,
+ 0x6297, 0x0946,
+ 0x6298, 0x117c,
+ 0x6299, 0x32c5,
+ 0x629a, 0x06a2,
+ 0x629b, 0x0b98,
+ 0x629c, 0x32c6,
+ 0x629f, 0x14bc,
+ 0x62a0, 0x0966,
+ 0x62a1, 0x0a7c,
+ 0x62a2, 0x0c3d,
+ 0x62a3, 0x32c9,
+ 0x62a4, 0x07b9,
+ 0x62a5, 0x0411,
+ 0x62a6, 0x32ca,
+ 0x62a8, 0x0bab,
+ 0x62a9, 0x32cc,
+ 0x62ab, 0x0bbc,
+ 0x62ac, 0x0dfa,
+ 0x62ad, 0x32ce,
+ 0x62b1, 0x0410,
+ 0x62b2, 0x32d2,
+ 0x62b5, 0x05b7,
+ 0x62b6, 0x32d5,
+ 0x62b9, 0x0b0b,
+ 0x62ba, 0x32d8,
+ 0x62bb, 0x14bd,
+ 0x62bc, 0x0fe3,
+ 0x62bd, 0x050e,
+ 0x62be, 0x32d9,
+ 0x62bf, 0x0af7,
+ 0x62c0, 0x32da,
+ 0x62c2, 0x0694,
+ 0x62c3, 0x32dc,
+ 0x62c4, 0x11f3,
+ 0x62c5, 0x0584,
+ 0x62c6, 0x04b7,
+ 0x62c7, 0x0b17,
+ 0x62c8, 0x0b4c,
+ 0x62c9, 0x0998,
+ 0x62ca, 0x14be,
+ 0x62cb, 0x32dd,
+ 0x62cc, 0x03f3,
+ 0x62cd, 0x0b85,
+ 0x62ce, 0x0a29,
+ 0x62cf, 0x32de,
+ 0x62d0, 0x072e,
+ 0x62d1, 0x32df,
+ 0x62d2, 0x090b,
+ 0x62d3, 0x0e89,
+ 0x62d4, 0x03d9,
+ 0x62d5, 0x32e0,
+ 0x62d6, 0x0e80,
+ 0x62d7, 0x14c0,
+ 0x62d8, 0x08ff,
+ 0x62d9, 0x121b,
+ 0x62da, 0x14bf,
+ 0x62db, 0x1171,
+ 0x62dc, 0x03e8,
+ 0x62dd, 0x32e1,
+ 0x62df, 0x0b45,
+ 0x62e0, 0x32e3,
+ 0x62e2, 0x0a4a,
+ 0x62e3, 0x0863,
+ 0x62e4, 0x32e5,
+ 0x62e5, 0x109a,
+ 0x62e6, 0x09a4,
+ 0x62e7, 0x0b62,
+ 0x62e8, 0x046d,
+ 0x62e9, 0x1134,
+ 0x62ea, 0x32e6,
+ 0x62ec, 0x0993,
+ 0x62ed, 0x0d5a,
+ 0x62ee, 0x14c1,
+ 0x62ef, 0x119d,
+ 0x62f0, 0x32e8,
+ 0x62f1, 0x0709,
+ 0x62f2, 0x32e9,
+ 0x62f3, 0x0c88,
+ 0x62f4, 0x0d9e,
+ 0x62f5, 0x32ea,
+ 0x62f6, 0x14c3,
+ 0x62f7, 0x094a,
+ 0x62f8, 0x32eb,
+ 0x62fc, 0x0bd3,
+ 0x62fd, 0x1204,
+ 0x62fe, 0x0d47,
+ 0x62ff, 0x0b26,
+ 0x6300, 0x32ef,
+ 0x6301, 0x04fb,
+ 0x6302, 0x072b,
+ 0x6303, 0x32f0,
+ 0x6307, 0x11b7,
+ 0x6308, 0x194e,
+ 0x6309, 0x03bf,
+ 0x630a, 0x32f4,
+ 0x630e, 0x0973,
+ 0x630f, 0x32f8,
+ 0x6311, 0x0e47,
+ 0x6312, 0x32fa,
+ 0x6316, 0x0e8b,
+ 0x6317, 0x32fe,
+ 0x631a, 0x11be,
+ 0x631b, 0x0a75,
+ 0x631c, 0x3301,
+ 0x631d, 0x0edd,
+ 0x631e, 0x0df5,
+ 0x631f, 0x0f79,
+ 0x6320, 0x0b36,
+ 0x6321, 0x0593,
+ 0x6322, 0x14c2,
+ 0x6323, 0x1196,
+ 0x6324, 0x082a,
+ 0x6325, 0x07e8,
+ 0x6326, 0x3302,
+ 0x6328, 0x03af,
+ 0x6329, 0x3304,
+ 0x632a, 0x0b73,
+ 0x632b, 0x056f,
+ 0x632c, 0x3305,
+ 0x632f, 0x1192,
+ 0x6330, 0x3308,
+ 0x6332, 0x194f,
+ 0x6333, 0x330a,
+ 0x6339, 0x14c4,
+ 0x633a, 0x0e57,
+ 0x633b, 0x3310,
+ 0x633d, 0x0e9d,
+ 0x633e, 0x21d1,
+ 0x633f, 0x3312,
+ 0x6342, 0x0ef5,
+ 0x6343, 0x14c6,
+ 0x6344, 0x3315,
+ 0x6345, 0x0e62,
+ 0x6346, 0x0991,
+ 0x6347, 0x3316,
+ 0x6349, 0x121a,
+ 0x634a, 0x3318,
+ 0x634b, 0x14c5,
+ 0x634c, 0x03d1,
+ 0x634d, 0x076b,
+ 0x634e, 0x0d0c,
+ 0x634f, 0x0b56,
+ 0x6350, 0x0917,
+ 0x6351, 0x3319,
+ 0x6355, 0x047d,
+ 0x6356, 0x331d,
+ 0x635e, 0x09b7,
+ 0x635f, 0x0de5,
+ 0x6360, 0x3325,
+ 0x6361, 0x0864,
+ 0x6362, 0x07d0,
+ 0x6363, 0x0598,
+ 0x6364, 0x3326,
+ 0x6367, 0x0bb6,
+ 0x6368, 0x211c,
+ 0x6369, 0x14d0,
+ 0x636a, 0x3329,
+ 0x636b, 0x235d,
+ 0x636c, 0x332a,
+ 0x636d, 0x14cd,
+ 0x636e, 0x090c,
+ 0x636f, 0x332b,
+ 0x6371, 0x14c9,
+ 0x6372, 0x2682,
+ 0x6373, 0x332d,
+ 0x6376, 0x053a,
+ 0x6377, 0x08ae,
+ 0x6378, 0x3330,
+ 0x637a, 0x14ca,
+ 0x637b, 0x0b50,
+ 0x637c, 0x3332,
+ 0x6380, 0x0f33,
+ 0x6381, 0x3336,
+ 0x6382, 0x05c1,
+ 0x6383, 0x210d,
+ 0x6384, 0x205a,
+ 0x6385, 0x3337,
+ 0x6387, 0x061d,
+ 0x6388, 0x0d71,
+ 0x6389, 0x05d5,
+ 0x638a, 0x14cf,
+ 0x638b, 0x3339,
+ 0x638c, 0x1167,
+ 0x638d, 0x333a,
+ 0x638e, 0x14cb,
+ 0x638f, 0x0e20,
+ 0x6390, 0x0c1d,
+ 0x6391, 0x333b,
+ 0x6392, 0x0b86,
+ 0x6393, 0x333c,
+ 0x6396, 0x103b,
+ 0x6397, 0x333f,
+ 0x6398, 0x0921,
+ 0x6399, 0x3340,
+ 0x63a0, 0x0a7a,
+ 0x63a1, 0x3347,
+ 0x63a2, 0x0e10,
+ 0x63a3, 0x04dd,
+ 0x63a4, 0x3348,
+ 0x63a5, 0x08a4,
+ 0x63a6, 0x3349,
+ 0x63a7, 0x0965,
+ 0x63a8, 0x0e77,
+ 0x63a9, 0x1003,
+ 0x63aa, 0x056e,
+ 0x63ab, 0x334a,
+ 0x63ac, 0x14ce,
+ 0x63ad, 0x14c7,
+ 0x63ae, 0x14d1,
+ 0x63af, 0x334b,
+ 0x63b0, 0x1950,
+ 0x63b1, 0x334c,
+ 0x63b3, 0x0a57,
+ 0x63b4, 0x14cc,
+ 0x63b5, 0x334e,
+ 0x63b7, 0x11bf,
+ 0x63b8, 0x0588,
+ 0x63b9, 0x3350,
+ 0x63ba, 0x04bb,
+ 0x63bb, 0x3351,
+ 0x63bc, 0x14d2,
+ 0x63bd, 0x3352,
+ 0x63be, 0x14dc,
+ 0x63bf, 0x3353,
+ 0x63c0, 0x1f8d,
+ 0x63c1, 0x3354,
+ 0x63c4, 0x14d7,
+ 0x63c5, 0x3357,
+ 0x63c6, 0x14db,
+ 0x63c7, 0x3358,
+ 0x63c9, 0x0cbb,
+ 0x63ca, 0x335a,
+ 0x63cd, 0x123e,
+ 0x63ce, 0x14d9,
+ 0x63cf, 0x0aed,
+ 0x63d0, 0x0e34,
+ 0x63d1, 0x335d,
+ 0x63d2, 0x04ac,
+ 0x63d3, 0x335e,
+ 0x63d6, 0x1045,
+ 0x63d7, 0x3361,
+ 0x63da, 0x21ff,
+ 0x63db, 0x3364,
+ 0x63de, 0x14d8,
+ 0x63df, 0x3367,
+ 0x63e0, 0x14d5,
+ 0x63e1, 0x0ee4,
+ 0x63e2, 0x3368,
+ 0x63e3, 0x052a,
+ 0x63e4, 0x3369,
+ 0x63e9, 0x0938,
+ 0x63ea, 0x08ed,
+ 0x63eb, 0x336e,
+ 0x63ed, 0x08a3,
+ 0x63ee, 0x1f58,
+ 0x63ef, 0x3370,
+ 0x63f2, 0x14d3,
+ 0x63f3, 0x3373,
+ 0x63f4, 0x10f1,
+ 0x63f5, 0x3374,
+ 0x63f6, 0x14c8,
+ 0x63f7, 0x3375,
+ 0x63f8, 0x14d4,
+ 0x63f9, 0x3376,
+ 0x63fd, 0x09aa,
+ 0x63fe, 0x337a,
+ 0x63ff, 0x14d6,
+ 0x6400, 0x04ba,
+ 0x6401, 0x06e4,
+ 0x6402, 0x0a4e,
+ 0x6403, 0x337b,
+ 0x6405, 0x0892,
+ 0x6406, 0x337d,
+ 0x640b, 0x14df,
+ 0x640c, 0x14e2,
+ 0x640d, 0x215b,
+ 0x640e, 0x3382,
+ 0x640f, 0x0472,
+ 0x6410, 0x0527,
+ 0x6411, 0x3383,
+ 0x6413, 0x056d,
+ 0x6414, 0x0cdf,
+ 0x6415, 0x3385,
+ 0x6417, 0x1eb6,
+ 0x6418, 0x3387,
+ 0x641b, 0x14e0,
+ 0x641c, 0x0dc6,
+ 0x641d, 0x338a,
+ 0x641e, 0x06de,
+ 0x641f, 0x338b,
+ 0x6420, 0x14e1,
+ 0x6421, 0x14e4,
+ 0x6422, 0x338c,
+ 0x6426, 0x14e3,
+ 0x6427, 0x3390,
+ 0x642a, 0x0e15,
+ 0x642b, 0x3393,
+ 0x642c, 0x03ec,
+ 0x642d, 0x0571,
+ 0x642e, 0x3394,
+ 0x6434, 0x1736,
+ 0x6435, 0x339a,
+ 0x6436, 0x20db,
+ 0x6437, 0x339b,
+ 0x643a, 0x0f7a,
+ 0x643b, 0x339e,
+ 0x643d, 0x04b2,
+ 0x643e, 0x33a0,
+ 0x643f, 0x1951,
+ 0x6440, 0x33a1,
+ 0x6441, 0x14de,
+ 0x6442, 0x33a2,
+ 0x6444, 0x0d1c,
+ 0x6445, 0x14dd,
+ 0x6446, 0x03e5,
+ 0x6447, 0x1028,
+ 0x6448, 0x0460,
+ 0x6449, 0x33a4,
+ 0x644a, 0x0e02,
+ 0x644b, 0x33a5,
+ 0x6451, 0x2360,
+ 0x6452, 0x14da,
+ 0x6453, 0x33ab,
+ 0x6454, 0x0d99,
+ 0x6455, 0x33ac,
+ 0x6458, 0x114b,
+ 0x6459, 0x33af,
+ 0x645c, 0x2361,
+ 0x645d, 0x33b2,
+ 0x645e, 0x14e5,
+ 0x645f, 0x2040,
+ 0x6460, 0x33b3,
+ 0x6467, 0x0560,
+ 0x6468, 0x33ba,
+ 0x6469, 0x0b09,
+ 0x646a, 0x33bb,
+ 0x646d, 0x14e7,
+ 0x646e, 0x33be,
+ 0x646f, 0x228e,
+ 0x6470, 0x33bf,
+ 0x6473, 0x1fdf,
+ 0x6474, 0x33c2,
+ 0x6476, 0x235e,
+ 0x6477, 0x33c4,
+ 0x6478, 0x0b03,
+ 0x647a, 0x14e9,
+ 0x647b, 0x1e6a,
+ 0x647c, 0x33c5,
+ 0x6482, 0x0a15,
+ 0x6483, 0x33cb,
+ 0x6484, 0x14e6,
+ 0x6485, 0x091e,
+ 0x6486, 0x33cc,
+ 0x6487, 0x0bd1,
+ 0x6488, 0x2002,
+ 0x6489, 0x33cd,
+ 0x6491, 0x04ea,
+ 0x6492, 0x0cd1,
+ 0x6493, 0x2093,
+ 0x6494, 0x33d5,
+ 0x6495, 0x0daf,
+ 0x6496, 0x14e8,
+ 0x6497, 0x33d6,
+ 0x6499, 0x14ec,
+ 0x649a, 0x33d8,
+ 0x649e, 0x120f,
+ 0x649f, 0x235f,
+ 0x64a0, 0x33dc,
+ 0x64a3, 0x1eac,
+ 0x64a4, 0x04dc,
+ 0x64a5, 0x1e54,
+ 0x64a6, 0x33df,
+ 0x64a9, 0x0a0c,
+ 0x64aa, 0x33e2,
+ 0x64ab, 0x1f08,
+ 0x64ac, 0x0c48,
+ 0x64ad, 0x046c,
+ 0x64ae, 0x056c,
+ 0x64af, 0x33e3,
+ 0x64b0, 0x1208,
+ 0x64b1, 0x33e4,
+ 0x64b2, 0x20c0,
+ 0x64b3, 0x2362,
+ 0x64b4, 0x33e5,
+ 0x64b5, 0x0b4f,
+ 0x64b6, 0x33e6,
+ 0x64b7, 0x14ea,
+ 0x64b9, 0x33e7,
+ 0x64ba, 0x14ed,
+ 0x64bb, 0x2160,
+ 0x64bc, 0x076a,
+ 0x64bd, 0x33e8,
+ 0x64be, 0x219d,
+ 0x64bf, 0x1f8e,
+ 0x64c0, 0x14ee,
+ 0x64c1, 0x222d,
+ 0x64c2, 0x09c9,
+ 0x64c3, 0x33e9,
+ 0x64c4, 0x2047,
+ 0x64c5, 0x0cfc,
+ 0x64c6, 0x33ea,
+ 0x64c7, 0x2262,
+ 0x64c8, 0x33eb,
+ 0x64ca, 0x1f67,
+ 0x64cb, 0x1eb2,
+ 0x64cc, 0x33ed,
+ 0x64cd, 0x04a0,
+ 0x64ce, 0x0c63,
+ 0x64cf, 0x33ee,
+ 0x64d0, 0x14ef,
+ 0x64d1, 0x33ef,
+ 0x64d2, 0x0c59,
+ 0x64d3, 0x33f0,
+ 0x64d4, 0x1ea9,
+ 0x64d5, 0x33f1,
+ 0x64d7, 0x14f0,
+ 0x64d8, 0x1952,
+ 0x64d9, 0x33f3,
+ 0x64da, 0x1fcc,
+ 0x64db, 0x33f4,
+ 0x64de, 0x0dc8,
+ 0x64df, 0x33f7,
+ 0x64e0, 0x1f72,
+ 0x64e1, 0x33f8,
+ 0x64e2, 0x14f2,
+ 0x64e3, 0x33f9,
+ 0x64e4, 0x14f1,
+ 0x64e5, 0x33fa,
+ 0x64e6, 0x0488,
+ 0x64e7, 0x33fb,
+ 0x64ec, 0x2098,
+ 0x64ed, 0x3400,
+ 0x64ef, 0x1e52,
+ 0x64f0, 0x20a4,
+ 0x64f1, 0x1f1c,
+ 0x64f2, 0x228f,
+ 0x64f3, 0x3402,
+ 0x64f4, 0x1fed,
+ 0x64f5, 0x3403,
+ 0x64f7, 0x2365,
+ 0x64f8, 0x3405,
+ 0x64fa, 0x1e2d,
+ 0x64fb, 0x2152,
+ 0x64fc, 0x2366,
+ 0x64fd, 0x3407,
+ 0x64fe, 0x20fa,
+ 0x64ff, 0x3408,
+ 0x6500, 0x0b8b,
+ 0x6501, 0x3409,
+ 0x6504, 0x2363,
+ 0x6505, 0x340c,
+ 0x6506, 0x209a,
+ 0x6507, 0x340d,
+ 0x6509, 0x14f3,
+ 0x650a, 0x340f,
+ 0x650f, 0x203c,
+ 0x6510, 0x3414,
+ 0x6512, 0x111f,
+ 0x6513, 0x3416,
+ 0x6514, 0x1ff6,
+ 0x6515, 0x3417,
+ 0x6516, 0x2364,
+ 0x6517, 0x3418,
+ 0x6518, 0x0c9c,
+ 0x6519, 0x1e69,
+ 0x651a, 0x3419,
+ 0x651b, 0x2367,
+ 0x651c, 0x341a,
+ 0x651d, 0x211d,
+ 0x651e, 0x341b,
+ 0x6522, 0x2259,
+ 0x6523, 0x2056,
+ 0x6524, 0x2163,
+ 0x6525, 0x14f4,
+ 0x6526, 0x341f,
+ 0x652a, 0x1fa9,
+ 0x652b, 0x091f,
+ 0x652c, 0x1ffc,
+ 0x652d, 0x3423,
+ 0x652e, 0x14f5,
+ 0x652f, 0x11a6,
+ 0x6530, 0x3424,
+ 0x6534, 0x1909,
+ 0x6535, 0x1966,
+ 0x6536, 0x0d6c,
+ 0x6537, 0x3428,
+ 0x6538, 0x12b2,
+ 0x6539, 0x06bf,
+ 0x653a, 0x3429,
+ 0x653b, 0x06fe,
+ 0x653c, 0x342a,
+ 0x653e, 0x0662,
+ 0x653f, 0x119f,
+ 0x6540, 0x342c,
+ 0x6545, 0x0723,
+ 0x6546, 0x3431,
+ 0x6548, 0x0f72,
+ 0x6549, 0x1ccb,
+ 0x654a, 0x3433,
+ 0x654c, 0x05b1,
+ 0x654d, 0x3435,
+ 0x654f, 0x0af9,
+ 0x6550, 0x3437,
+ 0x6551, 0x08f7,
+ 0x6552, 0x3438,
+ 0x6555, 0x1967,
+ 0x6556, 0x03c8,
+ 0x6557, 0x1e2e,
+ 0x6558, 0x343b,
+ 0x6559, 0x089d,
+ 0x655a, 0x343c,
+ 0x655b, 0x09fb,
+ 0x655c, 0x343d,
+ 0x655d, 0x043f,
+ 0x655e, 0x04cd,
+ 0x655f, 0x343e,
+ 0x6562, 0x06cd,
+ 0x6563, 0x0cdb,
+ 0x6564, 0x3441,
+ 0x6566, 0x0617,
+ 0x6567, 0x3443,
+ 0x656b, 0x1968,
+ 0x656c, 0x08e3,
+ 0x656d, 0x3447,
+ 0x6570, 0x0d94,
+ 0x6571, 0x344a,
+ 0x6572, 0x0c40,
+ 0x6573, 0x344b,
+ 0x6574, 0x119c,
+ 0x6575, 0x1ebc,
+ 0x6576, 0x344c,
+ 0x6577, 0x0690,
+ 0x6578, 0x2142,
+ 0x6579, 0x344d,
+ 0x6582, 0x201e,
+ 0x6583, 0x1e43,
+ 0x6584, 0x3456,
+ 0x6587, 0x0ed3,
+ 0x6588, 0x3459,
+ 0x658b, 0x114c,
+ 0x658c, 0x045c,
+ 0x658d, 0x345c,
+ 0x6590, 0x19c1,
+ 0x6591, 0x03ea,
+ 0x6592, 0x345f,
+ 0x6593, 0x19c3,
+ 0x6594, 0x3460,
+ 0x6595, 0x24d4,
+ 0x6596, 0x3461,
+ 0x6597, 0x05f6,
+ 0x6598, 0x3462,
+ 0x6599, 0x0a18,
+ 0x659a, 0x3463,
+ 0x659b, 0x1d56,
+ 0x659c, 0x0f7c,
+ 0x659d, 0x3464,
+ 0x659f, 0x1186,
+ 0x65a0, 0x3466,
+ 0x65a1, 0x0ee2,
+ 0x65a2, 0x3467,
+ 0x65a4, 0x08c0,
+ 0x65a5, 0x0507,
+ 0x65a6, 0x3469,
+ 0x65a7, 0x06a6,
+ 0x65a8, 0x346a,
+ 0x65a9, 0x1157,
+ 0x65aa, 0x346b,
+ 0x65ab, 0x1a29,
+ 0x65ac, 0x226f,
+ 0x65ad, 0x060e,
+ 0x65ae, 0x346c,
+ 0x65af, 0x0dae,
+ 0x65b0, 0x0f8d,
+ 0x65b1, 0x346d,
+ 0x65b7, 0x1ed7,
+ 0x65b8, 0x3473,
+ 0x65b9, 0x065a,
+ 0x65ba, 0x3474,
+ 0x65bc, 0x19c4,
+ 0x65bd, 0x0d40,
+ 0x65be, 0x3476,
+ 0x65c1, 0x0b95,
+ 0x65c2, 0x3479,
+ 0x65c3, 0x19c7,
+ 0x65c4, 0x19c6,
+ 0x65c5, 0x0a6a,
+ 0x65c6, 0x19c5,
+ 0x65c7, 0x347a,
+ 0x65cb, 0x0fc8,
+ 0x65cc, 0x19c8,
+ 0x65cd, 0x347e,
+ 0x65ce, 0x19c9,
+ 0x65cf, 0x1242,
+ 0x65d0, 0x347f,
+ 0x65d2, 0x19ca,
+ 0x65d3, 0x3481,
+ 0x65d6, 0x19cb,
+ 0x65d7, 0x0c0b,
+ 0x65d8, 0x3484,
+ 0x65e0, 0x0eed,
+ 0x65e1, 0x348c,
+ 0x65e2, 0x083b,
+ 0x65e3, 0x348d,
+ 0x65e5, 0x0cb0,
+ 0x65e6, 0x058a,
+ 0x65e7, 0x08f8,
+ 0x65e8, 0x11bb,
+ 0x65e9, 0x112a,
+ 0x65ea, 0x348f,
+ 0x65ec, 0x0fd7,
+ 0x65ed, 0x0fbc,
+ 0x65ee, 0x190a,
+ 0x65f1, 0x076c,
+ 0x65f2, 0x3491,
+ 0x65f6, 0x0d48,
+ 0x65f7, 0x0982,
+ 0x65f8, 0x3495,
+ 0x65fa, 0x0eab,
+ 0x65fb, 0x3497,
+ 0x6600, 0x1912,
+ 0x6601, 0x349c,
+ 0x6602, 0x03c5,
+ 0x6603, 0x1910,
+ 0x6604, 0x349d,
+ 0x6606, 0x0990,
+ 0x6607, 0x349f,
+ 0x660a, 0x190d,
+ 0x660b, 0x34a2,
+ 0x660c, 0x04c4,
+ 0x660d, 0x34a3,
+ 0x660e, 0x0afc,
+ 0x660f, 0x07fd,
+ 0x6610, 0x34a4,
+ 0x6613, 0x105e,
+ 0x6614, 0x0f03,
+ 0x6615, 0x1911,
+ 0x6616, 0x34a7,
+ 0x6619, 0x190e,
+ 0x661a, 0x34aa,
+ 0x661d, 0x1915,
+ 0x661e, 0x34ad,
+ 0x661f, 0x0f92,
+ 0x6620, 0x1098,
+ 0x6621, 0x34ae,
+ 0x6625, 0x053d,
+ 0x6626, 0x34b2,
+ 0x6627, 0x0ac6,
+ 0x6628, 0x124f,
+ 0x6629, 0x34b3,
+ 0x662d, 0x1172,
+ 0x662e, 0x34b7,
+ 0x662f, 0x0d5e,
+ 0x6630, 0x34b8,
+ 0x6631, 0x1917,
+ 0x6632, 0x34b9,
+ 0x6634, 0x1916,
+ 0x6635, 0x1919,
+ 0x6636, 0x1918,
+ 0x6637, 0x34bb,
+ 0x663c, 0x11e6,
+ 0x663d, 0x34c0,
+ 0x663e, 0x0f41,
+ 0x663f, 0x34c1,
+ 0x6641, 0x191d,
+ 0x6642, 0x212d,
+ 0x6643, 0x07e3,
+ 0x6644, 0x34c3,
+ 0x664b, 0x08cb,
+ 0x664c, 0x0d07,
+ 0x664d, 0x34ca,
+ 0x664f, 0x191e,
+ 0x6650, 0x34cc,
+ 0x6652, 0x0cf2,
+ 0x6653, 0x0f6b,
+ 0x6654, 0x191c,
+ 0x6655, 0x1111,
+ 0x6656, 0x191f,
+ 0x6657, 0x1921,
+ 0x6658, 0x34ce,
+ 0x665a, 0x0e9e,
+ 0x665b, 0x34d0,
+ 0x665d, 0x229b,
+ 0x665e, 0x34d2,
+ 0x665f, 0x191b,
+ 0x6660, 0x34d3,
+ 0x6661, 0x1920,
+ 0x6662, 0x34d4,
+ 0x6664, 0x0efd,
+ 0x6665, 0x34d6,
+ 0x6666, 0x07f3,
+ 0x6667, 0x34d7,
+ 0x6668, 0x04e4,
+ 0x6669, 0x34d8,
+ 0x666e, 0x0bf4,
+ 0x666f, 0x08df,
+ 0x6670, 0x0f09,
+ 0x6671, 0x34dd,
+ 0x6674, 0x0c64,
+ 0x6675, 0x34e0,
+ 0x6676, 0x08d6,
+ 0x6677, 0x1922,
+ 0x6678, 0x34e1,
+ 0x667a, 0x11c6,
+ 0x667b, 0x34e3,
+ 0x667e, 0x0a09,
+ 0x667f, 0x34e6,
+ 0x6682, 0x1120,
+ 0x6683, 0x34e9,
+ 0x6684, 0x1923,
+ 0x6685, 0x34ea,
+ 0x6687, 0x0f2b,
+ 0x6688, 0x2256,
+ 0x6689, 0x24a8,
+ 0x668a, 0x34ec,
+ 0x668c, 0x1924,
+ 0x668d, 0x34ee,
+ 0x6691, 0x0d85,
+ 0x6692, 0x34f2,
+ 0x6696, 0x0b70,
+ 0x6697, 0x03c0,
+ 0x6698, 0x34f6,
+ 0x669d, 0x1926,
+ 0x669e, 0x34fb,
+ 0x66a2, 0x1e79,
+ 0x66a3, 0x34ff,
+ 0x66a7, 0x1925,
+ 0x66a8, 0x1cdd,
+ 0x66a9, 0x3503,
+ 0x66ab, 0x225a,
+ 0x66ac, 0x3505,
+ 0x66ae, 0x0b1d,
+ 0x66af, 0x3507,
+ 0x66b4, 0x0412,
+ 0x66b5, 0x350c,
+ 0x66b9, 0x175b,
+ 0x66ba, 0x3510,
+ 0x66be, 0x1927,
+ 0x66bf, 0x3514,
+ 0x66c4, 0x24a7,
+ 0x66c5, 0x3519,
+ 0x66c6, 0x2686,
+ 0x66c7, 0x24a6,
+ 0x66c8, 0x351a,
+ 0x66c9, 0x21ce,
+ 0x66ca, 0x351b,
+ 0x66d6, 0x24a9,
+ 0x66d7, 0x3527,
+ 0x66d9, 0x0d86,
+ 0x66da, 0x3529,
+ 0x66db, 0x1928,
+ 0x66dd, 0x0bf7,
+ 0x66de, 0x352a,
+ 0x66e0, 0x1fe7,
+ 0x66e1, 0x352c,
+ 0x66e6, 0x192a,
+ 0x66e7, 0x3531,
+ 0x66e9, 0x192b,
+ 0x66ea, 0x3533,
+ 0x66ec, 0x2112,
+ 0x66ed, 0x3535,
+ 0x66f0, 0x10fe,
+ 0x66f1, 0x3538,
+ 0x66f2, 0x0c77,
+ 0x66f3, 0x103e,
+ 0x66f4, 0x06f7,
+ 0x66f5, 0x3539,
+ 0x66f7, 0x1914,
+ 0x66f8, 0x213c,
+ 0x66f9, 0x04a3,
+ 0x66fa, 0x353b,
+ 0x66fc, 0x0aa3,
+ 0x66fd, 0x353d,
+ 0x66fe, 0x113b,
+ 0x66ff, 0x0e39,
+ 0x6700, 0x124b,
+ 0x6701, 0x353e,
+ 0x6703, 0x1f5c,
+ 0x6704, 0x3540,
+ 0x6708, 0x1105,
+ 0x6709, 0x10b5,
+ 0x670a, 0x1973,
+ 0x670b, 0x0bb4,
+ 0x670c, 0x3544,
+ 0x670d, 0x069b,
+ 0x670e, 0x3545,
+ 0x6710, 0x1984,
+ 0x6711, 0x3547,
+ 0x6714, 0x0dac,
+ 0x6715, 0x198e,
+ 0x6716, 0x354a,
+ 0x6717, 0x09b5,
+ 0x6718, 0x354b,
+ 0x671b, 0x0eac,
+ 0x671c, 0x354e,
+ 0x671d, 0x04d4,
+ 0x671e, 0x354f,
+ 0x671f, 0x0bf9,
+ 0x6720, 0x3550,
+ 0x6726, 0x19ac,
+ 0x6727, 0x24c4,
+ 0x6728, 0x0b21,
+ 0x6729, 0x3556,
+ 0x672a, 0x0ec3,
+ 0x672b, 0x0b0c,
+ 0x672c, 0x0427,
+ 0x672d, 0x1140,
+ 0x672e, 0x3557,
+ 0x672f, 0x0d8c,
+ 0x6730, 0x3558,
+ 0x6731, 0x11eb,
+ 0x6732, 0x3559,
+ 0x6734, 0x0bf2,
+ 0x6735, 0x0623,
+ 0x6736, 0x355b,
+ 0x673a, 0x080f,
+ 0x673b, 0x355f,
+ 0x673d, 0x0fab,
+ 0x673e, 0x3561,
+ 0x6740, 0x0cea,
+ 0x6741, 0x3563,
+ 0x6742, 0x1116,
+ 0x6743, 0x0c83,
+ 0x6744, 0x3564,
+ 0x6746, 0x06c6,
+ 0x6747, 0x3566,
+ 0x6748, 0x1854,
+ 0x6749, 0x0cf5,
+ 0x674a, 0x3567,
+ 0x674c, 0x1851,
+ 0x674d, 0x3569,
+ 0x674e, 0x09d9,
+ 0x674f, 0x0f9e,
+ 0x6750, 0x048b,
+ 0x6751, 0x0568,
+ 0x6752, 0x356a,
+ 0x6753, 0x1852,
+ 0x6754, 0x356b,
+ 0x6756, 0x1169,
+ 0x6757, 0x356d,
+ 0x675c, 0x0604,
+ 0x675d, 0x3572,
+ 0x675e, 0x1853,
+ 0x675f, 0x0d8f,
+ 0x6760, 0x06d7,
+ 0x6761, 0x0e48,
+ 0x6762, 0x3573,
+ 0x6765, 0x099f,
+ 0x6766, 0x3576,
+ 0x6768, 0x1017,
+ 0x6769, 0x1855,
+ 0x676a, 0x1858,
+ 0x676b, 0x3578,
+ 0x676d, 0x0773,
+ 0x676e, 0x357a,
+ 0x676f, 0x0416,
+ 0x6770, 0x08ad,
+ 0x6771, 0x1ecc,
+ 0x6772, 0x190f,
+ 0x6773, 0x1859,
+ 0x6774, 0x357b,
+ 0x6775, 0x185c,
+ 0x6776, 0x357c,
+ 0x6777, 0x1861,
+ 0x6778, 0x357d,
+ 0x677c, 0x1862,
+ 0x677d, 0x3581,
+ 0x677e, 0x0dbe,
+ 0x677f, 0x03f0,
+ 0x6780, 0x3582,
+ 0x6781, 0x081e,
+ 0x6782, 0x3583,
+ 0x6784, 0x0712,
+ 0x6785, 0x3585,
+ 0x6787, 0x1857,
+ 0x6788, 0x3587,
+ 0x6789, 0x0ea8,
+ 0x678a, 0x3588,
+ 0x678b, 0x1860,
+ 0x678c, 0x3589,
+ 0x6790, 0x0f05,
+ 0x6791, 0x358d,
+ 0x6795, 0x118e,
+ 0x6796, 0x3591,
+ 0x6797, 0x0a1f,
+ 0x6798, 0x185a,
+ 0x6799, 0x3592,
+ 0x679a, 0x0abb,
+ 0x679b, 0x3593,
+ 0x679c, 0x0754,
+ 0x679d, 0x11a5,
+ 0x679e, 0x185e,
+ 0x679f, 0x3594,
+ 0x67a2, 0x0d77,
+ 0x67a3, 0x1129,
+ 0x67a4, 0x3597,
+ 0x67a5, 0x1856,
+ 0x67a6, 0x3598,
+ 0x67a7, 0x185b,
+ 0x67a8, 0x185d,
+ 0x67a9, 0x3599,
+ 0x67aa, 0x0c36,
+ 0x67ab, 0x0680,
+ 0x67ac, 0x359a,
+ 0x67ad, 0x185f,
+ 0x67ae, 0x359b,
+ 0x67af, 0x096a,
+ 0x67b0, 0x1868,
+ 0x67b1, 0x359c,
+ 0x67b3, 0x186d,
+ 0x67b4, 0x359e,
+ 0x67b5, 0x186b,
+ 0x67b6, 0x084f,
+ 0x67b7, 0x0842,
+ 0x67b8, 0x1871,
+ 0x67b9, 0x359f,
+ 0x67c1, 0x1874,
+ 0x67c2, 0x35a7,
+ 0x67c3, 0x1870,
+ 0x67c4, 0x0463,
+ 0x67c5, 0x35a8,
+ 0x67cf, 0x03e3,
+ 0x67d0, 0x0b16,
+ 0x67d1, 0x06c7,
+ 0x67d2, 0x0c01,
+ 0x67d3, 0x0c99,
+ 0x67d4, 0x0cbc,
+ 0x67d5, 0x35b2,
+ 0x67d8, 0x1865,
+ 0x67d9, 0x186a,
+ 0x67da, 0x186c,
+ 0x67db, 0x35b5,
+ 0x67dc, 0x074a,
+ 0x67dd, 0x186e,
+ 0x67de, 0x1252,
+ 0x67df, 0x35b6,
+ 0x67e0, 0x0b5e,
+ 0x67e1, 0x35b7,
+ 0x67e2, 0x1872,
+ 0x67e3, 0x35b8,
+ 0x67e5, 0x04b0,
+ 0x67e6, 0x35ba,
+ 0x67e9, 0x1867,
+ 0x67ea, 0x35bd,
+ 0x67ec, 0x0860,
+ 0x67ed, 0x35bf,
+ 0x67ef, 0x094f,
+ 0x67f0, 0x1863,
+ 0x67f1, 0x11f8,
+ 0x67f2, 0x35c1,
+ 0x67f3, 0x0a41,
+ 0x67f4, 0x04b8,
+ 0x67f5, 0x35c2,
+ 0x67fd, 0x1875,
+ 0x67fe, 0x35ca,
+ 0x67ff, 0x0d58,
+ 0x6800, 0x186f,
+ 0x6801, 0x35cb,
+ 0x6805, 0x1145,
+ 0x6806, 0x35cf,
+ 0x6807, 0x0453,
+ 0x6808, 0x115c,
+ 0x6809, 0x1864,
+ 0x680a, 0x1866,
+ 0x680b, 0x05ef,
+ 0x680c, 0x1869,
+ 0x680d, 0x35d0,
+ 0x680e, 0x1873,
+ 0x680f, 0x09a3,
+ 0x6810, 0x35d1,
+ 0x6811, 0x0d8e,
+ 0x6812, 0x35d2,
+ 0x6813, 0x0d9d,
+ 0x6814, 0x35d3,
+ 0x6816, 0x0bfb,
+ 0x6817, 0x09e0,
+ 0x6818, 0x35d5,
+ 0x681d, 0x187f,
+ 0x681e, 0x35da,
+ 0x6821, 0x0f6e,
+ 0x6822, 0x35dd,
+ 0x6829, 0x1888,
+ 0x682a, 0x11e9,
+ 0x682b, 0x35e4,
+ 0x6832, 0x1876,
+ 0x6834, 0x35eb,
+ 0x6837, 0x1022,
+ 0x6838, 0x0782,
+ 0x6839, 0x06f4,
+ 0x683a, 0x35ee,
+ 0x683c, 0x06ec,
+ 0x683d, 0x1117,
+ 0x683e, 0x1885,
+ 0x683f, 0x35f0,
+ 0x6840, 0x1884,
+ 0x6841, 0x1882,
+ 0x6842, 0x0749,
+ 0x6843, 0x0e25,
+ 0x6844, 0x187c,
+ 0x6845, 0x0eb5,
+ 0x6846, 0x097f,
+ 0x6847, 0x35f1,
+ 0x6848, 0x03c3,
+ 0x6849, 0x1887,
+ 0x684a, 0x1886,
+ 0x684b, 0x35f2,
+ 0x684c, 0x121d,
+ 0x684d, 0x35f3,
+ 0x684e, 0x187a,
+ 0x684f, 0x35f4,
+ 0x6850, 0x0e5a,
+ 0x6851, 0x0cdc,
+ 0x6852, 0x35f5,
+ 0x6853, 0x07cd,
+ 0x6854, 0x08ac,
+ 0x6855, 0x1880,
+ 0x6856, 0x35f6,
+ 0x6860, 0x1878,
+ 0x6862, 0x187b,
+ 0x6863, 0x0596,
+ 0x6864, 0x187d,
+ 0x6865, 0x0c42,
+ 0x6866, 0x1881,
+ 0x6867, 0x1883,
+ 0x6868, 0x0881,
+ 0x6869, 0x120b,
+ 0x686a, 0x3600,
+ 0x686b, 0x188e,
+ 0x686c, 0x3601,
+ 0x6874, 0x188b,
+ 0x6875, 0x3609,
+ 0x6876, 0x0e61,
+ 0x6877, 0x188c,
+ 0x6878, 0x360a,
+ 0x6881, 0x0a03,
+ 0x6882, 0x3613,
+ 0x6883, 0x187e,
+ 0x6884, 0x3614,
+ 0x6885, 0x0abc,
+ 0x6886, 0x03fb,
+ 0x6887, 0x3615,
+ 0x688f, 0x188a,
+ 0x6890, 0x361d,
+ 0x6893, 0x188d,
+ 0x6894, 0x3620,
+ 0x6897, 0x06fc,
+ 0x6898, 0x246a,
+ 0x6899, 0x3623,
+ 0x689d, 0x2175,
+ 0x689e, 0x3627,
+ 0x689f, 0x246d,
+ 0x68a0, 0x3628,
+ 0x68a2, 0x0d0b,
+ 0x68a3, 0x362a,
+ 0x68a6, 0x0ad3,
+ 0x68a7, 0x0eef,
+ 0x68a8, 0x09d1,
+ 0x68a9, 0x362d,
+ 0x68ad, 0x0de8,
+ 0x68ae, 0x3631,
+ 0x68af, 0x0e30,
+ 0x68b0, 0x0f80,
+ 0x68b1, 0x3632,
+ 0x68b3, 0x0d78,
+ 0x68b4, 0x3634,
+ 0x68b5, 0x1889,
+ 0x68b6, 0x3635,
+ 0x68c0, 0x085f,
+ 0x68c1, 0x363f,
+ 0x68c2, 0x188f,
+ 0x68c3, 0x3640,
+ 0x68c9, 0x0ae3,
+ 0x68ca, 0x3646,
+ 0x68cb, 0x0c04,
+ 0x68cc, 0x3647,
+ 0x68cd, 0x0750,
+ 0x68ce, 0x3648,
+ 0x68d2, 0x03ff,
+ 0x68d3, 0x364c,
+ 0x68d5, 0x1235,
+ 0x68d6, 0x246b,
+ 0x68d7, 0x225f,
+ 0x68d8, 0x081f,
+ 0x68d9, 0x364e,
+ 0x68da, 0x0bb0,
+ 0x68db, 0x364f,
+ 0x68df, 0x1ece,
+ 0x68e0, 0x0e17,
+ 0x68e1, 0x3653,
+ 0x68e3, 0x189a,
+ 0x68e4, 0x3655,
+ 0x68e7, 0x2272,
+ 0x68e8, 0x3658,
+ 0x68ee, 0x0ce6,
+ 0x68ef, 0x365e,
+ 0x68f0, 0x1896,
+ 0x68f1, 0x09cd,
+ 0x68f2, 0x365f,
+ 0x68f5, 0x0950,
+ 0x68f6, 0x3662,
+ 0x68f9, 0x1894,
+ 0x68fa, 0x0730,
+ 0x68fb, 0x3665,
+ 0x68fc, 0x1891,
+ 0x68fd, 0x3666,
+ 0x6900, 0x3669,
+ 0x6901, 0x1898,
+ 0x6902, 0x366a,
+ 0x6905, 0x1055,
+ 0x6906, 0x366d,
+ 0x690b, 0x1897,
+ 0x690c, 0x3672,
+ 0x690d, 0x11b1,
+ 0x690e, 0x1212,
+ 0x690f, 0x2473,
+ 0x6910, 0x189b,
+ 0x6911, 0x3673,
+ 0x6912, 0x0888,
+ 0x6913, 0x3674,
+ 0x691f, 0x1892,
+ 0x6921, 0x3680,
+ 0x6924, 0x1895,
+ 0x6925, 0x3683,
+ 0x692d, 0x0e87,
+ 0x692e, 0x368b,
+ 0x6930, 0x1033,
+ 0x6931, 0x368d,
+ 0x6934, 0x18a6,
+ 0x6935, 0x3690,
+ 0x6939, 0x189d,
+ 0x693a, 0x3694,
+ 0x693d, 0x052d,
+ 0x693e, 0x3697,
+ 0x693f, 0x053e,
+ 0x6940, 0x3698,
+ 0x6942, 0x189f,
+ 0x6943, 0x369a,
+ 0x694a, 0x21fe,
+ 0x694b, 0x36a1,
+ 0x6953, 0x1efe,
+ 0x6954, 0x0f73,
+ 0x6955, 0x36a9,
+ 0x6957, 0x1899,
+ 0x6958, 0x36ab,
+ 0x695a, 0x0523,
+ 0x695b, 0x36ad,
+ 0x695d, 0x18a0,
+ 0x695e, 0x09ce,
+ 0x695f, 0x36af,
+ 0x6960, 0x189e,
+ 0x6961, 0x36b0,
+ 0x6963, 0x18ad,
+ 0x6964, 0x36b2,
+ 0x6966, 0x18ac,
+ 0x6967, 0x36b4,
+ 0x6968, 0x2475,
+ 0x6969, 0x36b5,
+ 0x696b, 0x18a2,
+ 0x696c, 0x36b7,
+ 0x696d, 0x220a,
+ 0x696e, 0x1890,
+ 0x696f, 0x36b8,
+ 0x6971, 0x189c,
+ 0x6972, 0x36ba,
+ 0x6975, 0x1f6f,
+ 0x6976, 0x36bd,
+ 0x6977, 0x0939,
+ 0x6978, 0x18a5,
+ 0x6979, 0x18ae,
+ 0x697a, 0x36be,
+ 0x697c, 0x0a4c,
+ 0x697d, 0x36c0,
+ 0x6980, 0x18a3,
+ 0x6981, 0x36c3,
+ 0x6982, 0x06c0,
+ 0x6983, 0x36c4,
+ 0x6984, 0x18a1,
+ 0x6985, 0x36c5,
+ 0x6986, 0x10c1,
+ 0x6987, 0x18a8,
+ 0x6989, 0x18ab,
+ 0x698a, 0x36c6,
+ 0x698d, 0x18bb,
+ 0x698e, 0x36c9,
+ 0x6994, 0x09b1,
+ 0x6995, 0x18b9,
+ 0x6996, 0x36cf,
+ 0x6998, 0x18a4,
+ 0x6999, 0x36d1,
+ 0x699b, 0x18af,
+ 0x699c, 0x03fc,
+ 0x699d, 0x36d3,
+ 0x69a7, 0x18b0,
+ 0x69a8, 0x1146,
+ 0x69a9, 0x36dd,
+ 0x69aa, 0x2468,
+ 0x69ab, 0x18b2,
+ 0x69ac, 0x36de,
+ 0x69ad, 0x18b3,
+ 0x69ae, 0x2100,
+ 0x69af, 0x36df,
+ 0x69b1, 0x18b5,
+ 0x69b2, 0x36e1,
+ 0x69b4, 0x0a3a,
+ 0x69b5, 0x36e3,
+ 0x69b7, 0x0c91,
+ 0x69b8, 0x36e5,
+ 0x69bb, 0x18b1,
+ 0x69bc, 0x36e8,
+ 0x69bf, 0x2476,
+ 0x69c0, 0x36eb,
+ 0x69c1, 0x18b6,
+ 0x69c2, 0x36ec,
+ 0x69ca, 0x18b7,
+ 0x69cb, 0x1f27,
+ 0x69cc, 0x18a7,
+ 0x69cd, 0x20d7,
+ 0x69ce, 0x18aa,
+ 0x69cf, 0x36f4,
+ 0x69d0, 0x07c6,
+ 0x69d1, 0x36f5,
+ 0x69d4, 0x18b4,
+ 0x69d5, 0x36f8,
+ 0x69db, 0x086a,
+ 0x69dc, 0x36fe,
+ 0x69df, 0x18b8,
+ 0x69e0, 0x18ba,
+ 0x69e1, 0x3701,
+ 0x69e7, 0x247c,
+ 0x69e8, 0x3707,
+ 0x69ed, 0x18be,
+ 0x69ee, 0x370c,
+ 0x69f2, 0x18c2,
+ 0x69f3, 0x1fa1,
+ 0x69f4, 0x3710,
+ 0x69fd, 0x04a2,
+ 0x69fe, 0x3719,
+ 0x69ff, 0x18bc,
+ 0x6a00, 0x371a,
+ 0x6a01, 0x22aa,
+ 0x6a02, 0x2005,
+ 0x6a03, 0x371b,
+ 0x6a05, 0x246c,
+ 0x6a06, 0x371d,
+ 0x6a0a, 0x064b,
+ 0x6a0b, 0x3721,
+ 0x6a13, 0x203e,
+ 0x6a14, 0x3729,
+ 0x6a17, 0x18bf,
+ 0x6a19, 0x1e4c,
+ 0x6a1a, 0x372c,
+ 0x6a1e, 0x213a,
+ 0x6a1f, 0x1162,
+ 0x6a20, 0x3730,
+ 0x6a21, 0x0b06,
+ 0x6a22, 0x3731,
+ 0x6a23, 0x2204,
+ 0x6a24, 0x3732,
+ 0x6a28, 0x18cc,
+ 0x6a29, 0x3736,
+ 0x6a2a, 0x0798,
+ 0x6a2b, 0x3737,
+ 0x6a2f, 0x18bd,
+ 0x6a30, 0x373b,
+ 0x6a31, 0x1088,
+ 0x6a32, 0x373c,
+ 0x6a35, 0x18c8,
+ 0x6a36, 0x373f,
+ 0x6a38, 0x20c3,
+ 0x6a39, 0x2140,
+ 0x6a3a, 0x2477,
+ 0x6a3b, 0x3741,
+ 0x6a3d, 0x18cb,
+ 0x6a3e, 0x18c4,
+ 0x6a3f, 0x3743,
+ 0x6a44, 0x18c3,
+ 0x6a45, 0x3748,
+ 0x6a47, 0x0c3e,
+ 0x6a48, 0x2474,
+ 0x6a49, 0x374a,
+ 0x6a4b, 0x20dd,
+ 0x6a4c, 0x374c,
+ 0x6a50, 0x18c6,
+ 0x6a51, 0x3750,
+ 0x6a58, 0x18cd,
+ 0x6a59, 0x04ed,
+ 0x6a5a, 0x3757,
+ 0x6a5b, 0x18c7,
+ 0x6a5c, 0x3758,
+ 0x6a5f, 0x1f68,
+ 0x6a60, 0x375b,
+ 0x6a61, 0x0f5d,
+ 0x6a62, 0x2185,
+ 0x6a63, 0x375c,
+ 0x6a65, 0x18c1,
+ 0x6a66, 0x375e,
+ 0x6a71, 0x051c,
+ 0x6a72, 0x3769,
+ 0x6a79, 0x18ca,
+ 0x6a7a, 0x3770,
+ 0x6a7c, 0x18ce,
+ 0x6a7d, 0x3772,
+ 0x6a80, 0x0e07,
+ 0x6a81, 0x3775,
+ 0x6a84, 0x0f1a,
+ 0x6a85, 0x3778,
+ 0x6a89, 0x2472,
+ 0x6a8a, 0x377c,
+ 0x6a8e, 0x18c9,
+ 0x6a8f, 0x3780,
+ 0x6a90, 0x18d0,
+ 0x6a91, 0x18cf,
+ 0x6a92, 0x3781,
+ 0x6a94, 0x1eb5,
+ 0x6a95, 0x3783,
+ 0x6a97, 0x18d2,
+ 0x6a98, 0x3785,
+ 0x6a9c, 0x2478,
+ 0x6a9d, 0x3789,
+ 0x6aa0, 0x18c5,
+ 0x6aa1, 0x378c,
+ 0x6aa2, 0x1f8b,
+ 0x6aa3, 0x2484,
+ 0x6aa4, 0x378d,
+ 0x6aa9, 0x18d1,
+ 0x6aaa, 0x3792,
+ 0x6aab, 0x18d3,
+ 0x6aac, 0x0acf,
+ 0x6aad, 0x3793,
+ 0x6aaf, 0x2699,
+ 0x6ab0, 0x3795,
+ 0x6ab3, 0x2482,
+ 0x6ab4, 0x3798,
+ 0x6ab8, 0x20a1,
+ 0x6ab9, 0x379c,
+ 0x6abb, 0x1f92,
+ 0x6abc, 0x379e,
+ 0x6ac3, 0x1f38,
+ 0x6ac4, 0x37a5,
+ 0x6ad3, 0x2485,
+ 0x6ad4, 0x37b4,
+ 0x6ada, 0x2480,
+ 0x6adb, 0x246e,
+ 0x6adc, 0x37ba,
+ 0x6add, 0x247b,
+ 0x6ade, 0x2486,
+ 0x6adf, 0x2471,
+ 0x6ae0, 0x37bb,
+ 0x6ae7, 0x2483,
+ 0x6ae8, 0x2470,
+ 0x6ae9, 0x37c2,
+ 0x6aea, 0x2469,
+ 0x6aeb, 0x37c3,
+ 0x6aec, 0x247f,
+ 0x6aed, 0x37c4,
+ 0x6af3, 0x246f,
+ 0x6af4, 0x37ca,
+ 0x6af8, 0x2481,
+ 0x6af9, 0x37ce,
+ 0x6afb, 0x2220,
+ 0x6afc, 0x37d0,
+ 0x6b00, 0x37d4,
+ 0x6b04, 0x1ff5,
+ 0x6b05, 0x37d8,
+ 0x6b0a, 0x20f4,
+ 0x6b0b, 0x37dd,
+ 0x6b0f, 0x247d,
+ 0x6b10, 0x37e1,
+ 0x6b12, 0x2479,
+ 0x6b13, 0x37e3,
+ 0x6b16, 0x247e,
+ 0x6b17, 0x37e6,
+ 0x6b1e, 0x247a,
+ 0x6b1f, 0x37ed,
+ 0x6b20, 0x0c34,
+ 0x6b21, 0x0551,
+ 0x6b22, 0x07cb,
+ 0x6b23, 0x0f8b,
+ 0x6b24, 0x19b1,
+ 0x6b25, 0x37ee,
+ 0x6b27, 0x0b78,
+ 0x6b28, 0x37f0,
+ 0x6b32, 0x10e0,
+ 0x6b33, 0x37fa,
+ 0x6b37, 0x19b2,
+ 0x6b38, 0x37fe,
+ 0x6b39, 0x19b3,
+ 0x6b3a, 0x0bfa,
+ 0x6b3b, 0x37ff,
+ 0x6b3d, 0x20e3,
+ 0x6b3e, 0x097b,
+ 0x6b3f, 0x3801,
+ 0x6b43, 0x19b4,
+ 0x6b44, 0x3805,
+ 0x6b46, 0x19b5,
+ 0x6b47, 0x0f75,
+ 0x6b48, 0x3807,
+ 0x6b49, 0x0c35,
+ 0x6b4a, 0x3808,
+ 0x6b4c, 0x06e3,
+ 0x6b4d, 0x380a,
+ 0x6b50, 0x20ad,
+ 0x6b51, 0x380d,
+ 0x6b59, 0x19b6,
+ 0x6b5a, 0x3815,
+ 0x6b5f, 0x24cb,
+ 0x6b60, 0x381a,
+ 0x6b61, 0x1f53,
+ 0x6b62, 0x11b8,
+ 0x6b63, 0x119e,
+ 0x6b64, 0x054e,
+ 0x6b65, 0x0484,
+ 0x6b66, 0x0ef3,
+ 0x6b67, 0x0c06,
+ 0x6b68, 0x381b,
+ 0x6b6a, 0x0e92,
+ 0x6b6b, 0x381d,
+ 0x6b72, 0x2159,
+ 0x6b73, 0x3824,
+ 0x6b77, 0x2013,
+ 0x6b78, 0x1f33,
+ 0x6b79, 0x0578,
+ 0x6b7a, 0x3828,
+ 0x6b7b, 0x0db5,
+ 0x6b7c, 0x0852,
+ 0x6b7d, 0x3829,
+ 0x6b81, 0x18d6,
+ 0x6b83, 0x1013,
+ 0x6b84, 0x18d9,
+ 0x6b85, 0x382d,
+ 0x6b86, 0x057c,
+ 0x6b87, 0x18d8,
+ 0x6b88, 0x382e,
+ 0x6b89, 0x0fdc,
+ 0x6b8a, 0x0d79,
+ 0x6b8b, 0x0497,
+ 0x6b8c, 0x382f,
+ 0x6b8d, 0x18dc,
+ 0x6b8e, 0x3830,
+ 0x6b92, 0x18da,
+ 0x6b94, 0x3834,
+ 0x6b96, 0x11b2,
+ 0x6b97, 0x3836,
+ 0x6b98, 0x1e5c,
+ 0x6b99, 0x3837,
+ 0x6b9a, 0x18dd,
+ 0x6b9c, 0x3838,
+ 0x6b9e, 0x2488,
+ 0x6b9f, 0x383a,
+ 0x6ba1, 0x18df,
+ 0x6ba2, 0x383c,
+ 0x6ba4, 0x2487,
+ 0x6ba5, 0x383e,
+ 0x6baa, 0x18e0,
+ 0x6bab, 0x248a,
+ 0x6bac, 0x3843,
+ 0x6bae, 0x2489,
+ 0x6baf, 0x248b,
+ 0x6bb0, 0x3845,
+ 0x6bb2, 0x1f83,
+ 0x6bb3, 0x19bd,
+ 0x6bb4, 0x0b7a,
+ 0x6bb5, 0x060d,
+ 0x6bb6, 0x3847,
+ 0x6bb7, 0x107a,
+ 0x6bb8, 0x3848,
+ 0x6bba, 0x210f,
+ 0x6bbb, 0x1fdb,
+ 0x6bbc, 0x384a,
+ 0x6bbf, 0x05cf,
+ 0x6bc0, 0x384d,
+ 0x6bc1, 0x07ee,
+ 0x6bc2, 0x19bf,
+ 0x6bc3, 0x384e,
+ 0x6bc5, 0x106a,
+ 0x6bc6, 0x20af,
+ 0x6bc7, 0x3850,
+ 0x6bcb, 0x0ef2,
+ 0x6bcc, 0x3854,
+ 0x6bcd, 0x0b1b,
+ 0x6bce, 0x3855,
+ 0x6bcf, 0x0ac4,
+ 0x6bd0, 0x3856,
+ 0x6bd2, 0x05fd,
+ 0x6bd3, 0x126f,
+ 0x6bd4, 0x0431,
+ 0x6bd5, 0x0438,
+ 0x6bd6, 0x043a,
+ 0x6bd7, 0x0bbf,
+ 0x6bd8, 0x3858,
+ 0x6bd9, 0x0439,
+ 0x6bda, 0x3859,
+ 0x6bdb, 0x0ab0,
+ 0x6bdc, 0x385a,
+ 0x6be1, 0x1152,
+ 0x6be2, 0x385f,
+ 0x6bea, 0x1954,
+ 0x6beb, 0x0778,
+ 0x6bec, 0x3867,
+ 0x6bef, 0x0e0d,
+ 0x6bf0, 0x386a,
+ 0x6bf3, 0x1955,
+ 0x6bf4, 0x386d,
+ 0x6bf5, 0x1957,
+ 0x6bf6, 0x386e,
+ 0x6bf9, 0x1958,
+ 0x6bfa, 0x3871,
+ 0x6bfd, 0x1956,
+ 0x6bfe, 0x3874,
+ 0x6bff, 0x24c0,
+ 0x6c00, 0x3875,
+ 0x6c05, 0x1959,
+ 0x6c06, 0x195b,
+ 0x6c07, 0x195a,
+ 0x6c08, 0x226d,
+ 0x6c09, 0x387a,
+ 0x6c0c, 0x24c1,
+ 0x6c0d, 0x195c,
+ 0x6c0e, 0x387d,
+ 0x6c0f, 0x0d66,
+ 0x6c10, 0x126b,
+ 0x6c11, 0x0af6,
+ 0x6c12, 0x387e,
+ 0x6c13, 0x0aaa,
+ 0x6c14, 0x0c17,
+ 0x6c15, 0x195d,
+ 0x6c16, 0x0b2d,
+ 0x6c17, 0x387f,
+ 0x6c18, 0x195e,
+ 0x6c1b, 0x0672,
+ 0x6c1c, 0x3880,
+ 0x6c1f, 0x0697,
+ 0x6c20, 0x3883,
+ 0x6c21, 0x1961,
+ 0x6c22, 0x0c5f,
+ 0x6c23, 0x20ca,
+ 0x6c24, 0x1963,
+ 0x6c25, 0x3884,
+ 0x6c26, 0x075b,
+ 0x6c27, 0x101e,
+ 0x6c28, 0x03bc,
+ 0x6c29, 0x1962,
+ 0x6c2a, 0x1964,
+ 0x6c2b, 0x20e7,
+ 0x6c2c, 0x24c2,
+ 0x6c2d, 0x3885,
+ 0x6c2e, 0x058b,
+ 0x6c2f, 0x0a6f,
+ 0x6c30, 0x0c65,
+ 0x6c31, 0x3886,
+ 0x6c32, 0x1965,
+ 0x6c33, 0x3887,
+ 0x6c34, 0x0da3,
+ 0x6c35, 0x169f,
+ 0x6c36, 0x3888,
+ 0x6c38, 0x10a5,
+ 0x6c39, 0x388a,
+ 0x6c3d, 0x12ef,
+ 0x6c3e, 0x388e,
+ 0x6c40, 0x0e52,
+ 0x6c41, 0x11ac,
+ 0x6c42, 0x0c70,
+ 0x6c43, 0x3890,
+ 0x6c46, 0x12f4,
+ 0x6c47, 0x07f8,
+ 0x6c48, 0x3893,
+ 0x6c49, 0x0771,
+ 0x6c4a, 0x16a2,
+ 0x6c4b, 0x3894,
+ 0x6c50, 0x0f18,
+ 0x6c51, 0x3899,
+ 0x6c54, 0x16a0,
+ 0x6c55, 0x0d00,
+ 0x6c56, 0x389c,
+ 0x6c57, 0x0770,
+ 0x6c58, 0x389d,
+ 0x6c5b, 0x0fdd,
+ 0x6c5c, 0x16a1,
+ 0x6c5d, 0x0cc5,
+ 0x6c5e, 0x0708,
+ 0x6c5f, 0x087e,
+ 0x6c60, 0x04fd,
+ 0x6c61, 0x0eea,
+ 0x6c62, 0x38a0,
+ 0x6c64, 0x0e13,
+ 0x6c65, 0x38a2,
+ 0x6c68, 0x16a8,
+ 0x6c6a, 0x0ea5,
+ 0x6c6b, 0x38a5,
+ 0x6c70, 0x0e00,
+ 0x6c71, 0x38aa,
+ 0x6c72, 0x0826,
+ 0x6c73, 0x38ab,
+ 0x6c74, 0x16aa,
+ 0x6c75, 0x38ac,
+ 0x6c76, 0x16ab,
+ 0x6c77, 0x38ad,
+ 0x6c79, 0x0fa5,
+ 0x6c7a, 0x38af,
+ 0x6c7d, 0x0c1a,
+ 0x6c7e, 0x0677,
+ 0x6c7f, 0x38b2,
+ 0x6c81, 0x0c5c,
+ 0x6c82, 0x1051,
+ 0x6c83, 0x0ee5,
+ 0x6c84, 0x38b4,
+ 0x6c85, 0x16a4,
+ 0x6c86, 0x16ac,
+ 0x6c87, 0x38b5,
+ 0x6c88, 0x0d2b,
+ 0x6c89, 0x04e6,
+ 0x6c8a, 0x38b6,
+ 0x6c8c, 0x16a7,
+ 0x6c8d, 0x38b8,
+ 0x6c8f, 0x0c02,
+ 0x6c90, 0x16a5,
+ 0x6c91, 0x38ba,
+ 0x6c93, 0x1a1f,
+ 0x6c94, 0x16a6,
+ 0x6c95, 0x38bc,
+ 0x6c99, 0x0cec,
+ 0x6c9a, 0x38c0,
+ 0x6c9b, 0x0ba7,
+ 0x6c9c, 0x38c1,
+ 0x6c9f, 0x070e,
+ 0x6ca0, 0x38c4,
+ 0x6ca1, 0x0ac0,
+ 0x6ca2, 0x38c5,
+ 0x6ca3, 0x16a3,
+ 0x6ca4, 0x0b7e,
+ 0x6ca5, 0x09ed,
+ 0x6ca6, 0x0a80,
+ 0x6ca7, 0x049e,
+ 0x6ca8, 0x38c6,
+ 0x6ca9, 0x16ad,
+ 0x6caa, 0x07bb,
+ 0x6cab, 0x0b10,
+ 0x6cac, 0x38c7,
+ 0x6cad, 0x16b0,
+ 0x6cae, 0x0909,
+ 0x6caf, 0x38c8,
+ 0x6cb1, 0x16bb,
+ 0x6cb2, 0x16b5,
+ 0x6cb3, 0x078a,
+ 0x6cb4, 0x38ca,
+ 0x6cb8, 0x066d,
+ 0x6cb9, 0x10b2,
+ 0x6cba, 0x38ce,
+ 0x6cbb, 0x11cd,
+ 0x6cbc, 0x1174,
+ 0x6cbd, 0x071a,
+ 0x6cbe, 0x1155,
+ 0x6cbf, 0x1001,
+ 0x6cc0, 0x38cf,
+ 0x6cc4, 0x0f84,
+ 0x6cc5, 0x0c73,
+ 0x6cc6, 0x38d3,
+ 0x6cc9, 0x0c85,
+ 0x6cca, 0x047b,
+ 0x6ccb, 0x38d6,
+ 0x6ccc, 0x0adf,
+ 0x6ccd, 0x38d7,
+ 0x6cd0, 0x16ae,
+ 0x6cd1, 0x38da,
+ 0x6cd3, 0x16bc,
+ 0x6cd4, 0x16af,
+ 0x6cd5, 0x0645,
+ 0x6cd6, 0x16b7,
+ 0x6cd7, 0x16b4,
+ 0x6cd8, 0x38dc,
+ 0x6cdb, 0x0657,
+ 0x6cdc, 0x38df,
+ 0x6cde, 0x0b63,
+ 0x6cdf, 0x38e1,
+ 0x6ce0, 0x16b6,
+ 0x6ce1, 0x0b9e,
+ 0x6ce2, 0x046f,
+ 0x6ce3, 0x0c1b,
+ 0x6ce4, 0x38e2,
+ 0x6ce5, 0x0b43,
+ 0x6ce6, 0x38e3,
+ 0x6ce8, 0x11ff,
+ 0x6ce9, 0x38e5,
+ 0x6cea, 0x09cc,
+ 0x6ceb, 0x16b9,
+ 0x6cec, 0x38e6,
+ 0x6cee, 0x16ba,
+ 0x6cef, 0x16bd,
+ 0x6cf0, 0x0dfc,
+ 0x6cf1, 0x16b3,
+ 0x6cf2, 0x38e8,
+ 0x6cf3, 0x10a3,
+ 0x6cf4, 0x38e9,
+ 0x6cf5, 0x042c,
+ 0x6cf6, 0x1a20,
+ 0x6cf7, 0x16b1,
+ 0x6cf9, 0x38ea,
+ 0x6cfa, 0x16b8,
+ 0x6cfb, 0x0f85,
+ 0x6cfc, 0x0be2,
+ 0x6cfd, 0x1136,
+ 0x6cfe, 0x16be,
+ 0x6cff, 0x38eb,
+ 0x6d00, 0x38ec,
+ 0x6d01, 0x08b1,
+ 0x6d02, 0x38ed,
+ 0x6d04, 0x16c5,
+ 0x6d05, 0x38ef,
+ 0x6d07, 0x16c4,
+ 0x6d08, 0x38f1,
+ 0x6d0b, 0x101c,
+ 0x6d0c, 0x16c1,
+ 0x6d0d, 0x38f4,
+ 0x6d0e, 0x16c7,
+ 0x6d0f, 0x38f5,
+ 0x6d12, 0x0cd2,
+ 0x6d13, 0x38f8,
+ 0x6d17, 0x0f21,
+ 0x6d18, 0x38fc,
+ 0x6d19, 0x16c6,
+ 0x6d1a, 0x16cc,
+ 0x6d1b, 0x0a8c,
+ 0x6d1c, 0x38fd,
+ 0x6d1e, 0x05f3,
+ 0x6d1f, 0x38ff,
+ 0x6d25, 0x08c3,
+ 0x6d26, 0x3905,
+ 0x6d27, 0x16c0,
+ 0x6d28, 0x3906,
+ 0x6d2a, 0x07a0,
+ 0x6d2b, 0x16c8,
+ 0x6d2c, 0x3908,
+ 0x6d2e, 0x16ca,
+ 0x6d2f, 0x390a,
+ 0x6d31, 0x063c,
+ 0x6d32, 0x11dd,
+ 0x6d33, 0x16d0,
+ 0x6d34, 0x390c,
+ 0x6d35, 0x16cb,
+ 0x6d36, 0x390d,
+ 0x6d39, 0x16bf,
+ 0x6d3a, 0x3910,
+ 0x6d3b, 0x0803,
+ 0x6d3c, 0x0e8e,
+ 0x6d3d, 0x0c1f,
+ 0x6d3e, 0x0b8a,
+ 0x6d3f, 0x3911,
+ 0x6d41, 0x0a40,
+ 0x6d42, 0x3913,
+ 0x6d43, 0x16c2,
+ 0x6d44, 0x3914,
+ 0x6d45, 0x0c30,
+ 0x6d46, 0x087d,
+ 0x6d47, 0x088e,
+ 0x6d48, 0x16c3,
+ 0x6d49, 0x3915,
+ 0x6d4a, 0x1224,
+ 0x6d4b, 0x04a9,
+ 0x6d4c, 0x3916,
+ 0x6d4d, 0x16c9,
+ 0x6d4e, 0x0836,
+ 0x6d4f, 0x16cd,
+ 0x6d50, 0x3917,
+ 0x6d51, 0x0800,
+ 0x6d52, 0x16ce,
+ 0x6d53, 0x0b69,
+ 0x6d54, 0x16cf,
+ 0x6d55, 0x3918,
+ 0x6d59, 0x1184,
+ 0x6d5a, 0x0930,
+ 0x6d5b, 0x391c,
+ 0x6d5c, 0x16d8,
+ 0x6d5d, 0x391d,
+ 0x6d5e, 0x16d5,
+ 0x6d5f, 0x391e,
+ 0x6d60, 0x16d9,
+ 0x6d61, 0x391f,
+ 0x6d63, 0x16db,
+ 0x6d64, 0x3921,
+ 0x6d66, 0x0bf5,
+ 0x6d67, 0x3923,
+ 0x6d69, 0x077d,
+ 0x6d6a, 0x09b6,
+ 0x6d6b, 0x3925,
+ 0x6d6e, 0x069c,
+ 0x6d6f, 0x16d2,
+ 0x6d70, 0x3928,
+ 0x6d74, 0x10e4,
+ 0x6d75, 0x392c,
+ 0x6d77, 0x075a,
+ 0x6d78, 0x08cf,
+ 0x6d79, 0x23dc,
+ 0x6d7a, 0x392e,
+ 0x6d7c, 0x16da,
+ 0x6d7d, 0x3930,
+ 0x6d82, 0x0e70,
+ 0x6d83, 0x3935,
+ 0x6d85, 0x0b5c,
+ 0x6d86, 0x3937,
+ 0x6d87, 0x23db,
+ 0x6d88, 0x0f68,
+ 0x6d89, 0x0d1f,
+ 0x6d8a, 0x3938,
+ 0x6d8c, 0x10a4,
+ 0x6d8d, 0x393a,
+ 0x6d8e, 0x0f3e,
+ 0x6d8f, 0x393b,
+ 0x6d91, 0x16d1,
+ 0x6d92, 0x393d,
+ 0x6d93, 0x16d6,
+ 0x6d95, 0x0e3c,
+ 0x6d96, 0x393e,
+ 0x6d9b, 0x0e21,
+ 0x6d9c, 0x3943,
+ 0x6d9d, 0x09bf,
+ 0x6d9e, 0x16d3,
+ 0x6d9f, 0x09f9,
+ 0x6da0, 0x16d4,
+ 0x6da1, 0x0edf,
+ 0x6da2, 0x3944,
+ 0x6da3, 0x07d6,
+ 0x6da4, 0x05b4,
+ 0x6da5, 0x3945,
+ 0x6da6, 0x0cce,
+ 0x6da7, 0x0878,
+ 0x6da8, 0x1168,
+ 0x6da9, 0x0ce5,
+ 0x6daa, 0x069d,
+ 0x6dab, 0x16e8,
+ 0x6dac, 0x3946,
+ 0x6dae, 0x16ea,
+ 0x6daf, 0x0fed,
+ 0x6db0, 0x3948,
+ 0x6db2, 0x1041,
+ 0x6db3, 0x394a,
+ 0x6db5, 0x0764,
+ 0x6db6, 0x394c,
+ 0x6db8, 0x078b,
+ 0x6db9, 0x394e,
+ 0x6dbf, 0x16e1,
+ 0x6dc0, 0x05ce,
+ 0x6dc1, 0x3954,
+ 0x6dc4, 0x122a,
+ 0x6dc5, 0x16de,
+ 0x6dc6, 0x0f6a,
+ 0x6dc7, 0x16dd,
+ 0x6dc8, 0x3957,
+ 0x6dcb, 0x0a25,
+ 0x6dcc, 0x0e1d,
+ 0x6dcd, 0x395a,
+ 0x6dd1, 0x0d7e,
+ 0x6dd2, 0x395e,
+ 0x6dd6, 0x0b3a,
+ 0x6dd7, 0x3962,
+ 0x6dd8, 0x0e27,
+ 0x6dd9, 0x16e6,
+ 0x6dda, 0x3963,
+ 0x6ddd, 0x16e5,
+ 0x6dde, 0x16df,
+ 0x6ddf, 0x3966,
+ 0x6de0, 0x16e2,
+ 0x6de1, 0x058e,
+ 0x6de2, 0x3967,
+ 0x6de4, 0x10be,
+ 0x6de5, 0x3969,
+ 0x6de6, 0x16e4,
+ 0x6de7, 0x396a,
+ 0x6dea, 0x205e,
+ 0x6deb, 0x1080,
+ 0x6dec, 0x0566,
+ 0x6ded, 0x396d,
+ 0x6dee, 0x07c9,
+ 0x6def, 0x396e,
+ 0x6df1, 0x0d27,
+ 0x6df2, 0x3970,
+ 0x6df3, 0x0541,
+ 0x6df4, 0x3971,
+ 0x6df5, 0x2244,
+ 0x6df6, 0x23e2,
+ 0x6df7, 0x0801,
+ 0x6df8, 0x3972,
+ 0x6df9, 0x0ff6,
+ 0x6dfa, 0x20d4,
+ 0x6dfb, 0x0e40,
+ 0x6dfc, 0x1a21,
+ 0x6dfd, 0x3973,
+ 0x6e00, 0x3976,
+ 0x6e05, 0x0c62,
+ 0x6e06, 0x397b,
+ 0x6e0a, 0x10eb,
+ 0x6e0b, 0x397f,
+ 0x6e0c, 0x16e9,
+ 0x6e0d, 0x1232,
+ 0x6e0e, 0x16e0,
+ 0x6e0f, 0x3980,
+ 0x6e10, 0x0876,
+ 0x6e11, 0x16e3,
+ 0x6e12, 0x3981,
+ 0x6e14, 0x10cb,
+ 0x6e15, 0x3983,
+ 0x6e16, 0x16e7,
+ 0x6e17, 0x0d31,
+ 0x6e18, 0x3984,
+ 0x6e1a, 0x16dc,
+ 0x6e1b, 0x3986,
+ 0x6e1d, 0x10ca,
+ 0x6e1e, 0x3988,
+ 0x6e20, 0x0c7b,
+ 0x6e21, 0x0608,
+ 0x6e22, 0x398a,
+ 0x6e23, 0x113f,
+ 0x6e24, 0x047a,
+ 0x6e25, 0x16f5,
+ 0x6e26, 0x219f,
+ 0x6e27, 0x398b,
+ 0x6e29, 0x0ed1,
+ 0x6e2a, 0x398d,
+ 0x6e2b, 0x16eb,
+ 0x6e2c, 0x1e66,
+ 0x6e2d, 0x0ecb,
+ 0x6e2e, 0x398e,
+ 0x6e2f, 0x06d6,
+ 0x6e30, 0x398f,
+ 0x6e32, 0x16f4,
+ 0x6e33, 0x3991,
+ 0x6e34, 0x0957,
+ 0x6e35, 0x3992,
+ 0x6e38, 0x10b3,
+ 0x6e39, 0x3995,
+ 0x6e3a, 0x0af1,
+ 0x6e3b, 0x3996,
+ 0x6e3e, 0x1f63,
+ 0x6e3f, 0x3999,
+ 0x6e43, 0x0b89,
+ 0x6e44, 0x16f6,
+ 0x6e45, 0x399d,
+ 0x6e4d, 0x0e75,
+ 0x6e4e, 0x16ed,
+ 0x6e4f, 0x39a5,
+ 0x6e53, 0x16f2,
+ 0x6e55, 0x39a9,
+ 0x6e56, 0x07b5,
+ 0x6e57, 0x39aa,
+ 0x6e58, 0x0f53,
+ 0x6e59, 0x39ab,
+ 0x6e5b, 0x1160,
+ 0x6e5c, 0x39ad,
+ 0x6e5e, 0x23dd,
+ 0x6e5f, 0x16f0,
+ 0x6e60, 0x39af,
+ 0x6e6b, 0x16ee,
+ 0x6e6c, 0x39ba,
+ 0x6e6e, 0x16ec,
+ 0x6e6f, 0x216b,
+ 0x6e70, 0x39bc,
+ 0x6e7e, 0x0e96,
+ 0x6e7f, 0x0d41,
+ 0x6e80, 0x39ca,
+ 0x6e83, 0x098e,
+ 0x6e84, 0x39cd,
+ 0x6e85, 0x0877,
+ 0x6e86, 0x16f1,
+ 0x6e87, 0x39ce,
+ 0x6e89, 0x06c3,
+ 0x6e8a, 0x39d0,
+ 0x6e8f, 0x1705,
+ 0x6e90, 0x10f7,
+ 0x6e91, 0x39d5,
+ 0x6e96, 0x22b5,
+ 0x6e97, 0x39da,
+ 0x6e98, 0x16f9,
+ 0x6e99, 0x39db,
+ 0x6e9c, 0x0a38,
+ 0x6e9d, 0x1f26,
+ 0x6e9e, 0x39de,
+ 0x6e9f, 0x1707,
+ 0x6ea0, 0x39df,
+ 0x6ea2, 0x106e,
+ 0x6ea3, 0x39e1,
+ 0x6ea5, 0x16fd,
+ 0x6ea6, 0x39e3,
+ 0x6ea7, 0x16fe,
+ 0x6ea8, 0x39e4,
+ 0x6eaa, 0x0f17,
+ 0x6eab, 0x39e6,
+ 0x6eaf, 0x0dd2,
+ 0x6eb0, 0x39ea,
+ 0x6eb1, 0x16f8,
+ 0x6eb2, 0x16ef,
+ 0x6eb3, 0x39eb,
+ 0x6eb4, 0x1703,
+ 0x6eb5, 0x39ec,
+ 0x6eb6, 0x0cb7,
+ 0x6eb7, 0x1701,
+ 0x6eb8, 0x39ed,
+ 0x6eba, 0x0b4a,
+ 0x6ebb, 0x1700,
+ 0x6ebc, 0x39ef,
+ 0x6ebd, 0x16ff,
+ 0x6ebe, 0x39f0,
+ 0x6ec1, 0x0521,
+ 0x6ec2, 0x1706,
+ 0x6ec3, 0x39f3,
+ 0x6ec4, 0x1e63,
+ 0x6ec5, 0x2088,
+ 0x6ec6, 0x39f4,
+ 0x6ec7, 0x05c2,
+ 0x6ec8, 0x39f5,
+ 0x6ecb, 0x1229,
+ 0x6ecc, 0x1ebd,
+ 0x6ecd, 0x39f8,
+ 0x6ece, 0x2341,
+ 0x6ecf, 0x1704,
+ 0x6ed0, 0x39f9,
+ 0x6ed1, 0x07c1,
+ 0x6ed2, 0x39fa,
+ 0x6ed3, 0x122f,
+ 0x6ed4, 0x0e22,
+ 0x6ed5, 0x19a8,
+ 0x6ed6, 0x39fb,
+ 0x6ed7, 0x1702,
+ 0x6ed8, 0x39fc,
+ 0x6eda, 0x074f,
+ 0x6edb, 0x39fe,
+ 0x6ede, 0x11cc,
+ 0x6edf, 0x16f7,
+ 0x6ee0, 0x16fa,
+ 0x6ee1, 0x0aa1,
+ 0x6ee2, 0x16fc,
+ 0x6ee3, 0x3a01,
+ 0x6ee4, 0x0a72,
+ 0x6ee5, 0x09af,
+ 0x6ee6, 0x0a77,
+ 0x6ee7, 0x3a02,
+ 0x6ee8, 0x045e,
+ 0x6ee9, 0x0e05,
+ 0x6eea, 0x3a03,
+ 0x6eec, 0x1f4b,
+ 0x6eed, 0x3a05,
+ 0x6eef, 0x2292,
+ 0x6ef0, 0x3a07,
+ 0x6ef2, 0x2124,
+ 0x6ef3, 0x3a09,
+ 0x6ef4, 0x05af,
+ 0x6ef5, 0x3a0a,
+ 0x6ef7, 0x2048,
+ 0x6ef8, 0x23e0,
+ 0x6ef9, 0x170d,
+ 0x6efa, 0x3a0c,
+ 0x6eff, 0x2077,
+ 0x6f00, 0x3a11,
+ 0x6f01, 0x223a,
+ 0x6f02, 0x0bce,
+ 0x6f03, 0x3a12,
+ 0x6f06, 0x0c00,
+ 0x6f07, 0x3a15,
+ 0x6f09, 0x1713,
+ 0x6f0a, 0x3a17,
+ 0x6f0f, 0x0a50,
+ 0x6f10, 0x3a1c,
+ 0x6f13, 0x09d7,
+ 0x6f14, 0x1006,
+ 0x6f15, 0x170c,
+ 0x6f16, 0x3a1f,
+ 0x6f1a, 0x20b1,
+ 0x6f1b, 0x3a23,
+ 0x6f20, 0x0b11,
+ 0x6f21, 0x3a28,
+ 0x6f22, 0x1f41,
+ 0x6f23, 0x201c,
+ 0x6f24, 0x170b,
+ 0x6f25, 0x3a29,
+ 0x6f29, 0x1714,
+ 0x6f2a, 0x1712,
+ 0x6f2b, 0x0aa5,
+ 0x6f2c, 0x22b8,
+ 0x6f2d, 0x16fb,
+ 0x6f2e, 0x3a2d,
+ 0x6f2f, 0x170e,
+ 0x6f30, 0x3a2e,
+ 0x6f31, 0x0d95,
+ 0x6f32, 0x2276,
+ 0x6f33, 0x1165,
+ 0x6f34, 0x3a2f,
+ 0x6f36, 0x170f,
+ 0x6f37, 0x3a31,
+ 0x6f38, 0x1f9b,
+ 0x6f39, 0x3a32,
+ 0x6f3e, 0x1023,
+ 0x6f3f, 0x1f9f,
+ 0x6f40, 0x3a37,
+ 0x6f41, 0x25ca,
+ 0x6f42, 0x3a38,
+ 0x6f46, 0x1709,
+ 0x6f48, 0x3a3c,
+ 0x6f4b, 0x1710,
+ 0x6f4c, 0x3a3f,
+ 0x6f4d, 0x0eba,
+ 0x6f4e, 0x3a40,
+ 0x6f51, 0x20be,
+ 0x6f52, 0x3a43,
+ 0x6f54, 0x1fb4,
+ 0x6f55, 0x3a45,
+ 0x6f58, 0x0b8c,
+ 0x6f59, 0x23d7,
+ 0x6f5a, 0x3a48,
+ 0x6f5c, 0x0c2e,
+ 0x6f5d, 0x3a4a,
+ 0x6f5e, 0x0a61,
+ 0x6f5f, 0x3a4b,
+ 0x6f62, 0x1708,
+ 0x6f63, 0x3a4e,
+ 0x6f64, 0x2105,
+ 0x6f65, 0x3a4f,
+ 0x6f66, 0x0a13,
+ 0x6f67, 0x3a50,
+ 0x6f6d, 0x0e09,
+ 0x6f6e, 0x04d6,
+ 0x6f6f, 0x23e1,
+ 0x6f70, 0x1fec,
+ 0x6f71, 0x3a56,
+ 0x6f72, 0x1719,
+ 0x6f73, 0x3a57,
+ 0x6f74, 0x1711,
+ 0x6f75, 0x3a58,
+ 0x6f77, 0x23ea,
+ 0x6f78, 0x1718,
+ 0x6f79, 0x3a5a,
+ 0x6f7a, 0x171b,
+ 0x6f7b, 0x3a5b,
+ 0x6f7c, 0x171a,
+ 0x6f7d, 0x3a5c,
+ 0x6f7f, 0x23e3,
+ 0x6f80, 0x210e,
+ 0x6f81, 0x3a5e,
+ 0x6f84, 0x04f3,
+ 0x6f85, 0x3a61,
+ 0x6f86, 0x1fa6,
+ 0x6f87, 0x2004,
+ 0x6f88, 0x04df,
+ 0x6f89, 0x1715,
+ 0x6f8a, 0x3a62,
+ 0x6f8c, 0x1717,
+ 0x6f8d, 0x1716,
+ 0x6f8e, 0x0bad,
+ 0x6f8f, 0x3a64,
+ 0x6f97, 0x1f9d,
+ 0x6f98, 0x3a6c,
+ 0x6f9c, 0x09a8,
+ 0x6f9d, 0x3a70,
+ 0x6fa0, 0x23e5,
+ 0x6fa1, 0x112b,
+ 0x6fa2, 0x3a73,
+ 0x6fa4, 0x2264,
+ 0x6fa5, 0x3a75,
+ 0x6fa7, 0x171e,
+ 0x6fa8, 0x3a77,
+ 0x6fa9, 0x24e2,
+ 0x6faa, 0x3a78,
+ 0x6fae, 0x23de,
+ 0x6faf, 0x3a7c,
+ 0x6fb1, 0x1ec4,
+ 0x6fb2, 0x3a7e,
+ 0x6fb3, 0x03cf,
+ 0x6fb4, 0x3a7f,
+ 0x6fb6, 0x1720,
+ 0x6fb7, 0x3a81,
+ 0x6fb9, 0x171f,
+ 0x6fba, 0x3a83,
+ 0x6fc0, 0x0817,
+ 0x6fc1, 0x22b6,
+ 0x6fc2, 0x1721,
+ 0x6fc3, 0x20a9,
+ 0x6fc4, 0x3a89,
+ 0x6fc9, 0x171d,
+ 0x6fca, 0x3a8e,
+ 0x6fd1, 0x171c,
+ 0x6fd2, 0x045d,
+ 0x6fd3, 0x3a95,
+ 0x6fd5, 0x212b,
+ 0x6fd6, 0x3a97,
+ 0x6fd8, 0x20a5,
+ 0x6fd9, 0x3a99,
+ 0x6fdb, 0x268b,
+ 0x6fdc, 0x3a9b,
+ 0x6fde, 0x1724,
+ 0x6fdf, 0x1f76,
+ 0x6fe0, 0x1725,
+ 0x6fe1, 0x1722,
+ 0x6fe2, 0x3a9d,
+ 0x6fe4, 0x216d,
+ 0x6fe5, 0x3a9f,
+ 0x6feb, 0x2001,
+ 0x6fec, 0x3aa5,
+ 0x6fee, 0x1723,
+ 0x6fef, 0x1726,
+ 0x6ff0, 0x2191,
+ 0x6ff1, 0x1e50,
+ 0x6ff2, 0x3aa7,
+ 0x6ffa, 0x1f9c,
+ 0x6ffb, 0x3aaf,
+ 0x6ffc, 0x23da,
+ 0x6ffd, 0x3ab0,
+ 0x6ffe, 0x2053,
+ 0x6fff, 0x3ab1,
+ 0x7000, 0x3ab2,
+ 0x7005, 0x23e9,
+ 0x7006, 0x23e4,
+ 0x7007, 0x3ab7,
+ 0x7009, 0x21d5,
+ 0x700a, 0x3ab9,
+ 0x700b, 0x23e6,
+ 0x700c, 0x3aba,
+ 0x700f, 0x23df,
+ 0x7010, 0x3abd,
+ 0x7011, 0x0bf8,
+ 0x7012, 0x3abe,
+ 0x7015, 0x1e4f,
+ 0x7016, 0x3ac1,
+ 0x7018, 0x23d9,
+ 0x7019, 0x3ac3,
+ 0x701a, 0x1727,
+ 0x701b, 0x1729,
+ 0x701c, 0x3ac4,
+ 0x701d, 0x2014,
+ 0x701e, 0x3ac5,
+ 0x701f, 0x23ec,
+ 0x7020, 0x23eb,
+ 0x7021, 0x3ac6,
+ 0x7023, 0x1728,
+ 0x7024, 0x3ac8,
+ 0x7027, 0x23d8,
+ 0x7028, 0x23ee,
+ 0x7029, 0x3acb,
+ 0x7030, 0x268e,
+ 0x7031, 0x3ad2,
+ 0x7032, 0x23ed,
+ 0x7033, 0x3ad3,
+ 0x7035, 0x172b,
+ 0x7036, 0x3ad5,
+ 0x7039, 0x172a,
+ 0x703a, 0x3ad8,
+ 0x703e, 0x1ffa,
+ 0x703f, 0x3adc,
+ 0x7043, 0x23d6,
+ 0x7044, 0x23e8,
+ 0x7045, 0x3ae0,
+ 0x704c, 0x0739,
+ 0x704d, 0x3ae7,
+ 0x704f, 0x172c,
+ 0x7050, 0x3ae9,
+ 0x7051, 0x2106,
+ 0x7052, 0x3aea,
+ 0x7055, 0x200b,
+ 0x7056, 0x3aed,
+ 0x7058, 0x2166,
+ 0x7059, 0x3aef,
+ 0x705d, 0x23ef,
+ 0x705e, 0x172d,
+ 0x705f, 0x3af3,
+ 0x7063, 0x2189,
+ 0x7064, 0x2058,
+ 0x7065, 0x3af7,
+ 0x7067, 0x23e7,
+ 0x7068, 0x3af9,
+ 0x706b, 0x0805,
+ 0x706c, 0x19ef,
+ 0x706d, 0x0af5,
+ 0x706e, 0x3afc,
+ 0x706f, 0x05a7,
+ 0x7070, 0x07e7,
+ 0x7071, 0x3afd,
+ 0x7075, 0x0a32,
+ 0x7076, 0x1131,
+ 0x7077, 0x3b01,
+ 0x7078, 0x08f3,
+ 0x7079, 0x3b02,
+ 0x707c, 0x1223,
+ 0x707d, 0x3b05,
+ 0x707e, 0x1119,
+ 0x707f, 0x049a,
+ 0x7080, 0x19cc,
+ 0x7081, 0x3b06,
+ 0x7085, 0x1913,
+ 0x7086, 0x3b0a,
+ 0x7089, 0x0a56,
+ 0x708a, 0x0539,
+ 0x708b, 0x3b0d,
+ 0x708e, 0x1000,
+ 0x708f, 0x3b10,
+ 0x7092, 0x04d9,
+ 0x7093, 0x3b13,
+ 0x7094, 0x0c8d,
+ 0x7095, 0x0948,
+ 0x7096, 0x19ce,
+ 0x7097, 0x3b14,
+ 0x7099, 0x11ca,
+ 0x709a, 0x3b16,
+ 0x709c, 0x19cd,
+ 0x709d, 0x19cf,
+ 0x709e, 0x3b18,
+ 0x70ab, 0x19d3,
+ 0x70ac, 0x0915,
+ 0x70ad, 0x0e12,
+ 0x70ae, 0x0b9b,
+ 0x70af, 0x08eb,
+ 0x70b0, 0x3b25,
+ 0x70b1, 0x19d4,
+ 0x70b2, 0x3b26,
+ 0x70b3, 0x0467,
+ 0x70b4, 0x3b27,
+ 0x70b7, 0x19d2,
+ 0x70b8, 0x1149,
+ 0x70b9, 0x05c4,
+ 0x70ba, 0x3b2a,
+ 0x70bb, 0x19d0,
+ 0x70bc, 0x09ff,
+ 0x70bd, 0x0508,
+ 0x70be, 0x3b2b,
+ 0x70c0, 0x19d1,
+ 0x70c1, 0x0dad,
+ 0x70c2, 0x09ae,
+ 0x70c3, 0x0e51,
+ 0x70c4, 0x3b2d,
+ 0x70c8, 0x0a1b,
+ 0x70c9, 0x3b31,
+ 0x70ca, 0x19d6,
+ 0x70cb, 0x3b32,
+ 0x70cf, 0x21a3,
+ 0x70d0, 0x3b36,
+ 0x70d8, 0x079d,
+ 0x70d9, 0x09be,
+ 0x70da, 0x3b3e,
+ 0x70db, 0x11f1,
+ 0x70dc, 0x3b3f,
+ 0x70df, 0x0ff5,
+ 0x70e0, 0x3b42,
+ 0x70e4, 0x094b,
+ 0x70e5, 0x3b46,
+ 0x70e6, 0x0650,
+ 0x70e7, 0x0d0e,
+ 0x70e8, 0x19d5,
+ 0x70e9, 0x07f7,
+ 0x70ea, 0x3b47,
+ 0x70eb, 0x0e1f,
+ 0x70ec, 0x08ce,
+ 0x70ed, 0x0ca3,
+ 0x70ee, 0x3b48,
+ 0x70ef, 0x0f16,
+ 0x70f0, 0x3b49,
+ 0x70f4, 0x217a,
+ 0x70f5, 0x3b4d,
+ 0x70f7, 0x0e9a,
+ 0x70f8, 0x3b4f,
+ 0x70f9, 0x0bac,
+ 0x70fa, 0x3b50,
+ 0x70fd, 0x0686,
+ 0x70fe, 0x3b53,
+ 0x7100, 0x3b55,
+ 0x7109, 0x0ff2,
+ 0x710a, 0x076f,
+ 0x710b, 0x3b5e,
+ 0x7110, 0x19d7,
+ 0x7111, 0x3b63,
+ 0x7113, 0x19d8,
+ 0x7114, 0x3b65,
+ 0x7115, 0x07d5,
+ 0x7116, 0x19d9,
+ 0x7117, 0x3b66,
+ 0x7118, 0x19f0,
+ 0x7119, 0x0423,
+ 0x711a, 0x0676,
+ 0x711b, 0x3b67,
+ 0x7121, 0x21a5,
+ 0x7122, 0x3b6d,
+ 0x7126, 0x088a,
+ 0x7127, 0x3b71,
+ 0x712f, 0x19da,
+ 0x7130, 0x100f,
+ 0x7131, 0x19db,
+ 0x7132, 0x3b79,
+ 0x7136, 0x0c96,
+ 0x7137, 0x3b7d,
+ 0x7145, 0x19df,
+ 0x7146, 0x3b8b,
+ 0x7149, 0x2022,
+ 0x714a, 0x19e1,
+ 0x714b, 0x3b8e,
+ 0x714c, 0x07e2,
+ 0x714d, 0x3b8f,
+ 0x714e, 0x0858,
+ 0x714f, 0x3b90,
+ 0x7152, 0x24d6,
+ 0x7153, 0x3b93,
+ 0x715c, 0x19dd,
+ 0x715d, 0x3b9c,
+ 0x715e, 0x0cf0,
+ 0x715f, 0x3b9d,
+ 0x7162, 0x233a,
+ 0x7163, 0x3ba0,
+ 0x7164, 0x0abf,
+ 0x7165, 0x3ba1,
+ 0x7166, 0x19f1,
+ 0x7167, 0x1176,
+ 0x7168, 0x19de,
+ 0x7169, 0x1eee,
+ 0x716a, 0x3ba2,
+ 0x716c, 0x24d5,
+ 0x716d, 0x3ba4,
+ 0x716e, 0x11f2,
+ 0x716f, 0x3ba5,
+ 0x7172, 0x19e0,
+ 0x7173, 0x19dc,
+ 0x7174, 0x3ba8,
+ 0x7178, 0x19e2,
+ 0x7179, 0x3bac,
+ 0x717a, 0x19e3,
+ 0x717b, 0x3bad,
+ 0x717d, 0x0cf8,
+ 0x717e, 0x3baf,
+ 0x7184, 0x0f15,
+ 0x7185, 0x3bb5,
+ 0x718a, 0x0fa7,
+ 0x718b, 0x3bba,
+ 0x718f, 0x0fd5,
+ 0x7190, 0x3bbe,
+ 0x7192, 0x2228,
+ 0x7193, 0x3bc0,
+ 0x7194, 0x0cb6,
+ 0x7195, 0x3bc1,
+ 0x7197, 0x24d7,
+ 0x7198, 0x19e4,
+ 0x7199, 0x0f04,
+ 0x719a, 0x3bc3,
+ 0x719f, 0x0d83,
+ 0x71a0, 0x19e8,
+ 0x71a1, 0x3bc8,
+ 0x71a8, 0x19e7,
+ 0x71a9, 0x3bcf,
+ 0x71ac, 0x03c9,
+ 0x71ad, 0x3bd2,
+ 0x71b1, 0x20fc,
+ 0x71b2, 0x3bd6,
+ 0x71b3, 0x19e5,
+ 0x71b4, 0x3bd7,
+ 0x71b5, 0x19e6,
+ 0x71b6, 0x3bd8,
+ 0x71b9, 0x19f2,
+ 0x71ba, 0x3bdb,
+ 0x71be, 0x1e87,
+ 0x71bf, 0x3bdf,
+ 0x71c1, 0x24d8,
+ 0x71c2, 0x3be1,
+ 0x71c3, 0x0c97,
+ 0x71c4, 0x3be2,
+ 0x71c8, 0x1eba,
+ 0x71c9, 0x3be6,
+ 0x71ce, 0x0a10,
+ 0x71cf, 0x3beb,
+ 0x71d2, 0x2119,
+ 0x71d3, 0x3bee,
+ 0x71d4, 0x19ea,
+ 0x71d5, 0x1009,
+ 0x71d6, 0x3bef,
+ 0x71d9, 0x216c,
+ 0x71da, 0x3bf2,
+ 0x71dc, 0x24d9,
+ 0x71dd, 0x3bf4,
+ 0x71df, 0x2227,
+ 0x71e0, 0x19e9,
+ 0x71e1, 0x3bf6,
+ 0x71e5, 0x1132,
+ 0x71e6, 0x1e5f,
+ 0x71e7, 0x19eb,
+ 0x71e8, 0x3bfa,
+ 0x71ed, 0x229f,
+ 0x71ee, 0x1396,
+ 0x71ef, 0x3bff,
+ 0x71f4, 0x1f5d,
+ 0x71f5, 0x3c04,
+ 0x71f9, 0x19ec,
+ 0x71fa, 0x3c08,
+ 0x71fc, 0x1fbc,
+ 0x71fd, 0x3c0a,
+ 0x71fe, 0x24da,
+ 0x71ff, 0x3c0b,
+ 0x7200, 0x3c0c,
+ 0x7206, 0x0415,
+ 0x7207, 0x3c12,
+ 0x720d, 0x2149,
+ 0x720e, 0x3c18,
+ 0x7210, 0x2046,
+ 0x7211, 0x3c1a,
+ 0x721b, 0x2000,
+ 0x721c, 0x3c24,
+ 0x721d, 0x19ed,
+ 0x721e, 0x3c25,
+ 0x7228, 0x19ee,
+ 0x7229, 0x3c2f,
+ 0x722a, 0x1203,
+ 0x722b, 0x3c30,
+ 0x722c, 0x0b81,
+ 0x722d, 0x3c31,
+ 0x7230, 0x196c,
+ 0x7231, 0x03b9,
+ 0x7232, 0x2190,
+ 0x7233, 0x3c34,
+ 0x7235, 0x0923,
+ 0x7236, 0x06b3,
+ 0x7237, 0x1036,
+ 0x7238, 0x03e1,
+ 0x7239, 0x05da,
+ 0x723a, 0x2208,
+ 0x723b, 0x1269,
+ 0x723c, 0x3c36,
+ 0x723d, 0x0da1,
+ 0x723e, 0x1ee6,
+ 0x723f, 0x169d,
+ 0x7240, 0x3c37,
+ 0x7247, 0x0bcb,
+ 0x7248, 0x03f1,
+ 0x7249, 0x3c3e,
+ 0x724c, 0x0b87,
+ 0x724d, 0x1969,
+ 0x724e, 0x3c41,
+ 0x7252, 0x196a,
+ 0x7253, 0x3c45,
+ 0x7256, 0x196b,
+ 0x7257, 0x3c48,
+ 0x7258, 0x24c3,
+ 0x7259, 0x0fe9,
+ 0x725a, 0x3c49,
+ 0x725b, 0x0b64,
+ 0x725c, 0x3c4a,
+ 0x725d, 0x1944,
+ 0x725e, 0x3c4b,
+ 0x725f, 0x0b15,
+ 0x7260, 0x3c4c,
+ 0x7261, 0x0b18,
+ 0x7262, 0x09b9,
+ 0x7263, 0x3c4d,
+ 0x7266, 0x1945,
+ 0x7267, 0x0b24,
+ 0x7268, 0x3c50,
+ 0x7269, 0x0efe,
+ 0x726a, 0x3c51,
+ 0x726e, 0x1942,
+ 0x726f, 0x1946,
+ 0x7270, 0x3c55,
+ 0x7272, 0x0d35,
+ 0x7273, 0x3c57,
+ 0x7275, 0x0c20,
+ 0x7276, 0x3c59,
+ 0x7279, 0x0e2b,
+ 0x727a, 0x0f0d,
+ 0x727b, 0x3c5c,
+ 0x727d, 0x20cc,
+ 0x727e, 0x1947,
+ 0x7280, 0x0f19,
+ 0x7281, 0x09d2,
+ 0x7282, 0x3c5e,
+ 0x7284, 0x1949,
+ 0x7285, 0x3c60,
+ 0x728a, 0x05fe,
+ 0x728b, 0x194a,
+ 0x728c, 0x3c65,
+ 0x728d, 0x194b,
+ 0x728e, 0x3c66,
+ 0x728f, 0x194c,
+ 0x7290, 0x3c67,
+ 0x7292, 0x194d,
+ 0x7293, 0x3c69,
+ 0x7296, 0x2340,
+ 0x7297, 0x3c6c,
+ 0x729f, 0x1943,
+ 0x72a0, 0x3c74,
+ 0x72a2, 0x1ed1,
+ 0x72a3, 0x3c76,
+ 0x72a7, 0x21ac,
+ 0x72a8, 0x3c7a,
+ 0x72ac, 0x0c89,
+ 0x72ad, 0x15ef,
+ 0x72ae, 0x3c7e,
+ 0x72af, 0x0655,
+ 0x72b0, 0x15f0,
+ 0x72b1, 0x3c7f,
+ 0x72b4, 0x15f1,
+ 0x72b5, 0x3c82,
+ 0x72b6, 0x1211,
+ 0x72b7, 0x15f2,
+ 0x72b9, 0x10b1,
+ 0x72ba, 0x3c83,
+ 0x72c0, 0x22af,
+ 0x72c1, 0x15f5,
+ 0x72c2, 0x097e,
+ 0x72c3, 0x15f4,
+ 0x72c4, 0x05b3,
+ 0x72c5, 0x3c89,
+ 0x72c8, 0x0420,
+ 0x72c9, 0x3c8c,
+ 0x72cd, 0x15f7,
+ 0x72ce, 0x15f6,
+ 0x72cf, 0x3c90,
+ 0x72d0, 0x07b3,
+ 0x72d1, 0x3c91,
+ 0x72d2, 0x15f8,
+ 0x72d3, 0x3c92,
+ 0x72d7, 0x0710,
+ 0x72d8, 0x3c96,
+ 0x72d9, 0x0900,
+ 0x72da, 0x3c97,
+ 0x72de, 0x0b5f,
+ 0x72df, 0x3c9b,
+ 0x72e0, 0x0794,
+ 0x72e1, 0x0897,
+ 0x72e2, 0x3c9c,
+ 0x72e8, 0x15f9,
+ 0x72e9, 0x15fb,
+ 0x72ea, 0x3ca2,
+ 0x72ec, 0x05ff,
+ 0x72ed, 0x0f2e,
+ 0x72ee, 0x0d3f,
+ 0x72ef, 0x15fa,
+ 0x72f0, 0x1199,
+ 0x72f1, 0x10e1,
+ 0x72f2, 0x15fc,
+ 0x72f3, 0x1600,
+ 0x72f4, 0x15fd,
+ 0x72f5, 0x3ca4,
+ 0x72f7, 0x15fe,
+ 0x72f8, 0x09d5,
+ 0x72f9, 0x21b6,
+ 0x72fa, 0x1602,
+ 0x72fc, 0x09b2,
+ 0x72fd, 0x1e3d,
+ 0x72fe, 0x3ca6,
+ 0x7300, 0x3ca8,
+ 0x7301, 0x15ff,
+ 0x7302, 0x3ca9,
+ 0x7303, 0x1601,
+ 0x7304, 0x3caa,
+ 0x730a, 0x1607,
+ 0x730b, 0x3cb0,
+ 0x730e, 0x0a1d,
+ 0x730f, 0x3cb3,
+ 0x7313, 0x1605,
+ 0x7314, 0x3cb7,
+ 0x7315, 0x160a,
+ 0x7316, 0x04c5,
+ 0x7317, 0x1604,
+ 0x7318, 0x3cb8,
+ 0x731b, 0x0ad2,
+ 0x731c, 0x0489,
+ 0x731d, 0x1609,
+ 0x731e, 0x1608,
+ 0x731f, 0x3cbb,
+ 0x7321, 0x1606,
+ 0x7322, 0x160b,
+ 0x7323, 0x3cbd,
+ 0x7325, 0x160d,
+ 0x7326, 0x3cbf,
+ 0x7329, 0x0f94,
+ 0x732a, 0x11ec,
+ 0x732b, 0x0aad,
+ 0x732c, 0x160e,
+ 0x732d, 0x3cc2,
+ 0x732e, 0x0f44,
+ 0x732f, 0x3cc3,
+ 0x7331, 0x1610,
+ 0x7332, 0x3cc5,
+ 0x7334, 0x07a6,
+ 0x7335, 0x3cc7,
+ 0x7336, 0x2235,
+ 0x7337, 0x18d4,
+ 0x7338, 0x160f,
+ 0x7339, 0x160c,
+ 0x733a, 0x3cc8,
+ 0x733b, 0x2397,
+ 0x733c, 0x3cc9,
+ 0x733e, 0x07c0,
+ 0x733f, 0x10f6,
+ 0x7340, 0x3ccb,
+ 0x7341, 0x2395,
+ 0x7342, 0x3ccc,
+ 0x7344, 0x223f,
+ 0x7345, 0x212a,
+ 0x7346, 0x3cce,
+ 0x734d, 0x1612,
+ 0x734e, 0x3cd5,
+ 0x7350, 0x1611,
+ 0x7351, 0x3cd7,
+ 0x7352, 0x18d5,
+ 0x7353, 0x3cd8,
+ 0x7357, 0x1613,
+ 0x7358, 0x3cdc,
+ 0x7360, 0x1614,
+ 0x7361, 0x3ce4,
+ 0x7368, 0x1ed2,
+ 0x7369, 0x3ceb,
+ 0x736a, 0x2396,
+ 0x736b, 0x2398,
+ 0x736c, 0x1615,
+ 0x736d, 0x0df4,
+ 0x736e, 0x3cec,
+ 0x736f, 0x1616,
+ 0x7370, 0x20a2,
+ 0x7371, 0x3ced,
+ 0x7372, 0x1f64,
+ 0x7373, 0x3cee,
+ 0x7375, 0x202b,
+ 0x7376, 0x3cf0,
+ 0x7377, 0x2394,
+ 0x7378, 0x2139,
+ 0x7379, 0x3cf1,
+ 0x737a, 0x215f,
+ 0x737b, 0x21c1,
+ 0x737c, 0x239a,
+ 0x737d, 0x3cf2,
+ 0x737e, 0x1617,
+ 0x737f, 0x3cf3,
+ 0x7380, 0x2399,
+ 0x7381, 0x3cf4,
+ 0x7384, 0x0fc9,
+ 0x7385, 0x3cf7,
+ 0x7387, 0x0a71,
+ 0x7388, 0x3cf9,
+ 0x7389, 0x10d6,
+ 0x738a, 0x3cfa,
+ 0x738b, 0x0ea6,
+ 0x738c, 0x3cfb,
+ 0x738e, 0x1818,
+ 0x738f, 0x3cfd,
+ 0x7391, 0x1819,
+ 0x7392, 0x3cff,
+ 0x7396, 0x08f0,
+ 0x7397, 0x3d03,
+ 0x739b, 0x0a91,
+ 0x739c, 0x3d07,
+ 0x739f, 0x181c,
+ 0x73a0, 0x3d0a,
+ 0x73a2, 0x181b,
+ 0x73a3, 0x3d0c,
+ 0x73a9, 0x0e97,
+ 0x73aa, 0x3d12,
+ 0x73ab, 0x0aba,
+ 0x73ac, 0x3d13,
+ 0x73ae, 0x181a,
+ 0x73af, 0x07cc,
+ 0x73b0, 0x0f43,
+ 0x73b1, 0x3d15,
+ 0x73b2, 0x0a2a,
+ 0x73b3, 0x1821,
+ 0x73b4, 0x3d16,
+ 0x73b7, 0x1820,
+ 0x73b8, 0x3d19,
+ 0x73ba, 0x182c,
+ 0x73bb, 0x046a,
+ 0x73bc, 0x3d1b,
+ 0x73c0, 0x1822,
+ 0x73c1, 0x3d1f,
+ 0x73c2, 0x181e,
+ 0x73c3, 0x3d20,
+ 0x73c8, 0x1824,
+ 0x73c9, 0x1823,
+ 0x73ca, 0x0cf3,
+ 0x73cb, 0x3d25,
+ 0x73cd, 0x1185,
+ 0x73ce, 0x3d27,
+ 0x73cf, 0x181d,
+ 0x73d0, 0x0646,
+ 0x73d1, 0x181f,
+ 0x73d2, 0x3d28,
+ 0x73d9, 0x1826,
+ 0x73da, 0x3d2f,
+ 0x73de, 0x182b,
+ 0x73df, 0x3d33,
+ 0x73e0, 0x11e8,
+ 0x73e1, 0x3d34,
+ 0x73e5, 0x1825,
+ 0x73e6, 0x3d38,
+ 0x73e7, 0x182a,
+ 0x73e8, 0x3d39,
+ 0x73e9, 0x1829,
+ 0x73ea, 0x3d3a,
+ 0x73ed, 0x03eb,
+ 0x73ee, 0x3d3d,
+ 0x73f2, 0x182d,
+ 0x73f3, 0x3d41,
+ 0x73fe, 0x21c0,
+ 0x73ff, 0x3d4c,
+ 0x7400, 0x3d4d,
+ 0x7403, 0x0c6f,
+ 0x7404, 0x3d50,
+ 0x7405, 0x09b0,
+ 0x7406, 0x09d8,
+ 0x7407, 0x3d51,
+ 0x7409, 0x0a39,
+ 0x740a, 0x1828,
+ 0x740b, 0x3d53,
+ 0x740f, 0x182e,
+ 0x7410, 0x0deb,
+ 0x7411, 0x3d57,
+ 0x741a, 0x1838,
+ 0x741b, 0x1837,
+ 0x741c, 0x3d60,
+ 0x7422, 0x121e,
+ 0x7423, 0x3d66,
+ 0x7425, 0x1832,
+ 0x7426, 0x1831,
+ 0x7427, 0x3d68,
+ 0x7428, 0x1833,
+ 0x7429, 0x3d69,
+ 0x742a, 0x182f,
+ 0x742b, 0x3d6a,
+ 0x742c, 0x1836,
+ 0x742d, 0x3d6b,
+ 0x742e, 0x1835,
+ 0x742f, 0x3d6c,
+ 0x7430, 0x1834,
+ 0x7431, 0x3d6d,
+ 0x7433, 0x0a1e,
+ 0x7434, 0x0c56,
+ 0x7435, 0x0bbe,
+ 0x7436, 0x0b84,
+ 0x7437, 0x3d6f,
+ 0x743c, 0x0c6a,
+ 0x743d, 0x3d74,
+ 0x743f, 0x2460,
+ 0x7440, 0x3d76,
+ 0x7441, 0x1839,
+ 0x7442, 0x3d77,
+ 0x744b, 0x245c,
+ 0x744c, 0x3d80,
+ 0x7455, 0x183c,
+ 0x7456, 0x3d89,
+ 0x7457, 0x183b,
+ 0x7458, 0x3d8a,
+ 0x7459, 0x183d,
+ 0x745a, 0x07ae,
+ 0x745b, 0x1830,
+ 0x745c, 0x183a,
+ 0x745d, 0x3d8b,
+ 0x745e, 0x0ccb,
+ 0x745f, 0x0ce3,
+ 0x7460, 0x3d8c,
+ 0x7463, 0x215d,
+ 0x7464, 0x3d8f,
+ 0x7469, 0x2225,
+ 0x746a, 0x206a,
+ 0x746b, 0x3d94,
+ 0x746d, 0x183f,
+ 0x746e, 0x3d96,
+ 0x7470, 0x073e,
+ 0x7471, 0x3d98,
+ 0x7476, 0x1027,
+ 0x7477, 0x183e,
+ 0x7478, 0x3d9d,
+ 0x747e, 0x1840,
+ 0x747f, 0x3da3,
+ 0x7480, 0x1843,
+ 0x7482, 0x3da4,
+ 0x7483, 0x09f0,
+ 0x7484, 0x3da5,
+ 0x7487, 0x1845,
+ 0x7488, 0x3da8,
+ 0x7489, 0x2461,
+ 0x748a, 0x3da9,
+ 0x748b, 0x1846,
+ 0x748c, 0x3daa,
+ 0x748e, 0x1842,
+ 0x748f, 0x3dac,
+ 0x7490, 0x184a,
+ 0x7491, 0x3dad,
+ 0x749c, 0x1841,
+ 0x749d, 0x3db8,
+ 0x749e, 0x1847,
+ 0x749f, 0x3db9,
+ 0x74a3, 0x245b,
+ 0x74a4, 0x3dbd,
+ 0x74a6, 0x2462,
+ 0x74a7, 0x184b,
+ 0x74a8, 0x1848,
+ 0x74aa, 0x3dbf,
+ 0x74b0, 0x1f54,
+ 0x74b1, 0x3dc5,
+ 0x74ba, 0x184d,
+ 0x74bb, 0x3dce,
+ 0x74bd, 0x245f,
+ 0x74be, 0x3dd0,
+ 0x74ca, 0x20ec,
+ 0x74cb, 0x3ddc,
+ 0x74cf, 0x245d,
+ 0x74d0, 0x3de0,
+ 0x74d2, 0x184c,
+ 0x74d3, 0x3de2,
+ 0x74d4, 0x2463,
+ 0x74d5, 0x3de3,
+ 0x74da, 0x2464,
+ 0x74db, 0x3de8,
+ 0x74dc, 0x0728,
+ 0x74dd, 0x3de9,
+ 0x74de, 0x1b32,
+ 0x74df, 0x3dea,
+ 0x74e0, 0x1b33,
+ 0x74e1, 0x3deb,
+ 0x74e2, 0x0bcf,
+ 0x74e3, 0x03f5,
+ 0x74e4, 0x0c9a,
+ 0x74e5, 0x3dec,
+ 0x74e6, 0x0e90,
+ 0x74e7, 0x3ded,
+ 0x74ee, 0x0edc,
+ 0x74ef, 0x1903,
+ 0x74f0, 0x3df4,
+ 0x74f4, 0x1904,
+ 0x74f5, 0x3df8,
+ 0x74f6, 0x0bde,
+ 0x74f7, 0x054c,
+ 0x74f8, 0x3df9,
+ 0x74ff, 0x1905,
+ 0x7500, 0x3e00,
+ 0x7504, 0x1188,
+ 0x7505, 0x3e04,
+ 0x750c, 0x24a5,
+ 0x750d, 0x1485,
+ 0x750e, 0x3e0b,
+ 0x750f, 0x1906,
+ 0x7510, 0x3e0c,
+ 0x7511, 0x1907,
+ 0x7512, 0x3e0d,
+ 0x7513, 0x1908,
+ 0x7514, 0x3e0e,
+ 0x7518, 0x06c5,
+ 0x7519, 0x14f8,
+ 0x751a, 0x0d2e,
+ 0x751b, 0x3e12,
+ 0x751c, 0x0e43,
+ 0x751d, 0x3e13,
+ 0x751f, 0x0d33,
+ 0x7520, 0x3e15,
+ 0x7523, 0x1e70,
+ 0x7524, 0x3e18,
+ 0x7525, 0x0d34,
+ 0x7526, 0x3e19,
+ 0x7528, 0x10a8,
+ 0x7529, 0x0d9b,
+ 0x752a, 0x3e1b,
+ 0x752b, 0x06a1,
+ 0x752c, 0x1b34,
+ 0x752d, 0x042b,
+ 0x752e, 0x3e1c,
+ 0x752f, 0x1734,
+ 0x7530, 0x0e42,
+ 0x7531, 0x10ae,
+ 0x7532, 0x084a,
+ 0x7533, 0x0d23,
+ 0x7534, 0x3e1d,
+ 0x7535, 0x05c8,
+ 0x7536, 0x3e1e,
+ 0x7537, 0x0b33,
+ 0x7538, 0x05ca,
+ 0x7539, 0x3e1f,
+ 0x753a, 0x1a78,
+ 0x753b, 0x07c2,
+ 0x753c, 0x3e20,
+ 0x753e, 0x1816,
+ 0x753f, 0x3e22,
+ 0x7540, 0x1a79,
+ 0x7541, 0x3e23,
+ 0x7545, 0x04ce,
+ 0x7546, 0x3e27,
+ 0x7548, 0x1a7c,
+ 0x7549, 0x3e29,
+ 0x754b, 0x1a7b,
+ 0x754c, 0x08b8,
+ 0x754d, 0x3e2b,
+ 0x754e, 0x1a7a,
+ 0x754f, 0x0ec6,
+ 0x7550, 0x3e2c,
+ 0x7554, 0x0b90,
+ 0x7555, 0x3e30,
+ 0x7559, 0x0a3d,
+ 0x755a, 0x139e,
+ 0x755b, 0x1a7d,
+ 0x755c, 0x0fbe,
+ 0x755d, 0x208f,
+ 0x755e, 0x3e34,
+ 0x7562, 0x1e42,
+ 0x7563, 0x3e38,
+ 0x7565, 0x0a7b,
+ 0x7566, 0x0c07,
+ 0x7567, 0x3e3a,
+ 0x756a, 0x0649,
+ 0x756b, 0x1f4e,
+ 0x756c, 0x3e3d,
+ 0x7572, 0x1a7e,
+ 0x7573, 0x3e43,
+ 0x7574, 0x0510,
+ 0x7575, 0x3e44,
+ 0x7576, 0x1eb1,
+ 0x7577, 0x3e45,
+ 0x7578, 0x0810,
+ 0x7579, 0x1a7f,
+ 0x757a, 0x3e46,
+ 0x757f, 0x1814,
+ 0x7580, 0x3e4b,
+ 0x7583, 0x1a80,
+ 0x7584, 0x3e4e,
+ 0x7586, 0x087f,
+ 0x7587, 0x1e8b,
+ 0x7588, 0x3e50,
+ 0x758b, 0x1bc6,
+ 0x758c, 0x3e53,
+ 0x758f, 0x0d7f,
+ 0x7590, 0x3e56,
+ 0x7591, 0x1050,
+ 0x7592, 0x1b60,
+ 0x7593, 0x3e57,
+ 0x7594, 0x1b61,
+ 0x7595, 0x3e58,
+ 0x7596, 0x1b62,
+ 0x7597, 0x0a0f,
+ 0x7598, 0x3e59,
+ 0x7599, 0x06e8,
+ 0x759a, 0x08fd,
+ 0x759b, 0x3e5a,
+ 0x759d, 0x1b64,
+ 0x759e, 0x3e5c,
+ 0x759f, 0x0b72,
+ 0x75a0, 0x1b63,
+ 0x75a1, 0x101a,
+ 0x75a2, 0x3e5d,
+ 0x75a3, 0x1b66,
+ 0x75a4, 0x03d7,
+ 0x75a5, 0x08bb,
+ 0x75a6, 0x3e5e,
+ 0x75ab, 0x1066,
+ 0x75ac, 0x1b65,
+ 0x75ad, 0x3e63,
+ 0x75ae, 0x0532,
+ 0x75af, 0x0685,
+ 0x75b0, 0x1b6c,
+ 0x75b1, 0x1b6b,
+ 0x75b2, 0x0bc2,
+ 0x75b3, 0x1b67,
+ 0x75b5, 0x0546,
+ 0x75b6, 0x3e64,
+ 0x75b8, 0x1b69,
+ 0x75b9, 0x118f,
+ 0x75ba, 0x3e66,
+ 0x75bc, 0x0e2e,
+ 0x75bd, 0x0901,
+ 0x75be, 0x0825,
+ 0x75bf, 0x3e68,
+ 0x75c2, 0x1b6e,
+ 0x75c3, 0x1b6d,
+ 0x75c4, 0x1b6a,
+ 0x75c5, 0x0468,
+ 0x75c6, 0x3e6b,
+ 0x75c7, 0x11a1,
+ 0x75c8, 0x109d,
+ 0x75c9, 0x08e6,
+ 0x75ca, 0x0c87,
+ 0x75cb, 0x3e6c,
+ 0x75cd, 0x1b70,
+ 0x75ce, 0x3e6e,
+ 0x75d2, 0x1020,
+ 0x75d3, 0x3e72,
+ 0x75d4, 0x11cb,
+ 0x75d5, 0x0792,
+ 0x75d6, 0x1b6f,
+ 0x75d7, 0x3e73,
+ 0x75d8, 0x05fa,
+ 0x75d9, 0x1fc6,
+ 0x75da, 0x3e74,
+ 0x75db, 0x0e65,
+ 0x75dc, 0x3e75,
+ 0x75de, 0x0bc5,
+ 0x75df, 0x3e77,
+ 0x75e2, 0x09ea,
+ 0x75e3, 0x1b71,
+ 0x75e4, 0x1b74,
+ 0x75e5, 0x3e7a,
+ 0x75e6, 0x1b73,
+ 0x75e7, 0x1b76,
+ 0x75e8, 0x1b72,
+ 0x75e9, 0x3e7b,
+ 0x75ea, 0x07d3,
+ 0x75eb, 0x1b75,
+ 0x75ec, 0x3e7c,
+ 0x75f0, 0x0e08,
+ 0x75f1, 0x1b78,
+ 0x75f2, 0x3e80,
+ 0x75f4, 0x04fa,
+ 0x75f5, 0x3e82,
+ 0x75f9, 0x043d,
+ 0x75fa, 0x3e86,
+ 0x75fc, 0x1b79,
+ 0x75fd, 0x3e88,
+ 0x75ff, 0x1b7a,
+ 0x7600, 0x1b7c,
+ 0x7601, 0x0564,
+ 0x7602, 0x25ae,
+ 0x7603, 0x1b77,
+ 0x7604, 0x3e8a,
+ 0x7605, 0x1b7d,
+ 0x7606, 0x3e8b,
+ 0x760a, 0x1b80,
+ 0x760b, 0x1f01,
+ 0x760c, 0x1b7e,
+ 0x760d, 0x2200,
+ 0x760e, 0x3e8f,
+ 0x7610, 0x1b7b,
+ 0x7611, 0x3e91,
+ 0x7615, 0x1b83,
+ 0x7616, 0x3e95,
+ 0x7617, 0x1b7f,
+ 0x7618, 0x1b82,
+ 0x7619, 0x1b84,
+ 0x761a, 0x3e96,
+ 0x761b, 0x1b85,
+ 0x761c, 0x3e97,
+ 0x761e, 0x25b2,
+ 0x761f, 0x0ed0,
+ 0x7620, 0x1b88,
+ 0x7621, 0x1e97,
+ 0x7622, 0x1b87,
+ 0x7623, 0x3e99,
+ 0x7624, 0x0a3f,
+ 0x7625, 0x1b81,
+ 0x7626, 0x0d74,
+ 0x7627, 0x20ab,
+ 0x7628, 0x3e9a,
+ 0x7629, 0x0574,
+ 0x762a, 0x045a,
+ 0x762b, 0x0e04,
+ 0x762c, 0x3e9b,
+ 0x762d, 0x1b8a,
+ 0x762e, 0x3e9c,
+ 0x7630, 0x1b8b,
+ 0x7631, 0x3e9e,
+ 0x7633, 0x1b90,
+ 0x7634, 0x116f,
+ 0x7635, 0x1b8d,
+ 0x7636, 0x3ea0,
+ 0x7638, 0x0c8e,
+ 0x7639, 0x3ea2,
+ 0x763b, 0x25b3,
+ 0x763c, 0x1b86,
+ 0x763d, 0x3ea4,
+ 0x763e, 0x1b8f,
+ 0x763f, 0x1b8c,
+ 0x7640, 0x1b89,
+ 0x7641, 0x3ea5,
+ 0x7642, 0x2028,
+ 0x7643, 0x1b8e,
+ 0x7644, 0x3ea6,
+ 0x7646, 0x25af,
+ 0x7648, 0x3ea8,
+ 0x7649, 0x25b1,
+ 0x764a, 0x3ea9,
+ 0x764c, 0x03b4,
+ 0x764d, 0x1b91,
+ 0x764e, 0x3eab,
+ 0x7654, 0x1b93,
+ 0x7655, 0x3eb1,
+ 0x7656, 0x1b95,
+ 0x7657, 0x3eb2,
+ 0x7658, 0x25ac,
+ 0x7659, 0x3eb3,
+ 0x765c, 0x1b94,
+ 0x765d, 0x3eb6,
+ 0x765e, 0x1b92,
+ 0x765f, 0x1e4e,
+ 0x7660, 0x3eb7,
+ 0x7662, 0x2202,
+ 0x7663, 0x0fcb,
+ 0x7664, 0x25ab,
+ 0x7665, 0x2286,
+ 0x7666, 0x3eb9,
+ 0x7667, 0x25ad,
+ 0x7668, 0x3eba,
+ 0x7669, 0x25b6,
+ 0x766a, 0x3ebb,
+ 0x766b, 0x1b96,
+ 0x766c, 0x21e3,
+ 0x766d, 0x25b4,
+ 0x766f, 0x1b97,
+ 0x7670, 0x222f,
+ 0x7671, 0x2165,
+ 0x7672, 0x25b7,
+ 0x7673, 0x3ebc,
+ 0x7678, 0x0748,
+ 0x7679, 0x3ec1,
+ 0x767b, 0x05a8,
+ 0x767c, 0x1ee9,
+ 0x767d, 0x03e2,
+ 0x767e, 0x03e4,
+ 0x767f, 0x3ec3,
+ 0x7682, 0x1130,
+ 0x7683, 0x3ec6,
+ 0x7684, 0x05a5,
+ 0x7685, 0x3ec7,
+ 0x7686, 0x08a5,
+ 0x7687, 0x07df,
+ 0x7688, 0x1b2d,
+ 0x7689, 0x3ec8,
+ 0x768b, 0x06d9,
+ 0x768c, 0x3eca,
+ 0x768e, 0x1b2e,
+ 0x768f, 0x3ecc,
+ 0x7691, 0x03b3,
+ 0x7692, 0x3ece,
+ 0x7693, 0x1b2f,
+ 0x7694, 0x3ecf,
+ 0x7696, 0x0e9f,
+ 0x7697, 0x3ed1,
+ 0x7699, 0x1b30,
+ 0x769a, 0x1e25,
+ 0x769b, 0x3ed3,
+ 0x76a4, 0x1b31,
+ 0x76a5, 0x3edc,
+ 0x76ae, 0x0bc3,
+ 0x76af, 0x3ee5,
+ 0x76b1, 0x11e4,
+ 0x76b2, 0x1bc8,
+ 0x76b3, 0x3ee7,
+ 0x76b4, 0x1bc9,
+ 0x76b5, 0x3ee8,
+ 0x76b8, 0x25c0,
+ 0x76b9, 0x3eeb,
+ 0x76ba, 0x229a,
+ 0x76bb, 0x3eec,
+ 0x76bf, 0x0af8,
+ 0x76c0, 0x3ef0,
+ 0x76c2, 0x10c0,
+ 0x76c3, 0x3ef2,
+ 0x76c5, 0x11d0,
+ 0x76c6, 0x0ba9,
+ 0x76c7, 0x3ef4,
+ 0x76c8, 0x1094,
+ 0x76c9, 0x3ef5,
+ 0x76ca, 0x106d,
+ 0x76cb, 0x3ef6,
+ 0x76cd, 0x1a8b,
+ 0x76ce, 0x03c6,
+ 0x76cf, 0x1156,
+ 0x76d0, 0x0ff7,
+ 0x76d1, 0x0853,
+ 0x76d2, 0x0787,
+ 0x76d3, 0x3ef8,
+ 0x76d4, 0x0985,
+ 0x76d5, 0x3ef9,
+ 0x76d6, 0x06c2,
+ 0x76d7, 0x05a2,
+ 0x76d8, 0x0b8d,
+ 0x76d9, 0x3efa,
+ 0x76db, 0x0d39,
+ 0x76dc, 0x3efc,
+ 0x76de, 0x226e,
+ 0x76df, 0x0ad0,
+ 0x76e0, 0x3efe,
+ 0x76e1, 0x1fbd,
+ 0x76e2, 0x3eff,
+ 0x76e3, 0x1f84,
+ 0x76e4, 0x20b2,
+ 0x76e5, 0x1a8c,
+ 0x76e6, 0x3f00,
+ 0x76e7, 0x2043,
+ 0x76e8, 0x3f01,
+ 0x76ee, 0x0b22,
+ 0x76ef, 0x05e1,
+ 0x76f0, 0x3f07,
+ 0x76f1, 0x1a58,
+ 0x76f2, 0x0aa9,
+ 0x76f3, 0x3f08,
+ 0x76f4, 0x11b0,
+ 0x76f5, 0x3f09,
+ 0x76f8, 0x0f4d,
+ 0x76f9, 0x1a5b,
+ 0x76fa, 0x3f0c,
+ 0x76fc, 0x0b8f,
+ 0x76fd, 0x3f0e,
+ 0x76fe, 0x061b,
+ 0x76ff, 0x3f0f,
+ 0x7700, 0x3f10,
+ 0x7701, 0x0d38,
+ 0x7702, 0x3f11,
+ 0x7704, 0x1a59,
+ 0x7705, 0x3f13,
+ 0x7707, 0x1a5c,
+ 0x7709, 0x0ac1,
+ 0x770a, 0x3f15,
+ 0x770b, 0x0941,
+ 0x770c, 0x3f16,
+ 0x770d, 0x1a5a,
+ 0x770e, 0x3f17,
+ 0x7719, 0x1a60,
+ 0x771a, 0x1a5e,
+ 0x771b, 0x3f22,
+ 0x771f, 0x1187,
+ 0x7720, 0x0ae4,
+ 0x7721, 0x3f26,
+ 0x7722, 0x1a5f,
+ 0x7723, 0x3f27,
+ 0x7726, 0x1a62,
+ 0x7727, 0x3f2a,
+ 0x7728, 0x1144,
+ 0x7729, 0x0fcc,
+ 0x772a, 0x3f2b,
+ 0x772d, 0x1a61,
+ 0x772e, 0x3f2e,
+ 0x772f, 0x0ad5,
+ 0x7730, 0x3f2f,
+ 0x7735, 0x1a63,
+ 0x7736, 0x0981,
+ 0x7737, 0x091b,
+ 0x7738, 0x1a64,
+ 0x7739, 0x3f34,
+ 0x773a, 0x0e4a,
+ 0x773b, 0x3f35,
+ 0x773c, 0x1004,
+ 0x773d, 0x3f36,
+ 0x7740, 0x1222,
+ 0x7741, 0x1197,
+ 0x7742, 0x3f39,
+ 0x7743, 0x1a68,
+ 0x7744, 0x3f3a,
+ 0x7747, 0x1a67,
+ 0x7748, 0x3f3d,
+ 0x774f, 0x2684,
+ 0x7750, 0x1a65,
+ 0x7752, 0x3f44,
+ 0x775a, 0x1a69,
+ 0x775b, 0x08d5,
+ 0x775c, 0x3f4c,
+ 0x775e, 0x24ef,
+ 0x775f, 0x3f4e,
+ 0x7761, 0x0da4,
+ 0x7762, 0x1a6b,
+ 0x7763, 0x05fc,
+ 0x7764, 0x3f50,
+ 0x7765, 0x1a6c,
+ 0x7766, 0x0b23,
+ 0x7767, 0x3f51,
+ 0x7768, 0x1a6a,
+ 0x7769, 0x3f52,
+ 0x776b, 0x08af,
+ 0x776c, 0x048e,
+ 0x776d, 0x3f54,
+ 0x7779, 0x0602,
+ 0x777a, 0x3f60,
+ 0x777d, 0x1a6f,
+ 0x777e, 0x1270,
+ 0x777f, 0x1a6d,
+ 0x7780, 0x1a70,
+ 0x7781, 0x3f63,
+ 0x7784, 0x0aee,
+ 0x7785, 0x0517,
+ 0x7786, 0x3f66,
+ 0x778c, 0x1a71,
+ 0x778d, 0x1a6e,
+ 0x778e, 0x0f26,
+ 0x778f, 0x3f6c,
+ 0x7791, 0x1a72,
+ 0x7792, 0x0a9e,
+ 0x7793, 0x3f6e,
+ 0x7798, 0x24ee,
+ 0x7799, 0x3f73,
+ 0x779e, 0x2074,
+ 0x779f, 0x1a73,
+ 0x77a1, 0x3f78,
+ 0x77a2, 0x1495,
+ 0x77a3, 0x3f79,
+ 0x77a5, 0x0bd2,
+ 0x77a6, 0x3f7b,
+ 0x77a7, 0x0c43,
+ 0x77a8, 0x3f7c,
+ 0x77a9, 0x11f4,
+ 0x77aa, 0x05aa,
+ 0x77ab, 0x3f7d,
+ 0x77ac, 0x0da7,
+ 0x77ad, 0x2687,
+ 0x77ae, 0x3f7e,
+ 0x77b0, 0x1a75,
+ 0x77b1, 0x3f80,
+ 0x77b3, 0x0e5c,
+ 0x77b4, 0x3f82,
+ 0x77b5, 0x1a76,
+ 0x77b6, 0x3f83,
+ 0x77bb, 0x1151,
+ 0x77bc, 0x24f0,
+ 0x77bd, 0x1a77,
+ 0x77be, 0x3f88,
+ 0x77bf, 0x1d7e,
+ 0x77c0, 0x3f89,
+ 0x77c7, 0x268d,
+ 0x77c8, 0x3f90,
+ 0x77cd, 0x1397,
+ 0x77ce, 0x3f95,
+ 0x77d7, 0x0526,
+ 0x77d8, 0x3f9e,
+ 0x77da, 0x22a0,
+ 0x77db, 0x0ab1,
+ 0x77dc, 0x1bca,
+ 0x77dd, 0x3fa0,
+ 0x77e2, 0x0d4f,
+ 0x77e3, 0x105a,
+ 0x77e4, 0x3fa5,
+ 0x77e5, 0x11a9,
+ 0x77e6, 0x3fa6,
+ 0x77e7, 0x1b1a,
+ 0x77e8, 0x3fa7,
+ 0x77e9, 0x0907,
+ 0x77ea, 0x3fa8,
+ 0x77eb, 0x0894,
+ 0x77ec, 0x1b1b,
+ 0x77ed, 0x060b,
+ 0x77ee, 0x03b6,
+ 0x77ef, 0x1fab,
+ 0x77f0, 0x3fa9,
+ 0x77f3, 0x0d46,
+ 0x77f4, 0x3fac,
+ 0x77f6, 0x1a22,
+ 0x77f7, 0x3fae,
+ 0x77f8, 0x1a23,
+ 0x77f9, 0x3faf,
+ 0x77fd, 0x0f08,
+ 0x77fe, 0x064c,
+ 0x77ff, 0x0980,
+ 0x7800, 0x1a24,
+ 0x7801, 0x0a92,
+ 0x7802, 0x0ce9,
+ 0x7803, 0x3fb3,
+ 0x7809, 0x1a25,
+ 0x780a, 0x3fb9,
+ 0x780c, 0x0c15,
+ 0x780d, 0x0940,
+ 0x780e, 0x3fbb,
+ 0x7811, 0x1a28,
+ 0x7812, 0x0bb9,
+ 0x7813, 0x3fbe,
+ 0x7814, 0x0ff9,
+ 0x7815, 0x3fbf,
+ 0x7816, 0x1206,
+ 0x7817, 0x1a26,
+ 0x7819, 0x3fc0,
+ 0x781a, 0x100b,
+ 0x781b, 0x3fc1,
+ 0x781c, 0x1a2b,
+ 0x781e, 0x3fc2,
+ 0x781f, 0x1a30,
+ 0x7820, 0x3fc3,
+ 0x7823, 0x1a34,
+ 0x7824, 0x3fc6,
+ 0x7825, 0x1a32,
+ 0x7826, 0x1a3a,
+ 0x7827, 0x1189,
+ 0x7828, 0x3fc7,
+ 0x7829, 0x1a35,
+ 0x782a, 0x3fc8,
+ 0x782c, 0x1a33,
+ 0x782d, 0x1a2a,
+ 0x782e, 0x3fca,
+ 0x7830, 0x0baa,
+ 0x7831, 0x3fcc,
+ 0x7834, 0x0be5,
+ 0x7835, 0x3fcf,
+ 0x7837, 0x0d22,
+ 0x7838, 0x1115,
+ 0x7839, 0x1a2d,
+ 0x783c, 0x1a31,
+ 0x783d, 0x3fd1,
+ 0x783e, 0x09e4,
+ 0x783f, 0x3fd2,
+ 0x7840, 0x0524,
+ 0x7841, 0x3fd3,
+ 0x7843, 0x26a8,
+ 0x7844, 0x3fd5,
+ 0x7845, 0x0741,
+ 0x7846, 0x3fd6,
+ 0x7847, 0x1a3c,
+ 0x7848, 0x3fd7,
+ 0x784c, 0x1a3d,
+ 0x784d, 0x3fdb,
+ 0x784e, 0x1a36,
+ 0x784f, 0x3fdc,
+ 0x7850, 0x1a3b,
+ 0x7851, 0x3fdd,
+ 0x7852, 0x0f07,
+ 0x7853, 0x3fde,
+ 0x7855, 0x0dab,
+ 0x7856, 0x1a38,
+ 0x7858, 0x3fe0,
+ 0x785d, 0x0f62,
+ 0x785e, 0x3fe5,
+ 0x7864, 0x24e9,
+ 0x7865, 0x3feb,
+ 0x7868, 0x24e5,
+ 0x7869, 0x3fee,
+ 0x786a, 0x1a3e,
+ 0x786b, 0x0a3b,
+ 0x786c, 0x1097,
+ 0x786d, 0x1a37,
+ 0x786e, 0x0c92,
+ 0x786f, 0x21fa,
+ 0x7870, 0x3fef,
+ 0x7877, 0x0862,
+ 0x7878, 0x3ff6,
+ 0x787c, 0x0bb1,
+ 0x787d, 0x3ffa,
+ 0x7887, 0x1a42,
+ 0x7888, 0x4004,
+ 0x7889, 0x05d0,
+ 0x788a, 0x4005,
+ 0x788c, 0x0a5c,
+ 0x788d, 0x03b8,
+ 0x788e, 0x0dde,
+ 0x788f, 0x4007,
+ 0x7891, 0x0417,
+ 0x7892, 0x4009,
+ 0x7893, 0x1a40,
+ 0x7894, 0x400a,
+ 0x7897, 0x0e9c,
+ 0x7898, 0x05c3,
+ 0x7899, 0x400d,
+ 0x789a, 0x1a41,
+ 0x789b, 0x1a3f,
+ 0x789c, 0x1a43,
+ 0x789d, 0x400e,
+ 0x789f, 0x05db,
+ 0x78a0, 0x4010,
+ 0x78a1, 0x1a44,
+ 0x78a2, 0x4011,
+ 0x78a3, 0x1a45,
+ 0x78a4, 0x4012,
+ 0x78a5, 0x1a48,
+ 0x78a6, 0x4013,
+ 0x78a7, 0x0435,
+ 0x78a8, 0x4014,
+ 0x78a9, 0x2148,
+ 0x78aa, 0x4015,
+ 0x78ad, 0x24e4,
+ 0x78ae, 0x4018,
+ 0x78b0, 0x0bb7,
+ 0x78b1, 0x0861,
+ 0x78b2, 0x1a46,
+ 0x78b3, 0x0e0f,
+ 0x78b4, 0x04b1,
+ 0x78b5, 0x401a,
+ 0x78b8, 0x24e6,
+ 0x78b9, 0x1a47,
+ 0x78ba, 0x20f7,
+ 0x78bb, 0x401d,
+ 0x78bc, 0x206b,
+ 0x78bd, 0x401e,
+ 0x78be, 0x0b4e,
+ 0x78bf, 0x401f,
+ 0x78c1, 0x0548,
+ 0x78c2, 0x4021,
+ 0x78c5, 0x0400,
+ 0x78c6, 0x4024,
+ 0x78c9, 0x1a4b,
+ 0x78ca, 0x09c5,
+ 0x78cb, 0x056b,
+ 0x78cc, 0x4027,
+ 0x78d0, 0x0b8e,
+ 0x78d1, 0x402b,
+ 0x78d4, 0x1a49,
+ 0x78d5, 0x0951,
+ 0x78d6, 0x402e,
+ 0x78d9, 0x1a4a,
+ 0x78da, 0x22a7,
+ 0x78db, 0x4031,
+ 0x78e3, 0x24ec,
+ 0x78e4, 0x4039,
+ 0x78e7, 0x24eb,
+ 0x78e8, 0x0b08,
+ 0x78e9, 0x403c,
+ 0x78ec, 0x1a4c,
+ 0x78ed, 0x403f,
+ 0x78ef, 0x24e3,
+ 0x78f0, 0x4041,
+ 0x78f2, 0x1a4d,
+ 0x78f3, 0x4043,
+ 0x78f4, 0x1a4f,
+ 0x78f5, 0x4044,
+ 0x78f7, 0x0a20,
+ 0x78f8, 0x4046,
+ 0x78fa, 0x07dc,
+ 0x78fb, 0x4048,
+ 0x78fd, 0x24ea,
+ 0x78fe, 0x404a,
+ 0x7900, 0x404c,
+ 0x7901, 0x0889,
+ 0x7902, 0x404d,
+ 0x7905, 0x1a4e,
+ 0x7906, 0x4050,
+ 0x790e, 0x1e92,
+ 0x790f, 0x4058,
+ 0x7913, 0x1a50,
+ 0x7914, 0x405c,
+ 0x7919, 0x1e27,
+ 0x791a, 0x4061,
+ 0x791e, 0x1a52,
+ 0x791f, 0x4065,
+ 0x7924, 0x1a51,
+ 0x7925, 0x406a,
+ 0x7926, 0x1fe6,
+ 0x7927, 0x406b,
+ 0x792a, 0x24e7,
+ 0x792b, 0x2012,
+ 0x792c, 0x1eec,
+ 0x792d, 0x406e,
+ 0x7931, 0x24e8,
+ 0x7932, 0x4072,
+ 0x7934, 0x1a53,
+ 0x7935, 0x4074,
+ 0x793a, 0x0d55,
+ 0x793b, 0x19f8,
+ 0x793c, 0x09dc,
+ 0x793d, 0x4079,
+ 0x793e, 0x0d20,
+ 0x793f, 0x407a,
+ 0x7940, 0x19f9,
+ 0x7941, 0x0c0d,
+ 0x7942, 0x407b,
+ 0x7946, 0x19fa,
+ 0x7947, 0x407f,
+ 0x7948, 0x0c0c,
+ 0x7949, 0x19fb,
+ 0x794a, 0x4080,
+ 0x7953, 0x19fe,
+ 0x7954, 0x4089,
+ 0x7956, 0x1243,
+ 0x7957, 0x1a01,
+ 0x7958, 0x408b,
+ 0x795a, 0x19ff,
+ 0x795b, 0x19fc,
+ 0x795d, 0x1200,
+ 0x795e, 0x0d2a,
+ 0x795f, 0x0de3,
+ 0x7960, 0x1a02,
+ 0x7961, 0x408d,
+ 0x7962, 0x1a00,
+ 0x7963, 0x408e,
+ 0x7965, 0x0f56,
+ 0x7966, 0x4090,
+ 0x7967, 0x1a04,
+ 0x7968, 0x0bd0,
+ 0x7969, 0x4091,
+ 0x796d, 0x0833,
+ 0x796e, 0x4095,
+ 0x796f, 0x1a03,
+ 0x7970, 0x4096,
+ 0x7977, 0x059c,
+ 0x7978, 0x080b,
+ 0x7979, 0x409d,
+ 0x797a, 0x1a05,
+ 0x797b, 0x409e,
+ 0x7980, 0x130b,
+ 0x7981, 0x08cc,
+ 0x7982, 0x40a3,
+ 0x7984, 0x0a62,
+ 0x7985, 0x1a06,
+ 0x7986, 0x40a5,
+ 0x798a, 0x1a07,
+ 0x798b, 0x40a9,
+ 0x798d, 0x1f66,
+ 0x798e, 0x24dc,
+ 0x798f, 0x069e,
+ 0x7990, 0x40ab,
+ 0x799a, 0x1a08,
+ 0x799b, 0x40b5,
+ 0x79a6, 0x26a2,
+ 0x79a7, 0x1a09,
+ 0x79a8, 0x40c0,
+ 0x79aa, 0x24dd,
+ 0x79ab, 0x40c2,
+ 0x79ae, 0x200e,
+ 0x79af, 0x40c5,
+ 0x79b0, 0x24db,
+ 0x79b1, 0x1eb8,
+ 0x79b2, 0x40c6,
+ 0x79b3, 0x1a0a,
+ 0x79b4, 0x40c7,
+ 0x79b9, 0x10d2,
+ 0x79ba, 0x1264,
+ 0x79bb, 0x09d6,
+ 0x79bc, 0x40cc,
+ 0x79bd, 0x0c5a,
+ 0x79be, 0x0783,
+ 0x79bf, 0x40cd,
+ 0x79c0, 0x0fae,
+ 0x79c1, 0x0db2,
+ 0x79c2, 0x40ce,
+ 0x79c3, 0x0e6b,
+ 0x79c4, 0x40cf,
+ 0x79c6, 0x06cc,
+ 0x79c7, 0x40d1,
+ 0x79c9, 0x0465,
+ 0x79ca, 0x40d3,
+ 0x79cb, 0x0c6c,
+ 0x79cc, 0x40d4,
+ 0x79cd, 0x11d5,
+ 0x79ce, 0x40d5,
+ 0x79d1, 0x0953,
+ 0x79d2, 0x0af0,
+ 0x79d3, 0x40d8,
+ 0x79d5, 0x1b1d,
+ 0x79d6, 0x40da,
+ 0x79d8, 0x0add,
+ 0x79d9, 0x40dc,
+ 0x79df, 0x123f,
+ 0x79e0, 0x40e2,
+ 0x79e3, 0x1b1f,
+ 0x79e4, 0x04f8,
+ 0x79e5, 0x40e5,
+ 0x79e6, 0x0c55,
+ 0x79e7, 0x1016,
+ 0x79e8, 0x40e6,
+ 0x79e9, 0x11c7,
+ 0x79ea, 0x40e7,
+ 0x79eb, 0x1b20,
+ 0x79ec, 0x40e8,
+ 0x79ed, 0x1b1e,
+ 0x79ee, 0x40e9,
+ 0x79ef, 0x0812,
+ 0x79f0, 0x04eb,
+ 0x79f1, 0x40ea,
+ 0x79f8, 0x08a6,
+ 0x79f9, 0x40f1,
+ 0x79fb, 0x104d,
+ 0x79fc, 0x40f3,
+ 0x79fd, 0x07f5,
+ 0x79fe, 0x40f4,
+ 0x7a00, 0x0f0e,
+ 0x7a01, 0x40f6,
+ 0x7a02, 0x1b24,
+ 0x7a03, 0x1b23,
+ 0x7a04, 0x40f7,
+ 0x7a06, 0x1b21,
+ 0x7a07, 0x40f9,
+ 0x7a0b, 0x04f1,
+ 0x7a0c, 0x40fd,
+ 0x7a0d, 0x0d0d,
+ 0x7a0e, 0x0da5,
+ 0x7a0f, 0x40fe,
+ 0x7a14, 0x1b26,
+ 0x7a15, 0x4103,
+ 0x7a17, 0x03e9,
+ 0x7a18, 0x4105,
+ 0x7a1a, 0x11c8,
+ 0x7a1b, 0x4107,
+ 0x7a1e, 0x1b25,
+ 0x7a1f, 0x410a,
+ 0x7a20, 0x0512,
+ 0x7a21, 0x410b,
+ 0x7a23, 0x1d8f,
+ 0x7a24, 0x410d,
+ 0x7a2e, 0x2295,
+ 0x7a2f, 0x4117,
+ 0x7a31, 0x1e80,
+ 0x7a32, 0x4119,
+ 0x7a33, 0x0ed7,
+ 0x7a34, 0x411a,
+ 0x7a37, 0x1b28,
+ 0x7a38, 0x411d,
+ 0x7a39, 0x1b27,
+ 0x7a3a, 0x411e,
+ 0x7a3b, 0x059f,
+ 0x7a3c, 0x084d,
+ 0x7a3d, 0x0811,
+ 0x7a3e, 0x411f,
+ 0x7a3f, 0x06e0,
+ 0x7a40, 0x2677,
+ 0x7a41, 0x4120,
+ 0x7a46, 0x0b25,
+ 0x7a47, 0x4125,
+ 0x7a4c, 0x2624,
+ 0x7a4d, 0x1f69,
+ 0x7a4e, 0x222b,
+ 0x7a4f, 0x412a,
+ 0x7a51, 0x1b29,
+ 0x7a52, 0x412c,
+ 0x7a57, 0x0de0,
+ 0x7a58, 0x4131,
+ 0x7a61, 0x257f,
+ 0x7a62, 0x1f5b,
+ 0x7a63, 0x413a,
+ 0x7a69, 0x219b,
+ 0x7a6a, 0x4140,
+ 0x7a6b, 0x267d,
+ 0x7a6c, 0x4141,
+ 0x7a70, 0x1b2c,
+ 0x7a71, 0x4145,
+ 0x7a74, 0x0fd1,
+ 0x7a75, 0x4148,
+ 0x7a76, 0x08ee,
+ 0x7a77, 0x0c6b,
+ 0x7a78, 0x1b9a,
+ 0x7a7a, 0x0962,
+ 0x7a7b, 0x4149,
+ 0x7a7f, 0x052c,
+ 0x7a80, 0x1b9c,
+ 0x7a81, 0x0e6c,
+ 0x7a82, 0x414d,
+ 0x7a83, 0x0c51,
+ 0x7a84, 0x114e,
+ 0x7a85, 0x414e,
+ 0x7a86, 0x1b9d,
+ 0x7a87, 0x414f,
+ 0x7a88, 0x1b9e,
+ 0x7a89, 0x4150,
+ 0x7a8d, 0x0c4c,
+ 0x7a8e, 0x4154,
+ 0x7a91, 0x102b,
+ 0x7a92, 0x11ce,
+ 0x7a93, 0x4157,
+ 0x7a95, 0x1b9f,
+ 0x7a96, 0x08a2,
+ 0x7a97, 0x0533,
+ 0x7a98, 0x08ec,
+ 0x7a99, 0x4159,
+ 0x7a9c, 0x055f,
+ 0x7a9d, 0x0ee0,
+ 0x7a9e, 0x415c,
+ 0x7a9f, 0x096c,
+ 0x7aa0, 0x1ba1,
+ 0x7aa1, 0x415d,
+ 0x7aa5, 0x0987,
+ 0x7aa6, 0x1ba0,
+ 0x7aa7, 0x4161,
+ 0x7aa8, 0x1ba3,
+ 0x7aa9, 0x21a0,
+ 0x7aaa, 0x2186,
+ 0x7aab, 0x4162,
+ 0x7aac, 0x1ba2,
+ 0x7aad, 0x1ba4,
+ 0x7aae, 0x20ed,
+ 0x7aaf, 0x4163,
+ 0x7ab3, 0x1ba5,
+ 0x7ab4, 0x4167,
+ 0x7ab6, 0x25b9,
+ 0x7ab7, 0x4169,
+ 0x7aba, 0x1fea,
+ 0x7abb, 0x416c,
+ 0x7abf, 0x0a47,
+ 0x7ac0, 0x4170,
+ 0x7ac4, 0x1ea4,
+ 0x7ac5, 0x20e1,
+ 0x7ac6, 0x4174,
+ 0x7ac7, 0x25b8,
+ 0x7ac8, 0x2260,
+ 0x7ac9, 0x4175,
+ 0x7aca, 0x20e2,
+ 0x7acb, 0x09eb,
+ 0x7acc, 0x4176,
+ 0x7ad6, 0x0d91,
+ 0x7ad7, 0x4180,
+ 0x7ad9, 0x115f,
+ 0x7ada, 0x4182,
+ 0x7ade, 0x08e9,
+ 0x7adf, 0x08e8,
+ 0x7ae0, 0x1163,
+ 0x7ae1, 0x4186,
+ 0x7ae3, 0x092f,
+ 0x7ae4, 0x4188,
+ 0x7ae5, 0x0e60,
+ 0x7ae6, 0x1b99,
+ 0x7ae7, 0x4189,
+ 0x7aea, 0x2141,
+ 0x7aeb, 0x418c,
+ 0x7aed, 0x08b0,
+ 0x7aee, 0x418e,
+ 0x7aef, 0x060a,
+ 0x7af0, 0x418f,
+ 0x7af6, 0x1fc7,
+ 0x7af7, 0x4195,
+ 0x7af9, 0x11f0,
+ 0x7afa, 0x1c63,
+ 0x7afb, 0x4197,
+ 0x7afd, 0x1c64,
+ 0x7afe, 0x4199,
+ 0x7aff, 0x06c8,
+ 0x7b00, 0x419a,
+ 0x7b03, 0x1c66,
+ 0x7b05, 0x419d,
+ 0x7b06, 0x03d5,
+ 0x7b07, 0x419e,
+ 0x7b08, 0x1c65,
+ 0x7b09, 0x419f,
+ 0x7b0a, 0x1c69,
+ 0x7b0b, 0x0de6,
+ 0x7b0c, 0x41a0,
+ 0x7b0f, 0x1c6b,
+ 0x7b10, 0x41a3,
+ 0x7b11, 0x0f71,
+ 0x7b12, 0x41a4,
+ 0x7b14, 0x0433,
+ 0x7b15, 0x1c68,
+ 0x7b16, 0x41a6,
+ 0x7b19, 0x1c6f,
+ 0x7b1a, 0x41a9,
+ 0x7b1b, 0x05b2,
+ 0x7b1c, 0x41aa,
+ 0x7b1e, 0x1c77,
+ 0x7b1f, 0x41ac,
+ 0x7b20, 0x1c72,
+ 0x7b21, 0x41ad,
+ 0x7b24, 0x1c74,
+ 0x7b25, 0x1c73,
+ 0x7b26, 0x0698,
+ 0x7b27, 0x41b0,
+ 0x7b28, 0x0428,
+ 0x7b29, 0x41b1,
+ 0x7b2a, 0x1c6e,
+ 0x7b2b, 0x1c6a,
+ 0x7b2c, 0x05bb,
+ 0x7b2d, 0x41b2,
+ 0x7b2e, 0x1c70,
+ 0x7b2f, 0x41b3,
+ 0x7b31, 0x1c71,
+ 0x7b32, 0x41b5,
+ 0x7b33, 0x1c75,
+ 0x7b34, 0x41b6,
+ 0x7b38, 0x1c6d,
+ 0x7b39, 0x41ba,
+ 0x7b3a, 0x0856,
+ 0x7b3b, 0x41bb,
+ 0x7b3c, 0x0a46,
+ 0x7b3d, 0x41bc,
+ 0x7b3e, 0x1c76,
+ 0x7b3f, 0x41bd,
+ 0x7b45, 0x1c7a,
+ 0x7b46, 0x1e41,
+ 0x7b47, 0x1c6c,
+ 0x7b48, 0x41c3,
+ 0x7b49, 0x05a9,
+ 0x7b4a, 0x41c4,
+ 0x7b4b, 0x08bf,
+ 0x7b4c, 0x1c7c,
+ 0x7b4d, 0x41c5,
+ 0x7b4f, 0x0641,
+ 0x7b50, 0x097d,
+ 0x7b51, 0x11fd,
+ 0x7b52, 0x0e63,
+ 0x7b53, 0x41c7,
+ 0x7b54, 0x0573,
+ 0x7b55, 0x41c8,
+ 0x7b56, 0x04a6,
+ 0x7b57, 0x41c9,
+ 0x7b58, 0x1c78,
+ 0x7b59, 0x41ca,
+ 0x7b5a, 0x1c79,
+ 0x7b5b, 0x0cf1,
+ 0x7b5c, 0x41cb,
+ 0x7b5d, 0x1c7d,
+ 0x7b5e, 0x41cc,
+ 0x7b60, 0x1c7e,
+ 0x7b61, 0x41ce,
+ 0x7b62, 0x1c81,
+ 0x7b63, 0x41cf,
+ 0x7b67, 0x25e4,
+ 0x7b68, 0x41d3,
+ 0x7b6e, 0x1c7f,
+ 0x7b6f, 0x41d9,
+ 0x7b71, 0x1c83,
+ 0x7b72, 0x1c82,
+ 0x7b73, 0x41db,
+ 0x7b75, 0x1c7b,
+ 0x7b76, 0x41dd,
+ 0x7b77, 0x0977,
+ 0x7b78, 0x41de,
+ 0x7b79, 0x0514,
+ 0x7b7a, 0x41df,
+ 0x7b7b, 0x1c80,
+ 0x7b7c, 0x41e0,
+ 0x7b7e, 0x0c26,
+ 0x7b7f, 0x41e2,
+ 0x7b80, 0x0865,
+ 0x7b81, 0x41e3,
+ 0x7b85, 0x1c8b,
+ 0x7b86, 0x41e7,
+ 0x7b8b, 0x1f86,
+ 0x7b8c, 0x41ec,
+ 0x7b8d, 0x0718,
+ 0x7b8e, 0x41ed,
+ 0x7b90, 0x1c84,
+ 0x7b91, 0x41ef,
+ 0x7b94, 0x0474,
+ 0x7b95, 0x0813,
+ 0x7b96, 0x41f2,
+ 0x7b97, 0x0dd8,
+ 0x7b98, 0x41f3,
+ 0x7b9c, 0x1c8d,
+ 0x7b9d, 0x1c89,
+ 0x7b9e, 0x41f7,
+ 0x7ba1, 0x0735,
+ 0x7ba2, 0x1c8e,
+ 0x7ba3, 0x41fa,
+ 0x7ba6, 0x1c85,
+ 0x7ba8, 0x1c8a,
+ 0x7ba9, 0x0a88,
+ 0x7baa, 0x1c8c,
+ 0x7bab, 0x1c8f,
+ 0x7bac, 0x1c88,
+ 0x7bad, 0x0870,
+ 0x7bae, 0x41fd,
+ 0x7bb1, 0x0f51,
+ 0x7bb2, 0x4200,
+ 0x7bb4, 0x1c90,
+ 0x7bb5, 0x4202,
+ 0x7bb8, 0x1c87,
+ 0x7bb9, 0x4205,
+ 0x7bc0, 0x1fb3,
+ 0x7bc1, 0x1c92,
+ 0x7bc2, 0x420c,
+ 0x7bc4, 0x1eef,
+ 0x7bc5, 0x420e,
+ 0x7bc6, 0x120a,
+ 0x7bc7, 0x0bc9,
+ 0x7bc8, 0x420f,
+ 0x7bc9, 0x22a4,
+ 0x7bca, 0x4210,
+ 0x7bcb, 0x25e8,
+ 0x7bcc, 0x1c93,
+ 0x7bcd, 0x4211,
+ 0x7bd1, 0x1c91,
+ 0x7bd2, 0x4215,
+ 0x7bd3, 0x0a4f,
+ 0x7bd4, 0x4216,
+ 0x7bd9, 0x06d8,
+ 0x7bda, 0x1c95,
+ 0x7bdb, 0x421b,
+ 0x7bdd, 0x1c94,
+ 0x7bde, 0x421d,
+ 0x7be1, 0x055e,
+ 0x7be2, 0x4220,
+ 0x7be4, 0x25e3,
+ 0x7be5, 0x1c96,
+ 0x7be7, 0x4222,
+ 0x7be9, 0x2111,
+ 0x7bea, 0x1c98,
+ 0x7beb, 0x4224,
+ 0x7bee, 0x09a5,
+ 0x7bef, 0x4227,
+ 0x7bf1, 0x09d4,
+ 0x7bf2, 0x4229,
+ 0x7bf3, 0x25e6,
+ 0x7bf4, 0x422a,
+ 0x7bf7, 0x0bb2,
+ 0x7bf8, 0x422d,
+ 0x7bfc, 0x1c9b,
+ 0x7bfd, 0x4231,
+ 0x7bfe, 0x1c9a,
+ 0x7bff, 0x4232,
+ 0x7c00, 0x25e7,
+ 0x7c01, 0x4233,
+ 0x7c07, 0x055b,
+ 0x7c08, 0x4239,
+ 0x7c0b, 0x1c9e,
+ 0x7c0c, 0x1c99,
+ 0x7c0d, 0x2041,
+ 0x7c0e, 0x423c,
+ 0x7c0f, 0x1c9c,
+ 0x7c10, 0x423d,
+ 0x7c16, 0x1c9d,
+ 0x7c17, 0x4243,
+ 0x7c1e, 0x25ea,
+ 0x7c1f, 0x1c9f,
+ 0x7c20, 0x424a,
+ 0x7c21, 0x1f8f,
+ 0x7c22, 0x424b,
+ 0x7c23, 0x25ec,
+ 0x7c24, 0x424c,
+ 0x7c26, 0x1ca1,
+ 0x7c27, 0x07de,
+ 0x7c28, 0x424e,
+ 0x7c2a, 0x1ca0,
+ 0x7c2b, 0x25eb,
+ 0x7c2c, 0x4250,
+ 0x7c38, 0x1ca2,
+ 0x7c39, 0x425c,
+ 0x7c3d, 0x20d0,
+ 0x7c3e, 0x201d,
+ 0x7c3f, 0x0485,
+ 0x7c40, 0x1ca4,
+ 0x7c41, 0x1ca3,
+ 0x7c42, 0x4260,
+ 0x7c43, 0x1ff7,
+ 0x7c44, 0x4261,
+ 0x7c4c, 0x1e8d,
+ 0x7c4d, 0x0821,
+ 0x7c4e, 0x4269,
+ 0x7c5c, 0x25e9,
+ 0x7c5d, 0x4277,
+ 0x7c5f, 0x25ee,
+ 0x7c60, 0x203a,
+ 0x7c61, 0x4279,
+ 0x7c64, 0x2693,
+ 0x7c65, 0x427c,
+ 0x7c69, 0x25e5,
+ 0x7c6a, 0x25ed,
+ 0x7c6b, 0x4280,
+ 0x7c6c, 0x2009,
+ 0x7c6d, 0x4281,
+ 0x7c6e, 0x2065,
+ 0x7c6f, 0x4282,
+ 0x7c72, 0x26a3,
+ 0x7c73, 0x0adc,
+ 0x7c74, 0x12f5,
+ 0x7c75, 0x4285,
+ 0x7c7b, 0x09cb,
+ 0x7c7c, 0x1cca,
+ 0x7c7d, 0x122e,
+ 0x7c7e, 0x428b,
+ 0x7c89, 0x0678,
+ 0x7c8a, 0x4296,
+ 0x7c91, 0x1ccc,
+ 0x7c92, 0x09ec,
+ 0x7c93, 0x429d,
+ 0x7c95, 0x0be8,
+ 0x7c96, 0x429f,
+ 0x7c97, 0x0559,
+ 0x7c98, 0x1154,
+ 0x7c99, 0x42a0,
+ 0x7c9c, 0x1cce,
+ 0x7c9d, 0x1ccd,
+ 0x7c9e, 0x1ccf,
+ 0x7c9f, 0x0dcf,
+ 0x7ca0, 0x42a3,
+ 0x7ca2, 0x1cd0,
+ 0x7ca3, 0x42a5,
+ 0x7ca4, 0x1104,
+ 0x7ca5, 0x11df,
+ 0x7ca6, 0x42a6,
+ 0x7caa, 0x067d,
+ 0x7cab, 0x42aa,
+ 0x7cae, 0x0a01,
+ 0x7caf, 0x42ad,
+ 0x7cb1, 0x0a04,
+ 0x7cb2, 0x1cd1,
+ 0x7cb3, 0x08db,
+ 0x7cb4, 0x42af,
+ 0x7cb9, 0x0565,
+ 0x7cba, 0x42b4,
+ 0x7cbc, 0x1cd2,
+ 0x7cbe, 0x08da,
+ 0x7cbf, 0x42b6,
+ 0x7cc1, 0x1cd4,
+ 0x7cc2, 0x42b8,
+ 0x7cc5, 0x1cd9,
+ 0x7cc6, 0x42bb,
+ 0x7cc7, 0x1cd5,
+ 0x7cc8, 0x1cd8,
+ 0x7cc9, 0x42bc,
+ 0x7cca, 0x07b4,
+ 0x7ccb, 0x42bd,
+ 0x7ccc, 0x1cd6,
+ 0x7cce, 0x42be,
+ 0x7cd5, 0x06dd,
+ 0x7cd6, 0x0e1a,
+ 0x7cd7, 0x1cda,
+ 0x7cd8, 0x42c5,
+ 0x7cd9, 0x04a1,
+ 0x7cda, 0x42c6,
+ 0x7cdc, 0x0ad8,
+ 0x7cdd, 0x25f5,
+ 0x7cde, 0x1efc,
+ 0x7cdf, 0x1126,
+ 0x7ce0, 0x0944,
+ 0x7ce1, 0x42c8,
+ 0x7ce7, 0x2024,
+ 0x7ce8, 0x1cdb,
+ 0x7ce9, 0x42ce,
+ 0x7cef, 0x0b75,
+ 0x7cf0, 0x269b,
+ 0x7cf1, 0x42d4,
+ 0x7cf2, 0x25f3,
+ 0x7cf3, 0x42d5,
+ 0x7cf4, 0x22d9,
+ 0x7cf5, 0x42d6,
+ 0x7cf6, 0x25f4,
+ 0x7cf7, 0x42d7,
+ 0x7cf8, 0x1ce7,
+ 0x7cf9, 0x241b,
+ 0x7cfa, 0x42d8,
+ 0x7cfb, 0x0f22,
+ 0x7cfc, 0x42d9,
+ 0x7cfe, 0x1fc8,
+ 0x7cff, 0x42db,
+ 0x7d00, 0x1f7b,
+ 0x7d01, 0x42dc,
+ 0x7d02, 0x241d,
+ 0x7d03, 0x42dd,
+ 0x7d04, 0x224c,
+ 0x7d05, 0x1f48,
+ 0x7d06, 0x241c,
+ 0x7d07, 0x241e,
+ 0x7d09, 0x20ff,
+ 0x7d0a, 0x0ed8,
+ 0x7d0b, 0x219a,
+ 0x7d0c, 0x42de,
+ 0x7d0d, 0x2091,
+ 0x7d0e, 0x42df,
+ 0x7d10, 0x20a7,
+ 0x7d11, 0x42e1,
+ 0x7d13, 0x2423,
+ 0x7d14, 0x1e9b,
+ 0x7d15, 0x2422,
+ 0x7d16, 0x42e3,
+ 0x7d17, 0x2110,
+ 0x7d18, 0x42e4,
+ 0x7d19, 0x228d,
+ 0x7d1a, 0x1f71,
+ 0x7d1b, 0x1ef8,
+ 0x7d1c, 0x2421,
+ 0x7d1d, 0x42e5,
+ 0x7d20, 0x0dcd,
+ 0x7d21, 0x1ef3,
+ 0x7d22, 0x0dec,
+ 0x7d23, 0x42e8,
+ 0x7d27, 0x08c5,
+ 0x7d28, 0x42ec,
+ 0x7d2b, 0x122c,
+ 0x7d2c, 0x42ef,
+ 0x7d2f, 0x09c6,
+ 0x7d30, 0x21b1,
+ 0x7d31, 0x2426,
+ 0x7d32, 0x2425,
+ 0x7d33, 0x2120,
+ 0x7d34, 0x42f2,
+ 0x7d39, 0x211a,
+ 0x7d3a, 0x2424,
+ 0x7d3b, 0x42f7,
+ 0x7d3c, 0x2428,
+ 0x7d3d, 0x42f8,
+ 0x7d3f, 0x242a,
+ 0x7d40, 0x2429,
+ 0x7d41, 0x42fa,
+ 0x7d42, 0x2294,
+ 0x7d43, 0x42fb,
+ 0x7d44, 0x22be,
+ 0x7d45, 0x42fc,
+ 0x7d46, 0x1e31,
+ 0x7d47, 0x42fd,
+ 0x7d4e, 0x242c,
+ 0x7d4f, 0x4304,
+ 0x7d50, 0x1fb5,
+ 0x7d51, 0x4305,
+ 0x7d5d, 0x242b,
+ 0x7d5e, 0x1faf,
+ 0x7d5f, 0x4311,
+ 0x7d61, 0x2068,
+ 0x7d62, 0x21e4,
+ 0x7d63, 0x4313,
+ 0x7d66, 0x1f21,
+ 0x7d67, 0x4316,
+ 0x7d68, 0x2101,
+ 0x7d69, 0x4317,
+ 0x7d6e, 0x0fc0,
+ 0x7d6f, 0x431c,
+ 0x7d71, 0x217c,
+ 0x7d72, 0x214a,
+ 0x7d73, 0x242d,
+ 0x7d74, 0x431e,
+ 0x7d76, 0x1fd4,
+ 0x7d77, 0x1ce8,
+ 0x7d78, 0x4320,
+ 0x7d79, 0x1fd1,
+ 0x7d7a, 0x4321,
+ 0x7d81, 0x1e33,
+ 0x7d82, 0x4328,
+ 0x7d83, 0x242f,
+ 0x7d84, 0x4329,
+ 0x7d86, 0x242e,
+ 0x7d87, 0x432b,
+ 0x7d88, 0x2430,
+ 0x7d89, 0x21db,
+ 0x7d8a, 0x432c,
+ 0x7d8f, 0x2158,
+ 0x7d90, 0x4331,
+ 0x7d93, 0x1fc2,
+ 0x7d94, 0x4334,
+ 0x7d9c, 0x22b9,
+ 0x7d9d, 0x433c,
+ 0x7d9e, 0x2436,
+ 0x7d9f, 0x433d,
+ 0x7da2, 0x1e8e,
+ 0x7da3, 0x2439,
+ 0x7da4, 0x4340,
+ 0x7da6, 0x1ce9,
+ 0x7da7, 0x4342,
+ 0x7dab, 0x21c5,
+ 0x7dac, 0x2437,
+ 0x7dad, 0x2192,
+ 0x7dae, 0x1cea,
+ 0x7daf, 0x4346,
+ 0x7db0, 0x243a,
+ 0x7db1, 0x1f19,
+ 0x7db2, 0x218c,
+ 0x7db3, 0x1e40,
+ 0x7db4, 0x22b3,
+ 0x7db5, 0x4347,
+ 0x7db8, 0x205f,
+ 0x7db9, 0x2438,
+ 0x7dba, 0x2432,
+ 0x7dbb, 0x2274,
+ 0x7dbc, 0x434a,
+ 0x7dbd, 0x1e9c,
+ 0x7dbe, 0x2431,
+ 0x7dbf, 0x2085,
+ 0x7dc0, 0x434b,
+ 0x7dc4, 0x2435,
+ 0x7dc5, 0x434f,
+ 0x7dc7, 0x243b,
+ 0x7dc8, 0x4351,
+ 0x7dca, 0x1fb7,
+ 0x7dcb, 0x2433,
+ 0x7dcc, 0x4353,
+ 0x7dd1, 0x2054,
+ 0x7dd2, 0x21de,
+ 0x7dd3, 0x4358,
+ 0x7dd4, 0x2434,
+ 0x7dd5, 0x4359,
+ 0x7dd7, 0x243d,
+ 0x7dd8, 0x1f89,
+ 0x7dd9, 0x243c,
+ 0x7dda, 0x435b,
+ 0x7ddd, 0x1f6e,
+ 0x7dde, 0x1ed8,
+ 0x7ddf, 0x435e,
+ 0x7de0, 0x1ebf,
+ 0x7de1, 0x2445,
+ 0x7de2, 0x435f,
+ 0x7de3, 0x2249,
+ 0x7de4, 0x4360,
+ 0x7de6, 0x2441,
+ 0x7de7, 0x4362,
+ 0x7de8, 0x1e47,
+ 0x7de9, 0x1f56,
+ 0x7dea, 0x4363,
+ 0x7dec, 0x2086,
+ 0x7ded, 0x4365,
+ 0x7def, 0x2196,
+ 0x7df0, 0x4367,
+ 0x7df1, 0x2443,
+ 0x7df2, 0x243f,
+ 0x7df3, 0x4368,
+ 0x7df4, 0x2023,
+ 0x7df5, 0x4369,
+ 0x7df6, 0x2442,
+ 0x7df7, 0x436a,
+ 0x7df9, 0x243e,
+ 0x7dfa, 0x436c,
+ 0x7dfb, 0x26a6,
+ 0x7dfc, 0x436d,
+ 0x7e00, 0x4371,
+ 0x7e08, 0x234e,
+ 0x7e09, 0x2446,
+ 0x7e0a, 0x244b,
+ 0x7e0b, 0x2444,
+ 0x7e0c, 0x4379,
+ 0x7e10, 0x2427,
+ 0x7e11, 0x244c,
+ 0x7e12, 0x437d,
+ 0x7e1b, 0x1f0f,
+ 0x7e1c, 0x4386,
+ 0x7e1d, 0x2447,
+ 0x7e1e, 0x2449,
+ 0x7e1f, 0x2448,
+ 0x7e20, 0x4387,
+ 0x7e23, 0x21c2,
+ 0x7e24, 0x438a,
+ 0x7e27, 0x216e,
+ 0x7e28, 0x438d,
+ 0x7e2b, 0x1f03,
+ 0x7e2c, 0x4390,
+ 0x7e2d, 0x244a,
+ 0x7e2e, 0x215c,
+ 0x7e2f, 0x4391,
+ 0x7e31, 0x22bb,
+ 0x7e32, 0x2450,
+ 0x7e33, 0x4393,
+ 0x7e34, 0x2694,
+ 0x7e35, 0x244f,
+ 0x7e36, 0x25f6,
+ 0x7e37, 0x2051,
+ 0x7e38, 0x4394,
+ 0x7e39, 0x244e,
+ 0x7e3a, 0x4395,
+ 0x7e3b, 0x1dfb,
+ 0x7e3c, 0x4396,
+ 0x7e3d, 0x22ba,
+ 0x7e3e, 0x1f6d,
+ 0x7e3f, 0x4397,
+ 0x7e41, 0x064e,
+ 0x7e42, 0x4399,
+ 0x7e45, 0x2452,
+ 0x7e46, 0x2451,
+ 0x7e47, 0x1ceb,
+ 0x7e48, 0x439c,
+ 0x7e52, 0x2455,
+ 0x7e53, 0x43a6,
+ 0x7e54, 0x2289,
+ 0x7e55, 0x2116,
+ 0x7e56, 0x43a7,
+ 0x7e5a, 0x2454,
+ 0x7e5b, 0x43ab,
+ 0x7e5e, 0x20fb,
+ 0x7e5f, 0x43ae,
+ 0x7e62, 0x2440,
+ 0x7e63, 0x43b1,
+ 0x7e69, 0x2126,
+ 0x7e6a, 0x1f61,
+ 0x7e6b, 0x269d,
+ 0x7e6c, 0x43b7,
+ 0x7e6d, 0x1f8a,
+ 0x7e6e, 0x2456,
+ 0x7e6f, 0x2459,
+ 0x7e70, 0x2458,
+ 0x7e71, 0x43b8,
+ 0x7e73, 0x1fae,
+ 0x7e74, 0x43ba,
+ 0x7e79, 0x221a,
+ 0x7e7a, 0x43bf,
+ 0x7e7c, 0x1f7a,
+ 0x7e7d, 0x244d,
+ 0x7e7e, 0x2457,
+ 0x7e7f, 0x43c1,
+ 0x7e82, 0x1248,
+ 0x7e83, 0x43c4,
+ 0x7e88, 0x2453,
+ 0x7e89, 0x43c9,
+ 0x7e8a, 0x2420,
+ 0x7e8b, 0x43ca,
+ 0x7e8c, 0x21df,
+ 0x7e8d, 0x2685,
+ 0x7e8e, 0x43cb,
+ 0x7e8f, 0x1e6e,
+ 0x7e90, 0x43cc,
+ 0x7e93, 0x2224,
+ 0x7e94, 0x2670,
+ 0x7e95, 0x43cf,
+ 0x7e96, 0x21ba,
+ 0x7e97, 0x43d0,
+ 0x7e98, 0x245a,
+ 0x7e99, 0x43d1,
+ 0x7e9b, 0x1cec,
+ 0x7e9c, 0x1fff,
+ 0x7e9d, 0x43d3,
+ 0x7e9f, 0x17d3,
+ 0x7ea0, 0x08ef,
+ 0x7ea1, 0x17d4,
+ 0x7ea2, 0x07a3,
+ 0x7ea3, 0x17d5,
+ 0x7ea4, 0x0f38,
+ 0x7ea5, 0x17d6,
+ 0x7ea6, 0x10ff,
+ 0x7ea7, 0x0829,
+ 0x7ea8, 0x17d7,
+ 0x7eaa, 0x0840,
+ 0x7eab, 0x0cad,
+ 0x7eac, 0x0ec2,
+ 0x7ead, 0x17d9,
+ 0x7eae, 0x43d5,
+ 0x7eaf, 0x0542,
+ 0x7eb0, 0x17da,
+ 0x7eb1, 0x0ced,
+ 0x7eb2, 0x06d4,
+ 0x7eb3, 0x0b2c,
+ 0x7eb4, 0x43d6,
+ 0x7eb5, 0x123a,
+ 0x7eb6, 0x0a81,
+ 0x7eb7, 0x0674,
+ 0x7eb8, 0x11bc,
+ 0x7eb9, 0x0ed5,
+ 0x7eba, 0x0661,
+ 0x7ebb, 0x43d7,
+ 0x7ebd, 0x0b67,
+ 0x7ebe, 0x17db,
+ 0x7ebf, 0x0f4c,
+ 0x7ec0, 0x17dc,
+ 0x7ec3, 0x0a00,
+ 0x7ec4, 0x1246,
+ 0x7ec5, 0x0d29,
+ 0x7ec6, 0x0f25,
+ 0x7ec7, 0x11ae,
+ 0x7ec8, 0x11d4,
+ 0x7ec9, 0x17df,
+ 0x7eca, 0x03f8,
+ 0x7ecb, 0x17e0,
+ 0x7ecd, 0x0d15,
+ 0x7ece, 0x1076,
+ 0x7ecf, 0x08dc,
+ 0x7ed0, 0x17e2,
+ 0x7ed1, 0x03fe,
+ 0x7ed2, 0x0cb9,
+ 0x7ed3, 0x08b2,
+ 0x7ed4, 0x17e3,
+ 0x7ed5, 0x0ca1,
+ 0x7ed6, 0x43d9,
+ 0x7ed7, 0x17e4,
+ 0x7ed8, 0x07fb,
+ 0x7ed9, 0x06f3,
+ 0x7eda, 0x0fcd,
+ 0x7edb, 0x17e5,
+ 0x7edc, 0x0a8e,
+ 0x7edd, 0x0927,
+ 0x7ede, 0x089b,
+ 0x7edf, 0x0e64,
+ 0x7ee0, 0x17e6,
+ 0x7ee2, 0x091d,
+ 0x7ee3, 0x0fb0,
+ 0x7ee4, 0x43da,
+ 0x7ee5, 0x0ddc,
+ 0x7ee6, 0x0e23,
+ 0x7ee7, 0x083f,
+ 0x7ee8, 0x17e8,
+ 0x7ee9, 0x081b,
+ 0x7eea, 0x0fc2,
+ 0x7eeb, 0x17e9,
+ 0x7eec, 0x43db,
+ 0x7eed, 0x0fc3,
+ 0x7eee, 0x17ea,
+ 0x7ef0, 0x0545,
+ 0x7ef1, 0x17ec,
+ 0x7ef3, 0x0d37,
+ 0x7ef4, 0x0ebb,
+ 0x7ef5, 0x0ae5,
+ 0x7ef6, 0x17ef,
+ 0x7ef7, 0x042a,
+ 0x7ef8, 0x0516,
+ 0x7ef9, 0x43dc,
+ 0x7efa, 0x17f0,
+ 0x7efc, 0x1238,
+ 0x7efd, 0x1161,
+ 0x7efe, 0x17f2,
+ 0x7eff, 0x0a73,
+ 0x7f00, 0x1217,
+ 0x7f01, 0x17f3,
+ 0x7f04, 0x085d,
+ 0x7f05, 0x0aea,
+ 0x7f06, 0x09ad,
+ 0x7f07, 0x17f6,
+ 0x7f09, 0x081c,
+ 0x7f0a, 0x43dd,
+ 0x7f0b, 0x17f8,
+ 0x7f0d, 0x17ee,
+ 0x7f0e, 0x060f,
+ 0x7f0f, 0x17fa,
+ 0x7f10, 0x43de,
+ 0x7f11, 0x17fb,
+ 0x7f13, 0x07cf,
+ 0x7f14, 0x05bf,
+ 0x7f15, 0x0a6d,
+ 0x7f16, 0x0449,
+ 0x7f17, 0x17fd,
+ 0x7f18, 0x10f8,
+ 0x7f19, 0x17fe,
+ 0x7f1a, 0x06ba,
+ 0x7f1b, 0x1800,
+ 0x7f1c, 0x17ff,
+ 0x7f1d, 0x0689,
+ 0x7f1e, 0x43df,
+ 0x7f1f, 0x1801,
+ 0x7f20, 0x04bf,
+ 0x7f21, 0x1802,
+ 0x7f28, 0x108c,
+ 0x7f29, 0x0dea,
+ 0x7f2a, 0x1809,
+ 0x7f2e, 0x0d02,
+ 0x7f2f, 0x180d,
+ 0x7f34, 0x089a,
+ 0x7f35, 0x1812,
+ 0x7f36, 0x1c5e,
+ 0x7f37, 0x43e0,
+ 0x7f38, 0x06d2,
+ 0x7f39, 0x43e1,
+ 0x7f3a, 0x0c8c,
+ 0x7f3b, 0x43e2,
+ 0x7f42, 0x1c5f,
+ 0x7f43, 0x43e9,
+ 0x7f44, 0x1c60,
+ 0x7f46, 0x43ea,
+ 0x7f4c, 0x25e2,
+ 0x7f4d, 0x43f0,
+ 0x7f4e, 0x269a,
+ 0x7f4f, 0x43f1,
+ 0x7f50, 0x0737,
+ 0x7f51, 0x0ea9,
+ 0x7f52, 0x43f2,
+ 0x7f54, 0x129e,
+ 0x7f55, 0x0768,
+ 0x7f56, 0x43f4,
+ 0x7f57, 0x0a85,
+ 0x7f58, 0x1a81,
+ 0x7f59, 0x43f5,
+ 0x7f5a, 0x0640,
+ 0x7f5b, 0x43f6,
+ 0x7f5f, 0x1a83,
+ 0x7f60, 0x43fa,
+ 0x7f61, 0x1a82,
+ 0x7f62, 0x03e0,
+ 0x7f63, 0x43fb,
+ 0x7f68, 0x1a85,
+ 0x7f69, 0x1177,
+ 0x7f6a, 0x124c,
+ 0x7f6b, 0x4400,
+ 0x7f6e, 0x11c2,
+ 0x7f6f, 0x4403,
+ 0x7f70, 0x1eea,
+ 0x7f71, 0x1a87,
+ 0x7f72, 0x0d87,
+ 0x7f73, 0x4404,
+ 0x7f74, 0x1a86,
+ 0x7f75, 0x4405,
+ 0x7f77, 0x1e2c,
+ 0x7f78, 0x4407,
+ 0x7f79, 0x1a88,
+ 0x7f7a, 0x4408,
+ 0x7f7e, 0x1a8a,
+ 0x7f7f, 0x440c,
+ 0x7f81, 0x1a89,
+ 0x7f82, 0x440e,
+ 0x7f85, 0x2062,
+ 0x7f86, 0x24f1,
+ 0x7f87, 0x4411,
+ 0x7f88, 0x24f2,
+ 0x7f89, 0x4412,
+ 0x7f8a, 0x101b,
+ 0x7f8b, 0x4413,
+ 0x7f8c, 0x0c39,
+ 0x7f8d, 0x4414,
+ 0x7f8e, 0x0ac5,
+ 0x7f8f, 0x4415,
+ 0x7f94, 0x06dc,
+ 0x7f95, 0x441a,
+ 0x7f9a, 0x0a30,
+ 0x7f9b, 0x441f,
+ 0x7f9d, 0x1cc4,
+ 0x7f9e, 0x0faa,
+ 0x7f9f, 0x1cc5,
+ 0x7fa0, 0x4421,
+ 0x7fa1, 0x0f48,
+ 0x7fa2, 0x4422,
+ 0x7fa4, 0x0c95,
+ 0x7fa5, 0x25f2,
+ 0x7fa6, 0x4424,
+ 0x7fa7, 0x1cc6,
+ 0x7fa8, 0x4425,
+ 0x7fa9, 0x2215,
+ 0x7faa, 0x4426,
+ 0x7faf, 0x1cc7,
+ 0x7fb1, 0x442b,
+ 0x7fb2, 0x1cc9,
+ 0x7fb3, 0x442c,
+ 0x7fb8, 0x130e,
+ 0x7fb9, 0x06f9,
+ 0x7fba, 0x4431,
+ 0x7fbc, 0x176d,
+ 0x7fbd, 0x10d5,
+ 0x7fbe, 0x4433,
+ 0x7fbf, 0x1cde,
+ 0x7fc0, 0x4434,
+ 0x7fc1, 0x0edb,
+ 0x7fc2, 0x4435,
+ 0x7fc5, 0x0506,
+ 0x7fc6, 0x4438,
+ 0x7fca, 0x1b98,
+ 0x7fcb, 0x443c,
+ 0x7fcc, 0x1075,
+ 0x7fcd, 0x443d,
+ 0x7fce, 0x1cdf,
+ 0x7fcf, 0x443e,
+ 0x7fd2, 0x21ae,
+ 0x7fd3, 0x4441,
+ 0x7fd4, 0x0f55,
+ 0x7fd5, 0x1ce0,
+ 0x7fd6, 0x4442,
+ 0x7fd8, 0x0c49,
+ 0x7fd9, 0x4444,
+ 0x7fdf, 0x05b5,
+ 0x7fe0, 0x0567,
+ 0x7fe1, 0x1ce2,
+ 0x7fe2, 0x444a,
+ 0x7fe5, 0x1ce1,
+ 0x7fe6, 0x1ce3,
+ 0x7fe7, 0x444d,
+ 0x7fe9, 0x1ce4,
+ 0x7fea, 0x444f,
+ 0x7fee, 0x1ce5,
+ 0x7fef, 0x4453,
+ 0x7ff0, 0x0769,
+ 0x7ff1, 0x03ca,
+ 0x7ff2, 0x4454,
+ 0x7ff3, 0x1ce6,
+ 0x7ff4, 0x4455,
+ 0x7ff9, 0x20e0,
+ 0x7ffa, 0x445a,
+ 0x7ffb, 0x064a,
+ 0x7ffc, 0x1074,
+ 0x7ffd, 0x445b,
+ 0x8000, 0x1032,
+ 0x8001, 0x09ba,
+ 0x8002, 0x445e,
+ 0x8003, 0x0949,
+ 0x8004, 0x1953,
+ 0x8005, 0x1180,
+ 0x8006, 0x191a,
+ 0x8007, 0x445f,
+ 0x800b, 0x1bd7,
+ 0x800c, 0x0637,
+ 0x800d, 0x0d98,
+ 0x800e, 0x4463,
+ 0x8010, 0x0b30,
+ 0x8011, 0x4465,
+ 0x8012, 0x1bcb,
+ 0x8013, 0x4466,
+ 0x8014, 0x1bcc,
+ 0x8015, 0x06f6,
+ 0x8016, 0x1bcd,
+ 0x8017, 0x077b,
+ 0x8018, 0x1108,
+ 0x8019, 0x03dd,
+ 0x801a, 0x4467,
+ 0x801c, 0x1bce,
+ 0x801d, 0x4469,
+ 0x8020, 0x1bcf,
+ 0x8021, 0x446c,
+ 0x8022, 0x1bd0,
+ 0x8023, 0x446d,
+ 0x8025, 0x1bd1,
+ 0x8028, 0x1bd5,
+ 0x8029, 0x1bd4,
+ 0x802a, 0x0b96,
+ 0x802b, 0x446f,
+ 0x802c, 0x25c2,
+ 0x802d, 0x4470,
+ 0x802e, 0x25c1,
+ 0x802f, 0x4471,
+ 0x8031, 0x1bd6,
+ 0x8032, 0x4473,
+ 0x8033, 0x0639,
+ 0x8034, 0x4474,
+ 0x8035, 0x1bd8,
+ 0x8036, 0x1035,
+ 0x8037, 0x14b1,
+ 0x8038, 0x0dbf,
+ 0x8039, 0x4475,
+ 0x803b, 0x0501,
+ 0x803c, 0x4477,
+ 0x803d, 0x0583,
+ 0x803e, 0x4478,
+ 0x803f, 0x06fb,
+ 0x8040, 0x4479,
+ 0x8042, 0x0b57,
+ 0x8043, 0x1bd9,
+ 0x8044, 0x447b,
+ 0x8046, 0x1bda,
+ 0x8047, 0x447d,
+ 0x804a, 0x0a0d,
+ 0x804b, 0x0a44,
+ 0x804c, 0x11af,
+ 0x804d, 0x1bdb,
+ 0x804e, 0x4480,
+ 0x8052, 0x1bdc,
+ 0x8053, 0x4484,
+ 0x8054, 0x09f3,
+ 0x8055, 0x4485,
+ 0x8056, 0x2128,
+ 0x8057, 0x4486,
+ 0x8058, 0x0bd7,
+ 0x8059, 0x4487,
+ 0x805a, 0x090a,
+ 0x805b, 0x4488,
+ 0x805e, 0x2199,
+ 0x805f, 0x448b,
+ 0x8069, 0x1bdd,
+ 0x806a, 0x0552,
+ 0x806b, 0x4495,
+ 0x806f, 0x2017,
+ 0x8070, 0x1ea0,
+ 0x8071, 0x1bde,
+ 0x8072, 0x2125,
+ 0x8073, 0x214d,
+ 0x8074, 0x4499,
+ 0x8075, 0x25c4,
+ 0x8076, 0x209d,
+ 0x8077, 0x228a,
+ 0x8078, 0x449a,
+ 0x8079, 0x25c3,
+ 0x807a, 0x449b,
+ 0x807d, 0x2179,
+ 0x807e, 0x2038,
+ 0x807f, 0x1a1e,
+ 0x8080, 0x1a1d,
+ 0x8081, 0x449e,
+ 0x8083, 0x0dd5,
+ 0x8084, 0x1065,
+ 0x8085, 0x2155,
+ 0x8086, 0x0db6,
+ 0x8087, 0x1179,
+ 0x8088, 0x44a0,
+ 0x8089, 0x0cbd,
+ 0x808a, 0x44a1,
+ 0x808b, 0x09ca,
+ 0x808c, 0x0814,
+ 0x808d, 0x44a2,
+ 0x8093, 0x1971,
+ 0x8094, 0x44a8,
+ 0x8096, 0x0f6f,
+ 0x8097, 0x44aa,
+ 0x8098, 0x11e1,
+ 0x8099, 0x44ab,
+ 0x809a, 0x0606,
+ 0x809b, 0x06d3,
+ 0x809c, 0x1970,
+ 0x809d, 0x06c9,
+ 0x809e, 0x44ac,
+ 0x809f, 0x196f,
+ 0x80a0, 0x04cb,
+ 0x80a1, 0x0722,
+ 0x80a2, 0x11aa,
+ 0x80a3, 0x44ad,
+ 0x80a4, 0x0691,
+ 0x80a5, 0x0667,
+ 0x80a6, 0x44ae,
+ 0x80a9, 0x085a,
+ 0x80aa, 0x065b,
+ 0x80ab, 0x1976,
+ 0x80ac, 0x44b1,
+ 0x80ad, 0x1977,
+ 0x80ae, 0x03c4,
+ 0x80af, 0x095c,
+ 0x80b0, 0x44b2,
+ 0x80b1, 0x1975,
+ 0x80b2, 0x10e2,
+ 0x80b3, 0x44b3,
+ 0x80b4, 0x1978,
+ 0x80b5, 0x44b4,
+ 0x80b7, 0x1979,
+ 0x80b8, 0x44b6,
+ 0x80ba, 0x066b,
+ 0x80bb, 0x44b8,
+ 0x80bc, 0x1972,
+ 0x80bd, 0x1974,
+ 0x80be, 0x0d2f,
+ 0x80bf, 0x11d6,
+ 0x80c0, 0x116e,
+ 0x80c1, 0x0f7d,
+ 0x80c2, 0x197f,
+ 0x80c3, 0x0ec7,
+ 0x80c4, 0x1980,
+ 0x80c5, 0x44b9,
+ 0x80c6, 0x0589,
+ 0x80c7, 0x44ba,
+ 0x80cc, 0x041c,
+ 0x80cd, 0x1982,
+ 0x80ce, 0x0df8,
+ 0x80cf, 0x44bf,
+ 0x80d6, 0x0b97,
+ 0x80d7, 0x1983,
+ 0x80d8, 0x44c6,
+ 0x80d9, 0x1981,
+ 0x80da, 0x0ba0,
+ 0x80db, 0x197e,
+ 0x80dc, 0x0d3b,
+ 0x80dd, 0x1985,
+ 0x80de, 0x0406,
+ 0x80df, 0x44c7,
+ 0x80e1, 0x07b1,
+ 0x80e2, 0x44c9,
+ 0x80e4, 0x126d,
+ 0x80e5, 0x1bc7,
+ 0x80e6, 0x44cb,
+ 0x80e7, 0x197a,
+ 0x80eb, 0x1986,
+ 0x80ec, 0x179a,
+ 0x80ed, 0x1989,
+ 0x80ee, 0x44cc,
+ 0x80ef, 0x0975,
+ 0x80f0, 0x104f,
+ 0x80f1, 0x1987,
+ 0x80f2, 0x198c,
+ 0x80f3, 0x06e7,
+ 0x80f4, 0x1988,
+ 0x80f5, 0x44cd,
+ 0x80f6, 0x088b,
+ 0x80f7, 0x44ce,
+ 0x80f8, 0x0fa3,
+ 0x80f9, 0x44cf,
+ 0x80fa, 0x03c2,
+ 0x80fb, 0x44d0,
+ 0x80fc, 0x198d,
+ 0x80fd, 0x0b3f,
+ 0x80fe, 0x44d1,
+ 0x8100, 0x44d3,
+ 0x8102, 0x11ab,
+ 0x8103, 0x44d5,
+ 0x8105, 0x21d2,
+ 0x8106, 0x0563,
+ 0x8107, 0x44d7,
+ 0x8109, 0x0a9d,
+ 0x810a, 0x082c,
+ 0x810b, 0x44d9,
+ 0x810d, 0x198a,
+ 0x810f, 0x1123,
+ 0x8110, 0x0c09,
+ 0x8111, 0x0b37,
+ 0x8112, 0x198f,
+ 0x8113, 0x0b68,
+ 0x8114, 0x1309,
+ 0x8115, 0x44db,
+ 0x8116, 0x0478,
+ 0x8117, 0x44dc,
+ 0x8118, 0x1994,
+ 0x8119, 0x44dd,
+ 0x811a, 0x0896,
+ 0x811b, 0x24c7,
+ 0x811c, 0x44de,
+ 0x811e, 0x1992,
+ 0x811f, 0x44e0,
+ 0x812c, 0x1993,
+ 0x812d, 0x44ed,
+ 0x812f, 0x06a7,
+ 0x8130, 0x44ef,
+ 0x8131, 0x0e82,
+ 0x8132, 0x1995,
+ 0x8133, 0x44f0,
+ 0x8136, 0x1991,
+ 0x8137, 0x44f3,
+ 0x8138, 0x09fc,
+ 0x8139, 0x2279,
+ 0x813a, 0x44f4,
+ 0x813e, 0x0bc1,
+ 0x813f, 0x44f8,
+ 0x8146, 0x0e46,
+ 0x8147, 0x44ff,
+ 0x8148, 0x1996,
+ 0x8149, 0x4500,
+ 0x814a, 0x099b,
+ 0x814b, 0x103f,
+ 0x814c, 0x1997,
+ 0x814d, 0x4501,
+ 0x814e, 0x2123,
+ 0x814f, 0x4502,
+ 0x8150, 0x06aa,
+ 0x8151, 0x06a8,
+ 0x8152, 0x4503,
+ 0x8153, 0x1998,
+ 0x8154, 0x0c38,
+ 0x8155, 0x0ea4,
+ 0x8156, 0x24c5,
+ 0x8157, 0x4504,
+ 0x8159, 0x199a,
+ 0x815b, 0x4506,
+ 0x8160, 0x199d,
+ 0x8161, 0x24c9,
+ 0x8162, 0x450b,
+ 0x8165, 0x0f93,
+ 0x8166, 0x2094,
+ 0x8167, 0x19a2,
+ 0x8168, 0x450e,
+ 0x8169, 0x199e,
+ 0x816a, 0x450f,
+ 0x816b, 0x2296,
+ 0x816c, 0x4510,
+ 0x816d, 0x19a1,
+ 0x816e, 0x0cd4,
+ 0x816f, 0x4511,
+ 0x8170, 0x1025,
+ 0x8171, 0x199c,
+ 0x8172, 0x4512,
+ 0x8174, 0x1999,
+ 0x8175, 0x4514,
+ 0x8178, 0x1e77,
+ 0x8179, 0x06b4,
+ 0x817a, 0x0f46,
+ 0x817b, 0x0b48,
+ 0x817c, 0x199f,
+ 0x817e, 0x0e2d,
+ 0x817f, 0x0e79,
+ 0x8180, 0x03fd,
+ 0x8181, 0x4517,
+ 0x8182, 0x19a6,
+ 0x8183, 0x4518,
+ 0x8188, 0x19a5,
+ 0x8189, 0x451d,
+ 0x818a, 0x0479,
+ 0x818b, 0x451e,
+ 0x818f, 0x06db,
+ 0x8190, 0x4522,
+ 0x8191, 0x19a7,
+ 0x8192, 0x4523,
+ 0x8198, 0x0455,
+ 0x8199, 0x4529,
+ 0x819a, 0x1f06,
+ 0x819b, 0x0e18,
+ 0x819c, 0x0b07,
+ 0x819d, 0x0f12,
+ 0x819e, 0x452a,
+ 0x81a0, 0x1fa5,
+ 0x81a1, 0x452c,
+ 0x81a3, 0x19a9,
+ 0x81a4, 0x452e,
+ 0x81a6, 0x19b0,
+ 0x81a7, 0x4530,
+ 0x81a8, 0x0bb3,
+ 0x81a9, 0x2099,
+ 0x81aa, 0x19aa,
+ 0x81ab, 0x4531,
+ 0x81b3, 0x0cfe,
+ 0x81b4, 0x4539,
+ 0x81ba, 0x1641,
+ 0x81bb, 0x19ae,
+ 0x81bc, 0x453f,
+ 0x81bd, 0x1ead,
+ 0x81be, 0x24c8,
+ 0x81bf, 0x20a8,
+ 0x81c0, 0x0e7f,
+ 0x81c1, 0x19af,
+ 0x81c2, 0x0444,
+ 0x81c3, 0x109c,
+ 0x81c4, 0x4540,
+ 0x81c6, 0x1063,
+ 0x81c7, 0x4542,
+ 0x81c9, 0x201f,
+ 0x81ca, 0x19ad,
+ 0x81cb, 0x4544,
+ 0x81cc, 0x19ab,
+ 0x81cd, 0x20c5,
+ 0x81ce, 0x4545,
+ 0x81cf, 0x24ca,
+ 0x81d0, 0x4546,
+ 0x81d8, 0x1ff0,
+ 0x81d9, 0x454e,
+ 0x81da, 0x24c6,
+ 0x81db, 0x454f,
+ 0x81df, 0x225d,
+ 0x81e0, 0x22de,
+ 0x81e1, 0x4553,
+ 0x81e3, 0x04e1,
+ 0x81e4, 0x4555,
+ 0x81e7, 0x1902,
+ 0x81e8, 0x202c,
+ 0x81e9, 0x4558,
+ 0x81ea, 0x1231,
+ 0x81eb, 0x4559,
+ 0x81ec, 0x1ca9,
+ 0x81ed, 0x0519,
+ 0x81ee, 0x455a,
+ 0x81f3, 0x11c0,
+ 0x81f5, 0x455f,
+ 0x81fa, 0x2161,
+ 0x81fb, 0x118a,
+ 0x81fc, 0x08f9,
+ 0x81fd, 0x4564,
+ 0x81fe, 0x1ca5,
+ 0x81ff, 0x4565,
+ 0x8200, 0x102f,
+ 0x8201, 0x1ca6,
+ 0x8203, 0x4566,
+ 0x8204, 0x1ca8,
+ 0x8205, 0x08fa,
+ 0x8206, 0x10c4,
+ 0x8207, 0x223b,
+ 0x8208, 0x21d9,
+ 0x8209, 0x1fcb,
+ 0x820a, 0x1fc9,
+ 0x820b, 0x4567,
+ 0x820c, 0x0d19,
+ 0x820e, 0x4568,
+ 0x8210, 0x1c62,
+ 0x8211, 0x456a,
+ 0x8212, 0x0d7d,
+ 0x8213, 0x456b,
+ 0x8214, 0x0e45,
+ 0x8215, 0x456c,
+ 0x821b, 0x1618,
+ 0x821c, 0x0da9,
+ 0x821d, 0x4572,
+ 0x821e, 0x0ef7,
+ 0x821f, 0x11da,
+ 0x8220, 0x4573,
+ 0x8221, 0x1cab,
+ 0x8224, 0x4574,
+ 0x8228, 0x1cb0,
+ 0x8229, 0x4578,
+ 0x822a, 0x0774,
+ 0x822b, 0x1cb1,
+ 0x822c, 0x03ee,
+ 0x822d, 0x1cae,
+ 0x822e, 0x4579,
+ 0x822f, 0x1caf,
+ 0x8230, 0x0873,
+ 0x8231, 0x049c,
+ 0x8232, 0x457a,
+ 0x8233, 0x1cb4,
+ 0x8235, 0x0625,
+ 0x8236, 0x0477,
+ 0x8237, 0x0f3c,
+ 0x8238, 0x1cb2,
+ 0x8239, 0x052f,
+ 0x823a, 0x457b,
+ 0x823b, 0x1cb3,
+ 0x823c, 0x457c,
+ 0x823e, 0x1cb6,
+ 0x823f, 0x457e,
+ 0x8244, 0x1cb7,
+ 0x8245, 0x4583,
+ 0x8247, 0x0e58,
+ 0x8248, 0x4585,
+ 0x8249, 0x1cb8,
+ 0x824a, 0x4586,
+ 0x824b, 0x1cb9,
+ 0x824c, 0x4587,
+ 0x824f, 0x1cba,
+ 0x8250, 0x458a,
+ 0x8258, 0x0dc7,
+ 0x8259, 0x1e61,
+ 0x825a, 0x1cbb,
+ 0x825b, 0x4592,
+ 0x825f, 0x1cbc,
+ 0x8260, 0x4596,
+ 0x8264, 0x25ef,
+ 0x8265, 0x459a,
+ 0x8266, 0x1f98,
+ 0x8267, 0x459b,
+ 0x8268, 0x1cbd,
+ 0x8269, 0x459c,
+ 0x826b, 0x25f0,
+ 0x826c, 0x459e,
+ 0x826e, 0x1cdc,
+ 0x826f, 0x0a05,
+ 0x8270, 0x085b,
+ 0x8271, 0x1f88,
+ 0x8272, 0x0ce4,
+ 0x8273, 0x1007,
+ 0x8274, 0x1771,
+ 0x8275, 0x45a0,
+ 0x8277, 0x21f8,
+ 0x8278, 0x45a2,
+ 0x8279, 0x13e1,
+ 0x827a, 0x105c,
+ 0x827b, 0x45a3,
+ 0x827d, 0x13e2,
+ 0x827e, 0x03b7,
+ 0x827f, 0x13e3,
+ 0x8280, 0x45a5,
+ 0x8282, 0x08ab,
+ 0x8283, 0x45a7,
+ 0x8284, 0x13e7,
+ 0x8285, 0x45a8,
+ 0x8288, 0x1278,
+ 0x8289, 0x45ab,
+ 0x828a, 0x13e5,
+ 0x828b, 0x10d8,
+ 0x828c, 0x45ac,
+ 0x828d, 0x0d0f,
+ 0x828e, 0x13e8,
+ 0x828f, 0x13e4,
+ 0x8290, 0x45ad,
+ 0x8291, 0x13e9,
+ 0x8292, 0x0aa7,
+ 0x8293, 0x45ae,
+ 0x8297, 0x13ea,
+ 0x8298, 0x13f3,
+ 0x8299, 0x13eb,
+ 0x829a, 0x45b2,
+ 0x829c, 0x0eee,
+ 0x829d, 0x11a4,
+ 0x829e, 0x45b4,
+ 0x829f, 0x13fd,
+ 0x82a0, 0x45b5,
+ 0x82a1, 0x13fb,
+ 0x82a2, 0x45b6,
+ 0x82a4, 0x1400,
+ 0x82a5, 0x08b7,
+ 0x82a6, 0x0a52,
+ 0x82a7, 0x45b8,
+ 0x82a8, 0x13e6,
+ 0x82a9, 0x13f9,
+ 0x82aa, 0x13fc,
+ 0x82ab, 0x13ec,
+ 0x82ac, 0x066f,
+ 0x82ad, 0x03d0,
+ 0x82ae, 0x13f5,
+ 0x82af, 0x0f89,
+ 0x82b0, 0x13ef,
+ 0x82b1, 0x07bd,
+ 0x82b2, 0x45b9,
+ 0x82b3, 0x0659,
+ 0x82b4, 0x13fa,
+ 0x82b5, 0x45ba,
+ 0x82b7, 0x13f4,
+ 0x82b8, 0x13ed,
+ 0x82b9, 0x0c58,
+ 0x82ba, 0x45bc,
+ 0x82bb, 0x2322,
+ 0x82bc, 0x45bd,
+ 0x82bd, 0x0fe8,
+ 0x82be, 0x13ee,
+ 0x82bf, 0x45be,
+ 0x82c1, 0x13f8,
+ 0x82c2, 0x45c0,
+ 0x82c4, 0x13fe,
+ 0x82c5, 0x45c2,
+ 0x82c7, 0x0ebc,
+ 0x82c8, 0x13f0,
+ 0x82c9, 0x45c4,
+ 0x82ca, 0x13f1,
+ 0x82cb, 0x13f6,
+ 0x82cd, 0x049b,
+ 0x82ce, 0x13ff,
+ 0x82cf, 0x0dca,
+ 0x82d0, 0x45c5,
+ 0x82d1, 0x10fa,
+ 0x82d2, 0x1409,
+ 0x82d3, 0x140d,
+ 0x82d4, 0x0df9,
+ 0x82d5, 0x1414,
+ 0x82d6, 0x45c6,
+ 0x82d7, 0x0aec,
+ 0x82d8, 0x140a,
+ 0x82d9, 0x45c7,
+ 0x82db, 0x094e,
+ 0x82dc, 0x1407,
+ 0x82dd, 0x45c9,
+ 0x82de, 0x0405,
+ 0x82df, 0x070f,
+ 0x82e0, 0x1413,
+ 0x82e1, 0x1401,
+ 0x82e2, 0x45ca,
+ 0x82e3, 0x13f2,
+ 0x82e4, 0x1404,
+ 0x82e5, 0x0ccf,
+ 0x82e6, 0x096d,
+ 0x82e7, 0x2336,
+ 0x82e8, 0x45cb,
+ 0x82eb, 0x0cf4,
+ 0x82ec, 0x45ce,
+ 0x82ef, 0x0426,
+ 0x82f0, 0x45d1,
+ 0x82f1, 0x1087,
+ 0x82f2, 0x45d2,
+ 0x82f4, 0x1408,
+ 0x82f5, 0x45d4,
+ 0x82f7, 0x1403,
+ 0x82f8, 0x45d6,
+ 0x82f9, 0x0bda,
+ 0x82fa, 0x45d7,
+ 0x82fb, 0x140c,
+ 0x82fc, 0x45d8,
+ 0x8300, 0x45dc,
+ 0x8301, 0x121f,
+ 0x8302, 0x0ab4,
+ 0x8303, 0x0653,
+ 0x8304, 0x0c4e,
+ 0x8305, 0x0aae,
+ 0x8306, 0x1410,
+ 0x8307, 0x1406,
+ 0x8308, 0x1419,
+ 0x8309, 0x1402,
+ 0x830a, 0x45dd,
+ 0x830c, 0x140b,
+ 0x830d, 0x45df,
+ 0x830e, 0x08d4,
+ 0x830f, 0x1405,
+ 0x8310, 0x45e0,
+ 0x8311, 0x140e,
+ 0x8312, 0x45e1,
+ 0x8314, 0x1411,
+ 0x8316, 0x45e3,
+ 0x8317, 0x1426,
+ 0x8318, 0x45e4,
+ 0x831a, 0x140f,
+ 0x831b, 0x142e,
+ 0x831c, 0x1415,
+ 0x831d, 0x45e6,
+ 0x8327, 0x085e,
+ 0x8328, 0x0547,
+ 0x8329, 0x45f0,
+ 0x832b, 0x0aa8,
+ 0x832c, 0x04ae,
+ 0x832d, 0x1428,
+ 0x832e, 0x45f2,
+ 0x832f, 0x1420,
+ 0x8330, 0x45f3,
+ 0x8331, 0x141d,
+ 0x8332, 0x45f4,
+ 0x8333, 0x142a,
+ 0x8334, 0x141c,
+ 0x8335, 0x1077,
+ 0x8336, 0x04af,
+ 0x8337, 0x45f5,
+ 0x8338, 0x0cb2,
+ 0x8339, 0x0cbe,
+ 0x833a, 0x1429,
+ 0x833b, 0x45f6,
+ 0x833c, 0x141b,
+ 0x833d, 0x45f7,
+ 0x8340, 0x1425,
+ 0x8341, 0x45fa,
+ 0x8343, 0x1423,
+ 0x8344, 0x45fc,
+ 0x8346, 0x08d2,
+ 0x8347, 0x1422,
+ 0x8348, 0x45fe,
+ 0x8349, 0x04a4,
+ 0x834a, 0x45ff,
+ 0x834f, 0x1421,
+ 0x8350, 0x0869,
+ 0x8351, 0x1416,
+ 0x8352, 0x07d9,
+ 0x8353, 0x4604,
+ 0x8354, 0x09de,
+ 0x8355, 0x4605,
+ 0x835a, 0x0847,
+ 0x835b, 0x1417,
+ 0x835d, 0x460a,
+ 0x835e, 0x141f,
+ 0x835f, 0x1424,
+ 0x8360, 0x1427,
+ 0x8361, 0x0595,
+ 0x8362, 0x460b,
+ 0x8363, 0x0cb4,
+ 0x8364, 0x07fc,
+ 0x8365, 0x142c,
+ 0x8366, 0x142b,
+ 0x8367, 0x1090,
+ 0x8368, 0x142d,
+ 0x8369, 0x142f,
+ 0x836a, 0x1431,
+ 0x836b, 0x1078,
+ 0x836c, 0x1430,
+ 0x836d, 0x1432,
+ 0x836f, 0x1030,
+ 0x8370, 0x460c,
+ 0x8377, 0x0780,
+ 0x8378, 0x1435,
+ 0x8379, 0x4613,
+ 0x837b, 0x1442,
+ 0x837c, 0x143d,
+ 0x837d, 0x1440,
+ 0x837e, 0x4615,
+ 0x8385, 0x143c,
+ 0x8386, 0x0bed,
+ 0x8387, 0x461c,
+ 0x8389, 0x09dd,
+ 0x838a, 0x22ab,
+ 0x838b, 0x461e,
+ 0x838e, 0x0ce8,
+ 0x838f, 0x4621,
+ 0x8392, 0x141a,
+ 0x8393, 0x143a,
+ 0x8394, 0x4624,
+ 0x8396, 0x1fbf,
+ 0x8397, 0x4626,
+ 0x8398, 0x1443,
+ 0x8399, 0x4627,
+ 0x839b, 0x141e,
+ 0x839c, 0x143b,
+ 0x839d, 0x4629,
+ 0x839e, 0x1444,
+ 0x839f, 0x462a,
+ 0x83a0, 0x1438,
+ 0x83a1, 0x462b,
+ 0x83a2, 0x1f7d,
+ 0x83a3, 0x462c,
+ 0x83a7, 0x2333,
+ 0x83a8, 0x1445,
+ 0x83a9, 0x143f,
+ 0x83aa, 0x1439,
+ 0x83ab, 0x0b0d,
+ 0x83ac, 0x4630,
+ 0x83b0, 0x1434,
+ 0x83b1, 0x099e,
+ 0x83b2, 0x09f4,
+ 0x83b3, 0x1436,
+ 0x83b5, 0x4634,
+ 0x83b6, 0x143e,
+ 0x83b7, 0x0806,
+ 0x83b8, 0x1441,
+ 0x83b9, 0x108d,
+ 0x83ba, 0x1446,
+ 0x83bb, 0x4635,
+ 0x83bc, 0x1447,
+ 0x83bd, 0x0aac,
+ 0x83be, 0x4636,
+ 0x83c0, 0x145e,
+ 0x83c1, 0x1448,
+ 0x83c2, 0x4638,
+ 0x83c5, 0x145d,
+ 0x83c6, 0x463b,
+ 0x83c7, 0x0716,
+ 0x83c8, 0x463c,
+ 0x83ca, 0x0904,
+ 0x83cb, 0x463e,
+ 0x83cc, 0x0929,
+ 0x83cd, 0x463f,
+ 0x83cf, 0x0781,
+ 0x83d0, 0x4641,
+ 0x83d4, 0x1456,
+ 0x83d5, 0x4645,
+ 0x83d6, 0x1451,
+ 0x83d7, 0x4646,
+ 0x83d8, 0x144b,
+ 0x83d9, 0x4647,
+ 0x83dc, 0x0492,
+ 0x83dd, 0x144f,
+ 0x83de, 0x464a,
+ 0x83df, 0x1457,
+ 0x83e0, 0x046b,
+ 0x83e1, 0x1461,
+ 0x83e2, 0x464b,
+ 0x83e5, 0x144a,
+ 0x83e6, 0x464e,
+ 0x83e9, 0x0bef,
+ 0x83ea, 0x145c,
+ 0x83eb, 0x4651,
+ 0x83ef, 0x1f4d,
+ 0x83f0, 0x1460,
+ 0x83f1, 0x0a2b,
+ 0x83f2, 0x0663,
+ 0x83f3, 0x4655,
+ 0x83f8, 0x145a,
+ 0x83fa, 0x465a,
+ 0x83fd, 0x1450,
+ 0x83fe, 0x465d,
+ 0x8400, 0x465f,
+ 0x8401, 0x1449,
+ 0x8402, 0x4660,
+ 0x8403, 0x1459,
+ 0x8404, 0x0e24,
+ 0x8405, 0x4661,
+ 0x8406, 0x1455,
+ 0x8407, 0x2334,
+ 0x8408, 0x4662,
+ 0x840a, 0x1ff1,
+ 0x840b, 0x144e,
+ 0x840c, 0x0acd,
+ 0x840d, 0x0bdb,
+ 0x840e, 0x0ebd,
+ 0x840f, 0x1458,
+ 0x8410, 0x4664,
+ 0x8411, 0x1454,
+ 0x8412, 0x4665,
+ 0x8418, 0x144d,
+ 0x8419, 0x466b,
+ 0x841c, 0x1452,
+ 0x841d, 0x0a83,
+ 0x841e, 0x466e,
+ 0x8424, 0x108e,
+ 0x8426, 0x145f,
+ 0x8427, 0x0f61,
+ 0x8428, 0x0cd3,
+ 0x8429, 0x4674,
+ 0x842c, 0x218b,
+ 0x842d, 0x4677,
+ 0x8431, 0x1472,
+ 0x8432, 0x467b,
+ 0x8435, 0x2349,
+ 0x8436, 0x467e,
+ 0x8438, 0x1453,
+ 0x8439, 0x4680,
+ 0x843c, 0x146c,
+ 0x843d, 0x0a8b,
+ 0x843e, 0x4683,
+ 0x8446, 0x146d,
+ 0x8447, 0x468b,
+ 0x8449, 0x220b,
+ 0x844a, 0x468d,
+ 0x8451, 0x1463,
+ 0x8452, 0x2346,
+ 0x8453, 0x4694,
+ 0x8457, 0x11f7,
+ 0x8458, 0x4698,
+ 0x8459, 0x1465,
+ 0x845a, 0x1464,
+ 0x845b, 0x06eb,
+ 0x845c, 0x1462,
+ 0x845d, 0x4699,
+ 0x8461, 0x0bee,
+ 0x8462, 0x469d,
+ 0x8463, 0x05ec,
+ 0x8464, 0x2347,
+ 0x8465, 0x469e,
+ 0x8466, 0x2193,
+ 0x8467, 0x469f,
+ 0x8469, 0x146e,
+ 0x846a, 0x46a1,
+ 0x846b, 0x07b0,
+ 0x846c, 0x1124,
+ 0x846d, 0x1473,
+ 0x846e, 0x46a2,
+ 0x846f, 0x26a1,
+ 0x8470, 0x46a3,
+ 0x8471, 0x0553,
+ 0x8472, 0x46a4,
+ 0x8473, 0x1466,
+ 0x8474, 0x46a5,
+ 0x8475, 0x0988,
+ 0x8476, 0x146f,
+ 0x8477, 0x1f62,
+ 0x8478, 0x146b,
+ 0x8479, 0x46a6,
+ 0x847a, 0x1469,
+ 0x847b, 0x46a7,
+ 0x8482, 0x05ba,
+ 0x8483, 0x46ae,
+ 0x8487, 0x1467,
+ 0x8489, 0x146a,
+ 0x848a, 0x46b2,
+ 0x848b, 0x0880,
+ 0x848c, 0x1470,
+ 0x848d, 0x46b3,
+ 0x848e, 0x1471,
+ 0x848f, 0x46b4,
+ 0x8493, 0x234d,
+ 0x8494, 0x2348,
+ 0x8495, 0x46b8,
+ 0x8497, 0x1481,
+ 0x8498, 0x46ba,
+ 0x8499, 0x0ace,
+ 0x849a, 0x46bb,
+ 0x849c, 0x0dd7,
+ 0x849d, 0x46bd,
+ 0x84a1, 0x147e,
+ 0x84a2, 0x46c1,
+ 0x84af, 0x1297,
+ 0x84b0, 0x46ce,
+ 0x84b2, 0x0bf0,
+ 0x84b3, 0x46d0,
+ 0x84b4, 0x1480,
+ 0x84b5, 0x46d1,
+ 0x84b8, 0x1195,
+ 0x84b9, 0x147f,
+ 0x84ba, 0x147c,
+ 0x84bb, 0x46d4,
+ 0x84bc, 0x1e60,
+ 0x84bd, 0x1478,
+ 0x84be, 0x46d5,
+ 0x84bf, 0x147b,
+ 0x84c0, 0x2345,
+ 0x84c1, 0x1474,
+ 0x84c2, 0x46d6,
+ 0x84c4, 0x0fb9,
+ 0x84c5, 0x46d8,
+ 0x84c9, 0x0cb3,
+ 0x84ca, 0x147a,
+ 0x84cb, 0x1f12,
+ 0x84cc, 0x46dc,
+ 0x84cd, 0x1475,
+ 0x84ce, 0x46dd,
+ 0x84d0, 0x1476,
+ 0x84d1, 0x0de7,
+ 0x84d2, 0x46df,
+ 0x84d3, 0x1479,
+ 0x84d4, 0x46e0,
+ 0x84d6, 0x0436,
+ 0x84d7, 0x46e2,
+ 0x84dd, 0x09a1,
+ 0x84de, 0x46e8,
+ 0x84df, 0x082e,
+ 0x84e0, 0x147d,
+ 0x84e1, 0x46e9,
+ 0x84e3, 0x1483,
+ 0x84e4, 0x46eb,
+ 0x84e5, 0x1482,
+ 0x84e6, 0x1477,
+ 0x84e7, 0x46ec,
+ 0x84ec, 0x0baf,
+ 0x84ed, 0x46f1,
+ 0x84ee, 0x2018,
+ 0x84ef, 0x2335,
+ 0x84f0, 0x1487,
+ 0x84f1, 0x46f2,
+ 0x84fc, 0x148e,
+ 0x84fd, 0x233c,
+ 0x84fe, 0x46fd,
+ 0x84ff, 0x148d,
+ 0x8500, 0x46fe,
+ 0x850c, 0x1484,
+ 0x850d, 0x470a,
+ 0x8511, 0x0af4,
+ 0x8512, 0x470e,
+ 0x8513, 0x0aa2,
+ 0x8514, 0x266f,
+ 0x8515, 0x470f,
+ 0x8517, 0x1182,
+ 0x8518, 0x4711,
+ 0x851a, 0x0ec4,
+ 0x851b, 0x4713,
+ 0x851e, 0x2351,
+ 0x851f, 0x1489,
+ 0x8520, 0x4716,
+ 0x8521, 0x0493,
+ 0x8522, 0x4717,
+ 0x8523, 0x1fa0,
+ 0x8524, 0x4718,
+ 0x8526, 0x2338,
+ 0x8527, 0x471a,
+ 0x852b, 0x0b4b,
+ 0x852c, 0x0d76,
+ 0x852d, 0x221b,
+ 0x852e, 0x471e,
+ 0x8537, 0x0c3b,
+ 0x8538, 0x1486,
+ 0x8539, 0x1488,
+ 0x853a, 0x148a,
+ 0x853b, 0x148c,
+ 0x853c, 0x03b5,
+ 0x853d, 0x0437,
+ 0x853e, 0x4727,
+ 0x8541, 0x2342,
+ 0x8542, 0x472a,
+ 0x8543, 0x1496,
+ 0x8544, 0x472b,
+ 0x8546, 0x234f,
+ 0x8547, 0x472d,
+ 0x8548, 0x1490,
+ 0x8549, 0x0887,
+ 0x854a, 0x0cca,
+ 0x854b, 0x472e,
+ 0x854e, 0x233d,
+ 0x854f, 0x4731,
+ 0x8552, 0x2344,
+ 0x8553, 0x2331,
+ 0x8554, 0x4734,
+ 0x8555, 0x234b,
+ 0x8556, 0x148b,
+ 0x8557, 0x4735,
+ 0x8558, 0x233b,
+ 0x8559, 0x148f,
+ 0x855a, 0x4736,
+ 0x855e, 0x1493,
+ 0x855f, 0x473a,
+ 0x8562, 0x2350,
+ 0x8563, 0x473d,
+ 0x8564, 0x1492,
+ 0x8565, 0x473e,
+ 0x8568, 0x1491,
+ 0x8569, 0x1eb4,
+ 0x856a, 0x21a6,
+ 0x856b, 0x4741,
+ 0x856d, 0x21cb,
+ 0x856e, 0x4743,
+ 0x8572, 0x1497,
+ 0x8573, 0x4747,
+ 0x8574, 0x110f,
+ 0x8575, 0x4748,
+ 0x8577, 0x2355,
+ 0x8578, 0x474a,
+ 0x8579, 0x149d,
+ 0x857a, 0x1494,
+ 0x857b, 0x1498,
+ 0x857c, 0x474b,
+ 0x857e, 0x09c4,
+ 0x857f, 0x474d,
+ 0x8584, 0x040a,
+ 0x8585, 0x14a0,
+ 0x8586, 0x4752,
+ 0x8587, 0x149b,
+ 0x8588, 0x233e,
+ 0x8589, 0x4753,
+ 0x858a, 0x1f74,
+ 0x858b, 0x4754,
+ 0x858c, 0x2330,
+ 0x858d, 0x4755,
+ 0x858f, 0x149c,
+ 0x8590, 0x4757,
+ 0x8591, 0x2680,
+ 0x8592, 0x4758,
+ 0x8594, 0x20da,
+ 0x8595, 0x475a,
+ 0x859b, 0x0fcf,
+ 0x859c, 0x149f,
+ 0x859d, 0x4760,
+ 0x859f, 0x234a,
+ 0x85a0, 0x4762,
+ 0x85a4, 0x1499,
+ 0x85a5, 0x4766,
+ 0x85a6, 0x1f91,
+ 0x85a7, 0x4767,
+ 0x85a8, 0x149a,
+ 0x85a9, 0x2107,
+ 0x85aa, 0x0f88,
+ 0x85ab, 0x4768,
+ 0x85ae, 0x149e,
+ 0x85af, 0x0d84,
+ 0x85b0, 0x14a3,
+ 0x85b1, 0x476b,
+ 0x85b7, 0x14a2,
+ 0x85b8, 0x4771,
+ 0x85b9, 0x14a1,
+ 0x85ba, 0x233f,
+ 0x85bb, 0x4772,
+ 0x85c1, 0x14a5,
+ 0x85c2, 0x4778,
+ 0x85c9, 0x08b6,
+ 0x85ca, 0x477f,
+ 0x85cd, 0x1ff4,
+ 0x85ce, 0x2343,
+ 0x85cf, 0x049f,
+ 0x85d0, 0x0aef,
+ 0x85d1, 0x4782,
+ 0x85d3, 0x14a4,
+ 0x85d4, 0x4784,
+ 0x85d5, 0x0b7b,
+ 0x85d6, 0x4785,
+ 0x85dc, 0x14a6,
+ 0x85dd, 0x2212,
+ 0x85de, 0x478b,
+ 0x85e4, 0x0e2c,
+ 0x85e5, 0x2207,
+ 0x85e6, 0x4791,
+ 0x85e9, 0x0647,
+ 0x85ea, 0x2359,
+ 0x85eb, 0x4794,
+ 0x85f4, 0x2254,
+ 0x85f5, 0x479d,
+ 0x85f6, 0x2332,
+ 0x85f7, 0x479e,
+ 0x85f9, 0x1e26,
+ 0x85fa, 0x2357,
+ 0x85fb, 0x1128,
+ 0x85fc, 0x47a0,
+ 0x85ff, 0x14a7,
+ 0x8600, 0x47a3,
+ 0x8604, 0x2358,
+ 0x8605, 0x14a9,
+ 0x8606, 0x2042,
+ 0x8607, 0x2153,
+ 0x8608, 0x47a7,
+ 0x860b, 0x20bb,
+ 0x860c, 0x47aa,
+ 0x8611, 0x0b05,
+ 0x8612, 0x47af,
+ 0x8616, 0x14ab,
+ 0x8617, 0x47b3,
+ 0x861a, 0x235a,
+ 0x861b, 0x47b6,
+ 0x861e, 0x2356,
+ 0x861f, 0x47b9,
+ 0x8622, 0x2337,
+ 0x8623, 0x47bc,
+ 0x8627, 0x14a8,
+ 0x8628, 0x47c0,
+ 0x8629, 0x14aa,
+ 0x862a, 0x47c1,
+ 0x862d, 0x1ff9,
+ 0x862e, 0x47c4,
+ 0x8638, 0x115b,
+ 0x8639, 0x47ce,
+ 0x863a, 0x2353,
+ 0x863b, 0x47cf,
+ 0x863c, 0x14ac,
+ 0x863d, 0x47d0,
+ 0x863f, 0x2061,
+ 0x8640, 0x47d2,
+ 0x864d, 0x1bf0,
+ 0x864e, 0x07b7,
+ 0x864f, 0x0a59,
+ 0x8650, 0x0b71,
+ 0x8651, 0x0a6e,
+ 0x8652, 0x47df,
+ 0x8654, 0x1bf1,
+ 0x8655, 0x1e95,
+ 0x8656, 0x47e1,
+ 0x865a, 0x0fb4,
+ 0x865b, 0x47e5,
+ 0x865c, 0x2049,
+ 0x865d, 0x47e6,
+ 0x865e, 0x10c2,
+ 0x865f, 0x1f42,
+ 0x8660, 0x47e7,
+ 0x8662, 0x196d,
+ 0x8663, 0x47e9,
+ 0x8667, 0x1fe8,
+ 0x8668, 0x47ed,
+ 0x866b, 0x050b,
+ 0x866c, 0x1bf2,
+ 0x866d, 0x47f0,
+ 0x866e, 0x1bf3,
+ 0x866f, 0x47f1,
+ 0x8671, 0x0d44,
+ 0x8672, 0x47f3,
+ 0x8679, 0x079e,
+ 0x867a, 0x1bf5,
+ 0x867b, 0x1bf7,
+ 0x867c, 0x1bf6,
+ 0x867d, 0x0dd9,
+ 0x867e, 0x0f27,
+ 0x867f, 0x1bf4,
+ 0x8680, 0x0d4b,
+ 0x8681, 0x1056,
+ 0x8682, 0x0a93,
+ 0x8683, 0x47fa,
+ 0x868a, 0x0ed2,
+ 0x868b, 0x1bfa,
+ 0x868c, 0x0401,
+ 0x868d, 0x1bf9,
+ 0x868e, 0x4801,
+ 0x8693, 0x1c00,
+ 0x8694, 0x4806,
+ 0x8695, 0x0496,
+ 0x8696, 0x4807,
+ 0x869c, 0x0fea,
+ 0x869d, 0x1bfc,
+ 0x869e, 0x480d,
+ 0x86a3, 0x1bfe,
+ 0x86a4, 0x112c,
+ 0x86a5, 0x4812,
+ 0x86a7, 0x1bfd,
+ 0x86a8, 0x1bf8,
+ 0x86a9, 0x1c01,
+ 0x86aa, 0x1bff,
+ 0x86ab, 0x4814,
+ 0x86ac, 0x1bfb,
+ 0x86ad, 0x4815,
+ 0x86af, 0x1c09,
+ 0x86b0, 0x1c06,
+ 0x86b1, 0x1c08,
+ 0x86b2, 0x4817,
+ 0x86b4, 0x1c0c,
+ 0x86b5, 0x1c04,
+ 0x86b6, 0x1c02,
+ 0x86b7, 0x4819,
+ 0x86ba, 0x1c07,
+ 0x86bb, 0x481c,
+ 0x86c0, 0x11fa,
+ 0x86c1, 0x4821,
+ 0x86c4, 0x1c03,
+ 0x86c5, 0x4824,
+ 0x86c6, 0x0c76,
+ 0x86c7, 0x0d18,
+ 0x86c8, 0x4825,
+ 0x86c9, 0x1c0a,
+ 0x86ca, 0x071f,
+ 0x86cb, 0x0591,
+ 0x86cc, 0x4826,
+ 0x86ce, 0x1c05,
+ 0x86cf, 0x1c0b,
+ 0x86d0, 0x1c12,
+ 0x86d1, 0x1c18,
+ 0x86d2, 0x4828,
+ 0x86d4, 0x07ec,
+ 0x86d5, 0x482a,
+ 0x86d8, 0x1c17,
+ 0x86d9, 0x0e8d,
+ 0x86da, 0x482d,
+ 0x86db, 0x11ea,
+ 0x86dc, 0x482e,
+ 0x86de, 0x1c14,
+ 0x86df, 0x1c16,
+ 0x86e0, 0x4830,
+ 0x86e4, 0x06ed,
+ 0x86e5, 0x4834,
+ 0x86e9, 0x1c0d,
+ 0x86ea, 0x4838,
+ 0x86ed, 0x1c10,
+ 0x86ee, 0x0aa0,
+ 0x86ef, 0x483b,
+ 0x86f0, 0x117e,
+ 0x86f1, 0x1c0e,
+ 0x86f3, 0x1c11,
+ 0x86f4, 0x1c15,
+ 0x86f5, 0x483c,
+ 0x86f8, 0x1c1b,
+ 0x86f9, 0x10a1,
+ 0x86fa, 0x25da,
+ 0x86fb, 0x483f,
+ 0x86fe, 0x0629,
+ 0x86ff, 0x4842,
+ 0x8700, 0x0d88,
+ 0x8701, 0x4843,
+ 0x8702, 0x0681,
+ 0x8703, 0x1c19,
+ 0x8704, 0x4844,
+ 0x8706, 0x25d7,
+ 0x8707, 0x1c1a,
+ 0x8708, 0x1c1c,
+ 0x8709, 0x1c1f,
+ 0x870a, 0x1c1d,
+ 0x870b, 0x4846,
+ 0x870d, 0x1c1e,
+ 0x870e, 0x4848,
+ 0x8712, 0x0ffa,
+ 0x8713, 0x1c13,
+ 0x8714, 0x484c,
+ 0x8715, 0x0e7a,
+ 0x8716, 0x484d,
+ 0x8717, 0x0ede,
+ 0x8718, 0x11a8,
+ 0x8719, 0x484e,
+ 0x871a, 0x1c25,
+ 0x871b, 0x484f,
+ 0x871c, 0x0ae0,
+ 0x871d, 0x4850,
+ 0x871e, 0x1c22,
+ 0x871f, 0x4851,
+ 0x8721, 0x099a,
+ 0x8722, 0x1c2e,
+ 0x8723, 0x1c20,
+ 0x8724, 0x4853,
+ 0x8725, 0x1c23,
+ 0x8726, 0x4854,
+ 0x8729, 0x1c2a,
+ 0x872a, 0x4857,
+ 0x872e, 0x1c24,
+ 0x872f, 0x485b,
+ 0x8731, 0x1c29,
+ 0x8732, 0x485d,
+ 0x8734, 0x1c28,
+ 0x8735, 0x485f,
+ 0x8737, 0x1c2b,
+ 0x8738, 0x4861,
+ 0x873b, 0x1c21,
+ 0x873c, 0x4864,
+ 0x873e, 0x1c26,
+ 0x873f, 0x1c2c,
+ 0x8740, 0x4866,
+ 0x8747, 0x1091,
+ 0x8748, 0x1c27,
+ 0x8749, 0x04bc,
+ 0x874a, 0x486d,
+ 0x874c, 0x1c34,
+ 0x874d, 0x486f,
+ 0x874e, 0x0f76,
+ 0x874f, 0x4870,
+ 0x8753, 0x1c37,
+ 0x8754, 0x4874,
+ 0x8755, 0x212e,
+ 0x8756, 0x4875,
+ 0x8757, 0x07dd,
+ 0x8758, 0x4876,
+ 0x8759, 0x1c3b,
+ 0x875a, 0x4877,
+ 0x8760, 0x1c32,
+ 0x8761, 0x487d,
+ 0x8763, 0x1c38,
+ 0x8764, 0x1c3a,
+ 0x8765, 0x1c3c,
+ 0x8766, 0x21b2,
+ 0x8767, 0x487f,
+ 0x876e, 0x1c35,
+ 0x876f, 0x4886,
+ 0x8770, 0x1c33,
+ 0x8771, 0x4887,
+ 0x8774, 0x07b2,
+ 0x8775, 0x488a,
+ 0x8776, 0x05dc,
+ 0x8777, 0x488b,
+ 0x8778, 0x219e,
+ 0x8779, 0x488c,
+ 0x877b, 0x1c31,
+ 0x877c, 0x1c39,
+ 0x877d, 0x1c2f,
+ 0x877f, 0x488e,
+ 0x8782, 0x1c2d,
+ 0x8783, 0x1c46,
+ 0x8784, 0x25dc,
+ 0x8785, 0x1c43,
+ 0x8786, 0x4891,
+ 0x8788, 0x1c42,
+ 0x8789, 0x4893,
+ 0x878b, 0x1c36,
+ 0x878c, 0x4895,
+ 0x878d, 0x0cb5,
+ 0x878e, 0x4896,
+ 0x8793, 0x1c3d,
+ 0x8794, 0x489b,
+ 0x8797, 0x1c45,
+ 0x8798, 0x489e,
+ 0x879e, 0x206c,
+ 0x879f, 0x0afd,
+ 0x87a0, 0x48a4,
+ 0x87a2, 0x2226,
+ 0x87a3, 0x48a6,
+ 0x87a8, 0x1c3f,
+ 0x87a9, 0x48ab,
+ 0x87ab, 0x1c47,
+ 0x87ac, 0x1c49,
+ 0x87ad, 0x1c44,
+ 0x87ae, 0x48ad,
+ 0x87af, 0x1c3e,
+ 0x87b0, 0x48ae,
+ 0x87b3, 0x1c4b,
+ 0x87b4, 0x48b1,
+ 0x87b5, 0x1c4a,
+ 0x87b6, 0x48b2,
+ 0x87ba, 0x0a84,
+ 0x87bb, 0x25e0,
+ 0x87bc, 0x48b6,
+ 0x87bd, 0x1c4e,
+ 0x87be, 0x48b7,
+ 0x87c0, 0x1c50,
+ 0x87c1, 0x48b9,
+ 0x87c4, 0x227b,
+ 0x87c5, 0x48bc,
+ 0x87c6, 0x1c41,
+ 0x87c7, 0x48bd,
+ 0x87c8, 0x25de,
+ 0x87c9, 0x48be,
+ 0x87ca, 0x1c51,
+ 0x87cb, 0x1c4c,
+ 0x87cc, 0x48bf,
+ 0x87ce, 0x25e1,
+ 0x87cf, 0x48c1,
+ 0x87d1, 0x1c4f,
+ 0x87d2, 0x1c40,
+ 0x87d3, 0x1c4d,
+ 0x87d4, 0x48c3,
+ 0x87db, 0x1c52,
+ 0x87dc, 0x48ca,
+ 0x87e0, 0x1c54,
+ 0x87e1, 0x48ce,
+ 0x87e3, 0x25d5,
+ 0x87e4, 0x48d0,
+ 0x87e5, 0x1c48,
+ 0x87e6, 0x48d1,
+ 0x87ea, 0x1c53,
+ 0x87eb, 0x48d5,
+ 0x87ec, 0x1e6b,
+ 0x87ed, 0x48d6,
+ 0x87ee, 0x1c55,
+ 0x87ef, 0x25db,
+ 0x87f0, 0x48d7,
+ 0x87f2, 0x1e89,
+ 0x87f3, 0x48d9,
+ 0x87f6, 0x25d9,
+ 0x87f7, 0x48dc,
+ 0x87f9, 0x0f82,
+ 0x87fa, 0x48de,
+ 0x87fb, 0x2211,
+ 0x87fc, 0x48df,
+ 0x87fe, 0x1c58,
+ 0x87ff, 0x48e1,
+ 0x8800, 0x48e2,
+ 0x8803, 0x130d,
+ 0x8804, 0x48e5,
+ 0x8805, 0x2229,
+ 0x8806, 0x25d6,
+ 0x8807, 0x48e6,
+ 0x880a, 0x1c59,
+ 0x880b, 0x48e9,
+ 0x8810, 0x25dd,
+ 0x8811, 0x25df,
+ 0x8812, 0x48ee,
+ 0x8813, 0x1c57,
+ 0x8814, 0x48ef,
+ 0x8815, 0x0cbf,
+ 0x8816, 0x1c56,
+ 0x8817, 0x48f0,
+ 0x881b, 0x1c5a,
+ 0x881c, 0x48f4,
+ 0x881f, 0x1fef,
+ 0x8820, 0x48f7,
+ 0x8821, 0x1c5b,
+ 0x8822, 0x0543,
+ 0x8823, 0x25d8,
+ 0x8824, 0x48f8,
+ 0x8831, 0x1f29,
+ 0x8832, 0x1a8d,
+ 0x8833, 0x4905,
+ 0x8836, 0x1e5b,
+ 0x8837, 0x4908,
+ 0x8839, 0x1c5c,
+ 0x883a, 0x490a,
+ 0x883b, 0x2076,
+ 0x883c, 0x1c5d,
+ 0x883d, 0x490b,
+ 0x8840, 0x0fd3,
+ 0x8841, 0x490e,
+ 0x8844, 0x1caa,
+ 0x8845, 0x0f91,
+ 0x8846, 0x2297,
+ 0x8847, 0x4911,
+ 0x884a, 0x2690,
+ 0x884b, 0x4914,
+ 0x884c, 0x0f9b,
+ 0x884d, 0x1005,
+ 0x884e, 0x4915,
+ 0x8853, 0x213f,
+ 0x8854, 0x0f3b,
+ 0x8855, 0x491a,
+ 0x8857, 0x08a7,
+ 0x8858, 0x491c,
+ 0x8859, 0x0fec,
+ 0x885a, 0x491d,
+ 0x885b, 0x2198,
+ 0x885c, 0x491e,
+ 0x885d, 0x1e88,
+ 0x885e, 0x491f,
+ 0x8861, 0x0799,
+ 0x8862, 0x15ed,
+ 0x8863, 0x1049,
+ 0x8864, 0x1ba6,
+ 0x8865, 0x0480,
+ 0x8866, 0x4922,
+ 0x8868, 0x0456,
+ 0x8869, 0x1ba7,
+ 0x886a, 0x4924,
+ 0x886b, 0x0cf9,
+ 0x886c, 0x04e9,
+ 0x886d, 0x4925,
+ 0x886e, 0x1306,
+ 0x886f, 0x4926,
+ 0x8870, 0x0d9a,
+ 0x8871, 0x4927,
+ 0x8872, 0x1ba8,
+ 0x8873, 0x4928,
+ 0x8877, 0x11d3,
+ 0x8878, 0x492c,
+ 0x8879, 0x228c,
+ 0x887a, 0x492d,
+ 0x887d, 0x1ba9,
+ 0x887e, 0x1cbe,
+ 0x887f, 0x1baa,
+ 0x8880, 0x4930,
+ 0x8881, 0x10ef,
+ 0x8882, 0x1bab,
+ 0x8883, 0x4931,
+ 0x8884, 0x03cb,
+ 0x8885, 0x1cbf,
+ 0x8886, 0x4932,
+ 0x8888, 0x1cc0,
+ 0x8889, 0x4934,
+ 0x888b, 0x057f,
+ 0x888c, 0x4936,
+ 0x888d, 0x0b9c,
+ 0x888e, 0x4937,
+ 0x8892, 0x0e0e,
+ 0x8893, 0x493b,
+ 0x8896, 0x0faf,
+ 0x8897, 0x493e,
+ 0x889c, 0x0e91,
+ 0x889d, 0x4943,
+ 0x88a2, 0x1bac,
+ 0x88a3, 0x4948,
+ 0x88a4, 0x1307,
+ 0x88a5, 0x4949,
+ 0x88ab, 0x0424,
+ 0x88ac, 0x494f,
+ 0x88ad, 0x0f1b,
+ 0x88ae, 0x4950,
+ 0x88b1, 0x069f,
+ 0x88b2, 0x4953,
+ 0x88b7, 0x1bae,
+ 0x88b8, 0x4958,
+ 0x88bc, 0x1baf,
+ 0x88bd, 0x495c,
+ 0x88c1, 0x048a,
+ 0x88c2, 0x0a1a,
+ 0x88c3, 0x4960,
+ 0x88c5, 0x120d,
+ 0x88c6, 0x1bad,
+ 0x88c7, 0x4962,
+ 0x88c9, 0x1bb0,
+ 0x88ca, 0x25f1,
+ 0x88cb, 0x4964,
+ 0x88ce, 0x1bb2,
+ 0x88cf, 0x200c,
+ 0x88d0, 0x4967,
+ 0x88d2, 0x130a,
+ 0x88d3, 0x4969,
+ 0x88d4, 0x1068,
+ 0x88d5, 0x10e6,
+ 0x88d6, 0x496a,
+ 0x88d8, 0x1cc1,
+ 0x88d9, 0x0c94,
+ 0x88da, 0x496c,
+ 0x88dc, 0x1e58,
+ 0x88dd, 0x22ac,
+ 0x88de, 0x496e,
+ 0x88df, 0x1cc2,
+ 0x88e0, 0x496f,
+ 0x88e2, 0x1bb1,
+ 0x88e3, 0x1bb3,
+ 0x88e4, 0x0970,
+ 0x88e5, 0x1bb4,
+ 0x88e6, 0x4971,
+ 0x88e8, 0x1bb8,
+ 0x88e9, 0x4973,
+ 0x88f0, 0x1bba,
+ 0x88f1, 0x1bb5,
+ 0x88f2, 0x497a,
+ 0x88f3, 0x0d0a,
+ 0x88f4, 0x0ba2,
+ 0x88f5, 0x497b,
+ 0x88f8, 0x0a8a,
+ 0x88f9, 0x0755,
+ 0x88fa, 0x497e,
+ 0x88fc, 0x1bb7,
+ 0x88fd, 0x26a7,
+ 0x88fe, 0x1bb9,
+ 0x88ff, 0x4980,
+ 0x8900, 0x4981,
+ 0x8902, 0x072c,
+ 0x8903, 0x4983,
+ 0x8907, 0x2676,
+ 0x8908, 0x4987,
+ 0x890a, 0x1bbf,
+ 0x890b, 0x4989,
+ 0x8910, 0x078d,
+ 0x8911, 0x498e,
+ 0x8912, 0x0408,
+ 0x8913, 0x1bbd,
+ 0x8914, 0x498f,
+ 0x8919, 0x1bbc,
+ 0x891a, 0x1bb6,
+ 0x891b, 0x1bbe,
+ 0x891c, 0x4994,
+ 0x8921, 0x1bbb,
+ 0x8922, 0x4999,
+ 0x8925, 0x0cc7,
+ 0x8926, 0x499c,
+ 0x892a, 0x0e7b,
+ 0x892b, 0x1bc1,
+ 0x892c, 0x49a0,
+ 0x8930, 0x1739,
+ 0x8931, 0x49a4,
+ 0x8932, 0x1fe1,
+ 0x8933, 0x25bb,
+ 0x8934, 0x1bc0,
+ 0x8935, 0x49a5,
+ 0x8936, 0x1bc2,
+ 0x8937, 0x49a6,
+ 0x8938, 0x25be,
+ 0x8939, 0x49a7,
+ 0x893b, 0x22dd,
+ 0x893c, 0x49a9,
+ 0x8941, 0x1bc3,
+ 0x8942, 0x49ae,
+ 0x8944, 0x0f52,
+ 0x8945, 0x49b0,
+ 0x8947, 0x25bd,
+ 0x8948, 0x49b2,
+ 0x8956, 0x1e2a,
+ 0x8957, 0x49c0,
+ 0x895d, 0x25bc,
+ 0x895e, 0x1cc3,
+ 0x895f, 0x08c4,
+ 0x8960, 0x25ba,
+ 0x8961, 0x49c6,
+ 0x8964, 0x25bf,
+ 0x8965, 0x49c9,
+ 0x8966, 0x1bc4,
+ 0x8967, 0x49ca,
+ 0x896a, 0x2187,
+ 0x896b, 0x49cd,
+ 0x896c, 0x266b,
+ 0x896d, 0x49ce,
+ 0x896f, 0x1e7f,
+ 0x8970, 0x49d0,
+ 0x8972, 0x21ad,
+ 0x8973, 0x49d2,
+ 0x897b, 0x1bc5,
+ 0x897c, 0x49da,
+ 0x897f, 0x0f06,
+ 0x8980, 0x49dd,
+ 0x8981, 0x1031,
+ 0x8982, 0x49de,
+ 0x8983, 0x1bdf,
+ 0x8984, 0x49df,
+ 0x8986, 0x06ad,
+ 0x8987, 0x49e1,
+ 0x898b, 0x1f96,
+ 0x898c, 0x49e5,
+ 0x898f, 0x1f32,
+ 0x8990, 0x49e8,
+ 0x8993, 0x2084,
+ 0x8994, 0x49eb,
+ 0x8996, 0x2136,
+ 0x8997, 0x49ed,
+ 0x8998, 0x24b8,
+ 0x8999, 0x49ee,
+ 0x89a1, 0x24ba,
+ 0x89a2, 0x49f6,
+ 0x89a6, 0x24bc,
+ 0x89a7, 0x49fa,
+ 0x89aa, 0x20e4,
+ 0x89ab, 0x49fd,
+ 0x89ac, 0x24b9,
+ 0x89ad, 0x49fe,
+ 0x89af, 0x24bd,
+ 0x89b0, 0x4a00,
+ 0x89b2, 0x24be,
+ 0x89b3, 0x4a02,
+ 0x89b7, 0x24bf,
+ 0x89b8, 0x4a06,
+ 0x89ba, 0x1fd2,
+ 0x89bb, 0x4a08,
+ 0x89bd, 0x1ffd,
+ 0x89be, 0x4a0a,
+ 0x89bf, 0x24bb,
+ 0x89c0, 0x1f2d,
+ 0x89c1, 0x086e,
+ 0x89c2, 0x0734,
+ 0x89c3, 0x4a0b,
+ 0x89c4, 0x073f,
+ 0x89c5, 0x0ade,
+ 0x89c6, 0x0d6a,
+ 0x89c7, 0x193a,
+ 0x89c8, 0x09ab,
+ 0x89c9, 0x0924,
+ 0x89ca, 0x193b,
+ 0x89cd, 0x4a0c,
+ 0x89ce, 0x193e,
+ 0x89d2, 0x0898,
+ 0x89d3, 0x4a0d,
+ 0x89d6, 0x1d57,
+ 0x89d7, 0x4a10,
+ 0x89da, 0x1d59,
+ 0x89db, 0x4a13,
+ 0x89dc, 0x1d5a,
+ 0x89dd, 0x4a14,
+ 0x89de, 0x1d58,
+ 0x89df, 0x4a15,
+ 0x89e3, 0x08b3,
+ 0x89e4, 0x4a19,
+ 0x89e5, 0x1d5b,
+ 0x89e6, 0x0528,
+ 0x89e7, 0x4a1a,
+ 0x89eb, 0x1d5c,
+ 0x89ec, 0x4a1e,
+ 0x89ef, 0x1d5d,
+ 0x89f0, 0x4a21,
+ 0x89f3, 0x19c0,
+ 0x89f4, 0x2609,
+ 0x89f5, 0x4a24,
+ 0x89f6, 0x260a,
+ 0x89f7, 0x4a25,
+ 0x89f8, 0x1e94,
+ 0x89f9, 0x4a26,
+ 0x8a00, 0x0ffd,
+ 0x8a01, 0x22df,
+ 0x8a02, 0x1ecb,
+ 0x8a03, 0x1f0d,
+ 0x8a04, 0x4a2d,
+ 0x8a07, 0x12fe,
+ 0x8a08, 0x1f77,
+ 0x8a09, 0x4a30,
+ 0x8a0a, 0x21eb,
+ 0x8a0b, 0x4a31,
+ 0x8a0c, 0x22e1,
+ 0x8a0d, 0x4a32,
+ 0x8a0e, 0x216f,
+ 0x8a0f, 0x4a33,
+ 0x8a10, 0x22e0,
+ 0x8a11, 0x4a34,
+ 0x8a13, 0x21ea,
+ 0x8a14, 0x4a36,
+ 0x8a15, 0x22e2,
+ 0x8a16, 0x20cb,
+ 0x8a17, 0x4a37,
+ 0x8a18, 0x1f78,
+ 0x8a19, 0x4a38,
+ 0x8a1b, 0x1ee2,
+ 0x8a1c, 0x4a3a,
+ 0x8a1d, 0x21f2,
+ 0x8a1e, 0x4a3b,
+ 0x8a1f, 0x2150,
+ 0x8a20, 0x4a3c,
+ 0x8a23, 0x1fd3,
+ 0x8a24, 0x4a3f,
+ 0x8a25, 0x22e5,
+ 0x8a26, 0x4a40,
+ 0x8a2a, 0x1ef2,
+ 0x8a2b, 0x4a44,
+ 0x8a2d, 0x211f,
+ 0x8a2e, 0x4a46,
+ 0x8a31, 0x21dd,
+ 0x8a32, 0x4a49,
+ 0x8a34, 0x2154,
+ 0x8a35, 0x4a4b,
+ 0x8a36, 0x22e7,
+ 0x8a37, 0x4a4c,
+ 0x8a3a, 0x2282,
+ 0x8a3b, 0x4a4f,
+ 0x8a3e, 0x1d5e,
+ 0x8a3f, 0x4a52,
+ 0x8a41, 0x22e6,
+ 0x8a42, 0x4a54,
+ 0x8a46, 0x22e8,
+ 0x8a47, 0x4a58,
+ 0x8a48, 0x1a84,
+ 0x8a49, 0x4a59,
+ 0x8a4e, 0x22e4,
+ 0x8a4f, 0x4a5e,
+ 0x8a50, 0x226a,
+ 0x8a51, 0x4a5f,
+ 0x8a52, 0x22eb,
+ 0x8a53, 0x4a60,
+ 0x8a54, 0x22e9,
+ 0x8a55, 0x20bd,
+ 0x8a56, 0x4a61,
+ 0x8a58, 0x22ea,
+ 0x8a59, 0x4a63,
+ 0x8a5b, 0x22bd,
+ 0x8a5c, 0x4a65,
+ 0x8a5e, 0x1e9e,
+ 0x8a5f, 0x4a67,
+ 0x8a61, 0x22f6,
+ 0x8a62, 0x21e7,
+ 0x8a63, 0x2216,
+ 0x8a64, 0x4a69,
+ 0x8a66, 0x2137,
+ 0x8a67, 0x4a6b,
+ 0x8a69, 0x212c,
+ 0x8a6a, 0x4a6d,
+ 0x8a6b, 0x1e68,
+ 0x8a6c, 0x22f2,
+ 0x8a6d, 0x1f37,
+ 0x8a6e, 0x22f3,
+ 0x8a6f, 0x4a6e,
+ 0x8a70, 0x22ef,
+ 0x8a71, 0x1f50,
+ 0x8a72, 0x1f10,
+ 0x8a73, 0x21c8,
+ 0x8a74, 0x4a6f,
+ 0x8a75, 0x22f1,
+ 0x8a76, 0x4a70,
+ 0x8a79, 0x1153,
+ 0x8a7a, 0x4a73,
+ 0x8a7c, 0x22f0,
+ 0x8a7d, 0x4a75,
+ 0x8a7f, 0x22ee,
+ 0x8a80, 0x4a77,
+ 0x8a84, 0x22ed,
+ 0x8a85, 0x229e,
+ 0x8a86, 0x22ec,
+ 0x8a87, 0x1fe2,
+ 0x8a88, 0x4a7b,
+ 0x8a89, 0x10e3,
+ 0x8a8a, 0x0e2f,
+ 0x8a8b, 0x4a7c,
+ 0x8a8d, 0x20fe,
+ 0x8a8e, 0x4a7e,
+ 0x8a91, 0x22f9,
+ 0x8a93, 0x0d5b,
+ 0x8a94, 0x4a81,
+ 0x8a95, 0x1eaf,
+ 0x8a96, 0x4a82,
+ 0x8a98, 0x2236,
+ 0x8a99, 0x4a84,
+ 0x8a9a, 0x22f7,
+ 0x8a9b, 0x4a85,
+ 0x8a9e, 0x223d,
+ 0x8a9f, 0x4a88,
+ 0x8aa0, 0x1e82,
+ 0x8aa1, 0x1fb6,
+ 0x8aa2, 0x4a89,
+ 0x8aa3, 0x21a4,
+ 0x8aa4, 0x21aa,
+ 0x8aa5, 0x22f8,
+ 0x8aa6, 0x2151,
+ 0x8aa7, 0x4a8a,
+ 0x8aa8, 0x1f60,
+ 0x8aa9, 0x4a8b,
+ 0x8aac, 0x2147,
+ 0x8aad, 0x4a8e,
+ 0x8ab0, 0x2145,
+ 0x8ab1, 0x4a91,
+ 0x8ab2, 0x1fdc,
+ 0x8ab3, 0x4a92,
+ 0x8ab6, 0x2301,
+ 0x8ab7, 0x4a95,
+ 0x8ab9, 0x1ef5,
+ 0x8aba, 0x4a97,
+ 0x8abc, 0x2218,
+ 0x8abd, 0x4a99,
+ 0x8abf, 0x1ec6,
+ 0x8ac0, 0x4a9b,
+ 0x8ac2, 0x2300,
+ 0x8ac3, 0x4a9d,
+ 0x8ac4, 0x22b4,
+ 0x8ac5, 0x4a9e,
+ 0x8ac7, 0x2169,
+ 0x8ac8, 0x4aa0,
+ 0x8ac9, 0x22fd,
+ 0x8aca, 0x4aa1,
+ 0x8acb, 0x20ea,
+ 0x8acc, 0x4aa2,
+ 0x8acd, 0x22f4,
+ 0x8ace, 0x4aa3,
+ 0x8acf, 0x22fb,
+ 0x8ad0, 0x4aa4,
+ 0x8ad1, 0x22fc,
+ 0x8ad2, 0x2027,
+ 0x8ad3, 0x4aa5,
+ 0x8ad6, 0x2060,
+ 0x8ad7, 0x22ff,
+ 0x8ad8, 0x4aa8,
+ 0x8adb, 0x22fe,
+ 0x8adc, 0x1ec7,
+ 0x8add, 0x4aab,
+ 0x8ade, 0x230c,
+ 0x8adf, 0x4aac,
+ 0x8ae2, 0x22f5,
+ 0x8ae3, 0x4aaf,
+ 0x8ae4, 0x2306,
+ 0x8ae5, 0x4ab0,
+ 0x8ae6, 0x230a,
+ 0x8ae7, 0x21d3,
+ 0x8ae8, 0x4ab1,
+ 0x8aeb, 0x2303,
+ 0x8aec, 0x4ab4,
+ 0x8aed, 0x2307,
+ 0x8aee, 0x230b,
+ 0x8aef, 0x4ab5,
+ 0x8af1, 0x1f5f,
+ 0x8af2, 0x4ab7,
+ 0x8af3, 0x2309,
+ 0x8af4, 0x4ab8,
+ 0x8af6, 0x2302,
+ 0x8af7, 0x1f04,
+ 0x8af8, 0x229d,
+ 0x8af9, 0x4aba,
+ 0x8afa, 0x21fb,
+ 0x8afb, 0x4abb,
+ 0x8afc, 0x2308,
+ 0x8afd, 0x4abc,
+ 0x8afe, 0x20ac,
+ 0x8aff, 0x4abd,
+ 0x8b00, 0x208e,
+ 0x8b01, 0x2305,
+ 0x8b02, 0x2197,
+ 0x8b03, 0x4abe,
+ 0x8b04, 0x2171,
+ 0x8b05, 0x2298,
+ 0x8b06, 0x4abf,
+ 0x8b07, 0x173c,
+ 0x8b08, 0x4ac0,
+ 0x8b0a, 0x1f57,
+ 0x8b0b, 0x4ac2,
+ 0x8b0e, 0x2082,
+ 0x8b0f, 0x4ac5,
+ 0x8b10, 0x2311,
+ 0x8b11, 0x4ac6,
+ 0x8b14, 0x2304,
+ 0x8b15, 0x4ac9,
+ 0x8b16, 0x230f,
+ 0x8b17, 0x1e35,
+ 0x8b18, 0x4aca,
+ 0x8b19, 0x20d1,
+ 0x8b1a, 0x2310,
+ 0x8b1b, 0x1fa3,
+ 0x8b1c, 0x4acb,
+ 0x8b1d, 0x21d6,
+ 0x8b1e, 0x4acc,
+ 0x8b21, 0x2206,
+ 0x8b22, 0x4acf,
+ 0x8b26, 0x1d5f,
+ 0x8b27, 0x4ad3,
+ 0x8b28, 0x230d,
+ 0x8b29, 0x4ad4,
+ 0x8b2b, 0x2312,
+ 0x8b2c, 0x208d,
+ 0x8b2d, 0x2313,
+ 0x8b2e, 0x4ad6,
+ 0x8b33, 0x22e3,
+ 0x8b34, 0x4adb,
+ 0x8b39, 0x1fba,
+ 0x8b3a, 0x4ae0,
+ 0x8b3e, 0x2078,
+ 0x8b3f, 0x4ae4,
+ 0x8b49, 0x2288,
+ 0x8b4a, 0x4aee,
+ 0x8b4e, 0x2316,
+ 0x8b4f, 0x1f6b,
+ 0x8b50, 0x4af2,
+ 0x8b56, 0x2314,
+ 0x8b57, 0x4af8,
+ 0x8b58, 0x2130,
+ 0x8b59, 0x2315,
+ 0x8b5a, 0x2168,
+ 0x8b5b, 0x4af9,
+ 0x8b5c, 0x20c4,
+ 0x8b5d, 0x4afa,
+ 0x8b66, 0x08de,
+ 0x8b67, 0x4b03,
+ 0x8b6b, 0x2318,
+ 0x8b6c, 0x0bc8,
+ 0x8b6d, 0x4b07,
+ 0x8b6f, 0x2219,
+ 0x8b70, 0x2217,
+ 0x8b71, 0x4b09,
+ 0x8b74, 0x20d5,
+ 0x8b75, 0x4b0c,
+ 0x8b77, 0x1f4a,
+ 0x8b78, 0x4b0e,
+ 0x8b7d, 0x2240,
+ 0x8b7e, 0x4b13,
+ 0x8b80, 0x1ed3,
+ 0x8b81, 0x4b15,
+ 0x8b8a, 0x1e49,
+ 0x8b8b, 0x4b1e,
+ 0x8b8e, 0x261b,
+ 0x8b8f, 0x4b21,
+ 0x8b92, 0x1e6d,
+ 0x8b93, 0x20f8,
+ 0x8b94, 0x4b24,
+ 0x8b95, 0x1ffb,
+ 0x8b96, 0x2319,
+ 0x8b97, 0x4b25,
+ 0x8b9c, 0x230e,
+ 0x8b9d, 0x4b2a,
+ 0x8b9e, 0x2317,
+ 0x8b9f, 0x4b2b,
+ 0x8ba0, 0x1317,
+ 0x8ba1, 0x0839,
+ 0x8ba2, 0x05e8,
+ 0x8ba3, 0x06b7,
+ 0x8ba4, 0x0caa,
+ 0x8ba5, 0x0818,
+ 0x8ba6, 0x1318,
+ 0x8ba8, 0x0e29,
+ 0x8ba9, 0x0c9e,
+ 0x8baa, 0x131a,
+ 0x8bab, 0x0c1c,
+ 0x8bac, 0x4b2c,
+ 0x8bad, 0x0fde,
+ 0x8bae, 0x1070,
+ 0x8baf, 0x0fdf,
+ 0x8bb0, 0x083a,
+ 0x8bb1, 0x4b2d,
+ 0x8bb2, 0x0883,
+ 0x8bb3, 0x07f9,
+ 0x8bb4, 0x131b,
+ 0x8bb6, 0x0ff1,
+ 0x8bb7, 0x131d,
+ 0x8bb8, 0x0fb8,
+ 0x8bb9, 0x062e,
+ 0x8bba, 0x0a82,
+ 0x8bbb, 0x4b2e,
+ 0x8bbc, 0x0dc4,
+ 0x8bbd, 0x068a,
+ 0x8bbe, 0x0d21,
+ 0x8bbf, 0x0660,
+ 0x8bc0, 0x0926,
+ 0x8bc1, 0x11a3,
+ 0x8bc2, 0x131e,
+ 0x8bc4, 0x0bdf,
+ 0x8bc5, 0x1244,
+ 0x8bc6, 0x0d4d,
+ 0x8bc7, 0x4b2f,
+ 0x8bc8, 0x114a,
+ 0x8bc9, 0x0dd4,
+ 0x8bca, 0x1190,
+ 0x8bcb, 0x1320,
+ 0x8bcc, 0x11de,
+ 0x8bcd, 0x054d,
+ 0x8bce, 0x1322,
+ 0x8bcf, 0x1321,
+ 0x8bd0, 0x4b30,
+ 0x8bd1, 0x1072,
+ 0x8bd2, 0x1323,
+ 0x8bd5, 0x0d6b,
+ 0x8bd6, 0x1326,
+ 0x8bd7, 0x0d42,
+ 0x8bd8, 0x1327,
+ 0x8bda, 0x04f4,
+ 0x8bdb, 0x11ee,
+ 0x8bdc, 0x1329,
+ 0x8bdd, 0x07c5,
+ 0x8bde, 0x058f,
+ 0x8bdf, 0x132a,
+ 0x8be1, 0x0747,
+ 0x8be2, 0x0fd8,
+ 0x8be3, 0x106f,
+ 0x8be4, 0x132c,
+ 0x8be5, 0x06be,
+ 0x8be6, 0x0f57,
+ 0x8be7, 0x04b6,
+ 0x8be8, 0x132d,
+ 0x8bea, 0x4b31,
+ 0x8beb, 0x08bc,
+ 0x8bec, 0x0eeb,
+ 0x8bed, 0x10d4,
+ 0x8bee, 0x132f,
+ 0x8bef, 0x0f02,
+ 0x8bf0, 0x1330,
+ 0x8bf1, 0x10ba,
+ 0x8bf2, 0x07fa,
+ 0x8bf3, 0x1331,
+ 0x8bf4, 0x0daa,
+ 0x8bf5, 0x0dc5,
+ 0x8bf6, 0x1332,
+ 0x8bf7, 0x0c68,
+ 0x8bf8, 0x11ed,
+ 0x8bf9, 0x1333,
+ 0x8bfa, 0x0b76,
+ 0x8bfb, 0x0600,
+ 0x8bfc, 0x1334,
+ 0x8bfd, 0x0669,
+ 0x8bfe, 0x095b,
+ 0x8bff, 0x1335,
+ 0x8c00, 0x1336,
+ 0x8c01, 0x0da2,
+ 0x8c02, 0x1337,
+ 0x8c03, 0x05d8,
+ 0x8c04, 0x1338,
+ 0x8c05, 0x0a0b,
+ 0x8c06, 0x1218,
+ 0x8c07, 0x1339,
+ 0x8c08, 0x0e0b,
+ 0x8c09, 0x4b32,
+ 0x8c0a, 0x1071,
+ 0x8c0b, 0x0b14,
+ 0x8c0c, 0x133a,
+ 0x8c0d, 0x05de,
+ 0x8c0e, 0x07e6,
+ 0x8c0f, 0x133b,
+ 0x8c10, 0x0f7e,
+ 0x8c11, 0x133c,
+ 0x8c13, 0x0ecc,
+ 0x8c14, 0x133e,
+ 0x8c17, 0x04be,
+ 0x8c18, 0x1343,
+ 0x8c19, 0x1341,
+ 0x8c1a, 0x1011,
+ 0x8c1b, 0x1342,
+ 0x8c1c, 0x0ada,
+ 0x8c1d, 0x1344,
+ 0x8c1e, 0x4b33,
+ 0x8c1f, 0x1345,
+ 0x8c22, 0x0f86,
+ 0x8c23, 0x102c,
+ 0x8c24, 0x0404,
+ 0x8c25, 0x1348,
+ 0x8c26, 0x0c28,
+ 0x8c27, 0x1349,
+ 0x8c28, 0x08c8,
+ 0x8c29, 0x0aa6,
+ 0x8c2a, 0x134a,
+ 0x8c2c, 0x0b02,
+ 0x8c2d, 0x0e0a,
+ 0x8c2e, 0x134c,
+ 0x8c30, 0x09a9,
+ 0x8c31, 0x0bf6,
+ 0x8c32, 0x134e,
+ 0x8c34, 0x0c31,
+ 0x8c35, 0x1350,
+ 0x8c37, 0x0721,
+ 0x8c38, 0x4b34,
+ 0x8c41, 0x0802,
+ 0x8c42, 0x4b3d,
+ 0x8c46, 0x05f8,
+ 0x8c47, 0x1cf6,
+ 0x8c48, 0x20c8,
+ 0x8c49, 0x1cf7,
+ 0x8c4a, 0x4b41,
+ 0x8c4c, 0x0e94,
+ 0x8c4d, 0x4b43,
+ 0x8c50, 0x1efd,
+ 0x8c51, 0x4b46,
+ 0x8c55, 0x1d15,
+ 0x8c56, 0x4b4a,
+ 0x8c5a, 0x1990,
+ 0x8c5b, 0x4b4e,
+ 0x8c61, 0x0f60,
+ 0x8c62, 0x07d4,
+ 0x8c63, 0x4b54,
+ 0x8c6a, 0x0777,
+ 0x8c6b, 0x10e8,
+ 0x8c6c, 0x4b5b,
+ 0x8c73, 0x15dd,
+ 0x8c74, 0x4b62,
+ 0x8c78, 0x1d50,
+ 0x8c79, 0x0413,
+ 0x8c7a, 0x04b9,
+ 0x8c7b, 0x4b66,
+ 0x8c82, 0x1d51,
+ 0x8c83, 0x4b6d,
+ 0x8c85, 0x1d53,
+ 0x8c86, 0x4b6f,
+ 0x8c89, 0x0788,
+ 0x8c8a, 0x1d52,
+ 0x8c8b, 0x4b72,
+ 0x8c8c, 0x0ab7,
+ 0x8c8d, 0x4b73,
+ 0x8c94, 0x1d55,
+ 0x8c95, 0x4b7a,
+ 0x8c98, 0x1d54,
+ 0x8c99, 0x4b7d,
+ 0x8c9d, 0x1e3b,
+ 0x8c9e, 0x227f,
+ 0x8c9f, 0x4b81,
+ 0x8ca0, 0x1f0c,
+ 0x8ca1, 0x1e59,
+ 0x8ca2, 0x1f24,
+ 0x8ca3, 0x4b82,
+ 0x8ca7, 0x20ba,
+ 0x8ca8, 0x1f65,
+ 0x8ca9, 0x1ef0,
+ 0x8caa, 0x2164,
+ 0x8cab, 0x1f30,
+ 0x8cac, 0x2261,
+ 0x8cad, 0x4b86,
+ 0x8caf, 0x22a2,
+ 0x8cb0, 0x24ab,
+ 0x8cb1, 0x4b88,
+ 0x8cb2, 0x24af,
+ 0x8cb3, 0x1ee8,
+ 0x8cb4, 0x1f39,
+ 0x8cb5, 0x4b89,
+ 0x8cb6, 0x1e48,
+ 0x8cb7, 0x2070,
+ 0x8cb8, 0x1ea8,
+ 0x8cb9, 0x4b8a,
+ 0x8cba, 0x24ac,
+ 0x8cbb, 0x1ef7,
+ 0x8cbc, 0x2176,
+ 0x8cbd, 0x24ad,
+ 0x8cbe, 0x4b8b,
+ 0x8cbf, 0x207b,
+ 0x8cc0, 0x1f45,
+ 0x8cc1, 0x24aa,
+ 0x8cc2, 0x204b,
+ 0x8cc3, 0x202f,
+ 0x8cc4, 0x1f5a,
+ 0x8cc5, 0x24b0,
+ 0x8cc6, 0x4b8c,
+ 0x8cc7, 0x22b7,
+ 0x8cc8, 0x1f7f,
+ 0x8cc9, 0x4b8d,
+ 0x8cca, 0x2265,
+ 0x8ccb, 0x4b8e,
+ 0x8cd1, 0x24b2,
+ 0x8cd2, 0x211b,
+ 0x8cd3, 0x1e51,
+ 0x8cd4, 0x4b94,
+ 0x8cd5, 0x24b4,
+ 0x8cd6, 0x4b95,
+ 0x8cda, 0x24b3,
+ 0x8cdb, 0x4b99,
+ 0x8cdc, 0x1e9f,
+ 0x8cdd, 0x4b9a,
+ 0x8cde, 0x2118,
+ 0x8cdf, 0x4b9b,
+ 0x8ce0, 0x20b4,
+ 0x8ce1, 0x23af,
+ 0x8ce2, 0x21bb,
+ 0x8ce3, 0x2072,
+ 0x8ce4, 0x1f95,
+ 0x8ce5, 0x4b9c,
+ 0x8ce6, 0x1f0a,
+ 0x8ce7, 0x24b6,
+ 0x8ce8, 0x4b9d,
+ 0x8cea, 0x2291,
+ 0x8ceb, 0x24b5,
+ 0x8cec, 0x2278,
+ 0x8ced, 0x1ed4,
+ 0x8cee, 0x4b9f,
+ 0x8cf4, 0x1ff3,
+ 0x8cf5, 0x4ba5,
+ 0x8cfa, 0x22a9,
+ 0x8cfb, 0x24b7,
+ 0x8cfc, 0x1f28,
+ 0x8cfd, 0x2109,
+ 0x8cfe, 0x22c7,
+ 0x8cff, 0x4baa,
+ 0x8d00, 0x4bab,
+ 0x8d04, 0x24ae,
+ 0x8d05, 0x22b1,
+ 0x8d06, 0x4baf,
+ 0x8d08, 0x2266,
+ 0x8d09, 0x4bb1,
+ 0x8d0a, 0x225b,
+ 0x8d0b, 0x22c4,
+ 0x8d0c, 0x4bb2,
+ 0x8d0d, 0x2115,
+ 0x8d0e, 0x4bb3,
+ 0x8d0f, 0x222a,
+ 0x8d10, 0x24b1,
+ 0x8d11, 0x4bb4,
+ 0x8d16, 0x213d,
+ 0x8d17, 0x4bb9,
+ 0x8d1b, 0x1f15,
+ 0x8d1c, 0x225c,
+ 0x8d1d, 0x041d,
+ 0x8d1e, 0x118b,
+ 0x8d1f, 0x06b5,
+ 0x8d20, 0x4bbd,
+ 0x8d21, 0x070a,
+ 0x8d22, 0x048d,
+ 0x8d23, 0x1133,
+ 0x8d24, 0x0f3a,
+ 0x8d25, 0x03e7,
+ 0x8d26, 0x116c,
+ 0x8d27, 0x080a,
+ 0x8d28, 0x11c9,
+ 0x8d29, 0x0654,
+ 0x8d2a, 0x0e03,
+ 0x8d2b, 0x0bd5,
+ 0x8d2c, 0x044a,
+ 0x8d2d, 0x0713,
+ 0x8d2e, 0x11fb,
+ 0x8d2f, 0x073a,
+ 0x8d30, 0x063e,
+ 0x8d31, 0x086d,
+ 0x8d32, 0x192c,
+ 0x8d34, 0x0e4c,
+ 0x8d35, 0x074c,
+ 0x8d36, 0x192e,
+ 0x8d37, 0x057e,
+ 0x8d38, 0x0ab8,
+ 0x8d39, 0x066e,
+ 0x8d3a, 0x078f,
+ 0x8d3b, 0x192f,
+ 0x8d3c, 0x1137,
+ 0x8d3d, 0x1930,
+ 0x8d3e, 0x0849,
+ 0x8d3f, 0x07f4,
+ 0x8d40, 0x1931,
+ 0x8d41, 0x0a27,
+ 0x8d42, 0x0a5f,
+ 0x8d43, 0x1122,
+ 0x8d44, 0x1227,
+ 0x8d45, 0x1932,
+ 0x8d47, 0x1936,
+ 0x8d48, 0x1934,
+ 0x8d4a, 0x0d17,
+ 0x8d4b, 0x06ae,
+ 0x8d4c, 0x0603,
+ 0x8d4d, 0x1937,
+ 0x8d4e, 0x0d81,
+ 0x8d4f, 0x0d06,
+ 0x8d50, 0x0550,
+ 0x8d51, 0x4bbe,
+ 0x8d53, 0x163b,
+ 0x8d54, 0x0ba3,
+ 0x8d55, 0x1938,
+ 0x8d56, 0x09a0,
+ 0x8d57, 0x4bc0,
+ 0x8d58, 0x1215,
+ 0x8d59, 0x1939,
+ 0x8d5a, 0x1209,
+ 0x8d5b, 0x0cd7,
+ 0x8d5c, 0x1289,
+ 0x8d5d, 0x1283,
+ 0x8d5e, 0x1121,
+ 0x8d5f, 0x4bc1,
+ 0x8d60, 0x113c,
+ 0x8d61, 0x0cfd,
+ 0x8d62, 0x1093,
+ 0x8d63, 0x06ce,
+ 0x8d64, 0x0505,
+ 0x8d65, 0x4bc2,
+ 0x8d66, 0x0d1b,
+ 0x8d67, 0x1cf4,
+ 0x8d68, 0x4bc3,
+ 0x8d6b, 0x078c,
+ 0x8d6c, 0x4bc6,
+ 0x8d6d, 0x1cf5,
+ 0x8d6e, 0x4bc7,
+ 0x8d70, 0x123c,
+ 0x8d71, 0x4bc9,
+ 0x8d73, 0x1cef,
+ 0x8d74, 0x06ab,
+ 0x8d75, 0x1175,
+ 0x8d76, 0x06ca,
+ 0x8d77, 0x0c0f,
+ 0x8d78, 0x4bcb,
+ 0x8d81, 0x04e8,
+ 0x8d82, 0x4bd4,
+ 0x8d84, 0x1cf0,
+ 0x8d85, 0x04d1,
+ 0x8d86, 0x4bd6,
+ 0x8d8a, 0x1100,
+ 0x8d8b, 0x0c74,
+ 0x8d8c, 0x4bda,
+ 0x8d91, 0x1cf2,
+ 0x8d92, 0x4bdf,
+ 0x8d94, 0x1cf1,
+ 0x8d95, 0x1f14,
+ 0x8d96, 0x4be1,
+ 0x8d99, 0x227a,
+ 0x8d9a, 0x4be4,
+ 0x8d9f, 0x0e1e,
+ 0x8da0, 0x4be9,
+ 0x8da3, 0x0c7f,
+ 0x8da4, 0x4bec,
+ 0x8da8, 0x20ee,
+ 0x8da9, 0x4bf0,
+ 0x8db1, 0x1cf3,
+ 0x8db2, 0x25f8,
+ 0x8db3, 0x1240,
+ 0x8db4, 0x0b80,
+ 0x8db5, 0x1d1c,
+ 0x8db6, 0x4bf8,
+ 0x8db8, 0x1d17,
+ 0x8db9, 0x4bfa,
+ 0x8dba, 0x1d1f,
+ 0x8dbb, 0x4bfb,
+ 0x8dbc, 0x1d1e,
+ 0x8dbd, 0x4bfc,
+ 0x8dbe, 0x11b9,
+ 0x8dbf, 0x1d1d,
+ 0x8dc0, 0x4bfd,
+ 0x8dc3, 0x1101,
+ 0x8dc4, 0x1d20,
+ 0x8dc5, 0x4c00,
+ 0x8dc6, 0x1d28,
+ 0x8dc7, 0x4c01,
+ 0x8dcb, 0x03da,
+ 0x8dcc, 0x05d9,
+ 0x8dcd, 0x4c05,
+ 0x8dce, 0x1d25,
+ 0x8dd0, 0x4c06,
+ 0x8dd1, 0x0b9d,
+ 0x8dd2, 0x4c07,
+ 0x8dd6, 0x1d21,
+ 0x8dd8, 0x4c0b,
+ 0x8dda, 0x1d23,
+ 0x8ddb, 0x1d27,
+ 0x8ddc, 0x4c0d,
+ 0x8ddd, 0x090f,
+ 0x8dde, 0x1d24,
+ 0x8ddf, 0x06f5,
+ 0x8de0, 0x4c0e,
+ 0x8de3, 0x1d2c,
+ 0x8de4, 0x1d2f,
+ 0x8de5, 0x4c11,
+ 0x8de8, 0x0974,
+ 0x8de9, 0x4c14,
+ 0x8dea, 0x074b,
+ 0x8deb, 0x1d18,
+ 0x8dec, 0x1d29,
+ 0x8ded, 0x4c15,
+ 0x8def, 0x0a5e,
+ 0x8df0, 0x4c17,
+ 0x8df3, 0x0e4b,
+ 0x8df4, 0x4c1a,
+ 0x8df5, 0x086c,
+ 0x8df6, 0x4c1b,
+ 0x8df7, 0x1d2a,
+ 0x8df9, 0x1d2d,
+ 0x8dfa, 0x0624,
+ 0x8dfb, 0x1d2e,
+ 0x8dfc, 0x4c1c,
+ 0x8dfd, 0x1d31,
+ 0x8dfe, 0x4c1d,
+ 0x8e00, 0x4c1f,
+ 0x8e05, 0x1d19,
+ 0x8e06, 0x4c24,
+ 0x8e09, 0x1d30,
+ 0x8e0a, 0x10a0,
+ 0x8e0b, 0x4c27,
+ 0x8e0c, 0x0511,
+ 0x8e0d, 0x4c28,
+ 0x8e0f, 0x0df7,
+ 0x8e10, 0x1f94,
+ 0x8e11, 0x4c2a,
+ 0x8e14, 0x1d32,
+ 0x8e15, 0x4c2d,
+ 0x8e1d, 0x1d33,
+ 0x8e1e, 0x0910,
+ 0x8e1f, 0x1d34,
+ 0x8e20, 0x4c35,
+ 0x8e22, 0x0e32,
+ 0x8e23, 0x1d37,
+ 0x8e24, 0x4c37,
+ 0x8e29, 0x048f,
+ 0x8e2a, 0x1236,
+ 0x8e2b, 0x4c3c,
+ 0x8e2c, 0x1d35,
+ 0x8e2d, 0x4c3d,
+ 0x8e2e, 0x1d36,
+ 0x8e2f, 0x1d38,
+ 0x8e30, 0x4c3e,
+ 0x8e31, 0x1d3e,
+ 0x8e32, 0x4c3f,
+ 0x8e34, 0x2230,
+ 0x8e35, 0x1d3c,
+ 0x8e36, 0x4c41,
+ 0x8e39, 0x1d3b,
+ 0x8e3a, 0x1d39,
+ 0x8e3b, 0x4c44,
+ 0x8e3d, 0x1d3d,
+ 0x8e3e, 0x4c46,
+ 0x8e40, 0x1d3a,
+ 0x8e41, 0x1d40,
+ 0x8e43, 0x4c48,
+ 0x8e44, 0x0e36,
+ 0x8e45, 0x4c49,
+ 0x8e47, 0x173b,
+ 0x8e48, 0x0599,
+ 0x8e49, 0x1d3f,
+ 0x8e4a, 0x1d44,
+ 0x8e4b, 0x0df6,
+ 0x8e4c, 0x25fd,
+ 0x8e4d, 0x4c4b,
+ 0x8e51, 0x1d42,
+ 0x8e53, 0x4c4f,
+ 0x8e55, 0x2600,
+ 0x8e56, 0x4c51,
+ 0x8e59, 0x1d1a,
+ 0x8e5a, 0x4c54,
+ 0x8e63, 0x2606,
+ 0x8e64, 0x4c5d,
+ 0x8e66, 0x042d,
+ 0x8e67, 0x4c5f,
+ 0x8e69, 0x1d1b,
+ 0x8e6a, 0x4c61,
+ 0x8e6c, 0x05a6,
+ 0x8e6d, 0x04ab,
+ 0x8e6e, 0x4c63,
+ 0x8e6f, 0x1d48,
+ 0x8e70, 0x1d45,
+ 0x8e71, 0x4c64,
+ 0x8e72, 0x0616,
+ 0x8e73, 0x4c65,
+ 0x8e74, 0x1d49,
+ 0x8e75, 0x4c66,
+ 0x8e76, 0x1d46,
+ 0x8e77, 0x4c67,
+ 0x8e7a, 0x25ff,
+ 0x8e7b, 0x4c6a,
+ 0x8e7c, 0x1d47,
+ 0x8e7d, 0x4c6b,
+ 0x8e7f, 0x055d,
+ 0x8e80, 0x4c6d,
+ 0x8e81, 0x112d,
+ 0x8e82, 0x4c6e,
+ 0x8e85, 0x1d4a,
+ 0x8e86, 0x4c71,
+ 0x8e87, 0x051e,
+ 0x8e88, 0x4c72,
+ 0x8e89, 0x25fc,
+ 0x8e8a, 0x1e8c,
+ 0x8e8b, 0x2602,
+ 0x8e8c, 0x4c73,
+ 0x8e8d, 0x224d,
+ 0x8e8e, 0x4c74,
+ 0x8e8f, 0x1d4b,
+ 0x8e90, 0x1d4d,
+ 0x8e91, 0x2604,
+ 0x8e92, 0x25fe,
+ 0x8e93, 0x2603,
+ 0x8e94, 0x1d4c,
+ 0x8e95, 0x4c75,
+ 0x8e9a, 0x2601,
+ 0x8e9b, 0x4c7a,
+ 0x8e9c, 0x1d4e,
+ 0x8e9d, 0x4c7b,
+ 0x8e9e, 0x1d4f,
+ 0x8e9f, 0x4c7c,
+ 0x8ea1, 0x2605,
+ 0x8ea2, 0x4c7e,
+ 0x8ea5, 0x1ea3,
+ 0x8ea6, 0x2608,
+ 0x8ea7, 0x4c81,
+ 0x8eaa, 0x2607,
+ 0x8eab, 0x0d26,
+ 0x8eac, 0x0703,
+ 0x8ead, 0x4c84,
+ 0x8eaf, 0x0c78,
+ 0x8eb0, 0x4c86,
+ 0x8eb2, 0x0622,
+ 0x8eb3, 0x4c88,
+ 0x8eba, 0x0e1c,
+ 0x8ebb, 0x4c8f,
+ 0x8ec0, 0x20f0,
+ 0x8ec1, 0x4c94,
+ 0x8eca, 0x1e7b,
+ 0x8ecb, 0x2267,
+ 0x8ecc, 0x1f36,
+ 0x8ecd, 0x1fd6,
+ 0x8ece, 0x18f8,
+ 0x8ecf, 0x4c9d,
+ 0x8ed2, 0x21e0,
+ 0x8ed3, 0x4ca0,
+ 0x8ed4, 0x248c,
+ 0x8ed5, 0x4ca1,
+ 0x8edb, 0x248d,
+ 0x8edc, 0x4ca7,
+ 0x8edf, 0x2102,
+ 0x8ee0, 0x4caa,
+ 0x8ee4, 0x2494,
+ 0x8ee5, 0x4cae,
+ 0x8eeb, 0x2493,
+ 0x8eec, 0x4cb4,
+ 0x8ef2, 0x248e,
+ 0x8ef3, 0x4cba,
+ 0x8ef8, 0x2299,
+ 0x8ef9, 0x2491,
+ 0x8efa, 0x2496,
+ 0x8efb, 0x248f,
+ 0x8efc, 0x2492,
+ 0x8efd, 0x4cbf,
+ 0x8efe, 0x2497,
+ 0x8eff, 0x4cc0,
+ 0x8f00, 0x4cc1,
+ 0x8f03, 0x1fb1,
+ 0x8f04, 0x4cc4,
+ 0x8f05, 0x249a,
+ 0x8f06, 0x4cc5,
+ 0x8f07, 0x2499,
+ 0x8f08, 0x4cc6,
+ 0x8f09, 0x2258,
+ 0x8f0a, 0x2498,
+ 0x8f0b, 0x4cc7,
+ 0x8f12, 0x249b,
+ 0x8f13, 0x4cce,
+ 0x8f14, 0x1f09,
+ 0x8f15, 0x20e6,
+ 0x8f16, 0x4ccf,
+ 0x8f1b, 0x2026,
+ 0x8f1c, 0x249f,
+ 0x8f1d, 0x1f59,
+ 0x8f1e, 0x249d,
+ 0x8f20, 0x4cd4,
+ 0x8f25, 0x1f3b,
+ 0x8f26, 0x249c,
+ 0x8f27, 0x4cd9,
+ 0x8f29, 0x1e3a,
+ 0x8f2a, 0x205b,
+ 0x8f2b, 0x4cdb,
+ 0x8f2f, 0x1f70,
+ 0x8f30, 0x4cdf,
+ 0x8f33, 0x24a0,
+ 0x8f34, 0x4ce2,
+ 0x8f38, 0x213b,
+ 0x8f39, 0x4ce6,
+ 0x8f3b, 0x1f07,
+ 0x8f3c, 0x4ce8,
+ 0x8f3e, 0x2270,
+ 0x8f3f, 0x2237,
+ 0x8f40, 0x4cea,
+ 0x8f42, 0x24d2,
+ 0x8f43, 0x4cec,
+ 0x8f44, 0x21b3,
+ 0x8f45, 0x2245,
+ 0x8f46, 0x24a1,
+ 0x8f47, 0x4ced,
+ 0x8f49, 0x22a8,
+ 0x8f4a, 0x4cef,
+ 0x8f4d, 0x227c,
+ 0x8f4e, 0x1fb0,
+ 0x8f4f, 0x4cf2,
+ 0x8f54, 0x24a2,
+ 0x8f55, 0x4cf7,
+ 0x8f5f, 0x1f46,
+ 0x8f60, 0x4d01,
+ 0x8f61, 0x2380,
+ 0x8f62, 0x2495,
+ 0x8f63, 0x4d02,
+ 0x8f64, 0x2490,
+ 0x8f65, 0x4d03,
+ 0x8f66, 0x04da,
+ 0x8f67, 0x1141,
+ 0x8f68, 0x0745,
+ 0x8f69, 0x0fc4,
+ 0x8f6a, 0x4d04,
+ 0x8f6b, 0x18e1,
+ 0x8f6c, 0x1207,
+ 0x8f6d, 0x18e2,
+ 0x8f6e, 0x0a7d,
+ 0x8f6f, 0x0cc8,
+ 0x8f70, 0x079b,
+ 0x8f71, 0x18e3,
+ 0x8f74, 0x11e0,
+ 0x8f75, 0x18e6,
+ 0x8f77, 0x18e9,
+ 0x8f78, 0x18e8,
+ 0x8f79, 0x18ea,
+ 0x8f7b, 0x0c5e,
+ 0x8f7c, 0x18ec,
+ 0x8f7d, 0x111b,
+ 0x8f7e, 0x18ed,
+ 0x8f7f, 0x089f,
+ 0x8f80, 0x4d05,
+ 0x8f81, 0x18ee,
+ 0x8f83, 0x08a0,
+ 0x8f84, 0x18f0,
+ 0x8f85, 0x06a3,
+ 0x8f86, 0x0a07,
+ 0x8f87, 0x18f1,
+ 0x8f88, 0x041b,
+ 0x8f89, 0x07e9,
+ 0x8f8a, 0x074e,
+ 0x8f8b, 0x18f2,
+ 0x8f8c, 0x4d06,
+ 0x8f8d, 0x18f3,
+ 0x8f90, 0x0695,
+ 0x8f91, 0x0820,
+ 0x8f92, 0x4d07,
+ 0x8f93, 0x0d7b,
+ 0x8f94, 0x1574,
+ 0x8f95, 0x10f2,
+ 0x8f96, 0x0f2a,
+ 0x8f97, 0x1158,
+ 0x8f98, 0x18f6,
+ 0x8f99, 0x117f,
+ 0x8f9a, 0x18f7,
+ 0x8f9b, 0x0f8c,
+ 0x8f9c, 0x0715,
+ 0x8f9d, 0x4d08,
+ 0x8f9e, 0x054a,
+ 0x8f9f, 0x0442,
+ 0x8fa0, 0x4d09,
+ 0x8fa3, 0x099c,
+ 0x8fa4, 0x4d0c,
+ 0x8fa6, 0x1e30,
+ 0x8fa7, 0x4d0e,
+ 0x8fa8, 0x044f,
+ 0x8faa, 0x4d0f,
+ 0x8fab, 0x0451,
+ 0x8fac, 0x4d10,
+ 0x8fad, 0x1e9d,
+ 0x8fae, 0x1e4b,
+ 0x8faf, 0x1e4a,
+ 0x8fb0, 0x04e2,
+ 0x8fb1, 0x0cc3,
+ 0x8fb2, 0x20aa,
+ 0x8fb3, 0x4d11,
+ 0x8fb6, 0x173d,
+ 0x8fb7, 0x4d14,
+ 0x8fb9, 0x0448,
+ 0x8fba, 0x4d16,
+ 0x8fbd, 0x0a12,
+ 0x8fbe, 0x0572,
+ 0x8fbf, 0x4d19,
+ 0x8fc1, 0x0c25,
+ 0x8fc2, 0x10bd,
+ 0x8fc3, 0x4d1b,
+ 0x8fc4, 0x0c18,
+ 0x8fc5, 0x0fe1,
+ 0x8fc6, 0x4d1c,
+ 0x8fc7, 0x0756,
+ 0x8fc8, 0x0a9c,
+ 0x8fc9, 0x4d1d,
+ 0x8fce, 0x1092,
+ 0x8fcf, 0x4d22,
+ 0x8fd0, 0x110e,
+ 0x8fd1, 0x08cd,
+ 0x8fd2, 0x4d23,
+ 0x8fd3, 0x173e,
+ 0x8fd4, 0x0652,
+ 0x8fd5, 0x173f,
+ 0x8fd6, 0x4d24,
+ 0x8fd8, 0x07ce,
+ 0x8fd9, 0x1183,
+ 0x8fda, 0x4d26,
+ 0x8fdb, 0x08c9,
+ 0x8fdc, 0x10f9,
+ 0x8fdd, 0x0eb4,
+ 0x8fde, 0x09f5,
+ 0x8fdf, 0x04fe,
+ 0x8fe0, 0x4d27,
+ 0x8fe2, 0x0e49,
+ 0x8fe3, 0x4d29,
+ 0x8fe4, 0x1742,
+ 0x8fe5, 0x1740,
+ 0x8fe6, 0x1744,
+ 0x8fe7, 0x4d2a,
+ 0x8fe8, 0x1746,
+ 0x8fe9, 0x1743,
+ 0x8fea, 0x05b0,
+ 0x8feb, 0x0be7,
+ 0x8fec, 0x4d2b,
+ 0x8fed, 0x05dd,
+ 0x8fee, 0x1741,
+ 0x8fef, 0x4d2c,
+ 0x8ff0, 0x0d8d,
+ 0x8ff1, 0x4d2d,
+ 0x8ff3, 0x1745,
+ 0x8ff4, 0x267b,
+ 0x8ff5, 0x4d2f,
+ 0x8ff7, 0x0ad9,
+ 0x8ff8, 0x042e,
+ 0x8ff9, 0x0816,
+ 0x8ffa, 0x4d31,
+ 0x8ffd, 0x1214,
+ 0x8ffe, 0x4d34,
+ 0x9000, 0x0e7c,
+ 0x9001, 0x0dc2,
+ 0x9002, 0x0d61,
+ 0x9003, 0x0e26,
+ 0x9004, 0x1748,
+ 0x9005, 0x1747,
+ 0x9006, 0x0b49,
+ 0x9007, 0x4d36,
+ 0x9009, 0x0fca,
+ 0x900a, 0x0fe0,
+ 0x900b, 0x1749,
+ 0x900c, 0x4d38,
+ 0x900d, 0x174c,
+ 0x900e, 0x4d39,
+ 0x900f, 0x0e69,
+ 0x9010, 0x11ef,
+ 0x9011, 0x174b,
+ 0x9012, 0x05be,
+ 0x9013, 0x4d3a,
+ 0x9014, 0x0e6f,
+ 0x9015, 0x23f2,
+ 0x9016, 0x174d,
+ 0x9017, 0x05f9,
+ 0x9018, 0x4d3b,
+ 0x9019, 0x227e,
+ 0x901a, 0x0e59,
+ 0x901b, 0x073d,
+ 0x901c, 0x4d3c,
+ 0x901d, 0x0d5c,
+ 0x901e, 0x04f6,
+ 0x901f, 0x0dce,
+ 0x9020, 0x112f,
+ 0x9021, 0x174e,
+ 0x9022, 0x0687,
+ 0x9023, 0x2019,
+ 0x9024, 0x4d3d,
+ 0x9026, 0x174a,
+ 0x9027, 0x4d3f,
+ 0x902d, 0x1751,
+ 0x902e, 0x0581,
+ 0x902f, 0x1752,
+ 0x9030, 0x4d45,
+ 0x9032, 0x1fbb,
+ 0x9033, 0x4d47,
+ 0x9035, 0x174f,
+ 0x9037, 0x4d49,
+ 0x9038, 0x1064,
+ 0x9039, 0x4d4a,
+ 0x903b, 0x0a86,
+ 0x903c, 0x042f,
+ 0x903d, 0x4d4c,
+ 0x903e, 0x10c7,
+ 0x903f, 0x4d4d,
+ 0x9041, 0x061c,
+ 0x9042, 0x0de1,
+ 0x9043, 0x4d4f,
+ 0x9044, 0x1753,
+ 0x9045, 0x4d50,
+ 0x9047, 0x10db,
+ 0x9048, 0x4d52,
+ 0x904b, 0x2253,
+ 0x904c, 0x4d55,
+ 0x904d, 0x0452,
+ 0x904e, 0x1f3e,
+ 0x904f, 0x0633,
+ 0x9050, 0x1756,
+ 0x9051, 0x1754,
+ 0x9053, 0x05a1,
+ 0x9054, 0x1ea6,
+ 0x9055, 0x218e,
+ 0x9056, 0x4d56,
+ 0x9057, 0x104c,
+ 0x9058, 0x1758,
+ 0x9059, 0x4d57,
+ 0x905b, 0x175a,
+ 0x905c, 0x21ec,
+ 0x905d, 0x4d59,
+ 0x905e, 0x1ebe,
+ 0x905f, 0x4d5a,
+ 0x9060, 0x224a,
+ 0x9061, 0x4d5b,
+ 0x9062, 0x1759,
+ 0x9063, 0x0c2f,
+ 0x9064, 0x4d5c,
+ 0x9065, 0x102a,
+ 0x9066, 0x4d5d,
+ 0x9068, 0x1757,
+ 0x9069, 0x2133,
+ 0x906a, 0x4d5f,
+ 0x906d, 0x1125,
+ 0x906e, 0x117b,
+ 0x906f, 0x4d62,
+ 0x9072, 0x1e84,
+ 0x9073, 0x4d65,
+ 0x9074, 0x175c,
+ 0x9075, 0x124e,
+ 0x9076, 0x4d66,
+ 0x9077, 0x20cf,
+ 0x9078, 0x21e2,
+ 0x9079, 0x4d67,
+ 0x907a, 0x220f,
+ 0x907b, 0x4d68,
+ 0x907c, 0x2029,
+ 0x907d, 0x175d,
+ 0x907e, 0x4d69,
+ 0x907f, 0x0445,
+ 0x9080, 0x1024,
+ 0x9081, 0x2073,
+ 0x9082, 0x175e,
+ 0x9083, 0x1760,
+ 0x9084, 0x1f55,
+ 0x9085, 0x4d6a,
+ 0x9087, 0x23f1,
+ 0x9088, 0x175f,
+ 0x9089, 0x4d6c,
+ 0x908a, 0x1e46,
+ 0x908b, 0x1761,
+ 0x908c, 0x4d6d,
+ 0x908f, 0x2063,
+ 0x9090, 0x23f3,
+ 0x9091, 0x105f,
+ 0x9092, 0x4d70,
+ 0x9093, 0x05ac,
+ 0x9094, 0x4d71,
+ 0x9095, 0x1817,
+ 0x9096, 0x4d72,
+ 0x9097, 0x1367,
+ 0x9098, 0x4d73,
+ 0x9099, 0x136a,
+ 0x909a, 0x4d74,
+ 0x909b, 0x1368,
+ 0x909c, 0x4d75,
+ 0x909d, 0x1369,
+ 0x909e, 0x4d76,
+ 0x90a1, 0x136c,
+ 0x90a2, 0x0f9a,
+ 0x90a3, 0x0b2a,
+ 0x90a4, 0x4d79,
+ 0x90a6, 0x03f9,
+ 0x90a7, 0x4d7b,
+ 0x90aa, 0x0f7b,
+ 0x90ab, 0x4d7e,
+ 0x90ac, 0x136b,
+ 0x90ad, 0x4d7f,
+ 0x90ae, 0x10af,
+ 0x90af, 0x0761,
+ 0x90b0, 0x1372,
+ 0x90b1, 0x0c6e,
+ 0x90b2, 0x4d80,
+ 0x90b3, 0x136e,
+ 0x90b4, 0x136d,
+ 0x90b5, 0x0d14,
+ 0x90b6, 0x136f,
+ 0x90b7, 0x4d81,
+ 0x90b8, 0x1371,
+ 0x90b9, 0x123b,
+ 0x90ba, 0x1370,
+ 0x90bb, 0x0a23,
+ 0x90bc, 0x4d82,
+ 0x90be, 0x1375,
+ 0x90bf, 0x4d84,
+ 0x90c1, 0x10d9,
+ 0x90c2, 0x4d86,
+ 0x90c4, 0x1377,
+ 0x90c5, 0x1374,
+ 0x90c6, 0x4d88,
+ 0x90c7, 0x1378,
+ 0x90c8, 0x4d89,
+ 0x90ca, 0x088d,
+ 0x90cb, 0x4d8b,
+ 0x90ce, 0x09b4,
+ 0x90cf, 0x1373,
+ 0x90d0, 0x1376,
+ 0x90d1, 0x11a2,
+ 0x90d2, 0x4d8e,
+ 0x90d3, 0x1379,
+ 0x90d4, 0x4d8f,
+ 0x90d7, 0x137d,
+ 0x90d8, 0x4d92,
+ 0x90db, 0x137e,
+ 0x90dc, 0x137c,
+ 0x90dd, 0x0779,
+ 0x90de, 0x4d95,
+ 0x90df, 0x231e,
+ 0x90e0, 0x4d96,
+ 0x90e1, 0x0931,
+ 0x90e2, 0x137b,
+ 0x90e3, 0x4d97,
+ 0x90e6, 0x137a,
+ 0x90e7, 0x110a,
+ 0x90e8, 0x0486,
+ 0x90e9, 0x4d9a,
+ 0x90eb, 0x137f,
+ 0x90ec, 0x4d9c,
+ 0x90ed, 0x0752,
+ 0x90ee, 0x4d9d,
+ 0x90ef, 0x1380,
+ 0x90f0, 0x4d9e,
+ 0x90f4, 0x04e0,
+ 0x90f5, 0x2233,
+ 0x90f6, 0x4da2,
+ 0x90f8, 0x0587,
+ 0x90f9, 0x4da4,
+ 0x90fd, 0x05fb,
+ 0x90fe, 0x1381,
+ 0x90ff, 0x4da8,
+ 0x9100, 0x4da9,
+ 0x9102, 0x0634,
+ 0x9103, 0x4dab,
+ 0x9104, 0x1382,
+ 0x9105, 0x4dac,
+ 0x9106, 0x2320,
+ 0x9107, 0x4dad,
+ 0x9109, 0x21c7,
+ 0x910a, 0x4daf,
+ 0x9112, 0x22bc,
+ 0x9113, 0x4db7,
+ 0x9114, 0x231c,
+ 0x9115, 0x4db8,
+ 0x9116, 0x2251,
+ 0x9117, 0x4db9,
+ 0x9119, 0x0432,
+ 0x911a, 0x4dbb,
+ 0x911e, 0x1384,
+ 0x911f, 0x4dbf,
+ 0x9122, 0x1383,
+ 0x9123, 0x1385,
+ 0x9124, 0x4dc2,
+ 0x9127, 0x1ebb,
+ 0x9128, 0x4dc5,
+ 0x912d, 0x2287,
+ 0x912e, 0x4dca,
+ 0x912f, 0x1387,
+ 0x9130, 0x202d,
+ 0x9131, 0x1386,
+ 0x9132, 0x1eab,
+ 0x9133, 0x4dcb,
+ 0x9134, 0x231d,
+ 0x9135, 0x4dcc,
+ 0x9136, 0x231f,
+ 0x9137, 0x4dcd,
+ 0x9139, 0x1388,
+ 0x913a, 0x231b,
+ 0x913b, 0x4dcf,
+ 0x9143, 0x1389,
+ 0x9144, 0x4dd7,
+ 0x9146, 0x138a,
+ 0x9147, 0x4dd9,
+ 0x9148, 0x2321,
+ 0x9149, 0x10b4,
+ 0x914a, 0x1cf8,
+ 0x914b, 0x0c72,
+ 0x914c, 0x1220,
+ 0x914d, 0x0ba5,
+ 0x914e, 0x1cfa,
+ 0x9150, 0x1cf9,
+ 0x9151, 0x4dda,
+ 0x9152, 0x08f5,
+ 0x9153, 0x4ddb,
+ 0x9157, 0x0fba,
+ 0x9158, 0x4ddf,
+ 0x915a, 0x0670,
+ 0x915b, 0x4de1,
+ 0x915d, 0x1110,
+ 0x915e, 0x0dfd,
+ 0x915f, 0x4de3,
+ 0x9161, 0x1cfe,
+ 0x9162, 0x1cfd,
+ 0x9163, 0x075f,
+ 0x9164, 0x1cfc,
+ 0x9165, 0x0dcb,
+ 0x9166, 0x4de5,
+ 0x9169, 0x1d00,
+ 0x916a, 0x09bd,
+ 0x916b, 0x4de8,
+ 0x916c, 0x050f,
+ 0x916d, 0x4de9,
+ 0x916e, 0x0e5b,
+ 0x916f, 0x1d01,
+ 0x9170, 0x1cff,
+ 0x9171, 0x0885,
+ 0x9172, 0x1d04,
+ 0x9173, 0x4dea,
+ 0x9174, 0x1d05,
+ 0x9175, 0x089e,
+ 0x9176, 0x0abd,
+ 0x9177, 0x096e,
+ 0x9178, 0x0dd6,
+ 0x9179, 0x1d06,
+ 0x917a, 0x4deb,
+ 0x917d, 0x1d02,
+ 0x917f, 0x0b53,
+ 0x9180, 0x4dee,
+ 0x9185, 0x1d08,
+ 0x9186, 0x4df3,
+ 0x9187, 0x053f,
+ 0x9188, 0x4df4,
+ 0x9189, 0x124a,
+ 0x918a, 0x4df5,
+ 0x918b, 0x055a,
+ 0x918c, 0x1d07,
+ 0x918d, 0x1d0a,
+ 0x918e, 0x4df6,
+ 0x9190, 0x1d09,
+ 0x9191, 0x1d0b,
+ 0x9192, 0x0f9c,
+ 0x9193, 0x4df8,
+ 0x9196, 0x2255,
+ 0x9197, 0x4dfb,
+ 0x919a, 0x0ad6,
+ 0x919b, 0x0c84,
+ 0x919c, 0x1e8f,
+ 0x919d, 0x4dfe,
+ 0x91a2, 0x1d0c,
+ 0x91a4, 0x4e03,
+ 0x91aa, 0x1d0e,
+ 0x91ab, 0x220c,
+ 0x91ac, 0x1fa4,
+ 0x91ad, 0x1d0f,
+ 0x91b0, 0x4e09,
+ 0x91b4, 0x1d13,
+ 0x91b5, 0x1d12,
+ 0x91b6, 0x4e0d,
+ 0x91ba, 0x1d14,
+ 0x91bb, 0x4e11,
+ 0x91c0, 0x209b,
+ 0x91c1, 0x21d8,
+ 0x91c2, 0x4e16,
+ 0x91c3, 0x25fa,
+ 0x91c4, 0x4e17,
+ 0x91c5, 0x25f9,
+ 0x91c6, 0x4e18,
+ 0x91c7, 0x0490,
+ 0x91c8, 0x4e19,
+ 0x91c9, 0x10b9,
+ 0x91ca, 0x0d64,
+ 0x91cb, 0x2134,
+ 0x91cc, 0x09da,
+ 0x91cd, 0x11d7,
+ 0x91ce, 0x1037,
+ 0x91cf, 0x0a08,
+ 0x91d0, 0x4e1a,
+ 0x91d1, 0x08c1,
+ 0x91d2, 0x24f3,
+ 0x91d5, 0x24f8,
+ 0x91d6, 0x4e1b,
+ 0x91d7, 0x24f7,
+ 0x91d8, 0x1ec8,
+ 0x91d9, 0x24f6,
+ 0x91da, 0x4e1c,
+ 0x91dc, 0x06a5,
+ 0x91dd, 0x2280,
+ 0x91de, 0x4e1e,
+ 0x91e3, 0x1ec5,
+ 0x91e4, 0x24fb,
+ 0x91e5, 0x4e23,
+ 0x91e7, 0x24fa,
+ 0x91e8, 0x4e25,
+ 0x91e9, 0x1eed,
+ 0x91ea, 0x4e26,
+ 0x91f5, 0x24fd,
+ 0x91f6, 0x4e31,
+ 0x91f7, 0x24f9,
+ 0x91f8, 0x4e32,
+ 0x91f9, 0x24fe,
+ 0x91fa, 0x20cd,
+ 0x91fb, 0x4e33,
+ 0x9200, 0x2508,
+ 0x9201, 0x2504,
+ 0x9202, 0x4e38,
+ 0x9204, 0x2506,
+ 0x9205, 0x4e3a,
+ 0x9208, 0x24ff,
+ 0x9209, 0x2090,
+ 0x920a, 0x4e3d,
+ 0x920d, 0x1edd,
+ 0x920e, 0x1f25,
+ 0x920f, 0x4e40,
+ 0x9210, 0x2503,
+ 0x9211, 0x2502,
+ 0x9212, 0x4e41,
+ 0x9214, 0x1e7a,
+ 0x9215, 0x20a6,
+ 0x9216, 0x4e43,
+ 0x921e, 0x1fd5,
+ 0x921f, 0x4e4b,
+ 0x9223, 0x1f11,
+ 0x9224, 0x4e4f,
+ 0x9225, 0x2507,
+ 0x9226, 0x2500,
+ 0x9227, 0x2505,
+ 0x9228, 0x4e50,
+ 0x922e, 0x2519,
+ 0x922f, 0x4e56,
+ 0x9230, 0x2515,
+ 0x9231, 0x4e57,
+ 0x9233, 0x250c,
+ 0x9234, 0x2031,
+ 0x9235, 0x4e59,
+ 0x9237, 0x250b,
+ 0x9238, 0x250f,
+ 0x9239, 0x251a,
+ 0x923a, 0x2509,
+ 0x923b, 0x4e5b,
+ 0x923d, 0x250e,
+ 0x923e, 0x2234,
+ 0x923f, 0x2513,
+ 0x9240, 0x1f80,
+ 0x9241, 0x4e5d,
+ 0x9245, 0x2501,
+ 0x9246, 0x4e61,
+ 0x9248, 0x2517,
+ 0x9249, 0x2516,
+ 0x924a, 0x4e63,
+ 0x924d, 0x2518,
+ 0x924e, 0x4e66,
+ 0x9251, 0x1e56,
+ 0x9252, 0x4e69,
+ 0x9255, 0x250d,
+ 0x9256, 0x4e6c,
+ 0x9257, 0x20d3,
+ 0x9258, 0x4e6d,
+ 0x925a, 0x207a,
+ 0x925b, 0x20ce,
+ 0x925c, 0x4e6f,
+ 0x925e, 0x2510,
+ 0x925f, 0x4e71,
+ 0x9262, 0x1e55,
+ 0x9263, 0x4e74,
+ 0x9266, 0x250a,
+ 0x9267, 0x4e77,
+ 0x926c, 0x2511,
+ 0x926e, 0x4e7c,
+ 0x9274, 0x086b,
+ 0x9275, 0x4e82,
+ 0x9278, 0x1faa,
+ 0x9279, 0x4e85,
+ 0x927a, 0x251e,
+ 0x927b, 0x1f1f,
+ 0x927c, 0x4e86,
+ 0x927f, 0x252d,
+ 0x9280, 0x221d,
+ 0x9281, 0x4e89,
+ 0x9283, 0x2532,
+ 0x9284, 0x4e8b,
+ 0x9285, 0x217b,
+ 0x9286, 0x4e8c,
+ 0x928e, 0x1d80,
+ 0x928f, 0x4e94,
+ 0x9291, 0x21af,
+ 0x9292, 0x4e96,
+ 0x9293, 0x252c,
+ 0x9294, 0x4e97,
+ 0x9296, 0x2528,
+ 0x9297, 0x4e99,
+ 0x9298, 0x208c,
+ 0x9299, 0x4e9a,
+ 0x929a, 0x252f,
+ 0x929b, 0x4e9b,
+ 0x929c, 0x21bc,
+ 0x929d, 0x4e9c,
+ 0x92a0, 0x251d,
+ 0x92a1, 0x4e9f,
+ 0x92a3, 0x2535,
+ 0x92a4, 0x4ea1,
+ 0x92a5, 0x220d,
+ 0x92a6, 0x2526,
+ 0x92a7, 0x4ea2,
+ 0x92a8, 0x2534,
+ 0x92a9, 0x252a,
+ 0x92aa, 0x251f,
+ 0x92ab, 0x2531,
+ 0x92ac, 0x251c,
+ 0x92ad, 0x4ea3,
+ 0x92ae, 0x1d81,
+ 0x92af, 0x4ea4,
+ 0x92b1, 0x2525,
+ 0x92b2, 0x4ea6,
+ 0x92b7, 0x21cd,
+ 0x92b8, 0x4eab,
+ 0x92b9, 0x21da,
+ 0x92ba, 0x4eac,
+ 0x92bb, 0x2172,
+ 0x92bc, 0x253e,
+ 0x92bd, 0x4ead,
+ 0x92c1, 0x204f,
+ 0x92c2, 0x4eb1,
+ 0x92c3, 0x2543,
+ 0x92c4, 0x4eb2,
+ 0x92c5, 0x21d7,
+ 0x92c6, 0x4eb3,
+ 0x92c7, 0x1e3c,
+ 0x92c8, 0x1d82,
+ 0x92c9, 0x4eb4,
+ 0x92cc, 0x2529,
+ 0x92cd, 0x4eb7,
+ 0x92cf, 0x2521,
+ 0x92d0, 0x4eb9,
+ 0x92d2, 0x1eff,
+ 0x92d3, 0x4ebb,
+ 0x92dd, 0x253f,
+ 0x92de, 0x4ec5,
+ 0x92df, 0x2544,
+ 0x92e0, 0x4ec6,
+ 0x92e3, 0x2523,
+ 0x92e4, 0x1e90,
+ 0x92e5, 0x253a,
+ 0x92e6, 0x2545,
+ 0x92e7, 0x4ec9,
+ 0x92e8, 0x253d,
+ 0x92e9, 0x4eca,
+ 0x92ea, 0x20c1,
+ 0x92eb, 0x4ecb,
+ 0x92ed, 0x2103,
+ 0x92ee, 0x2520,
+ 0x92ef, 0x253c,
+ 0x92f0, 0x253b,
+ 0x92f1, 0x2538,
+ 0x92f2, 0x4ecd,
+ 0x92f6, 0x2540,
+ 0x92f7, 0x4ed1,
+ 0x92f8, 0x1fcd,
+ 0x92f9, 0x4ed2,
+ 0x92fc, 0x1f18,
+ 0x92fd, 0x4ed5,
+ 0x9300, 0x4ed8,
+ 0x9301, 0x254b,
+ 0x9302, 0x4ed9,
+ 0x9306, 0x2547,
+ 0x9307, 0x254f,
+ 0x9309, 0x4edd,
+ 0x9310, 0x22b0,
+ 0x9311, 0x4ee4,
+ 0x9312, 0x2546,
+ 0x9313, 0x4ee5,
+ 0x9315, 0x254c,
+ 0x9316, 0x4ee7,
+ 0x9318, 0x1e9a,
+ 0x9319, 0x2552,
+ 0x931a, 0x2530,
+ 0x931b, 0x2549,
+ 0x931c, 0x4ee9,
+ 0x931f, 0x2551,
+ 0x9320, 0x1eca,
+ 0x9321, 0x4eec,
+ 0x9322, 0x20d2,
+ 0x9323, 0x4eed,
+ 0x9326, 0x1fb8,
+ 0x9327, 0x4ef0,
+ 0x9328, 0x2079,
+ 0x9329, 0x4ef1,
+ 0x932b, 0x21ab,
+ 0x932c, 0x4ef3,
+ 0x932e, 0x254d,
+ 0x932f, 0x1ea5,
+ 0x9330, 0x4ef5,
+ 0x9332, 0x204c,
+ 0x9333, 0x2080,
+ 0x9334, 0x4ef7,
+ 0x9336, 0x266d,
+ 0x9337, 0x4ef9,
+ 0x9338, 0x2537,
+ 0x9339, 0x4efa,
+ 0x933e, 0x1d83,
+ 0x933f, 0x4eff,
+ 0x9340, 0x254a,
+ 0x9341, 0x21b8,
+ 0x9342, 0x4f00,
+ 0x9343, 0x254e,
+ 0x9344, 0x4f01,
+ 0x9346, 0x24fc,
+ 0x9347, 0x2554,
+ 0x9348, 0x4f03,
+ 0x934b, 0x1f3c,
+ 0x934c, 0x4f06,
+ 0x934d, 0x1ed5,
+ 0x934e, 0x4f07,
+ 0x9354, 0x2556,
+ 0x9355, 0x4f0d,
+ 0x9358, 0x2268,
+ 0x9359, 0x4f10,
+ 0x935b, 0x1ed6,
+ 0x935c, 0x4f12,
+ 0x9364, 0x2557,
+ 0x9365, 0x2553,
+ 0x9366, 0x4f1a,
+ 0x9369, 0x2548,
+ 0x936a, 0x1d84,
+ 0x936b, 0x4f1d,
+ 0x936c, 0x20dc,
+ 0x936d, 0x4f1e,
+ 0x9370, 0x2559,
+ 0x9371, 0x4f21,
+ 0x9375, 0x1f97,
+ 0x9376, 0x2555,
+ 0x9377, 0x4f25,
+ 0x937a, 0x227d,
+ 0x937b, 0x4f28,
+ 0x937e, 0x257e,
+ 0x937f, 0x4f2b,
+ 0x9382, 0x207c,
+ 0x9383, 0x4f2e,
+ 0x9384, 0x255a,
+ 0x9385, 0x4f2f,
+ 0x9387, 0x255e,
+ 0x9388, 0x4f31,
+ 0x938a, 0x1e34,
+ 0x938b, 0x4f33,
+ 0x938f, 0x1d86,
+ 0x9390, 0x4f37,
+ 0x9396, 0x215e,
+ 0x9397, 0x4f3d,
+ 0x9398, 0x2560,
+ 0x9399, 0x4f3e,
+ 0x93a2, 0x21a2,
+ 0x93a3, 0x2354,
+ 0x93a4, 0x4f47,
+ 0x93a6, 0x2563,
+ 0x93a7, 0x2527,
+ 0x93a8, 0x4f49,
+ 0x93a9, 0x252e,
+ 0x93aa, 0x2558,
+ 0x93ab, 0x4f4a,
+ 0x93ac, 0x1f1b,
+ 0x93ad, 0x4f4b,
+ 0x93ae, 0x2283,
+ 0x93af, 0x4f4c,
+ 0x93b0, 0x2564,
+ 0x93b1, 0x4f4d,
+ 0x93b3, 0x20a0,
+ 0x93b4, 0x4f4f,
+ 0x93b5, 0x2565,
+ 0x93b6, 0x4f50,
+ 0x93b8, 0x2561,
+ 0x93b9, 0x4f52,
+ 0x93bf, 0x2562,
+ 0x93c0, 0x4f58,
+ 0x93c3, 0x256c,
+ 0x93c4, 0x4f5b,
+ 0x93c7, 0x256d,
+ 0x93c8, 0x2020,
+ 0x93c9, 0x4f5e,
+ 0x93ca, 0x1d85,
+ 0x93cb, 0x4f5f,
+ 0x93cc, 0x255f,
+ 0x93cd, 0x256a,
+ 0x93ce, 0x4f60,
+ 0x93d1, 0x256e,
+ 0x93d2, 0x4f63,
+ 0x93d6, 0x1e01,
+ 0x93d7, 0x2539,
+ 0x93d8, 0x255c,
+ 0x93d9, 0x4f67,
+ 0x93dc, 0x2568,
+ 0x93de, 0x256b,
+ 0x93df, 0x1e6f,
+ 0x93e0, 0x4f6a,
+ 0x93e1, 0x1fc4,
+ 0x93e2, 0x2567,
+ 0x93e3, 0x4f6b,
+ 0x93e4, 0x255b,
+ 0x93e5, 0x4f6c,
+ 0x93e8, 0x261d,
+ 0x93e9, 0x4f6f,
+ 0x93f5, 0x252b,
+ 0x93f6, 0x4f7b,
+ 0x93f7, 0x2571,
+ 0x93f8, 0x4f7c,
+ 0x93f9, 0x2577,
+ 0x93fa, 0x4f7d,
+ 0x9400, 0x4f83,
+ 0x9403, 0x2522,
+ 0x9404, 0x4f86,
+ 0x940b, 0x2533,
+ 0x940c, 0x4f8d,
+ 0x9410, 0x202a,
+ 0x9411, 0x4f91,
+ 0x9412, 0x2536,
+ 0x9413, 0x2573,
+ 0x9414, 0x256f,
+ 0x9415, 0x4f92,
+ 0x9418, 0x2293,
+ 0x9419, 0x2578,
+ 0x941a, 0x4f95,
+ 0x941d, 0x2570,
+ 0x941e, 0x4f98,
+ 0x9420, 0x2575,
+ 0x9421, 0x4f9a,
+ 0x9426, 0x2541,
+ 0x9428, 0x255d,
+ 0x9429, 0x4f9f,
+ 0x942e, 0x201a,
+ 0x942f, 0x4fa4,
+ 0x9432, 0x257a,
+ 0x9433, 0x2006,
+ 0x9434, 0x4fa7,
+ 0x9435, 0x2177,
+ 0x9436, 0x4fa8,
+ 0x9438, 0x251b,
+ 0x9439, 0x4faa,
+ 0x943a, 0x2524,
+ 0x943b, 0x4fab,
+ 0x943e, 0x1d87,
+ 0x943f, 0x257b,
+ 0x9440, 0x4fae,
+ 0x9444, 0x22a3,
+ 0x9445, 0x4fb2,
+ 0x944a, 0x2579,
+ 0x944b, 0x4fb7,
+ 0x944c, 0x2566,
+ 0x944d, 0x4fb8,
+ 0x9452, 0x1f93,
+ 0x9453, 0x4fbd,
+ 0x9454, 0x257c,
+ 0x9455, 0x4fbe,
+ 0x9460, 0x2514,
+ 0x9461, 0x4fc9,
+ 0x9463, 0x257d,
+ 0x9464, 0x4fcb,
+ 0x9465, 0x2572,
+ 0x9466, 0x4fcc,
+ 0x946b, 0x1d88,
+ 0x946c, 0x4fd1,
+ 0x946d, 0x2574,
+ 0x946e, 0x4fd2,
+ 0x9470, 0x224e,
+ 0x9471, 0x4fd4,
+ 0x9472, 0x21c6,
+ 0x9473, 0x4fd5,
+ 0x9477, 0x209f,
+ 0x9478, 0x4fd9,
+ 0x9479, 0x2576,
+ 0x947a, 0x4fda,
+ 0x947c, 0x2064,
+ 0x947d, 0x22bf,
+ 0x947e, 0x261c,
+ 0x947f, 0x225e,
+ 0x9480, 0x4fdc,
+ 0x9485, 0x1a8e,
+ 0x9488, 0x118c,
+ 0x9489, 0x05e3,
+ 0x948a, 0x1a92,
+ 0x948b, 0x1a91,
+ 0x948c, 0x1a93,
+ 0x948e, 0x0c22,
+ 0x948f, 0x1a95,
+ 0x9491, 0x4fe1,
+ 0x9492, 0x064d,
+ 0x9493, 0x05d7,
+ 0x9494, 0x1a97,
+ 0x9495, 0x1a99,
+ 0x9496, 0x4fe2,
+ 0x9497, 0x1a98,
+ 0x9498, 0x4fe3,
+ 0x9499, 0x06c1,
+ 0x949a, 0x1a9a,
+ 0x949d, 0x061a,
+ 0x949e, 0x04d3,
+ 0x949f, 0x11d2,
+ 0x94a0, 0x0b29,
+ 0x94a1, 0x041e,
+ 0x94a2, 0x06d1,
+ 0x94a3, 0x1a9d,
+ 0x94a5, 0x1102,
+ 0x94a6, 0x0c52,
+ 0x94a7, 0x092a,
+ 0x94a8, 0x0ee8,
+ 0x94a9, 0x070c,
+ 0x94aa, 0x1aa0,
+ 0x94ab, 0x1a9f,
+ 0x94ac, 0x1aa2,
+ 0x94ad, 0x1aa1,
+ 0x94ae, 0x0b66,
+ 0x94af, 0x1aa3,
+ 0x94b1, 0x0c2b,
+ 0x94b2, 0x1aa5,
+ 0x94b3, 0x0c2c,
+ 0x94b4, 0x1aa6,
+ 0x94b5, 0x046e,
+ 0x94b6, 0x1aa7,
+ 0x94bb, 0x1247,
+ 0x94bc, 0x1aac,
+ 0x94be, 0x084b,
+ 0x94bf, 0x1aae,
+ 0x94c0, 0x10b0,
+ 0x94c1, 0x0e4d,
+ 0x94c2, 0x0473,
+ 0x94c3, 0x0a2e,
+ 0x94c4, 0x1aaf,
+ 0x94c5, 0x0c23,
+ 0x94c6, 0x0ab2,
+ 0x94c7, 0x4fe4,
+ 0x94c8, 0x1ab0,
+ 0x94cf, 0x4fe5,
+ 0x94d0, 0x1ab7,
+ 0x94d3, 0x4fe6,
+ 0x94d5, 0x1aba,
+ 0x94d8, 0x1abe,
+ 0x94d9, 0x1abd,
+ 0x94da, 0x4fe8,
+ 0x94db, 0x1abf,
+ 0x94dc, 0x0e5e,
+ 0x94dd, 0x0a68,
+ 0x94de, 0x1ac0,
+ 0x94e1, 0x1142,
+ 0x94e2, 0x1ac3,
+ 0x94e3, 0x0f20,
+ 0x94e4, 0x1ac4,
+ 0x94e6, 0x4fe9,
+ 0x94e7, 0x1ac6,
+ 0x94e9, 0x1ac9,
+ 0x94ea, 0x1ac8,
+ 0x94eb, 0x1aca,
+ 0x94ec, 0x06f0,
+ 0x94ed, 0x0aff,
+ 0x94ee, 0x1acb,
+ 0x94f0, 0x0893,
+ 0x94f1, 0x1046,
+ 0x94f2, 0x04c0,
+ 0x94f3, 0x1acd,
+ 0x94f6, 0x107f,
+ 0x94f7, 0x1ad0,
+ 0x94f8, 0x11fc,
+ 0x94f9, 0x1ad1,
+ 0x94fa, 0x0beb,
+ 0x94fb, 0x4fea,
+ 0x94fc, 0x1ad2,
+ 0x94fe, 0x09fd,
+ 0x94ff, 0x1ad4,
+ 0x9500, 0x0f67,
+ 0x9501, 0x0ded,
+ 0x9502, 0x1ad6,
+ 0x9503, 0x1ad5,
+ 0x9504, 0x051f,
+ 0x9505, 0x0751,
+ 0x9506, 0x1ad7,
+ 0x9508, 0x0fad,
+ 0x9509, 0x1ad9,
+ 0x950b, 0x0683,
+ 0x950c, 0x0f8a,
+ 0x950d, 0x1adb,
+ 0x9510, 0x0ccc,
+ 0x9511, 0x0e33,
+ 0x9512, 0x1ade,
+ 0x9517, 0x1181,
+ 0x9518, 0x1ae3,
+ 0x9519, 0x0570,
+ 0x951a, 0x0aaf,
+ 0x951b, 0x1ae4,
+ 0x951c, 0x4feb,
+ 0x951d, 0x1ae5,
+ 0x9520, 0x4fec,
+ 0x9521, 0x0f0c,
+ 0x9522, 0x1ae8,
+ 0x9523, 0x0a87,
+ 0x9524, 0x053b,
+ 0x9525, 0x1213,
+ 0x9526, 0x08c6,
+ 0x9527, 0x4fed,
+ 0x9528, 0x0f34,
+ 0x9529, 0x1aeb,
+ 0x952a, 0x1ae9,
+ 0x952c, 0x1aec,
+ 0x952d, 0x05e6,
+ 0x952e, 0x086f,
+ 0x952f, 0x0911,
+ 0x9530, 0x0ad1,
+ 0x9531, 0x1aed,
+ 0x9533, 0x4fee,
+ 0x9534, 0x1aef,
+ 0x9535, 0x1af7,
+ 0x9536, 0x1af0,
+ 0x9539, 0x0c3f,
+ 0x953a, 0x1b19,
+ 0x953b, 0x060c,
+ 0x953c, 0x1af3,
+ 0x953d, 0x4fef,
+ 0x953e, 0x1af4,
+ 0x9540, 0x0605,
+ 0x9541, 0x0ac3,
+ 0x9542, 0x1af6,
+ 0x9543, 0x4ff0,
+ 0x9544, 0x1af8,
+ 0x9547, 0x1193,
+ 0x9548, 0x4ff1,
+ 0x9549, 0x1afb,
+ 0x954a, 0x0b5a,
+ 0x954b, 0x4ff2,
+ 0x954c, 0x1afc,
+ 0x954d, 0x0b5b,
+ 0x954e, 0x1afd,
+ 0x9550, 0x06df,
+ 0x9551, 0x0402,
+ 0x9552, 0x1aff,
+ 0x9555, 0x4ff3,
+ 0x9556, 0x1b02,
+ 0x955a, 0x4ff4,
+ 0x955b, 0x1b06,
+ 0x955c, 0x08e4,
+ 0x955d, 0x1b09,
+ 0x955e, 0x1b07,
+ 0x9560, 0x4ff5,
+ 0x9561, 0x1b0a,
+ 0x9563, 0x0a16,
+ 0x9564, 0x1b0c,
+ 0x956d, 0x09c3,
+ 0x956e, 0x4ff6,
+ 0x956f, 0x1b15,
+ 0x9570, 0x09f6,
+ 0x9571, 0x1b16,
+ 0x9574, 0x4ff7,
+ 0x9576, 0x0f4f,
+ 0x9577, 0x1e75,
+ 0x9578, 0x4ff9,
+ 0x957f, 0x04c9,
+ 0x9580, 0x207d,
+ 0x9581, 0x5000,
+ 0x9582, 0x23bf,
+ 0x9583, 0x2113,
+ 0x9584, 0x5001,
+ 0x9586, 0x23c0,
+ 0x9587, 0x5003,
+ 0x9589, 0x1e45,
+ 0x958a, 0x5005,
+ 0x958b, 0x1fd8,
+ 0x958c, 0x23c4,
+ 0x958d, 0x5006,
+ 0x958e, 0x23c2,
+ 0x958f, 0x2104,
+ 0x9590, 0x5007,
+ 0x9591, 0x21bd,
+ 0x9592, 0x5008,
+ 0x9593, 0x1f87,
+ 0x9594, 0x23c3,
+ 0x9595, 0x5009,
+ 0x9598, 0x2269,
+ 0x9599, 0x500c,
+ 0x95a1, 0x1f43,
+ 0x95a2, 0x5014,
+ 0x95a3, 0x1f1e,
+ 0x95a4, 0x2679,
+ 0x95a5, 0x1eeb,
+ 0x95a6, 0x5015,
+ 0x95a8, 0x1f35,
+ 0x95a9, 0x208a,
+ 0x95aa, 0x5017,
+ 0x95ab, 0x23c7,
+ 0x95ac, 0x23c9,
+ 0x95ad, 0x23c6,
+ 0x95ae, 0x5018,
+ 0x95b2, 0x224f,
+ 0x95b3, 0x501c,
+ 0x95b6, 0x23cb,
+ 0x95b7, 0x501f,
+ 0x95b9, 0x21f3,
+ 0x95ba, 0x5021,
+ 0x95bb, 0x21f7,
+ 0x95bc, 0x23cf,
+ 0x95bd, 0x23ce,
+ 0x95be, 0x23ca,
+ 0x95bf, 0x23cd,
+ 0x95c0, 0x5022,
+ 0x95c3, 0x23d0,
+ 0x95c4, 0x5025,
+ 0x95c6, 0x266c,
+ 0x95c7, 0x5027,
+ 0x95c8, 0x23c1,
+ 0x95c9, 0x5028,
+ 0x95ca, 0x1fee,
+ 0x95cb, 0x23d1,
+ 0x95cc, 0x1ff8,
+ 0x95cd, 0x5029,
+ 0x95d0, 0x23d3,
+ 0x95d1, 0x502c,
+ 0x95d4, 0x23d2,
+ 0x95d5, 0x23d4,
+ 0x95d6, 0x1e98,
+ 0x95d7, 0x502f,
+ 0x95dc, 0x1f2c,
+ 0x95dd, 0x5034,
+ 0x95de, 0x23d5,
+ 0x95df, 0x5035,
+ 0x95e1, 0x1e71,
+ 0x95e2, 0x2691,
+ 0x95e3, 0x5037,
+ 0x95e5, 0x23c5,
+ 0x95e6, 0x5039,
+ 0x95e8, 0x0aca,
+ 0x95e9, 0x1685,
+ 0x95ea, 0x0cfa,
+ 0x95eb, 0x1686,
+ 0x95ec, 0x503b,
+ 0x95ed, 0x043e,
+ 0x95ee, 0x0ed9,
+ 0x95ef, 0x0536,
+ 0x95f0, 0x0ccd,
+ 0x95f1, 0x1687,
+ 0x95f2, 0x0f3d,
+ 0x95f3, 0x1688,
+ 0x95f4, 0x0857,
+ 0x95f5, 0x1689,
+ 0x95f7, 0x0acb,
+ 0x95f8, 0x1143,
+ 0x95f9, 0x0b39,
+ 0x95fa, 0x0744,
+ 0x95fb, 0x0ed4,
+ 0x95fc, 0x168b,
+ 0x95fd, 0x0afb,
+ 0x95fe, 0x168c,
+ 0x95ff, 0x503c,
+ 0x9600, 0x0644,
+ 0x9601, 0x06ee,
+ 0x9602, 0x0789,
+ 0x9603, 0x168d,
+ 0x9605, 0x1107,
+ 0x9606, 0x168f,
+ 0x9607, 0x503d,
+ 0x9608, 0x1690,
+ 0x9609, 0x0ff4,
+ 0x960a, 0x1691,
+ 0x960e, 0x0fff,
+ 0x960f, 0x1695,
+ 0x9610, 0x04c2,
+ 0x9611, 0x09a6,
+ 0x9612, 0x1696,
+ 0x9613, 0x503e,
+ 0x9614, 0x0996,
+ 0x9615, 0x1697,
+ 0x9618, 0x503f,
+ 0x9619, 0x169a,
+ 0x961b, 0x5040,
+ 0x961c, 0x06b2,
+ 0x961d, 0x1354,
+ 0x961e, 0x5041,
+ 0x961f, 0x0612,
+ 0x9620, 0x5042,
+ 0x9621, 0x1356,
+ 0x9622, 0x1355,
+ 0x9623, 0x5043,
+ 0x962a, 0x1358,
+ 0x962b, 0x504a,
+ 0x962e, 0x0cc9,
+ 0x962f, 0x504d,
+ 0x9631, 0x1357,
+ 0x9632, 0x065d,
+ 0x9633, 0x101d,
+ 0x9634, 0x107c,
+ 0x9635, 0x1194,
+ 0x9636, 0x08a8,
+ 0x9637, 0x504f,
+ 0x963b, 0x1245,
+ 0x963c, 0x135a,
+ 0x963d, 0x1359,
+ 0x963e, 0x5053,
+ 0x963f, 0x03ad,
+ 0x9640, 0x0e84,
+ 0x9641, 0x5054,
+ 0x9642, 0x135b,
+ 0x9643, 0x5055,
+ 0x9644, 0x06b8,
+ 0x9645, 0x083d,
+ 0x9646, 0x0a64,
+ 0x9647, 0x0a4b,
+ 0x9648, 0x04e7,
+ 0x9649, 0x135c,
+ 0x964a, 0x5056,
+ 0x964b, 0x0a51,
+ 0x964c, 0x0b13,
+ 0x964d, 0x0886,
+ 0x964e, 0x5057,
+ 0x9650, 0x0f4b,
+ 0x9651, 0x5059,
+ 0x9654, 0x135d,
+ 0x9655, 0x0cfb,
+ 0x9656, 0x505c,
+ 0x9658, 0x231a,
+ 0x9659, 0x505e,
+ 0x965b, 0x0446,
+ 0x965c, 0x5060,
+ 0x965d, 0x2114,
+ 0x965e, 0x5061,
+ 0x965f, 0x135e,
+ 0x9660, 0x5062,
+ 0x9661, 0x05f7,
+ 0x9662, 0x10fd,
+ 0x9663, 0x2284,
+ 0x9664, 0x0522,
+ 0x9665, 0x5063,
+ 0x9667, 0x135f,
+ 0x9668, 0x110c,
+ 0x9669, 0x0f42,
+ 0x966a, 0x0ba4,
+ 0x966b, 0x5065,
+ 0x966c, 0x1360,
+ 0x966d, 0x5066,
+ 0x9670, 0x221c,
+ 0x9671, 0x5069,
+ 0x9672, 0x1361,
+ 0x9673, 0x1e7e,
+ 0x9674, 0x1362,
+ 0x9675, 0x0a33,
+ 0x9676, 0x0e28,
+ 0x9677, 0x0f4a,
+ 0x9678, 0x204d,
+ 0x9679, 0x506a,
+ 0x967d, 0x2201,
+ 0x967e, 0x506e,
+ 0x9685, 0x10cc,
+ 0x9686, 0x0a48,
+ 0x9687, 0x5075,
+ 0x9688, 0x1363,
+ 0x9689, 0x5076,
+ 0x968a, 0x1ed9,
+ 0x968b, 0x0dda,
+ 0x968c, 0x5077,
+ 0x968d, 0x1364,
+ 0x968e, 0x1fb2,
+ 0x968f, 0x0ddb,
+ 0x9690, 0x1085,
+ 0x9691, 0x5078,
+ 0x9694, 0x06ef,
+ 0x9695, 0x2252,
+ 0x9696, 0x507b,
+ 0x9697, 0x1365,
+ 0x9698, 0x03ba,
+ 0x9699, 0x0f23,
+ 0x969a, 0x507c,
+ 0x969b, 0x1f79,
+ 0x969c, 0x1170,
+ 0x969d, 0x507d,
+ 0x96a7, 0x0de2,
+ 0x96a8, 0x2157,
+ 0x96a9, 0x5087,
+ 0x96aa, 0x21bf,
+ 0x96ab, 0x5088,
+ 0x96b0, 0x1366,
+ 0x96b1, 0x221f,
+ 0x96b2, 0x508d,
+ 0x96b3, 0x1684,
+ 0x96b4, 0x203d,
+ 0x96b5, 0x508e,
+ 0x96b6, 0x09ee,
+ 0x96b7, 0x508f,
+ 0x96b8, 0x2015,
+ 0x96b9, 0x1d79,
+ 0x96ba, 0x5090,
+ 0x96bb, 0x26a5,
+ 0x96bc, 0x1d7a,
+ 0x96be, 0x0b34,
+ 0x96bf, 0x5091,
+ 0x96c0, 0x0c93,
+ 0x96c1, 0x100c,
+ 0x96c2, 0x5092,
+ 0x96c4, 0x0fa6,
+ 0x96c5, 0x0fee,
+ 0x96c6, 0x0822,
+ 0x96c7, 0x0726,
+ 0x96c8, 0x5094,
+ 0x96c9, 0x1b1c,
+ 0x96ca, 0x5095,
+ 0x96cc, 0x0549,
+ 0x96cd, 0x109f,
+ 0x96ce, 0x1d7c,
+ 0x96cf, 0x0520,
+ 0x96d0, 0x5097,
+ 0x96d2, 0x1d7d,
+ 0x96d3, 0x5099,
+ 0x96d5, 0x05d2,
+ 0x96d6, 0x2156,
+ 0x96d7, 0x509b,
+ 0x96d9, 0x2144,
+ 0x96da, 0x509d,
+ 0x96db, 0x1e91,
+ 0x96dc, 0x2257,
+ 0x96dd, 0x509e,
+ 0x96e0, 0x1d7f,
+ 0x96e1, 0x50a1,
+ 0x96e2, 0x200a,
+ 0x96e3, 0x2092,
+ 0x96e4, 0x50a2,
+ 0x96e8, 0x10cf,
+ 0x96e9, 0x1d61,
+ 0x96ea, 0x0fd2,
+ 0x96eb, 0x50a6,
+ 0x96ef, 0x1d63,
+ 0x96f0, 0x50aa,
+ 0x96f2, 0x2250,
+ 0x96f3, 0x1d62,
+ 0x96f4, 0x50ac,
+ 0x96f6, 0x0a2c,
+ 0x96f7, 0x09c2,
+ 0x96f8, 0x50ae,
+ 0x96f9, 0x040b,
+ 0x96fa, 0x50af,
+ 0x96fb, 0x1ec3,
+ 0x96fc, 0x50b0,
+ 0x96fe, 0x0efc,
+ 0x96ff, 0x50b2,
+ 0x9700, 0x0fb3,
+ 0x9701, 0x1d65,
+ 0x9702, 0x50b3,
+ 0x9704, 0x0f63,
+ 0x9705, 0x50b5,
+ 0x9706, 0x1d64,
+ 0x9707, 0x1191,
+ 0x9708, 0x1d66,
+ 0x9709, 0x0abe,
+ 0x970a, 0x50b6,
+ 0x970d, 0x0809,
+ 0x970e, 0x1d68,
+ 0x970f, 0x1d67,
+ 0x9710, 0x50b9,
+ 0x9713, 0x0b41,
+ 0x9714, 0x50bc,
+ 0x9716, 0x0a21,
+ 0x9717, 0x50be,
+ 0x971c, 0x0d9f,
+ 0x971d, 0x50c3,
+ 0x971e, 0x0f29,
+ 0x971f, 0x50c4,
+ 0x9727, 0x21a8,
+ 0x9728, 0x50cc,
+ 0x972a, 0x1d69,
+ 0x972b, 0x50ce,
+ 0x972d, 0x1d6a,
+ 0x972e, 0x50d0,
+ 0x9730, 0x1d6b,
+ 0x9731, 0x50d2,
+ 0x9732, 0x0a5d,
+ 0x9733, 0x50d3,
+ 0x9738, 0x03df,
+ 0x9739, 0x0bba,
+ 0x973a, 0x50d8,
+ 0x973d, 0x260d,
+ 0x973e, 0x1d6c,
+ 0x973f, 0x50db,
+ 0x9742, 0x260c,
+ 0x9743, 0x50de,
+ 0x9744, 0x260e,
+ 0x9745, 0x50df,
+ 0x9748, 0x2032,
+ 0x9749, 0x50e2,
+ 0x9752, 0x0c5d,
+ 0x9753, 0x1d60,
+ 0x9754, 0x50eb,
+ 0x9756, 0x08e7,
+ 0x9757, 0x50ed,
+ 0x9759, 0x08e1,
+ 0x975a, 0x260b,
+ 0x975b, 0x05c6,
+ 0x975c, 0x50ef,
+ 0x975e, 0x0664,
+ 0x975f, 0x50f1,
+ 0x9760, 0x094c,
+ 0x9761, 0x0ad7,
+ 0x9762, 0x0aeb,
+ 0x9763, 0x50f2,
+ 0x9765, 0x1282,
+ 0x9766, 0x50f4,
+ 0x9768, 0x22c3,
+ 0x9769, 0x06ea,
+ 0x976a, 0x50f6,
+ 0x9773, 0x08ca,
+ 0x9774, 0x0fce,
+ 0x9775, 0x50ff,
+ 0x9776, 0x03db,
+ 0x9777, 0x5100,
+ 0x977c, 0x1dc8,
+ 0x977d, 0x5105,
+ 0x9785, 0x1dc9,
+ 0x9786, 0x510d,
+ 0x978b, 0x0f77,
+ 0x978c, 0x5112,
+ 0x978d, 0x03bb,
+ 0x978e, 0x5113,
+ 0x978f, 0x1f23,
+ 0x9790, 0x5114,
+ 0x9791, 0x1dca,
+ 0x9793, 0x5115,
+ 0x9794, 0x1dcc,
+ 0x9795, 0x5116,
+ 0x9798, 0x0c47,
+ 0x9799, 0x5119,
+ 0x97a0, 0x08fe,
+ 0x97a1, 0x5120,
+ 0x97a3, 0x1dcf,
+ 0x97a4, 0x5122,
+ 0x97a6, 0x2695,
+ 0x97a7, 0x5124,
+ 0x97ab, 0x1dce,
+ 0x97ac, 0x5128,
+ 0x97ad, 0x0447,
+ 0x97ae, 0x5129,
+ 0x97af, 0x1dcd,
+ 0x97b0, 0x512a,
+ 0x97b2, 0x1dd0,
+ 0x97b3, 0x512c,
+ 0x97b4, 0x1dd1,
+ 0x97b5, 0x512d,
+ 0x97bd, 0x265e,
+ 0x97be, 0x5135,
+ 0x97c3, 0x265d,
+ 0x97c4, 0x513a,
+ 0x97c6, 0x2692,
+ 0x97c7, 0x513c,
+ 0x97c9, 0x265f,
+ 0x97ca, 0x513e,
+ 0x97cb, 0x218d,
+ 0x97cc, 0x20fd,
+ 0x97cd, 0x513f,
+ 0x97d3, 0x1f40,
+ 0x97d4, 0x5145,
+ 0x97d9, 0x2465,
+ 0x97da, 0x514a,
+ 0x97dc, 0x2467,
+ 0x97dd, 0x514c,
+ 0x97de, 0x2466,
+ 0x97df, 0x514d,
+ 0x97e6, 0x0eb3,
+ 0x97e7, 0x0ca8,
+ 0x97e8, 0x5154,
+ 0x97e9, 0x0762,
+ 0x97ea, 0x184e,
+ 0x97ed, 0x08f1,
+ 0x97ee, 0x5155,
+ 0x97f3, 0x107b,
+ 0x97f4, 0x515a,
+ 0x97f5, 0x1112,
+ 0x97f6, 0x0d11,
+ 0x97f7, 0x515b,
+ 0x97ff, 0x21c9,
+ 0x9800, 0x5163,
+ 0x9801, 0x2209,
+ 0x9802, 0x1ec9,
+ 0x9803, 0x20e9,
+ 0x9804, 0x5164,
+ 0x9805, 0x21ca,
+ 0x9806, 0x2146,
+ 0x9807, 0x25c5,
+ 0x9808, 0x21dc,
+ 0x9809, 0x5165,
+ 0x980a, 0x245e,
+ 0x980b, 0x5166,
+ 0x980c, 0x214f,
+ 0x980d, 0x5167,
+ 0x980e, 0x25c6,
+ 0x9810, 0x2241,
+ 0x9811, 0x218a,
+ 0x9812, 0x1e2f,
+ 0x9813, 0x1edc,
+ 0x9814, 0x5168,
+ 0x9817, 0x20bf,
+ 0x9818, 0x2034,
+ 0x9819, 0x516b,
+ 0x981c, 0x25c9,
+ 0x981d, 0x516e,
+ 0x9821, 0x25c8,
+ 0x9822, 0x5172,
+ 0x9824, 0x220e,
+ 0x9825, 0x5174,
+ 0x9826, 0x25cb,
+ 0x9827, 0x5175,
+ 0x982d, 0x217d,
+ 0x982e, 0x517b,
+ 0x9830, 0x1f7e,
+ 0x9831, 0x517d,
+ 0x9837, 0x25cc,
+ 0x9838, 0x1fc3,
+ 0x9839, 0x5183,
+ 0x983b, 0x20b9,
+ 0x983c, 0x5185,
+ 0x983d, 0x2181,
+ 0x983e, 0x5186,
+ 0x9846, 0x1fda,
+ 0x9847, 0x518e,
+ 0x984c, 0x2173,
+ 0x984d, 0x1ee1,
+ 0x984e, 0x25cd,
+ 0x984f, 0x5193,
+ 0x9853, 0x25ce,
+ 0x9854, 0x21f6,
+ 0x9855, 0x5197,
+ 0x9858, 0x224b,
+ 0x9859, 0x25d1,
+ 0x985a, 0x519a,
+ 0x985b, 0x1ec0,
+ 0x985c, 0x519b,
+ 0x985e, 0x2008,
+ 0x985f, 0x519d,
+ 0x9862, 0x25d0,
+ 0x9863, 0x51a0,
+ 0x9865, 0x25d2,
+ 0x9866, 0x51a2,
+ 0x9867, 0x1f2a,
+ 0x9868, 0x51a3,
+ 0x986b, 0x1e72,
+ 0x986c, 0x25d3,
+ 0x986d, 0x51a6,
+ 0x986f, 0x21be,
+ 0x9870, 0x25d4,
+ 0x9871, 0x2044,
+ 0x9872, 0x51a8,
+ 0x9873, 0x25cf,
+ 0x9874, 0x20f3,
+ 0x9875, 0x103a,
+ 0x9876, 0x05e4,
+ 0x9877, 0x0c67,
+ 0x9878, 0x1be0,
+ 0x9879, 0x0f5b,
+ 0x987a, 0x0da8,
+ 0x987b, 0x0fb6,
+ 0x987c, 0x1827,
+ 0x987d, 0x0e98,
+ 0x987e, 0x0724,
+ 0x987f, 0x0618,
+ 0x9880, 0x1be1,
+ 0x9881, 0x03ef,
+ 0x9882, 0x0dc1,
+ 0x9883, 0x1be2,
+ 0x9884, 0x10e7,
+ 0x9885, 0x0a54,
+ 0x9886, 0x0a35,
+ 0x9887, 0x0be3,
+ 0x9888, 0x08e0,
+ 0x9889, 0x1be3,
+ 0x988a, 0x0848,
+ 0x988b, 0x51a9,
+ 0x988c, 0x1be4,
+ 0x988e, 0x51aa,
+ 0x988f, 0x1be6,
+ 0x9890, 0x104a,
+ 0x9891, 0x0bd4,
+ 0x9892, 0x51ab,
+ 0x9893, 0x0e78,
+ 0x9894, 0x1be7,
+ 0x9895, 0x51ac,
+ 0x9896, 0x1096,
+ 0x9897, 0x0952,
+ 0x9898, 0x0e35,
+ 0x9899, 0x51ad,
+ 0x989a, 0x1be8,
+ 0x989c, 0x0ffe,
+ 0x989d, 0x062d,
+ 0x989e, 0x1bea,
+ 0x98a0, 0x05c0,
+ 0x98a1, 0x1bec,
+ 0x98a3, 0x51ae,
+ 0x98a4, 0x04c3,
+ 0x98a5, 0x1bee,
+ 0x98a7, 0x0c82,
+ 0x98a8, 0x1f00,
+ 0x98a9, 0x51af,
+ 0x98ae, 0x24cc,
+ 0x98b0, 0x51b4,
+ 0x98b1, 0x2698,
+ 0x98b2, 0x51b5,
+ 0x98b3, 0x2678,
+ 0x98b4, 0x51b6,
+ 0x98b6, 0x24ce,
+ 0x98b7, 0x51b8,
+ 0x98bc, 0x24cf,
+ 0x98bd, 0x51bd,
+ 0x98c4, 0x20b8,
+ 0x98c5, 0x51c4,
+ 0x98c6, 0x24d0,
+ 0x98c7, 0x51c5,
+ 0x98c8, 0x24d1,
+ 0x98c9, 0x51c6,
+ 0x98ce, 0x0684,
+ 0x98cf, 0x51cb,
+ 0x98d1, 0x19b7,
+ 0x98d4, 0x51cd,
+ 0x98d5, 0x19ba,
+ 0x98d6, 0x51ce,
+ 0x98d8, 0x0bcd,
+ 0x98d9, 0x19bb,
+ 0x98db, 0x1ef4,
+ 0x98dc, 0x51d0,
+ 0x98de, 0x0666,
+ 0x98df, 0x0d4a,
+ 0x98e0, 0x239b,
+ 0x98e1, 0x51d2,
+ 0x98e2, 0x267e,
+ 0x98e3, 0x51d3,
+ 0x98e7, 0x161a,
+ 0x98e8, 0x1de7,
+ 0x98e9, 0x239d,
+ 0x98ea, 0x239f,
+ 0x98ec, 0x51d7,
+ 0x98ed, 0x23a1,
+ 0x98ee, 0x51d8,
+ 0x98ef, 0x1ef1,
+ 0x98f0, 0x51d9,
+ 0x98f2, 0x221e,
+ 0x98f3, 0x51db,
+ 0x98f4, 0x23a2,
+ 0x98f5, 0x51dc,
+ 0x98fc, 0x214b,
+ 0x98fd, 0x1e36,
+ 0x98fe, 0x2135,
+ 0x98ff, 0x51e3,
+ 0x9900, 0x51e4,
+ 0x9903, 0x1fad,
+ 0x9904, 0x51e7,
+ 0x9905, 0x1e53,
+ 0x9906, 0x51e8,
+ 0x9909, 0x23a3,
+ 0x990a, 0x2203,
+ 0x990b, 0x51eb,
+ 0x990c, 0x1ee7,
+ 0x990d, 0x1de8,
+ 0x990e, 0x51ec,
+ 0x9910, 0x0494,
+ 0x9911, 0x23a4,
+ 0x9912, 0x2097,
+ 0x9913, 0x1ee4,
+ 0x9914, 0x51ee,
+ 0x9918, 0x2238,
+ 0x9919, 0x51f2,
+ 0x991b, 0x23a5,
+ 0x991c, 0x51f4,
+ 0x991e, 0x1f9a,
+ 0x991f, 0x51f6,
+ 0x9921, 0x21c3,
+ 0x9922, 0x51f8,
+ 0x9928, 0x1f2e,
+ 0x9929, 0x51fe,
+ 0x992e, 0x1de9,
+ 0x992f, 0x5203,
+ 0x9933, 0x239c,
+ 0x9934, 0x5207,
+ 0x9937, 0x23a6,
+ 0x9938, 0x520a,
+ 0x993c, 0x239e,
+ 0x993d, 0x520e,
+ 0x993e, 0x2035,
+ 0x993f, 0x23a7,
+ 0x9940, 0x520f,
+ 0x9943, 0x23a8,
+ 0x9944, 0x5212,
+ 0x9945, 0x2075,
+ 0x9946, 0x5213,
+ 0x9948, 0x23a9,
+ 0x994b, 0x1feb,
+ 0x994c, 0x23ac,
+ 0x994d, 0x5215,
+ 0x9951, 0x1f6a,
+ 0x9952, 0x20f9,
+ 0x9953, 0x5219,
+ 0x9954, 0x1deb,
+ 0x9955, 0x1dea,
+ 0x9956, 0x521a,
+ 0x9957, 0x2666,
+ 0x9958, 0x521b,
+ 0x995c, 0x2667,
+ 0x995d, 0x521f,
+ 0x995e, 0x1e6c,
+ 0x995f, 0x5220,
+ 0x9962, 0x23ad,
+ 0x9963, 0x161d,
+ 0x9964, 0x5223,
+ 0x9965, 0x0815,
+ 0x9966, 0x5224,
+ 0x9967, 0x161e,
+ 0x996d, 0x0656,
+ 0x996e, 0x1082,
+ 0x996f, 0x0875,
+ 0x9970, 0x0d65,
+ 0x9971, 0x040e,
+ 0x9972, 0x0dbc,
+ 0x9973, 0x5225,
+ 0x9974, 0x1624,
+ 0x9975, 0x063b,
+ 0x9976, 0x0c9f,
+ 0x9977, 0x1625,
+ 0x9978, 0x5226,
+ 0x997a, 0x0899,
+ 0x997b, 0x5228,
+ 0x997c, 0x0466,
+ 0x997d, 0x1626,
+ 0x997e, 0x5229,
+ 0x997f, 0x0635,
+ 0x9980, 0x1627,
+ 0x9981, 0x0b3c,
+ 0x9982, 0x522a,
+ 0x9984, 0x1628,
+ 0x9985, 0x0f47,
+ 0x9986, 0x0736,
+ 0x9987, 0x1629,
+ 0x9988, 0x098c,
+ 0x9989, 0x522c,
+ 0x998a, 0x162a,
+ 0x998b, 0x04bd,
+ 0x998c, 0x522d,
+ 0x998d, 0x162b,
+ 0x998e, 0x522e,
+ 0x998f, 0x0a3c,
+ 0x9990, 0x162c,
+ 0x9992, 0x0a9f,
+ 0x9993, 0x162e,
+ 0x9996, 0x0d6e,
+ 0x9997, 0x126e,
+ 0x9998, 0x12f9,
+ 0x9999, 0x0f50,
+ 0x999a, 0x522f,
+ 0x99a5, 0x1b2b,
+ 0x99a6, 0x523a,
+ 0x99a8, 0x13de,
+ 0x99a9, 0x523c,
+ 0x99ac, 0x206d,
+ 0x99ad, 0x2242,
+ 0x99ae, 0x1f02,
+ 0x99af, 0x523f,
+ 0x99b1, 0x2183,
+ 0x99b2, 0x5241,
+ 0x99b3, 0x1e85,
+ 0x99b4, 0x21e9,
+ 0x99b5, 0x5242,
+ 0x99c1, 0x1e57,
+ 0x99c2, 0x524e,
+ 0x99d0, 0x22a5,
+ 0x99d1, 0x2407,
+ 0x99d2, 0x1fca,
+ 0x99d3, 0x525c,
+ 0x99d4, 0x2402,
+ 0x99d5, 0x1f82,
+ 0x99d6, 0x525d,
+ 0x99d8, 0x2408,
+ 0x99d9, 0x2404,
+ 0x99da, 0x525f,
+ 0x99db, 0x2131,
+ 0x99dc, 0x5260,
+ 0x99dd, 0x2184,
+ 0x99de, 0x5261,
+ 0x99df, 0x2403,
+ 0x99e0, 0x5262,
+ 0x99e1, 0x206e,
+ 0x99e2, 0x240b,
+ 0x99e3, 0x5263,
+ 0x99ed, 0x1f3f,
+ 0x99ee, 0x526d,
+ 0x99f1, 0x2067,
+ 0x99f2, 0x5270,
+ 0x99ff, 0x1fd7,
+ 0x9a00, 0x527d,
+ 0x9a01, 0x1e83,
+ 0x9a02, 0x527e,
+ 0x9a05, 0x240f,
+ 0x9a06, 0x5281,
+ 0x9a0d, 0x240e,
+ 0x9a0e, 0x20c7,
+ 0x9a0f, 0x240d,
+ 0x9a10, 0x5288,
+ 0x9a16, 0x2412,
+ 0x9a17, 0x528e,
+ 0x9a19, 0x20b7,
+ 0x9a1a, 0x5290,
+ 0x9a2b, 0x23f0,
+ 0x9a2c, 0x52a1,
+ 0x9a2d, 0x2411,
+ 0x9a2e, 0x2414,
+ 0x9a2f, 0x52a2,
+ 0x9a30, 0x2170,
+ 0x9a31, 0x52a3,
+ 0x9a36, 0x2405,
+ 0x9a37, 0x210c,
+ 0x9a38, 0x2415,
+ 0x9a39, 0x52a8,
+ 0x9a3e, 0x2066,
+ 0x9a3f, 0x52ad,
+ 0x9a40, 0x2352,
+ 0x9a41, 0x2413,
+ 0x9a42, 0x2410,
+ 0x9a43, 0x2416,
+ 0x9a45, 0x20f1,
+ 0x9a46, 0x52ae,
+ 0x9a4a, 0x240a,
+ 0x9a4b, 0x52b2,
+ 0x9a4d, 0x2409,
+ 0x9a4e, 0x52b4,
+ 0x9a4f, 0x2418,
+ 0x9a50, 0x52b5,
+ 0x9a55, 0x1fa7,
+ 0x9a56, 0x52ba,
+ 0x9a57, 0x21fc,
+ 0x9a58, 0x52bb,
+ 0x9a5a, 0x1fc1,
+ 0x9a5b, 0x2406,
+ 0x9a5c, 0x52bd,
+ 0x9a5f, 0x229c,
+ 0x9a60, 0x52c0,
+ 0x9a62, 0x204e,
+ 0x9a63, 0x52c2,
+ 0x9a64, 0x241a,
+ 0x9a65, 0x2419,
+ 0x9a66, 0x52c3,
+ 0x9a6a, 0x240c,
+ 0x9a6b, 0x52c7,
+ 0x9a6c, 0x0a94,
+ 0x9a6d, 0x10e9,
+ 0x9a6e, 0x0e85,
+ 0x9a6f, 0x0fda,
+ 0x9a70, 0x0500,
+ 0x9a71, 0x0c7a,
+ 0x9a72, 0x52c8,
+ 0x9a73, 0x047c,
+ 0x9a74, 0x0a66,
+ 0x9a75, 0x17ba,
+ 0x9a76, 0x0d52,
+ 0x9a77, 0x17bb,
+ 0x9a79, 0x0903,
+ 0x9a7a, 0x17bd,
+ 0x9a7b, 0x1201,
+ 0x9a7c, 0x0e86,
+ 0x9a7d, 0x17bf,
+ 0x9a7e, 0x0850,
+ 0x9a7f, 0x17be,
+ 0x9a80, 0x17c0,
+ 0x9a82, 0x0a95,
+ 0x9a83, 0x52c9,
+ 0x9a84, 0x088f,
+ 0x9a85, 0x17c2,
+ 0x9a86, 0x0a8d,
+ 0x9a87, 0x075e,
+ 0x9a88, 0x17c3,
+ 0x9a89, 0x52ca,
+ 0x9a8a, 0x17c4,
+ 0x9a8b, 0x04f7,
+ 0x9a8c, 0x1012,
+ 0x9a8d, 0x52cb,
+ 0x9a8f, 0x0932,
+ 0x9a90, 0x17c5,
+ 0x9a91, 0x0c0e,
+ 0x9a92, 0x17c6,
+ 0x9a94, 0x52cd,
+ 0x9a96, 0x17c8,
+ 0x9a97, 0x0bcc,
+ 0x9a98, 0x17c9,
+ 0x9a99, 0x52cf,
+ 0x9a9a, 0x0ce0,
+ 0x9a9b, 0x17ca,
+ 0x9a9e, 0x1735,
+ 0x9a9f, 0x17cd,
+ 0x9aa1, 0x0a89,
+ 0x9aa2, 0x17cf,
+ 0x9aa4, 0x11e7,
+ 0x9aa5, 0x17d1,
+ 0x9aa6, 0x52d0,
+ 0x9aa7, 0x17d2,
+ 0x9aa8, 0x0720,
+ 0x9aa9, 0x52d1,
+ 0x9aaf, 0x1e29,
+ 0x9ab0, 0x1dd3,
+ 0x9ab1, 0x1dd2,
+ 0x9ab2, 0x52d7,
+ 0x9ab6, 0x1dd6,
+ 0x9ab7, 0x1dd4,
+ 0x9ab8, 0x0758,
+ 0x9ab9, 0x52db,
+ 0x9aba, 0x1dd7,
+ 0x9abb, 0x52dc,
+ 0x9abc, 0x1dd8,
+ 0x9abd, 0x52dd,
+ 0x9ac0, 0x1dda,
+ 0x9ac1, 0x1dd9,
+ 0x9ac2, 0x1ddc,
+ 0x9ac3, 0x52e0,
+ 0x9ac5, 0x1ddb,
+ 0x9ac6, 0x52e2,
+ 0x9acb, 0x1ddd,
+ 0x9acd, 0x52e7,
+ 0x9acf, 0x2661,
+ 0x9ad0, 0x52e9,
+ 0x9ad1, 0x1ddf,
+ 0x9ad2, 0x26a4,
+ 0x9ad3, 0x0ddd,
+ 0x9ad4, 0x2174,
+ 0x9ad5, 0x2663,
+ 0x9ad6, 0x2662,
+ 0x9ad7, 0x52ea,
+ 0x9ad8, 0x06da,
+ 0x9ad9, 0x52eb,
+ 0x9adf, 0x1dec,
+ 0x9ae0, 0x52f1,
+ 0x9ae1, 0x1ded,
+ 0x9ae2, 0x52f2,
+ 0x9ae6, 0x1dee,
+ 0x9ae7, 0x52f6,
+ 0x9aeb, 0x1df0,
+ 0x9aec, 0x52fa,
+ 0x9aed, 0x1df2,
+ 0x9aee, 0x2675,
+ 0x9aef, 0x1def,
+ 0x9af0, 0x52fb,
+ 0x9af9, 0x1df3,
+ 0x9afa, 0x5304,
+ 0x9afb, 0x1df1,
+ 0x9afc, 0x5305,
+ 0x9b00, 0x5309,
+ 0x9b03, 0x1234,
+ 0x9b04, 0x530c,
+ 0x9b06, 0x214c,
+ 0x9b07, 0x530e,
+ 0x9b08, 0x1df4,
+ 0x9b09, 0x530f,
+ 0x9b0d, 0x267a,
+ 0x9b0e, 0x5313,
+ 0x9b0f, 0x1df5,
+ 0x9b10, 0x5314,
+ 0x9b13, 0x1df6,
+ 0x9b14, 0x5317,
+ 0x9b1a, 0x26a0,
+ 0x9b1b, 0x531d,
+ 0x9b1f, 0x1df7,
+ 0x9b20, 0x5321,
+ 0x9b22, 0x2668,
+ 0x9b23, 0x1df8,
+ 0x9b24, 0x5323,
+ 0x9b25, 0x1ed0,
+ 0x9b26, 0x5324,
+ 0x9b27, 0x2096,
+ 0x9b28, 0x5325,
+ 0x9b29, 0x23cc,
+ 0x9b2a, 0x5326,
+ 0x9b2e, 0x23c8,
+ 0x9b2f, 0x139b,
+ 0x9b30, 0x532a,
+ 0x9b31, 0x223e,
+ 0x9b32, 0x1260,
+ 0x9b33, 0x532b,
+ 0x9b3b, 0x1773,
+ 0x9b3c, 0x0746,
+ 0x9b3d, 0x5333,
+ 0x9b41, 0x098a,
+ 0x9b42, 0x07ff,
+ 0x9b43, 0x1de1,
+ 0x9b44, 0x0be6,
+ 0x9b45, 0x1de0,
+ 0x9b46, 0x5337,
+ 0x9b47, 0x1de2,
+ 0x9b48, 0x1de4,
+ 0x9b49, 0x1de3,
+ 0x9b4a, 0x5338,
+ 0x9b4d, 0x1de5,
+ 0x9b4e, 0x2665,
+ 0x9b4f, 0x0ec9,
+ 0x9b50, 0x533b,
+ 0x9b51, 0x1de6,
+ 0x9b52, 0x533c,
+ 0x9b54, 0x0b0a,
+ 0x9b55, 0x533e,
+ 0x9b58, 0x2664,
+ 0x9b59, 0x5341,
+ 0x9b5a, 0x2239,
+ 0x9b5b, 0x5342,
+ 0x9b6f, 0x204a,
+ 0x9b70, 0x5356,
+ 0x9b74, 0x261f,
+ 0x9b75, 0x535a,
+ 0x9b77, 0x261e,
+ 0x9b78, 0x535c,
+ 0x9b81, 0x2620,
+ 0x9b82, 0x5365,
+ 0x9b83, 0x2621,
+ 0x9b84, 0x5366,
+ 0x9b8e, 0x2622,
+ 0x9b8f, 0x5370,
+ 0x9b90, 0x2627,
+ 0x9b91, 0x1e39,
+ 0x9b92, 0x2625,
+ 0x9b93, 0x5371,
+ 0x9b9a, 0x2629,
+ 0x9b9b, 0x5378,
+ 0x9b9d, 0x262e,
+ 0x9b9e, 0x262b,
+ 0x9b9f, 0x537a,
+ 0x9baa, 0x262a,
+ 0x9bab, 0x262d,
+ 0x9bac, 0x5385,
+ 0x9bad, 0x2628,
+ 0x9bae, 0x21b9,
+ 0x9baf, 0x5386,
+ 0x9bc0, 0x2636,
+ 0x9bc1, 0x2630,
+ 0x9bc2, 0x5397,
+ 0x9bc7, 0x2638,
+ 0x9bc8, 0x539c,
+ 0x9bc9, 0x200d,
+ 0x9bca, 0x2637,
+ 0x9bcb, 0x539d,
+ 0x9bd4, 0x2645,
+ 0x9bd5, 0x53a6,
+ 0x9bd6, 0x263a,
+ 0x9bd7, 0x53a7,
+ 0x9bdb, 0x2643,
+ 0x9bdc, 0x53ab,
+ 0x9bdd, 0x2640,
+ 0x9bde, 0x53ac,
+ 0x9be1, 0x263d,
+ 0x9be2, 0x2641,
+ 0x9be3, 0x53af,
+ 0x9be4, 0x263e,
+ 0x9be5, 0x53b0,
+ 0x9be7, 0x263f,
+ 0x9be8, 0x1fc0,
+ 0x9be9, 0x53b2,
+ 0x9bea, 0x263b,
+ 0x9bec, 0x53b3,
+ 0x9bf0, 0x2642,
+ 0x9bf1, 0x53b7,
+ 0x9bf4, 0x2644,
+ 0x9bf5, 0x53ba,
+ 0x9bfd, 0x2639,
+ 0x9bfe, 0x53c2,
+ 0x9bff, 0x264c,
+ 0x9c00, 0x53c3,
+ 0x9c08, 0x2647,
+ 0x9c09, 0x264b,
+ 0x9c0a, 0x53cb,
+ 0x9c0d, 0x2649,
+ 0x9c0e, 0x53ce,
+ 0x9c10, 0x2648,
+ 0x9c11, 0x53d0,
+ 0x9c12, 0x264a,
+ 0x9c13, 0x2108,
+ 0x9c14, 0x53d1,
+ 0x9c20, 0x264d,
+ 0x9c21, 0x53dd,
+ 0x9c23, 0x2634,
+ 0x9c24, 0x53df,
+ 0x9c25, 0x2651,
+ 0x9c26, 0x53e0,
+ 0x9c28, 0x2650,
+ 0x9c29, 0x2652,
+ 0x9c2a, 0x53e2,
+ 0x9c2d, 0x264f,
+ 0x9c2e, 0x53e5,
+ 0x9c31, 0x2632,
+ 0x9c32, 0x264e,
+ 0x9c33, 0x2653,
+ 0x9c34, 0x53e8,
+ 0x9c35, 0x2657,
+ 0x9c36, 0x53e9,
+ 0x9c37, 0x2635,
+ 0x9c38, 0x53ea,
+ 0x9c39, 0x2633,
+ 0x9c3a, 0x53eb,
+ 0x9c3b, 0x2656,
+ 0x9c3c, 0x53ec,
+ 0x9c3e, 0x2654,
+ 0x9c3f, 0x53ee,
+ 0x9c45, 0x2658,
+ 0x9c46, 0x53f4,
+ 0x9c48, 0x2655,
+ 0x9c49, 0x1e4d,
+ 0x9c4a, 0x53f6,
+ 0x9c52, 0x265b,
+ 0x9c53, 0x53fe,
+ 0x9c54, 0x265a,
+ 0x9c55, 0x53ff,
+ 0x9c56, 0x2659,
+ 0x9c57, 0x202e,
+ 0x9c58, 0x262f,
+ 0x9c59, 0x5400,
+ 0x9c5d, 0x2646,
+ 0x9c5e, 0x5404,
+ 0x9c5f, 0x2626,
+ 0x9c60, 0x5405,
+ 0x9c67, 0x265c,
+ 0x9c68, 0x540c,
+ 0x9c6d, 0x262c,
+ 0x9c6e, 0x5411,
+ 0x9c78, 0x2623,
+ 0x9c79, 0x541b,
+ 0x9c7a, 0x2631,
+ 0x9c7b, 0x541c,
+ 0x9c7c, 0x10c8,
+ 0x9c7d, 0x541d,
+ 0x9c7f, 0x1d89,
+ 0x9c80, 0x541f,
+ 0x9c81, 0x0a5a,
+ 0x9c82, 0x1d8a,
+ 0x9c83, 0x5420,
+ 0x9c85, 0x1d8b,
+ 0x9c89, 0x5422,
+ 0x9c8b, 0x1d90,
+ 0x9c8c, 0x5424,
+ 0x9c8d, 0x0414,
+ 0x9c8e, 0x1d91,
+ 0x9c8f, 0x5425,
+ 0x9c90, 0x1d92,
+ 0x9c93, 0x5426,
+ 0x9c94, 0x1d95,
+ 0x9c96, 0x5427,
+ 0x9c9a, 0x1d97,
+ 0x9c9c, 0x0f37,
+ 0x9c9d, 0x542b,
+ 0x9c9e, 0x1d99,
+ 0x9ca4, 0x09db,
+ 0x9ca5, 0x1d9f,
+ 0x9caa, 0x542c,
+ 0x9cab, 0x1da4,
+ 0x9cac, 0x542d,
+ 0x9cad, 0x1da5,
+ 0x9caf, 0x542e,
+ 0x9cb0, 0x1da7,
+ 0x9cb8, 0x08d7,
+ 0x9cb9, 0x542f,
+ 0x9cba, 0x1daf,
+ 0x9cbe, 0x5430,
+ 0x9cc3, 0x0cd5,
+ 0x9cc4, 0x1db3,
+ 0x9cc8, 0x5435,
+ 0x9cca, 0x1db7,
+ 0x9cd1, 0x5437,
+ 0x9cd3, 0x1dbe,
+ 0x9cd6, 0x0457,
+ 0x9cd7, 0x1dc1,
+ 0x9cda, 0x5439,
+ 0x9cdc, 0x1dc4,
+ 0x9cde, 0x0a24,
+ 0x9cdf, 0x1dc6,
+ 0x9ce0, 0x543b,
+ 0x9ce2, 0x1dc7,
+ 0x9ce3, 0x543d,
+ 0x9ce5, 0x209c,
+ 0x9ce6, 0x543f,
+ 0x9ce9, 0x2580,
+ 0x9cea, 0x5442,
+ 0x9cec, 0x22dc,
+ 0x9ced, 0x5444,
+ 0x9cf3, 0x1f05,
+ 0x9cf4, 0x208b,
+ 0x9cf5, 0x544a,
+ 0x9cf6, 0x2581,
+ 0x9cf7, 0x544b,
+ 0x9d00, 0x5454,
+ 0x9d06, 0x2583,
+ 0x9d07, 0x2582,
+ 0x9d08, 0x545a,
+ 0x9d09, 0x21ee,
+ 0x9d0a, 0x545b,
+ 0x9d15, 0x2182,
+ 0x9d16, 0x5466,
+ 0x9d1b, 0x2243,
+ 0x9d1c, 0x546b,
+ 0x9d1d, 0x2587,
+ 0x9d1e, 0x546c,
+ 0x9d1f, 0x2588,
+ 0x9d20, 0x546d,
+ 0x9d23, 0x2584,
+ 0x9d24, 0x5470,
+ 0x9d26, 0x21fd,
+ 0x9d27, 0x5472,
+ 0x9d28, 0x21ef,
+ 0x9d29, 0x5473,
+ 0x9d2f, 0x258a,
+ 0x9d30, 0x258c,
+ 0x9d31, 0x5479,
+ 0x9d3b, 0x1f47,
+ 0x9d3c, 0x5483,
+ 0x9d3f, 0x1f1d,
+ 0x9d40, 0x5486,
+ 0x9d42, 0x258d,
+ 0x9d43, 0x5488,
+ 0x9d51, 0x1fd0,
+ 0x9d52, 0x2592,
+ 0x9d53, 0x258f,
+ 0x9d54, 0x5496,
+ 0x9d5c, 0x2594,
+ 0x9d5d, 0x1ee0,
+ 0x9d5e, 0x549e,
+ 0x9d60, 0x2591,
+ 0x9d61, 0x2595,
+ 0x9d62, 0x54a0,
+ 0x9d6a, 0x2597,
+ 0x9d6b, 0x54a8,
+ 0x9d6c, 0x20b6,
+ 0x9d6d, 0x54a9,
+ 0x9d6f, 0x2598,
+ 0x9d70, 0x54ab,
+ 0x9d72, 0x20f6,
+ 0x9d73, 0x54ad,
+ 0x9d87, 0x2585,
+ 0x9d88, 0x54c1,
+ 0x9d89, 0x2599,
+ 0x9d8a, 0x54c2,
+ 0x9d93, 0x2596,
+ 0x9d94, 0x54cb,
+ 0x9d98, 0x259a,
+ 0x9d99, 0x54cf,
+ 0x9d9a, 0x259b,
+ 0x9d9b, 0x54d0,
+ 0x9da5, 0x259d,
+ 0x9da6, 0x54da,
+ 0x9da9, 0x259e,
+ 0x9daa, 0x54dd,
+ 0x9daf, 0x234c,
+ 0x9db0, 0x54e2,
+ 0x9db4, 0x1f44,
+ 0x9db5, 0x54e6,
+ 0x9dbb, 0x2660,
+ 0x9dbc, 0x25a0,
+ 0x9dbd, 0x54ec,
+ 0x9dc0, 0x259c,
+ 0x9dc1, 0x54ef,
+ 0x9dc2, 0x259f,
+ 0x9dc3, 0x54f0,
+ 0x9dc4, 0x1f6c,
+ 0x9dc5, 0x54f1,
+ 0x9dd3, 0x25a2,
+ 0x9dd4, 0x54ff,
+ 0x9dd7, 0x20ae,
+ 0x9dd8, 0x5502,
+ 0x9dd9, 0x258b,
+ 0x9dda, 0x25a3,
+ 0x9ddb, 0x5503,
+ 0x9de5, 0x2589,
+ 0x9de6, 0x25a5,
+ 0x9de7, 0x550d,
+ 0x9def, 0x25a4,
+ 0x9df0, 0x5515,
+ 0x9df2, 0x25a6,
+ 0x9df3, 0x2593,
+ 0x9df4, 0x5517,
+ 0x9df8, 0x25a7,
+ 0x9df9, 0x2222,
+ 0x9dfa, 0x25a9,
+ 0x9dfb, 0x551b,
+ 0x9e00, 0x5520,
+ 0x9e0c, 0x25a8,
+ 0x9e0d, 0x552c,
+ 0x9e15, 0x2586,
+ 0x9e16, 0x5534,
+ 0x9e1a, 0x25a1,
+ 0x9e1b, 0x25aa,
+ 0x9e1c, 0x5538,
+ 0x9e1d, 0x2590,
+ 0x9e1e, 0x258e,
+ 0x9e1f, 0x0b54,
+ 0x9e20, 0x1b35,
+ 0x9e21, 0x0819,
+ 0x9e22, 0x1b36,
+ 0x9e23, 0x0afe,
+ 0x9e24, 0x5539,
+ 0x9e25, 0x0b79,
+ 0x9e26, 0x0fe4,
+ 0x9e27, 0x553a,
+ 0x9e28, 0x1b37,
+ 0x9e2d, 0x0fe5,
+ 0x9e2e, 0x553b,
+ 0x9e2f, 0x1015,
+ 0x9e30, 0x553c,
+ 0x9e31, 0x1b3d,
+ 0x9e32, 0x1b3c,
+ 0x9e33, 0x10ea,
+ 0x9e34, 0x553d,
+ 0x9e35, 0x0e83,
+ 0x9e36, 0x1b3e,
+ 0x9e37, 0x1b40,
+ 0x9e38, 0x1b3f,
+ 0x9e39, 0x1b41,
+ 0x9e3b, 0x553e,
+ 0x9e3d, 0x06e6,
+ 0x9e3e, 0x1b43,
+ 0x9e3f, 0x079f,
+ 0x9e40, 0x5540,
+ 0x9e41, 0x1b44,
+ 0x9e43, 0x0918,
+ 0x9e44, 0x1b46,
+ 0x9e45, 0x062b,
+ 0x9e46, 0x1b47,
+ 0x9e4a, 0x0c90,
+ 0x9e4b, 0x1b4b,
+ 0x9e4d, 0x5541,
+ 0x9e4e, 0x1b4d,
+ 0x9e4f, 0x0bb5,
+ 0x9e50, 0x5542,
+ 0x9e51, 0x1b4e,
+ 0x9e52, 0x5543,
+ 0x9e55, 0x1b4f,
+ 0x9e56, 0x5546,
+ 0x9e57, 0x1b50,
+ 0x9e58, 0x1dd5,
+ 0x9e59, 0x5547,
+ 0x9e5a, 0x1b51,
+ 0x9e5d, 0x5548,
+ 0x9e5e, 0x1b54,
+ 0x9e5f, 0x5549,
+ 0x9e63, 0x1b55,
+ 0x9e64, 0x078e,
+ 0x9e65, 0x554d,
+ 0x9e66, 0x1b56,
+ 0x9e6d, 0x1b5e,
+ 0x9e6e, 0x554e,
+ 0x9e70, 0x108a,
+ 0x9e71, 0x1b5d,
+ 0x9e72, 0x5550,
+ 0x9e73, 0x1b5f,
+ 0x9e74, 0x5551,
+ 0x9e75, 0x2688,
+ 0x9e76, 0x5552,
+ 0x9e79, 0x269e,
+ 0x9e7a, 0x25fb,
+ 0x9e7b, 0x5555,
+ 0x9e7c, 0x1f8c,
+ 0x9e7d, 0x21f4,
+ 0x9e7e, 0x1d16,
+ 0x9e7f, 0x0a60,
+ 0x9e80, 0x5556,
+ 0x9e82, 0x1dfc,
+ 0x9e83, 0x5558,
+ 0x9e87, 0x1dfd,
+ 0x9e89, 0x555c,
+ 0x9e8b, 0x1dff,
+ 0x9e8c, 0x555e,
+ 0x9e92, 0x1e00,
+ 0x9e93, 0x0a5b,
+ 0x9e94, 0x5564,
+ 0x9e97, 0x200f,
+ 0x9e98, 0x5567,
+ 0x9e9d, 0x1e02,
+ 0x9e9e, 0x556c,
+ 0x9e9f, 0x1e03,
+ 0x9ea0, 0x556d,
+ 0x9ea5, 0x2071,
+ 0x9ea6, 0x0a9a,
+ 0x9ea7, 0x5572,
+ 0x9ea9, 0x25f7,
+ 0x9eaa, 0x5574,
+ 0x9eaf, 0x2696,
+ 0x9eb0, 0x5579,
+ 0x9eb4, 0x1cee,
+ 0x9eb5, 0x268f,
+ 0x9eb6, 0x557d,
+ 0x9eb8, 0x1ced,
+ 0x9eb9, 0x557f,
+ 0x9ebb, 0x0a90,
+ 0x9ebc, 0x5581,
+ 0x9ebd, 0x1df9,
+ 0x9ebf, 0x5582,
+ 0x9ec4, 0x07db,
+ 0x9ec5, 0x5587,
+ 0x9ec9, 0x12f8,
+ 0x9eca, 0x558b,
+ 0x9ecc, 0x22da,
+ 0x9ecd, 0x0d89,
+ 0x9ece, 0x09d3,
+ 0x9ecf, 0x1b2a,
+ 0x9ed0, 0x558d,
+ 0x9ed1, 0x0791,
+ 0x9ed2, 0x558e,
+ 0x9ed4, 0x0c2a,
+ 0x9ed5, 0x5590,
+ 0x9ed8, 0x0b0f,
+ 0x9ed9, 0x5593,
+ 0x9edb, 0x1e04,
+ 0x9ede, 0x1ec1,
+ 0x9edf, 0x1e08,
+ 0x9ee0, 0x1e07,
+ 0x9ee1, 0x5595,
+ 0x9ee2, 0x1e09,
+ 0x9ee3, 0x5596,
+ 0x9ee5, 0x1e0c,
+ 0x9ee6, 0x5598,
+ 0x9ee7, 0x1e0b,
+ 0x9ee8, 0x1eb3,
+ 0x9ee9, 0x1e0a,
+ 0x9eea, 0x1e0d,
+ 0x9eeb, 0x5599,
+ 0x9eef, 0x1e0e,
+ 0x9ef0, 0x559d,
+ 0x9ef2, 0x266a,
+ 0x9ef3, 0x559f,
+ 0x9ef4, 0x268a,
+ 0x9ef5, 0x55a0,
+ 0x9ef7, 0x2669,
+ 0x9ef8, 0x55a2,
+ 0x9ef9, 0x1a55,
+ 0x9efa, 0x55a3,
+ 0x9efb, 0x1a56,
+ 0x9efd, 0x2618,
+ 0x9efe, 0x1d76,
+ 0x9eff, 0x2619,
+ 0x9f00, 0x55a4,
+ 0x9f09, 0x261a,
+ 0x9f0a, 0x55ad,
+ 0x9f0b, 0x1d77,
+ 0x9f0c, 0x55ae,
+ 0x9f0d, 0x1d78,
+ 0x9f0e, 0x05e5,
+ 0x9f0f, 0x55af,
+ 0x9f10, 0x1274,
+ 0x9f11, 0x55b0,
+ 0x9f13, 0x071d,
+ 0x9f14, 0x55b2,
+ 0x9f15, 0x2673,
+ 0x9f16, 0x55b3,
+ 0x9f17, 0x1271,
+ 0x9f18, 0x55b4,
+ 0x9f19, 0x13df,
+ 0x9f1a, 0x55b5,
+ 0x9f20, 0x0d8a,
+ 0x9f21, 0x55bb,
+ 0x9f22, 0x1e0f,
+ 0x9f23, 0x55bc,
+ 0x9f2c, 0x1e10,
+ 0x9f2d, 0x55c5,
+ 0x9f2f, 0x1e11,
+ 0x9f30, 0x55c7,
+ 0x9f37, 0x1e13,
+ 0x9f38, 0x55ce,
+ 0x9f39, 0x1e12,
+ 0x9f3a, 0x55cf,
+ 0x9f3b, 0x0430,
+ 0x9f3c, 0x55d0,
+ 0x9f3d, 0x1e14,
+ 0x9f3f, 0x55d1,
+ 0x9f44, 0x1e16,
+ 0x9f45, 0x55d6,
+ 0x9f4a, 0x20c6,
+ 0x9f4b, 0x226b,
+ 0x9f4c, 0x55db,
+ 0x9f4f, 0x24d3,
+ 0x9f50, 0x0c0a,
+ 0x9f51, 0x19c2,
+ 0x9f52, 0x1e86,
+ 0x9f53, 0x55de,
+ 0x9f54, 0x260f,
+ 0x9f55, 0x55df,
+ 0x9f59, 0x2611,
+ 0x9f5a, 0x55e3,
+ 0x9f5c, 0x2613,
+ 0x9f5d, 0x55e5,
+ 0x9f5f, 0x2610,
+ 0x9f60, 0x2612,
+ 0x9f61, 0x2030,
+ 0x9f62, 0x55e7,
+ 0x9f63, 0x2671,
+ 0x9f64, 0x55e8,
+ 0x9f66, 0x2614,
+ 0x9f67, 0x55ea,
+ 0x9f6a, 0x2616,
+ 0x9f6b, 0x55ed,
+ 0x9f6c, 0x2615,
+ 0x9f6d, 0x55ee,
+ 0x9f72, 0x20f2,
+ 0x9f73, 0x55f3,
+ 0x9f77, 0x2617,
+ 0x9f78, 0x55f7,
+ 0x9f7f, 0x0502,
+ 0x9f80, 0x1d6d,
+ 0x9f81, 0x55fe,
+ 0x9f83, 0x1d6e,
+ 0x9f84, 0x0a2d,
+ 0x9f85, 0x1d6f,
+ 0x9f8b, 0x0c7e,
+ 0x9f8c, 0x1d75,
+ 0x9f8d, 0x2037,
+ 0x9f8e, 0x5600,
+ 0x9f90, 0x20b3,
+ 0x9f91, 0x5602,
+ 0x9f94, 0x1f22,
+ 0x9f95, 0x24ed,
+ 0x9f96, 0x5605,
+ 0x9f99, 0x0a43,
+ 0x9f9a, 0x0701,
+ 0x9f9b, 0x1a54,
+ 0x9f9c, 0x1f34,
+ 0x9f9d, 0x5608,
+ 0x9f9f, 0x0743,
+ 0x9fa0, 0x12f3,
+ 0x9fa1, 0x560a,
+ 0xe7e7, 0x274b,
+ 0xe815, 0x561f,
+ 0xf92c, 0x560f,
+ 0xfa0d, 0x5610,
+ 0xfa11, 0x5613,
+ 0xfa13, 0x5614,
+ 0xfa18, 0x5616,
+ 0xfa1f, 0x5617,
+ 0xfa23, 0x561a,
+ 0xfa27, 0x561c,
+ 0xfe30, 0x271d,
+ 0xfe49, 0x272b,
+ 0xfe54, 0x2735,
+ 0xfe59, 0x2739,
+ 0xfe68, 0x2747,
+ 0xff01, 0x0106,
+ 0xff04, 0x00a6,
+ 0xff05, 0x010a,
+ 0xff5e, 0x006a,
+ 0xffe0, 0x00a8,
+ 0xffe2, 0x271e,
+ 0xffe3, 0x0163,
+ 0xffe4, 0x271f,
+ 0xffe5, 0x0109,
+ 0x2014, 0x0256,
+ 0x2026, 0x0257,
+ 0x2225, 0x1e1c,
+ 0x3001, 0x023f,
+ 0x3002, 0x023e,
+ 0x3008, 0x0248,
+ 0x3010, 0x0252,
+ 0x3013, 0x1e1a,
+ 0x3014, 0x0246,
+ 0x3016, 0x0250,
+ 0xff01, 0x0242,
+ 0xff08, 0x0244,
+ 0xff0c, 0x023d,
+ 0xff0e, 0x1e1b,
+ 0xff1a, 0x0240,
+ 0xff1d, 0x1e1c,
+ 0xff1f, 0x0243,
+ 0xff3b, 0x1e1d,
+ 0xff3d, 0x1e1e,
+ 0xff3f, 0x0258,
+ 0xff5b, 0x0254,
+ 0xff5d, 0x0255,
+ 0xff5e, 0x1e18,
+ 0xffe3, 0x1e1f,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 gb12UniGBUCS2VEnc16 = {
+ 1,
+ { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ gb12UniGBUCS2VMap2, 13485
+};
+
+static Gushort gb12AdobeGB12VMap2[178] = {
+ 0x0000, 0x0000,
+ 0x0000, 0x0000,
+ 0x0100, 0x0100,
+ 0x0200, 0x0200,
+ 0x0300, 0x0300,
+ 0x0400, 0x0400,
+ 0x0500, 0x0500,
+ 0x0600, 0x0600,
+ 0x0700, 0x0700,
+ 0x0800, 0x0800,
+ 0x0900, 0x0900,
+ 0x0a00, 0x0a00,
+ 0x0b00, 0x0b00,
+ 0x0c00, 0x0c00,
+ 0x0d00, 0x0d00,
+ 0x0e00, 0x0e00,
+ 0x0f00, 0x0f00,
+ 0x1000, 0x1000,
+ 0x1100, 0x1100,
+ 0x1200, 0x1200,
+ 0x1300, 0x1300,
+ 0x1400, 0x1400,
+ 0x1500, 0x1500,
+ 0x1600, 0x1600,
+ 0x1700, 0x1700,
+ 0x1800, 0x1800,
+ 0x1900, 0x1900,
+ 0x1a00, 0x1a00,
+ 0x1b00, 0x1b00,
+ 0x1c00, 0x1c00,
+ 0x1d00, 0x1d00,
+ 0x1e00, 0x1e00,
+ 0x1f00, 0x1f00,
+ 0x2000, 0x2000,
+ 0x2100, 0x2100,
+ 0x2200, 0x2200,
+ 0x2300, 0x2300,
+ 0x2400, 0x2400,
+ 0x2500, 0x2500,
+ 0x2600, 0x2600,
+ 0x2700, 0x2700,
+ 0x2800, 0x2800,
+ 0x2900, 0x2900,
+ 0x2a00, 0x2a00,
+ 0x2b00, 0x2b00,
+ 0x2c00, 0x2c00,
+ 0x2d00, 0x2d00,
+ 0x2e00, 0x2e00,
+ 0x2f00, 0x2f00,
+ 0x3000, 0x3000,
+ 0x3100, 0x3100,
+ 0x3200, 0x3200,
+ 0x3300, 0x3300,
+ 0x3400, 0x3400,
+ 0x3500, 0x3500,
+ 0x3600, 0x3600,
+ 0x3700, 0x3700,
+ 0x3800, 0x3800,
+ 0x3900, 0x3900,
+ 0x3a00, 0x3a00,
+ 0x3b00, 0x3b00,
+ 0x3c00, 0x3c00,
+ 0x3d00, 0x3d00,
+ 0x3e00, 0x3e00,
+ 0x3f00, 0x3f00,
+ 0x4000, 0x4000,
+ 0x4100, 0x4100,
+ 0x4200, 0x4200,
+ 0x4300, 0x4300,
+ 0x4400, 0x4400,
+ 0x4500, 0x4500,
+ 0x4600, 0x4600,
+ 0x4700, 0x4700,
+ 0x4800, 0x4800,
+ 0x4900, 0x4900,
+ 0x4a00, 0x4a00,
+ 0x4b00, 0x4b00,
+ 0x4c00, 0x4c00,
+ 0x4d00, 0x4d00,
+ 0x4e00, 0x4e00,
+ 0x4f00, 0x4f00,
+ 0x5000, 0x5000,
+ 0x5100, 0x5100,
+ 0x5200, 0x5200,
+ 0x5300, 0x5300,
+ 0x5400, 0x5400,
+ 0x5500, 0x5500,
+ 0x5600, 0x5600,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 gb12AdobeGB12VEnc16 = {
+ 1,
+ { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ gb12AdobeGB12VMap2, 89
+};
+
+static struct {
+ char *name;
+ GfxFontEncoding16 *enc;
+} gfxGB12Tab[] = {
+ { "Adobe-GB1-0", &gb12AdobeGB10Enc16 },
+ { "Adobe-GB1-1", &gb12AdobeGB11Enc16 },
+ { "Adobe-GB1-2", &gb12AdobeGB12Enc16 },
+ { "GB-EUC-H", &gb12GBEUCHEnc16 },
+ { "GB-EUC-V", &gb12GBEUCVEnc16 },
+ { "GB-H", &gb12GBHEnc16 },
+ { "GB-V", &gb12GBVEnc16 },
+ { "GBK-EUC-H", &gb12GBKEUCHEnc16 },
+ { "GBK-EUC-V", &gb12GBKEUCVEnc16 },
+ { "GBT-EUC-H", &gb12GBTEUCHEnc16 },
+ { "GBT-EUC-V", &gb12GBTEUCVEnc16 },
+ { "GBT-H", &gb12GBTHEnc16 },
+ { "GBT-V", &gb12GBTVEnc16 },
+ { "GBTpc-EUC-H", &gb12GBTpcEUCHEnc16 },
+ { "GBTpc-EUC-V", &gb12GBTpcEUCVEnc16 },
+ { "GBpc-EUC-H", &gb12GBpcEUCHEnc16 },
+ { "GBpc-EUC-V", &gb12GBpcEUCVEnc16 },
+ { "UniGB-UCS2-H", &gb12UniGBUCS2HEnc16 },
+ { "UniGB-UCS2-V", &gb12UniGBUCS2VEnc16 },
+ { "Identity-H", &gb12AdobeGB12Enc16 },
+ { "Identity-V", &gb12AdobeGB12VEnc16 },
+ { NULL, NULL }
+};
+
+#endif
diff --git a/pdftops/GString.cxx b/pdftops/GString.cxx
new file mode 100644
index 000000000..7b8f27184
--- /dev/null
+++ b/pdftops/GString.cxx
@@ -0,0 +1,223 @@
+//========================================================================
+//
+// GString.cc
+//
+// Simple variable-length string type.
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <ctype.h>
+#include "gtypes.h"
+#include "GString.h"
+
+static inline int size(int len) {
+ int delta;
+
+ delta = len < 256 ? 7 : 255;
+ return ((len + 1) + delta) & ~delta;
+}
+
+inline void GString::resize(int length1) {
+ char *s1;
+
+ if (!s) {
+ s = new char[size(length1)];
+ } else if (size(length1) != size(length)) {
+ s1 = new char[size(length1)];
+ memcpy(s1, s, length + 1);
+ delete[] s;
+ s = s1;
+ }
+}
+
+GString::GString() {
+ s = NULL;
+ resize(length = 0);
+ s[0] = '\0';
+}
+
+GString::GString(const char *s1) {
+ int n = strlen(s1);
+
+ s = NULL;
+ resize(length = n);
+ memcpy(s, s1, n + 1);
+}
+
+GString::GString(const char *s1, int length1) {
+ s = NULL;
+ resize(length = length1);
+ memcpy(s, s1, length * sizeof(char));
+ s[length] = '\0';
+}
+
+GString::GString(GString *str) {
+ s = NULL;
+ resize(length = str->getLength());
+ memcpy(s, str->getCString(), length + 1);
+}
+
+GString::GString(GString *str1, GString *str2) {
+ int n1 = str1->getLength();
+ int n2 = str2->getLength();
+
+ s = NULL;
+ resize(length = n1 + n2);
+ memcpy(s, str1->getCString(), n1);
+ memcpy(s + n1, str2->getCString(), n2 + 1);
+}
+
+GString *GString::fromInt(int x) {
+ char buf[24]; // enough space for 64-bit ints plus a little extra
+ GBool neg;
+ Guint y;
+ int i;
+
+ i = 24;
+ if (x == 0) {
+ buf[--i] = '0';
+ } else {
+ if ((neg = x < 0)) {
+ y = (Guint)-x;
+ } else {
+ y = (Guint)x;
+ }
+ while (i > 0 && y > 0) {
+ buf[--i] = '0' + y % 10;
+ y /= 10;
+ }
+ if (neg && i > 0) {
+ buf[--i] = '-';
+ }
+ }
+ return new GString(buf + i, 24 - i);
+}
+
+GString::~GString() {
+ delete[] s;
+}
+
+GString *GString::clear() {
+ s[length = 0] = '\0';
+ resize(0);
+ return this;
+}
+
+GString *GString::append(char c) {
+ resize(length + 1);
+ s[length++] = c;
+ s[length] = '\0';
+ return this;
+}
+
+GString *GString::append(GString *str) {
+ int n = str->getLength();
+
+ resize(length + n);
+ memcpy(s + length, str->getCString(), n + 1);
+ length += n;
+ return this;
+}
+
+GString *GString::append(const char *str) {
+ int n = strlen(str);
+
+ resize(length + n);
+ memcpy(s + length, str, n + 1);
+ length += n;
+ return this;
+}
+
+GString *GString::append(const char *str, int length1) {
+ resize(length + length1);
+ memcpy(s + length, str, length1);
+ length += length1;
+ s[length] = '\0';
+ return this;
+}
+
+GString *GString::insert(int i, char c) {
+ int j;
+
+ resize(length + 1);
+ for (j = length + 1; j > i; --j)
+ s[j] = s[j-1];
+ s[i] = c;
+ ++length;
+ return this;
+}
+
+GString *GString::insert(int i, GString *str) {
+ int n = str->getLength();
+ int j;
+
+ resize(length + n);
+ for (j = length; j >= i; --j)
+ s[j+n] = s[j];
+ memcpy(s+i, str->getCString(), n);
+ length += n;
+ return this;
+}
+
+GString *GString::insert(int i, const char *str) {
+ int n = strlen(str);
+ int j;
+
+ resize(length + n);
+ for (j = length; j >= i; --j)
+ s[j+n] = s[j];
+ memcpy(s+i, str, n);
+ length += n;
+ return this;
+}
+
+GString *GString::insert(int i, const char *str, int length1) {
+ int j;
+
+ resize(length + length1);
+ for (j = length; j >= i; --j)
+ s[j+length1] = s[j];
+ memcpy(s+i, str, length1);
+ length += length1;
+ return this;
+}
+
+GString *GString::del(int i, int n) {
+ int j;
+
+ if (n > 0) {
+ for (j = i; j <= length - n; ++j)
+ s[j] = s[j + n];
+ resize(length -= n);
+ }
+ return this;
+}
+
+GString *GString::upperCase() {
+ int i;
+
+ for (i = 0; i < length; ++i) {
+ if (islower(s[i]))
+ s[i] = toupper(s[i]);
+ }
+ return this;
+}
+
+GString *GString::lowerCase() {
+ int i;
+
+ for (i = 0; i < length; ++i) {
+ if (isupper(s[i]))
+ s[i] = tolower(s[i]);
+ }
+ return this;
+}
diff --git a/pdftops/GString.h b/pdftops/GString.h
new file mode 100644
index 000000000..4c3b95f34
--- /dev/null
+++ b/pdftops/GString.h
@@ -0,0 +1,95 @@
+//========================================================================
+//
+// GString.h
+//
+// Simple variable-length string type.
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifndef GSTRING_H
+#define GSTRING_H
+
+#ifdef __GNUC__
+#pragma interface
+#endif
+
+#include <string.h>
+
+class GString {
+public:
+
+ // Create an empty string.
+ GString();
+
+ // Create a string from a C string.
+ GString(const char *s1);
+
+ // Create a string from <length1> chars at <s1>. This string
+ // can contain null characters.
+ GString (const char *s1, int length1);
+
+ // Copy a string.
+ GString(GString *str);
+ GString *copy() { return new GString(this); }
+
+ // Concatenate two strings.
+ GString(GString *str1, GString *str2);
+
+ // Convert an integer to a string.
+ static GString *fromInt(int x);
+
+ // Destructor.
+ ~GString();
+
+ // Get length.
+ int getLength() { return length; }
+
+ // Get C string.
+ char *getCString() { return s; }
+
+ // Get <i>th character.
+ char getChar(int i) { return s[i]; }
+
+ // Change <i>th character.
+ void setChar(int i, char c) { s[i] = c; }
+
+ // Clear string to zero length.
+ GString *clear();
+
+ // Append a character or string.
+ GString *append(char c);
+ GString *append(GString *str);
+ GString *append(const char *str);
+ GString *append(const char *str, int length1);
+
+ // Insert a character or string.
+ GString *insert(int i, char c);
+ GString *insert(int i, GString *str);
+ GString *insert(int i, const char *str);
+ GString *insert(int i, const char *str, int length1);
+
+ // Delete a character or range of characters.
+ GString *del(int i, int n = 1);
+
+ // Convert string to all-upper/all-lower case.
+ GString *upperCase();
+ GString *lowerCase();
+
+ // Compare two strings: -1:< 0:= +1:>
+ // These functions assume the strings do not contain null characters.
+ int cmp(GString *str) { return strcmp(s, str->getCString()); }
+ int cmpN(GString *str, int n) { return strncmp(s, str->getCString(), n); }
+ int cmp(const char *s1) { return strcmp(s, s1); }
+ int cmpN(const char *s1, int n) { return strncmp(s, s1, n); }
+
+private:
+
+ int length;
+ char *s;
+
+ void resize(int length1);
+};
+
+#endif
diff --git a/pdftops/Gfx.cxx b/pdftops/Gfx.cxx
new file mode 100644
index 000000000..a55efde82
--- /dev/null
+++ b/pdftops/Gfx.cxx
@@ -0,0 +1,2508 @@
+//========================================================================
+//
+// Gfx.cc
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#include <stdio.h>
+#include <stddef.h>
+#include <string.h>
+#include <math.h>
+#include "gmem.h"
+#include "Object.h"
+#include "Array.h"
+#include "Dict.h"
+#include "Stream.h"
+#include "Lexer.h"
+#include "Parser.h"
+#include "GfxFont.h"
+#include "GfxState.h"
+#include "OutputDev.h"
+#include "Params.h"
+#include "Page.h"
+#include "Error.h"
+#include "Gfx.h"
+
+//------------------------------------------------------------------------
+// constants
+//------------------------------------------------------------------------
+
+// Max number of splits along the t axis for an axial shading fill.
+#define axialMaxSplits 256
+
+// Max delta allowed in any color component for an axial shading fill.
+#define axialColorDelta (1 / 256.0)
+
+//------------------------------------------------------------------------
+// Operator table
+//------------------------------------------------------------------------
+
+Operator Gfx::opTab[] = {
+ {"\"", 3, {tchkNum, tchkNum, tchkString},
+ &Gfx::opMoveSetShowText},
+ {"'", 1, {tchkString},
+ &Gfx::opMoveShowText},
+ {"B", 0, {tchkNone},
+ &Gfx::opFillStroke},
+ {"B*", 0, {tchkNone},
+ &Gfx::opEOFillStroke},
+ {"BDC", 2, {tchkName, tchkProps},
+ &Gfx::opBeginMarkedContent},
+ {"BI", 0, {tchkNone},
+ &Gfx::opBeginImage},
+ {"BMC", 1, {tchkName},
+ &Gfx::opBeginMarkedContent},
+ {"BT", 0, {tchkNone},
+ &Gfx::opBeginText},
+ {"BX", 0, {tchkNone},
+ &Gfx::opBeginIgnoreUndef},
+ {"CS", 1, {tchkName},
+ &Gfx::opSetStrokeColorSpace},
+ {"DP", 2, {tchkName, tchkProps},
+ &Gfx::opMarkPoint},
+ {"Do", 1, {tchkName},
+ &Gfx::opXObject},
+ {"EI", 0, {tchkNone},
+ &Gfx::opEndImage},
+ {"EMC", 0, {tchkNone},
+ &Gfx::opEndMarkedContent},
+ {"ET", 0, {tchkNone},
+ &Gfx::opEndText},
+ {"EX", 0, {tchkNone},
+ &Gfx::opEndIgnoreUndef},
+ {"F", 0, {tchkNone},
+ &Gfx::opFill},
+ {"G", 1, {tchkNum},
+ &Gfx::opSetStrokeGray},
+ {"ID", 0, {tchkNone},
+ &Gfx::opImageData},
+ {"J", 1, {tchkInt},
+ &Gfx::opSetLineCap},
+ {"K", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
+ &Gfx::opSetStrokeCMYKColor},
+ {"M", 1, {tchkNum},
+ &Gfx::opSetMiterLimit},
+ {"MP", 1, {tchkName},
+ &Gfx::opMarkPoint},
+ {"Q", 0, {tchkNone},
+ &Gfx::opRestore},
+ {"RG", 3, {tchkNum, tchkNum, tchkNum},
+ &Gfx::opSetStrokeRGBColor},
+ {"S", 0, {tchkNone},
+ &Gfx::opStroke},
+ {"SC", -4, {tchkNum, tchkNum, tchkNum, tchkNum},
+ &Gfx::opSetStrokeColor},
+ {"SCN", -5, {tchkSCN, tchkSCN, tchkSCN, tchkSCN,
+ tchkSCN},
+ &Gfx::opSetStrokeColorN},
+ {"T*", 0, {tchkNone},
+ &Gfx::opTextNextLine},
+ {"TD", 2, {tchkNum, tchkNum},
+ &Gfx::opTextMoveSet},
+ {"TJ", 1, {tchkArray},
+ &Gfx::opShowSpaceText},
+ {"TL", 1, {tchkNum},
+ &Gfx::opSetTextLeading},
+ {"Tc", 1, {tchkNum},
+ &Gfx::opSetCharSpacing},
+ {"Td", 2, {tchkNum, tchkNum},
+ &Gfx::opTextMove},
+ {"Tf", 2, {tchkName, tchkNum},
+ &Gfx::opSetFont},
+ {"Tj", 1, {tchkString},
+ &Gfx::opShowText},
+ {"Tm", 6, {tchkNum, tchkNum, tchkNum, tchkNum,
+ tchkNum, tchkNum},
+ &Gfx::opSetTextMatrix},
+ {"Tr", 1, {tchkInt},
+ &Gfx::opSetTextRender},
+ {"Ts", 1, {tchkNum},
+ &Gfx::opSetTextRise},
+ {"Tw", 1, {tchkNum},
+ &Gfx::opSetWordSpacing},
+ {"Tz", 1, {tchkNum},
+ &Gfx::opSetHorizScaling},
+ {"W", 0, {tchkNone},
+ &Gfx::opClip},
+ {"W*", 0, {tchkNone},
+ &Gfx::opEOClip},
+ {"b", 0, {tchkNone},
+ &Gfx::opCloseFillStroke},
+ {"b*", 0, {tchkNone},
+ &Gfx::opCloseEOFillStroke},
+ {"c", 6, {tchkNum, tchkNum, tchkNum, tchkNum,
+ tchkNum, tchkNum},
+ &Gfx::opCurveTo},
+ {"cm", 6, {tchkNum, tchkNum, tchkNum, tchkNum,
+ tchkNum, tchkNum},
+ &Gfx::opConcat},
+ {"cs", 1, {tchkName},
+ &Gfx::opSetFillColorSpace},
+ {"d", 2, {tchkArray, tchkNum},
+ &Gfx::opSetDash},
+ {"d0", 2, {tchkNum, tchkNum},
+ &Gfx::opSetCharWidth},
+ {"d1", 6, {tchkNum, tchkNum, tchkNum, tchkNum,
+ tchkNum, tchkNum},
+ &Gfx::opSetCacheDevice},
+ {"f", 0, {tchkNone},
+ &Gfx::opFill},
+ {"f*", 0, {tchkNone},
+ &Gfx::opEOFill},
+ {"g", 1, {tchkNum},
+ &Gfx::opSetFillGray},
+ {"gs", 1, {tchkName},
+ &Gfx::opSetExtGState},
+ {"h", 0, {tchkNone},
+ &Gfx::opClosePath},
+ {"i", 1, {tchkNum},
+ &Gfx::opSetFlat},
+ {"j", 1, {tchkInt},
+ &Gfx::opSetLineJoin},
+ {"k", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
+ &Gfx::opSetFillCMYKColor},
+ {"l", 2, {tchkNum, tchkNum},
+ &Gfx::opLineTo},
+ {"m", 2, {tchkNum, tchkNum},
+ &Gfx::opMoveTo},
+ {"n", 0, {tchkNone},
+ &Gfx::opEndPath},
+ {"q", 0, {tchkNone},
+ &Gfx::opSave},
+ {"re", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
+ &Gfx::opRectangle},
+ {"rg", 3, {tchkNum, tchkNum, tchkNum},
+ &Gfx::opSetFillRGBColor},
+ {"ri", 1, {tchkName},
+ &Gfx::opSetRenderingIntent},
+ {"s", 0, {tchkNone},
+ &Gfx::opCloseStroke},
+ {"sc", -4, {tchkNum, tchkNum, tchkNum, tchkNum},
+ &Gfx::opSetFillColor},
+ {"scn", -5, {tchkSCN, tchkSCN, tchkSCN, tchkSCN,
+ tchkSCN},
+ &Gfx::opSetFillColorN},
+ {"sh", 1, {tchkName},
+ &Gfx::opShFill},
+ {"v", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
+ &Gfx::opCurveTo1},
+ {"w", 1, {tchkNum},
+ &Gfx::opSetLineWidth},
+ {"y", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
+ &Gfx::opCurveTo2},
+};
+
+#define numOps (sizeof(opTab) / sizeof(Operator))
+
+//------------------------------------------------------------------------
+// GfxResources
+//------------------------------------------------------------------------
+
+GfxResources::GfxResources(XRef *xref, Dict *resDict, GfxResources *nextA) {
+ Object obj1;
+
+ if (resDict) {
+
+ // build font dictionary
+ fonts = NULL;
+ resDict->lookup("Font", &obj1);
+ if (obj1.isDict()) {
+ fonts = new GfxFontDict(xref, obj1.getDict());
+ }
+ obj1.free();
+
+ // get XObject dictionary
+ resDict->lookup("XObject", &xObjDict);
+
+ // get color space dictionary
+ resDict->lookup("ColorSpace", &colorSpaceDict);
+
+ // get pattern dictionary
+ resDict->lookup("Pattern", &patternDict);
+
+ // get shading dictionary
+ resDict->lookup("Shading", &shadingDict);
+
+ // get graphics state parameter dictionary
+ resDict->lookup("ExtGState", &gStateDict);
+
+ } else {
+ fonts = NULL;
+ xObjDict.initNull();
+ colorSpaceDict.initNull();
+ patternDict.initNull();
+ gStateDict.initNull();
+ }
+
+ next = nextA;
+}
+
+GfxResources::~GfxResources() {
+ if (fonts) {
+ delete fonts;
+ }
+ xObjDict.free();
+ colorSpaceDict.free();
+ patternDict.free();
+ shadingDict.free();
+ gStateDict.free();
+}
+
+GfxFont *GfxResources::lookupFont(char *name) {
+ GfxFont *font;
+ GfxResources *resPtr;
+
+ for (resPtr = this; resPtr; resPtr = resPtr->next) {
+ if (resPtr->fonts) {
+ if ((font = resPtr->fonts->lookup(name)))
+ return font;
+ }
+ }
+ error(-1, "Unknown font tag '%s'", name);
+ return NULL;
+}
+
+GBool GfxResources::lookupXObject(char *name, Object *obj) {
+ GfxResources *resPtr;
+
+ for (resPtr = this; resPtr; resPtr = resPtr->next) {
+ if (resPtr->xObjDict.isDict()) {
+ if (!resPtr->xObjDict.dictLookup(name, obj)->isNull())
+ return gTrue;
+ obj->free();
+ }
+ }
+ error(-1, "XObject '%s' is unknown", name);
+ return gFalse;
+}
+
+GBool GfxResources::lookupXObjectNF(char *name, Object *obj) {
+ GfxResources *resPtr;
+
+ for (resPtr = this; resPtr; resPtr = resPtr->next) {
+ if (resPtr->xObjDict.isDict()) {
+ if (!resPtr->xObjDict.dictLookupNF(name, obj)->isNull())
+ return gTrue;
+ obj->free();
+ }
+ }
+ error(-1, "XObject '%s' is unknown", name);
+ return gFalse;
+}
+
+void GfxResources::lookupColorSpace(char *name, Object *obj) {
+ GfxResources *resPtr;
+
+ for (resPtr = this; resPtr; resPtr = resPtr->next) {
+ if (resPtr->colorSpaceDict.isDict()) {
+ if (!resPtr->colorSpaceDict.dictLookup(name, obj)->isNull()) {
+ return;
+ }
+ obj->free();
+ }
+ }
+ obj->initNull();
+}
+
+GfxPattern *GfxResources::lookupPattern(char *name) {
+ GfxResources *resPtr;
+ GfxPattern *pattern;
+ Object obj;
+
+ for (resPtr = this; resPtr; resPtr = resPtr->next) {
+ if (resPtr->patternDict.isDict()) {
+ if (!resPtr->patternDict.dictLookup(name, &obj)->isNull()) {
+ pattern = GfxPattern::parse(&obj);
+ obj.free();
+ return pattern;
+ }
+ obj.free();
+ }
+ }
+ error(-1, "Unknown pattern '%s'", name);
+ return NULL;
+}
+
+GfxShading *GfxResources::lookupShading(char *name) {
+ GfxResources *resPtr;
+ GfxShading *shading;
+ Object obj;
+
+ for (resPtr = this; resPtr; resPtr = resPtr->next) {
+ if (resPtr->shadingDict.isDict()) {
+ if (!resPtr->shadingDict.dictLookup(name, &obj)->isNull()) {
+ shading = GfxShading::parse(&obj);
+ obj.free();
+ return shading;
+ }
+ obj.free();
+ }
+ }
+ error(-1, "Unknown shading '%s'", name);
+ return NULL;
+}
+
+GBool GfxResources::lookupGState(char *name, Object *obj) {
+ GfxResources *resPtr;
+
+ for (resPtr = this; resPtr; resPtr = resPtr->next) {
+ if (resPtr->gStateDict.isDict()) {
+ if (!resPtr->gStateDict.dictLookup(name, obj)->isNull()) {
+ return gTrue;
+ }
+ obj->free();
+ }
+ }
+ error(-1, "ExtGState '%s' is unknown", name);
+ return gFalse;
+}
+
+//------------------------------------------------------------------------
+// Gfx
+//------------------------------------------------------------------------
+
+Gfx::Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict, double dpi,
+ PDFRectangle *box, GBool crop, PDFRectangle *cropBox, int rotate,
+ GBool printCommandsA) {
+ int i;
+
+ xref = xrefA;
+ printCommands = printCommandsA;
+
+ // start the resource stack
+ res = new GfxResources(xref, resDict, NULL);
+
+ // initialize
+ out = outA;
+ state = new GfxState(dpi, box, rotate, out->upsideDown());
+ fontChanged = gFalse;
+ clip = clipNone;
+ ignoreUndef = 0;
+ out->startPage(pageNum, state);
+ out->setDefaultCTM(state->getCTM());
+ out->updateAll(state);
+ for (i = 0; i < 6; ++i) {
+ baseMatrix[i] = state->getCTM()[i];
+ }
+
+ // set crop box
+ if (crop) {
+ state->moveTo(cropBox->x1, cropBox->y1);
+ state->lineTo(cropBox->x2, cropBox->y1);
+ state->lineTo(cropBox->x2, cropBox->y2);
+ state->lineTo(cropBox->x1, cropBox->y2);
+ state->closePath();
+ state->clip();
+ out->clip(state);
+ state->clearPath();
+ }
+}
+
+Gfx::~Gfx() {
+ GfxResources *resPtr;
+
+ while (state->hasSaves()) {
+ state = state->restore();
+ out->restoreState(state);
+ }
+ out->endPage();
+ while (res) {
+ resPtr = res->getNext();
+ delete res;
+ res = resPtr;
+ }
+ if (state)
+ delete state;
+}
+
+void Gfx::display(Object *obj, GBool topLevel) {
+ Object obj2;
+ int i;
+
+ if (obj->isArray()) {
+ for (i = 0; i < obj->arrayGetLength(); ++i) {
+ obj->arrayGet(i, &obj2);
+ if (!obj2.isStream()) {
+ error(-1, "Weird page contents");
+ obj2.free();
+ return;
+ }
+ obj2.free();
+ }
+ } else if (!obj->isStream()) {
+ error(-1, "Weird page contents");
+ return;
+ }
+ parser = new Parser(xref, new Lexer(xref, obj));
+ go(topLevel);
+ delete parser;
+ parser = NULL;
+}
+
+void Gfx::go(GBool topLevel) {
+ Object obj;
+ Object args[maxArgs];
+ int numCmds, numArgs;
+ int i;
+
+ // scan a sequence of objects
+ numCmds = 0;
+ numArgs = 0;
+ parser->getObj(&obj);
+ while (!obj.isEOF()) {
+
+ // got a command - execute it
+ if (obj.isCmd()) {
+ if (printCommands) {
+ obj.print(stdout);
+ for (i = 0; i < numArgs; ++i) {
+ printf(" ");
+ args[i].print(stdout);
+ }
+ printf("\n");
+ fflush(stdout);
+ }
+ execOp(&obj, args, numArgs);
+ obj.free();
+ for (i = 0; i < numArgs; ++i)
+ args[i].free();
+ numArgs = 0;
+
+ // periodically update display
+ if (++numCmds == 200) {
+ out->dump();
+ numCmds = 0;
+ }
+
+ // got an argument - save it
+ } else if (numArgs < maxArgs) {
+ args[numArgs++] = obj;
+
+ // too many arguments - something is wrong
+ } else {
+ error(getPos(), "Too many args in content stream");
+ if (printCommands) {
+ printf("throwing away arg: ");
+ obj.print(stdout);
+ printf("\n");
+ fflush(stdout);
+ }
+ obj.free();
+ }
+
+ // grab the next object
+ parser->getObj(&obj);
+ }
+ obj.free();
+
+ // args at end with no command
+ if (numArgs > 0) {
+ error(getPos(), "Leftover args in content stream");
+ if (printCommands) {
+ printf("%d leftovers:", numArgs);
+ for (i = 0; i < numArgs; ++i) {
+ printf(" ");
+ args[i].print(stdout);
+ }
+ printf("\n");
+ fflush(stdout);
+ }
+ for (i = 0; i < numArgs; ++i)
+ args[i].free();
+ }
+
+ // update display
+ if (topLevel && numCmds > 0) {
+ out->dump();
+ }
+}
+
+void Gfx::execOp(Object *cmd, Object args[], int numArgs) {
+ Operator *op;
+ char *name;
+ int i;
+
+ // find operator
+ name = cmd->getName();
+ if (!(op = findOp(name))) {
+ if (ignoreUndef == 0)
+ error(getPos(), "Unknown operator '%s'", name);
+ return;
+ }
+
+ // type check args
+ if (op->numArgs >= 0) {
+ if (numArgs != op->numArgs) {
+ error(getPos(), "Wrong number (%d) of args to '%s' operator",
+ numArgs, name);
+ return;
+ }
+ } else {
+ if (numArgs > -op->numArgs) {
+ error(getPos(), "Too many (%d) args to '%s' operator",
+ numArgs, name);
+ return;
+ }
+ }
+ for (i = 0; i < numArgs; ++i) {
+ if (!checkArg(&args[i], op->tchk[i])) {
+ error(getPos(), "Arg #%d to '%s' operator is wrong type (%s)",
+ i, name, args[i].getTypeName());
+ return;
+ }
+ }
+
+ // do it
+ (this->*op->func)(args, numArgs);
+}
+
+Operator *Gfx::findOp(char *name) {
+ int a, b, m, cmp;
+
+ a = -1;
+ b = numOps;
+ // invariant: opTab[a] < name < opTab[b]
+ while (b - a > 1) {
+ m = (a + b) / 2;
+ cmp = strcmp(opTab[m].name, name);
+ if (cmp < 0)
+ a = m;
+ else if (cmp > 0)
+ b = m;
+ else
+ a = b = m;
+ }
+ if (cmp != 0)
+ return NULL;
+ return &opTab[a];
+}
+
+GBool Gfx::checkArg(Object *arg, TchkType type) {
+ switch (type) {
+ case tchkBool: return arg->isBool();
+ case tchkInt: return arg->isInt();
+ case tchkNum: return arg->isNum();
+ case tchkString: return arg->isString();
+ case tchkName: return arg->isName();
+ case tchkArray: return arg->isArray();
+ case tchkProps: return arg->isDict() || arg->isName();
+ case tchkSCN: return arg->isNum() || arg->isName();
+ case tchkNone: return gFalse;
+ }
+ return gFalse;
+}
+
+int Gfx::getPos() {
+ return parser ? parser->getPos() : -1;
+}
+
+//------------------------------------------------------------------------
+// graphics state operators
+//------------------------------------------------------------------------
+
+void Gfx::opSave(Object args[], int numArgs) {
+ out->saveState(state);
+ state = state->save();
+}
+
+void Gfx::opRestore(Object args[], int numArgs) {
+ state = state->restore();
+ out->restoreState(state);
+
+ // Some PDF producers (Macromedia FreeHand) generate a save (q) and
+ // restore (Q) inside a path sequence. The PDF spec seems to imply
+ // that this is illegal. Calling clearPath() here implements the
+ // behavior apparently expected by this software.
+ state->clearPath();
+}
+
+void Gfx::opConcat(Object args[], int numArgs) {
+ state->concatCTM(args[0].getNum(), args[1].getNum(),
+ args[2].getNum(), args[3].getNum(),
+ args[4].getNum(), args[5].getNum());
+ out->updateCTM(state, args[0].getNum(), args[1].getNum(),
+ args[2].getNum(), args[3].getNum(),
+ args[4].getNum(), args[5].getNum());
+ fontChanged = gTrue;
+}
+
+void Gfx::opSetDash(Object args[], int numArgs) {
+ Array *a;
+ int length;
+ Object obj;
+ double *dash;
+ int i;
+
+ a = args[0].getArray();
+ length = a->getLength();
+ if (length == 0) {
+ dash = NULL;
+ } else {
+ dash = (double *)gmalloc(length * sizeof(double));
+ for (i = 0; i < length; ++i) {
+ dash[i] = a->get(i, &obj)->getNum();
+ obj.free();
+ }
+ }
+ state->setLineDash(dash, length, args[1].getNum());
+ out->updateLineDash(state);
+}
+
+void Gfx::opSetFlat(Object args[], int numArgs) {
+ state->setFlatness((int)args[0].getNum());
+ out->updateFlatness(state);
+}
+
+void Gfx::opSetLineJoin(Object args[], int numArgs) {
+ state->setLineJoin(args[0].getInt());
+ out->updateLineJoin(state);
+}
+
+void Gfx::opSetLineCap(Object args[], int numArgs) {
+ state->setLineCap(args[0].getInt());
+ out->updateLineCap(state);
+}
+
+void Gfx::opSetMiterLimit(Object args[], int numArgs) {
+ state->setMiterLimit(args[0].getNum());
+ out->updateMiterLimit(state);
+}
+
+void Gfx::opSetLineWidth(Object args[], int numArgs) {
+ state->setLineWidth(args[0].getNum());
+ out->updateLineWidth(state);
+}
+
+void Gfx::opSetExtGState(Object args[], int numArgs) {
+ Object obj1, obj2;
+
+ if (!res->lookupGState(args[0].getName(), &obj1)) {
+ return;
+ }
+ if (!obj1.isDict()) {
+ error(getPos(), "ExtGState '%s' is wrong type", args[0].getName());
+ obj1.free();
+ return;
+ }
+ if (obj1.dictLookup("ca", &obj2)->isNum()) {
+ state->setFillOpacity(obj2.getNum());
+ out->updateFillOpacity(state);
+ }
+ obj2.free();
+ if (obj1.dictLookup("CA", &obj2)->isNum()) {
+ state->setStrokeOpacity(obj2.getNum());
+ out->updateStrokeOpacity(state);
+ }
+ obj2.free();
+ obj1.free();
+}
+
+void Gfx::opSetRenderingIntent(Object args[], int numArgs) {
+}
+
+//------------------------------------------------------------------------
+// color operators
+//------------------------------------------------------------------------
+
+void Gfx::opSetFillGray(Object args[], int numArgs) {
+ GfxColor color;
+
+ state->setFillPattern(NULL);
+ state->setFillColorSpace(new GfxDeviceGrayColorSpace());
+ color.c[0] = args[0].getNum();
+ state->setFillColor(&color);
+ out->updateFillColor(state);
+}
+
+void Gfx::opSetStrokeGray(Object args[], int numArgs) {
+ GfxColor color;
+
+ state->setStrokePattern(NULL);
+ state->setStrokeColorSpace(new GfxDeviceGrayColorSpace());
+ color.c[0] = args[0].getNum();
+ state->setStrokeColor(&color);
+ out->updateStrokeColor(state);
+}
+
+void Gfx::opSetFillCMYKColor(Object args[], int numArgs) {
+ GfxColor color;
+ int i;
+
+ state->setFillPattern(NULL);
+ state->setFillColorSpace(new GfxDeviceCMYKColorSpace());
+ for (i = 0; i < 4; ++i) {
+ color.c[i] = args[i].getNum();
+ }
+ state->setFillColor(&color);
+ out->updateFillColor(state);
+}
+
+void Gfx::opSetStrokeCMYKColor(Object args[], int numArgs) {
+ GfxColor color;
+ int i;
+
+ state->setStrokePattern(NULL);
+ state->setStrokeColorSpace(new GfxDeviceCMYKColorSpace());
+ for (i = 0; i < 4; ++i) {
+ color.c[i] = args[i].getNum();
+ }
+ state->setStrokeColor(&color);
+ out->updateStrokeColor(state);
+}
+
+void Gfx::opSetFillRGBColor(Object args[], int numArgs) {
+ GfxColor color;
+ int i;
+
+ state->setFillPattern(NULL);
+ state->setFillColorSpace(new GfxDeviceRGBColorSpace());
+ for (i = 0; i < 3; ++i) {
+ color.c[i] = args[i].getNum();
+ }
+ state->setFillColor(&color);
+ out->updateFillColor(state);
+}
+
+void Gfx::opSetStrokeRGBColor(Object args[], int numArgs) {
+ GfxColor color;
+ int i;
+
+ state->setStrokePattern(NULL);
+ state->setStrokeColorSpace(new GfxDeviceRGBColorSpace());
+ for (i = 0; i < 3; ++i) {
+ color.c[i] = args[i].getNum();
+ }
+ state->setStrokeColor(&color);
+ out->updateStrokeColor(state);
+}
+
+void Gfx::opSetFillColorSpace(Object args[], int numArgs) {
+ Object obj;
+ GfxColorSpace *colorSpace;
+ GfxColor color;
+ int i;
+
+ state->setFillPattern(NULL);
+ res->lookupColorSpace(args[0].getName(), &obj);
+ if (obj.isNull()) {
+ colorSpace = GfxColorSpace::parse(&args[0]);
+ } else {
+ colorSpace = GfxColorSpace::parse(&obj);
+ }
+ obj.free();
+ if (colorSpace) {
+ state->setFillColorSpace(colorSpace);
+ } else {
+ error(getPos(), "Bad color space (fill)");
+ }
+ for (i = 0; i < gfxColorMaxComps; ++i) {
+ color.c[i] = 0;
+ }
+ state->setFillColor(&color);
+ out->updateFillColor(state);
+}
+
+void Gfx::opSetStrokeColorSpace(Object args[], int numArgs) {
+ Object obj;
+ GfxColorSpace *colorSpace;
+ GfxColor color;
+ int i;
+
+ state->setStrokePattern(NULL);
+ res->lookupColorSpace(args[0].getName(), &obj);
+ if (obj.isNull()) {
+ colorSpace = GfxColorSpace::parse(&args[0]);
+ } else {
+ colorSpace = GfxColorSpace::parse(&obj);
+ }
+ obj.free();
+ if (colorSpace) {
+ state->setStrokeColorSpace(colorSpace);
+ } else {
+ error(getPos(), "Bad color space (stroke)");
+ }
+ for (i = 0; i < gfxColorMaxComps; ++i) {
+ color.c[i] = 0;
+ }
+ state->setStrokeColor(&color);
+ out->updateStrokeColor(state);
+}
+
+void Gfx::opSetFillColor(Object args[], int numArgs) {
+ GfxColor color;
+ int i;
+
+ state->setFillPattern(NULL);
+ for (i = 0; i < numArgs; ++i) {
+ color.c[i] = args[i].getNum();
+ }
+ state->setFillColor(&color);
+ out->updateFillColor(state);
+}
+
+void Gfx::opSetStrokeColor(Object args[], int numArgs) {
+ GfxColor color;
+ int i;
+
+ state->setStrokePattern(NULL);
+ for (i = 0; i < numArgs; ++i) {
+ color.c[i] = args[i].getNum();
+ }
+ state->setStrokeColor(&color);
+ out->updateStrokeColor(state);
+}
+
+void Gfx::opSetFillColorN(Object args[], int numArgs) {
+ GfxColor color;
+ GfxPattern *pattern;
+ int i;
+
+ if (state->getFillColorSpace()->getMode() == csPattern) {
+ if (numArgs > 1) {
+ for (i = 0; i < numArgs && i < 4; ++i) {
+ if (args[i].isNum()) {
+ color.c[i] = args[i].getNum();
+ }
+ }
+ state->setFillColor(&color);
+ out->updateFillColor(state);
+ }
+ if (args[numArgs-1].isName() &&
+ (pattern = res->lookupPattern(args[numArgs-1].getName()))) {
+ state->setFillPattern(pattern);
+ }
+
+ } else {
+ state->setFillPattern(NULL);
+ for (i = 0; i < numArgs && i < 4; ++i) {
+ if (args[i].isNum()) {
+ color.c[i] = args[i].getNum();
+ }
+ }
+ state->setFillColor(&color);
+ out->updateFillColor(state);
+ }
+}
+
+void Gfx::opSetStrokeColorN(Object args[], int numArgs) {
+ GfxColor color;
+ GfxPattern *pattern;
+ int i;
+
+ if (state->getStrokeColorSpace()->getMode() == csPattern) {
+ if (numArgs > 1) {
+ for (i = 0; i < numArgs && i < 4; ++i) {
+ if (args[i].isNum()) {
+ color.c[i] = args[i].getNum();
+ }
+ }
+ state->setStrokeColor(&color);
+ out->updateStrokeColor(state);
+ }
+ if (args[numArgs-1].isName() &&
+ (pattern = res->lookupPattern(args[numArgs-1].getName()))) {
+ state->setStrokePattern(pattern);
+ }
+
+ } else {
+ state->setStrokePattern(NULL);
+ for (i = 0; i < numArgs && i < 4; ++i) {
+ if (args[i].isNum()) {
+ color.c[i] = args[i].getNum();
+ }
+ }
+ state->setStrokeColor(&color);
+ out->updateStrokeColor(state);
+ }
+}
+
+//------------------------------------------------------------------------
+// path segment operators
+//------------------------------------------------------------------------
+
+void Gfx::opMoveTo(Object args[], int numArgs) {
+ state->moveTo(args[0].getNum(), args[1].getNum());
+}
+
+void Gfx::opLineTo(Object args[], int numArgs) {
+ if (!state->isCurPt()) {
+ error(getPos(), "No current point in lineto");
+ return;
+ }
+ state->lineTo(args[0].getNum(), args[1].getNum());
+}
+
+void Gfx::opCurveTo(Object args[], int numArgs) {
+ double x1, y1, x2, y2, x3, y3;
+
+ if (!state->isCurPt()) {
+ error(getPos(), "No current point in curveto");
+ return;
+ }
+ x1 = args[0].getNum();
+ y1 = args[1].getNum();
+ x2 = args[2].getNum();
+ y2 = args[3].getNum();
+ x3 = args[4].getNum();
+ y3 = args[5].getNum();
+ state->curveTo(x1, y1, x2, y2, x3, y3);
+}
+
+void Gfx::opCurveTo1(Object args[], int numArgs) {
+ double x1, y1, x2, y2, x3, y3;
+
+ if (!state->isCurPt()) {
+ error(getPos(), "No current point in curveto1");
+ return;
+ }
+ x1 = state->getCurX();
+ y1 = state->getCurY();
+ x2 = args[0].getNum();
+ y2 = args[1].getNum();
+ x3 = args[2].getNum();
+ y3 = args[3].getNum();
+ state->curveTo(x1, y1, x2, y2, x3, y3);
+}
+
+void Gfx::opCurveTo2(Object args[], int numArgs) {
+ double x1, y1, x2, y2, x3, y3;
+
+ if (!state->isCurPt()) {
+ error(getPos(), "No current point in curveto2");
+ return;
+ }
+ x1 = args[0].getNum();
+ y1 = args[1].getNum();
+ x2 = args[2].getNum();
+ y2 = args[3].getNum();
+ x3 = x2;
+ y3 = y2;
+ state->curveTo(x1, y1, x2, y2, x3, y3);
+}
+
+void Gfx::opRectangle(Object args[], int numArgs) {
+ double x, y, w, h;
+
+ x = args[0].getNum();
+ y = args[1].getNum();
+ w = args[2].getNum();
+ h = args[3].getNum();
+ state->moveTo(x, y);
+ state->lineTo(x + w, y);
+ state->lineTo(x + w, y + h);
+ state->lineTo(x, y + h);
+ state->closePath();
+}
+
+void Gfx::opClosePath(Object args[], int numArgs) {
+ if (!state->isPath()) {
+ error(getPos(), "No current point in closepath");
+ return;
+ }
+ state->closePath();
+}
+
+//------------------------------------------------------------------------
+// path painting operators
+//------------------------------------------------------------------------
+
+void Gfx::opEndPath(Object args[], int numArgs) {
+ doEndPath();
+}
+
+void Gfx::opStroke(Object args[], int numArgs) {
+ if (!state->isCurPt()) {
+ //error(getPos(), "No path in stroke");
+ return;
+ }
+ if (state->isPath())
+ out->stroke(state);
+ doEndPath();
+}
+
+void Gfx::opCloseStroke(Object args[], int numArgs) {
+ if (!state->isCurPt()) {
+ //error(getPos(), "No path in closepath/stroke");
+ return;
+ }
+ if (state->isPath()) {
+ state->closePath();
+ out->stroke(state);
+ }
+ doEndPath();
+}
+
+void Gfx::opFill(Object args[], int numArgs) {
+ if (!state->isCurPt()) {
+ //error(getPos(), "No path in fill");
+ return;
+ }
+ if (state->isPath()) {
+ if (state->getFillColorSpace()->getMode() == csPattern) {
+ doPatternFill(gFalse);
+ } else {
+ out->fill(state);
+ }
+ }
+ doEndPath();
+}
+
+void Gfx::opEOFill(Object args[], int numArgs) {
+ if (!state->isCurPt()) {
+ //error(getPos(), "No path in eofill");
+ return;
+ }
+ if (state->isPath()) {
+ if (state->getFillColorSpace()->getMode() == csPattern) {
+ doPatternFill(gTrue);
+ } else {
+ out->eoFill(state);
+ }
+ }
+ doEndPath();
+}
+
+void Gfx::opFillStroke(Object args[], int numArgs) {
+ if (!state->isCurPt()) {
+ //error(getPos(), "No path in fill/stroke");
+ return;
+ }
+ if (state->isPath()) {
+ if (state->getFillColorSpace()->getMode() == csPattern) {
+ doPatternFill(gFalse);
+ } else {
+ out->fill(state);
+ }
+ out->stroke(state);
+ }
+ doEndPath();
+}
+
+void Gfx::opCloseFillStroke(Object args[], int numArgs) {
+ if (!state->isCurPt()) {
+ //error(getPos(), "No path in closepath/fill/stroke");
+ return;
+ }
+ if (state->isPath()) {
+ state->closePath();
+ if (state->getFillColorSpace()->getMode() == csPattern) {
+ doPatternFill(gFalse);
+ } else {
+ out->fill(state);
+ }
+ out->stroke(state);
+ }
+ doEndPath();
+}
+
+void Gfx::opEOFillStroke(Object args[], int numArgs) {
+ if (!state->isCurPt()) {
+ //error(getPos(), "No path in eofill/stroke");
+ return;
+ }
+ if (state->isPath()) {
+ if (state->getFillColorSpace()->getMode() == csPattern) {
+ doPatternFill(gTrue);
+ } else {
+ out->eoFill(state);
+ }
+ out->stroke(state);
+ }
+ doEndPath();
+}
+
+void Gfx::opCloseEOFillStroke(Object args[], int numArgs) {
+ if (!state->isCurPt()) {
+ //error(getPos(), "No path in closepath/eofill/stroke");
+ return;
+ }
+ if (state->isPath()) {
+ state->closePath();
+ if (state->getFillColorSpace()->getMode() == csPattern) {
+ doPatternFill(gTrue);
+ } else {
+ out->eoFill(state);
+ }
+ out->stroke(state);
+ }
+ doEndPath();
+}
+
+void Gfx::doPatternFill(GBool eoFill) {
+ GfxPatternColorSpace *patCS;
+ GfxPattern *pattern;
+ GfxTilingPattern *tPat;
+ GfxColorSpace *cs;
+ double xMin, yMin, xMax, yMax, x, y, x1, y1;
+ double cxMin, cyMin, cxMax, cyMax;
+ int xi0, yi0, xi1, yi1, xi, yi;
+ double *ctm, *btm, *ptm;
+ double m[6], ictm[6], m1[6], im[6], imb[6];
+ double det;
+ double xstep, ystep;
+ int i;
+
+ // get color space
+ patCS = (GfxPatternColorSpace *)state->getFillColorSpace();
+
+ // get pattern
+ if (!(pattern = state->getFillPattern())) {
+ return;
+ }
+ if (pattern->getType() != 1) {
+ return;
+ }
+ tPat = (GfxTilingPattern *)pattern;
+
+ // construct a (pattern space) -> (current space) transform matrix
+ ctm = state->getCTM();
+ btm = baseMatrix;
+ ptm = tPat->getMatrix();
+ // iCTM = invert CTM
+ det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
+ ictm[0] = ctm[3] * det;
+ ictm[1] = -ctm[1] * det;
+ ictm[2] = -ctm[2] * det;
+ ictm[3] = ctm[0] * det;
+ ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
+ ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
+ // m1 = PTM * BTM = PTM * base transform matrix
+ m1[0] = ptm[0] * btm[0] + ptm[1] * btm[2];
+ m1[1] = ptm[0] * btm[1] + ptm[1] * btm[3];
+ m1[2] = ptm[2] * btm[0] + ptm[3] * btm[2];
+ m1[3] = ptm[2] * btm[1] + ptm[3] * btm[3];
+ m1[4] = ptm[4] * btm[0] + ptm[5] * btm[2] + btm[4];
+ m1[5] = ptm[4] * btm[1] + ptm[5] * btm[3] + btm[5];
+ // m = m1 * iCTM = (PTM * BTM) * (iCTM)
+ m[0] = m1[0] * ictm[0] + m1[1] * ictm[2];
+ m[1] = m1[0] * ictm[1] + m1[1] * ictm[3];
+ m[2] = m1[2] * ictm[0] + m1[3] * ictm[2];
+ m[3] = m1[2] * ictm[1] + m1[3] * ictm[3];
+ m[4] = m1[4] * ictm[0] + m1[5] * ictm[2] + ictm[4];
+ m[5] = m1[4] * ictm[1] + m1[5] * ictm[3] + ictm[5];
+
+ // construct a (current space) -> (pattern space) transform matrix
+ det = 1 / (m[0] * m[3] - m[1] * m[2]);
+ im[0] = m[3] * det;
+ im[1] = -m[1] * det;
+ im[2] = -m[2] * det;
+ im[3] = m[0] * det;
+ im[4] = (m[2] * m[5] - m[3] * m[4]) * det;
+ im[5] = (m[1] * m[4] - m[0] * m[5]) * det;
+
+ // construct a (base space) -> (pattern space) transform matrix
+ det = 1 / (m1[0] * m1[3] - m1[1] * m1[2]);
+ imb[0] = m1[3] * det;
+ imb[1] = -m1[1] * det;
+ imb[2] = -m1[2] * det;
+ imb[3] = m1[0] * det;
+ imb[4] = (m1[2] * m1[5] - m1[3] * m1[4]) * det;
+ imb[5] = (m1[1] * m1[4] - m1[0] * m1[5]) * det;
+
+ // save current graphics state
+ out->saveState(state);
+ state = state->save();
+
+ // set underlying color space (for uncolored tiling patterns)
+ if (tPat->getPaintType() == 2 && (cs = patCS->getUnder())) {
+ state->setFillColorSpace(cs->copy());
+ } else {
+ state->setFillColorSpace(new GfxDeviceGrayColorSpace());
+ }
+ state->setFillPattern(NULL);
+ out->updateFillColor(state);
+
+ // clip to current path
+ state->clip();
+ if (eoFill) {
+ out->eoClip(state);
+ } else {
+ out->clip(state);
+ }
+ state->clearPath();
+
+ // transform clip region bbox to pattern space
+ state->getClipBBox(&cxMin, &cyMin, &cxMax, &cyMax);
+ xMin = xMax = cxMin * imb[0] + cyMin * imb[2] + imb[4];
+ yMin = yMax = cxMin * imb[1] + cyMin * imb[3] + imb[5];
+ x1 = cxMin * imb[0] + cyMax * imb[2] + imb[4];
+ y1 = cxMin * imb[1] + cyMax * imb[3] + imb[5];
+ if (x1 < xMin) {
+ xMin = x1;
+ } else if (x1 > xMax) {
+ xMax = x1;
+ }
+ if (y1 < yMin) {
+ yMin = y1;
+ } else if (y1 > yMax) {
+ yMax = y1;
+ }
+ x1 = cxMax * imb[0] + cyMin * imb[2] + imb[4];
+ y1 = cxMax * imb[1] + cyMin * imb[3] + imb[5];
+ if (x1 < xMin) {
+ xMin = x1;
+ } else if (x1 > xMax) {
+ xMax = x1;
+ }
+ if (y1 < yMin) {
+ yMin = y1;
+ } else if (y1 > yMax) {
+ yMax = y1;
+ }
+ x1 = cxMax * imb[0] + cyMax * imb[2] + imb[4];
+ y1 = cxMax * imb[1] + cyMax * imb[3] + imb[5];
+ if (x1 < xMin) {
+ xMin = x1;
+ } else if (x1 > xMax) {
+ xMax = x1;
+ }
+ if (y1 < yMin) {
+ yMin = y1;
+ } else if (y1 > yMax) {
+ yMax = y1;
+ }
+
+ // draw the pattern
+ //~ this should treat negative steps differently -- start at right/top
+ //~ edge instead of left/bottom (?)
+ xstep = fabs(tPat->getXStep());
+ ystep = fabs(tPat->getYStep());
+ xi0 = (int)floor(xMin / xstep);
+ xi1 = (int)ceil(xMax / xstep);
+ yi0 = (int)floor(yMin / ystep);
+ yi1 = (int)ceil(yMax / ystep);
+ for (i = 0; i < 4; ++i) {
+ m1[i] = m[i];
+ }
+ for (yi = yi0; yi < yi1; ++yi) {
+ for (xi = xi0; xi < xi1; ++xi) {
+ x = xi * xstep;
+ y = yi * ystep;
+ m1[4] = x * m[0] + y * m[2] + m[4];
+ m1[5] = x * m[1] + y * m[3] + m[5];
+ doForm1(tPat->getContentStream(), tPat->getResDict(),
+ m1, tPat->getBBox());
+ }
+ }
+
+ // restore graphics state
+ state = state->restore();
+ out->restoreState(state);
+}
+
+void Gfx::opShFill(Object args[], int numArgs) {
+ GfxShading *shading;
+ double xMin, yMin, xMax, yMax;
+
+ if (!(shading = res->lookupShading(args[0].getName()))) {
+ return;
+ }
+
+ // save current graphics state
+ out->saveState(state);
+ state = state->save();
+
+ // clip to bbox
+ if (shading->getHasBBox()) {
+ shading->getBBox(&xMin, &yMin, &xMax, &yMax);
+ state->moveTo(xMin, yMin);
+ state->lineTo(xMax, yMin);
+ state->lineTo(xMax, yMax);
+ state->lineTo(xMin, yMax);
+ state->closePath();
+ state->clip();
+ out->clip(state);
+ state->clearPath();
+ }
+
+ // set the color space
+ state->setFillColorSpace(shading->getColorSpace()->copy());
+
+ // do shading type-specific operations
+ switch (shading->getType()) {
+ case 2:
+ doAxialShFill((GfxAxialShading *)shading);
+ break;
+ }
+
+ // restore graphics state
+ state = state->restore();
+ out->restoreState(state);
+
+ delete shading;
+}
+
+void Gfx::doAxialShFill(GfxAxialShading *shading) {
+ double xMin, yMin, xMax, yMax;
+ double x0, y0, x1, y1;
+ double det;
+ double *ctm;
+ double ictm[6];
+ double dx, dy, mul;
+ double tMin, tMax, t, tx, ty;
+ double s[4], sMin, sMax, tmp;
+ double ux0, uy0, ux1, uy1, vx0, vy0, vx1, vy1;
+ double t0, t1, tt;
+ double ta[axialMaxSplits + 1];
+ int next[axialMaxSplits + 1];
+ GfxColor color0, color1;
+ int nComps;
+ int i, j, k, kk;
+
+ // get clip region bbox and transform to current user space
+ state->getClipBBox(&x0, &y0, &x1, &y1);
+ ctm = state->getCTM();
+ det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
+ ictm[0] = ctm[3] * det;
+ ictm[1] = -ctm[1] * det;
+ ictm[2] = -ctm[2] * det;
+ ictm[3] = ctm[0] * det;
+ ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
+ ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
+ xMin = xMax = x0 * ictm[0] + y0 * ictm[2] + ictm[4];
+ yMin = yMax = x0 * ictm[1] + y0 * ictm[3] + ictm[5];
+ tx = x0 * ictm[0] + y1 * ictm[2] + ictm[4];
+ ty = x0 * ictm[1] + y1 * ictm[3] + ictm[5];
+ if (tx < xMin) {
+ xMin = tx;
+ } else if (tx > xMax) {
+ xMax = tx;
+ }
+ if (ty < yMin) {
+ yMin = ty;
+ } else if (ty > yMax) {
+ yMax = ty;
+ }
+ tx = x1 * ictm[0] + y0 * ictm[2] + ictm[4];
+ ty = x1 * ictm[1] + y0 * ictm[3] + ictm[5];
+ if (tx < xMin) {
+ xMin = tx;
+ } else if (tx > xMax) {
+ xMax = tx;
+ }
+ if (ty < yMin) {
+ yMin = ty;
+ } else if (ty > yMax) {
+ yMax = ty;
+ }
+ tx = x1 * ictm[0] + y1 * ictm[2] + ictm[4];
+ ty = x1 * ictm[1] + y1 * ictm[3] + ictm[5];
+ if (tx < xMin) {
+ xMin = tx;
+ } else if (tx > xMax) {
+ xMax = tx;
+ }
+ if (ty < yMin) {
+ yMin = ty;
+ } else if (ty > yMax) {
+ yMax = ty;
+ }
+
+ // compute min and max t values, based on the four corners of the
+ // clip region bbox
+ shading->getCoords(&x0, &y0, &x1, &y1);
+ dx = x1 - x0;
+ dy = y1 - y0;
+ mul = 1 / (dx * dx + dy * dy);
+ tMin = tMax = ((xMin - x0) * dx + (yMin - y0) * dy) * mul;
+ t = ((xMin - x0) * dx + (yMax - y0) * dy) * mul;
+ if (t < tMin) {
+ tMin = t;
+ } else if (t > tMax) {
+ tMax = t;
+ }
+ t = ((xMax - x0) * dx + (yMin - y0) * dy) * mul;
+ if (t < tMin) {
+ tMin = t;
+ } else if (t > tMax) {
+ tMax = t;
+ }
+ t = ((xMax - x0) * dx + (yMax - y0) * dy) * mul;
+ if (t < tMin) {
+ tMin = t;
+ } else if (t > tMax) {
+ tMax = t;
+ }
+ if (tMin < 0 && !shading->getExtend0()) {
+ tMin = 0;
+ }
+ if (tMax > 1 && !shading->getExtend1()) {
+ tMax = 1;
+ }
+
+ // get the function domain
+ t0 = shading->getDomain0();
+ t1 = shading->getDomain1();
+
+ // Traverse the t axis and do the shading.
+ //
+ // For each point (tx, ty) on the t axis, consider a line through
+ // that point perpendicular to the t axis:
+ //
+ // x(s) = tx + s * -dy --> s = (x - tx) / -dy
+ // y(s) = ty + s * dx --> s = (y - ty) / dx
+ //
+ // Then look at the intersection of this line with the bounding box
+ // (xMin, yMin, xMax, yMax). In the general case, there are four
+ // intersection points:
+ //
+ // s0 = (xMin - tx) / -dy
+ // s1 = (xMax - tx) / -dy
+ // s2 = (yMin - ty) / dx
+ // s3 = (yMax - ty) / dx
+ //
+ // and we want the middle two s values.
+ //
+ // In the case where dx = 0, take s0 and s1; in the case where dy =
+ // 0, take s2 and s3.
+ //
+ // Each filled polygon is bounded by two of these line segments
+ // perpdendicular to the t axis.
+ //
+ // The t axis is bisected into smaller regions until the color
+ // difference across a region is small enough, and then the region
+ // is painted with a single color.
+
+ // set up
+ nComps = shading->getColorSpace()->getNComps();
+ ta[0] = tMin;
+ ta[axialMaxSplits] = tMax;
+ next[0] = axialMaxSplits;
+
+ // compute the color at t = tMin
+ if (tMin < 0) {
+ tt = t0;
+ } else if (tMin > 1) {
+ tt = t1;
+ } else {
+ tt = t0 + (t1 - t0) * tMin;
+ }
+ shading->getColor(tt, &color0);
+
+ // compute the coordinates of the point on the t axis at t = tMin;
+ // then compute the intersection of the perpendicular line with the
+ // bounding box
+ tx = x0 + tMin * dx;
+ ty = y0 + tMin * dy;
+ if (dx == 0 && dy == 0) {
+ sMin = sMax = 0;
+ } if (dx == 0) {
+ sMin = (xMin - tx) / -dy;
+ sMax = (xMax - tx) / -dy;
+ if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; }
+ } else if (dy == 0) {
+ sMin = (yMin - ty) / dx;
+ sMax = (yMax - ty) / dx;
+ if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; }
+ } else {
+ s[0] = (yMin - ty) / dx;
+ s[1] = (yMax - ty) / dx;
+ s[2] = (xMin - tx) / -dy;
+ s[3] = (xMax - tx) / -dy;
+ for (j = 0; j < 3; ++j) {
+ kk = j;
+ for (k = j + 1; k < 4; ++k) {
+ if (s[k] < s[kk]) {
+ kk = k;
+ }
+ }
+ tmp = s[j]; s[j] = s[kk]; s[kk] = tmp;
+ }
+ sMin = s[1];
+ sMax = s[2];
+ }
+ ux0 = tx - sMin * dy;
+ uy0 = ty + sMin * dx;
+ vx0 = tx - sMax * dy;
+ vy0 = ty + sMax * dx;
+
+ i = 0;
+ while (i < axialMaxSplits) {
+
+ // bisect until color difference is small enough or we hit the
+ // bisection limit
+ j = next[i];
+ while (j > i + 1) {
+ if (ta[j] < 0) {
+ tt = t0;
+ } else if (ta[j] > 1) {
+ tt = t1;
+ } else {
+ tt = t0 + (t1 - t0) * ta[j];
+ }
+ shading->getColor(tt, &color1);
+ for (k = 0; k < nComps; ++k) {
+ if (fabs(color1.c[k] - color0.c[k]) > axialColorDelta) {
+ break;
+ }
+ }
+ if (k == nComps) {
+ break;
+ }
+ k = (i + j) / 2;
+ ta[k] = 0.5 * (ta[i] + ta[j]);
+ next[i] = k;
+ next[k] = j;
+ j = k;
+ }
+
+ // use the average of the colors of the two sides of the region
+ for (k = 0; k < nComps; ++k) {
+ color0.c[k] = 0.5 * (color0.c[k] + color1.c[k]);
+ }
+
+ // compute the coordinates of the point on the t axis; then
+ // compute the intersection of the perpendicular line with the
+ // bounding box
+ tx = x0 + ta[j] * dx;
+ ty = y0 + ta[j] * dy;
+ if (dx == 0 && dy == 0) {
+ sMin = sMax = 0;
+ } if (dx == 0) {
+ sMin = (xMin - tx) / -dy;
+ sMax = (xMax - tx) / -dy;
+ if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; }
+ } else if (dy == 0) {
+ sMin = (yMin - ty) / dx;
+ sMax = (yMax - ty) / dx;
+ if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; }
+ } else {
+ s[0] = (yMin - ty) / dx;
+ s[1] = (yMax - ty) / dx;
+ s[2] = (xMin - tx) / -dy;
+ s[3] = (xMax - tx) / -dy;
+ for (j = 0; j < 3; ++j) {
+ kk = j;
+ for (k = j + 1; k < 4; ++k) {
+ if (s[k] < s[kk]) {
+ kk = k;
+ }
+ }
+ tmp = s[j]; s[j] = s[kk]; s[kk] = tmp;
+ }
+ sMin = s[1];
+ sMax = s[2];
+ }
+ ux1 = tx - sMin * dy;
+ uy1 = ty + sMin * dx;
+ vx1 = tx - sMax * dy;
+ vy1 = ty + sMax * dx;
+
+ // set the color
+ state->setFillColor(&color0);
+ out->updateFillColor(state);
+
+ // fill the region
+ state->moveTo(ux0, uy0);
+ state->lineTo(vx0, vy0);
+ state->lineTo(vx1, vy1);
+ state->lineTo(ux1, uy1);
+ state->closePath();
+ out->fill(state);
+ state->clearPath();
+
+ // set up for next region
+ ux0 = ux1;
+ uy0 = uy1;
+ vx0 = vx1;
+ vy0 = vy1;
+ color0 = color1;
+ i = next[i];
+ }
+}
+
+void Gfx::doEndPath() {
+ if (state->isPath() && clip != clipNone) {
+ state->clip();
+ if (clip == clipNormal) {
+ out->clip(state);
+ } else {
+ out->eoClip(state);
+ }
+ }
+ clip = clipNone;
+ state->clearPath();
+}
+
+//------------------------------------------------------------------------
+// path clipping operators
+//------------------------------------------------------------------------
+
+void Gfx::opClip(Object args[], int numArgs) {
+ clip = clipNormal;
+}
+
+void Gfx::opEOClip(Object args[], int numArgs) {
+ clip = clipEO;
+}
+
+//------------------------------------------------------------------------
+// text object operators
+//------------------------------------------------------------------------
+
+void Gfx::opBeginText(Object args[], int numArgs) {
+ state->setTextMat(1, 0, 0, 1, 0, 0);
+ state->textMoveTo(0, 0);
+ out->updateTextMat(state);
+ out->updateTextPos(state);
+ fontChanged = gTrue;
+}
+
+void Gfx::opEndText(Object args[], int numArgs) {
+}
+
+//------------------------------------------------------------------------
+// text state operators
+//------------------------------------------------------------------------
+
+void Gfx::opSetCharSpacing(Object args[], int numArgs) {
+ state->setCharSpace(args[0].getNum());
+ out->updateCharSpace(state);
+}
+
+void Gfx::opSetFont(Object args[], int numArgs) {
+ GfxFont *font;
+
+ if (!(font = res->lookupFont(args[0].getName()))) {
+ return;
+ }
+ if (printCommands) {
+ printf(" font: '%s' %g\n",
+ font->getName() ? font->getName()->getCString() : "???",
+ args[1].getNum());
+ fflush(stdout);
+ }
+ state->setFont(font, args[1].getNum());
+ fontChanged = gTrue;
+}
+
+void Gfx::opSetTextLeading(Object args[], int numArgs) {
+ state->setLeading(args[0].getNum());
+}
+
+void Gfx::opSetTextRender(Object args[], int numArgs) {
+ state->setRender(args[0].getInt());
+ out->updateRender(state);
+}
+
+void Gfx::opSetTextRise(Object args[], int numArgs) {
+ state->setRise(args[0].getNum());
+ out->updateRise(state);
+}
+
+void Gfx::opSetWordSpacing(Object args[], int numArgs) {
+ state->setWordSpace(args[0].getNum());
+ out->updateWordSpace(state);
+}
+
+void Gfx::opSetHorizScaling(Object args[], int numArgs) {
+ state->setHorizScaling(args[0].getNum());
+ out->updateHorizScaling(state);
+ fontChanged = gTrue;
+}
+
+//------------------------------------------------------------------------
+// text positioning operators
+//------------------------------------------------------------------------
+
+void Gfx::opTextMove(Object args[], int numArgs) {
+ double tx, ty;
+
+ tx = state->getLineX() + args[0].getNum();
+ ty = state->getLineY() + args[1].getNum();
+ state->textMoveTo(tx, ty);
+ out->updateTextPos(state);
+}
+
+void Gfx::opTextMoveSet(Object args[], int numArgs) {
+ double tx, ty;
+
+ tx = state->getLineX() + args[0].getNum();
+ ty = args[1].getNum();
+ state->setLeading(-ty);
+ ty += state->getLineY();
+ state->textMoveTo(tx, ty);
+ out->updateTextPos(state);
+}
+
+void Gfx::opSetTextMatrix(Object args[], int numArgs) {
+ state->setTextMat(args[0].getNum(), args[1].getNum(),
+ args[2].getNum(), args[3].getNum(),
+ args[4].getNum(), args[5].getNum());
+ state->textMoveTo(0, 0);
+ out->updateTextMat(state);
+ out->updateTextPos(state);
+ fontChanged = gTrue;
+}
+
+void Gfx::opTextNextLine(Object args[], int numArgs) {
+ double tx, ty;
+
+ tx = state->getLineX();
+ ty = state->getLineY() - state->getLeading();
+ state->textMoveTo(tx, ty);
+ out->updateTextPos(state);
+}
+
+//------------------------------------------------------------------------
+// text string operators
+//------------------------------------------------------------------------
+
+void Gfx::opShowText(Object args[], int numArgs) {
+ if (!state->getFont()) {
+ error(getPos(), "No font in show");
+ return;
+ }
+ doShowText(args[0].getString());
+}
+
+void Gfx::opMoveShowText(Object args[], int numArgs) {
+ double tx, ty;
+
+ if (!state->getFont()) {
+ error(getPos(), "No font in move/show");
+ return;
+ }
+ tx = state->getLineX();
+ ty = state->getLineY() - state->getLeading();
+ state->textMoveTo(tx, ty);
+ out->updateTextPos(state);
+ doShowText(args[0].getString());
+}
+
+void Gfx::opMoveSetShowText(Object args[], int numArgs) {
+ double tx, ty;
+
+ if (!state->getFont()) {
+ error(getPos(), "No font in move/set/show");
+ return;
+ }
+ state->setWordSpace(args[0].getNum());
+ state->setCharSpace(args[1].getNum());
+ tx = state->getLineX();
+ ty = state->getLineY() - state->getLeading();
+ state->textMoveTo(tx, ty);
+ out->updateWordSpace(state);
+ out->updateCharSpace(state);
+ out->updateTextPos(state);
+ doShowText(args[2].getString());
+}
+
+void Gfx::opShowSpaceText(Object args[], int numArgs) {
+ Array *a;
+ Object obj;
+ int i;
+
+ if (!state->getFont()) {
+ error(getPos(), "No font in show/space");
+ return;
+ }
+ a = args[0].getArray();
+ for (i = 0; i < a->getLength(); ++i) {
+ a->get(i, &obj);
+ if (obj.isNum()) {
+ state->textShift(-obj.getNum() * 0.001 * state->getFontSize());
+ out->updateTextShift(state, obj.getNum());
+ } else if (obj.isString()) {
+ doShowText(obj.getString());
+ } else {
+ error(getPos(), "Element of show/space array must be number or string");
+ }
+ obj.free();
+ }
+}
+
+void Gfx::doShowText(GString *s) {
+ GfxFont *font;
+ GfxFontEncoding16 *enc;
+ Guchar *p;
+ Guchar c8;
+ int c16;
+ GString *s16;
+ char s16a[2];
+ int m, n;
+#if 1 //~type3
+ double dx, dy, width, height, w, h, x, y;
+ double oldCTM[6], newCTM[6];
+ double *mat;
+ Object charProc;
+ Parser *oldParser;
+ int i;
+#else
+ double dx, dy, width, height, w, h;
+#endif
+ double sWidth, sHeight;
+
+ if (fontChanged) {
+ out->updateFont(state);
+ fontChanged = gFalse;
+ }
+ font = state->getFont();
+
+ //----- 16-bit font
+ if (font->is16Bit()) {
+ enc = font->getEncoding16();
+ if (out->useDrawChar()) {
+ out->beginString(state, s);
+ s16 = NULL;
+ } else {
+ s16 = new GString();
+ }
+ sWidth = sHeight = 0;
+ state->textTransformDelta(0, state->getRise(), &dx, &dy);
+ p = (Guchar *)s->getCString();
+ n = s->getLength();
+ while (n > 0) {
+ m = getNextChar16(enc, p, &c16);
+ if (enc->wMode == 0) {
+ width = state->getFontSize() * font->getWidth16(c16) +
+ state->getCharSpace();
+ if (m == 1 && c16 == ' ') {
+ width += state->getWordSpace();
+ }
+ width *= state->getHorizScaling();
+ height = 0;
+ } else {
+ width = 0;
+ height = state->getFontSize() * font->getHeight16(c16);
+ }
+ state->textTransformDelta(width, height, &w, &h);
+ if (out->useDrawChar()) {
+ out->drawChar16(state, state->getCurX() + dx, state->getCurY() + dy,
+ w, h, c16);
+ state->textShift(width, height);
+ } else {
+ s16a[0] = (char)(c16 >> 8);
+ s16a[1] = (char)c16;
+ s16->append(s16a, 2);
+ sWidth += w;
+ sHeight += h;
+ }
+ n -= m;
+ p += m;
+ }
+ if (out->useDrawChar()) {
+ out->endString(state);
+ } else {
+ out->drawString16(state, s16);
+ delete s16;
+ state->textShift(sWidth, sHeight);
+ }
+
+ //----- 8-bit font
+ } else {
+#if 1 //~type3
+ //~ also check out->renderType3()
+ if (font->getType() == fontType3) {
+ out->beginString(state, s);
+ mat = state->getCTM();
+ for (i = 0; i < 6; ++i) {
+ oldCTM[i] = mat[i];
+ }
+ mat = state->getTextMat();
+ newCTM[0] = mat[0] * oldCTM[0] + mat[1] * oldCTM[2];
+ newCTM[1] = mat[0] * oldCTM[1] + mat[1] * oldCTM[3];
+ newCTM[2] = mat[2] * oldCTM[0] + mat[3] * oldCTM[2];
+ newCTM[3] = mat[2] * oldCTM[1] + mat[3] * oldCTM[3];
+ mat = font->getFontMatrix();
+ newCTM[0] = mat[0] * newCTM[0] + mat[1] * newCTM[2];
+ newCTM[1] = mat[0] * newCTM[1] + mat[1] * newCTM[3];
+ newCTM[2] = mat[2] * newCTM[0] + mat[3] * newCTM[2];
+ newCTM[3] = mat[2] * newCTM[1] + mat[3] * newCTM[3];
+ newCTM[0] *= state->getFontSize();
+ newCTM[3] *= state->getFontSize();
+ newCTM[0] *= state->getHorizScaling();
+ newCTM[2] *= state->getHorizScaling();
+ state->textTransformDelta(0, state->getRise(), &dx, &dy);
+ oldParser = parser;
+ for (p = (Guchar *)s->getCString(), n = s->getLength(); n; ++p, --n) {
+ c8 = *p;
+ font->getCharProc(c8, &charProc);
+ state->transform(state->getCurX() + dx, state->getCurY() + dy, &x, &y);
+ out->saveState(state);
+ state = state->save();
+ state->setCTM(newCTM[0], newCTM[1], newCTM[2], newCTM[3], x, y);
+ //~ out->updateCTM(???)
+ if (charProc.isStream()) {
+ display(&charProc, gFalse);
+ } else {
+ error(getPos(), "Missing or bad Type3 CharProc entry");
+ }
+ state = state->restore();
+ out->restoreState(state);
+ charProc.free();
+ width = state->getFontSize() * font->getWidth(c8) +
+ state->getCharSpace();
+ if (c8 == ' ') {
+ width += state->getWordSpace();
+ }
+ width *= state->getHorizScaling();
+ state->textShift(width);
+ }
+ parser = oldParser;
+ out->endString(state);
+ } else
+#endif
+ if (out->useDrawChar()) {
+ out->beginString(state, s);
+ state->textTransformDelta(0, state->getRise(), &dx, &dy);
+ for (p = (Guchar *)s->getCString(), n = s->getLength(); n; ++p, --n) {
+ c8 = *p;
+ width = state->getFontSize() * font->getWidth(c8) +
+ state->getCharSpace();
+ if (c8 == ' ') {
+ width += state->getWordSpace();
+ }
+ width *= state->getHorizScaling();
+ state->textTransformDelta(width, 0, &w, &h);
+ out->drawChar(state, state->getCurX() + dx, state->getCurY() + dy,
+ w, h, c8);
+ state->textShift(width);
+ }
+ out->endString(state);
+ } else {
+ out->drawString(state, s);
+ width = state->getFontSize() * font->getWidth(s) +
+ s->getLength() * state->getCharSpace();
+ for (p = (Guchar *)s->getCString(), n = s->getLength(); n; ++p, --n) {
+ if (*p == ' ') {
+ width += state->getWordSpace();
+ }
+ }
+ width *= state->getHorizScaling();
+ state->textShift(width);
+ }
+ }
+}
+
+int Gfx::getNextChar16(GfxFontEncoding16 *enc, Guchar *p, int *c16) {
+ int n;
+ int code;
+ int a, b, m;
+
+ n = enc->codeLen[*p];
+ if (n == 1) {
+ *c16 = enc->map1[*p];
+ } else {
+ code = (p[0] << 8) + p[1];
+ a = 0;
+ b = enc->map2Len;
+ // invariant: map2[2*a] <= code < map2[2*b]
+ while (b - a > 1) {
+ m = (a + b) / 2;
+ if (enc->map2[2*m] <= code)
+ a = m;
+ else if (enc->map2[2*m] > code)
+ b = m;
+ else
+ break;
+ }
+ *c16 = enc->map2[2*a+1] + (code - enc->map2[2*a]);
+ }
+ return n;
+}
+
+//------------------------------------------------------------------------
+// XObject operators
+//------------------------------------------------------------------------
+
+void Gfx::opXObject(Object args[], int numArgs) {
+ Object obj1, obj2, refObj;
+#if OPI_SUPPORT
+ Object opiDict;
+#endif
+
+ if (!res->lookupXObject(args[0].getName(), &obj1)) {
+ return;
+ }
+ if (!obj1.isStream()) {
+ error(getPos(), "XObject '%s' is wrong type", args[0].getName());
+ obj1.free();
+ return;
+ }
+#if OPI_SUPPORT
+ obj1.streamGetDict()->lookup("OPI", &opiDict);
+ if (opiDict.isDict()) {
+ out->opiBegin(state, opiDict.getDict());
+ }
+#endif
+ obj1.streamGetDict()->lookup("Subtype", &obj2);
+ if (obj2.isName("Image")) {
+ res->lookupXObjectNF(args[0].getName(), &refObj);
+ doImage(&refObj, obj1.getStream(), gFalse);
+ refObj.free();
+ } else if (obj2.isName("Form")) {
+ doForm(&obj1);
+ } else if (obj2.isName()) {
+ error(getPos(), "Unknown XObject subtype '%s'", obj2.getName());
+ } else {
+ error(getPos(), "XObject subtype is missing or wrong type");
+ }
+ obj2.free();
+#if OPI_SUPPORT
+ if (opiDict.isDict()) {
+ out->opiEnd(state, opiDict.getDict());
+ }
+ opiDict.free();
+#endif
+ obj1.free();
+}
+
+void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
+ Dict *dict;
+ int width, height;
+ int bits;
+ GBool mask;
+ GBool invert;
+ GfxColorSpace *colorSpace;
+ GfxImageColorMap *colorMap;
+ Object maskObj;
+ GBool haveMask;
+ int maskColors[2*gfxColorMaxComps];
+ Object obj1, obj2;
+ int i;
+
+ // get stream dict
+ dict = str->getDict();
+
+ // get size
+ dict->lookup("Width", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ dict->lookup("W", &obj1);
+ }
+ if (!obj1.isInt())
+ goto err2;
+ width = obj1.getInt();
+ obj1.free();
+ dict->lookup("Height", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ dict->lookup("H", &obj1);
+ }
+ if (!obj1.isInt())
+ goto err2;
+ height = obj1.getInt();
+ obj1.free();
+
+ // image or mask?
+ dict->lookup("ImageMask", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ dict->lookup("IM", &obj1);
+ }
+ mask = gFalse;
+ if (obj1.isBool())
+ mask = obj1.getBool();
+ else if (!obj1.isNull())
+ goto err2;
+ obj1.free();
+
+ // bit depth
+ dict->lookup("BitsPerComponent", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ dict->lookup("BPC", &obj1);
+ }
+ if (!obj1.isInt())
+ goto err2;
+ bits = obj1.getInt();
+ obj1.free();
+
+ // display a mask
+ if (mask) {
+
+ // check for inverted mask
+ if (bits != 1)
+ goto err1;
+ invert = gFalse;
+ dict->lookup("Decode", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ dict->lookup("D", &obj1);
+ }
+ if (obj1.isArray()) {
+ obj1.arrayGet(0, &obj2);
+ if (obj2.isInt() && obj2.getInt() == 1)
+ invert = gTrue;
+ obj2.free();
+ } else if (!obj1.isNull()) {
+ goto err2;
+ }
+ obj1.free();
+
+ // draw it
+ out->drawImageMask(state, ref, str, width, height, invert, inlineImg);
+
+ } else {
+
+ // get color space and color map
+ dict->lookup("ColorSpace", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ dict->lookup("CS", &obj1);
+ }
+ if (obj1.isName()) {
+ res->lookupColorSpace(obj1.getName(), &obj2);
+ if (!obj2.isNull()) {
+ obj1.free();
+ obj1 = obj2;
+ } else {
+ obj2.free();
+ }
+ }
+ colorSpace = GfxColorSpace::parse(&obj1);
+ obj1.free();
+ if (!colorSpace) {
+ goto err1;
+ }
+ dict->lookup("Decode", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ dict->lookup("D", &obj1);
+ }
+ colorMap = new GfxImageColorMap(bits, &obj1, colorSpace);
+ obj1.free();
+ if (!colorMap->isOk()) {
+ delete colorMap;
+ goto err1;
+ }
+
+ // get the mask
+ haveMask = gFalse;
+ dict->lookup("Mask", &maskObj);
+ if (maskObj.isArray()) {
+ for (i = 0; i < maskObj.arrayGetLength(); ++i) {
+ maskObj.arrayGet(i, &obj1);
+ maskColors[i] = obj1.getInt();
+ obj1.free();
+ }
+ haveMask = gTrue;
+ }
+
+ // draw it
+ out->drawImage(state, ref, str, width, height, colorMap,
+ haveMask ? maskColors : (int *)NULL, inlineImg);
+ delete colorMap;
+ str->close();
+
+ maskObj.free();
+ }
+
+ return;
+
+ err2:
+ obj1.free();
+ err1:
+ error(getPos(), "Bad image parameters");
+}
+
+void Gfx::doForm(Object *str) {
+ Dict *dict;
+ Object matrixObj, bboxObj;
+ double m[6], bbox[6];
+ Object resObj;
+ Dict *resDict;
+ Object obj1;
+ int i;
+
+ // get stream dict
+ dict = str->streamGetDict();
+
+ // check form type
+ dict->lookup("FormType", &obj1);
+ if (!(obj1.isInt() && obj1.getInt() == 1)) {
+ error(getPos(), "Unknown form type");
+ }
+ obj1.free();
+
+ // get bounding box
+ dict->lookup("BBox", &bboxObj);
+ if (!bboxObj.isArray()) {
+ matrixObj.free();
+ bboxObj.free();
+ error(getPos(), "Bad form bounding box");
+ return;
+ }
+ for (i = 0; i < 4; ++i) {
+ bboxObj.arrayGet(i, &obj1);
+ bbox[i] = obj1.getNum();
+ obj1.free();
+ }
+ bboxObj.free();
+
+ // get matrix
+ dict->lookup("Matrix", &matrixObj);
+ if (matrixObj.isArray()) {
+ for (i = 0; i < 6; ++i) {
+ matrixObj.arrayGet(i, &obj1);
+ m[i] = obj1.getNum();
+ obj1.free();
+ }
+ } else {
+ m[0] = 1; m[1] = 0;
+ m[2] = 0; m[3] = 1;
+ m[4] = 0; m[5] = 0;
+ }
+ matrixObj.free();
+
+ // get resources
+ dict->lookup("Resources", &resObj);
+ resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL;
+
+ // draw it
+ doForm1(str, resDict, m, bbox);
+
+ resObj.free();
+}
+
+void Gfx::doWidgetForm(Object *str, double xMin, double yMin,
+ double xMax, double yMax) {
+ Dict *dict, *resDict;
+ Object matrixObj, bboxObj, resObj;
+ Object obj1;
+ double m[6], bbox[6];
+ double sx, sy;
+ int i;
+
+ // get stream dict
+ dict = str->streamGetDict();
+
+ // get bounding box
+ dict->lookup("BBox", &bboxObj);
+ if (!bboxObj.isArray()) {
+ bboxObj.free();
+ error(getPos(), "Bad form bounding box");
+ return;
+ }
+ for (i = 0; i < 4; ++i) {
+ bboxObj.arrayGet(i, &obj1);
+ bbox[i] = obj1.getNum();
+ obj1.free();
+ }
+ bboxObj.free();
+
+ // get matrix
+ dict->lookup("Matrix", &matrixObj);
+ if (matrixObj.isArray()) {
+ for (i = 0; i < 6; ++i) {
+ matrixObj.arrayGet(i, &obj1);
+ m[i] = obj1.getNum();
+ obj1.free();
+ }
+ } else {
+ m[0] = 1; m[1] = 0;
+ m[2] = 0; m[3] = 1;
+ m[4] = 0; m[5] = 0;
+ }
+ matrixObj.free();
+
+ // scale form bbox to widget rectangle
+ sx = fabs((xMax - xMin) / (bbox[2] - bbox[0]));
+ sy = fabs((yMax - yMin) / (bbox[3] - bbox[1]));
+ m[0] *= sx; m[1] *= sy;
+ m[2] *= sx; m[3] *= sy;
+ m[4] *= sx; m[5] *= sy;
+
+ // translate to widget rectangle
+ m[4] += xMin;
+ m[5] += yMin;
+
+ // get resources
+ dict->lookup("Resources", &resObj);
+ resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL;
+
+ // draw it
+ doForm1(str, resDict, m, bbox);
+
+ resObj.free();
+ bboxObj.free();
+}
+
+void Gfx::doForm1(Object *str, Dict *resDict, double *matrix, double *bbox) {
+ Parser *oldParser;
+ double oldBaseMatrix[6];
+ GfxResources *resPtr;
+ int i;
+
+ // push new resources on stack
+ res = new GfxResources(xref, resDict, res);
+
+ // save current graphics state
+ out->saveState(state);
+ state = state->save();
+
+ // save current parser
+ oldParser = parser;
+
+ // set form transformation matrix
+ state->concatCTM(matrix[0], matrix[1], matrix[2],
+ matrix[3], matrix[4], matrix[5]);
+ out->updateCTM(state, matrix[0], matrix[1], matrix[2],
+ matrix[3], matrix[4], matrix[5]);
+
+ // set new base matrix
+ for (i = 0; i < 6; ++i) {
+ oldBaseMatrix[i] = baseMatrix[i];
+ baseMatrix[i] = state->getCTM()[i];
+ }
+
+ // set form bounding box
+ state->moveTo(bbox[0], bbox[1]);
+ state->lineTo(bbox[2], bbox[1]);
+ state->lineTo(bbox[2], bbox[3]);
+ state->lineTo(bbox[0], bbox[3]);
+ state->closePath();
+ state->clip();
+ out->clip(state);
+ state->clearPath();
+
+ // draw the form
+ display(str, gFalse);
+
+ // restore base matrix
+ for (i = 0; i < 6; ++i) {
+ baseMatrix[i] = oldBaseMatrix[i];
+ }
+
+ // restore parser
+ parser = oldParser;
+
+ // restore graphics state
+ state = state->restore();
+ out->restoreState(state);
+
+ // pop resource stack
+ resPtr = res->getNext();
+ delete res;
+ res = resPtr;
+
+ return;
+}
+
+//------------------------------------------------------------------------
+// in-line image operators
+//------------------------------------------------------------------------
+
+void Gfx::opBeginImage(Object args[], int numArgs) {
+ Stream *str;
+ int c1, c2;
+
+ // build dict/stream
+ str = buildImageStream();
+
+ // display the image
+ if (str) {
+ doImage(NULL, str, gTrue);
+
+ // skip 'EI' tag
+ c1 = str->getBaseStream()->getChar();
+ c2 = str->getBaseStream()->getChar();
+ while (!(c1 == 'E' && c2 == 'I') && c2 != EOF) {
+ c1 = c2;
+ c2 = str->getBaseStream()->getChar();
+ }
+ delete str;
+ }
+}
+
+Stream *Gfx::buildImageStream() {
+ Object dict;
+ Object obj;
+ char *key;
+ Stream *str;
+
+ // build dictionary
+ dict.initDict(xref);
+ parser->getObj(&obj);
+ while (!obj.isCmd("ID") && !obj.isEOF()) {
+ if (!obj.isName()) {
+ error(getPos(), "Inline image dictionary key must be a name object");
+ obj.free();
+ parser->getObj(&obj);
+ } else {
+ key = copyString(obj.getName());
+ obj.free();
+ parser->getObj(&obj);
+ if (obj.isEOF() || obj.isError())
+ break;
+ dict.dictAdd(key, &obj);
+ }
+ parser->getObj(&obj);
+ }
+ if (obj.isEOF())
+ error(getPos(), "End of file in inline image");
+ obj.free();
+
+ // make stream
+ str = new EmbedStream(parser->getStream(), &dict);
+ str = str->addFilters(&dict);
+
+ return str;
+}
+
+void Gfx::opImageData(Object args[], int numArgs) {
+ error(getPos(), "Internal: got 'ID' operator");
+}
+
+void Gfx::opEndImage(Object args[], int numArgs) {
+ error(getPos(), "Internal: got 'EI' operator");
+}
+
+//------------------------------------------------------------------------
+// type 3 font operators
+//------------------------------------------------------------------------
+
+void Gfx::opSetCharWidth(Object args[], int numArgs) {
+// error(getPos(), "Encountered 'd0' operator in content stream");
+}
+
+void Gfx::opSetCacheDevice(Object args[], int numArgs) {
+// error(getPos(), "Encountered 'd1' operator in content stream");
+}
+
+//------------------------------------------------------------------------
+// compatibility operators
+//------------------------------------------------------------------------
+
+void Gfx::opBeginIgnoreUndef(Object args[], int numArgs) {
+ ++ignoreUndef;
+}
+
+void Gfx::opEndIgnoreUndef(Object args[], int numArgs) {
+ if (ignoreUndef > 0)
+ --ignoreUndef;
+}
+
+//------------------------------------------------------------------------
+// marked content operators
+//------------------------------------------------------------------------
+
+void Gfx::opBeginMarkedContent(Object args[], int numArgs) {
+ if (printCommands) {
+ printf(" marked content: %s ", args[0].getName());
+ if (numArgs == 2)
+ args[2].print(stdout);
+ printf("\n");
+ fflush(stdout);
+ }
+}
+
+void Gfx::opEndMarkedContent(Object args[], int numArgs) {
+}
+
+void Gfx::opMarkPoint(Object args[], int numArgs) {
+ if (printCommands) {
+ printf(" mark point: %s ", args[0].getName());
+ if (numArgs == 2)
+ args[2].print(stdout);
+ printf("\n");
+ fflush(stdout);
+ }
+}
diff --git a/pdftops/Gfx.h b/pdftops/Gfx.h
new file mode 100644
index 000000000..24e124697
--- /dev/null
+++ b/pdftops/Gfx.h
@@ -0,0 +1,242 @@
+//========================================================================
+//
+// Gfx.h
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifndef GFX_H
+#define GFX_H
+
+#ifdef __GNUC__
+#pragma interface
+#endif
+
+#include "gtypes.h"
+
+class GString;
+class XRef;
+class Array;
+class Stream;
+class Parser;
+class Dict;
+class OutputDev;
+class GfxFontDict;
+class GfxFont;
+struct GfxFontEncoding16;
+class GfxPattern;
+class GfxShading;
+class GfxAxialShading;
+class GfxState;
+class Gfx;
+struct PDFRectangle;
+
+//------------------------------------------------------------------------
+// Gfx
+//------------------------------------------------------------------------
+
+enum GfxClipType {
+ clipNone,
+ clipNormal,
+ clipEO
+};
+
+enum TchkType {
+ tchkBool, // boolean
+ tchkInt, // integer
+ tchkNum, // number (integer or real)
+ tchkString, // string
+ tchkName, // name
+ tchkArray, // array
+ tchkProps, // properties (dictionary or name)
+ tchkSCN, // scn/SCN args (number of name)
+ tchkNone // used to avoid empty initializer lists
+};
+
+#define maxArgs 8
+
+struct Operator {
+ char name[4];
+ int numArgs;
+ TchkType tchk[maxArgs];
+ void (Gfx::*func)(Object args[], int numArgs);
+};
+
+class GfxResources {
+public:
+
+ GfxResources(XRef *xref, Dict *resDict, GfxResources *nextA);
+ ~GfxResources();
+
+ GfxFont *lookupFont(char *name);
+ GBool lookupXObject(char *name, Object *obj);
+ GBool lookupXObjectNF(char *name, Object *obj);
+ void lookupColorSpace(char *name, Object *obj);
+ GfxPattern *lookupPattern(char *name);
+ GfxShading *lookupShading(char *name);
+ GBool lookupGState(char *name, Object *obj);
+
+ GfxResources *getNext() { return next; }
+
+private:
+
+ GfxFontDict *fonts;
+ Object xObjDict;
+ Object colorSpaceDict;
+ Object patternDict;
+ Object shadingDict;
+ Object gStateDict;
+ GfxResources *next;
+};
+
+class Gfx {
+public:
+
+ // Constructor for regular output.
+ Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict, double dpi,
+ PDFRectangle *box, GBool crop, PDFRectangle *cropBox, int rotate,
+ GBool printCommandsA);
+
+ // Destructor.
+ ~Gfx();
+
+ // Interpret a stream or array of streams.
+ void display(Object *obj, GBool topLevel = gTrue);
+
+ void doWidgetForm(Object *str, double xMin, double yMin,
+ double xMax, double yMax);
+
+private:
+
+ XRef *xref; // the xref table for this PDF file
+ OutputDev *out; // output device
+ GBool printCommands; // print the drawing commands (for debugging)
+ GfxResources *res; // resource stack
+
+ GfxState *state; // current graphics state
+ GBool fontChanged; // set if font or text matrix has changed
+ GfxClipType clip; // do a clip?
+ int ignoreUndef; // current BX/EX nesting level
+ double baseMatrix[6]; // default matrix for most recent
+ // page/form/pattern
+
+ Parser *parser; // parser for page content stream(s)
+
+ static Operator opTab[]; // table of operators
+
+ void go(GBool topLevel);
+ void execOp(Object *cmd, Object args[], int numArgs);
+ Operator *findOp(char *name);
+ GBool checkArg(Object *arg, TchkType type);
+ int getPos();
+
+ // graphics state operators
+ void opSave(Object args[], int numArgs);
+ void opRestore(Object args[], int numArgs);
+ void opConcat(Object args[], int numArgs);
+ void opSetDash(Object args[], int numArgs);
+ void opSetFlat(Object args[], int numArgs);
+ void opSetLineJoin(Object args[], int numArgs);
+ void opSetLineCap(Object args[], int numArgs);
+ void opSetMiterLimit(Object args[], int numArgs);
+ void opSetLineWidth(Object args[], int numArgs);
+ void opSetExtGState(Object args[], int numArgs);
+ void opSetRenderingIntent(Object args[], int numArgs);
+
+ // color operators
+ void opSetFillGray(Object args[], int numArgs);
+ void opSetStrokeGray(Object args[], int numArgs);
+ void opSetFillCMYKColor(Object args[], int numArgs);
+ void opSetStrokeCMYKColor(Object args[], int numArgs);
+ void opSetFillRGBColor(Object args[], int numArgs);
+ void opSetStrokeRGBColor(Object args[], int numArgs);
+ void opSetFillColorSpace(Object args[], int numArgs);
+ void opSetStrokeColorSpace(Object args[], int numArgs);
+ void opSetFillColor(Object args[], int numArgs);
+ void opSetStrokeColor(Object args[], int numArgs);
+ void opSetFillColorN(Object args[], int numArgs);
+ void opSetStrokeColorN(Object args[], int numArgs);
+
+ // path segment operators
+ void opMoveTo(Object args[], int numArgs);
+ void opLineTo(Object args[], int numArgs);
+ void opCurveTo(Object args[], int numArgs);
+ void opCurveTo1(Object args[], int numArgs);
+ void opCurveTo2(Object args[], int numArgs);
+ void opRectangle(Object args[], int numArgs);
+ void opClosePath(Object args[], int numArgs);
+
+ // path painting operators
+ void opEndPath(Object args[], int numArgs);
+ void opStroke(Object args[], int numArgs);
+ void opCloseStroke(Object args[], int numArgs);
+ void opFill(Object args[], int numArgs);
+ void opEOFill(Object args[], int numArgs);
+ void opFillStroke(Object args[], int numArgs);
+ void opCloseFillStroke(Object args[], int numArgs);
+ void opEOFillStroke(Object args[], int numArgs);
+ void opCloseEOFillStroke(Object args[], int numArgs);
+ void doPatternFill(GBool eoFill);
+ void opShFill(Object args[], int numArgs);
+ void doAxialShFill(GfxAxialShading *shading);
+ void doEndPath();
+
+ // path clipping operators
+ void opClip(Object args[], int numArgs);
+ void opEOClip(Object args[], int numArgs);
+
+ // text object operators
+ void opBeginText(Object args[], int numArgs);
+ void opEndText(Object args[], int numArgs);
+
+ // text state operators
+ void opSetCharSpacing(Object args[], int numArgs);
+ void opSetFont(Object args[], int numArgs);
+ void opSetTextLeading(Object args[], int numArgs);
+ void opSetTextRender(Object args[], int numArgs);
+ void opSetTextRise(Object args[], int numArgs);
+ void opSetWordSpacing(Object args[], int numArgs);
+ void opSetHorizScaling(Object args[], int numArgs);
+
+ // text positioning operators
+ void opTextMove(Object args[], int numArgs);
+ void opTextMoveSet(Object args[], int numArgs);
+ void opSetTextMatrix(Object args[], int numArgs);
+ void opTextNextLine(Object args[], int numArgs);
+
+ // text string operators
+ void opShowText(Object args[], int numArgs);
+ void opMoveShowText(Object args[], int numArgs);
+ void opMoveSetShowText(Object args[], int numArgs);
+ void opShowSpaceText(Object args[], int numArgs);
+ void doShowText(GString *s);
+ int getNextChar16(GfxFontEncoding16 *enc, Guchar *p, int *c16);
+
+ // XObject operators
+ void opXObject(Object args[], int numArgs);
+ void doImage(Object *ref, Stream *str, GBool inlineImg);
+ void doForm(Object *str);
+ void doForm1(Object *str, Dict *resDict, double *matrix, double *bbox);
+
+ // in-line image operators
+ void opBeginImage(Object args[], int numArgs);
+ Stream *buildImageStream();
+ void opImageData(Object args[], int numArgs);
+ void opEndImage(Object args[], int numArgs);
+
+ // type 3 font operators
+ void opSetCharWidth(Object args[], int numArgs);
+ void opSetCacheDevice(Object args[], int numArgs);
+
+ // compatibility operators
+ void opBeginIgnoreUndef(Object args[], int numArgs);
+ void opEndIgnoreUndef(Object args[], int numArgs);
+
+ // marked content operators
+ void opBeginMarkedContent(Object args[], int numArgs);
+ void opEndMarkedContent(Object args[], int numArgs);
+ void opMarkPoint(Object args[], int numArgs);
+};
+
+#endif
diff --git a/pdftops/GfxFont.cxx b/pdftops/GfxFont.cxx
new file mode 100644
index 000000000..96b802e14
--- /dev/null
+++ b/pdftops/GfxFont.cxx
@@ -0,0 +1,1081 @@
+//========================================================================
+//
+// GfxFont.cc
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include "GString.h"
+#include "gmem.h"
+#include "gfile.h"
+#include "config.h"
+#include "Object.h"
+#include "Array.h"
+#include "Dict.h"
+#include "Error.h"
+#include "Params.h"
+#include "FontFile.h"
+#include "GfxFont.h"
+
+#include "FontInfo.h"
+#if JAPANESE_SUPPORT
+#include "Japan12CMapInfo.h"
+#endif
+#if CHINESE_GB_SUPPORT
+#include "GB12CMapInfo.h"
+#endif
+#if CHINESE_CNS_SUPPORT
+#include "CNS13CMapInfo.h"
+#endif
+
+//------------------------------------------------------------------------
+
+extern "C" {
+static int CDECL cmpWidthExcep(const void *w1, const void *w2);
+static int CDECL cmpWidthExcepV(const void *w1, const void *w2);
+}
+
+//------------------------------------------------------------------------
+
+static Gushort *defCharWidths[12] = {
+ courierWidths,
+ courierObliqueWidths,
+ courierBoldWidths,
+ courierBoldObliqueWidths,
+ helveticaWidths,
+ helveticaObliqueWidths,
+ helveticaBoldWidths,
+ helveticaBoldObliqueWidths,
+ timesRomanWidths,
+ timesItalicWidths,
+ timesBoldWidths,
+ timesBoldItalicWidths
+};
+
+//------------------------------------------------------------------------
+// GfxFont
+//------------------------------------------------------------------------
+
+GfxFont::GfxFont(XRef *xref, char *tagA, Ref idA, Dict *fontDict) {
+ BuiltinFont *builtinFont;
+ Object obj1, obj2, obj3, obj4;
+ int missingWidth;
+ char *name2, *p;
+ int i;
+
+ // get font tag and ID
+ tag = new GString(tagA);
+ id = idA;
+
+ // get font type
+ type = fontUnknownType;
+ fontDict->lookup("Subtype", &obj1);
+ if (obj1.isName("Type1"))
+ type = fontType1;
+ else if (obj1.isName("Type1C"))
+ type = fontType1C;
+ else if (obj1.isName("Type3"))
+ type = fontType3;
+ else if (obj1.isName("TrueType"))
+ type = fontTrueType;
+ else if (obj1.isName("Type0"))
+ type = fontType0;
+ obj1.free();
+ is16 = gFalse;
+
+ // get base font name
+ name = NULL;
+ fontDict->lookup("BaseFont", &obj1);
+ if (obj1.isName())
+ name = new GString(obj1.getName());
+ obj1.free();
+
+ // Newer Adobe tools are using Base14-compatible TrueType fonts
+ // without embedding them, so munge the names into the equivalent
+ // PostScript names. This is a kludge -- it would be nice if Adobe
+ // followed their own spec.
+ if (type == fontTrueType && name) {
+ p = name->getCString();
+ name2 = NULL;
+ if (!strncmp(p, "Arial", 5)) {
+ if (!strcmp(p+5, ",Bold")) {
+ name2 = "Helvetica-Bold";
+ } else if (!strcmp(p+5, ",Italic")) {
+ name2 = "Helvetica-Oblique";
+ } else if (!strcmp(p+5, ",BoldItalic")) {
+ name2 = "Helvetica-BoldOblique";
+ } else {
+ name2 = "Helvetica";
+ }
+ } else if (!strncmp(p, "TimesNewRoman", 13)) {
+ if (!strcmp(p+13, ",Bold")) {
+ name2 = "Times-Bold";
+ } else if (!strcmp(p+13, ",Italic")) {
+ name2 = "Times-Italic";
+ } else if (!strcmp(p+13, ",BoldItalic")) {
+ name2 = "Times-BoldItalic";
+ } else {
+ name2 = "Times-Roman";
+ }
+ } else if (!strncmp(p, "CourierNew", 10)) {
+ if (!strcmp(p+10, ",Bold")) {
+ name2 = "Courier-Bold";
+ } else if (!strcmp(p+10, ",Italic")) {
+ name2 = "Courier-Oblique";
+ } else if (!strcmp(p+10, ",BoldItalic")) {
+ name2 = "Courier-BoldOblique";
+ } else {
+ name2 = "Courier";
+ }
+ }
+ if (name2) {
+ delete name;
+ name = new GString(name2);
+ }
+ }
+
+ // is it a built-in font?
+ builtinFont = NULL;
+ if (name) {
+ for (i = 0; i < numBuiltinFonts; ++i) {
+ if (!strcmp(builtinFonts[i].name, name->getCString())) {
+ builtinFont = &builtinFonts[i];
+ break;
+ }
+ }
+ }
+
+ // assume Times-Roman by default (for substitution purposes)
+ flags = fontSerif;
+
+ // default ascent/descent values
+ if (builtinFont) {
+ ascent = 0.001 * builtinFont->ascent;
+ descent = 0.001 * builtinFont->descent;
+ } else {
+ ascent = 0.95;
+ descent = -0.35;
+ }
+
+ // get info from font descriptor
+ embFontName = NULL;
+ embFontID.num = -1;
+ embFontID.gen = -1;
+ missingWidth = 0;
+ if (type == fontType0) {
+ fontDict->lookup("DescendantFonts", &obj2);
+ if (obj2.isArray()) {
+ obj2.arrayGet(0, &obj3);
+ if (obj3.isDict()) {
+ obj3.dictLookup("FontDescriptor", &obj1);
+ } else {
+ error(-1, "Bad descendant font in Type 0 font");
+ obj1.initNull();
+ }
+ obj3.free();
+ } else {
+ error(-1, "Missing DescendantFonts entry in Type 0 font");
+ obj1.initNull();
+ }
+ obj2.free();
+ } else {
+ fontDict->lookup("FontDescriptor", &obj1);
+ }
+ if (obj1.isDict()) {
+
+ // get flags
+ obj1.dictLookup("Flags", &obj2);
+ if (obj2.isInt())
+ flags = obj2.getInt();
+ obj2.free();
+
+ // get name
+ obj1.dictLookup("FontName", &obj2);
+ if (obj2.isName())
+ embFontName = new GString(obj2.getName());
+ obj2.free();
+
+ // look for embedded font file
+ if (type == fontType1) {
+ obj1.dictLookupNF("FontFile", &obj2);
+ if (obj2.isRef())
+ embFontID = obj2.getRef();
+ obj2.free();
+ }
+ if (embFontID.num == -1 && type == fontTrueType) {
+ obj1.dictLookupNF("FontFile2", &obj2);
+ if (obj2.isRef())
+ embFontID = obj2.getRef();
+ obj2.free();
+ }
+ if (embFontID.num == -1) {
+ obj1.dictLookupNF("FontFile3", &obj2);
+ if (obj2.isRef()) {
+ embFontID = obj2.getRef();
+ obj2.fetch(xref, &obj3);
+ if (obj3.isStream()) {
+ obj3.streamGetDict()->lookup("Subtype", &obj4);
+ if (obj4.isName("Type1"))
+ type = fontType1;
+ else if (obj4.isName("Type1C"))
+ type = fontType1C;
+ else if (obj4.isName("Type3"))
+ type = fontType3;
+ else if (obj4.isName("TrueType"))
+ type = fontTrueType;
+ else if (obj4.isName("Type0"))
+ type = fontType0;
+ obj4.free();
+ }
+ obj3.free();
+ }
+ obj2.free();
+ }
+
+ // look for MissingWidth
+ obj1.dictLookup("MissingWidth", &obj2);
+ if (obj2.isInt()) {
+ missingWidth = obj2.getInt();
+ }
+ obj2.free();
+
+ // get Ascent and Descent
+ obj1.dictLookup("Ascent", &obj2);
+ if (obj2.isNum()) {
+ ascent = 0.001 * obj2.getNum();
+ }
+ obj2.free();
+ obj1.dictLookup("Descent", &obj2);
+ if (obj2.isNum()) {
+ descent = 0.001 * obj2.getNum();
+ }
+ obj2.free();
+
+ // font FontBBox
+ fontBBox[0] = fontBBox[1] = fontBBox[2] = fontBBox[3] = 0;
+ if (obj1.dictLookup("FontBBox", &obj2)->isArray()) {
+ for (i = 0; i < 4 && i < obj2.arrayGetLength(); ++i) {
+ if (obj2.arrayGet(i, &obj3)->isNum()) {
+ fontBBox[i] = obj3.getNum();
+ }
+ obj3.free();
+ }
+ }
+ obj2.free();
+ }
+ obj1.free();
+
+ // get Type3 font definition
+ if (type == fontType3) {
+ fontDict->lookup("CharProcs", &charProcs);
+ if (!charProcs.isDict()) {
+ error(-1, "Missing or invalid CharProcs dictionary in Type 3 font");
+ charProcs.free();
+ }
+ }
+
+ // look for an external font file
+ extFontFile = NULL;
+ if (type == fontType1 && name)
+ findExtFontFile();
+
+ // get font matrix
+ fontMat[0] = fontMat[3] = 1;
+ fontMat[1] = fontMat[2] = fontMat[4] = fontMat[5] = 0;
+ if (fontDict->lookup("FontMatrix", &obj1)->isArray()) {
+ for (i = 0; i < 6 && i < obj1.arrayGetLength(); ++i) {
+ if (obj1.arrayGet(i, &obj2)->isNum())
+ fontMat[i] = obj2.getNum();
+ obj2.free();
+ }
+ }
+ obj1.free();
+
+ // get encoding and character widths
+ if (type == fontType0) {
+ getType0EncAndWidths(fontDict);
+ } else {
+ getEncAndWidths(xref, fontDict, builtinFont, missingWidth);
+ }
+}
+
+GfxFont::~GfxFont() {
+ delete tag;
+ if (name) {
+ delete name;
+ }
+ if (!is16 && encoding) {
+ delete encoding;
+ }
+ if (embFontName) {
+ delete embFontName;
+ }
+ if (extFontFile) {
+ delete extFontFile;
+ }
+ if (charProcs.isDict()) {
+ charProcs.free();
+ }
+ if (is16) {
+ gfree(widths16.exceps);
+ gfree(widths16.excepsV);
+ }
+}
+
+double GfxFont::getWidth(GString *s) {
+ double w;
+ int i;
+
+ w = 0;
+ for (i = 0; i < s->getLength(); ++i)
+ w += widths[s->getChar(i) & 0xff];
+ return w;
+}
+
+double GfxFont::getWidth16(int c) {
+ double w;
+ int a, b, m;
+
+ w = widths16.defWidth;
+ a = -1;
+ b = widths16.numExceps;
+ // invariant: widths16.exceps[a].last < c < widths16.exceps[b].first
+ while (b - a > 1) {
+ m = (a + b) / 2;
+ if (widths16.exceps[m].last < c) {
+ a = m;
+ } else if (c < widths16.exceps[m].first) {
+ b = m;
+ } else {
+ w = widths16.exceps[m].width;
+ break;
+ }
+ }
+ return w;
+}
+
+double GfxFont::getHeight16(int c) {
+ double h;
+ int a, b, m;
+
+ h = widths16.defHeight;
+ a = -1;
+ b = widths16.numExcepsV;
+ // invariant: widths16.excepsV[a].last < c < widths16.excepsV[b].first
+ while (b - a > 1) {
+ m = (a + b) / 2;
+ if (widths16.excepsV[m].last < c) {
+ a = m;
+ } else if (c < widths16.excepsV[m].first) {
+ b = m;
+ } else {
+ h = widths16.excepsV[m].height;
+ break;
+ }
+ }
+ return h;
+}
+
+double GfxFont::getOriginX16(int c) {
+ double vx;
+ int a, b, m;
+
+ vx = widths16.defWidth / 2;
+ a = -1;
+ b = widths16.numExcepsV;
+ // invariant: widths16.excepsV[a].last < c < widths16.excepsV[b].first
+ while (b - a > 1) {
+ m = (a + b) / 2;
+ if (widths16.excepsV[m].last < c) {
+ a = m;
+ } else if (c < widths16.excepsV[m].first) {
+ b = m;
+ } else {
+ vx = widths16.excepsV[m].vx;
+ break;
+ }
+ }
+ return vx;
+}
+
+double GfxFont::getOriginY16(int c) {
+ double vy;
+ int a, b, m;
+
+ vy = widths16.defVY;
+ a = -1;
+ b = widths16.numExcepsV;
+ // invariant: widths16.excepsV[a].last < c < widths16.excepsV[b].first
+ while (b - a > 1) {
+ m = (a + b) / 2;
+ if (widths16.excepsV[m].last < c) {
+ a = m;
+ } else if (c < widths16.excepsV[m].first) {
+ b = m;
+ } else {
+ vy = widths16.excepsV[m].vy;
+ break;
+ }
+ }
+ return vy;
+}
+
+Object *GfxFont::getCharProc(int code, Object *proc) {
+ if (charProcs.isDict()) {
+ charProcs.dictLookup(encoding->getCharName(code), proc);
+ } else {
+ proc->initNull();
+ }
+ return proc;
+}
+
+void GfxFont::getEncAndWidths(XRef *xref, Dict *fontDict,
+ BuiltinFont *builtinFont, int missingWidth) {
+ Object obj1, obj2, obj3;
+ char *buf;
+ int len;
+ FontFile *fontFile;
+ int code, i;
+
+ // Encodings start with a base encoding, which can come from
+ // (in order of priority):
+ // 1. FontDict.Encoding or FontDict.Encoding.BaseEncoding
+ // - MacRoman / WinAnsi / Standard
+ // 2. embedded font file
+ // 3. default:
+ // - builtin --> builtin encoding
+ // - TrueType --> MacRomanEncoding
+ // - others --> StandardEncoding
+ // and then add a list of differences from
+ // FontDict.Encoding.Differences.
+
+ // check FontDict for base encoding
+ encoding = NULL;
+ fontDict->lookup("Encoding", &obj1);
+ if (obj1.isDict()) {
+ obj1.dictLookup("BaseEncoding", &obj2);
+ if (obj2.isName("MacRomanEncoding")) {
+ encoding = macRomanEncoding.copy();
+ } else if (obj2.isName("WinAnsiEncoding")) {
+ encoding = winAnsiEncoding.copy();
+ } else if (obj2.isName("StandardEncoding")) {
+ encoding = standardEncoding.copy();
+ }
+ obj2.free();
+ } else if (obj1.isName("MacRomanEncoding")) {
+ encoding = macRomanEncoding.copy();
+ } else if (obj1.isName("WinAnsiEncoding")) {
+ encoding = winAnsiEncoding.copy();
+ } else if (obj1.isName("StandardEncoding")) {
+ encoding = standardEncoding.copy();
+ }
+ obj1.free();
+
+ // check embedded or external font file for base encoding
+ if ((type == fontType1 || type == fontType1C || type == fontTrueType) &&
+ (extFontFile || embFontID.num >= 0)) {
+ if (extFontFile) {
+ buf = readExtFontFile(&len);
+ } else {
+ buf = readEmbFontFile(xref, &len);
+ }
+ if (buf) {
+ if (type == fontType1) {
+ fontFile = new Type1FontFile(buf, len);
+ } else if (type == fontType1C) {
+ fontFile = new Type1CFontFile(buf, len);
+ } else {
+ fontFile = new TrueTypeFontFile(buf, len);
+ }
+ if (fontFile->getName()) {
+ if (embFontName)
+ delete embFontName;
+ embFontName = new GString(fontFile->getName());
+ }
+ if (!encoding) {
+ encoding = fontFile->getEncoding(gTrue);
+ }
+ delete fontFile;
+ gfree(buf);
+ }
+ }
+
+ // get default base encoding
+ if (!encoding) {
+ if (builtinFont)
+ encoding = builtinFont->encoding->copy();
+ else if (type == fontTrueType)
+ encoding = macRomanEncoding.copy();
+ else
+ encoding = standardEncoding.copy();
+ }
+
+ // merge differences into encoding
+ fontDict->lookup("Encoding", &obj1);
+ if (obj1.isDict()) {
+ obj1.dictLookup("Differences", &obj2);
+ if (obj2.isArray()) {
+ code = 0;
+ for (i = 0; i < obj2.arrayGetLength(); ++i) {
+ obj2.arrayGet(i, &obj3);
+ if (obj3.isInt()) {
+ code = obj3.getInt();
+ } else if (obj3.isName()) {
+ if (code < 256)
+ encoding->addChar(code, copyString(obj3.getName()));
+ ++code;
+ } else {
+ error(-1, "Wrong type in font encoding resource differences (%s)",
+ obj3.getTypeName());
+ }
+ obj3.free();
+ }
+ }
+ obj2.free();
+ }
+ obj1.free();
+
+ // get character widths
+ if (builtinFont)
+ makeWidths(fontDict, builtinFont->encoding, builtinFont->widths,
+ missingWidth);
+ else
+ makeWidths(fontDict, NULL, NULL, missingWidth);
+}
+
+void GfxFont::findExtFontFile() {
+ char **path;
+ FILE *f;
+
+ for (path = fontPath; *path; ++path) {
+ extFontFile = appendToPath(new GString(*path), name->getCString());
+ f = fopen(extFontFile->getCString(), "rb");
+ if (!f) {
+ extFontFile->append(".pfb");
+ f = fopen(extFontFile->getCString(), "rb");
+ }
+ if (!f) {
+ extFontFile->del(extFontFile->getLength() - 4, 4);
+ extFontFile->append(".pfa");
+ f = fopen(extFontFile->getCString(), "rb");
+ }
+ if (f) {
+ fclose(f);
+ break;
+ }
+ delete extFontFile;
+ extFontFile = NULL;
+ }
+}
+
+char *GfxFont::readExtFontFile(int *len) {
+ FILE *f;
+ char *buf;
+
+ if (!(f = fopen(extFontFile->getCString(), "rb"))) {
+ error(-1, "Internal: external font file '%s' vanished", extFontFile);
+ return NULL;
+ }
+ fseek(f, 0, SEEK_END);
+ *len = (int)ftell(f);
+ fseek(f, 0, SEEK_SET);
+ buf = (char *)gmalloc(*len);
+ if ((int)fread(buf, 1, *len, f) != *len)
+ error(-1, "Error reading external font file '%s'", extFontFile);
+ fclose(f);
+ return buf;
+}
+
+char *GfxFont::readEmbFontFile(XRef *xref, int *len) {
+ char *buf;
+ Object obj1, obj2;
+ Stream *str;
+ int c;
+ int size, i;
+
+ obj1.initRef(embFontID.num, embFontID.gen);
+ obj1.fetch(xref, &obj2);
+ if (!obj2.isStream()) {
+ error(-1, "Embedded font file is not a stream");
+ obj2.free();
+ obj1.free();
+ embFontID.num = -1;
+ return NULL;
+ }
+ str = obj2.getStream();
+
+ buf = NULL;
+ i = size = 0;
+ str->reset();
+ while ((c = str->getChar()) != EOF) {
+ if (i == size) {
+ size += 4096;
+ buf = (char *)grealloc(buf, size);
+ }
+ buf[i++] = c;
+ }
+ *len = i;
+ str->close();
+
+ obj2.free();
+ obj1.free();
+
+ return buf;
+}
+
+void GfxFont::makeWidths(Dict *fontDict, FontEncoding *builtinEncoding,
+ Gushort *builtinWidths, int missingWidth) {
+ Object obj1, obj2;
+ int firstChar, lastChar;
+ int code, code2;
+ char *charName;
+ Gushort *defWidths;
+ int index;
+ double mult;
+
+ // initialize all widths
+ for (code = 0; code < 256; ++code) {
+ widths[code] = missingWidth * 0.001;
+ }
+
+ // use widths from font dict, if present
+ fontDict->lookup("FirstChar", &obj1);
+ firstChar = obj1.isInt() ? obj1.getInt() : 0;
+ obj1.free();
+ fontDict->lookup("LastChar", &obj1);
+ lastChar = obj1.isInt() ? obj1.getInt() : 255;
+ obj1.free();
+ if (type == fontType3)
+ mult = fontMat[0];
+ else
+ mult = 0.001;
+ fontDict->lookup("Widths", &obj1);
+ if (obj1.isArray()) {
+ for (code = firstChar; code <= lastChar; ++code) {
+ obj1.arrayGet(code - firstChar, &obj2);
+ if (obj2.isNum())
+ widths[code] = obj2.getNum() * mult;
+ obj2.free();
+ }
+
+ // use widths from built-in font
+ } else if (builtinEncoding) {
+ code2 = 0; // to make gcc happy
+ for (code = 0; code < 256; ++code) {
+ if ((charName = encoding->getCharName(code)) &&
+ (code2 = builtinEncoding->getCharCode(charName)) >= 0) {
+ widths[code] = builtinWidths[code2] * 0.001;
+ } else if (code == 32) {
+ // this is a kludge for broken PDF files that encode char 32
+ // as .notdef
+ widths[code] = builtinWidths[' '] * 0.001;
+ }
+ }
+
+ // couldn't find widths -- use defaults
+ } else {
+#if 0 //~
+ //~ certain PDF generators apparently don't include widths
+ //~ for Arial and TimesNewRoman -- and this error message
+ //~ is a nuisance
+ error(-1, "No character widths resource for non-builtin font");
+#endif
+ if (isFixedWidth())
+ index = 0;
+ else if (isSerif())
+ index = 8;
+ else
+ index = 4;
+ if (isBold())
+ index += 2;
+ if (isItalic())
+ index += 1;
+ defWidths = defCharWidths[index];
+ code2 = 0; // to make gcc happy
+ for (code = 0; code < 256; ++code) {
+ if ((charName = encoding->getCharName(code)) &&
+ (code2 = standardEncoding.getCharCode(charName)) >= 0)
+ widths[code] = defWidths[code2] * 0.001;
+ }
+ }
+ obj1.free();
+}
+
+void GfxFont::getType0EncAndWidths(Dict *fontDict) {
+ Object obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8;
+ int excepsSize;
+ int i, j, k, n;
+
+ widths16.exceps = NULL;
+ widths16.excepsV = NULL;
+
+ // get the CIDFont
+ fontDict->lookup("DescendantFonts", &obj1);
+ if (!obj1.isArray() || obj1.arrayGetLength() != 1) {
+ error(-1, "Bad DescendantFonts entry for Type 0 font");
+ goto err1;
+ }
+ obj1.arrayGet(0, &obj2);
+ if (!obj2.isDict()) {
+ error(-1, "Bad descendant font of Type 0 font");
+ goto err2;
+ }
+
+ // get font info
+ obj2.dictLookup("CIDSystemInfo", &obj3);
+ if (!obj3.isDict()) {
+ error(-1, "Bad CIDSystemInfo in Type 0 font descendant");
+ goto err3;
+ }
+ obj3.dictLookup("Registry", &obj4);
+ obj3.dictLookup("Ordering", &obj5);
+ if (obj4.isString() && obj5.isString()) {
+ if (obj4.getString()->cmp("Adobe") == 0 &&
+ obj5.getString()->cmp("Japan1") == 0) {
+#if JAPANESE_SUPPORT
+ is16 = gTrue;
+ enc16.charSet = font16AdobeJapan12;
+#else
+ error(-1, "Xpdf was compiled without Japanese font support");
+ goto err4;
+#endif
+ } else if (obj4.getString()->cmp("Adobe") == 0 &&
+ obj5.getString()->cmp("GB1") == 0) {
+#if CHINESE_GB_SUPPORT
+ is16 = gTrue;
+ enc16.charSet = font16AdobeGB12;
+#else
+ error(-1, "Xpdf was compiled without Chinese GB font support");
+ goto err4;
+#endif
+ } else if (obj4.getString()->cmp("Adobe") == 0 &&
+ obj5.getString()->cmp("CNS1") == 0) {
+#if CHINESE_CNS_SUPPORT
+ is16 = gTrue;
+ enc16.charSet = font16AdobeCNS13;
+#else
+ error(-1, "Xpdf was compiled without Chinese CNS font support");
+ goto err4;
+#endif
+ } else {
+ error(-1, "Unknown Type 0 character set: %s-%s",
+ obj4.getString()->getCString(), obj5.getString()->getCString());
+ goto err4;
+ }
+ } else {
+ error(-1, "Unknown Type 0 character set");
+ goto err4;
+ }
+ obj5.free();
+ obj4.free();
+ obj3.free();
+
+ // get default char width
+ obj2.dictLookup("DW", &obj3);
+ if (obj3.isInt())
+ widths16.defWidth = obj3.getInt() * 0.001;
+ else
+ widths16.defWidth = 1.0;
+ obj3.free();
+
+ // get default char metrics for vertical font
+ obj2.dictLookup("DW2", &obj3);
+ widths16.defVY = 0.880;
+ widths16.defHeight = -1;
+ if (obj3.isArray() && obj3.arrayGetLength() == 2) {
+ obj3.arrayGet(0, &obj4);
+ if (obj4.isInt()) {
+ widths16.defVY = obj4.getInt() * 0.001;
+ }
+ obj4.free();
+ obj3.arrayGet(1, &obj4);
+ if (obj4.isInt()) {
+ widths16.defHeight = obj4.getInt() * 0.001;
+ }
+ obj4.free();
+ }
+ obj3.free();
+
+ // get char width exceptions
+ widths16.exceps = NULL;
+ widths16.numExceps = 0;
+ obj2.dictLookup("W", &obj3);
+ if (obj3.isArray()) {
+ excepsSize = 0;
+ k = 0;
+ i = 0;
+ while (i+1 < obj3.arrayGetLength()) {
+ obj3.arrayGet(i, &obj4);
+ obj3.arrayGet(i+1, &obj5);
+ if (obj4.isInt() && obj5.isInt()) {
+ obj3.arrayGet(i+2, &obj6);
+ if (!obj6.isNum()) {
+ error(-1, "Bad widths array in Type 0 font");
+ obj6.free();
+ obj5.free();
+ obj4.free();
+ break;
+ }
+ if (k == excepsSize) {
+ excepsSize += 16;
+ widths16.exceps = (GfxFontWidthExcep *)
+ grealloc(widths16.exceps,
+ excepsSize * sizeof(GfxFontWidthExcep));
+ }
+ widths16.exceps[k].first = obj4.getInt();
+ widths16.exceps[k].last = obj5.getInt();
+ widths16.exceps[k].width = obj6.getNum() * 0.001;
+ obj6.free();
+ ++k;
+ i += 3;
+ } else if (obj4.isInt() && obj5.isArray()) {
+ if (k + obj5.arrayGetLength() >= excepsSize) {
+ excepsSize = (k + obj5.arrayGetLength() + 15) & ~15;
+ widths16.exceps = (GfxFontWidthExcep *)
+ grealloc(widths16.exceps,
+ excepsSize * sizeof(GfxFontWidthExcep));
+ }
+ n = obj4.getInt();
+ for (j = 0; j < obj5.arrayGetLength(); ++j) {
+ obj5.arrayGet(j, &obj6);
+ if (!obj6.isNum()) {
+ error(-1, "Bad widths array in Type 0 font");
+ obj6.free();
+ break;
+ }
+ widths16.exceps[k].first = widths16.exceps[k].last = n++;
+ widths16.exceps[k].width = obj6.getNum() * 0.001;
+ obj6.free();
+ ++k;
+ }
+ i += 2;
+ } else {
+ error(-1, "Bad widths array in Type 0 font");
+ obj6.free();
+ obj5.free();
+ obj4.free();
+ break;
+ }
+ obj5.free();
+ obj4.free();
+ }
+ widths16.numExceps = k;
+ if (k > 0)
+ qsort(widths16.exceps, k, sizeof(GfxFontWidthExcep), &cmpWidthExcep);
+ }
+ obj3.free();
+
+ // get char metric exceptions for vertical font
+ widths16.excepsV = NULL;
+ widths16.numExcepsV = 0;
+ obj2.dictLookup("W2", &obj3);
+ if (obj3.isArray()) {
+ excepsSize = 0;
+ k = 0;
+ i = 0;
+ while (i+1 < obj3.arrayGetLength()) {
+ obj3.arrayGet(i, &obj4);
+ obj3.arrayGet(i+1, &obj5);
+ if (obj4.isInt() && obj5.isInt()) {
+ obj3.arrayGet(i+2, &obj6);
+ obj3.arrayGet(i+3, &obj7);
+ obj3.arrayGet(i+4, &obj8);
+ if (!obj6.isNum() || !obj7.isNum() || !obj8.isNum()) {
+ error(-1, "Bad widths (W2) array in Type 0 font");
+ obj8.free();
+ obj7.free();
+ obj6.free();
+ obj5.free();
+ obj4.free();
+ break;
+ }
+ if (k == excepsSize) {
+ excepsSize += 16;
+ widths16.excepsV = (GfxFontWidthExcepV *)
+ grealloc(widths16.excepsV,
+ excepsSize * sizeof(GfxFontWidthExcepV));
+ }
+ widths16.excepsV[k].first = obj4.getInt();
+ widths16.excepsV[k].last = obj5.getInt();
+ widths16.excepsV[k].height = obj6.getNum() * 0.001;
+ widths16.excepsV[k].vx = obj7.getNum() * 0.001;
+ widths16.excepsV[k].vy = obj8.getNum() * 0.001;
+ obj8.free();
+ obj7.free();
+ obj6.free();
+ ++k;
+ i += 5;
+ } else if (obj4.isInt() && obj5.isArray()) {
+ if (k + obj5.arrayGetLength() / 3 >= excepsSize) {
+ excepsSize = (k + obj5.arrayGetLength() / 3 + 15) & ~15;
+ widths16.excepsV = (GfxFontWidthExcepV *)
+ grealloc(widths16.excepsV,
+ excepsSize * sizeof(GfxFontWidthExcepV));
+ }
+ n = obj4.getInt();
+ for (j = 0; j < obj5.arrayGetLength(); j += 3) {
+ obj5.arrayGet(j, &obj6);
+ obj5.arrayGet(j+1, &obj7);
+ obj5.arrayGet(j+1, &obj8);
+ if (!obj6.isNum() || !obj7.isNum() || !obj8.isNum()) {
+ error(-1, "Bad widths (W2) array in Type 0 font");
+ obj6.free();
+ break;
+ }
+ widths16.excepsV[k].first = widths16.exceps[k].last = n++;
+ widths16.excepsV[k].height = obj6.getNum() * 0.001;
+ widths16.excepsV[k].vx = obj7.getNum() * 0.001;
+ widths16.excepsV[k].vy = obj8.getNum() * 0.001;
+ obj8.free();
+ obj7.free();
+ obj6.free();
+ ++k;
+ }
+ i += 2;
+ } else {
+ error(-1, "Bad widths array in Type 0 font");
+ obj5.free();
+ obj4.free();
+ break;
+ }
+ obj5.free();
+ obj4.free();
+ }
+ widths16.numExcepsV = k;
+ if (k > 0) {
+ qsort(widths16.excepsV, k, sizeof(GfxFontWidthExcepV), &cmpWidthExcepV);
+ }
+ }
+ obj3.free();
+
+ obj2.free();
+ obj1.free();
+
+ // get encoding (CMap)
+ fontDict->lookup("Encoding", &obj1);
+ if (!obj1.isName()) {
+ error(-1, "Bad encoding for Type 0 font");
+ goto err1;
+ }
+#if JAPANESE_SUPPORT
+ if (enc16.charSet == font16AdobeJapan12) {
+ for (i = 0; gfxJapan12Tab[i].name; ++i) {
+ if (!strcmp(obj1.getName(), gfxJapan12Tab[i].name))
+ break;
+ }
+ if (!gfxJapan12Tab[i].name) {
+ error(-1, "Unknown encoding '%s' for Adobe-Japan1-2 font",
+ obj1.getName());
+ goto err1;
+ }
+ enc16.enc = gfxJapan12Tab[i].enc;
+ }
+#endif
+#if CHINESE_GB_SUPPORT
+ if (enc16.charSet == font16AdobeGB12) {
+ for (i = 0; gfxGB12Tab[i].name; ++i) {
+ if (!strcmp(obj1.getName(), gfxGB12Tab[i].name))
+ break;
+ }
+ if (!gfxGB12Tab[i].name) {
+ error(-1, "Unknown encoding '%s' for Adobe-GB1-2 font",
+ obj1.getName());
+ goto err1;
+ }
+ enc16.enc = gfxGB12Tab[i].enc;
+ }
+#endif
+#if CHINESE_CNS_SUPPORT
+ if (enc16.charSet == font16AdobeCNS13) {
+ for (i = 0; gfxCNS13Tab[i].name; ++i) {
+ if (!strcmp(obj1.getName(), gfxCNS13Tab[i].name))
+ break;
+ }
+ if (!gfxCNS13Tab[i].name) {
+ error(-1, "Unknown encoding '%s' for Adobe-CNS1-3 font",
+ obj1.getName());
+ goto err1;
+ }
+ enc16.enc = gfxCNS13Tab[i].enc;
+ }
+#endif
+ obj1.free();
+
+ return;
+
+ err4:
+ obj5.free();
+ obj4.free();
+ err3:
+ obj3.free();
+ err2:
+ obj2.free();
+ err1:
+ obj1.free();
+ //~ fix this --> add 16-bit font support to FontFile
+ encoding = new FontEncoding();
+ makeWidths(fontDict, NULL, NULL, 0);
+}
+
+extern "C" {
+static int CDECL cmpWidthExcep(const void *w1, const void *w2) {
+ return ((GfxFontWidthExcep *)w1)->first - ((GfxFontWidthExcep *)w2)->first;
+}
+
+static int CDECL cmpWidthExcepV(const void *w1, const void *w2) {
+ return ((GfxFontWidthExcepV *)w1)->first - ((GfxFontWidthExcepV *)w2)->first;
+}
+}
+
+//------------------------------------------------------------------------
+// GfxFontDict
+//------------------------------------------------------------------------
+
+GfxFontDict::GfxFontDict(XRef *xref, Dict *fontDict) {
+ int i;
+ Object obj1, obj2;
+
+ numFonts = fontDict->getLength();
+ fonts = (GfxFont **)gmalloc(numFonts * sizeof(GfxFont *));
+ for (i = 0; i < numFonts; ++i) {
+ fontDict->getValNF(i, &obj1);
+ obj1.fetch(xref, &obj2);
+ if (obj1.isRef() && obj2.isDict()) {
+ fonts[i] = new GfxFont(xref, fontDict->getKey(i),
+ obj1.getRef(), obj2.getDict());
+ } else {
+ error(-1, "font resource is not a dictionary");
+ fonts[i] = NULL;
+ }
+ obj1.free();
+ obj2.free();
+ }
+}
+
+GfxFontDict::~GfxFontDict() {
+ int i;
+
+ for (i = 0; i < numFonts; ++i)
+ delete fonts[i];
+ gfree(fonts);
+}
+
+GfxFont *GfxFontDict::lookup(char *tag) {
+ int i;
+
+ for (i = 0; i < numFonts; ++i) {
+ if (fonts[i]->matches(tag))
+ return fonts[i];
+ }
+ return NULL;
+}
diff --git a/pdftops/GfxFont.h b/pdftops/GfxFont.h
new file mode 100644
index 000000000..e51635632
--- /dev/null
+++ b/pdftops/GfxFont.h
@@ -0,0 +1,250 @@
+//========================================================================
+//
+// GfxFont.h
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifndef GFXFONT_H
+#define GFXFONT_H
+
+#ifdef __GNUC__
+#pragma interface
+#endif
+
+#include "gtypes.h"
+#include "GString.h"
+#include "Object.h"
+#include "FontEncoding.h"
+
+class Dict;
+struct BuiltinFont;
+
+//------------------------------------------------------------------------
+// GfxFontCharSet16
+//------------------------------------------------------------------------
+
+enum GfxFontCharSet16 {
+ font16AdobeJapan12, // Adobe-Japan1-2
+ font16AdobeGB12, // Adobe-GB1-2 (Chinese)
+ font16AdobeCNS13 // Adobe-CNS1-3 (Chinese)
+};
+
+//------------------------------------------------------------------------
+// GfxFontEncoding16
+//------------------------------------------------------------------------
+
+struct GfxFontEncoding16 {
+ int wMode; // writing mode (0=horizontal, 1=vertical)
+ Guchar codeLen[256]; // length of codes, in bytes, indexed by
+ // first byte of code
+ Gushort map1[256]; // one-byte code mapping:
+ // map1[code] --> 16-bit char selector
+ Gushort *map2; // two-byte code mapping
+ // map2[2*i] --> first code in range
+ // map2[2*i+1] --> 16-bit char selector
+ // for map2[2*i]
+ int map2Len; // length of map2 array (divided by 2)
+};
+
+//------------------------------------------------------------------------
+// GfxFontWidths16
+//------------------------------------------------------------------------
+
+struct GfxFontWidthExcep {
+ int first; // this record applies to
+ int last; // chars <first>..<last>
+ double width; // char width
+};
+
+struct GfxFontWidthExcepV {
+ int first; // this record applies to
+ int last; // chars <first>..<last>
+ double height; // char height
+ double vx, vy; // origin position
+};
+
+struct GfxFontWidths16 {
+ double defWidth; // default char width
+ double defHeight; // default char height
+ double defVY; // default origin position
+ GfxFontWidthExcep *exceps; // exceptions
+ int numExceps; // number of valid entries in exceps
+ GfxFontWidthExcepV *excepsV; // exceptions for vertical font
+ int numExcepsV; // number of valid entries in excepsV
+};
+
+//------------------------------------------------------------------------
+// GfxFont
+//------------------------------------------------------------------------
+
+#define fontFixedWidth (1 << 0)
+#define fontSerif (1 << 1)
+#define fontSymbolic (1 << 2)
+#define fontItalic (1 << 6)
+#define fontBold (1 << 18)
+
+enum GfxFontType {
+ fontUnknownType,
+ fontType1,
+ fontType1C,
+ fontType3,
+ fontTrueType,
+ fontType0
+};
+
+class GfxFont {
+public:
+
+ // Constructor.
+ GfxFont(XRef *xref, char *tagA, Ref idA, Dict *fontDict);
+
+ // Destructor.
+ ~GfxFont();
+
+ // Get font tag.
+ GString *getTag() { return tag; }
+
+ // Get font dictionary ID.
+ Ref getID() { return id; }
+
+ // Does this font match the tag?
+ GBool matches(char *tagA) { return !tag->cmp(tagA); }
+
+ // Get base font name.
+ GString *getName() { return name; }
+
+ // Get font type.
+ GfxFontType getType() { return type; }
+
+ // Does this font use 16-bit characters?
+ GBool is16Bit() { return is16; }
+
+ // Get embedded font ID, i.e., a ref for the font file stream.
+ // Returns false if there is no embedded font.
+ GBool getEmbeddedFontID(Ref *embID)
+ { *embID = embFontID; return embFontID.num >= 0; }
+
+ // Get the PostScript font name for the embedded font. Returns
+ // NULL if there is no embedded font.
+ char *getEmbeddedFontName()
+ { return embFontName ? embFontName->getCString() : (char *)NULL; }
+
+ // Get the name of the external font file. Returns NULL if there
+ // is no external font file.
+ GString *getExtFontFile() { return extFontFile; }
+
+ // Get font descriptor flags.
+ GBool isFixedWidth() { return flags & fontFixedWidth; }
+ GBool isSerif() { return flags & fontSerif; }
+ GBool isSymbolic() { return flags & fontSymbolic; }
+ GBool isItalic() { return flags & fontItalic; }
+ GBool isBold() { return flags & fontBold; }
+
+ // Get width of a character or string.
+ double getWidth(Guchar c) { return widths[c]; }
+ double getWidth(GString *s);
+
+ // Get character metrics for 16-bit font.
+ double getWidth16(int c);
+ double getHeight16(int c);
+ double getOriginX16(int c);
+ double getOriginY16(int c);
+
+ // Return the encoding.
+ FontEncoding *getEncoding() { return encoding; }
+
+ // Return the character name associated with <code>.
+ char *getCharName(int code) { return encoding->getCharName(code); }
+
+ // Return the code associated with <name>.
+ int getCharCode(char *charName) { return encoding->getCharCode(charName); }
+
+ // Return the Type 3 CharProc for the character associated with <code>.
+ Object *getCharProc(int code, Object *proc);
+
+ // Return the 16-bit character set and encoding.
+ GfxFontCharSet16 getCharSet16() { return enc16.charSet; }
+ GfxFontEncoding16 *getEncoding16() { return enc16.enc; }
+
+ // Get the writing mode (0=horizontal, 1=vertical).
+ int getWMode16() { return enc16.enc->wMode; }
+
+ // Return the font matrix.
+ double *getFontMatrix() { return fontMat; }
+
+ // Return the font bounding box.
+ double *getFontBBox() { return fontBBox; }
+
+ // Return the ascent and descent values.
+ double getAscent() { return ascent; }
+ double getDescent() { return descent; }
+
+ // Read an external or embedded font file into a buffer.
+ char *readExtFontFile(int *len);
+ char *readEmbFontFile(XRef *xref, int *len);
+
+private:
+
+ void getEncAndWidths(XRef *xref, Dict *fontDict,
+ BuiltinFont *builtinFont, int missingWidth);
+ void findExtFontFile();
+ void makeWidths(Dict *fontDict, FontEncoding *builtinEncoding,
+ Gushort *builtinWidths, int missingWidth);
+ void getType0EncAndWidths(Dict *fontDict);
+
+ GString *tag; // PDF font tag
+ Ref id; // reference (used as unique ID)
+ GString *name; // font name
+ int flags; // font descriptor flags
+ GfxFontType type; // type of font
+ GBool is16; // set if font uses 16-bit chars
+ GString *embFontName; // name of embedded font
+ Ref embFontID; // ref to embedded font file stream
+ GString *extFontFile; // external font file name
+ Object charProcs; // Type3 CharProcs dictionary
+ double fontMat[6]; // font matrix
+ double fontBBox[4]; // font bounding box
+ double ascent; // max height above baseline
+ double descent; // max depth below baseline
+ union {
+ FontEncoding *encoding; // 8-bit font encoding
+ struct {
+ GfxFontCharSet16 charSet; // 16-bit character set
+ GfxFontEncoding16 *enc; // 16-bit encoding (CMap)
+ } enc16;
+ };
+ union {
+ double widths[256]; // width of each char for 8-bit font
+ GfxFontWidths16 widths16; // char widths for 16-bit font
+ };
+};
+
+//------------------------------------------------------------------------
+// GfxFontDict
+//------------------------------------------------------------------------
+
+class GfxFontDict {
+public:
+
+ // Build the font dictionary, given the PDF font dictionary.
+ GfxFontDict(XRef *xref, Dict *fontDict);
+
+ // Destructor.
+ ~GfxFontDict();
+
+ // Get the specified font.
+ GfxFont *lookup(char *tag);
+
+ // Iterative access.
+ int getNumFonts() { return numFonts; }
+ GfxFont *getFont(int i) { return fonts[i]; }
+
+private:
+
+ GfxFont **fonts; // list of fonts
+ int numFonts; // number of fonts
+};
+
+#endif
diff --git a/pdftops/GfxState.cxx b/pdftops/GfxState.cxx
new file mode 100644
index 000000000..140741570
--- /dev/null
+++ b/pdftops/GfxState.cxx
@@ -0,0 +1,2100 @@
+//========================================================================
+//
+// GfxState.cc
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#include <stddef.h>
+#include <math.h>
+#include <string.h> // for memcpy()
+#include "gmem.h"
+#include "Error.h"
+#include "Object.h"
+#include "Array.h"
+#include "Page.h"
+#include "GfxState.h"
+
+//------------------------------------------------------------------------
+
+static inline double clip01(double x) {
+ return (x < 0) ? 0 : ((x > 1) ? 1 : x);
+}
+
+//------------------------------------------------------------------------
+// GfxColorSpace
+//------------------------------------------------------------------------
+
+GfxColorSpace::GfxColorSpace() {
+}
+
+GfxColorSpace::~GfxColorSpace() {
+}
+
+GfxColorSpace *GfxColorSpace::parse(Object *csObj) {
+ GfxColorSpace *cs;
+ Object obj1;
+
+ cs = NULL;
+ if (csObj->isName()) {
+ if (csObj->isName("DeviceGray") || csObj->isName("G")) {
+ cs = new GfxDeviceGrayColorSpace();
+ } else if (csObj->isName("DeviceRGB") || csObj->isName("RGB")) {
+ cs = new GfxDeviceRGBColorSpace();
+ } else if (csObj->isName("DeviceCMYK") || csObj->isName("CMYK")) {
+ cs = new GfxDeviceCMYKColorSpace();
+ } else if (csObj->isName("Pattern")) {
+ cs = new GfxPatternColorSpace(NULL);
+ } else {
+ error(-1, "Bad color space '%s'", csObj->getName());
+ }
+ } else if (csObj->isArray()) {
+ csObj->arrayGet(0, &obj1);
+ if (obj1.isName("DeviceGray") || obj1.isName("G")) {
+ cs = new GfxDeviceGrayColorSpace();
+ } else if (obj1.isName("DeviceRGB") || obj1.isName("RGB")) {
+ cs = new GfxDeviceRGBColorSpace();
+ } else if (obj1.isName("DeviceCMYK") || obj1.isName("CMYK")) {
+ cs = new GfxDeviceCMYKColorSpace();
+ } else if (obj1.isName("CalGray")) {
+ cs = GfxCalGrayColorSpace::parse(csObj->getArray());
+ } else if (obj1.isName("CalRGB")) {
+ cs = GfxCalRGBColorSpace::parse(csObj->getArray());
+ } else if (obj1.isName("Lab")) {
+ cs = GfxLabColorSpace::parse(csObj->getArray());
+ } else if (obj1.isName("ICCBased")) {
+ cs = GfxICCBasedColorSpace::parse(csObj->getArray());
+ } else if (obj1.isName("Indexed") || obj1.isName("I")) {
+ cs = GfxIndexedColorSpace::parse(csObj->getArray());
+ } else if (obj1.isName("Separation")) {
+ cs = GfxSeparationColorSpace::parse(csObj->getArray());
+ } else if (obj1.isName("DeviceN")) {
+ cs = GfxDeviceNColorSpace::parse(csObj->getArray());
+ } else if (obj1.isName("Pattern")) {
+ cs = GfxPatternColorSpace::parse(csObj->getArray());
+ } else {
+ error(-1, "Bad color space '%s'", csObj->getName());
+ }
+ obj1.free();
+ } else {
+ error(-1, "Bad color space - expected name or array");
+ }
+ return cs;
+}
+
+void GfxColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
+ int maxImgPixel) {
+ int i;
+
+ for (i = 0; i < getNComps(); ++i) {
+ decodeLow[i] = 0;
+ decodeRange[i] = 1;
+ }
+}
+
+//------------------------------------------------------------------------
+// GfxDeviceGrayColorSpace
+//------------------------------------------------------------------------
+
+GfxDeviceGrayColorSpace::GfxDeviceGrayColorSpace() {
+}
+
+GfxDeviceGrayColorSpace::~GfxDeviceGrayColorSpace() {
+}
+
+GfxColorSpace *GfxDeviceGrayColorSpace::copy() {
+ return new GfxDeviceGrayColorSpace();
+}
+
+void GfxDeviceGrayColorSpace::getGray(GfxColor *color, double *gray) {
+ *gray = clip01(color->c[0]);
+}
+
+void GfxDeviceGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
+ rgb->r = rgb->g = rgb->b = clip01(color->c[0]);
+}
+
+void GfxDeviceGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
+ cmyk->c = cmyk->m = cmyk->y = 0;
+ cmyk->k = clip01(1 - color->c[0]);
+}
+
+//------------------------------------------------------------------------
+// GfxCalGrayColorSpace
+//------------------------------------------------------------------------
+
+GfxCalGrayColorSpace::GfxCalGrayColorSpace() {
+ whiteX = whiteY = whiteZ = 1;
+ blackX = blackY = blackZ = 0;
+ gamma = 1;
+}
+
+GfxCalGrayColorSpace::~GfxCalGrayColorSpace() {
+}
+
+GfxColorSpace *GfxCalGrayColorSpace::copy() {
+ GfxCalGrayColorSpace *cs;
+
+ cs = new GfxCalGrayColorSpace();
+ cs->whiteX = whiteX;
+ cs->whiteY = whiteY;
+ cs->whiteZ = whiteZ;
+ cs->blackX = blackX;
+ cs->blackY = blackY;
+ cs->blackZ = blackZ;
+ cs->gamma = gamma;
+ return cs;
+}
+
+GfxColorSpace *GfxCalGrayColorSpace::parse(Array *arr) {
+ GfxCalGrayColorSpace *cs;
+ Object obj1, obj2, obj3;
+
+ arr->get(1, &obj1);
+ if (!obj1.isDict()) {
+ error(-1, "Bad CalGray color space");
+ obj1.free();
+ return NULL;
+ }
+ cs = new GfxCalGrayColorSpace();
+ if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
+ obj2.arrayGetLength() == 3) {
+ obj2.arrayGet(0, &obj3);
+ cs->whiteX = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(1, &obj3);
+ cs->whiteY = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(2, &obj3);
+ cs->whiteZ = obj3.getNum();
+ obj3.free();
+ }
+ obj2.free();
+ if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
+ obj2.arrayGetLength() == 3) {
+ obj2.arrayGet(0, &obj3);
+ cs->blackX = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(1, &obj3);
+ cs->blackY = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(2, &obj3);
+ cs->blackZ = obj3.getNum();
+ obj3.free();
+ }
+ obj2.free();
+ if (obj1.dictLookup("Gamma", &obj2)->isNum()) {
+ cs->gamma = obj2.getNum();
+ }
+ obj2.free();
+ obj1.free();
+ return cs;
+}
+
+void GfxCalGrayColorSpace::getGray(GfxColor *color, double *gray) {
+ *gray = clip01(color->c[0]);
+}
+
+void GfxCalGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
+ rgb->r = rgb->g = rgb->b = clip01(color->c[0]);
+}
+
+void GfxCalGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
+ cmyk->c = cmyk->m = cmyk->y = 0;
+ cmyk->k = clip01(1 - color->c[0]);
+}
+
+//------------------------------------------------------------------------
+// GfxDeviceRGBColorSpace
+//------------------------------------------------------------------------
+
+GfxDeviceRGBColorSpace::GfxDeviceRGBColorSpace() {
+}
+
+GfxDeviceRGBColorSpace::~GfxDeviceRGBColorSpace() {
+}
+
+GfxColorSpace *GfxDeviceRGBColorSpace::copy() {
+ return new GfxDeviceRGBColorSpace();
+}
+
+void GfxDeviceRGBColorSpace::getGray(GfxColor *color, double *gray) {
+ *gray = clip01(0.299 * color->c[0] +
+ 0.587 * color->c[1] +
+ 0.114 * color->c[2]);
+}
+
+void GfxDeviceRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
+ rgb->r = clip01(color->c[0]);
+ rgb->g = clip01(color->c[1]);
+ rgb->b = clip01(color->c[2]);
+}
+
+void GfxDeviceRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
+ double c, m, y, k;
+
+ c = clip01(1 - color->c[0]);
+ m = clip01(1 - color->c[1]);
+ y = clip01(1 - color->c[2]);
+ k = c;
+ if (m < k) {
+ k = m;
+ }
+ if (y < k) {
+ k = y;
+ }
+ cmyk->c = c - k;
+ cmyk->m = m - k;
+ cmyk->y = y - k;
+ cmyk->k = k;
+}
+
+//------------------------------------------------------------------------
+// GfxCalRGBColorSpace
+//------------------------------------------------------------------------
+
+GfxCalRGBColorSpace::GfxCalRGBColorSpace() {
+ whiteX = whiteY = whiteZ = 1;
+ blackX = blackY = blackZ = 0;
+ gammaR = gammaG = gammaB = 1;
+ mat[0] = 1; mat[1] = 0; mat[2] = 0;
+ mat[3] = 0; mat[4] = 1; mat[5] = 0;
+ mat[6] = 0; mat[7] = 0; mat[8] = 1;
+}
+
+GfxCalRGBColorSpace::~GfxCalRGBColorSpace() {
+}
+
+GfxColorSpace *GfxCalRGBColorSpace::copy() {
+ GfxCalRGBColorSpace *cs;
+ int i;
+
+ cs = new GfxCalRGBColorSpace();
+ cs->whiteX = whiteX;
+ cs->whiteY = whiteY;
+ cs->whiteZ = whiteZ;
+ cs->blackX = blackX;
+ cs->blackY = blackY;
+ cs->blackZ = blackZ;
+ cs->gammaR = gammaR;
+ cs->gammaG = gammaG;
+ cs->gammaB = gammaB;
+ for (i = 0; i < 9; ++i) {
+ cs->mat[i] = mat[i];
+ }
+ return cs;
+}
+
+GfxColorSpace *GfxCalRGBColorSpace::parse(Array *arr) {
+ GfxCalRGBColorSpace *cs;
+ Object obj1, obj2, obj3;
+ int i;
+
+ arr->get(1, &obj1);
+ if (!obj1.isDict()) {
+ error(-1, "Bad CalRGB color space");
+ obj1.free();
+ return NULL;
+ }
+ cs = new GfxCalRGBColorSpace();
+ if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
+ obj2.arrayGetLength() == 3) {
+ obj2.arrayGet(0, &obj3);
+ cs->whiteX = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(1, &obj3);
+ cs->whiteY = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(2, &obj3);
+ cs->whiteZ = obj3.getNum();
+ obj3.free();
+ }
+ obj2.free();
+ if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
+ obj2.arrayGetLength() == 3) {
+ obj2.arrayGet(0, &obj3);
+ cs->blackX = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(1, &obj3);
+ cs->blackY = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(2, &obj3);
+ cs->blackZ = obj3.getNum();
+ obj3.free();
+ }
+ obj2.free();
+ if (obj1.dictLookup("Gamma", &obj2)->isArray() &&
+ obj2.arrayGetLength() == 3) {
+ obj2.arrayGet(0, &obj3);
+ cs->gammaR = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(1, &obj3);
+ cs->gammaG = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(2, &obj3);
+ cs->gammaB = obj3.getNum();
+ obj3.free();
+ }
+ obj2.free();
+ if (obj1.dictLookup("Matrix", &obj2)->isArray() &&
+ obj2.arrayGetLength() == 9) {
+ for (i = 0; i < 9; ++i) {
+ obj2.arrayGet(i, &obj3);
+ cs->mat[i] = obj3.getNum();
+ obj3.free();
+ }
+ }
+ obj2.free();
+ obj1.free();
+ return cs;
+}
+
+void GfxCalRGBColorSpace::getGray(GfxColor *color, double *gray) {
+ *gray = clip01(0.299 * color->c[0] +
+ 0.587 * color->c[1] +
+ 0.114 * color->c[2]);
+}
+
+void GfxCalRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
+ rgb->r = clip01(color->c[0]);
+ rgb->g = clip01(color->c[1]);
+ rgb->b = clip01(color->c[2]);
+}
+
+void GfxCalRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
+ double c, m, y, k;
+
+ c = clip01(1 - color->c[0]);
+ m = clip01(1 - color->c[1]);
+ y = clip01(1 - color->c[2]);
+ k = c;
+ if (m < k) {
+ k = m;
+ }
+ if (y < k) {
+ k = y;
+ }
+ cmyk->c = c - k;
+ cmyk->m = m - k;
+ cmyk->y = y - k;
+ cmyk->k = k;
+}
+
+//------------------------------------------------------------------------
+// GfxDeviceCMYKColorSpace
+//------------------------------------------------------------------------
+
+GfxDeviceCMYKColorSpace::GfxDeviceCMYKColorSpace() {
+}
+
+GfxDeviceCMYKColorSpace::~GfxDeviceCMYKColorSpace() {
+}
+
+GfxColorSpace *GfxDeviceCMYKColorSpace::copy() {
+ return new GfxDeviceCMYKColorSpace();
+}
+
+void GfxDeviceCMYKColorSpace::getGray(GfxColor *color, double *gray) {
+ *gray = clip01(1 - color->c[3]
+ - 0.299 * color->c[0]
+ - 0.587 * color->c[1]
+ - 0.114 * color->c[2]);
+}
+
+void GfxDeviceCMYKColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
+ rgb->r = clip01(1 - (color->c[0] + color->c[3]));
+ rgb->g = clip01(1 - (color->c[1] + color->c[3]));
+ rgb->b = clip01(1 - (color->c[2] + color->c[3]));
+}
+
+void GfxDeviceCMYKColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
+ cmyk->c = clip01(color->c[0]);
+ cmyk->m = clip01(color->c[1]);
+ cmyk->y = clip01(color->c[2]);
+ cmyk->k = clip01(color->c[3]);
+}
+
+//------------------------------------------------------------------------
+// GfxLabColorSpace
+//------------------------------------------------------------------------
+
+// This is the inverse of MatrixLMN in Example 4.10 from the PostScript
+// Language Reference, Third Edition.
+static double xyzrgb[3][3] = {
+ { 3.240449, -1.537136, -0.498531 },
+ { -0.969265, 1.876011, 0.041556 },
+ { 0.055643, -0.204026, 1.057229 }
+};
+
+GfxLabColorSpace::GfxLabColorSpace() {
+ whiteX = whiteY = whiteZ = 1;
+ blackX = blackY = blackZ = 0;
+ aMin = bMin = -100;
+ aMax = bMax = 100;
+}
+
+GfxLabColorSpace::~GfxLabColorSpace() {
+}
+
+GfxColorSpace *GfxLabColorSpace::copy() {
+ GfxLabColorSpace *cs;
+
+ cs = new GfxLabColorSpace();
+ cs->whiteX = whiteX;
+ cs->whiteY = whiteY;
+ cs->whiteZ = whiteZ;
+ cs->blackX = blackX;
+ cs->blackY = blackY;
+ cs->blackZ = blackZ;
+ cs->aMin = aMin;
+ cs->aMax = aMax;
+ cs->bMin = bMin;
+ cs->bMax = bMax;
+ cs->kr = kr;
+ cs->kg = kg;
+ cs->kb = kb;
+ return cs;
+}
+
+GfxColorSpace *GfxLabColorSpace::parse(Array *arr) {
+ GfxLabColorSpace *cs;
+ Object obj1, obj2, obj3;
+
+ arr->get(1, &obj1);
+ if (!obj1.isDict()) {
+ error(-1, "Bad Lab color space");
+ obj1.free();
+ return NULL;
+ }
+ cs = new GfxLabColorSpace();
+ if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
+ obj2.arrayGetLength() == 3) {
+ obj2.arrayGet(0, &obj3);
+ cs->whiteX = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(1, &obj3);
+ cs->whiteY = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(2, &obj3);
+ cs->whiteZ = obj3.getNum();
+ obj3.free();
+ }
+ obj2.free();
+ if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
+ obj2.arrayGetLength() == 3) {
+ obj2.arrayGet(0, &obj3);
+ cs->blackX = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(1, &obj3);
+ cs->blackY = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(2, &obj3);
+ cs->blackZ = obj3.getNum();
+ obj3.free();
+ }
+ obj2.free();
+ if (obj1.dictLookup("Range", &obj2)->isArray() &&
+ obj2.arrayGetLength() == 4) {
+ obj2.arrayGet(0, &obj3);
+ cs->aMin = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(1, &obj3);
+ cs->aMax = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(2, &obj3);
+ cs->bMin = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(3, &obj3);
+ cs->bMax = obj3.getNum();
+ obj3.free();
+ }
+ obj2.free();
+ obj1.free();
+
+ cs->kr = 1 / (xyzrgb[0][0] * cs->whiteX +
+ xyzrgb[0][1] * cs->whiteY +
+ xyzrgb[0][2] * cs->whiteZ);
+ cs->kg = 1 / (xyzrgb[1][0] * cs->whiteX +
+ xyzrgb[1][1] * cs->whiteY +
+ xyzrgb[1][2] * cs->whiteZ);
+ cs->kb = 1 / (xyzrgb[2][0] * cs->whiteX +
+ xyzrgb[2][1] * cs->whiteY +
+ xyzrgb[2][2] * cs->whiteZ);
+
+ return cs;
+}
+
+void GfxLabColorSpace::getGray(GfxColor *color, double *gray) {
+ GfxRGB rgb;
+
+ getRGB(color, &rgb);
+ *gray = clip01(0.299 * rgb.r +
+ 0.587 * rgb.g +
+ 0.114 * rgb.b);
+}
+
+void GfxLabColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
+ double X, Y, Z;
+ double t1, t2;
+ double r, g, b;
+
+ // convert L*a*b* to CIE 1931 XYZ color space
+ t1 = (color->c[0] + 16) / 116;
+ t2 = t1 + color->c[1] / 500;
+ if (t2 >= (6.0 / 29.0)) {
+ X = t2 * t2 * t2;
+ } else {
+ X = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
+ }
+ X *= whiteX;
+ if (t1 >= (6.0 / 29.0)) {
+ Y = t1 * t1 * t1;
+ } else {
+ Y = (108.0 / 841.0) * (t1 - (4.0 / 29.0));
+ }
+ Y *= whiteY;
+ t2 = t1 - color->c[2] / 200;
+ if (t2 >= (6.0 / 29.0)) {
+ Z = t2 * t2 * t2;
+ } else {
+ Z = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
+ }
+ Z *= whiteZ;
+
+ // convert XYZ to RGB, including gamut mapping and gamma correction
+ r = xyzrgb[0][0] * X + xyzrgb[0][1] * Y + xyzrgb[0][2] * Z;
+ g = xyzrgb[1][0] * X + xyzrgb[1][1] * Y + xyzrgb[1][2] * Z;
+ b = xyzrgb[2][0] * X + xyzrgb[2][1] * Y + xyzrgb[2][2] * Z;
+ rgb->r = pow(clip01(r * kr), 0.5);
+ rgb->g = pow(clip01(g * kg), 0.5);
+ rgb->b = pow(clip01(b * kb), 0.5);
+}
+
+void GfxLabColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
+ GfxRGB rgb;
+ double c, m, y, k;
+
+ getRGB(color, &rgb);
+ c = clip01(1 - rgb.r);
+ m = clip01(1 - rgb.g);
+ y = clip01(1 - rgb.b);
+ k = c;
+ if (m < k) {
+ k = m;
+ }
+ if (y < k) {
+ k = y;
+ }
+ cmyk->c = c - k;
+ cmyk->m = m - k;
+ cmyk->y = y - k;
+ cmyk->k = k;
+}
+
+void GfxLabColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
+ int maxImgPixel) {
+ decodeLow[0] = 0;
+ decodeRange[0] = 100;
+ decodeLow[1] = aMin;
+ decodeRange[1] = aMax - aMin;
+ decodeLow[2] = bMin;
+ decodeRange[2] = bMax - bMin;
+}
+
+//------------------------------------------------------------------------
+// GfxICCBasedColorSpace
+//------------------------------------------------------------------------
+
+GfxICCBasedColorSpace::GfxICCBasedColorSpace(int nCompsA, GfxColorSpace *altA,
+ Ref *iccProfileStreamA) {
+ nComps = nCompsA;
+ alt = altA;
+ iccProfileStream = *iccProfileStreamA;
+ rangeMin[0] = rangeMin[1] = rangeMin[2] = rangeMin[3] = 0;
+ rangeMax[0] = rangeMax[1] = rangeMax[2] = rangeMax[3] = 1;
+}
+
+GfxICCBasedColorSpace::~GfxICCBasedColorSpace() {
+ delete alt;
+}
+
+GfxColorSpace *GfxICCBasedColorSpace::copy() {
+ GfxICCBasedColorSpace *cs;
+ int i;
+
+ cs = new GfxICCBasedColorSpace(nComps, alt->copy(), &iccProfileStream);
+ for (i = 0; i < 4; ++i) {
+ cs->rangeMin[i] = rangeMin[i];
+ cs->rangeMax[i] = rangeMax[i];
+ }
+ return cs;
+}
+
+GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr) {
+ GfxICCBasedColorSpace *cs;
+ Ref iccProfileStreamA;
+ int nCompsA;
+ GfxColorSpace *altA;
+ Dict *dict;
+ Object obj1, obj2, obj3;
+ int i;
+
+ arr->getNF(1, &obj1);
+ if (obj1.isRef()) {
+ iccProfileStreamA = obj1.getRef();
+ } else {
+ iccProfileStreamA.num = 0;
+ iccProfileStreamA.gen = 0;
+ }
+ obj1.free();
+ arr->get(1, &obj1);
+ if (!obj1.isStream()) {
+ error(-1, "Bad ICCBased color space (stream)");
+ obj1.free();
+ return NULL;
+ }
+ dict = obj1.streamGetDict();
+ if (!dict->lookup("N", &obj2)->isInt()) {
+ error(-1, "Bad ICCBased color space (N)");
+ obj2.free();
+ obj1.free();
+ return NULL;
+ }
+ nCompsA = obj2.getInt();
+ obj2.free();
+ if (dict->lookup("Alternate", &obj2)->isNull() ||
+ !(altA = GfxColorSpace::parse(&obj2))) {
+ switch (nCompsA) {
+ case 1:
+ altA = new GfxDeviceGrayColorSpace();
+ break;
+ case 3:
+ altA = new GfxDeviceRGBColorSpace();
+ break;
+ case 4:
+ altA = new GfxDeviceCMYKColorSpace();
+ break;
+ default:
+ error(-1, "Bad ICCBased color space - invalid N");
+ obj2.free();
+ obj1.free();
+ return NULL;
+ }
+ }
+ obj2.free();
+ cs = new GfxICCBasedColorSpace(nCompsA, altA, &iccProfileStreamA);
+ if (dict->lookup("Range", &obj2)->isArray() &&
+ obj2.arrayGetLength() == 2 * nCompsA) {
+ for (i = 0; i < nCompsA; ++i) {
+ obj2.arrayGet(2*i, &obj3);
+ cs->rangeMin[i] = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(2*i+1, &obj3);
+ cs->rangeMax[i] = obj3.getNum();
+ obj3.free();
+ }
+ }
+ obj2.free();
+ obj1.free();
+ return cs;
+}
+
+void GfxICCBasedColorSpace::getGray(GfxColor *color, double *gray) {
+ alt->getGray(color, gray);
+}
+
+void GfxICCBasedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
+ alt->getRGB(color, rgb);
+}
+
+void GfxICCBasedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
+ alt->getCMYK(color, cmyk);
+}
+
+void GfxICCBasedColorSpace::getDefaultRanges(double *decodeLow,
+ double *decodeRange,
+ int maxImgPixel) {
+ int i;
+
+ for (i = 0; i < nComps; ++i) {
+ decodeLow[i] = rangeMin[i];
+ decodeRange[i] = rangeMax[i] - rangeMin[i];
+ }
+}
+
+//------------------------------------------------------------------------
+// GfxIndexedColorSpace
+//------------------------------------------------------------------------
+
+GfxIndexedColorSpace::GfxIndexedColorSpace(GfxColorSpace *baseA,
+ int indexHighA) {
+ base = baseA;
+ indexHigh = indexHighA;
+ lookup = (Guchar *)gmalloc((indexHigh + 1) * base->getNComps() *
+ sizeof(Guchar));
+}
+
+GfxIndexedColorSpace::~GfxIndexedColorSpace() {
+ delete base;
+ gfree(lookup);
+}
+
+GfxColorSpace *GfxIndexedColorSpace::copy() {
+ GfxIndexedColorSpace *cs;
+
+ cs = new GfxIndexedColorSpace(base->copy(), indexHigh);
+ memcpy(cs->lookup, lookup,
+ (indexHigh + 1) * base->getNComps() * sizeof(Guchar));
+ return cs;
+}
+
+GfxColorSpace *GfxIndexedColorSpace::parse(Array *arr) {
+ GfxIndexedColorSpace *cs;
+ GfxColorSpace *baseA;
+ int indexHighA;
+ Object obj1;
+ int x;
+ char *s;
+ int n, i, j;
+
+ if (arr->getLength() != 4) {
+ error(-1, "Bad Indexed color space");
+ goto err1;
+ }
+ arr->get(1, &obj1);
+ if (!(baseA = GfxColorSpace::parse(&obj1))) {
+ error(-1, "Bad Indexed color space (base color space)");
+ goto err2;
+ }
+ obj1.free();
+ if (!arr->get(2, &obj1)->isInt()) {
+ error(-1, "Bad Indexed color space (hival)");
+ goto err2;
+ }
+ indexHighA = obj1.getInt();
+ obj1.free();
+ cs = new GfxIndexedColorSpace(baseA, indexHighA);
+ arr->get(3, &obj1);
+ n = baseA->getNComps();
+ if (obj1.isStream()) {
+ obj1.streamReset();
+ for (i = 0; i <= indexHighA; ++i) {
+ for (j = 0; j < n; ++j) {
+ if ((x = obj1.streamGetChar()) == EOF) {
+ error(-1, "Bad Indexed color space (lookup table stream too short)");
+ goto err3;
+ }
+ cs->lookup[i*n + j] = (Guchar)x;
+ }
+ }
+ obj1.streamClose();
+ } else if (obj1.isString()) {
+ if (obj1.getString()->getLength() < (indexHighA + 1) * n) {
+ error(-1, "Bad Indexed color space (lookup table string too short)");
+ goto err3;
+ }
+ s = obj1.getString()->getCString();
+ for (i = 0; i <= indexHighA; ++i) {
+ for (j = 0; j < n; ++j) {
+ cs->lookup[i*n + j] = (Guchar)*s++;
+ }
+ }
+ } else {
+ error(-1, "Bad Indexed color space (lookup table)");
+ goto err3;
+ }
+ obj1.free();
+ return cs;
+
+ err3:
+ delete cs;
+ err2:
+ obj1.free();
+ err1:
+ return NULL;
+}
+
+void GfxIndexedColorSpace::getGray(GfxColor *color, double *gray) {
+ Guchar *p;
+ GfxColor color2;
+ int n, i;
+
+ n = base->getNComps();
+ p = &lookup[(int)(color->c[0] + 0.5) * n];
+ for (i = 0; i < n; ++i) {
+ color2.c[i] = p[i] / 255.0;
+ }
+ base->getGray(&color2, gray);
+}
+
+void GfxIndexedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
+ Guchar *p;
+ GfxColor color2;
+ int n, i;
+
+ n = base->getNComps();
+ p = &lookup[(int)(color->c[0] + 0.5) * n];
+ for (i = 0; i < n; ++i) {
+ color2.c[i] = p[i] / 255.0;
+ }
+ base->getRGB(&color2, rgb);
+}
+
+void GfxIndexedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
+ Guchar *p;
+ GfxColor color2;
+ int n, i;
+
+ n = base->getNComps();
+ p = &lookup[(int)(color->c[0] + 0.5) * n];
+ for (i = 0; i < n; ++i) {
+ color2.c[i] = p[i] / 255.0;
+ }
+ base->getCMYK(&color2, cmyk);
+}
+
+void GfxIndexedColorSpace::getDefaultRanges(double *decodeLow,
+ double *decodeRange,
+ int maxImgPixel) {
+ decodeLow[0] = 0;
+ decodeRange[0] = maxImgPixel;
+}
+
+//------------------------------------------------------------------------
+// GfxSeparationColorSpace
+//------------------------------------------------------------------------
+
+GfxSeparationColorSpace::GfxSeparationColorSpace(GString *nameA,
+ GfxColorSpace *altA,
+ Function *funcA) {
+ name = nameA;
+ alt = altA;
+ func = funcA;
+}
+
+GfxSeparationColorSpace::~GfxSeparationColorSpace() {
+ delete name;
+ delete alt;
+ delete func;
+}
+
+GfxColorSpace *GfxSeparationColorSpace::copy() {
+ return new GfxSeparationColorSpace(name->copy(), alt->copy(), func->copy());
+}
+
+//~ handle the 'All' and 'None' colorants
+GfxColorSpace *GfxSeparationColorSpace::parse(Array *arr) {
+ GfxSeparationColorSpace *cs;
+ GString *nameA;
+ GfxColorSpace *altA;
+ Function *funcA;
+ Object obj1;
+
+ if (arr->getLength() != 4) {
+ error(-1, "Bad Separation color space");
+ goto err1;
+ }
+ if (!arr->get(1, &obj1)->isName()) {
+ error(-1, "Bad Separation color space (name)");
+ goto err2;
+ }
+ nameA = new GString(obj1.getName());
+ obj1.free();
+ arr->get(2, &obj1);
+ if (!(altA = GfxColorSpace::parse(&obj1))) {
+ error(-1, "Bad Separation color space (alternate color space)");
+ goto err3;
+ }
+ obj1.free();
+ arr->get(3, &obj1);
+ if (!(funcA = Function::parse(&obj1))) {
+ goto err4;
+ }
+ if (!funcA->isOk()) {
+ goto err5;
+ }
+ obj1.free();
+ cs = new GfxSeparationColorSpace(nameA, altA, funcA);
+ return cs;
+
+ err5:
+ delete funcA;
+ err4:
+ delete altA;
+ err3:
+ delete nameA;
+ err2:
+ obj1.free();
+ err1:
+ return NULL;
+}
+
+void GfxSeparationColorSpace::getGray(GfxColor *color, double *gray) {
+ GfxColor color2;
+
+ func->transform(color->c, color2.c);
+ alt->getGray(&color2, gray);
+}
+
+void GfxSeparationColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
+ GfxColor color2;
+
+ func->transform(color->c, color2.c);
+ alt->getRGB(&color2, rgb);
+}
+
+void GfxSeparationColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
+ GfxColor color2;
+
+ func->transform(color->c, color2.c);
+ alt->getCMYK(&color2, cmyk);
+}
+
+//------------------------------------------------------------------------
+// GfxDeviceNColorSpace
+//------------------------------------------------------------------------
+
+GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA,
+ GfxColorSpace *altA,
+ Function *funcA) {
+ nComps = nCompsA;
+ alt = altA;
+ func = funcA;
+}
+
+GfxDeviceNColorSpace::~GfxDeviceNColorSpace() {
+ int i;
+
+ for (i = 0; i < nComps; ++i) {
+ delete names[i];
+ }
+ delete alt;
+ delete func;
+}
+
+GfxColorSpace *GfxDeviceNColorSpace::copy() {
+ GfxDeviceNColorSpace *cs;
+ int i;
+
+ cs = new GfxDeviceNColorSpace(nComps, alt->copy(), func->copy());
+ for (i = 0; i < nComps; ++i) {
+ cs->names[i] = names[i]->copy();
+ }
+ return cs;
+}
+
+//~ handle the 'None' colorant
+GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr) {
+ GfxDeviceNColorSpace *cs;
+ int nCompsA;
+ GString *namesA[gfxColorMaxComps];
+ GfxColorSpace *altA;
+ Function *funcA;
+ Object obj1, obj2;
+ int i;
+
+ if (arr->getLength() != 4 && arr->getLength() != 5) {
+ error(-1, "Bad DeviceN color space");
+ goto err1;
+ }
+ if (!arr->get(1, &obj1)->isArray()) {
+ error(-1, "Bad DeviceN color space (names)");
+ goto err2;
+ }
+ nCompsA = obj1.arrayGetLength();
+ for (i = 0; i < nCompsA; ++i) {
+ if (!obj1.arrayGet(i, &obj2)->isName()) {
+ error(-1, "Bad DeviceN color space (names)");
+ obj2.free();
+ goto err2;
+ }
+ namesA[i] = new GString(obj2.getName());
+ obj2.free();
+ }
+ obj1.free();
+ arr->get(2, &obj1);
+ if (!(altA = GfxColorSpace::parse(&obj1))) {
+ error(-1, "Bad DeviceN color space (alternate color space)");
+ goto err3;
+ }
+ obj1.free();
+ arr->get(3, &obj1);
+ if (!(funcA = Function::parse(&obj1))) {
+ goto err4;
+ }
+ if (!funcA->isOk()) {
+ goto err5;
+ }
+ obj1.free();
+ cs = new GfxDeviceNColorSpace(nCompsA, altA, funcA);
+ for (i = 0; i < nCompsA; ++i) {
+ cs->names[i] = namesA[i];
+ }
+ return cs;
+
+ err5:
+ delete funcA;
+ err4:
+ delete altA;
+ err3:
+ for (i = 0; i < nCompsA; ++i) {
+ delete namesA[i];
+ }
+ err2:
+ obj1.free();
+ err1:
+ return NULL;
+}
+
+void GfxDeviceNColorSpace::getGray(GfxColor *color, double *gray) {
+ GfxColor color2;
+
+ func->transform(color->c, color2.c);
+ alt->getGray(&color2, gray);
+}
+
+void GfxDeviceNColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
+ GfxColor color2;
+
+ func->transform(color->c, color2.c);
+ alt->getRGB(&color2, rgb);
+}
+
+void GfxDeviceNColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
+ GfxColor color2;
+
+ func->transform(color->c, color2.c);
+ alt->getCMYK(&color2, cmyk);
+}
+
+//------------------------------------------------------------------------
+// GfxPatternColorSpace
+//------------------------------------------------------------------------
+
+GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace *underA) {
+ under = underA;
+}
+
+GfxPatternColorSpace::~GfxPatternColorSpace() {
+ if (under) {
+ delete under;
+ }
+}
+
+GfxColorSpace *GfxPatternColorSpace::copy() {
+ return new GfxPatternColorSpace(under ? under->copy() :
+ (GfxColorSpace *)NULL);
+}
+
+GfxColorSpace *GfxPatternColorSpace::parse(Array *arr) {
+ GfxPatternColorSpace *cs;
+ GfxColorSpace *underA;
+ Object obj1;
+
+ if (arr->getLength() != 1 && arr->getLength() != 2) {
+ error(-1, "Bad Pattern color space");
+ return NULL;
+ }
+ underA = NULL;
+ if (arr->getLength() == 2) {
+ arr->get(1, &obj1);
+ if (!(underA = GfxColorSpace::parse(&obj1))) {
+ error(-1, "Bad Pattern color space (underlying color space)");
+ obj1.free();
+ return NULL;
+ }
+ obj1.free();
+ }
+ cs = new GfxPatternColorSpace(underA);
+ return cs;
+}
+
+void GfxPatternColorSpace::getGray(GfxColor *color, double *gray) {
+ *gray = 0;
+}
+
+void GfxPatternColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
+ rgb->r = rgb->g = rgb->b = 0;
+}
+
+void GfxPatternColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
+ cmyk->c = cmyk->m = cmyk->y = 0;
+ cmyk->k = 1;
+}
+
+//------------------------------------------------------------------------
+// Pattern
+//------------------------------------------------------------------------
+
+GfxPattern::GfxPattern(int typeA) {
+ type = typeA;
+}
+
+GfxPattern::~GfxPattern() {
+}
+
+GfxPattern *GfxPattern::parse(Object *obj) {
+ GfxPattern *pattern;
+ Dict *dict;
+ Object obj1;
+
+ pattern = NULL;
+ if (obj->isStream()) {
+ dict = obj->streamGetDict();
+ dict->lookup("PatternType", &obj1);
+ if (obj1.isInt() && obj1.getInt() == 1) {
+ pattern = new GfxTilingPattern(dict, obj);
+ }
+ obj1.free();
+ }
+ return pattern;
+}
+
+//------------------------------------------------------------------------
+// GfxTilingPattern
+//------------------------------------------------------------------------
+
+GfxTilingPattern::GfxTilingPattern(Dict *streamDict, Object *stream):
+ GfxPattern(1)
+{
+ Object obj1, obj2;
+ int i;
+
+ if (streamDict->lookup("PaintType", &obj1)->isInt()) {
+ paintType = obj1.getInt();
+ } else {
+ paintType = 1;
+ error(-1, "Invalid or missing PaintType in pattern");
+ }
+ obj1.free();
+ if (streamDict->lookup("TilingType", &obj1)->isInt()) {
+ tilingType = obj1.getInt();
+ } else {
+ tilingType = 1;
+ error(-1, "Invalid or missing TilingType in pattern");
+ }
+ obj1.free();
+ bbox[0] = bbox[1] = 0;
+ bbox[2] = bbox[3] = 1;
+ if (streamDict->lookup("BBox", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 4) {
+ for (i = 0; i < 4; ++i) {
+ if (obj1.arrayGet(i, &obj2)->isNum()) {
+ bbox[i] = obj2.getNum();
+ }
+ obj2.free();
+ }
+ } else {
+ error(-1, "Invalid or missing BBox in pattern");
+ }
+ obj1.free();
+ if (streamDict->lookup("XStep", &obj1)->isNum()) {
+ xStep = obj1.getNum();
+ } else {
+ xStep = 1;
+ error(-1, "Invalid or missing XStep in pattern");
+ }
+ obj1.free();
+ if (streamDict->lookup("YStep", &obj1)->isNum()) {
+ yStep = obj1.getNum();
+ } else {
+ yStep = 1;
+ error(-1, "Invalid or missing YStep in pattern");
+ }
+ obj1.free();
+ if (!streamDict->lookup("Resources", &resDict)->isDict()) {
+ resDict.free();
+ resDict.initNull();
+ error(-1, "Invalid or missing Resources in pattern");
+ }
+ matrix[0] = 1; matrix[1] = 0;
+ matrix[2] = 0; matrix[3] = 1;
+ matrix[4] = 0; matrix[5] = 0;
+ if (streamDict->lookup("Matrix", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 6) {
+ for (i = 0; i < 6; ++i) {
+ if (obj1.arrayGet(i, &obj2)->isNum()) {
+ matrix[i] = obj2.getNum();
+ }
+ obj2.free();
+ }
+ }
+ obj1.free();
+ stream->copy(&contentStream);
+}
+
+GfxTilingPattern::~GfxTilingPattern() {
+ resDict.free();
+ contentStream.free();
+}
+
+GfxPattern *GfxTilingPattern::copy() {
+ return new GfxTilingPattern(this);
+}
+
+GfxTilingPattern::GfxTilingPattern(GfxTilingPattern *pat):
+ GfxPattern(1)
+{
+ memcpy(this, pat, sizeof(GfxTilingPattern));
+ pat->resDict.copy(&resDict);
+ pat->contentStream.copy(&contentStream);
+}
+
+//------------------------------------------------------------------------
+// GfxShading
+//------------------------------------------------------------------------
+
+GfxShading::GfxShading() {
+}
+
+GfxShading::~GfxShading() {
+ delete colorSpace;
+}
+
+GfxShading *GfxShading::parse(Object *obj) {
+ GfxShading *shading;
+ int typeA;
+ GfxColorSpace *colorSpaceA;
+ GfxColor backgroundA;
+ GBool hasBackgroundA;
+ double xMinA, yMinA, xMaxA, yMaxA;
+ GBool hasBBoxA;
+ Object obj1, obj2;
+ int i;
+
+ shading = NULL;
+ if (obj->isDict()) {
+
+ if (!obj->dictLookup("ShadingType", &obj1)->isInt()) {
+ error(-1, "Invalid ShadingType in shading dictionary");
+ obj1.free();
+ goto err1;
+ }
+ typeA = obj1.getInt();
+ obj1.free();
+ if (typeA != 2) {
+ error(-1, "Unimplemented shading type %d", typeA);
+ goto err1;
+ }
+
+ obj->dictLookup("ColorSpace", &obj1);
+ if (!(colorSpaceA = GfxColorSpace::parse(&obj1))) {
+ error(-1, "Bad color space in shading dictionary");
+ obj1.free();
+ goto err1;
+ }
+ obj1.free();
+
+ for (i = 0; i < gfxColorMaxComps; ++i) {
+ backgroundA.c[i] = 0;
+ }
+ hasBackgroundA = gFalse;
+ if (obj->dictLookup("Background", &obj1)->isArray()) {
+ if (obj1.arrayGetLength() == colorSpaceA->getNComps()) {
+ hasBackgroundA = gTrue;
+ for (i = 0; i < colorSpaceA->getNComps(); ++i) {
+ backgroundA.c[i] = obj1.arrayGet(i, &obj2)->getNum();
+ obj2.free();
+ }
+ } else {
+ error(-1, "Bad Background in shading dictionary");
+ }
+ }
+ obj1.free();
+
+ xMinA = yMinA = xMaxA = yMaxA = 0;
+ hasBBoxA = gFalse;
+ if (obj->dictLookup("BBox", &obj1)->isArray()) {
+ if (obj1.arrayGetLength() == 4) {
+ hasBBoxA = gTrue;
+ xMinA = obj1.arrayGet(0, &obj2)->getNum();
+ obj2.free();
+ yMinA = obj1.arrayGet(1, &obj2)->getNum();
+ obj2.free();
+ xMaxA = obj1.arrayGet(2, &obj2)->getNum();
+ obj2.free();
+ yMaxA = obj1.arrayGet(3, &obj2)->getNum();
+ obj2.free();
+ } else {
+ error(-1, "Bad BBox in shading dictionary");
+ }
+ }
+ obj1.free();
+
+ shading = GfxAxialShading::parse(obj->getDict());
+
+ if (shading) {
+ shading->type = typeA;
+ shading->colorSpace = colorSpaceA;
+ shading->background = backgroundA;
+ shading->hasBackground = hasBackgroundA;
+ shading->xMin = xMinA;
+ shading->yMin = yMinA;
+ shading->xMax = xMaxA;
+ shading->yMax = yMaxA;
+ shading->hasBBox = hasBBoxA;
+ }
+ }
+
+ return shading;
+
+ err1:
+ return NULL;
+}
+
+//------------------------------------------------------------------------
+// GfxAxialShading
+//------------------------------------------------------------------------
+
+GfxAxialShading::GfxAxialShading(double x0A, double y0A,
+ double x1A, double y1A,
+ double t0A, double t1A,
+ Function **funcsA, int nFuncsA,
+ GBool extend0A, GBool extend1A) {
+ int i;
+
+ x0 = x0A;
+ y0 = y0A;
+ x1 = x1A;
+ y1 = y1A;
+ t0 = t0A;
+ t1 = t1A;
+ nFuncs = nFuncsA;
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i] = funcsA[i];
+ }
+ extend0 = extend0A;
+ extend1 = extend1A;
+}
+
+GfxAxialShading::~GfxAxialShading() {
+ int i;
+
+ for (i = 0; i < nFuncs; ++i) {
+ delete funcs[i];
+ }
+}
+
+GfxAxialShading *GfxAxialShading::parse(Dict *dict) {
+ double x0A, y0A, x1A, y1A;
+ double t0A, t1A;
+ Function *funcsA[gfxColorMaxComps];
+ int nFuncsA;
+ GBool extend0A, extend1A;
+ Object obj1, obj2;
+ int i;
+
+ x0A = y0A = x1A = y1A = 0;
+ if (dict->lookup("Coords", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 4) {
+ x0A = obj1.arrayGet(0, &obj2)->getNum();
+ obj2.free();
+ y0A = obj1.arrayGet(1, &obj2)->getNum();
+ obj2.free();
+ x1A = obj1.arrayGet(2, &obj2)->getNum();
+ obj2.free();
+ y1A = obj1.arrayGet(3, &obj2)->getNum();
+ obj2.free();
+ } else {
+ error(-1, "Missing or invalid Coords in shading dictionary");
+ goto err1;
+ }
+ obj1.free();
+
+ t0A = 0;
+ t1A = 1;
+ if (dict->lookup("Domain", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 2) {
+ t0A = obj1.arrayGet(0, &obj2)->getNum();
+ obj2.free();
+ t1A = obj1.arrayGet(1, &obj2)->getNum();
+ obj2.free();
+ }
+ obj1.free();
+
+ dict->lookup("Function", &obj1);
+ if (obj1.isArray()) {
+ nFuncsA = obj1.arrayGetLength();
+ for (i = 0; i < nFuncsA; ++i) {
+ obj1.arrayGet(i, &obj2);
+ if (!(funcsA[i] = Function::parse(&obj2))) {
+ obj1.free();
+ obj2.free();
+ goto err1;
+ }
+ obj2.free();
+ }
+ } else {
+ nFuncsA = 1;
+ if (!(funcsA[0] = Function::parse(&obj1))) {
+ obj1.free();
+ goto err1;
+ }
+ }
+ obj1.free();
+ for (i = 0; i < nFuncsA; ++i) {
+ if (!funcsA[i]->isOk()) {
+ goto err2;
+ }
+ }
+
+ extend0A = extend1A = gFalse;
+ if (dict->lookup("Extend", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 2) {
+ extend0A = obj1.arrayGet(0, &obj2)->getBool();
+ obj2.free();
+ extend1A = obj1.arrayGet(1, &obj2)->getBool();
+ obj2.free();
+ }
+ obj1.free();
+
+ return new GfxAxialShading(x0A, y0A, x1A, y1A, t0A, t1A,
+ funcsA, nFuncsA, extend0A, extend1A);
+
+ err2:
+ for (i = 0; i < nFuncsA; ++i) {
+ delete funcsA[i];
+ }
+ err1:
+ return NULL;
+}
+
+void GfxAxialShading::getColor(double t, GfxColor *color) {
+ int i;
+
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i]->transform(&t, &color->c[i]);
+ }
+}
+
+//------------------------------------------------------------------------
+// GfxImageColorMap
+//------------------------------------------------------------------------
+
+GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode,
+ GfxColorSpace *colorSpaceA) {
+ GfxIndexedColorSpace *indexedCS;
+ GfxSeparationColorSpace *sepCS;
+ int maxPixel, indexHigh;
+ Guchar *lookup2;
+ Function *sepFunc;
+ Object obj;
+ double x[gfxColorMaxComps];
+ double y[gfxColorMaxComps];
+ int i, j, k;
+
+ ok = gTrue;
+
+ // bits per component and color space
+ bits = bitsA;
+ maxPixel = (1 << bits) - 1;
+ colorSpace = colorSpaceA;
+
+ // get decode map
+ if (decode->isNull()) {
+ nComps = colorSpace->getNComps();
+ colorSpace->getDefaultRanges(decodeLow, decodeRange, maxPixel);
+ } else if (decode->isArray()) {
+ nComps = decode->arrayGetLength() / 2;
+ if (nComps != colorSpace->getNComps()) {
+ goto err1;
+ }
+ for (i = 0; i < nComps; ++i) {
+ decode->arrayGet(2*i, &obj);
+ if (!obj.isNum()) {
+ goto err2;
+ }
+ decodeLow[i] = obj.getNum();
+ obj.free();
+ decode->arrayGet(2*i+1, &obj);
+ if (!obj.isNum()) {
+ goto err2;
+ }
+ decodeRange[i] = obj.getNum() - decodeLow[i];
+ obj.free();
+ }
+ } else {
+ goto err1;
+ }
+
+#if 0 //~
+ // handle the case where fewer than 2^n palette entries of an n-bit
+ // indexed color space are populated (this happens, e.g., in files
+ // optimized by Distiller)
+ if (colorSpace->getMode() == csIndexed) {
+ i = ((GfxIndexedColorSpace *)colorSpace)->getIndexHigh();
+ if (i < maxPixel) {
+ maxPixel = i;
+ }
+ }
+#endif
+
+ // Construct a lookup table -- this stores pre-computed decoded
+ // values for each component, i.e., the result of applying the
+ // decode mapping to each possible image pixel component value.
+ //
+ // Optimization: for Indexed and Separation color spaces (which have
+ // only one component), we store color values in the lookup table
+ // rather than component values.
+ colorSpace2 = NULL;
+ nComps2 = 0;
+ if (colorSpace->getMode() == csIndexed) {
+ // Note that indexHigh may not be the same as maxPixel --
+ // Distiller will remove unused palette entries, resulting in
+ // indexHigh < maxPixel.
+ indexedCS = (GfxIndexedColorSpace *)colorSpace;
+ colorSpace2 = indexedCS->getBase();
+ indexHigh = indexedCS->getIndexHigh();
+ nComps2 = colorSpace2->getNComps();
+ lookup = (double *)gmalloc((indexHigh + 1) * nComps2 * sizeof(double));
+ lookup2 = indexedCS->getLookup();
+ for (i = 0; i <= indexHigh; ++i) {
+ j = (int)(decodeLow[0] +(i * decodeRange[0]) / maxPixel + 0.5);
+ for (k = 0; k < nComps2; ++k) {
+ lookup[i*nComps2 + k] = lookup2[i*nComps2 + k] / 255.0;
+ }
+ }
+ } else if (colorSpace->getMode() == csSeparation) {
+ sepCS = (GfxSeparationColorSpace *)colorSpace;
+ colorSpace2 = sepCS->getAlt();
+ nComps2 = colorSpace2->getNComps();
+ lookup = (double *)gmalloc((maxPixel + 1) * nComps2 * sizeof(double));
+ sepFunc = sepCS->getFunc();
+ for (i = 0; i <= maxPixel; ++i) {
+ x[0] = decodeLow[0] + (i * decodeRange[0]) / maxPixel;
+ sepFunc->transform(x, y);
+ for (k = 0; k < nComps2; ++k) {
+ lookup[i*nComps2 + k] = y[k];
+ }
+ }
+ } else {
+ lookup = (double *)gmalloc((maxPixel + 1) * nComps * sizeof(double));
+ for (i = 0; i <= maxPixel; ++i) {
+ for (k = 0; k < nComps; ++k) {
+ lookup[i*nComps + k] = decodeLow[k] +
+ (i * decodeRange[k]) / maxPixel;
+ }
+ }
+ }
+
+ return;
+
+ err2:
+ obj.free();
+ err1:
+ ok = gFalse;
+}
+
+GfxImageColorMap::~GfxImageColorMap() {
+ delete colorSpace;
+ gfree(lookup);
+}
+
+void GfxImageColorMap::getGray(Guchar *x, double *gray) {
+ GfxColor color;
+ double *p;
+ int i;
+
+ if (colorSpace2) {
+ p = &lookup[x[0] * nComps2];
+ for (i = 0; i < nComps2; ++i) {
+ color.c[i] = *p++;
+ }
+ colorSpace2->getGray(&color, gray);
+ } else {
+ for (i = 0; i < nComps; ++i) {
+ color.c[i] = lookup[x[i] * nComps + i];
+ }
+ colorSpace->getGray(&color, gray);
+ }
+}
+
+void GfxImageColorMap::getRGB(Guchar *x, GfxRGB *rgb) {
+ GfxColor color;
+ double *p;
+ int i;
+
+ if (colorSpace2) {
+ p = &lookup[x[0] * nComps2];
+ for (i = 0; i < nComps2; ++i) {
+ color.c[i] = *p++;
+ }
+ colorSpace2->getRGB(&color, rgb);
+ } else {
+ for (i = 0; i < nComps; ++i) {
+ color.c[i] = lookup[x[i] * nComps + i];
+ }
+ colorSpace->getRGB(&color, rgb);
+ }
+}
+
+void GfxImageColorMap::getCMYK(Guchar *x, GfxCMYK *cmyk) {
+ GfxColor color;
+ double *p;
+ int i;
+
+ if (colorSpace2) {
+ p = &lookup[x[0] * nComps2];
+ for (i = 0; i < nComps2; ++i) {
+ color.c[i] = *p++;
+ }
+ colorSpace2->getCMYK(&color, cmyk);
+ } else {
+ for (i = 0; i < nComps; ++i) {
+ color.c[i] = lookup[x[i] * nComps + i];
+ }
+ colorSpace->getCMYK(&color, cmyk);
+ }
+}
+
+//------------------------------------------------------------------------
+// GfxSubpath and GfxPath
+//------------------------------------------------------------------------
+
+GfxSubpath::GfxSubpath(double x1, double y1) {
+ size = 16;
+ x = (double *)gmalloc(size * sizeof(double));
+ y = (double *)gmalloc(size * sizeof(double));
+ curve = (GBool *)gmalloc(size * sizeof(GBool));
+ n = 1;
+ x[0] = x1;
+ y[0] = y1;
+ curve[0] = gFalse;
+ closed = gFalse;
+}
+
+GfxSubpath::~GfxSubpath() {
+ gfree(x);
+ gfree(y);
+ gfree(curve);
+}
+
+// Used for copy().
+GfxSubpath::GfxSubpath(GfxSubpath *subpath) {
+ size = subpath->size;
+ n = subpath->n;
+ x = (double *)gmalloc(size * sizeof(double));
+ y = (double *)gmalloc(size * sizeof(double));
+ curve = (GBool *)gmalloc(size * sizeof(GBool));
+ memcpy(x, subpath->x, n * sizeof(double));
+ memcpy(y, subpath->y, n * sizeof(double));
+ memcpy(curve, subpath->curve, n * sizeof(GBool));
+ closed = subpath->closed;
+}
+
+void GfxSubpath::lineTo(double x1, double y1) {
+ if (n >= size) {
+ size += 16;
+ x = (double *)grealloc(x, size * sizeof(double));
+ y = (double *)grealloc(y, size * sizeof(double));
+ curve = (GBool *)grealloc(curve, size * sizeof(GBool));
+ }
+ x[n] = x1;
+ y[n] = y1;
+ curve[n] = gFalse;
+ ++n;
+}
+
+void GfxSubpath::curveTo(double x1, double y1, double x2, double y2,
+ double x3, double y3) {
+ if (n+3 > size) {
+ size += 16;
+ x = (double *)grealloc(x, size * sizeof(double));
+ y = (double *)grealloc(y, size * sizeof(double));
+ curve = (GBool *)grealloc(curve, size * sizeof(GBool));
+ }
+ x[n] = x1;
+ y[n] = y1;
+ x[n+1] = x2;
+ y[n+1] = y2;
+ x[n+2] = x3;
+ y[n+2] = y3;
+ curve[n] = curve[n+1] = gTrue;
+ curve[n+2] = gFalse;
+ n += 3;
+}
+
+void GfxSubpath::close() {
+ if (x[n-1] != x[0] || y[n-1] != y[0]) {
+ lineTo(x[0], y[0]);
+ }
+ closed = gTrue;
+}
+
+GfxPath::GfxPath() {
+ justMoved = gFalse;
+ size = 16;
+ n = 0;
+ firstX = firstY = 0;
+ subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
+}
+
+GfxPath::~GfxPath() {
+ int i;
+
+ for (i = 0; i < n; ++i)
+ delete subpaths[i];
+ gfree(subpaths);
+}
+
+// Used for copy().
+GfxPath::GfxPath(GBool justMoved1, double firstX1, double firstY1,
+ GfxSubpath **subpaths1, int n1, int size1) {
+ int i;
+
+ justMoved = justMoved1;
+ firstX = firstX1;
+ firstY = firstY1;
+ size = size1;
+ n = n1;
+ subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
+ for (i = 0; i < n; ++i)
+ subpaths[i] = subpaths1[i]->copy();
+}
+
+void GfxPath::moveTo(double x, double y) {
+ justMoved = gTrue;
+ firstX = x;
+ firstY = y;
+}
+
+void GfxPath::lineTo(double x, double y) {
+ if (justMoved) {
+ if (n >= size) {
+ size += 16;
+ subpaths = (GfxSubpath **)
+ grealloc(subpaths, size * sizeof(GfxSubpath *));
+ }
+ subpaths[n] = new GfxSubpath(firstX, firstY);
+ ++n;
+ justMoved = gFalse;
+ }
+ subpaths[n-1]->lineTo(x, y);
+}
+
+void GfxPath::curveTo(double x1, double y1, double x2, double y2,
+ double x3, double y3) {
+ if (justMoved) {
+ if (n >= size) {
+ size += 16;
+ subpaths = (GfxSubpath **)
+ grealloc(subpaths, size * sizeof(GfxSubpath *));
+ }
+ subpaths[n] = new GfxSubpath(firstX, firstY);
+ ++n;
+ justMoved = gFalse;
+ }
+ subpaths[n-1]->curveTo(x1, y1, x2, y2, x3, y3);
+}
+
+
+//------------------------------------------------------------------------
+// GfxState
+//------------------------------------------------------------------------
+
+GfxState::GfxState(double dpi, PDFRectangle *pageBox, int rotate,
+ GBool upsideDown) {
+ double k;
+
+ px1 = pageBox->x1;
+ py1 = pageBox->y1;
+ px2 = pageBox->x2;
+ py2 = pageBox->y2;
+ k = dpi / 72.0;
+ if (rotate == 90) {
+ ctm[0] = 0;
+ ctm[1] = upsideDown ? k : -k;
+ ctm[2] = k;
+ ctm[3] = 0;
+ ctm[4] = -k * py1;
+ ctm[5] = k * (upsideDown ? -px1 : px2);
+ pageWidth = k * (py2 - py1);
+ pageHeight = k * (px2 - px1);
+ } else if (rotate == 180) {
+ ctm[0] = -k;
+ ctm[1] = 0;
+ ctm[2] = 0;
+ ctm[3] = upsideDown ? k : -k;
+ ctm[4] = k * px2;
+ ctm[5] = k * (upsideDown ? -py1 : py2);
+ pageWidth = k * (px2 - px1);
+ pageHeight = k * (py2 - py1);
+ } else if (rotate == 270) {
+ ctm[0] = 0;
+ ctm[1] = upsideDown ? -k : k;
+ ctm[2] = -k;
+ ctm[3] = 0;
+ ctm[4] = k * py2;
+ ctm[5] = k * (upsideDown ? px2 : -px1);
+ pageWidth = k * (py2 - py1);
+ pageHeight = k * (px2 - px1);
+ } else {
+ ctm[0] = k;
+ ctm[1] = 0;
+ ctm[2] = 0;
+ ctm[3] = upsideDown ? -k : k;
+ ctm[4] = -k * px1;
+ ctm[5] = k * (upsideDown ? py2 : -py1);
+ pageWidth = k * (px2 - px1);
+ pageHeight = k * (py2 - py1);
+ }
+
+ fillColorSpace = new GfxDeviceGrayColorSpace();
+ strokeColorSpace = new GfxDeviceGrayColorSpace();
+ fillColor.c[0] = 0;
+ strokeColor.c[0] = 0;
+ fillPattern = NULL;
+ strokePattern = NULL;
+ fillOpacity = 1;
+ strokeOpacity = 1;
+
+ lineWidth = 1;
+ lineDash = NULL;
+ lineDashLength = 0;
+ lineDashStart = 0;
+ flatness = 0;
+ lineJoin = 0;
+ lineCap = 0;
+ miterLimit = 10;
+
+ font = NULL;
+ fontSize = 0;
+ textMat[0] = 1; textMat[1] = 0;
+ textMat[2] = 0; textMat[3] = 1;
+ textMat[4] = 0; textMat[5] = 0;
+ charSpace = 0;
+ wordSpace = 0;
+ horizScaling = 1;
+ leading = 0;
+ rise = 0;
+ render = 0;
+
+ path = new GfxPath();
+ curX = curY = 0;
+ lineX = lineY = 0;
+
+ clipXMin = 0;
+ clipYMin = 0;
+ clipXMax = pageWidth;
+ clipYMax = pageHeight;
+
+ saved = NULL;
+}
+
+GfxState::~GfxState() {
+ if (fillColorSpace) {
+ delete fillColorSpace;
+ }
+ if (strokeColorSpace) {
+ delete strokeColorSpace;
+ }
+ if (fillPattern) {
+ delete fillPattern;
+ }
+ if (strokePattern) {
+ delete strokePattern;
+ }
+ gfree(lineDash);
+ delete path;
+ if (saved) {
+ delete saved;
+ }
+}
+
+// Used for copy();
+GfxState::GfxState(GfxState *state) {
+ memcpy(this, state, sizeof(GfxState));
+ if (fillColorSpace) {
+ fillColorSpace = state->fillColorSpace->copy();
+ }
+ if (strokeColorSpace) {
+ strokeColorSpace = state->strokeColorSpace->copy();
+ }
+ if (fillPattern) {
+ fillPattern = state->fillPattern->copy();
+ }
+ if (strokePattern) {
+ strokePattern = state->strokePattern->copy();
+ }
+ if (lineDashLength > 0) {
+ lineDash = (double *)gmalloc(lineDashLength * sizeof(double));
+ memcpy(lineDash, state->lineDash, lineDashLength * sizeof(double));
+ }
+ path = state->path->copy();
+ saved = NULL;
+}
+
+double GfxState::transformWidth(double w) {
+ double x, y;
+
+ x = ctm[0] + ctm[2];
+ y = ctm[1] + ctm[3];
+ return w * sqrt(0.5 * (x * x + y * y));
+}
+
+double GfxState::getTransformedFontSize() {
+ double x1, y1, x2, y2;
+
+ x1 = textMat[2] * fontSize;
+ y1 = textMat[3] * fontSize;
+ x2 = ctm[0] * x1 + ctm[2] * y1;
+ y2 = ctm[1] * x1 + ctm[3] * y1;
+ return sqrt(x2 * x2 + y2 * y2);
+}
+
+void GfxState::getFontTransMat(double *m11, double *m12,
+ double *m21, double *m22) {
+ *m11 = (textMat[0] * ctm[0] + textMat[1] * ctm[2]) * fontSize;
+ *m12 = (textMat[0] * ctm[1] + textMat[1] * ctm[3]) * fontSize;
+ *m21 = (textMat[2] * ctm[0] + textMat[3] * ctm[2]) * fontSize;
+ *m22 = (textMat[2] * ctm[1] + textMat[3] * ctm[3]) * fontSize;
+}
+
+void GfxState::setCTM(double a, double b, double c,
+ double d, double e, double f) {
+ ctm[0] = a;
+ ctm[1] = b;
+ ctm[2] = c;
+ ctm[3] = d;
+ ctm[4] = e;
+ ctm[5] = f;
+}
+
+void GfxState::concatCTM(double a, double b, double c,
+ double d, double e, double f) {
+ double a1 = ctm[0];
+ double b1 = ctm[1];
+ double c1 = ctm[2];
+ double d1 = ctm[3];
+
+ ctm[0] = a * a1 + b * c1;
+ ctm[1] = a * b1 + b * d1;
+ ctm[2] = c * a1 + d * c1;
+ ctm[3] = c * b1 + d * d1;
+ ctm[4] = e * a1 + f * c1 + ctm[4];
+ ctm[5] = e * b1 + f * d1 + ctm[5];
+}
+
+void GfxState::setFillColorSpace(GfxColorSpace *colorSpace) {
+ if (fillColorSpace) {
+ delete fillColorSpace;
+ }
+ fillColorSpace = colorSpace;
+}
+
+void GfxState::setStrokeColorSpace(GfxColorSpace *colorSpace) {
+ if (strokeColorSpace) {
+ delete strokeColorSpace;
+ }
+ strokeColorSpace = colorSpace;
+}
+
+void GfxState::setFillPattern(GfxPattern *pattern) {
+ if (fillPattern) {
+ delete fillPattern;
+ }
+ fillPattern = pattern;
+}
+
+void GfxState::setStrokePattern(GfxPattern *pattern) {
+ if (strokePattern) {
+ delete strokePattern;
+ }
+ strokePattern = pattern;
+}
+
+void GfxState::setLineDash(double *dash, int length, double start) {
+ if (lineDash)
+ gfree(lineDash);
+ lineDash = dash;
+ lineDashLength = length;
+ lineDashStart = start;
+}
+
+void GfxState::clearPath() {
+ delete path;
+ path = new GfxPath();
+}
+
+void GfxState::clip() {
+ double xMin, yMin, xMax, yMax, x, y;
+ GfxSubpath *subpath;
+ int i, j;
+
+ xMin = xMax = yMin = yMax = 0; // make gcc happy
+ for (i = 0; i < path->getNumSubpaths(); ++i) {
+ subpath = path->getSubpath(i);
+ for (j = 0; j < subpath->getNumPoints(); ++j) {
+ transform(subpath->getX(j), subpath->getY(j), &x, &y);
+ if (i == 0 && j == 0) {
+ xMin = xMax = x;
+ yMin = yMax = y;
+ } else {
+ if (x < xMin) {
+ xMin = x;
+ } else if (x > xMax) {
+ xMax = x;
+ }
+ if (y < yMin) {
+ yMin = y;
+ } else if (y > yMax) {
+ yMax = y;
+ }
+ }
+ }
+ }
+ if (xMin > clipXMin) {
+ clipXMin = xMin;
+ }
+ if (yMin > clipYMin) {
+ clipYMin = yMin;
+ }
+ if (xMax < clipXMax) {
+ clipXMax = xMax;
+ }
+ if (yMax < clipYMax) {
+ clipYMax = yMax;
+ }
+}
+
+void GfxState::textShift(double tx) {
+ double dx, dy;
+
+ textTransformDelta(tx, 0, &dx, &dy);
+ curX += dx;
+ curY += dy;
+}
+
+void GfxState::textShift(double tx, double ty) {
+ double dx, dy;
+
+ textTransformDelta(tx, ty, &dx, &dy);
+ curX += dx;
+ curY += dy;
+}
+
+GfxState *GfxState::save() {
+ GfxState *newState;
+
+ newState = copy();
+ newState->saved = this;
+ return newState;
+}
+
+GfxState *GfxState::restore() {
+ GfxState *oldState;
+
+ if (saved) {
+ oldState = saved;
+ saved = NULL;
+ delete this;
+ } else {
+ oldState = this;
+ }
+ return oldState;
+}
diff --git a/pdftops/GfxState.h b/pdftops/GfxState.h
new file mode 100644
index 000000000..a628f6bf1
--- /dev/null
+++ b/pdftops/GfxState.h
@@ -0,0 +1,922 @@
+//========================================================================
+//
+// GfxState.h
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifndef GFXSTATE_H
+#define GFXSTATE_H
+
+#ifdef __GNUC__
+#pragma interface
+#endif
+
+#include "gtypes.h"
+#include "Object.h"
+#include "Function.h"
+
+class Array;
+class GfxFont;
+struct PDFRectangle;
+
+//------------------------------------------------------------------------
+// GfxColor
+//------------------------------------------------------------------------
+
+#define gfxColorMaxComps funcMaxOutputs
+
+struct GfxColor {
+ double c[gfxColorMaxComps];
+};
+
+//------------------------------------------------------------------------
+// GfxRGB
+//------------------------------------------------------------------------
+
+struct GfxRGB {
+ double r, g, b;
+};
+
+//------------------------------------------------------------------------
+// GfxCMYK
+//------------------------------------------------------------------------
+
+struct GfxCMYK {
+ double c, m, y, k;
+};
+
+//------------------------------------------------------------------------
+// GfxColorSpace
+//------------------------------------------------------------------------
+
+enum GfxColorSpaceMode {
+ csDeviceGray,
+ csCalGray,
+ csDeviceRGB,
+ csCalRGB,
+ csDeviceCMYK,
+ csLab,
+ csICCBased,
+ csIndexed,
+ csSeparation,
+ csDeviceN,
+ csPattern
+};
+
+class GfxColorSpace {
+public:
+
+ GfxColorSpace();
+ virtual ~GfxColorSpace();
+ virtual GfxColorSpace *copy() = 0;
+ virtual GfxColorSpaceMode getMode() = 0;
+
+ // Construct a color space. Returns NULL if unsuccessful.
+ static GfxColorSpace *parse(Object *csObj);
+
+ // Convert to gray, RGB, or CMYK.
+ virtual void getGray(GfxColor *color, double *gray) = 0;
+ virtual void getRGB(GfxColor *color, GfxRGB *rgb) = 0;
+ virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk) = 0;
+
+ // Return the number of color components.
+ virtual int getNComps() = 0;
+
+ // Return the default ranges for each component, assuming an image
+ // with a max pixel value of <maxImgPixel>.
+ virtual void getDefaultRanges(double *decodeLow, double *decodeRange,
+ int maxImgPixel);
+
+private:
+};
+
+//------------------------------------------------------------------------
+// GfxDeviceGrayColorSpace
+//------------------------------------------------------------------------
+
+class GfxDeviceGrayColorSpace: public GfxColorSpace {
+public:
+
+ GfxDeviceGrayColorSpace();
+ virtual ~GfxDeviceGrayColorSpace();
+ virtual GfxColorSpace *copy();
+ virtual GfxColorSpaceMode getMode() { return csDeviceGray; }
+
+ virtual void getGray(GfxColor *color, double *gray);
+ virtual void getRGB(GfxColor *color, GfxRGB *rgb);
+ virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+
+ virtual int getNComps() { return 1; }
+
+private:
+};
+
+//------------------------------------------------------------------------
+// GfxCalGrayColorSpace
+//------------------------------------------------------------------------
+
+class GfxCalGrayColorSpace: public GfxColorSpace {
+public:
+
+ GfxCalGrayColorSpace();
+ virtual ~GfxCalGrayColorSpace();
+ virtual GfxColorSpace *copy();
+ virtual GfxColorSpaceMode getMode() { return csCalGray; }
+
+ // Construct a CalGray color space. Returns NULL if unsuccessful.
+ static GfxColorSpace *parse(Array *arr);
+
+ virtual void getGray(GfxColor *color, double *gray);
+ virtual void getRGB(GfxColor *color, GfxRGB *rgb);
+ virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+
+ virtual int getNComps() { return 1; }
+
+ // CalGray-specific access.
+ double getWhiteX() { return whiteX; }
+ double getWhiteY() { return whiteY; }
+ double getWhiteZ() { return whiteZ; }
+ double getBlackX() { return blackX; }
+ double getBlackY() { return blackY; }
+ double getBlackZ() { return blackZ; }
+ double getGamma() { return gamma; }
+
+private:
+
+ double whiteX, whiteY, whiteZ; // white point
+ double blackX, blackY, blackZ; // black point
+ double gamma; // gamma value
+};
+
+//------------------------------------------------------------------------
+// GfxDeviceRGBColorSpace
+//------------------------------------------------------------------------
+
+class GfxDeviceRGBColorSpace: public GfxColorSpace {
+public:
+
+ GfxDeviceRGBColorSpace();
+ virtual ~GfxDeviceRGBColorSpace();
+ virtual GfxColorSpace *copy();
+ virtual GfxColorSpaceMode getMode() { return csDeviceRGB; }
+
+ virtual void getGray(GfxColor *color, double *gray);
+ virtual void getRGB(GfxColor *color, GfxRGB *rgb);
+ virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+
+ virtual int getNComps() { return 3; }
+
+private:
+};
+
+//------------------------------------------------------------------------
+// GfxCalRGBColorSpace
+//------------------------------------------------------------------------
+
+class GfxCalRGBColorSpace: public GfxColorSpace {
+public:
+
+ GfxCalRGBColorSpace();
+ virtual ~GfxCalRGBColorSpace();
+ virtual GfxColorSpace *copy();
+ virtual GfxColorSpaceMode getMode() { return csCalRGB; }
+
+ // Construct a CalRGB color space. Returns NULL if unsuccessful.
+ static GfxColorSpace *parse(Array *arr);
+
+ virtual void getGray(GfxColor *color, double *gray);
+ virtual void getRGB(GfxColor *color, GfxRGB *rgb);
+ virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+
+ virtual int getNComps() { return 3; }
+
+ // CalRGB-specific access.
+ double getWhiteX() { return whiteX; }
+ double getWhiteY() { return whiteY; }
+ double getWhiteZ() { return whiteZ; }
+ double getBlackX() { return blackX; }
+ double getBlackY() { return blackY; }
+ double getBlackZ() { return blackZ; }
+ double getGammaR() { return gammaR; }
+ double getGammaG() { return gammaG; }
+ double getGammaB() { return gammaB; }
+ double *getMatrix() { return mat; }
+
+private:
+
+ double whiteX, whiteY, whiteZ; // white point
+ double blackX, blackY, blackZ; // black point
+ double gammaR, gammaG, gammaB; // gamma values
+ double mat[9]; // ABC -> XYZ transform matrix
+};
+
+//------------------------------------------------------------------------
+// GfxDeviceCMYKColorSpace
+//------------------------------------------------------------------------
+
+class GfxDeviceCMYKColorSpace: public GfxColorSpace {
+public:
+
+ GfxDeviceCMYKColorSpace();
+ virtual ~GfxDeviceCMYKColorSpace();
+ virtual GfxColorSpace *copy();
+ virtual GfxColorSpaceMode getMode() { return csDeviceCMYK; }
+
+ virtual void getGray(GfxColor *color, double *gray);
+ virtual void getRGB(GfxColor *color, GfxRGB *rgb);
+ virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+
+ virtual int getNComps() { return 4; }
+
+private:
+};
+
+//------------------------------------------------------------------------
+// GfxLabColorSpace
+//------------------------------------------------------------------------
+
+class GfxLabColorSpace: public GfxColorSpace {
+public:
+
+ GfxLabColorSpace();
+ virtual ~GfxLabColorSpace();
+ virtual GfxColorSpace *copy();
+ virtual GfxColorSpaceMode getMode() { return csLab; }
+
+ // Construct a Lab color space. Returns NULL if unsuccessful.
+ static GfxColorSpace *parse(Array *arr);
+
+ virtual void getGray(GfxColor *color, double *gray);
+ virtual void getRGB(GfxColor *color, GfxRGB *rgb);
+ virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+
+ virtual int getNComps() { return 3; }
+
+ virtual void getDefaultRanges(double *decodeLow, double *decodeRange,
+ int maxImgPixel);
+
+ // Lab-specific access.
+ double getWhiteX() { return whiteX; }
+ double getWhiteY() { return whiteY; }
+ double getWhiteZ() { return whiteZ; }
+ double getBlackX() { return blackX; }
+ double getBlackY() { return blackY; }
+ double getBlackZ() { return blackZ; }
+ double getAMin() { return aMin; }
+ double getAMax() { return aMax; }
+ double getBMin() { return bMin; }
+ double getBMax() { return bMax; }
+
+private:
+
+ double whiteX, whiteY, whiteZ; // white point
+ double blackX, blackY, blackZ; // black point
+ double aMin, aMax, bMin, bMax; // range for the a and b components
+ double kr, kg, kb; // gamut mapping mulitpliers
+};
+
+//------------------------------------------------------------------------
+// GfxICCBasedColorSpace
+//------------------------------------------------------------------------
+
+class GfxICCBasedColorSpace: public GfxColorSpace {
+public:
+
+ GfxICCBasedColorSpace(int nCompsA, GfxColorSpace *altA,
+ Ref *iccProfileStreamA);
+ virtual ~GfxICCBasedColorSpace();
+ virtual GfxColorSpace *copy();
+ virtual GfxColorSpaceMode getMode() { return csICCBased; }
+
+ // Construct an ICCBased color space. Returns NULL if unsuccessful.
+ static GfxColorSpace *parse(Array *arr);
+
+ virtual void getGray(GfxColor *color, double *gray);
+ virtual void getRGB(GfxColor *color, GfxRGB *rgb);
+ virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+
+ virtual int getNComps() { return nComps; }
+
+ virtual void getDefaultRanges(double *decodeLow, double *decodeRange,
+ int maxImgPixel);
+
+ // ICCBased-specific access.
+ GfxColorSpace *getAlt() { return alt; }
+
+private:
+
+ int nComps; // number of color components (1, 3, or 4)
+ GfxColorSpace *alt; // alternate color space
+ double rangeMin[4]; // min values for each component
+ double rangeMax[4]; // max values for each component
+ Ref iccProfileStream; // the ICC profile
+};
+
+//------------------------------------------------------------------------
+// GfxIndexedColorSpace
+//------------------------------------------------------------------------
+
+class GfxIndexedColorSpace: public GfxColorSpace {
+public:
+
+ GfxIndexedColorSpace(GfxColorSpace *baseA, int indexHighA);
+ virtual ~GfxIndexedColorSpace();
+ virtual GfxColorSpace *copy();
+ virtual GfxColorSpaceMode getMode() { return csIndexed; }
+
+ // Construct a Lab color space. Returns NULL if unsuccessful.
+ static GfxColorSpace *parse(Array *arr);
+
+ virtual void getGray(GfxColor *color, double *gray);
+ virtual void getRGB(GfxColor *color, GfxRGB *rgb);
+ virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+
+ virtual int getNComps() { return 1; }
+
+ virtual void getDefaultRanges(double *decodeLow, double *decodeRange,
+ int maxImgPixel);
+
+ // Indexed-specific access.
+ GfxColorSpace *getBase() { return base; }
+ int getIndexHigh() { return indexHigh; }
+ Guchar *getLookup() { return lookup; }
+
+private:
+
+ GfxColorSpace *base; // base color space
+ int indexHigh; // max pixel value
+ Guchar *lookup; // lookup table
+};
+
+//------------------------------------------------------------------------
+// GfxSeparationColorSpace
+//------------------------------------------------------------------------
+
+class GfxSeparationColorSpace: public GfxColorSpace {
+public:
+
+ GfxSeparationColorSpace(GString *nameA, GfxColorSpace *altA,
+ Function *funcA);
+ virtual ~GfxSeparationColorSpace();
+ virtual GfxColorSpace *copy();
+ virtual GfxColorSpaceMode getMode() { return csSeparation; }
+
+ // Construct a Separation color space. Returns NULL if unsuccessful.
+ static GfxColorSpace *parse(Array *arr);
+
+ virtual void getGray(GfxColor *color, double *gray);
+ virtual void getRGB(GfxColor *color, GfxRGB *rgb);
+ virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+
+ virtual int getNComps() { return 1; }
+
+ // Separation-specific access.
+ GString *getName() { return name; }
+ GfxColorSpace *getAlt() { return alt; }
+ Function *getFunc() { return func; }
+
+private:
+
+ GString *name; // colorant name
+ GfxColorSpace *alt; // alternate color space
+ Function *func; // tint transform (into alternate color space)
+};
+
+//------------------------------------------------------------------------
+// GfxDeviceNColorSpace
+//------------------------------------------------------------------------
+
+class GfxDeviceNColorSpace: public GfxColorSpace {
+public:
+
+ GfxDeviceNColorSpace(int nComps, GfxColorSpace *alt, Function *func);
+ virtual ~GfxDeviceNColorSpace();
+ virtual GfxColorSpace *copy();
+ virtual GfxColorSpaceMode getMode() { return csDeviceN; }
+
+ // Construct a DeviceN color space. Returns NULL if unsuccessful.
+ static GfxColorSpace *parse(Array *arr);
+
+ virtual void getGray(GfxColor *color, double *gray);
+ virtual void getRGB(GfxColor *color, GfxRGB *rgb);
+ virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+
+ virtual int getNComps() { return nComps; }
+
+ // DeviceN-specific access.
+ GfxColorSpace *getAlt() { return alt; }
+
+private:
+
+ int nComps; // number of components
+ GString // colorant names
+ *names[gfxColorMaxComps];
+ GfxColorSpace *alt; // alternate color space
+ Function *func; // tint transform (into alternate color space)
+
+};
+
+//------------------------------------------------------------------------
+// GfxPatternColorSpace
+//------------------------------------------------------------------------
+
+class GfxPatternColorSpace: public GfxColorSpace {
+public:
+
+ GfxPatternColorSpace(GfxColorSpace *underA);
+ virtual ~GfxPatternColorSpace();
+ virtual GfxColorSpace *copy();
+ virtual GfxColorSpaceMode getMode() { return csPattern; }
+
+ // Construct a Pattern color space. Returns NULL if unsuccessful.
+ static GfxColorSpace *parse(Array *arr);
+
+ virtual void getGray(GfxColor *color, double *gray);
+ virtual void getRGB(GfxColor *color, GfxRGB *rgb);
+ virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+
+ virtual int getNComps() { return 0; }
+
+ // Pattern-specific access.
+ GfxColorSpace *getUnder() { return under; }
+
+private:
+
+ GfxColorSpace *under; // underlying color space (for uncolored
+ // patterns)
+};
+
+//------------------------------------------------------------------------
+// GfxPattern
+//------------------------------------------------------------------------
+
+class GfxPattern {
+public:
+
+ GfxPattern(int typeA);
+ virtual ~GfxPattern();
+
+ static GfxPattern *parse(Object *obj);
+
+ virtual GfxPattern *copy() = 0;
+
+ int getType() { return type; }
+
+private:
+
+ int type;
+};
+
+//------------------------------------------------------------------------
+// GfxTilingPattern
+//------------------------------------------------------------------------
+
+class GfxTilingPattern: public GfxPattern {
+public:
+
+ GfxTilingPattern(Dict *streamDict, Object *stream);
+ virtual ~GfxTilingPattern();
+
+ virtual GfxPattern *copy();
+
+ int getPaintType() { return paintType; }
+ int getTilingType() { return tilingType; }
+ double *getBBox() { return bbox; }
+ double getXStep() { return xStep; }
+ double getYStep() { return yStep; }
+ Dict *getResDict()
+ { return resDict.isDict() ? resDict.getDict() : (Dict *)NULL; }
+ double *getMatrix() { return matrix; }
+ Object *getContentStream() { return &contentStream; }
+
+private:
+
+ GfxTilingPattern(GfxTilingPattern *pat);
+
+ int paintType;
+ int tilingType;
+ double bbox[4];
+ double xStep, yStep;
+ Object resDict;
+ double matrix[6];
+ Object contentStream;
+};
+
+//------------------------------------------------------------------------
+// GfxShading
+//------------------------------------------------------------------------
+
+class GfxShading {
+public:
+
+ GfxShading();
+ virtual ~GfxShading();
+
+ static GfxShading *parse(Object *obj);
+
+ int getType() { return type; }
+ GfxColorSpace *getColorSpace() { return colorSpace; }
+ GfxColor *getBackground() { return &background; }
+ GBool getHasBackground() { return hasBackground; }
+ void getBBox(double *xMinA, double *yMinA, double *xMaxA, double *yMaxA)
+ { *xMinA = xMin; *yMinA = yMin; *xMaxA = xMax; *yMaxA = yMax; }
+ GBool getHasBBox() { return hasBBox; }
+
+private:
+
+ int type;
+ GfxColorSpace *colorSpace;
+ GfxColor background;
+ GBool hasBackground;
+ double xMin, yMin, xMax, yMax;
+ GBool hasBBox;
+};
+
+//------------------------------------------------------------------------
+// GfxAxialShading
+//------------------------------------------------------------------------
+
+class GfxAxialShading: public GfxShading {
+public:
+
+ GfxAxialShading(double x0A, double y0A,
+ double x1A, double y1A,
+ double t0A, double t1A,
+ Function **funcsA, int nFuncsA,
+ GBool extend0A, GBool extend1A);
+ virtual ~GfxAxialShading();
+
+ static GfxAxialShading *parse(Dict *dict);
+
+ void getCoords(double *x0A, double *y0A, double *x1A, double *y1A)
+ { *x0A = x0; *y0A = y0; *x1A = x1; *y1A = y1; }
+ double getDomain0() { return t0; }
+ double getDomain1() { return t1; }
+ void getColor(double t, GfxColor *color);
+ GBool getExtend0() { return extend0; }
+ GBool getExtend1() { return extend1; }
+
+private:
+
+ double x0, y0, x1, y1;
+ double t0, t1;
+ Function *funcs[gfxColorMaxComps];
+ int nFuncs;
+ GBool extend0, extend1;
+};
+
+//------------------------------------------------------------------------
+// GfxImageColorMap
+//------------------------------------------------------------------------
+
+class GfxImageColorMap {
+public:
+
+ // Constructor.
+ GfxImageColorMap(int bitsA, Object *decode, GfxColorSpace *colorSpaceA);
+
+ // Destructor.
+ ~GfxImageColorMap();
+
+ // Is color map valid?
+ GBool isOk() { return ok; }
+
+ // Get the color space.
+ GfxColorSpace *getColorSpace() { return colorSpace; }
+
+ // Get stream decoding info.
+ int getNumPixelComps() { return nComps; }
+ int getBits() { return bits; }
+
+ // Get decode table.
+ double getDecodeLow(int i) { return decodeLow[i]; }
+ double getDecodeHigh(int i) { return decodeLow[i] + decodeRange[i]; }
+
+ // Convert an image pixel to a color.
+ void getGray(Guchar *x, double *gray);
+ void getRGB(Guchar *x, GfxRGB *rgb);
+ void getCMYK(Guchar *x, GfxCMYK *cmyk);
+
+private:
+
+ GfxColorSpace *colorSpace; // the image color space
+ int bits; // bits per component
+ int nComps; // number of components in a pixel
+ GfxColorSpace *colorSpace2; // secondary color space
+ int nComps2; // number of components in colorSpace2
+ double *lookup; // lookup table
+ double // minimum values for each component
+ decodeLow[gfxColorMaxComps];
+ double // max - min value for each component
+ decodeRange[gfxColorMaxComps];
+ GBool ok;
+};
+
+//------------------------------------------------------------------------
+// GfxSubpath and GfxPath
+//------------------------------------------------------------------------
+
+class GfxSubpath {
+public:
+
+ // Constructor.
+ GfxSubpath(double x1, double y1);
+
+ // Destructor.
+ ~GfxSubpath();
+
+ // Copy.
+ GfxSubpath *copy() { return new GfxSubpath(this); }
+
+ // Get points.
+ int getNumPoints() { return n; }
+ double getX(int i) { return x[i]; }
+ double getY(int i) { return y[i]; }
+ GBool getCurve(int i) { return curve[i]; }
+
+ // Get last point.
+ double getLastX() { return x[n-1]; }
+ double getLastY() { return y[n-1]; }
+
+ // Add a line segment.
+ void lineTo(double x1, double y1);
+
+ // Add a Bezier curve.
+ void curveTo(double x1, double y1, double x2, double y2,
+ double x3, double y3);
+
+ // Close the subpath.
+ void close();
+ GBool isClosed() { return closed; }
+
+private:
+
+ double *x, *y; // points
+ GBool *curve; // curve[i] => point i is a control point
+ // for a Bezier curve
+ int n; // number of points
+ int size; // size of x/y arrays
+ GBool closed; // set if path is closed
+
+ GfxSubpath(GfxSubpath *subpath);
+};
+
+class GfxPath {
+public:
+
+ // Constructor.
+ GfxPath();
+
+ // Destructor.
+ ~GfxPath();
+
+ // Copy.
+ GfxPath *copy()
+ { return new GfxPath(justMoved, firstX, firstY, subpaths, n, size); }
+
+ // Is there a current point?
+ GBool isCurPt() { return n > 0 || justMoved; }
+
+ // Is the path non-empty, i.e., is there at least one segment?
+ GBool isPath() { return n > 0; }
+
+ // Get subpaths.
+ int getNumSubpaths() { return n; }
+ GfxSubpath *getSubpath(int i) { return subpaths[i]; }
+
+ // Get last point on last subpath.
+ double getLastX() { return subpaths[n-1]->getLastX(); }
+ double getLastY() { return subpaths[n-1]->getLastY(); }
+
+ // Move the current point.
+ void moveTo(double x, double y);
+
+ // Add a segment to the last subpath.
+ void lineTo(double x, double y);
+
+ // Add a Bezier curve to the last subpath
+ void curveTo(double x1, double y1, double x2, double y2,
+ double x3, double y3);
+
+ // Close the last subpath.
+ void close() { subpaths[n-1]->close(); }
+
+private:
+
+ GBool justMoved; // set if a new subpath was just started
+ double firstX, firstY; // first point in new subpath
+ GfxSubpath **subpaths; // subpaths
+ int n; // number of subpaths
+ int size; // size of subpaths array
+
+ GfxPath(GBool justMoved1, double firstX1, double firstY1,
+ GfxSubpath **subpaths1, int n1, int size1);
+};
+
+//------------------------------------------------------------------------
+// GfxState
+//------------------------------------------------------------------------
+
+class GfxState {
+public:
+
+ // Construct a default GfxState, for a device with resolution <dpi>,
+ // page box <pageBox>, page rotation <rotate>, and coordinate system
+ // specified by <upsideDown>.
+ GfxState(double dpi, PDFRectangle *pageBox, int rotate,
+ GBool upsideDown);
+
+ // Destructor.
+ ~GfxState();
+
+ // Copy.
+ GfxState *copy() { return new GfxState(this); }
+
+ // Accessors.
+ double *getCTM() { return ctm; }
+ double getX1() { return px1; }
+ double getY1() { return py1; }
+ double getX2() { return px2; }
+ double getY2() { return py2; }
+ double getPageWidth() { return pageWidth; }
+ double getPageHeight() { return pageHeight; }
+ GfxColor *getFillColor() { return &fillColor; }
+ GfxColor *getStrokeColor() { return &strokeColor; }
+ void getFillGray(double *gray)
+ { fillColorSpace->getGray(&fillColor, gray); }
+ void getStrokeGray(double *gray)
+ { strokeColorSpace->getGray(&fillColor, gray); }
+ void getFillRGB(GfxRGB *rgb)
+ { fillColorSpace->getRGB(&fillColor, rgb); }
+ void getStrokeRGB(GfxRGB *rgb)
+ { strokeColorSpace->getRGB(&strokeColor, rgb); }
+ void getFillCMYK(GfxCMYK *cmyk)
+ { fillColorSpace->getCMYK(&fillColor, cmyk); }
+ void getStrokeCMYK(GfxCMYK *cmyk)
+ { strokeColorSpace->getCMYK(&strokeColor, cmyk); }
+ GfxColorSpace *getFillColorSpace() { return fillColorSpace; }
+ GfxColorSpace *getStrokeColorSpace() { return strokeColorSpace; }
+ GfxPattern *getFillPattern() { return fillPattern; }
+ GfxPattern *getStrokePattern() { return strokePattern; }
+ double getFillOpacity() { return fillOpacity; }
+ double getStrokeOpacity() { return strokeOpacity; }
+ double getLineWidth() { return lineWidth; }
+ void getLineDash(double **dash, int *length, double *start)
+ { *dash = lineDash; *length = lineDashLength; *start = lineDashStart; }
+ int getFlatness() { return flatness; }
+ int getLineJoin() { return lineJoin; }
+ int getLineCap() { return lineCap; }
+ double getMiterLimit() { return miterLimit; }
+ GfxFont *getFont() { return font; }
+ double getFontSize() { return fontSize; }
+ double *getTextMat() { return textMat; }
+ double getCharSpace() { return charSpace; }
+ double getWordSpace() { return wordSpace; }
+ double getHorizScaling() { return horizScaling; }
+ double getLeading() { return leading; }
+ double getRise() { return rise; }
+ int getRender() { return render; }
+ GfxPath *getPath() { return path; }
+ double getCurX() { return curX; }
+ double getCurY() { return curY; }
+ void getClipBBox(double *xMin, double *yMin, double *xMax, double *yMax)
+ { *xMin = clipXMin; *yMin = clipYMin; *xMax = clipXMax; *yMax = clipYMax; }
+ double getLineX() { return lineX; }
+ double getLineY() { return lineY; }
+
+ // Is there a current point/path?
+ GBool isCurPt() { return path->isCurPt(); }
+ GBool isPath() { return path->isPath(); }
+
+ // Transforms.
+ void transform(double x1, double y1, double *x2, double *y2)
+ { *x2 = ctm[0] * x1 + ctm[2] * y1 + ctm[4];
+ *y2 = ctm[1] * x1 + ctm[3] * y1 + ctm[5]; }
+ void transformDelta(double x1, double y1, double *x2, double *y2)
+ { *x2 = ctm[0] * x1 + ctm[2] * y1;
+ *y2 = ctm[1] * x1 + ctm[3] * y1; }
+ void textTransform(double x1, double y1, double *x2, double *y2)
+ { *x2 = textMat[0] * x1 + textMat[2] * y1 + textMat[4];
+ *y2 = textMat[1] * x1 + textMat[3] * y1 + textMat[5]; }
+ void textTransformDelta(double x1, double y1, double *x2, double *y2)
+ { *x2 = textMat[0] * x1 + textMat[2] * y1;
+ *y2 = textMat[1] * x1 + textMat[3] * y1; }
+ double transformWidth(double w);
+ double getTransformedLineWidth()
+ { return transformWidth(lineWidth); }
+ double getTransformedFontSize();
+ void getFontTransMat(double *m11, double *m12, double *m21, double *m22);
+
+ // Change state parameters.
+ void setCTM(double a, double b, double c,
+ double d, double e, double f);
+ void concatCTM(double a, double b, double c,
+ double d, double e, double f);
+ void setFillColorSpace(GfxColorSpace *colorSpace);
+ void setStrokeColorSpace(GfxColorSpace *colorSpace);
+ void setFillColor(GfxColor *color) { fillColor = *color; }
+ void setStrokeColor(GfxColor *color) { strokeColor = *color; }
+ void setFillPattern(GfxPattern *pattern);
+ void setStrokePattern(GfxPattern *pattern);
+ void setFillOpacity(double opac) { fillOpacity = opac; }
+ void setStrokeOpacity(double opac) { strokeOpacity = opac; }
+ void setLineWidth(double width) { lineWidth = width; }
+ void setLineDash(double *dash, int length, double start);
+ void setFlatness(int flatness1) { flatness = flatness1; }
+ void setLineJoin(int lineJoin1) { lineJoin = lineJoin1; }
+ void setLineCap(int lineCap1) { lineCap = lineCap1; }
+ void setMiterLimit(double limit) { miterLimit = limit; }
+ void setFont(GfxFont *fontA, double fontSizeA)
+ { font = fontA; fontSize = fontSizeA; }
+ void setTextMat(double a, double b, double c,
+ double d, double e, double f)
+ { textMat[0] = a; textMat[1] = b; textMat[2] = c;
+ textMat[3] = d; textMat[4] = e; textMat[5] = f; }
+ void setCharSpace(double space)
+ { charSpace = space; }
+ void setWordSpace(double space)
+ { wordSpace = space; }
+ void setHorizScaling(double scale)
+ { horizScaling = 0.01 * scale; }
+ void setLeading(double leadingA)
+ { leading = leadingA; }
+ void setRise(double riseA)
+ { rise = riseA; }
+ void setRender(int renderA)
+ { render = renderA; }
+
+ // Add to path.
+ void moveTo(double x, double y)
+ { path->moveTo(curX = x, curY = y); }
+ void lineTo(double x, double y)
+ { path->lineTo(curX = x, curY = y); }
+ void curveTo(double x1, double y1, double x2, double y2,
+ double x3, double y3)
+ { path->curveTo(x1, y1, x2, y2, curX = x3, curY = y3); }
+ void closePath()
+ { path->close(); curX = path->getLastX(); curY = path->getLastY(); }
+ void clearPath();
+
+ // Update clip region.
+ void clip();
+
+ // Text position.
+ void textMoveTo(double tx, double ty)
+ { lineX = tx; lineY = ty; textTransform(tx, ty, &curX, &curY); }
+ void textShift(double tx);
+ void textShift(double tx, double ty);
+
+ // Push/pop GfxState on/off stack.
+ GfxState *save();
+ GfxState *restore();
+ GBool hasSaves() { return saved != NULL; }
+
+private:
+
+ double ctm[6]; // coord transform matrix
+ double px1, py1, px2, py2; // page corners (user coords)
+ double pageWidth, pageHeight; // page size (pixels)
+
+ GfxColorSpace *fillColorSpace; // fill color space
+ GfxColorSpace *strokeColorSpace; // stroke color space
+ GfxColor fillColor; // fill color
+ GfxColor strokeColor; // stroke color
+ GfxPattern *fillPattern; // fill pattern
+ GfxPattern *strokePattern; // stroke pattern
+ double fillOpacity; // fill opacity
+ double strokeOpacity; // stroke opacity
+
+ double lineWidth; // line width
+ double *lineDash; // line dash
+ int lineDashLength;
+ double lineDashStart;
+ int flatness; // curve flatness
+ int lineJoin; // line join style
+ int lineCap; // line cap style
+ double miterLimit; // line miter limit
+
+ GfxFont *font; // font
+ double fontSize; // font size
+ double textMat[6]; // text matrix
+ double charSpace; // character spacing
+ double wordSpace; // word spacing
+ double horizScaling; // horizontal scaling
+ double leading; // text leading
+ double rise; // text rise
+ int render; // text rendering mode
+
+ GfxPath *path; // array of path elements
+ double curX, curY; // current point (user coords)
+ double lineX, lineY; // start of current text line (text coords)
+
+ double clipXMin, clipYMin, // bounding box for clip region
+ clipXMax, clipYMax;
+
+ GfxState *saved; // next GfxState on stack
+
+ GfxState(GfxState *state);
+};
+
+#endif
diff --git a/pdftops/Japan12CMapInfo.h b/pdftops/Japan12CMapInfo.h
new file mode 100644
index 000000000..ae4ef9c9d
--- /dev/null
+++ b/pdftops/Japan12CMapInfo.h
@@ -0,0 +1,31362 @@
+//========================================================================
+//
+// Japan12CMapInfo.h
+//
+// This file was automatically generated by makeCMapInfo.
+//
+// Copyright 1998 Derek B. Noonburg
+//
+//========================================================================
+
+#ifndef JAPAN12CMAPINFO_H
+#define JAPAN12CMAPINFO_H
+
+static Gushort japan1278EUCHMap2[1252] = {
+ 0x0000, 0x0000,
+ 0x8ea0, 0x0146,
+ 0xa1a1, 0x0279,
+ 0xa2a1, 0x02d7,
+ 0xa3b0, 0x030c,
+ 0xa3c1, 0x0316,
+ 0xa3e1, 0x0330,
+ 0xa4a1, 0x034a,
+ 0xa5a1, 0x039d,
+ 0xa6a1, 0x03f3,
+ 0xa6c1, 0x040b,
+ 0xa7a1, 0x0423,
+ 0xa7d1, 0x0444,
+ 0xb0a1, 0x0465,
+ 0xb0a2, 0x1dd1,
+ 0xb0a3, 0x0467,
+ 0xb0a9, 0x204a,
+ 0xb0aa, 0x046e,
+ 0xb0b2, 0x1f19,
+ 0xb0b3, 0x1ca2,
+ 0xb0b4, 0x0478,
+ 0xb0bb, 0x1dd2,
+ 0xb0bc, 0x0480,
+ 0xb0ee, 0x1dd3,
+ 0xb0ef, 0x04b3,
+ 0xb0f3, 0x1dd4,
+ 0xb0f4, 0x04b8,
+ 0xb0fc, 0x1dd5,
+ 0xb0fd, 0x04c1,
+ 0xb1a1, 0x04c3,
+ 0xb1aa, 0x1dd6,
+ 0xb1ab, 0x04cd,
+ 0xb1b5, 0x1dd7,
+ 0xb1b6, 0x04d8,
+ 0xb1b9, 0x1dd8,
+ 0xb1ba, 0x04dc,
+ 0xb1bd, 0x1dda,
+ 0xb1be, 0x04e0,
+ 0xb1c2, 0x1ddb,
+ 0xb1c3, 0x04e5,
+ 0xb1eb, 0x1ddc,
+ 0xb1ec, 0x050e,
+ 0xb2a1, 0x0521,
+ 0xb2a8, 0x1ddd,
+ 0xb2a9, 0x1cc9,
+ 0xb2aa, 0x1dde,
+ 0xb2ab, 0x052b,
+ 0xb2e0, 0x1ddf,
+ 0xb2e1, 0x0561,
+ 0xb2fa, 0x1de0,
+ 0xb2fb, 0x057b,
+ 0xb2fd, 0x1de1,
+ 0xb2fe, 0x057e,
+ 0xb3a1, 0x057f,
+ 0xb3a2, 0x1de2,
+ 0xb3a3, 0x0581,
+ 0xb3c2, 0x1961,
+ 0xb3c3, 0x05a1,
+ 0xb3c9, 0x139f,
+ 0xb3ca, 0x05a8,
+ 0xb3e5, 0x1de3,
+ 0xb3e6, 0x05c4,
+ 0xb3eb, 0x1de4,
+ 0xb3ec, 0x05ca,
+ 0xb3f3, 0x1de5,
+ 0xb3f4, 0x05d2,
+ 0xb3f6, 0x1731,
+ 0xb3f7, 0x05d5,
+ 0xb3fa, 0x1de6,
+ 0xb3fb, 0x05d9,
+ 0xb4a1, 0x05dd,
+ 0xb4c2, 0x1de7,
+ 0xb4c3, 0x1572,
+ 0xb4c4, 0x0600,
+ 0xb4cd, 0x1de8,
+ 0xb4ce, 0x060a,
+ 0xb4d2, 0x1a20,
+ 0xb4d3, 0x060f,
+ 0xb4e5, 0x1de9,
+ 0xb4e6, 0x0622,
+ 0xb5a1, 0x063b,
+ 0xb5ab, 0x1dea,
+ 0xb5ac, 0x0646,
+ 0xb5c0, 0x1deb,
+ 0xb5c1, 0x065b,
+ 0xb6a1, 0x0699,
+ 0xb6a2, 0x1dec,
+ 0xb6a3, 0x069b,
+ 0xb6aa, 0x1ded,
+ 0xb6ab, 0x06a3,
+ 0xb6c6, 0x1d32,
+ 0xb6c7, 0x06bf,
+ 0xb6cf, 0x1dee,
+ 0xb6d0, 0x06c8,
+ 0xb6ed, 0x1def,
+ 0xb6ee, 0x06e6,
+ 0xb6f4, 0x1df0,
+ 0xb6f5, 0x06ed,
+ 0xb6fb, 0x1df1,
+ 0xb6fc, 0x06f4,
+ 0xb6fd, 0x1df2,
+ 0xb6fe, 0x06f6,
+ 0xb7a1, 0x06f7,
+ 0xb7a4, 0x1df3,
+ 0xb7a5, 0x06fb,
+ 0xb7b7, 0x1df4,
+ 0xb7b8, 0x070e,
+ 0xb7c5, 0x1df5,
+ 0xb7c6, 0x071c,
+ 0xb7ce, 0x1df6,
+ 0xb7cf, 0x0725,
+ 0xb7d2, 0x1df7,
+ 0xb7d3, 0x0729,
+ 0xb7d5, 0x1df8,
+ 0xb7d6, 0x072c,
+ 0xb7db, 0x1c0d,
+ 0xb7dc, 0x0732,
+ 0xb7e4, 0x1df9,
+ 0xb7e5, 0x073b,
+ 0xb7f1, 0x1dfa,
+ 0xb7f2, 0x0748,
+ 0xb7f9, 0x1dfb,
+ 0xb7fa, 0x0750,
+ 0xb7fe, 0x1dfc,
+ 0xb8a1, 0x0755,
+ 0xb8b4, 0x1dfd,
+ 0xb8b5, 0x0769,
+ 0xb8c1, 0x1dfe,
+ 0xb8c2, 0x0776,
+ 0xb9a1, 0x07b3,
+ 0xb9ab, 0x1dff,
+ 0xb9ac, 0x07be,
+ 0xb9b7, 0x1e00,
+ 0xb9b8, 0x07ca,
+ 0xb9c2, 0x1e01,
+ 0xb9c3, 0x07d5,
+ 0xb9dc, 0x16dd,
+ 0xb9dd, 0x07ef,
+ 0xb9ed, 0x1e02,
+ 0xb9ee, 0x0800,
+ 0xb9f4, 0x1e03,
+ 0xb9f5, 0x0807,
+ 0xb9f9, 0x1e04,
+ 0xb9fa, 0x080c,
+ 0xbaa1, 0x0811,
+ 0xbad3, 0x1e05,
+ 0xbad4, 0x0844,
+ 0xbae7, 0x1e06,
+ 0xbae8, 0x0858,
+ 0xbaf4, 0x1e07,
+ 0xbaf5, 0x0865,
+ 0xbba1, 0x086f,
+ 0xbba7, 0x1e08,
+ 0xbba8, 0x0876,
+ 0xbbaa, 0x1e09,
+ 0xbbab, 0x0879,
+ 0xbbac, 0x1e0a,
+ 0xbbad, 0x087b,
+ 0xbbb9, 0x1e0b,
+ 0xbbba, 0x0888,
+ 0xbca1, 0x08cd,
+ 0xbcc8, 0x1e0d,
+ 0xbcc9, 0x1929,
+ 0xbcca, 0x08f6,
+ 0xbcd7, 0x1e0e,
+ 0xbcd8, 0x0904,
+ 0xbcdd, 0x1e0f,
+ 0xbcdf, 0x090b,
+ 0xbda1, 0x092b,
+ 0xbdab, 0x1e11,
+ 0xbdac, 0x0936,
+ 0xbdb6, 0x1e12,
+ 0xbdb7, 0x0941,
+ 0xbdec, 0x1e13,
+ 0xbdee, 0x0978,
+ 0xbdf2, 0x1e15,
+ 0xbdf4, 0x097e,
+ 0xbea1, 0x0989,
+ 0xbea5, 0x1e17,
+ 0xbea6, 0x098e,
+ 0xbeb3, 0x1e18,
+ 0xbeb4, 0x099c,
+ 0xbebf, 0x1e19,
+ 0xbec0, 0x09a8,
+ 0xbed5, 0x1e1a,
+ 0xbed6, 0x09be,
+ 0xbedf, 0x1e1b,
+ 0xbee0, 0x09c8,
+ 0xbee4, 0x1e1c,
+ 0xbee5, 0x09cd,
+ 0xbfa1, 0x09e7,
+ 0xbfaa, 0x1e1d,
+ 0xbfab, 0x09f1,
+ 0xbfd9, 0x1e1e,
+ 0xbfda, 0x0a20,
+ 0xbfe0, 0x1e1f,
+ 0xbfe1, 0x0a27,
+ 0xbfe9, 0x1e20,
+ 0xbfea, 0x0a30,
+ 0xc0a1, 0x0a45,
+ 0xc0a2, 0x1e21,
+ 0xc0a3, 0x0a47,
+ 0xc0c2, 0x1e22,
+ 0xc0c3, 0x0a67,
+ 0xc0e6, 0x1e23,
+ 0xc0e7, 0x0a8b,
+ 0xc0f1, 0x1e24,
+ 0xc0f3, 0x0a97,
+ 0xc0f9, 0x1e26,
+ 0xc0fb, 0x0a9f,
+ 0xc1a1, 0x0aa3,
+ 0xc1a7, 0x1e28,
+ 0xc1a8, 0x1a6e,
+ 0xc1a9, 0x0aab,
+ 0xc1b9, 0x1e29,
+ 0xc1ba, 0x0abc,
+ 0xc1cc, 0x1e2a,
+ 0xc1cd, 0x0acf,
+ 0xc1cf, 0x1e2b,
+ 0xc1d0, 0x0ad2,
+ 0xc1df, 0x1e2c,
+ 0xc1e0, 0x0ae2,
+ 0xc1e9, 0x1e2d,
+ 0xc1ea, 0x0aec,
+ 0xc2a1, 0x0b01,
+ 0xc2bd, 0x1e2e,
+ 0xc2be, 0x0b1e,
+ 0xc2cd, 0x1e2f,
+ 0xc2ce, 0x0b2e,
+ 0xc2dc, 0x1e30,
+ 0xc2dd, 0x0b3d,
+ 0xc2e3, 0x1e31,
+ 0xc2e4, 0x0b44,
+ 0xc2ef, 0x1e32,
+ 0xc2f0, 0x0b50,
+ 0xc2f5, 0x1e33,
+ 0xc2f7, 0x0b57,
+ 0xc2fd, 0x1e35,
+ 0xc2fe, 0x0b5e,
+ 0xc3a1, 0x0b5f,
+ 0xc3a7, 0x1e36,
+ 0xc3a8, 0x0b66,
+ 0xc3a9, 0x1e37,
+ 0xc3ab, 0x0b69,
+ 0xc3ad, 0x1e39,
+ 0xc3af, 0x0b6d,
+ 0xc3bd, 0x1e3b,
+ 0xc3be, 0x0b7c,
+ 0xc3f0, 0x1e3c,
+ 0xc3f1, 0x0baf,
+ 0xc3f5, 0x1e3d,
+ 0xc3f6, 0x0bb4,
+ 0xc3fc, 0x1e3e,
+ 0xc3fd, 0x0bbb,
+ 0xc4a1, 0x0bbd,
+ 0xc4bd, 0x1e3f,
+ 0xc4be, 0x0bda,
+ 0xc4c8, 0x1e40,
+ 0xc4c9, 0x0be5,
+ 0xc4ca, 0x1e41,
+ 0xc4cb, 0x0be7,
+ 0xc4cd, 0x1e42,
+ 0xc4ce, 0x0bea,
+ 0xc4cf, 0x1e43,
+ 0xc4d0, 0x0bec,
+ 0xc4d4, 0x204b,
+ 0xc4d5, 0x0bf1,
+ 0xc4db, 0x11b5,
+ 0xc4dc, 0x0bf8,
+ 0xc5a1, 0x0c1b,
+ 0xc5a2, 0x1e44,
+ 0xc5a3, 0x0c1d,
+ 0xc5a7, 0x1e45,
+ 0xc5a8, 0x0c22,
+ 0xc5ae, 0x1e46,
+ 0xc5af, 0x0c29,
+ 0xc5b6, 0x1e47,
+ 0xc5b7, 0x0c31,
+ 0xc5bf, 0x1e48,
+ 0xc5c0, 0x0c3a,
+ 0xc5c8, 0x1e49,
+ 0xc5c9, 0x0c43,
+ 0xc5cb, 0x1e4a,
+ 0xc5cc, 0x0c46,
+ 0xc5d1, 0x1e4b,
+ 0xc5d3, 0x0c4d,
+ 0xc5d7, 0x16df,
+ 0xc5d8, 0x0c52,
+ 0xc5e4, 0x1e4d,
+ 0xc5e5, 0x0c5f,
+ 0xc5ee, 0x1450,
+ 0xc5ef, 0x0c69,
+ 0xc5f3, 0x1536,
+ 0xc5f4, 0x0c6e,
+ 0xc5f8, 0x1e4e,
+ 0xc5f9, 0x0c73,
+ 0xc6a1, 0x0c79,
+ 0xc6be, 0x1e4f,
+ 0xc6bf, 0x0c97,
+ 0xc6c2, 0x1e50,
+ 0xc6c3, 0x0c9b,
+ 0xc6d4, 0x1e51,
+ 0xc6d6, 0x0cae,
+ 0xc6db, 0x1e53,
+ 0xc6dd, 0x0cb5,
+ 0xc6e1, 0x1e55,
+ 0xc6e2, 0x0cba,
+ 0xc6e6, 0x1e56,
+ 0xc6e8, 0x0cc0,
+ 0xc6ea, 0x1e58,
+ 0xc6eb, 0x0cc3,
+ 0xc6f6, 0x1aed,
+ 0xc6f7, 0x0ccf,
+ 0xc7a1, 0x0cd7,
+ 0xc7a9, 0x1e59,
+ 0xc7aa, 0x0ce0,
+ 0xc7b9, 0x1e5a,
+ 0xc7ba, 0x0cf0,
+ 0xc7d7, 0x1e5b,
+ 0xc7d8, 0x0d0e,
+ 0xc7e7, 0x1e5c,
+ 0xc7e8, 0x1989,
+ 0xc7e9, 0x1e5d,
+ 0xc7ea, 0x0d20,
+ 0xc7ed, 0x1e5e,
+ 0xc7ee, 0x0d24,
+ 0xc8a1, 0x0d35,
+ 0xc8a4, 0x1e5f,
+ 0xc8a5, 0x0d39,
+ 0xc8ae, 0x1e60,
+ 0xc8af, 0x0d43,
+ 0xc8b0, 0x1e61,
+ 0xc8b1, 0x0d45,
+ 0xc8d4, 0x1e62,
+ 0xc8d5, 0x0d69,
+ 0xc8e2, 0x1e63,
+ 0xc8e3, 0x0d77,
+ 0xc8f5, 0x1e64,
+ 0xc8f6, 0x0d8a,
+ 0xc9a1, 0x0d93,
+ 0xc9a2, 0x1e65,
+ 0xc9a4, 0x0d96,
+ 0xc9af, 0x1e67,
+ 0xc9b0, 0x143b,
+ 0xc9b1, 0x0da3,
+ 0xc9b2, 0x1e68,
+ 0xc9b3, 0x0da5,
+ 0xc9b5, 0x1e69,
+ 0xc9b6, 0x0da8,
+ 0xc9c0, 0x1e6a,
+ 0xc9c1, 0x0db3,
+ 0xc9ce, 0x1e6b,
+ 0xc9cf, 0x0dc1,
+ 0xc9d1, 0x1e6c,
+ 0xc9d2, 0x0dc4,
+ 0xcaa1, 0x0df1,
+ 0xcac3, 0x1e6d,
+ 0xcac4, 0x0e14,
+ 0xcacd, 0x1e6e,
+ 0xcace, 0x0e1e,
+ 0xcada, 0x1e6f,
+ 0xcadb, 0x0e2b,
+ 0xcaf9, 0x1e70,
+ 0xcafa, 0x0e4a,
+ 0xcba1, 0x0e4f,
+ 0xcba2, 0x1e71,
+ 0xcba3, 0x0e51,
+ 0xcba9, 0x1e72,
+ 0xcbaa, 0x0e58,
+ 0xcbcb, 0x1e73,
+ 0xcbcc, 0x0e7a,
+ 0xcbea, 0x1d33,
+ 0xcbeb, 0x0e99,
+ 0xcbf0, 0x1e74,
+ 0xcbf1, 0x0e9f,
+ 0xcbf8, 0x1f2c,
+ 0xcbf9, 0x102f,
+ 0xcbfa, 0x0ea8,
+ 0xcca1, 0x0ead,
+ 0xcccd, 0x1e75,
+ 0xccce, 0x0eda,
+ 0xccd9, 0x1e76,
+ 0xccda, 0x0ee6,
+ 0xccdf, 0x1e77,
+ 0xcce0, 0x0eec,
+ 0xcce2, 0x1e78,
+ 0xcce3, 0x0eef,
+ 0xccf9, 0x1935,
+ 0xccfa, 0x1e79,
+ 0xccfb, 0x0f07,
+ 0xccfc, 0x1e7a,
+ 0xccfd, 0x0f09,
+ 0xccfe, 0x1e7b,
+ 0xcda1, 0x0f0b,
+ 0xcdb2, 0x1e7c,
+ 0xcdb3, 0x0f1d,
+ 0xcdd0, 0x1e7d,
+ 0xcdd1, 0x0f3b,
+ 0xcdd4, 0x1e7e,
+ 0xcdd5, 0x0f3f,
+ 0xcdda, 0x1d34,
+ 0xcddb, 0x0f45,
+ 0xcde9, 0x1e7f,
+ 0xcdea, 0x0f54,
+ 0xcea1, 0x0f69,
+ 0xcecb, 0x1e80,
+ 0xcecc, 0x0f94,
+ 0xcefa, 0x1e81,
+ 0xcefc, 0x0fc4,
+ 0xcfa1, 0x1e83,
+ 0xcfa2, 0x0fc8,
+ 0xcfb1, 0x1e84,
+ 0xcfb2, 0x0fd8,
+ 0xcfb6, 0x1777,
+ 0xcfb7, 0x0fdd,
+ 0xcfb9, 0x1e85,
+ 0xcfba, 0x0fe0,
+ 0xd0a1, 0x0ffa,
+ 0xd0d6, 0x0ea7,
+ 0xd0d7, 0x1030,
+ 0xd1a1, 0x1058,
+ 0xd1bd, 0x1e86,
+ 0xd1be, 0x1075,
+ 0xd1c7, 0x1e87,
+ 0xd1c8, 0x107f,
+ 0xd1cb, 0x1e88,
+ 0xd1cc, 0x1083,
+ 0xd1cd, 0x1e89,
+ 0xd1ce, 0x1085,
+ 0xd2a1, 0x10b6,
+ 0xd3a1, 0x1114,
+ 0xd3b0, 0x1e8a,
+ 0xd3b1, 0x1124,
+ 0xd3ba, 0x1e8b,
+ 0xd3bb, 0x112e,
+ 0xd3de, 0x1e8d,
+ 0xd3df, 0x1152,
+ 0xd3eb, 0x1e8e,
+ 0xd3ec, 0x115f,
+ 0xd4a1, 0x1172,
+ 0xd4c4, 0x1e8f,
+ 0xd4c5, 0x1196,
+ 0xd4e4, 0x0bf7,
+ 0xd4e5, 0x11b6,
+ 0xd5a1, 0x11d0,
+ 0xd5bd, 0x1e90,
+ 0xd5be, 0x11ed,
+ 0xd5e3, 0x1e91,
+ 0xd5e4, 0x1213,
+ 0xd6a1, 0x122e,
+ 0xd6a2, 0x1e92,
+ 0xd6a3, 0x1230,
+ 0xd7a1, 0x128c,
+ 0xd8a1, 0x12ea,
+ 0xd8a4, 0x1e94,
+ 0xd8a5, 0x12ee,
+ 0xd9a1, 0x1348,
+ 0xd9e0, 0x1e95,
+ 0xd9e1, 0x1388,
+ 0xd9ec, 0x1e96,
+ 0xd9ed, 0x1394,
+ 0xd9f8, 0x05a7,
+ 0xd9f9, 0x13a0,
+ 0xdaa1, 0x13a6,
+ 0xdab9, 0x1e97,
+ 0xdaba, 0x13bf,
+ 0xdacd, 0x1e98,
+ 0xdace, 0x13d3,
+ 0xdba1, 0x1404,
+ 0xdbc5, 0x1e99,
+ 0xdbc6, 0x1429,
+ 0xdbca, 0x1e9a,
+ 0xdbcb, 0x142e,
+ 0xdbd8, 0x0da2,
+ 0xdbd9, 0x143c,
+ 0xdbeb, 0x1e9b,
+ 0xdbec, 0x144f,
+ 0xdbed, 0x0c68,
+ 0xdbee, 0x1451,
+ 0xdbf4, 0x1e9c,
+ 0xdbf5, 0x1458,
+ 0xdca1, 0x1462,
+ 0xdda1, 0x14c0,
+ 0xdea1, 0x151e,
+ 0xdeb9, 0x0c6d,
+ 0xdeba, 0x1537,
+ 0xded0, 0x1e9d,
+ 0xded1, 0x154e,
+ 0xdef5, 0x05ff,
+ 0xdef6, 0x1573,
+ 0xdfa1, 0x157c,
+ 0xe0a1, 0x15da,
+ 0xe0a6, 0x1e9f,
+ 0xe0a7, 0x15e0,
+ 0xe0df, 0x1ea0,
+ 0xe0e0, 0x1619,
+ 0xe0f6, 0x1d35,
+ 0xe0f7, 0x1630,
+ 0xe1a1, 0x1638,
+ 0xe1ab, 0x1ea1,
+ 0xe1ac, 0x1643,
+ 0xe1b0, 0x1ea2,
+ 0xe1b2, 0x1649,
+ 0xe2a1, 0x1696,
+ 0xe2ab, 0x1ea4,
+ 0xe2ac, 0x16a1,
+ 0xe2e8, 0x07ee,
+ 0xe2e9, 0x16de,
+ 0xe2ea, 0x0c51,
+ 0xe2eb, 0x16e0,
+ 0xe2ef, 0x1ea5,
+ 0xe2f0, 0x16e5,
+ 0xe3a1, 0x16f4,
+ 0xe3ca, 0x1ea6,
+ 0xe3cb, 0x171e,
+ 0xe3d4, 0x1ea7,
+ 0xe3d5, 0x1728,
+ 0xe3de, 0x05d4,
+ 0xe3df, 0x1732,
+ 0xe4a1, 0x1752,
+ 0xe4b9, 0x1ea8,
+ 0xe4ba, 0x176b,
+ 0xe4c6, 0x0fdc,
+ 0xe4c7, 0x1778,
+ 0xe4e4, 0x1ea9,
+ 0xe4e5, 0x1796,
+ 0xe4ee, 0x1eaa,
+ 0xe4ef, 0x17a0,
+ 0xe5a1, 0x17b0,
+ 0xe5b9, 0x1eab,
+ 0xe5ba, 0x17c9,
+ 0xe5bb, 0x1eac,
+ 0xe5bc, 0x17cb,
+ 0xe5c6, 0x1ead,
+ 0xe5c7, 0x17d6,
+ 0xe6a1, 0x180e,
+ 0xe6c6, 0x1eae,
+ 0xe6c7, 0x1834,
+ 0xe7a1, 0x186c,
+ 0xe7e4, 0x1eaf,
+ 0xe7e5, 0x18b0,
+ 0xe7e9, 0x1eb0,
+ 0xe7ea, 0x18b5,
+ 0xe7f2, 0x1eb1,
+ 0xe7f3, 0x18be,
+ 0xe8a1, 0x18ca,
+ 0xe8b4, 0x1eb2,
+ 0xe8b5, 0x18de,
+ 0xe8bb, 0x1eb3,
+ 0xe8bc, 0x18e5,
+ 0xe8f4, 0x1eb4,
+ 0xe8f5, 0x191e,
+ 0xe9a1, 0x1928,
+ 0xe9a2, 0x08f5,
+ 0xe9a3, 0x192a,
+ 0xe9ae, 0x0f05,
+ 0xe9af, 0x1936,
+ 0xe9da, 0x05a0,
+ 0xe9db, 0x1962,
+ 0xeaa1, 0x1986,
+ 0xeaa4, 0x0d1e,
+ 0xeaa5, 0x198a,
+ 0xeaa7, 0x1eb6,
+ 0xeaa8, 0x198d,
+ 0xeabd, 0x1eb7,
+ 0xeabe, 0x19a3,
+ 0xeaef, 0x1eb8,
+ 0xeaf0, 0x19d5,
+ 0xeba1, 0x19e4,
+ 0xebb2, 0x1eb9,
+ 0xebb3, 0x19f6,
+ 0xebdd, 0x060e,
+ 0xebde, 0x1a21,
+ 0xebe6, 0x1eba,
+ 0xebe7, 0x1a2a,
+ 0xebf6, 0x1ebb,
+ 0xebf7, 0x1a3a,
+ 0xeca1, 0x1a42,
+ 0xeccd, 0x0aaa,
+ 0xecce, 0x1a6f,
+ 0xece9, 0x1ebc,
+ 0xecea, 0x1a8b,
+ 0xecf4, 0x1ebd,
+ 0xecf5, 0x1a96,
+ 0xeda1, 0x1aa0,
+ 0xedce, 0x1ebe,
+ 0xedcf, 0x1ace,
+ 0xedec, 0x1ebf,
+ 0xeded, 0x1aec,
+ 0xedee, 0x1ec0,
+ 0xedef, 0x1aee,
+ 0xeea1, 0x1afe,
+ 0xeea9, 0x1ec1,
+ 0xeeaa, 0x1b07,
+ 0xeebd, 0x1ec2,
+ 0xeebe, 0x1b1b,
+ 0xeed7, 0x1ec3,
+ 0xeed8, 0x1b35,
+ 0xefa1, 0x1b5c,
+ 0xf0a1, 0x1bba,
+ 0xf0c5, 0x1ec6,
+ 0xf0c6, 0x1bdf,
+ 0xf0d1, 0x1ec7,
+ 0xf0d2, 0x1beb,
+ 0xf0d7, 0x1ec8,
+ 0xf0d8, 0x1bf1,
+ 0xf0f4, 0x0731,
+ 0xf0f5, 0x1ec9,
+ 0xf0f6, 0x1c0f,
+ 0xf1a1, 0x1c18,
+ 0xf2a1, 0x1c76,
+ 0xf2ad, 0x1eca,
+ 0xf2ae, 0x1c83,
+ 0xf2bc, 0x1ecb,
+ 0xf2bd, 0x1c92,
+ 0xf2cd, 0x0477,
+ 0xf2ce, 0x1ecc,
+ 0xf2cf, 0x1ca4,
+ 0xf2f4, 0x0529,
+ 0xf2f5, 0x1cca,
+ 0xf3a1, 0x1cd4,
+ 0xf3d1, 0x1ecd,
+ 0xf3d2, 0x1d05,
+ 0xf3fd, 0x1ece,
+ 0xf3fe, 0x1d31,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 japan1278EUCHEnc16 = {
+ 0,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee,
+ 0x00ef, 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6,
+ 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe,
+ 0x00ff, 0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106,
+ 0x0107, 0x0108, 0x0109, 0x010a, 0x010b, 0x010c, 0x010d, 0x010e,
+ 0x010f, 0x0110, 0x0111, 0x0112, 0x0113, 0x0114, 0x0115, 0x0116,
+ 0x0117, 0x0118, 0x0119, 0x011a, 0x011b, 0x011c, 0x011d, 0x011e,
+ 0x011f, 0x0120, 0x0121, 0x0122, 0x0123, 0x0124, 0x0125, 0x0126,
+ 0x0127, 0x0128, 0x0129, 0x012a, 0x012b, 0x012c, 0x012d, 0x012e,
+ 0x012f, 0x0130, 0x0131, 0x0132, 0x0133, 0x0134, 0x0135, 0x0136,
+ 0x0137, 0x0138, 0x0139, 0x013a, 0x013b, 0x013c, 0x013d, 0x013e,
+ 0x013f, 0x0140, 0x0141, 0x0142, 0x0143, 0x0144, 0x0145, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ japan1278EUCHMap2, 626
+};
+
+static Gushort japan1278EUCVMap2[1306] = {
+ 0x0000, 0x0000,
+ 0x8ea0, 0x0146,
+ 0xa1a1, 0x0279,
+ 0xa2a1, 0x02d7,
+ 0xa3b0, 0x030c,
+ 0xa3c1, 0x0316,
+ 0xa3e1, 0x0330,
+ 0xa4a1, 0x034a,
+ 0xa5a1, 0x039d,
+ 0xa6a1, 0x03f3,
+ 0xa6c1, 0x040b,
+ 0xa7a1, 0x0423,
+ 0xa7d1, 0x0444,
+ 0xb0a1, 0x0465,
+ 0xb0a2, 0x1dd1,
+ 0xb0a3, 0x0467,
+ 0xb0a9, 0x204a,
+ 0xb0aa, 0x046e,
+ 0xb0b2, 0x1f19,
+ 0xb0b3, 0x1ca2,
+ 0xb0b4, 0x0478,
+ 0xb0bb, 0x1dd2,
+ 0xb0bc, 0x0480,
+ 0xb0ee, 0x1dd3,
+ 0xb0ef, 0x04b3,
+ 0xb0f3, 0x1dd4,
+ 0xb0f4, 0x04b8,
+ 0xb0fc, 0x1dd5,
+ 0xb0fd, 0x04c1,
+ 0xb1a1, 0x04c3,
+ 0xb1aa, 0x1dd6,
+ 0xb1ab, 0x04cd,
+ 0xb1b5, 0x1dd7,
+ 0xb1b6, 0x04d8,
+ 0xb1b9, 0x1dd8,
+ 0xb1ba, 0x04dc,
+ 0xb1bd, 0x1dda,
+ 0xb1be, 0x04e0,
+ 0xb1c2, 0x1ddb,
+ 0xb1c3, 0x04e5,
+ 0xb1eb, 0x1ddc,
+ 0xb1ec, 0x050e,
+ 0xb2a1, 0x0521,
+ 0xb2a8, 0x1ddd,
+ 0xb2a9, 0x1cc9,
+ 0xb2aa, 0x1dde,
+ 0xb2ab, 0x052b,
+ 0xb2e0, 0x1ddf,
+ 0xb2e1, 0x0561,
+ 0xb2fa, 0x1de0,
+ 0xb2fb, 0x057b,
+ 0xb2fd, 0x1de1,
+ 0xb2fe, 0x057e,
+ 0xb3a1, 0x057f,
+ 0xb3a2, 0x1de2,
+ 0xb3a3, 0x0581,
+ 0xb3c2, 0x1961,
+ 0xb3c3, 0x05a1,
+ 0xb3c9, 0x139f,
+ 0xb3ca, 0x05a8,
+ 0xb3e5, 0x1de3,
+ 0xb3e6, 0x05c4,
+ 0xb3eb, 0x1de4,
+ 0xb3ec, 0x05ca,
+ 0xb3f3, 0x1de5,
+ 0xb3f4, 0x05d2,
+ 0xb3f6, 0x1731,
+ 0xb3f7, 0x05d5,
+ 0xb3fa, 0x1de6,
+ 0xb3fb, 0x05d9,
+ 0xb4a1, 0x05dd,
+ 0xb4c2, 0x1de7,
+ 0xb4c3, 0x1572,
+ 0xb4c4, 0x0600,
+ 0xb4cd, 0x1de8,
+ 0xb4ce, 0x060a,
+ 0xb4d2, 0x1a20,
+ 0xb4d3, 0x060f,
+ 0xb4e5, 0x1de9,
+ 0xb4e6, 0x0622,
+ 0xb5a1, 0x063b,
+ 0xb5ab, 0x1dea,
+ 0xb5ac, 0x0646,
+ 0xb5c0, 0x1deb,
+ 0xb5c1, 0x065b,
+ 0xb6a1, 0x0699,
+ 0xb6a2, 0x1dec,
+ 0xb6a3, 0x069b,
+ 0xb6aa, 0x1ded,
+ 0xb6ab, 0x06a3,
+ 0xb6c6, 0x1d32,
+ 0xb6c7, 0x06bf,
+ 0xb6cf, 0x1dee,
+ 0xb6d0, 0x06c8,
+ 0xb6ed, 0x1def,
+ 0xb6ee, 0x06e6,
+ 0xb6f4, 0x1df0,
+ 0xb6f5, 0x06ed,
+ 0xb6fb, 0x1df1,
+ 0xb6fc, 0x06f4,
+ 0xb6fd, 0x1df2,
+ 0xb6fe, 0x06f6,
+ 0xb7a1, 0x06f7,
+ 0xb7a4, 0x1df3,
+ 0xb7a5, 0x06fb,
+ 0xb7b7, 0x1df4,
+ 0xb7b8, 0x070e,
+ 0xb7c5, 0x1df5,
+ 0xb7c6, 0x071c,
+ 0xb7ce, 0x1df6,
+ 0xb7cf, 0x0725,
+ 0xb7d2, 0x1df7,
+ 0xb7d3, 0x0729,
+ 0xb7d5, 0x1df8,
+ 0xb7d6, 0x072c,
+ 0xb7db, 0x1c0d,
+ 0xb7dc, 0x0732,
+ 0xb7e4, 0x1df9,
+ 0xb7e5, 0x073b,
+ 0xb7f1, 0x1dfa,
+ 0xb7f2, 0x0748,
+ 0xb7f9, 0x1dfb,
+ 0xb7fa, 0x0750,
+ 0xb7fe, 0x1dfc,
+ 0xb8a1, 0x0755,
+ 0xb8b4, 0x1dfd,
+ 0xb8b5, 0x0769,
+ 0xb8c1, 0x1dfe,
+ 0xb8c2, 0x0776,
+ 0xb9a1, 0x07b3,
+ 0xb9ab, 0x1dff,
+ 0xb9ac, 0x07be,
+ 0xb9b7, 0x1e00,
+ 0xb9b8, 0x07ca,
+ 0xb9c2, 0x1e01,
+ 0xb9c3, 0x07d5,
+ 0xb9dc, 0x16dd,
+ 0xb9dd, 0x07ef,
+ 0xb9ed, 0x1e02,
+ 0xb9ee, 0x0800,
+ 0xb9f4, 0x1e03,
+ 0xb9f5, 0x0807,
+ 0xb9f9, 0x1e04,
+ 0xb9fa, 0x080c,
+ 0xbaa1, 0x0811,
+ 0xbad3, 0x1e05,
+ 0xbad4, 0x0844,
+ 0xbae7, 0x1e06,
+ 0xbae8, 0x0858,
+ 0xbaf4, 0x1e07,
+ 0xbaf5, 0x0865,
+ 0xbba1, 0x086f,
+ 0xbba7, 0x1e08,
+ 0xbba8, 0x0876,
+ 0xbbaa, 0x1e09,
+ 0xbbab, 0x0879,
+ 0xbbac, 0x1e0a,
+ 0xbbad, 0x087b,
+ 0xbbb9, 0x1e0b,
+ 0xbbba, 0x0888,
+ 0xbca1, 0x08cd,
+ 0xbcc8, 0x1e0d,
+ 0xbcc9, 0x1929,
+ 0xbcca, 0x08f6,
+ 0xbcd7, 0x1e0e,
+ 0xbcd8, 0x0904,
+ 0xbcdd, 0x1e0f,
+ 0xbcdf, 0x090b,
+ 0xbda1, 0x092b,
+ 0xbdab, 0x1e11,
+ 0xbdac, 0x0936,
+ 0xbdb6, 0x1e12,
+ 0xbdb7, 0x0941,
+ 0xbdec, 0x1e13,
+ 0xbdee, 0x0978,
+ 0xbdf2, 0x1e15,
+ 0xbdf4, 0x097e,
+ 0xbea1, 0x0989,
+ 0xbea5, 0x1e17,
+ 0xbea6, 0x098e,
+ 0xbeb3, 0x1e18,
+ 0xbeb4, 0x099c,
+ 0xbebf, 0x1e19,
+ 0xbec0, 0x09a8,
+ 0xbed5, 0x1e1a,
+ 0xbed6, 0x09be,
+ 0xbedf, 0x1e1b,
+ 0xbee0, 0x09c8,
+ 0xbee4, 0x1e1c,
+ 0xbee5, 0x09cd,
+ 0xbfa1, 0x09e7,
+ 0xbfaa, 0x1e1d,
+ 0xbfab, 0x09f1,
+ 0xbfd9, 0x1e1e,
+ 0xbfda, 0x0a20,
+ 0xbfe0, 0x1e1f,
+ 0xbfe1, 0x0a27,
+ 0xbfe9, 0x1e20,
+ 0xbfea, 0x0a30,
+ 0xc0a1, 0x0a45,
+ 0xc0a2, 0x1e21,
+ 0xc0a3, 0x0a47,
+ 0xc0c2, 0x1e22,
+ 0xc0c3, 0x0a67,
+ 0xc0e6, 0x1e23,
+ 0xc0e7, 0x0a8b,
+ 0xc0f1, 0x1e24,
+ 0xc0f3, 0x0a97,
+ 0xc0f9, 0x1e26,
+ 0xc0fb, 0x0a9f,
+ 0xc1a1, 0x0aa3,
+ 0xc1a7, 0x1e28,
+ 0xc1a8, 0x1a6e,
+ 0xc1a9, 0x0aab,
+ 0xc1b9, 0x1e29,
+ 0xc1ba, 0x0abc,
+ 0xc1cc, 0x1e2a,
+ 0xc1cd, 0x0acf,
+ 0xc1cf, 0x1e2b,
+ 0xc1d0, 0x0ad2,
+ 0xc1df, 0x1e2c,
+ 0xc1e0, 0x0ae2,
+ 0xc1e9, 0x1e2d,
+ 0xc1ea, 0x0aec,
+ 0xc2a1, 0x0b01,
+ 0xc2bd, 0x1e2e,
+ 0xc2be, 0x0b1e,
+ 0xc2cd, 0x1e2f,
+ 0xc2ce, 0x0b2e,
+ 0xc2dc, 0x1e30,
+ 0xc2dd, 0x0b3d,
+ 0xc2e3, 0x1e31,
+ 0xc2e4, 0x0b44,
+ 0xc2ef, 0x1e32,
+ 0xc2f0, 0x0b50,
+ 0xc2f5, 0x1e33,
+ 0xc2f7, 0x0b57,
+ 0xc2fd, 0x1e35,
+ 0xc2fe, 0x0b5e,
+ 0xc3a1, 0x0b5f,
+ 0xc3a7, 0x1e36,
+ 0xc3a8, 0x0b66,
+ 0xc3a9, 0x1e37,
+ 0xc3ab, 0x0b69,
+ 0xc3ad, 0x1e39,
+ 0xc3af, 0x0b6d,
+ 0xc3bd, 0x1e3b,
+ 0xc3be, 0x0b7c,
+ 0xc3f0, 0x1e3c,
+ 0xc3f1, 0x0baf,
+ 0xc3f5, 0x1e3d,
+ 0xc3f6, 0x0bb4,
+ 0xc3fc, 0x1e3e,
+ 0xc3fd, 0x0bbb,
+ 0xc4a1, 0x0bbd,
+ 0xc4bd, 0x1e3f,
+ 0xc4be, 0x0bda,
+ 0xc4c8, 0x1e40,
+ 0xc4c9, 0x0be5,
+ 0xc4ca, 0x1e41,
+ 0xc4cb, 0x0be7,
+ 0xc4cd, 0x1e42,
+ 0xc4ce, 0x0bea,
+ 0xc4cf, 0x1e43,
+ 0xc4d0, 0x0bec,
+ 0xc4d4, 0x204b,
+ 0xc4d5, 0x0bf1,
+ 0xc4db, 0x11b5,
+ 0xc4dc, 0x0bf8,
+ 0xc5a1, 0x0c1b,
+ 0xc5a2, 0x1e44,
+ 0xc5a3, 0x0c1d,
+ 0xc5a7, 0x1e45,
+ 0xc5a8, 0x0c22,
+ 0xc5ae, 0x1e46,
+ 0xc5af, 0x0c29,
+ 0xc5b6, 0x1e47,
+ 0xc5b7, 0x0c31,
+ 0xc5bf, 0x1e48,
+ 0xc5c0, 0x0c3a,
+ 0xc5c8, 0x1e49,
+ 0xc5c9, 0x0c43,
+ 0xc5cb, 0x1e4a,
+ 0xc5cc, 0x0c46,
+ 0xc5d1, 0x1e4b,
+ 0xc5d3, 0x0c4d,
+ 0xc5d7, 0x16df,
+ 0xc5d8, 0x0c52,
+ 0xc5e4, 0x1e4d,
+ 0xc5e5, 0x0c5f,
+ 0xc5ee, 0x1450,
+ 0xc5ef, 0x0c69,
+ 0xc5f3, 0x1536,
+ 0xc5f4, 0x0c6e,
+ 0xc5f8, 0x1e4e,
+ 0xc5f9, 0x0c73,
+ 0xc6a1, 0x0c79,
+ 0xc6be, 0x1e4f,
+ 0xc6bf, 0x0c97,
+ 0xc6c2, 0x1e50,
+ 0xc6c3, 0x0c9b,
+ 0xc6d4, 0x1e51,
+ 0xc6d6, 0x0cae,
+ 0xc6db, 0x1e53,
+ 0xc6dd, 0x0cb5,
+ 0xc6e1, 0x1e55,
+ 0xc6e2, 0x0cba,
+ 0xc6e6, 0x1e56,
+ 0xc6e8, 0x0cc0,
+ 0xc6ea, 0x1e58,
+ 0xc6eb, 0x0cc3,
+ 0xc6f6, 0x1aed,
+ 0xc6f7, 0x0ccf,
+ 0xc7a1, 0x0cd7,
+ 0xc7a9, 0x1e59,
+ 0xc7aa, 0x0ce0,
+ 0xc7b9, 0x1e5a,
+ 0xc7ba, 0x0cf0,
+ 0xc7d7, 0x1e5b,
+ 0xc7d8, 0x0d0e,
+ 0xc7e7, 0x1e5c,
+ 0xc7e8, 0x1989,
+ 0xc7e9, 0x1e5d,
+ 0xc7ea, 0x0d20,
+ 0xc7ed, 0x1e5e,
+ 0xc7ee, 0x0d24,
+ 0xc8a1, 0x0d35,
+ 0xc8a4, 0x1e5f,
+ 0xc8a5, 0x0d39,
+ 0xc8ae, 0x1e60,
+ 0xc8af, 0x0d43,
+ 0xc8b0, 0x1e61,
+ 0xc8b1, 0x0d45,
+ 0xc8d4, 0x1e62,
+ 0xc8d5, 0x0d69,
+ 0xc8e2, 0x1e63,
+ 0xc8e3, 0x0d77,
+ 0xc8f5, 0x1e64,
+ 0xc8f6, 0x0d8a,
+ 0xc9a1, 0x0d93,
+ 0xc9a2, 0x1e65,
+ 0xc9a4, 0x0d96,
+ 0xc9af, 0x1e67,
+ 0xc9b0, 0x143b,
+ 0xc9b1, 0x0da3,
+ 0xc9b2, 0x1e68,
+ 0xc9b3, 0x0da5,
+ 0xc9b5, 0x1e69,
+ 0xc9b6, 0x0da8,
+ 0xc9c0, 0x1e6a,
+ 0xc9c1, 0x0db3,
+ 0xc9ce, 0x1e6b,
+ 0xc9cf, 0x0dc1,
+ 0xc9d1, 0x1e6c,
+ 0xc9d2, 0x0dc4,
+ 0xcaa1, 0x0df1,
+ 0xcac3, 0x1e6d,
+ 0xcac4, 0x0e14,
+ 0xcacd, 0x1e6e,
+ 0xcace, 0x0e1e,
+ 0xcada, 0x1e6f,
+ 0xcadb, 0x0e2b,
+ 0xcaf9, 0x1e70,
+ 0xcafa, 0x0e4a,
+ 0xcba1, 0x0e4f,
+ 0xcba2, 0x1e71,
+ 0xcba3, 0x0e51,
+ 0xcba9, 0x1e72,
+ 0xcbaa, 0x0e58,
+ 0xcbcb, 0x1e73,
+ 0xcbcc, 0x0e7a,
+ 0xcbea, 0x1d33,
+ 0xcbeb, 0x0e99,
+ 0xcbf0, 0x1e74,
+ 0xcbf1, 0x0e9f,
+ 0xcbf8, 0x1f2c,
+ 0xcbf9, 0x102f,
+ 0xcbfa, 0x0ea8,
+ 0xcca1, 0x0ead,
+ 0xcccd, 0x1e75,
+ 0xccce, 0x0eda,
+ 0xccd9, 0x1e76,
+ 0xccda, 0x0ee6,
+ 0xccdf, 0x1e77,
+ 0xcce0, 0x0eec,
+ 0xcce2, 0x1e78,
+ 0xcce3, 0x0eef,
+ 0xccf9, 0x1935,
+ 0xccfa, 0x1e79,
+ 0xccfb, 0x0f07,
+ 0xccfc, 0x1e7a,
+ 0xccfd, 0x0f09,
+ 0xccfe, 0x1e7b,
+ 0xcda1, 0x0f0b,
+ 0xcdb2, 0x1e7c,
+ 0xcdb3, 0x0f1d,
+ 0xcdd0, 0x1e7d,
+ 0xcdd1, 0x0f3b,
+ 0xcdd4, 0x1e7e,
+ 0xcdd5, 0x0f3f,
+ 0xcdda, 0x1d34,
+ 0xcddb, 0x0f45,
+ 0xcde9, 0x1e7f,
+ 0xcdea, 0x0f54,
+ 0xcea1, 0x0f69,
+ 0xcecb, 0x1e80,
+ 0xcecc, 0x0f94,
+ 0xcefa, 0x1e81,
+ 0xcefc, 0x0fc4,
+ 0xcfa1, 0x1e83,
+ 0xcfa2, 0x0fc8,
+ 0xcfb1, 0x1e84,
+ 0xcfb2, 0x0fd8,
+ 0xcfb6, 0x1777,
+ 0xcfb7, 0x0fdd,
+ 0xcfb9, 0x1e85,
+ 0xcfba, 0x0fe0,
+ 0xd0a1, 0x0ffa,
+ 0xd0d6, 0x0ea7,
+ 0xd0d7, 0x1030,
+ 0xd1a1, 0x1058,
+ 0xd1bd, 0x1e86,
+ 0xd1be, 0x1075,
+ 0xd1c7, 0x1e87,
+ 0xd1c8, 0x107f,
+ 0xd1cb, 0x1e88,
+ 0xd1cc, 0x1083,
+ 0xd1cd, 0x1e89,
+ 0xd1ce, 0x1085,
+ 0xd2a1, 0x10b6,
+ 0xd3a1, 0x1114,
+ 0xd3b0, 0x1e8a,
+ 0xd3b1, 0x1124,
+ 0xd3ba, 0x1e8b,
+ 0xd3bb, 0x112e,
+ 0xd3de, 0x1e8d,
+ 0xd3df, 0x1152,
+ 0xd3eb, 0x1e8e,
+ 0xd3ec, 0x115f,
+ 0xd4a1, 0x1172,
+ 0xd4c4, 0x1e8f,
+ 0xd4c5, 0x1196,
+ 0xd4e4, 0x0bf7,
+ 0xd4e5, 0x11b6,
+ 0xd5a1, 0x11d0,
+ 0xd5bd, 0x1e90,
+ 0xd5be, 0x11ed,
+ 0xd5e3, 0x1e91,
+ 0xd5e4, 0x1213,
+ 0xd6a1, 0x122e,
+ 0xd6a2, 0x1e92,
+ 0xd6a3, 0x1230,
+ 0xd7a1, 0x128c,
+ 0xd8a1, 0x12ea,
+ 0xd8a4, 0x1e94,
+ 0xd8a5, 0x12ee,
+ 0xd9a1, 0x1348,
+ 0xd9e0, 0x1e95,
+ 0xd9e1, 0x1388,
+ 0xd9ec, 0x1e96,
+ 0xd9ed, 0x1394,
+ 0xd9f8, 0x05a7,
+ 0xd9f9, 0x13a0,
+ 0xdaa1, 0x13a6,
+ 0xdab9, 0x1e97,
+ 0xdaba, 0x13bf,
+ 0xdacd, 0x1e98,
+ 0xdace, 0x13d3,
+ 0xdba1, 0x1404,
+ 0xdbc5, 0x1e99,
+ 0xdbc6, 0x1429,
+ 0xdbca, 0x1e9a,
+ 0xdbcb, 0x142e,
+ 0xdbd8, 0x0da2,
+ 0xdbd9, 0x143c,
+ 0xdbeb, 0x1e9b,
+ 0xdbec, 0x144f,
+ 0xdbed, 0x0c68,
+ 0xdbee, 0x1451,
+ 0xdbf4, 0x1e9c,
+ 0xdbf5, 0x1458,
+ 0xdca1, 0x1462,
+ 0xdda1, 0x14c0,
+ 0xdea1, 0x151e,
+ 0xdeb9, 0x0c6d,
+ 0xdeba, 0x1537,
+ 0xded0, 0x1e9d,
+ 0xded1, 0x154e,
+ 0xdef5, 0x05ff,
+ 0xdef6, 0x1573,
+ 0xdfa1, 0x157c,
+ 0xe0a1, 0x15da,
+ 0xe0a6, 0x1e9f,
+ 0xe0a7, 0x15e0,
+ 0xe0df, 0x1ea0,
+ 0xe0e0, 0x1619,
+ 0xe0f6, 0x1d35,
+ 0xe0f7, 0x1630,
+ 0xe1a1, 0x1638,
+ 0xe1ab, 0x1ea1,
+ 0xe1ac, 0x1643,
+ 0xe1b0, 0x1ea2,
+ 0xe1b2, 0x1649,
+ 0xe2a1, 0x1696,
+ 0xe2ab, 0x1ea4,
+ 0xe2ac, 0x16a1,
+ 0xe2e8, 0x07ee,
+ 0xe2e9, 0x16de,
+ 0xe2ea, 0x0c51,
+ 0xe2eb, 0x16e0,
+ 0xe2ef, 0x1ea5,
+ 0xe2f0, 0x16e5,
+ 0xe3a1, 0x16f4,
+ 0xe3ca, 0x1ea6,
+ 0xe3cb, 0x171e,
+ 0xe3d4, 0x1ea7,
+ 0xe3d5, 0x1728,
+ 0xe3de, 0x05d4,
+ 0xe3df, 0x1732,
+ 0xe4a1, 0x1752,
+ 0xe4b9, 0x1ea8,
+ 0xe4ba, 0x176b,
+ 0xe4c6, 0x0fdc,
+ 0xe4c7, 0x1778,
+ 0xe4e4, 0x1ea9,
+ 0xe4e5, 0x1796,
+ 0xe4ee, 0x1eaa,
+ 0xe4ef, 0x17a0,
+ 0xe5a1, 0x17b0,
+ 0xe5b9, 0x1eab,
+ 0xe5ba, 0x17c9,
+ 0xe5bb, 0x1eac,
+ 0xe5bc, 0x17cb,
+ 0xe5c6, 0x1ead,
+ 0xe5c7, 0x17d6,
+ 0xe6a1, 0x180e,
+ 0xe6c6, 0x1eae,
+ 0xe6c7, 0x1834,
+ 0xe7a1, 0x186c,
+ 0xe7e4, 0x1eaf,
+ 0xe7e5, 0x18b0,
+ 0xe7e9, 0x1eb0,
+ 0xe7ea, 0x18b5,
+ 0xe7f2, 0x1eb1,
+ 0xe7f3, 0x18be,
+ 0xe8a1, 0x18ca,
+ 0xe8b4, 0x1eb2,
+ 0xe8b5, 0x18de,
+ 0xe8bb, 0x1eb3,
+ 0xe8bc, 0x18e5,
+ 0xe8f4, 0x1eb4,
+ 0xe8f5, 0x191e,
+ 0xe9a1, 0x1928,
+ 0xe9a2, 0x08f5,
+ 0xe9a3, 0x192a,
+ 0xe9ae, 0x0f05,
+ 0xe9af, 0x1936,
+ 0xe9da, 0x05a0,
+ 0xe9db, 0x1962,
+ 0xeaa1, 0x1986,
+ 0xeaa4, 0x0d1e,
+ 0xeaa5, 0x198a,
+ 0xeaa7, 0x1eb6,
+ 0xeaa8, 0x198d,
+ 0xeabd, 0x1eb7,
+ 0xeabe, 0x19a3,
+ 0xeaef, 0x1eb8,
+ 0xeaf0, 0x19d5,
+ 0xeba1, 0x19e4,
+ 0xebb2, 0x1eb9,
+ 0xebb3, 0x19f6,
+ 0xebdd, 0x060e,
+ 0xebde, 0x1a21,
+ 0xebe6, 0x1eba,
+ 0xebe7, 0x1a2a,
+ 0xebf6, 0x1ebb,
+ 0xebf7, 0x1a3a,
+ 0xeca1, 0x1a42,
+ 0xeccd, 0x0aaa,
+ 0xecce, 0x1a6f,
+ 0xece9, 0x1ebc,
+ 0xecea, 0x1a8b,
+ 0xecf4, 0x1ebd,
+ 0xecf5, 0x1a96,
+ 0xeda1, 0x1aa0,
+ 0xedce, 0x1ebe,
+ 0xedcf, 0x1ace,
+ 0xedec, 0x1ebf,
+ 0xeded, 0x1aec,
+ 0xedee, 0x1ec0,
+ 0xedef, 0x1aee,
+ 0xeea1, 0x1afe,
+ 0xeea9, 0x1ec1,
+ 0xeeaa, 0x1b07,
+ 0xeebd, 0x1ec2,
+ 0xeebe, 0x1b1b,
+ 0xeed7, 0x1ec3,
+ 0xeed8, 0x1b35,
+ 0xefa1, 0x1b5c,
+ 0xf0a1, 0x1bba,
+ 0xf0c5, 0x1ec6,
+ 0xf0c6, 0x1bdf,
+ 0xf0d1, 0x1ec7,
+ 0xf0d2, 0x1beb,
+ 0xf0d7, 0x1ec8,
+ 0xf0d8, 0x1bf1,
+ 0xf0f4, 0x0731,
+ 0xf0f5, 0x1ec9,
+ 0xf0f6, 0x1c0f,
+ 0xf1a1, 0x1c18,
+ 0xf2a1, 0x1c76,
+ 0xf2ad, 0x1eca,
+ 0xf2ae, 0x1c83,
+ 0xf2bc, 0x1ecb,
+ 0xf2bd, 0x1c92,
+ 0xf2cd, 0x0477,
+ 0xf2ce, 0x1ecc,
+ 0xf2cf, 0x1ca4,
+ 0xf2f4, 0x0529,
+ 0xf2f5, 0x1cca,
+ 0xf3a1, 0x1cd4,
+ 0xf3d1, 0x1ecd,
+ 0xf3d2, 0x1d05,
+ 0xf3fd, 0x1ece,
+ 0xf3fe, 0x1d31,
+ 0xa1a2, 0x1ecf,
+ 0xa1b1, 0x1ed1,
+ 0xa1bc, 0x1ed3,
+ 0xa1c1, 0x1ed6,
+ 0xa1ca, 0x1edb,
+ 0xa1e1, 0x1eed,
+ 0xa4a1, 0x1eee,
+ 0xa4a3, 0x1eef,
+ 0xa4a5, 0x1ef0,
+ 0xa4a7, 0x1ef1,
+ 0xa4a9, 0x1ef2,
+ 0xa4c3, 0x1ef3,
+ 0xa4e3, 0x1ef4,
+ 0xa4e5, 0x1ef5,
+ 0xa4e7, 0x1ef6,
+ 0xa4ee, 0x1ef7,
+ 0xa5a1, 0x1ef8,
+ 0xa5a3, 0x1ef9,
+ 0xa5a5, 0x1efa,
+ 0xa5a7, 0x1efb,
+ 0xa5a9, 0x1efc,
+ 0xa5c3, 0x1efd,
+ 0xa5e3, 0x1efe,
+ 0xa5e5, 0x1eff,
+ 0xa5e7, 0x1f00,
+ 0xa5ee, 0x1f01,
+ 0xa5f5, 0x1f02,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 japan1278EUCVEnc16 = {
+ 1,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee,
+ 0x00ef, 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6,
+ 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe,
+ 0x00ff, 0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106,
+ 0x0107, 0x0108, 0x0109, 0x010a, 0x010b, 0x010c, 0x010d, 0x010e,
+ 0x010f, 0x0110, 0x0111, 0x0112, 0x0113, 0x0114, 0x0115, 0x0116,
+ 0x0117, 0x0118, 0x0119, 0x011a, 0x011b, 0x011c, 0x011d, 0x011e,
+ 0x011f, 0x0120, 0x0121, 0x0122, 0x0123, 0x0124, 0x0125, 0x0126,
+ 0x0127, 0x0128, 0x0129, 0x012a, 0x012b, 0x012c, 0x012d, 0x012e,
+ 0x012f, 0x0130, 0x0131, 0x0132, 0x0133, 0x0134, 0x0135, 0x0136,
+ 0x0137, 0x0138, 0x0139, 0x013a, 0x013b, 0x013c, 0x013d, 0x013e,
+ 0x013f, 0x0140, 0x0141, 0x0142, 0x0143, 0x0144, 0x0145, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ japan1278EUCVMap2, 653
+};
+
+static Gushort japan1278HMap2[1250] = {
+ 0x0000, 0x0000,
+ 0x2121, 0x0279,
+ 0x2221, 0x02d7,
+ 0x2330, 0x030c,
+ 0x2341, 0x0316,
+ 0x2361, 0x0330,
+ 0x2421, 0x034a,
+ 0x2521, 0x039d,
+ 0x2621, 0x03f3,
+ 0x2641, 0x040b,
+ 0x2721, 0x0423,
+ 0x2751, 0x0444,
+ 0x3021, 0x0465,
+ 0x3022, 0x1dd1,
+ 0x3023, 0x0467,
+ 0x3029, 0x204a,
+ 0x302a, 0x046e,
+ 0x3032, 0x1f19,
+ 0x3033, 0x1ca2,
+ 0x3034, 0x0478,
+ 0x303b, 0x1dd2,
+ 0x303c, 0x0480,
+ 0x306e, 0x1dd3,
+ 0x306f, 0x04b3,
+ 0x3073, 0x1dd4,
+ 0x3074, 0x04b8,
+ 0x307c, 0x1dd5,
+ 0x307d, 0x04c1,
+ 0x3121, 0x04c3,
+ 0x312a, 0x1dd6,
+ 0x312b, 0x04cd,
+ 0x3135, 0x1dd7,
+ 0x3136, 0x04d8,
+ 0x3139, 0x1dd8,
+ 0x313a, 0x04dc,
+ 0x313d, 0x1dda,
+ 0x313e, 0x04e0,
+ 0x3142, 0x1ddb,
+ 0x3143, 0x04e5,
+ 0x316b, 0x1ddc,
+ 0x316c, 0x050e,
+ 0x3221, 0x0521,
+ 0x3228, 0x1ddd,
+ 0x3229, 0x1cc9,
+ 0x322a, 0x1dde,
+ 0x322b, 0x052b,
+ 0x3260, 0x1ddf,
+ 0x3261, 0x0561,
+ 0x327a, 0x1de0,
+ 0x327b, 0x057b,
+ 0x327d, 0x1de1,
+ 0x327e, 0x057e,
+ 0x3321, 0x057f,
+ 0x3322, 0x1de2,
+ 0x3323, 0x0581,
+ 0x3342, 0x1961,
+ 0x3343, 0x05a1,
+ 0x3349, 0x139f,
+ 0x334a, 0x05a8,
+ 0x3365, 0x1de3,
+ 0x3366, 0x05c4,
+ 0x336b, 0x1de4,
+ 0x336c, 0x05ca,
+ 0x3373, 0x1de5,
+ 0x3374, 0x05d2,
+ 0x3376, 0x1731,
+ 0x3377, 0x05d5,
+ 0x337a, 0x1de6,
+ 0x337b, 0x05d9,
+ 0x3421, 0x05dd,
+ 0x3442, 0x1de7,
+ 0x3443, 0x1572,
+ 0x3444, 0x0600,
+ 0x344d, 0x1de8,
+ 0x344e, 0x060a,
+ 0x3452, 0x1a20,
+ 0x3453, 0x060f,
+ 0x3465, 0x1de9,
+ 0x3466, 0x0622,
+ 0x3521, 0x063b,
+ 0x352b, 0x1dea,
+ 0x352c, 0x0646,
+ 0x3540, 0x1deb,
+ 0x3541, 0x065b,
+ 0x3621, 0x0699,
+ 0x3622, 0x1dec,
+ 0x3623, 0x069b,
+ 0x362a, 0x1ded,
+ 0x362b, 0x06a3,
+ 0x3646, 0x1d32,
+ 0x3647, 0x06bf,
+ 0x364f, 0x1dee,
+ 0x3650, 0x06c8,
+ 0x366d, 0x1def,
+ 0x366e, 0x06e6,
+ 0x3674, 0x1df0,
+ 0x3675, 0x06ed,
+ 0x367b, 0x1df1,
+ 0x367c, 0x06f4,
+ 0x367d, 0x1df2,
+ 0x367e, 0x06f6,
+ 0x3721, 0x06f7,
+ 0x3724, 0x1df3,
+ 0x3725, 0x06fb,
+ 0x3737, 0x1df4,
+ 0x3738, 0x070e,
+ 0x3745, 0x1df5,
+ 0x3746, 0x071c,
+ 0x374e, 0x1df6,
+ 0x374f, 0x0725,
+ 0x3752, 0x1df7,
+ 0x3753, 0x0729,
+ 0x3755, 0x1df8,
+ 0x3756, 0x072c,
+ 0x375b, 0x1c0d,
+ 0x375c, 0x0732,
+ 0x3764, 0x1df9,
+ 0x3765, 0x073b,
+ 0x3771, 0x1dfa,
+ 0x3772, 0x0748,
+ 0x3779, 0x1dfb,
+ 0x377a, 0x0750,
+ 0x377e, 0x1dfc,
+ 0x3821, 0x0755,
+ 0x3834, 0x1dfd,
+ 0x3835, 0x0769,
+ 0x3841, 0x1dfe,
+ 0x3842, 0x0776,
+ 0x3921, 0x07b3,
+ 0x392b, 0x1dff,
+ 0x392c, 0x07be,
+ 0x3937, 0x1e00,
+ 0x3938, 0x07ca,
+ 0x3942, 0x1e01,
+ 0x3943, 0x07d5,
+ 0x395c, 0x16dd,
+ 0x395d, 0x07ef,
+ 0x396d, 0x1e02,
+ 0x396e, 0x0800,
+ 0x3974, 0x1e03,
+ 0x3975, 0x0807,
+ 0x3979, 0x1e04,
+ 0x397a, 0x080c,
+ 0x3a21, 0x0811,
+ 0x3a53, 0x1e05,
+ 0x3a54, 0x0844,
+ 0x3a67, 0x1e06,
+ 0x3a68, 0x0858,
+ 0x3a74, 0x1e07,
+ 0x3a75, 0x0865,
+ 0x3b21, 0x086f,
+ 0x3b27, 0x1e08,
+ 0x3b28, 0x0876,
+ 0x3b2a, 0x1e09,
+ 0x3b2b, 0x0879,
+ 0x3b2c, 0x1e0a,
+ 0x3b2d, 0x087b,
+ 0x3b39, 0x1e0b,
+ 0x3b3a, 0x0888,
+ 0x3c21, 0x08cd,
+ 0x3c48, 0x1e0d,
+ 0x3c49, 0x1929,
+ 0x3c4a, 0x08f6,
+ 0x3c57, 0x1e0e,
+ 0x3c58, 0x0904,
+ 0x3c5d, 0x1e0f,
+ 0x3c5f, 0x090b,
+ 0x3d21, 0x092b,
+ 0x3d2b, 0x1e11,
+ 0x3d2c, 0x0936,
+ 0x3d36, 0x1e12,
+ 0x3d37, 0x0941,
+ 0x3d6c, 0x1e13,
+ 0x3d6e, 0x0978,
+ 0x3d72, 0x1e15,
+ 0x3d74, 0x097e,
+ 0x3e21, 0x0989,
+ 0x3e25, 0x1e17,
+ 0x3e26, 0x098e,
+ 0x3e33, 0x1e18,
+ 0x3e34, 0x099c,
+ 0x3e3f, 0x1e19,
+ 0x3e40, 0x09a8,
+ 0x3e55, 0x1e1a,
+ 0x3e56, 0x09be,
+ 0x3e5f, 0x1e1b,
+ 0x3e60, 0x09c8,
+ 0x3e64, 0x1e1c,
+ 0x3e65, 0x09cd,
+ 0x3f21, 0x09e7,
+ 0x3f2a, 0x1e1d,
+ 0x3f2b, 0x09f1,
+ 0x3f59, 0x1e1e,
+ 0x3f5a, 0x0a20,
+ 0x3f60, 0x1e1f,
+ 0x3f61, 0x0a27,
+ 0x3f69, 0x1e20,
+ 0x3f6a, 0x0a30,
+ 0x4021, 0x0a45,
+ 0x4022, 0x1e21,
+ 0x4023, 0x0a47,
+ 0x4042, 0x1e22,
+ 0x4043, 0x0a67,
+ 0x4066, 0x1e23,
+ 0x4067, 0x0a8b,
+ 0x4071, 0x1e24,
+ 0x4073, 0x0a97,
+ 0x4079, 0x1e26,
+ 0x407b, 0x0a9f,
+ 0x4121, 0x0aa3,
+ 0x4127, 0x1e28,
+ 0x4128, 0x1a6e,
+ 0x4129, 0x0aab,
+ 0x4139, 0x1e29,
+ 0x413a, 0x0abc,
+ 0x414c, 0x1e2a,
+ 0x414d, 0x0acf,
+ 0x414f, 0x1e2b,
+ 0x4150, 0x0ad2,
+ 0x415f, 0x1e2c,
+ 0x4160, 0x0ae2,
+ 0x4169, 0x1e2d,
+ 0x416a, 0x0aec,
+ 0x4221, 0x0b01,
+ 0x423d, 0x1e2e,
+ 0x423e, 0x0b1e,
+ 0x424d, 0x1e2f,
+ 0x424e, 0x0b2e,
+ 0x425c, 0x1e30,
+ 0x425d, 0x0b3d,
+ 0x4263, 0x1e31,
+ 0x4264, 0x0b44,
+ 0x426f, 0x1e32,
+ 0x4270, 0x0b50,
+ 0x4275, 0x1e33,
+ 0x4277, 0x0b57,
+ 0x427d, 0x1e35,
+ 0x427e, 0x0b5e,
+ 0x4321, 0x0b5f,
+ 0x4327, 0x1e36,
+ 0x4328, 0x0b66,
+ 0x4329, 0x1e37,
+ 0x432b, 0x0b69,
+ 0x432d, 0x1e39,
+ 0x432f, 0x0b6d,
+ 0x433d, 0x1e3b,
+ 0x433e, 0x0b7c,
+ 0x4370, 0x1e3c,
+ 0x4371, 0x0baf,
+ 0x4375, 0x1e3d,
+ 0x4376, 0x0bb4,
+ 0x437c, 0x1e3e,
+ 0x437d, 0x0bbb,
+ 0x4421, 0x0bbd,
+ 0x443d, 0x1e3f,
+ 0x443e, 0x0bda,
+ 0x4448, 0x1e40,
+ 0x4449, 0x0be5,
+ 0x444a, 0x1e41,
+ 0x444b, 0x0be7,
+ 0x444d, 0x1e42,
+ 0x444e, 0x0bea,
+ 0x444f, 0x1e43,
+ 0x4450, 0x0bec,
+ 0x4454, 0x204b,
+ 0x4455, 0x0bf1,
+ 0x445b, 0x11b5,
+ 0x445c, 0x0bf8,
+ 0x4521, 0x0c1b,
+ 0x4522, 0x1e44,
+ 0x4523, 0x0c1d,
+ 0x4527, 0x1e45,
+ 0x4528, 0x0c22,
+ 0x452e, 0x1e46,
+ 0x452f, 0x0c29,
+ 0x4536, 0x1e47,
+ 0x4537, 0x0c31,
+ 0x453f, 0x1e48,
+ 0x4540, 0x0c3a,
+ 0x4548, 0x1e49,
+ 0x4549, 0x0c43,
+ 0x454b, 0x1e4a,
+ 0x454c, 0x0c46,
+ 0x4551, 0x1e4b,
+ 0x4553, 0x0c4d,
+ 0x4557, 0x16df,
+ 0x4558, 0x0c52,
+ 0x4564, 0x1e4d,
+ 0x4565, 0x0c5f,
+ 0x456e, 0x1450,
+ 0x456f, 0x0c69,
+ 0x4573, 0x1536,
+ 0x4574, 0x0c6e,
+ 0x4578, 0x1e4e,
+ 0x4579, 0x0c73,
+ 0x4621, 0x0c79,
+ 0x463e, 0x1e4f,
+ 0x463f, 0x0c97,
+ 0x4642, 0x1e50,
+ 0x4643, 0x0c9b,
+ 0x4654, 0x1e51,
+ 0x4656, 0x0cae,
+ 0x465b, 0x1e53,
+ 0x465d, 0x0cb5,
+ 0x4661, 0x1e55,
+ 0x4662, 0x0cba,
+ 0x4666, 0x1e56,
+ 0x4668, 0x0cc0,
+ 0x466a, 0x1e58,
+ 0x466b, 0x0cc3,
+ 0x4676, 0x1aed,
+ 0x4677, 0x0ccf,
+ 0x4721, 0x0cd7,
+ 0x4729, 0x1e59,
+ 0x472a, 0x0ce0,
+ 0x4739, 0x1e5a,
+ 0x473a, 0x0cf0,
+ 0x4757, 0x1e5b,
+ 0x4758, 0x0d0e,
+ 0x4767, 0x1e5c,
+ 0x4768, 0x1989,
+ 0x4769, 0x1e5d,
+ 0x476a, 0x0d20,
+ 0x476d, 0x1e5e,
+ 0x476e, 0x0d24,
+ 0x4821, 0x0d35,
+ 0x4824, 0x1e5f,
+ 0x4825, 0x0d39,
+ 0x482e, 0x1e60,
+ 0x482f, 0x0d43,
+ 0x4830, 0x1e61,
+ 0x4831, 0x0d45,
+ 0x4854, 0x1e62,
+ 0x4855, 0x0d69,
+ 0x4862, 0x1e63,
+ 0x4863, 0x0d77,
+ 0x4875, 0x1e64,
+ 0x4876, 0x0d8a,
+ 0x4921, 0x0d93,
+ 0x4922, 0x1e65,
+ 0x4924, 0x0d96,
+ 0x492f, 0x1e67,
+ 0x4930, 0x143b,
+ 0x4931, 0x0da3,
+ 0x4932, 0x1e68,
+ 0x4933, 0x0da5,
+ 0x4935, 0x1e69,
+ 0x4936, 0x0da8,
+ 0x4940, 0x1e6a,
+ 0x4941, 0x0db3,
+ 0x494e, 0x1e6b,
+ 0x494f, 0x0dc1,
+ 0x4951, 0x1e6c,
+ 0x4952, 0x0dc4,
+ 0x4a21, 0x0df1,
+ 0x4a43, 0x1e6d,
+ 0x4a44, 0x0e14,
+ 0x4a4d, 0x1e6e,
+ 0x4a4e, 0x0e1e,
+ 0x4a5a, 0x1e6f,
+ 0x4a5b, 0x0e2b,
+ 0x4a79, 0x1e70,
+ 0x4a7a, 0x0e4a,
+ 0x4b21, 0x0e4f,
+ 0x4b22, 0x1e71,
+ 0x4b23, 0x0e51,
+ 0x4b29, 0x1e72,
+ 0x4b2a, 0x0e58,
+ 0x4b4b, 0x1e73,
+ 0x4b4c, 0x0e7a,
+ 0x4b6a, 0x1d33,
+ 0x4b6b, 0x0e99,
+ 0x4b70, 0x1e74,
+ 0x4b71, 0x0e9f,
+ 0x4b78, 0x1f2c,
+ 0x4b79, 0x102f,
+ 0x4b7a, 0x0ea8,
+ 0x4c21, 0x0ead,
+ 0x4c4d, 0x1e75,
+ 0x4c4e, 0x0eda,
+ 0x4c59, 0x1e76,
+ 0x4c5a, 0x0ee6,
+ 0x4c5f, 0x1e77,
+ 0x4c60, 0x0eec,
+ 0x4c62, 0x1e78,
+ 0x4c63, 0x0eef,
+ 0x4c79, 0x1935,
+ 0x4c7a, 0x1e79,
+ 0x4c7b, 0x0f07,
+ 0x4c7c, 0x1e7a,
+ 0x4c7d, 0x0f09,
+ 0x4c7e, 0x1e7b,
+ 0x4d21, 0x0f0b,
+ 0x4d32, 0x1e7c,
+ 0x4d33, 0x0f1d,
+ 0x4d50, 0x1e7d,
+ 0x4d51, 0x0f3b,
+ 0x4d54, 0x1e7e,
+ 0x4d55, 0x0f3f,
+ 0x4d5a, 0x1d34,
+ 0x4d5b, 0x0f45,
+ 0x4d69, 0x1e7f,
+ 0x4d6a, 0x0f54,
+ 0x4e21, 0x0f69,
+ 0x4e4b, 0x1e80,
+ 0x4e4c, 0x0f94,
+ 0x4e7a, 0x1e81,
+ 0x4e7c, 0x0fc4,
+ 0x4f21, 0x1e83,
+ 0x4f22, 0x0fc8,
+ 0x4f31, 0x1e84,
+ 0x4f32, 0x0fd8,
+ 0x4f36, 0x1777,
+ 0x4f37, 0x0fdd,
+ 0x4f39, 0x1e85,
+ 0x4f3a, 0x0fe0,
+ 0x5021, 0x0ffa,
+ 0x5056, 0x0ea7,
+ 0x5057, 0x1030,
+ 0x5121, 0x1058,
+ 0x513d, 0x1e86,
+ 0x513e, 0x1075,
+ 0x5147, 0x1e87,
+ 0x5148, 0x107f,
+ 0x514b, 0x1e88,
+ 0x514c, 0x1083,
+ 0x514d, 0x1e89,
+ 0x514e, 0x1085,
+ 0x5221, 0x10b6,
+ 0x5321, 0x1114,
+ 0x5330, 0x1e8a,
+ 0x5331, 0x1124,
+ 0x533a, 0x1e8b,
+ 0x533b, 0x112e,
+ 0x535e, 0x1e8d,
+ 0x535f, 0x1152,
+ 0x536b, 0x1e8e,
+ 0x536c, 0x115f,
+ 0x5421, 0x1172,
+ 0x5444, 0x1e8f,
+ 0x5445, 0x1196,
+ 0x5464, 0x0bf7,
+ 0x5465, 0x11b6,
+ 0x5521, 0x11d0,
+ 0x553d, 0x1e90,
+ 0x553e, 0x11ed,
+ 0x5563, 0x1e91,
+ 0x5564, 0x1213,
+ 0x5621, 0x122e,
+ 0x5622, 0x1e92,
+ 0x5623, 0x1230,
+ 0x5721, 0x128c,
+ 0x5821, 0x12ea,
+ 0x5824, 0x1e94,
+ 0x5825, 0x12ee,
+ 0x5921, 0x1348,
+ 0x5960, 0x1e95,
+ 0x5961, 0x1388,
+ 0x596c, 0x1e96,
+ 0x596d, 0x1394,
+ 0x5978, 0x05a7,
+ 0x5979, 0x13a0,
+ 0x5a21, 0x13a6,
+ 0x5a39, 0x1e97,
+ 0x5a3a, 0x13bf,
+ 0x5a4d, 0x1e98,
+ 0x5a4e, 0x13d3,
+ 0x5b21, 0x1404,
+ 0x5b45, 0x1e99,
+ 0x5b46, 0x1429,
+ 0x5b4a, 0x1e9a,
+ 0x5b4b, 0x142e,
+ 0x5b58, 0x0da2,
+ 0x5b59, 0x143c,
+ 0x5b6b, 0x1e9b,
+ 0x5b6c, 0x144f,
+ 0x5b6d, 0x0c68,
+ 0x5b6e, 0x1451,
+ 0x5b74, 0x1e9c,
+ 0x5b75, 0x1458,
+ 0x5c21, 0x1462,
+ 0x5d21, 0x14c0,
+ 0x5e21, 0x151e,
+ 0x5e39, 0x0c6d,
+ 0x5e3a, 0x1537,
+ 0x5e50, 0x1e9d,
+ 0x5e51, 0x154e,
+ 0x5e75, 0x05ff,
+ 0x5e76, 0x1573,
+ 0x5f21, 0x157c,
+ 0x6021, 0x15da,
+ 0x6026, 0x1e9f,
+ 0x6027, 0x15e0,
+ 0x605f, 0x1ea0,
+ 0x6060, 0x1619,
+ 0x6076, 0x1d35,
+ 0x6077, 0x1630,
+ 0x6121, 0x1638,
+ 0x612b, 0x1ea1,
+ 0x612c, 0x1643,
+ 0x6130, 0x1ea2,
+ 0x6132, 0x1649,
+ 0x6221, 0x1696,
+ 0x622b, 0x1ea4,
+ 0x622c, 0x16a1,
+ 0x6268, 0x07ee,
+ 0x6269, 0x16de,
+ 0x626a, 0x0c51,
+ 0x626b, 0x16e0,
+ 0x626f, 0x1ea5,
+ 0x6270, 0x16e5,
+ 0x6321, 0x16f4,
+ 0x634a, 0x1ea6,
+ 0x634b, 0x171e,
+ 0x6354, 0x1ea7,
+ 0x6355, 0x1728,
+ 0x635e, 0x05d4,
+ 0x635f, 0x1732,
+ 0x6421, 0x1752,
+ 0x6439, 0x1ea8,
+ 0x643a, 0x176b,
+ 0x6446, 0x0fdc,
+ 0x6447, 0x1778,
+ 0x6464, 0x1ea9,
+ 0x6465, 0x1796,
+ 0x646e, 0x1eaa,
+ 0x646f, 0x17a0,
+ 0x6521, 0x17b0,
+ 0x6539, 0x1eab,
+ 0x653a, 0x17c9,
+ 0x653b, 0x1eac,
+ 0x653c, 0x17cb,
+ 0x6546, 0x1ead,
+ 0x6547, 0x17d6,
+ 0x6621, 0x180e,
+ 0x6646, 0x1eae,
+ 0x6647, 0x1834,
+ 0x6721, 0x186c,
+ 0x6764, 0x1eaf,
+ 0x6765, 0x18b0,
+ 0x6769, 0x1eb0,
+ 0x676a, 0x18b5,
+ 0x6772, 0x1eb1,
+ 0x6773, 0x18be,
+ 0x6821, 0x18ca,
+ 0x6834, 0x1eb2,
+ 0x6835, 0x18de,
+ 0x683b, 0x1eb3,
+ 0x683c, 0x18e5,
+ 0x6874, 0x1eb4,
+ 0x6875, 0x191e,
+ 0x6921, 0x1928,
+ 0x6922, 0x08f5,
+ 0x6923, 0x192a,
+ 0x692e, 0x0f05,
+ 0x692f, 0x1936,
+ 0x695a, 0x05a0,
+ 0x695b, 0x1962,
+ 0x6a21, 0x1986,
+ 0x6a24, 0x0d1e,
+ 0x6a25, 0x198a,
+ 0x6a27, 0x1eb6,
+ 0x6a28, 0x198d,
+ 0x6a3d, 0x1eb7,
+ 0x6a3e, 0x19a3,
+ 0x6a6f, 0x1eb8,
+ 0x6a70, 0x19d5,
+ 0x6b21, 0x19e4,
+ 0x6b32, 0x1eb9,
+ 0x6b33, 0x19f6,
+ 0x6b5d, 0x060e,
+ 0x6b5e, 0x1a21,
+ 0x6b66, 0x1eba,
+ 0x6b67, 0x1a2a,
+ 0x6b76, 0x1ebb,
+ 0x6b77, 0x1a3a,
+ 0x6c21, 0x1a42,
+ 0x6c4d, 0x0aaa,
+ 0x6c4e, 0x1a6f,
+ 0x6c69, 0x1ebc,
+ 0x6c6a, 0x1a8b,
+ 0x6c74, 0x1ebd,
+ 0x6c75, 0x1a96,
+ 0x6d21, 0x1aa0,
+ 0x6d4e, 0x1ebe,
+ 0x6d4f, 0x1ace,
+ 0x6d6c, 0x1ebf,
+ 0x6d6d, 0x1aec,
+ 0x6d6e, 0x1ec0,
+ 0x6d6f, 0x1aee,
+ 0x6e21, 0x1afe,
+ 0x6e29, 0x1ec1,
+ 0x6e2a, 0x1b07,
+ 0x6e3d, 0x1ec2,
+ 0x6e3e, 0x1b1b,
+ 0x6e57, 0x1ec3,
+ 0x6e58, 0x1b35,
+ 0x6f21, 0x1b5c,
+ 0x7021, 0x1bba,
+ 0x7045, 0x1ec6,
+ 0x7046, 0x1bdf,
+ 0x7051, 0x1ec7,
+ 0x7052, 0x1beb,
+ 0x7057, 0x1ec8,
+ 0x7058, 0x1bf1,
+ 0x7074, 0x0731,
+ 0x7075, 0x1ec9,
+ 0x7076, 0x1c0f,
+ 0x7121, 0x1c18,
+ 0x7221, 0x1c76,
+ 0x722d, 0x1eca,
+ 0x722e, 0x1c83,
+ 0x723c, 0x1ecb,
+ 0x723d, 0x1c92,
+ 0x724d, 0x0477,
+ 0x724e, 0x1ecc,
+ 0x724f, 0x1ca4,
+ 0x7274, 0x0529,
+ 0x7275, 0x1cca,
+ 0x7321, 0x1cd4,
+ 0x7351, 0x1ecd,
+ 0x7352, 0x1d05,
+ 0x737d, 0x1ece,
+ 0x737e, 0x1d31,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 japan1278HEnc16 = {
+ 0,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ japan1278HMap2, 625
+};
+
+static Gushort japan1278RKSJHMap2[1252] = {
+ 0x0000, 0x0000,
+ 0x8140, 0x0279,
+ 0x8180, 0x02b8,
+ 0x824f, 0x030c,
+ 0x8260, 0x0316,
+ 0x8281, 0x0330,
+ 0x829f, 0x034a,
+ 0x8340, 0x039d,
+ 0x8380, 0x03dc,
+ 0x839f, 0x03f3,
+ 0x83bf, 0x040b,
+ 0x8440, 0x0423,
+ 0x8470, 0x0444,
+ 0x8480, 0x0453,
+ 0x889f, 0x0465,
+ 0x88a0, 0x1dd1,
+ 0x88a1, 0x0467,
+ 0x88a7, 0x204a,
+ 0x88a8, 0x046e,
+ 0x88b0, 0x1f19,
+ 0x88b1, 0x1ca2,
+ 0x88b2, 0x0478,
+ 0x88b9, 0x1dd2,
+ 0x88ba, 0x0480,
+ 0x88ec, 0x1dd3,
+ 0x88ed, 0x04b3,
+ 0x88f1, 0x1dd4,
+ 0x88f2, 0x04b8,
+ 0x88fa, 0x1dd5,
+ 0x88fb, 0x04c1,
+ 0x8940, 0x04c3,
+ 0x8949, 0x1dd6,
+ 0x894a, 0x04cd,
+ 0x8954, 0x1dd7,
+ 0x8955, 0x04d8,
+ 0x8958, 0x1dd8,
+ 0x8959, 0x04dc,
+ 0x895c, 0x1dda,
+ 0x895d, 0x04e0,
+ 0x8961, 0x1ddb,
+ 0x8962, 0x04e5,
+ 0x8980, 0x0502,
+ 0x898b, 0x1ddc,
+ 0x898c, 0x050e,
+ 0x89a6, 0x1ddd,
+ 0x89a7, 0x1cc9,
+ 0x89a8, 0x1dde,
+ 0x89a9, 0x052b,
+ 0x89de, 0x1ddf,
+ 0x89df, 0x0561,
+ 0x89f8, 0x1de0,
+ 0x89f9, 0x057b,
+ 0x89fb, 0x1de1,
+ 0x89fc, 0x057e,
+ 0x8a40, 0x057f,
+ 0x8a41, 0x1de2,
+ 0x8a42, 0x0581,
+ 0x8a61, 0x1961,
+ 0x8a62, 0x05a1,
+ 0x8a68, 0x139f,
+ 0x8a69, 0x05a8,
+ 0x8a80, 0x05be,
+ 0x8a85, 0x1de3,
+ 0x8a86, 0x05c4,
+ 0x8a8b, 0x1de4,
+ 0x8a8c, 0x05ca,
+ 0x8a93, 0x1de5,
+ 0x8a94, 0x05d2,
+ 0x8a96, 0x1731,
+ 0x8a97, 0x05d5,
+ 0x8a9a, 0x1de6,
+ 0x8a9b, 0x05d9,
+ 0x8ac0, 0x1de7,
+ 0x8ac1, 0x1572,
+ 0x8ac2, 0x0600,
+ 0x8acb, 0x1de8,
+ 0x8acc, 0x060a,
+ 0x8ad0, 0x1a20,
+ 0x8ad1, 0x060f,
+ 0x8ae3, 0x1de9,
+ 0x8ae4, 0x0622,
+ 0x8b40, 0x063b,
+ 0x8b4a, 0x1dea,
+ 0x8b4b, 0x0646,
+ 0x8b5f, 0x1deb,
+ 0x8b60, 0x065b,
+ 0x8b80, 0x067a,
+ 0x8ba0, 0x1dec,
+ 0x8ba1, 0x069b,
+ 0x8ba8, 0x1ded,
+ 0x8ba9, 0x06a3,
+ 0x8bc4, 0x1d32,
+ 0x8bc5, 0x06bf,
+ 0x8bcd, 0x1dee,
+ 0x8bce, 0x06c8,
+ 0x8beb, 0x1def,
+ 0x8bec, 0x06e6,
+ 0x8bf2, 0x1df0,
+ 0x8bf3, 0x06ed,
+ 0x8bf9, 0x1df1,
+ 0x8bfa, 0x06f4,
+ 0x8bfb, 0x1df2,
+ 0x8bfc, 0x06f6,
+ 0x8c40, 0x06f7,
+ 0x8c43, 0x1df3,
+ 0x8c44, 0x06fb,
+ 0x8c56, 0x1df4,
+ 0x8c57, 0x070e,
+ 0x8c64, 0x1df5,
+ 0x8c65, 0x071c,
+ 0x8c6d, 0x1df6,
+ 0x8c6e, 0x0725,
+ 0x8c71, 0x1df7,
+ 0x8c72, 0x0729,
+ 0x8c74, 0x1df8,
+ 0x8c75, 0x072c,
+ 0x8c7a, 0x1c0d,
+ 0x8c7b, 0x0732,
+ 0x8c80, 0x0736,
+ 0x8c84, 0x1df9,
+ 0x8c85, 0x073b,
+ 0x8c91, 0x1dfa,
+ 0x8c92, 0x0748,
+ 0x8c99, 0x1dfb,
+ 0x8c9a, 0x0750,
+ 0x8c9e, 0x1dfc,
+ 0x8c9f, 0x0755,
+ 0x8cb2, 0x1dfd,
+ 0x8cb3, 0x0769,
+ 0x8cbf, 0x1dfe,
+ 0x8cc0, 0x0776,
+ 0x8d40, 0x07b3,
+ 0x8d4a, 0x1dff,
+ 0x8d4b, 0x07be,
+ 0x8d56, 0x1e00,
+ 0x8d57, 0x07ca,
+ 0x8d61, 0x1e01,
+ 0x8d62, 0x07d5,
+ 0x8d7b, 0x16dd,
+ 0x8d7c, 0x07ef,
+ 0x8d80, 0x07f2,
+ 0x8d8d, 0x1e02,
+ 0x8d8e, 0x0800,
+ 0x8d94, 0x1e03,
+ 0x8d95, 0x0807,
+ 0x8d99, 0x1e04,
+ 0x8d9a, 0x080c,
+ 0x8dd1, 0x1e05,
+ 0x8dd2, 0x0844,
+ 0x8de5, 0x1e06,
+ 0x8de6, 0x0858,
+ 0x8df2, 0x1e07,
+ 0x8df3, 0x0865,
+ 0x8e40, 0x086f,
+ 0x8e46, 0x1e08,
+ 0x8e47, 0x0876,
+ 0x8e49, 0x1e09,
+ 0x8e4a, 0x0879,
+ 0x8e4b, 0x1e0a,
+ 0x8e4c, 0x087b,
+ 0x8e58, 0x1e0b,
+ 0x8e59, 0x0888,
+ 0x8e80, 0x08ae,
+ 0x8ec6, 0x1e0d,
+ 0x8ec7, 0x1929,
+ 0x8ec8, 0x08f6,
+ 0x8ed5, 0x1e0e,
+ 0x8ed6, 0x0904,
+ 0x8edb, 0x1e0f,
+ 0x8edd, 0x090b,
+ 0x8f40, 0x092b,
+ 0x8f4a, 0x1e11,
+ 0x8f4b, 0x0936,
+ 0x8f55, 0x1e12,
+ 0x8f56, 0x0941,
+ 0x8f80, 0x096a,
+ 0x8f8c, 0x1e13,
+ 0x8f8e, 0x0978,
+ 0x8f92, 0x1e15,
+ 0x8f94, 0x097e,
+ 0x8fa3, 0x1e17,
+ 0x8fa4, 0x098e,
+ 0x8fb1, 0x1e18,
+ 0x8fb2, 0x099c,
+ 0x8fbd, 0x1e19,
+ 0x8fbe, 0x09a8,
+ 0x8fd3, 0x1e1a,
+ 0x8fd4, 0x09be,
+ 0x8fdd, 0x1e1b,
+ 0x8fde, 0x09c8,
+ 0x8fe2, 0x1e1c,
+ 0x8fe3, 0x09cd,
+ 0x9040, 0x09e7,
+ 0x9049, 0x1e1d,
+ 0x904a, 0x09f1,
+ 0x9078, 0x1e1e,
+ 0x9079, 0x0a20,
+ 0x9080, 0x1e1f,
+ 0x9081, 0x0a27,
+ 0x9089, 0x1e20,
+ 0x908a, 0x0a30,
+ 0x90a0, 0x1e21,
+ 0x90a1, 0x0a47,
+ 0x90c0, 0x1e22,
+ 0x90c1, 0x0a67,
+ 0x90e4, 0x1e23,
+ 0x90e5, 0x0a8b,
+ 0x90ef, 0x1e24,
+ 0x90f1, 0x0a97,
+ 0x90f7, 0x1e26,
+ 0x90f9, 0x0a9f,
+ 0x9140, 0x0aa3,
+ 0x9146, 0x1e28,
+ 0x9147, 0x1a6e,
+ 0x9148, 0x0aab,
+ 0x9158, 0x1e29,
+ 0x9159, 0x0abc,
+ 0x916b, 0x1e2a,
+ 0x916c, 0x0acf,
+ 0x916e, 0x1e2b,
+ 0x916f, 0x0ad2,
+ 0x917e, 0x1e2c,
+ 0x9180, 0x0ae2,
+ 0x9189, 0x1e2d,
+ 0x918a, 0x0aec,
+ 0x91bb, 0x1e2e,
+ 0x91bc, 0x0b1e,
+ 0x91cb, 0x1e2f,
+ 0x91cc, 0x0b2e,
+ 0x91da, 0x1e30,
+ 0x91db, 0x0b3d,
+ 0x91e1, 0x1e31,
+ 0x91e2, 0x0b44,
+ 0x91ed, 0x1e32,
+ 0x91ee, 0x0b50,
+ 0x91f3, 0x1e33,
+ 0x91f5, 0x0b57,
+ 0x91fb, 0x1e35,
+ 0x91fc, 0x0b5e,
+ 0x9240, 0x0b5f,
+ 0x9246, 0x1e36,
+ 0x9247, 0x0b66,
+ 0x9248, 0x1e37,
+ 0x924a, 0x0b69,
+ 0x924c, 0x1e39,
+ 0x924e, 0x0b6d,
+ 0x925c, 0x1e3b,
+ 0x925d, 0x0b7c,
+ 0x9280, 0x0b9e,
+ 0x9290, 0x1e3c,
+ 0x9291, 0x0baf,
+ 0x9295, 0x1e3d,
+ 0x9296, 0x0bb4,
+ 0x929c, 0x1e3e,
+ 0x929d, 0x0bbb,
+ 0x92bb, 0x1e3f,
+ 0x92bc, 0x0bda,
+ 0x92c6, 0x1e40,
+ 0x92c7, 0x0be5,
+ 0x92c8, 0x1e41,
+ 0x92c9, 0x0be7,
+ 0x92cb, 0x1e42,
+ 0x92cc, 0x0bea,
+ 0x92cd, 0x1e43,
+ 0x92ce, 0x0bec,
+ 0x92d2, 0x204b,
+ 0x92d3, 0x0bf1,
+ 0x92d9, 0x11b5,
+ 0x92da, 0x0bf8,
+ 0x9340, 0x0c1b,
+ 0x9341, 0x1e44,
+ 0x9342, 0x0c1d,
+ 0x9346, 0x1e45,
+ 0x9347, 0x0c22,
+ 0x934d, 0x1e46,
+ 0x934e, 0x0c29,
+ 0x9355, 0x1e47,
+ 0x9356, 0x0c31,
+ 0x935e, 0x1e48,
+ 0x935f, 0x0c3a,
+ 0x9367, 0x1e49,
+ 0x9368, 0x0c43,
+ 0x936a, 0x1e4a,
+ 0x936b, 0x0c46,
+ 0x9370, 0x1e4b,
+ 0x9372, 0x0c4d,
+ 0x9376, 0x16df,
+ 0x9377, 0x0c52,
+ 0x9380, 0x0c5a,
+ 0x9384, 0x1e4d,
+ 0x9385, 0x0c5f,
+ 0x938e, 0x1450,
+ 0x938f, 0x0c69,
+ 0x9393, 0x1536,
+ 0x9394, 0x0c6e,
+ 0x9398, 0x1e4e,
+ 0x9399, 0x0c73,
+ 0x93bc, 0x1e4f,
+ 0x93bd, 0x0c97,
+ 0x93c0, 0x1e50,
+ 0x93c1, 0x0c9b,
+ 0x93d2, 0x1e51,
+ 0x93d4, 0x0cae,
+ 0x93d9, 0x1e53,
+ 0x93db, 0x0cb5,
+ 0x93df, 0x1e55,
+ 0x93e0, 0x0cba,
+ 0x93e4, 0x1e56,
+ 0x93e6, 0x0cc0,
+ 0x93e8, 0x1e58,
+ 0x93e9, 0x0cc3,
+ 0x93f4, 0x1aed,
+ 0x93f5, 0x0ccf,
+ 0x9440, 0x0cd7,
+ 0x9448, 0x1e59,
+ 0x9449, 0x0ce0,
+ 0x9458, 0x1e5a,
+ 0x9459, 0x0cf0,
+ 0x9476, 0x1e5b,
+ 0x9477, 0x0d0e,
+ 0x9480, 0x0d16,
+ 0x9487, 0x1e5c,
+ 0x9488, 0x1989,
+ 0x9489, 0x1e5d,
+ 0x948a, 0x0d20,
+ 0x948d, 0x1e5e,
+ 0x948e, 0x0d24,
+ 0x94a2, 0x1e5f,
+ 0x94a3, 0x0d39,
+ 0x94ac, 0x1e60,
+ 0x94ad, 0x0d43,
+ 0x94ae, 0x1e61,
+ 0x94af, 0x0d45,
+ 0x94d2, 0x1e62,
+ 0x94d3, 0x0d69,
+ 0x94e0, 0x1e63,
+ 0x94e1, 0x0d77,
+ 0x94f3, 0x1e64,
+ 0x94f4, 0x0d8a,
+ 0x9540, 0x0d93,
+ 0x9541, 0x1e65,
+ 0x9543, 0x0d96,
+ 0x954e, 0x1e67,
+ 0x954f, 0x143b,
+ 0x9550, 0x0da3,
+ 0x9551, 0x1e68,
+ 0x9552, 0x0da5,
+ 0x9554, 0x1e69,
+ 0x9555, 0x0da8,
+ 0x955f, 0x1e6a,
+ 0x9560, 0x0db3,
+ 0x956d, 0x1e6b,
+ 0x956e, 0x0dc1,
+ 0x9570, 0x1e6c,
+ 0x9571, 0x0dc4,
+ 0x9580, 0x0dd2,
+ 0x95c1, 0x1e6d,
+ 0x95c2, 0x0e14,
+ 0x95cb, 0x1e6e,
+ 0x95cc, 0x0e1e,
+ 0x95d8, 0x1e6f,
+ 0x95d9, 0x0e2b,
+ 0x95f7, 0x1e70,
+ 0x95f8, 0x0e4a,
+ 0x9640, 0x0e4f,
+ 0x9641, 0x1e71,
+ 0x9642, 0x0e51,
+ 0x9648, 0x1e72,
+ 0x9649, 0x0e58,
+ 0x966a, 0x1e73,
+ 0x966b, 0x0e7a,
+ 0x9680, 0x0e8e,
+ 0x968a, 0x1d33,
+ 0x968b, 0x0e99,
+ 0x9690, 0x1e74,
+ 0x9691, 0x0e9f,
+ 0x9698, 0x1f2c,
+ 0x9699, 0x102f,
+ 0x969a, 0x0ea8,
+ 0x96cb, 0x1e75,
+ 0x96cc, 0x0eda,
+ 0x96d7, 0x1e76,
+ 0x96d8, 0x0ee6,
+ 0x96dd, 0x1e77,
+ 0x96de, 0x0eec,
+ 0x96e0, 0x1e78,
+ 0x96e1, 0x0eef,
+ 0x96f7, 0x1935,
+ 0x96f8, 0x1e79,
+ 0x96f9, 0x0f07,
+ 0x96fa, 0x1e7a,
+ 0x96fb, 0x0f09,
+ 0x96fc, 0x1e7b,
+ 0x9740, 0x0f0b,
+ 0x9751, 0x1e7c,
+ 0x9752, 0x0f1d,
+ 0x976f, 0x1e7d,
+ 0x9770, 0x0f3b,
+ 0x9773, 0x1e7e,
+ 0x9774, 0x0f3f,
+ 0x9779, 0x1d34,
+ 0x977a, 0x0f45,
+ 0x9780, 0x0f4a,
+ 0x9789, 0x1e7f,
+ 0x978a, 0x0f54,
+ 0x97c9, 0x1e80,
+ 0x97ca, 0x0f94,
+ 0x97f8, 0x1e81,
+ 0x97fa, 0x0fc4,
+ 0x9840, 0x1e83,
+ 0x9841, 0x0fc8,
+ 0x9850, 0x1e84,
+ 0x9851, 0x0fd8,
+ 0x9855, 0x1777,
+ 0x9856, 0x0fdd,
+ 0x9858, 0x1e85,
+ 0x9859, 0x0fe0,
+ 0x989f, 0x0ffa,
+ 0x98d4, 0x0ea7,
+ 0x98d5, 0x1030,
+ 0x9940, 0x1058,
+ 0x995c, 0x1e86,
+ 0x995d, 0x1075,
+ 0x9966, 0x1e87,
+ 0x9967, 0x107f,
+ 0x996a, 0x1e88,
+ 0x996b, 0x1083,
+ 0x996c, 0x1e89,
+ 0x996d, 0x1085,
+ 0x9980, 0x1097,
+ 0x9a40, 0x1114,
+ 0x9a4f, 0x1e8a,
+ 0x9a50, 0x1124,
+ 0x9a59, 0x1e8b,
+ 0x9a5a, 0x112e,
+ 0x9a7d, 0x1e8d,
+ 0x9a7e, 0x1152,
+ 0x9a80, 0x1153,
+ 0x9a8b, 0x1e8e,
+ 0x9a8c, 0x115f,
+ 0x9ac2, 0x1e8f,
+ 0x9ac3, 0x1196,
+ 0x9ae2, 0x0bf7,
+ 0x9ae3, 0x11b6,
+ 0x9b40, 0x11d0,
+ 0x9b5c, 0x1e90,
+ 0x9b5d, 0x11ed,
+ 0x9b80, 0x120f,
+ 0x9b83, 0x1e91,
+ 0x9b84, 0x1213,
+ 0x9ba0, 0x1e92,
+ 0x9ba1, 0x1230,
+ 0x9c40, 0x128c,
+ 0x9c80, 0x12cb,
+ 0x9ca2, 0x1e94,
+ 0x9ca3, 0x12ee,
+ 0x9d40, 0x1348,
+ 0x9d80, 0x1e95,
+ 0x9d81, 0x1388,
+ 0x9d8c, 0x1e96,
+ 0x9d8d, 0x1394,
+ 0x9d98, 0x05a7,
+ 0x9d99, 0x13a0,
+ 0x9db7, 0x1e97,
+ 0x9db8, 0x13bf,
+ 0x9dcb, 0x1e98,
+ 0x9dcc, 0x13d3,
+ 0x9e40, 0x1404,
+ 0x9e64, 0x1e99,
+ 0x9e65, 0x1429,
+ 0x9e69, 0x1e9a,
+ 0x9e6a, 0x142e,
+ 0x9e77, 0x0da2,
+ 0x9e78, 0x143c,
+ 0x9e80, 0x1443,
+ 0x9e8b, 0x1e9b,
+ 0x9e8c, 0x144f,
+ 0x9e8d, 0x0c68,
+ 0x9e8e, 0x1451,
+ 0x9e94, 0x1e9c,
+ 0x9e95, 0x1458,
+ 0x9f40, 0x14c0,
+ 0x9f80, 0x14ff,
+ 0x9fb7, 0x0c6d,
+ 0x9fb8, 0x1537,
+ 0x9fce, 0x1e9d,
+ 0x9fcf, 0x154e,
+ 0x9ff3, 0x05ff,
+ 0x9ff4, 0x1573,
+ 0xe040, 0x157c,
+ 0xe080, 0x15bb,
+ 0xe0a4, 0x1e9f,
+ 0xe0a5, 0x15e0,
+ 0xe0dd, 0x1ea0,
+ 0xe0de, 0x1619,
+ 0xe0f4, 0x1d35,
+ 0xe0f5, 0x1630,
+ 0xe140, 0x1638,
+ 0xe14a, 0x1ea1,
+ 0xe14b, 0x1643,
+ 0xe14f, 0x1ea2,
+ 0xe151, 0x1649,
+ 0xe180, 0x1677,
+ 0xe1a9, 0x1ea4,
+ 0xe1aa, 0x16a1,
+ 0xe1e6, 0x07ee,
+ 0xe1e7, 0x16de,
+ 0xe1e8, 0x0c51,
+ 0xe1e9, 0x16e0,
+ 0xe1ed, 0x1ea5,
+ 0xe1ee, 0x16e5,
+ 0xe240, 0x16f4,
+ 0xe269, 0x1ea6,
+ 0xe26a, 0x171e,
+ 0xe273, 0x1ea7,
+ 0xe274, 0x1728,
+ 0xe27d, 0x05d4,
+ 0xe27e, 0x1732,
+ 0xe280, 0x1733,
+ 0xe2b7, 0x1ea8,
+ 0xe2b8, 0x176b,
+ 0xe2c4, 0x0fdc,
+ 0xe2c5, 0x1778,
+ 0xe2e2, 0x1ea9,
+ 0xe2e3, 0x1796,
+ 0xe2ec, 0x1eaa,
+ 0xe2ed, 0x17a0,
+ 0xe340, 0x17b0,
+ 0xe358, 0x1eab,
+ 0xe359, 0x17c9,
+ 0xe35a, 0x1eac,
+ 0xe35b, 0x17cb,
+ 0xe365, 0x1ead,
+ 0xe366, 0x17d6,
+ 0xe380, 0x17ef,
+ 0xe3c4, 0x1eae,
+ 0xe3c5, 0x1834,
+ 0xe440, 0x186c,
+ 0xe480, 0x18ab,
+ 0xe484, 0x1eaf,
+ 0xe485, 0x18b0,
+ 0xe489, 0x1eb0,
+ 0xe48a, 0x18b5,
+ 0xe492, 0x1eb1,
+ 0xe493, 0x18be,
+ 0xe4b2, 0x1eb2,
+ 0xe4b3, 0x18de,
+ 0xe4b9, 0x1eb3,
+ 0xe4ba, 0x18e5,
+ 0xe4f2, 0x1eb4,
+ 0xe4f3, 0x191e,
+ 0xe540, 0x1928,
+ 0xe541, 0x08f5,
+ 0xe542, 0x192a,
+ 0xe54d, 0x0f05,
+ 0xe54e, 0x1936,
+ 0xe579, 0x05a0,
+ 0xe57a, 0x1962,
+ 0xe580, 0x1967,
+ 0xe5a2, 0x0d1e,
+ 0xe5a3, 0x198a,
+ 0xe5a5, 0x1eb6,
+ 0xe5a6, 0x198d,
+ 0xe5bb, 0x1eb7,
+ 0xe5bc, 0x19a3,
+ 0xe5ed, 0x1eb8,
+ 0xe5ee, 0x19d5,
+ 0xe640, 0x19e4,
+ 0xe651, 0x1eb9,
+ 0xe652, 0x19f6,
+ 0xe67c, 0x060e,
+ 0xe67d, 0x1a21,
+ 0xe680, 0x1a23,
+ 0xe686, 0x1eba,
+ 0xe687, 0x1a2a,
+ 0xe696, 0x1ebb,
+ 0xe697, 0x1a3a,
+ 0xe6cb, 0x0aaa,
+ 0xe6cc, 0x1a6f,
+ 0xe6e7, 0x1ebc,
+ 0xe6e8, 0x1a8b,
+ 0xe6f2, 0x1ebd,
+ 0xe6f3, 0x1a96,
+ 0xe740, 0x1aa0,
+ 0xe76d, 0x1ebe,
+ 0xe76e, 0x1ace,
+ 0xe780, 0x1adf,
+ 0xe78c, 0x1ebf,
+ 0xe78d, 0x1aec,
+ 0xe78e, 0x1ec0,
+ 0xe78f, 0x1aee,
+ 0xe7a7, 0x1ec1,
+ 0xe7a8, 0x1b07,
+ 0xe7bb, 0x1ec2,
+ 0xe7bc, 0x1b1b,
+ 0xe7d5, 0x1ec3,
+ 0xe7d6, 0x1b35,
+ 0xe840, 0x1b5c,
+ 0xe880, 0x1b9b,
+ 0xe8c3, 0x1ec6,
+ 0xe8c4, 0x1bdf,
+ 0xe8cf, 0x1ec7,
+ 0xe8d0, 0x1beb,
+ 0xe8d5, 0x1ec8,
+ 0xe8d6, 0x1bf1,
+ 0xe8f2, 0x0731,
+ 0xe8f3, 0x1ec9,
+ 0xe8f4, 0x1c0f,
+ 0xe940, 0x1c18,
+ 0xe980, 0x1c57,
+ 0xe9ab, 0x1eca,
+ 0xe9ac, 0x1c83,
+ 0xe9ba, 0x1ecb,
+ 0xe9bb, 0x1c92,
+ 0xe9cb, 0x0477,
+ 0xe9cc, 0x1ecc,
+ 0xe9cd, 0x1ca4,
+ 0xe9f2, 0x0529,
+ 0xe9f3, 0x1cca,
+ 0xea40, 0x1cd4,
+ 0xea70, 0x1ecd,
+ 0xea71, 0x1d05,
+ 0xea80, 0x1d13,
+ 0xea9d, 0x1ece,
+ 0xea9e, 0x1d31,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 japan1278RKSJHEnc16 = {
+ 0,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee,
+ 0x00ef, 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6,
+ 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe,
+ 0x00ff, 0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106,
+ 0x0107, 0x0108, 0x0109, 0x010a, 0x010b, 0x010c, 0x010d, 0x010e,
+ 0x010f, 0x0110, 0x0111, 0x0112, 0x0113, 0x0114, 0x0115, 0x0116,
+ 0x0117, 0x0118, 0x0119, 0x011a, 0x011b, 0x011c, 0x011d, 0x011e,
+ 0x011f, 0x0120, 0x0121, 0x0122, 0x0123, 0x0124, 0x0125, 0x0126,
+ 0x0127, 0x0128, 0x0129, 0x012a, 0x012b, 0x012c, 0x012d, 0x012e,
+ 0x012f, 0x0130, 0x0131, 0x0132, 0x0133, 0x0134, 0x0135, 0x0136,
+ 0x0137, 0x0138, 0x0139, 0x013a, 0x013b, 0x013c, 0x013d, 0x013e,
+ 0x013f, 0x0140, 0x0141, 0x0142, 0x0143, 0x0144, 0x0145, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0146, 0x0147, 0x0148, 0x0149, 0x014a, 0x014b, 0x014c, 0x014d,
+ 0x014e, 0x014f, 0x0150, 0x0151, 0x0152, 0x0153, 0x0154, 0x0155,
+ 0x0156, 0x0157, 0x0158, 0x0159, 0x015a, 0x015b, 0x015c, 0x015d,
+ 0x015e, 0x015f, 0x0160, 0x0161, 0x0162, 0x0163, 0x0164, 0x0165,
+ 0x0166, 0x0167, 0x0168, 0x0169, 0x016a, 0x016b, 0x016c, 0x016d,
+ 0x016e, 0x016f, 0x0170, 0x0171, 0x0172, 0x0173, 0x0174, 0x0175,
+ 0x0176, 0x0177, 0x0178, 0x0179, 0x017a, 0x017b, 0x017c, 0x017d,
+ 0x017e, 0x017f, 0x0180, 0x0181, 0x0182, 0x0183, 0x0184, 0x0185,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ japan1278RKSJHMap2, 626
+};
+
+static Gushort japan1278RKSJVMap2[1306] = {
+ 0x0000, 0x0000,
+ 0x8140, 0x0279,
+ 0x8180, 0x02b8,
+ 0x824f, 0x030c,
+ 0x8260, 0x0316,
+ 0x8281, 0x0330,
+ 0x829f, 0x034a,
+ 0x8340, 0x039d,
+ 0x8380, 0x03dc,
+ 0x839f, 0x03f3,
+ 0x83bf, 0x040b,
+ 0x8440, 0x0423,
+ 0x8470, 0x0444,
+ 0x8480, 0x0453,
+ 0x889f, 0x0465,
+ 0x88a0, 0x1dd1,
+ 0x88a1, 0x0467,
+ 0x88a7, 0x204a,
+ 0x88a8, 0x046e,
+ 0x88b0, 0x1f19,
+ 0x88b1, 0x1ca2,
+ 0x88b2, 0x0478,
+ 0x88b9, 0x1dd2,
+ 0x88ba, 0x0480,
+ 0x88ec, 0x1dd3,
+ 0x88ed, 0x04b3,
+ 0x88f1, 0x1dd4,
+ 0x88f2, 0x04b8,
+ 0x88fa, 0x1dd5,
+ 0x88fb, 0x04c1,
+ 0x8940, 0x04c3,
+ 0x8949, 0x1dd6,
+ 0x894a, 0x04cd,
+ 0x8954, 0x1dd7,
+ 0x8955, 0x04d8,
+ 0x8958, 0x1dd8,
+ 0x8959, 0x04dc,
+ 0x895c, 0x1dda,
+ 0x895d, 0x04e0,
+ 0x8961, 0x1ddb,
+ 0x8962, 0x04e5,
+ 0x8980, 0x0502,
+ 0x898b, 0x1ddc,
+ 0x898c, 0x050e,
+ 0x89a6, 0x1ddd,
+ 0x89a7, 0x1cc9,
+ 0x89a8, 0x1dde,
+ 0x89a9, 0x052b,
+ 0x89de, 0x1ddf,
+ 0x89df, 0x0561,
+ 0x89f8, 0x1de0,
+ 0x89f9, 0x057b,
+ 0x89fb, 0x1de1,
+ 0x89fc, 0x057e,
+ 0x8a40, 0x057f,
+ 0x8a41, 0x1de2,
+ 0x8a42, 0x0581,
+ 0x8a61, 0x1961,
+ 0x8a62, 0x05a1,
+ 0x8a68, 0x139f,
+ 0x8a69, 0x05a8,
+ 0x8a80, 0x05be,
+ 0x8a85, 0x1de3,
+ 0x8a86, 0x05c4,
+ 0x8a8b, 0x1de4,
+ 0x8a8c, 0x05ca,
+ 0x8a93, 0x1de5,
+ 0x8a94, 0x05d2,
+ 0x8a96, 0x1731,
+ 0x8a97, 0x05d5,
+ 0x8a9a, 0x1de6,
+ 0x8a9b, 0x05d9,
+ 0x8ac0, 0x1de7,
+ 0x8ac1, 0x1572,
+ 0x8ac2, 0x0600,
+ 0x8acb, 0x1de8,
+ 0x8acc, 0x060a,
+ 0x8ad0, 0x1a20,
+ 0x8ad1, 0x060f,
+ 0x8ae3, 0x1de9,
+ 0x8ae4, 0x0622,
+ 0x8b40, 0x063b,
+ 0x8b4a, 0x1dea,
+ 0x8b4b, 0x0646,
+ 0x8b5f, 0x1deb,
+ 0x8b60, 0x065b,
+ 0x8b80, 0x067a,
+ 0x8ba0, 0x1dec,
+ 0x8ba1, 0x069b,
+ 0x8ba8, 0x1ded,
+ 0x8ba9, 0x06a3,
+ 0x8bc4, 0x1d32,
+ 0x8bc5, 0x06bf,
+ 0x8bcd, 0x1dee,
+ 0x8bce, 0x06c8,
+ 0x8beb, 0x1def,
+ 0x8bec, 0x06e6,
+ 0x8bf2, 0x1df0,
+ 0x8bf3, 0x06ed,
+ 0x8bf9, 0x1df1,
+ 0x8bfa, 0x06f4,
+ 0x8bfb, 0x1df2,
+ 0x8bfc, 0x06f6,
+ 0x8c40, 0x06f7,
+ 0x8c43, 0x1df3,
+ 0x8c44, 0x06fb,
+ 0x8c56, 0x1df4,
+ 0x8c57, 0x070e,
+ 0x8c64, 0x1df5,
+ 0x8c65, 0x071c,
+ 0x8c6d, 0x1df6,
+ 0x8c6e, 0x0725,
+ 0x8c71, 0x1df7,
+ 0x8c72, 0x0729,
+ 0x8c74, 0x1df8,
+ 0x8c75, 0x072c,
+ 0x8c7a, 0x1c0d,
+ 0x8c7b, 0x0732,
+ 0x8c80, 0x0736,
+ 0x8c84, 0x1df9,
+ 0x8c85, 0x073b,
+ 0x8c91, 0x1dfa,
+ 0x8c92, 0x0748,
+ 0x8c99, 0x1dfb,
+ 0x8c9a, 0x0750,
+ 0x8c9e, 0x1dfc,
+ 0x8c9f, 0x0755,
+ 0x8cb2, 0x1dfd,
+ 0x8cb3, 0x0769,
+ 0x8cbf, 0x1dfe,
+ 0x8cc0, 0x0776,
+ 0x8d40, 0x07b3,
+ 0x8d4a, 0x1dff,
+ 0x8d4b, 0x07be,
+ 0x8d56, 0x1e00,
+ 0x8d57, 0x07ca,
+ 0x8d61, 0x1e01,
+ 0x8d62, 0x07d5,
+ 0x8d7b, 0x16dd,
+ 0x8d7c, 0x07ef,
+ 0x8d80, 0x07f2,
+ 0x8d8d, 0x1e02,
+ 0x8d8e, 0x0800,
+ 0x8d94, 0x1e03,
+ 0x8d95, 0x0807,
+ 0x8d99, 0x1e04,
+ 0x8d9a, 0x080c,
+ 0x8dd1, 0x1e05,
+ 0x8dd2, 0x0844,
+ 0x8de5, 0x1e06,
+ 0x8de6, 0x0858,
+ 0x8df2, 0x1e07,
+ 0x8df3, 0x0865,
+ 0x8e40, 0x086f,
+ 0x8e46, 0x1e08,
+ 0x8e47, 0x0876,
+ 0x8e49, 0x1e09,
+ 0x8e4a, 0x0879,
+ 0x8e4b, 0x1e0a,
+ 0x8e4c, 0x087b,
+ 0x8e58, 0x1e0b,
+ 0x8e59, 0x0888,
+ 0x8e80, 0x08ae,
+ 0x8ec6, 0x1e0d,
+ 0x8ec7, 0x1929,
+ 0x8ec8, 0x08f6,
+ 0x8ed5, 0x1e0e,
+ 0x8ed6, 0x0904,
+ 0x8edb, 0x1e0f,
+ 0x8edd, 0x090b,
+ 0x8f40, 0x092b,
+ 0x8f4a, 0x1e11,
+ 0x8f4b, 0x0936,
+ 0x8f55, 0x1e12,
+ 0x8f56, 0x0941,
+ 0x8f80, 0x096a,
+ 0x8f8c, 0x1e13,
+ 0x8f8e, 0x0978,
+ 0x8f92, 0x1e15,
+ 0x8f94, 0x097e,
+ 0x8fa3, 0x1e17,
+ 0x8fa4, 0x098e,
+ 0x8fb1, 0x1e18,
+ 0x8fb2, 0x099c,
+ 0x8fbd, 0x1e19,
+ 0x8fbe, 0x09a8,
+ 0x8fd3, 0x1e1a,
+ 0x8fd4, 0x09be,
+ 0x8fdd, 0x1e1b,
+ 0x8fde, 0x09c8,
+ 0x8fe2, 0x1e1c,
+ 0x8fe3, 0x09cd,
+ 0x9040, 0x09e7,
+ 0x9049, 0x1e1d,
+ 0x904a, 0x09f1,
+ 0x9078, 0x1e1e,
+ 0x9079, 0x0a20,
+ 0x9080, 0x1e1f,
+ 0x9081, 0x0a27,
+ 0x9089, 0x1e20,
+ 0x908a, 0x0a30,
+ 0x90a0, 0x1e21,
+ 0x90a1, 0x0a47,
+ 0x90c0, 0x1e22,
+ 0x90c1, 0x0a67,
+ 0x90e4, 0x1e23,
+ 0x90e5, 0x0a8b,
+ 0x90ef, 0x1e24,
+ 0x90f1, 0x0a97,
+ 0x90f7, 0x1e26,
+ 0x90f9, 0x0a9f,
+ 0x9140, 0x0aa3,
+ 0x9146, 0x1e28,
+ 0x9147, 0x1a6e,
+ 0x9148, 0x0aab,
+ 0x9158, 0x1e29,
+ 0x9159, 0x0abc,
+ 0x916b, 0x1e2a,
+ 0x916c, 0x0acf,
+ 0x916e, 0x1e2b,
+ 0x916f, 0x0ad2,
+ 0x917e, 0x1e2c,
+ 0x9180, 0x0ae2,
+ 0x9189, 0x1e2d,
+ 0x918a, 0x0aec,
+ 0x91bb, 0x1e2e,
+ 0x91bc, 0x0b1e,
+ 0x91cb, 0x1e2f,
+ 0x91cc, 0x0b2e,
+ 0x91da, 0x1e30,
+ 0x91db, 0x0b3d,
+ 0x91e1, 0x1e31,
+ 0x91e2, 0x0b44,
+ 0x91ed, 0x1e32,
+ 0x91ee, 0x0b50,
+ 0x91f3, 0x1e33,
+ 0x91f5, 0x0b57,
+ 0x91fb, 0x1e35,
+ 0x91fc, 0x0b5e,
+ 0x9240, 0x0b5f,
+ 0x9246, 0x1e36,
+ 0x9247, 0x0b66,
+ 0x9248, 0x1e37,
+ 0x924a, 0x0b69,
+ 0x924c, 0x1e39,
+ 0x924e, 0x0b6d,
+ 0x925c, 0x1e3b,
+ 0x925d, 0x0b7c,
+ 0x9280, 0x0b9e,
+ 0x9290, 0x1e3c,
+ 0x9291, 0x0baf,
+ 0x9295, 0x1e3d,
+ 0x9296, 0x0bb4,
+ 0x929c, 0x1e3e,
+ 0x929d, 0x0bbb,
+ 0x92bb, 0x1e3f,
+ 0x92bc, 0x0bda,
+ 0x92c6, 0x1e40,
+ 0x92c7, 0x0be5,
+ 0x92c8, 0x1e41,
+ 0x92c9, 0x0be7,
+ 0x92cb, 0x1e42,
+ 0x92cc, 0x0bea,
+ 0x92cd, 0x1e43,
+ 0x92ce, 0x0bec,
+ 0x92d2, 0x204b,
+ 0x92d3, 0x0bf1,
+ 0x92d9, 0x11b5,
+ 0x92da, 0x0bf8,
+ 0x9340, 0x0c1b,
+ 0x9341, 0x1e44,
+ 0x9342, 0x0c1d,
+ 0x9346, 0x1e45,
+ 0x9347, 0x0c22,
+ 0x934d, 0x1e46,
+ 0x934e, 0x0c29,
+ 0x9355, 0x1e47,
+ 0x9356, 0x0c31,
+ 0x935e, 0x1e48,
+ 0x935f, 0x0c3a,
+ 0x9367, 0x1e49,
+ 0x9368, 0x0c43,
+ 0x936a, 0x1e4a,
+ 0x936b, 0x0c46,
+ 0x9370, 0x1e4b,
+ 0x9372, 0x0c4d,
+ 0x9376, 0x16df,
+ 0x9377, 0x0c52,
+ 0x9380, 0x0c5a,
+ 0x9384, 0x1e4d,
+ 0x9385, 0x0c5f,
+ 0x938e, 0x1450,
+ 0x938f, 0x0c69,
+ 0x9393, 0x1536,
+ 0x9394, 0x0c6e,
+ 0x9398, 0x1e4e,
+ 0x9399, 0x0c73,
+ 0x93bc, 0x1e4f,
+ 0x93bd, 0x0c97,
+ 0x93c0, 0x1e50,
+ 0x93c1, 0x0c9b,
+ 0x93d2, 0x1e51,
+ 0x93d4, 0x0cae,
+ 0x93d9, 0x1e53,
+ 0x93db, 0x0cb5,
+ 0x93df, 0x1e55,
+ 0x93e0, 0x0cba,
+ 0x93e4, 0x1e56,
+ 0x93e6, 0x0cc0,
+ 0x93e8, 0x1e58,
+ 0x93e9, 0x0cc3,
+ 0x93f4, 0x1aed,
+ 0x93f5, 0x0ccf,
+ 0x9440, 0x0cd7,
+ 0x9448, 0x1e59,
+ 0x9449, 0x0ce0,
+ 0x9458, 0x1e5a,
+ 0x9459, 0x0cf0,
+ 0x9476, 0x1e5b,
+ 0x9477, 0x0d0e,
+ 0x9480, 0x0d16,
+ 0x9487, 0x1e5c,
+ 0x9488, 0x1989,
+ 0x9489, 0x1e5d,
+ 0x948a, 0x0d20,
+ 0x948d, 0x1e5e,
+ 0x948e, 0x0d24,
+ 0x94a2, 0x1e5f,
+ 0x94a3, 0x0d39,
+ 0x94ac, 0x1e60,
+ 0x94ad, 0x0d43,
+ 0x94ae, 0x1e61,
+ 0x94af, 0x0d45,
+ 0x94d2, 0x1e62,
+ 0x94d3, 0x0d69,
+ 0x94e0, 0x1e63,
+ 0x94e1, 0x0d77,
+ 0x94f3, 0x1e64,
+ 0x94f4, 0x0d8a,
+ 0x9540, 0x0d93,
+ 0x9541, 0x1e65,
+ 0x9543, 0x0d96,
+ 0x954e, 0x1e67,
+ 0x954f, 0x143b,
+ 0x9550, 0x0da3,
+ 0x9551, 0x1e68,
+ 0x9552, 0x0da5,
+ 0x9554, 0x1e69,
+ 0x9555, 0x0da8,
+ 0x955f, 0x1e6a,
+ 0x9560, 0x0db3,
+ 0x956d, 0x1e6b,
+ 0x956e, 0x0dc1,
+ 0x9570, 0x1e6c,
+ 0x9571, 0x0dc4,
+ 0x9580, 0x0dd2,
+ 0x95c1, 0x1e6d,
+ 0x95c2, 0x0e14,
+ 0x95cb, 0x1e6e,
+ 0x95cc, 0x0e1e,
+ 0x95d8, 0x1e6f,
+ 0x95d9, 0x0e2b,
+ 0x95f7, 0x1e70,
+ 0x95f8, 0x0e4a,
+ 0x9640, 0x0e4f,
+ 0x9641, 0x1e71,
+ 0x9642, 0x0e51,
+ 0x9648, 0x1e72,
+ 0x9649, 0x0e58,
+ 0x966a, 0x1e73,
+ 0x966b, 0x0e7a,
+ 0x9680, 0x0e8e,
+ 0x968a, 0x1d33,
+ 0x968b, 0x0e99,
+ 0x9690, 0x1e74,
+ 0x9691, 0x0e9f,
+ 0x9698, 0x1f2c,
+ 0x9699, 0x102f,
+ 0x969a, 0x0ea8,
+ 0x96cb, 0x1e75,
+ 0x96cc, 0x0eda,
+ 0x96d7, 0x1e76,
+ 0x96d8, 0x0ee6,
+ 0x96dd, 0x1e77,
+ 0x96de, 0x0eec,
+ 0x96e0, 0x1e78,
+ 0x96e1, 0x0eef,
+ 0x96f7, 0x1935,
+ 0x96f8, 0x1e79,
+ 0x96f9, 0x0f07,
+ 0x96fa, 0x1e7a,
+ 0x96fb, 0x0f09,
+ 0x96fc, 0x1e7b,
+ 0x9740, 0x0f0b,
+ 0x9751, 0x1e7c,
+ 0x9752, 0x0f1d,
+ 0x976f, 0x1e7d,
+ 0x9770, 0x0f3b,
+ 0x9773, 0x1e7e,
+ 0x9774, 0x0f3f,
+ 0x9779, 0x1d34,
+ 0x977a, 0x0f45,
+ 0x9780, 0x0f4a,
+ 0x9789, 0x1e7f,
+ 0x978a, 0x0f54,
+ 0x97c9, 0x1e80,
+ 0x97ca, 0x0f94,
+ 0x97f8, 0x1e81,
+ 0x97fa, 0x0fc4,
+ 0x9840, 0x1e83,
+ 0x9841, 0x0fc8,
+ 0x9850, 0x1e84,
+ 0x9851, 0x0fd8,
+ 0x9855, 0x1777,
+ 0x9856, 0x0fdd,
+ 0x9858, 0x1e85,
+ 0x9859, 0x0fe0,
+ 0x989f, 0x0ffa,
+ 0x98d4, 0x0ea7,
+ 0x98d5, 0x1030,
+ 0x9940, 0x1058,
+ 0x995c, 0x1e86,
+ 0x995d, 0x1075,
+ 0x9966, 0x1e87,
+ 0x9967, 0x107f,
+ 0x996a, 0x1e88,
+ 0x996b, 0x1083,
+ 0x996c, 0x1e89,
+ 0x996d, 0x1085,
+ 0x9980, 0x1097,
+ 0x9a40, 0x1114,
+ 0x9a4f, 0x1e8a,
+ 0x9a50, 0x1124,
+ 0x9a59, 0x1e8b,
+ 0x9a5a, 0x112e,
+ 0x9a7d, 0x1e8d,
+ 0x9a7e, 0x1152,
+ 0x9a80, 0x1153,
+ 0x9a8b, 0x1e8e,
+ 0x9a8c, 0x115f,
+ 0x9ac2, 0x1e8f,
+ 0x9ac3, 0x1196,
+ 0x9ae2, 0x0bf7,
+ 0x9ae3, 0x11b6,
+ 0x9b40, 0x11d0,
+ 0x9b5c, 0x1e90,
+ 0x9b5d, 0x11ed,
+ 0x9b80, 0x120f,
+ 0x9b83, 0x1e91,
+ 0x9b84, 0x1213,
+ 0x9ba0, 0x1e92,
+ 0x9ba1, 0x1230,
+ 0x9c40, 0x128c,
+ 0x9c80, 0x12cb,
+ 0x9ca2, 0x1e94,
+ 0x9ca3, 0x12ee,
+ 0x9d40, 0x1348,
+ 0x9d80, 0x1e95,
+ 0x9d81, 0x1388,
+ 0x9d8c, 0x1e96,
+ 0x9d8d, 0x1394,
+ 0x9d98, 0x05a7,
+ 0x9d99, 0x13a0,
+ 0x9db7, 0x1e97,
+ 0x9db8, 0x13bf,
+ 0x9dcb, 0x1e98,
+ 0x9dcc, 0x13d3,
+ 0x9e40, 0x1404,
+ 0x9e64, 0x1e99,
+ 0x9e65, 0x1429,
+ 0x9e69, 0x1e9a,
+ 0x9e6a, 0x142e,
+ 0x9e77, 0x0da2,
+ 0x9e78, 0x143c,
+ 0x9e80, 0x1443,
+ 0x9e8b, 0x1e9b,
+ 0x9e8c, 0x144f,
+ 0x9e8d, 0x0c68,
+ 0x9e8e, 0x1451,
+ 0x9e94, 0x1e9c,
+ 0x9e95, 0x1458,
+ 0x9f40, 0x14c0,
+ 0x9f80, 0x14ff,
+ 0x9fb7, 0x0c6d,
+ 0x9fb8, 0x1537,
+ 0x9fce, 0x1e9d,
+ 0x9fcf, 0x154e,
+ 0x9ff3, 0x05ff,
+ 0x9ff4, 0x1573,
+ 0xe040, 0x157c,
+ 0xe080, 0x15bb,
+ 0xe0a4, 0x1e9f,
+ 0xe0a5, 0x15e0,
+ 0xe0dd, 0x1ea0,
+ 0xe0de, 0x1619,
+ 0xe0f4, 0x1d35,
+ 0xe0f5, 0x1630,
+ 0xe140, 0x1638,
+ 0xe14a, 0x1ea1,
+ 0xe14b, 0x1643,
+ 0xe14f, 0x1ea2,
+ 0xe151, 0x1649,
+ 0xe180, 0x1677,
+ 0xe1a9, 0x1ea4,
+ 0xe1aa, 0x16a1,
+ 0xe1e6, 0x07ee,
+ 0xe1e7, 0x16de,
+ 0xe1e8, 0x0c51,
+ 0xe1e9, 0x16e0,
+ 0xe1ed, 0x1ea5,
+ 0xe1ee, 0x16e5,
+ 0xe240, 0x16f4,
+ 0xe269, 0x1ea6,
+ 0xe26a, 0x171e,
+ 0xe273, 0x1ea7,
+ 0xe274, 0x1728,
+ 0xe27d, 0x05d4,
+ 0xe27e, 0x1732,
+ 0xe280, 0x1733,
+ 0xe2b7, 0x1ea8,
+ 0xe2b8, 0x176b,
+ 0xe2c4, 0x0fdc,
+ 0xe2c5, 0x1778,
+ 0xe2e2, 0x1ea9,
+ 0xe2e3, 0x1796,
+ 0xe2ec, 0x1eaa,
+ 0xe2ed, 0x17a0,
+ 0xe340, 0x17b0,
+ 0xe358, 0x1eab,
+ 0xe359, 0x17c9,
+ 0xe35a, 0x1eac,
+ 0xe35b, 0x17cb,
+ 0xe365, 0x1ead,
+ 0xe366, 0x17d6,
+ 0xe380, 0x17ef,
+ 0xe3c4, 0x1eae,
+ 0xe3c5, 0x1834,
+ 0xe440, 0x186c,
+ 0xe480, 0x18ab,
+ 0xe484, 0x1eaf,
+ 0xe485, 0x18b0,
+ 0xe489, 0x1eb0,
+ 0xe48a, 0x18b5,
+ 0xe492, 0x1eb1,
+ 0xe493, 0x18be,
+ 0xe4b2, 0x1eb2,
+ 0xe4b3, 0x18de,
+ 0xe4b9, 0x1eb3,
+ 0xe4ba, 0x18e5,
+ 0xe4f2, 0x1eb4,
+ 0xe4f3, 0x191e,
+ 0xe540, 0x1928,
+ 0xe541, 0x08f5,
+ 0xe542, 0x192a,
+ 0xe54d, 0x0f05,
+ 0xe54e, 0x1936,
+ 0xe579, 0x05a0,
+ 0xe57a, 0x1962,
+ 0xe580, 0x1967,
+ 0xe5a2, 0x0d1e,
+ 0xe5a3, 0x198a,
+ 0xe5a5, 0x1eb6,
+ 0xe5a6, 0x198d,
+ 0xe5bb, 0x1eb7,
+ 0xe5bc, 0x19a3,
+ 0xe5ed, 0x1eb8,
+ 0xe5ee, 0x19d5,
+ 0xe640, 0x19e4,
+ 0xe651, 0x1eb9,
+ 0xe652, 0x19f6,
+ 0xe67c, 0x060e,
+ 0xe67d, 0x1a21,
+ 0xe680, 0x1a23,
+ 0xe686, 0x1eba,
+ 0xe687, 0x1a2a,
+ 0xe696, 0x1ebb,
+ 0xe697, 0x1a3a,
+ 0xe6cb, 0x0aaa,
+ 0xe6cc, 0x1a6f,
+ 0xe6e7, 0x1ebc,
+ 0xe6e8, 0x1a8b,
+ 0xe6f2, 0x1ebd,
+ 0xe6f3, 0x1a96,
+ 0xe740, 0x1aa0,
+ 0xe76d, 0x1ebe,
+ 0xe76e, 0x1ace,
+ 0xe780, 0x1adf,
+ 0xe78c, 0x1ebf,
+ 0xe78d, 0x1aec,
+ 0xe78e, 0x1ec0,
+ 0xe78f, 0x1aee,
+ 0xe7a7, 0x1ec1,
+ 0xe7a8, 0x1b07,
+ 0xe7bb, 0x1ec2,
+ 0xe7bc, 0x1b1b,
+ 0xe7d5, 0x1ec3,
+ 0xe7d6, 0x1b35,
+ 0xe840, 0x1b5c,
+ 0xe880, 0x1b9b,
+ 0xe8c3, 0x1ec6,
+ 0xe8c4, 0x1bdf,
+ 0xe8cf, 0x1ec7,
+ 0xe8d0, 0x1beb,
+ 0xe8d5, 0x1ec8,
+ 0xe8d6, 0x1bf1,
+ 0xe8f2, 0x0731,
+ 0xe8f3, 0x1ec9,
+ 0xe8f4, 0x1c0f,
+ 0xe940, 0x1c18,
+ 0xe980, 0x1c57,
+ 0xe9ab, 0x1eca,
+ 0xe9ac, 0x1c83,
+ 0xe9ba, 0x1ecb,
+ 0xe9bb, 0x1c92,
+ 0xe9cb, 0x0477,
+ 0xe9cc, 0x1ecc,
+ 0xe9cd, 0x1ca4,
+ 0xe9f2, 0x0529,
+ 0xe9f3, 0x1cca,
+ 0xea40, 0x1cd4,
+ 0xea70, 0x1ecd,
+ 0xea71, 0x1d05,
+ 0xea80, 0x1d13,
+ 0xea9d, 0x1ece,
+ 0xea9e, 0x1d31,
+ 0x8141, 0x1ecf,
+ 0x8150, 0x1ed1,
+ 0x815b, 0x1ed3,
+ 0x8160, 0x1ed6,
+ 0x8169, 0x1edb,
+ 0x8181, 0x1eed,
+ 0x829f, 0x1eee,
+ 0x82a1, 0x1eef,
+ 0x82a3, 0x1ef0,
+ 0x82a5, 0x1ef1,
+ 0x82a7, 0x1ef2,
+ 0x82c1, 0x1ef3,
+ 0x82e1, 0x1ef4,
+ 0x82e3, 0x1ef5,
+ 0x82e5, 0x1ef6,
+ 0x82ec, 0x1ef7,
+ 0x8340, 0x1ef8,
+ 0x8342, 0x1ef9,
+ 0x8344, 0x1efa,
+ 0x8346, 0x1efb,
+ 0x8348, 0x1efc,
+ 0x8362, 0x1efd,
+ 0x8383, 0x1efe,
+ 0x8385, 0x1eff,
+ 0x8387, 0x1f00,
+ 0x838e, 0x1f01,
+ 0x8395, 0x1f02,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 japan1278RKSJVEnc16 = {
+ 1,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee,
+ 0x00ef, 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6,
+ 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe,
+ 0x00ff, 0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106,
+ 0x0107, 0x0108, 0x0109, 0x010a, 0x010b, 0x010c, 0x010d, 0x010e,
+ 0x010f, 0x0110, 0x0111, 0x0112, 0x0113, 0x0114, 0x0115, 0x0116,
+ 0x0117, 0x0118, 0x0119, 0x011a, 0x011b, 0x011c, 0x011d, 0x011e,
+ 0x011f, 0x0120, 0x0121, 0x0122, 0x0123, 0x0124, 0x0125, 0x0126,
+ 0x0127, 0x0128, 0x0129, 0x012a, 0x012b, 0x012c, 0x012d, 0x012e,
+ 0x012f, 0x0130, 0x0131, 0x0132, 0x0133, 0x0134, 0x0135, 0x0136,
+ 0x0137, 0x0138, 0x0139, 0x013a, 0x013b, 0x013c, 0x013d, 0x013e,
+ 0x013f, 0x0140, 0x0141, 0x0142, 0x0143, 0x0144, 0x0145, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0146, 0x0147, 0x0148, 0x0149, 0x014a, 0x014b, 0x014c, 0x014d,
+ 0x014e, 0x014f, 0x0150, 0x0151, 0x0152, 0x0153, 0x0154, 0x0155,
+ 0x0156, 0x0157, 0x0158, 0x0159, 0x015a, 0x015b, 0x015c, 0x015d,
+ 0x015e, 0x015f, 0x0160, 0x0161, 0x0162, 0x0163, 0x0164, 0x0165,
+ 0x0166, 0x0167, 0x0168, 0x0169, 0x016a, 0x016b, 0x016c, 0x016d,
+ 0x016e, 0x016f, 0x0170, 0x0171, 0x0172, 0x0173, 0x0174, 0x0175,
+ 0x0176, 0x0177, 0x0178, 0x0179, 0x017a, 0x017b, 0x017c, 0x017d,
+ 0x017e, 0x017f, 0x0180, 0x0181, 0x0182, 0x0183, 0x0184, 0x0185,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ japan1278RKSJVMap2, 653
+};
+
+static Gushort japan1278VMap2[1304] = {
+ 0x0000, 0x0000,
+ 0x2121, 0x0279,
+ 0x2221, 0x02d7,
+ 0x2330, 0x030c,
+ 0x2341, 0x0316,
+ 0x2361, 0x0330,
+ 0x2421, 0x034a,
+ 0x2521, 0x039d,
+ 0x2621, 0x03f3,
+ 0x2641, 0x040b,
+ 0x2721, 0x0423,
+ 0x2751, 0x0444,
+ 0x3021, 0x0465,
+ 0x3022, 0x1dd1,
+ 0x3023, 0x0467,
+ 0x3029, 0x204a,
+ 0x302a, 0x046e,
+ 0x3032, 0x1f19,
+ 0x3033, 0x1ca2,
+ 0x3034, 0x0478,
+ 0x303b, 0x1dd2,
+ 0x303c, 0x0480,
+ 0x306e, 0x1dd3,
+ 0x306f, 0x04b3,
+ 0x3073, 0x1dd4,
+ 0x3074, 0x04b8,
+ 0x307c, 0x1dd5,
+ 0x307d, 0x04c1,
+ 0x3121, 0x04c3,
+ 0x312a, 0x1dd6,
+ 0x312b, 0x04cd,
+ 0x3135, 0x1dd7,
+ 0x3136, 0x04d8,
+ 0x3139, 0x1dd8,
+ 0x313a, 0x04dc,
+ 0x313d, 0x1dda,
+ 0x313e, 0x04e0,
+ 0x3142, 0x1ddb,
+ 0x3143, 0x04e5,
+ 0x316b, 0x1ddc,
+ 0x316c, 0x050e,
+ 0x3221, 0x0521,
+ 0x3228, 0x1ddd,
+ 0x3229, 0x1cc9,
+ 0x322a, 0x1dde,
+ 0x322b, 0x052b,
+ 0x3260, 0x1ddf,
+ 0x3261, 0x0561,
+ 0x327a, 0x1de0,
+ 0x327b, 0x057b,
+ 0x327d, 0x1de1,
+ 0x327e, 0x057e,
+ 0x3321, 0x057f,
+ 0x3322, 0x1de2,
+ 0x3323, 0x0581,
+ 0x3342, 0x1961,
+ 0x3343, 0x05a1,
+ 0x3349, 0x139f,
+ 0x334a, 0x05a8,
+ 0x3365, 0x1de3,
+ 0x3366, 0x05c4,
+ 0x336b, 0x1de4,
+ 0x336c, 0x05ca,
+ 0x3373, 0x1de5,
+ 0x3374, 0x05d2,
+ 0x3376, 0x1731,
+ 0x3377, 0x05d5,
+ 0x337a, 0x1de6,
+ 0x337b, 0x05d9,
+ 0x3421, 0x05dd,
+ 0x3442, 0x1de7,
+ 0x3443, 0x1572,
+ 0x3444, 0x0600,
+ 0x344d, 0x1de8,
+ 0x344e, 0x060a,
+ 0x3452, 0x1a20,
+ 0x3453, 0x060f,
+ 0x3465, 0x1de9,
+ 0x3466, 0x0622,
+ 0x3521, 0x063b,
+ 0x352b, 0x1dea,
+ 0x352c, 0x0646,
+ 0x3540, 0x1deb,
+ 0x3541, 0x065b,
+ 0x3621, 0x0699,
+ 0x3622, 0x1dec,
+ 0x3623, 0x069b,
+ 0x362a, 0x1ded,
+ 0x362b, 0x06a3,
+ 0x3646, 0x1d32,
+ 0x3647, 0x06bf,
+ 0x364f, 0x1dee,
+ 0x3650, 0x06c8,
+ 0x366d, 0x1def,
+ 0x366e, 0x06e6,
+ 0x3674, 0x1df0,
+ 0x3675, 0x06ed,
+ 0x367b, 0x1df1,
+ 0x367c, 0x06f4,
+ 0x367d, 0x1df2,
+ 0x367e, 0x06f6,
+ 0x3721, 0x06f7,
+ 0x3724, 0x1df3,
+ 0x3725, 0x06fb,
+ 0x3737, 0x1df4,
+ 0x3738, 0x070e,
+ 0x3745, 0x1df5,
+ 0x3746, 0x071c,
+ 0x374e, 0x1df6,
+ 0x374f, 0x0725,
+ 0x3752, 0x1df7,
+ 0x3753, 0x0729,
+ 0x3755, 0x1df8,
+ 0x3756, 0x072c,
+ 0x375b, 0x1c0d,
+ 0x375c, 0x0732,
+ 0x3764, 0x1df9,
+ 0x3765, 0x073b,
+ 0x3771, 0x1dfa,
+ 0x3772, 0x0748,
+ 0x3779, 0x1dfb,
+ 0x377a, 0x0750,
+ 0x377e, 0x1dfc,
+ 0x3821, 0x0755,
+ 0x3834, 0x1dfd,
+ 0x3835, 0x0769,
+ 0x3841, 0x1dfe,
+ 0x3842, 0x0776,
+ 0x3921, 0x07b3,
+ 0x392b, 0x1dff,
+ 0x392c, 0x07be,
+ 0x3937, 0x1e00,
+ 0x3938, 0x07ca,
+ 0x3942, 0x1e01,
+ 0x3943, 0x07d5,
+ 0x395c, 0x16dd,
+ 0x395d, 0x07ef,
+ 0x396d, 0x1e02,
+ 0x396e, 0x0800,
+ 0x3974, 0x1e03,
+ 0x3975, 0x0807,
+ 0x3979, 0x1e04,
+ 0x397a, 0x080c,
+ 0x3a21, 0x0811,
+ 0x3a53, 0x1e05,
+ 0x3a54, 0x0844,
+ 0x3a67, 0x1e06,
+ 0x3a68, 0x0858,
+ 0x3a74, 0x1e07,
+ 0x3a75, 0x0865,
+ 0x3b21, 0x086f,
+ 0x3b27, 0x1e08,
+ 0x3b28, 0x0876,
+ 0x3b2a, 0x1e09,
+ 0x3b2b, 0x0879,
+ 0x3b2c, 0x1e0a,
+ 0x3b2d, 0x087b,
+ 0x3b39, 0x1e0b,
+ 0x3b3a, 0x0888,
+ 0x3c21, 0x08cd,
+ 0x3c48, 0x1e0d,
+ 0x3c49, 0x1929,
+ 0x3c4a, 0x08f6,
+ 0x3c57, 0x1e0e,
+ 0x3c58, 0x0904,
+ 0x3c5d, 0x1e0f,
+ 0x3c5f, 0x090b,
+ 0x3d21, 0x092b,
+ 0x3d2b, 0x1e11,
+ 0x3d2c, 0x0936,
+ 0x3d36, 0x1e12,
+ 0x3d37, 0x0941,
+ 0x3d6c, 0x1e13,
+ 0x3d6e, 0x0978,
+ 0x3d72, 0x1e15,
+ 0x3d74, 0x097e,
+ 0x3e21, 0x0989,
+ 0x3e25, 0x1e17,
+ 0x3e26, 0x098e,
+ 0x3e33, 0x1e18,
+ 0x3e34, 0x099c,
+ 0x3e3f, 0x1e19,
+ 0x3e40, 0x09a8,
+ 0x3e55, 0x1e1a,
+ 0x3e56, 0x09be,
+ 0x3e5f, 0x1e1b,
+ 0x3e60, 0x09c8,
+ 0x3e64, 0x1e1c,
+ 0x3e65, 0x09cd,
+ 0x3f21, 0x09e7,
+ 0x3f2a, 0x1e1d,
+ 0x3f2b, 0x09f1,
+ 0x3f59, 0x1e1e,
+ 0x3f5a, 0x0a20,
+ 0x3f60, 0x1e1f,
+ 0x3f61, 0x0a27,
+ 0x3f69, 0x1e20,
+ 0x3f6a, 0x0a30,
+ 0x4021, 0x0a45,
+ 0x4022, 0x1e21,
+ 0x4023, 0x0a47,
+ 0x4042, 0x1e22,
+ 0x4043, 0x0a67,
+ 0x4066, 0x1e23,
+ 0x4067, 0x0a8b,
+ 0x4071, 0x1e24,
+ 0x4073, 0x0a97,
+ 0x4079, 0x1e26,
+ 0x407b, 0x0a9f,
+ 0x4121, 0x0aa3,
+ 0x4127, 0x1e28,
+ 0x4128, 0x1a6e,
+ 0x4129, 0x0aab,
+ 0x4139, 0x1e29,
+ 0x413a, 0x0abc,
+ 0x414c, 0x1e2a,
+ 0x414d, 0x0acf,
+ 0x414f, 0x1e2b,
+ 0x4150, 0x0ad2,
+ 0x415f, 0x1e2c,
+ 0x4160, 0x0ae2,
+ 0x4169, 0x1e2d,
+ 0x416a, 0x0aec,
+ 0x4221, 0x0b01,
+ 0x423d, 0x1e2e,
+ 0x423e, 0x0b1e,
+ 0x424d, 0x1e2f,
+ 0x424e, 0x0b2e,
+ 0x425c, 0x1e30,
+ 0x425d, 0x0b3d,
+ 0x4263, 0x1e31,
+ 0x4264, 0x0b44,
+ 0x426f, 0x1e32,
+ 0x4270, 0x0b50,
+ 0x4275, 0x1e33,
+ 0x4277, 0x0b57,
+ 0x427d, 0x1e35,
+ 0x427e, 0x0b5e,
+ 0x4321, 0x0b5f,
+ 0x4327, 0x1e36,
+ 0x4328, 0x0b66,
+ 0x4329, 0x1e37,
+ 0x432b, 0x0b69,
+ 0x432d, 0x1e39,
+ 0x432f, 0x0b6d,
+ 0x433d, 0x1e3b,
+ 0x433e, 0x0b7c,
+ 0x4370, 0x1e3c,
+ 0x4371, 0x0baf,
+ 0x4375, 0x1e3d,
+ 0x4376, 0x0bb4,
+ 0x437c, 0x1e3e,
+ 0x437d, 0x0bbb,
+ 0x4421, 0x0bbd,
+ 0x443d, 0x1e3f,
+ 0x443e, 0x0bda,
+ 0x4448, 0x1e40,
+ 0x4449, 0x0be5,
+ 0x444a, 0x1e41,
+ 0x444b, 0x0be7,
+ 0x444d, 0x1e42,
+ 0x444e, 0x0bea,
+ 0x444f, 0x1e43,
+ 0x4450, 0x0bec,
+ 0x4454, 0x204b,
+ 0x4455, 0x0bf1,
+ 0x445b, 0x11b5,
+ 0x445c, 0x0bf8,
+ 0x4521, 0x0c1b,
+ 0x4522, 0x1e44,
+ 0x4523, 0x0c1d,
+ 0x4527, 0x1e45,
+ 0x4528, 0x0c22,
+ 0x452e, 0x1e46,
+ 0x452f, 0x0c29,
+ 0x4536, 0x1e47,
+ 0x4537, 0x0c31,
+ 0x453f, 0x1e48,
+ 0x4540, 0x0c3a,
+ 0x4548, 0x1e49,
+ 0x4549, 0x0c43,
+ 0x454b, 0x1e4a,
+ 0x454c, 0x0c46,
+ 0x4551, 0x1e4b,
+ 0x4553, 0x0c4d,
+ 0x4557, 0x16df,
+ 0x4558, 0x0c52,
+ 0x4564, 0x1e4d,
+ 0x4565, 0x0c5f,
+ 0x456e, 0x1450,
+ 0x456f, 0x0c69,
+ 0x4573, 0x1536,
+ 0x4574, 0x0c6e,
+ 0x4578, 0x1e4e,
+ 0x4579, 0x0c73,
+ 0x4621, 0x0c79,
+ 0x463e, 0x1e4f,
+ 0x463f, 0x0c97,
+ 0x4642, 0x1e50,
+ 0x4643, 0x0c9b,
+ 0x4654, 0x1e51,
+ 0x4656, 0x0cae,
+ 0x465b, 0x1e53,
+ 0x465d, 0x0cb5,
+ 0x4661, 0x1e55,
+ 0x4662, 0x0cba,
+ 0x4666, 0x1e56,
+ 0x4668, 0x0cc0,
+ 0x466a, 0x1e58,
+ 0x466b, 0x0cc3,
+ 0x4676, 0x1aed,
+ 0x4677, 0x0ccf,
+ 0x4721, 0x0cd7,
+ 0x4729, 0x1e59,
+ 0x472a, 0x0ce0,
+ 0x4739, 0x1e5a,
+ 0x473a, 0x0cf0,
+ 0x4757, 0x1e5b,
+ 0x4758, 0x0d0e,
+ 0x4767, 0x1e5c,
+ 0x4768, 0x1989,
+ 0x4769, 0x1e5d,
+ 0x476a, 0x0d20,
+ 0x476d, 0x1e5e,
+ 0x476e, 0x0d24,
+ 0x4821, 0x0d35,
+ 0x4824, 0x1e5f,
+ 0x4825, 0x0d39,
+ 0x482e, 0x1e60,
+ 0x482f, 0x0d43,
+ 0x4830, 0x1e61,
+ 0x4831, 0x0d45,
+ 0x4854, 0x1e62,
+ 0x4855, 0x0d69,
+ 0x4862, 0x1e63,
+ 0x4863, 0x0d77,
+ 0x4875, 0x1e64,
+ 0x4876, 0x0d8a,
+ 0x4921, 0x0d93,
+ 0x4922, 0x1e65,
+ 0x4924, 0x0d96,
+ 0x492f, 0x1e67,
+ 0x4930, 0x143b,
+ 0x4931, 0x0da3,
+ 0x4932, 0x1e68,
+ 0x4933, 0x0da5,
+ 0x4935, 0x1e69,
+ 0x4936, 0x0da8,
+ 0x4940, 0x1e6a,
+ 0x4941, 0x0db3,
+ 0x494e, 0x1e6b,
+ 0x494f, 0x0dc1,
+ 0x4951, 0x1e6c,
+ 0x4952, 0x0dc4,
+ 0x4a21, 0x0df1,
+ 0x4a43, 0x1e6d,
+ 0x4a44, 0x0e14,
+ 0x4a4d, 0x1e6e,
+ 0x4a4e, 0x0e1e,
+ 0x4a5a, 0x1e6f,
+ 0x4a5b, 0x0e2b,
+ 0x4a79, 0x1e70,
+ 0x4a7a, 0x0e4a,
+ 0x4b21, 0x0e4f,
+ 0x4b22, 0x1e71,
+ 0x4b23, 0x0e51,
+ 0x4b29, 0x1e72,
+ 0x4b2a, 0x0e58,
+ 0x4b4b, 0x1e73,
+ 0x4b4c, 0x0e7a,
+ 0x4b6a, 0x1d33,
+ 0x4b6b, 0x0e99,
+ 0x4b70, 0x1e74,
+ 0x4b71, 0x0e9f,
+ 0x4b78, 0x1f2c,
+ 0x4b79, 0x102f,
+ 0x4b7a, 0x0ea8,
+ 0x4c21, 0x0ead,
+ 0x4c4d, 0x1e75,
+ 0x4c4e, 0x0eda,
+ 0x4c59, 0x1e76,
+ 0x4c5a, 0x0ee6,
+ 0x4c5f, 0x1e77,
+ 0x4c60, 0x0eec,
+ 0x4c62, 0x1e78,
+ 0x4c63, 0x0eef,
+ 0x4c79, 0x1935,
+ 0x4c7a, 0x1e79,
+ 0x4c7b, 0x0f07,
+ 0x4c7c, 0x1e7a,
+ 0x4c7d, 0x0f09,
+ 0x4c7e, 0x1e7b,
+ 0x4d21, 0x0f0b,
+ 0x4d32, 0x1e7c,
+ 0x4d33, 0x0f1d,
+ 0x4d50, 0x1e7d,
+ 0x4d51, 0x0f3b,
+ 0x4d54, 0x1e7e,
+ 0x4d55, 0x0f3f,
+ 0x4d5a, 0x1d34,
+ 0x4d5b, 0x0f45,
+ 0x4d69, 0x1e7f,
+ 0x4d6a, 0x0f54,
+ 0x4e21, 0x0f69,
+ 0x4e4b, 0x1e80,
+ 0x4e4c, 0x0f94,
+ 0x4e7a, 0x1e81,
+ 0x4e7c, 0x0fc4,
+ 0x4f21, 0x1e83,
+ 0x4f22, 0x0fc8,
+ 0x4f31, 0x1e84,
+ 0x4f32, 0x0fd8,
+ 0x4f36, 0x1777,
+ 0x4f37, 0x0fdd,
+ 0x4f39, 0x1e85,
+ 0x4f3a, 0x0fe0,
+ 0x5021, 0x0ffa,
+ 0x5056, 0x0ea7,
+ 0x5057, 0x1030,
+ 0x5121, 0x1058,
+ 0x513d, 0x1e86,
+ 0x513e, 0x1075,
+ 0x5147, 0x1e87,
+ 0x5148, 0x107f,
+ 0x514b, 0x1e88,
+ 0x514c, 0x1083,
+ 0x514d, 0x1e89,
+ 0x514e, 0x1085,
+ 0x5221, 0x10b6,
+ 0x5321, 0x1114,
+ 0x5330, 0x1e8a,
+ 0x5331, 0x1124,
+ 0x533a, 0x1e8b,
+ 0x533b, 0x112e,
+ 0x535e, 0x1e8d,
+ 0x535f, 0x1152,
+ 0x536b, 0x1e8e,
+ 0x536c, 0x115f,
+ 0x5421, 0x1172,
+ 0x5444, 0x1e8f,
+ 0x5445, 0x1196,
+ 0x5464, 0x0bf7,
+ 0x5465, 0x11b6,
+ 0x5521, 0x11d0,
+ 0x553d, 0x1e90,
+ 0x553e, 0x11ed,
+ 0x5563, 0x1e91,
+ 0x5564, 0x1213,
+ 0x5621, 0x122e,
+ 0x5622, 0x1e92,
+ 0x5623, 0x1230,
+ 0x5721, 0x128c,
+ 0x5821, 0x12ea,
+ 0x5824, 0x1e94,
+ 0x5825, 0x12ee,
+ 0x5921, 0x1348,
+ 0x5960, 0x1e95,
+ 0x5961, 0x1388,
+ 0x596c, 0x1e96,
+ 0x596d, 0x1394,
+ 0x5978, 0x05a7,
+ 0x5979, 0x13a0,
+ 0x5a21, 0x13a6,
+ 0x5a39, 0x1e97,
+ 0x5a3a, 0x13bf,
+ 0x5a4d, 0x1e98,
+ 0x5a4e, 0x13d3,
+ 0x5b21, 0x1404,
+ 0x5b45, 0x1e99,
+ 0x5b46, 0x1429,
+ 0x5b4a, 0x1e9a,
+ 0x5b4b, 0x142e,
+ 0x5b58, 0x0da2,
+ 0x5b59, 0x143c,
+ 0x5b6b, 0x1e9b,
+ 0x5b6c, 0x144f,
+ 0x5b6d, 0x0c68,
+ 0x5b6e, 0x1451,
+ 0x5b74, 0x1e9c,
+ 0x5b75, 0x1458,
+ 0x5c21, 0x1462,
+ 0x5d21, 0x14c0,
+ 0x5e21, 0x151e,
+ 0x5e39, 0x0c6d,
+ 0x5e3a, 0x1537,
+ 0x5e50, 0x1e9d,
+ 0x5e51, 0x154e,
+ 0x5e75, 0x05ff,
+ 0x5e76, 0x1573,
+ 0x5f21, 0x157c,
+ 0x6021, 0x15da,
+ 0x6026, 0x1e9f,
+ 0x6027, 0x15e0,
+ 0x605f, 0x1ea0,
+ 0x6060, 0x1619,
+ 0x6076, 0x1d35,
+ 0x6077, 0x1630,
+ 0x6121, 0x1638,
+ 0x612b, 0x1ea1,
+ 0x612c, 0x1643,
+ 0x6130, 0x1ea2,
+ 0x6132, 0x1649,
+ 0x6221, 0x1696,
+ 0x622b, 0x1ea4,
+ 0x622c, 0x16a1,
+ 0x6268, 0x07ee,
+ 0x6269, 0x16de,
+ 0x626a, 0x0c51,
+ 0x626b, 0x16e0,
+ 0x626f, 0x1ea5,
+ 0x6270, 0x16e5,
+ 0x6321, 0x16f4,
+ 0x634a, 0x1ea6,
+ 0x634b, 0x171e,
+ 0x6354, 0x1ea7,
+ 0x6355, 0x1728,
+ 0x635e, 0x05d4,
+ 0x635f, 0x1732,
+ 0x6421, 0x1752,
+ 0x6439, 0x1ea8,
+ 0x643a, 0x176b,
+ 0x6446, 0x0fdc,
+ 0x6447, 0x1778,
+ 0x6464, 0x1ea9,
+ 0x6465, 0x1796,
+ 0x646e, 0x1eaa,
+ 0x646f, 0x17a0,
+ 0x6521, 0x17b0,
+ 0x6539, 0x1eab,
+ 0x653a, 0x17c9,
+ 0x653b, 0x1eac,
+ 0x653c, 0x17cb,
+ 0x6546, 0x1ead,
+ 0x6547, 0x17d6,
+ 0x6621, 0x180e,
+ 0x6646, 0x1eae,
+ 0x6647, 0x1834,
+ 0x6721, 0x186c,
+ 0x6764, 0x1eaf,
+ 0x6765, 0x18b0,
+ 0x6769, 0x1eb0,
+ 0x676a, 0x18b5,
+ 0x6772, 0x1eb1,
+ 0x6773, 0x18be,
+ 0x6821, 0x18ca,
+ 0x6834, 0x1eb2,
+ 0x6835, 0x18de,
+ 0x683b, 0x1eb3,
+ 0x683c, 0x18e5,
+ 0x6874, 0x1eb4,
+ 0x6875, 0x191e,
+ 0x6921, 0x1928,
+ 0x6922, 0x08f5,
+ 0x6923, 0x192a,
+ 0x692e, 0x0f05,
+ 0x692f, 0x1936,
+ 0x695a, 0x05a0,
+ 0x695b, 0x1962,
+ 0x6a21, 0x1986,
+ 0x6a24, 0x0d1e,
+ 0x6a25, 0x198a,
+ 0x6a27, 0x1eb6,
+ 0x6a28, 0x198d,
+ 0x6a3d, 0x1eb7,
+ 0x6a3e, 0x19a3,
+ 0x6a6f, 0x1eb8,
+ 0x6a70, 0x19d5,
+ 0x6b21, 0x19e4,
+ 0x6b32, 0x1eb9,
+ 0x6b33, 0x19f6,
+ 0x6b5d, 0x060e,
+ 0x6b5e, 0x1a21,
+ 0x6b66, 0x1eba,
+ 0x6b67, 0x1a2a,
+ 0x6b76, 0x1ebb,
+ 0x6b77, 0x1a3a,
+ 0x6c21, 0x1a42,
+ 0x6c4d, 0x0aaa,
+ 0x6c4e, 0x1a6f,
+ 0x6c69, 0x1ebc,
+ 0x6c6a, 0x1a8b,
+ 0x6c74, 0x1ebd,
+ 0x6c75, 0x1a96,
+ 0x6d21, 0x1aa0,
+ 0x6d4e, 0x1ebe,
+ 0x6d4f, 0x1ace,
+ 0x6d6c, 0x1ebf,
+ 0x6d6d, 0x1aec,
+ 0x6d6e, 0x1ec0,
+ 0x6d6f, 0x1aee,
+ 0x6e21, 0x1afe,
+ 0x6e29, 0x1ec1,
+ 0x6e2a, 0x1b07,
+ 0x6e3d, 0x1ec2,
+ 0x6e3e, 0x1b1b,
+ 0x6e57, 0x1ec3,
+ 0x6e58, 0x1b35,
+ 0x6f21, 0x1b5c,
+ 0x7021, 0x1bba,
+ 0x7045, 0x1ec6,
+ 0x7046, 0x1bdf,
+ 0x7051, 0x1ec7,
+ 0x7052, 0x1beb,
+ 0x7057, 0x1ec8,
+ 0x7058, 0x1bf1,
+ 0x7074, 0x0731,
+ 0x7075, 0x1ec9,
+ 0x7076, 0x1c0f,
+ 0x7121, 0x1c18,
+ 0x7221, 0x1c76,
+ 0x722d, 0x1eca,
+ 0x722e, 0x1c83,
+ 0x723c, 0x1ecb,
+ 0x723d, 0x1c92,
+ 0x724d, 0x0477,
+ 0x724e, 0x1ecc,
+ 0x724f, 0x1ca4,
+ 0x7274, 0x0529,
+ 0x7275, 0x1cca,
+ 0x7321, 0x1cd4,
+ 0x7351, 0x1ecd,
+ 0x7352, 0x1d05,
+ 0x737d, 0x1ece,
+ 0x737e, 0x1d31,
+ 0x2122, 0x1ecf,
+ 0x2131, 0x1ed1,
+ 0x213c, 0x1ed3,
+ 0x2141, 0x1ed6,
+ 0x214a, 0x1edb,
+ 0x2161, 0x1eed,
+ 0x2421, 0x1eee,
+ 0x2423, 0x1eef,
+ 0x2425, 0x1ef0,
+ 0x2427, 0x1ef1,
+ 0x2429, 0x1ef2,
+ 0x2443, 0x1ef3,
+ 0x2463, 0x1ef4,
+ 0x2465, 0x1ef5,
+ 0x2467, 0x1ef6,
+ 0x246e, 0x1ef7,
+ 0x2521, 0x1ef8,
+ 0x2523, 0x1ef9,
+ 0x2525, 0x1efa,
+ 0x2527, 0x1efb,
+ 0x2529, 0x1efc,
+ 0x2543, 0x1efd,
+ 0x2563, 0x1efe,
+ 0x2565, 0x1eff,
+ 0x2567, 0x1f00,
+ 0x256e, 0x1f01,
+ 0x2575, 0x1f02,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 japan1278VEnc16 = {
+ 1,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ japan1278VMap2, 652
+};
+
+static Gushort japan1278msRKSJHMap2[1424] = {
+ 0x0000, 0x0000,
+ 0x8140, 0x0279,
+ 0x8180, 0x02b8,
+ 0x81b8, 0x02e5,
+ 0x81c8, 0x02ed,
+ 0x81da, 0x02f4,
+ 0x81f0, 0x0303,
+ 0x81fc, 0x030b,
+ 0x824f, 0x030c,
+ 0x8260, 0x0316,
+ 0x8281, 0x0330,
+ 0x829f, 0x034a,
+ 0x8340, 0x039d,
+ 0x8380, 0x03dc,
+ 0x839f, 0x03f3,
+ 0x83bf, 0x040b,
+ 0x8440, 0x0423,
+ 0x8470, 0x0444,
+ 0x8480, 0x0453,
+ 0x849f, 0x1d37,
+ 0x84a0, 0x1d39,
+ 0x84a1, 0x1d43,
+ 0x84a2, 0x1d47,
+ 0x84a3, 0x1d4f,
+ 0x84a4, 0x1d4b,
+ 0x84a5, 0x1d53,
+ 0x84a6, 0x1d63,
+ 0x84a7, 0x1d5b,
+ 0x84a8, 0x1d6b,
+ 0x84a9, 0x1d73,
+ 0x84aa, 0x1d38,
+ 0x84ab, 0x1d3a,
+ 0x84ac, 0x1d46,
+ 0x84ad, 0x1d4a,
+ 0x84ae, 0x1d52,
+ 0x84af, 0x1d4e,
+ 0x84b0, 0x1d5a,
+ 0x84b1, 0x1d6a,
+ 0x84b2, 0x1d62,
+ 0x84b3, 0x1d72,
+ 0x84b4, 0x1d82,
+ 0x84b5, 0x1d57,
+ 0x84b6, 0x1d66,
+ 0x84b7, 0x1d5f,
+ 0x84b8, 0x1d6e,
+ 0x84b9, 0x1d76,
+ 0x84ba, 0x1d54,
+ 0x84bb, 0x1d67,
+ 0x84bc, 0x1d5c,
+ 0x84bd, 0x1d6f,
+ 0x84be, 0x1d79,
+ 0x8740, 0x1d83,
+ 0x875f, 0x1da1,
+ 0x8761, 0x1f66,
+ 0x8762, 0x1da4,
+ 0x8763, 0x1f68,
+ 0x8764, 0x1da6,
+ 0x8765, 0x1f6a,
+ 0x8766, 0x1da8,
+ 0x8768, 0x1f6c,
+ 0x8769, 0x1dab,
+ 0x876b, 0x1f6b,
+ 0x876c, 0x1dae,
+ 0x876e, 0x1f6f,
+ 0x876f, 0x1db1,
+ 0x877e, 0x2083,
+ 0x8780, 0x1db8,
+ 0x8784, 0x1f77,
+ 0x8785, 0x1dbd,
+ 0x8790, 0x02fa,
+ 0x8791, 0x02f9,
+ 0x8792, 0x0301,
+ 0x8793, 0x1dc8,
+ 0x879a, 0x0300,
+ 0x879b, 0x1dcf,
+ 0x889f, 0x0465,
+ 0x88a0, 0x1dd1,
+ 0x88a1, 0x0467,
+ 0x88a7, 0x204a,
+ 0x88a8, 0x046e,
+ 0x88b0, 0x1f19,
+ 0x88b1, 0x1ca2,
+ 0x88b2, 0x0478,
+ 0x88b9, 0x1dd2,
+ 0x88ba, 0x0480,
+ 0x88ec, 0x1dd3,
+ 0x88ed, 0x04b3,
+ 0x88f1, 0x1dd4,
+ 0x88f2, 0x04b8,
+ 0x88fa, 0x1dd5,
+ 0x88fb, 0x04c1,
+ 0x8940, 0x04c3,
+ 0x8949, 0x1dd6,
+ 0x894a, 0x04cd,
+ 0x8954, 0x1dd7,
+ 0x8955, 0x04d8,
+ 0x8958, 0x1dd8,
+ 0x8959, 0x04dc,
+ 0x895c, 0x1dda,
+ 0x895d, 0x04e0,
+ 0x8961, 0x1ddb,
+ 0x8962, 0x04e5,
+ 0x8980, 0x0502,
+ 0x898b, 0x1ddc,
+ 0x898c, 0x050e,
+ 0x89a6, 0x1ddd,
+ 0x89a7, 0x1cc9,
+ 0x89a8, 0x1dde,
+ 0x89a9, 0x052b,
+ 0x89de, 0x1ddf,
+ 0x89df, 0x0561,
+ 0x89f8, 0x1de0,
+ 0x89f9, 0x057b,
+ 0x89fb, 0x1de1,
+ 0x89fc, 0x057e,
+ 0x8a40, 0x057f,
+ 0x8a41, 0x1de2,
+ 0x8a42, 0x0581,
+ 0x8a61, 0x1961,
+ 0x8a62, 0x05a1,
+ 0x8a68, 0x139f,
+ 0x8a69, 0x05a8,
+ 0x8a80, 0x05be,
+ 0x8a85, 0x1de3,
+ 0x8a86, 0x05c4,
+ 0x8a8b, 0x1de4,
+ 0x8a8c, 0x05ca,
+ 0x8a93, 0x1de5,
+ 0x8a94, 0x05d2,
+ 0x8a96, 0x1731,
+ 0x8a97, 0x05d5,
+ 0x8a9a, 0x1de6,
+ 0x8a9b, 0x05d9,
+ 0x8ac0, 0x1de7,
+ 0x8ac1, 0x1572,
+ 0x8ac2, 0x0600,
+ 0x8acb, 0x1de8,
+ 0x8acc, 0x060a,
+ 0x8ad0, 0x1a20,
+ 0x8ad1, 0x060f,
+ 0x8ae3, 0x1de9,
+ 0x8ae4, 0x0622,
+ 0x8b40, 0x063b,
+ 0x8b4a, 0x1dea,
+ 0x8b4b, 0x0646,
+ 0x8b5f, 0x1deb,
+ 0x8b60, 0x065b,
+ 0x8b80, 0x067a,
+ 0x8ba0, 0x1dec,
+ 0x8ba1, 0x069b,
+ 0x8ba8, 0x1ded,
+ 0x8ba9, 0x06a3,
+ 0x8bc4, 0x1d32,
+ 0x8bc5, 0x06bf,
+ 0x8bcd, 0x1dee,
+ 0x8bce, 0x06c8,
+ 0x8beb, 0x1def,
+ 0x8bec, 0x06e6,
+ 0x8bf2, 0x1df0,
+ 0x8bf3, 0x06ed,
+ 0x8bf9, 0x1df1,
+ 0x8bfa, 0x06f4,
+ 0x8bfb, 0x1df2,
+ 0x8bfc, 0x06f6,
+ 0x8c40, 0x06f7,
+ 0x8c43, 0x1df3,
+ 0x8c44, 0x06fb,
+ 0x8c56, 0x1df4,
+ 0x8c57, 0x070e,
+ 0x8c64, 0x1df5,
+ 0x8c65, 0x071c,
+ 0x8c6d, 0x1df6,
+ 0x8c6e, 0x0725,
+ 0x8c71, 0x1df7,
+ 0x8c72, 0x0729,
+ 0x8c74, 0x1df8,
+ 0x8c75, 0x072c,
+ 0x8c7a, 0x1c0d,
+ 0x8c7b, 0x0732,
+ 0x8c80, 0x0736,
+ 0x8c84, 0x1df9,
+ 0x8c85, 0x073b,
+ 0x8c91, 0x1dfa,
+ 0x8c92, 0x0748,
+ 0x8c99, 0x1dfb,
+ 0x8c9a, 0x0750,
+ 0x8c9e, 0x1dfc,
+ 0x8c9f, 0x0755,
+ 0x8cb2, 0x1dfd,
+ 0x8cb3, 0x0769,
+ 0x8cbf, 0x1dfe,
+ 0x8cc0, 0x0776,
+ 0x8d40, 0x07b3,
+ 0x8d4a, 0x1dff,
+ 0x8d4b, 0x07be,
+ 0x8d56, 0x1e00,
+ 0x8d57, 0x07ca,
+ 0x8d61, 0x1e01,
+ 0x8d62, 0x07d5,
+ 0x8d7b, 0x16dd,
+ 0x8d7c, 0x07ef,
+ 0x8d80, 0x07f2,
+ 0x8d8d, 0x1e02,
+ 0x8d8e, 0x0800,
+ 0x8d94, 0x1e03,
+ 0x8d95, 0x0807,
+ 0x8d99, 0x1e04,
+ 0x8d9a, 0x080c,
+ 0x8dd1, 0x1e05,
+ 0x8dd2, 0x0844,
+ 0x8de5, 0x1e06,
+ 0x8de6, 0x0858,
+ 0x8df2, 0x1e07,
+ 0x8df3, 0x0865,
+ 0x8e40, 0x086f,
+ 0x8e46, 0x1e08,
+ 0x8e47, 0x0876,
+ 0x8e49, 0x1e09,
+ 0x8e4a, 0x0879,
+ 0x8e4b, 0x1e0a,
+ 0x8e4c, 0x087b,
+ 0x8e58, 0x1e0b,
+ 0x8e59, 0x0888,
+ 0x8e80, 0x08ae,
+ 0x8ec6, 0x1e0d,
+ 0x8ec7, 0x1929,
+ 0x8ec8, 0x08f6,
+ 0x8ed5, 0x1e0e,
+ 0x8ed6, 0x0904,
+ 0x8edb, 0x1e0f,
+ 0x8edd, 0x090b,
+ 0x8f40, 0x092b,
+ 0x8f4a, 0x1e11,
+ 0x8f4b, 0x0936,
+ 0x8f55, 0x1e12,
+ 0x8f56, 0x0941,
+ 0x8f80, 0x096a,
+ 0x8f8c, 0x1e13,
+ 0x8f8e, 0x0978,
+ 0x8f92, 0x1e15,
+ 0x8f94, 0x097e,
+ 0x8fa3, 0x1e17,
+ 0x8fa4, 0x098e,
+ 0x8fb1, 0x1e18,
+ 0x8fb2, 0x099c,
+ 0x8fbd, 0x1e19,
+ 0x8fbe, 0x09a8,
+ 0x8fd3, 0x1e1a,
+ 0x8fd4, 0x09be,
+ 0x8fdd, 0x1e1b,
+ 0x8fde, 0x09c8,
+ 0x8fe2, 0x1e1c,
+ 0x8fe3, 0x09cd,
+ 0x9040, 0x09e7,
+ 0x9049, 0x1e1d,
+ 0x904a, 0x09f1,
+ 0x9078, 0x1e1e,
+ 0x9079, 0x0a20,
+ 0x9080, 0x1e1f,
+ 0x9081, 0x0a27,
+ 0x9089, 0x1e20,
+ 0x908a, 0x0a30,
+ 0x90a0, 0x1e21,
+ 0x90a1, 0x0a47,
+ 0x90c0, 0x1e22,
+ 0x90c1, 0x0a67,
+ 0x90e4, 0x1e23,
+ 0x90e5, 0x0a8b,
+ 0x90ef, 0x1e24,
+ 0x90f1, 0x0a97,
+ 0x90f7, 0x1e26,
+ 0x90f9, 0x0a9f,
+ 0x9140, 0x0aa3,
+ 0x9146, 0x1e28,
+ 0x9147, 0x1a6e,
+ 0x9148, 0x0aab,
+ 0x9158, 0x1e29,
+ 0x9159, 0x0abc,
+ 0x916b, 0x1e2a,
+ 0x916c, 0x0acf,
+ 0x916e, 0x1e2b,
+ 0x916f, 0x0ad2,
+ 0x917e, 0x1e2c,
+ 0x9180, 0x0ae2,
+ 0x9189, 0x1e2d,
+ 0x918a, 0x0aec,
+ 0x91bb, 0x1e2e,
+ 0x91bc, 0x0b1e,
+ 0x91cb, 0x1e2f,
+ 0x91cc, 0x0b2e,
+ 0x91da, 0x1e30,
+ 0x91db, 0x0b3d,
+ 0x91e1, 0x1e31,
+ 0x91e2, 0x0b44,
+ 0x91ed, 0x1e32,
+ 0x91ee, 0x0b50,
+ 0x91f3, 0x1e33,
+ 0x91f5, 0x0b57,
+ 0x91fb, 0x1e35,
+ 0x91fc, 0x0b5e,
+ 0x9240, 0x0b5f,
+ 0x9246, 0x1e36,
+ 0x9247, 0x0b66,
+ 0x9248, 0x1e37,
+ 0x924a, 0x0b69,
+ 0x924c, 0x1e39,
+ 0x924e, 0x0b6d,
+ 0x925c, 0x1e3b,
+ 0x925d, 0x0b7c,
+ 0x9280, 0x0b9e,
+ 0x9290, 0x1e3c,
+ 0x9291, 0x0baf,
+ 0x9295, 0x1e3d,
+ 0x9296, 0x0bb4,
+ 0x929c, 0x1e3e,
+ 0x929d, 0x0bbb,
+ 0x92bb, 0x1e3f,
+ 0x92bc, 0x0bda,
+ 0x92c6, 0x1e40,
+ 0x92c7, 0x0be5,
+ 0x92c8, 0x1e41,
+ 0x92c9, 0x0be7,
+ 0x92cb, 0x1e42,
+ 0x92cc, 0x0bea,
+ 0x92cd, 0x1e43,
+ 0x92ce, 0x0bec,
+ 0x92d2, 0x204b,
+ 0x92d3, 0x0bf1,
+ 0x92d9, 0x11b5,
+ 0x92da, 0x0bf8,
+ 0x9340, 0x0c1b,
+ 0x9341, 0x1e44,
+ 0x9342, 0x0c1d,
+ 0x9346, 0x1e45,
+ 0x9347, 0x0c22,
+ 0x934d, 0x1e46,
+ 0x934e, 0x0c29,
+ 0x9355, 0x1e47,
+ 0x9356, 0x0c31,
+ 0x935e, 0x1e48,
+ 0x935f, 0x0c3a,
+ 0x9367, 0x1e49,
+ 0x9368, 0x0c43,
+ 0x936a, 0x1e4a,
+ 0x936b, 0x0c46,
+ 0x9370, 0x1e4b,
+ 0x9372, 0x0c4d,
+ 0x9376, 0x16df,
+ 0x9377, 0x0c52,
+ 0x9380, 0x0c5a,
+ 0x9384, 0x1e4d,
+ 0x9385, 0x0c5f,
+ 0x938e, 0x1450,
+ 0x938f, 0x0c69,
+ 0x9393, 0x1536,
+ 0x9394, 0x0c6e,
+ 0x9398, 0x1e4e,
+ 0x9399, 0x0c73,
+ 0x93bc, 0x1e4f,
+ 0x93bd, 0x0c97,
+ 0x93c0, 0x1e50,
+ 0x93c1, 0x0c9b,
+ 0x93d2, 0x1e51,
+ 0x93d4, 0x0cae,
+ 0x93d9, 0x1e53,
+ 0x93db, 0x0cb5,
+ 0x93df, 0x1e55,
+ 0x93e0, 0x0cba,
+ 0x93e4, 0x1e56,
+ 0x93e6, 0x0cc0,
+ 0x93e8, 0x1e58,
+ 0x93e9, 0x0cc3,
+ 0x93f4, 0x1aed,
+ 0x93f5, 0x0ccf,
+ 0x9440, 0x0cd7,
+ 0x9448, 0x1e59,
+ 0x9449, 0x0ce0,
+ 0x9458, 0x1e5a,
+ 0x9459, 0x0cf0,
+ 0x9476, 0x1e5b,
+ 0x9477, 0x0d0e,
+ 0x9480, 0x0d16,
+ 0x9487, 0x1e5c,
+ 0x9488, 0x1989,
+ 0x9489, 0x1e5d,
+ 0x948a, 0x0d20,
+ 0x948d, 0x1e5e,
+ 0x948e, 0x0d24,
+ 0x94a2, 0x1e5f,
+ 0x94a3, 0x0d39,
+ 0x94ac, 0x1e60,
+ 0x94ad, 0x0d43,
+ 0x94ae, 0x1e61,
+ 0x94af, 0x0d45,
+ 0x94d2, 0x1e62,
+ 0x94d3, 0x0d69,
+ 0x94e0, 0x1e63,
+ 0x94e1, 0x0d77,
+ 0x94f3, 0x1e64,
+ 0x94f4, 0x0d8a,
+ 0x9540, 0x0d93,
+ 0x9541, 0x1e65,
+ 0x9543, 0x0d96,
+ 0x954e, 0x1e67,
+ 0x954f, 0x143b,
+ 0x9550, 0x0da3,
+ 0x9551, 0x1e68,
+ 0x9552, 0x0da5,
+ 0x9554, 0x1e69,
+ 0x9555, 0x0da8,
+ 0x955f, 0x1e6a,
+ 0x9560, 0x0db3,
+ 0x956d, 0x1e6b,
+ 0x956e, 0x0dc1,
+ 0x9570, 0x1e6c,
+ 0x9571, 0x0dc4,
+ 0x9580, 0x0dd2,
+ 0x95c1, 0x1e6d,
+ 0x95c2, 0x0e14,
+ 0x95cb, 0x1e6e,
+ 0x95cc, 0x0e1e,
+ 0x95d8, 0x1e6f,
+ 0x95d9, 0x0e2b,
+ 0x95f7, 0x1e70,
+ 0x95f8, 0x0e4a,
+ 0x9640, 0x0e4f,
+ 0x9641, 0x1e71,
+ 0x9642, 0x0e51,
+ 0x9648, 0x1e72,
+ 0x9649, 0x0e58,
+ 0x966a, 0x1e73,
+ 0x966b, 0x0e7a,
+ 0x9680, 0x0e8e,
+ 0x968a, 0x1d33,
+ 0x968b, 0x0e99,
+ 0x9690, 0x1e74,
+ 0x9691, 0x0e9f,
+ 0x9698, 0x1f2c,
+ 0x9699, 0x102f,
+ 0x969a, 0x0ea8,
+ 0x96cb, 0x1e75,
+ 0x96cc, 0x0eda,
+ 0x96d7, 0x1e76,
+ 0x96d8, 0x0ee6,
+ 0x96dd, 0x1e77,
+ 0x96de, 0x0eec,
+ 0x96e0, 0x1e78,
+ 0x96e1, 0x0eef,
+ 0x96f7, 0x1935,
+ 0x96f8, 0x1e79,
+ 0x96f9, 0x0f07,
+ 0x96fa, 0x1e7a,
+ 0x96fb, 0x0f09,
+ 0x96fc, 0x1e7b,
+ 0x9740, 0x0f0b,
+ 0x9751, 0x1e7c,
+ 0x9752, 0x0f1d,
+ 0x976f, 0x1e7d,
+ 0x9770, 0x0f3b,
+ 0x9773, 0x1e7e,
+ 0x9774, 0x0f3f,
+ 0x9779, 0x1d34,
+ 0x977a, 0x0f45,
+ 0x9780, 0x0f4a,
+ 0x9789, 0x1e7f,
+ 0x978a, 0x0f54,
+ 0x97c9, 0x1e80,
+ 0x97ca, 0x0f94,
+ 0x97f8, 0x1e81,
+ 0x97fa, 0x0fc4,
+ 0x9840, 0x1e83,
+ 0x9841, 0x0fc8,
+ 0x9850, 0x1e84,
+ 0x9851, 0x0fd8,
+ 0x9855, 0x1777,
+ 0x9856, 0x0fdd,
+ 0x9858, 0x1e85,
+ 0x9859, 0x0fe0,
+ 0x989f, 0x0ffa,
+ 0x98d4, 0x0ea7,
+ 0x98d5, 0x1030,
+ 0x9940, 0x1058,
+ 0x995c, 0x1e86,
+ 0x995d, 0x1075,
+ 0x9966, 0x1e87,
+ 0x9967, 0x107f,
+ 0x996a, 0x1e88,
+ 0x996b, 0x1083,
+ 0x996c, 0x1e89,
+ 0x996d, 0x1085,
+ 0x9980, 0x1097,
+ 0x9a40, 0x1114,
+ 0x9a4f, 0x1e8a,
+ 0x9a50, 0x1124,
+ 0x9a59, 0x1e8b,
+ 0x9a5a, 0x112e,
+ 0x9a7d, 0x1e8d,
+ 0x9a7e, 0x1152,
+ 0x9a80, 0x1153,
+ 0x9a8b, 0x1e8e,
+ 0x9a8c, 0x115f,
+ 0x9ac2, 0x1e8f,
+ 0x9ac3, 0x1196,
+ 0x9ae2, 0x0bf7,
+ 0x9ae3, 0x11b6,
+ 0x9b40, 0x11d0,
+ 0x9b5c, 0x1e90,
+ 0x9b5d, 0x11ed,
+ 0x9b80, 0x120f,
+ 0x9b83, 0x1e91,
+ 0x9b84, 0x1213,
+ 0x9ba0, 0x1e92,
+ 0x9ba1, 0x1230,
+ 0x9c40, 0x128c,
+ 0x9c80, 0x12cb,
+ 0x9ca2, 0x1e94,
+ 0x9ca3, 0x12ee,
+ 0x9d40, 0x1348,
+ 0x9d80, 0x1e95,
+ 0x9d81, 0x1388,
+ 0x9d8c, 0x1e96,
+ 0x9d8d, 0x1394,
+ 0x9d98, 0x05a7,
+ 0x9d99, 0x13a0,
+ 0x9db7, 0x1e97,
+ 0x9db8, 0x13bf,
+ 0x9dcb, 0x1e98,
+ 0x9dcc, 0x13d3,
+ 0x9e40, 0x1404,
+ 0x9e64, 0x1e99,
+ 0x9e65, 0x1429,
+ 0x9e69, 0x1e9a,
+ 0x9e6a, 0x142e,
+ 0x9e77, 0x0da2,
+ 0x9e78, 0x143c,
+ 0x9e80, 0x1443,
+ 0x9e8b, 0x1e9b,
+ 0x9e8c, 0x144f,
+ 0x9e8d, 0x0c68,
+ 0x9e8e, 0x1451,
+ 0x9e94, 0x1e9c,
+ 0x9e95, 0x1458,
+ 0x9f40, 0x14c0,
+ 0x9f80, 0x14ff,
+ 0x9fb7, 0x0c6d,
+ 0x9fb8, 0x1537,
+ 0x9fce, 0x1e9d,
+ 0x9fcf, 0x154e,
+ 0x9ff3, 0x05ff,
+ 0x9ff4, 0x1573,
+ 0xe040, 0x157c,
+ 0xe080, 0x15bb,
+ 0xe0a4, 0x1e9f,
+ 0xe0a5, 0x15e0,
+ 0xe0dd, 0x1ea0,
+ 0xe0de, 0x1619,
+ 0xe0f4, 0x1d35,
+ 0xe0f5, 0x1630,
+ 0xe140, 0x1638,
+ 0xe14a, 0x1ea1,
+ 0xe14b, 0x1643,
+ 0xe14f, 0x1ea2,
+ 0xe151, 0x1649,
+ 0xe180, 0x1677,
+ 0xe1a9, 0x1ea4,
+ 0xe1aa, 0x16a1,
+ 0xe1e6, 0x07ee,
+ 0xe1e7, 0x16de,
+ 0xe1e8, 0x0c51,
+ 0xe1e9, 0x16e0,
+ 0xe1ed, 0x1ea5,
+ 0xe1ee, 0x16e5,
+ 0xe240, 0x16f4,
+ 0xe269, 0x1ea6,
+ 0xe26a, 0x171e,
+ 0xe273, 0x1ea7,
+ 0xe274, 0x1728,
+ 0xe27d, 0x05d4,
+ 0xe27e, 0x1732,
+ 0xe280, 0x1733,
+ 0xe2b7, 0x1ea8,
+ 0xe2b8, 0x176b,
+ 0xe2c4, 0x0fdc,
+ 0xe2c5, 0x1778,
+ 0xe2e2, 0x1ea9,
+ 0xe2e3, 0x1796,
+ 0xe2ec, 0x1eaa,
+ 0xe2ed, 0x17a0,
+ 0xe340, 0x17b0,
+ 0xe358, 0x1eab,
+ 0xe359, 0x17c9,
+ 0xe35a, 0x1eac,
+ 0xe35b, 0x17cb,
+ 0xe365, 0x1ead,
+ 0xe366, 0x17d6,
+ 0xe380, 0x17ef,
+ 0xe3c4, 0x1eae,
+ 0xe3c5, 0x1834,
+ 0xe440, 0x186c,
+ 0xe480, 0x18ab,
+ 0xe484, 0x1eaf,
+ 0xe485, 0x18b0,
+ 0xe489, 0x1eb0,
+ 0xe48a, 0x18b5,
+ 0xe492, 0x1eb1,
+ 0xe493, 0x18be,
+ 0xe4b2, 0x1eb2,
+ 0xe4b3, 0x18de,
+ 0xe4b9, 0x1eb3,
+ 0xe4ba, 0x18e5,
+ 0xe4f2, 0x1eb4,
+ 0xe4f3, 0x191e,
+ 0xe540, 0x1928,
+ 0xe541, 0x08f5,
+ 0xe542, 0x192a,
+ 0xe54d, 0x0f05,
+ 0xe54e, 0x1936,
+ 0xe579, 0x05a0,
+ 0xe57a, 0x1962,
+ 0xe580, 0x1967,
+ 0xe5a2, 0x0d1e,
+ 0xe5a3, 0x198a,
+ 0xe5a5, 0x1eb6,
+ 0xe5a6, 0x198d,
+ 0xe5bb, 0x1eb7,
+ 0xe5bc, 0x19a3,
+ 0xe5ed, 0x1eb8,
+ 0xe5ee, 0x19d5,
+ 0xe640, 0x19e4,
+ 0xe651, 0x1eb9,
+ 0xe652, 0x19f6,
+ 0xe67c, 0x060e,
+ 0xe67d, 0x1a21,
+ 0xe680, 0x1a23,
+ 0xe686, 0x1eba,
+ 0xe687, 0x1a2a,
+ 0xe696, 0x1ebb,
+ 0xe697, 0x1a3a,
+ 0xe6cb, 0x0aaa,
+ 0xe6cc, 0x1a6f,
+ 0xe6e7, 0x1ebc,
+ 0xe6e8, 0x1a8b,
+ 0xe6f2, 0x1ebd,
+ 0xe6f3, 0x1a96,
+ 0xe740, 0x1aa0,
+ 0xe76d, 0x1ebe,
+ 0xe76e, 0x1ace,
+ 0xe780, 0x1adf,
+ 0xe78c, 0x1ebf,
+ 0xe78d, 0x1aec,
+ 0xe78e, 0x1ec0,
+ 0xe78f, 0x1aee,
+ 0xe7a7, 0x1ec1,
+ 0xe7a8, 0x1b07,
+ 0xe7bb, 0x1ec2,
+ 0xe7bc, 0x1b1b,
+ 0xe7d5, 0x1ec3,
+ 0xe7d6, 0x1b35,
+ 0xe840, 0x1b5c,
+ 0xe880, 0x1b9b,
+ 0xe8c3, 0x1ec6,
+ 0xe8c4, 0x1bdf,
+ 0xe8cf, 0x1ec7,
+ 0xe8d0, 0x1beb,
+ 0xe8d5, 0x1ec8,
+ 0xe8d6, 0x1bf1,
+ 0xe8f2, 0x0731,
+ 0xe8f3, 0x1ec9,
+ 0xe8f4, 0x1c0f,
+ 0xe940, 0x1c18,
+ 0xe980, 0x1c57,
+ 0xe9ab, 0x1eca,
+ 0xe9ac, 0x1c83,
+ 0xe9ba, 0x1ecb,
+ 0xe9bb, 0x1c92,
+ 0xe9cb, 0x0477,
+ 0xe9cc, 0x1ecc,
+ 0xe9cd, 0x1ca4,
+ 0xe9f2, 0x0529,
+ 0xe9f3, 0x1cca,
+ 0xea40, 0x1cd4,
+ 0xea70, 0x1ecd,
+ 0xea71, 0x1d05,
+ 0xea80, 0x1d13,
+ 0xea9d, 0x1ece,
+ 0xea9e, 0x1d31,
+ 0xeaa3, 0x205c,
+ 0xed40, 0x20a7,
+ 0xed80, 0x20e6,
+ 0xedb4, 0x07c9,
+ 0xedb5, 0x211a,
+ 0xee40, 0x2162,
+ 0xee80, 0x21a1,
+ 0xeeef, 0x1f9c,
+ 0xeef9, 0x02ef,
+ 0xeefa, 0x1f45,
+ 0xfa40, 0x1f9c,
+ 0xfa4a, 0x1d97,
+ 0xfa54, 0x02ef,
+ 0xfa55, 0x1f45,
+ 0xfa58, 0x1dc2,
+ 0xfa59, 0x1dba,
+ 0xfa5a, 0x1f77,
+ 0xfa5b, 0x0300,
+ 0xfa5c, 0x20a7,
+ 0xfa80, 0x20ca,
+ 0xfad0, 0x07c9,
+ 0xfad1, 0x211a,
+ 0xfb40, 0x2146,
+ 0xfb80, 0x2185,
+ 0xfc40, 0x2202,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 japan1278msRKSJHEnc16 = {
+ 0,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee,
+ 0x00ef, 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6,
+ 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe,
+ 0x00ff, 0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106,
+ 0x0107, 0x0108, 0x0109, 0x010a, 0x010b, 0x010c, 0x010d, 0x010e,
+ 0x010f, 0x0110, 0x0111, 0x0112, 0x0113, 0x0114, 0x0115, 0x0116,
+ 0x0117, 0x0118, 0x0119, 0x011a, 0x011b, 0x011c, 0x011d, 0x011e,
+ 0x011f, 0x0120, 0x0121, 0x0122, 0x0123, 0x0124, 0x0125, 0x0126,
+ 0x0127, 0x0128, 0x0129, 0x012a, 0x012b, 0x012c, 0x012d, 0x012e,
+ 0x012f, 0x0130, 0x0131, 0x0132, 0x0133, 0x0134, 0x0135, 0x0136,
+ 0x0137, 0x0138, 0x0139, 0x013a, 0x013b, 0x013c, 0x013d, 0x013e,
+ 0x013f, 0x0140, 0x0141, 0x0142, 0x0143, 0x0144, 0x0277, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0146, 0x0147, 0x0148, 0x0149, 0x014a, 0x014b, 0x014c, 0x014d,
+ 0x014e, 0x014f, 0x0150, 0x0151, 0x0152, 0x0153, 0x0154, 0x0155,
+ 0x0156, 0x0157, 0x0158, 0x0159, 0x015a, 0x015b, 0x015c, 0x015d,
+ 0x015e, 0x015f, 0x0160, 0x0161, 0x0162, 0x0163, 0x0164, 0x0165,
+ 0x0166, 0x0167, 0x0168, 0x0169, 0x016a, 0x016b, 0x016c, 0x016d,
+ 0x016e, 0x016f, 0x0170, 0x0171, 0x0172, 0x0173, 0x0174, 0x0175,
+ 0x0176, 0x0177, 0x0178, 0x0179, 0x017a, 0x017b, 0x017c, 0x017d,
+ 0x017e, 0x017f, 0x0180, 0x0181, 0x0182, 0x0183, 0x0184, 0x0185,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ japan1278msRKSJHMap2, 712
+};
+
+static Gushort japan1278msRKSJVMap2[1580] = {
+ 0x0000, 0x0000,
+ 0x8140, 0x0279,
+ 0x8180, 0x02b8,
+ 0x81b8, 0x02e5,
+ 0x81c8, 0x02ed,
+ 0x81da, 0x02f4,
+ 0x81f0, 0x0303,
+ 0x81fc, 0x030b,
+ 0x824f, 0x030c,
+ 0x8260, 0x0316,
+ 0x8281, 0x0330,
+ 0x829f, 0x034a,
+ 0x8340, 0x039d,
+ 0x8380, 0x03dc,
+ 0x839f, 0x03f3,
+ 0x83bf, 0x040b,
+ 0x8440, 0x0423,
+ 0x8470, 0x0444,
+ 0x8480, 0x0453,
+ 0x849f, 0x1d37,
+ 0x84a0, 0x1d39,
+ 0x84a1, 0x1d43,
+ 0x84a2, 0x1d47,
+ 0x84a3, 0x1d4f,
+ 0x84a4, 0x1d4b,
+ 0x84a5, 0x1d53,
+ 0x84a6, 0x1d63,
+ 0x84a7, 0x1d5b,
+ 0x84a8, 0x1d6b,
+ 0x84a9, 0x1d73,
+ 0x84aa, 0x1d38,
+ 0x84ab, 0x1d3a,
+ 0x84ac, 0x1d46,
+ 0x84ad, 0x1d4a,
+ 0x84ae, 0x1d52,
+ 0x84af, 0x1d4e,
+ 0x84b0, 0x1d5a,
+ 0x84b1, 0x1d6a,
+ 0x84b2, 0x1d62,
+ 0x84b3, 0x1d72,
+ 0x84b4, 0x1d82,
+ 0x84b5, 0x1d57,
+ 0x84b6, 0x1d66,
+ 0x84b7, 0x1d5f,
+ 0x84b8, 0x1d6e,
+ 0x84b9, 0x1d76,
+ 0x84ba, 0x1d54,
+ 0x84bb, 0x1d67,
+ 0x84bc, 0x1d5c,
+ 0x84bd, 0x1d6f,
+ 0x84be, 0x1d79,
+ 0x8740, 0x1d83,
+ 0x875f, 0x1da1,
+ 0x8761, 0x1f66,
+ 0x8762, 0x1da4,
+ 0x8763, 0x1f68,
+ 0x8764, 0x1da6,
+ 0x8765, 0x1f6a,
+ 0x8766, 0x1da8,
+ 0x8768, 0x1f6c,
+ 0x8769, 0x1dab,
+ 0x876b, 0x1f6b,
+ 0x876c, 0x1dae,
+ 0x876e, 0x1f6f,
+ 0x876f, 0x1db1,
+ 0x877e, 0x2083,
+ 0x8780, 0x1db8,
+ 0x8784, 0x1f77,
+ 0x8785, 0x1dbd,
+ 0x8790, 0x02fa,
+ 0x8791, 0x02f9,
+ 0x8792, 0x0301,
+ 0x8793, 0x1dc8,
+ 0x879a, 0x0300,
+ 0x879b, 0x1dcf,
+ 0x889f, 0x0465,
+ 0x88a0, 0x1dd1,
+ 0x88a1, 0x0467,
+ 0x88a7, 0x204a,
+ 0x88a8, 0x046e,
+ 0x88b0, 0x1f19,
+ 0x88b1, 0x1ca2,
+ 0x88b2, 0x0478,
+ 0x88b9, 0x1dd2,
+ 0x88ba, 0x0480,
+ 0x88ec, 0x1dd3,
+ 0x88ed, 0x04b3,
+ 0x88f1, 0x1dd4,
+ 0x88f2, 0x04b8,
+ 0x88fa, 0x1dd5,
+ 0x88fb, 0x04c1,
+ 0x8940, 0x04c3,
+ 0x8949, 0x1dd6,
+ 0x894a, 0x04cd,
+ 0x8954, 0x1dd7,
+ 0x8955, 0x04d8,
+ 0x8958, 0x1dd8,
+ 0x8959, 0x04dc,
+ 0x895c, 0x1dda,
+ 0x895d, 0x04e0,
+ 0x8961, 0x1ddb,
+ 0x8962, 0x04e5,
+ 0x8980, 0x0502,
+ 0x898b, 0x1ddc,
+ 0x898c, 0x050e,
+ 0x89a6, 0x1ddd,
+ 0x89a7, 0x1cc9,
+ 0x89a8, 0x1dde,
+ 0x89a9, 0x052b,
+ 0x89de, 0x1ddf,
+ 0x89df, 0x0561,
+ 0x89f8, 0x1de0,
+ 0x89f9, 0x057b,
+ 0x89fb, 0x1de1,
+ 0x89fc, 0x057e,
+ 0x8a40, 0x057f,
+ 0x8a41, 0x1de2,
+ 0x8a42, 0x0581,
+ 0x8a61, 0x1961,
+ 0x8a62, 0x05a1,
+ 0x8a68, 0x139f,
+ 0x8a69, 0x05a8,
+ 0x8a80, 0x05be,
+ 0x8a85, 0x1de3,
+ 0x8a86, 0x05c4,
+ 0x8a8b, 0x1de4,
+ 0x8a8c, 0x05ca,
+ 0x8a93, 0x1de5,
+ 0x8a94, 0x05d2,
+ 0x8a96, 0x1731,
+ 0x8a97, 0x05d5,
+ 0x8a9a, 0x1de6,
+ 0x8a9b, 0x05d9,
+ 0x8ac0, 0x1de7,
+ 0x8ac1, 0x1572,
+ 0x8ac2, 0x0600,
+ 0x8acb, 0x1de8,
+ 0x8acc, 0x060a,
+ 0x8ad0, 0x1a20,
+ 0x8ad1, 0x060f,
+ 0x8ae3, 0x1de9,
+ 0x8ae4, 0x0622,
+ 0x8b40, 0x063b,
+ 0x8b4a, 0x1dea,
+ 0x8b4b, 0x0646,
+ 0x8b5f, 0x1deb,
+ 0x8b60, 0x065b,
+ 0x8b80, 0x067a,
+ 0x8ba0, 0x1dec,
+ 0x8ba1, 0x069b,
+ 0x8ba8, 0x1ded,
+ 0x8ba9, 0x06a3,
+ 0x8bc4, 0x1d32,
+ 0x8bc5, 0x06bf,
+ 0x8bcd, 0x1dee,
+ 0x8bce, 0x06c8,
+ 0x8beb, 0x1def,
+ 0x8bec, 0x06e6,
+ 0x8bf2, 0x1df0,
+ 0x8bf3, 0x06ed,
+ 0x8bf9, 0x1df1,
+ 0x8bfa, 0x06f4,
+ 0x8bfb, 0x1df2,
+ 0x8bfc, 0x06f6,
+ 0x8c40, 0x06f7,
+ 0x8c43, 0x1df3,
+ 0x8c44, 0x06fb,
+ 0x8c56, 0x1df4,
+ 0x8c57, 0x070e,
+ 0x8c64, 0x1df5,
+ 0x8c65, 0x071c,
+ 0x8c6d, 0x1df6,
+ 0x8c6e, 0x0725,
+ 0x8c71, 0x1df7,
+ 0x8c72, 0x0729,
+ 0x8c74, 0x1df8,
+ 0x8c75, 0x072c,
+ 0x8c7a, 0x1c0d,
+ 0x8c7b, 0x0732,
+ 0x8c80, 0x0736,
+ 0x8c84, 0x1df9,
+ 0x8c85, 0x073b,
+ 0x8c91, 0x1dfa,
+ 0x8c92, 0x0748,
+ 0x8c99, 0x1dfb,
+ 0x8c9a, 0x0750,
+ 0x8c9e, 0x1dfc,
+ 0x8c9f, 0x0755,
+ 0x8cb2, 0x1dfd,
+ 0x8cb3, 0x0769,
+ 0x8cbf, 0x1dfe,
+ 0x8cc0, 0x0776,
+ 0x8d40, 0x07b3,
+ 0x8d4a, 0x1dff,
+ 0x8d4b, 0x07be,
+ 0x8d56, 0x1e00,
+ 0x8d57, 0x07ca,
+ 0x8d61, 0x1e01,
+ 0x8d62, 0x07d5,
+ 0x8d7b, 0x16dd,
+ 0x8d7c, 0x07ef,
+ 0x8d80, 0x07f2,
+ 0x8d8d, 0x1e02,
+ 0x8d8e, 0x0800,
+ 0x8d94, 0x1e03,
+ 0x8d95, 0x0807,
+ 0x8d99, 0x1e04,
+ 0x8d9a, 0x080c,
+ 0x8dd1, 0x1e05,
+ 0x8dd2, 0x0844,
+ 0x8de5, 0x1e06,
+ 0x8de6, 0x0858,
+ 0x8df2, 0x1e07,
+ 0x8df3, 0x0865,
+ 0x8e40, 0x086f,
+ 0x8e46, 0x1e08,
+ 0x8e47, 0x0876,
+ 0x8e49, 0x1e09,
+ 0x8e4a, 0x0879,
+ 0x8e4b, 0x1e0a,
+ 0x8e4c, 0x087b,
+ 0x8e58, 0x1e0b,
+ 0x8e59, 0x0888,
+ 0x8e80, 0x08ae,
+ 0x8ec6, 0x1e0d,
+ 0x8ec7, 0x1929,
+ 0x8ec8, 0x08f6,
+ 0x8ed5, 0x1e0e,
+ 0x8ed6, 0x0904,
+ 0x8edb, 0x1e0f,
+ 0x8edd, 0x090b,
+ 0x8f40, 0x092b,
+ 0x8f4a, 0x1e11,
+ 0x8f4b, 0x0936,
+ 0x8f55, 0x1e12,
+ 0x8f56, 0x0941,
+ 0x8f80, 0x096a,
+ 0x8f8c, 0x1e13,
+ 0x8f8e, 0x0978,
+ 0x8f92, 0x1e15,
+ 0x8f94, 0x097e,
+ 0x8fa3, 0x1e17,
+ 0x8fa4, 0x098e,
+ 0x8fb1, 0x1e18,
+ 0x8fb2, 0x099c,
+ 0x8fbd, 0x1e19,
+ 0x8fbe, 0x09a8,
+ 0x8fd3, 0x1e1a,
+ 0x8fd4, 0x09be,
+ 0x8fdd, 0x1e1b,
+ 0x8fde, 0x09c8,
+ 0x8fe2, 0x1e1c,
+ 0x8fe3, 0x09cd,
+ 0x9040, 0x09e7,
+ 0x9049, 0x1e1d,
+ 0x904a, 0x09f1,
+ 0x9078, 0x1e1e,
+ 0x9079, 0x0a20,
+ 0x9080, 0x1e1f,
+ 0x9081, 0x0a27,
+ 0x9089, 0x1e20,
+ 0x908a, 0x0a30,
+ 0x90a0, 0x1e21,
+ 0x90a1, 0x0a47,
+ 0x90c0, 0x1e22,
+ 0x90c1, 0x0a67,
+ 0x90e4, 0x1e23,
+ 0x90e5, 0x0a8b,
+ 0x90ef, 0x1e24,
+ 0x90f1, 0x0a97,
+ 0x90f7, 0x1e26,
+ 0x90f9, 0x0a9f,
+ 0x9140, 0x0aa3,
+ 0x9146, 0x1e28,
+ 0x9147, 0x1a6e,
+ 0x9148, 0x0aab,
+ 0x9158, 0x1e29,
+ 0x9159, 0x0abc,
+ 0x916b, 0x1e2a,
+ 0x916c, 0x0acf,
+ 0x916e, 0x1e2b,
+ 0x916f, 0x0ad2,
+ 0x917e, 0x1e2c,
+ 0x9180, 0x0ae2,
+ 0x9189, 0x1e2d,
+ 0x918a, 0x0aec,
+ 0x91bb, 0x1e2e,
+ 0x91bc, 0x0b1e,
+ 0x91cb, 0x1e2f,
+ 0x91cc, 0x0b2e,
+ 0x91da, 0x1e30,
+ 0x91db, 0x0b3d,
+ 0x91e1, 0x1e31,
+ 0x91e2, 0x0b44,
+ 0x91ed, 0x1e32,
+ 0x91ee, 0x0b50,
+ 0x91f3, 0x1e33,
+ 0x91f5, 0x0b57,
+ 0x91fb, 0x1e35,
+ 0x91fc, 0x0b5e,
+ 0x9240, 0x0b5f,
+ 0x9246, 0x1e36,
+ 0x9247, 0x0b66,
+ 0x9248, 0x1e37,
+ 0x924a, 0x0b69,
+ 0x924c, 0x1e39,
+ 0x924e, 0x0b6d,
+ 0x925c, 0x1e3b,
+ 0x925d, 0x0b7c,
+ 0x9280, 0x0b9e,
+ 0x9290, 0x1e3c,
+ 0x9291, 0x0baf,
+ 0x9295, 0x1e3d,
+ 0x9296, 0x0bb4,
+ 0x929c, 0x1e3e,
+ 0x929d, 0x0bbb,
+ 0x92bb, 0x1e3f,
+ 0x92bc, 0x0bda,
+ 0x92c6, 0x1e40,
+ 0x92c7, 0x0be5,
+ 0x92c8, 0x1e41,
+ 0x92c9, 0x0be7,
+ 0x92cb, 0x1e42,
+ 0x92cc, 0x0bea,
+ 0x92cd, 0x1e43,
+ 0x92ce, 0x0bec,
+ 0x92d2, 0x204b,
+ 0x92d3, 0x0bf1,
+ 0x92d9, 0x11b5,
+ 0x92da, 0x0bf8,
+ 0x9340, 0x0c1b,
+ 0x9341, 0x1e44,
+ 0x9342, 0x0c1d,
+ 0x9346, 0x1e45,
+ 0x9347, 0x0c22,
+ 0x934d, 0x1e46,
+ 0x934e, 0x0c29,
+ 0x9355, 0x1e47,
+ 0x9356, 0x0c31,
+ 0x935e, 0x1e48,
+ 0x935f, 0x0c3a,
+ 0x9367, 0x1e49,
+ 0x9368, 0x0c43,
+ 0x936a, 0x1e4a,
+ 0x936b, 0x0c46,
+ 0x9370, 0x1e4b,
+ 0x9372, 0x0c4d,
+ 0x9376, 0x16df,
+ 0x9377, 0x0c52,
+ 0x9380, 0x0c5a,
+ 0x9384, 0x1e4d,
+ 0x9385, 0x0c5f,
+ 0x938e, 0x1450,
+ 0x938f, 0x0c69,
+ 0x9393, 0x1536,
+ 0x9394, 0x0c6e,
+ 0x9398, 0x1e4e,
+ 0x9399, 0x0c73,
+ 0x93bc, 0x1e4f,
+ 0x93bd, 0x0c97,
+ 0x93c0, 0x1e50,
+ 0x93c1, 0x0c9b,
+ 0x93d2, 0x1e51,
+ 0x93d4, 0x0cae,
+ 0x93d9, 0x1e53,
+ 0x93db, 0x0cb5,
+ 0x93df, 0x1e55,
+ 0x93e0, 0x0cba,
+ 0x93e4, 0x1e56,
+ 0x93e6, 0x0cc0,
+ 0x93e8, 0x1e58,
+ 0x93e9, 0x0cc3,
+ 0x93f4, 0x1aed,
+ 0x93f5, 0x0ccf,
+ 0x9440, 0x0cd7,
+ 0x9448, 0x1e59,
+ 0x9449, 0x0ce0,
+ 0x9458, 0x1e5a,
+ 0x9459, 0x0cf0,
+ 0x9476, 0x1e5b,
+ 0x9477, 0x0d0e,
+ 0x9480, 0x0d16,
+ 0x9487, 0x1e5c,
+ 0x9488, 0x1989,
+ 0x9489, 0x1e5d,
+ 0x948a, 0x0d20,
+ 0x948d, 0x1e5e,
+ 0x948e, 0x0d24,
+ 0x94a2, 0x1e5f,
+ 0x94a3, 0x0d39,
+ 0x94ac, 0x1e60,
+ 0x94ad, 0x0d43,
+ 0x94ae, 0x1e61,
+ 0x94af, 0x0d45,
+ 0x94d2, 0x1e62,
+ 0x94d3, 0x0d69,
+ 0x94e0, 0x1e63,
+ 0x94e1, 0x0d77,
+ 0x94f3, 0x1e64,
+ 0x94f4, 0x0d8a,
+ 0x9540, 0x0d93,
+ 0x9541, 0x1e65,
+ 0x9543, 0x0d96,
+ 0x954e, 0x1e67,
+ 0x954f, 0x143b,
+ 0x9550, 0x0da3,
+ 0x9551, 0x1e68,
+ 0x9552, 0x0da5,
+ 0x9554, 0x1e69,
+ 0x9555, 0x0da8,
+ 0x955f, 0x1e6a,
+ 0x9560, 0x0db3,
+ 0x956d, 0x1e6b,
+ 0x956e, 0x0dc1,
+ 0x9570, 0x1e6c,
+ 0x9571, 0x0dc4,
+ 0x9580, 0x0dd2,
+ 0x95c1, 0x1e6d,
+ 0x95c2, 0x0e14,
+ 0x95cb, 0x1e6e,
+ 0x95cc, 0x0e1e,
+ 0x95d8, 0x1e6f,
+ 0x95d9, 0x0e2b,
+ 0x95f7, 0x1e70,
+ 0x95f8, 0x0e4a,
+ 0x9640, 0x0e4f,
+ 0x9641, 0x1e71,
+ 0x9642, 0x0e51,
+ 0x9648, 0x1e72,
+ 0x9649, 0x0e58,
+ 0x966a, 0x1e73,
+ 0x966b, 0x0e7a,
+ 0x9680, 0x0e8e,
+ 0x968a, 0x1d33,
+ 0x968b, 0x0e99,
+ 0x9690, 0x1e74,
+ 0x9691, 0x0e9f,
+ 0x9698, 0x1f2c,
+ 0x9699, 0x102f,
+ 0x969a, 0x0ea8,
+ 0x96cb, 0x1e75,
+ 0x96cc, 0x0eda,
+ 0x96d7, 0x1e76,
+ 0x96d8, 0x0ee6,
+ 0x96dd, 0x1e77,
+ 0x96de, 0x0eec,
+ 0x96e0, 0x1e78,
+ 0x96e1, 0x0eef,
+ 0x96f7, 0x1935,
+ 0x96f8, 0x1e79,
+ 0x96f9, 0x0f07,
+ 0x96fa, 0x1e7a,
+ 0x96fb, 0x0f09,
+ 0x96fc, 0x1e7b,
+ 0x9740, 0x0f0b,
+ 0x9751, 0x1e7c,
+ 0x9752, 0x0f1d,
+ 0x976f, 0x1e7d,
+ 0x9770, 0x0f3b,
+ 0x9773, 0x1e7e,
+ 0x9774, 0x0f3f,
+ 0x9779, 0x1d34,
+ 0x977a, 0x0f45,
+ 0x9780, 0x0f4a,
+ 0x9789, 0x1e7f,
+ 0x978a, 0x0f54,
+ 0x97c9, 0x1e80,
+ 0x97ca, 0x0f94,
+ 0x97f8, 0x1e81,
+ 0x97fa, 0x0fc4,
+ 0x9840, 0x1e83,
+ 0x9841, 0x0fc8,
+ 0x9850, 0x1e84,
+ 0x9851, 0x0fd8,
+ 0x9855, 0x1777,
+ 0x9856, 0x0fdd,
+ 0x9858, 0x1e85,
+ 0x9859, 0x0fe0,
+ 0x989f, 0x0ffa,
+ 0x98d4, 0x0ea7,
+ 0x98d5, 0x1030,
+ 0x9940, 0x1058,
+ 0x995c, 0x1e86,
+ 0x995d, 0x1075,
+ 0x9966, 0x1e87,
+ 0x9967, 0x107f,
+ 0x996a, 0x1e88,
+ 0x996b, 0x1083,
+ 0x996c, 0x1e89,
+ 0x996d, 0x1085,
+ 0x9980, 0x1097,
+ 0x9a40, 0x1114,
+ 0x9a4f, 0x1e8a,
+ 0x9a50, 0x1124,
+ 0x9a59, 0x1e8b,
+ 0x9a5a, 0x112e,
+ 0x9a7d, 0x1e8d,
+ 0x9a7e, 0x1152,
+ 0x9a80, 0x1153,
+ 0x9a8b, 0x1e8e,
+ 0x9a8c, 0x115f,
+ 0x9ac2, 0x1e8f,
+ 0x9ac3, 0x1196,
+ 0x9ae2, 0x0bf7,
+ 0x9ae3, 0x11b6,
+ 0x9b40, 0x11d0,
+ 0x9b5c, 0x1e90,
+ 0x9b5d, 0x11ed,
+ 0x9b80, 0x120f,
+ 0x9b83, 0x1e91,
+ 0x9b84, 0x1213,
+ 0x9ba0, 0x1e92,
+ 0x9ba1, 0x1230,
+ 0x9c40, 0x128c,
+ 0x9c80, 0x12cb,
+ 0x9ca2, 0x1e94,
+ 0x9ca3, 0x12ee,
+ 0x9d40, 0x1348,
+ 0x9d80, 0x1e95,
+ 0x9d81, 0x1388,
+ 0x9d8c, 0x1e96,
+ 0x9d8d, 0x1394,
+ 0x9d98, 0x05a7,
+ 0x9d99, 0x13a0,
+ 0x9db7, 0x1e97,
+ 0x9db8, 0x13bf,
+ 0x9dcb, 0x1e98,
+ 0x9dcc, 0x13d3,
+ 0x9e40, 0x1404,
+ 0x9e64, 0x1e99,
+ 0x9e65, 0x1429,
+ 0x9e69, 0x1e9a,
+ 0x9e6a, 0x142e,
+ 0x9e77, 0x0da2,
+ 0x9e78, 0x143c,
+ 0x9e80, 0x1443,
+ 0x9e8b, 0x1e9b,
+ 0x9e8c, 0x144f,
+ 0x9e8d, 0x0c68,
+ 0x9e8e, 0x1451,
+ 0x9e94, 0x1e9c,
+ 0x9e95, 0x1458,
+ 0x9f40, 0x14c0,
+ 0x9f80, 0x14ff,
+ 0x9fb7, 0x0c6d,
+ 0x9fb8, 0x1537,
+ 0x9fce, 0x1e9d,
+ 0x9fcf, 0x154e,
+ 0x9ff3, 0x05ff,
+ 0x9ff4, 0x1573,
+ 0xe040, 0x157c,
+ 0xe080, 0x15bb,
+ 0xe0a4, 0x1e9f,
+ 0xe0a5, 0x15e0,
+ 0xe0dd, 0x1ea0,
+ 0xe0de, 0x1619,
+ 0xe0f4, 0x1d35,
+ 0xe0f5, 0x1630,
+ 0xe140, 0x1638,
+ 0xe14a, 0x1ea1,
+ 0xe14b, 0x1643,
+ 0xe14f, 0x1ea2,
+ 0xe151, 0x1649,
+ 0xe180, 0x1677,
+ 0xe1a9, 0x1ea4,
+ 0xe1aa, 0x16a1,
+ 0xe1e6, 0x07ee,
+ 0xe1e7, 0x16de,
+ 0xe1e8, 0x0c51,
+ 0xe1e9, 0x16e0,
+ 0xe1ed, 0x1ea5,
+ 0xe1ee, 0x16e5,
+ 0xe240, 0x16f4,
+ 0xe269, 0x1ea6,
+ 0xe26a, 0x171e,
+ 0xe273, 0x1ea7,
+ 0xe274, 0x1728,
+ 0xe27d, 0x05d4,
+ 0xe27e, 0x1732,
+ 0xe280, 0x1733,
+ 0xe2b7, 0x1ea8,
+ 0xe2b8, 0x176b,
+ 0xe2c4, 0x0fdc,
+ 0xe2c5, 0x1778,
+ 0xe2e2, 0x1ea9,
+ 0xe2e3, 0x1796,
+ 0xe2ec, 0x1eaa,
+ 0xe2ed, 0x17a0,
+ 0xe340, 0x17b0,
+ 0xe358, 0x1eab,
+ 0xe359, 0x17c9,
+ 0xe35a, 0x1eac,
+ 0xe35b, 0x17cb,
+ 0xe365, 0x1ead,
+ 0xe366, 0x17d6,
+ 0xe380, 0x17ef,
+ 0xe3c4, 0x1eae,
+ 0xe3c5, 0x1834,
+ 0xe440, 0x186c,
+ 0xe480, 0x18ab,
+ 0xe484, 0x1eaf,
+ 0xe485, 0x18b0,
+ 0xe489, 0x1eb0,
+ 0xe48a, 0x18b5,
+ 0xe492, 0x1eb1,
+ 0xe493, 0x18be,
+ 0xe4b2, 0x1eb2,
+ 0xe4b3, 0x18de,
+ 0xe4b9, 0x1eb3,
+ 0xe4ba, 0x18e5,
+ 0xe4f2, 0x1eb4,
+ 0xe4f3, 0x191e,
+ 0xe540, 0x1928,
+ 0xe541, 0x08f5,
+ 0xe542, 0x192a,
+ 0xe54d, 0x0f05,
+ 0xe54e, 0x1936,
+ 0xe579, 0x05a0,
+ 0xe57a, 0x1962,
+ 0xe580, 0x1967,
+ 0xe5a2, 0x0d1e,
+ 0xe5a3, 0x198a,
+ 0xe5a5, 0x1eb6,
+ 0xe5a6, 0x198d,
+ 0xe5bb, 0x1eb7,
+ 0xe5bc, 0x19a3,
+ 0xe5ed, 0x1eb8,
+ 0xe5ee, 0x19d5,
+ 0xe640, 0x19e4,
+ 0xe651, 0x1eb9,
+ 0xe652, 0x19f6,
+ 0xe67c, 0x060e,
+ 0xe67d, 0x1a21,
+ 0xe680, 0x1a23,
+ 0xe686, 0x1eba,
+ 0xe687, 0x1a2a,
+ 0xe696, 0x1ebb,
+ 0xe697, 0x1a3a,
+ 0xe6cb, 0x0aaa,
+ 0xe6cc, 0x1a6f,
+ 0xe6e7, 0x1ebc,
+ 0xe6e8, 0x1a8b,
+ 0xe6f2, 0x1ebd,
+ 0xe6f3, 0x1a96,
+ 0xe740, 0x1aa0,
+ 0xe76d, 0x1ebe,
+ 0xe76e, 0x1ace,
+ 0xe780, 0x1adf,
+ 0xe78c, 0x1ebf,
+ 0xe78d, 0x1aec,
+ 0xe78e, 0x1ec0,
+ 0xe78f, 0x1aee,
+ 0xe7a7, 0x1ec1,
+ 0xe7a8, 0x1b07,
+ 0xe7bb, 0x1ec2,
+ 0xe7bc, 0x1b1b,
+ 0xe7d5, 0x1ec3,
+ 0xe7d6, 0x1b35,
+ 0xe840, 0x1b5c,
+ 0xe880, 0x1b9b,
+ 0xe8c3, 0x1ec6,
+ 0xe8c4, 0x1bdf,
+ 0xe8cf, 0x1ec7,
+ 0xe8d0, 0x1beb,
+ 0xe8d5, 0x1ec8,
+ 0xe8d6, 0x1bf1,
+ 0xe8f2, 0x0731,
+ 0xe8f3, 0x1ec9,
+ 0xe8f4, 0x1c0f,
+ 0xe940, 0x1c18,
+ 0xe980, 0x1c57,
+ 0xe9ab, 0x1eca,
+ 0xe9ac, 0x1c83,
+ 0xe9ba, 0x1ecb,
+ 0xe9bb, 0x1c92,
+ 0xe9cb, 0x0477,
+ 0xe9cc, 0x1ecc,
+ 0xe9cd, 0x1ca4,
+ 0xe9f2, 0x0529,
+ 0xe9f3, 0x1cca,
+ 0xea40, 0x1cd4,
+ 0xea70, 0x1ecd,
+ 0xea71, 0x1d05,
+ 0xea80, 0x1d13,
+ 0xea9d, 0x1ece,
+ 0xea9e, 0x1d31,
+ 0xeaa3, 0x205c,
+ 0xed40, 0x20a7,
+ 0xed80, 0x20e6,
+ 0xedb4, 0x07c9,
+ 0xedb5, 0x211a,
+ 0xee40, 0x2162,
+ 0xee80, 0x21a1,
+ 0xeeef, 0x1f9c,
+ 0xeef9, 0x02ef,
+ 0xeefa, 0x1f45,
+ 0xfa40, 0x1f9c,
+ 0xfa4a, 0x1d97,
+ 0xfa54, 0x02ef,
+ 0xfa55, 0x1f45,
+ 0xfa58, 0x1dc2,
+ 0xfa59, 0x1dba,
+ 0xfa5a, 0x1f77,
+ 0xfa5b, 0x0300,
+ 0xfa5c, 0x20a7,
+ 0xfa80, 0x20ca,
+ 0xfad0, 0x07c9,
+ 0xfad1, 0x211a,
+ 0xfb40, 0x2146,
+ 0xfb80, 0x2185,
+ 0xfc40, 0x2202,
+ 0x8141, 0x1ecf,
+ 0x8143, 0x204c,
+ 0x8144, 0x2052,
+ 0x8150, 0x1ed1,
+ 0x815b, 0x1ed3,
+ 0x8160, 0x1ed6,
+ 0x8169, 0x1edb,
+ 0x8181, 0x1eed,
+ 0x81a8, 0x02e3,
+ 0x81a9, 0x02e2,
+ 0x81aa, 0x02e0,
+ 0x81ac, 0x204e,
+ 0x829f, 0x1eee,
+ 0x82a1, 0x1eef,
+ 0x82a3, 0x1ef0,
+ 0x82a5, 0x1ef1,
+ 0x82a7, 0x1ef2,
+ 0x82c1, 0x1ef3,
+ 0x82e1, 0x1ef4,
+ 0x82e3, 0x1ef5,
+ 0x82e5, 0x1ef6,
+ 0x82ec, 0x1ef7,
+ 0x8340, 0x1ef8,
+ 0x8342, 0x1ef9,
+ 0x8344, 0x1efa,
+ 0x8346, 0x1efb,
+ 0x8348, 0x1efc,
+ 0x8362, 0x1efd,
+ 0x8383, 0x1efe,
+ 0x8385, 0x1eff,
+ 0x8387, 0x1f00,
+ 0x838e, 0x1f01,
+ 0x8395, 0x1f02,
+ 0x849f, 0x1d39,
+ 0x84a0, 0x1d37,
+ 0x84a1, 0x1d47,
+ 0x84a2, 0x1d4f,
+ 0x84a3, 0x1d4b,
+ 0x84a4, 0x1d43,
+ 0x84a5, 0x1d63,
+ 0x84a6, 0x1d5b,
+ 0x84a7, 0x1d6b,
+ 0x84a8, 0x1d53,
+ 0x84a9, 0x1d73,
+ 0x84aa, 0x1d3a,
+ 0x84ab, 0x1d38,
+ 0x84ac, 0x1d4a,
+ 0x84ad, 0x1d52,
+ 0x84ae, 0x1d4e,
+ 0x84af, 0x1d46,
+ 0x84b0, 0x1d6a,
+ 0x84b1, 0x1d62,
+ 0x84b2, 0x1d72,
+ 0x84b3, 0x1d5a,
+ 0x84b4, 0x1d82,
+ 0x84b5, 0x1d66,
+ 0x84b6, 0x1d5f,
+ 0x84b7, 0x1d6e,
+ 0x84b8, 0x1d57,
+ 0x84b9, 0x1d79,
+ 0x84ba, 0x1d67,
+ 0x84bb, 0x1d5c,
+ 0x84bc, 0x1d6f,
+ 0x84bd, 0x1d54,
+ 0x84be, 0x1d76,
+ 0x875f, 0x1f04,
+ 0x8761, 0x2089,
+ 0x8762, 0x1f07,
+ 0x8763, 0x2093,
+ 0x8764, 0x1f09,
+ 0x8765, 0x2092,
+ 0x8766, 0x1f0b,
+ 0x8768, 0x2098,
+ 0x8769, 0x1f0e,
+ 0x876b, 0x209c,
+ 0x876c, 0x1f11,
+ 0x876e, 0x209d,
+ 0x8780, 0x1f14,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 japan1278msRKSJVEnc16 = {
+ 1,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee,
+ 0x00ef, 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6,
+ 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe,
+ 0x00ff, 0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106,
+ 0x0107, 0x0108, 0x0109, 0x010a, 0x010b, 0x010c, 0x010d, 0x010e,
+ 0x010f, 0x0110, 0x0111, 0x0112, 0x0113, 0x0114, 0x0115, 0x0116,
+ 0x0117, 0x0118, 0x0119, 0x011a, 0x011b, 0x011c, 0x011d, 0x011e,
+ 0x011f, 0x0120, 0x0121, 0x0122, 0x0123, 0x0124, 0x0125, 0x0126,
+ 0x0127, 0x0128, 0x0129, 0x012a, 0x012b, 0x012c, 0x012d, 0x012e,
+ 0x012f, 0x0130, 0x0131, 0x0132, 0x0133, 0x0134, 0x0135, 0x0136,
+ 0x0137, 0x0138, 0x0139, 0x013a, 0x013b, 0x013c, 0x013d, 0x013e,
+ 0x013f, 0x0140, 0x0141, 0x0142, 0x0143, 0x0144, 0x0277, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0146, 0x0147, 0x0148, 0x0149, 0x014a, 0x014b, 0x014c, 0x014d,
+ 0x014e, 0x014f, 0x0150, 0x0151, 0x0152, 0x0153, 0x0154, 0x0155,
+ 0x0156, 0x0157, 0x0158, 0x0159, 0x015a, 0x015b, 0x015c, 0x015d,
+ 0x015e, 0x015f, 0x0160, 0x0161, 0x0162, 0x0163, 0x0164, 0x0165,
+ 0x0166, 0x0167, 0x0168, 0x0169, 0x016a, 0x016b, 0x016c, 0x016d,
+ 0x016e, 0x016f, 0x0170, 0x0171, 0x0172, 0x0173, 0x0174, 0x0175,
+ 0x0176, 0x0177, 0x0178, 0x0179, 0x017a, 0x017b, 0x017c, 0x017d,
+ 0x017e, 0x017f, 0x0180, 0x0181, 0x0182, 0x0183, 0x0184, 0x0185,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ japan1278msRKSJVMap2, 790
+};
+
+static Gushort japan1283pvRKSJHMap2[436] = {
+ 0x0000, 0x0000,
+ 0x8140, 0x0279,
+ 0x8180, 0x02b8,
+ 0x81b8, 0x02e5,
+ 0x81c8, 0x02ed,
+ 0x81da, 0x02f4,
+ 0x81f0, 0x0303,
+ 0x81fc, 0x030b,
+ 0x824f, 0x030c,
+ 0x8260, 0x0316,
+ 0x8281, 0x0330,
+ 0x829f, 0x034a,
+ 0x8340, 0x039d,
+ 0x8380, 0x03dc,
+ 0x839f, 0x03f3,
+ 0x83bf, 0x040b,
+ 0x8440, 0x0423,
+ 0x8470, 0x0444,
+ 0x8480, 0x0453,
+ 0x849f, 0x1d37,
+ 0x84a0, 0x1d39,
+ 0x84a1, 0x1d43,
+ 0x84a2, 0x1d47,
+ 0x84a3, 0x1d4f,
+ 0x84a4, 0x1d4b,
+ 0x84a5, 0x1d53,
+ 0x84a6, 0x1d63,
+ 0x84a7, 0x1d5b,
+ 0x84a8, 0x1d6b,
+ 0x84a9, 0x1d73,
+ 0x84aa, 0x1d38,
+ 0x84ab, 0x1d3a,
+ 0x84ac, 0x1d46,
+ 0x84ad, 0x1d4a,
+ 0x84ae, 0x1d52,
+ 0x84af, 0x1d4e,
+ 0x84b0, 0x1d5a,
+ 0x84b1, 0x1d6a,
+ 0x84b2, 0x1d62,
+ 0x84b3, 0x1d72,
+ 0x84b4, 0x1d82,
+ 0x84b5, 0x1d57,
+ 0x84b6, 0x1d66,
+ 0x84b7, 0x1d5f,
+ 0x84b8, 0x1d6e,
+ 0x84b9, 0x1d76,
+ 0x84ba, 0x1d54,
+ 0x84bb, 0x1d67,
+ 0x84bc, 0x1d5c,
+ 0x84bd, 0x1d6f,
+ 0x84be, 0x1d79,
+ 0x8540, 0x00e8,
+ 0x8580, 0x0186,
+ 0x8581, 0x0128,
+ 0x859f, 0x0147,
+ 0x85de, 0x0187,
+ 0x8640, 0x01a6,
+ 0x8680, 0x01e5,
+ 0x8692, 0x0127,
+ 0x8693, 0x01f7,
+ 0x86a2, 0x1d37,
+ 0x8740, 0x1d83,
+ 0x875f, 0x1da1,
+ 0x8780, 0x1db8,
+ 0x8790, 0x02fa,
+ 0x8791, 0x02f9,
+ 0x8792, 0x0301,
+ 0x8793, 0x1dc8,
+ 0x879a, 0x0300,
+ 0x879b, 0x1dcf,
+ 0x889f, 0x0465,
+ 0x8940, 0x04c3,
+ 0x8980, 0x0502,
+ 0x8a40, 0x057f,
+ 0x8a80, 0x05be,
+ 0x8b40, 0x063b,
+ 0x8b80, 0x067a,
+ 0x8c40, 0x06f7,
+ 0x8c80, 0x0736,
+ 0x8d40, 0x07b3,
+ 0x8d80, 0x07f2,
+ 0x8e40, 0x086f,
+ 0x8e80, 0x08ae,
+ 0x8f40, 0x092b,
+ 0x8f80, 0x096a,
+ 0x9040, 0x09e7,
+ 0x9080, 0x0a26,
+ 0x9140, 0x0aa3,
+ 0x9180, 0x0ae2,
+ 0x9240, 0x0b5f,
+ 0x9280, 0x0b9e,
+ 0x9340, 0x0c1b,
+ 0x9380, 0x0c5a,
+ 0x9440, 0x0cd7,
+ 0x9480, 0x0d16,
+ 0x9540, 0x0d93,
+ 0x9580, 0x0dd2,
+ 0x9640, 0x0e4f,
+ 0x9680, 0x0e8e,
+ 0x9740, 0x0f0b,
+ 0x9780, 0x0f4a,
+ 0x9840, 0x0fc7,
+ 0x989f, 0x0ffa,
+ 0x9940, 0x1058,
+ 0x9980, 0x1097,
+ 0x9a40, 0x1114,
+ 0x9a80, 0x1153,
+ 0x9b40, 0x11d0,
+ 0x9b80, 0x120f,
+ 0x9c40, 0x128c,
+ 0x9c80, 0x12cb,
+ 0x9d40, 0x1348,
+ 0x9d80, 0x1387,
+ 0x9e40, 0x1404,
+ 0x9e80, 0x1443,
+ 0x9f40, 0x14c0,
+ 0x9f80, 0x14ff,
+ 0xe040, 0x157c,
+ 0xe080, 0x15bb,
+ 0xe140, 0x1638,
+ 0xe180, 0x1677,
+ 0xe240, 0x16f4,
+ 0xe280, 0x1733,
+ 0xe340, 0x17b0,
+ 0xe380, 0x17ef,
+ 0xe440, 0x186c,
+ 0xe480, 0x18ab,
+ 0xe540, 0x1928,
+ 0xe580, 0x1967,
+ 0xe640, 0x19e4,
+ 0xe680, 0x1a23,
+ 0xe740, 0x1aa0,
+ 0xe780, 0x1adf,
+ 0xe840, 0x1b5c,
+ 0xe880, 0x1b9b,
+ 0xe940, 0x1c18,
+ 0xe980, 0x1c57,
+ 0xea40, 0x1cd4,
+ 0xea80, 0x1d13,
+ 0xeaa3, 0x205c,
+ 0xeb40, 0x0279,
+ 0xeb41, 0x1ecf,
+ 0xeb43, 0x027c,
+ 0xeb50, 0x1ed1,
+ 0xeb52, 0x028b,
+ 0xeb5b, 0x1ed3,
+ 0xeb5e, 0x0297,
+ 0xeb60, 0x1ed6,
+ 0xeb65, 0x029e,
+ 0xeb69, 0x1edb,
+ 0xeb7b, 0x02b4,
+ 0xeb80, 0x02b8,
+ 0xeb81, 0x1eed,
+ 0xeb82, 0x02ba,
+ 0xebb8, 0x02e5,
+ 0xebc8, 0x02ed,
+ 0xebda, 0x02f4,
+ 0xebf0, 0x0303,
+ 0xebfc, 0x030b,
+ 0xec4f, 0x030c,
+ 0xec60, 0x0316,
+ 0xec81, 0x0330,
+ 0xec9f, 0x1eee,
+ 0xeca0, 0x034b,
+ 0xeca1, 0x1eef,
+ 0xeca2, 0x034d,
+ 0xeca3, 0x1ef0,
+ 0xeca4, 0x034f,
+ 0xeca5, 0x1ef1,
+ 0xeca6, 0x0351,
+ 0xeca7, 0x1ef2,
+ 0xeca8, 0x0353,
+ 0xecc1, 0x1ef3,
+ 0xecc2, 0x036d,
+ 0xece1, 0x1ef4,
+ 0xece2, 0x038d,
+ 0xece3, 0x1ef5,
+ 0xece4, 0x038f,
+ 0xece5, 0x1ef6,
+ 0xece6, 0x0391,
+ 0xecec, 0x1ef7,
+ 0xeced, 0x0398,
+ 0xed40, 0x1ef8,
+ 0xed41, 0x039e,
+ 0xed42, 0x1ef9,
+ 0xed43, 0x03a0,
+ 0xed44, 0x1efa,
+ 0xed45, 0x03a2,
+ 0xed46, 0x1efb,
+ 0xed47, 0x03a4,
+ 0xed48, 0x1efc,
+ 0xed49, 0x03a6,
+ 0xed62, 0x1efd,
+ 0xed63, 0x03c0,
+ 0xed80, 0x03dc,
+ 0xed83, 0x1efe,
+ 0xed84, 0x03e0,
+ 0xed85, 0x1eff,
+ 0xed86, 0x03e2,
+ 0xed87, 0x1f00,
+ 0xed88, 0x03e4,
+ 0xed8e, 0x1f01,
+ 0xed8f, 0x03eb,
+ 0xed95, 0x1f02,
+ 0xed9f, 0x03f3,
+ 0xedbf, 0x040b,
+ 0xee40, 0x1d83,
+ 0xee5f, 0x1f04,
+ 0xee6f, 0x1db1,
+ 0xee80, 0x1f14,
+ 0xee82, 0x1dba,
+ 0xee90, 0x02fa,
+ 0xee91, 0x02f9,
+ 0xee92, 0x0301,
+ 0xee93, 0x1dc8,
+ 0xee9a, 0x0300,
+ 0xee9b, 0x1dcf,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 japan1283pvRKSJHEnc16 = {
+ 0,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
+ 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010,
+ 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018,
+ 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020,
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028,
+ 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030,
+ 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038,
+ 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040,
+ 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048,
+ 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050,
+ 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
+ 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0000,
+ 0x0061, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0146, 0x0147, 0x0148, 0x0149, 0x014a, 0x014b, 0x014c, 0x014d,
+ 0x014e, 0x014f, 0x0150, 0x0151, 0x0152, 0x0153, 0x0154, 0x0155,
+ 0x0156, 0x0157, 0x0158, 0x0159, 0x015a, 0x015b, 0x015c, 0x015d,
+ 0x015e, 0x015f, 0x0160, 0x0161, 0x0162, 0x0163, 0x0164, 0x0165,
+ 0x0166, 0x0167, 0x0168, 0x0169, 0x016a, 0x016b, 0x016c, 0x016d,
+ 0x016e, 0x016f, 0x0170, 0x0171, 0x0172, 0x0173, 0x0174, 0x0175,
+ 0x0176, 0x0177, 0x0178, 0x0179, 0x017a, 0x017b, 0x017c, 0x017d,
+ 0x017e, 0x017f, 0x0180, 0x0181, 0x0182, 0x0183, 0x0184, 0x0185,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0098, 0x00e4, 0x007c },
+ japan1283pvRKSJHMap2, 218
+};
+
+static Gushort japan1290msRKSJHMap2[340] = {
+ 0x0000, 0x0000,
+ 0x8140, 0x0279,
+ 0x8180, 0x02b8,
+ 0x81b8, 0x02e5,
+ 0x81c8, 0x02ed,
+ 0x81da, 0x02f4,
+ 0x81f0, 0x0303,
+ 0x81fc, 0x030b,
+ 0x824f, 0x030c,
+ 0x8260, 0x0316,
+ 0x8281, 0x0330,
+ 0x829f, 0x034a,
+ 0x8340, 0x039d,
+ 0x8380, 0x03dc,
+ 0x839f, 0x03f3,
+ 0x83bf, 0x040b,
+ 0x8440, 0x0423,
+ 0x8470, 0x0444,
+ 0x8480, 0x0453,
+ 0x849f, 0x1d37,
+ 0x84a0, 0x1d39,
+ 0x84a1, 0x1d43,
+ 0x84a2, 0x1d47,
+ 0x84a3, 0x1d4f,
+ 0x84a4, 0x1d4b,
+ 0x84a5, 0x1d53,
+ 0x84a6, 0x1d63,
+ 0x84a7, 0x1d5b,
+ 0x84a8, 0x1d6b,
+ 0x84a9, 0x1d73,
+ 0x84aa, 0x1d38,
+ 0x84ab, 0x1d3a,
+ 0x84ac, 0x1d46,
+ 0x84ad, 0x1d4a,
+ 0x84ae, 0x1d52,
+ 0x84af, 0x1d4e,
+ 0x84b0, 0x1d5a,
+ 0x84b1, 0x1d6a,
+ 0x84b2, 0x1d62,
+ 0x84b3, 0x1d72,
+ 0x84b4, 0x1d82,
+ 0x84b5, 0x1d57,
+ 0x84b6, 0x1d66,
+ 0x84b7, 0x1d5f,
+ 0x84b8, 0x1d6e,
+ 0x84b9, 0x1d76,
+ 0x84ba, 0x1d54,
+ 0x84bb, 0x1d67,
+ 0x84bc, 0x1d5c,
+ 0x84bd, 0x1d6f,
+ 0x84be, 0x1d79,
+ 0x8740, 0x1d83,
+ 0x875f, 0x1da1,
+ 0x8761, 0x1f66,
+ 0x8762, 0x1da4,
+ 0x8763, 0x1f68,
+ 0x8764, 0x1da6,
+ 0x8765, 0x1f6a,
+ 0x8766, 0x1da8,
+ 0x8768, 0x1f6c,
+ 0x8769, 0x1dab,
+ 0x876b, 0x1f6b,
+ 0x876c, 0x1dae,
+ 0x876e, 0x1f6f,
+ 0x876f, 0x1db1,
+ 0x877e, 0x2083,
+ 0x8780, 0x1db8,
+ 0x8784, 0x1f77,
+ 0x8785, 0x1dbd,
+ 0x8790, 0x02fa,
+ 0x8791, 0x02f9,
+ 0x8792, 0x0301,
+ 0x8793, 0x1dc8,
+ 0x879a, 0x0300,
+ 0x879b, 0x1dcf,
+ 0x889f, 0x0465,
+ 0x8940, 0x04c3,
+ 0x8980, 0x0502,
+ 0x8a40, 0x057f,
+ 0x8a80, 0x05be,
+ 0x8b40, 0x063b,
+ 0x8b80, 0x067a,
+ 0x8c40, 0x06f7,
+ 0x8c80, 0x0736,
+ 0x8d40, 0x07b3,
+ 0x8d80, 0x07f2,
+ 0x8e40, 0x086f,
+ 0x8e80, 0x08ae,
+ 0x8f40, 0x092b,
+ 0x8f80, 0x096a,
+ 0x9040, 0x09e7,
+ 0x9080, 0x0a26,
+ 0x9140, 0x0aa3,
+ 0x9180, 0x0ae2,
+ 0x9240, 0x0b5f,
+ 0x9280, 0x0b9e,
+ 0x9340, 0x0c1b,
+ 0x9380, 0x0c5a,
+ 0x9440, 0x0cd7,
+ 0x9480, 0x0d16,
+ 0x9540, 0x0d93,
+ 0x9580, 0x0dd2,
+ 0x9640, 0x0e4f,
+ 0x9680, 0x0e8e,
+ 0x9740, 0x0f0b,
+ 0x9780, 0x0f4a,
+ 0x9840, 0x0fc7,
+ 0x989f, 0x0ffa,
+ 0x9940, 0x1058,
+ 0x9980, 0x1097,
+ 0x9a40, 0x1114,
+ 0x9a80, 0x1153,
+ 0x9b40, 0x11d0,
+ 0x9b80, 0x120f,
+ 0x9c40, 0x128c,
+ 0x9c80, 0x12cb,
+ 0x9d40, 0x1348,
+ 0x9d80, 0x1387,
+ 0x9e40, 0x1404,
+ 0x9e80, 0x1443,
+ 0x9f40, 0x14c0,
+ 0x9f80, 0x14ff,
+ 0xe040, 0x157c,
+ 0xe080, 0x15bb,
+ 0xe140, 0x1638,
+ 0xe180, 0x1677,
+ 0xe240, 0x16f4,
+ 0xe280, 0x1733,
+ 0xe340, 0x17b0,
+ 0xe380, 0x17ef,
+ 0xe440, 0x186c,
+ 0xe480, 0x18ab,
+ 0xe540, 0x1928,
+ 0xe580, 0x1967,
+ 0xe640, 0x19e4,
+ 0xe680, 0x1a23,
+ 0xe740, 0x1aa0,
+ 0xe780, 0x1adf,
+ 0xe840, 0x1b5c,
+ 0xe880, 0x1b9b,
+ 0xe940, 0x1c18,
+ 0xe980, 0x1c57,
+ 0xea40, 0x1cd4,
+ 0xea80, 0x1d13,
+ 0xeaa3, 0x205c,
+ 0xed40, 0x20a7,
+ 0xed80, 0x20e6,
+ 0xedb4, 0x07c9,
+ 0xedb5, 0x211a,
+ 0xee40, 0x2162,
+ 0xee80, 0x21a1,
+ 0xeeef, 0x1f9c,
+ 0xeef9, 0x02ef,
+ 0xeefa, 0x1f45,
+ 0xfa40, 0x1f9c,
+ 0xfa4a, 0x1d97,
+ 0xfa54, 0x02ef,
+ 0xfa55, 0x1f45,
+ 0xfa58, 0x1dc2,
+ 0xfa59, 0x1dba,
+ 0xfa5a, 0x1f77,
+ 0xfa5b, 0x0300,
+ 0xfa5c, 0x20a7,
+ 0xfa80, 0x20ca,
+ 0xfad0, 0x07c9,
+ 0xfad1, 0x211a,
+ 0xfb40, 0x2146,
+ 0xfb80, 0x2185,
+ 0xfc40, 0x2202,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 japan1290msRKSJHEnc16 = {
+ 0,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee,
+ 0x00ef, 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6,
+ 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe,
+ 0x00ff, 0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106,
+ 0x0107, 0x0108, 0x0109, 0x010a, 0x010b, 0x010c, 0x010d, 0x010e,
+ 0x010f, 0x0110, 0x0111, 0x0112, 0x0113, 0x0114, 0x0115, 0x0116,
+ 0x0117, 0x0118, 0x0119, 0x011a, 0x011b, 0x011c, 0x011d, 0x011e,
+ 0x011f, 0x0120, 0x0121, 0x0122, 0x0123, 0x0124, 0x0125, 0x0126,
+ 0x0127, 0x0128, 0x0129, 0x012a, 0x012b, 0x012c, 0x012d, 0x012e,
+ 0x012f, 0x0130, 0x0131, 0x0132, 0x0133, 0x0134, 0x0135, 0x0136,
+ 0x0137, 0x0138, 0x0139, 0x013a, 0x013b, 0x013c, 0x013d, 0x013e,
+ 0x013f, 0x0140, 0x0141, 0x0142, 0x0143, 0x0144, 0x0277, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0146, 0x0147, 0x0148, 0x0149, 0x014a, 0x014b, 0x014c, 0x014d,
+ 0x014e, 0x014f, 0x0150, 0x0151, 0x0152, 0x0153, 0x0154, 0x0155,
+ 0x0156, 0x0157, 0x0158, 0x0159, 0x015a, 0x015b, 0x015c, 0x015d,
+ 0x015e, 0x015f, 0x0160, 0x0161, 0x0162, 0x0163, 0x0164, 0x0165,
+ 0x0166, 0x0167, 0x0168, 0x0169, 0x016a, 0x016b, 0x016c, 0x016d,
+ 0x016e, 0x016f, 0x0170, 0x0171, 0x0172, 0x0173, 0x0174, 0x0175,
+ 0x0176, 0x0177, 0x0178, 0x0179, 0x017a, 0x017b, 0x017c, 0x017d,
+ 0x017e, 0x017f, 0x0180, 0x0181, 0x0182, 0x0183, 0x0184, 0x0185,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ japan1290msRKSJHMap2, 170
+};
+
+static Gushort japan1290msRKSJVMap2[496] = {
+ 0x0000, 0x0000,
+ 0x8140, 0x0279,
+ 0x8180, 0x02b8,
+ 0x81b8, 0x02e5,
+ 0x81c8, 0x02ed,
+ 0x81da, 0x02f4,
+ 0x81f0, 0x0303,
+ 0x81fc, 0x030b,
+ 0x824f, 0x030c,
+ 0x8260, 0x0316,
+ 0x8281, 0x0330,
+ 0x829f, 0x034a,
+ 0x8340, 0x039d,
+ 0x8380, 0x03dc,
+ 0x839f, 0x03f3,
+ 0x83bf, 0x040b,
+ 0x8440, 0x0423,
+ 0x8470, 0x0444,
+ 0x8480, 0x0453,
+ 0x849f, 0x1d37,
+ 0x84a0, 0x1d39,
+ 0x84a1, 0x1d43,
+ 0x84a2, 0x1d47,
+ 0x84a3, 0x1d4f,
+ 0x84a4, 0x1d4b,
+ 0x84a5, 0x1d53,
+ 0x84a6, 0x1d63,
+ 0x84a7, 0x1d5b,
+ 0x84a8, 0x1d6b,
+ 0x84a9, 0x1d73,
+ 0x84aa, 0x1d38,
+ 0x84ab, 0x1d3a,
+ 0x84ac, 0x1d46,
+ 0x84ad, 0x1d4a,
+ 0x84ae, 0x1d52,
+ 0x84af, 0x1d4e,
+ 0x84b0, 0x1d5a,
+ 0x84b1, 0x1d6a,
+ 0x84b2, 0x1d62,
+ 0x84b3, 0x1d72,
+ 0x84b4, 0x1d82,
+ 0x84b5, 0x1d57,
+ 0x84b6, 0x1d66,
+ 0x84b7, 0x1d5f,
+ 0x84b8, 0x1d6e,
+ 0x84b9, 0x1d76,
+ 0x84ba, 0x1d54,
+ 0x84bb, 0x1d67,
+ 0x84bc, 0x1d5c,
+ 0x84bd, 0x1d6f,
+ 0x84be, 0x1d79,
+ 0x8740, 0x1d83,
+ 0x875f, 0x1da1,
+ 0x8761, 0x1f66,
+ 0x8762, 0x1da4,
+ 0x8763, 0x1f68,
+ 0x8764, 0x1da6,
+ 0x8765, 0x1f6a,
+ 0x8766, 0x1da8,
+ 0x8768, 0x1f6c,
+ 0x8769, 0x1dab,
+ 0x876b, 0x1f6b,
+ 0x876c, 0x1dae,
+ 0x876e, 0x1f6f,
+ 0x876f, 0x1db1,
+ 0x877e, 0x2083,
+ 0x8780, 0x1db8,
+ 0x8784, 0x1f77,
+ 0x8785, 0x1dbd,
+ 0x8790, 0x02fa,
+ 0x8791, 0x02f9,
+ 0x8792, 0x0301,
+ 0x8793, 0x1dc8,
+ 0x879a, 0x0300,
+ 0x879b, 0x1dcf,
+ 0x889f, 0x0465,
+ 0x8940, 0x04c3,
+ 0x8980, 0x0502,
+ 0x8a40, 0x057f,
+ 0x8a80, 0x05be,
+ 0x8b40, 0x063b,
+ 0x8b80, 0x067a,
+ 0x8c40, 0x06f7,
+ 0x8c80, 0x0736,
+ 0x8d40, 0x07b3,
+ 0x8d80, 0x07f2,
+ 0x8e40, 0x086f,
+ 0x8e80, 0x08ae,
+ 0x8f40, 0x092b,
+ 0x8f80, 0x096a,
+ 0x9040, 0x09e7,
+ 0x9080, 0x0a26,
+ 0x9140, 0x0aa3,
+ 0x9180, 0x0ae2,
+ 0x9240, 0x0b5f,
+ 0x9280, 0x0b9e,
+ 0x9340, 0x0c1b,
+ 0x9380, 0x0c5a,
+ 0x9440, 0x0cd7,
+ 0x9480, 0x0d16,
+ 0x9540, 0x0d93,
+ 0x9580, 0x0dd2,
+ 0x9640, 0x0e4f,
+ 0x9680, 0x0e8e,
+ 0x9740, 0x0f0b,
+ 0x9780, 0x0f4a,
+ 0x9840, 0x0fc7,
+ 0x989f, 0x0ffa,
+ 0x9940, 0x1058,
+ 0x9980, 0x1097,
+ 0x9a40, 0x1114,
+ 0x9a80, 0x1153,
+ 0x9b40, 0x11d0,
+ 0x9b80, 0x120f,
+ 0x9c40, 0x128c,
+ 0x9c80, 0x12cb,
+ 0x9d40, 0x1348,
+ 0x9d80, 0x1387,
+ 0x9e40, 0x1404,
+ 0x9e80, 0x1443,
+ 0x9f40, 0x14c0,
+ 0x9f80, 0x14ff,
+ 0xe040, 0x157c,
+ 0xe080, 0x15bb,
+ 0xe140, 0x1638,
+ 0xe180, 0x1677,
+ 0xe240, 0x16f4,
+ 0xe280, 0x1733,
+ 0xe340, 0x17b0,
+ 0xe380, 0x17ef,
+ 0xe440, 0x186c,
+ 0xe480, 0x18ab,
+ 0xe540, 0x1928,
+ 0xe580, 0x1967,
+ 0xe640, 0x19e4,
+ 0xe680, 0x1a23,
+ 0xe740, 0x1aa0,
+ 0xe780, 0x1adf,
+ 0xe840, 0x1b5c,
+ 0xe880, 0x1b9b,
+ 0xe940, 0x1c18,
+ 0xe980, 0x1c57,
+ 0xea40, 0x1cd4,
+ 0xea80, 0x1d13,
+ 0xeaa3, 0x205c,
+ 0xed40, 0x20a7,
+ 0xed80, 0x20e6,
+ 0xedb4, 0x07c9,
+ 0xedb5, 0x211a,
+ 0xee40, 0x2162,
+ 0xee80, 0x21a1,
+ 0xeeef, 0x1f9c,
+ 0xeef9, 0x02ef,
+ 0xeefa, 0x1f45,
+ 0xfa40, 0x1f9c,
+ 0xfa4a, 0x1d97,
+ 0xfa54, 0x02ef,
+ 0xfa55, 0x1f45,
+ 0xfa58, 0x1dc2,
+ 0xfa59, 0x1dba,
+ 0xfa5a, 0x1f77,
+ 0xfa5b, 0x0300,
+ 0xfa5c, 0x20a7,
+ 0xfa80, 0x20ca,
+ 0xfad0, 0x07c9,
+ 0xfad1, 0x211a,
+ 0xfb40, 0x2146,
+ 0xfb80, 0x2185,
+ 0xfc40, 0x2202,
+ 0x8141, 0x1ecf,
+ 0x8143, 0x204c,
+ 0x8144, 0x2052,
+ 0x8150, 0x1ed1,
+ 0x815b, 0x1ed3,
+ 0x8160, 0x1ed6,
+ 0x8169, 0x1edb,
+ 0x8181, 0x1eed,
+ 0x81a8, 0x02e3,
+ 0x81a9, 0x02e2,
+ 0x81aa, 0x02e0,
+ 0x81ac, 0x204e,
+ 0x829f, 0x1eee,
+ 0x82a1, 0x1eef,
+ 0x82a3, 0x1ef0,
+ 0x82a5, 0x1ef1,
+ 0x82a7, 0x1ef2,
+ 0x82c1, 0x1ef3,
+ 0x82e1, 0x1ef4,
+ 0x82e3, 0x1ef5,
+ 0x82e5, 0x1ef6,
+ 0x82ec, 0x1ef7,
+ 0x8340, 0x1ef8,
+ 0x8342, 0x1ef9,
+ 0x8344, 0x1efa,
+ 0x8346, 0x1efb,
+ 0x8348, 0x1efc,
+ 0x8362, 0x1efd,
+ 0x8383, 0x1efe,
+ 0x8385, 0x1eff,
+ 0x8387, 0x1f00,
+ 0x838e, 0x1f01,
+ 0x8395, 0x1f02,
+ 0x849f, 0x1d39,
+ 0x84a0, 0x1d37,
+ 0x84a1, 0x1d47,
+ 0x84a2, 0x1d4f,
+ 0x84a3, 0x1d4b,
+ 0x84a4, 0x1d43,
+ 0x84a5, 0x1d63,
+ 0x84a6, 0x1d5b,
+ 0x84a7, 0x1d6b,
+ 0x84a8, 0x1d53,
+ 0x84a9, 0x1d73,
+ 0x84aa, 0x1d3a,
+ 0x84ab, 0x1d38,
+ 0x84ac, 0x1d4a,
+ 0x84ad, 0x1d52,
+ 0x84ae, 0x1d4e,
+ 0x84af, 0x1d46,
+ 0x84b0, 0x1d6a,
+ 0x84b1, 0x1d62,
+ 0x84b2, 0x1d72,
+ 0x84b3, 0x1d5a,
+ 0x84b4, 0x1d82,
+ 0x84b5, 0x1d66,
+ 0x84b6, 0x1d5f,
+ 0x84b7, 0x1d6e,
+ 0x84b8, 0x1d57,
+ 0x84b9, 0x1d79,
+ 0x84ba, 0x1d67,
+ 0x84bb, 0x1d5c,
+ 0x84bc, 0x1d6f,
+ 0x84bd, 0x1d54,
+ 0x84be, 0x1d76,
+ 0x875f, 0x1f04,
+ 0x8761, 0x2089,
+ 0x8762, 0x1f07,
+ 0x8763, 0x2093,
+ 0x8764, 0x1f09,
+ 0x8765, 0x2092,
+ 0x8766, 0x1f0b,
+ 0x8768, 0x2098,
+ 0x8769, 0x1f0e,
+ 0x876b, 0x209c,
+ 0x876c, 0x1f11,
+ 0x876e, 0x209d,
+ 0x8780, 0x1f14,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 japan1290msRKSJVEnc16 = {
+ 1,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee,
+ 0x00ef, 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6,
+ 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe,
+ 0x00ff, 0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106,
+ 0x0107, 0x0108, 0x0109, 0x010a, 0x010b, 0x010c, 0x010d, 0x010e,
+ 0x010f, 0x0110, 0x0111, 0x0112, 0x0113, 0x0114, 0x0115, 0x0116,
+ 0x0117, 0x0118, 0x0119, 0x011a, 0x011b, 0x011c, 0x011d, 0x011e,
+ 0x011f, 0x0120, 0x0121, 0x0122, 0x0123, 0x0124, 0x0125, 0x0126,
+ 0x0127, 0x0128, 0x0129, 0x012a, 0x012b, 0x012c, 0x012d, 0x012e,
+ 0x012f, 0x0130, 0x0131, 0x0132, 0x0133, 0x0134, 0x0135, 0x0136,
+ 0x0137, 0x0138, 0x0139, 0x013a, 0x013b, 0x013c, 0x013d, 0x013e,
+ 0x013f, 0x0140, 0x0141, 0x0142, 0x0143, 0x0144, 0x0277, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0146, 0x0147, 0x0148, 0x0149, 0x014a, 0x014b, 0x014c, 0x014d,
+ 0x014e, 0x014f, 0x0150, 0x0151, 0x0152, 0x0153, 0x0154, 0x0155,
+ 0x0156, 0x0157, 0x0158, 0x0159, 0x015a, 0x015b, 0x015c, 0x015d,
+ 0x015e, 0x015f, 0x0160, 0x0161, 0x0162, 0x0163, 0x0164, 0x0165,
+ 0x0166, 0x0167, 0x0168, 0x0169, 0x016a, 0x016b, 0x016c, 0x016d,
+ 0x016e, 0x016f, 0x0170, 0x0171, 0x0172, 0x0173, 0x0174, 0x0175,
+ 0x0176, 0x0177, 0x0178, 0x0179, 0x017a, 0x017b, 0x017c, 0x017d,
+ 0x017e, 0x017f, 0x0180, 0x0181, 0x0182, 0x0183, 0x0184, 0x0185,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ japan1290msRKSJVMap2, 248
+};
+
+static Gushort japan1290mspRKSJHMap2[340] = {
+ 0x0000, 0x0000,
+ 0x8140, 0x0279,
+ 0x8180, 0x02b8,
+ 0x81b8, 0x02e5,
+ 0x81c8, 0x02ed,
+ 0x81da, 0x02f4,
+ 0x81f0, 0x0303,
+ 0x81fc, 0x030b,
+ 0x824f, 0x030c,
+ 0x8260, 0x0316,
+ 0x8281, 0x0330,
+ 0x829f, 0x034a,
+ 0x8340, 0x039d,
+ 0x8380, 0x03dc,
+ 0x839f, 0x03f3,
+ 0x83bf, 0x040b,
+ 0x8440, 0x0423,
+ 0x8470, 0x0444,
+ 0x8480, 0x0453,
+ 0x849f, 0x1d37,
+ 0x84a0, 0x1d39,
+ 0x84a1, 0x1d43,
+ 0x84a2, 0x1d47,
+ 0x84a3, 0x1d4f,
+ 0x84a4, 0x1d4b,
+ 0x84a5, 0x1d53,
+ 0x84a6, 0x1d63,
+ 0x84a7, 0x1d5b,
+ 0x84a8, 0x1d6b,
+ 0x84a9, 0x1d73,
+ 0x84aa, 0x1d38,
+ 0x84ab, 0x1d3a,
+ 0x84ac, 0x1d46,
+ 0x84ad, 0x1d4a,
+ 0x84ae, 0x1d52,
+ 0x84af, 0x1d4e,
+ 0x84b0, 0x1d5a,
+ 0x84b1, 0x1d6a,
+ 0x84b2, 0x1d62,
+ 0x84b3, 0x1d72,
+ 0x84b4, 0x1d82,
+ 0x84b5, 0x1d57,
+ 0x84b6, 0x1d66,
+ 0x84b7, 0x1d5f,
+ 0x84b8, 0x1d6e,
+ 0x84b9, 0x1d76,
+ 0x84ba, 0x1d54,
+ 0x84bb, 0x1d67,
+ 0x84bc, 0x1d5c,
+ 0x84bd, 0x1d6f,
+ 0x84be, 0x1d79,
+ 0x8740, 0x1d83,
+ 0x875f, 0x1da1,
+ 0x8761, 0x1f66,
+ 0x8762, 0x1da4,
+ 0x8763, 0x1f68,
+ 0x8764, 0x1da6,
+ 0x8765, 0x1f6a,
+ 0x8766, 0x1da8,
+ 0x8768, 0x1f6c,
+ 0x8769, 0x1dab,
+ 0x876b, 0x1f6b,
+ 0x876c, 0x1dae,
+ 0x876e, 0x1f6f,
+ 0x876f, 0x1db1,
+ 0x877e, 0x2083,
+ 0x8780, 0x1db8,
+ 0x8784, 0x1f77,
+ 0x8785, 0x1dbd,
+ 0x8790, 0x02fa,
+ 0x8791, 0x02f9,
+ 0x8792, 0x0301,
+ 0x8793, 0x1dc8,
+ 0x879a, 0x0300,
+ 0x879b, 0x1dcf,
+ 0x889f, 0x0465,
+ 0x8940, 0x04c3,
+ 0x8980, 0x0502,
+ 0x8a40, 0x057f,
+ 0x8a80, 0x05be,
+ 0x8b40, 0x063b,
+ 0x8b80, 0x067a,
+ 0x8c40, 0x06f7,
+ 0x8c80, 0x0736,
+ 0x8d40, 0x07b3,
+ 0x8d80, 0x07f2,
+ 0x8e40, 0x086f,
+ 0x8e80, 0x08ae,
+ 0x8f40, 0x092b,
+ 0x8f80, 0x096a,
+ 0x9040, 0x09e7,
+ 0x9080, 0x0a26,
+ 0x9140, 0x0aa3,
+ 0x9180, 0x0ae2,
+ 0x9240, 0x0b5f,
+ 0x9280, 0x0b9e,
+ 0x9340, 0x0c1b,
+ 0x9380, 0x0c5a,
+ 0x9440, 0x0cd7,
+ 0x9480, 0x0d16,
+ 0x9540, 0x0d93,
+ 0x9580, 0x0dd2,
+ 0x9640, 0x0e4f,
+ 0x9680, 0x0e8e,
+ 0x9740, 0x0f0b,
+ 0x9780, 0x0f4a,
+ 0x9840, 0x0fc7,
+ 0x989f, 0x0ffa,
+ 0x9940, 0x1058,
+ 0x9980, 0x1097,
+ 0x9a40, 0x1114,
+ 0x9a80, 0x1153,
+ 0x9b40, 0x11d0,
+ 0x9b80, 0x120f,
+ 0x9c40, 0x128c,
+ 0x9c80, 0x12cb,
+ 0x9d40, 0x1348,
+ 0x9d80, 0x1387,
+ 0x9e40, 0x1404,
+ 0x9e80, 0x1443,
+ 0x9f40, 0x14c0,
+ 0x9f80, 0x14ff,
+ 0xe040, 0x157c,
+ 0xe080, 0x15bb,
+ 0xe140, 0x1638,
+ 0xe180, 0x1677,
+ 0xe240, 0x16f4,
+ 0xe280, 0x1733,
+ 0xe340, 0x17b0,
+ 0xe380, 0x17ef,
+ 0xe440, 0x186c,
+ 0xe480, 0x18ab,
+ 0xe540, 0x1928,
+ 0xe580, 0x1967,
+ 0xe640, 0x19e4,
+ 0xe680, 0x1a23,
+ 0xe740, 0x1aa0,
+ 0xe780, 0x1adf,
+ 0xe840, 0x1b5c,
+ 0xe880, 0x1b9b,
+ 0xe940, 0x1c18,
+ 0xe980, 0x1c57,
+ 0xea40, 0x1cd4,
+ 0xea80, 0x1d13,
+ 0xeaa3, 0x205c,
+ 0xed40, 0x20a7,
+ 0xed80, 0x20e6,
+ 0xedb4, 0x07c9,
+ 0xedb5, 0x211a,
+ 0xee40, 0x2162,
+ 0xee80, 0x21a1,
+ 0xeeef, 0x1f9c,
+ 0xeef9, 0x02ef,
+ 0xeefa, 0x1f45,
+ 0xfa40, 0x1f9c,
+ 0xfa4a, 0x1d97,
+ 0xfa54, 0x02ef,
+ 0xfa55, 0x1f45,
+ 0xfa58, 0x1dc2,
+ 0xfa59, 0x1dba,
+ 0xfa5a, 0x1f77,
+ 0xfa5b, 0x0300,
+ 0xfa5c, 0x20a7,
+ 0xfa80, 0x20ca,
+ 0xfad0, 0x07c9,
+ 0xfad1, 0x211a,
+ 0xfb40, 0x2146,
+ 0xfb80, 0x2185,
+ 0xfc40, 0x2202,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 japan1290mspRKSJHEnc16 = {
+ 0,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
+ 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010,
+ 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018,
+ 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020,
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028,
+ 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030,
+ 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038,
+ 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040,
+ 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048,
+ 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050,
+ 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
+ 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0146, 0x0147, 0x0148, 0x0149, 0x014a, 0x014b, 0x014c, 0x014d,
+ 0x014e, 0x014f, 0x0150, 0x0151, 0x0152, 0x0153, 0x0154, 0x0155,
+ 0x0156, 0x0157, 0x0158, 0x0159, 0x015a, 0x015b, 0x015c, 0x015d,
+ 0x015e, 0x015f, 0x0160, 0x0161, 0x0162, 0x0163, 0x0164, 0x0165,
+ 0x0166, 0x0167, 0x0168, 0x0169, 0x016a, 0x016b, 0x016c, 0x016d,
+ 0x016e, 0x016f, 0x0170, 0x0171, 0x0172, 0x0173, 0x0174, 0x0175,
+ 0x0176, 0x0177, 0x0178, 0x0179, 0x017a, 0x017b, 0x017c, 0x017d,
+ 0x017e, 0x017f, 0x0180, 0x0181, 0x0182, 0x0183, 0x0184, 0x0185,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ japan1290mspRKSJHMap2, 170
+};
+
+static Gushort japan1290mspRKSJVMap2[496] = {
+ 0x0000, 0x0000,
+ 0x8140, 0x0279,
+ 0x8180, 0x02b8,
+ 0x81b8, 0x02e5,
+ 0x81c8, 0x02ed,
+ 0x81da, 0x02f4,
+ 0x81f0, 0x0303,
+ 0x81fc, 0x030b,
+ 0x824f, 0x030c,
+ 0x8260, 0x0316,
+ 0x8281, 0x0330,
+ 0x829f, 0x034a,
+ 0x8340, 0x039d,
+ 0x8380, 0x03dc,
+ 0x839f, 0x03f3,
+ 0x83bf, 0x040b,
+ 0x8440, 0x0423,
+ 0x8470, 0x0444,
+ 0x8480, 0x0453,
+ 0x849f, 0x1d37,
+ 0x84a0, 0x1d39,
+ 0x84a1, 0x1d43,
+ 0x84a2, 0x1d47,
+ 0x84a3, 0x1d4f,
+ 0x84a4, 0x1d4b,
+ 0x84a5, 0x1d53,
+ 0x84a6, 0x1d63,
+ 0x84a7, 0x1d5b,
+ 0x84a8, 0x1d6b,
+ 0x84a9, 0x1d73,
+ 0x84aa, 0x1d38,
+ 0x84ab, 0x1d3a,
+ 0x84ac, 0x1d46,
+ 0x84ad, 0x1d4a,
+ 0x84ae, 0x1d52,
+ 0x84af, 0x1d4e,
+ 0x84b0, 0x1d5a,
+ 0x84b1, 0x1d6a,
+ 0x84b2, 0x1d62,
+ 0x84b3, 0x1d72,
+ 0x84b4, 0x1d82,
+ 0x84b5, 0x1d57,
+ 0x84b6, 0x1d66,
+ 0x84b7, 0x1d5f,
+ 0x84b8, 0x1d6e,
+ 0x84b9, 0x1d76,
+ 0x84ba, 0x1d54,
+ 0x84bb, 0x1d67,
+ 0x84bc, 0x1d5c,
+ 0x84bd, 0x1d6f,
+ 0x84be, 0x1d79,
+ 0x8740, 0x1d83,
+ 0x875f, 0x1da1,
+ 0x8761, 0x1f66,
+ 0x8762, 0x1da4,
+ 0x8763, 0x1f68,
+ 0x8764, 0x1da6,
+ 0x8765, 0x1f6a,
+ 0x8766, 0x1da8,
+ 0x8768, 0x1f6c,
+ 0x8769, 0x1dab,
+ 0x876b, 0x1f6b,
+ 0x876c, 0x1dae,
+ 0x876e, 0x1f6f,
+ 0x876f, 0x1db1,
+ 0x877e, 0x2083,
+ 0x8780, 0x1db8,
+ 0x8784, 0x1f77,
+ 0x8785, 0x1dbd,
+ 0x8790, 0x02fa,
+ 0x8791, 0x02f9,
+ 0x8792, 0x0301,
+ 0x8793, 0x1dc8,
+ 0x879a, 0x0300,
+ 0x879b, 0x1dcf,
+ 0x889f, 0x0465,
+ 0x8940, 0x04c3,
+ 0x8980, 0x0502,
+ 0x8a40, 0x057f,
+ 0x8a80, 0x05be,
+ 0x8b40, 0x063b,
+ 0x8b80, 0x067a,
+ 0x8c40, 0x06f7,
+ 0x8c80, 0x0736,
+ 0x8d40, 0x07b3,
+ 0x8d80, 0x07f2,
+ 0x8e40, 0x086f,
+ 0x8e80, 0x08ae,
+ 0x8f40, 0x092b,
+ 0x8f80, 0x096a,
+ 0x9040, 0x09e7,
+ 0x9080, 0x0a26,
+ 0x9140, 0x0aa3,
+ 0x9180, 0x0ae2,
+ 0x9240, 0x0b5f,
+ 0x9280, 0x0b9e,
+ 0x9340, 0x0c1b,
+ 0x9380, 0x0c5a,
+ 0x9440, 0x0cd7,
+ 0x9480, 0x0d16,
+ 0x9540, 0x0d93,
+ 0x9580, 0x0dd2,
+ 0x9640, 0x0e4f,
+ 0x9680, 0x0e8e,
+ 0x9740, 0x0f0b,
+ 0x9780, 0x0f4a,
+ 0x9840, 0x0fc7,
+ 0x989f, 0x0ffa,
+ 0x9940, 0x1058,
+ 0x9980, 0x1097,
+ 0x9a40, 0x1114,
+ 0x9a80, 0x1153,
+ 0x9b40, 0x11d0,
+ 0x9b80, 0x120f,
+ 0x9c40, 0x128c,
+ 0x9c80, 0x12cb,
+ 0x9d40, 0x1348,
+ 0x9d80, 0x1387,
+ 0x9e40, 0x1404,
+ 0x9e80, 0x1443,
+ 0x9f40, 0x14c0,
+ 0x9f80, 0x14ff,
+ 0xe040, 0x157c,
+ 0xe080, 0x15bb,
+ 0xe140, 0x1638,
+ 0xe180, 0x1677,
+ 0xe240, 0x16f4,
+ 0xe280, 0x1733,
+ 0xe340, 0x17b0,
+ 0xe380, 0x17ef,
+ 0xe440, 0x186c,
+ 0xe480, 0x18ab,
+ 0xe540, 0x1928,
+ 0xe580, 0x1967,
+ 0xe640, 0x19e4,
+ 0xe680, 0x1a23,
+ 0xe740, 0x1aa0,
+ 0xe780, 0x1adf,
+ 0xe840, 0x1b5c,
+ 0xe880, 0x1b9b,
+ 0xe940, 0x1c18,
+ 0xe980, 0x1c57,
+ 0xea40, 0x1cd4,
+ 0xea80, 0x1d13,
+ 0xeaa3, 0x205c,
+ 0xed40, 0x20a7,
+ 0xed80, 0x20e6,
+ 0xedb4, 0x07c9,
+ 0xedb5, 0x211a,
+ 0xee40, 0x2162,
+ 0xee80, 0x21a1,
+ 0xeeef, 0x1f9c,
+ 0xeef9, 0x02ef,
+ 0xeefa, 0x1f45,
+ 0xfa40, 0x1f9c,
+ 0xfa4a, 0x1d97,
+ 0xfa54, 0x02ef,
+ 0xfa55, 0x1f45,
+ 0xfa58, 0x1dc2,
+ 0xfa59, 0x1dba,
+ 0xfa5a, 0x1f77,
+ 0xfa5b, 0x0300,
+ 0xfa5c, 0x20a7,
+ 0xfa80, 0x20ca,
+ 0xfad0, 0x07c9,
+ 0xfad1, 0x211a,
+ 0xfb40, 0x2146,
+ 0xfb80, 0x2185,
+ 0xfc40, 0x2202,
+ 0x8141, 0x1ecf,
+ 0x8143, 0x204c,
+ 0x8144, 0x2052,
+ 0x8150, 0x1ed1,
+ 0x815b, 0x1ed3,
+ 0x8160, 0x1ed6,
+ 0x8169, 0x1edb,
+ 0x8181, 0x1eed,
+ 0x81a8, 0x02e3,
+ 0x81a9, 0x02e2,
+ 0x81aa, 0x02e0,
+ 0x81ac, 0x204e,
+ 0x829f, 0x1eee,
+ 0x82a1, 0x1eef,
+ 0x82a3, 0x1ef0,
+ 0x82a5, 0x1ef1,
+ 0x82a7, 0x1ef2,
+ 0x82c1, 0x1ef3,
+ 0x82e1, 0x1ef4,
+ 0x82e3, 0x1ef5,
+ 0x82e5, 0x1ef6,
+ 0x82ec, 0x1ef7,
+ 0x8340, 0x1ef8,
+ 0x8342, 0x1ef9,
+ 0x8344, 0x1efa,
+ 0x8346, 0x1efb,
+ 0x8348, 0x1efc,
+ 0x8362, 0x1efd,
+ 0x8383, 0x1efe,
+ 0x8385, 0x1eff,
+ 0x8387, 0x1f00,
+ 0x838e, 0x1f01,
+ 0x8395, 0x1f02,
+ 0x849f, 0x1d39,
+ 0x84a0, 0x1d37,
+ 0x84a1, 0x1d47,
+ 0x84a2, 0x1d4f,
+ 0x84a3, 0x1d4b,
+ 0x84a4, 0x1d43,
+ 0x84a5, 0x1d63,
+ 0x84a6, 0x1d5b,
+ 0x84a7, 0x1d6b,
+ 0x84a8, 0x1d53,
+ 0x84a9, 0x1d73,
+ 0x84aa, 0x1d3a,
+ 0x84ab, 0x1d38,
+ 0x84ac, 0x1d4a,
+ 0x84ad, 0x1d52,
+ 0x84ae, 0x1d4e,
+ 0x84af, 0x1d46,
+ 0x84b0, 0x1d6a,
+ 0x84b1, 0x1d62,
+ 0x84b2, 0x1d72,
+ 0x84b3, 0x1d5a,
+ 0x84b4, 0x1d82,
+ 0x84b5, 0x1d66,
+ 0x84b6, 0x1d5f,
+ 0x84b7, 0x1d6e,
+ 0x84b8, 0x1d57,
+ 0x84b9, 0x1d79,
+ 0x84ba, 0x1d67,
+ 0x84bb, 0x1d5c,
+ 0x84bc, 0x1d6f,
+ 0x84bd, 0x1d54,
+ 0x84be, 0x1d76,
+ 0x875f, 0x1f04,
+ 0x8761, 0x2089,
+ 0x8762, 0x1f07,
+ 0x8763, 0x2093,
+ 0x8764, 0x1f09,
+ 0x8765, 0x2092,
+ 0x8766, 0x1f0b,
+ 0x8768, 0x2098,
+ 0x8769, 0x1f0e,
+ 0x876b, 0x209c,
+ 0x876c, 0x1f11,
+ 0x876e, 0x209d,
+ 0x8780, 0x1f14,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 japan1290mspRKSJVEnc16 = {
+ 1,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
+ 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010,
+ 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018,
+ 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020,
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028,
+ 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030,
+ 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038,
+ 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040,
+ 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048,
+ 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050,
+ 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
+ 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0146, 0x0147, 0x0148, 0x0149, 0x014a, 0x014b, 0x014c, 0x014d,
+ 0x014e, 0x014f, 0x0150, 0x0151, 0x0152, 0x0153, 0x0154, 0x0155,
+ 0x0156, 0x0157, 0x0158, 0x0159, 0x015a, 0x015b, 0x015c, 0x015d,
+ 0x015e, 0x015f, 0x0160, 0x0161, 0x0162, 0x0163, 0x0164, 0x0165,
+ 0x0166, 0x0167, 0x0168, 0x0169, 0x016a, 0x016b, 0x016c, 0x016d,
+ 0x016e, 0x016f, 0x0170, 0x0171, 0x0172, 0x0173, 0x0174, 0x0175,
+ 0x0176, 0x0177, 0x0178, 0x0179, 0x017a, 0x017b, 0x017c, 0x017d,
+ 0x017e, 0x017f, 0x0180, 0x0181, 0x0182, 0x0183, 0x0184, 0x0185,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ japan1290mspRKSJVMap2, 248
+};
+
+static Gushort japan1290pvRKSJHMap2[518] = {
+ 0x0000, 0x0000,
+ 0x8140, 0x0279,
+ 0x8180, 0x02b8,
+ 0x81b8, 0x02e5,
+ 0x81c8, 0x02ed,
+ 0x81da, 0x02f4,
+ 0x81f0, 0x0303,
+ 0x81fc, 0x030b,
+ 0x824f, 0x030c,
+ 0x8260, 0x0316,
+ 0x8281, 0x0330,
+ 0x829f, 0x034a,
+ 0x8340, 0x039d,
+ 0x8380, 0x03dc,
+ 0x839f, 0x03f3,
+ 0x83bf, 0x040b,
+ 0x8440, 0x0423,
+ 0x8470, 0x0444,
+ 0x8480, 0x0453,
+ 0x849f, 0x1d37,
+ 0x84a0, 0x1d39,
+ 0x84a1, 0x1d43,
+ 0x84a2, 0x1d47,
+ 0x84a3, 0x1d4f,
+ 0x84a4, 0x1d4b,
+ 0x84a5, 0x1d53,
+ 0x84a6, 0x1d63,
+ 0x84a7, 0x1d5b,
+ 0x84a8, 0x1d6b,
+ 0x84a9, 0x1d73,
+ 0x84aa, 0x1d38,
+ 0x84ab, 0x1d3a,
+ 0x84ac, 0x1d46,
+ 0x84ad, 0x1d4a,
+ 0x84ae, 0x1d52,
+ 0x84af, 0x1d4e,
+ 0x84b0, 0x1d5a,
+ 0x84b1, 0x1d6a,
+ 0x84b2, 0x1d62,
+ 0x84b3, 0x1d72,
+ 0x84b4, 0x1d82,
+ 0x84b5, 0x1d57,
+ 0x84b6, 0x1d66,
+ 0x84b7, 0x1d5f,
+ 0x84b8, 0x1d6e,
+ 0x84b9, 0x1d76,
+ 0x84ba, 0x1d54,
+ 0x84bb, 0x1d67,
+ 0x84bc, 0x1d5c,
+ 0x84bd, 0x1d6f,
+ 0x84be, 0x1d79,
+ 0x8540, 0x1d83,
+ 0x855e, 0x1f87,
+ 0x857c, 0x205e,
+ 0x8580, 0x2061,
+ 0x8591, 0x1f7d,
+ 0x859f, 0x1d97,
+ 0x85a9, 0x2021,
+ 0x85ab, 0x2067,
+ 0x85b3, 0x1f9c,
+ 0x85bd, 0x206a,
+ 0x85db, 0x1fb0,
+ 0x8640, 0x1db1,
+ 0x8641, 0x1ffa,
+ 0x8642, 0x1db2,
+ 0x8643, 0x1f54,
+ 0x8644, 0x1f56,
+ 0x8645, 0x206f,
+ 0x8646, 0x1db7,
+ 0x8647, 0x1f57,
+ 0x8648, 0x1db3,
+ 0x8649, 0x1f55,
+ 0x864a, 0x1db4,
+ 0x864b, 0x2070,
+ 0x864c, 0x1db5,
+ 0x864e, 0x1f65,
+ 0x864f, 0x1f58,
+ 0x8656, 0x2071,
+ 0x8657, 0x1f64,
+ 0x8658, 0x1f62,
+ 0x865a, 0x1f5f,
+ 0x865d, 0x2072,
+ 0x869b, 0x1dba,
+ 0x869e, 0x2073,
+ 0x869f, 0x1f52,
+ 0x86a0, 0x1f50,
+ 0x86a2, 0x1f53,
+ 0x86a3, 0x2013,
+ 0x86a4, 0x2015,
+ 0x86a5, 0x2014,
+ 0x86a6, 0x2016,
+ 0x86b3, 0x1f7a,
+ 0x86b4, 0x1f78,
+ 0x86b5, 0x2074,
+ 0x86c7, 0x201b,
+ 0x86cb, 0x2075,
+ 0x86cf, 0x1f4e,
+ 0x86d0, 0x1f4d,
+ 0x86d1, 0x1f4c,
+ 0x86d2, 0x1f4b,
+ 0x86d3, 0x200e,
+ 0x8740, 0x2005,
+ 0x8747, 0x1fd6,
+ 0x8748, 0x200c,
+ 0x8749, 0x1fd1,
+ 0x874a, 0x1fca,
+ 0x874b, 0x1dc4,
+ 0x874c, 0x1fd7,
+ 0x874d, 0x1dc2,
+ 0x874e, 0x1fd2,
+ 0x874f, 0x1fcd,
+ 0x8750, 0x1dc3,
+ 0x8751, 0x1fd5,
+ 0x8752, 0x1fd3,
+ 0x8753, 0x1fcf,
+ 0x8754, 0x1fd4,
+ 0x8755, 0x1fd0,
+ 0x8756, 0x1fcb,
+ 0x8758, 0x1fce,
+ 0x8791, 0x207d,
+ 0x8793, 0x1dbd,
+ 0x8798, 0x1fda,
+ 0x8799, 0x1fe5,
+ 0x879a, 0x207f,
+ 0x879b, 0x1fde,
+ 0x879c, 0x1fff,
+ 0x879d, 0x2080,
+ 0x879e, 0x201f,
+ 0x879f, 0x1da1,
+ 0x87a0, 0x1f66,
+ 0x87a1, 0x1da4,
+ 0x87a2, 0x1da2,
+ 0x87a3, 0x1f67,
+ 0x87a4, 0x1ff7,
+ 0x87a5, 0x2087,
+ 0x87a7, 0x1f6a,
+ 0x87a8, 0x1da8,
+ 0x87a9, 0x1f68,
+ 0x87ab, 0x1da6,
+ 0x87ac, 0x1da9,
+ 0x87ad, 0x1daf,
+ 0x87ae, 0x1f6e,
+ 0x87af, 0x1f6c,
+ 0x87b0, 0x1dab,
+ 0x87b1, 0x1f6d,
+ 0x87b2, 0x1f6b,
+ 0x87b3, 0x1dac,
+ 0x87b4, 0x1f6f,
+ 0x87b5, 0x1dae,
+ 0x87bd, 0x1f70,
+ 0x87be, 0x1f73,
+ 0x87c0, 0x1f71,
+ 0x87e5, 0x1dc5,
+ 0x87e8, 0x2083,
+ 0x87fa, 0x1f76,
+ 0x87fb, 0x2081,
+ 0x8840, 0x1dc8,
+ 0x8841, 0x1dcd,
+ 0x8854, 0x1db8,
+ 0x8868, 0x1f16,
+ 0x886a, 0x2079,
+ 0x889f, 0x0465,
+ 0x8940, 0x04c3,
+ 0x8980, 0x0502,
+ 0x8a40, 0x057f,
+ 0x8a80, 0x05be,
+ 0x8b40, 0x063b,
+ 0x8b80, 0x067a,
+ 0x8c40, 0x06f7,
+ 0x8c80, 0x0736,
+ 0x8d40, 0x07b3,
+ 0x8d80, 0x07f2,
+ 0x8e40, 0x086f,
+ 0x8e80, 0x08ae,
+ 0x8f40, 0x092b,
+ 0x8f80, 0x096a,
+ 0x9040, 0x09e7,
+ 0x9080, 0x0a26,
+ 0x9140, 0x0aa3,
+ 0x9180, 0x0ae2,
+ 0x9240, 0x0b5f,
+ 0x9280, 0x0b9e,
+ 0x9340, 0x0c1b,
+ 0x9380, 0x0c5a,
+ 0x9440, 0x0cd7,
+ 0x9480, 0x0d16,
+ 0x9540, 0x0d93,
+ 0x9580, 0x0dd2,
+ 0x9640, 0x0e4f,
+ 0x9680, 0x0e8e,
+ 0x9740, 0x0f0b,
+ 0x9780, 0x0f4a,
+ 0x9840, 0x0fc7,
+ 0x989f, 0x0ffa,
+ 0x9940, 0x1058,
+ 0x9980, 0x1097,
+ 0x9a40, 0x1114,
+ 0x9a80, 0x1153,
+ 0x9b40, 0x11d0,
+ 0x9b80, 0x120f,
+ 0x9c40, 0x128c,
+ 0x9c80, 0x12cb,
+ 0x9d40, 0x1348,
+ 0x9d80, 0x1387,
+ 0x9e40, 0x1404,
+ 0x9e80, 0x1443,
+ 0x9f40, 0x14c0,
+ 0x9f80, 0x14ff,
+ 0xe040, 0x157c,
+ 0xe080, 0x15bb,
+ 0xe140, 0x1638,
+ 0xe180, 0x1677,
+ 0xe240, 0x16f4,
+ 0xe280, 0x1733,
+ 0xe340, 0x17b0,
+ 0xe380, 0x17ef,
+ 0xe440, 0x186c,
+ 0xe480, 0x18ab,
+ 0xe540, 0x1928,
+ 0xe580, 0x1967,
+ 0xe640, 0x19e4,
+ 0xe680, 0x1a23,
+ 0xe740, 0x1aa0,
+ 0xe780, 0x1adf,
+ 0xe840, 0x1b5c,
+ 0xe880, 0x1b9b,
+ 0xe940, 0x1c18,
+ 0xe980, 0x1c57,
+ 0xea40, 0x1cd4,
+ 0xea80, 0x1d13,
+ 0xeaa3, 0x205c,
+ 0xeb41, 0x1ecf,
+ 0xeb50, 0x1ed1,
+ 0xeb5b, 0x1ed3,
+ 0xeb60, 0x1ed6,
+ 0xeb69, 0x1edb,
+ 0xeb81, 0x1eed,
+ 0xec9f, 0x1eee,
+ 0xeca1, 0x1eef,
+ 0xeca3, 0x1ef0,
+ 0xeca5, 0x1ef1,
+ 0xeca7, 0x1ef2,
+ 0xecc1, 0x1ef3,
+ 0xece1, 0x1ef4,
+ 0xece3, 0x1ef5,
+ 0xece5, 0x1ef6,
+ 0xecec, 0x1ef7,
+ 0xed40, 0x1ef8,
+ 0xed42, 0x1ef9,
+ 0xed44, 0x1efa,
+ 0xed46, 0x1efb,
+ 0xed48, 0x1efc,
+ 0xed62, 0x1efd,
+ 0xed83, 0x1efe,
+ 0xed85, 0x1eff,
+ 0xed87, 0x1f00,
+ 0xed8e, 0x1f01,
+ 0xed95, 0x1f02,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 japan1290pvRKSJHEnc16 = {
+ 0,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
+ 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010,
+ 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018,
+ 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020,
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028,
+ 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030,
+ 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038,
+ 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040,
+ 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048,
+ 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050,
+ 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
+ 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0000,
+ 0x0061, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0146, 0x0147, 0x0148, 0x0149, 0x014a, 0x014b, 0x014c, 0x014d,
+ 0x014e, 0x014f, 0x0150, 0x0151, 0x0152, 0x0153, 0x0154, 0x0155,
+ 0x0156, 0x0157, 0x0158, 0x0159, 0x015a, 0x015b, 0x015c, 0x015d,
+ 0x015e, 0x015f, 0x0160, 0x0161, 0x0162, 0x0163, 0x0164, 0x0165,
+ 0x0166, 0x0167, 0x0168, 0x0169, 0x016a, 0x016b, 0x016c, 0x016d,
+ 0x016e, 0x016f, 0x0170, 0x0171, 0x0172, 0x0173, 0x0174, 0x0175,
+ 0x0176, 0x0177, 0x0178, 0x0179, 0x017a, 0x017b, 0x017c, 0x017d,
+ 0x017e, 0x017f, 0x0180, 0x0181, 0x0182, 0x0183, 0x0184, 0x0185,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0098, 0x00e4, 0x007c },
+ japan1290pvRKSJHMap2, 259
+};
+
+static Gushort japan1290pvRKSJVMap2[620] = {
+ 0x0000, 0x0000,
+ 0x8140, 0x0279,
+ 0x8180, 0x02b8,
+ 0x81b8, 0x02e5,
+ 0x81c8, 0x02ed,
+ 0x81da, 0x02f4,
+ 0x81f0, 0x0303,
+ 0x81fc, 0x030b,
+ 0x824f, 0x030c,
+ 0x8260, 0x0316,
+ 0x8281, 0x0330,
+ 0x829f, 0x034a,
+ 0x8340, 0x039d,
+ 0x8380, 0x03dc,
+ 0x839f, 0x03f3,
+ 0x83bf, 0x040b,
+ 0x8440, 0x0423,
+ 0x8470, 0x0444,
+ 0x8480, 0x0453,
+ 0x849f, 0x1d37,
+ 0x84a0, 0x1d39,
+ 0x84a1, 0x1d43,
+ 0x84a2, 0x1d47,
+ 0x84a3, 0x1d4f,
+ 0x84a4, 0x1d4b,
+ 0x84a5, 0x1d53,
+ 0x84a6, 0x1d63,
+ 0x84a7, 0x1d5b,
+ 0x84a8, 0x1d6b,
+ 0x84a9, 0x1d73,
+ 0x84aa, 0x1d38,
+ 0x84ab, 0x1d3a,
+ 0x84ac, 0x1d46,
+ 0x84ad, 0x1d4a,
+ 0x84ae, 0x1d52,
+ 0x84af, 0x1d4e,
+ 0x84b0, 0x1d5a,
+ 0x84b1, 0x1d6a,
+ 0x84b2, 0x1d62,
+ 0x84b3, 0x1d72,
+ 0x84b4, 0x1d82,
+ 0x84b5, 0x1d57,
+ 0x84b6, 0x1d66,
+ 0x84b7, 0x1d5f,
+ 0x84b8, 0x1d6e,
+ 0x84b9, 0x1d76,
+ 0x84ba, 0x1d54,
+ 0x84bb, 0x1d67,
+ 0x84bc, 0x1d5c,
+ 0x84bd, 0x1d6f,
+ 0x84be, 0x1d79,
+ 0x8540, 0x1d83,
+ 0x855e, 0x1f87,
+ 0x857c, 0x205e,
+ 0x8580, 0x2061,
+ 0x8591, 0x1f7d,
+ 0x859f, 0x1d97,
+ 0x85a9, 0x2021,
+ 0x85ab, 0x2067,
+ 0x85b3, 0x1f9c,
+ 0x85bd, 0x206a,
+ 0x85db, 0x1fb0,
+ 0x8640, 0x1db1,
+ 0x8641, 0x1ffa,
+ 0x8642, 0x1db2,
+ 0x8643, 0x1f54,
+ 0x8644, 0x1f56,
+ 0x8645, 0x206f,
+ 0x8646, 0x1db7,
+ 0x8647, 0x1f57,
+ 0x8648, 0x1db3,
+ 0x8649, 0x1f55,
+ 0x864a, 0x1db4,
+ 0x864b, 0x2070,
+ 0x864c, 0x1db5,
+ 0x864e, 0x1f65,
+ 0x864f, 0x1f58,
+ 0x8656, 0x2071,
+ 0x8657, 0x1f64,
+ 0x8658, 0x1f62,
+ 0x865a, 0x1f5f,
+ 0x865d, 0x2072,
+ 0x869b, 0x1dba,
+ 0x869e, 0x2073,
+ 0x869f, 0x1f52,
+ 0x86a0, 0x1f50,
+ 0x86a2, 0x1f53,
+ 0x86a3, 0x2013,
+ 0x86a4, 0x2015,
+ 0x86a5, 0x2014,
+ 0x86a6, 0x2016,
+ 0x86b3, 0x1f7a,
+ 0x86b4, 0x1f78,
+ 0x86b5, 0x2074,
+ 0x86c7, 0x201b,
+ 0x86cb, 0x2075,
+ 0x86cf, 0x1f4e,
+ 0x86d0, 0x1f4d,
+ 0x86d1, 0x1f4c,
+ 0x86d2, 0x1f4b,
+ 0x86d3, 0x200e,
+ 0x8740, 0x2005,
+ 0x8747, 0x1fd6,
+ 0x8748, 0x200c,
+ 0x8749, 0x1fd1,
+ 0x874a, 0x1fca,
+ 0x874b, 0x1dc4,
+ 0x874c, 0x1fd7,
+ 0x874d, 0x1dc2,
+ 0x874e, 0x1fd2,
+ 0x874f, 0x1fcd,
+ 0x8750, 0x1dc3,
+ 0x8751, 0x1fd5,
+ 0x8752, 0x1fd3,
+ 0x8753, 0x1fcf,
+ 0x8754, 0x1fd4,
+ 0x8755, 0x1fd0,
+ 0x8756, 0x1fcb,
+ 0x8758, 0x1fce,
+ 0x8791, 0x207d,
+ 0x8793, 0x1dbd,
+ 0x8798, 0x1fda,
+ 0x8799, 0x1fe5,
+ 0x879a, 0x207f,
+ 0x879b, 0x1fde,
+ 0x879c, 0x1fff,
+ 0x879d, 0x2080,
+ 0x879e, 0x201f,
+ 0x879f, 0x1da1,
+ 0x87a0, 0x1f66,
+ 0x87a1, 0x1da4,
+ 0x87a2, 0x1da2,
+ 0x87a3, 0x1f67,
+ 0x87a4, 0x1ff7,
+ 0x87a5, 0x2087,
+ 0x87a7, 0x1f6a,
+ 0x87a8, 0x1da8,
+ 0x87a9, 0x1f68,
+ 0x87ab, 0x1da6,
+ 0x87ac, 0x1da9,
+ 0x87ad, 0x1daf,
+ 0x87ae, 0x1f6e,
+ 0x87af, 0x1f6c,
+ 0x87b0, 0x1dab,
+ 0x87b1, 0x1f6d,
+ 0x87b2, 0x1f6b,
+ 0x87b3, 0x1dac,
+ 0x87b4, 0x1f6f,
+ 0x87b5, 0x1dae,
+ 0x87bd, 0x1f70,
+ 0x87be, 0x1f73,
+ 0x87c0, 0x1f71,
+ 0x87e5, 0x1dc5,
+ 0x87e8, 0x2083,
+ 0x87fa, 0x1f76,
+ 0x87fb, 0x2081,
+ 0x8840, 0x1dc8,
+ 0x8841, 0x1dcd,
+ 0x8854, 0x1db8,
+ 0x8868, 0x1f16,
+ 0x886a, 0x2079,
+ 0x889f, 0x0465,
+ 0x8940, 0x04c3,
+ 0x8980, 0x0502,
+ 0x8a40, 0x057f,
+ 0x8a80, 0x05be,
+ 0x8b40, 0x063b,
+ 0x8b80, 0x067a,
+ 0x8c40, 0x06f7,
+ 0x8c80, 0x0736,
+ 0x8d40, 0x07b3,
+ 0x8d80, 0x07f2,
+ 0x8e40, 0x086f,
+ 0x8e80, 0x08ae,
+ 0x8f40, 0x092b,
+ 0x8f80, 0x096a,
+ 0x9040, 0x09e7,
+ 0x9080, 0x0a26,
+ 0x9140, 0x0aa3,
+ 0x9180, 0x0ae2,
+ 0x9240, 0x0b5f,
+ 0x9280, 0x0b9e,
+ 0x9340, 0x0c1b,
+ 0x9380, 0x0c5a,
+ 0x9440, 0x0cd7,
+ 0x9480, 0x0d16,
+ 0x9540, 0x0d93,
+ 0x9580, 0x0dd2,
+ 0x9640, 0x0e4f,
+ 0x9680, 0x0e8e,
+ 0x9740, 0x0f0b,
+ 0x9780, 0x0f4a,
+ 0x9840, 0x0fc7,
+ 0x989f, 0x0ffa,
+ 0x9940, 0x1058,
+ 0x9980, 0x1097,
+ 0x9a40, 0x1114,
+ 0x9a80, 0x1153,
+ 0x9b40, 0x11d0,
+ 0x9b80, 0x120f,
+ 0x9c40, 0x128c,
+ 0x9c80, 0x12cb,
+ 0x9d40, 0x1348,
+ 0x9d80, 0x1387,
+ 0x9e40, 0x1404,
+ 0x9e80, 0x1443,
+ 0x9f40, 0x14c0,
+ 0x9f80, 0x14ff,
+ 0xe040, 0x157c,
+ 0xe080, 0x15bb,
+ 0xe140, 0x1638,
+ 0xe180, 0x1677,
+ 0xe240, 0x16f4,
+ 0xe280, 0x1733,
+ 0xe340, 0x17b0,
+ 0xe380, 0x17ef,
+ 0xe440, 0x186c,
+ 0xe480, 0x18ab,
+ 0xe540, 0x1928,
+ 0xe580, 0x1967,
+ 0xe640, 0x19e4,
+ 0xe680, 0x1a23,
+ 0xe740, 0x1aa0,
+ 0xe780, 0x1adf,
+ 0xe840, 0x1b5c,
+ 0xe880, 0x1b9b,
+ 0xe940, 0x1c18,
+ 0xe980, 0x1c57,
+ 0xea40, 0x1cd4,
+ 0xea80, 0x1d13,
+ 0xeaa3, 0x205c,
+ 0xeb41, 0x1ecf,
+ 0xeb50, 0x1ed1,
+ 0xeb5b, 0x1ed3,
+ 0xeb60, 0x1ed6,
+ 0xeb69, 0x1edb,
+ 0xeb81, 0x1eed,
+ 0xec9f, 0x1eee,
+ 0xeca1, 0x1eef,
+ 0xeca3, 0x1ef0,
+ 0xeca5, 0x1ef1,
+ 0xeca7, 0x1ef2,
+ 0xecc1, 0x1ef3,
+ 0xece1, 0x1ef4,
+ 0xece3, 0x1ef5,
+ 0xece5, 0x1ef6,
+ 0xecec, 0x1ef7,
+ 0xed40, 0x1ef8,
+ 0xed42, 0x1ef9,
+ 0xed44, 0x1efa,
+ 0xed46, 0x1efb,
+ 0xed48, 0x1efc,
+ 0xed62, 0x1efd,
+ 0xed83, 0x1efe,
+ 0xed85, 0x1eff,
+ 0xed87, 0x1f00,
+ 0xed8e, 0x1f01,
+ 0xed95, 0x1f02,
+ 0x8141, 0x1ecf,
+ 0x8150, 0x1ed1,
+ 0x815b, 0x1ed3,
+ 0x8160, 0x1ed6,
+ 0x8169, 0x1edb,
+ 0x8181, 0x1eed,
+ 0x829f, 0x1eee,
+ 0x82a1, 0x1eef,
+ 0x82a3, 0x1ef0,
+ 0x82a5, 0x1ef1,
+ 0x82a7, 0x1ef2,
+ 0x82c1, 0x1ef3,
+ 0x82e1, 0x1ef4,
+ 0x82e3, 0x1ef5,
+ 0x82e5, 0x1ef6,
+ 0x82ec, 0x1ef7,
+ 0x8340, 0x1ef8,
+ 0x8342, 0x1ef9,
+ 0x8344, 0x1efa,
+ 0x8346, 0x1efb,
+ 0x8348, 0x1efc,
+ 0x8362, 0x1efd,
+ 0x8383, 0x1efe,
+ 0x8385, 0x1eff,
+ 0x8387, 0x1f00,
+ 0x838e, 0x1f01,
+ 0x8395, 0x1f02,
+ 0x879f, 0x1f04,
+ 0x87a0, 0x2089,
+ 0x87a1, 0x1f07,
+ 0x87a2, 0x1f05,
+ 0x87a3, 0x208a,
+ 0x87a4, 0x208d,
+ 0x87a6, 0x2091,
+ 0x87a8, 0x1f0b,
+ 0x87a9, 0x2093,
+ 0x87ab, 0x1f09,
+ 0x87ac, 0x1f0c,
+ 0x87ad, 0x1f12,
+ 0x87ae, 0x2097,
+ 0x87b0, 0x1f0e,
+ 0x87b1, 0x209b,
+ 0x87b3, 0x1f0f,
+ 0x87b4, 0x209d,
+ 0x87b5, 0x1f11,
+ 0x87bd, 0x209e,
+ 0x87be, 0x20a1,
+ 0x87bf, 0x20a4,
+ 0x87c0, 0x20a6,
+ 0x87c1, 0x20a5,
+ 0x87fa, 0x2084,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 japan1290pvRKSJVEnc16 = {
+ 1,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
+ 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010,
+ 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018,
+ 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020,
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028,
+ 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030,
+ 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038,
+ 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040,
+ 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048,
+ 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050,
+ 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
+ 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0000,
+ 0x0061, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0146, 0x0147, 0x0148, 0x0149, 0x014a, 0x014b, 0x014c, 0x014d,
+ 0x014e, 0x014f, 0x0150, 0x0151, 0x0152, 0x0153, 0x0154, 0x0155,
+ 0x0156, 0x0157, 0x0158, 0x0159, 0x015a, 0x015b, 0x015c, 0x015d,
+ 0x015e, 0x015f, 0x0160, 0x0161, 0x0162, 0x0163, 0x0164, 0x0165,
+ 0x0166, 0x0167, 0x0168, 0x0169, 0x016a, 0x016b, 0x016c, 0x016d,
+ 0x016e, 0x016f, 0x0170, 0x0171, 0x0172, 0x0173, 0x0174, 0x0175,
+ 0x0176, 0x0177, 0x0178, 0x0179, 0x017a, 0x017b, 0x017c, 0x017d,
+ 0x017e, 0x017f, 0x0180, 0x0181, 0x0182, 0x0183, 0x0184, 0x0185,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0098, 0x00e4, 0x007c },
+ japan1290pvRKSJVMap2, 310
+};
+
+static Gushort japan12AddHMap2[1266] = {
+ 0x0000, 0x0000,
+ 0x2121, 0x0279,
+ 0x2221, 0x02d7,
+ 0x223a, 0x02e5,
+ 0x224a, 0x02ed,
+ 0x225c, 0x02f4,
+ 0x2272, 0x0303,
+ 0x227e, 0x030b,
+ 0x2330, 0x030c,
+ 0x2341, 0x0316,
+ 0x2361, 0x0330,
+ 0x2421, 0x034a,
+ 0x2474, 0x1f16,
+ 0x2521, 0x039d,
+ 0x2621, 0x03f3,
+ 0x2641, 0x040b,
+ 0x2721, 0x0423,
+ 0x2751, 0x0444,
+ 0x2821, 0x1d37,
+ 0x2822, 0x1d39,
+ 0x2823, 0x1d43,
+ 0x2824, 0x1d47,
+ 0x2825, 0x1d4f,
+ 0x2826, 0x1d4b,
+ 0x2827, 0x1d53,
+ 0x2828, 0x1d63,
+ 0x2829, 0x1d5b,
+ 0x282a, 0x1d6b,
+ 0x282b, 0x1d73,
+ 0x282c, 0x1d38,
+ 0x282d, 0x1d3a,
+ 0x282e, 0x1d46,
+ 0x282f, 0x1d4a,
+ 0x2830, 0x1d52,
+ 0x2831, 0x1d4e,
+ 0x2832, 0x1d5a,
+ 0x2833, 0x1d6a,
+ 0x2834, 0x1d62,
+ 0x2835, 0x1d72,
+ 0x2836, 0x1d82,
+ 0x2837, 0x1d57,
+ 0x2838, 0x1d66,
+ 0x2839, 0x1d5f,
+ 0x283a, 0x1d6e,
+ 0x283b, 0x1d76,
+ 0x283c, 0x1d54,
+ 0x283d, 0x1d67,
+ 0x283e, 0x1d5c,
+ 0x283f, 0x1d6f,
+ 0x2840, 0x1d79,
+ 0x3021, 0x0465,
+ 0x3022, 0x1dd1,
+ 0x3023, 0x0467,
+ 0x3032, 0x1f19,
+ 0x3033, 0x0477,
+ 0x303b, 0x1dd2,
+ 0x303c, 0x0480,
+ 0x306e, 0x1dd3,
+ 0x306f, 0x04b3,
+ 0x3071, 0x1f1a,
+ 0x3072, 0x04b6,
+ 0x3073, 0x1dd4,
+ 0x3074, 0x04b8,
+ 0x307c, 0x1dd5,
+ 0x307d, 0x04c1,
+ 0x3121, 0x04c3,
+ 0x312a, 0x1dd6,
+ 0x312b, 0x04cd,
+ 0x3133, 0x1f1b,
+ 0x3134, 0x04d6,
+ 0x3135, 0x1dd7,
+ 0x3136, 0x04d8,
+ 0x3139, 0x1f1c,
+ 0x313a, 0x04dc,
+ 0x313d, 0x1dda,
+ 0x313e, 0x04e0,
+ 0x3142, 0x1ddb,
+ 0x3143, 0x04e5,
+ 0x316b, 0x1ddc,
+ 0x316c, 0x050e,
+ 0x3221, 0x0521,
+ 0x3228, 0x1ddd,
+ 0x3229, 0x0529,
+ 0x322a, 0x1dde,
+ 0x322b, 0x052b,
+ 0x3260, 0x1ddf,
+ 0x3261, 0x0561,
+ 0x3267, 0x1f1d,
+ 0x3268, 0x0568,
+ 0x327a, 0x1de0,
+ 0x327b, 0x057b,
+ 0x3321, 0x057f,
+ 0x3322, 0x1de2,
+ 0x3323, 0x0581,
+ 0x336b, 0x1de4,
+ 0x336c, 0x05ca,
+ 0x3373, 0x1de5,
+ 0x3374, 0x05d2,
+ 0x337a, 0x1de6,
+ 0x337b, 0x05d9,
+ 0x3421, 0x05dd,
+ 0x3442, 0x1de7,
+ 0x3443, 0x05ff,
+ 0x344d, 0x1de8,
+ 0x344e, 0x060a,
+ 0x3465, 0x1de9,
+ 0x3466, 0x0622,
+ 0x3521, 0x063b,
+ 0x352b, 0x1dea,
+ 0x352c, 0x0646,
+ 0x3540, 0x1deb,
+ 0x3541, 0x065b,
+ 0x3562, 0x1f1e,
+ 0x3563, 0x067d,
+ 0x3568, 0x1f1f,
+ 0x3569, 0x0683,
+ 0x3621, 0x0699,
+ 0x3622, 0x1dec,
+ 0x3623, 0x069b,
+ 0x362a, 0x1ded,
+ 0x362b, 0x06a3,
+ 0x3642, 0x1f20,
+ 0x3643, 0x06bb,
+ 0x364f, 0x1dee,
+ 0x3650, 0x06c8,
+ 0x366d, 0x1def,
+ 0x366e, 0x06e6,
+ 0x3674, 0x1df0,
+ 0x3675, 0x06ed,
+ 0x367b, 0x1df1,
+ 0x367c, 0x06f4,
+ 0x367d, 0x1df2,
+ 0x367e, 0x06f6,
+ 0x3721, 0x06f7,
+ 0x3737, 0x1df4,
+ 0x3738, 0x070e,
+ 0x3752, 0x1df7,
+ 0x3753, 0x0729,
+ 0x3771, 0x1dfa,
+ 0x3772, 0x0748,
+ 0x377d, 0x1f21,
+ 0x377e, 0x1dfc,
+ 0x3821, 0x0755,
+ 0x3834, 0x1dfd,
+ 0x3835, 0x0769,
+ 0x3841, 0x1dfe,
+ 0x3842, 0x0776,
+ 0x3921, 0x07b3,
+ 0x392b, 0x1dff,
+ 0x392c, 0x07be,
+ 0x396d, 0x1e02,
+ 0x396e, 0x0800,
+ 0x3974, 0x1e03,
+ 0x3975, 0x0807,
+ 0x3979, 0x1e04,
+ 0x397a, 0x080c,
+ 0x3a21, 0x0811,
+ 0x3a53, 0x1e05,
+ 0x3a54, 0x0844,
+ 0x3a67, 0x1e06,
+ 0x3a68, 0x0858,
+ 0x3a74, 0x1e07,
+ 0x3a75, 0x0865,
+ 0x3b21, 0x086f,
+ 0x3b27, 0x1e08,
+ 0x3b28, 0x0876,
+ 0x3b2a, 0x1e09,
+ 0x3b2b, 0x0879,
+ 0x3b2c, 0x1e0a,
+ 0x3b2d, 0x087b,
+ 0x3b39, 0x1e0b,
+ 0x3b3a, 0x0888,
+ 0x3b41, 0x1f22,
+ 0x3b42, 0x0890,
+ 0x3c21, 0x08cd,
+ 0x3c48, 0x1e0d,
+ 0x3c49, 0x08f5,
+ 0x3c5d, 0x1e0f,
+ 0x3c5f, 0x090b,
+ 0x3d21, 0x092b,
+ 0x3d2b, 0x1e11,
+ 0x3d2c, 0x0936,
+ 0x3d36, 0x1e12,
+ 0x3d37, 0x0941,
+ 0x3d6c, 0x1e13,
+ 0x3d6d, 0x0977,
+ 0x3d72, 0x1e15,
+ 0x3d74, 0x097e,
+ 0x3e21, 0x0989,
+ 0x3e25, 0x1e17,
+ 0x3e26, 0x098e,
+ 0x3e33, 0x1e18,
+ 0x3e34, 0x099c,
+ 0x3e55, 0x1e1a,
+ 0x3e56, 0x09be,
+ 0x3e5f, 0x1e1b,
+ 0x3e60, 0x09c8,
+ 0x3e64, 0x1e1c,
+ 0x3e65, 0x09cd,
+ 0x3f21, 0x09e7,
+ 0x3f2a, 0x1e1d,
+ 0x3f2b, 0x09f1,
+ 0x3f59, 0x1f23,
+ 0x3f5a, 0x0a20,
+ 0x3f60, 0x1e1f,
+ 0x3f61, 0x0a27,
+ 0x4021, 0x0a45,
+ 0x4022, 0x1e21,
+ 0x4023, 0x0a47,
+ 0x4066, 0x1e23,
+ 0x4067, 0x0a8b,
+ 0x4071, 0x1e24,
+ 0x4072, 0x0a96,
+ 0x4079, 0x1e26,
+ 0x407a, 0x1f24,
+ 0x407b, 0x0a9f,
+ 0x407c, 0x1f25,
+ 0x407e, 0x0aa2,
+ 0x4121, 0x0aa3,
+ 0x4127, 0x1e28,
+ 0x4128, 0x0aaa,
+ 0x4139, 0x1e29,
+ 0x413a, 0x0abc,
+ 0x414c, 0x1e2a,
+ 0x414d, 0x0acf,
+ 0x414f, 0x1e2b,
+ 0x4150, 0x0ad2,
+ 0x415f, 0x1e2c,
+ 0x4160, 0x0ae2,
+ 0x4169, 0x1e2d,
+ 0x416a, 0x0aec,
+ 0x4221, 0x0b01,
+ 0x4237, 0x1f27,
+ 0x4238, 0x0b18,
+ 0x423d, 0x1e2e,
+ 0x423e, 0x0b1e,
+ 0x424d, 0x1e2f,
+ 0x424e, 0x0b2e,
+ 0x425c, 0x1e30,
+ 0x425d, 0x0b3d,
+ 0x4263, 0x1e31,
+ 0x4264, 0x0b44,
+ 0x426f, 0x1e32,
+ 0x4270, 0x0b50,
+ 0x427d, 0x1e35,
+ 0x427e, 0x0b5e,
+ 0x4321, 0x0b5f,
+ 0x4327, 0x1e36,
+ 0x4328, 0x0b66,
+ 0x4329, 0x1e37,
+ 0x432a, 0x0b68,
+ 0x432d, 0x1e39,
+ 0x432f, 0x0b6d,
+ 0x433d, 0x1e3b,
+ 0x433e, 0x0b7c,
+ 0x4370, 0x1e3c,
+ 0x4371, 0x0baf,
+ 0x4375, 0x1e3d,
+ 0x4376, 0x0bb4,
+ 0x437c, 0x1e3e,
+ 0x437d, 0x0bbb,
+ 0x4421, 0x0bbd,
+ 0x443d, 0x1e3f,
+ 0x443e, 0x0bda,
+ 0x4448, 0x1e40,
+ 0x4449, 0x0be5,
+ 0x444a, 0x1e41,
+ 0x444b, 0x0be7,
+ 0x444f, 0x1e43,
+ 0x4450, 0x0bec,
+ 0x4521, 0x0c1b,
+ 0x4522, 0x1e44,
+ 0x4523, 0x0c1d,
+ 0x4527, 0x1e45,
+ 0x4528, 0x0c22,
+ 0x452e, 0x1e46,
+ 0x452f, 0x0c29,
+ 0x4536, 0x1e47,
+ 0x4537, 0x0c31,
+ 0x453f, 0x1e48,
+ 0x4540, 0x0c3a,
+ 0x4548, 0x1e49,
+ 0x4549, 0x0c43,
+ 0x454b, 0x1e4a,
+ 0x454c, 0x0c46,
+ 0x4551, 0x1f28,
+ 0x4552, 0x1e4c,
+ 0x4553, 0x0c4d,
+ 0x4564, 0x1e4d,
+ 0x4565, 0x0c5f,
+ 0x4578, 0x1e4e,
+ 0x4579, 0x0c73,
+ 0x4621, 0x0c79,
+ 0x4642, 0x1e50,
+ 0x4643, 0x0c9b,
+ 0x4654, 0x1e51,
+ 0x4655, 0x0cad,
+ 0x465b, 0x1e53,
+ 0x465c, 0x0cb4,
+ 0x4666, 0x1e56,
+ 0x4668, 0x0cc0,
+ 0x466a, 0x1e58,
+ 0x466b, 0x0cc3,
+ 0x4676, 0x1ec0,
+ 0x4677, 0x0ccf,
+ 0x4721, 0x0cd7,
+ 0x4729, 0x1e59,
+ 0x472a, 0x1f29,
+ 0x472b, 0x0ce1,
+ 0x4739, 0x1e5a,
+ 0x473a, 0x0cf0,
+ 0x4757, 0x1e5b,
+ 0x4758, 0x0d0e,
+ 0x4767, 0x1e5c,
+ 0x4768, 0x0d1e,
+ 0x4769, 0x1e5d,
+ 0x476a, 0x0d20,
+ 0x476d, 0x1e5e,
+ 0x476e, 0x0d24,
+ 0x4821, 0x0d35,
+ 0x4824, 0x1e5f,
+ 0x4825, 0x0d39,
+ 0x482e, 0x1e60,
+ 0x482f, 0x0d43,
+ 0x4830, 0x1e61,
+ 0x4831, 0x0d45,
+ 0x4840, 0x1f2a,
+ 0x4841, 0x0d55,
+ 0x4854, 0x1e62,
+ 0x4855, 0x0d69,
+ 0x4875, 0x1e64,
+ 0x4876, 0x0d8a,
+ 0x4921, 0x0d93,
+ 0x4922, 0x1e65,
+ 0x4924, 0x0d96,
+ 0x492f, 0x1e67,
+ 0x4930, 0x0da2,
+ 0x4932, 0x1e68,
+ 0x4933, 0x0da5,
+ 0x4935, 0x1e69,
+ 0x4936, 0x0da8,
+ 0x4940, 0x1e6a,
+ 0x4941, 0x0db3,
+ 0x494e, 0x1e6b,
+ 0x494f, 0x0dc1,
+ 0x4a21, 0x0df1,
+ 0x4a43, 0x1e6d,
+ 0x4a44, 0x0e14,
+ 0x4a4d, 0x1e6e,
+ 0x4a4e, 0x0e1e,
+ 0x4a53, 0x1f2b,
+ 0x4a54, 0x0e24,
+ 0x4a5a, 0x1e6f,
+ 0x4a5b, 0x0e2b,
+ 0x4a79, 0x1e70,
+ 0x4a7a, 0x0e4a,
+ 0x4b21, 0x0e4f,
+ 0x4b29, 0x1e72,
+ 0x4b2a, 0x0e58,
+ 0x4b4b, 0x1e73,
+ 0x4b4c, 0x0e7a,
+ 0x4b70, 0x1e74,
+ 0x4b71, 0x0e9f,
+ 0x4b78, 0x1f2c,
+ 0x4b79, 0x0ea7,
+ 0x4c21, 0x0ead,
+ 0x4c4d, 0x1e75,
+ 0x4c4e, 0x0eda,
+ 0x4c59, 0x1e76,
+ 0x4c5a, 0x0ee6,
+ 0x4c5f, 0x1e77,
+ 0x4c60, 0x0eec,
+ 0x4c62, 0x1e78,
+ 0x4c63, 0x0eef,
+ 0x4c7a, 0x1e79,
+ 0x4c7b, 0x0f07,
+ 0x4c7c, 0x1e7a,
+ 0x4c7d, 0x0f09,
+ 0x4d21, 0x0f0b,
+ 0x4d32, 0x1e7c,
+ 0x4d33, 0x0f1d,
+ 0x4d50, 0x1e7d,
+ 0x4d51, 0x0f3b,
+ 0x4d54, 0x1e7e,
+ 0x4d55, 0x0f3f,
+ 0x4d69, 0x1e7f,
+ 0x4d6a, 0x0f54,
+ 0x4e21, 0x0f69,
+ 0x4e7a, 0x1e81,
+ 0x4e7c, 0x1f2d,
+ 0x4e7d, 0x0fc5,
+ 0x4f21, 0x1e83,
+ 0x4f22, 0x0fc8,
+ 0x4f31, 0x1e84,
+ 0x4f32, 0x0fd8,
+ 0x4f39, 0x1e85,
+ 0x4f3a, 0x0fe0,
+ 0x5021, 0x0ffa,
+ 0x5121, 0x1058,
+ 0x5122, 0x1f2e,
+ 0x5123, 0x105a,
+ 0x513d, 0x1e86,
+ 0x513e, 0x1075,
+ 0x514d, 0x1e89,
+ 0x514e, 0x1085,
+ 0x5221, 0x10b6,
+ 0x5238, 0x1f2f,
+ 0x5239, 0x10ce,
+ 0x5321, 0x1114,
+ 0x5330, 0x1e8a,
+ 0x5331, 0x1124,
+ 0x533a, 0x1e8b,
+ 0x533b, 0x112e,
+ 0x5348, 0x1f30,
+ 0x5349, 0x113c,
+ 0x535e, 0x1e8d,
+ 0x535f, 0x1152,
+ 0x536b, 0x1e8e,
+ 0x536c, 0x1f31,
+ 0x536d, 0x1160,
+ 0x5421, 0x1172,
+ 0x5444, 0x1e8f,
+ 0x5445, 0x1f32,
+ 0x5446, 0x1197,
+ 0x546c, 0x1f33,
+ 0x546d, 0x11be,
+ 0x5521, 0x11d0,
+ 0x553d, 0x1e90,
+ 0x553e, 0x11ed,
+ 0x5563, 0x1e91,
+ 0x5564, 0x1213,
+ 0x5578, 0x1f34,
+ 0x5579, 0x1228,
+ 0x5621, 0x122e,
+ 0x5622, 0x1e92,
+ 0x5623, 0x1230,
+ 0x567d, 0x1f35,
+ 0x5721, 0x128c,
+ 0x5821, 0x12ea,
+ 0x5824, 0x1e94,
+ 0x5825, 0x12ee,
+ 0x5921, 0x1348,
+ 0x5928, 0x1f37,
+ 0x5929, 0x1350,
+ 0x5960, 0x1e95,
+ 0x5961, 0x1388,
+ 0x596c, 0x1e96,
+ 0x596d, 0x1394,
+ 0x5a21, 0x13a6,
+ 0x5a39, 0x1e97,
+ 0x5a3a, 0x13bf,
+ 0x5a7a, 0x1f38,
+ 0x5a7b, 0x1400,
+ 0x5b21, 0x1404,
+ 0x5b45, 0x1e99,
+ 0x5b46, 0x1429,
+ 0x5b6b, 0x1e9b,
+ 0x5b6c, 0x144f,
+ 0x5c21, 0x1462,
+ 0x5d21, 0x14c0,
+ 0x5d61, 0x1f39,
+ 0x5d62, 0x1501,
+ 0x5e21, 0x151e,
+ 0x5e50, 0x1e9d,
+ 0x5e51, 0x154e,
+ 0x5e56, 0x1f3a,
+ 0x5e57, 0x1554,
+ 0x5e76, 0x1f3b,
+ 0x5e77, 0x1574,
+ 0x5f21, 0x157c,
+ 0x5f73, 0x1e9e,
+ 0x5f74, 0x15cf,
+ 0x6021, 0x15da,
+ 0x6026, 0x1e9f,
+ 0x6027, 0x15e0,
+ 0x605f, 0x1ea0,
+ 0x6060, 0x1619,
+ 0x6121, 0x1638,
+ 0x612b, 0x1ea1,
+ 0x612c, 0x1643,
+ 0x6221, 0x1696,
+ 0x626f, 0x1ea5,
+ 0x6270, 0x16e5,
+ 0x6321, 0x16f4,
+ 0x634a, 0x1ea6,
+ 0x634b, 0x171e,
+ 0x6354, 0x1ea7,
+ 0x6355, 0x1728,
+ 0x6359, 0x1f3c,
+ 0x635a, 0x172d,
+ 0x6421, 0x1752,
+ 0x6439, 0x1ea8,
+ 0x643a, 0x176b,
+ 0x6440, 0x1f3d,
+ 0x6441, 0x1772,
+ 0x6464, 0x1ea9,
+ 0x6465, 0x1796,
+ 0x646e, 0x1eaa,
+ 0x646f, 0x17a0,
+ 0x6521, 0x17b0,
+ 0x6539, 0x1eab,
+ 0x653a, 0x17c9,
+ 0x653b, 0x1eac,
+ 0x653c, 0x17cb,
+ 0x6546, 0x1ead,
+ 0x6547, 0x17d6,
+ 0x6621, 0x180e,
+ 0x6649, 0x1f3e,
+ 0x664a, 0x1837,
+ 0x6721, 0x186c,
+ 0x6764, 0x1eaf,
+ 0x6765, 0x18b0,
+ 0x6769, 0x1eb0,
+ 0x676a, 0x18b5,
+ 0x6772, 0x1eb1,
+ 0x6773, 0x18be,
+ 0x6821, 0x18ca,
+ 0x683b, 0x1eb3,
+ 0x683c, 0x18e5,
+ 0x684d, 0x1f3f,
+ 0x684e, 0x18f7,
+ 0x6921, 0x1928,
+ 0x697e, 0x1f40,
+ 0x6a21, 0x1986,
+ 0x6a3c, 0x1f41,
+ 0x6a3e, 0x19a3,
+ 0x6a6f, 0x1eb8,
+ 0x6a70, 0x19d5,
+ 0x6b21, 0x19e4,
+ 0x6b32, 0x1eb9,
+ 0x6b33, 0x19f6,
+ 0x6b66, 0x1eba,
+ 0x6b67, 0x1a2a,
+ 0x6c21, 0x1a42,
+ 0x6c69, 0x1ebc,
+ 0x6c6a, 0x1a8b,
+ 0x6d21, 0x1aa0,
+ 0x6d4e, 0x1ebe,
+ 0x6d4f, 0x1ace,
+ 0x6e21, 0x1afe,
+ 0x6e29, 0x1ec1,
+ 0x6e2a, 0x1b07,
+ 0x6e3d, 0x1ec2,
+ 0x6e3e, 0x1b1b,
+ 0x6f21, 0x1b5c,
+ 0x7021, 0x1bba,
+ 0x7051, 0x1ec7,
+ 0x7052, 0x1beb,
+ 0x7121, 0x1c18,
+ 0x7159, 0x1f43,
+ 0x715a, 0x1c51,
+ 0x7221, 0x1c76,
+ 0x722d, 0x1eca,
+ 0x722e, 0x1c83,
+ 0x723c, 0x1ecb,
+ 0x723d, 0x1c92,
+ 0x724e, 0x1ecc,
+ 0x724f, 0x1ca4,
+ 0x7321, 0x1cd4,
+ 0x7351, 0x1ecd,
+ 0x7352, 0x1f44,
+ 0x7353, 0x1d06,
+ 0x737d, 0x1ece,
+ 0x737e, 0x1d31,
+ 0x7421, 0x1d32,
+ 0x7425, 0x205c,
+ 0x7721, 0x1f45,
+ 0x7727, 0x1f48,
+ 0x7728, 0x0300,
+ 0x7729, 0x02fa,
+ 0x772a, 0x02f9,
+ 0x772e, 0x1f49,
+ 0x773c, 0x1db1,
+ 0x773f, 0x1f54,
+ 0x7740, 0x1db7,
+ 0x7741, 0x1f55,
+ 0x7744, 0x1db4,
+ 0x7747, 0x1f58,
+ 0x7751, 0x0303,
+ 0x7752, 0x1f62,
+ 0x7753, 0x0304,
+ 0x7754, 0x1f63,
+ 0x7757, 0x1f65,
+ 0x7759, 0x1da4,
+ 0x775a, 0x1da1,
+ 0x775b, 0x1f66,
+ 0x775c, 0x1da2,
+ 0x775d, 0x1f67,
+ 0x7760, 0x1da6,
+ 0x7761, 0x1f6a,
+ 0x7762, 0x1da8,
+ 0x7763, 0x1dac,
+ 0x7764, 0x1f6b,
+ 0x7765, 0x1dae,
+ 0x7766, 0x1dab,
+ 0x7767, 0x1f6c,
+ 0x7769, 0x1daf,
+ 0x776a, 0x1f6e,
+ 0x7774, 0x1f75,
+ 0x777a, 0x1dba,
+ 0x777b, 0x1f7b,
+ 0x777e, 0x1f7c,
+ 0x7829, 0x1f7d,
+ 0x7834, 0x1f87,
+ 0x7849, 0x1d83,
+ 0x785d, 0x1f9b,
+ 0x785e, 0x1d97,
+ 0x786b, 0x1f9c,
+ 0x7921, 0x1fb0,
+ 0x7945, 0x1f16,
+ 0x7949, 0x1fca,
+ 0x794b, 0x1dc4,
+ 0x794c, 0x1fcc,
+ 0x794f, 0x1dc3,
+ 0x7950, 0x1fcf,
+ 0x7955, 0x1dc2,
+ 0x7956, 0x1fd4,
+ 0x795d, 0x1fd8,
+ 0x796f, 0x1fe6,
+ 0x7d21, 0x1ecf,
+ 0x7d23, 0x204c,
+ 0x7d24, 0x2052,
+ 0x7d25, 0x1ed1,
+ 0x7d2f, 0x205a,
+ 0x7d30, 0x2053,
+ 0x7d31, 0x2058,
+ 0x7d32, 0x2055,
+ 0x7d33, 0x1edb,
+ 0x7d45, 0x1eee,
+ 0x7d5b, 0x2048,
+ 0x7d6d, 0x02e0,
+ 0x7d71, 0x1ff6,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 japan12AddHEnc16 = {
+ 0,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ japan12AddHMap2, 633
+};
+
+static Gushort japan12AddRKSJHMap2[1270] = {
+ 0x0000, 0x0000,
+ 0x8140, 0x0279,
+ 0x8180, 0x02b8,
+ 0x81b8, 0x02e5,
+ 0x81c8, 0x02ed,
+ 0x81da, 0x02f4,
+ 0x81f0, 0x0303,
+ 0x81fc, 0x030b,
+ 0x824f, 0x030c,
+ 0x8260, 0x0316,
+ 0x8281, 0x0330,
+ 0x829f, 0x034a,
+ 0x82f2, 0x1f16,
+ 0x8340, 0x039d,
+ 0x8380, 0x03dc,
+ 0x839f, 0x03f3,
+ 0x83bf, 0x040b,
+ 0x8440, 0x0423,
+ 0x8470, 0x0444,
+ 0x8480, 0x0453,
+ 0x849f, 0x1d37,
+ 0x84a0, 0x1d39,
+ 0x84a1, 0x1d43,
+ 0x84a2, 0x1d47,
+ 0x84a3, 0x1d4f,
+ 0x84a4, 0x1d4b,
+ 0x84a5, 0x1d53,
+ 0x84a6, 0x1d63,
+ 0x84a7, 0x1d5b,
+ 0x84a8, 0x1d6b,
+ 0x84a9, 0x1d73,
+ 0x84aa, 0x1d38,
+ 0x84ab, 0x1d3a,
+ 0x84ac, 0x1d46,
+ 0x84ad, 0x1d4a,
+ 0x84ae, 0x1d52,
+ 0x84af, 0x1d4e,
+ 0x84b0, 0x1d5a,
+ 0x84b1, 0x1d6a,
+ 0x84b2, 0x1d62,
+ 0x84b3, 0x1d72,
+ 0x84b4, 0x1d82,
+ 0x84b5, 0x1d57,
+ 0x84b6, 0x1d66,
+ 0x84b7, 0x1d5f,
+ 0x84b8, 0x1d6e,
+ 0x84b9, 0x1d76,
+ 0x84ba, 0x1d54,
+ 0x84bb, 0x1d67,
+ 0x84bc, 0x1d5c,
+ 0x84bd, 0x1d6f,
+ 0x84be, 0x1d79,
+ 0x889f, 0x0465,
+ 0x88a0, 0x1dd1,
+ 0x88a1, 0x0467,
+ 0x88b0, 0x1f19,
+ 0x88b1, 0x0477,
+ 0x88b9, 0x1dd2,
+ 0x88ba, 0x0480,
+ 0x88ec, 0x1dd3,
+ 0x88ed, 0x04b3,
+ 0x88ef, 0x1f1a,
+ 0x88f0, 0x04b6,
+ 0x88f1, 0x1dd4,
+ 0x88f2, 0x04b8,
+ 0x88fa, 0x1dd5,
+ 0x88fb, 0x04c1,
+ 0x8940, 0x04c3,
+ 0x8949, 0x1dd6,
+ 0x894a, 0x04cd,
+ 0x8952, 0x1f1b,
+ 0x8953, 0x04d6,
+ 0x8954, 0x1dd7,
+ 0x8955, 0x04d8,
+ 0x8958, 0x1f1c,
+ 0x8959, 0x04dc,
+ 0x895c, 0x1dda,
+ 0x895d, 0x04e0,
+ 0x8961, 0x1ddb,
+ 0x8962, 0x04e5,
+ 0x8980, 0x0502,
+ 0x898b, 0x1ddc,
+ 0x898c, 0x050e,
+ 0x89a6, 0x1ddd,
+ 0x89a7, 0x0529,
+ 0x89a8, 0x1dde,
+ 0x89a9, 0x052b,
+ 0x89de, 0x1ddf,
+ 0x89df, 0x0561,
+ 0x89e5, 0x1f1d,
+ 0x89e6, 0x0568,
+ 0x89f8, 0x1de0,
+ 0x89f9, 0x057b,
+ 0x8a40, 0x057f,
+ 0x8a41, 0x1de2,
+ 0x8a42, 0x0581,
+ 0x8a80, 0x05be,
+ 0x8a8b, 0x1de4,
+ 0x8a8c, 0x05ca,
+ 0x8a93, 0x1de5,
+ 0x8a94, 0x05d2,
+ 0x8a9a, 0x1de6,
+ 0x8a9b, 0x05d9,
+ 0x8ac0, 0x1de7,
+ 0x8ac1, 0x05ff,
+ 0x8acb, 0x1de8,
+ 0x8acc, 0x060a,
+ 0x8ae3, 0x1de9,
+ 0x8ae4, 0x0622,
+ 0x8b40, 0x063b,
+ 0x8b4a, 0x1dea,
+ 0x8b4b, 0x0646,
+ 0x8b5f, 0x1deb,
+ 0x8b60, 0x065b,
+ 0x8b80, 0x067a,
+ 0x8b82, 0x1f1e,
+ 0x8b83, 0x067d,
+ 0x8b88, 0x1f1f,
+ 0x8b89, 0x0683,
+ 0x8ba0, 0x1dec,
+ 0x8ba1, 0x069b,
+ 0x8ba8, 0x1ded,
+ 0x8ba9, 0x06a3,
+ 0x8bc0, 0x1f20,
+ 0x8bc1, 0x06bb,
+ 0x8bcd, 0x1dee,
+ 0x8bce, 0x06c8,
+ 0x8beb, 0x1def,
+ 0x8bec, 0x06e6,
+ 0x8bf2, 0x1df0,
+ 0x8bf3, 0x06ed,
+ 0x8bf9, 0x1df1,
+ 0x8bfa, 0x06f4,
+ 0x8bfb, 0x1df2,
+ 0x8bfc, 0x06f6,
+ 0x8c40, 0x06f7,
+ 0x8c56, 0x1df4,
+ 0x8c57, 0x070e,
+ 0x8c71, 0x1df7,
+ 0x8c72, 0x0729,
+ 0x8c80, 0x0736,
+ 0x8c91, 0x1dfa,
+ 0x8c92, 0x0748,
+ 0x8c9d, 0x1f21,
+ 0x8c9e, 0x1dfc,
+ 0x8c9f, 0x0755,
+ 0x8cb2, 0x1dfd,
+ 0x8cb3, 0x0769,
+ 0x8cbf, 0x1dfe,
+ 0x8cc0, 0x0776,
+ 0x8d40, 0x07b3,
+ 0x8d4a, 0x1dff,
+ 0x8d4b, 0x07be,
+ 0x8d80, 0x07f2,
+ 0x8d8d, 0x1e02,
+ 0x8d8e, 0x0800,
+ 0x8d94, 0x1e03,
+ 0x8d95, 0x0807,
+ 0x8d99, 0x1e04,
+ 0x8d9a, 0x080c,
+ 0x8dd1, 0x1e05,
+ 0x8dd2, 0x0844,
+ 0x8de5, 0x1e06,
+ 0x8de6, 0x0858,
+ 0x8df2, 0x1e07,
+ 0x8df3, 0x0865,
+ 0x8e40, 0x086f,
+ 0x8e46, 0x1e08,
+ 0x8e47, 0x0876,
+ 0x8e49, 0x1e09,
+ 0x8e4a, 0x0879,
+ 0x8e4b, 0x1e0a,
+ 0x8e4c, 0x087b,
+ 0x8e58, 0x1e0b,
+ 0x8e59, 0x0888,
+ 0x8e60, 0x1f22,
+ 0x8e61, 0x0890,
+ 0x8e80, 0x08ae,
+ 0x8ec6, 0x1e0d,
+ 0x8ec7, 0x08f5,
+ 0x8edb, 0x1e0f,
+ 0x8edd, 0x090b,
+ 0x8f40, 0x092b,
+ 0x8f4a, 0x1e11,
+ 0x8f4b, 0x0936,
+ 0x8f55, 0x1e12,
+ 0x8f56, 0x0941,
+ 0x8f80, 0x096a,
+ 0x8f8c, 0x1e13,
+ 0x8f8d, 0x0977,
+ 0x8f92, 0x1e15,
+ 0x8f94, 0x097e,
+ 0x8fa3, 0x1e17,
+ 0x8fa4, 0x098e,
+ 0x8fb1, 0x1e18,
+ 0x8fb2, 0x099c,
+ 0x8fd3, 0x1e1a,
+ 0x8fd4, 0x09be,
+ 0x8fdd, 0x1e1b,
+ 0x8fde, 0x09c8,
+ 0x8fe2, 0x1e1c,
+ 0x8fe3, 0x09cd,
+ 0x9040, 0x09e7,
+ 0x9049, 0x1e1d,
+ 0x904a, 0x09f1,
+ 0x9078, 0x1f23,
+ 0x9079, 0x0a20,
+ 0x9080, 0x1e1f,
+ 0x9081, 0x0a27,
+ 0x90a0, 0x1e21,
+ 0x90a1, 0x0a47,
+ 0x90e4, 0x1e23,
+ 0x90e5, 0x0a8b,
+ 0x90ef, 0x1e24,
+ 0x90f0, 0x0a96,
+ 0x90f7, 0x1e26,
+ 0x90f8, 0x1f24,
+ 0x90f9, 0x0a9f,
+ 0x90fa, 0x1f25,
+ 0x90fc, 0x0aa2,
+ 0x9140, 0x0aa3,
+ 0x9146, 0x1e28,
+ 0x9147, 0x0aaa,
+ 0x9158, 0x1e29,
+ 0x9159, 0x0abc,
+ 0x916b, 0x1e2a,
+ 0x916c, 0x0acf,
+ 0x916e, 0x1e2b,
+ 0x916f, 0x0ad2,
+ 0x917e, 0x1e2c,
+ 0x9180, 0x0ae2,
+ 0x9189, 0x1e2d,
+ 0x918a, 0x0aec,
+ 0x91b5, 0x1f27,
+ 0x91b6, 0x0b18,
+ 0x91bb, 0x1e2e,
+ 0x91bc, 0x0b1e,
+ 0x91cb, 0x1e2f,
+ 0x91cc, 0x0b2e,
+ 0x91da, 0x1e30,
+ 0x91db, 0x0b3d,
+ 0x91e1, 0x1e31,
+ 0x91e2, 0x0b44,
+ 0x91ed, 0x1e32,
+ 0x91ee, 0x0b50,
+ 0x91fb, 0x1e35,
+ 0x91fc, 0x0b5e,
+ 0x9240, 0x0b5f,
+ 0x9246, 0x1e36,
+ 0x9247, 0x0b66,
+ 0x9248, 0x1e37,
+ 0x9249, 0x0b68,
+ 0x924c, 0x1e39,
+ 0x924e, 0x0b6d,
+ 0x925c, 0x1e3b,
+ 0x925d, 0x0b7c,
+ 0x9280, 0x0b9e,
+ 0x9290, 0x1e3c,
+ 0x9291, 0x0baf,
+ 0x9295, 0x1e3d,
+ 0x9296, 0x0bb4,
+ 0x929c, 0x1e3e,
+ 0x929d, 0x0bbb,
+ 0x92bb, 0x1e3f,
+ 0x92bc, 0x0bda,
+ 0x92c6, 0x1e40,
+ 0x92c7, 0x0be5,
+ 0x92c8, 0x1e41,
+ 0x92c9, 0x0be7,
+ 0x92cd, 0x1e43,
+ 0x92ce, 0x0bec,
+ 0x9340, 0x0c1b,
+ 0x9341, 0x1e44,
+ 0x9342, 0x0c1d,
+ 0x9346, 0x1e45,
+ 0x9347, 0x0c22,
+ 0x934d, 0x1e46,
+ 0x934e, 0x0c29,
+ 0x9355, 0x1e47,
+ 0x9356, 0x0c31,
+ 0x935e, 0x1e48,
+ 0x935f, 0x0c3a,
+ 0x9367, 0x1e49,
+ 0x9368, 0x0c43,
+ 0x936a, 0x1e4a,
+ 0x936b, 0x0c46,
+ 0x9370, 0x1f28,
+ 0x9371, 0x1e4c,
+ 0x9372, 0x0c4d,
+ 0x9380, 0x0c5a,
+ 0x9384, 0x1e4d,
+ 0x9385, 0x0c5f,
+ 0x9398, 0x1e4e,
+ 0x9399, 0x0c73,
+ 0x93c0, 0x1e50,
+ 0x93c1, 0x0c9b,
+ 0x93d2, 0x1e51,
+ 0x93d3, 0x0cad,
+ 0x93d9, 0x1e53,
+ 0x93da, 0x0cb4,
+ 0x93e4, 0x1e56,
+ 0x93e6, 0x0cc0,
+ 0x93e8, 0x1e58,
+ 0x93e9, 0x0cc3,
+ 0x93f4, 0x1ec0,
+ 0x93f5, 0x0ccf,
+ 0x9440, 0x0cd7,
+ 0x9448, 0x1e59,
+ 0x9449, 0x1f29,
+ 0x944a, 0x0ce1,
+ 0x9458, 0x1e5a,
+ 0x9459, 0x0cf0,
+ 0x9476, 0x1e5b,
+ 0x9477, 0x0d0e,
+ 0x9480, 0x0d16,
+ 0x9487, 0x1e5c,
+ 0x9488, 0x0d1e,
+ 0x9489, 0x1e5d,
+ 0x948a, 0x0d20,
+ 0x948d, 0x1e5e,
+ 0x948e, 0x0d24,
+ 0x94a2, 0x1e5f,
+ 0x94a3, 0x0d39,
+ 0x94ac, 0x1e60,
+ 0x94ad, 0x0d43,
+ 0x94ae, 0x1e61,
+ 0x94af, 0x0d45,
+ 0x94be, 0x1f2a,
+ 0x94bf, 0x0d55,
+ 0x94d2, 0x1e62,
+ 0x94d3, 0x0d69,
+ 0x94f3, 0x1e64,
+ 0x94f4, 0x0d8a,
+ 0x9540, 0x0d93,
+ 0x9541, 0x1e65,
+ 0x9543, 0x0d96,
+ 0x954e, 0x1e67,
+ 0x954f, 0x0da2,
+ 0x9551, 0x1e68,
+ 0x9552, 0x0da5,
+ 0x9554, 0x1e69,
+ 0x9555, 0x0da8,
+ 0x955f, 0x1e6a,
+ 0x9560, 0x0db3,
+ 0x956d, 0x1e6b,
+ 0x956e, 0x0dc1,
+ 0x9580, 0x0dd2,
+ 0x95c1, 0x1e6d,
+ 0x95c2, 0x0e14,
+ 0x95cb, 0x1e6e,
+ 0x95cc, 0x0e1e,
+ 0x95d1, 0x1f2b,
+ 0x95d2, 0x0e24,
+ 0x95d8, 0x1e6f,
+ 0x95d9, 0x0e2b,
+ 0x95f7, 0x1e70,
+ 0x95f8, 0x0e4a,
+ 0x9640, 0x0e4f,
+ 0x9648, 0x1e72,
+ 0x9649, 0x0e58,
+ 0x966a, 0x1e73,
+ 0x966b, 0x0e7a,
+ 0x9680, 0x0e8e,
+ 0x9690, 0x1e74,
+ 0x9691, 0x0e9f,
+ 0x9698, 0x1f2c,
+ 0x9699, 0x0ea7,
+ 0x96cb, 0x1e75,
+ 0x96cc, 0x0eda,
+ 0x96d7, 0x1e76,
+ 0x96d8, 0x0ee6,
+ 0x96dd, 0x1e77,
+ 0x96de, 0x0eec,
+ 0x96e0, 0x1e78,
+ 0x96e1, 0x0eef,
+ 0x96f8, 0x1e79,
+ 0x96f9, 0x0f07,
+ 0x96fa, 0x1e7a,
+ 0x96fb, 0x0f09,
+ 0x9740, 0x0f0b,
+ 0x9751, 0x1e7c,
+ 0x9752, 0x0f1d,
+ 0x976f, 0x1e7d,
+ 0x9770, 0x0f3b,
+ 0x9773, 0x1e7e,
+ 0x9774, 0x0f3f,
+ 0x9780, 0x0f4a,
+ 0x9789, 0x1e7f,
+ 0x978a, 0x0f54,
+ 0x97f8, 0x1e81,
+ 0x97fa, 0x1f2d,
+ 0x97fb, 0x0fc5,
+ 0x9840, 0x1e83,
+ 0x9841, 0x0fc8,
+ 0x9850, 0x1e84,
+ 0x9851, 0x0fd8,
+ 0x9858, 0x1e85,
+ 0x9859, 0x0fe0,
+ 0x989f, 0x0ffa,
+ 0x9940, 0x1058,
+ 0x9941, 0x1f2e,
+ 0x9942, 0x105a,
+ 0x995c, 0x1e86,
+ 0x995d, 0x1075,
+ 0x996c, 0x1e89,
+ 0x996d, 0x1085,
+ 0x9980, 0x1097,
+ 0x99b6, 0x1f2f,
+ 0x99b7, 0x10ce,
+ 0x9a40, 0x1114,
+ 0x9a4f, 0x1e8a,
+ 0x9a50, 0x1124,
+ 0x9a59, 0x1e8b,
+ 0x9a5a, 0x112e,
+ 0x9a67, 0x1f30,
+ 0x9a68, 0x113c,
+ 0x9a7d, 0x1e8d,
+ 0x9a7e, 0x1152,
+ 0x9a80, 0x1153,
+ 0x9a8b, 0x1e8e,
+ 0x9a8c, 0x1f31,
+ 0x9a8d, 0x1160,
+ 0x9ac2, 0x1e8f,
+ 0x9ac3, 0x1f32,
+ 0x9ac4, 0x1197,
+ 0x9aea, 0x1f33,
+ 0x9aeb, 0x11be,
+ 0x9b40, 0x11d0,
+ 0x9b5c, 0x1e90,
+ 0x9b5d, 0x11ed,
+ 0x9b80, 0x120f,
+ 0x9b83, 0x1e91,
+ 0x9b84, 0x1213,
+ 0x9b98, 0x1f34,
+ 0x9b99, 0x1228,
+ 0x9ba0, 0x1e92,
+ 0x9ba1, 0x1230,
+ 0x9bfb, 0x1f35,
+ 0x9c40, 0x128c,
+ 0x9c80, 0x12cb,
+ 0x9ca2, 0x1e94,
+ 0x9ca3, 0x12ee,
+ 0x9d40, 0x1348,
+ 0x9d47, 0x1f37,
+ 0x9d48, 0x1350,
+ 0x9d80, 0x1e95,
+ 0x9d81, 0x1388,
+ 0x9d8c, 0x1e96,
+ 0x9d8d, 0x1394,
+ 0x9db7, 0x1e97,
+ 0x9db8, 0x13bf,
+ 0x9df8, 0x1f38,
+ 0x9df9, 0x1400,
+ 0x9e40, 0x1404,
+ 0x9e64, 0x1e99,
+ 0x9e65, 0x1429,
+ 0x9e80, 0x1443,
+ 0x9e8b, 0x1e9b,
+ 0x9e8c, 0x144f,
+ 0x9f40, 0x14c0,
+ 0x9f80, 0x14ff,
+ 0x9f81, 0x1f39,
+ 0x9f82, 0x1501,
+ 0x9fce, 0x1e9d,
+ 0x9fcf, 0x154e,
+ 0x9fd4, 0x1f3a,
+ 0x9fd5, 0x1554,
+ 0x9ff4, 0x1f3b,
+ 0x9ff5, 0x1574,
+ 0xe040, 0x157c,
+ 0xe080, 0x15bb,
+ 0xe093, 0x1e9e,
+ 0xe094, 0x15cf,
+ 0xe0a4, 0x1e9f,
+ 0xe0a5, 0x15e0,
+ 0xe0dd, 0x1ea0,
+ 0xe0de, 0x1619,
+ 0xe140, 0x1638,
+ 0xe14a, 0x1ea1,
+ 0xe14b, 0x1643,
+ 0xe180, 0x1677,
+ 0xe1ed, 0x1ea5,
+ 0xe1ee, 0x16e5,
+ 0xe240, 0x16f4,
+ 0xe269, 0x1ea6,
+ 0xe26a, 0x171e,
+ 0xe273, 0x1ea7,
+ 0xe274, 0x1728,
+ 0xe278, 0x1f3c,
+ 0xe279, 0x172d,
+ 0xe280, 0x1733,
+ 0xe2b7, 0x1ea8,
+ 0xe2b8, 0x176b,
+ 0xe2be, 0x1f3d,
+ 0xe2bf, 0x1772,
+ 0xe2e2, 0x1ea9,
+ 0xe2e3, 0x1796,
+ 0xe2ec, 0x1eaa,
+ 0xe2ed, 0x17a0,
+ 0xe340, 0x17b0,
+ 0xe358, 0x1eab,
+ 0xe359, 0x17c9,
+ 0xe35a, 0x1eac,
+ 0xe35b, 0x17cb,
+ 0xe365, 0x1ead,
+ 0xe366, 0x17d6,
+ 0xe380, 0x17ef,
+ 0xe3c7, 0x1f3e,
+ 0xe3c8, 0x1837,
+ 0xe440, 0x186c,
+ 0xe480, 0x18ab,
+ 0xe484, 0x1eaf,
+ 0xe485, 0x18b0,
+ 0xe489, 0x1eb0,
+ 0xe48a, 0x18b5,
+ 0xe492, 0x1eb1,
+ 0xe493, 0x18be,
+ 0xe4b9, 0x1eb3,
+ 0xe4ba, 0x18e5,
+ 0xe4cb, 0x1f3f,
+ 0xe4cc, 0x18f7,
+ 0xe540, 0x1928,
+ 0xe580, 0x1967,
+ 0xe59e, 0x1f40,
+ 0xe59f, 0x1986,
+ 0xe5ba, 0x1f41,
+ 0xe5bc, 0x19a3,
+ 0xe5ed, 0x1eb8,
+ 0xe5ee, 0x19d5,
+ 0xe640, 0x19e4,
+ 0xe651, 0x1eb9,
+ 0xe652, 0x19f6,
+ 0xe680, 0x1a23,
+ 0xe686, 0x1eba,
+ 0xe687, 0x1a2a,
+ 0xe6e7, 0x1ebc,
+ 0xe6e8, 0x1a8b,
+ 0xe740, 0x1aa0,
+ 0xe76d, 0x1ebe,
+ 0xe76e, 0x1ace,
+ 0xe780, 0x1adf,
+ 0xe7a7, 0x1ec1,
+ 0xe7a8, 0x1b07,
+ 0xe7bb, 0x1ec2,
+ 0xe7bc, 0x1b1b,
+ 0xe840, 0x1b5c,
+ 0xe880, 0x1b9b,
+ 0xe8cf, 0x1ec7,
+ 0xe8d0, 0x1beb,
+ 0xe940, 0x1c18,
+ 0xe978, 0x1f43,
+ 0xe979, 0x1c51,
+ 0xe980, 0x1c57,
+ 0xe9ab, 0x1eca,
+ 0xe9ac, 0x1c83,
+ 0xe9ba, 0x1ecb,
+ 0xe9bb, 0x1c92,
+ 0xe9cc, 0x1ecc,
+ 0xe9cd, 0x1ca4,
+ 0xea40, 0x1cd4,
+ 0xea70, 0x1ecd,
+ 0xea71, 0x1f44,
+ 0xea72, 0x1d06,
+ 0xea80, 0x1d13,
+ 0xea9d, 0x1ece,
+ 0xea9e, 0x1d31,
+ 0xeaa3, 0x205c,
+ 0xec40, 0x1f45,
+ 0xec46, 0x1f48,
+ 0xec47, 0x0300,
+ 0xec48, 0x02fa,
+ 0xec49, 0x02f9,
+ 0xec4d, 0x1f49,
+ 0xec5b, 0x1db1,
+ 0xec5e, 0x1f54,
+ 0xec5f, 0x1db7,
+ 0xec60, 0x1f55,
+ 0xec63, 0x1db4,
+ 0xec66, 0x1f58,
+ 0xec70, 0x0303,
+ 0xec71, 0x1f62,
+ 0xec72, 0x0304,
+ 0xec73, 0x1f63,
+ 0xec76, 0x1f65,
+ 0xec78, 0x1da4,
+ 0xec79, 0x1da1,
+ 0xec7a, 0x1f66,
+ 0xec7b, 0x1da2,
+ 0xec7c, 0x1f67,
+ 0xec80, 0x1da6,
+ 0xec81, 0x1f6a,
+ 0xec82, 0x1da8,
+ 0xec83, 0x1dac,
+ 0xec84, 0x1f6b,
+ 0xec85, 0x1dae,
+ 0xec86, 0x1dab,
+ 0xec87, 0x1f6c,
+ 0xec89, 0x1daf,
+ 0xec8a, 0x1f6e,
+ 0xec94, 0x1f75,
+ 0xec9a, 0x1dba,
+ 0xec9b, 0x1f7b,
+ 0xec9e, 0x1f7c,
+ 0xeca7, 0x1f7d,
+ 0xecb2, 0x1f87,
+ 0xecc7, 0x1d83,
+ 0xecdb, 0x1f9b,
+ 0xecdc, 0x1d97,
+ 0xece9, 0x1f9c,
+ 0xed40, 0x1fb0,
+ 0xed64, 0x1f16,
+ 0xed68, 0x1fca,
+ 0xed6a, 0x1dc4,
+ 0xed6b, 0x1fcc,
+ 0xed6e, 0x1dc3,
+ 0xed6f, 0x1fcf,
+ 0xed74, 0x1dc2,
+ 0xed75, 0x1fd4,
+ 0xed7c, 0x1fd8,
+ 0xed80, 0x1fdb,
+ 0xed8f, 0x1fe6,
+ 0xef40, 0x1ecf,
+ 0xef42, 0x204c,
+ 0xef43, 0x2052,
+ 0xef44, 0x1ed1,
+ 0xef4e, 0x205a,
+ 0xef4f, 0x2053,
+ 0xef50, 0x2058,
+ 0xef51, 0x2055,
+ 0xef52, 0x1edb,
+ 0xef64, 0x1eee,
+ 0xef7a, 0x2048,
+ 0xef8d, 0x02e0,
+ 0xef91, 0x1ff6,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 japan12AddRKSJHEnc16 = {
+ 0,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee,
+ 0x00ef, 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6,
+ 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe,
+ 0x00ff, 0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106,
+ 0x0107, 0x0108, 0x0109, 0x010a, 0x010b, 0x010c, 0x010d, 0x010e,
+ 0x010f, 0x0110, 0x0111, 0x0112, 0x0113, 0x0114, 0x0115, 0x0116,
+ 0x0117, 0x0118, 0x0119, 0x011a, 0x011b, 0x011c, 0x011d, 0x011e,
+ 0x011f, 0x0120, 0x0121, 0x0122, 0x0123, 0x0124, 0x0125, 0x0126,
+ 0x0127, 0x0128, 0x0129, 0x012a, 0x012b, 0x012c, 0x012d, 0x012e,
+ 0x012f, 0x0130, 0x0131, 0x0132, 0x0133, 0x0134, 0x0135, 0x0136,
+ 0x0137, 0x0138, 0x0139, 0x013a, 0x013b, 0x013c, 0x013d, 0x013e,
+ 0x013f, 0x0140, 0x0141, 0x0142, 0x0143, 0x0144, 0x0145, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0146, 0x0147, 0x0148, 0x0149, 0x014a, 0x014b, 0x014c, 0x014d,
+ 0x014e, 0x014f, 0x0150, 0x0151, 0x0152, 0x0153, 0x0154, 0x0155,
+ 0x0156, 0x0157, 0x0158, 0x0159, 0x015a, 0x015b, 0x015c, 0x015d,
+ 0x015e, 0x015f, 0x0160, 0x0161, 0x0162, 0x0163, 0x0164, 0x0165,
+ 0x0166, 0x0167, 0x0168, 0x0169, 0x016a, 0x016b, 0x016c, 0x016d,
+ 0x016e, 0x016f, 0x0170, 0x0171, 0x0172, 0x0173, 0x0174, 0x0175,
+ 0x0176, 0x0177, 0x0178, 0x0179, 0x017a, 0x017b, 0x017c, 0x017d,
+ 0x017e, 0x017f, 0x0180, 0x0181, 0x0182, 0x0183, 0x0184, 0x0185,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ japan12AddRKSJHMap2, 635
+};
+
+static Gushort japan12AddRKSJVMap2[1384] = {
+ 0x0000, 0x0000,
+ 0x8140, 0x0279,
+ 0x8180, 0x02b8,
+ 0x81b8, 0x02e5,
+ 0x81c8, 0x02ed,
+ 0x81da, 0x02f4,
+ 0x81f0, 0x0303,
+ 0x81fc, 0x030b,
+ 0x824f, 0x030c,
+ 0x8260, 0x0316,
+ 0x8281, 0x0330,
+ 0x829f, 0x034a,
+ 0x82f2, 0x1f16,
+ 0x8340, 0x039d,
+ 0x8380, 0x03dc,
+ 0x839f, 0x03f3,
+ 0x83bf, 0x040b,
+ 0x8440, 0x0423,
+ 0x8470, 0x0444,
+ 0x8480, 0x0453,
+ 0x849f, 0x1d37,
+ 0x84a0, 0x1d39,
+ 0x84a1, 0x1d43,
+ 0x84a2, 0x1d47,
+ 0x84a3, 0x1d4f,
+ 0x84a4, 0x1d4b,
+ 0x84a5, 0x1d53,
+ 0x84a6, 0x1d63,
+ 0x84a7, 0x1d5b,
+ 0x84a8, 0x1d6b,
+ 0x84a9, 0x1d73,
+ 0x84aa, 0x1d38,
+ 0x84ab, 0x1d3a,
+ 0x84ac, 0x1d46,
+ 0x84ad, 0x1d4a,
+ 0x84ae, 0x1d52,
+ 0x84af, 0x1d4e,
+ 0x84b0, 0x1d5a,
+ 0x84b1, 0x1d6a,
+ 0x84b2, 0x1d62,
+ 0x84b3, 0x1d72,
+ 0x84b4, 0x1d82,
+ 0x84b5, 0x1d57,
+ 0x84b6, 0x1d66,
+ 0x84b7, 0x1d5f,
+ 0x84b8, 0x1d6e,
+ 0x84b9, 0x1d76,
+ 0x84ba, 0x1d54,
+ 0x84bb, 0x1d67,
+ 0x84bc, 0x1d5c,
+ 0x84bd, 0x1d6f,
+ 0x84be, 0x1d79,
+ 0x889f, 0x0465,
+ 0x88a0, 0x1dd1,
+ 0x88a1, 0x0467,
+ 0x88b0, 0x1f19,
+ 0x88b1, 0x0477,
+ 0x88b9, 0x1dd2,
+ 0x88ba, 0x0480,
+ 0x88ec, 0x1dd3,
+ 0x88ed, 0x04b3,
+ 0x88ef, 0x1f1a,
+ 0x88f0, 0x04b6,
+ 0x88f1, 0x1dd4,
+ 0x88f2, 0x04b8,
+ 0x88fa, 0x1dd5,
+ 0x88fb, 0x04c1,
+ 0x8940, 0x04c3,
+ 0x8949, 0x1dd6,
+ 0x894a, 0x04cd,
+ 0x8952, 0x1f1b,
+ 0x8953, 0x04d6,
+ 0x8954, 0x1dd7,
+ 0x8955, 0x04d8,
+ 0x8958, 0x1f1c,
+ 0x8959, 0x04dc,
+ 0x895c, 0x1dda,
+ 0x895d, 0x04e0,
+ 0x8961, 0x1ddb,
+ 0x8962, 0x04e5,
+ 0x8980, 0x0502,
+ 0x898b, 0x1ddc,
+ 0x898c, 0x050e,
+ 0x89a6, 0x1ddd,
+ 0x89a7, 0x0529,
+ 0x89a8, 0x1dde,
+ 0x89a9, 0x052b,
+ 0x89de, 0x1ddf,
+ 0x89df, 0x0561,
+ 0x89e5, 0x1f1d,
+ 0x89e6, 0x0568,
+ 0x89f8, 0x1de0,
+ 0x89f9, 0x057b,
+ 0x8a40, 0x057f,
+ 0x8a41, 0x1de2,
+ 0x8a42, 0x0581,
+ 0x8a80, 0x05be,
+ 0x8a8b, 0x1de4,
+ 0x8a8c, 0x05ca,
+ 0x8a93, 0x1de5,
+ 0x8a94, 0x05d2,
+ 0x8a9a, 0x1de6,
+ 0x8a9b, 0x05d9,
+ 0x8ac0, 0x1de7,
+ 0x8ac1, 0x05ff,
+ 0x8acb, 0x1de8,
+ 0x8acc, 0x060a,
+ 0x8ae3, 0x1de9,
+ 0x8ae4, 0x0622,
+ 0x8b40, 0x063b,
+ 0x8b4a, 0x1dea,
+ 0x8b4b, 0x0646,
+ 0x8b5f, 0x1deb,
+ 0x8b60, 0x065b,
+ 0x8b80, 0x067a,
+ 0x8b82, 0x1f1e,
+ 0x8b83, 0x067d,
+ 0x8b88, 0x1f1f,
+ 0x8b89, 0x0683,
+ 0x8ba0, 0x1dec,
+ 0x8ba1, 0x069b,
+ 0x8ba8, 0x1ded,
+ 0x8ba9, 0x06a3,
+ 0x8bc0, 0x1f20,
+ 0x8bc1, 0x06bb,
+ 0x8bcd, 0x1dee,
+ 0x8bce, 0x06c8,
+ 0x8beb, 0x1def,
+ 0x8bec, 0x06e6,
+ 0x8bf2, 0x1df0,
+ 0x8bf3, 0x06ed,
+ 0x8bf9, 0x1df1,
+ 0x8bfa, 0x06f4,
+ 0x8bfb, 0x1df2,
+ 0x8bfc, 0x06f6,
+ 0x8c40, 0x06f7,
+ 0x8c56, 0x1df4,
+ 0x8c57, 0x070e,
+ 0x8c71, 0x1df7,
+ 0x8c72, 0x0729,
+ 0x8c80, 0x0736,
+ 0x8c91, 0x1dfa,
+ 0x8c92, 0x0748,
+ 0x8c9d, 0x1f21,
+ 0x8c9e, 0x1dfc,
+ 0x8c9f, 0x0755,
+ 0x8cb2, 0x1dfd,
+ 0x8cb3, 0x0769,
+ 0x8cbf, 0x1dfe,
+ 0x8cc0, 0x0776,
+ 0x8d40, 0x07b3,
+ 0x8d4a, 0x1dff,
+ 0x8d4b, 0x07be,
+ 0x8d80, 0x07f2,
+ 0x8d8d, 0x1e02,
+ 0x8d8e, 0x0800,
+ 0x8d94, 0x1e03,
+ 0x8d95, 0x0807,
+ 0x8d99, 0x1e04,
+ 0x8d9a, 0x080c,
+ 0x8dd1, 0x1e05,
+ 0x8dd2, 0x0844,
+ 0x8de5, 0x1e06,
+ 0x8de6, 0x0858,
+ 0x8df2, 0x1e07,
+ 0x8df3, 0x0865,
+ 0x8e40, 0x086f,
+ 0x8e46, 0x1e08,
+ 0x8e47, 0x0876,
+ 0x8e49, 0x1e09,
+ 0x8e4a, 0x0879,
+ 0x8e4b, 0x1e0a,
+ 0x8e4c, 0x087b,
+ 0x8e58, 0x1e0b,
+ 0x8e59, 0x0888,
+ 0x8e60, 0x1f22,
+ 0x8e61, 0x0890,
+ 0x8e80, 0x08ae,
+ 0x8ec6, 0x1e0d,
+ 0x8ec7, 0x08f5,
+ 0x8edb, 0x1e0f,
+ 0x8edd, 0x090b,
+ 0x8f40, 0x092b,
+ 0x8f4a, 0x1e11,
+ 0x8f4b, 0x0936,
+ 0x8f55, 0x1e12,
+ 0x8f56, 0x0941,
+ 0x8f80, 0x096a,
+ 0x8f8c, 0x1e13,
+ 0x8f8d, 0x0977,
+ 0x8f92, 0x1e15,
+ 0x8f94, 0x097e,
+ 0x8fa3, 0x1e17,
+ 0x8fa4, 0x098e,
+ 0x8fb1, 0x1e18,
+ 0x8fb2, 0x099c,
+ 0x8fd3, 0x1e1a,
+ 0x8fd4, 0x09be,
+ 0x8fdd, 0x1e1b,
+ 0x8fde, 0x09c8,
+ 0x8fe2, 0x1e1c,
+ 0x8fe3, 0x09cd,
+ 0x9040, 0x09e7,
+ 0x9049, 0x1e1d,
+ 0x904a, 0x09f1,
+ 0x9078, 0x1f23,
+ 0x9079, 0x0a20,
+ 0x9080, 0x1e1f,
+ 0x9081, 0x0a27,
+ 0x90a0, 0x1e21,
+ 0x90a1, 0x0a47,
+ 0x90e4, 0x1e23,
+ 0x90e5, 0x0a8b,
+ 0x90ef, 0x1e24,
+ 0x90f0, 0x0a96,
+ 0x90f7, 0x1e26,
+ 0x90f8, 0x1f24,
+ 0x90f9, 0x0a9f,
+ 0x90fa, 0x1f25,
+ 0x90fc, 0x0aa2,
+ 0x9140, 0x0aa3,
+ 0x9146, 0x1e28,
+ 0x9147, 0x0aaa,
+ 0x9158, 0x1e29,
+ 0x9159, 0x0abc,
+ 0x916b, 0x1e2a,
+ 0x916c, 0x0acf,
+ 0x916e, 0x1e2b,
+ 0x916f, 0x0ad2,
+ 0x917e, 0x1e2c,
+ 0x9180, 0x0ae2,
+ 0x9189, 0x1e2d,
+ 0x918a, 0x0aec,
+ 0x91b5, 0x1f27,
+ 0x91b6, 0x0b18,
+ 0x91bb, 0x1e2e,
+ 0x91bc, 0x0b1e,
+ 0x91cb, 0x1e2f,
+ 0x91cc, 0x0b2e,
+ 0x91da, 0x1e30,
+ 0x91db, 0x0b3d,
+ 0x91e1, 0x1e31,
+ 0x91e2, 0x0b44,
+ 0x91ed, 0x1e32,
+ 0x91ee, 0x0b50,
+ 0x91fb, 0x1e35,
+ 0x91fc, 0x0b5e,
+ 0x9240, 0x0b5f,
+ 0x9246, 0x1e36,
+ 0x9247, 0x0b66,
+ 0x9248, 0x1e37,
+ 0x9249, 0x0b68,
+ 0x924c, 0x1e39,
+ 0x924e, 0x0b6d,
+ 0x925c, 0x1e3b,
+ 0x925d, 0x0b7c,
+ 0x9280, 0x0b9e,
+ 0x9290, 0x1e3c,
+ 0x9291, 0x0baf,
+ 0x9295, 0x1e3d,
+ 0x9296, 0x0bb4,
+ 0x929c, 0x1e3e,
+ 0x929d, 0x0bbb,
+ 0x92bb, 0x1e3f,
+ 0x92bc, 0x0bda,
+ 0x92c6, 0x1e40,
+ 0x92c7, 0x0be5,
+ 0x92c8, 0x1e41,
+ 0x92c9, 0x0be7,
+ 0x92cd, 0x1e43,
+ 0x92ce, 0x0bec,
+ 0x9340, 0x0c1b,
+ 0x9341, 0x1e44,
+ 0x9342, 0x0c1d,
+ 0x9346, 0x1e45,
+ 0x9347, 0x0c22,
+ 0x934d, 0x1e46,
+ 0x934e, 0x0c29,
+ 0x9355, 0x1e47,
+ 0x9356, 0x0c31,
+ 0x935e, 0x1e48,
+ 0x935f, 0x0c3a,
+ 0x9367, 0x1e49,
+ 0x9368, 0x0c43,
+ 0x936a, 0x1e4a,
+ 0x936b, 0x0c46,
+ 0x9370, 0x1f28,
+ 0x9371, 0x1e4c,
+ 0x9372, 0x0c4d,
+ 0x9380, 0x0c5a,
+ 0x9384, 0x1e4d,
+ 0x9385, 0x0c5f,
+ 0x9398, 0x1e4e,
+ 0x9399, 0x0c73,
+ 0x93c0, 0x1e50,
+ 0x93c1, 0x0c9b,
+ 0x93d2, 0x1e51,
+ 0x93d3, 0x0cad,
+ 0x93d9, 0x1e53,
+ 0x93da, 0x0cb4,
+ 0x93e4, 0x1e56,
+ 0x93e6, 0x0cc0,
+ 0x93e8, 0x1e58,
+ 0x93e9, 0x0cc3,
+ 0x93f4, 0x1ec0,
+ 0x93f5, 0x0ccf,
+ 0x9440, 0x0cd7,
+ 0x9448, 0x1e59,
+ 0x9449, 0x1f29,
+ 0x944a, 0x0ce1,
+ 0x9458, 0x1e5a,
+ 0x9459, 0x0cf0,
+ 0x9476, 0x1e5b,
+ 0x9477, 0x0d0e,
+ 0x9480, 0x0d16,
+ 0x9487, 0x1e5c,
+ 0x9488, 0x0d1e,
+ 0x9489, 0x1e5d,
+ 0x948a, 0x0d20,
+ 0x948d, 0x1e5e,
+ 0x948e, 0x0d24,
+ 0x94a2, 0x1e5f,
+ 0x94a3, 0x0d39,
+ 0x94ac, 0x1e60,
+ 0x94ad, 0x0d43,
+ 0x94ae, 0x1e61,
+ 0x94af, 0x0d45,
+ 0x94be, 0x1f2a,
+ 0x94bf, 0x0d55,
+ 0x94d2, 0x1e62,
+ 0x94d3, 0x0d69,
+ 0x94f3, 0x1e64,
+ 0x94f4, 0x0d8a,
+ 0x9540, 0x0d93,
+ 0x9541, 0x1e65,
+ 0x9543, 0x0d96,
+ 0x954e, 0x1e67,
+ 0x954f, 0x0da2,
+ 0x9551, 0x1e68,
+ 0x9552, 0x0da5,
+ 0x9554, 0x1e69,
+ 0x9555, 0x0da8,
+ 0x955f, 0x1e6a,
+ 0x9560, 0x0db3,
+ 0x956d, 0x1e6b,
+ 0x956e, 0x0dc1,
+ 0x9580, 0x0dd2,
+ 0x95c1, 0x1e6d,
+ 0x95c2, 0x0e14,
+ 0x95cb, 0x1e6e,
+ 0x95cc, 0x0e1e,
+ 0x95d1, 0x1f2b,
+ 0x95d2, 0x0e24,
+ 0x95d8, 0x1e6f,
+ 0x95d9, 0x0e2b,
+ 0x95f7, 0x1e70,
+ 0x95f8, 0x0e4a,
+ 0x9640, 0x0e4f,
+ 0x9648, 0x1e72,
+ 0x9649, 0x0e58,
+ 0x966a, 0x1e73,
+ 0x966b, 0x0e7a,
+ 0x9680, 0x0e8e,
+ 0x9690, 0x1e74,
+ 0x9691, 0x0e9f,
+ 0x9698, 0x1f2c,
+ 0x9699, 0x0ea7,
+ 0x96cb, 0x1e75,
+ 0x96cc, 0x0eda,
+ 0x96d7, 0x1e76,
+ 0x96d8, 0x0ee6,
+ 0x96dd, 0x1e77,
+ 0x96de, 0x0eec,
+ 0x96e0, 0x1e78,
+ 0x96e1, 0x0eef,
+ 0x96f8, 0x1e79,
+ 0x96f9, 0x0f07,
+ 0x96fa, 0x1e7a,
+ 0x96fb, 0x0f09,
+ 0x9740, 0x0f0b,
+ 0x9751, 0x1e7c,
+ 0x9752, 0x0f1d,
+ 0x976f, 0x1e7d,
+ 0x9770, 0x0f3b,
+ 0x9773, 0x1e7e,
+ 0x9774, 0x0f3f,
+ 0x9780, 0x0f4a,
+ 0x9789, 0x1e7f,
+ 0x978a, 0x0f54,
+ 0x97f8, 0x1e81,
+ 0x97fa, 0x1f2d,
+ 0x97fb, 0x0fc5,
+ 0x9840, 0x1e83,
+ 0x9841, 0x0fc8,
+ 0x9850, 0x1e84,
+ 0x9851, 0x0fd8,
+ 0x9858, 0x1e85,
+ 0x9859, 0x0fe0,
+ 0x989f, 0x0ffa,
+ 0x9940, 0x1058,
+ 0x9941, 0x1f2e,
+ 0x9942, 0x105a,
+ 0x995c, 0x1e86,
+ 0x995d, 0x1075,
+ 0x996c, 0x1e89,
+ 0x996d, 0x1085,
+ 0x9980, 0x1097,
+ 0x99b6, 0x1f2f,
+ 0x99b7, 0x10ce,
+ 0x9a40, 0x1114,
+ 0x9a4f, 0x1e8a,
+ 0x9a50, 0x1124,
+ 0x9a59, 0x1e8b,
+ 0x9a5a, 0x112e,
+ 0x9a67, 0x1f30,
+ 0x9a68, 0x113c,
+ 0x9a7d, 0x1e8d,
+ 0x9a7e, 0x1152,
+ 0x9a80, 0x1153,
+ 0x9a8b, 0x1e8e,
+ 0x9a8c, 0x1f31,
+ 0x9a8d, 0x1160,
+ 0x9ac2, 0x1e8f,
+ 0x9ac3, 0x1f32,
+ 0x9ac4, 0x1197,
+ 0x9aea, 0x1f33,
+ 0x9aeb, 0x11be,
+ 0x9b40, 0x11d0,
+ 0x9b5c, 0x1e90,
+ 0x9b5d, 0x11ed,
+ 0x9b80, 0x120f,
+ 0x9b83, 0x1e91,
+ 0x9b84, 0x1213,
+ 0x9b98, 0x1f34,
+ 0x9b99, 0x1228,
+ 0x9ba0, 0x1e92,
+ 0x9ba1, 0x1230,
+ 0x9bfb, 0x1f35,
+ 0x9c40, 0x128c,
+ 0x9c80, 0x12cb,
+ 0x9ca2, 0x1e94,
+ 0x9ca3, 0x12ee,
+ 0x9d40, 0x1348,
+ 0x9d47, 0x1f37,
+ 0x9d48, 0x1350,
+ 0x9d80, 0x1e95,
+ 0x9d81, 0x1388,
+ 0x9d8c, 0x1e96,
+ 0x9d8d, 0x1394,
+ 0x9db7, 0x1e97,
+ 0x9db8, 0x13bf,
+ 0x9df8, 0x1f38,
+ 0x9df9, 0x1400,
+ 0x9e40, 0x1404,
+ 0x9e64, 0x1e99,
+ 0x9e65, 0x1429,
+ 0x9e80, 0x1443,
+ 0x9e8b, 0x1e9b,
+ 0x9e8c, 0x144f,
+ 0x9f40, 0x14c0,
+ 0x9f80, 0x14ff,
+ 0x9f81, 0x1f39,
+ 0x9f82, 0x1501,
+ 0x9fce, 0x1e9d,
+ 0x9fcf, 0x154e,
+ 0x9fd4, 0x1f3a,
+ 0x9fd5, 0x1554,
+ 0x9ff4, 0x1f3b,
+ 0x9ff5, 0x1574,
+ 0xe040, 0x157c,
+ 0xe080, 0x15bb,
+ 0xe093, 0x1e9e,
+ 0xe094, 0x15cf,
+ 0xe0a4, 0x1e9f,
+ 0xe0a5, 0x15e0,
+ 0xe0dd, 0x1ea0,
+ 0xe0de, 0x1619,
+ 0xe140, 0x1638,
+ 0xe14a, 0x1ea1,
+ 0xe14b, 0x1643,
+ 0xe180, 0x1677,
+ 0xe1ed, 0x1ea5,
+ 0xe1ee, 0x16e5,
+ 0xe240, 0x16f4,
+ 0xe269, 0x1ea6,
+ 0xe26a, 0x171e,
+ 0xe273, 0x1ea7,
+ 0xe274, 0x1728,
+ 0xe278, 0x1f3c,
+ 0xe279, 0x172d,
+ 0xe280, 0x1733,
+ 0xe2b7, 0x1ea8,
+ 0xe2b8, 0x176b,
+ 0xe2be, 0x1f3d,
+ 0xe2bf, 0x1772,
+ 0xe2e2, 0x1ea9,
+ 0xe2e3, 0x1796,
+ 0xe2ec, 0x1eaa,
+ 0xe2ed, 0x17a0,
+ 0xe340, 0x17b0,
+ 0xe358, 0x1eab,
+ 0xe359, 0x17c9,
+ 0xe35a, 0x1eac,
+ 0xe35b, 0x17cb,
+ 0xe365, 0x1ead,
+ 0xe366, 0x17d6,
+ 0xe380, 0x17ef,
+ 0xe3c7, 0x1f3e,
+ 0xe3c8, 0x1837,
+ 0xe440, 0x186c,
+ 0xe480, 0x18ab,
+ 0xe484, 0x1eaf,
+ 0xe485, 0x18b0,
+ 0xe489, 0x1eb0,
+ 0xe48a, 0x18b5,
+ 0xe492, 0x1eb1,
+ 0xe493, 0x18be,
+ 0xe4b9, 0x1eb3,
+ 0xe4ba, 0x18e5,
+ 0xe4cb, 0x1f3f,
+ 0xe4cc, 0x18f7,
+ 0xe540, 0x1928,
+ 0xe580, 0x1967,
+ 0xe59e, 0x1f40,
+ 0xe59f, 0x1986,
+ 0xe5ba, 0x1f41,
+ 0xe5bc, 0x19a3,
+ 0xe5ed, 0x1eb8,
+ 0xe5ee, 0x19d5,
+ 0xe640, 0x19e4,
+ 0xe651, 0x1eb9,
+ 0xe652, 0x19f6,
+ 0xe680, 0x1a23,
+ 0xe686, 0x1eba,
+ 0xe687, 0x1a2a,
+ 0xe6e7, 0x1ebc,
+ 0xe6e8, 0x1a8b,
+ 0xe740, 0x1aa0,
+ 0xe76d, 0x1ebe,
+ 0xe76e, 0x1ace,
+ 0xe780, 0x1adf,
+ 0xe7a7, 0x1ec1,
+ 0xe7a8, 0x1b07,
+ 0xe7bb, 0x1ec2,
+ 0xe7bc, 0x1b1b,
+ 0xe840, 0x1b5c,
+ 0xe880, 0x1b9b,
+ 0xe8cf, 0x1ec7,
+ 0xe8d0, 0x1beb,
+ 0xe940, 0x1c18,
+ 0xe978, 0x1f43,
+ 0xe979, 0x1c51,
+ 0xe980, 0x1c57,
+ 0xe9ab, 0x1eca,
+ 0xe9ac, 0x1c83,
+ 0xe9ba, 0x1ecb,
+ 0xe9bb, 0x1c92,
+ 0xe9cc, 0x1ecc,
+ 0xe9cd, 0x1ca4,
+ 0xea40, 0x1cd4,
+ 0xea70, 0x1ecd,
+ 0xea71, 0x1f44,
+ 0xea72, 0x1d06,
+ 0xea80, 0x1d13,
+ 0xea9d, 0x1ece,
+ 0xea9e, 0x1d31,
+ 0xeaa3, 0x205c,
+ 0xec40, 0x1f45,
+ 0xec46, 0x1f48,
+ 0xec47, 0x0300,
+ 0xec48, 0x02fa,
+ 0xec49, 0x02f9,
+ 0xec4d, 0x1f49,
+ 0xec5b, 0x1db1,
+ 0xec5e, 0x1f54,
+ 0xec5f, 0x1db7,
+ 0xec60, 0x1f55,
+ 0xec63, 0x1db4,
+ 0xec66, 0x1f58,
+ 0xec70, 0x0303,
+ 0xec71, 0x1f62,
+ 0xec72, 0x0304,
+ 0xec73, 0x1f63,
+ 0xec76, 0x1f65,
+ 0xec78, 0x1da4,
+ 0xec79, 0x1da1,
+ 0xec7a, 0x1f66,
+ 0xec7b, 0x1da2,
+ 0xec7c, 0x1f67,
+ 0xec80, 0x1da6,
+ 0xec81, 0x1f6a,
+ 0xec82, 0x1da8,
+ 0xec83, 0x1dac,
+ 0xec84, 0x1f6b,
+ 0xec85, 0x1dae,
+ 0xec86, 0x1dab,
+ 0xec87, 0x1f6c,
+ 0xec89, 0x1daf,
+ 0xec8a, 0x1f6e,
+ 0xec94, 0x1f75,
+ 0xec9a, 0x1dba,
+ 0xec9b, 0x1f7b,
+ 0xec9e, 0x1f7c,
+ 0xeca7, 0x1f7d,
+ 0xecb2, 0x1f87,
+ 0xecc7, 0x1d83,
+ 0xecdb, 0x1f9b,
+ 0xecdc, 0x1d97,
+ 0xece9, 0x1f9c,
+ 0xed40, 0x1fb0,
+ 0xed64, 0x1f16,
+ 0xed68, 0x1fca,
+ 0xed6a, 0x1dc4,
+ 0xed6b, 0x1fcc,
+ 0xed6e, 0x1dc3,
+ 0xed6f, 0x1fcf,
+ 0xed74, 0x1dc2,
+ 0xed75, 0x1fd4,
+ 0xed7c, 0x1fd8,
+ 0xed80, 0x1fdb,
+ 0xed8f, 0x1fe6,
+ 0xef40, 0x1ecf,
+ 0xef42, 0x204c,
+ 0xef43, 0x2052,
+ 0xef44, 0x1ed1,
+ 0xef4e, 0x205a,
+ 0xef4f, 0x2053,
+ 0xef50, 0x2058,
+ 0xef51, 0x2055,
+ 0xef52, 0x1edb,
+ 0xef64, 0x1eee,
+ 0xef7a, 0x2048,
+ 0xef8d, 0x02e0,
+ 0xef91, 0x1ff6,
+ 0x8141, 0x1ecf,
+ 0x8143, 0x204c,
+ 0x8144, 0x2052,
+ 0x8150, 0x1ed1,
+ 0x815b, 0x1ed3,
+ 0x8160, 0x1ed6,
+ 0x8165, 0x205a,
+ 0x8166, 0x2053,
+ 0x8167, 0x2058,
+ 0x8168, 0x2055,
+ 0x8169, 0x1edb,
+ 0x829f, 0x1eee,
+ 0x82a1, 0x1eef,
+ 0x82a3, 0x1ef0,
+ 0x82a5, 0x1ef1,
+ 0x82a7, 0x1ef2,
+ 0x82c1, 0x1ef3,
+ 0x82e1, 0x1ef4,
+ 0x82e3, 0x1ef5,
+ 0x82e5, 0x1ef6,
+ 0x82ec, 0x1ef7,
+ 0x82f3, 0x2048,
+ 0x8340, 0x1ef8,
+ 0x8342, 0x1ef9,
+ 0x8344, 0x1efa,
+ 0x8346, 0x1efb,
+ 0x8348, 0x1efc,
+ 0x8362, 0x1efd,
+ 0x8383, 0x1efe,
+ 0x8385, 0x1eff,
+ 0x8387, 0x1f00,
+ 0x838e, 0x1f01,
+ 0x8395, 0x1f02,
+ 0xec78, 0x1f07,
+ 0xec79, 0x1f04,
+ 0xec7a, 0x2089,
+ 0xec7b, 0x1f05,
+ 0xec7c, 0x208a,
+ 0xec7d, 0x2093,
+ 0xec80, 0x1f09,
+ 0xec81, 0x2092,
+ 0xec82, 0x1f0b,
+ 0xec83, 0x1f0f,
+ 0xec84, 0x209c,
+ 0xec85, 0x1f11,
+ 0xec86, 0x1f0e,
+ 0xec87, 0x2098,
+ 0xec88, 0x209b,
+ 0xec89, 0x1f12,
+ 0xec8a, 0x2097,
+ 0xec8b, 0x209d,
+ 0xec8d, 0x20a6,
+ 0xec8e, 0x20a5,
+ 0xec8f, 0x20a1,
+ 0xec90, 0x20a4,
+ 0xec95, 0x2084,
+ 0xef92, 0x208d,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 japan12AddRKSJVEnc16 = {
+ 1,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee,
+ 0x00ef, 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6,
+ 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe,
+ 0x00ff, 0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106,
+ 0x0107, 0x0108, 0x0109, 0x010a, 0x010b, 0x010c, 0x010d, 0x010e,
+ 0x010f, 0x0110, 0x0111, 0x0112, 0x0113, 0x0114, 0x0115, 0x0116,
+ 0x0117, 0x0118, 0x0119, 0x011a, 0x011b, 0x011c, 0x011d, 0x011e,
+ 0x011f, 0x0120, 0x0121, 0x0122, 0x0123, 0x0124, 0x0125, 0x0126,
+ 0x0127, 0x0128, 0x0129, 0x012a, 0x012b, 0x012c, 0x012d, 0x012e,
+ 0x012f, 0x0130, 0x0131, 0x0132, 0x0133, 0x0134, 0x0135, 0x0136,
+ 0x0137, 0x0138, 0x0139, 0x013a, 0x013b, 0x013c, 0x013d, 0x013e,
+ 0x013f, 0x0140, 0x0141, 0x0142, 0x0143, 0x0144, 0x0145, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0146, 0x0147, 0x0148, 0x0149, 0x014a, 0x014b, 0x014c, 0x014d,
+ 0x014e, 0x014f, 0x0150, 0x0151, 0x0152, 0x0153, 0x0154, 0x0155,
+ 0x0156, 0x0157, 0x0158, 0x0159, 0x015a, 0x015b, 0x015c, 0x015d,
+ 0x015e, 0x015f, 0x0160, 0x0161, 0x0162, 0x0163, 0x0164, 0x0165,
+ 0x0166, 0x0167, 0x0168, 0x0169, 0x016a, 0x016b, 0x016c, 0x016d,
+ 0x016e, 0x016f, 0x0170, 0x0171, 0x0172, 0x0173, 0x0174, 0x0175,
+ 0x0176, 0x0177, 0x0178, 0x0179, 0x017a, 0x017b, 0x017c, 0x017d,
+ 0x017e, 0x017f, 0x0180, 0x0181, 0x0182, 0x0183, 0x0184, 0x0185,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ japan12AddRKSJVMap2, 692
+};
+
+static Gushort japan12AddVMap2[1380] = {
+ 0x0000, 0x0000,
+ 0x2121, 0x0279,
+ 0x2221, 0x02d7,
+ 0x223a, 0x02e5,
+ 0x224a, 0x02ed,
+ 0x225c, 0x02f4,
+ 0x2272, 0x0303,
+ 0x227e, 0x030b,
+ 0x2330, 0x030c,
+ 0x2341, 0x0316,
+ 0x2361, 0x0330,
+ 0x2421, 0x034a,
+ 0x2474, 0x1f16,
+ 0x2521, 0x039d,
+ 0x2621, 0x03f3,
+ 0x2641, 0x040b,
+ 0x2721, 0x0423,
+ 0x2751, 0x0444,
+ 0x2821, 0x1d37,
+ 0x2822, 0x1d39,
+ 0x2823, 0x1d43,
+ 0x2824, 0x1d47,
+ 0x2825, 0x1d4f,
+ 0x2826, 0x1d4b,
+ 0x2827, 0x1d53,
+ 0x2828, 0x1d63,
+ 0x2829, 0x1d5b,
+ 0x282a, 0x1d6b,
+ 0x282b, 0x1d73,
+ 0x282c, 0x1d38,
+ 0x282d, 0x1d3a,
+ 0x282e, 0x1d46,
+ 0x282f, 0x1d4a,
+ 0x2830, 0x1d52,
+ 0x2831, 0x1d4e,
+ 0x2832, 0x1d5a,
+ 0x2833, 0x1d6a,
+ 0x2834, 0x1d62,
+ 0x2835, 0x1d72,
+ 0x2836, 0x1d82,
+ 0x2837, 0x1d57,
+ 0x2838, 0x1d66,
+ 0x2839, 0x1d5f,
+ 0x283a, 0x1d6e,
+ 0x283b, 0x1d76,
+ 0x283c, 0x1d54,
+ 0x283d, 0x1d67,
+ 0x283e, 0x1d5c,
+ 0x283f, 0x1d6f,
+ 0x2840, 0x1d79,
+ 0x3021, 0x0465,
+ 0x3022, 0x1dd1,
+ 0x3023, 0x0467,
+ 0x3032, 0x1f19,
+ 0x3033, 0x0477,
+ 0x303b, 0x1dd2,
+ 0x303c, 0x0480,
+ 0x306e, 0x1dd3,
+ 0x306f, 0x04b3,
+ 0x3071, 0x1f1a,
+ 0x3072, 0x04b6,
+ 0x3073, 0x1dd4,
+ 0x3074, 0x04b8,
+ 0x307c, 0x1dd5,
+ 0x307d, 0x04c1,
+ 0x3121, 0x04c3,
+ 0x312a, 0x1dd6,
+ 0x312b, 0x04cd,
+ 0x3133, 0x1f1b,
+ 0x3134, 0x04d6,
+ 0x3135, 0x1dd7,
+ 0x3136, 0x04d8,
+ 0x3139, 0x1f1c,
+ 0x313a, 0x04dc,
+ 0x313d, 0x1dda,
+ 0x313e, 0x04e0,
+ 0x3142, 0x1ddb,
+ 0x3143, 0x04e5,
+ 0x316b, 0x1ddc,
+ 0x316c, 0x050e,
+ 0x3221, 0x0521,
+ 0x3228, 0x1ddd,
+ 0x3229, 0x0529,
+ 0x322a, 0x1dde,
+ 0x322b, 0x052b,
+ 0x3260, 0x1ddf,
+ 0x3261, 0x0561,
+ 0x3267, 0x1f1d,
+ 0x3268, 0x0568,
+ 0x327a, 0x1de0,
+ 0x327b, 0x057b,
+ 0x3321, 0x057f,
+ 0x3322, 0x1de2,
+ 0x3323, 0x0581,
+ 0x336b, 0x1de4,
+ 0x336c, 0x05ca,
+ 0x3373, 0x1de5,
+ 0x3374, 0x05d2,
+ 0x337a, 0x1de6,
+ 0x337b, 0x05d9,
+ 0x3421, 0x05dd,
+ 0x3442, 0x1de7,
+ 0x3443, 0x05ff,
+ 0x344d, 0x1de8,
+ 0x344e, 0x060a,
+ 0x3465, 0x1de9,
+ 0x3466, 0x0622,
+ 0x3521, 0x063b,
+ 0x352b, 0x1dea,
+ 0x352c, 0x0646,
+ 0x3540, 0x1deb,
+ 0x3541, 0x065b,
+ 0x3562, 0x1f1e,
+ 0x3563, 0x067d,
+ 0x3568, 0x1f1f,
+ 0x3569, 0x0683,
+ 0x3621, 0x0699,
+ 0x3622, 0x1dec,
+ 0x3623, 0x069b,
+ 0x362a, 0x1ded,
+ 0x362b, 0x06a3,
+ 0x3642, 0x1f20,
+ 0x3643, 0x06bb,
+ 0x364f, 0x1dee,
+ 0x3650, 0x06c8,
+ 0x366d, 0x1def,
+ 0x366e, 0x06e6,
+ 0x3674, 0x1df0,
+ 0x3675, 0x06ed,
+ 0x367b, 0x1df1,
+ 0x367c, 0x06f4,
+ 0x367d, 0x1df2,
+ 0x367e, 0x06f6,
+ 0x3721, 0x06f7,
+ 0x3737, 0x1df4,
+ 0x3738, 0x070e,
+ 0x3752, 0x1df7,
+ 0x3753, 0x0729,
+ 0x3771, 0x1dfa,
+ 0x3772, 0x0748,
+ 0x377d, 0x1f21,
+ 0x377e, 0x1dfc,
+ 0x3821, 0x0755,
+ 0x3834, 0x1dfd,
+ 0x3835, 0x0769,
+ 0x3841, 0x1dfe,
+ 0x3842, 0x0776,
+ 0x3921, 0x07b3,
+ 0x392b, 0x1dff,
+ 0x392c, 0x07be,
+ 0x396d, 0x1e02,
+ 0x396e, 0x0800,
+ 0x3974, 0x1e03,
+ 0x3975, 0x0807,
+ 0x3979, 0x1e04,
+ 0x397a, 0x080c,
+ 0x3a21, 0x0811,
+ 0x3a53, 0x1e05,
+ 0x3a54, 0x0844,
+ 0x3a67, 0x1e06,
+ 0x3a68, 0x0858,
+ 0x3a74, 0x1e07,
+ 0x3a75, 0x0865,
+ 0x3b21, 0x086f,
+ 0x3b27, 0x1e08,
+ 0x3b28, 0x0876,
+ 0x3b2a, 0x1e09,
+ 0x3b2b, 0x0879,
+ 0x3b2c, 0x1e0a,
+ 0x3b2d, 0x087b,
+ 0x3b39, 0x1e0b,
+ 0x3b3a, 0x0888,
+ 0x3b41, 0x1f22,
+ 0x3b42, 0x0890,
+ 0x3c21, 0x08cd,
+ 0x3c48, 0x1e0d,
+ 0x3c49, 0x08f5,
+ 0x3c5d, 0x1e0f,
+ 0x3c5f, 0x090b,
+ 0x3d21, 0x092b,
+ 0x3d2b, 0x1e11,
+ 0x3d2c, 0x0936,
+ 0x3d36, 0x1e12,
+ 0x3d37, 0x0941,
+ 0x3d6c, 0x1e13,
+ 0x3d6d, 0x0977,
+ 0x3d72, 0x1e15,
+ 0x3d74, 0x097e,
+ 0x3e21, 0x0989,
+ 0x3e25, 0x1e17,
+ 0x3e26, 0x098e,
+ 0x3e33, 0x1e18,
+ 0x3e34, 0x099c,
+ 0x3e55, 0x1e1a,
+ 0x3e56, 0x09be,
+ 0x3e5f, 0x1e1b,
+ 0x3e60, 0x09c8,
+ 0x3e64, 0x1e1c,
+ 0x3e65, 0x09cd,
+ 0x3f21, 0x09e7,
+ 0x3f2a, 0x1e1d,
+ 0x3f2b, 0x09f1,
+ 0x3f59, 0x1f23,
+ 0x3f5a, 0x0a20,
+ 0x3f60, 0x1e1f,
+ 0x3f61, 0x0a27,
+ 0x4021, 0x0a45,
+ 0x4022, 0x1e21,
+ 0x4023, 0x0a47,
+ 0x4066, 0x1e23,
+ 0x4067, 0x0a8b,
+ 0x4071, 0x1e24,
+ 0x4072, 0x0a96,
+ 0x4079, 0x1e26,
+ 0x407a, 0x1f24,
+ 0x407b, 0x0a9f,
+ 0x407c, 0x1f25,
+ 0x407e, 0x0aa2,
+ 0x4121, 0x0aa3,
+ 0x4127, 0x1e28,
+ 0x4128, 0x0aaa,
+ 0x4139, 0x1e29,
+ 0x413a, 0x0abc,
+ 0x414c, 0x1e2a,
+ 0x414d, 0x0acf,
+ 0x414f, 0x1e2b,
+ 0x4150, 0x0ad2,
+ 0x415f, 0x1e2c,
+ 0x4160, 0x0ae2,
+ 0x4169, 0x1e2d,
+ 0x416a, 0x0aec,
+ 0x4221, 0x0b01,
+ 0x4237, 0x1f27,
+ 0x4238, 0x0b18,
+ 0x423d, 0x1e2e,
+ 0x423e, 0x0b1e,
+ 0x424d, 0x1e2f,
+ 0x424e, 0x0b2e,
+ 0x425c, 0x1e30,
+ 0x425d, 0x0b3d,
+ 0x4263, 0x1e31,
+ 0x4264, 0x0b44,
+ 0x426f, 0x1e32,
+ 0x4270, 0x0b50,
+ 0x427d, 0x1e35,
+ 0x427e, 0x0b5e,
+ 0x4321, 0x0b5f,
+ 0x4327, 0x1e36,
+ 0x4328, 0x0b66,
+ 0x4329, 0x1e37,
+ 0x432a, 0x0b68,
+ 0x432d, 0x1e39,
+ 0x432f, 0x0b6d,
+ 0x433d, 0x1e3b,
+ 0x433e, 0x0b7c,
+ 0x4370, 0x1e3c,
+ 0x4371, 0x0baf,
+ 0x4375, 0x1e3d,
+ 0x4376, 0x0bb4,
+ 0x437c, 0x1e3e,
+ 0x437d, 0x0bbb,
+ 0x4421, 0x0bbd,
+ 0x443d, 0x1e3f,
+ 0x443e, 0x0bda,
+ 0x4448, 0x1e40,
+ 0x4449, 0x0be5,
+ 0x444a, 0x1e41,
+ 0x444b, 0x0be7,
+ 0x444f, 0x1e43,
+ 0x4450, 0x0bec,
+ 0x4521, 0x0c1b,
+ 0x4522, 0x1e44,
+ 0x4523, 0x0c1d,
+ 0x4527, 0x1e45,
+ 0x4528, 0x0c22,
+ 0x452e, 0x1e46,
+ 0x452f, 0x0c29,
+ 0x4536, 0x1e47,
+ 0x4537, 0x0c31,
+ 0x453f, 0x1e48,
+ 0x4540, 0x0c3a,
+ 0x4548, 0x1e49,
+ 0x4549, 0x0c43,
+ 0x454b, 0x1e4a,
+ 0x454c, 0x0c46,
+ 0x4551, 0x1f28,
+ 0x4552, 0x1e4c,
+ 0x4553, 0x0c4d,
+ 0x4564, 0x1e4d,
+ 0x4565, 0x0c5f,
+ 0x4578, 0x1e4e,
+ 0x4579, 0x0c73,
+ 0x4621, 0x0c79,
+ 0x4642, 0x1e50,
+ 0x4643, 0x0c9b,
+ 0x4654, 0x1e51,
+ 0x4655, 0x0cad,
+ 0x465b, 0x1e53,
+ 0x465c, 0x0cb4,
+ 0x4666, 0x1e56,
+ 0x4668, 0x0cc0,
+ 0x466a, 0x1e58,
+ 0x466b, 0x0cc3,
+ 0x4676, 0x1ec0,
+ 0x4677, 0x0ccf,
+ 0x4721, 0x0cd7,
+ 0x4729, 0x1e59,
+ 0x472a, 0x1f29,
+ 0x472b, 0x0ce1,
+ 0x4739, 0x1e5a,
+ 0x473a, 0x0cf0,
+ 0x4757, 0x1e5b,
+ 0x4758, 0x0d0e,
+ 0x4767, 0x1e5c,
+ 0x4768, 0x0d1e,
+ 0x4769, 0x1e5d,
+ 0x476a, 0x0d20,
+ 0x476d, 0x1e5e,
+ 0x476e, 0x0d24,
+ 0x4821, 0x0d35,
+ 0x4824, 0x1e5f,
+ 0x4825, 0x0d39,
+ 0x482e, 0x1e60,
+ 0x482f, 0x0d43,
+ 0x4830, 0x1e61,
+ 0x4831, 0x0d45,
+ 0x4840, 0x1f2a,
+ 0x4841, 0x0d55,
+ 0x4854, 0x1e62,
+ 0x4855, 0x0d69,
+ 0x4875, 0x1e64,
+ 0x4876, 0x0d8a,
+ 0x4921, 0x0d93,
+ 0x4922, 0x1e65,
+ 0x4924, 0x0d96,
+ 0x492f, 0x1e67,
+ 0x4930, 0x0da2,
+ 0x4932, 0x1e68,
+ 0x4933, 0x0da5,
+ 0x4935, 0x1e69,
+ 0x4936, 0x0da8,
+ 0x4940, 0x1e6a,
+ 0x4941, 0x0db3,
+ 0x494e, 0x1e6b,
+ 0x494f, 0x0dc1,
+ 0x4a21, 0x0df1,
+ 0x4a43, 0x1e6d,
+ 0x4a44, 0x0e14,
+ 0x4a4d, 0x1e6e,
+ 0x4a4e, 0x0e1e,
+ 0x4a53, 0x1f2b,
+ 0x4a54, 0x0e24,
+ 0x4a5a, 0x1e6f,
+ 0x4a5b, 0x0e2b,
+ 0x4a79, 0x1e70,
+ 0x4a7a, 0x0e4a,
+ 0x4b21, 0x0e4f,
+ 0x4b29, 0x1e72,
+ 0x4b2a, 0x0e58,
+ 0x4b4b, 0x1e73,
+ 0x4b4c, 0x0e7a,
+ 0x4b70, 0x1e74,
+ 0x4b71, 0x0e9f,
+ 0x4b78, 0x1f2c,
+ 0x4b79, 0x0ea7,
+ 0x4c21, 0x0ead,
+ 0x4c4d, 0x1e75,
+ 0x4c4e, 0x0eda,
+ 0x4c59, 0x1e76,
+ 0x4c5a, 0x0ee6,
+ 0x4c5f, 0x1e77,
+ 0x4c60, 0x0eec,
+ 0x4c62, 0x1e78,
+ 0x4c63, 0x0eef,
+ 0x4c7a, 0x1e79,
+ 0x4c7b, 0x0f07,
+ 0x4c7c, 0x1e7a,
+ 0x4c7d, 0x0f09,
+ 0x4d21, 0x0f0b,
+ 0x4d32, 0x1e7c,
+ 0x4d33, 0x0f1d,
+ 0x4d50, 0x1e7d,
+ 0x4d51, 0x0f3b,
+ 0x4d54, 0x1e7e,
+ 0x4d55, 0x0f3f,
+ 0x4d69, 0x1e7f,
+ 0x4d6a, 0x0f54,
+ 0x4e21, 0x0f69,
+ 0x4e7a, 0x1e81,
+ 0x4e7c, 0x1f2d,
+ 0x4e7d, 0x0fc5,
+ 0x4f21, 0x1e83,
+ 0x4f22, 0x0fc8,
+ 0x4f31, 0x1e84,
+ 0x4f32, 0x0fd8,
+ 0x4f39, 0x1e85,
+ 0x4f3a, 0x0fe0,
+ 0x5021, 0x0ffa,
+ 0x5121, 0x1058,
+ 0x5122, 0x1f2e,
+ 0x5123, 0x105a,
+ 0x513d, 0x1e86,
+ 0x513e, 0x1075,
+ 0x514d, 0x1e89,
+ 0x514e, 0x1085,
+ 0x5221, 0x10b6,
+ 0x5238, 0x1f2f,
+ 0x5239, 0x10ce,
+ 0x5321, 0x1114,
+ 0x5330, 0x1e8a,
+ 0x5331, 0x1124,
+ 0x533a, 0x1e8b,
+ 0x533b, 0x112e,
+ 0x5348, 0x1f30,
+ 0x5349, 0x113c,
+ 0x535e, 0x1e8d,
+ 0x535f, 0x1152,
+ 0x536b, 0x1e8e,
+ 0x536c, 0x1f31,
+ 0x536d, 0x1160,
+ 0x5421, 0x1172,
+ 0x5444, 0x1e8f,
+ 0x5445, 0x1f32,
+ 0x5446, 0x1197,
+ 0x546c, 0x1f33,
+ 0x546d, 0x11be,
+ 0x5521, 0x11d0,
+ 0x553d, 0x1e90,
+ 0x553e, 0x11ed,
+ 0x5563, 0x1e91,
+ 0x5564, 0x1213,
+ 0x5578, 0x1f34,
+ 0x5579, 0x1228,
+ 0x5621, 0x122e,
+ 0x5622, 0x1e92,
+ 0x5623, 0x1230,
+ 0x567d, 0x1f35,
+ 0x5721, 0x128c,
+ 0x5821, 0x12ea,
+ 0x5824, 0x1e94,
+ 0x5825, 0x12ee,
+ 0x5921, 0x1348,
+ 0x5928, 0x1f37,
+ 0x5929, 0x1350,
+ 0x5960, 0x1e95,
+ 0x5961, 0x1388,
+ 0x596c, 0x1e96,
+ 0x596d, 0x1394,
+ 0x5a21, 0x13a6,
+ 0x5a39, 0x1e97,
+ 0x5a3a, 0x13bf,
+ 0x5a7a, 0x1f38,
+ 0x5a7b, 0x1400,
+ 0x5b21, 0x1404,
+ 0x5b45, 0x1e99,
+ 0x5b46, 0x1429,
+ 0x5b6b, 0x1e9b,
+ 0x5b6c, 0x144f,
+ 0x5c21, 0x1462,
+ 0x5d21, 0x14c0,
+ 0x5d61, 0x1f39,
+ 0x5d62, 0x1501,
+ 0x5e21, 0x151e,
+ 0x5e50, 0x1e9d,
+ 0x5e51, 0x154e,
+ 0x5e56, 0x1f3a,
+ 0x5e57, 0x1554,
+ 0x5e76, 0x1f3b,
+ 0x5e77, 0x1574,
+ 0x5f21, 0x157c,
+ 0x5f73, 0x1e9e,
+ 0x5f74, 0x15cf,
+ 0x6021, 0x15da,
+ 0x6026, 0x1e9f,
+ 0x6027, 0x15e0,
+ 0x605f, 0x1ea0,
+ 0x6060, 0x1619,
+ 0x6121, 0x1638,
+ 0x612b, 0x1ea1,
+ 0x612c, 0x1643,
+ 0x6221, 0x1696,
+ 0x626f, 0x1ea5,
+ 0x6270, 0x16e5,
+ 0x6321, 0x16f4,
+ 0x634a, 0x1ea6,
+ 0x634b, 0x171e,
+ 0x6354, 0x1ea7,
+ 0x6355, 0x1728,
+ 0x6359, 0x1f3c,
+ 0x635a, 0x172d,
+ 0x6421, 0x1752,
+ 0x6439, 0x1ea8,
+ 0x643a, 0x176b,
+ 0x6440, 0x1f3d,
+ 0x6441, 0x1772,
+ 0x6464, 0x1ea9,
+ 0x6465, 0x1796,
+ 0x646e, 0x1eaa,
+ 0x646f, 0x17a0,
+ 0x6521, 0x17b0,
+ 0x6539, 0x1eab,
+ 0x653a, 0x17c9,
+ 0x653b, 0x1eac,
+ 0x653c, 0x17cb,
+ 0x6546, 0x1ead,
+ 0x6547, 0x17d6,
+ 0x6621, 0x180e,
+ 0x6649, 0x1f3e,
+ 0x664a, 0x1837,
+ 0x6721, 0x186c,
+ 0x6764, 0x1eaf,
+ 0x6765, 0x18b0,
+ 0x6769, 0x1eb0,
+ 0x676a, 0x18b5,
+ 0x6772, 0x1eb1,
+ 0x6773, 0x18be,
+ 0x6821, 0x18ca,
+ 0x683b, 0x1eb3,
+ 0x683c, 0x18e5,
+ 0x684d, 0x1f3f,
+ 0x684e, 0x18f7,
+ 0x6921, 0x1928,
+ 0x697e, 0x1f40,
+ 0x6a21, 0x1986,
+ 0x6a3c, 0x1f41,
+ 0x6a3e, 0x19a3,
+ 0x6a6f, 0x1eb8,
+ 0x6a70, 0x19d5,
+ 0x6b21, 0x19e4,
+ 0x6b32, 0x1eb9,
+ 0x6b33, 0x19f6,
+ 0x6b66, 0x1eba,
+ 0x6b67, 0x1a2a,
+ 0x6c21, 0x1a42,
+ 0x6c69, 0x1ebc,
+ 0x6c6a, 0x1a8b,
+ 0x6d21, 0x1aa0,
+ 0x6d4e, 0x1ebe,
+ 0x6d4f, 0x1ace,
+ 0x6e21, 0x1afe,
+ 0x6e29, 0x1ec1,
+ 0x6e2a, 0x1b07,
+ 0x6e3d, 0x1ec2,
+ 0x6e3e, 0x1b1b,
+ 0x6f21, 0x1b5c,
+ 0x7021, 0x1bba,
+ 0x7051, 0x1ec7,
+ 0x7052, 0x1beb,
+ 0x7121, 0x1c18,
+ 0x7159, 0x1f43,
+ 0x715a, 0x1c51,
+ 0x7221, 0x1c76,
+ 0x722d, 0x1eca,
+ 0x722e, 0x1c83,
+ 0x723c, 0x1ecb,
+ 0x723d, 0x1c92,
+ 0x724e, 0x1ecc,
+ 0x724f, 0x1ca4,
+ 0x7321, 0x1cd4,
+ 0x7351, 0x1ecd,
+ 0x7352, 0x1f44,
+ 0x7353, 0x1d06,
+ 0x737d, 0x1ece,
+ 0x737e, 0x1d31,
+ 0x7421, 0x1d32,
+ 0x7425, 0x205c,
+ 0x7721, 0x1f45,
+ 0x7727, 0x1f48,
+ 0x7728, 0x0300,
+ 0x7729, 0x02fa,
+ 0x772a, 0x02f9,
+ 0x772e, 0x1f49,
+ 0x773c, 0x1db1,
+ 0x773f, 0x1f54,
+ 0x7740, 0x1db7,
+ 0x7741, 0x1f55,
+ 0x7744, 0x1db4,
+ 0x7747, 0x1f58,
+ 0x7751, 0x0303,
+ 0x7752, 0x1f62,
+ 0x7753, 0x0304,
+ 0x7754, 0x1f63,
+ 0x7757, 0x1f65,
+ 0x7759, 0x1da4,
+ 0x775a, 0x1da1,
+ 0x775b, 0x1f66,
+ 0x775c, 0x1da2,
+ 0x775d, 0x1f67,
+ 0x7760, 0x1da6,
+ 0x7761, 0x1f6a,
+ 0x7762, 0x1da8,
+ 0x7763, 0x1dac,
+ 0x7764, 0x1f6b,
+ 0x7765, 0x1dae,
+ 0x7766, 0x1dab,
+ 0x7767, 0x1f6c,
+ 0x7769, 0x1daf,
+ 0x776a, 0x1f6e,
+ 0x7774, 0x1f75,
+ 0x777a, 0x1dba,
+ 0x777b, 0x1f7b,
+ 0x777e, 0x1f7c,
+ 0x7829, 0x1f7d,
+ 0x7834, 0x1f87,
+ 0x7849, 0x1d83,
+ 0x785d, 0x1f9b,
+ 0x785e, 0x1d97,
+ 0x786b, 0x1f9c,
+ 0x7921, 0x1fb0,
+ 0x7945, 0x1f16,
+ 0x7949, 0x1fca,
+ 0x794b, 0x1dc4,
+ 0x794c, 0x1fcc,
+ 0x794f, 0x1dc3,
+ 0x7950, 0x1fcf,
+ 0x7955, 0x1dc2,
+ 0x7956, 0x1fd4,
+ 0x795d, 0x1fd8,
+ 0x796f, 0x1fe6,
+ 0x7d21, 0x1ecf,
+ 0x7d23, 0x204c,
+ 0x7d24, 0x2052,
+ 0x7d25, 0x1ed1,
+ 0x7d2f, 0x205a,
+ 0x7d30, 0x2053,
+ 0x7d31, 0x2058,
+ 0x7d32, 0x2055,
+ 0x7d33, 0x1edb,
+ 0x7d45, 0x1eee,
+ 0x7d5b, 0x2048,
+ 0x7d6d, 0x02e0,
+ 0x7d71, 0x1ff6,
+ 0x2122, 0x1ecf,
+ 0x2124, 0x204c,
+ 0x2125, 0x2052,
+ 0x2131, 0x1ed1,
+ 0x213c, 0x1ed3,
+ 0x2141, 0x1ed6,
+ 0x2146, 0x205a,
+ 0x2147, 0x2053,
+ 0x2148, 0x2058,
+ 0x2149, 0x2055,
+ 0x214a, 0x1edb,
+ 0x2421, 0x1eee,
+ 0x2423, 0x1eef,
+ 0x2425, 0x1ef0,
+ 0x2427, 0x1ef1,
+ 0x2429, 0x1ef2,
+ 0x2443, 0x1ef3,
+ 0x2463, 0x1ef4,
+ 0x2465, 0x1ef5,
+ 0x2467, 0x1ef6,
+ 0x246e, 0x1ef7,
+ 0x2475, 0x2048,
+ 0x2521, 0x1ef8,
+ 0x2523, 0x1ef9,
+ 0x2525, 0x1efa,
+ 0x2527, 0x1efb,
+ 0x2529, 0x1efc,
+ 0x2543, 0x1efd,
+ 0x2563, 0x1efe,
+ 0x2565, 0x1eff,
+ 0x2567, 0x1f00,
+ 0x256e, 0x1f01,
+ 0x2575, 0x1f02,
+ 0x7759, 0x1f07,
+ 0x775a, 0x1f04,
+ 0x775b, 0x2089,
+ 0x775c, 0x1f05,
+ 0x775d, 0x208a,
+ 0x775e, 0x2093,
+ 0x7760, 0x1f09,
+ 0x7761, 0x2092,
+ 0x7762, 0x1f0b,
+ 0x7763, 0x1f0f,
+ 0x7764, 0x209c,
+ 0x7765, 0x1f11,
+ 0x7766, 0x1f0e,
+ 0x7767, 0x2098,
+ 0x7768, 0x209b,
+ 0x7769, 0x1f12,
+ 0x776a, 0x2097,
+ 0x776b, 0x209d,
+ 0x776d, 0x20a6,
+ 0x776e, 0x20a5,
+ 0x776f, 0x20a1,
+ 0x7770, 0x20a4,
+ 0x7775, 0x2084,
+ 0x7d72, 0x208d,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 japan12AddVEnc16 = {
+ 1,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ japan12AddVMap2, 690
+};
+
+static Gushort japan12AdobeJapan10Map2[70] = {
+ 0x0000, 0x0000,
+ 0x0000, 0x0000,
+ 0x0100, 0x0100,
+ 0x0200, 0x0200,
+ 0x0300, 0x0300,
+ 0x0400, 0x0400,
+ 0x0500, 0x0500,
+ 0x0600, 0x0600,
+ 0x0700, 0x0700,
+ 0x0800, 0x0800,
+ 0x0900, 0x0900,
+ 0x0a00, 0x0a00,
+ 0x0b00, 0x0b00,
+ 0x0c00, 0x0c00,
+ 0x0d00, 0x0d00,
+ 0x0e00, 0x0e00,
+ 0x0f00, 0x0f00,
+ 0x1000, 0x1000,
+ 0x1100, 0x1100,
+ 0x1200, 0x1200,
+ 0x1300, 0x1300,
+ 0x1400, 0x1400,
+ 0x1500, 0x1500,
+ 0x1600, 0x1600,
+ 0x1700, 0x1700,
+ 0x1800, 0x1800,
+ 0x1900, 0x1900,
+ 0x1a00, 0x1a00,
+ 0x1b00, 0x1b00,
+ 0x1c00, 0x1c00,
+ 0x1d00, 0x1d00,
+ 0x1e00, 0x1e00,
+ 0x1f00, 0x1f00,
+ 0x2000, 0x2000,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 japan12AdobeJapan10Enc16 = {
+ 0,
+ { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ japan12AdobeJapan10Map2, 35
+};
+
+static Gushort japan12AdobeJapan11Map2[70] = {
+ 0x0000, 0x0000,
+ 0x0000, 0x0000,
+ 0x0100, 0x0100,
+ 0x0200, 0x0200,
+ 0x0300, 0x0300,
+ 0x0400, 0x0400,
+ 0x0500, 0x0500,
+ 0x0600, 0x0600,
+ 0x0700, 0x0700,
+ 0x0800, 0x0800,
+ 0x0900, 0x0900,
+ 0x0a00, 0x0a00,
+ 0x0b00, 0x0b00,
+ 0x0c00, 0x0c00,
+ 0x0d00, 0x0d00,
+ 0x0e00, 0x0e00,
+ 0x0f00, 0x0f00,
+ 0x1000, 0x1000,
+ 0x1100, 0x1100,
+ 0x1200, 0x1200,
+ 0x1300, 0x1300,
+ 0x1400, 0x1400,
+ 0x1500, 0x1500,
+ 0x1600, 0x1600,
+ 0x1700, 0x1700,
+ 0x1800, 0x1800,
+ 0x1900, 0x1900,
+ 0x1a00, 0x1a00,
+ 0x1b00, 0x1b00,
+ 0x1c00, 0x1c00,
+ 0x1d00, 0x1d00,
+ 0x1e00, 0x1e00,
+ 0x1f00, 0x1f00,
+ 0x2000, 0x2000,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 japan12AdobeJapan11Enc16 = {
+ 0,
+ { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ japan12AdobeJapan11Map2, 35
+};
+
+static Gushort japan12AdobeJapan12Map2[74] = {
+ 0x0000, 0x0000,
+ 0x0000, 0x0000,
+ 0x0100, 0x0100,
+ 0x0200, 0x0200,
+ 0x0300, 0x0300,
+ 0x0400, 0x0400,
+ 0x0500, 0x0500,
+ 0x0600, 0x0600,
+ 0x0700, 0x0700,
+ 0x0800, 0x0800,
+ 0x0900, 0x0900,
+ 0x0a00, 0x0a00,
+ 0x0b00, 0x0b00,
+ 0x0c00, 0x0c00,
+ 0x0d00, 0x0d00,
+ 0x0e00, 0x0e00,
+ 0x0f00, 0x0f00,
+ 0x1000, 0x1000,
+ 0x1100, 0x1100,
+ 0x1200, 0x1200,
+ 0x1300, 0x1300,
+ 0x1400, 0x1400,
+ 0x1500, 0x1500,
+ 0x1600, 0x1600,
+ 0x1700, 0x1700,
+ 0x1800, 0x1800,
+ 0x1900, 0x1900,
+ 0x1a00, 0x1a00,
+ 0x1b00, 0x1b00,
+ 0x1c00, 0x1c00,
+ 0x1d00, 0x1d00,
+ 0x1e00, 0x1e00,
+ 0x1f00, 0x1f00,
+ 0x2000, 0x2000,
+ 0x2100, 0x2100,
+ 0x2200, 0x2200,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 japan12AdobeJapan12Enc16 = {
+ 0,
+ { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ japan12AdobeJapan12Map2, 37
+};
+
+static Gushort japan12EUCHMap2[242] = {
+ 0x0000, 0x0000,
+ 0x8ea0, 0x0146,
+ 0xa1a1, 0x0279,
+ 0xa2a1, 0x02d7,
+ 0xa2ba, 0x02e5,
+ 0xa2ca, 0x02ed,
+ 0xa2dc, 0x02f4,
+ 0xa2f2, 0x0303,
+ 0xa2fe, 0x030b,
+ 0xa3b0, 0x030c,
+ 0xa3c1, 0x0316,
+ 0xa3e1, 0x0330,
+ 0xa4a1, 0x034a,
+ 0xa5a1, 0x039d,
+ 0xa6a1, 0x03f3,
+ 0xa6c1, 0x040b,
+ 0xa7a1, 0x0423,
+ 0xa7d1, 0x0444,
+ 0xa8a1, 0x1d37,
+ 0xa8a2, 0x1d39,
+ 0xa8a3, 0x1d43,
+ 0xa8a4, 0x1d47,
+ 0xa8a5, 0x1d4f,
+ 0xa8a6, 0x1d4b,
+ 0xa8a7, 0x1d53,
+ 0xa8a8, 0x1d63,
+ 0xa8a9, 0x1d5b,
+ 0xa8aa, 0x1d6b,
+ 0xa8ab, 0x1d73,
+ 0xa8ac, 0x1d38,
+ 0xa8ad, 0x1d3a,
+ 0xa8ae, 0x1d46,
+ 0xa8af, 0x1d4a,
+ 0xa8b0, 0x1d52,
+ 0xa8b1, 0x1d4e,
+ 0xa8b2, 0x1d5a,
+ 0xa8b3, 0x1d6a,
+ 0xa8b4, 0x1d62,
+ 0xa8b5, 0x1d72,
+ 0xa8b6, 0x1d82,
+ 0xa8b7, 0x1d57,
+ 0xa8b8, 0x1d66,
+ 0xa8b9, 0x1d5f,
+ 0xa8ba, 0x1d6e,
+ 0xa8bb, 0x1d76,
+ 0xa8bc, 0x1d54,
+ 0xa8bd, 0x1d67,
+ 0xa8be, 0x1d5c,
+ 0xa8bf, 0x1d6f,
+ 0xa8c0, 0x1d79,
+ 0xb0a1, 0x0465,
+ 0xb1a1, 0x04c3,
+ 0xb2a1, 0x0521,
+ 0xb3a1, 0x057f,
+ 0xb4a1, 0x05dd,
+ 0xb5a1, 0x063b,
+ 0xb6a1, 0x0699,
+ 0xb7a1, 0x06f7,
+ 0xb8a1, 0x0755,
+ 0xb9a1, 0x07b3,
+ 0xbaa1, 0x0811,
+ 0xbba1, 0x086f,
+ 0xbca1, 0x08cd,
+ 0xbda1, 0x092b,
+ 0xbea1, 0x0989,
+ 0xbfa1, 0x09e7,
+ 0xc0a1, 0x0a45,
+ 0xc1a1, 0x0aa3,
+ 0xc2a1, 0x0b01,
+ 0xc3a1, 0x0b5f,
+ 0xc4a1, 0x0bbd,
+ 0xc5a1, 0x0c1b,
+ 0xc6a1, 0x0c79,
+ 0xc7a1, 0x0cd7,
+ 0xc8a1, 0x0d35,
+ 0xc9a1, 0x0d93,
+ 0xcaa1, 0x0df1,
+ 0xcba1, 0x0e4f,
+ 0xcca1, 0x0ead,
+ 0xcda1, 0x0f0b,
+ 0xcea1, 0x0f69,
+ 0xcfa1, 0x0fc7,
+ 0xd0a1, 0x0ffa,
+ 0xd1a1, 0x1058,
+ 0xd2a1, 0x10b6,
+ 0xd3a1, 0x1114,
+ 0xd4a1, 0x1172,
+ 0xd5a1, 0x11d0,
+ 0xd6a1, 0x122e,
+ 0xd7a1, 0x128c,
+ 0xd8a1, 0x12ea,
+ 0xd9a1, 0x1348,
+ 0xdaa1, 0x13a6,
+ 0xdba1, 0x1404,
+ 0xdca1, 0x1462,
+ 0xdda1, 0x14c0,
+ 0xdea1, 0x151e,
+ 0xdfa1, 0x157c,
+ 0xe0a1, 0x15da,
+ 0xe1a1, 0x1638,
+ 0xe2a1, 0x1696,
+ 0xe3a1, 0x16f4,
+ 0xe4a1, 0x1752,
+ 0xe5a1, 0x17b0,
+ 0xe6a1, 0x180e,
+ 0xe7a1, 0x186c,
+ 0xe8a1, 0x18ca,
+ 0xe9a1, 0x1928,
+ 0xeaa1, 0x1986,
+ 0xeba1, 0x19e4,
+ 0xeca1, 0x1a42,
+ 0xeda1, 0x1aa0,
+ 0xeea1, 0x1afe,
+ 0xefa1, 0x1b5c,
+ 0xf0a1, 0x1bba,
+ 0xf1a1, 0x1c18,
+ 0xf2a1, 0x1c76,
+ 0xf3a1, 0x1cd4,
+ 0xf4a1, 0x1d32,
+ 0xf4a5, 0x205c,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 japan12EUCHEnc16 = {
+ 0,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee,
+ 0x00ef, 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6,
+ 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe,
+ 0x00ff, 0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106,
+ 0x0107, 0x0108, 0x0109, 0x010a, 0x010b, 0x010c, 0x010d, 0x010e,
+ 0x010f, 0x0110, 0x0111, 0x0112, 0x0113, 0x0114, 0x0115, 0x0116,
+ 0x0117, 0x0118, 0x0119, 0x011a, 0x011b, 0x011c, 0x011d, 0x011e,
+ 0x011f, 0x0120, 0x0121, 0x0122, 0x0123, 0x0124, 0x0125, 0x0126,
+ 0x0127, 0x0128, 0x0129, 0x012a, 0x012b, 0x012c, 0x012d, 0x012e,
+ 0x012f, 0x0130, 0x0131, 0x0132, 0x0133, 0x0134, 0x0135, 0x0136,
+ 0x0137, 0x0138, 0x0139, 0x013a, 0x013b, 0x013c, 0x013d, 0x013e,
+ 0x013f, 0x0140, 0x0141, 0x0142, 0x0143, 0x0144, 0x0145, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ japan12EUCHMap2, 121
+};
+
+static Gushort japan12EUCVMap2[296] = {
+ 0x0000, 0x0000,
+ 0x8ea0, 0x0146,
+ 0xa1a1, 0x0279,
+ 0xa2a1, 0x02d7,
+ 0xa2ba, 0x02e5,
+ 0xa2ca, 0x02ed,
+ 0xa2dc, 0x02f4,
+ 0xa2f2, 0x0303,
+ 0xa2fe, 0x030b,
+ 0xa3b0, 0x030c,
+ 0xa3c1, 0x0316,
+ 0xa3e1, 0x0330,
+ 0xa4a1, 0x034a,
+ 0xa5a1, 0x039d,
+ 0xa6a1, 0x03f3,
+ 0xa6c1, 0x040b,
+ 0xa7a1, 0x0423,
+ 0xa7d1, 0x0444,
+ 0xa8a1, 0x1d37,
+ 0xa8a2, 0x1d39,
+ 0xa8a3, 0x1d43,
+ 0xa8a4, 0x1d47,
+ 0xa8a5, 0x1d4f,
+ 0xa8a6, 0x1d4b,
+ 0xa8a7, 0x1d53,
+ 0xa8a8, 0x1d63,
+ 0xa8a9, 0x1d5b,
+ 0xa8aa, 0x1d6b,
+ 0xa8ab, 0x1d73,
+ 0xa8ac, 0x1d38,
+ 0xa8ad, 0x1d3a,
+ 0xa8ae, 0x1d46,
+ 0xa8af, 0x1d4a,
+ 0xa8b0, 0x1d52,
+ 0xa8b1, 0x1d4e,
+ 0xa8b2, 0x1d5a,
+ 0xa8b3, 0x1d6a,
+ 0xa8b4, 0x1d62,
+ 0xa8b5, 0x1d72,
+ 0xa8b6, 0x1d82,
+ 0xa8b7, 0x1d57,
+ 0xa8b8, 0x1d66,
+ 0xa8b9, 0x1d5f,
+ 0xa8ba, 0x1d6e,
+ 0xa8bb, 0x1d76,
+ 0xa8bc, 0x1d54,
+ 0xa8bd, 0x1d67,
+ 0xa8be, 0x1d5c,
+ 0xa8bf, 0x1d6f,
+ 0xa8c0, 0x1d79,
+ 0xb0a1, 0x0465,
+ 0xb1a1, 0x04c3,
+ 0xb2a1, 0x0521,
+ 0xb3a1, 0x057f,
+ 0xb4a1, 0x05dd,
+ 0xb5a1, 0x063b,
+ 0xb6a1, 0x0699,
+ 0xb7a1, 0x06f7,
+ 0xb8a1, 0x0755,
+ 0xb9a1, 0x07b3,
+ 0xbaa1, 0x0811,
+ 0xbba1, 0x086f,
+ 0xbca1, 0x08cd,
+ 0xbda1, 0x092b,
+ 0xbea1, 0x0989,
+ 0xbfa1, 0x09e7,
+ 0xc0a1, 0x0a45,
+ 0xc1a1, 0x0aa3,
+ 0xc2a1, 0x0b01,
+ 0xc3a1, 0x0b5f,
+ 0xc4a1, 0x0bbd,
+ 0xc5a1, 0x0c1b,
+ 0xc6a1, 0x0c79,
+ 0xc7a1, 0x0cd7,
+ 0xc8a1, 0x0d35,
+ 0xc9a1, 0x0d93,
+ 0xcaa1, 0x0df1,
+ 0xcba1, 0x0e4f,
+ 0xcca1, 0x0ead,
+ 0xcda1, 0x0f0b,
+ 0xcea1, 0x0f69,
+ 0xcfa1, 0x0fc7,
+ 0xd0a1, 0x0ffa,
+ 0xd1a1, 0x1058,
+ 0xd2a1, 0x10b6,
+ 0xd3a1, 0x1114,
+ 0xd4a1, 0x1172,
+ 0xd5a1, 0x11d0,
+ 0xd6a1, 0x122e,
+ 0xd7a1, 0x128c,
+ 0xd8a1, 0x12ea,
+ 0xd9a1, 0x1348,
+ 0xdaa1, 0x13a6,
+ 0xdba1, 0x1404,
+ 0xdca1, 0x1462,
+ 0xdda1, 0x14c0,
+ 0xdea1, 0x151e,
+ 0xdfa1, 0x157c,
+ 0xe0a1, 0x15da,
+ 0xe1a1, 0x1638,
+ 0xe2a1, 0x1696,
+ 0xe3a1, 0x16f4,
+ 0xe4a1, 0x1752,
+ 0xe5a1, 0x17b0,
+ 0xe6a1, 0x180e,
+ 0xe7a1, 0x186c,
+ 0xe8a1, 0x18ca,
+ 0xe9a1, 0x1928,
+ 0xeaa1, 0x1986,
+ 0xeba1, 0x19e4,
+ 0xeca1, 0x1a42,
+ 0xeda1, 0x1aa0,
+ 0xeea1, 0x1afe,
+ 0xefa1, 0x1b5c,
+ 0xf0a1, 0x1bba,
+ 0xf1a1, 0x1c18,
+ 0xf2a1, 0x1c76,
+ 0xf3a1, 0x1cd4,
+ 0xf4a1, 0x1d32,
+ 0xf4a5, 0x205c,
+ 0xa1a2, 0x1ecf,
+ 0xa1b1, 0x1ed1,
+ 0xa1bc, 0x1ed3,
+ 0xa1c1, 0x1ed6,
+ 0xa1ca, 0x1edb,
+ 0xa1e1, 0x1eed,
+ 0xa4a1, 0x1eee,
+ 0xa4a3, 0x1eef,
+ 0xa4a5, 0x1ef0,
+ 0xa4a7, 0x1ef1,
+ 0xa4a9, 0x1ef2,
+ 0xa4c3, 0x1ef3,
+ 0xa4e3, 0x1ef4,
+ 0xa4e5, 0x1ef5,
+ 0xa4e7, 0x1ef6,
+ 0xa4ee, 0x1ef7,
+ 0xa5a1, 0x1ef8,
+ 0xa5a3, 0x1ef9,
+ 0xa5a5, 0x1efa,
+ 0xa5a7, 0x1efb,
+ 0xa5a9, 0x1efc,
+ 0xa5c3, 0x1efd,
+ 0xa5e3, 0x1efe,
+ 0xa5e5, 0x1eff,
+ 0xa5e7, 0x1f00,
+ 0xa5ee, 0x1f01,
+ 0xa5f5, 0x1f02,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 japan12EUCVEnc16 = {
+ 1,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee,
+ 0x00ef, 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6,
+ 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe,
+ 0x00ff, 0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106,
+ 0x0107, 0x0108, 0x0109, 0x010a, 0x010b, 0x010c, 0x010d, 0x010e,
+ 0x010f, 0x0110, 0x0111, 0x0112, 0x0113, 0x0114, 0x0115, 0x0116,
+ 0x0117, 0x0118, 0x0119, 0x011a, 0x011b, 0x011c, 0x011d, 0x011e,
+ 0x011f, 0x0120, 0x0121, 0x0122, 0x0123, 0x0124, 0x0125, 0x0126,
+ 0x0127, 0x0128, 0x0129, 0x012a, 0x012b, 0x012c, 0x012d, 0x012e,
+ 0x012f, 0x0130, 0x0131, 0x0132, 0x0133, 0x0134, 0x0135, 0x0136,
+ 0x0137, 0x0138, 0x0139, 0x013a, 0x013b, 0x013c, 0x013d, 0x013e,
+ 0x013f, 0x0140, 0x0141, 0x0142, 0x0143, 0x0144, 0x0145, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ japan12EUCVMap2, 148
+};
+
+static Gushort japan12ExtHMap2[1326] = {
+ 0x0000, 0x0000,
+ 0x2121, 0x0279,
+ 0x2169, 0x1d36,
+ 0x216a, 0x02c2,
+ 0x2221, 0x02d7,
+ 0x2330, 0x030c,
+ 0x2341, 0x0316,
+ 0x2361, 0x0330,
+ 0x2421, 0x034a,
+ 0x2521, 0x039d,
+ 0x2621, 0x03f3,
+ 0x2641, 0x040b,
+ 0x2721, 0x0423,
+ 0x2751, 0x0444,
+ 0x2921, 0x00e8,
+ 0x2960, 0x0186,
+ 0x2961, 0x0128,
+ 0x2a21, 0x0147,
+ 0x2a60, 0x0187,
+ 0x2b21, 0x01a6,
+ 0x2b72, 0x0127,
+ 0x2b73, 0x01f7,
+ 0x2c24, 0x1d37,
+ 0x2d21, 0x1d83,
+ 0x2d40, 0x1da1,
+ 0x2d5f, 0x2083,
+ 0x2d60, 0x1db8,
+ 0x2d70, 0x02fa,
+ 0x2d71, 0x02f9,
+ 0x2d72, 0x0301,
+ 0x2d73, 0x1dc8,
+ 0x2d7a, 0x0300,
+ 0x2d7b, 0x1dcf,
+ 0x3021, 0x0465,
+ 0x3022, 0x1dd1,
+ 0x3023, 0x0467,
+ 0x3033, 0x1ca2,
+ 0x3034, 0x0478,
+ 0x303b, 0x1dd2,
+ 0x303c, 0x0480,
+ 0x306e, 0x1dd3,
+ 0x306f, 0x04b3,
+ 0x3073, 0x1dd4,
+ 0x3074, 0x04b8,
+ 0x307c, 0x1dd5,
+ 0x307d, 0x04c1,
+ 0x3121, 0x04c3,
+ 0x312a, 0x1dd6,
+ 0x312b, 0x04cd,
+ 0x3135, 0x1dd7,
+ 0x3136, 0x04d8,
+ 0x3139, 0x1dd8,
+ 0x313a, 0x04dc,
+ 0x313c, 0x1dd9,
+ 0x313e, 0x04e0,
+ 0x3142, 0x1ddb,
+ 0x3143, 0x04e5,
+ 0x316b, 0x1ddc,
+ 0x316c, 0x050e,
+ 0x3221, 0x0521,
+ 0x3228, 0x1ddd,
+ 0x3229, 0x1cc9,
+ 0x322a, 0x1dde,
+ 0x322b, 0x052b,
+ 0x3260, 0x1ddf,
+ 0x3261, 0x0561,
+ 0x327a, 0x1de0,
+ 0x327b, 0x057b,
+ 0x327d, 0x1de1,
+ 0x327e, 0x057e,
+ 0x3321, 0x057f,
+ 0x3322, 0x1de2,
+ 0x3323, 0x0581,
+ 0x3342, 0x1961,
+ 0x3343, 0x05a1,
+ 0x3349, 0x139f,
+ 0x334a, 0x05a8,
+ 0x3365, 0x1de3,
+ 0x3366, 0x05c4,
+ 0x336b, 0x1de4,
+ 0x336c, 0x05ca,
+ 0x3373, 0x1de5,
+ 0x3374, 0x05d2,
+ 0x3376, 0x1731,
+ 0x3377, 0x05d5,
+ 0x337a, 0x1de6,
+ 0x337b, 0x05d9,
+ 0x3421, 0x05dd,
+ 0x3442, 0x1de7,
+ 0x3443, 0x1572,
+ 0x3444, 0x0600,
+ 0x344d, 0x1de8,
+ 0x344e, 0x060a,
+ 0x3452, 0x1a20,
+ 0x3453, 0x060f,
+ 0x3465, 0x1de9,
+ 0x3466, 0x0622,
+ 0x3521, 0x063b,
+ 0x352b, 0x1dea,
+ 0x352c, 0x0646,
+ 0x3540, 0x1deb,
+ 0x3541, 0x065b,
+ 0x3621, 0x0699,
+ 0x3622, 0x1dec,
+ 0x3623, 0x069b,
+ 0x362a, 0x1ded,
+ 0x362b, 0x06a3,
+ 0x3646, 0x1d32,
+ 0x3647, 0x06bf,
+ 0x364f, 0x1dee,
+ 0x3650, 0x06c8,
+ 0x366d, 0x1def,
+ 0x366e, 0x06e6,
+ 0x3674, 0x1df0,
+ 0x3675, 0x06ed,
+ 0x367b, 0x1df1,
+ 0x367c, 0x06f4,
+ 0x367d, 0x1df2,
+ 0x367e, 0x06f6,
+ 0x3721, 0x06f7,
+ 0x3724, 0x1df3,
+ 0x3725, 0x06fb,
+ 0x3737, 0x1df4,
+ 0x3738, 0x070e,
+ 0x3745, 0x1df5,
+ 0x3746, 0x071c,
+ 0x374e, 0x1df6,
+ 0x374f, 0x0725,
+ 0x3752, 0x1df7,
+ 0x3753, 0x0729,
+ 0x3755, 0x1df8,
+ 0x3756, 0x072c,
+ 0x375b, 0x1c0d,
+ 0x375c, 0x0732,
+ 0x3764, 0x1df9,
+ 0x3765, 0x073b,
+ 0x3771, 0x1dfa,
+ 0x3772, 0x0748,
+ 0x3779, 0x1dfb,
+ 0x377a, 0x0750,
+ 0x377e, 0x1dfc,
+ 0x3821, 0x0755,
+ 0x3834, 0x1dfd,
+ 0x3835, 0x0769,
+ 0x3841, 0x1dfe,
+ 0x3842, 0x0776,
+ 0x3921, 0x07b3,
+ 0x392b, 0x1dff,
+ 0x392c, 0x07be,
+ 0x3937, 0x1e00,
+ 0x3938, 0x07ca,
+ 0x3942, 0x1e01,
+ 0x3943, 0x07d5,
+ 0x395c, 0x16dd,
+ 0x395d, 0x07ef,
+ 0x396d, 0x1e02,
+ 0x396e, 0x0800,
+ 0x3974, 0x1e03,
+ 0x3975, 0x0807,
+ 0x3979, 0x1e04,
+ 0x397a, 0x080c,
+ 0x3a21, 0x0811,
+ 0x3a53, 0x1e05,
+ 0x3a54, 0x0844,
+ 0x3a67, 0x1e06,
+ 0x3a68, 0x0858,
+ 0x3a74, 0x1e07,
+ 0x3a75, 0x0865,
+ 0x3b21, 0x086f,
+ 0x3b27, 0x1e08,
+ 0x3b28, 0x0876,
+ 0x3b2a, 0x1e09,
+ 0x3b2b, 0x0879,
+ 0x3b2c, 0x1e0a,
+ 0x3b2d, 0x087b,
+ 0x3b39, 0x1e0b,
+ 0x3b3a, 0x0888,
+ 0x3c21, 0x08cd,
+ 0x3c38, 0x1e0c,
+ 0x3c39, 0x08e5,
+ 0x3c48, 0x1e0d,
+ 0x3c49, 0x1929,
+ 0x3c4a, 0x08f6,
+ 0x3c57, 0x1e0e,
+ 0x3c58, 0x0904,
+ 0x3c5d, 0x1e0f,
+ 0x3c5f, 0x090b,
+ 0x3d21, 0x092b,
+ 0x3d2b, 0x1e11,
+ 0x3d2c, 0x0936,
+ 0x3d36, 0x1e12,
+ 0x3d37, 0x0941,
+ 0x3d6c, 0x1e13,
+ 0x3d6e, 0x0978,
+ 0x3d72, 0x1e15,
+ 0x3d74, 0x097e,
+ 0x3e21, 0x0989,
+ 0x3e25, 0x1e17,
+ 0x3e26, 0x098e,
+ 0x3e33, 0x1e18,
+ 0x3e34, 0x099c,
+ 0x3e3f, 0x1e19,
+ 0x3e40, 0x09a8,
+ 0x3e55, 0x1e1a,
+ 0x3e56, 0x09be,
+ 0x3e5f, 0x1e1b,
+ 0x3e60, 0x09c8,
+ 0x3e64, 0x1e1c,
+ 0x3e65, 0x09cd,
+ 0x3f21, 0x09e7,
+ 0x3f2a, 0x1e1d,
+ 0x3f2b, 0x09f1,
+ 0x3f59, 0x1e1e,
+ 0x3f5a, 0x0a20,
+ 0x3f60, 0x1e1f,
+ 0x3f61, 0x0a27,
+ 0x3f69, 0x1e20,
+ 0x3f6a, 0x0a30,
+ 0x4021, 0x0a45,
+ 0x4022, 0x1e21,
+ 0x4023, 0x0a47,
+ 0x4042, 0x1e22,
+ 0x4043, 0x0a67,
+ 0x4066, 0x1e23,
+ 0x4067, 0x0a8b,
+ 0x4071, 0x1e24,
+ 0x4073, 0x0a97,
+ 0x4079, 0x1e26,
+ 0x407b, 0x0a9f,
+ 0x4121, 0x0aa3,
+ 0x4127, 0x1e28,
+ 0x4128, 0x1a6e,
+ 0x4129, 0x0aab,
+ 0x4139, 0x1e29,
+ 0x413a, 0x0abc,
+ 0x414c, 0x1e2a,
+ 0x414d, 0x0acf,
+ 0x414f, 0x1e2b,
+ 0x4150, 0x0ad2,
+ 0x415f, 0x1e2c,
+ 0x4160, 0x0ae2,
+ 0x4169, 0x1e2d,
+ 0x416a, 0x0aec,
+ 0x4221, 0x0b01,
+ 0x423d, 0x1e2e,
+ 0x423e, 0x0b1e,
+ 0x424d, 0x1e2f,
+ 0x424e, 0x0b2e,
+ 0x425c, 0x1e30,
+ 0x425d, 0x0b3d,
+ 0x4263, 0x1e31,
+ 0x4264, 0x0b44,
+ 0x426f, 0x1e32,
+ 0x4270, 0x0b50,
+ 0x4275, 0x1e33,
+ 0x4277, 0x0b57,
+ 0x427d, 0x1e35,
+ 0x427e, 0x0b5e,
+ 0x4321, 0x0b5f,
+ 0x4327, 0x1e36,
+ 0x4328, 0x0b66,
+ 0x4329, 0x1e37,
+ 0x432b, 0x0b69,
+ 0x432d, 0x1e39,
+ 0x432f, 0x0b6d,
+ 0x433d, 0x1e3b,
+ 0x433e, 0x0b7c,
+ 0x4370, 0x1e3c,
+ 0x4371, 0x0baf,
+ 0x4375, 0x1e3d,
+ 0x4376, 0x0bb4,
+ 0x437c, 0x1e3e,
+ 0x437d, 0x0bbb,
+ 0x4421, 0x0bbd,
+ 0x443d, 0x1e3f,
+ 0x443e, 0x0bda,
+ 0x4448, 0x1e40,
+ 0x4449, 0x0be5,
+ 0x444a, 0x1e41,
+ 0x444b, 0x0be7,
+ 0x444d, 0x1e42,
+ 0x444e, 0x0bea,
+ 0x444f, 0x1e43,
+ 0x4450, 0x0bec,
+ 0x445b, 0x11b5,
+ 0x445c, 0x0bf8,
+ 0x4521, 0x0c1b,
+ 0x4522, 0x1e44,
+ 0x4523, 0x0c1d,
+ 0x4527, 0x1e45,
+ 0x4528, 0x0c22,
+ 0x452e, 0x1e46,
+ 0x452f, 0x0c29,
+ 0x4536, 0x1e47,
+ 0x4537, 0x0c31,
+ 0x453f, 0x1e48,
+ 0x4540, 0x0c3a,
+ 0x4548, 0x1e49,
+ 0x4549, 0x0c43,
+ 0x454b, 0x1e4a,
+ 0x454c, 0x0c46,
+ 0x4551, 0x1e4b,
+ 0x4553, 0x0c4d,
+ 0x4557, 0x16df,
+ 0x4558, 0x0c52,
+ 0x4564, 0x1e4d,
+ 0x4565, 0x0c5f,
+ 0x456e, 0x1450,
+ 0x456f, 0x0c69,
+ 0x4573, 0x1536,
+ 0x4574, 0x0c6e,
+ 0x4578, 0x1e4e,
+ 0x4579, 0x0c73,
+ 0x4621, 0x0c79,
+ 0x463e, 0x1e4f,
+ 0x463f, 0x0c97,
+ 0x4642, 0x1e50,
+ 0x4643, 0x0c9b,
+ 0x4654, 0x1e51,
+ 0x4656, 0x0cae,
+ 0x465b, 0x1e53,
+ 0x465d, 0x0cb5,
+ 0x4661, 0x1e55,
+ 0x4662, 0x0cba,
+ 0x4666, 0x1e56,
+ 0x4668, 0x0cc0,
+ 0x466a, 0x1e58,
+ 0x466b, 0x0cc3,
+ 0x4676, 0x1aed,
+ 0x4677, 0x0ccf,
+ 0x4721, 0x0cd7,
+ 0x4729, 0x1e59,
+ 0x472a, 0x0ce0,
+ 0x4739, 0x1e5a,
+ 0x473a, 0x0cf0,
+ 0x4757, 0x1e5b,
+ 0x4758, 0x0d0e,
+ 0x4767, 0x1e5c,
+ 0x4768, 0x1989,
+ 0x4769, 0x1e5d,
+ 0x476a, 0x0d20,
+ 0x476d, 0x1e5e,
+ 0x476e, 0x0d24,
+ 0x4821, 0x0d35,
+ 0x4824, 0x1e5f,
+ 0x4825, 0x0d39,
+ 0x482e, 0x1e60,
+ 0x482f, 0x0d43,
+ 0x4830, 0x1e61,
+ 0x4831, 0x0d45,
+ 0x4854, 0x1e62,
+ 0x4855, 0x0d69,
+ 0x4862, 0x1e63,
+ 0x4863, 0x0d77,
+ 0x4875, 0x1e64,
+ 0x4876, 0x0d8a,
+ 0x4921, 0x0d93,
+ 0x4922, 0x1e65,
+ 0x4924, 0x0d96,
+ 0x492f, 0x1e67,
+ 0x4930, 0x143b,
+ 0x4931, 0x0da3,
+ 0x4932, 0x1e68,
+ 0x4933, 0x0da5,
+ 0x4935, 0x1e69,
+ 0x4936, 0x0da8,
+ 0x4940, 0x1e6a,
+ 0x4941, 0x0db3,
+ 0x494e, 0x1e6b,
+ 0x494f, 0x0dc1,
+ 0x4951, 0x1e6c,
+ 0x4952, 0x0dc4,
+ 0x4a21, 0x0df1,
+ 0x4a43, 0x1e6d,
+ 0x4a44, 0x0e14,
+ 0x4a4d, 0x1e6e,
+ 0x4a4e, 0x0e1e,
+ 0x4a5a, 0x1e6f,
+ 0x4a5b, 0x0e2b,
+ 0x4a79, 0x1e70,
+ 0x4a7a, 0x0e4a,
+ 0x4b21, 0x0e4f,
+ 0x4b22, 0x1e71,
+ 0x4b23, 0x0e51,
+ 0x4b29, 0x1e72,
+ 0x4b2a, 0x0e58,
+ 0x4b4b, 0x1e73,
+ 0x4b4c, 0x0e7a,
+ 0x4b6a, 0x1d33,
+ 0x4b6b, 0x0e99,
+ 0x4b70, 0x1e74,
+ 0x4b71, 0x0e9f,
+ 0x4b79, 0x102f,
+ 0x4b7a, 0x0ea8,
+ 0x4c21, 0x0ead,
+ 0x4c4d, 0x1e75,
+ 0x4c4e, 0x0eda,
+ 0x4c59, 0x1e76,
+ 0x4c5a, 0x0ee6,
+ 0x4c5f, 0x1e77,
+ 0x4c60, 0x0eec,
+ 0x4c62, 0x1e78,
+ 0x4c63, 0x0eef,
+ 0x4c79, 0x1935,
+ 0x4c7a, 0x1e79,
+ 0x4c7b, 0x0f07,
+ 0x4c7c, 0x1e7a,
+ 0x4c7d, 0x0f09,
+ 0x4c7e, 0x1e7b,
+ 0x4d21, 0x0f0b,
+ 0x4d32, 0x1e7c,
+ 0x4d33, 0x0f1d,
+ 0x4d50, 0x1e7d,
+ 0x4d51, 0x0f3b,
+ 0x4d54, 0x1e7e,
+ 0x4d55, 0x0f3f,
+ 0x4d5a, 0x1d34,
+ 0x4d5b, 0x0f45,
+ 0x4d69, 0x1e7f,
+ 0x4d6a, 0x0f54,
+ 0x4e21, 0x0f69,
+ 0x4e4b, 0x1e80,
+ 0x4e4c, 0x0f94,
+ 0x4e7a, 0x1e81,
+ 0x4e7c, 0x0fc4,
+ 0x4f21, 0x1e83,
+ 0x4f22, 0x0fc8,
+ 0x4f31, 0x1e84,
+ 0x4f32, 0x0fd8,
+ 0x4f36, 0x1777,
+ 0x4f37, 0x0fdd,
+ 0x4f39, 0x1e85,
+ 0x4f3a, 0x0fe0,
+ 0x5021, 0x0ffa,
+ 0x5056, 0x0ea7,
+ 0x5057, 0x1030,
+ 0x5121, 0x1058,
+ 0x513d, 0x1e86,
+ 0x513e, 0x1075,
+ 0x5147, 0x1e87,
+ 0x5148, 0x107f,
+ 0x514b, 0x1e88,
+ 0x514c, 0x1083,
+ 0x514d, 0x1e89,
+ 0x514e, 0x1085,
+ 0x5221, 0x10b6,
+ 0x5321, 0x1114,
+ 0x5330, 0x1e8a,
+ 0x5331, 0x1124,
+ 0x533a, 0x1e8b,
+ 0x533b, 0x112e,
+ 0x5350, 0x1e8c,
+ 0x5351, 0x1144,
+ 0x535e, 0x1e8d,
+ 0x535f, 0x1152,
+ 0x536b, 0x1e8e,
+ 0x536c, 0x115f,
+ 0x5421, 0x1172,
+ 0x5444, 0x1e8f,
+ 0x5445, 0x1196,
+ 0x5464, 0x0bf7,
+ 0x5465, 0x11b6,
+ 0x5521, 0x11d0,
+ 0x553d, 0x1e90,
+ 0x553e, 0x11ed,
+ 0x5563, 0x1e91,
+ 0x5564, 0x1213,
+ 0x5621, 0x122e,
+ 0x5622, 0x1e92,
+ 0x5623, 0x1230,
+ 0x5672, 0x1e93,
+ 0x5673, 0x1280,
+ 0x5721, 0x128c,
+ 0x5821, 0x12ea,
+ 0x5824, 0x1e94,
+ 0x5825, 0x12ee,
+ 0x5921, 0x1348,
+ 0x5960, 0x1e95,
+ 0x5961, 0x1388,
+ 0x596c, 0x1e96,
+ 0x596d, 0x1394,
+ 0x5978, 0x05a7,
+ 0x5979, 0x13a0,
+ 0x5a21, 0x13a6,
+ 0x5a39, 0x1e97,
+ 0x5a3a, 0x13bf,
+ 0x5a4d, 0x1e98,
+ 0x5a4e, 0x13d3,
+ 0x5b21, 0x1404,
+ 0x5b45, 0x1e99,
+ 0x5b46, 0x1429,
+ 0x5b4a, 0x1e9a,
+ 0x5b4b, 0x142e,
+ 0x5b58, 0x0da2,
+ 0x5b59, 0x143c,
+ 0x5b6b, 0x1e9b,
+ 0x5b6c, 0x144f,
+ 0x5b6d, 0x0c68,
+ 0x5b6e, 0x1451,
+ 0x5b74, 0x1e9c,
+ 0x5b75, 0x1458,
+ 0x5c21, 0x1462,
+ 0x5d21, 0x14c0,
+ 0x5e21, 0x151e,
+ 0x5e39, 0x0c6d,
+ 0x5e3a, 0x1537,
+ 0x5e50, 0x1e9d,
+ 0x5e51, 0x154e,
+ 0x5e75, 0x05ff,
+ 0x5e76, 0x1573,
+ 0x5f21, 0x157c,
+ 0x5f73, 0x1e9e,
+ 0x5f74, 0x15cf,
+ 0x6021, 0x15da,
+ 0x6026, 0x1e9f,
+ 0x6027, 0x15e0,
+ 0x605f, 0x1ea0,
+ 0x6060, 0x1619,
+ 0x6076, 0x1d35,
+ 0x6077, 0x1630,
+ 0x6121, 0x1638,
+ 0x612b, 0x1ea1,
+ 0x612c, 0x1643,
+ 0x6130, 0x1ea2,
+ 0x6132, 0x1649,
+ 0x6221, 0x1696,
+ 0x622b, 0x1ea4,
+ 0x622c, 0x16a1,
+ 0x6268, 0x07ee,
+ 0x6269, 0x16de,
+ 0x626a, 0x0c51,
+ 0x626b, 0x16e0,
+ 0x626f, 0x1ea5,
+ 0x6270, 0x16e5,
+ 0x6321, 0x16f4,
+ 0x634a, 0x1ea6,
+ 0x634b, 0x171e,
+ 0x6354, 0x1ea7,
+ 0x6355, 0x1728,
+ 0x635e, 0x05d4,
+ 0x635f, 0x1732,
+ 0x6421, 0x1752,
+ 0x6439, 0x1ea8,
+ 0x643a, 0x176b,
+ 0x6446, 0x0fdc,
+ 0x6447, 0x1778,
+ 0x6464, 0x1ea9,
+ 0x6465, 0x1796,
+ 0x646e, 0x1eaa,
+ 0x646f, 0x17a0,
+ 0x6521, 0x17b0,
+ 0x6539, 0x1eab,
+ 0x653a, 0x17c9,
+ 0x653b, 0x1eac,
+ 0x653c, 0x17cb,
+ 0x6546, 0x1ead,
+ 0x6547, 0x17d6,
+ 0x6621, 0x180e,
+ 0x6646, 0x1eae,
+ 0x6647, 0x1834,
+ 0x6721, 0x186c,
+ 0x6764, 0x1eaf,
+ 0x6765, 0x18b0,
+ 0x6769, 0x1eb0,
+ 0x676a, 0x18b5,
+ 0x6772, 0x1eb1,
+ 0x6773, 0x18be,
+ 0x6821, 0x18ca,
+ 0x6834, 0x1eb2,
+ 0x6835, 0x18de,
+ 0x683b, 0x1eb3,
+ 0x683c, 0x18e5,
+ 0x6874, 0x1eb4,
+ 0x6875, 0x191e,
+ 0x6921, 0x1928,
+ 0x6922, 0x08f5,
+ 0x6923, 0x192a,
+ 0x692e, 0x0f05,
+ 0x692f, 0x1936,
+ 0x693c, 0x1eb5,
+ 0x693d, 0x1944,
+ 0x695a, 0x05a0,
+ 0x695b, 0x1962,
+ 0x6a21, 0x1986,
+ 0x6a24, 0x0d1e,
+ 0x6a25, 0x198a,
+ 0x6a27, 0x1eb6,
+ 0x6a28, 0x198d,
+ 0x6a3d, 0x1eb7,
+ 0x6a3e, 0x19a3,
+ 0x6a6f, 0x1eb8,
+ 0x6a70, 0x19d5,
+ 0x6b21, 0x19e4,
+ 0x6b32, 0x1eb9,
+ 0x6b33, 0x19f6,
+ 0x6b5d, 0x060e,
+ 0x6b5e, 0x1a21,
+ 0x6b66, 0x1eba,
+ 0x6b67, 0x1a2a,
+ 0x6b76, 0x1ebb,
+ 0x6b77, 0x1a3a,
+ 0x6c21, 0x1a42,
+ 0x6c4d, 0x0aaa,
+ 0x6c4e, 0x1a6f,
+ 0x6c69, 0x1ebc,
+ 0x6c6a, 0x1a8b,
+ 0x6c74, 0x1ebd,
+ 0x6c75, 0x1a96,
+ 0x6d21, 0x1aa0,
+ 0x6d4e, 0x1ebe,
+ 0x6d4f, 0x1ace,
+ 0x6d6c, 0x1ebf,
+ 0x6d6d, 0x1aec,
+ 0x6d6e, 0x1ec0,
+ 0x6d6f, 0x1aee,
+ 0x6e21, 0x1afe,
+ 0x6e29, 0x1ec1,
+ 0x6e2a, 0x1b07,
+ 0x6e3d, 0x1ec2,
+ 0x6e3e, 0x1b1b,
+ 0x6e57, 0x1ec3,
+ 0x6e58, 0x1b35,
+ 0x6f21, 0x1b5c,
+ 0x6f65, 0x1ec4,
+ 0x6f66, 0x1ba1,
+ 0x7021, 0x1bba,
+ 0x7033, 0x1ec5,
+ 0x7034, 0x1bcd,
+ 0x7045, 0x1ec6,
+ 0x7046, 0x1bdf,
+ 0x7051, 0x1ec7,
+ 0x7052, 0x1beb,
+ 0x7057, 0x1ec8,
+ 0x7058, 0x1bf1,
+ 0x7074, 0x0731,
+ 0x7075, 0x1ec9,
+ 0x7076, 0x1c0f,
+ 0x7121, 0x1c18,
+ 0x7221, 0x1c76,
+ 0x722d, 0x1eca,
+ 0x722e, 0x1c83,
+ 0x723c, 0x1ecb,
+ 0x723d, 0x1c92,
+ 0x724d, 0x0477,
+ 0x724e, 0x1ecc,
+ 0x724f, 0x1ca4,
+ 0x7274, 0x0529,
+ 0x7275, 0x1cca,
+ 0x7321, 0x1cd4,
+ 0x7351, 0x1ecd,
+ 0x7352, 0x1d05,
+ 0x737d, 0x1ece,
+ 0x737e, 0x1d31,
+ 0x7921, 0x20a7,
+ 0x7a21, 0x2105,
+ 0x7a36, 0x07c9,
+ 0x7a37, 0x211a,
+ 0x7b21, 0x2162,
+ 0x7c21, 0x21c0,
+ 0x7c71, 0x1f9c,
+ 0x7c7b, 0x02ef,
+ 0x7c7c, 0x1f45,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 japan12ExtHEnc16 = {
+ 0,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ japan12ExtHMap2, 663
+};
+
+static Gushort japan12ExtRKSJHMap2[1330] = {
+ 0x0000, 0x0000,
+ 0x8140, 0x0279,
+ 0x8180, 0x02b8,
+ 0x8189, 0x1d36,
+ 0x818a, 0x02c2,
+ 0x824f, 0x030c,
+ 0x8260, 0x0316,
+ 0x8281, 0x0330,
+ 0x829f, 0x034a,
+ 0x8340, 0x039d,
+ 0x8380, 0x03dc,
+ 0x839f, 0x03f3,
+ 0x83bf, 0x040b,
+ 0x8440, 0x0423,
+ 0x8470, 0x0444,
+ 0x8480, 0x0453,
+ 0x8540, 0x00e8,
+ 0x8580, 0x0186,
+ 0x8581, 0x0128,
+ 0x859f, 0x0147,
+ 0x85de, 0x0187,
+ 0x8640, 0x01a6,
+ 0x8680, 0x01e5,
+ 0x8692, 0x0127,
+ 0x8693, 0x01f7,
+ 0x86a2, 0x1d37,
+ 0x8740, 0x1d83,
+ 0x875f, 0x1da1,
+ 0x877e, 0x2083,
+ 0x8780, 0x1db8,
+ 0x8790, 0x02fa,
+ 0x8791, 0x02f9,
+ 0x8792, 0x0301,
+ 0x8793, 0x1dc8,
+ 0x879a, 0x0300,
+ 0x879b, 0x1dcf,
+ 0x889f, 0x0465,
+ 0x88a0, 0x1dd1,
+ 0x88a1, 0x0467,
+ 0x88b1, 0x1ca2,
+ 0x88b2, 0x0478,
+ 0x88b9, 0x1dd2,
+ 0x88ba, 0x0480,
+ 0x88ec, 0x1dd3,
+ 0x88ed, 0x04b3,
+ 0x88f1, 0x1dd4,
+ 0x88f2, 0x04b8,
+ 0x88fa, 0x1dd5,
+ 0x88fb, 0x04c1,
+ 0x8940, 0x04c3,
+ 0x8949, 0x1dd6,
+ 0x894a, 0x04cd,
+ 0x8954, 0x1dd7,
+ 0x8955, 0x04d8,
+ 0x8958, 0x1dd8,
+ 0x8959, 0x04dc,
+ 0x895b, 0x1dd9,
+ 0x895d, 0x04e0,
+ 0x8961, 0x1ddb,
+ 0x8962, 0x04e5,
+ 0x8980, 0x0502,
+ 0x898b, 0x1ddc,
+ 0x898c, 0x050e,
+ 0x89a6, 0x1ddd,
+ 0x89a7, 0x1cc9,
+ 0x89a8, 0x1dde,
+ 0x89a9, 0x052b,
+ 0x89de, 0x1ddf,
+ 0x89df, 0x0561,
+ 0x89f8, 0x1de0,
+ 0x89f9, 0x057b,
+ 0x89fb, 0x1de1,
+ 0x89fc, 0x057e,
+ 0x8a40, 0x057f,
+ 0x8a41, 0x1de2,
+ 0x8a42, 0x0581,
+ 0x8a61, 0x1961,
+ 0x8a62, 0x05a1,
+ 0x8a68, 0x139f,
+ 0x8a69, 0x05a8,
+ 0x8a80, 0x05be,
+ 0x8a85, 0x1de3,
+ 0x8a86, 0x05c4,
+ 0x8a8b, 0x1de4,
+ 0x8a8c, 0x05ca,
+ 0x8a93, 0x1de5,
+ 0x8a94, 0x05d2,
+ 0x8a96, 0x1731,
+ 0x8a97, 0x05d5,
+ 0x8a9a, 0x1de6,
+ 0x8a9b, 0x05d9,
+ 0x8ac0, 0x1de7,
+ 0x8ac1, 0x1572,
+ 0x8ac2, 0x0600,
+ 0x8acb, 0x1de8,
+ 0x8acc, 0x060a,
+ 0x8ad0, 0x1a20,
+ 0x8ad1, 0x060f,
+ 0x8ae3, 0x1de9,
+ 0x8ae4, 0x0622,
+ 0x8b40, 0x063b,
+ 0x8b4a, 0x1dea,
+ 0x8b4b, 0x0646,
+ 0x8b5f, 0x1deb,
+ 0x8b60, 0x065b,
+ 0x8b80, 0x067a,
+ 0x8ba0, 0x1dec,
+ 0x8ba1, 0x069b,
+ 0x8ba8, 0x1ded,
+ 0x8ba9, 0x06a3,
+ 0x8bc4, 0x1d32,
+ 0x8bc5, 0x06bf,
+ 0x8bcd, 0x1dee,
+ 0x8bce, 0x06c8,
+ 0x8beb, 0x1def,
+ 0x8bec, 0x06e6,
+ 0x8bf2, 0x1df0,
+ 0x8bf3, 0x06ed,
+ 0x8bf9, 0x1df1,
+ 0x8bfa, 0x06f4,
+ 0x8bfb, 0x1df2,
+ 0x8bfc, 0x06f6,
+ 0x8c40, 0x06f7,
+ 0x8c43, 0x1df3,
+ 0x8c44, 0x06fb,
+ 0x8c56, 0x1df4,
+ 0x8c57, 0x070e,
+ 0x8c64, 0x1df5,
+ 0x8c65, 0x071c,
+ 0x8c6d, 0x1df6,
+ 0x8c6e, 0x0725,
+ 0x8c71, 0x1df7,
+ 0x8c72, 0x0729,
+ 0x8c74, 0x1df8,
+ 0x8c75, 0x072c,
+ 0x8c7a, 0x1c0d,
+ 0x8c7b, 0x0732,
+ 0x8c80, 0x0736,
+ 0x8c84, 0x1df9,
+ 0x8c85, 0x073b,
+ 0x8c91, 0x1dfa,
+ 0x8c92, 0x0748,
+ 0x8c99, 0x1dfb,
+ 0x8c9a, 0x0750,
+ 0x8c9e, 0x1dfc,
+ 0x8c9f, 0x0755,
+ 0x8cb2, 0x1dfd,
+ 0x8cb3, 0x0769,
+ 0x8cbf, 0x1dfe,
+ 0x8cc0, 0x0776,
+ 0x8d40, 0x07b3,
+ 0x8d4a, 0x1dff,
+ 0x8d4b, 0x07be,
+ 0x8d56, 0x1e00,
+ 0x8d57, 0x07ca,
+ 0x8d61, 0x1e01,
+ 0x8d62, 0x07d5,
+ 0x8d7b, 0x16dd,
+ 0x8d7c, 0x07ef,
+ 0x8d80, 0x07f2,
+ 0x8d8d, 0x1e02,
+ 0x8d8e, 0x0800,
+ 0x8d94, 0x1e03,
+ 0x8d95, 0x0807,
+ 0x8d99, 0x1e04,
+ 0x8d9a, 0x080c,
+ 0x8dd1, 0x1e05,
+ 0x8dd2, 0x0844,
+ 0x8de5, 0x1e06,
+ 0x8de6, 0x0858,
+ 0x8df2, 0x1e07,
+ 0x8df3, 0x0865,
+ 0x8e40, 0x086f,
+ 0x8e46, 0x1e08,
+ 0x8e47, 0x0876,
+ 0x8e49, 0x1e09,
+ 0x8e4a, 0x0879,
+ 0x8e4b, 0x1e0a,
+ 0x8e4c, 0x087b,
+ 0x8e58, 0x1e0b,
+ 0x8e59, 0x0888,
+ 0x8e80, 0x08ae,
+ 0x8eb6, 0x1e0c,
+ 0x8eb7, 0x08e5,
+ 0x8ec6, 0x1e0d,
+ 0x8ec7, 0x1929,
+ 0x8ec8, 0x08f6,
+ 0x8ed5, 0x1e0e,
+ 0x8ed6, 0x0904,
+ 0x8edb, 0x1e0f,
+ 0x8edd, 0x090b,
+ 0x8f40, 0x092b,
+ 0x8f4a, 0x1e11,
+ 0x8f4b, 0x0936,
+ 0x8f55, 0x1e12,
+ 0x8f56, 0x0941,
+ 0x8f80, 0x096a,
+ 0x8f8c, 0x1e13,
+ 0x8f8e, 0x0978,
+ 0x8f92, 0x1e15,
+ 0x8f94, 0x097e,
+ 0x8fa3, 0x1e17,
+ 0x8fa4, 0x098e,
+ 0x8fb1, 0x1e18,
+ 0x8fb2, 0x099c,
+ 0x8fbd, 0x1e19,
+ 0x8fbe, 0x09a8,
+ 0x8fd3, 0x1e1a,
+ 0x8fd4, 0x09be,
+ 0x8fdd, 0x1e1b,
+ 0x8fde, 0x09c8,
+ 0x8fe2, 0x1e1c,
+ 0x8fe3, 0x09cd,
+ 0x9040, 0x09e7,
+ 0x9049, 0x1e1d,
+ 0x904a, 0x09f1,
+ 0x9078, 0x1e1e,
+ 0x9079, 0x0a20,
+ 0x9080, 0x1e1f,
+ 0x9081, 0x0a27,
+ 0x9089, 0x1e20,
+ 0x908a, 0x0a30,
+ 0x90a0, 0x1e21,
+ 0x90a1, 0x0a47,
+ 0x90c0, 0x1e22,
+ 0x90c1, 0x0a67,
+ 0x90e4, 0x1e23,
+ 0x90e5, 0x0a8b,
+ 0x90ef, 0x1e24,
+ 0x90f1, 0x0a97,
+ 0x90f7, 0x1e26,
+ 0x90f9, 0x0a9f,
+ 0x9140, 0x0aa3,
+ 0x9146, 0x1e28,
+ 0x9147, 0x1a6e,
+ 0x9148, 0x0aab,
+ 0x9158, 0x1e29,
+ 0x9159, 0x0abc,
+ 0x916b, 0x1e2a,
+ 0x916c, 0x0acf,
+ 0x916e, 0x1e2b,
+ 0x916f, 0x0ad2,
+ 0x917e, 0x1e2c,
+ 0x9180, 0x0ae2,
+ 0x9189, 0x1e2d,
+ 0x918a, 0x0aec,
+ 0x91bb, 0x1e2e,
+ 0x91bc, 0x0b1e,
+ 0x91cb, 0x1e2f,
+ 0x91cc, 0x0b2e,
+ 0x91da, 0x1e30,
+ 0x91db, 0x0b3d,
+ 0x91e1, 0x1e31,
+ 0x91e2, 0x0b44,
+ 0x91ed, 0x1e32,
+ 0x91ee, 0x0b50,
+ 0x91f3, 0x1e33,
+ 0x91f5, 0x0b57,
+ 0x91fb, 0x1e35,
+ 0x91fc, 0x0b5e,
+ 0x9240, 0x0b5f,
+ 0x9246, 0x1e36,
+ 0x9247, 0x0b66,
+ 0x9248, 0x1e37,
+ 0x924a, 0x0b69,
+ 0x924c, 0x1e39,
+ 0x924e, 0x0b6d,
+ 0x925c, 0x1e3b,
+ 0x925d, 0x0b7c,
+ 0x9280, 0x0b9e,
+ 0x9290, 0x1e3c,
+ 0x9291, 0x0baf,
+ 0x9295, 0x1e3d,
+ 0x9296, 0x0bb4,
+ 0x929c, 0x1e3e,
+ 0x929d, 0x0bbb,
+ 0x92bb, 0x1e3f,
+ 0x92bc, 0x0bda,
+ 0x92c6, 0x1e40,
+ 0x92c7, 0x0be5,
+ 0x92c8, 0x1e41,
+ 0x92c9, 0x0be7,
+ 0x92cb, 0x1e42,
+ 0x92cc, 0x0bea,
+ 0x92cd, 0x1e43,
+ 0x92ce, 0x0bec,
+ 0x92d9, 0x11b5,
+ 0x92da, 0x0bf8,
+ 0x9340, 0x0c1b,
+ 0x9341, 0x1e44,
+ 0x9342, 0x0c1d,
+ 0x9346, 0x1e45,
+ 0x9347, 0x0c22,
+ 0x934d, 0x1e46,
+ 0x934e, 0x0c29,
+ 0x9355, 0x1e47,
+ 0x9356, 0x0c31,
+ 0x935e, 0x1e48,
+ 0x935f, 0x0c3a,
+ 0x9367, 0x1e49,
+ 0x9368, 0x0c43,
+ 0x936a, 0x1e4a,
+ 0x936b, 0x0c46,
+ 0x9370, 0x1e4b,
+ 0x9372, 0x0c4d,
+ 0x9376, 0x16df,
+ 0x9377, 0x0c52,
+ 0x9380, 0x0c5a,
+ 0x9384, 0x1e4d,
+ 0x9385, 0x0c5f,
+ 0x938e, 0x1450,
+ 0x938f, 0x0c69,
+ 0x9393, 0x1536,
+ 0x9394, 0x0c6e,
+ 0x9398, 0x1e4e,
+ 0x9399, 0x0c73,
+ 0x93bc, 0x1e4f,
+ 0x93bd, 0x0c97,
+ 0x93c0, 0x1e50,
+ 0x93c1, 0x0c9b,
+ 0x93d2, 0x1e51,
+ 0x93d4, 0x0cae,
+ 0x93d9, 0x1e53,
+ 0x93db, 0x0cb5,
+ 0x93df, 0x1e55,
+ 0x93e0, 0x0cba,
+ 0x93e4, 0x1e56,
+ 0x93e6, 0x0cc0,
+ 0x93e8, 0x1e58,
+ 0x93e9, 0x0cc3,
+ 0x93f4, 0x1aed,
+ 0x93f5, 0x0ccf,
+ 0x9440, 0x0cd7,
+ 0x9448, 0x1e59,
+ 0x9449, 0x0ce0,
+ 0x9458, 0x1e5a,
+ 0x9459, 0x0cf0,
+ 0x9476, 0x1e5b,
+ 0x9477, 0x0d0e,
+ 0x9480, 0x0d16,
+ 0x9487, 0x1e5c,
+ 0x9488, 0x1989,
+ 0x9489, 0x1e5d,
+ 0x948a, 0x0d20,
+ 0x948d, 0x1e5e,
+ 0x948e, 0x0d24,
+ 0x94a2, 0x1e5f,
+ 0x94a3, 0x0d39,
+ 0x94ac, 0x1e60,
+ 0x94ad, 0x0d43,
+ 0x94ae, 0x1e61,
+ 0x94af, 0x0d45,
+ 0x94d2, 0x1e62,
+ 0x94d3, 0x0d69,
+ 0x94e0, 0x1e63,
+ 0x94e1, 0x0d77,
+ 0x94f3, 0x1e64,
+ 0x94f4, 0x0d8a,
+ 0x9540, 0x0d93,
+ 0x9541, 0x1e65,
+ 0x9543, 0x0d96,
+ 0x954e, 0x1e67,
+ 0x954f, 0x143b,
+ 0x9550, 0x0da3,
+ 0x9551, 0x1e68,
+ 0x9552, 0x0da5,
+ 0x9554, 0x1e69,
+ 0x9555, 0x0da8,
+ 0x955f, 0x1e6a,
+ 0x9560, 0x0db3,
+ 0x956d, 0x1e6b,
+ 0x956e, 0x0dc1,
+ 0x9570, 0x1e6c,
+ 0x9571, 0x0dc4,
+ 0x9580, 0x0dd2,
+ 0x95c1, 0x1e6d,
+ 0x95c2, 0x0e14,
+ 0x95cb, 0x1e6e,
+ 0x95cc, 0x0e1e,
+ 0x95d8, 0x1e6f,
+ 0x95d9, 0x0e2b,
+ 0x95f7, 0x1e70,
+ 0x95f8, 0x0e4a,
+ 0x9640, 0x0e4f,
+ 0x9641, 0x1e71,
+ 0x9642, 0x0e51,
+ 0x9648, 0x1e72,
+ 0x9649, 0x0e58,
+ 0x966a, 0x1e73,
+ 0x966b, 0x0e7a,
+ 0x9680, 0x0e8e,
+ 0x968a, 0x1d33,
+ 0x968b, 0x0e99,
+ 0x9690, 0x1e74,
+ 0x9691, 0x0e9f,
+ 0x9699, 0x102f,
+ 0x969a, 0x0ea8,
+ 0x96cb, 0x1e75,
+ 0x96cc, 0x0eda,
+ 0x96d7, 0x1e76,
+ 0x96d8, 0x0ee6,
+ 0x96dd, 0x1e77,
+ 0x96de, 0x0eec,
+ 0x96e0, 0x1e78,
+ 0x96e1, 0x0eef,
+ 0x96f7, 0x1935,
+ 0x96f8, 0x1e79,
+ 0x96f9, 0x0f07,
+ 0x96fa, 0x1e7a,
+ 0x96fb, 0x0f09,
+ 0x96fc, 0x1e7b,
+ 0x9740, 0x0f0b,
+ 0x9751, 0x1e7c,
+ 0x9752, 0x0f1d,
+ 0x976f, 0x1e7d,
+ 0x9770, 0x0f3b,
+ 0x9773, 0x1e7e,
+ 0x9774, 0x0f3f,
+ 0x9779, 0x1d34,
+ 0x977a, 0x0f45,
+ 0x9780, 0x0f4a,
+ 0x9789, 0x1e7f,
+ 0x978a, 0x0f54,
+ 0x97c9, 0x1e80,
+ 0x97ca, 0x0f94,
+ 0x97f8, 0x1e81,
+ 0x97fa, 0x0fc4,
+ 0x9840, 0x1e83,
+ 0x9841, 0x0fc8,
+ 0x9850, 0x1e84,
+ 0x9851, 0x0fd8,
+ 0x9855, 0x1777,
+ 0x9856, 0x0fdd,
+ 0x9858, 0x1e85,
+ 0x9859, 0x0fe0,
+ 0x989f, 0x0ffa,
+ 0x98d4, 0x0ea7,
+ 0x98d5, 0x1030,
+ 0x9940, 0x1058,
+ 0x995c, 0x1e86,
+ 0x995d, 0x1075,
+ 0x9966, 0x1e87,
+ 0x9967, 0x107f,
+ 0x996a, 0x1e88,
+ 0x996b, 0x1083,
+ 0x996c, 0x1e89,
+ 0x996d, 0x1085,
+ 0x9980, 0x1097,
+ 0x9a40, 0x1114,
+ 0x9a4f, 0x1e8a,
+ 0x9a50, 0x1124,
+ 0x9a59, 0x1e8b,
+ 0x9a5a, 0x112e,
+ 0x9a6f, 0x1e8c,
+ 0x9a70, 0x1144,
+ 0x9a7d, 0x1e8d,
+ 0x9a7e, 0x1152,
+ 0x9a80, 0x1153,
+ 0x9a8b, 0x1e8e,
+ 0x9a8c, 0x115f,
+ 0x9ac2, 0x1e8f,
+ 0x9ac3, 0x1196,
+ 0x9ae2, 0x0bf7,
+ 0x9ae3, 0x11b6,
+ 0x9b40, 0x11d0,
+ 0x9b5c, 0x1e90,
+ 0x9b5d, 0x11ed,
+ 0x9b80, 0x120f,
+ 0x9b83, 0x1e91,
+ 0x9b84, 0x1213,
+ 0x9ba0, 0x1e92,
+ 0x9ba1, 0x1230,
+ 0x9bf0, 0x1e93,
+ 0x9bf1, 0x1280,
+ 0x9c40, 0x128c,
+ 0x9c80, 0x12cb,
+ 0x9ca2, 0x1e94,
+ 0x9ca3, 0x12ee,
+ 0x9d40, 0x1348,
+ 0x9d80, 0x1e95,
+ 0x9d81, 0x1388,
+ 0x9d8c, 0x1e96,
+ 0x9d8d, 0x1394,
+ 0x9d98, 0x05a7,
+ 0x9d99, 0x13a0,
+ 0x9db7, 0x1e97,
+ 0x9db8, 0x13bf,
+ 0x9dcb, 0x1e98,
+ 0x9dcc, 0x13d3,
+ 0x9e40, 0x1404,
+ 0x9e64, 0x1e99,
+ 0x9e65, 0x1429,
+ 0x9e69, 0x1e9a,
+ 0x9e6a, 0x142e,
+ 0x9e77, 0x0da2,
+ 0x9e78, 0x143c,
+ 0x9e80, 0x1443,
+ 0x9e8b, 0x1e9b,
+ 0x9e8c, 0x144f,
+ 0x9e8d, 0x0c68,
+ 0x9e8e, 0x1451,
+ 0x9e94, 0x1e9c,
+ 0x9e95, 0x1458,
+ 0x9f40, 0x14c0,
+ 0x9f80, 0x14ff,
+ 0x9fb7, 0x0c6d,
+ 0x9fb8, 0x1537,
+ 0x9fce, 0x1e9d,
+ 0x9fcf, 0x154e,
+ 0x9ff3, 0x05ff,
+ 0x9ff4, 0x1573,
+ 0xe040, 0x157c,
+ 0xe080, 0x15bb,
+ 0xe093, 0x1e9e,
+ 0xe094, 0x15cf,
+ 0xe0a4, 0x1e9f,
+ 0xe0a5, 0x15e0,
+ 0xe0dd, 0x1ea0,
+ 0xe0de, 0x1619,
+ 0xe0f4, 0x1d35,
+ 0xe0f5, 0x1630,
+ 0xe140, 0x1638,
+ 0xe14a, 0x1ea1,
+ 0xe14b, 0x1643,
+ 0xe14f, 0x1ea2,
+ 0xe151, 0x1649,
+ 0xe180, 0x1677,
+ 0xe1a9, 0x1ea4,
+ 0xe1aa, 0x16a1,
+ 0xe1e6, 0x07ee,
+ 0xe1e7, 0x16de,
+ 0xe1e8, 0x0c51,
+ 0xe1e9, 0x16e0,
+ 0xe1ed, 0x1ea5,
+ 0xe1ee, 0x16e5,
+ 0xe240, 0x16f4,
+ 0xe269, 0x1ea6,
+ 0xe26a, 0x171e,
+ 0xe273, 0x1ea7,
+ 0xe274, 0x1728,
+ 0xe27d, 0x05d4,
+ 0xe27e, 0x1732,
+ 0xe280, 0x1733,
+ 0xe2b7, 0x1ea8,
+ 0xe2b8, 0x176b,
+ 0xe2c4, 0x0fdc,
+ 0xe2c5, 0x1778,
+ 0xe2e2, 0x1ea9,
+ 0xe2e3, 0x1796,
+ 0xe2ec, 0x1eaa,
+ 0xe2ed, 0x17a0,
+ 0xe340, 0x17b0,
+ 0xe358, 0x1eab,
+ 0xe359, 0x17c9,
+ 0xe35a, 0x1eac,
+ 0xe35b, 0x17cb,
+ 0xe365, 0x1ead,
+ 0xe366, 0x17d6,
+ 0xe380, 0x17ef,
+ 0xe3c4, 0x1eae,
+ 0xe3c5, 0x1834,
+ 0xe440, 0x186c,
+ 0xe480, 0x18ab,
+ 0xe484, 0x1eaf,
+ 0xe485, 0x18b0,
+ 0xe489, 0x1eb0,
+ 0xe48a, 0x18b5,
+ 0xe492, 0x1eb1,
+ 0xe493, 0x18be,
+ 0xe4b2, 0x1eb2,
+ 0xe4b3, 0x18de,
+ 0xe4b9, 0x1eb3,
+ 0xe4ba, 0x18e5,
+ 0xe4f2, 0x1eb4,
+ 0xe4f3, 0x191e,
+ 0xe540, 0x1928,
+ 0xe541, 0x08f5,
+ 0xe542, 0x192a,
+ 0xe54d, 0x0f05,
+ 0xe54e, 0x1936,
+ 0xe55b, 0x1eb5,
+ 0xe55c, 0x1944,
+ 0xe579, 0x05a0,
+ 0xe57a, 0x1962,
+ 0xe580, 0x1967,
+ 0xe5a2, 0x0d1e,
+ 0xe5a3, 0x198a,
+ 0xe5a5, 0x1eb6,
+ 0xe5a6, 0x198d,
+ 0xe5bb, 0x1eb7,
+ 0xe5bc, 0x19a3,
+ 0xe5ed, 0x1eb8,
+ 0xe5ee, 0x19d5,
+ 0xe640, 0x19e4,
+ 0xe651, 0x1eb9,
+ 0xe652, 0x19f6,
+ 0xe67c, 0x060e,
+ 0xe67d, 0x1a21,
+ 0xe680, 0x1a23,
+ 0xe686, 0x1eba,
+ 0xe687, 0x1a2a,
+ 0xe696, 0x1ebb,
+ 0xe697, 0x1a3a,
+ 0xe6cb, 0x0aaa,
+ 0xe6cc, 0x1a6f,
+ 0xe6e7, 0x1ebc,
+ 0xe6e8, 0x1a8b,
+ 0xe6f2, 0x1ebd,
+ 0xe6f3, 0x1a96,
+ 0xe740, 0x1aa0,
+ 0xe76d, 0x1ebe,
+ 0xe76e, 0x1ace,
+ 0xe780, 0x1adf,
+ 0xe78c, 0x1ebf,
+ 0xe78d, 0x1aec,
+ 0xe78e, 0x1ec0,
+ 0xe78f, 0x1aee,
+ 0xe7a7, 0x1ec1,
+ 0xe7a8, 0x1b07,
+ 0xe7bb, 0x1ec2,
+ 0xe7bc, 0x1b1b,
+ 0xe7d5, 0x1ec3,
+ 0xe7d6, 0x1b35,
+ 0xe840, 0x1b5c,
+ 0xe880, 0x1b9b,
+ 0xe885, 0x1ec4,
+ 0xe886, 0x1ba1,
+ 0xe8b1, 0x1ec5,
+ 0xe8b2, 0x1bcd,
+ 0xe8c3, 0x1ec6,
+ 0xe8c4, 0x1bdf,
+ 0xe8cf, 0x1ec7,
+ 0xe8d0, 0x1beb,
+ 0xe8d5, 0x1ec8,
+ 0xe8d6, 0x1bf1,
+ 0xe8f2, 0x0731,
+ 0xe8f3, 0x1ec9,
+ 0xe8f4, 0x1c0f,
+ 0xe940, 0x1c18,
+ 0xe980, 0x1c57,
+ 0xe9ab, 0x1eca,
+ 0xe9ac, 0x1c83,
+ 0xe9ba, 0x1ecb,
+ 0xe9bb, 0x1c92,
+ 0xe9cb, 0x0477,
+ 0xe9cc, 0x1ecc,
+ 0xe9cd, 0x1ca4,
+ 0xe9f2, 0x0529,
+ 0xe9f3, 0x1cca,
+ 0xea40, 0x1cd4,
+ 0xea70, 0x1ecd,
+ 0xea71, 0x1d05,
+ 0xea80, 0x1d13,
+ 0xea9d, 0x1ece,
+ 0xea9e, 0x1d31,
+ 0xed40, 0x20a7,
+ 0xed80, 0x20e6,
+ 0xedb4, 0x07c9,
+ 0xedb5, 0x211a,
+ 0xee40, 0x2162,
+ 0xee80, 0x21a1,
+ 0xeeef, 0x1f9c,
+ 0xeef9, 0x02ef,
+ 0xeefa, 0x1f45,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 japan12ExtRKSJHEnc16 = {
+ 0,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee,
+ 0x00ef, 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6,
+ 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe,
+ 0x00ff, 0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106,
+ 0x0107, 0x0108, 0x0109, 0x010a, 0x010b, 0x010c, 0x010d, 0x010e,
+ 0x010f, 0x0110, 0x0111, 0x0112, 0x0113, 0x0114, 0x0115, 0x0116,
+ 0x0117, 0x0118, 0x0119, 0x011a, 0x011b, 0x011c, 0x011d, 0x011e,
+ 0x011f, 0x0120, 0x0121, 0x0122, 0x0123, 0x0124, 0x0125, 0x0126,
+ 0x0127, 0x0128, 0x0129, 0x012a, 0x012b, 0x012c, 0x012d, 0x012e,
+ 0x012f, 0x0130, 0x0131, 0x0132, 0x0133, 0x0134, 0x0135, 0x0136,
+ 0x0137, 0x0138, 0x0139, 0x013a, 0x013b, 0x013c, 0x013d, 0x013e,
+ 0x013f, 0x0140, 0x0141, 0x0142, 0x0143, 0x0144, 0x0145, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0146, 0x0147, 0x0148, 0x0149, 0x014a, 0x014b, 0x014c, 0x014d,
+ 0x014e, 0x014f, 0x0150, 0x0151, 0x0152, 0x0153, 0x0154, 0x0155,
+ 0x0156, 0x0157, 0x0158, 0x0159, 0x015a, 0x015b, 0x015c, 0x015d,
+ 0x015e, 0x015f, 0x0160, 0x0161, 0x0162, 0x0163, 0x0164, 0x0165,
+ 0x0166, 0x0167, 0x0168, 0x0169, 0x016a, 0x016b, 0x016c, 0x016d,
+ 0x016e, 0x016f, 0x0170, 0x0171, 0x0172, 0x0173, 0x0174, 0x0175,
+ 0x0176, 0x0177, 0x0178, 0x0179, 0x017a, 0x017b, 0x017c, 0x017d,
+ 0x017e, 0x017f, 0x0180, 0x0181, 0x0182, 0x0183, 0x0184, 0x0185,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ japan12ExtRKSJHMap2, 665
+};
+
+static Gushort japan12ExtRKSJVMap2[1408] = {
+ 0x0000, 0x0000,
+ 0x8140, 0x0279,
+ 0x8180, 0x02b8,
+ 0x8189, 0x1d36,
+ 0x818a, 0x02c2,
+ 0x824f, 0x030c,
+ 0x8260, 0x0316,
+ 0x8281, 0x0330,
+ 0x829f, 0x034a,
+ 0x8340, 0x039d,
+ 0x8380, 0x03dc,
+ 0x839f, 0x03f3,
+ 0x83bf, 0x040b,
+ 0x8440, 0x0423,
+ 0x8470, 0x0444,
+ 0x8480, 0x0453,
+ 0x8540, 0x00e8,
+ 0x8580, 0x0186,
+ 0x8581, 0x0128,
+ 0x859f, 0x0147,
+ 0x85de, 0x0187,
+ 0x8640, 0x01a6,
+ 0x8680, 0x01e5,
+ 0x8692, 0x0127,
+ 0x8693, 0x01f7,
+ 0x86a2, 0x1d37,
+ 0x8740, 0x1d83,
+ 0x875f, 0x1da1,
+ 0x877e, 0x2083,
+ 0x8780, 0x1db8,
+ 0x8790, 0x02fa,
+ 0x8791, 0x02f9,
+ 0x8792, 0x0301,
+ 0x8793, 0x1dc8,
+ 0x879a, 0x0300,
+ 0x879b, 0x1dcf,
+ 0x889f, 0x0465,
+ 0x88a0, 0x1dd1,
+ 0x88a1, 0x0467,
+ 0x88b1, 0x1ca2,
+ 0x88b2, 0x0478,
+ 0x88b9, 0x1dd2,
+ 0x88ba, 0x0480,
+ 0x88ec, 0x1dd3,
+ 0x88ed, 0x04b3,
+ 0x88f1, 0x1dd4,
+ 0x88f2, 0x04b8,
+ 0x88fa, 0x1dd5,
+ 0x88fb, 0x04c1,
+ 0x8940, 0x04c3,
+ 0x8949, 0x1dd6,
+ 0x894a, 0x04cd,
+ 0x8954, 0x1dd7,
+ 0x8955, 0x04d8,
+ 0x8958, 0x1dd8,
+ 0x8959, 0x04dc,
+ 0x895b, 0x1dd9,
+ 0x895d, 0x04e0,
+ 0x8961, 0x1ddb,
+ 0x8962, 0x04e5,
+ 0x8980, 0x0502,
+ 0x898b, 0x1ddc,
+ 0x898c, 0x050e,
+ 0x89a6, 0x1ddd,
+ 0x89a7, 0x1cc9,
+ 0x89a8, 0x1dde,
+ 0x89a9, 0x052b,
+ 0x89de, 0x1ddf,
+ 0x89df, 0x0561,
+ 0x89f8, 0x1de0,
+ 0x89f9, 0x057b,
+ 0x89fb, 0x1de1,
+ 0x89fc, 0x057e,
+ 0x8a40, 0x057f,
+ 0x8a41, 0x1de2,
+ 0x8a42, 0x0581,
+ 0x8a61, 0x1961,
+ 0x8a62, 0x05a1,
+ 0x8a68, 0x139f,
+ 0x8a69, 0x05a8,
+ 0x8a80, 0x05be,
+ 0x8a85, 0x1de3,
+ 0x8a86, 0x05c4,
+ 0x8a8b, 0x1de4,
+ 0x8a8c, 0x05ca,
+ 0x8a93, 0x1de5,
+ 0x8a94, 0x05d2,
+ 0x8a96, 0x1731,
+ 0x8a97, 0x05d5,
+ 0x8a9a, 0x1de6,
+ 0x8a9b, 0x05d9,
+ 0x8ac0, 0x1de7,
+ 0x8ac1, 0x1572,
+ 0x8ac2, 0x0600,
+ 0x8acb, 0x1de8,
+ 0x8acc, 0x060a,
+ 0x8ad0, 0x1a20,
+ 0x8ad1, 0x060f,
+ 0x8ae3, 0x1de9,
+ 0x8ae4, 0x0622,
+ 0x8b40, 0x063b,
+ 0x8b4a, 0x1dea,
+ 0x8b4b, 0x0646,
+ 0x8b5f, 0x1deb,
+ 0x8b60, 0x065b,
+ 0x8b80, 0x067a,
+ 0x8ba0, 0x1dec,
+ 0x8ba1, 0x069b,
+ 0x8ba8, 0x1ded,
+ 0x8ba9, 0x06a3,
+ 0x8bc4, 0x1d32,
+ 0x8bc5, 0x06bf,
+ 0x8bcd, 0x1dee,
+ 0x8bce, 0x06c8,
+ 0x8beb, 0x1def,
+ 0x8bec, 0x06e6,
+ 0x8bf2, 0x1df0,
+ 0x8bf3, 0x06ed,
+ 0x8bf9, 0x1df1,
+ 0x8bfa, 0x06f4,
+ 0x8bfb, 0x1df2,
+ 0x8bfc, 0x06f6,
+ 0x8c40, 0x06f7,
+ 0x8c43, 0x1df3,
+ 0x8c44, 0x06fb,
+ 0x8c56, 0x1df4,
+ 0x8c57, 0x070e,
+ 0x8c64, 0x1df5,
+ 0x8c65, 0x071c,
+ 0x8c6d, 0x1df6,
+ 0x8c6e, 0x0725,
+ 0x8c71, 0x1df7,
+ 0x8c72, 0x0729,
+ 0x8c74, 0x1df8,
+ 0x8c75, 0x072c,
+ 0x8c7a, 0x1c0d,
+ 0x8c7b, 0x0732,
+ 0x8c80, 0x0736,
+ 0x8c84, 0x1df9,
+ 0x8c85, 0x073b,
+ 0x8c91, 0x1dfa,
+ 0x8c92, 0x0748,
+ 0x8c99, 0x1dfb,
+ 0x8c9a, 0x0750,
+ 0x8c9e, 0x1dfc,
+ 0x8c9f, 0x0755,
+ 0x8cb2, 0x1dfd,
+ 0x8cb3, 0x0769,
+ 0x8cbf, 0x1dfe,
+ 0x8cc0, 0x0776,
+ 0x8d40, 0x07b3,
+ 0x8d4a, 0x1dff,
+ 0x8d4b, 0x07be,
+ 0x8d56, 0x1e00,
+ 0x8d57, 0x07ca,
+ 0x8d61, 0x1e01,
+ 0x8d62, 0x07d5,
+ 0x8d7b, 0x16dd,
+ 0x8d7c, 0x07ef,
+ 0x8d80, 0x07f2,
+ 0x8d8d, 0x1e02,
+ 0x8d8e, 0x0800,
+ 0x8d94, 0x1e03,
+ 0x8d95, 0x0807,
+ 0x8d99, 0x1e04,
+ 0x8d9a, 0x080c,
+ 0x8dd1, 0x1e05,
+ 0x8dd2, 0x0844,
+ 0x8de5, 0x1e06,
+ 0x8de6, 0x0858,
+ 0x8df2, 0x1e07,
+ 0x8df3, 0x0865,
+ 0x8e40, 0x086f,
+ 0x8e46, 0x1e08,
+ 0x8e47, 0x0876,
+ 0x8e49, 0x1e09,
+ 0x8e4a, 0x0879,
+ 0x8e4b, 0x1e0a,
+ 0x8e4c, 0x087b,
+ 0x8e58, 0x1e0b,
+ 0x8e59, 0x0888,
+ 0x8e80, 0x08ae,
+ 0x8eb6, 0x1e0c,
+ 0x8eb7, 0x08e5,
+ 0x8ec6, 0x1e0d,
+ 0x8ec7, 0x1929,
+ 0x8ec8, 0x08f6,
+ 0x8ed5, 0x1e0e,
+ 0x8ed6, 0x0904,
+ 0x8edb, 0x1e0f,
+ 0x8edd, 0x090b,
+ 0x8f40, 0x092b,
+ 0x8f4a, 0x1e11,
+ 0x8f4b, 0x0936,
+ 0x8f55, 0x1e12,
+ 0x8f56, 0x0941,
+ 0x8f80, 0x096a,
+ 0x8f8c, 0x1e13,
+ 0x8f8e, 0x0978,
+ 0x8f92, 0x1e15,
+ 0x8f94, 0x097e,
+ 0x8fa3, 0x1e17,
+ 0x8fa4, 0x098e,
+ 0x8fb1, 0x1e18,
+ 0x8fb2, 0x099c,
+ 0x8fbd, 0x1e19,
+ 0x8fbe, 0x09a8,
+ 0x8fd3, 0x1e1a,
+ 0x8fd4, 0x09be,
+ 0x8fdd, 0x1e1b,
+ 0x8fde, 0x09c8,
+ 0x8fe2, 0x1e1c,
+ 0x8fe3, 0x09cd,
+ 0x9040, 0x09e7,
+ 0x9049, 0x1e1d,
+ 0x904a, 0x09f1,
+ 0x9078, 0x1e1e,
+ 0x9079, 0x0a20,
+ 0x9080, 0x1e1f,
+ 0x9081, 0x0a27,
+ 0x9089, 0x1e20,
+ 0x908a, 0x0a30,
+ 0x90a0, 0x1e21,
+ 0x90a1, 0x0a47,
+ 0x90c0, 0x1e22,
+ 0x90c1, 0x0a67,
+ 0x90e4, 0x1e23,
+ 0x90e5, 0x0a8b,
+ 0x90ef, 0x1e24,
+ 0x90f1, 0x0a97,
+ 0x90f7, 0x1e26,
+ 0x90f9, 0x0a9f,
+ 0x9140, 0x0aa3,
+ 0x9146, 0x1e28,
+ 0x9147, 0x1a6e,
+ 0x9148, 0x0aab,
+ 0x9158, 0x1e29,
+ 0x9159, 0x0abc,
+ 0x916b, 0x1e2a,
+ 0x916c, 0x0acf,
+ 0x916e, 0x1e2b,
+ 0x916f, 0x0ad2,
+ 0x917e, 0x1e2c,
+ 0x9180, 0x0ae2,
+ 0x9189, 0x1e2d,
+ 0x918a, 0x0aec,
+ 0x91bb, 0x1e2e,
+ 0x91bc, 0x0b1e,
+ 0x91cb, 0x1e2f,
+ 0x91cc, 0x0b2e,
+ 0x91da, 0x1e30,
+ 0x91db, 0x0b3d,
+ 0x91e1, 0x1e31,
+ 0x91e2, 0x0b44,
+ 0x91ed, 0x1e32,
+ 0x91ee, 0x0b50,
+ 0x91f3, 0x1e33,
+ 0x91f5, 0x0b57,
+ 0x91fb, 0x1e35,
+ 0x91fc, 0x0b5e,
+ 0x9240, 0x0b5f,
+ 0x9246, 0x1e36,
+ 0x9247, 0x0b66,
+ 0x9248, 0x1e37,
+ 0x924a, 0x0b69,
+ 0x924c, 0x1e39,
+ 0x924e, 0x0b6d,
+ 0x925c, 0x1e3b,
+ 0x925d, 0x0b7c,
+ 0x9280, 0x0b9e,
+ 0x9290, 0x1e3c,
+ 0x9291, 0x0baf,
+ 0x9295, 0x1e3d,
+ 0x9296, 0x0bb4,
+ 0x929c, 0x1e3e,
+ 0x929d, 0x0bbb,
+ 0x92bb, 0x1e3f,
+ 0x92bc, 0x0bda,
+ 0x92c6, 0x1e40,
+ 0x92c7, 0x0be5,
+ 0x92c8, 0x1e41,
+ 0x92c9, 0x0be7,
+ 0x92cb, 0x1e42,
+ 0x92cc, 0x0bea,
+ 0x92cd, 0x1e43,
+ 0x92ce, 0x0bec,
+ 0x92d9, 0x11b5,
+ 0x92da, 0x0bf8,
+ 0x9340, 0x0c1b,
+ 0x9341, 0x1e44,
+ 0x9342, 0x0c1d,
+ 0x9346, 0x1e45,
+ 0x9347, 0x0c22,
+ 0x934d, 0x1e46,
+ 0x934e, 0x0c29,
+ 0x9355, 0x1e47,
+ 0x9356, 0x0c31,
+ 0x935e, 0x1e48,
+ 0x935f, 0x0c3a,
+ 0x9367, 0x1e49,
+ 0x9368, 0x0c43,
+ 0x936a, 0x1e4a,
+ 0x936b, 0x0c46,
+ 0x9370, 0x1e4b,
+ 0x9372, 0x0c4d,
+ 0x9376, 0x16df,
+ 0x9377, 0x0c52,
+ 0x9380, 0x0c5a,
+ 0x9384, 0x1e4d,
+ 0x9385, 0x0c5f,
+ 0x938e, 0x1450,
+ 0x938f, 0x0c69,
+ 0x9393, 0x1536,
+ 0x9394, 0x0c6e,
+ 0x9398, 0x1e4e,
+ 0x9399, 0x0c73,
+ 0x93bc, 0x1e4f,
+ 0x93bd, 0x0c97,
+ 0x93c0, 0x1e50,
+ 0x93c1, 0x0c9b,
+ 0x93d2, 0x1e51,
+ 0x93d4, 0x0cae,
+ 0x93d9, 0x1e53,
+ 0x93db, 0x0cb5,
+ 0x93df, 0x1e55,
+ 0x93e0, 0x0cba,
+ 0x93e4, 0x1e56,
+ 0x93e6, 0x0cc0,
+ 0x93e8, 0x1e58,
+ 0x93e9, 0x0cc3,
+ 0x93f4, 0x1aed,
+ 0x93f5, 0x0ccf,
+ 0x9440, 0x0cd7,
+ 0x9448, 0x1e59,
+ 0x9449, 0x0ce0,
+ 0x9458, 0x1e5a,
+ 0x9459, 0x0cf0,
+ 0x9476, 0x1e5b,
+ 0x9477, 0x0d0e,
+ 0x9480, 0x0d16,
+ 0x9487, 0x1e5c,
+ 0x9488, 0x1989,
+ 0x9489, 0x1e5d,
+ 0x948a, 0x0d20,
+ 0x948d, 0x1e5e,
+ 0x948e, 0x0d24,
+ 0x94a2, 0x1e5f,
+ 0x94a3, 0x0d39,
+ 0x94ac, 0x1e60,
+ 0x94ad, 0x0d43,
+ 0x94ae, 0x1e61,
+ 0x94af, 0x0d45,
+ 0x94d2, 0x1e62,
+ 0x94d3, 0x0d69,
+ 0x94e0, 0x1e63,
+ 0x94e1, 0x0d77,
+ 0x94f3, 0x1e64,
+ 0x94f4, 0x0d8a,
+ 0x9540, 0x0d93,
+ 0x9541, 0x1e65,
+ 0x9543, 0x0d96,
+ 0x954e, 0x1e67,
+ 0x954f, 0x143b,
+ 0x9550, 0x0da3,
+ 0x9551, 0x1e68,
+ 0x9552, 0x0da5,
+ 0x9554, 0x1e69,
+ 0x9555, 0x0da8,
+ 0x955f, 0x1e6a,
+ 0x9560, 0x0db3,
+ 0x956d, 0x1e6b,
+ 0x956e, 0x0dc1,
+ 0x9570, 0x1e6c,
+ 0x9571, 0x0dc4,
+ 0x9580, 0x0dd2,
+ 0x95c1, 0x1e6d,
+ 0x95c2, 0x0e14,
+ 0x95cb, 0x1e6e,
+ 0x95cc, 0x0e1e,
+ 0x95d8, 0x1e6f,
+ 0x95d9, 0x0e2b,
+ 0x95f7, 0x1e70,
+ 0x95f8, 0x0e4a,
+ 0x9640, 0x0e4f,
+ 0x9641, 0x1e71,
+ 0x9642, 0x0e51,
+ 0x9648, 0x1e72,
+ 0x9649, 0x0e58,
+ 0x966a, 0x1e73,
+ 0x966b, 0x0e7a,
+ 0x9680, 0x0e8e,
+ 0x968a, 0x1d33,
+ 0x968b, 0x0e99,
+ 0x9690, 0x1e74,
+ 0x9691, 0x0e9f,
+ 0x9699, 0x102f,
+ 0x969a, 0x0ea8,
+ 0x96cb, 0x1e75,
+ 0x96cc, 0x0eda,
+ 0x96d7, 0x1e76,
+ 0x96d8, 0x0ee6,
+ 0x96dd, 0x1e77,
+ 0x96de, 0x0eec,
+ 0x96e0, 0x1e78,
+ 0x96e1, 0x0eef,
+ 0x96f7, 0x1935,
+ 0x96f8, 0x1e79,
+ 0x96f9, 0x0f07,
+ 0x96fa, 0x1e7a,
+ 0x96fb, 0x0f09,
+ 0x96fc, 0x1e7b,
+ 0x9740, 0x0f0b,
+ 0x9751, 0x1e7c,
+ 0x9752, 0x0f1d,
+ 0x976f, 0x1e7d,
+ 0x9770, 0x0f3b,
+ 0x9773, 0x1e7e,
+ 0x9774, 0x0f3f,
+ 0x9779, 0x1d34,
+ 0x977a, 0x0f45,
+ 0x9780, 0x0f4a,
+ 0x9789, 0x1e7f,
+ 0x978a, 0x0f54,
+ 0x97c9, 0x1e80,
+ 0x97ca, 0x0f94,
+ 0x97f8, 0x1e81,
+ 0x97fa, 0x0fc4,
+ 0x9840, 0x1e83,
+ 0x9841, 0x0fc8,
+ 0x9850, 0x1e84,
+ 0x9851, 0x0fd8,
+ 0x9855, 0x1777,
+ 0x9856, 0x0fdd,
+ 0x9858, 0x1e85,
+ 0x9859, 0x0fe0,
+ 0x989f, 0x0ffa,
+ 0x98d4, 0x0ea7,
+ 0x98d5, 0x1030,
+ 0x9940, 0x1058,
+ 0x995c, 0x1e86,
+ 0x995d, 0x1075,
+ 0x9966, 0x1e87,
+ 0x9967, 0x107f,
+ 0x996a, 0x1e88,
+ 0x996b, 0x1083,
+ 0x996c, 0x1e89,
+ 0x996d, 0x1085,
+ 0x9980, 0x1097,
+ 0x9a40, 0x1114,
+ 0x9a4f, 0x1e8a,
+ 0x9a50, 0x1124,
+ 0x9a59, 0x1e8b,
+ 0x9a5a, 0x112e,
+ 0x9a6f, 0x1e8c,
+ 0x9a70, 0x1144,
+ 0x9a7d, 0x1e8d,
+ 0x9a7e, 0x1152,
+ 0x9a80, 0x1153,
+ 0x9a8b, 0x1e8e,
+ 0x9a8c, 0x115f,
+ 0x9ac2, 0x1e8f,
+ 0x9ac3, 0x1196,
+ 0x9ae2, 0x0bf7,
+ 0x9ae3, 0x11b6,
+ 0x9b40, 0x11d0,
+ 0x9b5c, 0x1e90,
+ 0x9b5d, 0x11ed,
+ 0x9b80, 0x120f,
+ 0x9b83, 0x1e91,
+ 0x9b84, 0x1213,
+ 0x9ba0, 0x1e92,
+ 0x9ba1, 0x1230,
+ 0x9bf0, 0x1e93,
+ 0x9bf1, 0x1280,
+ 0x9c40, 0x128c,
+ 0x9c80, 0x12cb,
+ 0x9ca2, 0x1e94,
+ 0x9ca3, 0x12ee,
+ 0x9d40, 0x1348,
+ 0x9d80, 0x1e95,
+ 0x9d81, 0x1388,
+ 0x9d8c, 0x1e96,
+ 0x9d8d, 0x1394,
+ 0x9d98, 0x05a7,
+ 0x9d99, 0x13a0,
+ 0x9db7, 0x1e97,
+ 0x9db8, 0x13bf,
+ 0x9dcb, 0x1e98,
+ 0x9dcc, 0x13d3,
+ 0x9e40, 0x1404,
+ 0x9e64, 0x1e99,
+ 0x9e65, 0x1429,
+ 0x9e69, 0x1e9a,
+ 0x9e6a, 0x142e,
+ 0x9e77, 0x0da2,
+ 0x9e78, 0x143c,
+ 0x9e80, 0x1443,
+ 0x9e8b, 0x1e9b,
+ 0x9e8c, 0x144f,
+ 0x9e8d, 0x0c68,
+ 0x9e8e, 0x1451,
+ 0x9e94, 0x1e9c,
+ 0x9e95, 0x1458,
+ 0x9f40, 0x14c0,
+ 0x9f80, 0x14ff,
+ 0x9fb7, 0x0c6d,
+ 0x9fb8, 0x1537,
+ 0x9fce, 0x1e9d,
+ 0x9fcf, 0x154e,
+ 0x9ff3, 0x05ff,
+ 0x9ff4, 0x1573,
+ 0xe040, 0x157c,
+ 0xe080, 0x15bb,
+ 0xe093, 0x1e9e,
+ 0xe094, 0x15cf,
+ 0xe0a4, 0x1e9f,
+ 0xe0a5, 0x15e0,
+ 0xe0dd, 0x1ea0,
+ 0xe0de, 0x1619,
+ 0xe0f4, 0x1d35,
+ 0xe0f5, 0x1630,
+ 0xe140, 0x1638,
+ 0xe14a, 0x1ea1,
+ 0xe14b, 0x1643,
+ 0xe14f, 0x1ea2,
+ 0xe151, 0x1649,
+ 0xe180, 0x1677,
+ 0xe1a9, 0x1ea4,
+ 0xe1aa, 0x16a1,
+ 0xe1e6, 0x07ee,
+ 0xe1e7, 0x16de,
+ 0xe1e8, 0x0c51,
+ 0xe1e9, 0x16e0,
+ 0xe1ed, 0x1ea5,
+ 0xe1ee, 0x16e5,
+ 0xe240, 0x16f4,
+ 0xe269, 0x1ea6,
+ 0xe26a, 0x171e,
+ 0xe273, 0x1ea7,
+ 0xe274, 0x1728,
+ 0xe27d, 0x05d4,
+ 0xe27e, 0x1732,
+ 0xe280, 0x1733,
+ 0xe2b7, 0x1ea8,
+ 0xe2b8, 0x176b,
+ 0xe2c4, 0x0fdc,
+ 0xe2c5, 0x1778,
+ 0xe2e2, 0x1ea9,
+ 0xe2e3, 0x1796,
+ 0xe2ec, 0x1eaa,
+ 0xe2ed, 0x17a0,
+ 0xe340, 0x17b0,
+ 0xe358, 0x1eab,
+ 0xe359, 0x17c9,
+ 0xe35a, 0x1eac,
+ 0xe35b, 0x17cb,
+ 0xe365, 0x1ead,
+ 0xe366, 0x17d6,
+ 0xe380, 0x17ef,
+ 0xe3c4, 0x1eae,
+ 0xe3c5, 0x1834,
+ 0xe440, 0x186c,
+ 0xe480, 0x18ab,
+ 0xe484, 0x1eaf,
+ 0xe485, 0x18b0,
+ 0xe489, 0x1eb0,
+ 0xe48a, 0x18b5,
+ 0xe492, 0x1eb1,
+ 0xe493, 0x18be,
+ 0xe4b2, 0x1eb2,
+ 0xe4b3, 0x18de,
+ 0xe4b9, 0x1eb3,
+ 0xe4ba, 0x18e5,
+ 0xe4f2, 0x1eb4,
+ 0xe4f3, 0x191e,
+ 0xe540, 0x1928,
+ 0xe541, 0x08f5,
+ 0xe542, 0x192a,
+ 0xe54d, 0x0f05,
+ 0xe54e, 0x1936,
+ 0xe55b, 0x1eb5,
+ 0xe55c, 0x1944,
+ 0xe579, 0x05a0,
+ 0xe57a, 0x1962,
+ 0xe580, 0x1967,
+ 0xe5a2, 0x0d1e,
+ 0xe5a3, 0x198a,
+ 0xe5a5, 0x1eb6,
+ 0xe5a6, 0x198d,
+ 0xe5bb, 0x1eb7,
+ 0xe5bc, 0x19a3,
+ 0xe5ed, 0x1eb8,
+ 0xe5ee, 0x19d5,
+ 0xe640, 0x19e4,
+ 0xe651, 0x1eb9,
+ 0xe652, 0x19f6,
+ 0xe67c, 0x060e,
+ 0xe67d, 0x1a21,
+ 0xe680, 0x1a23,
+ 0xe686, 0x1eba,
+ 0xe687, 0x1a2a,
+ 0xe696, 0x1ebb,
+ 0xe697, 0x1a3a,
+ 0xe6cb, 0x0aaa,
+ 0xe6cc, 0x1a6f,
+ 0xe6e7, 0x1ebc,
+ 0xe6e8, 0x1a8b,
+ 0xe6f2, 0x1ebd,
+ 0xe6f3, 0x1a96,
+ 0xe740, 0x1aa0,
+ 0xe76d, 0x1ebe,
+ 0xe76e, 0x1ace,
+ 0xe780, 0x1adf,
+ 0xe78c, 0x1ebf,
+ 0xe78d, 0x1aec,
+ 0xe78e, 0x1ec0,
+ 0xe78f, 0x1aee,
+ 0xe7a7, 0x1ec1,
+ 0xe7a8, 0x1b07,
+ 0xe7bb, 0x1ec2,
+ 0xe7bc, 0x1b1b,
+ 0xe7d5, 0x1ec3,
+ 0xe7d6, 0x1b35,
+ 0xe840, 0x1b5c,
+ 0xe880, 0x1b9b,
+ 0xe885, 0x1ec4,
+ 0xe886, 0x1ba1,
+ 0xe8b1, 0x1ec5,
+ 0xe8b2, 0x1bcd,
+ 0xe8c3, 0x1ec6,
+ 0xe8c4, 0x1bdf,
+ 0xe8cf, 0x1ec7,
+ 0xe8d0, 0x1beb,
+ 0xe8d5, 0x1ec8,
+ 0xe8d6, 0x1bf1,
+ 0xe8f2, 0x0731,
+ 0xe8f3, 0x1ec9,
+ 0xe8f4, 0x1c0f,
+ 0xe940, 0x1c18,
+ 0xe980, 0x1c57,
+ 0xe9ab, 0x1eca,
+ 0xe9ac, 0x1c83,
+ 0xe9ba, 0x1ecb,
+ 0xe9bb, 0x1c92,
+ 0xe9cb, 0x0477,
+ 0xe9cc, 0x1ecc,
+ 0xe9cd, 0x1ca4,
+ 0xe9f2, 0x0529,
+ 0xe9f3, 0x1cca,
+ 0xea40, 0x1cd4,
+ 0xea70, 0x1ecd,
+ 0xea71, 0x1d05,
+ 0xea80, 0x1d13,
+ 0xea9d, 0x1ece,
+ 0xea9e, 0x1d31,
+ 0xed40, 0x20a7,
+ 0xed80, 0x20e6,
+ 0xedb4, 0x07c9,
+ 0xedb5, 0x211a,
+ 0xee40, 0x2162,
+ 0xee80, 0x21a1,
+ 0xeeef, 0x1f9c,
+ 0xeef9, 0x02ef,
+ 0xeefa, 0x1f45,
+ 0x8141, 0x1ecf,
+ 0x8143, 0x204c,
+ 0x8144, 0x2052,
+ 0x814a, 0x2050,
+ 0x814b, 0x204f,
+ 0x815b, 0x1ed3,
+ 0x8160, 0x1ed6,
+ 0x8165, 0x2059,
+ 0x8166, 0x2054,
+ 0x8167, 0x2057,
+ 0x8168, 0x2056,
+ 0x8169, 0x1edb,
+ 0x818b, 0x204d,
+ 0x818c, 0x2051,
+ 0x818d, 0x205b,
+ 0x81ac, 0x204e,
+ 0x829f, 0x1eee,
+ 0x82a1, 0x1eef,
+ 0x82a3, 0x1ef0,
+ 0x82a5, 0x1ef1,
+ 0x82a7, 0x1ef2,
+ 0x82c1, 0x1ef3,
+ 0x82e1, 0x1ef4,
+ 0x82e3, 0x1ef5,
+ 0x82e5, 0x1ef6,
+ 0x82ec, 0x1ef7,
+ 0x8340, 0x1ef8,
+ 0x8342, 0x1ef9,
+ 0x8344, 0x1efa,
+ 0x8346, 0x1efb,
+ 0x8348, 0x1efc,
+ 0x8362, 0x1efd,
+ 0x8383, 0x1efe,
+ 0x8385, 0x1eff,
+ 0x8387, 0x1f00,
+ 0x838e, 0x1f01,
+ 0x8395, 0x1f02,
+ 0x875f, 0x1f04,
+ 0x8780, 0x1f14,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 japan12ExtRKSJVEnc16 = {
+ 1,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee,
+ 0x00ef, 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6,
+ 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe,
+ 0x00ff, 0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106,
+ 0x0107, 0x0108, 0x0109, 0x010a, 0x010b, 0x010c, 0x010d, 0x010e,
+ 0x010f, 0x0110, 0x0111, 0x0112, 0x0113, 0x0114, 0x0115, 0x0116,
+ 0x0117, 0x0118, 0x0119, 0x011a, 0x011b, 0x011c, 0x011d, 0x011e,
+ 0x011f, 0x0120, 0x0121, 0x0122, 0x0123, 0x0124, 0x0125, 0x0126,
+ 0x0127, 0x0128, 0x0129, 0x012a, 0x012b, 0x012c, 0x012d, 0x012e,
+ 0x012f, 0x0130, 0x0131, 0x0132, 0x0133, 0x0134, 0x0135, 0x0136,
+ 0x0137, 0x0138, 0x0139, 0x013a, 0x013b, 0x013c, 0x013d, 0x013e,
+ 0x013f, 0x0140, 0x0141, 0x0142, 0x0143, 0x0144, 0x0145, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0146, 0x0147, 0x0148, 0x0149, 0x014a, 0x014b, 0x014c, 0x014d,
+ 0x014e, 0x014f, 0x0150, 0x0151, 0x0152, 0x0153, 0x0154, 0x0155,
+ 0x0156, 0x0157, 0x0158, 0x0159, 0x015a, 0x015b, 0x015c, 0x015d,
+ 0x015e, 0x015f, 0x0160, 0x0161, 0x0162, 0x0163, 0x0164, 0x0165,
+ 0x0166, 0x0167, 0x0168, 0x0169, 0x016a, 0x016b, 0x016c, 0x016d,
+ 0x016e, 0x016f, 0x0170, 0x0171, 0x0172, 0x0173, 0x0174, 0x0175,
+ 0x0176, 0x0177, 0x0178, 0x0179, 0x017a, 0x017b, 0x017c, 0x017d,
+ 0x017e, 0x017f, 0x0180, 0x0181, 0x0182, 0x0183, 0x0184, 0x0185,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ japan12ExtRKSJVMap2, 704
+};
+
+static Gushort japan12ExtVMap2[1404] = {
+ 0x0000, 0x0000,
+ 0x2121, 0x0279,
+ 0x2169, 0x1d36,
+ 0x216a, 0x02c2,
+ 0x2221, 0x02d7,
+ 0x2330, 0x030c,
+ 0x2341, 0x0316,
+ 0x2361, 0x0330,
+ 0x2421, 0x034a,
+ 0x2521, 0x039d,
+ 0x2621, 0x03f3,
+ 0x2641, 0x040b,
+ 0x2721, 0x0423,
+ 0x2751, 0x0444,
+ 0x2921, 0x00e8,
+ 0x2960, 0x0186,
+ 0x2961, 0x0128,
+ 0x2a21, 0x0147,
+ 0x2a60, 0x0187,
+ 0x2b21, 0x01a6,
+ 0x2b72, 0x0127,
+ 0x2b73, 0x01f7,
+ 0x2c24, 0x1d37,
+ 0x2d21, 0x1d83,
+ 0x2d40, 0x1da1,
+ 0x2d5f, 0x2083,
+ 0x2d60, 0x1db8,
+ 0x2d70, 0x02fa,
+ 0x2d71, 0x02f9,
+ 0x2d72, 0x0301,
+ 0x2d73, 0x1dc8,
+ 0x2d7a, 0x0300,
+ 0x2d7b, 0x1dcf,
+ 0x3021, 0x0465,
+ 0x3022, 0x1dd1,
+ 0x3023, 0x0467,
+ 0x3033, 0x1ca2,
+ 0x3034, 0x0478,
+ 0x303b, 0x1dd2,
+ 0x303c, 0x0480,
+ 0x306e, 0x1dd3,
+ 0x306f, 0x04b3,
+ 0x3073, 0x1dd4,
+ 0x3074, 0x04b8,
+ 0x307c, 0x1dd5,
+ 0x307d, 0x04c1,
+ 0x3121, 0x04c3,
+ 0x312a, 0x1dd6,
+ 0x312b, 0x04cd,
+ 0x3135, 0x1dd7,
+ 0x3136, 0x04d8,
+ 0x3139, 0x1dd8,
+ 0x313a, 0x04dc,
+ 0x313c, 0x1dd9,
+ 0x313e, 0x04e0,
+ 0x3142, 0x1ddb,
+ 0x3143, 0x04e5,
+ 0x316b, 0x1ddc,
+ 0x316c, 0x050e,
+ 0x3221, 0x0521,
+ 0x3228, 0x1ddd,
+ 0x3229, 0x1cc9,
+ 0x322a, 0x1dde,
+ 0x322b, 0x052b,
+ 0x3260, 0x1ddf,
+ 0x3261, 0x0561,
+ 0x327a, 0x1de0,
+ 0x327b, 0x057b,
+ 0x327d, 0x1de1,
+ 0x327e, 0x057e,
+ 0x3321, 0x057f,
+ 0x3322, 0x1de2,
+ 0x3323, 0x0581,
+ 0x3342, 0x1961,
+ 0x3343, 0x05a1,
+ 0x3349, 0x139f,
+ 0x334a, 0x05a8,
+ 0x3365, 0x1de3,
+ 0x3366, 0x05c4,
+ 0x336b, 0x1de4,
+ 0x336c, 0x05ca,
+ 0x3373, 0x1de5,
+ 0x3374, 0x05d2,
+ 0x3376, 0x1731,
+ 0x3377, 0x05d5,
+ 0x337a, 0x1de6,
+ 0x337b, 0x05d9,
+ 0x3421, 0x05dd,
+ 0x3442, 0x1de7,
+ 0x3443, 0x1572,
+ 0x3444, 0x0600,
+ 0x344d, 0x1de8,
+ 0x344e, 0x060a,
+ 0x3452, 0x1a20,
+ 0x3453, 0x060f,
+ 0x3465, 0x1de9,
+ 0x3466, 0x0622,
+ 0x3521, 0x063b,
+ 0x352b, 0x1dea,
+ 0x352c, 0x0646,
+ 0x3540, 0x1deb,
+ 0x3541, 0x065b,
+ 0x3621, 0x0699,
+ 0x3622, 0x1dec,
+ 0x3623, 0x069b,
+ 0x362a, 0x1ded,
+ 0x362b, 0x06a3,
+ 0x3646, 0x1d32,
+ 0x3647, 0x06bf,
+ 0x364f, 0x1dee,
+ 0x3650, 0x06c8,
+ 0x366d, 0x1def,
+ 0x366e, 0x06e6,
+ 0x3674, 0x1df0,
+ 0x3675, 0x06ed,
+ 0x367b, 0x1df1,
+ 0x367c, 0x06f4,
+ 0x367d, 0x1df2,
+ 0x367e, 0x06f6,
+ 0x3721, 0x06f7,
+ 0x3724, 0x1df3,
+ 0x3725, 0x06fb,
+ 0x3737, 0x1df4,
+ 0x3738, 0x070e,
+ 0x3745, 0x1df5,
+ 0x3746, 0x071c,
+ 0x374e, 0x1df6,
+ 0x374f, 0x0725,
+ 0x3752, 0x1df7,
+ 0x3753, 0x0729,
+ 0x3755, 0x1df8,
+ 0x3756, 0x072c,
+ 0x375b, 0x1c0d,
+ 0x375c, 0x0732,
+ 0x3764, 0x1df9,
+ 0x3765, 0x073b,
+ 0x3771, 0x1dfa,
+ 0x3772, 0x0748,
+ 0x3779, 0x1dfb,
+ 0x377a, 0x0750,
+ 0x377e, 0x1dfc,
+ 0x3821, 0x0755,
+ 0x3834, 0x1dfd,
+ 0x3835, 0x0769,
+ 0x3841, 0x1dfe,
+ 0x3842, 0x0776,
+ 0x3921, 0x07b3,
+ 0x392b, 0x1dff,
+ 0x392c, 0x07be,
+ 0x3937, 0x1e00,
+ 0x3938, 0x07ca,
+ 0x3942, 0x1e01,
+ 0x3943, 0x07d5,
+ 0x395c, 0x16dd,
+ 0x395d, 0x07ef,
+ 0x396d, 0x1e02,
+ 0x396e, 0x0800,
+ 0x3974, 0x1e03,
+ 0x3975, 0x0807,
+ 0x3979, 0x1e04,
+ 0x397a, 0x080c,
+ 0x3a21, 0x0811,
+ 0x3a53, 0x1e05,
+ 0x3a54, 0x0844,
+ 0x3a67, 0x1e06,
+ 0x3a68, 0x0858,
+ 0x3a74, 0x1e07,
+ 0x3a75, 0x0865,
+ 0x3b21, 0x086f,
+ 0x3b27, 0x1e08,
+ 0x3b28, 0x0876,
+ 0x3b2a, 0x1e09,
+ 0x3b2b, 0x0879,
+ 0x3b2c, 0x1e0a,
+ 0x3b2d, 0x087b,
+ 0x3b39, 0x1e0b,
+ 0x3b3a, 0x0888,
+ 0x3c21, 0x08cd,
+ 0x3c38, 0x1e0c,
+ 0x3c39, 0x08e5,
+ 0x3c48, 0x1e0d,
+ 0x3c49, 0x1929,
+ 0x3c4a, 0x08f6,
+ 0x3c57, 0x1e0e,
+ 0x3c58, 0x0904,
+ 0x3c5d, 0x1e0f,
+ 0x3c5f, 0x090b,
+ 0x3d21, 0x092b,
+ 0x3d2b, 0x1e11,
+ 0x3d2c, 0x0936,
+ 0x3d36, 0x1e12,
+ 0x3d37, 0x0941,
+ 0x3d6c, 0x1e13,
+ 0x3d6e, 0x0978,
+ 0x3d72, 0x1e15,
+ 0x3d74, 0x097e,
+ 0x3e21, 0x0989,
+ 0x3e25, 0x1e17,
+ 0x3e26, 0x098e,
+ 0x3e33, 0x1e18,
+ 0x3e34, 0x099c,
+ 0x3e3f, 0x1e19,
+ 0x3e40, 0x09a8,
+ 0x3e55, 0x1e1a,
+ 0x3e56, 0x09be,
+ 0x3e5f, 0x1e1b,
+ 0x3e60, 0x09c8,
+ 0x3e64, 0x1e1c,
+ 0x3e65, 0x09cd,
+ 0x3f21, 0x09e7,
+ 0x3f2a, 0x1e1d,
+ 0x3f2b, 0x09f1,
+ 0x3f59, 0x1e1e,
+ 0x3f5a, 0x0a20,
+ 0x3f60, 0x1e1f,
+ 0x3f61, 0x0a27,
+ 0x3f69, 0x1e20,
+ 0x3f6a, 0x0a30,
+ 0x4021, 0x0a45,
+ 0x4022, 0x1e21,
+ 0x4023, 0x0a47,
+ 0x4042, 0x1e22,
+ 0x4043, 0x0a67,
+ 0x4066, 0x1e23,
+ 0x4067, 0x0a8b,
+ 0x4071, 0x1e24,
+ 0x4073, 0x0a97,
+ 0x4079, 0x1e26,
+ 0x407b, 0x0a9f,
+ 0x4121, 0x0aa3,
+ 0x4127, 0x1e28,
+ 0x4128, 0x1a6e,
+ 0x4129, 0x0aab,
+ 0x4139, 0x1e29,
+ 0x413a, 0x0abc,
+ 0x414c, 0x1e2a,
+ 0x414d, 0x0acf,
+ 0x414f, 0x1e2b,
+ 0x4150, 0x0ad2,
+ 0x415f, 0x1e2c,
+ 0x4160, 0x0ae2,
+ 0x4169, 0x1e2d,
+ 0x416a, 0x0aec,
+ 0x4221, 0x0b01,
+ 0x423d, 0x1e2e,
+ 0x423e, 0x0b1e,
+ 0x424d, 0x1e2f,
+ 0x424e, 0x0b2e,
+ 0x425c, 0x1e30,
+ 0x425d, 0x0b3d,
+ 0x4263, 0x1e31,
+ 0x4264, 0x0b44,
+ 0x426f, 0x1e32,
+ 0x4270, 0x0b50,
+ 0x4275, 0x1e33,
+ 0x4277, 0x0b57,
+ 0x427d, 0x1e35,
+ 0x427e, 0x0b5e,
+ 0x4321, 0x0b5f,
+ 0x4327, 0x1e36,
+ 0x4328, 0x0b66,
+ 0x4329, 0x1e37,
+ 0x432b, 0x0b69,
+ 0x432d, 0x1e39,
+ 0x432f, 0x0b6d,
+ 0x433d, 0x1e3b,
+ 0x433e, 0x0b7c,
+ 0x4370, 0x1e3c,
+ 0x4371, 0x0baf,
+ 0x4375, 0x1e3d,
+ 0x4376, 0x0bb4,
+ 0x437c, 0x1e3e,
+ 0x437d, 0x0bbb,
+ 0x4421, 0x0bbd,
+ 0x443d, 0x1e3f,
+ 0x443e, 0x0bda,
+ 0x4448, 0x1e40,
+ 0x4449, 0x0be5,
+ 0x444a, 0x1e41,
+ 0x444b, 0x0be7,
+ 0x444d, 0x1e42,
+ 0x444e, 0x0bea,
+ 0x444f, 0x1e43,
+ 0x4450, 0x0bec,
+ 0x445b, 0x11b5,
+ 0x445c, 0x0bf8,
+ 0x4521, 0x0c1b,
+ 0x4522, 0x1e44,
+ 0x4523, 0x0c1d,
+ 0x4527, 0x1e45,
+ 0x4528, 0x0c22,
+ 0x452e, 0x1e46,
+ 0x452f, 0x0c29,
+ 0x4536, 0x1e47,
+ 0x4537, 0x0c31,
+ 0x453f, 0x1e48,
+ 0x4540, 0x0c3a,
+ 0x4548, 0x1e49,
+ 0x4549, 0x0c43,
+ 0x454b, 0x1e4a,
+ 0x454c, 0x0c46,
+ 0x4551, 0x1e4b,
+ 0x4553, 0x0c4d,
+ 0x4557, 0x16df,
+ 0x4558, 0x0c52,
+ 0x4564, 0x1e4d,
+ 0x4565, 0x0c5f,
+ 0x456e, 0x1450,
+ 0x456f, 0x0c69,
+ 0x4573, 0x1536,
+ 0x4574, 0x0c6e,
+ 0x4578, 0x1e4e,
+ 0x4579, 0x0c73,
+ 0x4621, 0x0c79,
+ 0x463e, 0x1e4f,
+ 0x463f, 0x0c97,
+ 0x4642, 0x1e50,
+ 0x4643, 0x0c9b,
+ 0x4654, 0x1e51,
+ 0x4656, 0x0cae,
+ 0x465b, 0x1e53,
+ 0x465d, 0x0cb5,
+ 0x4661, 0x1e55,
+ 0x4662, 0x0cba,
+ 0x4666, 0x1e56,
+ 0x4668, 0x0cc0,
+ 0x466a, 0x1e58,
+ 0x466b, 0x0cc3,
+ 0x4676, 0x1aed,
+ 0x4677, 0x0ccf,
+ 0x4721, 0x0cd7,
+ 0x4729, 0x1e59,
+ 0x472a, 0x0ce0,
+ 0x4739, 0x1e5a,
+ 0x473a, 0x0cf0,
+ 0x4757, 0x1e5b,
+ 0x4758, 0x0d0e,
+ 0x4767, 0x1e5c,
+ 0x4768, 0x1989,
+ 0x4769, 0x1e5d,
+ 0x476a, 0x0d20,
+ 0x476d, 0x1e5e,
+ 0x476e, 0x0d24,
+ 0x4821, 0x0d35,
+ 0x4824, 0x1e5f,
+ 0x4825, 0x0d39,
+ 0x482e, 0x1e60,
+ 0x482f, 0x0d43,
+ 0x4830, 0x1e61,
+ 0x4831, 0x0d45,
+ 0x4854, 0x1e62,
+ 0x4855, 0x0d69,
+ 0x4862, 0x1e63,
+ 0x4863, 0x0d77,
+ 0x4875, 0x1e64,
+ 0x4876, 0x0d8a,
+ 0x4921, 0x0d93,
+ 0x4922, 0x1e65,
+ 0x4924, 0x0d96,
+ 0x492f, 0x1e67,
+ 0x4930, 0x143b,
+ 0x4931, 0x0da3,
+ 0x4932, 0x1e68,
+ 0x4933, 0x0da5,
+ 0x4935, 0x1e69,
+ 0x4936, 0x0da8,
+ 0x4940, 0x1e6a,
+ 0x4941, 0x0db3,
+ 0x494e, 0x1e6b,
+ 0x494f, 0x0dc1,
+ 0x4951, 0x1e6c,
+ 0x4952, 0x0dc4,
+ 0x4a21, 0x0df1,
+ 0x4a43, 0x1e6d,
+ 0x4a44, 0x0e14,
+ 0x4a4d, 0x1e6e,
+ 0x4a4e, 0x0e1e,
+ 0x4a5a, 0x1e6f,
+ 0x4a5b, 0x0e2b,
+ 0x4a79, 0x1e70,
+ 0x4a7a, 0x0e4a,
+ 0x4b21, 0x0e4f,
+ 0x4b22, 0x1e71,
+ 0x4b23, 0x0e51,
+ 0x4b29, 0x1e72,
+ 0x4b2a, 0x0e58,
+ 0x4b4b, 0x1e73,
+ 0x4b4c, 0x0e7a,
+ 0x4b6a, 0x1d33,
+ 0x4b6b, 0x0e99,
+ 0x4b70, 0x1e74,
+ 0x4b71, 0x0e9f,
+ 0x4b79, 0x102f,
+ 0x4b7a, 0x0ea8,
+ 0x4c21, 0x0ead,
+ 0x4c4d, 0x1e75,
+ 0x4c4e, 0x0eda,
+ 0x4c59, 0x1e76,
+ 0x4c5a, 0x0ee6,
+ 0x4c5f, 0x1e77,
+ 0x4c60, 0x0eec,
+ 0x4c62, 0x1e78,
+ 0x4c63, 0x0eef,
+ 0x4c79, 0x1935,
+ 0x4c7a, 0x1e79,
+ 0x4c7b, 0x0f07,
+ 0x4c7c, 0x1e7a,
+ 0x4c7d, 0x0f09,
+ 0x4c7e, 0x1e7b,
+ 0x4d21, 0x0f0b,
+ 0x4d32, 0x1e7c,
+ 0x4d33, 0x0f1d,
+ 0x4d50, 0x1e7d,
+ 0x4d51, 0x0f3b,
+ 0x4d54, 0x1e7e,
+ 0x4d55, 0x0f3f,
+ 0x4d5a, 0x1d34,
+ 0x4d5b, 0x0f45,
+ 0x4d69, 0x1e7f,
+ 0x4d6a, 0x0f54,
+ 0x4e21, 0x0f69,
+ 0x4e4b, 0x1e80,
+ 0x4e4c, 0x0f94,
+ 0x4e7a, 0x1e81,
+ 0x4e7c, 0x0fc4,
+ 0x4f21, 0x1e83,
+ 0x4f22, 0x0fc8,
+ 0x4f31, 0x1e84,
+ 0x4f32, 0x0fd8,
+ 0x4f36, 0x1777,
+ 0x4f37, 0x0fdd,
+ 0x4f39, 0x1e85,
+ 0x4f3a, 0x0fe0,
+ 0x5021, 0x0ffa,
+ 0x5056, 0x0ea7,
+ 0x5057, 0x1030,
+ 0x5121, 0x1058,
+ 0x513d, 0x1e86,
+ 0x513e, 0x1075,
+ 0x5147, 0x1e87,
+ 0x5148, 0x107f,
+ 0x514b, 0x1e88,
+ 0x514c, 0x1083,
+ 0x514d, 0x1e89,
+ 0x514e, 0x1085,
+ 0x5221, 0x10b6,
+ 0x5321, 0x1114,
+ 0x5330, 0x1e8a,
+ 0x5331, 0x1124,
+ 0x533a, 0x1e8b,
+ 0x533b, 0x112e,
+ 0x5350, 0x1e8c,
+ 0x5351, 0x1144,
+ 0x535e, 0x1e8d,
+ 0x535f, 0x1152,
+ 0x536b, 0x1e8e,
+ 0x536c, 0x115f,
+ 0x5421, 0x1172,
+ 0x5444, 0x1e8f,
+ 0x5445, 0x1196,
+ 0x5464, 0x0bf7,
+ 0x5465, 0x11b6,
+ 0x5521, 0x11d0,
+ 0x553d, 0x1e90,
+ 0x553e, 0x11ed,
+ 0x5563, 0x1e91,
+ 0x5564, 0x1213,
+ 0x5621, 0x122e,
+ 0x5622, 0x1e92,
+ 0x5623, 0x1230,
+ 0x5672, 0x1e93,
+ 0x5673, 0x1280,
+ 0x5721, 0x128c,
+ 0x5821, 0x12ea,
+ 0x5824, 0x1e94,
+ 0x5825, 0x12ee,
+ 0x5921, 0x1348,
+ 0x5960, 0x1e95,
+ 0x5961, 0x1388,
+ 0x596c, 0x1e96,
+ 0x596d, 0x1394,
+ 0x5978, 0x05a7,
+ 0x5979, 0x13a0,
+ 0x5a21, 0x13a6,
+ 0x5a39, 0x1e97,
+ 0x5a3a, 0x13bf,
+ 0x5a4d, 0x1e98,
+ 0x5a4e, 0x13d3,
+ 0x5b21, 0x1404,
+ 0x5b45, 0x1e99,
+ 0x5b46, 0x1429,
+ 0x5b4a, 0x1e9a,
+ 0x5b4b, 0x142e,
+ 0x5b58, 0x0da2,
+ 0x5b59, 0x143c,
+ 0x5b6b, 0x1e9b,
+ 0x5b6c, 0x144f,
+ 0x5b6d, 0x0c68,
+ 0x5b6e, 0x1451,
+ 0x5b74, 0x1e9c,
+ 0x5b75, 0x1458,
+ 0x5c21, 0x1462,
+ 0x5d21, 0x14c0,
+ 0x5e21, 0x151e,
+ 0x5e39, 0x0c6d,
+ 0x5e3a, 0x1537,
+ 0x5e50, 0x1e9d,
+ 0x5e51, 0x154e,
+ 0x5e75, 0x05ff,
+ 0x5e76, 0x1573,
+ 0x5f21, 0x157c,
+ 0x5f73, 0x1e9e,
+ 0x5f74, 0x15cf,
+ 0x6021, 0x15da,
+ 0x6026, 0x1e9f,
+ 0x6027, 0x15e0,
+ 0x605f, 0x1ea0,
+ 0x6060, 0x1619,
+ 0x6076, 0x1d35,
+ 0x6077, 0x1630,
+ 0x6121, 0x1638,
+ 0x612b, 0x1ea1,
+ 0x612c, 0x1643,
+ 0x6130, 0x1ea2,
+ 0x6132, 0x1649,
+ 0x6221, 0x1696,
+ 0x622b, 0x1ea4,
+ 0x622c, 0x16a1,
+ 0x6268, 0x07ee,
+ 0x6269, 0x16de,
+ 0x626a, 0x0c51,
+ 0x626b, 0x16e0,
+ 0x626f, 0x1ea5,
+ 0x6270, 0x16e5,
+ 0x6321, 0x16f4,
+ 0x634a, 0x1ea6,
+ 0x634b, 0x171e,
+ 0x6354, 0x1ea7,
+ 0x6355, 0x1728,
+ 0x635e, 0x05d4,
+ 0x635f, 0x1732,
+ 0x6421, 0x1752,
+ 0x6439, 0x1ea8,
+ 0x643a, 0x176b,
+ 0x6446, 0x0fdc,
+ 0x6447, 0x1778,
+ 0x6464, 0x1ea9,
+ 0x6465, 0x1796,
+ 0x646e, 0x1eaa,
+ 0x646f, 0x17a0,
+ 0x6521, 0x17b0,
+ 0x6539, 0x1eab,
+ 0x653a, 0x17c9,
+ 0x653b, 0x1eac,
+ 0x653c, 0x17cb,
+ 0x6546, 0x1ead,
+ 0x6547, 0x17d6,
+ 0x6621, 0x180e,
+ 0x6646, 0x1eae,
+ 0x6647, 0x1834,
+ 0x6721, 0x186c,
+ 0x6764, 0x1eaf,
+ 0x6765, 0x18b0,
+ 0x6769, 0x1eb0,
+ 0x676a, 0x18b5,
+ 0x6772, 0x1eb1,
+ 0x6773, 0x18be,
+ 0x6821, 0x18ca,
+ 0x6834, 0x1eb2,
+ 0x6835, 0x18de,
+ 0x683b, 0x1eb3,
+ 0x683c, 0x18e5,
+ 0x6874, 0x1eb4,
+ 0x6875, 0x191e,
+ 0x6921, 0x1928,
+ 0x6922, 0x08f5,
+ 0x6923, 0x192a,
+ 0x692e, 0x0f05,
+ 0x692f, 0x1936,
+ 0x693c, 0x1eb5,
+ 0x693d, 0x1944,
+ 0x695a, 0x05a0,
+ 0x695b, 0x1962,
+ 0x6a21, 0x1986,
+ 0x6a24, 0x0d1e,
+ 0x6a25, 0x198a,
+ 0x6a27, 0x1eb6,
+ 0x6a28, 0x198d,
+ 0x6a3d, 0x1eb7,
+ 0x6a3e, 0x19a3,
+ 0x6a6f, 0x1eb8,
+ 0x6a70, 0x19d5,
+ 0x6b21, 0x19e4,
+ 0x6b32, 0x1eb9,
+ 0x6b33, 0x19f6,
+ 0x6b5d, 0x060e,
+ 0x6b5e, 0x1a21,
+ 0x6b66, 0x1eba,
+ 0x6b67, 0x1a2a,
+ 0x6b76, 0x1ebb,
+ 0x6b77, 0x1a3a,
+ 0x6c21, 0x1a42,
+ 0x6c4d, 0x0aaa,
+ 0x6c4e, 0x1a6f,
+ 0x6c69, 0x1ebc,
+ 0x6c6a, 0x1a8b,
+ 0x6c74, 0x1ebd,
+ 0x6c75, 0x1a96,
+ 0x6d21, 0x1aa0,
+ 0x6d4e, 0x1ebe,
+ 0x6d4f, 0x1ace,
+ 0x6d6c, 0x1ebf,
+ 0x6d6d, 0x1aec,
+ 0x6d6e, 0x1ec0,
+ 0x6d6f, 0x1aee,
+ 0x6e21, 0x1afe,
+ 0x6e29, 0x1ec1,
+ 0x6e2a, 0x1b07,
+ 0x6e3d, 0x1ec2,
+ 0x6e3e, 0x1b1b,
+ 0x6e57, 0x1ec3,
+ 0x6e58, 0x1b35,
+ 0x6f21, 0x1b5c,
+ 0x6f65, 0x1ec4,
+ 0x6f66, 0x1ba1,
+ 0x7021, 0x1bba,
+ 0x7033, 0x1ec5,
+ 0x7034, 0x1bcd,
+ 0x7045, 0x1ec6,
+ 0x7046, 0x1bdf,
+ 0x7051, 0x1ec7,
+ 0x7052, 0x1beb,
+ 0x7057, 0x1ec8,
+ 0x7058, 0x1bf1,
+ 0x7074, 0x0731,
+ 0x7075, 0x1ec9,
+ 0x7076, 0x1c0f,
+ 0x7121, 0x1c18,
+ 0x7221, 0x1c76,
+ 0x722d, 0x1eca,
+ 0x722e, 0x1c83,
+ 0x723c, 0x1ecb,
+ 0x723d, 0x1c92,
+ 0x724d, 0x0477,
+ 0x724e, 0x1ecc,
+ 0x724f, 0x1ca4,
+ 0x7274, 0x0529,
+ 0x7275, 0x1cca,
+ 0x7321, 0x1cd4,
+ 0x7351, 0x1ecd,
+ 0x7352, 0x1d05,
+ 0x737d, 0x1ece,
+ 0x737e, 0x1d31,
+ 0x7921, 0x20a7,
+ 0x7a21, 0x2105,
+ 0x7a36, 0x07c9,
+ 0x7a37, 0x211a,
+ 0x7b21, 0x2162,
+ 0x7c21, 0x21c0,
+ 0x7c71, 0x1f9c,
+ 0x7c7b, 0x02ef,
+ 0x7c7c, 0x1f45,
+ 0x2122, 0x1ecf,
+ 0x2124, 0x204c,
+ 0x2125, 0x2052,
+ 0x212b, 0x2050,
+ 0x212c, 0x204f,
+ 0x213c, 0x1ed3,
+ 0x2141, 0x1ed6,
+ 0x2146, 0x2059,
+ 0x2147, 0x2054,
+ 0x2148, 0x2057,
+ 0x2149, 0x2056,
+ 0x214a, 0x1edb,
+ 0x216b, 0x204d,
+ 0x216c, 0x2051,
+ 0x216d, 0x205b,
+ 0x222e, 0x204e,
+ 0x2421, 0x1eee,
+ 0x2423, 0x1eef,
+ 0x2425, 0x1ef0,
+ 0x2427, 0x1ef1,
+ 0x2429, 0x1ef2,
+ 0x2443, 0x1ef3,
+ 0x2463, 0x1ef4,
+ 0x2465, 0x1ef5,
+ 0x2467, 0x1ef6,
+ 0x246e, 0x1ef7,
+ 0x2521, 0x1ef8,
+ 0x2523, 0x1ef9,
+ 0x2525, 0x1efa,
+ 0x2527, 0x1efb,
+ 0x2529, 0x1efc,
+ 0x2543, 0x1efd,
+ 0x2563, 0x1efe,
+ 0x2565, 0x1eff,
+ 0x2567, 0x1f00,
+ 0x256e, 0x1f01,
+ 0x2575, 0x1f02,
+ 0x2d40, 0x1f04,
+ 0x2d60, 0x1f14,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 japan12ExtVEnc16 = {
+ 1,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ japan12ExtVMap2, 702
+};
+
+static Gushort japan12HMap2[240] = {
+ 0x0000, 0x0000,
+ 0x2121, 0x0279,
+ 0x2221, 0x02d7,
+ 0x223a, 0x02e5,
+ 0x224a, 0x02ed,
+ 0x225c, 0x02f4,
+ 0x2272, 0x0303,
+ 0x227e, 0x030b,
+ 0x2330, 0x030c,
+ 0x2341, 0x0316,
+ 0x2361, 0x0330,
+ 0x2421, 0x034a,
+ 0x2521, 0x039d,
+ 0x2621, 0x03f3,
+ 0x2641, 0x040b,
+ 0x2721, 0x0423,
+ 0x2751, 0x0444,
+ 0x2821, 0x1d37,
+ 0x2822, 0x1d39,
+ 0x2823, 0x1d43,
+ 0x2824, 0x1d47,
+ 0x2825, 0x1d4f,
+ 0x2826, 0x1d4b,
+ 0x2827, 0x1d53,
+ 0x2828, 0x1d63,
+ 0x2829, 0x1d5b,
+ 0x282a, 0x1d6b,
+ 0x282b, 0x1d73,
+ 0x282c, 0x1d38,
+ 0x282d, 0x1d3a,
+ 0x282e, 0x1d46,
+ 0x282f, 0x1d4a,
+ 0x2830, 0x1d52,
+ 0x2831, 0x1d4e,
+ 0x2832, 0x1d5a,
+ 0x2833, 0x1d6a,
+ 0x2834, 0x1d62,
+ 0x2835, 0x1d72,
+ 0x2836, 0x1d82,
+ 0x2837, 0x1d57,
+ 0x2838, 0x1d66,
+ 0x2839, 0x1d5f,
+ 0x283a, 0x1d6e,
+ 0x283b, 0x1d76,
+ 0x283c, 0x1d54,
+ 0x283d, 0x1d67,
+ 0x283e, 0x1d5c,
+ 0x283f, 0x1d6f,
+ 0x2840, 0x1d79,
+ 0x3021, 0x0465,
+ 0x3121, 0x04c3,
+ 0x3221, 0x0521,
+ 0x3321, 0x057f,
+ 0x3421, 0x05dd,
+ 0x3521, 0x063b,
+ 0x3621, 0x0699,
+ 0x3721, 0x06f7,
+ 0x3821, 0x0755,
+ 0x3921, 0x07b3,
+ 0x3a21, 0x0811,
+ 0x3b21, 0x086f,
+ 0x3c21, 0x08cd,
+ 0x3d21, 0x092b,
+ 0x3e21, 0x0989,
+ 0x3f21, 0x09e7,
+ 0x4021, 0x0a45,
+ 0x4121, 0x0aa3,
+ 0x4221, 0x0b01,
+ 0x4321, 0x0b5f,
+ 0x4421, 0x0bbd,
+ 0x4521, 0x0c1b,
+ 0x4621, 0x0c79,
+ 0x4721, 0x0cd7,
+ 0x4821, 0x0d35,
+ 0x4921, 0x0d93,
+ 0x4a21, 0x0df1,
+ 0x4b21, 0x0e4f,
+ 0x4c21, 0x0ead,
+ 0x4d21, 0x0f0b,
+ 0x4e21, 0x0f69,
+ 0x4f21, 0x0fc7,
+ 0x5021, 0x0ffa,
+ 0x5121, 0x1058,
+ 0x5221, 0x10b6,
+ 0x5321, 0x1114,
+ 0x5421, 0x1172,
+ 0x5521, 0x11d0,
+ 0x5621, 0x122e,
+ 0x5721, 0x128c,
+ 0x5821, 0x12ea,
+ 0x5921, 0x1348,
+ 0x5a21, 0x13a6,
+ 0x5b21, 0x1404,
+ 0x5c21, 0x1462,
+ 0x5d21, 0x14c0,
+ 0x5e21, 0x151e,
+ 0x5f21, 0x157c,
+ 0x6021, 0x15da,
+ 0x6121, 0x1638,
+ 0x6221, 0x1696,
+ 0x6321, 0x16f4,
+ 0x6421, 0x1752,
+ 0x6521, 0x17b0,
+ 0x6621, 0x180e,
+ 0x6721, 0x186c,
+ 0x6821, 0x18ca,
+ 0x6921, 0x1928,
+ 0x6a21, 0x1986,
+ 0x6b21, 0x19e4,
+ 0x6c21, 0x1a42,
+ 0x6d21, 0x1aa0,
+ 0x6e21, 0x1afe,
+ 0x6f21, 0x1b5c,
+ 0x7021, 0x1bba,
+ 0x7121, 0x1c18,
+ 0x7221, 0x1c76,
+ 0x7321, 0x1cd4,
+ 0x7421, 0x1d32,
+ 0x7425, 0x205c,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 japan12HEnc16 = {
+ 0,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ japan12HMap2, 120
+};
+
+static Gushort japan12HankakuMap2[4] = {
+ 0x0000, 0x0000,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 japan12HankakuEnc16 = {
+ 0,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee,
+ 0x00ef, 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6,
+ 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe,
+ 0x00ff, 0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106,
+ 0x0107, 0x0108, 0x0109, 0x010a, 0x010b, 0x010c, 0x010d, 0x010e,
+ 0x010f, 0x0110, 0x0111, 0x0112, 0x0113, 0x0114, 0x0115, 0x0116,
+ 0x0117, 0x0118, 0x0119, 0x011a, 0x011b, 0x011c, 0x011d, 0x011e,
+ 0x011f, 0x0120, 0x0121, 0x0122, 0x0123, 0x0124, 0x0125, 0x0126,
+ 0x00e7, 0x0128, 0x0129, 0x012a, 0x012b, 0x012c, 0x012d, 0x012e,
+ 0x012f, 0x0130, 0x0131, 0x0132, 0x0133, 0x0134, 0x0135, 0x0136,
+ 0x0137, 0x0138, 0x0139, 0x013a, 0x013b, 0x013c, 0x013d, 0x013e,
+ 0x013f, 0x0140, 0x0141, 0x0142, 0x0143, 0x0144, 0x0145, 0x0000,
+ 0x0000, 0x0147, 0x0148, 0x0149, 0x014a, 0x014b, 0x0204, 0x0205,
+ 0x0206, 0x0207, 0x0208, 0x0209, 0x020a, 0x020b, 0x020c, 0x020d,
+ 0x0156, 0x020e, 0x020f, 0x0210, 0x0211, 0x0212, 0x0213, 0x0214,
+ 0x0215, 0x0216, 0x0217, 0x0218, 0x0219, 0x021a, 0x021b, 0x021c,
+ 0x0000, 0x0147, 0x0148, 0x0149, 0x014a, 0x014b, 0x014c, 0x014d,
+ 0x014e, 0x014f, 0x0150, 0x0151, 0x0152, 0x0153, 0x0154, 0x0155,
+ 0x0156, 0x0157, 0x0158, 0x0159, 0x015a, 0x015b, 0x015c, 0x015d,
+ 0x015e, 0x015f, 0x0160, 0x0161, 0x0162, 0x0163, 0x0164, 0x0165,
+ 0x0166, 0x0167, 0x0168, 0x0169, 0x016a, 0x016b, 0x016c, 0x016d,
+ 0x016e, 0x016f, 0x0170, 0x0171, 0x0172, 0x0173, 0x0174, 0x0175,
+ 0x0176, 0x0177, 0x0178, 0x0179, 0x017a, 0x017b, 0x017c, 0x017d,
+ 0x017e, 0x017f, 0x0180, 0x0181, 0x0182, 0x0183, 0x0184, 0x0185,
+ 0x021d, 0x021e, 0x021f, 0x0220, 0x0221, 0x0222, 0x0223, 0x0224,
+ 0x0225, 0x0226, 0x0227, 0x0228, 0x0229, 0x022a, 0x022b, 0x022c,
+ 0x022d, 0x022e, 0x022f, 0x0230, 0x0231, 0x0232, 0x0233, 0x0234,
+ 0x0235, 0x0236, 0x0237, 0x0238, 0x0239, 0x023a, 0x0184, 0x0185 },
+ japan12HankakuMap2, 2
+};
+
+static Gushort japan12HiraganaMap2[4] = {
+ 0x0000, 0x0000,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 japan12HiraganaEnc16 = {
+ 0,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0203, 0x0147, 0x0148, 0x0149, 0x014a, 0x014b, 0x0204, 0x0205,
+ 0x0206, 0x0207, 0x0208, 0x0209, 0x020a, 0x020b, 0x020c, 0x020d,
+ 0x0156, 0x020e, 0x020f, 0x0210, 0x0211, 0x0212, 0x0213, 0x0214,
+ 0x0215, 0x0216, 0x0217, 0x0218, 0x0219, 0x021a, 0x021b, 0x021c,
+ 0x021d, 0x021e, 0x021f, 0x0220, 0x0221, 0x0222, 0x0223, 0x0224,
+ 0x0225, 0x0226, 0x0227, 0x0228, 0x0229, 0x022a, 0x022b, 0x022c,
+ 0x022d, 0x022e, 0x022f, 0x0230, 0x0231, 0x0232, 0x0233, 0x0234,
+ 0x0235, 0x0236, 0x0237, 0x0238, 0x0239, 0x023a, 0x0184, 0x0185,
+ 0x023b, 0x023c, 0x023d, 0x0000, 0x0000, 0x0000, 0x023e, 0x023f,
+ 0x0240, 0x0241, 0x0242, 0x0243, 0x0244, 0x0245, 0x0246, 0x0247,
+ 0x0248, 0x0249, 0x024a, 0x024b, 0x024c, 0x024d, 0x024e, 0x024f,
+ 0x0250, 0x0251, 0x0252, 0x0253, 0x0254, 0x0255, 0x0256, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ japan12HiraganaMap2, 2
+};
+
+static Gushort japan12KatakanaMap2[4] = {
+ 0x0000, 0x0000,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 japan12KatakanaEnc16 = {
+ 0,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0146, 0x0147, 0x0148, 0x0149, 0x014a, 0x014b, 0x014c, 0x014d,
+ 0x014e, 0x014f, 0x0150, 0x0151, 0x0152, 0x0153, 0x0154, 0x0155,
+ 0x0156, 0x0157, 0x0158, 0x0159, 0x015a, 0x015b, 0x015c, 0x015d,
+ 0x015e, 0x015f, 0x0160, 0x0161, 0x0162, 0x0163, 0x0164, 0x0165,
+ 0x0166, 0x0167, 0x0168, 0x0169, 0x016a, 0x016b, 0x016c, 0x016d,
+ 0x016e, 0x016f, 0x0170, 0x0171, 0x0172, 0x0173, 0x0174, 0x0175,
+ 0x0176, 0x0177, 0x0178, 0x0179, 0x017a, 0x017b, 0x017c, 0x017d,
+ 0x017e, 0x017f, 0x0180, 0x0181, 0x0182, 0x0183, 0x0184, 0x0185,
+ 0x0187, 0x0188, 0x0189, 0x018a, 0x018b, 0x018c, 0x018d, 0x018e,
+ 0x018f, 0x0190, 0x0191, 0x0192, 0x0193, 0x0194, 0x0195, 0x0196,
+ 0x0197, 0x0198, 0x0199, 0x019a, 0x019b, 0x019c, 0x019d, 0x019e,
+ 0x019f, 0x01a0, 0x01a1, 0x01a2, 0x01a3, 0x01a4, 0x01a5, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ japan12KatakanaMap2, 2
+};
+
+static Gushort japan12NWPHMap2[1522] = {
+ 0x0000, 0x0000,
+ 0x2121, 0x0279,
+ 0x2169, 0x1d36,
+ 0x216a, 0x02c2,
+ 0x2221, 0x02d7,
+ 0x223a, 0x02e5,
+ 0x224a, 0x02ed,
+ 0x225c, 0x02f4,
+ 0x2272, 0x0303,
+ 0x227e, 0x030b,
+ 0x2330, 0x030c,
+ 0x2341, 0x0316,
+ 0x2361, 0x0330,
+ 0x2421, 0x034a,
+ 0x2521, 0x039d,
+ 0x2621, 0x03f3,
+ 0x2641, 0x040b,
+ 0x2721, 0x0423,
+ 0x2751, 0x0444,
+ 0x2921, 0x00e8,
+ 0x2960, 0x0186,
+ 0x2961, 0x0128,
+ 0x2a21, 0x0147,
+ 0x2a60, 0x0187,
+ 0x2b21, 0x01a6,
+ 0x2b72, 0x0127,
+ 0x2b73, 0x01f7,
+ 0x2c24, 0x1d37,
+ 0x2d21, 0x1d83,
+ 0x2d40, 0x1da1,
+ 0x2d60, 0x1db8,
+ 0x2d70, 0x02fa,
+ 0x2d71, 0x02f9,
+ 0x2d72, 0x0301,
+ 0x2d73, 0x1dc8,
+ 0x2d7a, 0x0300,
+ 0x2d7b, 0x1dcf,
+ 0x2e21, 0x0282,
+ 0x2e22, 0x02a1,
+ 0x2e23, 0x0305,
+ 0x2e24, 0x02c8,
+ 0x2e25, 0x02cb,
+ 0x2e26, 0x02cd,
+ 0x2e27, 0x029f,
+ 0x2e28, 0x02a2,
+ 0x2e2a, 0x02ce,
+ 0x2e2b, 0x02b4,
+ 0x2e2c, 0x027c,
+ 0x2e2d, 0x02b5,
+ 0x2e2e, 0x027d,
+ 0x2e2f, 0x0297,
+ 0x2e30, 0x030c,
+ 0x2e3a, 0x027f,
+ 0x2e3c, 0x02bb,
+ 0x2e3d, 0x02b9,
+ 0x2e3e, 0x02bc,
+ 0x2e3f, 0x0281,
+ 0x2e40, 0x02cf,
+ 0x2e41, 0x0316,
+ 0x2e5b, 0x02a6,
+ 0x2e5c, 0x02c7,
+ 0x2e5d, 0x02a7,
+ 0x2e5e, 0x0288,
+ 0x2e5f, 0x028a,
+ 0x2e60, 0x0286,
+ 0x2e61, 0x0330,
+ 0x2e7b, 0x02a8,
+ 0x2e7c, 0x029b,
+ 0x2e7d, 0x02a9,
+ 0x2e7e, 0x0289,
+ 0x2f21, 0x027b,
+ 0x2f22, 0x02ae,
+ 0x2f24, 0x027a,
+ 0x2f25, 0x027e,
+ 0x2f26, 0x03ee,
+ 0x2f27, 0x039d,
+ 0x2f28, 0x039f,
+ 0x2f29, 0x03a1,
+ 0x2f2a, 0x03a3,
+ 0x2f2b, 0x03a5,
+ 0x2f2c, 0x03df,
+ 0x2f2d, 0x03e1,
+ 0x2f2e, 0x03e3,
+ 0x2f2f, 0x03bf,
+ 0x2f30, 0x0294,
+ 0x2f31, 0x039e,
+ 0x2f32, 0x03a0,
+ 0x2f33, 0x03a2,
+ 0x2f34, 0x03a4,
+ 0x2f35, 0x03a6,
+ 0x2f37, 0x03a9,
+ 0x2f38, 0x03ab,
+ 0x2f39, 0x03ad,
+ 0x2f3a, 0x03af,
+ 0x2f3b, 0x03b1,
+ 0x2f3c, 0x03b3,
+ 0x2f3d, 0x03b5,
+ 0x2f3e, 0x03b7,
+ 0x2f3f, 0x03b9,
+ 0x2f40, 0x03bb,
+ 0x2f41, 0x03bd,
+ 0x2f42, 0x03c0,
+ 0x2f43, 0x03c2,
+ 0x2f44, 0x03c4,
+ 0x2f45, 0x03c6,
+ 0x2f4b, 0x03ce,
+ 0x2f4c, 0x03d1,
+ 0x2f4d, 0x03d4,
+ 0x2f4e, 0x03d7,
+ 0x2f4f, 0x03da,
+ 0x2f54, 0x03e0,
+ 0x2f55, 0x03e2,
+ 0x2f56, 0x03e4,
+ 0x2f5c, 0x03eb,
+ 0x2f5d, 0x03ef,
+ 0x2f5e, 0x0283,
+ 0x2f60, 0x03ec,
+ 0x2f62, 0x03ea,
+ 0x2f63, 0x03f1,
+ 0x2f65, 0x03f0,
+ 0x2f66, 0x03a8,
+ 0x2f67, 0x03aa,
+ 0x2f68, 0x03ac,
+ 0x2f69, 0x03ae,
+ 0x2f6a, 0x03b0,
+ 0x2f6b, 0x03b2,
+ 0x2f6c, 0x03b4,
+ 0x2f6d, 0x03b6,
+ 0x2f6e, 0x03b8,
+ 0x2f6f, 0x03ba,
+ 0x2f70, 0x03bc,
+ 0x2f71, 0x03be,
+ 0x2f72, 0x03c1,
+ 0x2f73, 0x03c3,
+ 0x2f74, 0x03c5,
+ 0x2f75, 0x03cc,
+ 0x2f77, 0x03cf,
+ 0x2f79, 0x03d2,
+ 0x2f7b, 0x03d5,
+ 0x2f7d, 0x03d8,
+ 0x3021, 0x0465,
+ 0x3022, 0x1dd1,
+ 0x3023, 0x0467,
+ 0x3033, 0x1ca2,
+ 0x3034, 0x0478,
+ 0x303b, 0x1dd2,
+ 0x303c, 0x0480,
+ 0x306e, 0x1dd3,
+ 0x306f, 0x04b3,
+ 0x3073, 0x1dd4,
+ 0x3074, 0x04b8,
+ 0x307c, 0x1dd5,
+ 0x307d, 0x04c1,
+ 0x3121, 0x04c3,
+ 0x312a, 0x1dd6,
+ 0x312b, 0x04cd,
+ 0x3135, 0x1dd7,
+ 0x3136, 0x04d8,
+ 0x3139, 0x1dd8,
+ 0x313a, 0x04dc,
+ 0x313c, 0x1dd9,
+ 0x313e, 0x04e0,
+ 0x3142, 0x1ddb,
+ 0x3143, 0x04e5,
+ 0x316b, 0x1ddc,
+ 0x316c, 0x050e,
+ 0x3221, 0x0521,
+ 0x3228, 0x1ddd,
+ 0x3229, 0x1cc9,
+ 0x322a, 0x1dde,
+ 0x322b, 0x052b,
+ 0x3260, 0x1ddf,
+ 0x3261, 0x0561,
+ 0x327a, 0x1de0,
+ 0x327b, 0x057b,
+ 0x327d, 0x1de1,
+ 0x327e, 0x057e,
+ 0x3321, 0x057f,
+ 0x3322, 0x1de2,
+ 0x3323, 0x0581,
+ 0x3342, 0x1961,
+ 0x3343, 0x05a1,
+ 0x3349, 0x139f,
+ 0x334a, 0x05a8,
+ 0x3365, 0x1de3,
+ 0x3366, 0x05c4,
+ 0x336b, 0x1de4,
+ 0x336c, 0x05ca,
+ 0x3373, 0x1de5,
+ 0x3374, 0x05d2,
+ 0x3376, 0x1731,
+ 0x3377, 0x05d5,
+ 0x337a, 0x1de6,
+ 0x337b, 0x05d9,
+ 0x3421, 0x05dd,
+ 0x3442, 0x1de7,
+ 0x3443, 0x1572,
+ 0x3444, 0x0600,
+ 0x344d, 0x1de8,
+ 0x344e, 0x060a,
+ 0x3452, 0x1a20,
+ 0x3453, 0x060f,
+ 0x3465, 0x1de9,
+ 0x3466, 0x0622,
+ 0x3521, 0x063b,
+ 0x352b, 0x1dea,
+ 0x352c, 0x0646,
+ 0x3540, 0x1deb,
+ 0x3541, 0x065b,
+ 0x3621, 0x0699,
+ 0x3622, 0x1dec,
+ 0x3623, 0x069b,
+ 0x362a, 0x1ded,
+ 0x362b, 0x06a3,
+ 0x3646, 0x1d32,
+ 0x3647, 0x06bf,
+ 0x364f, 0x1dee,
+ 0x3650, 0x06c8,
+ 0x366d, 0x1def,
+ 0x366e, 0x06e6,
+ 0x3674, 0x1df0,
+ 0x3675, 0x06ed,
+ 0x367b, 0x1df1,
+ 0x367c, 0x06f4,
+ 0x367d, 0x1df2,
+ 0x367e, 0x06f6,
+ 0x3721, 0x06f7,
+ 0x3724, 0x1df3,
+ 0x3725, 0x06fb,
+ 0x3737, 0x1df4,
+ 0x3738, 0x070e,
+ 0x3745, 0x1df5,
+ 0x3746, 0x071c,
+ 0x374e, 0x1df6,
+ 0x374f, 0x0725,
+ 0x3752, 0x1df7,
+ 0x3753, 0x0729,
+ 0x3755, 0x1df8,
+ 0x3756, 0x072c,
+ 0x375b, 0x1c0d,
+ 0x375c, 0x0732,
+ 0x3764, 0x1df9,
+ 0x3765, 0x073b,
+ 0x3771, 0x1dfa,
+ 0x3772, 0x0748,
+ 0x3779, 0x1dfb,
+ 0x377a, 0x0750,
+ 0x377e, 0x1dfc,
+ 0x3821, 0x0755,
+ 0x3834, 0x1dfd,
+ 0x3835, 0x0769,
+ 0x3841, 0x1dfe,
+ 0x3842, 0x0776,
+ 0x3921, 0x07b3,
+ 0x392b, 0x1dff,
+ 0x392c, 0x07be,
+ 0x3937, 0x1e00,
+ 0x3938, 0x07ca,
+ 0x3942, 0x1e01,
+ 0x3943, 0x07d5,
+ 0x395c, 0x16dd,
+ 0x395d, 0x07ef,
+ 0x396d, 0x1e02,
+ 0x396e, 0x0800,
+ 0x3974, 0x1e03,
+ 0x3975, 0x0807,
+ 0x3979, 0x1e04,
+ 0x397a, 0x080c,
+ 0x3a21, 0x0811,
+ 0x3a53, 0x1e05,
+ 0x3a54, 0x0844,
+ 0x3a67, 0x1e06,
+ 0x3a68, 0x0858,
+ 0x3a74, 0x1e07,
+ 0x3a75, 0x0865,
+ 0x3b21, 0x086f,
+ 0x3b27, 0x1e08,
+ 0x3b28, 0x0876,
+ 0x3b2a, 0x1e09,
+ 0x3b2b, 0x0879,
+ 0x3b2c, 0x1e0a,
+ 0x3b2d, 0x087b,
+ 0x3b39, 0x1e0b,
+ 0x3b3a, 0x0888,
+ 0x3c21, 0x08cd,
+ 0x3c38, 0x1e0c,
+ 0x3c39, 0x08e5,
+ 0x3c48, 0x1e0d,
+ 0x3c49, 0x1929,
+ 0x3c4a, 0x08f6,
+ 0x3c57, 0x1e0e,
+ 0x3c58, 0x0904,
+ 0x3c5d, 0x1e0f,
+ 0x3c5f, 0x090b,
+ 0x3d21, 0x092b,
+ 0x3d2b, 0x1e11,
+ 0x3d2c, 0x0936,
+ 0x3d36, 0x1e12,
+ 0x3d37, 0x0941,
+ 0x3d6c, 0x1e13,
+ 0x3d6e, 0x0978,
+ 0x3d72, 0x1e15,
+ 0x3d74, 0x097e,
+ 0x3e21, 0x0989,
+ 0x3e25, 0x1e17,
+ 0x3e26, 0x098e,
+ 0x3e33, 0x1e18,
+ 0x3e34, 0x099c,
+ 0x3e3f, 0x1e19,
+ 0x3e40, 0x09a8,
+ 0x3e55, 0x1e1a,
+ 0x3e56, 0x09be,
+ 0x3e5f, 0x1e1b,
+ 0x3e60, 0x09c8,
+ 0x3e64, 0x1e1c,
+ 0x3e65, 0x09cd,
+ 0x3f21, 0x09e7,
+ 0x3f2a, 0x1e1d,
+ 0x3f2b, 0x09f1,
+ 0x3f59, 0x1e1e,
+ 0x3f5a, 0x0a20,
+ 0x3f60, 0x1e1f,
+ 0x3f61, 0x0a27,
+ 0x3f69, 0x1e20,
+ 0x3f6a, 0x0a30,
+ 0x4021, 0x0a45,
+ 0x4022, 0x1e21,
+ 0x4023, 0x0a47,
+ 0x4042, 0x1e22,
+ 0x4043, 0x0a67,
+ 0x4066, 0x1e23,
+ 0x4067, 0x0a8b,
+ 0x4071, 0x1e24,
+ 0x4073, 0x0a97,
+ 0x4079, 0x1e26,
+ 0x407b, 0x0a9f,
+ 0x4121, 0x0aa3,
+ 0x4127, 0x1e28,
+ 0x4128, 0x1a6e,
+ 0x4129, 0x0aab,
+ 0x4139, 0x1e29,
+ 0x413a, 0x0abc,
+ 0x414c, 0x1e2a,
+ 0x414d, 0x0acf,
+ 0x414f, 0x1e2b,
+ 0x4150, 0x0ad2,
+ 0x415f, 0x1e2c,
+ 0x4160, 0x0ae2,
+ 0x4169, 0x1e2d,
+ 0x416a, 0x0aec,
+ 0x4221, 0x0b01,
+ 0x423d, 0x1e2e,
+ 0x423e, 0x0b1e,
+ 0x424d, 0x1e2f,
+ 0x424e, 0x0b2e,
+ 0x425c, 0x1e30,
+ 0x425d, 0x0b3d,
+ 0x4263, 0x1e31,
+ 0x4264, 0x0b44,
+ 0x426f, 0x1e32,
+ 0x4270, 0x0b50,
+ 0x4275, 0x1e33,
+ 0x4277, 0x0b57,
+ 0x427d, 0x1e35,
+ 0x427e, 0x0b5e,
+ 0x4321, 0x0b5f,
+ 0x4327, 0x1e36,
+ 0x4328, 0x0b66,
+ 0x4329, 0x1e37,
+ 0x432b, 0x0b69,
+ 0x432d, 0x1e39,
+ 0x432f, 0x0b6d,
+ 0x433d, 0x1e3b,
+ 0x433e, 0x0b7c,
+ 0x4370, 0x1e3c,
+ 0x4371, 0x0baf,
+ 0x4375, 0x1e3d,
+ 0x4376, 0x0bb4,
+ 0x437c, 0x1e3e,
+ 0x437d, 0x0bbb,
+ 0x4421, 0x0bbd,
+ 0x443d, 0x1e3f,
+ 0x443e, 0x0bda,
+ 0x4448, 0x1e40,
+ 0x4449, 0x0be5,
+ 0x444a, 0x1e41,
+ 0x444b, 0x0be7,
+ 0x444d, 0x1e42,
+ 0x444e, 0x0bea,
+ 0x444f, 0x1e43,
+ 0x4450, 0x0bec,
+ 0x445b, 0x11b5,
+ 0x445c, 0x0bf8,
+ 0x4521, 0x0c1b,
+ 0x4522, 0x1e44,
+ 0x4523, 0x0c1d,
+ 0x4527, 0x1e45,
+ 0x4528, 0x0c22,
+ 0x452e, 0x1e46,
+ 0x452f, 0x0c29,
+ 0x4536, 0x1e47,
+ 0x4537, 0x0c31,
+ 0x453f, 0x1e48,
+ 0x4540, 0x0c3a,
+ 0x4548, 0x1e49,
+ 0x4549, 0x0c43,
+ 0x454b, 0x1e4a,
+ 0x454c, 0x0c46,
+ 0x4551, 0x1e4b,
+ 0x4553, 0x0c4d,
+ 0x4557, 0x16df,
+ 0x4558, 0x0c52,
+ 0x4564, 0x1e4d,
+ 0x4565, 0x0c5f,
+ 0x456e, 0x1450,
+ 0x456f, 0x0c69,
+ 0x4573, 0x1536,
+ 0x4574, 0x0c6e,
+ 0x4578, 0x1e4e,
+ 0x4579, 0x0c73,
+ 0x4621, 0x0c79,
+ 0x463e, 0x1e4f,
+ 0x463f, 0x0c97,
+ 0x4642, 0x1e50,
+ 0x4643, 0x0c9b,
+ 0x4654, 0x1e51,
+ 0x4656, 0x0cae,
+ 0x465b, 0x1e53,
+ 0x465d, 0x0cb5,
+ 0x4661, 0x1e55,
+ 0x4662, 0x0cba,
+ 0x4666, 0x1e56,
+ 0x4668, 0x0cc0,
+ 0x466a, 0x1e58,
+ 0x466b, 0x0cc3,
+ 0x4676, 0x1aed,
+ 0x4677, 0x0ccf,
+ 0x4721, 0x0cd7,
+ 0x4729, 0x1e59,
+ 0x472a, 0x0ce0,
+ 0x4739, 0x1e5a,
+ 0x473a, 0x0cf0,
+ 0x4757, 0x1e5b,
+ 0x4758, 0x0d0e,
+ 0x4767, 0x1e5c,
+ 0x4768, 0x1989,
+ 0x4769, 0x1e5d,
+ 0x476a, 0x0d20,
+ 0x476d, 0x1e5e,
+ 0x476e, 0x0d24,
+ 0x4821, 0x0d35,
+ 0x4824, 0x1e5f,
+ 0x4825, 0x0d39,
+ 0x482e, 0x1e60,
+ 0x482f, 0x0d43,
+ 0x4830, 0x1e61,
+ 0x4831, 0x0d45,
+ 0x4854, 0x1e62,
+ 0x4855, 0x0d69,
+ 0x4862, 0x1e63,
+ 0x4863, 0x0d77,
+ 0x4875, 0x1e64,
+ 0x4876, 0x0d8a,
+ 0x4921, 0x0d93,
+ 0x4922, 0x1e65,
+ 0x4924, 0x0d96,
+ 0x492f, 0x1e67,
+ 0x4930, 0x143b,
+ 0x4931, 0x0da3,
+ 0x4932, 0x1e68,
+ 0x4933, 0x0da5,
+ 0x4935, 0x1e69,
+ 0x4936, 0x0da8,
+ 0x4940, 0x1e6a,
+ 0x4941, 0x0db3,
+ 0x494e, 0x1e6b,
+ 0x494f, 0x0dc1,
+ 0x4951, 0x1e6c,
+ 0x4952, 0x0dc4,
+ 0x4a21, 0x0df1,
+ 0x4a43, 0x1e6d,
+ 0x4a44, 0x0e14,
+ 0x4a4d, 0x1e6e,
+ 0x4a4e, 0x0e1e,
+ 0x4a5a, 0x1e6f,
+ 0x4a5b, 0x0e2b,
+ 0x4a79, 0x1e70,
+ 0x4a7a, 0x0e4a,
+ 0x4b21, 0x0e4f,
+ 0x4b22, 0x1e71,
+ 0x4b23, 0x0e51,
+ 0x4b29, 0x1e72,
+ 0x4b2a, 0x0e58,
+ 0x4b4b, 0x1e73,
+ 0x4b4c, 0x0e7a,
+ 0x4b6a, 0x1d33,
+ 0x4b6b, 0x0e99,
+ 0x4b70, 0x1e74,
+ 0x4b71, 0x0e9f,
+ 0x4b79, 0x102f,
+ 0x4b7a, 0x0ea8,
+ 0x4c21, 0x0ead,
+ 0x4c4d, 0x1e75,
+ 0x4c4e, 0x0eda,
+ 0x4c59, 0x1e76,
+ 0x4c5a, 0x0ee6,
+ 0x4c5f, 0x1e77,
+ 0x4c60, 0x0eec,
+ 0x4c62, 0x1e78,
+ 0x4c63, 0x0eef,
+ 0x4c79, 0x1935,
+ 0x4c7a, 0x1e79,
+ 0x4c7b, 0x0f07,
+ 0x4c7c, 0x1e7a,
+ 0x4c7d, 0x0f09,
+ 0x4c7e, 0x1e7b,
+ 0x4d21, 0x0f0b,
+ 0x4d32, 0x1e7c,
+ 0x4d33, 0x0f1d,
+ 0x4d50, 0x1e7d,
+ 0x4d51, 0x0f3b,
+ 0x4d54, 0x1e7e,
+ 0x4d55, 0x0f3f,
+ 0x4d5a, 0x1d34,
+ 0x4d5b, 0x0f45,
+ 0x4d69, 0x1e7f,
+ 0x4d6a, 0x0f54,
+ 0x4e21, 0x0f69,
+ 0x4e4b, 0x1e80,
+ 0x4e4c, 0x0f94,
+ 0x4e7a, 0x1e81,
+ 0x4e7c, 0x0fc4,
+ 0x4f21, 0x1e83,
+ 0x4f22, 0x0fc8,
+ 0x4f31, 0x1e84,
+ 0x4f32, 0x0fd8,
+ 0x4f36, 0x1777,
+ 0x4f37, 0x0fdd,
+ 0x4f39, 0x1e85,
+ 0x4f3a, 0x0fe0,
+ 0x5021, 0x0ffa,
+ 0x5056, 0x0ea7,
+ 0x5057, 0x1030,
+ 0x5121, 0x1058,
+ 0x513d, 0x1e86,
+ 0x513e, 0x1075,
+ 0x5147, 0x1e87,
+ 0x5148, 0x107f,
+ 0x514b, 0x1e88,
+ 0x514c, 0x1083,
+ 0x514d, 0x1e89,
+ 0x514e, 0x1085,
+ 0x5221, 0x10b6,
+ 0x5321, 0x1114,
+ 0x5330, 0x1e8a,
+ 0x5331, 0x1124,
+ 0x533a, 0x1e8b,
+ 0x533b, 0x112e,
+ 0x5350, 0x1e8c,
+ 0x5351, 0x1144,
+ 0x535e, 0x1e8d,
+ 0x535f, 0x1152,
+ 0x536b, 0x1e8e,
+ 0x536c, 0x115f,
+ 0x5421, 0x1172,
+ 0x5444, 0x1e8f,
+ 0x5445, 0x1196,
+ 0x5464, 0x0bf7,
+ 0x5465, 0x11b6,
+ 0x5521, 0x11d0,
+ 0x553d, 0x1e90,
+ 0x553e, 0x11ed,
+ 0x5563, 0x1e91,
+ 0x5564, 0x1213,
+ 0x5621, 0x122e,
+ 0x5622, 0x1e92,
+ 0x5623, 0x1230,
+ 0x5672, 0x1e93,
+ 0x5673, 0x1280,
+ 0x5721, 0x128c,
+ 0x5821, 0x12ea,
+ 0x5824, 0x1e94,
+ 0x5825, 0x12ee,
+ 0x5921, 0x1348,
+ 0x5960, 0x1e95,
+ 0x5961, 0x1388,
+ 0x596c, 0x1e96,
+ 0x596d, 0x1394,
+ 0x5978, 0x05a7,
+ 0x5979, 0x13a0,
+ 0x5a21, 0x13a6,
+ 0x5a39, 0x1e97,
+ 0x5a3a, 0x13bf,
+ 0x5a4d, 0x1e98,
+ 0x5a4e, 0x13d3,
+ 0x5b21, 0x1404,
+ 0x5b45, 0x1e99,
+ 0x5b46, 0x1429,
+ 0x5b4a, 0x1e9a,
+ 0x5b4b, 0x142e,
+ 0x5b58, 0x0da2,
+ 0x5b59, 0x143c,
+ 0x5b6b, 0x1e9b,
+ 0x5b6c, 0x144f,
+ 0x5b6d, 0x0c68,
+ 0x5b6e, 0x1451,
+ 0x5b74, 0x1e9c,
+ 0x5b75, 0x1458,
+ 0x5c21, 0x1462,
+ 0x5d21, 0x14c0,
+ 0x5e21, 0x151e,
+ 0x5e39, 0x0c6d,
+ 0x5e3a, 0x1537,
+ 0x5e50, 0x1e9d,
+ 0x5e51, 0x154e,
+ 0x5e75, 0x05ff,
+ 0x5e76, 0x1573,
+ 0x5f21, 0x157c,
+ 0x5f73, 0x1e9e,
+ 0x5f74, 0x15cf,
+ 0x6021, 0x15da,
+ 0x6026, 0x1e9f,
+ 0x6027, 0x15e0,
+ 0x605f, 0x1ea0,
+ 0x6060, 0x1619,
+ 0x6076, 0x1d35,
+ 0x6077, 0x1630,
+ 0x6121, 0x1638,
+ 0x612b, 0x1ea1,
+ 0x612c, 0x1643,
+ 0x6130, 0x1ea2,
+ 0x6132, 0x1649,
+ 0x6221, 0x1696,
+ 0x622b, 0x1ea4,
+ 0x622c, 0x16a1,
+ 0x6268, 0x07ee,
+ 0x6269, 0x16de,
+ 0x626a, 0x0c51,
+ 0x626b, 0x16e0,
+ 0x626f, 0x1ea5,
+ 0x6270, 0x16e5,
+ 0x6321, 0x16f4,
+ 0x634a, 0x1ea6,
+ 0x634b, 0x171e,
+ 0x6354, 0x1ea7,
+ 0x6355, 0x1728,
+ 0x635e, 0x05d4,
+ 0x635f, 0x1732,
+ 0x6421, 0x1752,
+ 0x6439, 0x1ea8,
+ 0x643a, 0x176b,
+ 0x6446, 0x0fdc,
+ 0x6447, 0x1778,
+ 0x6464, 0x1ea9,
+ 0x6465, 0x1796,
+ 0x646e, 0x1eaa,
+ 0x646f, 0x17a0,
+ 0x6521, 0x17b0,
+ 0x6539, 0x1eab,
+ 0x653a, 0x17c9,
+ 0x653b, 0x1eac,
+ 0x653c, 0x17cb,
+ 0x6546, 0x1ead,
+ 0x6547, 0x17d6,
+ 0x6621, 0x180e,
+ 0x6646, 0x1eae,
+ 0x6647, 0x1834,
+ 0x6721, 0x186c,
+ 0x6764, 0x1eaf,
+ 0x6765, 0x18b0,
+ 0x6769, 0x1eb0,
+ 0x676a, 0x18b5,
+ 0x6772, 0x1eb1,
+ 0x6773, 0x18be,
+ 0x6821, 0x18ca,
+ 0x6834, 0x1eb2,
+ 0x6835, 0x18de,
+ 0x683b, 0x1eb3,
+ 0x683c, 0x18e5,
+ 0x6874, 0x1eb4,
+ 0x6875, 0x191e,
+ 0x6921, 0x1928,
+ 0x6922, 0x08f5,
+ 0x6923, 0x192a,
+ 0x692e, 0x0f05,
+ 0x692f, 0x1936,
+ 0x693c, 0x1eb5,
+ 0x693d, 0x1944,
+ 0x695a, 0x05a0,
+ 0x695b, 0x1962,
+ 0x6a21, 0x1986,
+ 0x6a24, 0x0d1e,
+ 0x6a25, 0x198a,
+ 0x6a27, 0x1eb6,
+ 0x6a28, 0x198d,
+ 0x6a3d, 0x1eb7,
+ 0x6a3e, 0x19a3,
+ 0x6a6f, 0x1eb8,
+ 0x6a70, 0x19d5,
+ 0x6b21, 0x19e4,
+ 0x6b32, 0x1eb9,
+ 0x6b33, 0x19f6,
+ 0x6b5d, 0x060e,
+ 0x6b5e, 0x1a21,
+ 0x6b66, 0x1eba,
+ 0x6b67, 0x1a2a,
+ 0x6b76, 0x1ebb,
+ 0x6b77, 0x1a3a,
+ 0x6c21, 0x1a42,
+ 0x6c4d, 0x0aaa,
+ 0x6c4e, 0x1a6f,
+ 0x6c69, 0x1ebc,
+ 0x6c6a, 0x1a8b,
+ 0x6c74, 0x1ebd,
+ 0x6c75, 0x1a96,
+ 0x6d21, 0x1aa0,
+ 0x6d4e, 0x1ebe,
+ 0x6d4f, 0x1ace,
+ 0x6d6c, 0x1ebf,
+ 0x6d6d, 0x1aec,
+ 0x6d6e, 0x1ec0,
+ 0x6d6f, 0x1aee,
+ 0x6e21, 0x1afe,
+ 0x6e29, 0x1ec1,
+ 0x6e2a, 0x1b07,
+ 0x6e3d, 0x1ec2,
+ 0x6e3e, 0x1b1b,
+ 0x6e57, 0x1ec3,
+ 0x6e58, 0x1b35,
+ 0x6f21, 0x1b5c,
+ 0x6f65, 0x1ec4,
+ 0x6f66, 0x1ba1,
+ 0x7021, 0x1bba,
+ 0x7033, 0x1ec5,
+ 0x7034, 0x1bcd,
+ 0x7045, 0x1ec6,
+ 0x7046, 0x1bdf,
+ 0x7051, 0x1ec7,
+ 0x7052, 0x1beb,
+ 0x7057, 0x1ec8,
+ 0x7058, 0x1bf1,
+ 0x7074, 0x0731,
+ 0x7075, 0x1ec9,
+ 0x7076, 0x1c0f,
+ 0x7121, 0x1c18,
+ 0x7221, 0x1c76,
+ 0x722d, 0x1eca,
+ 0x722e, 0x1c83,
+ 0x723c, 0x1ecb,
+ 0x723d, 0x1c92,
+ 0x724d, 0x0477,
+ 0x724e, 0x1ecc,
+ 0x724f, 0x1ca4,
+ 0x7274, 0x0529,
+ 0x7275, 0x1cca,
+ 0x7321, 0x1cd4,
+ 0x7351, 0x1ecd,
+ 0x7352, 0x1d05,
+ 0x737d, 0x1ece,
+ 0x737e, 0x1d31,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 japan12NWPHEnc16 = {
+ 0,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ japan12NWPHMap2, 761
+};
+
+static Gushort japan12NWPVMap2[1618] = {
+ 0x0000, 0x0000,
+ 0x2121, 0x0279,
+ 0x2169, 0x1d36,
+ 0x216a, 0x02c2,
+ 0x2221, 0x02d7,
+ 0x223a, 0x02e5,
+ 0x224a, 0x02ed,
+ 0x225c, 0x02f4,
+ 0x2272, 0x0303,
+ 0x227e, 0x030b,
+ 0x2330, 0x030c,
+ 0x2341, 0x0316,
+ 0x2361, 0x0330,
+ 0x2421, 0x034a,
+ 0x2521, 0x039d,
+ 0x2621, 0x03f3,
+ 0x2641, 0x040b,
+ 0x2721, 0x0423,
+ 0x2751, 0x0444,
+ 0x2921, 0x00e8,
+ 0x2960, 0x0186,
+ 0x2961, 0x0128,
+ 0x2a21, 0x0147,
+ 0x2a60, 0x0187,
+ 0x2b21, 0x01a6,
+ 0x2b72, 0x0127,
+ 0x2b73, 0x01f7,
+ 0x2c24, 0x1d37,
+ 0x2d21, 0x1d83,
+ 0x2d40, 0x1da1,
+ 0x2d60, 0x1db8,
+ 0x2d70, 0x02fa,
+ 0x2d71, 0x02f9,
+ 0x2d72, 0x0301,
+ 0x2d73, 0x1dc8,
+ 0x2d7a, 0x0300,
+ 0x2d7b, 0x1dcf,
+ 0x2e21, 0x0282,
+ 0x2e22, 0x02a1,
+ 0x2e23, 0x0305,
+ 0x2e24, 0x02c8,
+ 0x2e25, 0x02cb,
+ 0x2e26, 0x02cd,
+ 0x2e27, 0x029f,
+ 0x2e28, 0x02a2,
+ 0x2e2a, 0x02ce,
+ 0x2e2b, 0x02b4,
+ 0x2e2c, 0x027c,
+ 0x2e2d, 0x02b5,
+ 0x2e2e, 0x027d,
+ 0x2e2f, 0x0297,
+ 0x2e30, 0x030c,
+ 0x2e3a, 0x027f,
+ 0x2e3c, 0x02bb,
+ 0x2e3d, 0x02b9,
+ 0x2e3e, 0x02bc,
+ 0x2e3f, 0x0281,
+ 0x2e40, 0x02cf,
+ 0x2e41, 0x0316,
+ 0x2e5b, 0x02a6,
+ 0x2e5c, 0x02c7,
+ 0x2e5d, 0x02a7,
+ 0x2e5e, 0x0288,
+ 0x2e5f, 0x028a,
+ 0x2e60, 0x0286,
+ 0x2e61, 0x0330,
+ 0x2e7b, 0x02a8,
+ 0x2e7c, 0x029b,
+ 0x2e7d, 0x02a9,
+ 0x2e7e, 0x0289,
+ 0x2f21, 0x027b,
+ 0x2f22, 0x02ae,
+ 0x2f24, 0x027a,
+ 0x2f25, 0x027e,
+ 0x2f26, 0x03ee,
+ 0x2f27, 0x039d,
+ 0x2f28, 0x039f,
+ 0x2f29, 0x03a1,
+ 0x2f2a, 0x03a3,
+ 0x2f2b, 0x03a5,
+ 0x2f2c, 0x03df,
+ 0x2f2d, 0x03e1,
+ 0x2f2e, 0x03e3,
+ 0x2f2f, 0x03bf,
+ 0x2f30, 0x0294,
+ 0x2f31, 0x039e,
+ 0x2f32, 0x03a0,
+ 0x2f33, 0x03a2,
+ 0x2f34, 0x03a4,
+ 0x2f35, 0x03a6,
+ 0x2f37, 0x03a9,
+ 0x2f38, 0x03ab,
+ 0x2f39, 0x03ad,
+ 0x2f3a, 0x03af,
+ 0x2f3b, 0x03b1,
+ 0x2f3c, 0x03b3,
+ 0x2f3d, 0x03b5,
+ 0x2f3e, 0x03b7,
+ 0x2f3f, 0x03b9,
+ 0x2f40, 0x03bb,
+ 0x2f41, 0x03bd,
+ 0x2f42, 0x03c0,
+ 0x2f43, 0x03c2,
+ 0x2f44, 0x03c4,
+ 0x2f45, 0x03c6,
+ 0x2f4b, 0x03ce,
+ 0x2f4c, 0x03d1,
+ 0x2f4d, 0x03d4,
+ 0x2f4e, 0x03d7,
+ 0x2f4f, 0x03da,
+ 0x2f54, 0x03e0,
+ 0x2f55, 0x03e2,
+ 0x2f56, 0x03e4,
+ 0x2f5c, 0x03eb,
+ 0x2f5d, 0x03ef,
+ 0x2f5e, 0x0283,
+ 0x2f60, 0x03ec,
+ 0x2f62, 0x03ea,
+ 0x2f63, 0x03f1,
+ 0x2f65, 0x03f0,
+ 0x2f66, 0x03a8,
+ 0x2f67, 0x03aa,
+ 0x2f68, 0x03ac,
+ 0x2f69, 0x03ae,
+ 0x2f6a, 0x03b0,
+ 0x2f6b, 0x03b2,
+ 0x2f6c, 0x03b4,
+ 0x2f6d, 0x03b6,
+ 0x2f6e, 0x03b8,
+ 0x2f6f, 0x03ba,
+ 0x2f70, 0x03bc,
+ 0x2f71, 0x03be,
+ 0x2f72, 0x03c1,
+ 0x2f73, 0x03c3,
+ 0x2f74, 0x03c5,
+ 0x2f75, 0x03cc,
+ 0x2f77, 0x03cf,
+ 0x2f79, 0x03d2,
+ 0x2f7b, 0x03d5,
+ 0x2f7d, 0x03d8,
+ 0x3021, 0x0465,
+ 0x3022, 0x1dd1,
+ 0x3023, 0x0467,
+ 0x3033, 0x1ca2,
+ 0x3034, 0x0478,
+ 0x303b, 0x1dd2,
+ 0x303c, 0x0480,
+ 0x306e, 0x1dd3,
+ 0x306f, 0x04b3,
+ 0x3073, 0x1dd4,
+ 0x3074, 0x04b8,
+ 0x307c, 0x1dd5,
+ 0x307d, 0x04c1,
+ 0x3121, 0x04c3,
+ 0x312a, 0x1dd6,
+ 0x312b, 0x04cd,
+ 0x3135, 0x1dd7,
+ 0x3136, 0x04d8,
+ 0x3139, 0x1dd8,
+ 0x313a, 0x04dc,
+ 0x313c, 0x1dd9,
+ 0x313e, 0x04e0,
+ 0x3142, 0x1ddb,
+ 0x3143, 0x04e5,
+ 0x316b, 0x1ddc,
+ 0x316c, 0x050e,
+ 0x3221, 0x0521,
+ 0x3228, 0x1ddd,
+ 0x3229, 0x1cc9,
+ 0x322a, 0x1dde,
+ 0x322b, 0x052b,
+ 0x3260, 0x1ddf,
+ 0x3261, 0x0561,
+ 0x327a, 0x1de0,
+ 0x327b, 0x057b,
+ 0x327d, 0x1de1,
+ 0x327e, 0x057e,
+ 0x3321, 0x057f,
+ 0x3322, 0x1de2,
+ 0x3323, 0x0581,
+ 0x3342, 0x1961,
+ 0x3343, 0x05a1,
+ 0x3349, 0x139f,
+ 0x334a, 0x05a8,
+ 0x3365, 0x1de3,
+ 0x3366, 0x05c4,
+ 0x336b, 0x1de4,
+ 0x336c, 0x05ca,
+ 0x3373, 0x1de5,
+ 0x3374, 0x05d2,
+ 0x3376, 0x1731,
+ 0x3377, 0x05d5,
+ 0x337a, 0x1de6,
+ 0x337b, 0x05d9,
+ 0x3421, 0x05dd,
+ 0x3442, 0x1de7,
+ 0x3443, 0x1572,
+ 0x3444, 0x0600,
+ 0x344d, 0x1de8,
+ 0x344e, 0x060a,
+ 0x3452, 0x1a20,
+ 0x3453, 0x060f,
+ 0x3465, 0x1de9,
+ 0x3466, 0x0622,
+ 0x3521, 0x063b,
+ 0x352b, 0x1dea,
+ 0x352c, 0x0646,
+ 0x3540, 0x1deb,
+ 0x3541, 0x065b,
+ 0x3621, 0x0699,
+ 0x3622, 0x1dec,
+ 0x3623, 0x069b,
+ 0x362a, 0x1ded,
+ 0x362b, 0x06a3,
+ 0x3646, 0x1d32,
+ 0x3647, 0x06bf,
+ 0x364f, 0x1dee,
+ 0x3650, 0x06c8,
+ 0x366d, 0x1def,
+ 0x366e, 0x06e6,
+ 0x3674, 0x1df0,
+ 0x3675, 0x06ed,
+ 0x367b, 0x1df1,
+ 0x367c, 0x06f4,
+ 0x367d, 0x1df2,
+ 0x367e, 0x06f6,
+ 0x3721, 0x06f7,
+ 0x3724, 0x1df3,
+ 0x3725, 0x06fb,
+ 0x3737, 0x1df4,
+ 0x3738, 0x070e,
+ 0x3745, 0x1df5,
+ 0x3746, 0x071c,
+ 0x374e, 0x1df6,
+ 0x374f, 0x0725,
+ 0x3752, 0x1df7,
+ 0x3753, 0x0729,
+ 0x3755, 0x1df8,
+ 0x3756, 0x072c,
+ 0x375b, 0x1c0d,
+ 0x375c, 0x0732,
+ 0x3764, 0x1df9,
+ 0x3765, 0x073b,
+ 0x3771, 0x1dfa,
+ 0x3772, 0x0748,
+ 0x3779, 0x1dfb,
+ 0x377a, 0x0750,
+ 0x377e, 0x1dfc,
+ 0x3821, 0x0755,
+ 0x3834, 0x1dfd,
+ 0x3835, 0x0769,
+ 0x3841, 0x1dfe,
+ 0x3842, 0x0776,
+ 0x3921, 0x07b3,
+ 0x392b, 0x1dff,
+ 0x392c, 0x07be,
+ 0x3937, 0x1e00,
+ 0x3938, 0x07ca,
+ 0x3942, 0x1e01,
+ 0x3943, 0x07d5,
+ 0x395c, 0x16dd,
+ 0x395d, 0x07ef,
+ 0x396d, 0x1e02,
+ 0x396e, 0x0800,
+ 0x3974, 0x1e03,
+ 0x3975, 0x0807,
+ 0x3979, 0x1e04,
+ 0x397a, 0x080c,
+ 0x3a21, 0x0811,
+ 0x3a53, 0x1e05,
+ 0x3a54, 0x0844,
+ 0x3a67, 0x1e06,
+ 0x3a68, 0x0858,
+ 0x3a74, 0x1e07,
+ 0x3a75, 0x0865,
+ 0x3b21, 0x086f,
+ 0x3b27, 0x1e08,
+ 0x3b28, 0x0876,
+ 0x3b2a, 0x1e09,
+ 0x3b2b, 0x0879,
+ 0x3b2c, 0x1e0a,
+ 0x3b2d, 0x087b,
+ 0x3b39, 0x1e0b,
+ 0x3b3a, 0x0888,
+ 0x3c21, 0x08cd,
+ 0x3c38, 0x1e0c,
+ 0x3c39, 0x08e5,
+ 0x3c48, 0x1e0d,
+ 0x3c49, 0x1929,
+ 0x3c4a, 0x08f6,
+ 0x3c57, 0x1e0e,
+ 0x3c58, 0x0904,
+ 0x3c5d, 0x1e0f,
+ 0x3c5f, 0x090b,
+ 0x3d21, 0x092b,
+ 0x3d2b, 0x1e11,
+ 0x3d2c, 0x0936,
+ 0x3d36, 0x1e12,
+ 0x3d37, 0x0941,
+ 0x3d6c, 0x1e13,
+ 0x3d6e, 0x0978,
+ 0x3d72, 0x1e15,
+ 0x3d74, 0x097e,
+ 0x3e21, 0x0989,
+ 0x3e25, 0x1e17,
+ 0x3e26, 0x098e,
+ 0x3e33, 0x1e18,
+ 0x3e34, 0x099c,
+ 0x3e3f, 0x1e19,
+ 0x3e40, 0x09a8,
+ 0x3e55, 0x1e1a,
+ 0x3e56, 0x09be,
+ 0x3e5f, 0x1e1b,
+ 0x3e60, 0x09c8,
+ 0x3e64, 0x1e1c,
+ 0x3e65, 0x09cd,
+ 0x3f21, 0x09e7,
+ 0x3f2a, 0x1e1d,
+ 0x3f2b, 0x09f1,
+ 0x3f59, 0x1e1e,
+ 0x3f5a, 0x0a20,
+ 0x3f60, 0x1e1f,
+ 0x3f61, 0x0a27,
+ 0x3f69, 0x1e20,
+ 0x3f6a, 0x0a30,
+ 0x4021, 0x0a45,
+ 0x4022, 0x1e21,
+ 0x4023, 0x0a47,
+ 0x4042, 0x1e22,
+ 0x4043, 0x0a67,
+ 0x4066, 0x1e23,
+ 0x4067, 0x0a8b,
+ 0x4071, 0x1e24,
+ 0x4073, 0x0a97,
+ 0x4079, 0x1e26,
+ 0x407b, 0x0a9f,
+ 0x4121, 0x0aa3,
+ 0x4127, 0x1e28,
+ 0x4128, 0x1a6e,
+ 0x4129, 0x0aab,
+ 0x4139, 0x1e29,
+ 0x413a, 0x0abc,
+ 0x414c, 0x1e2a,
+ 0x414d, 0x0acf,
+ 0x414f, 0x1e2b,
+ 0x4150, 0x0ad2,
+ 0x415f, 0x1e2c,
+ 0x4160, 0x0ae2,
+ 0x4169, 0x1e2d,
+ 0x416a, 0x0aec,
+ 0x4221, 0x0b01,
+ 0x423d, 0x1e2e,
+ 0x423e, 0x0b1e,
+ 0x424d, 0x1e2f,
+ 0x424e, 0x0b2e,
+ 0x425c, 0x1e30,
+ 0x425d, 0x0b3d,
+ 0x4263, 0x1e31,
+ 0x4264, 0x0b44,
+ 0x426f, 0x1e32,
+ 0x4270, 0x0b50,
+ 0x4275, 0x1e33,
+ 0x4277, 0x0b57,
+ 0x427d, 0x1e35,
+ 0x427e, 0x0b5e,
+ 0x4321, 0x0b5f,
+ 0x4327, 0x1e36,
+ 0x4328, 0x0b66,
+ 0x4329, 0x1e37,
+ 0x432b, 0x0b69,
+ 0x432d, 0x1e39,
+ 0x432f, 0x0b6d,
+ 0x433d, 0x1e3b,
+ 0x433e, 0x0b7c,
+ 0x4370, 0x1e3c,
+ 0x4371, 0x0baf,
+ 0x4375, 0x1e3d,
+ 0x4376, 0x0bb4,
+ 0x437c, 0x1e3e,
+ 0x437d, 0x0bbb,
+ 0x4421, 0x0bbd,
+ 0x443d, 0x1e3f,
+ 0x443e, 0x0bda,
+ 0x4448, 0x1e40,
+ 0x4449, 0x0be5,
+ 0x444a, 0x1e41,
+ 0x444b, 0x0be7,
+ 0x444d, 0x1e42,
+ 0x444e, 0x0bea,
+ 0x444f, 0x1e43,
+ 0x4450, 0x0bec,
+ 0x445b, 0x11b5,
+ 0x445c, 0x0bf8,
+ 0x4521, 0x0c1b,
+ 0x4522, 0x1e44,
+ 0x4523, 0x0c1d,
+ 0x4527, 0x1e45,
+ 0x4528, 0x0c22,
+ 0x452e, 0x1e46,
+ 0x452f, 0x0c29,
+ 0x4536, 0x1e47,
+ 0x4537, 0x0c31,
+ 0x453f, 0x1e48,
+ 0x4540, 0x0c3a,
+ 0x4548, 0x1e49,
+ 0x4549, 0x0c43,
+ 0x454b, 0x1e4a,
+ 0x454c, 0x0c46,
+ 0x4551, 0x1e4b,
+ 0x4553, 0x0c4d,
+ 0x4557, 0x16df,
+ 0x4558, 0x0c52,
+ 0x4564, 0x1e4d,
+ 0x4565, 0x0c5f,
+ 0x456e, 0x1450,
+ 0x456f, 0x0c69,
+ 0x4573, 0x1536,
+ 0x4574, 0x0c6e,
+ 0x4578, 0x1e4e,
+ 0x4579, 0x0c73,
+ 0x4621, 0x0c79,
+ 0x463e, 0x1e4f,
+ 0x463f, 0x0c97,
+ 0x4642, 0x1e50,
+ 0x4643, 0x0c9b,
+ 0x4654, 0x1e51,
+ 0x4656, 0x0cae,
+ 0x465b, 0x1e53,
+ 0x465d, 0x0cb5,
+ 0x4661, 0x1e55,
+ 0x4662, 0x0cba,
+ 0x4666, 0x1e56,
+ 0x4668, 0x0cc0,
+ 0x466a, 0x1e58,
+ 0x466b, 0x0cc3,
+ 0x4676, 0x1aed,
+ 0x4677, 0x0ccf,
+ 0x4721, 0x0cd7,
+ 0x4729, 0x1e59,
+ 0x472a, 0x0ce0,
+ 0x4739, 0x1e5a,
+ 0x473a, 0x0cf0,
+ 0x4757, 0x1e5b,
+ 0x4758, 0x0d0e,
+ 0x4767, 0x1e5c,
+ 0x4768, 0x1989,
+ 0x4769, 0x1e5d,
+ 0x476a, 0x0d20,
+ 0x476d, 0x1e5e,
+ 0x476e, 0x0d24,
+ 0x4821, 0x0d35,
+ 0x4824, 0x1e5f,
+ 0x4825, 0x0d39,
+ 0x482e, 0x1e60,
+ 0x482f, 0x0d43,
+ 0x4830, 0x1e61,
+ 0x4831, 0x0d45,
+ 0x4854, 0x1e62,
+ 0x4855, 0x0d69,
+ 0x4862, 0x1e63,
+ 0x4863, 0x0d77,
+ 0x4875, 0x1e64,
+ 0x4876, 0x0d8a,
+ 0x4921, 0x0d93,
+ 0x4922, 0x1e65,
+ 0x4924, 0x0d96,
+ 0x492f, 0x1e67,
+ 0x4930, 0x143b,
+ 0x4931, 0x0da3,
+ 0x4932, 0x1e68,
+ 0x4933, 0x0da5,
+ 0x4935, 0x1e69,
+ 0x4936, 0x0da8,
+ 0x4940, 0x1e6a,
+ 0x4941, 0x0db3,
+ 0x494e, 0x1e6b,
+ 0x494f, 0x0dc1,
+ 0x4951, 0x1e6c,
+ 0x4952, 0x0dc4,
+ 0x4a21, 0x0df1,
+ 0x4a43, 0x1e6d,
+ 0x4a44, 0x0e14,
+ 0x4a4d, 0x1e6e,
+ 0x4a4e, 0x0e1e,
+ 0x4a5a, 0x1e6f,
+ 0x4a5b, 0x0e2b,
+ 0x4a79, 0x1e70,
+ 0x4a7a, 0x0e4a,
+ 0x4b21, 0x0e4f,
+ 0x4b22, 0x1e71,
+ 0x4b23, 0x0e51,
+ 0x4b29, 0x1e72,
+ 0x4b2a, 0x0e58,
+ 0x4b4b, 0x1e73,
+ 0x4b4c, 0x0e7a,
+ 0x4b6a, 0x1d33,
+ 0x4b6b, 0x0e99,
+ 0x4b70, 0x1e74,
+ 0x4b71, 0x0e9f,
+ 0x4b79, 0x102f,
+ 0x4b7a, 0x0ea8,
+ 0x4c21, 0x0ead,
+ 0x4c4d, 0x1e75,
+ 0x4c4e, 0x0eda,
+ 0x4c59, 0x1e76,
+ 0x4c5a, 0x0ee6,
+ 0x4c5f, 0x1e77,
+ 0x4c60, 0x0eec,
+ 0x4c62, 0x1e78,
+ 0x4c63, 0x0eef,
+ 0x4c79, 0x1935,
+ 0x4c7a, 0x1e79,
+ 0x4c7b, 0x0f07,
+ 0x4c7c, 0x1e7a,
+ 0x4c7d, 0x0f09,
+ 0x4c7e, 0x1e7b,
+ 0x4d21, 0x0f0b,
+ 0x4d32, 0x1e7c,
+ 0x4d33, 0x0f1d,
+ 0x4d50, 0x1e7d,
+ 0x4d51, 0x0f3b,
+ 0x4d54, 0x1e7e,
+ 0x4d55, 0x0f3f,
+ 0x4d5a, 0x1d34,
+ 0x4d5b, 0x0f45,
+ 0x4d69, 0x1e7f,
+ 0x4d6a, 0x0f54,
+ 0x4e21, 0x0f69,
+ 0x4e4b, 0x1e80,
+ 0x4e4c, 0x0f94,
+ 0x4e7a, 0x1e81,
+ 0x4e7c, 0x0fc4,
+ 0x4f21, 0x1e83,
+ 0x4f22, 0x0fc8,
+ 0x4f31, 0x1e84,
+ 0x4f32, 0x0fd8,
+ 0x4f36, 0x1777,
+ 0x4f37, 0x0fdd,
+ 0x4f39, 0x1e85,
+ 0x4f3a, 0x0fe0,
+ 0x5021, 0x0ffa,
+ 0x5056, 0x0ea7,
+ 0x5057, 0x1030,
+ 0x5121, 0x1058,
+ 0x513d, 0x1e86,
+ 0x513e, 0x1075,
+ 0x5147, 0x1e87,
+ 0x5148, 0x107f,
+ 0x514b, 0x1e88,
+ 0x514c, 0x1083,
+ 0x514d, 0x1e89,
+ 0x514e, 0x1085,
+ 0x5221, 0x10b6,
+ 0x5321, 0x1114,
+ 0x5330, 0x1e8a,
+ 0x5331, 0x1124,
+ 0x533a, 0x1e8b,
+ 0x533b, 0x112e,
+ 0x5350, 0x1e8c,
+ 0x5351, 0x1144,
+ 0x535e, 0x1e8d,
+ 0x535f, 0x1152,
+ 0x536b, 0x1e8e,
+ 0x536c, 0x115f,
+ 0x5421, 0x1172,
+ 0x5444, 0x1e8f,
+ 0x5445, 0x1196,
+ 0x5464, 0x0bf7,
+ 0x5465, 0x11b6,
+ 0x5521, 0x11d0,
+ 0x553d, 0x1e90,
+ 0x553e, 0x11ed,
+ 0x5563, 0x1e91,
+ 0x5564, 0x1213,
+ 0x5621, 0x122e,
+ 0x5622, 0x1e92,
+ 0x5623, 0x1230,
+ 0x5672, 0x1e93,
+ 0x5673, 0x1280,
+ 0x5721, 0x128c,
+ 0x5821, 0x12ea,
+ 0x5824, 0x1e94,
+ 0x5825, 0x12ee,
+ 0x5921, 0x1348,
+ 0x5960, 0x1e95,
+ 0x5961, 0x1388,
+ 0x596c, 0x1e96,
+ 0x596d, 0x1394,
+ 0x5978, 0x05a7,
+ 0x5979, 0x13a0,
+ 0x5a21, 0x13a6,
+ 0x5a39, 0x1e97,
+ 0x5a3a, 0x13bf,
+ 0x5a4d, 0x1e98,
+ 0x5a4e, 0x13d3,
+ 0x5b21, 0x1404,
+ 0x5b45, 0x1e99,
+ 0x5b46, 0x1429,
+ 0x5b4a, 0x1e9a,
+ 0x5b4b, 0x142e,
+ 0x5b58, 0x0da2,
+ 0x5b59, 0x143c,
+ 0x5b6b, 0x1e9b,
+ 0x5b6c, 0x144f,
+ 0x5b6d, 0x0c68,
+ 0x5b6e, 0x1451,
+ 0x5b74, 0x1e9c,
+ 0x5b75, 0x1458,
+ 0x5c21, 0x1462,
+ 0x5d21, 0x14c0,
+ 0x5e21, 0x151e,
+ 0x5e39, 0x0c6d,
+ 0x5e3a, 0x1537,
+ 0x5e50, 0x1e9d,
+ 0x5e51, 0x154e,
+ 0x5e75, 0x05ff,
+ 0x5e76, 0x1573,
+ 0x5f21, 0x157c,
+ 0x5f73, 0x1e9e,
+ 0x5f74, 0x15cf,
+ 0x6021, 0x15da,
+ 0x6026, 0x1e9f,
+ 0x6027, 0x15e0,
+ 0x605f, 0x1ea0,
+ 0x6060, 0x1619,
+ 0x6076, 0x1d35,
+ 0x6077, 0x1630,
+ 0x6121, 0x1638,
+ 0x612b, 0x1ea1,
+ 0x612c, 0x1643,
+ 0x6130, 0x1ea2,
+ 0x6132, 0x1649,
+ 0x6221, 0x1696,
+ 0x622b, 0x1ea4,
+ 0x622c, 0x16a1,
+ 0x6268, 0x07ee,
+ 0x6269, 0x16de,
+ 0x626a, 0x0c51,
+ 0x626b, 0x16e0,
+ 0x626f, 0x1ea5,
+ 0x6270, 0x16e5,
+ 0x6321, 0x16f4,
+ 0x634a, 0x1ea6,
+ 0x634b, 0x171e,
+ 0x6354, 0x1ea7,
+ 0x6355, 0x1728,
+ 0x635e, 0x05d4,
+ 0x635f, 0x1732,
+ 0x6421, 0x1752,
+ 0x6439, 0x1ea8,
+ 0x643a, 0x176b,
+ 0x6446, 0x0fdc,
+ 0x6447, 0x1778,
+ 0x6464, 0x1ea9,
+ 0x6465, 0x1796,
+ 0x646e, 0x1eaa,
+ 0x646f, 0x17a0,
+ 0x6521, 0x17b0,
+ 0x6539, 0x1eab,
+ 0x653a, 0x17c9,
+ 0x653b, 0x1eac,
+ 0x653c, 0x17cb,
+ 0x6546, 0x1ead,
+ 0x6547, 0x17d6,
+ 0x6621, 0x180e,
+ 0x6646, 0x1eae,
+ 0x6647, 0x1834,
+ 0x6721, 0x186c,
+ 0x6764, 0x1eaf,
+ 0x6765, 0x18b0,
+ 0x6769, 0x1eb0,
+ 0x676a, 0x18b5,
+ 0x6772, 0x1eb1,
+ 0x6773, 0x18be,
+ 0x6821, 0x18ca,
+ 0x6834, 0x1eb2,
+ 0x6835, 0x18de,
+ 0x683b, 0x1eb3,
+ 0x683c, 0x18e5,
+ 0x6874, 0x1eb4,
+ 0x6875, 0x191e,
+ 0x6921, 0x1928,
+ 0x6922, 0x08f5,
+ 0x6923, 0x192a,
+ 0x692e, 0x0f05,
+ 0x692f, 0x1936,
+ 0x693c, 0x1eb5,
+ 0x693d, 0x1944,
+ 0x695a, 0x05a0,
+ 0x695b, 0x1962,
+ 0x6a21, 0x1986,
+ 0x6a24, 0x0d1e,
+ 0x6a25, 0x198a,
+ 0x6a27, 0x1eb6,
+ 0x6a28, 0x198d,
+ 0x6a3d, 0x1eb7,
+ 0x6a3e, 0x19a3,
+ 0x6a6f, 0x1eb8,
+ 0x6a70, 0x19d5,
+ 0x6b21, 0x19e4,
+ 0x6b32, 0x1eb9,
+ 0x6b33, 0x19f6,
+ 0x6b5d, 0x060e,
+ 0x6b5e, 0x1a21,
+ 0x6b66, 0x1eba,
+ 0x6b67, 0x1a2a,
+ 0x6b76, 0x1ebb,
+ 0x6b77, 0x1a3a,
+ 0x6c21, 0x1a42,
+ 0x6c4d, 0x0aaa,
+ 0x6c4e, 0x1a6f,
+ 0x6c69, 0x1ebc,
+ 0x6c6a, 0x1a8b,
+ 0x6c74, 0x1ebd,
+ 0x6c75, 0x1a96,
+ 0x6d21, 0x1aa0,
+ 0x6d4e, 0x1ebe,
+ 0x6d4f, 0x1ace,
+ 0x6d6c, 0x1ebf,
+ 0x6d6d, 0x1aec,
+ 0x6d6e, 0x1ec0,
+ 0x6d6f, 0x1aee,
+ 0x6e21, 0x1afe,
+ 0x6e29, 0x1ec1,
+ 0x6e2a, 0x1b07,
+ 0x6e3d, 0x1ec2,
+ 0x6e3e, 0x1b1b,
+ 0x6e57, 0x1ec3,
+ 0x6e58, 0x1b35,
+ 0x6f21, 0x1b5c,
+ 0x6f65, 0x1ec4,
+ 0x6f66, 0x1ba1,
+ 0x7021, 0x1bba,
+ 0x7033, 0x1ec5,
+ 0x7034, 0x1bcd,
+ 0x7045, 0x1ec6,
+ 0x7046, 0x1bdf,
+ 0x7051, 0x1ec7,
+ 0x7052, 0x1beb,
+ 0x7057, 0x1ec8,
+ 0x7058, 0x1bf1,
+ 0x7074, 0x0731,
+ 0x7075, 0x1ec9,
+ 0x7076, 0x1c0f,
+ 0x7121, 0x1c18,
+ 0x7221, 0x1c76,
+ 0x722d, 0x1eca,
+ 0x722e, 0x1c83,
+ 0x723c, 0x1ecb,
+ 0x723d, 0x1c92,
+ 0x724d, 0x0477,
+ 0x724e, 0x1ecc,
+ 0x724f, 0x1ca4,
+ 0x7274, 0x0529,
+ 0x7275, 0x1cca,
+ 0x7321, 0x1cd4,
+ 0x7351, 0x1ecd,
+ 0x7352, 0x1d05,
+ 0x737d, 0x1ece,
+ 0x737e, 0x1d31,
+ 0x2122, 0x1ecf,
+ 0x2124, 0x204c,
+ 0x2125, 0x2052,
+ 0x212b, 0x2050,
+ 0x212c, 0x204f,
+ 0x213c, 0x1ed3,
+ 0x2141, 0x1ed6,
+ 0x2146, 0x2059,
+ 0x2147, 0x2054,
+ 0x2148, 0x2057,
+ 0x2149, 0x2056,
+ 0x214a, 0x1edb,
+ 0x216b, 0x204d,
+ 0x216c, 0x2051,
+ 0x216d, 0x205b,
+ 0x222e, 0x204e,
+ 0x2421, 0x1eee,
+ 0x2423, 0x1eef,
+ 0x2425, 0x1ef0,
+ 0x2427, 0x1ef1,
+ 0x2429, 0x1ef2,
+ 0x2443, 0x1ef3,
+ 0x2463, 0x1ef4,
+ 0x2465, 0x1ef5,
+ 0x2467, 0x1ef6,
+ 0x246e, 0x1ef7,
+ 0x2521, 0x1ef8,
+ 0x2523, 0x1ef9,
+ 0x2525, 0x1efa,
+ 0x2527, 0x1efb,
+ 0x2529, 0x1efc,
+ 0x2543, 0x1efd,
+ 0x2563, 0x1efe,
+ 0x2565, 0x1eff,
+ 0x2567, 0x1f00,
+ 0x256e, 0x1f01,
+ 0x2575, 0x1f02,
+ 0x2d40, 0x1f04,
+ 0x2d60, 0x1f14,
+ 0x2f21, 0x1ed0,
+ 0x2f22, 0x1ee7,
+ 0x2f24, 0x1ecf,
+ 0x2f27, 0x1ef8,
+ 0x2f2c, 0x1efe,
+ 0x2f2f, 0x1efd,
+ 0x2f30, 0x1ed3,
+ 0x2f5e, 0x2050,
+ 0x2f5f, 0x204f,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 japan12NWPVEnc16 = {
+ 1,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ japan12NWPVMap2, 809
+};
+
+static Gushort japan12RKSJHMap2[244] = {
+ 0x0000, 0x0000,
+ 0x8140, 0x0279,
+ 0x8180, 0x02b8,
+ 0x81b8, 0x02e5,
+ 0x81c8, 0x02ed,
+ 0x81da, 0x02f4,
+ 0x81f0, 0x0303,
+ 0x81fc, 0x030b,
+ 0x824f, 0x030c,
+ 0x8260, 0x0316,
+ 0x8281, 0x0330,
+ 0x829f, 0x034a,
+ 0x8340, 0x039d,
+ 0x8380, 0x03dc,
+ 0x839f, 0x03f3,
+ 0x83bf, 0x040b,
+ 0x8440, 0x0423,
+ 0x8470, 0x0444,
+ 0x8480, 0x0453,
+ 0x849f, 0x1d37,
+ 0x84a0, 0x1d39,
+ 0x84a1, 0x1d43,
+ 0x84a2, 0x1d47,
+ 0x84a3, 0x1d4f,
+ 0x84a4, 0x1d4b,
+ 0x84a5, 0x1d53,
+ 0x84a6, 0x1d63,
+ 0x84a7, 0x1d5b,
+ 0x84a8, 0x1d6b,
+ 0x84a9, 0x1d73,
+ 0x84aa, 0x1d38,
+ 0x84ab, 0x1d3a,
+ 0x84ac, 0x1d46,
+ 0x84ad, 0x1d4a,
+ 0x84ae, 0x1d52,
+ 0x84af, 0x1d4e,
+ 0x84b0, 0x1d5a,
+ 0x84b1, 0x1d6a,
+ 0x84b2, 0x1d62,
+ 0x84b3, 0x1d72,
+ 0x84b4, 0x1d82,
+ 0x84b5, 0x1d57,
+ 0x84b6, 0x1d66,
+ 0x84b7, 0x1d5f,
+ 0x84b8, 0x1d6e,
+ 0x84b9, 0x1d76,
+ 0x84ba, 0x1d54,
+ 0x84bb, 0x1d67,
+ 0x84bc, 0x1d5c,
+ 0x84bd, 0x1d6f,
+ 0x84be, 0x1d79,
+ 0x889f, 0x0465,
+ 0x8940, 0x04c3,
+ 0x8980, 0x0502,
+ 0x8a40, 0x057f,
+ 0x8a80, 0x05be,
+ 0x8b40, 0x063b,
+ 0x8b80, 0x067a,
+ 0x8c40, 0x06f7,
+ 0x8c80, 0x0736,
+ 0x8d40, 0x07b3,
+ 0x8d80, 0x07f2,
+ 0x8e40, 0x086f,
+ 0x8e80, 0x08ae,
+ 0x8f40, 0x092b,
+ 0x8f80, 0x096a,
+ 0x9040, 0x09e7,
+ 0x9080, 0x0a26,
+ 0x9140, 0x0aa3,
+ 0x9180, 0x0ae2,
+ 0x9240, 0x0b5f,
+ 0x9280, 0x0b9e,
+ 0x9340, 0x0c1b,
+ 0x9380, 0x0c5a,
+ 0x9440, 0x0cd7,
+ 0x9480, 0x0d16,
+ 0x9540, 0x0d93,
+ 0x9580, 0x0dd2,
+ 0x9640, 0x0e4f,
+ 0x9680, 0x0e8e,
+ 0x9740, 0x0f0b,
+ 0x9780, 0x0f4a,
+ 0x9840, 0x0fc7,
+ 0x989f, 0x0ffa,
+ 0x9940, 0x1058,
+ 0x9980, 0x1097,
+ 0x9a40, 0x1114,
+ 0x9a80, 0x1153,
+ 0x9b40, 0x11d0,
+ 0x9b80, 0x120f,
+ 0x9c40, 0x128c,
+ 0x9c80, 0x12cb,
+ 0x9d40, 0x1348,
+ 0x9d80, 0x1387,
+ 0x9e40, 0x1404,
+ 0x9e80, 0x1443,
+ 0x9f40, 0x14c0,
+ 0x9f80, 0x14ff,
+ 0xe040, 0x157c,
+ 0xe080, 0x15bb,
+ 0xe140, 0x1638,
+ 0xe180, 0x1677,
+ 0xe240, 0x16f4,
+ 0xe280, 0x1733,
+ 0xe340, 0x17b0,
+ 0xe380, 0x17ef,
+ 0xe440, 0x186c,
+ 0xe480, 0x18ab,
+ 0xe540, 0x1928,
+ 0xe580, 0x1967,
+ 0xe640, 0x19e4,
+ 0xe680, 0x1a23,
+ 0xe740, 0x1aa0,
+ 0xe780, 0x1adf,
+ 0xe840, 0x1b5c,
+ 0xe880, 0x1b9b,
+ 0xe940, 0x1c18,
+ 0xe980, 0x1c57,
+ 0xea40, 0x1cd4,
+ 0xea80, 0x1d13,
+ 0xeaa3, 0x205c,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 japan12RKSJHEnc16 = {
+ 0,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee,
+ 0x00ef, 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6,
+ 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe,
+ 0x00ff, 0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106,
+ 0x0107, 0x0108, 0x0109, 0x010a, 0x010b, 0x010c, 0x010d, 0x010e,
+ 0x010f, 0x0110, 0x0111, 0x0112, 0x0113, 0x0114, 0x0115, 0x0116,
+ 0x0117, 0x0118, 0x0119, 0x011a, 0x011b, 0x011c, 0x011d, 0x011e,
+ 0x011f, 0x0120, 0x0121, 0x0122, 0x0123, 0x0124, 0x0125, 0x0126,
+ 0x0127, 0x0128, 0x0129, 0x012a, 0x012b, 0x012c, 0x012d, 0x012e,
+ 0x012f, 0x0130, 0x0131, 0x0132, 0x0133, 0x0134, 0x0135, 0x0136,
+ 0x0137, 0x0138, 0x0139, 0x013a, 0x013b, 0x013c, 0x013d, 0x013e,
+ 0x013f, 0x0140, 0x0141, 0x0142, 0x0143, 0x0144, 0x0145, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0146, 0x0147, 0x0148, 0x0149, 0x014a, 0x014b, 0x014c, 0x014d,
+ 0x014e, 0x014f, 0x0150, 0x0151, 0x0152, 0x0153, 0x0154, 0x0155,
+ 0x0156, 0x0157, 0x0158, 0x0159, 0x015a, 0x015b, 0x015c, 0x015d,
+ 0x015e, 0x015f, 0x0160, 0x0161, 0x0162, 0x0163, 0x0164, 0x0165,
+ 0x0166, 0x0167, 0x0168, 0x0169, 0x016a, 0x016b, 0x016c, 0x016d,
+ 0x016e, 0x016f, 0x0170, 0x0171, 0x0172, 0x0173, 0x0174, 0x0175,
+ 0x0176, 0x0177, 0x0178, 0x0179, 0x017a, 0x017b, 0x017c, 0x017d,
+ 0x017e, 0x017f, 0x0180, 0x0181, 0x0182, 0x0183, 0x0184, 0x0185,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ japan12RKSJHMap2, 122
+};
+
+static Gushort japan12RKSJVMap2[298] = {
+ 0x0000, 0x0000,
+ 0x8140, 0x0279,
+ 0x8180, 0x02b8,
+ 0x81b8, 0x02e5,
+ 0x81c8, 0x02ed,
+ 0x81da, 0x02f4,
+ 0x81f0, 0x0303,
+ 0x81fc, 0x030b,
+ 0x824f, 0x030c,
+ 0x8260, 0x0316,
+ 0x8281, 0x0330,
+ 0x829f, 0x034a,
+ 0x8340, 0x039d,
+ 0x8380, 0x03dc,
+ 0x839f, 0x03f3,
+ 0x83bf, 0x040b,
+ 0x8440, 0x0423,
+ 0x8470, 0x0444,
+ 0x8480, 0x0453,
+ 0x849f, 0x1d37,
+ 0x84a0, 0x1d39,
+ 0x84a1, 0x1d43,
+ 0x84a2, 0x1d47,
+ 0x84a3, 0x1d4f,
+ 0x84a4, 0x1d4b,
+ 0x84a5, 0x1d53,
+ 0x84a6, 0x1d63,
+ 0x84a7, 0x1d5b,
+ 0x84a8, 0x1d6b,
+ 0x84a9, 0x1d73,
+ 0x84aa, 0x1d38,
+ 0x84ab, 0x1d3a,
+ 0x84ac, 0x1d46,
+ 0x84ad, 0x1d4a,
+ 0x84ae, 0x1d52,
+ 0x84af, 0x1d4e,
+ 0x84b0, 0x1d5a,
+ 0x84b1, 0x1d6a,
+ 0x84b2, 0x1d62,
+ 0x84b3, 0x1d72,
+ 0x84b4, 0x1d82,
+ 0x84b5, 0x1d57,
+ 0x84b6, 0x1d66,
+ 0x84b7, 0x1d5f,
+ 0x84b8, 0x1d6e,
+ 0x84b9, 0x1d76,
+ 0x84ba, 0x1d54,
+ 0x84bb, 0x1d67,
+ 0x84bc, 0x1d5c,
+ 0x84bd, 0x1d6f,
+ 0x84be, 0x1d79,
+ 0x889f, 0x0465,
+ 0x8940, 0x04c3,
+ 0x8980, 0x0502,
+ 0x8a40, 0x057f,
+ 0x8a80, 0x05be,
+ 0x8b40, 0x063b,
+ 0x8b80, 0x067a,
+ 0x8c40, 0x06f7,
+ 0x8c80, 0x0736,
+ 0x8d40, 0x07b3,
+ 0x8d80, 0x07f2,
+ 0x8e40, 0x086f,
+ 0x8e80, 0x08ae,
+ 0x8f40, 0x092b,
+ 0x8f80, 0x096a,
+ 0x9040, 0x09e7,
+ 0x9080, 0x0a26,
+ 0x9140, 0x0aa3,
+ 0x9180, 0x0ae2,
+ 0x9240, 0x0b5f,
+ 0x9280, 0x0b9e,
+ 0x9340, 0x0c1b,
+ 0x9380, 0x0c5a,
+ 0x9440, 0x0cd7,
+ 0x9480, 0x0d16,
+ 0x9540, 0x0d93,
+ 0x9580, 0x0dd2,
+ 0x9640, 0x0e4f,
+ 0x9680, 0x0e8e,
+ 0x9740, 0x0f0b,
+ 0x9780, 0x0f4a,
+ 0x9840, 0x0fc7,
+ 0x989f, 0x0ffa,
+ 0x9940, 0x1058,
+ 0x9980, 0x1097,
+ 0x9a40, 0x1114,
+ 0x9a80, 0x1153,
+ 0x9b40, 0x11d0,
+ 0x9b80, 0x120f,
+ 0x9c40, 0x128c,
+ 0x9c80, 0x12cb,
+ 0x9d40, 0x1348,
+ 0x9d80, 0x1387,
+ 0x9e40, 0x1404,
+ 0x9e80, 0x1443,
+ 0x9f40, 0x14c0,
+ 0x9f80, 0x14ff,
+ 0xe040, 0x157c,
+ 0xe080, 0x15bb,
+ 0xe140, 0x1638,
+ 0xe180, 0x1677,
+ 0xe240, 0x16f4,
+ 0xe280, 0x1733,
+ 0xe340, 0x17b0,
+ 0xe380, 0x17ef,
+ 0xe440, 0x186c,
+ 0xe480, 0x18ab,
+ 0xe540, 0x1928,
+ 0xe580, 0x1967,
+ 0xe640, 0x19e4,
+ 0xe680, 0x1a23,
+ 0xe740, 0x1aa0,
+ 0xe780, 0x1adf,
+ 0xe840, 0x1b5c,
+ 0xe880, 0x1b9b,
+ 0xe940, 0x1c18,
+ 0xe980, 0x1c57,
+ 0xea40, 0x1cd4,
+ 0xea80, 0x1d13,
+ 0xeaa3, 0x205c,
+ 0x8141, 0x1ecf,
+ 0x8150, 0x1ed1,
+ 0x815b, 0x1ed3,
+ 0x8160, 0x1ed6,
+ 0x8169, 0x1edb,
+ 0x8181, 0x1eed,
+ 0x829f, 0x1eee,
+ 0x82a1, 0x1eef,
+ 0x82a3, 0x1ef0,
+ 0x82a5, 0x1ef1,
+ 0x82a7, 0x1ef2,
+ 0x82c1, 0x1ef3,
+ 0x82e1, 0x1ef4,
+ 0x82e3, 0x1ef5,
+ 0x82e5, 0x1ef6,
+ 0x82ec, 0x1ef7,
+ 0x8340, 0x1ef8,
+ 0x8342, 0x1ef9,
+ 0x8344, 0x1efa,
+ 0x8346, 0x1efb,
+ 0x8348, 0x1efc,
+ 0x8362, 0x1efd,
+ 0x8383, 0x1efe,
+ 0x8385, 0x1eff,
+ 0x8387, 0x1f00,
+ 0x838e, 0x1f01,
+ 0x8395, 0x1f02,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 japan12RKSJVEnc16 = {
+ 1,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee,
+ 0x00ef, 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6,
+ 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe,
+ 0x00ff, 0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106,
+ 0x0107, 0x0108, 0x0109, 0x010a, 0x010b, 0x010c, 0x010d, 0x010e,
+ 0x010f, 0x0110, 0x0111, 0x0112, 0x0113, 0x0114, 0x0115, 0x0116,
+ 0x0117, 0x0118, 0x0119, 0x011a, 0x011b, 0x011c, 0x011d, 0x011e,
+ 0x011f, 0x0120, 0x0121, 0x0122, 0x0123, 0x0124, 0x0125, 0x0126,
+ 0x0127, 0x0128, 0x0129, 0x012a, 0x012b, 0x012c, 0x012d, 0x012e,
+ 0x012f, 0x0130, 0x0131, 0x0132, 0x0133, 0x0134, 0x0135, 0x0136,
+ 0x0137, 0x0138, 0x0139, 0x013a, 0x013b, 0x013c, 0x013d, 0x013e,
+ 0x013f, 0x0140, 0x0141, 0x0142, 0x0143, 0x0144, 0x0145, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0146, 0x0147, 0x0148, 0x0149, 0x014a, 0x014b, 0x014c, 0x014d,
+ 0x014e, 0x014f, 0x0150, 0x0151, 0x0152, 0x0153, 0x0154, 0x0155,
+ 0x0156, 0x0157, 0x0158, 0x0159, 0x015a, 0x015b, 0x015c, 0x015d,
+ 0x015e, 0x015f, 0x0160, 0x0161, 0x0162, 0x0163, 0x0164, 0x0165,
+ 0x0166, 0x0167, 0x0168, 0x0169, 0x016a, 0x016b, 0x016c, 0x016d,
+ 0x016e, 0x016f, 0x0170, 0x0171, 0x0172, 0x0173, 0x0174, 0x0175,
+ 0x0176, 0x0177, 0x0178, 0x0179, 0x017a, 0x017b, 0x017c, 0x017d,
+ 0x017e, 0x017f, 0x0180, 0x0181, 0x0182, 0x0183, 0x0184, 0x0185,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ japan12RKSJVMap2, 149
+};
+
+static Gushort japan12RomanMap2[4] = {
+ 0x0000, 0x0000,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 japan12RomanEnc16 = {
+ 0,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee,
+ 0x00ef, 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6,
+ 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe,
+ 0x00ff, 0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106,
+ 0x0107, 0x0108, 0x0109, 0x010a, 0x010b, 0x010c, 0x010d, 0x010e,
+ 0x010f, 0x0110, 0x0111, 0x0112, 0x0113, 0x0114, 0x0115, 0x0116,
+ 0x0117, 0x0118, 0x0119, 0x011a, 0x011b, 0x011c, 0x011d, 0x011e,
+ 0x011f, 0x0120, 0x0121, 0x0122, 0x0123, 0x0124, 0x0125, 0x0126,
+ 0x0127, 0x0128, 0x0129, 0x012a, 0x012b, 0x012c, 0x012d, 0x012e,
+ 0x012f, 0x0130, 0x0131, 0x0132, 0x0133, 0x0134, 0x0135, 0x0136,
+ 0x0137, 0x0138, 0x0139, 0x013a, 0x013b, 0x013c, 0x013d, 0x013e,
+ 0x013f, 0x0140, 0x0141, 0x0142, 0x0143, 0x0144, 0x0145, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ japan12RomanMap2, 2
+};
+
+static Gushort japan12UniJISUCS2HMap2[13926] = {
+ 0x0000, 0x0000,
+ 0x0020, 0x0001,
+ 0x005c, 0x0061,
+ 0x005d, 0x003e,
+ 0x00a1, 0x0065,
+ 0x00a4, 0x006b,
+ 0x00a5, 0x003d,
+ 0x00a6, 0x0063,
+ 0x00a7, 0x02d0,
+ 0x00a8, 0x0287,
+ 0x00a9, 0x0098,
+ 0x00aa, 0x008c,
+ 0x00ab, 0x006d,
+ 0x00ac, 0x0099,
+ 0x00ad, 0x0097,
+ 0x00ae, 0x009a,
+ 0x00af, 0x0081,
+ 0x00b0, 0x02c3,
+ 0x00b1, 0x02b6,
+ 0x00b2, 0x009d,
+ 0x00b4, 0x0285,
+ 0x00b5, 0x009f,
+ 0x00b6, 0x030a,
+ 0x00b7, 0x0075,
+ 0x00b8, 0x0086,
+ 0x00b9, 0x00a0,
+ 0x00ba, 0x0090,
+ 0x00bb, 0x007b,
+ 0x00bc, 0x00a1,
+ 0x00bf, 0x007e,
+ 0x00c0, 0x00a4,
+ 0x00c6, 0x008b,
+ 0x00c7, 0x00aa,
+ 0x00d7, 0x02b7,
+ 0x00d8, 0x008e,
+ 0x00d9, 0x00bb,
+ 0x00df, 0x0096,
+ 0x00e0, 0x00c1,
+ 0x00e6, 0x0091,
+ 0x00e7, 0x00c7,
+ 0x00f7, 0x02b8,
+ 0x00f8, 0x0094,
+ 0x00f9, 0x00d8,
+ 0x0131, 0x0092,
+ 0x0141, 0x008d,
+ 0x0142, 0x0093,
+ 0x0152, 0x008f,
+ 0x0153, 0x0095,
+ 0x0160, 0x00df,
+ 0x0161, 0x00e3,
+ 0x0178, 0x00e0,
+ 0x017d, 0x00e1,
+ 0x017e, 0x00e5,
+ 0x01c0, 0x0063,
+ 0x0300, 0x0041,
+ 0x0301, 0x007f,
+ 0x0303, 0x005f,
+ 0x0304, 0x0081,
+ 0x0305, 0x00e2,
+ 0x0306, 0x0082,
+ 0x030a, 0x0085,
+ 0x030b, 0x0087,
+ 0x030c, 0x0089,
+ 0x0327, 0x0086,
+ 0x0328, 0x0088,
+ 0x0332, 0x0040,
+ 0x0336, 0x008a,
+ 0x0361, 0x02f6,
+ 0x0391, 0x03f3,
+ 0x03a3, 0x0404,
+ 0x03b1, 0x040b,
+ 0x03c3, 0x041c,
+ 0x0401, 0x0429,
+ 0x0410, 0x0423,
+ 0x0416, 0x042a,
+ 0x0436, 0x044b,
+ 0x0451, 0x044a,
+ 0x2002, 0x00e7,
+ 0x2003, 0x0279,
+ 0x2010, 0x000e,
+ 0x2011, 0x000e,
+ 0x2012, 0x0072,
+ 0x2013, 0x0072,
+ 0x2014, 0x008a,
+ 0x2015, 0x0295,
+ 0x2016, 0x029a,
+ 0x2018, 0x029e,
+ 0x201a, 0x0078,
+ 0x201c, 0x02a0,
+ 0x201e, 0x0079,
+ 0x2020, 0x0308,
+ 0x2022, 0x0077,
+ 0x2025, 0x029d,
+ 0x2026, 0x029c,
+ 0x2030, 0x0304,
+ 0x2032, 0x02c4,
+ 0x2039, 0x006e,
+ 0x203b, 0x02de,
+ 0x203e, 0x0145,
+ 0x2044, 0x0068,
+ 0x20dd, 0x030b,
+ 0x2103, 0x02c6,
+ 0x2109, 0x2071,
+ 0x2113, 0x1f59,
+ 0x2116, 0x1dba,
+ 0x2121, 0x1f77,
+ 0x2122, 0x00e4,
+ 0x212b, 0x0303,
+ 0x2160, 0x1d97,
+ 0x216a, 0x2021,
+ 0x2170, 0x1f9c,
+ 0x217a, 0x206a,
+ 0x217f, 0x206f,
+ 0x2190, 0x02e1,
+ 0x2192, 0x02e0,
+ 0x2193, 0x02e3,
+ 0x21c4, 0x2076,
+ 0x21c6, 0x2075,
+ 0x21d2, 0x02f0,
+ 0x21d4, 0x02f1,
+ 0x21e6, 0x1f4d,
+ 0x21e7, 0x1f4c,
+ 0x21e8, 0x1f4e,
+ 0x21e9, 0x1f4b,
+ 0x2200, 0x02f2,
+ 0x2202, 0x02f7,
+ 0x2203, 0x02f3,
+ 0x2207, 0x02f8,
+ 0x2208, 0x02e5,
+ 0x220b, 0x02e6,
+ 0x2211, 0x1dc9,
+ 0x2212, 0x02b5,
+ 0x221a, 0x02fd,
+ 0x221d, 0x02ff,
+ 0x221e, 0x02bf,
+ 0x221f, 0x1dcd,
+ 0x2220, 0x02f4,
+ 0x2225, 0x029a,
+ 0x2227, 0x02ed,
+ 0x2229, 0x02ec,
+ 0x222a, 0x02eb,
+ 0x222b, 0x0301,
+ 0x222d, 0x2003,
+ 0x222e, 0x1dc8,
+ 0x2234, 0x02c0,
+ 0x2235, 0x0300,
+ 0x223c, 0x0299,
+ 0x223d, 0x02fe,
+ 0x2252, 0x02fa,
+ 0x2260, 0x02ba,
+ 0x2261, 0x02f9,
+ 0x2266, 0x02bd,
+ 0x226a, 0x02fb,
+ 0x2282, 0x02e9,
+ 0x2286, 0x02e7,
+ 0x22a5, 0x02f5,
+ 0x22bf, 0x1dce,
+ 0x22ee, 0x1ed9,
+ 0x22ef, 0x029c,
+ 0x2312, 0x02f6,
+ 0x2460, 0x1d83,
+ 0x2474, 0x1f87,
+ 0x2488, 0x1f7e,
+ 0x249c, 0x1fb0,
+ 0x24ea, 0x2020,
+ 0x2500, 0x1d37,
+ 0x2550, 0x203b,
+ 0x255e, 0x203c,
+ 0x2561, 0x203e,
+ 0x256a, 0x203d,
+ 0x256d, 0x2037,
+ 0x256f, 0x203a,
+ 0x2570, 0x2039,
+ 0x2571, 0x2045,
+ 0x2581, 0x2026,
+ 0x2589, 0x2034,
+ 0x258a, 0x2033,
+ 0x258b, 0x2032,
+ 0x258c, 0x2031,
+ 0x258d, 0x2030,
+ 0x258e, 0x202f,
+ 0x258f, 0x202e,
+ 0x2594, 0x2035,
+ 0x25a0, 0x02d9,
+ 0x25a1, 0x02d8,
+ 0x25a2, 0x1f4f,
+ 0x25b2, 0x02db,
+ 0x25b3, 0x02da,
+ 0x25b7, 0x1f4a,
+ 0x25bc, 0x02dd,
+ 0x25bd, 0x02dc,
+ 0x25c1, 0x1f49,
+ 0x25c6, 0x02d7,
+ 0x25c7, 0x02d6,
+ 0x25c9, 0x2012,
+ 0x25cb, 0x02d3,
+ 0x25ce, 0x02d5,
+ 0x25cf, 0x02d4,
+ 0x25e2, 0x203f,
+ 0x25e4, 0x2042,
+ 0x25e5, 0x2041,
+ 0x25ef, 0x030b,
+ 0x2600, 0x2017,
+ 0x2605, 0x02d2,
+ 0x2606, 0x02d1,
+ 0x260e, 0x1f78,
+ 0x261c, 0x201c,
+ 0x261e, 0x201b,
+ 0x261f, 0x201e,
+ 0x2640, 0x02c2,
+ 0x2642, 0x02c1,
+ 0x2660, 0x2013,
+ 0x2661, 0x1f51,
+ 0x2662, 0x1f53,
+ 0x2663, 0x2015,
+ 0x2664, 0x1f52,
+ 0x2665, 0x2014,
+ 0x2666, 0x2016,
+ 0x2667, 0x1f50,
+ 0x266a, 0x0307,
+ 0x266d, 0x0306,
+ 0x266f, 0x0305,
+ 0x2776, 0x205e,
+ 0x27a1, 0x200e,
+ 0x3000, 0x0279,
+ 0x3003, 0x028f,
+ 0x3004, 0x2074,
+ 0x3005, 0x0291,
+ 0x3008, 0x02aa,
+ 0x3012, 0x02df,
+ 0x3013, 0x02e4,
+ 0x3014, 0x02a4,
+ 0x301c, 0x0299,
+ 0x301d, 0x1db8,
+ 0x301f, 0x1db9,
+ 0x3020, 0x1f7a,
+ 0x3036, 0x1f79,
+ 0x3041, 0x034a,
+ 0x3094, 0x1f16,
+ 0x309b, 0x0283,
+ 0x309d, 0x028d,
+ 0x30a1, 0x039d,
+ 0x30f7, 0x2079,
+ 0x30fb, 0x027e,
+ 0x30fc, 0x0294,
+ 0x30fd, 0x028b,
+ 0x322a, 0x2006,
+ 0x3230, 0x2005,
+ 0x3231, 0x1dc2,
+ 0x3233, 0x1fcf,
+ 0x3234, 0x1fcd,
+ 0x3235, 0x1fd4,
+ 0x3236, 0x1fd3,
+ 0x3237, 0x200c,
+ 0x3238, 0x1fce,
+ 0x3239, 0x1dc4,
+ 0x323a, 0x1fd7,
+ 0x323b, 0x1fd5,
+ 0x323c, 0x1fd0,
+ 0x323d, 0x1fcb,
+ 0x323e, 0x1fd2,
+ 0x323f, 0x1fcc,
+ 0x3240, 0x1fd6,
+ 0x3241, 0x200d,
+ 0x3242, 0x1fd1,
+ 0x3243, 0x1fca,
+ 0x3291, 0x1fe1,
+ 0x3292, 0x1fe0,
+ 0x3293, 0x1fe2,
+ 0x3294, 0x1fdc,
+ 0x3296, 0x1fe5,
+ 0x3298, 0x1fde,
+ 0x3299, 0x201f,
+ 0x329d, 0x207f,
+ 0x329e, 0x1fff,
+ 0x32a4, 0x1dbd,
+ 0x32a9, 0x1fda,
+ 0x32aa, 0x1fdd,
+ 0x32ab, 0x1fdf,
+ 0x32ac, 0x1fe3,
+ 0x32ad, 0x1fd9,
+ 0x32ae, 0x1fe4,
+ 0x32af, 0x1fdb,
+ 0x32b0, 0x1fd8,
+ 0x3300, 0x1f70,
+ 0x3303, 0x1f6a,
+ 0x3305, 0x1ff7,
+ 0x330d, 0x1dab,
+ 0x3314, 0x1da2,
+ 0x3315, 0x1f69,
+ 0x3316, 0x1f67,
+ 0x3318, 0x1f68,
+ 0x331e, 0x1f73,
+ 0x3322, 0x1f66,
+ 0x3323, 0x1f6b,
+ 0x3326, 0x1dac,
+ 0x3327, 0x1da6,
+ 0x332a, 0x1f74,
+ 0x332b, 0x1dae,
+ 0x3331, 0x1f71,
+ 0x3333, 0x2087,
+ 0x3336, 0x1da8,
+ 0x3339, 0x1f6e,
+ 0x333b, 0x1f6f,
+ 0x3342, 0x1f6d,
+ 0x3347, 0x1f72,
+ 0x3349, 0x1da1,
+ 0x334a, 0x1daf,
+ 0x334d, 0x1da4,
+ 0x334e, 0x2088,
+ 0x3351, 0x1da9,
+ 0x3357, 0x1f6c,
+ 0x337b, 0x2083,
+ 0x337c, 0x1dc7,
+ 0x337d, 0x1dc6,
+ 0x337e, 0x1dc5,
+ 0x337f, 0x1f76,
+ 0x3385, 0x1f5f,
+ 0x3388, 0x2000,
+ 0x338e, 0x1db4,
+ 0x3390, 0x1f63,
+ 0x3396, 0x1f65,
+ 0x3397, 0x1f58,
+ 0x3398, 0x1f5a,
+ 0x339c, 0x1db1,
+ 0x339f, 0x1ffa,
+ 0x33a0, 0x1f54,
+ 0x33a1, 0x1db7,
+ 0x33a2, 0x1f55,
+ 0x33a3, 0x1ffb,
+ 0x33a4, 0x1f56,
+ 0x33a6, 0x1ffc,
+ 0x33b0, 0x1f5e,
+ 0x33b1, 0x1f5d,
+ 0x33b2, 0x1f5c,
+ 0x33b3, 0x1f5b,
+ 0x33c4, 0x1db6,
+ 0x33c8, 0x2002,
+ 0x33cb, 0x1f62,
+ 0x33cc, 0x1ff6,
+ 0x33cd, 0x1dbb,
+ 0x33d4, 0x1f64,
+ 0x4e00, 0x04b0,
+ 0x4e01, 0x0bb8,
+ 0x4e03, 0x08e3,
+ 0x4e07, 0x0eaa,
+ 0x4e08, 0x09ce,
+ 0x4e09, 0x087e,
+ 0x4e0a, 0x09cd,
+ 0x4e0b, 0x053c,
+ 0x4e0d, 0x0dc6,
+ 0x4e0e, 0x0f29,
+ 0x4e10, 0x0ffb,
+ 0x4e11, 0x04d1,
+ 0x4e14, 0x05cc,
+ 0x4e15, 0x0ffc,
+ 0x4e16, 0x0a48,
+ 0x4e17, 0x10d7,
+ 0x4e18, 0x0670,
+ 0x4e19, 0x0e0a,
+ 0x4e1e, 0x09cf,
+ 0x4e21, 0x0f86,
+ 0x4e26, 0x0e12,
+ 0x4e28, 0x20b3,
+ 0x4e2a, 0x0ffd,
+ 0x4e2d, 0x0ba4,
+ 0x4e31, 0x0ffe,
+ 0x4e32, 0x06f2,
+ 0x4e36, 0x0fff,
+ 0x4e38, 0x0619,
+ 0x4e39, 0x0b6e,
+ 0x4e3b, 0x0913,
+ 0x4e3c, 0x1000,
+ 0x4e3f, 0x1001,
+ 0x4e42, 0x1002,
+ 0x4e43, 0x0ceb,
+ 0x4e45, 0x0671,
+ 0x4e4b, 0x0ced,
+ 0x4e4d, 0x0cbb,
+ 0x4e4e, 0x0777,
+ 0x4e4f, 0x0e61,
+ 0x4e55, 0x1950,
+ 0x4e56, 0x1003,
+ 0x4e57, 0x09d0,
+ 0x4e58, 0x1004,
+ 0x4e59, 0x0535,
+ 0x4e5d, 0x06dd,
+ 0x4e5e, 0x07a4,
+ 0x4e5f, 0x0ef5,
+ 0x4e62, 0x1233,
+ 0x4e71, 0x0f5a,
+ 0x4e73, 0x0cd5,
+ 0x4e7e, 0x05e1,
+ 0x4e80, 0x064f,
+ 0x4e82, 0x1005,
+ 0x4e85, 0x1006,
+ 0x4e86, 0x0f83,
+ 0x4e88, 0x0f27,
+ 0x4e89, 0x0aea,
+ 0x4e8a, 0x1008,
+ 0x4e8b, 0x08c4,
+ 0x4e8c, 0x0ccb,
+ 0x4e8e, 0x100b,
+ 0x4e91, 0x04e0,
+ 0x4e92, 0x0793,
+ 0x4e94, 0x0792,
+ 0x4e95, 0x04aa,
+ 0x4e98, 0x0ff1,
+ 0x4e99, 0x0ff0,
+ 0x4e9b, 0x0823,
+ 0x4e9c, 0x0465,
+ 0x4e9e, 0x100c,
+ 0x4ea1, 0x0e62,
+ 0x4ea2, 0x100f,
+ 0x4ea4, 0x07a6,
+ 0x4ea5, 0x04ab,
+ 0x4ea6, 0x0ea0,
+ 0x4ea8, 0x0696,
+ 0x4eab, 0x0697,
+ 0x4ead, 0x0bfe,
+ 0x4eae, 0x0f84,
+ 0x4eb0, 0x1010,
+ 0x4eb3, 0x1011,
+ 0x4eb6, 0x1012,
+ 0x4eba, 0x0a13,
+ 0x4ec0, 0x0944,
+ 0x4ec1, 0x0a14,
+ 0x4ec2, 0x1017,
+ 0x4ec4, 0x1015,
+ 0x4ec6, 0x1016,
+ 0x4ec7, 0x0672,
+ 0x4eca, 0x0813,
+ 0x4ecb, 0x0570,
+ 0x4ecd, 0x1014,
+ 0x4ece, 0x1013,
+ 0x4ecf, 0x0df9,
+ 0x4ed4, 0x0894,
+ 0x4ed5, 0x0893,
+ 0x4ed6, 0x0b1e,
+ 0x4ed7, 0x1018,
+ 0x4ed8, 0x0dc7,
+ 0x4ed9, 0x0a8b,
+ 0x4edd, 0x0290,
+ 0x4ede, 0x1019,
+ 0x4edf, 0x101b,
+ 0x4ee1, 0x20b4,
+ 0x4ee3, 0x0b45,
+ 0x4ee4, 0x0fa9,
+ 0x4ee5, 0x048e,
+ 0x4eed, 0x101a,
+ 0x4eee, 0x053e,
+ 0x4ef0, 0x06bc,
+ 0x4ef2, 0x0ba5,
+ 0x4ef6, 0x0745,
+ 0x4ef7, 0x101c,
+ 0x4efb, 0x0cda,
+ 0x4efc, 0x20b5,
+ 0x4f00, 0x20b6,
+ 0x4f01, 0x0627,
+ 0x4f03, 0x20b7,
+ 0x4f09, 0x101d,
+ 0x4f0a, 0x048f,
+ 0x4f0d, 0x0794,
+ 0x4f0e, 0x0628,
+ 0x4f0f, 0x0dec,
+ 0x4f10, 0x0d46,
+ 0x4f11, 0x0673,
+ 0x4f1a, 0x0571,
+ 0x4f1c, 0x1040,
+ 0x4f1d, 0x0c3b,
+ 0x4f2f, 0x0d22,
+ 0x4f30, 0x101f,
+ 0x4f34, 0x0d50,
+ 0x4f36, 0x0faa,
+ 0x4f38, 0x09f3,
+ 0x4f39, 0x20b8,
+ 0x4f3a, 0x0895,
+ 0x4f3c, 0x08c5,
+ 0x4f3d, 0x0540,
+ 0x4f43, 0x0bed,
+ 0x4f46, 0x0b60,
+ 0x4f47, 0x1023,
+ 0x4f4d, 0x0490,
+ 0x4f4e, 0x0bff,
+ 0x4f4f, 0x0945,
+ 0x4f50, 0x0824,
+ 0x4f51, 0x0f0e,
+ 0x4f53, 0x0b2e,
+ 0x4f55, 0x053f,
+ 0x4f56, 0x20b9,
+ 0x4f57, 0x1022,
+ 0x4f59, 0x0f28,
+ 0x4f5a, 0x101e,
+ 0x4f5b, 0x1020,
+ 0x4f5c, 0x085e,
+ 0x4f5d, 0x1021,
+ 0x4f5e, 0x11d3,
+ 0x4f69, 0x1029,
+ 0x4f6f, 0x102c,
+ 0x4f70, 0x102a,
+ 0x4f73, 0x0542,
+ 0x4f75, 0x0e0b,
+ 0x4f76, 0x1024,
+ 0x4f7b, 0x1028,
+ 0x4f7c, 0x07a7,
+ 0x4f7f, 0x0896,
+ 0x4f83, 0x05e2,
+ 0x4f86, 0x102d,
+ 0x4f88, 0x1025,
+ 0x4f8a, 0x20bb,
+ 0x4f8b, 0x0fab,
+ 0x4f8d, 0x08c6,
+ 0x4f8f, 0x1026,
+ 0x4f91, 0x102b,
+ 0x4f92, 0x20ba,
+ 0x4f94, 0x20bd,
+ 0x4f96, 0x102e,
+ 0x4f98, 0x1027,
+ 0x4f9a, 0x20bc,
+ 0x4f9b, 0x0699,
+ 0x4f9d, 0x0491,
+ 0x4fa0, 0x069a,
+ 0x4fa1, 0x0541,
+ 0x4fab, 0x11d4,
+ 0x4fad, 0x0ea7,
+ 0x4fae, 0x0de0,
+ 0x4faf, 0x07a8,
+ 0x4fb5, 0x09f5,
+ 0x4fb6, 0x0f7f,
+ 0x4fbf, 0x0e28,
+ 0x4fc2, 0x070e,
+ 0x4fc3, 0x0b05,
+ 0x4fc4, 0x0564,
+ 0x4fc9, 0x20ac,
+ 0x4fca, 0x095d,
+ 0x4fcd, 0x20be,
+ 0x4fce, 0x1032,
+ 0x4fd0, 0x1037,
+ 0x4fd1, 0x1035,
+ 0x4fd4, 0x1030,
+ 0x4fd7, 0x0b0f,
+ 0x4fd8, 0x1033,
+ 0x4fda, 0x1036,
+ 0x4fdb, 0x1034,
+ 0x4fdd, 0x0e2d,
+ 0x4fdf, 0x1031,
+ 0x4fe0, 0x1dec,
+ 0x4fe1, 0x09f4,
+ 0x4fe3, 0x0ea1,
+ 0x4fe4, 0x1038,
+ 0x4fee, 0x092e,
+ 0x4fef, 0x1046,
+ 0x4ff3, 0x0d06,
+ 0x4ff5, 0x0da8,
+ 0x4ff6, 0x1041,
+ 0x4ff8, 0x0e40,
+ 0x4ffa, 0x0536,
+ 0x4ffe, 0x1045,
+ 0x4fff, 0x20c1,
+ 0x5005, 0x103f,
+ 0x5006, 0x1048,
+ 0x5009, 0x0ad4,
+ 0x500b, 0x0778,
+ 0x500d, 0x0d12,
+ 0x500f, 0x1600,
+ 0x5011, 0x1047,
+ 0x5012, 0x0c57,
+ 0x5014, 0x103c,
+ 0x5016, 0x07aa,
+ 0x5019, 0x07a9,
+ 0x501a, 0x103a,
+ 0x501e, 0x20c2,
+ 0x501f, 0x0906,
+ 0x5021, 0x1042,
+ 0x5022, 0x20c0,
+ 0x5023, 0x0e3f,
+ 0x5024, 0x0b8b,
+ 0x5025, 0x103e,
+ 0x5026, 0x0747,
+ 0x5028, 0x103b,
+ 0x5029, 0x1043,
+ 0x502a, 0x103d,
+ 0x502b, 0x0f99,
+ 0x502c, 0x1044,
+ 0x502d, 0x0fe7,
+ 0x5036, 0x06de,
+ 0x5039, 0x0746,
+ 0x5040, 0x20bf,
+ 0x5042, 0x20c5,
+ 0x5043, 0x1049,
+ 0x5046, 0x20c3,
+ 0x5047, 0x104a,
+ 0x5048, 0x104e,
+ 0x5049, 0x0492,
+ 0x504f, 0x0e20,
+ 0x5050, 0x104d,
+ 0x5055, 0x104c,
+ 0x5056, 0x1050,
+ 0x505a, 0x104f,
+ 0x505c, 0x0c00,
+ 0x5065, 0x0748,
+ 0x506c, 0x1051,
+ 0x5070, 0x20c4,
+ 0x5072, 0x08f1,
+ 0x5074, 0x0b06,
+ 0x5075, 0x0c01,
+ 0x5076, 0x06ee,
+ 0x5078, 0x1052,
+ 0x507d, 0x0650,
+ 0x5080, 0x1053,
+ 0x5085, 0x1055,
+ 0x508d, 0x0e63,
+ 0x5091, 0x073c,
+ 0x5094, 0x20c6,
+ 0x5098, 0x087f,
+ 0x5099, 0x0d8b,
+ 0x509a, 0x1054,
+ 0x50ac, 0x0835,
+ 0x50ad, 0x0f2d,
+ 0x50b2, 0x1057,
+ 0x50b3, 0x105a,
+ 0x50b4, 0x1056,
+ 0x50b5, 0x0834,
+ 0x50b7, 0x0987,
+ 0x50be, 0x070f,
+ 0x50c2, 0x105b,
+ 0x50c5, 0x06c7,
+ 0x50c9, 0x1058,
+ 0x50cd, 0x0c87,
+ 0x50cf, 0x0afe,
+ 0x50d1, 0x069b,
+ 0x50d5, 0x0e7b,
+ 0x50d6, 0x105c,
+ 0x50d8, 0x20c8,
+ 0x50da, 0x0f85,
+ 0x50de, 0x105d,
+ 0x50e3, 0x1060,
+ 0x50e5, 0x105e,
+ 0x50e7, 0x0ad0,
+ 0x50ed, 0x105f,
+ 0x50ee, 0x1061,
+ 0x50f4, 0x20c7,
+ 0x50f5, 0x1063,
+ 0x50f9, 0x1062,
+ 0x50fb, 0x0e18,
+ 0x5100, 0x0651,
+ 0x5101, 0x1065,
+ 0x5104, 0x052f,
+ 0x5109, 0x1064,
+ 0x5112, 0x0920,
+ 0x5114, 0x1069,
+ 0x5115, 0x1068,
+ 0x5116, 0x1067,
+ 0x5118, 0x102f,
+ 0x511a, 0x106a,
+ 0x511f, 0x0988,
+ 0x5121, 0x106b,
+ 0x512a, 0x0f0f,
+ 0x5132, 0x0ee5,
+ 0x5137, 0x106d,
+ 0x513a, 0x106c,
+ 0x513b, 0x106f,
+ 0x513c, 0x106e,
+ 0x513f, 0x1070,
+ 0x5141, 0x04b8,
+ 0x5143, 0x0769,
+ 0x5144, 0x0711,
+ 0x5145, 0x0946,
+ 0x5146, 0x0bb9,
+ 0x5147, 0x069c,
+ 0x5148, 0x0a8c,
+ 0x5149, 0x07ab,
+ 0x514a, 0x20c9,
+ 0x514b, 0x0800,
+ 0x514c, 0x1073,
+ 0x514d, 0x0ed4,
+ 0x514e, 0x0c40,
+ 0x5150, 0x08c7,
+ 0x5152, 0x1072,
+ 0x5154, 0x1074,
+ 0x515a, 0x0c58,
+ 0x515c, 0x05d3,
+ 0x5162, 0x1075,
+ 0x5164, 0x20ca,
+ 0x5165, 0x0cd6,
+ 0x5168, 0x0ab6,
+ 0x5169, 0x1077,
+ 0x516b, 0x0d40,
+ 0x516c, 0x07ac,
+ 0x516d, 0x0fe1,
+ 0x516e, 0x1079,
+ 0x5171, 0x069e,
+ 0x5175, 0x0e0c,
+ 0x5176, 0x0b16,
+ 0x5177, 0x06e9,
+ 0x5178, 0x0c2f,
+ 0x517c, 0x0749,
+ 0x5180, 0x107a,
+ 0x5182, 0x107b,
+ 0x5185, 0x0cba,
+ 0x5186, 0x0501,
+ 0x5189, 0x107e,
+ 0x518a, 0x086d,
+ 0x518c, 0x107d,
+ 0x518d, 0x0836,
+ 0x518f, 0x107f,
+ 0x5190, 0x185b,
+ 0x5191, 0x1080,
+ 0x5192, 0x0e6f,
+ 0x5193, 0x1081,
+ 0x5195, 0x1082,
+ 0x5197, 0x09d1,
+ 0x5199, 0x08f8,
+ 0x519d, 0x20cb,
+ 0x51a0, 0x05e3,
+ 0x51a2, 0x1086,
+ 0x51a4, 0x1084,
+ 0x51a5, 0x0ec9,
+ 0x51a6, 0x1085,
+ 0x51a8, 0x0dcc,
+ 0x51a9, 0x1087,
+ 0x51ac, 0x0c59,
+ 0x51b0, 0x108d,
+ 0x51b1, 0x108b,
+ 0x51b3, 0x108a,
+ 0x51b4, 0x0853,
+ 0x51b5, 0x108e,
+ 0x51b6, 0x0ef6,
+ 0x51b7, 0x0fac,
+ 0x51bd, 0x108f,
+ 0x51be, 0x20cc,
+ 0x51c4, 0x0a4c,
+ 0x51c5, 0x1090,
+ 0x51c6, 0x0964,
+ 0x51c9, 0x1091,
+ 0x51cb, 0x0bba,
+ 0x51cc, 0x0f87,
+ 0x51cd, 0x0c5a,
+ 0x51d6, 0x10da,
+ 0x51db, 0x1092,
+ 0x51dc, 0x205c,
+ 0x51dd, 0x06bd,
+ 0x51e0, 0x1093,
+ 0x51e1, 0x0e8c,
+ 0x51e6, 0x0972,
+ 0x51e7, 0x0b5c,
+ 0x51e9, 0x1095,
+ 0x51ea, 0x0cbc,
+ 0x51ec, 0x20cd,
+ 0x51ed, 0x1096,
+ 0x51f0, 0x1097,
+ 0x51f1, 0x058c,
+ 0x51f5, 0x1098,
+ 0x51f6, 0x069f,
+ 0x51f8, 0x0ca4,
+ 0x51f9, 0x051c,
+ 0x51fa, 0x095a,
+ 0x51fd, 0x0d35,
+ 0x51fe, 0x1099,
+ 0x5200, 0x0c5b,
+ 0x5203, 0x0a15,
+ 0x5204, 0x109a,
+ 0x5206, 0x0dfc,
+ 0x5207, 0x0a7e,
+ 0x5208, 0x05de,
+ 0x520a, 0x05e5,
+ 0x520b, 0x109b,
+ 0x520e, 0x109d,
+ 0x5211, 0x0710,
+ 0x5214, 0x109c,
+ 0x5215, 0x20ce,
+ 0x5217, 0x0fbb,
+ 0x521d, 0x0973,
+ 0x5224, 0x0d51,
+ 0x5225, 0x0e1c,
+ 0x5227, 0x109e,
+ 0x5229, 0x0f62,
+ 0x522a, 0x109f,
+ 0x522e, 0x10a0,
+ 0x5230, 0x0c78,
+ 0x5233, 0x10a1,
+ 0x5236, 0x0a4d,
+ 0x5237, 0x086e,
+ 0x5238, 0x074a,
+ 0x5239, 0x10a2,
+ 0x523a, 0x0897,
+ 0x523b, 0x0801,
+ 0x5243, 0x0c02,
+ 0x5244, 0x10a4,
+ 0x5247, 0x0b07,
+ 0x524a, 0x085f,
+ 0x524b, 0x10a5,
+ 0x524d, 0x0ab2,
+ 0x524f, 0x10a3,
+ 0x5254, 0x10a8,
+ 0x5256, 0x0e64,
+ 0x525b, 0x07f6,
+ 0x525d, 0x1e5e,
+ 0x525e, 0x10a7,
+ 0x5263, 0x074b,
+ 0x5264, 0x084e,
+ 0x5265, 0x0d23,
+ 0x5269, 0x10ab,
+ 0x526a, 0x10a9,
+ 0x526f, 0x0ded,
+ 0x5270, 0x09d2,
+ 0x5271, 0x10b2,
+ 0x5272, 0x05c2,
+ 0x5273, 0x10ac,
+ 0x5274, 0x10aa,
+ 0x5275, 0x0ad1,
+ 0x527d, 0x10ae,
+ 0x527f, 0x10ad,
+ 0x5283, 0x05a2,
+ 0x5287, 0x0736,
+ 0x5288, 0x10b3,
+ 0x5289, 0x0f75,
+ 0x528d, 0x10af,
+ 0x5291, 0x10b4,
+ 0x5292, 0x10b1,
+ 0x5294, 0x10b0,
+ 0x529b, 0x0f97,
+ 0x529c, 0x20cf,
+ 0x529f, 0x07ad,
+ 0x52a0, 0x0543,
+ 0x52a3, 0x0fbc,
+ 0x52a6, 0x20d0,
+ 0x52a9, 0x097f,
+ 0x52aa, 0x0c52,
+ 0x52ab, 0x07f7,
+ 0x52ac, 0x10b7,
+ 0x52af, 0x217d,
+ 0x52b1, 0x0fad,
+ 0x52b4, 0x0fd1,
+ 0x52b5, 0x10ba,
+ 0x52b9, 0x07ae,
+ 0x52bc, 0x10b9,
+ 0x52be, 0x058d,
+ 0x52c0, 0x20d1,
+ 0x52c1, 0x10bb,
+ 0x52c3, 0x0e84,
+ 0x52c5, 0x0bd8,
+ 0x52c7, 0x0f10,
+ 0x52c9, 0x0e29,
+ 0x52cd, 0x10bc,
+ 0x52d2, 0x1bee,
+ 0x52d5, 0x0c88,
+ 0x52d7, 0x10bd,
+ 0x52d8, 0x05e6,
+ 0x52d9, 0x0ebf,
+ 0x52db, 0x20d2,
+ 0x52dd, 0x0989,
+ 0x52de, 0x10be,
+ 0x52df, 0x0e37,
+ 0x52e0, 0x10c2,
+ 0x52e2, 0x0a4e,
+ 0x52e3, 0x10bf,
+ 0x52e4, 0x06c8,
+ 0x52e6, 0x10c0,
+ 0x52e7, 0x05e7,
+ 0x52f2, 0x0704,
+ 0x52f3, 0x10c3,
+ 0x52f5, 0x10c4,
+ 0x52f8, 0x10c5,
+ 0x52fa, 0x0907,
+ 0x52fe, 0x07af,
+ 0x52ff, 0x0eea,
+ 0x5300, 0x20d3,
+ 0x5301, 0x0ef4,
+ 0x5302, 0x0ccf,
+ 0x5305, 0x0e41,
+ 0x5306, 0x10c7,
+ 0x5307, 0x20d4,
+ 0x5308, 0x10c8,
+ 0x530d, 0x10ca,
+ 0x530f, 0x10cc,
+ 0x5310, 0x10cb,
+ 0x5315, 0x10cd,
+ 0x5316, 0x053d,
+ 0x5317, 0x0e7a,
+ 0x5319, 0x086c,
+ 0x531a, 0x10ce,
+ 0x531d, 0x0adb,
+ 0x5320, 0x098a,
+ 0x5321, 0x06a1,
+ 0x5323, 0x10cf,
+ 0x5324, 0x20d5,
+ 0x532a, 0x0d6f,
+ 0x532f, 0x10d0,
+ 0x5331, 0x10d1,
+ 0x5333, 0x10d2,
+ 0x5338, 0x10d3,
+ 0x5339, 0x0d96,
+ 0x533a, 0x06e0,
+ 0x533b, 0x04a9,
+ 0x533f, 0x0c97,
+ 0x5340, 0x10d4,
+ 0x5341, 0x0947,
+ 0x5343, 0x0a8d,
+ 0x5345, 0x10d6,
+ 0x5346, 0x10d5,
+ 0x5347, 0x098b,
+ 0x5348, 0x0795,
+ 0x5349, 0x10d8,
+ 0x534a, 0x0d52,
+ 0x534d, 0x10d9,
+ 0x5351, 0x0d70,
+ 0x5352, 0x0b14,
+ 0x5353, 0x0b4e,
+ 0x5354, 0x06a0,
+ 0x5357, 0x0cc6,
+ 0x5358, 0x0b6f,
+ 0x535a, 0x0d24,
+ 0x535c, 0x0e7c,
+ 0x535e, 0x10db,
+ 0x5360, 0x0a8e,
+ 0x5366, 0x070b,
+ 0x5369, 0x10dc,
+ 0x536e, 0x10dd,
+ 0x536f, 0x04ce,
+ 0x5370, 0x04b9,
+ 0x5371, 0x0629,
+ 0x5372, 0x20d6,
+ 0x5373, 0x0b08,
+ 0x5374, 0x066b,
+ 0x5375, 0x0f5b,
+ 0x5377, 0x10e0,
+ 0x5378, 0x0537,
+ 0x537b, 0x10df,
+ 0x537f, 0x06a2,
+ 0x5382, 0x10e1,
+ 0x5384, 0x0efd,
+ 0x5393, 0x20d7,
+ 0x5396, 0x10e2,
+ 0x5398, 0x0f9a,
+ 0x539a, 0x07b0,
+ 0x539f, 0x076a,
+ 0x53a0, 0x10e3,
+ 0x53a5, 0x10e5,
+ 0x53a6, 0x10e4,
+ 0x53a8, 0x0a25,
+ 0x53a9, 0x04db,
+ 0x53ad, 0x0500,
+ 0x53ae, 0x10e6,
+ 0x53b0, 0x10e7,
+ 0x53b2, 0x20d8,
+ 0x53b3, 0x076b,
+ 0x53b6, 0x10e8,
+ 0x53bb, 0x0688,
+ 0x53c2, 0x0880,
+ 0x53c3, 0x10e9,
+ 0x53c8, 0x0ea2,
+ 0x53c9, 0x0825,
+ 0x53ca, 0x0674,
+ 0x53cb, 0x0f11,
+ 0x53cc, 0x0ad2,
+ 0x53cd, 0x0d53,
+ 0x53ce, 0x0929,
+ 0x53d4, 0x0951,
+ 0x53d6, 0x0914,
+ 0x53d7, 0x0921,
+ 0x53d9, 0x0980,
+ 0x53db, 0x0d54,
+ 0x53dd, 0x20d9,
+ 0x53df, 0x10ec,
+ 0x53e1, 0x04e5,
+ 0x53e2, 0x0ad3,
+ 0x53e3, 0x07b1,
+ 0x53e4, 0x0779,
+ 0x53e5, 0x06df,
+ 0x53e8, 0x10f0,
+ 0x53e9, 0x0b5f,
+ 0x53ea, 0x0b5e,
+ 0x53eb, 0x06a3,
+ 0x53ec, 0x098c,
+ 0x53ed, 0x10f1,
+ 0x53ee, 0x10ef,
+ 0x53ef, 0x0544,
+ 0x53f0, 0x0b46,
+ 0x53f1, 0x08e4,
+ 0x53f2, 0x0899,
+ 0x53f3, 0x04c8,
+ 0x53f6, 0x05ce,
+ 0x53f7, 0x07f8,
+ 0x53f8, 0x0898,
+ 0x53fa, 0x10f2,
+ 0x5401, 0x10f3,
+ 0x5403, 0x0663,
+ 0x5404, 0x05a4,
+ 0x5408, 0x07f9,
+ 0x5409, 0x0662,
+ 0x540a, 0x0bfb,
+ 0x540b, 0x04c7,
+ 0x540c, 0x0c89,
+ 0x540d, 0x0eca,
+ 0x540e, 0x07b3,
+ 0x540f, 0x0f63,
+ 0x5410, 0x0c41,
+ 0x5411, 0x07b2,
+ 0x541b, 0x0705,
+ 0x541d, 0x10fc,
+ 0x541f, 0x06db,
+ 0x5420, 0x0e78,
+ 0x5426, 0x0d71,
+ 0x5429, 0x10fb,
+ 0x542b, 0x061a,
+ 0x542c, 0x10f6,
+ 0x542e, 0x10f9,
+ 0x5436, 0x10fa,
+ 0x5438, 0x0675,
+ 0x5439, 0x0a27,
+ 0x543b, 0x0dfd,
+ 0x543c, 0x10f8,
+ 0x543d, 0x10f4,
+ 0x543e, 0x0797,
+ 0x5440, 0x10f5,
+ 0x5442, 0x0fca,
+ 0x5446, 0x0e42,
+ 0x5448, 0x0c04,
+ 0x5449, 0x0796,
+ 0x544a, 0x0802,
+ 0x544e, 0x10fd,
+ 0x5451, 0x0cb5,
+ 0x545f, 0x1101,
+ 0x5468, 0x092a,
+ 0x546a, 0x0922,
+ 0x5470, 0x1104,
+ 0x5471, 0x1102,
+ 0x5473, 0x0eaf,
+ 0x5475, 0x10ff,
+ 0x5476, 0x1108,
+ 0x5477, 0x1103,
+ 0x547b, 0x1106,
+ 0x547c, 0x077a,
+ 0x547d, 0x0ecb,
+ 0x5480, 0x1107,
+ 0x5484, 0x1109,
+ 0x5486, 0x110b,
+ 0x548a, 0x20dc,
+ 0x548b, 0x0860,
+ 0x548c, 0x0fe8,
+ 0x548e, 0x1100,
+ 0x548f, 0x10fe,
+ 0x5490, 0x110a,
+ 0x5492, 0x1105,
+ 0x549c, 0x20db,
+ 0x54a2, 0x110d,
+ 0x54a4, 0x1116,
+ 0x54a5, 0x110f,
+ 0x54a8, 0x1113,
+ 0x54a9, 0x20dd,
+ 0x54ab, 0x1114,
+ 0x54ac, 0x1110,
+ 0x54af, 0x1131,
+ 0x54b2, 0x0859,
+ 0x54b3, 0x058f,
+ 0x54b8, 0x110e,
+ 0x54bc, 0x1118,
+ 0x54bd, 0x04ba,
+ 0x54be, 0x1117,
+ 0x54c0, 0x0469,
+ 0x54c1, 0x0dbc,
+ 0x54c2, 0x1115,
+ 0x54c4, 0x1111,
+ 0x54c7, 0x110c,
+ 0x54c8, 0x1112,
+ 0x54c9, 0x0838,
+ 0x54d8, 0x1119,
+ 0x54e1, 0x04bb,
+ 0x54e2, 0x1122,
+ 0x54e5, 0x111a,
+ 0x54e8, 0x098d,
+ 0x54e9, 0x0e97,
+ 0x54ed, 0x1120,
+ 0x54ee, 0x111f,
+ 0x54f2, 0x0c29,
+ 0x54fa, 0x1121,
+ 0x54fd, 0x111e,
+ 0x54ff, 0x20de,
+ 0x5504, 0x04d6,
+ 0x5506, 0x0826,
+ 0x5507, 0x09f6,
+ 0x550f, 0x111c,
+ 0x5510, 0x0c5c,
+ 0x5514, 0x111d,
+ 0x5516, 0x0466,
+ 0x552e, 0x1127,
+ 0x552f, 0x0f0d,
+ 0x5531, 0x098f,
+ 0x5533, 0x112d,
+ 0x5538, 0x112c,
+ 0x5539, 0x1123,
+ 0x553e, 0x0b23,
+ 0x5540, 0x1124,
+ 0x5544, 0x0b4f,
+ 0x5545, 0x1129,
+ 0x5546, 0x098e,
+ 0x554c, 0x1126,
+ 0x554f, 0x0ef0,
+ 0x5553, 0x0712,
+ 0x5556, 0x112a,
+ 0x555c, 0x1128,
+ 0x555d, 0x112e,
+ 0x555e, 0x1dd1,
+ 0x5563, 0x1125,
+ 0x557b, 0x1134,
+ 0x557c, 0x1139,
+ 0x557e, 0x1135,
+ 0x5580, 0x1130,
+ 0x5583, 0x113a,
+ 0x5584, 0x0ab3,
+ 0x5586, 0x20df,
+ 0x5587, 0x113c,
+ 0x5589, 0x07b4,
+ 0x558a, 0x1132,
+ 0x558b, 0x0bbb,
+ 0x5598, 0x1136,
+ 0x5599, 0x112f,
+ 0x559a, 0x05e9,
+ 0x559c, 0x062a,
+ 0x559d, 0x05c3,
+ 0x559e, 0x1137,
+ 0x559f, 0x1133,
+ 0x55a7, 0x074c,
+ 0x55a8, 0x113d,
+ 0x55a9, 0x113b,
+ 0x55aa, 0x0ad5,
+ 0x55ab, 0x0664,
+ 0x55ac, 0x06a4,
+ 0x55ae, 0x1138,
+ 0x55b0, 0x06ec,
+ 0x55b6, 0x04e6,
+ 0x55c4, 0x1141,
+ 0x55c5, 0x113f,
+ 0x55c7, 0x1178,
+ 0x55d4, 0x1144,
+ 0x55da, 0x113e,
+ 0x55dc, 0x1142,
+ 0x55df, 0x1140,
+ 0x55e3, 0x089a,
+ 0x55e4, 0x1143,
+ 0x55f7, 0x1146,
+ 0x55f9, 0x114b,
+ 0x55fd, 0x1149,
+ 0x55fe, 0x1148,
+ 0x5606, 0x0b70,
+ 0x5609, 0x0545,
+ 0x5614, 0x1145,
+ 0x5616, 0x1147,
+ 0x5617, 0x0990,
+ 0x5618, 0x04d5,
+ 0x561b, 0x114a,
+ 0x5629, 0x055e,
+ 0x562f, 0x1155,
+ 0x5631, 0x09e4,
+ 0x5632, 0x1151,
+ 0x5634, 0x114f,
+ 0x5636, 0x1150,
+ 0x5638, 0x1152,
+ 0x5642, 0x04df,
+ 0x564c, 0x0abb,
+ 0x564e, 0x114c,
+ 0x5650, 0x114d,
+ 0x5653, 0x1f1b,
+ 0x565b, 0x05d8,
+ 0x5664, 0x1154,
+ 0x5668, 0x062b,
+ 0x566a, 0x1157,
+ 0x566b, 0x1153,
+ 0x566c, 0x1156,
+ 0x5674, 0x0dfe,
+ 0x5678, 0x0cad,
+ 0x567a, 0x0d4c,
+ 0x5680, 0x1159,
+ 0x5686, 0x1158,
+ 0x5687, 0x05a3,
+ 0x568a, 0x115a,
+ 0x568f, 0x115d,
+ 0x5694, 0x115c,
+ 0x5699, 0x1de6,
+ 0x56a0, 0x115b,
+ 0x56a2, 0x0cef,
+ 0x56a5, 0x115e,
+ 0x56ae, 0x115f,
+ 0x56b4, 0x1161,
+ 0x56b6, 0x1160,
+ 0x56bc, 0x1163,
+ 0x56c0, 0x1166,
+ 0x56c1, 0x1164,
+ 0x56c2, 0x1162,
+ 0x56c3, 0x1165,
+ 0x56c8, 0x1167,
+ 0x56ca, 0x1e5a,
+ 0x56ce, 0x1168,
+ 0x56d1, 0x1169,
+ 0x56d3, 0x116a,
+ 0x56d7, 0x116b,
+ 0x56d8, 0x107c,
+ 0x56da, 0x0928,
+ 0x56db, 0x089b,
+ 0x56de, 0x0573,
+ 0x56e0, 0x04bc,
+ 0x56e3, 0x0b82,
+ 0x56ee, 0x116c,
+ 0x56f0, 0x0814,
+ 0x56f2, 0x0493,
+ 0x56f3, 0x0a24,
+ 0x56f9, 0x116d,
+ 0x56fa, 0x077b,
+ 0x56fd, 0x0803,
+ 0x56ff, 0x116f,
+ 0x5700, 0x116e,
+ 0x5703, 0x0e30,
+ 0x5704, 0x1170,
+ 0x5708, 0x1172,
+ 0x5709, 0x1171,
+ 0x570b, 0x1173,
+ 0x570d, 0x1174,
+ 0x570f, 0x074d,
+ 0x5712, 0x0502,
+ 0x5713, 0x1175,
+ 0x5716, 0x1177,
+ 0x5718, 0x1176,
+ 0x571c, 0x1179,
+ 0x571f, 0x0c54,
+ 0x5726, 0x117a,
+ 0x5727, 0x0479,
+ 0x5728, 0x084f,
+ 0x572d, 0x0713,
+ 0x5730, 0x0b8d,
+ 0x5737, 0x117b,
+ 0x573b, 0x117e,
+ 0x5740, 0x117f,
+ 0x5742, 0x0854,
+ 0x5747, 0x06c9,
+ 0x574a, 0x0e65,
+ 0x574e, 0x117d,
+ 0x574f, 0x1180,
+ 0x5750, 0x0831,
+ 0x5751, 0x07b5,
+ 0x5759, 0x20e0,
+ 0x5761, 0x1184,
+ 0x5764, 0x0815,
+ 0x5765, 0x20e1,
+ 0x5766, 0x0b71,
+ 0x5769, 0x1181,
+ 0x576a, 0x0bf6,
+ 0x577f, 0x1185,
+ 0x5782, 0x0a28,
+ 0x5788, 0x1183,
+ 0x5789, 0x1186,
+ 0x578b, 0x0715,
+ 0x5793, 0x1187,
+ 0x57a0, 0x1188,
+ 0x57a2, 0x07b6,
+ 0x57a3, 0x059e,
+ 0x57a4, 0x118a,
+ 0x57aa, 0x118b,
+ 0x57ac, 0x20e2,
+ 0x57b0, 0x118c,
+ 0x57b3, 0x1189,
+ 0x57c0, 0x1182,
+ 0x57c3, 0x118d,
+ 0x57c6, 0x118e,
+ 0x57c7, 0x20e4,
+ 0x57c8, 0x20e3,
+ 0x57cb, 0x0e92,
+ 0x57ce, 0x09d3,
+ 0x57d2, 0x1190,
+ 0x57d4, 0x118f,
+ 0x57d6, 0x1193,
+ 0x57dc, 0x0cee,
+ 0x57df, 0x04ac,
+ 0x57e0, 0x0dc8,
+ 0x57e3, 0x1194,
+ 0x57f4, 0x09e5,
+ 0x57f7, 0x08e5,
+ 0x57f9, 0x0d13,
+ 0x57fa, 0x062c,
+ 0x57fc, 0x085b,
+ 0x5800, 0x0e87,
+ 0x5802, 0x0c8a,
+ 0x5805, 0x074e,
+ 0x5806, 0x0b2f,
+ 0x580a, 0x1192,
+ 0x580b, 0x1195,
+ 0x5815, 0x0b24,
+ 0x5819, 0x1196,
+ 0x581d, 0x1197,
+ 0x5821, 0x1199,
+ 0x5824, 0x0c05,
+ 0x582a, 0x05ea,
+ 0x582f, 0x1d32,
+ 0x5830, 0x0503,
+ 0x5831, 0x0e43,
+ 0x5834, 0x09d4,
+ 0x5835, 0x0c42,
+ 0x583a, 0x0856,
+ 0x583d, 0x119f,
+ 0x5840, 0x0e0d,
+ 0x5841, 0x0fa5,
+ 0x584a, 0x0574,
+ 0x584b, 0x119b,
+ 0x5851, 0x0abc,
+ 0x5852, 0x119e,
+ 0x5854, 0x0c5d,
+ 0x5857, 0x0c43,
+ 0x5858, 0x0c5e,
+ 0x5859, 0x0d4d,
+ 0x585a, 0x0be9,
+ 0x585e, 0x0839,
+ 0x5861, 0x1e47,
+ 0x5862, 0x119a,
+ 0x5869, 0x0518,
+ 0x586b, 0x0c30,
+ 0x5870, 0x119c,
+ 0x5872, 0x1198,
+ 0x5875, 0x0a16,
+ 0x5879, 0x11a0,
+ 0x587e, 0x0958,
+ 0x5883, 0x06a5,
+ 0x5885, 0x11a1,
+ 0x5893, 0x0e38,
+ 0x5897, 0x0aff,
+ 0x589c, 0x0be2,
+ 0x589e, 0x20e7,
+ 0x589f, 0x11a3,
+ 0x58a8, 0x0e7d,
+ 0x58ab, 0x11a4,
+ 0x58ae, 0x11a9,
+ 0x58b2, 0x20e8,
+ 0x58b3, 0x0dff,
+ 0x58b8, 0x11a8,
+ 0x58b9, 0x11a2,
+ 0x58ba, 0x11a5,
+ 0x58bb, 0x11a7,
+ 0x58be, 0x0816,
+ 0x58c1, 0x0e19,
+ 0x58c5, 0x11aa,
+ 0x58c7, 0x0b83,
+ 0x58ca, 0x0575,
+ 0x58cc, 0x09d5,
+ 0x58d1, 0x11ac,
+ 0x58d3, 0x11ab,
+ 0x58d5, 0x07fa,
+ 0x58d7, 0x11ad,
+ 0x58d8, 0x11af,
+ 0x58d9, 0x11ae,
+ 0x58dc, 0x11b1,
+ 0x58de, 0x11a6,
+ 0x58df, 0x11b3,
+ 0x58e4, 0x11b2,
+ 0x58e5, 0x11b0,
+ 0x58eb, 0x089c,
+ 0x58ec, 0x0a17,
+ 0x58ee, 0x0ad6,
+ 0x58ef, 0x11b4,
+ 0x58f0, 0x0a60,
+ 0x58f1, 0x04b1,
+ 0x58f2, 0x0d1a,
+ 0x58f7, 0x0bf7,
+ 0x58f9, 0x11b6,
+ 0x58fa, 0x11b5,
+ 0x58fb, 0x11b7,
+ 0x5902, 0x11ba,
+ 0x5909, 0x0e21,
+ 0x590a, 0x11bb,
+ 0x590b, 0x20e9,
+ 0x590f, 0x0546,
+ 0x5910, 0x11bc,
+ 0x5915, 0x0f26,
+ 0x5916, 0x058e,
+ 0x5918, 0x10de,
+ 0x5919, 0x0952,
+ 0x591a, 0x0b1f,
+ 0x591b, 0x11bd,
+ 0x591c, 0x0ef7,
+ 0x5922, 0x0ec0,
+ 0x5925, 0x11bf,
+ 0x5927, 0x0b47,
+ 0x5929, 0x0c31,
+ 0x592a, 0x0b20,
+ 0x592b, 0x0dc9,
+ 0x592c, 0x11c0,
+ 0x592e, 0x051d,
+ 0x5931, 0x08e6,
+ 0x5932, 0x11c2,
+ 0x5937, 0x0494,
+ 0x5938, 0x11c3,
+ 0x593e, 0x11c4,
+ 0x5944, 0x0504,
+ 0x5947, 0x062d,
+ 0x5948, 0x0cb8,
+ 0x5949, 0x0e44,
+ 0x594e, 0x11c8,
+ 0x594f, 0x0ad7,
+ 0x5950, 0x11c7,
+ 0x5951, 0x0716,
+ 0x5953, 0x20ea,
+ 0x5954, 0x0e89,
+ 0x5955, 0x11c6,
+ 0x5957, 0x0c5f,
+ 0x5958, 0x11ca,
+ 0x595a, 0x11c9,
+ 0x595b, 0x20eb,
+ 0x595d, 0x20ec,
+ 0x5960, 0x11cc,
+ 0x5962, 0x11cb,
+ 0x5963, 0x20ed,
+ 0x5965, 0x051e,
+ 0x5967, 0x11cd,
+ 0x5968, 0x0991,
+ 0x5969, 0x11cf,
+ 0x596a, 0x0b63,
+ 0x596c, 0x11ce,
+ 0x596e, 0x0e03,
+ 0x5973, 0x0981,
+ 0x5974, 0x0c55,
+ 0x5978, 0x11d0,
+ 0x597d, 0x07b7,
+ 0x5981, 0x11d1,
+ 0x5982, 0x0cd7,
+ 0x5983, 0x0d72,
+ 0x5984, 0x0edd,
+ 0x598a, 0x0cdb,
+ 0x598d, 0x11da,
+ 0x5993, 0x0652,
+ 0x5996, 0x0f2f,
+ 0x5999, 0x0ebb,
+ 0x599b, 0x1239,
+ 0x599d, 0x11d2,
+ 0x59a3, 0x11d5,
+ 0x59a4, 0x20ee,
+ 0x59a5, 0x0b25,
+ 0x59a8, 0x0e66,
+ 0x59ac, 0x0c44,
+ 0x59b2, 0x11d6,
+ 0x59b9, 0x0e93,
+ 0x59ba, 0x20ef,
+ 0x59bb, 0x083a,
+ 0x59be, 0x0992,
+ 0x59c6, 0x11d7,
+ 0x59c9, 0x089e,
+ 0x59cb, 0x089d,
+ 0x59d0, 0x047d,
+ 0x59d1, 0x077c,
+ 0x59d3, 0x0a4f,
+ 0x59d4, 0x0495,
+ 0x59d9, 0x11db,
+ 0x59dc, 0x11d9,
+ 0x59e5, 0x04da,
+ 0x59e6, 0x05eb,
+ 0x59e8, 0x11d8,
+ 0x59ea, 0x0ed1,
+ 0x59eb, 0x0da3,
+ 0x59f6, 0x046c,
+ 0x59fb, 0x04bd,
+ 0x59ff, 0x089f,
+ 0x5a01, 0x0496,
+ 0x5a03, 0x0467,
+ 0x5a09, 0x11e1,
+ 0x5a11, 0x11df,
+ 0x5a18, 0x0ec8,
+ 0x5a1a, 0x11e2,
+ 0x5a1c, 0x11e0,
+ 0x5a1f, 0x11de,
+ 0x5a20, 0x09f7,
+ 0x5a25, 0x11dd,
+ 0x5a29, 0x0e2a,
+ 0x5a2f, 0x0798,
+ 0x5a35, 0x11e6,
+ 0x5a3c, 0x0993,
+ 0x5a40, 0x11e3,
+ 0x5a41, 0x0fd2,
+ 0x5a46, 0x0d02,
+ 0x5a49, 0x11e5,
+ 0x5a5a, 0x0817,
+ 0x5a62, 0x11e8,
+ 0x5a66, 0x0dca,
+ 0x5a6a, 0x11e9,
+ 0x5a6c, 0x11e4,
+ 0x5a7f, 0x0ec7,
+ 0x5a92, 0x0d14,
+ 0x5a9a, 0x11ea,
+ 0x5a9b, 0x0da4,
+ 0x5abc, 0x11eb,
+ 0x5abd, 0x11ef,
+ 0x5abe, 0x11ec,
+ 0x5ac1, 0x0547,
+ 0x5ac2, 0x11ee,
+ 0x5ac9, 0x08e7,
+ 0x5acb, 0x11ed,
+ 0x5acc, 0x074f,
+ 0x5ad0, 0x11fb,
+ 0x5ad6, 0x11f4,
+ 0x5ad7, 0x11f1,
+ 0x5ae1, 0x0ba2,
+ 0x5ae3, 0x11f0,
+ 0x5ae6, 0x11f2,
+ 0x5ae9, 0x11f3,
+ 0x5afa, 0x11f5,
+ 0x5b09, 0x062e,
+ 0x5b0b, 0x11f8,
+ 0x5b0c, 0x11f7,
+ 0x5b16, 0x11f9,
+ 0x5b22, 0x09d6,
+ 0x5b2a, 0x11fc,
+ 0x5b2c, 0x0bf8,
+ 0x5b30, 0x04e7,
+ 0x5b32, 0x11fa,
+ 0x5b36, 0x11fd,
+ 0x5b3e, 0x11fe,
+ 0x5b40, 0x1201,
+ 0x5b43, 0x11ff,
+ 0x5b45, 0x1200,
+ 0x5b50, 0x08a0,
+ 0x5b51, 0x1202,
+ 0x5b54, 0x07b8,
+ 0x5b55, 0x1203,
+ 0x5b56, 0x20f0,
+ 0x5b57, 0x08c8,
+ 0x5b58, 0x0b18,
+ 0x5b5a, 0x1204,
+ 0x5b5c, 0x08a8,
+ 0x5b5d, 0x07b9,
+ 0x5b5f, 0x0ede,
+ 0x5b63, 0x0642,
+ 0x5b64, 0x077d,
+ 0x5b65, 0x1206,
+ 0x5b66, 0x05b6,
+ 0x5b69, 0x1207,
+ 0x5b6b, 0x0b19,
+ 0x5b70, 0x1208,
+ 0x5b71, 0x1230,
+ 0x5b73, 0x1209,
+ 0x5b75, 0x120a,
+ 0x5b78, 0x120b,
+ 0x5b7a, 0x120d,
+ 0x5b80, 0x120e,
+ 0x5b83, 0x120f,
+ 0x5b85, 0x0b50,
+ 0x5b87, 0x04c9,
+ 0x5b88, 0x0915,
+ 0x5b89, 0x0486,
+ 0x5b8b, 0x0ad9,
+ 0x5b8c, 0x05ec,
+ 0x5b8d, 0x08e1,
+ 0x5b8f, 0x07ba,
+ 0x5b95, 0x0c60,
+ 0x5b97, 0x092b,
+ 0x5b98, 0x05ed,
+ 0x5b99, 0x0ba6,
+ 0x5b9a, 0x0c06,
+ 0x5b9b, 0x047c,
+ 0x5b9c, 0x0653,
+ 0x5b9d, 0x0e45,
+ 0x5b9f, 0x08ee,
+ 0x5ba2, 0x066c,
+ 0x5ba3, 0x0a8f,
+ 0x5ba4, 0x08e8,
+ 0x5ba5, 0x0f12,
+ 0x5ba6, 0x1210,
+ 0x5bae, 0x0676,
+ 0x5bb0, 0x083b,
+ 0x5bb3, 0x0590,
+ 0x5bb4, 0x0505,
+ 0x5bb5, 0x0994,
+ 0x5bb6, 0x0548,
+ 0x5bb8, 0x1211,
+ 0x5bb9, 0x0f30,
+ 0x5bbf, 0x0953,
+ 0x5bc0, 0x20f1,
+ 0x5bc2, 0x0910,
+ 0x5bc3, 0x1212,
+ 0x5bc4, 0x062f,
+ 0x5bc5, 0x0caa,
+ 0x5bc6, 0x0eb5,
+ 0x5bc7, 0x1213,
+ 0x5bc9, 0x1214,
+ 0x5bcc, 0x0dcb,
+ 0x5bd0, 0x1216,
+ 0x5bd2, 0x05e4,
+ 0x5bd3, 0x06ef,
+ 0x5bd4, 0x1215,
+ 0x5bd8, 0x20f3,
+ 0x5bdb, 0x05ee,
+ 0x5bdd, 0x09f8,
+ 0x5bde, 0x121a,
+ 0x5bdf, 0x086f,
+ 0x5be1, 0x0549,
+ 0x5be2, 0x1219,
+ 0x5be4, 0x1217,
+ 0x5be5, 0x121b,
+ 0x5be6, 0x1218,
+ 0x5be7, 0x0ce1,
+ 0x5be8, 0x148e,
+ 0x5be9, 0x09f9,
+ 0x5beb, 0x121c,
+ 0x5bec, 0x20f4,
+ 0x5bee, 0x0f88,
+ 0x5bf0, 0x121d,
+ 0x5bf3, 0x121f,
+ 0x5bf5, 0x0bbc,
+ 0x5bf6, 0x121e,
+ 0x5bf8, 0x0a47,
+ 0x5bfa, 0x08c9,
+ 0x5bfe, 0x0b30,
+ 0x5bff, 0x0923,
+ 0x5c01, 0x0de7,
+ 0x5c02, 0x0a90,
+ 0x5c04, 0x08f9,
+ 0x5c05, 0x1220,
+ 0x5c06, 0x0995,
+ 0x5c07, 0x1221,
+ 0x5c09, 0x0497,
+ 0x5c0a, 0x0b1a,
+ 0x5c0b, 0x0a18,
+ 0x5c0d, 0x1223,
+ 0x5c0e, 0x0c8b,
+ 0x5c0f, 0x0996,
+ 0x5c11, 0x0997,
+ 0x5c13, 0x1224,
+ 0x5c16, 0x0a91,
+ 0x5c1a, 0x0998,
+ 0x5c1e, 0x20f5,
+ 0x5c20, 0x1225,
+ 0x5c22, 0x1226,
+ 0x5c24, 0x0eec,
+ 0x5c28, 0x1227,
+ 0x5c2d, 0x06be,
+ 0x5c31, 0x092c,
+ 0x5c38, 0x1228,
+ 0x5c3a, 0x0908,
+ 0x5c3b, 0x09f2,
+ 0x5c3c, 0x0ccc,
+ 0x5c3d, 0x0a1a,
+ 0x5c3e, 0x0d8c,
+ 0x5c3f, 0x0cd8,
+ 0x5c40, 0x06c1,
+ 0x5c41, 0x122a,
+ 0x5c45, 0x0689,
+ 0x5c46, 0x122b,
+ 0x5c48, 0x06f6,
+ 0x5c4a, 0x0ca7,
+ 0x5c4b, 0x0530,
+ 0x5c4d, 0x08a1,
+ 0x5c4e, 0x122c,
+ 0x5c4f, 0x122f,
+ 0x5c50, 0x122e,
+ 0x5c51, 0x06f5,
+ 0x5c53, 0x122d,
+ 0x5c55, 0x0c32,
+ 0x5c5b, 0x1e92,
+ 0x5c5e, 0x0b10,
+ 0x5c60, 0x0c45,
+ 0x5c61, 0x08f4,
+ 0x5c62, 0x1e0d,
+ 0x5c64, 0x0ada,
+ 0x5c65, 0x0f64,
+ 0x5c6c, 0x1231,
+ 0x5c6e, 0x1232,
+ 0x5c6f, 0x0cae,
+ 0x5c71, 0x0881,
+ 0x5c76, 0x1234,
+ 0x5c79, 0x1235,
+ 0x5c8c, 0x1236,
+ 0x5c90, 0x0630,
+ 0x5c91, 0x1237,
+ 0x5c94, 0x1238,
+ 0x5ca1, 0x052c,
+ 0x5ca6, 0x20f6,
+ 0x5ca8, 0x0abd,
+ 0x5ca9, 0x0620,
+ 0x5cab, 0x123a,
+ 0x5cac, 0x0eb4,
+ 0x5cb1, 0x0b32,
+ 0x5cb3, 0x05b7,
+ 0x5cb6, 0x123c,
+ 0x5cb7, 0x123e,
+ 0x5cb8, 0x061b,
+ 0x5cba, 0x20f7,
+ 0x5cbb, 0x123b,
+ 0x5cbc, 0x123d,
+ 0x5cbe, 0x1240,
+ 0x5cc5, 0x123f,
+ 0x5cc7, 0x1241,
+ 0x5cd9, 0x1242,
+ 0x5ce0, 0x0c95,
+ 0x5ce1, 0x06a6,
+ 0x5ce8, 0x0565,
+ 0x5ce9, 0x1243,
+ 0x5cea, 0x1248,
+ 0x5ced, 0x1246,
+ 0x5cef, 0x0e47,
+ 0x5cf0, 0x0e46,
+ 0x5cf5, 0x20f8,
+ 0x5cf6, 0x0c61,
+ 0x5cfa, 0x1245,
+ 0x5cfb, 0x095e,
+ 0x5cfd, 0x1244,
+ 0x5d07, 0x0a38,
+ 0x5d0b, 0x1249,
+ 0x5d0e, 0x085a,
+ 0x5d11, 0x124f,
+ 0x5d14, 0x1250,
+ 0x5d15, 0x124a,
+ 0x5d16, 0x0591,
+ 0x5d17, 0x124b,
+ 0x5d18, 0x1254,
+ 0x5d19, 0x1253,
+ 0x5d1a, 0x1252,
+ 0x5d1b, 0x124e,
+ 0x5d1f, 0x124d,
+ 0x5d22, 0x1251,
+ 0x5d27, 0x20f9,
+ 0x5d29, 0x0e48,
+ 0x5d42, 0x20fc,
+ 0x5d4b, 0x1258,
+ 0x5d4c, 0x1255,
+ 0x5d4e, 0x1257,
+ 0x5d50, 0x0f5c,
+ 0x5d52, 0x1256,
+ 0x5d53, 0x20fa,
+ 0x5d5c, 0x124c,
+ 0x5d69, 0x0a39,
+ 0x5d6c, 0x1259,
+ 0x5d6d, 0x20fd,
+ 0x5d6f, 0x0827,
+ 0x5d73, 0x125a,
+ 0x5d76, 0x125b,
+ 0x5d82, 0x125e,
+ 0x5d84, 0x125d,
+ 0x5d87, 0x125c,
+ 0x5d8b, 0x0c62,
+ 0x5d8c, 0x1247,
+ 0x5d90, 0x1264,
+ 0x5d9d, 0x1260,
+ 0x5da2, 0x125f,
+ 0x5dac, 0x1261,
+ 0x5dae, 0x1262,
+ 0x5db7, 0x1265,
+ 0x5db8, 0x20fe,
+ 0x5dba, 0x0fae,
+ 0x5dbc, 0x1266,
+ 0x5dbd, 0x1263,
+ 0x5dc9, 0x1267,
+ 0x5dcc, 0x061c,
+ 0x5dcd, 0x1268,
+ 0x5dd0, 0x2100,
+ 0x5dd2, 0x126a,
+ 0x5dd3, 0x1269,
+ 0x5dd6, 0x126b,
+ 0x5ddb, 0x126c,
+ 0x5ddd, 0x0a92,
+ 0x5dde, 0x092d,
+ 0x5de1, 0x096e,
+ 0x5de3, 0x0ae5,
+ 0x5de5, 0x07bb,
+ 0x5de6, 0x0828,
+ 0x5de7, 0x07bc,
+ 0x5de8, 0x068a,
+ 0x5deb, 0x126d,
+ 0x5dee, 0x0829,
+ 0x5df1, 0x077e,
+ 0x5df2, 0x126e,
+ 0x5df3, 0x0eb2,
+ 0x5df4, 0x0cf9,
+ 0x5df5, 0x126f,
+ 0x5df7, 0x07bd,
+ 0x5dfb, 0x05e8,
+ 0x5dfd, 0x0b65,
+ 0x5dfe, 0x06ca,
+ 0x5e02, 0x08a2,
+ 0x5e03, 0x0dcd,
+ 0x5e06, 0x0d55,
+ 0x5e0b, 0x1270,
+ 0x5e0c, 0x0631,
+ 0x5e11, 0x1273,
+ 0x5e16, 0x0bbd,
+ 0x5e19, 0x1272,
+ 0x5e1a, 0x1271,
+ 0x5e1b, 0x1274,
+ 0x5e1d, 0x0c07,
+ 0x5e25, 0x0a29,
+ 0x5e2b, 0x08a3,
+ 0x5e2d, 0x0a6e,
+ 0x5e2f, 0x0b33,
+ 0x5e30, 0x063c,
+ 0x5e33, 0x0bbe,
+ 0x5e36, 0x1275,
+ 0x5e38, 0x09d7,
+ 0x5e3d, 0x0e67,
+ 0x5e40, 0x1279,
+ 0x5e43, 0x1278,
+ 0x5e44, 0x1277,
+ 0x5e45, 0x0def,
+ 0x5e47, 0x1280,
+ 0x5e4c, 0x0e88,
+ 0x5e4e, 0x127a,
+ 0x5e54, 0x127c,
+ 0x5e55, 0x0e99,
+ 0x5e57, 0x127b,
+ 0x5e5f, 0x127d,
+ 0x5e61, 0x0d3c,
+ 0x5e62, 0x127e,
+ 0x5e63, 0x0e0e,
+ 0x5e64, 0x127f,
+ 0x5e72, 0x05ef,
+ 0x5e73, 0x0e0f,
+ 0x5e74, 0x0ce5,
+ 0x5e75, 0x1281,
+ 0x5e78, 0x07be,
+ 0x5e79, 0x05f0,
+ 0x5e7a, 0x1283,
+ 0x5e7b, 0x076c,
+ 0x5e7c, 0x0f2e,
+ 0x5e7d, 0x0f13,
+ 0x5e7e, 0x0632,
+ 0x5e7f, 0x1285,
+ 0x5e81, 0x0bbf,
+ 0x5e83, 0x07bf,
+ 0x5e84, 0x0999,
+ 0x5e87, 0x0d73,
+ 0x5e8a, 0x099a,
+ 0x5e8f, 0x0982,
+ 0x5e95, 0x0c08,
+ 0x5e96, 0x0e49,
+ 0x5e97, 0x0c33,
+ 0x5e9a, 0x07c0,
+ 0x5e9c, 0x0dce,
+ 0x5ea0, 0x1286,
+ 0x5ea6, 0x0c53,
+ 0x5ea7, 0x0832,
+ 0x5eab, 0x077f,
+ 0x5ead, 0x0c09,
+ 0x5eb5, 0x0487,
+ 0x5eb6, 0x0978,
+ 0x5eb7, 0x07c1,
+ 0x5eb8, 0x0f31,
+ 0x5ec1, 0x1287,
+ 0x5ec3, 0x0d07,
+ 0x5ec8, 0x1289,
+ 0x5ec9, 0x0fbf,
+ 0x5eca, 0x0fd3,
+ 0x5ecf, 0x128b,
+ 0x5ed0, 0x128a,
+ 0x5ed3, 0x05a5,
+ 0x5ed6, 0x128c,
+ 0x5eda, 0x128f,
+ 0x5edd, 0x128e,
+ 0x5edf, 0x0db2,
+ 0x5ee0, 0x099b,
+ 0x5ee1, 0x1292,
+ 0x5ee2, 0x1291,
+ 0x5ee3, 0x128d,
+ 0x5ee8, 0x1293,
+ 0x5eec, 0x1295,
+ 0x5ef0, 0x1298,
+ 0x5ef1, 0x1296,
+ 0x5ef3, 0x1297,
+ 0x5ef4, 0x1299,
+ 0x5ef6, 0x0506,
+ 0x5ef7, 0x0c0a,
+ 0x5ef8, 0x129a,
+ 0x5efa, 0x0750,
+ 0x5efb, 0x0576,
+ 0x5efc, 0x0cec,
+ 0x5efe, 0x129b,
+ 0x5eff, 0x0cd3,
+ 0x5f01, 0x0e2b,
+ 0x5f03, 0x129c,
+ 0x5f04, 0x0fd4,
+ 0x5f09, 0x129d,
+ 0x5f0a, 0x0e10,
+ 0x5f0b, 0x12a0,
+ 0x5f0c, 0x0ffa,
+ 0x5f0d, 0x100a,
+ 0x5f0f, 0x08dc,
+ 0x5f10, 0x0ccd,
+ 0x5f11, 0x12a1,
+ 0x5f13, 0x0677,
+ 0x5f14, 0x0bc0,
+ 0x5f15, 0x04be,
+ 0x5f16, 0x12a2,
+ 0x5f17, 0x0df6,
+ 0x5f18, 0x07c2,
+ 0x5f1b, 0x0b8e,
+ 0x5f1f, 0x0c0b,
+ 0x5f21, 0x2101,
+ 0x5f25, 0x0efb,
+ 0x5f26, 0x076d,
+ 0x5f27, 0x0780,
+ 0x5f29, 0x12a3,
+ 0x5f2d, 0x12a4,
+ 0x5f2f, 0x12aa,
+ 0x5f31, 0x0911,
+ 0x5f34, 0x2102,
+ 0x5f35, 0x0bc1,
+ 0x5f37, 0x06a7,
+ 0x5f38, 0x12a5,
+ 0x5f3c, 0x0d9d,
+ 0x5f3e, 0x0b84,
+ 0x5f41, 0x12a6,
+ 0x5f45, 0x20b2,
+ 0x5f48, 0x12a7,
+ 0x5f4a, 0x06a8,
+ 0x5f4c, 0x12a8,
+ 0x5f4e, 0x12a9,
+ 0x5f51, 0x12ab,
+ 0x5f53, 0x0c70,
+ 0x5f56, 0x12ac,
+ 0x5f59, 0x12ae,
+ 0x5f5c, 0x129f,
+ 0x5f5d, 0x129e,
+ 0x5f61, 0x12af,
+ 0x5f62, 0x0717,
+ 0x5f66, 0x0d99,
+ 0x5f67, 0x2103,
+ 0x5f69, 0x083c,
+ 0x5f6a, 0x0da9,
+ 0x5f6b, 0x0bc2,
+ 0x5f6c, 0x0dbd,
+ 0x5f6d, 0x12b0,
+ 0x5f70, 0x099c,
+ 0x5f71, 0x04e8,
+ 0x5f73, 0x12b1,
+ 0x5f77, 0x12b2,
+ 0x5f79, 0x0efe,
+ 0x5f7c, 0x0d74,
+ 0x5f7f, 0x12b5,
+ 0x5f80, 0x051f,
+ 0x5f81, 0x0a50,
+ 0x5f82, 0x12b4,
+ 0x5f83, 0x12b3,
+ 0x5f84, 0x0718,
+ 0x5f85, 0x0b34,
+ 0x5f87, 0x12b9,
+ 0x5f88, 0x12b7,
+ 0x5f8a, 0x12b6,
+ 0x5f8b, 0x0f6f,
+ 0x5f8c, 0x0799,
+ 0x5f90, 0x0983,
+ 0x5f91, 0x12b8,
+ 0x5f92, 0x0c46,
+ 0x5f93, 0x0948,
+ 0x5f97, 0x0c98,
+ 0x5f98, 0x12bc,
+ 0x5f99, 0x12bb,
+ 0x5f9e, 0x12ba,
+ 0x5fa0, 0x12bd,
+ 0x5fa1, 0x079a,
+ 0x5fa8, 0x12be,
+ 0x5fa9, 0x0dee,
+ 0x5faa, 0x0965,
+ 0x5fad, 0x12bf,
+ 0x5fae, 0x0d8d,
+ 0x5fb3, 0x0c99,
+ 0x5fb4, 0x0bc3,
+ 0x5fb7, 0x2104,
+ 0x5fb9, 0x0c2a,
+ 0x5fbc, 0x12c0,
+ 0x5fbd, 0x0645,
+ 0x5fc3, 0x09fa,
+ 0x5fc5, 0x0d9e,
+ 0x5fcc, 0x0633,
+ 0x5fcd, 0x0cdc,
+ 0x5fd6, 0x12c1,
+ 0x5fd7, 0x08a4,
+ 0x5fd8, 0x0e68,
+ 0x5fdc, 0x0520,
+ 0x5fdd, 0x12c6,
+ 0x5fde, 0x2105,
+ 0x5fe0, 0x0ba7,
+ 0x5fe4, 0x12c3,
+ 0x5feb, 0x0577,
+ 0x5ff0, 0x12f6,
+ 0x5ff1, 0x12c5,
+ 0x5ff5, 0x0ce6,
+ 0x5ff8, 0x12c4,
+ 0x5ffb, 0x12c2,
+ 0x5ffd, 0x080c,
+ 0x5fff, 0x12c8,
+ 0x600e, 0x12ce,
+ 0x600f, 0x12d4,
+ 0x6010, 0x12cc,
+ 0x6012, 0x0c56,
+ 0x6015, 0x12d1,
+ 0x6016, 0x0dcf,
+ 0x6019, 0x12cb,
+ 0x601b, 0x12d0,
+ 0x601c, 0x0faf,
+ 0x601d, 0x08a5,
+ 0x6020, 0x0b35,
+ 0x6021, 0x12c9,
+ 0x6025, 0x0678,
+ 0x6026, 0x12d3,
+ 0x6027, 0x0a51,
+ 0x6028, 0x0507,
+ 0x6029, 0x12cd,
+ 0x602a, 0x0578,
+ 0x602b, 0x12d2,
+ 0x602f, 0x06a9,
+ 0x6031, 0x12cf,
+ 0x603a, 0x12d5,
+ 0x6041, 0x12d7,
+ 0x6042, 0x12e1,
+ 0x6043, 0x12df,
+ 0x6046, 0x12dc,
+ 0x604a, 0x12db,
+ 0x604b, 0x0fc0,
+ 0x604d, 0x12dd,
+ 0x6050, 0x06aa,
+ 0x6052, 0x07c3,
+ 0x6055, 0x0984,
+ 0x6059, 0x12e4,
+ 0x605a, 0x12d6,
+ 0x605d, 0x2106,
+ 0x605f, 0x12da,
+ 0x6060, 0x12ca,
+ 0x6062, 0x057a,
+ 0x6063, 0x12de,
+ 0x6064, 0x12e0,
+ 0x6065, 0x0b8f,
+ 0x6068, 0x0818,
+ 0x6069, 0x0538,
+ 0x606a, 0x12d8,
+ 0x606b, 0x12e3,
+ 0x606c, 0x12e2,
+ 0x606d, 0x06ab,
+ 0x606f, 0x0b09,
+ 0x6070, 0x05c4,
+ 0x6075, 0x0719,
+ 0x6077, 0x12d9,
+ 0x6081, 0x12e5,
+ 0x6083, 0x12e8,
+ 0x6084, 0x12ea,
+ 0x6085, 0x2107,
+ 0x6089, 0x08e9,
+ 0x608a, 0x2108,
+ 0x608b, 0x12f0,
+ 0x608c, 0x0c0c,
+ 0x608d, 0x12e6,
+ 0x6092, 0x12ee,
+ 0x6094, 0x0579,
+ 0x6096, 0x12ec,
+ 0x609a, 0x12e9,
+ 0x609b, 0x12eb,
+ 0x609f, 0x079b,
+ 0x60a0, 0x0f14,
+ 0x60a3, 0x05f1,
+ 0x60a6, 0x04fb,
+ 0x60a7, 0x12ef,
+ 0x60a9, 0x0cf0,
+ 0x60aa, 0x0471,
+ 0x60b2, 0x0d75,
+ 0x60b3, 0x12c7,
+ 0x60b4, 0x12f5,
+ 0x60b5, 0x12f9,
+ 0x60b6, 0x0ef1,
+ 0x60b8, 0x12f2,
+ 0x60bc, 0x0c63,
+ 0x60bd, 0x12f7,
+ 0x60c5, 0x09d8,
+ 0x60c6, 0x12f8,
+ 0x60c7, 0x0caf,
+ 0x60d1, 0x0fed,
+ 0x60d3, 0x12f4,
+ 0x60d5, 0x210a,
+ 0x60d8, 0x12fa,
+ 0x60da, 0x080d,
+ 0x60dc, 0x0a6f,
+ 0x60de, 0x2109,
+ 0x60df, 0x0498,
+ 0x60e0, 0x12f3,
+ 0x60e1, 0x12f1,
+ 0x60e3, 0x0adc,
+ 0x60e7, 0x12e7,
+ 0x60e8, 0x0882,
+ 0x60f0, 0x0b26,
+ 0x60f1, 0x1306,
+ 0x60f2, 0x210c,
+ 0x60f3, 0x0add,
+ 0x60f4, 0x1301,
+ 0x60f6, 0x12fe,
+ 0x60f9, 0x0912,
+ 0x60fa, 0x1302,
+ 0x60fb, 0x1305,
+ 0x6100, 0x1300,
+ 0x6101, 0x092f,
+ 0x6103, 0x1303,
+ 0x6106, 0x12fd,
+ 0x6108, 0x0f08,
+ 0x6109, 0x0f07,
+ 0x610d, 0x1307,
+ 0x610f, 0x0499,
+ 0x6111, 0x210d,
+ 0x6115, 0x12fc,
+ 0x611a, 0x06ea,
+ 0x611b, 0x046a,
+ 0x611f, 0x05f2,
+ 0x6120, 0x210b,
+ 0x6121, 0x1304,
+ 0x6127, 0x130c,
+ 0x6128, 0x130b,
+ 0x612c, 0x1310,
+ 0x6130, 0x210f,
+ 0x6134, 0x1311,
+ 0x6137, 0x210e,
+ 0x613c, 0x130f,
+ 0x613d, 0x1312,
+ 0x613e, 0x130a,
+ 0x613f, 0x130e,
+ 0x6142, 0x1313,
+ 0x6144, 0x1314,
+ 0x6147, 0x1309,
+ 0x6148, 0x08ca,
+ 0x614a, 0x130d,
+ 0x614b, 0x0b36,
+ 0x614c, 0x07c4,
+ 0x614d, 0x12fb,
+ 0x614e, 0x09fb,
+ 0x6153, 0x1321,
+ 0x6155, 0x0e39,
+ 0x6158, 0x1317,
+ 0x615d, 0x1320,
+ 0x615f, 0x131f,
+ 0x6162, 0x0eab,
+ 0x6163, 0x05f3,
+ 0x6165, 0x131d,
+ 0x6167, 0x071b,
+ 0x6168, 0x0592,
+ 0x616b, 0x131a,
+ 0x616e, 0x0f80,
+ 0x616f, 0x131c,
+ 0x6170, 0x049a,
+ 0x6171, 0x131e,
+ 0x6173, 0x1315,
+ 0x6174, 0x131b,
+ 0x6175, 0x1322,
+ 0x6176, 0x071a,
+ 0x6177, 0x1316,
+ 0x617e, 0x0f47,
+ 0x6182, 0x0f15,
+ 0x6187, 0x1325,
+ 0x618a, 0x1329,
+ 0x618e, 0x0b00,
+ 0x6190, 0x0fc1,
+ 0x6191, 0x132a,
+ 0x6194, 0x1327,
+ 0x6196, 0x1324,
+ 0x6198, 0x2110,
+ 0x6199, 0x1323,
+ 0x619a, 0x1328,
+ 0x61a4, 0x0e00,
+ 0x61a7, 0x0c8c,
+ 0x61a9, 0x071c,
+ 0x61ab, 0x132b,
+ 0x61ac, 0x1326,
+ 0x61ae, 0x132c,
+ 0x61b2, 0x0751,
+ 0x61b6, 0x0531,
+ 0x61ba, 0x1334,
+ 0x61be, 0x05f4,
+ 0x61c3, 0x1332,
+ 0x61c6, 0x1333,
+ 0x61c7, 0x0819,
+ 0x61c8, 0x1331,
+ 0x61c9, 0x132f,
+ 0x61ca, 0x132e,
+ 0x61cb, 0x1335,
+ 0x61cc, 0x132d,
+ 0x61cd, 0x1337,
+ 0x61d0, 0x057b,
+ 0x61e3, 0x1339,
+ 0x61e6, 0x1338,
+ 0x61f2, 0x0bc4,
+ 0x61f4, 0x133c,
+ 0x61f6, 0x133a,
+ 0x61f7, 0x1330,
+ 0x61f8, 0x0752,
+ 0x61fa, 0x133b,
+ 0x61fc, 0x133f,
+ 0x61fd, 0x133e,
+ 0x61fe, 0x1340,
+ 0x61ff, 0x133d,
+ 0x6200, 0x1341,
+ 0x6208, 0x1342,
+ 0x620a, 0x0e3a,
+ 0x620c, 0x1345,
+ 0x620d, 0x1344,
+ 0x620e, 0x0949,
+ 0x6210, 0x0a52,
+ 0x6211, 0x0566,
+ 0x6212, 0x057c,
+ 0x6213, 0x2111,
+ 0x6214, 0x1346,
+ 0x6216, 0x0483,
+ 0x621a, 0x0a70,
+ 0x621b, 0x1347,
+ 0x621d, 0x1a64,
+ 0x621e, 0x1348,
+ 0x621f, 0x0737,
+ 0x6221, 0x1349,
+ 0x6226, 0x0a93,
+ 0x622a, 0x134a,
+ 0x622e, 0x134b,
+ 0x622f, 0x0654,
+ 0x6230, 0x134c,
+ 0x6232, 0x134d,
+ 0x6234, 0x0b37,
+ 0x6238, 0x0781,
+ 0x623b, 0x0eed,
+ 0x623f, 0x0e6a,
+ 0x6240, 0x0974,
+ 0x6241, 0x134f,
+ 0x6247, 0x0a94,
+ 0x6248, 0x1b1a,
+ 0x6249, 0x0d76,
+ 0x624b, 0x0916,
+ 0x624d, 0x083d,
+ 0x624e, 0x1350,
+ 0x6253, 0x0b27,
+ 0x6255, 0x0df7,
+ 0x6258, 0x0b51,
+ 0x625b, 0x1353,
+ 0x625e, 0x1351,
+ 0x6260, 0x1354,
+ 0x6263, 0x1352,
+ 0x6268, 0x1355,
+ 0x626e, 0x0e01,
+ 0x6271, 0x047b,
+ 0x6276, 0x0dd0,
+ 0x6279, 0x0d77,
+ 0x627c, 0x1356,
+ 0x627e, 0x1359,
+ 0x627f, 0x099d,
+ 0x6280, 0x0655,
+ 0x6282, 0x1357,
+ 0x6283, 0x135e,
+ 0x6284, 0x099e,
+ 0x6289, 0x1358,
+ 0x628a, 0x0cfa,
+ 0x6291, 0x0f48,
+ 0x6292, 0x135a,
+ 0x6294, 0x135f,
+ 0x6295, 0x0c64,
+ 0x6296, 0x135c,
+ 0x6297, 0x07c5,
+ 0x6298, 0x0a82,
+ 0x629b, 0x136d,
+ 0x629c, 0x0d48,
+ 0x629e, 0x0b52,
+ 0x62a6, 0x2112,
+ 0x62ab, 0x0d78,
+ 0x62ac, 0x13b2,
+ 0x62b1, 0x0e4a,
+ 0x62b5, 0x0c0d,
+ 0x62b9, 0x0ea3,
+ 0x62bb, 0x1362,
+ 0x62bc, 0x0521,
+ 0x62bd, 0x0ba8,
+ 0x62c2, 0x136b,
+ 0x62c5, 0x0b72,
+ 0x62c6, 0x1365,
+ 0x62c7, 0x136c,
+ 0x62c8, 0x1367,
+ 0x62c9, 0x136e,
+ 0x62ca, 0x136a,
+ 0x62cc, 0x1369,
+ 0x62cd, 0x0d25,
+ 0x62cf, 0x1363,
+ 0x62d0, 0x057d,
+ 0x62d1, 0x1361,
+ 0x62d2, 0x068b,
+ 0x62d3, 0x0b53,
+ 0x62d4, 0x135d,
+ 0x62d7, 0x1360,
+ 0x62d8, 0x07c6,
+ 0x62d9, 0x0a7f,
+ 0x62db, 0x099f,
+ 0x62dc, 0x1368,
+ 0x62dd, 0x0d08,
+ 0x62e0, 0x068c,
+ 0x62e1, 0x05a6,
+ 0x62ec, 0x05c5,
+ 0x62ed, 0x09e7,
+ 0x62ee, 0x1370,
+ 0x62ef, 0x1375,
+ 0x62f1, 0x1371,
+ 0x62f3, 0x0753,
+ 0x62f5, 0x1376,
+ 0x62f6, 0x0870,
+ 0x62f7, 0x07fb,
+ 0x62fe, 0x0930,
+ 0x62ff, 0x1364,
+ 0x6301, 0x08cb,
+ 0x6302, 0x1373,
+ 0x6307, 0x08a6,
+ 0x6308, 0x1374,
+ 0x6309, 0x0488,
+ 0x630c, 0x136f,
+ 0x6311, 0x0bc5,
+ 0x6319, 0x068d,
+ 0x631f, 0x06ac,
+ 0x6327, 0x1372,
+ 0x6328, 0x046b,
+ 0x632b, 0x0833,
+ 0x632f, 0x09fc,
+ 0x633a, 0x0c0e,
+ 0x633d, 0x0d68,
+ 0x633e, 0x1378,
+ 0x633f, 0x0ae0,
+ 0x6349, 0x0b0a,
+ 0x634c, 0x0879,
+ 0x634d, 0x1379,
+ 0x634f, 0x137b,
+ 0x6350, 0x1377,
+ 0x6355, 0x0e31,
+ 0x6357, 0x0bd9,
+ 0x635c, 0x0ade,
+ 0x6367, 0x0e4b,
+ 0x6368, 0x08fa,
+ 0x6369, 0x1387,
+ 0x636b, 0x1386,
+ 0x636e, 0x0a3e,
+ 0x6372, 0x0754,
+ 0x6376, 0x1380,
+ 0x6377, 0x09a1,
+ 0x637a, 0x0cc0,
+ 0x637b, 0x0ce7,
+ 0x6380, 0x137e,
+ 0x6383, 0x0adf,
+ 0x6388, 0x0924,
+ 0x6389, 0x1383,
+ 0x638c, 0x09a0,
+ 0x638e, 0x137d,
+ 0x638f, 0x1382,
+ 0x6392, 0x0d09,
+ 0x6396, 0x137c,
+ 0x6398, 0x06f7,
+ 0x639b, 0x05bb,
+ 0x639f, 0x1384,
+ 0x63a0, 0x0f73,
+ 0x63a1, 0x083e,
+ 0x63a2, 0x0b73,
+ 0x63a3, 0x1381,
+ 0x63a5, 0x0a80,
+ 0x63a7, 0x07c7,
+ 0x63a8, 0x0a2a,
+ 0x63a9, 0x0508,
+ 0x63aa, 0x0abe,
+ 0x63ab, 0x137f,
+ 0x63ac, 0x065f,
+ 0x63b2, 0x071d,
+ 0x63b4, 0x0beb,
+ 0x63b5, 0x1385,
+ 0x63bb, 0x0ae1,
+ 0x63be, 0x1388,
+ 0x63c0, 0x138a,
+ 0x63c3, 0x0b17,
+ 0x63c4, 0x1390,
+ 0x63c6, 0x138b,
+ 0x63c9, 0x138d,
+ 0x63cf, 0x0db3,
+ 0x63d0, 0x0c0f,
+ 0x63d2, 0x138e,
+ 0x63d6, 0x0f16,
+ 0x63da, 0x0f32,
+ 0x63db, 0x05f5,
+ 0x63e1, 0x0472,
+ 0x63e3, 0x138c,
+ 0x63e9, 0x1389,
+ 0x63ee, 0x0634,
+ 0x63f4, 0x0509,
+ 0x63f5, 0x2113,
+ 0x63f6, 0x138f,
+ 0x63fa, 0x0f33,
+ 0x6406, 0x1393,
+ 0x640d, 0x0b1b,
+ 0x640f, 0x139a,
+ 0x6413, 0x1394,
+ 0x6414, 0x1e2c,
+ 0x6416, 0x1391,
+ 0x6417, 0x1398,
+ 0x641c, 0x137a,
+ 0x6426, 0x1395,
+ 0x6428, 0x1399,
+ 0x642c, 0x0d56,
+ 0x642d, 0x0c65,
+ 0x6434, 0x1392,
+ 0x6436, 0x1396,
+ 0x643a, 0x071e,
+ 0x643e, 0x0861,
+ 0x6442, 0x0a81,
+ 0x644e, 0x139e,
+ 0x6451, 0x1e43,
+ 0x6458, 0x0c20,
+ 0x6460, 0x2114,
+ 0x6467, 0x139b,
+ 0x6469, 0x0e8e,
+ 0x646f, 0x139c,
+ 0x6476, 0x139d,
+ 0x6478, 0x0eda,
+ 0x647a, 0x0a46,
+ 0x6483, 0x0738,
+ 0x6488, 0x13a4,
+ 0x6492, 0x0883,
+ 0x6493, 0x13a1,
+ 0x6495, 0x13a0,
+ 0x649a, 0x0ce8,
+ 0x649d, 0x2115,
+ 0x649e, 0x0c8d,
+ 0x64a4, 0x0c2b,
+ 0x64a5, 0x13a2,
+ 0x64a9, 0x13a3,
+ 0x64ab, 0x0de1,
+ 0x64ad, 0x0cfb,
+ 0x64ae, 0x0871,
+ 0x64b0, 0x0a95,
+ 0x64b2, 0x0e7e,
+ 0x64b9, 0x05a7,
+ 0x64bb, 0x13aa,
+ 0x64bc, 0x13a5,
+ 0x64c1, 0x0f34,
+ 0x64c2, 0x13ac,
+ 0x64c5, 0x13a8,
+ 0x64c7, 0x13a9,
+ 0x64cd, 0x0ae2,
+ 0x64ce, 0x2116,
+ 0x64d2, 0x13a7,
+ 0x64d4, 0x1366,
+ 0x64d8, 0x13ab,
+ 0x64da, 0x13a6,
+ 0x64e0, 0x13b0,
+ 0x64e2, 0x0c21,
+ 0x64e3, 0x13b3,
+ 0x64e6, 0x0872,
+ 0x64e7, 0x13ae,
+ 0x64ec, 0x0656,
+ 0x64ef, 0x13b4,
+ 0x64f1, 0x13ad,
+ 0x64f2, 0x13b8,
+ 0x64f4, 0x13b7,
+ 0x64f6, 0x13b6,
+ 0x64fa, 0x13b9,
+ 0x64fd, 0x13bb,
+ 0x64fe, 0x09d9,
+ 0x6500, 0x13ba,
+ 0x6505, 0x13be,
+ 0x6518, 0x13bc,
+ 0x651c, 0x13bd,
+ 0x651d, 0x1397,
+ 0x6522, 0x1e97,
+ 0x6523, 0x13c0,
+ 0x6524, 0x13bf,
+ 0x652a, 0x139f,
+ 0x652b, 0x13c1,
+ 0x652c, 0x13b5,
+ 0x652f, 0x08a7,
+ 0x6534, 0x13c2,
+ 0x6536, 0x13c5,
+ 0x6537, 0x13c4,
+ 0x6538, 0x13c6,
+ 0x6539, 0x057e,
+ 0x653b, 0x07c8,
+ 0x653e, 0x0e4c,
+ 0x653f, 0x0a53,
+ 0x6545, 0x0782,
+ 0x6548, 0x13c8,
+ 0x654d, 0x13cb,
+ 0x654e, 0x2117,
+ 0x654f, 0x0dc4,
+ 0x6551, 0x0679,
+ 0x6555, 0x13ca,
+ 0x6556, 0x13c9,
+ 0x6557, 0x0d0a,
+ 0x6558, 0x13cc,
+ 0x6559, 0x06ad,
+ 0x655d, 0x13ce,
+ 0x655e, 0x13cd,
+ 0x6562, 0x05f6,
+ 0x6563, 0x0884,
+ 0x6566, 0x0cb0,
+ 0x656c, 0x071f,
+ 0x6570, 0x0a3a,
+ 0x6572, 0x13cf,
+ 0x6574, 0x0a54,
+ 0x6575, 0x0c22,
+ 0x6577, 0x0dd1,
+ 0x6578, 0x13d0,
+ 0x6582, 0x13d1,
+ 0x6587, 0x0e08,
+ 0x6588, 0x120c,
+ 0x6589, 0x0a6a,
+ 0x658c, 0x0dbe,
+ 0x658e, 0x0848,
+ 0x6590, 0x0d79,
+ 0x6591, 0x0d57,
+ 0x6597, 0x0c47,
+ 0x6599, 0x0f89,
+ 0x659b, 0x13d4,
+ 0x659c, 0x08fc,
+ 0x659f, 0x13d5,
+ 0x65a1, 0x047a,
+ 0x65a4, 0x06cc,
+ 0x65a5, 0x0a71,
+ 0x65a7, 0x0dd2,
+ 0x65ab, 0x13d6,
+ 0x65ac, 0x0890,
+ 0x65ad, 0x0b85,
+ 0x65af, 0x08a9,
+ 0x65b0, 0x09fd,
+ 0x65b7, 0x13d7,
+ 0x65b9, 0x0e4d,
+ 0x65bc, 0x0519,
+ 0x65bd, 0x08aa,
+ 0x65c1, 0x13da,
+ 0x65c3, 0x13d8,
+ 0x65c4, 0x13db,
+ 0x65c5, 0x0f81,
+ 0x65c6, 0x13d9,
+ 0x65cb, 0x0a9f,
+ 0x65cc, 0x13dc,
+ 0x65cf, 0x0b12,
+ 0x65d2, 0x13dd,
+ 0x65d7, 0x0636,
+ 0x65d9, 0x13df,
+ 0x65db, 0x13de,
+ 0x65e0, 0x13e0,
+ 0x65e2, 0x0637,
+ 0x65e5, 0x0cd4,
+ 0x65e6, 0x0b74,
+ 0x65e7, 0x0686,
+ 0x65e8, 0x08ab,
+ 0x65e9, 0x0ae3,
+ 0x65ec, 0x0966,
+ 0x65ed, 0x0474,
+ 0x65f1, 0x13e2,
+ 0x65fa, 0x0522,
+ 0x65fb, 0x13e6,
+ 0x6600, 0x2118,
+ 0x6602, 0x07c9,
+ 0x6603, 0x13e5,
+ 0x6606, 0x081b,
+ 0x6607, 0x09a2,
+ 0x6609, 0x211a,
+ 0x660a, 0x13e4,
+ 0x660c, 0x09a3,
+ 0x660e, 0x0ecc,
+ 0x660f, 0x081a,
+ 0x6613, 0x049b,
+ 0x6614, 0x0a72,
+ 0x6615, 0x2119,
+ 0x661c, 0x13eb,
+ 0x661e, 0x211c,
+ 0x661f, 0x0a55,
+ 0x6620, 0x04e9,
+ 0x6624, 0x211d,
+ 0x6625, 0x095f,
+ 0x6627, 0x0e94,
+ 0x6628, 0x0862,
+ 0x662d, 0x09a4,
+ 0x662e, 0x211b,
+ 0x662f, 0x0a4b,
+ 0x6631, 0x20ae,
+ 0x6634, 0x13ea,
+ 0x6635, 0x13e8,
+ 0x663b, 0x1e00,
+ 0x663c, 0x0ba9,
+ 0x663f, 0x1409,
+ 0x6641, 0x13ef,
+ 0x6642, 0x08cc,
+ 0x6643, 0x07ca,
+ 0x6644, 0x13ed,
+ 0x6649, 0x13ee,
+ 0x664b, 0x09fe,
+ 0x664f, 0x13ec,
+ 0x6652, 0x087d,
+ 0x6657, 0x211f,
+ 0x6659, 0x2120,
+ 0x665d, 0x13f1,
+ 0x665e, 0x13f0,
+ 0x665f, 0x13f5,
+ 0x6662, 0x13f6,
+ 0x6664, 0x13f2,
+ 0x6665, 0x211e,
+ 0x6666, 0x0580,
+ 0x6667, 0x13f3,
+ 0x6669, 0x0d69,
+ 0x666e, 0x0dd3,
+ 0x666f, 0x0720,
+ 0x6670, 0x13f7,
+ 0x6673, 0x2122,
+ 0x6674, 0x0a56,
+ 0x6676, 0x09a5,
+ 0x667a, 0x0b90,
+ 0x6681, 0x06bf,
+ 0x6683, 0x13f8,
+ 0x6684, 0x13fc,
+ 0x6687, 0x054b,
+ 0x6688, 0x13f9,
+ 0x6689, 0x13fb,
+ 0x668e, 0x13fa,
+ 0x6691, 0x0975,
+ 0x6696, 0x0b86,
+ 0x6697, 0x0489,
+ 0x6698, 0x13fd,
+ 0x6699, 0x2123,
+ 0x669d, 0x13fe,
+ 0x66a0, 0x2124,
+ 0x66a2, 0x0bc6,
+ 0x66a6, 0x0fb9,
+ 0x66ab, 0x0891,
+ 0x66ae, 0x0e3b,
+ 0x66b2, 0x2125,
+ 0x66b4, 0x0e6b,
+ 0x66b8, 0x1405,
+ 0x66b9, 0x1400,
+ 0x66bc, 0x1403,
+ 0x66be, 0x1402,
+ 0x66bf, 0x2126,
+ 0x66c1, 0x13ff,
+ 0x66c4, 0x1404,
+ 0x66c7, 0x0cb6,
+ 0x66c9, 0x1401,
+ 0x66d6, 0x1406,
+ 0x66d9, 0x0976,
+ 0x66da, 0x1407,
+ 0x66dc, 0x0f35,
+ 0x66dd, 0x0d2e,
+ 0x66e0, 0x1408,
+ 0x66e6, 0x140a,
+ 0x66e9, 0x140b,
+ 0x66f0, 0x140c,
+ 0x66f2, 0x06c2,
+ 0x66f3, 0x04ea,
+ 0x66f4, 0x07cb,
+ 0x66f5, 0x140d,
+ 0x66f7, 0x140e,
+ 0x66f8, 0x097b,
+ 0x66f9, 0x0ae4,
+ 0x66fa, 0x2127,
+ 0x66fb, 0x20b1,
+ 0x66fc, 0x10ed,
+ 0x66fd, 0x0ac0,
+ 0x66fe, 0x0abf,
+ 0x66ff, 0x0b38,
+ 0x6700, 0x0837,
+ 0x6703, 0x104b,
+ 0x6708, 0x0744,
+ 0x6709, 0x0f17,
+ 0x670b, 0x0e4e,
+ 0x670d, 0x0df0,
+ 0x670e, 0x2128,
+ 0x670f, 0x140f,
+ 0x6714, 0x0863,
+ 0x6715, 0x0bdb,
+ 0x6716, 0x1410,
+ 0x6717, 0x0fd5,
+ 0x671b, 0x0e6c,
+ 0x671d, 0x0bc7,
+ 0x671e, 0x1411,
+ 0x671f, 0x0638,
+ 0x6726, 0x1412,
+ 0x6728, 0x0ee6,
+ 0x672a, 0x0eb0,
+ 0x672b, 0x0ea4,
+ 0x672c, 0x0e8a,
+ 0x672d, 0x0873,
+ 0x672e, 0x1415,
+ 0x6731, 0x0917,
+ 0x6734, 0x0e7f,
+ 0x6736, 0x1417,
+ 0x6737, 0x141a,
+ 0x6738, 0x1419,
+ 0x673a, 0x0635,
+ 0x673d, 0x067a,
+ 0x673f, 0x1416,
+ 0x6741, 0x1418,
+ 0x6746, 0x141b,
+ 0x6749, 0x0a3f,
+ 0x674e, 0x0f65,
+ 0x674f, 0x048d,
+ 0x6750, 0x0850,
+ 0x6751, 0x0b1c,
+ 0x6753, 0x0909,
+ 0x6756, 0x09db,
+ 0x6759, 0x141e,
+ 0x675c, 0x0c48,
+ 0x675e, 0x141c,
+ 0x675f, 0x0b0b,
+ 0x6760, 0x141d,
+ 0x6761, 0x09da,
+ 0x6762, 0x0ee9,
+ 0x6763, 0x141f,
+ 0x6765, 0x0f52,
+ 0x6766, 0x212a,
+ 0x676a, 0x1425,
+ 0x676d, 0x07cc,
+ 0x676f, 0x0d0b,
+ 0x6770, 0x1422,
+ 0x6771, 0x0c66,
+ 0x6772, 0x13e3,
+ 0x6773, 0x13e7,
+ 0x6775, 0x0669,
+ 0x6777, 0x0cfd,
+ 0x677c, 0x1424,
+ 0x677e, 0x09a6,
+ 0x677f, 0x0d58,
+ 0x6785, 0x142a,
+ 0x6787, 0x0d8e,
+ 0x6789, 0x1421,
+ 0x678b, 0x1427,
+ 0x678c, 0x1426,
+ 0x6790, 0x0a73,
+ 0x6795, 0x0e9b,
+ 0x6797, 0x0f9b,
+ 0x679a, 0x0e95,
+ 0x679c, 0x054c,
+ 0x679d, 0x08ac,
+ 0x67a0, 0x0fee,
+ 0x67a1, 0x1429,
+ 0x67a2, 0x0a3b,
+ 0x67a6, 0x1428,
+ 0x67a9, 0x1423,
+ 0x67af, 0x0783,
+ 0x67b3, 0x142f,
+ 0x67b4, 0x142d,
+ 0x67b6, 0x054d,
+ 0x67b7, 0x142b,
+ 0x67b8, 0x1431,
+ 0x67b9, 0x1437,
+ 0x67bb, 0x212b,
+ 0x67c0, 0x212d,
+ 0x67c1, 0x0b28,
+ 0x67c4, 0x0e11,
+ 0x67c6, 0x1439,
+ 0x67ca, 0x0d94,
+ 0x67ce, 0x1438,
+ 0x67cf, 0x0d26,
+ 0x67d0, 0x0e6d,
+ 0x67d1, 0x05f7,
+ 0x67d3, 0x0a9b,
+ 0x67d4, 0x094a,
+ 0x67d8, 0x0bef,
+ 0x67da, 0x0f18,
+ 0x67dd, 0x1434,
+ 0x67de, 0x1433,
+ 0x67e2, 0x1435,
+ 0x67e4, 0x1432,
+ 0x67e7, 0x143a,
+ 0x67e9, 0x1430,
+ 0x67ec, 0x142e,
+ 0x67ee, 0x1436,
+ 0x67ef, 0x142c,
+ 0x67f1, 0x0baa,
+ 0x67f3, 0x0f04,
+ 0x67f4, 0x08f2,
+ 0x67f5, 0x0864,
+ 0x67fb, 0x082a,
+ 0x67fe, 0x0e9d,
+ 0x67ff, 0x059f,
+ 0x6801, 0x212e,
+ 0x6802, 0x0bea,
+ 0x6803, 0x0ca2,
+ 0x6804, 0x04eb,
+ 0x6805, 0x1e07,
+ 0x6813, 0x0a96,
+ 0x6816, 0x0a58,
+ 0x6817, 0x0700,
+ 0x681e, 0x143c,
+ 0x6821, 0x07cd,
+ 0x6822, 0x05da,
+ 0x6829, 0x143e,
+ 0x682a, 0x05d2,
+ 0x682b, 0x1444,
+ 0x6832, 0x1441,
+ 0x6834, 0x0a97,
+ 0x6838, 0x05a9,
+ 0x6839, 0x081c,
+ 0x683c, 0x05a8,
+ 0x683d, 0x083f,
+ 0x6840, 0x143f,
+ 0x6841, 0x073b,
+ 0x6842, 0x0721,
+ 0x6843, 0x0c67,
+ 0x6844, 0x212f,
+ 0x6846, 0x143d,
+ 0x6848, 0x048a,
+ 0x684d, 0x1440,
+ 0x684e, 0x1442,
+ 0x6850, 0x06c5,
+ 0x6851, 0x0702,
+ 0x6852, 0x212c,
+ 0x6853, 0x05f8,
+ 0x6854, 0x0665,
+ 0x6859, 0x1445,
+ 0x685c, 0x0869,
+ 0x685d, 0x0e9f,
+ 0x685f, 0x0885,
+ 0x6863, 0x1446,
+ 0x6867, 0x0da2,
+ 0x6874, 0x1452,
+ 0x6876, 0x0533,
+ 0x6877, 0x1447,
+ 0x687e, 0x1458,
+ 0x687f, 0x1448,
+ 0x6881, 0x0f8a,
+ 0x6883, 0x144f,
+ 0x6885, 0x0d15,
+ 0x688d, 0x1457,
+ 0x688e, 0x1e9c,
+ 0x688f, 0x144a,
+ 0x6893, 0x0478,
+ 0x6894, 0x144c,
+ 0x6897, 0x07ce,
+ 0x689b, 0x144e,
+ 0x689d, 0x144d,
+ 0x689f, 0x1449,
+ 0x68a0, 0x1454,
+ 0x68a2, 0x09a7,
+ 0x68a6, 0x11be,
+ 0x68a7, 0x079c,
+ 0x68a8, 0x0f66,
+ 0x68ad, 0x144b,
+ 0x68af, 0x0c10,
+ 0x68b0, 0x0581,
+ 0x68b1, 0x081d,
+ 0x68b3, 0x1443,
+ 0x68b5, 0x1453,
+ 0x68b6, 0x05bf,
+ 0x68b9, 0x1451,
+ 0x68ba, 0x1455,
+ 0x68bc, 0x0c68,
+ 0x68c4, 0x063a,
+ 0x68c6, 0x1473,
+ 0x68c8, 0x20af,
+ 0x68c9, 0x0ed5,
+ 0x68ca, 0x145a,
+ 0x68cb, 0x0639,
+ 0x68cd, 0x1461,
+ 0x68cf, 0x2130,
+ 0x68d2, 0x0e6e,
+ 0x68d4, 0x1462,
+ 0x68d5, 0x1464,
+ 0x68d7, 0x1468,
+ 0x68d8, 0x145c,
+ 0x68da, 0x0b68,
+ 0x68df, 0x0c69,
+ 0x68e0, 0x146c,
+ 0x68e1, 0x145f,
+ 0x68e3, 0x1469,
+ 0x68e7, 0x1463,
+ 0x68ee, 0x09ff,
+ 0x68ef, 0x146d,
+ 0x68f2, 0x0a57,
+ 0x68f9, 0x146b,
+ 0x68fa, 0x05f9,
+ 0x6900, 0x0ff6,
+ 0x6901, 0x1459,
+ 0x6904, 0x1467,
+ 0x6905, 0x049c,
+ 0x6908, 0x145b,
+ 0x690b, 0x0ec6,
+ 0x690c, 0x1460,
+ 0x690d, 0x09e8,
+ 0x690e, 0x0be3,
+ 0x690f, 0x1456,
+ 0x6912, 0x1466,
+ 0x6919, 0x0a40,
+ 0x691a, 0x1470,
+ 0x691b, 0x05cf,
+ 0x691c, 0x0755,
+ 0x6921, 0x1472,
+ 0x6922, 0x145d,
+ 0x6923, 0x1471,
+ 0x6925, 0x146a,
+ 0x6926, 0x145e,
+ 0x6928, 0x146e,
+ 0x692a, 0x146f,
+ 0x6930, 0x1480,
+ 0x6934, 0x0ca6,
+ 0x6936, 0x1465,
+ 0x6939, 0x147c,
+ 0x693d, 0x147e,
+ 0x693f, 0x0bf4,
+ 0x694a, 0x0f36,
+ 0x6953, 0x0de8,
+ 0x6954, 0x1479,
+ 0x6955, 0x0b2a,
+ 0x6959, 0x147f,
+ 0x695a, 0x0ac1,
+ 0x695c, 0x1476,
+ 0x695d, 0x1483,
+ 0x695e, 0x1482,
+ 0x6960, 0x0cc7,
+ 0x6961, 0x1481,
+ 0x6962, 0x0cc2,
+ 0x6968, 0x2132,
+ 0x696a, 0x1485,
+ 0x696b, 0x1478,
+ 0x696d, 0x06c0,
+ 0x696e, 0x147b,
+ 0x696f, 0x0967,
+ 0x6973, 0x0d16,
+ 0x6974, 0x147d,
+ 0x6975, 0x06c3,
+ 0x6977, 0x1475,
+ 0x6978, 0x1477,
+ 0x6979, 0x1474,
+ 0x697c, 0x0fd6,
+ 0x697d, 0x05b8,
+ 0x697e, 0x147a,
+ 0x6981, 0x1484,
+ 0x6982, 0x0593,
+ 0x698a, 0x0857,
+ 0x698e, 0x04ff,
+ 0x6991, 0x1495,
+ 0x6994, 0x0fd7,
+ 0x6995, 0x1498,
+ 0x6998, 0x2134,
+ 0x699b, 0x0a00,
+ 0x699c, 0x1497,
+ 0x69a0, 0x1496,
+ 0x69a7, 0x1493,
+ 0x69ae, 0x1487,
+ 0x69b1, 0x14a4,
+ 0x69b2, 0x1486,
+ 0x69b4, 0x1499,
+ 0x69bb, 0x1491,
+ 0x69be, 0x148c,
+ 0x69bf, 0x1489,
+ 0x69c1, 0x148a,
+ 0x69c3, 0x1492,
+ 0x69c7, 0x1d33,
+ 0x69ca, 0x148f,
+ 0x69cb, 0x07cf,
+ 0x69cc, 0x0be4,
+ 0x69cd, 0x0ae6,
+ 0x69ce, 0x148d,
+ 0x69d0, 0x1488,
+ 0x69d3, 0x148b,
+ 0x69d8, 0x0f37,
+ 0x69d9, 0x0e98,
+ 0x69dd, 0x1490,
+ 0x69de, 0x149a,
+ 0x69e2, 0x2135,
+ 0x69e7, 0x14a2,
+ 0x69e8, 0x149b,
+ 0x69eb, 0x14a8,
+ 0x69ed, 0x14a6,
+ 0x69f2, 0x14a1,
+ 0x69f9, 0x14a0,
+ 0x69fb, 0x0bec,
+ 0x69fd, 0x0ae7,
+ 0x69ff, 0x149e,
+ 0x6a02, 0x149c,
+ 0x6a05, 0x14a3,
+ 0x6a0a, 0x14a9,
+ 0x6a0b, 0x0d89,
+ 0x6a0c, 0x14af,
+ 0x6a12, 0x14aa,
+ 0x6a13, 0x14ad,
+ 0x6a14, 0x14a7,
+ 0x6a17, 0x0bb2,
+ 0x6a19, 0x0daa,
+ 0x6a1b, 0x149d,
+ 0x6a1e, 0x14a5,
+ 0x6a1f, 0x09a8,
+ 0x6a21, 0x0edb,
+ 0x6a22, 0x14b9,
+ 0x6a23, 0x14ac,
+ 0x6a29, 0x0756,
+ 0x6a2a, 0x0523,
+ 0x6a2b, 0x05bd,
+ 0x6a2e, 0x1494,
+ 0x6a30, 0x2136,
+ 0x6a35, 0x09a9,
+ 0x6a36, 0x14b1,
+ 0x6a38, 0x14b8,
+ 0x6a39, 0x0925,
+ 0x6a3a, 0x05d0,
+ 0x6a3d, 0x0b6c,
+ 0x6a44, 0x14ae,
+ 0x6a46, 0x2138,
+ 0x6a47, 0x14b3,
+ 0x6a48, 0x14b7,
+ 0x6a4b, 0x06ae,
+ 0x6a58, 0x0666,
+ 0x6a59, 0x14b5,
+ 0x6a5f, 0x063b,
+ 0x6a61, 0x0ca3,
+ 0x6a62, 0x14b4,
+ 0x6a66, 0x14b6,
+ 0x6a6b, 0x2137,
+ 0x6a72, 0x14b0,
+ 0x6a73, 0x2139,
+ 0x6a78, 0x14b2,
+ 0x6a7e, 0x213a,
+ 0x6a7f, 0x05be,
+ 0x6a80, 0x0b87,
+ 0x6a84, 0x14bd,
+ 0x6a8d, 0x14bb,
+ 0x6a8e, 0x079d,
+ 0x6a90, 0x14ba,
+ 0x6a97, 0x14c0,
+ 0x6a9c, 0x143b,
+ 0x6aa0, 0x14bc,
+ 0x6aa2, 0x14be,
+ 0x6aaa, 0x14cb,
+ 0x6aac, 0x14c7,
+ 0x6aae, 0x1450,
+ 0x6ab3, 0x14c6,
+ 0x6ab8, 0x14c5,
+ 0x6abb, 0x14c2,
+ 0x6ac1, 0x14ab,
+ 0x6ac2, 0x14c4,
+ 0x6ac3, 0x14c3,
+ 0x6ad1, 0x14c9,
+ 0x6ad3, 0x0fcc,
+ 0x6ada, 0x14cc,
+ 0x6adb, 0x06f3,
+ 0x6ade, 0x14c8,
+ 0x6adf, 0x14ca,
+ 0x6ae2, 0x213b,
+ 0x6ae4, 0x213c,
+ 0x6ae8, 0x0d3b,
+ 0x6aea, 0x14cd,
+ 0x6afa, 0x14d1,
+ 0x6afb, 0x14ce,
+ 0x6b04, 0x0f5d,
+ 0x6b05, 0x14cf,
+ 0x6b0a, 0x149f,
+ 0x6b12, 0x14d2,
+ 0x6b16, 0x14d3,
+ 0x6b1d, 0x04d7,
+ 0x6b1f, 0x14d5,
+ 0x6b20, 0x073d,
+ 0x6b21, 0x08cd,
+ 0x6b23, 0x06cd,
+ 0x6b27, 0x0524,
+ 0x6b32, 0x0f49,
+ 0x6b37, 0x14d7,
+ 0x6b38, 0x14d6,
+ 0x6b39, 0x14d9,
+ 0x6b3a, 0x0657,
+ 0x6b3d, 0x06ce,
+ 0x6b3e, 0x05fa,
+ 0x6b43, 0x14dc,
+ 0x6b47, 0x14db,
+ 0x6b49, 0x14dd,
+ 0x6b4c, 0x054e,
+ 0x6b4e, 0x0b75,
+ 0x6b50, 0x14de,
+ 0x6b53, 0x05fb,
+ 0x6b54, 0x14e0,
+ 0x6b59, 0x14df,
+ 0x6b5b, 0x14e1,
+ 0x6b5f, 0x14e2,
+ 0x6b61, 0x14e3,
+ 0x6b62, 0x08ad,
+ 0x6b63, 0x0a59,
+ 0x6b64, 0x0811,
+ 0x6b66, 0x0de2,
+ 0x6b69, 0x0e32,
+ 0x6b6a, 0x0fea,
+ 0x6b6f, 0x08c3,
+ 0x6b73, 0x0840,
+ 0x6b74, 0x0fba,
+ 0x6b78, 0x14e4,
+ 0x6b7b, 0x08ae,
+ 0x6b7f, 0x14e6,
+ 0x6b83, 0x14e9,
+ 0x6b84, 0x14e8,
+ 0x6b86, 0x0e86,
+ 0x6b89, 0x0968,
+ 0x6b8a, 0x0918,
+ 0x6b8b, 0x0892,
+ 0x6b8d, 0x14ea,
+ 0x6b95, 0x14ec,
+ 0x6b96, 0x09e9,
+ 0x6b98, 0x14eb,
+ 0x6b9e, 0x14ed,
+ 0x6ba4, 0x14ee,
+ 0x6baa, 0x14ef,
+ 0x6baf, 0x14f1,
+ 0x6bb1, 0x14f3,
+ 0x6bb2, 0x14f2,
+ 0x6bb3, 0x14f4,
+ 0x6bb4, 0x0525,
+ 0x6bb5, 0x0b88,
+ 0x6bb7, 0x14f5,
+ 0x6bba, 0x0874,
+ 0x6bbb, 0x05aa,
+ 0x6bbc, 0x14f6,
+ 0x6bbf, 0x0c3c,
+ 0x6bc0, 0x119d,
+ 0x6bc5, 0x063d,
+ 0x6bc6, 0x14f7,
+ 0x6bcb, 0x14f8,
+ 0x6bcd, 0x0e3c,
+ 0x6bce, 0x0e96,
+ 0x6bd2, 0x0c9f,
+ 0x6bd3, 0x14f9,
+ 0x6bd4, 0x0d7a,
+ 0x6bd6, 0x213d,
+ 0x6bd8, 0x0d8f,
+ 0x6bdb, 0x0edf,
+ 0x6bdf, 0x14fa,
+ 0x6beb, 0x14fc,
+ 0x6bec, 0x14fb,
+ 0x6bef, 0x14fe,
+ 0x6bf3, 0x14fd,
+ 0x6c08, 0x1500,
+ 0x6c0f, 0x08af,
+ 0x6c11, 0x0ebd,
+ 0x6c13, 0x1501,
+ 0x6c17, 0x063e,
+ 0x6c1b, 0x1503,
+ 0x6c23, 0x1505,
+ 0x6c24, 0x1504,
+ 0x6c34, 0x0a2b,
+ 0x6c37, 0x0dab,
+ 0x6c38, 0x04ec,
+ 0x6c3e, 0x0d59,
+ 0x6c3f, 0x213e,
+ 0x6c40, 0x0c11,
+ 0x6c41, 0x094b,
+ 0x6c42, 0x067b,
+ 0x6c4e, 0x0d5a,
+ 0x6c50, 0x08da,
+ 0x6c55, 0x1507,
+ 0x6c57, 0x05fc,
+ 0x6c5a, 0x051a,
+ 0x6c5c, 0x213f,
+ 0x6c5d, 0x0cca,
+ 0x6c5e, 0x1506,
+ 0x6c5f, 0x07d0,
+ 0x6c60, 0x0b91,
+ 0x6c62, 0x1508,
+ 0x6c68, 0x1510,
+ 0x6c6a, 0x1509,
+ 0x6c6f, 0x2141,
+ 0x6c70, 0x0b21,
+ 0x6c72, 0x067c,
+ 0x6c73, 0x1511,
+ 0x6c7a, 0x073e,
+ 0x6c7d, 0x063f,
+ 0x6c7e, 0x150f,
+ 0x6c81, 0x150d,
+ 0x6c82, 0x150a,
+ 0x6c83, 0x0f4a,
+ 0x6c86, 0x2140,
+ 0x6c88, 0x0bdc,
+ 0x6c8c, 0x0cb1,
+ 0x6c8d, 0x150b,
+ 0x6c90, 0x1513,
+ 0x6c92, 0x1512,
+ 0x6c93, 0x06f9,
+ 0x6c96, 0x052d,
+ 0x6c99, 0x082b,
+ 0x6c9a, 0x150c,
+ 0x6c9b, 0x150e,
+ 0x6ca1, 0x0e85,
+ 0x6ca2, 0x0b54,
+ 0x6cab, 0x0ea5,
+ 0x6cae, 0x151b,
+ 0x6cb1, 0x151c,
+ 0x6cb3, 0x054f,
+ 0x6cb8, 0x0df8,
+ 0x6cb9, 0x0f09,
+ 0x6cba, 0x151e,
+ 0x6cbb, 0x08cf,
+ 0x6cbc, 0x09aa,
+ 0x6cbd, 0x1517,
+ 0x6cbe, 0x151d,
+ 0x6cbf, 0x050a,
+ 0x6cc1, 0x06af,
+ 0x6cc4, 0x1514,
+ 0x6cc5, 0x1519,
+ 0x6cc9, 0x0a98,
+ 0x6cca, 0x0d27,
+ 0x6ccc, 0x0d7b,
+ 0x6cd3, 0x1516,
+ 0x6cd5, 0x0e4f,
+ 0x6cd7, 0x1518,
+ 0x6cd9, 0x1521,
+ 0x6cda, 0x2142,
+ 0x6cdb, 0x151f,
+ 0x6cdd, 0x151a,
+ 0x6ce1, 0x0e50,
+ 0x6ce2, 0x0cfe,
+ 0x6ce3, 0x067d,
+ 0x6ce5, 0x0c1f,
+ 0x6ce8, 0x0bab,
+ 0x6cea, 0x1522,
+ 0x6cef, 0x1520,
+ 0x6cf0, 0x0b39,
+ 0x6cf1, 0x1515,
+ 0x6cf3, 0x04ed,
+ 0x6d04, 0x2143,
+ 0x6d0b, 0x0f38,
+ 0x6d0c, 0x152d,
+ 0x6d12, 0x152c,
+ 0x6d17, 0x0a9a,
+ 0x6d19, 0x1529,
+ 0x6d1b, 0x0f56,
+ 0x6d1e, 0x0c8e,
+ 0x6d1f, 0x1523,
+ 0x6d25, 0x0be1,
+ 0x6d29, 0x04ee,
+ 0x6d2a, 0x07d1,
+ 0x6d2b, 0x1526,
+ 0x6d32, 0x0931,
+ 0x6d33, 0x152b,
+ 0x6d35, 0x152a,
+ 0x6d36, 0x1525,
+ 0x6d38, 0x1528,
+ 0x6d3b, 0x05c6,
+ 0x6d3d, 0x1527,
+ 0x6d3e, 0x0cff,
+ 0x6d41, 0x0f76,
+ 0x6d44, 0x09dc,
+ 0x6d45, 0x0a99,
+ 0x6d59, 0x1533,
+ 0x6d5a, 0x1531,
+ 0x6d5c, 0x0dbf,
+ 0x6d63, 0x152e,
+ 0x6d64, 0x1530,
+ 0x6d66, 0x04dc,
+ 0x6d69, 0x07d2,
+ 0x6d6a, 0x0fd8,
+ 0x6d6c, 0x059b,
+ 0x6d6e, 0x0dd4,
+ 0x6d6f, 0x2145,
+ 0x6d74, 0x0f4b,
+ 0x6d77, 0x0582,
+ 0x6d78, 0x0a01,
+ 0x6d79, 0x1532,
+ 0x6d85, 0x1537,
+ 0x6d87, 0x2144,
+ 0x6d88, 0x09ab,
+ 0x6d8c, 0x0f1a,
+ 0x6d8e, 0x1534,
+ 0x6d93, 0x152f,
+ 0x6d95, 0x1535,
+ 0x6d96, 0x2146,
+ 0x6d99, 0x0fa6,
+ 0x6d9b, 0x0c6d,
+ 0x6d9c, 0x0c9a,
+ 0x6dac, 0x2147,
+ 0x6daf, 0x0594,
+ 0x6db2, 0x04f7,
+ 0x6db5, 0x153b,
+ 0x6db8, 0x153e,
+ 0x6dbc, 0x0f8b,
+ 0x6dc0, 0x0f4e,
+ 0x6dc5, 0x1545,
+ 0x6dc6, 0x153f,
+ 0x6dc7, 0x153c,
+ 0x6dcb, 0x0f9c,
+ 0x6dcc, 0x1542,
+ 0x6dcf, 0x2148,
+ 0x6dd1, 0x0954,
+ 0x6dd2, 0x1544,
+ 0x6dd5, 0x1549,
+ 0x6dd8, 0x0c6b,
+ 0x6dd9, 0x1547,
+ 0x6dde, 0x1541,
+ 0x6de1, 0x0b76,
+ 0x6de4, 0x1548,
+ 0x6de6, 0x153d,
+ 0x6de8, 0x1543,
+ 0x6dea, 0x154a,
+ 0x6deb, 0x04c0,
+ 0x6dec, 0x1540,
+ 0x6dee, 0x154b,
+ 0x6df1, 0x0a02,
+ 0x6df2, 0x214a,
+ 0x6df3, 0x0969,
+ 0x6df5, 0x0df5,
+ 0x6df7, 0x081e,
+ 0x6df8, 0x2149,
+ 0x6df9, 0x1538,
+ 0x6dfa, 0x1546,
+ 0x6dfb, 0x0c34,
+ 0x6dfc, 0x214b,
+ 0x6e05, 0x0a5a,
+ 0x6e07, 0x05c7,
+ 0x6e08, 0x0841,
+ 0x6e09, 0x09ac,
+ 0x6e0a, 0x153a,
+ 0x6e0b, 0x094c,
+ 0x6e13, 0x0722,
+ 0x6e15, 0x1539,
+ 0x6e19, 0x154f,
+ 0x6e1a, 0x0977,
+ 0x6e1b, 0x076e,
+ 0x6e1d, 0x155e,
+ 0x6e1f, 0x1558,
+ 0x6e20, 0x068e,
+ 0x6e21, 0x0c49,
+ 0x6e23, 0x1553,
+ 0x6e24, 0x155c,
+ 0x6e25, 0x0473,
+ 0x6e26, 0x04d4,
+ 0x6e27, 0x214e,
+ 0x6e29, 0x0539,
+ 0x6e2b, 0x1555,
+ 0x6e2c, 0x0b0c,
+ 0x6e2d, 0x154c,
+ 0x6e2e, 0x154e,
+ 0x6e2f, 0x07d3,
+ 0x6e38, 0x155f,
+ 0x6e39, 0x214c,
+ 0x6e3a, 0x155a,
+ 0x6e3c, 0x214f,
+ 0x6e3e, 0x1552,
+ 0x6e43, 0x1559,
+ 0x6e4a, 0x0eb7,
+ 0x6e4d, 0x1557,
+ 0x6e4e, 0x155b,
+ 0x6e56, 0x0784,
+ 0x6e58, 0x09ad,
+ 0x6e5b, 0x0b77,
+ 0x6e5c, 0x214d,
+ 0x6e5f, 0x1551,
+ 0x6e67, 0x0f19,
+ 0x6e6b, 0x1554,
+ 0x6e6e, 0x154d,
+ 0x6e6f, 0x0c6c,
+ 0x6e72, 0x1550,
+ 0x6e76, 0x1556,
+ 0x6e7e, 0x0ff7,
+ 0x6e7f, 0x08ea,
+ 0x6e80, 0x0eac,
+ 0x6e82, 0x1560,
+ 0x6e8c, 0x0d42,
+ 0x6e8f, 0x156c,
+ 0x6e90, 0x076f,
+ 0x6e96, 0x096a,
+ 0x6e98, 0x1562,
+ 0x6e9c, 0x0f77,
+ 0x6e9d, 0x07d4,
+ 0x6e9f, 0x156f,
+ 0x6ea2, 0x04b2,
+ 0x6ea5, 0x156d,
+ 0x6eaa, 0x1561,
+ 0x6eaf, 0x1567,
+ 0x6eb2, 0x1569,
+ 0x6eb6, 0x0f39,
+ 0x6eb7, 0x1564,
+ 0x6eba, 0x0c28,
+ 0x6ebd, 0x1566,
+ 0x6ebf, 0x2150,
+ 0x6ec2, 0x156e,
+ 0x6ec4, 0x1568,
+ 0x6ec5, 0x0ed3,
+ 0x6ec9, 0x1563,
+ 0x6ecb, 0x08ce,
+ 0x6ecc, 0x157b,
+ 0x6ed1, 0x05c8,
+ 0x6ed3, 0x1565,
+ 0x6ed4, 0x156a,
+ 0x6edd, 0x0b4c,
+ 0x6ede, 0x0b3a,
+ 0x6eec, 0x1573,
+ 0x6eef, 0x1579,
+ 0x6ef2, 0x1577,
+ 0x6ef4, 0x0c23,
+ 0x6ef7, 0x157e,
+ 0x6ef8, 0x1574,
+ 0x6efe, 0x1575,
+ 0x6eff, 0x155d,
+ 0x6f01, 0x0693,
+ 0x6f02, 0x0dac,
+ 0x6f06, 0x08eb,
+ 0x6f09, 0x0809,
+ 0x6f0f, 0x0fd9,
+ 0x6f11, 0x1571,
+ 0x6f13, 0x157d,
+ 0x6f14, 0x050b,
+ 0x6f15, 0x0ae8,
+ 0x6f20, 0x0d2f,
+ 0x6f22, 0x05fd,
+ 0x6f23, 0x0fc2,
+ 0x6f2b, 0x0ead,
+ 0x6f2c, 0x0bee,
+ 0x6f31, 0x1578,
+ 0x6f32, 0x157a,
+ 0x6f38, 0x0ab4,
+ 0x6f3e, 0x157c,
+ 0x6f3f, 0x1576,
+ 0x6f41, 0x1570,
+ 0x6f45, 0x05ff,
+ 0x6f51, 0x1e60,
+ 0x6f54, 0x073f,
+ 0x6f58, 0x158a,
+ 0x6f5b, 0x1585,
+ 0x6f5c, 0x0a9c,
+ 0x6f5f, 0x05c1,
+ 0x6f64, 0x096b,
+ 0x6f66, 0x158e,
+ 0x6f6d, 0x1587,
+ 0x6f6e, 0x0bc8,
+ 0x6f6f, 0x1584,
+ 0x6f70, 0x0bf5,
+ 0x6f74, 0x15a7,
+ 0x6f78, 0x1581,
+ 0x6f7a, 0x1580,
+ 0x6f7c, 0x1589,
+ 0x6f80, 0x1583,
+ 0x6f81, 0x1582,
+ 0x6f82, 0x1588,
+ 0x6f84, 0x0a45,
+ 0x6f86, 0x157f,
+ 0x6f88, 0x2151,
+ 0x6f8e, 0x158b,
+ 0x6f91, 0x158c,
+ 0x6f97, 0x05fe,
+ 0x6fa1, 0x1591,
+ 0x6fa3, 0x1590,
+ 0x6fa4, 0x1592,
+ 0x6faa, 0x1595,
+ 0x6fb1, 0x0c3d,
+ 0x6fb3, 0x158f,
+ 0x6fb5, 0x2152,
+ 0x6fb9, 0x1593,
+ 0x6fc0, 0x0739,
+ 0x6fc1, 0x0b59,
+ 0x6fc2, 0x158d,
+ 0x6fc3, 0x0cf1,
+ 0x6fc6, 0x1594,
+ 0x6fd4, 0x1599,
+ 0x6fd5, 0x1597,
+ 0x6fd8, 0x159a,
+ 0x6fdb, 0x159d,
+ 0x6fdf, 0x1596,
+ 0x6fe0, 0x07fc,
+ 0x6fe1, 0x0cde,
+ 0x6fe4, 0x1536,
+ 0x6feb, 0x0f5e,
+ 0x6fec, 0x1598,
+ 0x6fee, 0x159c,
+ 0x6fef, 0x0b55,
+ 0x6ff1, 0x159b,
+ 0x6ff3, 0x1586,
+ 0x6ff5, 0x2153,
+ 0x6ff6, 0x1ba4,
+ 0x6ffa, 0x15a0,
+ 0x6ffe, 0x15a4,
+ 0x7001, 0x15a2,
+ 0x7005, 0x2154,
+ 0x7006, 0x1e50,
+ 0x7007, 0x2155,
+ 0x7009, 0x159e,
+ 0x700b, 0x159f,
+ 0x700f, 0x15a3,
+ 0x7011, 0x15a1,
+ 0x7015, 0x0dc0,
+ 0x7018, 0x15a9,
+ 0x701a, 0x15a6,
+ 0x701b, 0x15a5,
+ 0x701d, 0x15a8,
+ 0x701e, 0x0cac,
+ 0x701f, 0x15aa,
+ 0x7026, 0x0bb3,
+ 0x7027, 0x0b4d,
+ 0x7028, 0x2156,
+ 0x702c, 0x0a49,
+ 0x7030, 0x15ab,
+ 0x7032, 0x15ad,
+ 0x703e, 0x15ac,
+ 0x704c, 0x1572,
+ 0x7051, 0x15ae,
+ 0x7058, 0x0cbf,
+ 0x7063, 0x15af,
+ 0x706b, 0x0550,
+ 0x706f, 0x0c6e,
+ 0x7070, 0x0583,
+ 0x7078, 0x067e,
+ 0x707c, 0x090a,
+ 0x707d, 0x0842,
+ 0x7085, 0x2157,
+ 0x7089, 0x0fcd,
+ 0x708a, 0x0a2c,
+ 0x708e, 0x050c,
+ 0x7092, 0x15b1,
+ 0x7099, 0x15b0,
+ 0x70ab, 0x2158,
+ 0x70ac, 0x15b4,
+ 0x70ad, 0x0b78,
+ 0x70ae, 0x15b7,
+ 0x70af, 0x15b2,
+ 0x70b3, 0x15b6,
+ 0x70b8, 0x15b5,
+ 0x70b9, 0x0c3a,
+ 0x70ba, 0x049d,
+ 0x70bb, 0x20ad,
+ 0x70c8, 0x0fbd,
+ 0x70cb, 0x15b9,
+ 0x70cf, 0x04ca,
+ 0x70d9, 0x15bb,
+ 0x70dd, 0x15ba,
+ 0x70df, 0x15b8,
+ 0x70f1, 0x15b3,
+ 0x70f9, 0x0e51,
+ 0x70fd, 0x15bd,
+ 0x7104, 0x215a,
+ 0x7109, 0x15bc,
+ 0x710f, 0x2159,
+ 0x7114, 0x050d,
+ 0x7119, 0x15bf,
+ 0x711a, 0x0e02,
+ 0x711c, 0x15be,
+ 0x7121, 0x0ec1,
+ 0x7126, 0x09af,
+ 0x7130, 0x1ddc,
+ 0x7136, 0x0ab5,
+ 0x713c, 0x09ae,
+ 0x7146, 0x215c,
+ 0x7149, 0x0fc3,
+ 0x714c, 0x15c5,
+ 0x714e, 0x0a9d,
+ 0x7155, 0x15c1,
+ 0x7156, 0x15c6,
+ 0x7159, 0x050e,
+ 0x715c, 0x215b,
+ 0x7162, 0x15c4,
+ 0x7164, 0x0d17,
+ 0x7165, 0x15c0,
+ 0x7166, 0x15c3,
+ 0x7167, 0x09b0,
+ 0x7169, 0x0d65,
+ 0x716c, 0x15c7,
+ 0x716e, 0x08fd,
+ 0x717d, 0x0a9e,
+ 0x7184, 0x15ca,
+ 0x7188, 0x15c2,
+ 0x718a, 0x06fd,
+ 0x718f, 0x15c8,
+ 0x7194, 0x0f3a,
+ 0x7195, 0x15cb,
+ 0x7199, 0x205d,
+ 0x719f, 0x0959,
+ 0x71a8, 0x15cc,
+ 0x71ac, 0x15cd,
+ 0x71b1, 0x0ce4,
+ 0x71b9, 0x15cf,
+ 0x71be, 0x15d0,
+ 0x71c1, 0x215f,
+ 0x71c3, 0x0ce9,
+ 0x71c8, 0x0c6f,
+ 0x71c9, 0x15d2,
+ 0x71ce, 0x15d4,
+ 0x71d0, 0x0f9d,
+ 0x71d2, 0x15d1,
+ 0x71d4, 0x15d3,
+ 0x71d5, 0x050f,
+ 0x71d7, 0x15ce,
+ 0x71df, 0x114e,
+ 0x71e0, 0x15d5,
+ 0x71e5, 0x0ae9,
+ 0x71e6, 0x0886,
+ 0x71e7, 0x15d7,
+ 0x71ec, 0x15d6,
+ 0x71ed, 0x09ea,
+ 0x71ee, 0x10ee,
+ 0x71f5, 0x15d8,
+ 0x71f9, 0x15da,
+ 0x71fb, 0x15c9,
+ 0x71fc, 0x15d9,
+ 0x71fe, 0x2160,
+ 0x71ff, 0x15db,
+ 0x7206, 0x0d30,
+ 0x720d, 0x15dc,
+ 0x7210, 0x15dd,
+ 0x721b, 0x15de,
+ 0x7228, 0x15df,
+ 0x722a, 0x0bfa,
+ 0x722c, 0x15e1,
+ 0x722d, 0x15e0,
+ 0x7230, 0x15e2,
+ 0x7232, 0x15e3,
+ 0x7235, 0x090b,
+ 0x7236, 0x0dd5,
+ 0x723a, 0x0ef8,
+ 0x723b, 0x15e4,
+ 0x723d, 0x0ad8,
+ 0x723e, 0x08d0,
+ 0x723f, 0x15e6,
+ 0x7246, 0x15e8,
+ 0x7247, 0x0e22,
+ 0x7248, 0x0d5b,
+ 0x724b, 0x15e9,
+ 0x724c, 0x0d0d,
+ 0x7252, 0x0bc9,
+ 0x7258, 0x15ea,
+ 0x7259, 0x0567,
+ 0x725b, 0x0687,
+ 0x725d, 0x0ed2,
+ 0x725f, 0x0ec2,
+ 0x7261, 0x0534,
+ 0x7262, 0x0fda,
+ 0x7267, 0x0e80,
+ 0x7269, 0x0dfa,
+ 0x7272, 0x0a5b,
+ 0x7274, 0x15eb,
+ 0x7279, 0x0c9b,
+ 0x727d, 0x0757,
+ 0x727e, 0x15ec,
+ 0x7280, 0x0844,
+ 0x7281, 0x15ee,
+ 0x7282, 0x15ed,
+ 0x7287, 0x15ef,
+ 0x7292, 0x15f0,
+ 0x7296, 0x15f1,
+ 0x72a0, 0x0658,
+ 0x72a2, 0x15f2,
+ 0x72a7, 0x15f3,
+ 0x72ac, 0x0758,
+ 0x72af, 0x0d5c,
+ 0x72b1, 0x2161,
+ 0x72b2, 0x15f5,
+ 0x72b6, 0x09dd,
+ 0x72b9, 0x15f4,
+ 0x72be, 0x2162,
+ 0x72c2, 0x06b0,
+ 0x72c3, 0x15f6,
+ 0x72c4, 0x15f8,
+ 0x72c6, 0x15f7,
+ 0x72ce, 0x15f9,
+ 0x72d0, 0x0785,
+ 0x72d2, 0x15fa,
+ 0x72d7, 0x06e1,
+ 0x72d9, 0x0ac2,
+ 0x72db, 0x080f,
+ 0x72e0, 0x15fc,
+ 0x72e2, 0x15fb,
+ 0x72e9, 0x0919,
+ 0x72ec, 0x0ca0,
+ 0x72ed, 0x06b1,
+ 0x72f7, 0x15ff,
+ 0x72f8, 0x0b6a,
+ 0x72f9, 0x15fe,
+ 0x72fc, 0x0fdb,
+ 0x72fd, 0x0d18,
+ 0x730a, 0x1602,
+ 0x7316, 0x1604,
+ 0x7317, 0x1601,
+ 0x731b, 0x0ee0,
+ 0x731c, 0x1603,
+ 0x731d, 0x1605,
+ 0x731f, 0x0f8c,
+ 0x7324, 0x2163,
+ 0x7325, 0x1609,
+ 0x7329, 0x1608,
+ 0x732a, 0x0bb4,
+ 0x732b, 0x0ce3,
+ 0x732e, 0x0759,
+ 0x732f, 0x1607,
+ 0x7334, 0x1606,
+ 0x7336, 0x0f1b,
+ 0x733e, 0x160a,
+ 0x733f, 0x0510,
+ 0x7344, 0x0808,
+ 0x7345, 0x08b0,
+ 0x734e, 0x160b,
+ 0x7357, 0x160e,
+ 0x7363, 0x094d,
+ 0x7368, 0x1610,
+ 0x736a, 0x160f,
+ 0x7370, 0x1611,
+ 0x7372, 0x05ab,
+ 0x7375, 0x1613,
+ 0x7377, 0x2165,
+ 0x7378, 0x1612,
+ 0x737a, 0x1615,
+ 0x737b, 0x1614,
+ 0x7384, 0x0770,
+ 0x7387, 0x0f70,
+ 0x7389, 0x06c4,
+ 0x738b, 0x0526,
+ 0x7396, 0x06e2,
+ 0x73a9, 0x061d,
+ 0x73b2, 0x0fb0,
+ 0x73b3, 0x1617,
+ 0x73bb, 0x1619,
+ 0x73bd, 0x2166,
+ 0x73c0, 0x161a,
+ 0x73c2, 0x0551,
+ 0x73c8, 0x1616,
+ 0x73c9, 0x2167,
+ 0x73ca, 0x0887,
+ 0x73cd, 0x0bdd,
+ 0x73ce, 0x1618,
+ 0x73d2, 0x216a,
+ 0x73d6, 0x2168,
+ 0x73de, 0x161d,
+ 0x73e0, 0x091a,
+ 0x73e3, 0x2169,
+ 0x73e5, 0x161b,
+ 0x73ea, 0x0714,
+ 0x73ed, 0x0d5d,
+ 0x73ee, 0x161c,
+ 0x73f1, 0x1637,
+ 0x73f5, 0x216c,
+ 0x73f8, 0x1622,
+ 0x73fe, 0x0771,
+ 0x7403, 0x067f,
+ 0x7405, 0x161f,
+ 0x7406, 0x0f67,
+ 0x7407, 0x216b,
+ 0x7409, 0x0f78,
+ 0x7422, 0x0b56,
+ 0x7425, 0x1621,
+ 0x7426, 0x216d,
+ 0x7429, 0x216f,
+ 0x742a, 0x216e,
+ 0x742e, 0x2170,
+ 0x7432, 0x1623,
+ 0x7433, 0x0f9e,
+ 0x7434, 0x06cf,
+ 0x7435, 0x0d90,
+ 0x7436, 0x0d00,
+ 0x743a, 0x1624,
+ 0x743f, 0x1626,
+ 0x7441, 0x1629,
+ 0x7455, 0x1625,
+ 0x7459, 0x1628,
+ 0x745a, 0x079e,
+ 0x745b, 0x04ef,
+ 0x745c, 0x162a,
+ 0x745e, 0x0a36,
+ 0x745f, 0x1627,
+ 0x7460, 0x0fa4,
+ 0x7462, 0x2171,
+ 0x7463, 0x162d,
+ 0x7464, 0x1d35,
+ 0x7469, 0x162b,
+ 0x746a, 0x162e,
+ 0x746f, 0x1620,
+ 0x7470, 0x162c,
+ 0x7473, 0x082c,
+ 0x7476, 0x162f,
+ 0x747e, 0x1630,
+ 0x7483, 0x0f68,
+ 0x7489, 0x2172,
+ 0x748b, 0x1631,
+ 0x749e, 0x1632,
+ 0x749f, 0x2173,
+ 0x74a2, 0x161e,
+ 0x74a7, 0x1633,
+ 0x74b0, 0x0600,
+ 0x74bd, 0x08d1,
+ 0x74ca, 0x1634,
+ 0x74cf, 0x1635,
+ 0x74d4, 0x1636,
+ 0x74dc, 0x04dd,
+ 0x74e0, 0x1638,
+ 0x74e2, 0x0dad,
+ 0x74e3, 0x1639,
+ 0x74e6, 0x05e0,
+ 0x74e7, 0x163a,
+ 0x74e9, 0x163b,
+ 0x74ee, 0x163c,
+ 0x74f0, 0x163e,
+ 0x74f2, 0x163d,
+ 0x74f6, 0x0dc5,
+ 0x74f7, 0x1641,
+ 0x74f8, 0x1640,
+ 0x7501, 0x2174,
+ 0x7503, 0x1643,
+ 0x7504, 0x1642,
+ 0x7505, 0x1644,
+ 0x750c, 0x1645,
+ 0x750d, 0x1647,
+ 0x750e, 0x1646,
+ 0x7511, 0x080b,
+ 0x7513, 0x1649,
+ 0x7515, 0x1648,
+ 0x7518, 0x0601,
+ 0x751a, 0x0a19,
+ 0x751c, 0x0c36,
+ 0x751e, 0x164a,
+ 0x751f, 0x0a5c,
+ 0x7523, 0x0888,
+ 0x7525, 0x051b,
+ 0x7526, 0x164b,
+ 0x7528, 0x0f3b,
+ 0x752b, 0x0e33,
+ 0x752c, 0x164c,
+ 0x752f, 0x20f2,
+ 0x7530, 0x0c3e,
+ 0x7531, 0x0f1d,
+ 0x7532, 0x07d5,
+ 0x7533, 0x0a03,
+ 0x7537, 0x0b89,
+ 0x7538, 0x10c9,
+ 0x753a, 0x0bca,
+ 0x753b, 0x0568,
+ 0x753c, 0x164d,
+ 0x7544, 0x164e,
+ 0x7546, 0x1653,
+ 0x7549, 0x1651,
+ 0x754a, 0x1650,
+ 0x754b, 0x13c7,
+ 0x754c, 0x0584,
+ 0x754d, 0x164f,
+ 0x754f, 0x049e,
+ 0x7551, 0x0d3e,
+ 0x7554, 0x0d5e,
+ 0x7559, 0x0f79,
+ 0x755a, 0x1654,
+ 0x755b, 0x1652,
+ 0x755c, 0x0b9a,
+ 0x755d, 0x0a4a,
+ 0x7560, 0x0d3f,
+ 0x7562, 0x0d9f,
+ 0x7564, 0x1656,
+ 0x7565, 0x0f74,
+ 0x7566, 0x0723,
+ 0x7567, 0x1657,
+ 0x7569, 0x1655,
+ 0x756a, 0x0d6a,
+ 0x756b, 0x1658,
+ 0x756d, 0x1659,
+ 0x756f, 0x2175,
+ 0x7570, 0x049f,
+ 0x7573, 0x09de,
+ 0x7574, 0x165e,
+ 0x7576, 0x165b,
+ 0x7577, 0x0cc5,
+ 0x7578, 0x165a,
+ 0x757f, 0x0640,
+ 0x7582, 0x1661,
+ 0x7586, 0x165c,
+ 0x7589, 0x1660,
+ 0x758a, 0x165f,
+ 0x758b, 0x0d97,
+ 0x758e, 0x0ac4,
+ 0x758f, 0x0ac3,
+ 0x7591, 0x0659,
+ 0x7594, 0x1662,
+ 0x759a, 0x1663,
+ 0x759d, 0x1664,
+ 0x75a3, 0x1666,
+ 0x75a5, 0x1665,
+ 0x75ab, 0x04f8,
+ 0x75b1, 0x166e,
+ 0x75b2, 0x0d7c,
+ 0x75b3, 0x1668,
+ 0x75b5, 0x166a,
+ 0x75b8, 0x166c,
+ 0x75b9, 0x0a04,
+ 0x75bc, 0x166d,
+ 0x75bd, 0x166b,
+ 0x75be, 0x08ec,
+ 0x75c2, 0x1667,
+ 0x75c3, 0x1669,
+ 0x75c5, 0x0db4,
+ 0x75c7, 0x09b1,
+ 0x75ca, 0x1670,
+ 0x75cd, 0x166f,
+ 0x75d2, 0x1671,
+ 0x75d4, 0x08d2,
+ 0x75d5, 0x081f,
+ 0x75d8, 0x0c71,
+ 0x75d9, 0x1672,
+ 0x75db, 0x0be7,
+ 0x75de, 0x1674,
+ 0x75e2, 0x0f69,
+ 0x75e3, 0x1673,
+ 0x75e9, 0x0aeb,
+ 0x75f0, 0x1679,
+ 0x75f2, 0x167b,
+ 0x75f4, 0x0b92,
+ 0x75fa, 0x167a,
+ 0x75fc, 0x1677,
+ 0x75fe, 0x1675,
+ 0x7601, 0x1678,
+ 0x7609, 0x167f,
+ 0x760b, 0x167d,
+ 0x760d, 0x167e,
+ 0x761f, 0x1680,
+ 0x7620, 0x1682,
+ 0x7624, 0x1685,
+ 0x7626, 0x1e2d,
+ 0x7627, 0x1681,
+ 0x7630, 0x1687,
+ 0x7634, 0x1686,
+ 0x763b, 0x1688,
+ 0x7642, 0x0f8d,
+ 0x7646, 0x168b,
+ 0x7647, 0x1689,
+ 0x764c, 0x061e,
+ 0x7652, 0x0f0a,
+ 0x7656, 0x0e1a,
+ 0x7658, 0x168d,
+ 0x765c, 0x168c,
+ 0x7661, 0x168e,
+ 0x7667, 0x1693,
+ 0x7668, 0x1690,
+ 0x766c, 0x1694,
+ 0x7670, 0x1695,
+ 0x7672, 0x1696,
+ 0x7676, 0x1697,
+ 0x7678, 0x1698,
+ 0x767a, 0x0d43,
+ 0x767b, 0x0c4a,
+ 0x767c, 0x1699,
+ 0x767d, 0x0d28,
+ 0x767e, 0x0da6,
+ 0x7680, 0x169a,
+ 0x7682, 0x2176,
+ 0x7683, 0x169b,
+ 0x7684, 0x0c24,
+ 0x7686, 0x0585,
+ 0x7687, 0x07d6,
+ 0x7688, 0x169c,
+ 0x768b, 0x169d,
+ 0x768e, 0x169e,
+ 0x7690, 0x0877,
+ 0x7693, 0x16a0,
+ 0x7696, 0x169f,
+ 0x7699, 0x16a1,
+ 0x769b, 0x2179,
+ 0x769c, 0x2177,
+ 0x769e, 0x2178,
+ 0x76a6, 0x217a,
+ 0x76ae, 0x0d7d,
+ 0x76b0, 0x16a3,
+ 0x76b4, 0x16a4,
+ 0x76b7, 0x1d1c,
+ 0x76b8, 0x16a5,
+ 0x76bf, 0x087c,
+ 0x76c2, 0x16a8,
+ 0x76c3, 0x0d0c,
+ 0x76c6, 0x0e8d,
+ 0x76c8, 0x04f0,
+ 0x76ca, 0x04f9,
+ 0x76cd, 0x16a9,
+ 0x76d2, 0x16ab,
+ 0x76d6, 0x16aa,
+ 0x76d7, 0x0c6a,
+ 0x76db, 0x0a5d,
+ 0x76dc, 0x14d8,
+ 0x76de, 0x16ac,
+ 0x76df, 0x0ecd,
+ 0x76e1, 0x16ad,
+ 0x76e3, 0x0602,
+ 0x76e4, 0x0d6b,
+ 0x76e5, 0x16ae,
+ 0x76e7, 0x16af,
+ 0x76ea, 0x16b0,
+ 0x76ee, 0x0ee8,
+ 0x76f2, 0x0ee1,
+ 0x76f4, 0x0bda,
+ 0x76f8, 0x0aec,
+ 0x76fb, 0x16b2,
+ 0x76fe, 0x096c,
+ 0x7701, 0x09b2,
+ 0x7704, 0x16b5,
+ 0x7707, 0x16b4,
+ 0x7708, 0x16b3,
+ 0x7709, 0x0d91,
+ 0x770b, 0x0603,
+ 0x770c, 0x075d,
+ 0x771b, 0x16bb,
+ 0x771e, 0x16b8,
+ 0x771f, 0x0a05,
+ 0x7720, 0x0ebe,
+ 0x7724, 0x16b7,
+ 0x7725, 0x16b9,
+ 0x7729, 0x16b6,
+ 0x7737, 0x16bc,
+ 0x773a, 0x0bcb,
+ 0x773c, 0x061f,
+ 0x7740, 0x0ba3,
+ 0x7746, 0x217c,
+ 0x7747, 0x16be,
+ 0x775a, 0x16bf,
+ 0x775b, 0x16c2,
+ 0x7761, 0x0a2d,
+ 0x7762, 0x1ec5,
+ 0x7763, 0x0c9c,
+ 0x7765, 0x16c3,
+ 0x7766, 0x0e81,
+ 0x7768, 0x16c0,
+ 0x776b, 0x16c1,
+ 0x7779, 0x16c6,
+ 0x777e, 0x16c5,
+ 0x777f, 0x16c4,
+ 0x778b, 0x16c8,
+ 0x778e, 0x16c7,
+ 0x7791, 0x16c9,
+ 0x779e, 0x16cb,
+ 0x77a0, 0x16ca,
+ 0x77a5, 0x0e1d,
+ 0x77ac, 0x0960,
+ 0x77ad, 0x0f8e,
+ 0x77b0, 0x16cc,
+ 0x77b3, 0x0c8f,
+ 0x77b6, 0x16cd,
+ 0x77b9, 0x16ce,
+ 0x77bb, 0x16d2,
+ 0x77bc, 0x16d0,
+ 0x77bf, 0x16cf,
+ 0x77c7, 0x16d3,
+ 0x77cd, 0x16d4,
+ 0x77d7, 0x16d5,
+ 0x77da, 0x16d6,
+ 0x77db, 0x0ec3,
+ 0x77dc, 0x16d7,
+ 0x77e2, 0x0efc,
+ 0x77e3, 0x16d8,
+ 0x77e5, 0x0b8c,
+ 0x77e7, 0x0d20,
+ 0x77e9, 0x06e3,
+ 0x77ed, 0x0b79,
+ 0x77ee, 0x16d9,
+ 0x77ef, 0x06b2,
+ 0x77f3, 0x0a74,
+ 0x77fc, 0x16da,
+ 0x7802, 0x082d,
+ 0x780c, 0x16db,
+ 0x7812, 0x16dc,
+ 0x7814, 0x075a,
+ 0x7815, 0x0845,
+ 0x7820, 0x16de,
+ 0x7821, 0x217e,
+ 0x7825, 0x0c50,
+ 0x7826, 0x0846,
+ 0x7827, 0x0668,
+ 0x7832, 0x0e52,
+ 0x7834, 0x0d01,
+ 0x783a, 0x0c51,
+ 0x783f, 0x07ee,
+ 0x7845, 0x16e0,
+ 0x784e, 0x217f,
+ 0x785d, 0x09b3,
+ 0x7864, 0x2180,
+ 0x786b, 0x0f7a,
+ 0x786c, 0x07d7,
+ 0x786f, 0x075b,
+ 0x7872, 0x0d37,
+ 0x7874, 0x16e2,
+ 0x787a, 0x2181,
+ 0x787c, 0x16e4,
+ 0x7881, 0x079f,
+ 0x7886, 0x16e3,
+ 0x7887, 0x0c12,
+ 0x788c, 0x16e6,
+ 0x788d, 0x0595,
+ 0x788e, 0x16e1,
+ 0x7891, 0x0d7e,
+ 0x7893, 0x04d2,
+ 0x7895, 0x085c,
+ 0x7897, 0x0ff8,
+ 0x789a, 0x16e5,
+ 0x78a3, 0x16e7,
+ 0x78a7, 0x0e1b,
+ 0x78a9, 0x0a7d,
+ 0x78aa, 0x16e9,
+ 0x78af, 0x16ea,
+ 0x78b5, 0x16e8,
+ 0x78ba, 0x05ac,
+ 0x78bc, 0x16f0,
+ 0x78be, 0x16ef,
+ 0x78c1, 0x08d3,
+ 0x78c5, 0x16f1,
+ 0x78c6, 0x16ec,
+ 0x78ca, 0x16f2,
+ 0x78cb, 0x16ed,
+ 0x78d0, 0x0d6c,
+ 0x78d1, 0x16eb,
+ 0x78d4, 0x16ee,
+ 0x78da, 0x16f5,
+ 0x78e7, 0x16f4,
+ 0x78e8, 0x0e8f,
+ 0x78ec, 0x16f3,
+ 0x78ef, 0x04af,
+ 0x78f4, 0x16f7,
+ 0x78fd, 0x16f6,
+ 0x7901, 0x09b4,
+ 0x7907, 0x16f8,
+ 0x790e, 0x0ac5,
+ 0x7911, 0x16fa,
+ 0x7912, 0x16f9,
+ 0x7919, 0x16fb,
+ 0x7926, 0x16dd,
+ 0x792a, 0x16df,
+ 0x792b, 0x16fd,
+ 0x792c, 0x16fc,
+ 0x7930, 0x2182,
+ 0x793a, 0x08d4,
+ 0x793c, 0x0fb1,
+ 0x793e, 0x08fe,
+ 0x7940, 0x16fe,
+ 0x7941, 0x070d,
+ 0x7947, 0x065a,
+ 0x7948, 0x0641,
+ 0x7949, 0x08b1,
+ 0x7950, 0x0f1e,
+ 0x7953, 0x1704,
+ 0x7955, 0x1703,
+ 0x7956, 0x0ac6,
+ 0x7957, 0x1700,
+ 0x795a, 0x1702,
+ 0x795d, 0x0955,
+ 0x795e, 0x0a06,
+ 0x795f, 0x1701,
+ 0x7960, 0x16ff,
+ 0x7962, 0x0ce0,
+ 0x7965, 0x09b5,
+ 0x7968, 0x0dae,
+ 0x796d, 0x0847,
+ 0x7977, 0x0c72,
+ 0x797a, 0x1705,
+ 0x797f, 0x1706,
+ 0x7980, 0x171c,
+ 0x7981, 0x06d0,
+ 0x7984, 0x0fe3,
+ 0x7985, 0x0ab7,
+ 0x798a, 0x1707,
+ 0x798d, 0x0552,
+ 0x798e, 0x0c13,
+ 0x798f, 0x0df1,
+ 0x7994, 0x2186,
+ 0x799b, 0x2188,
+ 0x799d, 0x1708,
+ 0x79a6, 0x0694,
+ 0x79a7, 0x1709,
+ 0x79aa, 0x170b,
+ 0x79ae, 0x170c,
+ 0x79b0, 0x0cdf,
+ 0x79b1, 0x1e4e,
+ 0x79b3, 0x170d,
+ 0x79b9, 0x170e,
+ 0x79bd, 0x06d1,
+ 0x79be, 0x0553,
+ 0x79bf, 0x0c9d,
+ 0x79c0, 0x0932,
+ 0x79c1, 0x08b2,
+ 0x79c9, 0x1710,
+ 0x79cb, 0x0933,
+ 0x79d1, 0x054a,
+ 0x79d2, 0x0db5,
+ 0x79d5, 0x1711,
+ 0x79d8, 0x0d7f,
+ 0x79df, 0x0ac7,
+ 0x79e1, 0x1714,
+ 0x79e3, 0x1715,
+ 0x79e4, 0x0d1f,
+ 0x79e6, 0x0a07,
+ 0x79e7, 0x1712,
+ 0x79e9, 0x0b9f,
+ 0x79ec, 0x1713,
+ 0x79f0, 0x09b6,
+ 0x79fb, 0x04a0,
+ 0x7a00, 0x0643,
+ 0x7a08, 0x1716,
+ 0x7a0b, 0x0c14,
+ 0x7a0d, 0x1717,
+ 0x7a0e, 0x0a6b,
+ 0x7a14, 0x0eb9,
+ 0x7a17, 0x0d95,
+ 0x7a18, 0x1718,
+ 0x7a1a, 0x0b93,
+ 0x7a1c, 0x0f8f,
+ 0x7a1f, 0x171b,
+ 0x7a20, 0x171a,
+ 0x7a2e, 0x091b,
+ 0x7a31, 0x171d,
+ 0x7a32, 0x04b4,
+ 0x7a37, 0x1720,
+ 0x7a3b, 0x171e,
+ 0x7a3c, 0x0554,
+ 0x7a3d, 0x0724,
+ 0x7a3e, 0x171f,
+ 0x7a3f, 0x07d8,
+ 0x7a40, 0x0804,
+ 0x7a42, 0x0e36,
+ 0x7a43, 0x1721,
+ 0x7a46, 0x0e82,
+ 0x7a49, 0x1723,
+ 0x7a4d, 0x0a75,
+ 0x7a4e, 0x04f1,
+ 0x7a4f, 0x053a,
+ 0x7a50, 0x0470,
+ 0x7a57, 0x1722,
+ 0x7a61, 0x1724,
+ 0x7a63, 0x09df,
+ 0x7a69, 0x1726,
+ 0x7a6b, 0x05ad,
+ 0x7a70, 0x1728,
+ 0x7a74, 0x0740,
+ 0x7a76, 0x0680,
+ 0x7a79, 0x1729,
+ 0x7a7a, 0x06ed,
+ 0x7a7d, 0x172a,
+ 0x7a7f, 0x0aa0,
+ 0x7a81, 0x0ca5,
+ 0x7a83, 0x0a84,
+ 0x7a84, 0x0865,
+ 0x7a88, 0x172b,
+ 0x7a92, 0x0ba0,
+ 0x7a93, 0x0aed,
+ 0x7a95, 0x172d,
+ 0x7a96, 0x172f,
+ 0x7a97, 0x172c,
+ 0x7a98, 0x172e,
+ 0x7a9f, 0x06f8,
+ 0x7aa9, 0x1730,
+ 0x7aaa, 0x06fc,
+ 0x7aae, 0x0681,
+ 0x7aaf, 0x0f3c,
+ 0x7ab0, 0x1732,
+ 0x7ab6, 0x1733,
+ 0x7aba, 0x04d0,
+ 0x7abf, 0x1736,
+ 0x7ac3, 0x05d4,
+ 0x7ac4, 0x1735,
+ 0x7ac5, 0x1734,
+ 0x7ac7, 0x1738,
+ 0x7ac8, 0x1731,
+ 0x7aca, 0x1739,
+ 0x7acb, 0x0f71,
+ 0x7acd, 0x173a,
+ 0x7acf, 0x173b,
+ 0x7ad1, 0x2189,
+ 0x7ad2, 0x11c5,
+ 0x7ad3, 0x173d,
+ 0x7ad5, 0x173c,
+ 0x7ad9, 0x173e,
+ 0x7adc, 0x0f7d,
+ 0x7add, 0x1740,
+ 0x7adf, 0x1c08,
+ 0x7ae0, 0x09b7,
+ 0x7ae1, 0x1741,
+ 0x7ae3, 0x0961,
+ 0x7ae5, 0x0c90,
+ 0x7ae6, 0x1743,
+ 0x7ae7, 0x218a,
+ 0x7aea, 0x0b66,
+ 0x7aeb, 0x218c,
+ 0x7aed, 0x1744,
+ 0x7aef, 0x0b7a,
+ 0x7af0, 0x1745,
+ 0x7af6, 0x069d,
+ 0x7af8, 0x1076,
+ 0x7af9, 0x0b9b,
+ 0x7afa, 0x08df,
+ 0x7aff, 0x0604,
+ 0x7b02, 0x1746,
+ 0x7b04, 0x1753,
+ 0x7b06, 0x1749,
+ 0x7b08, 0x0682,
+ 0x7b0a, 0x1748,
+ 0x7b0b, 0x1755,
+ 0x7b0f, 0x1747,
+ 0x7b11, 0x09b8,
+ 0x7b18, 0x174b,
+ 0x7b1b, 0x0c25,
+ 0x7b1e, 0x174d,
+ 0x7b20, 0x05bc,
+ 0x7b25, 0x0a20,
+ 0x7b26, 0x0dd6,
+ 0x7b28, 0x174f,
+ 0x7b2c, 0x0b48,
+ 0x7b33, 0x174a,
+ 0x7b35, 0x174e,
+ 0x7b36, 0x1750,
+ 0x7b39, 0x086b,
+ 0x7b45, 0x1757,
+ 0x7b46, 0x0da0,
+ 0x7b48, 0x0d3a,
+ 0x7b49, 0x0c73,
+ 0x7b4b, 0x06d2,
+ 0x7b4c, 0x1756,
+ 0x7b4d, 0x1754,
+ 0x7b4f, 0x0d49,
+ 0x7b50, 0x1751,
+ 0x7b51, 0x0b9c,
+ 0x7b52, 0x0c75,
+ 0x7b54, 0x0c74,
+ 0x7b56, 0x0866,
+ 0x7b5d, 0x1769,
+ 0x7b65, 0x1759,
+ 0x7b67, 0x175b,
+ 0x7b6c, 0x175e,
+ 0x7b6e, 0x175f,
+ 0x7b70, 0x175c,
+ 0x7b74, 0x175a,
+ 0x7b75, 0x1758,
+ 0x7b7a, 0x1752,
+ 0x7b86, 0x0e1f,
+ 0x7b87, 0x0555,
+ 0x7b8b, 0x1766,
+ 0x7b8d, 0x1763,
+ 0x7b8f, 0x1768,
+ 0x7b92, 0x1767,
+ 0x7b94, 0x0d29,
+ 0x7b95, 0x0eb3,
+ 0x7b97, 0x0889,
+ 0x7b98, 0x1761,
+ 0x7b99, 0x176a,
+ 0x7b9a, 0x1765,
+ 0x7b9c, 0x1764,
+ 0x7b9d, 0x1760,
+ 0x7b9e, 0x218d,
+ 0x7b9f, 0x1762,
+ 0x7ba1, 0x0605,
+ 0x7baa, 0x0b7b,
+ 0x7bad, 0x0aa1,
+ 0x7bb1, 0x0d36,
+ 0x7bb4, 0x176f,
+ 0x7bb8, 0x0d38,
+ 0x7bc0, 0x0a85,
+ 0x7bc1, 0x176c,
+ 0x7bc4, 0x0d63,
+ 0x7bc6, 0x1770,
+ 0x7bc7, 0x0e23,
+ 0x7bc9, 0x0b99,
+ 0x7bcb, 0x176b,
+ 0x7bcc, 0x176d,
+ 0x7bcf, 0x176e,
+ 0x7bdd, 0x1771,
+ 0x7be0, 0x08f0,
+ 0x7be4, 0x0c9e,
+ 0x7be5, 0x1776,
+ 0x7be6, 0x1775,
+ 0x7be9, 0x1772,
+ 0x7bed, 0x0fdc,
+ 0x7bf3, 0x177b,
+ 0x7bf6, 0x177f,
+ 0x7bf7, 0x177c,
+ 0x7c00, 0x1778,
+ 0x7c07, 0x1779,
+ 0x7c0d, 0x177e,
+ 0x7c11, 0x1773,
+ 0x7c12, 0x10ea,
+ 0x7c13, 0x177a,
+ 0x7c14, 0x1774,
+ 0x7c17, 0x177d,
+ 0x7c1e, 0x1e3b,
+ 0x7c1f, 0x1783,
+ 0x7c21, 0x0606,
+ 0x7c23, 0x1780,
+ 0x7c27, 0x1781,
+ 0x7c2a, 0x1782,
+ 0x7c2b, 0x1785,
+ 0x7c37, 0x1784,
+ 0x7c38, 0x0d8a,
+ 0x7c3d, 0x1786,
+ 0x7c3e, 0x0fc4,
+ 0x7c3f, 0x0e3d,
+ 0x7c40, 0x178b,
+ 0x7c43, 0x1788,
+ 0x7c4c, 0x1787,
+ 0x7c4d, 0x0a76,
+ 0x7c4f, 0x178a,
+ 0x7c50, 0x178c,
+ 0x7c54, 0x1789,
+ 0x7c56, 0x1790,
+ 0x7c58, 0x178d,
+ 0x7c5f, 0x178e,
+ 0x7c60, 0x1777,
+ 0x7c64, 0x178f,
+ 0x7c65, 0x1791,
+ 0x7c6c, 0x1792,
+ 0x7c73, 0x0e16,
+ 0x7c75, 0x1793,
+ 0x7c7e, 0x0eee,
+ 0x7c81, 0x06c6,
+ 0x7c82, 0x06ff,
+ 0x7c83, 0x1794,
+ 0x7c89, 0x0e04,
+ 0x7c8b, 0x0a2e,
+ 0x7c8d, 0x0ebc,
+ 0x7c90, 0x1795,
+ 0x7c92, 0x0f7b,
+ 0x7c95, 0x0d2a,
+ 0x7c97, 0x0ac8,
+ 0x7c98, 0x0cea,
+ 0x7c9b, 0x0957,
+ 0x7c9f, 0x0484,
+ 0x7ca1, 0x179a,
+ 0x7ca2, 0x1798,
+ 0x7ca4, 0x1796,
+ 0x7ca5, 0x05dd,
+ 0x7ca7, 0x09b9,
+ 0x7ca8, 0x179b,
+ 0x7cab, 0x1799,
+ 0x7cad, 0x1797,
+ 0x7cae, 0x179f,
+ 0x7cb1, 0x179e,
+ 0x7cb2, 0x179d,
+ 0x7cb3, 0x179c,
+ 0x7cb9, 0x17a0,
+ 0x7cbd, 0x17a1,
+ 0x7cbe, 0x0a5e,
+ 0x7cc0, 0x17a2,
+ 0x7cc2, 0x17a4,
+ 0x7cc5, 0x17a3,
+ 0x7cca, 0x0786,
+ 0x7cce, 0x0aba,
+ 0x7cd2, 0x17a6,
+ 0x7cd6, 0x0c76,
+ 0x7cd8, 0x17a5,
+ 0x7cdc, 0x17a7,
+ 0x7cde, 0x0e05,
+ 0x7cdf, 0x0aee,
+ 0x7ce0, 0x07d9,
+ 0x7ce2, 0x17a8,
+ 0x7ce7, 0x0f90,
+ 0x7cef, 0x17aa,
+ 0x7cf2, 0x17ab,
+ 0x7cf4, 0x17ac,
+ 0x7cf6, 0x17ad,
+ 0x7cf8, 0x08b3,
+ 0x7cfa, 0x17ae,
+ 0x7cfb, 0x0725,
+ 0x7cfe, 0x0684,
+ 0x7d00, 0x0644,
+ 0x7d02, 0x17b0,
+ 0x7d04, 0x0eff,
+ 0x7d05, 0x07da,
+ 0x7d06, 0x17af,
+ 0x7d0a, 0x17b3,
+ 0x7d0b, 0x0ef2,
+ 0x7d0d, 0x0cf2,
+ 0x7d10, 0x0da5,
+ 0x7d14, 0x096d,
+ 0x7d15, 0x17b2,
+ 0x7d17, 0x08ff,
+ 0x7d18, 0x07db,
+ 0x7d19, 0x08b4,
+ 0x7d1a, 0x0683,
+ 0x7d1b, 0x0e06,
+ 0x7d1c, 0x17b1,
+ 0x7d20, 0x0ac9,
+ 0x7d21, 0x0e70,
+ 0x7d22, 0x0867,
+ 0x7d2b, 0x08b5,
+ 0x7d2c, 0x0bf9,
+ 0x7d2e, 0x17b6,
+ 0x7d2f, 0x0fa7,
+ 0x7d30, 0x0849,
+ 0x7d32, 0x17b7,
+ 0x7d33, 0x0a08,
+ 0x7d35, 0x17b9,
+ 0x7d39, 0x09ba,
+ 0x7d3a, 0x0820,
+ 0x7d3f, 0x17b8,
+ 0x7d42, 0x0934,
+ 0x7d43, 0x0772,
+ 0x7d44, 0x0aca,
+ 0x7d45, 0x17b4,
+ 0x7d46, 0x17ba,
+ 0x7d48, 0x218f,
+ 0x7d4b, 0x17b5,
+ 0x7d4c, 0x0726,
+ 0x7d4e, 0x17bd,
+ 0x7d4f, 0x17c1,
+ 0x7d50, 0x0741,
+ 0x7d56, 0x17bc,
+ 0x7d5b, 0x17c5,
+ 0x7d5c, 0x2190,
+ 0x7d5e, 0x07dc,
+ 0x7d61, 0x0f57,
+ 0x7d62, 0x0480,
+ 0x7d63, 0x17c2,
+ 0x7d66, 0x0685,
+ 0x7d68, 0x17bf,
+ 0x7d6e, 0x17c0,
+ 0x7d71, 0x0c77,
+ 0x7d72, 0x17be,
+ 0x7d73, 0x17bb,
+ 0x7d75, 0x0586,
+ 0x7d76, 0x0a88,
+ 0x7d79, 0x075c,
+ 0x7d7d, 0x17c7,
+ 0x7d89, 0x17c4,
+ 0x7d8f, 0x17c6,
+ 0x7d93, 0x17c3,
+ 0x7d99, 0x0727,
+ 0x7d9a, 0x0b13,
+ 0x7d9b, 0x17c8,
+ 0x7d9c, 0x0af0,
+ 0x7d9f, 0x17d5,
+ 0x7da0, 0x2192,
+ 0x7da2, 0x17d1,
+ 0x7da3, 0x17cb,
+ 0x7dab, 0x17cf,
+ 0x7dac, 0x0926,
+ 0x7dad, 0x04a1,
+ 0x7dae, 0x17ca,
+ 0x7daf, 0x17d2,
+ 0x7db0, 0x17d6,
+ 0x7db1, 0x07dd,
+ 0x7db2, 0x0ee2,
+ 0x7db4, 0x0bf2,
+ 0x7db5, 0x17cc,
+ 0x7db7, 0x2191,
+ 0x7db8, 0x17d4,
+ 0x7dba, 0x17c9,
+ 0x7dbb, 0x0b7c,
+ 0x7dbd, 0x17ce,
+ 0x7dbe, 0x0481,
+ 0x7dbf, 0x0ed6,
+ 0x7dc7, 0x17cd,
+ 0x7dca, 0x06d3,
+ 0x7dcb, 0x0d80,
+ 0x7dcf, 0x0aef,
+ 0x7dd1, 0x0f98,
+ 0x7dd2, 0x0979,
+ 0x7dd5, 0x17fd,
+ 0x7dd6, 0x2193,
+ 0x7dd8, 0x17d7,
+ 0x7dda, 0x0aa2,
+ 0x7ddc, 0x17d3,
+ 0x7ddd, 0x17d8,
+ 0x7dde, 0x17da,
+ 0x7de0, 0x0c15,
+ 0x7de1, 0x17dd,
+ 0x7de4, 0x17d9,
+ 0x7de8, 0x0e24,
+ 0x7de9, 0x0607,
+ 0x7dec, 0x0ed7,
+ 0x7def, 0x04a2,
+ 0x7df2, 0x17dc,
+ 0x7df4, 0x0fc5,
+ 0x7dfb, 0x17db,
+ 0x7e01, 0x0511,
+ 0x7e04, 0x0cc4,
+ 0x7e05, 0x17de,
+ 0x7e09, 0x17e5,
+ 0x7e0a, 0x17df,
+ 0x7e0b, 0x17e6,
+ 0x7e12, 0x17e2,
+ 0x7e1b, 0x0d31,
+ 0x7e1e, 0x08f6,
+ 0x7e1f, 0x17e4,
+ 0x7e21, 0x17e1,
+ 0x7e22, 0x17e7,
+ 0x7e23, 0x17e0,
+ 0x7e26, 0x094e,
+ 0x7e2b, 0x0e53,
+ 0x7e2e, 0x0956,
+ 0x7e31, 0x17e3,
+ 0x7e32, 0x17ef,
+ 0x7e35, 0x17eb,
+ 0x7e37, 0x17ee,
+ 0x7e39, 0x17ec,
+ 0x7e3a, 0x17f0,
+ 0x7e3b, 0x17ea,
+ 0x7e3d, 0x17d0,
+ 0x7e3e, 0x0a77,
+ 0x7e41, 0x0d5f,
+ 0x7e43, 0x17ed,
+ 0x7e46, 0x17e8,
+ 0x7e4a, 0x0aa3,
+ 0x7e4b, 0x0728,
+ 0x7e4d, 0x0935,
+ 0x7e52, 0x2194,
+ 0x7e54, 0x09eb,
+ 0x7e55, 0x0ab8,
+ 0x7e56, 0x17f3,
+ 0x7e59, 0x17f5,
+ 0x7e5d, 0x17f2,
+ 0x7e5e, 0x17f4,
+ 0x7e61, 0x1e11,
+ 0x7e66, 0x17e9,
+ 0x7e67, 0x17f1,
+ 0x7e69, 0x17f9,
+ 0x7e6a, 0x17f8,
+ 0x7e6b, 0x1df7,
+ 0x7e6d, 0x0ea8,
+ 0x7e70, 0x0701,
+ 0x7e79, 0x17f7,
+ 0x7e7b, 0x17fb,
+ 0x7e7c, 0x17fa,
+ 0x7e7d, 0x17fe,
+ 0x7e7f, 0x1800,
+ 0x7e82, 0x088a,
+ 0x7e83, 0x17fc,
+ 0x7e88, 0x1801,
+ 0x7e8a, 0x20a7,
+ 0x7e8c, 0x1803,
+ 0x7e8e, 0x1809,
+ 0x7e8f, 0x0c35,
+ 0x7e90, 0x1805,
+ 0x7e92, 0x1804,
+ 0x7e93, 0x1806,
+ 0x7e96, 0x1808,
+ 0x7e9b, 0x180a,
+ 0x7f36, 0x0608,
+ 0x7f38, 0x180c,
+ 0x7f3a, 0x180d,
+ 0x7f45, 0x180e,
+ 0x7f47, 0x2195,
+ 0x7f4c, 0x180f,
+ 0x7f50, 0x1812,
+ 0x7f54, 0x1815,
+ 0x7f55, 0x1814,
+ 0x7f58, 0x1816,
+ 0x7f5f, 0x1817,
+ 0x7f67, 0x181b,
+ 0x7f68, 0x1819,
+ 0x7f6a, 0x0851,
+ 0x7f6b, 0x0729,
+ 0x7f6e, 0x0b94,
+ 0x7f70, 0x0d47,
+ 0x7f72, 0x097a,
+ 0x7f75, 0x0d03,
+ 0x7f77, 0x0d81,
+ 0x7f78, 0x181c,
+ 0x7f79, 0x1336,
+ 0x7f82, 0x181d,
+ 0x7f83, 0x181f,
+ 0x7f85, 0x0f4f,
+ 0x7f86, 0x181e,
+ 0x7f87, 0x1821,
+ 0x7f88, 0x1820,
+ 0x7f8a, 0x0f3d,
+ 0x7f8c, 0x1822,
+ 0x7f8e, 0x0d92,
+ 0x7f94, 0x1823,
+ 0x7f9a, 0x1826,
+ 0x7f9d, 0x1825,
+ 0x7f9e, 0x1824,
+ 0x7fa1, 0x2196,
+ 0x7fa3, 0x1827,
+ 0x7fa4, 0x0708,
+ 0x7fa8, 0x0aa4,
+ 0x7fa9, 0x065b,
+ 0x7fae, 0x182b,
+ 0x7faf, 0x1828,
+ 0x7fb2, 0x1829,
+ 0x7fb6, 0x182c,
+ 0x7fb8, 0x182d,
+ 0x7fb9, 0x182a,
+ 0x7fbd, 0x04cb,
+ 0x7fc1, 0x0527,
+ 0x7fc5, 0x182f,
+ 0x7fca, 0x1831,
+ 0x7fcc, 0x0f4c,
+ 0x7fd2, 0x0936,
+ 0x7fd4, 0x1833,
+ 0x7fd5, 0x1832,
+ 0x7fe0, 0x0a2f,
+ 0x7fe1, 0x1834,
+ 0x7fe6, 0x1835,
+ 0x7fe9, 0x1836,
+ 0x7feb, 0x0621,
+ 0x7ff0, 0x0609,
+ 0x7ff3, 0x1837,
+ 0x7ff9, 0x1838,
+ 0x7ffb, 0x0e8b,
+ 0x7ffc, 0x0f4d,
+ 0x8000, 0x0f3e,
+ 0x8001, 0x0fdd,
+ 0x8003, 0x07df,
+ 0x8004, 0x183b,
+ 0x8005, 0x0900,
+ 0x8006, 0x183a,
+ 0x800b, 0x183c,
+ 0x800c, 0x08d5,
+ 0x8010, 0x0b31,
+ 0x8012, 0x183d,
+ 0x8015, 0x07de,
+ 0x8017, 0x0ee3,
+ 0x8018, 0x183e,
+ 0x801c, 0x1840,
+ 0x8021, 0x1841,
+ 0x8028, 0x1842,
+ 0x8033, 0x08d6,
+ 0x8036, 0x0ef9,
+ 0x803b, 0x1844,
+ 0x803d, 0x0b7d,
+ 0x803f, 0x1843,
+ 0x8046, 0x1846,
+ 0x804a, 0x1845,
+ 0x8052, 0x1847,
+ 0x8056, 0x0a5f,
+ 0x8058, 0x1848,
+ 0x805a, 0x1849,
+ 0x805e, 0x0e09,
+ 0x805f, 0x184a,
+ 0x8061, 0x0af1,
+ 0x8062, 0x184b,
+ 0x8068, 0x184c,
+ 0x806f, 0x0fc6,
+ 0x8070, 0x184f,
+ 0x8072, 0x184e,
+ 0x8073, 0x184d,
+ 0x8074, 0x0bcc,
+ 0x8076, 0x1850,
+ 0x8077, 0x09ec,
+ 0x8079, 0x1851,
+ 0x807d, 0x1852,
+ 0x807e, 0x0fde,
+ 0x807f, 0x1853,
+ 0x8084, 0x1854,
+ 0x8085, 0x1856,
+ 0x8086, 0x1855,
+ 0x8087, 0x0d39,
+ 0x8089, 0x0cd1,
+ 0x808b, 0x0fe4,
+ 0x808c, 0x0d3d,
+ 0x8093, 0x1858,
+ 0x8096, 0x09bb,
+ 0x8098, 0x0d9c,
+ 0x809a, 0x1859,
+ 0x809b, 0x1857,
+ 0x809d, 0x060a,
+ 0x80a1, 0x0788,
+ 0x80a2, 0x08b6,
+ 0x80a5, 0x0d82,
+ 0x80a9, 0x075e,
+ 0x80aa, 0x0e71,
+ 0x80ac, 0x185c,
+ 0x80ad, 0x185a,
+ 0x80af, 0x07e0,
+ 0x80b1, 0x07e1,
+ 0x80b2, 0x04ad,
+ 0x80b4, 0x0858,
+ 0x80ba, 0x0d0f,
+ 0x80c3, 0x04a3,
+ 0x80c4, 0x1861,
+ 0x80c6, 0x0b7e,
+ 0x80cc, 0x0d0e,
+ 0x80ce, 0x0b3b,
+ 0x80d6, 0x1863,
+ 0x80d9, 0x185f,
+ 0x80da, 0x1862,
+ 0x80db, 0x185d,
+ 0x80dd, 0x1860,
+ 0x80de, 0x0e54,
+ 0x80e1, 0x0789,
+ 0x80e4, 0x04c1,
+ 0x80e5, 0x185e,
+ 0x80ef, 0x1865,
+ 0x80f1, 0x1866,
+ 0x80f4, 0x0c91,
+ 0x80f8, 0x06b3,
+ 0x80fc, 0x1871,
+ 0x80fd, 0x0cf3,
+ 0x8102, 0x08b7,
+ 0x8105, 0x06b4,
+ 0x8106, 0x0a6c,
+ 0x8107, 0x0fec,
+ 0x8108, 0x0eba,
+ 0x8109, 0x1864,
+ 0x810a, 0x0a78,
+ 0x811a, 0x066d,
+ 0x811b, 0x1867,
+ 0x8123, 0x1869,
+ 0x8129, 0x1868,
+ 0x812f, 0x186a,
+ 0x8131, 0x0b64,
+ 0x8133, 0x0cf4,
+ 0x8139, 0x0bcd,
+ 0x813e, 0x186e,
+ 0x8146, 0x186d,
+ 0x814b, 0x186b,
+ 0x814e, 0x0a1b,
+ 0x8150, 0x0dd7,
+ 0x8151, 0x1870,
+ 0x8153, 0x186f,
+ 0x8154, 0x07e2,
+ 0x8155, 0x0ff9,
+ 0x815f, 0x1880,
+ 0x8165, 0x1874,
+ 0x816b, 0x091c,
+ 0x816e, 0x1873,
+ 0x8170, 0x080a,
+ 0x8171, 0x1872,
+ 0x8174, 0x1876,
+ 0x8178, 0x0bce,
+ 0x8179, 0x0df2,
+ 0x817a, 0x0aa5,
+ 0x817f, 0x0b3c,
+ 0x8180, 0x187a,
+ 0x8182, 0x187b,
+ 0x8183, 0x1877,
+ 0x8188, 0x1878,
+ 0x818a, 0x1879,
+ 0x818f, 0x07e3,
+ 0x8193, 0x1881,
+ 0x8195, 0x187d,
+ 0x819a, 0x0dd8,
+ 0x819c, 0x0e9a,
+ 0x819d, 0x0d9a,
+ 0x81a0, 0x187c,
+ 0x81a3, 0x187f,
+ 0x81a4, 0x187e,
+ 0x81a8, 0x0e72,
+ 0x81a9, 0x1882,
+ 0x81b0, 0x1883,
+ 0x81b3, 0x0ab9,
+ 0x81b5, 0x1884,
+ 0x81b8, 0x1886,
+ 0x81ba, 0x188a,
+ 0x81bd, 0x1887,
+ 0x81be, 0x1885,
+ 0x81bf, 0x0cf5,
+ 0x81c0, 0x1888,
+ 0x81c2, 0x1889,
+ 0x81c6, 0x0532,
+ 0x81c8, 0x1890,
+ 0x81c9, 0x188b,
+ 0x81cd, 0x188c,
+ 0x81d1, 0x188d,
+ 0x81d3, 0x0b01,
+ 0x81d8, 0x188f,
+ 0x81d9, 0x188e,
+ 0x81da, 0x1891,
+ 0x81df, 0x1892,
+ 0x81e3, 0x0a09,
+ 0x81e5, 0x0569,
+ 0x81e7, 0x1894,
+ 0x81e8, 0x0f9f,
+ 0x81ea, 0x08d7,
+ 0x81ed, 0x0937,
+ 0x81f3, 0x08b8,
+ 0x81f4, 0x0b95,
+ 0x81fa, 0x1895,
+ 0x81fc, 0x04d3,
+ 0x81fe, 0x1897,
+ 0x8201, 0x1898,
+ 0x8205, 0x189a,
+ 0x8207, 0x189b,
+ 0x8208, 0x06b5,
+ 0x8209, 0x13af,
+ 0x820a, 0x189c,
+ 0x820c, 0x0a89,
+ 0x820d, 0x189d,
+ 0x820e, 0x08f7,
+ 0x8210, 0x189e,
+ 0x8212, 0x1009,
+ 0x8216, 0x189f,
+ 0x8217, 0x0e2e,
+ 0x8218, 0x0618,
+ 0x821b, 0x0aa6,
+ 0x821c, 0x0962,
+ 0x821e, 0x0de3,
+ 0x821f, 0x0938,
+ 0x8229, 0x18a0,
+ 0x822a, 0x07e4,
+ 0x822b, 0x18a1,
+ 0x822c, 0x0d60,
+ 0x822e, 0x18af,
+ 0x8233, 0x18a3,
+ 0x8235, 0x0b29,
+ 0x8236, 0x0d2b,
+ 0x8237, 0x0773,
+ 0x8238, 0x18a2,
+ 0x8239, 0x0aa7,
+ 0x8240, 0x18a4,
+ 0x8247, 0x0c16,
+ 0x8258, 0x18a6,
+ 0x8259, 0x18a5,
+ 0x825a, 0x18a8,
+ 0x825d, 0x18a7,
+ 0x825f, 0x18a9,
+ 0x8262, 0x18ab,
+ 0x8264, 0x18aa,
+ 0x8266, 0x060b,
+ 0x8268, 0x18ac,
+ 0x826a, 0x18ad,
+ 0x826e, 0x0821,
+ 0x826f, 0x0f91,
+ 0x8271, 0x18b0,
+ 0x8272, 0x09ed,
+ 0x8276, 0x0512,
+ 0x8277, 0x18b1,
+ 0x827e, 0x18b3,
+ 0x828b, 0x04b6,
+ 0x828d, 0x18b4,
+ 0x8292, 0x18b5,
+ 0x8299, 0x0dd9,
+ 0x829d, 0x08f3,
+ 0x829f, 0x18b7,
+ 0x82a5, 0x0587,
+ 0x82a6, 0x0476,
+ 0x82ab, 0x18b6,
+ 0x82ac, 0x18b9,
+ 0x82ad, 0x0d04,
+ 0x82af, 0x0a0a,
+ 0x82b1, 0x0556,
+ 0x82b3, 0x0e55,
+ 0x82b8, 0x0733,
+ 0x82b9, 0x06d4,
+ 0x82bb, 0x18b8,
+ 0x82bd, 0x056a,
+ 0x82c5, 0x05df,
+ 0x82d1, 0x0513,
+ 0x82d2, 0x18bd,
+ 0x82d3, 0x0fb2,
+ 0x82d4, 0x0b3d,
+ 0x82d7, 0x0db6,
+ 0x82d9, 0x18c9,
+ 0x82db, 0x0557,
+ 0x82dc, 0x18c7,
+ 0x82de, 0x18c5,
+ 0x82df, 0x18bc,
+ 0x82e1, 0x18ba,
+ 0x82e3, 0x18bb,
+ 0x82e5, 0x090f,
+ 0x82e6, 0x06e4,
+ 0x82e7, 0x0bb5,
+ 0x82eb, 0x0ca9,
+ 0x82f1, 0x04f3,
+ 0x82f3, 0x18bf,
+ 0x82f4, 0x18be,
+ 0x82f9, 0x18c4,
+ 0x82fa, 0x18c0,
+ 0x82fb, 0x18c3,
+ 0x8301, 0x2198,
+ 0x8302, 0x0edc,
+ 0x8303, 0x18c2,
+ 0x8304, 0x0558,
+ 0x8305, 0x05db,
+ 0x8306, 0x18c6,
+ 0x8309, 0x18c8,
+ 0x830e, 0x072a,
+ 0x8316, 0x18cc,
+ 0x8317, 0x18d5,
+ 0x831c, 0x046f,
+ 0x8323, 0x18dd,
+ 0x8328, 0x04b5,
+ 0x832b, 0x18d4,
+ 0x832f, 0x18d3,
+ 0x8331, 0x18ce,
+ 0x8332, 0x18cd,
+ 0x8334, 0x18cb,
+ 0x8335, 0x18ca,
+ 0x8336, 0x0ba1,
+ 0x8338, 0x0b5b,
+ 0x8339, 0x18d0,
+ 0x8340, 0x18cf,
+ 0x8345, 0x18d2,
+ 0x8349, 0x0af2,
+ 0x834a, 0x072b,
+ 0x834f, 0x04e3,
+ 0x8350, 0x18d1,
+ 0x8352, 0x07e5,
+ 0x8358, 0x0af3,
+ 0x8362, 0x2199,
+ 0x8373, 0x18e3,
+ 0x8375, 0x18e4,
+ 0x8377, 0x0559,
+ 0x837b, 0x052e,
+ 0x837c, 0x18e1,
+ 0x837f, 0x219a,
+ 0x8385, 0x18d7,
+ 0x8387, 0x18df,
+ 0x8389, 0x18e6,
+ 0x838a, 0x18e0,
+ 0x838e, 0x18de,
+ 0x8393, 0x18c1,
+ 0x8396, 0x18dc,
+ 0x839a, 0x18d8,
+ 0x839e, 0x060c,
+ 0x839f, 0x18da,
+ 0x83a0, 0x18e5,
+ 0x83a2, 0x18db,
+ 0x83a8, 0x18e7,
+ 0x83aa, 0x18d9,
+ 0x83ab, 0x0d32,
+ 0x83b1, 0x0f53,
+ 0x83b5, 0x18e2,
+ 0x83bd, 0x18f8,
+ 0x83c1, 0x18f0,
+ 0x83c5, 0x0a41,
+ 0x83c7, 0x219b,
+ 0x83ca, 0x0660,
+ 0x83cc, 0x06d5,
+ 0x83ce, 0x18eb,
+ 0x83d3, 0x055b,
+ 0x83d6, 0x09bc,
+ 0x83d8, 0x18ee,
+ 0x83dc, 0x084a,
+ 0x83df, 0x0c4b,
+ 0x83e0, 0x18f3,
+ 0x83e9, 0x0e3e,
+ 0x83eb, 0x18ea,
+ 0x83ef, 0x055a,
+ 0x83f0, 0x078a,
+ 0x83f1, 0x0d9b,
+ 0x83f2, 0x18f4,
+ 0x83f4, 0x18e8,
+ 0x83f6, 0x219c,
+ 0x83f7, 0x18f1,
+ 0x83fb, 0x18fb,
+ 0x83fd, 0x18ec,
+ 0x8403, 0x18ed,
+ 0x8404, 0x0c92,
+ 0x8407, 0x18f2,
+ 0x840a, 0x1e7f,
+ 0x840b, 0x18ef,
+ 0x840c, 0x0e56,
+ 0x840d, 0x18f5,
+ 0x840e, 0x04a4,
+ 0x8413, 0x18e9,
+ 0x8420, 0x18f7,
+ 0x8422, 0x18f6,
+ 0x8429, 0x0d21,
+ 0x842a, 0x18fd,
+ 0x842c, 0x1908,
+ 0x8431, 0x05dc,
+ 0x8435, 0x190b,
+ 0x8438, 0x18f9,
+ 0x843c, 0x18fe,
+ 0x843d, 0x0f58,
+ 0x8446, 0x1907,
+ 0x8448, 0x219d,
+ 0x8449, 0x0f3f,
+ 0x844e, 0x0f72,
+ 0x8457, 0x0bb6,
+ 0x845b, 0x05c9,
+ 0x8461, 0x0de4,
+ 0x8462, 0x190d,
+ 0x8463, 0x0c79,
+ 0x8466, 0x0475,
+ 0x8469, 0x1906,
+ 0x846b, 0x1902,
+ 0x846c, 0x0af4,
+ 0x846d, 0x18fc,
+ 0x846e, 0x1904,
+ 0x846f, 0x1909,
+ 0x8471, 0x0ce2,
+ 0x8475, 0x046e,
+ 0x8477, 0x1901,
+ 0x8479, 0x190a,
+ 0x847a, 0x0dea,
+ 0x8482, 0x1905,
+ 0x8484, 0x1900,
+ 0x848b, 0x09bd,
+ 0x8490, 0x0939,
+ 0x8494, 0x08d8,
+ 0x8499, 0x0ee4,
+ 0x849c, 0x0db9,
+ 0x849f, 0x1910,
+ 0x84a1, 0x1919,
+ 0x84ad, 0x1903,
+ 0x84b2, 0x05d5,
+ 0x84b4, 0x219e,
+ 0x84b8, 0x09e0,
+ 0x84b9, 0x190e,
+ 0x84bb, 0x1913,
+ 0x84bc, 0x0af5,
+ 0x84bf, 0x190f,
+ 0x84c1, 0x1916,
+ 0x84c4, 0x0b9d,
+ 0x84c6, 0x1917,
+ 0x84c9, 0x0f40,
+ 0x84ca, 0x190c,
+ 0x84cb, 0x0596,
+ 0x84cd, 0x1912,
+ 0x84d0, 0x1915,
+ 0x84d1, 0x0eb8,
+ 0x84d6, 0x1918,
+ 0x84d9, 0x1911,
+ 0x84da, 0x1914,
+ 0x84dc, 0x20ab,
+ 0x84ec, 0x0e57,
+ 0x84ee, 0x0fc7,
+ 0x84f4, 0x191c,
+ 0x84fc, 0x1923,
+ 0x84ff, 0x191b,
+ 0x8500, 0x08ef,
+ 0x8506, 0x18fa,
+ 0x8511, 0x0e1e,
+ 0x8513, 0x0eae,
+ 0x8514, 0x1922,
+ 0x8515, 0x1921,
+ 0x8517, 0x191d,
+ 0x851a, 0x04d8,
+ 0x851f, 0x1920,
+ 0x8521, 0x191a,
+ 0x8523, 0x1e1a,
+ 0x8526, 0x0bf1,
+ 0x852c, 0x191f,
+ 0x852d, 0x04c2,
+ 0x8535, 0x0b02,
+ 0x853d, 0x0e13,
+ 0x853e, 0x1eb5,
+ 0x8540, 0x1924,
+ 0x8541, 0x1928,
+ 0x8543, 0x0d6d,
+ 0x8548, 0x1927,
+ 0x8549, 0x09be,
+ 0x854a, 0x08f5,
+ 0x854b, 0x192a,
+ 0x854e, 0x06b6,
+ 0x8553, 0x219f,
+ 0x8555, 0x192b,
+ 0x8557, 0x0deb,
+ 0x8558, 0x1926,
+ 0x8559, 0x21a0,
+ 0x855a, 0x18ff,
+ 0x8563, 0x1925,
+ 0x8568, 0x0ff5,
+ 0x8569, 0x0c7a,
+ 0x856a, 0x0de5,
+ 0x856b, 0x21a1,
+ 0x856d, 0x1932,
+ 0x8577, 0x1938,
+ 0x857e, 0x1939,
+ 0x8580, 0x192c,
+ 0x8584, 0x0d2c,
+ 0x8587, 0x1936,
+ 0x8588, 0x192e,
+ 0x858a, 0x1930,
+ 0x8590, 0x193a,
+ 0x8591, 0x192f,
+ 0x8594, 0x1933,
+ 0x8597, 0x0514,
+ 0x8599, 0x0cbd,
+ 0x859b, 0x1934,
+ 0x859c, 0x1937,
+ 0x85a4, 0x192d,
+ 0x85a6, 0x0aa8,
+ 0x85a8, 0x1931,
+ 0x85a9, 0x0875,
+ 0x85aa, 0x0a0b,
+ 0x85ab, 0x0706,
+ 0x85ac, 0x0f00,
+ 0x85ae, 0x0f05,
+ 0x85af, 0x097c,
+ 0x85b0, 0x21a3,
+ 0x85b9, 0x193e,
+ 0x85ba, 0x193c,
+ 0x85c1, 0x0ff4,
+ 0x85c9, 0x193b,
+ 0x85cd, 0x0f5f,
+ 0x85cf, 0x193d,
+ 0x85d0, 0x193f,
+ 0x85d5, 0x1940,
+ 0x85dc, 0x1943,
+ 0x85dd, 0x1941,
+ 0x85e4, 0x0c7b,
+ 0x85e5, 0x1942,
+ 0x85e9, 0x0d61,
+ 0x85ea, 0x1935,
+ 0x85f7, 0x097d,
+ 0x85f9, 0x1944,
+ 0x85fa, 0x1949,
+ 0x85fb, 0x0af6,
+ 0x85fe, 0x1948,
+ 0x8602, 0x1929,
+ 0x8606, 0x194a,
+ 0x8607, 0x0acb,
+ 0x860a, 0x1945,
+ 0x860b, 0x1947,
+ 0x8613, 0x1946,
+ 0x8616, 0x14d0,
+ 0x8617, 0x14c1,
+ 0x861a, 0x194c,
+ 0x8622, 0x194b,
+ 0x862d, 0x0f60,
+ 0x862f, 0x16b1,
+ 0x8630, 0x194d,
+ 0x863f, 0x194e,
+ 0x864d, 0x194f,
+ 0x864e, 0x078b,
+ 0x8650, 0x066e,
+ 0x8654, 0x1951,
+ 0x8655, 0x1094,
+ 0x865a, 0x068f,
+ 0x865c, 0x0f82,
+ 0x865e, 0x06eb,
+ 0x865f, 0x1952,
+ 0x8667, 0x1953,
+ 0x866b, 0x0bac,
+ 0x8671, 0x1954,
+ 0x8679, 0x0cd2,
+ 0x867b, 0x047e,
+ 0x868a, 0x0563,
+ 0x868b, 0x1959,
+ 0x8693, 0x1955,
+ 0x8695, 0x088b,
+ 0x86a3, 0x1956,
+ 0x86a4, 0x0cf8,
+ 0x86a9, 0x1957,
+ 0x86ab, 0x1962,
+ 0x86af, 0x195c,
+ 0x86b0, 0x195f,
+ 0x86b6, 0x195b,
+ 0x86c4, 0x195d,
+ 0x86c6, 0x195e,
+ 0x86c7, 0x0904,
+ 0x86c9, 0x1960,
+ 0x86cb, 0x0b7f,
+ 0x86cd, 0x072c,
+ 0x86ce, 0x05a0,
+ 0x86d4, 0x1963,
+ 0x86d9, 0x059d,
+ 0x86db, 0x1968,
+ 0x86de, 0x1964,
+ 0x86df, 0x1967,
+ 0x86e4, 0x0d4e,
+ 0x86e9, 0x1965,
+ 0x86ec, 0x1966,
+ 0x86ed, 0x0dba,
+ 0x86ee, 0x0d6e,
+ 0x86ef, 0x1969,
+ 0x86f8, 0x0b5d,
+ 0x86f9, 0x1973,
+ 0x86fb, 0x196f,
+ 0x86fe, 0x056b,
+ 0x8700, 0x196d,
+ 0x8702, 0x0e58,
+ 0x8703, 0x196e,
+ 0x8706, 0x196b,
+ 0x8708, 0x196c,
+ 0x8709, 0x1971,
+ 0x870a, 0x1974,
+ 0x870d, 0x1972,
+ 0x8711, 0x1970,
+ 0x8712, 0x196a,
+ 0x8718, 0x0b96,
+ 0x871a, 0x197b,
+ 0x871c, 0x0eb6,
+ 0x8725, 0x1979,
+ 0x8729, 0x197a,
+ 0x8734, 0x1975,
+ 0x8737, 0x1977,
+ 0x873b, 0x1978,
+ 0x873f, 0x1976,
+ 0x8749, 0x0a8a,
+ 0x874b, 0x0fdf,
+ 0x874c, 0x197f,
+ 0x874e, 0x1980,
+ 0x8753, 0x1986,
+ 0x8755, 0x09f0,
+ 0x8757, 0x1982,
+ 0x8759, 0x1985,
+ 0x875f, 0x197d,
+ 0x8760, 0x197c,
+ 0x8763, 0x1987,
+ 0x8766, 0x055c,
+ 0x8768, 0x1983,
+ 0x876a, 0x1988,
+ 0x876e, 0x1984,
+ 0x8774, 0x1981,
+ 0x8776, 0x0bcf,
+ 0x8778, 0x197e,
+ 0x877f, 0x0d1e,
+ 0x8782, 0x198c,
+ 0x878d, 0x0f25,
+ 0x879f, 0x198b,
+ 0x87a2, 0x198a,
+ 0x87ab, 0x1993,
+ 0x87af, 0x198d,
+ 0x87b3, 0x1995,
+ 0x87ba, 0x0f50,
+ 0x87bb, 0x1998,
+ 0x87bd, 0x198f,
+ 0x87c0, 0x1990,
+ 0x87c4, 0x1994,
+ 0x87c6, 0x1997,
+ 0x87c7, 0x1996,
+ 0x87cb, 0x198e,
+ 0x87d0, 0x1991,
+ 0x87d2, 0x19a2,
+ 0x87e0, 0x199b,
+ 0x87ec, 0x1e23,
+ 0x87ef, 0x1999,
+ 0x87f2, 0x199a,
+ 0x87f6, 0x199f,
+ 0x87f9, 0x0588,
+ 0x87fb, 0x065c,
+ 0x87fe, 0x199e,
+ 0x8805, 0x1989,
+ 0x8807, 0x21a6,
+ 0x880d, 0x199d,
+ 0x880e, 0x19a1,
+ 0x880f, 0x199c,
+ 0x8811, 0x19a3,
+ 0x8815, 0x19a5,
+ 0x8816, 0x19a4,
+ 0x881f, 0x1e85,
+ 0x8821, 0x19a7,
+ 0x8822, 0x19a6,
+ 0x8823, 0x1961,
+ 0x8827, 0x19ab,
+ 0x8831, 0x19a8,
+ 0x8836, 0x19a9,
+ 0x8839, 0x19aa,
+ 0x883b, 0x19ac,
+ 0x8840, 0x0742,
+ 0x8842, 0x19ae,
+ 0x8844, 0x19ad,
+ 0x8846, 0x093a,
+ 0x884c, 0x07e6,
+ 0x884d, 0x1524,
+ 0x8852, 0x19af,
+ 0x8853, 0x095b,
+ 0x8857, 0x0597,
+ 0x8859, 0x19b0,
+ 0x885b, 0x04f4,
+ 0x885d, 0x09bf,
+ 0x885e, 0x19b1,
+ 0x8861, 0x07e7,
+ 0x8862, 0x19b2,
+ 0x8863, 0x04a5,
+ 0x8868, 0x0daf,
+ 0x886b, 0x19b3,
+ 0x8870, 0x0a30,
+ 0x8872, 0x19ba,
+ 0x8875, 0x19b7,
+ 0x8877, 0x0bad,
+ 0x887d, 0x19b8,
+ 0x887e, 0x19b5,
+ 0x887f, 0x06d6,
+ 0x8881, 0x19b4,
+ 0x8882, 0x19bb,
+ 0x8888, 0x070c,
+ 0x888b, 0x0b3e,
+ 0x888d, 0x19c1,
+ 0x8892, 0x19bd,
+ 0x8896, 0x0b15,
+ 0x8897, 0x19bc,
+ 0x8899, 0x19bf,
+ 0x889e, 0x19b6,
+ 0x88a2, 0x19c0,
+ 0x88a4, 0x19c2,
+ 0x88ab, 0x0d83,
+ 0x88ae, 0x19be,
+ 0x88b0, 0x19c3,
+ 0x88b1, 0x19c5,
+ 0x88b4, 0x0787,
+ 0x88b5, 0x19b9,
+ 0x88b7, 0x0485,
+ 0x88bf, 0x19c4,
+ 0x88c1, 0x084b,
+ 0x88c2, 0x0fbe,
+ 0x88c3, 0x19c6,
+ 0x88c5, 0x0af7,
+ 0x88cf, 0x0f6a,
+ 0x88d4, 0x19c8,
+ 0x88d5, 0x0f1f,
+ 0x88d8, 0x19c9,
+ 0x88dc, 0x0e34,
+ 0x88dd, 0x19cb,
+ 0x88df, 0x0830,
+ 0x88e1, 0x0f6b,
+ 0x88e8, 0x19d0,
+ 0x88f2, 0x19d1,
+ 0x88f3, 0x09c0,
+ 0x88f4, 0x19cf,
+ 0x88f5, 0x21a7,
+ 0x88f8, 0x0f51,
+ 0x88f9, 0x19cc,
+ 0x88fc, 0x19ce,
+ 0x88fd, 0x0a61,
+ 0x88fe, 0x0a44,
+ 0x8902, 0x19cd,
+ 0x8904, 0x19d2,
+ 0x8907, 0x0df3,
+ 0x890a, 0x19d4,
+ 0x890c, 0x19d3,
+ 0x8910, 0x05ca,
+ 0x8912, 0x0e59,
+ 0x8913, 0x19d5,
+ 0x891c, 0x20a8,
+ 0x891d, 0x19e1,
+ 0x891e, 0x19d7,
+ 0x8925, 0x19d8,
+ 0x892a, 0x19d9,
+ 0x8936, 0x19de,
+ 0x8938, 0x19df,
+ 0x893b, 0x19dd,
+ 0x8941, 0x19db,
+ 0x8943, 0x19d6,
+ 0x8944, 0x19dc,
+ 0x894c, 0x19e0,
+ 0x894d, 0x1bd0,
+ 0x8956, 0x0528,
+ 0x895e, 0x19e3,
+ 0x895f, 0x06d7,
+ 0x8960, 0x19e2,
+ 0x8964, 0x19e5,
+ 0x8966, 0x19e4,
+ 0x896a, 0x19e7,
+ 0x896d, 0x19e6,
+ 0x896f, 0x19e8,
+ 0x8972, 0x093b,
+ 0x8974, 0x19e9,
+ 0x8977, 0x19ea,
+ 0x897e, 0x19eb,
+ 0x897f, 0x0a62,
+ 0x8981, 0x0f41,
+ 0x8983, 0x19ec,
+ 0x8986, 0x0df4,
+ 0x8987, 0x0cfc,
+ 0x8988, 0x19ed,
+ 0x898a, 0x19ee,
+ 0x898b, 0x075f,
+ 0x898f, 0x0646,
+ 0x8993, 0x19ef,
+ 0x8996, 0x08b9,
+ 0x8997, 0x0cf7,
+ 0x8998, 0x19f0,
+ 0x899a, 0x05ae,
+ 0x89a1, 0x19f1,
+ 0x89a6, 0x19f3,
+ 0x89a7, 0x0f61,
+ 0x89a9, 0x19f2,
+ 0x89aa, 0x0a0c,
+ 0x89ac, 0x19f4,
+ 0x89af, 0x19f5,
+ 0x89b2, 0x19f6,
+ 0x89b3, 0x060d,
+ 0x89ba, 0x19f7,
+ 0x89bd, 0x19f8,
+ 0x89bf, 0x19f9,
+ 0x89d2, 0x05af,
+ 0x89da, 0x19fb,
+ 0x89dc, 0x19fc,
+ 0x89e3, 0x0572,
+ 0x89e6, 0x09ee,
+ 0x89e7, 0x19fe,
+ 0x89f4, 0x19ff,
+ 0x89f8, 0x1a00,
+ 0x8a00, 0x0774,
+ 0x8a02, 0x0c17,
+ 0x8a03, 0x1a01,
+ 0x8a08, 0x072d,
+ 0x8a0a, 0x0a1c,
+ 0x8a0c, 0x1a04,
+ 0x8a0e, 0x0c7c,
+ 0x8a10, 0x1a03,
+ 0x8a12, 0x21a8,
+ 0x8a13, 0x0707,
+ 0x8a16, 0x1a02,
+ 0x8a17, 0x0b57,
+ 0x8a18, 0x0647,
+ 0x8a1b, 0x1a05,
+ 0x8a1d, 0x1a06,
+ 0x8a1f, 0x09c1,
+ 0x8a23, 0x0743,
+ 0x8a25, 0x1a07,
+ 0x8a2a, 0x0e5a,
+ 0x8a2d, 0x0a83,
+ 0x8a31, 0x0690,
+ 0x8a33, 0x0f01,
+ 0x8a34, 0x0acc,
+ 0x8a36, 0x1a08,
+ 0x8a37, 0x21a9,
+ 0x8a3a, 0x0a0d,
+ 0x8a3b, 0x0bae,
+ 0x8a3c, 0x09c2,
+ 0x8a41, 0x1a09,
+ 0x8a46, 0x1a0c,
+ 0x8a48, 0x1a0d,
+ 0x8a50, 0x082e,
+ 0x8a51, 0x0b22,
+ 0x8a52, 0x1a0b,
+ 0x8a54, 0x09c3,
+ 0x8a55, 0x0db0,
+ 0x8a5b, 0x1a0a,
+ 0x8a5e, 0x08ba,
+ 0x8a60, 0x04f5,
+ 0x8a62, 0x1a11,
+ 0x8a63, 0x072e,
+ 0x8a66, 0x08bc,
+ 0x8a69, 0x08bb,
+ 0x8a6b, 0x0ff3,
+ 0x8a6c, 0x1a10,
+ 0x8a6d, 0x1a0f,
+ 0x8a6e, 0x0aa9,
+ 0x8a70, 0x0667,
+ 0x8a71, 0x0fe9,
+ 0x8a72, 0x0598,
+ 0x8a73, 0x09c4,
+ 0x8a79, 0x21aa,
+ 0x8a7c, 0x1a0e,
+ 0x8a82, 0x1a13,
+ 0x8a84, 0x1a14,
+ 0x8a85, 0x1a12,
+ 0x8a87, 0x078c,
+ 0x8a89, 0x0f2a,
+ 0x8a8c, 0x08bd,
+ 0x8a8d, 0x0cdd,
+ 0x8a91, 0x1a17,
+ 0x8a93, 0x0a64,
+ 0x8a95, 0x0b80,
+ 0x8a98, 0x0f20,
+ 0x8a9a, 0x1a1a,
+ 0x8a9e, 0x07a0,
+ 0x8aa0, 0x0a63,
+ 0x8aa1, 0x1a16,
+ 0x8aa3, 0x1a1b,
+ 0x8aa4, 0x07a1,
+ 0x8aa5, 0x1a18,
+ 0x8aa7, 0x21ab,
+ 0x8aa8, 0x1a15,
+ 0x8aac, 0x0a86,
+ 0x8aad, 0x0ca1,
+ 0x8ab0, 0x0b6d,
+ 0x8ab2, 0x055d,
+ 0x8ab9, 0x0d84,
+ 0x8abc, 0x065d,
+ 0x8abe, 0x21ac,
+ 0x8abf, 0x0bd0,
+ 0x8ac2, 0x1a1e,
+ 0x8ac4, 0x1a1c,
+ 0x8ac7, 0x0b8a,
+ 0x8acb, 0x0a65,
+ 0x8acc, 0x060e,
+ 0x8acd, 0x1a1d,
+ 0x8acf, 0x0a21,
+ 0x8ad2, 0x0f92,
+ 0x8ad6, 0x0fe6,
+ 0x8ada, 0x1a1f,
+ 0x8adb, 0x1a2a,
+ 0x8adc, 0x0bd1,
+ 0x8ade, 0x1a29,
+ 0x8adf, 0x21ad,
+ 0x8ae0, 0x1a26,
+ 0x8ae1, 0x1a2e,
+ 0x8ae2, 0x1a27,
+ 0x8ae4, 0x1a23,
+ 0x8ae6, 0x0c18,
+ 0x8ae7, 0x1a22,
+ 0x8aeb, 0x1a20,
+ 0x8aed, 0x0f0b,
+ 0x8aee, 0x08be,
+ 0x8af1, 0x1a24,
+ 0x8af3, 0x1a21,
+ 0x8af6, 0x21af,
+ 0x8af7, 0x1a28,
+ 0x8af8, 0x097e,
+ 0x8afa, 0x0775,
+ 0x8afe, 0x0b5a,
+ 0x8b00, 0x0e73,
+ 0x8b01, 0x04fc,
+ 0x8b02, 0x04a6,
+ 0x8b04, 0x0c7d,
+ 0x8b07, 0x1a2c,
+ 0x8b0c, 0x1a2b,
+ 0x8b0e, 0x0cbe,
+ 0x8b10, 0x1a30,
+ 0x8b14, 0x1a25,
+ 0x8b16, 0x1a2f,
+ 0x8b17, 0x1a31,
+ 0x8b19, 0x0760,
+ 0x8b1a, 0x1a2d,
+ 0x8b1b, 0x07e8,
+ 0x8b1d, 0x0901,
+ 0x8b20, 0x1a32,
+ 0x8b21, 0x0f42,
+ 0x8b26, 0x1a35,
+ 0x8b28, 0x1a38,
+ 0x8b2b, 0x1a36,
+ 0x8b2c, 0x0da7,
+ 0x8b33, 0x1a33,
+ 0x8b39, 0x06d8,
+ 0x8b3e, 0x1a37,
+ 0x8b41, 0x1a39,
+ 0x8b49, 0x1a3d,
+ 0x8b4c, 0x1a3a,
+ 0x8b4e, 0x1a3c,
+ 0x8b4f, 0x1a3b,
+ 0x8b53, 0x21b0,
+ 0x8b56, 0x1a3e,
+ 0x8b58, 0x08dd,
+ 0x8b5a, 0x1a40,
+ 0x8b5b, 0x1a3f,
+ 0x8b5c, 0x0dda,
+ 0x8b5f, 0x1a42,
+ 0x8b66, 0x072f,
+ 0x8b6b, 0x1a41,
+ 0x8b6c, 0x1a43,
+ 0x8b6f, 0x1a44,
+ 0x8b70, 0x065e,
+ 0x8b71, 0x182e,
+ 0x8b72, 0x09e1,
+ 0x8b74, 0x1a45,
+ 0x8b77, 0x07a2,
+ 0x8b7d, 0x1a46,
+ 0x8b7f, 0x21b1,
+ 0x8b80, 0x1a47,
+ 0x8b83, 0x088c,
+ 0x8b8a, 0x13d3,
+ 0x8b8c, 0x1a48,
+ 0x8b8e, 0x1a49,
+ 0x8b90, 0x093c,
+ 0x8b92, 0x1a4a,
+ 0x8b96, 0x1a4c,
+ 0x8b99, 0x1a4d,
+ 0x8c37, 0x0b69,
+ 0x8c3a, 0x1a4f,
+ 0x8c3f, 0x1a51,
+ 0x8c41, 0x1a50,
+ 0x8c46, 0x0c7e,
+ 0x8c48, 0x1a52,
+ 0x8c4a, 0x0e5b,
+ 0x8c4c, 0x1a53,
+ 0x8c4e, 0x1a54,
+ 0x8c50, 0x1a55,
+ 0x8c55, 0x1a56,
+ 0x8c5a, 0x0cb2,
+ 0x8c61, 0x09c5,
+ 0x8c62, 0x1a57,
+ 0x8c6a, 0x07fd,
+ 0x8c6b, 0x1007,
+ 0x8c6c, 0x1a58,
+ 0x8c78, 0x1a59,
+ 0x8c79, 0x0db1,
+ 0x8c7a, 0x1a5a,
+ 0x8c7c, 0x1a62,
+ 0x8c82, 0x1a5b,
+ 0x8c85, 0x1a5d,
+ 0x8c89, 0x1a5c,
+ 0x8c8a, 0x1a5e,
+ 0x8c8c, 0x0e74,
+ 0x8c8d, 0x1a5f,
+ 0x8c94, 0x1a61,
+ 0x8c98, 0x1a63,
+ 0x8c9d, 0x058b,
+ 0x8c9e, 0x0c03,
+ 0x8ca0, 0x0ddb,
+ 0x8ca1, 0x0852,
+ 0x8ca2, 0x07e9,
+ 0x8ca7, 0x0dc1,
+ 0x8ca8, 0x055f,
+ 0x8ca9, 0x0d62,
+ 0x8caa, 0x1a66,
+ 0x8cab, 0x060f,
+ 0x8cac, 0x0a79,
+ 0x8cad, 0x1a65,
+ 0x8cae, 0x1a6a,
+ 0x8caf, 0x0bb7,
+ 0x8cb0, 0x0eef,
+ 0x8cb2, 0x1a68,
+ 0x8cb4, 0x0648,
+ 0x8cb6, 0x1a6b,
+ 0x8cb7, 0x0d19,
+ 0x8cb8, 0x0b3f,
+ 0x8cbb, 0x0d85,
+ 0x8cbc, 0x0c37,
+ 0x8cbd, 0x1a67,
+ 0x8cbf, 0x0e75,
+ 0x8cc0, 0x056c,
+ 0x8cc1, 0x1a6d,
+ 0x8cc2, 0x0fce,
+ 0x8cc3, 0x0bde,
+ 0x8cc4, 0x0feb,
+ 0x8cc7, 0x08bf,
+ 0x8cc8, 0x1a6c,
+ 0x8cca, 0x0b11,
+ 0x8ccd, 0x1a7d,
+ 0x8cce, 0x0aaa,
+ 0x8cd1, 0x0cd0,
+ 0x8cd3, 0x0dc2,
+ 0x8cda, 0x1a70,
+ 0x8cdb, 0x088d,
+ 0x8cdc, 0x08c0,
+ 0x8cde, 0x09c6,
+ 0x8ce0, 0x0d1b,
+ 0x8ce2, 0x0761,
+ 0x8ce3, 0x1a6f,
+ 0x8ce4, 0x1a6e,
+ 0x8ce6, 0x0ddc,
+ 0x8cea, 0x08ed,
+ 0x8ced, 0x0c4c,
+ 0x8cf0, 0x21b2,
+ 0x8cf4, 0x21b3,
+ 0x8cfa, 0x1a72,
+ 0x8cfc, 0x07ea,
+ 0x8cfd, 0x1a71,
+ 0x8d04, 0x1a74,
+ 0x8d07, 0x1a77,
+ 0x8d08, 0x0b03,
+ 0x8d0a, 0x1a76,
+ 0x8d0b, 0x0622,
+ 0x8d0d, 0x1a79,
+ 0x8d0f, 0x1a78,
+ 0x8d10, 0x1a7a,
+ 0x8d12, 0x21b4,
+ 0x8d13, 0x1a7c,
+ 0x8d14, 0x1a7e,
+ 0x8d16, 0x1a7f,
+ 0x8d64, 0x0a7a,
+ 0x8d66, 0x08fb,
+ 0x8d67, 0x1a80,
+ 0x8d6b, 0x05b0,
+ 0x8d6d, 0x1a81,
+ 0x8d70, 0x0af8,
+ 0x8d71, 0x1a82,
+ 0x8d73, 0x1a83,
+ 0x8d74, 0x0ddd,
+ 0x8d76, 0x21b5,
+ 0x8d77, 0x0649,
+ 0x8d81, 0x1a84,
+ 0x8d85, 0x0bd2,
+ 0x8d8a, 0x04fd,
+ 0x8d99, 0x1a85,
+ 0x8da3, 0x091d,
+ 0x8da8, 0x0a3c,
+ 0x8db3, 0x0b0d,
+ 0x8dba, 0x1a88,
+ 0x8dbe, 0x1a87,
+ 0x8dc2, 0x1a86,
+ 0x8dcb, 0x1a8e,
+ 0x8dcc, 0x1a8c,
+ 0x8dcf, 0x1a89,
+ 0x8dd6, 0x1a8b,
+ 0x8dda, 0x1a8a,
+ 0x8ddb, 0x1a8d,
+ 0x8ddd, 0x0691,
+ 0x8ddf, 0x1a91,
+ 0x8de1, 0x0a7b,
+ 0x8de3, 0x1a92,
+ 0x8de8, 0x078d,
+ 0x8dea, 0x1a8f,
+ 0x8def, 0x0fcf,
+ 0x8df3, 0x0bd3,
+ 0x8df5, 0x0aab,
+ 0x8dfc, 0x1a93,
+ 0x8dff, 0x1a96,
+ 0x8e08, 0x1a94,
+ 0x8e0a, 0x0f43,
+ 0x8e0f, 0x0c7f,
+ 0x8e10, 0x1a99,
+ 0x8e1d, 0x1a97,
+ 0x8e1f, 0x1a9a,
+ 0x8e2a, 0x1aa8,
+ 0x8e30, 0x1a9d,
+ 0x8e34, 0x1a9e,
+ 0x8e35, 0x1a9c,
+ 0x8e42, 0x1a9b,
+ 0x8e44, 0x0c19,
+ 0x8e47, 0x1aa0,
+ 0x8e48, 0x1aa4,
+ 0x8e49, 0x1aa1,
+ 0x8e4a, 0x1a9f,
+ 0x8e4c, 0x1aa2,
+ 0x8e50, 0x1aa3,
+ 0x8e55, 0x1aaa,
+ 0x8e59, 0x1aa5,
+ 0x8e5f, 0x0a7c,
+ 0x8e60, 0x1aa7,
+ 0x8e63, 0x1aa9,
+ 0x8e64, 0x1aa6,
+ 0x8e72, 0x1aac,
+ 0x8e74, 0x093d,
+ 0x8e76, 0x1aab,
+ 0x8e7c, 0x1aad,
+ 0x8e81, 0x1aae,
+ 0x8e84, 0x1ab1,
+ 0x8e85, 0x1ab0,
+ 0x8e87, 0x1aaf,
+ 0x8e8a, 0x1ab3,
+ 0x8e8b, 0x1ab2,
+ 0x8e8d, 0x0f02,
+ 0x8e91, 0x1ab5,
+ 0x8e93, 0x1ab4,
+ 0x8e94, 0x1ab6,
+ 0x8e99, 0x1ab7,
+ 0x8ea1, 0x1ab9,
+ 0x8eaa, 0x1ab8,
+ 0x8eab, 0x0a0e,
+ 0x8eac, 0x1aba,
+ 0x8eaf, 0x06e5,
+ 0x8eb0, 0x1abb,
+ 0x8eb1, 0x1abd,
+ 0x8ebe, 0x1abe,
+ 0x8ec0, 0x1def,
+ 0x8ec5, 0x1abf,
+ 0x8ec6, 0x1abc,
+ 0x8ec8, 0x1ac0,
+ 0x8eca, 0x0902,
+ 0x8ecb, 0x1ac1,
+ 0x8ecc, 0x064a,
+ 0x8ecd, 0x0709,
+ 0x8ecf, 0x21b7,
+ 0x8ed2, 0x0762,
+ 0x8edb, 0x1ac2,
+ 0x8edf, 0x0cc8,
+ 0x8ee2, 0x0c38,
+ 0x8ee3, 0x1ac3,
+ 0x8eeb, 0x1ac6,
+ 0x8ef8, 0x08e0,
+ 0x8efb, 0x1ac5,
+ 0x8efc, 0x1ac4,
+ 0x8efd, 0x0730,
+ 0x8efe, 0x1ac7,
+ 0x8f03, 0x05b1,
+ 0x8f05, 0x1ac9,
+ 0x8f09, 0x084c,
+ 0x8f0a, 0x1ac8,
+ 0x8f0c, 0x1ad1,
+ 0x8f12, 0x1acb,
+ 0x8f13, 0x1acd,
+ 0x8f14, 0x0e35,
+ 0x8f15, 0x1aca,
+ 0x8f19, 0x1acc,
+ 0x8f1b, 0x1ad0,
+ 0x8f1c, 0x1ace,
+ 0x8f1d, 0x064b,
+ 0x8f1f, 0x1acf,
+ 0x8f26, 0x1ad2,
+ 0x8f29, 0x0d10,
+ 0x8f2a, 0x0fa0,
+ 0x8f2f, 0x093e,
+ 0x8f33, 0x1ad3,
+ 0x8f38, 0x0f0c,
+ 0x8f39, 0x1ad5,
+ 0x8f3b, 0x1ad4,
+ 0x8f3e, 0x1ad8,
+ 0x8f3f, 0x0f2b,
+ 0x8f42, 0x1ad7,
+ 0x8f44, 0x05cb,
+ 0x8f45, 0x1ad6,
+ 0x8f46, 0x1adb,
+ 0x8f49, 0x1ada,
+ 0x8f4c, 0x1ad9,
+ 0x8f4d, 0x0c2c,
+ 0x8f4e, 0x1adc,
+ 0x8f57, 0x1add,
+ 0x8f5c, 0x1ade,
+ 0x8f5f, 0x07fe,
+ 0x8f61, 0x06fb,
+ 0x8f62, 0x1adf,
+ 0x8f9b, 0x0a0f,
+ 0x8f9c, 0x1ae2,
+ 0x8f9e, 0x08d9,
+ 0x8f9f, 0x1ae3,
+ 0x8fa3, 0x1ae4,
+ 0x8fa7, 0x10b6,
+ 0x8fa8, 0x10b5,
+ 0x8fad, 0x1ae5,
+ 0x8fae, 0x17ff,
+ 0x8faf, 0x1ae6,
+ 0x8fb0, 0x0b62,
+ 0x8fb1, 0x09f1,
+ 0x8fb2, 0x0cf6,
+ 0x8fb7, 0x1ae7,
+ 0x8fba, 0x0e25,
+ 0x8fbb, 0x0bf0,
+ 0x8fbc, 0x0810,
+ 0x8fbf, 0x0b67,
+ 0x8fc2, 0x04cc,
+ 0x8fc4, 0x0ea6,
+ 0x8fc5, 0x0a1d,
+ 0x8fce, 0x0734,
+ 0x8fd1, 0x06d9,
+ 0x8fd4, 0x0e26,
+ 0x8fda, 0x1ae8,
+ 0x8fe2, 0x1aea,
+ 0x8fe5, 0x1ae9,
+ 0x8fe6, 0x0560,
+ 0x8fe9, 0x0cce,
+ 0x8fea, 0x1aeb,
+ 0x8feb, 0x0d2d,
+ 0x8fed, 0x0c2d,
+ 0x8fef, 0x1aec,
+ 0x8ff0, 0x095c,
+ 0x8ff4, 0x1aee,
+ 0x8ff7, 0x0ece,
+ 0x8ff8, 0x1afd,
+ 0x8ff9, 0x1af0,
+ 0x8ffd, 0x0be5,
+ 0x9000, 0x0b40,
+ 0x9001, 0x0af9,
+ 0x9003, 0x0c80,
+ 0x9005, 0x1aef,
+ 0x9006, 0x066f,
+ 0x900b, 0x1af8,
+ 0x900d, 0x1af5,
+ 0x900e, 0x1b02,
+ 0x900f, 0x0c81,
+ 0x9010, 0x0b9e,
+ 0x9011, 0x1af2,
+ 0x9013, 0x0c1a,
+ 0x9014, 0x0c4d,
+ 0x9015, 0x1af3,
+ 0x9016, 0x1af7,
+ 0x9017, 0x0a26,
+ 0x9019, 0x0d1d,
+ 0x901a, 0x0be8,
+ 0x901d, 0x0a66,
+ 0x901e, 0x1af6,
+ 0x901f, 0x0b0e,
+ 0x9020, 0x0b04,
+ 0x9021, 0x1af4,
+ 0x9022, 0x046d,
+ 0x9023, 0x0fc8,
+ 0x9027, 0x1af9,
+ 0x902e, 0x0b41,
+ 0x9031, 0x093f,
+ 0x9032, 0x0a10,
+ 0x9035, 0x1afb,
+ 0x9036, 0x1afa,
+ 0x9038, 0x04b3,
+ 0x9039, 0x1afc,
+ 0x903c, 0x0da1,
+ 0x903e, 0x1b04,
+ 0x9041, 0x0cb3,
+ 0x9042, 0x0a31,
+ 0x9045, 0x0b97,
+ 0x9047, 0x06f0,
+ 0x9049, 0x1b03,
+ 0x904a, 0x0f21,
+ 0x904b, 0x04e1,
+ 0x904d, 0x0e27,
+ 0x904e, 0x0561,
+ 0x904f, 0x1afe,
+ 0x9053, 0x0c93,
+ 0x9054, 0x0b61,
+ 0x9055, 0x04a7,
+ 0x9056, 0x1b05,
+ 0x9058, 0x1b06,
+ 0x9059, 0x1d34,
+ 0x905c, 0x0b1d,
+ 0x905e, 0x1b07,
+ 0x9060, 0x0515,
+ 0x9061, 0x0ace,
+ 0x9063, 0x0763,
+ 0x9065, 0x0f44,
+ 0x9067, 0x21ba,
+ 0x9068, 0x1b08,
+ 0x9069, 0x0c26,
+ 0x906d, 0x0afa,
+ 0x906e, 0x0903,
+ 0x906f, 0x1b09,
+ 0x9072, 0x1b0c,
+ 0x9075, 0x096f,
+ 0x9076, 0x1b0a,
+ 0x9077, 0x0aad,
+ 0x9078, 0x0aac,
+ 0x907a, 0x04a8,
+ 0x907c, 0x0f93,
+ 0x907d, 0x1b0e,
+ 0x907f, 0x0d86,
+ 0x9080, 0x1b10,
+ 0x9081, 0x1b0f,
+ 0x9082, 0x1b0d,
+ 0x9083, 0x1737,
+ 0x9084, 0x0610,
+ 0x9087, 0x1aed,
+ 0x9089, 0x1b12,
+ 0x908a, 0x1b11,
+ 0x908f, 0x1b13,
+ 0x9091, 0x0f22,
+ 0x90a3, 0x0cb9,
+ 0x90a6, 0x0e5c,
+ 0x90a8, 0x1b14,
+ 0x90aa, 0x0905,
+ 0x90af, 0x1b15,
+ 0x90b1, 0x1b16,
+ 0x90b5, 0x1b17,
+ 0x90b8, 0x0c1b,
+ 0x90c1, 0x04ae,
+ 0x90ca, 0x07eb,
+ 0x90ce, 0x0fe0,
+ 0x90db, 0x1b1b,
+ 0x90de, 0x21bb,
+ 0x90e1, 0x070a,
+ 0x90e2, 0x1b18,
+ 0x90e4, 0x1b19,
+ 0x90e8, 0x0de6,
+ 0x90ed, 0x05b2,
+ 0x90f5, 0x0f23,
+ 0x90f7, 0x06b7,
+ 0x90fd, 0x0c4e,
+ 0x9102, 0x1b1c,
+ 0x9112, 0x1b1d,
+ 0x9115, 0x21bd,
+ 0x9119, 0x1b1e,
+ 0x9127, 0x21be,
+ 0x912d, 0x0c1c,
+ 0x9130, 0x1b20,
+ 0x9132, 0x1b1f,
+ 0x9149, 0x0cab,
+ 0x914a, 0x1b21,
+ 0x914b, 0x0940,
+ 0x914c, 0x090c,
+ 0x914d, 0x0d11,
+ 0x914e, 0x0baf,
+ 0x9152, 0x091e,
+ 0x9154, 0x0a32,
+ 0x9156, 0x1b22,
+ 0x9158, 0x1b23,
+ 0x9162, 0x0a23,
+ 0x9163, 0x1b24,
+ 0x9165, 0x1b25,
+ 0x9169, 0x1b26,
+ 0x916a, 0x0f59,
+ 0x916c, 0x0941,
+ 0x9172, 0x1b28,
+ 0x9173, 0x1b27,
+ 0x9175, 0x07ec,
+ 0x9177, 0x0805,
+ 0x9178, 0x088e,
+ 0x9182, 0x1b2b,
+ 0x9187, 0x0970,
+ 0x9189, 0x1b2a,
+ 0x918b, 0x1b29,
+ 0x918d, 0x0b49,
+ 0x9190, 0x07a3,
+ 0x9192, 0x0a67,
+ 0x9197, 0x0d44,
+ 0x919c, 0x0943,
+ 0x91a2, 0x1b2c,
+ 0x91a4, 0x09c7,
+ 0x91aa, 0x1b2f,
+ 0x91ab, 0x1b2d,
+ 0x91ac, 0x1e1b,
+ 0x91af, 0x1b2e,
+ 0x91b1, 0x1e61,
+ 0x91b4, 0x1b31,
+ 0x91b5, 0x1b30,
+ 0x91b8, 0x09e2,
+ 0x91ba, 0x1b32,
+ 0x91c0, 0x1b33,
+ 0x91c6, 0x0d64,
+ 0x91c7, 0x0843,
+ 0x91c8, 0x090d,
+ 0x91c9, 0x1b35,
+ 0x91cb, 0x1b36,
+ 0x91cc, 0x0f6c,
+ 0x91cd, 0x094f,
+ 0x91ce, 0x0efa,
+ 0x91cf, 0x0f94,
+ 0x91d0, 0x1b37,
+ 0x91d1, 0x06da,
+ 0x91d6, 0x1b38,
+ 0x91d7, 0x21c0,
+ 0x91d8, 0x0c1d,
+ 0x91da, 0x21bf,
+ 0x91db, 0x1b3b,
+ 0x91dc, 0x05d6,
+ 0x91dd, 0x0a11,
+ 0x91de, 0x21c1,
+ 0x91df, 0x1b39,
+ 0x91e1, 0x1b3a,
+ 0x91e3, 0x0bfc,
+ 0x91e4, 0x21c4,
+ 0x91e6, 0x0e83,
+ 0x91e7, 0x06f4,
+ 0x91ed, 0x21c2,
+ 0x91f5, 0x1b3d,
+ 0x91fc, 0x1b3c,
+ 0x91ff, 0x1b40,
+ 0x9206, 0x21c6,
+ 0x920a, 0x21c8,
+ 0x920d, 0x0cb7,
+ 0x920e, 0x05a1,
+ 0x9210, 0x21c7,
+ 0x9211, 0x1b44,
+ 0x9214, 0x1b41,
+ 0x9215, 0x1b43,
+ 0x921e, 0x1b3f,
+ 0x9229, 0x1b8a,
+ 0x922c, 0x1b42,
+ 0x9234, 0x0fb3,
+ 0x9237, 0x078e,
+ 0x9239, 0x21cf,
+ 0x923a, 0x21c9,
+ 0x923c, 0x21cb,
+ 0x923f, 0x1b4c,
+ 0x9240, 0x21ca,
+ 0x9244, 0x0c2e,
+ 0x9245, 0x1b47,
+ 0x9248, 0x1b4a,
+ 0x9249, 0x1b48,
+ 0x924b, 0x1b4d,
+ 0x924e, 0x21cc,
+ 0x9250, 0x1b4e,
+ 0x9251, 0x21ce,
+ 0x9257, 0x1b46,
+ 0x9259, 0x21cd,
+ 0x925a, 0x1b53,
+ 0x925b, 0x0516,
+ 0x925e, 0x1b45,
+ 0x9262, 0x0d41,
+ 0x9264, 0x1b49,
+ 0x9266, 0x09c8,
+ 0x9267, 0x21d0,
+ 0x9271, 0x07ed,
+ 0x9277, 0x21d2,
+ 0x927e, 0x0e76,
+ 0x9280, 0x06dc,
+ 0x9283, 0x0950,
+ 0x9285, 0x0c94,
+ 0x9288, 0x20aa,
+ 0x9291, 0x0aaf,
+ 0x9293, 0x1b51,
+ 0x9295, 0x1b4b,
+ 0x9296, 0x1b50,
+ 0x9298, 0x0ecf,
+ 0x929a, 0x0bd4,
+ 0x929b, 0x1b52,
+ 0x929c, 0x1b4f,
+ 0x92a7, 0x21d1,
+ 0x92ad, 0x0aae,
+ 0x92b7, 0x1b56,
+ 0x92b9, 0x1b55,
+ 0x92cf, 0x1b54,
+ 0x92d0, 0x21d7,
+ 0x92d2, 0x0e5d,
+ 0x92d3, 0x21db,
+ 0x92d5, 0x21d9,
+ 0x92d7, 0x21d5,
+ 0x92d9, 0x21d6,
+ 0x92e0, 0x21da,
+ 0x92e4, 0x0985,
+ 0x92e7, 0x21d4,
+ 0x92e9, 0x1b57,
+ 0x92ea, 0x0e2f,
+ 0x92ed, 0x04f6,
+ 0x92f2, 0x0db8,
+ 0x92f3, 0x0bb0,
+ 0x92f8, 0x0692,
+ 0x92f9, 0x20b0,
+ 0x92fa, 0x1b59,
+ 0x92fb, 0x21de,
+ 0x92fc, 0x07ef,
+ 0x92ff, 0x21e1,
+ 0x9302, 0x21e3,
+ 0x9306, 0x087a,
+ 0x930f, 0x1b58,
+ 0x9310, 0x0a33,
+ 0x9318, 0x0a34,
+ 0x9319, 0x1b5c,
+ 0x931a, 0x1b5e,
+ 0x931d, 0x21e2,
+ 0x931e, 0x21e0,
+ 0x9320, 0x09e3,
+ 0x9321, 0x21dd,
+ 0x9322, 0x1b5d,
+ 0x9323, 0x1b5f,
+ 0x9325, 0x21dc,
+ 0x9326, 0x06cb,
+ 0x9328, 0x0db7,
+ 0x932b, 0x090e,
+ 0x932c, 0x0fc9,
+ 0x932e, 0x1b5b,
+ 0x932f, 0x0868,
+ 0x9332, 0x0fe5,
+ 0x9335, 0x1b61,
+ 0x933a, 0x1b60,
+ 0x933b, 0x1b62,
+ 0x9344, 0x1b5a,
+ 0x9348, 0x20a9,
+ 0x934b, 0x0cc1,
+ 0x934d, 0x0c4f,
+ 0x9354, 0x0bf3,
+ 0x9356, 0x1b67,
+ 0x9357, 0x21e5,
+ 0x935b, 0x0b81,
+ 0x935c, 0x1b63,
+ 0x9360, 0x1b64,
+ 0x936c, 0x0703,
+ 0x936e, 0x1b66,
+ 0x9370, 0x21e4,
+ 0x9375, 0x0764,
+ 0x937c, 0x1b65,
+ 0x937e, 0x09c9,
+ 0x938c, 0x05d7,
+ 0x9394, 0x1b6b,
+ 0x9396, 0x082f,
+ 0x9397, 0x0afb,
+ 0x939a, 0x0be6,
+ 0x93a4, 0x21e6,
+ 0x93a7, 0x0599,
+ 0x93ac, 0x1b69,
+ 0x93ae, 0x0bdf,
+ 0x93b0, 0x1b68,
+ 0x93b9, 0x1b6c,
+ 0x93c3, 0x1b72,
+ 0x93c6, 0x21e7,
+ 0x93c8, 0x1b75,
+ 0x93d0, 0x1b74,
+ 0x93d1, 0x0c27,
+ 0x93d6, 0x1b6d,
+ 0x93d8, 0x1b71,
+ 0x93dd, 0x1b73,
+ 0x93de, 0x21e8,
+ 0x93e1, 0x06b8,
+ 0x93e4, 0x1b76,
+ 0x93e5, 0x1b70,
+ 0x93e8, 0x1b6f,
+ 0x93f8, 0x21e9,
+ 0x9403, 0x1b7a,
+ 0x9407, 0x1b7b,
+ 0x9410, 0x1b7c,
+ 0x9413, 0x1b79,
+ 0x9414, 0x1b78,
+ 0x9418, 0x09ca,
+ 0x9419, 0x0c82,
+ 0x941a, 0x1b77,
+ 0x9421, 0x1b80,
+ 0x942b, 0x1b7e,
+ 0x9431, 0x21ea,
+ 0x9435, 0x1b7f,
+ 0x9436, 0x1b7d,
+ 0x9438, 0x0b58,
+ 0x943a, 0x1b81,
+ 0x9441, 0x1b82,
+ 0x9444, 0x1b84,
+ 0x9445, 0x21eb,
+ 0x9448, 0x21ec,
+ 0x9451, 0x0611,
+ 0x9452, 0x1b83,
+ 0x9453, 0x0f06,
+ 0x945a, 0x1b8f,
+ 0x945b, 0x1b85,
+ 0x945e, 0x1b88,
+ 0x9460, 0x1b86,
+ 0x9462, 0x1b87,
+ 0x946a, 0x1b89,
+ 0x9470, 0x1b8b,
+ 0x9475, 0x1b8c,
+ 0x9477, 0x1b8d,
+ 0x947c, 0x1b90,
+ 0x947d, 0x1b8e,
+ 0x947e, 0x1b91,
+ 0x947f, 0x1b93,
+ 0x9481, 0x1b92,
+ 0x9577, 0x0bd5,
+ 0x9580, 0x0ef3,
+ 0x9582, 0x1b94,
+ 0x9583, 0x0ab0,
+ 0x9587, 0x1b95,
+ 0x9589, 0x0e14,
+ 0x958a, 0x1b96,
+ 0x958b, 0x0589,
+ 0x958f, 0x04de,
+ 0x9591, 0x0613,
+ 0x9592, 0x21ed,
+ 0x9593, 0x0612,
+ 0x9594, 0x1b97,
+ 0x9596, 0x1b98,
+ 0x9598, 0x1b99,
+ 0x95a0, 0x1b9b,
+ 0x95a2, 0x0614,
+ 0x95a3, 0x05b3,
+ 0x95a4, 0x07f0,
+ 0x95a5, 0x0d4a,
+ 0x95a7, 0x1b9d,
+ 0x95a8, 0x1b9c,
+ 0x95ad, 0x1b9e,
+ 0x95b2, 0x04fe,
+ 0x95b9, 0x1ba1,
+ 0x95bb, 0x1ba0,
+ 0x95bc, 0x1b9f,
+ 0x95be, 0x1ba2,
+ 0x95c3, 0x1ba5,
+ 0x95c7, 0x048b,
+ 0x95ca, 0x1ba3,
+ 0x95cc, 0x1ba7,
+ 0x95cd, 0x1ba6,
+ 0x95d4, 0x1ba9,
+ 0x95d5, 0x1ba8,
+ 0x95d6, 0x1baa,
+ 0x95d8, 0x0c86,
+ 0x95dc, 0x1bab,
+ 0x95e1, 0x1bac,
+ 0x95e2, 0x1bae,
+ 0x95e5, 0x1bad,
+ 0x961c, 0x0dde,
+ 0x9621, 0x1baf,
+ 0x9628, 0x1bb0,
+ 0x962a, 0x0855,
+ 0x962e, 0x1bb1,
+ 0x9632, 0x0e77,
+ 0x963b, 0x0acd,
+ 0x963f, 0x0468,
+ 0x9640, 0x0b2b,
+ 0x9642, 0x1bb3,
+ 0x9644, 0x0ddf,
+ 0x964b, 0x1bb6,
+ 0x964c, 0x1bb4,
+ 0x964d, 0x07f1,
+ 0x964f, 0x1bb5,
+ 0x9650, 0x0776,
+ 0x965b, 0x0e15,
+ 0x965c, 0x1bb8,
+ 0x965d, 0x1bba,
+ 0x965e, 0x1bb9,
+ 0x965f, 0x1bbb,
+ 0x9662, 0x04c3,
+ 0x9663, 0x0a1e,
+ 0x9664, 0x0986,
+ 0x9665, 0x0615,
+ 0x9666, 0x1bbc,
+ 0x966a, 0x0d1c,
+ 0x966c, 0x1bbe,
+ 0x9670, 0x04c4,
+ 0x9672, 0x1bbd,
+ 0x9673, 0x0be0,
+ 0x9675, 0x0f95,
+ 0x9676, 0x0c83,
+ 0x9677, 0x1bb7,
+ 0x9678, 0x0f6e,
+ 0x967a, 0x0765,
+ 0x967d, 0x0f45,
+ 0x9685, 0x06f1,
+ 0x9686, 0x0f7c,
+ 0x9688, 0x06fe,
+ 0x968a, 0x0b42,
+ 0x968b, 0x186c,
+ 0x968d, 0x1bbf,
+ 0x968e, 0x058a,
+ 0x968f, 0x0a35,
+ 0x9694, 0x05b4,
+ 0x9695, 0x1bc1,
+ 0x9697, 0x1bc2,
+ 0x9698, 0x1bc0,
+ 0x9699, 0x073a,
+ 0x969b, 0x084d,
+ 0x969c, 0x09cb,
+ 0x969d, 0x21f0,
+ 0x96a0, 0x04c5,
+ 0x96a3, 0x0fa1,
+ 0x96a7, 0x1bc4,
+ 0x96a8, 0x1b0b,
+ 0x96aa, 0x1bc3,
+ 0x96af, 0x21f1,
+ 0x96b0, 0x1bc7,
+ 0x96b1, 0x1bc5,
+ 0x96b4, 0x1bc8,
+ 0x96b6, 0x1bc9,
+ 0x96b7, 0x0fb4,
+ 0x96b8, 0x1bca,
+ 0x96bb, 0x0a6d,
+ 0x96bc, 0x0d4f,
+ 0x96c0, 0x0a43,
+ 0x96c1, 0x0623,
+ 0x96c4, 0x0f24,
+ 0x96c5, 0x056d,
+ 0x96c6, 0x0942,
+ 0x96c7, 0x078f,
+ 0x96c9, 0x1bce,
+ 0x96cb, 0x1bcd,
+ 0x96cc, 0x08c1,
+ 0x96cd, 0x1bcf,
+ 0x96ce, 0x1bcc,
+ 0x96d1, 0x0876,
+ 0x96d5, 0x1bd3,
+ 0x96d6, 0x1992,
+ 0x96d9, 0x10eb,
+ 0x96db, 0x0a3d,
+ 0x96dc, 0x1bd1,
+ 0x96e2, 0x0f6d,
+ 0x96e3, 0x0cc9,
+ 0x96e8, 0x04cd,
+ 0x96ea, 0x0a87,
+ 0x96eb, 0x08e2,
+ 0x96f0, 0x0e07,
+ 0x96f2, 0x04e2,
+ 0x96f6, 0x0fb5,
+ 0x96f7, 0x0f55,
+ 0x96f9, 0x1bd4,
+ 0x96fb, 0x0c3f,
+ 0x9700, 0x0927,
+ 0x9704, 0x1bd5,
+ 0x9706, 0x1bd6,
+ 0x9707, 0x0a12,
+ 0x9708, 0x1bd7,
+ 0x970a, 0x0fb6,
+ 0x970d, 0x1bd2,
+ 0x970e, 0x1bd9,
+ 0x970f, 0x1bdb,
+ 0x9711, 0x1bda,
+ 0x9713, 0x1bd8,
+ 0x9716, 0x1bdc,
+ 0x9719, 0x1bdd,
+ 0x971c, 0x0afc,
+ 0x971e, 0x0562,
+ 0x9724, 0x1bde,
+ 0x9727, 0x0ec4,
+ 0x972a, 0x1bdf,
+ 0x9730, 0x1be0,
+ 0x9732, 0x0fd0,
+ 0x9733, 0x21f2,
+ 0x9738, 0x1414,
+ 0x9739, 0x1be1,
+ 0x973b, 0x21f3,
+ 0x973d, 0x1be2,
+ 0x9742, 0x1be7,
+ 0x9743, 0x21f4,
+ 0x9744, 0x1be4,
+ 0x9746, 0x1be5,
+ 0x9748, 0x1be6,
+ 0x9749, 0x1be8,
+ 0x974d, 0x21f5,
+ 0x974f, 0x21f6,
+ 0x9751, 0x21f7,
+ 0x9752, 0x0a68,
+ 0x9755, 0x21f8,
+ 0x9756, 0x0f03,
+ 0x9759, 0x0a69,
+ 0x975c, 0x1be9,
+ 0x975e, 0x0d87,
+ 0x9760, 0x1bea,
+ 0x9761, 0x1d06,
+ 0x9762, 0x0ed8,
+ 0x9764, 0x1beb,
+ 0x9766, 0x1bec,
+ 0x9768, 0x1bed,
+ 0x9769, 0x05b5,
+ 0x976b, 0x1bef,
+ 0x976d, 0x0a1f,
+ 0x9771, 0x1bf0,
+ 0x9774, 0x06fa,
+ 0x9779, 0x1bf1,
+ 0x977a, 0x1bf5,
+ 0x977c, 0x1bf3,
+ 0x9781, 0x1bf4,
+ 0x9784, 0x05d1,
+ 0x9785, 0x1bf2,
+ 0x9786, 0x1bf6,
+ 0x978b, 0x1bf7,
+ 0x978d, 0x048c,
+ 0x978f, 0x1bf8,
+ 0x9798, 0x09cc,
+ 0x979c, 0x1bfa,
+ 0x97a0, 0x0661,
+ 0x97a3, 0x1bfd,
+ 0x97a6, 0x1bfc,
+ 0x97a8, 0x1bfb,
+ 0x97ab, 0x1a34,
+ 0x97ad, 0x0e2c,
+ 0x97b3, 0x1bfe,
+ 0x97c3, 0x1c00,
+ 0x97c6, 0x1c01,
+ 0x97c8, 0x1c02,
+ 0x97cb, 0x1c03,
+ 0x97d3, 0x0616,
+ 0x97dc, 0x1c04,
+ 0x97ed, 0x1c05,
+ 0x97ee, 0x0cd9,
+ 0x97f2, 0x1c07,
+ 0x97f3, 0x053b,
+ 0x97f5, 0x1c0a,
+ 0x97f6, 0x1c09,
+ 0x97fb, 0x04c6,
+ 0x97ff, 0x06b9,
+ 0x9801, 0x0e17,
+ 0x9802, 0x0bd6,
+ 0x9803, 0x0812,
+ 0x9805, 0x07f2,
+ 0x9806, 0x0971,
+ 0x9808, 0x0a22,
+ 0x980c, 0x1c0c,
+ 0x980f, 0x1c0b,
+ 0x9810, 0x0f2c,
+ 0x9811, 0x0624,
+ 0x9812, 0x0d66,
+ 0x9813, 0x0cb4,
+ 0x9817, 0x0a42,
+ 0x9818, 0x0f96,
+ 0x981a, 0x0731,
+ 0x9821, 0x1c0f,
+ 0x9824, 0x1c0e,
+ 0x982c, 0x0e79,
+ 0x982d, 0x0c84,
+ 0x9830, 0x1e73,
+ 0x9834, 0x04f2,
+ 0x9837, 0x1c10,
+ 0x9838, 0x1c0d,
+ 0x983b, 0x0dc3,
+ 0x983c, 0x0f54,
+ 0x983d, 0x1c11,
+ 0x9846, 0x1c12,
+ 0x984b, 0x1c14,
+ 0x984c, 0x0b4a,
+ 0x984d, 0x05b9,
+ 0x984f, 0x1c13,
+ 0x9854, 0x0625,
+ 0x9855, 0x0766,
+ 0x9857, 0x21f9,
+ 0x9858, 0x0626,
+ 0x985a, 0x1e48,
+ 0x985b, 0x0c39,
+ 0x985e, 0x0fa8,
+ 0x9865, 0x21fa,
+ 0x9867, 0x0790,
+ 0x986b, 0x1c15,
+ 0x986f, 0x1c16,
+ 0x9873, 0x1c1a,
+ 0x9874, 0x1c19,
+ 0x98a8, 0x0de9,
+ 0x98aa, 0x1c1b,
+ 0x98af, 0x1c1c,
+ 0x98b1, 0x1c1d,
+ 0x98b6, 0x1c1e,
+ 0x98c3, 0x1c20,
+ 0x98c4, 0x1c1f,
+ 0x98c6, 0x1c21,
+ 0x98db, 0x0d88,
+ 0x98dc, 0x1839,
+ 0x98df, 0x09ef,
+ 0x98e2, 0x064c,
+ 0x98e9, 0x1c22,
+ 0x98eb, 0x1c23,
+ 0x98ed, 0x10c1,
+ 0x98ee, 0x14da,
+ 0x98ef, 0x0d67,
+ 0x98f2, 0x04bf,
+ 0x98f4, 0x047f,
+ 0x98fc, 0x08c2,
+ 0x98fd, 0x0e5e,
+ 0x98fe, 0x09e6,
+ 0x9903, 0x1c24,
+ 0x9905, 0x0eeb,
+ 0x9909, 0x1c25,
+ 0x990a, 0x0f46,
+ 0x990c, 0x04e4,
+ 0x9910, 0x088f,
+ 0x9912, 0x1c26,
+ 0x9913, 0x056e,
+ 0x9914, 0x1c27,
+ 0x9918, 0x1c28,
+ 0x991d, 0x1c2a,
+ 0x9920, 0x1c2d,
+ 0x9921, 0x1c29,
+ 0x9924, 0x1c2c,
+ 0x9927, 0x21fd,
+ 0x9928, 0x0617,
+ 0x992c, 0x1c2e,
+ 0x992e, 0x1c2f,
+ 0x993d, 0x1c30,
+ 0x9942, 0x1c32,
+ 0x9945, 0x1c34,
+ 0x9949, 0x1c33,
+ 0x994b, 0x1c36,
+ 0x994c, 0x1c39,
+ 0x9950, 0x1c35,
+ 0x9951, 0x1c37,
+ 0x9955, 0x1c3a,
+ 0x9957, 0x06ba,
+ 0x9996, 0x091f,
+ 0x9997, 0x1c3b,
+ 0x9999, 0x07f3,
+ 0x999e, 0x21ff,
+ 0x99a5, 0x1c3d,
+ 0x99a8, 0x059c,
+ 0x99ac, 0x0d05,
+ 0x99ad, 0x1c3e,
+ 0x99b3, 0x0b98,
+ 0x99b4, 0x0cc3,
+ 0x99bc, 0x1c40,
+ 0x99c1, 0x0d33,
+ 0x99c4, 0x0b2c,
+ 0x99c5, 0x04fa,
+ 0x99c6, 0x06e6,
+ 0x99c8, 0x06e7,
+ 0x99d0, 0x0bb1,
+ 0x99d1, 0x1c45,
+ 0x99d2, 0x06e8,
+ 0x99d5, 0x056f,
+ 0x99d8, 0x1c44,
+ 0x99db, 0x1c42,
+ 0x99dd, 0x1c43,
+ 0x99df, 0x1c41,
+ 0x99e2, 0x1c4f,
+ 0x99ed, 0x1c46,
+ 0x99f1, 0x1c48,
+ 0x99f8, 0x1c4b,
+ 0x99fb, 0x1c4a,
+ 0x99ff, 0x0963,
+ 0x9a01, 0x1c4c,
+ 0x9a05, 0x1c4e,
+ 0x9a0e, 0x064d,
+ 0x9a0f, 0x1c4d,
+ 0x9a12, 0x0afd,
+ 0x9a13, 0x0767,
+ 0x9a19, 0x1c50,
+ 0x9a28, 0x0b2d,
+ 0x9a2b, 0x1c51,
+ 0x9a30, 0x0c85,
+ 0x9a37, 0x1c52,
+ 0x9a3e, 0x1c57,
+ 0x9a40, 0x1c55,
+ 0x9a42, 0x1c54,
+ 0x9a43, 0x1c56,
+ 0x9a45, 0x1c53,
+ 0x9a4d, 0x1c59,
+ 0x9a4e, 0x2200,
+ 0x9a52, 0x1e2f,
+ 0x9a55, 0x1c58,
+ 0x9a57, 0x1c5b,
+ 0x9a5a, 0x06bb,
+ 0x9a5b, 0x1c5a,
+ 0x9a5f, 0x1c5c,
+ 0x9a62, 0x1c5d,
+ 0x9a64, 0x1c5f,
+ 0x9a65, 0x1c5e,
+ 0x9a69, 0x1c60,
+ 0x9a6a, 0x1c62,
+ 0x9a6b, 0x1c61,
+ 0x9aa8, 0x080e,
+ 0x9aad, 0x1c63,
+ 0x9ab0, 0x1c64,
+ 0x9ab8, 0x059a,
+ 0x9abc, 0x1c65,
+ 0x9ac0, 0x1c66,
+ 0x9ac4, 0x0a37,
+ 0x9acf, 0x1c67,
+ 0x9ad1, 0x1c68,
+ 0x9ad3, 0x1c69,
+ 0x9ad8, 0x07f4,
+ 0x9ad9, 0x2201,
+ 0x9adc, 0x2202,
+ 0x9ade, 0x1c6b,
+ 0x9ae2, 0x1c6d,
+ 0x9ae6, 0x1c6f,
+ 0x9aea, 0x0d45,
+ 0x9aeb, 0x1c71,
+ 0x9aed, 0x0d98,
+ 0x9aee, 0x1c72,
+ 0x9aef, 0x1c70,
+ 0x9af1, 0x1c74,
+ 0x9af4, 0x1c73,
+ 0x9af7, 0x1c75,
+ 0x9afb, 0x1c76,
+ 0x9b06, 0x1c77,
+ 0x9b18, 0x1c78,
+ 0x9b1a, 0x1c79,
+ 0x9b1f, 0x1c7a,
+ 0x9b22, 0x1c7b,
+ 0x9b25, 0x1c7d,
+ 0x9b27, 0x1c7e,
+ 0x9b2e, 0x1c82,
+ 0x9b31, 0x14d4,
+ 0x9b32, 0x1c84,
+ 0x9b3b, 0x17a9,
+ 0x9b3c, 0x064e,
+ 0x9b41, 0x057f,
+ 0x9b42, 0x0822,
+ 0x9b43, 0x1c86,
+ 0x9b44, 0x1c85,
+ 0x9b45, 0x0eb1,
+ 0x9b4d, 0x1c88,
+ 0x9b4f, 0x1c87,
+ 0x9b51, 0x1c8a,
+ 0x9b54, 0x0e90,
+ 0x9b58, 0x1c8b,
+ 0x9b5a, 0x0695,
+ 0x9b6f, 0x0fcb,
+ 0x9b72, 0x2204,
+ 0x9b74, 0x1c8c,
+ 0x9b75, 0x2203,
+ 0x9b83, 0x1c8e,
+ 0x9b8e, 0x0482,
+ 0x9b8f, 0x2205,
+ 0x9b91, 0x1c8f,
+ 0x9b92, 0x0dfb,
+ 0x9b93, 0x1c8d,
+ 0x9b96, 0x1c90,
+ 0x9b9f, 0x1c92,
+ 0x9ba8, 0x1c94,
+ 0x9baa, 0x0e9c,
+ 0x9bab, 0x087b,
+ 0x9bad, 0x086a,
+ 0x9bae, 0x0ab1,
+ 0x9bb1, 0x2206,
+ 0x9bb4, 0x1c95,
+ 0x9bb9, 0x1c98,
+ 0x9bbb, 0x2207,
+ 0x9bc0, 0x1c96,
+ 0x9bc6, 0x1c99,
+ 0x9bc9, 0x07a5,
+ 0x9bca, 0x1c97,
+ 0x9bcf, 0x1c9a,
+ 0x9bd1, 0x1c9b,
+ 0x9bd4, 0x1ca0,
+ 0x9bd6, 0x0878,
+ 0x9bdb, 0x0b44,
+ 0x9be1, 0x1ca1,
+ 0x9be2, 0x1c9e,
+ 0x9be3, 0x1c9d,
+ 0x9be4, 0x1c9f,
+ 0x9be8, 0x0735,
+ 0x9bf0, 0x1ca5,
+ 0x9bf1, 0x1ca4,
+ 0x9bf2, 0x1ca3,
+ 0x9bf5, 0x0477,
+ 0x9c00, 0x2208,
+ 0x9c04, 0x1caf,
+ 0x9c06, 0x1cab,
+ 0x9c08, 0x1cac,
+ 0x9c09, 0x1ca8,
+ 0x9c0a, 0x1cae,
+ 0x9c0c, 0x1caa,
+ 0x9c0d, 0x05c0,
+ 0x9c10, 0x0ff2,
+ 0x9c12, 0x1cad,
+ 0x9c13, 0x1ca9,
+ 0x9c14, 0x1ca7,
+ 0x9c15, 0x1ca6,
+ 0x9c1b, 0x1cb1,
+ 0x9c21, 0x1cb4,
+ 0x9c24, 0x1cb3,
+ 0x9c25, 0x1cb2,
+ 0x9c2d, 0x0dbb,
+ 0x9c2e, 0x1cb0,
+ 0x9c2f, 0x04b7,
+ 0x9c30, 0x1cb5,
+ 0x9c32, 0x1cb7,
+ 0x9c39, 0x05cd,
+ 0x9c3a, 0x1ca2,
+ 0x9c3b, 0x04d9,
+ 0x9c3e, 0x1cb9,
+ 0x9c46, 0x1cb8,
+ 0x9c47, 0x1cb6,
+ 0x9c48, 0x0b6b,
+ 0x9c52, 0x0e9e,
+ 0x9c57, 0x0fa2,
+ 0x9c5a, 0x1cba,
+ 0x9c60, 0x1cbb,
+ 0x9c67, 0x1cbc,
+ 0x9c76, 0x1cbd,
+ 0x9c78, 0x1cbe,
+ 0x9ce5, 0x0bd7,
+ 0x9ce7, 0x1cbf,
+ 0x9ce9, 0x0d4b,
+ 0x9ceb, 0x1cc4,
+ 0x9cec, 0x1cc0,
+ 0x9cf0, 0x1cc1,
+ 0x9cf3, 0x0e5f,
+ 0x9cf4, 0x0ed0,
+ 0x9cf6, 0x0ca8,
+ 0x9d03, 0x1cc5,
+ 0x9d06, 0x1cc6,
+ 0x9d07, 0x0c96,
+ 0x9d08, 0x1cc3,
+ 0x9d09, 0x1cc2,
+ 0x9d0e, 0x052a,
+ 0x9d12, 0x1cce,
+ 0x9d15, 0x1ccd,
+ 0x9d1b, 0x0517,
+ 0x9d1f, 0x1ccb,
+ 0x9d23, 0x1cca,
+ 0x9d26, 0x1cc8,
+ 0x9d28, 0x05d9,
+ 0x9d2a, 0x1cc7,
+ 0x9d2b, 0x08de,
+ 0x9d2c, 0x0529,
+ 0x9d3b, 0x07f5,
+ 0x9d3e, 0x1cd1,
+ 0x9d3f, 0x1cd0,
+ 0x9d41, 0x1ccf,
+ 0x9d44, 0x1ccc,
+ 0x9d46, 0x1cd2,
+ 0x9d48, 0x1cd3,
+ 0x9d50, 0x1cd8,
+ 0x9d51, 0x1cd7,
+ 0x9d59, 0x1cd9,
+ 0x9d5c, 0x04cf,
+ 0x9d5d, 0x1cd4,
+ 0x9d60, 0x0806,
+ 0x9d61, 0x0ec5,
+ 0x9d64, 0x1cd6,
+ 0x9d6b, 0x220a,
+ 0x9d6c, 0x0e60,
+ 0x9d6f, 0x1cde,
+ 0x9d70, 0x2209,
+ 0x9d72, 0x1cda,
+ 0x9d7a, 0x1cdf,
+ 0x9d87, 0x1cdc,
+ 0x9d89, 0x1cdb,
+ 0x9d8f, 0x0732,
+ 0x9d9a, 0x1ce0,
+ 0x9da4, 0x1ce1,
+ 0x9da9, 0x1ce2,
+ 0x9dab, 0x1cdd,
+ 0x9daf, 0x1cc9,
+ 0x9db2, 0x1ce3,
+ 0x9db4, 0x0bfd,
+ 0x9db8, 0x1ce7,
+ 0x9dba, 0x1ce8,
+ 0x9dbb, 0x1ce6,
+ 0x9dc1, 0x1ce5,
+ 0x9dc2, 0x1ceb,
+ 0x9dc4, 0x1ce4,
+ 0x9dc6, 0x1ce9,
+ 0x9dcf, 0x1cea,
+ 0x9dd3, 0x1ced,
+ 0x9dd7, 0x1dde,
+ 0x9dd9, 0x1cec,
+ 0x9de6, 0x1cef,
+ 0x9ded, 0x1cf0,
+ 0x9def, 0x1cf1,
+ 0x9df2, 0x0fef,
+ 0x9df8, 0x1cee,
+ 0x9df9, 0x0b4b,
+ 0x9dfa, 0x085d,
+ 0x9dfd, 0x1cf2,
+ 0x9e19, 0x220c,
+ 0x9e1a, 0x1cf3,
+ 0x9e1e, 0x1cf5,
+ 0x9e75, 0x1cf6,
+ 0x9e78, 0x0768,
+ 0x9e79, 0x1cf7,
+ 0x9e7c, 0x1dfd,
+ 0x9e7d, 0x1cf8,
+ 0x9e7f, 0x08db,
+ 0x9e81, 0x1cf9,
+ 0x9e88, 0x1cfa,
+ 0x9e8b, 0x1cfb,
+ 0x9e91, 0x1cff,
+ 0x9e92, 0x1cfd,
+ 0x9e93, 0x0fe2,
+ 0x9e95, 0x1cfe,
+ 0x9e97, 0x0fb7,
+ 0x9e9d, 0x1d00,
+ 0x9e9f, 0x0fa3,
+ 0x9ea5, 0x1d01,
+ 0x9ea6, 0x0d34,
+ 0x9ea9, 0x1d02,
+ 0x9eaa, 0x1d04,
+ 0x9ead, 0x1d05,
+ 0x9eb4, 0x1e02,
+ 0x9eb5, 0x1e75,
+ 0x9eb8, 0x1d03,
+ 0x9eb9, 0x07ff,
+ 0x9eba, 0x0ed9,
+ 0x9ebb, 0x0e91,
+ 0x9ebc, 0x1284,
+ 0x9ebe, 0x14ff,
+ 0x9ebf, 0x0ea9,
+ 0x9ec4, 0x052b,
+ 0x9ecc, 0x1d07,
+ 0x9ecd, 0x066a,
+ 0x9ece, 0x1d08,
+ 0x9ed1, 0x220d,
+ 0x9ed2, 0x0807,
+ 0x9ed4, 0x1d0b,
+ 0x9ed8, 0x160d,
+ 0x9ed9, 0x0ee7,
+ 0x9edb, 0x0b43,
+ 0x9edc, 0x1d0c,
+ 0x9edd, 0x1d0e,
+ 0x9ede, 0x1d0d,
+ 0x9ee0, 0x1d0f,
+ 0x9ee5, 0x1d10,
+ 0x9ee8, 0x1d11,
+ 0x9eef, 0x1d12,
+ 0x9ef4, 0x1d13,
+ 0x9ef6, 0x1d14,
+ 0x9ef9, 0x1d16,
+ 0x9efb, 0x1d17,
+ 0x9f07, 0x1d1a,
+ 0x9f0e, 0x0c1e,
+ 0x9f13, 0x0791,
+ 0x9f15, 0x1d1d,
+ 0x9f20, 0x0acf,
+ 0x9f21, 0x1d1e,
+ 0x9f2c, 0x1d1f,
+ 0x9f3b, 0x0d93,
+ 0x9f3e, 0x1d20,
+ 0x9f4a, 0x1d21,
+ 0x9f4b, 0x170a,
+ 0x9f4e, 0x1a7b,
+ 0x9f4f, 0x1c06,
+ 0x9f52, 0x1d22,
+ 0x9f54, 0x1d23,
+ 0x9f5f, 0x1d25,
+ 0x9f62, 0x0fb8,
+ 0x9f63, 0x1d24,
+ 0x9f66, 0x1d28,
+ 0x9f6a, 0x1d2b,
+ 0x9f6c, 0x1d2a,
+ 0x9f72, 0x1d2d,
+ 0x9f76, 0x1d2e,
+ 0x9f77, 0x1d2c,
+ 0x9f8d, 0x0f7e,
+ 0x9f95, 0x1d2f,
+ 0x9f9c, 0x1d30,
+ 0x9f9d, 0x1727,
+ 0x9fa0, 0x1d31,
+ 0xf929, 0x2129,
+ 0xf9dc, 0x21ee,
+ 0xfa0e, 0x20da,
+ 0xfa0f, 0x20e5,
+ 0xfa11, 0x20fb,
+ 0xfa12, 0x2121,
+ 0xfa13, 0x2131,
+ 0xfa14, 0x2133,
+ 0xfa15, 0x215e,
+ 0xfa16, 0x2164,
+ 0xfa17, 0x217b,
+ 0xfa18, 0x2183,
+ 0xfa1b, 0x2187,
+ 0xfa1c, 0x218b,
+ 0xfa1d, 0x218e,
+ 0xfa1e, 0x2197,
+ 0xfa1f, 0x21a2,
+ 0xfa20, 0x21a4,
+ 0xfa22, 0x21ae,
+ 0xfa23, 0x21b6,
+ 0xfa24, 0x21b8,
+ 0xfa26, 0x21bc,
+ 0xfa27, 0x21d8,
+ 0xfa28, 0x21df,
+ 0xfa29, 0x21ef,
+ 0xfa2a, 0x21fb,
+ 0xfa2c, 0x21fe,
+ 0xfa2d, 0x220b,
+ 0xfb01, 0x0070,
+ 0xfe30, 0x1eda,
+ 0xfe31, 0x1ed4,
+ 0xfe33, 0x1ed2,
+ 0xfe35, 0x1edb,
+ 0xfe37, 0x1ee1,
+ 0xfe39, 0x1edd,
+ 0xfe3b, 0x1eeb,
+ 0xfe3d, 0x1ee5,
+ 0xfe3f, 0x1ee3,
+ 0xfe41, 0x1ee7,
+ 0xff01, 0x0282,
+ 0xff02, 0x1f47,
+ 0xff03, 0x02cc,
+ 0xff04, 0x02c8,
+ 0xff05, 0x02cb,
+ 0xff06, 0x02cd,
+ 0xff07, 0x1f46,
+ 0xff08, 0x02a2,
+ 0xff0a, 0x02ce,
+ 0xff0b, 0x02b4,
+ 0xff0c, 0x027c,
+ 0xff0d, 0x0296,
+ 0xff0e, 0x027d,
+ 0xff0f, 0x0297,
+ 0xff10, 0x030c,
+ 0xff1a, 0x027f,
+ 0xff1c, 0x02bb,
+ 0xff1d, 0x02b9,
+ 0xff1e, 0x02bc,
+ 0xff1f, 0x0281,
+ 0xff20, 0x02cf,
+ 0xff21, 0x0316,
+ 0xff3b, 0x02a6,
+ 0xff3c, 0x0298,
+ 0xff3d, 0x02a7,
+ 0xff3e, 0x0288,
+ 0xff3f, 0x028a,
+ 0xff40, 0x0286,
+ 0xff41, 0x0330,
+ 0xff5b, 0x02a8,
+ 0xff5c, 0x029b,
+ 0xff5d, 0x02a9,
+ 0xff5e, 0x0299,
+ 0xff61, 0x0147,
+ 0xffe0, 0x02c9,
+ 0xffe2, 0x02ef,
+ 0xffe3, 0x0289,
+ 0xffe4, 0x1f45,
+ 0xffe5, 0x02c7,
+ 0xffe8, 0x0143,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 japan12UniJISUCS2HEnc16 = {
+ 0,
+ { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ japan12UniJISUCS2HMap2, 6963
+};
+
+static Gushort japan12UniJISUCS2VMap2[14216] = {
+ 0x0000, 0x0000,
+ 0x0020, 0x0001,
+ 0x005c, 0x0061,
+ 0x005d, 0x003e,
+ 0x00a1, 0x0065,
+ 0x00a4, 0x006b,
+ 0x00a5, 0x003d,
+ 0x00a6, 0x0063,
+ 0x00a7, 0x02d0,
+ 0x00a8, 0x0287,
+ 0x00a9, 0x0098,
+ 0x00aa, 0x008c,
+ 0x00ab, 0x006d,
+ 0x00ac, 0x0099,
+ 0x00ad, 0x0097,
+ 0x00ae, 0x009a,
+ 0x00af, 0x0081,
+ 0x00b0, 0x02c3,
+ 0x00b1, 0x02b6,
+ 0x00b2, 0x009d,
+ 0x00b4, 0x0285,
+ 0x00b5, 0x009f,
+ 0x00b6, 0x030a,
+ 0x00b7, 0x0075,
+ 0x00b8, 0x0086,
+ 0x00b9, 0x00a0,
+ 0x00ba, 0x0090,
+ 0x00bb, 0x007b,
+ 0x00bc, 0x00a1,
+ 0x00bf, 0x007e,
+ 0x00c0, 0x00a4,
+ 0x00c6, 0x008b,
+ 0x00c7, 0x00aa,
+ 0x00d7, 0x02b7,
+ 0x00d8, 0x008e,
+ 0x00d9, 0x00bb,
+ 0x00df, 0x0096,
+ 0x00e0, 0x00c1,
+ 0x00e6, 0x0091,
+ 0x00e7, 0x00c7,
+ 0x00f7, 0x02b8,
+ 0x00f8, 0x0094,
+ 0x00f9, 0x00d8,
+ 0x0131, 0x0092,
+ 0x0141, 0x008d,
+ 0x0142, 0x0093,
+ 0x0152, 0x008f,
+ 0x0153, 0x0095,
+ 0x0160, 0x00df,
+ 0x0161, 0x00e3,
+ 0x0178, 0x00e0,
+ 0x017d, 0x00e1,
+ 0x017e, 0x00e5,
+ 0x01c0, 0x0063,
+ 0x0300, 0x0041,
+ 0x0301, 0x007f,
+ 0x0303, 0x005f,
+ 0x0304, 0x0081,
+ 0x0305, 0x00e2,
+ 0x0306, 0x0082,
+ 0x030a, 0x0085,
+ 0x030b, 0x0087,
+ 0x030c, 0x0089,
+ 0x0327, 0x0086,
+ 0x0328, 0x0088,
+ 0x0332, 0x0040,
+ 0x0336, 0x008a,
+ 0x0361, 0x02f6,
+ 0x0391, 0x03f3,
+ 0x03a3, 0x0404,
+ 0x03b1, 0x040b,
+ 0x03c3, 0x041c,
+ 0x0401, 0x0429,
+ 0x0410, 0x0423,
+ 0x0416, 0x042a,
+ 0x0436, 0x044b,
+ 0x0451, 0x044a,
+ 0x2002, 0x00e7,
+ 0x2003, 0x0279,
+ 0x2010, 0x000e,
+ 0x2011, 0x000e,
+ 0x2012, 0x0072,
+ 0x2013, 0x0072,
+ 0x2014, 0x008a,
+ 0x2015, 0x0295,
+ 0x2016, 0x029a,
+ 0x2018, 0x029e,
+ 0x201a, 0x0078,
+ 0x201c, 0x02a0,
+ 0x201e, 0x0079,
+ 0x2020, 0x0308,
+ 0x2022, 0x0077,
+ 0x2025, 0x029d,
+ 0x2026, 0x029c,
+ 0x2030, 0x0304,
+ 0x2032, 0x02c4,
+ 0x2039, 0x006e,
+ 0x203b, 0x02de,
+ 0x203e, 0x0145,
+ 0x2044, 0x0068,
+ 0x20dd, 0x030b,
+ 0x2103, 0x02c6,
+ 0x2109, 0x2071,
+ 0x2113, 0x1f59,
+ 0x2116, 0x1dba,
+ 0x2121, 0x1f77,
+ 0x2122, 0x00e4,
+ 0x212b, 0x0303,
+ 0x2160, 0x1d97,
+ 0x216a, 0x2021,
+ 0x2170, 0x1f9c,
+ 0x217a, 0x206a,
+ 0x217f, 0x206f,
+ 0x2190, 0x02e1,
+ 0x2192, 0x02e0,
+ 0x2193, 0x02e3,
+ 0x21c4, 0x2076,
+ 0x21c6, 0x2075,
+ 0x21d2, 0x02f0,
+ 0x21d4, 0x02f1,
+ 0x21e6, 0x1f4d,
+ 0x21e7, 0x1f4c,
+ 0x21e8, 0x1f4e,
+ 0x21e9, 0x1f4b,
+ 0x2200, 0x02f2,
+ 0x2202, 0x02f7,
+ 0x2203, 0x02f3,
+ 0x2207, 0x02f8,
+ 0x2208, 0x02e5,
+ 0x220b, 0x02e6,
+ 0x2211, 0x1dc9,
+ 0x2212, 0x02b5,
+ 0x221a, 0x02fd,
+ 0x221d, 0x02ff,
+ 0x221e, 0x02bf,
+ 0x221f, 0x1dcd,
+ 0x2220, 0x02f4,
+ 0x2225, 0x029a,
+ 0x2227, 0x02ed,
+ 0x2229, 0x02ec,
+ 0x222a, 0x02eb,
+ 0x222b, 0x0301,
+ 0x222d, 0x2003,
+ 0x222e, 0x1dc8,
+ 0x2234, 0x02c0,
+ 0x2235, 0x0300,
+ 0x223c, 0x0299,
+ 0x223d, 0x02fe,
+ 0x2252, 0x02fa,
+ 0x2260, 0x02ba,
+ 0x2261, 0x02f9,
+ 0x2266, 0x02bd,
+ 0x226a, 0x02fb,
+ 0x2282, 0x02e9,
+ 0x2286, 0x02e7,
+ 0x22a5, 0x02f5,
+ 0x22bf, 0x1dce,
+ 0x22ee, 0x1ed9,
+ 0x22ef, 0x029c,
+ 0x2312, 0x02f6,
+ 0x2460, 0x1d83,
+ 0x2474, 0x1f87,
+ 0x2488, 0x1f7e,
+ 0x249c, 0x1fb0,
+ 0x24ea, 0x2020,
+ 0x2500, 0x1d37,
+ 0x2550, 0x203b,
+ 0x255e, 0x203c,
+ 0x2561, 0x203e,
+ 0x256a, 0x203d,
+ 0x256d, 0x2037,
+ 0x256f, 0x203a,
+ 0x2570, 0x2039,
+ 0x2571, 0x2045,
+ 0x2581, 0x2026,
+ 0x2589, 0x2034,
+ 0x258a, 0x2033,
+ 0x258b, 0x2032,
+ 0x258c, 0x2031,
+ 0x258d, 0x2030,
+ 0x258e, 0x202f,
+ 0x258f, 0x202e,
+ 0x2594, 0x2035,
+ 0x25a0, 0x02d9,
+ 0x25a1, 0x02d8,
+ 0x25a2, 0x1f4f,
+ 0x25b2, 0x02db,
+ 0x25b3, 0x02da,
+ 0x25b7, 0x1f4a,
+ 0x25bc, 0x02dd,
+ 0x25bd, 0x02dc,
+ 0x25c1, 0x1f49,
+ 0x25c6, 0x02d7,
+ 0x25c7, 0x02d6,
+ 0x25c9, 0x2012,
+ 0x25cb, 0x02d3,
+ 0x25ce, 0x02d5,
+ 0x25cf, 0x02d4,
+ 0x25e2, 0x203f,
+ 0x25e4, 0x2042,
+ 0x25e5, 0x2041,
+ 0x25ef, 0x030b,
+ 0x2600, 0x2017,
+ 0x2605, 0x02d2,
+ 0x2606, 0x02d1,
+ 0x260e, 0x1f78,
+ 0x261c, 0x201c,
+ 0x261e, 0x201b,
+ 0x261f, 0x201e,
+ 0x2640, 0x02c2,
+ 0x2642, 0x02c1,
+ 0x2660, 0x2013,
+ 0x2661, 0x1f51,
+ 0x2662, 0x1f53,
+ 0x2663, 0x2015,
+ 0x2664, 0x1f52,
+ 0x2665, 0x2014,
+ 0x2666, 0x2016,
+ 0x2667, 0x1f50,
+ 0x266a, 0x0307,
+ 0x266d, 0x0306,
+ 0x266f, 0x0305,
+ 0x2776, 0x205e,
+ 0x27a1, 0x200e,
+ 0x3000, 0x0279,
+ 0x3003, 0x028f,
+ 0x3004, 0x2074,
+ 0x3005, 0x0291,
+ 0x3008, 0x02aa,
+ 0x3012, 0x02df,
+ 0x3013, 0x02e4,
+ 0x3014, 0x02a4,
+ 0x301c, 0x0299,
+ 0x301d, 0x1db8,
+ 0x301f, 0x1db9,
+ 0x3020, 0x1f7a,
+ 0x3036, 0x1f79,
+ 0x3041, 0x034a,
+ 0x3094, 0x1f16,
+ 0x309b, 0x0283,
+ 0x309d, 0x028d,
+ 0x30a1, 0x039d,
+ 0x30f7, 0x2079,
+ 0x30fb, 0x027e,
+ 0x30fc, 0x0294,
+ 0x30fd, 0x028b,
+ 0x322a, 0x2006,
+ 0x3230, 0x2005,
+ 0x3231, 0x1dc2,
+ 0x3233, 0x1fcf,
+ 0x3234, 0x1fcd,
+ 0x3235, 0x1fd4,
+ 0x3236, 0x1fd3,
+ 0x3237, 0x200c,
+ 0x3238, 0x1fce,
+ 0x3239, 0x1dc4,
+ 0x323a, 0x1fd7,
+ 0x323b, 0x1fd5,
+ 0x323c, 0x1fd0,
+ 0x323d, 0x1fcb,
+ 0x323e, 0x1fd2,
+ 0x323f, 0x1fcc,
+ 0x3240, 0x1fd6,
+ 0x3241, 0x200d,
+ 0x3242, 0x1fd1,
+ 0x3243, 0x1fca,
+ 0x3291, 0x1fe1,
+ 0x3292, 0x1fe0,
+ 0x3293, 0x1fe2,
+ 0x3294, 0x1fdc,
+ 0x3296, 0x1fe5,
+ 0x3298, 0x1fde,
+ 0x3299, 0x201f,
+ 0x329d, 0x207f,
+ 0x329e, 0x1fff,
+ 0x32a4, 0x1dbd,
+ 0x32a9, 0x1fda,
+ 0x32aa, 0x1fdd,
+ 0x32ab, 0x1fdf,
+ 0x32ac, 0x1fe3,
+ 0x32ad, 0x1fd9,
+ 0x32ae, 0x1fe4,
+ 0x32af, 0x1fdb,
+ 0x32b0, 0x1fd8,
+ 0x3300, 0x1f70,
+ 0x3303, 0x1f6a,
+ 0x3305, 0x1ff7,
+ 0x330d, 0x1dab,
+ 0x3314, 0x1da2,
+ 0x3315, 0x1f69,
+ 0x3316, 0x1f67,
+ 0x3318, 0x1f68,
+ 0x331e, 0x1f73,
+ 0x3322, 0x1f66,
+ 0x3323, 0x1f6b,
+ 0x3326, 0x1dac,
+ 0x3327, 0x1da6,
+ 0x332a, 0x1f74,
+ 0x332b, 0x1dae,
+ 0x3331, 0x1f71,
+ 0x3333, 0x2087,
+ 0x3336, 0x1da8,
+ 0x3339, 0x1f6e,
+ 0x333b, 0x1f6f,
+ 0x3342, 0x1f6d,
+ 0x3347, 0x1f72,
+ 0x3349, 0x1da1,
+ 0x334a, 0x1daf,
+ 0x334d, 0x1da4,
+ 0x334e, 0x2088,
+ 0x3351, 0x1da9,
+ 0x3357, 0x1f6c,
+ 0x337b, 0x2083,
+ 0x337c, 0x1dc7,
+ 0x337d, 0x1dc6,
+ 0x337e, 0x1dc5,
+ 0x337f, 0x1f76,
+ 0x3385, 0x1f5f,
+ 0x3388, 0x2000,
+ 0x338e, 0x1db4,
+ 0x3390, 0x1f63,
+ 0x3396, 0x1f65,
+ 0x3397, 0x1f58,
+ 0x3398, 0x1f5a,
+ 0x339c, 0x1db1,
+ 0x339f, 0x1ffa,
+ 0x33a0, 0x1f54,
+ 0x33a1, 0x1db7,
+ 0x33a2, 0x1f55,
+ 0x33a3, 0x1ffb,
+ 0x33a4, 0x1f56,
+ 0x33a6, 0x1ffc,
+ 0x33b0, 0x1f5e,
+ 0x33b1, 0x1f5d,
+ 0x33b2, 0x1f5c,
+ 0x33b3, 0x1f5b,
+ 0x33c4, 0x1db6,
+ 0x33c8, 0x2002,
+ 0x33cb, 0x1f62,
+ 0x33cc, 0x1ff6,
+ 0x33cd, 0x1dbb,
+ 0x33d4, 0x1f64,
+ 0x4e00, 0x04b0,
+ 0x4e01, 0x0bb8,
+ 0x4e03, 0x08e3,
+ 0x4e07, 0x0eaa,
+ 0x4e08, 0x09ce,
+ 0x4e09, 0x087e,
+ 0x4e0a, 0x09cd,
+ 0x4e0b, 0x053c,
+ 0x4e0d, 0x0dc6,
+ 0x4e0e, 0x0f29,
+ 0x4e10, 0x0ffb,
+ 0x4e11, 0x04d1,
+ 0x4e14, 0x05cc,
+ 0x4e15, 0x0ffc,
+ 0x4e16, 0x0a48,
+ 0x4e17, 0x10d7,
+ 0x4e18, 0x0670,
+ 0x4e19, 0x0e0a,
+ 0x4e1e, 0x09cf,
+ 0x4e21, 0x0f86,
+ 0x4e26, 0x0e12,
+ 0x4e28, 0x20b3,
+ 0x4e2a, 0x0ffd,
+ 0x4e2d, 0x0ba4,
+ 0x4e31, 0x0ffe,
+ 0x4e32, 0x06f2,
+ 0x4e36, 0x0fff,
+ 0x4e38, 0x0619,
+ 0x4e39, 0x0b6e,
+ 0x4e3b, 0x0913,
+ 0x4e3c, 0x1000,
+ 0x4e3f, 0x1001,
+ 0x4e42, 0x1002,
+ 0x4e43, 0x0ceb,
+ 0x4e45, 0x0671,
+ 0x4e4b, 0x0ced,
+ 0x4e4d, 0x0cbb,
+ 0x4e4e, 0x0777,
+ 0x4e4f, 0x0e61,
+ 0x4e55, 0x1950,
+ 0x4e56, 0x1003,
+ 0x4e57, 0x09d0,
+ 0x4e58, 0x1004,
+ 0x4e59, 0x0535,
+ 0x4e5d, 0x06dd,
+ 0x4e5e, 0x07a4,
+ 0x4e5f, 0x0ef5,
+ 0x4e62, 0x1233,
+ 0x4e71, 0x0f5a,
+ 0x4e73, 0x0cd5,
+ 0x4e7e, 0x05e1,
+ 0x4e80, 0x064f,
+ 0x4e82, 0x1005,
+ 0x4e85, 0x1006,
+ 0x4e86, 0x0f83,
+ 0x4e88, 0x0f27,
+ 0x4e89, 0x0aea,
+ 0x4e8a, 0x1008,
+ 0x4e8b, 0x08c4,
+ 0x4e8c, 0x0ccb,
+ 0x4e8e, 0x100b,
+ 0x4e91, 0x04e0,
+ 0x4e92, 0x0793,
+ 0x4e94, 0x0792,
+ 0x4e95, 0x04aa,
+ 0x4e98, 0x0ff1,
+ 0x4e99, 0x0ff0,
+ 0x4e9b, 0x0823,
+ 0x4e9c, 0x0465,
+ 0x4e9e, 0x100c,
+ 0x4ea1, 0x0e62,
+ 0x4ea2, 0x100f,
+ 0x4ea4, 0x07a6,
+ 0x4ea5, 0x04ab,
+ 0x4ea6, 0x0ea0,
+ 0x4ea8, 0x0696,
+ 0x4eab, 0x0697,
+ 0x4ead, 0x0bfe,
+ 0x4eae, 0x0f84,
+ 0x4eb0, 0x1010,
+ 0x4eb3, 0x1011,
+ 0x4eb6, 0x1012,
+ 0x4eba, 0x0a13,
+ 0x4ec0, 0x0944,
+ 0x4ec1, 0x0a14,
+ 0x4ec2, 0x1017,
+ 0x4ec4, 0x1015,
+ 0x4ec6, 0x1016,
+ 0x4ec7, 0x0672,
+ 0x4eca, 0x0813,
+ 0x4ecb, 0x0570,
+ 0x4ecd, 0x1014,
+ 0x4ece, 0x1013,
+ 0x4ecf, 0x0df9,
+ 0x4ed4, 0x0894,
+ 0x4ed5, 0x0893,
+ 0x4ed6, 0x0b1e,
+ 0x4ed7, 0x1018,
+ 0x4ed8, 0x0dc7,
+ 0x4ed9, 0x0a8b,
+ 0x4edd, 0x0290,
+ 0x4ede, 0x1019,
+ 0x4edf, 0x101b,
+ 0x4ee1, 0x20b4,
+ 0x4ee3, 0x0b45,
+ 0x4ee4, 0x0fa9,
+ 0x4ee5, 0x048e,
+ 0x4eed, 0x101a,
+ 0x4eee, 0x053e,
+ 0x4ef0, 0x06bc,
+ 0x4ef2, 0x0ba5,
+ 0x4ef6, 0x0745,
+ 0x4ef7, 0x101c,
+ 0x4efb, 0x0cda,
+ 0x4efc, 0x20b5,
+ 0x4f00, 0x20b6,
+ 0x4f01, 0x0627,
+ 0x4f03, 0x20b7,
+ 0x4f09, 0x101d,
+ 0x4f0a, 0x048f,
+ 0x4f0d, 0x0794,
+ 0x4f0e, 0x0628,
+ 0x4f0f, 0x0dec,
+ 0x4f10, 0x0d46,
+ 0x4f11, 0x0673,
+ 0x4f1a, 0x0571,
+ 0x4f1c, 0x1040,
+ 0x4f1d, 0x0c3b,
+ 0x4f2f, 0x0d22,
+ 0x4f30, 0x101f,
+ 0x4f34, 0x0d50,
+ 0x4f36, 0x0faa,
+ 0x4f38, 0x09f3,
+ 0x4f39, 0x20b8,
+ 0x4f3a, 0x0895,
+ 0x4f3c, 0x08c5,
+ 0x4f3d, 0x0540,
+ 0x4f43, 0x0bed,
+ 0x4f46, 0x0b60,
+ 0x4f47, 0x1023,
+ 0x4f4d, 0x0490,
+ 0x4f4e, 0x0bff,
+ 0x4f4f, 0x0945,
+ 0x4f50, 0x0824,
+ 0x4f51, 0x0f0e,
+ 0x4f53, 0x0b2e,
+ 0x4f55, 0x053f,
+ 0x4f56, 0x20b9,
+ 0x4f57, 0x1022,
+ 0x4f59, 0x0f28,
+ 0x4f5a, 0x101e,
+ 0x4f5b, 0x1020,
+ 0x4f5c, 0x085e,
+ 0x4f5d, 0x1021,
+ 0x4f5e, 0x11d3,
+ 0x4f69, 0x1029,
+ 0x4f6f, 0x102c,
+ 0x4f70, 0x102a,
+ 0x4f73, 0x0542,
+ 0x4f75, 0x0e0b,
+ 0x4f76, 0x1024,
+ 0x4f7b, 0x1028,
+ 0x4f7c, 0x07a7,
+ 0x4f7f, 0x0896,
+ 0x4f83, 0x05e2,
+ 0x4f86, 0x102d,
+ 0x4f88, 0x1025,
+ 0x4f8a, 0x20bb,
+ 0x4f8b, 0x0fab,
+ 0x4f8d, 0x08c6,
+ 0x4f8f, 0x1026,
+ 0x4f91, 0x102b,
+ 0x4f92, 0x20ba,
+ 0x4f94, 0x20bd,
+ 0x4f96, 0x102e,
+ 0x4f98, 0x1027,
+ 0x4f9a, 0x20bc,
+ 0x4f9b, 0x0699,
+ 0x4f9d, 0x0491,
+ 0x4fa0, 0x069a,
+ 0x4fa1, 0x0541,
+ 0x4fab, 0x11d4,
+ 0x4fad, 0x0ea7,
+ 0x4fae, 0x0de0,
+ 0x4faf, 0x07a8,
+ 0x4fb5, 0x09f5,
+ 0x4fb6, 0x0f7f,
+ 0x4fbf, 0x0e28,
+ 0x4fc2, 0x070e,
+ 0x4fc3, 0x0b05,
+ 0x4fc4, 0x0564,
+ 0x4fc9, 0x20ac,
+ 0x4fca, 0x095d,
+ 0x4fcd, 0x20be,
+ 0x4fce, 0x1032,
+ 0x4fd0, 0x1037,
+ 0x4fd1, 0x1035,
+ 0x4fd4, 0x1030,
+ 0x4fd7, 0x0b0f,
+ 0x4fd8, 0x1033,
+ 0x4fda, 0x1036,
+ 0x4fdb, 0x1034,
+ 0x4fdd, 0x0e2d,
+ 0x4fdf, 0x1031,
+ 0x4fe0, 0x1dec,
+ 0x4fe1, 0x09f4,
+ 0x4fe3, 0x0ea1,
+ 0x4fe4, 0x1038,
+ 0x4fee, 0x092e,
+ 0x4fef, 0x1046,
+ 0x4ff3, 0x0d06,
+ 0x4ff5, 0x0da8,
+ 0x4ff6, 0x1041,
+ 0x4ff8, 0x0e40,
+ 0x4ffa, 0x0536,
+ 0x4ffe, 0x1045,
+ 0x4fff, 0x20c1,
+ 0x5005, 0x103f,
+ 0x5006, 0x1048,
+ 0x5009, 0x0ad4,
+ 0x500b, 0x0778,
+ 0x500d, 0x0d12,
+ 0x500f, 0x1600,
+ 0x5011, 0x1047,
+ 0x5012, 0x0c57,
+ 0x5014, 0x103c,
+ 0x5016, 0x07aa,
+ 0x5019, 0x07a9,
+ 0x501a, 0x103a,
+ 0x501e, 0x20c2,
+ 0x501f, 0x0906,
+ 0x5021, 0x1042,
+ 0x5022, 0x20c0,
+ 0x5023, 0x0e3f,
+ 0x5024, 0x0b8b,
+ 0x5025, 0x103e,
+ 0x5026, 0x0747,
+ 0x5028, 0x103b,
+ 0x5029, 0x1043,
+ 0x502a, 0x103d,
+ 0x502b, 0x0f99,
+ 0x502c, 0x1044,
+ 0x502d, 0x0fe7,
+ 0x5036, 0x06de,
+ 0x5039, 0x0746,
+ 0x5040, 0x20bf,
+ 0x5042, 0x20c5,
+ 0x5043, 0x1049,
+ 0x5046, 0x20c3,
+ 0x5047, 0x104a,
+ 0x5048, 0x104e,
+ 0x5049, 0x0492,
+ 0x504f, 0x0e20,
+ 0x5050, 0x104d,
+ 0x5055, 0x104c,
+ 0x5056, 0x1050,
+ 0x505a, 0x104f,
+ 0x505c, 0x0c00,
+ 0x5065, 0x0748,
+ 0x506c, 0x1051,
+ 0x5070, 0x20c4,
+ 0x5072, 0x08f1,
+ 0x5074, 0x0b06,
+ 0x5075, 0x0c01,
+ 0x5076, 0x06ee,
+ 0x5078, 0x1052,
+ 0x507d, 0x0650,
+ 0x5080, 0x1053,
+ 0x5085, 0x1055,
+ 0x508d, 0x0e63,
+ 0x5091, 0x073c,
+ 0x5094, 0x20c6,
+ 0x5098, 0x087f,
+ 0x5099, 0x0d8b,
+ 0x509a, 0x1054,
+ 0x50ac, 0x0835,
+ 0x50ad, 0x0f2d,
+ 0x50b2, 0x1057,
+ 0x50b3, 0x105a,
+ 0x50b4, 0x1056,
+ 0x50b5, 0x0834,
+ 0x50b7, 0x0987,
+ 0x50be, 0x070f,
+ 0x50c2, 0x105b,
+ 0x50c5, 0x06c7,
+ 0x50c9, 0x1058,
+ 0x50cd, 0x0c87,
+ 0x50cf, 0x0afe,
+ 0x50d1, 0x069b,
+ 0x50d5, 0x0e7b,
+ 0x50d6, 0x105c,
+ 0x50d8, 0x20c8,
+ 0x50da, 0x0f85,
+ 0x50de, 0x105d,
+ 0x50e3, 0x1060,
+ 0x50e5, 0x105e,
+ 0x50e7, 0x0ad0,
+ 0x50ed, 0x105f,
+ 0x50ee, 0x1061,
+ 0x50f4, 0x20c7,
+ 0x50f5, 0x1063,
+ 0x50f9, 0x1062,
+ 0x50fb, 0x0e18,
+ 0x5100, 0x0651,
+ 0x5101, 0x1065,
+ 0x5104, 0x052f,
+ 0x5109, 0x1064,
+ 0x5112, 0x0920,
+ 0x5114, 0x1069,
+ 0x5115, 0x1068,
+ 0x5116, 0x1067,
+ 0x5118, 0x102f,
+ 0x511a, 0x106a,
+ 0x511f, 0x0988,
+ 0x5121, 0x106b,
+ 0x512a, 0x0f0f,
+ 0x5132, 0x0ee5,
+ 0x5137, 0x106d,
+ 0x513a, 0x106c,
+ 0x513b, 0x106f,
+ 0x513c, 0x106e,
+ 0x513f, 0x1070,
+ 0x5141, 0x04b8,
+ 0x5143, 0x0769,
+ 0x5144, 0x0711,
+ 0x5145, 0x0946,
+ 0x5146, 0x0bb9,
+ 0x5147, 0x069c,
+ 0x5148, 0x0a8c,
+ 0x5149, 0x07ab,
+ 0x514a, 0x20c9,
+ 0x514b, 0x0800,
+ 0x514c, 0x1073,
+ 0x514d, 0x0ed4,
+ 0x514e, 0x0c40,
+ 0x5150, 0x08c7,
+ 0x5152, 0x1072,
+ 0x5154, 0x1074,
+ 0x515a, 0x0c58,
+ 0x515c, 0x05d3,
+ 0x5162, 0x1075,
+ 0x5164, 0x20ca,
+ 0x5165, 0x0cd6,
+ 0x5168, 0x0ab6,
+ 0x5169, 0x1077,
+ 0x516b, 0x0d40,
+ 0x516c, 0x07ac,
+ 0x516d, 0x0fe1,
+ 0x516e, 0x1079,
+ 0x5171, 0x069e,
+ 0x5175, 0x0e0c,
+ 0x5176, 0x0b16,
+ 0x5177, 0x06e9,
+ 0x5178, 0x0c2f,
+ 0x517c, 0x0749,
+ 0x5180, 0x107a,
+ 0x5182, 0x107b,
+ 0x5185, 0x0cba,
+ 0x5186, 0x0501,
+ 0x5189, 0x107e,
+ 0x518a, 0x086d,
+ 0x518c, 0x107d,
+ 0x518d, 0x0836,
+ 0x518f, 0x107f,
+ 0x5190, 0x185b,
+ 0x5191, 0x1080,
+ 0x5192, 0x0e6f,
+ 0x5193, 0x1081,
+ 0x5195, 0x1082,
+ 0x5197, 0x09d1,
+ 0x5199, 0x08f8,
+ 0x519d, 0x20cb,
+ 0x51a0, 0x05e3,
+ 0x51a2, 0x1086,
+ 0x51a4, 0x1084,
+ 0x51a5, 0x0ec9,
+ 0x51a6, 0x1085,
+ 0x51a8, 0x0dcc,
+ 0x51a9, 0x1087,
+ 0x51ac, 0x0c59,
+ 0x51b0, 0x108d,
+ 0x51b1, 0x108b,
+ 0x51b3, 0x108a,
+ 0x51b4, 0x0853,
+ 0x51b5, 0x108e,
+ 0x51b6, 0x0ef6,
+ 0x51b7, 0x0fac,
+ 0x51bd, 0x108f,
+ 0x51be, 0x20cc,
+ 0x51c4, 0x0a4c,
+ 0x51c5, 0x1090,
+ 0x51c6, 0x0964,
+ 0x51c9, 0x1091,
+ 0x51cb, 0x0bba,
+ 0x51cc, 0x0f87,
+ 0x51cd, 0x0c5a,
+ 0x51d6, 0x10da,
+ 0x51db, 0x1092,
+ 0x51dc, 0x205c,
+ 0x51dd, 0x06bd,
+ 0x51e0, 0x1093,
+ 0x51e1, 0x0e8c,
+ 0x51e6, 0x0972,
+ 0x51e7, 0x0b5c,
+ 0x51e9, 0x1095,
+ 0x51ea, 0x0cbc,
+ 0x51ec, 0x20cd,
+ 0x51ed, 0x1096,
+ 0x51f0, 0x1097,
+ 0x51f1, 0x058c,
+ 0x51f5, 0x1098,
+ 0x51f6, 0x069f,
+ 0x51f8, 0x0ca4,
+ 0x51f9, 0x051c,
+ 0x51fa, 0x095a,
+ 0x51fd, 0x0d35,
+ 0x51fe, 0x1099,
+ 0x5200, 0x0c5b,
+ 0x5203, 0x0a15,
+ 0x5204, 0x109a,
+ 0x5206, 0x0dfc,
+ 0x5207, 0x0a7e,
+ 0x5208, 0x05de,
+ 0x520a, 0x05e5,
+ 0x520b, 0x109b,
+ 0x520e, 0x109d,
+ 0x5211, 0x0710,
+ 0x5214, 0x109c,
+ 0x5215, 0x20ce,
+ 0x5217, 0x0fbb,
+ 0x521d, 0x0973,
+ 0x5224, 0x0d51,
+ 0x5225, 0x0e1c,
+ 0x5227, 0x109e,
+ 0x5229, 0x0f62,
+ 0x522a, 0x109f,
+ 0x522e, 0x10a0,
+ 0x5230, 0x0c78,
+ 0x5233, 0x10a1,
+ 0x5236, 0x0a4d,
+ 0x5237, 0x086e,
+ 0x5238, 0x074a,
+ 0x5239, 0x10a2,
+ 0x523a, 0x0897,
+ 0x523b, 0x0801,
+ 0x5243, 0x0c02,
+ 0x5244, 0x10a4,
+ 0x5247, 0x0b07,
+ 0x524a, 0x085f,
+ 0x524b, 0x10a5,
+ 0x524d, 0x0ab2,
+ 0x524f, 0x10a3,
+ 0x5254, 0x10a8,
+ 0x5256, 0x0e64,
+ 0x525b, 0x07f6,
+ 0x525d, 0x1e5e,
+ 0x525e, 0x10a7,
+ 0x5263, 0x074b,
+ 0x5264, 0x084e,
+ 0x5265, 0x0d23,
+ 0x5269, 0x10ab,
+ 0x526a, 0x10a9,
+ 0x526f, 0x0ded,
+ 0x5270, 0x09d2,
+ 0x5271, 0x10b2,
+ 0x5272, 0x05c2,
+ 0x5273, 0x10ac,
+ 0x5274, 0x10aa,
+ 0x5275, 0x0ad1,
+ 0x527d, 0x10ae,
+ 0x527f, 0x10ad,
+ 0x5283, 0x05a2,
+ 0x5287, 0x0736,
+ 0x5288, 0x10b3,
+ 0x5289, 0x0f75,
+ 0x528d, 0x10af,
+ 0x5291, 0x10b4,
+ 0x5292, 0x10b1,
+ 0x5294, 0x10b0,
+ 0x529b, 0x0f97,
+ 0x529c, 0x20cf,
+ 0x529f, 0x07ad,
+ 0x52a0, 0x0543,
+ 0x52a3, 0x0fbc,
+ 0x52a6, 0x20d0,
+ 0x52a9, 0x097f,
+ 0x52aa, 0x0c52,
+ 0x52ab, 0x07f7,
+ 0x52ac, 0x10b7,
+ 0x52af, 0x217d,
+ 0x52b1, 0x0fad,
+ 0x52b4, 0x0fd1,
+ 0x52b5, 0x10ba,
+ 0x52b9, 0x07ae,
+ 0x52bc, 0x10b9,
+ 0x52be, 0x058d,
+ 0x52c0, 0x20d1,
+ 0x52c1, 0x10bb,
+ 0x52c3, 0x0e84,
+ 0x52c5, 0x0bd8,
+ 0x52c7, 0x0f10,
+ 0x52c9, 0x0e29,
+ 0x52cd, 0x10bc,
+ 0x52d2, 0x1bee,
+ 0x52d5, 0x0c88,
+ 0x52d7, 0x10bd,
+ 0x52d8, 0x05e6,
+ 0x52d9, 0x0ebf,
+ 0x52db, 0x20d2,
+ 0x52dd, 0x0989,
+ 0x52de, 0x10be,
+ 0x52df, 0x0e37,
+ 0x52e0, 0x10c2,
+ 0x52e2, 0x0a4e,
+ 0x52e3, 0x10bf,
+ 0x52e4, 0x06c8,
+ 0x52e6, 0x10c0,
+ 0x52e7, 0x05e7,
+ 0x52f2, 0x0704,
+ 0x52f3, 0x10c3,
+ 0x52f5, 0x10c4,
+ 0x52f8, 0x10c5,
+ 0x52fa, 0x0907,
+ 0x52fe, 0x07af,
+ 0x52ff, 0x0eea,
+ 0x5300, 0x20d3,
+ 0x5301, 0x0ef4,
+ 0x5302, 0x0ccf,
+ 0x5305, 0x0e41,
+ 0x5306, 0x10c7,
+ 0x5307, 0x20d4,
+ 0x5308, 0x10c8,
+ 0x530d, 0x10ca,
+ 0x530f, 0x10cc,
+ 0x5310, 0x10cb,
+ 0x5315, 0x10cd,
+ 0x5316, 0x053d,
+ 0x5317, 0x0e7a,
+ 0x5319, 0x086c,
+ 0x531a, 0x10ce,
+ 0x531d, 0x0adb,
+ 0x5320, 0x098a,
+ 0x5321, 0x06a1,
+ 0x5323, 0x10cf,
+ 0x5324, 0x20d5,
+ 0x532a, 0x0d6f,
+ 0x532f, 0x10d0,
+ 0x5331, 0x10d1,
+ 0x5333, 0x10d2,
+ 0x5338, 0x10d3,
+ 0x5339, 0x0d96,
+ 0x533a, 0x06e0,
+ 0x533b, 0x04a9,
+ 0x533f, 0x0c97,
+ 0x5340, 0x10d4,
+ 0x5341, 0x0947,
+ 0x5343, 0x0a8d,
+ 0x5345, 0x10d6,
+ 0x5346, 0x10d5,
+ 0x5347, 0x098b,
+ 0x5348, 0x0795,
+ 0x5349, 0x10d8,
+ 0x534a, 0x0d52,
+ 0x534d, 0x10d9,
+ 0x5351, 0x0d70,
+ 0x5352, 0x0b14,
+ 0x5353, 0x0b4e,
+ 0x5354, 0x06a0,
+ 0x5357, 0x0cc6,
+ 0x5358, 0x0b6f,
+ 0x535a, 0x0d24,
+ 0x535c, 0x0e7c,
+ 0x535e, 0x10db,
+ 0x5360, 0x0a8e,
+ 0x5366, 0x070b,
+ 0x5369, 0x10dc,
+ 0x536e, 0x10dd,
+ 0x536f, 0x04ce,
+ 0x5370, 0x04b9,
+ 0x5371, 0x0629,
+ 0x5372, 0x20d6,
+ 0x5373, 0x0b08,
+ 0x5374, 0x066b,
+ 0x5375, 0x0f5b,
+ 0x5377, 0x10e0,
+ 0x5378, 0x0537,
+ 0x537b, 0x10df,
+ 0x537f, 0x06a2,
+ 0x5382, 0x10e1,
+ 0x5384, 0x0efd,
+ 0x5393, 0x20d7,
+ 0x5396, 0x10e2,
+ 0x5398, 0x0f9a,
+ 0x539a, 0x07b0,
+ 0x539f, 0x076a,
+ 0x53a0, 0x10e3,
+ 0x53a5, 0x10e5,
+ 0x53a6, 0x10e4,
+ 0x53a8, 0x0a25,
+ 0x53a9, 0x04db,
+ 0x53ad, 0x0500,
+ 0x53ae, 0x10e6,
+ 0x53b0, 0x10e7,
+ 0x53b2, 0x20d8,
+ 0x53b3, 0x076b,
+ 0x53b6, 0x10e8,
+ 0x53bb, 0x0688,
+ 0x53c2, 0x0880,
+ 0x53c3, 0x10e9,
+ 0x53c8, 0x0ea2,
+ 0x53c9, 0x0825,
+ 0x53ca, 0x0674,
+ 0x53cb, 0x0f11,
+ 0x53cc, 0x0ad2,
+ 0x53cd, 0x0d53,
+ 0x53ce, 0x0929,
+ 0x53d4, 0x0951,
+ 0x53d6, 0x0914,
+ 0x53d7, 0x0921,
+ 0x53d9, 0x0980,
+ 0x53db, 0x0d54,
+ 0x53dd, 0x20d9,
+ 0x53df, 0x10ec,
+ 0x53e1, 0x04e5,
+ 0x53e2, 0x0ad3,
+ 0x53e3, 0x07b1,
+ 0x53e4, 0x0779,
+ 0x53e5, 0x06df,
+ 0x53e8, 0x10f0,
+ 0x53e9, 0x0b5f,
+ 0x53ea, 0x0b5e,
+ 0x53eb, 0x06a3,
+ 0x53ec, 0x098c,
+ 0x53ed, 0x10f1,
+ 0x53ee, 0x10ef,
+ 0x53ef, 0x0544,
+ 0x53f0, 0x0b46,
+ 0x53f1, 0x08e4,
+ 0x53f2, 0x0899,
+ 0x53f3, 0x04c8,
+ 0x53f6, 0x05ce,
+ 0x53f7, 0x07f8,
+ 0x53f8, 0x0898,
+ 0x53fa, 0x10f2,
+ 0x5401, 0x10f3,
+ 0x5403, 0x0663,
+ 0x5404, 0x05a4,
+ 0x5408, 0x07f9,
+ 0x5409, 0x0662,
+ 0x540a, 0x0bfb,
+ 0x540b, 0x04c7,
+ 0x540c, 0x0c89,
+ 0x540d, 0x0eca,
+ 0x540e, 0x07b3,
+ 0x540f, 0x0f63,
+ 0x5410, 0x0c41,
+ 0x5411, 0x07b2,
+ 0x541b, 0x0705,
+ 0x541d, 0x10fc,
+ 0x541f, 0x06db,
+ 0x5420, 0x0e78,
+ 0x5426, 0x0d71,
+ 0x5429, 0x10fb,
+ 0x542b, 0x061a,
+ 0x542c, 0x10f6,
+ 0x542e, 0x10f9,
+ 0x5436, 0x10fa,
+ 0x5438, 0x0675,
+ 0x5439, 0x0a27,
+ 0x543b, 0x0dfd,
+ 0x543c, 0x10f8,
+ 0x543d, 0x10f4,
+ 0x543e, 0x0797,
+ 0x5440, 0x10f5,
+ 0x5442, 0x0fca,
+ 0x5446, 0x0e42,
+ 0x5448, 0x0c04,
+ 0x5449, 0x0796,
+ 0x544a, 0x0802,
+ 0x544e, 0x10fd,
+ 0x5451, 0x0cb5,
+ 0x545f, 0x1101,
+ 0x5468, 0x092a,
+ 0x546a, 0x0922,
+ 0x5470, 0x1104,
+ 0x5471, 0x1102,
+ 0x5473, 0x0eaf,
+ 0x5475, 0x10ff,
+ 0x5476, 0x1108,
+ 0x5477, 0x1103,
+ 0x547b, 0x1106,
+ 0x547c, 0x077a,
+ 0x547d, 0x0ecb,
+ 0x5480, 0x1107,
+ 0x5484, 0x1109,
+ 0x5486, 0x110b,
+ 0x548a, 0x20dc,
+ 0x548b, 0x0860,
+ 0x548c, 0x0fe8,
+ 0x548e, 0x1100,
+ 0x548f, 0x10fe,
+ 0x5490, 0x110a,
+ 0x5492, 0x1105,
+ 0x549c, 0x20db,
+ 0x54a2, 0x110d,
+ 0x54a4, 0x1116,
+ 0x54a5, 0x110f,
+ 0x54a8, 0x1113,
+ 0x54a9, 0x20dd,
+ 0x54ab, 0x1114,
+ 0x54ac, 0x1110,
+ 0x54af, 0x1131,
+ 0x54b2, 0x0859,
+ 0x54b3, 0x058f,
+ 0x54b8, 0x110e,
+ 0x54bc, 0x1118,
+ 0x54bd, 0x04ba,
+ 0x54be, 0x1117,
+ 0x54c0, 0x0469,
+ 0x54c1, 0x0dbc,
+ 0x54c2, 0x1115,
+ 0x54c4, 0x1111,
+ 0x54c7, 0x110c,
+ 0x54c8, 0x1112,
+ 0x54c9, 0x0838,
+ 0x54d8, 0x1119,
+ 0x54e1, 0x04bb,
+ 0x54e2, 0x1122,
+ 0x54e5, 0x111a,
+ 0x54e8, 0x098d,
+ 0x54e9, 0x0e97,
+ 0x54ed, 0x1120,
+ 0x54ee, 0x111f,
+ 0x54f2, 0x0c29,
+ 0x54fa, 0x1121,
+ 0x54fd, 0x111e,
+ 0x54ff, 0x20de,
+ 0x5504, 0x04d6,
+ 0x5506, 0x0826,
+ 0x5507, 0x09f6,
+ 0x550f, 0x111c,
+ 0x5510, 0x0c5c,
+ 0x5514, 0x111d,
+ 0x5516, 0x0466,
+ 0x552e, 0x1127,
+ 0x552f, 0x0f0d,
+ 0x5531, 0x098f,
+ 0x5533, 0x112d,
+ 0x5538, 0x112c,
+ 0x5539, 0x1123,
+ 0x553e, 0x0b23,
+ 0x5540, 0x1124,
+ 0x5544, 0x0b4f,
+ 0x5545, 0x1129,
+ 0x5546, 0x098e,
+ 0x554c, 0x1126,
+ 0x554f, 0x0ef0,
+ 0x5553, 0x0712,
+ 0x5556, 0x112a,
+ 0x555c, 0x1128,
+ 0x555d, 0x112e,
+ 0x555e, 0x1dd1,
+ 0x5563, 0x1125,
+ 0x557b, 0x1134,
+ 0x557c, 0x1139,
+ 0x557e, 0x1135,
+ 0x5580, 0x1130,
+ 0x5583, 0x113a,
+ 0x5584, 0x0ab3,
+ 0x5586, 0x20df,
+ 0x5587, 0x113c,
+ 0x5589, 0x07b4,
+ 0x558a, 0x1132,
+ 0x558b, 0x0bbb,
+ 0x5598, 0x1136,
+ 0x5599, 0x112f,
+ 0x559a, 0x05e9,
+ 0x559c, 0x062a,
+ 0x559d, 0x05c3,
+ 0x559e, 0x1137,
+ 0x559f, 0x1133,
+ 0x55a7, 0x074c,
+ 0x55a8, 0x113d,
+ 0x55a9, 0x113b,
+ 0x55aa, 0x0ad5,
+ 0x55ab, 0x0664,
+ 0x55ac, 0x06a4,
+ 0x55ae, 0x1138,
+ 0x55b0, 0x06ec,
+ 0x55b6, 0x04e6,
+ 0x55c4, 0x1141,
+ 0x55c5, 0x113f,
+ 0x55c7, 0x1178,
+ 0x55d4, 0x1144,
+ 0x55da, 0x113e,
+ 0x55dc, 0x1142,
+ 0x55df, 0x1140,
+ 0x55e3, 0x089a,
+ 0x55e4, 0x1143,
+ 0x55f7, 0x1146,
+ 0x55f9, 0x114b,
+ 0x55fd, 0x1149,
+ 0x55fe, 0x1148,
+ 0x5606, 0x0b70,
+ 0x5609, 0x0545,
+ 0x5614, 0x1145,
+ 0x5616, 0x1147,
+ 0x5617, 0x0990,
+ 0x5618, 0x04d5,
+ 0x561b, 0x114a,
+ 0x5629, 0x055e,
+ 0x562f, 0x1155,
+ 0x5631, 0x09e4,
+ 0x5632, 0x1151,
+ 0x5634, 0x114f,
+ 0x5636, 0x1150,
+ 0x5638, 0x1152,
+ 0x5642, 0x04df,
+ 0x564c, 0x0abb,
+ 0x564e, 0x114c,
+ 0x5650, 0x114d,
+ 0x5653, 0x1f1b,
+ 0x565b, 0x05d8,
+ 0x5664, 0x1154,
+ 0x5668, 0x062b,
+ 0x566a, 0x1157,
+ 0x566b, 0x1153,
+ 0x566c, 0x1156,
+ 0x5674, 0x0dfe,
+ 0x5678, 0x0cad,
+ 0x567a, 0x0d4c,
+ 0x5680, 0x1159,
+ 0x5686, 0x1158,
+ 0x5687, 0x05a3,
+ 0x568a, 0x115a,
+ 0x568f, 0x115d,
+ 0x5694, 0x115c,
+ 0x5699, 0x1de6,
+ 0x56a0, 0x115b,
+ 0x56a2, 0x0cef,
+ 0x56a5, 0x115e,
+ 0x56ae, 0x115f,
+ 0x56b4, 0x1161,
+ 0x56b6, 0x1160,
+ 0x56bc, 0x1163,
+ 0x56c0, 0x1166,
+ 0x56c1, 0x1164,
+ 0x56c2, 0x1162,
+ 0x56c3, 0x1165,
+ 0x56c8, 0x1167,
+ 0x56ca, 0x1e5a,
+ 0x56ce, 0x1168,
+ 0x56d1, 0x1169,
+ 0x56d3, 0x116a,
+ 0x56d7, 0x116b,
+ 0x56d8, 0x107c,
+ 0x56da, 0x0928,
+ 0x56db, 0x089b,
+ 0x56de, 0x0573,
+ 0x56e0, 0x04bc,
+ 0x56e3, 0x0b82,
+ 0x56ee, 0x116c,
+ 0x56f0, 0x0814,
+ 0x56f2, 0x0493,
+ 0x56f3, 0x0a24,
+ 0x56f9, 0x116d,
+ 0x56fa, 0x077b,
+ 0x56fd, 0x0803,
+ 0x56ff, 0x116f,
+ 0x5700, 0x116e,
+ 0x5703, 0x0e30,
+ 0x5704, 0x1170,
+ 0x5708, 0x1172,
+ 0x5709, 0x1171,
+ 0x570b, 0x1173,
+ 0x570d, 0x1174,
+ 0x570f, 0x074d,
+ 0x5712, 0x0502,
+ 0x5713, 0x1175,
+ 0x5716, 0x1177,
+ 0x5718, 0x1176,
+ 0x571c, 0x1179,
+ 0x571f, 0x0c54,
+ 0x5726, 0x117a,
+ 0x5727, 0x0479,
+ 0x5728, 0x084f,
+ 0x572d, 0x0713,
+ 0x5730, 0x0b8d,
+ 0x5737, 0x117b,
+ 0x573b, 0x117e,
+ 0x5740, 0x117f,
+ 0x5742, 0x0854,
+ 0x5747, 0x06c9,
+ 0x574a, 0x0e65,
+ 0x574e, 0x117d,
+ 0x574f, 0x1180,
+ 0x5750, 0x0831,
+ 0x5751, 0x07b5,
+ 0x5759, 0x20e0,
+ 0x5761, 0x1184,
+ 0x5764, 0x0815,
+ 0x5765, 0x20e1,
+ 0x5766, 0x0b71,
+ 0x5769, 0x1181,
+ 0x576a, 0x0bf6,
+ 0x577f, 0x1185,
+ 0x5782, 0x0a28,
+ 0x5788, 0x1183,
+ 0x5789, 0x1186,
+ 0x578b, 0x0715,
+ 0x5793, 0x1187,
+ 0x57a0, 0x1188,
+ 0x57a2, 0x07b6,
+ 0x57a3, 0x059e,
+ 0x57a4, 0x118a,
+ 0x57aa, 0x118b,
+ 0x57ac, 0x20e2,
+ 0x57b0, 0x118c,
+ 0x57b3, 0x1189,
+ 0x57c0, 0x1182,
+ 0x57c3, 0x118d,
+ 0x57c6, 0x118e,
+ 0x57c7, 0x20e4,
+ 0x57c8, 0x20e3,
+ 0x57cb, 0x0e92,
+ 0x57ce, 0x09d3,
+ 0x57d2, 0x1190,
+ 0x57d4, 0x118f,
+ 0x57d6, 0x1193,
+ 0x57dc, 0x0cee,
+ 0x57df, 0x04ac,
+ 0x57e0, 0x0dc8,
+ 0x57e3, 0x1194,
+ 0x57f4, 0x09e5,
+ 0x57f7, 0x08e5,
+ 0x57f9, 0x0d13,
+ 0x57fa, 0x062c,
+ 0x57fc, 0x085b,
+ 0x5800, 0x0e87,
+ 0x5802, 0x0c8a,
+ 0x5805, 0x074e,
+ 0x5806, 0x0b2f,
+ 0x580a, 0x1192,
+ 0x580b, 0x1195,
+ 0x5815, 0x0b24,
+ 0x5819, 0x1196,
+ 0x581d, 0x1197,
+ 0x5821, 0x1199,
+ 0x5824, 0x0c05,
+ 0x582a, 0x05ea,
+ 0x582f, 0x1d32,
+ 0x5830, 0x0503,
+ 0x5831, 0x0e43,
+ 0x5834, 0x09d4,
+ 0x5835, 0x0c42,
+ 0x583a, 0x0856,
+ 0x583d, 0x119f,
+ 0x5840, 0x0e0d,
+ 0x5841, 0x0fa5,
+ 0x584a, 0x0574,
+ 0x584b, 0x119b,
+ 0x5851, 0x0abc,
+ 0x5852, 0x119e,
+ 0x5854, 0x0c5d,
+ 0x5857, 0x0c43,
+ 0x5858, 0x0c5e,
+ 0x5859, 0x0d4d,
+ 0x585a, 0x0be9,
+ 0x585e, 0x0839,
+ 0x5861, 0x1e47,
+ 0x5862, 0x119a,
+ 0x5869, 0x0518,
+ 0x586b, 0x0c30,
+ 0x5870, 0x119c,
+ 0x5872, 0x1198,
+ 0x5875, 0x0a16,
+ 0x5879, 0x11a0,
+ 0x587e, 0x0958,
+ 0x5883, 0x06a5,
+ 0x5885, 0x11a1,
+ 0x5893, 0x0e38,
+ 0x5897, 0x0aff,
+ 0x589c, 0x0be2,
+ 0x589e, 0x20e7,
+ 0x589f, 0x11a3,
+ 0x58a8, 0x0e7d,
+ 0x58ab, 0x11a4,
+ 0x58ae, 0x11a9,
+ 0x58b2, 0x20e8,
+ 0x58b3, 0x0dff,
+ 0x58b8, 0x11a8,
+ 0x58b9, 0x11a2,
+ 0x58ba, 0x11a5,
+ 0x58bb, 0x11a7,
+ 0x58be, 0x0816,
+ 0x58c1, 0x0e19,
+ 0x58c5, 0x11aa,
+ 0x58c7, 0x0b83,
+ 0x58ca, 0x0575,
+ 0x58cc, 0x09d5,
+ 0x58d1, 0x11ac,
+ 0x58d3, 0x11ab,
+ 0x58d5, 0x07fa,
+ 0x58d7, 0x11ad,
+ 0x58d8, 0x11af,
+ 0x58d9, 0x11ae,
+ 0x58dc, 0x11b1,
+ 0x58de, 0x11a6,
+ 0x58df, 0x11b3,
+ 0x58e4, 0x11b2,
+ 0x58e5, 0x11b0,
+ 0x58eb, 0x089c,
+ 0x58ec, 0x0a17,
+ 0x58ee, 0x0ad6,
+ 0x58ef, 0x11b4,
+ 0x58f0, 0x0a60,
+ 0x58f1, 0x04b1,
+ 0x58f2, 0x0d1a,
+ 0x58f7, 0x0bf7,
+ 0x58f9, 0x11b6,
+ 0x58fa, 0x11b5,
+ 0x58fb, 0x11b7,
+ 0x5902, 0x11ba,
+ 0x5909, 0x0e21,
+ 0x590a, 0x11bb,
+ 0x590b, 0x20e9,
+ 0x590f, 0x0546,
+ 0x5910, 0x11bc,
+ 0x5915, 0x0f26,
+ 0x5916, 0x058e,
+ 0x5918, 0x10de,
+ 0x5919, 0x0952,
+ 0x591a, 0x0b1f,
+ 0x591b, 0x11bd,
+ 0x591c, 0x0ef7,
+ 0x5922, 0x0ec0,
+ 0x5925, 0x11bf,
+ 0x5927, 0x0b47,
+ 0x5929, 0x0c31,
+ 0x592a, 0x0b20,
+ 0x592b, 0x0dc9,
+ 0x592c, 0x11c0,
+ 0x592e, 0x051d,
+ 0x5931, 0x08e6,
+ 0x5932, 0x11c2,
+ 0x5937, 0x0494,
+ 0x5938, 0x11c3,
+ 0x593e, 0x11c4,
+ 0x5944, 0x0504,
+ 0x5947, 0x062d,
+ 0x5948, 0x0cb8,
+ 0x5949, 0x0e44,
+ 0x594e, 0x11c8,
+ 0x594f, 0x0ad7,
+ 0x5950, 0x11c7,
+ 0x5951, 0x0716,
+ 0x5953, 0x20ea,
+ 0x5954, 0x0e89,
+ 0x5955, 0x11c6,
+ 0x5957, 0x0c5f,
+ 0x5958, 0x11ca,
+ 0x595a, 0x11c9,
+ 0x595b, 0x20eb,
+ 0x595d, 0x20ec,
+ 0x5960, 0x11cc,
+ 0x5962, 0x11cb,
+ 0x5963, 0x20ed,
+ 0x5965, 0x051e,
+ 0x5967, 0x11cd,
+ 0x5968, 0x0991,
+ 0x5969, 0x11cf,
+ 0x596a, 0x0b63,
+ 0x596c, 0x11ce,
+ 0x596e, 0x0e03,
+ 0x5973, 0x0981,
+ 0x5974, 0x0c55,
+ 0x5978, 0x11d0,
+ 0x597d, 0x07b7,
+ 0x5981, 0x11d1,
+ 0x5982, 0x0cd7,
+ 0x5983, 0x0d72,
+ 0x5984, 0x0edd,
+ 0x598a, 0x0cdb,
+ 0x598d, 0x11da,
+ 0x5993, 0x0652,
+ 0x5996, 0x0f2f,
+ 0x5999, 0x0ebb,
+ 0x599b, 0x1239,
+ 0x599d, 0x11d2,
+ 0x59a3, 0x11d5,
+ 0x59a4, 0x20ee,
+ 0x59a5, 0x0b25,
+ 0x59a8, 0x0e66,
+ 0x59ac, 0x0c44,
+ 0x59b2, 0x11d6,
+ 0x59b9, 0x0e93,
+ 0x59ba, 0x20ef,
+ 0x59bb, 0x083a,
+ 0x59be, 0x0992,
+ 0x59c6, 0x11d7,
+ 0x59c9, 0x089e,
+ 0x59cb, 0x089d,
+ 0x59d0, 0x047d,
+ 0x59d1, 0x077c,
+ 0x59d3, 0x0a4f,
+ 0x59d4, 0x0495,
+ 0x59d9, 0x11db,
+ 0x59dc, 0x11d9,
+ 0x59e5, 0x04da,
+ 0x59e6, 0x05eb,
+ 0x59e8, 0x11d8,
+ 0x59ea, 0x0ed1,
+ 0x59eb, 0x0da3,
+ 0x59f6, 0x046c,
+ 0x59fb, 0x04bd,
+ 0x59ff, 0x089f,
+ 0x5a01, 0x0496,
+ 0x5a03, 0x0467,
+ 0x5a09, 0x11e1,
+ 0x5a11, 0x11df,
+ 0x5a18, 0x0ec8,
+ 0x5a1a, 0x11e2,
+ 0x5a1c, 0x11e0,
+ 0x5a1f, 0x11de,
+ 0x5a20, 0x09f7,
+ 0x5a25, 0x11dd,
+ 0x5a29, 0x0e2a,
+ 0x5a2f, 0x0798,
+ 0x5a35, 0x11e6,
+ 0x5a3c, 0x0993,
+ 0x5a40, 0x11e3,
+ 0x5a41, 0x0fd2,
+ 0x5a46, 0x0d02,
+ 0x5a49, 0x11e5,
+ 0x5a5a, 0x0817,
+ 0x5a62, 0x11e8,
+ 0x5a66, 0x0dca,
+ 0x5a6a, 0x11e9,
+ 0x5a6c, 0x11e4,
+ 0x5a7f, 0x0ec7,
+ 0x5a92, 0x0d14,
+ 0x5a9a, 0x11ea,
+ 0x5a9b, 0x0da4,
+ 0x5abc, 0x11eb,
+ 0x5abd, 0x11ef,
+ 0x5abe, 0x11ec,
+ 0x5ac1, 0x0547,
+ 0x5ac2, 0x11ee,
+ 0x5ac9, 0x08e7,
+ 0x5acb, 0x11ed,
+ 0x5acc, 0x074f,
+ 0x5ad0, 0x11fb,
+ 0x5ad6, 0x11f4,
+ 0x5ad7, 0x11f1,
+ 0x5ae1, 0x0ba2,
+ 0x5ae3, 0x11f0,
+ 0x5ae6, 0x11f2,
+ 0x5ae9, 0x11f3,
+ 0x5afa, 0x11f5,
+ 0x5b09, 0x062e,
+ 0x5b0b, 0x11f8,
+ 0x5b0c, 0x11f7,
+ 0x5b16, 0x11f9,
+ 0x5b22, 0x09d6,
+ 0x5b2a, 0x11fc,
+ 0x5b2c, 0x0bf8,
+ 0x5b30, 0x04e7,
+ 0x5b32, 0x11fa,
+ 0x5b36, 0x11fd,
+ 0x5b3e, 0x11fe,
+ 0x5b40, 0x1201,
+ 0x5b43, 0x11ff,
+ 0x5b45, 0x1200,
+ 0x5b50, 0x08a0,
+ 0x5b51, 0x1202,
+ 0x5b54, 0x07b8,
+ 0x5b55, 0x1203,
+ 0x5b56, 0x20f0,
+ 0x5b57, 0x08c8,
+ 0x5b58, 0x0b18,
+ 0x5b5a, 0x1204,
+ 0x5b5c, 0x08a8,
+ 0x5b5d, 0x07b9,
+ 0x5b5f, 0x0ede,
+ 0x5b63, 0x0642,
+ 0x5b64, 0x077d,
+ 0x5b65, 0x1206,
+ 0x5b66, 0x05b6,
+ 0x5b69, 0x1207,
+ 0x5b6b, 0x0b19,
+ 0x5b70, 0x1208,
+ 0x5b71, 0x1230,
+ 0x5b73, 0x1209,
+ 0x5b75, 0x120a,
+ 0x5b78, 0x120b,
+ 0x5b7a, 0x120d,
+ 0x5b80, 0x120e,
+ 0x5b83, 0x120f,
+ 0x5b85, 0x0b50,
+ 0x5b87, 0x04c9,
+ 0x5b88, 0x0915,
+ 0x5b89, 0x0486,
+ 0x5b8b, 0x0ad9,
+ 0x5b8c, 0x05ec,
+ 0x5b8d, 0x08e1,
+ 0x5b8f, 0x07ba,
+ 0x5b95, 0x0c60,
+ 0x5b97, 0x092b,
+ 0x5b98, 0x05ed,
+ 0x5b99, 0x0ba6,
+ 0x5b9a, 0x0c06,
+ 0x5b9b, 0x047c,
+ 0x5b9c, 0x0653,
+ 0x5b9d, 0x0e45,
+ 0x5b9f, 0x08ee,
+ 0x5ba2, 0x066c,
+ 0x5ba3, 0x0a8f,
+ 0x5ba4, 0x08e8,
+ 0x5ba5, 0x0f12,
+ 0x5ba6, 0x1210,
+ 0x5bae, 0x0676,
+ 0x5bb0, 0x083b,
+ 0x5bb3, 0x0590,
+ 0x5bb4, 0x0505,
+ 0x5bb5, 0x0994,
+ 0x5bb6, 0x0548,
+ 0x5bb8, 0x1211,
+ 0x5bb9, 0x0f30,
+ 0x5bbf, 0x0953,
+ 0x5bc0, 0x20f1,
+ 0x5bc2, 0x0910,
+ 0x5bc3, 0x1212,
+ 0x5bc4, 0x062f,
+ 0x5bc5, 0x0caa,
+ 0x5bc6, 0x0eb5,
+ 0x5bc7, 0x1213,
+ 0x5bc9, 0x1214,
+ 0x5bcc, 0x0dcb,
+ 0x5bd0, 0x1216,
+ 0x5bd2, 0x05e4,
+ 0x5bd3, 0x06ef,
+ 0x5bd4, 0x1215,
+ 0x5bd8, 0x20f3,
+ 0x5bdb, 0x05ee,
+ 0x5bdd, 0x09f8,
+ 0x5bde, 0x121a,
+ 0x5bdf, 0x086f,
+ 0x5be1, 0x0549,
+ 0x5be2, 0x1219,
+ 0x5be4, 0x1217,
+ 0x5be5, 0x121b,
+ 0x5be6, 0x1218,
+ 0x5be7, 0x0ce1,
+ 0x5be8, 0x148e,
+ 0x5be9, 0x09f9,
+ 0x5beb, 0x121c,
+ 0x5bec, 0x20f4,
+ 0x5bee, 0x0f88,
+ 0x5bf0, 0x121d,
+ 0x5bf3, 0x121f,
+ 0x5bf5, 0x0bbc,
+ 0x5bf6, 0x121e,
+ 0x5bf8, 0x0a47,
+ 0x5bfa, 0x08c9,
+ 0x5bfe, 0x0b30,
+ 0x5bff, 0x0923,
+ 0x5c01, 0x0de7,
+ 0x5c02, 0x0a90,
+ 0x5c04, 0x08f9,
+ 0x5c05, 0x1220,
+ 0x5c06, 0x0995,
+ 0x5c07, 0x1221,
+ 0x5c09, 0x0497,
+ 0x5c0a, 0x0b1a,
+ 0x5c0b, 0x0a18,
+ 0x5c0d, 0x1223,
+ 0x5c0e, 0x0c8b,
+ 0x5c0f, 0x0996,
+ 0x5c11, 0x0997,
+ 0x5c13, 0x1224,
+ 0x5c16, 0x0a91,
+ 0x5c1a, 0x0998,
+ 0x5c1e, 0x20f5,
+ 0x5c20, 0x1225,
+ 0x5c22, 0x1226,
+ 0x5c24, 0x0eec,
+ 0x5c28, 0x1227,
+ 0x5c2d, 0x06be,
+ 0x5c31, 0x092c,
+ 0x5c38, 0x1228,
+ 0x5c3a, 0x0908,
+ 0x5c3b, 0x09f2,
+ 0x5c3c, 0x0ccc,
+ 0x5c3d, 0x0a1a,
+ 0x5c3e, 0x0d8c,
+ 0x5c3f, 0x0cd8,
+ 0x5c40, 0x06c1,
+ 0x5c41, 0x122a,
+ 0x5c45, 0x0689,
+ 0x5c46, 0x122b,
+ 0x5c48, 0x06f6,
+ 0x5c4a, 0x0ca7,
+ 0x5c4b, 0x0530,
+ 0x5c4d, 0x08a1,
+ 0x5c4e, 0x122c,
+ 0x5c4f, 0x122f,
+ 0x5c50, 0x122e,
+ 0x5c51, 0x06f5,
+ 0x5c53, 0x122d,
+ 0x5c55, 0x0c32,
+ 0x5c5b, 0x1e92,
+ 0x5c5e, 0x0b10,
+ 0x5c60, 0x0c45,
+ 0x5c61, 0x08f4,
+ 0x5c62, 0x1e0d,
+ 0x5c64, 0x0ada,
+ 0x5c65, 0x0f64,
+ 0x5c6c, 0x1231,
+ 0x5c6e, 0x1232,
+ 0x5c6f, 0x0cae,
+ 0x5c71, 0x0881,
+ 0x5c76, 0x1234,
+ 0x5c79, 0x1235,
+ 0x5c8c, 0x1236,
+ 0x5c90, 0x0630,
+ 0x5c91, 0x1237,
+ 0x5c94, 0x1238,
+ 0x5ca1, 0x052c,
+ 0x5ca6, 0x20f6,
+ 0x5ca8, 0x0abd,
+ 0x5ca9, 0x0620,
+ 0x5cab, 0x123a,
+ 0x5cac, 0x0eb4,
+ 0x5cb1, 0x0b32,
+ 0x5cb3, 0x05b7,
+ 0x5cb6, 0x123c,
+ 0x5cb7, 0x123e,
+ 0x5cb8, 0x061b,
+ 0x5cba, 0x20f7,
+ 0x5cbb, 0x123b,
+ 0x5cbc, 0x123d,
+ 0x5cbe, 0x1240,
+ 0x5cc5, 0x123f,
+ 0x5cc7, 0x1241,
+ 0x5cd9, 0x1242,
+ 0x5ce0, 0x0c95,
+ 0x5ce1, 0x06a6,
+ 0x5ce8, 0x0565,
+ 0x5ce9, 0x1243,
+ 0x5cea, 0x1248,
+ 0x5ced, 0x1246,
+ 0x5cef, 0x0e47,
+ 0x5cf0, 0x0e46,
+ 0x5cf5, 0x20f8,
+ 0x5cf6, 0x0c61,
+ 0x5cfa, 0x1245,
+ 0x5cfb, 0x095e,
+ 0x5cfd, 0x1244,
+ 0x5d07, 0x0a38,
+ 0x5d0b, 0x1249,
+ 0x5d0e, 0x085a,
+ 0x5d11, 0x124f,
+ 0x5d14, 0x1250,
+ 0x5d15, 0x124a,
+ 0x5d16, 0x0591,
+ 0x5d17, 0x124b,
+ 0x5d18, 0x1254,
+ 0x5d19, 0x1253,
+ 0x5d1a, 0x1252,
+ 0x5d1b, 0x124e,
+ 0x5d1f, 0x124d,
+ 0x5d22, 0x1251,
+ 0x5d27, 0x20f9,
+ 0x5d29, 0x0e48,
+ 0x5d42, 0x20fc,
+ 0x5d4b, 0x1258,
+ 0x5d4c, 0x1255,
+ 0x5d4e, 0x1257,
+ 0x5d50, 0x0f5c,
+ 0x5d52, 0x1256,
+ 0x5d53, 0x20fa,
+ 0x5d5c, 0x124c,
+ 0x5d69, 0x0a39,
+ 0x5d6c, 0x1259,
+ 0x5d6d, 0x20fd,
+ 0x5d6f, 0x0827,
+ 0x5d73, 0x125a,
+ 0x5d76, 0x125b,
+ 0x5d82, 0x125e,
+ 0x5d84, 0x125d,
+ 0x5d87, 0x125c,
+ 0x5d8b, 0x0c62,
+ 0x5d8c, 0x1247,
+ 0x5d90, 0x1264,
+ 0x5d9d, 0x1260,
+ 0x5da2, 0x125f,
+ 0x5dac, 0x1261,
+ 0x5dae, 0x1262,
+ 0x5db7, 0x1265,
+ 0x5db8, 0x20fe,
+ 0x5dba, 0x0fae,
+ 0x5dbc, 0x1266,
+ 0x5dbd, 0x1263,
+ 0x5dc9, 0x1267,
+ 0x5dcc, 0x061c,
+ 0x5dcd, 0x1268,
+ 0x5dd0, 0x2100,
+ 0x5dd2, 0x126a,
+ 0x5dd3, 0x1269,
+ 0x5dd6, 0x126b,
+ 0x5ddb, 0x126c,
+ 0x5ddd, 0x0a92,
+ 0x5dde, 0x092d,
+ 0x5de1, 0x096e,
+ 0x5de3, 0x0ae5,
+ 0x5de5, 0x07bb,
+ 0x5de6, 0x0828,
+ 0x5de7, 0x07bc,
+ 0x5de8, 0x068a,
+ 0x5deb, 0x126d,
+ 0x5dee, 0x0829,
+ 0x5df1, 0x077e,
+ 0x5df2, 0x126e,
+ 0x5df3, 0x0eb2,
+ 0x5df4, 0x0cf9,
+ 0x5df5, 0x126f,
+ 0x5df7, 0x07bd,
+ 0x5dfb, 0x05e8,
+ 0x5dfd, 0x0b65,
+ 0x5dfe, 0x06ca,
+ 0x5e02, 0x08a2,
+ 0x5e03, 0x0dcd,
+ 0x5e06, 0x0d55,
+ 0x5e0b, 0x1270,
+ 0x5e0c, 0x0631,
+ 0x5e11, 0x1273,
+ 0x5e16, 0x0bbd,
+ 0x5e19, 0x1272,
+ 0x5e1a, 0x1271,
+ 0x5e1b, 0x1274,
+ 0x5e1d, 0x0c07,
+ 0x5e25, 0x0a29,
+ 0x5e2b, 0x08a3,
+ 0x5e2d, 0x0a6e,
+ 0x5e2f, 0x0b33,
+ 0x5e30, 0x063c,
+ 0x5e33, 0x0bbe,
+ 0x5e36, 0x1275,
+ 0x5e38, 0x09d7,
+ 0x5e3d, 0x0e67,
+ 0x5e40, 0x1279,
+ 0x5e43, 0x1278,
+ 0x5e44, 0x1277,
+ 0x5e45, 0x0def,
+ 0x5e47, 0x1280,
+ 0x5e4c, 0x0e88,
+ 0x5e4e, 0x127a,
+ 0x5e54, 0x127c,
+ 0x5e55, 0x0e99,
+ 0x5e57, 0x127b,
+ 0x5e5f, 0x127d,
+ 0x5e61, 0x0d3c,
+ 0x5e62, 0x127e,
+ 0x5e63, 0x0e0e,
+ 0x5e64, 0x127f,
+ 0x5e72, 0x05ef,
+ 0x5e73, 0x0e0f,
+ 0x5e74, 0x0ce5,
+ 0x5e75, 0x1281,
+ 0x5e78, 0x07be,
+ 0x5e79, 0x05f0,
+ 0x5e7a, 0x1283,
+ 0x5e7b, 0x076c,
+ 0x5e7c, 0x0f2e,
+ 0x5e7d, 0x0f13,
+ 0x5e7e, 0x0632,
+ 0x5e7f, 0x1285,
+ 0x5e81, 0x0bbf,
+ 0x5e83, 0x07bf,
+ 0x5e84, 0x0999,
+ 0x5e87, 0x0d73,
+ 0x5e8a, 0x099a,
+ 0x5e8f, 0x0982,
+ 0x5e95, 0x0c08,
+ 0x5e96, 0x0e49,
+ 0x5e97, 0x0c33,
+ 0x5e9a, 0x07c0,
+ 0x5e9c, 0x0dce,
+ 0x5ea0, 0x1286,
+ 0x5ea6, 0x0c53,
+ 0x5ea7, 0x0832,
+ 0x5eab, 0x077f,
+ 0x5ead, 0x0c09,
+ 0x5eb5, 0x0487,
+ 0x5eb6, 0x0978,
+ 0x5eb7, 0x07c1,
+ 0x5eb8, 0x0f31,
+ 0x5ec1, 0x1287,
+ 0x5ec3, 0x0d07,
+ 0x5ec8, 0x1289,
+ 0x5ec9, 0x0fbf,
+ 0x5eca, 0x0fd3,
+ 0x5ecf, 0x128b,
+ 0x5ed0, 0x128a,
+ 0x5ed3, 0x05a5,
+ 0x5ed6, 0x128c,
+ 0x5eda, 0x128f,
+ 0x5edd, 0x128e,
+ 0x5edf, 0x0db2,
+ 0x5ee0, 0x099b,
+ 0x5ee1, 0x1292,
+ 0x5ee2, 0x1291,
+ 0x5ee3, 0x128d,
+ 0x5ee8, 0x1293,
+ 0x5eec, 0x1295,
+ 0x5ef0, 0x1298,
+ 0x5ef1, 0x1296,
+ 0x5ef3, 0x1297,
+ 0x5ef4, 0x1299,
+ 0x5ef6, 0x0506,
+ 0x5ef7, 0x0c0a,
+ 0x5ef8, 0x129a,
+ 0x5efa, 0x0750,
+ 0x5efb, 0x0576,
+ 0x5efc, 0x0cec,
+ 0x5efe, 0x129b,
+ 0x5eff, 0x0cd3,
+ 0x5f01, 0x0e2b,
+ 0x5f03, 0x129c,
+ 0x5f04, 0x0fd4,
+ 0x5f09, 0x129d,
+ 0x5f0a, 0x0e10,
+ 0x5f0b, 0x12a0,
+ 0x5f0c, 0x0ffa,
+ 0x5f0d, 0x100a,
+ 0x5f0f, 0x08dc,
+ 0x5f10, 0x0ccd,
+ 0x5f11, 0x12a1,
+ 0x5f13, 0x0677,
+ 0x5f14, 0x0bc0,
+ 0x5f15, 0x04be,
+ 0x5f16, 0x12a2,
+ 0x5f17, 0x0df6,
+ 0x5f18, 0x07c2,
+ 0x5f1b, 0x0b8e,
+ 0x5f1f, 0x0c0b,
+ 0x5f21, 0x2101,
+ 0x5f25, 0x0efb,
+ 0x5f26, 0x076d,
+ 0x5f27, 0x0780,
+ 0x5f29, 0x12a3,
+ 0x5f2d, 0x12a4,
+ 0x5f2f, 0x12aa,
+ 0x5f31, 0x0911,
+ 0x5f34, 0x2102,
+ 0x5f35, 0x0bc1,
+ 0x5f37, 0x06a7,
+ 0x5f38, 0x12a5,
+ 0x5f3c, 0x0d9d,
+ 0x5f3e, 0x0b84,
+ 0x5f41, 0x12a6,
+ 0x5f45, 0x20b2,
+ 0x5f48, 0x12a7,
+ 0x5f4a, 0x06a8,
+ 0x5f4c, 0x12a8,
+ 0x5f4e, 0x12a9,
+ 0x5f51, 0x12ab,
+ 0x5f53, 0x0c70,
+ 0x5f56, 0x12ac,
+ 0x5f59, 0x12ae,
+ 0x5f5c, 0x129f,
+ 0x5f5d, 0x129e,
+ 0x5f61, 0x12af,
+ 0x5f62, 0x0717,
+ 0x5f66, 0x0d99,
+ 0x5f67, 0x2103,
+ 0x5f69, 0x083c,
+ 0x5f6a, 0x0da9,
+ 0x5f6b, 0x0bc2,
+ 0x5f6c, 0x0dbd,
+ 0x5f6d, 0x12b0,
+ 0x5f70, 0x099c,
+ 0x5f71, 0x04e8,
+ 0x5f73, 0x12b1,
+ 0x5f77, 0x12b2,
+ 0x5f79, 0x0efe,
+ 0x5f7c, 0x0d74,
+ 0x5f7f, 0x12b5,
+ 0x5f80, 0x051f,
+ 0x5f81, 0x0a50,
+ 0x5f82, 0x12b4,
+ 0x5f83, 0x12b3,
+ 0x5f84, 0x0718,
+ 0x5f85, 0x0b34,
+ 0x5f87, 0x12b9,
+ 0x5f88, 0x12b7,
+ 0x5f8a, 0x12b6,
+ 0x5f8b, 0x0f6f,
+ 0x5f8c, 0x0799,
+ 0x5f90, 0x0983,
+ 0x5f91, 0x12b8,
+ 0x5f92, 0x0c46,
+ 0x5f93, 0x0948,
+ 0x5f97, 0x0c98,
+ 0x5f98, 0x12bc,
+ 0x5f99, 0x12bb,
+ 0x5f9e, 0x12ba,
+ 0x5fa0, 0x12bd,
+ 0x5fa1, 0x079a,
+ 0x5fa8, 0x12be,
+ 0x5fa9, 0x0dee,
+ 0x5faa, 0x0965,
+ 0x5fad, 0x12bf,
+ 0x5fae, 0x0d8d,
+ 0x5fb3, 0x0c99,
+ 0x5fb4, 0x0bc3,
+ 0x5fb7, 0x2104,
+ 0x5fb9, 0x0c2a,
+ 0x5fbc, 0x12c0,
+ 0x5fbd, 0x0645,
+ 0x5fc3, 0x09fa,
+ 0x5fc5, 0x0d9e,
+ 0x5fcc, 0x0633,
+ 0x5fcd, 0x0cdc,
+ 0x5fd6, 0x12c1,
+ 0x5fd7, 0x08a4,
+ 0x5fd8, 0x0e68,
+ 0x5fdc, 0x0520,
+ 0x5fdd, 0x12c6,
+ 0x5fde, 0x2105,
+ 0x5fe0, 0x0ba7,
+ 0x5fe4, 0x12c3,
+ 0x5feb, 0x0577,
+ 0x5ff0, 0x12f6,
+ 0x5ff1, 0x12c5,
+ 0x5ff5, 0x0ce6,
+ 0x5ff8, 0x12c4,
+ 0x5ffb, 0x12c2,
+ 0x5ffd, 0x080c,
+ 0x5fff, 0x12c8,
+ 0x600e, 0x12ce,
+ 0x600f, 0x12d4,
+ 0x6010, 0x12cc,
+ 0x6012, 0x0c56,
+ 0x6015, 0x12d1,
+ 0x6016, 0x0dcf,
+ 0x6019, 0x12cb,
+ 0x601b, 0x12d0,
+ 0x601c, 0x0faf,
+ 0x601d, 0x08a5,
+ 0x6020, 0x0b35,
+ 0x6021, 0x12c9,
+ 0x6025, 0x0678,
+ 0x6026, 0x12d3,
+ 0x6027, 0x0a51,
+ 0x6028, 0x0507,
+ 0x6029, 0x12cd,
+ 0x602a, 0x0578,
+ 0x602b, 0x12d2,
+ 0x602f, 0x06a9,
+ 0x6031, 0x12cf,
+ 0x603a, 0x12d5,
+ 0x6041, 0x12d7,
+ 0x6042, 0x12e1,
+ 0x6043, 0x12df,
+ 0x6046, 0x12dc,
+ 0x604a, 0x12db,
+ 0x604b, 0x0fc0,
+ 0x604d, 0x12dd,
+ 0x6050, 0x06aa,
+ 0x6052, 0x07c3,
+ 0x6055, 0x0984,
+ 0x6059, 0x12e4,
+ 0x605a, 0x12d6,
+ 0x605d, 0x2106,
+ 0x605f, 0x12da,
+ 0x6060, 0x12ca,
+ 0x6062, 0x057a,
+ 0x6063, 0x12de,
+ 0x6064, 0x12e0,
+ 0x6065, 0x0b8f,
+ 0x6068, 0x0818,
+ 0x6069, 0x0538,
+ 0x606a, 0x12d8,
+ 0x606b, 0x12e3,
+ 0x606c, 0x12e2,
+ 0x606d, 0x06ab,
+ 0x606f, 0x0b09,
+ 0x6070, 0x05c4,
+ 0x6075, 0x0719,
+ 0x6077, 0x12d9,
+ 0x6081, 0x12e5,
+ 0x6083, 0x12e8,
+ 0x6084, 0x12ea,
+ 0x6085, 0x2107,
+ 0x6089, 0x08e9,
+ 0x608a, 0x2108,
+ 0x608b, 0x12f0,
+ 0x608c, 0x0c0c,
+ 0x608d, 0x12e6,
+ 0x6092, 0x12ee,
+ 0x6094, 0x0579,
+ 0x6096, 0x12ec,
+ 0x609a, 0x12e9,
+ 0x609b, 0x12eb,
+ 0x609f, 0x079b,
+ 0x60a0, 0x0f14,
+ 0x60a3, 0x05f1,
+ 0x60a6, 0x04fb,
+ 0x60a7, 0x12ef,
+ 0x60a9, 0x0cf0,
+ 0x60aa, 0x0471,
+ 0x60b2, 0x0d75,
+ 0x60b3, 0x12c7,
+ 0x60b4, 0x12f5,
+ 0x60b5, 0x12f9,
+ 0x60b6, 0x0ef1,
+ 0x60b8, 0x12f2,
+ 0x60bc, 0x0c63,
+ 0x60bd, 0x12f7,
+ 0x60c5, 0x09d8,
+ 0x60c6, 0x12f8,
+ 0x60c7, 0x0caf,
+ 0x60d1, 0x0fed,
+ 0x60d3, 0x12f4,
+ 0x60d5, 0x210a,
+ 0x60d8, 0x12fa,
+ 0x60da, 0x080d,
+ 0x60dc, 0x0a6f,
+ 0x60de, 0x2109,
+ 0x60df, 0x0498,
+ 0x60e0, 0x12f3,
+ 0x60e1, 0x12f1,
+ 0x60e3, 0x0adc,
+ 0x60e7, 0x12e7,
+ 0x60e8, 0x0882,
+ 0x60f0, 0x0b26,
+ 0x60f1, 0x1306,
+ 0x60f2, 0x210c,
+ 0x60f3, 0x0add,
+ 0x60f4, 0x1301,
+ 0x60f6, 0x12fe,
+ 0x60f9, 0x0912,
+ 0x60fa, 0x1302,
+ 0x60fb, 0x1305,
+ 0x6100, 0x1300,
+ 0x6101, 0x092f,
+ 0x6103, 0x1303,
+ 0x6106, 0x12fd,
+ 0x6108, 0x0f08,
+ 0x6109, 0x0f07,
+ 0x610d, 0x1307,
+ 0x610f, 0x0499,
+ 0x6111, 0x210d,
+ 0x6115, 0x12fc,
+ 0x611a, 0x06ea,
+ 0x611b, 0x046a,
+ 0x611f, 0x05f2,
+ 0x6120, 0x210b,
+ 0x6121, 0x1304,
+ 0x6127, 0x130c,
+ 0x6128, 0x130b,
+ 0x612c, 0x1310,
+ 0x6130, 0x210f,
+ 0x6134, 0x1311,
+ 0x6137, 0x210e,
+ 0x613c, 0x130f,
+ 0x613d, 0x1312,
+ 0x613e, 0x130a,
+ 0x613f, 0x130e,
+ 0x6142, 0x1313,
+ 0x6144, 0x1314,
+ 0x6147, 0x1309,
+ 0x6148, 0x08ca,
+ 0x614a, 0x130d,
+ 0x614b, 0x0b36,
+ 0x614c, 0x07c4,
+ 0x614d, 0x12fb,
+ 0x614e, 0x09fb,
+ 0x6153, 0x1321,
+ 0x6155, 0x0e39,
+ 0x6158, 0x1317,
+ 0x615d, 0x1320,
+ 0x615f, 0x131f,
+ 0x6162, 0x0eab,
+ 0x6163, 0x05f3,
+ 0x6165, 0x131d,
+ 0x6167, 0x071b,
+ 0x6168, 0x0592,
+ 0x616b, 0x131a,
+ 0x616e, 0x0f80,
+ 0x616f, 0x131c,
+ 0x6170, 0x049a,
+ 0x6171, 0x131e,
+ 0x6173, 0x1315,
+ 0x6174, 0x131b,
+ 0x6175, 0x1322,
+ 0x6176, 0x071a,
+ 0x6177, 0x1316,
+ 0x617e, 0x0f47,
+ 0x6182, 0x0f15,
+ 0x6187, 0x1325,
+ 0x618a, 0x1329,
+ 0x618e, 0x0b00,
+ 0x6190, 0x0fc1,
+ 0x6191, 0x132a,
+ 0x6194, 0x1327,
+ 0x6196, 0x1324,
+ 0x6198, 0x2110,
+ 0x6199, 0x1323,
+ 0x619a, 0x1328,
+ 0x61a4, 0x0e00,
+ 0x61a7, 0x0c8c,
+ 0x61a9, 0x071c,
+ 0x61ab, 0x132b,
+ 0x61ac, 0x1326,
+ 0x61ae, 0x132c,
+ 0x61b2, 0x0751,
+ 0x61b6, 0x0531,
+ 0x61ba, 0x1334,
+ 0x61be, 0x05f4,
+ 0x61c3, 0x1332,
+ 0x61c6, 0x1333,
+ 0x61c7, 0x0819,
+ 0x61c8, 0x1331,
+ 0x61c9, 0x132f,
+ 0x61ca, 0x132e,
+ 0x61cb, 0x1335,
+ 0x61cc, 0x132d,
+ 0x61cd, 0x1337,
+ 0x61d0, 0x057b,
+ 0x61e3, 0x1339,
+ 0x61e6, 0x1338,
+ 0x61f2, 0x0bc4,
+ 0x61f4, 0x133c,
+ 0x61f6, 0x133a,
+ 0x61f7, 0x1330,
+ 0x61f8, 0x0752,
+ 0x61fa, 0x133b,
+ 0x61fc, 0x133f,
+ 0x61fd, 0x133e,
+ 0x61fe, 0x1340,
+ 0x61ff, 0x133d,
+ 0x6200, 0x1341,
+ 0x6208, 0x1342,
+ 0x620a, 0x0e3a,
+ 0x620c, 0x1345,
+ 0x620d, 0x1344,
+ 0x620e, 0x0949,
+ 0x6210, 0x0a52,
+ 0x6211, 0x0566,
+ 0x6212, 0x057c,
+ 0x6213, 0x2111,
+ 0x6214, 0x1346,
+ 0x6216, 0x0483,
+ 0x621a, 0x0a70,
+ 0x621b, 0x1347,
+ 0x621d, 0x1a64,
+ 0x621e, 0x1348,
+ 0x621f, 0x0737,
+ 0x6221, 0x1349,
+ 0x6226, 0x0a93,
+ 0x622a, 0x134a,
+ 0x622e, 0x134b,
+ 0x622f, 0x0654,
+ 0x6230, 0x134c,
+ 0x6232, 0x134d,
+ 0x6234, 0x0b37,
+ 0x6238, 0x0781,
+ 0x623b, 0x0eed,
+ 0x623f, 0x0e6a,
+ 0x6240, 0x0974,
+ 0x6241, 0x134f,
+ 0x6247, 0x0a94,
+ 0x6248, 0x1b1a,
+ 0x6249, 0x0d76,
+ 0x624b, 0x0916,
+ 0x624d, 0x083d,
+ 0x624e, 0x1350,
+ 0x6253, 0x0b27,
+ 0x6255, 0x0df7,
+ 0x6258, 0x0b51,
+ 0x625b, 0x1353,
+ 0x625e, 0x1351,
+ 0x6260, 0x1354,
+ 0x6263, 0x1352,
+ 0x6268, 0x1355,
+ 0x626e, 0x0e01,
+ 0x6271, 0x047b,
+ 0x6276, 0x0dd0,
+ 0x6279, 0x0d77,
+ 0x627c, 0x1356,
+ 0x627e, 0x1359,
+ 0x627f, 0x099d,
+ 0x6280, 0x0655,
+ 0x6282, 0x1357,
+ 0x6283, 0x135e,
+ 0x6284, 0x099e,
+ 0x6289, 0x1358,
+ 0x628a, 0x0cfa,
+ 0x6291, 0x0f48,
+ 0x6292, 0x135a,
+ 0x6294, 0x135f,
+ 0x6295, 0x0c64,
+ 0x6296, 0x135c,
+ 0x6297, 0x07c5,
+ 0x6298, 0x0a82,
+ 0x629b, 0x136d,
+ 0x629c, 0x0d48,
+ 0x629e, 0x0b52,
+ 0x62a6, 0x2112,
+ 0x62ab, 0x0d78,
+ 0x62ac, 0x13b2,
+ 0x62b1, 0x0e4a,
+ 0x62b5, 0x0c0d,
+ 0x62b9, 0x0ea3,
+ 0x62bb, 0x1362,
+ 0x62bc, 0x0521,
+ 0x62bd, 0x0ba8,
+ 0x62c2, 0x136b,
+ 0x62c5, 0x0b72,
+ 0x62c6, 0x1365,
+ 0x62c7, 0x136c,
+ 0x62c8, 0x1367,
+ 0x62c9, 0x136e,
+ 0x62ca, 0x136a,
+ 0x62cc, 0x1369,
+ 0x62cd, 0x0d25,
+ 0x62cf, 0x1363,
+ 0x62d0, 0x057d,
+ 0x62d1, 0x1361,
+ 0x62d2, 0x068b,
+ 0x62d3, 0x0b53,
+ 0x62d4, 0x135d,
+ 0x62d7, 0x1360,
+ 0x62d8, 0x07c6,
+ 0x62d9, 0x0a7f,
+ 0x62db, 0x099f,
+ 0x62dc, 0x1368,
+ 0x62dd, 0x0d08,
+ 0x62e0, 0x068c,
+ 0x62e1, 0x05a6,
+ 0x62ec, 0x05c5,
+ 0x62ed, 0x09e7,
+ 0x62ee, 0x1370,
+ 0x62ef, 0x1375,
+ 0x62f1, 0x1371,
+ 0x62f3, 0x0753,
+ 0x62f5, 0x1376,
+ 0x62f6, 0x0870,
+ 0x62f7, 0x07fb,
+ 0x62fe, 0x0930,
+ 0x62ff, 0x1364,
+ 0x6301, 0x08cb,
+ 0x6302, 0x1373,
+ 0x6307, 0x08a6,
+ 0x6308, 0x1374,
+ 0x6309, 0x0488,
+ 0x630c, 0x136f,
+ 0x6311, 0x0bc5,
+ 0x6319, 0x068d,
+ 0x631f, 0x06ac,
+ 0x6327, 0x1372,
+ 0x6328, 0x046b,
+ 0x632b, 0x0833,
+ 0x632f, 0x09fc,
+ 0x633a, 0x0c0e,
+ 0x633d, 0x0d68,
+ 0x633e, 0x1378,
+ 0x633f, 0x0ae0,
+ 0x6349, 0x0b0a,
+ 0x634c, 0x0879,
+ 0x634d, 0x1379,
+ 0x634f, 0x137b,
+ 0x6350, 0x1377,
+ 0x6355, 0x0e31,
+ 0x6357, 0x0bd9,
+ 0x635c, 0x0ade,
+ 0x6367, 0x0e4b,
+ 0x6368, 0x08fa,
+ 0x6369, 0x1387,
+ 0x636b, 0x1386,
+ 0x636e, 0x0a3e,
+ 0x6372, 0x0754,
+ 0x6376, 0x1380,
+ 0x6377, 0x09a1,
+ 0x637a, 0x0cc0,
+ 0x637b, 0x0ce7,
+ 0x6380, 0x137e,
+ 0x6383, 0x0adf,
+ 0x6388, 0x0924,
+ 0x6389, 0x1383,
+ 0x638c, 0x09a0,
+ 0x638e, 0x137d,
+ 0x638f, 0x1382,
+ 0x6392, 0x0d09,
+ 0x6396, 0x137c,
+ 0x6398, 0x06f7,
+ 0x639b, 0x05bb,
+ 0x639f, 0x1384,
+ 0x63a0, 0x0f73,
+ 0x63a1, 0x083e,
+ 0x63a2, 0x0b73,
+ 0x63a3, 0x1381,
+ 0x63a5, 0x0a80,
+ 0x63a7, 0x07c7,
+ 0x63a8, 0x0a2a,
+ 0x63a9, 0x0508,
+ 0x63aa, 0x0abe,
+ 0x63ab, 0x137f,
+ 0x63ac, 0x065f,
+ 0x63b2, 0x071d,
+ 0x63b4, 0x0beb,
+ 0x63b5, 0x1385,
+ 0x63bb, 0x0ae1,
+ 0x63be, 0x1388,
+ 0x63c0, 0x138a,
+ 0x63c3, 0x0b17,
+ 0x63c4, 0x1390,
+ 0x63c6, 0x138b,
+ 0x63c9, 0x138d,
+ 0x63cf, 0x0db3,
+ 0x63d0, 0x0c0f,
+ 0x63d2, 0x138e,
+ 0x63d6, 0x0f16,
+ 0x63da, 0x0f32,
+ 0x63db, 0x05f5,
+ 0x63e1, 0x0472,
+ 0x63e3, 0x138c,
+ 0x63e9, 0x1389,
+ 0x63ee, 0x0634,
+ 0x63f4, 0x0509,
+ 0x63f5, 0x2113,
+ 0x63f6, 0x138f,
+ 0x63fa, 0x0f33,
+ 0x6406, 0x1393,
+ 0x640d, 0x0b1b,
+ 0x640f, 0x139a,
+ 0x6413, 0x1394,
+ 0x6414, 0x1e2c,
+ 0x6416, 0x1391,
+ 0x6417, 0x1398,
+ 0x641c, 0x137a,
+ 0x6426, 0x1395,
+ 0x6428, 0x1399,
+ 0x642c, 0x0d56,
+ 0x642d, 0x0c65,
+ 0x6434, 0x1392,
+ 0x6436, 0x1396,
+ 0x643a, 0x071e,
+ 0x643e, 0x0861,
+ 0x6442, 0x0a81,
+ 0x644e, 0x139e,
+ 0x6451, 0x1e43,
+ 0x6458, 0x0c20,
+ 0x6460, 0x2114,
+ 0x6467, 0x139b,
+ 0x6469, 0x0e8e,
+ 0x646f, 0x139c,
+ 0x6476, 0x139d,
+ 0x6478, 0x0eda,
+ 0x647a, 0x0a46,
+ 0x6483, 0x0738,
+ 0x6488, 0x13a4,
+ 0x6492, 0x0883,
+ 0x6493, 0x13a1,
+ 0x6495, 0x13a0,
+ 0x649a, 0x0ce8,
+ 0x649d, 0x2115,
+ 0x649e, 0x0c8d,
+ 0x64a4, 0x0c2b,
+ 0x64a5, 0x13a2,
+ 0x64a9, 0x13a3,
+ 0x64ab, 0x0de1,
+ 0x64ad, 0x0cfb,
+ 0x64ae, 0x0871,
+ 0x64b0, 0x0a95,
+ 0x64b2, 0x0e7e,
+ 0x64b9, 0x05a7,
+ 0x64bb, 0x13aa,
+ 0x64bc, 0x13a5,
+ 0x64c1, 0x0f34,
+ 0x64c2, 0x13ac,
+ 0x64c5, 0x13a8,
+ 0x64c7, 0x13a9,
+ 0x64cd, 0x0ae2,
+ 0x64ce, 0x2116,
+ 0x64d2, 0x13a7,
+ 0x64d4, 0x1366,
+ 0x64d8, 0x13ab,
+ 0x64da, 0x13a6,
+ 0x64e0, 0x13b0,
+ 0x64e2, 0x0c21,
+ 0x64e3, 0x13b3,
+ 0x64e6, 0x0872,
+ 0x64e7, 0x13ae,
+ 0x64ec, 0x0656,
+ 0x64ef, 0x13b4,
+ 0x64f1, 0x13ad,
+ 0x64f2, 0x13b8,
+ 0x64f4, 0x13b7,
+ 0x64f6, 0x13b6,
+ 0x64fa, 0x13b9,
+ 0x64fd, 0x13bb,
+ 0x64fe, 0x09d9,
+ 0x6500, 0x13ba,
+ 0x6505, 0x13be,
+ 0x6518, 0x13bc,
+ 0x651c, 0x13bd,
+ 0x651d, 0x1397,
+ 0x6522, 0x1e97,
+ 0x6523, 0x13c0,
+ 0x6524, 0x13bf,
+ 0x652a, 0x139f,
+ 0x652b, 0x13c1,
+ 0x652c, 0x13b5,
+ 0x652f, 0x08a7,
+ 0x6534, 0x13c2,
+ 0x6536, 0x13c5,
+ 0x6537, 0x13c4,
+ 0x6538, 0x13c6,
+ 0x6539, 0x057e,
+ 0x653b, 0x07c8,
+ 0x653e, 0x0e4c,
+ 0x653f, 0x0a53,
+ 0x6545, 0x0782,
+ 0x6548, 0x13c8,
+ 0x654d, 0x13cb,
+ 0x654e, 0x2117,
+ 0x654f, 0x0dc4,
+ 0x6551, 0x0679,
+ 0x6555, 0x13ca,
+ 0x6556, 0x13c9,
+ 0x6557, 0x0d0a,
+ 0x6558, 0x13cc,
+ 0x6559, 0x06ad,
+ 0x655d, 0x13ce,
+ 0x655e, 0x13cd,
+ 0x6562, 0x05f6,
+ 0x6563, 0x0884,
+ 0x6566, 0x0cb0,
+ 0x656c, 0x071f,
+ 0x6570, 0x0a3a,
+ 0x6572, 0x13cf,
+ 0x6574, 0x0a54,
+ 0x6575, 0x0c22,
+ 0x6577, 0x0dd1,
+ 0x6578, 0x13d0,
+ 0x6582, 0x13d1,
+ 0x6587, 0x0e08,
+ 0x6588, 0x120c,
+ 0x6589, 0x0a6a,
+ 0x658c, 0x0dbe,
+ 0x658e, 0x0848,
+ 0x6590, 0x0d79,
+ 0x6591, 0x0d57,
+ 0x6597, 0x0c47,
+ 0x6599, 0x0f89,
+ 0x659b, 0x13d4,
+ 0x659c, 0x08fc,
+ 0x659f, 0x13d5,
+ 0x65a1, 0x047a,
+ 0x65a4, 0x06cc,
+ 0x65a5, 0x0a71,
+ 0x65a7, 0x0dd2,
+ 0x65ab, 0x13d6,
+ 0x65ac, 0x0890,
+ 0x65ad, 0x0b85,
+ 0x65af, 0x08a9,
+ 0x65b0, 0x09fd,
+ 0x65b7, 0x13d7,
+ 0x65b9, 0x0e4d,
+ 0x65bc, 0x0519,
+ 0x65bd, 0x08aa,
+ 0x65c1, 0x13da,
+ 0x65c3, 0x13d8,
+ 0x65c4, 0x13db,
+ 0x65c5, 0x0f81,
+ 0x65c6, 0x13d9,
+ 0x65cb, 0x0a9f,
+ 0x65cc, 0x13dc,
+ 0x65cf, 0x0b12,
+ 0x65d2, 0x13dd,
+ 0x65d7, 0x0636,
+ 0x65d9, 0x13df,
+ 0x65db, 0x13de,
+ 0x65e0, 0x13e0,
+ 0x65e2, 0x0637,
+ 0x65e5, 0x0cd4,
+ 0x65e6, 0x0b74,
+ 0x65e7, 0x0686,
+ 0x65e8, 0x08ab,
+ 0x65e9, 0x0ae3,
+ 0x65ec, 0x0966,
+ 0x65ed, 0x0474,
+ 0x65f1, 0x13e2,
+ 0x65fa, 0x0522,
+ 0x65fb, 0x13e6,
+ 0x6600, 0x2118,
+ 0x6602, 0x07c9,
+ 0x6603, 0x13e5,
+ 0x6606, 0x081b,
+ 0x6607, 0x09a2,
+ 0x6609, 0x211a,
+ 0x660a, 0x13e4,
+ 0x660c, 0x09a3,
+ 0x660e, 0x0ecc,
+ 0x660f, 0x081a,
+ 0x6613, 0x049b,
+ 0x6614, 0x0a72,
+ 0x6615, 0x2119,
+ 0x661c, 0x13eb,
+ 0x661e, 0x211c,
+ 0x661f, 0x0a55,
+ 0x6620, 0x04e9,
+ 0x6624, 0x211d,
+ 0x6625, 0x095f,
+ 0x6627, 0x0e94,
+ 0x6628, 0x0862,
+ 0x662d, 0x09a4,
+ 0x662e, 0x211b,
+ 0x662f, 0x0a4b,
+ 0x6631, 0x20ae,
+ 0x6634, 0x13ea,
+ 0x6635, 0x13e8,
+ 0x663b, 0x1e00,
+ 0x663c, 0x0ba9,
+ 0x663f, 0x1409,
+ 0x6641, 0x13ef,
+ 0x6642, 0x08cc,
+ 0x6643, 0x07ca,
+ 0x6644, 0x13ed,
+ 0x6649, 0x13ee,
+ 0x664b, 0x09fe,
+ 0x664f, 0x13ec,
+ 0x6652, 0x087d,
+ 0x6657, 0x211f,
+ 0x6659, 0x2120,
+ 0x665d, 0x13f1,
+ 0x665e, 0x13f0,
+ 0x665f, 0x13f5,
+ 0x6662, 0x13f6,
+ 0x6664, 0x13f2,
+ 0x6665, 0x211e,
+ 0x6666, 0x0580,
+ 0x6667, 0x13f3,
+ 0x6669, 0x0d69,
+ 0x666e, 0x0dd3,
+ 0x666f, 0x0720,
+ 0x6670, 0x13f7,
+ 0x6673, 0x2122,
+ 0x6674, 0x0a56,
+ 0x6676, 0x09a5,
+ 0x667a, 0x0b90,
+ 0x6681, 0x06bf,
+ 0x6683, 0x13f8,
+ 0x6684, 0x13fc,
+ 0x6687, 0x054b,
+ 0x6688, 0x13f9,
+ 0x6689, 0x13fb,
+ 0x668e, 0x13fa,
+ 0x6691, 0x0975,
+ 0x6696, 0x0b86,
+ 0x6697, 0x0489,
+ 0x6698, 0x13fd,
+ 0x6699, 0x2123,
+ 0x669d, 0x13fe,
+ 0x66a0, 0x2124,
+ 0x66a2, 0x0bc6,
+ 0x66a6, 0x0fb9,
+ 0x66ab, 0x0891,
+ 0x66ae, 0x0e3b,
+ 0x66b2, 0x2125,
+ 0x66b4, 0x0e6b,
+ 0x66b8, 0x1405,
+ 0x66b9, 0x1400,
+ 0x66bc, 0x1403,
+ 0x66be, 0x1402,
+ 0x66bf, 0x2126,
+ 0x66c1, 0x13ff,
+ 0x66c4, 0x1404,
+ 0x66c7, 0x0cb6,
+ 0x66c9, 0x1401,
+ 0x66d6, 0x1406,
+ 0x66d9, 0x0976,
+ 0x66da, 0x1407,
+ 0x66dc, 0x0f35,
+ 0x66dd, 0x0d2e,
+ 0x66e0, 0x1408,
+ 0x66e6, 0x140a,
+ 0x66e9, 0x140b,
+ 0x66f0, 0x140c,
+ 0x66f2, 0x06c2,
+ 0x66f3, 0x04ea,
+ 0x66f4, 0x07cb,
+ 0x66f5, 0x140d,
+ 0x66f7, 0x140e,
+ 0x66f8, 0x097b,
+ 0x66f9, 0x0ae4,
+ 0x66fa, 0x2127,
+ 0x66fb, 0x20b1,
+ 0x66fc, 0x10ed,
+ 0x66fd, 0x0ac0,
+ 0x66fe, 0x0abf,
+ 0x66ff, 0x0b38,
+ 0x6700, 0x0837,
+ 0x6703, 0x104b,
+ 0x6708, 0x0744,
+ 0x6709, 0x0f17,
+ 0x670b, 0x0e4e,
+ 0x670d, 0x0df0,
+ 0x670e, 0x2128,
+ 0x670f, 0x140f,
+ 0x6714, 0x0863,
+ 0x6715, 0x0bdb,
+ 0x6716, 0x1410,
+ 0x6717, 0x0fd5,
+ 0x671b, 0x0e6c,
+ 0x671d, 0x0bc7,
+ 0x671e, 0x1411,
+ 0x671f, 0x0638,
+ 0x6726, 0x1412,
+ 0x6728, 0x0ee6,
+ 0x672a, 0x0eb0,
+ 0x672b, 0x0ea4,
+ 0x672c, 0x0e8a,
+ 0x672d, 0x0873,
+ 0x672e, 0x1415,
+ 0x6731, 0x0917,
+ 0x6734, 0x0e7f,
+ 0x6736, 0x1417,
+ 0x6737, 0x141a,
+ 0x6738, 0x1419,
+ 0x673a, 0x0635,
+ 0x673d, 0x067a,
+ 0x673f, 0x1416,
+ 0x6741, 0x1418,
+ 0x6746, 0x141b,
+ 0x6749, 0x0a3f,
+ 0x674e, 0x0f65,
+ 0x674f, 0x048d,
+ 0x6750, 0x0850,
+ 0x6751, 0x0b1c,
+ 0x6753, 0x0909,
+ 0x6756, 0x09db,
+ 0x6759, 0x141e,
+ 0x675c, 0x0c48,
+ 0x675e, 0x141c,
+ 0x675f, 0x0b0b,
+ 0x6760, 0x141d,
+ 0x6761, 0x09da,
+ 0x6762, 0x0ee9,
+ 0x6763, 0x141f,
+ 0x6765, 0x0f52,
+ 0x6766, 0x212a,
+ 0x676a, 0x1425,
+ 0x676d, 0x07cc,
+ 0x676f, 0x0d0b,
+ 0x6770, 0x1422,
+ 0x6771, 0x0c66,
+ 0x6772, 0x13e3,
+ 0x6773, 0x13e7,
+ 0x6775, 0x0669,
+ 0x6777, 0x0cfd,
+ 0x677c, 0x1424,
+ 0x677e, 0x09a6,
+ 0x677f, 0x0d58,
+ 0x6785, 0x142a,
+ 0x6787, 0x0d8e,
+ 0x6789, 0x1421,
+ 0x678b, 0x1427,
+ 0x678c, 0x1426,
+ 0x6790, 0x0a73,
+ 0x6795, 0x0e9b,
+ 0x6797, 0x0f9b,
+ 0x679a, 0x0e95,
+ 0x679c, 0x054c,
+ 0x679d, 0x08ac,
+ 0x67a0, 0x0fee,
+ 0x67a1, 0x1429,
+ 0x67a2, 0x0a3b,
+ 0x67a6, 0x1428,
+ 0x67a9, 0x1423,
+ 0x67af, 0x0783,
+ 0x67b3, 0x142f,
+ 0x67b4, 0x142d,
+ 0x67b6, 0x054d,
+ 0x67b7, 0x142b,
+ 0x67b8, 0x1431,
+ 0x67b9, 0x1437,
+ 0x67bb, 0x212b,
+ 0x67c0, 0x212d,
+ 0x67c1, 0x0b28,
+ 0x67c4, 0x0e11,
+ 0x67c6, 0x1439,
+ 0x67ca, 0x0d94,
+ 0x67ce, 0x1438,
+ 0x67cf, 0x0d26,
+ 0x67d0, 0x0e6d,
+ 0x67d1, 0x05f7,
+ 0x67d3, 0x0a9b,
+ 0x67d4, 0x094a,
+ 0x67d8, 0x0bef,
+ 0x67da, 0x0f18,
+ 0x67dd, 0x1434,
+ 0x67de, 0x1433,
+ 0x67e2, 0x1435,
+ 0x67e4, 0x1432,
+ 0x67e7, 0x143a,
+ 0x67e9, 0x1430,
+ 0x67ec, 0x142e,
+ 0x67ee, 0x1436,
+ 0x67ef, 0x142c,
+ 0x67f1, 0x0baa,
+ 0x67f3, 0x0f04,
+ 0x67f4, 0x08f2,
+ 0x67f5, 0x0864,
+ 0x67fb, 0x082a,
+ 0x67fe, 0x0e9d,
+ 0x67ff, 0x059f,
+ 0x6801, 0x212e,
+ 0x6802, 0x0bea,
+ 0x6803, 0x0ca2,
+ 0x6804, 0x04eb,
+ 0x6805, 0x1e07,
+ 0x6813, 0x0a96,
+ 0x6816, 0x0a58,
+ 0x6817, 0x0700,
+ 0x681e, 0x143c,
+ 0x6821, 0x07cd,
+ 0x6822, 0x05da,
+ 0x6829, 0x143e,
+ 0x682a, 0x05d2,
+ 0x682b, 0x1444,
+ 0x6832, 0x1441,
+ 0x6834, 0x0a97,
+ 0x6838, 0x05a9,
+ 0x6839, 0x081c,
+ 0x683c, 0x05a8,
+ 0x683d, 0x083f,
+ 0x6840, 0x143f,
+ 0x6841, 0x073b,
+ 0x6842, 0x0721,
+ 0x6843, 0x0c67,
+ 0x6844, 0x212f,
+ 0x6846, 0x143d,
+ 0x6848, 0x048a,
+ 0x684d, 0x1440,
+ 0x684e, 0x1442,
+ 0x6850, 0x06c5,
+ 0x6851, 0x0702,
+ 0x6852, 0x212c,
+ 0x6853, 0x05f8,
+ 0x6854, 0x0665,
+ 0x6859, 0x1445,
+ 0x685c, 0x0869,
+ 0x685d, 0x0e9f,
+ 0x685f, 0x0885,
+ 0x6863, 0x1446,
+ 0x6867, 0x0da2,
+ 0x6874, 0x1452,
+ 0x6876, 0x0533,
+ 0x6877, 0x1447,
+ 0x687e, 0x1458,
+ 0x687f, 0x1448,
+ 0x6881, 0x0f8a,
+ 0x6883, 0x144f,
+ 0x6885, 0x0d15,
+ 0x688d, 0x1457,
+ 0x688e, 0x1e9c,
+ 0x688f, 0x144a,
+ 0x6893, 0x0478,
+ 0x6894, 0x144c,
+ 0x6897, 0x07ce,
+ 0x689b, 0x144e,
+ 0x689d, 0x144d,
+ 0x689f, 0x1449,
+ 0x68a0, 0x1454,
+ 0x68a2, 0x09a7,
+ 0x68a6, 0x11be,
+ 0x68a7, 0x079c,
+ 0x68a8, 0x0f66,
+ 0x68ad, 0x144b,
+ 0x68af, 0x0c10,
+ 0x68b0, 0x0581,
+ 0x68b1, 0x081d,
+ 0x68b3, 0x1443,
+ 0x68b5, 0x1453,
+ 0x68b6, 0x05bf,
+ 0x68b9, 0x1451,
+ 0x68ba, 0x1455,
+ 0x68bc, 0x0c68,
+ 0x68c4, 0x063a,
+ 0x68c6, 0x1473,
+ 0x68c8, 0x20af,
+ 0x68c9, 0x0ed5,
+ 0x68ca, 0x145a,
+ 0x68cb, 0x0639,
+ 0x68cd, 0x1461,
+ 0x68cf, 0x2130,
+ 0x68d2, 0x0e6e,
+ 0x68d4, 0x1462,
+ 0x68d5, 0x1464,
+ 0x68d7, 0x1468,
+ 0x68d8, 0x145c,
+ 0x68da, 0x0b68,
+ 0x68df, 0x0c69,
+ 0x68e0, 0x146c,
+ 0x68e1, 0x145f,
+ 0x68e3, 0x1469,
+ 0x68e7, 0x1463,
+ 0x68ee, 0x09ff,
+ 0x68ef, 0x146d,
+ 0x68f2, 0x0a57,
+ 0x68f9, 0x146b,
+ 0x68fa, 0x05f9,
+ 0x6900, 0x0ff6,
+ 0x6901, 0x1459,
+ 0x6904, 0x1467,
+ 0x6905, 0x049c,
+ 0x6908, 0x145b,
+ 0x690b, 0x0ec6,
+ 0x690c, 0x1460,
+ 0x690d, 0x09e8,
+ 0x690e, 0x0be3,
+ 0x690f, 0x1456,
+ 0x6912, 0x1466,
+ 0x6919, 0x0a40,
+ 0x691a, 0x1470,
+ 0x691b, 0x05cf,
+ 0x691c, 0x0755,
+ 0x6921, 0x1472,
+ 0x6922, 0x145d,
+ 0x6923, 0x1471,
+ 0x6925, 0x146a,
+ 0x6926, 0x145e,
+ 0x6928, 0x146e,
+ 0x692a, 0x146f,
+ 0x6930, 0x1480,
+ 0x6934, 0x0ca6,
+ 0x6936, 0x1465,
+ 0x6939, 0x147c,
+ 0x693d, 0x147e,
+ 0x693f, 0x0bf4,
+ 0x694a, 0x0f36,
+ 0x6953, 0x0de8,
+ 0x6954, 0x1479,
+ 0x6955, 0x0b2a,
+ 0x6959, 0x147f,
+ 0x695a, 0x0ac1,
+ 0x695c, 0x1476,
+ 0x695d, 0x1483,
+ 0x695e, 0x1482,
+ 0x6960, 0x0cc7,
+ 0x6961, 0x1481,
+ 0x6962, 0x0cc2,
+ 0x6968, 0x2132,
+ 0x696a, 0x1485,
+ 0x696b, 0x1478,
+ 0x696d, 0x06c0,
+ 0x696e, 0x147b,
+ 0x696f, 0x0967,
+ 0x6973, 0x0d16,
+ 0x6974, 0x147d,
+ 0x6975, 0x06c3,
+ 0x6977, 0x1475,
+ 0x6978, 0x1477,
+ 0x6979, 0x1474,
+ 0x697c, 0x0fd6,
+ 0x697d, 0x05b8,
+ 0x697e, 0x147a,
+ 0x6981, 0x1484,
+ 0x6982, 0x0593,
+ 0x698a, 0x0857,
+ 0x698e, 0x04ff,
+ 0x6991, 0x1495,
+ 0x6994, 0x0fd7,
+ 0x6995, 0x1498,
+ 0x6998, 0x2134,
+ 0x699b, 0x0a00,
+ 0x699c, 0x1497,
+ 0x69a0, 0x1496,
+ 0x69a7, 0x1493,
+ 0x69ae, 0x1487,
+ 0x69b1, 0x14a4,
+ 0x69b2, 0x1486,
+ 0x69b4, 0x1499,
+ 0x69bb, 0x1491,
+ 0x69be, 0x148c,
+ 0x69bf, 0x1489,
+ 0x69c1, 0x148a,
+ 0x69c3, 0x1492,
+ 0x69c7, 0x1d33,
+ 0x69ca, 0x148f,
+ 0x69cb, 0x07cf,
+ 0x69cc, 0x0be4,
+ 0x69cd, 0x0ae6,
+ 0x69ce, 0x148d,
+ 0x69d0, 0x1488,
+ 0x69d3, 0x148b,
+ 0x69d8, 0x0f37,
+ 0x69d9, 0x0e98,
+ 0x69dd, 0x1490,
+ 0x69de, 0x149a,
+ 0x69e2, 0x2135,
+ 0x69e7, 0x14a2,
+ 0x69e8, 0x149b,
+ 0x69eb, 0x14a8,
+ 0x69ed, 0x14a6,
+ 0x69f2, 0x14a1,
+ 0x69f9, 0x14a0,
+ 0x69fb, 0x0bec,
+ 0x69fd, 0x0ae7,
+ 0x69ff, 0x149e,
+ 0x6a02, 0x149c,
+ 0x6a05, 0x14a3,
+ 0x6a0a, 0x14a9,
+ 0x6a0b, 0x0d89,
+ 0x6a0c, 0x14af,
+ 0x6a12, 0x14aa,
+ 0x6a13, 0x14ad,
+ 0x6a14, 0x14a7,
+ 0x6a17, 0x0bb2,
+ 0x6a19, 0x0daa,
+ 0x6a1b, 0x149d,
+ 0x6a1e, 0x14a5,
+ 0x6a1f, 0x09a8,
+ 0x6a21, 0x0edb,
+ 0x6a22, 0x14b9,
+ 0x6a23, 0x14ac,
+ 0x6a29, 0x0756,
+ 0x6a2a, 0x0523,
+ 0x6a2b, 0x05bd,
+ 0x6a2e, 0x1494,
+ 0x6a30, 0x2136,
+ 0x6a35, 0x09a9,
+ 0x6a36, 0x14b1,
+ 0x6a38, 0x14b8,
+ 0x6a39, 0x0925,
+ 0x6a3a, 0x05d0,
+ 0x6a3d, 0x0b6c,
+ 0x6a44, 0x14ae,
+ 0x6a46, 0x2138,
+ 0x6a47, 0x14b3,
+ 0x6a48, 0x14b7,
+ 0x6a4b, 0x06ae,
+ 0x6a58, 0x0666,
+ 0x6a59, 0x14b5,
+ 0x6a5f, 0x063b,
+ 0x6a61, 0x0ca3,
+ 0x6a62, 0x14b4,
+ 0x6a66, 0x14b6,
+ 0x6a6b, 0x2137,
+ 0x6a72, 0x14b0,
+ 0x6a73, 0x2139,
+ 0x6a78, 0x14b2,
+ 0x6a7e, 0x213a,
+ 0x6a7f, 0x05be,
+ 0x6a80, 0x0b87,
+ 0x6a84, 0x14bd,
+ 0x6a8d, 0x14bb,
+ 0x6a8e, 0x079d,
+ 0x6a90, 0x14ba,
+ 0x6a97, 0x14c0,
+ 0x6a9c, 0x143b,
+ 0x6aa0, 0x14bc,
+ 0x6aa2, 0x14be,
+ 0x6aaa, 0x14cb,
+ 0x6aac, 0x14c7,
+ 0x6aae, 0x1450,
+ 0x6ab3, 0x14c6,
+ 0x6ab8, 0x14c5,
+ 0x6abb, 0x14c2,
+ 0x6ac1, 0x14ab,
+ 0x6ac2, 0x14c4,
+ 0x6ac3, 0x14c3,
+ 0x6ad1, 0x14c9,
+ 0x6ad3, 0x0fcc,
+ 0x6ada, 0x14cc,
+ 0x6adb, 0x06f3,
+ 0x6ade, 0x14c8,
+ 0x6adf, 0x14ca,
+ 0x6ae2, 0x213b,
+ 0x6ae4, 0x213c,
+ 0x6ae8, 0x0d3b,
+ 0x6aea, 0x14cd,
+ 0x6afa, 0x14d1,
+ 0x6afb, 0x14ce,
+ 0x6b04, 0x0f5d,
+ 0x6b05, 0x14cf,
+ 0x6b0a, 0x149f,
+ 0x6b12, 0x14d2,
+ 0x6b16, 0x14d3,
+ 0x6b1d, 0x04d7,
+ 0x6b1f, 0x14d5,
+ 0x6b20, 0x073d,
+ 0x6b21, 0x08cd,
+ 0x6b23, 0x06cd,
+ 0x6b27, 0x0524,
+ 0x6b32, 0x0f49,
+ 0x6b37, 0x14d7,
+ 0x6b38, 0x14d6,
+ 0x6b39, 0x14d9,
+ 0x6b3a, 0x0657,
+ 0x6b3d, 0x06ce,
+ 0x6b3e, 0x05fa,
+ 0x6b43, 0x14dc,
+ 0x6b47, 0x14db,
+ 0x6b49, 0x14dd,
+ 0x6b4c, 0x054e,
+ 0x6b4e, 0x0b75,
+ 0x6b50, 0x14de,
+ 0x6b53, 0x05fb,
+ 0x6b54, 0x14e0,
+ 0x6b59, 0x14df,
+ 0x6b5b, 0x14e1,
+ 0x6b5f, 0x14e2,
+ 0x6b61, 0x14e3,
+ 0x6b62, 0x08ad,
+ 0x6b63, 0x0a59,
+ 0x6b64, 0x0811,
+ 0x6b66, 0x0de2,
+ 0x6b69, 0x0e32,
+ 0x6b6a, 0x0fea,
+ 0x6b6f, 0x08c3,
+ 0x6b73, 0x0840,
+ 0x6b74, 0x0fba,
+ 0x6b78, 0x14e4,
+ 0x6b7b, 0x08ae,
+ 0x6b7f, 0x14e6,
+ 0x6b83, 0x14e9,
+ 0x6b84, 0x14e8,
+ 0x6b86, 0x0e86,
+ 0x6b89, 0x0968,
+ 0x6b8a, 0x0918,
+ 0x6b8b, 0x0892,
+ 0x6b8d, 0x14ea,
+ 0x6b95, 0x14ec,
+ 0x6b96, 0x09e9,
+ 0x6b98, 0x14eb,
+ 0x6b9e, 0x14ed,
+ 0x6ba4, 0x14ee,
+ 0x6baa, 0x14ef,
+ 0x6baf, 0x14f1,
+ 0x6bb1, 0x14f3,
+ 0x6bb2, 0x14f2,
+ 0x6bb3, 0x14f4,
+ 0x6bb4, 0x0525,
+ 0x6bb5, 0x0b88,
+ 0x6bb7, 0x14f5,
+ 0x6bba, 0x0874,
+ 0x6bbb, 0x05aa,
+ 0x6bbc, 0x14f6,
+ 0x6bbf, 0x0c3c,
+ 0x6bc0, 0x119d,
+ 0x6bc5, 0x063d,
+ 0x6bc6, 0x14f7,
+ 0x6bcb, 0x14f8,
+ 0x6bcd, 0x0e3c,
+ 0x6bce, 0x0e96,
+ 0x6bd2, 0x0c9f,
+ 0x6bd3, 0x14f9,
+ 0x6bd4, 0x0d7a,
+ 0x6bd6, 0x213d,
+ 0x6bd8, 0x0d8f,
+ 0x6bdb, 0x0edf,
+ 0x6bdf, 0x14fa,
+ 0x6beb, 0x14fc,
+ 0x6bec, 0x14fb,
+ 0x6bef, 0x14fe,
+ 0x6bf3, 0x14fd,
+ 0x6c08, 0x1500,
+ 0x6c0f, 0x08af,
+ 0x6c11, 0x0ebd,
+ 0x6c13, 0x1501,
+ 0x6c17, 0x063e,
+ 0x6c1b, 0x1503,
+ 0x6c23, 0x1505,
+ 0x6c24, 0x1504,
+ 0x6c34, 0x0a2b,
+ 0x6c37, 0x0dab,
+ 0x6c38, 0x04ec,
+ 0x6c3e, 0x0d59,
+ 0x6c3f, 0x213e,
+ 0x6c40, 0x0c11,
+ 0x6c41, 0x094b,
+ 0x6c42, 0x067b,
+ 0x6c4e, 0x0d5a,
+ 0x6c50, 0x08da,
+ 0x6c55, 0x1507,
+ 0x6c57, 0x05fc,
+ 0x6c5a, 0x051a,
+ 0x6c5c, 0x213f,
+ 0x6c5d, 0x0cca,
+ 0x6c5e, 0x1506,
+ 0x6c5f, 0x07d0,
+ 0x6c60, 0x0b91,
+ 0x6c62, 0x1508,
+ 0x6c68, 0x1510,
+ 0x6c6a, 0x1509,
+ 0x6c6f, 0x2141,
+ 0x6c70, 0x0b21,
+ 0x6c72, 0x067c,
+ 0x6c73, 0x1511,
+ 0x6c7a, 0x073e,
+ 0x6c7d, 0x063f,
+ 0x6c7e, 0x150f,
+ 0x6c81, 0x150d,
+ 0x6c82, 0x150a,
+ 0x6c83, 0x0f4a,
+ 0x6c86, 0x2140,
+ 0x6c88, 0x0bdc,
+ 0x6c8c, 0x0cb1,
+ 0x6c8d, 0x150b,
+ 0x6c90, 0x1513,
+ 0x6c92, 0x1512,
+ 0x6c93, 0x06f9,
+ 0x6c96, 0x052d,
+ 0x6c99, 0x082b,
+ 0x6c9a, 0x150c,
+ 0x6c9b, 0x150e,
+ 0x6ca1, 0x0e85,
+ 0x6ca2, 0x0b54,
+ 0x6cab, 0x0ea5,
+ 0x6cae, 0x151b,
+ 0x6cb1, 0x151c,
+ 0x6cb3, 0x054f,
+ 0x6cb8, 0x0df8,
+ 0x6cb9, 0x0f09,
+ 0x6cba, 0x151e,
+ 0x6cbb, 0x08cf,
+ 0x6cbc, 0x09aa,
+ 0x6cbd, 0x1517,
+ 0x6cbe, 0x151d,
+ 0x6cbf, 0x050a,
+ 0x6cc1, 0x06af,
+ 0x6cc4, 0x1514,
+ 0x6cc5, 0x1519,
+ 0x6cc9, 0x0a98,
+ 0x6cca, 0x0d27,
+ 0x6ccc, 0x0d7b,
+ 0x6cd3, 0x1516,
+ 0x6cd5, 0x0e4f,
+ 0x6cd7, 0x1518,
+ 0x6cd9, 0x1521,
+ 0x6cda, 0x2142,
+ 0x6cdb, 0x151f,
+ 0x6cdd, 0x151a,
+ 0x6ce1, 0x0e50,
+ 0x6ce2, 0x0cfe,
+ 0x6ce3, 0x067d,
+ 0x6ce5, 0x0c1f,
+ 0x6ce8, 0x0bab,
+ 0x6cea, 0x1522,
+ 0x6cef, 0x1520,
+ 0x6cf0, 0x0b39,
+ 0x6cf1, 0x1515,
+ 0x6cf3, 0x04ed,
+ 0x6d04, 0x2143,
+ 0x6d0b, 0x0f38,
+ 0x6d0c, 0x152d,
+ 0x6d12, 0x152c,
+ 0x6d17, 0x0a9a,
+ 0x6d19, 0x1529,
+ 0x6d1b, 0x0f56,
+ 0x6d1e, 0x0c8e,
+ 0x6d1f, 0x1523,
+ 0x6d25, 0x0be1,
+ 0x6d29, 0x04ee,
+ 0x6d2a, 0x07d1,
+ 0x6d2b, 0x1526,
+ 0x6d32, 0x0931,
+ 0x6d33, 0x152b,
+ 0x6d35, 0x152a,
+ 0x6d36, 0x1525,
+ 0x6d38, 0x1528,
+ 0x6d3b, 0x05c6,
+ 0x6d3d, 0x1527,
+ 0x6d3e, 0x0cff,
+ 0x6d41, 0x0f76,
+ 0x6d44, 0x09dc,
+ 0x6d45, 0x0a99,
+ 0x6d59, 0x1533,
+ 0x6d5a, 0x1531,
+ 0x6d5c, 0x0dbf,
+ 0x6d63, 0x152e,
+ 0x6d64, 0x1530,
+ 0x6d66, 0x04dc,
+ 0x6d69, 0x07d2,
+ 0x6d6a, 0x0fd8,
+ 0x6d6c, 0x059b,
+ 0x6d6e, 0x0dd4,
+ 0x6d6f, 0x2145,
+ 0x6d74, 0x0f4b,
+ 0x6d77, 0x0582,
+ 0x6d78, 0x0a01,
+ 0x6d79, 0x1532,
+ 0x6d85, 0x1537,
+ 0x6d87, 0x2144,
+ 0x6d88, 0x09ab,
+ 0x6d8c, 0x0f1a,
+ 0x6d8e, 0x1534,
+ 0x6d93, 0x152f,
+ 0x6d95, 0x1535,
+ 0x6d96, 0x2146,
+ 0x6d99, 0x0fa6,
+ 0x6d9b, 0x0c6d,
+ 0x6d9c, 0x0c9a,
+ 0x6dac, 0x2147,
+ 0x6daf, 0x0594,
+ 0x6db2, 0x04f7,
+ 0x6db5, 0x153b,
+ 0x6db8, 0x153e,
+ 0x6dbc, 0x0f8b,
+ 0x6dc0, 0x0f4e,
+ 0x6dc5, 0x1545,
+ 0x6dc6, 0x153f,
+ 0x6dc7, 0x153c,
+ 0x6dcb, 0x0f9c,
+ 0x6dcc, 0x1542,
+ 0x6dcf, 0x2148,
+ 0x6dd1, 0x0954,
+ 0x6dd2, 0x1544,
+ 0x6dd5, 0x1549,
+ 0x6dd8, 0x0c6b,
+ 0x6dd9, 0x1547,
+ 0x6dde, 0x1541,
+ 0x6de1, 0x0b76,
+ 0x6de4, 0x1548,
+ 0x6de6, 0x153d,
+ 0x6de8, 0x1543,
+ 0x6dea, 0x154a,
+ 0x6deb, 0x04c0,
+ 0x6dec, 0x1540,
+ 0x6dee, 0x154b,
+ 0x6df1, 0x0a02,
+ 0x6df2, 0x214a,
+ 0x6df3, 0x0969,
+ 0x6df5, 0x0df5,
+ 0x6df7, 0x081e,
+ 0x6df8, 0x2149,
+ 0x6df9, 0x1538,
+ 0x6dfa, 0x1546,
+ 0x6dfb, 0x0c34,
+ 0x6dfc, 0x214b,
+ 0x6e05, 0x0a5a,
+ 0x6e07, 0x05c7,
+ 0x6e08, 0x0841,
+ 0x6e09, 0x09ac,
+ 0x6e0a, 0x153a,
+ 0x6e0b, 0x094c,
+ 0x6e13, 0x0722,
+ 0x6e15, 0x1539,
+ 0x6e19, 0x154f,
+ 0x6e1a, 0x0977,
+ 0x6e1b, 0x076e,
+ 0x6e1d, 0x155e,
+ 0x6e1f, 0x1558,
+ 0x6e20, 0x068e,
+ 0x6e21, 0x0c49,
+ 0x6e23, 0x1553,
+ 0x6e24, 0x155c,
+ 0x6e25, 0x0473,
+ 0x6e26, 0x04d4,
+ 0x6e27, 0x214e,
+ 0x6e29, 0x0539,
+ 0x6e2b, 0x1555,
+ 0x6e2c, 0x0b0c,
+ 0x6e2d, 0x154c,
+ 0x6e2e, 0x154e,
+ 0x6e2f, 0x07d3,
+ 0x6e38, 0x155f,
+ 0x6e39, 0x214c,
+ 0x6e3a, 0x155a,
+ 0x6e3c, 0x214f,
+ 0x6e3e, 0x1552,
+ 0x6e43, 0x1559,
+ 0x6e4a, 0x0eb7,
+ 0x6e4d, 0x1557,
+ 0x6e4e, 0x155b,
+ 0x6e56, 0x0784,
+ 0x6e58, 0x09ad,
+ 0x6e5b, 0x0b77,
+ 0x6e5c, 0x214d,
+ 0x6e5f, 0x1551,
+ 0x6e67, 0x0f19,
+ 0x6e6b, 0x1554,
+ 0x6e6e, 0x154d,
+ 0x6e6f, 0x0c6c,
+ 0x6e72, 0x1550,
+ 0x6e76, 0x1556,
+ 0x6e7e, 0x0ff7,
+ 0x6e7f, 0x08ea,
+ 0x6e80, 0x0eac,
+ 0x6e82, 0x1560,
+ 0x6e8c, 0x0d42,
+ 0x6e8f, 0x156c,
+ 0x6e90, 0x076f,
+ 0x6e96, 0x096a,
+ 0x6e98, 0x1562,
+ 0x6e9c, 0x0f77,
+ 0x6e9d, 0x07d4,
+ 0x6e9f, 0x156f,
+ 0x6ea2, 0x04b2,
+ 0x6ea5, 0x156d,
+ 0x6eaa, 0x1561,
+ 0x6eaf, 0x1567,
+ 0x6eb2, 0x1569,
+ 0x6eb6, 0x0f39,
+ 0x6eb7, 0x1564,
+ 0x6eba, 0x0c28,
+ 0x6ebd, 0x1566,
+ 0x6ebf, 0x2150,
+ 0x6ec2, 0x156e,
+ 0x6ec4, 0x1568,
+ 0x6ec5, 0x0ed3,
+ 0x6ec9, 0x1563,
+ 0x6ecb, 0x08ce,
+ 0x6ecc, 0x157b,
+ 0x6ed1, 0x05c8,
+ 0x6ed3, 0x1565,
+ 0x6ed4, 0x156a,
+ 0x6edd, 0x0b4c,
+ 0x6ede, 0x0b3a,
+ 0x6eec, 0x1573,
+ 0x6eef, 0x1579,
+ 0x6ef2, 0x1577,
+ 0x6ef4, 0x0c23,
+ 0x6ef7, 0x157e,
+ 0x6ef8, 0x1574,
+ 0x6efe, 0x1575,
+ 0x6eff, 0x155d,
+ 0x6f01, 0x0693,
+ 0x6f02, 0x0dac,
+ 0x6f06, 0x08eb,
+ 0x6f09, 0x0809,
+ 0x6f0f, 0x0fd9,
+ 0x6f11, 0x1571,
+ 0x6f13, 0x157d,
+ 0x6f14, 0x050b,
+ 0x6f15, 0x0ae8,
+ 0x6f20, 0x0d2f,
+ 0x6f22, 0x05fd,
+ 0x6f23, 0x0fc2,
+ 0x6f2b, 0x0ead,
+ 0x6f2c, 0x0bee,
+ 0x6f31, 0x1578,
+ 0x6f32, 0x157a,
+ 0x6f38, 0x0ab4,
+ 0x6f3e, 0x157c,
+ 0x6f3f, 0x1576,
+ 0x6f41, 0x1570,
+ 0x6f45, 0x05ff,
+ 0x6f51, 0x1e60,
+ 0x6f54, 0x073f,
+ 0x6f58, 0x158a,
+ 0x6f5b, 0x1585,
+ 0x6f5c, 0x0a9c,
+ 0x6f5f, 0x05c1,
+ 0x6f64, 0x096b,
+ 0x6f66, 0x158e,
+ 0x6f6d, 0x1587,
+ 0x6f6e, 0x0bc8,
+ 0x6f6f, 0x1584,
+ 0x6f70, 0x0bf5,
+ 0x6f74, 0x15a7,
+ 0x6f78, 0x1581,
+ 0x6f7a, 0x1580,
+ 0x6f7c, 0x1589,
+ 0x6f80, 0x1583,
+ 0x6f81, 0x1582,
+ 0x6f82, 0x1588,
+ 0x6f84, 0x0a45,
+ 0x6f86, 0x157f,
+ 0x6f88, 0x2151,
+ 0x6f8e, 0x158b,
+ 0x6f91, 0x158c,
+ 0x6f97, 0x05fe,
+ 0x6fa1, 0x1591,
+ 0x6fa3, 0x1590,
+ 0x6fa4, 0x1592,
+ 0x6faa, 0x1595,
+ 0x6fb1, 0x0c3d,
+ 0x6fb3, 0x158f,
+ 0x6fb5, 0x2152,
+ 0x6fb9, 0x1593,
+ 0x6fc0, 0x0739,
+ 0x6fc1, 0x0b59,
+ 0x6fc2, 0x158d,
+ 0x6fc3, 0x0cf1,
+ 0x6fc6, 0x1594,
+ 0x6fd4, 0x1599,
+ 0x6fd5, 0x1597,
+ 0x6fd8, 0x159a,
+ 0x6fdb, 0x159d,
+ 0x6fdf, 0x1596,
+ 0x6fe0, 0x07fc,
+ 0x6fe1, 0x0cde,
+ 0x6fe4, 0x1536,
+ 0x6feb, 0x0f5e,
+ 0x6fec, 0x1598,
+ 0x6fee, 0x159c,
+ 0x6fef, 0x0b55,
+ 0x6ff1, 0x159b,
+ 0x6ff3, 0x1586,
+ 0x6ff5, 0x2153,
+ 0x6ff6, 0x1ba4,
+ 0x6ffa, 0x15a0,
+ 0x6ffe, 0x15a4,
+ 0x7001, 0x15a2,
+ 0x7005, 0x2154,
+ 0x7006, 0x1e50,
+ 0x7007, 0x2155,
+ 0x7009, 0x159e,
+ 0x700b, 0x159f,
+ 0x700f, 0x15a3,
+ 0x7011, 0x15a1,
+ 0x7015, 0x0dc0,
+ 0x7018, 0x15a9,
+ 0x701a, 0x15a6,
+ 0x701b, 0x15a5,
+ 0x701d, 0x15a8,
+ 0x701e, 0x0cac,
+ 0x701f, 0x15aa,
+ 0x7026, 0x0bb3,
+ 0x7027, 0x0b4d,
+ 0x7028, 0x2156,
+ 0x702c, 0x0a49,
+ 0x7030, 0x15ab,
+ 0x7032, 0x15ad,
+ 0x703e, 0x15ac,
+ 0x704c, 0x1572,
+ 0x7051, 0x15ae,
+ 0x7058, 0x0cbf,
+ 0x7063, 0x15af,
+ 0x706b, 0x0550,
+ 0x706f, 0x0c6e,
+ 0x7070, 0x0583,
+ 0x7078, 0x067e,
+ 0x707c, 0x090a,
+ 0x707d, 0x0842,
+ 0x7085, 0x2157,
+ 0x7089, 0x0fcd,
+ 0x708a, 0x0a2c,
+ 0x708e, 0x050c,
+ 0x7092, 0x15b1,
+ 0x7099, 0x15b0,
+ 0x70ab, 0x2158,
+ 0x70ac, 0x15b4,
+ 0x70ad, 0x0b78,
+ 0x70ae, 0x15b7,
+ 0x70af, 0x15b2,
+ 0x70b3, 0x15b6,
+ 0x70b8, 0x15b5,
+ 0x70b9, 0x0c3a,
+ 0x70ba, 0x049d,
+ 0x70bb, 0x20ad,
+ 0x70c8, 0x0fbd,
+ 0x70cb, 0x15b9,
+ 0x70cf, 0x04ca,
+ 0x70d9, 0x15bb,
+ 0x70dd, 0x15ba,
+ 0x70df, 0x15b8,
+ 0x70f1, 0x15b3,
+ 0x70f9, 0x0e51,
+ 0x70fd, 0x15bd,
+ 0x7104, 0x215a,
+ 0x7109, 0x15bc,
+ 0x710f, 0x2159,
+ 0x7114, 0x050d,
+ 0x7119, 0x15bf,
+ 0x711a, 0x0e02,
+ 0x711c, 0x15be,
+ 0x7121, 0x0ec1,
+ 0x7126, 0x09af,
+ 0x7130, 0x1ddc,
+ 0x7136, 0x0ab5,
+ 0x713c, 0x09ae,
+ 0x7146, 0x215c,
+ 0x7149, 0x0fc3,
+ 0x714c, 0x15c5,
+ 0x714e, 0x0a9d,
+ 0x7155, 0x15c1,
+ 0x7156, 0x15c6,
+ 0x7159, 0x050e,
+ 0x715c, 0x215b,
+ 0x7162, 0x15c4,
+ 0x7164, 0x0d17,
+ 0x7165, 0x15c0,
+ 0x7166, 0x15c3,
+ 0x7167, 0x09b0,
+ 0x7169, 0x0d65,
+ 0x716c, 0x15c7,
+ 0x716e, 0x08fd,
+ 0x717d, 0x0a9e,
+ 0x7184, 0x15ca,
+ 0x7188, 0x15c2,
+ 0x718a, 0x06fd,
+ 0x718f, 0x15c8,
+ 0x7194, 0x0f3a,
+ 0x7195, 0x15cb,
+ 0x7199, 0x205d,
+ 0x719f, 0x0959,
+ 0x71a8, 0x15cc,
+ 0x71ac, 0x15cd,
+ 0x71b1, 0x0ce4,
+ 0x71b9, 0x15cf,
+ 0x71be, 0x15d0,
+ 0x71c1, 0x215f,
+ 0x71c3, 0x0ce9,
+ 0x71c8, 0x0c6f,
+ 0x71c9, 0x15d2,
+ 0x71ce, 0x15d4,
+ 0x71d0, 0x0f9d,
+ 0x71d2, 0x15d1,
+ 0x71d4, 0x15d3,
+ 0x71d5, 0x050f,
+ 0x71d7, 0x15ce,
+ 0x71df, 0x114e,
+ 0x71e0, 0x15d5,
+ 0x71e5, 0x0ae9,
+ 0x71e6, 0x0886,
+ 0x71e7, 0x15d7,
+ 0x71ec, 0x15d6,
+ 0x71ed, 0x09ea,
+ 0x71ee, 0x10ee,
+ 0x71f5, 0x15d8,
+ 0x71f9, 0x15da,
+ 0x71fb, 0x15c9,
+ 0x71fc, 0x15d9,
+ 0x71fe, 0x2160,
+ 0x71ff, 0x15db,
+ 0x7206, 0x0d30,
+ 0x720d, 0x15dc,
+ 0x7210, 0x15dd,
+ 0x721b, 0x15de,
+ 0x7228, 0x15df,
+ 0x722a, 0x0bfa,
+ 0x722c, 0x15e1,
+ 0x722d, 0x15e0,
+ 0x7230, 0x15e2,
+ 0x7232, 0x15e3,
+ 0x7235, 0x090b,
+ 0x7236, 0x0dd5,
+ 0x723a, 0x0ef8,
+ 0x723b, 0x15e4,
+ 0x723d, 0x0ad8,
+ 0x723e, 0x08d0,
+ 0x723f, 0x15e6,
+ 0x7246, 0x15e8,
+ 0x7247, 0x0e22,
+ 0x7248, 0x0d5b,
+ 0x724b, 0x15e9,
+ 0x724c, 0x0d0d,
+ 0x7252, 0x0bc9,
+ 0x7258, 0x15ea,
+ 0x7259, 0x0567,
+ 0x725b, 0x0687,
+ 0x725d, 0x0ed2,
+ 0x725f, 0x0ec2,
+ 0x7261, 0x0534,
+ 0x7262, 0x0fda,
+ 0x7267, 0x0e80,
+ 0x7269, 0x0dfa,
+ 0x7272, 0x0a5b,
+ 0x7274, 0x15eb,
+ 0x7279, 0x0c9b,
+ 0x727d, 0x0757,
+ 0x727e, 0x15ec,
+ 0x7280, 0x0844,
+ 0x7281, 0x15ee,
+ 0x7282, 0x15ed,
+ 0x7287, 0x15ef,
+ 0x7292, 0x15f0,
+ 0x7296, 0x15f1,
+ 0x72a0, 0x0658,
+ 0x72a2, 0x15f2,
+ 0x72a7, 0x15f3,
+ 0x72ac, 0x0758,
+ 0x72af, 0x0d5c,
+ 0x72b1, 0x2161,
+ 0x72b2, 0x15f5,
+ 0x72b6, 0x09dd,
+ 0x72b9, 0x15f4,
+ 0x72be, 0x2162,
+ 0x72c2, 0x06b0,
+ 0x72c3, 0x15f6,
+ 0x72c4, 0x15f8,
+ 0x72c6, 0x15f7,
+ 0x72ce, 0x15f9,
+ 0x72d0, 0x0785,
+ 0x72d2, 0x15fa,
+ 0x72d7, 0x06e1,
+ 0x72d9, 0x0ac2,
+ 0x72db, 0x080f,
+ 0x72e0, 0x15fc,
+ 0x72e2, 0x15fb,
+ 0x72e9, 0x0919,
+ 0x72ec, 0x0ca0,
+ 0x72ed, 0x06b1,
+ 0x72f7, 0x15ff,
+ 0x72f8, 0x0b6a,
+ 0x72f9, 0x15fe,
+ 0x72fc, 0x0fdb,
+ 0x72fd, 0x0d18,
+ 0x730a, 0x1602,
+ 0x7316, 0x1604,
+ 0x7317, 0x1601,
+ 0x731b, 0x0ee0,
+ 0x731c, 0x1603,
+ 0x731d, 0x1605,
+ 0x731f, 0x0f8c,
+ 0x7324, 0x2163,
+ 0x7325, 0x1609,
+ 0x7329, 0x1608,
+ 0x732a, 0x0bb4,
+ 0x732b, 0x0ce3,
+ 0x732e, 0x0759,
+ 0x732f, 0x1607,
+ 0x7334, 0x1606,
+ 0x7336, 0x0f1b,
+ 0x733e, 0x160a,
+ 0x733f, 0x0510,
+ 0x7344, 0x0808,
+ 0x7345, 0x08b0,
+ 0x734e, 0x160b,
+ 0x7357, 0x160e,
+ 0x7363, 0x094d,
+ 0x7368, 0x1610,
+ 0x736a, 0x160f,
+ 0x7370, 0x1611,
+ 0x7372, 0x05ab,
+ 0x7375, 0x1613,
+ 0x7377, 0x2165,
+ 0x7378, 0x1612,
+ 0x737a, 0x1615,
+ 0x737b, 0x1614,
+ 0x7384, 0x0770,
+ 0x7387, 0x0f70,
+ 0x7389, 0x06c4,
+ 0x738b, 0x0526,
+ 0x7396, 0x06e2,
+ 0x73a9, 0x061d,
+ 0x73b2, 0x0fb0,
+ 0x73b3, 0x1617,
+ 0x73bb, 0x1619,
+ 0x73bd, 0x2166,
+ 0x73c0, 0x161a,
+ 0x73c2, 0x0551,
+ 0x73c8, 0x1616,
+ 0x73c9, 0x2167,
+ 0x73ca, 0x0887,
+ 0x73cd, 0x0bdd,
+ 0x73ce, 0x1618,
+ 0x73d2, 0x216a,
+ 0x73d6, 0x2168,
+ 0x73de, 0x161d,
+ 0x73e0, 0x091a,
+ 0x73e3, 0x2169,
+ 0x73e5, 0x161b,
+ 0x73ea, 0x0714,
+ 0x73ed, 0x0d5d,
+ 0x73ee, 0x161c,
+ 0x73f1, 0x1637,
+ 0x73f5, 0x216c,
+ 0x73f8, 0x1622,
+ 0x73fe, 0x0771,
+ 0x7403, 0x067f,
+ 0x7405, 0x161f,
+ 0x7406, 0x0f67,
+ 0x7407, 0x216b,
+ 0x7409, 0x0f78,
+ 0x7422, 0x0b56,
+ 0x7425, 0x1621,
+ 0x7426, 0x216d,
+ 0x7429, 0x216f,
+ 0x742a, 0x216e,
+ 0x742e, 0x2170,
+ 0x7432, 0x1623,
+ 0x7433, 0x0f9e,
+ 0x7434, 0x06cf,
+ 0x7435, 0x0d90,
+ 0x7436, 0x0d00,
+ 0x743a, 0x1624,
+ 0x743f, 0x1626,
+ 0x7441, 0x1629,
+ 0x7455, 0x1625,
+ 0x7459, 0x1628,
+ 0x745a, 0x079e,
+ 0x745b, 0x04ef,
+ 0x745c, 0x162a,
+ 0x745e, 0x0a36,
+ 0x745f, 0x1627,
+ 0x7460, 0x0fa4,
+ 0x7462, 0x2171,
+ 0x7463, 0x162d,
+ 0x7464, 0x1d35,
+ 0x7469, 0x162b,
+ 0x746a, 0x162e,
+ 0x746f, 0x1620,
+ 0x7470, 0x162c,
+ 0x7473, 0x082c,
+ 0x7476, 0x162f,
+ 0x747e, 0x1630,
+ 0x7483, 0x0f68,
+ 0x7489, 0x2172,
+ 0x748b, 0x1631,
+ 0x749e, 0x1632,
+ 0x749f, 0x2173,
+ 0x74a2, 0x161e,
+ 0x74a7, 0x1633,
+ 0x74b0, 0x0600,
+ 0x74bd, 0x08d1,
+ 0x74ca, 0x1634,
+ 0x74cf, 0x1635,
+ 0x74d4, 0x1636,
+ 0x74dc, 0x04dd,
+ 0x74e0, 0x1638,
+ 0x74e2, 0x0dad,
+ 0x74e3, 0x1639,
+ 0x74e6, 0x05e0,
+ 0x74e7, 0x163a,
+ 0x74e9, 0x163b,
+ 0x74ee, 0x163c,
+ 0x74f0, 0x163e,
+ 0x74f2, 0x163d,
+ 0x74f6, 0x0dc5,
+ 0x74f7, 0x1641,
+ 0x74f8, 0x1640,
+ 0x7501, 0x2174,
+ 0x7503, 0x1643,
+ 0x7504, 0x1642,
+ 0x7505, 0x1644,
+ 0x750c, 0x1645,
+ 0x750d, 0x1647,
+ 0x750e, 0x1646,
+ 0x7511, 0x080b,
+ 0x7513, 0x1649,
+ 0x7515, 0x1648,
+ 0x7518, 0x0601,
+ 0x751a, 0x0a19,
+ 0x751c, 0x0c36,
+ 0x751e, 0x164a,
+ 0x751f, 0x0a5c,
+ 0x7523, 0x0888,
+ 0x7525, 0x051b,
+ 0x7526, 0x164b,
+ 0x7528, 0x0f3b,
+ 0x752b, 0x0e33,
+ 0x752c, 0x164c,
+ 0x752f, 0x20f2,
+ 0x7530, 0x0c3e,
+ 0x7531, 0x0f1d,
+ 0x7532, 0x07d5,
+ 0x7533, 0x0a03,
+ 0x7537, 0x0b89,
+ 0x7538, 0x10c9,
+ 0x753a, 0x0bca,
+ 0x753b, 0x0568,
+ 0x753c, 0x164d,
+ 0x7544, 0x164e,
+ 0x7546, 0x1653,
+ 0x7549, 0x1651,
+ 0x754a, 0x1650,
+ 0x754b, 0x13c7,
+ 0x754c, 0x0584,
+ 0x754d, 0x164f,
+ 0x754f, 0x049e,
+ 0x7551, 0x0d3e,
+ 0x7554, 0x0d5e,
+ 0x7559, 0x0f79,
+ 0x755a, 0x1654,
+ 0x755b, 0x1652,
+ 0x755c, 0x0b9a,
+ 0x755d, 0x0a4a,
+ 0x7560, 0x0d3f,
+ 0x7562, 0x0d9f,
+ 0x7564, 0x1656,
+ 0x7565, 0x0f74,
+ 0x7566, 0x0723,
+ 0x7567, 0x1657,
+ 0x7569, 0x1655,
+ 0x756a, 0x0d6a,
+ 0x756b, 0x1658,
+ 0x756d, 0x1659,
+ 0x756f, 0x2175,
+ 0x7570, 0x049f,
+ 0x7573, 0x09de,
+ 0x7574, 0x165e,
+ 0x7576, 0x165b,
+ 0x7577, 0x0cc5,
+ 0x7578, 0x165a,
+ 0x757f, 0x0640,
+ 0x7582, 0x1661,
+ 0x7586, 0x165c,
+ 0x7589, 0x1660,
+ 0x758a, 0x165f,
+ 0x758b, 0x0d97,
+ 0x758e, 0x0ac4,
+ 0x758f, 0x0ac3,
+ 0x7591, 0x0659,
+ 0x7594, 0x1662,
+ 0x759a, 0x1663,
+ 0x759d, 0x1664,
+ 0x75a3, 0x1666,
+ 0x75a5, 0x1665,
+ 0x75ab, 0x04f8,
+ 0x75b1, 0x166e,
+ 0x75b2, 0x0d7c,
+ 0x75b3, 0x1668,
+ 0x75b5, 0x166a,
+ 0x75b8, 0x166c,
+ 0x75b9, 0x0a04,
+ 0x75bc, 0x166d,
+ 0x75bd, 0x166b,
+ 0x75be, 0x08ec,
+ 0x75c2, 0x1667,
+ 0x75c3, 0x1669,
+ 0x75c5, 0x0db4,
+ 0x75c7, 0x09b1,
+ 0x75ca, 0x1670,
+ 0x75cd, 0x166f,
+ 0x75d2, 0x1671,
+ 0x75d4, 0x08d2,
+ 0x75d5, 0x081f,
+ 0x75d8, 0x0c71,
+ 0x75d9, 0x1672,
+ 0x75db, 0x0be7,
+ 0x75de, 0x1674,
+ 0x75e2, 0x0f69,
+ 0x75e3, 0x1673,
+ 0x75e9, 0x0aeb,
+ 0x75f0, 0x1679,
+ 0x75f2, 0x167b,
+ 0x75f4, 0x0b92,
+ 0x75fa, 0x167a,
+ 0x75fc, 0x1677,
+ 0x75fe, 0x1675,
+ 0x7601, 0x1678,
+ 0x7609, 0x167f,
+ 0x760b, 0x167d,
+ 0x760d, 0x167e,
+ 0x761f, 0x1680,
+ 0x7620, 0x1682,
+ 0x7624, 0x1685,
+ 0x7626, 0x1e2d,
+ 0x7627, 0x1681,
+ 0x7630, 0x1687,
+ 0x7634, 0x1686,
+ 0x763b, 0x1688,
+ 0x7642, 0x0f8d,
+ 0x7646, 0x168b,
+ 0x7647, 0x1689,
+ 0x764c, 0x061e,
+ 0x7652, 0x0f0a,
+ 0x7656, 0x0e1a,
+ 0x7658, 0x168d,
+ 0x765c, 0x168c,
+ 0x7661, 0x168e,
+ 0x7667, 0x1693,
+ 0x7668, 0x1690,
+ 0x766c, 0x1694,
+ 0x7670, 0x1695,
+ 0x7672, 0x1696,
+ 0x7676, 0x1697,
+ 0x7678, 0x1698,
+ 0x767a, 0x0d43,
+ 0x767b, 0x0c4a,
+ 0x767c, 0x1699,
+ 0x767d, 0x0d28,
+ 0x767e, 0x0da6,
+ 0x7680, 0x169a,
+ 0x7682, 0x2176,
+ 0x7683, 0x169b,
+ 0x7684, 0x0c24,
+ 0x7686, 0x0585,
+ 0x7687, 0x07d6,
+ 0x7688, 0x169c,
+ 0x768b, 0x169d,
+ 0x768e, 0x169e,
+ 0x7690, 0x0877,
+ 0x7693, 0x16a0,
+ 0x7696, 0x169f,
+ 0x7699, 0x16a1,
+ 0x769b, 0x2179,
+ 0x769c, 0x2177,
+ 0x769e, 0x2178,
+ 0x76a6, 0x217a,
+ 0x76ae, 0x0d7d,
+ 0x76b0, 0x16a3,
+ 0x76b4, 0x16a4,
+ 0x76b7, 0x1d1c,
+ 0x76b8, 0x16a5,
+ 0x76bf, 0x087c,
+ 0x76c2, 0x16a8,
+ 0x76c3, 0x0d0c,
+ 0x76c6, 0x0e8d,
+ 0x76c8, 0x04f0,
+ 0x76ca, 0x04f9,
+ 0x76cd, 0x16a9,
+ 0x76d2, 0x16ab,
+ 0x76d6, 0x16aa,
+ 0x76d7, 0x0c6a,
+ 0x76db, 0x0a5d,
+ 0x76dc, 0x14d8,
+ 0x76de, 0x16ac,
+ 0x76df, 0x0ecd,
+ 0x76e1, 0x16ad,
+ 0x76e3, 0x0602,
+ 0x76e4, 0x0d6b,
+ 0x76e5, 0x16ae,
+ 0x76e7, 0x16af,
+ 0x76ea, 0x16b0,
+ 0x76ee, 0x0ee8,
+ 0x76f2, 0x0ee1,
+ 0x76f4, 0x0bda,
+ 0x76f8, 0x0aec,
+ 0x76fb, 0x16b2,
+ 0x76fe, 0x096c,
+ 0x7701, 0x09b2,
+ 0x7704, 0x16b5,
+ 0x7707, 0x16b4,
+ 0x7708, 0x16b3,
+ 0x7709, 0x0d91,
+ 0x770b, 0x0603,
+ 0x770c, 0x075d,
+ 0x771b, 0x16bb,
+ 0x771e, 0x16b8,
+ 0x771f, 0x0a05,
+ 0x7720, 0x0ebe,
+ 0x7724, 0x16b7,
+ 0x7725, 0x16b9,
+ 0x7729, 0x16b6,
+ 0x7737, 0x16bc,
+ 0x773a, 0x0bcb,
+ 0x773c, 0x061f,
+ 0x7740, 0x0ba3,
+ 0x7746, 0x217c,
+ 0x7747, 0x16be,
+ 0x775a, 0x16bf,
+ 0x775b, 0x16c2,
+ 0x7761, 0x0a2d,
+ 0x7762, 0x1ec5,
+ 0x7763, 0x0c9c,
+ 0x7765, 0x16c3,
+ 0x7766, 0x0e81,
+ 0x7768, 0x16c0,
+ 0x776b, 0x16c1,
+ 0x7779, 0x16c6,
+ 0x777e, 0x16c5,
+ 0x777f, 0x16c4,
+ 0x778b, 0x16c8,
+ 0x778e, 0x16c7,
+ 0x7791, 0x16c9,
+ 0x779e, 0x16cb,
+ 0x77a0, 0x16ca,
+ 0x77a5, 0x0e1d,
+ 0x77ac, 0x0960,
+ 0x77ad, 0x0f8e,
+ 0x77b0, 0x16cc,
+ 0x77b3, 0x0c8f,
+ 0x77b6, 0x16cd,
+ 0x77b9, 0x16ce,
+ 0x77bb, 0x16d2,
+ 0x77bc, 0x16d0,
+ 0x77bf, 0x16cf,
+ 0x77c7, 0x16d3,
+ 0x77cd, 0x16d4,
+ 0x77d7, 0x16d5,
+ 0x77da, 0x16d6,
+ 0x77db, 0x0ec3,
+ 0x77dc, 0x16d7,
+ 0x77e2, 0x0efc,
+ 0x77e3, 0x16d8,
+ 0x77e5, 0x0b8c,
+ 0x77e7, 0x0d20,
+ 0x77e9, 0x06e3,
+ 0x77ed, 0x0b79,
+ 0x77ee, 0x16d9,
+ 0x77ef, 0x06b2,
+ 0x77f3, 0x0a74,
+ 0x77fc, 0x16da,
+ 0x7802, 0x082d,
+ 0x780c, 0x16db,
+ 0x7812, 0x16dc,
+ 0x7814, 0x075a,
+ 0x7815, 0x0845,
+ 0x7820, 0x16de,
+ 0x7821, 0x217e,
+ 0x7825, 0x0c50,
+ 0x7826, 0x0846,
+ 0x7827, 0x0668,
+ 0x7832, 0x0e52,
+ 0x7834, 0x0d01,
+ 0x783a, 0x0c51,
+ 0x783f, 0x07ee,
+ 0x7845, 0x16e0,
+ 0x784e, 0x217f,
+ 0x785d, 0x09b3,
+ 0x7864, 0x2180,
+ 0x786b, 0x0f7a,
+ 0x786c, 0x07d7,
+ 0x786f, 0x075b,
+ 0x7872, 0x0d37,
+ 0x7874, 0x16e2,
+ 0x787a, 0x2181,
+ 0x787c, 0x16e4,
+ 0x7881, 0x079f,
+ 0x7886, 0x16e3,
+ 0x7887, 0x0c12,
+ 0x788c, 0x16e6,
+ 0x788d, 0x0595,
+ 0x788e, 0x16e1,
+ 0x7891, 0x0d7e,
+ 0x7893, 0x04d2,
+ 0x7895, 0x085c,
+ 0x7897, 0x0ff8,
+ 0x789a, 0x16e5,
+ 0x78a3, 0x16e7,
+ 0x78a7, 0x0e1b,
+ 0x78a9, 0x0a7d,
+ 0x78aa, 0x16e9,
+ 0x78af, 0x16ea,
+ 0x78b5, 0x16e8,
+ 0x78ba, 0x05ac,
+ 0x78bc, 0x16f0,
+ 0x78be, 0x16ef,
+ 0x78c1, 0x08d3,
+ 0x78c5, 0x16f1,
+ 0x78c6, 0x16ec,
+ 0x78ca, 0x16f2,
+ 0x78cb, 0x16ed,
+ 0x78d0, 0x0d6c,
+ 0x78d1, 0x16eb,
+ 0x78d4, 0x16ee,
+ 0x78da, 0x16f5,
+ 0x78e7, 0x16f4,
+ 0x78e8, 0x0e8f,
+ 0x78ec, 0x16f3,
+ 0x78ef, 0x04af,
+ 0x78f4, 0x16f7,
+ 0x78fd, 0x16f6,
+ 0x7901, 0x09b4,
+ 0x7907, 0x16f8,
+ 0x790e, 0x0ac5,
+ 0x7911, 0x16fa,
+ 0x7912, 0x16f9,
+ 0x7919, 0x16fb,
+ 0x7926, 0x16dd,
+ 0x792a, 0x16df,
+ 0x792b, 0x16fd,
+ 0x792c, 0x16fc,
+ 0x7930, 0x2182,
+ 0x793a, 0x08d4,
+ 0x793c, 0x0fb1,
+ 0x793e, 0x08fe,
+ 0x7940, 0x16fe,
+ 0x7941, 0x070d,
+ 0x7947, 0x065a,
+ 0x7948, 0x0641,
+ 0x7949, 0x08b1,
+ 0x7950, 0x0f1e,
+ 0x7953, 0x1704,
+ 0x7955, 0x1703,
+ 0x7956, 0x0ac6,
+ 0x7957, 0x1700,
+ 0x795a, 0x1702,
+ 0x795d, 0x0955,
+ 0x795e, 0x0a06,
+ 0x795f, 0x1701,
+ 0x7960, 0x16ff,
+ 0x7962, 0x0ce0,
+ 0x7965, 0x09b5,
+ 0x7968, 0x0dae,
+ 0x796d, 0x0847,
+ 0x7977, 0x0c72,
+ 0x797a, 0x1705,
+ 0x797f, 0x1706,
+ 0x7980, 0x171c,
+ 0x7981, 0x06d0,
+ 0x7984, 0x0fe3,
+ 0x7985, 0x0ab7,
+ 0x798a, 0x1707,
+ 0x798d, 0x0552,
+ 0x798e, 0x0c13,
+ 0x798f, 0x0df1,
+ 0x7994, 0x2186,
+ 0x799b, 0x2188,
+ 0x799d, 0x1708,
+ 0x79a6, 0x0694,
+ 0x79a7, 0x1709,
+ 0x79aa, 0x170b,
+ 0x79ae, 0x170c,
+ 0x79b0, 0x0cdf,
+ 0x79b1, 0x1e4e,
+ 0x79b3, 0x170d,
+ 0x79b9, 0x170e,
+ 0x79bd, 0x06d1,
+ 0x79be, 0x0553,
+ 0x79bf, 0x0c9d,
+ 0x79c0, 0x0932,
+ 0x79c1, 0x08b2,
+ 0x79c9, 0x1710,
+ 0x79cb, 0x0933,
+ 0x79d1, 0x054a,
+ 0x79d2, 0x0db5,
+ 0x79d5, 0x1711,
+ 0x79d8, 0x0d7f,
+ 0x79df, 0x0ac7,
+ 0x79e1, 0x1714,
+ 0x79e3, 0x1715,
+ 0x79e4, 0x0d1f,
+ 0x79e6, 0x0a07,
+ 0x79e7, 0x1712,
+ 0x79e9, 0x0b9f,
+ 0x79ec, 0x1713,
+ 0x79f0, 0x09b6,
+ 0x79fb, 0x04a0,
+ 0x7a00, 0x0643,
+ 0x7a08, 0x1716,
+ 0x7a0b, 0x0c14,
+ 0x7a0d, 0x1717,
+ 0x7a0e, 0x0a6b,
+ 0x7a14, 0x0eb9,
+ 0x7a17, 0x0d95,
+ 0x7a18, 0x1718,
+ 0x7a1a, 0x0b93,
+ 0x7a1c, 0x0f8f,
+ 0x7a1f, 0x171b,
+ 0x7a20, 0x171a,
+ 0x7a2e, 0x091b,
+ 0x7a31, 0x171d,
+ 0x7a32, 0x04b4,
+ 0x7a37, 0x1720,
+ 0x7a3b, 0x171e,
+ 0x7a3c, 0x0554,
+ 0x7a3d, 0x0724,
+ 0x7a3e, 0x171f,
+ 0x7a3f, 0x07d8,
+ 0x7a40, 0x0804,
+ 0x7a42, 0x0e36,
+ 0x7a43, 0x1721,
+ 0x7a46, 0x0e82,
+ 0x7a49, 0x1723,
+ 0x7a4d, 0x0a75,
+ 0x7a4e, 0x04f1,
+ 0x7a4f, 0x053a,
+ 0x7a50, 0x0470,
+ 0x7a57, 0x1722,
+ 0x7a61, 0x1724,
+ 0x7a63, 0x09df,
+ 0x7a69, 0x1726,
+ 0x7a6b, 0x05ad,
+ 0x7a70, 0x1728,
+ 0x7a74, 0x0740,
+ 0x7a76, 0x0680,
+ 0x7a79, 0x1729,
+ 0x7a7a, 0x06ed,
+ 0x7a7d, 0x172a,
+ 0x7a7f, 0x0aa0,
+ 0x7a81, 0x0ca5,
+ 0x7a83, 0x0a84,
+ 0x7a84, 0x0865,
+ 0x7a88, 0x172b,
+ 0x7a92, 0x0ba0,
+ 0x7a93, 0x0aed,
+ 0x7a95, 0x172d,
+ 0x7a96, 0x172f,
+ 0x7a97, 0x172c,
+ 0x7a98, 0x172e,
+ 0x7a9f, 0x06f8,
+ 0x7aa9, 0x1730,
+ 0x7aaa, 0x06fc,
+ 0x7aae, 0x0681,
+ 0x7aaf, 0x0f3c,
+ 0x7ab0, 0x1732,
+ 0x7ab6, 0x1733,
+ 0x7aba, 0x04d0,
+ 0x7abf, 0x1736,
+ 0x7ac3, 0x05d4,
+ 0x7ac4, 0x1735,
+ 0x7ac5, 0x1734,
+ 0x7ac7, 0x1738,
+ 0x7ac8, 0x1731,
+ 0x7aca, 0x1739,
+ 0x7acb, 0x0f71,
+ 0x7acd, 0x173a,
+ 0x7acf, 0x173b,
+ 0x7ad1, 0x2189,
+ 0x7ad2, 0x11c5,
+ 0x7ad3, 0x173d,
+ 0x7ad5, 0x173c,
+ 0x7ad9, 0x173e,
+ 0x7adc, 0x0f7d,
+ 0x7add, 0x1740,
+ 0x7adf, 0x1c08,
+ 0x7ae0, 0x09b7,
+ 0x7ae1, 0x1741,
+ 0x7ae3, 0x0961,
+ 0x7ae5, 0x0c90,
+ 0x7ae6, 0x1743,
+ 0x7ae7, 0x218a,
+ 0x7aea, 0x0b66,
+ 0x7aeb, 0x218c,
+ 0x7aed, 0x1744,
+ 0x7aef, 0x0b7a,
+ 0x7af0, 0x1745,
+ 0x7af6, 0x069d,
+ 0x7af8, 0x1076,
+ 0x7af9, 0x0b9b,
+ 0x7afa, 0x08df,
+ 0x7aff, 0x0604,
+ 0x7b02, 0x1746,
+ 0x7b04, 0x1753,
+ 0x7b06, 0x1749,
+ 0x7b08, 0x0682,
+ 0x7b0a, 0x1748,
+ 0x7b0b, 0x1755,
+ 0x7b0f, 0x1747,
+ 0x7b11, 0x09b8,
+ 0x7b18, 0x174b,
+ 0x7b1b, 0x0c25,
+ 0x7b1e, 0x174d,
+ 0x7b20, 0x05bc,
+ 0x7b25, 0x0a20,
+ 0x7b26, 0x0dd6,
+ 0x7b28, 0x174f,
+ 0x7b2c, 0x0b48,
+ 0x7b33, 0x174a,
+ 0x7b35, 0x174e,
+ 0x7b36, 0x1750,
+ 0x7b39, 0x086b,
+ 0x7b45, 0x1757,
+ 0x7b46, 0x0da0,
+ 0x7b48, 0x0d3a,
+ 0x7b49, 0x0c73,
+ 0x7b4b, 0x06d2,
+ 0x7b4c, 0x1756,
+ 0x7b4d, 0x1754,
+ 0x7b4f, 0x0d49,
+ 0x7b50, 0x1751,
+ 0x7b51, 0x0b9c,
+ 0x7b52, 0x0c75,
+ 0x7b54, 0x0c74,
+ 0x7b56, 0x0866,
+ 0x7b5d, 0x1769,
+ 0x7b65, 0x1759,
+ 0x7b67, 0x175b,
+ 0x7b6c, 0x175e,
+ 0x7b6e, 0x175f,
+ 0x7b70, 0x175c,
+ 0x7b74, 0x175a,
+ 0x7b75, 0x1758,
+ 0x7b7a, 0x1752,
+ 0x7b86, 0x0e1f,
+ 0x7b87, 0x0555,
+ 0x7b8b, 0x1766,
+ 0x7b8d, 0x1763,
+ 0x7b8f, 0x1768,
+ 0x7b92, 0x1767,
+ 0x7b94, 0x0d29,
+ 0x7b95, 0x0eb3,
+ 0x7b97, 0x0889,
+ 0x7b98, 0x1761,
+ 0x7b99, 0x176a,
+ 0x7b9a, 0x1765,
+ 0x7b9c, 0x1764,
+ 0x7b9d, 0x1760,
+ 0x7b9e, 0x218d,
+ 0x7b9f, 0x1762,
+ 0x7ba1, 0x0605,
+ 0x7baa, 0x0b7b,
+ 0x7bad, 0x0aa1,
+ 0x7bb1, 0x0d36,
+ 0x7bb4, 0x176f,
+ 0x7bb8, 0x0d38,
+ 0x7bc0, 0x0a85,
+ 0x7bc1, 0x176c,
+ 0x7bc4, 0x0d63,
+ 0x7bc6, 0x1770,
+ 0x7bc7, 0x0e23,
+ 0x7bc9, 0x0b99,
+ 0x7bcb, 0x176b,
+ 0x7bcc, 0x176d,
+ 0x7bcf, 0x176e,
+ 0x7bdd, 0x1771,
+ 0x7be0, 0x08f0,
+ 0x7be4, 0x0c9e,
+ 0x7be5, 0x1776,
+ 0x7be6, 0x1775,
+ 0x7be9, 0x1772,
+ 0x7bed, 0x0fdc,
+ 0x7bf3, 0x177b,
+ 0x7bf6, 0x177f,
+ 0x7bf7, 0x177c,
+ 0x7c00, 0x1778,
+ 0x7c07, 0x1779,
+ 0x7c0d, 0x177e,
+ 0x7c11, 0x1773,
+ 0x7c12, 0x10ea,
+ 0x7c13, 0x177a,
+ 0x7c14, 0x1774,
+ 0x7c17, 0x177d,
+ 0x7c1e, 0x1e3b,
+ 0x7c1f, 0x1783,
+ 0x7c21, 0x0606,
+ 0x7c23, 0x1780,
+ 0x7c27, 0x1781,
+ 0x7c2a, 0x1782,
+ 0x7c2b, 0x1785,
+ 0x7c37, 0x1784,
+ 0x7c38, 0x0d8a,
+ 0x7c3d, 0x1786,
+ 0x7c3e, 0x0fc4,
+ 0x7c3f, 0x0e3d,
+ 0x7c40, 0x178b,
+ 0x7c43, 0x1788,
+ 0x7c4c, 0x1787,
+ 0x7c4d, 0x0a76,
+ 0x7c4f, 0x178a,
+ 0x7c50, 0x178c,
+ 0x7c54, 0x1789,
+ 0x7c56, 0x1790,
+ 0x7c58, 0x178d,
+ 0x7c5f, 0x178e,
+ 0x7c60, 0x1777,
+ 0x7c64, 0x178f,
+ 0x7c65, 0x1791,
+ 0x7c6c, 0x1792,
+ 0x7c73, 0x0e16,
+ 0x7c75, 0x1793,
+ 0x7c7e, 0x0eee,
+ 0x7c81, 0x06c6,
+ 0x7c82, 0x06ff,
+ 0x7c83, 0x1794,
+ 0x7c89, 0x0e04,
+ 0x7c8b, 0x0a2e,
+ 0x7c8d, 0x0ebc,
+ 0x7c90, 0x1795,
+ 0x7c92, 0x0f7b,
+ 0x7c95, 0x0d2a,
+ 0x7c97, 0x0ac8,
+ 0x7c98, 0x0cea,
+ 0x7c9b, 0x0957,
+ 0x7c9f, 0x0484,
+ 0x7ca1, 0x179a,
+ 0x7ca2, 0x1798,
+ 0x7ca4, 0x1796,
+ 0x7ca5, 0x05dd,
+ 0x7ca7, 0x09b9,
+ 0x7ca8, 0x179b,
+ 0x7cab, 0x1799,
+ 0x7cad, 0x1797,
+ 0x7cae, 0x179f,
+ 0x7cb1, 0x179e,
+ 0x7cb2, 0x179d,
+ 0x7cb3, 0x179c,
+ 0x7cb9, 0x17a0,
+ 0x7cbd, 0x17a1,
+ 0x7cbe, 0x0a5e,
+ 0x7cc0, 0x17a2,
+ 0x7cc2, 0x17a4,
+ 0x7cc5, 0x17a3,
+ 0x7cca, 0x0786,
+ 0x7cce, 0x0aba,
+ 0x7cd2, 0x17a6,
+ 0x7cd6, 0x0c76,
+ 0x7cd8, 0x17a5,
+ 0x7cdc, 0x17a7,
+ 0x7cde, 0x0e05,
+ 0x7cdf, 0x0aee,
+ 0x7ce0, 0x07d9,
+ 0x7ce2, 0x17a8,
+ 0x7ce7, 0x0f90,
+ 0x7cef, 0x17aa,
+ 0x7cf2, 0x17ab,
+ 0x7cf4, 0x17ac,
+ 0x7cf6, 0x17ad,
+ 0x7cf8, 0x08b3,
+ 0x7cfa, 0x17ae,
+ 0x7cfb, 0x0725,
+ 0x7cfe, 0x0684,
+ 0x7d00, 0x0644,
+ 0x7d02, 0x17b0,
+ 0x7d04, 0x0eff,
+ 0x7d05, 0x07da,
+ 0x7d06, 0x17af,
+ 0x7d0a, 0x17b3,
+ 0x7d0b, 0x0ef2,
+ 0x7d0d, 0x0cf2,
+ 0x7d10, 0x0da5,
+ 0x7d14, 0x096d,
+ 0x7d15, 0x17b2,
+ 0x7d17, 0x08ff,
+ 0x7d18, 0x07db,
+ 0x7d19, 0x08b4,
+ 0x7d1a, 0x0683,
+ 0x7d1b, 0x0e06,
+ 0x7d1c, 0x17b1,
+ 0x7d20, 0x0ac9,
+ 0x7d21, 0x0e70,
+ 0x7d22, 0x0867,
+ 0x7d2b, 0x08b5,
+ 0x7d2c, 0x0bf9,
+ 0x7d2e, 0x17b6,
+ 0x7d2f, 0x0fa7,
+ 0x7d30, 0x0849,
+ 0x7d32, 0x17b7,
+ 0x7d33, 0x0a08,
+ 0x7d35, 0x17b9,
+ 0x7d39, 0x09ba,
+ 0x7d3a, 0x0820,
+ 0x7d3f, 0x17b8,
+ 0x7d42, 0x0934,
+ 0x7d43, 0x0772,
+ 0x7d44, 0x0aca,
+ 0x7d45, 0x17b4,
+ 0x7d46, 0x17ba,
+ 0x7d48, 0x218f,
+ 0x7d4b, 0x17b5,
+ 0x7d4c, 0x0726,
+ 0x7d4e, 0x17bd,
+ 0x7d4f, 0x17c1,
+ 0x7d50, 0x0741,
+ 0x7d56, 0x17bc,
+ 0x7d5b, 0x17c5,
+ 0x7d5c, 0x2190,
+ 0x7d5e, 0x07dc,
+ 0x7d61, 0x0f57,
+ 0x7d62, 0x0480,
+ 0x7d63, 0x17c2,
+ 0x7d66, 0x0685,
+ 0x7d68, 0x17bf,
+ 0x7d6e, 0x17c0,
+ 0x7d71, 0x0c77,
+ 0x7d72, 0x17be,
+ 0x7d73, 0x17bb,
+ 0x7d75, 0x0586,
+ 0x7d76, 0x0a88,
+ 0x7d79, 0x075c,
+ 0x7d7d, 0x17c7,
+ 0x7d89, 0x17c4,
+ 0x7d8f, 0x17c6,
+ 0x7d93, 0x17c3,
+ 0x7d99, 0x0727,
+ 0x7d9a, 0x0b13,
+ 0x7d9b, 0x17c8,
+ 0x7d9c, 0x0af0,
+ 0x7d9f, 0x17d5,
+ 0x7da0, 0x2192,
+ 0x7da2, 0x17d1,
+ 0x7da3, 0x17cb,
+ 0x7dab, 0x17cf,
+ 0x7dac, 0x0926,
+ 0x7dad, 0x04a1,
+ 0x7dae, 0x17ca,
+ 0x7daf, 0x17d2,
+ 0x7db0, 0x17d6,
+ 0x7db1, 0x07dd,
+ 0x7db2, 0x0ee2,
+ 0x7db4, 0x0bf2,
+ 0x7db5, 0x17cc,
+ 0x7db7, 0x2191,
+ 0x7db8, 0x17d4,
+ 0x7dba, 0x17c9,
+ 0x7dbb, 0x0b7c,
+ 0x7dbd, 0x17ce,
+ 0x7dbe, 0x0481,
+ 0x7dbf, 0x0ed6,
+ 0x7dc7, 0x17cd,
+ 0x7dca, 0x06d3,
+ 0x7dcb, 0x0d80,
+ 0x7dcf, 0x0aef,
+ 0x7dd1, 0x0f98,
+ 0x7dd2, 0x0979,
+ 0x7dd5, 0x17fd,
+ 0x7dd6, 0x2193,
+ 0x7dd8, 0x17d7,
+ 0x7dda, 0x0aa2,
+ 0x7ddc, 0x17d3,
+ 0x7ddd, 0x17d8,
+ 0x7dde, 0x17da,
+ 0x7de0, 0x0c15,
+ 0x7de1, 0x17dd,
+ 0x7de4, 0x17d9,
+ 0x7de8, 0x0e24,
+ 0x7de9, 0x0607,
+ 0x7dec, 0x0ed7,
+ 0x7def, 0x04a2,
+ 0x7df2, 0x17dc,
+ 0x7df4, 0x0fc5,
+ 0x7dfb, 0x17db,
+ 0x7e01, 0x0511,
+ 0x7e04, 0x0cc4,
+ 0x7e05, 0x17de,
+ 0x7e09, 0x17e5,
+ 0x7e0a, 0x17df,
+ 0x7e0b, 0x17e6,
+ 0x7e12, 0x17e2,
+ 0x7e1b, 0x0d31,
+ 0x7e1e, 0x08f6,
+ 0x7e1f, 0x17e4,
+ 0x7e21, 0x17e1,
+ 0x7e22, 0x17e7,
+ 0x7e23, 0x17e0,
+ 0x7e26, 0x094e,
+ 0x7e2b, 0x0e53,
+ 0x7e2e, 0x0956,
+ 0x7e31, 0x17e3,
+ 0x7e32, 0x17ef,
+ 0x7e35, 0x17eb,
+ 0x7e37, 0x17ee,
+ 0x7e39, 0x17ec,
+ 0x7e3a, 0x17f0,
+ 0x7e3b, 0x17ea,
+ 0x7e3d, 0x17d0,
+ 0x7e3e, 0x0a77,
+ 0x7e41, 0x0d5f,
+ 0x7e43, 0x17ed,
+ 0x7e46, 0x17e8,
+ 0x7e4a, 0x0aa3,
+ 0x7e4b, 0x0728,
+ 0x7e4d, 0x0935,
+ 0x7e52, 0x2194,
+ 0x7e54, 0x09eb,
+ 0x7e55, 0x0ab8,
+ 0x7e56, 0x17f3,
+ 0x7e59, 0x17f5,
+ 0x7e5d, 0x17f2,
+ 0x7e5e, 0x17f4,
+ 0x7e61, 0x1e11,
+ 0x7e66, 0x17e9,
+ 0x7e67, 0x17f1,
+ 0x7e69, 0x17f9,
+ 0x7e6a, 0x17f8,
+ 0x7e6b, 0x1df7,
+ 0x7e6d, 0x0ea8,
+ 0x7e70, 0x0701,
+ 0x7e79, 0x17f7,
+ 0x7e7b, 0x17fb,
+ 0x7e7c, 0x17fa,
+ 0x7e7d, 0x17fe,
+ 0x7e7f, 0x1800,
+ 0x7e82, 0x088a,
+ 0x7e83, 0x17fc,
+ 0x7e88, 0x1801,
+ 0x7e8a, 0x20a7,
+ 0x7e8c, 0x1803,
+ 0x7e8e, 0x1809,
+ 0x7e8f, 0x0c35,
+ 0x7e90, 0x1805,
+ 0x7e92, 0x1804,
+ 0x7e93, 0x1806,
+ 0x7e96, 0x1808,
+ 0x7e9b, 0x180a,
+ 0x7f36, 0x0608,
+ 0x7f38, 0x180c,
+ 0x7f3a, 0x180d,
+ 0x7f45, 0x180e,
+ 0x7f47, 0x2195,
+ 0x7f4c, 0x180f,
+ 0x7f50, 0x1812,
+ 0x7f54, 0x1815,
+ 0x7f55, 0x1814,
+ 0x7f58, 0x1816,
+ 0x7f5f, 0x1817,
+ 0x7f67, 0x181b,
+ 0x7f68, 0x1819,
+ 0x7f6a, 0x0851,
+ 0x7f6b, 0x0729,
+ 0x7f6e, 0x0b94,
+ 0x7f70, 0x0d47,
+ 0x7f72, 0x097a,
+ 0x7f75, 0x0d03,
+ 0x7f77, 0x0d81,
+ 0x7f78, 0x181c,
+ 0x7f79, 0x1336,
+ 0x7f82, 0x181d,
+ 0x7f83, 0x181f,
+ 0x7f85, 0x0f4f,
+ 0x7f86, 0x181e,
+ 0x7f87, 0x1821,
+ 0x7f88, 0x1820,
+ 0x7f8a, 0x0f3d,
+ 0x7f8c, 0x1822,
+ 0x7f8e, 0x0d92,
+ 0x7f94, 0x1823,
+ 0x7f9a, 0x1826,
+ 0x7f9d, 0x1825,
+ 0x7f9e, 0x1824,
+ 0x7fa1, 0x2196,
+ 0x7fa3, 0x1827,
+ 0x7fa4, 0x0708,
+ 0x7fa8, 0x0aa4,
+ 0x7fa9, 0x065b,
+ 0x7fae, 0x182b,
+ 0x7faf, 0x1828,
+ 0x7fb2, 0x1829,
+ 0x7fb6, 0x182c,
+ 0x7fb8, 0x182d,
+ 0x7fb9, 0x182a,
+ 0x7fbd, 0x04cb,
+ 0x7fc1, 0x0527,
+ 0x7fc5, 0x182f,
+ 0x7fca, 0x1831,
+ 0x7fcc, 0x0f4c,
+ 0x7fd2, 0x0936,
+ 0x7fd4, 0x1833,
+ 0x7fd5, 0x1832,
+ 0x7fe0, 0x0a2f,
+ 0x7fe1, 0x1834,
+ 0x7fe6, 0x1835,
+ 0x7fe9, 0x1836,
+ 0x7feb, 0x0621,
+ 0x7ff0, 0x0609,
+ 0x7ff3, 0x1837,
+ 0x7ff9, 0x1838,
+ 0x7ffb, 0x0e8b,
+ 0x7ffc, 0x0f4d,
+ 0x8000, 0x0f3e,
+ 0x8001, 0x0fdd,
+ 0x8003, 0x07df,
+ 0x8004, 0x183b,
+ 0x8005, 0x0900,
+ 0x8006, 0x183a,
+ 0x800b, 0x183c,
+ 0x800c, 0x08d5,
+ 0x8010, 0x0b31,
+ 0x8012, 0x183d,
+ 0x8015, 0x07de,
+ 0x8017, 0x0ee3,
+ 0x8018, 0x183e,
+ 0x801c, 0x1840,
+ 0x8021, 0x1841,
+ 0x8028, 0x1842,
+ 0x8033, 0x08d6,
+ 0x8036, 0x0ef9,
+ 0x803b, 0x1844,
+ 0x803d, 0x0b7d,
+ 0x803f, 0x1843,
+ 0x8046, 0x1846,
+ 0x804a, 0x1845,
+ 0x8052, 0x1847,
+ 0x8056, 0x0a5f,
+ 0x8058, 0x1848,
+ 0x805a, 0x1849,
+ 0x805e, 0x0e09,
+ 0x805f, 0x184a,
+ 0x8061, 0x0af1,
+ 0x8062, 0x184b,
+ 0x8068, 0x184c,
+ 0x806f, 0x0fc6,
+ 0x8070, 0x184f,
+ 0x8072, 0x184e,
+ 0x8073, 0x184d,
+ 0x8074, 0x0bcc,
+ 0x8076, 0x1850,
+ 0x8077, 0x09ec,
+ 0x8079, 0x1851,
+ 0x807d, 0x1852,
+ 0x807e, 0x0fde,
+ 0x807f, 0x1853,
+ 0x8084, 0x1854,
+ 0x8085, 0x1856,
+ 0x8086, 0x1855,
+ 0x8087, 0x0d39,
+ 0x8089, 0x0cd1,
+ 0x808b, 0x0fe4,
+ 0x808c, 0x0d3d,
+ 0x8093, 0x1858,
+ 0x8096, 0x09bb,
+ 0x8098, 0x0d9c,
+ 0x809a, 0x1859,
+ 0x809b, 0x1857,
+ 0x809d, 0x060a,
+ 0x80a1, 0x0788,
+ 0x80a2, 0x08b6,
+ 0x80a5, 0x0d82,
+ 0x80a9, 0x075e,
+ 0x80aa, 0x0e71,
+ 0x80ac, 0x185c,
+ 0x80ad, 0x185a,
+ 0x80af, 0x07e0,
+ 0x80b1, 0x07e1,
+ 0x80b2, 0x04ad,
+ 0x80b4, 0x0858,
+ 0x80ba, 0x0d0f,
+ 0x80c3, 0x04a3,
+ 0x80c4, 0x1861,
+ 0x80c6, 0x0b7e,
+ 0x80cc, 0x0d0e,
+ 0x80ce, 0x0b3b,
+ 0x80d6, 0x1863,
+ 0x80d9, 0x185f,
+ 0x80da, 0x1862,
+ 0x80db, 0x185d,
+ 0x80dd, 0x1860,
+ 0x80de, 0x0e54,
+ 0x80e1, 0x0789,
+ 0x80e4, 0x04c1,
+ 0x80e5, 0x185e,
+ 0x80ef, 0x1865,
+ 0x80f1, 0x1866,
+ 0x80f4, 0x0c91,
+ 0x80f8, 0x06b3,
+ 0x80fc, 0x1871,
+ 0x80fd, 0x0cf3,
+ 0x8102, 0x08b7,
+ 0x8105, 0x06b4,
+ 0x8106, 0x0a6c,
+ 0x8107, 0x0fec,
+ 0x8108, 0x0eba,
+ 0x8109, 0x1864,
+ 0x810a, 0x0a78,
+ 0x811a, 0x066d,
+ 0x811b, 0x1867,
+ 0x8123, 0x1869,
+ 0x8129, 0x1868,
+ 0x812f, 0x186a,
+ 0x8131, 0x0b64,
+ 0x8133, 0x0cf4,
+ 0x8139, 0x0bcd,
+ 0x813e, 0x186e,
+ 0x8146, 0x186d,
+ 0x814b, 0x186b,
+ 0x814e, 0x0a1b,
+ 0x8150, 0x0dd7,
+ 0x8151, 0x1870,
+ 0x8153, 0x186f,
+ 0x8154, 0x07e2,
+ 0x8155, 0x0ff9,
+ 0x815f, 0x1880,
+ 0x8165, 0x1874,
+ 0x816b, 0x091c,
+ 0x816e, 0x1873,
+ 0x8170, 0x080a,
+ 0x8171, 0x1872,
+ 0x8174, 0x1876,
+ 0x8178, 0x0bce,
+ 0x8179, 0x0df2,
+ 0x817a, 0x0aa5,
+ 0x817f, 0x0b3c,
+ 0x8180, 0x187a,
+ 0x8182, 0x187b,
+ 0x8183, 0x1877,
+ 0x8188, 0x1878,
+ 0x818a, 0x1879,
+ 0x818f, 0x07e3,
+ 0x8193, 0x1881,
+ 0x8195, 0x187d,
+ 0x819a, 0x0dd8,
+ 0x819c, 0x0e9a,
+ 0x819d, 0x0d9a,
+ 0x81a0, 0x187c,
+ 0x81a3, 0x187f,
+ 0x81a4, 0x187e,
+ 0x81a8, 0x0e72,
+ 0x81a9, 0x1882,
+ 0x81b0, 0x1883,
+ 0x81b3, 0x0ab9,
+ 0x81b5, 0x1884,
+ 0x81b8, 0x1886,
+ 0x81ba, 0x188a,
+ 0x81bd, 0x1887,
+ 0x81be, 0x1885,
+ 0x81bf, 0x0cf5,
+ 0x81c0, 0x1888,
+ 0x81c2, 0x1889,
+ 0x81c6, 0x0532,
+ 0x81c8, 0x1890,
+ 0x81c9, 0x188b,
+ 0x81cd, 0x188c,
+ 0x81d1, 0x188d,
+ 0x81d3, 0x0b01,
+ 0x81d8, 0x188f,
+ 0x81d9, 0x188e,
+ 0x81da, 0x1891,
+ 0x81df, 0x1892,
+ 0x81e3, 0x0a09,
+ 0x81e5, 0x0569,
+ 0x81e7, 0x1894,
+ 0x81e8, 0x0f9f,
+ 0x81ea, 0x08d7,
+ 0x81ed, 0x0937,
+ 0x81f3, 0x08b8,
+ 0x81f4, 0x0b95,
+ 0x81fa, 0x1895,
+ 0x81fc, 0x04d3,
+ 0x81fe, 0x1897,
+ 0x8201, 0x1898,
+ 0x8205, 0x189a,
+ 0x8207, 0x189b,
+ 0x8208, 0x06b5,
+ 0x8209, 0x13af,
+ 0x820a, 0x189c,
+ 0x820c, 0x0a89,
+ 0x820d, 0x189d,
+ 0x820e, 0x08f7,
+ 0x8210, 0x189e,
+ 0x8212, 0x1009,
+ 0x8216, 0x189f,
+ 0x8217, 0x0e2e,
+ 0x8218, 0x0618,
+ 0x821b, 0x0aa6,
+ 0x821c, 0x0962,
+ 0x821e, 0x0de3,
+ 0x821f, 0x0938,
+ 0x8229, 0x18a0,
+ 0x822a, 0x07e4,
+ 0x822b, 0x18a1,
+ 0x822c, 0x0d60,
+ 0x822e, 0x18af,
+ 0x8233, 0x18a3,
+ 0x8235, 0x0b29,
+ 0x8236, 0x0d2b,
+ 0x8237, 0x0773,
+ 0x8238, 0x18a2,
+ 0x8239, 0x0aa7,
+ 0x8240, 0x18a4,
+ 0x8247, 0x0c16,
+ 0x8258, 0x18a6,
+ 0x8259, 0x18a5,
+ 0x825a, 0x18a8,
+ 0x825d, 0x18a7,
+ 0x825f, 0x18a9,
+ 0x8262, 0x18ab,
+ 0x8264, 0x18aa,
+ 0x8266, 0x060b,
+ 0x8268, 0x18ac,
+ 0x826a, 0x18ad,
+ 0x826e, 0x0821,
+ 0x826f, 0x0f91,
+ 0x8271, 0x18b0,
+ 0x8272, 0x09ed,
+ 0x8276, 0x0512,
+ 0x8277, 0x18b1,
+ 0x827e, 0x18b3,
+ 0x828b, 0x04b6,
+ 0x828d, 0x18b4,
+ 0x8292, 0x18b5,
+ 0x8299, 0x0dd9,
+ 0x829d, 0x08f3,
+ 0x829f, 0x18b7,
+ 0x82a5, 0x0587,
+ 0x82a6, 0x0476,
+ 0x82ab, 0x18b6,
+ 0x82ac, 0x18b9,
+ 0x82ad, 0x0d04,
+ 0x82af, 0x0a0a,
+ 0x82b1, 0x0556,
+ 0x82b3, 0x0e55,
+ 0x82b8, 0x0733,
+ 0x82b9, 0x06d4,
+ 0x82bb, 0x18b8,
+ 0x82bd, 0x056a,
+ 0x82c5, 0x05df,
+ 0x82d1, 0x0513,
+ 0x82d2, 0x18bd,
+ 0x82d3, 0x0fb2,
+ 0x82d4, 0x0b3d,
+ 0x82d7, 0x0db6,
+ 0x82d9, 0x18c9,
+ 0x82db, 0x0557,
+ 0x82dc, 0x18c7,
+ 0x82de, 0x18c5,
+ 0x82df, 0x18bc,
+ 0x82e1, 0x18ba,
+ 0x82e3, 0x18bb,
+ 0x82e5, 0x090f,
+ 0x82e6, 0x06e4,
+ 0x82e7, 0x0bb5,
+ 0x82eb, 0x0ca9,
+ 0x82f1, 0x04f3,
+ 0x82f3, 0x18bf,
+ 0x82f4, 0x18be,
+ 0x82f9, 0x18c4,
+ 0x82fa, 0x18c0,
+ 0x82fb, 0x18c3,
+ 0x8301, 0x2198,
+ 0x8302, 0x0edc,
+ 0x8303, 0x18c2,
+ 0x8304, 0x0558,
+ 0x8305, 0x05db,
+ 0x8306, 0x18c6,
+ 0x8309, 0x18c8,
+ 0x830e, 0x072a,
+ 0x8316, 0x18cc,
+ 0x8317, 0x18d5,
+ 0x831c, 0x046f,
+ 0x8323, 0x18dd,
+ 0x8328, 0x04b5,
+ 0x832b, 0x18d4,
+ 0x832f, 0x18d3,
+ 0x8331, 0x18ce,
+ 0x8332, 0x18cd,
+ 0x8334, 0x18cb,
+ 0x8335, 0x18ca,
+ 0x8336, 0x0ba1,
+ 0x8338, 0x0b5b,
+ 0x8339, 0x18d0,
+ 0x8340, 0x18cf,
+ 0x8345, 0x18d2,
+ 0x8349, 0x0af2,
+ 0x834a, 0x072b,
+ 0x834f, 0x04e3,
+ 0x8350, 0x18d1,
+ 0x8352, 0x07e5,
+ 0x8358, 0x0af3,
+ 0x8362, 0x2199,
+ 0x8373, 0x18e3,
+ 0x8375, 0x18e4,
+ 0x8377, 0x0559,
+ 0x837b, 0x052e,
+ 0x837c, 0x18e1,
+ 0x837f, 0x219a,
+ 0x8385, 0x18d7,
+ 0x8387, 0x18df,
+ 0x8389, 0x18e6,
+ 0x838a, 0x18e0,
+ 0x838e, 0x18de,
+ 0x8393, 0x18c1,
+ 0x8396, 0x18dc,
+ 0x839a, 0x18d8,
+ 0x839e, 0x060c,
+ 0x839f, 0x18da,
+ 0x83a0, 0x18e5,
+ 0x83a2, 0x18db,
+ 0x83a8, 0x18e7,
+ 0x83aa, 0x18d9,
+ 0x83ab, 0x0d32,
+ 0x83b1, 0x0f53,
+ 0x83b5, 0x18e2,
+ 0x83bd, 0x18f8,
+ 0x83c1, 0x18f0,
+ 0x83c5, 0x0a41,
+ 0x83c7, 0x219b,
+ 0x83ca, 0x0660,
+ 0x83cc, 0x06d5,
+ 0x83ce, 0x18eb,
+ 0x83d3, 0x055b,
+ 0x83d6, 0x09bc,
+ 0x83d8, 0x18ee,
+ 0x83dc, 0x084a,
+ 0x83df, 0x0c4b,
+ 0x83e0, 0x18f3,
+ 0x83e9, 0x0e3e,
+ 0x83eb, 0x18ea,
+ 0x83ef, 0x055a,
+ 0x83f0, 0x078a,
+ 0x83f1, 0x0d9b,
+ 0x83f2, 0x18f4,
+ 0x83f4, 0x18e8,
+ 0x83f6, 0x219c,
+ 0x83f7, 0x18f1,
+ 0x83fb, 0x18fb,
+ 0x83fd, 0x18ec,
+ 0x8403, 0x18ed,
+ 0x8404, 0x0c92,
+ 0x8407, 0x18f2,
+ 0x840a, 0x1e7f,
+ 0x840b, 0x18ef,
+ 0x840c, 0x0e56,
+ 0x840d, 0x18f5,
+ 0x840e, 0x04a4,
+ 0x8413, 0x18e9,
+ 0x8420, 0x18f7,
+ 0x8422, 0x18f6,
+ 0x8429, 0x0d21,
+ 0x842a, 0x18fd,
+ 0x842c, 0x1908,
+ 0x8431, 0x05dc,
+ 0x8435, 0x190b,
+ 0x8438, 0x18f9,
+ 0x843c, 0x18fe,
+ 0x843d, 0x0f58,
+ 0x8446, 0x1907,
+ 0x8448, 0x219d,
+ 0x8449, 0x0f3f,
+ 0x844e, 0x0f72,
+ 0x8457, 0x0bb6,
+ 0x845b, 0x05c9,
+ 0x8461, 0x0de4,
+ 0x8462, 0x190d,
+ 0x8463, 0x0c79,
+ 0x8466, 0x0475,
+ 0x8469, 0x1906,
+ 0x846b, 0x1902,
+ 0x846c, 0x0af4,
+ 0x846d, 0x18fc,
+ 0x846e, 0x1904,
+ 0x846f, 0x1909,
+ 0x8471, 0x0ce2,
+ 0x8475, 0x046e,
+ 0x8477, 0x1901,
+ 0x8479, 0x190a,
+ 0x847a, 0x0dea,
+ 0x8482, 0x1905,
+ 0x8484, 0x1900,
+ 0x848b, 0x09bd,
+ 0x8490, 0x0939,
+ 0x8494, 0x08d8,
+ 0x8499, 0x0ee4,
+ 0x849c, 0x0db9,
+ 0x849f, 0x1910,
+ 0x84a1, 0x1919,
+ 0x84ad, 0x1903,
+ 0x84b2, 0x05d5,
+ 0x84b4, 0x219e,
+ 0x84b8, 0x09e0,
+ 0x84b9, 0x190e,
+ 0x84bb, 0x1913,
+ 0x84bc, 0x0af5,
+ 0x84bf, 0x190f,
+ 0x84c1, 0x1916,
+ 0x84c4, 0x0b9d,
+ 0x84c6, 0x1917,
+ 0x84c9, 0x0f40,
+ 0x84ca, 0x190c,
+ 0x84cb, 0x0596,
+ 0x84cd, 0x1912,
+ 0x84d0, 0x1915,
+ 0x84d1, 0x0eb8,
+ 0x84d6, 0x1918,
+ 0x84d9, 0x1911,
+ 0x84da, 0x1914,
+ 0x84dc, 0x20ab,
+ 0x84ec, 0x0e57,
+ 0x84ee, 0x0fc7,
+ 0x84f4, 0x191c,
+ 0x84fc, 0x1923,
+ 0x84ff, 0x191b,
+ 0x8500, 0x08ef,
+ 0x8506, 0x18fa,
+ 0x8511, 0x0e1e,
+ 0x8513, 0x0eae,
+ 0x8514, 0x1922,
+ 0x8515, 0x1921,
+ 0x8517, 0x191d,
+ 0x851a, 0x04d8,
+ 0x851f, 0x1920,
+ 0x8521, 0x191a,
+ 0x8523, 0x1e1a,
+ 0x8526, 0x0bf1,
+ 0x852c, 0x191f,
+ 0x852d, 0x04c2,
+ 0x8535, 0x0b02,
+ 0x853d, 0x0e13,
+ 0x853e, 0x1eb5,
+ 0x8540, 0x1924,
+ 0x8541, 0x1928,
+ 0x8543, 0x0d6d,
+ 0x8548, 0x1927,
+ 0x8549, 0x09be,
+ 0x854a, 0x08f5,
+ 0x854b, 0x192a,
+ 0x854e, 0x06b6,
+ 0x8553, 0x219f,
+ 0x8555, 0x192b,
+ 0x8557, 0x0deb,
+ 0x8558, 0x1926,
+ 0x8559, 0x21a0,
+ 0x855a, 0x18ff,
+ 0x8563, 0x1925,
+ 0x8568, 0x0ff5,
+ 0x8569, 0x0c7a,
+ 0x856a, 0x0de5,
+ 0x856b, 0x21a1,
+ 0x856d, 0x1932,
+ 0x8577, 0x1938,
+ 0x857e, 0x1939,
+ 0x8580, 0x192c,
+ 0x8584, 0x0d2c,
+ 0x8587, 0x1936,
+ 0x8588, 0x192e,
+ 0x858a, 0x1930,
+ 0x8590, 0x193a,
+ 0x8591, 0x192f,
+ 0x8594, 0x1933,
+ 0x8597, 0x0514,
+ 0x8599, 0x0cbd,
+ 0x859b, 0x1934,
+ 0x859c, 0x1937,
+ 0x85a4, 0x192d,
+ 0x85a6, 0x0aa8,
+ 0x85a8, 0x1931,
+ 0x85a9, 0x0875,
+ 0x85aa, 0x0a0b,
+ 0x85ab, 0x0706,
+ 0x85ac, 0x0f00,
+ 0x85ae, 0x0f05,
+ 0x85af, 0x097c,
+ 0x85b0, 0x21a3,
+ 0x85b9, 0x193e,
+ 0x85ba, 0x193c,
+ 0x85c1, 0x0ff4,
+ 0x85c9, 0x193b,
+ 0x85cd, 0x0f5f,
+ 0x85cf, 0x193d,
+ 0x85d0, 0x193f,
+ 0x85d5, 0x1940,
+ 0x85dc, 0x1943,
+ 0x85dd, 0x1941,
+ 0x85e4, 0x0c7b,
+ 0x85e5, 0x1942,
+ 0x85e9, 0x0d61,
+ 0x85ea, 0x1935,
+ 0x85f7, 0x097d,
+ 0x85f9, 0x1944,
+ 0x85fa, 0x1949,
+ 0x85fb, 0x0af6,
+ 0x85fe, 0x1948,
+ 0x8602, 0x1929,
+ 0x8606, 0x194a,
+ 0x8607, 0x0acb,
+ 0x860a, 0x1945,
+ 0x860b, 0x1947,
+ 0x8613, 0x1946,
+ 0x8616, 0x14d0,
+ 0x8617, 0x14c1,
+ 0x861a, 0x194c,
+ 0x8622, 0x194b,
+ 0x862d, 0x0f60,
+ 0x862f, 0x16b1,
+ 0x8630, 0x194d,
+ 0x863f, 0x194e,
+ 0x864d, 0x194f,
+ 0x864e, 0x078b,
+ 0x8650, 0x066e,
+ 0x8654, 0x1951,
+ 0x8655, 0x1094,
+ 0x865a, 0x068f,
+ 0x865c, 0x0f82,
+ 0x865e, 0x06eb,
+ 0x865f, 0x1952,
+ 0x8667, 0x1953,
+ 0x866b, 0x0bac,
+ 0x8671, 0x1954,
+ 0x8679, 0x0cd2,
+ 0x867b, 0x047e,
+ 0x868a, 0x0563,
+ 0x868b, 0x1959,
+ 0x8693, 0x1955,
+ 0x8695, 0x088b,
+ 0x86a3, 0x1956,
+ 0x86a4, 0x0cf8,
+ 0x86a9, 0x1957,
+ 0x86ab, 0x1962,
+ 0x86af, 0x195c,
+ 0x86b0, 0x195f,
+ 0x86b6, 0x195b,
+ 0x86c4, 0x195d,
+ 0x86c6, 0x195e,
+ 0x86c7, 0x0904,
+ 0x86c9, 0x1960,
+ 0x86cb, 0x0b7f,
+ 0x86cd, 0x072c,
+ 0x86ce, 0x05a0,
+ 0x86d4, 0x1963,
+ 0x86d9, 0x059d,
+ 0x86db, 0x1968,
+ 0x86de, 0x1964,
+ 0x86df, 0x1967,
+ 0x86e4, 0x0d4e,
+ 0x86e9, 0x1965,
+ 0x86ec, 0x1966,
+ 0x86ed, 0x0dba,
+ 0x86ee, 0x0d6e,
+ 0x86ef, 0x1969,
+ 0x86f8, 0x0b5d,
+ 0x86f9, 0x1973,
+ 0x86fb, 0x196f,
+ 0x86fe, 0x056b,
+ 0x8700, 0x196d,
+ 0x8702, 0x0e58,
+ 0x8703, 0x196e,
+ 0x8706, 0x196b,
+ 0x8708, 0x196c,
+ 0x8709, 0x1971,
+ 0x870a, 0x1974,
+ 0x870d, 0x1972,
+ 0x8711, 0x1970,
+ 0x8712, 0x196a,
+ 0x8718, 0x0b96,
+ 0x871a, 0x197b,
+ 0x871c, 0x0eb6,
+ 0x8725, 0x1979,
+ 0x8729, 0x197a,
+ 0x8734, 0x1975,
+ 0x8737, 0x1977,
+ 0x873b, 0x1978,
+ 0x873f, 0x1976,
+ 0x8749, 0x0a8a,
+ 0x874b, 0x0fdf,
+ 0x874c, 0x197f,
+ 0x874e, 0x1980,
+ 0x8753, 0x1986,
+ 0x8755, 0x09f0,
+ 0x8757, 0x1982,
+ 0x8759, 0x1985,
+ 0x875f, 0x197d,
+ 0x8760, 0x197c,
+ 0x8763, 0x1987,
+ 0x8766, 0x055c,
+ 0x8768, 0x1983,
+ 0x876a, 0x1988,
+ 0x876e, 0x1984,
+ 0x8774, 0x1981,
+ 0x8776, 0x0bcf,
+ 0x8778, 0x197e,
+ 0x877f, 0x0d1e,
+ 0x8782, 0x198c,
+ 0x878d, 0x0f25,
+ 0x879f, 0x198b,
+ 0x87a2, 0x198a,
+ 0x87ab, 0x1993,
+ 0x87af, 0x198d,
+ 0x87b3, 0x1995,
+ 0x87ba, 0x0f50,
+ 0x87bb, 0x1998,
+ 0x87bd, 0x198f,
+ 0x87c0, 0x1990,
+ 0x87c4, 0x1994,
+ 0x87c6, 0x1997,
+ 0x87c7, 0x1996,
+ 0x87cb, 0x198e,
+ 0x87d0, 0x1991,
+ 0x87d2, 0x19a2,
+ 0x87e0, 0x199b,
+ 0x87ec, 0x1e23,
+ 0x87ef, 0x1999,
+ 0x87f2, 0x199a,
+ 0x87f6, 0x199f,
+ 0x87f9, 0x0588,
+ 0x87fb, 0x065c,
+ 0x87fe, 0x199e,
+ 0x8805, 0x1989,
+ 0x8807, 0x21a6,
+ 0x880d, 0x199d,
+ 0x880e, 0x19a1,
+ 0x880f, 0x199c,
+ 0x8811, 0x19a3,
+ 0x8815, 0x19a5,
+ 0x8816, 0x19a4,
+ 0x881f, 0x1e85,
+ 0x8821, 0x19a7,
+ 0x8822, 0x19a6,
+ 0x8823, 0x1961,
+ 0x8827, 0x19ab,
+ 0x8831, 0x19a8,
+ 0x8836, 0x19a9,
+ 0x8839, 0x19aa,
+ 0x883b, 0x19ac,
+ 0x8840, 0x0742,
+ 0x8842, 0x19ae,
+ 0x8844, 0x19ad,
+ 0x8846, 0x093a,
+ 0x884c, 0x07e6,
+ 0x884d, 0x1524,
+ 0x8852, 0x19af,
+ 0x8853, 0x095b,
+ 0x8857, 0x0597,
+ 0x8859, 0x19b0,
+ 0x885b, 0x04f4,
+ 0x885d, 0x09bf,
+ 0x885e, 0x19b1,
+ 0x8861, 0x07e7,
+ 0x8862, 0x19b2,
+ 0x8863, 0x04a5,
+ 0x8868, 0x0daf,
+ 0x886b, 0x19b3,
+ 0x8870, 0x0a30,
+ 0x8872, 0x19ba,
+ 0x8875, 0x19b7,
+ 0x8877, 0x0bad,
+ 0x887d, 0x19b8,
+ 0x887e, 0x19b5,
+ 0x887f, 0x06d6,
+ 0x8881, 0x19b4,
+ 0x8882, 0x19bb,
+ 0x8888, 0x070c,
+ 0x888b, 0x0b3e,
+ 0x888d, 0x19c1,
+ 0x8892, 0x19bd,
+ 0x8896, 0x0b15,
+ 0x8897, 0x19bc,
+ 0x8899, 0x19bf,
+ 0x889e, 0x19b6,
+ 0x88a2, 0x19c0,
+ 0x88a4, 0x19c2,
+ 0x88ab, 0x0d83,
+ 0x88ae, 0x19be,
+ 0x88b0, 0x19c3,
+ 0x88b1, 0x19c5,
+ 0x88b4, 0x0787,
+ 0x88b5, 0x19b9,
+ 0x88b7, 0x0485,
+ 0x88bf, 0x19c4,
+ 0x88c1, 0x084b,
+ 0x88c2, 0x0fbe,
+ 0x88c3, 0x19c6,
+ 0x88c5, 0x0af7,
+ 0x88cf, 0x0f6a,
+ 0x88d4, 0x19c8,
+ 0x88d5, 0x0f1f,
+ 0x88d8, 0x19c9,
+ 0x88dc, 0x0e34,
+ 0x88dd, 0x19cb,
+ 0x88df, 0x0830,
+ 0x88e1, 0x0f6b,
+ 0x88e8, 0x19d0,
+ 0x88f2, 0x19d1,
+ 0x88f3, 0x09c0,
+ 0x88f4, 0x19cf,
+ 0x88f5, 0x21a7,
+ 0x88f8, 0x0f51,
+ 0x88f9, 0x19cc,
+ 0x88fc, 0x19ce,
+ 0x88fd, 0x0a61,
+ 0x88fe, 0x0a44,
+ 0x8902, 0x19cd,
+ 0x8904, 0x19d2,
+ 0x8907, 0x0df3,
+ 0x890a, 0x19d4,
+ 0x890c, 0x19d3,
+ 0x8910, 0x05ca,
+ 0x8912, 0x0e59,
+ 0x8913, 0x19d5,
+ 0x891c, 0x20a8,
+ 0x891d, 0x19e1,
+ 0x891e, 0x19d7,
+ 0x8925, 0x19d8,
+ 0x892a, 0x19d9,
+ 0x8936, 0x19de,
+ 0x8938, 0x19df,
+ 0x893b, 0x19dd,
+ 0x8941, 0x19db,
+ 0x8943, 0x19d6,
+ 0x8944, 0x19dc,
+ 0x894c, 0x19e0,
+ 0x894d, 0x1bd0,
+ 0x8956, 0x0528,
+ 0x895e, 0x19e3,
+ 0x895f, 0x06d7,
+ 0x8960, 0x19e2,
+ 0x8964, 0x19e5,
+ 0x8966, 0x19e4,
+ 0x896a, 0x19e7,
+ 0x896d, 0x19e6,
+ 0x896f, 0x19e8,
+ 0x8972, 0x093b,
+ 0x8974, 0x19e9,
+ 0x8977, 0x19ea,
+ 0x897e, 0x19eb,
+ 0x897f, 0x0a62,
+ 0x8981, 0x0f41,
+ 0x8983, 0x19ec,
+ 0x8986, 0x0df4,
+ 0x8987, 0x0cfc,
+ 0x8988, 0x19ed,
+ 0x898a, 0x19ee,
+ 0x898b, 0x075f,
+ 0x898f, 0x0646,
+ 0x8993, 0x19ef,
+ 0x8996, 0x08b9,
+ 0x8997, 0x0cf7,
+ 0x8998, 0x19f0,
+ 0x899a, 0x05ae,
+ 0x89a1, 0x19f1,
+ 0x89a6, 0x19f3,
+ 0x89a7, 0x0f61,
+ 0x89a9, 0x19f2,
+ 0x89aa, 0x0a0c,
+ 0x89ac, 0x19f4,
+ 0x89af, 0x19f5,
+ 0x89b2, 0x19f6,
+ 0x89b3, 0x060d,
+ 0x89ba, 0x19f7,
+ 0x89bd, 0x19f8,
+ 0x89bf, 0x19f9,
+ 0x89d2, 0x05af,
+ 0x89da, 0x19fb,
+ 0x89dc, 0x19fc,
+ 0x89e3, 0x0572,
+ 0x89e6, 0x09ee,
+ 0x89e7, 0x19fe,
+ 0x89f4, 0x19ff,
+ 0x89f8, 0x1a00,
+ 0x8a00, 0x0774,
+ 0x8a02, 0x0c17,
+ 0x8a03, 0x1a01,
+ 0x8a08, 0x072d,
+ 0x8a0a, 0x0a1c,
+ 0x8a0c, 0x1a04,
+ 0x8a0e, 0x0c7c,
+ 0x8a10, 0x1a03,
+ 0x8a12, 0x21a8,
+ 0x8a13, 0x0707,
+ 0x8a16, 0x1a02,
+ 0x8a17, 0x0b57,
+ 0x8a18, 0x0647,
+ 0x8a1b, 0x1a05,
+ 0x8a1d, 0x1a06,
+ 0x8a1f, 0x09c1,
+ 0x8a23, 0x0743,
+ 0x8a25, 0x1a07,
+ 0x8a2a, 0x0e5a,
+ 0x8a2d, 0x0a83,
+ 0x8a31, 0x0690,
+ 0x8a33, 0x0f01,
+ 0x8a34, 0x0acc,
+ 0x8a36, 0x1a08,
+ 0x8a37, 0x21a9,
+ 0x8a3a, 0x0a0d,
+ 0x8a3b, 0x0bae,
+ 0x8a3c, 0x09c2,
+ 0x8a41, 0x1a09,
+ 0x8a46, 0x1a0c,
+ 0x8a48, 0x1a0d,
+ 0x8a50, 0x082e,
+ 0x8a51, 0x0b22,
+ 0x8a52, 0x1a0b,
+ 0x8a54, 0x09c3,
+ 0x8a55, 0x0db0,
+ 0x8a5b, 0x1a0a,
+ 0x8a5e, 0x08ba,
+ 0x8a60, 0x04f5,
+ 0x8a62, 0x1a11,
+ 0x8a63, 0x072e,
+ 0x8a66, 0x08bc,
+ 0x8a69, 0x08bb,
+ 0x8a6b, 0x0ff3,
+ 0x8a6c, 0x1a10,
+ 0x8a6d, 0x1a0f,
+ 0x8a6e, 0x0aa9,
+ 0x8a70, 0x0667,
+ 0x8a71, 0x0fe9,
+ 0x8a72, 0x0598,
+ 0x8a73, 0x09c4,
+ 0x8a79, 0x21aa,
+ 0x8a7c, 0x1a0e,
+ 0x8a82, 0x1a13,
+ 0x8a84, 0x1a14,
+ 0x8a85, 0x1a12,
+ 0x8a87, 0x078c,
+ 0x8a89, 0x0f2a,
+ 0x8a8c, 0x08bd,
+ 0x8a8d, 0x0cdd,
+ 0x8a91, 0x1a17,
+ 0x8a93, 0x0a64,
+ 0x8a95, 0x0b80,
+ 0x8a98, 0x0f20,
+ 0x8a9a, 0x1a1a,
+ 0x8a9e, 0x07a0,
+ 0x8aa0, 0x0a63,
+ 0x8aa1, 0x1a16,
+ 0x8aa3, 0x1a1b,
+ 0x8aa4, 0x07a1,
+ 0x8aa5, 0x1a18,
+ 0x8aa7, 0x21ab,
+ 0x8aa8, 0x1a15,
+ 0x8aac, 0x0a86,
+ 0x8aad, 0x0ca1,
+ 0x8ab0, 0x0b6d,
+ 0x8ab2, 0x055d,
+ 0x8ab9, 0x0d84,
+ 0x8abc, 0x065d,
+ 0x8abe, 0x21ac,
+ 0x8abf, 0x0bd0,
+ 0x8ac2, 0x1a1e,
+ 0x8ac4, 0x1a1c,
+ 0x8ac7, 0x0b8a,
+ 0x8acb, 0x0a65,
+ 0x8acc, 0x060e,
+ 0x8acd, 0x1a1d,
+ 0x8acf, 0x0a21,
+ 0x8ad2, 0x0f92,
+ 0x8ad6, 0x0fe6,
+ 0x8ada, 0x1a1f,
+ 0x8adb, 0x1a2a,
+ 0x8adc, 0x0bd1,
+ 0x8ade, 0x1a29,
+ 0x8adf, 0x21ad,
+ 0x8ae0, 0x1a26,
+ 0x8ae1, 0x1a2e,
+ 0x8ae2, 0x1a27,
+ 0x8ae4, 0x1a23,
+ 0x8ae6, 0x0c18,
+ 0x8ae7, 0x1a22,
+ 0x8aeb, 0x1a20,
+ 0x8aed, 0x0f0b,
+ 0x8aee, 0x08be,
+ 0x8af1, 0x1a24,
+ 0x8af3, 0x1a21,
+ 0x8af6, 0x21af,
+ 0x8af7, 0x1a28,
+ 0x8af8, 0x097e,
+ 0x8afa, 0x0775,
+ 0x8afe, 0x0b5a,
+ 0x8b00, 0x0e73,
+ 0x8b01, 0x04fc,
+ 0x8b02, 0x04a6,
+ 0x8b04, 0x0c7d,
+ 0x8b07, 0x1a2c,
+ 0x8b0c, 0x1a2b,
+ 0x8b0e, 0x0cbe,
+ 0x8b10, 0x1a30,
+ 0x8b14, 0x1a25,
+ 0x8b16, 0x1a2f,
+ 0x8b17, 0x1a31,
+ 0x8b19, 0x0760,
+ 0x8b1a, 0x1a2d,
+ 0x8b1b, 0x07e8,
+ 0x8b1d, 0x0901,
+ 0x8b20, 0x1a32,
+ 0x8b21, 0x0f42,
+ 0x8b26, 0x1a35,
+ 0x8b28, 0x1a38,
+ 0x8b2b, 0x1a36,
+ 0x8b2c, 0x0da7,
+ 0x8b33, 0x1a33,
+ 0x8b39, 0x06d8,
+ 0x8b3e, 0x1a37,
+ 0x8b41, 0x1a39,
+ 0x8b49, 0x1a3d,
+ 0x8b4c, 0x1a3a,
+ 0x8b4e, 0x1a3c,
+ 0x8b4f, 0x1a3b,
+ 0x8b53, 0x21b0,
+ 0x8b56, 0x1a3e,
+ 0x8b58, 0x08dd,
+ 0x8b5a, 0x1a40,
+ 0x8b5b, 0x1a3f,
+ 0x8b5c, 0x0dda,
+ 0x8b5f, 0x1a42,
+ 0x8b66, 0x072f,
+ 0x8b6b, 0x1a41,
+ 0x8b6c, 0x1a43,
+ 0x8b6f, 0x1a44,
+ 0x8b70, 0x065e,
+ 0x8b71, 0x182e,
+ 0x8b72, 0x09e1,
+ 0x8b74, 0x1a45,
+ 0x8b77, 0x07a2,
+ 0x8b7d, 0x1a46,
+ 0x8b7f, 0x21b1,
+ 0x8b80, 0x1a47,
+ 0x8b83, 0x088c,
+ 0x8b8a, 0x13d3,
+ 0x8b8c, 0x1a48,
+ 0x8b8e, 0x1a49,
+ 0x8b90, 0x093c,
+ 0x8b92, 0x1a4a,
+ 0x8b96, 0x1a4c,
+ 0x8b99, 0x1a4d,
+ 0x8c37, 0x0b69,
+ 0x8c3a, 0x1a4f,
+ 0x8c3f, 0x1a51,
+ 0x8c41, 0x1a50,
+ 0x8c46, 0x0c7e,
+ 0x8c48, 0x1a52,
+ 0x8c4a, 0x0e5b,
+ 0x8c4c, 0x1a53,
+ 0x8c4e, 0x1a54,
+ 0x8c50, 0x1a55,
+ 0x8c55, 0x1a56,
+ 0x8c5a, 0x0cb2,
+ 0x8c61, 0x09c5,
+ 0x8c62, 0x1a57,
+ 0x8c6a, 0x07fd,
+ 0x8c6b, 0x1007,
+ 0x8c6c, 0x1a58,
+ 0x8c78, 0x1a59,
+ 0x8c79, 0x0db1,
+ 0x8c7a, 0x1a5a,
+ 0x8c7c, 0x1a62,
+ 0x8c82, 0x1a5b,
+ 0x8c85, 0x1a5d,
+ 0x8c89, 0x1a5c,
+ 0x8c8a, 0x1a5e,
+ 0x8c8c, 0x0e74,
+ 0x8c8d, 0x1a5f,
+ 0x8c94, 0x1a61,
+ 0x8c98, 0x1a63,
+ 0x8c9d, 0x058b,
+ 0x8c9e, 0x0c03,
+ 0x8ca0, 0x0ddb,
+ 0x8ca1, 0x0852,
+ 0x8ca2, 0x07e9,
+ 0x8ca7, 0x0dc1,
+ 0x8ca8, 0x055f,
+ 0x8ca9, 0x0d62,
+ 0x8caa, 0x1a66,
+ 0x8cab, 0x060f,
+ 0x8cac, 0x0a79,
+ 0x8cad, 0x1a65,
+ 0x8cae, 0x1a6a,
+ 0x8caf, 0x0bb7,
+ 0x8cb0, 0x0eef,
+ 0x8cb2, 0x1a68,
+ 0x8cb4, 0x0648,
+ 0x8cb6, 0x1a6b,
+ 0x8cb7, 0x0d19,
+ 0x8cb8, 0x0b3f,
+ 0x8cbb, 0x0d85,
+ 0x8cbc, 0x0c37,
+ 0x8cbd, 0x1a67,
+ 0x8cbf, 0x0e75,
+ 0x8cc0, 0x056c,
+ 0x8cc1, 0x1a6d,
+ 0x8cc2, 0x0fce,
+ 0x8cc3, 0x0bde,
+ 0x8cc4, 0x0feb,
+ 0x8cc7, 0x08bf,
+ 0x8cc8, 0x1a6c,
+ 0x8cca, 0x0b11,
+ 0x8ccd, 0x1a7d,
+ 0x8cce, 0x0aaa,
+ 0x8cd1, 0x0cd0,
+ 0x8cd3, 0x0dc2,
+ 0x8cda, 0x1a70,
+ 0x8cdb, 0x088d,
+ 0x8cdc, 0x08c0,
+ 0x8cde, 0x09c6,
+ 0x8ce0, 0x0d1b,
+ 0x8ce2, 0x0761,
+ 0x8ce3, 0x1a6f,
+ 0x8ce4, 0x1a6e,
+ 0x8ce6, 0x0ddc,
+ 0x8cea, 0x08ed,
+ 0x8ced, 0x0c4c,
+ 0x8cf0, 0x21b2,
+ 0x8cf4, 0x21b3,
+ 0x8cfa, 0x1a72,
+ 0x8cfc, 0x07ea,
+ 0x8cfd, 0x1a71,
+ 0x8d04, 0x1a74,
+ 0x8d07, 0x1a77,
+ 0x8d08, 0x0b03,
+ 0x8d0a, 0x1a76,
+ 0x8d0b, 0x0622,
+ 0x8d0d, 0x1a79,
+ 0x8d0f, 0x1a78,
+ 0x8d10, 0x1a7a,
+ 0x8d12, 0x21b4,
+ 0x8d13, 0x1a7c,
+ 0x8d14, 0x1a7e,
+ 0x8d16, 0x1a7f,
+ 0x8d64, 0x0a7a,
+ 0x8d66, 0x08fb,
+ 0x8d67, 0x1a80,
+ 0x8d6b, 0x05b0,
+ 0x8d6d, 0x1a81,
+ 0x8d70, 0x0af8,
+ 0x8d71, 0x1a82,
+ 0x8d73, 0x1a83,
+ 0x8d74, 0x0ddd,
+ 0x8d76, 0x21b5,
+ 0x8d77, 0x0649,
+ 0x8d81, 0x1a84,
+ 0x8d85, 0x0bd2,
+ 0x8d8a, 0x04fd,
+ 0x8d99, 0x1a85,
+ 0x8da3, 0x091d,
+ 0x8da8, 0x0a3c,
+ 0x8db3, 0x0b0d,
+ 0x8dba, 0x1a88,
+ 0x8dbe, 0x1a87,
+ 0x8dc2, 0x1a86,
+ 0x8dcb, 0x1a8e,
+ 0x8dcc, 0x1a8c,
+ 0x8dcf, 0x1a89,
+ 0x8dd6, 0x1a8b,
+ 0x8dda, 0x1a8a,
+ 0x8ddb, 0x1a8d,
+ 0x8ddd, 0x0691,
+ 0x8ddf, 0x1a91,
+ 0x8de1, 0x0a7b,
+ 0x8de3, 0x1a92,
+ 0x8de8, 0x078d,
+ 0x8dea, 0x1a8f,
+ 0x8def, 0x0fcf,
+ 0x8df3, 0x0bd3,
+ 0x8df5, 0x0aab,
+ 0x8dfc, 0x1a93,
+ 0x8dff, 0x1a96,
+ 0x8e08, 0x1a94,
+ 0x8e0a, 0x0f43,
+ 0x8e0f, 0x0c7f,
+ 0x8e10, 0x1a99,
+ 0x8e1d, 0x1a97,
+ 0x8e1f, 0x1a9a,
+ 0x8e2a, 0x1aa8,
+ 0x8e30, 0x1a9d,
+ 0x8e34, 0x1a9e,
+ 0x8e35, 0x1a9c,
+ 0x8e42, 0x1a9b,
+ 0x8e44, 0x0c19,
+ 0x8e47, 0x1aa0,
+ 0x8e48, 0x1aa4,
+ 0x8e49, 0x1aa1,
+ 0x8e4a, 0x1a9f,
+ 0x8e4c, 0x1aa2,
+ 0x8e50, 0x1aa3,
+ 0x8e55, 0x1aaa,
+ 0x8e59, 0x1aa5,
+ 0x8e5f, 0x0a7c,
+ 0x8e60, 0x1aa7,
+ 0x8e63, 0x1aa9,
+ 0x8e64, 0x1aa6,
+ 0x8e72, 0x1aac,
+ 0x8e74, 0x093d,
+ 0x8e76, 0x1aab,
+ 0x8e7c, 0x1aad,
+ 0x8e81, 0x1aae,
+ 0x8e84, 0x1ab1,
+ 0x8e85, 0x1ab0,
+ 0x8e87, 0x1aaf,
+ 0x8e8a, 0x1ab3,
+ 0x8e8b, 0x1ab2,
+ 0x8e8d, 0x0f02,
+ 0x8e91, 0x1ab5,
+ 0x8e93, 0x1ab4,
+ 0x8e94, 0x1ab6,
+ 0x8e99, 0x1ab7,
+ 0x8ea1, 0x1ab9,
+ 0x8eaa, 0x1ab8,
+ 0x8eab, 0x0a0e,
+ 0x8eac, 0x1aba,
+ 0x8eaf, 0x06e5,
+ 0x8eb0, 0x1abb,
+ 0x8eb1, 0x1abd,
+ 0x8ebe, 0x1abe,
+ 0x8ec0, 0x1def,
+ 0x8ec5, 0x1abf,
+ 0x8ec6, 0x1abc,
+ 0x8ec8, 0x1ac0,
+ 0x8eca, 0x0902,
+ 0x8ecb, 0x1ac1,
+ 0x8ecc, 0x064a,
+ 0x8ecd, 0x0709,
+ 0x8ecf, 0x21b7,
+ 0x8ed2, 0x0762,
+ 0x8edb, 0x1ac2,
+ 0x8edf, 0x0cc8,
+ 0x8ee2, 0x0c38,
+ 0x8ee3, 0x1ac3,
+ 0x8eeb, 0x1ac6,
+ 0x8ef8, 0x08e0,
+ 0x8efb, 0x1ac5,
+ 0x8efc, 0x1ac4,
+ 0x8efd, 0x0730,
+ 0x8efe, 0x1ac7,
+ 0x8f03, 0x05b1,
+ 0x8f05, 0x1ac9,
+ 0x8f09, 0x084c,
+ 0x8f0a, 0x1ac8,
+ 0x8f0c, 0x1ad1,
+ 0x8f12, 0x1acb,
+ 0x8f13, 0x1acd,
+ 0x8f14, 0x0e35,
+ 0x8f15, 0x1aca,
+ 0x8f19, 0x1acc,
+ 0x8f1b, 0x1ad0,
+ 0x8f1c, 0x1ace,
+ 0x8f1d, 0x064b,
+ 0x8f1f, 0x1acf,
+ 0x8f26, 0x1ad2,
+ 0x8f29, 0x0d10,
+ 0x8f2a, 0x0fa0,
+ 0x8f2f, 0x093e,
+ 0x8f33, 0x1ad3,
+ 0x8f38, 0x0f0c,
+ 0x8f39, 0x1ad5,
+ 0x8f3b, 0x1ad4,
+ 0x8f3e, 0x1ad8,
+ 0x8f3f, 0x0f2b,
+ 0x8f42, 0x1ad7,
+ 0x8f44, 0x05cb,
+ 0x8f45, 0x1ad6,
+ 0x8f46, 0x1adb,
+ 0x8f49, 0x1ada,
+ 0x8f4c, 0x1ad9,
+ 0x8f4d, 0x0c2c,
+ 0x8f4e, 0x1adc,
+ 0x8f57, 0x1add,
+ 0x8f5c, 0x1ade,
+ 0x8f5f, 0x07fe,
+ 0x8f61, 0x06fb,
+ 0x8f62, 0x1adf,
+ 0x8f9b, 0x0a0f,
+ 0x8f9c, 0x1ae2,
+ 0x8f9e, 0x08d9,
+ 0x8f9f, 0x1ae3,
+ 0x8fa3, 0x1ae4,
+ 0x8fa7, 0x10b6,
+ 0x8fa8, 0x10b5,
+ 0x8fad, 0x1ae5,
+ 0x8fae, 0x17ff,
+ 0x8faf, 0x1ae6,
+ 0x8fb0, 0x0b62,
+ 0x8fb1, 0x09f1,
+ 0x8fb2, 0x0cf6,
+ 0x8fb7, 0x1ae7,
+ 0x8fba, 0x0e25,
+ 0x8fbb, 0x0bf0,
+ 0x8fbc, 0x0810,
+ 0x8fbf, 0x0b67,
+ 0x8fc2, 0x04cc,
+ 0x8fc4, 0x0ea6,
+ 0x8fc5, 0x0a1d,
+ 0x8fce, 0x0734,
+ 0x8fd1, 0x06d9,
+ 0x8fd4, 0x0e26,
+ 0x8fda, 0x1ae8,
+ 0x8fe2, 0x1aea,
+ 0x8fe5, 0x1ae9,
+ 0x8fe6, 0x0560,
+ 0x8fe9, 0x0cce,
+ 0x8fea, 0x1aeb,
+ 0x8feb, 0x0d2d,
+ 0x8fed, 0x0c2d,
+ 0x8fef, 0x1aec,
+ 0x8ff0, 0x095c,
+ 0x8ff4, 0x1aee,
+ 0x8ff7, 0x0ece,
+ 0x8ff8, 0x1afd,
+ 0x8ff9, 0x1af0,
+ 0x8ffd, 0x0be5,
+ 0x9000, 0x0b40,
+ 0x9001, 0x0af9,
+ 0x9003, 0x0c80,
+ 0x9005, 0x1aef,
+ 0x9006, 0x066f,
+ 0x900b, 0x1af8,
+ 0x900d, 0x1af5,
+ 0x900e, 0x1b02,
+ 0x900f, 0x0c81,
+ 0x9010, 0x0b9e,
+ 0x9011, 0x1af2,
+ 0x9013, 0x0c1a,
+ 0x9014, 0x0c4d,
+ 0x9015, 0x1af3,
+ 0x9016, 0x1af7,
+ 0x9017, 0x0a26,
+ 0x9019, 0x0d1d,
+ 0x901a, 0x0be8,
+ 0x901d, 0x0a66,
+ 0x901e, 0x1af6,
+ 0x901f, 0x0b0e,
+ 0x9020, 0x0b04,
+ 0x9021, 0x1af4,
+ 0x9022, 0x046d,
+ 0x9023, 0x0fc8,
+ 0x9027, 0x1af9,
+ 0x902e, 0x0b41,
+ 0x9031, 0x093f,
+ 0x9032, 0x0a10,
+ 0x9035, 0x1afb,
+ 0x9036, 0x1afa,
+ 0x9038, 0x04b3,
+ 0x9039, 0x1afc,
+ 0x903c, 0x0da1,
+ 0x903e, 0x1b04,
+ 0x9041, 0x0cb3,
+ 0x9042, 0x0a31,
+ 0x9045, 0x0b97,
+ 0x9047, 0x06f0,
+ 0x9049, 0x1b03,
+ 0x904a, 0x0f21,
+ 0x904b, 0x04e1,
+ 0x904d, 0x0e27,
+ 0x904e, 0x0561,
+ 0x904f, 0x1afe,
+ 0x9053, 0x0c93,
+ 0x9054, 0x0b61,
+ 0x9055, 0x04a7,
+ 0x9056, 0x1b05,
+ 0x9058, 0x1b06,
+ 0x9059, 0x1d34,
+ 0x905c, 0x0b1d,
+ 0x905e, 0x1b07,
+ 0x9060, 0x0515,
+ 0x9061, 0x0ace,
+ 0x9063, 0x0763,
+ 0x9065, 0x0f44,
+ 0x9067, 0x21ba,
+ 0x9068, 0x1b08,
+ 0x9069, 0x0c26,
+ 0x906d, 0x0afa,
+ 0x906e, 0x0903,
+ 0x906f, 0x1b09,
+ 0x9072, 0x1b0c,
+ 0x9075, 0x096f,
+ 0x9076, 0x1b0a,
+ 0x9077, 0x0aad,
+ 0x9078, 0x0aac,
+ 0x907a, 0x04a8,
+ 0x907c, 0x0f93,
+ 0x907d, 0x1b0e,
+ 0x907f, 0x0d86,
+ 0x9080, 0x1b10,
+ 0x9081, 0x1b0f,
+ 0x9082, 0x1b0d,
+ 0x9083, 0x1737,
+ 0x9084, 0x0610,
+ 0x9087, 0x1aed,
+ 0x9089, 0x1b12,
+ 0x908a, 0x1b11,
+ 0x908f, 0x1b13,
+ 0x9091, 0x0f22,
+ 0x90a3, 0x0cb9,
+ 0x90a6, 0x0e5c,
+ 0x90a8, 0x1b14,
+ 0x90aa, 0x0905,
+ 0x90af, 0x1b15,
+ 0x90b1, 0x1b16,
+ 0x90b5, 0x1b17,
+ 0x90b8, 0x0c1b,
+ 0x90c1, 0x04ae,
+ 0x90ca, 0x07eb,
+ 0x90ce, 0x0fe0,
+ 0x90db, 0x1b1b,
+ 0x90de, 0x21bb,
+ 0x90e1, 0x070a,
+ 0x90e2, 0x1b18,
+ 0x90e4, 0x1b19,
+ 0x90e8, 0x0de6,
+ 0x90ed, 0x05b2,
+ 0x90f5, 0x0f23,
+ 0x90f7, 0x06b7,
+ 0x90fd, 0x0c4e,
+ 0x9102, 0x1b1c,
+ 0x9112, 0x1b1d,
+ 0x9115, 0x21bd,
+ 0x9119, 0x1b1e,
+ 0x9127, 0x21be,
+ 0x912d, 0x0c1c,
+ 0x9130, 0x1b20,
+ 0x9132, 0x1b1f,
+ 0x9149, 0x0cab,
+ 0x914a, 0x1b21,
+ 0x914b, 0x0940,
+ 0x914c, 0x090c,
+ 0x914d, 0x0d11,
+ 0x914e, 0x0baf,
+ 0x9152, 0x091e,
+ 0x9154, 0x0a32,
+ 0x9156, 0x1b22,
+ 0x9158, 0x1b23,
+ 0x9162, 0x0a23,
+ 0x9163, 0x1b24,
+ 0x9165, 0x1b25,
+ 0x9169, 0x1b26,
+ 0x916a, 0x0f59,
+ 0x916c, 0x0941,
+ 0x9172, 0x1b28,
+ 0x9173, 0x1b27,
+ 0x9175, 0x07ec,
+ 0x9177, 0x0805,
+ 0x9178, 0x088e,
+ 0x9182, 0x1b2b,
+ 0x9187, 0x0970,
+ 0x9189, 0x1b2a,
+ 0x918b, 0x1b29,
+ 0x918d, 0x0b49,
+ 0x9190, 0x07a3,
+ 0x9192, 0x0a67,
+ 0x9197, 0x0d44,
+ 0x919c, 0x0943,
+ 0x91a2, 0x1b2c,
+ 0x91a4, 0x09c7,
+ 0x91aa, 0x1b2f,
+ 0x91ab, 0x1b2d,
+ 0x91ac, 0x1e1b,
+ 0x91af, 0x1b2e,
+ 0x91b1, 0x1e61,
+ 0x91b4, 0x1b31,
+ 0x91b5, 0x1b30,
+ 0x91b8, 0x09e2,
+ 0x91ba, 0x1b32,
+ 0x91c0, 0x1b33,
+ 0x91c6, 0x0d64,
+ 0x91c7, 0x0843,
+ 0x91c8, 0x090d,
+ 0x91c9, 0x1b35,
+ 0x91cb, 0x1b36,
+ 0x91cc, 0x0f6c,
+ 0x91cd, 0x094f,
+ 0x91ce, 0x0efa,
+ 0x91cf, 0x0f94,
+ 0x91d0, 0x1b37,
+ 0x91d1, 0x06da,
+ 0x91d6, 0x1b38,
+ 0x91d7, 0x21c0,
+ 0x91d8, 0x0c1d,
+ 0x91da, 0x21bf,
+ 0x91db, 0x1b3b,
+ 0x91dc, 0x05d6,
+ 0x91dd, 0x0a11,
+ 0x91de, 0x21c1,
+ 0x91df, 0x1b39,
+ 0x91e1, 0x1b3a,
+ 0x91e3, 0x0bfc,
+ 0x91e4, 0x21c4,
+ 0x91e6, 0x0e83,
+ 0x91e7, 0x06f4,
+ 0x91ed, 0x21c2,
+ 0x91f5, 0x1b3d,
+ 0x91fc, 0x1b3c,
+ 0x91ff, 0x1b40,
+ 0x9206, 0x21c6,
+ 0x920a, 0x21c8,
+ 0x920d, 0x0cb7,
+ 0x920e, 0x05a1,
+ 0x9210, 0x21c7,
+ 0x9211, 0x1b44,
+ 0x9214, 0x1b41,
+ 0x9215, 0x1b43,
+ 0x921e, 0x1b3f,
+ 0x9229, 0x1b8a,
+ 0x922c, 0x1b42,
+ 0x9234, 0x0fb3,
+ 0x9237, 0x078e,
+ 0x9239, 0x21cf,
+ 0x923a, 0x21c9,
+ 0x923c, 0x21cb,
+ 0x923f, 0x1b4c,
+ 0x9240, 0x21ca,
+ 0x9244, 0x0c2e,
+ 0x9245, 0x1b47,
+ 0x9248, 0x1b4a,
+ 0x9249, 0x1b48,
+ 0x924b, 0x1b4d,
+ 0x924e, 0x21cc,
+ 0x9250, 0x1b4e,
+ 0x9251, 0x21ce,
+ 0x9257, 0x1b46,
+ 0x9259, 0x21cd,
+ 0x925a, 0x1b53,
+ 0x925b, 0x0516,
+ 0x925e, 0x1b45,
+ 0x9262, 0x0d41,
+ 0x9264, 0x1b49,
+ 0x9266, 0x09c8,
+ 0x9267, 0x21d0,
+ 0x9271, 0x07ed,
+ 0x9277, 0x21d2,
+ 0x927e, 0x0e76,
+ 0x9280, 0x06dc,
+ 0x9283, 0x0950,
+ 0x9285, 0x0c94,
+ 0x9288, 0x20aa,
+ 0x9291, 0x0aaf,
+ 0x9293, 0x1b51,
+ 0x9295, 0x1b4b,
+ 0x9296, 0x1b50,
+ 0x9298, 0x0ecf,
+ 0x929a, 0x0bd4,
+ 0x929b, 0x1b52,
+ 0x929c, 0x1b4f,
+ 0x92a7, 0x21d1,
+ 0x92ad, 0x0aae,
+ 0x92b7, 0x1b56,
+ 0x92b9, 0x1b55,
+ 0x92cf, 0x1b54,
+ 0x92d0, 0x21d7,
+ 0x92d2, 0x0e5d,
+ 0x92d3, 0x21db,
+ 0x92d5, 0x21d9,
+ 0x92d7, 0x21d5,
+ 0x92d9, 0x21d6,
+ 0x92e0, 0x21da,
+ 0x92e4, 0x0985,
+ 0x92e7, 0x21d4,
+ 0x92e9, 0x1b57,
+ 0x92ea, 0x0e2f,
+ 0x92ed, 0x04f6,
+ 0x92f2, 0x0db8,
+ 0x92f3, 0x0bb0,
+ 0x92f8, 0x0692,
+ 0x92f9, 0x20b0,
+ 0x92fa, 0x1b59,
+ 0x92fb, 0x21de,
+ 0x92fc, 0x07ef,
+ 0x92ff, 0x21e1,
+ 0x9302, 0x21e3,
+ 0x9306, 0x087a,
+ 0x930f, 0x1b58,
+ 0x9310, 0x0a33,
+ 0x9318, 0x0a34,
+ 0x9319, 0x1b5c,
+ 0x931a, 0x1b5e,
+ 0x931d, 0x21e2,
+ 0x931e, 0x21e0,
+ 0x9320, 0x09e3,
+ 0x9321, 0x21dd,
+ 0x9322, 0x1b5d,
+ 0x9323, 0x1b5f,
+ 0x9325, 0x21dc,
+ 0x9326, 0x06cb,
+ 0x9328, 0x0db7,
+ 0x932b, 0x090e,
+ 0x932c, 0x0fc9,
+ 0x932e, 0x1b5b,
+ 0x932f, 0x0868,
+ 0x9332, 0x0fe5,
+ 0x9335, 0x1b61,
+ 0x933a, 0x1b60,
+ 0x933b, 0x1b62,
+ 0x9344, 0x1b5a,
+ 0x9348, 0x20a9,
+ 0x934b, 0x0cc1,
+ 0x934d, 0x0c4f,
+ 0x9354, 0x0bf3,
+ 0x9356, 0x1b67,
+ 0x9357, 0x21e5,
+ 0x935b, 0x0b81,
+ 0x935c, 0x1b63,
+ 0x9360, 0x1b64,
+ 0x936c, 0x0703,
+ 0x936e, 0x1b66,
+ 0x9370, 0x21e4,
+ 0x9375, 0x0764,
+ 0x937c, 0x1b65,
+ 0x937e, 0x09c9,
+ 0x938c, 0x05d7,
+ 0x9394, 0x1b6b,
+ 0x9396, 0x082f,
+ 0x9397, 0x0afb,
+ 0x939a, 0x0be6,
+ 0x93a4, 0x21e6,
+ 0x93a7, 0x0599,
+ 0x93ac, 0x1b69,
+ 0x93ae, 0x0bdf,
+ 0x93b0, 0x1b68,
+ 0x93b9, 0x1b6c,
+ 0x93c3, 0x1b72,
+ 0x93c6, 0x21e7,
+ 0x93c8, 0x1b75,
+ 0x93d0, 0x1b74,
+ 0x93d1, 0x0c27,
+ 0x93d6, 0x1b6d,
+ 0x93d8, 0x1b71,
+ 0x93dd, 0x1b73,
+ 0x93de, 0x21e8,
+ 0x93e1, 0x06b8,
+ 0x93e4, 0x1b76,
+ 0x93e5, 0x1b70,
+ 0x93e8, 0x1b6f,
+ 0x93f8, 0x21e9,
+ 0x9403, 0x1b7a,
+ 0x9407, 0x1b7b,
+ 0x9410, 0x1b7c,
+ 0x9413, 0x1b79,
+ 0x9414, 0x1b78,
+ 0x9418, 0x09ca,
+ 0x9419, 0x0c82,
+ 0x941a, 0x1b77,
+ 0x9421, 0x1b80,
+ 0x942b, 0x1b7e,
+ 0x9431, 0x21ea,
+ 0x9435, 0x1b7f,
+ 0x9436, 0x1b7d,
+ 0x9438, 0x0b58,
+ 0x943a, 0x1b81,
+ 0x9441, 0x1b82,
+ 0x9444, 0x1b84,
+ 0x9445, 0x21eb,
+ 0x9448, 0x21ec,
+ 0x9451, 0x0611,
+ 0x9452, 0x1b83,
+ 0x9453, 0x0f06,
+ 0x945a, 0x1b8f,
+ 0x945b, 0x1b85,
+ 0x945e, 0x1b88,
+ 0x9460, 0x1b86,
+ 0x9462, 0x1b87,
+ 0x946a, 0x1b89,
+ 0x9470, 0x1b8b,
+ 0x9475, 0x1b8c,
+ 0x9477, 0x1b8d,
+ 0x947c, 0x1b90,
+ 0x947d, 0x1b8e,
+ 0x947e, 0x1b91,
+ 0x947f, 0x1b93,
+ 0x9481, 0x1b92,
+ 0x9577, 0x0bd5,
+ 0x9580, 0x0ef3,
+ 0x9582, 0x1b94,
+ 0x9583, 0x0ab0,
+ 0x9587, 0x1b95,
+ 0x9589, 0x0e14,
+ 0x958a, 0x1b96,
+ 0x958b, 0x0589,
+ 0x958f, 0x04de,
+ 0x9591, 0x0613,
+ 0x9592, 0x21ed,
+ 0x9593, 0x0612,
+ 0x9594, 0x1b97,
+ 0x9596, 0x1b98,
+ 0x9598, 0x1b99,
+ 0x95a0, 0x1b9b,
+ 0x95a2, 0x0614,
+ 0x95a3, 0x05b3,
+ 0x95a4, 0x07f0,
+ 0x95a5, 0x0d4a,
+ 0x95a7, 0x1b9d,
+ 0x95a8, 0x1b9c,
+ 0x95ad, 0x1b9e,
+ 0x95b2, 0x04fe,
+ 0x95b9, 0x1ba1,
+ 0x95bb, 0x1ba0,
+ 0x95bc, 0x1b9f,
+ 0x95be, 0x1ba2,
+ 0x95c3, 0x1ba5,
+ 0x95c7, 0x048b,
+ 0x95ca, 0x1ba3,
+ 0x95cc, 0x1ba7,
+ 0x95cd, 0x1ba6,
+ 0x95d4, 0x1ba9,
+ 0x95d5, 0x1ba8,
+ 0x95d6, 0x1baa,
+ 0x95d8, 0x0c86,
+ 0x95dc, 0x1bab,
+ 0x95e1, 0x1bac,
+ 0x95e2, 0x1bae,
+ 0x95e5, 0x1bad,
+ 0x961c, 0x0dde,
+ 0x9621, 0x1baf,
+ 0x9628, 0x1bb0,
+ 0x962a, 0x0855,
+ 0x962e, 0x1bb1,
+ 0x9632, 0x0e77,
+ 0x963b, 0x0acd,
+ 0x963f, 0x0468,
+ 0x9640, 0x0b2b,
+ 0x9642, 0x1bb3,
+ 0x9644, 0x0ddf,
+ 0x964b, 0x1bb6,
+ 0x964c, 0x1bb4,
+ 0x964d, 0x07f1,
+ 0x964f, 0x1bb5,
+ 0x9650, 0x0776,
+ 0x965b, 0x0e15,
+ 0x965c, 0x1bb8,
+ 0x965d, 0x1bba,
+ 0x965e, 0x1bb9,
+ 0x965f, 0x1bbb,
+ 0x9662, 0x04c3,
+ 0x9663, 0x0a1e,
+ 0x9664, 0x0986,
+ 0x9665, 0x0615,
+ 0x9666, 0x1bbc,
+ 0x966a, 0x0d1c,
+ 0x966c, 0x1bbe,
+ 0x9670, 0x04c4,
+ 0x9672, 0x1bbd,
+ 0x9673, 0x0be0,
+ 0x9675, 0x0f95,
+ 0x9676, 0x0c83,
+ 0x9677, 0x1bb7,
+ 0x9678, 0x0f6e,
+ 0x967a, 0x0765,
+ 0x967d, 0x0f45,
+ 0x9685, 0x06f1,
+ 0x9686, 0x0f7c,
+ 0x9688, 0x06fe,
+ 0x968a, 0x0b42,
+ 0x968b, 0x186c,
+ 0x968d, 0x1bbf,
+ 0x968e, 0x058a,
+ 0x968f, 0x0a35,
+ 0x9694, 0x05b4,
+ 0x9695, 0x1bc1,
+ 0x9697, 0x1bc2,
+ 0x9698, 0x1bc0,
+ 0x9699, 0x073a,
+ 0x969b, 0x084d,
+ 0x969c, 0x09cb,
+ 0x969d, 0x21f0,
+ 0x96a0, 0x04c5,
+ 0x96a3, 0x0fa1,
+ 0x96a7, 0x1bc4,
+ 0x96a8, 0x1b0b,
+ 0x96aa, 0x1bc3,
+ 0x96af, 0x21f1,
+ 0x96b0, 0x1bc7,
+ 0x96b1, 0x1bc5,
+ 0x96b4, 0x1bc8,
+ 0x96b6, 0x1bc9,
+ 0x96b7, 0x0fb4,
+ 0x96b8, 0x1bca,
+ 0x96bb, 0x0a6d,
+ 0x96bc, 0x0d4f,
+ 0x96c0, 0x0a43,
+ 0x96c1, 0x0623,
+ 0x96c4, 0x0f24,
+ 0x96c5, 0x056d,
+ 0x96c6, 0x0942,
+ 0x96c7, 0x078f,
+ 0x96c9, 0x1bce,
+ 0x96cb, 0x1bcd,
+ 0x96cc, 0x08c1,
+ 0x96cd, 0x1bcf,
+ 0x96ce, 0x1bcc,
+ 0x96d1, 0x0876,
+ 0x96d5, 0x1bd3,
+ 0x96d6, 0x1992,
+ 0x96d9, 0x10eb,
+ 0x96db, 0x0a3d,
+ 0x96dc, 0x1bd1,
+ 0x96e2, 0x0f6d,
+ 0x96e3, 0x0cc9,
+ 0x96e8, 0x04cd,
+ 0x96ea, 0x0a87,
+ 0x96eb, 0x08e2,
+ 0x96f0, 0x0e07,
+ 0x96f2, 0x04e2,
+ 0x96f6, 0x0fb5,
+ 0x96f7, 0x0f55,
+ 0x96f9, 0x1bd4,
+ 0x96fb, 0x0c3f,
+ 0x9700, 0x0927,
+ 0x9704, 0x1bd5,
+ 0x9706, 0x1bd6,
+ 0x9707, 0x0a12,
+ 0x9708, 0x1bd7,
+ 0x970a, 0x0fb6,
+ 0x970d, 0x1bd2,
+ 0x970e, 0x1bd9,
+ 0x970f, 0x1bdb,
+ 0x9711, 0x1bda,
+ 0x9713, 0x1bd8,
+ 0x9716, 0x1bdc,
+ 0x9719, 0x1bdd,
+ 0x971c, 0x0afc,
+ 0x971e, 0x0562,
+ 0x9724, 0x1bde,
+ 0x9727, 0x0ec4,
+ 0x972a, 0x1bdf,
+ 0x9730, 0x1be0,
+ 0x9732, 0x0fd0,
+ 0x9733, 0x21f2,
+ 0x9738, 0x1414,
+ 0x9739, 0x1be1,
+ 0x973b, 0x21f3,
+ 0x973d, 0x1be2,
+ 0x9742, 0x1be7,
+ 0x9743, 0x21f4,
+ 0x9744, 0x1be4,
+ 0x9746, 0x1be5,
+ 0x9748, 0x1be6,
+ 0x9749, 0x1be8,
+ 0x974d, 0x21f5,
+ 0x974f, 0x21f6,
+ 0x9751, 0x21f7,
+ 0x9752, 0x0a68,
+ 0x9755, 0x21f8,
+ 0x9756, 0x0f03,
+ 0x9759, 0x0a69,
+ 0x975c, 0x1be9,
+ 0x975e, 0x0d87,
+ 0x9760, 0x1bea,
+ 0x9761, 0x1d06,
+ 0x9762, 0x0ed8,
+ 0x9764, 0x1beb,
+ 0x9766, 0x1bec,
+ 0x9768, 0x1bed,
+ 0x9769, 0x05b5,
+ 0x976b, 0x1bef,
+ 0x976d, 0x0a1f,
+ 0x9771, 0x1bf0,
+ 0x9774, 0x06fa,
+ 0x9779, 0x1bf1,
+ 0x977a, 0x1bf5,
+ 0x977c, 0x1bf3,
+ 0x9781, 0x1bf4,
+ 0x9784, 0x05d1,
+ 0x9785, 0x1bf2,
+ 0x9786, 0x1bf6,
+ 0x978b, 0x1bf7,
+ 0x978d, 0x048c,
+ 0x978f, 0x1bf8,
+ 0x9798, 0x09cc,
+ 0x979c, 0x1bfa,
+ 0x97a0, 0x0661,
+ 0x97a3, 0x1bfd,
+ 0x97a6, 0x1bfc,
+ 0x97a8, 0x1bfb,
+ 0x97ab, 0x1a34,
+ 0x97ad, 0x0e2c,
+ 0x97b3, 0x1bfe,
+ 0x97c3, 0x1c00,
+ 0x97c6, 0x1c01,
+ 0x97c8, 0x1c02,
+ 0x97cb, 0x1c03,
+ 0x97d3, 0x0616,
+ 0x97dc, 0x1c04,
+ 0x97ed, 0x1c05,
+ 0x97ee, 0x0cd9,
+ 0x97f2, 0x1c07,
+ 0x97f3, 0x053b,
+ 0x97f5, 0x1c0a,
+ 0x97f6, 0x1c09,
+ 0x97fb, 0x04c6,
+ 0x97ff, 0x06b9,
+ 0x9801, 0x0e17,
+ 0x9802, 0x0bd6,
+ 0x9803, 0x0812,
+ 0x9805, 0x07f2,
+ 0x9806, 0x0971,
+ 0x9808, 0x0a22,
+ 0x980c, 0x1c0c,
+ 0x980f, 0x1c0b,
+ 0x9810, 0x0f2c,
+ 0x9811, 0x0624,
+ 0x9812, 0x0d66,
+ 0x9813, 0x0cb4,
+ 0x9817, 0x0a42,
+ 0x9818, 0x0f96,
+ 0x981a, 0x0731,
+ 0x9821, 0x1c0f,
+ 0x9824, 0x1c0e,
+ 0x982c, 0x0e79,
+ 0x982d, 0x0c84,
+ 0x9830, 0x1e73,
+ 0x9834, 0x04f2,
+ 0x9837, 0x1c10,
+ 0x9838, 0x1c0d,
+ 0x983b, 0x0dc3,
+ 0x983c, 0x0f54,
+ 0x983d, 0x1c11,
+ 0x9846, 0x1c12,
+ 0x984b, 0x1c14,
+ 0x984c, 0x0b4a,
+ 0x984d, 0x05b9,
+ 0x984f, 0x1c13,
+ 0x9854, 0x0625,
+ 0x9855, 0x0766,
+ 0x9857, 0x21f9,
+ 0x9858, 0x0626,
+ 0x985a, 0x1e48,
+ 0x985b, 0x0c39,
+ 0x985e, 0x0fa8,
+ 0x9865, 0x21fa,
+ 0x9867, 0x0790,
+ 0x986b, 0x1c15,
+ 0x986f, 0x1c16,
+ 0x9873, 0x1c1a,
+ 0x9874, 0x1c19,
+ 0x98a8, 0x0de9,
+ 0x98aa, 0x1c1b,
+ 0x98af, 0x1c1c,
+ 0x98b1, 0x1c1d,
+ 0x98b6, 0x1c1e,
+ 0x98c3, 0x1c20,
+ 0x98c4, 0x1c1f,
+ 0x98c6, 0x1c21,
+ 0x98db, 0x0d88,
+ 0x98dc, 0x1839,
+ 0x98df, 0x09ef,
+ 0x98e2, 0x064c,
+ 0x98e9, 0x1c22,
+ 0x98eb, 0x1c23,
+ 0x98ed, 0x10c1,
+ 0x98ee, 0x14da,
+ 0x98ef, 0x0d67,
+ 0x98f2, 0x04bf,
+ 0x98f4, 0x047f,
+ 0x98fc, 0x08c2,
+ 0x98fd, 0x0e5e,
+ 0x98fe, 0x09e6,
+ 0x9903, 0x1c24,
+ 0x9905, 0x0eeb,
+ 0x9909, 0x1c25,
+ 0x990a, 0x0f46,
+ 0x990c, 0x04e4,
+ 0x9910, 0x088f,
+ 0x9912, 0x1c26,
+ 0x9913, 0x056e,
+ 0x9914, 0x1c27,
+ 0x9918, 0x1c28,
+ 0x991d, 0x1c2a,
+ 0x9920, 0x1c2d,
+ 0x9921, 0x1c29,
+ 0x9924, 0x1c2c,
+ 0x9927, 0x21fd,
+ 0x9928, 0x0617,
+ 0x992c, 0x1c2e,
+ 0x992e, 0x1c2f,
+ 0x993d, 0x1c30,
+ 0x9942, 0x1c32,
+ 0x9945, 0x1c34,
+ 0x9949, 0x1c33,
+ 0x994b, 0x1c36,
+ 0x994c, 0x1c39,
+ 0x9950, 0x1c35,
+ 0x9951, 0x1c37,
+ 0x9955, 0x1c3a,
+ 0x9957, 0x06ba,
+ 0x9996, 0x091f,
+ 0x9997, 0x1c3b,
+ 0x9999, 0x07f3,
+ 0x999e, 0x21ff,
+ 0x99a5, 0x1c3d,
+ 0x99a8, 0x059c,
+ 0x99ac, 0x0d05,
+ 0x99ad, 0x1c3e,
+ 0x99b3, 0x0b98,
+ 0x99b4, 0x0cc3,
+ 0x99bc, 0x1c40,
+ 0x99c1, 0x0d33,
+ 0x99c4, 0x0b2c,
+ 0x99c5, 0x04fa,
+ 0x99c6, 0x06e6,
+ 0x99c8, 0x06e7,
+ 0x99d0, 0x0bb1,
+ 0x99d1, 0x1c45,
+ 0x99d2, 0x06e8,
+ 0x99d5, 0x056f,
+ 0x99d8, 0x1c44,
+ 0x99db, 0x1c42,
+ 0x99dd, 0x1c43,
+ 0x99df, 0x1c41,
+ 0x99e2, 0x1c4f,
+ 0x99ed, 0x1c46,
+ 0x99f1, 0x1c48,
+ 0x99f8, 0x1c4b,
+ 0x99fb, 0x1c4a,
+ 0x99ff, 0x0963,
+ 0x9a01, 0x1c4c,
+ 0x9a05, 0x1c4e,
+ 0x9a0e, 0x064d,
+ 0x9a0f, 0x1c4d,
+ 0x9a12, 0x0afd,
+ 0x9a13, 0x0767,
+ 0x9a19, 0x1c50,
+ 0x9a28, 0x0b2d,
+ 0x9a2b, 0x1c51,
+ 0x9a30, 0x0c85,
+ 0x9a37, 0x1c52,
+ 0x9a3e, 0x1c57,
+ 0x9a40, 0x1c55,
+ 0x9a42, 0x1c54,
+ 0x9a43, 0x1c56,
+ 0x9a45, 0x1c53,
+ 0x9a4d, 0x1c59,
+ 0x9a4e, 0x2200,
+ 0x9a52, 0x1e2f,
+ 0x9a55, 0x1c58,
+ 0x9a57, 0x1c5b,
+ 0x9a5a, 0x06bb,
+ 0x9a5b, 0x1c5a,
+ 0x9a5f, 0x1c5c,
+ 0x9a62, 0x1c5d,
+ 0x9a64, 0x1c5f,
+ 0x9a65, 0x1c5e,
+ 0x9a69, 0x1c60,
+ 0x9a6a, 0x1c62,
+ 0x9a6b, 0x1c61,
+ 0x9aa8, 0x080e,
+ 0x9aad, 0x1c63,
+ 0x9ab0, 0x1c64,
+ 0x9ab8, 0x059a,
+ 0x9abc, 0x1c65,
+ 0x9ac0, 0x1c66,
+ 0x9ac4, 0x0a37,
+ 0x9acf, 0x1c67,
+ 0x9ad1, 0x1c68,
+ 0x9ad3, 0x1c69,
+ 0x9ad8, 0x07f4,
+ 0x9ad9, 0x2201,
+ 0x9adc, 0x2202,
+ 0x9ade, 0x1c6b,
+ 0x9ae2, 0x1c6d,
+ 0x9ae6, 0x1c6f,
+ 0x9aea, 0x0d45,
+ 0x9aeb, 0x1c71,
+ 0x9aed, 0x0d98,
+ 0x9aee, 0x1c72,
+ 0x9aef, 0x1c70,
+ 0x9af1, 0x1c74,
+ 0x9af4, 0x1c73,
+ 0x9af7, 0x1c75,
+ 0x9afb, 0x1c76,
+ 0x9b06, 0x1c77,
+ 0x9b18, 0x1c78,
+ 0x9b1a, 0x1c79,
+ 0x9b1f, 0x1c7a,
+ 0x9b22, 0x1c7b,
+ 0x9b25, 0x1c7d,
+ 0x9b27, 0x1c7e,
+ 0x9b2e, 0x1c82,
+ 0x9b31, 0x14d4,
+ 0x9b32, 0x1c84,
+ 0x9b3b, 0x17a9,
+ 0x9b3c, 0x064e,
+ 0x9b41, 0x057f,
+ 0x9b42, 0x0822,
+ 0x9b43, 0x1c86,
+ 0x9b44, 0x1c85,
+ 0x9b45, 0x0eb1,
+ 0x9b4d, 0x1c88,
+ 0x9b4f, 0x1c87,
+ 0x9b51, 0x1c8a,
+ 0x9b54, 0x0e90,
+ 0x9b58, 0x1c8b,
+ 0x9b5a, 0x0695,
+ 0x9b6f, 0x0fcb,
+ 0x9b72, 0x2204,
+ 0x9b74, 0x1c8c,
+ 0x9b75, 0x2203,
+ 0x9b83, 0x1c8e,
+ 0x9b8e, 0x0482,
+ 0x9b8f, 0x2205,
+ 0x9b91, 0x1c8f,
+ 0x9b92, 0x0dfb,
+ 0x9b93, 0x1c8d,
+ 0x9b96, 0x1c90,
+ 0x9b9f, 0x1c92,
+ 0x9ba8, 0x1c94,
+ 0x9baa, 0x0e9c,
+ 0x9bab, 0x087b,
+ 0x9bad, 0x086a,
+ 0x9bae, 0x0ab1,
+ 0x9bb1, 0x2206,
+ 0x9bb4, 0x1c95,
+ 0x9bb9, 0x1c98,
+ 0x9bbb, 0x2207,
+ 0x9bc0, 0x1c96,
+ 0x9bc6, 0x1c99,
+ 0x9bc9, 0x07a5,
+ 0x9bca, 0x1c97,
+ 0x9bcf, 0x1c9a,
+ 0x9bd1, 0x1c9b,
+ 0x9bd4, 0x1ca0,
+ 0x9bd6, 0x0878,
+ 0x9bdb, 0x0b44,
+ 0x9be1, 0x1ca1,
+ 0x9be2, 0x1c9e,
+ 0x9be3, 0x1c9d,
+ 0x9be4, 0x1c9f,
+ 0x9be8, 0x0735,
+ 0x9bf0, 0x1ca5,
+ 0x9bf1, 0x1ca4,
+ 0x9bf2, 0x1ca3,
+ 0x9bf5, 0x0477,
+ 0x9c00, 0x2208,
+ 0x9c04, 0x1caf,
+ 0x9c06, 0x1cab,
+ 0x9c08, 0x1cac,
+ 0x9c09, 0x1ca8,
+ 0x9c0a, 0x1cae,
+ 0x9c0c, 0x1caa,
+ 0x9c0d, 0x05c0,
+ 0x9c10, 0x0ff2,
+ 0x9c12, 0x1cad,
+ 0x9c13, 0x1ca9,
+ 0x9c14, 0x1ca7,
+ 0x9c15, 0x1ca6,
+ 0x9c1b, 0x1cb1,
+ 0x9c21, 0x1cb4,
+ 0x9c24, 0x1cb3,
+ 0x9c25, 0x1cb2,
+ 0x9c2d, 0x0dbb,
+ 0x9c2e, 0x1cb0,
+ 0x9c2f, 0x04b7,
+ 0x9c30, 0x1cb5,
+ 0x9c32, 0x1cb7,
+ 0x9c39, 0x05cd,
+ 0x9c3a, 0x1ca2,
+ 0x9c3b, 0x04d9,
+ 0x9c3e, 0x1cb9,
+ 0x9c46, 0x1cb8,
+ 0x9c47, 0x1cb6,
+ 0x9c48, 0x0b6b,
+ 0x9c52, 0x0e9e,
+ 0x9c57, 0x0fa2,
+ 0x9c5a, 0x1cba,
+ 0x9c60, 0x1cbb,
+ 0x9c67, 0x1cbc,
+ 0x9c76, 0x1cbd,
+ 0x9c78, 0x1cbe,
+ 0x9ce5, 0x0bd7,
+ 0x9ce7, 0x1cbf,
+ 0x9ce9, 0x0d4b,
+ 0x9ceb, 0x1cc4,
+ 0x9cec, 0x1cc0,
+ 0x9cf0, 0x1cc1,
+ 0x9cf3, 0x0e5f,
+ 0x9cf4, 0x0ed0,
+ 0x9cf6, 0x0ca8,
+ 0x9d03, 0x1cc5,
+ 0x9d06, 0x1cc6,
+ 0x9d07, 0x0c96,
+ 0x9d08, 0x1cc3,
+ 0x9d09, 0x1cc2,
+ 0x9d0e, 0x052a,
+ 0x9d12, 0x1cce,
+ 0x9d15, 0x1ccd,
+ 0x9d1b, 0x0517,
+ 0x9d1f, 0x1ccb,
+ 0x9d23, 0x1cca,
+ 0x9d26, 0x1cc8,
+ 0x9d28, 0x05d9,
+ 0x9d2a, 0x1cc7,
+ 0x9d2b, 0x08de,
+ 0x9d2c, 0x0529,
+ 0x9d3b, 0x07f5,
+ 0x9d3e, 0x1cd1,
+ 0x9d3f, 0x1cd0,
+ 0x9d41, 0x1ccf,
+ 0x9d44, 0x1ccc,
+ 0x9d46, 0x1cd2,
+ 0x9d48, 0x1cd3,
+ 0x9d50, 0x1cd8,
+ 0x9d51, 0x1cd7,
+ 0x9d59, 0x1cd9,
+ 0x9d5c, 0x04cf,
+ 0x9d5d, 0x1cd4,
+ 0x9d60, 0x0806,
+ 0x9d61, 0x0ec5,
+ 0x9d64, 0x1cd6,
+ 0x9d6b, 0x220a,
+ 0x9d6c, 0x0e60,
+ 0x9d6f, 0x1cde,
+ 0x9d70, 0x2209,
+ 0x9d72, 0x1cda,
+ 0x9d7a, 0x1cdf,
+ 0x9d87, 0x1cdc,
+ 0x9d89, 0x1cdb,
+ 0x9d8f, 0x0732,
+ 0x9d9a, 0x1ce0,
+ 0x9da4, 0x1ce1,
+ 0x9da9, 0x1ce2,
+ 0x9dab, 0x1cdd,
+ 0x9daf, 0x1cc9,
+ 0x9db2, 0x1ce3,
+ 0x9db4, 0x0bfd,
+ 0x9db8, 0x1ce7,
+ 0x9dba, 0x1ce8,
+ 0x9dbb, 0x1ce6,
+ 0x9dc1, 0x1ce5,
+ 0x9dc2, 0x1ceb,
+ 0x9dc4, 0x1ce4,
+ 0x9dc6, 0x1ce9,
+ 0x9dcf, 0x1cea,
+ 0x9dd3, 0x1ced,
+ 0x9dd7, 0x1dde,
+ 0x9dd9, 0x1cec,
+ 0x9de6, 0x1cef,
+ 0x9ded, 0x1cf0,
+ 0x9def, 0x1cf1,
+ 0x9df2, 0x0fef,
+ 0x9df8, 0x1cee,
+ 0x9df9, 0x0b4b,
+ 0x9dfa, 0x085d,
+ 0x9dfd, 0x1cf2,
+ 0x9e19, 0x220c,
+ 0x9e1a, 0x1cf3,
+ 0x9e1e, 0x1cf5,
+ 0x9e75, 0x1cf6,
+ 0x9e78, 0x0768,
+ 0x9e79, 0x1cf7,
+ 0x9e7c, 0x1dfd,
+ 0x9e7d, 0x1cf8,
+ 0x9e7f, 0x08db,
+ 0x9e81, 0x1cf9,
+ 0x9e88, 0x1cfa,
+ 0x9e8b, 0x1cfb,
+ 0x9e91, 0x1cff,
+ 0x9e92, 0x1cfd,
+ 0x9e93, 0x0fe2,
+ 0x9e95, 0x1cfe,
+ 0x9e97, 0x0fb7,
+ 0x9e9d, 0x1d00,
+ 0x9e9f, 0x0fa3,
+ 0x9ea5, 0x1d01,
+ 0x9ea6, 0x0d34,
+ 0x9ea9, 0x1d02,
+ 0x9eaa, 0x1d04,
+ 0x9ead, 0x1d05,
+ 0x9eb4, 0x1e02,
+ 0x9eb5, 0x1e75,
+ 0x9eb8, 0x1d03,
+ 0x9eb9, 0x07ff,
+ 0x9eba, 0x0ed9,
+ 0x9ebb, 0x0e91,
+ 0x9ebc, 0x1284,
+ 0x9ebe, 0x14ff,
+ 0x9ebf, 0x0ea9,
+ 0x9ec4, 0x052b,
+ 0x9ecc, 0x1d07,
+ 0x9ecd, 0x066a,
+ 0x9ece, 0x1d08,
+ 0x9ed1, 0x220d,
+ 0x9ed2, 0x0807,
+ 0x9ed4, 0x1d0b,
+ 0x9ed8, 0x160d,
+ 0x9ed9, 0x0ee7,
+ 0x9edb, 0x0b43,
+ 0x9edc, 0x1d0c,
+ 0x9edd, 0x1d0e,
+ 0x9ede, 0x1d0d,
+ 0x9ee0, 0x1d0f,
+ 0x9ee5, 0x1d10,
+ 0x9ee8, 0x1d11,
+ 0x9eef, 0x1d12,
+ 0x9ef4, 0x1d13,
+ 0x9ef6, 0x1d14,
+ 0x9ef9, 0x1d16,
+ 0x9efb, 0x1d17,
+ 0x9f07, 0x1d1a,
+ 0x9f0e, 0x0c1e,
+ 0x9f13, 0x0791,
+ 0x9f15, 0x1d1d,
+ 0x9f20, 0x0acf,
+ 0x9f21, 0x1d1e,
+ 0x9f2c, 0x1d1f,
+ 0x9f3b, 0x0d93,
+ 0x9f3e, 0x1d20,
+ 0x9f4a, 0x1d21,
+ 0x9f4b, 0x170a,
+ 0x9f4e, 0x1a7b,
+ 0x9f4f, 0x1c06,
+ 0x9f52, 0x1d22,
+ 0x9f54, 0x1d23,
+ 0x9f5f, 0x1d25,
+ 0x9f62, 0x0fb8,
+ 0x9f63, 0x1d24,
+ 0x9f66, 0x1d28,
+ 0x9f6a, 0x1d2b,
+ 0x9f6c, 0x1d2a,
+ 0x9f72, 0x1d2d,
+ 0x9f76, 0x1d2e,
+ 0x9f77, 0x1d2c,
+ 0x9f8d, 0x0f7e,
+ 0x9f95, 0x1d2f,
+ 0x9f9c, 0x1d30,
+ 0x9f9d, 0x1727,
+ 0x9fa0, 0x1d31,
+ 0xf929, 0x2129,
+ 0xf9dc, 0x21ee,
+ 0xfa0e, 0x20da,
+ 0xfa0f, 0x20e5,
+ 0xfa11, 0x20fb,
+ 0xfa12, 0x2121,
+ 0xfa13, 0x2131,
+ 0xfa14, 0x2133,
+ 0xfa15, 0x215e,
+ 0xfa16, 0x2164,
+ 0xfa17, 0x217b,
+ 0xfa18, 0x2183,
+ 0xfa1b, 0x2187,
+ 0xfa1c, 0x218b,
+ 0xfa1d, 0x218e,
+ 0xfa1e, 0x2197,
+ 0xfa1f, 0x21a2,
+ 0xfa20, 0x21a4,
+ 0xfa22, 0x21ae,
+ 0xfa23, 0x21b6,
+ 0xfa24, 0x21b8,
+ 0xfa26, 0x21bc,
+ 0xfa27, 0x21d8,
+ 0xfa28, 0x21df,
+ 0xfa29, 0x21ef,
+ 0xfa2a, 0x21fb,
+ 0xfa2c, 0x21fe,
+ 0xfa2d, 0x220b,
+ 0xfb01, 0x0070,
+ 0xfe30, 0x1eda,
+ 0xfe31, 0x1ed4,
+ 0xfe33, 0x1ed2,
+ 0xfe35, 0x1edb,
+ 0xfe37, 0x1ee1,
+ 0xfe39, 0x1edd,
+ 0xfe3b, 0x1eeb,
+ 0xfe3d, 0x1ee5,
+ 0xfe3f, 0x1ee3,
+ 0xfe41, 0x1ee7,
+ 0xff01, 0x0282,
+ 0xff02, 0x1f47,
+ 0xff03, 0x02cc,
+ 0xff04, 0x02c8,
+ 0xff05, 0x02cb,
+ 0xff06, 0x02cd,
+ 0xff07, 0x1f46,
+ 0xff08, 0x02a2,
+ 0xff0a, 0x02ce,
+ 0xff0b, 0x02b4,
+ 0xff0c, 0x027c,
+ 0xff0d, 0x0296,
+ 0xff0e, 0x027d,
+ 0xff0f, 0x0297,
+ 0xff10, 0x030c,
+ 0xff1a, 0x027f,
+ 0xff1c, 0x02bb,
+ 0xff1d, 0x02b9,
+ 0xff1e, 0x02bc,
+ 0xff1f, 0x0281,
+ 0xff20, 0x02cf,
+ 0xff21, 0x0316,
+ 0xff3b, 0x02a6,
+ 0xff3c, 0x0298,
+ 0xff3d, 0x02a7,
+ 0xff3e, 0x0288,
+ 0xff3f, 0x028a,
+ 0xff40, 0x0286,
+ 0xff41, 0x0330,
+ 0xff5b, 0x02a8,
+ 0xff5c, 0x029b,
+ 0xff5d, 0x02a9,
+ 0xff5e, 0x0299,
+ 0xff61, 0x0147,
+ 0xffe0, 0x02c9,
+ 0xffe2, 0x02ef,
+ 0xffe3, 0x0289,
+ 0xffe4, 0x1f45,
+ 0xffe5, 0x02c7,
+ 0xffe8, 0x0143,
+ 0x00b0, 0x204d,
+ 0x2015, 0x1ed4,
+ 0x2016, 0x1ed7,
+ 0x2018, 0x2059,
+ 0x201c, 0x2057,
+ 0x2025, 0x1eda,
+ 0x2026, 0x1ed9,
+ 0x2032, 0x2051,
+ 0x2033, 0x205b,
+ 0x2190, 0x02e2,
+ 0x2191, 0x02e0,
+ 0x2192, 0x02e3,
+ 0x2193, 0x02e1,
+ 0x2225, 0x1ed7,
+ 0x223c, 0x1ed6,
+ 0x22ef, 0x1ed9,
+ 0x2500, 0x1d39,
+ 0x2502, 0x1d37,
+ 0x2504, 0x1d3d,
+ 0x2506, 0x1d3b,
+ 0x2508, 0x1d41,
+ 0x250a, 0x1d3f,
+ 0x250c, 0x1d47,
+ 0x250d, 0x1d49,
+ 0x250e, 0x1d48,
+ 0x250f, 0x1d4a,
+ 0x2510, 0x1d4f,
+ 0x2511, 0x1d51,
+ 0x2512, 0x1d50,
+ 0x2513, 0x1d52,
+ 0x2514, 0x1d43,
+ 0x2515, 0x1d45,
+ 0x2516, 0x1d44,
+ 0x2517, 0x1d46,
+ 0x2518, 0x1d4b,
+ 0x2519, 0x1d4d,
+ 0x251a, 0x1d4c,
+ 0x251b, 0x1d4e,
+ 0x251c, 0x1d63,
+ 0x251d, 0x1d67,
+ 0x251e, 0x1d65,
+ 0x251f, 0x1d64,
+ 0x2520, 0x1d66,
+ 0x2521, 0x1d69,
+ 0x2522, 0x1d68,
+ 0x2523, 0x1d6a,
+ 0x2525, 0x1d6f,
+ 0x2526, 0x1d6d,
+ 0x2527, 0x1d6c,
+ 0x2528, 0x1d6e,
+ 0x2529, 0x1d71,
+ 0x252a, 0x1d70,
+ 0x252b, 0x1d72,
+ 0x252c, 0x1d5b,
+ 0x252d, 0x1d5d,
+ 0x2530, 0x1d5c,
+ 0x2531, 0x1d60,
+ 0x2534, 0x1d53,
+ 0x2535, 0x1d55,
+ 0x2538, 0x1d54,
+ 0x2539, 0x1d58,
+ 0x253d, 0x1d77,
+ 0x2540, 0x1d75,
+ 0x2541, 0x1d74,
+ 0x2542, 0x1d76,
+ 0x2543, 0x1d7b,
+ 0x2544, 0x1d7d,
+ 0x2545, 0x1d7a,
+ 0x2546, 0x1d7c,
+ 0x2547, 0x1d81,
+ 0x2548, 0x1d80,
+ 0x2549, 0x1d7e,
+ 0x3001, 0x1ecf,
+ 0x3008, 0x1ee3,
+ 0x3013, 0x204e,
+ 0x3014, 0x1edd,
+ 0x301c, 0x1ed6,
+ 0x301d, 0x1f14,
+ 0x301f, 0x1f15,
+ 0x3041, 0x1eee,
+ 0x3043, 0x1eef,
+ 0x3045, 0x1ef0,
+ 0x3047, 0x1ef1,
+ 0x3049, 0x1ef2,
+ 0x3063, 0x1ef3,
+ 0x3083, 0x1ef4,
+ 0x3085, 0x1ef5,
+ 0x3087, 0x1ef6,
+ 0x308e, 0x1ef7,
+ 0x309b, 0x2050,
+ 0x309c, 0x204f,
+ 0x30a1, 0x1ef8,
+ 0x30a3, 0x1ef9,
+ 0x30a5, 0x1efa,
+ 0x30a7, 0x1efb,
+ 0x30a9, 0x1efc,
+ 0x30c3, 0x1efd,
+ 0x30e3, 0x1efe,
+ 0x30e5, 0x1eff,
+ 0x30e7, 0x1f00,
+ 0x30ee, 0x1f01,
+ 0x30f5, 0x1f02,
+ 0x30fc, 0x1ed3,
+ 0x3300, 0x209e,
+ 0x3303, 0x2092,
+ 0x3305, 0x208d,
+ 0x330d, 0x1f0e,
+ 0x3314, 0x1f05,
+ 0x3315, 0x2094,
+ 0x3316, 0x208a,
+ 0x3318, 0x2093,
+ 0x331e, 0x20a1,
+ 0x3322, 0x2089,
+ 0x3323, 0x209c,
+ 0x3326, 0x1f0f,
+ 0x3327, 0x1f09,
+ 0x332a, 0x20a4,
+ 0x332b, 0x1f11,
+ 0x3331, 0x20a6,
+ 0x3333, 0x208e,
+ 0x3336, 0x1f0b,
+ 0x3339, 0x2097,
+ 0x333b, 0x209d,
+ 0x3342, 0x209b,
+ 0x3347, 0x20a5,
+ 0x3349, 0x1f04,
+ 0x334a, 0x1f12,
+ 0x334d, 0x1f07,
+ 0x334e, 0x2091,
+ 0x3351, 0x1f0c,
+ 0x3357, 0x2098,
+ 0x337f, 0x2084,
+ 0xff08, 0x1edb,
+ 0xff0c, 0x204c,
+ 0xff0d, 0x1ed5,
+ 0xff0e, 0x2052,
+ 0xff1d, 0x1eed,
+ 0xff3b, 0x1edf,
+ 0xff3d, 0x1ee0,
+ 0xff3f, 0x1ed2,
+ 0xff5b, 0x1ee1,
+ 0xff5c, 0x1ed8,
+ 0xff5d, 0x1ee2,
+ 0xff5e, 0x1ed6,
+ 0xffe3, 0x1ed1,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 japan12UniJISUCS2VEnc16 = {
+ 1,
+ { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ japan12UniJISUCS2VMap2, 7108
+};
+
+static Gushort japan12VMap2[294] = {
+ 0x0000, 0x0000,
+ 0x2121, 0x0279,
+ 0x2221, 0x02d7,
+ 0x223a, 0x02e5,
+ 0x224a, 0x02ed,
+ 0x225c, 0x02f4,
+ 0x2272, 0x0303,
+ 0x227e, 0x030b,
+ 0x2330, 0x030c,
+ 0x2341, 0x0316,
+ 0x2361, 0x0330,
+ 0x2421, 0x034a,
+ 0x2521, 0x039d,
+ 0x2621, 0x03f3,
+ 0x2641, 0x040b,
+ 0x2721, 0x0423,
+ 0x2751, 0x0444,
+ 0x2821, 0x1d37,
+ 0x2822, 0x1d39,
+ 0x2823, 0x1d43,
+ 0x2824, 0x1d47,
+ 0x2825, 0x1d4f,
+ 0x2826, 0x1d4b,
+ 0x2827, 0x1d53,
+ 0x2828, 0x1d63,
+ 0x2829, 0x1d5b,
+ 0x282a, 0x1d6b,
+ 0x282b, 0x1d73,
+ 0x282c, 0x1d38,
+ 0x282d, 0x1d3a,
+ 0x282e, 0x1d46,
+ 0x282f, 0x1d4a,
+ 0x2830, 0x1d52,
+ 0x2831, 0x1d4e,
+ 0x2832, 0x1d5a,
+ 0x2833, 0x1d6a,
+ 0x2834, 0x1d62,
+ 0x2835, 0x1d72,
+ 0x2836, 0x1d82,
+ 0x2837, 0x1d57,
+ 0x2838, 0x1d66,
+ 0x2839, 0x1d5f,
+ 0x283a, 0x1d6e,
+ 0x283b, 0x1d76,
+ 0x283c, 0x1d54,
+ 0x283d, 0x1d67,
+ 0x283e, 0x1d5c,
+ 0x283f, 0x1d6f,
+ 0x2840, 0x1d79,
+ 0x3021, 0x0465,
+ 0x3121, 0x04c3,
+ 0x3221, 0x0521,
+ 0x3321, 0x057f,
+ 0x3421, 0x05dd,
+ 0x3521, 0x063b,
+ 0x3621, 0x0699,
+ 0x3721, 0x06f7,
+ 0x3821, 0x0755,
+ 0x3921, 0x07b3,
+ 0x3a21, 0x0811,
+ 0x3b21, 0x086f,
+ 0x3c21, 0x08cd,
+ 0x3d21, 0x092b,
+ 0x3e21, 0x0989,
+ 0x3f21, 0x09e7,
+ 0x4021, 0x0a45,
+ 0x4121, 0x0aa3,
+ 0x4221, 0x0b01,
+ 0x4321, 0x0b5f,
+ 0x4421, 0x0bbd,
+ 0x4521, 0x0c1b,
+ 0x4621, 0x0c79,
+ 0x4721, 0x0cd7,
+ 0x4821, 0x0d35,
+ 0x4921, 0x0d93,
+ 0x4a21, 0x0df1,
+ 0x4b21, 0x0e4f,
+ 0x4c21, 0x0ead,
+ 0x4d21, 0x0f0b,
+ 0x4e21, 0x0f69,
+ 0x4f21, 0x0fc7,
+ 0x5021, 0x0ffa,
+ 0x5121, 0x1058,
+ 0x5221, 0x10b6,
+ 0x5321, 0x1114,
+ 0x5421, 0x1172,
+ 0x5521, 0x11d0,
+ 0x5621, 0x122e,
+ 0x5721, 0x128c,
+ 0x5821, 0x12ea,
+ 0x5921, 0x1348,
+ 0x5a21, 0x13a6,
+ 0x5b21, 0x1404,
+ 0x5c21, 0x1462,
+ 0x5d21, 0x14c0,
+ 0x5e21, 0x151e,
+ 0x5f21, 0x157c,
+ 0x6021, 0x15da,
+ 0x6121, 0x1638,
+ 0x6221, 0x1696,
+ 0x6321, 0x16f4,
+ 0x6421, 0x1752,
+ 0x6521, 0x17b0,
+ 0x6621, 0x180e,
+ 0x6721, 0x186c,
+ 0x6821, 0x18ca,
+ 0x6921, 0x1928,
+ 0x6a21, 0x1986,
+ 0x6b21, 0x19e4,
+ 0x6c21, 0x1a42,
+ 0x6d21, 0x1aa0,
+ 0x6e21, 0x1afe,
+ 0x6f21, 0x1b5c,
+ 0x7021, 0x1bba,
+ 0x7121, 0x1c18,
+ 0x7221, 0x1c76,
+ 0x7321, 0x1cd4,
+ 0x7421, 0x1d32,
+ 0x7425, 0x205c,
+ 0x2122, 0x1ecf,
+ 0x2131, 0x1ed1,
+ 0x213c, 0x1ed3,
+ 0x2141, 0x1ed6,
+ 0x214a, 0x1edb,
+ 0x2161, 0x1eed,
+ 0x2421, 0x1eee,
+ 0x2423, 0x1eef,
+ 0x2425, 0x1ef0,
+ 0x2427, 0x1ef1,
+ 0x2429, 0x1ef2,
+ 0x2443, 0x1ef3,
+ 0x2463, 0x1ef4,
+ 0x2465, 0x1ef5,
+ 0x2467, 0x1ef6,
+ 0x246e, 0x1ef7,
+ 0x2521, 0x1ef8,
+ 0x2523, 0x1ef9,
+ 0x2525, 0x1efa,
+ 0x2527, 0x1efb,
+ 0x2529, 0x1efc,
+ 0x2543, 0x1efd,
+ 0x2563, 0x1efe,
+ 0x2565, 0x1eff,
+ 0x2567, 0x1f00,
+ 0x256e, 0x1f01,
+ 0x2575, 0x1f02,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 japan12VEnc16 = {
+ 1,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ japan12VMap2, 147
+};
+
+static Gushort japan12WPSymbolMap2[4] = {
+ 0x0000, 0x0000,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 japan12WPSymbolEnc16 = {
+ 0,
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0x0000, 0x1f78, 0x1f7a, 0x1fff, 0x2004, 0x1f7d, 0x1f7e, 0x1f7f,
+ 0x1f80, 0x1f81, 0x1f82, 0x1f83, 0x1f84, 0x1f85, 0x1f86, 0x1f87,
+ 0x1f88, 0x1f89, 0x1f8a, 0x1f8b, 0x1f8c, 0x1f8d, 0x1f8e, 0x1f8f,
+ 0x1f90, 0x1f9c, 0x1f9d, 0x1f9e, 0x1f9f, 0x1fa0, 0x1fa1, 0x1fa2,
+ 0x1fa3, 0x1fa4, 0x1fa5, 0x1ffa, 0x1f54, 0x1f55, 0x1ffb, 0x1f56,
+ 0x1f57, 0x1ffc, 0x1f65, 0x1f58, 0x1f59, 0x1f5a, 0x1ffd, 0x1ffe,
+ 0x2000, 0x2001, 0x1edb, 0x1edc, 0x1ed6, 0x2002, 0x1f63, 0x1f5b,
+ 0x1f5c, 0x1f5d, 0x2003, 0x1fb0, 0x1fb1, 0x1fb2, 0x1fb3, 0x1fb4,
+ 0x1fb5, 0x1fb6, 0x1fb7, 0x1fb8, 0x1fb9, 0x1fba, 0x1fbb, 0x1fbc,
+ 0x1fbd, 0x1fbe, 0x1fbf, 0x1fc0, 0x1fc1, 0x1fc2, 0x1fc3, 0x1fc4,
+ 0x1fc5, 0x1fc6, 0x1fc7, 0x1fc8, 0x1fc9, 0x2005, 0x2006, 0x2007,
+ 0x2008, 0x2009, 0x200a, 0x200b, 0x200c, 0x200d, 0x1fd7, 0x0000,
+ 0x0000, 0x200e, 0x200f, 0x2010, 0x2011, 0x2012, 0x2013, 0x2014,
+ 0x2015, 0x2016, 0x2017, 0x2018, 0x2019, 0x201a, 0x201b, 0x201c,
+ 0x201d, 0x201e, 0x1f79, 0x201f, 0x2020, 0x2021, 0x2022, 0x2023,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ japan12WPSymbolMap2, 2
+};
+
+static Gushort japan12AdobeJapan12VMap2[74] = {
+ 0x0000, 0x0000,
+ 0x0000, 0x0000,
+ 0x0100, 0x0100,
+ 0x0200, 0x0200,
+ 0x0300, 0x0300,
+ 0x0400, 0x0400,
+ 0x0500, 0x0500,
+ 0x0600, 0x0600,
+ 0x0700, 0x0700,
+ 0x0800, 0x0800,
+ 0x0900, 0x0900,
+ 0x0a00, 0x0a00,
+ 0x0b00, 0x0b00,
+ 0x0c00, 0x0c00,
+ 0x0d00, 0x0d00,
+ 0x0e00, 0x0e00,
+ 0x0f00, 0x0f00,
+ 0x1000, 0x1000,
+ 0x1100, 0x1100,
+ 0x1200, 0x1200,
+ 0x1300, 0x1300,
+ 0x1400, 0x1400,
+ 0x1500, 0x1500,
+ 0x1600, 0x1600,
+ 0x1700, 0x1700,
+ 0x1800, 0x1800,
+ 0x1900, 0x1900,
+ 0x1a00, 0x1a00,
+ 0x1b00, 0x1b00,
+ 0x1c00, 0x1c00,
+ 0x1d00, 0x1d00,
+ 0x1e00, 0x1e00,
+ 0x1f00, 0x1f00,
+ 0x2000, 0x2000,
+ 0x2100, 0x2100,
+ 0x2200, 0x2200,
+ 0xffff, 0x0000
+};
+
+static GfxFontEncoding16 japan12AdobeJapan12VEnc16 = {
+ 1,
+ { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+ japan12AdobeJapan12VMap2, 37
+};
+
+static struct {
+ char *name;
+ GfxFontEncoding16 *enc;
+} gfxJapan12Tab[] = {
+ { "78-EUC-H", &japan1278EUCHEnc16 },
+ { "78-EUC-V", &japan1278EUCVEnc16 },
+ { "78-H", &japan1278HEnc16 },
+ { "78-RKSJ-H", &japan1278RKSJHEnc16 },
+ { "78-RKSJ-V", &japan1278RKSJVEnc16 },
+ { "78-V", &japan1278VEnc16 },
+ { "78ms-RKSJ-H", &japan1278msRKSJHEnc16 },
+ { "78ms-RKSJ-V", &japan1278msRKSJVEnc16 },
+ { "83pv-RKSJ-H", &japan1283pvRKSJHEnc16 },
+ { "90ms-RKSJ-H", &japan1290msRKSJHEnc16 },
+ { "90ms-RKSJ-V", &japan1290msRKSJVEnc16 },
+ { "90msp-RKSJ-H", &japan1290mspRKSJHEnc16 },
+ { "90msp-RKSJ-V", &japan1290mspRKSJVEnc16 },
+ { "90pv-RKSJ-H", &japan1290pvRKSJHEnc16 },
+ { "90pv-RKSJ-V", &japan1290pvRKSJVEnc16 },
+ { "Add-H", &japan12AddHEnc16 },
+ { "Add-RKSJ-H", &japan12AddRKSJHEnc16 },
+ { "Add-RKSJ-V", &japan12AddRKSJVEnc16 },
+ { "Add-V", &japan12AddVEnc16 },
+ { "Adobe-Japan1-0", &japan12AdobeJapan10Enc16 },
+ { "Adobe-Japan1-1", &japan12AdobeJapan11Enc16 },
+ { "Adobe-Japan1-2", &japan12AdobeJapan12Enc16 },
+ { "EUC-H", &japan12EUCHEnc16 },
+ { "EUC-V", &japan12EUCVEnc16 },
+ { "Ext-H", &japan12ExtHEnc16 },
+ { "Ext-RKSJ-H", &japan12ExtRKSJHEnc16 },
+ { "Ext-RKSJ-V", &japan12ExtRKSJVEnc16 },
+ { "Ext-V", &japan12ExtVEnc16 },
+ { "H", &japan12HEnc16 },
+ { "Hankaku", &japan12HankakuEnc16 },
+ { "Hiragana", &japan12HiraganaEnc16 },
+ { "Katakana", &japan12KatakanaEnc16 },
+ { "NWP-H", &japan12NWPHEnc16 },
+ { "NWP-V", &japan12NWPVEnc16 },
+ { "RKSJ-H", &japan12RKSJHEnc16 },
+ { "RKSJ-V", &japan12RKSJVEnc16 },
+ { "Roman", &japan12RomanEnc16 },
+ { "UniJIS-UCS2-H", &japan12UniJISUCS2HEnc16 },
+ { "UniJIS-UCS2-V", &japan12UniJISUCS2VEnc16 },
+ { "V", &japan12VEnc16 },
+ { "WP-Symbol", &japan12WPSymbolEnc16 },
+ { "Identity-H", &japan12AdobeJapan12Enc16 },
+ { "Identity-V", &japan12AdobeJapan12VEnc16 },
+ { NULL, NULL }
+};
+
+#endif
diff --git a/pdftops/Japan12ToRKSJ.h b/pdftops/Japan12ToRKSJ.h
new file mode 100644
index 000000000..5ca62c30c
--- /dev/null
+++ b/pdftops/Japan12ToRKSJ.h
@@ -0,0 +1,1038 @@
+static Gushort japan12ToRKSJ[8286] = {
+ 0x0020, 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026,
+ 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e,
+ 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036,
+ 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e,
+ 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046,
+ 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e,
+ 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056,
+ 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e,
+ 0x005f, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066,
+ 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e,
+ 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076,
+ 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028,
+ 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030,
+ 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038,
+ 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040,
+ 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048,
+ 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050,
+ 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
+ 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0060,
+ 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068,
+ 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070,
+ 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078,
+ 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x00a0, 0x00a1,
+ 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, 0x00a8, 0x00a9,
+ 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af, 0x00b0, 0x00b1,
+ 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, 0x00b8, 0x00b9,
+ 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf, 0x00c0, 0x00c1,
+ 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, 0x00c8, 0x00c9,
+ 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf, 0x00d0, 0x00d1,
+ 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, 0x00d8, 0x00d9,
+ 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x8140, 0x8141, 0x8142, 0x8143, 0x8144, 0x8145, 0x8146,
+ 0x8147, 0x8148, 0x8149, 0x814a, 0x814b, 0x814c, 0x814d, 0x814e,
+ 0x814f, 0x8150, 0x8151, 0x8152, 0x8153, 0x8154, 0x8155, 0x8156,
+ 0x8157, 0x8158, 0x8159, 0x815a, 0x815b, 0x815c, 0x815d, 0x815e,
+ 0x815f, 0x8160, 0x8161, 0x8162, 0x8163, 0x8164, 0x8165, 0x8166,
+ 0x8167, 0x8168, 0x8169, 0x816a, 0x816b, 0x816c, 0x816d, 0x816e,
+ 0x816f, 0x8170, 0x8171, 0x8172, 0x8173, 0x8174, 0x8175, 0x8176,
+ 0x8177, 0x8178, 0x8179, 0x817a, 0x817b, 0x817c, 0x817d, 0x817e,
+ 0x8180, 0x8181, 0x8182, 0x8183, 0x8184, 0x8185, 0x8186, 0x8187,
+ 0x8188, 0x8189, 0x818a, 0x818b, 0x818c, 0x818d, 0x818e, 0x818f,
+ 0x8190, 0x8191, 0x8192, 0x8193, 0x8194, 0x8195, 0x8196, 0x8197,
+ 0x8198, 0x8199, 0x819a, 0x819b, 0x819c, 0x819d, 0x819e, 0x819f,
+ 0x81a0, 0x81a1, 0x81a2, 0x81a3, 0x81a4, 0x81a5, 0x81a6, 0x81a7,
+ 0x81a8, 0x81a9, 0x81aa, 0x81ab, 0x81ac, 0x81b8, 0x81b9, 0x81ba,
+ 0x81bb, 0x81bc, 0x81bd, 0x81be, 0x81bf, 0x81c8, 0x81c9, 0x81ca,
+ 0x81cb, 0x81cc, 0x81cd, 0x81ce, 0x81da, 0x81db, 0x81dc, 0x81dd,
+ 0x81de, 0x81df, 0x81e0, 0x81e1, 0x81e2, 0x81e3, 0x81e4, 0x81e5,
+ 0x81e6, 0x81e7, 0x81e8, 0x81f0, 0x81f1, 0x81f2, 0x81f3, 0x81f4,
+ 0x81f5, 0x81f6, 0x81f7, 0x81fc, 0x824f, 0x8250, 0x8251, 0x8252,
+ 0x8253, 0x8254, 0x8255, 0x8256, 0x8257, 0x8258, 0x8260, 0x8261,
+ 0x8262, 0x8263, 0x8264, 0x8265, 0x8266, 0x8267, 0x8268, 0x8269,
+ 0x826a, 0x826b, 0x826c, 0x826d, 0x826e, 0x826f, 0x8270, 0x8271,
+ 0x8272, 0x8273, 0x8274, 0x8275, 0x8276, 0x8277, 0x8278, 0x8279,
+ 0x8281, 0x8282, 0x8283, 0x8284, 0x8285, 0x8286, 0x8287, 0x8288,
+ 0x8289, 0x828a, 0x828b, 0x828c, 0x828d, 0x828e, 0x828f, 0x8290,
+ 0x8291, 0x8292, 0x8293, 0x8294, 0x8295, 0x8296, 0x8297, 0x8298,
+ 0x8299, 0x829a, 0x829f, 0x82a0, 0x82a1, 0x82a2, 0x82a3, 0x82a4,
+ 0x82a5, 0x82a6, 0x82a7, 0x82a8, 0x82a9, 0x82aa, 0x82ab, 0x82ac,
+ 0x82ad, 0x82ae, 0x82af, 0x82b0, 0x82b1, 0x82b2, 0x82b3, 0x82b4,
+ 0x82b5, 0x82b6, 0x82b7, 0x82b8, 0x82b9, 0x82ba, 0x82bb, 0x82bc,
+ 0x82bd, 0x82be, 0x82bf, 0x82c0, 0x82c1, 0x82c2, 0x82c3, 0x82c4,
+ 0x82c5, 0x82c6, 0x82c7, 0x82c8, 0x82c9, 0x82ca, 0x82cb, 0x82cc,
+ 0x82cd, 0x82ce, 0x82cf, 0x82d0, 0x82d1, 0x82d2, 0x82d3, 0x82d4,
+ 0x82d5, 0x82d6, 0x82d7, 0x82d8, 0x82d9, 0x82da, 0x82db, 0x82dc,
+ 0x82dd, 0x82de, 0x82df, 0x82e0, 0x82e1, 0x82e2, 0x82e3, 0x82e4,
+ 0x82e5, 0x82e6, 0x82e7, 0x82e8, 0x82e9, 0x82ea, 0x82eb, 0x82ec,
+ 0x82ed, 0x82ee, 0x82ef, 0x82f0, 0x82f1, 0x8340, 0x8341, 0x8342,
+ 0x8343, 0x8344, 0x8345, 0x8346, 0x8347, 0x8348, 0x8349, 0x834a,
+ 0x834b, 0x834c, 0x834d, 0x834e, 0x834f, 0x8350, 0x8351, 0x8352,
+ 0x8353, 0x8354, 0x8355, 0x8356, 0x8357, 0x8358, 0x8359, 0x835a,
+ 0x835b, 0x835c, 0x835d, 0x835e, 0x835f, 0x8360, 0x8361, 0x8362,
+ 0x8363, 0x8364, 0x8365, 0x8366, 0x8367, 0x8368, 0x8369, 0x836a,
+ 0x836b, 0x836c, 0x836d, 0x836e, 0x836f, 0x8370, 0x8371, 0x8372,
+ 0x8373, 0x8374, 0x8375, 0x8376, 0x8377, 0x8378, 0x8379, 0x837a,
+ 0x837b, 0x837c, 0x837d, 0x837e, 0x8380, 0x8381, 0x8382, 0x8383,
+ 0x8384, 0x8385, 0x8386, 0x8387, 0x8388, 0x8389, 0x838a, 0x838b,
+ 0x838c, 0x838d, 0x838e, 0x838f, 0x8390, 0x8391, 0x8392, 0x8393,
+ 0x8394, 0x8395, 0x8396, 0x839f, 0x83a0, 0x83a1, 0x83a2, 0x83a3,
+ 0x83a4, 0x83a5, 0x83a6, 0x83a7, 0x83a8, 0x83a9, 0x83aa, 0x83ab,
+ 0x83ac, 0x83ad, 0x83ae, 0x83af, 0x83b0, 0x83b1, 0x83b2, 0x83b3,
+ 0x83b4, 0x83b5, 0x83b6, 0x83bf, 0x83c0, 0x83c1, 0x83c2, 0x83c3,
+ 0x83c4, 0x83c5, 0x83c6, 0x83c7, 0x83c8, 0x83c9, 0x83ca, 0x83cb,
+ 0x83cc, 0x83cd, 0x83ce, 0x83cf, 0x83d0, 0x83d1, 0x83d2, 0x83d3,
+ 0x83d4, 0x83d5, 0x83d6, 0x8440, 0x8441, 0x8442, 0x8443, 0x8444,
+ 0x8445, 0x8446, 0x8447, 0x8448, 0x8449, 0x844a, 0x844b, 0x844c,
+ 0x844d, 0x844e, 0x844f, 0x8450, 0x8451, 0x8452, 0x8453, 0x8454,
+ 0x8455, 0x8456, 0x8457, 0x8458, 0x8459, 0x845a, 0x845b, 0x845c,
+ 0x845d, 0x845e, 0x845f, 0x8460, 0x8470, 0x8471, 0x8472, 0x8473,
+ 0x8474, 0x8475, 0x8476, 0x8477, 0x8478, 0x8479, 0x847a, 0x847b,
+ 0x847c, 0x847d, 0x847e, 0x8480, 0x8481, 0x8482, 0x8483, 0x8484,
+ 0x8485, 0x8486, 0x8487, 0x8488, 0x8489, 0x848a, 0x848b, 0x848c,
+ 0x848d, 0x848e, 0x848f, 0x8490, 0x8491, 0x889f, 0x88a0, 0x88a1,
+ 0x88a2, 0x88a3, 0x88a4, 0x88a5, 0x88a6, 0x88a7, 0x88a8, 0x88a9,
+ 0x88aa, 0x88ab, 0x88ac, 0x88ad, 0x88ae, 0x88af, 0x88b0, 0x88b1,
+ 0x88b2, 0x88b3, 0x88b4, 0x88b5, 0x88b6, 0x88b7, 0x88b8, 0x88b9,
+ 0x88ba, 0x88bb, 0x88bc, 0x88bd, 0x88be, 0x88bf, 0x88c0, 0x88c1,
+ 0x88c2, 0x88c3, 0x88c4, 0x88c5, 0x88c6, 0x88c7, 0x88c8, 0x88c9,
+ 0x88ca, 0x88cb, 0x88cc, 0x88cd, 0x88ce, 0x88cf, 0x88d0, 0x88d1,
+ 0x88d2, 0x88d3, 0x88d4, 0x88d5, 0x88d6, 0x88d7, 0x88d8, 0x88d9,
+ 0x88da, 0x88db, 0x88dc, 0x88dd, 0x88de, 0x88df, 0x88e0, 0x88e1,
+ 0x88e2, 0x88e3, 0x88e4, 0x88e5, 0x88e6, 0x88e7, 0x88e8, 0x88e9,
+ 0x88ea, 0x88eb, 0x88ec, 0x88ed, 0x88ee, 0x88ef, 0x88f0, 0x88f1,
+ 0x88f2, 0x88f3, 0x88f4, 0x88f5, 0x88f6, 0x88f7, 0x88f8, 0x88f9,
+ 0x88fa, 0x88fb, 0x88fc, 0x8940, 0x8941, 0x8942, 0x8943, 0x8944,
+ 0x8945, 0x8946, 0x8947, 0x8948, 0x8949, 0x894a, 0x894b, 0x894c,
+ 0x894d, 0x894e, 0x894f, 0x8950, 0x8951, 0x8952, 0x8953, 0x8954,
+ 0x8955, 0x8956, 0x8957, 0x8958, 0x8959, 0x895a, 0x895b, 0x895c,
+ 0x895d, 0x895e, 0x895f, 0x8960, 0x8961, 0x8962, 0x8963, 0x8964,
+ 0x8965, 0x8966, 0x8967, 0x8968, 0x8969, 0x896a, 0x896b, 0x896c,
+ 0x896d, 0x896e, 0x896f, 0x8970, 0x8971, 0x8972, 0x8973, 0x8974,
+ 0x8975, 0x8976, 0x8977, 0x8978, 0x8979, 0x897a, 0x897b, 0x897c,
+ 0x897d, 0x897e, 0x8980, 0x8981, 0x8982, 0x8983, 0x8984, 0x8985,
+ 0x8986, 0x8987, 0x8988, 0x8989, 0x898a, 0x898b, 0x898c, 0x898d,
+ 0x898e, 0x898f, 0x8990, 0x8991, 0x8992, 0x8993, 0x8994, 0x8995,
+ 0x8996, 0x8997, 0x8998, 0x8999, 0x899a, 0x899b, 0x899c, 0x899d,
+ 0x899e, 0x899f, 0x89a0, 0x89a1, 0x89a2, 0x89a3, 0x89a4, 0x89a5,
+ 0x89a6, 0x89a7, 0x89a8, 0x89a9, 0x89aa, 0x89ab, 0x89ac, 0x89ad,
+ 0x89ae, 0x89af, 0x89b0, 0x89b1, 0x89b2, 0x89b3, 0x89b4, 0x89b5,
+ 0x89b6, 0x89b7, 0x89b8, 0x89b9, 0x89ba, 0x89bb, 0x89bc, 0x89bd,
+ 0x89be, 0x89bf, 0x89c0, 0x89c1, 0x89c2, 0x89c3, 0x89c4, 0x89c5,
+ 0x89c6, 0x89c7, 0x89c8, 0x89c9, 0x89ca, 0x89cb, 0x89cc, 0x89cd,
+ 0x89ce, 0x89cf, 0x89d0, 0x89d1, 0x89d2, 0x89d3, 0x89d4, 0x89d5,
+ 0x89d6, 0x89d7, 0x89d8, 0x89d9, 0x89da, 0x89db, 0x89dc, 0x89dd,
+ 0x89de, 0x89df, 0x89e0, 0x89e1, 0x89e2, 0x89e3, 0x89e4, 0x89e5,
+ 0x89e6, 0x89e7, 0x89e8, 0x89e9, 0x89ea, 0x89eb, 0x89ec, 0x89ed,
+ 0x89ee, 0x89ef, 0x89f0, 0x89f1, 0x89f2, 0x89f3, 0x89f4, 0x89f5,
+ 0x89f6, 0x89f7, 0x89f8, 0x89f9, 0x89fa, 0x89fb, 0x89fc, 0x8a40,
+ 0x8a41, 0x8a42, 0x8a43, 0x8a44, 0x8a45, 0x8a46, 0x8a47, 0x8a48,
+ 0x8a49, 0x8a4a, 0x8a4b, 0x8a4c, 0x8a4d, 0x8a4e, 0x8a4f, 0x8a50,
+ 0x8a51, 0x8a52, 0x8a53, 0x8a54, 0x8a55, 0x8a56, 0x8a57, 0x8a58,
+ 0x8a59, 0x8a5a, 0x8a5b, 0x8a5c, 0x8a5d, 0x8a5e, 0x8a5f, 0x8a60,
+ 0x8a61, 0x8a62, 0x8a63, 0x8a64, 0x8a65, 0x8a66, 0x8a67, 0x8a68,
+ 0x8a69, 0x8a6a, 0x8a6b, 0x8a6c, 0x8a6d, 0x8a6e, 0x8a6f, 0x8a70,
+ 0x8a71, 0x8a72, 0x8a73, 0x8a74, 0x8a75, 0x8a76, 0x8a77, 0x8a78,
+ 0x8a79, 0x8a7a, 0x8a7b, 0x8a7c, 0x8a7d, 0x8a7e, 0x8a80, 0x8a81,
+ 0x8a82, 0x8a83, 0x8a84, 0x8a85, 0x8a86, 0x8a87, 0x8a88, 0x8a89,
+ 0x8a8a, 0x8a8b, 0x8a8c, 0x8a8d, 0x8a8e, 0x8a8f, 0x8a90, 0x8a91,
+ 0x8a92, 0x8a93, 0x8a94, 0x8a95, 0x8a96, 0x8a97, 0x8a98, 0x8a99,
+ 0x8a9a, 0x8a9b, 0x8a9c, 0x8a9d, 0x8a9e, 0x8a9f, 0x8aa0, 0x8aa1,
+ 0x8aa2, 0x8aa3, 0x8aa4, 0x8aa5, 0x8aa6, 0x8aa7, 0x8aa8, 0x8aa9,
+ 0x8aaa, 0x8aab, 0x8aac, 0x8aad, 0x8aae, 0x8aaf, 0x8ab0, 0x8ab1,
+ 0x8ab2, 0x8ab3, 0x8ab4, 0x8ab5, 0x8ab6, 0x8ab7, 0x8ab8, 0x8ab9,
+ 0x8aba, 0x8abb, 0x8abc, 0x8abd, 0x8abe, 0x8abf, 0x8ac0, 0x8ac1,
+ 0x8ac2, 0x8ac3, 0x8ac4, 0x8ac5, 0x8ac6, 0x8ac7, 0x8ac8, 0x8ac9,
+ 0x8aca, 0x8acb, 0x8acc, 0x8acd, 0x8ace, 0x8acf, 0x8ad0, 0x8ad1,
+ 0x8ad2, 0x8ad3, 0x8ad4, 0x8ad5, 0x8ad6, 0x8ad7, 0x8ad8, 0x8ad9,
+ 0x8ada, 0x8adb, 0x8adc, 0x8add, 0x8ade, 0x8adf, 0x8ae0, 0x8ae1,
+ 0x8ae2, 0x8ae3, 0x8ae4, 0x8ae5, 0x8ae6, 0x8ae7, 0x8ae8, 0x8ae9,
+ 0x8aea, 0x8aeb, 0x8aec, 0x8aed, 0x8aee, 0x8aef, 0x8af0, 0x8af1,
+ 0x8af2, 0x8af3, 0x8af4, 0x8af5, 0x8af6, 0x8af7, 0x8af8, 0x8af9,
+ 0x8afa, 0x8afb, 0x8afc, 0x8b40, 0x8b41, 0x8b42, 0x8b43, 0x8b44,
+ 0x8b45, 0x8b46, 0x8b47, 0x8b48, 0x8b49, 0x8b4a, 0x8b4b, 0x8b4c,
+ 0x8b4d, 0x8b4e, 0x8b4f, 0x8b50, 0x8b51, 0x8b52, 0x8b53, 0x8b54,
+ 0x8b55, 0x8b56, 0x8b57, 0x8b58, 0x8b59, 0x8b5a, 0x8b5b, 0x8b5c,
+ 0x8b5d, 0x8b5e, 0x8b5f, 0x8b60, 0x8b61, 0x8b62, 0x8b63, 0x8b64,
+ 0x8b65, 0x8b66, 0x8b67, 0x8b68, 0x8b69, 0x8b6a, 0x8b6b, 0x8b6c,
+ 0x8b6d, 0x8b6e, 0x8b6f, 0x8b70, 0x8b71, 0x8b72, 0x8b73, 0x8b74,
+ 0x8b75, 0x8b76, 0x8b77, 0x8b78, 0x8b79, 0x8b7a, 0x8b7b, 0x8b7c,
+ 0x8b7d, 0x8b7e, 0x8b80, 0x8b81, 0x8b82, 0x8b83, 0x8b84, 0x8b85,
+ 0x8b86, 0x8b87, 0x8b88, 0x8b89, 0x8b8a, 0x8b8b, 0x8b8c, 0x8b8d,
+ 0x8b8e, 0x8b8f, 0x8b90, 0x8b91, 0x8b92, 0x8b93, 0x8b94, 0x8b95,
+ 0x8b96, 0x8b97, 0x8b98, 0x8b99, 0x8b9a, 0x8b9b, 0x8b9c, 0x8b9d,
+ 0x8b9e, 0x8b9f, 0x8ba0, 0x8ba1, 0x8ba2, 0x8ba3, 0x8ba4, 0x8ba5,
+ 0x8ba6, 0x8ba7, 0x8ba8, 0x8ba9, 0x8baa, 0x8bab, 0x8bac, 0x8bad,
+ 0x8bae, 0x8baf, 0x8bb0, 0x8bb1, 0x8bb2, 0x8bb3, 0x8bb4, 0x8bb5,
+ 0x8bb6, 0x8bb7, 0x8bb8, 0x8bb9, 0x8bba, 0x8bbb, 0x8bbc, 0x8bbd,
+ 0x8bbe, 0x8bbf, 0x8bc0, 0x8bc1, 0x8bc2, 0x8bc3, 0x8bc4, 0x8bc5,
+ 0x8bc6, 0x8bc7, 0x8bc8, 0x8bc9, 0x8bca, 0x8bcb, 0x8bcc, 0x8bcd,
+ 0x8bce, 0x8bcf, 0x8bd0, 0x8bd1, 0x8bd2, 0x8bd3, 0x8bd4, 0x8bd5,
+ 0x8bd6, 0x8bd7, 0x8bd8, 0x8bd9, 0x8bda, 0x8bdb, 0x8bdc, 0x8bdd,
+ 0x8bde, 0x8bdf, 0x8be0, 0x8be1, 0x8be2, 0x8be3, 0x8be4, 0x8be5,
+ 0x8be6, 0x8be7, 0x8be8, 0x8be9, 0x8bea, 0x8beb, 0x8bec, 0x8bed,
+ 0x8bee, 0x8bef, 0x8bf0, 0x8bf1, 0x8bf2, 0x8bf3, 0x8bf4, 0x8bf5,
+ 0x8bf6, 0x8bf7, 0x8bf8, 0x8bf9, 0x8bfa, 0x8bfb, 0x8bfc, 0x8c40,
+ 0x8c41, 0x8c42, 0x8c43, 0x8c44, 0x8c45, 0x8c46, 0x8c47, 0x8c48,
+ 0x8c49, 0x8c4a, 0x8c4b, 0x8c4c, 0x8c4d, 0x8c4e, 0x8c4f, 0x8c50,
+ 0x8c51, 0x8c52, 0x8c53, 0x8c54, 0x8c55, 0x8c56, 0x8c57, 0x8c58,
+ 0x8c59, 0x8c5a, 0x8c5b, 0x8c5c, 0x8c5d, 0x8c5e, 0x8c5f, 0x8c60,
+ 0x8c61, 0x8c62, 0x8c63, 0x8c64, 0x8c65, 0x8c66, 0x8c67, 0x8c68,
+ 0x8c69, 0x8c6a, 0x8c6b, 0x8c6c, 0x8c6d, 0x8c6e, 0x8c6f, 0x8c70,
+ 0x8c71, 0x8c72, 0x8c73, 0x8c74, 0x8c75, 0x8c76, 0x8c77, 0x8c78,
+ 0x8c79, 0x8c7a, 0x8c7b, 0x8c7c, 0x8c7d, 0x8c7e, 0x8c80, 0x8c81,
+ 0x8c82, 0x8c83, 0x8c84, 0x8c85, 0x8c86, 0x8c87, 0x8c88, 0x8c89,
+ 0x8c8a, 0x8c8b, 0x8c8c, 0x8c8d, 0x8c8e, 0x8c8f, 0x8c90, 0x8c91,
+ 0x8c92, 0x8c93, 0x8c94, 0x8c95, 0x8c96, 0x8c97, 0x8c98, 0x8c99,
+ 0x8c9a, 0x8c9b, 0x8c9c, 0x8c9d, 0x8c9e, 0x8c9f, 0x8ca0, 0x8ca1,
+ 0x8ca2, 0x8ca3, 0x8ca4, 0x8ca5, 0x8ca6, 0x8ca7, 0x8ca8, 0x8ca9,
+ 0x8caa, 0x8cab, 0x8cac, 0x8cad, 0x8cae, 0x8caf, 0x8cb0, 0x8cb1,
+ 0x8cb2, 0x8cb3, 0x8cb4, 0x8cb5, 0x8cb6, 0x8cb7, 0x8cb8, 0x8cb9,
+ 0x8cba, 0x8cbb, 0x8cbc, 0x8cbd, 0x8cbe, 0x8cbf, 0x8cc0, 0x8cc1,
+ 0x8cc2, 0x8cc3, 0x8cc4, 0x8cc5, 0x8cc6, 0x8cc7, 0x8cc8, 0x8cc9,
+ 0x8cca, 0x8ccb, 0x8ccc, 0x8ccd, 0x8cce, 0x8ccf, 0x8cd0, 0x8cd1,
+ 0x8cd2, 0x8cd3, 0x8cd4, 0x8cd5, 0x8cd6, 0x8cd7, 0x8cd8, 0x8cd9,
+ 0x8cda, 0x8cdb, 0x8cdc, 0x8cdd, 0x8cde, 0x8cdf, 0x8ce0, 0x8ce1,
+ 0x8ce2, 0x8ce3, 0x8ce4, 0x8ce5, 0x8ce6, 0x8ce7, 0x8ce8, 0x8ce9,
+ 0x8cea, 0x8ceb, 0x8cec, 0x8ced, 0x8cee, 0x8cef, 0x8cf0, 0x8cf1,
+ 0x8cf2, 0x8cf3, 0x8cf4, 0x8cf5, 0x8cf6, 0x8cf7, 0x8cf8, 0x8cf9,
+ 0x8cfa, 0x8cfb, 0x8cfc, 0x8d40, 0x8d41, 0x8d42, 0x8d43, 0x8d44,
+ 0x8d45, 0x8d46, 0x8d47, 0x8d48, 0x8d49, 0x8d4a, 0x8d4b, 0x8d4c,
+ 0x8d4d, 0x8d4e, 0x8d4f, 0x8d50, 0x8d51, 0x8d52, 0x8d53, 0x8d54,
+ 0x8d55, 0x8d56, 0x8d57, 0x8d58, 0x8d59, 0x8d5a, 0x8d5b, 0x8d5c,
+ 0x8d5d, 0x8d5e, 0x8d5f, 0x8d60, 0x8d61, 0x8d62, 0x8d63, 0x8d64,
+ 0x8d65, 0x8d66, 0x8d67, 0x8d68, 0x8d69, 0x8d6a, 0x8d6b, 0x8d6c,
+ 0x8d6d, 0x8d6e, 0x8d6f, 0x8d70, 0x8d71, 0x8d72, 0x8d73, 0x8d74,
+ 0x8d75, 0x8d76, 0x8d77, 0x8d78, 0x8d79, 0x8d7a, 0x8d7b, 0x8d7c,
+ 0x8d7d, 0x8d7e, 0x8d80, 0x8d81, 0x8d82, 0x8d83, 0x8d84, 0x8d85,
+ 0x8d86, 0x8d87, 0x8d88, 0x8d89, 0x8d8a, 0x8d8b, 0x8d8c, 0x8d8d,
+ 0x8d8e, 0x8d8f, 0x8d90, 0x8d91, 0x8d92, 0x8d93, 0x8d94, 0x8d95,
+ 0x8d96, 0x8d97, 0x8d98, 0x8d99, 0x8d9a, 0x8d9b, 0x8d9c, 0x8d9d,
+ 0x8d9e, 0x8d9f, 0x8da0, 0x8da1, 0x8da2, 0x8da3, 0x8da4, 0x8da5,
+ 0x8da6, 0x8da7, 0x8da8, 0x8da9, 0x8daa, 0x8dab, 0x8dac, 0x8dad,
+ 0x8dae, 0x8daf, 0x8db0, 0x8db1, 0x8db2, 0x8db3, 0x8db4, 0x8db5,
+ 0x8db6, 0x8db7, 0x8db8, 0x8db9, 0x8dba, 0x8dbb, 0x8dbc, 0x8dbd,
+ 0x8dbe, 0x8dbf, 0x8dc0, 0x8dc1, 0x8dc2, 0x8dc3, 0x8dc4, 0x8dc5,
+ 0x8dc6, 0x8dc7, 0x8dc8, 0x8dc9, 0x8dca, 0x8dcb, 0x8dcc, 0x8dcd,
+ 0x8dce, 0x8dcf, 0x8dd0, 0x8dd1, 0x8dd2, 0x8dd3, 0x8dd4, 0x8dd5,
+ 0x8dd6, 0x8dd7, 0x8dd8, 0x8dd9, 0x8dda, 0x8ddb, 0x8ddc, 0x8ddd,
+ 0x8dde, 0x8ddf, 0x8de0, 0x8de1, 0x8de2, 0x8de3, 0x8de4, 0x8de5,
+ 0x8de6, 0x8de7, 0x8de8, 0x8de9, 0x8dea, 0x8deb, 0x8dec, 0x8ded,
+ 0x8dee, 0x8def, 0x8df0, 0x8df1, 0x8df2, 0x8df3, 0x8df4, 0x8df5,
+ 0x8df6, 0x8df7, 0x8df8, 0x8df9, 0x8dfa, 0x8dfb, 0x8dfc, 0x8e40,
+ 0x8e41, 0x8e42, 0x8e43, 0x8e44, 0x8e45, 0x8e46, 0x8e47, 0x8e48,
+ 0x8e49, 0x8e4a, 0x8e4b, 0x8e4c, 0x8e4d, 0x8e4e, 0x8e4f, 0x8e50,
+ 0x8e51, 0x8e52, 0x8e53, 0x8e54, 0x8e55, 0x8e56, 0x8e57, 0x8e58,
+ 0x8e59, 0x8e5a, 0x8e5b, 0x8e5c, 0x8e5d, 0x8e5e, 0x8e5f, 0x8e60,
+ 0x8e61, 0x8e62, 0x8e63, 0x8e64, 0x8e65, 0x8e66, 0x8e67, 0x8e68,
+ 0x8e69, 0x8e6a, 0x8e6b, 0x8e6c, 0x8e6d, 0x8e6e, 0x8e6f, 0x8e70,
+ 0x8e71, 0x8e72, 0x8e73, 0x8e74, 0x8e75, 0x8e76, 0x8e77, 0x8e78,
+ 0x8e79, 0x8e7a, 0x8e7b, 0x8e7c, 0x8e7d, 0x8e7e, 0x8e80, 0x8e81,
+ 0x8e82, 0x8e83, 0x8e84, 0x8e85, 0x8e86, 0x8e87, 0x8e88, 0x8e89,
+ 0x8e8a, 0x8e8b, 0x8e8c, 0x8e8d, 0x8e8e, 0x8e8f, 0x8e90, 0x8e91,
+ 0x8e92, 0x8e93, 0x8e94, 0x8e95, 0x8e96, 0x8e97, 0x8e98, 0x8e99,
+ 0x8e9a, 0x8e9b, 0x8e9c, 0x8e9d, 0x8e9e, 0x8e9f, 0x8ea0, 0x8ea1,
+ 0x8ea2, 0x8ea3, 0x8ea4, 0x8ea5, 0x8ea6, 0x8ea7, 0x8ea8, 0x8ea9,
+ 0x8eaa, 0x8eab, 0x8eac, 0x8ead, 0x8eae, 0x8eaf, 0x8eb0, 0x8eb1,
+ 0x8eb2, 0x8eb3, 0x8eb4, 0x8eb5, 0x8eb6, 0x8eb7, 0x8eb8, 0x8eb9,
+ 0x8eba, 0x8ebb, 0x8ebc, 0x8ebd, 0x8ebe, 0x8ebf, 0x8ec0, 0x8ec1,
+ 0x8ec2, 0x8ec3, 0x8ec4, 0x8ec5, 0x8ec6, 0x8ec7, 0x8ec8, 0x8ec9,
+ 0x8eca, 0x8ecb, 0x8ecc, 0x8ecd, 0x8ece, 0x8ecf, 0x8ed0, 0x8ed1,
+ 0x8ed2, 0x8ed3, 0x8ed4, 0x8ed5, 0x8ed6, 0x8ed7, 0x8ed8, 0x8ed9,
+ 0x8eda, 0x8edb, 0x8edc, 0x8edd, 0x8ede, 0x8edf, 0x8ee0, 0x8ee1,
+ 0x8ee2, 0x8ee3, 0x8ee4, 0x8ee5, 0x8ee6, 0x8ee7, 0x8ee8, 0x8ee9,
+ 0x8eea, 0x8eeb, 0x8eec, 0x8eed, 0x8eee, 0x8eef, 0x8ef0, 0x8ef1,
+ 0x8ef2, 0x8ef3, 0x8ef4, 0x8ef5, 0x8ef6, 0x8ef7, 0x8ef8, 0x8ef9,
+ 0x8efa, 0x8efb, 0x8efc, 0x8f40, 0x8f41, 0x8f42, 0x8f43, 0x8f44,
+ 0x8f45, 0x8f46, 0x8f47, 0x8f48, 0x8f49, 0x8f4a, 0x8f4b, 0x8f4c,
+ 0x8f4d, 0x8f4e, 0x8f4f, 0x8f50, 0x8f51, 0x8f52, 0x8f53, 0x8f54,
+ 0x8f55, 0x8f56, 0x8f57, 0x8f58, 0x8f59, 0x8f5a, 0x8f5b, 0x8f5c,
+ 0x8f5d, 0x8f5e, 0x8f5f, 0x8f60, 0x8f61, 0x8f62, 0x8f63, 0x8f64,
+ 0x8f65, 0x8f66, 0x8f67, 0x8f68, 0x8f69, 0x8f6a, 0x8f6b, 0x8f6c,
+ 0x8f6d, 0x8f6e, 0x8f6f, 0x8f70, 0x8f71, 0x8f72, 0x8f73, 0x8f74,
+ 0x8f75, 0x8f76, 0x8f77, 0x8f78, 0x8f79, 0x8f7a, 0x8f7b, 0x8f7c,
+ 0x8f7d, 0x8f7e, 0x8f80, 0x8f81, 0x8f82, 0x8f83, 0x8f84, 0x8f85,
+ 0x8f86, 0x8f87, 0x8f88, 0x8f89, 0x8f8a, 0x8f8b, 0x8f8c, 0x8f8d,
+ 0x8f8e, 0x8f8f, 0x8f90, 0x8f91, 0x8f92, 0x8f93, 0x8f94, 0x8f95,
+ 0x8f96, 0x8f97, 0x8f98, 0x8f99, 0x8f9a, 0x8f9b, 0x8f9c, 0x8f9d,
+ 0x8f9e, 0x8f9f, 0x8fa0, 0x8fa1, 0x8fa2, 0x8fa3, 0x8fa4, 0x8fa5,
+ 0x8fa6, 0x8fa7, 0x8fa8, 0x8fa9, 0x8faa, 0x8fab, 0x8fac, 0x8fad,
+ 0x8fae, 0x8faf, 0x8fb0, 0x8fb1, 0x8fb2, 0x8fb3, 0x8fb4, 0x8fb5,
+ 0x8fb6, 0x8fb7, 0x8fb8, 0x8fb9, 0x8fba, 0x8fbb, 0x8fbc, 0x8fbd,
+ 0x8fbe, 0x8fbf, 0x8fc0, 0x8fc1, 0x8fc2, 0x8fc3, 0x8fc4, 0x8fc5,
+ 0x8fc6, 0x8fc7, 0x8fc8, 0x8fc9, 0x8fca, 0x8fcb, 0x8fcc, 0x8fcd,
+ 0x8fce, 0x8fcf, 0x8fd0, 0x8fd1, 0x8fd2, 0x8fd3, 0x8fd4, 0x8fd5,
+ 0x8fd6, 0x8fd7, 0x8fd8, 0x8fd9, 0x8fda, 0x8fdb, 0x8fdc, 0x8fdd,
+ 0x8fde, 0x8fdf, 0x8fe0, 0x8fe1, 0x8fe2, 0x8fe3, 0x8fe4, 0x8fe5,
+ 0x8fe6, 0x8fe7, 0x8fe8, 0x8fe9, 0x8fea, 0x8feb, 0x8fec, 0x8fed,
+ 0x8fee, 0x8fef, 0x8ff0, 0x8ff1, 0x8ff2, 0x8ff3, 0x8ff4, 0x8ff5,
+ 0x8ff6, 0x8ff7, 0x8ff8, 0x8ff9, 0x8ffa, 0x8ffb, 0x8ffc, 0x9040,
+ 0x9041, 0x9042, 0x9043, 0x9044, 0x9045, 0x9046, 0x9047, 0x9048,
+ 0x9049, 0x904a, 0x904b, 0x904c, 0x904d, 0x904e, 0x904f, 0x9050,
+ 0x9051, 0x9052, 0x9053, 0x9054, 0x9055, 0x9056, 0x9057, 0x9058,
+ 0x9059, 0x905a, 0x905b, 0x905c, 0x905d, 0x905e, 0x905f, 0x9060,
+ 0x9061, 0x9062, 0x9063, 0x9064, 0x9065, 0x9066, 0x9067, 0x9068,
+ 0x9069, 0x906a, 0x906b, 0x906c, 0x906d, 0x906e, 0x906f, 0x9070,
+ 0x9071, 0x9072, 0x9073, 0x9074, 0x9075, 0x9076, 0x9077, 0x9078,
+ 0x9079, 0x907a, 0x907b, 0x907c, 0x907d, 0x907e, 0x9080, 0x9081,
+ 0x9082, 0x9083, 0x9084, 0x9085, 0x9086, 0x9087, 0x9088, 0x9089,
+ 0x908a, 0x908b, 0x908c, 0x908d, 0x908e, 0x908f, 0x9090, 0x9091,
+ 0x9092, 0x9093, 0x9094, 0x9095, 0x9096, 0x9097, 0x9098, 0x9099,
+ 0x909a, 0x909b, 0x909c, 0x909d, 0x909e, 0x909f, 0x90a0, 0x90a1,
+ 0x90a2, 0x90a3, 0x90a4, 0x90a5, 0x90a6, 0x90a7, 0x90a8, 0x90a9,
+ 0x90aa, 0x90ab, 0x90ac, 0x90ad, 0x90ae, 0x90af, 0x90b0, 0x90b1,
+ 0x90b2, 0x90b3, 0x90b4, 0x90b5, 0x90b6, 0x90b7, 0x90b8, 0x90b9,
+ 0x90ba, 0x90bb, 0x90bc, 0x90bd, 0x90be, 0x90bf, 0x90c0, 0x90c1,
+ 0x90c2, 0x90c3, 0x90c4, 0x90c5, 0x90c6, 0x90c7, 0x90c8, 0x90c9,
+ 0x90ca, 0x90cb, 0x90cc, 0x90cd, 0x90ce, 0x90cf, 0x90d0, 0x90d1,
+ 0x90d2, 0x90d3, 0x90d4, 0x90d5, 0x90d6, 0x90d7, 0x90d8, 0x90d9,
+ 0x90da, 0x90db, 0x90dc, 0x90dd, 0x90de, 0x90df, 0x90e0, 0x90e1,
+ 0x90e2, 0x90e3, 0x90e4, 0x90e5, 0x90e6, 0x90e7, 0x90e8, 0x90e9,
+ 0x90ea, 0x90eb, 0x90ec, 0x90ed, 0x90ee, 0x90ef, 0x90f0, 0x90f1,
+ 0x90f2, 0x90f3, 0x90f4, 0x90f5, 0x90f6, 0x90f7, 0x90f8, 0x90f9,
+ 0x90fa, 0x90fb, 0x90fc, 0x9140, 0x9141, 0x9142, 0x9143, 0x9144,
+ 0x9145, 0x9146, 0x9147, 0x9148, 0x9149, 0x914a, 0x914b, 0x914c,
+ 0x914d, 0x914e, 0x914f, 0x9150, 0x9151, 0x9152, 0x9153, 0x9154,
+ 0x9155, 0x9156, 0x9157, 0x9158, 0x9159, 0x915a, 0x915b, 0x915c,
+ 0x915d, 0x915e, 0x915f, 0x9160, 0x9161, 0x9162, 0x9163, 0x9164,
+ 0x9165, 0x9166, 0x9167, 0x9168, 0x9169, 0x916a, 0x916b, 0x916c,
+ 0x916d, 0x916e, 0x916f, 0x9170, 0x9171, 0x9172, 0x9173, 0x9174,
+ 0x9175, 0x9176, 0x9177, 0x9178, 0x9179, 0x917a, 0x917b, 0x917c,
+ 0x917d, 0x917e, 0x9180, 0x9181, 0x9182, 0x9183, 0x9184, 0x9185,
+ 0x9186, 0x9187, 0x9188, 0x9189, 0x918a, 0x918b, 0x918c, 0x918d,
+ 0x918e, 0x918f, 0x9190, 0x9191, 0x9192, 0x9193, 0x9194, 0x9195,
+ 0x9196, 0x9197, 0x9198, 0x9199, 0x919a, 0x919b, 0x919c, 0x919d,
+ 0x919e, 0x919f, 0x91a0, 0x91a1, 0x91a2, 0x91a3, 0x91a4, 0x91a5,
+ 0x91a6, 0x91a7, 0x91a8, 0x91a9, 0x91aa, 0x91ab, 0x91ac, 0x91ad,
+ 0x91ae, 0x91af, 0x91b0, 0x91b1, 0x91b2, 0x91b3, 0x91b4, 0x91b5,
+ 0x91b6, 0x91b7, 0x91b8, 0x91b9, 0x91ba, 0x91bb, 0x91bc, 0x91bd,
+ 0x91be, 0x91bf, 0x91c0, 0x91c1, 0x91c2, 0x91c3, 0x91c4, 0x91c5,
+ 0x91c6, 0x91c7, 0x91c8, 0x91c9, 0x91ca, 0x91cb, 0x91cc, 0x91cd,
+ 0x91ce, 0x91cf, 0x91d0, 0x91d1, 0x91d2, 0x91d3, 0x91d4, 0x91d5,
+ 0x91d6, 0x91d7, 0x91d8, 0x91d9, 0x91da, 0x91db, 0x91dc, 0x91dd,
+ 0x91de, 0x91df, 0x91e0, 0x91e1, 0x91e2, 0x91e3, 0x91e4, 0x91e5,
+ 0x91e6, 0x91e7, 0x91e8, 0x91e9, 0x91ea, 0x91eb, 0x91ec, 0x91ed,
+ 0x91ee, 0x91ef, 0x91f0, 0x91f1, 0x91f2, 0x91f3, 0x91f4, 0x91f5,
+ 0x91f6, 0x91f7, 0x91f8, 0x91f9, 0x91fa, 0x91fb, 0x91fc, 0x9240,
+ 0x9241, 0x9242, 0x9243, 0x9244, 0x9245, 0x9246, 0x9247, 0x9248,
+ 0x9249, 0x924a, 0x924b, 0x924c, 0x924d, 0x924e, 0x924f, 0x9250,
+ 0x9251, 0x9252, 0x9253, 0x9254, 0x9255, 0x9256, 0x9257, 0x9258,
+ 0x9259, 0x925a, 0x925b, 0x925c, 0x925d, 0x925e, 0x925f, 0x9260,
+ 0x9261, 0x9262, 0x9263, 0x9264, 0x9265, 0x9266, 0x9267, 0x9268,
+ 0x9269, 0x926a, 0x926b, 0x926c, 0x926d, 0x926e, 0x926f, 0x9270,
+ 0x9271, 0x9272, 0x9273, 0x9274, 0x9275, 0x9276, 0x9277, 0x9278,
+ 0x9279, 0x927a, 0x927b, 0x927c, 0x927d, 0x927e, 0x9280, 0x9281,
+ 0x9282, 0x9283, 0x9284, 0x9285, 0x9286, 0x9287, 0x9288, 0x9289,
+ 0x928a, 0x928b, 0x928c, 0x928d, 0x928e, 0x928f, 0x9290, 0x9291,
+ 0x9292, 0x9293, 0x9294, 0x9295, 0x9296, 0x9297, 0x9298, 0x9299,
+ 0x929a, 0x929b, 0x929c, 0x929d, 0x929e, 0x929f, 0x92a0, 0x92a1,
+ 0x92a2, 0x92a3, 0x92a4, 0x92a5, 0x92a6, 0x92a7, 0x92a8, 0x92a9,
+ 0x92aa, 0x92ab, 0x92ac, 0x92ad, 0x92ae, 0x92af, 0x92b0, 0x92b1,
+ 0x92b2, 0x92b3, 0x92b4, 0x92b5, 0x92b6, 0x92b7, 0x92b8, 0x92b9,
+ 0x92ba, 0x92bb, 0x92bc, 0x92bd, 0x92be, 0x92bf, 0x92c0, 0x92c1,
+ 0x92c2, 0x92c3, 0x92c4, 0x92c5, 0x92c6, 0x92c7, 0x92c8, 0x92c9,
+ 0x92ca, 0x92cb, 0x92cc, 0x92cd, 0x92ce, 0x92cf, 0x92d0, 0x92d1,
+ 0x92d2, 0x92d3, 0x92d4, 0x92d5, 0x92d6, 0x92d7, 0x92d8, 0x92d9,
+ 0x92da, 0x92db, 0x92dc, 0x92dd, 0x92de, 0x92df, 0x92e0, 0x92e1,
+ 0x92e2, 0x92e3, 0x92e4, 0x92e5, 0x92e6, 0x92e7, 0x92e8, 0x92e9,
+ 0x92ea, 0x92eb, 0x92ec, 0x92ed, 0x92ee, 0x92ef, 0x92f0, 0x92f1,
+ 0x92f2, 0x92f3, 0x92f4, 0x92f5, 0x92f6, 0x92f7, 0x92f8, 0x92f9,
+ 0x92fa, 0x92fb, 0x92fc, 0x9340, 0x9341, 0x9342, 0x9343, 0x9344,
+ 0x9345, 0x9346, 0x9347, 0x9348, 0x9349, 0x934a, 0x934b, 0x934c,
+ 0x934d, 0x934e, 0x934f, 0x9350, 0x9351, 0x9352, 0x9353, 0x9354,
+ 0x9355, 0x9356, 0x9357, 0x9358, 0x9359, 0x935a, 0x935b, 0x935c,
+ 0x935d, 0x935e, 0x935f, 0x9360, 0x9361, 0x9362, 0x9363, 0x9364,
+ 0x9365, 0x9366, 0x9367, 0x9368, 0x9369, 0x936a, 0x936b, 0x936c,
+ 0x936d, 0x936e, 0x936f, 0x9370, 0x9371, 0x9372, 0x9373, 0x9374,
+ 0x9375, 0x9376, 0x9377, 0x9378, 0x9379, 0x937a, 0x937b, 0x937c,
+ 0x937d, 0x937e, 0x9380, 0x9381, 0x9382, 0x9383, 0x9384, 0x9385,
+ 0x9386, 0x9387, 0x9388, 0x9389, 0x938a, 0x938b, 0x938c, 0x938d,
+ 0x938e, 0x938f, 0x9390, 0x9391, 0x9392, 0x9393, 0x9394, 0x9395,
+ 0x9396, 0x9397, 0x9398, 0x9399, 0x939a, 0x939b, 0x939c, 0x939d,
+ 0x939e, 0x939f, 0x93a0, 0x93a1, 0x93a2, 0x93a3, 0x93a4, 0x93a5,
+ 0x93a6, 0x93a7, 0x93a8, 0x93a9, 0x93aa, 0x93ab, 0x93ac, 0x93ad,
+ 0x93ae, 0x93af, 0x93b0, 0x93b1, 0x93b2, 0x93b3, 0x93b4, 0x93b5,
+ 0x93b6, 0x93b7, 0x93b8, 0x93b9, 0x93ba, 0x93bb, 0x93bc, 0x93bd,
+ 0x93be, 0x93bf, 0x93c0, 0x93c1, 0x93c2, 0x93c3, 0x93c4, 0x93c5,
+ 0x93c6, 0x93c7, 0x93c8, 0x93c9, 0x93ca, 0x93cb, 0x93cc, 0x93cd,
+ 0x93ce, 0x93cf, 0x93d0, 0x93d1, 0x93d2, 0x93d3, 0x93d4, 0x93d5,
+ 0x93d6, 0x93d7, 0x93d8, 0x93d9, 0x93da, 0x93db, 0x93dc, 0x93dd,
+ 0x93de, 0x93df, 0x93e0, 0x93e1, 0x93e2, 0x93e3, 0x93e4, 0x93e5,
+ 0x93e6, 0x93e7, 0x93e8, 0x93e9, 0x93ea, 0x93eb, 0x93ec, 0x93ed,
+ 0x93ee, 0x93ef, 0x93f0, 0x93f1, 0x93f2, 0x93f3, 0x93f4, 0x93f5,
+ 0x93f6, 0x93f7, 0x93f8, 0x93f9, 0x93fa, 0x93fb, 0x93fc, 0x9440,
+ 0x9441, 0x9442, 0x9443, 0x9444, 0x9445, 0x9446, 0x9447, 0x9448,
+ 0x9449, 0x944a, 0x944b, 0x944c, 0x944d, 0x944e, 0x944f, 0x9450,
+ 0x9451, 0x9452, 0x9453, 0x9454, 0x9455, 0x9456, 0x9457, 0x9458,
+ 0x9459, 0x945a, 0x945b, 0x945c, 0x945d, 0x945e, 0x945f, 0x9460,
+ 0x9461, 0x9462, 0x9463, 0x9464, 0x9465, 0x9466, 0x9467, 0x9468,
+ 0x9469, 0x946a, 0x946b, 0x946c, 0x946d, 0x946e, 0x946f, 0x9470,
+ 0x9471, 0x9472, 0x9473, 0x9474, 0x9475, 0x9476, 0x9477, 0x9478,
+ 0x9479, 0x947a, 0x947b, 0x947c, 0x947d, 0x947e, 0x9480, 0x9481,
+ 0x9482, 0x9483, 0x9484, 0x9485, 0x9486, 0x9487, 0x9488, 0x9489,
+ 0x948a, 0x948b, 0x948c, 0x948d, 0x948e, 0x948f, 0x9490, 0x9491,
+ 0x9492, 0x9493, 0x9494, 0x9495, 0x9496, 0x9497, 0x9498, 0x9499,
+ 0x949a, 0x949b, 0x949c, 0x949d, 0x949e, 0x949f, 0x94a0, 0x94a1,
+ 0x94a2, 0x94a3, 0x94a4, 0x94a5, 0x94a6, 0x94a7, 0x94a8, 0x94a9,
+ 0x94aa, 0x94ab, 0x94ac, 0x94ad, 0x94ae, 0x94af, 0x94b0, 0x94b1,
+ 0x94b2, 0x94b3, 0x94b4, 0x94b5, 0x94b6, 0x94b7, 0x94b8, 0x94b9,
+ 0x94ba, 0x94bb, 0x94bc, 0x94bd, 0x94be, 0x94bf, 0x94c0, 0x94c1,
+ 0x94c2, 0x94c3, 0x94c4, 0x94c5, 0x94c6, 0x94c7, 0x94c8, 0x94c9,
+ 0x94ca, 0x94cb, 0x94cc, 0x94cd, 0x94ce, 0x94cf, 0x94d0, 0x94d1,
+ 0x94d2, 0x94d3, 0x94d4, 0x94d5, 0x94d6, 0x94d7, 0x94d8, 0x94d9,
+ 0x94da, 0x94db, 0x94dc, 0x94dd, 0x94de, 0x94df, 0x94e0, 0x94e1,
+ 0x94e2, 0x94e3, 0x94e4, 0x94e5, 0x94e6, 0x94e7, 0x94e8, 0x94e9,
+ 0x94ea, 0x94eb, 0x94ec, 0x94ed, 0x94ee, 0x94ef, 0x94f0, 0x94f1,
+ 0x94f2, 0x94f3, 0x94f4, 0x94f5, 0x94f6, 0x94f7, 0x94f8, 0x94f9,
+ 0x94fa, 0x94fb, 0x94fc, 0x9540, 0x9541, 0x9542, 0x9543, 0x9544,
+ 0x9545, 0x9546, 0x9547, 0x9548, 0x9549, 0x954a, 0x954b, 0x954c,
+ 0x954d, 0x954e, 0x954f, 0x9550, 0x9551, 0x9552, 0x9553, 0x9554,
+ 0x9555, 0x9556, 0x9557, 0x9558, 0x9559, 0x955a, 0x955b, 0x955c,
+ 0x955d, 0x955e, 0x955f, 0x9560, 0x9561, 0x9562, 0x9563, 0x9564,
+ 0x9565, 0x9566, 0x9567, 0x9568, 0x9569, 0x956a, 0x956b, 0x956c,
+ 0x956d, 0x956e, 0x956f, 0x9570, 0x9571, 0x9572, 0x9573, 0x9574,
+ 0x9575, 0x9576, 0x9577, 0x9578, 0x9579, 0x957a, 0x957b, 0x957c,
+ 0x957d, 0x957e, 0x9580, 0x9581, 0x9582, 0x9583, 0x9584, 0x9585,
+ 0x9586, 0x9587, 0x9588, 0x9589, 0x958a, 0x958b, 0x958c, 0x958d,
+ 0x958e, 0x958f, 0x9590, 0x9591, 0x9592, 0x9593, 0x9594, 0x9595,
+ 0x9596, 0x9597, 0x9598, 0x9599, 0x959a, 0x959b, 0x959c, 0x959d,
+ 0x959e, 0x959f, 0x95a0, 0x95a1, 0x95a2, 0x95a3, 0x95a4, 0x95a5,
+ 0x95a6, 0x95a7, 0x95a8, 0x95a9, 0x95aa, 0x95ab, 0x95ac, 0x95ad,
+ 0x95ae, 0x95af, 0x95b0, 0x95b1, 0x95b2, 0x95b3, 0x95b4, 0x95b5,
+ 0x95b6, 0x95b7, 0x95b8, 0x95b9, 0x95ba, 0x95bb, 0x95bc, 0x95bd,
+ 0x95be, 0x95bf, 0x95c0, 0x95c1, 0x95c2, 0x95c3, 0x95c4, 0x95c5,
+ 0x95c6, 0x95c7, 0x95c8, 0x95c9, 0x95ca, 0x95cb, 0x95cc, 0x95cd,
+ 0x95ce, 0x95cf, 0x95d0, 0x95d1, 0x95d2, 0x95d3, 0x95d4, 0x95d5,
+ 0x95d6, 0x95d7, 0x95d8, 0x95d9, 0x95da, 0x95db, 0x95dc, 0x95dd,
+ 0x95de, 0x95df, 0x95e0, 0x95e1, 0x95e2, 0x95e3, 0x95e4, 0x95e5,
+ 0x95e6, 0x95e7, 0x95e8, 0x95e9, 0x95ea, 0x95eb, 0x95ec, 0x95ed,
+ 0x95ee, 0x95ef, 0x95f0, 0x95f1, 0x95f2, 0x95f3, 0x95f4, 0x95f5,
+ 0x95f6, 0x95f7, 0x95f8, 0x95f9, 0x95fa, 0x95fb, 0x95fc, 0x9640,
+ 0x9641, 0x9642, 0x9643, 0x9644, 0x9645, 0x9646, 0x9647, 0x9648,
+ 0x9649, 0x964a, 0x964b, 0x964c, 0x964d, 0x964e, 0x964f, 0x9650,
+ 0x9651, 0x9652, 0x9653, 0x9654, 0x9655, 0x9656, 0x9657, 0x9658,
+ 0x9659, 0x965a, 0x965b, 0x965c, 0x965d, 0x965e, 0x965f, 0x9660,
+ 0x9661, 0x9662, 0x9663, 0x9664, 0x9665, 0x9666, 0x9667, 0x9668,
+ 0x9669, 0x966a, 0x966b, 0x966c, 0x966d, 0x966e, 0x966f, 0x9670,
+ 0x9671, 0x9672, 0x9673, 0x9674, 0x9675, 0x9676, 0x9677, 0x9678,
+ 0x9679, 0x967a, 0x967b, 0x967c, 0x967d, 0x967e, 0x9680, 0x9681,
+ 0x9682, 0x9683, 0x9684, 0x9685, 0x9686, 0x9687, 0x9688, 0x9689,
+ 0x968a, 0x968b, 0x968c, 0x968d, 0x968e, 0x968f, 0x9690, 0x9691,
+ 0x9692, 0x9693, 0x9694, 0x9695, 0x9696, 0x9697, 0x9698, 0x9699,
+ 0x969a, 0x969b, 0x969c, 0x969d, 0x969e, 0x969f, 0x96a0, 0x96a1,
+ 0x96a2, 0x96a3, 0x96a4, 0x96a5, 0x96a6, 0x96a7, 0x96a8, 0x96a9,
+ 0x96aa, 0x96ab, 0x96ac, 0x96ad, 0x96ae, 0x96af, 0x96b0, 0x96b1,
+ 0x96b2, 0x96b3, 0x96b4, 0x96b5, 0x96b6, 0x96b7, 0x96b8, 0x96b9,
+ 0x96ba, 0x96bb, 0x96bc, 0x96bd, 0x96be, 0x96bf, 0x96c0, 0x96c1,
+ 0x96c2, 0x96c3, 0x96c4, 0x96c5, 0x96c6, 0x96c7, 0x96c8, 0x96c9,
+ 0x96ca, 0x96cb, 0x96cc, 0x96cd, 0x96ce, 0x96cf, 0x96d0, 0x96d1,
+ 0x96d2, 0x96d3, 0x96d4, 0x96d5, 0x96d6, 0x96d7, 0x96d8, 0x96d9,
+ 0x96da, 0x96db, 0x96dc, 0x96dd, 0x96de, 0x96df, 0x96e0, 0x96e1,
+ 0x96e2, 0x96e3, 0x96e4, 0x96e5, 0x96e6, 0x96e7, 0x96e8, 0x96e9,
+ 0x96ea, 0x96eb, 0x96ec, 0x96ed, 0x96ee, 0x96ef, 0x96f0, 0x96f1,
+ 0x96f2, 0x96f3, 0x96f4, 0x96f5, 0x96f6, 0x96f7, 0x96f8, 0x96f9,
+ 0x96fa, 0x96fb, 0x96fc, 0x9740, 0x9741, 0x9742, 0x9743, 0x9744,
+ 0x9745, 0x9746, 0x9747, 0x9748, 0x9749, 0x974a, 0x974b, 0x974c,
+ 0x974d, 0x974e, 0x974f, 0x9750, 0x9751, 0x9752, 0x9753, 0x9754,
+ 0x9755, 0x9756, 0x9757, 0x9758, 0x9759, 0x975a, 0x975b, 0x975c,
+ 0x975d, 0x975e, 0x975f, 0x9760, 0x9761, 0x9762, 0x9763, 0x9764,
+ 0x9765, 0x9766, 0x9767, 0x9768, 0x9769, 0x976a, 0x976b, 0x976c,
+ 0x976d, 0x976e, 0x976f, 0x9770, 0x9771, 0x9772, 0x9773, 0x9774,
+ 0x9775, 0x9776, 0x9777, 0x9778, 0x9779, 0x977a, 0x977b, 0x977c,
+ 0x977d, 0x977e, 0x9780, 0x9781, 0x9782, 0x9783, 0x9784, 0x9785,
+ 0x9786, 0x9787, 0x9788, 0x9789, 0x978a, 0x978b, 0x978c, 0x978d,
+ 0x978e, 0x978f, 0x9790, 0x9791, 0x9792, 0x9793, 0x9794, 0x9795,
+ 0x9796, 0x9797, 0x9798, 0x9799, 0x979a, 0x979b, 0x979c, 0x979d,
+ 0x979e, 0x979f, 0x97a0, 0x97a1, 0x97a2, 0x97a3, 0x97a4, 0x97a5,
+ 0x97a6, 0x97a7, 0x97a8, 0x97a9, 0x97aa, 0x97ab, 0x97ac, 0x97ad,
+ 0x97ae, 0x97af, 0x97b0, 0x97b1, 0x97b2, 0x97b3, 0x97b4, 0x97b5,
+ 0x97b6, 0x97b7, 0x97b8, 0x97b9, 0x97ba, 0x97bb, 0x97bc, 0x97bd,
+ 0x97be, 0x97bf, 0x97c0, 0x97c1, 0x97c2, 0x97c3, 0x97c4, 0x97c5,
+ 0x97c6, 0x97c7, 0x97c8, 0x97c9, 0x97ca, 0x97cb, 0x97cc, 0x97cd,
+ 0x97ce, 0x97cf, 0x97d0, 0x97d1, 0x97d2, 0x97d3, 0x97d4, 0x97d5,
+ 0x97d6, 0x97d7, 0x97d8, 0x97d9, 0x97da, 0x97db, 0x97dc, 0x97dd,
+ 0x97de, 0x97df, 0x97e0, 0x97e1, 0x97e2, 0x97e3, 0x97e4, 0x97e5,
+ 0x97e6, 0x97e7, 0x97e8, 0x97e9, 0x97ea, 0x97eb, 0x97ec, 0x97ed,
+ 0x97ee, 0x97ef, 0x97f0, 0x97f1, 0x97f2, 0x97f3, 0x97f4, 0x97f5,
+ 0x97f6, 0x97f7, 0x97f8, 0x97f9, 0x97fa, 0x97fb, 0x97fc, 0x9840,
+ 0x9841, 0x9842, 0x9843, 0x9844, 0x9845, 0x9846, 0x9847, 0x9848,
+ 0x9849, 0x984a, 0x984b, 0x984c, 0x984d, 0x984e, 0x984f, 0x9850,
+ 0x9851, 0x9852, 0x9853, 0x9854, 0x9855, 0x9856, 0x9857, 0x9858,
+ 0x9859, 0x985a, 0x985b, 0x985c, 0x985d, 0x985e, 0x985f, 0x9860,
+ 0x9861, 0x9862, 0x9863, 0x9864, 0x9865, 0x9866, 0x9867, 0x9868,
+ 0x9869, 0x986a, 0x986b, 0x986c, 0x986d, 0x986e, 0x986f, 0x9870,
+ 0x9871, 0x9872, 0x989f, 0x98a0, 0x98a1, 0x98a2, 0x98a3, 0x98a4,
+ 0x98a5, 0x98a6, 0x98a7, 0x98a8, 0x98a9, 0x98aa, 0x98ab, 0x98ac,
+ 0x98ad, 0x98ae, 0x98af, 0x98b0, 0x98b1, 0x98b2, 0x98b3, 0x98b4,
+ 0x98b5, 0x98b6, 0x98b7, 0x98b8, 0x98b9, 0x98ba, 0x98bb, 0x98bc,
+ 0x98bd, 0x98be, 0x98bf, 0x98c0, 0x98c1, 0x98c2, 0x98c3, 0x98c4,
+ 0x98c5, 0x98c6, 0x98c7, 0x98c8, 0x98c9, 0x98ca, 0x98cb, 0x98cc,
+ 0x98cd, 0x98ce, 0x98cf, 0x98d0, 0x98d1, 0x98d2, 0x98d3, 0x98d4,
+ 0x98d5, 0x98d6, 0x98d7, 0x98d8, 0x98d9, 0x98da, 0x98db, 0x98dc,
+ 0x98dd, 0x98de, 0x98df, 0x98e0, 0x98e1, 0x98e2, 0x98e3, 0x98e4,
+ 0x98e5, 0x98e6, 0x98e7, 0x98e8, 0x98e9, 0x98ea, 0x98eb, 0x98ec,
+ 0x98ed, 0x98ee, 0x98ef, 0x98f0, 0x98f1, 0x98f2, 0x98f3, 0x98f4,
+ 0x98f5, 0x98f6, 0x98f7, 0x98f8, 0x98f9, 0x98fa, 0x98fb, 0x98fc,
+ 0x9940, 0x9941, 0x9942, 0x9943, 0x9944, 0x9945, 0x9946, 0x9947,
+ 0x9948, 0x9949, 0x994a, 0x994b, 0x994c, 0x994d, 0x994e, 0x994f,
+ 0x9950, 0x9951, 0x9952, 0x9953, 0x9954, 0x9955, 0x9956, 0x9957,
+ 0x9958, 0x9959, 0x995a, 0x995b, 0x995c, 0x995d, 0x995e, 0x995f,
+ 0x9960, 0x9961, 0x9962, 0x9963, 0x9964, 0x9965, 0x9966, 0x9967,
+ 0x9968, 0x9969, 0x996a, 0x996b, 0x996c, 0x996d, 0x996e, 0x996f,
+ 0x9970, 0x9971, 0x9972, 0x9973, 0x9974, 0x9975, 0x9976, 0x9977,
+ 0x9978, 0x9979, 0x997a, 0x997b, 0x997c, 0x997d, 0x997e, 0x9980,
+ 0x9981, 0x9982, 0x9983, 0x9984, 0x9985, 0x9986, 0x9987, 0x9988,
+ 0x9989, 0x998a, 0x998b, 0x998c, 0x998d, 0x998e, 0x998f, 0x9990,
+ 0x9991, 0x9992, 0x9993, 0x9994, 0x9995, 0x9996, 0x9997, 0x9998,
+ 0x9999, 0x999a, 0x999b, 0x999c, 0x999d, 0x999e, 0x999f, 0x99a0,
+ 0x99a1, 0x99a2, 0x99a3, 0x99a4, 0x99a5, 0x99a6, 0x99a7, 0x99a8,
+ 0x99a9, 0x99aa, 0x99ab, 0x99ac, 0x99ad, 0x99ae, 0x99af, 0x99b0,
+ 0x99b1, 0x99b2, 0x99b3, 0x99b4, 0x99b5, 0x99b6, 0x99b7, 0x99b8,
+ 0x99b9, 0x99ba, 0x99bb, 0x99bc, 0x99bd, 0x99be, 0x99bf, 0x99c0,
+ 0x99c1, 0x99c2, 0x99c3, 0x99c4, 0x99c5, 0x99c6, 0x99c7, 0x99c8,
+ 0x99c9, 0x99ca, 0x99cb, 0x99cc, 0x99cd, 0x99ce, 0x99cf, 0x99d0,
+ 0x99d1, 0x99d2, 0x99d3, 0x99d4, 0x99d5, 0x99d6, 0x99d7, 0x99d8,
+ 0x99d9, 0x99da, 0x99db, 0x99dc, 0x99dd, 0x99de, 0x99df, 0x99e0,
+ 0x99e1, 0x99e2, 0x99e3, 0x99e4, 0x99e5, 0x99e6, 0x99e7, 0x99e8,
+ 0x99e9, 0x99ea, 0x99eb, 0x99ec, 0x99ed, 0x99ee, 0x99ef, 0x99f0,
+ 0x99f1, 0x99f2, 0x99f3, 0x99f4, 0x99f5, 0x99f6, 0x99f7, 0x99f8,
+ 0x99f9, 0x99fa, 0x99fb, 0x99fc, 0x9a40, 0x9a41, 0x9a42, 0x9a43,
+ 0x9a44, 0x9a45, 0x9a46, 0x9a47, 0x9a48, 0x9a49, 0x9a4a, 0x9a4b,
+ 0x9a4c, 0x9a4d, 0x9a4e, 0x9a4f, 0x9a50, 0x9a51, 0x9a52, 0x9a53,
+ 0x9a54, 0x9a55, 0x9a56, 0x9a57, 0x9a58, 0x9a59, 0x9a5a, 0x9a5b,
+ 0x9a5c, 0x9a5d, 0x9a5e, 0x9a5f, 0x9a60, 0x9a61, 0x9a62, 0x9a63,
+ 0x9a64, 0x9a65, 0x9a66, 0x9a67, 0x9a68, 0x9a69, 0x9a6a, 0x9a6b,
+ 0x9a6c, 0x9a6d, 0x9a6e, 0x9a6f, 0x9a70, 0x9a71, 0x9a72, 0x9a73,
+ 0x9a74, 0x9a75, 0x9a76, 0x9a77, 0x9a78, 0x9a79, 0x9a7a, 0x9a7b,
+ 0x9a7c, 0x9a7d, 0x9a7e, 0x9a80, 0x9a81, 0x9a82, 0x9a83, 0x9a84,
+ 0x9a85, 0x9a86, 0x9a87, 0x9a88, 0x9a89, 0x9a8a, 0x9a8b, 0x9a8c,
+ 0x9a8d, 0x9a8e, 0x9a8f, 0x9a90, 0x9a91, 0x9a92, 0x9a93, 0x9a94,
+ 0x9a95, 0x9a96, 0x9a97, 0x9a98, 0x9a99, 0x9a9a, 0x9a9b, 0x9a9c,
+ 0x9a9d, 0x9a9e, 0x9a9f, 0x9aa0, 0x9aa1, 0x9aa2, 0x9aa3, 0x9aa4,
+ 0x9aa5, 0x9aa6, 0x9aa7, 0x9aa8, 0x9aa9, 0x9aaa, 0x9aab, 0x9aac,
+ 0x9aad, 0x9aae, 0x9aaf, 0x9ab0, 0x9ab1, 0x9ab2, 0x9ab3, 0x9ab4,
+ 0x9ab5, 0x9ab6, 0x9ab7, 0x9ab8, 0x9ab9, 0x9aba, 0x9abb, 0x9abc,
+ 0x9abd, 0x9abe, 0x9abf, 0x9ac0, 0x9ac1, 0x9ac2, 0x9ac3, 0x9ac4,
+ 0x9ac5, 0x9ac6, 0x9ac7, 0x9ac8, 0x9ac9, 0x9aca, 0x9acb, 0x9acc,
+ 0x9acd, 0x9ace, 0x9acf, 0x9ad0, 0x9ad1, 0x9ad2, 0x9ad3, 0x9ad4,
+ 0x9ad5, 0x9ad6, 0x9ad7, 0x9ad8, 0x9ad9, 0x9ada, 0x9adb, 0x9adc,
+ 0x9add, 0x9ade, 0x9adf, 0x9ae0, 0x9ae1, 0x9ae2, 0x9ae3, 0x9ae4,
+ 0x9ae5, 0x9ae6, 0x9ae7, 0x9ae8, 0x9ae9, 0x9aea, 0x9aeb, 0x9aec,
+ 0x9aed, 0x9aee, 0x9aef, 0x9af0, 0x9af1, 0x9af2, 0x9af3, 0x9af4,
+ 0x9af5, 0x9af6, 0x9af7, 0x9af8, 0x9af9, 0x9afa, 0x9afb, 0x9afc,
+ 0x9b40, 0x9b41, 0x9b42, 0x9b43, 0x9b44, 0x9b45, 0x9b46, 0x9b47,
+ 0x9b48, 0x9b49, 0x9b4a, 0x9b4b, 0x9b4c, 0x9b4d, 0x9b4e, 0x9b4f,
+ 0x9b50, 0x9b51, 0x9b52, 0x9b53, 0x9b54, 0x9b55, 0x9b56, 0x9b57,
+ 0x9b58, 0x9b59, 0x9b5a, 0x9b5b, 0x9b5c, 0x9b5d, 0x9b5e, 0x9b5f,
+ 0x9b60, 0x9b61, 0x9b62, 0x9b63, 0x9b64, 0x9b65, 0x9b66, 0x9b67,
+ 0x9b68, 0x9b69, 0x9b6a, 0x9b6b, 0x9b6c, 0x9b6d, 0x9b6e, 0x9b6f,
+ 0x9b70, 0x9b71, 0x9b72, 0x9b73, 0x9b74, 0x9b75, 0x9b76, 0x9b77,
+ 0x9b78, 0x9b79, 0x9b7a, 0x9b7b, 0x9b7c, 0x9b7d, 0x9b7e, 0x9b80,
+ 0x9b81, 0x9b82, 0x9b83, 0x9b84, 0x9b85, 0x9b86, 0x9b87, 0x9b88,
+ 0x9b89, 0x9b8a, 0x9b8b, 0x9b8c, 0x9b8d, 0x9b8e, 0x9b8f, 0x9b90,
+ 0x9b91, 0x9b92, 0x9b93, 0x9b94, 0x9b95, 0x9b96, 0x9b97, 0x9b98,
+ 0x9b99, 0x9b9a, 0x9b9b, 0x9b9c, 0x9b9d, 0x9b9e, 0x9b9f, 0x9ba0,
+ 0x9ba1, 0x9ba2, 0x9ba3, 0x9ba4, 0x9ba5, 0x9ba6, 0x9ba7, 0x9ba8,
+ 0x9ba9, 0x9baa, 0x9bab, 0x9bac, 0x9bad, 0x9bae, 0x9baf, 0x9bb0,
+ 0x9bb1, 0x9bb2, 0x9bb3, 0x9bb4, 0x9bb5, 0x9bb6, 0x9bb7, 0x9bb8,
+ 0x9bb9, 0x9bba, 0x9bbb, 0x9bbc, 0x9bbd, 0x9bbe, 0x9bbf, 0x9bc0,
+ 0x9bc1, 0x9bc2, 0x9bc3, 0x9bc4, 0x9bc5, 0x9bc6, 0x9bc7, 0x9bc8,
+ 0x9bc9, 0x9bca, 0x9bcb, 0x9bcc, 0x9bcd, 0x9bce, 0x9bcf, 0x9bd0,
+ 0x9bd1, 0x9bd2, 0x9bd3, 0x9bd4, 0x9bd5, 0x9bd6, 0x9bd7, 0x9bd8,
+ 0x9bd9, 0x9bda, 0x9bdb, 0x9bdc, 0x9bdd, 0x9bde, 0x9bdf, 0x9be0,
+ 0x9be1, 0x9be2, 0x9be3, 0x9be4, 0x9be5, 0x9be6, 0x9be7, 0x9be8,
+ 0x9be9, 0x9bea, 0x9beb, 0x9bec, 0x9bed, 0x9bee, 0x9bef, 0x9bf0,
+ 0x9bf1, 0x9bf2, 0x9bf3, 0x9bf4, 0x9bf5, 0x9bf6, 0x9bf7, 0x9bf8,
+ 0x9bf9, 0x9bfa, 0x9bfb, 0x9bfc, 0x9c40, 0x9c41, 0x9c42, 0x9c43,
+ 0x9c44, 0x9c45, 0x9c46, 0x9c47, 0x9c48, 0x9c49, 0x9c4a, 0x9c4b,
+ 0x9c4c, 0x9c4d, 0x9c4e, 0x9c4f, 0x9c50, 0x9c51, 0x9c52, 0x9c53,
+ 0x9c54, 0x9c55, 0x9c56, 0x9c57, 0x9c58, 0x9c59, 0x9c5a, 0x9c5b,
+ 0x9c5c, 0x9c5d, 0x9c5e, 0x9c5f, 0x9c60, 0x9c61, 0x9c62, 0x9c63,
+ 0x9c64, 0x9c65, 0x9c66, 0x9c67, 0x9c68, 0x9c69, 0x9c6a, 0x9c6b,
+ 0x9c6c, 0x9c6d, 0x9c6e, 0x9c6f, 0x9c70, 0x9c71, 0x9c72, 0x9c73,
+ 0x9c74, 0x9c75, 0x9c76, 0x9c77, 0x9c78, 0x9c79, 0x9c7a, 0x9c7b,
+ 0x9c7c, 0x9c7d, 0x9c7e, 0x9c80, 0x9c81, 0x9c82, 0x9c83, 0x9c84,
+ 0x9c85, 0x9c86, 0x9c87, 0x9c88, 0x9c89, 0x9c8a, 0x9c8b, 0x9c8c,
+ 0x9c8d, 0x9c8e, 0x9c8f, 0x9c90, 0x9c91, 0x9c92, 0x9c93, 0x9c94,
+ 0x9c95, 0x9c96, 0x9c97, 0x9c98, 0x9c99, 0x9c9a, 0x9c9b, 0x9c9c,
+ 0x9c9d, 0x9c9e, 0x9c9f, 0x9ca0, 0x9ca1, 0x9ca2, 0x9ca3, 0x9ca4,
+ 0x9ca5, 0x9ca6, 0x9ca7, 0x9ca8, 0x9ca9, 0x9caa, 0x9cab, 0x9cac,
+ 0x9cad, 0x9cae, 0x9caf, 0x9cb0, 0x9cb1, 0x9cb2, 0x9cb3, 0x9cb4,
+ 0x9cb5, 0x9cb6, 0x9cb7, 0x9cb8, 0x9cb9, 0x9cba, 0x9cbb, 0x9cbc,
+ 0x9cbd, 0x9cbe, 0x9cbf, 0x9cc0, 0x9cc1, 0x9cc2, 0x9cc3, 0x9cc4,
+ 0x9cc5, 0x9cc6, 0x9cc7, 0x9cc8, 0x9cc9, 0x9cca, 0x9ccb, 0x9ccc,
+ 0x9ccd, 0x9cce, 0x9ccf, 0x9cd0, 0x9cd1, 0x9cd2, 0x9cd3, 0x9cd4,
+ 0x9cd5, 0x9cd6, 0x9cd7, 0x9cd8, 0x9cd9, 0x9cda, 0x9cdb, 0x9cdc,
+ 0x9cdd, 0x9cde, 0x9cdf, 0x9ce0, 0x9ce1, 0x9ce2, 0x9ce3, 0x9ce4,
+ 0x9ce5, 0x9ce6, 0x9ce7, 0x9ce8, 0x9ce9, 0x9cea, 0x9ceb, 0x9cec,
+ 0x9ced, 0x9cee, 0x9cef, 0x9cf0, 0x9cf1, 0x9cf2, 0x9cf3, 0x9cf4,
+ 0x9cf5, 0x9cf6, 0x9cf7, 0x9cf8, 0x9cf9, 0x9cfa, 0x9cfb, 0x9cfc,
+ 0x9d40, 0x9d41, 0x9d42, 0x9d43, 0x9d44, 0x9d45, 0x9d46, 0x9d47,
+ 0x9d48, 0x9d49, 0x9d4a, 0x9d4b, 0x9d4c, 0x9d4d, 0x9d4e, 0x9d4f,
+ 0x9d50, 0x9d51, 0x9d52, 0x9d53, 0x9d54, 0x9d55, 0x9d56, 0x9d57,
+ 0x9d58, 0x9d59, 0x9d5a, 0x9d5b, 0x9d5c, 0x9d5d, 0x9d5e, 0x9d5f,
+ 0x9d60, 0x9d61, 0x9d62, 0x9d63, 0x9d64, 0x9d65, 0x9d66, 0x9d67,
+ 0x9d68, 0x9d69, 0x9d6a, 0x9d6b, 0x9d6c, 0x9d6d, 0x9d6e, 0x9d6f,
+ 0x9d70, 0x9d71, 0x9d72, 0x9d73, 0x9d74, 0x9d75, 0x9d76, 0x9d77,
+ 0x9d78, 0x9d79, 0x9d7a, 0x9d7b, 0x9d7c, 0x9d7d, 0x9d7e, 0x9d80,
+ 0x9d81, 0x9d82, 0x9d83, 0x9d84, 0x9d85, 0x9d86, 0x9d87, 0x9d88,
+ 0x9d89, 0x9d8a, 0x9d8b, 0x9d8c, 0x9d8d, 0x9d8e, 0x9d8f, 0x9d90,
+ 0x9d91, 0x9d92, 0x9d93, 0x9d94, 0x9d95, 0x9d96, 0x9d97, 0x9d98,
+ 0x9d99, 0x9d9a, 0x9d9b, 0x9d9c, 0x9d9d, 0x9d9e, 0x9d9f, 0x9da0,
+ 0x9da1, 0x9da2, 0x9da3, 0x9da4, 0x9da5, 0x9da6, 0x9da7, 0x9da8,
+ 0x9da9, 0x9daa, 0x9dab, 0x9dac, 0x9dad, 0x9dae, 0x9daf, 0x9db0,
+ 0x9db1, 0x9db2, 0x9db3, 0x9db4, 0x9db5, 0x9db6, 0x9db7, 0x9db8,
+ 0x9db9, 0x9dba, 0x9dbb, 0x9dbc, 0x9dbd, 0x9dbe, 0x9dbf, 0x9dc0,
+ 0x9dc1, 0x9dc2, 0x9dc3, 0x9dc4, 0x9dc5, 0x9dc6, 0x9dc7, 0x9dc8,
+ 0x9dc9, 0x9dca, 0x9dcb, 0x9dcc, 0x9dcd, 0x9dce, 0x9dcf, 0x9dd0,
+ 0x9dd1, 0x9dd2, 0x9dd3, 0x9dd4, 0x9dd5, 0x9dd6, 0x9dd7, 0x9dd8,
+ 0x9dd9, 0x9dda, 0x9ddb, 0x9ddc, 0x9ddd, 0x9dde, 0x9ddf, 0x9de0,
+ 0x9de1, 0x9de2, 0x9de3, 0x9de4, 0x9de5, 0x9de6, 0x9de7, 0x9de8,
+ 0x9de9, 0x9dea, 0x9deb, 0x9dec, 0x9ded, 0x9dee, 0x9def, 0x9df0,
+ 0x9df1, 0x9df2, 0x9df3, 0x9df4, 0x9df5, 0x9df6, 0x9df7, 0x9df8,
+ 0x9df9, 0x9dfa, 0x9dfb, 0x9dfc, 0x9e40, 0x9e41, 0x9e42, 0x9e43,
+ 0x9e44, 0x9e45, 0x9e46, 0x9e47, 0x9e48, 0x9e49, 0x9e4a, 0x9e4b,
+ 0x9e4c, 0x9e4d, 0x9e4e, 0x9e4f, 0x9e50, 0x9e51, 0x9e52, 0x9e53,
+ 0x9e54, 0x9e55, 0x9e56, 0x9e57, 0x9e58, 0x9e59, 0x9e5a, 0x9e5b,
+ 0x9e5c, 0x9e5d, 0x9e5e, 0x9e5f, 0x9e60, 0x9e61, 0x9e62, 0x9e63,
+ 0x9e64, 0x9e65, 0x9e66, 0x9e67, 0x9e68, 0x9e69, 0x9e6a, 0x9e6b,
+ 0x9e6c, 0x9e6d, 0x9e6e, 0x9e6f, 0x9e70, 0x9e71, 0x9e72, 0x9e73,
+ 0x9e74, 0x9e75, 0x9e76, 0x9e77, 0x9e78, 0x9e79, 0x9e7a, 0x9e7b,
+ 0x9e7c, 0x9e7d, 0x9e7e, 0x9e80, 0x9e81, 0x9e82, 0x9e83, 0x9e84,
+ 0x9e85, 0x9e86, 0x9e87, 0x9e88, 0x9e89, 0x9e8a, 0x9e8b, 0x9e8c,
+ 0x9e8d, 0x9e8e, 0x9e8f, 0x9e90, 0x9e91, 0x9e92, 0x9e93, 0x9e94,
+ 0x9e95, 0x9e96, 0x9e97, 0x9e98, 0x9e99, 0x9e9a, 0x9e9b, 0x9e9c,
+ 0x9e9d, 0x9e9e, 0x9e9f, 0x9ea0, 0x9ea1, 0x9ea2, 0x9ea3, 0x9ea4,
+ 0x9ea5, 0x9ea6, 0x9ea7, 0x9ea8, 0x9ea9, 0x9eaa, 0x9eab, 0x9eac,
+ 0x9ead, 0x9eae, 0x9eaf, 0x9eb0, 0x9eb1, 0x9eb2, 0x9eb3, 0x9eb4,
+ 0x9eb5, 0x9eb6, 0x9eb7, 0x9eb8, 0x9eb9, 0x9eba, 0x9ebb, 0x9ebc,
+ 0x9ebd, 0x9ebe, 0x9ebf, 0x9ec0, 0x9ec1, 0x9ec2, 0x9ec3, 0x9ec4,
+ 0x9ec5, 0x9ec6, 0x9ec7, 0x9ec8, 0x9ec9, 0x9eca, 0x9ecb, 0x9ecc,
+ 0x9ecd, 0x9ece, 0x9ecf, 0x9ed0, 0x9ed1, 0x9ed2, 0x9ed3, 0x9ed4,
+ 0x9ed5, 0x9ed6, 0x9ed7, 0x9ed8, 0x9ed9, 0x9eda, 0x9edb, 0x9edc,
+ 0x9edd, 0x9ede, 0x9edf, 0x9ee0, 0x9ee1, 0x9ee2, 0x9ee3, 0x9ee4,
+ 0x9ee5, 0x9ee6, 0x9ee7, 0x9ee8, 0x9ee9, 0x9eea, 0x9eeb, 0x9eec,
+ 0x9eed, 0x9eee, 0x9eef, 0x9ef0, 0x9ef1, 0x9ef2, 0x9ef3, 0x9ef4,
+ 0x9ef5, 0x9ef6, 0x9ef7, 0x9ef8, 0x9ef9, 0x9efa, 0x9efb, 0x9efc,
+ 0x9f40, 0x9f41, 0x9f42, 0x9f43, 0x9f44, 0x9f45, 0x9f46, 0x9f47,
+ 0x9f48, 0x9f49, 0x9f4a, 0x9f4b, 0x9f4c, 0x9f4d, 0x9f4e, 0x9f4f,
+ 0x9f50, 0x9f51, 0x9f52, 0x9f53, 0x9f54, 0x9f55, 0x9f56, 0x9f57,
+ 0x9f58, 0x9f59, 0x9f5a, 0x9f5b, 0x9f5c, 0x9f5d, 0x9f5e, 0x9f5f,
+ 0x9f60, 0x9f61, 0x9f62, 0x9f63, 0x9f64, 0x9f65, 0x9f66, 0x9f67,
+ 0x9f68, 0x9f69, 0x9f6a, 0x9f6b, 0x9f6c, 0x9f6d, 0x9f6e, 0x9f6f,
+ 0x9f70, 0x9f71, 0x9f72, 0x9f73, 0x9f74, 0x9f75, 0x9f76, 0x9f77,
+ 0x9f78, 0x9f79, 0x9f7a, 0x9f7b, 0x9f7c, 0x9f7d, 0x9f7e, 0x9f80,
+ 0x9f81, 0x9f82, 0x9f83, 0x9f84, 0x9f85, 0x9f86, 0x9f87, 0x9f88,
+ 0x9f89, 0x9f8a, 0x9f8b, 0x9f8c, 0x9f8d, 0x9f8e, 0x9f8f, 0x9f90,
+ 0x9f91, 0x9f92, 0x9f93, 0x9f94, 0x9f95, 0x9f96, 0x9f97, 0x9f98,
+ 0x9f99, 0x9f9a, 0x9f9b, 0x9f9c, 0x9f9d, 0x9f9e, 0x9f9f, 0x9fa0,
+ 0x9fa1, 0x9fa2, 0x9fa3, 0x9fa4, 0x9fa5, 0x9fa6, 0x9fa7, 0x9fa8,
+ 0x9fa9, 0x9faa, 0x9fab, 0x9fac, 0x9fad, 0x9fae, 0x9faf, 0x9fb0,
+ 0x9fb1, 0x9fb2, 0x9fb3, 0x9fb4, 0x9fb5, 0x9fb6, 0x9fb7, 0x9fb8,
+ 0x9fb9, 0x9fba, 0x9fbb, 0x9fbc, 0x9fbd, 0x9fbe, 0x9fbf, 0x9fc0,
+ 0x9fc1, 0x9fc2, 0x9fc3, 0x9fc4, 0x9fc5, 0x9fc6, 0x9fc7, 0x9fc8,
+ 0x9fc9, 0x9fca, 0x9fcb, 0x9fcc, 0x9fcd, 0x9fce, 0x9fcf, 0x9fd0,
+ 0x9fd1, 0x9fd2, 0x9fd3, 0x9fd4, 0x9fd5, 0x9fd6, 0x9fd7, 0x9fd8,
+ 0x9fd9, 0x9fda, 0x9fdb, 0x9fdc, 0x9fdd, 0x9fde, 0x9fdf, 0x9fe0,
+ 0x9fe1, 0x9fe2, 0x9fe3, 0x9fe4, 0x9fe5, 0x9fe6, 0x9fe7, 0x9fe8,
+ 0x9fe9, 0x9fea, 0x9feb, 0x9fec, 0x9fed, 0x9fee, 0x9fef, 0x9ff0,
+ 0x9ff1, 0x9ff2, 0x9ff3, 0x9ff4, 0x9ff5, 0x9ff6, 0x9ff7, 0x9ff8,
+ 0x9ff9, 0x9ffa, 0x9ffb, 0x9ffc, 0xe040, 0xe041, 0xe042, 0xe043,
+ 0xe044, 0xe045, 0xe046, 0xe047, 0xe048, 0xe049, 0xe04a, 0xe04b,
+ 0xe04c, 0xe04d, 0xe04e, 0xe04f, 0xe050, 0xe051, 0xe052, 0xe053,
+ 0xe054, 0xe055, 0xe056, 0xe057, 0xe058, 0xe059, 0xe05a, 0xe05b,
+ 0xe05c, 0xe05d, 0xe05e, 0xe05f, 0xe060, 0xe061, 0xe062, 0xe063,
+ 0xe064, 0xe065, 0xe066, 0xe067, 0xe068, 0xe069, 0xe06a, 0xe06b,
+ 0xe06c, 0xe06d, 0xe06e, 0xe06f, 0xe070, 0xe071, 0xe072, 0xe073,
+ 0xe074, 0xe075, 0xe076, 0xe077, 0xe078, 0xe079, 0xe07a, 0xe07b,
+ 0xe07c, 0xe07d, 0xe07e, 0xe080, 0xe081, 0xe082, 0xe083, 0xe084,
+ 0xe085, 0xe086, 0xe087, 0xe088, 0xe089, 0xe08a, 0xe08b, 0xe08c,
+ 0xe08d, 0xe08e, 0xe08f, 0xe090, 0xe091, 0xe092, 0xe093, 0xe094,
+ 0xe095, 0xe096, 0xe097, 0xe098, 0xe099, 0xe09a, 0xe09b, 0xe09c,
+ 0xe09d, 0xe09e, 0xe09f, 0xe0a0, 0xe0a1, 0xe0a2, 0xe0a3, 0xe0a4,
+ 0xe0a5, 0xe0a6, 0xe0a7, 0xe0a8, 0xe0a9, 0xe0aa, 0xe0ab, 0xe0ac,
+ 0xe0ad, 0xe0ae, 0xe0af, 0xe0b0, 0xe0b1, 0xe0b2, 0xe0b3, 0xe0b4,
+ 0xe0b5, 0xe0b6, 0xe0b7, 0xe0b8, 0xe0b9, 0xe0ba, 0xe0bb, 0xe0bc,
+ 0xe0bd, 0xe0be, 0xe0bf, 0xe0c0, 0xe0c1, 0xe0c2, 0xe0c3, 0xe0c4,
+ 0xe0c5, 0xe0c6, 0xe0c7, 0xe0c8, 0xe0c9, 0xe0ca, 0xe0cb, 0xe0cc,
+ 0xe0cd, 0xe0ce, 0xe0cf, 0xe0d0, 0xe0d1, 0xe0d2, 0xe0d3, 0xe0d4,
+ 0xe0d5, 0xe0d6, 0xe0d7, 0xe0d8, 0xe0d9, 0xe0da, 0xe0db, 0xe0dc,
+ 0xe0dd, 0xe0de, 0xe0df, 0xe0e0, 0xe0e1, 0xe0e2, 0xe0e3, 0xe0e4,
+ 0xe0e5, 0xe0e6, 0xe0e7, 0xe0e8, 0xe0e9, 0xe0ea, 0xe0eb, 0xe0ec,
+ 0xe0ed, 0xe0ee, 0xe0ef, 0xe0f0, 0xe0f1, 0xe0f2, 0xe0f3, 0xe0f4,
+ 0xe0f5, 0xe0f6, 0xe0f7, 0xe0f8, 0xe0f9, 0xe0fa, 0xe0fb, 0xe0fc,
+ 0xe140, 0xe141, 0xe142, 0xe143, 0xe144, 0xe145, 0xe146, 0xe147,
+ 0xe148, 0xe149, 0xe14a, 0xe14b, 0xe14c, 0xe14d, 0xe14e, 0xe14f,
+ 0xe150, 0xe151, 0xe152, 0xe153, 0xe154, 0xe155, 0xe156, 0xe157,
+ 0xe158, 0xe159, 0xe15a, 0xe15b, 0xe15c, 0xe15d, 0xe15e, 0xe15f,
+ 0xe160, 0xe161, 0xe162, 0xe163, 0xe164, 0xe165, 0xe166, 0xe167,
+ 0xe168, 0xe169, 0xe16a, 0xe16b, 0xe16c, 0xe16d, 0xe16e, 0xe16f,
+ 0xe170, 0xe171, 0xe172, 0xe173, 0xe174, 0xe175, 0xe176, 0xe177,
+ 0xe178, 0xe179, 0xe17a, 0xe17b, 0xe17c, 0xe17d, 0xe17e, 0xe180,
+ 0xe181, 0xe182, 0xe183, 0xe184, 0xe185, 0xe186, 0xe187, 0xe188,
+ 0xe189, 0xe18a, 0xe18b, 0xe18c, 0xe18d, 0xe18e, 0xe18f, 0xe190,
+ 0xe191, 0xe192, 0xe193, 0xe194, 0xe195, 0xe196, 0xe197, 0xe198,
+ 0xe199, 0xe19a, 0xe19b, 0xe19c, 0xe19d, 0xe19e, 0xe19f, 0xe1a0,
+ 0xe1a1, 0xe1a2, 0xe1a3, 0xe1a4, 0xe1a5, 0xe1a6, 0xe1a7, 0xe1a8,
+ 0xe1a9, 0xe1aa, 0xe1ab, 0xe1ac, 0xe1ad, 0xe1ae, 0xe1af, 0xe1b0,
+ 0xe1b1, 0xe1b2, 0xe1b3, 0xe1b4, 0xe1b5, 0xe1b6, 0xe1b7, 0xe1b8,
+ 0xe1b9, 0xe1ba, 0xe1bb, 0xe1bc, 0xe1bd, 0xe1be, 0xe1bf, 0xe1c0,
+ 0xe1c1, 0xe1c2, 0xe1c3, 0xe1c4, 0xe1c5, 0xe1c6, 0xe1c7, 0xe1c8,
+ 0xe1c9, 0xe1ca, 0xe1cb, 0xe1cc, 0xe1cd, 0xe1ce, 0xe1cf, 0xe1d0,
+ 0xe1d1, 0xe1d2, 0xe1d3, 0xe1d4, 0xe1d5, 0xe1d6, 0xe1d7, 0xe1d8,
+ 0xe1d9, 0xe1da, 0xe1db, 0xe1dc, 0xe1dd, 0xe1de, 0xe1df, 0xe1e0,
+ 0xe1e1, 0xe1e2, 0xe1e3, 0xe1e4, 0xe1e5, 0xe1e6, 0xe1e7, 0xe1e8,
+ 0xe1e9, 0xe1ea, 0xe1eb, 0xe1ec, 0xe1ed, 0xe1ee, 0xe1ef, 0xe1f0,
+ 0xe1f1, 0xe1f2, 0xe1f3, 0xe1f4, 0xe1f5, 0xe1f6, 0xe1f7, 0xe1f8,
+ 0xe1f9, 0xe1fa, 0xe1fb, 0xe1fc, 0xe240, 0xe241, 0xe242, 0xe243,
+ 0xe244, 0xe245, 0xe246, 0xe247, 0xe248, 0xe249, 0xe24a, 0xe24b,
+ 0xe24c, 0xe24d, 0xe24e, 0xe24f, 0xe250, 0xe251, 0xe252, 0xe253,
+ 0xe254, 0xe255, 0xe256, 0xe257, 0xe258, 0xe259, 0xe25a, 0xe25b,
+ 0xe25c, 0xe25d, 0xe25e, 0xe25f, 0xe260, 0xe261, 0xe262, 0xe263,
+ 0xe264, 0xe265, 0xe266, 0xe267, 0xe268, 0xe269, 0xe26a, 0xe26b,
+ 0xe26c, 0xe26d, 0xe26e, 0xe26f, 0xe270, 0xe271, 0xe272, 0xe273,
+ 0xe274, 0xe275, 0xe276, 0xe277, 0xe278, 0xe279, 0xe27a, 0xe27b,
+ 0xe27c, 0xe27d, 0xe27e, 0xe280, 0xe281, 0xe282, 0xe283, 0xe284,
+ 0xe285, 0xe286, 0xe287, 0xe288, 0xe289, 0xe28a, 0xe28b, 0xe28c,
+ 0xe28d, 0xe28e, 0xe28f, 0xe290, 0xe291, 0xe292, 0xe293, 0xe294,
+ 0xe295, 0xe296, 0xe297, 0xe298, 0xe299, 0xe29a, 0xe29b, 0xe29c,
+ 0xe29d, 0xe29e, 0xe29f, 0xe2a0, 0xe2a1, 0xe2a2, 0xe2a3, 0xe2a4,
+ 0xe2a5, 0xe2a6, 0xe2a7, 0xe2a8, 0xe2a9, 0xe2aa, 0xe2ab, 0xe2ac,
+ 0xe2ad, 0xe2ae, 0xe2af, 0xe2b0, 0xe2b1, 0xe2b2, 0xe2b3, 0xe2b4,
+ 0xe2b5, 0xe2b6, 0xe2b7, 0xe2b8, 0xe2b9, 0xe2ba, 0xe2bb, 0xe2bc,
+ 0xe2bd, 0xe2be, 0xe2bf, 0xe2c0, 0xe2c1, 0xe2c2, 0xe2c3, 0xe2c4,
+ 0xe2c5, 0xe2c6, 0xe2c7, 0xe2c8, 0xe2c9, 0xe2ca, 0xe2cb, 0xe2cc,
+ 0xe2cd, 0xe2ce, 0xe2cf, 0xe2d0, 0xe2d1, 0xe2d2, 0xe2d3, 0xe2d4,
+ 0xe2d5, 0xe2d6, 0xe2d7, 0xe2d8, 0xe2d9, 0xe2da, 0xe2db, 0xe2dc,
+ 0xe2dd, 0xe2de, 0xe2df, 0xe2e0, 0xe2e1, 0xe2e2, 0xe2e3, 0xe2e4,
+ 0xe2e5, 0xe2e6, 0xe2e7, 0xe2e8, 0xe2e9, 0xe2ea, 0xe2eb, 0xe2ec,
+ 0xe2ed, 0xe2ee, 0xe2ef, 0xe2f0, 0xe2f1, 0xe2f2, 0xe2f3, 0xe2f4,
+ 0xe2f5, 0xe2f6, 0xe2f7, 0xe2f8, 0xe2f9, 0xe2fa, 0xe2fb, 0xe2fc,
+ 0xe340, 0xe341, 0xe342, 0xe343, 0xe344, 0xe345, 0xe346, 0xe347,
+ 0xe348, 0xe349, 0xe34a, 0xe34b, 0xe34c, 0xe34d, 0xe34e, 0xe34f,
+ 0xe350, 0xe351, 0xe352, 0xe353, 0xe354, 0xe355, 0xe356, 0xe357,
+ 0xe358, 0xe359, 0xe35a, 0xe35b, 0xe35c, 0xe35d, 0xe35e, 0xe35f,
+ 0xe360, 0xe361, 0xe362, 0xe363, 0xe364, 0xe365, 0xe366, 0xe367,
+ 0xe368, 0xe369, 0xe36a, 0xe36b, 0xe36c, 0xe36d, 0xe36e, 0xe36f,
+ 0xe370, 0xe371, 0xe372, 0xe373, 0xe374, 0xe375, 0xe376, 0xe377,
+ 0xe378, 0xe379, 0xe37a, 0xe37b, 0xe37c, 0xe37d, 0xe37e, 0xe380,
+ 0xe381, 0xe382, 0xe383, 0xe384, 0xe385, 0xe386, 0xe387, 0xe388,
+ 0xe389, 0xe38a, 0xe38b, 0xe38c, 0xe38d, 0xe38e, 0xe38f, 0xe390,
+ 0xe391, 0xe392, 0xe393, 0xe394, 0xe395, 0xe396, 0xe397, 0xe398,
+ 0xe399, 0xe39a, 0xe39b, 0xe39c, 0xe39d, 0xe39e, 0xe39f, 0xe3a0,
+ 0xe3a1, 0xe3a2, 0xe3a3, 0xe3a4, 0xe3a5, 0xe3a6, 0xe3a7, 0xe3a8,
+ 0xe3a9, 0xe3aa, 0xe3ab, 0xe3ac, 0xe3ad, 0xe3ae, 0xe3af, 0xe3b0,
+ 0xe3b1, 0xe3b2, 0xe3b3, 0xe3b4, 0xe3b5, 0xe3b6, 0xe3b7, 0xe3b8,
+ 0xe3b9, 0xe3ba, 0xe3bb, 0xe3bc, 0xe3bd, 0xe3be, 0xe3bf, 0xe3c0,
+ 0xe3c1, 0xe3c2, 0xe3c3, 0xe3c4, 0xe3c5, 0xe3c6, 0xe3c7, 0xe3c8,
+ 0xe3c9, 0xe3ca, 0xe3cb, 0xe3cc, 0xe3cd, 0xe3ce, 0xe3cf, 0xe3d0,
+ 0xe3d1, 0xe3d2, 0xe3d3, 0xe3d4, 0xe3d5, 0xe3d6, 0xe3d7, 0xe3d8,
+ 0xe3d9, 0xe3da, 0xe3db, 0xe3dc, 0xe3dd, 0xe3de, 0xe3df, 0xe3e0,
+ 0xe3e1, 0xe3e2, 0xe3e3, 0xe3e4, 0xe3e5, 0xe3e6, 0xe3e7, 0xe3e8,
+ 0xe3e9, 0xe3ea, 0xe3eb, 0xe3ec, 0xe3ed, 0xe3ee, 0xe3ef, 0xe3f0,
+ 0xe3f1, 0xe3f2, 0xe3f3, 0xe3f4, 0xe3f5, 0xe3f6, 0xe3f7, 0xe3f8,
+ 0xe3f9, 0xe3fa, 0xe3fb, 0xe3fc, 0xe440, 0xe441, 0xe442, 0xe443,
+ 0xe444, 0xe445, 0xe446, 0xe447, 0xe448, 0xe449, 0xe44a, 0xe44b,
+ 0xe44c, 0xe44d, 0xe44e, 0xe44f, 0xe450, 0xe451, 0xe452, 0xe453,
+ 0xe454, 0xe455, 0xe456, 0xe457, 0xe458, 0xe459, 0xe45a, 0xe45b,
+ 0xe45c, 0xe45d, 0xe45e, 0xe45f, 0xe460, 0xe461, 0xe462, 0xe463,
+ 0xe464, 0xe465, 0xe466, 0xe467, 0xe468, 0xe469, 0xe46a, 0xe46b,
+ 0xe46c, 0xe46d, 0xe46e, 0xe46f, 0xe470, 0xe471, 0xe472, 0xe473,
+ 0xe474, 0xe475, 0xe476, 0xe477, 0xe478, 0xe479, 0xe47a, 0xe47b,
+ 0xe47c, 0xe47d, 0xe47e, 0xe480, 0xe481, 0xe482, 0xe483, 0xe484,
+ 0xe485, 0xe486, 0xe487, 0xe488, 0xe489, 0xe48a, 0xe48b, 0xe48c,
+ 0xe48d, 0xe48e, 0xe48f, 0xe490, 0xe491, 0xe492, 0xe493, 0xe494,
+ 0xe495, 0xe496, 0xe497, 0xe498, 0xe499, 0xe49a, 0xe49b, 0xe49c,
+ 0xe49d, 0xe49e, 0xe49f, 0xe4a0, 0xe4a1, 0xe4a2, 0xe4a3, 0xe4a4,
+ 0xe4a5, 0xe4a6, 0xe4a7, 0xe4a8, 0xe4a9, 0xe4aa, 0xe4ab, 0xe4ac,
+ 0xe4ad, 0xe4ae, 0xe4af, 0xe4b0, 0xe4b1, 0xe4b2, 0xe4b3, 0xe4b4,
+ 0xe4b5, 0xe4b6, 0xe4b7, 0xe4b8, 0xe4b9, 0xe4ba, 0xe4bb, 0xe4bc,
+ 0xe4bd, 0xe4be, 0xe4bf, 0xe4c0, 0xe4c1, 0xe4c2, 0xe4c3, 0xe4c4,
+ 0xe4c5, 0xe4c6, 0xe4c7, 0xe4c8, 0xe4c9, 0xe4ca, 0xe4cb, 0xe4cc,
+ 0xe4cd, 0xe4ce, 0xe4cf, 0xe4d0, 0xe4d1, 0xe4d2, 0xe4d3, 0xe4d4,
+ 0xe4d5, 0xe4d6, 0xe4d7, 0xe4d8, 0xe4d9, 0xe4da, 0xe4db, 0xe4dc,
+ 0xe4dd, 0xe4de, 0xe4df, 0xe4e0, 0xe4e1, 0xe4e2, 0xe4e3, 0xe4e4,
+ 0xe4e5, 0xe4e6, 0xe4e7, 0xe4e8, 0xe4e9, 0xe4ea, 0xe4eb, 0xe4ec,
+ 0xe4ed, 0xe4ee, 0xe4ef, 0xe4f0, 0xe4f1, 0xe4f2, 0xe4f3, 0xe4f4,
+ 0xe4f5, 0xe4f6, 0xe4f7, 0xe4f8, 0xe4f9, 0xe4fa, 0xe4fb, 0xe4fc,
+ 0xe540, 0xe541, 0xe542, 0xe543, 0xe544, 0xe545, 0xe546, 0xe547,
+ 0xe548, 0xe549, 0xe54a, 0xe54b, 0xe54c, 0xe54d, 0xe54e, 0xe54f,
+ 0xe550, 0xe551, 0xe552, 0xe553, 0xe554, 0xe555, 0xe556, 0xe557,
+ 0xe558, 0xe559, 0xe55a, 0xe55b, 0xe55c, 0xe55d, 0xe55e, 0xe55f,
+ 0xe560, 0xe561, 0xe562, 0xe563, 0xe564, 0xe565, 0xe566, 0xe567,
+ 0xe568, 0xe569, 0xe56a, 0xe56b, 0xe56c, 0xe56d, 0xe56e, 0xe56f,
+ 0xe570, 0xe571, 0xe572, 0xe573, 0xe574, 0xe575, 0xe576, 0xe577,
+ 0xe578, 0xe579, 0xe57a, 0xe57b, 0xe57c, 0xe57d, 0xe57e, 0xe580,
+ 0xe581, 0xe582, 0xe583, 0xe584, 0xe585, 0xe586, 0xe587, 0xe588,
+ 0xe589, 0xe58a, 0xe58b, 0xe58c, 0xe58d, 0xe58e, 0xe58f, 0xe590,
+ 0xe591, 0xe592, 0xe593, 0xe594, 0xe595, 0xe596, 0xe597, 0xe598,
+ 0xe599, 0xe59a, 0xe59b, 0xe59c, 0xe59d, 0xe59e, 0xe59f, 0xe5a0,
+ 0xe5a1, 0xe5a2, 0xe5a3, 0xe5a4, 0xe5a5, 0xe5a6, 0xe5a7, 0xe5a8,
+ 0xe5a9, 0xe5aa, 0xe5ab, 0xe5ac, 0xe5ad, 0xe5ae, 0xe5af, 0xe5b0,
+ 0xe5b1, 0xe5b2, 0xe5b3, 0xe5b4, 0xe5b5, 0xe5b6, 0xe5b7, 0xe5b8,
+ 0xe5b9, 0xe5ba, 0xe5bb, 0xe5bc, 0xe5bd, 0xe5be, 0xe5bf, 0xe5c0,
+ 0xe5c1, 0xe5c2, 0xe5c3, 0xe5c4, 0xe5c5, 0xe5c6, 0xe5c7, 0xe5c8,
+ 0xe5c9, 0xe5ca, 0xe5cb, 0xe5cc, 0xe5cd, 0xe5ce, 0xe5cf, 0xe5d0,
+ 0xe5d1, 0xe5d2, 0xe5d3, 0xe5d4, 0xe5d5, 0xe5d6, 0xe5d7, 0xe5d8,
+ 0xe5d9, 0xe5da, 0xe5db, 0xe5dc, 0xe5dd, 0xe5de, 0xe5df, 0xe5e0,
+ 0xe5e1, 0xe5e2, 0xe5e3, 0xe5e4, 0xe5e5, 0xe5e6, 0xe5e7, 0xe5e8,
+ 0xe5e9, 0xe5ea, 0xe5eb, 0xe5ec, 0xe5ed, 0xe5ee, 0xe5ef, 0xe5f0,
+ 0xe5f1, 0xe5f2, 0xe5f3, 0xe5f4, 0xe5f5, 0xe5f6, 0xe5f7, 0xe5f8,
+ 0xe5f9, 0xe5fa, 0xe5fb, 0xe5fc, 0xe640, 0xe641, 0xe642, 0xe643,
+ 0xe644, 0xe645, 0xe646, 0xe647, 0xe648, 0xe649, 0xe64a, 0xe64b,
+ 0xe64c, 0xe64d, 0xe64e, 0xe64f, 0xe650, 0xe651, 0xe652, 0xe653,
+ 0xe654, 0xe655, 0xe656, 0xe657, 0xe658, 0xe659, 0xe65a, 0xe65b,
+ 0xe65c, 0xe65d, 0xe65e, 0xe65f, 0xe660, 0xe661, 0xe662, 0xe663,
+ 0xe664, 0xe665, 0xe666, 0xe667, 0xe668, 0xe669, 0xe66a, 0xe66b,
+ 0xe66c, 0xe66d, 0xe66e, 0xe66f, 0xe670, 0xe671, 0xe672, 0xe673,
+ 0xe674, 0xe675, 0xe676, 0xe677, 0xe678, 0xe679, 0xe67a, 0xe67b,
+ 0xe67c, 0xe67d, 0xe67e, 0xe680, 0xe681, 0xe682, 0xe683, 0xe684,
+ 0xe685, 0xe686, 0xe687, 0xe688, 0xe689, 0xe68a, 0xe68b, 0xe68c,
+ 0xe68d, 0xe68e, 0xe68f, 0xe690, 0xe691, 0xe692, 0xe693, 0xe694,
+ 0xe695, 0xe696, 0xe697, 0xe698, 0xe699, 0xe69a, 0xe69b, 0xe69c,
+ 0xe69d, 0xe69e, 0xe69f, 0xe6a0, 0xe6a1, 0xe6a2, 0xe6a3, 0xe6a4,
+ 0xe6a5, 0xe6a6, 0xe6a7, 0xe6a8, 0xe6a9, 0xe6aa, 0xe6ab, 0xe6ac,
+ 0xe6ad, 0xe6ae, 0xe6af, 0xe6b0, 0xe6b1, 0xe6b2, 0xe6b3, 0xe6b4,
+ 0xe6b5, 0xe6b6, 0xe6b7, 0xe6b8, 0xe6b9, 0xe6ba, 0xe6bb, 0xe6bc,
+ 0xe6bd, 0xe6be, 0xe6bf, 0xe6c0, 0xe6c1, 0xe6c2, 0xe6c3, 0xe6c4,
+ 0xe6c5, 0xe6c6, 0xe6c7, 0xe6c8, 0xe6c9, 0xe6ca, 0xe6cb, 0xe6cc,
+ 0xe6cd, 0xe6ce, 0xe6cf, 0xe6d0, 0xe6d1, 0xe6d2, 0xe6d3, 0xe6d4,
+ 0xe6d5, 0xe6d6, 0xe6d7, 0xe6d8, 0xe6d9, 0xe6da, 0xe6db, 0xe6dc,
+ 0xe6dd, 0xe6de, 0xe6df, 0xe6e0, 0xe6e1, 0xe6e2, 0xe6e3, 0xe6e4,
+ 0xe6e5, 0xe6e6, 0xe6e7, 0xe6e8, 0xe6e9, 0xe6ea, 0xe6eb, 0xe6ec,
+ 0xe6ed, 0xe6ee, 0xe6ef, 0xe6f0, 0xe6f1, 0xe6f2, 0xe6f3, 0xe6f4,
+ 0xe6f5, 0xe6f6, 0xe6f7, 0xe6f8, 0xe6f9, 0xe6fa, 0xe6fb, 0xe6fc,
+ 0xe740, 0xe741, 0xe742, 0xe743, 0xe744, 0xe745, 0xe746, 0xe747,
+ 0xe748, 0xe749, 0xe74a, 0xe74b, 0xe74c, 0xe74d, 0xe74e, 0xe74f,
+ 0xe750, 0xe751, 0xe752, 0xe753, 0xe754, 0xe755, 0xe756, 0xe757,
+ 0xe758, 0xe759, 0xe75a, 0xe75b, 0xe75c, 0xe75d, 0xe75e, 0xe75f,
+ 0xe760, 0xe761, 0xe762, 0xe763, 0xe764, 0xe765, 0xe766, 0xe767,
+ 0xe768, 0xe769, 0xe76a, 0xe76b, 0xe76c, 0xe76d, 0xe76e, 0xe76f,
+ 0xe770, 0xe771, 0xe772, 0xe773, 0xe774, 0xe775, 0xe776, 0xe777,
+ 0xe778, 0xe779, 0xe77a, 0xe77b, 0xe77c, 0xe77d, 0xe77e, 0xe780,
+ 0xe781, 0xe782, 0xe783, 0xe784, 0xe785, 0xe786, 0xe787, 0xe788,
+ 0xe789, 0xe78a, 0xe78b, 0xe78c, 0xe78d, 0xe78e, 0xe78f, 0xe790,
+ 0xe791, 0xe792, 0xe793, 0xe794, 0xe795, 0xe796, 0xe797, 0xe798,
+ 0xe799, 0xe79a, 0xe79b, 0xe79c, 0xe79d, 0xe79e, 0xe79f, 0xe7a0,
+ 0xe7a1, 0xe7a2, 0xe7a3, 0xe7a4, 0xe7a5, 0xe7a6, 0xe7a7, 0xe7a8,
+ 0xe7a9, 0xe7aa, 0xe7ab, 0xe7ac, 0xe7ad, 0xe7ae, 0xe7af, 0xe7b0,
+ 0xe7b1, 0xe7b2, 0xe7b3, 0xe7b4, 0xe7b5, 0xe7b6, 0xe7b7, 0xe7b8,
+ 0xe7b9, 0xe7ba, 0xe7bb, 0xe7bc, 0xe7bd, 0xe7be, 0xe7bf, 0xe7c0,
+ 0xe7c1, 0xe7c2, 0xe7c3, 0xe7c4, 0xe7c5, 0xe7c6, 0xe7c7, 0xe7c8,
+ 0xe7c9, 0xe7ca, 0xe7cb, 0xe7cc, 0xe7cd, 0xe7ce, 0xe7cf, 0xe7d0,
+ 0xe7d1, 0xe7d2, 0xe7d3, 0xe7d4, 0xe7d5, 0xe7d6, 0xe7d7, 0xe7d8,
+ 0xe7d9, 0xe7da, 0xe7db, 0xe7dc, 0xe7dd, 0xe7de, 0xe7df, 0xe7e0,
+ 0xe7e1, 0xe7e2, 0xe7e3, 0xe7e4, 0xe7e5, 0xe7e6, 0xe7e7, 0xe7e8,
+ 0xe7e9, 0xe7ea, 0xe7eb, 0xe7ec, 0xe7ed, 0xe7ee, 0xe7ef, 0xe7f0,
+ 0xe7f1, 0xe7f2, 0xe7f3, 0xe7f4, 0xe7f5, 0xe7f6, 0xe7f7, 0xe7f8,
+ 0xe7f9, 0xe7fa, 0xe7fb, 0xe7fc, 0xe840, 0xe841, 0xe842, 0xe843,
+ 0xe844, 0xe845, 0xe846, 0xe847, 0xe848, 0xe849, 0xe84a, 0xe84b,
+ 0xe84c, 0xe84d, 0xe84e, 0xe84f, 0xe850, 0xe851, 0xe852, 0xe853,
+ 0xe854, 0xe855, 0xe856, 0xe857, 0xe858, 0xe859, 0xe85a, 0xe85b,
+ 0xe85c, 0xe85d, 0xe85e, 0xe85f, 0xe860, 0xe861, 0xe862, 0xe863,
+ 0xe864, 0xe865, 0xe866, 0xe867, 0xe868, 0xe869, 0xe86a, 0xe86b,
+ 0xe86c, 0xe86d, 0xe86e, 0xe86f, 0xe870, 0xe871, 0xe872, 0xe873,
+ 0xe874, 0xe875, 0xe876, 0xe877, 0xe878, 0xe879, 0xe87a, 0xe87b,
+ 0xe87c, 0xe87d, 0xe87e, 0xe880, 0xe881, 0xe882, 0xe883, 0xe884,
+ 0xe885, 0xe886, 0xe887, 0xe888, 0xe889, 0xe88a, 0xe88b, 0xe88c,
+ 0xe88d, 0xe88e, 0xe88f, 0xe890, 0xe891, 0xe892, 0xe893, 0xe894,
+ 0xe895, 0xe896, 0xe897, 0xe898, 0xe899, 0xe89a, 0xe89b, 0xe89c,
+ 0xe89d, 0xe89e, 0xe89f, 0xe8a0, 0xe8a1, 0xe8a2, 0xe8a3, 0xe8a4,
+ 0xe8a5, 0xe8a6, 0xe8a7, 0xe8a8, 0xe8a9, 0xe8aa, 0xe8ab, 0xe8ac,
+ 0xe8ad, 0xe8ae, 0xe8af, 0xe8b0, 0xe8b1, 0xe8b2, 0xe8b3, 0xe8b4,
+ 0xe8b5, 0xe8b6, 0xe8b7, 0xe8b8, 0xe8b9, 0xe8ba, 0xe8bb, 0xe8bc,
+ 0xe8bd, 0xe8be, 0xe8bf, 0xe8c0, 0xe8c1, 0xe8c2, 0xe8c3, 0xe8c4,
+ 0xe8c5, 0xe8c6, 0xe8c7, 0xe8c8, 0xe8c9, 0xe8ca, 0xe8cb, 0xe8cc,
+ 0xe8cd, 0xe8ce, 0xe8cf, 0xe8d0, 0xe8d1, 0xe8d2, 0xe8d3, 0xe8d4,
+ 0xe8d5, 0xe8d6, 0xe8d7, 0xe8d8, 0xe8d9, 0xe8da, 0xe8db, 0xe8dc,
+ 0xe8dd, 0xe8de, 0xe8df, 0xe8e0, 0xe8e1, 0xe8e2, 0xe8e3, 0xe8e4,
+ 0xe8e5, 0xe8e6, 0xe8e7, 0xe8e8, 0xe8e9, 0xe8ea, 0xe8eb, 0xe8ec,
+ 0xe8ed, 0xe8ee, 0xe8ef, 0xe8f0, 0xe8f1, 0xe8f2, 0xe8f3, 0xe8f4,
+ 0xe8f5, 0xe8f6, 0xe8f7, 0xe8f8, 0xe8f9, 0xe8fa, 0xe8fb, 0xe8fc,
+ 0xe940, 0xe941, 0xe942, 0xe943, 0xe944, 0xe945, 0xe946, 0xe947,
+ 0xe948, 0xe949, 0xe94a, 0xe94b, 0xe94c, 0xe94d, 0xe94e, 0xe94f,
+ 0xe950, 0xe951, 0xe952, 0xe953, 0xe954, 0xe955, 0xe956, 0xe957,
+ 0xe958, 0xe959, 0xe95a, 0xe95b, 0xe95c, 0xe95d, 0xe95e, 0xe95f,
+ 0xe960, 0xe961, 0xe962, 0xe963, 0xe964, 0xe965, 0xe966, 0xe967,
+ 0xe968, 0xe969, 0xe96a, 0xe96b, 0xe96c, 0xe96d, 0xe96e, 0xe96f,
+ 0xe970, 0xe971, 0xe972, 0xe973, 0xe974, 0xe975, 0xe976, 0xe977,
+ 0xe978, 0xe979, 0xe97a, 0xe97b, 0xe97c, 0xe97d, 0xe97e, 0xe980,
+ 0xe981, 0xe982, 0xe983, 0xe984, 0xe985, 0xe986, 0xe987, 0xe988,
+ 0xe989, 0xe98a, 0xe98b, 0xe98c, 0xe98d, 0xe98e, 0xe98f, 0xe990,
+ 0xe991, 0xe992, 0xe993, 0xe994, 0xe995, 0xe996, 0xe997, 0xe998,
+ 0xe999, 0xe99a, 0xe99b, 0xe99c, 0xe99d, 0xe99e, 0xe99f, 0xe9a0,
+ 0xe9a1, 0xe9a2, 0xe9a3, 0xe9a4, 0xe9a5, 0xe9a6, 0xe9a7, 0xe9a8,
+ 0xe9a9, 0xe9aa, 0xe9ab, 0xe9ac, 0xe9ad, 0xe9ae, 0xe9af, 0xe9b0,
+ 0xe9b1, 0xe9b2, 0xe9b3, 0xe9b4, 0xe9b5, 0xe9b6, 0xe9b7, 0xe9b8,
+ 0xe9b9, 0xe9ba, 0xe9bb, 0xe9bc, 0xe9bd, 0xe9be, 0xe9bf, 0xe9c0,
+ 0xe9c1, 0xe9c2, 0xe9c3, 0xe9c4, 0xe9c5, 0xe9c6, 0xe9c7, 0xe9c8,
+ 0xe9c9, 0xe9ca, 0xe9cb, 0xe9cc, 0xe9cd, 0xe9ce, 0xe9cf, 0xe9d0,
+ 0xe9d1, 0xe9d2, 0xe9d3, 0xe9d4, 0xe9d5, 0xe9d6, 0xe9d7, 0xe9d8,
+ 0xe9d9, 0xe9da, 0xe9db, 0xe9dc, 0xe9dd, 0xe9de, 0xe9df, 0xe9e0,
+ 0xe9e1, 0xe9e2, 0xe9e3, 0xe9e4, 0xe9e5, 0xe9e6, 0xe9e7, 0xe9e8,
+ 0xe9e9, 0xe9ea, 0xe9eb, 0xe9ec, 0xe9ed, 0xe9ee, 0xe9ef, 0xe9f0,
+ 0xe9f1, 0xe9f2, 0xe9f3, 0xe9f4, 0xe9f5, 0xe9f6, 0xe9f7, 0xe9f8,
+ 0xe9f9, 0xe9fa, 0xe9fb, 0xe9fc, 0xea40, 0xea41, 0xea42, 0xea43,
+ 0xea44, 0xea45, 0xea46, 0xea47, 0xea48, 0xea49, 0xea4a, 0xea4b,
+ 0xea4c, 0xea4d, 0xea4e, 0xea4f, 0xea50, 0xea51, 0xea52, 0xea53,
+ 0xea54, 0xea55, 0xea56, 0xea57, 0xea58, 0xea59, 0xea5a, 0xea5b,
+ 0xea5c, 0xea5d, 0xea5e, 0xea5f, 0xea60, 0xea61, 0xea62, 0xea63,
+ 0xea64, 0xea65, 0xea66, 0xea67, 0xea68, 0xea69, 0xea6a, 0xea6b,
+ 0xea6c, 0xea6d, 0xea6e, 0xea6f, 0xea70, 0xea71, 0xea72, 0xea73,
+ 0xea74, 0xea75, 0xea76, 0xea77, 0xea78, 0xea79, 0xea7a, 0xea7b,
+ 0xea7c, 0xea7d, 0xea7e, 0xea80, 0xea81, 0xea82, 0xea83, 0xea84,
+ 0xea85, 0xea86, 0xea87, 0xea88, 0xea89, 0xea8a, 0xea8b, 0xea8c,
+ 0xea8d, 0xea8e, 0xea8f, 0xea90, 0xea91, 0xea92, 0xea93, 0xea94,
+ 0xea95, 0xea96, 0xea97, 0xea98, 0xea99, 0xea9a, 0xea9b, 0xea9c,
+ 0xea9d, 0xea9e, 0xea9f, 0xeaa0, 0xeaa1, 0xeaa2, 0x0020, 0x849f,
+ 0x84aa, 0x84a0, 0x84ab, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x84a1, 0x0020, 0x0020, 0x84ac, 0x84a2,
+ 0x0020, 0x0020, 0x84ad, 0x84a4, 0x0020, 0x0020, 0x84af, 0x84a3,
+ 0x0020, 0x0020, 0x84ae, 0x84a5, 0x84ba, 0x0020, 0x0020, 0x84b5,
+ 0x0020, 0x0020, 0x84b0, 0x84a7, 0x84bc, 0x0020, 0x0020, 0x84b7,
+ 0x0020, 0x0020, 0x84b2, 0x84a6, 0x0020, 0x0020, 0x84b6, 0x84bb,
+ 0x0020, 0x0020, 0x84b1, 0x84a8, 0x0020, 0x0020, 0x84b8, 0x84bd,
+ 0x0020, 0x0020, 0x84b3, 0x84a9, 0x0020, 0x0020, 0x84b9, 0x0020,
+ 0x0020, 0x84be, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x84b4, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
+ 0x0020, 0x0020, 0x0020, 0x0020, 0xeaa3, 0xeaa4
+};
diff --git a/pdftops/Lexer.cxx b/pdftops/Lexer.cxx
new file mode 100644
index 000000000..442566b72
--- /dev/null
+++ b/pdftops/Lexer.cxx
@@ -0,0 +1,472 @@
+//========================================================================
+//
+// Lexer.cc
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <ctype.h>
+#include "Lexer.h"
+#include "Error.h"
+
+//------------------------------------------------------------------------
+
+// A '1' in this array means the character is white space. A '1' or
+// '2' means the character ends a name or command.
+static char specialChars[256] = {
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, // 0x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
+ 1, 0, 0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, // 2x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, // 3x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 5x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 7x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ax
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // bx
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // cx
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // dx
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ex
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // fx
+};
+
+//------------------------------------------------------------------------
+// Lexer
+//------------------------------------------------------------------------
+
+Lexer::Lexer(XRef *xref, Stream *str) {
+ Object obj;
+
+ curStr.initStream(str);
+ streams = new Array(xref);
+ streams->add(curStr.copy(&obj));
+ strPtr = 0;
+ freeArray = gTrue;
+ curStr.streamReset();
+}
+
+Lexer::Lexer(XRef *xref, Object *obj) {
+ Object obj2;
+
+ if (obj->isStream()) {
+ streams = new Array(xref);
+ freeArray = gTrue;
+ streams->add(obj->copy(&obj2));
+ } else {
+ streams = obj->getArray();
+ freeArray = gFalse;
+ }
+ strPtr = 0;
+ if (streams->getLength() > 0) {
+ streams->get(strPtr, &curStr);
+ curStr.streamReset();
+ }
+}
+
+Lexer::~Lexer() {
+ if (!curStr.isNone()) {
+ curStr.streamClose();
+ curStr.free();
+ }
+ if (freeArray) {
+ delete streams;
+ }
+}
+
+int Lexer::getChar() {
+ int c;
+
+ c = EOF;
+ while (!curStr.isNone() && (c = curStr.streamGetChar()) == EOF) {
+ curStr.streamClose();
+ curStr.free();
+ ++strPtr;
+ if (strPtr < streams->getLength()) {
+ streams->get(strPtr, &curStr);
+ curStr.streamReset();
+ }
+ }
+ return c;
+}
+
+int Lexer::lookChar() {
+ if (curStr.isNone()) {
+ return EOF;
+ }
+ return curStr.streamLookChar();
+}
+
+Object *Lexer::getObj(Object *obj) {
+ char *p;
+ int c, c2;
+ GBool comment, neg, done;
+ int numParen;
+ int xi;
+ double xf, scale;
+ GString *s;
+ int n, m;
+
+ // skip whitespace and comments
+ comment = gFalse;
+ while (1) {
+ if ((c = getChar()) == EOF) {
+ return obj->initEOF();
+ }
+ if (comment) {
+ if (c == '\r' || c == '\n')
+ comment = gFalse;
+ } else if (c == '%') {
+ comment = gTrue;
+ } else if (specialChars[c] != 1) {
+ break;
+ }
+ }
+
+ // start reading token
+ switch (c) {
+
+ // number
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ case '-': case '.':
+ neg = gFalse;
+ xi = 0;
+ if (c == '-') {
+ neg = gTrue;
+ } else if (c == '.') {
+ goto doReal;
+ } else {
+ xi = c - '0';
+ }
+ while (1) {
+ c = lookChar();
+ if (isdigit(c)) {
+ getChar();
+ xi = xi * 10 + (c - '0');
+ } else if (c == '.') {
+ getChar();
+ goto doReal;
+ } else {
+ break;
+ }
+ }
+ if (neg)
+ xi = -xi;
+ obj->initInt(xi);
+ break;
+ doReal:
+ xf = xi;
+ scale = 0.1;
+ while (1) {
+ c = lookChar();
+ if (!isdigit(c)) {
+ break;
+ }
+ getChar();
+ xf = xf + scale * (c - '0');
+ scale *= 0.1;
+ }
+ if (neg)
+ xf = -xf;
+ obj->initReal(xf);
+ break;
+
+ // string
+ case '(':
+ p = tokBuf;
+ n = 0;
+ numParen = 1;
+ done = gFalse;
+ s = NULL;
+ do {
+ c2 = EOF;
+ switch (c = getChar()) {
+
+ case EOF:
+#if 0
+ // This breaks some PDF files, e.g., ones from Photoshop.
+ case '\r':
+ case '\n':
+#endif
+ error(getPos(), "Unterminated string");
+ done = gTrue;
+ break;
+
+ case '(':
+ ++numParen;
+ c2 = c;
+ break;
+
+ case ')':
+ if (--numParen == 0) {
+ done = gTrue;
+ } else {
+ c2 = c;
+ }
+ break;
+
+ case '\\':
+ switch (c = getChar()) {
+ case 'n':
+ c2 = '\n';
+ break;
+ case 'r':
+ c2 = '\r';
+ break;
+ case 't':
+ c2 = '\t';
+ break;
+ case 'b':
+ c2 = '\b';
+ break;
+ case 'f':
+ c2 = '\f';
+ break;
+ case '\\':
+ case '(':
+ case ')':
+ c2 = c;
+ break;
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ c2 = c - '0';
+ c = lookChar();
+ if (c >= '0' && c <= '7') {
+ getChar();
+ c2 = (c2 << 3) + (c - '0');
+ c = lookChar();
+ if (c >= '0' && c <= '7') {
+ getChar();
+ c2 = (c2 << 3) + (c - '0');
+ }
+ }
+ break;
+ case '\r':
+ c = lookChar();
+ if (c == '\n') {
+ getChar();
+ }
+ break;
+ case '\n':
+ break;
+ case EOF:
+ error(getPos(), "Unterminated string");
+ done = gTrue;
+ break;
+ default:
+ c2 = c;
+ break;
+ }
+ break;
+
+ default:
+ c2 = c;
+ break;
+ }
+
+ if (c2 != EOF) {
+ if (n == tokBufSize) {
+ if (!s)
+ s = new GString(tokBuf, tokBufSize);
+ else
+ s->append(tokBuf, tokBufSize);
+ p = tokBuf;
+ n = 0;
+ }
+ *p++ = (char)c2;
+ ++n;
+ }
+ } while (!done);
+ if (!s)
+ s = new GString(tokBuf, n);
+ else
+ s->append(tokBuf, n);
+ obj->initString(s);
+ break;
+
+ // name
+ case '/':
+ p = tokBuf;
+ n = 0;
+ while ((c = lookChar()) != EOF && !specialChars[c]) {
+ getChar();
+ if (c == '#') {
+ c2 = lookChar();
+ if (c2 >= '0' && c2 <= '9') {
+ c = c2 - '0';
+ } else if (c2 >= 'A' && c2 <= 'F') {
+ c = c2 - 'A' + 10;
+ } else if (c2 >= 'a' && c2 <= 'f') {
+ c = c2 - 'a' + 10;
+ } else {
+ goto notEscChar;
+ }
+ getChar();
+ c <<= 4;
+ c2 = getChar();
+ if (c2 >= '0' && c2 <= '9') {
+ c += c2 - '0';
+ } else if (c2 >= 'A' && c2 <= 'F') {
+ c += c2 - 'A' + 10;
+ } else if (c2 >= 'a' && c2 <= 'f') {
+ c += c2 - 'a' + 10;
+ } else {
+ error(getPos(), "Illegal digit in hex char in name");
+ }
+ }
+ notEscChar:
+ if (++n == tokBufSize) {
+ error(getPos(), "Name token too long");
+ break;
+ }
+ *p++ = c;
+ }
+ *p = '\0';
+ obj->initName(tokBuf);
+ break;
+
+ // array punctuation
+ case '[':
+ case ']':
+ tokBuf[0] = c;
+ tokBuf[1] = '\0';
+ obj->initCmd(tokBuf);
+ break;
+
+ // hex string or dict punctuation
+ case '<':
+ c = lookChar();
+
+ // dict punctuation
+ if (c == '<') {
+ getChar();
+ tokBuf[0] = tokBuf[1] = '<';
+ tokBuf[2] = '\0';
+ obj->initCmd(tokBuf);
+
+ // hex string
+ } else {
+ p = tokBuf;
+ m = n = 0;
+ c2 = 0;
+ s = NULL;
+ while (1) {
+ c = getChar();
+ if (c == '>') {
+ break;
+ } else if (c == EOF) {
+ error(getPos(), "Unterminated hex string");
+ break;
+ } else if (specialChars[c] != 1) {
+ c2 = c2 << 4;
+ if (c >= '0' && c <= '9')
+ c2 += c - '0';
+ else if (c >= 'A' && c <= 'F')
+ c2 += c - 'A' + 10;
+ else if (c >= 'a' && c <= 'f')
+ c2 += c - 'a' + 10;
+ else
+ error(getPos(), "Illegal character <%02x> in hex string", c);
+ if (++m == 2) {
+ if (n == tokBufSize) {
+ if (!s)
+ s = new GString(tokBuf, tokBufSize);
+ else
+ s->append(tokBuf, tokBufSize);
+ p = tokBuf;
+ n = 0;
+ }
+ *p++ = (char)c2;
+ ++n;
+ c2 = 0;
+ m = 0;
+ }
+ }
+ }
+ if (!s)
+ s = new GString(tokBuf, n);
+ else
+ s->append(tokBuf, n);
+ if (m == 1)
+ s->append((char)(c2 << 4));
+ obj->initString(s);
+ }
+ break;
+
+ // dict punctuation
+ case '>':
+ c = lookChar();
+ if (c == '>') {
+ getChar();
+ tokBuf[0] = tokBuf[1] = '>';
+ tokBuf[2] = '\0';
+ obj->initCmd(tokBuf);
+ } else {
+ error(getPos(), "Illegal character '>'");
+ obj->initError();
+ }
+ break;
+
+ // error
+ case ')':
+ case '{':
+ case '}':
+ error(getPos(), "Illegal character '%c'", c);
+ obj->initError();
+ break;
+
+ // command
+ default:
+ p = tokBuf;
+ *p++ = c;
+ n = 1;
+ while ((c = lookChar()) != EOF && !specialChars[c]) {
+ getChar();
+ if (++n == tokBufSize) {
+ error(getPos(), "Command token too long");
+ break;
+ }
+ *p++ = c;
+ }
+ *p = '\0';
+ if (tokBuf[0] == 't' && !strcmp(tokBuf, "true")) {
+ obj->initBool(gTrue);
+ } else if (tokBuf[0] == 'f' && !strcmp(tokBuf, "false")) {
+ obj->initBool(gFalse);
+ } else if (tokBuf[0] == 'n' && !strcmp(tokBuf, "null")) {
+ obj->initNull();
+ } else {
+ obj->initCmd(tokBuf);
+ }
+ break;
+ }
+
+ return obj;
+}
+
+void Lexer::skipToNextLine() {
+ int c;
+
+ while (1) {
+ c = getChar();
+ if (c == EOF || c == '\n') {
+ return;
+ }
+ if (c == '\r') {
+ if ((c = lookChar()) == '\n') {
+ getChar();
+ }
+ return;
+ }
+ }
+}
diff --git a/pdftops/Lexer.h b/pdftops/Lexer.h
new file mode 100644
index 000000000..5edbeda6b
--- /dev/null
+++ b/pdftops/Lexer.h
@@ -0,0 +1,74 @@
+//========================================================================
+//
+// Lexer.h
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifndef LEXER_H
+#define LEXER_H
+
+#ifdef __GNUC__
+#pragma interface
+#endif
+
+#include "Object.h"
+#include "Stream.h"
+
+class XRef;
+
+#define tokBufSize 128 // size of token buffer
+
+//------------------------------------------------------------------------
+// Lexer
+//------------------------------------------------------------------------
+
+class Lexer {
+public:
+
+ // Construct a lexer for a single stream. Deletes the stream when
+ // lexer is deleted.
+ Lexer(XRef *xref, Stream *str);
+
+ // Construct a lexer for a stream or array of streams (assumes obj
+ // is either a stream or array of streams).
+ Lexer(XRef *xref, Object *obj);
+
+ // Destructor.
+ ~Lexer();
+
+ // Get the next object from the input stream.
+ Object *getObj(Object *obj);
+
+ // Skip to the beginning of the next line in the input stream.
+ void skipToNextLine();
+
+ // Skip over one character.
+ void skipChar() { getChar(); }
+
+ // Get stream.
+ Stream *getStream()
+ { return curStr.isNone() ? (Stream *)NULL : curStr.getStream(); }
+
+ // Get current position in file.
+ int getPos()
+ { return curStr.isNone() ? -1 : curStr.streamGetPos(); }
+
+ // Set position in file.
+ void setPos(int pos)
+ { if (!curStr.isNone()) curStr.streamSetPos(pos); }
+
+private:
+
+ int getChar();
+ int lookChar();
+
+ Array *streams; // array of input streams
+ int strPtr; // index of current stream
+ Object curStr; // current stream
+ GBool freeArray; // should lexer free the streams array?
+ char tokBuf[tokBufSize]; // temporary token buffer
+};
+
+#endif
diff --git a/pdftops/Link.cxx b/pdftops/Link.cxx
new file mode 100644
index 000000000..999c1f202
--- /dev/null
+++ b/pdftops/Link.cxx
@@ -0,0 +1,633 @@
+//========================================================================
+//
+// Link.cc
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#include <stddef.h>
+#include <string.h>
+#include "gmem.h"
+#include "GString.h"
+#include "Error.h"
+#include "Object.h"
+#include "Array.h"
+#include "Dict.h"
+#include "Link.h"
+
+//------------------------------------------------------------------------
+
+static GString *getFileSpecName(Object *fileSpecObj);
+
+//------------------------------------------------------------------------
+// LinkDest
+//------------------------------------------------------------------------
+
+LinkDest::LinkDest(Array *a, GBool pageIsRefA) {
+ Object obj1, obj2;
+
+ // initialize fields
+ pageIsRef = pageIsRefA;
+ left = bottom = right = top = zoom = 0;
+ ok = gFalse;
+
+ // get page
+ if (pageIsRef) {
+ if (!a->getNF(0, &obj1)->isRef()) {
+ error(-1, "Bad annotation destination");
+ goto err2;
+ }
+ pageRef.num = obj1.getRefNum();
+ pageRef.gen = obj1.getRefGen();
+ obj1.free();
+ } else {
+ if (!a->get(0, &obj1)->isInt()) {
+ error(-1, "Bad annotation destination");
+ goto err2;
+ }
+ pageNum = obj1.getInt() + 1;
+ obj1.free();
+ }
+
+ // get destination type
+ a->get(1, &obj1);
+
+ // XYZ link
+ if (obj1.isName("XYZ")) {
+ kind = destXYZ;
+ a->get(2, &obj2);
+ if (obj2.isNull()) {
+ changeLeft = gFalse;
+ } else if (obj2.isNum()) {
+ changeLeft = gTrue;
+ left = obj2.getNum();
+ } else {
+ error(-1, "Bad annotation destination position");
+ goto err1;
+ }
+ obj2.free();
+ a->get(3, &obj2);
+ if (obj2.isNull()) {
+ changeTop = gFalse;
+ } else if (obj2.isNum()) {
+ changeTop = gTrue;
+ top = obj2.getNum();
+ } else {
+ error(-1, "Bad annotation destination position");
+ goto err1;
+ }
+ obj2.free();
+ a->get(4, &obj2);
+ if (obj2.isNull()) {
+ changeZoom = gFalse;
+ } else if (obj2.isNum()) {
+ changeZoom = gTrue;
+ zoom = obj2.getNum();
+ } else {
+ error(-1, "Bad annotation destination position");
+ goto err1;
+ }
+ obj2.free();
+
+ // Fit link
+ } else if (obj1.isName("Fit")) {
+ kind = destFit;
+
+ // FitH link
+ } else if (obj1.isName("FitH")) {
+ kind = destFitH;
+ if (!a->get(2, &obj2)->isNum()) {
+ error(-1, "Bad annotation destination position");
+ goto err1;
+ }
+ top = obj2.getNum();
+ obj2.free();
+
+ // FitV link
+ } else if (obj1.isName("FitV")) {
+ kind = destFitV;
+ if (!a->get(2, &obj2)->isNum()) {
+ error(-1, "Bad annotation destination position");
+ goto err1;
+ }
+ left = obj2.getNum();
+ obj2.free();
+
+ // FitR link
+ } else if (obj1.isName("FitR")) {
+ kind = destFitR;
+ if (!a->get(2, &obj2)->isNum()) {
+ error(-1, "Bad annotation destination position");
+ goto err1;
+ }
+ left = obj2.getNum();
+ obj2.free();
+ if (!a->get(3, &obj2)->isNum()) {
+ error(-1, "Bad annotation destination position");
+ goto err1;
+ }
+ bottom = obj2.getNum();
+ obj2.free();
+ if (!a->get(4, &obj2)->isNum()) {
+ error(-1, "Bad annotation destination position");
+ goto err1;
+ }
+ right = obj2.getNum();
+ obj2.free();
+ if (!a->get(5, &obj2)->isNum()) {
+ error(-1, "Bad annotation destination position");
+ goto err1;
+ }
+ top = obj2.getNum();
+ obj2.free();
+
+ // FitB link
+ } else if (obj1.isName("FitB")) {
+ kind = destFitB;
+
+ // FitBH link
+ } else if (obj1.isName("FitBH")) {
+ kind = destFitBH;
+ if (!a->get(2, &obj2)->isNum()) {
+ error(-1, "Bad annotation destination position");
+ goto err1;
+ }
+ top = obj2.getNum();
+ obj2.free();
+
+ // FitBV link
+ } else if (obj1.isName("FitBV")) {
+ kind = destFitBV;
+ if (!a->get(2, &obj2)->isNum()) {
+ error(-1, "Bad annotation destination position");
+ goto err1;
+ }
+ left = obj2.getNum();
+ obj2.free();
+
+ // unknown link kind
+ } else {
+ error(-1, "Unknown annotation destination type");
+ goto err2;
+ }
+
+ obj1.free();
+ ok = gTrue;
+ return;
+
+ err1:
+ obj2.free();
+ err2:
+ obj1.free();
+}
+
+LinkDest::LinkDest(LinkDest *dest) {
+ kind = dest->kind;
+ pageIsRef = dest->pageIsRef;
+ if (pageIsRef)
+ pageRef = dest->pageRef;
+ else
+ pageNum = dest->pageNum;
+ left = dest->left;
+ bottom = dest->bottom;
+ right = dest->right;
+ top = dest->top;
+ zoom = dest->zoom;
+ changeLeft = dest->changeLeft;
+ changeTop = dest->changeTop;
+ changeZoom = dest->changeZoom;
+ ok = gTrue;
+}
+
+//------------------------------------------------------------------------
+// LinkGoTo
+//------------------------------------------------------------------------
+
+LinkGoTo::LinkGoTo(Object *destObj) {
+ dest = NULL;
+ namedDest = NULL;
+
+ // named destination
+ if (destObj->isName()) {
+ namedDest = new GString(destObj->getName());
+ } else if (destObj->isString()) {
+ namedDest = destObj->getString()->copy();
+
+ // destination dictionary
+ } else if (destObj->isArray()) {
+ dest = new LinkDest(destObj->getArray(), gTrue);
+ if (!dest->isOk()) {
+ delete dest;
+ dest = NULL;
+ }
+
+ // error
+ } else {
+ error(-1, "Illegal annotation destination");
+ }
+}
+
+LinkGoTo::~LinkGoTo() {
+ if (dest)
+ delete dest;
+ if (namedDest)
+ delete namedDest;
+}
+
+//------------------------------------------------------------------------
+// LinkGoToR
+//------------------------------------------------------------------------
+
+LinkGoToR::LinkGoToR(Object *fileSpecObj, Object *destObj) {
+ dest = NULL;
+ namedDest = NULL;
+
+ // get file name
+ fileName = getFileSpecName(fileSpecObj);
+
+ // named destination
+ if (destObj->isName()) {
+ namedDest = new GString(destObj->getName());
+ } else if (destObj->isString()) {
+ namedDest = destObj->getString()->copy();
+
+ // destination dictionary
+ } else if (destObj->isArray()) {
+ dest = new LinkDest(destObj->getArray(), gFalse);
+ if (!dest->isOk()) {
+ delete dest;
+ dest = NULL;
+ }
+
+ // error
+ } else {
+ error(-1, "Illegal annotation destination");
+ }
+}
+
+LinkGoToR::~LinkGoToR() {
+ if (fileName)
+ delete fileName;
+ if (dest)
+ delete dest;
+ if (namedDest)
+ delete namedDest;
+}
+
+
+//------------------------------------------------------------------------
+// LinkLaunch
+//------------------------------------------------------------------------
+
+LinkLaunch::LinkLaunch(Object *actionObj) {
+ Object obj1, obj2;
+
+ fileName = NULL;
+ params = NULL;
+
+ if (actionObj->isDict()) {
+ if (!actionObj->dictLookup("F", &obj1)->isNull()) {
+ fileName = getFileSpecName(&obj1);
+ } else {
+ obj1.free();
+ //~ This hasn't been defined by Adobe yet, so assume it looks
+ //~ just like the Win dictionary until they say otherwise.
+ if (actionObj->dictLookup("Unix", &obj1)->isDict()) {
+ obj1.dictLookup("F", &obj2);
+ fileName = getFileSpecName(&obj2);
+ obj2.free();
+ if (obj1.dictLookup("P", &obj2)->isString())
+ params = obj2.getString()->copy();
+ obj2.free();
+ } else {
+ error(-1, "Bad launch-type link action");
+ }
+ }
+ obj1.free();
+ }
+}
+
+LinkLaunch::~LinkLaunch() {
+ if (fileName)
+ delete fileName;
+ if (params)
+ delete params;
+}
+
+//------------------------------------------------------------------------
+// LinkURI
+//------------------------------------------------------------------------
+
+LinkURI::LinkURI(Object *uriObj, GString *baseURI) {
+ GString *uri2;
+ int n;
+ char c;
+
+ uri = NULL;
+ if (uriObj->isString()) {
+ uri2 = uriObj->getString()->copy();
+ if (baseURI) {
+ n = strcspn(uri2->getCString(), "/:");
+ if (n == uri2->getLength() || uri2->getChar(n) == '/') {
+ uri = baseURI->copy();
+ c = uri->getChar(uri->getLength() - 1);
+ if (c == '/' || c == '?') {
+ if (uri2->getChar(0) == '/') {
+ uri2->del(0);
+ }
+ } else {
+ if (uri2->getChar(0) != '/') {
+ uri->append('/');
+ }
+ }
+ uri->append(uri2);
+ delete uri2;
+ } else {
+ uri = uri2;
+ }
+ } else {
+ uri = uri2;
+ }
+ } else {
+ error(-1, "Illegal URI-type link");
+ }
+}
+
+LinkURI::~LinkURI() {
+ if (uri)
+ delete uri;
+}
+
+//------------------------------------------------------------------------
+// LinkNamed
+//------------------------------------------------------------------------
+
+LinkNamed::LinkNamed(Object *nameObj) {
+ name = NULL;
+ if (nameObj->isName()) {
+ name = new GString(nameObj->getName());
+ }
+}
+
+LinkNamed::~LinkNamed() {
+ if (name) {
+ delete name;
+ }
+}
+
+//------------------------------------------------------------------------
+// LinkUnknown
+//------------------------------------------------------------------------
+
+LinkUnknown::LinkUnknown(char *actionA) {
+ action = new GString(actionA);
+}
+
+LinkUnknown::~LinkUnknown() {
+ delete action;
+}
+
+//------------------------------------------------------------------------
+// Link
+//------------------------------------------------------------------------
+
+Link::Link(Dict *dict, GString *baseURI) {
+ Object obj1, obj2, obj3, obj4;
+ double t;
+
+ action = NULL;
+ ok = gFalse;
+
+ // get rectangle
+ if (!dict->lookup("Rect", &obj1)->isArray()) {
+ error(-1, "Annotation rectangle is wrong type");
+ goto err2;
+ }
+ if (!obj1.arrayGet(0, &obj2)->isNum()) {
+ error(-1, "Bad annotation rectangle");
+ goto err1;
+ }
+ x1 = obj2.getNum();
+ obj2.free();
+ if (!obj1.arrayGet(1, &obj2)->isNum()) {
+ error(-1, "Bad annotation rectangle");
+ goto err1;
+ }
+ y1 = obj2.getNum();
+ obj2.free();
+ if (!obj1.arrayGet(2, &obj2)->isNum()) {
+ error(-1, "Bad annotation rectangle");
+ goto err1;
+ }
+ x2 = obj2.getNum();
+ obj2.free();
+ if (!obj1.arrayGet(3, &obj2)->isNum()) {
+ error(-1, "Bad annotation rectangle");
+ goto err1;
+ }
+ y2 = obj2.getNum();
+ obj2.free();
+ obj1.free();
+ if (x1 > x2) {
+ t = x1;
+ x1 = x2;
+ x2 = t;
+ }
+ if (y1 > y2) {
+ t = y1;
+ y1 = y2;
+ y2 = t;
+ }
+
+ // get border
+ borderW = 0;
+ if (!dict->lookup("Border", &obj1)->isNull()) {
+ if (obj1.isArray() && obj1.arrayGetLength() >= 3) {
+ if (obj1.arrayGet(2, &obj2)->isNum()) {
+ borderW = obj2.getNum();
+ } else {
+ error(-1, "Bad annotation border");
+ }
+ obj2.free();
+ }
+ }
+ obj1.free();
+
+ // look for destination
+ if (!dict->lookup("Dest", &obj1)->isNull()) {
+ action = new LinkGoTo(&obj1);
+
+ // look for action
+ } else {
+ obj1.free();
+ if (dict->lookup("A", &obj1)->isDict()) {
+ obj1.dictLookup("S", &obj2);
+
+ // GoTo action
+ if (obj2.isName("GoTo")) {
+ obj1.dictLookup("D", &obj3);
+ action = new LinkGoTo(&obj3);
+ obj3.free();
+
+ // GoToR action
+ } else if (obj2.isName("GoToR")) {
+ obj1.dictLookup("F", &obj3);
+ obj1.dictLookup("D", &obj4);
+ action = new LinkGoToR(&obj3, &obj4);
+ obj3.free();
+ obj4.free();
+
+ // Launch action
+ } else if (obj2.isName("Launch")) {
+ action = new LinkLaunch(&obj1);
+
+ // URI action
+ } else if (obj2.isName("URI")) {
+ obj1.dictLookup("URI", &obj3);
+ action = new LinkURI(&obj3, baseURI);
+ obj3.free();
+
+ // Named action
+ } else if (obj2.isName("Named")) {
+ obj1.dictLookup("N", &obj3);
+ action = new LinkNamed(&obj3);
+ obj3.free();
+
+ // unknown action
+ } else if (obj2.isName()) {
+ action = new LinkUnknown(obj2.getName());
+
+ // action is missing or wrong type
+ } else {
+ error(-1, "Bad annotation action");
+ action = NULL;
+ }
+
+ obj2.free();
+
+ } else {
+ error(-1, "Missing annotation destination/action");
+ action = NULL;
+ }
+ }
+ obj1.free();
+
+ // check for bad action
+ if (action && action->isOk())
+ ok = gTrue;
+
+ return;
+
+ err1:
+ obj2.free();
+ err2:
+ obj1.free();
+}
+
+Link::~Link() {
+ if (action)
+ delete action;
+}
+
+//------------------------------------------------------------------------
+// Links
+//------------------------------------------------------------------------
+
+Links::Links(Object *annots, GString *baseURI) {
+ Link *link;
+ Object obj1, obj2;
+ int size;
+ int i;
+
+ links = NULL;
+ size = 0;
+ numLinks = 0;
+
+ if (annots->isArray()) {
+ for (i = 0; i < annots->arrayGetLength(); ++i) {
+ if (annots->arrayGet(i, &obj1)->isDict()) {
+ if (obj1.dictLookup("Subtype", &obj2)->isName("Link")) {
+ link = new Link(obj1.getDict(), baseURI);
+ if (link->isOk()) {
+ if (numLinks >= size) {
+ size += 16;
+ links = (Link **)grealloc(links, size * sizeof(Link *));
+ }
+ links[numLinks++] = link;
+ } else {
+ delete link;
+ }
+ }
+ obj2.free();
+ }
+ obj1.free();
+ }
+ }
+}
+
+Links::~Links() {
+ int i;
+
+ for (i = 0; i < numLinks; ++i)
+ delete links[i];
+ gfree(links);
+}
+
+LinkAction *Links::find(double x, double y) {
+ int i;
+
+ for (i = 0; i < numLinks; ++i) {
+ if (links[i]->inRect(x, y)) {
+ return links[i]->getAction();
+ }
+ }
+ return NULL;
+}
+
+GBool Links::onLink(double x, double y) {
+ int i;
+
+ for (i = 0; i < numLinks; ++i) {
+ if (links[i]->inRect(x, y))
+ return gTrue;
+ }
+ return gFalse;
+}
+
+//------------------------------------------------------------------------
+
+// Extract a file name from a file specification (string or dictionary).
+static GString *getFileSpecName(Object *fileSpecObj) {
+ GString *name;
+ Object obj1;
+
+ name = NULL;
+
+ // string
+ if (fileSpecObj->isString()) {
+ name = fileSpecObj->getString()->copy();
+
+ // dictionary
+ } else if (fileSpecObj->isDict()) {
+ if (!fileSpecObj->dictLookup("Unix", &obj1)->isString()) {
+ obj1.free();
+ fileSpecObj->dictLookup("F", &obj1);
+ }
+ if (obj1.isString())
+ name = obj1.getString()->copy();
+ else
+ error(-1, "Illegal file spec in link");
+ obj1.free();
+
+ // error
+ } else {
+ error(-1, "Illegal file spec in link");
+ }
+
+ return name;
+}
diff --git a/pdftops/Link.h b/pdftops/Link.h
new file mode 100644
index 000000000..4d1672478
--- /dev/null
+++ b/pdftops/Link.h
@@ -0,0 +1,336 @@
+//========================================================================
+//
+// Link.h
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifndef LINK_H
+#define LINK_H
+
+#ifdef __GNUC__
+#pragma interface
+#endif
+
+#include "Object.h"
+
+class GString;
+class Array;
+class Dict;
+
+//------------------------------------------------------------------------
+// LinkAction
+//------------------------------------------------------------------------
+
+enum LinkActionKind {
+ actionGoTo, // go to destination
+ actionGoToR, // go to destination in new file
+ actionLaunch, // launch app (or open document)
+ actionURI, // URI
+ actionNamed, // named action
+ actionUnknown // anything else
+};
+
+class LinkAction {
+public:
+
+ // Destructor.
+ virtual ~LinkAction() {}
+
+ // Was the LinkAction created successfully?
+ virtual GBool isOk() = 0;
+
+ // Check link action type.
+ virtual LinkActionKind getKind() = 0;
+};
+
+//------------------------------------------------------------------------
+// LinkDest
+//------------------------------------------------------------------------
+
+enum LinkDestKind {
+ destXYZ,
+ destFit,
+ destFitH,
+ destFitV,
+ destFitR,
+ destFitB,
+ destFitBH,
+ destFitBV
+};
+
+class LinkDest {
+public:
+
+ // Build a LinkDest from the array. If <pageIsRef> is true, the
+ // page is specified by an object reference; otherwise the page is
+ // specified by a (zero-relative) page number.
+ LinkDest(Array *a, GBool pageIsRef1);
+
+ // Copy a LinkDest.
+ LinkDest *copy() { return new LinkDest(this); }
+
+ // Was the LinkDest created successfully?
+ GBool isOk() { return ok; }
+
+ // Accessors.
+ LinkDestKind getKind() { return kind; }
+ GBool isPageRef() { return pageIsRef; }
+ int getPageNum() { return pageNum; }
+ Ref getPageRef() { return pageRef; }
+ double getLeft() { return left; }
+ double getBottom() { return bottom; }
+ double getRight() { return right; }
+ double getTop() { return top; }
+ double getZoom() { return zoom; }
+ GBool getChangeLeft() { return changeLeft; }
+ GBool getChangeTop() { return changeTop; }
+ GBool getChangeZoom() { return changeZoom; }
+
+private:
+
+ LinkDestKind kind; // destination type
+ GBool pageIsRef; // is the page a reference or number?
+ union {
+ Ref pageRef; // reference to page
+ int pageNum; // one-relative page number
+ };
+ double left, bottom; // position
+ double right, top;
+ double zoom; // zoom factor
+ GBool changeLeft, changeTop; // for destXYZ links, which position
+ GBool changeZoom; // components to change
+ GBool ok; // set if created successfully
+
+ LinkDest(LinkDest *dest);
+};
+
+//------------------------------------------------------------------------
+// LinkGoTo
+//------------------------------------------------------------------------
+
+class LinkGoTo: public LinkAction {
+public:
+
+ // Build a LinkGoTo from a destination (dictionary, name, or string).
+ LinkGoTo(Object *destObj);
+
+ // Destructor.
+ virtual ~LinkGoTo();
+
+ // Was the LinkGoTo created successfully?
+ virtual GBool isOk() { return dest || namedDest; }
+
+ // Accessors.
+ virtual LinkActionKind getKind() { return actionGoTo; }
+ LinkDest *getDest() { return dest; }
+ GString *getNamedDest() { return namedDest; }
+
+private:
+
+ LinkDest *dest; // regular destination (NULL for remote
+ // link with bad destination)
+ GString *namedDest; // named destination (only one of dest and
+ // and namedDest may be non-NULL)
+};
+
+//------------------------------------------------------------------------
+// LinkGoToR
+//------------------------------------------------------------------------
+
+class LinkGoToR: public LinkAction {
+public:
+
+ // Build a LinkGoToR from a file spec (dictionary) and destination
+ // (dictionary, name, or string).
+ LinkGoToR(Object *fileSpecObj, Object *destObj);
+
+ // Destructor.
+ virtual ~LinkGoToR();
+
+ // Was the LinkGoToR created successfully?
+ virtual GBool isOk() { return fileName && (dest || namedDest); }
+
+ // Accessors.
+ virtual LinkActionKind getKind() { return actionGoToR; }
+ GString *getFileName() { return fileName; }
+ LinkDest *getDest() { return dest; }
+ GString *getNamedDest() { return namedDest; }
+
+private:
+
+ GString *fileName; // file name
+ LinkDest *dest; // regular destination (NULL for remote
+ // link with bad destination)
+ GString *namedDest; // named destination (only one of dest and
+ // and namedDest may be non-NULL)
+};
+
+//------------------------------------------------------------------------
+// LinkLaunch
+//------------------------------------------------------------------------
+
+class LinkLaunch: public LinkAction {
+public:
+
+ // Build a LinkLaunch from an action dictionary.
+ LinkLaunch(Object *actionObj);
+
+ // Destructor.
+ virtual ~LinkLaunch();
+
+ // Was the LinkLaunch created successfully?
+ virtual GBool isOk() { return fileName != NULL; }
+
+ // Accessors.
+ virtual LinkActionKind getKind() { return actionLaunch; }
+ GString *getFileName() { return fileName; }
+ GString *getParams() { return params; }
+
+private:
+
+ GString *fileName; // file name
+ GString *params; // parameters
+};
+
+//------------------------------------------------------------------------
+// LinkURI
+//------------------------------------------------------------------------
+
+class LinkURI: public LinkAction {
+public:
+
+ // Build a LinkURI given the URI (string) and base URI.
+ LinkURI(Object *uriObj, GString *baseURI);
+
+ // Destructor.
+ virtual ~LinkURI();
+
+ // Was the LinkURI created successfully?
+ virtual GBool isOk() { return uri != NULL; }
+
+ // Accessors.
+ virtual LinkActionKind getKind() { return actionURI; }
+ GString *getURI() { return uri; }
+
+private:
+
+ GString *uri; // the URI
+};
+
+//------------------------------------------------------------------------
+// LinkNamed
+//------------------------------------------------------------------------
+
+class LinkNamed: public LinkAction {
+public:
+
+ // Build a LinkNamed given the action name.
+ LinkNamed(Object *nameObj);
+
+ virtual ~LinkNamed();
+
+ virtual GBool isOk() { return name != NULL; }
+
+ virtual LinkActionKind getKind() { return actionNamed; }
+ GString *getName() { return name; }
+
+private:
+
+ GString *name;
+};
+
+//------------------------------------------------------------------------
+// LinkUnknown
+//------------------------------------------------------------------------
+
+class LinkUnknown: public LinkAction {
+public:
+
+ // Build a LinkUnknown with the specified action type.
+ LinkUnknown(char *actionA);
+
+ // Destructor.
+ virtual ~LinkUnknown();
+
+ // Was the LinkUnknown create successfully?
+ virtual GBool isOk() { return action != NULL; }
+
+ // Accessors.
+ virtual LinkActionKind getKind() { return actionUnknown; }
+ GString *getAction() { return action; }
+
+private:
+
+ GString *action; // action subtype
+};
+
+//------------------------------------------------------------------------
+// Link
+//------------------------------------------------------------------------
+
+class Link {
+public:
+
+ // Construct a link, given its dictionary.
+ Link(Dict *dict, GString *baseURI);
+
+ // Destructor.
+ ~Link();
+
+ // Was the link created successfully?
+ GBool isOk() { return ok; }
+
+ // Check if point is inside the link rectangle.
+ GBool inRect(double x, double y)
+ { return x1 <= x && x <= x2 && y1 <= y && y <= y2; }
+
+ // Get action.
+ LinkAction *getAction() { return action; }
+
+ // Get border corners and width.
+ void getBorder(double *xa1, double *ya1, double *xa2, double *ya2,
+ double *wa)
+ { *xa1 = x1; *ya1 = y1; *xa2 = x2; *ya2 = y2; *wa = borderW; }
+
+private:
+
+ double x1, y1; // lower left corner
+ double x2, y2; // upper right corner
+ double borderW; // border width
+ LinkAction *action; // action
+ GBool ok; // is link valid?
+};
+
+//------------------------------------------------------------------------
+// Links
+//------------------------------------------------------------------------
+
+class Links {
+public:
+
+ // Extract links from array of annotations.
+ Links(Object *annots, GString *baseURI);
+
+ // Destructor.
+ ~Links();
+
+ // Iterate through list of links.
+ int getNumLinks() { return numLinks; }
+ Link *getLink(int i) { return links[i]; }
+
+ // If point <x>,<y> is in a link, return the associated action;
+ // else return NULL.
+ LinkAction *find(double x, double y);
+
+ // Return true if <x>,<y> is in a link.
+ GBool onLink(double x, double y);
+
+private:
+
+ Link **links;
+ int numLinks;
+};
+
+#endif
diff --git a/pdftops/Makefile b/pdftops/Makefile
new file mode 100644
index 000000000..67a79c8b3
--- /dev/null
+++ b/pdftops/Makefile
@@ -0,0 +1,132 @@
+#
+# "$Id$"
+#
+# pdftops filter Makefile for the Common UNIX Printing System (CUPS).
+#
+# CUPS filter changes Copyright 1997-2002 by Easy Software Products.
+# Xpdf code Copyright 1996-1999 by Derek B. Noonburg
+#
+
+
+include ../Makedefs
+
+#
+# Object files...
+#
+
+LIBOBJS = Decrypt.o GString.o gfile.o gmempp.o gmem.o parseargs.o \
+ Array.o Catalog.o Dict.o Error.o FontEncoding.o \
+ FontFile.o FormWidget.o Function.o Gfx.o GfxFont.o GfxState.o \
+ Lexer.o Link.o Object.o OutputDev.o Page.o Params.o \
+ Parser.o PDFDoc.o PSOutputDev.o Stream.o XRef.o
+OBJS = pdftops.o $(LIBOBJS)
+
+#
+# Make everything...
+#
+
+all: pdftops
+
+
+#
+# Clean all object files...
+#
+
+clean:
+ $(RM) $(OBJS)
+ $(RM) libxpdf.a
+ $(RM) pdftops
+
+
+#
+# Install the filter...
+#
+
+install:
+ $(INSTALL_DIR) $(SERVERBIN)/filter
+ $(INSTALL_BIN) pdftops $(SERVERBIN)/filter
+
+
+#
+# pdftops
+#
+
+pdftops: libxpdf.a pdftops.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CXX) $(LDFLAGS) -o $@ pdftops.o libxpdf.a $(LIBS) -lm
+
+pdftops.o: parseargs.h gtypes.h GString.h gmem.h Object.h Array.h \
+ Dict.h Stream.h XRef.h Catalog.h Page.h PDFDoc.h Link.h \
+ PSOutputDev.h config.h OutputDev.h Params.h Error.h
+
+
+#
+# libxpdf.a
+#
+
+libxpdf.a: $(LIBOBJS)
+ echo Archiving $@...
+ $(RM) $@
+ $(AR) $(ARFLAGS) $@ $(LIBOBJS)
+ $(RANLIB) $@
+
+GString.o: GString.h
+gmempp.o: gmem.h
+gfile.o: GString.h gfile.h gtypes.h
+gmem.o: gmem.h
+parseargs.o: parseargs.h gtypes.h
+Array.o: gmem.h Object.h gtypes.h GString.h Array.h Dict.h Stream.h
+Catalog.o: gmem.h Object.h gtypes.h GString.h Array.h Dict.h Stream.h \
+ Page.h Error.h config.h Link.h Catalog.h
+Decrypt.o: gmem.h Decrypt.h gtypes.h GString.h
+Dict.o: gmem.h Object.h gtypes.h GString.h Array.h Dict.h Stream.h \
+ XRef.h
+Error.o: gtypes.h Params.h Error.h config.h
+FontEncoding.o: gmem.h FontEncoding.h gtypes.h
+FontFile.o: gmem.h Error.h config.h FontFile.h gtypes.h GString.h \
+ FontEncoding.h StdFontInfo.h CompactFontInfo.h
+FormWidget.o: FormWidget.h gmem.h Object.h Gfx.h
+Function.o: gmem.h Object.h Dict.h Stream.h Error.h Function.h
+Gfx.o: gmem.h Object.h gtypes.h GString.h Array.h Dict.h Stream.h \
+ Lexer.h Parser.h GfxFont.h FontEncoding.h GfxState.h \
+ OutputDev.h Params.h Error.h config.h Gfx.h
+GfxFont.o: GString.h gmem.h gfile.h gtypes.h config.h Object.h Array.h \
+ Dict.h Stream.h Error.h Params.h FontFile.h FontEncoding.h \
+ GfxFont.h FontInfo.h
+GfxState.o: gmem.h Error.h config.h Object.h gtypes.h GString.h Array.h \
+ Dict.h Stream.h GfxState.h
+ImageOutputDev.o: gmem.h config.h Error.h GfxState.h gtypes.h Object.h \
+ GString.h Array.h Dict.h Stream.h ImageOutputDev.h OutputDev.h
+Lexer.o: Lexer.h Object.h gtypes.h gmem.h GString.h Array.h Dict.h \
+ Stream.h Error.h config.h
+Link.o: gmem.h GString.h Error.h config.h Object.h gtypes.h Array.h \
+ Dict.h Stream.h Link.h
+Object.o: Object.h gtypes.h gmem.h GString.h Array.h Dict.h Stream.h \
+ Error.h config.h XRef.h
+OutputDev.o: Object.h gtypes.h gmem.h GString.h Array.h Dict.h Stream.h \
+ GfxState.h OutputDev.h
+Page.o: Object.h gtypes.h gmem.h GString.h Array.h Dict.h Stream.h \
+ XRef.h OutputDev.h Gfx.h Error.h config.h Params.h Page.h
+Params.o: gtypes.h gmem.h GString.h gfile.h Params.h
+Parser.o: Object.h gtypes.h gmem.h GString.h Array.h Dict.h Stream.h \
+ Parser.h Lexer.h Error.h config.h
+PDFDoc.o: GString.h config.h Page.h Object.h gtypes.h gmem.h Array.h \
+ Dict.h Stream.h Catalog.h XRef.h Link.h OutputDev.h Params.h \
+ Error.h PDFDoc.h
+PSOutputDev.o: GString.h config.h Object.h gtypes.h gmem.h Array.h Dict.h \
+ Stream.h Error.h GfxState.h GfxFont.h FontEncoding.h \
+ FontFile.h Catalog.h Page.h PSOutputDev.h OutputDev.h
+SFont.o: SFont.h gtypes.h
+Stream.o: gmem.h config.h Error.h Object.h gtypes.h GString.h Array.h \
+ Dict.h Stream.h Stream-CCITT.h
+T1Font.o: T1Font.h gmem.h FontEncoding.h
+TTFont.o: TTFont.h gmem.h FontEncoding.h
+XRef.o: gmem.h Object.h gtypes.h GString.h Array.h Dict.h Stream.h \
+ Lexer.h Parser.h Error.h config.h XRef.h
+
+
+$(OBJS): ../config.h ../Makedefs
+
+#
+# End of "$Id$".
+#
diff --git a/pdftops/Object.cxx b/pdftops/Object.cxx
new file mode 100644
index 000000000..ca671ea2c
--- /dev/null
+++ b/pdftops/Object.cxx
@@ -0,0 +1,220 @@
+//========================================================================
+//
+// Object.cc
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#include <stddef.h>
+#include "Object.h"
+#include "Array.h"
+#include "Dict.h"
+#include "Error.h"
+#include "Stream.h"
+#include "XRef.h"
+
+//------------------------------------------------------------------------
+// Object
+//------------------------------------------------------------------------
+
+char *objTypeNames[numObjTypes] = {
+ "boolean",
+ "integer",
+ "real",
+ "string",
+ "name",
+ "null",
+ "array",
+ "dictionary",
+ "stream",
+ "ref",
+ "cmd",
+ "error",
+ "eof",
+ "none"
+};
+
+#ifdef DEBUG_MEM
+int Object::numAlloc[numObjTypes] =
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+#endif
+
+Object *Object::initArray(XRef *xref) {
+ initObj(objArray);
+ array = new Array(xref);
+ return this;
+}
+
+Object *Object::initDict(XRef *xref) {
+ initObj(objDict);
+ dict = new Dict(xref);
+ return this;
+}
+
+Object *Object::initStream(Stream *streamA) {
+ initObj(objStream);
+ stream = streamA;
+ return this;
+}
+
+Object *Object::copy(Object *obj) {
+ *obj = *this;
+ switch (type) {
+ case objString:
+ obj->string = string->copy();
+ break;
+ case objName:
+ obj->name = copyString(name);
+ break;
+ case objArray:
+ array->incRef();
+ break;
+ case objDict:
+ dict->incRef();
+ break;
+ case objStream:
+ stream->incRef();
+ break;
+ case objCmd:
+ obj->cmd = copyString(cmd);
+ break;
+ default:
+ break;
+ }
+#ifdef DEBUG_MEM
+ ++numAlloc[type];
+#endif
+ return obj;
+}
+
+Object *Object::fetch(XRef *xref, Object *obj) {
+ return (type == objRef && xref) ?
+ xref->fetch(ref.num, ref.gen, obj) : copy(obj);
+}
+
+void Object::free() {
+ switch (type) {
+ case objString:
+ delete string;
+ break;
+ case objName:
+ gfree(name);
+ break;
+ case objArray:
+ if (!array->decRef()) {
+ delete array;
+ }
+ break;
+ case objDict:
+ if (!dict->decRef()) {
+ delete dict;
+ }
+ break;
+ case objStream:
+ if (!stream->decRef()) {
+ delete stream;
+ }
+ break;
+ case objCmd:
+ gfree(cmd);
+ break;
+ default:
+ break;
+ }
+#ifdef DEBUG_MEM
+ --numAlloc[type];
+#endif
+ type = objNone;
+}
+
+char *Object::getTypeName() {
+ return objTypeNames[type];
+}
+
+void Object::print(FILE *f) {
+ Object obj;
+ int i;
+
+ switch (type) {
+ case objBool:
+ fprintf(f, "%s", booln ? "true" : "false");
+ break;
+ case objInt:
+ fprintf(f, "%d", intg);
+ break;
+ case objReal:
+ fprintf(f, "%g", real);
+ break;
+ case objString:
+ fprintf(f, "(%s)", string->getCString());
+ break;
+ case objName:
+ fprintf(f, "/%s", name);
+ break;
+ case objNull:
+ fprintf(f, "null");
+ break;
+ case objArray:
+ fprintf(f, "[");
+ for (i = 0; i < arrayGetLength(); ++i) {
+ if (i > 0)
+ fprintf(f, " ");
+ arrayGetNF(i, &obj);
+ obj.print(f);
+ obj.free();
+ }
+ fprintf(f, "]");
+ break;
+ case objDict:
+ fprintf(f, "<<");
+ for (i = 0; i < dictGetLength(); ++i) {
+ fprintf(f, " /%s ", dictGetKey(i));
+ dictGetValNF(i, &obj);
+ obj.print(f);
+ obj.free();
+ }
+ fprintf(f, " >>");
+ break;
+ case objStream:
+ fprintf(f, "<stream>");
+ break;
+ case objRef:
+ fprintf(f, "%d %d R", ref.num, ref.gen);
+ break;
+ case objCmd:
+ fprintf(f, "%s", cmd);
+ break;
+ case objError:
+ fprintf(f, "<error>");
+ break;
+ case objEOF:
+ fprintf(f, "<EOF>");
+ break;
+ case objNone:
+ fprintf(f, "<none>");
+ break;
+ }
+}
+
+void Object::memCheck(FILE *f) {
+#ifdef DEBUG_MEM
+ int i;
+ int t;
+
+ t = 0;
+ for (i = 0; i < numObjTypes; ++i)
+ t += numAlloc[i];
+ if (t > 0) {
+ fprintf(f, "Allocated objects:\n");
+ for (i = 0; i < numObjTypes; ++i) {
+ if (numAlloc[i] > 0)
+ fprintf(f, " %-20s: %6d\n", objTypeNames[i], numAlloc[i]);
+ }
+ }
+#endif
+}
diff --git a/pdftops/Object.h b/pdftops/Object.h
new file mode 100644
index 000000000..49af58613
--- /dev/null
+++ b/pdftops/Object.h
@@ -0,0 +1,299 @@
+//========================================================================
+//
+// Object.h
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifndef OBJECT_H
+#define OBJECT_H
+
+#ifdef __GNUC__
+#pragma interface
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include "gtypes.h"
+#include "gmem.h"
+#include "GString.h"
+
+class XRef;
+class Array;
+class Dict;
+class Stream;
+
+//------------------------------------------------------------------------
+// Ref
+//------------------------------------------------------------------------
+
+struct Ref {
+ int num; // object number
+ int gen; // generation number
+};
+
+//------------------------------------------------------------------------
+// object types
+//------------------------------------------------------------------------
+
+enum ObjType {
+ // simple objects
+ objBool, // boolean
+ objInt, // integer
+ objReal, // real
+ objString, // string
+ objName, // name
+ objNull, // null
+
+ // complex objects
+ objArray, // array
+ objDict, // dictionary
+ objStream, // stream
+ objRef, // indirect reference
+
+ // special objects
+ objCmd, // command name
+ objError, // error return from Lexer
+ objEOF, // end of file return from Lexer
+ objNone // uninitialized object
+};
+
+#define numObjTypes 14 // total number of object types
+
+//------------------------------------------------------------------------
+// Object
+//------------------------------------------------------------------------
+
+#ifdef DEBUG_MEM
+#define initObj(t) ++numAlloc[type = t]
+#else
+#define initObj(t) type = t
+#endif
+
+class Object {
+public:
+
+ // Default constructor.
+ Object():
+ type(objNone) {}
+
+ // Initialize an object.
+ Object *initBool(GBool boolnA)
+ { initObj(objBool); booln = boolnA; return this; }
+ Object *initInt(int intgA)
+ { initObj(objInt); intg = intgA; return this; }
+ Object *initReal(double realA)
+ { initObj(objReal); real = realA; return this; }
+ Object *initString(GString *stringA)
+ { initObj(objString); string = stringA; return this; }
+ Object *initName(char *nameA)
+ { initObj(objName); name = copyString(nameA); return this; }
+ Object *initNull()
+ { initObj(objNull); return this; }
+ Object *initArray(XRef *xref);
+ Object *initDict(XRef *xref);
+ Object *initStream(Stream *streamA);
+ Object *initRef(int numA, int genA)
+ { initObj(objRef); ref.num = numA; ref.gen = genA; return this; }
+ Object *initCmd(char *cmdA)
+ { initObj(objCmd); cmd = copyString(cmdA); return this; }
+ Object *initError()
+ { initObj(objError); return this; }
+ Object *initEOF()
+ { initObj(objEOF); return this; }
+
+ // Copy an object.
+ Object *copy(Object *obj);
+
+ // If object is a Ref, fetch and return the referenced object.
+ // Otherwise, return a copy of the object.
+ Object *fetch(XRef *xref, Object *obj);
+
+ // Free object contents.
+ void free();
+
+ // Type checking.
+ ObjType getType() { return type; }
+ GBool isBool() { return type == objBool; }
+ GBool isInt() { return type == objInt; }
+ GBool isReal() { return type == objReal; }
+ GBool isNum() { return type == objInt || type == objReal; }
+ GBool isString() { return type == objString; }
+ GBool isName() { return type == objName; }
+ GBool isNull() { return type == objNull; }
+ GBool isArray() { return type == objArray; }
+ GBool isDict() { return type == objDict; }
+ GBool isStream() { return type == objStream; }
+ GBool isRef() { return type == objRef; }
+ GBool isCmd() { return type == objCmd; }
+ GBool isError() { return type == objError; }
+ GBool isEOF() { return type == objEOF; }
+ GBool isNone() { return type == objNone; }
+
+ // Special type checking.
+ GBool isName(char *nameA)
+ { return type == objName && !strcmp(name, nameA); }
+ GBool isDict(char *dictType);
+ GBool isStream(char *dictType);
+ GBool isCmd(char *cmdA)
+ { return type == objCmd && !strcmp(cmd, cmdA); }
+
+ // Accessors. NB: these assume object is of correct type.
+ GBool getBool() { return booln; }
+ int getInt() { return intg; }
+ double getReal() { return real; }
+ double getNum() { return type == objInt ? (double)intg : real; }
+ GString *getString() { return string; }
+ char *getName() { return name; }
+ Array *getArray() { return array; }
+ Dict *getDict() { return dict; }
+ Stream *getStream() { return stream; }
+ Ref getRef() { return ref; }
+ int getRefNum() { return ref.num; }
+ int getRefGen() { return ref.gen; }
+
+ // Array accessors.
+ int arrayGetLength();
+ void arrayAdd(Object *elem);
+ Object *arrayGet(int i, Object *obj);
+ Object *arrayGetNF(int i, Object *obj);
+
+ // Dict accessors.
+ int dictGetLength();
+ void dictAdd(char *key, Object *val);
+ GBool dictIs(char *dictType);
+ Object *dictLookup(char *key, Object *obj);
+ Object *dictLookupNF(char *key, Object *obj);
+ char *dictGetKey(int i);
+ Object *dictGetVal(int i, Object *obj);
+ Object *dictGetValNF(int i, Object *obj);
+
+ // Stream accessors.
+ GBool streamIs(char *dictType);
+ void streamReset();
+ void streamClose();
+ int streamGetChar();
+ int streamLookChar();
+ char *streamGetLine(char *buf, int size);
+ int streamGetPos();
+ void streamSetPos(int pos);
+ Dict *streamGetDict();
+
+ // Output.
+ char *getTypeName();
+ void print(FILE *f = stdout);
+
+ // Memory testing.
+ static void memCheck(FILE *f);
+
+private:
+
+ ObjType type; // object type
+ union { // value for each type:
+ GBool booln; // boolean
+ int intg; // integer
+ double real; // real
+ GString *string; // string
+ char *name; // name
+ Array *array; // array
+ Dict *dict; // dictionary
+ Stream *stream; // stream
+ Ref ref; // indirect reference
+ char *cmd; // command
+ };
+
+#ifdef DEBUG_MEM
+ static int // number of each type of object
+ numAlloc[numObjTypes]; // currently allocated
+#endif
+};
+
+//------------------------------------------------------------------------
+// Array accessors.
+//------------------------------------------------------------------------
+
+#include "Array.h"
+
+inline int Object::arrayGetLength()
+ { return array->getLength(); }
+
+inline void Object::arrayAdd(Object *elem)
+ { array->add(elem); }
+
+inline Object *Object::arrayGet(int i, Object *obj)
+ { return array->get(i, obj); }
+
+inline Object *Object::arrayGetNF(int i, Object *obj)
+ { return array->getNF(i, obj); }
+
+//------------------------------------------------------------------------
+// Dict accessors.
+//------------------------------------------------------------------------
+
+#include "Dict.h"
+
+inline int Object::dictGetLength()
+ { return dict->getLength(); }
+
+inline void Object::dictAdd(char *key, Object *val)
+ { dict->add(key, val); }
+
+inline GBool Object::dictIs(char *dictType)
+ { return dict->is(dictType); }
+
+inline GBool Object::isDict(char *dictType)
+ { return type == objDict && dictIs(dictType); }
+
+inline Object *Object::dictLookup(char *key, Object *obj)
+ { return dict->lookup(key, obj); }
+
+inline Object *Object::dictLookupNF(char *key, Object *obj)
+ { return dict->lookupNF(key, obj); }
+
+inline char *Object::dictGetKey(int i)
+ { return dict->getKey(i); }
+
+inline Object *Object::dictGetVal(int i, Object *obj)
+ { return dict->getVal(i, obj); }
+
+inline Object *Object::dictGetValNF(int i, Object *obj)
+ { return dict->getValNF(i, obj); }
+
+//------------------------------------------------------------------------
+// Stream accessors.
+//------------------------------------------------------------------------
+
+#include "Stream.h"
+
+inline GBool Object::streamIs(char *dictType)
+ { return stream->getDict()->is(dictType); }
+
+inline GBool Object::isStream(char *dictType)
+ { return type == objStream && streamIs(dictType); }
+
+inline void Object::streamReset()
+ { stream->reset(); }
+
+inline void Object::streamClose()
+ { stream->close(); }
+
+inline int Object::streamGetChar()
+ { return stream->getChar(); }
+
+inline int Object::streamLookChar()
+ { return stream->lookChar(); }
+
+inline char *Object::streamGetLine(char *buf, int size)
+ { return stream->getLine(buf, size); }
+
+inline int Object::streamGetPos()
+ { return stream->getPos(); }
+
+inline void Object::streamSetPos(int pos)
+ { stream->setPos(pos); }
+
+inline Dict *Object::streamGetDict()
+ { return stream->getDict(); }
+
+#endif
diff --git a/pdftops/OutputDev.cxx b/pdftops/OutputDev.cxx
new file mode 100644
index 000000000..014b2aef6
--- /dev/null
+++ b/pdftops/OutputDev.cxx
@@ -0,0 +1,94 @@
+//========================================================================
+//
+// OutputDev.cc
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#include <stddef.h>
+#include "Object.h"
+#include "Stream.h"
+#include "GfxState.h"
+#include "OutputDev.h"
+
+//------------------------------------------------------------------------
+// OutputDev
+//------------------------------------------------------------------------
+
+void OutputDev::setDefaultCTM(double *ctm) {
+ int i;
+ double det;
+
+ for (i = 0; i < 6; ++i) {
+ defCTM[i] = ctm[i];
+ }
+ det = 1 / (defCTM[0] * defCTM[3] - defCTM[1] * defCTM[2]);
+ defICTM[0] = defCTM[3] * det;
+ defICTM[1] = -defCTM[1] * det;
+ defICTM[2] = -defCTM[2] * det;
+ defICTM[3] = defCTM[0] * det;
+ defICTM[4] = (defCTM[2] * defCTM[5] - defCTM[3] * defCTM[4]) * det;
+ defICTM[5] = (defCTM[1] * defCTM[4] - defCTM[0] * defCTM[5]) * det;
+}
+
+void OutputDev::cvtDevToUser(int dx, int dy, double *ux, double *uy) {
+ *ux = defICTM[0] * dx + defICTM[2] * dy + defICTM[4];
+ *uy = defICTM[1] * dx + defICTM[3] * dy + defICTM[5];
+}
+
+void OutputDev::cvtUserToDev(double ux, double uy, int *dx, int *dy) {
+ *dx = (int)(defCTM[0] * ux + defCTM[2] * uy + defCTM[4] + 0.5);
+ *dy = (int)(defCTM[1] * ux + defCTM[3] * uy + defCTM[5] + 0.5);
+}
+
+void OutputDev::updateAll(GfxState *state) {
+ updateLineDash(state);
+ updateFlatness(state);
+ updateLineJoin(state);
+ updateLineCap(state);
+ updateMiterLimit(state);
+ updateLineWidth(state);
+ updateFillColor(state);
+ updateStrokeColor(state);
+ updateFont(state);
+}
+
+void OutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GBool invert,
+ GBool inlineImg) {
+ int i, j;
+
+ if (inlineImg) {
+ str->reset();
+ j = height * ((width + 7) / 8);
+ for (i = 0; i < j; ++i)
+ str->getChar();
+ }
+}
+
+void OutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GfxImageColorMap *colorMap,
+ int *maskColors, GBool inlineImg) {
+ int i, j;
+
+ if (inlineImg) {
+ str->reset();
+ j = height * ((width * colorMap->getNumPixelComps() *
+ colorMap->getBits() + 7) / 8);
+ for (i = 0; i < j; ++i)
+ str->getChar();
+ }
+}
+
+#if OPI_SUPPORT
+void OutputDev::opiBegin(GfxState *state, Dict *opiDict) {
+}
+
+void OutputDev::opiEnd(GfxState *state, Dict *opiDict) {
+}
+#endif
diff --git a/pdftops/OutputDev.h b/pdftops/OutputDev.h
new file mode 100644
index 000000000..c332fa933
--- /dev/null
+++ b/pdftops/OutputDev.h
@@ -0,0 +1,140 @@
+//========================================================================
+//
+// OutputDev.h
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifndef OUTPUTDEV_H
+#define OUTPUTDEV_H
+
+#ifdef __GNUC__
+#pragma interface
+#endif
+
+#include "gtypes.h"
+
+class GString;
+class GfxState;
+class GfxColorSpace;
+class GfxImageColorMap;
+class Stream;
+class Link;
+class Catalog;
+
+//------------------------------------------------------------------------
+// OutputDev
+//------------------------------------------------------------------------
+
+class OutputDev {
+public:
+
+ // Constructor.
+ OutputDev() {}
+
+ // Destructor.
+ virtual ~OutputDev() {}
+
+ //----- get info about output device
+
+ // Does this device use upside-down coordinates?
+ // (Upside-down means (0,0) is the top left corner of the page.)
+ virtual GBool upsideDown() = 0;
+
+ // Does this device use drawChar() or drawString()?
+ virtual GBool useDrawChar() = 0;
+
+ //----- initialization and control
+
+ // Set default transform matrix.
+ virtual void setDefaultCTM(double *ctm);
+
+ // Start a page.
+ virtual void startPage(int pageNum, GfxState *state) {}
+
+ // End a page.
+ virtual void endPage() {}
+
+ // Dump page contents to display.
+ virtual void dump() {}
+
+ //----- coordinate conversion
+
+ // Convert between device and user coordinates.
+ virtual void cvtDevToUser(int dx, int dy, double *ux, double *uy);
+ virtual void cvtUserToDev(double ux, double uy, int *dx, int *dy);
+
+ //----- link borders
+ virtual void drawLink(Link *link, Catalog *catalog) {}
+
+ //----- save/restore graphics state
+ virtual void saveState(GfxState *state) {}
+ virtual void restoreState(GfxState *state) {}
+
+ //----- update graphics state
+ virtual void updateAll(GfxState *state);
+ virtual void updateCTM(GfxState *state, double m11, double m12,
+ double m21, double m22, double m31, double m32) {}
+ virtual void updateLineDash(GfxState *state) {}
+ virtual void updateFlatness(GfxState *state) {}
+ virtual void updateLineJoin(GfxState *state) {}
+ virtual void updateLineCap(GfxState *state) {}
+ virtual void updateMiterLimit(GfxState *state) {}
+ virtual void updateLineWidth(GfxState *state) {}
+ virtual void updateFillColor(GfxState *state) {}
+ virtual void updateStrokeColor(GfxState *state) {}
+ virtual void updateFillOpacity(GfxState *state) {}
+ virtual void updateStrokeOpacity(GfxState *state) {}
+
+ //----- update text state
+ virtual void updateFont(GfxState *state) {}
+ virtual void updateTextMat(GfxState *state) {}
+ virtual void updateCharSpace(GfxState *state) {}
+ virtual void updateRender(GfxState *state) {}
+ virtual void updateRise(GfxState *state) {}
+ virtual void updateWordSpace(GfxState *state) {}
+ virtual void updateHorizScaling(GfxState *state) {}
+ virtual void updateTextPos(GfxState *state) {}
+ virtual void updateTextShift(GfxState *state, double shift) {}
+
+ //----- path painting
+ virtual void stroke(GfxState *state) {}
+ virtual void fill(GfxState *state) {}
+ virtual void eoFill(GfxState *state) {}
+
+ //----- path clipping
+ virtual void clip(GfxState *state) {}
+ virtual void eoClip(GfxState *state) {}
+
+ //----- text drawing
+ virtual void beginString(GfxState *state, GString *s) {}
+ virtual void endString(GfxState *state) {}
+ virtual void drawChar(GfxState *state, double x, double y,
+ double dx, double dy, Guchar c) {}
+ virtual void drawChar16(GfxState *state, double x, double y,
+ double dx, double dy, int c) {}
+ virtual void drawString(GfxState *state, GString *s) {}
+ virtual void drawString16(GfxState *state, GString *s) {}
+
+ //----- image drawing
+ virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GBool invert,
+ GBool inlineImg);
+ virtual void drawImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GfxImageColorMap *colorMap,
+ int *maskColors, GBool inlineImg);
+
+#if OPI_SUPPORT
+ //----- OPI functions
+ virtual void opiBegin(GfxState *state, Dict *opiDict);
+ virtual void opiEnd(GfxState *state, Dict *opiDict);
+#endif
+
+private:
+
+ double defCTM[6]; // default coordinate transform matrix
+ double defICTM[6]; // inverse of default CTM
+};
+
+#endif
diff --git a/pdftops/PDFDoc.cxx b/pdftops/PDFDoc.cxx
new file mode 100644
index 000000000..ae0428054
--- /dev/null
+++ b/pdftops/PDFDoc.cxx
@@ -0,0 +1,251 @@
+//========================================================================
+//
+// PDFDoc.cc
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include "GString.h"
+#include "config.h"
+#include "Page.h"
+#include "Catalog.h"
+#include "Stream.h"
+#include "XRef.h"
+#include "Link.h"
+#include "OutputDev.h"
+#include "Params.h"
+#include "Error.h"
+#include "Lexer.h"
+#include "Parser.h"
+#include "PDFDoc.h"
+
+//------------------------------------------------------------------------
+
+#define headerSearchSize 1024 // read this many bytes at beginning of
+ // file to look for '%PDF'
+
+//------------------------------------------------------------------------
+// PDFDoc
+//------------------------------------------------------------------------
+
+PDFDoc::PDFDoc(GString *fileNameA, GString *ownerPassword,
+ GString *userPassword, GBool printCommandsA) {
+ Object obj;
+ GString *fileName2;
+
+ ok = gFalse;
+
+ file = NULL;
+ str = NULL;
+ xref = NULL;
+ catalog = NULL;
+ links = NULL;
+ printCommands = printCommandsA;
+
+ // try to open file
+ fileName = fileNameA;
+ fileName2 = NULL;
+#ifdef VMS
+ if (!(file = fopen(fileName->getCString(), "rb", "ctx=stm"))) {
+ error(-1, "Couldn't open file '%s'", fileName->getCString());
+ return;
+ }
+#else
+ if (!(file = fopen(fileName->getCString(), "rb"))) {
+ fileName2 = fileName->copy();
+ fileName2->lowerCase();
+ if (!(file = fopen(fileName2->getCString(), "rb"))) {
+ fileName2->upperCase();
+ if (!(file = fopen(fileName2->getCString(), "rb"))) {
+ error(-1, "Couldn't open file '%s'", fileName->getCString());
+ delete fileName2;
+ return;
+ }
+ }
+ delete fileName2;
+ }
+#endif
+
+ // create stream
+ obj.initNull();
+ str = new FileStream(file, 0, -1, &obj);
+
+ ok = setup(ownerPassword, userPassword);
+}
+
+PDFDoc::PDFDoc(BaseStream *strA, GString *ownerPassword,
+ GString *userPassword, GBool printCommandsA) {
+ ok = gFalse;
+ fileName = NULL;
+ file = NULL;
+ str = strA;
+ xref = NULL;
+ catalog = NULL;
+ links = NULL;
+ printCommands = printCommandsA;
+ ok = setup(ownerPassword, userPassword);
+}
+
+GBool PDFDoc::setup(GString *ownerPassword, GString *userPassword) {
+ // check header
+ checkHeader();
+
+ // read xref table
+ xref = new XRef(str, ownerPassword, userPassword);
+ if (!xref->isOk()) {
+ error(-1, "Couldn't read xref table");
+ return gFalse;
+ }
+
+ // read catalog
+ catalog = new Catalog(xref, printCommands);
+ if (!catalog->isOk()) {
+ error(-1, "Couldn't read page catalog");
+ return gFalse;
+ }
+
+ // done
+ return gTrue;
+}
+
+PDFDoc::~PDFDoc() {
+ if (catalog) {
+ delete catalog;
+ }
+ if (xref) {
+ delete xref;
+ }
+ if (str) {
+ delete str;
+ }
+ if (file) {
+ fclose(file);
+ }
+ if (fileName) {
+ delete fileName;
+ }
+ if (links) {
+ delete links;
+ }
+}
+
+// Check for a PDF header on this stream. Skip past some garbage
+// if necessary.
+void PDFDoc::checkHeader() {
+ char hdrBuf[headerSearchSize+1];
+ char *p;
+ int i;
+
+ pdfVersion = 0;
+ for (i = 0; i < headerSearchSize; ++i) {
+ hdrBuf[i] = str->getChar();
+ }
+ hdrBuf[headerSearchSize] = '\0';
+ for (i = 0; i < headerSearchSize - 5; ++i) {
+ if (!strncmp(&hdrBuf[i], "%PDF-", 5)) {
+ break;
+ }
+ }
+ if (i >= headerSearchSize - 5) {
+ error(-1, "May not be a PDF file (continuing anyway)");
+ return;
+ }
+ str->moveStart(i);
+ p = strtok(&hdrBuf[i+5], " \t\n\r");
+ pdfVersion = atof(p);
+ if (!(hdrBuf[i+5] >= '0' && hdrBuf[i+5] <= '9') ||
+ pdfVersion > supportedPDFVersionNum + 0.0001) {
+ error(-1, "PDF version %s -- xpdf supports version %s"
+ " (continuing anyway)", p, supportedPDFVersionStr);
+ }
+}
+
+void PDFDoc::displayPage(OutputDev *out, int page, double zoom,
+ int rotate, GBool doLinks) {
+ Page *p;
+
+ if (printCommands) {
+ printf("***** page %d *****\n", page);
+ }
+ p = catalog->getPage(page);
+ if (doLinks) {
+ if (links) {
+ delete links;
+ }
+ getLinks(p);
+ p->display(out, zoom, rotate, links, catalog);
+ } else {
+ p->display(out, zoom, rotate, NULL, catalog);
+ }
+}
+
+void PDFDoc::displayPages(OutputDev *out, int firstPage, int lastPage,
+ int zoom, int rotate, GBool doLinks) {
+ int page;
+
+ for (page = firstPage; page <= lastPage; ++page) {
+ displayPage(out, page, zoom, rotate, doLinks);
+ }
+}
+
+GBool PDFDoc::isLinearized() {
+ Parser *parser;
+ Object obj1, obj2, obj3, obj4, obj5;
+ GBool lin;
+
+ lin = gFalse;
+ obj1.initNull();
+ parser = new Parser(xref, new Lexer(xref, str->makeSubStream(str->getStart(),
+ -1, &obj1)));
+ parser->getObj(&obj1);
+ parser->getObj(&obj2);
+ parser->getObj(&obj3);
+ parser->getObj(&obj4);
+ if (obj1.isInt() && obj2.isInt() && obj3.isCmd("obj") &&
+ obj4.isDict()) {
+ obj4.dictLookup("Linearized", &obj5);
+ if (obj5.isNum() && obj5.getNum() > 0) {
+ lin = gTrue;
+ }
+ obj5.free();
+ }
+ obj4.free();
+ obj3.free();
+ obj2.free();
+ obj1.free();
+ delete parser;
+ return lin;
+}
+
+GBool PDFDoc::saveAs(GString *name) {
+ FILE *f;
+ int c;
+
+ if (!(f = fopen(name->getCString(), "wb"))) {
+ error(-1, "Couldn't open file '%s'", name->getCString());
+ return gFalse;
+ }
+ str->reset();
+ while ((c = str->getChar()) != EOF) {
+ fputc(c, f);
+ }
+ str->close();
+ fclose(f);
+ return gTrue;
+}
+
+void PDFDoc::getLinks(Page *page) {
+ Object obj;
+
+ links = new Links(page->getAnnots(&obj), catalog->getBaseURI());
+ obj.free();
+}
diff --git a/pdftops/PDFDoc.h b/pdftops/PDFDoc.h
new file mode 100644
index 000000000..c693e991a
--- /dev/null
+++ b/pdftops/PDFDoc.h
@@ -0,0 +1,135 @@
+//========================================================================
+//
+// PDFDoc.h
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifndef PDFDOC_H
+#define PDFDOC_H
+
+#ifdef __GNUC__
+#pragma interface
+#endif
+
+#include <stdio.h>
+#include "XRef.h"
+#include "Link.h"
+#include "Catalog.h"
+#include "Page.h"
+
+class GString;
+class BaseStream;
+class OutputDev;
+class Links;
+class LinkAction;
+class LinkDest;
+
+//------------------------------------------------------------------------
+// PDFDoc
+//------------------------------------------------------------------------
+
+class PDFDoc {
+public:
+
+ PDFDoc(GString *fileNameA, GString *ownerPassword = NULL,
+ GString *userPassword = NULL, GBool printCommandsA = gFalse);
+ PDFDoc(BaseStream *strA, GString *ownerPassword = NULL,
+ GString *userPassword = NULL, GBool printCommandsA = gFalse);
+ ~PDFDoc();
+
+ // Was PDF document successfully opened?
+ GBool isOk() { return ok; }
+
+ // Get file name.
+ GString *getFileName() { return fileName; }
+
+ // Get the xref table.
+ XRef *getXRef() { return xref; }
+
+ // Get catalog.
+ Catalog *getCatalog() { return catalog; }
+
+ // Get base stream.
+ BaseStream *getBaseStream() { return str; }
+
+ // Get page parameters.
+ double getPageWidth(int page)
+ { return catalog->getPage(page)->getWidth(); }
+ double getPageHeight(int page)
+ { return catalog->getPage(page)->getHeight(); }
+ int getPageRotate(int page)
+ { return catalog->getPage(page)->getRotate(); }
+
+ // Get number of pages.
+ int getNumPages() { return catalog->getNumPages(); }
+
+ // Display a page.
+ void displayPage(OutputDev *out, int page, double zoom,
+ int rotate, GBool doLinks);
+
+ // Display a range of pages.
+ void displayPages(OutputDev *out, int firstPage, int lastPage,
+ int zoom, int rotate, GBool doLinks);
+
+ // Find a page, given its object ID. Returns page number, or 0 if
+ // not found.
+ int findPage(int num, int gen) { return catalog->findPage(num, gen); }
+
+ // If point <x>,<y> is in a link, return the associated action;
+ // else return NULL.
+ LinkAction *findLink(double x, double y) { return links->find(x, y); }
+
+ // Return true if <x>,<y> is in a link.
+ GBool onLink(double x, double y) { return links->onLink(x, y); }
+
+ // Find a named destination. Returns the link destination, or
+ // NULL if <name> is not a destination.
+ LinkDest *findDest(GString *name)
+ { return catalog->findDest(name); }
+
+ // Is the file encrypted?
+ GBool isEncrypted() { return xref->isEncrypted(); }
+
+ // Check various permissions.
+ GBool okToPrint(GBool ignoreOwnerPW = gFalse)
+ { return xref->okToPrint(ignoreOwnerPW); }
+ GBool okToChange(GBool ignoreOwnerPW = gFalse)
+ { return xref->okToChange(ignoreOwnerPW); }
+ GBool okToCopy(GBool ignoreOwnerPW = gFalse)
+ { return xref->okToCopy(ignoreOwnerPW); }
+ GBool okToAddNotes(GBool ignoreOwnerPW = gFalse)
+ { return xref->okToAddNotes(ignoreOwnerPW); }
+
+ // Is this document linearized?
+ GBool isLinearized();
+
+ // Return the document's Info dictionary (if any).
+ Object *getDocInfo(Object *obj) { return xref->getDocInfo(obj); }
+
+ // Return the PDF version specified by the file.
+ double getPDFVersion() { return pdfVersion; }
+
+ // Save this file with another name.
+ GBool saveAs(GString *name);
+
+private:
+
+ GBool setup(GString *ownerPassword, GString *userPassword);
+ void checkHeader();
+ void getLinks(Page *page);
+
+ GString *fileName;
+ FILE *file;
+ BaseStream *str;
+ double pdfVersion;
+ XRef *xref;
+ Catalog *catalog;
+ Links *links;
+ GBool printCommands;
+
+ GBool ok;
+};
+
+#endif
diff --git a/pdftops/PSOutputDev.cxx b/pdftops/PSOutputDev.cxx
new file mode 100644
index 000000000..b62a23d24
--- /dev/null
+++ b/pdftops/PSOutputDev.cxx
@@ -0,0 +1,2562 @@
+//========================================================================
+//
+// PSOutputDev.cc
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <signal.h>
+#include <math.h>
+#include "GString.h"
+#include "config.h"
+#include "Object.h"
+#include "Error.h"
+#include "Function.h"
+#include "GfxState.h"
+#include "GfxFont.h"
+#include "FontFile.h"
+#include "Catalog.h"
+#include "Page.h"
+#include "Stream.h"
+#include "FormWidget.h"
+#include "PSOutputDev.h"
+
+#if JAPANESE_SUPPORT
+#include "Japan12ToRKSJ.h"
+#endif
+
+#ifdef MACOS
+// needed for setting type/creator of MacOS files
+#include "ICSupport.h"
+#endif
+
+//------------------------------------------------------------------------
+// PostScript prolog and setup
+//------------------------------------------------------------------------
+
+static char *prolog[] = {
+ "/xpdf 75 dict def xpdf begin",
+ "% PDF special state",
+ "/pdfDictSize 14 def",
+ "/pdfSetup {",
+ " 2 array astore",
+ " /setpagedevice where {",
+ " pop 3 dict dup begin",
+ " exch /PageSize exch def",
+ " /ImagingBBox null def",
+ " /Policies 1 dict dup begin /PageSize 3 def end def",
+ " end setpagedevice",
+ " } {",
+ " pop",
+ " } ifelse",
+ "} def",
+ "/pdfStartPage {",
+ " pdfDictSize dict begin",
+ " /pdfFill [0] def",
+ " /pdfStroke [0] def",
+ " /pdfLastFill false def",
+ " /pdfLastStroke false def",
+ " /pdfTextMat [1 0 0 1 0 0] def",
+ " /pdfFontSize 0 def",
+ " /pdfCharSpacing 0 def",
+ " /pdfTextRender 0 def",
+ " /pdfTextRise 0 def",
+ " /pdfWordSpacing 0 def",
+ " /pdfHorizScaling 1 def",
+ "} def",
+ "/pdfEndPage { end } def",
+ "% separation convention operators",
+ "/findcmykcustomcolor where {",
+ " pop",
+ "}{",
+ " /findcmykcustomcolor { 5 array astore } def",
+ "} ifelse",
+ "/setcustomcolor where {",
+ " pop",
+ "}{",
+ " /setcustomcolor {",
+ " exch",
+ " [ exch /Separation exch dup 4 get exch /DeviceCMYK exch",
+ " 0 4 getinterval cvx",
+ " [ exch /dup load exch { mul exch dup } /forall load",
+ " /pop load dup ] cvx",
+ " ] setcolorspace setcolor",
+ " } def",
+ "} ifelse",
+ "/customcolorimage where {",
+ " pop",
+ "}{",
+ " /customcolorimage {",
+ " gsave",
+ " [ exch /Separation exch dup 4 get exch /DeviceCMYK exch",
+ " 0 4 getinterval cvx",
+ " [ exch /dup load exch { mul exch dup } /forall load",
+ " /pop load dup ] cvx",
+ " ] setcolorspace",
+ " 10 dict begin",
+ " /ImageType 1 def",
+ " /DataSource exch def",
+ " /ImageMatrix exch def",
+ " /BitsPerComponent exch def",
+ " /Height exch def",
+ " /Width exch def",
+ " /Decode [1 0] def",
+ " currentdict end",
+ " image",
+ " grestore",
+ " } def",
+ "} ifelse",
+ "% PDF color state",
+ "/sCol {",
+ " pdfLastStroke not {",
+ " pdfStroke aload length",
+ " dup 1 eq {",
+ " pop setgray",
+ " }{",
+ " dup 3 eq {",
+ " pop setrgbcolor",
+ " }{",
+ " 4 eq {",
+ " setcmykcolor",
+ " }{",
+ " findcmykcustomcolor exch setcustomcolor",
+ " } ifelse",
+ " } ifelse",
+ " } ifelse",
+ " /pdfLastStroke true def /pdfLastFill false def",
+ " } if",
+ "} def",
+ "/fCol {",
+ " pdfLastFill not {",
+ " pdfFill aload length",
+ " dup 1 eq {",
+ " pop setgray",
+ " }{",
+ " dup 3 eq {",
+ " pop setrgbcolor",
+ " }{",
+ " 4 eq {",
+ " setcmykcolor",
+ " }{",
+ " findcmykcustomcolor exch setcustomcolor",
+ " } ifelse",
+ " } ifelse",
+ " } ifelse",
+ " /pdfLastFill true def /pdfLastStroke false def",
+ " } if",
+ "} def",
+ "% build a font",
+ "/pdfMakeFont {",
+ " 4 3 roll findfont",
+ " 4 2 roll matrix scale makefont",
+ " dup length dict begin",
+ " { 1 index /FID ne { def } { pop pop } ifelse } forall",
+ " /Encoding exch def",
+ " currentdict",
+ " end",
+ " definefont pop",
+ "} def",
+ "/pdfMakeFont16 { findfont definefont pop } def",
+ "% graphics state operators",
+ "/q { gsave pdfDictSize dict begin } def",
+ "/Q { end grestore } def",
+ "/cm { concat } def",
+ "/d { setdash } def",
+ "/i { setflat } def",
+ "/j { setlinejoin } def",
+ "/J { setlinecap } def",
+ "/M { setmiterlimit } def",
+ "/w { setlinewidth } def",
+ "% color operators",
+ "/g { dup 1 array astore /pdfFill exch def setgray",
+ " /pdfLastFill true def /pdfLastStroke false def } def",
+ "/G { dup 1 array astore /pdfStroke exch def setgray",
+ " /pdfLastStroke true def /pdfLastFill false def } def",
+ "/rg { 3 copy 3 array astore /pdfFill exch def setrgbcolor",
+ " /pdfLastFill true def /pdfLastStroke false def } def",
+ "/RG { 3 copy 3 array astore /pdfStroke exch def setrgbcolor",
+ " /pdfLastStroke true def /pdfLastFill false def } def",
+ "/k { 4 copy 4 array astore /pdfFill exch def setcmykcolor",
+ " /pdfLastFill true def /pdfLastStroke false def } def",
+ "/K { 4 copy 4 array astore /pdfStroke exch def setcmykcolor",
+ " /pdfLastStroke true def /pdfLastFill false def } def",
+ "/ck { 6 copy 6 array astore /pdfFill exch def",
+ " findcmykcustomcolor exch setcustomcolor",
+ " /pdfLastFill true def /pdfLastStroke false def } def",
+ "/CK { 6 copy 6 array astore /pdfStroke exch def",
+ " findcmykcustomcolor exch setcustomcolor",
+ " /pdfLastStroke true def /pdfLastFill false def } def",
+ "% path segment operators",
+ "/m { moveto } def",
+ "/l { lineto } def",
+ "/c { curveto } def",
+ "/re { 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto",
+ " neg 0 rlineto closepath } def",
+ "/h { closepath } def",
+ "% path painting operators",
+ "/S { sCol stroke } def",
+ "/f { fCol fill } def",
+ "/f* { fCol eofill } def",
+ "% clipping operators",
+ "/W { clip newpath } def",
+ "/W* { eoclip newpath } def",
+ "% text state operators",
+ "/Tc { /pdfCharSpacing exch def } def",
+ "/Tf { dup /pdfFontSize exch def",
+ " dup pdfHorizScaling mul exch matrix scale",
+ " pdfTextMat matrix concatmatrix dup 4 0 put dup 5 0 put",
+ " exch findfont exch makefont setfont } def",
+ "/Tr { /pdfTextRender exch def } def",
+ "/Ts { /pdfTextRise exch def } def",
+ "/Tw { /pdfWordSpacing exch def } def",
+ "/Tz { /pdfHorizScaling exch def } def",
+ "% text positioning operators",
+ "/Td { pdfTextMat transform moveto } def",
+ "/Tm { /pdfTextMat exch def } def",
+ "% text string operators",
+ "/Tj { pdfTextRender 1 and 0 eq { fCol } { sCol } ifelse",
+ " 0 pdfTextRise pdfTextMat dtransform rmoveto",
+ " pdfFontSize mul pdfHorizScaling mul",
+ " 1 index stringwidth pdfTextMat idtransform pop",
+ " sub 1 index length dup 0 ne { div } { pop pop 0 } ifelse",
+ " pdfWordSpacing pdfHorizScaling mul 0 pdfTextMat dtransform 32",
+ " 4 3 roll pdfCharSpacing pdfHorizScaling mul add 0",
+ " pdfTextMat dtransform",
+ " 6 5 roll awidthshow",
+ " 0 pdfTextRise neg pdfTextMat dtransform rmoveto } def",
+ "/TJm { pdfFontSize 0.001 mul mul neg 0",
+ " pdfTextMat dtransform rmoveto } def",
+ "% Level 1 image operators",
+ "/pdfIm1 {",
+ " /pdfImBuf1 4 index string def",
+ " { currentfile pdfImBuf1 readhexstring pop } image",
+ "} def",
+ "/pdfIm1Sep {",
+ " /pdfImBuf1 4 index string def",
+ " /pdfImBuf2 4 index string def",
+ " /pdfImBuf3 4 index string def",
+ " /pdfImBuf4 4 index string def",
+ " { currentfile pdfImBuf1 readhexstring pop }",
+ " { currentfile pdfImBuf2 readhexstring pop }",
+ " { currentfile pdfImBuf3 readhexstring pop }",
+ " { currentfile pdfImBuf4 readhexstring pop }",
+ " true 4 colorimage",
+ "} def",
+ "/pdfImM1 {",
+ " /pdfImBuf1 4 index 7 add 8 idiv string def",
+ " { currentfile pdfImBuf1 readhexstring pop } imagemask",
+ "} def",
+ "% Level 2 image operators",
+ "/pdfImBuf 100 string def",
+ "/pdfIm {",
+ " image",
+ " { currentfile pdfImBuf readline",
+ " not { pop exit } if",
+ " (%-EOD-) eq { exit } if } loop",
+ "} def",
+ "/pdfImSep {",
+ " findcmykcustomcolor exch",
+ " dup /Width get /pdfImBuf1 exch string def",
+ " begin Width Height BitsPerComponent ImageMatrix DataSource end",
+ " /pdfImData exch def",
+ " { pdfImData pdfImBuf1 readstring pop",
+ " 0 1 2 index length 1 sub {",
+ " 1 index exch 2 copy get 255 exch sub put",
+ " } for }",
+ " 6 5 roll customcolorimage",
+ " { currentfile pdfImBuf readline",
+ " not { pop exit } if",
+ " (%-EOD-) eq { exit } if } loop",
+ "} def",
+ "/pdfImM {",
+ " fCol imagemask",
+ " { currentfile pdfImBuf readline",
+ " not { pop exit } if",
+ " (%-EOD-) eq { exit } if } loop",
+ "} def",
+ "end",
+ NULL
+};
+
+//------------------------------------------------------------------------
+// Fonts
+//------------------------------------------------------------------------
+
+struct PSFont {
+ char *name; // PDF name
+ char *psName; // PostScript name
+};
+
+struct PSSubstFont {
+ char *psName; // PostScript name
+ double mWidth; // width of 'm' character
+};
+
+static PSFont psFonts[] = {
+ {"Courier", "Courier"},
+ {"Courier-Bold", "Courier-Bold"},
+ {"Courier-Oblique", "Courier-Oblique"},
+ {"Courier-BoldOblique", "Courier-BoldOblique"},
+ {"Helvetica", "Helvetica"},
+ {"Helvetica-Bold", "Helvetica-Bold"},
+ {"Helvetica-Oblique", "Helvetica-Oblique"},
+ {"Helvetica-BoldOblique", "Helvetica-BoldOblique"},
+ {"Symbol", "Symbol"},
+ {"Times-Roman", "Times-Roman"},
+ {"Times-Bold", "Times-Bold"},
+ {"Times-Italic", "Times-Italic"},
+ {"Times-BoldItalic", "Times-BoldItalic"},
+ {"ZapfDingbats", "ZapfDingbats"},
+ {NULL}
+};
+
+static PSSubstFont psSubstFonts[] = {
+ {"Helvetica", 0.833},
+ {"Helvetica-Oblique", 0.833},
+ {"Helvetica-Bold", 0.889},
+ {"Helvetica-BoldOblique", 0.889},
+ {"Times-Roman", 0.788},
+ {"Times-Italic", 0.722},
+ {"Times-Bold", 0.833},
+ {"Times-BoldItalic", 0.778},
+ {"Courier", 0.600},
+ {"Courier-Oblique", 0.600},
+ {"Courier-Bold", 0.600},
+ {"Courier-BoldOblique", 0.600}
+};
+
+//------------------------------------------------------------------------
+// process colors
+//------------------------------------------------------------------------
+
+#define psProcessCyan 1
+#define psProcessMagenta 2
+#define psProcessYellow 4
+#define psProcessBlack 8
+#define psProcessCMYK 15
+
+//------------------------------------------------------------------------
+// PSOutCustomColor
+//------------------------------------------------------------------------
+
+class PSOutCustomColor {
+public:
+
+ PSOutCustomColor(double cA, double mA,
+ double yA, double kA, GString *nameA);
+ ~PSOutCustomColor();
+
+ double c, m, y, k;
+ GString *name;
+ PSOutCustomColor *next;
+};
+
+PSOutCustomColor::PSOutCustomColor(double cA, double mA,
+ double yA, double kA, GString *nameA) {
+ c = cA;
+ m = mA;
+ y = yA;
+ k = kA;
+ name = nameA;
+ next = NULL;
+}
+
+PSOutCustomColor::~PSOutCustomColor() {
+ delete name;
+}
+
+//------------------------------------------------------------------------
+// PSOutputDev
+//------------------------------------------------------------------------
+
+extern "C" {
+typedef void (*SignalFunc)(int);
+}
+
+PSOutputDev::PSOutputDev(char *fileName, XRef *xrefA, Catalog *catalog,
+ int firstPage, int lastPage,
+ PSOutLevel levelA, PSOutMode modeA, GBool doOPIA,
+ GBool embedType1A, GBool embedTrueTypeA,
+ int paperWidthA, int paperHeightA) {
+ Page *page;
+ PDFRectangle *box;
+ Dict *resDict;
+ FormWidgets *formWidgets;
+ char **p;
+ int pg;
+ Object obj1, obj2;
+ int i;
+
+ // initialize
+ xref = xrefA;
+ level = levelA;
+ mode = modeA;
+ doOPI = doOPIA;
+ embedType1 = embedType1A;
+ embedTrueType = embedTrueTypeA;
+ paperWidth = paperWidthA;
+ paperHeight = paperHeightA;
+ fontIDs = NULL;
+ fontFileIDs = NULL;
+ fontFileNames = NULL;
+ embFontList = NULL;
+ f = NULL;
+ if (mode == psModeForm) {
+ lastPage = firstPage;
+ }
+ processColors = 0;
+ customColors = NULL;
+
+ // open file or pipe
+ ok = gTrue;
+ if (!strcmp(fileName, "-")) {
+ fileType = psStdout;
+ f = stdout;
+ } else if (fileName[0] == '|') {
+ fileType = psPipe;
+#ifdef HAVE_POPEN
+#ifndef WIN32
+ signal(SIGPIPE, (SignalFunc)SIG_IGN);
+#endif
+ if (!(f = popen(fileName + 1, "w"))) {
+ error(-1, "Couldn't run print command '%s'", fileName);
+ ok = gFalse;
+ return;
+ }
+#else
+ error(-1, "Print commands are not supported ('%s')", fileName);
+ ok = gFalse;
+ return;
+#endif
+ } else {
+ fileType = psFile;
+ if (!(f = fopen(fileName, "w"))) {
+ error(-1, "Couldn't open PostScript file '%s'", fileName);
+ ok = gFalse;
+ return;
+ }
+ }
+
+ // initialize fontIDs, fontFileIDs, and fontFileNames lists
+ fontIDSize = 64;
+ fontIDLen = 0;
+ fontIDs = (Ref *)gmalloc(fontIDSize * sizeof(Ref));
+ fontFileIDSize = 64;
+ fontFileIDLen = 0;
+ fontFileIDs = (Ref *)gmalloc(fontFileIDSize * sizeof(Ref));
+ fontFileNameSize = 64;
+ fontFileNameLen = 0;
+ fontFileNames = (GString **)gmalloc(fontFileNameSize * sizeof(GString *));
+
+ // initialize embedded font resource comment list
+ embFontList = new GString();
+
+ // write header
+ switch (mode) {
+ case psModePS:
+ writePS("%%!PS-Adobe-3.0\n");
+ writePS("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion);
+ writePS("%%%%LanguageLevel: %d\n",
+ (level == psLevel1 || level == psLevel1Sep) ? 1 : 2);
+ if (level == psLevel1Sep || level == psLevel2Sep) {
+ writePS("%%%%DocumentProcessColors: (atend)\n");
+ writePS("%%%%DocumentCustomColors: (atend)\n");
+ }
+ writePS("%%%%DocumentMedia: plain %d %d 0 () ()\n",
+ paperWidth, paperHeight);
+ writePS("%%%%Pages: %d\n", lastPage - firstPage + 1);
+ writePS("%%%%EndComments\n");
+ writePS("%%%%BeginDefaults\n");
+ writePS("%%%%PageMedia: plain\n");
+ writePS("%%%%EndDefaults\n");
+ break;
+ case psModeEPS:
+ writePS("%%!PS-Adobe-3.0 EPSF-3.0\n");
+ writePS("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion);
+ writePS("%%%%LanguageLevel: %d\n",
+ (level == psLevel1 || level == psLevel1Sep) ? 1 : 2);
+ if (level == psLevel1Sep || level == psLevel2Sep) {
+ writePS("%%%%DocumentProcessColors: (atend)\n");
+ writePS("%%%%DocumentCustomColors: (atend)\n");
+ }
+ page = catalog->getPage(firstPage);
+ box = page->getBox();
+ writePS("%%%%BoundingBox: %d %d %d %d\n",
+ (int)floor(box->x1), (int)floor(box->y1),
+ (int)ceil(box->x2), (int)ceil(box->y2));
+ if (floor(box->x1) != ceil(box->x1) ||
+ floor(box->y1) != ceil(box->y1) ||
+ floor(box->x2) != ceil(box->x2) ||
+ floor(box->y2) != ceil(box->y2)) {
+ writePS("%%%%HiResBoundingBox: %g %g %g %g\n",
+ box->x1, box->y1, box->x2, box->y2);
+ }
+ writePS("%%%%DocumentSuppliedResources: (atend)\n");
+ writePS("%%%%EndComments\n");
+ break;
+ case psModeForm:
+ writePS("%%!PS-Adobe-3.0 Resource-Form\n");
+ writePS("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion);
+ writePS("%%%%LanguageLevel: %d\n",
+ (level == psLevel1 || level == psLevel1Sep) ? 1 : 2);
+ if (level == psLevel1Sep || level == psLevel2Sep) {
+ writePS("%%%%DocumentProcessColors: (atend)\n");
+ writePS("%%%%DocumentCustomColors: (atend)\n");
+ }
+ writePS("%%%%EndComments\n");
+ page = catalog->getPage(firstPage);
+ box = page->getBox();
+ writePS("32 dict dup begin\n");
+ writePS("/BBox [%d %d %d %d] def\n",
+ (int)box->x1, (int)box->y1, (int)box->x2, (int)box->y2);
+ writePS("/FormType 1 def\n");
+ writePS("/Matrix [1 0 0 1 0 0] def\n");
+ break;
+ }
+
+ // write prolog
+ if (mode != psModeForm) {
+ writePS("%%%%BeginProlog\n");
+ }
+ writePS("%%%%BeginResource: procset xpdf %s 0\n", xpdfVersion);
+ for (p = prolog; *p; ++p) {
+ writePS("%s\n", *p);
+ }
+ writePS("%%%%EndResource\n");
+ if (mode != psModeForm) {
+ writePS("%%%%EndProlog\n");
+ }
+
+ // set up fonts and images
+ type3Warning = gFalse;
+ if (mode == psModeForm) {
+ // swap the form and xpdf dicts
+ writePS("xpdf end begin dup begin\n");
+ } else {
+ writePS("%%%%BeginSetup\n");
+ writePS("xpdf begin\n");
+ }
+ for (pg = firstPage; pg <= lastPage; ++pg) {
+ page = catalog->getPage(pg);
+ if ((resDict = page->getResourceDict())) {
+ setupResources(resDict);
+ }
+ formWidgets = new FormWidgets(xref, page->getAnnots(&obj1));
+ obj1.free();
+ for (i = 0; i < formWidgets->getNumWidgets(); ++i) {
+ if (formWidgets->getWidget(i)->getAppearance(&obj1)->isStream()) {
+ obj1.streamGetDict()->lookup("Resources", &obj2);
+ if (obj2.isDict()) {
+ setupResources(obj2.getDict());
+ }
+ obj2.free();
+ }
+ obj1.free();
+ }
+ delete formWidgets;
+ }
+ if (mode != psModeForm) {
+#if OPI_SUPPORT
+ if (doOPI) {
+ writePS("/opiMatrix matrix currentmatrix def\n");
+ }
+#endif
+ if (mode != psModeEPS) {
+ writePS("%d %d pdfSetup\n", paperWidth, paperHeight);
+ }
+ writePS("%%%%EndSetup\n");
+ }
+
+ // initialize sequential page number
+ seqPage = 1;
+
+#if OPI_SUPPORT
+ // initialize OPI nesting levels
+ opi13Nest = 0;
+ opi20Nest = 0;
+#endif
+}
+
+PSOutputDev::~PSOutputDev() {
+ PSOutCustomColor *cc;
+ int i;
+
+ if (f) {
+ if (mode == psModeForm) {
+ writePS("/Foo exch /Form defineresource pop\n");
+ } else {
+ writePS("%%%%Trailer\n");
+ writePS("end\n");
+ writePS("%%%%DocumentSuppliedResources:\n");
+ writePS("%s", embFontList->getCString());
+ if (level == psLevel1Sep || level == psLevel2Sep) {
+ writePS("%%%%DocumentProcessColors:");
+ if (processColors & psProcessCyan) {
+ writePS(" Cyan");
+ }
+ if (processColors & psProcessMagenta) {
+ writePS(" Magenta");
+ }
+ if (processColors & psProcessYellow) {
+ writePS(" Yellow");
+ }
+ if (processColors & psProcessBlack) {
+ writePS(" Black");
+ }
+ writePS("\n");
+ writePS("%%%%DocumentCustomColors:");
+ for (cc = customColors; cc; cc = cc->next) {
+ writePS(" (%s)", cc->name->getCString());
+ }
+ writePS("\n");
+ writePS("%%%%CMYKCustomColor:\n");
+ for (cc = customColors; cc; cc = cc->next) {
+ writePS("%%%%+ %g %g %g %g (%s)\n",
+ cc->c, cc->m, cc->y, cc->k, cc->name->getCString());
+ }
+ }
+ writePS("%%%%EOF\n");
+ }
+ if (fileType == psFile) {
+#ifdef MACOS
+ ICS_MapRefNumAndAssign((short)f->handle);
+#endif
+ fclose(f);
+ }
+#ifdef HAVE_POPEN
+ else if (fileType == psPipe) {
+ pclose(f);
+#ifndef WIN32
+ signal(SIGPIPE, (SignalFunc)SIG_DFL);
+#endif
+ }
+#endif
+ }
+ if (embFontList) {
+ delete embFontList;
+ }
+ if (fontIDs) {
+ gfree(fontIDs);
+ }
+ if (fontFileIDs) {
+ gfree(fontFileIDs);
+ }
+ if (fontFileNames) {
+ for (i = 0; i < fontFileNameLen; ++i) {
+ delete fontFileNames[i];
+ }
+ gfree(fontFileNames);
+ }
+ while (customColors) {
+ cc = customColors;
+ customColors = cc->next;
+ delete cc;
+ }
+}
+
+void PSOutputDev::setupResources(Dict *resDict) {
+ Object xObjDict, xObj, resObj;
+ int i;
+
+ setupFonts(resDict);
+ setupImages(resDict);
+
+ resDict->lookup("XObject", &xObjDict);
+ if (xObjDict.isDict()) {
+ for (i = 0; i < xObjDict.dictGetLength(); ++i) {
+ xObjDict.dictGetVal(i, &xObj);
+ if (xObj.isStream()) {
+ xObj.streamGetDict()->lookup("Resources", &resObj);
+ if (resObj.isDict()) {
+ setupResources(resObj.getDict());
+ }
+ resObj.free();
+ }
+ xObj.free();
+ }
+ }
+ xObjDict.free();
+}
+
+void PSOutputDev::setupFonts(Dict *resDict) {
+ Object fontDict;
+ GfxFontDict *gfxFontDict;
+ GfxFont *font;
+ int i;
+
+ resDict->lookup("Font", &fontDict);
+ if (fontDict.isDict()) {
+ gfxFontDict = new GfxFontDict(xref, fontDict.getDict());
+ for (i = 0; i < gfxFontDict->getNumFonts(); ++i) {
+ font = gfxFontDict->getFont(i);
+ setupFont(font);
+ }
+ delete gfxFontDict;
+ }
+ fontDict.free();
+}
+
+void PSOutputDev::setupFont(GfxFont *font) {
+ Ref fontFileID;
+ GString *name;
+ char *psName;
+ char *charName;
+ double xs, ys;
+ GBool do16Bit;
+ int code;
+ double w1, w2;
+ double *fm;
+ int i, j;
+
+ // check if font is already set up
+ for (i = 0; i < fontIDLen; ++i) {
+ if (fontIDs[i].num == font->getID().num &&
+ fontIDs[i].gen == font->getID().gen)
+ return;
+ }
+
+ // add entry to fontIDs list
+ if (fontIDLen >= fontIDSize) {
+ fontIDSize += 64;
+ fontIDs = (Ref *)grealloc(fontIDs, fontIDSize * sizeof(Ref));
+ }
+ fontIDs[fontIDLen++] = font->getID();
+
+ xs = ys = 1;
+ do16Bit = gFalse;
+
+ // check for embedded Type 1 font
+ if (embedType1 && font->getType() == fontType1 &&
+ font->getEmbeddedFontID(&fontFileID)) {
+ psName = font->getEmbeddedFontName();
+ setupEmbeddedType1Font(&fontFileID, psName);
+
+ // check for external Type 1 font file
+ } else if (embedType1 && font->getType() == fontType1 &&
+ font->getExtFontFile()) {
+ // this assumes that the PS font name matches the PDF font name
+ psName = font->getName()->getCString();
+ setupEmbeddedType1Font(font->getExtFontFile(), psName);
+
+ // check for embedded Type 1C font
+ } else if (embedType1 && font->getType() == fontType1C &&
+ font->getEmbeddedFontID(&fontFileID)) {
+ psName = font->getEmbeddedFontName();
+ setupEmbeddedType1CFont(font, &fontFileID, psName);
+
+ // check for embedded TrueType font
+ } else if (embedTrueType && font->getType() == fontTrueType &&
+ font->getEmbeddedFontID(&fontFileID)) {
+ psName = font->getEmbeddedFontName();
+ setupEmbeddedTrueTypeFont(font, &fontFileID, psName);
+
+ // check for Japanese font
+ } else if (font->is16Bit() && font->getCharSet16() == font16AdobeJapan12) {
+ psName = "Ryumin-Light-RKSJ";
+ do16Bit = gTrue;
+
+ // do font substitution
+ } else {
+ if (!type3Warning && font->getType() == fontType3) {
+ error(-1, "This document uses Type 3 fonts - some text may not be correctly printed");
+ type3Warning = gTrue;
+ }
+ name = font->getName();
+ psName = NULL;
+ if (name) {
+ for (i = 0; psFonts[i].name; ++i) {
+ if (name->cmp(psFonts[i].name) == 0) {
+ psName = psFonts[i].psName;
+ break;
+ }
+ }
+ }
+ if (!psName) {
+ if (font->isFixedWidth())
+ i = 8;
+ else if (font->isSerif())
+ i = 4;
+ else
+ i = 0;
+ if (font->isBold())
+ i += 2;
+ if (font->isItalic())
+ i += 1;
+ psName = psSubstFonts[i].psName;
+ if ((code = font->getCharCode("m")) >= 0) {
+ w1 = font->getWidth(code);
+ } else {
+ w1 = 0;
+ }
+ w2 = psSubstFonts[i].mWidth;
+ xs = w1 / w2;
+ if (xs < 0.1) {
+ xs = 1;
+ }
+ if (font->getType() == fontType3) {
+ // This is a hack which makes it possible to substitute for some
+ // Type 3 fonts. The problem is that it's impossible to know what
+ // the base coordinate system used in the font is without actually
+ // rendering the font.
+ ys = xs;
+ fm = font->getFontMatrix();
+ if (fm[0] != 0) {
+ ys *= fm[3] / fm[0];
+ }
+ } else {
+ ys = 1;
+ }
+ }
+ }
+
+ // generate PostScript code to set up the font
+ if (do16Bit) {
+ writePS("/F%d_%d /%s pdfMakeFont16\n",
+ font->getID().num, font->getID().gen, psName);
+ } else {
+ writePS("/F%d_%d /%s %g %g\n",
+ font->getID().num, font->getID().gen, psName, xs, ys);
+ for (i = 0; i < 256; i += 8) {
+ writePS((i == 0) ? "[ " : " ");
+ for (j = 0; j < 8; ++j) {
+ charName = font->getCharName(i+j);
+ // this is a kludge for broken PDF files that encode char 32
+ // as .notdef
+ if (i+j == 32 && charName && !strcmp(charName, ".notdef")) {
+ charName = "space";
+ }
+ writePS("/%s", charName ? charName : ".notdef");
+ }
+ writePS((i == 256-8) ? "]\n" : "\n");
+ }
+ writePS("pdfMakeFont\n");
+ }
+}
+
+void PSOutputDev::setupEmbeddedType1Font(Ref *id, char *psName) {
+ static char hexChar[17] = "0123456789abcdef";
+ Object refObj, strObj, obj1, obj2;
+ Dict *dict;
+ int length1, length2;
+ int c;
+ int start[4];
+ GBool binMode;
+ int i;
+
+ // check if font is already embedded
+ for (i = 0; i < fontFileIDLen; ++i) {
+ if (fontFileIDs[i].num == id->num &&
+ fontFileIDs[i].gen == id->gen)
+ return;
+ }
+
+ // add entry to fontFileIDs list
+ if (fontFileIDLen >= fontFileIDSize) {
+ fontFileIDSize += 64;
+ fontFileIDs = (Ref *)grealloc(fontFileIDs, fontFileIDSize * sizeof(Ref));
+ }
+ fontFileIDs[fontFileIDLen++] = *id;
+
+ // get the font stream and info
+ refObj.initRef(id->num, id->gen);
+ refObj.fetch(xref, &strObj);
+ refObj.free();
+ if (!strObj.isStream()) {
+ error(-1, "Embedded font file object is not a stream");
+ goto err1;
+ }
+ if (!(dict = strObj.streamGetDict())) {
+ error(-1, "Embedded font stream is missing its dictionary");
+ goto err1;
+ }
+ dict->lookup("Length1", &obj1);
+ dict->lookup("Length2", &obj2);
+ if (!obj1.isInt() || !obj2.isInt()) {
+ error(-1, "Missing length fields in embedded font stream dictionary");
+ obj1.free();
+ obj2.free();
+ goto err1;
+ }
+ length1 = obj1.getInt();
+ length2 = obj2.getInt();
+ obj1.free();
+ obj2.free();
+
+ // beginning comment
+ writePS("%%%%BeginResource: font %s\n", psName);
+ embFontList->append("%%+ font ");
+ embFontList->append(psName);
+ embFontList->append("\n");
+
+ // copy ASCII portion of font
+ strObj.streamReset();
+ for (i = 0; i < length1 && (c = strObj.streamGetChar()) != EOF; ++i)
+ fputc(c, f);
+
+ // figure out if encrypted portion is binary or ASCII
+ binMode = gFalse;
+ for (i = 0; i < 4; ++i) {
+ start[i] = strObj.streamGetChar();
+ if (start[i] == EOF) {
+ error(-1, "Unexpected end of file in embedded font stream");
+ goto err1;
+ }
+ if (!((start[i] >= '0' && start[i] <= '9') ||
+ (start[i] >= 'A' && start[i] <= 'F') ||
+ (start[i] >= 'a' && start[i] <= 'f')))
+ binMode = gTrue;
+ }
+
+ // convert binary data to ASCII
+ if (binMode) {
+ for (i = 0; i < 4; ++i) {
+ fputc(hexChar[(start[i] >> 4) & 0x0f], f);
+ fputc(hexChar[start[i] & 0x0f], f);
+ }
+ while (i < length2) {
+ if ((c = strObj.streamGetChar()) == EOF)
+ break;
+ fputc(hexChar[(c >> 4) & 0x0f], f);
+ fputc(hexChar[c & 0x0f], f);
+ if (++i % 32 == 0)
+ fputc('\n', f);
+ }
+ if (i % 32 > 0)
+ fputc('\n', f);
+
+ // already in ASCII format -- just copy it
+ } else {
+ for (i = 0; i < 4; ++i)
+ fputc(start[i], f);
+ for (i = 4; i < length2; ++i) {
+ if ((c = strObj.streamGetChar()) == EOF)
+ break;
+ fputc(c, f);
+ }
+ }
+
+ // write padding and "cleartomark"
+ for (i = 0; i < 8; ++i)
+ writePS("00000000000000000000000000000000"
+ "00000000000000000000000000000000\n");
+ writePS("cleartomark\n");
+
+ // ending comment
+ writePS("%%%%EndResource\n");
+
+ err1:
+ strObj.streamClose();
+ strObj.free();
+}
+
+//~ This doesn't handle .pfb files or binary eexec data (which only
+//~ happens in pfb files?).
+void PSOutputDev::setupEmbeddedType1Font(GString *fileName, char *psName) {
+ FILE *fontFile;
+ int c;
+ int i;
+
+ // check if font is already embedded
+ for (i = 0; i < fontFileNameLen; ++i) {
+ if (!fontFileNames[i]->cmp(fileName)) {
+ return;
+ }
+ }
+
+ // add entry to fontFileNames list
+ if (fontFileNameLen >= fontFileNameSize) {
+ fontFileNameSize += 64;
+ fontFileNames = (GString **)grealloc(fontFileNames,
+ fontFileNameSize * sizeof(GString *));
+ }
+ fontFileNames[fontFileNameLen++] = fileName->copy();
+
+ // beginning comment
+ writePS("%%%%BeginResource: font %s\n", psName);
+ embFontList->append("%%+ font ");
+ embFontList->append(psName);
+ embFontList->append("\n");
+
+ // copy the font file
+ if (!(fontFile = fopen(fileName->getCString(), "rb"))) {
+ error(-1, "Couldn't open external font file");
+ return;
+ }
+ while ((c = fgetc(fontFile)) != EOF)
+ fputc(c, f);
+ fclose(fontFile);
+
+ // ending comment
+ writePS("%%%%EndResource\n");
+}
+
+void PSOutputDev::setupEmbeddedType1CFont(GfxFont *font, Ref *id,
+ char *psName) {
+ char *fontBuf;
+ int fontLen;
+ Type1CFontConverter *cvt;
+ int i;
+
+ // check if font is already embedded
+ for (i = 0; i < fontFileIDLen; ++i) {
+ if (fontFileIDs[i].num == id->num &&
+ fontFileIDs[i].gen == id->gen)
+ return;
+ }
+
+ // add entry to fontFileIDs list
+ if (fontFileIDLen >= fontFileIDSize) {
+ fontFileIDSize += 64;
+ fontFileIDs = (Ref *)grealloc(fontFileIDs, fontFileIDSize * sizeof(Ref));
+ }
+ fontFileIDs[fontFileIDLen++] = *id;
+
+ // beginning comment
+ writePS("%%%%BeginResource: font %s\n", psName);
+ embFontList->append("%%+ font ");
+ embFontList->append(psName);
+ embFontList->append("\n");
+
+ // convert it to a Type 1 font
+ fontBuf = font->readEmbFontFile(xref, &fontLen);
+ cvt = new Type1CFontConverter(fontBuf, fontLen, f);
+ cvt->convert();
+ delete cvt;
+ gfree(fontBuf);
+
+ // ending comment
+ writePS("%%%%EndResource\n");
+}
+
+void PSOutputDev::setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id,
+ char *psName) {
+ char *fontBuf;
+ int fontLen;
+ TrueTypeFontFile *ttFile;
+ int i;
+
+ // check if font is already embedded
+ for (i = 0; i < fontFileIDLen; ++i) {
+ if (fontFileIDs[i].num == id->num &&
+ fontFileIDs[i].gen == id->gen)
+ return;
+ }
+
+ // add entry to fontFileIDs list
+ if (fontFileIDLen >= fontFileIDSize) {
+ fontFileIDSize += 64;
+ fontFileIDs = (Ref *)grealloc(fontFileIDs, fontFileIDSize * sizeof(Ref));
+ }
+ fontFileIDs[fontFileIDLen++] = *id;
+
+ // beginning comment
+ writePS("%%%%BeginResource: font %s\n", psName);
+ embFontList->append("%%+ font ");
+ embFontList->append(psName);
+ embFontList->append("\n");
+
+ // convert it to a Type 42 font
+ fontBuf = font->readEmbFontFile(xref, &fontLen);
+ ttFile = new TrueTypeFontFile(fontBuf, fontLen);
+ ttFile->convertToType42(psName, font->getEncoding(), f);
+ delete ttFile;
+ gfree(fontBuf);
+
+ // ending comment
+ writePS("%%%%EndResource\n");
+}
+
+void PSOutputDev::setupImages(Dict *resDict) {
+ Object xObjDict, xObj, xObjRef, subtypeObj;
+ int i;
+
+ if (mode != psModeForm) {
+ return;
+ }
+
+ resDict->lookup("XObject", &xObjDict);
+ if (xObjDict.isDict()) {
+ for (i = 0; i < xObjDict.dictGetLength(); ++i) {
+ xObjDict.dictGetValNF(i, &xObjRef);
+ xObjDict.dictGetVal(i, &xObj);
+ if (xObj.isStream()) {
+ xObj.streamGetDict()->lookup("Subtype", &subtypeObj);
+ if (subtypeObj.isName("Image")) {
+ if (xObjRef.isRef()) {
+ setupImage(xObjRef.getRef(), xObj.getStream());
+ } else {
+ error(-1, "Image in resource dict is not an indirect reference");
+ }
+ }
+ subtypeObj.free();
+ }
+ xObj.free();
+ xObjRef.free();
+ }
+ }
+ xObjDict.free();
+}
+
+void PSOutputDev::setupImage(Ref id, Stream *str) {
+ int c;
+ int size, line, col, i;
+
+ // construct an encoder stream
+ str = new ASCII85Encoder(str);
+
+ // compute image data size
+ str->reset();
+ col = size = 0;
+ do {
+ do {
+ c = str->getChar();
+ } while (c == '\n' || c == '\r');
+ if (c == '~' || c == EOF) {
+ break;
+ }
+ if (c == 'z') {
+ ++col;
+ } else {
+ ++col;
+ for (i = 1; i <= 4; ++i) {
+ do {
+ c = str->getChar();
+ } while (c == '\n' || c == '\r');
+ if (c == '~' || c == EOF) {
+ break;
+ }
+ ++col;
+ }
+ }
+ if (col > 225) {
+ ++size;
+ col = 0;
+ }
+ } while (c != '~' && c != EOF);
+ ++size;
+ writePS("%d array dup /ImData_%d_%d exch def\n", size, id.num, id.gen);
+
+ // write the data into the array
+ str->reset();
+ line = col = 0;
+ writePS("dup 0 <~");
+ do {
+ do {
+ c = str->getChar();
+ } while (c == '\n' || c == '\r');
+ if (c == '~' || c == EOF) {
+ break;
+ }
+ if (c == 'z') {
+ fputc(c, f);
+ ++col;
+ } else {
+ fputc(c, f);
+ ++col;
+ for (i = 1; i <= 4; ++i) {
+ do {
+ c = str->getChar();
+ } while (c == '\n' || c == '\r');
+ if (c == '~' || c == EOF) {
+ break;
+ }
+ fputc(c, f);
+ ++col;
+ }
+ }
+ // each line is: "dup nnnnn <~...data...~> put<eol>"
+ // so max data length = 255 - 20 = 235
+ // chunks are 1 or 4 bytes each, so we have to stop at 232
+ // but make it 225 just to be safe
+ if (col > 225) {
+ writePS("~> put\n");
+ ++line;
+ writePS("dup %d <~", line);
+ col = 0;
+ }
+ } while (c != '~' && c != EOF);
+ writePS("~> put\n");
+ writePS("pop\n");
+
+ delete str;
+}
+
+void PSOutputDev::startPage(int pageNum, GfxState *state) {
+ int x1, y1, x2, y2, width, height, t;
+
+ switch (mode) {
+
+ case psModePS:
+ writePS("%%%%Page: %d %d\n", pageNum, seqPage);
+ writePS("%%%%BeginPageSetup\n");
+
+ // rotate, translate, and scale page
+ x1 = (int)(state->getX1() + 0.5);
+ y1 = (int)(state->getY1() + 0.5);
+ x2 = (int)(state->getX2() + 0.5);
+ y2 = (int)(state->getY2() + 0.5);
+ width = x2 - x1;
+ height = y2 - y1;
+ if (width > height && width > paperWidth) {
+ landscape = gTrue;
+ writePS("%%%%PageOrientation: Landscape\n");
+ writePS("pdfStartPage\n");
+ writePS("90 rotate\n");
+ tx = -x1;
+ ty = -(y1 + paperWidth);
+ t = width;
+ width = height;
+ height = t;
+ } else {
+ landscape = gFalse;
+ writePS("%%%%PageOrientation: Portrait\n");
+ writePS("pdfStartPage\n");
+ tx = -x1;
+ ty = -y1;
+ }
+ if (width < paperWidth) {
+ tx += (paperWidth - width) / 2;
+ }
+ if (height < paperHeight) {
+ ty += (paperHeight - height) / 2;
+ }
+ if (tx != 0 || ty != 0) {
+ writePS("%g %g translate\n", tx, ty);
+ }
+ if (width > paperWidth || height > paperHeight) {
+ xScale = (double)paperWidth / (double)width;
+ yScale = (double)paperHeight / (double)height;
+ if (yScale < xScale) {
+ xScale = yScale;
+ }
+ writePS("%0.4f %0.4f scale\n", xScale, xScale);
+ } else {
+ xScale = yScale = 1;
+ }
+
+ writePS("%%%%EndPageSetup\n");
+ ++seqPage;
+ break;
+
+ case psModeEPS:
+ writePS("pdfStartPage\n");
+ tx = ty = 0;
+ xScale = yScale = 1;
+ landscape = gFalse;
+ break;
+
+ case psModeForm:
+ writePS("/PaintProc {\n");
+ writePS("begin xpdf begin\n");
+ writePS("pdfStartPage\n");
+ tx = ty = 0;
+ xScale = yScale = 1;
+ landscape = gFalse;
+ break;
+ }
+}
+
+void PSOutputDev::endPage() {
+ if (mode == psModeForm) {
+ writePS("pdfEndPage\n");
+ writePS("end end\n");
+ writePS("} def\n");
+ writePS("end end\n");
+ } else {
+ writePS("showpage\n");
+ writePS("%%%%PageTrailer\n");
+ writePS("pdfEndPage\n");
+ }
+}
+
+void PSOutputDev::saveState(GfxState *state) {
+ writePS("q\n");
+}
+
+void PSOutputDev::restoreState(GfxState *state) {
+ writePS("Q\n");
+}
+
+void PSOutputDev::updateCTM(GfxState *state, double m11, double m12,
+ double m21, double m22, double m31, double m32) {
+ writePS("[%g %g %g %g %g %g] cm\n", m11, m12, m21, m22, m31, m32);
+}
+
+void PSOutputDev::updateLineDash(GfxState *state) {
+ double *dash;
+ double start;
+ int length, i;
+
+ state->getLineDash(&dash, &length, &start);
+ writePS("[");
+ for (i = 0; i < length; ++i)
+ writePS("%g%s", dash[i], (i == length-1) ? "" : " ");
+ writePS("] %g d\n", start);
+}
+
+void PSOutputDev::updateFlatness(GfxState *state) {
+ writePS("%d i\n", state->getFlatness());
+}
+
+void PSOutputDev::updateLineJoin(GfxState *state) {
+ writePS("%d j\n", state->getLineJoin());
+}
+
+void PSOutputDev::updateLineCap(GfxState *state) {
+ writePS("%d J\n", state->getLineCap());
+}
+
+void PSOutputDev::updateMiterLimit(GfxState *state) {
+ writePS("%g M\n", state->getMiterLimit());
+}
+
+void PSOutputDev::updateLineWidth(GfxState *state) {
+ writePS("%g w\n", state->getLineWidth());
+}
+
+void PSOutputDev::updateFillColor(GfxState *state) {
+ GfxColor color;
+ double gray;
+ GfxRGB rgb;
+ GfxCMYK cmyk;
+ GfxSeparationColorSpace *sepCS;
+
+ switch (level) {
+ case psLevel1:
+ state->getFillGray(&gray);
+ writePS("%g g\n", gray);
+ break;
+ case psLevel1Sep:
+ state->getFillCMYK(&cmyk);
+ writePS("%g %g %g %g k\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
+ break;
+ case psLevel2:
+ if (state->getFillColorSpace()->getMode() == csDeviceCMYK) {
+ state->getFillCMYK(&cmyk);
+ writePS("%g %g %g %g k\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
+ } else {
+ state->getFillRGB(&rgb);
+ if (rgb.r == rgb.g && rgb.g == rgb.b) {
+ writePS("%g g\n", rgb.r);
+ } else {
+ writePS("%g %g %g rg\n", rgb.r, rgb.g, rgb.b);
+ }
+ }
+ break;
+ case psLevel2Sep:
+ if (state->getFillColorSpace()->getMode() == csSeparation) {
+ sepCS = (GfxSeparationColorSpace *)state->getFillColorSpace();
+ color.c[0] = 1;
+ sepCS->getCMYK(&color, &cmyk);
+ writePS("%g %g %g %g %g (%s) ck\n",
+ state->getFillColor()->c[0],
+ cmyk.c, cmyk.m, cmyk.y, cmyk.k,
+ sepCS->getName()->getCString());
+ addCustomColor(sepCS);
+ } else {
+ state->getFillCMYK(&cmyk);
+ writePS("%g %g %g %g k\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
+ addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k);
+ }
+ break;
+ }
+}
+
+void PSOutputDev::updateStrokeColor(GfxState *state) {
+ GfxColor color;
+ double gray;
+ GfxRGB rgb;
+ GfxCMYK cmyk;
+ GfxSeparationColorSpace *sepCS;
+
+ switch (level) {
+ case psLevel1:
+ state->getStrokeGray(&gray);
+ writePS("%g G\n", gray);
+ break;
+ case psLevel1Sep:
+ state->getStrokeCMYK(&cmyk);
+ writePS("%g %g %g %g K\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
+ break;
+ case psLevel2:
+ if (state->getStrokeColorSpace()->getMode() == csDeviceCMYK) {
+ state->getStrokeCMYK(&cmyk);
+ writePS("%g %g %g %g K\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
+ } else {
+ state->getStrokeRGB(&rgb);
+ if (rgb.r == rgb.g && rgb.g == rgb.b) {
+ writePS("%g G\n", rgb.r);
+ } else {
+ writePS("%g %g %g RG\n", rgb.r, rgb.g, rgb.b);
+ }
+ }
+ break;
+ case psLevel2Sep:
+ if (state->getStrokeColorSpace()->getMode() == csSeparation) {
+ sepCS = (GfxSeparationColorSpace *)state->getStrokeColorSpace();
+ color.c[0] = 1;
+ sepCS->getCMYK(&color, &cmyk);
+ writePS("%g %g %g %g %g (%s) CK\n",
+ state->getStrokeColor()->c[0],
+ cmyk.c, cmyk.m, cmyk.y, cmyk.k,
+ sepCS->getName()->getCString());
+ addCustomColor(sepCS);
+ } else {
+ state->getStrokeCMYK(&cmyk);
+ writePS("%g %g %g %g K\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
+ addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k);
+ }
+ break;
+ }
+}
+
+void PSOutputDev::addProcessColor(double c, double m, double y, double k) {
+ if (c > 0) {
+ processColors |= psProcessCyan;
+ }
+ if (m > 0) {
+ processColors |= psProcessMagenta;
+ }
+ if (y > 0) {
+ processColors |= psProcessYellow;
+ }
+ if (k > 0) {
+ processColors |= psProcessBlack;
+ }
+}
+
+void PSOutputDev::addCustomColor(GfxSeparationColorSpace *sepCS) {
+ PSOutCustomColor *cc;
+ GfxColor color;
+ GfxCMYK cmyk;
+
+ for (cc = customColors; cc; cc = cc->next) {
+ if (!cc->name->cmp(sepCS->getName())) {
+ return;
+ }
+ }
+ color.c[0] = 1;
+ sepCS->getCMYK(&color, &cmyk);
+ cc = new PSOutCustomColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k,
+ sepCS->getName()->copy());
+ cc->next = customColors;
+ customColors = cc;
+}
+
+void PSOutputDev::updateFont(GfxState *state) {
+ if (state->getFont()) {
+ writePS("/F%d_%d %g Tf\n",
+ state->getFont()->getID().num, state->getFont()->getID().gen,
+ state->getFontSize());
+ }
+}
+
+void PSOutputDev::updateTextMat(GfxState *state) {
+ double *mat;
+
+ mat = state->getTextMat();
+ writePS("[%g %g %g %g %g %g] Tm\n",
+ mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]);
+}
+
+void PSOutputDev::updateCharSpace(GfxState *state) {
+ writePS("%g Tc\n", state->getCharSpace());
+}
+
+void PSOutputDev::updateRender(GfxState *state) {
+ writePS("%d Tr\n", state->getRender());
+}
+
+void PSOutputDev::updateRise(GfxState *state) {
+ writePS("%g Ts\n", state->getRise());
+}
+
+void PSOutputDev::updateWordSpace(GfxState *state) {
+ writePS("%g Tw\n", state->getWordSpace());
+}
+
+void PSOutputDev::updateHorizScaling(GfxState *state) {
+ writePS("%g Tz\n", state->getHorizScaling());
+}
+
+void PSOutputDev::updateTextPos(GfxState *state) {
+ writePS("%g %g Td\n", state->getLineX(), state->getLineY());
+}
+
+void PSOutputDev::updateTextShift(GfxState *state, double shift) {
+ writePS("%g TJm\n", shift);
+}
+
+void PSOutputDev::stroke(GfxState *state) {
+ doPath(state->getPath());
+ writePS("S\n");
+}
+
+void PSOutputDev::fill(GfxState *state) {
+ doPath(state->getPath());
+ writePS("f\n");
+}
+
+void PSOutputDev::eoFill(GfxState *state) {
+ doPath(state->getPath());
+ writePS("f*\n");
+}
+
+void PSOutputDev::clip(GfxState *state) {
+ doPath(state->getPath());
+ writePS("W\n");
+}
+
+void PSOutputDev::eoClip(GfxState *state) {
+ doPath(state->getPath());
+ writePS("W*\n");
+}
+
+void PSOutputDev::doPath(GfxPath *path) {
+ GfxSubpath *subpath;
+ double x0, y0, x1, y1, x2, y2, x3, y3, x4, y4;
+ int n, m, i, j;
+
+ n = path->getNumSubpaths();
+
+ if (n == 1 && path->getSubpath(0)->getNumPoints() == 5) {
+ subpath = path->getSubpath(0);
+ x0 = subpath->getX(0);
+ y0 = subpath->getY(0);
+ x4 = subpath->getX(4);
+ y4 = subpath->getY(4);
+ if (x4 == x0 && y4 == y0) {
+ x1 = subpath->getX(1);
+ y1 = subpath->getY(1);
+ x2 = subpath->getX(2);
+ y2 = subpath->getY(2);
+ x3 = subpath->getX(3);
+ y3 = subpath->getY(3);
+ if (x0 == x1 && x2 == x3 && y0 == y3 && y1 == y2) {
+ writePS("%g %g %g %g re\n",
+ x0 < x2 ? x0 : x2, y0 < y1 ? y0 : y1,
+ fabs(x2 - x0), fabs(y1 - y0));
+ return;
+ } else if (x0 == x3 && x1 == x2 && y0 == y1 && y2 == y3) {
+ writePS("%g %g %g %g re\n",
+ x0 < x1 ? x0 : x1, y0 < y2 ? y0 : y2,
+ fabs(x1 - x0), fabs(y2 - y0));
+ return;
+ }
+ }
+ }
+
+ for (i = 0; i < n; ++i) {
+ subpath = path->getSubpath(i);
+ m = subpath->getNumPoints();
+ writePS("%g %g m\n", subpath->getX(0), subpath->getY(0));
+ j = 1;
+ while (j < m) {
+ if (subpath->getCurve(j)) {
+ writePS("%g %g %g %g %g %g c\n", subpath->getX(j), subpath->getY(j),
+ subpath->getX(j+1), subpath->getY(j+1),
+ subpath->getX(j+2), subpath->getY(j+2));
+ j += 3;
+ } else {
+ writePS("%g %g l\n", subpath->getX(j), subpath->getY(j));
+ ++j;
+ }
+ }
+ if (subpath->isClosed()) {
+ writePS("h\n");
+ }
+ }
+}
+
+void PSOutputDev::drawString(GfxState *state, GString *s) {
+ // check for invisible text -- this is used by Acrobat Capture
+ if ((state->getRender() & 3) == 3)
+ return;
+
+ writePSString(s);
+ writePS(" %g Tj\n", state->getFont()->getWidth(s));
+}
+
+void PSOutputDev::drawString16(GfxState *state, GString *s) {
+ int c1, c2;
+ double w;
+ int i;
+
+ // check for invisible text -- this is used by Acrobat Capture
+ if ((state->getRender() & 3) == 3)
+ return;
+
+ switch (state->getFont()->getCharSet16()) {
+
+ case font16AdobeJapan12:
+#if JAPANESE_SUPPORT
+ writePS("<");
+ w = 0;
+ for (i = 0; i < s->getLength(); i += 2) {
+ c1 = ((s->getChar(i) & 0xff) << 8) + (s->getChar(i+1) & 0xff);
+ if (c1 <= 8285) {
+ c2 = japan12ToRKSJ[c1];
+ } else {
+ c2 = 0x20;
+ }
+ if (c2 <= 0xff) {
+ writePS("%02x", c2);
+ } else {
+ writePS("%02x%02x", c2 >> 8, c2 & 0xff);
+ }
+ w += state->getFont()->getWidth16(c1);
+ }
+ writePS("> %g Tj\n", w);
+#endif
+ break;
+
+ case font16AdobeGB12:
+ break;
+
+ case font16AdobeCNS13:
+ break;
+ }
+}
+
+void PSOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GBool invert,
+ GBool inlineImg) {
+ int len;
+
+ len = height * ((width + 7) / 8);
+ if (level == psLevel1 || level == psLevel1Sep) {
+ doImageL1(NULL, invert, inlineImg, str, width, height, len);
+ } else {
+ doImageL2(ref, NULL, invert, inlineImg, str, width, height, len);
+ }
+}
+
+void PSOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GfxImageColorMap *colorMap,
+ int *maskColors, GBool inlineImg) {
+ int len;
+
+ len = height * ((width * colorMap->getNumPixelComps() *
+ colorMap->getBits() + 7) / 8);
+ switch (level) {
+ case psLevel1:
+ doImageL1(colorMap, gFalse, inlineImg, str, width, height, len);
+ break;
+ case psLevel1Sep:
+ //~ handle indexed, separation, ... color spaces
+ doImageL1Sep(colorMap, gFalse, inlineImg, str, width, height, len);
+ break;
+ case psLevel2:
+ case psLevel2Sep:
+ doImageL2(ref, colorMap, gFalse, inlineImg, str, width, height, len);
+ break;
+ }
+}
+
+void PSOutputDev::doImageL1(GfxImageColorMap *colorMap,
+ GBool invert, GBool inlineImg,
+ Stream *str, int width, int height, int len) {
+ ImageStream *imgStr;
+ Guchar pixBuf[gfxColorMaxComps];
+ double gray;
+ int x, y, i;
+
+ // width, height, matrix, bits per component
+ if (colorMap) {
+ writePS("%d %d 8 [%d 0 0 %d 0 %d] pdfIm1\n",
+ width, height,
+ width, -height, height);
+ } else {
+ writePS("%d %d %s [%d 0 0 %d 0 %d] pdfImM1\n",
+ width, height, invert ? "true" : "false",
+ width, -height, height);
+ }
+
+ // image
+ if (colorMap) {
+
+ // set up to process the data stream
+ imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(),
+ colorMap->getBits());
+ imgStr->reset();
+
+ // process the data stream
+ i = 0;
+ for (y = 0; y < height; ++y) {
+
+ // write the line
+ for (x = 0; x < width; ++x) {
+ imgStr->getPixel(pixBuf);
+ colorMap->getGray(pixBuf, &gray);
+ fprintf(f, "%02x", (int)(gray * 255 + 0.5));
+ if (++i == 32) {
+ fputc('\n', f);
+ i = 0;
+ }
+ }
+ }
+ if (i != 0)
+ fputc('\n', f);
+ delete imgStr;
+
+ // imagemask
+ } else {
+ str->reset();
+ i = 0;
+ for (y = 0; y < height; ++y) {
+ for (x = 0; x < width; x += 8) {
+ fprintf(f, "%02x", str->getChar() & 0xff);
+ if (++i == 32) {
+ fputc('\n', f);
+ i = 0;
+ }
+ }
+ }
+ if (i != 0)
+ fputc('\n', f);
+ }
+}
+
+void PSOutputDev::doImageL1Sep(GfxImageColorMap *colorMap,
+ GBool invert, GBool inlineImg,
+ Stream *str, int width, int height, int len) {
+ ImageStream *imgStr;
+ Guchar *lineBuf;
+ Guchar pixBuf[gfxColorMaxComps];
+ GfxCMYK cmyk;
+ int x, y, i, comp;
+
+ // width, height, matrix, bits per component
+ writePS("%d %d 8 [%d 0 0 %d 0 %d] pdfIm1Sep\n",
+ width, height,
+ width, -height, height);
+
+ // allocate a line buffer
+ lineBuf = (Guchar *)gmalloc(4 * width);
+
+ // set up to process the data stream
+ imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(),
+ colorMap->getBits());
+ imgStr->reset();
+
+ // process the data stream
+ i = 0;
+ for (y = 0; y < height; ++y) {
+
+ // read the line
+ for (x = 0; x < width; ++x) {
+ imgStr->getPixel(pixBuf);
+ colorMap->getCMYK(pixBuf, &cmyk);
+ lineBuf[4*x+0] = (int)(255 * cmyk.c + 0.5);
+ lineBuf[4*x+1] = (int)(255 * cmyk.m + 0.5);
+ lineBuf[4*x+2] = (int)(255 * cmyk.y + 0.5);
+ lineBuf[4*x+3] = (int)(255 * cmyk.k + 0.5);
+ }
+
+ // write one line of each color component
+ for (comp = 0; comp < 4; ++comp) {
+ for (x = 0; x < width; ++x) {
+ fprintf(f, "%02x", lineBuf[4*x + comp]);
+ if (++i == 32) {
+ fputc('\n', f);
+ i = 0;
+ }
+ }
+ }
+ }
+
+ if (i != 0) {
+ fputc('\n', f);
+ }
+
+ delete imgStr;
+ gfree(lineBuf);
+}
+
+void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
+ GBool invert, GBool inlineImg,
+ Stream *str, int width, int height, int len) {
+ GString *s;
+ int n, numComps;
+ GBool useRLE, useA85;
+ GfxSeparationColorSpace *sepCS;
+ GfxColor color;
+ GfxCMYK cmyk;
+ int c;
+ int i;
+
+ // color space
+ if (colorMap) {
+ dumpColorSpaceL2(colorMap->getColorSpace());
+ writePS(" setcolorspace\n");
+ }
+
+ // set up to use the array created by setupImages()
+ if (mode == psModeForm && !inlineImg) {
+ writePS("ImData_%d_%d 0\n", ref->getRefNum(), ref->getRefGen());
+ }
+
+ // image dictionary
+ writePS("<<\n /ImageType 1\n");
+
+ // width, height, matrix, bits per component
+ writePS(" /Width %d\n", width);
+ writePS(" /Height %d\n", height);
+ writePS(" /ImageMatrix [%d 0 0 %d 0 %d]\n", width, -height, height);
+ writePS(" /BitsPerComponent %d\n",
+ colorMap ? colorMap->getBits() : 1);
+
+ // decode
+ if (colorMap) {
+ writePS(" /Decode [");
+ if (colorMap->getColorSpace()->getMode() == csSeparation) {
+ //~ this is a kludge -- see comment in dumpColorSpaceL2
+ n = (1 << colorMap->getBits()) - 1;
+ writePS("%g %g", colorMap->getDecodeLow(0) * n,
+ colorMap->getDecodeHigh(0) * n);
+ } else {
+ numComps = colorMap->getNumPixelComps();
+ for (i = 0; i < numComps; ++i) {
+ if (i > 0) {
+ writePS(" ");
+ }
+ writePS("%g %g", colorMap->getDecodeLow(i),
+ colorMap->getDecodeHigh(i));
+ }
+ }
+ writePS("]\n");
+ } else {
+ writePS(" /Decode [%d %d]\n", invert ? 1 : 0, invert ? 0 : 1);
+ }
+
+ if (mode == psModeForm) {
+
+ if (inlineImg) {
+
+ // data source
+ writePS(" /DataSource <~\n");
+
+ // write image data stream, using ASCII85 encode filter
+ str = new FixedLengthEncoder(str, len);
+ str = new ASCII85Encoder(str);
+ str->reset();
+ while ((c = str->getChar()) != EOF) {
+ fputc(c, f);
+ }
+ fputc('\n', f);
+ delete str;
+
+ } else {
+ writePS(" /DataSource { 2 copy get exch 1 add exch }\n");
+ }
+
+ // end of image dictionary
+ writePS(">>\n%s\n", colorMap ? "image" : "imagemask");
+
+ // get rid of the array and index
+ if (!inlineImg) {
+ writePS("pop pop\n");
+ }
+
+ } else {
+
+ // data source
+ writePS(" /DataSource currentfile\n");
+ s = str->getPSFilter(" ");
+ if (inlineImg || !s) {
+ useRLE = gTrue;
+ useA85 = gTrue;
+ } else {
+ useRLE = gFalse;
+ useA85 = str->isBinary();
+ }
+ if (useA85) {
+ writePS(" /ASCII85Decode filter\n");
+ }
+ if (useRLE) {
+ writePS(" /RunLengthDecode filter\n");
+ } else {
+ writePS("%s", s->getCString());
+ }
+ if (s) {
+ delete s;
+ }
+
+ // cut off inline image streams at appropriate length
+ if (inlineImg) {
+ str = new FixedLengthEncoder(str, len);
+ } else if (!useRLE) {
+ str = str->getBaseStream();
+ }
+
+ // add RunLengthEncode and ASCII85 encode filters
+ if (useRLE) {
+ str = new RunLengthEncoder(str);
+ }
+ if (useA85) {
+ str = new ASCII85Encoder(str);
+ }
+
+ // end of image dictionary
+ writePS(">>\n");
+#if OPI_SUPPORT
+ if (opi13Nest) {
+ if (inlineImg) {
+ // this can't happen -- OPI dictionaries are in XObjects
+ error(-1, "Internal: OPI in inline image");
+ n = 0;
+ } else {
+ // need to read the stream to count characters -- the length
+ // is data-dependent (because of A85 and RLE filters)
+ str->reset();
+ n = 0;
+ while ((c = str->getChar()) != EOF) {
+ ++n;
+ }
+ }
+ // +6/7 for "pdfIm\n" / "pdfImM\n"
+ // +8 for newline + trailer
+ n += colorMap ? 14 : 15;
+ writePS("%%%%BeginData: %d Hex Bytes\n", n);
+ }
+#endif
+ if (level == psLevel2Sep && colorMap &&
+ colorMap->getColorSpace()->getMode() == csSeparation) {
+ color.c[0] = 1;
+ sepCS = (GfxSeparationColorSpace *)colorMap->getColorSpace();
+ sepCS->getCMYK(&color, &cmyk);
+ writePS("%g %g %g %g (%s) pdfImSep\n",
+ cmyk.c, cmyk.m, cmyk.y, cmyk.k, sepCS->getName()->getCString());
+ } else {
+ writePS("%s\n", colorMap ? "pdfIm" : "pdfImM");
+ }
+
+ // copy the stream data
+ str->reset();
+ while ((c = str->getChar()) != EOF) {
+ fputc(c, f);
+ }
+
+ // add newline and trailer to the end
+ fputc('\n', f);
+ fputs("%-EOD-\n", f);
+#if OPI_SUPPORT
+ if (opi13Nest) {
+ writePS("%%%%EndData\n");
+ }
+#endif
+
+ // delete encoders
+ if (useRLE || useA85) {
+ delete str;
+ }
+ }
+}
+
+void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace) {
+ GfxCalGrayColorSpace *calGrayCS;
+ GfxCalRGBColorSpace *calRGBCS;
+ GfxLabColorSpace *labCS;
+ GfxIndexedColorSpace *indexedCS;
+ GfxSeparationColorSpace *separationCS;
+ Guchar *lookup;
+ double x[gfxColorMaxComps], y[gfxColorMaxComps];
+ GfxColor color;
+ GfxCMYK cmyk;
+ int n, numComps;
+ int i, j, k;
+
+ switch (colorSpace->getMode()) {
+
+ case csDeviceGray:
+ writePS("/DeviceGray");
+ processColors |= psProcessBlack;
+ break;
+
+ case csCalGray:
+ calGrayCS = (GfxCalGrayColorSpace *)colorSpace;
+ writePS("[/CIEBasedA <<\n");
+ writePS(" /DecodeA {%g exp} bind\n", calGrayCS->getGamma());
+ writePS(" /MatrixA [%g %g %g]\n",
+ calGrayCS->getWhiteX(), calGrayCS->getWhiteY(),
+ calGrayCS->getWhiteZ());
+ writePS(" /WhitePoint [%g %g %g]\n",
+ calGrayCS->getWhiteX(), calGrayCS->getWhiteY(),
+ calGrayCS->getWhiteZ());
+ writePS(" /BlackPoint [%g %g %g]\n",
+ calGrayCS->getBlackX(), calGrayCS->getBlackY(),
+ calGrayCS->getBlackZ());
+ writePS(">>]");
+ processColors |= psProcessBlack;
+ break;
+
+ case csDeviceRGB:
+ writePS("/DeviceRGB");
+ processColors |= psProcessCMYK;
+ break;
+
+ case csCalRGB:
+ calRGBCS = (GfxCalRGBColorSpace *)colorSpace;
+ writePS("[/CIEBasedABC <<\n");
+ writePS(" /DecodeABC [{%g exp} bind {%g exp} bind {%g exp} bind]\n",
+ calRGBCS->getGammaR(), calRGBCS->getGammaG(),
+ calRGBCS->getGammaB());
+ writePS(" /MatrixABC [%g %g %g %g %g %g %g %g %g]\n",
+ calRGBCS->getMatrix()[0], calRGBCS->getMatrix()[1],
+ calRGBCS->getMatrix()[2], calRGBCS->getMatrix()[3],
+ calRGBCS->getMatrix()[4], calRGBCS->getMatrix()[5],
+ calRGBCS->getMatrix()[6], calRGBCS->getMatrix()[7],
+ calRGBCS->getMatrix()[8]);
+ writePS(" /WhitePoint [%g %g %g]\n",
+ calRGBCS->getWhiteX(), calRGBCS->getWhiteY(),
+ calRGBCS->getWhiteZ());
+ writePS(" /BlackPoint [%g %g %g]\n",
+ calRGBCS->getBlackX(), calRGBCS->getBlackY(),
+ calRGBCS->getBlackZ());
+ writePS(">>]");
+ processColors |= psProcessCMYK;
+ break;
+
+ case csDeviceCMYK:
+ writePS("/DeviceCMYK");
+ processColors |= psProcessCMYK;
+ break;
+
+ case csLab:
+ labCS = (GfxLabColorSpace *)colorSpace;
+ writePS("[/CIEBasedABC <<\n");
+ writePS(" /RangeABC [0 100 %g %g %g %g]\n",
+ labCS->getAMin(), labCS->getAMax(),
+ labCS->getBMin(), labCS->getBMax());
+ writePS(" /DecodeABC [{16 add 116 div} bind {500 div} bind {200 div} bind]\n");
+ writePS(" /MatrixABC [1 1 1 1 0 0 0 0 -1]\n");
+ writePS(" /DecodeLMN\n");
+ writePS(" [{dup 6 29 div ge {dup dup mul mul}\n");
+ writePS(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind\n",
+ labCS->getWhiteX());
+ writePS(" {dup 6 29 div ge {dup dup mul mul}\n");
+ writePS(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind\n",
+ labCS->getWhiteY());
+ writePS(" {dup 6 29 div ge {dup dup mul mul}\n");
+ writePS(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind]\n",
+ labCS->getWhiteZ());
+ writePS(" /WhitePoint [%g %g %g]\n",
+ labCS->getWhiteX(), labCS->getWhiteY(), labCS->getWhiteZ());
+ writePS(" /BlackPoint [%g %g %g]\n",
+ labCS->getBlackX(), labCS->getBlackY(), labCS->getBlackZ());
+ writePS(">>]");
+ processColors |= psProcessCMYK;
+ break;
+
+ case csICCBased:
+ dumpColorSpaceL2(((GfxICCBasedColorSpace *)colorSpace)->getAlt());
+ break;
+
+ case csIndexed:
+ indexedCS = (GfxIndexedColorSpace *)colorSpace;
+ writePS("[/Indexed ");
+ dumpColorSpaceL2(indexedCS->getBase());
+ n = indexedCS->getIndexHigh();
+ numComps = indexedCS->getBase()->getNComps();
+ lookup = indexedCS->getLookup();
+ writePS(" %d <\n", n);
+ for (i = 0; i <= n; i += 8) {
+ writePS(" ");
+ for (j = i; j < i+8 && j <= n; ++j) {
+ for (k = 0; k < numComps; ++k) {
+ writePS("%02x", lookup[j * numComps + k]);
+ }
+ color.c[0] = j;
+ indexedCS->getCMYK(&color, &cmyk);
+ addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k);
+ }
+ writePS("\n");
+ }
+ writePS(">]");
+ break;
+
+ case csSeparation:
+ //~ this is a kludge -- the correct thing would to ouput a
+ //~ separation color space, with the specified alternate color
+ //~ space and tint transform
+ separationCS = (GfxSeparationColorSpace *)colorSpace;
+ writePS("[/Indexed ");
+ dumpColorSpaceL2(separationCS->getAlt());
+ writePS(" 255 <\n");
+ numComps = separationCS->getAlt()->getNComps();
+ for (i = 0; i <= 255; i += 8) {
+ writePS(" ");
+ for (j = i; j < i+8 && j <= 255; ++j) {
+ x[0] = (double)j / 255.0;
+ separationCS->getFunc()->transform(x, y);
+ for (k = 0; k < numComps; ++k) {
+ writePS("%02x", (int)(255 * y[k] + 0.5));
+ }
+ }
+ writePS("\n");
+ }
+ writePS(">]");
+ addCustomColor(separationCS);
+ break;
+
+ case csDeviceN:
+ // DeviceN color spaces are a Level 3 PostScript feature.
+ dumpColorSpaceL2(((GfxDeviceNColorSpace *)colorSpace)->getAlt());
+ break;
+
+ case csPattern:
+ //~ unimplemented
+ break;
+
+ }
+}
+
+#if OPI_SUPPORT
+void PSOutputDev::opiBegin(GfxState *state, Dict *opiDict) {
+ Object dict;
+
+ if (doOPI) {
+ opiDict->lookup("2.0", &dict);
+ if (dict.isDict()) {
+ opiBegin20(state, dict.getDict());
+ dict.free();
+ } else {
+ dict.free();
+ opiDict->lookup("1.3", &dict);
+ if (dict.isDict()) {
+ opiBegin13(state, dict.getDict());
+ }
+ dict.free();
+ }
+ }
+}
+
+void PSOutputDev::opiBegin20(GfxState *state, Dict *dict) {
+ Object obj1, obj2, obj3, obj4;
+ double width, height, left, right, top, bottom;
+ int w, h;
+ int i;
+
+ writePS("%%%%BeginOPI: 2.0\n");
+ writePS("%%%%Distilled\n");
+
+ dict->lookup("F", &obj1);
+ if (getFileSpec(&obj1, &obj2)) {
+ writePS("%%%%ImageFileName: %s\n",
+ obj2.getString()->getCString());
+ obj2.free();
+ }
+ obj1.free();
+
+ dict->lookup("MainImage", &obj1);
+ if (obj1.isString()) {
+ writePS("%%%%MainImage: %s\n", obj1.getString()->getCString());
+ }
+ obj1.free();
+
+ //~ ignoring 'Tags' entry
+ //~ need to use writePSString() and deal with >255-char lines
+
+ dict->lookup("Size", &obj1);
+ if (obj1.isArray() && obj1.arrayGetLength() == 2) {
+ obj1.arrayGet(0, &obj2);
+ width = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(1, &obj2);
+ height = obj2.getNum();
+ obj2.free();
+ writePS("%%%%ImageDimensions: %g %g\n", width, height);
+ }
+ obj1.free();
+
+ dict->lookup("CropRect", &obj1);
+ if (obj1.isArray() && obj1.arrayGetLength() == 4) {
+ obj1.arrayGet(0, &obj2);
+ left = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(1, &obj2);
+ top = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(2, &obj2);
+ right = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(3, &obj2);
+ bottom = obj2.getNum();
+ obj2.free();
+ writePS("%%%%ImageCropRect: %g %g %g %g\n", left, top, right, bottom);
+ }
+ obj1.free();
+
+ dict->lookup("Overprint", &obj1);
+ if (obj1.isBool()) {
+ writePS("%%%%ImageOverprint: %s\n", obj1.getBool() ? "true" : "false");
+ }
+ obj1.free();
+
+ dict->lookup("Inks", &obj1);
+ if (obj1.isName()) {
+ writePS("%%%%ImageInks: %s\n", obj1.getName());
+ } else if (obj1.isArray() && obj1.arrayGetLength() >= 1) {
+ obj1.arrayGet(0, &obj2);
+ if (obj2.isName()) {
+ writePS("%%%%ImageInks: %s %d",
+ obj2.getName(), (obj1.arrayGetLength() - 1) / 2);
+ for (i = 1; i+1 < obj1.arrayGetLength(); i += 2) {
+ obj1.arrayGet(i, &obj3);
+ obj1.arrayGet(i+1, &obj4);
+ if (obj3.isString() && obj4.isNum()) {
+ writePS(" ");
+ writePSString(obj3.getString());
+ writePS(" %g", obj4.getNum());
+ }
+ obj3.free();
+ obj4.free();
+ }
+ writePS("\n");
+ }
+ obj2.free();
+ }
+ obj1.free();
+
+ writePS("gsave\n");
+
+ writePS("%%%%BeginIncludedImage\n");
+
+ dict->lookup("IncludedImageDimensions", &obj1);
+ if (obj1.isArray() && obj1.arrayGetLength() == 2) {
+ obj1.arrayGet(0, &obj2);
+ w = obj2.getInt();
+ obj2.free();
+ obj1.arrayGet(1, &obj2);
+ h = obj2.getInt();
+ obj2.free();
+ writePS("%%%%IncludedImageDimensions: %d %d\n", w, h);
+ }
+ obj1.free();
+
+ dict->lookup("IncludedImageQuality", &obj1);
+ if (obj1.isNum()) {
+ writePS("%%%%IncludedImageQuality: %g\n", obj1.getNum());
+ }
+ obj1.free();
+
+ ++opi20Nest;
+}
+
+void PSOutputDev::opiBegin13(GfxState *state, Dict *dict) {
+ Object obj1, obj2;
+ int left, right, top, bottom, samples, bits, width, height;
+ double c, m, y, k;
+ double llx, lly, ulx, uly, urx, ury, lrx, lry;
+ double tllx, tlly, tulx, tuly, turx, tury, tlrx, tlry;
+ double horiz, vert;
+ int i, j;
+
+ writePS("save\n");
+ writePS("/opiMatrix2 matrix currentmatrix def\n");
+ writePS("opiMatrix setmatrix\n");
+
+ dict->lookup("F", &obj1);
+ if (getFileSpec(&obj1, &obj2)) {
+ writePS("%%ALDImageFileName: %s\n",
+ obj2.getString()->getCString());
+ obj2.free();
+ }
+ obj1.free();
+
+ dict->lookup("CropRect", &obj1);
+ if (obj1.isArray() && obj1.arrayGetLength() == 4) {
+ obj1.arrayGet(0, &obj2);
+ left = obj2.getInt();
+ obj2.free();
+ obj1.arrayGet(1, &obj2);
+ top = obj2.getInt();
+ obj2.free();
+ obj1.arrayGet(2, &obj2);
+ right = obj2.getInt();
+ obj2.free();
+ obj1.arrayGet(3, &obj2);
+ bottom = obj2.getInt();
+ obj2.free();
+ writePS("%%ALDImageCropRect: %d %d %d %d\n", left, top, right, bottom);
+ }
+ obj1.free();
+
+ dict->lookup("Color", &obj1);
+ if (obj1.isArray() && obj1.arrayGetLength() == 5) {
+ obj1.arrayGet(0, &obj2);
+ c = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(1, &obj2);
+ m = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(2, &obj2);
+ y = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(3, &obj2);
+ k = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(4, &obj2);
+ if (obj2.isString()) {
+ writePS("%%ALDImageColor: %g %g %g %g ", c, m, y, k);
+ writePSString(obj2.getString());
+ writePS("\n");
+ }
+ obj2.free();
+ }
+ obj1.free();
+
+ dict->lookup("ColorType", &obj1);
+ if (obj1.isName()) {
+ writePS("%%ALDImageColorType: %s\n", obj1.getName());
+ }
+ obj1.free();
+
+ //~ ignores 'Comments' entry
+ //~ need to handle multiple lines
+
+ dict->lookup("CropFixed", &obj1);
+ if (obj1.isArray()) {
+ obj1.arrayGet(0, &obj2);
+ ulx = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(1, &obj2);
+ uly = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(2, &obj2);
+ lrx = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(3, &obj2);
+ lry = obj2.getNum();
+ obj2.free();
+ writePS("%%ALDImageCropFixed: %g %g %g %g\n", ulx, uly, lrx, lry);
+ }
+ obj1.free();
+
+ dict->lookup("GrayMap", &obj1);
+ if (obj1.isArray()) {
+ writePS("%%ALDImageGrayMap:");
+ for (i = 0; i < obj1.arrayGetLength(); i += 16) {
+ if (i > 0) {
+ writePS("\n%%%%+");
+ }
+ for (j = 0; j < 16 && i+j < obj1.arrayGetLength(); ++j) {
+ obj1.arrayGet(i+j, &obj2);
+ writePS(" %d", obj2.getInt());
+ obj2.free();
+ }
+ }
+ writePS("\n");
+ }
+ obj1.free();
+
+ dict->lookup("ID", &obj1);
+ if (obj1.isString()) {
+ writePS("%%ALDImageID: %s\n", obj1.getString()->getCString());
+ }
+ obj1.free();
+
+ dict->lookup("ImageType", &obj1);
+ if (obj1.isArray() && obj1.arrayGetLength() == 2) {
+ obj1.arrayGet(0, &obj2);
+ samples = obj2.getInt();
+ obj2.free();
+ obj1.arrayGet(1, &obj2);
+ bits = obj2.getInt();
+ obj2.free();
+ writePS("%%ALDImageType: %d %d\n", samples, bits);
+ }
+ obj1.free();
+
+ dict->lookup("Overprint", &obj1);
+ if (obj1.isBool()) {
+ writePS("%%ALDImageOverprint: %s\n", obj1.getBool() ? "true" : "false");
+ }
+ obj1.free();
+
+ dict->lookup("Position", &obj1);
+ if (obj1.isArray() && obj1.arrayGetLength() == 8) {
+ obj1.arrayGet(0, &obj2);
+ llx = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(1, &obj2);
+ lly = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(2, &obj2);
+ ulx = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(3, &obj2);
+ uly = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(4, &obj2);
+ urx = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(5, &obj2);
+ ury = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(6, &obj2);
+ lrx = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(7, &obj2);
+ lry = obj2.getNum();
+ obj2.free();
+ opiTransform(state, llx, lly, &tllx, &tlly);
+ opiTransform(state, ulx, uly, &tulx, &tuly);
+ opiTransform(state, urx, ury, &turx, &tury);
+ opiTransform(state, lrx, lry, &tlrx, &tlry);
+ writePS("%%ALDImagePosition: %g %g %g %g %g %g %g %g\n",
+ tllx, tlly, tulx, tuly, turx, tury, tlrx, tlry);
+ obj2.free();
+ }
+ obj1.free();
+
+ dict->lookup("Resolution", &obj1);
+ if (obj1.isArray() && obj1.arrayGetLength() == 2) {
+ obj1.arrayGet(0, &obj2);
+ horiz = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(1, &obj2);
+ vert = obj2.getNum();
+ obj2.free();
+ writePS("%%ALDImageResoution: %g %g\n", horiz, vert);
+ obj2.free();
+ }
+ obj1.free();
+
+ dict->lookup("Size", &obj1);
+ if (obj1.isArray() && obj1.arrayGetLength() == 2) {
+ obj1.arrayGet(0, &obj2);
+ width = obj2.getInt();
+ obj2.free();
+ obj1.arrayGet(1, &obj2);
+ height = obj2.getInt();
+ obj2.free();
+ writePS("%%ALDImageDimensions: %d %d\n", width, height);
+ }
+ obj1.free();
+
+ //~ ignoring 'Tags' entry
+ //~ need to use writePSString() and deal with >255-char lines
+
+ dict->lookup("Tint", &obj1);
+ if (obj1.isNum()) {
+ writePS("%%ALDImageTint: %g\n", obj1.getNum());
+ }
+ obj1.free();
+
+ dict->lookup("Transparency", &obj1);
+ if (obj1.isBool()) {
+ writePS("%%ALDImageTransparency: %s\n", obj1.getBool() ? "true" : "false");
+ }
+ obj1.free();
+
+ writePS("%%%%BeginObject: image\n");
+ writePS("opiMatrix2 setmatrix\n");
+ ++opi13Nest;
+}
+
+// Convert PDF user space coordinates to PostScript default user space
+// coordinates. This has to account for both the PDF CTM and the
+// PSOutputDev page-fitting transform.
+void PSOutputDev::opiTransform(GfxState *state, double x0, double y0,
+ double *x1, double *y1) {
+ double t;
+
+ state->transform(x0, y0, x1, y1);
+ *x1 += tx;
+ *y1 += ty;
+ if (landscape) {
+ t = *x1;
+ *x1 = -*y1;
+ *y1 = t;
+ }
+ *x1 *= xScale;
+ *y1 *= yScale;
+}
+
+void PSOutputDev::opiEnd(GfxState *state, Dict *opiDict) {
+ Object dict;
+
+ if (doOPI) {
+ opiDict->lookup("2.0", &dict);
+ if (dict.isDict()) {
+ writePS("%%%%EndIncludedImage\n");
+ writePS("%%%%EndOPI\n");
+ writePS("grestore\n");
+ --opi20Nest;
+ dict.free();
+ } else {
+ dict.free();
+ opiDict->lookup("1.3", &dict);
+ if (dict.isDict()) {
+ writePS("%%%%EndObject\n");
+ writePS("restore\n");
+ --opi13Nest;
+ }
+ dict.free();
+ }
+ }
+}
+
+GBool PSOutputDev::getFileSpec(Object *fileSpec, Object *fileName) {
+ if (fileSpec->isString()) {
+ fileSpec->copy(fileName);
+ return gTrue;
+ }
+ if (fileSpec->isDict()) {
+ fileSpec->dictLookup("DOS", fileName);
+ if (fileName->isString()) {
+ return gTrue;
+ }
+ fileName->free();
+ fileSpec->dictLookup("Mac", fileName);
+ if (fileName->isString()) {
+ return gTrue;
+ }
+ fileName->free();
+ fileSpec->dictLookup("Unix", fileName);
+ if (fileName->isString()) {
+ return gTrue;
+ }
+ fileName->free();
+ fileSpec->dictLookup("F", fileName);
+ if (fileName->isString()) {
+ return gTrue;
+ }
+ fileName->free();
+ }
+ return gFalse;
+}
+#endif // OPI_SUPPORT
+
+void PSOutputDev::writePS(const char *fmt, ...) {
+ va_list args;
+
+ va_start(args, fmt);
+ vfprintf(f, fmt, args);
+ va_end(args);
+}
+
+void PSOutputDev::writePSString(GString *s) {
+ Guchar *p;
+ int n;
+
+ fputc('(', f);
+ for (p = (Guchar *)s->getCString(), n = s->getLength(); n; ++p, --n) {
+ if (*p == '(' || *p == ')' || *p == '\\')
+ fprintf(f, "\\%c", *p);
+ else if (*p < 0x20 || *p >= 0x80)
+ fprintf(f, "\\%03o", *p);
+ else
+ fputc(*p, f);
+ }
+ fputc(')', f);
+}
diff --git a/pdftops/PSOutputDev.h b/pdftops/PSOutputDev.h
new file mode 100644
index 000000000..81279be4a
--- /dev/null
+++ b/pdftops/PSOutputDev.h
@@ -0,0 +1,215 @@
+//========================================================================
+//
+// PSOutputDev.h
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifndef PSOUTPUTDEV_H
+#define PSOUTPUTDEV_H
+
+#ifdef __GNUC__
+#pragma interface
+#endif
+
+#include <stddef.h>
+#include "config.h"
+#include "Object.h"
+#include "OutputDev.h"
+
+class GfxPath;
+class GfxFont;
+class GfxColorSpace;
+class GfxSeparationColorSpace;
+class PSOutCustomColor;
+
+//------------------------------------------------------------------------
+// PSOutputDev
+//------------------------------------------------------------------------
+
+enum PSOutLevel {
+ psLevel1,
+ psLevel1Sep,
+ psLevel2,
+ psLevel2Sep
+};
+
+enum PSOutMode {
+ psModePS,
+ psModeEPS,
+ psModeForm
+};
+
+enum PSFileType {
+ psFile, // write to file
+ psPipe, // write to pipe
+ psStdout // write to stdout
+};
+
+class PSOutputDev: public OutputDev {
+public:
+
+ // Open a PostScript output file, and write the prolog.
+ PSOutputDev(char *fileName, XRef *xrefA, Catalog *catalog,
+ int firstPage, int lastPage,
+ PSOutLevel levelA, PSOutMode modeA, GBool doOPIA,
+ GBool embedType1A, GBool embedTrueTypeA,
+ int paperWidthA, int paperHeightA);
+
+ // Destructor -- writes the trailer and closes the file.
+ virtual ~PSOutputDev();
+
+ // Check if file was successfully created.
+ virtual GBool isOk() { return ok; }
+
+ //---- get info about output device
+
+ // Does this device use upside-down coordinates?
+ // (Upside-down means (0,0) is the top left corner of the page.)
+ virtual GBool upsideDown() { return gFalse; }
+
+ // Does this device use drawChar() or drawString()?
+ virtual GBool useDrawChar() { return gFalse; }
+
+ //----- initialization and control
+
+ // Start a page.
+ virtual void startPage(int pageNum, GfxState *state);
+
+ // End a page.
+ virtual void endPage();
+
+ //----- save/restore graphics state
+ virtual void saveState(GfxState *state);
+ virtual void restoreState(GfxState *state);
+
+ //----- update graphics state
+ virtual void updateCTM(GfxState *state, double m11, double m12,
+ double m21, double m22, double m31, double m32);
+ virtual void updateLineDash(GfxState *state);
+ virtual void updateFlatness(GfxState *state);
+ virtual void updateLineJoin(GfxState *state);
+ virtual void updateLineCap(GfxState *state);
+ virtual void updateMiterLimit(GfxState *state);
+ virtual void updateLineWidth(GfxState *state);
+ virtual void updateFillColor(GfxState *state);
+ virtual void updateStrokeColor(GfxState *state);
+
+ //----- update text state
+ virtual void updateFont(GfxState *state);
+ virtual void updateTextMat(GfxState *state);
+ virtual void updateCharSpace(GfxState *state);
+ virtual void updateRender(GfxState *state);
+ virtual void updateRise(GfxState *state);
+ virtual void updateWordSpace(GfxState *state);
+ virtual void updateHorizScaling(GfxState *state);
+ virtual void updateTextPos(GfxState *state);
+ virtual void updateTextShift(GfxState *state, double shift);
+
+ //----- path painting
+ virtual void stroke(GfxState *state);
+ virtual void fill(GfxState *state);
+ virtual void eoFill(GfxState *state);
+
+ //----- path clipping
+ virtual void clip(GfxState *state);
+ virtual void eoClip(GfxState *state);
+
+ //----- text drawing
+ virtual void drawString(GfxState *state, GString *s);
+ virtual void drawString16(GfxState *state, GString *s);
+
+ //----- image drawing
+ virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GBool invert,
+ GBool inlineImg);
+ virtual void drawImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GfxImageColorMap *colorMap,
+ int *maskColors, GBool inlineImg);
+
+#if OPI_SUPPORT
+ //----- OPI functions
+ virtual void opiBegin(GfxState *state, Dict *opiDict);
+ virtual void opiEnd(GfxState *state, Dict *opiDict);
+#endif
+
+private:
+
+ void setupResources(Dict *resDict);
+ void setupFonts(Dict *resDict);
+ void setupFont(GfxFont *font);
+ void setupEmbeddedType1Font(Ref *id, char *psName);
+ void setupEmbeddedType1Font(GString *fileName, char *psName);
+ void setupEmbeddedType1CFont(GfxFont *font, Ref *id, char *psName);
+ void setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id, char *psName);
+ void setupImages(Dict *resDict);
+ void setupImage(Ref id, Stream *str);
+ void addProcessColor(double c, double m, double y, double k);
+ void addCustomColor(GfxSeparationColorSpace *sepCS);
+ void doPath(GfxPath *path);
+ void doImageL1(GfxImageColorMap *colorMap,
+ GBool invert, GBool inlineImg,
+ Stream *str, int width, int height, int len);
+ void doImageL1Sep(GfxImageColorMap *colorMap,
+ GBool invert, GBool inlineImg,
+ Stream *str, int width, int height, int len);
+ void doImageL2(Object *ref, GfxImageColorMap *colorMap,
+ GBool invert, GBool inlineImg,
+ Stream *str, int width, int height, int len);
+ void dumpColorSpaceL2(GfxColorSpace *colorSpace);
+#if OPI_SUPPORT
+ void opiBegin20(GfxState *state, Dict *dict);
+ void opiBegin13(GfxState *state, Dict *dict);
+ void opiTransform(GfxState *state, double x0, double y0,
+ double *x1, double *y1);
+ GBool getFileSpec(Object *fileSpec, Object *fileName);
+#endif
+ void writePS(const char *fmt, ...);
+ void writePSString(GString *s);
+
+ PSOutLevel level; // PostScript level (1, 2, separation)
+ PSOutMode mode; // PostScript mode (PS, EPS, form)
+ GBool doOPI; // generate OPI comments?
+ GBool embedType1; // embed Type 1 fonts?
+ GBool embedTrueType; // embed TrueType fonts?
+ int paperWidth; // width of paper, in pts
+ int paperHeight; // height of paper, in pts
+
+ FILE *f; // PostScript file
+ PSFileType fileType; // file / pipe / stdout
+ int seqPage; // current sequential page number
+
+ XRef *xref; // the xref table for this PDF file
+
+ Ref *fontIDs; // list of object IDs of all used fonts
+ int fontIDLen; // number of entries in fontIDs array
+ int fontIDSize; // size of fontIDs array
+ Ref *fontFileIDs; // list of object IDs of all embedded fonts
+ int fontFileIDLen; // number of entries in fontFileIDs array
+ int fontFileIDSize; // size of fontFileIDs array
+ GString **fontFileNames; // list of names of all embedded external fonts
+ int fontFileNameLen; // number of entries in fontFileNames array
+ int fontFileNameSize; // size of fontFileNames array
+
+ double tx, ty; // global translation
+ double xScale, yScale; // global scaling
+ GBool landscape; // true for landscape, false for portrait
+
+ GString *embFontList; // resource comments for embedded fonts
+
+ int processColors; // used process colors
+ PSOutCustomColor // used custom colors
+ *customColors;
+
+#if OPI_SUPPORT
+ int opi13Nest; // nesting level of OPI 1.3 objects
+ int opi20Nest; // nesting level of OPI 2.0 objects
+#endif
+
+ GBool type3Warning; // only show the Type 3 font warning once
+
+ GBool ok; // set up ok?
+};
+
+#endif
diff --git a/pdftops/Page.cxx b/pdftops/Page.cxx
new file mode 100644
index 000000000..975fcf1b6
--- /dev/null
+++ b/pdftops/Page.cxx
@@ -0,0 +1,268 @@
+//========================================================================
+//
+// Page.cc
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#include <stddef.h>
+#include "Object.h"
+#include "Array.h"
+#include "Dict.h"
+#include "XRef.h"
+#include "Link.h"
+#include "OutputDev.h"
+#ifndef PDF_PARSER_ONLY
+#include "Gfx.h"
+#include "FormWidget.h"
+#endif
+#include "Error.h"
+
+#include "Params.h"
+#include "Page.h"
+
+//------------------------------------------------------------------------
+// PageAttrs
+//------------------------------------------------------------------------
+
+PageAttrs::PageAttrs(PageAttrs *attrs, Dict *dict) {
+ Object obj1;
+ double w, h;
+
+ // get old/default values
+ if (attrs) {
+ mediaBox = attrs->mediaBox;
+ cropBox = attrs->cropBox;
+ haveCropBox = attrs->haveCropBox;
+ rotate = attrs->rotate;
+ attrs->resources.copy(&resources);
+ } else {
+ // set default MediaBox to 8.5" x 11" -- this shouldn't be necessary
+ // but some (non-compliant) PDF files don't specify a MediaBox
+ mediaBox.x1 = 0;
+ mediaBox.y1 = 0;
+ mediaBox.x2 = 612;
+ mediaBox.y2 = 792;
+ cropBox.x1 = cropBox.y1 = cropBox.x2 = cropBox.y2 = 0;
+ haveCropBox = gFalse;
+ rotate = 0;
+ resources.initNull();
+ }
+
+ // media box
+ readBox(dict, "MediaBox", &mediaBox);
+
+ // crop box
+ cropBox = mediaBox;
+ haveCropBox = readBox(dict, "CropBox", &cropBox);
+
+ // if the MediaBox is excessively larger than the CropBox,
+ // just use the CropBox
+ limitToCropBox = gFalse;
+ if (haveCropBox) {
+ w = 0.25 * (cropBox.x2 - cropBox.x1);
+ h = 0.25 * (cropBox.y2 - cropBox.y1);
+ if ((cropBox.x1 - mediaBox.x1) + (mediaBox.x2 - cropBox.x2) > w ||
+ (cropBox.y1 - mediaBox.y1) + (mediaBox.y2 - cropBox.y2) > h) {
+ limitToCropBox = gTrue;
+ }
+ }
+
+ // other boxes
+ bleedBox = cropBox;
+ readBox(dict, "BleedBox", &bleedBox);
+ trimBox = cropBox;
+ readBox(dict, "TrimBox", &trimBox);
+ artBox = cropBox;
+ readBox(dict, "ArtBox", &artBox);
+
+ // rotate
+ dict->lookup("Rotate", &obj1);
+ if (obj1.isInt()) {
+ rotate = obj1.getInt();
+ }
+ obj1.free();
+ while (rotate < 0) {
+ rotate += 360;
+ }
+ while (rotate >= 360) {
+ rotate -= 360;
+ }
+
+ // resource dictionary
+ dict->lookup("Resources", &obj1);
+ if (obj1.isDict()) {
+ resources.free();
+ obj1.copy(&resources);
+ }
+ obj1.free();
+}
+
+PageAttrs::~PageAttrs() {
+ resources.free();
+}
+
+GBool PageAttrs::readBox(Dict *dict, char *key, PDFRectangle *box) {
+ PDFRectangle tmp;
+ Object obj1, obj2;
+ GBool ok;
+
+ dict->lookup(key, &obj1);
+ if (obj1.isArray() && obj1.arrayGetLength() == 4) {
+ ok = gTrue;
+ obj1.arrayGet(0, &obj2);
+ if (obj2.isNum()) {
+ tmp.x1 = obj2.getNum();
+ } else {
+ ok = gFalse;
+ }
+ obj2.free();
+ obj1.arrayGet(1, &obj2);
+ if (obj2.isNum()) {
+ tmp.y1 = obj2.getNum();
+ } else {
+ ok = gFalse;
+ }
+ obj2.free();
+ obj1.arrayGet(2, &obj2);
+ if (obj2.isNum()) {
+ tmp.x2 = obj2.getNum();
+ } else {
+ ok = gFalse;
+ }
+ obj2.free();
+ obj1.arrayGet(3, &obj2);
+ if (obj2.isNum()) {
+ tmp.y2 = obj2.getNum();
+ } else {
+ ok = gFalse;
+ }
+ obj2.free();
+ if (ok) {
+ *box = tmp;
+ }
+ } else {
+ ok = gFalse;
+ }
+ obj1.free();
+ return ok;
+}
+
+//------------------------------------------------------------------------
+// Page
+//------------------------------------------------------------------------
+
+Page::Page(XRef *xrefA, int numA, Dict *pageDict, PageAttrs *attrsA,
+ GBool printCommandsA) {
+
+ ok = gTrue;
+ xref = xrefA;
+ num = numA;
+ printCommands = printCommandsA;
+
+ // get attributes
+ attrs = attrsA;
+
+ // annotations
+ pageDict->lookupNF("Annots", &annots);
+ if (!(annots.isRef() || annots.isArray() || annots.isNull())) {
+ error(-1, "Page annotations object (page %d) is wrong type (%s)",
+ num, annots.getTypeName());
+ annots.free();
+ goto err2;
+ }
+
+ // contents
+ pageDict->lookupNF("Contents", &contents);
+ if (!(contents.isRef() || contents.isArray() ||
+ contents.isNull())) {
+ error(-1, "Page contents object (page %d) is wrong type (%s)",
+ num, contents.getTypeName());
+ contents.free();
+ goto err1;
+ }
+
+ return;
+
+ err2:
+ annots.initNull();
+ err1:
+ contents.initNull();
+ ok = gFalse;
+}
+
+Page::~Page() {
+ delete attrs;
+ annots.free();
+ contents.free();
+}
+
+void Page::display(OutputDev *out, double dpi, int rotate,
+ Links *links, Catalog *catalog) {
+#ifndef PDF_PARSER_ONLY
+ PDFRectangle *box, *cropBox;
+ Gfx *gfx;
+ Object obj;
+ Link *link;
+ int i;
+ FormWidgets *formWidgets;
+
+ box = getBox();
+ cropBox = getCropBox();
+
+ if (printCommands) {
+ printf("***** MediaBox = ll:%g,%g ur:%g,%g\n",
+ box->x1, box->y1, box->x2, box->y2);
+ if (isCropped()) {
+ printf("***** CropBox = ll:%g,%g ur:%g,%g\n",
+ cropBox->x1, cropBox->y1, cropBox->x2, cropBox->y2);
+ }
+ printf("***** Rotate = %d\n", attrs->getRotate());
+ }
+
+ rotate += getRotate();
+ if (rotate >= 360) {
+ rotate -= 360;
+ } else if (rotate < 0) {
+ rotate += 360;
+ }
+ gfx = new Gfx(xref, out, num, attrs->getResourceDict(),
+ dpi, box, isCropped(), cropBox, rotate, printCommands);
+ contents.fetch(xref, &obj);
+ if (!obj.isNull()) {
+ gfx->display(&obj);
+ }
+ obj.free();
+
+ // draw links
+ if (links) {
+ for (i = 0; i < links->getNumLinks(); ++i) {
+ link = links->getLink(i);
+ out->drawLink(link, catalog);
+ }
+ out->dump();
+ }
+
+ // draw AcroForm widgets
+ //~ need to reset CTM ???
+ formWidgets = new FormWidgets(xref, annots.fetch(xref, &obj));
+ obj.free();
+ if (printCommands && formWidgets->getNumWidgets() > 0) {
+ printf("***** AcroForm widgets\n");
+ }
+ for (i = 0; i < formWidgets->getNumWidgets(); ++i) {
+ formWidgets->getWidget(i)->draw(gfx);
+ }
+ if (formWidgets->getNumWidgets() > 0) {
+ out->dump();
+ }
+ delete formWidgets;
+
+ delete gfx;
+#endif
+}
diff --git a/pdftops/Page.h b/pdftops/Page.h
new file mode 100644
index 000000000..a40974cfc
--- /dev/null
+++ b/pdftops/Page.h
@@ -0,0 +1,125 @@
+//========================================================================
+//
+// Page.h
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifndef PAGE_H
+#define PAGE_H
+
+#ifdef __GNUC__
+#pragma interface
+#endif
+
+#include "Object.h"
+
+class Dict;
+class XRef;
+class OutputDev;
+class Links;
+class Catalog;
+
+//------------------------------------------------------------------------
+
+struct PDFRectangle {
+ double x1, y1, x2, y2;
+};
+
+//------------------------------------------------------------------------
+// PageAttrs
+//------------------------------------------------------------------------
+
+class PageAttrs {
+public:
+
+ // Construct a new PageAttrs object by merging a dictionary
+ // (of type Pages or Page) into another PageAttrs object. If
+ // <attrs> is NULL, uses defaults.
+ PageAttrs(PageAttrs *attrs, Dict *dict);
+
+ // Destructor.
+ ~PageAttrs();
+
+ // Accessors.
+ PDFRectangle *getBox() { return limitToCropBox ? &cropBox : &mediaBox; }
+ PDFRectangle *getMediaBox() { return &mediaBox; }
+ PDFRectangle *getCropBox() { return &cropBox; }
+ GBool isCropped() { return haveCropBox; }
+ PDFRectangle *getBleedBox() { return &bleedBox; }
+ PDFRectangle *getTrimBox() { return &trimBox; }
+ PDFRectangle *getArtBox() { return &artBox; }
+ int getRotate() { return rotate; }
+ Dict *getResourceDict()
+ { return resources.isDict() ? resources.getDict() : (Dict *)NULL; }
+
+private:
+
+ GBool readBox(Dict *dict, char *key, PDFRectangle *box);
+
+ PDFRectangle mediaBox;
+ PDFRectangle cropBox;
+ GBool haveCropBox;
+ GBool limitToCropBox;
+ PDFRectangle bleedBox;
+ PDFRectangle trimBox;
+ PDFRectangle artBox;
+ int rotate;
+ Object resources;
+};
+
+//------------------------------------------------------------------------
+// Page
+//------------------------------------------------------------------------
+
+class Page {
+public:
+
+ // Constructor.
+ Page(XRef *xrefA, int numA, Dict *pageDict, PageAttrs *attrsA,
+ GBool printCommandsA);
+
+ // Destructor.
+ ~Page();
+
+ // Is page valid?
+ GBool isOk() { return ok; }
+
+ // Get page parameters.
+ PDFRectangle *getBox() { return attrs->getBox(); }
+ PDFRectangle *getMediaBox() { return attrs->getMediaBox(); }
+ PDFRectangle *getCropBox() { return attrs->getCropBox(); }
+ GBool isCropped() { return attrs->isCropped(); }
+ double getWidth() { return attrs->getBox()->x2 - attrs->getBox()->x1; }
+ double getHeight() { return attrs->getBox()->y2 - attrs->getBox()->y1; }
+ PDFRectangle *getBleedBox() { return attrs->getBleedBox(); }
+ PDFRectangle *getTrimBox() { return attrs->getTrimBox(); }
+ PDFRectangle *getArtBox() { return attrs->getArtBox(); }
+ int getRotate() { return attrs->getRotate(); }
+
+ // Get resource dictionary.
+ Dict *getResourceDict() { return attrs->getResourceDict(); }
+
+ // Get annotations array.
+ Object *getAnnots(Object *obj) { return annots.fetch(xref, obj); }
+
+ // Get contents.
+ Object *getContents(Object *obj) { return contents.fetch(xref, obj); }
+
+ // Display a page.
+ void display(OutputDev *out, double dpi, int rotate,
+ Links *links, Catalog *catalog);
+
+private:
+
+ XRef *xref; // the xref table for this PDF file
+ int num; // page number
+ PageAttrs *attrs; // page attributes
+ Object annots; // annotations array
+ Object contents; // page contents
+ GBool printCommands; // print the drawing commands (for debugging)
+ GBool ok; // true if page is valid
+};
+
+#endif
diff --git a/pdftops/Params.cxx b/pdftops/Params.cxx
new file mode 100644
index 000000000..8536da20d
--- /dev/null
+++ b/pdftops/Params.cxx
@@ -0,0 +1,90 @@
+//========================================================================
+//
+// Params.cc
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include "gtypes.h"
+#include "gmem.h"
+#include "GString.h"
+#include "gfile.h"
+#include "Params.h"
+
+char **fontPath = NULL;
+static int fontPathLen, fontPathSize;
+
+DevFontMapEntry *devFontMap = NULL;
+static int devFontMapLen, devFontMapSize;
+
+void initParams(char *userConfigFile, char *sysConfigFile) {
+ GString *fileName;
+ FILE *f;
+ char buf[256];
+ char *p, *q;
+
+ // initialize font path and font map
+ fontPath = (char **)gmalloc((fontPathSize = 8) * sizeof(char *));
+ fontPath[fontPathLen = 0] = NULL;
+ devFontMap = (DevFontMapEntry *)gmalloc((devFontMapSize = 8) *
+ sizeof(DevFontMapEntry));
+ devFontMap[devFontMapLen = 0].pdfFont = NULL;
+
+ // read config file
+ fileName = appendToPath(getHomeDir(), userConfigFile);
+ if (!(f = fopen(fileName->getCString(), "r"))) {
+ f = fopen(sysConfigFile, "r");
+ }
+ if (f) {
+ while (fgets(buf, sizeof(buf)-1, f)) {
+ buf[sizeof(buf)-1] = '\0';
+ p = strtok(buf, " \t\n\r");
+ if (p && !strcmp(p, "fontpath")) {
+ if (fontPathLen+1 >= fontPathSize)
+ fontPath = (char **)
+ grealloc(fontPath, (fontPathSize += 8) * sizeof(char *));
+ p = strtok(NULL, " \t\n\r");
+ fontPath[fontPathLen++] = copyString(p);
+ } else if (p && !strcmp(p, "fontmap")) {
+ if (devFontMapLen+1 >= devFontMapSize)
+ devFontMap = (DevFontMapEntry *)
+ grealloc(devFontMap,
+ (devFontMapSize += 8) * sizeof(DevFontMapEntry));
+ p = strtok(NULL, " \t\n\r");
+ devFontMap[devFontMapLen].pdfFont = copyString(p);
+ p = strtok(NULL, "\t\n\r");
+ while (*p == ' ')
+ ++p;
+ for (q = p + strlen(p) - 1; q >= p && *q == ' '; --q) ;
+ q[1] = '\0';
+ devFontMap[devFontMapLen++].devFont = copyString(p);
+ }
+ }
+ fclose(f);
+ fontPath[fontPathLen] = NULL;
+ devFontMap[devFontMapLen].pdfFont = NULL;
+ }
+ delete fileName;
+}
+
+void freeParams() {
+ int i;
+
+ if (fontPath) {
+ for (i = 0; i < fontPathLen; ++i)
+ gfree(fontPath[i]);
+ gfree(fontPath);
+ }
+ if (devFontMap) {
+ for (i = 0; i < devFontMapLen; ++i) {
+ gfree(devFontMap[i].pdfFont);
+ gfree(devFontMap[i].devFont);
+ }
+ gfree(devFontMap);
+ }
+}
diff --git a/pdftops/Params.h b/pdftops/Params.h
new file mode 100644
index 000000000..1d8ce3828
--- /dev/null
+++ b/pdftops/Params.h
@@ -0,0 +1,38 @@
+//========================================================================
+//
+// Params.h
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifndef PARAMS_H
+#define PARAMS_H
+
+#include "gtypes.h"
+
+// If this is set, error messages will be silently discarded.
+extern GBool errQuiet;
+
+// Font search path.
+extern char **fontPath;
+
+// Mapping from PDF font name to device font name.
+struct DevFontMapEntry {
+ char *pdfFont;
+ char *devFont;
+};
+extern DevFontMapEntry *devFontMap;
+
+//------------------------------------------------------------------------
+
+// Initialize font path and font map, and read configuration file. If
+// <userConfigFile> exists, read it; else if <sysConfigFile> exists,
+// read it. <userConfigFile> is relative to the user's home
+// directory; <sysConfigFile> should be an absolute path.
+extern void initParams(char *userConfigFile, char *sysConfigFile);
+
+// Free memory used for font path and font map.
+extern void freeParams();
+
+#endif
diff --git a/pdftops/Parser.cxx b/pdftops/Parser.cxx
new file mode 100644
index 000000000..57ba05061
--- /dev/null
+++ b/pdftops/Parser.cxx
@@ -0,0 +1,212 @@
+//========================================================================
+//
+// Parser.cc
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#include <stddef.h>
+#include "Object.h"
+#include "Array.h"
+#include "Dict.h"
+#include "Parser.h"
+#include "XRef.h"
+#include "Error.h"
+#ifndef NO_DECRYPTION
+#include "Decrypt.h"
+#endif
+
+Parser::Parser(XRef *xrefA, Lexer *lexerA) {
+ xref = xrefA;
+ lexer = lexerA;
+ inlineImg = 0;
+ lexer->getObj(&buf1);
+ lexer->getObj(&buf2);
+}
+
+Parser::~Parser() {
+ buf1.free();
+ buf2.free();
+ delete lexer;
+}
+
+#ifndef NO_DECRYPTION
+Object *Parser::getObj(Object *obj,
+ Guchar *fileKey, int keyLength,
+ int objNum, int objGen) {
+#else
+Object *Parser::getObj(Object *obj) {
+#endif
+ char *key;
+ Stream *str;
+ Object obj2;
+ int num;
+#ifndef NO_DECRYPTION
+ Decrypt *decrypt;
+ GString *s;
+ char *p;
+ int i;
+#endif
+
+ // refill buffer after inline image data
+ if (inlineImg == 2) {
+ buf1.free();
+ buf2.free();
+ lexer->getObj(&buf1);
+ lexer->getObj(&buf2);
+ inlineImg = 0;
+ }
+
+ // array
+ if (buf1.isCmd("[")) {
+ shift();
+ obj->initArray(xref);
+ while (!buf1.isCmd("]") && !buf1.isEOF())
+#ifndef NO_DECRYPTION
+ obj->arrayAdd(getObj(&obj2, fileKey, keyLength, objNum, objGen));
+#else
+ obj->arrayAdd(getObj(&obj2));
+#endif
+ if (buf1.isEOF())
+ error(getPos(), "End of file inside array");
+ shift();
+
+ // dictionary or stream
+ } else if (buf1.isCmd("<<")) {
+ shift();
+ obj->initDict(xref);
+ while (!buf1.isCmd(">>") && !buf1.isEOF()) {
+ if (!buf1.isName()) {
+ error(getPos(), "Dictionary key must be a name object");
+ shift();
+ } else {
+ key = copyString(buf1.getName());
+ shift();
+ if (buf1.isEOF() || buf1.isError())
+ break;
+#ifndef NO_DECRYPTION
+ obj->dictAdd(key, getObj(&obj2, fileKey, keyLength, objNum, objGen));
+#else
+ obj->dictAdd(key, getObj(&obj2));
+#endif
+ }
+ }
+ if (buf1.isEOF())
+ error(getPos(), "End of file inside dictionary");
+ if (buf2.isCmd("stream")) {
+ if ((str = makeStream(obj))) {
+ obj->initStream(str);
+#ifndef NO_DECRYPTION
+ if (fileKey) {
+ str->getBaseStream()->doDecryption(fileKey, keyLength,
+ objNum, objGen);
+ }
+#endif
+ } else {
+ obj->free();
+ obj->initError();
+ }
+ } else {
+ shift();
+ }
+
+ // indirect reference or integer
+ } else if (buf1.isInt()) {
+ num = buf1.getInt();
+ shift();
+ if (buf1.isInt() && buf2.isCmd("R")) {
+ obj->initRef(num, buf1.getInt());
+ shift();
+ shift();
+ } else {
+ obj->initInt(num);
+ }
+
+#ifndef NO_DECRYPTION
+ // string
+ } else if (buf1.isString() && fileKey) {
+ buf1.copy(obj);
+ s = obj->getString();
+ decrypt = new Decrypt(fileKey, keyLength, objNum, objGen);
+ for (i = 0, p = obj->getString()->getCString();
+ i < s->getLength();
+ ++i, ++p) {
+ *p = decrypt->decryptByte(*p);
+ }
+ delete decrypt;
+ shift();
+#endif
+
+ // simple object
+ } else {
+ buf1.copy(obj);
+ shift();
+ }
+
+ return obj;
+}
+
+Stream *Parser::makeStream(Object *dict) {
+ Object obj;
+ Stream *str;
+ int pos, endPos, length;
+
+ // get stream start position
+ lexer->skipToNextLine();
+ pos = lexer->getPos();
+
+ // get length
+ dict->dictLookup("Length", &obj);
+ if (obj.isInt()) {
+ length = obj.getInt();
+ obj.free();
+ } else {
+ error(getPos(), "Bad 'Length' attribute in stream");
+ obj.free();
+ return NULL;
+ }
+
+ // check for length in damaged file
+ if ((endPos = xref->getStreamEnd(pos)) >= 0) {
+ length = endPos - pos;
+ }
+
+ // make base stream
+ str = lexer->getStream()->getBaseStream()->makeSubStream(pos, length, dict);
+
+ // get filters
+ str = str->addFilters(dict);
+
+ // skip over stream data
+ lexer->setPos(pos + length);
+
+ // refill token buffers and check for 'endstream'
+ shift(); // kill '>>'
+ shift(); // kill 'stream'
+ if (buf1.isCmd("endstream"))
+ shift();
+ else
+ error(getPos(), "Missing 'endstream'");
+
+ return str;
+}
+
+void Parser::shift() {
+ if (inlineImg > 0) {
+ ++inlineImg;
+ } else if (buf2.isCmd("ID")) {
+ lexer->skipChar(); // skip char after 'ID' command
+ inlineImg = 1;
+ }
+ buf1.free();
+ buf1 = buf2;
+ if (inlineImg > 0) // don't buffer inline image data
+ buf2.initNull();
+ else
+ lexer->getObj(&buf2);
+}
diff --git a/pdftops/Parser.h b/pdftops/Parser.h
new file mode 100644
index 000000000..463d99827
--- /dev/null
+++ b/pdftops/Parser.h
@@ -0,0 +1,58 @@
+//========================================================================
+//
+// Parser.h
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifndef PARSER_H
+#define PARSER_H
+
+#ifdef __GNUC__
+#pragma interface
+#endif
+
+#include "Lexer.h"
+
+//------------------------------------------------------------------------
+// Parser
+//------------------------------------------------------------------------
+
+class Parser {
+public:
+
+ // Constructor.
+ Parser(XRef *xrefA, Lexer *lexerA);
+
+ // Destructor.
+ ~Parser();
+
+ // Get the next object from the input stream.
+#ifndef NO_DECRYPTION
+ Object *getObj(Object *obj,
+ Guchar *fileKey = NULL, int keyLength = 0,
+ int objNum = 0, int objGen = 0);
+#else
+ Object *getObj(Object *obj);
+#endif
+
+ // Get stream.
+ Stream *getStream() { return lexer->getStream(); }
+
+ // Get current position in file.
+ int getPos() { return lexer->getPos(); }
+
+private:
+
+ XRef *xref; // the xref table for this PDF file
+ Lexer *lexer; // input stream
+ Object buf1, buf2; // next two tokens
+ int inlineImg; // set when inline image data is encountered
+
+ Stream *makeStream(Object *dict);
+ void shift();
+};
+
+#endif
+
diff --git a/pdftops/README b/pdftops/README
new file mode 100644
index 000000000..4835a82f8
--- /dev/null
+++ b/pdftops/README
@@ -0,0 +1,426 @@
+Xpdf
+====
+
+version 0.93
+2001-oct-25
+
+The Xpdf software and documentation are
+copyright 1996-2001 Derek B. Noonburg.
+
+Email: derekn@foolabs.com
+WWW: http://www.foolabs.com/xpdf/
+
+The PDF data structures, operators, and specification are
+copyright 1995 Adobe Systems Inc.
+
+
+What is Xpdf?
+-------------
+
+Xpdf is a viewer for Portable Document Format (PDF) files. (These are
+also sometimes also called 'Acrobat' files, from the name of Adobe's
+PDF software.) Xpdf runs under the X Window System on UNIX, VMS, and
+OS/2. The non-X components of the package (pdftops, pdftotext, etc.)
+also run on Win32 systems and should run on pretty much any system
+with a decent C++ compiler.
+
+Xpdf is designed to be small and efficient. It can use Type 1,
+TrueType, or standard X fonts.
+
+
+Distribution
+------------
+
+Xpdf is licensed under the GNU General Public License (GPL), version
+2. In my opinion, the GPL is a convoluted, confusing, ambiguous mess.
+But it's also pervasive, and I'm sick of arguing. And even if it is
+confusing, the basic idea is good.
+
+In order to cut down on the confusion a little bit, here are some
+informal clarifications:
+
+- I don't mind if you redistribute Xpdf in source and/or binary form,
+ as long as you include all of the documentation: README, man pages
+ (or help files), and COPYING. (Note that the README file contains a
+ pointer to a web page with the source code.)
+
+- Selling a CD-ROM that contains Xpdf is fine with me, as long as it
+ includes the documentation. I wouldn't mind receiving a sample
+ copy, but it's not necessary.
+
+- If you make useful changes to Xpdf, please make the source code
+ available -- post it on a web site, email it to me, whatever.
+
+If you're interested in commercial licensing, please contact me by
+email: derekn@foolabs.com .
+
+
+Compatibility
+-------------
+
+Xpdf is developed and tested on a Linux 2.2 x86 system.
+
+In addition, it has been compiled by others on Solaris, AIX, HP-UX,
+SCO UnixWare, Digital Unix, Irix, and numerous other Unix
+implementations, as well as VMS and OS/2. It should work on pretty
+much any system which runs X11 and has Unix-like libraries. You'll
+need ANSI C++ and C compilers to compile it.
+
+The non-X components of Xpdf (pdftops, pdftotext, pdfinfo, pdfimages)
+can also be compiled on Win32 systems. See the Xpdf web page for
+details.
+
+If you compile Xpdf for a system not listed on the web page, please
+let me know. If you're willing to make your binary available by ftp
+or on the web, I'll be happy to add a link from the Xpdf web page. I
+have decided not to host any binaries I didn't compile myself (for
+disk space and support reasons).
+
+If you can't get Xpdf to compile on your system, send me email and
+I'll try to help.
+
+Xpdf has been ported to the Acorn, Amiga, BeOS, and EPOC. See the
+Xpdf web page for links.
+
+
+Getting Xpdf
+------------
+
+The latest version is available from:
+
+ http://www.foolabs.com/xpdf/
+
+or:
+
+ ftp://ftp.foolabs.com/pub/xpdf/
+
+Source code and several precompiled executables are available.
+
+Announcements of new versions are posted to several newsgroups
+(comp.text.pdf, comp.os.linux.announce, and others) and emailed to a
+list of people. If you'd like to receive email notification of new
+versions, just let me know.
+
+
+Running Xpdf
+------------
+
+To run xpdf, simply type:
+
+ xpdf file.pdf
+
+To generate a PostScript file, hit the "print" button in xpdf, or run
+pdftops:
+
+ pdftops file.pdf
+
+To generate a plain text file, run pdftotext:
+
+ pdftotext file.pdf
+
+There are three additional utilities (which are fully described in
+their man pages):
+
+ pdfinfo -- dumps a PDF file's Info dictionary (plus some other
+ useful information)
+ pdftopbm -- converts a PDF file to a series of PBM-format bitmaps
+ pdfimages -- extracts the images from a PDF file
+
+Command line options and many other details are described in the man
+pages (xpdf.1, etc.) and the VMS help files (xpdf.hlp, etc.).
+
+
+Fonts
+-----
+
+Xpdf uses X server fonts. It requires the following fonts:
+
+* Courier: medium-r, bold-r, medium-o, and bold-o
+* Helvetica: medium-r, bold-r, medium-o, and bold-o
+* Times: medium-r, bold-r, medium-i, and bold-i
+* Symbol: medium-r
+* Zapf Dingbats: medium-r
+
+Most X installations should already have all of these fonts, except
+Zapf Dingbats. You can install a Type 1 Zapf Dingbats font -- see the
+mkfontdir(1) man page for details. Use this font descriptor in your
+fonts.scale file:
+
+ -itc-zapfdingbats-medium-r-normal--0-0-0-0-p-0-adobe-fontspecific
+
+You can get a Type 1 font file from the ghostscript 4.x distribution
+(look for d050000l.pfb).
+
+X servers, starting at R5, support font scaling. Xpdf will
+automatically take advantage of this. There are two types of scaling.
+The first type uses standard bitmap fonts: if a font doesn't exist in
+the requested size, the server will scale the bitmapped characters.
+This is reasonably fast, and the results are readable but not very
+pretty. X servers can also handle true scalable, e.g., Type 1, fonts.
+(See the mkfontdir(1) man page for details on setting these up.)
+Scalable fonts are slower, especially since PDF documents tend to use
+lots of fonts, but they look much nicer.
+
+Some X servers also support font rotation. Xpdf will use this feature
+if available.
+
+For Japanese support, you will need a Japanese font of the form:
+
+ -*-fixed-medium-r-normal-*-NN-*-*-*-*-*-jisx0208.1983-0
+
+and an X server that can handle 16-bit fonts. You can also set this
+font using the xpdf.japaneseFont resource.
+
+For Chinese GB (simplified Chinese) support, you will need a font of
+the form:
+
+ -*-fangsong ti-medium-r-normal-*-%s-*-*-*-*-*-gb2312.1980-0
+
+You can replace this font using the xpdf.chineseGBFont resource.
+
+For Chinese CNS (traditional Chinese) support, you will need a font of
+the form:
+
+ -*-fixed-medium-r-normal--*-%s-*-*-*-*-big5-0
+
+You can replace this font using the xpdf.chineseCNSFont resource.
+
+If compiled with t1lib support, xpdf will use t1lib to render embedded
+Type 1 and Type 1C fonts. In addition, xpdf can be configured to use
+t1lib for the base 14 fonts and for substituted fonts. To enable this
+feature, you must set an X resource for each Type 1 font file. For
+example:
+
+ xpdf.t1TimesRoman: /usr/local/fonts/Times-Roman.pfa
+ xpdf.t1TimesItalic: /usr/local/fonts/Times-Italic.pfa
+ xpdf.t1TimesBold: /usr/local/fonts/Times-Bold.pfa
+ xpdf.t1TimesBoldItalic: /usr/local/fonts/Times-BoldItalic.pfa
+ xpdf.t1Helvetica: /usr/local/fonts/Helvetica.pfa
+ xpdf.t1HelveticaOblique: /usr/local/fonts/Helvetica-Oblique.pfa
+ xpdf.t1HelveticaBold: /usr/local/fonts/Helvetica-Bold.pfa
+ xpdf.t1HelveticaBoldOblique: /usr/local/fonts/Helvetica-BoldOblique.pfa
+ xpdf.t1Courier: /usr/local/fonts/Courier.pfa
+ xpdf.t1CourierOblique: /usr/local/fonts/Courier-Oblique.pfa
+ xpdf.t1CourierBold: /usr/local/fonts/Courier-Bold.pfa
+ xpdf.t1CourierBoldOblique: /usr/local/fonts/Courier-BoldOblique.pfa
+ xpdf.t1Symbol: /usr/local/fonts/Symbol.pfa
+ xpdf.t1ZapfDingbats: /usr/local/fonts/ZapfDingbats.pfa
+
+Ghostscript comes with a set of free, high-quality Type 1 fonts,
+donated by URW++ Design and Development Incorporated. The xpdf X
+resources needed for these fonts are:
+
+ xpdf.t1TimesRoman: /usr/ghostscript/fonts/n021003l.pfb
+ xpdf.t1TimesItalic: /usr/ghostscript/fonts/n021023l.pfb
+ xpdf.t1TimesBold: /usr/ghostscript/fonts/n021004l.pfb
+ xpdf.t1TimesBoldItalic: /usr/ghostscript/fonts/n021024l.pfb
+ xpdf.t1Helvetica: /usr/ghostscript/fonts/n019003l.pfb
+ xpdf.t1HelveticaOblique: /usr/ghostscript/fonts/n019023l.pfb
+ xpdf.t1HelveticaBold: /usr/ghostscript/fonts/n019004l.pfb
+ xpdf.t1HelveticaBoldOblique: /usr/ghostscript/fonts/n019024l.pfb
+ xpdf.t1Courier: /usr/ghostscript/fonts/n022003l.pfb
+ xpdf.t1CourierOblique: /usr/ghostscript/fonts/n022023l.pfb
+ xpdf.t1CourierBold: /usr/ghostscript/fonts/n022004l.pfb
+ xpdf.t1CourierBoldOblique: /usr/ghostscript/fonts/n022024l.pfb
+ xpdf.t1Symbol: /usr/ghostscript/fonts/s050000l.pfb
+ xpdf.t1ZapfDingbats: /usr/ghostscript/fonts/d050000l.pfb
+
+You will obviously need to replace '/usr/ghostscript/fonts' with the
+appropriate path on your system.
+
+
+The Unisys LZW Patent
+---------------------
+
+Nearly all PDF files include data which has been compressed with the
+LZW compression algorithm. Unfortunately, LZW is covered by a
+software patent which is owned by Unisys Corporation. Unisys refuses
+to license this patent for PDF-related use in software such as Xpdf
+which is released for free and which may be freely redistributed.
+(This is same algorithm which is used by GIF. However, Unisys is not
+doing licensing for free PDF viwers in the same way as for free GIF
+viewers.)
+
+As a workaround, Xpdf converts PDF-format LZW data to compress-format
+LZW data. (The standard UNIX compress utility also uses LZW, but with
+a slightly different file format.) This conversion does *not*
+decompress the data; it simply converts it to a different file format.
+Xpdf then calls uncompress to actually decompress the data.
+
+I have been told by several notable people that the LZW patent covers
+compression only, and does not cover decompression. This seems pretty
+fuzzy to me, so I'm going to stick with my workaround, at least for
+now.
+
+For Unisys's slant on things (mostly regarding GIF), see
+<http://www.unisys.com/LeadStory/lzwterms.html> and
+<http://www.unisys.com/LeadStory/lzwfaq.html>. These pages mention
+an email address for feedback.
+
+
+Compiling Xpdf
+--------------
+
+See the separate file, INSTALL.
+
+
+Bugs
+----
+
+Type 3 fonts are still not well supported by Xpdf.
+
+If you find a bug in Xpdf, i.e., if it prints an error message,
+crashes, or incorrectly displays a document, and you don't see that
+bug listed here, please send me email, with a pointer (URL, ftp site,
+etc.) to the PDF file.
+
+
+Acknowledgments
+---------------
+
+Thanks to:
+
+* Patrick Voigt for help with the remote server code.
+* Patrick Moreau, Martin P.J. Zinser, and David Mathog for the VMS
+ port.
+* David Boldt and Rick Rodgers for sample man pages.
+* Brendan Miller for the icon idea.
+* Olly Betts for help testing pdftotext.
+* Peter Ganten for the OS/2 port.
+* Michael Richmond for the Win32 port of pdftops and pdftotext.
+* Frank M. Siegert for improvements in the PostScript code.
+* Leo Smiers for the decryption patches.
+* Rainer Menzner for creating t1lib, and for helping me adapt it to
+ xpdf.
+* Pine Tree Systems A/S for funding the OPI and EPS support in
+ pdftops.
+* Easy Software Products for funding the "sh" operator support.
+
+
+References
+----------
+
+Adobe Systems Inc., _PDF Reference_, 2nd ed.
+Addison-Wesley, 2000, ISBN 0-201-61588-6.
+[The printed manual for PDF version 1.3.]
+
+Adobe Systems Inc., _Portable Document Format: Changes from Version
+1.3 to 1.4_, Adobe Developer Support Technical Note #5409.
+June 11, 2001.
+http://partners.adobe.com/asn/developer/acrosdk/docs/filefmtspecs/PDF14Deltas.pdf
+[Updates for PDF 1.4.]
+
+Adobe Systems Inc., _PostScript Language Reference_, 3rd ed.
+Addison-Wesley, 1999, ISBN 0-201-37922-8.
+[The official PostScript manual.]
+
+Adobe Systems, Inc., _The Type 42 Font Format Specification_,
+Adobe Developer Support Technical Specification #5012. 1998.
+http://partners.adobe.com/asn/developer/pdfs/tn/5012.Type42_Spec.pdf
+[Type 42 is the format used to embed TrueType fonts in PostScript
+files.]
+
+Adobe Systems, Inc., _Adobe CMap and CIDFont Files Specification_,
+Adobe Developer Support Technical Specification #5014. 1995.
+http://www.adobe.com/supportservice/devrelations/PDFS/TN/5014.CIDFont_Spec.pdf
+[CMap file format needed for Japanese and Chinese font support.]
+
+Adobe Systems, Inc., _Adobe-Japan1-2 Character Collection for
+CID-Keyed Fonts_, Adobe Developer Support Technical Note #5078.
+1994.
+http://partners.adobe.com/asn/developer/PDFS/TN/5078.CID_Glyph.pdf
+[The Adobe Japanese character set.]
+
+Adobe Systems, Inc., _Adobe-GB1-3 Character Collection for
+CID-Keyed Fonts_, Adobe Developer Support Technical Note #5079.
+1998.
+http://partners.adobe.com/asn/developer/PDFS/TN/5079.GB_CharColl.pdf
+[The Adobe Chinese GB character set.]
+
+Adobe Systems, Inc., _Adobe-CNS1-3 Character Collection for
+CID-Keyed Fonts_, Adobe Developer Support Technical Note #5080.
+2000.
+http://partners.adobe.com/asn/developer/PDFS/TN/5080.CNS_CharColl.pdf
+[The Adobe Chinese CNS character set.]
+
+Adobe Systems Inc., _Supporting the DCT Filters in PostScript Level
+2_, Adobe Developer Support Technical Note #5116. 1992.
+http://www.adobe.com/supportservice/devrelations/PDFS/TN/5116.PS2_DCT.PDF
+[Description of the DCTDecode filter parameters.]
+
+Adobe Systems Inc., _Open Prepress Interface (OPI) Specification -
+Version 2.0_, Adobe Developer Support Technical Note #5660. 2000.
+http://partners.adobe.com/asn/developer/PDFS/TN/5660.OPI_2.0.pdf
+
+Adobe Systems Inc., CMap files.
+ftp://ftp.oreilly.com/pub/examples/nutshell/cjkv/adobe/
+[The actual CMap files for the 16-bit CJK encodings.]
+
+Aldus Corp., _OPI: Open Prepress Interface Specification 1.3_. 1993.
+http://partners.adobe.com/asn/developer/PDFS/TN/OPI_13.pdf
+
+Anonymous, RC4 source code.
+ftp://ftp.ox.ac.uk/pub/crypto/misc/rc4.tar.gz
+ftp://idea.sec.dsi.unimi.it/pub/crypt/code/rc4.tar.gz
+[This is the algorithm used to encrypt PDF files.]
+
+CCITT, _Blue Book_, Volume VII Fascicle 3: "Terminal Equipment and
+Protocols for Telematic Services", Recommendations T.4 and T.6.
+ftp://ftp.uu.net/doc/standards/ccitt/1988/7_3_01.ps
+ftp://ftp.uu.net/doc/standards/ccitt/1988/7_3_02.ps
+[The official Group 3 and 4 fax standards. The online copies are
+unfortunately misformatted.]
+
+L. Peter Deutsch, "ZLIB Compressed Data Format Specification version
+3.3". RFC 1950.
+[Information on the general format used in FlateDecode streams.]
+
+L. Peter Deutsch, "DEFLATE Compressed Data Format Specification
+version 1.3". RFC 1951.
+[The definition of the compression algorithm used in FlateDecode
+streams.]
+
+Jim Flowers, "X Logical Font Description Conventions", Version 1.5, X
+Consortium Standard, X Version 11, Release 6.1.
+ftp://ftp.x.org/pub/R6.1/xc/doc/hardcopy/XLFD/xlfd.PS.Z
+[The official specification of X font descriptors, including font
+transformation matrices.]
+
+Foley, van Dam, Feiner, and Hughes, _Computer Graphics: Principles and
+Practice_, 2nd ed. Addison-Wesley, 1990, ISBN 0-201-12110-7.
+[Colorspace conversion functions, Bezier spline math.]
+
+Robert L. Hummel, _Programmer's Technical Reference: Data and Fax
+Communications_. Ziff-Davis Press, 1993, ISBN 1-56276-077-7.
+[CCITT Group 3 and 4 fax decoding.]
+
+Christoph Loeffler, Adriaan Ligtenberg, George S. Moschytz, "Practical
+Fast 1-D DCT Algorithms with 11 Multiplications". IEEE Intl. Conf. on
+Acoustics, Speech & Signal Processing, 1989, 988-991.
+[The fast IDCT algorithm used in the DCTDecode filter.]
+
+Microsoft, _TrueType 1.0 Font Files_, rev. 1.66. 1995.
+http://www.microsoft.com/typography/tt/tt.htm
+[The TrueType font spec (in MS Word format, naturally).]
+
+Charles Poynton, "Color FAQ".
+http://www.inforamp.net/~poynton/ColorFAQ.html
+[The mapping from the CIE 1931 (XYZ) color space to RGB.]
+
+R. Rivest, "The MD5 Message-Digest Algorithm". RFC 1321.
+[MD5 is used in PDF document encryption.]
+
+Gregory K. Wallace, "The JPEG Still Picture Compression Standard".
+ftp://ftp.uu.net/graphics/jpeg/wallace.ps.gz
+[Good description of the JPEG standard. Also published in CACM, April
+1991, and submitted to IEEE Transactions on Consumer Electronics.]
+
+W3C Recommendation, "PNG (Portable Network Graphics) Specification
+Version 1.0".
+http://www.w3.org/Graphics/PNG/
+[Defines the PNG image predictor.]
+
+"ISO 8859-2 (Latin 2) Resources".
+http://sizif.mf.uni-lj.si/linux/cee/iso8859-2.html
+[This is a web page with all sorts of useful Latin-2 character set and
+font information.]
diff --git a/pdftops/SFont.h b/pdftops/SFont.h
new file mode 100644
index 000000000..cab17961e
--- /dev/null
+++ b/pdftops/SFont.h
@@ -0,0 +1,127 @@
+//========================================================================
+//
+// SFont.h
+//
+// Base class for font rasterizers.
+//
+//========================================================================
+
+#ifndef SFONT_H
+#define SFONT_H
+
+#ifdef __GNUC__
+#pragma interface
+#endif
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include "gtypes.h"
+
+//------------------------------------------------------------------------
+
+class SFontEngine {
+public:
+
+ SFontEngine(Display *displayA, Visual *visualA, int depthA,
+ Colormap colormapA);
+ virtual ~SFontEngine();
+
+ // Use a TrueColor visual. Pixel values are computed as:
+ //
+ // (r << rShift) + (g << gShift) + (b << bShift)
+ //
+ // where r, g, and b are scaled to the ranges [0,rMax], [0,gMax],
+ // and [0,bMax], respectively.
+ virtual void useTrueColor(int rMaxA, int rShiftA, int gMaxA, int gShiftA,
+ int bMaxA, int bShiftA);
+
+ // Use an RGB color cube. <colors> is an array containing
+ // <nRGB>*<nRGB>*<nRGB> pixel values in red,green,blue order, e.g.,
+ // for <nRGB>=2, there will be 8 entries:
+ //
+ // |--- colors[i] ---|
+ // i red green blue
+ // - ----- ----- -----
+ // 0 0000 0000 0000
+ // 1 0000 0000 ffff
+ // 2 0000 ffff 0000
+ // 3 0000 ffff ffff
+ // 4 ffff 0000 0000
+ // 5 ffff 0000 ffff
+ // 6 ffff ffff 0000
+ // 7 ffff ffff ffff
+ //
+ // The <colors> array is not copied and must remain valid for the
+ // lifetime of this SFont object.
+ virtual void useColorCube(Gulong *colorsA, int nRGBA);
+
+protected:
+
+ // Find the closest match to (<r>,<g>,<b>).
+ Gulong findColor(int r, int g, int b);
+
+ //----- X parameters
+ Display *display;
+ Visual *visual;
+ int depth;
+ Colormap colormap;
+
+ GBool trueColor; // true for TrueColor, false for RGB cube
+
+ //----- TrueColor parameters
+ int rMax, gMax, bMax;
+ int rShift, gShift, bShift;
+
+ //----- RGB color cube parameters
+ Gulong *colors;
+ int nRGB;
+};
+
+//------------------------------------------------------------------------
+
+class SFontFile {
+public:
+
+ // A typical subclass will provide a constructor along the lines of:
+ //
+ // SomeFontFile(SomeFontEngine *engine, char *fontFileName);
+ SFontFile();
+
+ virtual ~SFontFile();
+
+private:
+};
+
+//------------------------------------------------------------------------
+
+class SFont {
+public:
+
+ // A typical subclass will provide a constructor along the lines of:
+ //
+ // SomeFont(SomeFontFile *fontFile, double *m);
+ //
+ // where <m> is a transform matrix consisting of four elements,
+ // using the PostScript ordering conventions (without any
+ // translation):
+ //
+ // [x' y'] = [x y] * [m0 m1]
+ // [m2 m3]
+ //
+ // This is the level at which fonts are cached, and so the font
+ // cannot be transformed after it is created.
+ SFont();
+
+ virtual ~SFont();
+
+ // Draw a character <c> at <x>,<y> in color (<r>,<g>,<b>). The RGB
+ // values should each be in the range [0,65535]. Draws into <d>,
+ // clipped to the rectangle (0,0)-(<w>-1,<h>-1). Returns true if
+ // the character was drawn successfully.
+ virtual GBool drawChar(Drawable d, int w, int h, GC gc,
+ int x, int y, int r, int g, int b, Gushort c) = 0;
+
+protected:
+};
+
+#endif
diff --git a/pdftops/StdFontInfo.h b/pdftops/StdFontInfo.h
new file mode 100644
index 000000000..0db033f6b
--- /dev/null
+++ b/pdftops/StdFontInfo.h
@@ -0,0 +1,546 @@
+//========================================================================
+//
+// StdFontInfo.h
+//
+// This file was automatically generated by makeFontInfo.
+//
+// Copyright 1999 Derek B. Noonburg
+//
+//========================================================================
+
+#ifndef STDFONTINFO_H
+#define STDFONTINFO_H
+
+//------------------------------------------------------------------------
+// type1StdEncoding -- Adobe Type 1 StandardEncoding
+//------------------------------------------------------------------------
+
+#define type1StdEncodingSize 256
+static char *type1StdEncodingNames[type1StdEncodingSize] = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "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",
+ "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",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "exclamdown",
+ "cent",
+ "sterling",
+ "fraction",
+ "yen",
+ "florin",
+ "section",
+ "currency",
+ "quotesingle",
+ "quotedblleft",
+ "guillemotleft",
+ "guilsinglleft",
+ "guilsinglright",
+ "fi",
+ "fl",
+ NULL,
+ "endash",
+ "dagger",
+ "daggerdbl",
+ "periodcentered",
+ NULL,
+ "paragraph",
+ "bullet",
+ "quotesinglbase",
+ "quotedblbase",
+ "quotedblright",
+ "guillemotright",
+ "ellipsis",
+ "perthousand",
+ NULL,
+ "questiondown",
+ NULL,
+ "grave",
+ "acute",
+ "circumflex",
+ "tilde",
+ "macron",
+ "breve",
+ "dotaccent",
+ "dieresis",
+ NULL,
+ "ring",
+ "cedilla",
+ NULL,
+ "hungarumlaut",
+ "ogonek",
+ "caron",
+ "emdash",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "AE",
+ NULL,
+ "ordfeminine",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Lslash",
+ "Oslash",
+ "OE",
+ "ordmasculine",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "ae",
+ NULL,
+ NULL,
+ NULL,
+ "dotlessi",
+ NULL,
+ NULL,
+ "lslash",
+ "oslash",
+ "oe",
+ "germandbls",
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+static FontEncoding type1StdEncoding(type1StdEncodingNames,
+ type1StdEncodingSize);
+
+//------------------------------------------------------------------------
+// type1ExpertEncoding -- Adobe Type 1 ExpertEncoding
+//------------------------------------------------------------------------
+
+#define type1ExpertEncodingSize 256
+static char *type1ExpertEncodingNames[type1ExpertEncodingSize] = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "space",
+ "exclamsmall",
+ "Hungarumlautsmall",
+ NULL,
+ "dollaroldstyle",
+ "dollarsuperior",
+ "ampersandsmall",
+ "Acutesmall",
+ "parenleftsuperior",
+ "parenrightsuperior",
+ "twodotenleader",
+ "onedotenleader",
+ "comma",
+ "hyphen",
+ "period",
+ "fraction",
+ "zerooldstyle",
+ "oneoldstyle",
+ "twooldstyle",
+ "threeoldstyle",
+ "fouroldstyle",
+ "fiveoldstyle",
+ "sixoldstyle",
+ "sevenoldstyle",
+ "eightoldstyle",
+ "nineoldstyle",
+ "colon",
+ "semicolon",
+ "commasuperior",
+ "threequartersemdash",
+ "periodsuperior",
+ "questionsmall",
+ NULL,
+ "asuperior",
+ "bsuperior",
+ "centsuperior",
+ "dsuperior",
+ "esuperior",
+ NULL,
+ NULL,
+ NULL,
+ "isuperior",
+ NULL,
+ NULL,
+ "lsuperior",
+ "msuperior",
+ "nsuperior",
+ "osuperior",
+ NULL,
+ NULL,
+ "rsuperior",
+ "ssuperior",
+ "tsuperior",
+ NULL,
+ "ff",
+ "fi",
+ "fl",
+ "ffi",
+ "ffl",
+ "parenleftinferior",
+ NULL,
+ "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",
+ "colonmonetary",
+ "onefitted",
+ "rupiah",
+ "Tildesmall",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "exclamdownsmall",
+ "centoldstyle",
+ "Lslashsmall",
+ NULL,
+ NULL,
+ "Scaronsmall",
+ "Zcaronsmall",
+ "Dieresissmall",
+ "Brevesmall",
+ "Caronsmall",
+ NULL,
+ "Dotaccentsmall",
+ NULL,
+ NULL,
+ "Macronsmall",
+ NULL,
+ NULL,
+ "figuredash",
+ "hypheninferior",
+ NULL,
+ NULL,
+ "Ogoneksmall",
+ "Ringsmall",
+ "Cedillasmall",
+ NULL,
+ NULL,
+ NULL,
+ "onequarter",
+ "onehalf",
+ "threequarters",
+ "questiondownsmall",
+ "oneeighth",
+ "threeeighths",
+ "fiveeighths",
+ "seveneighths",
+ "onethird",
+ "twothirds",
+ NULL,
+ NULL,
+ "zerosuperior",
+ "onesuperior",
+ "twosuperior",
+ "threesuperior",
+ "foursuperior",
+ "fivesuperior",
+ "sixsuperior",
+ "sevensuperior",
+ "eightsuperior",
+ "ninesuperior",
+ "zeroinferior",
+ "oneinferior",
+ "twoinferior",
+ "threeinferior",
+ "fourinferior",
+ "fiveinferior",
+ "sixinferior",
+ "seveninferior",
+ "eightinferior",
+ "nineinferior",
+ "centinferior",
+ "dollarinferior",
+ "periodinferior",
+ "commainferior",
+ "Agravesmall",
+ "Aacutesmall",
+ "Acircumflexsmall",
+ "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"
+};
+static FontEncoding type1ExpertEncoding(type1ExpertEncodingNames,
+ type1ExpertEncodingSize);
+
+#endif
diff --git a/pdftops/Stream-CCITT.h b/pdftops/Stream-CCITT.h
new file mode 100644
index 000000000..1af874225
--- /dev/null
+++ b/pdftops/Stream-CCITT.h
@@ -0,0 +1,459 @@
+//========================================================================
+//
+// Stream-CCITT.h
+//
+// Tables for CCITT Fax decoding.
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+struct CCITTCode {
+ short bits;
+ short n;
+};
+
+#define ccittEOL -2
+
+//------------------------------------------------------------------------
+// 2D codes
+//------------------------------------------------------------------------
+
+#define twoDimPass 0
+#define twoDimHoriz 1
+#define twoDimVert0 2
+#define twoDimVertR1 3
+#define twoDimVertL1 4
+#define twoDimVertR2 5
+#define twoDimVertL2 6
+#define twoDimVertR3 7
+#define twoDimVertL3 8
+
+// 1-7 bit codes
+static CCITTCode twoDimTab1[128] = {
+ {-1, -1}, {-1, -1}, // 000000x
+ {7, twoDimVertL3}, // 0000010
+ {7, twoDimVertR3}, // 0000011
+ {6, twoDimVertL2}, {6, twoDimVertL2}, // 000010x
+ {6, twoDimVertR2}, {6, twoDimVertR2}, // 000011x
+ {4, twoDimPass}, {4, twoDimPass}, // 0001xxx
+ {4, twoDimPass}, {4, twoDimPass},
+ {4, twoDimPass}, {4, twoDimPass},
+ {4, twoDimPass}, {4, twoDimPass},
+ {3, twoDimHoriz}, {3, twoDimHoriz}, // 001xxxx
+ {3, twoDimHoriz}, {3, twoDimHoriz},
+ {3, twoDimHoriz}, {3, twoDimHoriz},
+ {3, twoDimHoriz}, {3, twoDimHoriz},
+ {3, twoDimHoriz}, {3, twoDimHoriz},
+ {3, twoDimHoriz}, {3, twoDimHoriz},
+ {3, twoDimHoriz}, {3, twoDimHoriz},
+ {3, twoDimHoriz}, {3, twoDimHoriz},
+ {3, twoDimVertL1}, {3, twoDimVertL1}, // 010xxxx
+ {3, twoDimVertL1}, {3, twoDimVertL1},
+ {3, twoDimVertL1}, {3, twoDimVertL1},
+ {3, twoDimVertL1}, {3, twoDimVertL1},
+ {3, twoDimVertL1}, {3, twoDimVertL1},
+ {3, twoDimVertL1}, {3, twoDimVertL1},
+ {3, twoDimVertL1}, {3, twoDimVertL1},
+ {3, twoDimVertL1}, {3, twoDimVertL1},
+ {3, twoDimVertR1}, {3, twoDimVertR1}, // 011xxxx
+ {3, twoDimVertR1}, {3, twoDimVertR1},
+ {3, twoDimVertR1}, {3, twoDimVertR1},
+ {3, twoDimVertR1}, {3, twoDimVertR1},
+ {3, twoDimVertR1}, {3, twoDimVertR1},
+ {3, twoDimVertR1}, {3, twoDimVertR1},
+ {3, twoDimVertR1}, {3, twoDimVertR1},
+ {3, twoDimVertR1}, {3, twoDimVertR1},
+ {1, twoDimVert0}, {1, twoDimVert0}, // 1xxxxxx
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0}
+};
+
+//------------------------------------------------------------------------
+// white run lengths
+//------------------------------------------------------------------------
+
+// 11-12 bit codes (upper 7 bits are 0)
+static CCITTCode whiteTab1[32] = {
+ {-1, -1}, // 00000
+ {12, ccittEOL}, // 00001
+ {-1, -1}, {-1, -1}, // 0001x
+ {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 001xx
+ {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 010xx
+ {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 011xx
+ {11, 1792}, {11, 1792}, // 1000x
+ {12, 1984}, // 10010
+ {12, 2048}, // 10011
+ {12, 2112}, // 10100
+ {12, 2176}, // 10101
+ {12, 2240}, // 10110
+ {12, 2304}, // 10111
+ {11, 1856}, {11, 1856}, // 1100x
+ {11, 1920}, {11, 1920}, // 1101x
+ {12, 2368}, // 11100
+ {12, 2432}, // 11101
+ {12, 2496}, // 11110
+ {12, 2560} // 11111
+};
+
+// 1-9 bit codes
+static CCITTCode whiteTab2[512] = {
+ {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 0000000xx
+ {8, 29}, {8, 29}, // 00000010x
+ {8, 30}, {8, 30}, // 00000011x
+ {8, 45}, {8, 45}, // 00000100x
+ {8, 46}, {8, 46}, // 00000101x
+ {7, 22}, {7, 22}, {7, 22}, {7, 22}, // 0000011xx
+ {7, 23}, {7, 23}, {7, 23}, {7, 23}, // 0000100xx
+ {8, 47}, {8, 47}, // 00001010x
+ {8, 48}, {8, 48}, // 00001011x
+ {6, 13}, {6, 13}, {6, 13}, {6, 13}, // 000011xxx
+ {6, 13}, {6, 13}, {6, 13}, {6, 13},
+ {7, 20}, {7, 20}, {7, 20}, {7, 20}, // 0001000xx
+ {8, 33}, {8, 33}, // 00010010x
+ {8, 34}, {8, 34}, // 00010011x
+ {8, 35}, {8, 35}, // 00010100x
+ {8, 36}, {8, 36}, // 00010101x
+ {8, 37}, {8, 37}, // 00010110x
+ {8, 38}, {8, 38}, // 00010111x
+ {7, 19}, {7, 19}, {7, 19}, {7, 19}, // 0001100xx
+ {8, 31}, {8, 31}, // 00011010x
+ {8, 32}, {8, 32}, // 00011011x
+ {6, 1}, {6, 1}, {6, 1}, {6, 1}, // 000111xxx
+ {6, 1}, {6, 1}, {6, 1}, {6, 1},
+ {6, 12}, {6, 12}, {6, 12}, {6, 12}, // 001000xxx
+ {6, 12}, {6, 12}, {6, 12}, {6, 12},
+ {8, 53}, {8, 53}, // 00100100x
+ {8, 54}, {8, 54}, // 00100101x
+ {7, 26}, {7, 26}, {7, 26}, {7, 26}, // 0010011xx
+ {8, 39}, {8, 39}, // 00101000x
+ {8, 40}, {8, 40}, // 00101001x
+ {8, 41}, {8, 41}, // 00101010x
+ {8, 42}, {8, 42}, // 00101011x
+ {8, 43}, {8, 43}, // 00101100x
+ {8, 44}, {8, 44}, // 00101101x
+ {7, 21}, {7, 21}, {7, 21}, {7, 21}, // 0010111xx
+ {7, 28}, {7, 28}, {7, 28}, {7, 28}, // 0011000xx
+ {8, 61}, {8, 61}, // 00110010x
+ {8, 62}, {8, 62}, // 00110011x
+ {8, 63}, {8, 63}, // 00110100x
+ {8, 0}, {8, 0}, // 00110101x
+ {8, 320}, {8, 320}, // 00110110x
+ {8, 384}, {8, 384}, // 00110111x
+ {5, 10}, {5, 10}, {5, 10}, {5, 10}, // 00111xxxx
+ {5, 10}, {5, 10}, {5, 10}, {5, 10},
+ {5, 10}, {5, 10}, {5, 10}, {5, 10},
+ {5, 10}, {5, 10}, {5, 10}, {5, 10},
+ {5, 11}, {5, 11}, {5, 11}, {5, 11}, // 01000xxxx
+ {5, 11}, {5, 11}, {5, 11}, {5, 11},
+ {5, 11}, {5, 11}, {5, 11}, {5, 11},
+ {5, 11}, {5, 11}, {5, 11}, {5, 11},
+ {7, 27}, {7, 27}, {7, 27}, {7, 27}, // 0100100xx
+ {8, 59}, {8, 59}, // 01001010x
+ {8, 60}, {8, 60}, // 01001011x
+ {9, 1472}, // 010011000
+ {9, 1536}, // 010011001
+ {9, 1600}, // 010011010
+ {9, 1728}, // 010011011
+ {7, 18}, {7, 18}, {7, 18}, {7, 18}, // 0100111xx
+ {7, 24}, {7, 24}, {7, 24}, {7, 24}, // 0101000xx
+ {8, 49}, {8, 49}, // 01010010x
+ {8, 50}, {8, 50}, // 01010011x
+ {8, 51}, {8, 51}, // 01010100x
+ {8, 52}, {8, 52}, // 01010101x
+ {7, 25}, {7, 25}, {7, 25}, {7, 25}, // 0101011xx
+ {8, 55}, {8, 55}, // 01011000x
+ {8, 56}, {8, 56}, // 01011001x
+ {8, 57}, {8, 57}, // 01011010x
+ {8, 58}, {8, 58}, // 01011011x
+ {6, 192}, {6, 192}, {6, 192}, {6, 192}, // 010111xxx
+ {6, 192}, {6, 192}, {6, 192}, {6, 192},
+ {6, 1664}, {6, 1664}, {6, 1664}, {6, 1664}, // 011000xxx
+ {6, 1664}, {6, 1664}, {6, 1664}, {6, 1664},
+ {8, 448}, {8, 448}, // 01100100x
+ {8, 512}, {8, 512}, // 01100101x
+ {9, 704}, // 011001100
+ {9, 768}, // 011001101
+ {8, 640}, {8, 640}, // 01100111x
+ {8, 576}, {8, 576}, // 01101000x
+ {9, 832}, // 011010010
+ {9, 896}, // 011010011
+ {9, 960}, // 011010100
+ {9, 1024}, // 011010101
+ {9, 1088}, // 011010110
+ {9, 1152}, // 011010111
+ {9, 1216}, // 011011000
+ {9, 1280}, // 011011001
+ {9, 1344}, // 011011010
+ {9, 1408}, // 011011011
+ {7, 256}, {7, 256}, {7, 256}, {7, 256}, // 0110111xx
+ {4, 2}, {4, 2}, {4, 2}, {4, 2}, // 0111xxxxx
+ {4, 2}, {4, 2}, {4, 2}, {4, 2},
+ {4, 2}, {4, 2}, {4, 2}, {4, 2},
+ {4, 2}, {4, 2}, {4, 2}, {4, 2},
+ {4, 2}, {4, 2}, {4, 2}, {4, 2},
+ {4, 2}, {4, 2}, {4, 2}, {4, 2},
+ {4, 2}, {4, 2}, {4, 2}, {4, 2},
+ {4, 2}, {4, 2}, {4, 2}, {4, 2},
+ {4, 3}, {4, 3}, {4, 3}, {4, 3}, // 1000xxxxx
+ {4, 3}, {4, 3}, {4, 3}, {4, 3},
+ {4, 3}, {4, 3}, {4, 3}, {4, 3},
+ {4, 3}, {4, 3}, {4, 3}, {4, 3},
+ {4, 3}, {4, 3}, {4, 3}, {4, 3},
+ {4, 3}, {4, 3}, {4, 3}, {4, 3},
+ {4, 3}, {4, 3}, {4, 3}, {4, 3},
+ {4, 3}, {4, 3}, {4, 3}, {4, 3},
+ {5, 128}, {5, 128}, {5, 128}, {5, 128}, // 10010xxxx
+ {5, 128}, {5, 128}, {5, 128}, {5, 128},
+ {5, 128}, {5, 128}, {5, 128}, {5, 128},
+ {5, 128}, {5, 128}, {5, 128}, {5, 128},
+ {5, 8}, {5, 8}, {5, 8}, {5, 8}, // 10011xxxx
+ {5, 8}, {5, 8}, {5, 8}, {5, 8},
+ {5, 8}, {5, 8}, {5, 8}, {5, 8},
+ {5, 8}, {5, 8}, {5, 8}, {5, 8},
+ {5, 9}, {5, 9}, {5, 9}, {5, 9}, // 10100xxxx
+ {5, 9}, {5, 9}, {5, 9}, {5, 9},
+ {5, 9}, {5, 9}, {5, 9}, {5, 9},
+ {5, 9}, {5, 9}, {5, 9}, {5, 9},
+ {6, 16}, {6, 16}, {6, 16}, {6, 16}, // 101010xxx
+ {6, 16}, {6, 16}, {6, 16}, {6, 16},
+ {6, 17}, {6, 17}, {6, 17}, {6, 17}, // 101011xxx
+ {6, 17}, {6, 17}, {6, 17}, {6, 17},
+ {4, 4}, {4, 4}, {4, 4}, {4, 4}, // 1011xxxxx
+ {4, 4}, {4, 4}, {4, 4}, {4, 4},
+ {4, 4}, {4, 4}, {4, 4}, {4, 4},
+ {4, 4}, {4, 4}, {4, 4}, {4, 4},
+ {4, 4}, {4, 4}, {4, 4}, {4, 4},
+ {4, 4}, {4, 4}, {4, 4}, {4, 4},
+ {4, 4}, {4, 4}, {4, 4}, {4, 4},
+ {4, 4}, {4, 4}, {4, 4}, {4, 4},
+ {4, 5}, {4, 5}, {4, 5}, {4, 5}, // 1100xxxxx
+ {4, 5}, {4, 5}, {4, 5}, {4, 5},
+ {4, 5}, {4, 5}, {4, 5}, {4, 5},
+ {4, 5}, {4, 5}, {4, 5}, {4, 5},
+ {4, 5}, {4, 5}, {4, 5}, {4, 5},
+ {4, 5}, {4, 5}, {4, 5}, {4, 5},
+ {4, 5}, {4, 5}, {4, 5}, {4, 5},
+ {4, 5}, {4, 5}, {4, 5}, {4, 5},
+ {6, 14}, {6, 14}, {6, 14}, {6, 14}, // 110100xxx
+ {6, 14}, {6, 14}, {6, 14}, {6, 14},
+ {6, 15}, {6, 15}, {6, 15}, {6, 15}, // 110101xxx
+ {6, 15}, {6, 15}, {6, 15}, {6, 15},
+ {5, 64}, {5, 64}, {5, 64}, {5, 64}, // 11011xxxx
+ {5, 64}, {5, 64}, {5, 64}, {5, 64},
+ {5, 64}, {5, 64}, {5, 64}, {5, 64},
+ {5, 64}, {5, 64}, {5, 64}, {5, 64},
+ {4, 6}, {4, 6}, {4, 6}, {4, 6}, // 1110xxxxx
+ {4, 6}, {4, 6}, {4, 6}, {4, 6},
+ {4, 6}, {4, 6}, {4, 6}, {4, 6},
+ {4, 6}, {4, 6}, {4, 6}, {4, 6},
+ {4, 6}, {4, 6}, {4, 6}, {4, 6},
+ {4, 6}, {4, 6}, {4, 6}, {4, 6},
+ {4, 6}, {4, 6}, {4, 6}, {4, 6},
+ {4, 6}, {4, 6}, {4, 6}, {4, 6},
+ {4, 7}, {4, 7}, {4, 7}, {4, 7}, // 1111xxxxx
+ {4, 7}, {4, 7}, {4, 7}, {4, 7},
+ {4, 7}, {4, 7}, {4, 7}, {4, 7},
+ {4, 7}, {4, 7}, {4, 7}, {4, 7},
+ {4, 7}, {4, 7}, {4, 7}, {4, 7},
+ {4, 7}, {4, 7}, {4, 7}, {4, 7},
+ {4, 7}, {4, 7}, {4, 7}, {4, 7},
+ {4, 7}, {4, 7}, {4, 7}, {4, 7}
+};
+
+//------------------------------------------------------------------------
+// black run lengths
+//------------------------------------------------------------------------
+
+// 10-13 bit codes (upper 6 bits are 0)
+static CCITTCode blackTab1[128] = {
+ {-1, -1}, {-1, -1}, // 000000000000x
+ {12, ccittEOL}, {12, ccittEOL}, // 000000000001x
+ {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000001xx
+ {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000010xx
+ {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000011xx
+ {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000100xx
+ {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000101xx
+ {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000110xx
+ {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000111xx
+ {11, 1792}, {11, 1792}, {11, 1792}, {11, 1792}, // 00000001000xx
+ {12, 1984}, {12, 1984}, // 000000010010x
+ {12, 2048}, {12, 2048}, // 000000010011x
+ {12, 2112}, {12, 2112}, // 000000010100x
+ {12, 2176}, {12, 2176}, // 000000010101x
+ {12, 2240}, {12, 2240}, // 000000010110x
+ {12, 2304}, {12, 2304}, // 000000010111x
+ {11, 1856}, {11, 1856}, {11, 1856}, {11, 1856}, // 00000001100xx
+ {11, 1920}, {11, 1920}, {11, 1920}, {11, 1920}, // 00000001101xx
+ {12, 2368}, {12, 2368}, // 000000011100x
+ {12, 2432}, {12, 2432}, // 000000011101x
+ {12, 2496}, {12, 2496}, // 000000011110x
+ {12, 2560}, {12, 2560}, // 000000011111x
+ {10, 18}, {10, 18}, {10, 18}, {10, 18}, // 0000001000xxx
+ {10, 18}, {10, 18}, {10, 18}, {10, 18},
+ {12, 52}, {12, 52}, // 000000100100x
+ {13, 640}, // 0000001001010
+ {13, 704}, // 0000001001011
+ {13, 768}, // 0000001001100
+ {13, 832}, // 0000001001101
+ {12, 55}, {12, 55}, // 000000100111x
+ {12, 56}, {12, 56}, // 000000101000x
+ {13, 1280}, // 0000001010010
+ {13, 1344}, // 0000001010011
+ {13, 1408}, // 0000001010100
+ {13, 1472}, // 0000001010101
+ {12, 59}, {12, 59}, // 000000101011x
+ {12, 60}, {12, 60}, // 000000101100x
+ {13, 1536}, // 0000001011010
+ {13, 1600}, // 0000001011011
+ {11, 24}, {11, 24}, {11, 24}, {11, 24}, // 00000010111xx
+ {11, 25}, {11, 25}, {11, 25}, {11, 25}, // 00000011000xx
+ {13, 1664}, // 0000001100100
+ {13, 1728}, // 0000001100101
+ {12, 320}, {12, 320}, // 000000110011x
+ {12, 384}, {12, 384}, // 000000110100x
+ {12, 448}, {12, 448}, // 000000110101x
+ {13, 512}, // 0000001101100
+ {13, 576}, // 0000001101101
+ {12, 53}, {12, 53}, // 000000110111x
+ {12, 54}, {12, 54}, // 000000111000x
+ {13, 896}, // 0000001110010
+ {13, 960}, // 0000001110011
+ {13, 1024}, // 0000001110100
+ {13, 1088}, // 0000001110101
+ {13, 1152}, // 0000001110110
+ {13, 1216}, // 0000001110111
+ {10, 64}, {10, 64}, {10, 64}, {10, 64}, // 0000001111xxx
+ {10, 64}, {10, 64}, {10, 64}, {10, 64}
+};
+
+// 7-12 bit codes (upper 4 bits are 0)
+static CCITTCode blackTab2[192] = {
+ {8, 13}, {8, 13}, {8, 13}, {8, 13}, // 00000100xxxx
+ {8, 13}, {8, 13}, {8, 13}, {8, 13},
+ {8, 13}, {8, 13}, {8, 13}, {8, 13},
+ {8, 13}, {8, 13}, {8, 13}, {8, 13},
+ {11, 23}, {11, 23}, // 00000101000x
+ {12, 50}, // 000001010010
+ {12, 51}, // 000001010011
+ {12, 44}, // 000001010100
+ {12, 45}, // 000001010101
+ {12, 46}, // 000001010110
+ {12, 47}, // 000001010111
+ {12, 57}, // 000001011000
+ {12, 58}, // 000001011001
+ {12, 61}, // 000001011010
+ {12, 256}, // 000001011011
+ {10, 16}, {10, 16}, {10, 16}, {10, 16}, // 0000010111xx
+ {10, 17}, {10, 17}, {10, 17}, {10, 17}, // 0000011000xx
+ {12, 48}, // 000001100100
+ {12, 49}, // 000001100101
+ {12, 62}, // 000001100110
+ {12, 63}, // 000001100111
+ {12, 30}, // 000001101000
+ {12, 31}, // 000001101001
+ {12, 32}, // 000001101010
+ {12, 33}, // 000001101011
+ {12, 40}, // 000001101100
+ {12, 41}, // 000001101101
+ {11, 22}, {11, 22}, // 00000110111x
+ {8, 14}, {8, 14}, {8, 14}, {8, 14}, // 00000111xxxx
+ {8, 14}, {8, 14}, {8, 14}, {8, 14},
+ {8, 14}, {8, 14}, {8, 14}, {8, 14},
+ {8, 14}, {8, 14}, {8, 14}, {8, 14},
+ {7, 10}, {7, 10}, {7, 10}, {7, 10}, // 0000100xxxxx
+ {7, 10}, {7, 10}, {7, 10}, {7, 10},
+ {7, 10}, {7, 10}, {7, 10}, {7, 10},
+ {7, 10}, {7, 10}, {7, 10}, {7, 10},
+ {7, 10}, {7, 10}, {7, 10}, {7, 10},
+ {7, 10}, {7, 10}, {7, 10}, {7, 10},
+ {7, 10}, {7, 10}, {7, 10}, {7, 10},
+ {7, 10}, {7, 10}, {7, 10}, {7, 10},
+ {7, 11}, {7, 11}, {7, 11}, {7, 11}, // 0000101xxxxx
+ {7, 11}, {7, 11}, {7, 11}, {7, 11},
+ {7, 11}, {7, 11}, {7, 11}, {7, 11},
+ {7, 11}, {7, 11}, {7, 11}, {7, 11},
+ {7, 11}, {7, 11}, {7, 11}, {7, 11},
+ {7, 11}, {7, 11}, {7, 11}, {7, 11},
+ {7, 11}, {7, 11}, {7, 11}, {7, 11},
+ {7, 11}, {7, 11}, {7, 11}, {7, 11},
+ {9, 15}, {9, 15}, {9, 15}, {9, 15}, // 000011000xxx
+ {9, 15}, {9, 15}, {9, 15}, {9, 15},
+ {12, 128}, // 000011001000
+ {12, 192}, // 000011001001
+ {12, 26}, // 000011001010
+ {12, 27}, // 000011001011
+ {12, 28}, // 000011001100
+ {12, 29}, // 000011001101
+ {11, 19}, {11, 19}, // 00001100111x
+ {11, 20}, {11, 20}, // 00001101000x
+ {12, 34}, // 000011010010
+ {12, 35}, // 000011010011
+ {12, 36}, // 000011010100
+ {12, 37}, // 000011010101
+ {12, 38}, // 000011010110
+ {12, 39}, // 000011010111
+ {11, 21}, {11, 21}, // 00001101100x
+ {12, 42}, // 000011011010
+ {12, 43}, // 000011011011
+ {10, 0}, {10, 0}, {10, 0}, {10, 0}, // 0000110111xx
+ {7, 12}, {7, 12}, {7, 12}, {7, 12}, // 0000111xxxxx
+ {7, 12}, {7, 12}, {7, 12}, {7, 12},
+ {7, 12}, {7, 12}, {7, 12}, {7, 12},
+ {7, 12}, {7, 12}, {7, 12}, {7, 12},
+ {7, 12}, {7, 12}, {7, 12}, {7, 12},
+ {7, 12}, {7, 12}, {7, 12}, {7, 12},
+ {7, 12}, {7, 12}, {7, 12}, {7, 12},
+ {7, 12}, {7, 12}, {7, 12}, {7, 12}
+};
+
+// 2-6 bit codes
+static CCITTCode blackTab3[64] = {
+ {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 0000xx
+ {6, 9}, // 000100
+ {6, 8}, // 000101
+ {5, 7}, {5, 7}, // 00011x
+ {4, 6}, {4, 6}, {4, 6}, {4, 6}, // 0010xx
+ {4, 5}, {4, 5}, {4, 5}, {4, 5}, // 0011xx
+ {3, 1}, {3, 1}, {3, 1}, {3, 1}, // 010xxx
+ {3, 1}, {3, 1}, {3, 1}, {3, 1},
+ {3, 4}, {3, 4}, {3, 4}, {3, 4}, // 011xxx
+ {3, 4}, {3, 4}, {3, 4}, {3, 4},
+ {2, 3}, {2, 3}, {2, 3}, {2, 3}, // 10xxxx
+ {2, 3}, {2, 3}, {2, 3}, {2, 3},
+ {2, 3}, {2, 3}, {2, 3}, {2, 3},
+ {2, 3}, {2, 3}, {2, 3}, {2, 3},
+ {2, 2}, {2, 2}, {2, 2}, {2, 2}, // 11xxxx
+ {2, 2}, {2, 2}, {2, 2}, {2, 2},
+ {2, 2}, {2, 2}, {2, 2}, {2, 2},
+ {2, 2}, {2, 2}, {2, 2}, {2, 2}
+};
diff --git a/pdftops/Stream.cxx b/pdftops/Stream.cxx
new file mode 100644
index 000000000..a8a88e623
--- /dev/null
+++ b/pdftops/Stream.cxx
@@ -0,0 +1,3466 @@
+//========================================================================
+//
+// Stream.cc
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#ifndef WIN32
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <ctype.h>
+#include "gmem.h"
+#include "gfile.h"
+#include "config.h"
+#include "Error.h"
+#include "Object.h"
+#ifndef NO_DECRYPTION
+#include "Decrypt.h"
+#endif
+#include "Stream.h"
+#include "Stream-CCITT.h"
+
+#ifdef __DJGPP__
+static GBool setDJSYSFLAGS = gFalse;
+#endif
+
+#ifdef VMS
+#if (__VMS_VER < 70000000)
+extern "C" int unlink(char *filename);
+#endif
+#ifdef __GNUC__
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+#endif
+#endif
+
+#ifdef MACOS
+#include "StuffItEngineLib.h"
+#endif
+
+//------------------------------------------------------------------------
+// Stream (base class)
+//------------------------------------------------------------------------
+
+Stream::Stream() {
+ ref = 1;
+}
+
+Stream::~Stream() {
+}
+
+void Stream::close() {
+}
+
+int Stream::getRawChar() {
+ error(-1, "Internal: called getRawChar() on non-predictor stream");
+ return EOF;
+}
+
+char *Stream::getLine(char *buf, int size) {
+ int i;
+ int c;
+
+ if (lookChar() == EOF)
+ return NULL;
+ for (i = 0; i < size - 1; ++i) {
+ c = getChar();
+ if (c == EOF || c == '\n')
+ break;
+ if (c == '\r') {
+ if ((c = lookChar()) == '\n')
+ getChar();
+ break;
+ }
+ buf[i] = c;
+ }
+ buf[i] = '\0';
+ return buf;
+}
+
+GString *Stream::getPSFilter(char *indent) {
+ return new GString();
+}
+
+Stream *Stream::addFilters(Object *dict) {
+ Object obj, obj2;
+ Object params, params2;
+ Stream *str;
+ int i;
+
+ str = this;
+ dict->dictLookup("Filter", &obj);
+ if (obj.isNull()) {
+ obj.free();
+ dict->dictLookup("F", &obj);
+ }
+ dict->dictLookup("DecodeParms", &params);
+ if (params.isNull()) {
+ params.free();
+ dict->dictLookup("DP", &params);
+ }
+ if (obj.isName()) {
+ str = makeFilter(obj.getName(), str, &params);
+ } else if (obj.isArray()) {
+ for (i = 0; i < obj.arrayGetLength(); ++i) {
+ obj.arrayGet(i, &obj2);
+ if (params.isArray())
+ params.arrayGet(i, &params2);
+ else
+ params2.initNull();
+ if (obj2.isName()) {
+ str = makeFilter(obj2.getName(), str, &params2);
+ } else {
+ error(getPos(), "Bad filter name");
+ str = new EOFStream(str);
+ }
+ obj2.free();
+ params2.free();
+ }
+ } else if (!obj.isNull()) {
+ error(getPos(), "Bad 'Filter' attribute in stream");
+ }
+ obj.free();
+ params.free();
+
+ return str;
+}
+
+Stream *Stream::makeFilter(char *name, Stream *str, Object *params) {
+ int pred; // parameters
+ int colors;
+ int bits;
+ int early;
+ int encoding;
+ GBool endOfLine, byteAlign, endOfBlock, black;
+ int columns, rows;
+ Object obj;
+
+ if (!strcmp(name, "ASCIIHexDecode") || !strcmp(name, "AHx")) {
+ str = new ASCIIHexStream(str);
+ } else if (!strcmp(name, "ASCII85Decode") || !strcmp(name, "A85")) {
+ str = new ASCII85Stream(str);
+ } else if (!strcmp(name, "LZWDecode") || !strcmp(name, "LZW")) {
+ pred = 1;
+ columns = 1;
+ colors = 1;
+ bits = 8;
+ early = 1;
+ if (params->isDict()) {
+ params->dictLookup("Predictor", &obj);
+ if (obj.isInt())
+ pred = obj.getInt();
+ obj.free();
+ params->dictLookup("Columns", &obj);
+ if (obj.isInt())
+ columns = obj.getInt();
+ obj.free();
+ params->dictLookup("Colors", &obj);
+ if (obj.isInt())
+ colors = obj.getInt();
+ obj.free();
+ params->dictLookup("BitsPerComponent", &obj);
+ if (obj.isInt())
+ bits = obj.getInt();
+ obj.free();
+ params->dictLookup("EarlyChange", &obj);
+ if (obj.isInt())
+ early = obj.getInt();
+ obj.free();
+ }
+ str = new LZWStream(str, pred, columns, colors, bits, early);
+ } else if (!strcmp(name, "RunLengthDecode") || !strcmp(name, "RL")) {
+ str = new RunLengthStream(str);
+ } else if (!strcmp(name, "CCITTFaxDecode") || !strcmp(name, "CCF")) {
+ encoding = 0;
+ endOfLine = gFalse;
+ byteAlign = gFalse;
+ columns = 1728;
+ rows = 0;
+ endOfBlock = gTrue;
+ black = gFalse;
+ if (params->isDict()) {
+ params->dictLookup("K", &obj);
+ if (obj.isInt()) {
+ encoding = obj.getInt();
+ }
+ obj.free();
+ params->dictLookup("EndOfLine", &obj);
+ if (obj.isBool()) {
+ endOfLine = obj.getBool();
+ }
+ obj.free();
+ params->dictLookup("EncodedByteAlign", &obj);
+ if (obj.isBool()) {
+ byteAlign = obj.getBool();
+ }
+ obj.free();
+ params->dictLookup("Columns", &obj);
+ if (obj.isInt()) {
+ columns = obj.getInt();
+ }
+ obj.free();
+ params->dictLookup("Rows", &obj);
+ if (obj.isInt()) {
+ rows = obj.getInt();
+ }
+ obj.free();
+ params->dictLookup("EndOfBlock", &obj);
+ if (obj.isBool()) {
+ endOfBlock = obj.getBool();
+ }
+ obj.free();
+ params->dictLookup("BlackIs1", &obj);
+ if (obj.isBool()) {
+ black = obj.getBool();
+ }
+ obj.free();
+ }
+ str = new CCITTFaxStream(str, encoding, endOfLine, byteAlign,
+ columns, rows, endOfBlock, black);
+ } else if (!strcmp(name, "DCTDecode") || !strcmp(name, "DCT")) {
+ str = new DCTStream(str);
+ } else if (!strcmp(name, "FlateDecode") || !strcmp(name, "Fl")) {
+ pred = 1;
+ columns = 1;
+ colors = 1;
+ bits = 8;
+ if (params->isDict()) {
+ params->dictLookup("Predictor", &obj);
+ if (obj.isInt())
+ pred = obj.getInt();
+ obj.free();
+ params->dictLookup("Columns", &obj);
+ if (obj.isInt())
+ columns = obj.getInt();
+ obj.free();
+ params->dictLookup("Colors", &obj);
+ if (obj.isInt())
+ colors = obj.getInt();
+ obj.free();
+ params->dictLookup("BitsPerComponent", &obj);
+ if (obj.isInt())
+ bits = obj.getInt();
+ obj.free();
+ }
+ str = new FlateStream(str, pred, columns, colors, bits);
+ } else {
+ error(getPos(), "Unknown filter '%s'", name);
+ str = new EOFStream(str);
+ }
+ return str;
+}
+
+//------------------------------------------------------------------------
+// BaseStream
+//------------------------------------------------------------------------
+
+BaseStream::BaseStream(Object *dictA) {
+ dict = *dictA;
+#ifndef NO_DECRYPTION
+ decrypt = NULL;
+#endif
+}
+
+BaseStream::~BaseStream() {
+ dict.free();
+#ifndef NO_DECRYPTION
+ if (decrypt)
+ delete decrypt;
+#endif
+}
+
+#ifndef NO_DECRYPTION
+void BaseStream::doDecryption(Guchar *fileKey, int keyLength,
+ int objNum, int objGen) {
+ decrypt = new Decrypt(fileKey, keyLength, objNum, objGen);
+}
+#endif
+
+//------------------------------------------------------------------------
+// FilterStream
+//------------------------------------------------------------------------
+
+FilterStream::FilterStream(Stream *strA) {
+ str = strA;
+}
+
+FilterStream::~FilterStream() {
+}
+
+void FilterStream::close() {
+ str->close();
+}
+
+void FilterStream::setPos(int pos) {
+ error(-1, "Internal: called setPos() on FilterStream");
+}
+
+//------------------------------------------------------------------------
+// ImageStream
+//------------------------------------------------------------------------
+
+ImageStream::ImageStream(Stream *strA, int widthA, int nCompsA, int nBitsA) {
+ int imgLineSize;
+
+ str = strA;
+ width = widthA;
+ nComps = nCompsA;
+ nBits = nBitsA;
+
+ nVals = width * nComps;
+ if (nBits == 1) {
+ imgLineSize = (nVals + 7) & ~7;
+ } else {
+ imgLineSize = nVals;
+ }
+ imgLine = (Guchar *)gmalloc(imgLineSize * sizeof(Guchar));
+ imgIdx = nVals;
+}
+
+ImageStream::~ImageStream() {
+ gfree(imgLine);
+}
+
+void ImageStream::reset() {
+ str->reset();
+}
+
+GBool ImageStream::getPixel(Guchar *pix) {
+ Gulong buf, bitMask;
+ int bits;
+ int c;
+ int i;
+
+ if (imgIdx >= nVals) {
+
+ // read one line of image pixels
+ if (nBits == 1) {
+ for (i = 0; i < nVals; i += 8) {
+ c = str->getChar();
+ imgLine[i+0] = (Guchar)((c >> 7) & 1);
+ imgLine[i+1] = (Guchar)((c >> 6) & 1);
+ imgLine[i+2] = (Guchar)((c >> 5) & 1);
+ imgLine[i+3] = (Guchar)((c >> 4) & 1);
+ imgLine[i+4] = (Guchar)((c >> 3) & 1);
+ imgLine[i+5] = (Guchar)((c >> 2) & 1);
+ imgLine[i+6] = (Guchar)((c >> 1) & 1);
+ imgLine[i+7] = (Guchar)(c & 1);
+ }
+ } else if (nBits == 8) {
+ for (i = 0; i < nVals; ++i) {
+ imgLine[i] = str->getChar();
+ }
+ } else {
+ bitMask = (1 << nBits) - 1;
+ buf = 0;
+ bits = 0;
+ for (i = 0; i < nVals; ++i) {
+ if (bits < nBits) {
+ buf = (buf << 8) | (str->getChar() & 0xff);
+ bits += 8;
+ }
+ imgLine[i] = (Guchar)((buf >> (bits - nBits)) & bitMask);
+ bits -= nBits;
+ }
+ }
+
+ // reset to start of line
+ imgIdx = 0;
+ }
+
+ for (i = 0; i < nComps; ++i)
+ pix[i] = imgLine[imgIdx++];
+ return gTrue;
+}
+
+void ImageStream::skipLine() {
+ int n, i;
+
+ n = (nVals * nBits + 7) >> 3;
+ for (i = 0; i < n; ++i) {
+ str->getChar();
+ }
+}
+
+//------------------------------------------------------------------------
+// StreamPredictor
+//------------------------------------------------------------------------
+
+StreamPredictor::StreamPredictor(Stream *strA, int predictorA,
+ int widthA, int nCompsA, int nBitsA) {
+ str = strA;
+ predictor = predictorA;
+ width = widthA;
+ nComps = nCompsA;
+ nBits = nBitsA;
+
+ nVals = width * nComps;
+ pixBytes = (nComps * nBits + 7) >> 3;
+ rowBytes = ((nVals * nBits + 7) >> 3) + pixBytes;
+ predLine = (Guchar *)gmalloc(rowBytes);
+ memset(predLine, 0, rowBytes);
+ predIdx = rowBytes;
+}
+
+StreamPredictor::~StreamPredictor() {
+ gfree(predLine);
+}
+
+int StreamPredictor::lookChar() {
+ if (predIdx >= rowBytes) {
+ if (!getNextLine()) {
+ return EOF;
+ }
+ }
+ return predLine[predIdx];
+}
+
+int StreamPredictor::getChar() {
+ if (predIdx >= rowBytes) {
+ if (!getNextLine()) {
+ return EOF;
+ }
+ }
+ return predLine[predIdx++];
+}
+
+GBool StreamPredictor::getNextLine() {
+ int curPred;
+ Guchar upLeftBuf[4];
+ int left, up, upLeft, p, pa, pb, pc;
+ int c;
+ Gulong inBuf, outBuf, bitMask;
+ int inBits, outBits;
+ int i, j, k;
+
+ // get PNG optimum predictor number
+ if (predictor == 15) {
+ if ((curPred = str->getRawChar()) == EOF) {
+ return gFalse;
+ }
+ curPred += 10;
+ } else {
+ curPred = predictor;
+ }
+
+ // read the raw line, apply PNG (byte) predictor
+ upLeftBuf[0] = upLeftBuf[1] = upLeftBuf[2] = upLeftBuf[3] = 0;
+ for (i = pixBytes; i < rowBytes; ++i) {
+ upLeftBuf[3] = upLeftBuf[2];
+ upLeftBuf[2] = upLeftBuf[1];
+ upLeftBuf[1] = upLeftBuf[0];
+ upLeftBuf[0] = predLine[i];
+ if ((c = str->getRawChar()) == EOF) {
+ break;
+ }
+ switch (curPred) {
+ case 11: // PNG sub
+ predLine[i] = predLine[i - pixBytes] + (Guchar)c;
+ break;
+ case 12: // PNG up
+ predLine[i] = predLine[i] + (Guchar)c;
+ break;
+ case 13: // PNG average
+ predLine[i] = ((predLine[i - pixBytes] + predLine[i]) >> 1) +
+ (Guchar)c;
+ break;
+ case 14: // PNG Paeth
+ left = predLine[i - pixBytes];
+ up = predLine[i];
+ upLeft = upLeftBuf[pixBytes];
+ p = left + up - upLeft;
+ if ((pa = p - left) < 0)
+ pa = -pa;
+ if ((pb = p - up) < 0)
+ pb = -pb;
+ if ((pc = p - upLeft) < 0)
+ pc = -pc;
+ if (pa <= pb && pa <= pc)
+ predLine[i] = pa + (Guchar)c;
+ else if (pb <= pc)
+ predLine[i] = pb + (Guchar)c;
+ else
+ predLine[i] = pc + (Guchar)c;
+ break;
+ case 10: // PNG none
+ default: // no predictor or TIFF predictor
+ predLine[i] = (Guchar)c;
+ break;
+ }
+ }
+
+ // apply TIFF (component) predictor
+ //~ this is completely untested
+ if (predictor == 2) {
+ if (nBits == 1) {
+ inBuf = predLine[pixBytes - 1];
+ for (i = pixBytes; i < rowBytes; i += 8) {
+ // 1-bit add is just xor
+ inBuf = (inBuf << 8) | predLine[i];
+ predLine[i] ^= inBuf >> nComps;
+ }
+ } else if (nBits == 8) {
+ for (i = pixBytes; i < rowBytes; ++i) {
+ predLine[i] += predLine[i - nComps];
+ }
+ } else {
+ upLeftBuf[0] = upLeftBuf[1] = upLeftBuf[2] = upLeftBuf[3] = 0;
+ bitMask = (1 << nBits) - 1;
+ inBuf = outBuf = 0;
+ inBits = outBits = 0;
+ j = k = pixBytes;
+ for (i = 0; i < nVals; ++i) {
+ if (inBits < nBits) {
+ inBuf = (inBuf << 8) | (predLine[j++] & 0xff);
+ inBits += 8;
+ }
+ upLeftBuf[3] = upLeftBuf[2];
+ upLeftBuf[2] = upLeftBuf[1];
+ upLeftBuf[1] = upLeftBuf[0];
+ upLeftBuf[0] = (upLeftBuf[nComps] +
+ (inBuf >> (inBits - nBits))) & bitMask;
+ outBuf = (outBuf << nBits) | upLeftBuf[0];
+ inBits -= nBits;
+ outBits += nBits;
+ if (outBits > 8) {
+ predLine[k++] = (Guchar)(outBuf >> (outBits - 8));
+ }
+ }
+ if (outBits > 0) {
+ predLine[k++] = (Guchar)(outBuf << (8 - outBits));
+ }
+ }
+ }
+
+ // reset to start of line
+ predIdx = pixBytes;
+
+ return gTrue;
+}
+
+//------------------------------------------------------------------------
+// FileStream
+//------------------------------------------------------------------------
+
+FileStream::FileStream(FILE *fA, int startA, int lengthA, Object *dictA):
+ BaseStream(dictA) {
+ f = fA;
+ start = startA;
+ length = lengthA;
+ bufPtr = bufEnd = buf;
+ bufPos = start;
+ savePos = -1;
+}
+
+FileStream::~FileStream() {
+ close();
+}
+
+Stream *FileStream::makeSubStream(int startA, int lengthA, Object *dictA) {
+ return new FileStream(f, startA, lengthA, dictA);
+}
+
+void FileStream::reset() {
+ savePos = (int)ftell(f);
+ fseek(f, start, SEEK_SET);
+ bufPtr = bufEnd = buf;
+ bufPos = start;
+#ifndef NO_DECRYPTION
+ if (decrypt)
+ decrypt->reset();
+#endif
+}
+
+void FileStream::close() {
+ if (savePos >= 0) {
+ fseek(f, savePos, SEEK_SET);
+ savePos = -1;
+ }
+}
+
+GBool FileStream::fillBuf() {
+ int n;
+#ifndef NO_DECRYPTION
+ char *p;
+#endif
+
+ bufPos += bufEnd - buf;
+ bufPtr = bufEnd = buf;
+ if (length >= 0 && bufPos >= start + length) {
+ return gFalse;
+ }
+ if (length >= 0 && bufPos + fileStreamBufSize > start + length) {
+ n = start + length - bufPos;
+ } else {
+ n = fileStreamBufSize;
+ }
+ n = fread(buf, 1, n, f);
+ bufEnd = buf + n;
+ if (bufPtr >= bufEnd) {
+ return gFalse;
+ }
+#ifndef NO_DECRYPTION
+ if (decrypt) {
+ for (p = buf; p < bufEnd; ++p) {
+ *p = (char)decrypt->decryptByte((Guchar)*p);
+ }
+ }
+#endif
+ return gTrue;
+}
+
+void FileStream::setPos(int pos) {
+ long size;
+
+ if (pos >= 0) {
+ fseek(f, pos, SEEK_SET);
+ bufPos = pos;
+ } else {
+ fseek(f, 0, SEEK_END);
+ size = ftell(f);
+ if (pos < -size)
+ pos = (int)(-size);
+#ifdef __CYGWIN32__
+ //~ work around a bug in cygwin's implementation of fseek
+ rewind(f);
+#endif
+ fseek(f, pos, SEEK_END);
+ bufPos = (int)ftell(f);
+ }
+ bufPtr = bufEnd = buf;
+}
+
+void FileStream::moveStart(int delta) {
+ start += delta;
+ bufPtr = bufEnd = buf;
+ bufPos = start;
+}
+
+//------------------------------------------------------------------------
+// EmbedStream
+//------------------------------------------------------------------------
+
+EmbedStream::EmbedStream(Stream *strA, Object *dictA):
+ BaseStream(dictA) {
+ str = strA;
+}
+
+EmbedStream::~EmbedStream() {
+}
+
+Stream *EmbedStream::makeSubStream(int start, int length, Object *dictA) {
+ error(-1, "Internal: called makeSubStream() on EmbedStream");
+ return NULL;
+}
+
+void EmbedStream::setPos(int pos) {
+ error(-1, "Internal: called setPos() on EmbedStream");
+}
+
+int EmbedStream::getStart() {
+ error(-1, "Internal: called getStart() on EmbedStream");
+ return 0;
+}
+
+void EmbedStream::moveStart(int start) {
+ error(-1, "Internal: called moveStart() on EmbedStream");
+}
+
+//------------------------------------------------------------------------
+// ASCIIHexStream
+//------------------------------------------------------------------------
+
+ASCIIHexStream::ASCIIHexStream(Stream *strA):
+ FilterStream(strA) {
+ buf = EOF;
+ eof = gFalse;
+}
+
+ASCIIHexStream::~ASCIIHexStream() {
+ delete str;
+}
+
+void ASCIIHexStream::reset() {
+ str->reset();
+ buf = EOF;
+ eof = gFalse;
+}
+
+int ASCIIHexStream::lookChar() {
+ int c1, c2, x;
+
+ if (buf != EOF)
+ return buf;
+ if (eof) {
+ buf = EOF;
+ return EOF;
+ }
+ do {
+ c1 = str->getChar();
+ } while (isspace(c1));
+ if (c1 == '>') {
+ eof = gTrue;
+ buf = EOF;
+ return buf;
+ }
+ do {
+ c2 = str->getChar();
+ } while (isspace(c2));
+ if (c2 == '>') {
+ eof = gTrue;
+ c2 = '0';
+ }
+ if (c1 >= '0' && c1 <= '9') {
+ x = (c1 - '0') << 4;
+ } else if (c1 >= 'A' && c1 <= 'F') {
+ x = (c1 - 'A' + 10) << 4;
+ } else if (c1 >= 'a' && c1 <= 'f') {
+ x = (c1 - 'a' + 10) << 4;
+ } else if (c1 == EOF) {
+ eof = gTrue;
+ x = 0;
+ } else {
+ error(getPos(), "Illegal character <%02x> in ASCIIHex stream", c1);
+ x = 0;
+ }
+ if (c2 >= '0' && c2 <= '9') {
+ x += c2 - '0';
+ } else if (c2 >= 'A' && c2 <= 'F') {
+ x += c2 - 'A' + 10;
+ } else if (c2 >= 'a' && c2 <= 'f') {
+ x += c2 - 'a' + 10;
+ } else if (c2 == EOF) {
+ eof = gTrue;
+ x = 0;
+ } else {
+ error(getPos(), "Illegal character <%02x> in ASCIIHex stream", c2);
+ }
+ buf = x & 0xff;
+ return buf;
+}
+
+GString *ASCIIHexStream::getPSFilter(char *indent) {
+ GString *s;
+
+ if (!(s = str->getPSFilter(indent))) {
+ return NULL;
+ }
+ s->append(indent)->append("/ASCIIHexDecode filter\n");
+ return s;
+}
+
+GBool ASCIIHexStream::isBinary(GBool last) {
+ return str->isBinary(gFalse);
+}
+
+//------------------------------------------------------------------------
+// ASCII85Stream
+//------------------------------------------------------------------------
+
+ASCII85Stream::ASCII85Stream(Stream *strA):
+ FilterStream(strA) {
+ index = n = 0;
+ eof = gFalse;
+}
+
+ASCII85Stream::~ASCII85Stream() {
+ delete str;
+}
+
+void ASCII85Stream::reset() {
+ str->reset();
+ index = n = 0;
+ eof = gFalse;
+}
+
+int ASCII85Stream::lookChar() {
+ int k;
+ Gulong t;
+
+ if (index >= n) {
+ if (eof)
+ return EOF;
+ index = 0;
+ do {
+ c[0] = str->getChar();
+ } while (c[0] == '\n' || c[0] == '\r');
+ if (c[0] == '~' || c[0] == EOF) {
+ eof = gTrue;
+ n = 0;
+ return EOF;
+ } else if (c[0] == 'z') {
+ b[0] = b[1] = b[2] = b[3] = 0;
+ n = 4;
+ } else {
+ for (k = 1; k < 5; ++k) {
+ do {
+ c[k] = str->getChar();
+ } while (c[k] == '\n' || c[k] == '\r');
+ if (c[k] == '~' || c[k] == EOF)
+ break;
+ }
+ n = k - 1;
+ if (k < 5 && (c[k] == '~' || c[k] == EOF)) {
+ for (++k; k < 5; ++k)
+ c[k] = 0x21 + 84;
+ eof = gTrue;
+ }
+ t = 0;
+ for (k = 0; k < 5; ++k)
+ t = t * 85 + (c[k] - 0x21);
+ for (k = 3; k >= 0; --k) {
+ b[k] = (int)(t & 0xff);
+ t >>= 8;
+ }
+ }
+ }
+ return b[index];
+}
+
+GString *ASCII85Stream::getPSFilter(char *indent) {
+ GString *s;
+
+ if (!(s = str->getPSFilter(indent))) {
+ return NULL;
+ }
+ s->append(indent)->append("/ASCII85Decode filter\n");
+ return s;
+}
+
+GBool ASCII85Stream::isBinary(GBool last) {
+ return str->isBinary(gFalse);
+}
+
+//------------------------------------------------------------------------
+// LZWStream
+//------------------------------------------------------------------------
+
+LZWStream::LZWStream(Stream *strA, int predictor, int columns, int colors,
+ int bits, int earlyA):
+ FilterStream(strA) {
+ if (predictor != 1) {
+ pred = new StreamPredictor(this, predictor, columns, colors, bits);
+ } else {
+ pred = NULL;
+ }
+ early = earlyA;
+ zPipe = NULL;
+ bufPtr = bufEnd = buf;
+}
+
+LZWStream::~LZWStream() {
+ if (zPipe) {
+#ifdef HAVE_POPEN
+ pclose(zPipe);
+#else
+ fclose(zPipe);
+#endif
+ zPipe = NULL;
+ unlink(zName->getCString());
+ delete zName;
+ }
+ if (pred) {
+ delete pred;
+ }
+ delete str;
+}
+
+int LZWStream::getChar() {
+ if (pred) {
+ return pred->getChar();
+ }
+ return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff);
+}
+
+int LZWStream::lookChar() {
+ if (pred) {
+ return pred->lookChar();
+ }
+ return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff);
+}
+
+int LZWStream::getRawChar() {
+ return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff);
+}
+
+void LZWStream::reset() {
+ FILE *f;
+ GString *zCmd;
+
+ //----- close old LZW stream
+ if (zPipe) {
+#ifdef HAVE_POPEN
+ pclose(zPipe);
+#else
+ fclose(zPipe);
+#endif
+ zPipe = NULL;
+ unlink(zName->getCString());
+ delete zName;
+ }
+
+ //----- tell Delorie runtime to spawn a new instance of COMMAND.COM
+ // to run gzip
+#if __DJGPP__
+ if (!setDJSYSFLAGS) {
+ setenv("DJSYSFLAGS", "0x0002", 0);
+ setDJSYSFLAGS = gTrue;
+ }
+#endif
+
+ //----- create the .Z file
+ if (!openTempFile(&zName, &f, "wb", ".Z")) {
+ error(getPos(), "Couldn't create temporary file for LZW stream");
+ return;
+ }
+ dumpFile(f);
+ fclose(f);
+
+ //----- execute uncompress / gzip
+ zCmd = new GString(uncompressCmd);
+ zCmd->append(' ');
+ zCmd->append(zName);
+#if defined(MACOS)
+ long magicCookie;
+ // first we open the engine up
+ OSErr err = OpenSITEngine(kUseExternalEngine, &magicCookie);
+ // if we found it - let's use it!
+ if (!err && magicCookie) {
+ // make sure we have the correct version of the Engine
+ if (GetSITEngineVersion(magicCookie) >= kFirstSupportedEngine) {
+ FSSpec myFSS;
+ Str255 pName;
+ strcpy((char *)pName, zName->getCString());
+ c2pstr((char *)pName);
+ FSMakeFSSpec(0, 0, pName, &myFSS);
+ short ftype = DetermineFileType(magicCookie, &myFSS);
+ OSErr expandErr = ExpandFSSpec(magicCookie, ftype, &myFSS,
+ NULL, NULL, kCreateFolderNever,
+ kDeleteOriginal, kTextConvertSmart);
+ }
+ }
+#elif defined(HAVE_POPEN)
+ if (!(zPipe = popen(zCmd->getCString(), POPEN_READ_MODE))) {
+ error(getPos(), "Couldn't popen '%s'", zCmd->getCString());
+ unlink(zName->getCString());
+ delete zName;
+ return;
+ }
+#else // HAVE_POPEN
+#ifdef VMS
+ if (!system(zCmd->getCString())) {
+#else
+ if (system(zCmd->getCString())) {
+#endif
+ error(getPos(), "Couldn't execute '%s'", zCmd->getCString());
+ unlink(zName->getCString());
+ delete zName;
+ return;
+ }
+ zName->del(zName->getLength() - 2, 2);
+ if (!(zPipe = fopen(zName->getCString(), "rb"))) {
+ error(getPos(), "Couldn't open uncompress file '%s'", zName->getCString());
+ unlink(zName->getCString());
+ delete zName;
+ return;
+ }
+#endif // HAVE_POPEN
+
+ //----- clean up
+ delete zCmd;
+
+ //----- initialize buffer
+ bufPtr = bufEnd = buf;
+}
+
+void LZWStream::dumpFile(FILE *f) {
+ int outCodeBits; // size of output code
+ int outBits; // max output code
+ int outBuf[8]; // output buffer
+ int outData; // temporary output buffer
+ int inCode, outCode; // input and output codes
+ int nextCode; // next code index
+ GBool eof; // set when EOF is reached
+ GBool clear; // set if table needs to be cleared
+ GBool first; // indicates first code word after clear
+ int i, j;
+
+ str->reset();
+
+ // magic number
+ fputc(0x1f, f);
+ fputc(0x9d, f);
+
+ // max code length, block mode flag
+ fputc(0x8c, f);
+
+ // init input side
+ inCodeBits = 9;
+ inputBuf = 0;
+ inputBits = 0;
+ eof = gFalse;
+
+ // init output side
+ outCodeBits = 9;
+
+ // clear table
+ first = gTrue;
+ nextCode = 258;
+
+ clear = gFalse;
+ do {
+ for (i = 0; i < 8; ++i) {
+ // check for table overflow
+ if (nextCode + early > 0x1001) {
+ inCode = 256;
+
+ // read input code
+ } else {
+ do {
+ inCode = getCode();
+ if (inCode == EOF) {
+ eof = gTrue;
+ inCode = 0;
+ }
+ } while (first && inCode == 256);
+ }
+
+ // compute output code
+ if (inCode < 256) {
+ outCode = inCode;
+ } else if (inCode == 256) {
+ outCode = 256;
+ clear = gTrue;
+ } else if (inCode == 257) {
+ outCode = 0;
+ eof = gTrue;
+ } else {
+ outCode = inCode - 1;
+ }
+ outBuf[i] = outCode;
+
+ // next code index
+ if (first)
+ first = gFalse;
+ else
+ ++nextCode;
+
+ // check input code size
+ if (nextCode + early == 0x200)
+ inCodeBits = 10;
+ else if (nextCode + early == 0x400) {
+ inCodeBits = 11;
+ } else if (nextCode + early == 0x800) {
+ inCodeBits = 12;
+ }
+
+ // check for eof/clear
+ if (eof)
+ break;
+ if (clear) {
+ i = 8;
+ break;
+ }
+ }
+
+ // write output block
+ outData = 0;
+ outBits = 0;
+ j = 0;
+ while (j < i || outBits > 0) {
+ if (outBits < 8 && j < i) {
+ outData = outData | (outBuf[j++] << outBits);
+ outBits += outCodeBits;
+ }
+ fputc(outData & 0xff, f);
+ outData >>= 8;
+ outBits -= 8;
+ }
+
+ // check output code size
+ if (nextCode - 1 == 512 ||
+ nextCode - 1 == 1024 ||
+ nextCode - 1 == 2048 ||
+ nextCode - 1 == 4096) {
+ outCodeBits = inCodeBits;
+ }
+
+ // clear table if necessary
+ if (clear) {
+ inCodeBits = 9;
+ outCodeBits = 9;
+ first = gTrue;
+ nextCode = 258;
+ clear = gFalse;
+ }
+ } while (!eof);
+}
+
+int LZWStream::getCode() {
+ int c;
+ int code;
+
+ while (inputBits < inCodeBits) {
+ if ((c = str->getChar()) == EOF)
+ return EOF;
+ inputBuf = (inputBuf << 8) | (c & 0xff);
+ inputBits += 8;
+ }
+ code = (inputBuf >> (inputBits - inCodeBits)) & ((1 << inCodeBits) - 1);
+ inputBits -= inCodeBits;
+ return code;
+}
+
+GBool LZWStream::fillBuf() {
+ int n;
+
+ if (!zPipe)
+ return gFalse;
+ if ((n = fread(buf, 1, 256, zPipe)) < 256) {
+#ifdef HAVE_POPEN
+ pclose(zPipe);
+#else
+ fclose(zPipe);
+#endif
+ zPipe = NULL;
+ unlink(zName->getCString());
+ delete zName;
+ }
+ bufPtr = buf;
+ bufEnd = buf + n;
+ return n > 0;
+}
+
+GString *LZWStream::getPSFilter(char *indent) {
+ GString *s;
+
+ if (pred) {
+ return NULL;
+ }
+ if (!(s = str->getPSFilter(indent))) {
+ return NULL;
+ }
+ s->append(indent)->append("/LZWDecode filter\n");
+ return s;
+}
+
+GBool LZWStream::isBinary(GBool last) {
+ return str->isBinary(gTrue);
+}
+
+//------------------------------------------------------------------------
+// RunLengthStream
+//------------------------------------------------------------------------
+
+RunLengthStream::RunLengthStream(Stream *strA):
+ FilterStream(strA) {
+ bufPtr = bufEnd = buf;
+ eof = gFalse;
+}
+
+RunLengthStream::~RunLengthStream() {
+ delete str;
+}
+
+void RunLengthStream::reset() {
+ str->reset();
+ bufPtr = bufEnd = buf;
+ eof = gFalse;
+}
+
+GString *RunLengthStream::getPSFilter(char *indent) {
+ GString *s;
+
+ if (!(s = str->getPSFilter(indent))) {
+ return NULL;
+ }
+ s->append(indent)->append("/RunLengthDecode filter\n");
+ return s;
+}
+
+GBool RunLengthStream::isBinary(GBool last) {
+ return str->isBinary(gTrue);
+}
+
+GBool RunLengthStream::fillBuf() {
+ int c;
+ int n, i;
+
+ if (eof)
+ return gFalse;
+ c = str->getChar();
+ if (c == 0x80 || c == EOF) {
+ eof = gTrue;
+ return gFalse;
+ }
+ if (c < 0x80) {
+ n = c + 1;
+ for (i = 0; i < n; ++i)
+ buf[i] = (char)str->getChar();
+ } else {
+ n = 0x101 - c;
+ c = str->getChar();
+ for (i = 0; i < n; ++i)
+ buf[i] = (char)c;
+ }
+ bufPtr = buf;
+ bufEnd = buf + n;
+ return gTrue;
+}
+
+//------------------------------------------------------------------------
+// CCITTFaxStream
+//------------------------------------------------------------------------
+
+CCITTFaxStream::CCITTFaxStream(Stream *strA, int encodingA, GBool endOfLineA,
+ GBool byteAlignA, int columnsA, int rowsA,
+ GBool endOfBlockA, GBool blackA):
+ FilterStream(strA) {
+ encoding = encodingA;
+ endOfLine = endOfLineA;
+ byteAlign = byteAlignA;
+ columns = columnsA;
+ rows = rowsA;
+ endOfBlock = endOfBlockA;
+ black = blackA;
+ refLine = (short *)gmalloc((columns + 3) * sizeof(short));
+ codingLine = (short *)gmalloc((columns + 2) * sizeof(short));
+
+ eof = gFalse;
+ row = 0;
+ nextLine2D = encoding < 0;
+ inputBits = 0;
+ codingLine[0] = 0;
+ codingLine[1] = refLine[2] = columns;
+ a0 = 1;
+
+ buf = EOF;
+}
+
+CCITTFaxStream::~CCITTFaxStream() {
+ delete str;
+ gfree(refLine);
+ gfree(codingLine);
+}
+
+void CCITTFaxStream::reset() {
+ int n;
+
+ str->reset();
+ eof = gFalse;
+ row = 0;
+ nextLine2D = encoding < 0;
+ inputBits = 0;
+ codingLine[0] = 0;
+ codingLine[1] = refLine[2] = columns;
+ a0 = 1;
+ buf = EOF;
+
+ // get initial end-of-line marker and 2D encoding tag
+ if (endOfBlock) {
+ if (lookBits(12) == 0x001) {
+ eatBits(12);
+ }
+ } else {
+ for (n = 0; n < 11 && lookBits(n) == 0; ++n) ;
+ if (n == 11 && lookBits(12) == 0x001) {
+ eatBits(12);
+ }
+ }
+ if (encoding > 0) {
+ nextLine2D = !lookBits(1);
+ eatBits(1);
+ }
+}
+
+int CCITTFaxStream::lookChar() {
+ short code1, code2, code3;
+ int a0New;
+#if 0 //~
+ GBool err;
+#endif
+ GBool gotEOL;
+ int ret;
+ int bits, i;
+
+ // if at eof just return EOF
+ if (eof && codingLine[a0] >= columns) {
+ return EOF;
+ }
+
+ // read the next row
+#if 0 //~
+ err = gFalse;
+#endif
+ if (codingLine[a0] >= columns) {
+
+ // 2-D encoding
+ if (nextLine2D) {
+ for (i = 0; codingLine[i] < columns; ++i)
+ refLine[i] = codingLine[i];
+ refLine[i] = refLine[i + 1] = columns;
+ b1 = 1;
+ a0New = codingLine[a0 = 0] = 0;
+ do {
+ code1 = getTwoDimCode();
+ switch (code1) {
+ case twoDimPass:
+ if (refLine[b1] < columns) {
+ a0New = refLine[b1 + 1];
+ b1 += 2;
+ }
+ break;
+ case twoDimHoriz:
+ if ((a0 & 1) == 0) {
+ code1 = code2 = 0;
+ do {
+ code1 += code3 = getWhiteCode();
+ } while (code3 >= 64);
+ do {
+ code2 += code3 = getBlackCode();
+ } while (code3 >= 64);
+ } else {
+ code1 = code2 = 0;
+ do {
+ code1 += code3 = getBlackCode();
+ } while (code3 >= 64);
+ do {
+ code2 += code3 = getWhiteCode();
+ } while (code3 >= 64);
+ }
+ codingLine[a0 + 1] = a0New + code1;
+ ++a0;
+ a0New = codingLine[a0 + 1] = codingLine[a0] + code2;
+ ++a0;
+ while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns)
+ b1 += 2;
+ break;
+ case twoDimVert0:
+ a0New = codingLine[++a0] = refLine[b1];
+ if (refLine[b1] < columns) {
+ ++b1;
+ while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns)
+ b1 += 2;
+ }
+ break;
+ case twoDimVertR1:
+ a0New = codingLine[++a0] = refLine[b1] + 1;
+ if (refLine[b1] < columns) {
+ ++b1;
+ while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns)
+ b1 += 2;
+ }
+ break;
+ case twoDimVertL1:
+ a0New = codingLine[++a0] = refLine[b1] - 1;
+ --b1;
+ while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns)
+ b1 += 2;
+ break;
+ case twoDimVertR2:
+ a0New = codingLine[++a0] = refLine[b1] + 2;
+ if (refLine[b1] < columns) {
+ ++b1;
+ while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns)
+ b1 += 2;
+ }
+ break;
+ case twoDimVertL2:
+ a0New = codingLine[++a0] = refLine[b1] - 2;
+ --b1;
+ while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns)
+ b1 += 2;
+ break;
+ case twoDimVertR3:
+ a0New = codingLine[++a0] = refLine[b1] + 3;
+ if (refLine[b1] < columns) {
+ ++b1;
+ while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns)
+ b1 += 2;
+ }
+ break;
+ case twoDimVertL3:
+ a0New = codingLine[++a0] = refLine[b1] - 3;
+ --b1;
+ while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns)
+ b1 += 2;
+ break;
+ case EOF:
+ eof = gTrue;
+ codingLine[a0 = 0] = columns;
+ return EOF;
+ default:
+ error(getPos(), "Bad 2D code %04x in CCITTFax stream", code1);
+#if 0 //~
+ err = gTrue;
+ break;
+#else
+ eof = gTrue;
+ return EOF;
+#endif
+ }
+ } while (codingLine[a0] < columns);
+
+ // 1-D encoding
+ } else {
+ codingLine[a0 = 0] = 0;
+ while (1) {
+ code1 = 0;
+ do {
+ code1 += code3 = getWhiteCode();
+ } while (code3 >= 64);
+ codingLine[a0+1] = codingLine[a0] + code1;
+ ++a0;
+ if (codingLine[a0] >= columns)
+ break;
+ code2 = 0;
+ do {
+ code2 += code3 = getBlackCode();
+ } while (code3 >= 64);
+ codingLine[a0+1] = codingLine[a0] + code2;
+ ++a0;
+ if (codingLine[a0] >= columns)
+ break;
+ }
+ }
+
+ if (codingLine[a0] != columns) {
+ error(getPos(), "CCITTFax row is wrong length (%d)", codingLine[a0]);
+#if 0 //~
+ err = gTrue;
+#endif
+ }
+
+ // byte-align the row
+ if (byteAlign) {
+ inputBits &= ~7;
+ }
+
+ // check for end-of-line marker, skipping over any extra zero bits
+ gotEOL = gFalse;
+ if (!endOfBlock && row == rows - 1) {
+ eof = gTrue;
+ } else {
+ code1 = lookBits(12);
+ while (code1 == 0) {
+ eatBits(1);
+ code1 = lookBits(12);
+ }
+ if (code1 == 0x001) {
+ eatBits(12);
+ gotEOL = gTrue;
+ } else if (code1 == EOF) {
+ eof = gTrue;
+ }
+ }
+
+ // get 2D encoding tag
+ if (!eof && encoding > 0) {
+ nextLine2D = !lookBits(1);
+ eatBits(1);
+ }
+
+ // check for end-of-block marker
+ if (endOfBlock && gotEOL) {
+ code1 = lookBits(12);
+ if (code1 == 0x001) {
+ eatBits(12);
+ if (encoding > 0) {
+ lookBits(1);
+ eatBits(1);
+ }
+ if (encoding >= 0) {
+ for (i = 0; i < 4; ++i) {
+ code1 = lookBits(12);
+ if (code1 != 0x001) {
+ error(getPos(), "Bad RTC code in CCITTFax stream");
+ }
+ eatBits(12);
+ if (encoding > 0) {
+ lookBits(1);
+ eatBits(1);
+ }
+ }
+ }
+ eof = gTrue;
+ }
+ }
+
+#if 0 //~
+ // This looks for an end-of-line marker after an error, however
+ // some (most?) CCITT streams in PDF files don't use end-of-line
+ // markers, and the just-plow-on technique works better in those
+ // cases.
+ else if (err) {
+ do {
+ if (code1 == EOF) {
+ eof = gTrue;
+ return EOF;
+ }
+ eatBits(1);
+ code1 = look13Bits();
+ } while ((code1 >> 1) != 0x001);
+ eatBits(12);
+ codingLine[++a0] = columns;
+ if (encoding > 0) {
+ eatBits(1);
+ nextLine2D = !(code1 & 1);
+ }
+ }
+#endif
+
+ a0 = 0;
+ outputBits = codingLine[1] - codingLine[0];
+ if (outputBits == 0) {
+ a0 = 1;
+ outputBits = codingLine[2] - codingLine[1];
+ }
+
+ ++row;
+ }
+
+ // get a byte
+ if (outputBits >= 8) {
+ ret = ((a0 & 1) == 0) ? 0xff : 0x00;
+ if ((outputBits -= 8) == 0) {
+ ++a0;
+ if (codingLine[a0] < columns) {
+ outputBits = codingLine[a0 + 1] - codingLine[a0];
+ }
+ }
+ } else {
+ bits = 8;
+ ret = 0;
+ do {
+ if (outputBits > bits) {
+ i = bits;
+ bits = 0;
+ if ((a0 & 1) == 0) {
+ ret |= 0xff >> (8 - i);
+ }
+ outputBits -= i;
+ } else {
+ i = outputBits;
+ bits -= outputBits;
+ if ((a0 & 1) == 0) {
+ ret |= (0xff >> (8 - i)) << bits;
+ }
+ outputBits = 0;
+ ++a0;
+ if (codingLine[a0] < columns) {
+ outputBits = codingLine[a0 + 1] - codingLine[a0];
+ }
+ }
+ } while (bits > 0 && codingLine[a0] < columns);
+ }
+ buf = black ? (ret ^ 0xff) : ret;
+ return buf;
+}
+
+short CCITTFaxStream::getTwoDimCode() {
+ short code;
+ CCITTCode *p;
+ int n;
+
+ code = 0; // make gcc happy
+ if (endOfBlock) {
+ code = lookBits(7);
+ p = &twoDimTab1[code];
+ if (p->bits > 0) {
+ eatBits(p->bits);
+ return p->n;
+ }
+ } else {
+ for (n = 1; n <= 7; ++n) {
+ code = lookBits(n);
+ if (n < 7) {
+ code <<= 7 - n;
+ }
+ p = &twoDimTab1[code];
+ if (p->bits == n) {
+ eatBits(n);
+ return p->n;
+ }
+ }
+ }
+ error(getPos(), "Bad two dim code (%04x) in CCITTFax stream", code);
+ return EOF;
+}
+
+short CCITTFaxStream::getWhiteCode() {
+ short code;
+ CCITTCode *p;
+ int n;
+
+ code = 0; // make gcc happy
+ if (endOfBlock) {
+ code = lookBits(12);
+ if ((code >> 5) == 0) {
+ p = &whiteTab1[code];
+ } else {
+ p = &whiteTab2[code >> 3];
+ }
+ if (p->bits > 0) {
+ eatBits(p->bits);
+ return p->n;
+ }
+ } else {
+ for (n = 1; n <= 9; ++n) {
+ code = lookBits(n);
+ if (n < 9) {
+ code <<= 9 - n;
+ }
+ p = &whiteTab2[code];
+ if (p->bits == n) {
+ eatBits(n);
+ return p->n;
+ }
+ }
+ for (n = 11; n <= 12; ++n) {
+ code = lookBits(n);
+ if (n < 12) {
+ code <<= 12 - n;
+ }
+ p = &whiteTab1[code];
+ if (p->bits == n) {
+ eatBits(n);
+ return p->n;
+ }
+ }
+ }
+ error(getPos(), "Bad white code (%04x) in CCITTFax stream", code);
+ // eat a bit and return a positive number so that the caller doesn't
+ // go into an infinite loop
+ eatBits(1);
+ return 1;
+}
+
+short CCITTFaxStream::getBlackCode() {
+ short code;
+ CCITTCode *p;
+ int n;
+
+ code = 0; // make gcc happy
+ if (endOfBlock) {
+ code = lookBits(13);
+ if ((code >> 7) == 0) {
+ p = &blackTab1[code];
+ } else if ((code >> 9) == 0) {
+ p = &blackTab2[(code >> 1) - 64];
+ } else {
+ p = &blackTab3[code >> 7];
+ }
+ if (p->bits > 0) {
+ eatBits(p->bits);
+ return p->n;
+ }
+ } else {
+ for (n = 2; n <= 6; ++n) {
+ code = lookBits(n);
+ if (n < 6) {
+ code <<= 6 - n;
+ }
+ p = &blackTab3[code];
+ if (p->bits == n) {
+ eatBits(n);
+ return p->n;
+ }
+ }
+ for (n = 7; n <= 12; ++n) {
+ code = lookBits(n);
+ if (n < 12) {
+ code <<= 12 - n;
+ }
+ if (code >= 64) {
+ p = &blackTab2[code - 64];
+ if (p->bits == n) {
+ eatBits(n);
+ return p->n;
+ }
+ }
+ }
+ for (n = 10; n <= 13; ++n) {
+ code = lookBits(n);
+ if (n < 13) {
+ code <<= 13 - n;
+ }
+ p = &blackTab1[code];
+ if (p->bits == n) {
+ eatBits(n);
+ return p->n;
+ }
+ }
+ }
+ error(getPos(), "Bad black code (%04x) in CCITTFax stream", code);
+ // eat a bit and return a positive number so that the caller doesn't
+ // go into an infinite loop
+ eatBits(1);
+ return 1;
+}
+
+short CCITTFaxStream::lookBits(int n) {
+ int c;
+
+ while (inputBits < n) {
+ if ((c = str->getChar()) == EOF) {
+ if (inputBits == 0) {
+ return EOF;
+ }
+ // near the end of the stream, the caller may ask for more bits
+ // than are available, but there may still be a valid code in
+ // however many bits are available -- we need to return correct
+ // data in this case
+ return (inputBuf << (n - inputBits)) & (0xffff >> (16 - n));
+ }
+ inputBuf = (inputBuf << 8) + c;
+ inputBits += 8;
+ }
+ return (inputBuf >> (inputBits - n)) & (0xffff >> (16 - n));
+}
+
+GString *CCITTFaxStream::getPSFilter(char *indent) {
+ GString *s;
+ char s1[50];
+
+ if (!(s = str->getPSFilter(indent))) {
+ return NULL;
+ }
+ s->append(indent)->append("<< ");
+ if (encoding != 0) {
+ sprintf(s1, "/K %d ", encoding);
+ s->append(s1);
+ }
+ if (endOfLine) {
+ s->append("/EndOfLine true ");
+ }
+ if (byteAlign) {
+ s->append("/EncodedByteAlign true ");
+ }
+ sprintf(s1, "/Columns %d ", columns);
+ s->append(s1);
+ if (rows != 0) {
+ sprintf(s1, "/Rows %d ", rows);
+ s->append(s1);
+ }
+ if (!endOfBlock) {
+ s->append("/EndOfBlock false ");
+ }
+ if (black) {
+ s->append("/BlackIs1 true ");
+ }
+ s->append(">> /CCITTFaxDecode filter\n");
+ return s;
+}
+
+GBool CCITTFaxStream::isBinary(GBool last) {
+ return str->isBinary(gTrue);
+}
+
+//------------------------------------------------------------------------
+// DCTStream
+//------------------------------------------------------------------------
+
+// IDCT constants (20.12 fixed point format)
+#ifndef FP_IDCT
+#define dctCos1 4017 // cos(pi/16)
+#define dctSin1 799 // sin(pi/16)
+#define dctCos3 3406 // cos(3*pi/16)
+#define dctSin3 2276 // sin(3*pi/16)
+#define dctCos6 1567 // cos(6*pi/16)
+#define dctSin6 3784 // sin(6*pi/16)
+#define dctSqrt2 5793 // sqrt(2)
+#define dctSqrt1d2 2896 // sqrt(2) / 2
+#endif
+
+// IDCT constants
+#ifdef FP_IDCT
+#define dctCos1 0.98078528 // cos(pi/16)
+#define dctSin1 0.19509032 // sin(pi/16)
+#define dctCos3 0.83146961 // cos(3*pi/16)
+#define dctSin3 0.55557023 // sin(3*pi/16)
+#define dctCos6 0.38268343 // cos(6*pi/16)
+#define dctSin6 0.92387953 // sin(6*pi/16)
+#define dctSqrt2 1.41421356 // sqrt(2)
+#define dctSqrt1d2 0.70710678 // sqrt(2) / 2
+#endif
+
+// color conversion parameters (16.16 fixed point format)
+#define dctCrToR 91881 // 1.4020
+#define dctCbToG -22553 // -0.3441363
+#define dctCrToG -46802 // -0.71413636
+#define dctCbToB 116130 // 1.772
+
+// clip [-256,511] --> [0,255]
+#define dctClipOffset 256
+static Guchar dctClip[768];
+static int dctClipInit = 0;
+
+// zig zag decode map
+static int dctZigZag[64] = {
+ 0,
+ 1, 8,
+ 16, 9, 2,
+ 3, 10, 17, 24,
+ 32, 25, 18, 11, 4,
+ 5, 12, 19, 26, 33, 40,
+ 48, 41, 34, 27, 20, 13, 6,
+ 7, 14, 21, 28, 35, 42, 49, 56,
+ 57, 50, 43, 36, 29, 22, 15,
+ 23, 30, 37, 44, 51, 58,
+ 59, 52, 45, 38, 31,
+ 39, 46, 53, 60,
+ 61, 54, 47,
+ 55, 62,
+ 63
+};
+
+DCTStream::DCTStream(Stream *strA):
+ FilterStream(strA) {
+ int i, j;
+
+ width = height = 0;
+ mcuWidth = mcuHeight = 0;
+ numComps = 0;
+ comp = 0;
+ x = y = dy = 0;
+ for (i = 0; i < 4; ++i)
+ for (j = 0; j < 32; ++j)
+ rowBuf[i][j] = NULL;
+
+ if (!dctClipInit) {
+ for (i = -256; i < 0; ++i)
+ dctClip[dctClipOffset + i] = 0;
+ for (i = 0; i < 256; ++i)
+ dctClip[dctClipOffset + i] = i;
+ for (i = 256; i < 512; ++i)
+ dctClip[dctClipOffset + i] = 255;
+ dctClipInit = 1;
+ }
+}
+
+DCTStream::~DCTStream() {
+ int i, j;
+
+ delete str;
+ for (i = 0; i < numComps; ++i)
+ for (j = 0; j < mcuHeight; ++j)
+ gfree(rowBuf[i][j]);
+}
+
+void DCTStream::reset() {
+ str->reset();
+ if (!readHeader()) {
+ y = height;
+ return;
+ }
+ restartMarker = 0xd0;
+ restart();
+}
+
+int DCTStream::getChar() {
+ int c;
+
+ c = lookChar();
+ if (c == EOF)
+ return EOF;
+ if (++comp == numComps) {
+ comp = 0;
+ if (++x == width) {
+ x = 0;
+ ++y;
+ ++dy;
+ }
+ }
+ if (y == height)
+ readTrailer();
+ return c;
+}
+
+int DCTStream::lookChar() {
+ if (y >= height)
+ return EOF;
+ if (dy >= mcuHeight) {
+ if (!readMCURow()) {
+ y = height;
+ return EOF;
+ }
+ comp = 0;
+ x = 0;
+ dy = 0;
+ }
+ return rowBuf[comp][dy][x];
+}
+
+void DCTStream::restart() {
+ int i;
+
+ inputBits = 0;
+ restartCtr = restartInterval;
+ for (i = 0; i < numComps; ++i)
+ compInfo[i].prevDC = 0;
+}
+
+GBool DCTStream::readMCURow() {
+ Guchar data[64];
+ Guchar *p1, *p2;
+ int pY, pCb, pCr, pR, pG, pB;
+ int h, v, horiz, vert, hSub, vSub;
+ int x1, x2, y2, x3, y3, x4, y4, x5, y5, cc, i;
+ int c;
+
+ for (x1 = 0; x1 < width; x1 += mcuWidth) {
+
+ // deal with restart marker
+ if (restartInterval > 0 && restartCtr == 0) {
+ c = readMarker();
+ if (c != restartMarker) {
+ error(getPos(), "Bad DCT data: incorrect restart marker");
+ return gFalse;
+ }
+ if (++restartMarker == 0xd8)
+ restartMarker = 0xd0;
+ restart();
+ }
+
+ // read one MCU
+ for (cc = 0; cc < numComps; ++cc) {
+ h = compInfo[cc].hSample;
+ v = compInfo[cc].vSample;
+ horiz = mcuWidth / h;
+ vert = mcuHeight / v;
+ hSub = horiz / 8;
+ vSub = vert / 8;
+ for (y2 = 0; y2 < mcuHeight; y2 += vert) {
+ for (x2 = 0; x2 < mcuWidth; x2 += horiz) {
+ if (!readDataUnit(&dcHuffTables[compInfo[cc].dcHuffTable],
+ &acHuffTables[compInfo[cc].acHuffTable],
+ quantTables[compInfo[cc].quantTable],
+ &compInfo[cc].prevDC,
+ data))
+ return gFalse;
+ if (hSub == 1 && vSub == 1) {
+ for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) {
+ p1 = &rowBuf[cc][y2+y3][x1+x2];
+ p1[0] = data[i];
+ p1[1] = data[i+1];
+ p1[2] = data[i+2];
+ p1[3] = data[i+3];
+ p1[4] = data[i+4];
+ p1[5] = data[i+5];
+ p1[6] = data[i+6];
+ p1[7] = data[i+7];
+ }
+ } else if (hSub == 2 && vSub == 2) {
+ for (y3 = 0, i = 0; y3 < 16; y3 += 2, i += 8) {
+ p1 = &rowBuf[cc][y2+y3][x1+x2];
+ p2 = &rowBuf[cc][y2+y3+1][x1+x2];
+ p1[0] = p1[1] = p2[0] = p2[1] = data[i];
+ p1[2] = p1[3] = p2[2] = p2[3] = data[i+1];
+ p1[4] = p1[5] = p2[4] = p2[5] = data[i+2];
+ p1[6] = p1[7] = p2[6] = p2[7] = data[i+3];
+ p1[8] = p1[9] = p2[8] = p2[9] = data[i+4];
+ p1[10] = p1[11] = p2[10] = p2[11] = data[i+5];
+ p1[12] = p1[13] = p2[12] = p2[13] = data[i+6];
+ p1[14] = p1[15] = p2[14] = p2[15] = data[i+7];
+ }
+ } else {
+ i = 0;
+ for (y3 = 0, y4 = 0; y3 < 8; ++y3, y4 += vSub) {
+ for (x3 = 0, x4 = 0; x3 < 8; ++x3, x4 += hSub) {
+ for (y5 = 0; y5 < vSub; ++y5)
+ for (x5 = 0; x5 < hSub; ++x5)
+ rowBuf[cc][y2+y4+y5][x1+x2+x4+x5] = data[i];
+ ++i;
+ }
+ }
+ }
+ }
+ }
+ }
+ --restartCtr;
+
+ // color space conversion
+ if (colorXform) {
+ // convert YCbCr to RGB
+ if (numComps == 3) {
+ for (y2 = 0; y2 < mcuHeight; ++y2) {
+ for (x2 = 0; x2 < mcuWidth; ++x2) {
+ pY = rowBuf[0][y2][x1+x2];
+ pCb = rowBuf[1][y2][x1+x2] - 128;
+ pCr = rowBuf[2][y2][x1+x2] - 128;
+ pR = ((pY << 16) + dctCrToR * pCr + 32768) >> 16;
+ rowBuf[0][y2][x1+x2] = dctClip[dctClipOffset + pR];
+ pG = ((pY << 16) + dctCbToG * pCb + dctCrToG * pCr + 32768) >> 16;
+ rowBuf[1][y2][x1+x2] = dctClip[dctClipOffset + pG];
+ pB = ((pY << 16) + dctCbToB * pCb + 32768) >> 16;
+ rowBuf[2][y2][x1+x2] = dctClip[dctClipOffset + pB];
+ }
+ }
+ // convert YCbCrK to CMYK (K is passed through unchanged)
+ } else if (numComps == 4) {
+ for (y2 = 0; y2 < mcuHeight; ++y2) {
+ for (x2 = 0; x2 < mcuWidth; ++x2) {
+ pY = rowBuf[0][y2][x1+x2];
+ pCb = rowBuf[1][y2][x1+x2] - 128;
+ pCr = rowBuf[2][y2][x1+x2] - 128;
+ pR = ((pY << 16) + dctCrToR * pCr + 32768) >> 16;
+ rowBuf[0][y2][x1+x2] = 255 - dctClip[dctClipOffset + pR];
+ pG = ((pY << 16) + dctCbToG * pCb + dctCrToG * pCr + 32678) >> 16;
+ rowBuf[1][y2][x1+x2] = 255 - dctClip[dctClipOffset + pG];
+ pB = ((pY << 16) + dctCbToB * pCb + 32768) >> 16;
+ rowBuf[2][y2][x1+x2] = 255 - dctClip[dctClipOffset + pB];
+ }
+ }
+ }
+ }
+ }
+ return gTrue;
+}
+
+// This IDCT algorithm is taken from:
+// Christoph Loeffler, Adriaan Ligtenberg, George S. Moschytz,
+// "Practical Fast 1-D DCT Algorithms with 11 Multiplications",
+// IEEE Intl. Conf. on Acoustics, Speech & Signal Processing, 1989,
+// 988-991.
+// The stage numbers mentioned in the comments refer to Figure 1 in this
+// paper.
+#ifndef FP_IDCT
+GBool DCTStream::readDataUnit(DCTHuffTable *dcHuffTable,
+ DCTHuffTable *acHuffTable,
+ Guchar quantTable[64], int *prevDC,
+ Guchar data[64]) {
+ int tmp1[64];
+ int v0, v1, v2, v3, v4, v5, v6, v7, t;
+ int run, size, amp;
+ int c;
+ int i, j;
+
+ // Huffman decode and dequantize
+ size = readHuffSym(dcHuffTable);
+ if (size == 9999)
+ return gFalse;
+ if (size > 0) {
+ amp = readAmp(size);
+ if (amp == 9999)
+ return gFalse;
+ } else {
+ amp = 0;
+ }
+ tmp1[0] = (*prevDC += amp) * quantTable[0];
+ for (i = 1; i < 64; ++i)
+ tmp1[i] = 0;
+ i = 1;
+ while (i < 64) {
+ run = 0;
+ while ((c = readHuffSym(acHuffTable)) == 0xf0 && run < 0x30)
+ run += 0x10;
+ if (c == 9999)
+ return gFalse;
+ if (c == 0x00) {
+ break;
+ } else {
+ run += (c >> 4) & 0x0f;
+ size = c & 0x0f;
+ amp = readAmp(size);
+ if (amp == 9999)
+ return gFalse;
+ i += run;
+ j = dctZigZag[i++];
+ tmp1[j] = amp * quantTable[j];
+ }
+ }
+
+ // inverse DCT on rows
+ for (i = 0; i < 64; i += 8) {
+
+ // stage 4
+ v0 = (dctSqrt2 * tmp1[i+0] + 128) >> 8;
+ v1 = (dctSqrt2 * tmp1[i+4] + 128) >> 8;
+ v2 = tmp1[i+2];
+ v3 = tmp1[i+6];
+ v4 = (dctSqrt1d2 * (tmp1[i+1] - tmp1[i+7]) + 128) >> 8;
+ v7 = (dctSqrt1d2 * (tmp1[i+1] + tmp1[i+7]) + 128) >> 8;
+ v5 = tmp1[i+3] << 4;
+ v6 = tmp1[i+5] << 4;
+
+ // stage 3
+ t = (v0 - v1+ 1) >> 1;
+ v0 = (v0 + v1 + 1) >> 1;
+ v1 = t;
+ t = (v2 * dctSin6 + v3 * dctCos6 + 128) >> 8;
+ v2 = (v2 * dctCos6 - v3 * dctSin6 + 128) >> 8;
+ v3 = t;
+ t = (v4 - v6 + 1) >> 1;
+ v4 = (v4 + v6 + 1) >> 1;
+ v6 = t;
+ t = (v7 + v5 + 1) >> 1;
+ v5 = (v7 - v5 + 1) >> 1;
+ v7 = t;
+
+ // stage 2
+ t = (v0 - v3 + 1) >> 1;
+ v0 = (v0 + v3 + 1) >> 1;
+ v3 = t;
+ t = (v1 - v2 + 1) >> 1;
+ v1 = (v1 + v2 + 1) >> 1;
+ v2 = t;
+ t = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12;
+ v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12;
+ v7 = t;
+ t = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12;
+ v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12;
+ v6 = t;
+
+ // stage 1
+ tmp1[i+0] = v0 + v7;
+ tmp1[i+7] = v0 - v7;
+ tmp1[i+1] = v1 + v6;
+ tmp1[i+6] = v1 - v6;
+ tmp1[i+2] = v2 + v5;
+ tmp1[i+5] = v2 - v5;
+ tmp1[i+3] = v3 + v4;
+ tmp1[i+4] = v3 - v4;
+ }
+
+ // inverse DCT on columns
+ for (i = 0; i < 8; ++i) {
+
+ // stage 4
+ v0 = (dctSqrt2 * tmp1[0*8+i] + 2048) >> 12;
+ v1 = (dctSqrt2 * tmp1[4*8+i] + 2048) >> 12;
+ v2 = tmp1[2*8+i];
+ v3 = tmp1[6*8+i];
+ v4 = (dctSqrt1d2 * (tmp1[1*8+i] - tmp1[7*8+i]) + 2048) >> 12;
+ v7 = (dctSqrt1d2 * (tmp1[1*8+i] + tmp1[7*8+i]) + 2048) >> 12;
+ v5 = tmp1[3*8+i];
+ v6 = tmp1[5*8+i];
+
+ // stage 3
+ t = (v0 - v1 + 1) >> 1;
+ v0 = (v0 + v1 + 1) >> 1;
+ v1 = t;
+ t = (v2 * dctSin6 + v3 * dctCos6 + 2048) >> 12;
+ v2 = (v2 * dctCos6 - v3 * dctSin6 + 2048) >> 12;
+ v3 = t;
+ t = (v4 - v6 + 1) >> 1;
+ v4 = (v4 + v6 + 1) >> 1;
+ v6 = t;
+ t = (v7 + v5 + 1) >> 1;
+ v5 = (v7 - v5 + 1) >> 1;
+ v7 = t;
+
+ // stage 2
+ t = (v0 - v3 + 1) >> 1;
+ v0 = (v0 + v3 + 1) >> 1;
+ v3 = t;
+ t = (v1 - v2 + 1) >> 1;
+ v1 = (v1 + v2 + 1) >> 1;
+ v2 = t;
+ t = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12;
+ v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12;
+ v7 = t;
+ t = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12;
+ v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12;
+ v6 = t;
+
+ // stage 1
+ tmp1[0*8+i] = v0 + v7;
+ tmp1[7*8+i] = v0 - v7;
+ tmp1[1*8+i] = v1 + v6;
+ tmp1[6*8+i] = v1 - v6;
+ tmp1[2*8+i] = v2 + v5;
+ tmp1[5*8+i] = v2 - v5;
+ tmp1[3*8+i] = v3 + v4;
+ tmp1[4*8+i] = v3 - v4;
+ }
+
+ // convert to 8-bit integers
+ for (i = 0; i < 64; ++i)
+ data[i] = dctClip[dctClipOffset + 128 + ((tmp1[i] + 8) >> 4)];
+
+ return gTrue;
+}
+#endif
+
+#ifdef FP_IDCT
+GBool DCTStream::readDataUnit(DCTHuffTable *dcHuffTable,
+ DCTHuffTable *acHuffTable,
+ Guchar quantTable[64], int *prevDC,
+ Guchar data[64]) {
+ double tmp1[64];
+ double v0, v1, v2, v3, v4, v5, v6, v7, t;
+ int run, size, amp;
+ int c;
+ int i, j;
+
+ // Huffman decode and dequantize
+ size = readHuffSym(dcHuffTable);
+ if (size == 9999)
+ return gFalse;
+ if (size > 0) {
+ amp = readAmp(size);
+ if (amp == 9999)
+ return gFalse;
+ } else {
+ amp = 0;
+ }
+ tmp1[0] = (*prevDC += amp) * quantTable[0];
+ for (i = 1; i < 64; ++i)
+ tmp1[i] = 0;
+ i = 1;
+ while (i < 64) {
+ run = 0;
+ while ((c = readHuffSym(acHuffTable)) == 0xf0 && run < 0x30)
+ run += 0x10;
+ if (c == 9999)
+ return gFalse;
+ if (c == 0x00) {
+ break;
+ } else {
+ run += (c >> 4) & 0x0f;
+ size = c & 0x0f;
+ amp = readAmp(size);
+ if (amp == 9999)
+ return gFalse;
+ i += run;
+ j = dctZigZag[i++];
+ tmp1[j] = amp * quantTable[j];
+ }
+ }
+
+ // inverse DCT on rows
+ for (i = 0; i < 64; i += 8) {
+
+ // stage 4
+ v0 = dctSqrt2 * tmp1[i+0];
+ v1 = dctSqrt2 * tmp1[i+4];
+ v2 = tmp1[i+2];
+ v3 = tmp1[i+6];
+ v4 = dctSqrt1d2 * (tmp1[i+1] - tmp1[i+7]);
+ v7 = dctSqrt1d2 * (tmp1[i+1] + tmp1[i+7]);
+ v5 = tmp1[i+3];
+ v6 = tmp1[i+5];
+
+ // stage 3
+ t = 0.5 * (v0 - v1);
+ v0 = 0.5 * (v0 + v1);
+ v1 = t;
+ t = v2 * dctSin6 + v3 * dctCos6;
+ v2 = v2 * dctCos6 - v3 * dctSin6;
+ v3 = t;
+ t = 0.5 * (v4 - v6);
+ v4 = 0.5 * (v4 + v6);
+ v6 = t;
+ t = 0.5 * (v7 + v5);
+ v5 = 0.5 * (v7 - v5);
+ v7 = t;
+
+ // stage 2
+ t = 0.5 * (v0 - v3);
+ v0 = 0.5 * (v0 + v3);
+ v3 = t;
+ t = 0.5 * (v1 - v2);
+ v1 = 0.5 * (v1 + v2);
+ v2 = t;
+ t = v4 * dctSin3 + v7 * dctCos3;
+ v4 = v4 * dctCos3 - v7 * dctSin3;
+ v7 = t;
+ t = v5 * dctSin1 + v6 * dctCos1;
+ v5 = v5 * dctCos1 - v6 * dctSin1;
+ v6 = t;
+
+ // stage 1
+ tmp1[i+0] = v0 + v7;
+ tmp1[i+7] = v0 - v7;
+ tmp1[i+1] = v1 + v6;
+ tmp1[i+6] = v1 - v6;
+ tmp1[i+2] = v2 + v5;
+ tmp1[i+5] = v2 - v5;
+ tmp1[i+3] = v3 + v4;
+ tmp1[i+4] = v3 - v4;
+ }
+
+ // inverse DCT on columns
+ for (i = 0; i < 8; ++i) {
+
+ // stage 4
+ v0 = dctSqrt2 * tmp1[0*8+i];
+ v1 = dctSqrt2 * tmp1[4*8+i];
+ v2 = tmp1[2*8+i];
+ v3 = tmp1[6*8+i];
+ v4 = dctSqrt1d2 * (tmp1[1*8+i] - tmp1[7*8+i]);
+ v7 = dctSqrt1d2 * (tmp1[1*8+i] + tmp1[7*8+i]);
+ v5 = tmp1[3*8+i];
+ v6 = tmp1[5*8+i];
+
+ // stage 3
+ t = 0.5 * (v0 - v1);
+ v0 = 0.5 * (v0 + v1);
+ v1 = t;
+ t = v2 * dctSin6 + v3 * dctCos6;
+ v2 = v2 * dctCos6 - v3 * dctSin6;
+ v3 = t;
+ t = 0.5 * (v4 - v6);
+ v4 = 0.5 * (v4 + v6);
+ v6 = t;
+ t = 0.5 * (v7 + v5);
+ v5 = 0.5 * (v7 - v5);
+ v7 = t;
+
+ // stage 2
+ t = 0.5 * (v0 - v3);
+ v0 = 0.5 * (v0 + v3);
+ v3 = t;
+ t = 0.5 * (v1 - v2);
+ v1 = 0.5 * (v1 + v2);
+ v2 = t;
+ t = v4 * dctSin3 + v7 * dctCos3;
+ v4 = v4 * dctCos3 - v7 * dctSin3;
+ v7 = t;
+ t = v5 * dctSin1 + v6 * dctCos1;
+ v5 = v5 * dctCos1 - v6 * dctSin1;
+ v6 = t;
+
+ // stage 1
+ tmp1[0*8+i] = v0 + v7;
+ tmp1[7*8+i] = v0 - v7;
+ tmp1[1*8+i] = v1 + v6;
+ tmp1[6*8+i] = v1 - v6;
+ tmp1[2*8+i] = v2 + v5;
+ tmp1[5*8+i] = v2 - v5;
+ tmp1[3*8+i] = v3 + v4;
+ tmp1[4*8+i] = v3 - v4;
+ }
+
+ // convert to 8-bit integers
+ for (i = 0; i < 64; ++i)
+ data[i] = dctClip[dctClipOffset + (int)(tmp1[i] + 128.5)];
+
+ return gTrue;
+}
+#endif
+
+int DCTStream::readHuffSym(DCTHuffTable *table) {
+ Gushort code;
+ int bit;
+ int codeBits;
+
+ code = 0;
+ codeBits = 0;
+ do {
+ // add a bit to the code
+ if ((bit = readBit()) == EOF)
+ return 9999;
+ code = (code << 1) + bit;
+ ++codeBits;
+
+ // look up code
+ if (code - table->firstCode[codeBits] < table->numCodes[codeBits]) {
+ code -= table->firstCode[codeBits];
+ return table->sym[table->firstSym[codeBits] + code];
+ }
+ } while (codeBits < 16);
+
+ error(getPos(), "Bad Huffman code in DCT stream");
+ return 9999;
+}
+
+int DCTStream::readAmp(int size) {
+ int amp, bit;
+ int bits;
+
+ amp = 0;
+ for (bits = 0; bits < size; ++bits) {
+ if ((bit = readBit()) == EOF)
+ return 9999;
+ amp = (amp << 1) + bit;
+ }
+ if (amp < (1 << (size - 1)))
+ amp -= (1 << size) - 1;
+ return amp;
+}
+
+int DCTStream::readBit() {
+ int bit;
+ int c, c2;
+
+ if (inputBits == 0) {
+ if ((c = str->getChar()) == EOF)
+ return EOF;
+ if (c == 0xff) {
+ do {
+ c2 = str->getChar();
+ } while (c2 == 0xff);
+ if (c2 != 0x00) {
+ error(getPos(), "Bad DCT data: missing 00 after ff");
+ return EOF;
+ }
+ }
+ inputBuf = c;
+ inputBits = 8;
+ }
+ bit = (inputBuf >> (inputBits - 1)) & 1;
+ --inputBits;
+ return bit;
+}
+
+GBool DCTStream::readHeader() {
+ GBool doScan;
+ int minHSample, minVSample;
+ int bufWidth;
+ int n;
+ int c = 0;
+ int i, j;
+
+ width = height = 0;
+ numComps = 0;
+ numQuantTables = 0;
+ numDCHuffTables = 0;
+ numACHuffTables = 0;
+ colorXform = 0;
+ gotAdobeMarker = gFalse;
+ restartInterval = 0;
+
+ // read headers
+ doScan = gFalse;
+ while (!doScan) {
+ c = readMarker();
+ switch (c) {
+ case 0xc0: // SOF0
+ if (!readFrameInfo())
+ return gFalse;
+ break;
+ case 0xc4: // DHT
+ if (!readHuffmanTables())
+ return gFalse;
+ break;
+ case 0xd8: // SOI
+ break;
+ case 0xda: // SOS
+ if (!readScanInfo())
+ return gFalse;
+ doScan = gTrue;
+ break;
+ case 0xdb: // DQT
+ if (!readQuantTables())
+ return gFalse;
+ break;
+ case 0xdd: // DRI
+ if (!readRestartInterval())
+ return gFalse;
+ break;
+ case 0xee: // APP14
+ if (!readAdobeMarker())
+ return gFalse;
+ break;
+ case EOF:
+ error(getPos(), "Bad DCT header");
+ return gFalse;
+ default:
+ // skip APPn / COM / etc.
+ if (c >= 0xe0) {
+ n = read16() - 2;
+ for (i = 0; i < n; ++i)
+ str->getChar();
+ } else {
+ error(getPos(), "Unknown DCT marker <%02x>", c);
+ return gFalse;
+ }
+ break;
+ }
+ }
+
+ // compute MCU size
+ mcuWidth = minHSample = compInfo[0].hSample;
+ mcuHeight = minVSample = compInfo[0].vSample;
+ for (i = 1; i < numComps; ++i) {
+ if (compInfo[i].hSample < minHSample)
+ minHSample = compInfo[i].hSample;
+ if (compInfo[i].vSample < minVSample)
+ minVSample = compInfo[i].vSample;
+ if (compInfo[i].hSample > mcuWidth)
+ mcuWidth = compInfo[i].hSample;
+ if (compInfo[i].vSample > mcuHeight)
+ mcuHeight = compInfo[i].vSample;
+ }
+ for (i = 0; i < numComps; ++i) {
+ compInfo[i].hSample /= minHSample;
+ compInfo[i].vSample /= minVSample;
+ }
+ mcuWidth = (mcuWidth / minHSample) * 8;
+ mcuHeight = (mcuHeight / minVSample) * 8;
+
+ // allocate buffers
+ bufWidth = ((width + mcuWidth - 1) / mcuWidth) * mcuWidth;
+ for (i = 0; i < numComps; ++i)
+ for (j = 0; j < mcuHeight; ++j)
+ rowBuf[i][j] = (Guchar *)gmalloc(bufWidth * sizeof(Guchar));
+
+ // figure out color transform
+ if (!gotAdobeMarker && numComps == 3) {
+ if (compInfo[0].id == 1 && compInfo[1].id == 2 && compInfo[2].id == 3) {
+ colorXform = 1;
+ }
+ }
+
+ // initialize counters
+ comp = 0;
+ x = 0;
+ y = 0;
+ dy = mcuHeight;
+
+ return gTrue;
+}
+
+GBool DCTStream::readFrameInfo() {
+ int length;
+ int prec;
+ int i;
+ int c;
+
+ length = read16() - 2;
+ prec = str->getChar();
+ height = read16();
+ width = read16();
+ numComps = str->getChar();
+ length -= 6;
+ if (prec != 8) {
+ error(getPos(), "Bad DCT precision %d", prec);
+ return gFalse;
+ }
+ for (i = 0; i < numComps; ++i) {
+ compInfo[i].id = str->getChar();
+ compInfo[i].inScan = gFalse;
+ c = str->getChar();
+ compInfo[i].hSample = (c >> 4) & 0x0f;
+ compInfo[i].vSample = c & 0x0f;
+ compInfo[i].quantTable = str->getChar();
+ compInfo[i].dcHuffTable = 0;
+ compInfo[i].acHuffTable = 0;
+ }
+ return gTrue;
+}
+
+GBool DCTStream::readScanInfo() {
+ int length;
+ int scanComps, id, c;
+ int i, j;
+
+ length = read16() - 2;
+ scanComps = str->getChar();
+ --length;
+ if (length != 2 * scanComps + 3) {
+ error(getPos(), "Bad DCT scan info block");
+ return gFalse;
+ }
+ for (i = 0; i < scanComps; ++i) {
+ id = str->getChar();
+ for (j = 0; j < numComps; ++j) {
+ if (id == compInfo[j].id)
+ break;
+ }
+ if (j == numComps) {
+ error(getPos(), "Bad DCT component ID in scan info block");
+ return gFalse;
+ }
+ compInfo[j].inScan = gTrue;
+ c = str->getChar();
+ compInfo[j].dcHuffTable = (c >> 4) & 0x0f;
+ compInfo[j].acHuffTable = c & 0x0f;
+ }
+ str->getChar();
+ str->getChar();
+ str->getChar();
+ return gTrue;
+}
+
+GBool DCTStream::readQuantTables() {
+ int length;
+ int i;
+ int index;
+
+ length = read16() - 2;
+ while (length > 0) {
+ index = str->getChar();
+ if ((index & 0xf0) || index >= 4) {
+ error(getPos(), "Bad DCT quantization table");
+ return gFalse;
+ }
+ if (index == numQuantTables)
+ numQuantTables = index + 1;
+ for (i = 0; i < 64; ++i)
+ quantTables[index][dctZigZag[i]] = str->getChar();
+ length -= 65;
+ }
+ return gTrue;
+}
+
+GBool DCTStream::readHuffmanTables() {
+ DCTHuffTable *tbl;
+ int length;
+ int index;
+ Gushort code;
+ Guchar sym;
+ int i;
+ int c;
+
+ length = read16() - 2;
+ while (length > 0) {
+ index = str->getChar();
+ --length;
+ if ((index & 0x0f) >= 4) {
+ error(getPos(), "Bad DCT Huffman table");
+ return gFalse;
+ }
+ if (index & 0x10) {
+ index &= 0x0f;
+ if (index >= numACHuffTables)
+ numACHuffTables = index+1;
+ tbl = &acHuffTables[index];
+ } else {
+ if (index >= numDCHuffTables)
+ numDCHuffTables = index+1;
+ tbl = &dcHuffTables[index];
+ }
+ sym = 0;
+ code = 0;
+ for (i = 1; i <= 16; ++i) {
+ c = str->getChar();
+ tbl->firstSym[i] = sym;
+ tbl->firstCode[i] = code;
+ tbl->numCodes[i] = c;
+ sym += c;
+ code = (code + c) << 1;
+ }
+ length -= 16;
+ for (i = 0; i < sym; ++i)
+ tbl->sym[i] = str->getChar();
+ length -= sym;
+ }
+ return gTrue;
+}
+
+GBool DCTStream::readRestartInterval() {
+ int length;
+
+ length = read16();
+ if (length != 4) {
+ error(getPos(), "Bad DCT restart interval");
+ return gFalse;
+ }
+ restartInterval = read16();
+ return gTrue;
+}
+
+GBool DCTStream::readAdobeMarker() {
+ int length, i;
+ char buf[12];
+ int c;
+
+ length = read16();
+ if (length != 14)
+ goto err;
+ for (i = 0; i < 12; ++i) {
+ if ((c = str->getChar()) == EOF)
+ goto err;
+ buf[i] = c;
+ }
+ if (strncmp(buf, "Adobe", 5))
+ goto err;
+ colorXform = buf[11];
+ gotAdobeMarker = gTrue;
+ return gTrue;
+
+ err:
+ error(getPos(), "Bad DCT Adobe APP14 marker");
+ return gFalse;
+}
+
+GBool DCTStream::readTrailer() {
+ int c;
+
+ c = readMarker();
+ if (c != 0xd9) { // EOI
+ error(getPos(), "Bad DCT trailer");
+ return gFalse;
+ }
+ return gTrue;
+}
+
+int DCTStream::readMarker() {
+ int c;
+
+ do {
+ do {
+ c = str->getChar();
+ } while (c != 0xff);
+ do {
+ c = str->getChar();
+ } while (c == 0xff);
+ } while (c == 0x00);
+ return c;
+}
+
+int DCTStream::read16() {
+ int c1, c2;
+
+ if ((c1 = str->getChar()) == EOF)
+ return EOF;
+ if ((c2 = str->getChar()) == EOF)
+ return EOF;
+ return (c1 << 8) + c2;
+}
+
+GString *DCTStream::getPSFilter(char *indent) {
+ GString *s;
+
+ if (!(s = str->getPSFilter(indent))) {
+ return NULL;
+ }
+ s->append(indent)->append("<< >> /DCTDecode filter\n");
+ return s;
+}
+
+GBool DCTStream::isBinary(GBool last) {
+ return str->isBinary(gTrue);
+}
+
+//------------------------------------------------------------------------
+// FlateStream
+//------------------------------------------------------------------------
+
+int FlateStream::codeLenCodeMap[flateMaxCodeLenCodes] = {
+ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
+};
+
+FlateDecode FlateStream::lengthDecode[flateMaxLitCodes-257] = {
+ {0, 3},
+ {0, 4},
+ {0, 5},
+ {0, 6},
+ {0, 7},
+ {0, 8},
+ {0, 9},
+ {0, 10},
+ {1, 11},
+ {1, 13},
+ {1, 15},
+ {1, 17},
+ {2, 19},
+ {2, 23},
+ {2, 27},
+ {2, 31},
+ {3, 35},
+ {3, 43},
+ {3, 51},
+ {3, 59},
+ {4, 67},
+ {4, 83},
+ {4, 99},
+ {4, 115},
+ {5, 131},
+ {5, 163},
+ {5, 195},
+ {5, 227},
+ {0, 258}
+};
+
+FlateDecode FlateStream::distDecode[flateMaxDistCodes] = {
+ { 0, 1},
+ { 0, 2},
+ { 0, 3},
+ { 0, 4},
+ { 1, 5},
+ { 1, 7},
+ { 2, 9},
+ { 2, 13},
+ { 3, 17},
+ { 3, 25},
+ { 4, 33},
+ { 4, 49},
+ { 5, 65},
+ { 5, 97},
+ { 6, 129},
+ { 6, 193},
+ { 7, 257},
+ { 7, 385},
+ { 8, 513},
+ { 8, 769},
+ { 9, 1025},
+ { 9, 1537},
+ {10, 2049},
+ {10, 3073},
+ {11, 4097},
+ {11, 6145},
+ {12, 8193},
+ {12, 12289},
+ {13, 16385},
+ {13, 24577}
+};
+
+FlateStream::FlateStream(Stream *strA, int predictor, int columns,
+ int colors, int bits):
+ FilterStream(strA) {
+ if (predictor != 1) {
+ pred = new StreamPredictor(this, predictor, columns, colors, bits);
+ } else {
+ pred = NULL;
+ }
+}
+
+FlateStream::~FlateStream() {
+ if (pred) {
+ delete pred;
+ }
+ delete str;
+}
+
+void FlateStream::reset() {
+ int cmf, flg;
+
+ index = 0;
+ remain = 0;
+ codeBuf = 0;
+ codeSize = 0;
+ compressedBlock = gFalse;
+ endOfBlock = gTrue;
+ eof = gTrue;
+
+ str->reset();
+
+ // read header
+ //~ need to look at window size?
+ endOfBlock = eof = gTrue;
+ cmf = str->getChar();
+ flg = str->getChar();
+ if (cmf == EOF || flg == EOF)
+ return;
+ if ((cmf & 0x0f) != 0x08) {
+ error(getPos(), "Unknown compression method in flate stream");
+ return;
+ }
+ if ((((cmf << 8) + flg) % 31) != 0) {
+ error(getPos(), "Bad FCHECK in flate stream");
+ return;
+ }
+ if (flg & 0x20) {
+ error(getPos(), "FDICT bit set in flate stream");
+ return;
+ }
+
+ eof = gFalse;
+}
+
+int FlateStream::getChar() {
+ int c;
+
+ if (pred) {
+ return pred->getChar();
+ }
+ while (remain == 0) {
+ if (endOfBlock && eof)
+ return EOF;
+ readSome();
+ }
+ c = buf[index];
+ index = (index + 1) & flateMask;
+ --remain;
+ return c;
+}
+
+int FlateStream::lookChar() {
+ int c;
+
+ if (pred) {
+ return pred->lookChar();
+ }
+ while (remain == 0) {
+ if (endOfBlock && eof)
+ return EOF;
+ readSome();
+ }
+ c = buf[index];
+ return c;
+}
+
+int FlateStream::getRawChar() {
+ int c;
+
+ while (remain == 0) {
+ if (endOfBlock && eof)
+ return EOF;
+ readSome();
+ }
+ c = buf[index];
+ index = (index + 1) & flateMask;
+ --remain;
+ return c;
+}
+
+GString *FlateStream::getPSFilter(char *indent) {
+ return NULL;
+}
+
+GBool FlateStream::isBinary(GBool last) {
+ return str->isBinary(gTrue);
+}
+
+void FlateStream::readSome() {
+ int code1, code2;
+ int len, dist;
+ int i, j, k;
+ int c;
+
+ if (endOfBlock) {
+ if (!startBlock())
+ return;
+ }
+
+ if (compressedBlock) {
+ if ((code1 = getHuffmanCodeWord(&litCodeTab)) == EOF)
+ goto err;
+ if (code1 < 256) {
+ buf[index] = code1;
+ remain = 1;
+ } else if (code1 == 256) {
+ endOfBlock = gTrue;
+ remain = 0;
+ } else {
+ code1 -= 257;
+ code2 = lengthDecode[code1].bits;
+ if (code2 > 0 && (code2 = getCodeWord(code2)) == EOF)
+ goto err;
+ len = lengthDecode[code1].first + code2;
+ if ((code1 = getHuffmanCodeWord(&distCodeTab)) == EOF)
+ goto err;
+ code2 = distDecode[code1].bits;
+ if (code2 > 0 && (code2 = getCodeWord(code2)) == EOF)
+ goto err;
+ dist = distDecode[code1].first + code2;
+ i = index;
+ j = (index - dist) & flateMask;
+ for (k = 0; k < len; ++k) {
+ buf[i] = buf[j];
+ i = (i + 1) & flateMask;
+ j = (j + 1) & flateMask;
+ }
+ remain = len;
+ }
+
+ } else {
+ len = (blockLen < flateWindow) ? blockLen : flateWindow;
+ for (i = 0, j = index; i < len; ++i, j = (j + 1) & flateMask) {
+ if ((c = str->getChar()) == EOF) {
+ endOfBlock = eof = gTrue;
+ break;
+ }
+ buf[j] = c & 0xff;
+ }
+ remain = i;
+ blockLen -= len;
+ if (blockLen == 0)
+ endOfBlock = gTrue;
+ }
+
+ return;
+
+err:
+ error(getPos(), "Unexpected end of file in flate stream");
+ endOfBlock = eof = gTrue;
+ remain = 0;
+}
+
+GBool FlateStream::startBlock() {
+ int blockHdr;
+ int c;
+ int check;
+
+ // read block header
+ blockHdr = getCodeWord(3);
+ if (blockHdr & 1)
+ eof = gTrue;
+ blockHdr >>= 1;
+
+ // uncompressed block
+ if (blockHdr == 0) {
+ compressedBlock = gFalse;
+ if ((c = str->getChar()) == EOF)
+ goto err;
+ blockLen = c & 0xff;
+ if ((c = str->getChar()) == EOF)
+ goto err;
+ blockLen |= (c & 0xff) << 8;
+ if ((c = str->getChar()) == EOF)
+ goto err;
+ check = c & 0xff;
+ if ((c = str->getChar()) == EOF)
+ goto err;
+ check |= (c & 0xff) << 8;
+ if (check != (~blockLen & 0xffff))
+ error(getPos(), "Bad uncompressed block length in flate stream");
+ codeBuf = 0;
+ codeSize = 0;
+
+ // compressed block with fixed codes
+ } else if (blockHdr == 1) {
+ compressedBlock = gTrue;
+ loadFixedCodes();
+
+ // compressed block with dynamic codes
+ } else if (blockHdr == 2) {
+ compressedBlock = gTrue;
+ if (!readDynamicCodes())
+ goto err;
+
+ // unknown block type
+ } else {
+ goto err;
+ }
+
+ endOfBlock = gFalse;
+ return gTrue;
+
+err:
+ error(getPos(), "Bad block header in flate stream");
+ endOfBlock = eof = gTrue;
+ return gFalse;
+}
+
+void FlateStream::loadFixedCodes() {
+ int i;
+
+ // set up code arrays
+ litCodeTab.codes = allCodes;
+ distCodeTab.codes = allCodes + flateMaxLitCodes;
+
+ // initialize literal code table
+ for (i = 0; i <= 143; ++i)
+ litCodeTab.codes[i].len = 8;
+ for (i = 144; i <= 255; ++i)
+ litCodeTab.codes[i].len = 9;
+ for (i = 256; i <= 279; ++i)
+ litCodeTab.codes[i].len = 7;
+ for (i = 280; i <= 287; ++i)
+ litCodeTab.codes[i].len = 8;
+ compHuffmanCodes(&litCodeTab, flateMaxLitCodes);
+
+ // initialize distance code table
+ for (i = 0; i <= 5; ++i) {
+ distCodeTab.start[i] = 0;
+ }
+ for (i = 6; i <= flateMaxHuffman+1; ++i) {
+ distCodeTab.start[i] = flateMaxDistCodes;
+ }
+ for (i = 0; i < flateMaxDistCodes; ++i) {
+ distCodeTab.codes[i].len = 5;
+ distCodeTab.codes[i].code = i;
+ distCodeTab.codes[i].val = i;
+ }
+}
+
+GBool FlateStream::readDynamicCodes() {
+ int numCodeLenCodes;
+ int numLitCodes;
+ int numDistCodes;
+ FlateCode codeLenCodes[flateMaxCodeLenCodes];
+ FlateHuffmanTab codeLenCodeTab;
+ int len, repeat, code;
+ int i;
+
+ // read lengths
+ if ((numLitCodes = getCodeWord(5)) == EOF)
+ goto err;
+ numLitCodes += 257;
+ if ((numDistCodes = getCodeWord(5)) == EOF)
+ goto err;
+ numDistCodes += 1;
+ if ((numCodeLenCodes = getCodeWord(4)) == EOF)
+ goto err;
+ numCodeLenCodes += 4;
+ if (numLitCodes > flateMaxLitCodes ||
+ numDistCodes > flateMaxDistCodes ||
+ numCodeLenCodes > flateMaxCodeLenCodes)
+ goto err;
+
+ // read code length code table
+ codeLenCodeTab.codes = codeLenCodes;
+ for (i = 0; i < flateMaxCodeLenCodes; ++i)
+ codeLenCodes[i].len = 0;
+ for (i = 0; i < numCodeLenCodes; ++i) {
+ if ((codeLenCodes[codeLenCodeMap[i]].len = getCodeWord(3)) == -1)
+ goto err;
+ }
+ compHuffmanCodes(&codeLenCodeTab, flateMaxCodeLenCodes);
+
+ // set up code arrays
+ litCodeTab.codes = allCodes;
+ distCodeTab.codes = allCodes + numLitCodes;
+
+ // read literal and distance code tables
+ len = 0;
+ repeat = 0;
+ i = 0;
+ while (i < numLitCodes + numDistCodes) {
+ if ((code = getHuffmanCodeWord(&codeLenCodeTab)) == EOF)
+ goto err;
+ if (code == 16) {
+ if ((repeat = getCodeWord(2)) == EOF)
+ goto err;
+ for (repeat += 3; repeat > 0; --repeat)
+ allCodes[i++].len = len;
+ } else if (code == 17) {
+ if ((repeat = getCodeWord(3)) == EOF)
+ goto err;
+ len = 0;
+ for (repeat += 3; repeat > 0; --repeat)
+ allCodes[i++].len = 0;
+ } else if (code == 18) {
+ if ((repeat = getCodeWord(7)) == EOF)
+ goto err;
+ len = 0;
+ for (repeat += 11; repeat > 0; --repeat)
+ allCodes[i++].len = 0;
+ } else {
+ allCodes[i++].len = len = code;
+ }
+ }
+ compHuffmanCodes(&litCodeTab, numLitCodes);
+ compHuffmanCodes(&distCodeTab, numDistCodes);
+
+ return gTrue;
+
+err:
+ error(getPos(), "Bad dynamic code table in flate stream");
+ return gFalse;
+}
+
+// On entry, the <tab->codes> array contains the lengths of each code,
+// stored in code value order. This function computes the code words.
+// The result is sorted in order of (1) code length and (2) code word.
+// The length values are no longer valid. The <tab->start> array is
+// filled with the indexes of the first code of each length.
+void FlateStream::compHuffmanCodes(FlateHuffmanTab *tab, int n) {
+ int numLengths[flateMaxHuffman+1];
+ int nextCode[flateMaxHuffman+1];
+ int nextIndex[flateMaxHuffman+2];
+ int code;
+ int i, j;
+
+ // count number of codes for each code length
+ for (i = 0; i <= flateMaxHuffman; ++i)
+ numLengths[i] = 0;
+ for (i = 0; i < n; ++i)
+ ++numLengths[tab->codes[i].len];
+
+ // compute first index for each length
+ tab->start[0] = nextIndex[0] = 0;
+ for (i = 1; i <= flateMaxHuffman + 1; ++i)
+ tab->start[i] = nextIndex[i] = tab->start[i-1] + numLengths[i-1];
+
+ // compute first code for each length
+ code = 0;
+ numLengths[0] = 0;
+ for (i = 1; i <= flateMaxHuffman; ++i) {
+ code = (code + numLengths[i-1]) << 1;
+ nextCode[i] = code;
+ }
+
+ // compute the codes -- this permutes the codes array from value
+ // order to length/code order
+ for (i = 0; i < n; ++i) {
+ j = nextIndex[tab->codes[i].len]++;
+ if (tab->codes[i].len == 0)
+ tab->codes[j].code = 0;
+ else
+ tab->codes[j].code = nextCode[tab->codes[i].len]++;
+ tab->codes[j].val = i;
+ }
+}
+
+int FlateStream::getHuffmanCodeWord(FlateHuffmanTab *tab) {
+ int len;
+ int code;
+ int c;
+ int i, j;
+
+ code = 0;
+ for (len = 1; len <= flateMaxHuffman; ++len) {
+
+ // add a bit to the code
+ if (codeSize == 0) {
+ if ((c = str->getChar()) == EOF)
+ return EOF;
+ codeBuf = c & 0xff;
+ codeSize = 8;
+ }
+ code = (code << 1) | (codeBuf & 1);
+ codeBuf >>= 1;
+ --codeSize;
+
+ // look for code
+ i = tab->start[len];
+ j = tab->start[len + 1];
+ if (i < j && code >= tab->codes[i].code && code <= tab->codes[j-1].code) {
+ i += code - tab->codes[i].code;
+ return tab->codes[i].val;
+ }
+ }
+
+ // not found
+ error(getPos(), "Bad code (%04x) in flate stream", code);
+ return EOF;
+}
+
+int FlateStream::getCodeWord(int bits) {
+ int c;
+
+ while (codeSize < bits) {
+ if ((c = str->getChar()) == EOF)
+ return EOF;
+ codeBuf |= (c & 0xff) << codeSize;
+ codeSize += 8;
+ }
+ c = codeBuf & ((1 << bits) - 1);
+ codeBuf >>= bits;
+ codeSize -= bits;
+ return c;
+}
+
+//------------------------------------------------------------------------
+// EOFStream
+//------------------------------------------------------------------------
+
+EOFStream::EOFStream(Stream *strA):
+ FilterStream(strA) {
+}
+
+EOFStream::~EOFStream() {
+ delete str;
+}
+
+//------------------------------------------------------------------------
+// FixedLengthEncoder
+//------------------------------------------------------------------------
+
+FixedLengthEncoder::FixedLengthEncoder(Stream *strA, int lengthA):
+ FilterStream(strA) {
+ length = lengthA;
+ count = 0;
+}
+
+FixedLengthEncoder::~FixedLengthEncoder() {
+ if (str->isEncoder())
+ delete str;
+}
+
+void FixedLengthEncoder::reset() {
+ str->reset();
+ count = 0;
+}
+
+void FixedLengthEncoder::close() {
+}
+
+int FixedLengthEncoder::getChar() {
+ if (length >= 0 && count >= length)
+ return EOF;
+ ++count;
+ return str->getChar();
+}
+
+int FixedLengthEncoder::lookChar() {
+ if (length >= 0 && count >= length)
+ return EOF;
+ return str->getChar();
+}
+
+//------------------------------------------------------------------------
+// ASCII85Encoder
+//------------------------------------------------------------------------
+
+ASCII85Encoder::ASCII85Encoder(Stream *strA):
+ FilterStream(strA) {
+ bufPtr = bufEnd = buf;
+ lineLen = 0;
+ eof = gFalse;
+}
+
+ASCII85Encoder::~ASCII85Encoder() {
+ if (str->isEncoder())
+ delete str;
+}
+
+void ASCII85Encoder::reset() {
+ str->reset();
+ bufPtr = bufEnd = buf;
+ lineLen = 0;
+ eof = gFalse;
+}
+
+void ASCII85Encoder::close() {
+}
+
+GBool ASCII85Encoder::fillBuf() {
+ Gulong t;
+ char buf1[5];
+ int c;
+ int n, i;
+
+ if (eof)
+ return gFalse;
+ t = 0;
+ for (n = 0; n < 4; ++n) {
+ if ((c = str->getChar()) == EOF)
+ break;
+ t = (t << 8) + c;
+ }
+ bufPtr = bufEnd = buf;
+ if (n > 0) {
+ if (n == 4 && t == 0) {
+ *bufEnd++ = 'z';
+ if (++lineLen == 65) {
+ *bufEnd++ = '\n';
+ lineLen = 0;
+ }
+ } else {
+ if (n < 4)
+ t <<= 8 * (4 - n);
+ for (i = 4; i >= 0; --i) {
+ buf1[i] = (char)(t % 85 + 0x21);
+ t /= 85;
+ }
+ for (i = 0; i <= n; ++i) {
+ *bufEnd++ = buf1[i];
+ if (++lineLen == 65) {
+ *bufEnd++ = '\n';
+ lineLen = 0;
+ }
+ }
+ }
+ }
+ if (n < 4) {
+ *bufEnd++ = '~';
+ *bufEnd++ = '>';
+ eof = gTrue;
+ }
+ return bufPtr < bufEnd;
+}
+
+//------------------------------------------------------------------------
+// RunLengthEncoder
+//------------------------------------------------------------------------
+
+RunLengthEncoder::RunLengthEncoder(Stream *strA):
+ FilterStream(strA) {
+ bufPtr = bufEnd = nextEnd = buf;
+ eof = gFalse;
+}
+
+RunLengthEncoder::~RunLengthEncoder() {
+ if (str->isEncoder())
+ delete str;
+}
+
+void RunLengthEncoder::reset() {
+ str->reset();
+ bufPtr = bufEnd = nextEnd = buf;
+ eof = gFalse;
+}
+
+void RunLengthEncoder::close() {
+}
+
+//
+// When fillBuf finishes, buf[] looks like this:
+// +-----+--------------+-----------------+--
+// + tag | ... data ... | next 0, 1, or 2 |
+// +-----+--------------+-----------------+--
+// ^ ^ ^
+// bufPtr bufEnd nextEnd
+//
+GBool RunLengthEncoder::fillBuf() {
+ int c, c1, c2;
+ int n;
+
+ // already hit EOF?
+ if (eof)
+ return gFalse;
+
+ // grab two bytes
+ if (nextEnd < bufEnd + 1) {
+ if ((c1 = str->getChar()) == EOF) {
+ eof = gTrue;
+ return gFalse;
+ }
+ } else {
+ c1 = bufEnd[0] & 0xff;
+ }
+ if (nextEnd < bufEnd + 2) {
+ if ((c2 = str->getChar()) == EOF) {
+ eof = gTrue;
+ buf[0] = 0;
+ buf[1] = c1;
+ bufPtr = buf;
+ bufEnd = &buf[2];
+ return gTrue;
+ }
+ } else {
+ c2 = bufEnd[1] & 0xff;
+ }
+
+ // check for repeat
+ c = 0; // make gcc happy
+ if (c1 == c2) {
+ n = 2;
+ while (n < 128 && (c = str->getChar()) == c1)
+ ++n;
+ buf[0] = (char)(257 - n);
+ buf[1] = c1;
+ bufEnd = &buf[2];
+ if (c == EOF) {
+ eof = gTrue;
+ } else if (n < 128) {
+ buf[2] = c;
+ nextEnd = &buf[3];
+ } else {
+ nextEnd = bufEnd;
+ }
+
+ // get up to 128 chars
+ } else {
+ buf[1] = c1;
+ buf[2] = c2;
+ n = 2;
+ while (n < 128) {
+ if ((c = str->getChar()) == EOF) {
+ eof = gTrue;
+ break;
+ }
+ ++n;
+ buf[n] = c;
+ if (buf[n] == buf[n-1])
+ break;
+ }
+ if (buf[n] == buf[n-1]) {
+ buf[0] = (char)(n-2-1);
+ bufEnd = &buf[n-1];
+ nextEnd = &buf[n+1];
+ } else {
+ buf[0] = (char)(n-1);
+ bufEnd = nextEnd = &buf[n+1];
+ }
+ }
+ bufPtr = buf;
+ return gTrue;
+}
diff --git a/pdftops/Stream.h b/pdftops/Stream.h
new file mode 100644
index 000000000..1f9c561d1
--- /dev/null
+++ b/pdftops/Stream.h
@@ -0,0 +1,723 @@
+//========================================================================
+//
+// Stream.h
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifndef STREAM_H
+#define STREAM_H
+
+#ifdef __GNUC__
+#pragma interface
+#endif
+
+#include <stdio.h>
+#include "gtypes.h"
+#include "Object.h"
+
+#ifndef NO_DECRYPTION
+class Decrypt;
+#endif
+class BaseStream;
+
+//------------------------------------------------------------------------
+
+enum StreamKind {
+ strFile,
+ strASCIIHex,
+ strASCII85,
+ strLZW,
+ strRunLength,
+ strCCITTFax,
+ strDCT,
+ strFlate,
+ strWeird // internal-use stream types
+};
+
+//------------------------------------------------------------------------
+// Stream (base class)
+//------------------------------------------------------------------------
+
+class Stream {
+public:
+
+ // Constructor.
+ Stream();
+
+ // Destructor.
+ virtual ~Stream();
+
+ // Reference counting.
+ int incRef() { return ++ref; }
+ int decRef() { return --ref; }
+
+ // Get kind of stream.
+ virtual StreamKind getKind() = 0;
+
+ // Reset stream to beginning.
+ virtual void reset() = 0;
+
+ // Close down the stream.
+ virtual void close();
+
+ // Get next char from stream.
+ virtual int getChar() = 0;
+
+ // Peek at next char in stream.
+ virtual int lookChar() = 0;
+
+ // Get next char from stream without using the predictor.
+ // This is only used by StreamPredictor.
+ virtual int getRawChar();
+
+ // Get next line from stream.
+ virtual char *getLine(char *buf, int size);
+
+ // Get current position in file.
+ virtual int getPos() = 0;
+
+ // Go to a position in the stream.
+ virtual void setPos(int pos) = 0;
+
+ // Get PostScript command for the filter(s).
+ virtual GString *getPSFilter(char *indent);
+
+ // Does this stream type potentially contain non-printable chars?
+ virtual GBool isBinary(GBool last = gTrue) = 0;
+
+ // Get the BaseStream or EmbedStream of this stream.
+ virtual BaseStream *getBaseStream() = 0;
+
+ // Get the dictionary associated with this stream.
+ virtual Dict *getDict() = 0;
+
+ // Is this an encoding filter?
+ virtual GBool isEncoder() { return gFalse; }
+
+ // Add filters to this stream according to the parameters in <dict>.
+ // Returns the new stream.
+ Stream *addFilters(Object *dict);
+
+private:
+
+ Stream *makeFilter(char *name, Stream *str, Object *params);
+
+ int ref; // reference count
+};
+
+//------------------------------------------------------------------------
+// BaseStream
+//
+// This is the base class for all streams that read directly from a file.
+//------------------------------------------------------------------------
+
+class BaseStream: public Stream {
+public:
+
+ BaseStream(Object *dictA);
+ virtual ~BaseStream();
+ virtual Stream *makeSubStream(int start, int length, Object *dict) = 0;
+ virtual void setPos(int pos) = 0;
+ virtual BaseStream *getBaseStream() { return this; }
+ virtual Dict *getDict() { return dict.getDict(); }
+
+ // Get/set position of first byte of stream within the file.
+ virtual int getStart() = 0;
+ virtual void moveStart(int delta) = 0;
+
+#ifndef NO_DECRYPTION
+ // Set decryption for this stream.
+ void doDecryption(Guchar *fileKey, int keyLength, int objNum, int objGen);
+#endif
+
+#ifndef NO_DECRYPTION
+protected:
+
+ Decrypt *decrypt;
+#endif
+
+private:
+
+ Object dict;
+};
+
+//------------------------------------------------------------------------
+// FilterStream
+//
+// This is the base class for all streams that filter another stream.
+//------------------------------------------------------------------------
+
+class FilterStream: public Stream {
+public:
+
+ FilterStream(Stream *strA);
+ virtual ~FilterStream();
+ virtual void close();
+ virtual int getPos() { return str->getPos(); }
+ virtual void setPos(int pos);
+ virtual BaseStream *getBaseStream() { return str->getBaseStream(); }
+ virtual Dict *getDict() { return str->getDict(); }
+
+protected:
+
+ Stream *str;
+};
+
+//------------------------------------------------------------------------
+// ImageStream
+//------------------------------------------------------------------------
+
+class ImageStream {
+public:
+
+ // Create an image stream object for an image with the specified
+ // parameters. Note that these are the actual image parameters,
+ // which may be different from the predictor parameters.
+ ImageStream(Stream *strA, int widthA, int nCompsA, int nBitsA);
+
+ ~ImageStream();
+
+ // Reset the stream.
+ void reset();
+
+ // Gets the next pixel from the stream. <pix> should be able to hold
+ // at least nComps elements. Returns false at end of file.
+ GBool getPixel(Guchar *pix);
+
+ // Skip an entire line from the image.
+ void skipLine();
+
+private:
+
+ Stream *str; // base stream
+ int width; // pixels per line
+ int nComps; // components per pixel
+ int nBits; // bits per component
+ int nVals; // components per line
+ Guchar *imgLine; // line buffer
+ int imgIdx; // current index in imgLine
+};
+
+//------------------------------------------------------------------------
+// StreamPredictor
+//------------------------------------------------------------------------
+
+class StreamPredictor {
+public:
+
+ // Create a predictor object. Note that the parameters are for the
+ // predictor, and may not match the actual image parameters.
+ StreamPredictor(Stream *strA, int predictorA,
+ int widthA, int nCompsA, int nBitsA);
+
+ ~StreamPredictor();
+
+ int lookChar();
+ int getChar();
+
+private:
+
+ GBool getNextLine();
+
+ Stream *str; // base stream
+ int predictor; // predictor
+ int width; // pixels per line
+ int nComps; // components per pixel
+ int nBits; // bits per component
+ int nVals; // components per line
+ int pixBytes; // bytes per pixel
+ int rowBytes; // bytes per line
+ Guchar *predLine; // line buffer
+ int predIdx; // current index in predLine
+};
+
+//------------------------------------------------------------------------
+// FileStream
+//------------------------------------------------------------------------
+
+#define fileStreamBufSize 256
+
+class FileStream: public BaseStream {
+public:
+
+ FileStream(FILE *fA, int startA, int lengthA, Object *dictA);
+ virtual ~FileStream();
+ virtual Stream *makeSubStream(int startA, int lengthA, Object *dictA);
+ virtual StreamKind getKind() { return strFile; }
+ virtual void reset();
+ virtual void close();
+ virtual int getChar()
+ { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); }
+ virtual int lookChar()
+ { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); }
+ virtual int getPos() { return bufPos + (bufPtr - buf); }
+ virtual void setPos(int pos);
+ virtual GBool isBinary(GBool last = gTrue) { return last; }
+ virtual int getStart() { return start; }
+ virtual void moveStart(int delta);
+
+private:
+
+ GBool fillBuf();
+
+ FILE *f;
+ int start;
+ int length;
+ char buf[fileStreamBufSize];
+ char *bufPtr;
+ char *bufEnd;
+ int bufPos;
+ int savePos;
+};
+
+//------------------------------------------------------------------------
+// EmbedStream
+//
+// This is a special stream type used for embedded streams (inline
+// images). It reads directly from the base stream -- after the
+// EmbedStream is deleted, reads from the base stream will proceed where
+// the BaseStream left off. Note that this is very different behavior
+// that creating a new FileStream (using makeSubStream).
+//------------------------------------------------------------------------
+
+class EmbedStream: public BaseStream {
+public:
+
+ EmbedStream(Stream *strA, Object *dictA);
+ virtual ~EmbedStream();
+ virtual Stream *makeSubStream(int start, int length, Object *dictA);
+ virtual StreamKind getKind() { return str->getKind(); }
+ virtual void reset() {}
+ virtual int getChar() { return str->getChar(); }
+ virtual int lookChar() { return str->lookChar(); }
+ virtual int getPos() { return str->getPos(); }
+ virtual void setPos(int pos);
+ virtual GBool isBinary(GBool last = gTrue) { return last; }
+ virtual int getStart();
+ virtual void moveStart(int delta);
+
+private:
+
+ Stream *str;
+};
+
+//------------------------------------------------------------------------
+// ASCIIHexStream
+//------------------------------------------------------------------------
+
+class ASCIIHexStream: public FilterStream {
+public:
+
+ ASCIIHexStream(Stream *strA);
+ virtual ~ASCIIHexStream();
+ virtual StreamKind getKind() { return strASCIIHex; }
+ virtual void reset();
+ virtual int getChar()
+ { int c = lookChar(); buf = EOF; return c; }
+ virtual int lookChar();
+ virtual GString *getPSFilter(char *indent);
+ virtual GBool isBinary(GBool last = gTrue);
+
+private:
+
+ int buf;
+ GBool eof;
+};
+
+//------------------------------------------------------------------------
+// ASCII85Stream
+//------------------------------------------------------------------------
+
+class ASCII85Stream: public FilterStream {
+public:
+
+ ASCII85Stream(Stream *strA);
+ virtual ~ASCII85Stream();
+ virtual StreamKind getKind() { return strASCII85; }
+ virtual void reset();
+ virtual int getChar()
+ { int ch = lookChar(); ++index; return ch; }
+ virtual int lookChar();
+ virtual GString *getPSFilter(char *indent);
+ virtual GBool isBinary(GBool last = gTrue);
+
+private:
+
+ int c[5];
+ int b[4];
+ int index, n;
+ GBool eof;
+};
+
+//------------------------------------------------------------------------
+// LZWStream
+//------------------------------------------------------------------------
+
+class LZWStream: public FilterStream {
+public:
+
+ LZWStream(Stream *strA, int predictor, int columns, int colors,
+ int bits, int earlyA);
+ virtual ~LZWStream();
+ virtual StreamKind getKind() { return strLZW; }
+ virtual void reset();
+ virtual int getChar();
+ virtual int lookChar();
+ virtual int getRawChar();
+ virtual GString *getPSFilter(char *indent);
+ virtual GBool isBinary(GBool last = gTrue);
+
+private:
+
+ StreamPredictor *pred; // predictor
+ int early; // early parameter
+ FILE *zPipe; // uncompress pipe
+ GString *zName; // .Z file name
+ int inputBuf; // input buffer
+ int inputBits; // number of bits in input buffer
+ int inCodeBits; // size of input code
+ char buf[256]; // buffer
+ char *bufPtr; // next char to read
+ char *bufEnd; // end of buffer
+
+ void dumpFile(FILE *f);
+ int getCode();
+ GBool fillBuf();
+};
+
+//------------------------------------------------------------------------
+// RunLengthStream
+//------------------------------------------------------------------------
+
+class RunLengthStream: public FilterStream {
+public:
+
+ RunLengthStream(Stream *strA);
+ virtual ~RunLengthStream();
+ virtual StreamKind getKind() { return strRunLength; }
+ virtual void reset();
+ virtual int getChar()
+ { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); }
+ virtual int lookChar()
+ { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); }
+ virtual GString *getPSFilter(char *indent);
+ virtual GBool isBinary(GBool last = gTrue);
+
+private:
+
+ char buf[128]; // buffer
+ char *bufPtr; // next char to read
+ char *bufEnd; // end of buffer
+ GBool eof;
+
+ GBool fillBuf();
+};
+
+//------------------------------------------------------------------------
+// CCITTFaxStream
+//------------------------------------------------------------------------
+
+struct CCITTCodeTable;
+
+class CCITTFaxStream: public FilterStream {
+public:
+
+ CCITTFaxStream(Stream *strA, int encodingA, GBool endOfLineA,
+ GBool byteAlignA, int columnsA, int rowsA,
+ GBool endOfBlockA, GBool blackA);
+ virtual ~CCITTFaxStream();
+ virtual StreamKind getKind() { return strCCITTFax; }
+ virtual void reset();
+ virtual int getChar()
+ { int c = lookChar(); buf = EOF; return c; }
+ virtual int lookChar();
+ virtual GString *getPSFilter(char *indent);
+ virtual GBool isBinary(GBool last = gTrue);
+
+private:
+
+ int encoding; // 'K' parameter
+ GBool endOfLine; // 'EndOfLine' parameter
+ GBool byteAlign; // 'EncodedByteAlign' parameter
+ int columns; // 'Columns' parameter
+ int rows; // 'Rows' parameter
+ GBool endOfBlock; // 'EndOfBlock' parameter
+ GBool black; // 'BlackIs1' parameter
+ GBool eof; // true if at eof
+ GBool nextLine2D; // true if next line uses 2D encoding
+ int row; // current row
+ int inputBuf; // input buffer
+ int inputBits; // number of bits in input buffer
+ short *refLine; // reference line changing elements
+ int b1; // index into refLine
+ short *codingLine; // coding line changing elements
+ int a0; // index into codingLine
+ int outputBits; // remaining ouput bits
+ int buf; // character buffer
+
+ short getTwoDimCode();
+ short getWhiteCode();
+ short getBlackCode();
+ short lookBits(int n);
+ void eatBits(int n) { inputBits -= n; }
+};
+
+//------------------------------------------------------------------------
+// DCTStream
+//------------------------------------------------------------------------
+
+// DCT component info
+struct DCTCompInfo {
+ int id; // component ID
+ GBool inScan; // is this component in the current scan?
+ int hSample, vSample; // horiz/vert sampling resolutions
+ int quantTable; // quantization table number
+ int dcHuffTable, acHuffTable; // Huffman table numbers
+ int prevDC; // DC coefficient accumulator
+};
+
+// DCT Huffman decoding table
+struct DCTHuffTable {
+ Guchar firstSym[17]; // first symbol for this bit length
+ Gushort firstCode[17]; // first code for this bit length
+ Gushort numCodes[17]; // number of codes of this bit length
+ Guchar sym[256]; // symbols
+};
+
+class DCTStream: public FilterStream {
+public:
+
+ DCTStream(Stream *strA);
+ virtual ~DCTStream();
+ virtual StreamKind getKind() { return strDCT; }
+ virtual void reset();
+ virtual int getChar();
+ virtual int lookChar();
+ virtual GString *getPSFilter(char *indent);
+ virtual GBool isBinary(GBool last = gTrue);
+ Stream *getRawStream() { return str; }
+
+private:
+
+ int width, height; // image size
+ int mcuWidth, mcuHeight; // size of min coding unit, in data units
+ DCTCompInfo compInfo[4]; // info for each component
+ int numComps; // number of components in image
+ int colorXform; // need YCbCr-to-RGB transform?
+ GBool gotAdobeMarker; // set if APP14 Adobe marker was present
+ int restartInterval; // restart interval, in MCUs
+ Guchar quantTables[4][64]; // quantization tables
+ int numQuantTables; // number of quantization tables
+ DCTHuffTable dcHuffTables[4]; // DC Huffman tables
+ DCTHuffTable acHuffTables[4]; // AC Huffman tables
+ int numDCHuffTables; // number of DC Huffman tables
+ int numACHuffTables; // number of AC Huffman tables
+ Guchar *rowBuf[4][32]; // buffer for one MCU
+ int comp, x, y, dy; // current position within image/MCU
+ int restartCtr; // MCUs left until restart
+ int restartMarker; // next restart marker
+ int inputBuf; // input buffer for variable length codes
+ int inputBits; // number of valid bits in input buffer
+
+ void restart();
+ GBool readMCURow();
+ GBool readDataUnit(DCTHuffTable *dcHuffTable, DCTHuffTable *acHuffTable,
+ Guchar quantTable[64], int *prevDC, Guchar data[64]);
+ int readHuffSym(DCTHuffTable *table);
+ int readAmp(int size);
+ int readBit();
+ GBool readHeader();
+ GBool readFrameInfo();
+ GBool readScanInfo();
+ GBool readQuantTables();
+ GBool readHuffmanTables();
+ GBool readRestartInterval();
+ GBool readAdobeMarker();
+ GBool readTrailer();
+ int readMarker();
+ int read16();
+};
+
+//------------------------------------------------------------------------
+// FlateStream
+//------------------------------------------------------------------------
+
+#define flateWindow 32768 // buffer size
+#define flateMask (flateWindow-1)
+#define flateMaxHuffman 15 // max Huffman code length
+#define flateMaxCodeLenCodes 19 // max # code length codes
+#define flateMaxLitCodes 288 // max # literal codes
+#define flateMaxDistCodes 30 // max # distance codes
+
+// Huffman code table entry
+struct FlateCode {
+ int len; // code length in bits
+ int code; // code word
+ int val; // value represented by this code
+};
+
+// Huffman code table
+struct FlateHuffmanTab {
+ int start[flateMaxHuffman+2]; // indexes of first code of each length
+ FlateCode *codes; // codes, sorted by length and code word
+};
+
+// Decoding info for length and distance code words
+struct FlateDecode {
+ int bits; // # extra bits
+ int first; // first length/distance
+};
+
+class FlateStream: public FilterStream {
+public:
+
+ FlateStream(Stream *strA, int predictor, int columns,
+ int colors, int bits);
+ virtual ~FlateStream();
+ virtual StreamKind getKind() { return strFlate; }
+ virtual void reset();
+ virtual int getChar();
+ virtual int lookChar();
+ virtual int getRawChar();
+ virtual GString *getPSFilter(char *indent);
+ virtual GBool isBinary(GBool last = gTrue);
+
+private:
+
+ StreamPredictor *pred; // predictor
+ Guchar buf[flateWindow]; // output data buffer
+ int index; // current index into output buffer
+ int remain; // number valid bytes in output buffer
+ int codeBuf; // input buffer
+ int codeSize; // number of bits in input buffer
+ FlateCode // literal and distance codes
+ allCodes[flateMaxLitCodes + flateMaxDistCodes];
+ FlateHuffmanTab litCodeTab; // literal code table
+ FlateHuffmanTab distCodeTab; // distance code table
+ GBool compressedBlock; // set if reading a compressed block
+ int blockLen; // remaining length of uncompressed block
+ GBool endOfBlock; // set when end of block is reached
+ GBool eof; // set when end of stream is reached
+
+ static int // code length code reordering
+ codeLenCodeMap[flateMaxCodeLenCodes];
+ static FlateDecode // length decoding info
+ lengthDecode[flateMaxLitCodes-257];
+ static FlateDecode // distance decoding info
+ distDecode[flateMaxDistCodes];
+
+ void readSome();
+ GBool startBlock();
+ void loadFixedCodes();
+ GBool readDynamicCodes();
+ void compHuffmanCodes(FlateHuffmanTab *tab, int n);
+ int getHuffmanCodeWord(FlateHuffmanTab *tab);
+ int getCodeWord(int bits);
+};
+
+//------------------------------------------------------------------------
+// EOFStream
+//------------------------------------------------------------------------
+
+class EOFStream: public FilterStream {
+public:
+
+ EOFStream(Stream *strA);
+ virtual ~EOFStream();
+ virtual StreamKind getKind() { return strWeird; }
+ virtual void reset() {}
+ virtual int getChar() { return EOF; }
+ virtual int lookChar() { return EOF; }
+ virtual GString *getPSFilter(char *indent) { return NULL; }
+ virtual GBool isBinary(GBool last = gTrue) { return gFalse; }
+};
+
+//------------------------------------------------------------------------
+// FixedLengthEncoder
+//------------------------------------------------------------------------
+
+class FixedLengthEncoder: public FilterStream {
+public:
+
+ FixedLengthEncoder(Stream *strA, int lengthA);
+ ~FixedLengthEncoder();
+ virtual StreamKind getKind() { return strWeird; }
+ virtual void reset();
+ virtual void close();
+ virtual int getChar();
+ virtual int lookChar();
+ virtual GString *getPSFilter(char *indent) { return NULL; }
+ virtual GBool isBinary(GBool last = gTrue) { return gFalse; }
+ virtual GBool isEncoder() { return gTrue; }
+
+private:
+
+ int length;
+ int count;
+};
+
+//------------------------------------------------------------------------
+// ASCII85Encoder
+//------------------------------------------------------------------------
+
+class ASCII85Encoder: public FilterStream {
+public:
+
+ ASCII85Encoder(Stream *strA);
+ virtual ~ASCII85Encoder();
+ virtual StreamKind getKind() { return strWeird; }
+ virtual void reset();
+ virtual void close();
+ virtual int getChar()
+ { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); }
+ virtual int lookChar()
+ { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); }
+ virtual GString *getPSFilter(char *indent) { return NULL; }
+ virtual GBool isBinary(GBool last = gTrue) { return gFalse; }
+ virtual GBool isEncoder() { return gTrue; }
+
+private:
+
+ char buf[8];
+ char *bufPtr;
+ char *bufEnd;
+ int lineLen;
+ GBool eof;
+
+ GBool fillBuf();
+};
+
+//------------------------------------------------------------------------
+// RunLengthEncoder
+//------------------------------------------------------------------------
+
+class RunLengthEncoder: public FilterStream {
+public:
+
+ RunLengthEncoder(Stream *strA);
+ virtual ~RunLengthEncoder();
+ virtual StreamKind getKind() { return strWeird; }
+ virtual void reset();
+ virtual void close();
+ virtual int getChar()
+ { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); }
+ virtual int lookChar()
+ { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); }
+ virtual GString *getPSFilter(char *indent) { return NULL; }
+ virtual GBool isBinary(GBool last = gTrue) { return gFalse; }
+ virtual GBool isEncoder() { return gTrue; }
+
+private:
+
+ char buf[131];
+ char *bufPtr;
+ char *bufEnd;
+ char *nextEnd;
+ GBool eof;
+
+ GBool fillBuf();
+};
+
+#endif
diff --git a/pdftops/T1Font.h b/pdftops/T1Font.h
new file mode 100644
index 000000000..846d253e9
--- /dev/null
+++ b/pdftops/T1Font.h
@@ -0,0 +1,102 @@
+//========================================================================
+//
+// T1Font.h
+//
+// An X wrapper for the t1lib Type 1 font rasterizer.
+//
+//========================================================================
+
+#ifndef T1FONT_H
+#define T1FONT_H
+
+#if HAVE_T1LIB_H
+
+#ifdef __GNUC__
+#pragma interface
+#endif
+
+#include <X11/Xlib.h>
+#include <t1lib.h>
+#include "SFont.h"
+
+class FontEncoding;
+
+//------------------------------------------------------------------------
+
+class T1FontEngine: public SFontEngine {
+public:
+
+ T1FontEngine(Display *displayA, Visual *visualA, int depthA,
+ Colormap colormapA, GBool aaA, GBool aaHighA);
+ GBool isOk() { return ok; }
+ virtual ~T1FontEngine();
+
+private:
+
+ GBool aa; // use anti-aliasing?
+ GBool aaHigh; // use high-res anti-aliasing?
+ GBool ok;
+
+ friend class T1FontFile;
+ friend class T1Font;
+};
+
+//------------------------------------------------------------------------
+
+class T1FontFile: public SFontFile {
+public:
+
+ T1FontFile(T1FontEngine *engineA, char *fontFileName,
+ FontEncoding *fontEnc, double *bboxA);
+ GBool isOk() { return ok; }
+ virtual ~T1FontFile();
+
+private:
+
+ T1FontEngine *engine;
+ int id; // t1lib font ID
+ char **enc;
+ char *encStr;
+ double bbox[4];
+ GBool ok;
+
+ friend class T1Font;
+};
+
+//------------------------------------------------------------------------
+
+struct T1FontCacheTag {
+ Gushort code;
+ Gushort mru; // valid bit (0x8000) and MRU index
+ int x, y, w, h; // offset and size of glyph
+};
+
+class T1Font: public SFont {
+public:
+
+ T1Font(T1FontFile *fontFileA, double *m);
+ GBool isOk() { return ok; }
+ virtual ~T1Font();
+ virtual GBool drawChar(Drawable d, int w, int h, GC gc,
+ int x, int y, int r, int g, int b, Gushort c);
+
+private:
+
+ Guchar *getGlyphPixmap(Gushort c, int *x, int *y, int *w, int *h);
+
+ T1FontFile *fontFile;
+ int id;
+ float size;
+ XImage *image;
+ int glyphW, glyphH; // size of glyph pixmaps
+ int glyphSize; // size of glyph pixmaps, in bytes
+ Guchar *cache; // glyph pixmap cache
+ T1FontCacheTag *cacheTags; // cache tags, i.e., char codes
+ int cacheSets; // number of sets in cache
+ int cacheAssoc; // cache associativity (glyphs per set)
+ GBool ok;
+};
+
+#endif // HAVE_T1LIB_H
+
+#endif
diff --git a/pdftops/TTFont.h b/pdftops/TTFont.h
new file mode 100644
index 000000000..998087c9c
--- /dev/null
+++ b/pdftops/TTFont.h
@@ -0,0 +1,104 @@
+//========================================================================
+//
+// TTFont.h
+//
+// An X wrapper for the FreeType TrueType font rasterizer.
+//
+//========================================================================
+
+#ifndef TTFONT_H
+#define TTFONT_H
+
+#if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
+
+#ifdef __GNUC__
+#pragma interface
+#endif
+
+#if HAVE_FREETYPE_FREETYPE_H
+#include <freetype/freetype.h>
+#include <freetype/ftxpost.h>
+#else
+#include <freetype.h>
+#include <ftxpost.h>
+#endif
+#include "SFont.h"
+
+//------------------------------------------------------------------------
+
+class TTFontEngine: public SFontEngine {
+public:
+
+ TTFontEngine(Display *displayA, Visual *visualA, int depthA,
+ Colormap colormapA, GBool aaA);
+ GBool isOk() { return ok; }
+ virtual ~TTFontEngine();
+
+private:
+
+ TT_Engine engine;
+ GBool aa;
+ Gulong palette[5];
+ GBool ok;
+
+ friend class TTFontFile;
+ friend class TTFont;
+};
+
+//------------------------------------------------------------------------
+
+class TTFontFile: public SFontFile {
+public:
+
+ TTFontFile(TTFontEngine *engineA, char *fontFileName);
+ GBool isOk() { return ok; }
+ virtual ~TTFontFile();
+
+private:
+
+ TTFontEngine *engine;
+ TT_Face face;
+ TT_CharMap charMap;
+ int charMapOffset;
+ GBool ok;
+
+ friend class TTFont;
+};
+
+//------------------------------------------------------------------------
+
+struct TTFontCacheTag {
+ Gushort code;
+ Gushort mru; // valid bit (0x8000) and MRU index
+};
+
+class TTFont: public SFont {
+public:
+
+ TTFont(TTFontFile *fontFileA, double *m);
+ GBool isOk() { return ok; }
+ virtual ~TTFont();
+ virtual GBool drawChar(Drawable d, int w, int h, GC gc,
+ int x, int y, int r, int g, int b, Gushort c);
+
+private:
+
+ GBool getGlyphPixmap(Gushort c);
+
+ TTFontFile *fontFile;
+ TT_Instance instance;
+ TT_Glyph glyph;
+ TT_Raster_Map ras;
+ XImage *image;
+ TT_Matrix matrix;
+ TT_F26Dot6 xOffset, yOffset;
+ Guchar *cache; // glyph pixmap cache
+ TTFontCacheTag *cacheTags; // cache tags, i.e., char codes
+ int cacheSets; // number of sets in cache
+ int cacheAssoc; // cache associativity (glyphs per set)
+ GBool ok;
+};
+
+#endif // !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
+
+#endif
diff --git a/pdftops/XRef.cxx b/pdftops/XRef.cxx
new file mode 100644
index 000000000..de2db2f23
--- /dev/null
+++ b/pdftops/XRef.cxx
@@ -0,0 +1,635 @@
+//========================================================================
+//
+// XRef.cc
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <ctype.h>
+#include "gmem.h"
+#include "Object.h"
+#include "Stream.h"
+#include "Lexer.h"
+#include "Parser.h"
+#include "Dict.h"
+#ifndef NO_DECRYPTION
+#include "Decrypt.h"
+#endif
+#include "Error.h"
+#include "XRef.h"
+
+//------------------------------------------------------------------------
+
+#define xrefSearchSize 1024 // read this many bytes at end of file
+ // to look for 'startxref'
+
+#ifndef NO_DECRYPTION
+//------------------------------------------------------------------------
+// Permission bits
+//------------------------------------------------------------------------
+
+#define permPrint (1<<2)
+#define permChange (1<<3)
+#define permCopy (1<<4)
+#define permNotes (1<<5)
+#define defPermFlags 0xfffc
+#endif
+
+//------------------------------------------------------------------------
+// XRef
+//------------------------------------------------------------------------
+
+XRef::XRef(BaseStream *strA, GString *ownerPassword, GString *userPassword) {
+ int pos;
+ int i;
+
+ ok = gTrue;
+ size = 0;
+ entries = NULL;
+ streamEnds = NULL;
+ streamEndsLen = 0;
+
+ // read the trailer
+ str = strA;
+ start = str->getStart();
+ pos = readTrailer();
+
+ // if there was a problem with the trailer,
+ // try to reconstruct the xref table
+ if (pos == 0) {
+ if (!(ok = constructXRef())) {
+ return;
+ }
+
+ // trailer is ok - read the xref table
+ } else {
+ entries = (XRefEntry *)gmalloc(size * sizeof(XRefEntry));
+ for (i = 0; i < size; ++i) {
+ entries[i].offset = -1;
+ entries[i].used = gFalse;
+ }
+ while (readXRef(&pos)) ;
+
+ // if there was a problem with the xref table,
+ // try to reconstruct it
+ if (!ok) {
+ gfree(entries);
+ size = 0;
+ entries = NULL;
+ if (!(ok = constructXRef())) {
+ return;
+ }
+ }
+ }
+
+ // now set the trailer dictionary's xref pointer so we can fetch
+ // indirect objects from it
+ trailerDict.getDict()->setXRef(this);
+
+ // check for encryption
+#ifndef NO_DECRYPTION
+ encrypted = gFalse;
+#endif
+ if (checkEncrypted(ownerPassword, userPassword)) {
+ ok = gFalse;
+ return;
+ }
+}
+
+XRef::~XRef() {
+ gfree(entries);
+ trailerDict.free();
+ if (streamEnds) {
+ gfree(streamEnds);
+ }
+}
+
+// Read startxref position, xref table size, and root. Returns
+// first xref position.
+int XRef::readTrailer() {
+ Parser *parser;
+ Object obj;
+ char buf[xrefSearchSize+1];
+ int n, pos, pos1;
+ char *p;
+ int c;
+ int i;
+
+ // read last xrefSearchSize bytes
+ str->setPos(-xrefSearchSize);
+ for (n = 0; n < xrefSearchSize; ++n) {
+ if ((c = str->getChar()) == EOF)
+ break;
+ buf[n] = c;
+ }
+ buf[n] = '\0';
+
+ // find startxref
+ for (i = n - 9; i >= 0; --i) {
+ if (!strncmp(&buf[i], "startxref", 9))
+ break;
+ }
+ if (i < 0)
+ return 0;
+ for (p = &buf[i+9]; isspace(*p); ++p) ;
+ pos = lastXRefPos = atoi(p);
+
+ // find trailer dict by looking after first xref table
+ // (NB: we can't just use the trailer dict at the end of the file --
+ // this won't work for linearized files.)
+ str->setPos(start + pos);
+ for (i = 0; i < 4; ++i)
+ buf[i] = str->getChar();
+ if (strncmp(buf, "xref", 4))
+ return 0;
+ pos1 = pos + 4;
+ while (1) {
+ str->setPos(start + pos1);
+ for (i = 0; i < 35; ++i) {
+ if ((c = str->getChar()) == EOF)
+ return 0;
+ buf[i] = c;
+ }
+ if (!strncmp(buf, "trailer", 7))
+ break;
+ p = buf;
+ while (isspace(*p)) ++p;
+ while ('0' <= *p && *p <= '9') ++p;
+ while (isspace(*p)) ++p;
+ n = atoi(p);
+ while ('0' <= *p && *p <= '9') ++p;
+ while (isspace(*p)) ++p;
+ if (p == buf)
+ return 0;
+ pos1 += (p - buf) + n * 20;
+ }
+ pos1 += 7;
+
+ // read trailer dict
+ obj.initNull();
+ parser = new Parser(NULL, new Lexer(NULL, str->makeSubStream(start + pos1,
+ -1, &obj)));
+ parser->getObj(&trailerDict);
+ if (trailerDict.isDict()) {
+ trailerDict.dictLookupNF("Size", &obj);
+ if (obj.isInt())
+ size = obj.getInt();
+ else
+ pos = 0;
+ obj.free();
+ trailerDict.dictLookupNF("Root", &obj);
+ if (obj.isRef()) {
+ rootNum = obj.getRefNum();
+ rootGen = obj.getRefGen();
+ } else {
+ pos = 0;
+ }
+ obj.free();
+ } else {
+ pos = 0;
+ }
+ delete parser;
+
+ // return first xref position
+ return pos;
+}
+
+// Read an xref table and the prev pointer from the trailer.
+GBool XRef::readXRef(int *pos) {
+ Parser *parser;
+ Object obj, obj2;
+ char s[20];
+ GBool more;
+ int first, newSize, n, i, j;
+ int c;
+
+ // seek to xref in stream
+ str->setPos(start + *pos);
+
+ // make sure it's an xref table
+ while ((c = str->getChar()) != EOF && isspace(c)) ;
+ s[0] = (char)c;
+ s[1] = (char)str->getChar();
+ s[2] = (char)str->getChar();
+ s[3] = (char)str->getChar();
+ if (!(s[0] == 'x' && s[1] == 'r' && s[2] == 'e' && s[3] == 'f')) {
+ goto err2;
+ }
+
+ // read xref
+ while (1) {
+ while ((c = str->lookChar()) != EOF && isspace(c)) {
+ str->getChar();
+ }
+ if (c == 't') {
+ break;
+ }
+ for (i = 0; (c = str->getChar()) != EOF && isdigit(c) && i < 20; ++i) {
+ s[i] = (char)c;
+ }
+ if (i == 0) {
+ goto err2;
+ }
+ s[i] = '\0';
+ first = atoi(s);
+ while ((c = str->lookChar()) != EOF && isspace(c)) {
+ str->getChar();
+ }
+ for (i = 0; (c = str->getChar()) != EOF && isdigit(c) && i < 20; ++i) {
+ s[i] = (char)c;
+ }
+ if (i == 0) {
+ goto err2;
+ }
+ s[i] = '\0';
+ n = atoi(s);
+ while ((c = str->lookChar()) != EOF && isspace(c)) {
+ str->getChar();
+ }
+ // check for buggy PDF files with an incorrect (too small) xref
+ // table size
+ if (first + n > size) {
+ newSize = size + 256;
+ entries = (XRefEntry *)grealloc(entries, newSize * sizeof(XRefEntry));
+ for (i = size; i < newSize; ++i) {
+ entries[i].offset = -1;
+ entries[i].used = gFalse;
+ }
+ size = newSize;
+ }
+ for (i = first; i < first + n; ++i) {
+ for (j = 0; j < 20; ++j) {
+ if ((c = str->getChar()) == EOF) {
+ goto err2;
+ }
+ s[j] = (char)c;
+ }
+ if (entries[i].offset < 0) {
+ s[10] = '\0';
+ entries[i].offset = atoi(s);
+ s[16] = '\0';
+ entries[i].gen = atoi(&s[11]);
+ if (s[17] == 'n') {
+ entries[i].used = gTrue;
+ } else if (s[17] == 'f') {
+ entries[i].used = gFalse;
+ } else {
+ goto err2;
+ }
+ // PDF files of patents from the IBM Intellectual Property
+ // Network have a bug: the xref table claims to start at 1
+ // instead of 0.
+ if (i == 1 && first == 1 &&
+ entries[1].offset == 0 && entries[1].gen == 65535 &&
+ !entries[1].used) {
+ i = first = 0;
+ entries[0] = entries[1];
+ entries[1].offset = -1;
+ }
+ }
+ }
+ }
+
+ // read prev pointer from trailer dictionary
+ obj.initNull();
+ parser = new Parser(NULL, new Lexer(NULL, str->makeSubStream(str->getPos(),
+ -1, &obj)));
+ parser->getObj(&obj);
+ if (!obj.isCmd("trailer")) {
+ goto err1;
+ }
+ obj.free();
+ parser->getObj(&obj);
+ if (!obj.isDict()) {
+ goto err1;
+ }
+ obj.getDict()->lookupNF("Prev", &obj2);
+ if (obj2.isInt()) {
+ *pos = obj2.getInt();
+ more = gTrue;
+ } else {
+ more = gFalse;
+ }
+ obj.free();
+ obj2.free();
+
+ delete parser;
+ return more;
+
+ err1:
+ obj.free();
+ err2:
+ ok = gFalse;
+ return gFalse;
+}
+
+// Attempt to construct an xref table for a damaged file.
+GBool XRef::constructXRef() {
+ Parser *parser;
+ Object obj;
+ char buf[256];
+ int pos;
+ int num, gen;
+ int newSize;
+ int streamEndsSize;
+ char *p;
+ int i;
+ GBool gotRoot;
+
+ error(0, "PDF file is damaged - attempting to reconstruct xref table...");
+ gotRoot = gFalse;
+ streamEndsLen = streamEndsSize = 0;
+
+ str->reset();
+ while (1) {
+ pos = str->getPos();
+ if (!str->getLine(buf, 256)) {
+ break;
+ }
+ p = buf;
+
+ // got trailer dictionary
+ if (!strncmp(p, "trailer", 7)) {
+ obj.initNull();
+ parser = new Parser(NULL, new Lexer(NULL,
+ str->makeSubStream(start + pos + 7, -1, &obj)));
+ if (!trailerDict.isNone())
+ trailerDict.free();
+ parser->getObj(&trailerDict);
+ if (trailerDict.isDict()) {
+ trailerDict.dictLookupNF("Root", &obj);
+ if (obj.isRef()) {
+ rootNum = obj.getRefNum();
+ rootGen = obj.getRefGen();
+ gotRoot = gTrue;
+ }
+ obj.free();
+ } else {
+ pos = 0;
+ }
+ delete parser;
+
+ // look for object
+ } else if (isdigit(*p)) {
+ num = atoi(p);
+ do {
+ ++p;
+ } while (*p && isdigit(*p));
+ if (isspace(*p)) {
+ do {
+ ++p;
+ } while (*p && isspace(*p));
+ if (isdigit(*p)) {
+ gen = atoi(p);
+ do {
+ ++p;
+ } while (*p && isdigit(*p));
+ if (isspace(*p)) {
+ do {
+ ++p;
+ } while (*p && isspace(*p));
+ if (!strncmp(p, "obj", 3)) {
+ if (num >= size) {
+ newSize = (num + 1 + 255) & ~255;
+ entries = (XRefEntry *)
+ grealloc(entries, newSize * sizeof(XRefEntry));
+ for (i = size; i < newSize; ++i) {
+ entries[i].offset = -1;
+ entries[i].used = gFalse;
+ }
+ size = newSize;
+ }
+ if (!entries[num].used || gen >= entries[num].gen) {
+ entries[num].offset = pos - start;
+ entries[num].gen = gen;
+ entries[num].used = gTrue;
+ }
+ }
+ }
+ }
+ }
+
+ } else if (!strncmp(p, "endstream", 9)) {
+ if (streamEndsLen == streamEndsSize) {
+ streamEndsSize += 64;
+ streamEnds = (int *)grealloc(streamEnds, streamEndsSize * sizeof(int));
+ }
+ streamEnds[streamEndsLen++] = pos;
+ }
+ }
+
+ if (gotRoot)
+ return gTrue;
+
+ error(-1, "Couldn't find trailer dictionary");
+ return gFalse;
+}
+
+#ifndef NO_DECRYPTION
+GBool XRef::checkEncrypted(GString *ownerPassword, GString *userPassword) {
+ Object encrypt, filterObj, versionObj, revisionObj, lengthObj;
+ Object ownerKey, userKey, permissions, fileID, fileID1;
+ GBool encrypted1;
+ GBool ret;
+
+ ret = gFalse;
+
+ permFlags = defPermFlags;
+ trailerDict.dictLookup("Encrypt", &encrypt);
+ if ((encrypted1 = encrypt.isDict())) {
+ ret = gTrue;
+ encrypt.dictLookup("Filter", &filterObj);
+ if (filterObj.isName("Standard")) {
+ encrypt.dictLookup("V", &versionObj);
+ encrypt.dictLookup("R", &revisionObj);
+ encrypt.dictLookup("Length", &lengthObj);
+ encrypt.dictLookup("O", &ownerKey);
+ encrypt.dictLookup("U", &userKey);
+ encrypt.dictLookup("P", &permissions);
+ trailerDict.dictLookup("ID", &fileID);
+ if (versionObj.isInt() &&
+ revisionObj.isInt() &&
+ ownerKey.isString() && ownerKey.getString()->getLength() == 32 &&
+ userKey.isString() && userKey.getString()->getLength() == 32 &&
+ permissions.isInt() &&
+ fileID.isArray()) {
+ encVersion = versionObj.getInt();
+ encRevision = revisionObj.getInt();
+ if (lengthObj.isInt()) {
+ keyLength = lengthObj.getInt() / 8;
+ } else {
+ keyLength = 5;
+ }
+ permFlags = permissions.getInt();
+ if (encVersion >= 1 && encVersion <= 2 &&
+ encRevision >= 2 && encRevision <= 3) {
+ fileID.arrayGet(0, &fileID1);
+ if (fileID1.isString()) {
+ if (Decrypt::makeFileKey(encVersion, encRevision, keyLength,
+ ownerKey.getString(), userKey.getString(),
+ permFlags, fileID1.getString(),
+ ownerPassword, userPassword, fileKey,
+ &ownerPasswordOk)) {
+ if (ownerPassword && !ownerPasswordOk) {
+ error(-1, "Incorrect owner password");
+ }
+ ret = gFalse;
+ } else {
+ error(-1, "Incorrect password");
+ }
+ } else {
+ error(-1, "Weird encryption info");
+ }
+ fileID1.free();
+ } else {
+ error(-1, "Unsupported version/revision (%d/%d) of Standard security handler",
+ encVersion, encRevision);
+ }
+ } else {
+ error(-1, "Weird encryption info");
+ }
+ fileID.free();
+ permissions.free();
+ userKey.free();
+ ownerKey.free();
+ lengthObj.free();
+ revisionObj.free();
+ versionObj.free();
+ } else {
+ error(-1, "Unknown security handler '%s'",
+ filterObj.isName() ? filterObj.getName() : "???");
+ }
+ filterObj.free();
+ }
+ encrypt.free();
+
+ // this flag has to be set *after* we read the O/U/P strings
+ encrypted = encrypted1;
+
+ return ret;
+}
+#else
+GBool XRef::checkEncrypted(GString *ownerPassword, GString *userPassword) {
+ Object obj;
+ GBool encrypted;
+
+ trailerDict.dictLookup("Encrypt", &obj);
+ if ((encrypted = !obj.isNull())) {
+ error(-1, "PDF file is encrypted and this version of the Xpdf tools");
+ error(-1, "was built without decryption support.");
+ }
+ obj.free();
+ return encrypted;
+}
+#endif
+
+GBool XRef::okToPrint(GBool ignoreOwnerPW) {
+#ifndef NO_DECRYPTION
+ if ((ignoreOwnerPW || !ownerPasswordOk) && !(permFlags & permPrint)) {
+ return gFalse;
+ }
+#endif
+ return gTrue;
+}
+
+GBool XRef::okToChange(GBool ignoreOwnerPW) {
+#ifndef NO_DECRYPTION
+ if ((ignoreOwnerPW || !ownerPasswordOk) && !(permFlags & permChange)) {
+ return gFalse;
+ }
+#endif
+ return gTrue;
+}
+
+GBool XRef::okToCopy(GBool ignoreOwnerPW) {
+#ifndef NO_DECRYPTION
+ if ((ignoreOwnerPW || !ownerPasswordOk) && !(permFlags & permCopy)) {
+ return gFalse;
+ }
+#endif
+ return gTrue;
+}
+
+GBool XRef::okToAddNotes(GBool ignoreOwnerPW) {
+#ifndef NO_DECRYPTION
+ if ((ignoreOwnerPW || !ownerPasswordOk) && !(permFlags & permNotes)) {
+ return gFalse;
+ }
+#endif
+ return gTrue;
+}
+
+Object *XRef::fetch(int num, int gen, Object *obj) {
+ XRefEntry *e;
+ Parser *parser;
+ Object obj1, obj2, obj3;
+
+ // check for bogus ref - this can happen in corrupted PDF files
+ if (num < 0 || num >= size) {
+ obj->initNull();
+ return obj;
+ }
+
+ e = &entries[num];
+ if (e->gen == gen && e->offset >= 0) {
+ obj1.initNull();
+ parser = new Parser(this, new Lexer(this,
+ str->makeSubStream(start + e->offset, -1, &obj1)));
+ parser->getObj(&obj1);
+ parser->getObj(&obj2);
+ parser->getObj(&obj3);
+ if (obj1.isInt() && obj1.getInt() == num &&
+ obj2.isInt() && obj2.getInt() == gen &&
+ obj3.isCmd("obj")) {
+#ifndef NO_DECRYPTION
+ parser->getObj(obj, encrypted ? fileKey : (Guchar *)NULL, keyLength,
+ num, gen);
+#else
+ parser->getObj(obj);
+#endif
+ } else {
+ obj->initNull();
+ }
+ obj1.free();
+ obj2.free();
+ obj3.free();
+ delete parser;
+ } else {
+ obj->initNull();
+ }
+ return obj;
+}
+
+Object *XRef::getDocInfo(Object *obj) {
+ return trailerDict.dictLookup("Info", obj);
+}
+
+int XRef::getStreamEnd(int streamStart) {
+ int a, b, m;
+
+ if (streamEndsLen == 0 ||
+ streamStart > streamEnds[streamEndsLen - 1]) {
+ return -1;
+ }
+
+ a = -1;
+ b = streamEndsLen - 1;
+ // invariant: streamEnds[a] < streamStart <= streamEnds[b]
+ while (b - a > 1) {
+ m = (a + b) / 2;
+ if (streamStart <= streamEnds[m]) {
+ b = m;
+ } else {
+ a = m;
+ }
+ }
+ return streamEnds[b];
+}
diff --git a/pdftops/XRef.h b/pdftops/XRef.h
new file mode 100644
index 000000000..35306bba8
--- /dev/null
+++ b/pdftops/XRef.h
@@ -0,0 +1,110 @@
+//========================================================================
+//
+// XRef.h
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifndef XREF_H
+#define XREF_H
+
+#ifdef __GNUC__
+#pragma interface
+#endif
+
+#include "gtypes.h"
+#include "Object.h"
+
+class Dict;
+class Stream;
+
+//------------------------------------------------------------------------
+// XRef
+//------------------------------------------------------------------------
+
+struct XRefEntry {
+ int offset;
+ int gen;
+ GBool used;
+};
+
+class XRef {
+public:
+
+ // Constructor. Read xref table from stream.
+ XRef(BaseStream *strA, GString *ownerPassword, GString *userPassword);
+
+ // Destructor.
+ ~XRef();
+
+ // Is xref table valid?
+ GBool isOk() { return ok; }
+
+ // Is the file encrypted?
+#ifndef NO_DECRYPTION
+ GBool isEncrypted() { return encrypted; }
+#else
+ GBool isEncrypted() { return gFalse; }
+#endif
+
+ // Check various permissions.
+ GBool okToPrint(GBool ignoreOwnerPW = gFalse);
+ GBool okToChange(GBool ignoreOwnerPW = gFalse);
+ GBool okToCopy(GBool ignoreOwnerPW = gFalse);
+ GBool okToAddNotes(GBool ignoreOwnerPW = gFalse);
+
+ // Get catalog object.
+ Object *getCatalog(Object *obj) { return fetch(rootNum, rootGen, obj); }
+
+ // Fetch an indirect reference.
+ Object *fetch(int num, int gen, Object *obj);
+
+ // Return the document's Info dictionary (if any).
+ Object *getDocInfo(Object *obj);
+
+ // Return the number of objects in the xref table.
+ int getNumObjects() { return size; }
+
+ // Return the offset of the last xref table.
+ int getLastXRefPos() { return lastXRefPos; }
+
+ // Return the catalog object reference.
+ int getRootNum() { return rootNum; }
+ int getRootGen() { return rootGen; }
+
+ // Get end position for a stream in a damaged file.
+ // Returns -1 if unknown or file is not damaged.
+ int getStreamEnd(int streamStart);
+
+private:
+
+ BaseStream *str; // input stream
+ int start; // offset in file (to allow for garbage
+ // at beginning of file)
+ XRefEntry *entries; // xref entries
+ int size; // size of <entries> array
+ int rootNum, rootGen; // catalog dict
+ GBool ok; // true if xref table is valid
+ Object trailerDict; // trailer dictionary
+ int lastXRefPos; // offset of last xref table
+ int *streamEnds; // 'endstream' positions - only used in
+ // damaged files
+ int streamEndsLen; // number of valid entries in streamEnds
+#ifndef NO_DECRYPTION
+ GBool encrypted; // true if file is encrypted
+ int encVersion; // encryption algorithm
+ int encRevision; // security handler revision
+ int keyLength; // length of key, in bytes
+ int permFlags; // permission bits
+ Guchar fileKey[16]; // file decryption key
+ GBool ownerPasswordOk; // true if owner password is correct
+#endif
+
+ int readTrailer();
+ GBool readXRef(int *pos);
+ GBool constructXRef();
+ GBool checkEncrypted(GString *ownerPassword, GString *userPassword);
+};
+
+#endif
diff --git a/pdftops/config.h b/pdftops/config.h
new file mode 100644
index 000000000..f2b889b73
--- /dev/null
+++ b/pdftops/config.h
@@ -0,0 +1,140 @@
+//========================================================================
+//
+// config.h
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifndef CONFIG_H
+#define CONFIG_H
+
+#include <config.h>
+#define HAVE_LIBCUPS
+
+//------------------------------------------------------------------------
+// general constants
+//------------------------------------------------------------------------
+
+// xpdf version
+#define xpdfVersion "0.93a"
+
+// supported PDF version
+#define supportedPDFVersionStr "1.4"
+#define supportedPDFVersionNum 1.4
+
+// copyright notice
+#define xpdfCopyright "Copyright 1996-2002 Derek B. Noonburg"
+
+// default paper size (in points) for PostScript output
+#ifdef A4_PAPER
+#define defPaperWidth 595 // ISO A4 (210x297 mm)
+#define defPaperHeight 842
+#else
+#define defPaperWidth 612 // American letter (8.5x11")
+#define defPaperHeight 792
+#endif
+
+// user config file name, relative to the user's home directory
+#if defined(VMS)
+#define xpdfUserConfigFile "xpdfrc"
+#else
+#define xpdfUserConfigFile ".xpdfrc"
+#endif
+
+#ifndef SYSTEM_XPDFRC
+# define SYSTEM_XPDFRC CUPS_SERVERROOT "/pdftops.conf"
+#endif // SYSTEM_XPDFRC
+
+// system config file name (set via the configure script)
+#define xpdfSysConfigFile SYSTEM_XPDFRC
+
+// Support Unicode/etc.
+//
+// The IBM AIX GNUPro compilers seem not to like the Asian font
+// code, causing a "virtual memory exhausted" error. Only support
+// Asian fonts on platforms that will compile it...
+
+#if !defined(_AIX) || __GNUC__ != 2 || __GNUC_MINOR__ != 9
+# define JAPANESE_SUPPORT 1
+# define CHINESE_GB_SUPPORT 1
+# define CHINESE_CNS_SUPPORT 1
+#endif // !_AIX || !GCC 2.9
+
+//------------------------------------------------------------------------
+// X-related constants
+//------------------------------------------------------------------------
+
+// default maximum size of color cube to allocate
+#define defaultRGBCube 5
+
+// number of X server fonts to cache
+#define serverFontCacheSize 16
+
+// number of Type 1 (t1lib) fonts to cache
+#define t1FontCacheSize 32
+
+// number of TrueType (FreeType) fonts to cache
+#define ttFontCacheSize 32
+
+// number of FreeType (TrueType and Type 1) fonts to cache
+#define ftFontCacheSize 32
+
+//------------------------------------------------------------------------
+// popen
+//------------------------------------------------------------------------
+
+#ifdef _MSC_VER
+#define popen _popen
+#define pclose _pclose
+#endif
+
+#if defined(VMS) || defined(VMCMS) || defined(DOS) || defined(OS2) || defined(__EMX__) || defined(WIN32) || defined(__DJGPP__) || defined(__CYGWIN32__) || defined(MACOS)
+#define POPEN_READ_MODE "rb"
+#else
+#define POPEN_READ_MODE "r"
+#endif
+
+//------------------------------------------------------------------------
+// uncompress program
+//------------------------------------------------------------------------
+
+#ifdef HAVE_POPEN
+
+// command to uncompress to stdout
+# ifdef USE_GZIP
+# define uncompressCmd "gzip -d -c -q"
+# else
+# ifdef __EMX__
+# define uncompressCmd "compress -d -c"
+# else
+# define uncompressCmd "uncompress -c"
+# endif // __EMX__
+# endif // USE_GZIP
+
+#else // HAVE_POPEN
+
+// command to uncompress a file
+# ifdef USE_GZIP
+# define uncompressCmd "gzip -d -q"
+# else
+# define uncompressCmd "uncompress"
+# endif // USE_GZIP
+
+#endif // HAVE_POPEN
+
+//------------------------------------------------------------------------
+// Win32 stuff
+//------------------------------------------------------------------------
+
+#ifdef CDECL
+#undef CDECL
+#endif
+
+#ifdef _MSC_VER
+#define CDECL __cdecl
+#else
+#define CDECL
+#endif
+
+#endif
diff --git a/pdftops/gfile.cxx b/pdftops/gfile.cxx
new file mode 100644
index 000000000..e6428b71b
--- /dev/null
+++ b/pdftops/gfile.cxx
@@ -0,0 +1,678 @@
+//========================================================================
+//
+// gfile.cc
+//
+// Miscellaneous file and directory name manipulation.
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifdef WIN32
+ extern "C" {
+# ifndef _MSC_VER
+# include <kpathsea/win32lib.h>
+# endif
+ }
+#else // !WIN32
+# if defined(MACOS)
+# include <sys/stat.h>
+# elif !defined(ACORN)
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <fcntl.h>
+# endif
+# include <limits.h>
+# include <string.h>
+# if !defined(VMS) && !defined(ACORN) && !defined(MACOS)
+# include <pwd.h>
+# endif
+# if defined(VMS) && (__DECCXX_VER < 50200000)
+# include <unixlib.h>
+# endif
+#endif // WIN32
+#include "GString.h"
+#include "gfile.h"
+
+#ifdef HAVE_LIBCUPS
+# include <cups/cups.h>
+#endif // HAVE_LIBCUPS
+
+#ifdef __sun
+// Solaris doesn't define mkstemp()...
+extern "C" {
+extern int mkstemp(char *);
+}
+#endif // __sun
+
+// Some systems don't define this, so just make it something reasonably
+// large.
+#ifndef PATH_MAX
+#define PATH_MAX 1024
+#endif
+
+//------------------------------------------------------------------------
+
+GString *getHomeDir() {
+#ifdef VMS
+ //---------- VMS ----------
+ return new GString("SYS$LOGIN:");
+
+#elif defined(__EMX__) || defined(WIN32)
+ //---------- OS/2+EMX and Win32 ----------
+ char *s;
+ GString *ret;
+
+ if ((s = getenv("HOME")))
+ ret = new GString(s);
+ else
+ ret = new GString(".");
+ return ret;
+
+#elif defined(ACORN)
+ //---------- RISCOS ----------
+ return new GString("@");
+
+#elif defined(MACOS)
+ //---------- MacOS ----------
+ return new GString(":");
+
+#else
+ //---------- Unix ----------
+ char *s;
+ struct passwd *pw;
+ GString *ret;
+
+ if ((s = getenv("HOME"))) {
+ ret = new GString(s);
+# ifdef HAVE_LIBCUPS
+ } else if ((s = getenv("CUPS_SERVERROOT"))) {
+ ret = new GString(s);
+# endif // HAVE_LIBCUPS
+ } else {
+ if ((s = getenv("USER")))
+ pw = getpwnam(s);
+ else
+ pw = getpwuid(getuid());
+ if (pw)
+ ret = new GString(pw->pw_dir);
+ else
+ ret = new GString(".");
+ }
+ return ret;
+#endif
+}
+
+GString *getCurrentDir() {
+ char buf[PATH_MAX+1];
+
+#if defined(__EMX__)
+ if (_getcwd2(buf, sizeof(buf)))
+#elif defined(WIN32)
+ if (GetCurrentDirectory(sizeof(buf), buf))
+#elif defined(ACORN)
+ if (strcpy(buf, "@"))
+#elif defined(MACOS)
+ if (strcpy(buf, ":"))
+#else
+ if (getcwd(buf, sizeof(buf)))
+#endif
+ return new GString(buf);
+ return new GString();
+}
+
+GString *appendToPath(GString *path, const char *fileName) {
+#if defined(VMS)
+ //---------- VMS ----------
+ //~ this should handle everything necessary for file
+ //~ requesters, but it's certainly not complete
+ char *p0, *p1, *p2;
+ char *q1;
+
+ p0 = path->getCString();
+ p1 = p0 + path->getLength() - 1;
+ if (!strcmp(fileName, "-")) {
+ if (*p1 == ']') {
+ for (p2 = p1; p2 > p0 && *p2 != '.' && *p2 != '['; --p2) ;
+ if (*p2 == '[')
+ ++p2;
+ path->del(p2 - p0, p1 - p2);
+ } else if (*p1 == ':') {
+ path->append("[-]");
+ } else {
+ path->clear();
+ path->append("[-]");
+ }
+ } else if ((q1 = strrchr(fileName, '.')) && !strncmp(q1, ".DIR;", 5)) {
+ if (*p1 == ']') {
+ path->insert(p1 - p0, '.');
+ path->insert(p1 - p0 + 1, fileName, q1 - fileName);
+ } else if (*p1 == ':') {
+ path->append('[');
+ path->append(']');
+ path->append(fileName, q1 - fileName);
+ } else {
+ path->clear();
+ path->append(fileName, q1 - fileName);
+ }
+ } else {
+ if (*p1 != ']' && *p1 != ':')
+ path->clear();
+ path->append(fileName);
+ }
+ return path;
+
+#elif defined(WIN32)
+ //---------- Win32 ----------
+ GString *tmp;
+ char buf[256];
+ char *fp;
+
+ tmp = new GString(path);
+ tmp->append('/');
+ tmp->append(fileName);
+ GetFullPathName(tmp->getCString(), sizeof(buf), buf, &fp);
+ delete tmp;
+ path->clear();
+ path->append(buf);
+ return path;
+
+#elif defined(ACORN)
+ //---------- RISCOS ----------
+ char *p;
+ int i;
+
+ path->append(".");
+ i = path->getLength();
+ path->append(fileName);
+ for (p = path->getCString() + i; *p; ++p) {
+ if (*p == '/') {
+ *p = '.';
+ } else if (*p == '.') {
+ *p = '/';
+ }
+ }
+ return path;
+
+#elif defined(MACOS)
+ //---------- MacOS ----------
+ char *p;
+ int i;
+
+ path->append(":");
+ i = path->getLength();
+ path->append(fileName);
+ for (p = path->getCString() + i; *p; ++p) {
+ if (*p == '/') {
+ *p = ':';
+ } else if (*p == '.') {
+ *p = ':';
+ }
+ }
+ return path;
+
+#elif defined(__EMX__)
+ //---------- OS/2+EMX ----------
+ int i;
+
+ // appending "." does nothing
+ if (!strcmp(fileName, "."))
+ return path;
+
+ // appending ".." goes up one directory
+ if (!strcmp(fileName, "..")) {
+ for (i = path->getLength() - 2; i >= 0; --i) {
+ if (path->getChar(i) == '/' || path->getChar(i) == '\\' ||
+ path->getChar(i) == ':')
+ break;
+ }
+ if (i <= 0) {
+ if (path->getChar(0) == '/' || path->getChar(0) == '\\') {
+ path->del(1, path->getLength() - 1);
+ } else if (path->getLength() >= 2 && path->getChar(1) == ':') {
+ path->del(2, path->getLength() - 2);
+ } else {
+ path->clear();
+ path->append("..");
+ }
+ } else {
+ if (path->getChar(i-1) == ':')
+ ++i;
+ path->del(i, path->getLength() - i);
+ }
+ return path;
+ }
+
+ // otherwise, append "/" and new path component
+ if (path->getLength() > 0 &&
+ path->getChar(path->getLength() - 1) != '/' &&
+ path->getChar(path->getLength() - 1) != '\\')
+ path->append('/');
+ path->append(fileName);
+ return path;
+
+#else
+ //---------- Unix ----------
+ int i;
+
+ // appending "." does nothing
+ if (!strcmp(fileName, "."))
+ return path;
+
+ // appending ".." goes up one directory
+ if (!strcmp(fileName, "..")) {
+ for (i = path->getLength() - 2; i >= 0; --i) {
+ if (path->getChar(i) == '/')
+ break;
+ }
+ if (i <= 0) {
+ if (path->getChar(0) == '/') {
+ path->del(1, path->getLength() - 1);
+ } else {
+ path->clear();
+ path->append("..");
+ }
+ } else {
+ path->del(i, path->getLength() - i);
+ }
+ return path;
+ }
+
+ // otherwise, append "/" and new path component
+ if (path->getLength() > 0 &&
+ path->getChar(path->getLength() - 1) != '/')
+ path->append('/');
+ path->append(fileName);
+ return path;
+#endif
+}
+
+GString *grabPath(const char *fileName) {
+#ifdef VMS
+ //---------- VMS ----------
+ const char *p;
+
+ if ((p = strrchr(fileName, ']')))
+ return new GString(fileName, p + 1 - fileName);
+ if ((p = strrchr(fileName, ':')))
+ return new GString(fileName, p + 1 - fileName);
+ return new GString();
+
+#elif defined(__EMX__) || defined(WIN32)
+ //---------- OS/2+EMX and Win32 ----------
+ const char *p;
+
+ if ((p = strrchr(fileName, '/')))
+ return new GString(fileName, p - fileName);
+ if ((p = strrchr(fileName, '\\')))
+ return new GString(fileName, p - fileName);
+ if ((p = strrchr(fileName, ':')))
+ return new GString(fileName, p + 1 - fileName);
+ return new GString();
+
+#elif defined(ACORN)
+ //---------- RISCOS ----------
+ const char *p;
+
+ if ((p = strrchr(fileName, '.')))
+ return new GString(fileName, p - fileName);
+ return new GString();
+
+#elif defined(MACOS)
+ //---------- MacOS ----------
+ const char *p;
+
+ if ((p = strrchr(fileName, ':')))
+ return new GString(fileName, p - fileName);
+ return new GString();
+
+#else
+ //---------- Unix ----------
+ const char *p;
+
+ if ((p = strrchr(fileName, '/')))
+ return new GString(fileName, p - fileName);
+ return new GString();
+#endif
+}
+
+GBool isAbsolutePath(const char *path) {
+#ifdef VMS
+ //---------- VMS ----------
+ return strchr(path, ':') ||
+ (path[0] == '[' && path[1] != '.' && path[1] != '-');
+
+#elif defined(__EMX__) || defined(WIN32)
+ //---------- OS/2+EMX and Win32 ----------
+ return path[0] == '/' || path[0] == '\\' || path[1] == ':';
+
+#elif defined(ACORN)
+ //---------- RISCOS ----------
+ return path[0] == '$';
+
+#elif defined(MACOS)
+ //---------- MacOS ----------
+ return path[0] != ':';
+
+#else
+ //---------- Unix ----------
+ return path[0] == '/';
+#endif
+}
+
+GString *makePathAbsolute(GString *path) {
+#ifdef VMS
+ //---------- VMS ----------
+ char buf[PATH_MAX+1];
+
+ if (!isAbsolutePath(path->getCString())) {
+ if (getcwd(buf, sizeof(buf))) {
+ path->insert(0, buf);
+ }
+ }
+ return path;
+
+#elif defined(WIN32)
+ //---------- Win32 ----------
+ char buf[_MAX_PATH];
+ char *fp;
+
+ buf[0] = '\0';
+ if (!GetFullPathName(path->getCString(), _MAX_PATH, buf, &fp)) {
+ path->clear();
+ return path;
+ }
+ path->clear();
+ path->append(buf);
+ return path;
+
+#elif defined(ACORN)
+ //---------- RISCOS ----------
+ path->insert(0, '@');
+ return path;
+
+#elif defined(MACOS)
+ //---------- MacOS ----------
+ path->del(0, 1);
+ return path;
+
+#else
+ //---------- Unix and OS/2+EMX ----------
+ struct passwd *pw;
+ char buf[PATH_MAX+1];
+ GString *s;
+ char *p1, *p2;
+ int n;
+
+ if (path->getChar(0) == '~') {
+ if (path->getChar(1) == '/' ||
+#ifdef __EMX__
+ path->getChar(1) == '\\' ||
+#endif
+ path->getLength() == 1) {
+ path->del(0, 1);
+ s = getHomeDir();
+ path->insert(0, s);
+ delete s;
+ } else {
+ p1 = path->getCString() + 1;
+#ifdef __EMX__
+ for (p2 = p1; *p2 && *p2 != '/' && *p2 != '\\'; ++p2) ;
+#else
+ for (p2 = p1; *p2 && *p2 != '/'; ++p2) ;
+#endif
+ if ((n = p2 - p1) > PATH_MAX)
+ n = PATH_MAX;
+ strncpy(buf, p1, n);
+ buf[n] = '\0';
+ if ((pw = getpwnam(buf))) {
+ path->del(0, p2 - p1 + 1);
+ path->insert(0, pw->pw_dir);
+ }
+ }
+ } else if (!isAbsolutePath(path->getCString())) {
+ if (getcwd(buf, sizeof(buf))) {
+#ifndef __EMX__
+ path->insert(0, '/');
+#endif
+ path->insert(0, buf);
+ }
+ }
+ return path;
+#endif
+}
+
+time_t getModTime(const char *fileName) {
+#ifdef WIN32
+ //~ should implement this, but it's (currently) only used in xpdf
+ return 0;
+#else
+ struct stat statBuf;
+
+ if (stat(fileName, &statBuf)) {
+ return 0;
+ }
+ return statBuf.st_mtime;
+#endif
+}
+
+GBool openTempFile(GString **name, FILE **f, const char *mode, const char *ext) {
+#if defined(VMS) || defined(__EMX__) || defined(WIN32) || defined(ACORN) || defined(MACOS)
+ //---------- non-Unix ----------
+ char *s;
+
+ // There is a security hole here: an attacker can create a symlink
+ // with this file name after the tmpnam call and before the fopen
+ // call. I will happily accept fixes to this function for non-Unix
+ // OSs.
+ if (!(s = tmpnam(NULL))) {
+ return gFalse;
+ }
+ *name = new GString(s);
+ if (ext) {
+ (*name)->append(ext);
+ }
+ if (!(*f = fopen((*name)->getCString(), mode))) {
+ delete (*name);
+ return gFalse;
+ }
+ return gTrue;
+#else
+ //---------- Unix ----------
+ char *s;
+ int fd;
+
+ // MRS: Currently there is no standard function for creating a temporary
+ // file with an extension; this is required when uncompressing
+ // LZW data using the uncompress program on some UNIX, which is
+ // looking for a ".Z" extension on the temporary filename. Sooo,
+ // when you print an *OLD* PDF file that uses LZW compression,
+ // the tmpnam() function is usually the one that is called to
+ // create the temporary file. Under *BSD, the safer mkstemps()
+ // function is used instead.
+ //
+ // That said, all CUPS filters are run with TMPDIR pointing to
+ // a private temporary directory, which by default is only
+ // accessible to the 'lp' user. Also, most files use Flate
+ // compression now and will be able to use the (safer)
+ // mkstemp() function for any temporary files...
+
+ if (ext) {
+# if HAVE_MKSTEMPS
+ if ((s = getenv("TMPDIR"))) {
+ *name = new GString(s);
+ } else {
+ *name = new GString("/tmp");
+ }
+ (*name)->append("/XXXXXX");
+ (*name)->append(ext);
+ fd = mkstemps((*name)->getCString(), strlen(ext));
+# else // HAVE_MKSTEMPS
+ char *p;
+ if (!(s = tmpnam(NULL))) {
+ return gFalse;
+ }
+ *name = new GString(s);
+ s = (*name)->getCString();
+ if ((p = strrchr(s, '.'))) {
+ (*name)->del(p - s, (*name)->getLength() - (p - s));
+ }
+ (*name)->append(ext);
+ fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600);
+# endif // HAVE_MKSTEMPS
+ } else {
+# if HAVE_MKSTEMP
+ if ((s = getenv("TMPDIR"))) {
+ *name = new GString(s);
+ } else {
+ *name = new GString("/tmp");
+ }
+ (*name)->append("/XXXXXX");
+ fd = mkstemp((*name)->getCString());
+# else // HAVE_MKSTEMP
+ if (!(s = tmpnam(NULL))) {
+ return gFalse;
+ }
+ *name = new GString(s);
+ fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600);
+# endif // HAVE_MKSTEMP
+ }
+ if (fd < 0 || !(*f = fdopen(fd, mode))) {
+ delete *name;
+ return gFalse;
+ }
+ return gTrue;
+#endif
+}
+
+//------------------------------------------------------------------------
+// GDir and GDirEntry
+//------------------------------------------------------------------------
+
+GDirEntry::GDirEntry(const char *dirPath, const char *name1, GBool doStat) {
+#ifdef VMS
+ char *p;
+#elif defined(WIN32)
+ int fa;
+ GString *s;
+#elif defined(ACORN)
+#else
+ struct stat st;
+ GString *s;
+#endif
+
+ name = new GString(name1);
+ dir = gFalse;
+ if (doStat) {
+#ifdef VMS
+ if (!strcmp(name1, "-") ||
+ ((p = strrchr(name1, '.')) && !strncmp(p, ".DIR;", 5)))
+ dir = gTrue;
+#elif defined(ACORN)
+#else
+ s = new GString(dirPath);
+ appendToPath(s, name1);
+#ifdef WIN32
+ fa = GetFileAttributes(s->getCString());
+ dir = (fa != 0xFFFFFFFF && (fa & FILE_ATTRIBUTE_DIRECTORY));
+#else
+ if (stat(s->getCString(), &st) == 0)
+ dir = S_ISDIR(st.st_mode);
+#endif
+ delete s;
+#endif
+ }
+}
+
+GDirEntry::~GDirEntry() {
+ delete name;
+}
+
+GDir::GDir(const char *name, GBool doStat1) {
+ path = new GString(name);
+ doStat = doStat1;
+#if defined(WIN32)
+ GString *tmp;
+
+ tmp = path->copy();
+ tmp->append("/*.*");
+ hnd = FindFirstFile(tmp->getCString(), &ffd);
+ delete tmp;
+#elif defined(ACORN)
+#elif defined(MACOS)
+#else
+ dir = opendir(name);
+#ifdef VMS
+ needParent = strchr(name, '[') != NULL;
+#endif
+#endif
+}
+
+GDir::~GDir() {
+ delete path;
+#if defined(WIN32)
+ if (hnd) {
+ FindClose(hnd);
+ hnd = NULL;
+ }
+#elif defined(ACORN)
+#elif defined(MACOS)
+#else
+ if (dir)
+ closedir(dir);
+#endif
+}
+
+GDirEntry *GDir::getNextEntry() {
+ struct dirent *ent;
+ GDirEntry *e;
+
+ e = NULL;
+#if defined(WIN32)
+ e = new GDirEntry(path->getCString(), ffd.cFileName, doStat);
+ if (hnd && !FindNextFile(hnd, &ffd)) {
+ FindClose(hnd);
+ hnd = NULL;
+ }
+#elif defined(ACORN)
+#elif defined(MACOS)
+#else
+ if (dir) {
+#ifdef VMS
+ if (needParent) {
+ e = new GDirEntry(path->getCString(), "-", doStat);
+ needParent = gFalse;
+ return e;
+ }
+#endif
+ ent = readdir(dir);
+#ifndef VMS
+ if (ent && !strcmp(ent->d_name, "."))
+ ent = readdir(dir);
+#endif
+ if (ent)
+ e = new GDirEntry(path->getCString(), ent->d_name, doStat);
+ }
+#endif
+ return e;
+}
+
+void GDir::rewind() {
+#ifdef WIN32
+ GString *tmp;
+
+ if (hnd)
+ FindClose(hnd);
+ tmp = path->copy();
+ tmp->append("/*.*");
+ hnd = FindFirstFile(tmp->getCString(), &ffd);
+#elif defined(ACORN)
+#elif defined(MACOS)
+#else
+ if (dir)
+ rewinddir(dir);
+#ifdef VMS
+ needParent = strchr(path->getCString(), '[') != NULL;
+#endif
+#endif
+}
diff --git a/pdftops/gfile.h b/pdftops/gfile.h
new file mode 100644
index 000000000..49c6888ca
--- /dev/null
+++ b/pdftops/gfile.h
@@ -0,0 +1,132 @@
+//========================================================================
+//
+// gfile.h
+//
+// Miscellaneous file and directory name manipulation.
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifndef GFILE_H
+#define GFILE_H
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#if defined(WIN32)
+# include <sys/stat.h>
+# ifdef FPTEX
+# include <win32lib.h>
+# else
+# include <windows.h>
+# endif
+#elif defined(ACORN)
+#elif defined(MACOS)
+# include <ctime.h>
+#else
+# include <unistd.h>
+# include <sys/types.h>
+# ifdef VMS
+# include "vms_dirent.h"
+# elif HAVE_DIRENT_H
+# include <dirent.h>
+# define NAMLEN(d) strlen((d)->d_name)
+# else
+# define dirent direct
+# define NAMLEN(d) (d)->d_namlen
+# if HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# if HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# if HAVE_NDIR_H
+# include <ndir.h>
+# endif
+# endif
+#endif
+#include "gtypes.h"
+
+class GString;
+
+//------------------------------------------------------------------------
+
+// Get home directory path.
+extern GString *getHomeDir();
+
+// Get current directory.
+extern GString *getCurrentDir();
+
+// Append a file name to a path string. <path> may be an empty
+// string, denoting the current directory). Returns <path>.
+extern GString *appendToPath(GString *path, const char *fileName);
+
+// Grab the path from the front of the file name. If there is no
+// directory component in <fileName>, returns an empty string.
+extern GString *grabPath(const char *fileName);
+
+// Is this an absolute path or file name?
+extern GBool isAbsolutePath(const char *path);
+
+// Make this path absolute by prepending current directory (if path is
+// relative) or prepending user's directory (if path starts with '~').
+GString *makePathAbsolute(GString *path);
+
+// Get the modification time for <fileName>. Returns 0 if there is an
+// error.
+time_t getModTime(const char *fileName);
+
+// Create a temporary file and open it for writing. If <ext> is not
+// NULL, it will be used as the file name extension. Returns both the
+// name and the file pointer. For security reasons, all writing
+// should be done to the returned file pointer; the file may be
+// reopened later for reading, but not for writing. The <mode> string
+// should be "w" or "wb". Returns true on success.
+GBool openTempFile(GString **name, FILE **f, const char *mode, const char *ext);
+
+//------------------------------------------------------------------------
+// GDir and GDirEntry
+//------------------------------------------------------------------------
+
+class GDirEntry {
+public:
+
+ GDirEntry(const char *dirPath, const char *name1, GBool doStat);
+ ~GDirEntry();
+ GString *getName() { return name; }
+ GBool isDir() { return dir; }
+
+private:
+
+ GString *name; // dir/file name
+ GBool dir; // is it a directory?
+};
+
+class GDir {
+public:
+
+ GDir(const char *name, GBool doStat1 = gTrue);
+ ~GDir();
+ GDirEntry *getNextEntry();
+ void rewind();
+
+private:
+
+ GString *path; // directory path
+ GBool doStat; // call stat() for each entry?
+#if defined(WIN32)
+ WIN32_FIND_DATA ffd;
+ HANDLE hnd;
+#elif defined(ACORN)
+#elif defined(MACOS)
+#else
+ DIR *dir; // the DIR structure from opendir()
+#ifdef VMS
+ GBool needParent; // need to return an entry for [-]
+#endif
+#endif
+};
+
+#endif
diff --git a/pdftops/gmem.c b/pdftops/gmem.c
new file mode 100644
index 000000000..5b3743db3
--- /dev/null
+++ b/pdftops/gmem.c
@@ -0,0 +1,203 @@
+/*
+ * gmem.c
+ *
+ * Memory routines with out-of-memory checking.
+ *
+ * Copyright 1996 Derek B. Noonburg
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include "gmem.h"
+
+#ifdef DEBUG_MEM
+
+typedef struct _GMemHdr {
+ int size;
+ int index;
+ struct _GMemHdr *next;
+} GMemHdr;
+
+#define gMemHdrSize ((sizeof(GMemHdr) + 7) & ~7)
+#define gMemTrlSize (sizeof(long))
+
+#if gmemTrlSize==8
+#define gMemDeadVal 0xdeadbeefdeadbeef
+#else
+#define gMemDeadVal 0xdeadbeef
+#endif
+
+/* round data size so trailer will be aligned */
+#define gMemDataSize(size) \
+ ((((size) + gMemTrlSize - 1) / gMemTrlSize) * gMemTrlSize)
+
+#define gMemNLists 64
+#define gMemListShift 4
+#define gMemListMask (gMemNLists - 1)
+static GMemHdr *gMemList[gMemNLists] = {
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static int gMemIndex = 0;
+static int gMemAlloc = 0;
+
+#endif /* DEBUG_MEM */
+
+void *gmalloc(int size) {
+#ifdef DEBUG_MEM
+ int size1;
+ char *mem;
+ GMemHdr *hdr;
+ void *data;
+ int lst;
+ long *trl, *p;
+
+ if (size == 0)
+ return NULL;
+ size1 = gMemDataSize(size);
+ if (!(mem = (char *)malloc(size1 + gMemHdrSize + gMemTrlSize))) {
+ fprintf(stderr, "Out of memory\n");
+ exit(1);
+ }
+ hdr = (GMemHdr *)mem;
+ data = (void *)(mem + gMemHdrSize);
+ trl = (long *)(mem + gMemHdrSize + size1);
+ hdr->size = size;
+ hdr->index = gMemIndex++;
+ lst = ((int)hdr >> gMemListShift) & gMemListMask;
+ hdr->next = gMemList[lst];
+ gMemList[lst] = hdr;
+ ++gMemAlloc;
+ for (p = (long *)data; p <= trl; ++p)
+ *p = gMemDeadVal;
+ return data;
+#else
+ void *p;
+
+ if (size == 0)
+ return NULL;
+ if (!(p = malloc(size))) {
+ fprintf(stderr, "Out of memory\n");
+ exit(1);
+ }
+ return p;
+#endif
+}
+
+void *grealloc(void *p, int size) {
+#ifdef DEBUG_MEM
+ GMemHdr *hdr;
+ void *q;
+ int oldSize;
+
+ if (size == 0) {
+ if (p)
+ gfree(p);
+ return NULL;
+ }
+ if (p) {
+ hdr = (GMemHdr *)((char *)p - gMemHdrSize);
+ oldSize = hdr->size;
+ q = gmalloc(size);
+ memcpy(q, p, size < oldSize ? size : oldSize);
+ gfree(p);
+ } else {
+ q = gmalloc(size);
+ }
+ return q;
+#else
+ void *q;
+
+ if (size == 0) {
+ if (p)
+ free(p);
+ return NULL;
+ }
+ if (p)
+ q = realloc(p, size);
+ else
+ q = malloc(size);
+ if (!q) {
+ fprintf(stderr, "Out of memory\n");
+ exit(1);
+ }
+ return q;
+#endif
+}
+
+void gfree(void *p) {
+#ifdef DEBUG_MEM
+ int size;
+ GMemHdr *hdr;
+ GMemHdr *prevHdr, *q;
+ int lst;
+ long *trl, *clr;
+
+ if (p) {
+ hdr = (GMemHdr *)((char *)p - gMemHdrSize);
+ lst = ((int)hdr >> gMemListShift) & gMemListMask;
+ for (prevHdr = NULL, q = gMemList[lst]; q; prevHdr = q, q = q->next) {
+ if (q == hdr)
+ break;
+ }
+ if (q) {
+ if (prevHdr)
+ prevHdr->next = hdr->next;
+ else
+ gMemList[lst] = hdr->next;
+ --gMemAlloc;
+ size = gMemDataSize(hdr->size);
+ trl = (long *)((char *)hdr + gMemHdrSize + size);
+ if (*trl != gMemDeadVal) {
+ fprintf(stderr, "Overwrite past end of block %d at address %p\n",
+ hdr->index, p);
+ }
+ for (clr = (long *)hdr; clr <= trl; ++clr)
+ *clr = gMemDeadVal;
+ free(hdr);
+ } else {
+ fprintf(stderr, "Attempted to free bad address %p\n", p);
+ }
+ }
+#else
+ if (p)
+ free(p);
+#endif
+}
+
+#ifdef DEBUG_MEM
+void gMemReport(FILE *f) {
+ GMemHdr *p;
+ int lst;
+
+ fprintf(f, "%d memory allocations in all\n", gMemIndex);
+ if (gMemAlloc > 0) {
+ fprintf(f, "%d memory blocks left allocated:\n", gMemAlloc);
+ fprintf(f, " index size\n");
+ fprintf(f, "-------- --------\n");
+ for (lst = 0; lst < gMemNLists; ++lst) {
+ for (p = gMemList[lst]; p; p = p->next)
+ fprintf(f, "%8d %8d\n", p->index, p->size);
+ }
+ } else {
+ fprintf(f, "No memory blocks left allocated\n");
+ }
+}
+#endif
+
+char *copyString(const char *s) {
+ char *s1;
+
+ s1 = (char *)gmalloc(strlen(s) + 1);
+ strcpy(s1, s);
+ return s1;
+}
diff --git a/pdftops/gmem.h b/pdftops/gmem.h
new file mode 100644
index 000000000..8c8ca1f4a
--- /dev/null
+++ b/pdftops/gmem.h
@@ -0,0 +1,53 @@
+/*
+ * gmem.h
+ *
+ * Memory routines with out-of-memory checking.
+ *
+ * Copyright 1996 Derek B. Noonburg
+ */
+
+#ifndef GMEM_H
+#define GMEM_H
+
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Same as malloc, but prints error message and exits if malloc()
+ * returns NULL.
+ */
+extern void *gmalloc(int size);
+
+/*
+ * Same as realloc, but prints error message and exits if realloc()
+ * returns NULL. If <p> is NULL, calls malloc instead of realloc().
+ */
+extern void *grealloc(void *p, int size);
+
+/*
+ * Same as free, but checks for and ignores NULL pointers.
+ */
+extern void gfree(void *p);
+
+#ifdef DEBUG_MEM
+/*
+ * Report on unfreed memory.
+ */
+extern void gMemReport(FILE *f);
+#else
+#define gMemReport(f)
+#endif
+
+/*
+ * Allocate memory and copy a string into it.
+ */
+extern char *copyString(const char *s);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/pdftops/gmempp.cxx b/pdftops/gmempp.cxx
new file mode 100644
index 000000000..6eb64948d
--- /dev/null
+++ b/pdftops/gmempp.cxx
@@ -0,0 +1,31 @@
+//========================================================================
+//
+// gmempp.cc
+//
+// Use gmalloc/gfree for C++ new/delete operators.
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#include "gmem.h"
+
+#ifdef DEBUG_MEM
+
+void *operator new(size_t size) {
+ return gmalloc((int)size);
+}
+
+void *operator new[](size_t size) {
+ return gmalloc((int)size);
+}
+
+void operator delete(void *p) {
+ gfree(p);
+}
+
+void operator delete[](void *p) {
+ gfree(p);
+}
+
+#endif
diff --git a/pdftops/gtypes.h b/pdftops/gtypes.h
new file mode 100644
index 000000000..7a3487663
--- /dev/null
+++ b/pdftops/gtypes.h
@@ -0,0 +1,31 @@
+/*
+ * gtypes.h
+ *
+ * Some useful simple types.
+ *
+ * Copyright 1996 Derek B. Noonburg
+ */
+
+#ifndef GTYPES_H
+#define GTYPES_H
+
+#define HAVE_LIBCUPS
+
+/*
+ * These have stupid names to avoid conflicts with some (but not all)
+ * C++ compilers which define them.
+ */
+typedef int GBool;
+#define gTrue 1
+#define gFalse 0
+
+/*
+ * These have stupid names to avoid conflicts with <sys/types.h>,
+ * which on various systems defines some random subset of these.
+ */
+typedef unsigned char Guchar;
+typedef unsigned short Gushort;
+typedef unsigned int Guint;
+typedef unsigned long Gulong;
+
+#endif
diff --git a/pdftops/parseargs.c b/pdftops/parseargs.c
new file mode 100644
index 000000000..ceba88779
--- /dev/null
+++ b/pdftops/parseargs.c
@@ -0,0 +1,190 @@
+/*
+ * parseargs.h
+ *
+ * Command line argument parser.
+ *
+ * Copyright 1996 Derek B. Noonburg
+ */
+
+#include <stdio.h>
+#include <stddef.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include "parseargs.h"
+
+static ArgDesc *findArg(ArgDesc *args, char *arg);
+static GBool grabArg(ArgDesc *arg, int i, int *argc, char *argv[]);
+
+GBool parseArgs(ArgDesc *args, int *argc, char *argv[]) {
+ ArgDesc *arg;
+ int i, j;
+ GBool ok;
+
+ ok = gTrue;
+ i = 1;
+ while (i < *argc) {
+ if (!strcmp(argv[i], "--")) {
+ --*argc;
+ for (j = i; j < *argc; ++j)
+ argv[j] = argv[j+1];
+ break;
+ } else if ((arg = findArg(args, argv[i]))) {
+ if (!grabArg(arg, i, argc, argv))
+ ok = gFalse;
+ } else {
+ ++i;
+ }
+ }
+ return ok;
+}
+
+void printUsage(char *program, char *otherArgs, ArgDesc *args) {
+ ArgDesc *arg;
+ char *typ;
+ int w, w1;
+
+ w = 0;
+ for (arg = args; arg->arg; ++arg) {
+ if ((w1 = strlen(arg->arg)) > w)
+ w = w1;
+ }
+
+ fprintf(stderr, "Usage: %s [options]", program);
+ if (otherArgs)
+ fprintf(stderr, " %s", otherArgs);
+ fprintf(stderr, "\n");
+
+ for (arg = args; arg->arg; ++arg) {
+ fprintf(stderr, " %s", arg->arg);
+ w1 = 9 + w - strlen(arg->arg);
+ switch (arg->kind) {
+ case argInt:
+ case argIntDummy:
+ typ = " <int>";
+ break;
+ case argFP:
+ case argFPDummy:
+ typ = " <fp>";
+ break;
+ case argString:
+ case argStringDummy:
+ typ = " <string>";
+ break;
+ case argFlag:
+ case argFlagDummy:
+ default:
+ typ = "";
+ break;
+ }
+ fprintf(stderr, "%-*s", w1, typ);
+ if (arg->usage)
+ fprintf(stderr, ": %s", arg->usage);
+ fprintf(stderr, "\n");
+ }
+}
+
+static ArgDesc *findArg(ArgDesc *args, char *arg) {
+ ArgDesc *p;
+
+ for (p = args; p->arg; ++p) {
+ if (p->kind < argFlagDummy && !strcmp(p->arg, arg))
+ return p;
+ }
+ return NULL;
+}
+
+static GBool grabArg(ArgDesc *arg, int i, int *argc, char *argv[]) {
+ int n;
+ int j;
+ GBool ok;
+
+ ok = gTrue;
+ n = 0;
+ switch (arg->kind) {
+ case argFlag:
+ *(GBool *)arg->val = gTrue;
+ n = 1;
+ break;
+ case argInt:
+ if (i + 1 < *argc && isInt(argv[i+1])) {
+ *(int *)arg->val = atoi(argv[i+1]);
+ n = 2;
+ } else {
+ ok = gFalse;
+ n = 1;
+ }
+ break;
+ case argFP:
+ if (i + 1 < *argc && isFP(argv[i+1])) {
+ *(double *)arg->val = atof(argv[i+1]);
+ n = 2;
+ } else {
+ ok = gFalse;
+ n = 1;
+ }
+ break;
+ case argString:
+ if (i + 1 < *argc) {
+ strncpy((char *)arg->val, argv[i+1], arg->size - 1);
+ ((char *)arg->val)[arg->size - 1] = '\0';
+ n = 2;
+ } else {
+ ok = gFalse;
+ n = 1;
+ }
+ break;
+ default:
+ fprintf(stderr, "Internal error in arg table\n");
+ n = 1;
+ break;
+ }
+ if (n > 0) {
+ *argc -= n;
+ for (j = i; j < *argc; ++j)
+ argv[j] = argv[j+n];
+ }
+ return ok;
+}
+
+GBool isInt(char *s) {
+ if (*s == '-' || *s == '+')
+ ++s;
+ while (isdigit(*s))
+ ++s;
+ if (*s)
+ return gFalse;
+ return gTrue;
+}
+
+GBool isFP(char *s) {
+ int n;
+
+ if (*s == '-' || *s == '+')
+ ++s;
+ n = 0;
+ while (isdigit(*s)) {
+ ++s;
+ ++n;
+ }
+ if (*s == '.')
+ ++s;
+ while (isdigit(*s)) {
+ ++s;
+ ++n;
+ }
+ if (n > 0 && (*s == 'e' || *s == 'E')) {
+ ++s;
+ if (*s == '-' || *s == '+')
+ ++s;
+ n = 0;
+ if (!isdigit(*s))
+ return gFalse;
+ do {
+ ++s;
+ } while (isdigit(*s));
+ }
+ if (*s)
+ return gFalse;
+ return gTrue;
+}
diff --git a/pdftops/parseargs.h b/pdftops/parseargs.h
new file mode 100644
index 000000000..e0aa2be33
--- /dev/null
+++ b/pdftops/parseargs.h
@@ -0,0 +1,71 @@
+/*
+ * parseargs.h
+ *
+ * Command line argument parser.
+ *
+ * Copyright 1996 Derek B. Noonburg
+ */
+
+#ifndef PARSEARGS_H
+#define PARSEARGS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "gtypes.h"
+
+/*
+ * Argument kinds.
+ */
+typedef enum {
+ argFlag, /* flag (present / not-present) */
+ /* [val: GBool *] */
+ argInt, /* integer arg */
+ /* [val: int *] */
+ argFP, /* floating point arg */
+ /* [val: double *] */
+ argString, /* string arg */
+ /* [val: char *] */
+ /* dummy entries -- these show up in the usage listing only; */
+ /* useful for X args, for example */
+ argFlagDummy,
+ argIntDummy,
+ argFPDummy,
+ argStringDummy
+} ArgKind;
+
+/*
+ * Argument descriptor.
+ */
+typedef struct {
+ char *arg; /* the command line switch */
+ ArgKind kind; /* kind of arg */
+ void *val; /* place to store value */
+ int size; /* for argString: size of string */
+ char *usage; /* usage string */
+} ArgDesc;
+
+/*
+ * Parse command line. Removes all args which are found in the arg
+ * descriptor list <args>. Stops parsing if "--" is found (and removes
+ * it). Returns gFalse if there was an error.
+ */
+extern GBool parseArgs(ArgDesc *args, int *argc, char *argv[]);
+
+/*
+ * Print usage message, based on arg descriptor list.
+ */
+extern void printUsage(char *program, char *otherArgs, ArgDesc *args);
+
+/*
+ * Check if a string is a valid integer or floating point number.
+ */
+extern GBool isInt(char *s);
+extern GBool isFP(char *s);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/pdftops/pdftops.cxx b/pdftops/pdftops.cxx
new file mode 100644
index 000000000..fe107f945
--- /dev/null
+++ b/pdftops/pdftops.cxx
@@ -0,0 +1,157 @@
+//========================================================================
+//
+// pdftops.cc
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include "parseargs.h"
+#include "GString.h"
+#include "gmem.h"
+#include "Object.h"
+#include "Stream.h"
+#include "Array.h"
+#include "Dict.h"
+#include "XRef.h"
+#include "Catalog.h"
+#include "Page.h"
+#include "PDFDoc.h"
+#include "PSOutputDev.h"
+#include "Params.h"
+#include "Error.h"
+#include "config.h"
+
+#include <cups/cups.h>
+
+int main(int argc, char *argv[]) {
+ PDFDoc *doc;
+ GString *fileName;
+ GString *psFileName;
+ PSOutLevel level;
+ PSOutputDev *psOut;
+ int num_options;
+ cups_option_t *options;
+ ppd_file_t *ppd;
+ ppd_size_t *size;
+ FILE *fp;
+ const char *server_root;
+ char tempfile[1024];
+ char buffer[8192];
+ int bytes;
+ int width, length;
+
+
+ // Make sure status messages are not buffered...
+ setbuf(stderr, NULL);
+
+ // Send all error messages...
+ errQuiet = 0;
+
+ // Make sure we have the right number of arguments for CUPS!
+ if (argc < 6 || argc > 7) {
+ fputs("Usage: pdftops job user title copies options [filename]\n", stderr);
+ return (1);
+ }
+
+ // Copy stdin if needed...
+ if (argc == 6) {
+ if ((fp = fopen(cupsTempFile(tempfile, sizeof(tempfile)), "w")) == NULL) {
+ perror("ERROR: Unable to copy PDF file");
+ return (1);
+ }
+
+ fprintf(stderr, "DEBUG: pdftops - copying to temp print file \"%s\"\n",
+ tempfile);
+
+ while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0)
+ fwrite(buffer, 1, bytes, fp);
+ fclose(fp);
+
+ fileName = new GString(tempfile);
+ } else {
+ fileName = new GString(argv[6]);
+ tempfile[0] = '\0';
+ }
+
+ // Default to "Universal" size - min of A4 and Letter...
+ width = 595;
+ length = 792;
+ level = psLevel2;
+
+ // Get PPD and initialize options as needed...
+ if ((ppd = ppdOpenFile(getenv("PPD"))) != NULL)
+ {
+ fprintf(stderr, "DEBUG: pdftops - opened PPD file \"%s\"...\n", getenv("PPD"));
+
+ ppdMarkDefaults(ppd);
+ num_options = cupsParseOptions(argv[5], 0, &options);
+ cupsMarkOptions(ppd, num_options, options);
+ cupsFreeOptions(num_options, options);
+
+ if ((size = ppdPageSize(ppd, NULL)) != NULL)
+ {
+ width = (int)size->width;
+ length = (int)size->length;
+ }
+
+ level = ppd->language_level == 1 ? psLevel1 : psLevel2;
+
+ ppdClose(ppd);
+ }
+
+ fprintf(stderr, "DEBUG: pdftops - level = %d, width = %d, length = %d\n",
+ level, width, length);
+
+ // init error file
+ errorInit();
+
+ // read config file
+ if ((server_root = getenv("CUPS_SERVERROOT")) == NULL)
+ server_root = CUPS_SERVERROOT;
+
+ sprintf(tempfile, "%s/pdftops.conf", server_root);
+ initParams("", tempfile);
+
+ // open PDF file
+ doc = new PDFDoc(fileName, NULL, NULL, getenv("DEBUG") != NULL);
+
+ // check for print permission
+ if (doc->isOk() && doc->okToPrint())
+ {
+ // CUPS always writes to stdout...
+ psFileName = new GString("-");
+
+ // write PostScript file
+ psOut = new PSOutputDev(psFileName->getCString(), doc->getXRef(),
+ doc->getCatalog(), 1, doc->getNumPages(),
+ level, psModePS, 0, 1, 1, width, length);
+ if (psOut->isOk())
+ doc->displayPages(psOut, 1, doc->getNumPages(), 72, 0, gFalse);
+ delete psOut;
+
+ // clean up
+ delete psFileName;
+ }
+ else
+ {
+ error(-1, "Unable to print this document.");
+ }
+
+ delete doc;
+ freeParams();
+
+ // check for memory leaks
+ Object::memCheck(stderr);
+ gMemReport(stderr);
+
+ // Remove temp file if needed...
+ if (tempfile[0])
+ unlink(tempfile);
+
+ return 0;
+}
diff --git a/ppd/Makefile b/ppd/Makefile
new file mode 100644
index 000000000..73fa3c194
--- /dev/null
+++ b/ppd/Makefile
@@ -0,0 +1,63 @@
+#
+# "$Id$"
+#
+# PPD file makefile for the Common UNIX Printing System (CUPS).
+#
+# Copyright 1993-2002 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 deskjet2.ppd dymo.ppd epson9.ppd epson24.ppd \
+ laserjet.ppd okidata9.ppd okidat24.ppd stcolor.ppd \
+ stcolor2.ppd stphoto.ppd stphoto2.ppd
+
+
+#
+# Make everything...
+#
+
+all:
+
+
+#
+# Clean all config and object files...
+#
+
+clean:
+
+
+#
+# Install files...
+#
+
+install:
+ $(INSTALL_DIR) $(DATADIR)/model
+ for file in $(FILES); do \
+ $(INSTALL_DATA) $$file $(DATADIR)/model; \
+ done
+
+
+#
+# End of "$Id$".
+#
diff --git a/ppd/deskjet.ppd b/ppd/deskjet.ppd
new file mode 100644
index 000000000..3df9a913b
--- /dev/null
+++ b/ppd/deskjet.ppd
@@ -0,0 +1,198 @@
+*PPD-Adobe: "4.3"
+*%
+*% "$Id$"
+*%
+*% Sample HP DeskJet driver PPD file for the Common UNIX Printing
+*% System (CUPS).
+*%
+*% Copyright 1997-2002 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"
+*cupsModelNumber: 1
+*ModelName: "HP DeskJet Series"
+*ShortNickName: "HP DeskJet Series"
+*NickName: "HP DeskJet Series CUPS v1.1"
+*PSVersion: "(3010.000) 550"
+*LanguageLevel: "3"
+*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 Tabloid *InputSlot Envelope
+*UIConstraints: *PageSize A3 *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/US Letter: "<</PageSize[612 792]/ImagingBBox null>>setpagedevice"
+*PageSize Legal/US Legal: "<</PageSize[612 1008]/ImagingBBox null>>setpagedevice"
+*PageSize Executive/US Executive: "<</PageSize[522 756]/ImagingBBox null>>setpagedevice"
+*PageSize Tabloid/US Tabloid: "<</PageSize[792 1224]/ImagingBBox null>>setpagedevice"
+*PageSize A3/A3: "<</PageSize[842 1191]/ImagingBBox null>>setpagedevice"
+*PageSize A4/A4: "<</PageSize[595 842]/ImagingBBox null>>setpagedevice"
+*PageSize A5/A5: "<</PageSize[421 595]/ImagingBBox null>>setpagedevice"
+*PageSize B5/B5 (JIS): "<</PageSize[516 729]/ImagingBBox null>>setpagedevice"
+*PageSize EnvISOB5/Envelope B5: "<</PageSize[499 709]/ImagingBBox null>>setpagedevice"
+*PageSize Env10/Envelope #10: "<</PageSize[297 684]/ImagingBBox null>>setpagedevice"
+*PageSize EnvC5/Envelope C5: "<</PageSize[459 649]/ImagingBBox null>>setpagedevice"
+*PageSize EnvDL/Envelope DL: "<</PageSize[312 624]/ImagingBBox null>>setpagedevice"
+*PageSize EnvMonarch/Envelope Monarch: "<</PageSize[279 540]/ImagingBBox null>>setpagedevice"
+*CloseUI: *PageSize
+
+*OpenUI *PageRegion: PickOne
+*OrderDependency: 10 AnySetup *PageRegion
+*DefaultPageRegion: Letter
+*PageRegion Letter/US Letter: "<</PageSize[612 792]/ImagingBBox null>>setpagedevice"
+*PageRegion Legal/US Legal: "<</PageSize[612 1008]/ImagingBBox null>>setpagedevice"
+*PageRegion Executive/US Executive: "<</PageSize[522 756]/ImagingBBox null>>setpagedevice"
+*PageRegion Tabloid/US Tabloid: "<</PageSize[792 1224]/ImagingBBox null>>setpagedevice"
+*PageRegion A3/A3: "<</PageSize[842 1191]/ImagingBBox null>>setpagedevice"
+*PageRegion A4/A4: "<</PageSize[595 842]/ImagingBBox null>>setpagedevice"
+*PageRegion A5/A5: "<</PageSize[421 595]/ImagingBBox null>>setpagedevice"
+*PageRegion B5/B5 (JIS): "<</PageSize[516 729]/ImagingBBox null>>setpagedevice"
+*PageRegion EnvISOB5/Envelope B5: "<</PageSize[499 709]/ImagingBBox null>>setpagedevice"
+*PageRegion Env10/Envelope #10: "<</PageSize[297 684]/ImagingBBox null>>setpagedevice"
+*PageRegion EnvC5/Envelope C5: "<</PageSize[459 649]/ImagingBBox null>>setpagedevice"
+*PageRegion EnvDL/Envelope DL: "<</PageSize[312 624]/ImagingBBox null>>setpagedevice"
+*PageRegion EnvMonarch/Envelope Monarch: "<</PageSize[279 540]/ImagingBBox null>>setpagedevice"
+*CloseUI: *PageRegion
+
+*DefaultImageableArea: Letter
+*ImageableArea Letter/US Letter: "18 36 594 756"
+*ImageableArea Legal/US Legal: "18 36 594 972"
+*ImageableArea Executive/US Executive: "18 36 504 684"
+*ImageableArea Tabloid/US Tabloid: "18 36 774 1188"
+*ImageableArea A3/A3: "18 36 824 1155"
+*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/US Letter: "612 792"
+*PaperDimension Legal/US Legal: "612 1008"
+*PaperDimension Executive/US Executive: "522 756"
+*PaperDimension Tabloid/US Tabloid: "792 1224"
+*PaperDimension A3/A3: "842 1191"
+*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: "<</MediaType(Plain)/cupsMediaType 0>>setpagedevice"
+*MediaType Bond/Bond Paper: "<</MediaType(Bond)/cupsMediaType 1>>setpagedevice"
+*MediaType Special/Special Paper: "<</MediaType(Special)/cupsMediaType 2>>setpagedevice"
+*MediaType Transparency/Transparency: "<</MediaType(Transparency)/cupsMediaType 3>>setpagedevice"
+*MediaType Glossy/Glossy Paper: "<</MediaType(Glossy)/cupsMediaType 4>>setpagedevice"
+*CloseUI: *MediaType
+
+*OpenUI *InputSlot/Media Source: PickOne
+*OrderDependency: 10 AnySetup *InputSlot
+*DefaultInputSlot: Tray
+*InputSlot Tray/Tray: "<</cupsMediaPosition 1>>setpagedevice"
+*InputSlot Manual/Manual Feed: "<</cupsMediaPosition 2>>setpagedevice"
+*InputSlot Envelope/Envelope Feed: "<</cupsMediaPosition 3>>setpagedevice"
+*CloseUI: *InputSlot
+
+*OpenUI *Resolution/Output Resolution: PickOne
+*OrderDependency: 20 AnySetup *Resolution
+*DefaultResolution: 300dpi
+*Resolution 150dpi/150 DPI: "<</HWResolution[150 150]>>setpagedevice"
+*Resolution 300dpi/300 DPI: "<</HWResolution[300 300]>>setpagedevice"
+*Resolution 600dpi/600 DPI: "<</HWResolution[600 600]/cupsColorSpace 3>>setpagedevice"
+*CloseUI: *Resolution
+
+*OpenUI *ColorModel/Output Mode: PickOne
+*OrderDependency: 10 AnySetup *ColorModel
+*DefaultColorModel: CMYK
+*ColorModel CMYK/CMYK Color: "<</cupsColorOrder 1/cupsColorSpace 8/cupsCompression 2>>setpagedevice"
+*ColorModel RGB/CMY Color: "<</cupsColorOrder 1/cupsColorSpace 4/cupsCompression 2>>setpagedevice"
+*ColorModel Gray/Grayscale: "<</cupsColorOrder 0/cupsColorSpace 3/cupsCompression 2>>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/deskjet2.ppd b/ppd/deskjet2.ppd
new file mode 100644
index 000000000..fa105ef1f
--- /dev/null
+++ b/ppd/deskjet2.ppd
@@ -0,0 +1,217 @@
+*PPD-Adobe: "4.3"
+*%
+*% "$Id$"
+*%
+*% Second sample HP DeskJet driver PPD file for the Common UNIX Printing
+*% System (CUPS).
+*%
+*% Copyright 1997-2002 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: "DESKJET2.PPD"
+*Manufacturer: "ESP"
+*Product: "(CUPS v1.1)"
+*cupsVersion: 1.1
+*cupsManualCopies: True
+*cupsFilter: "application/vnd.cups-raster 0 rastertohp"
+*cupsModelNumber: 2
+*cupsFlipDuplex: True
+*cupsColorProfile -/-: "1.0 1.5 1.0 -0.25 -0.225 -0.25 1.0 -0.225 -0.25 -0.25 0.9"
+
+*ModelName: "HP New DeskJet Series"
+*ShortNickName: "HP New DeskJet Series"
+*NickName: "HP New DeskJet Series CUPS v1.1"
+*PSVersion: "(3010.000) 550"
+*LanguageLevel: "3"
+*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 Tabloid *InputSlot Envelope
+*UIConstraints: *PageSize A3 *InputSlot Envelope
+*UIConstraints: *PageSize A4 *InputSlot Envelope
+*UIConstraints: *PageSize A5 *InputSlot Envelope
+*UIConstraints: *PageSize B5 *InputSlot Envelope
+*UIConstraints: *Duplex *Option1 False
+
+*OpenUI *PageSize/Media Size: PickOne
+*OrderDependency: 10 AnySetup *PageSize
+*DefaultPageSize: Letter
+*PageSize Letter/US Letter: "<</PageSize[612 792]/ImagingBBox null>>setpagedevice"
+*PageSize Legal/US Legal: "<</PageSize[612 1008]/ImagingBBox null>>setpagedevice"
+*PageSize Executive/US Executive: "<</PageSize[522 756]/ImagingBBox null>>setpagedevice"
+*PageSize Tabloid/US Tabloid: "<</PageSize[792 1224]/ImagingBBox null>>setpagedevice"
+*PageSize A3/A3: "<</PageSize[842 1191]/ImagingBBox null>>setpagedevice"
+*PageSize A4/A4: "<</PageSize[595 842]/ImagingBBox null>>setpagedevice"
+*PageSize A5/A5: "<</PageSize[421 595]/ImagingBBox null>>setpagedevice"
+*PageSize B5/B5 (JIS): "<</PageSize[516 729]/ImagingBBox null>>setpagedevice"
+*PageSize EnvISOB5/Envelope B5: "<</PageSize[499 709]/ImagingBBox null>>setpagedevice"
+*PageSize Env10/Envelope #10: "<</PageSize[297 684]/ImagingBBox null>>setpagedevice"
+*PageSize EnvC5/Envelope C5: "<</PageSize[459 649]/ImagingBBox null>>setpagedevice"
+*PageSize EnvDL/Envelope DL: "<</PageSize[312 624]/ImagingBBox null>>setpagedevice"
+*PageSize EnvMonarch/Envelope Monarch: "<</PageSize[279 540]/ImagingBBox null>>setpagedevice"
+*CloseUI: *PageSize
+
+*OpenUI *PageRegion: PickOne
+*OrderDependency: 10 AnySetup *PageRegion
+*DefaultPageRegion: Letter
+*PageRegion Letter/US Letter: "<</PageSize[612 792]/ImagingBBox null>>setpagedevice"
+*PageRegion Legal/US Legal: "<</PageSize[612 1008]/ImagingBBox null>>setpagedevice"
+*PageRegion Executive/US Executive: "<</PageSize[522 756]/ImagingBBox null>>setpagedevice"
+*PageRegion Tabloid/US Tabloid: "<</PageSize[792 1224]/ImagingBBox null>>setpagedevice"
+*PageRegion A3/A3: "<</PageSize[842 1191]/ImagingBBox null>>setpagedevice"
+*PageRegion A4/A4: "<</PageSize[595 842]/ImagingBBox null>>setpagedevice"
+*PageRegion A5/A5: "<</PageSize[421 595]/ImagingBBox null>>setpagedevice"
+*PageRegion B5/B5 (JIS): "<</PageSize[516 729]/ImagingBBox null>>setpagedevice"
+*PageRegion EnvISOB5/Envelope B5: "<</PageSize[499 709]/ImagingBBox null>>setpagedevice"
+*PageRegion Env10/Envelope #10: "<</PageSize[297 684]/ImagingBBox null>>setpagedevice"
+*PageRegion EnvC5/Envelope C5: "<</PageSize[459 649]/ImagingBBox null>>setpagedevice"
+*PageRegion EnvDL/Envelope DL: "<</PageSize[312 624]/ImagingBBox null>>setpagedevice"
+*PageRegion EnvMonarch/Envelope Monarch: "<</PageSize[279 540]/ImagingBBox null>>setpagedevice"
+*CloseUI: *PageRegion
+
+*DefaultImageableArea: Letter
+*ImageableArea Letter/US Letter: "18 36 594 786"
+*ImageableArea Legal/US Legal: "18 36 594 1002"
+*ImageableArea Executive/US Executive: "18 36 504 714"
+*ImageableArea Tabloid/US Tabloid: "18 36 774 1218"
+*ImageableArea A3/A3: "18 36 824 1185"
+*ImageableArea A4/A4: "18 36 577 836"
+*ImageableArea A5/A5: "18 36 403 589"
+*ImageableArea B5/JIS B5: "18 36 498 723"
+*ImageableArea EnvISOB5/B5 (ISO): "18 36 463 703"
+*ImageableArea Env10/Com-10: "18 36 279 678"
+*ImageableArea EnvC5/EnvC5: "18 36 441 643"
+*ImageableArea EnvDL/EnvDL: "18 36 294 618"
+*ImageableArea EnvMonarch/Envelope Monarch: "18 36 261 534"
+
+*DefaultPaperDimension: Letter
+*PaperDimension Letter/US Letter: "612 792"
+*PaperDimension Legal/US Legal: "612 1008"
+*PaperDimension Executive/US Executive: "522 756"
+*PaperDimension Tabloid/US Tabloid: "792 1224"
+*PaperDimension A3/A3: "842 1191"
+*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: "<</MediaType(Plain)/cupsMediaType 0>>setpagedevice"
+*MediaType Bond/Bond Paper: "<</MediaType(Bond)/cupsMediaType 1>>setpagedevice"
+*MediaType Special/Special Paper: "<</MediaType(Special)/cupsMediaType 2>>setpagedevice"
+*MediaType Transparency/Transparency: "<</MediaType(Transparency)/cupsMediaType 3>>setpagedevice"
+*MediaType Glossy/Glossy Paper: "<</MediaType(Glossy)/cupsMediaType 4>>setpagedevice"
+*CloseUI: *MediaType
+
+*OpenUI *InputSlot/Media Source: PickOne
+*OrderDependency: 10 AnySetup *InputSlot
+*DefaultInputSlot: Tray
+*InputSlot Tray/Tray: "<</cupsMediaPosition 1>>setpagedevice"
+*InputSlot Manual/Manual Feed: "<</cupsMediaPosition 2>>setpagedevice"
+*InputSlot Envelope/Envelope Feed: "<</cupsMediaPosition 3>>setpagedevice"
+*CloseUI: *InputSlot
+
+*OpenUI *Resolution/Output Resolution: PickOne
+*OrderDependency: 20 AnySetup *Resolution
+*DefaultResolution: 300dpi
+*Resolution 300dpi/300 DPI: "<</HWResolution[300 300]>>setpagedevice"
+*Resolution 600x300dpi/600x300 DPI: "<</HWResolution[600 300]>>setpagedevice"
+*Resolution 600dpi/600 DPI: "<</HWResolution[600 600]>>setpagedevice"
+*CloseUI: *Resolution
+
+*OpenUI *ColorModel/Output Mode: PickOne
+*OrderDependency: 10 AnySetup *ColorModel
+*DefaultColorModel: CMYK
+*ColorModel CMYK2/CRET Color: "<</cupsColorOrder 1/cupsColorSpace 8/cupsCompression 2/cupsBitsPerColor 2>>setpagedevice"
+*ColorModel CMYK/CMYK Color: "<</cupsColorOrder 1/cupsColorSpace 8/cupsCompression 2>>setpagedevice"
+*ColorModel Gray/Grayscale: "<</cupsColorOrder 0/cupsColorSpace 3/cupsCompression 2>>setpagedevice"
+*CloseUI: *ColorModel
+
+*OpenUI *Duplex/Double-Sided Printing: PickOne
+*OrderDependency: 20 PageSetup *Duplex
+*DefaultDuplex: None
+*Duplex None/Off: "<</Duplex false>>setpagedevice"
+*Duplex DuplexNoTumble/Long Edge (Standard): "<</Duplex true/Tumble false>>setpagedevice"
+*Duplex DuplexTumble/Short Edge (Flip): "<</Duplex true/Tumble true>>setpagedevice"
+*CloseUI: *Duplex
+
+*OpenGroup: InstallableOptions
+*OpenUI *Option1/Duplexer: Boolean
+*DefaultOption1: False
+*Option1 True/Installed: ""
+*Option1 False/Not Installed: ""
+*CloseUI: *Option1
+*CloseGroup: InstallableOptions
+
+*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/dymo.ppd b/ppd/dymo.ppd
new file mode 100644
index 000000000..43801737f
--- /dev/null
+++ b/ppd/dymo.ppd
@@ -0,0 +1,155 @@
+*PPD-Adobe: "4.3"
+*%
+*% "$Id$"
+*%
+*% Sample DYMO label printer driver PPD file for the Common UNIX Printing
+*% System (CUPS).
+*%
+*% Copyright 2001-2002 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: "DYMO.PPD"
+*Manufacturer: "ESP"
+*Product: "(CUPS v1.1)"
+*cupsVersion: 1.1
+*cupsManualCopies: False
+*cupsFilter: "application/vnd.cups-raster 0 rastertodymo"
+*cupsModelNumber: 0
+*ModelName: "DYMO Label Printer"
+*ShortNickName: "DYMO Label Printer"
+*NickName: "DYMO Label Printer CUPS v1.1"
+*PSVersion: "(3010.000) 550"
+*LanguageLevel: "3"
+*ColorDevice: False
+*DefaultColorSpace: Gray
+*FileSystem: False
+*Throughput: "8"
+*LandscapeOrientation: Plus90
+*VariablePaperSize: False
+*TTRasterizer: Type42
+
+*OpenUI *PageSize/Media Size: PickOne
+*OrderDependency: 10 AnySetup *PageSize
+*DefaultPageSize: w81h252
+*PageSize w81h252/Address - 1 1/8 x 3 1/2": "<</PageSize[81 252]/ImagingBBox null>>setpagedevice"
+*PageSize w101h252/Large Address - 1 4/10 x 3 1/2": "<</PageSize[101 252]/ImagingBBox null>>setpagedevice"
+*PageSize w54h144/Return Address - 3/4 x 2": "<</PageSize[54 144]/ImagingBBox null>>setpagedevice"
+*PageSize w167h288/Shipping Address - 2 5/16 x 4": "<</PageSize[167 288]/ImagingBBox null>>setpagedevice"
+*PageSize w162h540/Internet Postage 2-Part - 2 1/4 x 7 1/2": "<</PageSize[162 540]/ImagingBBox null>>setpagedevice"
+*PageSize w162h504/Internet Postage 3-Part - 2 1/4 x 7": "<</PageSize[162 504]/ImagingBBox null>>setpagedevice"
+*PageSize w41h248/File Folder - 9/16 x 3 7/16": "<</PageSize[41 248]/ImagingBBox null>>setpagedevice"
+*PageSize w41h144/Hanging Folder - 9/16 x 2": "<</PageSize[41 144]/ImagingBBox null>>setpagedevice"
+*PageSize w153h198/3.5" Disk - 2 1/8 x 2 3/4": "<</PageSize[153 198]/ImagingBBox null>>setpagedevice"
+*CloseUI: *PageSize
+
+*OpenUI *PageRegion: PickOne
+*OrderDependency: 10 AnySetup *PageRegion
+*DefaultPageRegion: w81h252
+*PageRegion w81h252/Address - 1 1/8 x 3 1/2": "<</PageSize[81 252]/ImagingBBox null>>setpagedevice"
+*PageRegion w101h252/Large Address - 1 4/10 x 3 1/2": "<</PageSize[101 252]/ImagingBBox null>>setpagedevice"
+*PageRegion w54h144/Return Address - 3/4 x 2": "<</PageSize[54 144]/ImagingBBox null>>setpagedevice"
+*PageRegion w167h288/Shipping Address - 2 5/16 x 4": "<</PageSize[167 288]/ImagingBBox null>>setpagedevice"
+*PageRegion w162h540/Internet Postage 2-Part - 2 1/4 x 7 1/2": "<</PageSize[162 540]/ImagingBBox null>>setpagedevice"
+*PageRegion w162h504/Internet Postage 3-Part - 2 1/4 x 7": "<</PageSize[162 504]/ImagingBBox null>>setpagedevice"
+*PageRegion w41h248/File Folder - 9/16 x 3 7/16": "<</PageSize[41 248]/ImagingBBox null>>setpagedevice"
+*PageRegion w41h144/Hanging Folder - 9/16 x 2": "<</PageSize[41 144]/ImagingBBox null>>setpagedevice"
+*PageRegion w153h198/3.5" Disk - 2 1/8 x 2 3/4": "<</PageSize[153 198]/ImagingBBox null>>setpagedevice"
+*CloseUI: *PageRegion
+
+*DefaultImageableArea: w81h252
+*ImageableArea w81h252/Address - 1 1/8 x 3 1/2": "2 14.9 79 237.1"
+*ImageableArea w101h252/Large Address - 1 4/10 x 3 1/2": "2 14.9 99 237.1"
+*ImageableArea w54h144/Return Address - 3/4 x 2": "2 14.9 52 129.1"
+*ImageableArea w167h288/Shipping Address - 2 5/16 x 4": "2 14.9 165 273.1"
+*ImageableArea w162h540/Internet Postage 2-Part - 2 1/4 x 7 1/2": "2 14.9 160 525.1"
+*ImageableArea w162h504/Internet Postage 3-Part - 2 1/4 x 7": "2 14.9 160 489.1"
+*ImageableArea w41h248/File Folder - 9/16 x 3 7/16": "2 14.9 39 233.1"
+*ImageableArea w41h144/Hanging Folder - 9/16 x 2": "2 14.9 39 129.1"
+*ImageableArea w153h198/3.5" Disk - 2 1/8 x 2 3/4": "2 14.9 151 183.1"
+
+*DefaultPaperDimension: w81h252
+*PaperDimension w81h252/Address - 1 1/8 x 3 1/2": "81 252"
+*PaperDimension w101h252/Large Address - 1 4/10 x 3 1/2": "101 252"
+*PaperDimension w54h144/Return Address - 3/4 x 2": "54 144"
+*PaperDimension w167h288/Shipping Address - 2 5/16 x 4": "167 288"
+*PaperDimension w162h540/Internet Postage 2-Part - 2 1/4 x 7 1/2": "162 540"
+*PaperDimension w162h504/Internet Postage 3-Part - 2 1/4 x 7": "162 504"
+*PaperDimension w41h248/File Folder - 9/16 x 3 7/16": "41 248"
+*PaperDimension w41h144/Hanging Folder - 9/16 x 2": "41 144"
+*PaperDimension w153h198/3.5" Disk - 2 1/8 x 2 3/4": "153 198"
+
+*OpenUI *Resolution/Output Resolution: PickOne
+*OrderDependency: 20 AnySetup *Resolution
+*DefaultResolution: 300dpi
+*Resolution 136dpi/136 DPI: "<</HWResolution[136 136]>>setpagedevice"
+*Resolution 203dpi/203 DPI: "<</HWResolution[203 203]>>setpagedevice"
+*Resolution 300dpi/300 DPI: "<</HWResolution[300 300]>>setpagedevice"
+*CloseUI: *Resolution
+
+*OpenUI *Darkness/Output Darkness: PickOne
+*OrderDependency: 20 AnySetup *Darkness
+*DefaultDarkness: Normal
+*Darkness Light: "<</cupsCompression 0>>setpagedevice"
+*Darkness Medium: "<</cupsCompression 1>>setpagedevice"
+*Darkness Normal: "<</cupsCompression 2>>setpagedevice"
+*Darkness Dark: "<</cupsCompression 3>>setpagedevice"
+*CloseUI: *Darkness
+
+*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/epson24.ppd b/ppd/epson24.ppd
new file mode 100644
index 000000000..e60b3b56e
--- /dev/null
+++ b/ppd/epson24.ppd
@@ -0,0 +1,128 @@
+*PPD-Adobe: "4.3"
+*%
+*% "$Id$"
+*%
+*% Sample EPSON 24-Pin driver PPD file for the Common UNIX Printing
+*% System (CUPS).
+*%
+*% Copyright 1997-2002 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: "EPSON24.PPD"
+*Manufacturer: "ESP"
+*Product: "(CUPS v1.1)"
+*cupsVersion: 1.1
+*cupsManualCopies: True
+*cupsModelNumber: 1
+*cupsFilter: "application/vnd.cups-raster 0 rastertoepson"
+*ModelName: "EPSON 24-Pin Series"
+*ShortNickName: "EPSON 24-Pin Series"
+*NickName: "EPSON 24-Pin Series CUPS v1.1"
+*PSVersion: "(3010.000) 550"
+*LanguageLevel: "3"
+*ColorDevice: False
+*DefaultColorSpace: Gray
+*FileSystem: False
+*Throughput: "1"
+*LandscapeOrientation: Plus90
+*VariablePaperSize: False
+*TTRasterizer: Type42
+
+*OpenUI *PageSize/Media Size: PickOne
+*OrderDependency: 10 AnySetup *PageSize
+*DefaultPageSize: Letter
+*PageSize Letter: "<</PageSize[612 792]/ImagingBBox null>>setpagedevice"
+*PageSize Legal: "<</PageSize[612 1008]/ImagingBBox null>>setpagedevice"
+*PageSize A4: "<</PageSize[595 842]/ImagingBBox null>>setpagedevice"
+*PageSize FanFoldUS: "<</PageSize[1071 792]/ImagingBBox null>>setpagedevice"
+*CloseUI: *PageSize
+
+*OpenUI *PageRegion: PickOne
+*OrderDependency: 10 AnySetup *PageRegion
+*DefaultPageRegion: Letter
+*PageRegion Letter: "<</PageSize[612 792]/ImagingBBox null>>setpagedevice"
+*PageRegion Legal: "<</PageSize[612 1008]/ImagingBBox null>>setpagedevice"
+*PageRegion A4: "<</PageSize[595 842]/ImagingBBox null>>setpagedevice"
+*PageRegion FanFoldUS: "<</PageSize[1071 792]/ImagingBBox null>>setpagedevice"
+*CloseUI: *PageRegion
+
+*DefaultImageableArea: Letter
+*ImageableArea Letter: "18.0 18.0 594.0 774.0"
+*ImageableArea Legal: "18.0 18.0 594.0 990.0"
+*ImageableArea A4: "18.0 18.0 577.0 824.0"
+*ImageableArea FanFoldUS: "18.0 18.0 1053.0 774.0"
+
+*DefaultPaperDimension: Letter
+*PaperDimension Letter: "612 792"
+*PaperDimension Legal: "612 1008"
+*PaperDimension A4: "595 842"
+*PaperDimension FanFoldUS: "1071 792"
+
+*OpenUI *Resolution/Output Resolution: PickOne
+*OrderDependency: 20 AnySetup *Resolution
+*DefaultResolution: 120dpi
+*Resolution 60dpi/60 DPI: "<</HWResolution[60 60]/cupsRowCount 8>>setpagedevice"
+*Resolution 120dpi/120x60 DPI: "<</HWResolution[120 60]/cupsRowCount 8>>setpagedevice"
+*Resolution 180dpi/180 DPI: "<</HWResolution[180 180]/cupsRowCount 24>>setpagedevice"
+*Resolution 360x180dpi/360x180 DPI: "<</HWResolution[360 180]/cupsRowCount 24>>setpagedevice"
+*Resolution 360dpi/360 DPI: "<</HWResolution[360 360]/cupsRowCount 48>>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/epson9.ppd b/ppd/epson9.ppd
new file mode 100644
index 000000000..a6889db81
--- /dev/null
+++ b/ppd/epson9.ppd
@@ -0,0 +1,126 @@
+*PPD-Adobe: "4.3"
+*%
+*% "$Id$"
+*%
+*% Sample EPSON 9-Pin driver PPD file for the Common UNIX Printing
+*% System (CUPS).
+*%
+*% Copyright 1997-2002 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: "EPSON9.PPD"
+*Manufacturer: "ESP"
+*Product: "(CUPS v1.1)"
+*cupsVersion: 1.1
+*cupsManualCopies: True
+*cupsModelNumber: 0
+*cupsFilter: "application/vnd.cups-raster 0 rastertoepson"
+*ModelName: "EPSON 9-Pin Series"
+*ShortNickName: "EPSON 9-Pin Series"
+*NickName: "EPSON 9-Pin Series CUPS v1.1"
+*PSVersion: "(3010.000) 550"
+*LanguageLevel: "3"
+*ColorDevice: False
+*DefaultColorSpace: Gray
+*FileSystem: False
+*Throughput: "1"
+*LandscapeOrientation: Plus90
+*VariablePaperSize: False
+*TTRasterizer: Type42
+
+*OpenUI *PageSize/Media Size: PickOne
+*OrderDependency: 10 AnySetup *PageSize
+*DefaultPageSize: Letter
+*PageSize Letter: "<</PageSize[612 792]/ImagingBBox null>>setpagedevice"
+*PageSize Legal: "<</PageSize[612 1008]/ImagingBBox null>>setpagedevice"
+*PageSize A4: "<</PageSize[595 842]/ImagingBBox null>>setpagedevice"
+*PageSize FanFoldUS: "<</PageSize[1071 792]/ImagingBBox null>>setpagedevice"
+*CloseUI: *PageSize
+
+*OpenUI *PageRegion: PickOne
+*OrderDependency: 10 AnySetup *PageRegion
+*DefaultPageRegion: Letter
+*PageRegion Letter: "<</PageSize[612 792]/ImagingBBox null>>setpagedevice"
+*PageRegion Legal: "<</PageSize[612 1008]/ImagingBBox null>>setpagedevice"
+*PageRegion A4: "<</PageSize[595 842]/ImagingBBox null>>setpagedevice"
+*PageRegion FanFoldUS: "<</PageSize[1071 792]/ImagingBBox null>>setpagedevice"
+*CloseUI: *PageRegion
+
+*DefaultImageableArea: Letter
+*ImageableArea Letter: "18.0 18.0 594.0 774.0"
+*ImageableArea Legal: "18.0 18.0 594.0 990.0"
+*ImageableArea A4: "18.0 18.0 577.0 824.0"
+*ImageableArea FanFoldUS: "18.0 18.0 1053.0 774.0"
+
+*DefaultPaperDimension: Letter
+*PaperDimension Letter: "612 792"
+*PaperDimension Legal: "612 1008"
+*PaperDimension A4: "595 842"
+*PaperDimension FanFoldUS: "1071 792"
+
+*OpenUI *Resolution/Output Resolution: PickOne
+*OrderDependency: 20 AnySetup *Resolution
+*DefaultResolution: 120dpi
+*Resolution 60dpi/60x72 DPI: "<</HWResolution[60 72]/cupsRowCount 8>>setpagedevice"
+*Resolution 120dpi/120x72 DPI: "<</HWResolution[120 72]/cupsRowCount 8>>setpagedevice"
+*Resolution 240dpi/240x72 DPI: "<</HWResolution[240 72]/cupsRowCount 8>>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/laserjet.ppd b/ppd/laserjet.ppd
new file mode 100644
index 000000000..a37eea38a
--- /dev/null
+++ b/ppd/laserjet.ppd
@@ -0,0 +1,200 @@
+*PPD-Adobe: "4.3"
+*%
+*% "$Id$"
+*%
+*% Sample HP LaserJet driver PPD file for the Common UNIX Printing
+*% System (CUPS).
+*%
+*% Copyright 1997-2002 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"
+*cupsModelNumber: 0
+*ModelName: "HP LaserJet Series"
+*ShortNickName: "HP LaserJet Series"
+*NickName: "HP LaserJet Series CUPS v1.1"
+*PSVersion: "(3010.000) 550"
+*LanguageLevel: "3"
+*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 Tabloid *InputSlot Envelope
+*UIConstraints: *PageSize A3 *InputSlot Envelope
+*UIConstraints: *PageSize A4 *InputSlot Envelope
+*UIConstraints: *PageSize A5 *InputSlot Envelope
+*UIConstraints: *PageSize B5 *InputSlot Envelope
+*UIConstraints: *Duplex *Option1 False
+
+*OpenUI *PageSize/Media Size: PickOne
+*OrderDependency: 10 AnySetup *PageSize
+*DefaultPageSize: Letter
+*PageSize Letter/US Letter: "<</PageSize[612 792]/ImagingBBox null>>setpagedevice"
+*PageSize Legal/US Legal: "<</PageSize[612 1008]/ImagingBBox null>>setpagedevice"
+*PageSize Executive/US Executive: "<</PageSize[522 756]/ImagingBBox null>>setpagedevice"
+*PageSize Tabloid/US Tabloid: "<</PageSize[792 1224]/ImagingBBox null>>setpagedevice"
+*PageSize A3/A3: "<</PageSize[842 1191]/ImagingBBox null>>setpagedevice"
+*PageSize A4/A4: "<</PageSize[595 842]/ImagingBBox null>>setpagedevice"
+*PageSize A5/A5: "<</PageSize[421 595]/ImagingBBox null>>setpagedevice"
+*PageSize B5/B5 (JIS): "<</PageSize[516 729]/ImagingBBox null>>setpagedevice"
+*PageSize EnvISOB5/Envelope B5: "<</PageSize[499 709]/ImagingBBox null>>setpagedevice"
+*PageSize Env10/Envelope #10: "<</PageSize[297 684]/ImagingBBox null>>setpagedevice"
+*PageSize EnvC5/Envelope C5: "<</PageSize[459 649]/ImagingBBox null>>setpagedevice"
+*PageSize EnvDL/Envelope DL: "<</PageSize[312 624]/ImagingBBox null>>setpagedevice"
+*PageSize EnvMonarch/Envelope Monarch: "<</PageSize[279 540]/ImagingBBox null>>setpagedevice"
+*CloseUI: *PageSize
+
+*OpenUI *PageRegion: PickOne
+*OrderDependency: 10 AnySetup *PageRegion
+*DefaultPageRegion: Letter
+*PageRegion Letter/US Letter: "<</PageSize[612 792]/ImagingBBox null>>setpagedevice"
+*PageRegion Legal/US Legal: "<</PageSize[612 1008]/ImagingBBox null>>setpagedevice"
+*PageRegion Executive/US Executive: "<</PageSize[522 756]/ImagingBBox null>>setpagedevice"
+*PageRegion Tabloid/US Tabloid: "<</PageSize[792 1224]/ImagingBBox null>>setpagedevice"
+*PageRegion A3/A3: "<</PageSize[842 1191]/ImagingBBox null>>setpagedevice"
+*PageRegion A4/A4: "<</PageSize[595 842]/ImagingBBox null>>setpagedevice"
+*PageRegion A5/A5: "<</PageSize[421 595]/ImagingBBox null>>setpagedevice"
+*PageRegion B5/B5 (JIS): "<</PageSize[516 729]/ImagingBBox null>>setpagedevice"
+*PageRegion EnvISOB5/Envelope B5: "<</PageSize[499 709]/ImagingBBox null>>setpagedevice"
+*PageRegion Env10/Envelope #10: "<</PageSize[297 684]/ImagingBBox null>>setpagedevice"
+*PageRegion EnvC5/Envelope C5: "<</PageSize[459 649]/ImagingBBox null>>setpagedevice"
+*PageRegion EnvDL/Envelope DL: "<</PageSize[312 624]/ImagingBBox null>>setpagedevice"
+*PageRegion EnvMonarch/Envelope Monarch: "<</PageSize[279 540]/ImagingBBox null>>setpagedevice"
+*CloseUI: *PageRegion
+
+*DefaultImageableArea: Letter
+*ImageableArea Letter/US Letter: "18 36 594 756"
+*ImageableArea Legal/US Legal: "18 36 594 972"
+*ImageableArea Executive/US Executive: "18 36 504 684"
+*ImageableArea Tabloid/US Tabloid: "18 36 774 1188"
+*ImageableArea A3/A3: "18 36 824 1155"
+*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/US Letter: "612 792"
+*PaperDimension Legal/US Legal: "612 1008"
+*PaperDimension Executive/US Executive: "522 756"
+*PaperDimension Tabloid/US Tabloid: "792 1224"
+*PaperDimension A3/A3: "842 1191"
+*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: "<</cupsMediaPosition 0>>setpagedevice"
+*InputSlot Tray1/Tray 1: "<</cupsMediaPosition 8>>setpagedevice"
+*InputSlot Tray2/Tray 2: "<</cupsMediaPosition 1>>setpagedevice"
+*InputSlot Tray3/Tray 3: "<</cupsMediaPosition 4>>setpagedevice"
+*InputSlot Tray4/Tray 4: "<</cupsMediaPosition 5>>setpagedevice"
+*InputSlot Manual/Manual Feed: "<</cupsMediaPosition 2>>setpagedevice"
+*InputSlot Envelope/Envelope Feed: "<</cupsMediaPosition 3>>setpagedevice"
+*CloseUI: *InputSlot
+
+*OpenUI *Resolution/Output Resolution: PickOne
+*OrderDependency: 20 AnySetup *Resolution
+*DefaultResolution: 300dpi
+*Resolution 150dpi/150 DPI: "<</HWResolution[150 150]/cupsColorOrder 0/cupsColorSpace 3/cupsCompression 2>>setpagedevice"
+*Resolution 300dpi/300 DPI: "<</HWResolution[300 300]/cupsColorOrder 0/cupsColorSpace 3/cupsCompression 2>>setpagedevice"
+*Resolution 600dpi/600 DPI: "<</HWResolution[600 600]/cupsColorOrder 0/cupsColorSpace 3/cupsCompression 2>>setpagedevice"
+*CloseUI: *Resolution
+
+*OpenUI *Duplex/Double-Sided Printing: PickOne
+*OrderDependency: 20 AnySetup *Duplex
+*DefaultDuplex: None
+*Duplex None/Off: "<</Duplex false>>setpagedevice"
+*Duplex DuplexNoTumble/Long Edge (Standard): "<</Duplex true/Tumble false>>setpagedevice"
+*Duplex DuplexTumble/Short Edge (Flip): "<</Duplex true/Tumble true>>setpagedevice"
+*CloseUI: *Duplex
+
+*OpenGroup: InstallableOptions
+*OpenUI *Option1/Duplexer: Boolean
+*DefaultOption1: False
+*Option1 True/Installed: ""
+*Option1 False/Not Installed: ""
+*CloseUI: *Option1
+*CloseGroup: InstallableOptions
+
+*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/okidat24.ppd b/ppd/okidat24.ppd
new file mode 100644
index 000000000..8a991c112
--- /dev/null
+++ b/ppd/okidat24.ppd
@@ -0,0 +1,128 @@
+*PPD-Adobe: "4.3"
+*%
+*% "$Id$"
+*%
+*% Sample OKIDATA 24-Pin driver PPD file for the Common UNIX Printing
+*% System (CUPS).
+*%
+*% Copyright 1997-2002 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: "OKIDAT24.PPD"
+*Manufacturer: "ESP"
+*Product: "(CUPS v1.1)"
+*cupsVersion: 1.1
+*cupsManualCopies: True
+*cupsModelNumber: 1
+*cupsFilter: "application/vnd.cups-raster 0 rastertoepson"
+*ModelName: "OKIDATA 24-Pin Series"
+*ShortNickName: "OKIDATA 24-Pin Series"
+*NickName: "OKIDATA 24-Pin Series CUPS v1.1"
+*PSVersion: "(3010.000) 550"
+*LanguageLevel: "3"
+*ColorDevice: False
+*DefaultColorSpace: Gray
+*FileSystem: False
+*Throughput: "1"
+*LandscapeOrientation: Plus90
+*VariablePaperSize: False
+*TTRasterizer: Type42
+
+*OpenUI *PageSize/Media Size: PickOne
+*OrderDependency: 10 AnySetup *PageSize
+*DefaultPageSize: Letter
+*PageSize Letter: "<</PageSize[612 792]/ImagingBBox null>>setpagedevice"
+*PageSize Legal: "<</PageSize[612 1008]/ImagingBBox null>>setpagedevice"
+*PageSize A4: "<</PageSize[595 842]/ImagingBBox null>>setpagedevice"
+*PageSize FanFoldUS: "<</PageSize[1071 792]/ImagingBBox null>>setpagedevice"
+*CloseUI: *PageSize
+
+*OpenUI *PageRegion: PickOne
+*OrderDependency: 10 AnySetup *PageRegion
+*DefaultPageRegion: Letter
+*PageRegion Letter: "<</PageSize[612 792]/ImagingBBox null>>setpagedevice"
+*PageRegion Legal: "<</PageSize[612 1008]/ImagingBBox null>>setpagedevice"
+*PageRegion A4: "<</PageSize[595 842]/ImagingBBox null>>setpagedevice"
+*PageRegion FanFoldUS: "<</PageSize[1071 792]/ImagingBBox null>>setpagedevice"
+*CloseUI: *PageRegion
+
+*DefaultImageableArea: Letter
+*ImageableArea Letter: "18.0 18.0 594.0 774.0"
+*ImageableArea Legal: "18.0 18.0 594.0 990.0"
+*ImageableArea A4: "18.0 18.0 577.0 824.0"
+*ImageableArea FanFoldUS: "18.0 18.0 1053.0 774.0"
+
+*DefaultPaperDimension: Letter
+*PaperDimension Letter: "612 792"
+*PaperDimension Legal: "612 1008"
+*PaperDimension A4: "595 842"
+*PaperDimension FanFoldUS: "1071 792"
+
+*OpenUI *Resolution/Output Resolution: PickOne
+*OrderDependency: 20 AnySetup *Resolution
+*DefaultResolution: 120dpi
+*Resolution 60dpi/60 DPI: "<</HWResolution[60 60]/cupsRowCount 8>>setpagedevice"
+*Resolution 120dpi/120x60 DPI: "<</HWResolution[120 60]/cupsRowCount 8>>setpagedevice"
+*Resolution 180dpi/180 DPI: "<</HWResolution[180 180]/cupsRowCount 24>>setpagedevice"
+*Resolution 360x180dpi/360x180 DPI: "<</HWResolution[360 180]/cupsRowCount 24>>setpagedevice"
+*Resolution 360dpi/360 DPI: "<</HWResolution[360 360]/cupsRowCount 48>>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/okidata9.ppd b/ppd/okidata9.ppd
new file mode 100644
index 000000000..8f133582f
--- /dev/null
+++ b/ppd/okidata9.ppd
@@ -0,0 +1,126 @@
+*PPD-Adobe: "4.3"
+*%
+*% "$Id$"
+*%
+*% Sample OKIDATA 9-Pin driver PPD file for the Common UNIX Printing
+*% System (CUPS).
+*%
+*% Copyright 1997-2002 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: "OKIDATA9.PPD"
+*Manufacturer: "ESP"
+*Product: "(CUPS v1.1)"
+*cupsVersion: 1.1
+*cupsManualCopies: True
+*cupsModelNumber: 0
+*cupsFilter: "application/vnd.cups-raster 0 rastertoepson"
+*ModelName: "OKIDATA 9-Pin Series"
+*ShortNickName: "OKIDATA 9-Pin Series"
+*NickName: "OKIDATA 9-Pin Series CUPS v1.1"
+*PSVersion: "(3010.000) 550"
+*LanguageLevel: "3"
+*ColorDevice: False
+*DefaultColorSpace: Gray
+*FileSystem: False
+*Throughput: "1"
+*LandscapeOrientation: Plus90
+*VariablePaperSize: False
+*TTRasterizer: Type42
+
+*OpenUI *PageSize/Media Size: PickOne
+*OrderDependency: 10 AnySetup *PageSize
+*DefaultPageSize: Letter
+*PageSize Letter: "<</PageSize[612 792]/ImagingBBox null>>setpagedevice"
+*PageSize Legal: "<</PageSize[612 1008]/ImagingBBox null>>setpagedevice"
+*PageSize A4: "<</PageSize[595 842]/ImagingBBox null>>setpagedevice"
+*PageSize FanFoldUS: "<</PageSize[1071 792]/ImagingBBox null>>setpagedevice"
+*CloseUI: *PageSize
+
+*OpenUI *PageRegion: PickOne
+*OrderDependency: 10 AnySetup *PageRegion
+*DefaultPageRegion: Letter
+*PageRegion Letter: "<</PageSize[612 792]/ImagingBBox null>>setpagedevice"
+*PageRegion Legal: "<</PageSize[612 1008]/ImagingBBox null>>setpagedevice"
+*PageRegion A4: "<</PageSize[595 842]/ImagingBBox null>>setpagedevice"
+*PageRegion FanFoldUS: "<</PageSize[1071 792]/ImagingBBox null>>setpagedevice"
+*CloseUI: *PageRegion
+
+*DefaultImageableArea: Letter
+*ImageableArea Letter: "18.0 18.0 594.0 774.0"
+*ImageableArea Legal: "18.0 18.0 594.0 990.0"
+*ImageableArea A4: "18.0 18.0 577.0 824.0"
+*ImageableArea FanFoldUS: "18.0 18.0 1053.0 774.0"
+
+*DefaultPaperDimension: Letter
+*PaperDimension Letter: "612 792"
+*PaperDimension Legal: "612 1008"
+*PaperDimension A4: "595 842"
+*PaperDimension FanFoldUS: "1071 792"
+
+*OpenUI *Resolution/Output Resolution: PickOne
+*OrderDependency: 20 AnySetup *Resolution
+*DefaultResolution: 120dpi
+*Resolution 60dpi/60x72 DPI: "<</HWResolution[60 72]/cupsRowCount 8>>setpagedevice"
+*Resolution 120dpi/120x72 DPI: "<</HWResolution[120 72]/cupsRowCount 8>>setpagedevice"
+*Resolution 240dpi/240x72 DPI: "<</HWResolution[240 72]/cupsRowCount 8>>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 000000000..a6ec8c528
--- /dev/null
+++ b/ppd/stcolor.ppd
@@ -0,0 +1,132 @@
+*PPD-Adobe: "4.3"
+*%
+*% "$Id$"
+*%
+*% Sample EPSON Stylus Color driver PPD file for the Common UNIX Printing
+*% System (CUPS).
+*%
+*% Copyright 1997-2002 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
+*cupsModelNumber: 2
+*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: "(3010.000) 550"
+*LanguageLevel: "3"
+*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: "<</PageSize[612 792]/ImagingBBox null>>setpagedevice"
+*PageSize Legal: "<</PageSize[612 1008]/ImagingBBox null>>setpagedevice"
+*PageSize A4: "<</PageSize[595 842]/ImagingBBox null>>setpagedevice"
+*CloseUI: *PageSize
+
+*OpenUI *PageRegion: PickOne
+*OrderDependency: 10 AnySetup *PageRegion
+*DefaultPageRegion: Letter
+*PageRegion Letter: "<</PageSize[612 792]/ImagingBBox null>>setpagedevice"
+*PageRegion Legal: "<</PageSize[612 1008]/ImagingBBox null>>setpagedevice"
+*PageRegion A4: "<</PageSize[595 842]/ImagingBBox null>>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: "<</HWResolution[180 180]>>setpagedevice"
+*Resolution 360dpi/360 DPI: "<</HWResolution[360 360]>>setpagedevice{0.6666 exp}bind settransfer"
+*Resolution 720dpi/720 DPI: "<</HWResolution[720 720]>>setpagedevice{0.4 exp}bind settransfer"
+*CloseUI: *Resolution
+
+*OpenUI *ColorModel/Output Mode: PickOne
+*OrderDependency: 10 AnySetup *ColorModel
+*DefaultColorModel: CMYK
+*ColorModel CMYK/Color: "<</cupsColorOrder 1/cupsColorSpace 8/cupsCompression 1>>setpagedevice"
+*ColorModel Gray/Grayscale: "<</cupsColorOrder 0/cupsColorSpace 3/cupsCompression 1>>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/stcolor2.ppd b/ppd/stcolor2.ppd
new file mode 100644
index 000000000..a8c470ac0
--- /dev/null
+++ b/ppd/stcolor2.ppd
@@ -0,0 +1,132 @@
+*PPD-Adobe: "4.3"
+*%
+*% "$Id$"
+*%
+*% Sample EPSON Stylus Color driver PPD file for the Common UNIX Printing
+*% System (CUPS).
+*%
+*% Copyright 1997-2002 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: "STCOLOR2.PPD"
+*Manufacturer: "ESP"
+*Product: "(CUPS v1.1)"
+*cupsVersion: 1.1
+*cupsManualCopies: True
+*cupsModelNumber: 4
+*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 New Stylus Color Series"
+*ShortNickName: "EPSON New Stylus Color Series"
+*NickName: "EPSON New Stylus Color Series CUPS v1.1"
+*PSVersion: "(3010.000) 550"
+*LanguageLevel: "3"
+*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: "<</PageSize[612 792]/ImagingBBox null>>setpagedevice"
+*PageSize Legal: "<</PageSize[612 1008]/ImagingBBox null>>setpagedevice"
+*PageSize A4: "<</PageSize[595 842]/ImagingBBox null>>setpagedevice"
+*CloseUI: *PageSize
+
+*OpenUI *PageRegion: PickOne
+*OrderDependency: 10 AnySetup *PageRegion
+*DefaultPageRegion: Letter
+*PageRegion Letter: "<</PageSize[612 792]/ImagingBBox null>>setpagedevice"
+*PageRegion Legal: "<</PageSize[612 1008]/ImagingBBox null>>setpagedevice"
+*PageRegion A4: "<</PageSize[595 842]/ImagingBBox null>>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: "<</HWResolution[180 180]>>setpagedevice"
+*Resolution 360dpi/360 DPI: "<</HWResolution[360 360]>>setpagedevice{0.6666 exp}bind settransfer"
+*Resolution 720dpi/720 DPI: "<</HWResolution[720 720]>>setpagedevice{0.4 exp}bind settransfer"
+*CloseUI: *Resolution
+
+*OpenUI *ColorModel/Output Mode: PickOne
+*OrderDependency: 10 AnySetup *ColorModel
+*DefaultColorModel: CMYK
+*ColorModel CMYK/Color: "<</cupsColorOrder 1/cupsColorSpace 8/cupsCompression 1>>setpagedevice"
+*ColorModel Gray/Grayscale: "<</cupsColorOrder 0/cupsColorSpace 3/cupsCompression 1>>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 000000000..91edf4adc
--- /dev/null
+++ b/ppd/stphoto.ppd
@@ -0,0 +1,132 @@
+*PPD-Adobe: "4.3"
+*%
+*% "$Id$"
+*%
+*% Sample EPSON Stylus Photo driver PPD file for the Common UNIX Printing
+*% System (CUPS).
+*%
+*% Copyright 1997-2002 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
+*cupsModelNumber: 3
+*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: "(3010.000) 550"
+*LanguageLevel: "3"
+*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: "<</PageSize[612 792]/ImagingBBox null>>setpagedevice"
+*PageSize Legal: "<</PageSize[612 1008]/ImagingBBox null>>setpagedevice"
+*PageSize A4: "<</PageSize[595 842]/ImagingBBox null>>setpagedevice"
+*CloseUI: *PageSize
+
+*OpenUI *PageRegion: PickOne
+*OrderDependency: 10 AnySetup *PageRegion
+*DefaultPageRegion: Letter
+*PageRegion Letter: "<</PageSize[612 792]/ImagingBBox null>>setpagedevice"
+*PageRegion Legal: "<</PageSize[612 1008]/ImagingBBox null>>setpagedevice"
+*PageRegion A4: "<</PageSize[595 842]/ImagingBBox null>>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: "<</HWResolution[180 180]>>setpagedevice"
+*Resolution 360dpi/360 DPI: "<</HWResolution[360 360]>>setpagedevice{0.6666 exp}bind settransfer"
+*Resolution 720dpi/720 DPI: "<</HWResolution[720 720]>>setpagedevice{0.4 exp}bind settransfer"
+*CloseUI: *Resolution
+
+*OpenUI *ColorModel/Output Mode: PickOne
+*OrderDependency: 10 AnySetup *ColorModel
+*DefaultColorModel: CMYK
+*ColorModel CMYK/Color: "<</cupsColorOrder 1/cupsColorSpace 9/cupsCompression 1>>setpagedevice"
+*ColorModel Gray/Grayscale: "<</cupsColorOrder 0/cupsColorSpace 3/cupsCompression 1>>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/stphoto2.ppd b/ppd/stphoto2.ppd
new file mode 100644
index 000000000..c944f4133
--- /dev/null
+++ b/ppd/stphoto2.ppd
@@ -0,0 +1,132 @@
+*PPD-Adobe: "4.3"
+*%
+*% "$Id$"
+*%
+*% Sample EPSON Stylus Photo driver PPD file for the Common UNIX Printing
+*% System (CUPS).
+*%
+*% Copyright 1997-2002 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: "STPHOTO2.PPD"
+*Manufacturer: "ESP"
+*Product: "(CUPS v1.1)"
+*cupsVersion: 1.1
+*cupsManualCopies: True
+*cupsModelNumber: 5
+*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 New Stylus Photo Series"
+*ShortNickName: "EPSON New Stylus Photo Series"
+*NickName: "EPSON New Stylus Photo Series CUPS v1.1"
+*PSVersion: "(3010.000) 550"
+*LanguageLevel: "3"
+*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: "<</PageSize[612 792]/ImagingBBox null>>setpagedevice"
+*PageSize Legal: "<</PageSize[612 1008]/ImagingBBox null>>setpagedevice"
+*PageSize A4: "<</PageSize[595 842]/ImagingBBox null>>setpagedevice"
+*CloseUI: *PageSize
+
+*OpenUI *PageRegion: PickOne
+*OrderDependency: 10 AnySetup *PageRegion
+*DefaultPageRegion: Letter
+*PageRegion Letter: "<</PageSize[612 792]/ImagingBBox null>>setpagedevice"
+*PageRegion Legal: "<</PageSize[612 1008]/ImagingBBox null>>setpagedevice"
+*PageRegion A4: "<</PageSize[595 842]/ImagingBBox null>>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: "<</HWResolution[180 180]>>setpagedevice"
+*Resolution 360dpi/360 DPI: "<</HWResolution[360 360]>>setpagedevice{0.6666 exp}bind settransfer"
+*Resolution 720dpi/720 DPI: "<</HWResolution[720 720]>>setpagedevice{0.4 exp}bind settransfer"
+*CloseUI: *Resolution
+
+*OpenUI *ColorModel/Output Mode: PickOne
+*OrderDependency: 10 AnySetup *ColorModel
+*DefaultColorModel: CMYK
+*ColorModel CMYK/Color: "<</cupsColorOrder 1/cupsColorSpace 9/cupsCompression 1>>setpagedevice"
+*ColorModel Gray/Grayscale: "<</cupsColorOrder 0/cupsColorSpace 3/cupsCompression 1>>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/.cvsignore b/pstoraster/.cvsignore
new file mode 100644
index 000000000..cf5b1a290
--- /dev/null
+++ b/pstoraster/.cvsignore
@@ -0,0 +1,3 @@
+pstoraster
+genarch
+arch.h
diff --git a/pstoraster/Dependencies b/pstoraster/Dependencies
new file mode 100644
index 000000000..1a72580af
--- /dev/null
+++ b/pstoraster/Dependencies
@@ -0,0 +1,2213 @@
+# DO NOT DELETE
+
+gconfig.o: memory_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gconfig.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gscdefs.h gconfigv.h
+gconfig.o: gconf.h gconfig.h ../config.h gxdevice.h gxdevcli.h gscompt.h
+gconfig.o: gsdcolor.h gsccolor.h gsstruct.h gxarith.h gxbitmap.h gsbitmap.h
+gconfig.o: gxhttile.h gxcindex.h gsbitops.h gsmatrix.h gsiparam.h gsrefct.h
+gconfig.o: gsropt.h gsxfont.h gxcvalue.h gxfixed.h gxtext.h gstext.h
+gconfig.o: gsccode.h gsparam.h gsmalloc.h gxiodev.h stat_.h
+
+gdevabuf.o: memory_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gdevabuf.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h gxdevice.h
+gdevabuf.o: gxdevcli.h gscompt.h gsdcolor.h gsccolor.h gsstruct.h gxarith.h
+gdevabuf.o: gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h gsbitops.h gsmatrix.h
+gdevabuf.o: gsiparam.h gsrefct.h gsropt.h gsxfont.h gxcvalue.h gxfixed.h
+gdevabuf.o: gxtext.h gstext.h gsccode.h gsparam.h gsmalloc.h gxdevmem.h
+gdevabuf.o: gdevmem.h gxbitops.h
+
+gdevbbox.o: math_.h std.h stdpre.h arch.h memory_.h gx.h stdio_.h gserror.h
+gdevbbox.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h
+gdevbbox.o: gsparam.h gxdevice.h gxdevcli.h gscompt.h gsdcolor.h gsccolor.h
+gdevbbox.o: gsstruct.h gxarith.h gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h
+gdevbbox.o: gsbitops.h gsmatrix.h gsiparam.h gsrefct.h gsropt.h gsxfont.h
+gdevbbox.o: gxcvalue.h gxfixed.h gxtext.h gstext.h gsccode.h gsmalloc.h
+gdevbbox.o: gsdevice.h gdevbbox.h gxdcolor.h gscsel.h gxiparam.h gxistate.h
+gdevbbox.o: gxline.h gslparam.h gxmatrix.h gxtmap.h gxpaint.h gxpath.h
+gdevbbox.o: gscpm.h gspenum.h gsrect.h gxcpath.h
+
+gdevcups.o: std.h stdpre.h arch.h gdevprn.h memory_.h string_.h gx.h stdio_.h
+gdevcups.o: gserror.h gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h gp.h
+gdevcups.o: gpgetenv.h gserrors.h gsmatrix.h gsutil.h gxdevice.h gxdevcli.h
+gdevcups.o: gscompt.h gsdcolor.h gsccolor.h gsstruct.h gxarith.h gxbitmap.h
+gdevcups.o: gsbitmap.h gxhttile.h gxcindex.h gsbitops.h gsiparam.h gsrefct.h
+gdevcups.o: gsropt.h gsxfont.h gxcvalue.h gxfixed.h gxtext.h gstext.h
+gdevcups.o: gsccode.h gsparam.h gsmalloc.h gxdevmem.h gxcldev.h gxht.h
+gdevcups.o: gscsepnm.h gsht1.h gsht.h gxhttype.h gxtmap.h gxdht.h strimpl.h
+gdevcups.o: scommon.h scfx.h shc.h gsbittab.h srlx.h gxclist.h gscspace.h
+gdevcups.o: gxband.h gxclio.h gxbcache.h gxistate.h gscsel.h gxline.h
+gdevcups.o: gslparam.h gxmatrix.h gsexit.h ../filter/raster.h ../cups/ppd.h
+
+gdevdbit.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gdevdbit.o: gsmemory.h gsmemraw.h gdebug.h gpcheck.h gserrors.h gsbittab.h
+gdevdbit.o: gsrect.h gsropt.h gxdcolor.h gscsel.h gsdcolor.h gsccolor.h
+gdevdbit.o: gsstruct.h gxarith.h gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h
+gdevdbit.o: gsbitops.h gxdevice.h gxdevcli.h gscompt.h gsmatrix.h gsiparam.h
+gdevdbit.o: gsrefct.h gsxfont.h gxcvalue.h gxfixed.h gxtext.h gstext.h
+gdevdbit.o: gsccode.h gsparam.h gsmalloc.h gxdevmem.h gdevmem.h gxbitops.h
+gdevdbit.o: gxcpath.h
+
+gdevddrw.o: math_.h std.h stdpre.h arch.h memory_.h gx.h stdio_.h gserror.h
+gdevddrw.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h gpcheck.h
+gdevddrw.o: gserrors.h gxfixed.h gxmatrix.h gsmatrix.h gxdcolor.h gscsel.h
+gdevddrw.o: gsdcolor.h gsccolor.h gsstruct.h gxarith.h gxbitmap.h gsbitmap.h
+gdevddrw.o: gxhttile.h gxcindex.h gsbitops.h gsropt.h gxdevice.h gxdevcli.h
+gdevddrw.o: gscompt.h gsiparam.h gsrefct.h gsxfont.h gxcvalue.h gxtext.h
+gdevddrw.o: gstext.h gsccode.h gsparam.h gsmalloc.h gxiparam.h gxistate.h
+gdevddrw.o: gxline.h gslparam.h gxtmap.h
+
+gdevdflt.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gdevdflt.o: gsmemory.h gsmemraw.h gdebug.h gserrors.h gsropt.h gxcomp.h
+gdevdflt.o: gscompt.h gsrefct.h gxbitfmt.h gxdevice.h gxdevcli.h gsdcolor.h
+gdevdflt.o: gsccolor.h gsstruct.h gxarith.h gxbitmap.h gsbitmap.h gxhttile.h
+gdevdflt.o: gxcindex.h gsbitops.h gsmatrix.h gsiparam.h gsxfont.h gxcvalue.h
+gdevdflt.o: gxfixed.h gxtext.h gstext.h gsccode.h gsparam.h gsmalloc.h
+gdevdflt.o: gxdevmem.h
+
+gdevdgbr.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gdevdgbr.o: gsmemory.h gsmemraw.h gdebug.h gserrors.h gxdevice.h gxdevcli.h
+gdevdgbr.o: gscompt.h gsdcolor.h gsccolor.h gsstruct.h gxarith.h gxbitmap.h
+gdevdgbr.o: gsbitmap.h gxhttile.h gxcindex.h gsbitops.h gsmatrix.h gsiparam.h
+gdevdgbr.o: gsrefct.h gsropt.h gsxfont.h gxcvalue.h gxfixed.h gxtext.h
+gdevdgbr.o: gstext.h gsccode.h gsparam.h gsmalloc.h gxdevmem.h gxgetbit.h
+gdevdgbr.o: gxbitfmt.h gxlum.h gdevmem.h gxbitops.h
+
+gdevhit.o: std.h stdpre.h arch.h gserror.h gserrors.h gstypes.h gsmemory.h
+gdevhit.o: gsmemraw.h gxdevice.h stdio_.h gxdevcli.h gscompt.h gsdcolor.h
+gdevhit.o: gsccolor.h gsstruct.h gxarith.h gxbitmap.h gsbitmap.h gxhttile.h
+gdevhit.o: gxcindex.h gsbitops.h gsmatrix.h gsiparam.h gsrefct.h gsropt.h
+gdevhit.o: gsxfont.h gxcvalue.h gxfixed.h gxtext.h gstext.h gsccode.h
+gdevhit.o: gsparam.h gsmalloc.h
+
+gdevm16.o: memory_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gdevm16.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gxdevice.h gxdevcli.h
+gdevm16.o: gscompt.h gsdcolor.h gsccolor.h gsstruct.h gxarith.h gxbitmap.h
+gdevm16.o: gsbitmap.h gxhttile.h gxcindex.h gsbitops.h gsmatrix.h gsiparam.h
+gdevm16.o: gsrefct.h gsropt.h gsxfont.h gxcvalue.h gxfixed.h gxtext.h
+gdevm16.o: gstext.h gsccode.h gsparam.h gsmalloc.h gxdevmem.h gdevmem.h
+gdevm16.o: gxbitops.h
+
+gdevm1.o: memory_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gdevm1.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gxdevice.h gxdevcli.h
+gdevm1.o: gscompt.h gsdcolor.h gsccolor.h gsstruct.h gxarith.h gxbitmap.h
+gdevm1.o: gsbitmap.h gxhttile.h gxcindex.h gsbitops.h gsmatrix.h gsiparam.h
+gdevm1.o: gsrefct.h gsropt.h gsxfont.h gxcvalue.h gxfixed.h gxtext.h gstext.h
+gdevm1.o: gsccode.h gsparam.h gsmalloc.h gxdevmem.h gdevmem.h gxbitops.h
+
+gdevm24.o: memory_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gdevm24.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gxdevice.h gxdevcli.h
+gdevm24.o: gscompt.h gsdcolor.h gsccolor.h gsstruct.h gxarith.h gxbitmap.h
+gdevm24.o: gsbitmap.h gxhttile.h gxcindex.h gsbitops.h gsmatrix.h gsiparam.h
+gdevm24.o: gsrefct.h gsropt.h gsxfont.h gxcvalue.h gxfixed.h gxtext.h
+gdevm24.o: gstext.h gsccode.h gsparam.h gsmalloc.h gxdevmem.h gdevmem.h
+gdevm24.o: gxbitops.h
+
+gdevm2.o: memory_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gdevm2.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gxdevice.h gxdevcli.h
+gdevm2.o: gscompt.h gsdcolor.h gsccolor.h gsstruct.h gxarith.h gxbitmap.h
+gdevm2.o: gsbitmap.h gxhttile.h gxcindex.h gsbitops.h gsmatrix.h gsiparam.h
+gdevm2.o: gsrefct.h gsropt.h gsxfont.h gxcvalue.h gxfixed.h gxtext.h gstext.h
+gdevm2.o: gsccode.h gsparam.h gsmalloc.h gxdevmem.h gdevmem.h gxbitops.h
+
+gdevm32.o: memory_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gdevm32.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gxdevice.h gxdevcli.h
+gdevm32.o: gscompt.h gsdcolor.h gsccolor.h gsstruct.h gxarith.h gxbitmap.h
+gdevm32.o: gsbitmap.h gxhttile.h gxcindex.h gsbitops.h gsmatrix.h gsiparam.h
+gdevm32.o: gsrefct.h gsropt.h gsxfont.h gxcvalue.h gxfixed.h gxtext.h
+gdevm32.o: gstext.h gsccode.h gsparam.h gsmalloc.h gxdevmem.h gdevmem.h
+gdevm32.o: gxbitops.h
+
+gdevm4.o: memory_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gdevm4.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gxdevice.h gxdevcli.h
+gdevm4.o: gscompt.h gsdcolor.h gsccolor.h gsstruct.h gxarith.h gxbitmap.h
+gdevm4.o: gsbitmap.h gxhttile.h gxcindex.h gsbitops.h gsmatrix.h gsiparam.h
+gdevm4.o: gsrefct.h gsropt.h gsxfont.h gxcvalue.h gxfixed.h gxtext.h gstext.h
+gdevm4.o: gsccode.h gsparam.h gsmalloc.h gxdevmem.h gdevmem.h gxbitops.h
+
+gdevm8.o: memory_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gdevm8.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gxdevice.h gxdevcli.h
+gdevm8.o: gscompt.h gsdcolor.h gsccolor.h gsstruct.h gxarith.h gxbitmap.h
+gdevm8.o: gsbitmap.h gxhttile.h gxcindex.h gsbitops.h gsmatrix.h gsiparam.h
+gdevm8.o: gsrefct.h gsropt.h gsxfont.h gxcvalue.h gxfixed.h gxtext.h gstext.h
+gdevm8.o: gsccode.h gsparam.h gsmalloc.h gxdevmem.h gdevmem.h gxbitops.h
+
+gdevmem.o: memory_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gdevmem.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h gsrect.h
+gdevmem.o: gsstruct.h gxarith.h gxdevice.h gxdevcli.h gscompt.h gsdcolor.h
+gdevmem.o: gsccolor.h gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h gsbitops.h
+gdevmem.o: gsmatrix.h gsiparam.h gsrefct.h gsropt.h gsxfont.h gxcvalue.h
+gdevmem.o: gxfixed.h gxtext.h gstext.h gsccode.h gsparam.h gsmalloc.h
+gdevmem.o: gxgetbit.h gxbitfmt.h gxdevmem.h gdevmem.h gxbitops.h
+
+gdevmpla.o: memory_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gdevmpla.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gxdevice.h gxdevcli.h
+gdevmpla.o: gscompt.h gsdcolor.h gsccolor.h gsstruct.h gxarith.h gxbitmap.h
+gdevmpla.o: gsbitmap.h gxhttile.h gxcindex.h gsbitops.h gsmatrix.h gsiparam.h
+gdevmpla.o: gsrefct.h gsropt.h gsxfont.h gxcvalue.h gxfixed.h gxtext.h
+gdevmpla.o: gstext.h gsccode.h gsparam.h gsmalloc.h gxdevmem.h gdevmem.h
+gdevmpla.o: gxbitops.h
+
+gdevnfwd.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gdevnfwd.o: gsmemory.h gsmemraw.h gdebug.h gserrors.h gxdevice.h gxdevcli.h
+gdevnfwd.o: gscompt.h gsdcolor.h gsccolor.h gsstruct.h gxarith.h gxbitmap.h
+gdevnfwd.o: gsbitmap.h gxhttile.h gxcindex.h gsbitops.h gsmatrix.h gsiparam.h
+gdevnfwd.o: gsrefct.h gsropt.h gsxfont.h gxcvalue.h gxfixed.h gxtext.h
+gdevnfwd.o: gstext.h gsccode.h gsparam.h gsmalloc.h
+
+gdevpipe.o: errno_.h std.h stdpre.h arch.h pipe_.h stdio_.h string_.h
+gdevpipe.o: gserror.h gstypes.h gsmemory.h gsmemraw.h stream.h scommon.h
+gdevpipe.o: gsstruct.h gxiodev.h stat_.h
+
+gdevprn.o: ctype_.h std.h stdpre.h arch.h gdevprn.h memory_.h string_.h gx.h
+gdevprn.o: stdio_.h gserror.h gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h
+gdevprn.o: gp.h gpgetenv.h gserrors.h gsmatrix.h gsutil.h gxdevice.h
+gdevprn.o: gxdevcli.h gscompt.h gsdcolor.h gsccolor.h gsstruct.h gxarith.h
+gdevprn.o: gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h gsbitops.h gsiparam.h
+gdevprn.o: gsrefct.h gsropt.h gsxfont.h gxcvalue.h gxfixed.h gxtext.h
+gdevprn.o: gstext.h gsccode.h gsparam.h gsmalloc.h gxdevmem.h gxcldev.h
+gdevprn.o: gxht.h gscsepnm.h gsht1.h gsht.h gxhttype.h gxtmap.h gxdht.h
+gdevprn.o: strimpl.h scommon.h scfx.h shc.h gsbittab.h srlx.h gxclist.h
+gdevprn.o: gscspace.h gxband.h gxclio.h gxbcache.h gxistate.h gscsel.h
+gdevprn.o: gxline.h gslparam.h gxmatrix.h
+
+gp_getnv.o: stdio_.h std.h stdpre.h arch.h string_.h gsmemory.h gsmemraw.h
+gp_getnv.o: gstypes.h gp.h gpgetenv.h
+
+gp_nofb.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gp_nofb.o: gsmemory.h gsmemraw.h gdebug.h gp.h gpgetenv.h gxdevice.h
+gp_nofb.o: gxdevcli.h gscompt.h gsdcolor.h gsccolor.h gsstruct.h gxarith.h
+gp_nofb.o: gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h gsbitops.h gsmatrix.h
+gp_nofb.o: gsiparam.h gsrefct.h gsropt.h gsxfont.h gxcvalue.h gxfixed.h
+gp_nofb.o: gxtext.h gstext.h gsccode.h gsparam.h gsmalloc.h
+
+gp_nsync.o: std.h stdpre.h arch.h gserror.h gserrors.h gpsync.h
+
+gp_unifn.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gp_unifn.o: gsmemory.h gsmemraw.h gdebug.h gp.h gpgetenv.h
+
+gp_unifs.o: memory_.h std.h stdpre.h arch.h string_.h gx.h stdio_.h gserror.h
+gp_unifs.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h gp.h gpgetenv.h
+gp_unifs.o: gsstruct.h gsutil.h stat_.h dirent_.h ../config.h ../cups/cups.h
+gp_unifs.o: ../cups/ipp.h ../cups/http.h ../cups/string.h ../cups/md5.h
+gp_unifs.o: ../cups/ppd.h
+
+gp_unix.o: pipe_.h stdio_.h std.h stdpre.h arch.h string_.h time_.h
+gp_unix.o: ../config.h gx.h gserror.h gsio.h gstypes.h gsmemory.h gsmemraw.h
+gp_unix.o: gdebug.h gsexit.h gp.h gpgetenv.h
+
+gsalloc.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gsalloc.o: gsmemory.h gsmemraw.h gdebug.h memory_.h gserrors.h gsmdebug.h
+gsalloc.o: gsstruct.h gxalloc.h gsalloc.h gxobj.h gxbitmap.h gsbitmap.h
+gsalloc.o: stream.h scommon.h
+
+gsalpha.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gsalpha.o: gsmemory.h gsmemraw.h gdebug.h gsalpha.h gxdcolor.h gscsel.h
+gsalpha.o: gsdcolor.h gsccolor.h gsstruct.h gxarith.h gxbitmap.h gsbitmap.h
+gsalpha.o: gxhttile.h gxcindex.h gsbitops.h gsropt.h gzstate.h gscpm.h
+gsalpha.o: gsrefct.h gxistate.h gxcvalue.h gxfixed.h gxline.h gslparam.h
+gsalpha.o: gxmatrix.h gsmatrix.h gxtmap.h gsstate.h gsdevice.h gsline.h
+gsalpha.o: gscolor.h gsht.h gxstate.h
+
+gsargs.o: ctype_.h std.h stdpre.h arch.h stdio_.h string_.h gsexit.h
+gsargs.o: gsmemory.h gsmemraw.h gsargs.h
+
+gsbitops.o: stdio_.h std.h stdpre.h arch.h memory_.h gdebug.h gstypes.h
+gsbitops.o: gxbitops.h gsbitops.h
+
+gsbittab.o: stdpre.h gsbittab.h
+
+gscdefs.o: stdpre.h gscdefs.h gconfigv.h gconf.h gconfig.h ../config.h
+
+gscdevn.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gscdevn.o: gsmemory.h gsmemraw.h gdebug.h gserrors.h gsrefct.h gsmatrix.h
+gscdevn.o: gxcspace.h gscspace.h gsccolor.h gsstruct.h gscsel.h gxfrac.h
+
+gschar0.o: memory_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gschar0.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h gsstruct.h
+gschar0.o: gsfcmap.h gsccode.h gxfixed.h gxdevice.h gxdevcli.h gscompt.h
+gschar0.o: gsdcolor.h gsccolor.h gxarith.h gxbitmap.h gsbitmap.h gxhttile.h
+gschar0.o: gxcindex.h gsbitops.h gsmatrix.h gsiparam.h gsrefct.h gsropt.h
+gschar0.o: gsxfont.h gxcvalue.h gxtext.h gstext.h gsparam.h gsmalloc.h
+gschar0.o: gxdevmem.h gxchar.h gschar.h gscpm.h gxfont.h gsfont.h gsuid.h
+gschar0.o: gxftype.h gxfont0.h
+
+gschar.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gschar.o: gsmemory.h gsmemraw.h gdebug.h memory_.h string_.h gserrors.h
+gschar.o: gsstruct.h gxfixed.h gxarith.h gxmatrix.h gsmatrix.h gzstate.h
+gschar.o: gscpm.h gsrefct.h gxdcolor.h gscsel.h gsdcolor.h gsccolor.h
+gschar.o: gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h gsbitops.h gsropt.h
+gschar.o: gxistate.h gxcvalue.h gxline.h gslparam.h gxtmap.h gsstate.h
+gschar.o: gsdevice.h gsline.h gscolor.h gsht.h gxstate.h gxcoord.h gscoord.h
+gschar.o: gxdevice.h gxdevcli.h gscompt.h gsiparam.h gsxfont.h gxtext.h
+gschar.o: gstext.h gsccode.h gsparam.h gsmalloc.h gxdevmem.h gxchar.h
+gschar.o: gschar.h gxfont.h gsfont.h gsuid.h gxftype.h gxfont0.h gxfcache.h
+gschar.o: gxbcache.h gspath.h gspenum.h gzpath.h gxpath.h gsrect.h
+
+gscie.o: math_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gscie.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h gsstruct.h
+gscie.o: gsmatrix.h gxcspace.h gscspace.h gsccolor.h gscsel.h gxfrac.h
+gscie.o: gscolor2.h gsptype1.h gspcolor.h gsuid.h gxbitmap.h gsbitmap.h
+gscie.o: gscie.h gsrefct.h gxctable.h gxfixed.h gxarith.h gxdevice.h
+gscie.o: gxdevcli.h gscompt.h gsdcolor.h gxhttile.h gxcindex.h gsbitops.h
+gscie.o: gsiparam.h gsropt.h gsxfont.h gxcvalue.h gxtext.h gstext.h gsccode.h
+gscie.o: gsparam.h gsmalloc.h gxcmap.h gxfmap.h gxtmap.h gzstate.h gscpm.h
+gscie.o: gxdcolor.h gxistate.h gxline.h gslparam.h gxmatrix.h gsstate.h
+gscie.o: gsdevice.h gsline.h gscolor.h gsht.h gxstate.h
+
+gsclipsr.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gsclipsr.o: gsmemory.h gsmemraw.h gdebug.h gserrors.h gsclipsr.h
+
+gscolor1.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gscolor1.o: gsmemory.h gsmemraw.h gdebug.h gserrors.h gsstruct.h gsutil.h
+gscolor1.o: gsccolor.h gxcspace.h gscspace.h gscsel.h gxfrac.h gxdcconv.h
+gscolor1.o: gxdevice.h gxdevcli.h gscompt.h gsdcolor.h gxarith.h gxbitmap.h
+gscolor1.o: gsbitmap.h gxhttile.h gxcindex.h gsbitops.h gsmatrix.h gsiparam.h
+gscolor1.o: gsrefct.h gsropt.h gsxfont.h gxcvalue.h gxfixed.h gxtext.h
+gscolor1.o: gstext.h gsccode.h gsparam.h gsmalloc.h gxcmap.h gxfmap.h
+gscolor1.o: gxtmap.h gzstate.h gscpm.h gxdcolor.h gxistate.h gxline.h
+gscolor1.o: gslparam.h gxmatrix.h gsstate.h gsdevice.h gsline.h gscolor.h
+gscolor1.o: gsht.h gxstate.h gscolor1.h
+
+gscolor2.o: memory_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gscolor2.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h gxarith.h
+gscolor2.o: gxfixed.h gxmatrix.h gsmatrix.h gxcspace.h gscspace.h gsccolor.h
+gscolor2.o: gsstruct.h gscsel.h gxfrac.h gxcolor2.h gscolor2.h gsptype1.h
+gscolor2.o: gspcolor.h gsuid.h gxbitmap.h gsbitmap.h gsrefct.h gzstate.h
+gscolor2.o: gscpm.h gxdcolor.h gsdcolor.h gxhttile.h gxcindex.h gsbitops.h
+gscolor2.o: gsropt.h gxistate.h gxcvalue.h gxline.h gslparam.h gxtmap.h
+gscolor2.o: gsstate.h gsdevice.h gsline.h gscolor.h gsht.h gxstate.h
+
+gscolor3.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gscolor3.o: gsmemory.h gsmemraw.h gdebug.h gserrors.h gscspace.h gsmatrix.h
+gscolor3.o: gscolor2.h gsptype1.h gspcolor.h gsccolor.h gsstruct.h gsuid.h
+gscolor3.o: gxbitmap.h gsbitmap.h gscolor3.h gspath.h gspenum.h gzstate.h
+gscolor3.o: gscpm.h gsrefct.h gxdcolor.h gscsel.h gsdcolor.h gxarith.h
+gscolor3.o: gxhttile.h gxcindex.h gsbitops.h gsropt.h gxistate.h gxcvalue.h
+gscolor3.o: gxfixed.h gxline.h gslparam.h gxmatrix.h gxtmap.h gsstate.h
+gscolor3.o: gsdevice.h gsline.h gscolor.h gsht.h gxstate.h gxshade.h
+gscolor3.o: gsshade.h gsdsrc.h gsfunc.h stream.h scommon.h
+
+gscolor.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gscolor.o: gsmemory.h gsmemraw.h gdebug.h gserrors.h gsstruct.h gsutil.h
+gscolor.o: gsccolor.h gxcspace.h gscspace.h gscsel.h gxfrac.h gxdcconv.h
+gscolor.o: gxdevice.h gxdevcli.h gscompt.h gsdcolor.h gxarith.h gxbitmap.h
+gscolor.o: gsbitmap.h gxhttile.h gxcindex.h gsbitops.h gsmatrix.h gsiparam.h
+gscolor.o: gsrefct.h gsropt.h gsxfont.h gxcvalue.h gxfixed.h gxtext.h
+gscolor.o: gstext.h gsccode.h gsparam.h gsmalloc.h gxcmap.h gxfmap.h gxtmap.h
+gscolor.o: gzstate.h gscpm.h gxdcolor.h gxistate.h gxline.h gslparam.h
+gscolor.o: gxmatrix.h gsstate.h gsdevice.h gsline.h gscolor.h gsht.h
+gscolor.o: gxstate.h
+
+gscoord.o: math_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gscoord.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h gsccode.h
+gscoord.o: gxfarith.h gconfigv.h gxarith.h gxfixed.h gxmatrix.h gsmatrix.h
+gscoord.o: gxfont.h gsfont.h gsuid.h gsstruct.h gxftype.h gxpath.h gscpm.h
+gscoord.o: gslparam.h gspenum.h gsrect.h gzstate.h gsrefct.h gxdcolor.h
+gscoord.o: gscsel.h gsdcolor.h gsccolor.h gxbitmap.h gsbitmap.h gxhttile.h
+gscoord.o: gxcindex.h gsbitops.h gsropt.h gxistate.h gxcvalue.h gxline.h
+gscoord.o: gxtmap.h gsstate.h gsdevice.h gsline.h gscolor.h gsht.h gxstate.h
+gscoord.o: gxcoord.h gscoord.h gxdevice.h gxdevcli.h gscompt.h gsiparam.h
+gscoord.o: gsxfont.h gxtext.h gstext.h gsparam.h gsmalloc.h
+
+gscparam.o: memory_.h std.h stdpre.h arch.h string_.h gx.h stdio_.h gserror.h
+gscparam.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h
+gscparam.o: gsparam.h gsstruct.h
+
+gscpixel.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gscpixel.o: gsmemory.h gsmemraw.h gdebug.h gserrors.h gsrefct.h gxcspace.h
+gscpixel.o: gscspace.h gsccolor.h gsstruct.h gscsel.h gxfrac.h gscpixel.h
+gscpixel.o: gxdevice.h gxdevcli.h gscompt.h gsdcolor.h gxarith.h gxbitmap.h
+gscpixel.o: gsbitmap.h gxhttile.h gxcindex.h gsbitops.h gsmatrix.h gsiparam.h
+gscpixel.o: gsropt.h gsxfont.h gxcvalue.h gxfixed.h gxtext.h gstext.h
+gscpixel.o: gsccode.h gsparam.h gsmalloc.h
+
+gscrdp.o: math_.h std.h stdpre.h arch.h memory_.h gx.h stdio_.h gserror.h
+gscrdp.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h gsdevice.h
+gscrdp.o: gserrors.h gsmatrix.h gxcspace.h gscspace.h gsccolor.h gsstruct.h
+gscrdp.o: gscsel.h gxfrac.h gscolor2.h gsptype1.h gspcolor.h gsuid.h
+gscrdp.o: gxbitmap.h gsbitmap.h gscrdp.h gscie.h gsrefct.h gxctable.h
+gscrdp.o: gxfixed.h gsparam.h gxarith.h
+
+gscrd.o: math_.h std.h stdpre.h arch.h memory_.h string_.h gx.h stdio_.h
+gscrd.o: gserror.h gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h gscdefs.h
+gscrd.o: gconfigv.h gsdevice.h gserrors.h gsmatrix.h gsparam.h gxcspace.h
+gscrd.o: gscspace.h gsccolor.h gsstruct.h gscsel.h gxfrac.h gscolor2.h
+gscrd.o: gsptype1.h gspcolor.h gsuid.h gxbitmap.h gsbitmap.h gscrd.h gscie.h
+gscrd.o: gsrefct.h gxctable.h gxfixed.h
+
+gscscie.o: math_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gscscie.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h gsstruct.h
+gscscie.o: gsmatrix.h gxcspace.h gscspace.h gsccolor.h gscsel.h gxfrac.h
+gscscie.o: gscolor2.h gsptype1.h gspcolor.h gsuid.h gxbitmap.h gsbitmap.h
+gscscie.o: gscie.h gsrefct.h gxctable.h gxfixed.h gxarith.h gxdevice.h
+gscscie.o: gxdevcli.h gscompt.h gsdcolor.h gxhttile.h gxcindex.h gsbitops.h
+gscscie.o: gsiparam.h gsropt.h gsxfont.h gxcvalue.h gxtext.h gstext.h
+gscscie.o: gsccode.h gsparam.h gsmalloc.h gxcmap.h gxfmap.h gxtmap.h
+gscscie.o: gzstate.h gscpm.h gxdcolor.h gxistate.h gxline.h gslparam.h
+gscscie.o: gxmatrix.h gsstate.h gsdevice.h gsline.h gscolor.h gsht.h
+gscscie.o: gxstate.h
+
+gscsepr.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gscsepr.o: gsmemory.h gsmemraw.h gdebug.h gserrors.h gsrefct.h gsmatrix.h
+gscsepr.o: gscsepr.h gscspace.h gxcspace.h gsccolor.h gsstruct.h gscsel.h
+gscsepr.o: gxfrac.h gxfixed.h gxcolor2.h gscolor2.h gsptype1.h gspcolor.h
+gscsepr.o: gsuid.h gxbitmap.h gsbitmap.h gzstate.h gscpm.h gxdcolor.h
+gscsepr.o: gsdcolor.h gxarith.h gxhttile.h gxcindex.h gsbitops.h gsropt.h
+gscsepr.o: gxistate.h gxcvalue.h gxline.h gslparam.h gxmatrix.h gxtmap.h
+gscsepr.o: gsstate.h gsdevice.h gsline.h gscolor.h gsht.h gxstate.h
+
+gscspace.o: memory_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gscspace.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h gsstruct.h
+gscspace.o: gsccolor.h gxcspace.h gscspace.h gscsel.h gxfrac.h gxistate.h
+gscspace.o: gsrefct.h gsropt.h gxcvalue.h gxfixed.h gxline.h gslparam.h
+gscspace.o: gxmatrix.h gsmatrix.h gxtmap.h
+
+gsdevice.o: ctype_.h std.h stdpre.h arch.h memory_.h string_.h gx.h stdio_.h
+gsdevice.o: gserror.h gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h
+gsdevice.o: gscdefs.h gconfigv.h gserrors.h gp.h gpgetenv.h gsstruct.h
+gsdevice.o: gspath.h gspenum.h gspaint.h gsmatrix.h gscoord.h gzstate.h
+gsdevice.o: gscpm.h gsrefct.h gxdcolor.h gscsel.h gsdcolor.h gsccolor.h
+gsdevice.o: gxarith.h gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h gsbitops.h
+gsdevice.o: gsropt.h gxistate.h gxcvalue.h gxfixed.h gxline.h gslparam.h
+gsdevice.o: gxmatrix.h gxtmap.h gsstate.h gsdevice.h gsline.h gscolor.h
+gsdevice.o: gsht.h gxstate.h gxcmap.h gxfmap.h gxfrac.h gxdevice.h gxdevcli.h
+gsdevice.o: gscompt.h gsiparam.h gsxfont.h gxtext.h gstext.h gsccode.h
+gsdevice.o: gsparam.h gsmalloc.h gxdevmem.h
+
+gsdevmem.o: math_.h std.h stdpre.h arch.h memory_.h gx.h stdio_.h gserror.h
+gsdevmem.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h
+gsdevmem.o: gxarith.h gxdevice.h gxdevcli.h gscompt.h gsdcolor.h gsccolor.h
+gsdevmem.o: gsstruct.h gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h gsbitops.h
+gsdevmem.o: gsmatrix.h gsiparam.h gsrefct.h gsropt.h gsxfont.h gxcvalue.h
+gsdevmem.o: gxfixed.h gxtext.h gstext.h gsccode.h gsparam.h gsmalloc.h
+gsdevmem.o: gxdevmem.h
+
+gsdparam.o: memory_.h std.h stdpre.h arch.h string_.h gx.h stdio_.h gserror.h
+gsdparam.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h
+gsdparam.o: gsparam.h gxdevice.h gxdevcli.h gscompt.h gsdcolor.h gsccolor.h
+gsdparam.o: gsstruct.h gxarith.h gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h
+gsdparam.o: gsbitops.h gsmatrix.h gsiparam.h gsrefct.h gsropt.h gsxfont.h
+gsdparam.o: gxcvalue.h gxfixed.h gxtext.h gstext.h gsccode.h gsmalloc.h
+
+gsdps1.o: math_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gsdps1.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h gsmatrix.h
+gsdps1.o: gscoord.h gspaint.h gxdevice.h gxdevcli.h gscompt.h gsdcolor.h
+gsdps1.o: gsccolor.h gsstruct.h gxarith.h gxbitmap.h gsbitmap.h gxhttile.h
+gsdps1.o: gxcindex.h gsbitops.h gsiparam.h gsrefct.h gsropt.h gsxfont.h
+gsdps1.o: gxcvalue.h gxfixed.h gxtext.h gstext.h gsccode.h gsparam.h
+gsdps1.o: gsmalloc.h gxmatrix.h gspath.h gspenum.h gspath2.h gzpath.h
+gsdps1.o: gxpath.h gscpm.h gslparam.h gsrect.h gzcpath.h gxcpath.h gzstate.h
+gsdps1.o: gxdcolor.h gscsel.h gxistate.h gxline.h gxtmap.h gsstate.h
+gsdps1.o: gsdevice.h gsline.h gscolor.h gsht.h gxstate.h
+
+gsdsrc.o: memory_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gsdsrc.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gsdsrc.h gsstruct.h
+gsdsrc.o: gserrors.h stream.h scommon.h
+
+gsfcmap.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gsfcmap.o: gsmemory.h gsmemraw.h gdebug.h gserrors.h gsstruct.h gxfcmap.h
+gsfcmap.o: gsfcmap.h gsccode.h gsuid.h
+
+gsfont0.o: memory_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gsfont0.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h gsstruct.h
+gsfont0.o: gxfixed.h gsmatrix.h gxdevice.h gxdevcli.h gscompt.h gsdcolor.h
+gsfont0.o: gsccolor.h gxarith.h gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h
+gsfont0.o: gsbitops.h gsiparam.h gsrefct.h gsropt.h gsxfont.h gxcvalue.h
+gsfont0.o: gxtext.h gstext.h gsccode.h gsparam.h gsmalloc.h gxdevmem.h
+gsfont0.o: gxchar.h gschar.h gscpm.h gxfcache.h gsuid.h gxbcache.h gxftype.h
+gsfont0.o: gxfont.h gsfont.h gxfont0.h
+
+gsfont.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gsfont.o: gsmemory.h gsmemraw.h gdebug.h memory_.h gserrors.h gsstruct.h
+gsfont.o: gxfixed.h gxmatrix.h gsmatrix.h gzstate.h gscpm.h gsrefct.h
+gsfont.o: gxdcolor.h gscsel.h gsdcolor.h gsccolor.h gxarith.h gxbitmap.h
+gsfont.o: gsbitmap.h gxhttile.h gxcindex.h gsbitops.h gsropt.h gxistate.h
+gsfont.o: gxcvalue.h gxline.h gslparam.h gxtmap.h gsstate.h gsdevice.h
+gsfont.o: gsline.h gscolor.h gsht.h gxstate.h gxdevice.h gxdevcli.h gscompt.h
+gsfont.o: gsiparam.h gsxfont.h gxtext.h gstext.h gsccode.h gsparam.h
+gsfont.o: gsmalloc.h gschar.h gxfont.h gsfont.h gsuid.h gxftype.h gxfcache.h
+gsfont.o: gxbcache.h
+
+gsfunc0.o: math_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gsfunc0.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h gsfunc0.h
+gsfunc0.o: gsfunc.h gsdsrc.h gsstruct.h gxfarith.h gconfigv.h gxarith.h
+gsfunc0.o: gxfunc.h
+
+gsfunc3.o: math_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gsfunc3.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h gsfunc3.h
+gsfunc3.o: gsfunc.h gsdsrc.h gsstruct.h gxfunc.h
+
+gsfunc.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gsfunc.o: gsmemory.h gsmemraw.h gdebug.h gserrors.h gxfunc.h gsfunc.h
+gsfunc.o: gsstruct.h
+
+gshsb.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gshsb.o: gsmemory.h gsmemraw.h gdebug.h gscolor.h gxtmap.h gshsb.h gxfrac.h
+
+gsht1.o: memory_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gsht1.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h gsstruct.h
+gsht1.o: gsutil.h gzstate.h gscpm.h gsrefct.h gxdcolor.h gscsel.h gsdcolor.h
+gsht1.o: gsccolor.h gxarith.h gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h
+gsht1.o: gsbitops.h gsropt.h gxistate.h gxcvalue.h gxfixed.h gxline.h
+gsht1.o: gslparam.h gxmatrix.h gsmatrix.h gxtmap.h gsstate.h gsdevice.h
+gsht1.o: gsline.h gscolor.h gsht.h gxstate.h gxdevice.h gxdevcli.h gscompt.h
+gsht1.o: gsiparam.h gsxfont.h gxtext.h gstext.h gsccode.h gsparam.h
+gsht1.o: gsmalloc.h gzht.h gxht.h gscsepnm.h gsht1.h gxhttype.h gxfmap.h
+gsht1.o: gxfrac.h gxdht.h
+
+gshtscr.o: math_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gshtscr.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h gsstruct.h
+gshtscr.o: gxarith.h gzstate.h gscpm.h gsrefct.h gxdcolor.h gscsel.h
+gshtscr.o: gsdcolor.h gsccolor.h gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h
+gshtscr.o: gsbitops.h gsropt.h gxistate.h gxcvalue.h gxfixed.h gxline.h
+gshtscr.o: gslparam.h gxmatrix.h gsmatrix.h gxtmap.h gsstate.h gsdevice.h
+gshtscr.o: gsline.h gscolor.h gsht.h gxstate.h gxdevice.h gxdevcli.h
+gshtscr.o: gscompt.h gsiparam.h gsxfont.h gxtext.h gstext.h gsccode.h
+gshtscr.o: gsparam.h gsmalloc.h gzht.h gxht.h gscsepnm.h gsht1.h gxhttype.h
+gshtscr.o: gxfmap.h gxfrac.h gxdht.h
+
+gsht.o: memory_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gsht.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h gsstruct.h
+gsht.o: gsutil.h gxarith.h gzstate.h gscpm.h gsrefct.h gxdcolor.h gscsel.h
+gsht.o: gsdcolor.h gsccolor.h gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h
+gsht.o: gsbitops.h gsropt.h gxistate.h gxcvalue.h gxfixed.h gxline.h
+gsht.o: gslparam.h gxmatrix.h gsmatrix.h gxtmap.h gsstate.h gsdevice.h
+gsht.o: gsline.h gscolor.h gsht.h gxstate.h gxdevice.h gxdevcli.h gscompt.h
+gsht.o: gsiparam.h gsxfont.h gxtext.h gstext.h gsccode.h gsparam.h gsmalloc.h
+gsht.o: gzht.h gxht.h gscsepnm.h gsht1.h gxhttype.h gxfmap.h gxfrac.h gxdht.h
+
+gsimage.o: memory_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gsimage.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h gsstruct.h
+gsimage.o: gscspace.h gsmatrix.h gsimage.h gsiparam.h gxarith.h gxdevice.h
+gsimage.o: gxdevcli.h gscompt.h gsdcolor.h gsccolor.h gxbitmap.h gsbitmap.h
+gsimage.o: gxhttile.h gxcindex.h gsbitops.h gsrefct.h gsropt.h gsxfont.h
+gsimage.o: gxcvalue.h gxfixed.h gxtext.h gstext.h gsccode.h gsparam.h
+gsimage.o: gsmalloc.h gxiparam.h gxpath.h gscpm.h gslparam.h gspenum.h
+gsimage.o: gsrect.h gzstate.h gxdcolor.h gscsel.h gxistate.h gxline.h
+gsimage.o: gxmatrix.h gxtmap.h gsstate.h gsdevice.h gsline.h gscolor.h gsht.h
+gsimage.o: gxstate.h
+
+gsimpath.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gsimpath.o: gsmemory.h gsmemraw.h gdebug.h gserrors.h gsmatrix.h gsstate.h
+gsimpath.o: gsdevice.h gsline.h gslparam.h gscolor.h gxtmap.h gsht.h gscsel.h
+gsimpath.o: gspath.h gspenum.h
+
+gsinit.o: stdio_.h std.h stdpre.h arch.h memory_.h gdebug.h gscdefs.h
+gsinit.o: gconfigv.h gsmemory.h gsmemraw.h gsmalloc.h gp.h gpgetenv.h gslib.h
+
+gsiodev.o: errno_.h std.h stdpre.h arch.h string_.h gx.h stdio_.h gserror.h
+gsiodev.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h gp.h
+gsiodev.o: gpgetenv.h gscdefs.h gconfigv.h gsparam.h gsstruct.h gxiodev.h
+gsiodev.o: stat_.h
+
+gsline.o: math_.h std.h stdpre.h arch.h memory_.h gx.h stdio_.h gserror.h
+gsline.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h
+gsline.o: gxfixed.h gxmatrix.h gsmatrix.h gzstate.h gscpm.h gsrefct.h
+gsline.o: gxdcolor.h gscsel.h gsdcolor.h gsccolor.h gsstruct.h gxarith.h
+gsline.o: gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h gsbitops.h gsropt.h
+gsline.o: gxistate.h gxcvalue.h gxline.h gslparam.h gxtmap.h gsstate.h
+gsline.o: gsdevice.h gsline.h gscolor.h gsht.h gxstate.h gzline.h
+
+gsmalloc.o: malloc_.h std.h stdpre.h arch.h gdebug.h gstypes.h gsmemory.h
+gsmalloc.o: gsmemraw.h gsmdebug.h gsstruct.h gsmalloc.h
+
+gsmatrix.o: math_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gsmatrix.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h gxfarith.h
+gsmatrix.o: gconfigv.h gxarith.h gxfixed.h gxmatrix.h gsmatrix.h
+
+gsmemory.o: memory_.h std.h stdpre.h arch.h gstypes.h gsmemory.h gsmemraw.h
+gsmemory.o: gsmdebug.h gsrefct.h gsstruct.h
+
+gsmisc.o: ctype_.h std.h stdpre.h arch.h malloc_.h math_.h memory_.h
+gsmisc.o: string_.h gx.h stdio_.h gserror.h gsio.h gstypes.h gsmemory.h
+gsmisc.o: gsmemraw.h gdebug.h gpcheck.h gserrors.h gconfigv.h gxfarith.h
+gsmisc.o: gxarith.h gxfixed.h
+
+gsnorop.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gsnorop.o: gsmemory.h gsmemraw.h gdebug.h gserrors.h gsrop.h gsropt.h
+gsnorop.o: gxdevcli.h gscompt.h gsdcolor.h gsccolor.h gsstruct.h gxarith.h
+gsnorop.o: gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h gsbitops.h gsmatrix.h
+gsnorop.o: gsiparam.h gsrefct.h gsxfont.h gxcvalue.h gxfixed.h gxtext.h
+gsnorop.o: gstext.h gsccode.h gdevmrop.h
+
+gspaint.o: math_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gspaint.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gpcheck.h gserrors.h
+gspaint.o: gsropt.h gxfixed.h gxmatrix.h gsmatrix.h gspaint.h gspath.h
+gspaint.o: gspenum.h gzpath.h gxpath.h gscpm.h gslparam.h gsrect.h gsrefct.h
+gspaint.o: gsstruct.h gxpaint.h gzstate.h gxdcolor.h gscsel.h gsdcolor.h
+gspaint.o: gsccolor.h gxarith.h gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h
+gspaint.o: gsbitops.h gxistate.h gxcvalue.h gxline.h gxtmap.h gsstate.h
+gspaint.o: gsdevice.h gsline.h gscolor.h gsht.h gxstate.h gxdevice.h
+gspaint.o: gxdevcli.h gscompt.h gsiparam.h gsxfont.h gxtext.h gstext.h
+gspaint.o: gsccode.h gsparam.h gsmalloc.h gxdevmem.h gxcpath.h
+
+gsparams.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gsparams.o: gsmemory.h gsmemraw.h gdebug.h memory_.h gserrors.h gsparams.h
+gsparams.o: stream.h scommon.h gsstruct.h gsparam.h
+
+gsparam.o: memory_.h std.h stdpre.h arch.h string_.h gx.h stdio_.h gserror.h
+gsparam.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h
+gsparam.o: gsparam.h gsstruct.h
+
+gspath1.o: math_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gspath1.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h gsstruct.h
+gspath1.o: gxfixed.h gxfarith.h gconfigv.h gxarith.h gxmatrix.h gsmatrix.h
+gspath1.o: gzstate.h gscpm.h gsrefct.h gxdcolor.h gscsel.h gsdcolor.h
+gspath1.o: gsccolor.h gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h gsbitops.h
+gspath1.o: gsropt.h gxistate.h gxcvalue.h gxline.h gslparam.h gxtmap.h
+gspath1.o: gsstate.h gsdevice.h gsline.h gscolor.h gsht.h gxstate.h gspath.h
+gspath1.o: gspenum.h gzpath.h gxpath.h gsrect.h gscoord.h
+
+gspath.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gspath.o: gsmemory.h gsmemraw.h gdebug.h gserrors.h gxfixed.h gxmatrix.h
+gspath.o: gsmatrix.h gscoord.h gzstate.h gscpm.h gsrefct.h gxdcolor.h
+gspath.o: gscsel.h gsdcolor.h gsccolor.h gsstruct.h gxarith.h gxbitmap.h
+gspath.o: gsbitmap.h gxhttile.h gxcindex.h gsbitops.h gsropt.h gxistate.h
+gspath.o: gxcvalue.h gxline.h gslparam.h gxtmap.h gsstate.h gsdevice.h
+gspath.o: gsline.h gscolor.h gsht.h gxstate.h gzpath.h gxpath.h gspenum.h
+gspath.o: gsrect.h gxdevice.h gxdevcli.h gscompt.h gsiparam.h gsxfont.h
+gspath.o: gxtext.h gstext.h gsccode.h gsparam.h gsmalloc.h gxdevmem.h
+gspath.o: gzcpath.h gxcpath.h
+
+gspcolor.o: math_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gspcolor.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h gsrop.h
+gspcolor.o: gsropt.h gsstruct.h gsutil.h gxarith.h gxfixed.h gxmatrix.h
+gspcolor.o: gsmatrix.h gxcoord.h gscoord.h gxcspace.h gscspace.h gsccolor.h
+gspcolor.o: gscsel.h gxfrac.h gxcolor2.h gscolor2.h gsptype1.h gspcolor.h
+gspcolor.o: gsuid.h gxbitmap.h gsbitmap.h gsrefct.h gxdcolor.h gsdcolor.h
+gspcolor.o: gxhttile.h gxcindex.h gsbitops.h gxdevice.h gxdevcli.h gscompt.h
+gspcolor.o: gsiparam.h gsxfont.h gxcvalue.h gxtext.h gstext.h gsccode.h
+gspcolor.o: gsparam.h gsmalloc.h gxdevmem.h gxclip2.h gxmclip.h gxclip.h
+gspcolor.o: gspath.h gspenum.h gxpath.h gscpm.h gslparam.h gsrect.h
+gspcolor.o: gxp1fill.h gxpcolor.h gxpcache.h gzstate.h gxistate.h gxline.h
+gspcolor.o: gxtmap.h gsstate.h gsdevice.h gsline.h gscolor.h gsht.h gxstate.h
+gspcolor.o: gsimage.h gsiparm4.h
+
+gsshade.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gsshade.o: gsmemory.h gsmemraw.h gdebug.h gscspace.h gserrors.h gsstruct.h
+gsshade.o: gxdevcli.h gscompt.h gsdcolor.h gsccolor.h gxarith.h gxbitmap.h
+gsshade.o: gsbitmap.h gxhttile.h gxcindex.h gsbitops.h gsmatrix.h gsiparam.h
+gsshade.o: gsrefct.h gsropt.h gsxfont.h gxcvalue.h gxfixed.h gxtext.h
+gsshade.o: gstext.h gsccode.h gxcpath.h gxistate.h gscsel.h gxline.h
+gsshade.o: gslparam.h gxmatrix.h gxtmap.h gxpath.h gscpm.h gspenum.h gsrect.h
+gsshade.o: gxshade.h gsshade.h gsdsrc.h gsfunc.h stream.h scommon.h
+
+gsstate.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gsstate.o: gsmemory.h gsmemraw.h gdebug.h memory_.h gserrors.h gsstruct.h
+gsstate.o: gsutil.h gzstate.h gscpm.h gsrefct.h gxdcolor.h gscsel.h
+gsstate.o: gsdcolor.h gsccolor.h gxarith.h gxbitmap.h gsbitmap.h gxhttile.h
+gsstate.o: gxcindex.h gsbitops.h gsropt.h gxistate.h gxcvalue.h gxfixed.h
+gsstate.o: gxline.h gslparam.h gxmatrix.h gsmatrix.h gxtmap.h gsstate.h
+gsstate.o: gsdevice.h gsline.h gscolor.h gsht.h gxstate.h gxcspace.h
+gsstate.o: gscspace.h gxfrac.h gsalpha.h gscolor2.h gsptype1.h gspcolor.h
+gsstate.o: gsuid.h gscoord.h gscie.h gxctable.h gxcmap.h gxfmap.h gxdevice.h
+gsstate.o: gxdevcli.h gscompt.h gsiparam.h gsxfont.h gxtext.h gstext.h
+gsstate.o: gsccode.h gsparam.h gsmalloc.h gxpcache.h gzht.h gxht.h gscsepnm.h
+gsstate.o: gsht1.h gxhttype.h gxdht.h gzline.h gspath.h gspenum.h gzpath.h
+gsstate.o: gxpath.h gsrect.h gzcpath.h gxcpath.h
+
+gstext.o: std.h stdpre.h arch.h gstypes.h gdebug.h gserror.h gserrors.h
+gstext.o: gsmemory.h gsmemraw.h gsstruct.h gxdevcli.h gscompt.h gsdcolor.h
+gstext.o: gsccolor.h gxarith.h gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h
+gstext.o: gsbitops.h gsmatrix.h gsiparam.h gsrefct.h gsropt.h gsxfont.h
+gstext.o: gxcvalue.h gxfixed.h gxtext.h gstext.h gsccode.h gxpath.h gscpm.h
+gstext.o: gslparam.h gspenum.h gsrect.h gzstate.h gxdcolor.h gscsel.h
+gstext.o: gxistate.h gxline.h gxmatrix.h gxtmap.h gsstate.h gsdevice.h
+gstext.o: gsline.h gscolor.h gsht.h gxstate.h
+
+gstrap.o: string_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gstrap.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h gstrap.h
+gstrap.o: gsparam.h
+
+gstype1.o: math_.h std.h stdpre.h arch.h memory_.h gx.h stdio_.h gserror.h
+gstype1.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h
+gstype1.o: gsstruct.h gxarith.h gxfixed.h gxmatrix.h gsmatrix.h gxcoord.h
+gstype1.o: gscoord.h gxistate.h gscsel.h gsrefct.h gsropt.h gxcvalue.h
+gstype1.o: gxline.h gslparam.h gxtmap.h gzpath.h gxpath.h gscpm.h gspenum.h
+gstype1.o: gsrect.h gxfont.h gsccode.h gsfont.h gsuid.h gxftype.h gxfont1.h
+gstype1.o: gxtype1.h gscrypt1.h gstype1.h gxop1.h
+
+gstype2.o: math_.h std.h stdpre.h arch.h memory_.h gx.h stdio_.h gserror.h
+gstype2.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h
+gstype2.o: gsstruct.h gxarith.h gxfixed.h gxmatrix.h gsmatrix.h gxcoord.h
+gstype2.o: gscoord.h gxistate.h gscsel.h gsrefct.h gsropt.h gxcvalue.h
+gstype2.o: gxline.h gslparam.h gxtmap.h gzpath.h gxpath.h gscpm.h gspenum.h
+gstype2.o: gsrect.h gxfont.h gsccode.h gsfont.h gsuid.h gxftype.h gxfont1.h
+gstype2.o: gxtype1.h gscrypt1.h gstype1.h gxop1.h
+
+gstype42.o: memory_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gstype42.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h gsstruct.h
+gstype42.o: gsccode.h gsmatrix.h gxfixed.h gxpath.h gscpm.h gslparam.h
+gstype42.o: gspenum.h gsrect.h gxfont.h gsfont.h gsuid.h gxftype.h gxfont42.h
+gstype42.o: gxistate.h gscsel.h gsrefct.h gsropt.h gxcvalue.h gxline.h
+gstype42.o: gxmatrix.h gxtmap.h
+
+gsutil.o: string_.h std.h stdpre.h arch.h memory_.h gstypes.h gconfigv.h
+gsutil.o: gsmemory.h gsmemraw.h gsrect.h gsuid.h gsutil.h
+
+gxacpath.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gxacpath.o: gsmemory.h gsmemraw.h gdebug.h gserrors.h gsrop.h gsropt.h
+gxacpath.o: gsstruct.h gsutil.h gsdcolor.h gsccolor.h gxarith.h gxbitmap.h
+gxacpath.o: gsbitmap.h gxhttile.h gxcindex.h gsbitops.h gxdevice.h gxdevcli.h
+gxacpath.o: gscompt.h gsmatrix.h gsiparam.h gsrefct.h gsxfont.h gxcvalue.h
+gxacpath.o: gxfixed.h gxtext.h gstext.h gsccode.h gsparam.h gsmalloc.h
+gxacpath.o: gzpath.h gxpath.h gscpm.h gslparam.h gspenum.h gsrect.h gxpaint.h
+gxacpath.o: gzcpath.h gxcpath.h gzacpath.h
+
+gxbcache.o: memory_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gxbcache.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gsmdebug.h gxbcache.h
+gxbcache.o: gxbitmap.h gsbitmap.h gsstruct.h
+
+gxccache.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gxccache.o: gsmemory.h gsmemraw.h gdebug.h gpcheck.h gserrors.h gsstruct.h
+gxccache.o: gxfixed.h gxmatrix.h gsmatrix.h gzstate.h gscpm.h gsrefct.h
+gxccache.o: gxdcolor.h gscsel.h gsdcolor.h gsccolor.h gxarith.h gxbitmap.h
+gxccache.o: gsbitmap.h gxhttile.h gxcindex.h gsbitops.h gsropt.h gxistate.h
+gxccache.o: gxcvalue.h gxline.h gslparam.h gxtmap.h gsstate.h gsdevice.h
+gxccache.o: gsline.h gscolor.h gsht.h gxstate.h gzpath.h gxpath.h gspenum.h
+gxccache.o: gsrect.h gxdevice.h gxdevcli.h gscompt.h gsiparam.h gsxfont.h
+gxccache.o: gxtext.h gstext.h gsccode.h gsparam.h gsmalloc.h gxdevmem.h
+gxccache.o: gzcpath.h gxcpath.h gxchar.h gschar.h gxfont.h gsfont.h gsuid.h
+gxccache.o: gxftype.h gxfcache.h gxbcache.h gxxfont.h gscspace.h gsimage.h
+
+gxccman.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gxccman.o: gsmemory.h gsmemraw.h gdebug.h memory_.h gpcheck.h gserrors.h
+gxccman.o: gsstruct.h gsbitops.h gsutil.h gxfixed.h gxmatrix.h gsmatrix.h
+gxccman.o: gzstate.h gscpm.h gsrefct.h gxdcolor.h gscsel.h gsdcolor.h
+gxccman.o: gsccolor.h gxarith.h gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h
+gxccman.o: gsropt.h gxistate.h gxcvalue.h gxline.h gslparam.h gxtmap.h
+gxccman.o: gsstate.h gsdevice.h gsline.h gscolor.h gsht.h gxstate.h gzpath.h
+gxccman.o: gxpath.h gspenum.h gsrect.h gxdevice.h gxdevcli.h gscompt.h
+gxccman.o: gsiparam.h gsxfont.h gxtext.h gstext.h gsccode.h gsparam.h
+gxccman.o: gsmalloc.h gxdevmem.h gxchar.h gschar.h gxfont.h gsfont.h gsuid.h
+gxccman.o: gxftype.h gxfcache.h gxbcache.h gxxfont.h
+
+gxcht.o: memory_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gxcht.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h gsutil.h
+gxcht.o: gxarith.h gxfixed.h gxmatrix.h gsmatrix.h gxdevice.h gxdevcli.h
+gxcht.o: gscompt.h gsdcolor.h gsccolor.h gsstruct.h gxbitmap.h gsbitmap.h
+gxcht.o: gxhttile.h gxcindex.h gsbitops.h gsiparam.h gsrefct.h gsropt.h
+gxcht.o: gsxfont.h gxcvalue.h gxtext.h gstext.h gsccode.h gsparam.h
+gxcht.o: gsmalloc.h gxcmap.h gscsel.h gxfmap.h gxfrac.h gxtmap.h gxdcolor.h
+gxcht.o: gxistate.h gxline.h gslparam.h gzht.h gxht.h gscsepnm.h gsht1.h
+gxcht.o: gsht.h gxhttype.h gxdht.h
+
+gxclbits.o: memory_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gxclbits.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gpcheck.h gserrors.h
+gxclbits.o: gsbitops.h gxdevice.h gxdevcli.h gscompt.h gsdcolor.h gsccolor.h
+gxclbits.o: gsstruct.h gxarith.h gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h
+gxclbits.o: gsmatrix.h gsiparam.h gsrefct.h gsropt.h gsxfont.h gxcvalue.h
+gxclbits.o: gxfixed.h gxtext.h gstext.h gsccode.h gsparam.h gsmalloc.h
+gxclbits.o: gxdevmem.h gxcldev.h gxht.h gscsepnm.h gsht1.h gsht.h gxhttype.h
+gxclbits.o: gxtmap.h gxdht.h strimpl.h scommon.h scfx.h shc.h gsbittab.h
+gxclbits.o: srlx.h gxclist.h gscspace.h gxband.h gxclio.h gp.h gpgetenv.h
+gxclbits.o: gxbcache.h gxistate.h gscsel.h gxline.h gslparam.h gxmatrix.h
+gxclbits.o: gxfmap.h gxfrac.h
+
+gxclimag.o: math_.h std.h stdpre.h arch.h memory_.h gx.h stdio_.h gserror.h
+gxclimag.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h
+gxclimag.o: gscspace.h gxarith.h gxdevice.h gxdevcli.h gscompt.h gsdcolor.h
+gxclimag.o: gsccolor.h gsstruct.h gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h
+gxclimag.o: gsbitops.h gsmatrix.h gsiparam.h gsrefct.h gsropt.h gsxfont.h
+gxclimag.o: gxcvalue.h gxfixed.h gxtext.h gstext.h gsccode.h gsparam.h
+gxclimag.o: gsmalloc.h gxdevmem.h gxcldev.h gxht.h gscsepnm.h gsht1.h gsht.h
+gxclimag.o: gxhttype.h gxtmap.h gxdht.h strimpl.h scommon.h scfx.h shc.h
+gxclimag.o: gsbittab.h srlx.h gxclist.h gxband.h gxclio.h gp.h gpgetenv.h
+gxclimag.o: gxbcache.h gxistate.h gscsel.h gxline.h gslparam.h gxmatrix.h
+gxclimag.o: gxclpath.h gxfmap.h gxfrac.h gxiparam.h gxpath.h gscpm.h
+gxclimag.o: gspenum.h gsrect.h siscale.h gconfigv.h
+
+gxclip2.o: memory_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gxclip2.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h gsstruct.h
+gxclip2.o: gxdevice.h gxdevcli.h gscompt.h gsdcolor.h gsccolor.h gxarith.h
+gxclip2.o: gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h gsbitops.h gsmatrix.h
+gxclip2.o: gsiparam.h gsrefct.h gsropt.h gsxfont.h gxcvalue.h gxfixed.h
+gxclip2.o: gxtext.h gstext.h gsccode.h gsparam.h gsmalloc.h gxdevmem.h
+gxclip2.o: gxclip2.h gxmclip.h gxclip.h
+
+gxclipm.o: memory_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gxclipm.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gxdevice.h gxdevcli.h
+gxclipm.o: gscompt.h gsdcolor.h gsccolor.h gsstruct.h gxarith.h gxbitmap.h
+gxclipm.o: gsbitmap.h gxhttile.h gxcindex.h gsbitops.h gsmatrix.h gsiparam.h
+gxclipm.o: gsrefct.h gsropt.h gsxfont.h gxcvalue.h gxfixed.h gxtext.h
+gxclipm.o: gstext.h gsccode.h gsparam.h gsmalloc.h gxdevmem.h gxclipm.h
+gxclipm.o: gxmclip.h gxclip.h
+
+gxclip.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gxclip.o: gsmemory.h gsmemraw.h gdebug.h gxdevice.h gxdevcli.h gscompt.h
+gxclip.o: gsdcolor.h gsccolor.h gsstruct.h gxarith.h gxbitmap.h gsbitmap.h
+gxclip.o: gxhttile.h gxcindex.h gsbitops.h gsmatrix.h gsiparam.h gsrefct.h
+gxclip.o: gsropt.h gsxfont.h gxcvalue.h gxfixed.h gxtext.h gstext.h gsccode.h
+gxclip.o: gsparam.h gsmalloc.h gxclip.h gzpath.h gxpath.h gscpm.h gslparam.h
+gxclip.o: gspenum.h gsrect.h gzcpath.h gxcpath.h
+
+gxclist.o: memory_.h std.h stdpre.h arch.h string_.h gx.h stdio_.h gserror.h
+gxclist.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h gp.h gpgetenv.h
+gxclist.o: gpcheck.h gserrors.h gxdevice.h gxdevcli.h gscompt.h gsdcolor.h
+gxclist.o: gsccolor.h gsstruct.h gxarith.h gxbitmap.h gsbitmap.h gxhttile.h
+gxclist.o: gxcindex.h gsbitops.h gsmatrix.h gsiparam.h gsrefct.h gsropt.h
+gxclist.o: gsxfont.h gxcvalue.h gxfixed.h gxtext.h gstext.h gsccode.h
+gxclist.o: gsparam.h gsmalloc.h gxdevmem.h gxcldev.h gxht.h gscsepnm.h
+gxclist.o: gsht1.h gsht.h gxhttype.h gxtmap.h gxdht.h strimpl.h scommon.h
+gxclist.o: scfx.h shc.h gsbittab.h srlx.h gxclist.h gscspace.h gxband.h
+gxclist.o: gxclio.h gxbcache.h gxistate.h gscsel.h gxline.h gslparam.h
+gxclist.o: gxmatrix.h gxclpath.h gsparams.h stream.h
+
+gxclmem.o: memory_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gxclmem.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h gsmalloc.h
+gxclmem.o: gxclmem.h gxclio.h gp.h gpgetenv.h strimpl.h scommon.h gsstruct.h
+gxclmem.o: ../config.h
+
+gxclpage.o: gdevprn.h memory_.h std.h stdpre.h arch.h string_.h gx.h stdio_.h
+gxclpage.o: gserror.h gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h gp.h
+gxclpage.o: gpgetenv.h gserrors.h gsmatrix.h gsutil.h gxdevice.h gxdevcli.h
+gxclpage.o: gscompt.h gsdcolor.h gsccolor.h gsstruct.h gxarith.h gxbitmap.h
+gxclpage.o: gsbitmap.h gxhttile.h gxcindex.h gsbitops.h gsiparam.h gsrefct.h
+gxclpage.o: gsropt.h gsxfont.h gxcvalue.h gxfixed.h gxtext.h gstext.h
+gxclpage.o: gsccode.h gsparam.h gsmalloc.h gxdevmem.h gxcldev.h gxht.h
+gxclpage.o: gscsepnm.h gsht1.h gsht.h gxhttype.h gxtmap.h gxdht.h strimpl.h
+gxclpage.o: scommon.h scfx.h shc.h gsbittab.h srlx.h gxclist.h gscspace.h
+gxclpage.o: gxband.h gxclio.h gxbcache.h gxistate.h gscsel.h gxline.h
+gxclpage.o: gslparam.h gxmatrix.h gxclpage.h
+
+gxclpath.o: math_.h std.h stdpre.h arch.h memory_.h gx.h stdio_.h gserror.h
+gxclpath.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h gpcheck.h
+gxclpath.o: gserrors.h gxdevice.h gxdevcli.h gscompt.h gsdcolor.h gsccolor.h
+gxclpath.o: gsstruct.h gxarith.h gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h
+gxclpath.o: gsbitops.h gsmatrix.h gsiparam.h gsrefct.h gsropt.h gsxfont.h
+gxclpath.o: gxcvalue.h gxfixed.h gxtext.h gstext.h gsccode.h gsparam.h
+gxclpath.o: gsmalloc.h gxdevmem.h gxcldev.h gxht.h gscsepnm.h gsht1.h gsht.h
+gxclpath.o: gxhttype.h gxtmap.h gxdht.h strimpl.h scommon.h scfx.h shc.h
+gxclpath.o: gsbittab.h srlx.h gxclist.h gscspace.h gxband.h gxclio.h gp.h
+gxclpath.o: gpgetenv.h gxbcache.h gxistate.h gscsel.h gxline.h gslparam.h
+gxclpath.o: gxmatrix.h gxclpath.h gxcolor2.h gscolor2.h gsptype1.h gspcolor.h
+gxclpath.o: gsuid.h gxpaint.h gzpath.h gxpath.h gscpm.h gspenum.h gsrect.h
+gxclpath.o: gzcpath.h gxcpath.h
+
+gxclrast.o: memory_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gxclrast.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gp.h gpgetenv.h
+gxclrast.o: gpcheck.h gserrors.h gsbitops.h gsparams.h stream.h scommon.h
+gxclrast.o: gsstruct.h gsparam.h gsstate.h gsdevice.h gsline.h gslparam.h
+gxclrast.o: gscolor.h gxtmap.h gsht.h gscsel.h gxdcolor.h gsdcolor.h
+gxclrast.o: gsccolor.h gxarith.h gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h
+gxclrast.o: gsropt.h gxdevice.h gxdevcli.h gscompt.h gsmatrix.h gsiparam.h
+gxclrast.o: gsrefct.h gsxfont.h gxcvalue.h gxfixed.h gxtext.h gstext.h
+gxclrast.o: gsccode.h gsmalloc.h gscoord.h gxdevmem.h gxcldev.h gxht.h
+gxclrast.o: gscsepnm.h gsht1.h gxhttype.h gxdht.h strimpl.h scfx.h shc.h
+gxclrast.o: gsbittab.h srlx.h gxclist.h gscspace.h gxband.h gxclio.h
+gxclrast.o: gxbcache.h gxistate.h gxline.h gxmatrix.h gxclpath.h gxcmap.h
+gxclrast.o: gxfmap.h gxfrac.h gxcspace.h gxgetbit.h gxbitfmt.h gxpaint.h
+gxclrast.o: gdevht.h gzht.h gzpath.h gxpath.h gscpm.h gspenum.h gsrect.h
+gxclrast.o: gzcpath.h gxcpath.h gzacpath.h
+
+gxclread.o: memory_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gxclread.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gp.h gpgetenv.h
+gxclread.o: gpcheck.h gserrors.h gxdevice.h gxdevcli.h gscompt.h gsdcolor.h
+gxclread.o: gsccolor.h gsstruct.h gxarith.h gxbitmap.h gsbitmap.h gxhttile.h
+gxclread.o: gxcindex.h gsbitops.h gsmatrix.h gsiparam.h gsrefct.h gsropt.h
+gxclread.o: gsxfont.h gxcvalue.h gxfixed.h gxtext.h gstext.h gsccode.h
+gxclread.o: gsparam.h gsmalloc.h gscoord.h gsdevice.h gxdevmem.h gxcldev.h
+gxclread.o: gxht.h gscsepnm.h gsht1.h gsht.h gxhttype.h gxtmap.h gxdht.h
+gxclread.o: strimpl.h scommon.h scfx.h shc.h gsbittab.h srlx.h gxclist.h
+gxclread.o: gscspace.h gxband.h gxclio.h gxbcache.h gxistate.h gscsel.h
+gxclread.o: gxline.h gslparam.h gxmatrix.h gxgetbit.h gxbitfmt.h gdevht.h
+gxclread.o: gzht.h gxfmap.h gxfrac.h stream.h
+
+gxclrect.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gxclrect.o: gsmemory.h gsmemraw.h gdebug.h gserrors.h gsutil.h gxdevice.h
+gxclrect.o: gxdevcli.h gscompt.h gsdcolor.h gsccolor.h gsstruct.h gxarith.h
+gxclrect.o: gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h gsbitops.h gsmatrix.h
+gxclrect.o: gsiparam.h gsrefct.h gsropt.h gsxfont.h gxcvalue.h gxfixed.h
+gxclrect.o: gxtext.h gstext.h gsccode.h gsparam.h gsmalloc.h gxdevmem.h
+gxclrect.o: gxcldev.h gxht.h gscsepnm.h gsht1.h gsht.h gxhttype.h gxtmap.h
+gxclrect.o: gxdht.h strimpl.h scommon.h scfx.h shc.h gsbittab.h srlx.h
+gxclrect.o: gxclist.h gscspace.h gxband.h gxclio.h gp.h gpgetenv.h gxbcache.h
+gxclrect.o: gxistate.h gscsel.h gxline.h gslparam.h gxmatrix.h
+
+gxclutil.o: memory_.h std.h stdpre.h arch.h string_.h gx.h stdio_.h gserror.h
+gxclutil.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h gp.h gpgetenv.h
+gxclutil.o: gpcheck.h gserrors.h gxdevice.h gxdevcli.h gscompt.h gsdcolor.h
+gxclutil.o: gsccolor.h gsstruct.h gxarith.h gxbitmap.h gsbitmap.h gxhttile.h
+gxclutil.o: gxcindex.h gsbitops.h gsmatrix.h gsiparam.h gsrefct.h gsropt.h
+gxclutil.o: gsxfont.h gxcvalue.h gxfixed.h gxtext.h gstext.h gsccode.h
+gxclutil.o: gsparam.h gsmalloc.h gxdevmem.h gxcldev.h gxht.h gscsepnm.h
+gxclutil.o: gsht1.h gsht.h gxhttype.h gxtmap.h gxdht.h strimpl.h scommon.h
+gxclutil.o: scfx.h shc.h gsbittab.h srlx.h gxclist.h gscspace.h gxband.h
+gxclutil.o: gxclio.h gxbcache.h gxistate.h gscsel.h gxline.h gslparam.h
+gxclutil.o: gxmatrix.h gxclpath.h gsparams.h stream.h
+
+gxclzlib.o: ../config.h std.h stdpre.h arch.h gstypes.h gsmemory.h gsmemraw.h
+gxclzlib.o: gxclmem.h gxclio.h gp.h gpgetenv.h strimpl.h scommon.h gsstruct.h
+gxclzlib.o: szlibx.h
+
+gxcmap.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gxcmap.o: gsmemory.h gsmemraw.h gdebug.h gserrors.h gsccolor.h gsstruct.h
+gxcmap.o: gxalpha.h gxcspace.h gscspace.h gscsel.h gxfrac.h gxfarith.h
+gxcmap.o: gconfigv.h gxarith.h gxdcconv.h gxdevice.h gxdevcli.h gscompt.h
+gxcmap.o: gsdcolor.h gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h gsbitops.h
+gxcmap.o: gsmatrix.h gsiparam.h gsrefct.h gsropt.h gsxfont.h gxcvalue.h
+gxcmap.o: gxfixed.h gxtext.h gstext.h gsccode.h gsparam.h gsmalloc.h gxcmap.h
+gxcmap.o: gxfmap.h gxtmap.h gxlum.h gzstate.h gscpm.h gxdcolor.h gxistate.h
+gxcmap.o: gxline.h gslparam.h gxmatrix.h gsstate.h gsdevice.h gsline.h
+gxcmap.o: gscolor.h gsht.h gxstate.h gxdither.h
+
+gxcpath.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gxcpath.o: gsmemory.h gsmemraw.h gdebug.h gserrors.h gsstruct.h gsutil.h
+gxcpath.o: gsline.h gslparam.h gxdevice.h gxdevcli.h gscompt.h gsdcolor.h
+gxcpath.o: gsccolor.h gxarith.h gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h
+gxcpath.o: gsbitops.h gsmatrix.h gsiparam.h gsrefct.h gsropt.h gsxfont.h
+gxcpath.o: gxcvalue.h gxfixed.h gxtext.h gstext.h gsccode.h gsparam.h
+gxcpath.o: gsmalloc.h gscoord.h gxstate.h gzpath.h gxpath.h gscpm.h gspenum.h
+gxcpath.o: gsrect.h gzcpath.h gxcpath.h
+
+gxctable.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gxctable.o: gsmemory.h gsmemraw.h gdebug.h gxfixed.h gxfrac.h gxctable.h
+
+gxdcconv.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gxdcconv.o: gsmemory.h gsmemraw.h gdebug.h gsdcolor.h gsccolor.h gsstruct.h
+gxdcconv.o: gxarith.h gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h gsbitops.h
+gxdcconv.o: gxdcconv.h gxfrac.h gxdevice.h gxdevcli.h gscompt.h gsmatrix.h
+gxdcconv.o: gsiparam.h gsrefct.h gsropt.h gsxfont.h gxcvalue.h gxfixed.h
+gxdcconv.o: gxtext.h gstext.h gsccode.h gsparam.h gsmalloc.h gxcmap.h
+gxdcconv.o: gscsel.h gxfmap.h gxtmap.h gxfarith.h gconfigv.h gxlum.h
+gxdcconv.o: gxistate.h gxline.h gslparam.h gxmatrix.h
+
+gxdcolor.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gxdcolor.o: gsmemory.h gsmemraw.h gdebug.h gserrors.h gsbittab.h gxdcolor.h
+gxdcolor.o: gscsel.h gsdcolor.h gsccolor.h gsstruct.h gxarith.h gxbitmap.h
+gxdcolor.o: gsbitmap.h gxhttile.h gxcindex.h gsbitops.h gsropt.h gxdevice.h
+gxdcolor.o: gxdevcli.h gscompt.h gsmatrix.h gsiparam.h gsrefct.h gsxfont.h
+gxdcolor.o: gxcvalue.h gxfixed.h gxtext.h gstext.h gsccode.h gsparam.h
+gxdcolor.o: gsmalloc.h
+
+gxdither.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gxdither.o: gsmemory.h gsmemraw.h gdebug.h gsstruct.h gsdcolor.h gsccolor.h
+gxdither.o: gxarith.h gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h gsbitops.h
+gxdither.o: gxdevice.h gxdevcli.h gscompt.h gsmatrix.h gsiparam.h gsrefct.h
+gxdither.o: gsropt.h gsxfont.h gxcvalue.h gxfixed.h gxtext.h gstext.h
+gxdither.o: gsccode.h gsparam.h gsmalloc.h gxlum.h gxcmap.h gscsel.h gxfmap.h
+gxdither.o: gxfrac.h gxtmap.h gxdither.h gzht.h gxht.h gscsepnm.h gsht1.h
+gxdither.o: gsht.h gxhttype.h gxdht.h
+
+gxfill.o: math_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gxfill.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h gsstruct.h
+gxfill.o: gxfixed.h gxdevice.h gxdevcli.h gscompt.h gsdcolor.h gsccolor.h
+gxfill.o: gxarith.h gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h gsbitops.h
+gxfill.o: gsmatrix.h gsiparam.h gsrefct.h gsropt.h gsxfont.h gxcvalue.h
+gxfill.o: gxtext.h gstext.h gsccode.h gsparam.h gsmalloc.h gzpath.h gxpath.h
+gxfill.o: gscpm.h gslparam.h gspenum.h gsrect.h gzcpath.h gxcpath.h
+gxfill.o: gxdcolor.h gscsel.h gxistate.h gxline.h gxmatrix.h gxtmap.h
+gxfill.o: gxpaint.h
+
+gxhint1.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gxhint1.o: gsmemory.h gsmemraw.h gdebug.h gserrors.h gxarith.h gxfixed.h
+gxhint1.o: gxmatrix.h gsmatrix.h gxfont.h gsccode.h gsfont.h gsuid.h
+gxhint1.o: gsstruct.h gxftype.h gxfont1.h gxtype1.h gscrypt1.h gstype1.h
+gxhint1.o: gxop1.h
+
+gxhint2.o: memory_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gxhint2.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h gxarith.h
+gxhint2.o: gxfixed.h gxmatrix.h gsmatrix.h gxfont.h gsccode.h gsfont.h
+gxhint2.o: gsuid.h gsstruct.h gxftype.h gxfont1.h gxtype1.h gscrypt1.h
+gxhint2.o: gstype1.h gxop1.h
+
+gxhint3.o: math_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gxhint3.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h gxarith.h
+gxhint3.o: gxfixed.h gxmatrix.h gsmatrix.h gxfont.h gsccode.h gsfont.h
+gxhint3.o: gsuid.h gsstruct.h gxftype.h gxfont1.h gxtype1.h gscrypt1.h
+gxhint3.o: gstype1.h gxop1.h gzpath.h gxpath.h gscpm.h gslparam.h gspenum.h
+gxhint3.o: gsrect.h gsrefct.h
+
+gxht.o: memory_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gxht.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h gsstruct.h
+gxht.o: gsbitops.h gsutil.h gxdcolor.h gscsel.h gsdcolor.h gsccolor.h
+gxht.o: gxarith.h gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h gsropt.h
+gxht.o: gxfixed.h gxdevice.h gxdevcli.h gscompt.h gsmatrix.h gsiparam.h
+gxht.o: gsrefct.h gsxfont.h gxcvalue.h gxtext.h gstext.h gsccode.h gsparam.h
+gxht.o: gsmalloc.h gxistate.h gxline.h gslparam.h gxmatrix.h gxtmap.h gzht.h
+gxht.o: gxht.h gscsepnm.h gsht1.h gsht.h gxhttype.h gxfmap.h gxfrac.h gxdht.h
+
+gxi12bit.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gxi12bit.o: gsmemory.h gsmemraw.h gdebug.h memory_.h gpcheck.h gserrors.h
+gxi12bit.o: gxfixed.h gxfrac.h gxarith.h gxmatrix.h gsmatrix.h gsccolor.h
+gxi12bit.o: gsstruct.h gspaint.h gxdevice.h gxdevcli.h gscompt.h gsdcolor.h
+gxi12bit.o: gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h gsbitops.h gsiparam.h
+gxi12bit.o: gsrefct.h gsropt.h gsxfont.h gxcvalue.h gxtext.h gstext.h
+gxi12bit.o: gsccode.h gsparam.h gsmalloc.h gxcmap.h gscsel.h gxfmap.h
+gxi12bit.o: gxtmap.h gxdcolor.h gxistate.h gxline.h gslparam.h gzpath.h
+gxi12bit.o: gxpath.h gscpm.h gspenum.h gsrect.h gxdevmem.h gxcpath.h
+gxi12bit.o: gximage.h gxcspace.h gscspace.h strimpl.h scommon.h siscale.h
+gxi12bit.o: gconfigv.h gxdda.h gxiparam.h gxsample.h
+
+gxicolor.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gxicolor.o: gsmemory.h gsmemraw.h gdebug.h memory_.h gpcheck.h gserrors.h
+gxicolor.o: gxfixed.h gxfrac.h gxarith.h gxmatrix.h gsmatrix.h gsccolor.h
+gxicolor.o: gsstruct.h gspaint.h gzstate.h gscpm.h gsrefct.h gxdcolor.h
+gxicolor.o: gscsel.h gsdcolor.h gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h
+gxicolor.o: gsbitops.h gsropt.h gxistate.h gxcvalue.h gxline.h gslparam.h
+gxicolor.o: gxtmap.h gsstate.h gsdevice.h gsline.h gscolor.h gsht.h gxstate.h
+gxicolor.o: gxdevice.h gxdevcli.h gscompt.h gsiparam.h gsxfont.h gxtext.h
+gxicolor.o: gstext.h gsccode.h gsparam.h gsmalloc.h gxcmap.h gxfmap.h
+gxicolor.o: gxdcconv.h gzpath.h gxpath.h gspenum.h gsrect.h gxdevmem.h
+gxicolor.o: gxcpath.h gximage.h gxcspace.h gscspace.h strimpl.h scommon.h
+gxicolor.o: siscale.h gconfigv.h gxdda.h gxiparam.h gxsample.h
+
+gxidata.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gxidata.o: gsmemory.h gsmemraw.h gdebug.h memory_.h gserrors.h gxdevice.h
+gxidata.o: gxdevcli.h gscompt.h gsdcolor.h gsccolor.h gsstruct.h gxarith.h
+gxidata.o: gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h gsbitops.h gsmatrix.h
+gxidata.o: gsiparam.h gsrefct.h gsropt.h gsxfont.h gxcvalue.h gxfixed.h
+gxidata.o: gxtext.h gstext.h gsccode.h gsparam.h gsmalloc.h gxcpath.h
+gxidata.o: gximage.h gxcspace.h gscspace.h gscsel.h gxfrac.h strimpl.h
+gxidata.o: scommon.h siscale.h gconfigv.h gxdda.h gxiparam.h gxsample.h
+
+gxifast.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gxifast.o: gsmemory.h gsmemraw.h gdebug.h memory_.h gpcheck.h gsbittab.h
+gxifast.o: gserrors.h gxfixed.h gxarith.h gxmatrix.h gsmatrix.h gsccolor.h
+gxifast.o: gsstruct.h gspaint.h gsutil.h gxdevice.h gxdevcli.h gscompt.h
+gxifast.o: gsdcolor.h gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h gsbitops.h
+gxifast.o: gsiparam.h gsrefct.h gsropt.h gsxfont.h gxcvalue.h gxtext.h
+gxifast.o: gstext.h gsccode.h gsparam.h gsmalloc.h gxcmap.h gscsel.h gxfmap.h
+gxifast.o: gxfrac.h gxtmap.h gxdcolor.h gxistate.h gxline.h gslparam.h
+gxifast.o: gzpath.h gxpath.h gscpm.h gspenum.h gsrect.h gxdevmem.h gdevmem.h
+gxifast.o: gxbitops.h gxcpath.h gximage.h gxcspace.h gscspace.h strimpl.h
+gxifast.o: scommon.h siscale.h gconfigv.h gxdda.h gxiparam.h gxsample.h
+gxifast.o: gzht.h gxht.h gscsepnm.h gsht1.h gsht.h gxhttype.h gxdht.h
+
+gxiinit.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gxiinit.o: gsmemory.h gsmemraw.h gdebug.h math_.h memory_.h gpcheck.h
+gxiinit.o: gserrors.h gsstruct.h gsutil.h gxfixed.h gxfrac.h gxarith.h
+gxiinit.o: gxmatrix.h gsmatrix.h gsccolor.h gspaint.h gzstate.h gscpm.h
+gxiinit.o: gsrefct.h gxdcolor.h gscsel.h gsdcolor.h gxbitmap.h gsbitmap.h
+gxiinit.o: gxhttile.h gxcindex.h gsbitops.h gsropt.h gxistate.h gxcvalue.h
+gxiinit.o: gxline.h gslparam.h gxtmap.h gsstate.h gsdevice.h gsline.h
+gxiinit.o: gscolor.h gsht.h gxstate.h gxdevice.h gxdevcli.h gscompt.h
+gxiinit.o: gsiparam.h gsxfont.h gxtext.h gstext.h gsccode.h gsparam.h
+gxiinit.o: gsmalloc.h gzpath.h gxpath.h gspenum.h gsrect.h gzcpath.h
+gxiinit.o: gxcpath.h gxdevmem.h gximage.h gxcspace.h gscspace.h strimpl.h
+gxiinit.o: scommon.h siscale.h gconfigv.h gxdda.h gxiparam.h gxsample.h
+gxiinit.o: gdevmrop.h
+
+gximage3.o: math_.h std.h stdpre.h arch.h memory_.h gx.h stdio_.h gserror.h
+gximage3.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h
+gximage3.o: gsbitops.h gscspace.h gsiparm3.h gsiparam.h gsmatrix.h gsstruct.h
+gximage3.o: gxdevice.h gxdevcli.h gscompt.h gsdcolor.h gsccolor.h gxarith.h
+gximage3.o: gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h gsrefct.h gsropt.h
+gximage3.o: gsxfont.h gxcvalue.h gxfixed.h gxtext.h gstext.h gsccode.h
+gximage3.o: gsparam.h gsmalloc.h gxdevmem.h gxclipm.h gxmclip.h gxclip.h
+gximage3.o: gxiparam.h gxistate.h gscsel.h gxline.h gslparam.h gxmatrix.h
+gximage3.o: gxtmap.h
+
+gximage4.o: memory_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gximage4.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h gscspace.h
+gximage4.o: gsiparm3.h gsiparam.h gsmatrix.h gsiparm4.h gxiparam.h gxdevcli.h
+gximage4.o: gscompt.h gsdcolor.h gsccolor.h gsstruct.h gxarith.h gxbitmap.h
+gximage4.o: gsbitmap.h gxhttile.h gxcindex.h gsbitops.h gsrefct.h gsropt.h
+gximage4.o: gsxfont.h gxcvalue.h gxfixed.h gxtext.h gstext.h gsccode.h
+
+gximono.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gximono.o: gsmemory.h gsmemraw.h gdebug.h memory_.h gpcheck.h gserrors.h
+gximono.o: gxfixed.h gxarith.h gxmatrix.h gsmatrix.h gsccolor.h gsstruct.h
+gximono.o: gspaint.h gsutil.h gxdevice.h gxdevcli.h gscompt.h gsdcolor.h
+gximono.o: gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h gsbitops.h gsiparam.h
+gximono.o: gsrefct.h gsropt.h gsxfont.h gxcvalue.h gxtext.h gstext.h
+gximono.o: gsccode.h gsparam.h gsmalloc.h gxcmap.h gscsel.h gxfmap.h gxfrac.h
+gximono.o: gxtmap.h gxdcolor.h gxistate.h gxline.h gslparam.h gzpath.h
+gximono.o: gxpath.h gscpm.h gspenum.h gsrect.h gxdevmem.h gdevmem.h
+gximono.o: gxbitops.h gxcpath.h gximage.h gxcspace.h gscspace.h strimpl.h
+gximono.o: scommon.h siscale.h gconfigv.h gxdda.h gxiparam.h gxsample.h
+gximono.o: gzht.h gxht.h gscsepnm.h gsht1.h gsht.h gxhttype.h gxdht.h
+
+gxiscale.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gxiscale.o: gsmemory.h gsmemraw.h gdebug.h math_.h memory_.h gpcheck.h
+gxiscale.o: gserrors.h gxfixed.h gxfrac.h gxarith.h gxmatrix.h gsmatrix.h
+gxiscale.o: gsccolor.h gsstruct.h gspaint.h gxdevice.h gxdevcli.h gscompt.h
+gxiscale.o: gsdcolor.h gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h gsbitops.h
+gxiscale.o: gsiparam.h gsrefct.h gsropt.h gsxfont.h gxcvalue.h gxtext.h
+gxiscale.o: gstext.h gsccode.h gsparam.h gsmalloc.h gxcmap.h gscsel.h
+gxiscale.o: gxfmap.h gxtmap.h gxdcolor.h gxistate.h gxline.h gslparam.h
+gxiscale.o: gzpath.h gxpath.h gscpm.h gspenum.h gsrect.h gxdevmem.h gxcpath.h
+gxiscale.o: gximage.h gxcspace.h gscspace.h strimpl.h scommon.h siscale.h
+gxiscale.o: gconfigv.h gxdda.h gxiparam.h gxsample.h
+
+gxmclip.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gxmclip.o: gsmemory.h gsmemraw.h gdebug.h gxdevice.h gxdevcli.h gscompt.h
+gxmclip.o: gsdcolor.h gsccolor.h gsstruct.h gxarith.h gxbitmap.h gsbitmap.h
+gxmclip.o: gxhttile.h gxcindex.h gsbitops.h gsmatrix.h gsiparam.h gsrefct.h
+gxmclip.o: gsropt.h gsxfont.h gxcvalue.h gxfixed.h gxtext.h gstext.h
+gxmclip.o: gsccode.h gsparam.h gsmalloc.h gxdevmem.h gxmclip.h gxclip.h
+
+gxp1fill.o: math_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gxp1fill.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h gsrop.h
+gxp1fill.o: gsropt.h gsmatrix.h gxcspace.h gscspace.h gsccolor.h gsstruct.h
+gxp1fill.o: gscsel.h gxfrac.h gxcolor2.h gscolor2.h gsptype1.h gspcolor.h
+gxp1fill.o: gsuid.h gxbitmap.h gsbitmap.h gsrefct.h gxdcolor.h gsdcolor.h
+gxp1fill.o: gxarith.h gxhttile.h gxcindex.h gsbitops.h gxdevcli.h gscompt.h
+gxp1fill.o: gsiparam.h gsxfont.h gxcvalue.h gxfixed.h gxtext.h gstext.h
+gxp1fill.o: gsccode.h gxdevmem.h gxclip2.h gxmclip.h gxclip.h gxpcolor.h
+gxp1fill.o: gxpcache.h gxp1fill.h
+
+gxpaint.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gxpaint.o: gsmemory.h gsmemraw.h gdebug.h gzstate.h gscpm.h gsrefct.h
+gxpaint.o: gxdcolor.h gscsel.h gsdcolor.h gsccolor.h gsstruct.h gxarith.h
+gxpaint.o: gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h gsbitops.h gsropt.h
+gxpaint.o: gxistate.h gxcvalue.h gxfixed.h gxline.h gslparam.h gxmatrix.h
+gxpaint.o: gsmatrix.h gxtmap.h gsstate.h gsdevice.h gsline.h gscolor.h gsht.h
+gxpaint.o: gxstate.h gxdevice.h gxdevcli.h gscompt.h gsiparam.h gsxfont.h
+gxpaint.o: gxtext.h gstext.h gsccode.h gsparam.h gsmalloc.h gxpaint.h
+gxpaint.o: gxpath.h gspenum.h gsrect.h
+
+gxpath2.o: math_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gxpath2.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h gxfixed.h
+gxpath2.o: gxarith.h gzpath.h gxpath.h gscpm.h gslparam.h gspenum.h gsrect.h
+gxpath2.o: gsmatrix.h gsrefct.h gsstruct.h
+
+gxpath.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gxpath.o: gsmemory.h gsmemraw.h gdebug.h gserrors.h gsstruct.h gxfixed.h
+gxpath.o: gzpath.h gxpath.h gscpm.h gslparam.h gspenum.h gsrect.h gsmatrix.h
+gxpath.o: gsrefct.h
+
+gxpcmap.o: math_.h std.h stdpre.h arch.h memory_.h gx.h stdio_.h gserror.h
+gxpcmap.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h
+gxpcmap.o: gsstruct.h gsutil.h gxfixed.h gxmatrix.h gsmatrix.h gxcspace.h
+gxpcmap.o: gscspace.h gsccolor.h gscsel.h gxfrac.h gxcolor2.h gscolor2.h
+gxpcmap.o: gsptype1.h gspcolor.h gsuid.h gxbitmap.h gsbitmap.h gsrefct.h
+gxpcmap.o: gxdcolor.h gsdcolor.h gxarith.h gxhttile.h gxcindex.h gsbitops.h
+gxpcmap.o: gsropt.h gxdevice.h gxdevcli.h gscompt.h gsiparam.h gsxfont.h
+gxpcmap.o: gxcvalue.h gxtext.h gstext.h gsccode.h gsparam.h gsmalloc.h
+gxpcmap.o: gxdevmem.h gxpcolor.h gxpcache.h gzstate.h gscpm.h gxistate.h
+gxpcmap.o: gxline.h gslparam.h gxtmap.h gsstate.h gsdevice.h gsline.h
+gxpcmap.o: gscolor.h gsht.h gxstate.h gzpath.h gxpath.h gspenum.h gsrect.h
+gxpcmap.o: gzcpath.h gxcpath.h
+
+gxpcopy.o: math_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gxpcopy.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h gconfigv.h
+gxpcopy.o: gxfixed.h gxfarith.h gxarith.h gzpath.h gxpath.h gscpm.h
+gxpcopy.o: gslparam.h gspenum.h gsrect.h gsmatrix.h gsrefct.h gsstruct.h
+
+gxpdash.o: math_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gxpdash.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gsmatrix.h gscoord.h
+gxpdash.o: gxfixed.h gsline.h gslparam.h gzline.h gxline.h gzpath.h gxpath.h
+gxpdash.o: gscpm.h gspenum.h gsrect.h gsrefct.h gsstruct.h
+
+gxpflat.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gxpflat.o: gsmemory.h gsmemraw.h gdebug.h gxarith.h gxfixed.h gzpath.h
+gxpflat.o: gxpath.h gscpm.h gslparam.h gspenum.h gsrect.h gsmatrix.h
+gxpflat.o: gsrefct.h gsstruct.h
+
+gxsample.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+gxsample.o: gsmemory.h gsmemraw.h gdebug.h gxsample.h
+
+gxshade1.o: math_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gxshade1.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h gsmatrix.h
+gxshade1.o: gscoord.h gspath.h gspenum.h gxcspace.h gscspace.h gsccolor.h
+gxshade1.o: gsstruct.h gscsel.h gxfrac.h gxdcolor.h gsdcolor.h gxarith.h
+gxshade1.o: gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h gsbitops.h gsropt.h
+gxshade1.o: gxfarith.h gconfigv.h gxfixed.h gxistate.h gsrefct.h gxcvalue.h
+gxshade1.o: gxline.h gslparam.h gxmatrix.h gxtmap.h gxpath.h gscpm.h gsrect.h
+gxshade1.o: gxshade.h gsshade.h gsdsrc.h gsfunc.h stream.h scommon.h
+
+gxshade4.o: memory_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gxshade4.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h gsmatrix.h
+gxshade4.o: gscoord.h gxcspace.h gscspace.h gsccolor.h gsstruct.h gscsel.h
+gxshade4.o: gxfrac.h gxdcolor.h gsdcolor.h gxarith.h gxbitmap.h gsbitmap.h
+gxshade4.o: gxhttile.h gxcindex.h gsbitops.h gsropt.h gxdevcli.h gscompt.h
+gxshade4.o: gsiparam.h gsrefct.h gsxfont.h gxcvalue.h gxfixed.h gxtext.h
+gxshade4.o: gstext.h gsccode.h gxistate.h gxline.h gslparam.h gxmatrix.h
+gxshade4.o: gxtmap.h gxpath.h gscpm.h gspenum.h gsrect.h gxshade.h gsshade.h
+gxshade4.o: gsdsrc.h gsfunc.h stream.h scommon.h gxshade4.h
+
+gxshade6.o: memory_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gxshade6.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h gsmatrix.h
+gxshade6.o: gscoord.h gxcspace.h gscspace.h gsccolor.h gsstruct.h gscsel.h
+gxshade6.o: gxfrac.h gxdcolor.h gsdcolor.h gxarith.h gxbitmap.h gsbitmap.h
+gxshade6.o: gxhttile.h gxcindex.h gsbitops.h gsropt.h gxistate.h gsrefct.h
+gxshade6.o: gxcvalue.h gxfixed.h gxline.h gslparam.h gxmatrix.h gxtmap.h
+gxshade6.o: gxshade.h gsshade.h gsdsrc.h gsfunc.h stream.h scommon.h
+gxshade6.o: gxshade4.h gzpath.h gxpath.h gscpm.h gspenum.h gsrect.h
+
+gxshade.o: math_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gxshade.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h gsrect.h
+gxshade.o: gxcspace.h gscspace.h gsccolor.h gsstruct.h gscsel.h gxfrac.h
+gxshade.o: gscie.h gsrefct.h gxctable.h gxfixed.h gxdevcli.h gscompt.h
+gxshade.o: gsdcolor.h gxarith.h gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h
+gxshade.o: gsbitops.h gsmatrix.h gsiparam.h gsropt.h gsxfont.h gxcvalue.h
+gxshade.o: gxtext.h gstext.h gsccode.h gxistate.h gxline.h gslparam.h
+gxshade.o: gxmatrix.h gxtmap.h gxdht.h gscsepnm.h gxhttype.h gxpaint.h
+gxshade.o: gxshade.h gsshade.h gsdsrc.h gsfunc.h stream.h scommon.h
+
+gxstroke.o: math_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gxstroke.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gpcheck.h gserrors.h
+gxstroke.o: gsdcolor.h gsccolor.h gsstruct.h gxarith.h gxbitmap.h gsbitmap.h
+gxstroke.o: gxhttile.h gxcindex.h gsbitops.h gxfixed.h gxfarith.h gconfigv.h
+gxstroke.o: gxmatrix.h gsmatrix.h gscoord.h gsdevice.h gxdevice.h gxdevcli.h
+gxstroke.o: gscompt.h gsiparam.h gsrefct.h gsropt.h gsxfont.h gxcvalue.h
+gxstroke.o: gxtext.h gstext.h gsccode.h gsparam.h gsmalloc.h gxistate.h
+gxstroke.o: gscsel.h gxline.h gslparam.h gxtmap.h gzline.h gzpath.h gxpath.h
+gxstroke.o: gscpm.h gspenum.h gsrect.h gzcpath.h gxcpath.h gxpaint.h
+
+gxtype1.o: math_.h std.h stdpre.h arch.h gx.h stdio_.h gserror.h gsio.h
+gxtype1.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h gsccode.h
+gxtype1.o: gsline.h gslparam.h gsstruct.h gxarith.h gxfixed.h gxistate.h
+gxtype1.o: gscsel.h gsrefct.h gsropt.h gxcvalue.h gxline.h gxmatrix.h
+gxtype1.o: gsmatrix.h gxtmap.h gxcoord.h gscoord.h gxfont.h gsfont.h gsuid.h
+gxtype1.o: gxftype.h gxfont1.h gxtype1.h gscrypt1.h gstype1.h gxop1.h
+gxtype1.o: gzpath.h gxpath.h gscpm.h gspenum.h gsrect.h
+
+ialloc.o: gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+ialloc.o: gsmemory.h gsmemraw.h gdebug.h memory_.h errors.h gsstruct.h
+ialloc.o: gxarith.h iref.h iastate.h gxalloc.h gsalloc.h gxobj.h gxbitmap.h
+ialloc.o: gsbitmap.h istruct.h ialloc.h imemory.h ivmspace.h gsgc.h ipacked.h
+ialloc.o: iutil.h store.h
+
+ibnum.o: math_.h std.h stdpre.h arch.h memory_.h ghost.h gx.h stdio_.h
+ibnum.o: gserror.h gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h
+ibnum.o: errors.h stream.h scommon.h gsstruct.h ibnum.h imemory.h ivmspace.h
+ibnum.o: gsgc.h gsalloc.h iutil.h
+
+iccinit0.o: stdpre.h
+
+iconfig.o: stdio_.h std.h stdpre.h arch.h gstypes.h gsmemory.h gsmemraw.h
+iconfig.o: gconf.h gconfig.h ../config.h iref.h ivmspace.h gsgc.h opdef.h
+iconfig.o: iminst.h
+
+icontext.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+icontext.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h gsstruct.h
+icontext.o: gxalloc.h gsalloc.h gxobj.h gxbitmap.h gsbitmap.h errors.h
+icontext.o: stream.h scommon.h files.h idict.h igstate.h gsstate.h gsdevice.h
+icontext.o: gsline.h gslparam.h gscolor.h gxtmap.h gsht.h gscsel.h gxstate.h
+icontext.o: istruct.h icontext.h icstate.h imemory.h ivmspace.h gsgc.h
+icontext.o: interp.h isave.h dstack.h idstack.h istack.h estack.h iestack.h
+icontext.o: ostack.h iostack.h store.h ialloc.h
+
+idebug.o: string_.h std.h stdpre.h arch.h ghost.h gx.h stdio_.h gserror.h
+idebug.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h ialloc.h
+idebug.o: imemory.h ivmspace.h gsgc.h gsalloc.h idebug.h idict.h iname.h
+idebug.o: inames.h ipacked.h istack.h iutil.h opdef.h
+
+idict.o: string_.h std.h stdpre.h arch.h ghost.h gx.h stdio_.h gserror.h
+idict.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h errors.h
+idict.o: imemory.h ivmspace.h gsgc.h gsalloc.h idebug.h inamedef.h inames.h
+idict.o: gconfigv.h gsstruct.h iname.h ipacked.h isave.h store.h ialloc.h
+idict.o: idict.h idictdef.h iutil.h idstack.h istack.h
+
+idparam.o: memory_.h std.h stdpre.h arch.h string_.h ghost.h gx.h stdio_.h
+idparam.o: gserror.h gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h
+idparam.o: errors.h gsmatrix.h gsuid.h idict.h idparam.h ilevel.h imemory.h
+idparam.o: ivmspace.h gsgc.h gsalloc.h iname.h inames.h iutil.h oper.h
+idparam.o: ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h store.h
+idparam.o: ialloc.h
+
+idstack.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+idstack.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h idict.h idictdef.h
+idstack.o: idstack.h istack.h inamedef.h inames.h gconfigv.h gsstruct.h
+idstack.o: iname.h ipacked.h iutil.h ivmspace.h gsgc.h
+
+igcref.o: memory_.h std.h stdpre.h arch.h ghost.h gx.h stdio_.h gserror.h
+igcref.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h gsexit.h
+igcref.o: gsstruct.h iname.h inames.h iastate.h gxalloc.h gsalloc.h gxobj.h
+igcref.o: gxbitmap.h gsbitmap.h istruct.h ialloc.h imemory.h ivmspace.h
+igcref.o: gsgc.h idebug.h igc.h ipacked.h store.h
+
+igcstr.o: memory_.h std.h stdpre.h arch.h ghost.h gx.h stdio_.h gserror.h
+igcstr.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h gsmdebug.h
+igcstr.o: gsstruct.h iastate.h gxalloc.h gsalloc.h gxobj.h gxbitmap.h
+igcstr.o: gsbitmap.h istruct.h ialloc.h imemory.h ivmspace.h gsgc.h igcstr.h
+
+igc.o: memory_.h std.h stdpre.h arch.h ghost.h gx.h stdio_.h gserror.h gsio.h
+igc.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h errors.h gsexit.h
+igc.o: gsmdebug.h gsstruct.h gsutil.h iastate.h gxalloc.h gsalloc.h gxobj.h
+igc.o: gxbitmap.h gsbitmap.h istruct.h ialloc.h imemory.h ivmspace.h gsgc.h
+igc.o: isave.h isstate.h idict.h ipacked.h igc.h igcstr.h inamedef.h inames.h
+igc.o: gconfigv.h opdef.h
+
+iinit.o: string_.h std.h stdpre.h arch.h ghost.h gx.h stdio_.h gserror.h
+iinit.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h gscdefs.h
+iinit.o: gconfigv.h gsexit.h gsstruct.h errors.h ialloc.h imemory.h
+iinit.o: ivmspace.h gsgc.h gsalloc.h idict.h dstack.h idstack.h istack.h
+iinit.o: ilevel.h iname.h inames.h interp.h ipacked.h iparray.h iutil.h
+iinit.o: opdef.h store.h
+
+ilocate.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+ilocate.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h memory_.h errors.h
+ilocate.o: gsexit.h gsstruct.h iastate.h gxalloc.h gsalloc.h gxobj.h
+ilocate.o: gxbitmap.h gsbitmap.h istruct.h ialloc.h imemory.h ivmspace.h
+ilocate.o: gsgc.h idict.h igc.h igcstr.h iname.h inames.h ipacked.h isstate.h
+ilocate.o: iutil.h store.h
+
+imainarg.o: ctype_.h std.h stdpre.h arch.h memory_.h string_.h ghost.h gx.h
+imainarg.o: stdio_.h gserror.h gsio.h gstypes.h gsmemory.h gsmemraw.h
+imainarg.o: gdebug.h iref.h gp.h gpgetenv.h gsargs.h gscdefs.h gconfigv.h
+imainarg.o: gsmalloc.h gsmdebug.h gxdevice.h gxdevcli.h gscompt.h gsdcolor.h
+imainarg.o: gsccolor.h gsstruct.h gxarith.h gxbitmap.h gsbitmap.h gxhttile.h
+imainarg.o: gxcindex.h gsbitops.h gsmatrix.h gsiparam.h gsrefct.h gsropt.h
+imainarg.o: gsxfont.h gxcvalue.h gxfixed.h gxtext.h gstext.h gsccode.h
+imainarg.o: gsparam.h gxdevmem.h gsdevice.h stream.h scommon.h errors.h
+imainarg.o: estack.h iestack.h istack.h ialloc.h imemory.h ivmspace.h gsgc.h
+imainarg.o: gsalloc.h strimpl.h sfilter.h ostack.h iostack.h iscan.h sa85x.h
+imainarg.o: sstring.h imain.h gsexit.h imainarg.h iminst.h iname.h inames.h
+imainarg.o: store.h files.h interp.h iutil.h
+
+imain.o: memory_.h std.h stdpre.h arch.h string_.h ghost.h gx.h stdio_.h
+imain.o: gserror.h gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h
+imain.o: gp.h gpgetenv.h gslib.h gsmatrix.h gsutil.h gxdevice.h gxdevcli.h
+imain.o: gscompt.h gsdcolor.h gsccolor.h gsstruct.h gxarith.h gxbitmap.h
+imain.o: gsbitmap.h gxhttile.h gxcindex.h gsbitops.h gsiparam.h gsrefct.h
+imain.o: gsropt.h gsxfont.h gxcvalue.h gxfixed.h gxtext.h gstext.h gsccode.h
+imain.o: gsparam.h gsmalloc.h errors.h oper.h ostack.h iostack.h istack.h
+imain.o: opdef.h opextern.h opcheck.h iutil.h idebug.h idict.h iname.h
+imain.o: inames.h dstack.h idstack.h estack.h iestack.h stream.h scommon.h
+imain.o: files.h ialloc.h imemory.h ivmspace.h gsgc.h gsalloc.h strimpl.h
+imain.o: sfilter.h iscan.h sa85x.h sstring.h main.h imain.h gsexit.h iminst.h
+imain.o: store.h isave.h interp.h
+
+iname.o: memory_.h std.h stdpre.h arch.h string_.h ghost.h gx.h stdio_.h
+iname.o: gserror.h gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h
+iname.o: gsstruct.h gxobj.h gxbitmap.h gsbitmap.h errors.h inamedef.h
+iname.o: inames.h gconfigv.h imemory.h ivmspace.h gsgc.h gsalloc.h isave.h
+iname.o: store.h ialloc.h
+
+interp.o: memory_.h std.h stdpre.h arch.h string_.h ghost.h gx.h stdio_.h
+interp.o: gserror.h gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h
+interp.o: gsstruct.h stream.h scommon.h errors.h estack.h iestack.h istack.h
+interp.o: ialloc.h imemory.h ivmspace.h gsgc.h gsalloc.h iastruct.h gxobj.h
+interp.o: gxbitmap.h gsbitmap.h icontext.h icstate.h inamedef.h inames.h
+interp.o: gconfigv.h iname.h interp.h ipacked.h ostack.h iostack.h strimpl.h
+interp.o: sfilter.h iscan.h sa85x.h sstring.h idict.h isave.h iutil.h
+interp.o: dstack.h idstack.h files.h oper.h opdef.h opextern.h opcheck.h
+interp.o: store.h
+
+iparam.o: memory_.h std.h stdpre.h arch.h string_.h ghost.h gx.h stdio_.h
+iparam.o: gserror.h gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h
+iparam.o: errors.h oper.h ostack.h iostack.h istack.h opdef.h opextern.h
+iparam.o: opcheck.h iutil.h ialloc.h imemory.h ivmspace.h gsgc.h gsalloc.h
+iparam.o: idict.h iname.h inames.h iparam.h gsparam.h store.h
+
+ireclaim.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+ireclaim.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h errors.h
+ireclaim.o: gsstruct.h iastate.h gxalloc.h gsalloc.h gxobj.h gxbitmap.h
+ireclaim.o: gsbitmap.h istruct.h ialloc.h imemory.h ivmspace.h gsgc.h
+ireclaim.o: icontext.h icstate.h interp.h isave.h isstate.h dstack.h
+ireclaim.o: idstack.h istack.h estack.h iestack.h ostack.h iostack.h opdef.h
+ireclaim.o: store.h
+
+isave.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+isave.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h memory_.h errors.h
+isave.o: gsexit.h gsstruct.h stream.h scommon.h iastate.h gxalloc.h gsalloc.h
+isave.o: gxobj.h gxbitmap.h gsbitmap.h istruct.h ialloc.h imemory.h
+isave.o: ivmspace.h gsgc.h inamedef.h inames.h gconfigv.h iname.h ipacked.h
+isave.o: isave.h isstate.h store.h gsutil.h
+
+iscanbin.o: math_.h std.h stdpre.h arch.h memory_.h ghost.h gx.h stdio_.h
+iscanbin.o: gserror.h gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h
+iscanbin.o: gsutil.h stream.h scommon.h gsstruct.h strimpl.h sfilter.h
+iscanbin.o: errors.h ialloc.h imemory.h ivmspace.h gsgc.h gsalloc.h idict.h
+iscanbin.o: dstack.h idstack.h istack.h ostack.h iostack.h iname.h inames.h
+iscanbin.o: iscan.h sa85x.h sstring.h iutil.h store.h btoken.h ibnum.h
+
+iscannum.o: math_.h std.h stdpre.h arch.h ghost.h gx.h stdio_.h gserror.h
+iscannum.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h errors.h
+iscannum.o: scommon.h gsstruct.h iscannum.h scanchar.h store.h ialloc.h
+iscannum.o: imemory.h ivmspace.h gsgc.h gsalloc.h
+
+iscan.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+iscan.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h memory_.h stream.h
+iscan.o: scommon.h gsstruct.h errors.h files.h ialloc.h imemory.h ivmspace.h
+iscan.o: gsgc.h gsalloc.h idict.h dstack.h idstack.h istack.h ilevel.h
+iscan.o: iname.h inames.h ipacked.h iparray.h strimpl.h sfilter.h ostack.h
+iscan.o: iostack.h iscan.h sa85x.h sstring.h iscannum.h istream.h istruct.h
+iscan.o: iutil.h store.h scanchar.h
+
+istack.o: memory_.h std.h stdpre.h arch.h ghost.h gx.h stdio_.h gserror.h
+istack.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h gsstruct.h
+istack.o: gsutil.h errors.h ialloc.h imemory.h ivmspace.h gsgc.h gsalloc.h
+istack.o: istack.h istruct.h iutil.h store.h
+
+iutil2.o: memory_.h std.h stdpre.h arch.h string_.h ghost.h gx.h stdio_.h
+iutil2.o: gserror.h gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h
+iutil2.o: errors.h opcheck.h gsparam.h gsutil.h idict.h imemory.h ivmspace.h
+iutil2.o: gsgc.h gsalloc.h iutil.h iutil2.h
+
+iutil.o: math_.h std.h stdpre.h arch.h memory_.h string_.h ghost.h gx.h
+iutil.o: stdio_.h gserror.h gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h
+iutil.o: iref.h errors.h idict.h imemory.h ivmspace.h gsgc.h gsalloc.h
+iutil.o: iname.h inames.h ipacked.h iutil.h oper.h ostack.h iostack.h
+iutil.o: istack.h opdef.h opextern.h opcheck.h store.h ialloc.h gsccode.h
+iutil.o: gsmatrix.h gsutil.h gxfont.h gsfont.h gsuid.h gsstruct.h gxftype.h
+
+sbcp.o: stdio_.h std.h stdpre.h arch.h strimpl.h scommon.h gsmemory.h
+sbcp.o: gsmemraw.h gstypes.h gsstruct.h sfilter.h
+
+sbhc.o: memory_.h std.h stdpre.h arch.h stdio_.h gdebug.h strimpl.h scommon.h
+sbhc.o: gsmemory.h gsmemraw.h gstypes.h gsstruct.h sbhc.h shc.h gsbittab.h
+sbhc.o: shcgen.h
+
+sbwbs.o: stdio_.h std.h stdpre.h arch.h memory_.h gdebug.h strimpl.h
+sbwbs.o: scommon.h gsmemory.h gsmemraw.h gstypes.h gsstruct.h sfilter.h
+sbwbs.o: sbwbs.h
+
+scantab.o: stdpre.h scommon.h gsmemory.h gsmemraw.h gstypes.h gsstruct.h
+scantab.o: scanchar.h
+
+scfdtab.o: std.h stdpre.h arch.h scommon.h gsmemory.h gsmemraw.h gstypes.h
+scfdtab.o: gsstruct.h scf.h shc.h gsbittab.h
+
+scfd.o: stdio_.h std.h stdpre.h arch.h memory_.h gdebug.h strimpl.h scommon.h
+scfd.o: gsmemory.h gsmemraw.h gstypes.h gsstruct.h scf.h shc.h gsbittab.h
+scfd.o: scfx.h
+
+scfetab.o: std.h stdpre.h arch.h scommon.h gsmemory.h gsmemraw.h gstypes.h
+scfetab.o: gsstruct.h scf.h shc.h gsbittab.h
+
+scfe.o: stdio_.h std.h stdpre.h arch.h memory_.h gdebug.h strimpl.h scommon.h
+scfe.o: gsmemory.h gsmemraw.h gstypes.h gsstruct.h scf.h shc.h gsbittab.h
+scfe.o: scfx.h
+
+scfparam.o: std.h stdpre.h arch.h gserror.h gserrors.h gstypes.h gsmemory.h
+scfparam.o: gsmemraw.h gsparam.h scommon.h gsstruct.h scf.h shc.h gsbittab.h
+scfparam.o: scfx.h
+
+sdcparam.o: ../config.h memory_.h std.h stdpre.h arch.h gserror.h gserrors.h
+sdcparam.o: gstypes.h gsmemory.h gsmemraw.h gsparam.h strimpl.h scommon.h
+sdcparam.o: gsstruct.h sdct.h sdcparam.h sjpeg.h
+
+sdctc.o: ../config.h stdio_.h std.h stdpre.h arch.h gsmemory.h gsmemraw.h
+sdctc.o: gsmalloc.h strimpl.h scommon.h gstypes.h gsstruct.h sdct.h
+
+sdctd.o: ../config.h memory_.h std.h stdpre.h arch.h stdio_.h gdebug.h
+sdctd.o: gsmemory.h gsmemraw.h gsmalloc.h strimpl.h scommon.h gstypes.h
+sdctd.o: gsstruct.h sdct.h sjpeg.h
+
+sdcte.o: ../config.h memory_.h std.h stdpre.h arch.h stdio_.h gdebug.h
+sdcte.o: gsmemory.h gsmemraw.h gsmalloc.h strimpl.h scommon.h gstypes.h
+sdcte.o: gsstruct.h sdct.h sjpeg.h
+
+sddparam.o: ../config.h std.h stdpre.h arch.h gserror.h gserrors.h gstypes.h
+sddparam.o: gsmemory.h gsmemraw.h gsparam.h strimpl.h scommon.h gsstruct.h
+sddparam.o: sdct.h sdcparam.h sjpeg.h
+
+sdeparam.o: ../config.h memory_.h std.h stdpre.h arch.h gserror.h gserrors.h
+sdeparam.o: gstypes.h gsmemory.h gsmemraw.h gsparam.h strimpl.h scommon.h
+sdeparam.o: gsstruct.h sdct.h sdcparam.h sjpeg.h
+
+seexec.o: stdio_.h std.h stdpre.h arch.h strimpl.h scommon.h gsmemory.h
+seexec.o: gsmemraw.h gstypes.h gsstruct.h sfilter.h gscrypt1.h scanchar.h
+
+sfilter1.o: stdio_.h std.h stdpre.h arch.h memory_.h strimpl.h scommon.h
+sfilter1.o: gsmemory.h gsmemraw.h gstypes.h gsstruct.h sfilter.h
+
+sfilter2.o: stdio_.h std.h stdpre.h arch.h memory_.h strimpl.h scommon.h
+sfilter2.o: gsmemory.h gsmemraw.h gstypes.h gsstruct.h sa85x.h sbtx.h
+sfilter2.o: scanchar.h
+
+sfxstdio.o: stdio_.h std.h stdpre.h arch.h memory_.h gdebug.h gpcheck.h
+sfxstdio.o: stream.h scommon.h gsmemory.h gsmemraw.h gstypes.h gsstruct.h
+sfxstdio.o: strimpl.h
+
+shcgen.o: memory_.h std.h stdpre.h arch.h stdio_.h gdebug.h gserror.h
+shcgen.o: gserrors.h gsmemory.h gsmemraw.h scommon.h gstypes.h gsstruct.h
+shcgen.o: shc.h gsbittab.h shcgen.h
+
+shc.o: std.h stdpre.h arch.h scommon.h gsmemory.h gsmemraw.h gstypes.h
+shc.o: gsstruct.h shc.h gsbittab.h
+
+siscale.o: math_.h std.h stdpre.h arch.h memory_.h stdio_.h strimpl.h
+siscale.o: scommon.h gsmemory.h gsmemraw.h gstypes.h gsstruct.h siscale.h
+siscale.o: gconfigv.h
+
+sjpegc.o: ../config.h stdio_.h std.h stdpre.h arch.h string_.h gx.h gserror.h
+sjpegc.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h
+sjpegc.o: strimpl.h scommon.h gsstruct.h sdct.h sjpeg.h
+
+sjpegd.o: ../config.h stdio_.h std.h stdpre.h arch.h string_.h gx.h gserror.h
+sjpegd.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h
+sjpegd.o: strimpl.h scommon.h gsstruct.h sdct.h sjpeg.h
+
+sjpegerr.o: ../config.h stdio_.h std.h stdpre.h arch.h
+
+sjpege.o: ../config.h stdio_.h std.h stdpre.h arch.h string_.h gx.h gserror.h
+sjpege.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h gserrors.h
+sjpege.o: strimpl.h scommon.h gsstruct.h sdct.h sjpeg.h
+
+slzwce.o: stdio_.h std.h stdpre.h arch.h gdebug.h strimpl.h scommon.h
+slzwce.o: gsmemory.h gsmemraw.h gstypes.h gsstruct.h slzwx.h
+
+slzwc.o: std.h stdpre.h arch.h strimpl.h scommon.h gsmemory.h gsmemraw.h
+slzwc.o: gstypes.h gsstruct.h slzwx.h
+
+slzwd.o: stdio_.h std.h stdpre.h arch.h gdebug.h strimpl.h scommon.h
+slzwd.o: gsmemory.h gsmemraw.h gstypes.h gsstruct.h slzwx.h
+
+smtf.o: stdio_.h std.h stdpre.h arch.h strimpl.h scommon.h gsmemory.h
+smtf.o: gsmemraw.h gstypes.h gsstruct.h smtf.h
+
+spcxd.o: stdio_.h std.h stdpre.h arch.h memory_.h strimpl.h scommon.h
+spcxd.o: gsmemory.h gsmemraw.h gstypes.h gsstruct.h spcxx.h
+
+spdiff.o: stdio_.h std.h stdpre.h arch.h strimpl.h scommon.h gsmemory.h
+spdiff.o: gsmemraw.h gstypes.h gsstruct.h spdiffx.h
+
+spngp.o: memory_.h std.h stdpre.h arch.h strimpl.h scommon.h gsmemory.h
+spngp.o: gsmemraw.h gstypes.h gsstruct.h spngpx.h
+
+srld.o: stdio_.h std.h stdpre.h arch.h memory_.h strimpl.h scommon.h
+srld.o: gsmemory.h gsmemraw.h gstypes.h gsstruct.h srlx.h
+
+srle.o: stdio_.h std.h stdpre.h arch.h memory_.h strimpl.h scommon.h
+srle.o: gsmemory.h gsmemraw.h gstypes.h gsstruct.h srlx.h
+
+sstring.o: stdio_.h std.h stdpre.h arch.h memory_.h string_.h strimpl.h
+sstring.o: scommon.h gsmemory.h gsmemraw.h gstypes.h gsstruct.h sstring.h
+sstring.o: scanchar.h
+
+stream.o: stdio_.h std.h stdpre.h arch.h memory_.h gdebug.h gpcheck.h
+stream.o: stream.h scommon.h gsmemory.h gsmemraw.h gstypes.h gsstruct.h
+stream.o: strimpl.h
+
+szlibc.o: ../config.h std.h stdpre.h arch.h gserror.h gserrors.h gstypes.h
+szlibc.o: gsmemory.h gsmemraw.h gsmalloc.h gsstruct.h strimpl.h scommon.h
+szlibc.o: szlibxx.h szlibx.h
+
+szlibd.o: ../config.h std.h stdpre.h arch.h gsmemory.h gsmemraw.h gsmalloc.h
+szlibd.o: strimpl.h scommon.h gstypes.h gsstruct.h szlibxx.h szlibx.h
+
+szlibe.o: ../config.h std.h stdpre.h arch.h gsmemory.h gsmemraw.h gsmalloc.h
+szlibe.o: strimpl.h scommon.h gstypes.h gsstruct.h szlibxx.h szlibx.h
+
+zarith.o: math_.h std.h stdpre.h arch.h ghost.h gx.h stdio_.h gserror.h
+zarith.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h
+zarith.o: errors.h ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h
+zarith.o: iutil.h store.h ialloc.h imemory.h ivmspace.h gsgc.h gsalloc.h
+
+zarray.o: memory_.h std.h stdpre.h arch.h ghost.h gx.h stdio_.h gserror.h
+zarray.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h ialloc.h
+zarray.o: imemory.h ivmspace.h gsgc.h gsalloc.h ipacked.h oper.h errors.h
+zarray.o: ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h iutil.h
+zarray.o: store.h
+
+zbseq.o: memory_.h std.h stdpre.h arch.h ghost.h gx.h stdio_.h gserror.h
+zbseq.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h
+zbseq.o: errors.h ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h
+zbseq.o: iutil.h ialloc.h imemory.h ivmspace.h gsgc.h gsalloc.h btoken.h
+zbseq.o: store.h
+
+zcfont.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+zcfont.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h errors.h
+zcfont.o: ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h iutil.h
+zcfont.o: gschar.h gsccode.h gscpm.h gsmatrix.h gxfixed.h gxfont.h gsfont.h
+zcfont.o: gsuid.h gsstruct.h gxftype.h gxchar.h gxtext.h gstext.h gsrefct.h
+zcfont.o: estack.h iestack.h ichar.h ifont.h igstate.h gsstate.h gsdevice.h
+zcfont.o: gsline.h gslparam.h gscolor.h gxtmap.h gsht.h gscsel.h gxstate.h
+zcfont.o: istruct.h store.h ialloc.h imemory.h ivmspace.h gsgc.h gsalloc.h
+
+zchar1.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+zchar1.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h errors.h
+zchar1.o: ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h iutil.h
+zchar1.o: gsstruct.h gxfixed.h gxmatrix.h gsmatrix.h gxchar.h gschar.h
+zchar1.o: gsccode.h gscpm.h gxtext.h gstext.h gsrefct.h gxdevice.h gxdevcli.h
+zchar1.o: gscompt.h gsdcolor.h gsccolor.h gxarith.h gxbitmap.h gsbitmap.h
+zchar1.o: gxhttile.h gxcindex.h gsbitops.h gsiparam.h gsropt.h gsxfont.h
+zchar1.o: gxcvalue.h gsparam.h gsmalloc.h gxfont.h gsfont.h gsuid.h gxftype.h
+zchar1.o: gxfont1.h gxtype1.h gscrypt1.h gstype1.h gxop1.h gzstate.h
+zchar1.o: gxdcolor.h gscsel.h gxistate.h gxline.h gslparam.h gxtmap.h
+zchar1.o: gsstate.h gsdevice.h gsline.h gscolor.h gsht.h gxstate.h gspaint.h
+zchar1.o: gspath.h gspenum.h estack.h iestack.h ialloc.h imemory.h ivmspace.h
+zchar1.o: gsgc.h gsalloc.h ichar.h icharout.h idict.h ifont.h igstate.h
+zchar1.o: istruct.h iname.h inames.h store.h
+
+zchar2.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+zchar2.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h errors.h
+zchar2.o: ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h iutil.h
+zchar2.o: gschar.h gsccode.h gscpm.h gsmatrix.h gsstruct.h gxfixed.h gxfont.h
+zchar2.o: gsfont.h gsuid.h gxftype.h gxchar.h gxtext.h gstext.h gsrefct.h
+zchar2.o: estack.h iestack.h ialloc.h imemory.h ivmspace.h gsgc.h gsalloc.h
+zchar2.o: ichar.h ifont.h igstate.h gsstate.h gsdevice.h gsline.h gslparam.h
+zchar2.o: gscolor.h gxtmap.h gsht.h gscsel.h gxstate.h istruct.h iname.h
+zchar2.o: inames.h store.h stream.h scommon.h ibnum.h gspath.h gspenum.h
+
+zchar32.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+zchar32.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h errors.h
+zchar32.o: ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h iutil.h
+zchar32.o: gsccode.h gsmatrix.h gsutil.h gxfixed.h gxchar.h gschar.h gscpm.h
+zchar32.o: gxtext.h gstext.h gsrefct.h gxfont.h gsfont.h gsuid.h gsstruct.h
+zchar32.o: gxftype.h gxfcache.h gsxfont.h gxbcache.h gxbitmap.h gsbitmap.h
+zchar32.o: ifont.h igstate.h gsstate.h gsdevice.h gsline.h gslparam.h
+zchar32.o: gscolor.h gxtmap.h gsht.h gscsel.h gxstate.h istruct.h store.h
+zchar32.o: ialloc.h imemory.h ivmspace.h gsgc.h gsalloc.h
+
+zchar42.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+zchar42.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h errors.h
+zchar42.o: ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h iutil.h
+zchar42.o: gsmatrix.h gspaint.h gspath.h gspenum.h gxfixed.h gxchar.h
+zchar42.o: gschar.h gsccode.h gscpm.h gxtext.h gstext.h gsrefct.h gxfont.h
+zchar42.o: gsfont.h gsuid.h gsstruct.h gxftype.h gxfont42.h gxistate.h
+zchar42.o: gscsel.h gsropt.h gxcvalue.h gxline.h gslparam.h gxmatrix.h
+zchar42.o: gxtmap.h gxpath.h gsrect.h gzstate.h gxdcolor.h gsdcolor.h
+zchar42.o: gsccolor.h gxarith.h gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h
+zchar42.o: gsbitops.h gsstate.h gsdevice.h gsline.h gscolor.h gsht.h
+zchar42.o: gxstate.h dstack.h idstack.h estack.h iestack.h ichar.h icharout.h
+zchar42.o: ifont.h igstate.h istruct.h store.h ialloc.h imemory.h ivmspace.h
+zchar42.o: gsgc.h gsalloc.h
+
+zcharout.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+zcharout.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h errors.h
+zcharout.o: ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h iutil.h
+zcharout.o: gschar.h gsccode.h gscpm.h gxdevice.h gxdevcli.h gscompt.h
+zcharout.o: gsdcolor.h gsccolor.h gsstruct.h gxarith.h gxbitmap.h gsbitmap.h
+zcharout.o: gxhttile.h gxcindex.h gsbitops.h gsmatrix.h gsiparam.h gsrefct.h
+zcharout.o: gsropt.h gsxfont.h gxcvalue.h gxfixed.h gxtext.h gstext.h
+zcharout.o: gsparam.h gsmalloc.h gxfont.h gsfont.h gsuid.h gxftype.h dstack.h
+zcharout.o: idstack.h estack.h iestack.h ichar.h icharout.h idict.h ifont.h
+zcharout.o: igstate.h gsstate.h gsdevice.h gsline.h gslparam.h gscolor.h
+zcharout.o: gxtmap.h gsht.h gscsel.h gxstate.h istruct.h store.h ialloc.h
+zcharout.o: imemory.h ivmspace.h gsgc.h gsalloc.h
+
+zchar.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+zchar.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h errors.h
+zchar.o: ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h iutil.h
+zchar.o: gsstruct.h gxarith.h gxfixed.h gxmatrix.h gsmatrix.h gxchar.h
+zchar.o: gschar.h gsccode.h gscpm.h gxtext.h gstext.h gsrefct.h gxdevice.h
+zchar.o: gxdevcli.h gscompt.h gsdcolor.h gsccolor.h gxbitmap.h gsbitmap.h
+zchar.o: gxhttile.h gxcindex.h gsbitops.h gsiparam.h gsropt.h gsxfont.h
+zchar.o: gxcvalue.h gsparam.h gsmalloc.h gxfont.h gsfont.h gsuid.h gxftype.h
+zchar.o: gzpath.h gxpath.h gslparam.h gspenum.h gsrect.h gzstate.h gxdcolor.h
+zchar.o: gscsel.h gxistate.h gxline.h gxtmap.h gsstate.h gsdevice.h gsline.h
+zchar.o: gscolor.h gsht.h gxstate.h dstack.h idstack.h estack.h iestack.h
+zchar.o: ialloc.h imemory.h ivmspace.h gsgc.h gsalloc.h ichar.h idict.h
+zchar.o: ifont.h igstate.h istruct.h ilevel.h iname.h inames.h ipacked.h
+zchar.o: store.h
+
+zcid.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+zcid.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h errors.h
+zcid.o: ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h iutil.h
+zcid.o: gsmatrix.h gsccode.h gxfont.h gsfont.h gsuid.h gsstruct.h gxftype.h
+zcid.o: bfont.h ifont.h iname.h inames.h store.h ialloc.h imemory.h
+zcid.o: ivmspace.h gsgc.h gsalloc.h
+
+zcie.o: math_.h std.h stdpre.h arch.h memory_.h ghost.h gx.h stdio_.h
+zcie.o: gserror.h gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h
+zcie.o: oper.h errors.h ostack.h iostack.h istack.h opdef.h opextern.h
+zcie.o: opcheck.h iutil.h gsstruct.h gxcspace.h gscspace.h gsccolor.h
+zcie.o: gscsel.h gxfrac.h gscolor2.h gsptype1.h gspcolor.h gsuid.h gxbitmap.h
+zcie.o: gsbitmap.h gscie.h gsrefct.h gxctable.h gxfixed.h estack.h iestack.h
+zcie.o: ialloc.h imemory.h ivmspace.h gsgc.h gsalloc.h idict.h idparam.h
+zcie.o: igstate.h gsstate.h gsdevice.h gsline.h gslparam.h gscolor.h gxtmap.h
+zcie.o: gsht.h gxstate.h istruct.h icie.h isave.h store.h
+
+zcolor1.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+zcolor1.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h errors.h
+zcolor1.o: ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h iutil.h
+zcolor1.o: estack.h iestack.h ialloc.h imemory.h ivmspace.h gsgc.h gsalloc.h
+zcolor1.o: igstate.h gsstate.h gsdevice.h gsline.h gslparam.h gscolor.h
+zcolor1.o: gxtmap.h gsht.h gscsel.h gxstate.h istruct.h gsstruct.h store.h
+zcolor1.o: gxfixed.h gxmatrix.h gsmatrix.h gzstate.h gscpm.h gsrefct.h
+zcolor1.o: gxdcolor.h gsdcolor.h gsccolor.h gxarith.h gxbitmap.h gsbitmap.h
+zcolor1.o: gxhttile.h gxcindex.h gsbitops.h gsropt.h gxistate.h gxcvalue.h
+zcolor1.o: gxline.h gxdevice.h gxdevcli.h gscompt.h gsiparam.h gsxfont.h
+zcolor1.o: gxtext.h gstext.h gsccode.h gsparam.h gsmalloc.h gxcmap.h gxfmap.h
+zcolor1.o: gxfrac.h gscolor1.h gxcspace.h gscspace.h icolor.h iimage.h
+
+zcolor2.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+zcolor2.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h errors.h
+zcolor2.o: ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h iutil.h
+zcolor2.o: gscolor.h gxtmap.h gsmatrix.h gsstruct.h gxcspace.h gscspace.h
+zcolor2.o: gsccolor.h gscsel.h gxfrac.h gxfixed.h gxcolor2.h gscolor2.h
+zcolor2.o: gsptype1.h gspcolor.h gsuid.h gxbitmap.h gsbitmap.h gsrefct.h
+zcolor2.o: gxdcolor.h gsdcolor.h gxarith.h gxhttile.h gxcindex.h gsbitops.h
+zcolor2.o: gsropt.h gxdevice.h gxdevcli.h gscompt.h gsiparam.h gsxfont.h
+zcolor2.o: gxcvalue.h gxtext.h gstext.h gsccode.h gsparam.h gsmalloc.h
+zcolor2.o: gxdevmem.h gxpcolor.h gxpcache.h estack.h iestack.h ialloc.h
+zcolor2.o: imemory.h ivmspace.h gsgc.h gsalloc.h istruct.h idict.h idparam.h
+zcolor2.o: igstate.h gsstate.h gsdevice.h gsline.h gslparam.h gsht.h
+zcolor2.o: gxstate.h store.h
+
+zcolor.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+zcolor.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h errors.h
+zcolor.o: ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h iutil.h
+zcolor.o: estack.h iestack.h ialloc.h imemory.h ivmspace.h gsgc.h gsalloc.h
+zcolor.o: igstate.h gsstate.h gsdevice.h gsline.h gslparam.h gscolor.h
+zcolor.o: gxtmap.h gsht.h gscsel.h gxstate.h istruct.h gsstruct.h store.h
+zcolor.o: gxfixed.h gxmatrix.h gsmatrix.h gzstate.h gscpm.h gsrefct.h
+zcolor.o: gxdcolor.h gsdcolor.h gsccolor.h gxarith.h gxbitmap.h gsbitmap.h
+zcolor.o: gxhttile.h gxcindex.h gsbitops.h gsropt.h gxistate.h gxcvalue.h
+zcolor.o: gxline.h gxdevice.h gxdevcli.h gscompt.h gsiparam.h gsxfont.h
+zcolor.o: gxtext.h gstext.h gsccode.h gsparam.h gsmalloc.h gxcmap.h gxfmap.h
+zcolor.o: gxfrac.h icolor.h
+
+zcontrol.o: string_.h std.h stdpre.h arch.h ghost.h gx.h stdio_.h gserror.h
+zcontrol.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h stream.h
+zcontrol.o: scommon.h gsstruct.h oper.h errors.h ostack.h iostack.h istack.h
+zcontrol.o: opdef.h opextern.h opcheck.h iutil.h estack.h iestack.h files.h
+zcontrol.o: ipacked.h store.h ialloc.h imemory.h ivmspace.h gsgc.h gsalloc.h
+
+zcrd.o: math_.h std.h stdpre.h arch.h ghost.h gx.h stdio_.h gserror.h gsio.h
+zcrd.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h errors.h
+zcrd.o: ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h iutil.h
+zcrd.o: gsstruct.h gscspace.h gscolor2.h gsptype1.h gspcolor.h gsccolor.h
+zcrd.o: gsuid.h gxbitmap.h gsbitmap.h gscrd.h gscie.h gsrefct.h gxctable.h
+zcrd.o: gxfixed.h gxfrac.h estack.h iestack.h ialloc.h imemory.h ivmspace.h
+zcrd.o: gsgc.h gsalloc.h idict.h idparam.h igstate.h gsstate.h gsdevice.h
+zcrd.o: gsline.h gslparam.h gscolor.h gxtmap.h gsht.h gscsel.h gxstate.h
+zcrd.o: istruct.h icie.h store.h
+
+zcsdevn.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+zcsdevn.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h errors.h
+zcsdevn.o: ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h iutil.h
+zcsdevn.o: gxcspace.h gscspace.h gsccolor.h gsstruct.h gscsel.h gxfrac.h
+zcsdevn.o: gscolor2.h gsptype1.h gspcolor.h gsuid.h gxbitmap.h gsbitmap.h
+zcsdevn.o: igstate.h gsstate.h gsdevice.h gsline.h gslparam.h gscolor.h
+zcsdevn.o: gxtmap.h gsht.h gxstate.h istruct.h ialloc.h imemory.h ivmspace.h
+zcsdevn.o: gsgc.h gsalloc.h iname.h inames.h
+
+zcsindex.o: memory_.h std.h stdpre.h arch.h ghost.h gx.h stdio_.h gserror.h
+zcsindex.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h
+zcsindex.o: errors.h ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h
+zcsindex.o: iutil.h gsstruct.h gscolor.h gxtmap.h gsmatrix.h gxcspace.h
+zcsindex.o: gscspace.h gsccolor.h gscsel.h gxfrac.h gxfixed.h gxcolor2.h
+zcsindex.o: gscolor2.h gsptype1.h gspcolor.h gsuid.h gxbitmap.h gsbitmap.h
+zcsindex.o: gsrefct.h estack.h iestack.h ialloc.h imemory.h ivmspace.h gsgc.h
+zcsindex.o: gsalloc.h icsmap.h igstate.h gsstate.h gsdevice.h gsline.h
+zcsindex.o: gslparam.h gsht.h gxstate.h istruct.h store.h
+
+zcspixel.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+zcspixel.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h errors.h
+zcspixel.o: ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h iutil.h
+zcspixel.o: igstate.h gsstate.h gsdevice.h gsline.h gslparam.h gscolor.h
+zcspixel.o: gxtmap.h gsht.h gscsel.h gxstate.h istruct.h gsstruct.h
+zcspixel.o: gscspace.h gsmatrix.h gscolor2.h gsptype1.h gspcolor.h gsccolor.h
+zcspixel.o: gsuid.h gxbitmap.h gsbitmap.h gscpixel.h
+
+zcssepr.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+zcssepr.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h errors.h
+zcssepr.o: ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h iutil.h
+zcssepr.o: gsstruct.h gscolor.h gxtmap.h gsmatrix.h gscsepr.h gscspace.h
+zcssepr.o: gxcspace.h gsccolor.h gscsel.h gxfrac.h gxfixed.h gxcolor2.h
+zcssepr.o: gscolor2.h gsptype1.h gspcolor.h gsuid.h gxbitmap.h gsbitmap.h
+zcssepr.o: gsrefct.h estack.h iestack.h ialloc.h imemory.h ivmspace.h gsgc.h
+zcssepr.o: gsalloc.h icsmap.h igstate.h gsstate.h gsdevice.h gsline.h
+zcssepr.o: gslparam.h gsht.h gxstate.h istruct.h store.h
+
+zdevcal.o: time_.h std.h stdpre.h arch.h ../config.h ghost.h gx.h stdio_.h
+zdevcal.o: gserror.h gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h
+zdevcal.o: gxiodev.h stat_.h istack.h iparam.h gsparam.h
+
+zdevice2.o: math_.h std.h stdpre.h arch.h memory_.h ghost.h gx.h stdio_.h
+zdevice2.o: gserror.h gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h
+zdevice2.o: oper.h errors.h ostack.h iostack.h istack.h opdef.h opextern.h
+zdevice2.o: opcheck.h iutil.h dstack.h idstack.h estack.h iestack.h idict.h
+zdevice2.o: idparam.h igstate.h gsstate.h gsdevice.h gsline.h gslparam.h
+zdevice2.o: gscolor.h gxtmap.h gsht.h gscsel.h gxstate.h istruct.h gsstruct.h
+zdevice2.o: iname.h inames.h store.h ialloc.h imemory.h ivmspace.h gsgc.h
+zdevice2.o: gsalloc.h gxdevice.h gxdevcli.h gscompt.h gsdcolor.h gsccolor.h
+zdevice2.o: gxarith.h gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h gsbitops.h
+zdevice2.o: gsmatrix.h gsiparam.h gsrefct.h gsropt.h gsxfont.h gxcvalue.h
+zdevice2.o: gxfixed.h gxtext.h gstext.h gsccode.h gsparam.h gsmalloc.h
+
+zdevice.o: string_.h std.h stdpre.h arch.h ghost.h gx.h stdio_.h gserror.h
+zdevice.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h
+zdevice.o: errors.h ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h
+zdevice.o: iutil.h ialloc.h imemory.h ivmspace.h gsgc.h gsalloc.h idict.h
+zdevice.o: igstate.h gsstate.h gsdevice.h gsline.h gslparam.h gscolor.h
+zdevice.o: gxtmap.h gsht.h gscsel.h gxstate.h istruct.h gsstruct.h iname.h
+zdevice.o: inames.h interp.h iparam.h gsparam.h gsmatrix.h gxdevice.h
+zdevice.o: gxdevcli.h gscompt.h gsdcolor.h gsccolor.h gxarith.h gxbitmap.h
+zdevice.o: gsbitmap.h gxhttile.h gxcindex.h gsbitops.h gsiparam.h gsrefct.h
+zdevice.o: gsropt.h gsxfont.h gxcvalue.h gxfixed.h gxtext.h gstext.h
+zdevice.o: gsccode.h gsmalloc.h gxgetbit.h gxbitfmt.h store.h
+
+zdict.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+zdict.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h errors.h
+zdict.o: ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h iutil.h
+zdict.o: idict.h dstack.h idstack.h ilevel.h iname.h inames.h ipacked.h
+zdict.o: ivmspace.h gsgc.h store.h ialloc.h imemory.h gsalloc.h
+
+zdps1.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+zdps1.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h errors.h
+zdps1.o: ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h iutil.h
+zdps1.o: gsmatrix.h gspath.h gspenum.h gspath2.h gsstate.h gsdevice.h
+zdps1.o: gsline.h gslparam.h gscolor.h gxtmap.h gsht.h gscsel.h ialloc.h
+zdps1.o: imemory.h ivmspace.h gsgc.h gsalloc.h igstate.h gxstate.h istruct.h
+zdps1.o: gsstruct.h store.h stream.h scommon.h ibnum.h
+
+zfbcp.o: memory_.h std.h stdpre.h arch.h ghost.h gx.h stdio_.h gserror.h
+zfbcp.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h
+zfbcp.o: errors.h ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h
+zfbcp.o: iutil.h gsstruct.h ialloc.h imemory.h ivmspace.h gsgc.h gsalloc.h
+zfbcp.o: stream.h scommon.h strimpl.h sfilter.h ifilter.h istream.h
+
+zfcmap.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+zfcmap.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h errors.h
+zfcmap.o: ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h iutil.h
+zfcmap.o: gsmatrix.h gsstruct.h gsutil.h gxfcmap.h gsfcmap.h gsccode.h
+zfcmap.o: gsuid.h gxfont.h gsfont.h gxftype.h ialloc.h imemory.h ivmspace.h
+zfcmap.o: gsgc.h gsalloc.h idict.h idparam.h ifont.h iname.h inames.h store.h
+
+zfdctd.o: ../config.h memory_.h std.h stdpre.h arch.h stdio_.h ghost.h gx.h
+zfdctd.o: gserror.h gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h
+zfdctd.o: oper.h errors.h ostack.h iostack.h istack.h opdef.h opextern.h
+zfdctd.o: opcheck.h iutil.h gsmalloc.h strimpl.h scommon.h gsstruct.h sdct.h
+zfdctd.o: sjpeg.h ialloc.h imemory.h ivmspace.h gsgc.h gsalloc.h ifilter.h
+zfdctd.o: istream.h iparam.h gsparam.h
+
+zfdcte.o: ../config.h memory_.h std.h stdpre.h arch.h stdio_.h ghost.h gx.h
+zfdcte.o: gserror.h gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h
+zfdcte.o: oper.h errors.h ostack.h iostack.h istack.h opdef.h opextern.h
+zfdcte.o: opcheck.h iutil.h gsmalloc.h ialloc.h imemory.h ivmspace.h gsgc.h
+zfdcte.o: gsalloc.h idict.h idparam.h strimpl.h scommon.h gsstruct.h sdct.h
+zfdcte.o: sjpeg.h ifilter.h istream.h iparam.h gsparam.h
+
+zfdecode.o: memory_.h std.h stdpre.h arch.h ghost.h gx.h stdio_.h gserror.h
+zfdecode.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h
+zfdecode.o: errors.h ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h
+zfdecode.o: iutil.h gsparam.h gsstruct.h ialloc.h imemory.h ivmspace.h gsgc.h
+zfdecode.o: gsalloc.h idict.h idparam.h ilevel.h iparam.h store.h stream.h
+zfdecode.o: scommon.h strimpl.h sfilter.h sa85x.h scfx.h shc.h gsbittab.h
+zfdecode.o: scf.h slzwx.h spdiffx.h spngpx.h ifilter.h istream.h
+
+zfileio.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+zfileio.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h gp.h gpgetenv.h
+zfileio.o: oper.h errors.h ostack.h iostack.h istack.h opdef.h opextern.h
+zfileio.o: opcheck.h iutil.h stream.h scommon.h gsstruct.h files.h store.h
+zfileio.o: ialloc.h imemory.h ivmspace.h gsgc.h gsalloc.h strimpl.h ifilter.h
+zfileio.o: istream.h gsmatrix.h gxdevice.h gxdevcli.h gscompt.h gsdcolor.h
+zfileio.o: gsccolor.h gxarith.h gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h
+zfileio.o: gsbitops.h gsiparam.h gsrefct.h gsropt.h gsxfont.h gxcvalue.h
+zfileio.o: gxfixed.h gxtext.h gstext.h gsccode.h gsparam.h gsmalloc.h
+zfileio.o: gxdevmem.h
+
+zfile.o: memory_.h std.h stdpre.h arch.h string_.h ghost.h gx.h stdio_.h
+zfile.o: gserror.h gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h
+zfile.o: gscdefs.h gconfigv.h gp.h gpgetenv.h gsstruct.h gxalloc.h gsalloc.h
+zfile.o: gxobj.h gxbitmap.h gsbitmap.h oper.h errors.h ostack.h iostack.h
+zfile.o: istack.h opdef.h opextern.h opcheck.h iutil.h estack.h iestack.h
+zfile.o: ialloc.h imemory.h ivmspace.h gsgc.h ilevel.h interp.h isave.h
+zfile.o: stream.h scommon.h strimpl.h sfilter.h gxiodev.h stat_.h files.h
+zfile.o: fname.h main.h imain.h gsexit.h iminst.h store.h
+
+zfilter2.o: memory_.h std.h stdpre.h arch.h ghost.h gx.h stdio_.h gserror.h
+zfilter2.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h
+zfilter2.o: errors.h ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h
+zfilter2.o: iutil.h gsstruct.h ialloc.h imemory.h ivmspace.h gsgc.h gsalloc.h
+zfilter2.o: idict.h idparam.h store.h strimpl.h scommon.h sfilter.h scfx.h
+zfilter2.o: shc.h gsbittab.h slzwx.h spdiffx.h spngpx.h ifilter.h istream.h
+
+zfilterx.o: memory_.h std.h stdpre.h arch.h ghost.h gx.h stdio_.h gserror.h
+zfilterx.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h
+zfilterx.o: errors.h ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h
+zfilterx.o: iutil.h gsstruct.h ialloc.h imemory.h ivmspace.h gsgc.h gsalloc.h
+zfilterx.o: idict.h idparam.h store.h strimpl.h scommon.h sfilter.h sbwbs.h
+zfilterx.o: sbhc.h shc.h gsbittab.h sbtx.h shcgen.h smtf.h spcxx.h ifilter.h
+zfilterx.o: istream.h
+
+zfilter.o: memory_.h std.h stdpre.h arch.h ghost.h gx.h stdio_.h gserror.h
+zfilter.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h
+zfilter.o: errors.h ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h
+zfilter.o: iutil.h gsstruct.h ialloc.h imemory.h ivmspace.h gsgc.h gsalloc.h
+zfilter.o: idict.h idparam.h ilevel.h stream.h scommon.h strimpl.h sfilter.h
+zfilter.o: srlx.h sstring.h ifilter.h istream.h files.h
+
+zfname.o: memory_.h std.h stdpre.h arch.h ghost.h gx.h stdio_.h gserror.h
+zfname.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h
+zfname.o: errors.h ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h
+zfname.o: iutil.h ialloc.h imemory.h ivmspace.h gsgc.h gsalloc.h stream.h
+zfname.o: scommon.h gsstruct.h gxiodev.h stat_.h fname.h
+
+zfont0.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+zfont0.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h errors.h
+zfont0.o: ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h iutil.h
+zfont0.o: gsstruct.h gxfixed.h gxmatrix.h gsmatrix.h gzstate.h gscpm.h
+zfont0.o: gsrefct.h gxdcolor.h gscsel.h gsdcolor.h gsccolor.h gxarith.h
+zfont0.o: gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h gsbitops.h gsropt.h
+zfont0.o: gxistate.h gxcvalue.h gxline.h gslparam.h gxtmap.h gsstate.h
+zfont0.o: gsdevice.h gsline.h gscolor.h gsht.h gxstate.h gxdevice.h
+zfont0.o: gxdevcli.h gscompt.h gsiparam.h gsxfont.h gxtext.h gstext.h
+zfont0.o: gsccode.h gsparam.h gsmalloc.h gschar.h gxfcmap.h gsfcmap.h gsuid.h
+zfont0.o: gxfont.h gsfont.h gxftype.h gxfont0.h bfont.h ifont.h ialloc.h
+zfont0.o: imemory.h ivmspace.h gsgc.h gsalloc.h idict.h idparam.h igstate.h
+zfont0.o: istruct.h iname.h inames.h store.h
+
+zfont1.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+zfont1.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h errors.h
+zfont1.o: ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h iutil.h
+zfont1.o: gxfixed.h gsmatrix.h gxdevice.h gxdevcli.h gscompt.h gsdcolor.h
+zfont1.o: gsccolor.h gsstruct.h gxarith.h gxbitmap.h gsbitmap.h gxhttile.h
+zfont1.o: gxcindex.h gsbitops.h gsiparam.h gsrefct.h gsropt.h gsxfont.h
+zfont1.o: gxcvalue.h gxtext.h gstext.h gsccode.h gsparam.h gsmalloc.h
+zfont1.o: gschar.h gscpm.h gxfont.h gsfont.h gsuid.h gxftype.h gxfont1.h
+zfont1.o: bfont.h ifont.h ialloc.h imemory.h ivmspace.h gsgc.h gsalloc.h
+zfont1.o: idict.h idparam.h store.h
+
+zfont2.o: memory_.h std.h stdpre.h arch.h string_.h ghost.h gx.h stdio_.h
+zfont2.o: gserror.h gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h
+zfont2.o: oper.h errors.h ostack.h iostack.h istack.h opdef.h opextern.h
+zfont2.o: opcheck.h iutil.h gxfixed.h gsmatrix.h gxdevice.h gxdevcli.h
+zfont2.o: gscompt.h gsdcolor.h gsccolor.h gsstruct.h gxarith.h gxbitmap.h
+zfont2.o: gsbitmap.h gxhttile.h gxcindex.h gsbitops.h gsiparam.h gsrefct.h
+zfont2.o: gsropt.h gsxfont.h gxcvalue.h gxtext.h gstext.h gsccode.h gsparam.h
+zfont2.o: gsmalloc.h gschar.h gscpm.h gxfont.h gsfont.h gsuid.h gxftype.h
+zfont2.o: bfont.h ifont.h ialloc.h imemory.h ivmspace.h gsgc.h gsalloc.h
+zfont2.o: idict.h idparam.h ilevel.h iname.h inames.h interp.h ipacked.h
+zfont2.o: istruct.h store.h
+
+zfont32.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+zfont32.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h errors.h
+zfont32.o: ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h iutil.h
+zfont32.o: gsccode.h gsmatrix.h gsutil.h gxfixed.h gxchar.h gschar.h gscpm.h
+zfont32.o: gxtext.h gstext.h gsrefct.h gxfont.h gsfont.h gsuid.h gsstruct.h
+zfont32.o: gxftype.h bfont.h ifont.h store.h ialloc.h imemory.h ivmspace.h
+zfont32.o: gsgc.h gsalloc.h
+
+zfont42.o: memory_.h std.h stdpre.h arch.h ghost.h gx.h stdio_.h gserror.h
+zfont42.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h
+zfont42.o: errors.h ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h
+zfont42.o: iutil.h gsccode.h gsmatrix.h gxfont.h gsfont.h gsuid.h gsstruct.h
+zfont42.o: gxftype.h gxfont42.h bfont.h ifont.h idict.h idparam.h store.h
+zfont42.o: ialloc.h imemory.h ivmspace.h gsgc.h gsalloc.h
+
+zfont.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+zfont.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h errors.h
+zfont.o: ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h iutil.h
+zfont.o: gsstruct.h gzstate.h gscpm.h gsrefct.h gxdcolor.h gscsel.h
+zfont.o: gsdcolor.h gsccolor.h gxarith.h gxbitmap.h gsbitmap.h gxhttile.h
+zfont.o: gxcindex.h gsbitops.h gsropt.h gxistate.h gxcvalue.h gxfixed.h
+zfont.o: gxline.h gslparam.h gxmatrix.h gsmatrix.h gxtmap.h gsstate.h
+zfont.o: gsdevice.h gsline.h gscolor.h gsht.h gxstate.h gxdevice.h gxdevcli.h
+zfont.o: gscompt.h gsiparam.h gsxfont.h gxtext.h gstext.h gsccode.h gsparam.h
+zfont.o: gsmalloc.h gschar.h gxfont.h gsfont.h gsuid.h gxftype.h gxfcache.h
+zfont.o: gxbcache.h bfont.h ifont.h ialloc.h imemory.h ivmspace.h gsgc.h
+zfont.o: gsalloc.h idict.h igstate.h istruct.h iname.h inames.h isave.h
+zfont.o: store.h
+
+zfproc.o: memory_.h std.h stdpre.h arch.h ghost.h gx.h stdio_.h gserror.h
+zfproc.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h
+zfproc.o: errors.h ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h
+zfproc.o: iutil.h estack.h iestack.h gsstruct.h ialloc.h imemory.h ivmspace.h
+zfproc.o: gsgc.h gsalloc.h istruct.h stream.h scommon.h strimpl.h ifilter.h
+zfproc.o: istream.h files.h store.h
+
+zfreuse.o: memory_.h std.h stdpre.h arch.h ghost.h gx.h stdio_.h gserror.h
+zfreuse.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h
+zfreuse.o: errors.h ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h
+zfreuse.o: iutil.h stream.h scommon.h gsstruct.h strimpl.h sfilter.h files.h
+zfreuse.o: idict.h idparam.h iname.h inames.h store.h ialloc.h imemory.h
+zfreuse.o: ivmspace.h gsgc.h gsalloc.h
+
+zfunc0.o: memory_.h std.h stdpre.h arch.h ghost.h gx.h stdio_.h gserror.h
+zfunc0.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h
+zfunc0.o: errors.h ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h
+zfunc0.o: iutil.h gsdsrc.h gsstruct.h gsfunc.h gsfunc0.h stream.h scommon.h
+zfunc0.o: files.h ialloc.h imemory.h ivmspace.h gsgc.h gsalloc.h idict.h
+zfunc0.o: idparam.h ifunc.h
+
+zfunc3.o: memory_.h std.h stdpre.h arch.h ghost.h gx.h stdio_.h gserror.h
+zfunc3.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h
+zfunc3.o: errors.h ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h
+zfunc3.o: iutil.h gsfunc3.h gsfunc.h gsdsrc.h gsstruct.h stream.h scommon.h
+zfunc3.o: files.h ialloc.h imemory.h ivmspace.h gsgc.h gsalloc.h idict.h
+zfunc3.o: idparam.h ifunc.h store.h
+
+zfunc.o: memory_.h std.h stdpre.h arch.h ghost.h gx.h stdio_.h gserror.h
+zfunc.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h
+zfunc.o: errors.h ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h
+zfunc.o: iutil.h gsfunc.h gsstruct.h ialloc.h imemory.h ivmspace.h gsgc.h
+zfunc.o: gsalloc.h idict.h idparam.h ifunc.h store.h
+
+zfzlib.o: ../config.h ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h
+zfzlib.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h
+zfzlib.o: errors.h ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h
+zfzlib.o: iutil.h idict.h strimpl.h scommon.h gsstruct.h spdiffx.h spngpx.h
+zfzlib.o: szlibx.h ifilter.h istream.h ivmspace.h gsgc.h
+
+zgeneric.o: memory_.h std.h stdpre.h arch.h ghost.h gx.h stdio_.h gserror.h
+zgeneric.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h
+zgeneric.o: errors.h ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h
+zgeneric.o: iutil.h estack.h iestack.h idict.h iname.h inames.h ipacked.h
+zgeneric.o: ivmspace.h gsgc.h store.h ialloc.h imemory.h gsalloc.h
+
+zgstate.o: math_.h std.h stdpre.h arch.h ghost.h gx.h stdio_.h gserror.h
+zgstate.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h
+zgstate.o: errors.h ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h
+zgstate.o: iutil.h ialloc.h imemory.h ivmspace.h gsgc.h gsalloc.h idict.h
+zgstate.o: istruct.h gsstruct.h igstate.h gsstate.h gsdevice.h gsline.h
+zgstate.o: gslparam.h gscolor.h gxtmap.h gsht.h gscsel.h gxstate.h gsmatrix.h
+zgstate.o: store.h
+
+zhsb.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+zhsb.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h errors.h
+zhsb.o: ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h iutil.h
+zhsb.o: igstate.h gsstate.h gsdevice.h gsline.h gslparam.h gscolor.h gxtmap.h
+zhsb.o: gsht.h gscsel.h gxstate.h istruct.h gsstruct.h store.h ialloc.h
+zhsb.o: imemory.h ivmspace.h gsgc.h gsalloc.h gshsb.h
+
+zht1.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+zht1.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h memory_.h oper.h
+zht1.o: errors.h ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h
+zht1.o: iutil.h estack.h iestack.h gsstruct.h ialloc.h imemory.h ivmspace.h
+zht1.o: gsgc.h gsalloc.h igstate.h gsstate.h gsdevice.h gsline.h gslparam.h
+zht1.o: gscolor.h gxtmap.h gsht.h gscsel.h gxstate.h istruct.h gsmatrix.h
+zht1.o: gxdevice.h gxdevcli.h gscompt.h gsdcolor.h gsccolor.h gxarith.h
+zht1.o: gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h gsbitops.h gsiparam.h
+zht1.o: gsrefct.h gsropt.h gsxfont.h gxcvalue.h gxfixed.h gxtext.h gstext.h
+zht1.o: gsccode.h gsparam.h gsmalloc.h gzht.h gxht.h gscsepnm.h gsht1.h
+zht1.o: gxhttype.h gxfmap.h gxfrac.h gxdht.h iht.h store.h
+
+zht2.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+zht2.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h errors.h
+zht2.o: ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h iutil.h
+zht2.o: gsstruct.h gxdevice.h gxdevcli.h gscompt.h gsdcolor.h gsccolor.h
+zht2.o: gxarith.h gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h gsbitops.h
+zht2.o: gsmatrix.h gsiparam.h gsrefct.h gsropt.h gsxfont.h gxcvalue.h
+zht2.o: gxfixed.h gxtext.h gstext.h gsccode.h gsparam.h gsmalloc.h gzht.h
+zht2.o: gscsel.h gxht.h gscsepnm.h gsht1.h gsht.h gxhttype.h gxtmap.h
+zht2.o: gxfmap.h gxfrac.h gxdht.h estack.h iestack.h ialloc.h imemory.h
+zht2.o: ivmspace.h gsgc.h gsalloc.h idict.h idparam.h igstate.h gsstate.h
+zht2.o: gsdevice.h gsline.h gslparam.h gscolor.h gxstate.h istruct.h icolor.h
+zht2.o: iht.h store.h
+
+zht.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h gstypes.h
+zht.o: gsmemory.h gsmemraw.h gdebug.h iref.h memory_.h oper.h errors.h
+zht.o: ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h iutil.h
+zht.o: estack.h iestack.h gsstruct.h ialloc.h imemory.h ivmspace.h gsgc.h
+zht.o: gsalloc.h igstate.h gsstate.h gsdevice.h gsline.h gslparam.h gscolor.h
+zht.o: gxtmap.h gsht.h gscsel.h gxstate.h istruct.h gsmatrix.h gxdevice.h
+zht.o: gxdevcli.h gscompt.h gsdcolor.h gsccolor.h gxarith.h gxbitmap.h
+zht.o: gsbitmap.h gxhttile.h gxcindex.h gsbitops.h gsiparam.h gsrefct.h
+zht.o: gsropt.h gsxfont.h gxcvalue.h gxfixed.h gxtext.h gstext.h gsccode.h
+zht.o: gsparam.h gsmalloc.h gzht.h gxht.h gscsepnm.h gsht1.h gxhttype.h
+zht.o: gxfmap.h gxfrac.h gxdht.h iht.h store.h
+
+zimage2.o: math_.h std.h stdpre.h arch.h memory_.h ghost.h gx.h stdio_.h
+zimage2.o: gserror.h gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h
+zimage2.o: oper.h errors.h ostack.h iostack.h istack.h opdef.h opextern.h
+zimage2.o: opcheck.h iutil.h gscolor.h gxtmap.h gscspace.h gscolor2.h
+zimage2.o: gsptype1.h gspcolor.h gsccolor.h gsstruct.h gsuid.h gxbitmap.h
+zimage2.o: gsbitmap.h gsmatrix.h gsimage.h gsiparam.h gxfixed.h idict.h
+zimage2.o: idparam.h iimage.h iimage2.h ilevel.h igstate.h gsstate.h
+zimage2.o: gsdevice.h gsline.h gslparam.h gsht.h gscsel.h gxstate.h istruct.h
+
+zimage3.o: memory_.h std.h stdpre.h arch.h ghost.h gx.h stdio_.h gserror.h
+zimage3.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h
+zimage3.o: errors.h ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h
+zimage3.o: iutil.h gscspace.h gscolor2.h gsptype1.h gspcolor.h gsccolor.h
+zimage3.o: gsstruct.h gsuid.h gxbitmap.h gsbitmap.h gsiparm3.h gsiparam.h
+zimage3.o: gsmatrix.h gsiparm4.h gxiparam.h gxdevcli.h gscompt.h gsdcolor.h
+zimage3.o: gxarith.h gxhttile.h gxcindex.h gsbitops.h gsrefct.h gsropt.h
+zimage3.o: gsxfont.h gxcvalue.h gxfixed.h gxtext.h gstext.h gsccode.h idict.h
+zimage3.o: idparam.h igstate.h gsstate.h gsdevice.h gsline.h gslparam.h
+zimage3.o: gscolor.h gxtmap.h gsht.h gscsel.h gxstate.h istruct.h iimage.h
+zimage3.o: iimage2.h
+
+zimage.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+zimage.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h errors.h
+zimage.o: ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h iutil.h
+zimage.o: estack.h iestack.h gsstruct.h ialloc.h imemory.h ivmspace.h gsgc.h
+zimage.o: gsalloc.h igstate.h gsstate.h gsdevice.h gsline.h gslparam.h
+zimage.o: gscolor.h gxtmap.h gsht.h gscsel.h gxstate.h istruct.h ilevel.h
+zimage.o: store.h gscspace.h gsmatrix.h gsimage.h gsiparam.h gxiparam.h
+zimage.o: gxdevcli.h gscompt.h gsdcolor.h gsccolor.h gxarith.h gxbitmap.h
+zimage.o: gsbitmap.h gxhttile.h gxcindex.h gsbitops.h gsrefct.h gsropt.h
+zimage.o: gsxfont.h gxcvalue.h gxfixed.h gxtext.h gstext.h gsccode.h stream.h
+zimage.o: scommon.h ifilter.h istream.h iimage.h
+
+ziodev2.o: string_.h std.h stdpre.h arch.h ghost.h gx.h stdio_.h gserror.h
+ziodev2.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h gp.h
+ziodev2.o: gpgetenv.h oper.h errors.h ostack.h iostack.h istack.h opdef.h
+ziodev2.o: opextern.h opcheck.h iutil.h stream.h scommon.h gsstruct.h
+ziodev2.o: gxiodev.h stat_.h dstack.h idstack.h files.h iparam.h gsparam.h
+ziodev2.o: iutil2.h store.h ialloc.h imemory.h ivmspace.h gsgc.h gsalloc.h
+
+ziodev.o: memory_.h std.h stdpre.h arch.h stdio_.h string_.h ghost.h gx.h
+ziodev.o: gserror.h gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h
+ziodev.o: gp.h gpgetenv.h gpcheck.h gsstruct.h oper.h errors.h ostack.h
+ziodev.o: iostack.h istack.h opdef.h opextern.h opcheck.h iutil.h stream.h
+ziodev.o: scommon.h ialloc.h imemory.h ivmspace.h gsgc.h gsalloc.h iscan.h
+ziodev.o: sa85x.h sstring.h gxiodev.h stat_.h files.h scanchar.h store.h
+
+zmath.o: math_.h std.h stdpre.h arch.h ghost.h gx.h stdio_.h gserror.h gsio.h
+zmath.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h gxfarith.h
+zmath.o: gconfigv.h gxarith.h oper.h errors.h ostack.h iostack.h istack.h
+zmath.o: opdef.h opextern.h opcheck.h iutil.h store.h ialloc.h imemory.h
+zmath.o: ivmspace.h gsgc.h gsalloc.h
+
+zmatrix.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+zmatrix.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h errors.h
+zmatrix.o: ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h iutil.h
+zmatrix.o: igstate.h gsstate.h gsdevice.h gsline.h gslparam.h gscolor.h
+zmatrix.o: gxtmap.h gsht.h gscsel.h gxstate.h istruct.h gsstruct.h gsmatrix.h
+zmatrix.o: gscoord.h store.h ialloc.h imemory.h ivmspace.h gsgc.h gsalloc.h
+
+zmedia2.o: math_.h std.h stdpre.h arch.h memory_.h ghost.h gx.h stdio_.h
+zmedia2.o: gserror.h gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h
+zmedia2.o: gsmatrix.h oper.h errors.h ostack.h iostack.h istack.h opdef.h
+zmedia2.o: opextern.h opcheck.h iutil.h idict.h idparam.h iname.h inames.h
+zmedia2.o: store.h ialloc.h imemory.h ivmspace.h gsgc.h gsalloc.h
+
+zmisc1.o: memory_.h std.h stdpre.h arch.h ghost.h gx.h stdio_.h gserror.h
+zmisc1.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h
+zmisc1.o: errors.h ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h
+zmisc1.o: iutil.h gscrypt1.h stream.h scommon.h gsstruct.h strimpl.h
+zmisc1.o: sfilter.h idict.h idparam.h ifilter.h istream.h ivmspace.h gsgc.h
+
+zmisc2.o: memory_.h std.h stdpre.h arch.h string_.h ghost.h gx.h stdio_.h
+zmisc2.o: gserror.h gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h
+zmisc2.o: oper.h errors.h ostack.h iostack.h istack.h opdef.h opextern.h
+zmisc2.o: opcheck.h iutil.h estack.h iestack.h idict.h idparam.h iparam.h
+zmisc2.o: gsparam.h dstack.h idstack.h ilevel.h iname.h inames.h iutil2.h
+zmisc2.o: ivmspace.h gsgc.h store.h ialloc.h imemory.h gsalloc.h
+
+zmisc3.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+zmisc3.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h gsclipsr.h oper.h
+zmisc3.o: errors.h ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h
+zmisc3.o: iutil.h igstate.h gsstate.h gsdevice.h gsline.h gslparam.h
+zmisc3.o: gscolor.h gxtmap.h gsht.h gscsel.h gxstate.h istruct.h gsstruct.h
+zmisc3.o: store.h ialloc.h imemory.h ivmspace.h gsgc.h gsalloc.h
+
+zmisc.o: errno_.h std.h stdpre.h arch.h memory_.h string_.h ghost.h gx.h
+zmisc.o: stdio_.h gserror.h gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h
+zmisc.o: iref.h gscdefs.h gconfigv.h gp.h gpgetenv.h oper.h errors.h ostack.h
+zmisc.o: iostack.h istack.h opdef.h opextern.h opcheck.h iutil.h ialloc.h
+zmisc.o: imemory.h ivmspace.h gsgc.h gsalloc.h idict.h dstack.h idstack.h
+zmisc.o: iname.h inames.h ipacked.h store.h
+
+zpacked.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+zpacked.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h ialloc.h imemory.h
+zpacked.o: ivmspace.h gsgc.h gsalloc.h idict.h iname.h inames.h istack.h
+zpacked.o: ipacked.h iparray.h oper.h errors.h ostack.h iostack.h opdef.h
+zpacked.o: opextern.h opcheck.h iutil.h store.h
+
+zpaint.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+zpaint.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h errors.h
+zpaint.o: ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h iutil.h
+zpaint.o: gspaint.h igstate.h gsstate.h gsdevice.h gsline.h gslparam.h
+zpaint.o: gscolor.h gxtmap.h gsht.h gscsel.h gxstate.h istruct.h gsstruct.h
+
+zpath1.o: memory_.h std.h stdpre.h arch.h ghost.h gx.h stdio_.h gserror.h
+zpath1.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h
+zpath1.o: errors.h ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h
+zpath1.o: iutil.h estack.h iestack.h ialloc.h imemory.h ivmspace.h gsgc.h
+zpath1.o: gsalloc.h igstate.h gsstate.h gsdevice.h gsline.h gslparam.h
+zpath1.o: gscolor.h gxtmap.h gsht.h gscsel.h gxstate.h istruct.h gsstruct.h
+zpath1.o: gspath.h gspenum.h store.h
+
+zpath.o: math_.h std.h stdpre.h arch.h ghost.h gx.h stdio_.h gserror.h gsio.h
+zpath.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h errors.h
+zpath.o: ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h iutil.h
+zpath.o: igstate.h gsstate.h gsdevice.h gsline.h gslparam.h gscolor.h
+zpath.o: gxtmap.h gsht.h gscsel.h gxstate.h istruct.h gsstruct.h gsmatrix.h
+zpath.o: gspath.h gspenum.h store.h ialloc.h imemory.h ivmspace.h gsgc.h
+zpath.o: gsalloc.h
+
+zpcolor.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+zpcolor.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h errors.h
+zpcolor.o: ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h iutil.h
+zpcolor.o: gscolor.h gxtmap.h gsmatrix.h gsstruct.h gxcspace.h gscspace.h
+zpcolor.o: gsccolor.h gscsel.h gxfrac.h gxfixed.h gxcolor2.h gscolor2.h
+zpcolor.o: gsptype1.h gspcolor.h gsuid.h gxbitmap.h gsbitmap.h gsrefct.h
+zpcolor.o: gxdcolor.h gsdcolor.h gxarith.h gxhttile.h gxcindex.h gsbitops.h
+zpcolor.o: gsropt.h gxdevice.h gxdevcli.h gscompt.h gsiparam.h gsxfont.h
+zpcolor.o: gxcvalue.h gxtext.h gstext.h gsccode.h gsparam.h gsmalloc.h
+zpcolor.o: gxdevmem.h gxpcolor.h gxpcache.h estack.h iestack.h ialloc.h
+zpcolor.o: imemory.h ivmspace.h gsgc.h gsalloc.h istruct.h idict.h idparam.h
+zpcolor.o: igstate.h gsstate.h gsdevice.h gsline.h gslparam.h gsht.h
+zpcolor.o: gxstate.h store.h
+
+zrelbit.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+zrelbit.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h errors.h
+zrelbit.o: ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h iutil.h
+zrelbit.o: gsutil.h idict.h store.h ialloc.h imemory.h ivmspace.h gsgc.h
+zrelbit.o: gsalloc.h
+
+zshade.o: memory_.h std.h stdpre.h arch.h ghost.h gx.h stdio_.h gserror.h
+zshade.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h
+zshade.o: errors.h ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h
+zshade.o: iutil.h gscolor3.h gscspace.h gscolor2.h gsptype1.h gspcolor.h
+zshade.o: gsccolor.h gsstruct.h gsuid.h gxbitmap.h gsbitmap.h gsfunc3.h
+zshade.o: gsfunc.h gsdsrc.h gsshade.h gsmatrix.h stream.h scommon.h files.h
+zshade.o: ialloc.h imemory.h ivmspace.h gsgc.h gsalloc.h idict.h idparam.h
+zshade.o: ifunc.h igstate.h gsstate.h gsdevice.h gsline.h gslparam.h
+zshade.o: gscolor.h gxtmap.h gsht.h gscsel.h gxstate.h istruct.h store.h
+
+zstack.o: memory_.h std.h stdpre.h arch.h ghost.h gx.h stdio_.h gserror.h
+zstack.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h ialloc.h
+zstack.o: imemory.h ivmspace.h gsgc.h gsalloc.h istack.h oper.h errors.h
+zstack.o: ostack.h iostack.h opdef.h opextern.h opcheck.h iutil.h store.h
+
+zstring.o: memory_.h std.h stdpre.h arch.h ghost.h gx.h stdio_.h gserror.h
+zstring.o: gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h gsutil.h
+zstring.o: ialloc.h imemory.h ivmspace.h gsgc.h gsalloc.h iname.h inames.h
+zstring.o: oper.h errors.h ostack.h iostack.h istack.h opdef.h opextern.h
+zstring.o: opcheck.h iutil.h store.h
+
+zsysvm.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+zsysvm.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h errors.h
+zsysvm.o: ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h iutil.h
+zsysvm.o: ialloc.h imemory.h ivmspace.h gsgc.h gsalloc.h store.h
+
+ztoken.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+ztoken.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h errors.h
+ztoken.o: ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h iutil.h
+ztoken.o: estack.h iestack.h gsstruct.h stream.h scommon.h files.h store.h
+ztoken.o: ialloc.h imemory.h ivmspace.h gsgc.h gsalloc.h strimpl.h sfilter.h
+ztoken.o: iscan.h sa85x.h sstring.h
+
+ztrap.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+ztrap.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h errors.h
+ztrap.o: ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h iutil.h
+ztrap.o: ialloc.h imemory.h ivmspace.h gsgc.h gsalloc.h iparam.h gsparam.h
+ztrap.o: gstrap.h
+
+ztype.o: math_.h std.h stdpre.h arch.h memory_.h string_.h gsexit.h ghost.h
+ztype.o: gx.h stdio_.h gserror.h gsio.h gstypes.h gsmemory.h gsmemraw.h
+ztype.o: gdebug.h iref.h oper.h errors.h ostack.h iostack.h istack.h opdef.h
+ztype.o: opextern.h opcheck.h iutil.h imemory.h ivmspace.h gsgc.h gsalloc.h
+ztype.o: idict.h iname.h inames.h stream.h scommon.h gsstruct.h strimpl.h
+ztype.o: sfilter.h iscan.h sa85x.h sstring.h dstack.h idstack.h store.h
+ztype.o: ialloc.h
+
+zupath.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+zupath.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h errors.h
+zupath.o: ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h iutil.h
+zupath.o: idict.h dstack.h idstack.h igstate.h gsstate.h gsdevice.h gsline.h
+zupath.o: gslparam.h gscolor.h gxtmap.h gsht.h gscsel.h gxstate.h istruct.h
+zupath.o: gsstruct.h iname.h inames.h store.h ialloc.h imemory.h ivmspace.h
+zupath.o: gsgc.h gsalloc.h stream.h scommon.h ibnum.h gsmatrix.h gscoord.h
+zupath.o: gspaint.h gxfixed.h gxdevice.h gxdevcli.h gscompt.h gsdcolor.h
+zupath.o: gsccolor.h gxarith.h gxbitmap.h gsbitmap.h gxhttile.h gxcindex.h
+zupath.o: gsbitops.h gsiparam.h gsrefct.h gsropt.h gsxfont.h gxcvalue.h
+zupath.o: gxtext.h gstext.h gsccode.h gsparam.h gsmalloc.h gspath.h gspenum.h
+zupath.o: gzpath.h gxpath.h gscpm.h gsrect.h gzstate.h gxdcolor.h gxistate.h
+zupath.o: gxline.h gxmatrix.h
+
+zusparam.o: memory_.h std.h stdpre.h arch.h string_.h ghost.h gx.h stdio_.h
+zusparam.o: gserror.h gsio.h gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h
+zusparam.o: oper.h errors.h ostack.h iostack.h istack.h opdef.h opextern.h
+zusparam.o: opcheck.h iutil.h gscdefs.h gconfigv.h gsstruct.h gsfont.h gxht.h
+zusparam.o: gscsepnm.h gsht1.h gsht.h gsrefct.h gxhttype.h gxtmap.h gsutil.h
+zusparam.o: estack.h iestack.h ialloc.h imemory.h ivmspace.h gsgc.h gsalloc.h
+zusparam.o: icontext.h icstate.h idict.h idparam.h iparam.h gsparam.h
+zusparam.o: dstack.h idstack.h iname.h inames.h iutil2.h store.h
+
+zvmem2.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+zvmem2.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h oper.h errors.h
+zvmem2.o: ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h iutil.h
+zvmem2.o: estack.h iestack.h ialloc.h imemory.h ivmspace.h gsgc.h gsalloc.h
+zvmem2.o: store.h
+
+zvmem.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+zvmem.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h gsstruct.h oper.h
+zvmem.o: errors.h ostack.h iostack.h istack.h opdef.h opextern.h opcheck.h
+zvmem.o: iutil.h estack.h iestack.h ialloc.h imemory.h ivmspace.h gsgc.h
+zvmem.o: gsalloc.h idict.h igstate.h gsstate.h gsdevice.h gsline.h gslparam.h
+zvmem.o: gscolor.h gxtmap.h gsht.h gscsel.h gxstate.h istruct.h isave.h
+zvmem.o: dstack.h idstack.h stream.h scommon.h files.h store.h gsmalloc.h
+zvmem.o: gsmatrix.h
+
+genarch.o: stdpre.h
+
+pstoraster.o: ../cups/cups.h ../cups/ipp.h ../cups/http.h ../cups/string.h
+pstoraster.o: ../config.h ../cups/md5.h ../cups/ppd.h ../cups/string.h
+pstoraster.o: ghost.h gx.h stdio_.h std.h stdpre.h arch.h gserror.h gsio.h
+pstoraster.o: gstypes.h gsmemory.h gsmemraw.h gdebug.h iref.h imain.h
+pstoraster.o: gsexit.h iminst.h istack.h interp.h ostack.h iostack.h
+pstoraster.o: opextern.h gscdefs.h gconfigv.h store.h ialloc.h imemory.h
+pstoraster.o: ivmspace.h gsgc.h gsalloc.h
diff --git a/pstoraster/Fontmap b/pstoraster/Fontmap
new file mode 100644
index 000000000..42797fe18
--- /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 000000000..e04f17c25
--- /dev/null
+++ b/pstoraster/Makefile
@@ -0,0 +1,454 @@
+#
+# "$Id$"
+#
+# GNU Ghostscript makefile for the Common UNIX Printing System (CUPS).
+#
+# Copyright 1993-2002 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 \
+ 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_lev2.ps gs_ll3.ps \
+ gs_mex_e.ps gs_mro_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
+
+
+#
+# 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)
+ $(INSTALL_DIR) $(SERVERBIN)/filter
+ $(INSTALL_BIN) pstoraster $(SERVERBIN)/filter
+ $(INSTALL_DIR) $(DATADIR)/pstoraster
+ for file in $(DFILES); do \
+ $(INSTALL_DATA) $$file $(DATADIR)/pstoraster; \
+ done
+
+
+#
+# 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) $@
+
+
+#
+# pstoraster - PostScript RIP filter.
+#
+
+pstoraster: pstoraster.o libgs.a ../Makedefs ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o pstoraster pstoraster.o libgs.a \
+ $(LINKCUPSIMAGE) $(IMGLIBS) $(DSOLIBS) $(LIBS) -lm
+
+
+#
+# purify - target to test Ghostscript to see how leaky it is...
+#
+
+purify: pstoraster.o libgs.a ../Makedefs ../cups/$(LIBCUPS)
+ echo Linking $@...
+ purify $(CC) $(LDFLAGS) -o pstoraster.pure pstoraster.o libgs.a \
+ $(LINKCUPSIMAGE) $(IMGLIBS) $(DSOLIBS) $(LIBS) -lm
+
+
+#
+# Generate dependencies for Ghostscript source files...
+#
+
+depend:
+ rm -f Dependencies
+ touch Dependencies
+ for file in $(OBJS:.o=.c); do \
+ echo $$file; \
+ makedepend -a -fDependencies -I.. -Y $$file >/dev/null 2>&1; \
+ done
+
+
+#
+# Dependencies...
+#
+
+$(OBJS): ../Makedefs
+
+include Dependencies
+
+
+#
+# End of "$Id$".
+#
diff --git a/pstoraster/bfont.h b/pstoraster/bfont.h
new file mode 100644
index 000000000..7adae17de
--- /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 000000000..46dab4a60
--- /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 000000000..ac798ef9c
--- /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 000000000..c120d647f
--- /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 <ctype.h>
+
+#endif /* ctype__INCLUDED */
diff --git a/pstoraster/dirent_.h b/pstoraster/dirent_.h
new file mode 100644
index 000000000..2e33dc0d2
--- /dev/null
+++ b/pstoraster/dirent_.h
@@ -0,0 +1,60 @@
+/*
+ Copyright 1993-2002 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 <config.h>
+
+/*
+ * 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 <dirent.h>
+typedef struct dirent dir_entry;
+
+#else /* sys/ndir or ndir or sys/dir, i.e., no dirent */
+# ifdef HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# ifdef HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# ifdef HAVE_NDIR_H
+# include <ndir.h>
+# 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 000000000..a9480a9e9
--- /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 <D,M,F,E> 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 <P,E> 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 = <ptr to invalid value, 0>
+ begin(D):
+ *++dsp = <D, {0...}, D->F, ++Epoch>
+ set D->F
+ value = lookup(K):
+ if K->E >= dsp->E
+ value = *K->P
+ else
+ do lookup as usual
+ *K = <ptr to value, Epoch>
+ 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 000000000..b2a2ae561
--- /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 <errno.h>
+#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 000000000..b5fd1844b
--- /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 000000000..2c42beace
--- /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 000000000..bca695d4c
--- /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 000000000..f6eeb8c73
--- /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 000000000..0317aa903
--- /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 000000000..71d5b106f
--- /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 000000000..51ef7fa9c
--- /dev/null
+++ b/pstoraster/gconfig.h
@@ -0,0 +1,243 @@
+/*
+ * "$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-2002 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 <config.h>
+
+#ifdef device2_
+device2_(gs_cups_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_wan_e.ps",11)
+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 000000000..518b79020
--- /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 000000000..a9ae98b88
--- /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/gdebug.h b/pstoraster/gdebug.h
new file mode 100644
index 000000000..9b1480248
--- /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 000000000..f9f678114
--- /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 000000000..991584c04
--- /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 000000000..5641b3675
--- /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 000000000..5b647347b
--- /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 000000000..abfa9266f
--- /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 000000000..e6762a99c
--- /dev/null
+++ b/pstoraster/gdevcups.c
@@ -0,0 +1,3058 @@
+/*
+ * "$Id$"
+ *
+ * GNU Ghostscript raster output driver for the Common UNIX Printing
+ * System (CUPS).
+ *
+ * Copyright 1993-2002 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 <stdlib.h>
+#include <filter/raster.h>
+#include <cups/ppd.h>
+#include <math.h>
+
+#undef private
+#define private
+
+
+/*
+ * 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 <macros.h>; we can't include <macros.h> 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_cmyk_color(cups_map_cmyk_color);
+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, /* 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 */
+};
+
+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];
+static unsigned char rev_lower1[16] =
+ {
+ 0x00, 0x08, 0x04, 0x0c, 0x02, 0x0a, 0x06, 0x0e,
+ 0x01, 0x09, 0x05, 0x0d, 0x03, 0x0b, 0x07, 0x0f
+ },
+ rev_upper1[16] =
+ {
+ 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+ 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0
+ },
+ rev_lower2[16] = /* 2-bit colors */
+ {
+ 0x00, 0x04, 0x08, 0x0c, 0x01, 0x05, 0x09, 0x0d,
+ 0x02, 0x06, 0x0a, 0x0e, 0x03, 0x07, 0x0b, 0x0f
+ },
+ rev_upper2[16] = /* 2-bit colors */
+ {
+ 0x00, 0x40, 0x80, 0xc0, 0x10, 0x50, 0x90, 0xd0,
+ 0x20, 0x60, 0xa0, 0xe0, 0x30, 0x70, 0xb0, 0xf0
+ };
+
+
+/*
+ * Local functions...
+ */
+
+static void cups_print_chunked(gx_device_printer *, unsigned char *,
+ unsigned char *, int);
+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(%p)\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(%p, %p)\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...
+ */
+
+ fprintf(stderr, "DEBUG: cups->header.Duplex = %d\n", cups->header.Duplex);
+ fprintf(stderr, "DEBUG: cups->page = %d\n", cups->page);
+ if (cups->ppd)
+ {
+ fprintf(stderr, "DEBUG: cups->ppd = %p\n", cups->ppd);
+ fprintf(stderr, "DEBUG: cups->ppd->flip_duplex = %d\n", cups->ppd->flip_duplex);
+ }
+
+ if (cups->header.Duplex && !cups->header.Tumble &&
+ cups->ppd && cups->ppd->flip_duplex && !(cups->page & 1))
+ {
+ pmat->xx = (float)cups->header.HWResolution[0] / 72.0;
+ pmat->xy = 0.0;
+ pmat->yx = 0.0;
+ pmat->yy = (float)cups->header.HWResolution[1] / 72.0;
+ pmat->tx = -(float)cups->header.HWResolution[0] * pdev->HWMargins[2] / 72.0;
+ pmat->ty = -(float)cups->header.HWResolution[1] * pdev->HWMargins[3] / 72.0;
+ }
+ else
+ {
+ 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;
+ }
+
+ 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: HWMargins = [ %.3f %.3f %.3f %.3f ]\n",
+ pdev->HWMargins[0], pdev->HWMargins[1], pdev->HWMargins[2],
+ pdev->HWMargins[3]);
+ fprintf(stderr, "DEBUG: matrix = [ %.3f %.3f %.3f %.3f %.3f %.3f ]\n",
+ pmat->xx, pmat->xy, pmat->yx, pmat->yy, pmat->tx, pmat->ty);
+}
+
+
+/*
+ * '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 */
+ gs_param_string s; /* Temporary string value */
+ bool b; /* Temporary boolean value */
+
+
+#ifdef DEBUG
+ fprintf(stderr, "DEBUG: cups_get_params(%p, %p)\n", pdev, plist);
+#endif /* DEBUG */
+
+ /*
+ * First process the "standard" page device parameters...
+ */
+
+#ifdef DEBUG
+ fputs("DEBUG: before gdev_prn_get_params()\n", stderr);
+#endif /* DEBUG */
+
+ if ((code = gdev_prn_get_params(pdev, plist)) < 0)
+ return (code);
+
+#ifdef DEBUG
+ fputs("DEBUG: after gdev_prn_get_params()\n", stderr);
+#endif /* DEBUG */
+
+ /*
+ * Then write the CUPS parameters...
+ */
+
+#ifdef DEBUG
+ fputs("DEBUG: MediaClass\n", stderr);
+#endif /* DEBUG */
+
+ param_string_from_string(s, cups->header.MediaClass);
+ if ((code = param_write_string(plist, "MediaClass", &s)) < 0)
+ return (code);
+
+#ifdef DEBUG
+ fputs("DEBUG: AdvanceDistance\n", stderr);
+#endif /* DEBUG */
+
+ if ((code = param_write_int(plist, "AdvanceDistance",
+ (int *)&(cups->header.AdvanceDistance))) < 0)
+ return (code);
+
+#ifdef DEBUG
+ fputs("DEBUG: AdvanceDistance\n", stderr);
+#endif /* DEBUG */
+
+ if ((code = param_write_int(plist, "AdvanceMedia",
+ (int *)&(cups->header.AdvanceMedia))) < 0)
+ return (code);
+
+#ifdef DEBUG
+ fputs("DEBUG: Collate\n", stderr);
+#endif /* DEBUG */
+
+ b = cups->header.Collate;
+ if ((code = param_write_bool(plist, "Collate", &b)) < 0)
+ return (code);
+
+#ifdef DEBUG
+ fputs("DEBUG: CutMedia\n", stderr);
+#endif /* DEBUG */
+
+ if ((code = param_write_int(plist, "CutMedia",
+ (int *)&(cups->header.CutMedia))) < 0)
+ return (code);
+
+#ifdef DEBUG
+ fputs("DEBUG: InsertSheet\n", stderr);
+#endif /* DEBUG */
+
+ b = cups->header.InsertSheet;
+ if ((code = param_write_bool(plist, "InsertSheet", &b)) < 0)
+ return (code);
+
+#ifdef DEBUG
+ fputs("DEBUG: Jog\n", stderr);
+#endif /* DEBUG */
+
+ if ((code = param_write_int(plist, "Jog",
+ (int *)&(cups->header.Jog))) < 0)
+ return (code);
+
+#ifdef DEBUG
+ fputs("DEBUG: LeadingEdge\n", stderr);
+#endif /* DEBUG */
+
+ if ((code = param_write_int(plist, "LeadingEdge",
+ (int *)&(cups->header.LeadingEdge))) < 0)
+ return (code);
+
+#ifdef DEBUG
+ fputs("DEBUG: ManualFeed\n", stderr);
+#endif /* DEBUG */
+
+ b = cups->header.ManualFeed;
+ if ((code = param_write_bool(plist, "ManualFeed", &b)) < 0)
+ return (code);
+
+#ifdef DEBUG
+ fputs("DEBUG: MediaPosition\n", stderr);
+#endif /* DEBUG */
+
+ if ((code = param_write_int(plist, "MediaPosition",
+ (int *)&(cups->header.MediaPosition))) < 0)
+ return (code);
+
+#ifdef DEBUG
+ fputs("DEBUG: MirrorPrint\n", stderr);
+#endif /* DEBUG */
+
+ b = cups->header.MirrorPrint;
+ if ((code = param_write_bool(plist, "MirrorPrint", &b)) < 0)
+ return (code);
+
+#ifdef DEBUG
+ fputs("DEBUG: NegativePrint\n", stderr);
+#endif /* DEBUG */
+
+ b = cups->header.NegativePrint;
+ if ((code = param_write_bool(plist, "NegativePrint", &b)) < 0)
+ return (code);
+
+#ifdef DEBUG
+ fputs("DEBUG: OutputFaceUp\n", stderr);
+#endif /* DEBUG */
+
+ b = cups->header.OutputFaceUp;
+ if ((code = param_write_bool(plist, "OutputFaceUp", &b)) < 0)
+ return (code);
+
+#ifdef DEBUG
+ fputs("DEBUG: Separations\n", stderr);
+#endif /* DEBUG */
+
+ b = cups->header.Separations;
+ if ((code = param_write_bool(plist, "Separations", &b)) < 0)
+ return (code);
+
+#ifdef DEBUG
+ fputs("DEBUG: TraySwitch\n", stderr);
+#endif /* DEBUG */
+
+ b = cups->header.TraySwitch;
+ if ((code = param_write_bool(plist, "TraySwitch", &b)) < 0)
+ return (code);
+
+#ifdef DEBUG
+ fputs("DEBUG: Tumble\n", stderr);
+#endif /* DEBUG */
+
+ b = cups->header.Tumble;
+ if ((code = param_write_bool(plist, "Tumble", &b)) < 0)
+ return (code);
+
+#ifdef DEBUG
+ fputs("DEBUG: cupsWidth\n", stderr);
+#endif /* DEBUG */
+
+ if ((code = param_write_int(plist, "cupsWidth",
+ (int *)&(cups->header.cupsWidth))) < 0)
+ return (code);
+
+#ifdef DEBUG
+ fputs("DEBUG: cupsHeight\n", stderr);
+#endif /* DEBUG */
+
+ if ((code = param_write_int(plist, "cupsHeight",
+ (int *)&(cups->header.cupsHeight))) < 0)
+ return (code);
+
+#ifdef DEBUG
+ fputs("DEBUG: cupsMediaType\n", stderr);
+#endif /* DEBUG */
+
+ if ((code = param_write_int(plist, "cupsMediaType",
+ (int *)&(cups->header.cupsMediaType))) < 0)
+ return (code);
+
+#ifdef DEBUG
+ fputs("DEBUG: cupsBitsPerColor\n", stderr);
+#endif /* DEBUG */
+
+ if ((code = param_write_int(plist, "cupsBitsPerColor",
+ (int *)&(cups->header.cupsBitsPerColor))) < 0)
+ return (code);
+
+#ifdef DEBUG
+ fputs("DEBUG: cupsBitsPerPixel\n", stderr);
+#endif /* DEBUG */
+
+ if ((code = param_write_int(plist, "cupsBitsPerPixel",
+ (int *)&(cups->header.cupsBitsPerPixel))) < 0)
+ return (code);
+
+#ifdef DEBUG
+ fputs("DEBUG: cupsBytesPerLine\n", stderr);
+#endif /* DEBUG */
+
+ if ((code = param_write_int(plist, "cupsBytesPerLine",
+ (int *)&(cups->header.cupsBytesPerLine))) < 0)
+ return (code);
+
+#ifdef DEBUG
+ fputs("DEBUG: cupsColorOrder\n", stderr);
+#endif /* DEBUG */
+
+ if ((code = param_write_int(plist, "cupsColorOrder",
+ (int *)&(cups->header.cupsColorOrder))) < 0)
+ return (code);
+
+#ifdef DEBUG
+ fputs("DEBUG: cupsColorSpace\n", stderr);
+#endif /* DEBUG */
+
+ if ((code = param_write_int(plist, "cupsColorSpace",
+ (int *)&(cups->header.cupsColorSpace))) < 0)
+ return (code);
+
+#ifdef DEBUG
+ fputs("DEBUG: cupsCompression\n", stderr);
+#endif /* DEBUG */
+
+ if ((code = param_write_int(plist, "cupsCompression",
+ (int *)&(cups->header.cupsCompression))) < 0)
+ return (code);
+
+#ifdef DEBUG
+ fputs("DEBUG: cupsRowCount\n", stderr);
+#endif /* DEBUG */
+
+ if ((code = param_write_int(plist, "cupsRowCount",
+ (int *)&(cups->header.cupsRowCount))) < 0)
+ return (code);
+
+#ifdef DEBUG
+ fputs("DEBUG: cupsRowFeed\n", stderr);
+#endif /* DEBUG */
+
+ if ((code = param_write_int(plist, "cupsRowFeed",
+ (int *)&(cups->header.cupsRowFeed))) < 0)
+ return (code);
+
+#ifdef DEBUG
+ fputs("DEBUG: cupsRowStep\n", stderr);
+#endif /* DEBUG */
+
+ if ((code = param_write_int(plist, "cupsRowStep",
+ (int *)&(cups->header.cupsRowStep))) < 0)
+ return (code);
+
+#ifdef DEBUG
+ fputs("DEBUG: Leaving cups_get_params()\n", stderr);
+#endif /* DEBUG */
+
+ return (0);
+}
+
+
+/*
+ * 'cups_map_cmyk_color()' - Map a CMYK color to a color index.
+ *
+ * This function is only called when a 4 or 6 color colorspace is
+ * selected for output. CMYK colors are *not* corrected but *are*
+ * density adjusted.
+ */
+
+private gx_color_index /* O - Color index */
+cups_map_cmyk_color(gx_device *pdev, /* I - Device info */
+ gx_color_value c, /* I - Cyan value */
+ gx_color_value m, /* I - Magenta value */
+ gx_color_value y, /* I - Yellow value */
+ gx_color_value k) /* I - Black value */
+{
+ gx_color_index i; /* Temporary index */
+ gx_color_value ic, im, iy, ik; /* Integral CMYK values */
+
+
+#ifdef DEBUG
+ fprintf(stderr, "DEBUG: cups_map_cmyk_color(%p, %d, %d, %d, %d)\n", pdev,
+ c, m, y, k);
+#endif /* DEBUG */
+
+ /*
+ * Setup the color info data as needed...
+ */
+
+ if (pdev->color_info.num_components == 0)
+ cups_set_color_info(pdev);
+
+ /*
+ * Density correct...
+ */
+
+ c = cupsDensity[c];
+ m = cupsDensity[m];
+ y = cupsDensity[y];
+ k = cupsDensity[k];
+
+ ic = lut_rgb_color[c];
+ im = lut_rgb_color[m];
+ iy = lut_rgb_color[y];
+ ik = lut_rgb_color[k];
+
+ /*
+ * Convert the CMYK color to a color index...
+ */
+
+ switch (cups->header.cupsColorSpace)
+ {
+ default :
+ switch (cups->header.cupsBitsPerColor)
+ {
+ default :
+ 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;
+ }
+ break;
+
+ case CUPS_CSPACE_YMCK :
+ case CUPS_CSPACE_GMCK :
+ case CUPS_CSPACE_GMCS :
+ switch (cups->header.cupsBitsPerColor)
+ {
+ default :
+ 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)
+ {
+ if (ik)
+ i = 32;
+ else
+ i = 0;
+
+ 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;
+ break;
+ }
+
+ case CUPS_CSPACE_KCMY :
+ switch (cups->header.cupsBitsPerColor)
+ {
+ default :
+ 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;
+ }
+
+ if (gs_log_errors > 1)
+ fprintf(stderr, "DEBUG: CMYK (%d,%d,%d,%d) -> CMYK %8x (%d,%d,%d,%d)\n",
+ c, m, y, k, i, ic, im, iy, ik);
+
+ return (i);
+}
+
+
+/*
+ * '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(%p, %d, %8x)\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 %8x = ", color);
+#endif /* DEBUG */
+
+ /*
+ * Extract the color components from the color index...
+ */
+
+ switch (cups->header.cupsBitsPerColor)
+ {
+ default :
+ 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;
+ c1 = 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_RGBA :
+ prgb[0] = lut_color_rgb[c0];
+ prgb[1] = lut_color_rgb[c1];
+ prgb[2] = lut_color_rgb[c2];
+ 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 :
+ case CUPS_CSPACE_KCMYcm :
+ k = lut_color_rgb[c0];
+ divk = gx_max_color_value - k;
+ if (divk == 0)
+ {
+ prgb[0] = 0;
+ prgb[1] = 0;
+ prgb[2] = 0;
+ }
+ else
+ {
+ prgb[0] = gx_max_color_value + divk -
+ gx_max_color_value * c1 / divk;
+ prgb[1] = gx_max_color_value + divk -
+ gx_max_color_value * c2 / divk;
+ prgb[2] = gx_max_color_value + divk -
+ gx_max_color_value * c3 / divk;
+ }
+ break;
+
+ case CUPS_CSPACE_CMYK :
+ k = lut_color_rgb[c3];
+ divk = gx_max_color_value - k;
+ if (divk == 0)
+ {
+ prgb[0] = 0;
+ prgb[1] = 0;
+ prgb[2] = 0;
+ }
+ else
+ {
+ prgb[0] = gx_max_color_value + divk -
+ gx_max_color_value * c0 / divk;
+ prgb[1] = gx_max_color_value + divk -
+ gx_max_color_value * c1 / divk;
+ prgb[2] = gx_max_color_value + divk -
+ gx_max_color_value * c2 / divk;
+ }
+ break;
+
+ case CUPS_CSPACE_YMCK :
+ case CUPS_CSPACE_GMCK :
+ case CUPS_CSPACE_GMCS :
+ k = lut_color_rgb[c3];
+ divk = gx_max_color_value - k;
+ if (divk == 0)
+ {
+ prgb[0] = 0;
+ prgb[1] = 0;
+ prgb[2] = 0;
+ }
+ else
+ {
+ prgb[0] = gx_max_color_value + divk -
+ gx_max_color_value * c2 / divk;
+ prgb[1] = gx_max_color_value + divk -
+ gx_max_color_value * c1 / divk;
+ prgb[2] = gx_max_color_value + divk -
+ gx_max_color_value * c0 / divk;
+ }
+ break;
+ }
+
+#ifdef DEBUG
+ fprintf(stderr, "%d,%d,%d\n", prgb[0], prgb[1], prgb[2]);
+#endif /* DEBUG */
+
+ return (0);
+}
+
+
+/*
+ * 'cups_map_rgb_color()' - Map an RGB color to a color index. We map the
+ * RGB color to the output colorspace & bits (we
+ * figure out the format when we output a page).
+ */
+
+private gx_color_index /* O - Color index */
+cups_map_rgb_color(gx_device *pdev, /* I - Device info */
+ gx_color_value r, /* I - Red value */
+ gx_color_value g, /* I - Green value */
+ gx_color_value b) /* I - Blue value */
+{
+ gx_color_index i; /* Temporary index */
+ gx_color_value ic, im, iy, ik; /* Integral CMYK values */
+ gx_color_value mk; /* Maximum K value */
+ int tc, tm, ty; /* Temporary color values */
+
+
+#ifdef DEBUG
+ fprintf(stderr, "DEBUG: cups_map_rgb_color(%p, %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));
+
+ if ((mk = max(ic, max(im, iy))) > ik)
+ ik = (int)((float)ik * (float)ik * (float)ik / ((float)mk * (float)mk));
+
+ 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)
+ {
+ default :
+ 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_RGBA :
+ ic = lut_rgb_color[r];
+ im = lut_rgb_color[g];
+ iy = lut_rgb_color[b];
+
+ switch (cups->header.cupsBitsPerColor)
+ {
+ default :
+ i = (((((ic << 1) | im) << 1) | iy) << 1) | 0x01;
+ break;
+ case 2 :
+ i = (((((ic << 2) | im) << 2) | iy) << 2) | 0x03;
+ break;
+ case 4 :
+ i = (((((ic << 4) | im) << 4) | iy) << 4) | 0x0f;
+ break;
+ case 8 :
+ i = (((((ic << 8) | im) << 8) | iy) << 8) | 0xff;
+ break;
+ }
+ break;
+
+ default :
+ 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)
+ {
+ default :
+ 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)
+ {
+ default :
+ i = (((iy << 1) | im) << 1) | ic;
+ break;
+ case 2 :
+ i = (((iy << 2) | im) << 2) | ic;
+ break;
+ case 4 :
+ i = (((iy << 4) | im) << 4) | ic;
+ break;
+ case 8 :
+ i = (((iy << 8) | im) << 8) | ic;
+ break;
+ }
+ break;
+
+ case CUPS_CSPACE_CMYK :
+ ic = gx_max_color_value - r;
+ im = gx_max_color_value - g;
+ iy = gx_max_color_value - b;
+ ik = min(ic, min(im, iy));
+
+ if ((mk = max(ic, max(im, iy))) > ik)
+ ik = (int)((float)ik * (float)ik * (float)ik /
+ ((float)mk * (float)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)
+ {
+ default :
+ 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 %8x (%d,%d,%d,%d)\n",
+ r, g, b, i, ic, im, iy, ik);
+ break;
+
+ case CUPS_CSPACE_YMCK :
+ case CUPS_CSPACE_GMCK :
+ case CUPS_CSPACE_GMCS :
+ ic = gx_max_color_value - r;
+ im = gx_max_color_value - g;
+ iy = gx_max_color_value - b;
+ ik = min(ic, min(im, iy));
+
+ if ((mk = max(ic, max(im, iy))) > ik)
+ ik = (int)((float)ik * (float)ik * (float)ik /
+ ((float)mk * (float)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)
+ {
+ default :
+ i = (((((iy << 1) | im) << 1) | ic) << 1) | ik;
+ break;
+ case 2 :
+ i = (((((iy << 2) | im) << 2) | ic) << 2) | ik;
+ break;
+ case 4 :
+ i = (((((iy << 4) | im) << 4) | ic) << 4) | ik;
+ break;
+ case 8 :
+ i = (((((iy << 8) | im) << 8) | ic) << 8) | ik;
+ break;
+ }
+ break;
+
+ case CUPS_CSPACE_KCMYcm :
+ if (cups->header.cupsBitsPerColor == 1)
+ {
+ ic = gx_max_color_value - r;
+ im = gx_max_color_value - g;
+ iy = gx_max_color_value - b;
+ ik = min(ic, min(im, iy));
+
+ if ((mk = max(ic, max(im, iy))) > ik)
+ ik = (int)((float)ik * (float)ik * (float)ik /
+ ((float)mk * (float)mk));
+
+ ic = lut_rgb_color[ic - ik];
+ im = lut_rgb_color[im - ik];
+ iy = lut_rgb_color[iy - ik];
+ ik = lut_rgb_color[ik];
+ if (ik)
+ i = 32;
+ else if (ic && im)
+ i = 17;
+ else if (ic && iy)
+ i = 6;
+ else if (im && iy)
+ i = 12;
+ else if (ic)
+ i = 16;
+ else if (im)
+ i = 8;
+ else if (iy)
+ i = 4;
+ else
+ i = 0;
+ break;
+ }
+
+ case CUPS_CSPACE_KCMY :
+ ic = gx_max_color_value - r;
+ im = gx_max_color_value - g;
+ iy = gx_max_color_value - b;
+ ik = min(ic, min(im, iy));
+
+ if ((mk = max(ic, max(im, iy))) > ik)
+ ik = (int)((float)ik * (float)ik * (float)ik /
+ ((float)mk * (float)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)
+ {
+ default :
+ 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 = %8x\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(%p)\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 */
+
+
+ (void)fp; /* reference unused file pointer to prevent compiler warning */
+
+#ifdef DEBUG
+ fprintf(stderr, "DEBUG: cups_print_pages(%p, %p, %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);
+
+ /*
+ * 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);
+
+ /*
+ * See if the stream has been initialized yet...
+ */
+
+ if (cups->stream == NULL)
+ {
+ if ((cups->stream = cupsRasterOpen(1, CUPS_RASTER_WRITE)) == 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, dst, srcbytes);
+ else
+ switch (cups->header.cupsColorOrder)
+ {
+ case CUPS_ORDER_CHUNKED :
+ cups_print_chunked(pdev, src, dst, srcbytes);
+ 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");
+ 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 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 */
+ int old_depth; /* Old color depth */
+ int size_set; /* Was the size set? */
+ gdev_prn_space_params sp; /* Space parameter data */
+
+
+#ifdef DEBUG
+ fprintf(stderr, "DEBUG: cups_put_params(%p, %p)\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) \
+ { \
+ fprintf(stderr, "DEBUG: Setting %s to %d...\n", sname, intval); \
+ 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]; \
+ }
+
+ old_depth = pdev->color_info.depth;
+ size_set = param_read_float_array(plist, "PageSize", &arrayval) == 0;
+
+ 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) /* Compatibility */
+ intoption(MediaPosition, "MediaPosition", 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(cupsMediaType, "cupsMediaType", unsigned)
+ intoption(cupsBitsPerColor, "cupsBitsPerColor", 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)
+
+ cups_set_color_info(pdev);
+
+ /*
+ * Compute the page margins...
+ */
+
+ if (cups->ppd != NULL)
+ {
+ /*
+ * Pull the margins from the first size entry; since the margins are not
+ * like the bounding box we have to adjust the top and right values
+ * accordingly.
+ */
+
+ for (i = cups->ppd->num_sizes, size = cups->ppd->sizes;
+ i > 0;
+ i --, size ++)
+ if ((fabs(cups->PageSize[1] - size->length) < 18.0 &&
+ fabs(cups->PageSize[0] - size->width) < 18.0) ||
+ (fabs(cups->PageSize[0] - size->length) < 18.0 &&
+ fabs(cups->PageSize[1] - size->width) < 18.0))
+ break;
+
+ if (i == 0 && !cups->ppd->variable_sizes)
+ {
+ i = 1;
+ size = cups->ppd->sizes;
+ }
+
+ if (i > 0)
+ {
+ /*
+ * Standard size...
+ */
+
+ fprintf(stderr, "DEBUG: size = %s\n", size->name);
+
+ 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
+ {
+ /*
+ * Custom size...
+ */
+
+ fputs("DEBUG: size = Custom\n", stderr);
+
+ for (i = 0; i < 4; i ++)
+ margins[i] = cups->ppd->custom_margins[i] / 72.0;
+ }
+
+ fprintf(stderr, "DEBUG: margins[] = [ %f %f %f %f ]\n",
+ margins[0], margins[1], margins[2], margins[3]);
+ }
+ else
+ {
+ /*
+ * Set default margins of 0.0...
+ */
+
+ memset(margins, 0, sizeof(margins));
+ }
+
+ /*
+ * Set the margins to update the bitmap size...
+ */
+
+ gx_device_set_margins(pdev, margins, false);
+
+ /*
+ * 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.Margins[0] = 72.0 * margins[0];
+ cups->header.Margins[1] = 72.0 * margins[1];
+
+ cups->header.PageSize[0] = pdev->PageSize[0];
+ cups->header.PageSize[1] = pdev->PageSize[1];
+
+ /*
+ * Reallocate memory if the size or color depth was changed...
+ */
+
+ if (old_depth != pdev->color_info.depth || size_set)
+ {
+ fputs("DEBUG: Reallocating memory...\n", stderr);
+ sp = ((gx_device_printer *)pdev)->space_params;
+
+ if ((code = gdev_prn_reallocate_memory(pdev, &sp, pdev->width,
+ pdev->height)) < 0)
+ return (code);
+ }
+
+#ifdef DEBUG
+ fprintf(stderr, "DEBUG: ppd = %8x\n", cups->ppd);
+ fprintf(stderr, "DEBUG: PageSize = [ %.3f %.3f ]\n",
+ pdev->PageSize[0], pdev->PageSize[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 */
+
+ 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(%p)\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;
+ }
+
+ /*
+ * Enable/disable CMYK color support...
+ */
+
+ if (cups->color_info.num_components == 4)
+ cups->procs.map_cmyk_color = cups_map_cmyk_color;
+ else
+ cups->procs.map_cmyk_color = NULL;
+
+ /*
+ * 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 */
+ unsigned char *dst, /* I - Bitmap buffer */
+ int srcbytes) /* I - Number of bytes in src */
+{
+ int y; /* Looping var */
+ unsigned char *srcptr, /* Pointer to data */
+ *dstptr; /* Pointer to bits */
+ int count; /* Count for loop */
+ int flip; /* Flip scanline? */
+
+
+ if (cups->header.Duplex && !cups->header.Tumble &&
+ cups->ppd && cups->ppd->flip_duplex && !(cups->page & 1))
+ flip = 1;
+ else
+ flip = 0;
+
+ fprintf(stderr, "DEBUG: cups_print_chunked - flip = %d\n", flip);
+
+ /*
+ * Loop through the page bitmap and write chunked pixels, reversing as
+ * needed...
+ */
+
+ 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);
+ }
+
+ if (flip)
+ {
+ /*
+ * Flip the raster data before writing it...
+ */
+
+ if (srcptr[0] == 0 && memcmp(srcptr, srcptr + 1, srcbytes - 1) == 0)
+ memset(dst, 0, cups->header.cupsBytesPerLine);
+ else
+ {
+ dstptr = dst;
+ count = srcbytes;
+
+ switch (cups->color_info.depth)
+ {
+ case 1 : /* B&W bitmap */
+ for (srcptr += srcbytes - 1;
+ count > 0;
+ count --, srcptr --, dstptr ++)
+ {
+ *dstptr = rev_upper1[*srcptr & 15] |
+ rev_lower1[*srcptr >> 4];
+ }
+ break;
+
+ case 2 : /* 2-bit grayscale */
+ for (srcptr += srcbytes - 1;
+ count > 0;
+ count --, srcptr --, dstptr ++)
+ {
+ *dstptr = rev_upper2[*srcptr & 15] |
+ rev_lower2[*srcptr >> 4];
+ }
+ break;
+
+ case 4 : /* 4-bit grayscale, or RGB, CMY, or CMYK bitmap */
+ for (srcptr += srcbytes - 1;
+ count > 0;
+ count --, srcptr --, dstptr ++)
+ *dstptr = (*srcptr >> 4) | (*srcptr << 4);
+ break;
+
+ case 8 : /* 8-bit grayscale, or 2-bit RGB, CMY, or CMYK image */
+ for (srcptr += srcbytes - 1;
+ count > 0;
+ count --, srcptr --, dstptr ++)
+ *dstptr = *srcptr;
+ break;
+
+ case 16 : /* 4-bit RGB, CMY or CMYK image */
+ for (srcptr += srcbytes - 2;
+ count > 0;
+ count -= 2, srcptr -= 2, dstptr += 2)
+ {
+ dstptr[0] = srcptr[0];
+ dstptr[1] = srcptr[1];
+ }
+ break;
+
+ case 24 : /* 8-bit RGB or CMY image */
+ for (srcptr += srcbytes - 3;
+ count > 0;
+ count -= 3, srcptr -= 3, dstptr += 3)
+ {
+ dstptr[0] = srcptr[0];
+ dstptr[1] = srcptr[1];
+ dstptr[2] = srcptr[2];
+ }
+ break;
+
+ case 32 : /* 4-bit RGB, CMY or CMYK bitmap */
+ for (srcptr += srcbytes - 4;
+ count > 0;
+ count -= 4, srcptr -= 4, dstptr += 4)
+ {
+ dstptr[0] = srcptr[0];
+ dstptr[1] = srcptr[1];
+ dstptr[2] = srcptr[2];
+ dstptr[3] = srcptr[3];
+ }
+ break;
+ }
+ }
+
+ /*
+ * Write the bitmap data to the raster stream...
+ */
+
+ cupsRasterWritePixels(cups->stream, dst, cups->header.cupsBytesPerLine);
+ }
+ else
+ {
+ /*
+ * 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; /* ... */
+ int flip; /* Flip scanline? */
+
+
+ if (cups->header.Duplex && !cups->header.Tumble &&
+ cups->ppd && cups->ppd->flip_duplex && !(cups->page & 1))
+ flip = 1;
+ else
+ flip = 0;
+
+ fprintf(stderr, "DEBUG: cups_print_banded - flip = %d\n", flip);
+
+ /*
+ * Loop through the page bitmap and write banded pixels... We have
+ * to separate each chunked color as needed...
+ */
+
+ 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
+ {
+ if (flip)
+ cptr = dst + bandbytes - 1;
+ else
+ cptr = dst;
+
+ mptr = cptr + bandbytes;
+ yptr = mptr + bandbytes;
+ kptr = yptr + bandbytes;
+ lcptr = yptr + bandbytes;
+ lmptr = lcptr + bandbytes;
+
+ switch (cups->header.cupsBitsPerColor)
+ {
+ default :
+ memset(dst, 0, cups->header.cupsBytesPerLine);
+
+ switch (cups->header.cupsColorSpace)
+ {
+ default :
+ for (x = cups->width, bit = flip ? 1 << (x & 7) : 128;
+ x > 0;
+ x --, srcptr ++)
+ {
+ if (*srcptr & 0x40)
+ *cptr |= bit;
+ if (*srcptr & 0x20)
+ *mptr |= bit;
+ if (*srcptr & 0x10)
+ *yptr |= bit;
+
+ if (flip)
+ {
+ if (bit < 128)
+ bit <<= 1;
+ else
+ {
+ cptr --;
+ mptr --;
+ yptr --;
+ bit = 1;
+ }
+ }
+ else
+ bit >>= 1;
+
+ x --;
+ if (x == 0)
+ break;
+
+ if (*srcptr & 0x4)
+ *cptr |= bit;
+ if (*srcptr & 0x2)
+ *mptr |= bit;
+ if (*srcptr & 0x1)
+ *yptr |= bit;
+
+ if (flip)
+ {
+ if (bit < 128)
+ bit <<= 1;
+ else
+ {
+ cptr --;
+ mptr --;
+ yptr --;
+ bit = 1;
+ }
+ }
+ else if (bit > 1)
+ bit >>= 1;
+ else
+ {
+ cptr ++;
+ mptr ++;
+ yptr ++;
+ bit = 128;
+ }
+ }
+ break;
+ case CUPS_CSPACE_GMCK :
+ case CUPS_CSPACE_GMCS :
+ case CUPS_CSPACE_RGBA :
+ case CUPS_CSPACE_CMYK :
+ case CUPS_CSPACE_YMCK :
+ case CUPS_CSPACE_KCMY :
+ for (x = cups->width, bit = flip ? 1 << (x & 7) : 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;
+
+ if (flip)
+ {
+ if (bit < 128)
+ bit <<= 1;
+ else
+ {
+ cptr --;
+ mptr --;
+ yptr --;
+ kptr --;
+ bit = 1;
+ }
+ }
+ else
+ 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 (flip)
+ {
+ if (bit < 128)
+ bit <<= 1;
+ else
+ {
+ cptr --;
+ mptr --;
+ yptr --;
+ kptr --;
+ bit = 1;
+ }
+ }
+ else if (bit > 1)
+ bit >>= 1;
+ else
+ {
+ cptr ++;
+ mptr ++;
+ yptr ++;
+ kptr ++;
+ bit = 128;
+ }
+ }
+ break;
+ case CUPS_CSPACE_KCMYcm :
+ for (x = cups->width, bit = flip ? 1 << (x & 7) : 128;
+ x > 0;
+ x --, srcptr ++)
+ {
+ /*
+ * Note: Because of the way the pointers are setup,
+ * the following code is correct even though
+ * the names don't match...
+ */
+
+ if (*srcptr & 0x20)
+ *cptr |= bit;
+ if (*srcptr & 0x10)
+ *mptr |= bit;
+ if (*srcptr & 0x08)
+ *yptr |= bit;
+ if (*srcptr & 0x04)
+ *kptr |= bit;
+ if (*srcptr & 0x02)
+ *lcptr |= bit;
+ if (*srcptr & 0x01)
+ *lmptr |= bit;
+
+ if (flip)
+ {
+ if (bit < 128)
+ bit <<= 1;
+ else
+ {
+ cptr --;
+ mptr --;
+ yptr --;
+ kptr --;
+ lcptr --;
+ lmptr --;
+ bit = 1;
+ }
+ }
+ else 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)
+ {
+ default :
+ for (x = cups->width, bit = flip ? 3 << (2 * (x & 3)) : 0xc0;
+ x > 0;
+ x --, srcptr ++)
+ switch (bit)
+ {
+ case 0xc0 :
+ if ((temp = *srcptr & 0x30) != 0)
+ *cptr |= temp << 2;
+ if ((temp = *srcptr & 0x0c) != 0)
+ *mptr |= temp << 4;
+ if ((temp = *srcptr & 0x03) != 0)
+ *yptr |= temp << 6;
+
+ if (flip)
+ {
+ bit = 0x03;
+ cptr --;
+ mptr --;
+ yptr --;
+ }
+ else
+ bit = 0x30;
+ break;
+ case 0x30 :
+ if ((temp = *srcptr & 0x30) != 0)
+ *cptr |= temp;
+ if ((temp = *srcptr & 0x0c) != 0)
+ *mptr |= temp << 2;
+ if ((temp = *srcptr & 0x03) != 0)
+ *yptr |= temp << 4;
+
+ if (flip)
+ bit = 0xc0;
+ else
+ bit = 0x0c;
+ break;
+ case 0x0c :
+ if ((temp = *srcptr & 0x30) != 0)
+ *cptr |= temp >> 2;
+ if ((temp = *srcptr & 0x0c) != 0)
+ *mptr |= temp;
+ if ((temp = *srcptr & 0x03) != 0)
+ *yptr |= temp << 2;
+
+ if (flip)
+ bit = 0x30;
+ else
+ bit = 0x03;
+ break;
+ case 0x03 :
+ if ((temp = *srcptr & 0x30) != 0)
+ *cptr |= temp >> 4;
+ if ((temp = *srcptr & 0x0c) != 0)
+ *mptr |= temp >> 2;
+ if ((temp = *srcptr & 0x03) != 0)
+ *yptr |= temp;
+
+ if (flip)
+ bit = 0x0c;
+ else
+ {
+ bit = 0xc0;
+ cptr ++;
+ mptr ++;
+ yptr ++;
+ }
+ break;
+ }
+ break;
+ case CUPS_CSPACE_GMCK :
+ case CUPS_CSPACE_GMCS :
+ case CUPS_CSPACE_RGBA :
+ case CUPS_CSPACE_CMYK :
+ case CUPS_CSPACE_YMCK :
+ case CUPS_CSPACE_KCMY :
+ case CUPS_CSPACE_KCMYcm :
+ for (x = cups->width, bit = flip ? 3 << (2 * (x & 3)) : 0xc0;
+ x > 0;
+ x --, srcptr ++)
+ switch (bit)
+ {
+ case 0xc0 :
+ if ((temp = *srcptr & 0xc0) != 0)
+ *cptr |= temp;
+ if ((temp = *srcptr & 0x30) != 0)
+ *mptr |= temp << 2;
+ if ((temp = *srcptr & 0x0c) != 0)
+ *yptr |= temp << 4;
+ if ((temp = *srcptr & 0x03) != 0)
+ *kptr |= temp << 6;
+
+ if (flip)
+ {
+ bit = 0x03;
+ cptr --;
+ mptr --;
+ yptr --;
+ kptr --;
+ }
+ else
+ bit = 0x30;
+ break;
+ case 0x30 :
+ if ((temp = *srcptr & 0xc0) != 0)
+ *cptr |= temp >> 2;
+ if ((temp = *srcptr & 0x30) != 0)
+ *mptr |= temp;
+ if ((temp = *srcptr & 0x0c) != 0)
+ *yptr |= temp << 2;
+ if ((temp = *srcptr & 0x03) != 0)
+ *kptr |= temp << 4;
+
+ if (flip)
+ bit = 0xc0;
+ else
+ bit = 0x0c;
+ break;
+ case 0x0c :
+ if ((temp = *srcptr & 0xc0) != 0)
+ *cptr |= temp >> 4;
+ if ((temp = *srcptr & 0x30) != 0)
+ *mptr |= temp >> 2;
+ if ((temp = *srcptr & 0x0c) != 0)
+ *yptr |= temp;
+ if ((temp = *srcptr & 0x03) != 0)
+ *kptr |= temp << 2;
+
+ if (flip)
+ bit = 0x30;
+ else
+ bit = 0x03;
+ break;
+ case 0x03 :
+ if ((temp = *srcptr & 0xc0) != 0)
+ *cptr |= temp >> 6;
+ if ((temp = *srcptr & 0x30) != 0)
+ *mptr |= temp >> 4;
+ if ((temp = *srcptr & 0x0c) != 0)
+ *yptr |= temp >> 2;
+ if ((temp = *srcptr & 0x03) != 0)
+ *kptr |= temp;
+
+ if (flip)
+ bit = 0x0c;
+ else
+ {
+ bit = 0xc0;
+ cptr ++;
+ mptr ++;
+ yptr ++;
+ kptr ++;
+ }
+ break;
+ }
+ break;
+ }
+ break;
+
+ case 4 :
+ memset(dst, 0, cups->header.cupsBytesPerLine);
+
+ switch (cups->header.cupsColorSpace)
+ {
+ default :
+ for (x = cups->width, bit = flip && (x & 1) ? 0xf0 : 0x0f;
+ x > 0;
+ x --, srcptr += 2)
+ switch (bit)
+ {
+ case 0xf0 :
+ if ((temp = srcptr[0] & 0x0f) != 0)
+ *cptr |= temp << 4;
+ if ((temp = srcptr[1] & 0xf0) != 0)
+ *mptr |= temp;
+ if ((temp = srcptr[1] & 0x0f) != 0)
+ *yptr |= temp << 4;
+
+ bit = 0x0f;
+
+ if (flip)
+ {
+ cptr --;
+ mptr --;
+ yptr --;
+ }
+ break;
+ case 0x0f :
+ if ((temp = srcptr[0] & 0x0f) != 0)
+ *cptr |= temp;
+ if ((temp = srcptr[1] & 0xf0) != 0)
+ *mptr |= temp >> 4;
+ if ((temp = srcptr[1] & 0x0f) != 0)
+ *yptr |= temp;
+
+ bit = 0xf0;
+
+ if (!flip)
+ {
+ cptr ++;
+ mptr ++;
+ yptr ++;
+ }
+ break;
+ }
+ break;
+ case CUPS_CSPACE_GMCK :
+ case CUPS_CSPACE_GMCS :
+ case CUPS_CSPACE_RGBA :
+ case CUPS_CSPACE_CMYK :
+ case CUPS_CSPACE_YMCK :
+ case CUPS_CSPACE_KCMY :
+ case CUPS_CSPACE_KCMYcm :
+ for (x = cups->width, bit = flip && (x & 1) ? 0xf0 : 0x0f;
+ x > 0;
+ x --, srcptr += 2)
+ switch (bit)
+ {
+ case 0xf0 :
+ if ((temp = srcptr[0] & 0xf0) != 0)
+ *cptr |= temp;
+ if ((temp = srcptr[0] & 0x0f) != 0)
+ *mptr |= temp << 4;
+ if ((temp = srcptr[1] & 0xf0) != 0)
+ *yptr |= temp;
+ if ((temp = srcptr[1] & 0x0f) != 0)
+ *kptr |= temp << 4;
+
+ bit = 0x0f;
+
+ if (flip)
+ {
+ cptr --;
+ mptr --;
+ yptr --;
+ kptr --;
+ }
+ break;
+ case 0x0f :
+ if ((temp = srcptr[0] & 0xf0) != 0)
+ *cptr |= temp >> 4;
+ if ((temp = srcptr[0] & 0x0f) != 0)
+ *mptr |= temp;
+ if ((temp = srcptr[1] & 0xf0) != 0)
+ *yptr |= temp >> 4;
+ if ((temp = srcptr[1] & 0x0f) != 0)
+ *kptr |= temp;
+
+ bit = 0xf0;
+
+ if (!flip)
+ {
+ cptr ++;
+ mptr ++;
+ yptr ++;
+ kptr ++;
+ }
+ break;
+ }
+ break;
+ }
+ break;
+
+ case 8 :
+ switch (cups->header.cupsColorSpace)
+ {
+ default :
+ if (flip)
+ for (x = cups->width; x > 0; x --)
+ {
+ *cptr-- = *srcptr++;
+ *mptr-- = *srcptr++;
+ *yptr-- = *srcptr++;
+ }
+ else
+ for (x = cups->width; x > 0; x --)
+ {
+ *cptr++ = *srcptr++;
+ *mptr++ = *srcptr++;
+ *yptr++ = *srcptr++;
+ }
+ break;
+ case CUPS_CSPACE_GMCK :
+ case CUPS_CSPACE_GMCS :
+ case CUPS_CSPACE_RGBA :
+ case CUPS_CSPACE_CMYK :
+ case CUPS_CSPACE_YMCK :
+ case CUPS_CSPACE_KCMY :
+ case CUPS_CSPACE_KCMYcm :
+ if (flip)
+ for (x = cups->width; x > 0; x --)
+ {
+ *cptr-- = *srcptr++;
+ *mptr-- = *srcptr++;
+ *yptr-- = *srcptr++;
+ *kptr-- = *srcptr++;
+ }
+ else
+ for (x = cups->width; 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 */
+
+
+ /**** NOTE: Currently planar output doesn't support flipped duplex!!! ****/
+
+ /*
+ * 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)
+ {
+ default :
+ memset(dst, 0, cups->header.cupsBytesPerLine);
+
+ switch (cups->header.cupsColorSpace)
+ {
+ default :
+ 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_GMCK :
+ case CUPS_CSPACE_GMCS :
+ case CUPS_CSPACE_RGBA :
+ 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)
+ {
+ default :
+ for (dstptr = dst, x = cups->width, srcbit = 48 >> (z * 2),
+ dstbit = 0xc0;
+ x > 0;
+ x --, srcptr ++)
+ {
+ if ((temp = *srcptr & srcbit) != 0)
+ {
+ 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_GMCK :
+ case CUPS_CSPACE_GMCS :
+ case CUPS_CSPACE_RGBA :
+ 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) != 0)
+ {
+ 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)
+ {
+ default :
+ 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) != 0)
+ {
+ 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_GMCK :
+ case CUPS_CSPACE_GMCS :
+ case CUPS_CSPACE_RGBA :
+ 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) != 0)
+ {
+ 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 000000000..9b6ccecc5
--- /dev/null
+++ b/pstoraster/gdevdbit.c
@@ -0,0 +1,708 @@
+/* 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 000000000..7985876e7
--- /dev/null
+++ b/pstoraster/gdevddrw.c
@@ -0,0 +1,643 @@
+/* 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);
+ }
+ else
+ {
+ cindex = 0;
+ fill_rect = 0;
+ }
+
+ 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 = &image;
+ }
+ 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 000000000..7633b7b43
--- /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 000000000..c15669695
--- /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, &params, 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, &params->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, &copy_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 000000000..9e16a2a0d
--- /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 000000000..a2f665f12
--- /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 000000000..231a14d6e
--- /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 <color0,color1> to copy_mode.
+ * Logically, this is a 2-D array.
+ * The indexing is (transparent, 0, 1, unused). */
+private const copy_mode copy_modes[16] =
+{
+ {~0UL, COPY_FUNNY}, /* NN */
+ {~0UL, 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 */
+ {~0UL, COPY_OR}, /* 1N */
+ {~0UL, 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 000000000..9a9413a94
--- /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 000000000..12cf8ec9b
--- /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 000000000..1e3a4b932
--- /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 000000000..d35483323
--- /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 000000000..e0df0e13f
--- /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 000000000..875bcaddb
--- /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 000000000..94dd921e8
--- /dev/null
+++ b/pstoraster/gdevmem.c
@@ -0,0 +1,501 @@
+/* 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), 8);
+}
+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)
+{
+ int offset;
+
+ 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)))
+
+
+ offset = mem_bitmap_bits_size(mdev, mdev->width, mdev->height);
+
+ mem_set_line_ptrs(mdev,
+ huge_ptr_add(mdev->base, offset),
+ 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 000000000..17dc5c059
--- /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 000000000..0cab14414
--- /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 000000000..239ffbcc8
--- /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 000000000..3c143c921
--- /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 000000000..e8cbb0fd9
--- /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 000000000..1322594d2
--- /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 000000000..21bde1bb9
--- /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 000000000..b6954f159
--- /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/gdevpipe.c b/pstoraster/gdevpipe.c
new file mode 100644
index 000000000..03909db6a
--- /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 000000000..f1f7b3cd8
--- /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 000000000..77a6e5bde
--- /dev/null
+++ b/pstoraster/gdevprn.c
@@ -0,0 +1,837 @@
+/*
+ Copyright 1993-2002 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 <stdlib.h>
+
+/* ---------------- 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 = false;
+ 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;
+
+ 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 = ppdev->space_params;
+ 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);
+
+ if (code < 0 ||
+ (ppdev->Duplex_set >= 0 &&
+ (code = (ppdev->Duplex_set ?
+ param_write_bool(plist, "Duplex", &ppdev->Duplex) :
+ param_write_null(plist, "Duplex"))) < 0)
+ )
+ return code;
+
+ 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_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
+
+ /* 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;
+
+ return 0;
+}
+
+/* ------ Others ------ */
+
+#define TILE_SIZE 256
+
+/* Default routine to override current space_params. */
+void
+gdev_prn_default_get_space_params(const gx_device_printer *printer_dev,
+ gdev_prn_space_params *space_params)
+{
+ int cache_size; /* Size of tile cache in bytes */
+ char *cache_env, /* Cache size environment variable */
+ cache_units[255]; /* Cache size units */
+
+
+ if ((cache_env = getenv("RIP_MAX_CACHE")) != NULL)
+ {
+ switch (sscanf(cache_env, "%d%254s", &cache_size, cache_units))
+ {
+ case 0 :
+ cache_size = 8 * 1024 * 1024;
+ break;
+ case 1 :
+ cache_size *= 4 * TILE_SIZE * TILE_SIZE;
+ break;
+ case 2 :
+ if (tolower(cache_units[0]) == 'g')
+ cache_size *= 1024 * 1024 * 1024;
+ else if (tolower(cache_units[0]) == 'm')
+ cache_size *= 1024 * 1024;
+ else if (tolower(cache_units[0]) == 'k')
+ cache_size *= 1024;
+ else if (tolower(cache_units[0]) == 't')
+ cache_size *= 4 * TILE_SIZE * TILE_SIZE;
+ break;
+ }
+ }
+ else
+ cache_size = 8 * 1024 * 1024;
+
+ space_params->MaxBitmap = cache_size;
+ space_params->BufferSpace = cache_size / 10;
+}
+
+/* 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;
+
+ if (prdev->is_open &&
+ (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 000000000..0b3dc84ba
--- /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 "gxcldev.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 000000000..799a8dc12
--- /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 000000000..dfb4d2848
--- /dev/null
+++ b/pstoraster/gdevps.c
@@ -0,0 +1,1151 @@
+/* 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}!",
+ /* <rbyte> <gbyte> <bbyte> rG - */
+ /* <graybyte> G - */
+ "/rG{3{3 -1 roll 255 div}repeat setrgbcolor}!/G{255 div setgray}!/K{0 G}!",
+ /* <bbyte> <rgbyte> r6 - */
+ /* <gbyte> <rbbyte> r5 - */
+ /* <rbyte> <gbbyte> 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}!",
+ /* <dx> lx - */
+ /* <dy> ly - */
+ /* <dx2> <dy2> <dx3> <dy3> v - */
+ /* <dx1> <dy1> <dx2> <dy2> y - */
+ "/lx{0 rlineto}!/ly{0 exch rlineto}!/v{0 0 6 2 roll c}!/y{2 copy c}!",
+ /* <x> <y> <dx> <dy> re - */
+ "/re{4 -2 roll m exch dup lx exch ly neg lx h}!",
+ /* <x> <y> <a> <b> ^ <x> <y> <a> <b> <-a> <-y> */
+ "/^{3 index neg 3 index neg}!",
+ /* <x> <y> <dx1> <dy1> ... <dxn> <dyn> P - */
+ "/P{count 0 gt{count -2 roll moveto p}if}!",
+ /* <dx1> <dy1> ... <dxn> <dyn> 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}!",
+ /* <w> <h> <name> <length> <src> | <w> <h> <data> */
+ "/|{exch string readstring pop exch 4 1 roll 3 packedarray cvx exch 1 index def exec}!",
+ /* <w> <?> <name> (<length>|) + <w> <?> <name> <length> */
+ "/+{dup type/nametype eq{2 index 7 add -3 bitshift 2 index mul}if}!",
+ /* <w> <h> <name> (<length>|) $ <w> <h> <data> */
+ "/@/currentfile #/${+ @ |}!",
+ /* <x> <y> <w> <h> <bpc/inv> <src> Ix <w> <h> <bps/inv> <mtx> <src> */
+ "/Ix{[1 0 0 1 11 -2 roll exch neg exch neg]exch}!",
+ /* <x> <y> <h> <src> , - */
+ /* <x> <y> <h> <src> If - */
+ /* <x> <y> <h> <src> 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[] =
+{
+ /* <src> <w> <h> F <g4src> */
+ "/F{<</Columns 4 2 roll/Rows exch/K -1/BlackIs1 true >>/CCITTFaxDecode filter}!",
+ /* <src> X <a85src> */
+ /* - @X <a85src> */
+ /* <w> <h> <src> +F <w> <h> <g4src> */
+ /* <w> <h> +F <w> <h> <g4src> */
+ /* <w> <h> @F <w> <h> <g4src> */
+ /* <w> <h> @C <w> <h> <g4a85src> */
+ "/X{/ASCII85Decode filter}!/@X{@ X}!/+F{2 index 2 index F}!/@F{@ +F}!/@C{@X +F}!",
+ /* <w> <h> <name> (<length>|) $X <w> <h> <data> */
+ /* <w> <h> <?> <?> <src> -F <w> <h> <?> <?> <g4src> */
+ /* <w> <h> <name> (<length>|) $F <w> <h> <data> */
+ /* <w> <h> <name> (<length>|) $C <w> <h> <data> */
+ "/$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);
+ pputs(s, "/pagesave save def GS_pswrite_ProcSet begin\n");
+ if (!pdev->ProduceEPS) {
+ int width = (int)(vdev->width * 72.0 / vdev->HWResolution[0] + 0.5);
+ int height = (int)(vdev->height * 72.0 / vdev->HWResolution[1] + 0.5);
+
+ if (pdev->LanguageLevel > 1.5)
+ pprintd2(s, "<< /PageSize [%d %d] >> setpagedevice\n",
+ width, height);
+ else {
+ typedef struct ps_ {
+ const char *size_name;
+ int width, height;
+ } page_size;
+ static const page_size sizes[] = {
+ {"/11x17", 792, 1224},
+ {"/a3", 842, 1190},
+ {"/a4", 595, 842},
+ {"/b5", 501, 709},
+ {"/ledger", 1224, 792},
+ {"/legal", 612, 1008},
+ {"/letter", 612, 792},
+ {"null", 0, 0}
+ };
+ const page_size *p = sizes;
+
+ while (p->size_name[0] == '/' &&
+ (p->width != width || p->height != height))
+ ++p;
+ pprintd2(s, "%d %d ", width, height);
+ pprints1(s, "%s PS\n", p->size_name);
+ }
+ }
+ pprintg2(s, "%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 > pdev->path_state.move)
+ 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 > 0 && !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 000000000..9389b60ab
--- /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 000000000..38e5f4098
--- /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 000000000..1e814a52f
--- /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 000000000..e93f61d33
--- /dev/null
+++ b/pstoraster/gdevpsdi.c
@@ -0,0 +1,349 @@
+/*
+ Copyright 1993-2002 by Easy Software Products.
+ Copyright 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 "strimpl.h"
+#include "scfx.h"
+#include <config.h>
+#ifdef HAVE_LIBJPEG
+#include "jpeglib.h" /* for sdct.h */
+#include "sdct.h"
+#endif /* HAVE_LIBJPEG */
+#include "slzwx.h"
+#include "spngpx.h"
+#include "srlx.h"
+#ifdef HAVE_LIBZ
+#include "szlibx.h"
+#endif /* HAVE_LIBZ */
+
+/* ---------------- 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.
+ */
+#ifdef HAVE_LIBZ
+ template =
+ (pdev->params.UseFlateCompression &&
+ pdev->version >= psdf_version_ll3 ?
+ &s_zlibE_template : &s_LZWE_template);
+#else
+ template = &s_LZWE_template;
+#endif /* HAVE_LIBZ */
+ }
+ if (!pdip->Encode || template == 0) /* no compression */
+ return 0;
+#ifdef HAVE_LIBJPEG
+ /* 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;
+ }
+#endif /* HAVE_LIBJPEG */
+ 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);
+#ifdef HAVE_LIBZ
+ } else if (template == &s_LZWE_template ||
+ template == &s_zlibE_template) {
+#else
+ } else if (template == &s_LZWE_template) {
+#endif /* HAVE_LIBZ */
+ /* 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;
+ }
+#ifdef HAVE_LIBJPEG
+ } else if (template == &s_DCTE_template) {
+ /****** ADD PARAMETERS FROM pdip->Dict ******/
+#endif /* HAVE_LIBJPEG */
+ } {
+ 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, &params, pim, resolution);
+ } else {
+ code = setup_image_compression(pbw, &params, 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, &params, pim, resolution);
+ } else {
+ code = setup_image_compression(pbw, &params, 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 000000000..346c76e45
--- /dev/null
+++ b/pstoraster/gdevpsdp.c
@@ -0,0 +1,705 @@
+/*
+ Copyright 1993-2002 by Easy Software Products.
+ Copyright 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 <config.h>
+#ifdef HAVE_LIBJPEG
+#include "jpeglib.h" /* for sdct.h */
+#include "sdct.h"
+#endif /* HAVE_LIBJPEG */
+#include "slzwx.h"
+#include "srlx.h"
+#ifdef HAVE_LIBZ
+#include "szlibx.h"
+#endif /* HAVE_LIBZ */
+
+/* ---------------- 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[] =
+{
+#ifdef HAVE_LIBJPEG
+ {"DCTEncode", &s_DCTE_template},
+#endif /* HAVE_LIBJPEG */
+#ifdef HAVE_LIBZ
+ {"FlateEncode", &s_zlibE_template, psdf_version_ll3},
+#endif /* HAVE_LIBZ */
+ {"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},
+#ifdef HAVE_LIBZ
+ {"FlateEncode", &s_zlibE_template, psdf_version_ll3},
+#endif /* HAVE_LIBZ */
+ {"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 -------- */
+
+#ifdef HAVE_LIBJPEG
+extern stream_state_proc_get_params(s_DCTE_get_params, stream_DCT_state);
+#endif /* HAVE_LIBJPEG */
+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));
+}
+#ifdef HAVE_LIBJPEG
+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;
+}
+#endif /* HAVE_LIBJPEG */
+
+/*
+ * 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 (
+#ifdef HAVE_LIBJPEG
+ (code = psdf_get_image_dict_param(plist, pnames->ACSDict,
+ params->ACSDict,
+ psdf_DCT_get_params)) < 0 ||
+#endif /* HAVE_LIBJPEG */
+ (code = param_write_bool(plist, pnames->AntiAlias,
+ &params->AntiAlias)) < 0 ||
+ (pnames->AutoFilter != 0 &&
+ (code = param_write_bool(plist, pnames->AutoFilter,
+ &params->AutoFilter)) < 0) ||
+ (code = param_write_int(plist, pnames->Depth,
+ &params->Depth)) < 0 ||
+ (code = psdf_get_image_dict_param(plist, pnames->Dict,
+ params->Dict,
+#ifdef HAVE_LIBJPEG
+ (params->Dict == 0 ||
+ params->Dict->template ==
+ &s_CFE_template ?
+ psdf_CF_get_params :
+ psdf_DCT_get_params))) < 0 ||
+#else
+ psdf_CF_get_params)) < 0 ||
+#endif /* HAVE_LIBJPEG */
+ (code = param_write_bool(plist, pnames->Downsample,
+ &params->Downsample)) < 0 ||
+ (code = param_write_name(plist, pnames->DownsampleType,
+ &dsts)) < 0 ||
+ (code = param_write_bool(plist, pnames->Encode,
+ &params->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,
+ &params->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 -------- */
+
+#ifdef HAVE_LIBJPEG
+extern stream_state_proc_put_params(s_DCTE_put_params, stream_DCT_state);
+#endif /* HAVE_LIBJPEG */
+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);
+}
+#ifdef HAVE_LIBJPEG
+private int
+psdf_DCT_put_params(gs_param_list * plist, stream_state * ss)
+{
+ return s_DCTE_put_params(plist, (stream_DCT_state *) ss);
+}
+#endif /* HAVE_LIBJPEG */
+
+/* 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.
+ ******/
+#ifdef HAVE_LIBJPEG
+ if (template != &s_DCTE_template)
+#endif /* HAVE_LIBJPEG */
+ {
+ 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;
+
+#ifdef HAVE_LIBJPEG
+ if ((pname = pnames->ACSDict) != 0) {
+ code = psdf_put_image_dict_param(plist, pname, &params->ACSDict,
+ &s_DCTE_template,
+ psdf_DCT_put_params, mem);
+ if (code < 0)
+ ecode = code;
+ }
+#endif /* HAVE_LIBJPEG */
+ ecode = psdf_put_bool_param(plist, pnames->AntiAlias,
+ &params->AntiAlias, ecode);
+ if (pnames->AutoFilter)
+ ecode = psdf_put_bool_param(plist, pnames->AutoFilter,
+ &params->AutoFilter, ecode);
+ ecode = psdf_put_int_param(plist, pnames->Depth,
+ &params->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;
+#ifdef HAVE_LIBJPEG
+ else
+ template = &s_DCTE_template,
+ put_params = psdf_DCT_put_params;
+#endif /* HAVE_LIBJPEG */
+ code = psdf_put_image_dict_param(plist, pname, &params->Dict,
+ template, put_params, mem);
+ if (code < 0)
+ ecode = code;
+ }
+ ecode = psdf_put_bool_param(plist, pnames->Downsample,
+ &params->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,
+ &params->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,
+ &params->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",
+ &params.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",
+ &params.CompressPages, ecode);
+ switch (code = param_read_long(plist, (param_name = "ImageMemory"), &params.ImageMemory)) {
+ default:
+ ecode = code;
+ param_signal_error(plist, param_name, ecode);
+ case 0:
+ case 1:
+ break;
+ }
+ ecode = psdf_put_bool_param(plist, "LZWEncodePages",
+ &params.LZWEncodePages, ecode);
+ ecode = psdf_put_bool_param(plist, "PreserveHalftoneInfo",
+ &params.PreserveHalftoneInfo, ecode);
+ ecode = psdf_put_bool_param(plist, "PreserveOPIComments",
+ &params.PreserveOPIComments, ecode);
+ ecode = psdf_put_bool_param(plist, "PreserveOverprintSettings",
+ &params.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;
+ }
+#ifdef HAVE_LIBZ
+ ecode = psdf_put_bool_param(plist, "UseFlateCompression",
+ &params.UseFlateCompression, ecode);
+#endif /* HAVE_LIBZ */
+
+ /* Color sampled image parameters */
+
+ ecode = psdf_put_image_params(pdev, plist, &Color_names, Poly_filters,
+ &params.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",
+ &params.ConvertCMYKImagesToRGB, ecode);
+ ecode = psdf_put_bool_param(plist, "ConvertImagesToIndexed",
+ &params.ConvertImagesToIndexed, ecode);
+
+ /* Gray sampled image parameters */
+
+ ecode = psdf_put_image_params(pdev, plist, &Gray_names, Poly_filters,
+ &params.GrayImage, ecode);
+
+ /* Mono sampled image parameters */
+
+ ecode = psdf_put_image_params(pdev, plist, &Mono_names, Mono_filters,
+ &params.MonoImage, ecode);
+
+ /* Font embedding parameters */
+
+ ecode = psdf_put_embed_param(plist, "~AlwaysEmbed",
+ &params.AlwaysEmbed, ecode);
+ ecode = psdf_put_embed_param(plist, "~NeverEmbed",
+ &params.NeverEmbed, ecode);
+ ecode = psdf_put_bool_param(plist, "EmbedAllFonts",
+ &params.EmbedAllFonts, ecode);
+ ecode = psdf_put_bool_param(plist, "SubsetFonts",
+ &params.SubsetFonts, ecode);
+ ecode = psdf_put_int_param(plist, "MaxSubsetPct",
+ &params.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 000000000..da128b5b7
--- /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 000000000..772c1ff53
--- /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.h b/pstoraster/gdevpstr.h
new file mode 100644
index 000000000..12156c39a
--- /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/gdevpxop.h b/pstoraster/gdevpxop.h
new file mode 100644
index 000000000..9b61a01e0
--- /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 000000000..80adbb7e8
--- /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 000000000..f4a2aebb4
--- /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 000000000..a8f308bff
--- /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 <stdio.h>
+
+/* 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 000000000..5df931e78
--- /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 000000000..39aa8c4aa
--- /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 000000000..fbf997f32
--- /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 000000000..49c50ae8a
--- /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 000000000..0163cf5a2
--- /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 000000000..aa128faab
--- /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 000000000..567d5be0c
--- /dev/null
+++ b/pstoraster/gp_unifs.c
@@ -0,0 +1,424 @@
+/*Copyright 1993-2002 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 <sys/param.h> /* for MAXPATHLEN */
+#include <cups/cups.h>
+
+/* 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
+
+/* ------ 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)
+{
+ int fd; /* File descriptor for temp file */
+
+
+ if ((fd = cupsTempFd(fname, gp_file_name_sizeof)) < 0)
+ return (NULL);
+ else
+ return (fdopen(fd, 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 000000000..e705af635
--- /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
+ * <stdlib.h> 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 <stdlib.h> /* 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 000000000..aaaf2b734
--- /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 000000000..61b75c388
--- /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 000000000..48049a536
--- /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 000000000..f5ff8a373
--- /dev/null
+++ b/pstoraster/gs_btokn.ps
@@ -0,0 +1,313 @@
+% Copyright 1993-2001 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 1605 2001-03-02 22:34:21Z andy $
+% 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> <obj> -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 { % <top_length> <total_length> <string8> .bosheader
+ % <string4|8>
+ 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 % <file> <tag> <array> .writeobjects -
+ {
+ mark exch
+
+ % Count the space required for refs and strings.
+ dup length 0 3 -1 roll
+ % Stack: <file> <tag> -mark- <#refs> <#chars> <array>
+
+ dup 4 1 roll
+ { dup type //cntdict exch get exec
+ } forall
+
+ % Write the header.
+ % Stack: <file> <tag> -mark- <array1> ... <array|dictN> <#refs> <#chars>
+ counttomark 3 add -2 roll 4 1 roll
+ % Stack: -mark- <array1> ... <array|dictN> <tag> <#refs> <#chars> <file>
+ 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- <array1> ... <array|dictN> <tag> <file> <ref#> <char#>
+
+ 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- <array1> ... <array|dictN> <file>
+
+ 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- <file>
+
+ pop pop
+
+ } odef
+currentdict /cntdict .undef
+currentdict /w2dict .undef
+
+%%%% MRS - stderr instead of stdout, which is used for output...
+/printobject { % <obj> <tag> printobject -
+ (%stderr) (w) file 2 index 2 index writeobject pop pop
+} odef
+/writeobject { % <file> <obj> <tag> 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 000000000..5d4ada0e4
--- /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 % <fontname> <fontdict> registerfont <font>
+ { 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 000000000..515fe5d08
--- /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 1159 2000-06-26 15:50:18Z 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.
+
+100 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 { % <n> advance -
+ f cff eq { /pos pos 3 -1 roll add store } { pop } ifelse
+} def
+/next { % - next <byte>
+ f read { 1 advance } if
+} def
+/nextstring { % <length> nextstring <string>
+ dup 0 eq {
+ pop ()
+ } {
+ string f exch readstring pop dup length advance
+ } ifelse
+} def
+/card8 % - card8 <card8>
+ /next load
+def
+/card16 { % - card16 <card16>
+ card8 8 bitshift card8 add
+} def
+/offset { % <offsize> offset <offset>
+ 0 exch { 8 bitshift next add } repeat
+} def
+/sid % - <sid> sid
+ /card16 load
+def
+/Index { % - Index <array>
+ 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 <num1> ... <op#> (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 { % <index> <char> tokenput <index+1>
+ 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 <float>
+ 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 { % <opsdict> Dict -
+ /opdict exch store {
+ mark tokens opdict exch .knownget { exec } if cleartomark
+ } loop cleartomark
+} def
+/idstring { % <sid> idstring <string|name>
+ dup 391 lt { StandardStrings } { 391 sub strings } ifelse exch get
+} def
+/idname { % <sid> idname <name>
+ idstring dup type /nametype ne { cvn } if
+} def
+
+% ------ Top dictionary ------ %
+
+/offput { % <offset> <proc> offput -
+ currentdict exch aload length 1 add packedarray cvx
+ offsets 3 1 roll put
+} def
+/queueput { % <font> <proc> 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 { % <value> <key> <dict> xxput -
+ 3 1 roll exch put
+} def
+/putfi { % <value> <key> putfi -
+ FontInfo xxput
+} def
+/xdef { % <value> <key> 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 { % <font> 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 { % <font> queuecharset -
+ { readcharset } queueput
+} def
+/readcharset { % <data> <font> 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 { % <font> queueEncoding -
+ { readEncoding } queueput
+} def
+/readEncoding { % <data> <font> 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- <num1> ... deltarray <num1'> ...
+ 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 { % <font> <size> 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 { % <resname> <nbytes> StartData -
+ currentfile exch () /SubFileDecode filter ReadData
+} def
+/ReadData { % <resname> <file> 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 000000000..f7f926502
--- /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)> <datalength> 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 % <file> <count> .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 % <pos> <string> <file> .binaryreadstring <string>
+ { dup 4 -1 roll DataOffset add setfileposition exch readstring pop
+ } bind def
+/.hexreadstring % <pos> <string> <file> .hexreadstring <string>
+{ % 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 % <pos> <string> .vmreadstring <vmstring>
+{ GlyphData .stringsreadstring
+} bind def
+/.stringsreadstring % <pos> <string> <strings> .stringsreadstring
+ % <vmstring>
+{ 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 % <bytes> .cvbsi <int>
+{ 0 exch { exch 8 bitshift add } forall
+} bind def
+
+% Read an integer from binary data.
+/.readint % <pos> <nbytes> .readint <int>
+{ 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 { % <cid> .readglyphdata <subfont> <string|null>
+ 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 { % <Subrs> <start> .readsubrs <Subrs>
+ 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 { % <cidfont> <cid> %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 { % <cidfont> <cid> %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 { % <name> <fontdict> .buildcidfont
+ % <name> <cidfont>
+ 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 000000000..e2ce96d65
--- /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 { % <name> <cmap|cmapname> <fonts> composefont <font>
+ 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 % <count> begincodespacerange -
+ { pop mark
+ } bind def
+/endcodespacerange % <code_lo> <code_hi> ... endcodespacerange -
+ { counttomark 2 idiv
+ { .CodeMaps { 3 copy .addcodespacerange pop } forall pop pop
+ } repeat pop
+ } bind def
+
+/.addcodespacerange % <code_lo> <code_hi> <map> .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 % <map> .endmap <map>
+ { dup type /arraytype eq { dup { .endmap exch } forall astore readonly } if
+ } bind def
+
+/usecmap % <CMap_name> usecmap -
+ { /CMap findresource
+ dup length dict .copydict
+ currentdict end exch .copydict begin
+ } bind def
+
+% ------ Rearranged font operators ------ %
+
+/beginrearrangedfont % <font_name> <font*> beginrearrangedfont -
+ { (NOT IMPLEMENTED YET.\n) print flush
+ } bind def
+/endrearrangedfont % - endrearrangedfont -
+ { (NOT IMPLEMENTED YET.\n) print flush
+ } bind def
+
+/usefont % <fontID> usefont -
+ { (NOT IMPLEMENTED YET.\n) print flush
+ } bind def
+
+/beginusematrix % <fontID> beginusematrix -
+ { (NOT IMPLEMENTED YET.\n) print flush
+ } bind def
+/endusematrix % <matrix> endusematrix -
+ { (NOT IMPLEMENTED YET.\n) print flush
+ } bind def
+
+% ------ Character name/code selector operators ------ %
+
+/beginbfchar % <count> beginbfchar -
+ { pop mark
+ } bind def
+/endbfchar % <code> <to_code|charname> ... endbfchar
+ { 0 .getmap .endmapchar 0 .putmap
+ } bind def
+
+/beginbfrange % <count> beginbfrange -
+ { pop mark
+ } bind def
+/endbfrange % <code_lo> <code_hi> <to_code|(charname*)> ...
+ % endbfrange -
+ { 0 .getmap counttomark 3 idiv { .addbfrange } repeat 0 .putmap pop
+ } bind def
+
+/.addbfrange % <code_lo> <code_hi> <to_code|(charname*)> <map>
+ % .addbfrange <map>
+ { 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 % <count> begincidchar -
+ { pop mark
+ } bind def
+/endcidchar % <code> <cid> ... endcidchar -
+ { 0 .getmap .endmapchar 0 .putmap
+ } bind def
+
+/begincidrange % <count> begincidrange -
+ { pop mark
+ } bind def
+/endcidrange % <code_lo> <code_hi> <cid_base> ... endcidrange -
+ { 0 .getmap counttomark 3 idiv { { 1 add } exch .addmaprange exch pop } repeat
+ 0 .putmap pop
+ } bind def
+
+/.endmapchar % -mark- <code> <value> ... <map> .endmapchar -
+ { counttomark 2 idiv
+ { 2 index 3 1 roll { } exch .addmaprange exch pop
+ } repeat exch pop
+ } bind def
+
+/.addmaprange % <code_lo> <code_hi> <value_base> <next_proc> <map>
+ % .addcidrange <value_next> <map>
+ { % 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 % <count> beginnotdefchar -
+ { pop mark
+ } bind def
+/endnotdefchar % <code> <cid> ... endnotdefchar -
+ { counttomark 2 idiv { 1 index exch .addnotdefrange } repeat pop
+ } bind def
+
+/beginnotdefrange % <count> beginnotdefrange -
+ { pop mark
+ } bind def
+/endnotdefrange % <code_lo> <code_hi> <cid> ... endnotdefrange -
+ { counttomark 3 idiv { .addnotdefrange } repeat pop
+ } bind def
+
+/.addnotdefrange % <code_lo> <code_hi> <cid_base> .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 000000000..7293e0923
--- /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 <arg> 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 % <file> runjob -
+ { end % cmddict
+ /startjob where { pop false () startjob pop }
+ run
+ //cmddict begin
+ } bind def
+/runfilejob % <filename> runfilejob -
+ { findlibfile { exch pop } { (r) file } runjob
+ } bind def
+
+% Expand arguments. Free variables: expand@.
+/expandarg % <string> expandarg <args...>
+ { 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 % <file> expandargfile <args...>
+ { [ 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 <x>;
+% switches without arguments are defined as -<x>.
+
+% 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 000000000..b31a39228
--- /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 000000000..eedd98082
--- /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
+% <index|charname> <length> <readproc> cskip_C
+% to skip over each character definition and return the file position instead.
+% This substitutes for the procedure
+% <index|charname> <length> 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 % <charname> <fileposandlength> 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 % <charstring> seac_C <achar> <bchar> ..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
+% <font> /CharStrings <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 % <font> <code|name> 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 000000000..2d2573ff7
--- /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:
+%
+% <x> <y> <width> <height> <matrix> .sizeimagebox
+% <dev_x> <dev_y> <dev_width> <dev_height> <matrix>
+%
+% - .sizeimageparams <bits/sample> <multiproc> <ncolors>
+%
+% <device> <x> <y> <width> <max_height> <alpha?> <std_depth|null>
+% <string> .getbitsrect <height> <substring>
+%
+% 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 { % <x> <y> <width> <height> <proc> [... <procN-1>]
+ % <string> <alpha?> 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 { % <x> <y> <width> <height> <matrix> sizeimage
+ % <devwidth> <devheight> <bits/sample> <matrix>
+ % <multiproc> <ncolors>
+ .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 000000000..354d8155b
--- /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 { % <name> <dict> .copylocal <name> <dict'>
+ % 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 { % <mark> <obj1> ... <objN> <proc>
+ % <stdin|null> <stdout|null>
+ % localfork <context>
+ .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 { % <mark> <obj1> ... <objN> <proc> fork <context>
+ .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 { % <x> <y> sethalftonephase -
+ -1 2 index 2 index .setscreenphase pop pop
+} odef
+/currenthalftonephase { % - currenthalftonephase <x> <y>
+ 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 <dict>
+ 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 <x> <y>
+ currentdevice //.wtdict .getdeviceparams exch pop exch pop aload pop
+} odef
+currentdict /.wtdict .undef
+
+% ------ View clipping ------ %
+
+/rectviewclip { % <x> <y> <width> <height> rectviewclip -
+ % <numarray|numstring> rectviewclip -
+ newpath .rectappend viewclip
+} odef
diff --git a/pstoraster/gs_dps1.ps b/pstoraster/gs_dps1.ps
new file mode 100644
index 000000000..f343b571a
--- /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 % <bool> .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 % <fontname> <size> 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 % <fontname> 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 % <save> 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 000000000..e375505ab
--- /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 <dict>
+ { 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 % <dict> <type> <keys> <keysRGBV>
+ { 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 { % <dict> 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 % <freq> <angle> <dict> .fix...screen
+ % <freq> <angle> <dict> <dict'>
+ { 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 % <ignore*2> <dict> setscreen -
+ { dup type /dicttype eq
+ { .fixsethalftonescreen sethalftone pop pop pop }
+ { //setscreen }
+ ifelse
+ } odef
+/setcolorscreen % <ignore*11> <dict> 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 % <dict> .fix... <freq> <angle> <proc>
+ { dup /HalftoneType get 1 eq
+ { dup /Frequency get 1 index /Angle get }
+ { 60 0 }
+ ifelse 3 2 roll
+ } bind def
+/currentscreen % - currentscreen 60 0 <dict>
+ { .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 <dict>)*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 { % <index> <value> 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 { % <index> execuserobject -
+ .UserObjects get 1 index get exch pop exec
+} odef
+/undefineuserobject { % <index> undefineuserobject -
+ .UserObjects get 1 index null put pop
+} odef
+
+% ------ Cache control ------ %
+
+% Dummy definitions for cache control operators
+
+/ucachestatus { % - ucachestatus -mark- ? ? ? ? <size>
+ mark 0 0 0 0 .userdict /.ucachesize .knownget not { 0 } if
+} odef
+/setucacheparams { % -mark- ... <size> 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 000000000..fcccb3e33
--- /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 <C5D0D3C6> 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 000000000..17dfbef74
--- /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 000000000..99db47217
--- /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 1686 2001-04-23 19:52:31Z 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 % <path> .pathlist <dir1|file1> ...
+ { { 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 % <file> .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: <file> 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 % <fontname> <file|alias> .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 % <file> <key> .findfontvalue <value> true
+ % <file> <key> .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 % <string> .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 % <dir.../base.extn> .basename <base> <extn>
+ { { (/) 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 % <dirname> .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: <fontcount> <scancount> <filecount> <filename>
+ exch 1 add exch % increment filecount
+ dup .splitfilename .lowerstring
+ % stack: <fontcount> <scancount> <filecount+1> <filename>
+ % <BASE> <ext>
+ .scanfontskip exch known exch .scanfontdict exch known or
+ { pop
+ % stack: <fontcount> <scancount> <filecount+1>
+ }
+ { 3 -1 roll 1 add 3 1 roll
+ % stack: <fontcount> <scancount+1> <filecount+1> <filename>
+ dup (r) { file } .internalstopped
+ { pop pop null ()
+ % stack: <fontcount> <scancount+1> <filecount+1> <filename>
+ % 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: <fontcount> <scancount+1> <filecount+1>
+ % <filename> <file> <header>
+ }
+ 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: <fontcount> <scancount+1> <filecount+1> <filename>
+ % <file>
+ dup 0 setfileposition .findfontname
+ { dup Fontmap exch known
+ { pop pop
+ }
+ { exch copystring exch
+ DEBUG { dup =only (\n) print 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 % <name> <font> .aliasfont <newFont>
+ { .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 % <fontname> .substitutefont <altname>
+ { % 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 { % <name> <font> definefont <font>
+ dup /FontMatrix known {
+ //definefont
+ } {
+ 2 copy /FontName get findfont //definefont exch pop exch pop
+ } ifelse
+} bind odef
+
+/scalefont { % <font> <scale> scalefont <font>
+ 1 index /FontMatrix known {
+ //scalefont
+ } {
+ 1 index /FontName get findfont 1 index //scalefont
+ exch pop exch pop
+ } ifelse
+} bind odef
+
+/makefont { % <font> <matrix> makefont <font>
+ 1 index /FontMatrix known {
+ //makefont
+ } {
+ 1 index /FontName get findfont 1 index //makefont
+ exch pop exch pop
+ } ifelse
+} bind odef
+
+/setfont { % <font> 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- <alias1> ... <name> .checkalias <<same>>
+ { 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 % <fontdir> <fontname> .fontknownget <font> true
+ % <fontdir> <fontname> .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 % <fontname> .dofindfont <font>
+ { { .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 % <fontname> .tryfindfont <font> true
+ % <fontname> .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 % <filename> .loadfontloop <font> true
+ % <filename> .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 % <fontdict> <paramdict> .makemodifiedfont <fontdict'>
+ { 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 % <fontdict> <paramdict> .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 000000000..fd40a567a
--- /dev/null
+++ b/pstoraster/gs_init.ps
@@ -0,0 +1,1521 @@
+% Copyright 1993-2001 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 1605 2001-03-02 22:34:21Z andy $
+% Initialization file for the interpreter.
+% When this is run, systemdict is still writable.
+
+% Comment lines of the form
+% %% Replace <n> <file(s)>
+% indicate places where the next <n> lines should be replaced by
+% the contents of <file(s)>, 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.
+/DEBUG true 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 % <string> .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 { % <name> <proc> obind <name> <oper>
+ 1 index exch .makeoperator
+} .bind def
+/odef { % <name> <proc> 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 { % <key> <value> .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 { % <name> .systemvar <value>
+ //systemdict exch get
+} .bind odef
+/.userdict { % - .userdict <dict>
+ /userdict .systemvar
+} .bind odef
+/.uservar { % <name> .uservar <value>
+ .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 { % <device> <y> <string> copyscanlines <substr>
+ 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 <return> 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:
+% <lit-file|fileproc> .runexec1 <lit-file|fileproc> .runexec2
+/.runexec1 { % <file|fileproc> .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 { % <continue> <file|fileproc> .runexec2 -
+ exch {
+ .runexec
+ } {
+ dup type /filetype ne { cvx exec } if
+ closefile
+ } ifelse
+} bind def
+/.runexec { % <file|fileproc> .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 <return> 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 % <fromdict> <todict> .copydict <todict>
+ { 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 % <object> <errorname> 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 % <device> <propname> gsgetdeviceprop <value>
+ { 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 { % <obj> .execute <stopped>
+ stopped $error /newerror get and
+ { handleerror flush true } { false } ifelse
+} bind def
+/execute { % <obj> execute -
+ .execute pop
+} odef
+% Define an execute analogue of runlibfile0.
+/execute0 { % <obj> 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 % <command> <errorname> .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 % <command> <errorname> .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.
+ % <heading> <==flag> <override-name> <stackname> proc
+ {
+ currentdict exch .knownget % stackname defined in $error?
+ {
+ 4 1 roll % stack: <stack> <head> <==flag> <over>
+ errordict exch .knownget % overridename defined?
+ {
+ exch pop exch pop exec % call override with <stack>
+ }
+ {
+ exch print exch % print heading. stack <==flag> <stack>
+ 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 { % <index> <array> .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: <pagedevice> <pagedevice> /Policies
+1 index /InputAttributes
+2 copy get dup length dict .copydict
+ % Stack: <pagedevice> <pagedevice> /Policies <pagedevice>
+ % /InputAttributes <inputattrs'>
+dup 0 2 copy get dup length dict .copydict
+ % Stack: <pagedevice> <pagedevice> /Policies <pagedevice>
+ % /InputAttributes <inputattrs'> <inputattrs'> 0 <attrs0'>
+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: <pagedevice> <pagedevice> /Policies
+2 copy get dup length dict .copydict
+ % Stack: <pagedevice> <pagedevice> /Policies <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 000000000..607d9714f
--- /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 000000000..ee4272dd4
--- /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 % <fontname> T1NF <font>
+{
+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 % <fontname> T0NF <font>
+{
+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 % <fontname> CompNF <font>
+{
+/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 % <charstring> <(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 000000000..e418ea3aa
--- /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_lev2.ps b/pstoraster/gs_lev2.ps
new file mode 100644
index 000000000..94c490f8d
--- /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 { % <newdict> <opname> <checkdict>
+ % .checksetparams <newdict>
+ 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 { % <value> .copyparam <value'>
+ 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 { % <name> getuserparam <value>
+ /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 { % <name> <value> .definepsuserparam -
+ psuserparams 3 copy pop put
+ userparams 3 1 roll put
+} .bind def
+end
+/currentuserparams { % - currentuserparams <dict>
+ /userparams .systemvar dup length dict .copydict
+} odef
+/setuserparams { % <dict> 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 { % <save> 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 { % <name> getsystemparam <value>
+ //pssystemparams 1 index .knownget { exch pop } { .getsystemparam } ifelse
+} odef
+end
+/currentsystemparams { % - currentsystemparams <dict>
+ mark .currentsystemparams //pssystemparams { } forall .dicttomark
+} odef
+/setsystemparams { % <dict> 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- <key1> <value1> ... >> <dict>
+ /.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 <bool>
+ /currentshared load def
+/gcheck % <obj> gcheck <bool>
+ /scheck load def
+/setglobal % <bool> 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 { % <int> setvmthreshold -
+ mark /VMThreshold 2 index .dicttomark setuserparams pop
+} odef
+/vmreclaim { % <int> vmreclaim -
+ dup 0 gt {
+ .vmreclaim
+ } {
+ mark /VMReclaim 2 index .dicttomark setuserparams pop
+ } ifelse
+} odef
+-1 setvmthreshold
+
+% ------ IODevices ------ %
+
+/.getdevparams where {
+ pop /currentdevparams { % <iodevice> currentdevparams <dict>
+ .getdevparams .dicttomark
+ } odef
+} if
+/.putdevparams where {
+ pop /setdevparams { % <iodevice> <dict> 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 { % <exit_bool> <password_level>
+ % .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 { % <exit_bool> <password> <finish_proc>
+ % .startjob <ok_bool>
+ 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 { % <exit_bool> <password> startjob <ok_bool>
+ { .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 { % <password> 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:
+% <colorspace> proc <colorspace'|null>
+/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 <array>
+ .currentcolorspace dup type /integertype eq {
+ //.devcs exch 1 getinterval
+ } if
+} odef
+currentdict /.devcs .undef
+
+/setcolorspace { % <name|array> 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 { % <intentname> findcolorrendering
+ % <crdname> <found>
+ /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 <name>
+ currentpagedevice dup /PageDeviceName .knownget {
+ exch pop
+ } {
+ pop /none
+ } ifelse
+} bind def
+
+/GetHalftoneName { % - GetHalftoneName <name>
+ currenthalftone /HalftoneName .knownget not { /none } if
+} bind def
+
+/GetSubstituteCRD { % <intentname> GetSubstituteCRD <crdname>
+ 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 { % <crd> 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 { % <form> execform -
+ gsave {
+ dup /FormType get //.formtypes exch get exec
+ } stopped grestore { stop } if
+} odef
+
+/.patterntypes 5 dict
+ dup 1 /.buildpattern1 load put
+def
+
+/makepattern { % <proto_dict> <matrix> makepattern <pattern>
+ //.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 { % [<comp1> ...] <pattern> 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 000000000..acf701ec6
--- /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 { % <proc> bind <proc'>
+ //.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:
+%
+% <dict> <Width> <Height> <Thresholds> <bits> <shift> .setstriphalftone -
+%
+% <dict> 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 { % <source> <dest> <count> .copybytes -
+ { 1 index read not { /sethalftone load /rangecheck signalerror exit } if
+ 1 index exch write
+ } repeat pop pop
+} bind def
+
+/.copythresholds { % <dict> <Width> <Height> <bits> .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 { % <dict> .sethalftone6 -
+ % Keys: Width, Height, Thresholds, T'Function
+ dup /Width get 1 index /Height get
+ 8 .copythresholds
+} odef
+
+/.copythresholds2 { % <dict> <Width> <Height> <Width2> <Height2>
+ % <bits> .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 { % <dest> <width> <B> <N> <R> <stride> <offset>
+ % <source> .copyshifted -
+% Copy N blocks of <width> x B bytes from <source>.
+% 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 { % <dict> .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 { % <dict> .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 { % <shadingdict> .buildshading <shading>
+ % 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 { % <template> <matrix> .buildpattern2
+ % <template> <pattern>
+ 1 index /Shading get .buildshading .buildshadingpattern
+} bind def
+
+.patterntypes
+ 2 /.buildpattern2 load put
+
+/shfill { % <shadingdict> shfill -
+ % Currently, .shfill requires that the color space
+ % in the pattern be the current color space.
+ dup .buildshading
+ 1 index /ColorSpace get
+ gsave { setcolorspace .shfill } stopped grestore { stop } if
+ pop
+} odef
+
+% Establish an arbitrary initial smoothness value.
+1 64 div setsmoothness
+
+% ------ Trapping ------ %
+
+% The PostScript-level trapping parameters are maintained in userdict,
+% and explicitly reinstalled upon restore.
+
+/Trapping mark
+
+/settrapparams dup { % <paramdict> settrapparams -
+ /.trapparams .uservar dup length dict .copydict
+ dup 2 index {
+ % Stack: paramdict olddict olddict key value
+ 2 index 2 index known { put dup } { pop pop } ifelse
+ } forall pop
+ dup .settrapparams % Let the operator check parameter validity.
+ .userdict /.trapparams 3 -1 roll put pop
+} bind .makeoperator
+
+/.copyparams { % <obj> .copyparams <obj'>
+ dup type /dicttype eq {
+ dup length dict .copydict
+ dup {
+ .copyparams 3 copy put pop pop
+ } forall
+ } {
+ dup type /arraytype eq {
+ [ exch { .copyparams } forall ]
+ } if
+ } ifelse
+} odef
+
+/currenttrapparams dup { % - currenttrapparams <paramdict>
+ /.trapparams .uservar .copyparams
+} bind .makeoperator
+
+/settrapzone dup { % - settrapzone -
+ % ****** DUMMY ******
+ newpath
+} bind .makeoperator
+
+% Define initial (dummy) trapping parameters.
+% These values are mostly complete guesses.
+userdict /.trapparams mark
+ /BlackColorLimit 1.0
+ /BlackDensityLimit 1.0
+ /BlackWidth 1.0
+ /ColorantZoneDetails 0 dict
+ /Enabled true
+ /HalftoneName null
+ /ImageInternalTrapping false
+ /ImageResolution 1
+ /ImageToObjectTrapping true
+ /ImageTrapPlacement /Center
+ /SlidingTrapLimit 1.0
+ /StepLimit 1.0
+ /TrapColorScaling 0.0
+ /TrapSetName null
+ /TrapWidth 1.0
+.dicttomark readonly put
+
+.dicttomark /ProcSet defineresource pop
+
+% ------ Miscellaneous ------ %
+
+% Define additional user and system parameters.
+psuserparams begin
+ /HalftoneMode 0 def
+ /MaxSuperScreen 1016 def
+end
+pssystemparams begin % read-only, so use .forcedef
+ /MaxDisplayAndSourceList 160000 .forcedef
+end
+
+% Define the IdiomSet, InkParams, and TrapParams resource categories.
+{ /IdiomSet /InkParams /TrapParams } {
+ /Generic /Category findresource dup maxlength 3 add dict .copydict begin
+ /InstanceType /dicttype def
+ currentdict end /Category defineresource pop
+} forall
+
+% Define the ReusableStreamDecode filter.
+% ****** DOESN'T WORK FOR CONTENTS >64K ******
+/.reusablestreamdecode { % <source> <dict> .reusablestreamdecode <file>
+ % <source> .reusablestreamdecode <file>
+ % Collect the filter parameters.
+ dup type /dicttype eq { 2 copy } { dup 0 dict } ifelse
+ dup .rsdparams
+ % Construct the filter pipeline.
+ % The very first filter should use the value of CloseSource
+ % from the RSD dictionary; all the others should have
+ % CloseSource = true.
+ % Stack: source dict filters parms
+ 2 index /CloseSource .knownget not { false } if 5 -1 roll
+ % Stack: dict filters parms CloseSource source
+ 0 1 5 index length 1 sub {
+ 4 index 1 index get
+ % Stack: dict filters parms CloseSource source index filtname
+ 4 index null eq {
+ 0 dict
+ } {
+ 4 index 2 index get dup null eq { pop } if
+ } ifelse
+ 3 -1 roll pop filter
+ exch pop true exch % set CloseSource for further filters
+ } for
+ % See if we can create the filter directly.
+ % Stack: dict filters parms CloseSource file
+ null 2 index { .reusablestream } .internalstopped {
+ pop pop
+ % No luck. Read the entire contents of the stream now.
+ 10 dict exch {
+ % Stack: dict filters parms CloseSource contdict file
+ dup 1000 string readstring
+ 3 index dup length 4 -1 roll put not { break } if
+ } loop pop
+ % Concatenate the contents into one big string.
+ % Stack: dict filters parms CloseSource contdict
+ 0 1 index { length exch pop add } forall string
+ exch {
+ % Stack: dict filters parms CloseSource string index substring
+ exch 1000 mul exch 2 index 3 1 roll putinterval
+ } forall
+ % Now create the stream on the string.
+ null 3 -1 roll .reusablestream
+ } if
+ % We created the stream successfully: clean up.
+ 4 { exch pop } repeat
+ dup type /dicttype eq { pop } if pop
+} odef
+filterdict /ReusableStreamDecode /.reusablestreamdecode load put
+
+/languagelevel 3 def
+% When running in LanguageLevel 3 mode, this interpreter is supposed to be
+% compatible with Adobe version 3010.
+/version (3010) readonly def
+
+.setlanguagelevel
+
+end % ll3dict
diff --git a/pstoraster/gs_mex_e.ps b/pstoraster/gs_mex_e.ps
new file mode 100644
index 000000000..7724de22d
--- /dev/null
+++ b/pstoraster/gs_mex_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_mex_e.ps 956 2000-03-08 23:15:43Z mike $
+% Define the MacExpert encoding vector.
+/currentglobal where
+ { pop currentglobal { setglobal } true setglobal }
+ { { } }
+ifelse
+/MacExpertEncoding
+% \00x
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+% \04x
+ /space /exclamsmall /Hungarumlautsmall /centoldstyle /dollaroldstyle /dollarsuperior /ampersandsmall /Acutesmall
+ /parenleftsuperior /parenrightsuperior /twodotenleader /onedotenleader /comma /hyphen /period /fraction
+ /zerooldstyle /oneoldstyle /twooldstyle /threeoldstyle /fouroldstyle /fiveoldstyle /sixoldstyle /sevenoldstyle
+ /eightoldstyle /nineoldstyle /colon /semicolon /.notdef /threequartersemdash /.notdef /questionsmall
+% \10x
+ /.notdef /.notdef /.notdef /.notdef /Ethsmall /.notdef /.notdef /onequarter
+ /onehalf /threequarters /oneeighth /threeeighths /fiveeighths /seveneighths /onethird /twothirds
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /ff /fi
+ /fl /ffi /ffl /parenleftinferior /.notdef /parenrightinferior /Circumflexsmall /hypheninferior
+% \14x
+ /Gravesmall /Asmall /Bsmall /Csmall /Dsmall /Esmall /Fsmall /Gsmall
+ /Hsmall /Ismall /Jsmall /Ksmall /Lsmall /Msmall /Nsmall /Osmall
+ /Psmall /Qsmall /Rsmall /Ssmall /Tsmall /Usmall /Vsmall /Wsmall
+ /Xsmall /Ysmall /Zsmall /colonmonetary /onefitted /rupiah /Tildesmall /.notdef
+% \20x
+ /.notdef /asuperior /centsuperior /.notdef /.notdef /.notdef /.notdef /Aacutesmall
+ /Agravesmall /Acircumflexsmall /Adieresissmall /Atildesmall /Aringsmall /Ccedillasmall /Eacutesmall /Egravesmall
+ /Ecircumflexsmall /Edieresissmall /Iacutesmall /Igravesmall /Icircumflexsmall /Idieresissmall /Ntildesmall /Oacutesmall
+ /Ogravesmall /Ocircumflexsmall /Odieresissmall /Otildesmall /Uacutesmall /Ugravesmall /Ucircumflexsmall /Udieresissmall
+% \24x
+ /.notdef /eightsuperior /fourinferior /threeinferior /sixinferior /eightinferior /seveninferior /Scaronsmall
+ /.notdef /centinferior /twoinferior /.notdef /Dieresissmall /.notdef /Caronsmall /osuperior
+ /fiveinferior /.notdef /commainferior /periodinferior /Yacutesmall /.notdef /dollarinferior /.notdef
+ /.notdef /Thornsmall /.notdef /nineinferior /zeroinferior /Zcaronsmall /AEsmall /Oslashsmall
+% \30x
+ /questiondownsmall /oneinferior /Lslashsmall /.notdef /.notdef /.notdef /.notdef /.notdef
+ /.notdef /Cedillasmall /.notdef /.notdef /.notdef /.notdef /.notdef /OEsmall
+ /figuredash /hyphensuperior /.notdef /.notdef /.notdef /.notdef /exclamdownsmall /.notdef
+ /Ydieresissmall /.notdef /onesuperior /twosuperior /threesuperior /foursuperior /fivesuperior /sixsuperior
+% \34x
+ /sevensuperior /ninesuperior /zerosuperior /.notdef /esuperior /rsuperior /tsuperior /.notdef
+ /.notdef /isuperior /ssuperior /dsuperior /.notdef /.notdef /.notdef /.notdef
+ /.notdef /lsuperior /Ogoneksmall /Brevesmall /Macronsmall /bsuperior /nsuperior /msuperior
+ /commasuperior /periodsuperior /Dotaccentsmall /Ringsmall /.notdef /.notdef /.notdef /.notdef
+256 packedarray .defineencoding
+exec
diff --git a/pstoraster/gs_mro_e.ps b/pstoraster/gs_mro_e.ps
new file mode 100644
index 000000000..87fdf896f
--- /dev/null
+++ b/pstoraster/gs_mro_e.ps
@@ -0,0 +1,65 @@
+% 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_mro_e.ps 956 2000-03-08 23:15:43Z mike $
+% Define the MacRoman encoding vector.
+/currentglobal where
+ { pop currentglobal { setglobal } true setglobal }
+ { { } }
+ifelse
+/MacRomanEncoding
+StandardEncoding 0 39 getinterval aload pop
+ /quotesingle
+StandardEncoding 40 56 getinterval aload pop
+ /grave
+StandardEncoding 97 31 getinterval aload pop
+% \20x
+ /Adieresis /Aring /Ccedilla /Eacute /Ntilde /Odieresis /Udieresis /aacute
+ /agrave /acircumflex /adieresis /atilde /aring /ccedilla /eacute /egrave
+ /ecircumflex /edieresis /iacute /igrave
+ /icircumflex /idieresis /ntilde /oacute
+ /ograve /ocircumflex /odieresis /otilde
+ /uacute /ugrave /ucircumflex /udieresis
+% \24x
+ /dagger /degree /cent /sterling /section /bullet /paragraph /germandbls
+ /registered /copyright /trademark /acute /dieresis /.notdef /AE /Oslash
+ /.notdef /plusminus /.notdef /.notdef /yen /mu /.notdef /.notdef
+ /.notdef /.notdef /.notdef /ordfeminine /ordmasculine /.notdef /ae /oslash
+% \30x
+ /questiondown /exclamdown /logicalnot /.notdef
+ /florin /.notdef /.notdef /guillemotleft
+ /guillemotright /ellipsis /space /Agrave /Atilde /Otilde /OE /oe
+ /endash /emdash /quotedblleft /quotedblright
+ /quoteleft /quoteright /divide /.notdef
+ /ydieresis /Ydieresis /fraction /currency
+ /guilsingleft /guilsingright /fi /fl
+% \34x
+ /daggerdbl /periodcentered /quotesinglbase /quotedblbase
+ /perthousand /Acircumflex /Ecircumflex /Aacute
+ /Edieresis /Egrave /Iacute /Icircumflex
+ /Idieresis /Igrave /Oacute /Ocircumflex
+ /.notdef /Ograve /Uacute /Ucircumflex
+ /Ugrave /dotlessi /circumflex /tilde
+ /macron /breve /dotaccent /ring /cedilla /hungarumlaut /ogonek /caron
+256 packedarray .defineencoding
+exec
diff --git a/pstoraster/gs_pfile.ps b/pstoraster/gs_pfile.ps
new file mode 100644
index 000000000..6720cd935
--- /dev/null
+++ b/pstoraster/gs_pfile.ps
@@ -0,0 +1,135 @@
+% Copyright (C) 1994, 1995 Aladdin Enterprises. All rights reserved.
+%
+% This file is part of GNU Ghostscript.
+%
+% GNU Ghostscript is distributed in the hope that it will be useful, but
+% WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
+% to anyone for the consequences of using it or for whether it serves any
+% particular purpose or works at all, unless he says so in writing. Refer
+% to the GNU General Public License for full details.
+%
+% Everyone is granted permission to copy, modify and redistribute GNU
+% Ghostscript, but only under the conditions described in the GNU General
+% Public License. A copy of this license is supposed to have been given
+% to you along with GNU Ghostscript so you can know your rights and
+% responsibilities. It should be in a file named COPYING. Among other
+% things, the copyright notice and this notice must be preserved on all
+% copies.
+%
+% Aladdin Enterprises 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_pfile.ps 956 2000-03-08 23:15:43Z mike $
+% Runtime support for minimum-space fonts and packed files.
+
+% ****** NOTE: This file must be kept consistent with
+% ****** packfile.ps and wrfont.ps.
+
+% ---------------- Packed file support ---------------- %
+
+% A packed file is the concatenation of several file groups, each of which
+% is the result of compressing several files concatenated together.
+% The packed file begins with a procedure that creates an appropriate
+% decoding filter for each file group, as follows:
+% <group-subfile-filter> -proc- <group-decode-filter>
+% Thus, accessing an individual file requires 4 parameters:
+% the starting address and length of the outer compressed file,
+% and the starting address and length of the inner file.
+/.packedfilefilter % <file> <ostart> <olength> <istart> <ilength>
+ % .packedfilefilter <filter>
+ { 4 index systemdict begin token pop end 6 1 roll
+ % Stack: fproc file ostart olength istart ilength
+ 4 index 5 -1 roll setfileposition
+ % Stack: fproc file olength istart ilength
+ 4 -2 roll () /SubFileDecode filter
+ % Stack: fproc istart ilength ofilter
+ 4 -1 roll exec
+ % Filters don't support setfileposition, so we must skip data
+ % by reading it into a buffer. We rely on the fact that
+ % save/restore don't affect file positions.
+ % Stack: istart ilength dfilter
+ save exch 1000 string
+ % Stack: istart ilength save dfilter scratch
+ 4 index 1 index length idiv { 2 copy readstring pop pop } repeat
+ 2 copy 0 8 -1 roll 2 index length mod getinterval readstring pop pop pop
+ % Stack: ilength save dfilter
+ exch restore exch () /SubFileDecode filter
+ } bind def
+
+% Run a packed library file.
+/.runpackedlibfile % <filename> <ostart> <olength> <istart> <ilength>
+ % .runpackedlibfile
+ { 5 -1 roll findlibfile
+ { exch pop dup 6 2 roll .packedfilefilter
+ currentobjectformat exch 1 setobjectformat run
+ setobjectformat closefile
+ }
+ { 5 1 roll /findlibfile load /undefinedfilename signalerror
+ }
+ ifelse
+ } bind def
+
+% ---------------- Compacted font support ---------------- %
+
+% Compacted fonts written by wrfont.ps depend on the existence and
+% specifications of the procedures and data in this section.
+
+/.compactfontdefault mark
+ /PaintType 0
+ /FontMatrix [0.001 0 0 0.001 0 0] readonly
+ /FontType 1
+ /Encoding StandardEncoding
+.dicttomark readonly def
+
+/.checkexistingfont % <fontname> <uid> <privatesize> <fontsize>
+ % .checkexistingfont
+ % {} (<font> on d-stack)
+ % <fontname> <uid> <privatesize> <fontsize>
+ % .checkexistingfont
+ % -save- --restore-- (<font> on d-stack)
+ { FontDirectory 4 index .knownget
+ { dup /UniqueID .knownget
+ { 4 index eq exch /FontType get 1 eq and }
+ { pop false }
+ ifelse
+ }
+ { false
+ }
+ ifelse
+ { save /restore load 6 2 roll }
+ { {} 5 1 roll }
+ ifelse
+ dict //.compactfontdefault exch .copydict begin
+ dict /Private exch def
+ Private begin
+ /MinFeature {16 16} def
+ /Password 5839 def
+ /UniqueID 1 index def
+ end
+ /UniqueID exch def
+ /FontName exch def
+ } bind def
+
+/.knownEncodings [
+ ISOLatin1Encoding
+ StandardEncoding
+ SymbolEncoding
+] readonly def
+
+/.readCharStrings % <count> <encrypt> .readCharStrings <dict>
+ { exch dup dict dup 3 -1 roll
+ { currentfile token pop dup type /integertype eq
+ { dup -8 bitshift //.knownEncodings exch get exch 255 and get } if
+ currentfile token pop dup type /nametype eq
+ { 2 index exch get
+ }
+ { % Stack: encrypt dict dict key value
+ 4 index { 4330 exch dup .type1encrypt exch pop } if
+ readonly
+ }
+ ifelse put dup
+ }
+ repeat pop exch pop
+ } bind def
diff --git a/pstoraster/gs_res.ps b/pstoraster/gs_res.ps
new file mode 100644
index 000000000..660348803
--- /dev/null
+++ b/pstoraster/gs_res.ps
@@ -0,0 +1,726 @@
+% Copyright (C) 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_res.ps 956 2000-03-08 23:15:43Z mike $
+% Initialization file for Level 2 resource machinery.
+% When this is run, systemdict is still writable,
+% but (almost) everything defined here goes into level2dict.
+
+level2dict begin
+
+(BEGIN RESOURCES) VMDEBUG
+
+% We keep track of (global) instances with another entry in the resource
+% dictionary, an Instances dictionary. For categories with implicit
+% instances, the values in Instances are the same as the keys;
+% for other categories, the values are [instance status size].
+
+% Note that the dictionary that defines a resource category is stored
+% in global memory. The PostScript manual says that each category must
+% manage global and local instances separately. However, objects in
+% global memory other than systemdict can't reference objects in local memory.
+% This means that the resource category dictionary, which would otherwise be
+% the obvious place to keep track of the instances, can't be used to keep
+% track of local instances. Instead, we define a dictionary in local VM
+% called localinstancedict, in which the key is the category name and
+% the value is the analogue of Instances for local instances.
+
+% We don't currently implement automatic resource unloading.
+% When and if we do, it should be hooked to the garbage collector.
+% However, Ed Taft of Adobe says their interpreters don't implement this
+% either, so we aren't going to worry about it for a while.
+
+currentglobal false setglobal systemdict begin
+ /localinstancedict 5 dict
+ .forcedef % localinstancedict is local, systemdict is global
+end true setglobal
+/.emptydict 0 dict readonly def
+setglobal
+
+% Resource category dictionaries have the following keys (those marked with
+% * are optional):
+% Standard, defined in the Red Book:
+% Category (name)
+% *InstanceType (name)
+% DefineResource
+% <key> <instance> DefineResource <instance>
+% UndefineResource
+% <key> UndefineResource -
+% FindResource
+% <key> FindResource <instance>
+% ResourceStatus
+% <key> ResourceStatus <status> <size> true
+% <key> ResourceStatus false
+% ResourceForAll
+% <template> <proc> <scratch> ResourceForAll -
+% *ResourceFileName
+% <key> <scratch> ResourceFileName <filename>
+% Additional, specific to our implementation:
+% Instances (dictionary)
+% .LocalInstances
+% - .LocalInstances <dict>
+% .GetInstance
+% <key> .GetInstance <instance> -true-
+% <key> .GetInstance -false-
+% .CheckResource
+% <key> <value> .CheckResource <key> <value> <ok>
+% (or may give an error if not OK)
+% .DoLoadResource
+% <key> .DoLoadResource - (may give an error)
+% .LoadResource
+% <key> .LoadResource - (may give an error)
+% .ResourceFile
+% <key> .ResourceFile <file> -true-
+% <key> .ResourceFile <key> -false-
+% All the above procedures expect that the top dictionary on the d-stack
+% is the resource dictionary.
+
+% Define enough of the Category category so we can define other categories.
+% The dictionary we're about to create will become the Category
+% category definition dictionary.
+
+% .findcategory and .resourceexec are only called from within the
+% implementation of the resource 'operators', so they doesn't have to worry
+% about cleaning up the stack if they fail (the interpreter's stack
+% protection machinery for pseudo-operators takes care of this).
+/.findcategory { % <name> .findcategory -
+ % (pushes the category on the dstack)
+ /Category findresource begin
+} bind def
+
+/.resourceexec { % <key> /xxxResource .resourceexec -
+ % (also pops the category from the dstack)
+ load exec end
+} bind def
+
+15 dict begin
+
+ % Standard entries
+
+/Category /Category def
+/InstanceType /dicttype def
+
+/DefineResource
+ { .CheckResource
+ { dup /Category 3 index cvlit .growput
+ % We would like to make Category dictionaries read-only,
+ % and we used to do that here, but we can't do it,
+ % because we have to be able to replace the dummy, empty
+ % Instances dictionary with the real one later.
+ dup [ exch 0 -1 ] exch
+ Instances 4 2 roll put
+ }
+ { /defineresource load /typecheck signalerror
+ }
+ ifelse
+ } bind def
+/FindResource % (redefined below)
+ { Instances exch get 0 get
+ } bind def
+
+ % Additional entries
+
+/Instances 30 dict def
+Instances /Category [currentdict 0 -1] put
+
+/.LocalInstances 0 dict def
+/.GetInstance
+ { Instances exch .knownget
+ } bind def
+/.CheckResource
+ { dup gcheck currentglobal and
+ { /DefineResource /FindResource /ResourceForAll /ResourceStatus
+ /UndefineResource }
+ { 2 index exch known and }
+ forall
+ not { /defineresource load /invalidaccess signalerror } if
+ true
+ } bind def
+
+Instances end begin % for the base case of findresource
+
+(END CATEGORY) VMDEBUG
+
+% Define the resource operators. We use the "stack protection" feature of
+% odef to make sure the stacks are restored properly on an error.
+% This requires that the operators not pop anything from the stack until
+% they have executed their logic successfully. We can't make this
+% work for resourceforall, because the procedure it executes mustn't see
+% the operands of resourceforall on the stack, but we can make it work for
+% the others.
+
+mark
+/defineresource { % <key> <instance> <category> defineresource <instance>
+ 3 copy .findcategory
+ currentdict /InstanceType known {
+ dup type InstanceType ne {
+ dup type /packedarraytype eq InstanceType /arraytype eq and
+ not { /defineresource load /typecheck signalerror } if
+ } if
+ } if
+ /DefineResource .resourceexec
+ 4 1 roll pop pop pop
+}
+/findresource { % <key> <category> findresource <instance>
+ 2 copy dup /Category eq
+ { pop //Category 0 get begin } { .findcategory } ifelse
+ /FindResource .resourceexec exch pop exch pop
+}
+/resourceforall { % <template> <proc> <scratch> <category> resourceforall -
+ dup /Category findresource begin
+ /ResourceForAll load
+ % Make sure we can recover the original operands.
+ % Stack: ...operands... proc
+ 5 copy pop 4 packedarray count
+ % Stack: ...operands... proc saved count
+ 4 -1 roll pop % pop the category
+ /.internalstopped load 3 1 roll
+ 3 .execn
+ % Stack: ... stopped saved count
+ 3 -1 roll {
+ % The count is the original stack depth + 2.
+ count exch 4 sub sub { exch pop } repeat
+ aload pop stop
+ } {
+ pop pop
+ } ifelse end
+}
+/resourcestatus { % <key> <category> resourcestatus <status> <size> true
+ % <key> <category> resourcestatus false
+ 2 copy .findcategory /ResourceStatus .resourceexec
+ { 4 2 roll pop pop true } { pop pop false } ifelse
+}
+/undefineresource { % <key> <category> undefineresource -
+ 2 copy .findcategory /UndefineResource .resourceexec pop pop
+}
+end % Instances of Category
+counttomark 2 idiv { bind odef } repeat pop
+
+% Define the system parameters used for the Generic implementation of
+% ResourceFileName.
+systemdict begin
+currentdict /pssystemparams known not {
+ /pssystemparams 10 dict readonly def
+} if
+pssystemparams begin
+ /FontResourceDir (/Resource/Font/) readonly .forcedef % pssys'params is r-o
+ /GenericResourceDir (/Resource/) readonly .forcedef % pssys'params is r-o
+ /GenericResourcePathSep (/) readonly .forcedef % pssys'params is r-o
+end
+end
+
+% Define the generic algorithm for computing resource file names.
+/.rfnstring 100 string def
+/.genericrfn % <key> <scratch> <prefix> .genericrfn <filename>
+ { 3 -1 roll //.rfnstring cvs concatstrings exch copy
+ } bind def
+
+% Define the Generic category.
+
+/Generic mark
+
+ % Standard entries
+
+% We're still running in Level 1 mode, so dictionaries won't expand.
+% Leave room for the /Category entry.
+/Category null
+
+/DefineResource
+ { .CheckResource
+ { dup [ exch 0 -1 ]
+ % Stack: key value instance
+ currentglobal
+ { false setglobal 2 index UndefineResource % remove local def if any
+ true setglobal
+ Instances dup //.emptydict eq
+ { pop 3 dict /Instances 1 index def
+ }
+ if
+ }
+ { .LocalInstances dup //.emptydict eq
+ { pop 3 dict localinstancedict Category 2 index put
+ }
+ if
+ }
+ ifelse
+ % Stack: key value instance instancedict
+ 3 index 2 index .growput
+ % Now make the resource value read-only.
+ 0 2 copy get { readonly } .internalstopped pop
+ dup 4 1 roll put exch pop exch pop
+ }
+ { /defineresource load /typecheck signalerror
+ }
+ ifelse
+ } bind
+/UndefineResource
+ { { dup 2 index .knownget
+ { dup 1 get 1 ge
+ { dup 0 null put 1 2 put pop pop }
+ { pop exch .undef }
+ ifelse
+ }
+ { pop pop
+ }
+ ifelse
+ }
+ currentglobal
+ { 2 copy Instances exch exec
+ }
+ if .LocalInstances exch exec
+ } bind
+/FindResource
+ { dup ResourceStatus
+ { pop 1 gt % not in VM
+ { .DoLoadResource
+ }
+ if
+ .GetInstance pop % can't fail
+ 0 get
+ }
+ { /findresource load /undefinedresource signalerror
+ }
+ ifelse
+ } bind
+/ResourceStatus
+ { dup .GetInstance
+ { exch pop dup 1 get exch 2 get true }
+ { .ResourceFile
+ { closefile 2 -1 true }
+ { pop false }
+ ifelse
+ }
+ ifelse
+ } bind
+/ResourceForAll
+ { % **************** Doesn't present instance groups in
+ % **************** the correct order yet.
+ % Construct a new procedure to hold the arguments.
+ % It must be in local VM to avoid a possible invalidaccess.
+ .currentglobal 4 1 roll false .setglobal
+ 3 packedarray % template, proc, scratch
+ { exch pop % stack contains: key, {template, proc, scratch}
+ 2 copy 0 get .stringmatch
+ { 1 index type dup /stringtype eq exch /nametype eq or
+ { 2 copy 2 get cvs
+ exch 1 get 3 -1 roll pop
+ }
+ { 1 get
+ }
+ ifelse exec
+ }
+ { pop pop
+ }
+ ifelse
+ } /exec cvx 3 packedarray
+ % Stack: global? iterproc
+ % We must pop the resource dictionary off the dict stack
+ % when doing the actual iteration, and restore it afterwards.
+ exch {
+ true .setglobal
+ } {
+ .LocalInstances length 0 ne {
+ % We must do local instances, and do them first.
+ .LocalInstances exch cvx /forall cvx 1 index cvlit
+ currentdict end 3 .execn begin
+ } if
+ } ifelse
+ Instances exch cvx
+ /forall cvx currentdict end 2 .execn begin
+ } bind
+/ResourceFileName
+ { /GenericResourceDir getsystemparam
+ Category .namestring concatstrings
+ /GenericResourcePathSep getsystemparam concatstrings
+ .genericrfn
+ } bind
+
+ % Additional entries
+
+% Unfortunately, we can't create the real Instances dictionary now,
+% because if someone copies the Generic category (which pp. 95-96 of the
+% 2nd Edition Red Book says is legitimate), they'll wind up sharing
+% the Instances. Instead, we have to create Instances on demand,
+% just like the entry in localinstancedict.
+% We also have to prevent anyone from creating instances of Generic itself.
+/Instances //.emptydict
+
+/.LocalInstances
+ { localinstancedict Category .knownget not { //.emptydict } if
+ } bind
+/.GetInstance
+ { currentglobal
+ { Instances exch .knownget }
+ { .LocalInstances 1 index .knownget
+ { exch pop true }
+ { Instances exch .knownget }
+ ifelse
+ }
+ ifelse
+ } bind
+/.CheckResource
+ { true
+ } bind
+/.DoLoadResource
+ { dup vmstatus pop exch pop exch
+ .LoadResource
+ vmstatus pop exch pop exch sub
+ 1 index .GetInstance not
+ { pop dup /undefinedresource signalerror } % didn't load
+ if
+ dup 1 1 put
+ 2 3 -1 roll put
+ } bind
+/.LoadResource
+ { dup .ResourceFile
+ { exch pop currentglobal
+ { run }
+ { true setglobal { run } stopped false setglobal { stop } if }
+ ifelse
+ }
+ { dup /undefinedresource signalerror
+ }
+ ifelse
+ } bind
+/.ResourceFile
+ { currentdict /ResourceFileName known
+ { mark 1 index 100 string { ResourceFileName }
+ .internalstopped
+ { cleartomark false }
+ { exch pop findlibfile
+ { exch pop exch pop true }
+ { pop false }
+ ifelse
+ }
+ ifelse
+ }
+ { false }
+ ifelse
+ } bind
+
+.dicttomark
+/Category defineresource pop
+
+% Fill in the rest of the Category category.
+/Category /Category findresource dup
+/Generic /Category findresource begin
+ { /FindResource /ResourceForAll /ResourceStatus /UndefineResource
+ /ResourceFileName /.ResourceFile /.LoadResource /.DoLoadResource
+ }
+ { dup load put dup } forall
+pop readonly pop end
+
+(END GENERIC) VMDEBUG
+
+% Define the fixed categories.
+
+mark
+ % Non-Type categories with existing entries.
+ /ColorSpaceFamily
+ mark colorspacedict { pop } forall .packtomark
+ /Emulator
+ mark EMULATORS { cvn } forall .packtomark
+ /Filter
+ mark filterdict { pop } forall .packtomark
+ /IODevice
+ % Loop until the .getiodevice gets a rangecheck.
+ errordict /rangecheck 2 copy get
+ errordict /rangecheck { pop stop } put % pop the command
+ mark 0 { {dup .getiodevice exch 1 add} loop} .internalstopped
+ pop pop pop .packtomark
+ 4 1 roll put
+ .clearerror
+ % Type categories listed in the Red Book.
+ /ColorRenderingType
+ { } % These must be deferred, because optional features may add some.
+ /FMapType
+ { } % These must be deferred, because optional features may add some.
+ /FontType
+ { } % These must be deferred, because optional features may add some.
+ /FormType
+ { } % These must be deferred, because optional features may add some.
+ /HalftoneType
+ {1 2 3 4 5}
+ /ImageType
+ { } % Deferred, optional features may add some.
+ /PatternType
+ { } % Deferred, optional features may add some.
+ % Type categories added since the Red Book.
+ /setsmoothness where {
+ pop /ShadingType { } % Deferred, optional features may add some.
+ } if
+counttomark 2 idiv
+ { mark
+
+ % Standard entries
+
+ % We'd like to prohibit defineresource,
+ % but because optional features may add entries, we can't.
+ % We can at least require that the key and value match.
+ /DefineResource
+ { currentglobal not
+ { /defineresource load /invalidaccess signalerror }
+ { 2 copy ne
+ { /defineresource load /rangecheck signalerror }
+ { dup Instances 4 -2 roll .growput }
+ ifelse
+ }
+ ifelse
+ } bind
+ /UndefineResource
+ { /undefineresource load /invalidaccess signalerror } bind
+ /FindResource
+ { Instances 1 index .knownget
+ { exch pop }
+ { /findresource load /undefinedresource signalerror }
+ ifelse
+ } bind
+ /ResourceStatus
+ { Instances exch known { 0 0 true } { false } ifelse } bind
+ /ResourceForAll
+ /Generic /Category findresource /ResourceForAll get
+
+ % Additional entries
+
+ counttomark 2 add -1 roll
+ dup length dict dup begin exch { dup def } forall end
+ % We'd like to make the Instances readonly here,
+ % but because optional features may add entries, we can't.
+ /Instances exch
+ /.LocalInstances % used by ResourceForAll
+ 0 dict def
+
+ .dicttomark /Category defineresource pop
+ } repeat pop
+
+(END FIXED) VMDEBUG
+
+% Define the other built-in categories.
+
+/.definecategory % <name> -mark- <key1> ... <valuen> .definecategory -
+ { counttomark 2 idiv 2 add % Instances, Category
+ /Generic /Category findresource dup maxlength 3 -1 roll add
+ dict .copydict begin
+ counttomark 2 idiv { def } repeat pop % pop the mark
+ currentdict end /Category defineresource pop
+ } bind def
+
+/ColorRendering mark /InstanceType /dicttype .definecategory
+/ColorSpace mark /InstanceType /arraytype .definecategory
+/Form mark /InstanceType /dicttype .definecategory
+/Halftone mark /InstanceType /dicttype .definecategory
+/Pattern mark /InstanceType /dicttype .definecategory
+/ProcSet mark /InstanceType /dicttype .definecategory
+% Added since the Red Book:
+/ControlLanguage mark /InstanceType /dicttype .definecategory
+/HWOptions mark /InstanceType /dicttype .definecategory
+/Localization mark /InstanceType /dicttype .definecategory
+/OutputDevice mark /InstanceType /dicttype .definecategory
+/PDL mark /InstanceType /dicttype .definecategory
+% CIDFont, CIDMap, and CMap are defined in gs_cidfn.ps
+% FontSet is defined in gs_cff.ps
+% IdiomSet, InkParams, and TrapParams are defined in gs_ll3.ps
+
+(END MISC) VMDEBUG
+
+% Define the Encoding category.
+
+/Encoding mark
+
+/InstanceType /arraytype
+
+% Handle already-registered encodings, including lazily loaded encodings
+% that aren't loaded yet.
+
+/Instances mark
+ EncodingDirectory
+ { dup length 256 eq { [ exch readonly 0 -1 ] } { pop [null 2 -1] } ifelse
+ } forall
+.dicttomark
+
+/.ResourceFileDict mark
+ EncodingDirectory
+ { dup length 256 eq { pop pop } { 0 get } ifelse
+ } forall
+.dicttomark
+
+/ResourceFileName
+ { .ResourceFileDict 2 index .knownget
+ { exch copy exch pop }
+ { /Generic /Category findresource /ResourceFileName get exec }
+ ifelse
+ } bind
+
+.definecategory % Encoding
+
+% Make placeholders in level2dict for the redefined Encoding operators,
+% so that they will be swapped properly when we switch language levels.
+
+/.findencoding /.findencoding load def
+/findencoding /findencoding load def
+/.defineencoding /.defineencoding load def
+
+(END ENCODING) VMDEBUG
+
+% Define the Font category.
+
+/Font mark
+
+/InstanceType /dicttype
+
+/DefineResource
+ { 2 copy //definefont exch pop
+ /Generic /Category findresource /DefineResource get exec
+ } bind
+/UndefineResource
+ { dup //undefinefont
+ /Generic /Category findresource /UndefineResource get exec
+ } bind
+/FindResource
+ { dup ResourceStatus
+ { pop 1 gt { .loadfont } { .GetInstance pop 0 get } ifelse }
+ { .loadfont }
+ ifelse
+ } bind
+/ResourceFileName
+ { /FontResourceDir getsystemparam .genericrfn
+ } bind
+
+/.loadfont
+ { dup vmstatus pop exch pop exch
+ //findfont exec exch % findfont is a procedure....
+ vmstatus pop exch pop exch sub
+ % stack: name font vmused
+ % findfont has the prerogative of not calling definefont
+ % in certain obscure cases of font substitution.
+ 2 index .GetInstance
+ { dup 1 1 put
+ 2 3 -1 roll put
+ }
+ { pop
+ }
+ ifelse exch pop
+ } bind
+
+/Instances FontDirectory length 2 mul dict
+
+.definecategory % Font
+
+% Redefine font "operators".
+/.definefontmap
+ { /Font /Category findresource /Instances get
+ dup 3 index known
+ { pop
+ }
+ { 2 index
+ % Make sure we create the array in global VM.
+ .currentglobal true .setglobal
+ [null 2 -1] exch .setglobal
+ .growput
+ }
+ ifelse
+ //.definefontmap exec
+ } bind def
+
+% Make sure the old definitions are still in systemdict so that
+% they will get bound properly.
+systemdict begin
+ /.origdefinefont /definefont load def
+ /.origundefinefont /undefinefont load def
+ /.origfindfont /findfont load def
+end
+/definefont {
+ /Font defineresource
+} bind odef
+/undefinefont {
+ /Font undefineresource
+} bind odef
+% The Red Book requires that findfont be a procedure, not an operator,
+% but it still needs to restore the stacks reliably if it fails.
+/.findfontop {
+ /Font findresource
+} bind odef
+/findfont {
+ .findfontop
+} bind def % Must be a procedure, not an operator
+
+% Remove initialization utilities.
+currentdict /.definecategory .undef
+currentdict /.emptydict .undef
+
+end % level2dict
+
+% Convert deferred resources after we finally switch to Level 2.
+
+/.fixresources {
+ % Encoding resources
+ EncodingDirectory
+ { dup length 256 eq
+ { /Encoding defineresource pop }
+ { pop pop }
+ ifelse
+ } forall
+ /.findencoding { /Encoding findresource } bind def
+ /findencoding /.findencoding load def % must be a procedure
+ /.defineencoding { /Encoding defineresource pop } bind def
+ % ColorRendering resources and ProcSet
+ systemdict /ColorRendering .knownget {
+ /ColorRendering exch /ProcSet defineresource pop
+ systemdict /ColorRendering undef
+ /Default currentcolorrendering /ColorRendering defineresource pop
+ } if
+ % ColorSpace resources
+ systemdict /CIEsRGB .knownget {
+ /sRGB exch /ColorSpace defineresource pop
+ systemdict /CIEsRGB undef
+ } if
+ % FontType and FMapType resources
+ buildfontdict { pop dup /FontType defineresource pop } forall
+ mark
+ buildfontdict 0 known { 2 3 4 5 6 7 8 } if
+ buildfontdict 9 known { 9 } if
+ counttomark { dup /FMapType defineresource pop } repeat pop
+ % FormType resources
+ .formtypes { pop dup /FormType defineresource pop } forall
+ % ColorRenderingType resources
+ .colorrenderingtypes {pop dup /ColorRenderingType defineresource pop} forall
+ % ImageType resources
+ .imagetypes { pop dup /ImageType defineresource pop } forall
+ % PatternType resources
+ .patterntypes { pop dup /PatternType defineresource pop } forall
+ % Make the fixed resource categories immutable.
+ /.shadingtypes where {
+ pop .shadingtypes { pop dup /ShadingType defineresource pop } forall
+ } if
+ [ /ColorSpaceFamily /Emulator /Filter /IODevice /ColorRenderingType
+ /FMapType /FontType /FormType /HalftoneType /ImageType /PatternType
+ /.shadingtypes where { pop /ShadingType } if
+ ] {
+ /Category findresource
+ dup /Instances get readonly pop
+ .LocalInstances readonly pop
+ readonly pop
+ } forall
+ % clean up
+ systemdict /.fixresources undef
+} bind def
diff --git a/pstoraster/gs_setpd.ps b/pstoraster/gs_setpd.ps
new file mode 100644
index 000000000..f9bc7faf5
--- /dev/null
+++ b/pstoraster/gs_setpd.ps
@@ -0,0 +1,715 @@
+% Copyright (C) 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_setpd.ps 1396 2000-09-29 17:42:56Z mike $
+% The current implementation of setpagedevice has the following limitations:
+% - It doesn't attempt to "interact with the user" for Policy = 2.
+
+languagelevel 1 .setlanguagelevel
+level2dict begin
+
+% ---------------- Redefinitions ---------------- %
+
+% Redefine .beginpage and .endpage so that they call BeginPage and
+% EndPage respectively if appropriate.
+
+% We have to guard against the BeginPage procedure not popping its operand.
+% This is really stupid, but the Genoa CET does it.
+/.beginpage { % - .beginpage -
+ .currentshowpagecount {
+ .currentpagedevice pop
+ dup null ne { /BeginPage .knownget } { pop false } ifelse {
+ % Stack: ... pagecount proc
+ count 2 .execn
+ % Stack: ... ..???.. oldcount
+ count 1 add exch sub { pop } repeat
+ } {
+ pop
+ } ifelse
+ } if
+} bind odef
+
+% Guard similarly against EndPage not popping its operand.
+/.endpage { % <reason> .endpage <print_bool>
+ .currentshowpagecount {
+ 1 index .currentpagedevice pop
+ dup null ne { /EndPage .knownget } { pop false } ifelse {
+ % Stack: ... reason pagecount reason proc
+ count 2 .execn
+ % Stack: ... ..???.. print oldcount
+ count 2 add exch sub { exch pop } repeat
+ } {
+ pop pop 2 ne
+ } ifelse
+ } {
+ 2 ne
+ } ifelse
+} bind odef
+
+% Define interpreter callouts for handling gstate-saving operators,
+% to make sure that they create a page device dictionary for use by
+% the corresponding gstate-restoring operator.
+% We'd really like to avoid the cost of doing this, but we don't see how.
+% The names %gsavepagedevice, %savepagedevice, %gstatepagedevice,
+% %copygstatepagedevice, and %currentgstatepagedevice are known to the
+% interpreter.
+
+(%gsavepagedevice) cvn
+ { currentpagedevice pop gsave
+ } bind def
+
+(%savepagedevice) cvn
+ { currentpagedevice pop save
+ } bind def
+
+(%gstatepagedevice) cvn
+ { currentpagedevice pop gstate
+ } bind def
+
+(%copygstatepagedevice) cvn
+ { currentpagedevice pop copy
+ } bind def
+
+(%currentgstatepagedevice) cvn
+ { currentpagedevice pop currentgstate
+ } bind def
+
+% Define interpreter callouts for handling gstate-restoring operators
+% when the current page device needs to be changed.
+% The names %grestorepagedevice, %grestoreallpagedevice,
+% %restorepagedevice, and %setgstatepagedevice are known to the interpreter.
+
+/.installpagedevice
+ { % Since setpagedevice doesn't create new device objects,
+ % we must (carefully) reinstall the old parameters in
+ % the same device.
+ .currentpagedevice pop null currentdevice null .trysetparams
+ dup type /booleantype eq
+ { pop pop }
+ { % This should never happen!
+ DEBUG { (Error in .trysetparams!\n) print pstack flush } if
+ cleartomark pop pop pop
+ /.installpagedevice cvx /rangecheck signalerror
+ }
+ ifelse pop pop
+ % A careful reading of the Red Book reveals that an erasepage
+ % should occur, but *not* an initgraphics.
+ erasepage .beginpage
+ } bind def
+
+/.uninstallpagedevice
+ { 2 .endpage { .currentnumcopies false .outputpage } if
+ nulldevice
+ } bind def
+
+(%grestorepagedevice) cvn
+ { .uninstallpagedevice grestore .installpagedevice
+ } bind def
+
+(%grestoreallpagedevice) cvn
+ { .uninstallpagedevice grestore .installpagedevice grestoreall
+ } bind def
+
+(%restorepagedevice) cvn
+ { .uninstallpagedevice grestore .installpagedevice restore
+ } bind def
+
+(%setgstatepagedevice) cvn
+ { .uninstallpagedevice setgstate .installpagedevice
+ } bind def
+
+% Redefine .currentnumcopies so it consults the NumCopies device parameter.
+/.numcopiesdict mark
+ /NumCopies dup
+.dicttomark readonly def
+
+/.currentnumcopies
+ { currentdevice //.numcopiesdict .getdeviceparams
+ dup type /integertype eq
+ { exch pop exch pop }
+ { cleartomark #copies }
+ ifelse
+ } bind odef
+
+% Redefine .currentpagedevice and .setpagedevice so they convert between
+% null and a fixed empty directionary.
+/.nullpagedevice 0 dict readonly def
+/.currentpagedevice {
+ //.currentpagedevice exch dup null eq { pop //.nullpagedevice } if exch
+} bind odef
+/.setpagedevice {
+ dup //.nullpagedevice eq { pop null } if //.setpagedevice
+} bind odef
+
+% ---------------- Auxiliary definitions ---------------- %
+
+% Define the required attributes of all page devices, and their default values.
+% We don't include attributes such as PageSize, which all devices
+% are guaranteed to supply on their own.
+/.defaultpolicies mark
+ /PolicyNotFound 1
+ /PageSize 0
+ /PolicyReport {pop} bind
+.dicttomark readonly def
+/.requiredattrs mark
+ /PageOffset [0 0] readonly
+% We define InputAttributes and OutputAttributes with a single
+% dummy media type that handles pages of any size.
+% Devices that care will override this.
+ /InputAttributes mark 0
+ % Since sizes match within 5 user units, we need to set the smallest
+ % PageSize to 6 units so that [0 0] will fail.
+ mark /PageSize [6 dup 16#7ffff dup] .dicttomark readonly
+ .dicttomark readonly
+ (%MediaSource) 0
+ /OutputAttributes mark 0
+ mark .dicttomark readonly
+ .dicttomark readonly
+ (%MediaDestination) 0
+ /Install {.callinstall} bind
+ /BeginPage {.callbeginpage} bind
+ /EndPage {.callendpage} bind
+ /Policies .defaultpolicies
+.dicttomark readonly def
+
+% Define currentpagedevice so it creates the dictionary on demand if needed,
+% adding all the required entries defined just above.
+% We have to deal specially with entries that the driver may change
+% on its own.
+/.dynamicppkeys mark
+ /PageSize dup % because it changes when PageSize is set
+ /PageCount dup
+.dicttomark readonly def
+/.makecurrentpagedevice % - .makecurrentpagedevice <dict>
+ { currentdevice null .getdeviceparams
+ % In case of duplicate keys, .dicttomark takes the entry
+ % lower on the stack, so we can just append the defaults here.
+ .requiredattrs { } forall .dicttomark
+ dup .setpagedevice
+ } bind def
+/currentpagedevice
+ { .currentpagedevice
+ { dup length 0 eq
+ { pop .makecurrentpagedevice
+ }
+ { % If any of the dynamic keys have changed,
+ % we must update the page device dictionary.
+ currentdevice //.dynamicppkeys .getdeviceparams .dicttomark
+ { % Stack: current key value
+ 2 index 2 index .knownget { 1 index ne } { true } ifelse
+ { 2 index wcheck not
+ { % This is the first entry being updated.
+ % Copy the dictionary to make it writable.
+ 3 -1 roll dup length dict .copydict
+ 3 1 roll
+ }
+ if
+ 2 index 3 1 roll put
+ }
+ { pop pop
+ }
+ ifelse
+ }
+ forall
+ % We would like to do a .setpagedevice so we don't keep
+ % re-creating the dictionary. Unfortunately, the effect
+ % of this is that if any dynamic key changes (PageCount
+ % in particular), we will do the equivalent of a
+ % setpagedevice at the next restore or grestore.
+ % Therefore, we make the dictionary read-only, but
+ % we don't store it away. I.e., NOT:
+ % dup wcheck { .setpagedevice .currentpagedevice pop } if
+ readonly
+ }
+ ifelse
+ }
+ if
+ } bind odef
+
+% The implementation of setpagedevice is quite complex. Currently,
+% everything but the media matching algorithm is implemented here.
+
+% By default, we only present the requested changes to the device,
+% but there are some parameters that require special merging action.
+% Define those parameters here, with the procedures that do the merging.
+% The procedures are called as follows:
+% <merged> <key> <new_value> -proc- <merged> <key> <new_value'>
+/.mergespecial mark
+ /InputAttributes
+ { dup null eq
+ { pop null
+ }
+ { 3 copy pop .knownget
+ { dup null eq
+ { pop dup length dict }
+ { dup length 2 index length add dict .copydict }
+ ifelse
+ }
+ { dup length dict
+ }
+ ifelse .copydict readonly
+ }
+ ifelse
+ } bind
+ /OutputAttributes 1 index
+ /Policies
+ { 3 copy pop .knownget
+ { dup length 2 index length add dict .copydict }
+ { dup length dict }
+ ifelse copy readonly
+ } bind
+.dicttomark readonly def
+
+% Define the keys used in input attribute matching.
+/.inputattrkeys [
+%%%% MRS: Can't get Ghostscript to leave these alone, so we only
+%%%% include PageSize here...
+% /PageSize /MediaColor /MediaWeight /MediaType /InsertSheet
+ /PageSize
+ % The following are documented in Adobe's supplement for v2017.
+% /LeadingEdge /MediaClass
+] readonly def
+% Define other keys used in media selection.
+/.inputselectionkeys [
+%%%% MRS: Can't get Ghostscript to leave these alone, so we only
+%%%% provide a dummy attribute here...
+% /MediaPosition /Orientation
+ /DummyInput
+] readonly def
+
+% Define the keys used in output attribute matching.
+/.outputattrkeys [
+%%%% MRS: Can't get Ghostscript to leave these alone, so we only
+%%%% include a dummy attribute here...
+% /OutputType
+ /DummyOutput
+] readonly def
+
+% Define all the parameters that should always be copied to the merged
+% dictionary.
+/.copiedkeys [
+ /OutputDevice
+ .mergespecial { pop } forall
+ .inputattrkeys aload pop
+ .inputselectionkeys aload pop
+ .outputattrkeys aload pop
+] readonly def
+
+% Define the parameters that should not be presented to the device.
+% The procedures are called as follows:
+% <merged> <key> <value> -proc-
+% The procedure leaves all its operands on the stack and returns
+% true iff the key/value pair should be presented to .putdeviceparams.
+/.presentspecial mark
+ .dynamicppkeys { pop false } forall
+ % We must ignore an explicit request for PageSize,
+ % because media matching always handles this.
+ /PageSize false
+ /Name false
+ /OutputDevice false
+ /PageOffset false
+ /InputAttributes false
+ .inputattrkeys
+ { dup /PageSize eq
+ { pop }
+ { { 2 index /InputAttributes .knownget { null eq } { true } ifelse } }
+ ifelse
+ }
+ forall
+ .inputselectionkeys { false } forall
+ /OutputAttributes false
+ .outputattrkeys
+ { { 2 index /OutputAttributes .knownget { null eq } { true } ifelse } }
+ forall
+ /Install false
+ /BeginPage false
+ /EndPage false
+ /Policies false
+ % Our extensions:
+ /HWColorMap
+ { % HACK: don't transmit the color map, because
+ % window systems can change the color map on their own
+ % incrementally. Someday we'll have a better
+ % solution for this....
+ false
+ }
+ /ViewerPreProcess false
+.dicttomark readonly def
+
+% Define access to device defaults.
+/.defaultdeviceparams
+ { finddevice null .getdeviceparams
+ } bind def
+
+% Select media (input or output). The hard work is done in an operator:
+% <pagedict> <attrdict> <policydict> <keys> .matchmedia <key> true
+% <pagedict> <attrdict> <policydict> <keys> .matchmedia false
+% <pagedict> null <policydict> <keys> .matchmedia null true
+/.selectmedia % <orig> <request> <merged> <failed> <-- retained
+ % <attrdict> <policydict> <attrkeys> <mediakey>
+ % .selectmedia
+ { 5 index 5 -2 roll 4 index .matchmedia
+ % Stack: orig request merged failed attrkeys mediakey
+ % (key true | false)
+ { 4 index 3 1 roll put pop
+ }
+ { % Adobe's implementations have a "big hairy heuristic"
+ % to choose the set of keys to report as having failed the match.
+ % For the moment, we report any keys that are in the request
+ % and don't have the same value as in the original dictionary.
+ 5 index 1 index .knownget
+ { 4 index 3 1 roll put }
+ { 3 index exch .undef }
+ ifelse
+ { % Stack: <orig> <request> <merged> <failed> <attrkey>
+ 3 index 1 index .knownget
+ { 5 index 2 index .knownget { ne } { pop true } ifelse }
+ { true }
+ ifelse % Stack: ... <failed> <attrkey> <report>
+ { 2 copy /rangecheck put }
+ if pop
+ }
+ forall
+ }
+ ifelse
+ } bind def
+
+% Apply Policies to any unprocessed failed requests.
+% As we process each request entry, we replace the error name
+% in the <failed> dictionary with the policy value,
+% and we replace the key in the <merged> dictionary with its prior value
+% (or remove it if it had no prior value).
+/.policyprocs mark
+% These procedures are called with the following on the stack:
+% <orig> <merged> <failed> <Policies> <key> <policy>
+% They are expected to consume the top 2 operands.
+% NOTE: we currently treat all values other than 0, 1, or 7 (for PageSize)
+% the same as 0, i.e., we signal an error.
+% 0 { % Set errorinfo and signal a configurationerror.
+% pop dup 4 index exch get 2 array astore
+% $error /errorinfo 3 -1 roll put
+% cleartomark
+% /setpagedevice load /configurationerror signalerror
+% } bind
+%%%% MRS - The current CUPS backend driver does not register any of
+%%%% these attributes with GhostScript from the PPD file. As
+%%%% a result, we must allow all attributes and values.
+ 0 { % For all attributes just impose the request.
+ pop 2 index exch 7 put
+ } bind
+ 1 { % Roll back the failed request to its previous status.
+DEBUG { (Rolling back.\n) print pstack flush } if
+ 3 index 2 index 3 -1 roll put
+ 4 index 1 index .knownget
+ { 4 index 3 1 roll put }
+ { 3 index exch .undef }
+ ifelse
+ } bind
+ 7 { % For PageSize only, just impose the request.
+ 1 index /PageSize eq
+ { pop pop 1 index /PageSize 7 put }
+ { .policyprocs 0 get exec }
+ ifelse
+ } bind
+.dicttomark readonly def
+/.applypolicies % <orig> <merged> <failed> .applypolicies
+ % <orig> <merged'> <failed'>
+ { 1 index /Policies get 1 index
+ { type /integertype eq
+ { pop % already processed
+ }
+ { 2 copy .knownget not { 1 index /PolicyNotFound get } if
+ % Stack: <orig> <merged> <failed> <Policies> <key>
+ % <policy>
+ .policyprocs 1 index .knownget not { .policyprocs 0 get } if exec
+ }
+ ifelse
+ }
+ forall pop
+ } bind def
+
+% Prepare to present parameters to the device, by spreading them onto the
+% operand stack and removing any that shouldn't be presented.
+/.prepareparams % <params> .prepareparams -mark- <key1> <value1> ...
+ { mark exch dup
+ { % Stack: -mark- key1 value1 ... merged key value
+ .presentspecial 2 index .knownget
+ { exec { 3 -1 roll } { pop pop } ifelse }
+ { 3 -1 roll }
+ ifelse
+ }
+ forall pop
+ } bind def
+
+% Put device parameters without resetting currentpagedevice.
+% (.putdeviceparams clears the current page device.)
+/.putdeviceparamsonly % <device> <Policies|null> <require_all> -mark-
+ % <key1> <value1> ... .putdeviceparamsonly
+ % On success: <device> <eraseflag>
+ % On failure: <device> <Policies|null> <req_all> -mark-
+ % <key1> <error1> ...
+ { .currentpagedevice
+ { counttomark 4 add 1 roll .putdeviceparams
+ dup type /booleantype eq { 3 } { counttomark 5 add } ifelse -1 roll
+ .setpagedevice
+ }
+ { pop .putdeviceparams
+ }
+ ifelse
+ } bind def
+
+% Try setting the device parameters from the merged request.
+/.trysetparams % <merged> <(ignored)> <device> <Policies>
+ % .trysetparams
+ { true 4 index .prepareparams
+ % Add the computed PageSize.
+ % Stack: merged (ignored) device Policies -true-
+ % -mark- key1 value1 ...
+ counttomark 5 add index .computemediasize
+ exch pop exch pop /PageSize exch
+DEBUG { (Putting.\n) print pstack flush } if
+ .putdeviceparamsonly
+DEBUG { (Result of putting.\n) print pstack flush } if
+ } bind def
+
+% Compute the media size and initial matrix from a merged request (after
+% media selection).
+/.computemediasize % <request> .computemediasize
+ % <request> <matrix> <[width height]>
+ { dup /PageSize get % requested page size
+ 1 index /InputAttributes get
+ 2 index (%MediaSource) get get /PageSize get % media size
+ % (may be a range)
+ 2 index /Policies get
+ dup /PageSize .knownget
+ { exch pop } { /PolicyNotFound get } ifelse % PageSize policy,
+ % affects scaling
+ 3 index /Orientation .knownget not { null } if
+ 4 index /RollFedMedia .knownget not { false } if
+ matrix .matchpagesize not {
+ % This is a "can't happen" condition!
+ /setpagedevice load /rangecheck signalerror
+ } if
+ 2 array astore
+ } bind def
+
+% ---------------- setpagedevice itself ---------------- %
+
+/setpagedevice
+ { % We mustn't pop the argument until the very end,
+ % so that the pseudo-operator machinery can restore the stack
+ % if an error occurs.
+ mark 1 index currentpagedevice
+
+ % Check whether we are changing OutputDevice;
+ % also handle the case where the current device
+ % is not a page device.
+ % Stack: mark <request> <current>
+DEBUG { (Checking.\n) print pstack flush } if
+
+ dup /OutputDevice .knownget
+ { % Current device is a page device.
+ 2 index /OutputDevice .knownget
+ { % A specific OutputDevice was requested.
+ 2 copy eq
+ { pop pop null }
+ { exch pop }
+ ifelse
+ }
+ { pop null
+ }
+ ifelse
+ }
+ { % Current device is not a page device.
+ % Use the default device.
+ 1 index /OutputDevice .knownget not { .defaultdevicename } if
+ }
+ ifelse
+ dup null eq
+ { pop
+ }
+ { exch pop .defaultdeviceparams
+ % In case of duplicate keys, .dicttomark takes the entry
+ % lower on the stack, so we can just append the defaults here.
+ .requiredattrs { } forall .dicttomark
+ }
+ ifelse
+
+ % Check whether a viewer wants to intervene.
+ % We must check both the request (which takes precedence)
+ % and the current dictionary.
+ % Stack: mark <request> <orig>
+ exch dup /ViewerPreProcess .knownget
+ { exec }
+ { 1 index /ViewerPreProcess .knownget { exec } if }
+ ifelse exch
+
+ % Construct a merged request from the actual request plus
+ % any keys that should always be propagated.
+ % Stack: mark <request> <orig>
+DEBUG { (Merging.\n) print pstack flush } if
+
+ exch 1 index length 1 index length add dict
+ .copiedkeys
+ { % Stack: <orig> <request> <merged> <key>
+ 3 index 1 index .knownget { 3 copy put pop } if pop
+ }
+ forall
+ % Stack: <orig> <request> <merged>
+ dup 2 index
+ { % stack: <orig> <request> <merged> <merged> <rkey> <rvalue>
+ .mergespecial 2 index .knownget { exec } if
+ put dup
+ }
+ forall pop
+ % Hack: if FIXEDRESOLUTION is true, discard any attempt to
+ % change HWResolution.
+ FIXEDRESOLUTION { dup /HWResolution .undef } if
+ % Hack: if FIXEDMEDIA is true, discard any attempt to change
+ % PageSize or HWSize.
+ FIXEDMEDIA
+ { dup /PageSize 4 index /PageSize get put
+ dup /HWSize 4 index /HWSize get put
+ } if
+
+ % Select input and output media.
+ % Stack: mark <orig> <request> <merged>
+DEBUG { (Selecting.\n) print pstack flush } if
+
+ 0 dict % <failed>
+ 1 index /InputAttributes .knownget
+ { 2 index /Policies get
+ .inputattrkeys (%MediaSource) cvn .selectmedia
+ } if
+ 1 index /OutputAttributes .knownget
+ { 2 index /Policies get
+ .outputattrkeys (%MediaDestination) cvn .selectmedia
+ } if
+ 3 -1 roll 4 1 roll % temporarily swap orig & request
+ .applypolicies
+ 3 -1 roll 4 1 roll % swap back
+
+ % Construct the new device, and attempt to set its attributes.
+ % Stack: mark <orig> <request> <merged> <failed>
+DEBUG { (Constructing.\n) print pstack flush } if
+
+ currentdevice .devicename 2 index /OutputDevice get eq
+ { currentdevice }
+ { 1 index /OutputDevice get finddevice }
+ ifelse
+ %**************** We should copy the device here,
+ %**************** but since we can't close the old device,
+ %**************** we don't. This is WRONG.
+ %****************copydevice
+ 2 index /Policies get
+ .trysetparams
+ dup type /booleantype ne
+ { % The request failed.
+ % Stack: ... <orig> <request> <merged> <failed> <device>
+ % <Policies> true mark <name> <errorname> ...
+DEBUG { (Recovering.\n) print pstack flush } if
+ counttomark 4 add index
+ counttomark 2 idiv { dup 4 -2 roll put } repeat
+ pop pop pop
+ % Stack: mark ... <orig> <request> <merged> <failed> <device>
+ % <Policies>
+ 6 2 roll 3 -1 roll 4 1 roll
+ .applypolicies
+ 3 -1 roll 4 1 roll 6 -2 roll
+ .trysetparams % shouldn't fail!
+ dup type /booleantype ne
+ { 2 { counttomark 1 add 1 roll cleartomark } repeat
+ /setpagedevice load exch signalerror
+ }
+ if
+ }
+ if
+
+ % The attempt succeeded. Install the new device.
+ % Stack: mark ... <merged> <failed> <device> <eraseflag>
+DEBUG { (Installing.\n) print pstack flush } if
+
+ pop 2 .endpage
+ { 1 true .outputpage
+ (>>setpagedevice, press <return> to continue<<\n) .confirm
+ }
+ if
+ % .setdevice clears the current page device!
+ .currentpagedevice pop exch
+ .setdevice pop
+ .setpagedevice
+
+ % Merge the request into the current page device,
+ % unless we're changing the OutputDevice.
+ % Stack: mark ... <merged> <failed>
+ exch currentpagedevice dup length 2 index length add dict
+ % Stack: mark ... <failed> <merged> <current> <newdict>
+ 2 index /OutputDevice .knownget {
+ 2 index /OutputDevice .knownget not { null } if eq
+ } {
+ true
+ } ifelse {
+ % Same OutputDevice, merge the dictionaries.
+ .copydict
+ } {
+ % Different OutputDevice, discard the old dictionary.
+ exch pop
+ } ifelse .copydict
+ % Initialize the default matrix, taking media matching
+ % into account.
+ .computemediasize pop initmatrix concat
+ dup /PageOffset .knownget
+ { % Translate by the given number of 1/72" units in device X/Y.
+ dup 0 get exch 1 get
+ 2 index /HWResolution get dup 1 get exch 0 get
+ 4 -1 roll mul 72 div 3 1 roll mul 72 div
+ idtransform translate
+ }
+ if
+ % We must install the new page device dictionary
+ % before calling the Install procedure.
+ dup .setpagedevice
+ .setdefaultscreen % Set the default screen before calling Install.
+ dup /Install .knownget { exec } if
+ matrix currentmatrix .setdefaultmatrix
+ % Erase and initialize the page.
+ erasepage initgraphics
+ .beginpage
+
+ % Clean up, calling PolicyReport if needed.
+ % Stack: mark ... <failed> <merged>
+DEBUG { (Finishing.\n) print pstack flush } if
+
+ exch dup length 0 ne
+ { 1 index /Policies get /PolicyReport get
+ counttomark 1 add 2 roll cleartomark
+ exec
+ }
+ { cleartomark
+ }
+ ifelse pop
+
+ } odef
+
+end % level2dict
+.setlanguagelevel
diff --git a/pstoraster/gs_statd.ps b/pstoraster/gs_statd.ps
new file mode 100644
index 000000000..4c070e7ea
--- /dev/null
+++ b/pstoraster/gs_statd.ps
@@ -0,0 +1,301 @@
+% Copyright (C) 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_statd.ps 1395 2000-09-29 13:31:48Z mike $
+% This file provides statusdict, serverdict, and assorted LaserWriter
+% operators, mostly for the benefit of poorly designed PostScript programs
+% that 'know' they are running on a LaserWriter.
+
+systemdict begin
+ % We make statusdict a little larger for Level 2 stuff.
+ % Note that it must be allocated in local VM.
+ .currentglobal false .setglobal
+ /statusdict 89 dict .forcedef % statusdict is local, sys'dict global
+ % To support the Level 2 job control features,
+ % serverdict must also be in local VM.
+ /serverdict 10 dict .forcedef % serverdict is local, sys'dict global
+ .setglobal
+end
+
+% Define various paper formats. The Adobe documentation defines only these:
+% 11x17, a3, a4, a4small, b5, ledger, legal, letter, lettersmall, note.
+% These procedures are also accessed as data structures during initialization,
+% so the page dimensions must be the first two elements of the procedure.
+
+/.setpagesize { /statusdict .systemvar begin .setpagesize end } bind def
+userdict begin
+ % Page sizes defined by Adobe documentation
+ /11x17 {792 1224 //.setpagesize exec} bind def % 11x17 portrait
+ /a3 {842 1191 //.setpagesize exec} bind def
+ /a4 {595 842 //.setpagesize exec} bind def
+% a4small should be a4 with an ImagingBBox of [25 25 570 817].
+ /a4small /a4 load def
+ /b5 {516 729 //.setpagesize exec} bind def
+ /ledger {1224 792 //.setpagesize exec} bind def % 11x17 landscape
+ /legal {612 1008 //.setpagesize exec} bind def
+ /letter {612 792 //.setpagesize exec} bind def
+% lettersmall should be letter with an ImagingBBox of [25 25 587 767].
+ /lettersmall /letter load def
+% note should be letter (or some other size) with the ImagingBBox
+% shrunk by 25 units on all 4 sides.
+ /note /letter load def
+ % End of Adobe-defined page sizes
+STRICT { (%END) .skipeof } if
+ % Other page sizes
+ % ISO standard paper sizes
+ /a0 {2384 3370 //.setpagesize exec} bind def
+ /a1 {1684 2384 //.setpagesize exec} bind def
+ /a2 {1191 1684 //.setpagesize exec} bind def
+% /a3 {842 1191 //.setpagesize exec} bind def % defined by Adobe
+% /a4 {595 842 //.setpagesize exec} bind def % defined by Adobe
+ /a5 {420 595 //.setpagesize exec} bind def
+ /a6 {297 420 //.setpagesize exec} bind def
+ /a7 {210 297 //.setpagesize exec} bind def
+ /a8 {148 210 //.setpagesize exec} bind def
+ /a9 {105 148 //.setpagesize exec} bind def
+ /a10 {73 105 //.setpagesize exec} bind def
+ /b0 {2920 4127 //.setpagesize exec} bind def
+ /b1 {2064 2920 //.setpagesize exec} bind def
+ /b2 {1460 2064 //.setpagesize exec} bind def
+ /b3 {1032 1460 //.setpagesize exec} bind def
+ /b4 {729 1032 //.setpagesize exec} bind def
+% /b5 {516 729 //.setpagesize exec} bind def % defined by Adobe
+ /b6 {363 516 //.setpagesize exec} bind def
+ /b7 {258 363 //.setpagesize exec} bind def
+ /b8 {181 258 //.setpagesize exec} bind def
+ /b9 {127 181 //.setpagesize exec} bind def
+ /b10 {91 127 //.setpagesize exec} bind def
+ /c0 {2599 3676 //.setpagesize exec} bind def
+ /c1 {1837 2599 //.setpagesize exec} bind def
+ /c2 {1298 1837 //.setpagesize exec} bind def
+ /c3 {918 1298 //.setpagesize exec} bind def
+ /c4 {649 918 //.setpagesize exec} bind def
+ /c5 {459 649 //.setpagesize exec} bind def
+ /c6 {324 459 //.setpagesize exec} bind def
+ % U.S. CAD standard paper sizes
+ /archE {2592 3456 //.setpagesize exec} bind def
+ /archD {1728 2592 //.setpagesize exec} bind def
+ /archC {1296 1728 //.setpagesize exec} bind def
+ /archB {864 1296 //.setpagesize exec} bind def
+ /archA {648 864 //.setpagesize exec} bind def
+ % Other paper sizes
+ /flsa {612 936 //.setpagesize exec} bind def % U.S. foolscap
+ /flse {612 936 //.setpagesize exec} bind def % European foolscap
+ /halfletter {396 612 //.setpagesize exec} bind def
+% /tabloid {792 1224 //.setpagesize exec} bind def % 11x17 portrait
+% /csheet {1224 1584 //.setpagesize exec} bind def % ANSI C 17x22
+% /dsheet {1584 2448 //.setpagesize exec} bind def % ANSI D 22x34
+% /esheet {2448 3168 //.setpagesize exec} bind def % ANSI E 34x44
+%END SIZES
+end
+currentdict /.setpagesize .undef
+
+statusdict begin
+
+% Define the pagetype values for the known page formats.
+% The values for all but letter and note are arbitrary.
+/.pagetypenames
+ { /letter /note /legal
+ /a0 /a1 /a2 /a3 /a4 /a5 /a6 /a7 /a8 /a9 /a10
+ /b0 /b1 /b2 /b3 /b4 /b5 /archE /archD /archC /archB /archA
+ /flsa /flse /halfletter /11x17 /ledger
+ } cvlit readonly def
+
+%%%%%% The following items were suggested by a user as useful.
+
+% Permanent definitions
+
+/ramsize 4194304 def
+/hardwareiomode 0 def
+ /sethardwareiomode {pop} bind def
+/softwareiomode 0 def
+ /setsoftwareiomode {pop} bind def
+/dosysstart false def
+ /setdosysstart {pop} bind def
+/allowjobreset true def
+ /setallowjobreset {pop} bind def
+/defaultpaperfamily 0 def
+ /setdefaultpaperfamily {pop} bind def
+/defaultpapertray 0 def
+ /setdefaultpapertray {pop} bind def
+/defaulttrayswitch false def
+ /setdefaulttrayswitch {pop} bind def
+
+% Tray and format selection
+
+ /11x17tray userdict /11x17 get def
+ /a3tray userdict /a3 get def
+ /a4tray userdict /a4 get def
+ /a5tray userdict /a5 get def
+ /a6tray userdict /a6 get def
+ /b4tray userdict /b4 get def
+ /flsatray userdict /flsa get def
+ /flsetray userdict /flse get def
+ /halflettertray userdict /halfletter get def
+ /ledgertray userdict /ledger get def
+ /legaltray userdict /legal get def
+ /lettertray userdict /letter get def
+
+% Per-job parameters
+
+/paperfamily 0 def % 0 is US, 1 is European
+/papertray 1 def
+ /setpapertray {statusdict exch /papertray exch put} bind def
+/trayswitch false def % paperout feeds from another tray
+% We don't implement the (undocumented by Adobe) papersize 'operator',
+% because it's very awkward to make it interact properly with all the
+% different ways of setting the paper size.
+%/papersize {/letter true} bind def % <name of paper size>, <short-edge-first-p>
+/appletalktype (LaserWriter) def
+
+%%%%%% The following items are defined in the PostScript Language
+%%%%%% Reference Manual, First Edition, and subsequent 'compatibility'
+%%%%%% documentation from Adobe.
+
+ /checkpassword {statusdict begin .password eq end} bind def
+ /defaulttimeouts {statusdict begin .timeouts aload pop end} bind def
+%/dostartpage
+ /eescratch {pop 0} bind def
+ /idlefonts {statusdict begin mark .idlefonts aload pop end} bind def
+ /jobname () def
+%/jobtimeout
+ /manualfeed false def
+ /manualfeedtimeout 60 def
+ /margins {statusdict begin .topmargin .leftmargin end} bind def
+ /pagecount {4711} bind def
+ /pagestackorder {false} bind def
+ /pagetype 0 def
+ /prefeed false def
+ /printererror {pop pop} bind def
+ /printername {statusdict /.printername get exch copy} bind def
+ /processcolors /processcolors load def % defined in systemdict
+ /product product def % product is defined in systemdict
+ /revision revision def % revision is defined in systemdict
+ /sccbatch {pop 9600 0} bind def
+ /sccinteractive {pop 9600 0} bind def
+ /setdefaulttimeouts {statusdict begin .timeouts astore pop end} bind def
+ /setdostartpage {statusdict exch /dostartpage exch put} bind def
+ /setduplexmode {mark /Duplex 3 -1 roll currentdevice putdeviceprops} bind def
+ /seteescratch {pop pop} bind def
+ /setidlefonts {] statusdict exch /.idlefonts exch put} bind def
+ /setjobtimeout {statusdict exch /jobtimeout exch put} bind def
+ /setmargins
+ { statusdict begin
+ /.leftmargin exch def /.topmargin exch def
+ end
+ } bind def
+
+% The following compatibility operators are only documented by Adobe in a
+% supplement to the Red Book.
+%
+% - pagemargin <offset>
+% - pageparams <width> <height> <offset> <orientation>
+% <width> <height> <orientation> setpage -
+% <offset> setpagemargin -
+% <width> <height> <offset> <orientation> setpageparams -
+%
+% width and height are in default units (and if orientation is odd, are
+% exchanged!). offset is the x margin, also in default units.
+% Unfortunately, because orientation is relative to the device paper feed,
+% it does not have a consistent meaning in terms of image orientation.
+% We follow the convention that ORIENT1 determines the orientation value
+% that means portait: false means 0, true means 1.
+
+ /pagemargin { 0 } bind def
+ /pageparams
+ { currentdevice 1 dict dup /PageSize dup put .getdeviceparams
+ exch pop exch pop aload pop 0 ORIENT1 { 1 } { 0 } ifelse
+ } bind def
+ /setpage
+ { ORIENT1 { 1 } { 0 } ifelse ne {exch} if
+ statusdict /.setpagesize get exec
+ } bind def
+ /setpagemargin {pop} bind def % can't do better without setpagedevice
+ /setpageparams
+ { exch pop ORIENT1 { 1 } { 0 } ifelse ne {exch} if
+ statusdict /.setpagesize get exec
+ } bind def
+ /setpagetype
+ { statusdict begin
+ dup .pagetypenames exch get //systemdict exch get exec
+ /pagetype exch def
+ end
+ } bind def
+ /setpassword
+ {exch checkpassword
+ {statusdict exch /.password exch put true}
+ {pop false}
+ ifelse} bind def
+ /setprintername
+ {dup length string copy statusdict exch /.printername exch put} bind def
+
+% setresolution is not documented by Adobe, but some applications
+% use it anyway, without testing whether or not it is present.
+%
+% <pixels_per_inch> setresolution -
+%
+% sets the resolution of the device.
+
+ /setresolution
+ { mark /HWResolution [ 4 -1 roll dup ] currentdevice putdeviceprops pop
+ initmatrix erasepage
+ } bind def
+ /setsccbatch {pop pop pop} bind def
+ /setsccinteractive {pop pop pop} bind def
+ /settumble {pop} bind def
+ /waittimeout 300 def
+
+%%%%%% End of documented items.
+
+/.setpagesize
+ { mark /HWSize [
+ 4 index 4 index matrix defaultmatrix dtransform
+ abs ceiling cvi exch abs ceiling cvi exch
+ ] currentdevice putdeviceprops pop pop pop
+ initmatrix initclip erasepage
+ } bind def
+/.password 0 def
+/.timeouts [0 60 30] def
+true setdostartpage
+mark setidlefonts
+0 setjobtimeout
+0 0 setmargins
+product setprintername
+
+end % statusdict
+
+% The following contents of serverdict are a complete guess,
+% based on some observed LaserWriter boilerplate.
+
+serverdict begin
+
+ /execjob { } bind def
+% The Red Book implies that something like the following is
+% an appropriate definition of exitserver.
+ /exitserver { clear stop } bind def
+% However, this interacts badly with our standard error handler,
+% so we override it with the following less appropriate definition.
+ /exitserver { 0 ne { clear cleardictstack } if } bind def
+ /setrealdevice { } bind def
+
+end % serverdict
diff --git a/pstoraster/gs_std_e.ps b/pstoraster/gs_std_e.ps
new file mode 100644
index 000000000..79e1dca44
--- /dev/null
+++ b/pstoraster/gs_std_e.ps
@@ -0,0 +1,81 @@
+% 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_std_e.ps 956 2000-03-08 23:15:43Z mike $
+% Define the standard encoding vector.
+/StandardEncoding
+% \00x
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+% \04x
+ /space /exclam /quotedbl /numbersign
+ /dollar /percent /ampersand /quoteright
+ /parenleft /parenright /asterisk /plus
+ /comma /minus /period /slash
+ /zero /one /two /three
+ /four /five /six /seven
+ /eight /nine /colon /semicolon
+ /less /equal /greater /question
+% \10x
+ /at /A /B /C /D /E /F /G
+ /H /I /J /K /L /M /N /O
+ /P /Q /R /S /T /U /V /W
+ /X /Y /Z /bracketleft /backslash /bracketright /asciicircum /underscore
+% \14x
+ /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 /.notdef
+% \20x
+ /.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
+% \24x
+ /.notdef /exclamdown /cent /sterling
+ /fraction /yen /florin /section
+ /currency /quotesingle /quotedblleft /guillemotleft
+ /guilsinglleft /guilsinglright /fi /fl
+ /.notdef /endash /dagger /daggerdbl
+ /periodcentered /.notdef /paragraph /bullet
+ /quotesinglbase /quotedblbase /quotedblright /guillemotright
+ /ellipsis /perthousand /.notdef /questiondown
+% \30x
+ /.notdef /grave /acute /circumflex /tilde /macron /breve /dotaccent
+ /dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek /caron
+ /emdash /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+% \34x
+ /.notdef /AE /.notdef /ordfeminine /.notdef /.notdef /.notdef /.notdef
+ /Lslash /Oslash /OE /ordmasculine /.notdef /.notdef /.notdef /.notdef
+ /.notdef /ae /.notdef /.notdef /.notdef /dotlessi /.notdef /.notdef
+ /lslash /oslash /oe /germandbls /.notdef /.notdef /.notdef /.notdef
+% 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
+0 StandardEncoding .registerencoding
+/StandardEncoding StandardEncoding .defineencoding
diff --git a/pstoraster/gs_sym_e.ps b/pstoraster/gs_sym_e.ps
new file mode 100644
index 000000000..cdd17141f
--- /dev/null
+++ b/pstoraster/gs_sym_e.ps
@@ -0,0 +1,91 @@
+% Copyright (C) 1991, 1994, 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_sym_e.ps 956 2000-03-08 23:15:43Z mike $
+% Define the Symbol encoding vector.
+/currentglobal where
+ { pop currentglobal { setglobal } true setglobal }
+ { { } }
+ifelse
+/SymbolEncoding
+% \000
+ StandardEncoding 0 32 getinterval aload pop % /.notdef
+% \040
+ /space /exclam /universal /numbersign
+ /existential /percent /ampersand /suchthat
+ /parenleft /parenright /asteriskmath /plus
+ /comma /minus /period /slash
+ /zero /one /two /three
+ /four /five /six /seven
+ /eight /nine /colon /semicolon
+ /less /equal /greater /question
+% \100
+ /congruent /Alpha /Beta /Chi
+ /Delta /Epsilon /Phi /Gamma
+ /Eta /Iota /theta1 /Kappa
+ /Lambda /Mu /Nu /Omicron
+ /Pi /Theta /Rho /Sigma
+ /Tau /Upsilon /sigma1 /Omega
+ /Xi /Psi /Zeta /bracketleft
+ /therefore /bracketright /perpendicular /underscore
+% \140
+ /radicalex /alpha /beta /chi
+ /delta /epsilon /phi /gamma
+ /eta /iota /phi1 /kappa
+ /lambda /mu /nu /omicron
+ /pi /theta /rho /sigma
+ /tau /upsilon /omega1 /omega
+ /xi /psi /zeta /braceleft
+ /bar /braceright /similar /.notdef
+% \200
+ StandardEncoding 0 32 getinterval aload pop % /.notdef
+% \240
+ /.notdef /Upsilon1 /minute /lessequal
+ /fraction /infinity /florin /club
+ /diamond /heart /spade /arrowboth
+ /arrowleft /arrowup /arrowright /arrowdown
+ /degree /plusminus /second /greaterequal
+ /multiply /proportional /partialdiff /bullet
+ /divide /notequal /equivalence /approxequal
+ /ellipsis /arrowvertex /arrowhorizex /carriagereturn
+% \300
+ /aleph /Ifraktur /Rfraktur /weierstrass
+ /circlemultiply /circleplus /emptyset /intersection
+ /union /propersuperset /reflexsuperset /notsubset
+ /propersubset /reflexsubset /element /notelement
+ /angle /gradient /registerserif /copyrightserif
+ /trademarkserif /product /radical /dotmath
+ /logicalnot /logicaland /logicalor /arrowdblboth
+ /arrowdblleft /arrowdblup /arrowdblright /arrowdbldown
+% \340
+ /lozenge /angleleft /registersans /copyrightsans
+ /trademarksans /summation /parenlefttp /parenleftex
+ /parenleftbt /bracketlefttp /bracketleftex /bracketleftbt
+ /bracelefttp /braceleftmid /braceleftbt /braceex
+ /euro /angleright /integral /integraltp
+ /integralex /integralbt /parenrighttp /parenrightex
+ /parenrightbt /bracketrighttp /bracketrightex /bracketrightbt
+ /bracerighttp /bracerightmid /bracerightbt /.notdef
+256 packedarray .defineencoding
+2 SymbolEncoding .registerencoding
+exec
diff --git a/pstoraster/gs_ttf.ps b/pstoraster/gs_ttf.ps
new file mode 100644
index 000000000..8fdbd2eb9
--- /dev/null
+++ b/pstoraster/gs_ttf.ps
@@ -0,0 +1,694 @@
+% 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: gs_ttf.ps 956 2000-03-08 23:15:43Z mike $
+% Support code for direct use of TrueType fonts.
+% (Not needed for Type 42 fonts.)
+
+% Thanks to B. Jackowski and GUST (the Polish TeX Users' Group) for
+% the glyf-splitting code.
+
+% ---------------- Font loading machinery ---------------- %
+
+% Augment the FONTPATH machinery so it recognizes TrueType fonts.
+
+/.scanfontheaders where { % only defined if DISKFONTS is recognized
+ pop /.scanfontheaders [ .scanfontheaders aload pop (\000\001\000\000*) ] def
+} if
+
+% <file> <key> .findfontvalue <value> true
+% <file> <key> .findfontvalue false
+% Closes the file in either case.
+/.findnonttfontvalue /.findfontvalue load def
+/.findfontvalue {
+ 1 index read pop 2 index 1 index unread 0 eq {
+ % If this is a font at all, it's a TrueType font.
+ dup /FontType eq {
+ pop closefile 42 true
+ } {
+ dup /FontName eq { pop .findttfontname } { pop closefile false } ifelse
+ } ifelse
+ } {
+ % Not a TrueType font.
+ .findnonttfontvalue
+ } ifelse
+} bind def
+
+% <file> .findttfontname <fname> true
+% <file> .findttfontname false
+% Closes the file in either case.
+/.findttfontname {
+ .loadttfonttables
+ tabdict /name .knownget {
+ dup 8 getu32 f exch setfileposition
+ 12 getu32 string f exch readstring pop
+ 6 findname
+ } {
+ false
+ } ifelse
+ f closefile end end
+} bind def
+
+% Load a font file that might be a TrueType font.
+
+% <file> .loadfontfile -
+/.loadnonttfontfile /.loadfontfile load def
+/.loadfontfile {
+ dup read pop 2 copy unread 0 eq {
+ % If this is a font at all, it's a TrueType font.
+ .loadttfont pop
+ } {
+ % Not a TrueType font.
+ .loadnonttfontfile
+ } ifelse
+} bind def
+
+% ---------------- Automatic Type 42 generation ---------------- %
+
+% Load a TrueType font from a file as a Type 42 PostScript font.
+% The thing that makes this really messy is the handling of encodings.
+% There are 2 interacting tables that affect the encoding:
+% 'cmap' provides multiple maps from character codes to glyph indices
+% 'post' maps glyph indices to glyph names (if present)
+% What we need to get out of this is:
+% Encoding mapping character codes to glyph names
+% (the composition of cmap and post)
+% CharStrings mapping glyph names to glyph indices
+% (the inverse of post)
+% If the post table is missing, we have to take a guess based on the cmap
+% table.
+
+/.loadttfontdict mark
+/orgXUID 107 def % Aladdin Enterprises organization XUID
+/maxstring 32000 def % half the maximum length of a PostScript string,
+ % must be a multiple of 4 (for hmtx / loca / vmtx)
+
+% Define the Macintosh standard mapping from characters to glyph indices.
+/MacRomanEncoding dup .findencoding def
+/MacGlyphEncoding mark
+ /.notdef /.null /CR
+MacRomanEncoding 32 95 getinterval aload pop
+MacRomanEncoding 128 45 getinterval aload pop
+% 143
+ /notequal /AE
+ /Oslash /infinity /plusinus /lessequal /greaterequal
+ /yen /mu1 /partialdiff /summation /product
+ /pi /integral /ordfeminine /ordmasculine /Ohm
+ /ae /oslash /questiondown /exclamdown /logicalnot
+ /radical /florin /approxequal /increment /guillemotleft
+ /guillemotright /ellipsis /nbspace
+MacRomanEncoding 203 12 getinterval aload pop
+ /lozenge
+MacRomanEncoding 216 24 getinterval aload pop
+ /applelogo
+MacRomanEncoding 241 7 getinterval aload pop
+ /overscore
+MacRomanEncoding 249 7 getinterval aload pop
+% 226
+ /Lslash /lslash /Scaron /scaron
+ /Zcaron /zcaron /brokenbar /Eth /eth
+ /Yacute /yacute /Thorn /thorn /minus
+ /multiply /onesuperior /twosuperior /threesuperior /onehalf
+ /onequarter /threequarters /franc /Gbreve /gbreve
+ /Idot /Scedilla /scedilla /Cacute /cacute
+ /Ccaron /ccaron /dmacron
+/packedarray where
+ { pop counttomark packedarray exch pop }
+ { ] readonly }
+ifelse def
+
+% ---- Utilities ---- %
+
+% <string> <index> getu16 <integer>
+/getu16 {
+ 2 copy get 8 bitshift 3 1 roll 1 add get add
+} bind def
+
+% <string> <index> gets16 <integer>
+/gets16 {
+ getu16 16#8000 xor 16#8000 sub
+} bind def
+
+% <string> <index> getu32 <integer>
+/getu32 {
+ 2 copy getu16 16 bitshift 3 1 roll 2 add getu16 add
+} bind def
+
+% <string> <index> gets32 <integer>
+/gets32 {
+ 2 copy gets16 16 bitshift 3 1 roll 2 add getu16 add
+} bind def
+
+% <string> <index> <integer> putu16 -
+/putu16 {
+ 3 copy -8 bitshift put
+ exch 1 add exch 16#ff and put
+} bind def
+
+% <string> <index> <integer> putu32 -
+/putu32 {
+ 3 copy -16 bitshift putu16
+ exch 2 add exch 16#ffff and putu16
+} bind def
+
+% <nametable> <nameid> findname <string> true
+% <nametable> <nameid> findname false
+/findname {
+ false 3 1 roll 0 1 3 index 2 getu16 1 sub {
+ % Stack: false table id index
+ 12 mul 6 add 2 index exch 12 getinterval
+ dup 6 getu16 2 index eq {
+ % We found the name we want.
+ exch pop
+ % Stack: false table record
+ dup 10 getu16 2 index 4 getu16 add
+ 1 index 8 getu16 4 -1 roll 3 1 roll getinterval exch
+ % Stack: false string record
+ % Check for 8- vs. 16-bit characters.
+ is2byte { string2to1 } if true null 4 -1 roll exit
+ } if pop
+ } for pop pop
+} bind def
+
+% <namerecord> is2byte <bool>
+/is2byte {
+ dup 0 getu16 {
+ { pop true } % Apple Unicode
+ { pop false } % Macintosh Script manager
+ { 1 getu16 1 eq } % ISO
+ { 1 getu16 1 eq } % Microsoft
+ } exch get exec
+} bind def
+
+% <string2> string2to1 <string>
+/string2to1 {
+ dup length 2 idiv string dup
+ 0 1 3 index length 1 sub {
+ 3 index 1 index 2 mul 1 add get put dup
+ } for pop exch pop
+} bind def
+
+% <array> <lt-proc> sort <array>
+/sort {
+ 1 index length 1 sub -1 1 {
+ 2 index exch 2 copy get 3 copy % arr proc arr i arr[i] arr i arr[i]
+ 0 1 3 index 1 sub {
+ 3 index 1 index get % arr proc arr i arr[i] arr imax amax j arr[j]
+ 2 index 1 index 10 index exec { % ... amax < arr[j]
+ 4 2 roll
+ } if pop pop
+ } for % arr proc arr i arr[i] arr imax amax
+ 4 -1 roll exch 4 1 roll put put
+ } for pop
+} def
+
+% Each procedure in this dictionary is called as follows:
+% -mark- encodingtable <<proc>> -mark- glyphindices...
+/cmapformats mark
+ 0 % Apple standard 1-to-1 mapping.
+ { 6 256 getinterval { } forall
+ } bind
+ 4 % Microsoft/Adobe segmented mapping.
+ { /etab exch def
+ /nseg2 etab 6 getu16 def
+ 14 /endc etab 2 index nseg2 getinterval def
+ % The Apple TrueType documentation omits the 2-byte
+ % 'reserved pad' that follows the endCount vector!
+ 2 add
+ nseg2 add /startc etab 2 index nseg2 getinterval def
+ nseg2 add /iddelta etab 2 index nseg2 getinterval def
+ nseg2 add /idroff etab 2 index nseg2 getinterval def
+ % The following hack allows us to properly handle
+ % idiosyncratic fonts that start at 0xf000:
+ /firstcode startc 0 getu16 16#ff00 and dup 16#f000 ne { pop 0 } if def
+ pop /numcodes counttomark 1 sub def
+ 0 2 nseg2 3 sub
+ { /i2 exch def
+ /scode startc i2 getu16 def
+ /ecode endc i2 getu16 def
+ numcodes scode firstcode sub
+ % Hack for fonts that have only 0x0000 and 0xf000 ranges
+ dup 16#e000 ge { 255 and } if
+ exch sub 0 max dup { 0 exch } repeat
+ ecode scode sub 1 add add numcodes add /numcodes exch def
+ /delta iddelta i2 gets16 def
+ DEBUG {
+ (scode=) print scode =only
+ ( ecode=) print ecode =only
+ ( delta=) print delta =only
+ ( droff=) print idroff i2 getu16 =
+ } if
+ idroff i2 getu16 dup 0 eq {
+ pop scode delta add 65535 and 1 ecode delta add 65535 and { } for
+ }
+ { % The +2 is for the 'reserved pad'.
+ /gloff exch 14 nseg2 3 mul add 2 add i2 add add def
+ 0 1 ecode scode sub {
+ 2 mul gloff add etab exch getu16
+ dup 0 ne { delta add 65535 and } if
+ } for
+ } ifelse
+ }
+ for
+ } bind
+ 6 % Single interval lookup.
+ { dup 6 getu16 { 0 exch } repeat
+ dup 8 getu16 0 exch 1 exch 1 sub
+ { 2 mul 10 add 2 copy getu16 exch pop exch }
+ for pop
+ } bind
+.dicttomark readonly def % cmapformats
+
+% <cmaptab> cmaparray -mark- <glyphs> ...
+/cmaparray {
+ mark exch dup 0 getu16 cmapformats exch .knownget {
+ exec
+ } {
+ (Can't handle format ) print 0 getu16 = flush
+ 0 1 255 { } for
+ } ifelse
+ DEBUG {
+ ([) print counttomark 1 sub -1 0 { index =only ( ) print } for (]) =
+ } if
+} bind def
+
+% Each procedure in this dictionary is called as follows:
+% posttable <<proc>> glyphencoding
+/postformats mark
+ 16#00010000 { % 258 standard Macintosh glyphs.
+ MacGlyphEncoding
+ }
+ 16#00020000 { % Detailed map, required by Microsoft fonts.
+ /postglyphs exch def
+ postglyphs 32 getu16 /numglyphs exch def
+ /glyphnames numglyphs 2 mul 34 add def
+ [ 0 1 numglyphs 1 sub
+ { 2 mul 34 add postglyphs exch getu16
+ dup 258 lt
+ { MacGlyphEncoding exch get
+ }
+ { 258 sub glyphnames exch
+ { postglyphs 1 index get 1 add add }
+ repeat
+ 1 add postglyphs exch 2 copy 1 sub get getinterval cvn
+ }
+ ifelse
+ }
+ for ]
+ } bind
+ 16#00030000 { % No map.
+ pop [ ]
+ } bind
+.dicttomark readonly def % postformats
+
+% Each procedure in this dictionary is called as follows:
+% <file> <length> -proc- <string|array_of_strings>
+% Note that each table must have an even length, because of a strange
+% Adobe requirement that each sfnts entry have even length.
+/readtables mark
+ % Ordinary tables
+ (cmap) { .readtable }
+ (head) 1 index
+ (hhea) 1 index
+ (name) 1 index
+ (post) 1 index
+ (vhea) 1 index
+ % Big tables
+ (glyf) { .readbigtable }
+ (loca) 1 index
+ (hmtx) 1 index
+ (vmtx) 1 index
+.dicttomark readonly def % readtables
+
+% Read a table as a single string.
+% <file> <length> .readtable <string>
+/.readtable {
+ dup dup 1 and add string
+ % Stack: f len str
+ dup 0 4 -1 roll getinterval
+ % Stack: f str str1
+ 3 -1 roll exch readstring pop pop
+} bind def
+
+% Read a big table (one that may exceed 64K).
+% <file> <length> .readbigtable <string[s]>
+/.readbigtable {
+ dup 65400 lt {
+ .readtable
+ } {
+ currentuserparams /VMReclaim get -2 vmreclaim
+ [ 4 2 roll {
+ % Stack: mark ... f left
+ dup maxstring le { exit } if
+ 1 index maxstring string readstring pop 3 1 roll maxstring sub
+ } loop .readtable ]
+ exch vmreclaim
+ } ifelse
+} bind def
+
+.dicttomark readonly def % .loadttfontdict
+
+% <tab> .printtab -
+/.printtab {
+ dup 0 4 getinterval print ( ) print
+ dup 8 getu32 =only ( ) print
+ 12 getu32 =
+} bind def
+
+% <file> .loadttfonttables -
+% Pushes .loadttfontdict & scratch dict on d-stack.
+% Defines f, offsets, tables, tabdict, tabs.
+/.loadttfonttables {
+ .loadttfontdict begin
+ 40 dict begin
+ /f exch def
+ /offsets f 12 string readstring pop def
+ /tables f offsets 4 getu16 16 mul string readstring pop def
+ /tabdict tables length 16 idiv dict def
+ % tabs = tables we want to keep, sorted by file position.
+ /tabs [ 0 16 tables length 1 sub {
+ tables exch 16 getinterval
+ DEBUG { dup .printtab } if
+ dup 0 4 getinterval readtables 1 index known {
+ tabdict exch 2 index put
+ } {
+ pop pop
+ } ifelse
+ } for ] {
+ exch 8 getu32 exch 8 getu32 lt
+ } sort def
+} bind def
+
+% - .readttdata -
+% Read data. Updates offsets, tabs; stores data in tabdict.
+/.readttdata {
+ /fpos offsets length tables length add def
+ /sfpos offsets length tabs length 16 mul add def
+ offsets 4 tabs length putu16
+ tabs {
+ dup 0 4 getinterval /tname exch def
+ dup 8 getu32 /tpos exch def
+ dup 12 getu32 /tlen exch def
+ 8 sfpos putu32
+ % Skip data between the end of the previous table and
+ % the beginning of this one, if any.
+ tpos fpos gt {
+ f tpos fpos sub () /SubFileDecode filter dup flushfile closefile
+ /fpos tpos def
+ } if
+ f tlen readtables tname get exec
+ tabdict tname 3 -1 roll put
+ /fpos fpos tlen add def
+ % Round up the table length to an even value.
+ /sfpos sfpos tlen dup 1 and add add def
+ } forall
+} bind def
+
+% Find the string in a list of strings that includes a given index.
+% <strings> <index> .findseg <string> <index'>
+/.findseg {
+ exch {
+ dup length 2 index gt { exch exit } if
+ length sub
+ } forall
+} bind def
+
+% - .makesfnts -
+% Defines checksum, getloca, head, locatable, numglyphs, post, sfnts, upem
+/.makesfnts {
+ .readttdata
+ /head tabdict /head get def
+ /checksum head 8 getu32 def
+ /locatable tabdict /loca get def
+ /post tabdict /post .knownget not { null } if def
+ /numglyphs
+ locatable dup type /stringtype eq
+ { length }
+ { 0 exch { length add } forall }
+ ifelse % no def yet
+ locatable type /stringtype eq {
+ /.indexloca {} def
+ } {
+ /.indexloca /.findseg load def
+ } ifelse
+ head 50 getu16 0 ne {
+ /getloca {
+ 2 bitshift locatable exch .indexloca getu32
+ } def
+ 4 idiv 1 sub
+ } {
+ /getloca {
+ dup add locatable exch .indexloca getu16 dup add
+ } def
+ 2 idiv 1 sub
+ } ifelse def % numglyphs
+ % If necessary, re-partition the glyfs.
+ tabdict /glyf get dup type /stringtype ne {
+ .dividesfnts tabdict /glyf 3 -1 roll put
+ } {
+ pop
+ } ifelse
+ /sfnts [
+ offsets tabs { concatstrings } forall
+ tabs {
+ 0 4 getinterval tabdict exch get
+ dup type /stringtype ne { aload pop } if
+ } forall
+ ] def
+} bind def
+
+% - .getcmap -
+% Defines cmapsub, cmaptab
+/.getcmap {
+ tabdict /cmap get
+ % The Apple cmap format is no help in determining the encoding.
+ % Look for a Microsoft table. If we can't find one,
+ % just use the first table, whatever it is.
+ dup 4 8 getinterval exch % the default
+ 0 1 2 index 2 getu16 1 sub
+ { 8 mul 4 add 1 index exch 8 getinterval
+ dup 0 getu16 3 eq { exch 3 -1 roll pop exit } if pop
+ }
+ for
+ % Stack: subentry table
+ /cmapsub 2 index def
+ exch 4 getu32 1 index length 1 index sub getinterval
+ /cmaptab exch def
+} bind def
+
+% <glyfs> .dividesfnts <glyfs'>
+/.dividesfnts {
+ /glyfs exch def
+ /len1 0 glyfs { length add } forall def
+ % Determine where to split the glyfs by scanning loca.
+ % The very last entry in loca may be bogus.
+ %
+ % Construct splitarray, the array of final lengths of
+ % the sfnts entries covering the glyfs (i.e., all but
+ % the first and last sfnts entries).
+ /prevsplit 0 def
+ /prevboundary 0 def
+ /splitarray [
+ 0 1 numglyphs 1 sub {
+ getloca dup prevsplit maxstring add gt {
+ prevboundary prevsplit sub exch
+ /prevsplit prevboundary def
+ } if
+ /prevboundary exch def
+ } for
+ len1 prevsplit sub
+ ] def
+ currentuserparams /VMReclaim get -2 vmreclaim
+ [
+ % Re-split the sfnts glyfs strings according to splitarray.
+ % We do this by iterating over the final segments defined
+ % by splitarray, and constructing them from pieces of the
+ % current glyfs strings. We recycle the current strings
+ % when possible, to avoid stressing the allocator.
+ /sfnt_idx 0 def
+ /strpos 0 def
+ /avail () def
+ splitarray {
+ /seglen exch def
+ /segpos 0 def
+ avail length seglen ge
+ { avail 0 seglen getinterval /avail () def } { seglen string }
+ ifelse
+ {
+ /str glyfs sfnt_idx get def
+ /strlen str length def
+ /strleft strlen strpos sub def
+ seglen segpos sub strleft lt { exit } if
+ % Copy the (rest of the) string into the new segment.
+ % We know strleft <= segleft.
+ dup segpos str strpos strleft getinterval putinterval
+ /segpos segpos strleft add def
+ /avail str def
+ /sfnt_idx sfnt_idx 1 add def
+ /strpos 0 def
+ segpos seglen eq { exit } if
+ } loop
+ % Fill up the segment with an initial piece of the next
+ % existing glyfs string. We know strleft > segleft.
+ /segleft seglen segpos sub def
+ dup segpos str strpos segleft getinterval putinterval
+ /strpos strpos segleft add def
+ } forall
+ ]
+ exch vmreclaim
+} bind def
+
+% - .ttkeys <key> <value> ...
+/.ttkeys {
+ /upem head 18 getu16 def
+ /FontMatrix matrix
+ /FontBBox [ 36 2 42 { head exch gets16 upem div } for ]
+ tabdict /name .knownget {
+ % Find the names from the 'name' table.
+ /names exch def
+ /FontName names 6 findname not { checksum 16 8 string cvrs } if
+ /fontname 1 index def
+ /FontInfo mark
+ names 0 findname { /Notice exch } if
+ names 1 findname { /FamilyName exch } if
+ names 4 findname { /FullName exch } if
+ names 5 findname { /Version exch } if
+ } {
+ % No name table, fabricate a FontName.
+ /FontName checksum 16 8 string cvrs
+ /fontname 1 index def
+ /FontInfo mark
+ } ifelse
+ % Stack: ... /FontInfo mark key1 value1 ...
+ post null ne {
+ /ItalicAngle post 4 gets32 65536.0 div
+ /isFixedPitch post 12 getu32 0 ne
+ /UnderlinePosition post 8 gets16 upem div
+ /UnderlineThickness post 10 gets16 upem div
+ } if
+ counttomark 0 ne { .dicttomark } { pop pop } ifelse
+ /XUID [orgXUID 42 checksum]
+ /sfnts sfnts
+ DEBUG {
+ tabs { .printtab } forall
+ [ sfnts { length } forall ] ==
+ } if
+} bind def
+
+% -mark- <key> <value> ... .definettfont <font>
+/.definettfont {
+ /FontType 42
+ /PaintType 0
+ % See if we have PostScript glyph name information.
+ /glyphencoding post null eq {
+ [ ]
+ } {
+ postformats post 0 getu32 .knownget { post exch exec } { [ ] } ifelse
+ } ifelse
+ % If necessary, fabricate additional glyphencoding entries
+ % to cover all of loca.
+ dup length numglyphs lt {
+ [ exch aload pop
+ counttomark 1 numglyphs 1 sub {
+ =string cvs (_) exch concatstrings cvn
+ } for ]
+ } if def
+ /Encoding
+ cmaptab cmaparray
+ counttomark array astore
+ { glyphencoding exch get } forall
+ counttomark 256 sub dup 0 ge {
+ { pop } repeat
+ } { neg { /.notdef } repeat
+ } ifelse ]
+ % Until we can compute the MD5 fingerprint,
+ % just use the precomputed checksum.
+ /CharStrings glyphencoding dup length dict
+ 0 1 3 index length 1 sub {
+ % Stack: glyphencoding dict index
+ 2 index 1 index get 2 index 1 index known {
+ pop pop
+ } {
+ 2 index exch 3 -1 roll put
+ } ifelse
+ } for exch pop readonly
+ .dicttomark
+ end end dup /FontName get exch definefont
+} bind def
+
+% Create a string with N CIDs from the top of the stack.
+% <cid1> ... <cidN> <N> .makecidmap <string>
+/.makecidmap {
+ dup 2 mul string dup 3 -1 roll 1 sub 2 mul -2 0 {
+ % Stack: cids str str i2
+ 2 copy 5 index -8 bitshift put
+ 1 add 4 -1 roll 16#ff and put dup
+ } for pop
+} bind def
+
+% -mark- <key> <value> ... .definettcidfont <font>
+/.definettcidfont {
+ /CIDFontName fontname
+ /CIDFontType 2
+ /CIDSystemInfo mark
+ /Registry (Adobe)
+ /Ordering (Japan1) % adhoc
+ /Supplement 0
+ .dicttomark
+ /CharStrings mark /.notdef 0 .dicttomark
+ cmaptab cmaparray
+ counttomark /cidcount exch def
+ cidcount maxstring le {
+ % Use a single string.
+ cidcount .makecidmap exch pop
+ } {
+ % We must use 2 strings.
+ maxstring .makecidmap counttomark 1 add 1 roll
+ counttomark .makecidmap exch pop exch 2 array astore
+ } ifelse
+ /CIDMap exch
+ /CIDCount cidcount
+ /GDBytes 2
+ .dicttomark
+ end end dup /CIDFontName get exch /CIDFont defineresource
+} bind def
+
+% <file> .loadttfont <type42font>
+/.loadttfont {
+ .loadttfonttables
+ .makesfnts
+ .getcmap
+ mark
+ .ttkeys
+ .definettfont
+} bind def
+
+% <file> .loadttcidfont <cidtype2font>
+/.loadttcidfont {
+ .loadttfonttables
+ .makesfnts
+ .getcmap
+ mark
+ .ttkeys
+ .definettcidfont
+} bind def
diff --git a/pstoraster/gs_typ32.ps b/pstoraster/gs_typ32.ps
new file mode 100644
index 000000000..444decd17
--- /dev/null
+++ b/pstoraster/gs_typ32.ps
@@ -0,0 +1,134 @@
+% 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_typ32.ps 956 2000-03-08 23:15:43Z mike $
+% Initialization file for Type 32 fonts.
+
+% ------ Type 32 fonts ------ %
+
+% We need LanguageLevel 2 or higher in order to have defineresource.
+languagelevel dup 2 max .setlanguagelevel
+
+/BitmapFontInit mark
+
+/.makeglyph32 systemdict /.makeglyph32 get
+systemdict /.makeglyph32 .undef
+
+/addglyph { % ([wx wy llx lly urx ury] |
+ % [w0x w0y llx lly urx ury w1x w1y vx vy])
+ % <bitmap> <cid> <type32font> addglyph -
+ 1 index dup 2 index .removeglyphs
+ 22 string .makeglyph32
+ % Stack: metrics bitmap cid font metstr
+ 3 index () ne {
+ % Use G4 encoding to compress the bitmap.
+ % Define a string large enough to hold the metrics,
+ % an uncompressed bitmap (worst case = 5x expansion),
+ % and the 2 RTC codes (3 bytes).
+ dup length 4 index length 5 mul add 10 add string
+ % Stack: metrics bitmap cid font metstr buffer
+ dup 0 3 index putinterval
+ dup 2 index length 1 index length 1 index sub getinterval
+ % Stack: metrics bitmap cid font metstr buffer bitbuf
+ mark /Columns 8 index dup 4 get exch 2 get sub
+ /Rows 10 index dup 5 get exch 3 get sub
+ /K -1 /EndOfBlock true /BlackIs1 true
+ .dicttomark /CCITTFaxEncode filter
+ % Stack: metrics bitmap cid font metstr buffer filter
+ dup 6 index writestring closefile
+ % Find the end of the data by scanning backwards for the RTC.
+ % There are 2 RTCs x 12 bits = 3 bytes to remove.
+ {
+ dup dup length 1 sub get 0 ne { exit } if
+ 0 1 index length 1 sub getinterval
+ } loop
+ 0 1 index length 3 sub getinterval
+ exch pop % metstr
+ } if
+ 1 index /CharStrings get 3 index 3 -1 roll put
+ pop pop pop pop
+} obind
+
+/removeall { % <type32font> removeall -
+ 0 65535 2 index removeglyphs pop
+} obind
+
+/.removeglyphs systemdict /.removeglyphs get
+systemdict /.removeglyphs .undef
+
+/removeglyphs { % <cid_min> <cid_max> <type32font> .removeglyphs -
+ 3 copy .removeglyphs
+ dup /CharStrings get dup {
+ % Stack: cidmin cidmax font CharStrings cid bitmap
+ pop dup 5 index ge { dup 4 index le { 2 copy undef } if } if pop
+ } forall pop pop pop pop
+} obind
+
+.dicttomark /ProcSet defineresource pop
+
+/.cidfonttypes where { pop } { /.cidfonttypes 6 dict def } ifelse
+.cidfonttypes begin
+
+4 % CIDFontType 4 = FontType 32
+{ dup /FontType 32 put
+ dup /CharStrings 20 dict put
+ 1 index exch .buildfont32 exch pop
+} bind def
+
+end % .cidfonttypes
+
+% Define the BuildGlyph procedure.
+% Since Type 32 fonts are indexed by CID, there is no BuildChar procedure.
+% The name %Type32BuildGlyph is known to the interpreter.
+(%Type32BuildGlyph) cvn { % <font> <cid> %Type32BuildGlyph -
+ 1 index /CharStrings get
+ % Stack: font cid CharStrings
+ dup 2 index .knownget { exch pop } { 0 get } ifelse
+ % Stack: font cid cstr
+ dup .getmetrics32
+ dup 14 gt {
+ 11 1 roll setcachedevice2
+ } {
+ 7 1 roll setcachedevice
+ } ifelse
+ % Stack: font cid cstr w h nmetrics
+ 4 -1 roll exch 1 index length 1 index sub getinterval
+ % Stack: font cid w h bitstr
+ dup () eq {
+ pop
+ } {
+ mark /Columns 4 index /Rows 5 index /K -1 /EndOfBlock false /BlackIs1 true
+ .dicttomark /CCITTFaxDecode filter 2 index 2 index true
+ % Stack: font cid w h filter w h true
+ [ 1 0 0 1 0 7 index ] 5 -1 roll imagemask
+ } ifelse
+ pop pop pop pop
+} bind def
+
+systemdict /.getmetrics32 .undef
+
+buildfontdict 32 /.buildfont32 cvx put
+
+32 dup /FontType defineresource pop
+
+.setlanguagelevel
diff --git a/pstoraster/gs_typ42.ps b/pstoraster/gs_typ42.ps
new file mode 100644
index 000000000..c50726802
--- /dev/null
+++ b/pstoraster/gs_typ42.ps
@@ -0,0 +1,52 @@
+% 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_typ42.ps 956 2000-03-08 23:15:43Z mike $
+% Type 42 font support code.
+
+% Here are the BuildChar and BuildGlyph implementation for Type 42 fonts.
+% The names %Type42BuildChar and %Type42BuildGlyph are known to the
+% interpreter. The real work is done in an operator:
+% <font> <code|name> <name> <glyphindex> .type42execchar -
+
+(%Type42BuildChar) cvn % <font> <code> %Type42BuildChar -
+ { 1 index /Encoding get 1 index get .type42build
+ } bind def
+(%Type42BuildGlyph) cvn % <font> <name> %Type42BuildGlyph -
+ { dup .type42build
+ } bind def
+/.type42build % <font> <code|name> <name> .type42build -
+ { 2 index begin
+ 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
+ end .type42execchar
+ } bind def
+
+% Register the font type for definefont.
+buildfontdict 42 /.buildfont42 cvx put
diff --git a/pstoraster/gs_type1.ps b/pstoraster/gs_type1.ps
new file mode 100644
index 000000000..9a8a09c01
--- /dev/null
+++ b/pstoraster/gs_type1.ps
@@ -0,0 +1,145 @@
+% 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: gs_type1.ps 956 2000-03-08 23:15:43Z mike $
+% Type 1 font support code.
+
+% The standard representation for PostScript compatible fonts is described
+% in the book "Adobe Type 1 Font Format", published by Adobe Systems Inc.
+
+% Define an augmented version of .buildfont1 that inserts UnderlinePosition
+% and UnderlineThickness entries in FontInfo if they aren't there already.
+% (This works around the incorrect assumption, made by many word processors,
+% that these entries are present in the built-in fonts.)
+/.buildfont1
+ { dup /FontInfo known not
+ { .growfontdict dup /FontInfo 2 dict put }
+ if
+ dup dup /FontInfo get dup dup
+ /UnderlinePosition known exch /UnderlineThickness known and
+ { pop pop % entries already present
+ }
+ { dup length 2 add dict .copydict
+ dup /UnderlinePosition known not
+ { dup /UnderlinePosition 3 index /FontBBox .knownget
+ { 1 get 2 div } % 1/2 the font descent
+ { -100 } ifelse put
+ }
+ if
+ dup /UnderlineThickness known not
+ { dup /UnderlineThickness 3 index /FontBBox .knownget
+ { dup 3 get exch 1 get sub 20 div } % 1/20 the font height
+ { 50 } ifelse put
+ }
+ if
+ 1 index /FontInfo get wcheck not { readonly } if
+ /FontInfo exch put
+ }
+ ifelse //.buildfont1
+ } bind def
+% If the diskfont feature isn't included, define a dummy .loadfontdict.
+/.loadfontdict where
+ { pop }
+ { /.loadfontdict 0 dict readonly def }
+ifelse
+/.loadfontfile % <file> .loadfontfile -
+ { mark exch
+ DISKFONTS { .loadfontdict begin } if
+ % In order to load fonts reliably, we should push systemdict
+ % here. However, Ed Taft says that Adobe implementations
+ % push userdict and nothing else!
+ % We really would just like systemdict on the stack,
+ % but fonts produced by Fontographer require a writable dictionary.
+ % However, we can't use any of the other well-known dictionaries
+ % (such as userdict), since the whole point of pushing systemdict
+ % is to make sure that nothing important has been redefined.
+ userdict begin
+ % We can't just use `run', because we want to check for .PFB files.
+ currentpacking
+ { false setpacking .loadfont1 true setpacking }
+ { .loadfont1 }
+ ifelse end
+ { stop } if
+ DISKFONTS { end } if
+ cleartomark
+ } bind def
+/.loadfont1 % <file> .loadfont1 <errorflag>
+ { % We would like to use `false /PFBDecode filter',
+ % but this occasionally produces a whitespace character as
+ % the first of an eexec section, so we can't do it.
+ % Also, since the real input file never reaches EOF if we are using
+ % a PFBDecode filter (the filter stops just after reading the last
+ % character), we must explicitly close the real file in this case.
+ % Since the file might leave garbage on the operand stack,
+ % we have to create a procedure to close the file reliably.
+ { dup read not { -1 } if
+ 2 copy unread 16#80 eq
+ { [ exch dup true /PFBDecode filter cvx exch cvlit
+ /closefile .systemvar ]
+ }
+ if cvx exec
+ } stopped
+ $error /newerror get and dup { .clearerror } if
+ } bind def
+
+
+% The CharStrings are a dictionary in which the key is the character name,
+% and the value is a compressed and encrypted representation of a path.
+% For detailed information, see the book "Adobe Type 1 Font Format",
+% published by Adobe Systems Inc.
+
+% Here are the BuildChar and BuildGlyph implementation for Type 1 fonts.
+% The names %Type1BuildChar and %Type1BuildGlyph are known to the interpreter.
+% The real work is done in an operator:
+% <font> <code|name> <name> <charstring> .type1execchar -
+
+(%Type1BuildChar) cvn % <font> <code> %Type1BuildChar -
+ { 1 index /Encoding get 1 index get .type1build
+ } bind def
+(%Type1BuildGlyph) cvn % <font> <name> %Type1BuildGlyph -
+ { dup .type1build
+ } bind def
+/.type1build % <font> <code|name> <name> .type1build -
+ { 2 index begin
+ 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
+ end .type1execchar
+ } bind def
+% CCRun is an undocumented procedure provided for Type 4 fonts.
+1183615869 internaldict begin
+/CCRun % <font> <code|name> <charstring> CCRun -
+ { 1 index dup type /integertype eq
+ { 3 index /Encoding get exch get }
+ if exch .type1execchar
+ } bind def
+end
+
+% Register the font types for definefont.
+buildfontdict 1 /.buildfont1 cvx put
+buildfontdict 4 /.buildfont4 cvx put
diff --git a/pstoraster/gs_wan_e.ps b/pstoraster/gs_wan_e.ps
new file mode 100644
index 000000000..c58ab2021
--- /dev/null
+++ b/pstoraster/gs_wan_e.ps
@@ -0,0 +1,52 @@
+% Copyright (C) 1994, 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_wan_e.ps 956 2000-03-08 23:15:43Z mike $
+% Define the WinAnsi encoding vector.
+/currentglobal where
+ { pop currentglobal { setglobal } true setglobal }
+ { { } }
+ifelse
+/WinAnsiEncoding
+ISOLatin1Encoding 0 39 getinterval aload pop
+ /quotesingle
+ISOLatin1Encoding 40 5 getinterval aload pop
+ /hyphen
+ISOLatin1Encoding 46 50 getinterval aload pop
+ /grave
+ISOLatin1Encoding 97 30 getinterval aload pop
+ /bullet
+% \20x
+ /bullet /bullet /quotesinglbase /florin
+ /quotedblbase /ellipsis /dagger /daggerdbl
+ /circumflex /perthousand /Scaron /guilsinglleft
+ /OE /bullet /bullet /bullet
+ /bullet /quoteleft /quoteright /quotedblleft
+ /quotedblright /bullet /endash /emdash
+ /tilde /trademark /scaron /guilsinglright
+ /oe /bullet /bullet /Ydieresis
+ISOLatin1Encoding 160 96 getinterval aload pop
+256 packedarray
+4 1 index .registerencoding
+.defineencoding
+exec
diff --git a/pstoraster/gs_wl1_e.ps b/pstoraster/gs_wl1_e.ps
new file mode 100644
index 000000000..13a0e1c87
--- /dev/null
+++ b/pstoraster/gs_wl1_e.ps
@@ -0,0 +1,74 @@
+% 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_wl1_e.ps 956 2000-03-08 23:15:43Z mike $
+% Define the Windows 3.1 Latin 1 encoding vector (H-P Symbol set 19U).
+/currentglobal where
+ { pop currentglobal { setglobal } true setglobal }
+ { { } }
+ifelse
+/Win31Latin1Encoding
+ISOLatin1Encoding 0 39 getinterval aload pop
+ /quotesingle
+ISOLatin1Encoding 40 5 getinterval aload pop
+ /hyphen
+ISOLatin1Encoding 46 50 getinterval aload pop
+ /grave
+ISOLatin1Encoding 97 30 getinterval aload pop
+ /graybox
+% \20x
+ /.notdef /.notdef /quotesinglbase /florin
+ /quotedblbase /ellipsis /dagger /daggerdbl
+ /circumflex /perthousand /Scaron /guilsinglleft
+ /OE /.notdef /.notdef /.notdef
+ /.notdef /quoteleft /quoteright /quotedblleft
+ /quotedblright /bullet /endash /emdash
+ /tilde /trademark /scaron /guilsinglright
+ /oe /.notdef /.notdef /Ydieresis
+ /.notdef /exclamdown /cent /sterling
+ /currency /yen /brokenbar /section
+ /dieresis /copyright /ordfeminine /guillemotleft
+ /logicalnot /softhyphen /registered /overscore
+ /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
+ /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
+256 packedarray .defineencoding
+exec
diff --git a/pstoraster/gs_wl2_e.ps b/pstoraster/gs_wl2_e.ps
new file mode 100644
index 000000000..22310a977
--- /dev/null
+++ b/pstoraster/gs_wl2_e.ps
@@ -0,0 +1,74 @@
+% 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_wl2_e.ps 956 2000-03-08 23:15:43Z mike $
+% Define the Windows 3.1 Latin 2 encoding vector (H-P Symbol set 9E).
+/currentglobal where
+ { pop currentglobal { setglobal } true setglobal }
+ { { } }
+ifelse
+/Win32Latin2Encoding
+ISOLatin1Encoding 0 39 getinterval aload pop
+ /quotesingle
+ISOLatin1Encoding 40 5 getinterval aload pop
+ /hyphen
+ISOLatin1Encoding 46 50 getinterval aload pop
+ /grave
+ISOLatin1Encoding 97 30 getinterval aload pop
+ /graybox
+% \20x
+ /.notdef /.notdef /quotesinglbase /.notdef
+ /quotedblbase /ellipsis /dagger /daggerdbl
+ /.notdef /perthousand /Scaron /guilsinglleft
+ /Sacute /Tcaron /Zcaron /Zacute
+ /.notdef /quoteleft /quoteright /quotedblleft
+ /quotedblright /bullet /endash /emdash
+ /.notdef /trademark /scaron /guilsinglright
+ /sacute /tcaron /zcaron /zacute
+ /.notdef /caron /breve /Lslash
+ /currency /Aogonek /brokenbar /section
+ /dieresis /copyright /Scedilla /guillemotleft
+ /logicalnot /softhyphen /registered /Zdotaccent
+ /degree /plusminus /ogonek /lslash
+ /acute /mu /paragraph /periodcentered
+ /cedilla /aogonek /scedilla /guillemotright
+ /Lcaron /hungarumlaut /lcaron /zdotaccent
+% \30x
+ /Racute /Aacute /Acircumflex /Abreve
+ /Adieresis /Lacute /Cacute /Ccedilla
+ /Ccaron /Eacute /Eogonek /Edieresis
+ /Ecaron /Iacute /Icircumflex /Dcaron
+ /Dcroat /Nacute /Ncaron /Oacute
+ /Ocircumflex /Ohungarumlaut /Odieresis /multiply
+ /Rcaron /Uring /Uacute /Uhungarumlaut
+ /Udieresis /Yacute /Tcommaaccent /germandbls
+ /racute /aacute /acircumflex /abreve
+ /adieresis /lacute /cacute /ccedilla
+ /ccaron /eacute /eogonek /edieresis
+ /ecaron /iacute /icircumflex /dcaron
+ /dcroat /nacute /ncaron /oacute
+ /ocircumflex /ohungarumlaut /odieresis /divide
+ /rcaron /uring /uacute /uhungarumlaut
+ /udieresis /yacute /tcommaaccent /dotaccent
+256 packedarray .defineencoding
+exec
diff --git a/pstoraster/gs_wl5_e.ps b/pstoraster/gs_wl5_e.ps
new file mode 100644
index 000000000..9ea9224db
--- /dev/null
+++ b/pstoraster/gs_wl5_e.ps
@@ -0,0 +1,74 @@
+% 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_wl5_e.ps 956 2000-03-08 23:15:43Z mike $
+% Define the Windows 3.1 Latin 5 encoding vector (H-P Symbol set 5T).
+/currentglobal where
+ { pop currentglobal { setglobal } true setglobal }
+ { { } }
+ifelse
+/Win32Latin5Encoding
+ISOLatin1Encoding 0 39 getinterval aload pop
+ /quotesingle
+ISOLatin1Encoding 40 5 getinterval aload pop
+ /hyphen
+ISOLatin1Encoding 46 50 getinterval aload pop
+ /grave
+ISOLatin1Encoding 97 30 getinterval aload pop
+ /graybox
+% \20x
+ /.notdef /.notdef /quotesinglbase /florin
+ /quotedblbase /ellipsis /dagger /daggerdbl
+ /circumflex /perthousand /Scaron /guilsinglleft
+ /OE /.notdef /.notdef /.notdef
+ /.notdef /quoteleft /quoteright /quotedblleft
+ /quotedblright /bullet /endash /emdash
+ /tilde /trademark /scaron /guilsinglright
+ /oe /.notdef /.notdef /Ydieresis
+ /.notdef /exclamdown /cent /sterling
+ /currency /yen /brokenbar /section
+ /dieresis /copyright /ordfeminine /guillemotleft
+ /logicalnot /softhyphen /registered /overscore
+ /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
+ /Gbreve /Ntilde /Ograve /Oacute
+ /Ocircumflex /Otilde /Odieresis /multiply
+ /Oslash /Ugrave /Uacute /Ucircumflex
+ /Udieresis /Idotaccent /Scedilla /germandbls
+ /agrave /aacute /acircumflex /atilde
+ /adieresis /aring /ae /ccedilla
+ /egrave /eacute /ecircumflex /edieresis
+ /igrave /iacute /icircumflex /idieresis
+ /gbreve /ntilde /ograve /oacute
+ /ocircumflex /otilde /odieresis /divide
+ /oslash /ugrave /uacute /ucircumflex
+ /udieresis /dotlessi /scedilla /ydieresis
+256 packedarray .defineencoding
+exec
diff --git a/pstoraster/gsalloc.c b/pstoraster/gsalloc.c
new file mode 100644
index 000000000..25ad5577d
--- /dev/null
+++ b/pstoraster/gsalloc.c
@@ -0,0 +1,1621 @@
+/* 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$ */
+/* Standard memory allocator */
+#include "gx.h"
+#include "memory_.h"
+#include "gserrors.h"
+#include "gsmdebug.h"
+#include "gsstruct.h"
+#include "gxalloc.h"
+#include "stream.h" /* for clearing stream list */
+
+/*
+ * This allocator produces tracing messages of the form
+ * [aNMOTS]...
+ * where
+ * N is the VM space number,
+ * M is : for movable objects, | for immovable,
+ * O is {alloc = +, free = -, grow = >, shrink = <},
+ * T is {bytes = b, object = <, ref = $, string = >}, and
+ * S is {freelist = F, LIFO = space, own chunk = L, lost = #,
+ * lost own chunk = ~, other = .}.
+ */
+#ifdef DEBUG
+private void
+alloc_trace(const char *chars, gs_ref_memory_t * imem, client_name_t cname,
+ gs_memory_type_ptr_t stype, uint size, const void *ptr)
+{
+ if_debug7('A', "[a%d%s]%s %s(%u) %s0x%lx\n",
+ imem->space, chars, client_name_string(cname),
+ (ptr == 0 || stype == 0 ? "" :
+ struct_type_name_string(stype)),
+ size, (chars[1] == '+' ? "= " : ""), (ulong) ptr);
+}
+private bool
+alloc_size_is_ok(gs_memory_type_ptr_t stype)
+{
+ return (stype->ssize > 0 && stype->ssize < 0x100000);
+}
+# define ALLOC_CHECK_SIZE(stype)\
+ BEGIN\
+ if (!alloc_size_is_ok(stype)) {\
+ lprintf2("size of struct type 0x%lx is 0x%lx!\n",\
+ (ulong)(stype), (ulong)((stype)->ssize));\
+ return 0;\
+ }\
+ END
+#else
+# define alloc_trace(chars, imem, cname, stype, size, ptr) DO_NOTHING
+# define ALLOC_CHECK_SIZE(stype) DO_NOTHING
+#endif
+
+/*
+ * The structure descriptor for allocators. Even though allocators
+ * are allocated outside GC space, they reference objects within it.
+ */
+public_st_ref_memory();
+#define mptr ((gs_ref_memory_t *)vptr)
+private
+ENUM_PTRS_BEGIN(ref_memory_enum_ptrs) return 0;
+
+ENUM_PTR3(0, gs_ref_memory_t, streams, changes, saved);
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(ref_memory_reloc_ptrs)
+{
+ RELOC_PTR(gs_ref_memory_t, streams);
+ RELOC_PTR(gs_ref_memory_t, changes);
+ /* Don't relocate the saved pointer now -- see igc.c for details. */
+ mptr->reloc_saved = RELOC_OBJ(mptr->saved);
+}
+RELOC_PTRS_END
+
+/* Forward references */
+private ulong compute_free_objects(P1(gs_ref_memory_t *));
+private obj_header_t *alloc_obj(P5(gs_ref_memory_t *, ulong, gs_memory_type_ptr_t, bool, client_name_t));
+private chunk_t *alloc_acquire_chunk(P4(gs_ref_memory_t *, ulong, bool, client_name_t));
+private chunk_t *alloc_add_chunk(P3(gs_ref_memory_t *, ulong, client_name_t));
+void alloc_close_chunk(P1(gs_ref_memory_t *));
+
+/*
+ * Define the standard implementation (with garbage collection)
+ * of Ghostscript's memory manager interface.
+ */
+/* Raw memory procedures */
+private gs_memory_proc_alloc_bytes(i_alloc_bytes_immovable);
+private gs_memory_proc_resize_object(i_resize_object);
+private gs_memory_proc_free_object(i_free_object);
+private gs_memory_proc_status(i_status);
+private gs_memory_proc_free_all(i_free_all);
+private gs_memory_proc_consolidate_free(i_consolidate_free);
+
+/* Object memory procedures */
+private gs_memory_proc_alloc_bytes(i_alloc_bytes);
+private gs_memory_proc_alloc_struct(i_alloc_struct);
+private gs_memory_proc_alloc_struct(i_alloc_struct_immovable);
+private gs_memory_proc_alloc_byte_array(i_alloc_byte_array);
+private gs_memory_proc_alloc_byte_array(i_alloc_byte_array_immovable);
+private gs_memory_proc_alloc_struct_array(i_alloc_struct_array);
+private gs_memory_proc_alloc_struct_array(i_alloc_struct_array_immovable);
+private gs_memory_proc_object_size(i_object_size);
+private gs_memory_proc_object_type(i_object_type);
+private gs_memory_proc_alloc_string(i_alloc_string);
+private gs_memory_proc_alloc_string(i_alloc_string_immovable);
+private gs_memory_proc_resize_string(i_resize_string);
+private gs_memory_proc_free_string(i_free_string);
+private gs_memory_proc_register_root(i_register_root);
+private gs_memory_proc_unregister_root(i_unregister_root);
+private gs_memory_proc_enable_free(i_enable_free);
+
+/* We export the procedures for subclasses. */
+const gs_memory_procs_t gs_ref_memory_procs =
+{
+ /* Raw memory procedures */
+ i_alloc_bytes_immovable,
+ i_resize_object,
+ i_free_object,
+ i_status,
+ i_free_all,
+ i_consolidate_free,
+ /* Object memory procedures */
+ i_alloc_bytes,
+ i_alloc_struct,
+ i_alloc_struct_immovable,
+ i_alloc_byte_array,
+ i_alloc_byte_array_immovable,
+ i_alloc_struct_array,
+ i_alloc_struct_array_immovable,
+ i_object_size,
+ i_object_type,
+ i_alloc_string,
+ i_alloc_string_immovable,
+ i_resize_string,
+ i_free_string,
+ i_register_root,
+ i_unregister_root,
+ i_enable_free
+};
+
+/*
+ * Allocate and mostly initialize the state of an allocator (system, global,
+ * or local). Does not initialize global or space.
+ */
+private void *ialloc_solo(P3(gs_raw_memory_t *, gs_memory_type_ptr_t,
+ chunk_t **));
+gs_ref_memory_t *
+ialloc_alloc_state(gs_raw_memory_t * parent, uint chunk_size)
+{
+ chunk_t *cp;
+ gs_ref_memory_t *iimem = ialloc_solo(parent, &st_ref_memory, &cp);
+
+ if (iimem == 0)
+ return 0;
+ iimem->procs = gs_ref_memory_procs;
+ iimem->parent = parent;
+ iimem->chunk_size = chunk_size;
+ iimem->large_size = ((chunk_size / 4) & -obj_align_mod) + 1;
+ iimem->is_controlled = false;
+ iimem->gc_status.vm_threshold = chunk_size * 3L;
+ iimem->gc_status.max_vm = max_long;
+ iimem->gc_status.psignal = NULL;
+ iimem->gc_status.enabled = false;
+ iimem->previous_status.allocated = 0;
+ iimem->previous_status.used = 0;
+ ialloc_reset(iimem);
+ iimem->cfirst = iimem->clast = cp;
+ ialloc_set_limit(iimem);
+ iimem->cc.cbot = iimem->cc.ctop = 0;
+ iimem->pcc = 0;
+ iimem->streams = 0;
+ iimem->roots = 0;
+ iimem->num_contexts = 0;
+ iimem->saved = 0;
+ return iimem;
+}
+
+/* Allocate a 'solo' object with its own chunk. */
+private void *
+ialloc_solo(gs_raw_memory_t * parent, gs_memory_type_ptr_t pstype,
+ chunk_t ** pcp)
+{ /*
+ * We can't assume that the parent uses the same object header
+ * that we do, but the GC requires that allocators have
+ * such a header. Therefore, we prepend one explicitly.
+ */
+ chunk_t *cp =
+ gs_raw_alloc_struct_immovable(parent, &st_chunk,
+ "ialloc_solo(chunk)");
+ uint csize =
+ round_up(sizeof(chunk_head_t) + sizeof(obj_header_t) +
+ pstype->ssize,
+ obj_align_mod);
+ byte *cdata = gs_alloc_bytes_immovable(parent, csize, "ialloc_solo");
+ obj_header_t *obj = (obj_header_t *) (cdata + sizeof(chunk_head_t));
+
+ if (cp == 0 || cdata == 0)
+ return 0;
+ alloc_init_chunk(cp, cdata, cdata + csize, false, (chunk_t *) NULL);
+ cp->cbot = cp->ctop;
+ cp->cprev = cp->cnext = 0;
+ /* Construct the object header "by hand". */
+ obj->o_large = 0;
+ obj->o_size = pstype->ssize;
+ obj->o_type = pstype;
+ *pcp = cp;
+ return (void *)(obj + 1);
+}
+
+/*
+ * Add a chunk to an externally controlled allocator. Such allocators
+ * allocate all objects as immovable, are not garbage-collected, and
+ * don't attempt to acquire additional memory on their own.
+ */
+int
+ialloc_add_chunk(gs_ref_memory_t *imem, ulong space, client_name_t cname)
+{
+ chunk_t *cp;
+
+ /* Allow acquisition of this chunk. */
+ imem->is_controlled = false;
+ imem->large_size = imem->chunk_size;
+ imem->limit = max_long;
+ imem->gc_status.max_vm = max_long;
+
+ /* Acquire the chunk. */
+ cp = alloc_add_chunk(imem, space, cname);
+
+ /*
+ * Make all allocations immovable. Since the "movable" allocators
+ * allocate within existing chunks, whereas the "immovable" ones
+ * allocate in new chunks, we equate the latter to the former, even
+ * though this seems backwards.
+ */
+ imem->procs.alloc_bytes_immovable = imem->procs.alloc_bytes;
+ imem->procs.alloc_struct_immovable = imem->procs.alloc_struct;
+ imem->procs.alloc_byte_array_immovable = imem->procs.alloc_byte_array;
+ imem->procs.alloc_struct_array_immovable = imem->procs.alloc_struct_array;
+ imem->procs.alloc_string_immovable = imem->procs.alloc_string;
+
+ /* Disable acquisition of additional chunks. */
+ imem->is_controlled = true;
+ imem->limit = 0;
+
+ return (cp ? 0 : gs_note_error(gs_error_VMerror));
+}
+
+/* Prepare for a GC by clearing the stream list. */
+/* This probably belongs somewhere else.... */
+void
+ialloc_gc_prepare(gs_ref_memory_t * mem)
+{ /*
+ * We have to unlink every stream from its neighbors,
+ * so that referenced streams don't keep all streams around.
+ */
+ while (mem->streams != 0) {
+ stream *s = mem->streams;
+
+ mem->streams = s->next;
+ s->prev = s->next = 0;
+ }
+}
+
+/* Initialize after a save. */
+void
+ialloc_reset(gs_ref_memory_t * mem)
+{
+ mem->cfirst = 0;
+ mem->clast = 0;
+ mem->cc.rcur = 0;
+ mem->cc.rtop = 0;
+ mem->cc.has_refs = false;
+ mem->allocated = 0;
+ mem->inherited = 0;
+ mem->changes = 0;
+ ialloc_reset_free(mem);
+}
+
+/* Initialize after a save or GC. */
+void
+ialloc_reset_free(gs_ref_memory_t * mem)
+{
+ int i;
+ obj_header_t **p;
+
+ mem->lost.objects = 0;
+ mem->lost.refs = 0;
+ mem->lost.strings = 0;
+ mem->cfreed.cp = 0;
+ for (i = 0, p = &mem->freelists[0]; i < num_freelists; i++, p++)
+ *p = 0;
+}
+
+/* Set the allocation limit after a change in one or more of */
+/* vm_threshold, max_vm, or enabled, or after a GC. */
+void
+ialloc_set_limit(register gs_ref_memory_t * mem)
+{ /*
+ * The following code is intended to set the limit so that
+ * we stop allocating when allocated + previous_status.allocated
+ * exceeds the lesser of max_vm or (if GC is enabled)
+ * gc_allocated + vm_threshold.
+ */
+ ulong max_allocated =
+ (mem->gc_status.max_vm > mem->previous_status.allocated ?
+ mem->gc_status.max_vm - mem->previous_status.allocated :
+ 0);
+
+ if (mem->gc_status.enabled) {
+ ulong limit = mem->gc_allocated + mem->gc_status.vm_threshold;
+
+ if (limit < mem->previous_status.allocated)
+ mem->limit = 0;
+ else {
+ limit -= mem->previous_status.allocated;
+ mem->limit = min(limit, max_allocated);
+ }
+ } else
+ mem->limit = max_allocated;
+ if_debug7('0', "[0]space=%d, max_vm=%ld, prev.alloc=%ld, enabled=%d,\n\
+ gc_alloc=%ld, threshold=%ld => limit=%ld\n",
+ mem->space, (long)mem->gc_status.max_vm,
+ (long)mem->previous_status.allocated,
+ mem->gc_status.enabled, (long)mem->gc_allocated,
+ (long)mem->gc_status.vm_threshold, (long)mem->limit);
+}
+
+/*
+ * Free all the memory owned by the allocator, except the allocator itself.
+ * Note that this only frees memory at the current save level: the client
+ * is responsible for restoring to the outermost level if desired.
+ */
+private void
+i_free_all(gs_memory_t * mem, uint free_mask, client_name_t cname)
+{
+ gs_ref_memory_t * const imem = (gs_ref_memory_t *)mem;
+ chunk_t *cp;
+
+ if (free_mask & FREE_ALL_DATA) {
+ chunk_t *csucc;
+
+ /*
+ * Free the chunks in reverse order, to encourage LIFO behavior.
+ * Don't free the chunk holding the allocator itself.
+ */
+ for (cp = imem->clast; cp != 0; cp = csucc) {
+ csucc = cp->cprev; /* save before freeing */
+ if (cp->cbase + sizeof(obj_header_t) != (byte *)mem)
+ alloc_free_chunk(cp, imem);
+ }
+ }
+ if (free_mask & FREE_ALL_ALLOCATOR) {
+ /* Free the chunk holding the allocator itself. */
+ for (cp = imem->clast; cp != 0; cp = cp->cprev)
+ if (cp->cbase + sizeof(obj_header_t) == (byte *)mem) {
+ alloc_free_chunk(cp, imem);
+ break;
+ }
+ }
+}
+
+/* ================ Accessors ================ */
+
+/* Get the size of an object from the header. */
+private uint
+i_object_size(gs_memory_t * mem, const void /*obj_header_t */ *obj)
+{
+ return pre_obj_contents_size((const obj_header_t *)obj - 1);
+}
+
+/* Get the type of a structure from the header. */
+private gs_memory_type_ptr_t
+i_object_type(gs_memory_t * mem, const void /*obj_header_t */ *obj)
+{
+ return ((const obj_header_t *)obj - 1)->o_type;
+}
+
+/* Get the GC status of a memory. */
+void
+gs_memory_gc_status(const gs_ref_memory_t * mem, gs_memory_gc_status_t * pstat)
+{
+ *pstat = mem->gc_status;
+}
+
+/* Set the GC status of a memory. */
+void
+gs_memory_set_gc_status(gs_ref_memory_t * mem, const gs_memory_gc_status_t * pstat)
+{
+ mem->gc_status = *pstat;
+ ialloc_set_limit(mem);
+}
+
+/* ================ Objects ================ */
+
+/* Allocate a small object quickly if possible. */
+/* The size must be substantially less than max_uint. */
+/* ptr must be declared as obj_header_t *. */
+/* pfl must be declared as obj_header_t **. */
+#define IF_FREELIST_ALLOC(ptr, imem, size, pstype, pfl)\
+ if ( size <= max_freelist_size &&\
+ *(pfl = &imem->freelists[(size + obj_align_mask) >> log2_obj_align_mod]) != 0\
+ )\
+ { ptr = *pfl;\
+ *pfl = *(obj_header_t **)ptr;\
+ ptr[-1].o_size = size;\
+ ptr[-1].o_type = pstype;\
+ /* If debugging, clear the block in an attempt to */\
+ /* track down uninitialized data errors. */\
+ gs_alloc_fill(ptr, gs_alloc_fill_alloc, size);
+#define ELSEIF_LIFO_ALLOC(ptr, imem, size, pstype)\
+ }\
+ else if ( (imem->cc.ctop - (byte *)(ptr = (obj_header_t *)imem->cc.cbot))\
+ >= size + (obj_align_mod + sizeof(obj_header_t) * 2) &&\
+ size < imem->large_size\
+ )\
+ { imem->cc.cbot = (byte *)ptr + obj_size_round(size);\
+ ptr->o_large = 0;\
+ ptr->o_size = size;\
+ ptr->o_type = pstype;\
+ ptr++;\
+ /* If debugging, clear the block in an attempt to */\
+ /* track down uninitialized data errors. */\
+ gs_alloc_fill(ptr, gs_alloc_fill_alloc, size);
+#define ELSE_ALLOC\
+ }\
+ else
+
+private byte *
+i_alloc_bytes(gs_memory_t * mem, uint size, client_name_t cname)
+{
+ gs_ref_memory_t * const imem = (gs_ref_memory_t *)mem;
+ obj_header_t *obj;
+ obj_header_t **pfl;
+
+ IF_FREELIST_ALLOC(obj, imem, size, &st_bytes, pfl)
+ alloc_trace(":+bF", imem, cname, NULL, size, obj);
+ ELSEIF_LIFO_ALLOC(obj, imem, size, &st_bytes)
+ alloc_trace(":+b ", imem, cname, NULL, size, obj);
+ ELSE_ALLOC
+ {
+ obj = alloc_obj(imem, size, &st_bytes, false, cname);
+ if (obj == 0)
+ return 0;
+ alloc_trace(":+b.", imem, cname, NULL, size, obj);
+ }
+ return (byte *) obj;
+}
+private byte *
+i_alloc_bytes_immovable(gs_memory_t * mem, uint size, client_name_t cname)
+{
+ gs_ref_memory_t * const imem = (gs_ref_memory_t *)mem;
+ obj_header_t *obj = alloc_obj(imem, size, &st_bytes, true, cname);
+
+ if (obj == 0)
+ return 0;
+ alloc_trace("|+b.", imem, cname, NULL, size, obj);
+ return (byte *) obj;
+}
+private void *
+i_alloc_struct(gs_memory_t * mem, gs_memory_type_ptr_t pstype,
+ client_name_t cname)
+{
+ gs_ref_memory_t * const imem = (gs_ref_memory_t *)mem;
+ uint size = pstype->ssize;
+ obj_header_t *obj;
+ obj_header_t **pfl;
+
+ ALLOC_CHECK_SIZE(pstype);
+ IF_FREELIST_ALLOC(obj, imem, size, pstype, pfl)
+ alloc_trace(":+<F", imem, cname, pstype, size, obj);
+ ELSEIF_LIFO_ALLOC(obj, imem, size, pstype)
+ alloc_trace(":+< ", imem, cname, pstype, size, obj);
+ ELSE_ALLOC
+ {
+ obj = alloc_obj(imem, size, pstype, false, cname);
+ if (obj == 0)
+ return 0;
+ alloc_trace(":+<.", imem, cname, pstype, size, obj);
+ }
+ return obj;
+}
+private void *
+i_alloc_struct_immovable(gs_memory_t * mem, gs_memory_type_ptr_t pstype,
+ client_name_t cname)
+{
+ gs_ref_memory_t * const imem = (gs_ref_memory_t *)mem;
+ uint size = pstype->ssize;
+ obj_header_t *obj;
+
+ ALLOC_CHECK_SIZE(pstype);
+ obj = alloc_obj(imem, size, pstype, true, cname);
+ alloc_trace("|+<.", imem, cname, pstype, size, obj);
+ return obj;
+}
+private byte *
+i_alloc_byte_array(gs_memory_t * mem, uint num_elements, uint elt_size,
+ client_name_t cname)
+{
+ gs_ref_memory_t * const imem = (gs_ref_memory_t *)mem;
+ obj_header_t *obj = alloc_obj(imem, (ulong) num_elements * elt_size,
+ &st_bytes, false, cname);
+
+ if_debug6('A', "[a%d:+b.]%s -bytes-*(%lu=%u*%u) = 0x%lx\n",
+ imem->space, client_name_string(cname),
+ (ulong) num_elements * elt_size,
+ num_elements, elt_size, (ulong) obj);
+ return (byte *) obj;
+}
+private byte *
+i_alloc_byte_array_immovable(gs_memory_t * mem, uint num_elements,
+ uint elt_size, client_name_t cname)
+{
+ gs_ref_memory_t * const imem = (gs_ref_memory_t *)mem;
+ obj_header_t *obj = alloc_obj(imem, (ulong) num_elements * elt_size,
+ &st_bytes, true, cname);
+
+ if_debug6('A', "[a%d|+b.]%s -bytes-*(%lu=%u*%u) = 0x%lx\n",
+ imem->space, client_name_string(cname),
+ (ulong) num_elements * elt_size,
+ num_elements, elt_size, (ulong) obj);
+ return (byte *) obj;
+}
+private void *
+i_alloc_struct_array(gs_memory_t * mem, uint num_elements,
+ gs_memory_type_ptr_t pstype, client_name_t cname)
+{
+ gs_ref_memory_t * const imem = (gs_ref_memory_t *)mem;
+ obj_header_t *obj;
+
+ ALLOC_CHECK_SIZE(pstype);
+ obj = alloc_obj(imem,
+ (ulong) num_elements * pstype->ssize,
+ pstype, false, cname);
+ if_debug7('A', "[a%d:+<.]%s %s*(%lu=%u*%u) = 0x%lx\n",
+ imem->space,
+ client_name_string(cname), struct_type_name_string(pstype),
+ (ulong) num_elements * pstype->ssize,
+ num_elements, pstype->ssize, (ulong) obj);
+ return (char *)obj;
+}
+private void *
+i_alloc_struct_array_immovable(gs_memory_t * mem, uint num_elements,
+ gs_memory_type_ptr_t pstype, client_name_t cname)
+{
+ gs_ref_memory_t * const imem = (gs_ref_memory_t *)mem;
+ obj_header_t *obj;
+
+ ALLOC_CHECK_SIZE(pstype);
+ obj = alloc_obj(imem,
+ (ulong) num_elements * pstype->ssize,
+ pstype, true, cname);
+ if_debug7('A', "[a%d|+<.]%s %s*(%lu=%u*%u) = 0x%lx\n",
+ imem->space,
+ client_name_string(cname), struct_type_name_string(pstype),
+ (ulong) num_elements * pstype->ssize,
+ num_elements, pstype->ssize, (ulong) obj);
+ return (char *)obj;
+}
+private void *
+i_resize_object(gs_memory_t * mem, void *obj, uint new_num_elements,
+ client_name_t cname)
+{
+ gs_ref_memory_t * const imem = (gs_ref_memory_t *)mem;
+ obj_header_t *pp = (obj_header_t *) obj - 1;
+ gs_memory_type_ptr_t pstype = pp->o_type;
+ ulong old_size = pre_obj_contents_size(pp);
+ ulong new_size = (ulong) pstype->ssize * new_num_elements;
+ ulong new_size_rounded;
+ void *new_obj;
+
+ if ((byte *)obj + obj_align_round(old_size) == imem->cc.cbot &&
+ imem->cc.ctop - (byte *)obj >=
+ (new_size_rounded = obj_align_round(new_size))
+ ) {
+ imem->cc.cbot = (byte *)obj + new_size_rounded;
+ pp->o_size = new_size;
+ if_debug8('A', "[a%d:%c%c ]%s %s(%lu=>%lu) 0x%lx\n",
+ imem->space,
+ (new_size > old_size ? '>' : '<'),
+ (pstype == &st_bytes ? 'b' : '<'),
+ client_name_string(cname),
+ struct_type_name_string(pstype),
+ old_size, new_size, (ulong) obj);
+ return obj;
+ }
+ /* Punt. */
+ new_obj = gs_alloc_struct_array(mem, new_num_elements, void,
+ pstype, cname);
+ if (new_obj == 0)
+ return 0;
+ memcpy(new_obj, obj, min(old_size, new_size));
+ gs_free_object(mem, obj, cname);
+ return new_obj;
+}
+private void
+i_free_object(gs_memory_t * mem, void *ptr, client_name_t cname)
+{
+ gs_ref_memory_t * const imem = (gs_ref_memory_t *)mem;
+ obj_header_t *pp;
+ gs_memory_type_ptr_t pstype;
+
+ struct_proc_finalize((*finalize));
+ uint size;
+
+ if (ptr == 0)
+ return;
+ pp = (obj_header_t *) ptr - 1;
+ pstype = pp->o_type;
+#ifdef DEBUG
+ if (gs_debug_c('?')) {
+ chunk_locator_t cld;
+
+ if (pstype == &st_free) {
+ lprintf2("%s: object 0x%lx already free!\n",
+ client_name_string(cname), (ulong) ptr);
+ return; /*gs_abort(); */
+ }
+ /* Check that this allocator owns the object being freed. */
+ cld.memory = imem;
+ while ((cld.cp = cld.memory->clast),
+ !chunk_locate_ptr(ptr, &cld)
+ ) {
+ if (!cld.memory->saved) {
+ lprintf3("%s: freeing 0x%lx, not owned by memory 0x%lx!\n",
+ client_name_string(cname), (ulong) ptr,
+ (ulong) mem);
+ return; /*gs_abort(); */
+ }
+ /****** HACK: we know the saved state is the first ******
+ ****** member of an alloc_save_t. ******/
+ cld.memory = (gs_ref_memory_t *) cld.memory->saved;
+ }
+ /* Check that the object is in the allocated region. */
+ if (cld.memory == imem && cld.cp == imem->pcc)
+ cld.cp = &imem->cc;
+ if (!(ptr_between((const byte *)pp, cld.cp->cbase,
+ cld.cp->cbot))
+ ) {
+ lprintf5("%s: freeing 0x%lx,\n\toutside chunk 0x%lx cbase=0x%lx, cbot=0x%lx!\n",
+ client_name_string(cname), (ulong) ptr,
+ (ulong) cld.cp, (ulong) cld.cp->cbase,
+ (ulong) cld.cp->cbot);
+ return; /*gs_abort(); */
+ }
+ }
+#endif
+ size = pre_obj_contents_size(pp);
+ finalize = pstype->finalize;
+ if (finalize != 0) {
+ if_debug3('u', "[u]finalizing %s 0x%lx (%s)\n",
+ struct_type_name_string(pstype),
+ (ulong) ptr, client_name_string(cname));
+ (*finalize) (ptr);
+ }
+ if ((byte *) ptr + obj_align_round(size) == imem->cc.cbot) {
+ alloc_trace(":-o ", imem, cname, pstype, size, ptr);
+ gs_alloc_fill(ptr, gs_alloc_fill_free, size);
+ imem->cc.cbot = (byte *) pp;
+ return;
+ }
+ if (pp->o_large) {
+ /*
+ * We gave this object its own chunk. Free the entire chunk,
+ * unless it belongs to an older save level, in which case
+ * we mustn't overwrite it.
+ */
+ chunk_locator_t cl;
+
+#ifdef DEBUG
+ {
+ chunk_locator_t cld;
+
+ cld.memory = imem;
+ cld.cp = 0;
+ if (gs_debug_c('a'))
+ alloc_trace(
+ (chunk_locate_ptr(ptr, &cld) ? ":-oL" : ":-o~"),
+ imem, cname, pstype, size, ptr);
+ }
+#endif
+ cl.memory = imem;
+ cl.cp = 0;
+ if (chunk_locate_ptr(ptr, &cl)) {
+ if (!imem->is_controlled)
+ alloc_free_chunk(cl.cp, imem);
+ return;
+ }
+ /* Don't overwrite even if gs_alloc_debug is set. */
+ }
+ if (size <= max_freelist_size &&
+ obj_align_round(size) >= sizeof(obj_header_t *)
+ ) {
+ /*
+ * Put the object on a freelist, unless it belongs to
+ * an older save level, in which case we mustn't
+ * overwrite it.
+ */
+ imem->cfreed.memory = imem;
+ if (chunk_locate(ptr, &imem->cfreed)) {
+ obj_header_t **pfl =
+ &imem->freelists[(size + obj_align_mask) >>
+ log2_obj_align_mod];
+
+ pp->o_type = &st_free; /* don't confuse GC */
+ gs_alloc_fill(ptr, gs_alloc_fill_free, size);
+ *(obj_header_t **) ptr = *pfl;
+ *pfl = (obj_header_t *) ptr;
+ alloc_trace(":-oF", imem, cname, pstype, size, ptr);
+ return;
+ }
+ /* Don't overwrite even if gs_alloc_debug is set. */
+ } else {
+ pp->o_type = &st_free; /* don't confuse GC */
+ gs_alloc_fill(ptr, gs_alloc_fill_free, size);
+ }
+ alloc_trace(":-o#", imem, cname, pstype, size, ptr);
+ imem->lost.objects += obj_size_round(size);
+}
+private byte *
+i_alloc_string(gs_memory_t * mem, uint nbytes, client_name_t cname)
+{
+ gs_ref_memory_t * const imem = (gs_ref_memory_t *)mem;
+ byte *str;
+
+top:if (imem->cc.ctop - imem->cc.cbot > nbytes) {
+ if_debug4('A', "[a%d:+> ]%s(%u) = 0x%lx\n", imem->space,
+ client_name_string(cname), nbytes,
+ (ulong) (imem->cc.ctop - nbytes));
+ str = imem->cc.ctop -= nbytes;
+ gs_alloc_fill(str, gs_alloc_fill_alloc, nbytes);
+ return str;
+ }
+ if (nbytes > string_space_quanta(max_uint - sizeof(chunk_head_t)) *
+ string_data_quantum
+ ) { /* Can't represent the size in a uint! */
+ return 0;
+ }
+ if (nbytes >= imem->large_size) { /* Give it a chunk all its own. */
+ return i_alloc_string_immovable(mem, nbytes, cname);
+ } else { /* Add another chunk. */
+ chunk_t *cp =
+ alloc_acquire_chunk(imem, (ulong) imem->chunk_size, true, "chunk");
+
+ if (cp == 0)
+ return 0;
+ alloc_close_chunk(imem);
+ imem->pcc = cp;
+ imem->cc = *imem->pcc;
+ gs_alloc_fill(imem->cc.cbase, gs_alloc_fill_free,
+ imem->cc.climit - imem->cc.cbase);
+ goto top;
+ }
+}
+private byte *
+i_alloc_string_immovable(gs_memory_t * mem, uint nbytes, client_name_t cname)
+{
+ gs_ref_memory_t * const imem = (gs_ref_memory_t *)mem;
+ byte *str;
+ /* Give it a chunk all its own. */
+ uint asize = string_chunk_space(nbytes) + sizeof(chunk_head_t);
+ chunk_t *cp = alloc_acquire_chunk(imem, (ulong) asize, true,
+ "large string chunk");
+
+ if (cp == 0)
+ return 0;
+ str = cp->ctop = cp->climit - nbytes;
+ if_debug4('a', "[a%d|+>L]%s(%u) = 0x%lx\n", imem->space,
+ client_name_string(cname), nbytes, (ulong) str);
+ gs_alloc_fill(str, gs_alloc_fill_alloc, nbytes);
+ return str;
+}
+private byte *
+i_resize_string(gs_memory_t * mem, byte * data, uint old_num, uint new_num,
+ client_name_t cname)
+{
+ gs_ref_memory_t * const imem = (gs_ref_memory_t *)mem;
+ byte *ptr;
+
+ if (data == imem->cc.ctop &&
+ (new_num < old_num ||
+ imem->cc.ctop - imem->cc.cbot > new_num - old_num)
+ ) { /* Resize in place. */
+ ptr = data + old_num - new_num;
+ if_debug6('A', "[a%d:%c> ]%s(%u->%u) 0x%lx\n",
+ imem->space, (new_num > old_num ? '>' : '<'),
+ client_name_string(cname), old_num, new_num,
+ (ulong) ptr);
+ imem->cc.ctop = ptr;
+ memmove(ptr, data, min(old_num, new_num));
+#ifdef DEBUG
+ if (new_num > old_num)
+ gs_alloc_fill(ptr + old_num, gs_alloc_fill_alloc,
+ new_num - old_num);
+ else
+ gs_alloc_fill(data, gs_alloc_fill_free, old_num - new_num);
+#endif
+ } else { /* Punt. */
+ ptr = gs_alloc_string(mem, new_num, cname);
+ if (ptr == 0)
+ return 0;
+ memcpy(ptr, data, min(old_num, new_num));
+ gs_free_string(mem, data, old_num, cname);
+ }
+ return ptr;
+}
+private void
+i_free_string(gs_memory_t * mem, byte * data, uint nbytes,
+ client_name_t cname)
+{
+ gs_ref_memory_t * const imem = (gs_ref_memory_t *)mem;
+ if (data == imem->cc.ctop) {
+ if_debug4('A', "[a%d:-> ]%s(%u) 0x%lx\n", imem->space,
+ client_name_string(cname), nbytes, (ulong) data);
+ imem->cc.ctop += nbytes;
+ } else {
+ if_debug4('A', "[a%d:->#]%s(%u) 0x%lx\n", imem->space,
+ client_name_string(cname), nbytes, (ulong) data);
+ imem->lost.strings += nbytes;
+ }
+ gs_alloc_fill(data, gs_alloc_fill_free, nbytes);
+}
+
+private void
+i_status(gs_memory_t * mem, gs_memory_status_t * pstat)
+{
+ gs_ref_memory_t * const imem = (gs_ref_memory_t *)mem;
+ ulong unused = imem->lost.refs + imem->lost.strings;
+ ulong inner = 0;
+
+ alloc_close_chunk(imem);
+ /* Add up unallocated space within each chunk. */
+ /* Also keep track of space allocated to inner chunks, */
+ /* which are included in previous_status.allocated. */
+ {
+ const chunk_t *cp = imem->cfirst;
+
+ while (cp != 0) {
+ unused += cp->ctop - cp->cbot;
+ if (cp->outer)
+ inner += cp->cend - (byte *) cp->chead;
+ cp = cp->cnext;
+ }
+ }
+ unused += compute_free_objects(imem);
+ pstat->used = imem->allocated + inner - unused +
+ imem->previous_status.used;
+ pstat->allocated = imem->allocated +
+ imem->previous_status.allocated;
+}
+
+private void
+i_enable_free(gs_memory_t * mem, bool enable)
+{
+ if (enable)
+ mem->procs.free_object = i_free_object,
+ mem->procs.free_string = i_free_string;
+ else
+ mem->procs.free_object = gs_ignore_free_object,
+ mem->procs.free_string = gs_ignore_free_string;
+}
+
+/* ------ Internal procedures ------ */
+
+/* Compute the amount of free object space by scanning free lists. */
+private ulong
+compute_free_objects(gs_ref_memory_t * mem)
+{
+ ulong unused = mem->lost.objects;
+ int i;
+
+ /* Add up space on free lists. */
+ for (i = 0; i < num_freelists; i++) {
+ uint free_size =
+ (i << log2_obj_align_mod) + sizeof(obj_header_t);
+ const obj_header_t *pfree;
+
+ for (pfree = mem->freelists[i]; pfree != 0;
+ pfree = *(const obj_header_t * const *)pfree
+ )
+ unused += free_size;
+ }
+ return unused;
+}
+
+/* Allocate an object. This handles all but the fastest, simplest case. */
+private obj_header_t *
+alloc_obj(gs_ref_memory_t * mem, ulong lsize, gs_memory_type_ptr_t pstype,
+ bool immovable, client_name_t cname)
+{
+ obj_header_t *ptr;
+
+ if (lsize >= mem->large_size || immovable) {
+ /*
+ * Give the object a chunk all its own. Note that this case does
+ * not occur if is_controlled is true.
+ */
+ ulong asize =
+ ((lsize + obj_align_mask) & -obj_align_mod) +
+ sizeof(obj_header_t);
+ chunk_t *cp =
+ alloc_acquire_chunk(mem, asize + sizeof(chunk_head_t), false,
+ "large object chunk");
+
+ if (cp == 0)
+ return 0;
+ ptr = (obj_header_t *) cp->cbot;
+ cp->cbot += asize;
+ ptr->o_large = 1;
+ pre_obj_set_large_size(ptr, lsize);
+ } else {
+ uint asize = obj_size_round((uint) lsize);
+ bool consolidate = mem->is_controlled;
+
+ while (mem->cc.ctop -
+ (byte *) (ptr = (obj_header_t *) mem->cc.cbot)
+ <= asize + sizeof(obj_header_t)) {
+ if (consolidate) {
+ /* Try consolidating free space. */
+ gs_consolidate_free((gs_memory_t *)mem);
+ consolidate = false;
+ continue;
+ } else {
+ /* Add another chunk. */
+ chunk_t *cp =
+ alloc_add_chunk(mem, (ulong)mem->chunk_size, "chunk");
+
+ if (cp == 0)
+ return 0;
+ }
+ }
+ mem->cc.cbot = (byte *) ptr + asize;
+ ptr->o_large = 0;
+ ptr->o_size = (uint) lsize;
+ }
+ ptr->o_type = pstype;
+ ptr++;
+ gs_alloc_fill(ptr, gs_alloc_fill_alloc, lsize);
+ return ptr;
+}
+
+/* Consolidate free objects. */
+void
+ialloc_consolidate_free(gs_ref_memory_t *mem)
+{
+ chunk_t *cp;
+ chunk_t *cprev;
+ /*
+ * We're going to recompute lost.objects, by subtracting the
+ * amount of space reclaimed minus the amount of that space that
+ * was on free lists.
+ */
+ ulong found = 0;
+
+ alloc_close_chunk(mem);
+
+ /* Visit chunks in reverse order to encourage LIFO behavior. */
+ for (cp = mem->clast; cp != 0; cp = cprev) {
+ obj_header_t *begin_free = 0;
+
+ cprev = cp->cprev;
+ SCAN_CHUNK_OBJECTS(cp)
+ DO_ALL
+ if (pre->o_type == &st_free) {
+ if (begin_free == 0)
+ begin_free = pre;
+ } else
+ begin_free = 0;
+ END_OBJECTS_SCAN
+ if (begin_free) {
+ /* We found free objects at the top of the object area. */
+ int i;
+
+ found += (byte *)cp->cbot - (byte *)begin_free;
+ /* Remove the free objects from the freelists. */
+ for (i = 0; i < num_freelists; i++) {
+ obj_header_t *pfree;
+ obj_header_t **ppfprev = &mem->freelists[i];
+ uint free_size =
+ (i << log2_obj_align_mod) + sizeof(obj_header_t);
+
+ while ((pfree = *ppfprev) != 0)
+ if (ptr_ge(pfree, begin_free) &&
+ ptr_lt(pfree, cp->cbot)
+ ) { /* We're removing an object. */
+ *ppfprev = *(obj_header_t **) pfree;
+ found -= free_size;
+ } else
+ ppfprev = (obj_header_t **) pfree;
+ }
+ } else
+ begin_free = (obj_header_t *)cp->cbot;
+ if (begin_free == (obj_header_t *) cp->cbase &&
+ cp->ctop == cp->climit
+ ) { /* The entire chunk is free. */
+ chunk_t *cnext = cp->cnext;
+
+ if (!mem->is_controlled)
+ alloc_free_chunk(cp, mem);
+ if (mem->pcc == cp)
+ mem->pcc =
+ (cnext == 0 ? cprev : cprev == 0 ? cnext :
+ cprev->cbot - cprev->ctop >
+ cnext->cbot - cnext->ctop ? cprev :
+ cnext);
+ } else if (begin_free != (obj_header_t *)cp->cbot) {
+ if_debug4('a', "[a]resetting chunk 0x%lx cbot from 0x%lx to 0x%lx (%lu free)\n",
+ (ulong) cp, (ulong) cp->cbot, (ulong) begin_free,
+ (ulong) ((byte *) cp->cbot - (byte *) begin_free));
+ cp->cbot = (byte *) begin_free;
+ }
+ }
+ mem->lost.objects -= found;
+ alloc_open_chunk(mem);
+}
+private void
+i_consolidate_free(gs_memory_t *mem)
+{
+ ialloc_consolidate_free((gs_ref_memory_t *)mem);
+}
+
+/* ================ Roots ================ */
+
+/* Register a root. */
+private int
+i_register_root(gs_memory_t * mem, gs_gc_root_t * rp, gs_ptr_type_t ptype,
+ void **up, client_name_t cname)
+{
+ gs_ref_memory_t * const imem = (gs_ref_memory_t *)mem;
+
+ if (rp == NULL) {
+ rp = gs_raw_alloc_struct_immovable(imem->parent, &st_gc_root_t,
+ "i_register_root");
+ if (rp == 0)
+ return_error(gs_error_VMerror);
+ rp->free_on_unregister = true;
+ } else
+ rp->free_on_unregister = false;
+ if_debug3('8', "[8]register root(%s) 0x%lx -> 0x%lx\n",
+ client_name_string(cname), (ulong)rp, (ulong)up);
+ rp->ptype = ptype;
+ rp->p = up;
+ rp->next = imem->roots;
+ imem->roots = rp;
+ return 0;
+}
+
+/* Unregister a root. */
+private void
+i_unregister_root(gs_memory_t * mem, gs_gc_root_t * rp, client_name_t cname)
+{
+ gs_ref_memory_t * const imem = (gs_ref_memory_t *)mem;
+ gs_gc_root_t **rpp = &imem->roots;
+
+ if_debug2('8', "[8]unregister root(%s) 0x%lx\n",
+ client_name_string(cname), (ulong) rp);
+ while (*rpp != rp)
+ rpp = &(*rpp)->next;
+ *rpp = (*rpp)->next;
+ if (rp->free_on_unregister)
+ gs_free_object(imem->parent, rp, "i_unregister_root");
+}
+
+/* ================ Chunks ================ */
+
+public_st_chunk();
+
+/* Insert a chunk in the chain. This is exported for the GC and for */
+/* the forget_save operation. */
+void
+alloc_link_chunk(chunk_t * cp, gs_ref_memory_t * imem)
+{
+ byte *cdata = cp->cbase;
+ chunk_t *icp;
+ chunk_t *prev;
+
+ for (icp = imem->cfirst; icp != 0 && ptr_ge(cdata, icp->ctop);
+ icp = icp->cnext
+ );
+ cp->cnext = icp;
+ if (icp == 0) { /* add at end of chain */
+ prev = imem->clast;
+ imem->clast = cp;
+ } else { /* insert before icp */
+ prev = icp->cprev;
+ icp->cprev = cp;
+ }
+ cp->cprev = prev;
+ if (prev == 0)
+ imem->cfirst = cp;
+ else
+ prev->cnext = cp;
+ if (imem->pcc != 0) {
+ imem->cc.cnext = imem->pcc->cnext;
+ imem->cc.cprev = imem->pcc->cprev;
+ }
+}
+
+/* Add a chunk for ordinary allocation. */
+private chunk_t *
+alloc_add_chunk(gs_ref_memory_t * mem, ulong csize, client_name_t cname)
+{
+ chunk_t *cp = alloc_acquire_chunk(mem, csize, true, cname);
+
+ if (cp) {
+ alloc_close_chunk(mem);
+ mem->pcc = cp;
+ mem->cc = *mem->pcc;
+ gs_alloc_fill(mem->cc.cbase, gs_alloc_fill_free,
+ mem->cc.climit - mem->cc.cbase);
+ }
+ return cp;
+}
+
+/* Acquire a chunk. If we would exceed MaxLocalVM (if relevant), */
+/* or if we would exceed the VMThreshold and psignal is NULL, */
+/* return 0; if we would exceed the VMThreshold but psignal is valid, */
+/* just set the signal and return successfully. */
+private chunk_t *
+alloc_acquire_chunk(gs_ref_memory_t * mem, ulong csize, bool has_strings,
+ client_name_t cname)
+{
+ gs_raw_memory_t *parent = mem->parent;
+ chunk_t *cp;
+ byte *cdata;
+
+#if arch_sizeof_long > arch_sizeof_int
+ /* If csize is larger than max_uint, punt. */
+ if (csize != (uint) csize)
+ return 0;
+#endif
+ cp = gs_raw_alloc_struct_immovable(parent, &st_chunk, cname);
+ if ((ulong) (mem->allocated + mem->inherited) >= mem->limit) {
+ mem->gc_status.requested += csize;
+ if (mem->limit >= mem->gc_status.max_vm ||
+ mem->gc_status.psignal == 0
+ )
+ return 0;
+ if_debug4('0', "[0]signaling space=%d, allocated=%ld, limit=%ld, requested=%ld\n",
+ mem->space, (long)mem->allocated,
+ (long)mem->limit, (long)mem->gc_status.requested);
+ *mem->gc_status.psignal = mem->gc_status.signal_value;
+ }
+ cdata = gs_alloc_bytes_immovable(parent, csize, cname);
+ if (cp == 0 || cdata == 0) {
+ gs_free_object(parent, cdata, cname);
+ gs_free_object(parent, cp, cname);
+ mem->gc_status.requested = csize;
+ return 0;
+ }
+ alloc_init_chunk(cp, cdata, cdata + csize, has_strings, (chunk_t *) 0);
+ alloc_link_chunk(cp, mem);
+ mem->allocated += st_chunk.ssize + csize;
+ return cp;
+}
+
+/* Initialize the pointers in a chunk. This is exported for save/restore. */
+/* The bottom pointer must be aligned, but the top pointer need not */
+/* be aligned. */
+void
+alloc_init_chunk(chunk_t * cp, byte * bot, byte * top, bool has_strings,
+ chunk_t * outer)
+{
+ byte *cdata = bot;
+
+ if (outer != 0)
+ outer->inner_count++;
+ cp->chead = (chunk_head_t *) cdata;
+ cdata += sizeof(chunk_head_t);
+ cp->cbot = cp->cbase = cdata;
+ cp->cend = top;
+ cp->rcur = 0;
+ cp->rtop = 0;
+ cp->outer = outer;
+ cp->inner_count = 0;
+ cp->has_refs = false;
+ cp->sbase = cdata;
+ if (has_strings && top - cdata >= string_space_quantum + sizeof(long) - 1) { /*
+ * We allocate a large enough string marking and reloc table
+ * to cover the entire chunk.
+ */
+ uint nquanta = string_space_quanta(top - cdata);
+
+ cp->climit = cdata + nquanta * string_data_quantum;
+ cp->smark = cp->climit;
+ cp->smark_size = string_quanta_mark_size(nquanta);
+ cp->sreloc =
+ (string_reloc_offset *) (cp->smark + cp->smark_size);
+ cp->sfree1 = (ushort *) cp->sreloc;
+ } else { /* No strings, don't need the string GC tables. */
+ cp->climit = cp->cend;
+ cp->sfree1 = 0;
+ cp->smark = 0;
+ cp->smark_size = 0;
+ cp->sreloc = 0;
+ }
+ cp->ctop = cp->climit;
+ alloc_init_free_strings(cp);
+}
+
+/* Initialize the string freelists in a chunk. */
+void
+alloc_init_free_strings(chunk_t * cp)
+{
+ if (cp->sfree1)
+ memset(cp->sfree1, 0,
+ ((cp->climit - csbase(cp) + 255) >> 8) *
+ sizeof(*cp->sfree1));
+ cp->sfree = 0;
+}
+
+/* Close up the current chunk. */
+/* This is exported for save/restore and the GC. */
+void
+alloc_close_chunk(gs_ref_memory_t * mem)
+{
+ if (mem->pcc != 0) {
+ *mem->pcc = mem->cc;
+#ifdef DEBUG
+ if (gs_debug_c('a')) {
+ dlprintf1("[a%d]", mem->space);
+ dprintf_chunk("closing chunk", mem->pcc);
+ }
+#endif
+ }
+}
+
+/* Reopen the current chunk after a GC or restore. */
+void
+alloc_open_chunk(gs_ref_memory_t * mem)
+{
+ if (mem->pcc != 0) {
+ mem->cc = *mem->pcc;
+#ifdef DEBUG
+ if (gs_debug_c('a')) {
+ dlprintf1("[a%d]", mem->space);
+ dprintf_chunk("opening chunk", mem->pcc);
+ }
+#endif
+ }
+}
+
+/* Remove a chunk from the chain. This is exported for the GC. */
+void
+alloc_unlink_chunk(chunk_t * cp, gs_ref_memory_t * mem)
+{
+#ifdef DEBUG
+ if (gs_alloc_debug) { /* Check to make sure this chunk belongs to this allocator. */
+ const chunk_t *ap = mem->cfirst;
+
+ while (ap != 0 && ap != cp)
+ ap = ap->cnext;
+ if (ap != cp) {
+ lprintf2("unlink_chunk 0x%lx not owned by memory 0x%lx!\n",
+ (ulong) cp, (ulong) mem);
+ return; /*gs_abort(); */
+ }
+ }
+#endif
+ if (cp->cprev == 0)
+ mem->cfirst = cp->cnext;
+ else
+ cp->cprev->cnext = cp->cnext;
+ if (cp->cnext == 0)
+ mem->clast = cp->cprev;
+ else
+ cp->cnext->cprev = cp->cprev;
+ if (mem->pcc != 0) {
+ mem->cc.cnext = mem->pcc->cnext;
+ mem->cc.cprev = mem->pcc->cprev;
+ if (mem->pcc == cp) {
+ mem->pcc = 0;
+ mem->cc.cbot = mem->cc.ctop = 0;
+ }
+ }
+}
+
+/*
+ * Free a chunk. This is exported for the GC. Since we eventually use
+ * this to free the chunk containing the allocator itself, we must be
+ * careful not to reference anything in the allocator after freeing the
+ * chunk data.
+ */
+void
+alloc_free_chunk(chunk_t * cp, gs_ref_memory_t * mem)
+{
+ gs_raw_memory_t *parent = mem->parent;
+
+ alloc_unlink_chunk(cp, mem);
+ mem->allocated -= st_chunk.ssize;
+ if (mem->cfreed.cp == cp)
+ mem->cfreed.cp = 0;
+ if (cp->outer == 0) {
+ byte *cdata = (byte *) cp->chead;
+
+ mem->allocated -= cp->cend - cdata;
+ gs_free_object(parent, cdata, "alloc_free_chunk(data)");
+ } else
+ cp->outer->inner_count--;
+ gs_free_object(parent, cp, "alloc_free_chunk(chunk struct)");
+}
+
+/* Find the chunk for a pointer. */
+/* Note that this only searches the current save level. */
+/* Since a given save level can't contain both a chunk and an inner chunk */
+/* of that chunk, we can stop when is_within_chunk succeeds, and just test */
+/* is_in_inner_chunk then. */
+bool
+chunk_locate_ptr(const void *ptr, chunk_locator_t * clp)
+{
+ register chunk_t *cp = clp->cp;
+
+ if (cp == 0) {
+ cp = clp->memory->cfirst;
+ if (cp == 0)
+ return false;
+ }
+ if (ptr_lt(ptr, cp->cbase)) {
+ do {
+ cp = cp->cprev;
+ if (cp == 0)
+ return false;
+ }
+ while (ptr_lt(ptr, cp->cbase));
+ if (ptr_ge(ptr, cp->cend))
+ return false;
+ } else {
+ while (ptr_ge(ptr, cp->cend)) {
+ cp = cp->cnext;
+ if (cp == 0)
+ return false;
+ }
+ if (ptr_lt(ptr, cp->cbase))
+ return false;
+ }
+ clp->cp = cp;
+ return !ptr_is_in_inner_chunk(ptr, cp);
+}
+
+/* ------ Debugging printout ------ */
+
+#ifdef DEBUG
+
+#include "string_.h"
+
+/*
+ * Define the options for a memory dump. These may be or'ed together.
+ */
+typedef enum {
+ dump_do_default = 0, /* pro forma */
+ dump_do_strings = 1,
+ dump_do_type_addresses = 2,
+ dump_do_no_types = 4,
+ dump_do_pointers = 8,
+ dump_do_pointed_strings = 16, /* only if do_pointers also set */
+ dump_do_contents = 32,
+ dump_do_marks = 64
+} dump_options_t;
+
+/*
+ * Define all the parameters controlling what gets dumped.
+ */
+typedef struct dump_control_s {
+ dump_options_t options;
+ const byte *bottom;
+ const byte *top;
+} dump_control_t;
+
+inline private bool
+obj_in_control_region(const void *obot, const void *otop,
+ const dump_control_t *pdc)
+{
+ return
+ ((pdc->bottom == NULL || ptr_gt(otop, pdc->bottom)) &&
+ (pdc->top == NULL || ptr_lt(obot, pdc->top)));
+}
+
+const dump_control_t dump_control_default =
+{
+ dump_do_default, NULL, NULL
+};
+const dump_control_t dump_control_all =
+{
+ dump_do_strings | dump_do_type_addresses | dump_do_pointers |
+ dump_do_pointed_strings | dump_do_contents, NULL, NULL
+};
+
+/*
+ * Internal procedure to dump a block of memory, in hex and optionally
+ * also as characters.
+ */
+private void
+debug_indent(int indent)
+{
+ int i;
+
+ for (i = indent; i > 0; --i)
+ dputc(' ');
+}
+private void
+debug_dump_contents(const byte * bot, const byte * top, int indent,
+ bool as_chars)
+{
+ const byte *block;
+
+#define block_size 16
+
+ if (bot >= top)
+ return;
+ for (block = bot - ((bot - (byte *) 0) & (block_size - 1));
+ block < top; block += block_size
+ ) {
+ int i;
+ char label[12];
+
+ /* Check for repeated blocks. */
+ if (block >= bot + block_size &&
+ block <= top - (block_size * 2) &&
+ !memcmp(block, block - block_size, block_size) &&
+ !memcmp(block, block + block_size, block_size)
+ ) {
+ if (block < bot + block_size * 2 ||
+ memcmp(block, block - block_size * 2, block_size)
+ ) {
+ debug_indent(indent);
+ dputs(" ...\n");
+ }
+ continue;
+ }
+ sprintf(label, "0x%lx:", (ulong) block);
+ debug_indent(indent);
+ dputs(label);
+ for (i = 0; i < block_size; ++i) {
+ const char *sepr = ((i & 3) == 0 && i != 0 ? " " : " ");
+
+ dputs(sepr);
+ if (block + i >= bot && block + i < top)
+ dprintf1("%02x", block[i]);
+ else
+ dputs(" ");
+ }
+ dputc('\n');
+ if (as_chars) {
+ debug_indent(indent + strlen(label));
+ for (i = 0; i < block_size; ++i) {
+ byte ch;
+
+ if ((i & 3) == 0 && i != 0)
+ dputc(' ');
+ if (block + i >= bot && block + i < top &&
+ (ch = block[i]) >= 32 && ch <= 126
+ )
+ dprintf1(" %c", ch);
+ else
+ dputs(" ");
+ }
+ dputc('\n');
+ }
+ }
+#undef block_size
+}
+
+/* Print one object with the given options. */
+/* Relevant options: type_addresses, no_types, pointers, pointed_strings, */
+/* contents. */
+void
+debug_print_object(const void *obj, const dump_control_t * control)
+{
+ const obj_header_t *pre = ((const obj_header_t *)obj) - 1;
+ ulong size = pre_obj_contents_size(pre);
+ const gs_memory_struct_type_t *type = pre->o_type;
+ dump_options_t options = control->options;
+
+ dprintf3(" pre=0x%lx(obj=0x%lx) size=%lu", (ulong) pre, (ulong) obj,
+ size);
+ switch (options & (dump_do_type_addresses | dump_do_no_types)) {
+ case dump_do_type_addresses + dump_do_no_types: /* addresses only */
+ dprintf1(" type=0x%lx", (ulong) type);
+ break;
+ case dump_do_type_addresses: /* addresses & names */
+ dprintf2(" type=%s(0x%lx)", struct_type_name_string(type),
+ (ulong) type);
+ break;
+ case 0: /* names only */
+ dprintf1(" type=%s", struct_type_name_string(type));
+ case dump_do_no_types: /* nothing */
+ ;
+ }
+ if (options & dump_do_marks) {
+ if (pre->o_large)
+ dprintf1(" lmark=%d", pre->o_lmark);
+ else
+ dprintf2(" smark/back=%u (0x%x)", pre->o_smark, pre->o_smark);
+ }
+ dputc('\n');
+ if (type == &st_free)
+ return;
+ if (options & dump_do_pointers) {
+ struct_proc_enum_ptrs((*proc)) = type->enum_ptrs;
+ uint index = 0;
+ const void *ptr;
+ gs_ptr_type_t ptype;
+
+ /*
+ * NOTE: the following cast should be unnecessary, but that
+ * will require adding 'const' to the first prototype argument
+ * of struct_proc_enum_ptrs.
+ */
+ if (proc != gs_no_struct_enum_ptrs)
+ for (; (ptype = (*proc) ((obj_header_t *) pre + 1, size, index, &ptr, type, NULL)) != 0;
+ ++index
+ ) {
+ dprintf1(" ptr %u: ", index);
+ if (ptype == ptr_string_type || ptype == ptr_const_string_type) {
+ const gs_const_string *str = (const gs_const_string *)ptr;
+
+ dprintf2("0x%lx(%u)", (ulong) str->data, str->size);
+ if (options & dump_do_pointed_strings) {
+ dputs(" =>\n");
+ debug_dump_contents(str->data, str->data + str->size, 6,
+ true);
+ } else {
+ dputc('\n');
+ }
+ } else {
+ dprintf1((ptr_between(ptr, obj, (const byte *)obj + size) ?
+ "(0x%lx)\n" : "0x%lx\n"), (ulong) ptr);
+ }
+ }
+ }
+ if (options & dump_do_contents) {
+ debug_dump_contents((const byte *)obj, (const byte *)obj + size,
+ 0, false);
+ }
+}
+
+/* Print the contents of a chunk with the given options. */
+/* Relevant options: all. */
+void
+debug_dump_chunk(const chunk_t * cp, const dump_control_t * control)
+{
+ dprintf1("chunk at 0x%lx:\n", (ulong) cp);
+ dprintf3(" chead=0x%lx cbase=0x%lx sbase=0x%lx\n",
+ (ulong) cp->chead, (ulong) cp->cbase, (ulong) cp->sbase);
+ dprintf3(" rcur=0x%lx rtop=0x%lx cbot=0x%lx\n",
+ (ulong) cp->rcur, (ulong) cp->rtop, (ulong) cp->cbot);
+ dprintf4(" ctop=0x%lx climit=0x%lx smark=0x%lx, size=%u\n",
+ (ulong) cp->ctop, (ulong) cp->climit, (ulong) cp->smark,
+ cp->smark_size);
+ dprintf2(" sreloc=0x%lx cend=0x%lx\n",
+ (ulong) cp->sreloc, (ulong) cp->cend);
+ dprintf5("cprev=0x%lx cnext=0x%lx outer=0x%lx inner_count=%u has_refs=%s\n",
+ (ulong) cp->cprev, (ulong) cp->cnext, (ulong) cp->outer,
+ cp->inner_count, (cp->has_refs ? "true" : "false"));
+
+ dprintf2(" sfree1=0x%lx sfree=0x%x\n",
+ (ulong) cp->sfree1, cp->sfree);
+ if (control->options & dump_do_strings) {
+ debug_dump_contents((control->bottom == 0 ? cp->ctop :
+ max(control->bottom, cp->ctop)),
+ (control->top == 0 ? cp->climit :
+ min(control->top, cp->climit)),
+ 0, true);
+ }
+ SCAN_CHUNK_OBJECTS(cp)
+ DO_ALL
+ if (obj_in_control_region(pre + 1,
+ (const byte *)(pre + 1) + size,
+ control)
+ )
+ debug_print_object(pre + 1, control);
+/* Temporarily redefine gs_exit so a chunk parsing error */
+/* won't actually exit. */
+#define gs_exit(n) DO_NOTHING
+ END_OBJECTS_SCAN
+#undef gs_exit
+}
+void
+debug_print_chunk(const chunk_t * cp)
+{
+ dump_control_t control;
+
+ control = dump_control_default;
+ debug_dump_chunk(cp, &control);
+}
+
+/* Print the contents of all chunks managed by an allocator. */
+/* Relevant options: all. */
+void
+debug_dump_memory(const gs_ref_memory_t * mem, const dump_control_t * control)
+{
+ const chunk_t *mcp;
+
+ for (mcp = mem->cfirst; mcp != 0; mcp = mcp->cnext) {
+ const chunk_t *cp = (mcp == mem->pcc ? &mem->cc : mcp);
+
+ if (obj_in_control_region(cp->cbase, cp->cend, control))
+ debug_dump_chunk(cp, control);
+ }
+}
+
+#endif /* DEBUG */
diff --git a/pstoraster/gsalloc.h b/pstoraster/gsalloc.h
new file mode 100644
index 000000000..d5f855f37
--- /dev/null
+++ b/pstoraster/gsalloc.h
@@ -0,0 +1,87 @@
+/* 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$ */
+/* Memory allocator extensions for standard allocator */
+
+#ifndef gsalloc_INCLUDED
+# define gsalloc_INCLUDED
+
+/* The following should not be needed at this level! */
+
+#ifndef gs_ref_memory_DEFINED
+# define gs_ref_memory_DEFINED
+typedef struct gs_ref_memory_s gs_ref_memory_t;
+#endif
+
+/*
+ * Define a structure and interface for GC-related allocator state.
+ */
+typedef struct gs_memory_gc_status_s {
+ /* Set by client */
+ long vm_threshold; /* GC interval */
+ long max_vm; /* maximum allowed allocation */
+ int *psignal; /* if not NULL, store signal_value */
+ /* here if we go over the vm_threshold */
+ int signal_value; /* value to store in *psignal */
+ bool enabled; /* auto GC enabled if true */
+ /* Set by allocator */
+ long requested; /* amount of last failing request */
+} gs_memory_gc_status_t;
+void gs_memory_gc_status(P2(const gs_ref_memory_t *, gs_memory_gc_status_t *));
+void gs_memory_set_gc_status(P2(gs_ref_memory_t *, const gs_memory_gc_status_t *));
+
+/* ------ Initialization ------ */
+
+/*
+ * Allocate and mostly initialize the state of an allocator (system, global,
+ * or local). Does not initialize global or space.
+ */
+gs_ref_memory_t *ialloc_alloc_state(P2(gs_raw_memory_t *, uint));
+
+/*
+ * Add a chunk to an externally controlled allocator. Such allocators
+ * allocate all objects as immovable, are not garbage-collected, and
+ * don't attempt to acquire additional memory (or free chunks) on their own.
+ */
+int ialloc_add_chunk(P3(gs_ref_memory_t *, ulong, client_name_t));
+
+/* ------ Internal routines ------ */
+
+/* Prepare for a GC. */
+void ialloc_gc_prepare(P1(gs_ref_memory_t *));
+
+/* Initialize after a save. */
+void ialloc_reset(P1(gs_ref_memory_t *));
+
+/* Initialize after a save or GC. */
+void ialloc_reset_free(P1(gs_ref_memory_t *));
+
+/* Set the cached allocation limit of an alloctor from its GC parameters. */
+void ialloc_set_limit(P1(gs_ref_memory_t *));
+
+/* Consolidate free objects. */
+void ialloc_consolidate_free(P1(gs_ref_memory_t *));
+
+#endif /* gsalloc_INCLUDED */
diff --git a/pstoraster/gsalpha.c b/pstoraster/gsalpha.c
new file mode 100644
index 000000000..45f185c73
--- /dev/null
+++ b/pstoraster/gsalpha.c
@@ -0,0 +1,48 @@
+/* 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$ */
+/* Graphics state alpha value access */
+#include "gx.h"
+#include "gsalpha.h"
+#include "gxdcolor.h"
+#include "gzstate.h"
+
+/* setalpha */
+int
+gs_setalpha(gs_state * pgs, floatp alpha)
+{
+ pgs->alpha =
+ (gx_color_value) (alpha < 0 ? 0 : alpha > 1 ? gx_max_color_value :
+ alpha * gx_max_color_value);
+ gx_unset_dev_color(pgs);
+ return 0;
+}
+
+/* currentalpha */
+float
+gs_currentalpha(const gs_state * pgs)
+{
+ return (float)pgs->alpha / gx_max_color_value;
+}
diff --git a/pstoraster/gsalpha.h b/pstoraster/gsalpha.h
new file mode 100644
index 000000000..772553ff8
--- /dev/null
+++ b/pstoraster/gsalpha.h
@@ -0,0 +1,41 @@
+/* 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$ */
+/* API for alpha value in graphics state */
+
+#ifndef gsalpha_INCLUDED
+# define gsalpha_INCLUDED
+
+/*
+ * This tiny little file is separate so that it can be included by
+ * gsstate.c for initializing the alpha value, even in configurations
+ * that don't have full alpha support.
+ */
+
+/* Set/read alpha value. */
+int gs_setalpha(P2(gs_state *, floatp));
+float gs_currentalpha(P1(const gs_state *));
+
+#endif /* gsalpha_INCLUDED */
diff --git a/pstoraster/gsalphac.h b/pstoraster/gsalphac.h
new file mode 100644
index 000000000..5afe0c3ef
--- /dev/null
+++ b/pstoraster/gsalphac.h
@@ -0,0 +1,71 @@
+/* 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$ */
+/* Alpha-compositing interface */
+
+#ifndef gsalphac_INCLUDED
+# define gsalphac_INCLUDED
+
+#include "gscompt.h"
+
+/*
+ * Define the compositing operations. These values must match the ones in
+ * dpsNeXT.h.
+ */
+typedef enum {
+ composite_Clear = 0,
+ composite_Copy,
+ composite_Sover,
+ composite_Sin,
+ composite_Sout,
+ composite_Satop,
+ composite_Dover,
+ composite_Din,
+ composite_Dout,
+ composite_Datop,
+ composite_Xor,
+ composite_PlusD,
+ composite_PlusL,
+#define composite_last composite_PlusL
+ composite_Highlight, /* (only for compositerect) */
+#define compositerect_last composite_Highlight
+ composite_Dissolve /* (not for PostScript composite operators) */
+#define composite_op_last composite_Dissolve
+} gs_composite_op_t;
+
+/*
+ * Define parameters for alpha-compositing.
+ */
+typedef struct gs_composite_alpha_params_s {
+ gs_composite_op_t op;
+ float delta; /* only for Dissolve */
+} gs_composite_alpha_params_t;
+
+/* Create an alpha-compositing object. */
+int gs_create_composite_alpha(P3(gs_composite_t ** ppcte,
+ const gs_composite_alpha_params_t * params,
+ gs_memory_t * mem));
+
+#endif /* gsalphac_INCLUDED */
diff --git a/pstoraster/gsargs.c b/pstoraster/gsargs.c
new file mode 100644
index 000000000..f0102c1b3
--- /dev/null
+++ b/pstoraster/gsargs.c
@@ -0,0 +1,225 @@
+/* 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$ */
+/* Command line argument list management */
+#include "ctype_.h"
+#include "stdio_.h"
+#include "string_.h"
+#include "gsexit.h"
+#include "gsmemory.h"
+#include "gsargs.h"
+
+/* Initialize an arg list. */
+void
+arg_init(arg_list * pal, const char **argv, int argc,
+ FILE * (*arg_fopen) (P2(const char *fname, void *fopen_data)),
+ void *fopen_data)
+{
+ pal->expand_ats = true;
+ pal->arg_fopen = arg_fopen;
+ pal->fopen_data = fopen_data;
+ pal->argp = argv + 1;
+ pal->argn = argc - 1;
+ pal->depth = 0;
+}
+
+/* Push a string onto an arg list. */
+void
+arg_push_memory_string(arg_list * pal, const char *str, gs_memory_t * mem)
+{
+ arg_source *pas;
+
+ if (pal->depth == arg_depth_max) {
+ lprintf("Too much nesting of @-files.\n");
+ gs_exit(1);
+ }
+ pas = &pal->sources[pal->depth];
+ pas->is_file = false;
+ pas->u.s.chars = str;
+ pas->u.s.memory = mem;
+ pas->u.s.str = str;
+ pal->depth++;
+}
+
+/* Clean up an arg list. */
+void
+arg_finit(arg_list * pal)
+{
+ while (pal->depth) {
+ arg_source *pas = &pal->sources[--(pal->depth)];
+
+ if (pas->is_file)
+ fclose(pas->u.file);
+ else if (pas->u.s.memory)
+ gs_free_object(pas->u.s.memory, (void *)pas->u.s.chars, "arg_finit");
+ }
+}
+
+/* Get the next arg from a list. */
+/* Note that these are not copied to the heap. */
+const char *
+arg_next(arg_list * pal)
+{
+ arg_source *pas;
+ FILE *f;
+ const char *astr = 0; /* initialized only to pacify gcc */
+ char *cstr;
+ const char *result;
+ int endc;
+ int c, i;
+ bool in_quote, eol;
+
+ top:pas = &pal->sources[pal->depth - 1];
+ if (pal->depth == 0) {
+ if (pal->argn <= 0) /* all done */
+ return 0;
+ pal->argn--;
+ result = *(pal->argp++);
+ goto at;
+ }
+ if (pas->is_file)
+ f = pas->u.file, endc = EOF;
+ else
+ astr = pas->u.s.str, f = NULL, endc = 0;
+ result = cstr = pal->cstr;
+#define cfsgetc() (f == NULL ? (*astr ? *astr++ : 0) : fgetc(f))
+#define is_eol(c) (c == '\r' || c == '\n')
+ i = 0;
+ in_quote = false;
+ eol = true;
+ c = cfsgetc();
+ for (i = 0;;) {
+ if (c == endc) {
+ if (in_quote) {
+ cstr[i] = 0;
+ fprintf(stderr, "Unterminated quote in @-file: %s\n", cstr);
+ gs_exit(1);
+ }
+ if (i == 0) {
+ /* EOF before any argument characters. */
+ if (f != NULL)
+ fclose(f);
+ else if (pas->u.s.memory)
+ gs_free_object(pas->u.s.memory, (void *)pas->u.s.chars,
+ "arg_next");
+ pal->depth--;
+ goto top;
+ }
+ break;
+ }
+ /* c != endc */
+ if (isspace(c)) {
+ if (i == 0) {
+ c = cfsgetc();
+ continue;
+ }
+ if (!in_quote)
+ break;
+ }
+ /* c isn't leading or terminating whitespace. */
+ if (c == '#' && eol) {
+ /* Skip a comment. */
+ do {
+ c = cfsgetc();
+ } while (!(c == endc || is_eol(c)));
+ if (c == '\r')
+ c = cfsgetc();
+ if (c == '\n')
+ c = cfsgetc();
+ continue;
+ }
+ if (c == '\\') {
+ /* Check for \ followed by newline. */
+ c = cfsgetc();
+ if (is_eol(c)) {
+ if (c == '\r')
+ c = cfsgetc();
+ if (c == '\n')
+ c = cfsgetc();
+ eol = true;
+ continue;
+ }
+ /* \ anywhere else is treated as a printing character. */
+ /* This is different from the Unix shells. */
+ if (i == arg_str_max - 1) {
+ cstr[i] = 0;
+ fprintf(stderr, "Command too long: %s\n", cstr);
+ gs_exit(1);
+ }
+ cstr[i++] = '\\';
+ eol = false;
+ continue;
+ }
+ /* c will become part of the argument */
+ if (i == arg_str_max - 1) {
+ cstr[i] = 0;
+ fprintf(stderr, "Command too long: %s\n", cstr);
+ gs_exit(1);
+ }
+ /* If input is coming from an @-file, allow quotes */
+ /* to protect whitespace. */
+ if (c == '"' && f != NULL)
+ in_quote = !in_quote;
+ else
+ cstr[i++] = c;
+ eol = is_eol(c);
+ c = cfsgetc();
+ }
+ cstr[i] = 0;
+ if (f == NULL)
+ pas->u.s.str = astr;
+ at:if (pal->expand_ats && result[0] == '@') {
+ if (pal->depth == arg_depth_max) {
+ lprintf("Too much nesting of @-files.\n");
+ gs_exit(1);
+ }
+ result++; /* skip @ */
+ f = (*pal->arg_fopen) (result, pal->fopen_data);
+ if (f == NULL) {
+ fprintf(stderr, "Unable to open command line file %s\n", result);
+ gs_exit(1);
+ }
+ pal->depth++;
+ pas++;
+ pas->is_file = true;
+ pas->u.file = f;
+ goto top;
+ }
+ return result;
+}
+
+/* Copy an argument string to the heap. */
+char *
+arg_copy(const char *str, gs_memory_t * mem)
+{
+ char *sstr = (char *)gs_alloc_bytes(mem, strlen(str) + 1, "arg_copy");
+
+ if (sstr == 0) {
+ lprintf("Out of memory!\n");
+ gs_exit(1);
+ }
+ strcpy(sstr, str);
+ return sstr;
+}
diff --git a/pstoraster/gsargs.h b/pstoraster/gsargs.h
new file mode 100644
index 000000000..e5de18661
--- /dev/null
+++ b/pstoraster/gsargs.h
@@ -0,0 +1,89 @@
+/* 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$ */
+/* Command line argument list management */
+
+#ifndef gsargs_INCLUDED
+# define gsargs_INCLUDED
+
+/*
+ * We need to handle recursion into @-files.
+ * The following structures keep track of the state.
+ * Defining a maximum argument length and a maximum nesting depth
+ * decreases generality, but eliminates the need for dynamic allocation.
+ */
+#define arg_str_max 512
+#define arg_depth_max 10
+typedef struct arg_source_s {
+ bool is_file;
+ union _u {
+ struct _su {
+ const char *chars; /* original string */
+ gs_memory_t *memory; /* if non-0, free chars when done with it */
+ const char *str; /* string being read */
+ } s;
+ FILE *file;
+ } u;
+} arg_source;
+typedef struct arg_list_s {
+ bool expand_ats; /* if true, expand @-files */
+ FILE *(*arg_fopen) (P2(const char *fname, void *fopen_data));
+ void *fopen_data;
+ const char **argp;
+ int argn;
+ int depth; /* depth of @-files */
+ char cstr[arg_str_max + 1];
+ arg_source sources[arg_depth_max];
+} arg_list;
+
+/* Initialize an arg list. */
+void arg_init(P5(arg_list * pal, const char **argv, int argc,
+ FILE * (*arg_fopen) (P2(const char *fname, void *fopen_data)),
+ void *fopen_data));
+
+/*
+ * Push a string onto an arg list.
+ * This may also be used (once) to "unread" the last argument.
+ * If mem != 0, it is used to free the string when we are done with it.
+ */
+void arg_push_memory_string(P3(arg_list * pal, const char *str,
+ gs_memory_t * mem));
+
+#define arg_push_string(pal, str)\
+ arg_push_memory_string(pal, str, (gs_memory_t *)0);
+
+/* Clean up an arg list before exiting. */
+void arg_finit(P1(arg_list * pal));
+
+/*
+ * Get the next arg from a list.
+ * Note that these are not copied to the heap.
+ */
+const char *arg_next(P1(arg_list * pal));
+
+/* Copy an argument string to the heap. */
+char *arg_copy(P2(const char *str, gs_memory_t * mem));
+
+#endif /* gsargs_INCLUDED */
diff --git a/pstoraster/gsbitmap.h b/pstoraster/gsbitmap.h
new file mode 100644
index 000000000..bd9c7498e
--- /dev/null
+++ b/pstoraster/gsbitmap.h
@@ -0,0 +1,193 @@
+/* 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$ */
+/* Library "client" bitmap structures */
+
+#ifndef gsbitmap_INCLUDED
+#define gsbitmap_INCLUDED
+
+#include "gsstruct.h" /* for extern_st */
+
+/*
+ * The Ghostscript library stores all bitmaps bit-big-endian (i.e., the 0x80
+ * bit of the first byte corresponds to x=0), as a sequence of bytes (i.e.,
+ * you can't do word-oriented operations on them if you're on a
+ * little-endian platform like the Intel 80x86 or VAX). The first scan line
+ * corresponds to y=0 in whatever coordinate system is relevant.
+ *
+ * The structures defined here are for APIs that don't impose any alignment
+ * restrictions on either the starting address or the raster (distance
+ * between scan lines) of bitmap data. The structures defined in gxbitmap.h
+ * do impose alignment restrictions, so that the library can use more
+ * efficient algorithms; they are declared with identical contents to the
+ * ones defined here, so that one can cast between them under appropriate
+ * circumstances (aligned to unaligned is always safe; unaligned to
+ * aligned is safe if one knows somehow that the data are actually aligned.)
+ *
+ * In this file we also provide structures that include depth information.
+ * It probably was a design mistake not to include this information in the
+ * gx structures as well.
+ */
+
+/*
+ * Drivers such as the X driver and the command list (band list) driver
+ * benefit greatly by being able to cache bitmaps (tiles and characters)
+ * and refer to them later. To help them recognize when a bitmap is the
+ * same as one that they have seen before, the core code passes an optional
+ * ID with the property that if two bitmaps have the same ID, they are
+ * guaranteed to have the same contents. (The converse is *not* true,
+ * however: two bitmaps may have different IDs and still be the same.)
+ */
+typedef gs_id gs_bitmap_id;
+
+/* Define a special value to indicate "no identifier". */
+#define gs_no_bitmap_id gs_no_id
+
+/*
+ * In its simplest form, the client bitmap structure does not specify a
+ * depth, expecting it to be implicit in the context of use. In many cases
+ * it is possible to guess this by comparing size.x and raster, but of
+ * course code should not rely on this. See also gs_depth_bitmap below.
+ * Requirements:
+ * size.x > 0, size.y > 0
+ * If size.y > 1,
+ * raster >= (size.x * depth + 7) / 8
+ */
+#define gs_bitmap_common \
+ byte * data; /* pointer to the data */ \
+ int raster; /* increment between scanlines, bytes */ \
+ gs_int_point size; /* width and height */ \
+ gs_bitmap_id id /* usually unused */
+
+typedef struct gs_bitmap_s {
+ gs_bitmap_common;
+} gs_bitmap;
+
+/*
+ * For bitmaps used as halftone tiles, we may replicate the tile in
+ * X and/or Y, but it is still valuable to know the true tile dimensions
+ * (i.e., the dimensions prior to replication). Requirements:
+ * size.x % rep_width = 0
+ * size.y % rep_height = 0
+ * Unaligned bitmaps are not very likely to be used as tiles (replicated),
+ * since most of the library procedures that replicate tiles expect them
+ * to be aligned.
+ */
+#define gs_tile_bitmap_common \
+ gs_bitmap_common; \
+ ushort rep_width, rep_height /* true size of tile */
+
+typedef struct gs_tile_bitmap_s {
+ gs_tile_bitmap_common;
+} gs_tile_bitmap;
+
+/*
+ * There is no "strip" version for client bitmaps, as the strip structure is
+ * primarily used to efficiently store bitmaps rendered at an angle, and
+ * there is little reason to do so with client bitmaps.
+ *
+ * For client bitmaps it is not always apparent from context what the intended
+ * depth per sample value is. To provide for this, an extended version of the
+ * bitmap structure is provided, that handles both variable depth and
+ * interleaved color components. This structure is provided in both the
+ * normal and tiled version.
+ *
+ * Extending this line of thinking, one could also add color space information
+ * to a client bitmap structure. We have chosen not to do so, because color
+ * space is almost always derived from context, and to provide such a feature
+ * would involve additional memory-management complexity.
+ */
+#define gs_depth_bitmap_common \
+ gs_bitmap_common; \
+ byte pix_depth; /* bits per sample */ \
+ byte num_comps /* number of interleaved components */ \
+
+typedef struct gs_depth_bitmap_s {
+ gs_depth_bitmap_common;
+} gs_depth_bitmap;
+
+#define gs_tile_depth_bitmap_common \
+ gs_tile_bitmap_common; \
+ byte pix_depth; /* bits per sample */ \
+ byte num_comps /* number of interleaved components */ \
+
+typedef struct gs_tile_depth_bitmap_s {
+ gs_tile_depth_bitmap_common;
+} gs_tile_depth_bitmap;
+
+/*
+ * For reasons that are no entirely clear, no memory management routines were
+ * provided for the aligned bitmap structures provided in gxbitmap.h. Since
+ * client bitmaps will, by nature, be created by different clients, so public
+ * memory management procedures are provided. Note that the memory management
+ * structure names retain the "gs_" prefix, to distinguish these structures
+ * from those that may be provided for the gx_*_bitmap structures.
+ *
+ * For historical reasons of no particular validity (this was where the client
+ * bitmap structure was first provided), the memory managment procedures for
+ * client bitmap structures are included in gspcolor.c.
+ */
+extern_st(st_gs_bitmap);
+extern_st(st_gs_tile_bitmap);
+extern_st(st_gs_depth_bitmap);
+extern_st(st_gs_tile_depth_bitmap);
+
+#define public_st_gs_bitmap() /* in gspcolor.c */ \
+ gs_public_st_ptrs1( st_gs_bitmap, \
+ gs_bitmap, \
+ "client bitmap", \
+ bitmap_enum_ptrs, \
+ bitmap_reloc_ptrs, \
+ data \
+ )
+
+#define public_st_gs_tile_bitmap() /* in gspcolor.c */ \
+ gs_public_st_suffix_add0_local( st_gs_tile_bitmap, \
+ gs_tile_bitmap, \
+ "client tile bitmap", \
+ bitmap_enum_ptrs, \
+ bitmap_reloc_ptrs, \
+ st_gs_bitmap \
+ )
+
+#define public_st_gs_depth_bitmap() /* in gspcolor.c */ \
+ gs_public_st_suffix_add0_local( st_gs_depth_bitmap, \
+ gs_depth_bitmap, \
+ "client depth bitmap", \
+ bitmap_enum_ptrs, \
+ bitmap_reloc_ptrs, \
+ st_gs_bitmap \
+ )
+
+#define public_st_gs_tile_depth_bitmap()/* in gspcolor.c */ \
+ gs_public_st_suffix_add0_local( st_gs_tile_depth_bitmap, \
+ gs_tile_depth_bitmap, \
+ "client tile_depth bitmap", \
+ bitmap_enum_ptrs, \
+ bitmap_reloc_ptrs, \
+ st_gs_tile_bitmap \
+ )
+
+#endif /* gsbitmap_INCLUDED */
diff --git a/pstoraster/gsbitops.c b/pstoraster/gsbitops.c
new file mode 100644
index 000000000..f93446428
--- /dev/null
+++ b/pstoraster/gsbitops.c
@@ -0,0 +1,674 @@
+/* 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$ */
+/* Bitmap filling, copying, and transforming operations */
+#include "stdio_.h"
+#include "memory_.h"
+#include "gdebug.h"
+#include "gstypes.h"
+#include "gxbitops.h"
+
+/*
+ * Define a compile-time option to reverse nibble order in alpha maps.
+ * Note that this does not reverse bit order within nibbles.
+ * This option is here for a very specialized purpose and does not
+ * interact well with the rest of the code.
+ */
+#ifndef ALPHA_LSB_FIRST
+# define ALPHA_LSB_FIRST 0
+#endif
+
+/* ---------------- Bit-oriented operations ---------------- */
+
+/* Define masks for little-endian operation. */
+/* masks[i] has the first i bits off and the rest on. */
+#if !arch_is_big_endian
+const bits16 mono_copy_masks[17] =
+{
+ 0xffff, 0xff7f, 0xff3f, 0xff1f,
+ 0xff0f, 0xff07, 0xff03, 0xff01,
+ 0xff00, 0x7f00, 0x3f00, 0x1f00,
+ 0x0f00, 0x0700, 0x0300, 0x0100,
+ 0x0000
+};
+
+# if arch_sizeof_int > 2
+const bits32 mono_fill_masks[33] =
+{
+ 0xffffffff, 0xffffff7f, 0xffffff3f, 0xffffff1f,
+ 0xffffff0f, 0xffffff07, 0xffffff03, 0xffffff01,
+ 0xffffff00, 0xffff7f00, 0xffff3f00, 0xffff1f00,
+ 0xffff0f00, 0xffff0700, 0xffff0300, 0xffff0100,
+ 0xffff0000, 0xff7f0000, 0xff3f0000, 0xff1f0000,
+ 0xff0f0000, 0xff070000, 0xff030000, 0xff010000,
+ 0xff000000, 0x7f000000, 0x3f000000, 0x1f000000,
+ 0x0f000000, 0x07000000, 0x03000000, 0x01000000,
+ 0x00000000
+};
+
+# endif
+#endif
+
+/* Fill a rectangle of bits with an 8x1 pattern. */
+/* The pattern argument must consist of the pattern in every byte, */
+/* e.g., if the desired pattern is 0xaa, the pattern argument must */
+/* have the value 0xaaaa (if ints are short) or 0xaaaaaaaa. */
+#undef chunk
+#define chunk mono_fill_chunk
+#undef mono_masks
+#define mono_masks mono_fill_masks
+void
+bits_fill_rectangle(byte * dest, int dest_bit, uint draster,
+ mono_fill_chunk pattern, int width_bits, int height)
+{
+ uint bit;
+ chunk right_mask;
+ int line_count = height;
+ chunk *ptr;
+ int last_bit;
+
+#define FOR_EACH_LINE(stat)\
+ do { stat } while ( inc_ptr(ptr, draster), --line_count )
+
+ dest += (dest_bit >> 3) & -chunk_align_bytes;
+ ptr = (chunk *) dest;
+ bit = dest_bit & chunk_align_bit_mask;
+ last_bit = width_bits + bit - (chunk_bits + 1);
+
+ if (last_bit < 0) { /* <=1 chunk */
+ set_mono_thin_mask(right_mask, width_bits, bit);
+ switch ((byte) pattern) {
+ case 0:
+ FOR_EACH_LINE(*ptr &= ~right_mask;
+ );
+ break;
+ case 0xff:
+ FOR_EACH_LINE(*ptr |= right_mask;
+ );
+ break;
+ default:
+ FOR_EACH_LINE(
+ *ptr = (*ptr & ~right_mask) | (pattern & right_mask);
+ );
+ }
+ } else {
+ chunk mask;
+ int last = last_bit >> chunk_log2_bits;
+
+ set_mono_left_mask(mask, bit);
+ set_mono_right_mask(right_mask, (last_bit & chunk_bit_mask) + 1);
+ switch (last) {
+ case 0: /* 2 chunks */
+ switch ((byte) pattern) {
+ case 0:
+ FOR_EACH_LINE(*ptr &= ~mask;
+ ptr[1] &= ~right_mask;
+ );
+ break;
+ case 0xff:
+ FOR_EACH_LINE(*ptr |= mask;
+ ptr[1] |= right_mask;
+ );
+ break;
+ default:
+ FOR_EACH_LINE(
+ *ptr = (*ptr & ~mask) | (pattern & mask);
+ ptr[1] = (ptr[1] & ~right_mask) | (pattern & right_mask);
+ );
+ }
+ break;
+ case 1: /* 3 chunks */
+ switch ((byte) pattern) {
+ case 0:
+ FOR_EACH_LINE(
+ *ptr &= ~mask;
+ ptr[1] = 0;
+ ptr[2] &= ~right_mask;
+ );
+ break;
+ case 0xff:
+ FOR_EACH_LINE(
+ *ptr |= mask;
+ ptr[1] = ~(chunk) 0;
+ ptr[2] |= right_mask;
+ );
+ break;
+ default:
+ FOR_EACH_LINE(
+ *ptr = (*ptr & ~mask) | (pattern & mask);
+ ptr[1] = pattern;
+ ptr[2] = (ptr[2] & ~right_mask) | (pattern & right_mask);
+ );
+ }
+ break;
+ default:{ /* >3 chunks */
+ uint byte_count = (last_bit >> 3) & -chunk_bytes;
+
+ switch ((byte) pattern) {
+ case 0:
+ FOR_EACH_LINE(
+ *ptr &= ~mask;
+ memset(ptr + 1, 0, byte_count);
+ ptr[last + 1] &= ~right_mask;
+ );
+ break;
+ case 0xff:
+ FOR_EACH_LINE(
+ *ptr |= mask;
+ memset(ptr + 1, 0xff, byte_count);
+ ptr[last + 1] |= right_mask;
+ );
+ break;
+ default:
+ FOR_EACH_LINE(
+ *ptr = (*ptr & ~mask) | (pattern & mask);
+ memset(ptr + 1, (byte) pattern, byte_count);
+ ptr[last + 1] =
+ (ptr[last + 1] & ~right_mask) |
+ (pattern & right_mask);
+ );
+ }
+ }
+ }
+ }
+#undef FOR_EACH_LINE
+}
+
+/* Replicate a bitmap horizontally in place. */
+void
+bits_replicate_horizontally(byte * data, uint width, uint height,
+ uint raster, uint replicated_width, uint replicated_raster)
+{ /* The current algorithm is extremely inefficient. */
+ uint y;
+
+ for (y = height; y-- > 0;) {
+ const byte *orig_row = data + y * raster;
+ byte *tile_row = data + y * replicated_raster;
+ uint sx;
+
+ if (!(width & 7)) {
+ uint wbytes = width >> 3;
+
+ for (sx = wbytes; sx-- > 0;) {
+ byte sb = orig_row[sx];
+ uint dx;
+
+ for (dx = sx + (replicated_width >> 3); dx >= wbytes;)
+ tile_row[dx -= wbytes] = sb;
+ }
+ } else
+ for (sx = width; sx-- > 0;) {
+ byte sm = orig_row[sx >> 3] & (0x80 >> (sx & 7));
+ uint dx;
+
+ for (dx = sx + replicated_width; dx >= width;
+ ) {
+ byte *dp =
+ (dx -= width, tile_row + (dx >> 3));
+ byte dm = 0x80 >> (dx & 7);
+
+ if (sm)
+ *dp |= dm;
+ else
+ *dp &= ~dm;
+ }
+ }
+ }
+}
+
+/* Replicate a bitmap vertically in place. */
+void
+bits_replicate_vertically(byte * data, uint height, uint raster,
+ uint replicated_height)
+{
+ byte *dest = data;
+ uint h = replicated_height;
+ uint size = raster * height;
+
+ while (h > height) {
+ memcpy(dest + size, dest, size);
+ dest += size;
+ h -= height;
+ }
+}
+
+/* Find the bounding box of a bitmap. */
+/* Assume bits beyond the width are zero. */
+void
+bits_bounding_box(const byte * data, uint height, uint raster,
+ gs_int_rect * pbox)
+{
+ register const ulong *lp;
+ static const byte first_1[16] =
+ {4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0};
+ static const byte last_1[16] =
+ {0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4};
+
+ /* Count trailing blank rows. */
+ /* Since the raster is a multiple of sizeof(long), */
+ /* we don't need to scan by bytes, only by longs. */
+
+ lp = (const ulong *)(data + raster * height);
+ while ((const byte *)lp > data && !lp[-1])
+ --lp;
+ if ((const byte *)lp == data) {
+ pbox->p.x = pbox->q.x = pbox->p.y = pbox->q.y = 0;
+ return;
+ }
+ pbox->q.y = height = ((const byte *)lp - data + raster - 1) / raster;
+
+ /* Count leading blank rows. */
+
+ lp = (const ulong *)data;
+ while (!*lp)
+ ++lp;
+ {
+ uint n = ((const byte *)lp - data) / raster;
+
+ pbox->p.y = n;
+ if (n)
+ height -= n, data += n * raster;
+ }
+
+ /* Find the left and right edges. */
+ /* We know that the first and last rows are non-blank. */
+
+ {
+ uint raster_longs = raster >> arch_log2_sizeof_long;
+ uint left = raster_longs - 1, right = 0;
+ ulong llong = 0, rlong = 0;
+ const byte *q;
+ uint h, n;
+
+ for (q = data, h = height; h-- > 0; q += raster) { /* Work from the left edge by longs. */
+ for (lp = (const ulong *)q, n = 0;
+ n < left && !*lp; lp++, n++
+ );
+ if (n < left)
+ left = n, llong = *lp;
+ else
+ llong |= *lp;
+ /* Work from the right edge by longs. */
+ for (lp = (const ulong *)(q + raster - sizeof(long)),
+ n = raster_longs - 1;
+
+ n > right && !*lp; lp--, n--
+ );
+ if (n > right)
+ right = n, rlong = *lp;
+ else
+ rlong |= *lp;
+ }
+
+ /* Do binary subdivision on edge longs. We assume that */
+ /* sizeof(long) = 4 or 8. */
+#if arch_sizeof_long > 8
+ Error_longs_are_too_large();
+#endif
+
+#if arch_is_big_endian
+# define last_bits(n) ((1L << (n)) - 1)
+# define shift_out_last(x,n) ((x) >>= (n))
+# define right_justify_last(x,n) DO_NOTHING
+#else
+# define last_bits(n) (-1L << ((arch_sizeof_long * 8) - (n)))
+# define shift_out_last(x,n) ((x) <<= (n))
+# define right_justify_last(x,n) (x) >>= ((arch_sizeof_long * 8) - (n))
+#endif
+
+ left <<= arch_log2_sizeof_long + 3;
+#if arch_sizeof_long == 8
+ if (llong & ~last_bits(32))
+ shift_out_last(llong, 32);
+ else
+ left += 32;
+#endif
+ if (llong & ~last_bits(16))
+ shift_out_last(llong, 16);
+ else
+ left += 16;
+ if (llong & ~last_bits(8))
+ shift_out_last(llong, 8);
+ else
+ left += 8;
+ right_justify_last(llong, 8);
+ if (llong & 0xf0)
+ left += first_1[(byte) llong >> 4];
+ else
+ left += first_1[(byte) llong] + 4;
+
+ right <<= arch_log2_sizeof_long + 3;
+#if arch_sizeof_long == 8
+ if (!(rlong & last_bits(32)))
+ shift_out_last(rlong, 32);
+ else
+ right += 32;
+#endif
+ if (!(rlong & last_bits(16)))
+ shift_out_last(rlong, 16);
+ else
+ right += 16;
+ if (!(rlong & last_bits(8)))
+ shift_out_last(rlong, 8);
+ else
+ right += 8;
+ right_justify_last(rlong, 8);
+ if (!(rlong & 0xf))
+ right += last_1[(byte) rlong >> 4];
+ else
+ right += last_1[(uint) rlong & 0xf] + 4;
+
+ pbox->p.x = left;
+ pbox->q.x = right;
+ }
+}
+
+/* Count the number of 1-bits in a half-byte. */
+static const byte half_byte_1s[16] =
+{0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4};
+
+/* Count the number of trailing 1s in an up-to-5-bit value, -1. */
+static const byte bits5_trailing_1s[32] =
+{0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 4};
+
+/* Count the number of leading 1s in an up-to-5-bit value, -1. */
+static const byte bits5_leading_1s[32] =
+{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, 1, 1, 1, 2, 2, 3, 4};
+
+/*
+ * Compress a value between 0 and 2^M to a value between 0 and 2^N-1.
+ * Possible values of M are 1, 2, 3, or 4; of N are 1, 2, and 4.
+ * The name of the table is compress_count_M_N.
+ * As noted below, we require that N <= M.
+ */
+static const byte compress_1_1[3] =
+{0, 1, 1};
+static const byte compress_2_1[5] =
+{0, 0, 1, 1, 1};
+static const byte compress_2_2[5] =
+{0, 1, 2, 2, 3};
+static const byte compress_3_1[9] =
+{0, 0, 0, 0, 1, 1, 1, 1, 1};
+static const byte compress_3_2[9] =
+{0, 0, 1, 1, 2, 2, 2, 3, 3};
+static const byte compress_4_1[17] =
+{0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
+static const byte compress_4_2[17] =
+{0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3};
+static const byte compress_4_4[17] =
+{0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 10, 11, 12, 13, 14, 15};
+
+/* The table of tables is indexed by log2(N) and then by M-1. */
+static const byte *const compress_tables[4][4] =
+{
+ {compress_1_1, compress_2_1, compress_3_1, compress_4_1},
+ {0, compress_2_2, compress_3_2, compress_4_2},
+ {0, 0, 0, compress_4_4}
+};
+
+/*
+ * Compress an XxY-oversampled bitmap to Nx1 by counting 1-bits. The X and
+ * Y oversampling factors are 1, 2, or 4, but may be different. N, the
+ * resulting number of (alpha) bits per pixel, may be 1, 2, or 4; we allow
+ * compression in place, in which case N must not exceed the X oversampling
+ * factor. Width and height are the source dimensions, and hence reflect
+ * the oversampling; both are multiples of the relevant scale factor. The
+ * same is true for srcx.
+ */
+void
+bits_compress_scaled(const byte * src, int srcx, uint width, uint height,
+ uint sraster, byte * dest, uint draster,
+ const gs_log2_scale_point * plog2_scale, int log2_out_bits)
+{
+ int log2_x = plog2_scale->x, log2_y = plog2_scale->y;
+ int xscale = 1 << log2_x;
+ int yscale = 1 << log2_y;
+ int out_bits = 1 << log2_out_bits;
+ int input_byte_out_bits;
+ byte input_byte_out_mask;
+ const byte *table =
+ compress_tables[log2_out_bits][log2_x + log2_y - 1];
+ uint sskip = sraster << log2_y;
+ uint dwidth = (width >> log2_x) << log2_out_bits;
+ uint dskip = draster - ((dwidth + 7) >> 3);
+ uint mask = (1 << xscale) - 1;
+ uint count_max = 1 << (log2_x + log2_y);
+
+ /*
+ * For right now, we don't attempt to take advantage of the fact
+ * that the input is aligned.
+ */
+ const byte *srow = src + (srcx >> 3);
+ int in_shift_initial = 8 - xscale - (srcx & 7);
+ int in_shift_check = (out_bits <= xscale ? 8 - xscale : -1);
+ byte *d = dest;
+ uint h;
+
+ if (out_bits <= xscale)
+ {
+ input_byte_out_bits = out_bits << (3 - log2_x);
+ input_byte_out_mask = (1 << input_byte_out_bits) - 1;
+ }
+ else
+ {
+ input_byte_out_bits = out_bits;
+ input_byte_out_mask = (1 << input_byte_out_bits) - 1;
+ }
+
+ for (h = height; h; srow += sskip, h -= yscale) {
+ const byte *s = srow;
+
+#if ALPHA_LSB_FIRST
+# define out_shift_initial 0
+# define out_shift_update(out_shift, nbits) ((out_shift += (nbits)) >= 8)
+#else
+# define out_shift_initial (8 - out_bits)
+# define out_shift_update(out_shift, nbits) ((out_shift -= (nbits)) < 0)
+#endif
+ int out_shift = out_shift_initial;
+ byte out = 0;
+ int in_shift = in_shift_initial;
+ int dw = 8 - (srcx & 7);
+ int w;
+
+ /* Loop over source bytes. */
+ for (w = width; w > 0; w -= dw, dw = 8) {
+ int index;
+ int in_shift_final =
+ (w >= dw ? 0 : dw - w);
+
+ /*
+ * Check quickly for all-0s or all-1s, but only if each
+ * input byte generates no more than one output byte,
+ * we're at an input byte boundary, and we're processing
+ * an entire input byte (i.e., this isn't a final
+ * partial byte.)
+ */
+ if (in_shift == in_shift_check && in_shift_final == 0)
+ switch (*s) {
+ case 0:
+ for (index = sraster; index != sskip; index += sraster)
+ if (s[index] != 0)
+ goto p;
+ if (out_shift_update(out_shift, input_byte_out_bits))
+ *d++ = out, out_shift &= 7, out = 0;
+ s++;
+ continue;
+#if !ALPHA_LSB_FIRST /* too messy to make it work */
+ case 0xff:
+ for (index = sraster; index != sskip; index += sraster)
+ if (s[index] != 0xff)
+ goto p;
+ {
+ int shift =
+ (out_shift -= input_byte_out_bits) + out_bits;
+
+ if (shift > 0)
+ out |= input_byte_out_mask << shift;
+ else {
+ out |= input_byte_out_mask >> -shift;
+ *d++ = out;
+ out_shift += 8;
+ out = input_byte_out_mask << (8 + shift);
+ }
+ }
+ s++;
+ continue;
+#endif
+ default:
+ ;
+ }
+ p: /* Loop over source pixels within a byte. */
+ do {
+ uint count;
+
+ for (index = 0, count = 0; index != sskip;
+ index += sraster
+ )
+ count += half_byte_1s[(s[index] >> in_shift) & mask];
+ if (count != 0 && table[count] == 0) { /* Look at adjacent cells to help prevent */
+ /* dropouts. */
+ uint orig_count = count;
+ uint shifted_mask = mask << in_shift;
+ byte in;
+
+ if_debug3('B', "[B]count(%d,%d)=%d\n",
+ (width - w) / xscale,
+ (height - h) / yscale, count);
+ if (yscale > 1) { /* Look at the next "lower" cell. */
+ if (h < height && (in = s[0] & shifted_mask) != 0) {
+ uint lower;
+
+ for (index = 0, lower = 0;
+ -(index -= sraster) <= sskip &&
+ (in &= s[index]) != 0;
+ )
+ lower += half_byte_1s[in >> in_shift];
+ if_debug1('B', "[B] lower adds %d\n",
+ lower);
+ if (lower <= orig_count)
+ count += lower;
+ }
+ /* Look at the next "higher" cell. */
+ if (h > yscale && (in = s[sskip - sraster] & shifted_mask) != 0) {
+ uint upper;
+
+ for (index = sskip, upper = 0;
+ index < sskip << 1 &&
+ (in &= s[index]) != 0;
+ index += sraster
+ )
+ upper += half_byte_1s[in >> in_shift];
+ if_debug1('B', "[B] upper adds %d\n",
+ upper);
+ if (upper < orig_count)
+ count += upper;
+ }
+ }
+ if (xscale > 1) {
+ uint mask1 = (mask << 1) + 1;
+
+ /* Look at the next cell to the left. */
+ if (w < width) {
+ int lshift = in_shift + xscale - 1;
+ uint left;
+
+ for (index = 0, left = 0;
+ index < sskip; index += sraster
+ ) {
+ uint bits =
+ ((s[index - 1] << 8) +
+ s[index]) >> lshift;
+
+ left += bits5_trailing_1s[bits & mask1];
+ }
+ if_debug1('B', "[B] left adds %d\n",
+ left);
+ if (left < orig_count)
+ count += left;
+ }
+ /* Look at the next cell to the right. */
+ if (w > xscale) {
+ int rshift = in_shift - xscale + 8;
+ uint right;
+
+ for (index = 0, right = 0;
+ index < sskip; index += sraster
+ ) {
+ uint bits =
+ ((s[index] << 8) +
+ s[index + 1]) >> rshift;
+
+ right += bits5_leading_1s[(bits & mask1) << (4 - xscale)];
+ }
+ if_debug1('B', "[B] right adds %d\n",
+ right);
+ if (right <= orig_count)
+ count += right;
+ }
+ }
+ if (count > count_max)
+ count = count_max;
+ }
+ out += table[count] << out_shift;
+ if (out_shift_update(out_shift, out_bits))
+ *d++ = out, out_shift &= 7, out = 0;
+ }
+ while ((in_shift -= xscale) >= in_shift_final);
+ s++, in_shift += 8;
+ }
+ if (out_shift != out_shift_initial)
+ *d++ = out;
+ for (w = dskip; w != 0; w--)
+ *d++ = 0;
+#undef out_shift_initial
+#undef out_shift_update
+ }
+}
+
+/* ---------------- Byte-oriented operations ---------------- */
+
+/* Fill a rectangle of bytes. */
+void
+bytes_fill_rectangle(byte * dest, uint raster,
+ byte value, int width_bytes, int height)
+{
+ while (height-- > 0) {
+ memset(dest, value, width_bytes);
+ dest += raster;
+ }
+}
+
+/* Copy a rectangle of bytes. */
+void
+bytes_copy_rectangle(byte * dest, uint dest_raster,
+ const byte * src, uint src_raster, int width_bytes, int height)
+{
+ while (height-- > 0) {
+ memcpy(dest, src, width_bytes);
+ src += src_raster;
+ dest += dest_raster;
+ }
+}
diff --git a/pstoraster/gsbitops.h b/pstoraster/gsbitops.h
new file mode 100644
index 000000000..efaeef228
--- /dev/null
+++ b/pstoraster/gsbitops.h
@@ -0,0 +1,222 @@
+/* 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 for bitmap operations */
+
+#ifndef gsbitops_INCLUDED
+# define gsbitops_INCLUDED
+
+/* ---------------- Pixel processing macros ---------------- */
+
+/*
+ * These macros support code that processes data pixel-by-pixel (or, to be
+ * more accurate, packed arrays of values -- they may be complete pixels
+ * or individual components of pixels).
+ *
+ * Supported #s of bits per value (bpv) are 1, 2, 4, 8, 12[, 16[, 24, 32]].
+ * The suffix 12, 16, or 32 on a macro name indicates the maximum value
+ * of bpv that the macro is prepared to handle.
+ *
+ * The setup macros number bits within a byte in big-endian order, i.e.,
+ * 0x80 is bit 0, 0x01 is bit 7. However, sbit/dbit may use a different
+ * representation for better performance. ****** NYI ******
+ */
+
+#define sample_end_\
+ default: return_error(gs_error_rangecheck);\
+ } END
+
+/* Declare variables for loading. */
+#define sample_load_declare(sptr, sbit)\
+ const byte *sptr;\
+ int sbit
+#define sample_load_declare_setup(sptr, sbit, ptr, bitno, sbpv)\
+ const byte *sptr = (ptr);\
+ int sample_load_setup(sbit, bitno, sbpv)
+
+/* Set up to load starting at a given bit number. */
+#define sample_load_setup(sbit, bitno, sbpv)\
+ sbit = (bitno)
+
+/* Load a value from memory, without incrementing. */
+#define sample_load12_(value, sptr, sbit, sbpv)\
+ BEGIN\
+ switch ( (sbpv) >> 2 ) {\
+ case 0: value = (*(sptr) >> (8 - (sbit) - (sbpv))) & ((sbpv) - 1); break;\
+ case 1: value = (*(sptr) >> (4 - (sbit))) & 0xf; break;\
+ case 2: value = *(sptr); break;\
+ case 3:\
+ value = ((sbit) ? ((*(sptr) & 0xf) << 8) | (sptr)[1] :\
+ (*(sptr) << 4) | ((sptr)[1] >> 4));\
+ break;
+#define sample_load12(value, sptr, sbit, sbpv)\
+ sample_load12_(value, sptr, sbit, sbpv)\
+ sample_end_
+#define sample_load_next12(value, sptr, sbit, sbpv)\
+ sample_load12(value, sptr, sbit, sbpv);\
+ sample_next(sptr, sbit, sbpv)
+#define sample_load16_(value, sptr, sbit, sbpv)\
+ sample_load12_(value, sptr, sbit, sbpv)\
+ case 4: value = (*(sptr) << 8) | (sptr)[1]; break;
+#define sample_load16(value, sptr, sbit, sbpv)\
+ sample_load16_(value, sptr, sbit, sbpv)\
+ sample_end_
+#define sample_load_next16(value, sptr, sbit, sbpv)\
+ sample_load16(value, sptr, sbit, sbpv);\
+ sample_next(sptr, sbit, sbpv)
+#define sample_load32(value, sptr, sbit, sbpv)\
+ sample_load16_(value, sptr, sbit, sbpv)\
+ case 6: value = (*(sptr) << 16) | ((sptr)[1] << 8) | (sptr)[2]; break;\
+ case 8:\
+ value = (*(sptr) << 24) | ((sptr)[1] << 16) | ((sptr)[2] << 8) | sptr[3];\
+ break;\
+ sample_end_
+#define sample_load_next32(value, sptr, sbit, sbpv)\
+ sample_load32(value, sptr, sbit, sbpv);\
+ sample_next(sptr, sbit, sbpv)
+
+/* Declare variables for storing. */
+#define sample_store_declare(dptr, dbit, dbbyte)\
+ byte *dptr;\
+ int dbit;\
+ byte dbbyte /* maybe should be uint? */
+#define sample_store_declare_setup(dptr, dbit, dbbyte, ptr, bitno, dbpv)\
+ byte *dptr = (ptr);\
+ int sample_store_setup(dbit, bitno, dbpv);\
+ byte /* maybe should be uint? */\
+ sample_store_preload(dbbyte, dptr, dbit, dbpv)
+
+/* Set up to store starting at a given bit number. */
+#define sample_store_setup(dbit, bitno, dbpv)\
+ dbit = (bitno)
+
+/* Prepare for storing by preloading any partial byte. */
+#define sample_store_preload(dbbyte, dptr, dbit, dbpv)\
+ dbbyte = ((dbit) ? (byte)(*(dptr) & (0xff00 >> (dbit))) : 0)
+
+/* Store a value and increment the pointer. */
+#define sample_store_next12_(value, dptr, dbit, dbpv, dbbyte)\
+ BEGIN\
+ switch ( (dbpv) >> 2 ) {\
+ case 0:\
+ if ( (dbit += (dbpv)) == 8 )\
+ *(dptr)++ = dbbyte | (value), dbbyte = 0, dbit = 0;\
+ else dbbyte |= (value) << (8 - dbit);\
+ break;\
+ case 1:\
+ if ( dbit ^= 4 ) dbbyte = (byte)((value) << 4);\
+ else *(dptr)++ = dbbyte | (value);\
+ break;\
+ /* case 2 is deliberately omitted */\
+ case 3:\
+ if ( dbit ^= 4 ) *(dptr)++ = (value) >> 4, dbbyte = (byte)((value) << 4);\
+ else\
+ *(dptr) = dbbyte | ((value) >> 8), (dptr)[1] = (byte)(value), dptr += 2;\
+ break;
+#define sample_store_next12(value, dptr, dbit, dbpv, dbbyte)\
+ sample_store_next12_(value, dptr, dbit, dbpv, dbbyte)\
+ case 2: *(dptr)++ = (byte)(value); break;\
+ sample_end_
+#define sample_store_next16(value, dptr, dbit, dbpv, dbbyte)\
+ sample_store_next12_(value, dptr, dbit, dbpv, dbbyte)\
+ case 4: *(dptr)++ = (byte)((value) >> 8);\
+ case 2: *(dptr)++ = (byte)(value); break;\
+ sample_end_
+#define sample_store_next32(value, dptr, dbit, dbpv, dbbyte)\
+ sample_store_next12_(value, dptr, dbit, dbpv, dbbyte)\
+ case 8: *(dptr)++ = (byte)((value) >> 24);\
+ case 6: *(dptr)++ = (byte)((value) >> 16);\
+ case 4: *(dptr)++ = (byte)((value) >> 8);\
+ case 2: *(dptr)++ = (byte)(value); break;\
+ sample_end_
+
+/* Skip over storing one sample. This may or may not store into the */
+/* skipped region. */
+#define sample_store_skip_next(dptr, dbit, dbpv, dbbyte)\
+ if ( (dbpv) < 8 ) {\
+ sample_store_flush(dptr, dbit, dbpv, dbbyte);\
+ sample_next(dptr, dbit, dbpv);\
+ } else dptr += ((dbpv) >> 3)
+
+/* Finish storing by flushing any partial byte. */
+#define sample_store_flush(dptr, dbit, dbpv, dbbyte)\
+ if ( (dbit) != 0 )\
+ *(dptr) = dbbyte | (*(dptr) & (0xff >> (dbit)));
+
+/* Increment a pointer to the next sample. */
+#define sample_next(ptr, bit, bpv)\
+ BEGIN bit += (bpv); ptr += bit >> 3; bit &= 7; END
+
+/* ---------------- Definitions ---------------- */
+
+/*
+ * Define the chunk size for monobit filling operations.
+ * This is always uint, regardless of byte order.
+ */
+#define mono_fill_chunk uint
+#define mono_fill_chunk_bytes arch_sizeof_int
+
+/* ---------------- Procedures ---------------- */
+
+/* Fill a rectangle of bits with an 8x1 pattern. */
+/* The pattern argument must consist of the pattern in every byte, */
+/* e.g., if the desired pattern is 0xaa, the pattern argument must */
+/* have the value 0xaaaa (if ints are short) or 0xaaaaaaaa. */
+#if mono_fill_chunk_bytes == 2
+# define mono_fill_make_pattern(byt) (uint)((uint)(byt) * 0x0101)
+#else
+# define mono_fill_make_pattern(byt) (uint)((uint)(byt) * 0x01010101)
+#endif
+void bits_fill_rectangle(P6(byte * dest, int dest_bit, uint raster,
+ mono_fill_chunk pattern, int width_bits, int height));
+
+/* Replicate a bitmap horizontally in place. */
+void bits_replicate_horizontally(P6(byte * data, uint width, uint height,
+ uint raster, uint replicated_width, uint replicated_raster));
+
+/* Replicate a bitmap vertically in place. */
+void bits_replicate_vertically(P4(byte * data, uint height, uint raster,
+ uint replicated_height));
+
+/* Find the bounding box of a bitmap. */
+void bits_bounding_box(P4(const byte * data, uint height, uint raster,
+ gs_int_rect * pbox));
+
+/* Compress an oversampled image, possibly in place. */
+/* The width and height must be multiples of the respective scale factors. */
+/* The source must be an aligned bitmap, as usual. */
+void bits_compress_scaled(P9(const byte * src, int srcx, uint width,
+ uint height, uint sraster, byte * dest, uint draster,
+ const gs_log2_scale_point * plog2_scale, int log2_out_bits));
+
+/* Fill a rectangle of bytes. */
+void bytes_fill_rectangle(P5(byte * dest, uint raster,
+ byte value, int width_bytes, int height));
+
+/* Copy a rectangle of bytes. */
+void bytes_copy_rectangle(P6(byte * dest, uint dest_raster,
+ const byte * src, uint src_raster, int width_bytes, int height));
+
+#endif /* gsbitops_INCLUDED */
diff --git a/pstoraster/gsbittab.c b/pstoraster/gsbittab.c
new file mode 100644
index 000000000..ac2c5abdb
--- /dev/null
+++ b/pstoraster/gsbittab.c
@@ -0,0 +1,144 @@
+/* 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$ */
+/* Tables for bit operations */
+#include "stdpre.h"
+#include "gsbittab.h"
+
+/* ---------------- Byte processing tables ---------------- */
+
+/*
+ * byte_reverse_bits[B] = the byte B with the order of bits reversed.
+ */
+const byte byte_reverse_bits[256] =
+{
+ bit_table_8(0, 1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80)
+};
+
+/*
+ * byte_right_mask[N] = a byte with N trailing 1s, 0 <= N <= 8.
+ */
+const byte byte_right_mask[9] =
+{
+ 0, 1, 3, 7, 0xf, 0x1f, 0x3f, 0x7f, 0xff
+};
+
+/*
+ * byte_count_bits[B] = the number of 1-bits in a byte with value B.
+ */
+const byte byte_count_bits[256] =
+{
+ bit_table_8(0, 1, 1, 1, 1, 1, 1, 1, 1)
+};
+
+/* ---------------- Scanning tables ---------------- */
+
+/*
+ * byte_bit_run_length_N[B], for 0 <= N <= 7, gives the length of the
+ * run of 1-bits starting at bit N in a byte with value B,
+ * numbering the bits in the byte as 01234567. If the run includes
+ * the low-order bit (i.e., might be continued into a following byte),
+ * the run length is increased by 8.
+ */
+
+#define t8(n) n,n,n,n,n+1,n+1,n+2,n+11
+#define r8(n) n,n,n,n,n,n,n,n
+#define r16(n) r8(n),r8(n)
+#define r32(n) r16(n),r16(n)
+#define r64(n) r32(n),r32(n)
+#define r128(n) r64(n),r64(n)
+const byte byte_bit_run_length_0[256] =
+{
+ r128(0), r64(1), r32(2), r16(3), r8(4), t8(5)
+};
+const byte byte_bit_run_length_1[256] =
+{
+ r64(0), r32(1), r16(2), r8(3), t8(4),
+ r64(0), r32(1), r16(2), r8(3), t8(4)
+};
+const byte byte_bit_run_length_2[256] =
+{
+ r32(0), r16(1), r8(2), t8(3),
+ r32(0), r16(1), r8(2), t8(3),
+ r32(0), r16(1), r8(2), t8(3),
+ r32(0), r16(1), r8(2), t8(3)
+};
+const byte byte_bit_run_length_3[256] =
+{
+ r16(0), r8(1), t8(2), r16(0), r8(1), t8(2),
+ r16(0), r8(1), t8(2), r16(0), r8(1), t8(2),
+ r16(0), r8(1), t8(2), r16(0), r8(1), t8(2),
+ r16(0), r8(1), t8(2), r16(0), r8(1), t8(2)
+};
+const byte byte_bit_run_length_4[256] =
+{
+ r8(0), t8(1), r8(0), t8(1), r8(0), t8(1), r8(0), t8(1),
+ r8(0), t8(1), r8(0), t8(1), r8(0), t8(1), r8(0), t8(1),
+ r8(0), t8(1), r8(0), t8(1), r8(0), t8(1), r8(0), t8(1),
+ r8(0), t8(1), r8(0), t8(1), r8(0), t8(1), r8(0), t8(1),
+};
+
+#define rr8(a,b,c,d,e,f,g,h)\
+ a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h,\
+ a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h,\
+ a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h,\
+ a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h,\
+ a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h,\
+ a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h,\
+ a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h,\
+ a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h, a,b,c,d,e,f,g,h
+const byte byte_bit_run_length_5[256] =
+{
+ rr8(0, 0, 0, 0, 1, 1, 2, 11)
+};
+const byte byte_bit_run_length_6[256] =
+{
+ rr8(0, 0, 1, 10, 0, 0, 1, 10)
+};
+const byte byte_bit_run_length_7[256] =
+{
+ rr8(0, 9, 0, 9, 0, 9, 0, 9)
+};
+
+/* Pointer tables indexed by bit number. */
+
+const byte *const byte_bit_run_length[8] =
+{byte_bit_run_length_0, byte_bit_run_length_1,
+ byte_bit_run_length_2, byte_bit_run_length_3,
+ byte_bit_run_length_4, byte_bit_run_length_5,
+ byte_bit_run_length_6, byte_bit_run_length_7
+};
+const byte *const byte_bit_run_length_neg[8] =
+{byte_bit_run_length_0, byte_bit_run_length_7,
+ byte_bit_run_length_6, byte_bit_run_length_5,
+ byte_bit_run_length_4, byte_bit_run_length_3,
+ byte_bit_run_length_2, byte_bit_run_length_1
+};
+
+/* Some C compilers insist on having executable code in every file.... */
+void
+gsbittab_dummy(void)
+{
+}
diff --git a/pstoraster/gsbittab.h b/pstoraster/gsbittab.h
new file mode 100644
index 000000000..f41e2ed9a
--- /dev/null
+++ b/pstoraster/gsbittab.h
@@ -0,0 +1,83 @@
+/* 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$ */
+/* Interface to tables for bit operations */
+
+#ifndef gsbittab_INCLUDED
+# define gsbittab_INCLUDED
+
+/*
+ * Generate tables for transforming 2, 4, 6, or 8 bits.
+ */
+#define btab2_(v0,v2,v1)\
+ v0,v1+v0,v2+v0,v2+v1+v0
+#define bit_table_2(v0,v2,v1) btab2_(v0,v2,v1)
+#define btab4_(v0,v8,v4,v2,v1)\
+ btab2_(v0,v2,v1), btab2_(v4+v0,v2,v1),\
+ btab2_(v8+v0,v2,v1), btab2_(v8+v4+v0,v2,v1)
+#define bit_table_4(v0,v8,v4,v2,v1) btab4_(v0,v8,v4,v2,v1)
+#define btab6_(v0,v20,v10,v8,v4,v2,v1)\
+ btab4_(v0,v8,v4,v2,v1), btab4_(v10+v0,v8,v4,v2,v1),\
+ btab4_(v20+v0,v8,v4,v2,v1), btab4_(v20+v10+v0,v8,v4,v2,v1)
+#define bit_table_6(v0,v20,v10,v8,v4,v2,v1) btab6_(v0,v20,v10,v8,v4,v2,v1)
+#define bit_table_8(v0,v80,v40,v20,v10,v8,v4,v2,v1)\
+ btab6_(v0,v20,v10,v8,v4,v2,v1), btab6_(v40+v0,v20,v10,v8,v4,v2,v1),\
+ btab6_(v80+v0,v20,v10,v8,v4,v2,v1), btab6_(v80+v40+v0,v20,v10,v8,v4,v2,v1)
+
+/*
+ * byte_reverse_bits[B] = the byte B with the order of bits reversed.
+ */
+extern const byte byte_reverse_bits[256];
+
+/*
+ * byte_right_mask[N] = a byte with N trailing 1s, 0 <= N <= 8.
+ */
+extern const byte byte_right_mask[9];
+
+/*
+ * byte_count_bits[B] = the number of 1-bits in a byte with value B.
+ */
+extern const byte byte_count_bits[256];
+
+/*
+ * byte_bit_run_length_N[B], for 0 <= N <= 7, gives the length of the
+ * run of 1-bits starting at bit N in a byte with value B,
+ * numbering the bits in the byte as 01234567. If the run includes
+ * the low-order bit (i.e., might be continued into a following byte),
+ * the run length is increased by 8.
+ */
+extern const byte
+ byte_bit_run_length_0[256], byte_bit_run_length_1[256], byte_bit_run_length_2[256],
+ byte_bit_run_length_3[256], byte_bit_run_length_4[256], byte_bit_run_length_5[256],
+ byte_bit_run_length_6[256], byte_bit_run_length_7[256];
+
+/*
+ * byte_bit_run_length[N] points to byte_bit_run_length_N.
+ * byte_bit_run_length_neg[N] = byte_bit_run_length[-N & 7].
+ */
+extern const byte *const byte_bit_run_length[8];
+extern const byte *const byte_bit_run_length_neg[8];
+
+#endif /* gsbittab_INCLUDED */
diff --git a/pstoraster/gsccode.h b/pstoraster/gsccode.h
new file mode 100644
index 000000000..4945f5456
--- /dev/null
+++ b/pstoraster/gsccode.h
@@ -0,0 +1,72 @@
+/* Copyright (C) 1993, 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$ */
+/* Types for character codes */
+
+#ifndef gsccode_INCLUDED
+# define gsccode_INCLUDED
+
+/*
+ * Define a character code. Normally this is just a single byte from a
+ * string, but because of composite fonts, character codes must be
+ * at least 32 bits.
+ */
+typedef ulong gs_char;
+
+#define gs_no_char ((gs_char)~0L)
+
+/*
+ * Define a character glyph code, a.k.a. character name.
+ * gs_glyphs from 0 to 2^31-1 are (PostScript) names; gs_glyphs 2^31 and
+ * above are CIDs, biased by 2^31.
+ */
+typedef ulong gs_glyph;
+
+#define gs_no_glyph ((gs_glyph)0x7fffffff)
+#define gs_min_cid_glyph ((gs_glyph)0x80000000)
+#define gs_max_glyph max_ulong
+
+/* Define a procedure for marking a gs_glyph during garbage collection. */
+typedef bool(*gs_glyph_mark_proc_t) (P2(gs_glyph glyph, void *proc_data));
+
+/* Define a procedure for mapping a gs_glyph to its (string) name. */
+#define gs_proc_glyph_name(proc)\
+ const char *proc(P2(gs_glyph, uint *))
+/* The following typedef is needed because ansi2knr can't handle */
+/* gs_proc_glyph_name((*procname)) in a formal argument list. */
+typedef gs_proc_glyph_name((*gs_proc_glyph_name_t));
+
+/* Define a procedure for accessing the known encodings. */
+#define gs_proc_known_encode(proc)\
+ gs_glyph proc(P2(gs_char, int))
+typedef gs_proc_known_encode((*gs_proc_known_encode_t));
+
+/* Define the callback procedure vector for character to xglyph mapping. */
+typedef struct gx_xfont_callbacks_s {
+ gs_proc_glyph_name((*glyph_name));
+ gs_proc_known_encode((*known_encode));
+} gx_xfont_callbacks;
+
+#endif /* gsccode_INCLUDED */
diff --git a/pstoraster/gsccolor.h b/pstoraster/gsccolor.h
new file mode 100644
index 000000000..efe1345aa
--- /dev/null
+++ b/pstoraster/gsccolor.h
@@ -0,0 +1,58 @@
+/* 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$ */
+/* Client color structure definition */
+
+#ifndef gsccolor_INCLUDED
+# define gsccolor_INCLUDED
+
+#include "gsstruct.h" /* for extern_st */
+
+/* Pattern instance, usable in color. */
+typedef struct gs_pattern_instance_s gs_pattern_instance;
+
+/* Paint (non-pattern) colors (Device, CIE, Indexed, Separation) */
+typedef struct gs_paint_color_s {
+ float values[4];
+} gs_paint_color;
+
+/* General colors */
+#ifndef gs_client_color_DEFINED
+# define gs_client_color_DEFINED
+typedef struct gs_client_color_s gs_client_color;
+
+#endif
+struct gs_client_color_s {
+ gs_paint_color paint; /* also color for uncolored pattern */
+ gs_pattern_instance *pattern;
+};
+
+extern_st(st_client_color);
+#define public_st_client_color() /* in gscolor.c */\
+ gs_public_st_ptrs1(st_client_color, gs_client_color, "gs_client_color",\
+ client_color_enum_ptrs, client_color_reloc_ptrs, pattern)
+#define st_client_color_max_ptrs 1
+
+#endif /* gsccolor_INCLUDED */
diff --git a/pstoraster/gscdefs.c b/pstoraster/gscdefs.c
new file mode 100644
index 000000000..846e89ae6
--- /dev/null
+++ b/pstoraster/gscdefs.c
@@ -0,0 +1,78 @@
+/*
+ Copyright 1993-2002 by Easy Software Products.
+ Copyright 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 scalars */
+#include "stdpre.h"
+#include "gscdefs.h" /* interface */
+#include "gconf.h" /* for #defines */
+#include <config.h>
+
+/* ---------------- Miscellaneous system parameters ---------------- */
+
+/* All of these can be set in the makefile. */
+/* Normally they are all const; see gscdefs.h for more information. */
+
+#ifndef GS_BUILDTIME
+# define GS_BUILDTIME\
+ 0 /* should be set in the makefile */
+#endif
+CONFIG_CONST long gs_buildtime = GS_BUILDTIME;
+
+#ifndef GS_COPYRIGHT
+# define GS_COPYRIGHT\
+ "Copyright 1993-2002 Easy Software Products, All Rights Reserved.\n"\
+ "Copyright 1998 Aladdin Enterprises, Menlo Park, CA. All rights reserved."
+#endif
+const char *CONFIG_CONST gs_copyright = GS_COPYRIGHT;
+
+#ifndef GS_PRODUCT
+# define GS_PRODUCT CUPS_SVERSION
+#endif
+const char *CONFIG_CONST gs_product = GS_PRODUCT;
+
+const char *
+gs_program_name(void)
+{
+ return gs_product;
+}
+
+CONFIG_CONST long gs_revision = 550;
+CONFIG_CONST long gs_revisiondate = 20000308;
+
+#ifndef GS_SERIALNUMBER
+# define GS_SERIALNUMBER\
+ 40100
+#endif
+CONFIG_CONST long gs_serialnumber = GS_SERIALNUMBER;
+
+/* ---------------- Installation directories and files ---------------- */
+
+/* Here is where the library search path, the name of the */
+/* initialization file, and the doc directory are defined. */
+
+/* Define the interpreter initialization file. */
+const char *const gs_init_file = "gs_init.ps";
diff --git a/pstoraster/gscdefs.h b/pstoraster/gscdefs.h
new file mode 100644
index 000000000..463782c64
--- /dev/null
+++ b/pstoraster/gscdefs.h
@@ -0,0 +1,81 @@
+/* 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$ */
+/* Prototypes for configuration definitions in gconfig.c. */
+
+#ifndef gscdefs_INCLUDED
+# define gscdefs_INCLUDED
+
+#include "gconfigv.h"
+
+/*
+ * This file may be #included in places that don't even have stdpre.h,
+ * so it mustn't use any Ghostscript definitions in any code that is
+ * actually processed here (as opposed to being part of a macro
+ * definition).
+ */
+
+/* Miscellaneous system constants (read-only systemparams). */
+/* They should all be const, but one application needs some of them */
+/* to be writable.... */
+
+#if SYSTEM_CONSTANTS_ARE_WRITABLE
+# define CONFIG_CONST /* */
+#else
+# define CONFIG_CONST const
+#endif
+
+extern CONFIG_CONST long gs_buildtime;
+extern const char *CONFIG_CONST gs_copyright;
+extern const char *CONFIG_CONST gs_product;
+extern CONFIG_CONST long gs_revision;
+extern CONFIG_CONST long gs_revisiondate;
+extern CONFIG_CONST long gs_serialnumber;
+
+/* Installation directories and files */
+extern const char *const gs_doc_directory;
+extern const char *const gs_lib_default_path;
+extern const char *const gs_init_file;
+
+/* Resource tables. In order to avoid importing a large number of types, */
+/* we only provide macros for the externs, not the externs themselves. */
+
+/* We need the extra typedef so that the const will apply to the table. */
+#define extern_gx_init_table()\
+ typedef void (*gx_init_proc)(P1(gs_memory_t *));\
+ extern const gx_init_proc gx_init_table[]
+
+/* We need the extra typedef so that the const will apply to the table. */
+#define extern_gx_io_device_table()\
+ extern const gx_io_device * const gx_io_device_table[]
+extern const unsigned gx_io_device_table_count;
+
+/* Return the list of device prototypes, the list of their structure */
+/* descriptors, and (as the value) the length of the lists. */
+#define extern_gs_lib_device_list()\
+ int gs_lib_device_list(P2(const gx_device * const **plist,\
+ gs_memory_struct_type_t **pst))
+
+#endif /* gscdefs_INCLUDED */
diff --git a/pstoraster/gscdevn.c b/pstoraster/gscdevn.c
new file mode 100644
index 000000000..af0b4847e
--- /dev/null
+++ b/pstoraster/gscdevn.c
@@ -0,0 +1,184 @@
+/* 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$ */
+/* DeviceN color space and operation definition */
+#include "gx.h"
+#include "gserrors.h"
+#include "gsrefct.h"
+#include "gsmatrix.h" /* for gscolor2.h */
+#include "gxcspace.h"
+
+gs_private_st_composite(st_color_space_DeviceN, gs_paint_color_space,
+ "gs_color_space_DeviceN", cs_DeviceN_enum_ptrs, cs_DeviceN_reloc_ptrs);
+
+/* Define the DeviceN color space type. */
+private cs_proc_num_components(gx_num_components_DeviceN);
+private cs_proc_base_space(gx_alt_space_DeviceN);
+private cs_proc_init_color(gx_init_DeviceN);
+private cs_proc_restrict_color(gx_restrict_DeviceN);
+private cs_proc_concrete_space(gx_concrete_space_DeviceN);
+private cs_proc_concretize_color(gx_concretize_DeviceN);
+private cs_proc_remap_concrete_color(gx_remap_concrete_DeviceN);
+private cs_proc_install_cspace(gx_install_DeviceN);
+private cs_proc_adjust_cspace_count(gx_adjust_cspace_DeviceN);
+const gs_color_space_type gs_color_space_type_DeviceN = {
+ gs_color_space_index_DeviceN, true, false,
+ &st_color_space_DeviceN, gx_num_components_DeviceN,
+ gx_alt_space_DeviceN,
+ gx_init_DeviceN, gx_restrict_DeviceN,
+ gx_concrete_space_DeviceN,
+ gx_concretize_DeviceN, gx_remap_concrete_DeviceN,
+ gx_default_remap_color, gx_install_DeviceN,
+ gx_adjust_cspace_DeviceN, gx_no_adjust_color_count
+};
+
+/* ------ Internal routines ------ */
+
+/* Return the number of components of a DeviceN space. */
+private int
+gx_num_components_DeviceN(const gs_color_space * pcs)
+{
+ return pcs->params.device_n.num_components;
+}
+
+/* Return the alternate space of a DeviceN space. */
+private const gs_color_space *
+gx_alt_space_DeviceN(const gs_color_space * pcs)
+{
+ return (const gs_color_space *)&(pcs->params.device_n.alt_space);
+}
+
+/* Initialize a DeviceN color. */
+/****** DOESN'T WORK IF num_components > 4 ******/
+private void
+gx_init_DeviceN(gs_client_color * pcc, const gs_color_space * pcs)
+{
+ int i;
+
+ for (i = 0; i < pcs->params.device_n.num_components; ++i)
+ pcc->paint.values[i] = 1.0;
+}
+
+/* Force a DeviceN color into legal range. */
+private void
+gx_restrict_DeviceN(gs_client_color * pcc, const gs_color_space * pcs)
+{
+ int i;
+
+ for (i = 0; i < pcs->params.device_n.num_components; ++i) {
+ floatp value = pcc->paint.values[i];
+
+ pcc->paint.values[i] = (value <= 0 ? 0 : value >= 1 ? 1 : value);
+ }
+}
+
+/* Remap a DeviceN color. */
+private const gs_color_space *
+gx_concrete_space_DeviceN(const gs_color_space * pcs,
+ const gs_imager_state * pis)
+{ /* We don't support concrete DeviceN spaces yet. */
+ const gs_color_space *pacs =
+ (const gs_color_space *)&pcs->params.device_n.alt_space;
+
+ return cs_concrete_space(pacs, pis);
+}
+
+private int
+gx_concretize_DeviceN(const gs_client_color * pc, const gs_color_space * pcs,
+ frac * pconc, const gs_imager_state * pis)
+{
+ int code;
+ gs_client_color cc;
+ const gs_color_space *pacs =
+ (const gs_color_space *)&pcs->params.device_n.alt_space;
+
+ /* We always map into the alternate color space. */
+ code = (*pcs->params.device_n.tint_transform)
+ (&pcs->params.device_n, pc->paint.values, &cc.paint.values[0],
+ pcs->params.device_n.tint_transform_data);
+ if (code < 0)
+ return code;
+ return (*pacs->type->concretize_color) (&cc, pacs, pconc, pis);
+}
+
+private int
+gx_remap_concrete_DeviceN(const frac * pconc,
+ gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
+ gs_color_select_t select)
+{ /* We don't support concrete DeviceN colors yet. */
+ return_error(gs_error_rangecheck);
+}
+
+/* Install a DeviceN color space. */
+private int
+gx_install_DeviceN(gs_color_space * pcs, gs_state * pgs)
+{ /*
+ * Give an error if any of the separation names are duplicated.
+ * We can't check this any earlier.
+ */
+ const gs_separation_name *names = pcs->params.device_n.names;
+ uint i, j;
+
+ for (i = 1; i < pcs->params.device_n.num_components; ++i)
+ for (j = 0; j < i; ++j)
+ if (names[i] == names[j])
+ return_error(gs_error_rangecheck);
+ return (*pcs->params.device_n.alt_space.type->install_cspace)
+ ((gs_color_space *) & pcs->params.device_n.alt_space, pgs);
+}
+
+/* Adjust the reference count of a DeviceN color space. */
+private void
+gx_adjust_cspace_DeviceN(const gs_color_space * pcs, int delta)
+{
+ (*pcs->params.device_n.alt_space.type->adjust_cspace_count)
+ ((const gs_color_space *)&pcs->params.device_n.alt_space, delta);
+}
+
+/* GC procedures */
+
+#define pcs ((gs_color_space *)vptr)
+
+private
+ENUM_PTRS_BEGIN(cs_DeviceN_enum_ptrs)
+{
+ return ENUM_USING(*pcs->params.device_n.alt_space.type->stype,
+ &pcs->params.device_n.alt_space,
+ sizeof(pcs->params.device_n.alt_space), index - 2);
+}
+ENUM_PTR(0, gs_color_space, params.device_n.names);
+ENUM_PTR(1, gs_color_space, params.device_n.tint_transform_data);
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(cs_DeviceN_reloc_ptrs)
+{
+ RELOC_PTR(gs_color_space, params.device_n.names);
+ RELOC_PTR(gs_color_space, params.device_n.tint_transform_data);
+ RELOC_USING(*pcs->params.device_n.alt_space.type->stype,
+ &pcs->params.device_n.alt_space,
+ sizeof(gs_base_color_space));
+}
+RELOC_PTRS_END
+
+#undef pcs
diff --git a/pstoraster/gschar.c b/pstoraster/gschar.c
new file mode 100644
index 000000000..b97b6c211
--- /dev/null
+++ b/pstoraster/gschar.c
@@ -0,0 +1,1492 @@
+/* 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$ */
+/* Character writing operators for Ghostscript library */
+#include "gx.h"
+#include "memory_.h"
+#include "string_.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gxfixed.h" /* ditto */
+#include "gxarith.h"
+#include "gxmatrix.h"
+#include "gzstate.h"
+#include "gxcoord.h"
+#include "gxdevice.h"
+#include "gxdevmem.h"
+#include "gxchar.h"
+#include "gxfont.h"
+#include "gxfont0.h"
+#include "gxfcache.h"
+#include "gspath.h"
+#include "gzpath.h"
+
+/* Define whether or not to cache characters rotated by angles other than */
+/* multiples of 90 degrees. */
+private bool CACHE_ROTATED_CHARS = true;
+
+/* Define whether or not to oversample characters at small sizes. */
+private bool OVERSAMPLE = true;
+
+/* Define the maximum size of a full temporary bitmap when rasterizing, */
+/* in bits (not bytes). */
+private uint MAX_TEMP_BITMAP_BITS = 80000;
+
+/* Structure descriptors */
+private_st_gs_show_enum();
+extern_st(st_gs_text_params);
+#define eptr ((gs_show_enum *)vptr)
+private
+ENUM_PTRS_BEGIN(show_enum_enum_ptrs)
+{
+ index -= 5;
+ if (index <= eptr->fstack.depth)
+ ENUM_RETURN(eptr->fstack.items[index].font);
+ index -= eptr->fstack.depth + 1;
+ return ENUM_USING(st_gs_text_params, vptr, size, index);
+}
+ENUM_PTR(0, gs_show_enum, pgs);
+ENUM_PTR(1, gs_show_enum, show_gstate);
+ENUM_PTR3(2, gs_show_enum, dev_cache, dev_cache2, dev_null);
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(show_enum_reloc_ptrs)
+{
+ int i;
+
+ RELOC_USING(st_gs_text_params, vptr, size); /* superclass */
+ RELOC_PTR(gs_show_enum, pgs);
+ RELOC_PTR(gs_show_enum, show_gstate);
+ RELOC_PTR3(gs_show_enum, dev_cache, dev_cache2, dev_null);
+ for (i = 0; i <= eptr->fstack.depth; i++)
+ RELOC_PTR(gs_show_enum, fstack.items[i].font);
+}
+RELOC_PTRS_END
+#undef eptr
+
+/* Forward declarations */
+private int continue_kshow(P1(gs_show_enum *));
+private int continue_show(P1(gs_show_enum *));
+private int continue_show_update(P1(gs_show_enum *));
+private int show_setup(P6(gs_show_enum *, gs_state *, const char *, uint,
+ uint, bool));
+private void show_set_scale(P1(gs_show_enum *));
+private int show_cache_setup(P1(gs_show_enum *));
+private int show_state_setup(P1(gs_show_enum *));
+private int show_origin_setup(P4(gs_state *, fixed, fixed, gs_char_path_mode));
+private int stringwidth_setup(P4(gs_show_enum *, gs_state *, const char *,
+ uint));
+
+/* Print the ctm if debugging */
+#define print_ctm(s,pgs)\
+ dlprintf7("[p]%sctm=[%g %g %g %g %g %g]\n", s,\
+ pgs->ctm.xx, pgs->ctm.xy, pgs->ctm.yx, pgs->ctm.yy,\
+ pgs->ctm.tx, pgs->ctm.ty)
+
+/* ------ Driver procedure ------ */
+
+/*
+ * When actually implemented, this will be moved further down in the file
+ * and will replace other code that is there now....
+ */
+
+int
+gx_default_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)
+{
+ return_error(gs_error_undefined);
+}
+
+/* ------ Font procedures ------ */
+
+/* Dummy (ineffective) BuildChar/BuildGlyph procedure */
+int
+gs_no_build_char(gs_show_enum * penum, gs_state * pgs,
+ gs_font * pfont, gs_char chr, gs_glyph glyph)
+{
+ return 1; /* failure, but not error */
+}
+
+/* Dummy character encoding procedure */
+gs_glyph
+gs_no_encode_char(gs_show_enum * penum,
+ gs_font * pfont, gs_char * pchr)
+{
+ return gs_no_glyph;
+}
+
+/* ------ String writing operators ------ */
+
+/* Allocate a show enumerator. */
+gs_show_enum *
+gs_show_enum_alloc(gs_memory_t * mem, gs_state * pgs, client_name_t cname)
+{
+ gs_show_enum *penum;
+
+ rc_alloc_struct_1(penum, gs_show_enum, &st_gs_show_enum, mem,
+ return 0, cname);
+ /* Initialize pointers for GC */
+ penum->text.operation = 0; /* no pointers relevant */
+ penum->dev = 0;
+ penum->pgs = pgs;
+ penum->dev_cache = 0;
+ penum->dev_cache2 = 0;
+ penum->dev_null = 0;
+ penum->fstack.depth = -1;
+ return penum;
+}
+
+/* Free the contents of a show enumerator. */
+void
+gs_show_enum_release(gs_show_enum * penum, gs_memory_t * emem)
+{
+ penum->cc = 0;
+ if (penum->dev_cache2 != 0) {
+ rc_decrement_only(penum->dev_cache2,
+ "gs_show_enum_release(dev_cache2)");
+ penum->dev_cache2 = 0;
+ }
+ if (penum->dev_cache != 0) {
+ rc_decrement_only(penum->dev_cache,
+ "gs_show_enum_release(dev_cache)");
+ penum->dev_cache = 0;
+ }
+ if (penum->dev_null != 0) {
+ rc_decrement_only(penum->dev_null,
+ "gs_show_enum_release(dev_null)");
+ penum->dev_null = 0;
+ }
+ if (emem != 0)
+ gs_free_object(emem, penum, "gs_show_enum_release(enum)");
+}
+
+/* show[_n] */
+int
+gs_show_n_init(gs_show_enum * penum, gs_state * pgs,
+ const char *str, uint size)
+{
+ return show_setup(penum, pgs, str, size,
+ TEXT_FROM_STRING | TEXT_DO_DRAW | TEXT_RETURN_WIDTH,
+ true);
+}
+
+/* ashow[_n] */
+int
+gs_ashow_n_init(gs_show_enum * penum, gs_state * pgs,
+ floatp ax, floatp ay, const char *str, uint size)
+{
+ penum->text.delta_all.x = ax;
+ penum->text.delta_all.y = ay;
+ return show_setup(penum, pgs, str, size,
+ TEXT_FROM_STRING | TEXT_ADD_TO_ALL_WIDTHS |
+ TEXT_DO_DRAW | TEXT_RETURN_WIDTH,
+ true);
+}
+
+/* widthshow[_n] */
+int
+gs_widthshow_n_init(gs_show_enum * penum, gs_state * pgs,
+ floatp cx, floatp cy, gs_char chr,
+ const char *str, uint size)
+{
+ penum->text.delta_space.x = cx;
+ penum->text.delta_space.y = cy;
+ penum->text.space.s_char = chr;
+ return show_setup(penum, pgs, str, size,
+ TEXT_FROM_STRING | TEXT_ADD_TO_SPACE_WIDTH |
+ TEXT_DO_DRAW | TEXT_RETURN_WIDTH,
+ true);
+}
+
+/* awidthshow[_n] */
+int
+gs_awidthshow_n_init(gs_show_enum * penum, gs_state * pgs,
+ floatp cx, floatp cy, gs_char chr, floatp ax, floatp ay,
+ const char *str, uint size)
+{
+ penum->text.delta_space.x = cx;
+ penum->text.delta_space.y = cy;
+ penum->text.space.s_char = chr;
+ penum->text.delta_all.x = ax;
+ penum->text.delta_all.y = ay;
+ return show_setup(penum, pgs, str, size,
+ TEXT_FROM_STRING |
+ TEXT_ADD_TO_ALL_WIDTHS | TEXT_ADD_TO_SPACE_WIDTH |
+ TEXT_DO_DRAW | TEXT_RETURN_WIDTH,
+ true);
+}
+
+/* kshow[_n] */
+int
+gs_kshow_n_init(register gs_show_enum * penum,
+ gs_state * pgs, const char *str, uint size)
+{
+ if (pgs->font->FontType == ft_composite)
+ return_error(gs_error_invalidfont);
+ return show_setup(penum, pgs, str, size,
+ TEXT_FROM_STRING | TEXT_DO_DRAW | TEXT_INTERVENE |
+ TEXT_RETURN_WIDTH,
+ true);
+}
+
+/* xyshow[_n] */
+int
+gs_xyshow_n_init(register gs_show_enum * penum,
+ gs_state * pgs, const char *str, uint size)
+{
+ return show_setup(penum, pgs, str, size,
+ TEXT_FROM_STRING |
+ TEXT_REPLACE_X_WIDTHS | TEXT_REPLACE_Y_WIDTHS |
+ TEXT_DO_DRAW | TEXT_INTERVENE | TEXT_RETURN_WIDTH,
+ true);
+}
+
+/* glyphshow */
+private int setup_glyph(P4(gs_show_enum *, gs_state *, gs_glyph, uint));
+private font_proc_encode_char(gs_glyphshow_encode_char);
+int
+gs_glyphshow_init(gs_show_enum * penum, gs_state * pgs, gs_glyph glyph)
+{
+ return setup_glyph(penum, pgs, glyph, TEXT_DO_DRAW);
+}
+int
+gs_glyphpath_init(gs_show_enum * penum, gs_state * pgs, gs_glyph glyph,
+ bool stroke_path)
+{
+ int code = setup_glyph(penum, pgs, glyph,
+ (stroke_path ? TEXT_DO_TRUE_CHARPATH :
+ TEXT_DO_FALSE_CHARPATH));
+
+ penum->can_cache = -1;
+ if_debug1('k', "[k]glyphpath, can_cache=%d", penum->can_cache);
+ return code;
+}
+private int
+setup_glyph(gs_show_enum * penum, gs_state * pgs, gs_glyph glyph,
+ uint operation)
+{
+ int code;
+
+ if (pgs->font->FontType == ft_composite)
+ return_error(gs_error_invalidfont);
+ code = show_setup(penum, pgs, "\000" /* arbitrary char */ , 1,
+ TEXT_FROM_GLYPHS | TEXT_RETURN_WIDTH | operation,
+ true);
+ penum->current_glyph = glyph;
+ penum->encode_char = gs_glyphshow_encode_char;
+ return code;
+}
+private gs_glyph
+gs_glyphshow_encode_char(gs_show_enum * penum, gs_font * pfont, gs_char * pchr)
+{
+ /* We just nil out the character, and return the pre-loaded glyph. */
+ *pchr = gs_no_char;
+ return penum->current_glyph;
+}
+
+/* ------ Related operators ------ */
+
+/* cshow[_n] */
+int
+gs_cshow_n_init(register gs_show_enum * penum,
+ gs_state * pgs, const char *str, uint size)
+{
+ return show_setup(penum, pgs, str, size,
+ TEXT_FROM_STRING | TEXT_DO_NONE | TEXT_INTERVENE,
+ false);
+}
+
+/* stringwidth[_n] */
+int
+gs_stringwidth_n_init(gs_show_enum * penum, gs_state * pgs,
+ const char *str, uint size)
+{
+ return stringwidth_setup(penum, pgs, str, size);
+}
+
+/* Common code for stringwidth[_n] */
+private int
+stringwidth_setup(gs_show_enum * penum, gs_state * pgs, const char *str,
+ uint size)
+{
+ int code = show_setup(penum, pgs, str, size,
+ TEXT_FROM_STRING | TEXT_DO_NONE | TEXT_RETURN_WIDTH,
+ false);
+ gs_memory_t *mem = pgs->memory;
+ gx_device_null *dev_null;
+
+ if (code < 0)
+ return code;
+ dev_null = gs_alloc_struct(mem, gx_device_null, &st_device_null,
+ "stringwidth_setup(dev_null)");
+ if (dev_null == 0)
+ return_error(gs_error_VMerror);
+ /* Do an extra gsave and suppress output */
+ if ((code = gs_gsave(pgs)) < 0)
+ return code;
+ penum->level = pgs->level; /* for level check in show_update */
+ /* Set up a null device that forwards xfont requests properly. */
+ gs_make_null_device(dev_null, mem);
+ dev_null->target = gs_currentdevice_inline(pgs);
+ pgs->ctm_default_set = false;
+ penum->dev_null = dev_null;
+ /* Account for the extra reference from the enumerator. */
+ rc_increment(dev_null);
+ gs_setdevice_no_init(pgs, (gx_device *) dev_null);
+ /* Establish an arbitrary translation and current point. */
+ gs_newpath(pgs);
+ gx_translate_to_fixed(pgs, fixed_0, fixed_0);
+ return gx_path_add_point(pgs->path, fixed_0, fixed_0);
+}
+
+/* charpath[_n] */
+int
+gs_charpath_n_init(gs_show_enum * penum, gs_state * pgs,
+ const char *str, uint size, bool stroke_path)
+{
+ int code = show_setup(penum, pgs, str, size,
+ TEXT_FROM_STRING |
+ (stroke_path ? TEXT_DO_TRUE_CHARPATH :
+ TEXT_DO_FALSE_CHARPATH),
+ false);
+
+ penum->can_cache = -1;
+ if_debug1('k', "[k]charpath, can_cache=%d", penum->can_cache);
+ return code;
+}
+
+/* charboxpath[_n] */
+int
+gs_charboxpath_n_init(gs_show_enum * penum, gs_state * pgs,
+ const char *str, uint size, bool use_boxes)
+{
+ int code = show_setup(penum, pgs, str, size,
+ TEXT_FROM_STRING |
+ (use_boxes ? TEXT_DO_TRUE_CHARBOXPATH :
+ TEXT_DO_FALSE_CHARBOXPATH),
+ false);
+
+ penum->can_cache = 0; /* different from charpath! */
+ if_debug1('k', "[k]charboxpath, can_cache=%d", penum->can_cache);
+ return code;
+}
+
+/* ------ Width/cache operators ------ */
+
+private int set_cache_device(P6(gs_show_enum * penum, gs_state * pgs,
+ floatp llx, floatp lly, floatp urx, floatp ury));
+
+/* setcachedevice */
+/* The elements of pw are: wx, wy, llx, lly, urx, ury. */
+/* Note that this returns 1 if we just set up the cache device. */
+int
+gs_setcachedevice_double(gs_show_enum * penum, gs_state * pgs, const double *pw)
+{
+ int code = gs_setcharwidth(penum, pgs, pw[0], pw[1]); /* default is don't cache */
+
+ if (code < 0)
+ return code;
+ return set_cache_device(penum, pgs, pw[2], pw[3], pw[4], pw[5]);
+}
+/* The _float procedure is strictly for backward compatibility. */
+int
+gs_setcachedevice_float(gs_show_enum * penum, gs_state * pgs, const float *pw)
+{
+ double w[6];
+ int i;
+
+ for (i = 0; i < 6; ++i)
+ w[i] = pw[i];
+ return gs_setcachedevice_double(penum, pgs, w);
+}
+
+/* setcachedevice2 */
+/* The elements of pw2 are: w0x, w0y, llx, lly, urx, ury, w1x, w1y, vx, vy. */
+/* Note that this returns 1 if we just set up the cache device. */
+int
+gs_setcachedevice2_double(gs_show_enum * penum, gs_state * pgs,
+ const double *pw2)
+{
+ int code;
+
+ if (gs_rootfont(pgs)->WMode) {
+ float vx = pw2[8], vy = pw2[9];
+ gs_fixed_point pvxy, dvxy;
+ cached_char *cc;
+
+ if ((code = gs_point_transform2fixed(&pgs->ctm, -vx, -vy, &pvxy)) < 0 ||
+ (code = gs_distance_transform2fixed(&pgs->ctm, vx, vy, &dvxy)) < 0
+ )
+ return 0; /* don't cache */
+ if ((code = gs_setcharwidth(penum, pgs, pw2[6], pw2[7])) < 0)
+ return code;
+ /* Adjust the origin by (vx, vy). */
+ gx_translate_to_fixed(pgs, pvxy.x, pvxy.y);
+ code = set_cache_device(penum, pgs, pw2[2], pw2[3], pw2[4], pw2[5]);
+ if (code != 1)
+ return code;
+ /* Adjust the character origin too. */
+ cc = penum->cc;
+ cc->offset.x += dvxy.x;
+ cc->offset.y += dvxy.y;
+ } else {
+ code = gs_setcharwidth(penum, pgs, pw2[0], pw2[1]);
+ if (code < 0)
+ return code;
+ code = set_cache_device(penum, pgs, pw2[2], pw2[3], pw2[4], pw2[5]);
+ }
+ return code;
+}
+/* The _float procedure is strictly for backward compatibility. */
+int
+gs_setcachedevice2_float(gs_show_enum * penum, gs_state * pgs, const float *pw2)
+{
+ double w2[10];
+ int i;
+
+ for (i = 0; i < 10; ++i)
+ w2[i] = pw2[i];
+ return gs_setcachedevice2_double(penum, pgs, w2);
+}
+
+/* Set up the cache device if relevant. */
+/* Return 1 if we just set up a cache device. */
+/* Used by setcachedevice and setcachedevice2. */
+private int
+set_cache_device(gs_show_enum * penum, gs_state * pgs, floatp llx, floatp lly,
+ floatp urx, floatp ury)
+{
+ gs_glyph glyph;
+
+ /* See if we want to cache this character. */
+ if (pgs->in_cachedevice) /* no recursion! */
+ return 0;
+ pgs->in_cachedevice = 1; /* disable color/gray/image operators */
+ /* We can only use the cache if we know the glyph. */
+ glyph = gs_show_current_glyph(penum);
+ if (glyph == gs_no_glyph)
+ return 0;
+ /* We can only use the cache if ctm is unchanged */
+ /* (aside from a possible translation). */
+ if (penum->can_cache <= 0 || !pgs->char_tm_valid) {
+ if_debug2('k', "[k]no cache: can_cache=%d, char_tm_valid=%d\n",
+ penum->can_cache, (int)pgs->char_tm_valid);
+ return 0;
+ } {
+ const gs_font *pfont = pgs->font;
+ gs_font_dir *dir = pfont->dir;
+ gx_device *dev = gs_currentdevice_inline(pgs);
+ int alpha_bits =
+ (*dev_proc(dev, get_alpha_bits)) (dev, go_text);
+ gs_log2_scale_point log2_scale;
+ static const fixed max_cdim[3] =
+ {
+#define max_cd(n)\
+ (fixed_1 << (arch_sizeof_short * 8 - n)) - (fixed_1 >> n) * 3
+ max_cd(0), max_cd(1), max_cd(2)
+#undef max_cd
+ };
+ ushort iwidth, iheight;
+ cached_char *cc;
+ gs_fixed_rect clip_box;
+ int code;
+
+ /* Compute the bounding box of the transformed character. */
+ /* Since we accept arbitrary transformations, the extrema */
+ /* may occur in any order; however, we can save some work */
+ /* by observing that opposite corners before transforming */
+ /* are still opposite afterwards. */
+ gs_fixed_point cll, clr, cul, cur, cdim;
+
+ if ((code = gs_distance_transform2fixed(&pgs->ctm, llx, lly, &cll)) < 0 ||
+ (code = gs_distance_transform2fixed(&pgs->ctm, llx, ury, &clr)) < 0 ||
+ (code = gs_distance_transform2fixed(&pgs->ctm, urx, lly, &cul)) < 0 ||
+ (code = gs_distance_transform2fixed(&pgs->ctm, urx, ury, &cur)) < 0
+ )
+ return 0; /* don't cache */
+ {
+ fixed ctemp;
+
+#define swap(a, b) ctemp = a, a = b, b = ctemp
+#define make_min(a, b) if ( (a) > (b) ) swap(a, b)
+
+ make_min(cll.x, cur.x);
+ make_min(cll.y, cur.y);
+ make_min(clr.x, cul.x);
+ make_min(clr.y, cul.y);
+#undef make_min
+#undef swap
+ }
+ /* Now take advantage of symmetry. */
+ if (clr.x < cll.x)
+ cll.x = clr.x, cur.x = cul.x;
+ if (clr.y < cll.y)
+ cll.y = clr.y, cur.y = cul.y;
+ /* Now cll and cur are the extrema of the box. */
+ cdim.x = cur.x - cll.x;
+ cdim.y = cur.y - cll.y;
+ show_set_scale(penum);
+ log2_scale.x = penum->log2_suggested_scale.x;
+ log2_scale.y = penum->log2_suggested_scale.y;
+#ifdef DEBUG
+ if (gs_debug_c('k')) {
+ dlprintf6("[k]cbox=[%g %g %g %g] scale=%dx%d\n",
+ fixed2float(cll.x), fixed2float(cll.y),
+ fixed2float(cur.x), fixed2float(cur.y),
+ 1 << log2_scale.x, 1 << log2_scale.y);
+ print_ctm(" ", pgs);
+ }
+#endif
+ /*
+ * If the device wants anti-aliased text,
+ * increase the sampling scale to ensure that
+ * if we want N bits of alpha, we generate
+ * at least 2^N sampled bits per pixel.
+ */
+ if (alpha_bits > 1) {
+ int more_bits =
+ alpha_bits - (log2_scale.x + log2_scale.y);
+
+ if (more_bits > 0) {
+ if (log2_scale.x <= log2_scale.y) {
+ log2_scale.x += (more_bits + 1) >> 1;
+ log2_scale.y += more_bits >> 1;
+ } else {
+ log2_scale.x += more_bits >> 1;
+ log2_scale.y += (more_bits + 1) >> 1;
+ }
+ }
+ } else if (!OVERSAMPLE || pfont->PaintType != 0) {
+ /* Don't oversample artificially stroked fonts. */
+ log2_scale.x = log2_scale.y = 0;
+ }
+ if (cdim.x > max_cdim[log2_scale.x] ||
+ cdim.y > max_cdim[log2_scale.y]
+ )
+ return 0; /* much too big */
+ iwidth = ((ushort) fixed2int_var(cdim.x) + 2) << log2_scale.x;
+ iheight = ((ushort) fixed2int_var(cdim.y) + 2) << log2_scale.y;
+ if_debug3('k', "[k]iwidth=%u iheight=%u dev_cache %s\n",
+ (uint) iwidth, (uint) iheight,
+ (penum->dev_cache == 0 ? "not set" : "set"));
+ if (penum->dev_cache == 0) {
+ code = show_cache_setup(penum);
+ if (code < 0)
+ return code;
+ }
+ /*
+ * If we're oversampling (i.e., the temporary bitmap is
+ * larger than the final monobit or alpha array) and the
+ * temporary bitmap is large, use incremental conversion
+ * from oversampled bitmap strips to alpha values instead of
+ * full oversampling with compression at the end.
+ */
+ cc = gx_alloc_char_bits(dir, penum->dev_cache,
+ (iwidth > MAX_TEMP_BITMAP_BITS / iheight &&
+ log2_scale.x + log2_scale.y > alpha_bits ?
+ penum->dev_cache2 : NULL),
+ iwidth, iheight, &log2_scale, alpha_bits);
+ if (cc == 0)
+ return 0; /* too big for cache */
+ /* The mins handle transposed coordinate systems.... */
+ /* Truncate the offsets to avoid artifacts later. */
+ cc->offset.x = fixed_ceiling(-cll.x);
+ cc->offset.y = fixed_ceiling(-cll.y);
+ if_debug4('k', "[k]width=%u, height=%u, offset=[%g %g]\n",
+ (uint) iwidth, (uint) iheight,
+ fixed2float(cc->offset.x),
+ fixed2float(cc->offset.y));
+ if ((code = gs_gsave(pgs)) < 0) {
+ gx_free_cached_char(dir, cc);
+ return code;
+ }
+ /* Nothing can go wrong now.... */
+ penum->cc = cc;
+ cc->code = glyph;
+ cc->wmode = gs_rootfont(pgs)->WMode;
+ cc->wxy = penum->wxy;
+ /* Install the device */
+ gx_set_device_only(pgs, (gx_device *) penum->dev_cache);
+ pgs->ctm_default_set = false;
+ /* Adjust the transformation in the graphics context */
+ /* so that the character lines up with the cache. */
+ gx_translate_to_fixed(pgs,
+ cc->offset.x << log2_scale.x,
+ cc->offset.y << log2_scale.y);
+ if ((log2_scale.x | log2_scale.y) != 0)
+ gx_scale_char_matrix(pgs, 1 << log2_scale.x,
+ 1 << log2_scale.y);
+ /* Set the initial matrix for the cache device. */
+ penum->dev_cache->initial_matrix = ctm_only(pgs);
+ /* Set the oversampling factor. */
+ penum->log2_current_scale.x = log2_scale.x;
+ penum->log2_current_scale.y = log2_scale.y;
+ /* Reset the clipping path to match the metrics. */
+ clip_box.p.x = clip_box.p.y = 0;
+ clip_box.q.x = int2fixed(iwidth);
+ clip_box.q.y = int2fixed(iheight);
+ if ((code = gx_clip_to_rectangle(pgs, &clip_box)) < 0)
+ return code;
+ gx_set_device_color_1(pgs); /* write 1's */
+ pgs->in_cachedevice = 2; /* we are caching */
+ }
+ penum->width_status = sws_cache;
+ return 1;
+}
+
+/* setcharwidth */
+/* Note that this returns 1 if the current show operation is */
+/* non-displaying (stringwidth or cshow). */
+int
+gs_setcharwidth(register gs_show_enum * penum, gs_state * pgs,
+ floatp wx, floatp wy)
+{
+ int code;
+
+ if (penum->width_status != sws_none)
+ return_error(gs_error_undefined);
+ if ((code = gs_distance_transform2fixed(&pgs->ctm, wx, wy, &penum->wxy)) < 0)
+ return code;
+ /* Check whether we're setting the scalable width */
+ /* for a cached xfont character. */
+ if (penum->cc != 0) {
+ penum->cc->wxy = penum->wxy;
+ penum->width_status = sws_cache_width_only;
+ } else {
+ penum->width_status = sws_no_cache;
+ }
+ return !SHOW_IS_DRAWING(penum);
+}
+
+/* ------ Enumerator ------ */
+
+/* Do the next step of a show (or stringwidth) operation */
+int
+gs_show_next(gs_show_enum * penum)
+{
+ return (*penum->continue_proc) (penum);
+}
+
+/* Continuation procedures */
+private int show_update(P1(gs_show_enum * penum));
+private int show_move(P1(gs_show_enum * penum));
+private int show_proceed(P1(gs_show_enum * penum));
+private int show_finish(P1(gs_show_enum * penum));
+private int
+continue_show_update(register gs_show_enum * penum)
+{
+ int code = show_update(penum);
+
+ if (code < 0)
+ return code;
+ code = show_move(penum);
+ if (code != 0)
+ return code;
+ return show_proceed(penum);
+}
+private int
+continue_show(register gs_show_enum * penum)
+{
+ return show_proceed(penum);
+}
+/* For kshow, the CTM or font may have changed, so we have to reestablish */
+/* the cached values in the enumerator. */
+private int
+continue_kshow(register gs_show_enum * penum)
+{
+ int code = show_state_setup(penum);
+
+ if (code < 0)
+ return code;
+ return show_proceed(penum);
+}
+
+/* Update position */
+private int
+show_update(register gs_show_enum * penum)
+{
+ register gs_state *pgs = penum->pgs;
+ cached_char *cc = penum->cc;
+ int code;
+
+ /* Update position for last character */
+ switch (penum->width_status) {
+ case sws_none:
+ /* Adobe interpreters assume a character width of 0, */
+ /* even though the documentation says this is an error.... */
+ penum->wxy.x = penum->wxy.y = 0;
+ break;
+ case sws_cache:
+ /* Finish installing the cache entry. */
+ /* If the BuildChar/BuildGlyph procedure did a save and a */
+ /* restore, it already undid the gsave in setcachedevice. */
+ /* We have to check for this by comparing levels. */
+ switch (pgs->level - penum->level) {
+ default:
+ return_error(gs_error_invalidfont); /* WRONG */
+ case 2:
+ code = gs_grestore(pgs);
+ if (code < 0)
+ return code;
+ case 1:
+ ;
+ }
+ gx_add_cached_char(pgs->font->dir, penum->dev_cache,
+ cc, gx_lookup_fm_pair(pgs->font, pgs),
+ &penum->log2_current_scale);
+ if (!SHOW_IS_DRAWING(penum) ||
+ penum->charpath_flag != cpm_show
+ )
+ break;
+ /* falls through */
+ case sws_cache_width_only:
+ /* Copy the bits to the real output device. */
+ code = gs_grestore(pgs);
+ if (code < 0)
+ return code;
+ code = gs_state_color_load(pgs);
+ if (code < 0)
+ return code;
+ return gx_image_cached_char(penum, cc);
+ case sws_no_cache:
+ ;
+ }
+ if (penum->charpath_flag != cpm_show) {
+ /* Move back to the character origin, so that */
+ /* show_move will get us to the right place. */
+ code = gx_path_add_point(pgs->show_gstate->path,
+ penum->origin.x, penum->origin.y);
+ if (code < 0)
+ return code;
+ }
+ return gs_grestore(pgs);
+}
+
+/* Move to next character */
+private int
+show_fast_move(gs_state * pgs, gs_fixed_point * pwxy)
+{
+ int code = gx_path_add_rel_point_inline(pgs->path, pwxy->x, pwxy->y);
+
+ /* If the current position is out of range, don't try to move. */
+ if (code == gs_error_limitcheck && pgs->clamp_coordinates)
+ code = 0;
+ return code;
+}
+private int
+show_move(register gs_show_enum * penum)
+{
+ register gs_state *pgs = penum->pgs;
+
+ if (SHOW_IS_XYCSHOW(penum)) {
+ penum->continue_proc = continue_show;
+ return gs_show_move;
+ }
+ if (SHOW_IS_ADD_TO_ALL(penum))
+ gs_rmoveto(pgs, penum->text.delta_all.x, penum->text.delta_all.y);
+ if (SHOW_IS_ADD_TO_SPACE(penum)) {
+ gs_char chr = penum->current_char;
+ int fdepth = penum->fstack.depth;
+
+ if (fdepth > 0) {
+ /* Add in the shifted font number. */
+ uint fidx = penum->fstack.items[fdepth].index;
+
+ switch (((gs_font_type0 *) (penum->fstack.items[fdepth - 1].font))->data.FMapType) {
+ case fmap_1_7:
+ case fmap_9_7:
+ chr += fidx << 7;
+ break;
+ default:
+ chr += fidx << 8;
+ }
+ }
+ if (chr == penum->text.space.s_char)
+ gs_rmoveto(pgs, penum->text.delta_space.x,
+ penum->text.delta_space.y);
+ }
+ /* wxy is in device coordinates */
+ {
+ int code = show_fast_move(pgs, &penum->wxy);
+
+ if (code < 0)
+ return code;
+ }
+ /* Check for kerning, but not on the last character. */
+ if (SHOW_IS_DO_KERN(penum) && penum->index < penum->text.size) {
+ penum->continue_proc = continue_kshow;
+ return gs_show_kern;
+ }
+ return 0;
+}
+/* Process next character */
+private int
+show_proceed(register gs_show_enum * penum)
+{
+ register gs_state *pgs = penum->pgs;
+ gs_font *pfont;
+ cached_fm_pair *pair = 0;
+ gs_font *rfont =
+ (penum->fstack.depth < 0 ? pgs->font : penum->fstack.items[0].font);
+ int wmode = rfont->WMode;
+
+ font_proc_next_char((*next_char)) = rfont->procs.next_char;
+ font_proc_next_glyph((*next_glyph)) = rfont->procs.next_glyph;
+#define next_char_glyph(penum, pchr, pglyph)\
+ (next_char == 0 ? (*next_glyph)(penum, pchr, pglyph) :\
+ (*(pglyph) = gs_no_glyph, (*next_char)(penum, pchr)))
+ gs_char chr;
+ gs_glyph glyph;
+ int code;
+ cached_char *cc;
+ gx_device *dev = gs_currentdevice_inline(pgs);
+ int alpha_bits = (*dev_proc(dev, get_alpha_bits)) (dev, go_text);
+
+ if (penum->charpath_flag == cpm_show && SHOW_IS_DRAWING(penum)) {
+ code = gs_state_color_load(pgs);
+ if (code < 0)
+ return code;
+ }
+ more: /* Proceed to next character */
+ pfont = (penum->fstack.depth < 0 ? pgs->font :
+ penum->fstack.items[penum->fstack.depth].font);
+ /* can_cache >= 0 allows us to use cached characters, */
+ /* even if we can't make new cache entries. */
+ if (penum->can_cache >= 0) {
+ /* Loop with cache */
+ for (;;) {
+ switch ((code = next_char_glyph(penum, &chr, &glyph))) {
+ default: /* error */
+ return code;
+ case 2: /* done */
+ return show_finish(penum);
+ case 1: /* font change */
+ pfont = penum->fstack.items[penum->fstack.depth].font;
+ pgs->char_tm_valid = false;
+ show_state_setup(penum);
+ pair = 0;
+ /* falls through */
+ case 0: /* plain char */
+ /*
+ * We don't need to set penum->current_char in the
+ * normal cases, but it's needed for widthshow,
+ * kshow, and one strange client, so we may as well
+ * do it here.
+ */
+ penum->current_char = chr;
+ if (glyph == gs_no_glyph) {
+ glyph = (*penum->encode_char) (penum, pfont, &chr);
+ penum->current_char = chr;
+ if (glyph == gs_no_glyph) {
+ cc = 0;
+ goto no_cache;
+ }
+ }
+ if (pair == 0)
+ pair = gx_lookup_fm_pair(pfont, pgs);
+ cc = gx_lookup_cached_char(pfont, pair, glyph, wmode,
+ alpha_bits);
+ if (cc == 0) {
+ /* Character is not in cache. */
+ /* If possible, try for an xfont before */
+ /* rendering from the outline. */
+ if (pfont->ExactSize == fbit_use_outlines ||
+ pfont->PaintType == 2
+ )
+ goto no_cache;
+ if (pfont->BitmapWidths) {
+ cc = gx_lookup_xfont_char(pgs, pair, chr,
+ glyph, &pfont->procs.callbacks, wmode);
+ if (cc == 0)
+ goto no_cache;
+ } else {
+ if (!SHOW_IS_DRAWING(penum) != 0 ||
+ penum->charpath_flag != cpm_show
+ )
+ goto no_cache;
+ /* We might have an xfont, but we still */
+ /* want the scalable widths. */
+ cc = gx_lookup_xfont_char(pgs, pair, chr,
+ glyph, &pfont->procs.callbacks, wmode);
+ /* Render up to the point of */
+ /* setcharwidth or setcachedevice, */
+ /* just as for stringwidth. */
+ /* This is the only case in which we can */
+ /* to go no_cache with cc != 0. */
+ goto no_cache;
+ }
+ }
+ /* Character is in cache. */
+ /* We might be doing .charboxpath or stringwidth; */
+ /* check for these now. */
+ if (penum->charpath_flag != cpm_show) {
+ /* This is .charboxpath. Get the bounding box */
+ /* and append it to a path. */
+ gx_path box_path;
+ gs_fixed_point pt;
+ fixed llx, lly, urx, ury;
+
+ code = gx_path_current_point(pgs->path, &pt);
+ if (code < 0)
+ return code;
+ llx = fixed_rounded(pt.x - cc->offset.x) +
+ int2fixed(penum->ftx);
+ lly = fixed_rounded(pt.y - cc->offset.y) +
+ int2fixed(penum->fty);
+ urx = llx + int2fixed(cc->width),
+ ury = lly + int2fixed(cc->height);
+ gx_path_init_local(&box_path, pgs->memory);
+ code =
+ gx_path_add_rectangle(&box_path, llx, lly,
+ urx, ury);
+ if (code >= 0)
+ code =
+ gx_path_add_char_path(pgs->show_gstate->path,
+ &box_path,
+ penum->charpath_flag);
+ if (code >= 0)
+ code = gx_path_add_point(pgs->path, pt.x, pt.y);
+ gx_path_free(&box_path, "show_proceed(box path)");
+ if (code < 0)
+ return code;
+ } else if (SHOW_IS_DRAWING(penum)) {
+ code = gx_image_cached_char(penum, cc);
+ if (code < 0)
+ return code;
+ else if (code > 0) {
+ cc = 0;
+ goto no_cache;
+ }
+ }
+ if (SHOW_IS_SLOW(penum)) {
+ /* Split up the assignment so that the */
+ /* Watcom compiler won't reserve esi/edi. */
+ penum->wxy.x = cc->wxy.x;
+ penum->wxy.y = cc->wxy.y;
+ code = show_move(penum);
+ } else
+ code = show_fast_move(pgs, &cc->wxy);
+ if (code) {
+ /* Might be kshow, so store the state. */
+ penum->current_glyph = glyph;
+ return code;
+ }
+ }
+ }
+ } else {
+ /* Can't use cache */
+ switch ((code = next_char_glyph(penum, &chr, &glyph))) {
+ default:
+ return code;
+ case 2:
+ return show_finish(penum);
+ case 1:
+ pfont = penum->fstack.items[penum->fstack.depth].font;
+ show_state_setup(penum);
+ case 0:
+ ;
+ }
+ penum->current_char = chr;
+ if (glyph == gs_no_glyph) {
+ glyph = (*penum->encode_char) (penum, pfont, &chr);
+ penum->current_char = chr;
+ }
+ cc = 0;
+ }
+ no_cache:
+ /*
+ * We must call the client's rendering code. Normally,
+ * we only do this if the character is not cached (cc = 0);
+ * however, we also must do this if we have an xfont but
+ * are using scalable widths. In this case, and only this case,
+ * we get here with cc != 0. penum->current_char has already
+ * been set, but not penum->current_glyph.
+ */
+ penum->current_glyph = glyph;
+ if ((code = gs_gsave(pgs)) < 0)
+ return code;
+ /* Set the font to the current descendant font. */
+ pgs->font = pfont;
+ /* Reset the in_cachedevice flag, so that a recursive show */
+ /* will use the cache properly. */
+ pgs->in_cachedevice = 0;
+ /* Reset the sampling scale. */
+ penum->log2_current_scale.x = penum->log2_current_scale.y = 0;
+ /* Set the charpath data in the graphics context if necessary, */
+ /* so that fill and stroke will add to the path */
+ /* rather than having their usual effect. */
+ pgs->in_charpath = penum->charpath_flag;
+ pgs->show_gstate =
+ (penum->show_gstate == pgs ? pgs->saved : penum->show_gstate);
+ pgs->stroke_adjust = false; /* per specification */
+ {
+ gs_fixed_point cpt;
+ gx_path *ppath = pgs->path;
+
+ if ((code = gx_path_current_point_inline(ppath, &cpt)) < 0)
+ goto rret;
+ penum->origin.x = cpt.x;
+ penum->origin.y = cpt.y;
+ /* Normally, char_tm is valid because of show_state_setup, */
+ /* but if we're in a cshow, it may not be. */
+ gs_currentcharmatrix(pgs, NULL, true);
+#if 1 /*USE_FPU <= 0 */
+ if (pgs->ctm.txy_fixed_valid && pgs->char_tm.txy_fixed_valid) {
+ fixed tx = pgs->ctm.tx_fixed;
+ fixed ty = pgs->ctm.ty_fixed;
+
+ gs_settocharmatrix(pgs);
+ cpt.x += pgs->ctm.tx_fixed - tx;
+ cpt.y += pgs->ctm.ty_fixed - ty;
+ } else
+#endif
+ {
+ double tx = pgs->ctm.tx;
+ double ty = pgs->ctm.ty;
+ double fpx, fpy;
+
+ gs_settocharmatrix(pgs);
+ fpx = fixed2float(cpt.x) + (pgs->ctm.tx - tx);
+ fpy = fixed2float(cpt.y) + (pgs->ctm.ty - ty);
+#define f_fits_in_fixed(f) f_fits_in_bits(f, fixed_int_bits)
+ if (!(f_fits_in_fixed(fpx) && f_fits_in_fixed(fpy))) {
+ gs_note_error(code = gs_error_limitcheck);
+ goto rret;
+ }
+ cpt.x = float2fixed(fpx);
+ cpt.y = float2fixed(fpy);
+ }
+ gs_newpath(pgs);
+ code = show_origin_setup(pgs, cpt.x, cpt.y,
+ penum->charpath_flag);
+ if (code < 0)
+ goto rret;
+ }
+ penum->width_status = sws_none;
+ penum->continue_proc = continue_show_update;
+ /* Try using the build procedure in the font. */
+ /* < 0 means error, 0 means success, 1 means failure. */
+ penum->cc = cc; /* set this now for build procedure */
+ code = (*pfont->procs.build_char) (penum, pgs, pfont, chr, glyph);
+ if (code < 0) {
+ discard(gs_note_error(code));
+ goto rret;
+ }
+ if (code == 0) {
+ code = show_update(penum);
+ if (code < 0)
+ goto rret;
+ /* Note that show_update does a grestore.... */
+ code = show_move(penum);
+ if (code)
+ return code; /* ... so don't go to rret here. */
+ goto more;
+ }
+ /*
+ * Some BuildChar procedures do a save before the setcachedevice,
+ * and a restore at the end. If we waited to allocate the cache
+ * device until the setcachedevice, we would attempt to free it
+ * after the restore. Therefore, allocate it now.
+ */
+ if (penum->dev_cache == 0) {
+ code = show_cache_setup(penum);
+ if (code < 0)
+ goto rret;
+ }
+ return gs_show_render;
+ /* If we get an error while setting up for BuildChar, */
+ /* we must undo the partial setup. */
+ rret:gs_grestore(pgs);
+ return code;
+#undef next_char_glyph
+}
+
+/* Finish show or stringwidth */
+private int
+show_finish(gs_show_enum * penum)
+{
+ gs_state *pgs = penum->pgs;
+ int code, rcode;
+
+ gs_show_enum_release(penum, NULL);
+ if (!SHOW_IS_STRINGWIDTH(penum))
+ return 0;
+ /* Save the accumulated width before returning, */
+ /* and undo the extra gsave. */
+ code = gs_currentpoint(pgs, &penum->width);
+ rcode = gs_grestore(pgs);
+ return (code < 0 ? code : rcode);
+}
+
+/* Return the current character for rendering. */
+gs_char
+gs_show_current_char(const gs_show_enum * penum)
+{
+ return penum->current_char;
+}
+
+/* Return the current glyph for rendering. */
+gs_glyph
+gs_show_current_glyph(const gs_show_enum * penum)
+{
+ return penum->current_glyph;
+}
+
+/* Return the width of the just-enumerated character (for cshow). */
+int
+gs_show_current_width(const gs_show_enum * penum, gs_point * ppt)
+{
+ return gs_idtransform(penum->pgs,
+ fixed2float(penum->wxy.x),
+ fixed2float(penum->wxy.y), ppt);
+}
+
+/* Return the just-displayed character for kerning. */
+gs_char
+gs_kshow_previous_char(const gs_show_enum * penum)
+{
+ return penum->current_char;
+}
+
+/* Return the about-to-be-displayed character for kerning. */
+gs_char
+gs_kshow_next_char(const gs_show_enum * penum)
+{
+ return penum->text.data.bytes[penum->index];
+}
+
+/* ------ Miscellaneous accessors ------ */
+
+/* Return the current font for cshow. */
+gs_font *
+gs_show_current_font(const gs_show_enum * penum)
+{
+ return (penum->fstack.depth < 0 ? penum->pgs->font :
+ penum->fstack.items[penum->fstack.depth].font);
+}
+
+/* Restore the current font after cshow. */
+int
+gs_show_restore_font(const gs_show_enum * penum)
+{
+ int fdepth = penum->fstack.depth;
+
+ if (fdepth >= 0) {
+ gs_state *pgs = penum->pgs;
+
+ gs_setfont(pgs, penum->fstack.items[0].font);
+ pgs->font = penum->fstack.items[fdepth].font;
+ }
+ return 0;
+}
+
+/* Return the charpath mode. */
+gs_char_path_mode
+gs_show_in_charpath(const gs_show_enum * penum)
+{
+ return penum->charpath_flag;
+}
+
+/* Return the accumulated width for stringwidth. */
+void
+gs_show_width(const gs_show_enum * penum, gs_point * ppt)
+{
+ *ppt = penum->width;
+}
+
+/* Return true if we only need the width from the rasterizer */
+/* and can short-circuit the full rendering of the character, */
+/* false if we need the actual character bits. */
+/* This is only meaningful just before calling gs_setcharwidth or */
+/* gs_setcachedevice[2]. */
+/* Note that we can't do this if the procedure has done any extra [g]saves. */
+bool
+gs_show_width_only(const gs_show_enum * penum)
+{
+ /* penum->cc will be non-zero iff we are calculating */
+ /* the scalable width for an xfont character. */
+ return ((!SHOW_IS_DRAWING(penum) || penum->cc != 0) &&
+ penum->pgs->level == penum->level + 1);
+}
+
+/* ------ Internal routines ------ */
+
+/* Initialize a show enumerator. */
+private int
+show_setup(register gs_show_enum * penum, gs_state * pgs, const char *str,
+ uint size, uint operation, bool propagate_charpath)
+{
+ int code;
+ gs_font *pfont;
+
+ /* Set rest of common members. */
+ penum->text.operation = operation;
+ penum->text.data.bytes = (const byte *)str; /* avoid signed chars */
+ penum->text.size = size;
+ penum->index = 0;
+ /* Set other members. */
+ gx_set_dev_color(pgs);
+ pfont = pgs->font;
+ penum->pgs = pgs;
+ penum->level = pgs->level;
+ if (operation & TEXT_DO_ANY_CHARPATH)
+ penum->charpath_flag =
+ (operation & TEXT_DO_FALSE_CHARPATH ? cpm_false_charpath :
+ operation & TEXT_DO_TRUE_CHARPATH ? cpm_true_charpath :
+ operation & TEXT_DO_FALSE_CHARBOXPATH ? cpm_false_charboxpath :
+ operation & TEXT_DO_TRUE_CHARBOXPATH ? cpm_true_charboxpath :
+ cpm_show /* can't happen */ );
+ else
+ penum->charpath_flag =
+ (propagate_charpath ? pgs->in_charpath : cpm_show);
+ penum->dev_cache = 0;
+ penum->dev_cache2 = 0;
+ penum->dev_null = 0;
+ penum->cc = 0;
+ penum->continue_proc = continue_show;
+ code = (*pfont->procs.init_fstack) (penum, pfont);
+ if (code < 0)
+ return code;
+ penum->can_cache = /* show_state_setup may reset */
+ (penum->charpath_flag == cpm_show ? 1 : -1);
+ code = show_state_setup(penum);
+ if (code < 0)
+ return code;
+ penum->show_gstate =
+ (propagate_charpath && (pgs->in_charpath != 0) ?
+ pgs->show_gstate : pgs);
+ return 0;
+}
+
+/* Initialize the gstate-derived parts of a show enumerator. */
+/* We do this both when starting the show operation, */
+/* and when returning from the kshow callout. */
+private int
+show_state_setup(gs_show_enum * penum)
+{
+ gs_state *pgs = penum->pgs;
+ gx_clip_path *pcpath;
+ const gs_font *pfont;
+
+ if (penum->fstack.depth <= 0) {
+ pfont = pgs->font;
+ gs_currentcharmatrix(pgs, NULL, 1); /* make char_tm valid */
+ } else {
+ /* We have to concatenate the parent's FontMatrix as well. */
+ gs_matrix mat;
+ const gx_font_stack_item *pfsi =
+ &penum->fstack.items[penum->fstack.depth];
+
+ pfont = pfsi->font;
+ gs_matrix_multiply(&pfont->FontMatrix,
+ &pfsi[-1].font->FontMatrix, &mat);
+ gs_setcharmatrix(pgs, &mat);
+ }
+ /* Skewing or non-rectangular rotation are not supported. */
+ if (!CACHE_ROTATED_CHARS &&
+ (is_fzero2(pgs->char_tm.xy, pgs->char_tm.yx) ||
+ is_fzero2(pgs->char_tm.xx, pgs->char_tm.yy))
+ )
+ penum->can_cache = 0;
+ if (penum->can_cache >= 0 &&
+ gx_effective_clip_path(pgs, &pcpath) >= 0
+ ) {
+ gs_fixed_rect cbox;
+
+ gx_cpath_inner_box(pcpath, &cbox);
+ /* Since characters occupy an integral number of pixels, */
+ /* we can (and should) round the inner clipping box */
+ /* outward rather than inward. */
+ penum->ibox.p.x = fixed2int_var(cbox.p.x);
+ penum->ibox.p.y = fixed2int_var(cbox.p.y);
+ penum->ibox.q.x = fixed2int_var_ceiling(cbox.q.x);
+ penum->ibox.q.y = fixed2int_var_ceiling(cbox.q.y);
+ gx_cpath_outer_box(pcpath, &cbox);
+ penum->obox.p.x = fixed2int_var(cbox.p.x);
+ penum->obox.p.y = fixed2int_var(cbox.p.y);
+ penum->obox.q.x = fixed2int_var_ceiling(cbox.q.x);
+ penum->obox.q.y = fixed2int_var_ceiling(cbox.q.y);
+#if 1 /*USE_FPU <= 0 */
+ if (pgs->ctm.txy_fixed_valid && pgs->char_tm.txy_fixed_valid) {
+ penum->ftx = (int)fixed2long(pgs->char_tm.tx_fixed -
+ pgs->ctm.tx_fixed);
+ penum->fty = (int)fixed2long(pgs->char_tm.ty_fixed -
+ pgs->ctm.ty_fixed);
+ } else {
+#endif
+ double fdx = pgs->char_tm.tx - pgs->ctm.tx;
+ double fdy = pgs->char_tm.ty - pgs->ctm.ty;
+
+#define int_bits (arch_sizeof_int * 8 - 1)
+ if (!(f_fits_in_bits(fdx, int_bits) &&
+ f_fits_in_bits(fdy, int_bits))
+ )
+ return_error(gs_error_limitcheck);
+#undef int_bits
+ penum->ftx = (int)fdx;
+ penum->fty = (int)fdy;
+ }
+ }
+ penum->encode_char = pfont->procs.encode_char;
+ return 0;
+}
+
+/* Set the suggested oversampling scale for character rendering. */
+private void
+show_set_scale(gs_show_enum * penum)
+{
+ /*
+ * Decide whether to oversample.
+ * We have to decide this each time setcachedevice is called.
+ */
+ const gs_state *pgs = penum->pgs;
+
+ if (penum->charpath_flag == cpm_show &&
+ SHOW_IS_DRAWING(penum) &&
+ gx_path_is_void_inline(pgs->path) &&
+ /* Oversampling rotated characters doesn't work well. */
+ (is_fzero2(pgs->char_tm.xy, pgs->char_tm.yx) ||
+ is_fzero2(pgs->char_tm.xx, pgs->char_tm.yy))
+ ) {
+ const gs_font_base *pfont = (gs_font_base *) pgs->font;
+ gs_fixed_point extent;
+ int code = gs_distance_transform2fixed(&pgs->char_tm,
+ pfont->FontBBox.q.x - pfont->FontBBox.p.x,
+ pfont->FontBBox.q.y - pfont->FontBBox.p.y,
+ &extent);
+
+ if (code >= 0) {
+ int sx =
+ (extent.x == 0 ? 0 :
+ any_abs(extent.x) < int2fixed(25) ? 2 :
+ any_abs(extent.x) < int2fixed(60) ? 1 :
+ 0);
+ int sy =
+ (extent.y == 0 ? 0 :
+ any_abs(extent.y) < int2fixed(25) ? 2 :
+ any_abs(extent.y) < int2fixed(60) ? 1 :
+ 0);
+
+ /* If we oversample at all, make sure we do it */
+ /* in both X and Y. */
+ if (sx == 0 && sy != 0)
+ sx = 1;
+ else if (sy == 0 && sx != 0)
+ sy = 1;
+ penum->log2_suggested_scale.x = sx;
+ penum->log2_suggested_scale.y = sy;
+ return;
+ }
+ }
+ /* By default, don't scale. */
+ penum->log2_suggested_scale.x =
+ penum->log2_suggested_scale.y = 0;
+}
+
+/* Set up the cache device and related information. */
+/* Note that we always allocate both cache devices, */
+/* even if we only use one of them. */
+private int
+show_cache_setup(gs_show_enum * penum)
+{
+ gs_state *pgs = penum->pgs;
+ gs_memory_t *mem = pgs->memory;
+ gx_device_memory *dev =
+ gs_alloc_struct(mem, gx_device_memory, &st_device_memory,
+ "show_cache_setup(dev_cache)");
+ gx_device_memory *dev2 =
+ gs_alloc_struct(mem, gx_device_memory, &st_device_memory,
+ "show_cache_setup(dev_cache2)");
+
+ if (dev == 0 || dev2 == 0) {
+ gs_free_object(mem, dev2, "show_cache_setup(dev_cache2)");
+ gs_free_object(mem, dev, "show_cache_setup(dev_cache)");
+ return_error(gs_error_VMerror);
+ }
+ /*
+ * We only initialize the device for the sake of the GC,
+ * (since we have to re-initialize it as either a mem_mono
+ * or a mem_abuf device before actually using it) and also
+ * to set its memory pointer.
+ */
+ gs_make_mem_mono_device(dev, mem, gs_currentdevice_inline(pgs));
+ penum->dev_cache = dev;
+ penum->dev_cache2 = dev2;
+ /* Initialize dev2 for the sake of the GC. */
+ *dev2 = *dev;
+ /* Account for the extra references from the enumerator. */
+ rc_increment(dev);
+ rc_increment(dev2);
+ return 0;
+}
+
+/* Set the character origin as the origin of the coordinate system. */
+/* Used before rendering characters, and for moving the origin */
+/* in setcachedevice2 when WMode=1. */
+private int
+show_origin_setup(gs_state * pgs, fixed cpt_x, fixed cpt_y,
+ gs_char_path_mode charpath_flag)
+{
+ if (charpath_flag == cpm_show) {
+ /* Round the translation in the graphics state. */
+ /* This helps prevent rounding artifacts later. */
+ cpt_x = fixed_rounded(cpt_x);
+ cpt_y = fixed_rounded(cpt_y);
+ }
+ /*
+ * BuildChar procedures expect the current point to be undefined,
+ * so we omit the gx_path_add_point with ctm.t*_fixed.
+ */
+ return gx_translate_to_fixed(pgs, cpt_x, cpt_y);
+}
+
+/* Default fstack initialization procedure. */
+int
+gs_default_init_fstack(gs_show_enum * penum, gs_font * pfont)
+{
+ penum->fstack.depth = -1;
+ return 0;
+}
+
+/* Default next-character procedure. */
+int
+gs_default_next_char(gs_show_enum * penum, gs_char * pchr)
+{
+ gs_glyph ignore_glyph;
+
+ return gs_default_next_glyph(penum, pchr, &ignore_glyph);
+}
+
+/* Default next-glyph procedure. */
+int
+gs_default_next_glyph(gs_show_enum * penum, gs_char * pchr, gs_glyph * pglyph)
+{
+ if (penum->index == penum->text.size)
+ return 2;
+ *pchr = penum->text.data.bytes[penum->index++];
+ *pglyph = gs_no_glyph;
+ return 0;
+}
diff --git a/pstoraster/gschar.h b/pstoraster/gschar.h
new file mode 100644
index 000000000..4350a4c13
--- /dev/null
+++ b/pstoraster/gschar.h
@@ -0,0 +1,130 @@
+/* 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$ */
+/* Client interface to character operations */
+
+#ifndef gschar_INCLUDED
+# define gschar_INCLUDED
+
+#include "gsccode.h"
+#include "gscpm.h"
+
+/* String display, like image display, uses an enumeration structure */
+/* to keep track of what's going on (aka 'poor man's coroutine'). */
+#ifndef gs_show_enum_DEFINED
+# define gs_show_enum_DEFINED
+typedef struct gs_show_enum_s gs_show_enum;
+
+#endif
+
+/* Define an opaque type for fonts if necessary. */
+#ifndef gs_font_DEFINED
+# define gs_font_DEFINED
+typedef struct gs_font_s gs_font;
+
+#endif
+
+/* Allocate an enumerator. */
+gs_show_enum *gs_show_enum_alloc(P3(gs_memory_t *, gs_state *, client_name_t));
+
+/* Release the contents of an enumerator. */
+/* (This happens automatically if the enumeration finishes normally.) */
+/* If the second argument is not NULL, also free the enumerator. */
+void gs_show_enum_release(P2(gs_show_enum *, gs_memory_t *));
+
+/* Initialize a text enumeration. */
+int gs_show_n_init(P4(gs_show_enum *, gs_state *, const char *, uint)),
+ gs_ashow_n_init(P6(gs_show_enum *, gs_state *, floatp, floatp, const char *, uint)),
+ gs_widthshow_n_init(P7(gs_show_enum *, gs_state *, floatp, floatp, gs_char, const char *, uint)),
+ gs_awidthshow_n_init(P9(gs_show_enum *, gs_state *, floatp, floatp, gs_char, floatp, floatp, const char *, uint)),
+ gs_kshow_n_init(P4(gs_show_enum *, gs_state *, const char *, uint)),
+ gs_xyshow_n_init(P4(gs_show_enum *, gs_state *, const char *, uint)),
+ gs_glyphshow_init(P3(gs_show_enum *, gs_state *, gs_glyph)), gs_cshow_n_init(P4(gs_show_enum *, gs_state *, const char *, uint)),
+ gs_stringwidth_n_init(P4(gs_show_enum *, gs_state *, const char *, uint)),
+ gs_charpath_n_init(P5(gs_show_enum *, gs_state *, const char *, uint, bool)),
+ gs_glyphpath_init(P4(gs_show_enum *, gs_state *, gs_glyph, bool)),
+ gs_charboxpath_n_init(P5(gs_show_enum *, gs_state *, const char *, uint, bool));
+
+/* After setting up the enumeration, all the string-related routines */
+/* work the same way. The client calls gs_show_next until it returns */
+/* a zero (successful completion) or negative (error) value. */
+/* Other values indicate the following situations: */
+
+ /* The client must render a character: obtain the code from */
+ /* gs_show_current_char, do whatever is necessary, and then */
+ /* call gs_show_next again. */
+#define gs_show_render 1
+
+ /* The client has asked to intervene between characters (kshow). */
+ /* Obtain the previous and next codes from gs_kshow_previous_char */
+ /* and gs_kshow_next_char, do whatever is necessary, and then */
+ /* call gs_show_next again. */
+#define gs_show_kern 2
+
+ /* The client has asked to handle characters individually */
+ /* (xshow, yshow, xyshow, cshow). Obtain the current code */
+ /* from gs_show_current_char, do whatever is necessary, and then */
+ /* call gs_show_next again. */
+#define gs_show_move 3
+
+int gs_show_next(P1(gs_show_enum *));
+
+gs_char
+gs_show_current_char(P1(const gs_show_enum *)), gs_kshow_previous_char(P1(const gs_show_enum *)),
+ gs_kshow_next_char(P1(const gs_show_enum *));
+gs_font *
+ gs_show_current_font(P1(const gs_show_enum *));
+int gs_show_restore_font(P1(const gs_show_enum *));
+
+gs_glyph
+gs_show_current_glyph(P1(const gs_show_enum *));
+int gs_show_current_width(P2(const gs_show_enum *, gs_point *));
+void gs_show_width(P2(const gs_show_enum *, gs_point *)); /* cumulative width */
+
+gs_char_path_mode
+gs_show_in_charpath(P1(const gs_show_enum *)); /* return charpath flag */
+
+/* Character cache and metrics operators. */
+/* gs_setcachedevice* return 1 iff the cache device was just installed. */
+int gs_setcachedevice_float(P3(gs_show_enum *, gs_state *, const float * /*[6] */ ));
+int gs_setcachedevice_double(P3(gs_show_enum *, gs_state *, const double * /*[6] */ ));
+
+#define gs_setcachedevice(penum, pgs, pw)\
+ gs_setcachedevice_float(penum, pgs, pw)
+int gs_setcachedevice2_float(P3(gs_show_enum *, gs_state *, const float * /*[10] */ ));
+int gs_setcachedevice2_double(P3(gs_show_enum *, gs_state *, const double * /*[10] */ ));
+
+#define gs_setcachedevice2(penum, pgs, pw2)\
+ gs_setcachedevice2_float(penum, pgs, pw2)
+int gs_setcharwidth(P4(gs_show_enum *, gs_state *, floatp, floatp));
+
+/* Return true if we only need the width from the rasterizer */
+/* and can short-circuit the full rendering of the character, */
+/* false if we need the actual character bits. */
+/* This is only meaningful just before calling gs_setcharwidth or */
+/* gs_setcachedevice[2]. */
+bool gs_show_width_only(P1(const gs_show_enum *));
+
+#endif /* gschar_INCLUDED */
diff --git a/pstoraster/gschar0.c b/pstoraster/gschar0.c
new file mode 100644
index 000000000..69f207d3c
--- /dev/null
+++ b/pstoraster/gschar0.c
@@ -0,0 +1,407 @@
+/* Copyright (C) 1991, 1992, 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$ */
+/* Composite font decoding for Ghostscript library */
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gsfcmap.h"
+#include "gxfixed.h"
+#include "gxdevice.h"
+#include "gxdevmem.h" /* for gxchar.h */
+#include "gxchar.h"
+#include "gxfont.h"
+#include "gxfont0.h"
+
+/* Stack up modal composite fonts, down to a non-modal or base font. */
+private int
+gs_stack_modal_fonts(gs_show_enum * penum)
+{
+ int fdepth = penum->fstack.depth;
+ gs_font *cfont = penum->fstack.items[fdepth].font;
+
+ while (cfont->FontType == ft_composite) {
+ gs_font_type0 *const cmfont = (gs_font_type0 *) cfont;
+
+ if (!fmap_type_is_modal(cmfont->data.FMapType))
+ break;
+ if (fdepth == max_font_depth)
+ return_error(gs_error_invalidfont);
+ fdepth++;
+ cfont = cmfont->data.FDepVector[cmfont->data.Encoding[0]];
+ penum->fstack.items[fdepth].font = cfont;
+ penum->fstack.items[fdepth].index = 0;
+ if_debug2('j', "[j]stacking depth=%d font=0x%lx\n",
+ fdepth, (ulong) cfont);
+ }
+ penum->fstack.depth = fdepth;
+ return 0;
+}
+/* Initialize the composite font stack for a show enumerator. */
+int
+gs_type0_init_fstack(gs_show_enum * penum, gs_font * pfont)
+{
+ if_debug1('j', "[j]stacking depth=0 font=0x%lx\n",
+ (ulong) pfont);
+ penum->fstack.depth = 0;
+ penum->fstack.items[0].font = pfont;
+ penum->fstack.items[0].index = 0;
+ return gs_stack_modal_fonts(penum);
+}
+
+/* Select the appropriate descendant of a font. */
+/* Uses free variables: penum. */
+/* Uses pdata, uses & updates fdepth, sets pfont. */
+#define select_descendant(pfont, pdata, fidx, fdepth)\
+ if ( fidx >= pdata->encoding_size )\
+ return_error(gs_error_rangecheck);\
+ if ( fdepth == max_font_depth )\
+ return_error(gs_error_invalidfont);\
+ pfont = pdata->FDepVector[pdata->Encoding[fidx]];\
+ if ( ++fdepth > orig_depth || pfont != penum->fstack.items[fdepth].font )\
+ penum->fstack.items[fdepth].font = pfont,\
+ changed = 1;\
+ penum->fstack.items[fdepth].index = fidx
+
+/* Get the root EscChar of a composite font, which overrides the EscChar */
+/* of descendant fonts. */
+private uint
+root_esc_char(const gs_show_enum * penum)
+{
+ return ((gs_font_type0 *) (penum->fstack.items[0].font))->data.EscChar;
+}
+
+/* Get the next character or glyph from a composite string. */
+/* If we run off the end of the string in the middle of a */
+/* multi-byte sequence, return gs_error_rangecheck. */
+/* If the string is empty, return 2. */
+/* If the current (base) font changed, return 1. Otherwise, return 0. */
+int
+gs_type0_next_glyph(register gs_show_enum * penum, gs_char * pchr,
+ gs_glyph * pglyph)
+{
+ const byte *str = penum->text.data.bytes;
+ const byte *p = str + penum->index;
+ const byte *end = str + penum->text.size;
+ int fdepth = penum->fstack.depth;
+ int orig_depth = fdepth;
+ gs_font *pfont;
+
+#define pfont0 ((gs_font_type0 *)pfont)
+ gs_type0_data *pdata;
+ uint fidx;
+ gs_char chr;
+ gs_glyph glyph = gs_no_glyph;
+ int changed = 0;
+
+#define need_left(n)\
+ if ( end - p < n ) return_error(gs_error_rangecheck)
+
+ /*
+ * Although the Adobe documentation doesn't say anything about this,
+ * if the root font is modal and the very first character of the
+ * string being decoded is an escape or shift character, then
+ * font selection via the escape mechanism works down from the root,
+ * rather than up from the lowest modal font. (This was first
+ * reported by Norio Katayama, and confirmed by someone at Adobe.)
+ */
+
+ if (penum->index == 0) {
+ int idepth = 0;
+
+ pfont = penum->fstack.items[0].font;
+ for (; pfont->FontType == ft_composite;) {
+ fmap_type fmt = (pdata = &pfont0->data)->FMapType;
+
+ if (p == end)
+ return 2;
+ chr = *p;
+ switch (fmt) {
+ case fmap_escape:
+ if (chr != root_esc_char(penum))
+ break;
+ need_left(2);
+ fidx = p[1];
+ p += 2;
+ if_debug1('j', "[j]from root: escape %d\n", fidx);
+ rdown:select_descendant(pfont, pdata, fidx, idepth);
+ if_debug2('j', "[j]... new depth=%d, new font=0x%lx\n",
+ idepth, (ulong) pfont);
+ continue;
+ case fmap_double_escape:
+ if (chr != root_esc_char(penum))
+ break;
+ need_left(2);
+ fidx = p[1];
+ p += 2;
+ if (fidx == chr) {
+ need_left(1);
+ fidx = *p++ + 256;
+ }
+ if_debug1('j', "[j]from root: double escape %d\n", fidx);
+ goto rdown;
+ case fmap_shift:
+ if (chr == pdata->ShiftIn)
+ fidx = 0;
+ else if (chr == pdata->ShiftOut)
+ fidx = 1;
+ else
+ break;
+ p++;
+ if_debug1('j', "[j]from root: shift %d\n", fidx);
+ goto rdown;
+ default:
+ break;
+ }
+ break;
+ }
+ /* If we saw any initial escapes or shifts, */
+ /* compute a new initial base font. */
+ if (idepth != 0) {
+ int code;
+
+ penum->fstack.depth = idepth;
+ code = gs_stack_modal_fonts(penum);
+ if (code < 0)
+ return code;
+ if (penum->fstack.depth > idepth)
+ changed = 1;
+ orig_depth = fdepth = penum->fstack.depth;
+ }
+ }
+ /* Handle initial escapes or shifts. */
+
+ up:if (p == end)
+ return 2;
+ chr = *p;
+ while (fdepth > 0) {
+ pfont = penum->fstack.items[fdepth - 1].font;
+ pdata = &pfont0->data;
+ switch (pdata->FMapType) {
+ default: /* non-modal */
+ fdepth--;
+ continue;
+
+ case fmap_escape:
+ if (chr != root_esc_char(penum))
+ break;
+ need_left(2);
+ fidx = *++p;
+ if_debug1('j', "[j]next: escape %d\n", fidx);
+ /* Per Adobe, if we get an escape at the root, */
+ /* treat it as an ordinary character (font index). */
+ if (fidx == chr && fdepth > 1) {
+ fdepth--;
+ goto up;
+ }
+ down:if (++p == end)
+ return 2;
+ chr = *p;
+ fdepth--;
+ do {
+ select_descendant(pfont, pdata, fidx, fdepth);
+ if_debug3('j', "[j]down from modal: new depth=%d, index=%d, new font=0x%lx\n",
+ fdepth, fidx, (ulong) pfont);
+ if (pfont->FontType != ft_composite)
+ break;
+ pdata = &pfont0->data;
+ fidx = 0;
+ }
+ while (pdata->FMapType == fmap_escape);
+ continue;
+
+ case fmap_double_escape:
+ if (chr != root_esc_char(penum))
+ break;
+ need_left(2);
+ fidx = *++p;
+ if (fidx == chr) {
+ need_left(2);
+ fidx = *++p + 256;
+ }
+ if_debug1('j', "[j]next: double escape %d\n", fidx);
+ goto down;
+
+ case fmap_shift:
+ if (chr == pdata->ShiftIn)
+ fidx = 0;
+ else if (chr == pdata->ShiftOut)
+ fidx = 1;
+ else
+ break;
+ if_debug1('j', "[j]next: shift %d\n", fidx);
+ goto down;
+ }
+ break;
+ }
+ /* At this point, chr == *p. */
+ /* (This is important to know for CMap'ed fonts.) */
+ p++;
+
+ /*
+ * Now handle non-modal descendants.
+ * The PostScript language manual has some confusing
+ * wording about the parent supplying the "first part"
+ * of the child's decoding information; what this means
+ * is not (as one might imagine) the font index, but
+ * simply the first byte of the data.
+ */
+
+ while ((pfont = penum->fstack.items[fdepth].font)->FontType == ft_composite) {
+ pdata = &pfont0->data;
+ switch (pdata->FMapType) {
+ default: /* can't happen */
+ return_error(gs_error_invalidfont);
+
+ case fmap_8_8:
+ need_left(1);
+ fidx = chr;
+ chr = *p++;
+ if_debug2('J', "[J]8/8 index=%d, char=%ld\n",
+ fidx, chr);
+ break;
+
+ case fmap_1_7:
+ fidx = chr >> 7;
+ chr &= 0x7f;
+ if_debug2('J', "[J]1/7 index=%d, char=%ld\n",
+ fidx, chr);
+ break;
+
+ case fmap_9_7:
+ need_left(1);
+ fidx = ((uint) chr << 1) + (*p >> 7);
+ chr = *p & 0x7f;
+ if_debug2('J', "[J]9/7 index=%d, char=%ld\n",
+ fidx, chr);
+ p++;
+ break;
+
+ case fmap_SubsVector:
+ {
+ int width = pdata->subs_width;
+ uint subs_count = pdata->subs_size;
+ const byte *psv = pdata->SubsVector.data;
+
+#define subs_loop(subs_elt, width)\
+ while ( subs_count != 0 && tchr >= (schr = subs_elt) )\
+ subs_count--, tchr -= schr, psv += width;\
+ chr = tchr; p += width - 1; break
+
+ switch (width) {
+ default: /* can't happen */
+ return_error(gs_error_invalidfont);
+ case 1:
+ {
+ byte tchr = (byte) chr, schr;
+
+ subs_loop(*psv, 1);
+ }
+ case 2:
+ need_left(1);
+#define w2(p) (((ushort)*p << 8) + p[1])
+ {
+ ushort tchr = ((ushort) chr << 8) + *p,
+ schr;
+
+ subs_loop(w2(psv), 2);
+ }
+ case 3:
+ need_left(2);
+#define w3(p) (((ulong)*p << 16) + ((uint)p[1] << 8) + p[2])
+ {
+ ulong tchr = ((ulong) chr << 16) + w2(p),
+ schr;
+
+ subs_loop(w3(psv), 3);
+ }
+ case 4:
+ need_left(3);
+#define w4(p) (((ulong)*p << 24) + ((ulong)p[1] << 16) + ((uint)p[2] << 8) + p[3])
+ {
+ ulong tchr = ((ulong) chr << 24) + w3(p),
+ schr;
+
+ subs_loop(w4(psv), 4);
+ }
+#undef w2
+#undef w3
+#undef w4
+#undef subs_loop
+ }
+ fidx = pdata->subs_size - subs_count;
+ if_debug2('J', "[J]SubsVector index=%d, char=%ld\n",
+ fidx, chr);
+ break;
+ }
+
+ case fmap_CMap:
+ {
+ gs_const_string cstr;
+ uint mindex = p - str - 1; /* p was incremented */
+ int code;
+
+ cstr.data = str;
+ cstr.size = end - str;
+ code = gs_cmap_decode_next(pdata->CMap, &cstr, &mindex,
+ &fidx, &chr, &glyph);
+ if (code < 0)
+ return code;
+ p = str + mindex;
+ if_debug3('J', "[J]CMap returns %d, chr=0x%lx, glyph=0x%lx\n",
+ code, (ulong) chr, (ulong) glyph);
+ if (code == 0) {
+ if (glyph == gs_no_glyph) {
+ glyph = gs_min_cid_glyph;
+ if_debug0('J', "... undefined\n");
+ goto done;
+ }
+ } else
+ chr = (gs_char) glyph, glyph = gs_no_glyph;
+/****** RESCAN chr IF DESCENDANT IS CMAP'ED ******/
+ break;
+ }
+
+ }
+
+ select_descendant(pfont, pdata, fidx, fdepth);
+ if_debug2('J', "... new depth=%d, new font=0x%lx\n",
+ fdepth, (ulong) pfont);
+ }
+done:
+ *pchr = chr;
+ *pglyph = glyph;
+ /* Update the pointer into the original string, but only if */
+ /* we didn't switch over to parsing a code from a CMap. */
+ if (str == penum->text.data.bytes)
+ penum->index = p - str;
+ penum->fstack.depth = fdepth;
+ if_debug4('J', "[J]depth=%d font=0x%lx index=%d changed=%d\n",
+ fdepth, (ulong) penum->fstack.items[fdepth].font,
+ penum->fstack.items[fdepth].index, changed);
+ return changed;
+#undef pfont0
+}
diff --git a/pstoraster/gscie.c b/pstoraster/gscie.c
new file mode 100644
index 000000000..968b81346
--- /dev/null
+++ b/pstoraster/gscie.c
@@ -0,0 +1,1357 @@
+/* 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$ */
+/* CIE color rendering for Ghostscript */
+#include "math_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gsmatrix.h" /* for gscolor2.h */
+#include "gxcspace.h"
+#include "gscolor2.h" /* for gs_set/currentcolorrendering */
+#include "gscie.h"
+#include "gxarith.h"
+#include "gxdevice.h" /* for gxcmap.h */
+#include "gxcmap.h"
+#include "gzstate.h"
+
+/* Forward references */
+private int cie_joint_caches_init(P3(gx_cie_joint_caches *,
+ const gs_cie_common *,
+ gs_cie_render *));
+private void cie_joint_caches_complete(P3(gx_cie_joint_caches *,
+ const gs_cie_common *, const gs_cie_render *));
+private void cie_cache_restrict(P2(cie_cache_floats *, const gs_range *));
+private void cie_mult3(P3(const gs_vector3 *, const gs_matrix3 *,
+ gs_vector3 *));
+private void cie_matrix_mult3(P3(const gs_matrix3 *, const gs_matrix3 *,
+ gs_matrix3 *));
+private void cie_invert3(P2(const gs_matrix3 *, gs_matrix3 *));
+private void cie_matrix_init(P1(gs_matrix3 *));
+
+#define set_restrict_index(i, v, n)\
+ if ( (uint)(i = (int)(v)) >= (n) )\
+ i = (i < 0 ? 0 : (n) - 1)
+#define restrict_index(v, n, itemp)\
+ ((uint)(itemp = (int)(v)) >= (n) ?\
+ (itemp < 0 ? 0 : (n) - 1) : itemp)
+
+/* Compute a cache index as (vin - base) * factor. */
+/* vin, base, factor, and the result are cie_cached_values. */
+/* We know that the result doesn't exceed (gx_cie_cache_size - 1) << fbits. */
+#define lookup_index(vin, pcache, fbits)\
+ ((vin) <= (pcache)->vecs.params.base ? 0 :\
+ (vin) >= (pcache)->vecs.params.limit ? (gx_cie_cache_size - 1) << (fbits) :\
+ cie_cached_product2int( ((vin) - (pcache)->vecs.params.base),\
+ (pcache)->vecs.params.factor, fbits ))
+#define lookup_value(vin, pcache)\
+ ((pcache)->vecs.values[lookup_index(vin, pcache, 0)])
+
+#define if_restrict(v, range)\
+ if ( (v) < (range).rmin ) v = (range).rmin;\
+ else if ( (v) > (range).rmax ) v = (range).rmax
+
+/* Define the template for loading a cache. */
+/* If we had parameterized types, or a more flexible type system, */
+/* this could be done with a single procedure. */
+#define CIE_LOAD_CACHE_BODY(pcache, domains, rprocs, pcie, cname)\
+ BEGIN\
+ int j;\
+\
+ for (j = 0; j < countof(pcache); j++) {\
+ int i;\
+ gs_for_loop_params lp;\
+\
+ gs_cie_cache_init(&(pcache)[j].floats.params, &lp,\
+ &(domains)[j], cname);\
+ for (i = 0; i < gx_cie_cache_size; lp.init += lp.step, i++)\
+ pcache[j].floats.values[i] = (*(rprocs)->procs[j])(lp.init, pcie);\
+ }\
+ END
+
+/* Allocator structure types */
+private_st_joint_caches();
+
+/* ------ Default values for CIE dictionary elements ------ */
+
+/* Default transformation procedures. */
+
+private float
+a_identity(floatp in, const gs_cie_a * pcie)
+{
+ return in;
+}
+private float
+abc_identity(floatp in, const gs_cie_abc * pcie)
+{
+ return in;
+}
+private float
+def_identity(floatp in, const gs_cie_def * pcie)
+{
+ return in;
+}
+private float
+defg_identity(floatp in, const gs_cie_defg * pcie)
+{
+ return in;
+}
+private float
+common_identity(floatp in, const gs_cie_common * pcie)
+{
+ return in;
+}
+
+/* Default vectors and matrices. */
+
+const gs_range3 Range3_default = {
+ { {0, 1}, {0, 1}, {0, 1} }
+};
+const gs_range4 Range4_default = {
+ { {0, 1}, {0, 1}, {0, 1}, {0, 1} }
+};
+const gs_cie_defg_proc4 DecodeDEFG_default = {
+ {defg_identity, defg_identity, defg_identity, defg_identity}
+};
+const gs_cie_def_proc3 DecodeDEF_default = {
+ {def_identity, def_identity, def_identity}
+};
+const gs_cie_abc_proc3 DecodeABC_default = {
+ {abc_identity, abc_identity, abc_identity}
+};
+const gs_cie_common_proc3 DecodeLMN_default = {
+ {common_identity, common_identity, common_identity}
+};
+const gs_matrix3 Matrix3_default = {
+ {1, 0, 0},
+ {0, 1, 0},
+ {0, 0, 1},
+ 1 /*true */
+};
+const gs_range RangeA_default = {0, 1};
+const gs_cie_a_proc DecodeA_default = a_identity;
+const gs_vector3 MatrixA_default = {1, 1, 1};
+const gs_vector3 BlackPoint_default = {0, 0, 0};
+
+/* Initialize a CIE color. */
+/* This only happens on setcolorspace. */
+void
+gx_init_CIE(gs_client_color * pcc, const gs_color_space * pcs)
+{
+ gx_init_paint_4(pcc, pcs);
+ /* (0...) may not be within the range of allowable values. */
+ (*pcs->type->restrict_color)(pcc, pcs);
+}
+
+/* Restrict CIE colors. */
+
+#define FORCE_VALUE(pcc, i, range)\
+ if ( pcc->paint.values[i] <= range.rmin )\
+ pcc->paint.values[i] = range.rmin;\
+ else if ( pcc->paint.values[i] >= range.rmax )\
+ pcc->paint.values[i] = range.rmax
+#define FORCE_RANGE(pcc, i, erange)\
+ FORCE_VALUE(pcc, i, pcie->erange.ranges[i])
+
+void
+gx_restrict_CIEDEFG(gs_client_color * pcc, const gs_color_space * pcs)
+{
+ const gs_cie_defg *pcie = pcs->params.defg;
+
+ FORCE_RANGE(pcc, 0, RangeDEFG);
+ FORCE_RANGE(pcc, 1, RangeDEFG);
+ FORCE_RANGE(pcc, 2, RangeDEFG);
+ FORCE_RANGE(pcc, 3, RangeDEFG);
+}
+void
+gx_restrict_CIEDEF(gs_client_color * pcc, const gs_color_space * pcs)
+{
+ const gs_cie_def *pcie = pcs->params.def;
+
+ FORCE_RANGE(pcc, 0, RangeDEF);
+ FORCE_RANGE(pcc, 1, RangeDEF);
+ FORCE_RANGE(pcc, 2, RangeDEF);
+}
+void
+gx_restrict_CIEABC(gs_client_color * pcc, const gs_color_space * pcs)
+{
+ const gs_cie_abc *pcie = pcs->params.abc;
+
+ FORCE_RANGE(pcc, 0, RangeABC);
+ FORCE_RANGE(pcc, 1, RangeABC);
+ FORCE_RANGE(pcc, 2, RangeABC);
+}
+void
+gx_restrict_CIEA(gs_client_color * pcc, const gs_color_space * pcs)
+{
+ const gs_cie_a *pcie = pcs->params.a;
+
+ FORCE_VALUE(pcc, 0, pcie->RangeA);
+}
+
+#undef FORCE_VALUE
+#undef FORCE_RANGE
+
+/* ================ Table setup ================ */
+
+/* ------ Install a CIE color space ------ */
+
+private int cie_load_common_cache(P3(gs_cie_common *, gs_state *,
+ client_name_t));
+private void cie_cache_mult(P3(gx_cie_vector_cache *, const gs_vector3 *,
+ const cie_cache_floats *));
+private bool cie_cache_mult3(P2(gx_cie_vector_cache *,
+ const gs_matrix3 *));
+
+private int
+gx_install_cie_abc(gs_cie_abc *pcie, gs_state * pgs)
+{
+ cie_matrix_init(&pcie->MatrixABC);
+ CIE_LOAD_CACHE_BODY(pcie->caches.DecodeABC, pcie->RangeABC.ranges,
+ &pcie->DecodeABC, pcie, "DecodeABC");
+ gs_cie_abc_complete(pcie);
+ return cie_load_common_cache(&pcie->common, pgs, "gx_install_CIEABC");
+}
+
+int
+gx_install_CIEDEFG(gs_color_space * pcs, gs_state * pgs)
+{
+ gs_cie_defg *pcie = pcs->params.defg;
+
+ CIE_LOAD_CACHE_BODY(pcie->caches_defg.DecodeDEFG, pcie->RangeDEFG.ranges,
+ &pcie->DecodeDEFG, pcie, "DecodeDEFG");
+ return gx_install_cie_abc((gs_cie_abc *)pcie, pgs);
+}
+
+int
+gx_install_CIEDEF(gs_color_space * pcs, gs_state * pgs)
+{
+ gs_cie_def *pcie = pcs->params.def;
+
+ CIE_LOAD_CACHE_BODY(pcie->caches_def.DecodeDEF, pcie->RangeDEF.ranges,
+ &pcie->DecodeDEF, pcie, "DecodeDEF");
+ return gx_install_cie_abc((gs_cie_abc *)pcie, pgs);
+}
+
+int
+gx_install_CIEABC(gs_color_space * pcs, gs_state * pgs)
+{
+ return gx_install_cie_abc(pcs->params.abc, pgs);
+}
+
+int
+gx_install_CIEA(gs_color_space * pcs, gs_state * pgs)
+{
+ gs_cie_a *pcie = pcs->params.a;
+ int i;
+ gs_for_loop_params lp;
+ float in;
+
+ gs_cie_cache_init(&pcie->caches.DecodeA.floats.params, &lp,
+ &pcie->RangeA, "DecodeA");
+ for (i = 0, in = lp.init; i < gx_cie_cache_size; in += lp.step, i++)
+ pcie->caches.DecodeA.floats.values[i] =
+ (*pcie->DecodeA)(in, pcie);
+ gs_cie_a_complete(pcie);
+ return cie_load_common_cache(&pcie->common, pgs, "gx_install_CIEA");
+}
+
+/* Load the common caches when installing the color space. */
+private int
+cie_load_common_cache(gs_cie_common * pcie, gs_state * pgs, client_name_t cname)
+{
+ gx_cie_joint_caches *pjc;
+ int code;
+
+ cie_matrix_init(&pcie->MatrixLMN);
+ CIE_LOAD_CACHE_BODY(pcie->caches.DecodeLMN, pcie->RangeLMN.ranges,
+ &pcie->DecodeLMN, pcie, "DecodeLMN");
+ if (pgs->cie_render == 0)
+ return 0;
+ pjc = gx_currentciecaches(pgs);
+ if (pjc == 0)
+ return_error(gs_error_VMerror);
+ code = cie_joint_caches_init(pjc, pcie, pgs->cie_render);
+ if (code < 0)
+ return code;
+ cie_joint_caches_complete(pjc, pcie, pgs->cie_render);
+ return 0;
+}
+
+/* Restrict and scale the DecodeDEF[G] cache according to RangeHIJ[K]. */
+private void
+gs_cie_defx_scale(float *values, const gs_range *range)
+{
+ double scale = 255.0 / (range->rmax - range->rmin);
+ int i;
+
+ for (i = 0; i < gx_cie_cache_size; ++i) {
+ float value = values[i];
+
+ values[i] =
+ (value <= range->rmin ? 0 :
+ value >= range->rmax ? 255 :
+ (value - range->rmin) * scale);
+ }
+}
+
+/* Complete loading a CIEBasedDEFG color space. */
+/* This routine is not idempotent. */
+void
+gs_cie_defg_complete(gs_cie_defg * pcie)
+{
+ int j;
+
+ for (j = 0; j < 4; ++j)
+ gs_cie_defx_scale(pcie->caches_defg.DecodeDEFG[j].floats.values,
+ &pcie->RangeHIJK.ranges[j]);
+ gs_cie_abc_complete((gs_cie_abc *)pcie);
+}
+
+/* Complete loading a CIEBasedDEF color space. */
+/* This routine is not idempotent. */
+void
+gs_cie_def_complete(gs_cie_def * pcie)
+{
+ int j;
+
+ for (j = 0; j < 3; ++j)
+ gs_cie_defx_scale(pcie->caches_def.DecodeDEF[j].floats.values,
+ &pcie->RangeHIJ.ranges[j]);
+ gs_cie_abc_complete((gs_cie_abc *)pcie);
+}
+
+/* Complete loading a CIEBasedABC color space. */
+/* This routine is not idempotent. */
+void
+gs_cie_abc_complete(gs_cie_abc * pcie)
+{
+ pcie->caches.skipABC =
+ cie_cache_mult3(pcie->caches.DecodeABC, &pcie->MatrixABC);
+}
+
+/* Complete loading a CIEBasedA color space. */
+/* This routine is not idempotent. */
+void
+gs_cie_a_complete(gs_cie_a * pcie)
+{
+ cie_cache_mult(&pcie->caches.DecodeA, &pcie->MatrixA,
+ &pcie->caches.DecodeA.floats);
+}
+
+/* Convert a scalar cache to a vector cache by multiplying */
+/* the scalar values by a vector. */
+private void
+cie_cache_mult(gx_cie_vector_cache * pcache, const gs_vector3 * pvec,
+ const cie_cache_floats * pcf)
+{
+ int i;
+ cie_vector_cache_params params;
+
+ params.is_identity = pcf->params.is_identity;
+ params.base = float2cie_cached(pcf->params.base);
+ params.factor = float2cie_cached(pcf->params.factor);
+ params.limit =
+ float2cie_cached((gx_cie_cache_size - 1) / pcf->params.factor +
+ pcf->params.base);
+ /* Loop from top to bottom so that we don't */
+ /* overwrite elements before they're used, */
+ /* in case pcf is an alias for pcache->floats. */
+ for (i = gx_cie_cache_size; --i >= 0;) {
+ float f = pcf->values[i];
+
+ pcache->vecs.values[i].u = float2cie_cached(f * pvec->u);
+ pcache->vecs.values[i].v = float2cie_cached(f * pvec->v);
+ pcache->vecs.values[i].w = float2cie_cached(f * pvec->w);
+ }
+ pcache->vecs.params = params;
+}
+
+/* Convert 3 scalar caches to vector caches by multiplying by a matrix. */
+/* Return true iff the resulting cache is an identity transformation. */
+private bool
+cie_cache_mult3(gx_cie_vector_cache * pc /*[3] */ , const gs_matrix3 * pmat)
+{
+ cie_cache_mult(pc, &pmat->cu, &pc->floats);
+ cie_cache_mult(pc + 1, &pmat->cv, &pc[1].floats);
+ cie_cache_mult(pc + 2, &pmat->cw, &pc[2].floats);
+ return pmat->is_identity & pc[0].vecs.params.is_identity &
+ pc[1].vecs.params.is_identity & pc[2].vecs.params.is_identity;
+}
+
+/* ------ Install a rendering dictionary ------ */
+
+/* setcolorrendering */
+int
+gs_setcolorrendering(gs_state * pgs, gs_cie_render * pcrd)
+{
+ int code = gs_cie_render_complete(pcrd);
+
+ if (code < 0)
+ return code;
+ rc_assign(pgs->cie_render, pcrd, "gs_setcolorrendering");
+ /* Initialize the joint caches if needed. */
+ code = gs_cie_cs_complete(pgs, true);
+ gx_unset_dev_color(pgs);
+ return code;
+}
+
+/* currentcolorrendering */
+const gs_cie_render *
+gs_currentcolorrendering(const gs_state * pgs)
+{
+ return pgs->cie_render;
+}
+
+/* Unshare (allocating if necessary) the joint caches. */
+gx_cie_joint_caches *
+gx_currentciecaches(gs_state * pgs)
+{
+ rc_unshare_struct(pgs->cie_joint_caches, gx_cie_joint_caches,
+ &st_joint_caches, pgs->memory,
+ return 0, "gx_currentciecaches");
+ return pgs->cie_joint_caches;
+}
+
+/* Compute the parameters for loading a cache, setting base and factor. */
+/* This procedure is idempotent. */
+void
+gs_cie_cache_init(cie_cache_params * pcache, gs_for_loop_params * pflp,
+ const gs_range * domain, client_name_t cname)
+{ /*
+ * We need to map the values in the range
+ * [domain->rmin..domain->rmax]. However, if neither rmin
+ * nor rmax is zero and the function is non-linear,
+ * this can lead to anomalies at zero, which is the
+ * default value for CIE colors. The "correct" way to
+ * approach this is to run the mapping functions on demand,
+ * but we don't want to deal with the complexities of the
+ * callbacks this would involve (especially in the middle of
+ * rendering images); instead, we adjust the range so that zero
+ * maps precisely to a cache slot. Define:
+ * a = domain->rmin;
+ * b = domain->rmax;
+ * R = b - a;
+ * N = gx_cie_cache_size - 1;
+ * f(v) = N(v-a)/R;
+ * x = f(0).
+ * If x is not an integer, we can either increase b or
+ * decrease a to make it one. In the former case, compute:
+ * Kb = floor(x); R'b = N(0-a)/Kb; b' = a + R'b.
+ * In the latter case, compute:
+ * Ka = ceiling(x-N); R'a = N(0-b)/Ka; a' = b - R'a.
+ * We choose whichever method stretches the range the least,
+ * i.e., the one whose R' value (R'a or R'b) is smaller.
+ */
+ double a = domain->rmin, b = domain->rmax;
+ double R = b - a;
+
+#define N (gx_cie_cache_size - 1)
+ double delta;
+
+ /* Adjust the range if necessary. */
+ if (a < 0 && b >= 0) {
+ double x = -N * a / R; /* must be > 0 */
+ double Kb = floor(x); /* must be >= 0 */
+ double Ka = ceil(x) - N; /* must be <= 0 */
+
+ if (Kb == 0 || (Ka != 0 && -b / Ka < -a / Kb)) /* use R'a */
+ R = -N * b / Ka, a = b - R;
+ else /* use R'b */
+ R = -N * a / Kb, b = a + R;
+ }
+ delta = R / N;
+#ifdef CIE_CACHE_INTERPOLATE
+ pcache->base = a; /* no rounding */
+#else
+ pcache->base = a - delta / 2; /* so lookup will round */
+#endif
+ pcache->factor = (delta == 0 ? 0 : N / R);
+ if_debug4('c', "[c]cache %s 0x%lx base=%g, factor=%g\n",
+ (const char *)cname, (ulong) pcache,
+ pcache->base, pcache->factor);
+ pflp->init = a;
+ pflp->step = delta;
+ pflp->limit = b + delta / 2;
+}
+
+/* ------ Complete a rendering structure ------ */
+
+/*
+ * Compute the derived values in a CRD that don't involve the cached
+ * procedure values. This procedure is idempotent.
+ */
+private void cie_transform_range3(P3(const gs_range3 *, const gs_matrix3 *,
+ gs_range3 *));
+int
+gs_cie_render_init(gs_cie_render * pcrd)
+{
+ gs_matrix3 PQR_inverse;
+
+ if (pcrd->status >= CIE_RENDER_STATUS_INITED)
+ return 0; /* init already done */
+ cie_matrix_init(&pcrd->MatrixLMN);
+ cie_matrix_init(&pcrd->MatrixABC);
+ cie_matrix_init(&pcrd->MatrixPQR);
+ cie_invert3(&pcrd->MatrixPQR, &PQR_inverse);
+ cie_matrix_mult3(&pcrd->MatrixLMN, &PQR_inverse,
+ &pcrd->MatrixPQR_inverse_LMN);
+ cie_transform_range3(&pcrd->RangePQR, &pcrd->MatrixPQR_inverse_LMN,
+ &pcrd->DomainLMN);
+ cie_transform_range3(&pcrd->RangeLMN, &pcrd->MatrixABC,
+ &pcrd->DomainABC);
+ cie_mult3(&pcrd->points.WhitePoint, &pcrd->MatrixPQR, &pcrd->wdpqr);
+ cie_mult3(&pcrd->points.BlackPoint, &pcrd->MatrixPQR, &pcrd->bdpqr);
+ pcrd->status = CIE_RENDER_STATUS_INITED;
+ return 0;
+}
+
+/*
+ * Sample the EncodeLMN, EncodeABC, and RenderTableT CRD procedures, and
+ * load the caches. This procedure is idempotent.
+ */
+int
+gs_cie_render_sample(gs_cie_render * pcrd)
+{
+ int code;
+
+ if (pcrd->status >= CIE_RENDER_STATUS_SAMPLED)
+ return 0; /* sampling already done */
+ code = gs_cie_render_init(pcrd);
+ if (code < 0)
+ return code;
+ CIE_LOAD_CACHE_BODY(pcrd->caches.EncodeLMN, pcrd->DomainLMN.ranges,
+ &pcrd->EncodeLMN, pcrd, "EncodeLMN");
+ CIE_LOAD_CACHE_BODY(pcrd->caches.EncodeABC, pcrd->DomainABC.ranges,
+ &pcrd->EncodeABC, pcrd, "EncodeABC");
+ if (pcrd->RenderTable.lookup.table != 0) {
+ int i, j, m = pcrd->RenderTable.lookup.m;
+ gs_for_loop_params flp;
+
+ for (j = 0; j < m; j++)
+ gs_cie_cache_init(&pcrd->caches.RenderTableT[j].fracs.params,
+ &flp, &Range3_default.ranges[0],
+ "RenderTableT");
+ /****** ASSUMES gx_cie_cache_size >= 256 ******/
+ for (i = 0; i < 256; i++)
+ for (j = 0; j < m; j++)
+ pcrd->caches.RenderTableT[j].fracs.values[i] =
+ (*pcrd->RenderTable.T.procs[j])((byte) i, pcrd);
+ }
+ pcrd->status = CIE_RENDER_STATUS_SAMPLED;
+ return 0;
+}
+
+/* Transform a set of ranges. */
+private void
+cie_transform_range(const gs_range3 * in, floatp mu, floatp mv, floatp mw,
+ gs_range * out)
+{
+ float umin = mu * in->ranges[0].rmin, umax = mu * in->ranges[0].rmax;
+ float vmin = mv * in->ranges[1].rmin, vmax = mv * in->ranges[1].rmax;
+ float wmin = mw * in->ranges[2].rmin, wmax = mw * in->ranges[2].rmax;
+ float temp;
+
+ if (umin > umax)
+ temp = umin, umin = umax, umax = temp;
+ if (vmin > vmax)
+ temp = vmin, vmin = vmax, vmax = temp;
+ if (wmin > wmax)
+ temp = wmin, wmin = wmax, wmax = temp;
+ out->rmin = umin + vmin + wmin;
+ out->rmax = umax + vmax + wmax;
+}
+private void
+cie_transform_range3(const gs_range3 * in, const gs_matrix3 * mat,
+ gs_range3 * out)
+{
+ cie_transform_range(in, mat->cu.u, mat->cv.u, mat->cw.u,
+ &out->ranges[0]);
+ cie_transform_range(in, mat->cu.v, mat->cv.v, mat->cw.v,
+ &out->ranges[1]);
+ cie_transform_range(in, mat->cu.w, mat->cv.w, mat->cw.w,
+ &out->ranges[2]);
+}
+
+/*
+ * Finish preparing a CRD for installation, by restricting and/or
+ * transforming the cached procedure values. The actual work done by
+ * this procedure is not idempotent, but the CRD status prevents it
+ * from being done more than once.
+ */
+int
+gs_cie_render_complete(gs_cie_render * pcrd)
+{
+ int code;
+
+ if (pcrd->status >= CIE_RENDER_STATUS_COMPLETED)
+ return 0; /* completion already done */
+ code = gs_cie_render_sample(pcrd);
+ if (code < 0)
+ return code;
+ /*
+ * Since range restriction happens immediately after
+ * the cache lookup, we can save a step by restricting
+ * the values in the cache entries.
+ *
+ * If there is no lookup table, we want the final ABC values
+ * to be fracs; if there is a table, we want them to be
+ * appropriately scaled ints.
+ */
+ pcrd->MatrixABCEncode = pcrd->MatrixABC;
+ {
+ int c;
+ double f;
+
+ for (c = 0; c < 3; c++) {
+ gx_cie_scalar_cache *pcache = &pcrd->caches.EncodeABC[c];
+
+ cie_cache_restrict(&pcrd->caches.EncodeLMN[c].floats,
+ &pcrd->RangeLMN.ranges[c]);
+ cie_cache_restrict(&pcrd->caches.EncodeABC[c].floats,
+ &pcrd->RangeABC.ranges[c]);
+ if (pcrd->RenderTable.lookup.table == 0) {
+ cie_cache_restrict(&pcache->floats,
+ &Range3_default.ranges[0]);
+ gs_cie_cache_to_fracs(pcache);
+ pcache->fracs.params.is_identity = false;
+ } else {
+ int i;
+ int n = pcrd->RenderTable.lookup.dims[c];
+
+#ifdef CIE_RENDER_TABLE_INTERPOLATE
+# define scale_index(f, n, itemp)\
+ restrict_index(f * (1 << _cie_interpolate_bits),\
+ (n) << _cie_interpolate_bits, itemp)
+#else
+ int m = pcrd->RenderTable.lookup.m;
+ int k =
+ (c == 0 ? 1 : c == 1 ?
+ m * pcrd->RenderTable.lookup.dims[2] : m);
+
+# define scale_index(f, n, itemp)\
+ (restrict_index(f, n, itemp) * k)
+#endif
+ const gs_range *prange =
+ pcrd->RangeABC.ranges + c;
+
+ /* Loop from top to bottom so that we don't */
+ /* overwrite elements before they're used. */
+ for (i = gx_cie_cache_size; --i >= 0;) {
+ float v =
+ (pcache->floats.values[i] -
+ prange->rmin) * (n - 1) /
+ (prange->rmax - prange->rmin)
+#ifndef CIE_RENDER_TABLE_INTERPOLATE
+ + 0.5
+#endif
+ ;
+ int itemp;
+
+ if_debug5('c',
+ "[c]cache[%d][%d] = %g => %g => %d\n",
+ c, i, pcache->floats.values[i], v,
+ scale_index(v, n, itemp));
+ pcache->ints.values[i] =
+ scale_index(v, n, itemp);
+ }
+ pcache->ints.params = pcache->floats.params; /* (not necessary) */
+ pcache->ints.params.is_identity = false;
+#undef scale_index
+ }
+ }
+ /* Fold the scaling of the EncodeABC cache index */
+ /* into MatrixABC. */
+#define mabc(i, t)\
+ f = pcrd->caches.EncodeABC[i].floats.params.factor;\
+ pcrd->MatrixABCEncode.cu.t *= f;\
+ pcrd->MatrixABCEncode.cv.t *= f;\
+ pcrd->MatrixABCEncode.cw.t *= f;\
+ pcrd->EncodeABC_base[i] =\
+ float2cie_cached(pcrd->caches.EncodeABC[i].floats.params.base * f)
+ mabc(0, u);
+ mabc(1, v);
+ mabc(2, w);
+ pcrd->MatrixABCEncode.is_identity = 0;
+ }
+#undef mabc
+ cie_cache_mult3(pcrd->caches.EncodeLMN, &pcrd->MatrixABCEncode);
+ pcrd->status = CIE_RENDER_STATUS_COMPLETED;
+ return 0;
+}
+
+/* Apply a range restriction to a cache. */
+private void
+cie_cache_restrict(cie_cache_floats * pcache, const gs_range * prange)
+{
+ int i;
+
+ for (i = 0; i < gx_cie_cache_size; i++)
+ if_restrict(pcache->values[i], *prange);
+}
+
+/* Convert a cache from floats to fracs. */
+void
+gs_cie_cache_to_fracs(gx_cie_scalar_cache * pcache)
+{
+ int i;
+
+ /* Loop from bottom to top so that we don't */
+ /* overwrite elements before they're used. */
+ for (i = 0; i < gx_cie_cache_size; ++i)
+ pcache->fracs.values[i] = float2frac(pcache->floats.values[i]);
+ pcache->fracs.params = pcache->floats.params; /* (not necessary) */
+}
+
+/* ------ Fill in the joint cache ------ */
+
+/* If the current color space is a CIE space, or has a CIE base space, */
+/* return a pointer to the common part of the space; otherwise return 0. */
+const gs_cie_common *
+gs_cie_cs_common(gs_state * pgs)
+{
+ const gs_color_space *pcs = pgs->color_space;
+
+ do {
+ switch (pcs->type->index) {
+ case gs_color_space_index_CIEDEF:
+ return &pcs->params.def->common;
+ case gs_color_space_index_CIEDEFG:
+ return &pcs->params.defg->common;
+ case gs_color_space_index_CIEABC:
+ return &pcs->params.abc->common;
+ case gs_color_space_index_CIEA:
+ return &pcs->params.a->common;
+ default:
+ pcs = gs_cspace_base_space(pcs);
+ break;
+ }
+ } while (pcs != 0);
+
+ return 0;
+}
+
+/* Finish loading the joint caches for the current color space. */
+int
+gs_cie_cs_complete(gs_state * pgs, bool init)
+{
+ const gs_cie_common *common = gs_cie_cs_common(pgs);
+
+ if (common) {
+ if (init) {
+ int code = cie_joint_caches_init(pgs->cie_joint_caches, common,
+ pgs->cie_render);
+
+ if (code < 0)
+ return code;
+ }
+ cie_joint_caches_complete(pgs->cie_joint_caches, common,
+ pgs->cie_render);
+ }
+ return 0;
+}
+
+/*
+ * Compute the source and destination WhitePoint and BlackPoint for
+ * the TransformPQR procedure.
+ */
+int
+gs_cie_compute_wbsd(gs_cie_wbsd * pwbsd,
+ const gs_vector3 * cs_WhitePoint, const gs_vector3 * cs_BlackPoint,
+ const gs_cie_render * pcrd)
+{
+ pwbsd->ws.xyz = *cs_WhitePoint;
+ cie_mult3(&pwbsd->ws.xyz, &pcrd->MatrixPQR, &pwbsd->ws.pqr);
+ pwbsd->bs.xyz = *cs_BlackPoint;
+ cie_mult3(&pwbsd->bs.xyz, &pcrd->MatrixPQR, &pwbsd->bs.pqr);
+ pwbsd->wd.xyz = pcrd->points.WhitePoint;
+ pwbsd->wd.pqr = pcrd->wdpqr;
+ pwbsd->bd.xyz = pcrd->points.BlackPoint;
+ pwbsd->bd.pqr = pcrd->bdpqr;
+ return 0;
+}
+
+/* Compute values derived from the color space and rendering parameters */
+/* other than the cached procedure values. This routine is idempotent. */
+private int
+cie_joint_caches_init(gx_cie_joint_caches * pjc,
+ const gs_cie_common * pcie,
+ gs_cie_render * pcrd)
+{
+ gs_cie_compute_wbsd(&pjc->points_sd, &pcie->points.WhitePoint,
+ &pcie->points.BlackPoint, pcrd);
+ cie_matrix_mult3(&pcrd->MatrixPQR, &pcie->MatrixLMN,
+ &pjc->MatrixLMN_PQR);
+ /* Load the TransformPQR caches. */
+ {
+ int j;
+
+ for (j = 0; j < 3; j++) {
+ int i;
+ gs_for_loop_params lp;
+
+ gs_cie_cache_init(&pjc->TransformPQR[j].floats.params, &lp,
+ &pcrd->RangePQR.ranges[j], "TransformPQR");
+ for (i = 0; i < gx_cie_cache_size; lp.init += lp.step, i++) {
+ float out;
+ int code =
+ (*pcrd->TransformPQR.proc)(j, lp.init, &pjc->points_sd,
+ pcrd, &out);
+
+ if (code < 0)
+ return code;
+ pjc->TransformPQR[j].floats.values[i] = out;
+ }
+ }
+ }
+ return 0;
+}
+
+/* Complete the loading of the joint caches. This routine is NOT */
+/* idempotent. */
+private void
+cie_joint_caches_complete(gx_cie_joint_caches * pjc,
+ const gs_cie_common * pcie, const gs_cie_render * pcrd)
+{
+ int j;
+
+ for (j = 0; j < 3; j++) {
+ cie_cache_restrict(&pjc->TransformPQR[j].floats,
+ &pcrd->RangePQR.ranges[j]);
+ cie_cache_mult(&pjc->DecodeLMN[j],
+ &pjc->MatrixLMN_PQR.cu + j,
+ &pcie->caches.DecodeLMN[j].floats);
+ }
+ pjc->skipLMN = pjc->MatrixLMN_PQR.is_identity &
+ pjc->DecodeLMN[0].vecs.params.is_identity &
+ pjc->DecodeLMN[1].vecs.params.is_identity &
+ pjc->DecodeLMN[2].vecs.params.is_identity;
+ pjc->skipPQR =
+ cie_cache_mult3(pjc->TransformPQR, &pcrd->MatrixPQR_inverse_LMN);
+}
+
+/* ================ Color rendering (using the caches) ================ */
+
+private int cie_remap_finish(P3(const cie_cached_vector3 *,
+ frac *, const gs_imager_state *));
+private void cie_lookup_mult3(P2(cie_cached_vector3 *,
+ const gx_cie_vector_cache *));
+
+#ifdef DEBUG
+private void
+cie_lookup_map3(cie_cached_vector3 * pvec,
+ const gx_cie_vector_cache * pc /*[3] */ , const char *cname)
+{
+ if_debug5('c', "[c]lookup %s 0x%lx [%g %g %g]\n",
+ (const char *)cname, (ulong) pc,
+ cie_cached2float(pvec->u), cie_cached2float(pvec->v),
+ cie_cached2float(pvec->w));
+ cie_lookup_mult3(pvec, pc);
+ if_debug3('c', " =[%g %g %g]\n",
+ cie_cached2float(pvec->u), cie_cached2float(pvec->v),
+ cie_cached2float(pvec->w));
+}
+#else
+# define cie_lookup_map3(pvec, pc, cname) cie_lookup_mult3(pvec, pc)
+#endif
+
+/* Render a CIEBasedDEFG color. */
+int
+gx_concretize_CIEDEFG(const gs_client_color * pc, const gs_color_space * pcs,
+ frac * pconc, const gs_imager_state * pis)
+{
+ const gs_cie_defg *pcie = pcs->params.defg;
+ int i;
+ fixed hijk[4];
+ frac abc[3];
+ cie_cached_vector3 vec3;
+
+ if_debug4('c', "[c]concretize DEFG [%g %g %g %g]\n",
+ pc->paint.values[0], pc->paint.values[1],
+ pc->paint.values[2], pc->paint.values[3]);
+ /* Apply DecodeDEFG (including restriction to RangeHIJK). */
+ for (i = 0; i < 4; ++i) {
+ int tmax = pcie->Table.dims[i] - 1;
+ float value = (pc->paint.values[i] - pcie->RangeDEFG.ranges[i].rmin) *
+ tmax /
+ (pcie->RangeDEFG.ranges[i].rmax - pcie->RangeDEFG.ranges[i].rmin);
+ int vi = (int)value;
+ float vf = value - vi;
+ float v = pcie->caches_defg.DecodeDEFG[i].floats.values[vi];
+
+ if (vf != 0 && vi < tmax)
+ v += vf *
+ (pcie->caches_defg.DecodeDEFG[i].floats.values[vi + 1] - v);
+ hijk[i] = float2fixed(v);
+ }
+ /* Apply Table. */
+ gx_color_interpolate_linear(hijk, &pcie->Table, abc);
+ vec3.u = float2cie_cached(frac2float(abc[0]));
+ vec3.v = float2cie_cached(frac2float(abc[1]));
+ vec3.w = float2cie_cached(frac2float(abc[2]));
+ /* Apply DecodeABC and MatrixABC. */
+ if (!pcie->caches.skipABC)
+ cie_lookup_map3(&vec3 /* ABC => LMN */, &pcie->caches.DecodeABC[0],
+ "Decode/MatrixABC");
+ cie_remap_finish(&vec3, pconc, pis);
+ return 0;
+}
+
+/* Render a CIEBasedDEF color. */
+int
+gx_concretize_CIEDEF(const gs_client_color * pc, const gs_color_space * pcs,
+ frac * pconc, const gs_imager_state * pis)
+{
+ const gs_cie_def *pcie = pcs->params.def;
+ int i;
+ fixed hij[3];
+ frac abc[3];
+ cie_cached_vector3 vec3;
+
+ if_debug3('c', "[c]concretize DEF [%g %g %g]\n",
+ pc->paint.values[0], pc->paint.values[1],
+ pc->paint.values[2]);
+ /* Apply DecodeDEF (including restriction to RangeHIJ). */
+ for (i = 0; i < 3; ++i) {
+ int tmax = pcie->Table.dims[i] - 1;
+ float value = (pc->paint.values[i] - pcie->RangeDEF.ranges[i].rmin) *
+ tmax /
+ (pcie->RangeDEF.ranges[i].rmax - pcie->RangeDEF.ranges[i].rmin);
+ int vi = (int)value;
+ float vf = value - vi;
+ float v = pcie->caches_def.DecodeDEF[i].floats.values[vi];
+
+ if (vf != 0 && vi < tmax)
+ v += vf *
+ (pcie->caches_def.DecodeDEF[i].floats.values[vi + 1] - v);
+ hij[i] = float2fixed(v);
+ }
+ /* Apply Table. */
+ gx_color_interpolate_linear(hij, &pcie->Table, abc);
+ vec3.u = float2cie_cached(frac2float(abc[0]));
+ vec3.v = float2cie_cached(frac2float(abc[1]));
+ vec3.w = float2cie_cached(frac2float(abc[2]));
+ /* Apply DecodeABC and MatrixABC. */
+ if (!pcie->caches.skipABC)
+ cie_lookup_map3(&vec3 /* ABC => LMN */, &pcie->caches.DecodeABC[0],
+ "Decode/MatrixABC");
+ cie_remap_finish(&vec3, pconc, pis);
+ return 0;
+}
+
+/* Render a CIEBasedABC color. */
+/* We provide both remap and concretize, but only the former */
+/* needs to be efficient. */
+int
+gx_remap_CIEABC(const gs_client_color * pc, const gs_color_space * pcs,
+ gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
+ gs_color_select_t select)
+{
+ frac conc[4];
+ const gs_cie_abc *pcie = pcs->params.abc;
+ cie_cached_vector3 vec3;
+
+ if_debug3('c', "[c]remap CIEABC [%g %g %g]\n",
+ pc->paint.values[0], pc->paint.values[1],
+ pc->paint.values[2]);
+ vec3.u = float2cie_cached(pc->paint.values[0]);
+ vec3.v = float2cie_cached(pc->paint.values[1]);
+ vec3.w = float2cie_cached(pc->paint.values[2]);
+
+ /* Apply DecodeABC and MatrixABC. */
+#define vabc vec3
+#define vlmn vec3
+ if (!pcie->caches.skipABC)
+ cie_lookup_map3(&vabc /*&vlmn */ , &pcie->caches.DecodeABC[0],
+ "Decode/MatrixABC");
+#undef vabc
+ switch (cie_remap_finish(&vlmn, conc, pis)) {
+ case 3:
+ if_debug3('c', "[c]=RGB [%g %g %g]\n",
+ frac2float(conc[0]), frac2float(conc[1]),
+ frac2float(conc[2]));
+ gx_remap_concrete_rgb(conc[0], conc[1], conc[2], pdc, pis,
+ dev, select);
+ return 0;
+ case 4:
+ if_debug4('c', "[c]=CMYK [%g %g %g %g]\n",
+ frac2float(conc[0]), frac2float(conc[1]),
+ frac2float(conc[2]), frac2float(conc[3]));
+ gx_remap_concrete_cmyk(conc[0], conc[1], conc[2], conc[3],
+ pdc, pis, dev, select);
+ return 0;
+ }
+ /* Can't happen. */
+ return_error(gs_error_unknownerror);
+#undef vlmn
+}
+int
+gx_concretize_CIEABC(const gs_client_color * pc, const gs_color_space * pcs,
+ frac * pconc, const gs_imager_state * pis)
+{
+ const gs_cie_abc *pcie = pcs->params.abc;
+ cie_cached_vector3 vec3;
+
+ if_debug3('c', "[c]concretize CIEABC [%g %g %g]\n",
+ pc->paint.values[0], pc->paint.values[1],
+ pc->paint.values[2]);
+ vec3.u = float2cie_cached(pc->paint.values[0]);
+ vec3.v = float2cie_cached(pc->paint.values[1]);
+ vec3.w = float2cie_cached(pc->paint.values[2]);
+#define vabc vec3
+#define vlmn vec3
+ if (!pcie->caches.skipABC)
+ cie_lookup_map3(&vabc /*&vlmn */ , &pcie->caches.DecodeABC[0],
+ "Decode/MatrixABC");
+#undef vabc
+ cie_remap_finish(&vlmn, pconc, pis);
+#undef vlmn
+ return 0;
+}
+
+/* Render a CIEBasedA color. */
+int
+gx_concretize_CIEA(const gs_client_color * pc, const gs_color_space * pcs,
+ frac * pconc, const gs_imager_state * pis)
+{
+ const gs_cie_a *pcie = pcs->params.a;
+ cie_cached_value a = float2cie_cached(pc->paint.values[0]);
+ cie_cached_vector3 vlmn;
+
+ if_debug1('c', "[c]concretize CIEA %g\n", pc->paint.values[0]);
+
+ /* Apply DecodeA and MatrixA. */
+ vlmn = lookup_value(a, &pcie->caches.DecodeA);
+ return cie_remap_finish(&vlmn, pconc, pis);
+}
+
+/* Common rendering code. */
+/* Return 3 if RGB, 4 if CMYK. */
+private int
+cie_remap_finish(const cie_cached_vector3 * plmn, frac * pconc,
+ const gs_imager_state * pis)
+{
+ const gs_cie_render *pcie = pis->cie_render;
+ const gx_cie_joint_caches *pjc = pis->cie_joint_caches;
+ const gs_const_string *table;
+ cie_cached_vector3 vec3;
+ int tabc[3]; /* indices for final EncodeABC lookup */
+
+ if (pcie == 0) { /* No rendering has been defined yet. */
+ /* Just return black. */
+ pconc[0] = pconc[1] = pconc[2] = frac_0;
+ return 3;
+ }
+ /* Apply DecodeLMN, MatrixLMN(decode), and MatrixPQR. */
+#define vlmn vec3
+ vlmn = *plmn;
+#define vpqr vec3
+ if (!pjc->skipLMN)
+ cie_lookup_map3(&vlmn /*&vpqr */ , &pjc->DecodeLMN[0],
+ "Decode/MatrixLMN+MatrixPQR");
+#undef vlmn
+
+ /* Apply TransformPQR, MatrixPQR', and MatrixLMN(encode). */
+#define vlmn vec3
+ if (!pjc->skipPQR)
+ cie_lookup_map3(&vpqr /*&vlmn */ , &pjc->TransformPQR[0],
+ "Transform/Matrix'PQR+MatrixLMN");
+#undef vpqr
+
+ /* Apply EncodeLMN and MatrixABC(encode). */
+#define vabc vec3
+ cie_lookup_map3(&vlmn /*&vabc */ , &pcie->caches.EncodeLMN[0],
+ "EncodeLMN+MatrixABC");
+#undef vlmn
+ /* MatrixABCEncode includes the scaling of the EncodeABC */
+ /* cache index. */
+#define set_tabc(i, t)\
+ set_restrict_index(tabc[i],\
+ cie_cached2int(vabc.t - pcie->EncodeABC_base[i],\
+ _cie_interpolate_bits),\
+ gx_cie_cache_size << _cie_interpolate_bits)
+ set_tabc(0, u);
+ set_tabc(1, v);
+ set_tabc(2, w);
+ table = pcie->RenderTable.lookup.table;
+ if (table == 0) { /* No further transformation. */
+ /* The final mapping step includes both restriction to */
+ /* the range [0..1] and conversion to fracs. */
+#define eabc(i)\
+ cie_interpolate_fracs(pcie->caches.EncodeABC[i].fracs.values, tabc[i])
+ pconc[0] = eabc(0);
+ pconc[1] = eabc(1);
+ pconc[2] = eabc(2);
+#undef eabc
+ return 3;
+ } else { /* Use the RenderTable. */
+ int m = pcie->RenderTable.lookup.m;
+
+#define rt_lookup(j, i) pcie->caches.RenderTableT[j].fracs.values[i]
+#ifdef CIE_RENDER_TABLE_INTERPOLATE
+
+ /* The final mapping step includes restriction to the */
+ /* ranges [0..dims[c]] as ints with interpolation bits. */
+ fixed rfix[3];
+
+#define eabc(i)\
+ cie_interpolate_fracs(pcie->caches.EncodeABC[i].ints.values, tabc[i])
+#define fabc(i)\
+ (eabc(i) << (_fixed_shift - _cie_interpolate_bits))
+ rfix[0] = fabc(0);
+ rfix[1] = fabc(1);
+ rfix[2] = fabc(2);
+ if_debug6('c', "[c]ABC=%g,%g,%g => iabc=%g,%g,%g\n",
+ cie_cached2float(vabc.u), cie_cached2float(vabc.v),
+ cie_cached2float(vabc.w), fixed2float(rfix[0]),
+ fixed2float(rfix[1]), fixed2float(rfix[2]));
+ gx_color_interpolate_linear(rfix, &pcie->RenderTable.lookup,
+ pconc);
+ if_debug3('c', "[c] interpolated => %g,%g,%g\n",
+ frac2float(pconc[0]), frac2float(pconc[1]),
+ frac2float(pconc[2]));
+ if (!pcie->caches.RenderTableT_is_identity) { /* Map the interpolated values. */
+#define frac2cache_index(v) frac2bits(v, gx_cie_log2_cache_size)
+ pconc[0] = rt_lookup(0, frac2cache_index(pconc[0]));
+ pconc[1] = rt_lookup(1, frac2cache_index(pconc[1]));
+ pconc[2] = rt_lookup(2, frac2cache_index(pconc[2]));
+ if (m > 3)
+ pconc[3] = rt_lookup(3, frac2cache_index(pconc[3]));
+#undef frac2cache_index
+ }
+#else /* !CIE_RENDER_TABLE_INTERPOLATE */
+
+ /* The final mapping step includes restriction to the */
+ /* ranges [0..dims[c]], plus scaling of the indices */
+ /* in the strings. */
+#define ri(i)\
+ pcie->caches.EncodeABC[i].ints.values[tabc[i] >> _cie_interpolate_bits]
+ int ia = ri(0);
+ int ib = ri(1); /* pre-multiplied by m * NC */
+ int ic = ri(2); /* pre-multiplied by m */
+ const byte *prtc = table[ia].data + ib + ic;
+
+ /* (*pcie->RenderTable.T)(prtc, m, pcie, pconc); */
+
+ if_debug6('c', "[c]ABC=%g,%g,%g => iabc=%d,%d,%d\n",
+ cie_cached2float(vabc.u), cie_cached2float(vabc.v),
+ cie_cached2float(vabc.w), ia, ib, ic);
+ if (pcie->caches.RenderTableT_is_identity) {
+ pconc[0] = byte2frac(prtc[0]);
+ pconc[1] = byte2frac(prtc[1]);
+ pconc[2] = byte2frac(prtc[2]);
+ if (m > 3)
+ pconc[3] = byte2frac(prtc[3]);
+ } else {
+#if gx_cie_log2_cache_size == 8
+# define byte2cache_index(b) (b)
+#else
+# if gx_cie_log2_cache_size > 8
+# define byte2cache_index(b)\
+ ( ((b) << (gx_cie_log2_cache_size - 8)) +\
+ ((b) >> (16 - gx_cie_log2_cache_size)) )
+# else /* < 8 */
+# define byte2cache_index(b) ((b) >> (8 - gx_cie_log2_cache_size))
+# endif
+#endif
+ pconc[0] = rt_lookup(0, byte2cache_index(prtc[0]));
+ pconc[1] = rt_lookup(1, byte2cache_index(prtc[1]));
+ pconc[2] = rt_lookup(2, byte2cache_index(prtc[2]));
+ if (m > 3)
+ pconc[3] = rt_lookup(3, byte2cache_index(prtc[3]));
+#undef byte2cache_index
+ }
+
+#endif /* !CIE_RENDER_TABLE_INTERPOLATE */
+#undef ri
+#undef rt_lookup
+ return m;
+ }
+}
+
+/* ================ Utilities ================ */
+
+#define if_debug_vector3(str, vec)\
+ if_debug4('c', "%s[%g %g %g]\n", str, vec->u, vec->v, vec->w)
+#define if_debug_matrix3(str, mat)\
+ if_debug10('c', "%s[%g %g %g / %g %g %g / %g %g %g]\n", str,\
+ mat->cu.u, mat->cu.v, mat->cu.w, mat->cv.u, mat->cv.v, mat->cv.w,\
+ mat->cw.u, mat->cw.v, mat->cw.w)
+
+/* Multiply a vector by a matrix. */
+/* Note that we are computing M * V where v is a column vector. */
+private void
+cie_mult3(const gs_vector3 * in, register const gs_matrix3 * mat,
+ gs_vector3 * out)
+{
+ if_debug_vector3("[c]mult", in);
+ if_debug_matrix3(" *", mat);
+ {
+ float u = in->u, v = in->v, w = in->w;
+
+ out->u = (u * mat->cu.u) + (v * mat->cv.u) + (w * mat->cw.u);
+ out->v = (u * mat->cu.v) + (v * mat->cv.v) + (w * mat->cw.v);
+ out->w = (u * mat->cu.w) + (v * mat->cv.w) + (w * mat->cw.w);
+ }
+ if_debug_vector3(" =", out);
+}
+
+/* Multiply two matrices. We assume the result is not an alias for */
+/* either of the operands. Note that the composition of the transformations */
+/* M1 followed by M2 is M2 * M1, not M1 * M2. (See gscie.h for details.) */
+private void
+cie_matrix_mult3(const gs_matrix3 * ma, const gs_matrix3 * mb, gs_matrix3 * mc)
+{
+ if_debug_matrix3("[c]matrix_mult", ma);
+ if_debug_matrix3(" *", mb);
+ cie_mult3(&mb->cu, ma, &mc->cu);
+ cie_mult3(&mb->cv, ma, &mc->cv);
+ cie_mult3(&mb->cw, ma, &mc->cw);
+ cie_matrix_init(mc);
+ if_debug_matrix3(" =", mc);
+}
+
+/* Invert a matrix. */
+/* The output must not be an alias for the input. */
+private void
+cie_invert3(register const gs_matrix3 * in, register gs_matrix3 * out)
+{ /* This is a brute force algorithm; maybe there are better. */
+ /* We label the array elements */
+ /* [ A B C ] */
+ /* [ D E F ] */
+ /* [ G H I ] */
+#define A cu.u
+#define B cv.u
+#define C cw.u
+#define D cu.v
+#define E cv.v
+#define F cw.v
+#define G cu.w
+#define H cv.w
+#define I cw.w
+ double coA = in->E * in->I - in->F * in->H;
+ double coB = in->F * in->G - in->D * in->I;
+ double coC = in->D * in->H - in->E * in->G;
+ double det = in->A * coA + in->B * coB + in->C * coC;
+
+ if_debug_matrix3("[c]invert", in);
+ out->A = coA / det;
+ out->D = coB / det;
+ out->G = coC / det;
+ out->B = (in->C * in->H - in->B * in->I) / det;
+ out->E = (in->A * in->I - in->C * in->G) / det;
+ out->H = (in->B * in->G - in->A * in->H) / det;
+ out->C = (in->B * in->F - in->C * in->E) / det;
+ out->F = (in->C * in->D - in->A * in->F) / det;
+ out->I = (in->A * in->E - in->B * in->D) / det;
+ if_debug_matrix3(" =", out);
+#undef A
+#undef B
+#undef C
+#undef D
+#undef E
+#undef F
+#undef G
+#undef H
+#undef I
+ out->is_identity = in->is_identity;
+}
+
+/* Look up 3 values in a cache, with cached post-multiplication. */
+private void
+cie_lookup_mult3(cie_cached_vector3 * pvec, const gx_cie_vector_cache * pc /*[3] */ )
+{
+/****** Interpolating at intermediate stages doesn't seem to ******/
+/****** make things better, and slows things down, so.... ******/
+#ifdef CIE_INTERPOLATE_INTERMEDIATE
+ /* Interpolate between adjacent cache entries. */
+ /* This is expensive! */
+#ifdef CIE_CACHE_USE_FIXED
+# define lookup_interpolate_between(v0, v1, i, ftemp)\
+ cie_interpolate_between(v0, v1, i)
+#else
+ float ftu, ftv, ftw;
+
+# define lookup_interpolate_between(v0, v1, i, ftemp)\
+ ((v0) + ((v1) - (v0)) *\
+ ((ftemp = float_rshift(i, _cie_interpolate_bits)), ftemp - (int)ftemp))
+#endif
+
+ cie_cached_value iu =
+ lookup_index(pvec->u, pc, _cie_interpolate_bits);
+ const cie_cached_vector3 *pu =
+ &pc[0].vecs.values[(int)cie_cached_rshift(iu,
+ _cie_interpolate_bits)];
+ const cie_cached_vector3 *pu1 =
+ (iu >= (gx_cie_cache_size - 1) << _cie_interpolate_bits ?
+ pu : pu + 1);
+
+ cie_cached_value iv =
+ lookup_index(pvec->v, pc + 1, _cie_interpolate_bits);
+ const cie_cached_vector3 *pv =
+ &pc[1].vecs.values[(int)cie_cached_rshift(iv,
+ _cie_interpolate_bits)];
+ const cie_cached_vector3 *pv1 =
+ (iv >= (gx_cie_cache_size - 1) << _cie_interpolate_bits ?
+ pv : pv + 1);
+
+ cie_cached_value iw =
+ lookup_index(pvec->w, pc + 2, _cie_interpolate_bits);
+ const cie_cached_vector3 *pw =
+ &pc[2].vecs.values[(int)cie_cached_rshift(iw,
+ _cie_interpolate_bits)];
+ const cie_cached_vector3 *pw1 =
+ (iw >= (gx_cie_cache_size - 1) << _cie_interpolate_bits ?
+ pw : pw + 1);
+
+ pvec->u = lookup_interpolate_between(pu->u, pu1->u, iu, ftu) +
+ lookup_interpolate_between(pv->u, pv1->u, iv, ftv) +
+ lookup_interpolate_between(pw->u, pw1->u, iw, ftw);
+ pvec->v = lookup_interpolate_between(pu->v, pu1->v, iu, ftu) +
+ lookup_interpolate_between(pv->v, pv1->v, iv, ftv) +
+ lookup_interpolate_between(pw->v, pw1->v, iw, ftw);
+ pvec->w = lookup_interpolate_between(pu->w, pu1->w, iu, ftu) +
+ lookup_interpolate_between(pv->w, pv1->w, iv, ftv) +
+ lookup_interpolate_between(pw->w, pw1->w, iw, ftw);
+#else
+ const cie_cached_vector3 *pu = &lookup_value(pvec->u, pc);
+ const cie_cached_vector3 *pv = &lookup_value(pvec->v, pc + 1);
+ const cie_cached_vector3 *pw = &lookup_value(pvec->w, pc + 2);
+
+ pvec->u = pu->u + pv->u + pw->u;
+ pvec->v = pu->v + pv->v + pw->v;
+ pvec->w = pu->w + pv->w + pw->w;
+#endif
+}
+
+/* Set the is_identity flag that accelerates multiplication. */
+private void
+cie_matrix_init(register gs_matrix3 * mat)
+{
+ mat->is_identity =
+ mat->cu.u == 1.0 && is_fzero2(mat->cu.v, mat->cu.w) &&
+ mat->cv.v == 1.0 && is_fzero2(mat->cv.u, mat->cv.w) &&
+ mat->cw.w == 1.0 && is_fzero2(mat->cw.u, mat->cw.v);
+}
diff --git a/pstoraster/gscie.h b/pstoraster/gscie.h
new file mode 100644
index 000000000..8b8e3b736
--- /dev/null
+++ b/pstoraster/gscie.h
@@ -0,0 +1,688 @@
+/* Copyright (C) 1992, 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$ */
+/* Structures for CIE color algorithms */
+/* (requires gscspace.h, gscolor2.h) */
+
+#ifndef gscie_INCLUDED
+# define gscie_INCLUDED
+
+#include "gsrefct.h"
+#include "gsstruct.h" /* for extern_st */
+#include "gxctable.h"
+
+/* ---------------- Configuration parameters ---------------- */
+
+/* Define the size of the Encode/Decode/Transform procedure value caches. */
+/* With the current design, these caches must all have the same size. */
+#ifndef CIE_LOG2_CACHE_SIZE
+# define CIE_LOG2_CACHE_SIZE 9
+#endif
+
+/* Define whether to use fixed- or floating-point values in the caches. */
+/*#define CIE_CACHE_USE_FIXED */
+
+/* If we are using fixed-point values, define the number of fraction bits. */
+#define CIE_FIXED_FRACTION_BITS 12
+
+/* Define whether to interpolate between cached values. */
+#define CIE_CACHE_INTERPOLATE
+
+/* Define whether to interpolate at all intermediate lookup steps. */
+/* This is computationally expensive and doesn't seem to improve */
+/* the accuracy of the result. */
+/*#define CIE_INTERPOLATE_INTERMEDIATE */
+
+/* Define whether to interpolate in the RenderTable. */
+/* This is computationally very expensive, so it is normally disabled. */
+#define CIE_RENDER_TABLE_INTERPOLATE
+
+/* ------ Derived values ------ */
+
+/* from CIE_LOG2_CACHE_SIZE */
+#define gx_cie_log2_cache_size CIE_LOG2_CACHE_SIZE
+#define gx_cie_cache_size (1 << gx_cie_log2_cache_size)
+
+/* From CIE_FIXED_FRACTION_BITS 12 */
+#ifndef CIE_FIXED_FRACTION_BITS
+/* Take as many bits as we can without having to multiply in two pieces. */
+# define CIE_FIXED_FRACTION_BITS\
+ ((arch_sizeof_long * 8 - gx_cie_log2_cache_size) / 2 - 1)
+#endif
+
+/* From CIE_RENDER_TABLE_INTERPOLATE */
+#ifdef CIE_RENDER_TABLE_INTERPOLATE
+# define CIE_CACHE_INTERPOLATE
+#endif
+
+#define float_lshift(v, nb) ((v) * (1L << (nb)))
+#define float_rshift(v, nb) ((v) * (1.0 / (1L << (nb))))
+
+#ifdef CIE_CACHE_INTERPOLATE
+/* We have to have room for both a cache index and the interpolation bits */
+/* in a positive int (i.e., leaving 1 bit for the sign), plus a little slop. */
+/* The values for interpolation are cie_cached_values by default. */
+# define _cie_interpolate_bits\
+ min(arch_sizeof_int * 8 - gx_cie_log2_cache_size - 2, 10)
+# define _cix(i) ((i) >> _cie_interpolate_bits)
+# define _cif(i) ((int)(i) & ((1 << _cie_interpolate_bits) - 1))
+# define cie_interpolate_between(v0, v1, i)\
+ ((v0) + cie_cached_rshift(((v1) - (v0)) * _cif(i) +\
+ (1 << (_cie_interpolate_bits - 1)),\
+ _cie_interpolate_bits))
+# define cie_interpolate(p, i)\
+ cie_interpolate_between((p)[_cix(i)], (p)[_cix(i) + 1], i)
+# define cie_interpolate_fracs(p, i)\
+ ((p)[_cix(i)] + (frac)arith_rshift((long)((p)[_cix(i) + 1] - (p)[_cix(i)]) * _cif(i), _cie_interpolate_bits))
+#else
+# define _cie_interpolate_bits 0
+# define cie_interpolate_between(v0, v1, i) (v0)
+# define cie_interpolate(p, i) ((p)[i])
+# define cie_interpolate_fracs(p, i) ((p)[i])
+#endif
+
+#ifdef CIE_CACHE_USE_FIXED
+typedef long cie_cached_value;
+
+# define _cie_fixed_shift CIE_FIXED_FRACTION_BITS
+# define float2cie_cached(v)\
+ ((cie_cached_value)float_lshift(v, _cie_fixed_shift))
+# define cie_cached2float(v)\
+ float_rshift(v, _cie_fixed_shift)
+# define cie_cached2int(v, fbits)\
+ arith_rshift(v, _cie_fixed_shift - (fbits))
+/* We are multiplying two cie_cached_values to produce a result that */
+/* lies between 0 and gx_cie_cache_size - 1. If the intermediate result */
+/* might overflow, compute it in pieces (being a little sloppy). */
+# define _cie_product_excess_bits\
+ (_cie_fixed_shift * 2 + gx_cie_log2_cache_size - (arch_sizeof_long * 8 - 1))
+# define cie_cached_product2int(v, factor, fbits)\
+ (_cie_product_excess_bits > 0 ?\
+ arith_rshift( (v) * arith_rshift(factor, _cie_product_excess_bits) +\
+ arith_rshift(v, _cie_product_excess_bits) *\
+ ((factor) & ((1 << _cie_product_excess_bits) - 1)),\
+ _cie_fixed_shift * 2 - _cie_product_excess_bits - (fbits)) :\
+ arith_rshift((v) * (factor), _cie_fixed_shift * 2 - (fbits)))
+# define cie_cached_rshift(v, n) arith_rshift(v, n)
+#else
+typedef float cie_cached_value;
+# define float2cie_cached(v) (v)
+# define cie_cached2float(v) (v)
+# define cie_cached2int(v, fbits)\
+ ((int)float_lshift(v, fbits))
+# define cie_cached_product2int(v, factor, fbits)\
+ ((int)float_lshift((v) * (factor), fbits))
+# define cie_cached_rshift(v, n) float_rshift(v, n)
+#endif
+
+/* ---------------- Structures ---------------- */
+
+#ifndef gs_cie_render_DEFINED
+# define gs_cie_render_DEFINED
+typedef struct gs_cie_render_s gs_cie_render;
+#endif
+
+/* ------ Common definitions ------ */
+
+/*
+ * For the purposes of the CIE routines, we consider that all the vectors
+ * are column vectors, that the matrices are specified in column order
+ * (e.g., the matrix
+ * [ A B C ]
+ * [ D E F ]
+ * [ G H I ]
+ * is represented as [A D G B E H C F I]), and that to transform a vector
+ * V by a matrix M, we compute M * V to produce another column vector.
+ * Note in particular that in order to produce a matrix M that is
+ * equivalent to transforming by M1 and then by M2, we must compute
+ * M = M2 * M1.
+ */
+
+/* A 3-element vector. */
+typedef struct gs_vector3_s {
+ float u, v, w;
+} gs_vector3;
+
+/* A 3x3 matrix, stored in column order. */
+typedef struct gs_matrix3_s {
+ gs_vector3 cu, cv, cw;
+ bool is_identity;
+} gs_matrix3;
+
+/* 3- and 4-element vectors of ranges. */
+typedef struct gs_range_s {
+ float rmin, rmax;
+} gs_range;
+typedef struct gs_range3_s {
+ gs_range ranges[3];
+} gs_range3;
+typedef struct gs_range4_s {
+ gs_range ranges[4];
+} gs_range4;
+
+/* Client-supplied transformation procedures. */
+typedef struct gs_cie_common_s gs_cie_common;
+typedef struct gs_cie_wbsd_s gs_cie_wbsd;
+
+typedef float (*gs_cie_a_proc) (P2(floatp, const gs_cie_a *));
+
+typedef float (*gs_cie_abc_proc) (P2(floatp, const gs_cie_abc *));
+typedef struct gs_cie_abc_proc3_s {
+ gs_cie_abc_proc procs[3];
+} gs_cie_abc_proc3;
+
+typedef float (*gs_cie_def_proc) (P2(floatp, const gs_cie_def *));
+typedef struct gs_cie_def_proc3_s {
+ gs_cie_def_proc procs[3];
+} gs_cie_def_proc3;
+
+typedef float (*gs_cie_defg_proc) (P2(floatp, const gs_cie_defg *));
+typedef struct gs_cie_defg_proc4_s {
+ gs_cie_defg_proc procs[4];
+} gs_cie_defg_proc4;
+
+typedef float (*gs_cie_common_proc) (P2(floatp, const gs_cie_common *));
+typedef struct gs_cie_common_proc3_s {
+ gs_cie_common_proc procs[3];
+} gs_cie_common_proc3;
+
+typedef float (*gs_cie_render_proc) (P2(floatp, const gs_cie_render *));
+typedef struct gs_cie_render_proc3_s {
+ gs_cie_render_proc procs[3];
+} gs_cie_render_proc3;
+
+/*
+ * The TransformPQR procedure depends on both the color space and the
+ * CRD, so we can't simply pass it through the band list as a table of
+ * sampled values, even though such a table exists as part of an
+ * internal cache. Instead, we use two different approaches. The
+ * graphics library knows that the cache must be reloaded whenever the
+ * color space or CRD changes, so we can simply transmit the cached
+ * values through the band list whenever this occurs. However, this
+ * still leaves the issue of how to represent the procedure in the CRD
+ * per se: such a representation is required in order for
+ * currentcolorrendering and setcolorrendering to work. For this
+ * purpose, we provide a procedure name and procedure data, which
+ * drivers can supply with their default CRDs; the driver must also be
+ * prepared to map the procedure name back to an actual set of
+ * procedures.
+ *
+ * To simplify the driver-provided CRD machinery, we define TransformPQR as
+ * a single procedure taking an integer that specifies the component number,
+ * rather than an array of procedures. Note that if proc_name != 0,
+ * proc is irrelevant -- the driver will provide it by looking up proc_name.
+ * For this reason, the last argument of TransformPQR must be writable.
+ * Note also that since TransformPQR can fail (if the driver doesn't
+ * recognize the proc_name), it must return a failure code.
+ */
+typedef int (*gs_cie_transform_proc)(P5(int, floatp, const gs_cie_wbsd *,
+ gs_cie_render *, float *));
+typedef struct gs_cie_transform_proc3_s {
+ gs_cie_transform_proc proc;
+ const char *proc_name;
+ gs_const_string proc_data;
+ const char *driver_name; /* for mapping proc_name back to procs */
+} gs_cie_transform_proc3;
+
+typedef frac(*gs_cie_render_table_proc) (P2(byte, const gs_cie_render *));
+typedef struct gs_cie_render_table_procs_s {
+ gs_cie_render_table_proc procs[4];
+} gs_cie_render_table_procs;
+
+/* CIE white and black points. */
+typedef struct gs_cie_wb_s {
+ gs_vector3 WhitePoint;
+ gs_vector3 BlackPoint;
+} gs_cie_wb;
+
+/* ------ Caches ------ */
+
+/*
+ * Given that all the client-supplied procedures involved in CIE color
+ * mapping and rendering are monotonic, and given that we can determine
+ * the minimum and maximum input values for them, we can cache their values.
+ * This takes quite a lot of space, but eliminates the need for callbacks
+ * deep in the graphics code (particularly the image operator).
+ *
+ * The procedures, and how we determine their domains, are as follows:
+
+ Stage Name Domain determination
+ ----- ---- --------------------
+ pre-decode DecodeDEF RangeDEF
+ pre-decode DecodeDEFG RangeDEFG
+ color space DecodeA RangeA
+ color space DecodeABC RangeABC
+ color space DecodeLMN RangeLMN
+ rendering TransformPQR RangePQR
+ (but depends on color space White/BlackPoints)
+ rendering EncodeLMN RangePQR transformed by the inverse of
+ MatrixPQR and then by MatrixLMN
+ rendering EncodeABC RangeLMN transformed by MatrixABC
+ rendering RenderTable.T [0..1]*m
+
+ * Note that we can mostly cache the results of the color space procedures
+ * without knowing the color rendering parameters, and vice versa,
+ * because of the range parameters supplied in the dictionaries.
+ * Unfortunately, TransformPQR is an exception.
+ */
+/*
+ * The index into a cache is (value - base) * factor, where
+ * factor is computed as (cie_cache_size - 1) / (rmax - rmin).
+ */
+/*
+ * We have two kinds of caches: ordinary caches, where each value is
+ * a scalar, and vector caches, where each value is a gs_cached_vector3.
+ * The latter allow us to pre-multiply the values by one column of
+ * a gs_matrix3, avoiding multiplications at lookup time.
+ * Since we sometimes alias the two types of caches for access to
+ * the floats, values must come last.
+ */
+typedef struct cie_cache_params_s {
+ bool is_identity; /* must come first */
+ float base, factor;
+} cie_cache_params;
+typedef struct cie_cache_floats_s {
+ cie_cache_params params;
+ float values[gx_cie_cache_size];
+} cie_cache_floats;
+typedef struct cie_cache_fracs_s {
+ cie_cache_params params;
+ frac values[gx_cie_cache_size];
+} cie_cache_fracs;
+typedef struct cie_cache_ints_s {
+ cie_cache_params params;
+ int values[gx_cie_cache_size];
+} cie_cache_ints;
+typedef union gx_cie_scalar_cache_s {
+ cie_cache_floats floats;
+ cie_cache_fracs fracs;
+ cie_cache_ints ints;
+} gx_cie_scalar_cache;
+
+typedef struct cie_cached_vector3_s {
+ cie_cached_value u, v, w;
+} cie_cached_vector3;
+typedef struct cie_vector_cache_params_s {
+ bool is_identity; /* must come first */
+ cie_cached_value base, factor, limit;
+} cie_vector_cache_params;
+typedef struct cie_cache_vectors_s {
+ cie_vector_cache_params params; /* must come first for is_identity */
+ cie_cached_vector3 values[gx_cie_cache_size];
+} cie_cache_vectors;
+typedef union gx_cie_vector_cache_s {
+ cie_cache_floats floats;
+ cie_cache_vectors vecs;
+} gx_cie_vector_cache;
+
+/* ------ Color space dictionaries ------ */
+
+/* Elements common to all CIE color space dictionaries. */
+struct gs_cie_common_s {
+ int (*install_cspace) (P2(gs_color_space *, gs_state *));
+ void *client_data;
+ gs_range3 RangeLMN;
+ gs_cie_common_proc3 DecodeLMN;
+ gs_matrix3 MatrixLMN;
+ gs_cie_wb points;
+ /* Following are computed when structure is initialized. */
+ struct {
+ gx_cie_scalar_cache DecodeLMN[3];
+ } caches;
+};
+
+#define private_st_cie_common() /* in gscscie.c */\
+ gs_private_st_ptrs1(st_cie_common, gs_cie_common, "gs_cie_common",\
+ cie_common_enum_ptrs, cie_common_reloc_ptrs, client_data)
+
+#define gs_cie_common_elements\
+ gs_cie_common common; /* must be first */\
+ rc_header rc
+typedef struct gs_cie_common_elements_s {
+ gs_cie_common_elements;
+} gs_cie_common_elements_t;
+
+#define private_st_cie_common_elements() /* in gscscie.c */ \
+ gs_private_st_suffix_add0_local(st_cie_common_elements_t,\
+ gs_cie_common_elements_t,\
+ "gs_cie_common_elements_t",\
+ cie_common_enum_ptrs,\
+ cie_common_reloc_ptrs,\
+ st_cie_common)
+
+/* A CIEBasedA dictionary. */
+struct gs_cie_a_s {
+ gs_cie_common_elements; /* must be first */
+ gs_range RangeA;
+ gs_cie_a_proc DecodeA;
+ gs_vector3 MatrixA;
+ /* Following are computed when structure is initialized. */
+ struct {
+ gx_cie_vector_cache DecodeA; /* mult. by MatrixA */
+ } caches;
+};
+
+#define private_st_cie_a() /* in gscscie.c */\
+ gs_private_st_suffix_add0_local(st_cie_a, gs_cie_a, "gs_cie_a",\
+ cie_common_enum_ptrs,\
+ cie_common_reloc_ptrs,\
+ st_cie_common_elements_t)
+
+/* Common elements for CIEBasedABC, DEF, and DEFG dictionaries. */
+#define gs_cie_abc_elements\
+ gs_cie_common_elements; /* must be first */\
+ gs_range3 RangeABC;\
+ gs_cie_abc_proc3 DecodeABC;\
+ gs_matrix3 MatrixABC;\
+ /* Following are computed when structure is initialized. */\
+ struct {\
+ bool skipABC;\
+ gx_cie_vector_cache DecodeABC[3]; /* mult. by MatrixABC */\
+ } caches
+
+/* A CIEBasedABC dictionary. */
+struct gs_cie_abc_s {
+ gs_cie_abc_elements;
+};
+
+#define private_st_cie_abc() /* in gscscie.c */\
+ gs_private_st_suffix_add0_local(st_cie_abc, gs_cie_abc, "gs_cie_abc",\
+ cie_common_enum_ptrs, cie_common_reloc_ptrs,\
+ st_cie_common_elements_t)
+
+/* A CIEBasedDEF dictionary. */
+struct gs_cie_def_s {
+ gs_cie_abc_elements; /* must be first */
+ gs_range3 RangeDEF;
+ gs_cie_def_proc3 DecodeDEF;
+ gs_range3 RangeHIJ;
+ gx_color_lookup_table Table; /* [NH][NI * NJ * 3] */
+ struct {
+ gx_cie_scalar_cache DecodeDEF[3];
+ } caches_def;
+};
+
+#define private_st_cie_def() /* in gscscie.c */\
+ gs_private_st_suffix_add1(st_cie_def, gs_cie_def, "gs_cie_def",\
+ cie_def_enum_ptrs, cie_def_reloc_ptrs,\
+ st_cie_abc, Table.table)
+
+/* A CIEBasedDEFG dictionary. */
+struct gs_cie_defg_s {
+ gs_cie_abc_elements;
+ gs_range4 RangeDEFG;
+ gs_cie_defg_proc4 DecodeDEFG;
+ gs_range4 RangeHIJK;
+ gx_color_lookup_table Table; /* [NH * NI][NJ * NK * 3] */
+ struct {
+ gx_cie_scalar_cache DecodeDEFG[4];
+ } caches_defg;
+};
+
+#define private_st_cie_defg() /* in gscscie.c */\
+ gs_private_st_suffix_add1(st_cie_defg, gs_cie_defg, "gs_cie_defg",\
+ cie_defg_enum_ptrs, cie_defg_reloc_ptrs,\
+ st_cie_abc, Table.table)
+
+/*
+ * Default values for components. Note that for some components, there are
+ * two sets of default procedures: _default (identity procedures) and
+ * _from_cache (procedures that just return the cached values). Currently
+ * we only provide the latter for the Encode elements of the CRD.
+ */
+extern const gs_range3 Range3_default;
+extern const gs_range4 Range4_default;
+extern const gs_cie_defg_proc4 DecodeDEFG_default;
+extern const gs_cie_def_proc3 DecodeDEF_default;
+extern const gs_cie_abc_proc3 DecodeABC_default;
+extern const gs_cie_common_proc3 DecodeLMN_default;
+extern const gs_matrix3 Matrix3_default;
+extern const gs_range RangeA_default;
+extern const gs_cie_a_proc DecodeA_default;
+extern const gs_vector3 MatrixA_default;
+extern const gs_vector3 BlackPoint_default;
+extern const gs_cie_render_proc3 Encode_default;
+extern const gs_cie_render_proc3 EncodeLMN_from_cache;
+extern const gs_cie_render_proc3 EncodeABC_from_cache;
+extern const gs_cie_transform_proc3 TransformPQR_default;
+extern const gs_cie_transform_proc TransformPQR_lookup_proc_name;
+extern const gs_cie_render_table_procs RenderTableT_default;
+extern const gs_cie_render_table_procs RenderTableT_from_cache;
+
+/* ------ Rendering dictionaries ------ */
+
+struct gs_cie_wbsd_s {
+ struct {
+ gs_vector3 xyz, pqr;
+ } ws, bs, wd, bd;
+};
+typedef struct gs_cie_render_table_s {
+ /*
+ * If lookup.table == 0, the other members (of both lookup and T) are
+ * not set. If not 0, lookup.table points to an array of
+ * st_const_string_elements.
+ */
+ gx_color_lookup_table lookup;
+ gs_cie_render_table_procs T;
+} gs_cie_render_table_t;
+typedef enum {
+ CIE_RENDER_STATUS_BUILT,
+ CIE_RENDER_STATUS_INITED,
+ CIE_RENDER_STATUS_SAMPLED,
+ CIE_RENDER_STATUS_COMPLETED
+} cie_render_status_t;
+
+/* The main dictionary */
+struct gs_cie_render_s {
+ cie_render_status_t status;
+ rc_header rc;
+ void *client_data;
+ gs_cie_wb points;
+ gs_matrix3 MatrixPQR;
+ gs_range3 RangePQR;
+ gs_cie_transform_proc3 TransformPQR;
+ gs_matrix3 MatrixLMN;
+ gs_cie_render_proc3 EncodeLMN;
+ gs_range3 RangeLMN;
+ gs_matrix3 MatrixABC;
+ gs_cie_render_proc3 EncodeABC;
+ gs_range3 RangeABC;
+ gs_cie_render_table_t RenderTable;
+ /* Following are computed when structure is initialized. */
+ gs_range3 DomainLMN;
+ gs_range3 DomainABC;
+ gs_matrix3 MatrixABCEncode;
+ cie_cached_value EncodeABC_base[3];
+ gs_matrix3 MatrixPQR_inverse_LMN;
+ gs_vector3 wdpqr, bdpqr;
+ struct {
+ gx_cie_vector_cache EncodeLMN[3]; /* mult. by M'ABCEncode */
+ gx_cie_scalar_cache EncodeABC[3];
+ gx_cie_scalar_cache RenderTableT[4];
+ bool RenderTableT_is_identity;
+ } caches;
+};
+
+/* The CRD type is public only for a type test in zcrd.c. */
+extern_st(st_cie_render1);
+#define public_st_cie_render1() /* in gscrd.c */\
+ gs_public_st_composite(st_cie_render1, gs_cie_render, "gs_cie_render",\
+ cie_render1_enum_ptrs, cie_render1_reloc_ptrs)
+
+/* ------ Joint caches ------ */
+
+/* This cache depends on both the color space and the rendering */
+/* dictionary -- see above. */
+
+typedef struct gx_cie_joint_caches_s {
+ rc_header rc;
+ bool skipLMN;
+ gx_cie_vector_cache DecodeLMN[3]; /* mult. by dLMN_PQR */
+ gs_cie_wbsd points_sd;
+ gs_matrix3 MatrixLMN_PQR;
+ bool skipPQR;
+ gx_cie_vector_cache TransformPQR[3]; /* mult. by PQR_inverse_LMN */
+} gx_cie_joint_caches;
+
+#define private_st_joint_caches() /* in gscie.c */\
+ gs_private_st_simple(st_joint_caches, gx_cie_joint_caches,\
+ "gx_cie_joint_caches")
+
+/* ------ Internal procedures ------ */
+
+typedef struct gs_for_loop_params_s {
+ float init, step, limit;
+} gs_for_loop_params;
+void gs_cie_cache_init(P4(cie_cache_params *, gs_for_loop_params *,
+ const gs_range *, client_name_t));
+void gs_cie_cache_to_fracs(P1(gx_cie_scalar_cache *));
+void gs_cie_defg_complete(P1(gs_cie_defg *));
+void gs_cie_def_complete(P1(gs_cie_def *));
+void gs_cie_abc_complete(P1(gs_cie_abc *));
+void gs_cie_a_complete(P1(gs_cie_a *));
+gx_cie_joint_caches *gx_currentciecaches(P1(gs_state *));
+const gs_cie_common *gs_cie_cs_common(P1(gs_state *));
+int gs_cie_cs_complete(P2(gs_state *, bool));
+
+/*
+ * Compute the source and destination WhitePoint and BlackPoint for
+ * the TransformPQR procedure.
+ */
+int gs_cie_compute_wbsd(P4(gs_cie_wbsd * pwbsd,
+ const gs_vector3 * cs_WhitePoint,
+ const gs_vector3 * cs_BlackPoint,
+ const gs_cie_render * pcrd));
+
+/*
+ * Compute the derived values in a CRD that don't involve the cached
+ * procedure values, moving the CRD from "built" to "inited" status.
+ * If the CRD is already in "inited" or a later status, do nothing.
+ */
+int gs_cie_render_init(P1(gs_cie_render *));
+
+/*
+ * Sample the EncodeLMN, EncodeABC, and RenderTableT CRD procedures, and
+ * load the caches, moving the CRD from "inited" to "sampled" status.
+ * If the CRD is already in "sampled" or a later status, do nothing;
+ * otherwise, if the CRD is not in "inited" status, return an error.
+ */
+int gs_cie_render_sample(P1(gs_cie_render *));
+
+/*
+ * Finish preparing a CRD for installation, by restricting and/or
+ * transforming the cached procedure values, moving the CRD from "sampled"
+ * to "completed" status. If the CRD is already in "completed" status, do
+ * nothing; otherwise, if the CRD is not in "sampled" status, return an
+ * error.
+ */
+int gs_cie_render_complete(P1(gs_cie_render *));
+
+/* ---------------- Procedures ---------------- */
+
+/* ------ Constructors ------ */
+
+/*
+ * Note that these procedures take a client_data pointer as an operand. The
+ * client is responsible for allocating and deleting this object; the
+ * color space machinery does not take ownership of it.
+ *
+ * Note that these procedures set the reference count of the (large)
+ * parameter structures to 1, not 0. gs_setcolorspace will increment
+ * the reference count again, so unless you want the parameter structures
+ * to stay allocated permanently (or until a garbage collection),
+ * you should call cs_adjust_count(pcspace, -1). THIS IS A BUG IN THE API.
+ */
+extern int
+ gs_cspace_build_CIEA(P3(gs_color_space ** ppcspace, void *client_data,
+ gs_memory_t * pmem)),
+ gs_cspace_build_CIEABC(P3(gs_color_space ** ppcspace, void *client_data,
+ gs_memory_t * pmem)),
+ gs_cspace_build_CIEDEF(P3(gs_color_space ** ppcspace, void *client_data,
+ gs_memory_t * pmem)),
+ gs_cspace_build_CIEDEFG(P3(gs_color_space ** ppcspace, void *client_data,
+ gs_memory_t * pmem));
+
+/* ------ Accessors ------ */
+
+/*
+ * Note that the accessors depend heavily on "puns" between the variants
+ * of pcspace->params.{a,abc,def,defg}.
+ */
+
+/* Generic CIE based color space parameters */
+#define gs_cie_RangeLMN(pcspace) (&(pcspace)->params.a->common.RangeLMN)
+#define gs_cie_DecodeLMN(pcspace) (&(pcspace)->params.a->common.DecodeLMN)
+#define gs_cie_MatrixLMN(pcspace) (&(pcspace)->params.a->common.MatrixLMN)
+#define gs_cie_WhitePoint(pcspace)\
+ ((pcspace)->params.a->common.points.WhitePoint)
+#define gs_cie_BlackPoint(pcspace)\
+ ((pcspace)->params.a->common.points.BlackPoint)
+
+/* CIEBasedA color space */
+#define gs_cie_a_RangeA(pcspace) (&(pcspace)->params.a->RangeA)
+#define gs_cie_a_DecodeA(pcspace) (&(pcspace)->params.a->DecodeA)
+#define gs_cie_a_MatrixA(pcspace) (&(pcspace)->params.a->MatrixA)
+#define gs_cie_a_RangeA(pcspace) (&(pcspace)->params.a->RangeA)
+
+/* CIEBasedABC color space */
+/* Note that these also work for CIEBasedDEF[G] spaces. */
+#define gs_cie_abc_RangeABC(pcspace) (&(pcspace)->params.abc->RangeABC)
+#define gs_cie_abc_DecodeABC(pcspace) (&(pcspace)->params.abc->DecodeABC)
+#define gs_cie_abc_MatrixABC(pcspace) (&(pcspace)->params.abc->MatrixABC)
+
+/* CIDBasedDEF color space */
+#define gs_cie_def_RangeDEF(pcspace) (&(pcspace)->params.def->RangeDEF)
+#define gs_cie_def_DecodeDEF(pcspace) (&(pcspace)->params.def->DecodeDEF)
+#define gs_cie_def_RangeHIJ(pcspace) (&(pcspace)->params.def->RangeHIJ)
+
+/* CIDBasedDEFG color space */
+#define gs_cie_defg_RangeDEFG(pcspace) (&(pcspace)->params.defg->RangeDEFG)
+#define gs_cie_defg_DecodeDEFG(pcspace) (&(pcspace)->params.defg->DecodeDEFG)
+#define gs_cie_defg_RangeHIJK(pcspace) (&(pcspace)->params.defg->RangeHIJK)
+
+/*
+ * The following routine is provided so as to avoid explicitly exporting the
+ * CIEBasedDEF[G] color lookup table structure. It is doubtful any
+ * high-level clients will ever need to get this information.
+ *
+ * The caller must make sure the number of dimensions and strings provided
+ * are the number expected given the number of components in the color space.
+ * The procedure gs_color_space_num_components is available for this purpose.
+ *
+ * For a 3 component color space (CIEBasedDEF), ptable points to an array of
+ * pdims[0] gs_const_string structures, each of which is of length
+ * 3 * pdims[1] * pdims[2].
+ *
+ * For a 4 component color space (CIEBasedDEFG), ptable points to an array of
+ * pdims[0] * pdims[1] strings, each of which is of length
+ * 3 * pdims[2] * pdims[3].
+ *
+ * NB: the caller is responsible for deallocating the color table data
+ * when no longer needed. */
+extern int
+ gs_cie_defx_set_lookup_table(P3(gs_color_space * pcspace, int *pdims,
+ const gs_const_string * ptable));
+
+#endif /* gscie_INCLUDED */
diff --git a/pstoraster/gsclipsr.c b/pstoraster/gsclipsr.c
new file mode 100644
index 000000000..5d4cdabae
--- /dev/null
+++ b/pstoraster/gsclipsr.c
@@ -0,0 +1,45 @@
+/* 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$ */
+/* clipsave/cliprestore */
+#include "gx.h"
+#include "gserrors.h"
+#include "gsclipsr.h"
+
+/* clipsave */
+int
+gs_clipsave(gs_state *pgs)
+{
+ /****** NYI ******/
+ return_error(gs_error_undefined);
+}
+
+/* cliprestore */
+int
+gs_cliprestore(gs_state *pgs)
+{
+ /****** NYI ******/
+ return_error(gs_error_undefined);
+}
diff --git a/pstoraster/gsclipsr.h b/pstoraster/gsclipsr.h
new file mode 100644
index 000000000..17560637d
--- /dev/null
+++ b/pstoraster/gsclipsr.h
@@ -0,0 +1,34 @@
+/* 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 clipsave/cliprestore */
+
+#ifndef gsclipsr_INCLUDED
+# define gsclipsr_INCLUDED
+
+int gs_clipsave(P1(gs_state *));
+int gs_cliprestore(P1(gs_state *));
+
+#endif /* gsclipsr_INCLUDED */
diff --git a/pstoraster/gscolor.c b/pstoraster/gscolor.c
new file mode 100644
index 000000000..849035a06
--- /dev/null
+++ b/pstoraster/gscolor.c
@@ -0,0 +1,357 @@
+/* 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$ */
+/* Color and halftone operators for Ghostscript library */
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gsutil.h" /* for gs_next_ids */
+#include "gsccolor.h"
+#include "gxcspace.h"
+#include "gxdcconv.h"
+#include "gxdevice.h" /* for gx_color_index */
+#include "gxcmap.h"
+#include "gzstate.h"
+
+/* Imported from gsht.c */
+void gx_set_effective_transfer(P1(gs_state *));
+
+/* Structure descriptors */
+public_st_client_color();
+public_st_transfer_map();
+
+/* GC procedures */
+#define mptr ((gx_transfer_map *)vptr)
+private
+ENUM_PTRS_BEGIN(transfer_map_enum_ptrs) return 0;
+
+case 0:
+ENUM_RETURN((mptr->proc == 0 ? mptr->closure.data : 0));
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(transfer_map_reloc_ptrs)
+{
+ if (mptr->proc == 0)
+ RELOC_PTR(gx_transfer_map, closure.data);
+}
+RELOC_PTRS_END
+#undef mptr
+
+/* Initialize colors with 1, or 3, or 4 paint components. */
+/* (These are only used by setcolorspace.) */
+void
+gx_init_paint_1(gs_client_color * pcc, const gs_color_space * pcs)
+{
+ pcc->paint.values[0] = 0.0;
+}
+void
+gx_init_paint_3(gs_client_color * pcc, const gs_color_space * pcs)
+{
+ pcc->paint.values[2] = 0.0;
+ pcc->paint.values[1] = 0.0;
+ pcc->paint.values[0] = 0.0;
+}
+void
+gx_init_paint_4(gs_client_color * pcc, const gs_color_space * pcs)
+{
+ /* DeviceCMYK and CIEBasedDEFG spaces initialize to 0,0,0,1. */
+ pcc->paint.values[3] = 1.0;
+ gx_init_paint_3(pcc, pcs);
+}
+
+/* Force a value into the range [0.0..1.0]. */
+#define FORCE_UNIT(p) (p <= 0.0 ? 0.0 : p >= 1.0 ? 1.0 : p)
+
+/* Restrict colors with 1, 3, or 4 components to the range (0,1). */
+void
+gx_restrict01_paint_1(gs_client_color * pcc, const gs_color_space * pcs)
+{
+ pcc->paint.values[0] = FORCE_UNIT(pcc->paint.values[0]);
+}
+void
+gx_restrict01_paint_3(gs_client_color * pcc, const gs_color_space * pcs)
+{
+ pcc->paint.values[2] = FORCE_UNIT(pcc->paint.values[2]);
+ pcc->paint.values[1] = FORCE_UNIT(pcc->paint.values[1]);
+ pcc->paint.values[0] = FORCE_UNIT(pcc->paint.values[0]);
+}
+void
+gx_restrict01_paint_4(gs_client_color * pcc, const gs_color_space * pcs)
+{
+ pcc->paint.values[3] = FORCE_UNIT(pcc->paint.values[3]);
+ gx_restrict01_paint_3(pcc, pcs);
+}
+
+/* Null reference count adjustment procedure. */
+void
+gx_no_adjust_color_count(const gs_client_color * pcc,
+ const gs_color_space * pcs, int delta)
+{
+}
+
+/* Forward declarations */
+void load_transfer_map(P3(gs_state *, gx_transfer_map *, floatp));
+
+/* setgray */
+int
+gs_setgray(gs_state * pgs, floatp gray)
+{
+ if (pgs->in_cachedevice)
+ return_error(gs_error_undefined);
+ cs_adjust_counts(pgs, -1);
+ pgs->ccolor->paint.values[0] = FORCE_UNIT(gray);
+ pgs->color_space->type = &gs_color_space_type_DeviceGray;
+ gx_unset_dev_color(pgs);
+ return 0;
+}
+
+/* currentgray */
+float
+gs_currentgray(const gs_state * pgs)
+{
+ const gs_client_color *pcc = pgs->ccolor;
+ const gs_imager_state *const pis = (const gs_imager_state *)pgs;
+
+ switch (pgs->color_space->type->index) {
+ case gs_color_space_index_DeviceGray:
+ return pcc->paint.values[0];
+ case gs_color_space_index_DeviceRGB:
+ return frac2float(
+ color_rgb_to_gray(
+ float2frac(pcc->paint.values[0]),
+ float2frac(pcc->paint.values[1]),
+ float2frac(pcc->paint.values[2]),
+ pis));
+ case gs_color_space_index_DeviceCMYK:
+ return frac2float(
+ color_cmyk_to_gray(
+ float2frac(pcc->paint.values[0]),
+ float2frac(pcc->paint.values[1]),
+ float2frac(pcc->paint.values[2]),
+ float2frac(pcc->paint.values[3]),
+ pis));
+ default:
+ /*
+ * Might be another convertible color space, but this is rare,
+ * so we don't care about speed or (to some extent) accuracy.
+ */
+ {
+ float rgb[3];
+
+ gs_currentrgbcolor(pgs, rgb);
+ return frac2float(
+ color_rgb_to_gray(
+ float2frac(rgb[0]), float2frac(rgb[1]), float2frac(rgb[2]),
+ pis));
+ }
+ }
+}
+
+/* setrgbcolor */
+int
+gs_setrgbcolor(gs_state * pgs, floatp r, floatp g, floatp b)
+{
+ gs_client_color *pcc = pgs->ccolor;
+
+ if (pgs->in_cachedevice)
+ return_error(gs_error_undefined);
+ cs_adjust_counts(pgs, -1);
+ pcc->paint.values[0] = FORCE_UNIT(r);
+ pcc->paint.values[1] = FORCE_UNIT(g);
+ pcc->paint.values[2] = FORCE_UNIT(b);
+ pcc->pattern = 0; /* for GC */
+ pgs->color_space->type = &gs_color_space_type_DeviceRGB;
+ gx_unset_dev_color(pgs);
+ return 0;
+}
+
+/* currentrgbcolor */
+int
+gs_currentrgbcolor(const gs_state * pgs, float pr3[3])
+{
+ const gs_client_color *pcc = pgs->ccolor;
+ const gs_color_space *pcs = pgs->color_space;
+ const gs_color_space *pbcs = pcs;
+ const gs_imager_state *const pis = (const gs_imager_state *)pgs;
+ frac fcc[4];
+ gs_client_color cc;
+
+ sw:switch (pbcs->type->index) {
+ case gs_color_space_index_DeviceGray:
+ pr3[0] = pr3[1] = pr3[2] = pcc->paint.values[0];
+ return 0;
+ case gs_color_space_index_DeviceRGB:
+ pr3[0] = pcc->paint.values[0];
+ pr3[1] = pcc->paint.values[1];
+ pr3[2] = pcc->paint.values[2];
+ return 0;
+ case gs_color_space_index_DeviceCMYK:
+ color_cmyk_to_rgb(
+ float2frac(pcc->paint.values[0]),
+ float2frac(pcc->paint.values[1]),
+ float2frac(pcc->paint.values[2]),
+ float2frac(pcc->paint.values[3]),
+ pis, fcc);
+ pr3[0] = frac2float(fcc[0]);
+ pr3[1] = frac2float(fcc[1]);
+ pr3[2] = frac2float(fcc[2]);
+ return 0;
+ case gs_color_space_index_DeviceN:
+ case gs_color_space_index_Separation:
+ ds:if (cs_concrete_space(pbcs, pis) == pbcs)
+ break; /* not using alternative space */
+ /* (falls through) */
+ case gs_color_space_index_Indexed:
+ pbcs = gs_cspace_base_space(pbcs);
+ switch (pbcs->type->index) {
+ case gs_color_space_index_DeviceN:
+ case gs_color_space_index_Separation:
+ goto ds;
+ default: /* outer switch will catch undefined cases */
+ break;
+ }
+ if (cs_concretize_color(pcc, pcs, fcc, pis) < 0)
+ break;
+ cc.paint.values[0] = frac2float(fcc[0]);
+ cc.paint.values[1] = frac2float(fcc[1]);
+ cc.paint.values[2] = frac2float(fcc[2]);
+ cc.paint.values[3] = frac2float(fcc[3]);
+ pcc = &cc;
+ pcs = pbcs;
+ goto sw;
+ default:
+ break;
+ }
+ pr3[0] = pr3[1] = pr3[2] = 0.0;
+ return 0;
+}
+
+/* setnullcolor */
+int
+gs_setnullcolor(gs_state * pgs)
+{
+ if (pgs->in_cachedevice)
+ return_error(gs_error_undefined);
+ gs_setgray(pgs, 0.0); /* set color space to something harmless */
+ color_set_null(pgs->dev_color);
+ return 0;
+}
+
+/* settransfer */
+/* Remap=0 is used by the interpreter. */
+int
+gs_settransfer(gs_state * pgs, gs_mapping_proc tproc)
+{
+ return gs_settransfer_remap(pgs, tproc, true);
+}
+int
+gs_settransfer_remap(gs_state * pgs, gs_mapping_proc tproc, bool remap)
+{
+ gx_transfer_colored *ptran = &pgs->set_transfer.colored;
+
+ /*
+ * We can safely decrement the reference counts
+ * of the non-gray transfer maps, because
+ * if any of them get freed, the rc_unshare can't fail.
+ */
+ rc_decrement(ptran->red, "gs_settransfer");
+ rc_decrement(ptran->green, "gs_settransfer");
+ rc_decrement(ptran->blue, "gs_settransfer");
+ rc_unshare_struct(ptran->gray, gx_transfer_map, &st_transfer_map,
+ pgs->memory, goto fail, "gs_settransfer");
+ ptran->gray->proc = tproc;
+ ptran->gray->id = gs_next_ids(1);
+ ptran->red = ptran->gray;
+ ptran->green = ptran->gray;
+ ptran->blue = ptran->gray;
+ ptran->gray->rc.ref_count += 3;
+ if (remap) {
+ load_transfer_map(pgs, ptran->gray, 0.0);
+ gx_set_effective_transfer(pgs);
+ gx_unset_dev_color(pgs);
+ }
+ return 0;
+ fail:
+ rc_increment(ptran->red);
+ rc_increment(ptran->green);
+ rc_increment(ptran->blue);
+ return_error(gs_error_VMerror);
+}
+
+/* currenttransfer */
+gs_mapping_proc
+gs_currenttransfer(const gs_state * pgs)
+{
+ return pgs->set_transfer.colored.gray->proc;
+}
+
+/* ------ Non-operator routines ------ */
+
+/* Set device color = 1 for writing into the character cache. */
+void
+gx_set_device_color_1(gs_state * pgs)
+{
+ gx_device_color *pdc = pgs->dev_color;
+ gs_client_color *pcc = pgs->ccolor;
+
+ cs_adjust_counts(pgs, -1);
+ pcc->paint.values[0] = 0.0;
+ pcc->pattern = 0; /* for GC */
+ pgs->color_space->type = &gs_color_space_type_DeviceGray;
+ color_set_pure(pdc, 1);
+ pgs->log_op = lop_default;
+}
+
+/* ------ Internal routines ------ */
+
+/*
+ * Load one cached transfer map. We export this for gscolor1.c.
+ * Note that we must deal with both old (proc) and new (closure) maps.
+ */
+private float
+transfer_use_proc(floatp value, const gx_transfer_map * pmap,
+ const void *ignore_proc_data)
+{
+ return (*pmap->proc) (value, pmap);
+}
+void
+load_transfer_map(gs_state * pgs, gx_transfer_map * pmap, floatp min_value)
+{
+ gs_mapping_closure_proc_t proc =
+ (pmap->proc == 0 ? pmap->closure.proc : transfer_use_proc);
+ const void *proc_data = pmap->closure.data;
+ frac *values = pmap->values;
+ frac fmin = float2frac(min_value);
+ int i;
+
+ for (i = 0; i < transfer_map_size; i++) {
+ float fval =
+ (*proc) ((float)i / (transfer_map_size - 1), pmap, proc_data);
+
+ values[i] =
+ (fval < min_value ? fmin :
+ fval >= 1.0 ? frac_1 :
+ float2frac(fval));
+ }
+}
diff --git a/pstoraster/gscolor.h b/pstoraster/gscolor.h
new file mode 100644
index 000000000..b595a184b
--- /dev/null
+++ b/pstoraster/gscolor.h
@@ -0,0 +1,43 @@
+/* Copyright (C) 1991, 1992, 1993, 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$ */
+/* Client interface to color routines */
+
+#ifndef gscolor_INCLUDED
+# define gscolor_INCLUDED
+
+#include "gxtmap.h"
+
+/* Color and gray interface */
+int gs_setgray(P2(gs_state *, floatp));
+float gs_currentgray(P1(const gs_state *));
+int gs_setrgbcolor(P4(gs_state *, floatp, floatp, floatp)), gs_currentrgbcolor(P2(const gs_state *, float[3]));
+int gs_setnullcolor(P1(gs_state *));
+
+/* Transfer function */
+int gs_settransfer(P2(gs_state *, gs_mapping_proc)), gs_settransfer_remap(P3(gs_state *, gs_mapping_proc, bool));
+gs_mapping_proc gs_currenttransfer(P1(const gs_state *));
+
+#endif /* gscolor_INCLUDED */
diff --git a/pstoraster/gscolor1.c b/pstoraster/gscolor1.c
new file mode 100644
index 000000000..fa7c32697
--- /dev/null
+++ b/pstoraster/gscolor1.c
@@ -0,0 +1,271 @@
+/* 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$ */
+/* Level 1 extended color operators for Ghostscript library */
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gsutil.h" /* for gs_next_ids */
+#include "gsccolor.h"
+#include "gxcspace.h"
+#include "gxdcconv.h"
+#include "gxdevice.h" /* for gx_color_index */
+#include "gxcmap.h"
+#include "gzstate.h"
+#include "gscolor1.h"
+
+/* Imports from gscolor.c */
+void load_transfer_map(P3(gs_state *, gx_transfer_map *, floatp));
+
+/* Imported from gsht.c */
+void gx_set_effective_transfer(P1(gs_state *));
+
+/* Force a parameter into the range [0.0..1.0]. */
+#define FORCE_UNIT(p) (p < 0.0 ? 0.0 : p > 1.0 ? 1.0 : p)
+
+/* Define the CMYK color space type. */
+extern cs_proc_remap_color(gx_remap_DeviceCMYK);
+extern cs_proc_concretize_color(gx_concretize_DeviceCMYK);
+extern cs_proc_remap_concrete_color(gx_remap_concrete_DCMYK);
+const gs_color_space_type gs_color_space_type_DeviceCMYK = {
+ gs_color_space_index_DeviceCMYK, true, true,
+ &st_base_color_space, gx_num_components_4,
+ gx_no_base_space,
+ gx_init_paint_4, gx_restrict01_paint_4,
+ gx_same_concrete_space,
+ gx_concretize_DeviceCMYK, gx_remap_concrete_DCMYK,
+ gx_remap_DeviceCMYK, gx_no_install_cspace,
+ gx_no_adjust_cspace_count, gx_no_adjust_color_count
+};
+
+/* setcmykcolor */
+int
+gs_setcmykcolor(gs_state * pgs, floatp c, floatp m, floatp y, floatp k)
+{
+ gs_client_color *pcc = pgs->ccolor;
+
+ if (pgs->in_cachedevice)
+ return_error(gs_error_undefined);
+ cs_adjust_counts(pgs, -1);
+ pcc->paint.values[0] = FORCE_UNIT(c);
+ pcc->paint.values[1] = FORCE_UNIT(m);
+ pcc->paint.values[2] = FORCE_UNIT(y);
+ pcc->paint.values[3] = FORCE_UNIT(k);
+ pcc->pattern = 0; /* for GC */
+ pgs->color_space->type = &gs_color_space_type_DeviceCMYK;
+ gx_unset_dev_color(pgs);
+ return 0;
+}
+
+/* currentcmykcolor */
+int
+gs_currentcmykcolor(const gs_state * pgs, float pr4[4])
+{
+ const gs_client_color *pcc = pgs->ccolor;
+ const gs_color_space *pcs = pgs->color_space;
+ const gs_color_space *pbcs = pcs;
+ const gs_imager_state *const pis = (const gs_imager_state *)pgs;
+ frac fcc[4];
+ gs_client_color cc;
+
+ sw:switch (pbcs->type->index) {
+ case gs_color_space_index_DeviceGray:
+ pr4[0] = pr4[1] = pr4[2] = 0.0;
+ pr4[3] = 1.0 - pcc->paint.values[0];
+ return 0;
+ case gs_color_space_index_DeviceRGB:
+ color_rgb_to_cmyk(float2frac(pcc->paint.values[0]),
+ float2frac(pcc->paint.values[1]),
+ float2frac(pcc->paint.values[2]),
+ pis, fcc);
+ pr4[0] = frac2float(fcc[0]);
+ pr4[1] = frac2float(fcc[1]);
+ pr4[2] = frac2float(fcc[2]);
+ pr4[3] = frac2float(fcc[3]);
+ return 0;
+ case gs_color_space_index_DeviceCMYK:
+ pr4[0] = pcc->paint.values[0];
+ pr4[1] = pcc->paint.values[1];
+ pr4[2] = pcc->paint.values[2];
+ pr4[3] = pcc->paint.values[3];
+ return 0;
+ case gs_color_space_index_DeviceN:
+ case gs_color_space_index_Separation:
+ ds:if (cs_concrete_space(pbcs, pis) == pbcs)
+ break; /* not using alternative space */
+ /* (falls through) */
+ case gs_color_space_index_Indexed:
+ pbcs = gs_cspace_base_space(pbcs);
+ switch (pbcs->type->index) {
+ case gs_color_space_index_DeviceN:
+ case gs_color_space_index_Separation:
+ goto ds;
+ default: /* outer switch will catch undefined cases */
+ break;
+ }
+ if (cs_concretize_color(pcc, pcs, fcc, pis) < 0)
+ break;
+ cc.paint.values[0] = frac2float(fcc[0]);
+ cc.paint.values[1] = frac2float(fcc[1]);
+ cc.paint.values[2] = frac2float(fcc[2]);
+ cc.paint.values[3] = frac2float(fcc[3]);
+ pcc = &cc;
+ pcs = pbcs;
+ goto sw;
+ default:
+ break;
+ }
+ pr4[0] = pr4[1] = pr4[2] = 0.0;
+ pr4[3] = 1.0;
+ return 0;
+}
+
+/* setblackgeneration */
+/* Remap=0 is used by the interpreter. */
+int
+gs_setblackgeneration(gs_state * pgs, gs_mapping_proc proc)
+{
+ return gs_setblackgeneration_remap(pgs, proc, true);
+}
+int
+gs_setblackgeneration_remap(gs_state * pgs, gs_mapping_proc proc, bool remap)
+{
+ rc_unshare_struct(pgs->black_generation, gx_transfer_map,
+ &st_transfer_map, pgs->memory,
+ return_error(gs_error_VMerror),
+ "gs_setblackgeneration");
+ pgs->black_generation->proc = proc;
+ pgs->black_generation->id = gs_next_ids(1);
+ if (remap) {
+ load_transfer_map(pgs, pgs->black_generation, 0.0);
+ gx_unset_dev_color(pgs);
+ }
+ return 0;
+}
+
+/* currentblackgeneration */
+gs_mapping_proc
+gs_currentblackgeneration(const gs_state * pgs)
+{
+ return pgs->black_generation->proc;
+}
+
+/* setundercolorremoval */
+/* Remap=0 is used by the interpreter. */
+int
+gs_setundercolorremoval(gs_state * pgs, gs_mapping_proc proc)
+{
+ return gs_setundercolorremoval_remap(pgs, proc, true);
+}
+int
+gs_setundercolorremoval_remap(gs_state * pgs, gs_mapping_proc proc, bool remap)
+{
+ rc_unshare_struct(pgs->undercolor_removal, gx_transfer_map,
+ &st_transfer_map, pgs->memory,
+ return_error(gs_error_VMerror),
+ "gs_setundercolorremoval");
+ pgs->undercolor_removal->proc = proc;
+ pgs->undercolor_removal->id = gs_next_ids(1);
+ if (remap) {
+ load_transfer_map(pgs, pgs->undercolor_removal, -1.0);
+ gx_unset_dev_color(pgs);
+ }
+ return 0;
+}
+
+/* currentundercolorremoval */
+gs_mapping_proc
+gs_currentundercolorremoval(const gs_state * pgs)
+{
+ return pgs->undercolor_removal->proc;
+}
+
+/* setcolortransfer */
+/* Remap=0 is used by the interpreter. */
+int
+gs_setcolortransfer_remap(gs_state * pgs, gs_mapping_proc red_proc,
+ gs_mapping_proc green_proc,
+ gs_mapping_proc blue_proc,
+ gs_mapping_proc gray_proc, bool remap)
+{
+ gx_transfer_colored *ptran = &pgs->set_transfer.colored;
+ gx_transfer_colored old;
+ gs_id new_ids = gs_next_ids(4);
+
+ old = *ptran;
+ rc_unshare_struct(ptran->gray, gx_transfer_map, &st_transfer_map,
+ pgs->memory, goto fgray, "gs_setcolortransfer");
+ rc_unshare_struct(ptran->red, gx_transfer_map, &st_transfer_map,
+ pgs->memory, goto fred, "gs_setcolortransfer");
+ rc_unshare_struct(ptran->green, gx_transfer_map, &st_transfer_map,
+ pgs->memory, goto fgreen, "gs_setcolortransfer");
+ rc_unshare_struct(ptran->blue, gx_transfer_map, &st_transfer_map,
+ pgs->memory, goto fblue, "gs_setcolortransfer");
+ ptran->gray->proc = gray_proc;
+ ptran->gray->id = new_ids;
+ ptran->red->proc = red_proc;
+ ptran->red->id = new_ids + 1;
+ ptran->green->proc = green_proc;
+ ptran->green->id = new_ids + 2;
+ ptran->blue->proc = blue_proc;
+ ptran->blue->id = new_ids + 3;
+ if (remap) {
+ load_transfer_map(pgs, ptran->red, 0.0);
+ load_transfer_map(pgs, ptran->green, 0.0);
+ load_transfer_map(pgs, ptran->blue, 0.0);
+ load_transfer_map(pgs, ptran->gray, 0.0);
+ gx_set_effective_transfer(pgs);
+ gx_unset_dev_color(pgs);
+ }
+ return 0;
+ fblue:
+ rc_assign(ptran->green, old.green, "setcolortransfer");
+ fgreen:
+ rc_assign(ptran->red, old.red, "setcolortransfer");
+ fred:
+ rc_assign(ptran->gray, old.gray, "setcolortransfer");
+ fgray:
+ return_error(gs_error_VMerror);
+}
+int
+gs_setcolortransfer(gs_state * pgs, gs_mapping_proc red_proc,
+ gs_mapping_proc green_proc, gs_mapping_proc blue_proc,
+ gs_mapping_proc gray_proc)
+{
+ return gs_setcolortransfer_remap(pgs, red_proc, green_proc,
+ blue_proc, gray_proc, true);
+}
+
+/* currentcolortransfer */
+void
+gs_currentcolortransfer(const gs_state * pgs, gs_mapping_proc procs[4])
+{
+ const gx_transfer_colored *ptran = &pgs->set_transfer.colored;
+
+ procs[0] = ptran->red->proc;
+ procs[1] = ptran->green->proc;
+ procs[2] = ptran->blue->proc;
+ procs[3] = ptran->gray->proc;
+}
diff --git a/pstoraster/gscolor1.h b/pstoraster/gscolor1.h
new file mode 100644
index 000000000..9ced3e2d3
--- /dev/null
+++ b/pstoraster/gscolor1.h
@@ -0,0 +1,47 @@
+/* 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$ */
+/* Client interface to Level 1 extended color facilities */
+/* Requires gscolor.h */
+
+#ifndef gscolor1_INCLUDED
+# define gscolor1_INCLUDED
+
+/* Color and gray interface */
+int gs_setcmykcolor(P5(gs_state *, floatp, floatp, floatp, floatp)), gs_currentcmykcolor(P2(const gs_state *, float[4])),
+ gs_setblackgeneration(P2(gs_state *, gs_mapping_proc)), gs_setblackgeneration_remap(P3(gs_state *, gs_mapping_proc, bool));
+gs_mapping_proc gs_currentblackgeneration(P1(const gs_state *));
+int gs_setundercolorremoval(P2(gs_state *, gs_mapping_proc)), gs_setundercolorremoval_remap(P3(gs_state *, gs_mapping_proc, bool));
+gs_mapping_proc gs_currentundercolorremoval(P1(const gs_state *));
+
+/* Transfer function */
+int gs_setcolortransfer(P5(gs_state *, gs_mapping_proc /*red */ ,
+ gs_mapping_proc /*green */ , gs_mapping_proc /*blue */ ,
+ gs_mapping_proc /*gray */ )), gs_setcolortransfer_remap(P6(gs_state *, gs_mapping_proc /*red */ ,
+ gs_mapping_proc /*green */ , gs_mapping_proc /*blue */ ,
+ gs_mapping_proc /*gray */ , bool));
+void gs_currentcolortransfer(P2(const gs_state *, gs_mapping_proc[4]));
+
+#endif /* gscolor1_INCLUDED */
diff --git a/pstoraster/gscolor2.c b/pstoraster/gscolor2.c
new file mode 100644
index 000000000..f00cfceb3
--- /dev/null
+++ b/pstoraster/gscolor2.c
@@ -0,0 +1,455 @@
+/* Copyright (C) 1992, 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$ */
+/* Level 2 color operators for Ghostscript library */
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gxarith.h"
+#include "gxfixed.h" /* ditto */
+#include "gxmatrix.h" /* for gzstate.h */
+#include "gxcspace.h" /* for gscolor2.h */
+#include "gxcolor2.h"
+#include "gzstate.h"
+
+/* ---------------- General colors and color spaces ---------------- */
+
+/* setcolorspace */
+int
+gs_setcolorspace(gs_state * pgs, gs_color_space * pcs)
+{
+ int code;
+ gs_color_space cs_old;
+ gs_client_color cc_old;
+
+ if (pgs->in_cachedevice)
+ return_error(gs_error_undefined);
+ cs_old = *pgs->color_space;
+ cc_old = *pgs->ccolor;
+ (*pcs->type->adjust_cspace_count)(pcs, 1);
+ *pgs->color_space = *pcs;
+ if ((code = (*pcs->type->install_cspace)(pcs, pgs)) < 0)
+ goto rcs;
+ cs_full_init_color(pgs->ccolor, pcs);
+ (*cs_old.type->adjust_color_count)(&cc_old, &cs_old, -1);
+ (*cs_old.type->adjust_cspace_count)(&cs_old, -1);
+ gx_unset_dev_color(pgs);
+ return code;
+ /* Restore the color space if installation failed. */
+rcs:*pgs->color_space = cs_old;
+ (*pcs->type->adjust_cspace_count)(pcs, -1);
+ return code;
+}
+
+/* currentcolorspace */
+const gs_color_space *
+gs_currentcolorspace(const gs_state * pgs)
+{
+ return pgs->color_space;
+}
+
+/* setcolor */
+int
+gs_setcolor(gs_state * pgs, const gs_client_color * pcc)
+{
+ gs_color_space *pcs = pgs->color_space;
+
+ if (pgs->in_cachedevice)
+ return_error(gs_error_undefined);
+ (*pcs->type->adjust_color_count)(pcc, pcs, 1);
+ (*pcs->type->adjust_color_count)(pgs->ccolor, pcs, -1);
+ *pgs->ccolor = *pcc;
+ (*pcs->type->restrict_color)(pgs->ccolor, pcs);
+ gx_unset_dev_color(pgs);
+ return 0;
+}
+
+/* currentcolor */
+const gs_client_color *
+gs_currentcolor(const gs_state * pgs)
+{
+ return pgs->ccolor;
+}
+
+/* ------ Internal procedures ------ */
+
+/* GC descriptors */
+public_st_indexed_map();
+
+/* Free an indexed map and its values when the reference count goes to 0. */
+void
+free_indexed_map(gs_memory_t * pmem, void *pmap, client_name_t cname)
+{
+ gs_free_object(pmem, ((gs_indexed_map *) pmap)->values, cname);
+ gs_free_object(pmem, pmap, cname);
+}
+
+/*
+ * Allocate an indexed map for an Indexed or Separation color space.
+ */
+int
+alloc_indexed_map(gs_indexed_map ** ppmap, int nvals, gs_memory_t * pmem,
+ client_name_t cname)
+{
+ gs_indexed_map *pimap;
+
+ rc_alloc_struct_1(pimap, gs_indexed_map, &st_indexed_map, pmem,
+ return_error(gs_error_VMerror), cname);
+ pimap->values =
+ (float *)gs_alloc_byte_array(pmem, nvals, sizeof(float), cname);
+
+ if (pimap->values == 0) {
+ gs_free_object(pmem, pimap, cname);
+ return_error(gs_error_VMerror);
+ }
+ pimap->rc.free = free_indexed_map;
+ pimap->num_values = nvals;
+ *ppmap = pimap;
+ return 0;
+}
+
+/* ---------------- Indexed color spaces ---------------- */
+
+gs_private_st_composite(st_color_space_Indexed, gs_paint_color_space,
+ "gs_color_space_Indexed", cs_Indexed_enum_ptrs, cs_Indexed_reloc_ptrs);
+
+/* ------ Color space ------ */
+
+/* Define the Indexed color space type. */
+private cs_proc_base_space(gx_base_space_Indexed);
+private cs_proc_restrict_color(gx_restrict_Indexed);
+private cs_proc_concrete_space(gx_concrete_space_Indexed);
+private cs_proc_concretize_color(gx_concretize_Indexed);
+private cs_proc_install_cspace(gx_install_Indexed);
+private cs_proc_adjust_cspace_count(gx_adjust_cspace_Indexed);
+const gs_color_space_type gs_color_space_type_Indexed = {
+ gs_color_space_index_Indexed, false, false,
+ &st_color_space_Indexed, gx_num_components_1,
+ gx_base_space_Indexed,
+ gx_init_paint_1, gx_restrict_Indexed,
+ gx_concrete_space_Indexed,
+ gx_concretize_Indexed, NULL,
+ gx_default_remap_color, gx_install_Indexed,
+ gx_adjust_cspace_Indexed, gx_no_adjust_color_count
+};
+
+/* GC procedures. */
+
+#define pcs ((gs_color_space *)vptr)
+
+private
+ENUM_PTRS_BEGIN(cs_Indexed_enum_ptrs)
+{
+ return ENUM_USING(*pcs->params.indexed.base_space.type->stype,
+ &pcs->params.indexed.base_space,
+ sizeof(pcs->params.indexed.base_space), index - 1);
+}
+case 0:
+if (pcs->params.indexed.use_proc)
+ ENUM_RETURN((void *)pcs->params.indexed.lookup.map);
+else {
+ pcs->params.indexed.lookup.table.size =
+ (pcs->params.indexed.hival + 1) *
+ cs_num_components((const gs_color_space *)
+ &pcs->params.indexed.base_space);
+ ENUM_RETURN_CONST_STRING_PTR(gs_color_space,
+ params.indexed.lookup.table);
+}
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(cs_Indexed_reloc_ptrs)
+{
+ RELOC_USING(*pcs->params.indexed.base_space.type->stype,
+ &pcs->params.indexed.base_space,
+ sizeof(gs_base_color_space));
+ if (pcs->params.indexed.use_proc)
+ RELOC_PTR(gs_color_space, params.indexed.lookup.map);
+ else
+ RELOC_CONST_STRING_PTR(gs_color_space, params.indexed.lookup.table);
+}
+RELOC_PTRS_END
+
+#undef pcs
+
+/* Return the base space of an Indexed color space. */
+private const gs_color_space *
+gx_base_space_Indexed(const gs_color_space * pcs)
+{
+ return (const gs_color_space *)&(pcs->params.indexed.base_space);
+}
+
+/* Color space installation ditto. */
+
+private int
+gx_install_Indexed(gs_color_space * pcs, gs_state * pgs)
+{
+ return (*pcs->params.indexed.base_space.type->install_cspace)
+ ((gs_color_space *) & pcs->params.indexed.base_space, pgs);
+}
+
+/* Color space reference count adjustment ditto. */
+
+private void
+gx_adjust_cspace_Indexed(const gs_color_space * pcs, int delta)
+{
+ if (pcs->params.indexed.use_proc) {
+ rc_adjust_const(pcs->params.indexed.lookup.map, delta,
+ "gx_adjust_Indexed");
+ }
+ (*pcs->params.indexed.base_space.type->adjust_cspace_count)
+ ((const gs_color_space *)&pcs->params.indexed.base_space, delta);
+}
+
+/*
+ * Default palette mapping functions for indexed color maps. These just
+ * return the values already in the palette.
+ *
+ * For performance reasons, we provide four functions: special cases for 1,
+ * 3, and 4 entry palettes, and a general case. Note that these procedures
+ * do not range-check their input values.
+ */
+private int
+map_palette_entry_1(const gs_indexed_params * params, int indx, float *values)
+{
+ values[0] = params->lookup.map->values[indx];
+ return 0;
+}
+
+private int
+map_palette_entry_3(const gs_indexed_params * params, int indx, float *values)
+{
+ const float *pv = &(params->lookup.map->values[3 * indx]);
+
+ values[0] = pv[0];
+ values[1] = pv[1];
+ values[2] = pv[2];
+ return 0;
+}
+
+private int
+map_palette_entry_4(const gs_indexed_params * params, int indx, float *values)
+{
+ const float *pv = &(params->lookup.map->values[4 * indx]);
+
+ values[0] = pv[0];
+ values[1] = pv[1];
+ values[2] = pv[2];
+ values[3] = pv[3];
+ return 0;
+}
+
+private int
+map_palette_entry_n(const gs_indexed_params * params, int indx, float *values)
+{
+ int m = cs_num_components((const gs_color_space *)&params->base_space);
+
+ memcpy((void *)values,
+ (const void *)(params->lookup.map->values + indx * m),
+ m * sizeof(float)
+ );
+
+ return 0;
+}
+
+/*
+ * Allocate an indexed map to be used as a palette for indexed color space.
+ */
+private gs_indexed_map *
+alloc_indexed_palette(
+ const gs_color_space * pbase_cspace,
+ int nvals,
+ gs_memory_t * pmem
+)
+{
+ int num_comps = gs_color_space_num_components(pbase_cspace);
+ gs_indexed_map *pimap;
+ int code =
+ alloc_indexed_map(&pimap, nvals * num_comps, pmem,
+ "alloc_indexed_palette");
+
+ if (code < 0)
+ return 0;
+ if (num_comps == 1)
+ pimap->proc.lookup_index = map_palette_entry_1;
+ else if (num_comps == 3)
+ pimap->proc.lookup_index = map_palette_entry_3;
+ else if (num_comps == 4)
+ pimap->proc.lookup_index = map_palette_entry_4;
+ else
+ pimap->proc.lookup_index = map_palette_entry_n;
+ return pimap;
+}
+
+/*
+ * Build an indexed color space.
+ */
+int
+gs_cspace_build_Indexed(
+ gs_color_space ** ppcspace,
+ const gs_color_space * pbase_cspace,
+ uint num_entries,
+ const gs_const_string * ptbl,
+ gs_memory_t * pmem
+)
+{
+ gs_color_space *pcspace = 0;
+ gs_indexed_params *pindexed = 0;
+ int code;
+
+ if ((pbase_cspace == 0) || !pbase_cspace->type->can_be_base_space)
+ return_error(gs_error_rangecheck);
+
+ code = gs_cspace_alloc(&pcspace, &gs_color_space_type_Indexed, pmem);
+ if (code < 0)
+ return code;
+ pindexed = &(pcspace->params.indexed);
+ if (ptbl == 0) {
+ pindexed->lookup.map =
+ alloc_indexed_palette(pbase_cspace, num_entries, pmem);
+ if (pindexed->lookup.map == 0) {
+ gs_free_object(pmem, pcspace, "gs_cspace_build_Indexed");
+ return_error(gs_error_VMerror);
+ }
+ pindexed->use_proc = true;
+ } else {
+ pindexed->lookup.table = *ptbl;
+ pindexed->use_proc = false;
+ }
+ gs_cspace_init_from((gs_color_space *) & (pindexed->base_space),
+ pbase_cspace);
+ pindexed->hival = num_entries - 1;
+ *ppcspace = pcspace;
+ return 0;
+}
+
+/*
+ * Return the number of entries in an indexed color space.
+ */
+int
+gs_cspace_indexed_num_entries(const gs_color_space * pcspace)
+{
+ if (gs_color_space_get_index(pcspace) != gs_color_space_index_Indexed)
+ return 0;
+ return pcspace->params.indexed.hival + 1;
+}
+
+/*
+ * Get the palette for an indexed color space. This will return a null
+ * pointer if the color space is not an indexed color space or if the
+ * color space does not use the mapped index palette.
+ */
+float *
+gs_cspace_indexed_value_array(const gs_color_space * pcspace)
+{
+ if ((gs_color_space_get_index(pcspace) != gs_color_space_index_Indexed) ||
+ pcspace->params.indexed.use_proc
+ )
+ return 0;
+ return pcspace->params.indexed.lookup.map->values;
+}
+
+/*
+ * Set the lookup procedure to be used with an indexed color space.
+ */
+int
+gs_cspace_indexed_set_proc(
+ gs_color_space * pcspace,
+ int (*proc) (P3(const gs_indexed_params *, int, float *))
+)
+{
+ if ((gs_color_space_get_index(pcspace) != gs_color_space_index_Indexed) ||
+ !pcspace->params.indexed.use_proc
+ )
+ return_error(gs_error_rangecheck);
+ pcspace->params.indexed.lookup.map->proc.lookup_index = proc;
+ return 0;
+}
+
+/* ------ Colors ------ */
+
+/* Force an Indexed color into legal range. */
+
+private void
+gx_restrict_Indexed(gs_client_color * pcc, const gs_color_space * pcs)
+{
+ float value = pcc->paint.values[0];
+
+ pcc->paint.values[0] =
+ (is_fneg(value) ? 0 :
+ value >= pcs->params.indexed.hival ? pcs->params.indexed.hival :
+ value);
+}
+
+/* Color remapping for Indexed color spaces. */
+
+private const gs_color_space *
+gx_concrete_space_Indexed(const gs_color_space * pcs,
+ const gs_imager_state * pis)
+{
+ const gs_color_space *pbcs =
+ (const gs_color_space *)&pcs->params.indexed.base_space;
+
+ return cs_concrete_space(pbcs, pis);
+}
+
+private int
+gx_concretize_Indexed(const gs_client_color * pc, const gs_color_space * pcs,
+ frac * pconc, const gs_imager_state * pis)
+{
+ float value = pc->paint.values[0];
+ int index =
+ (is_fneg(value) ? 0 :
+ value >= pcs->params.indexed.hival ? pcs->params.indexed.hival :
+ (int)value);
+ gs_client_color cc;
+ const gs_color_space *pbcs =
+ (const gs_color_space *)&pcs->params.indexed.base_space;
+
+ if (pcs->params.indexed.use_proc) {
+ int code =
+ (*pcs->params.indexed.lookup.map->proc.lookup_index)
+ (&pcs->params.indexed, index, &cc.paint.values[0]);
+
+ if (code < 0)
+ return code;
+ } else {
+ int m = cs_num_components((const gs_color_space *)
+ &pcs->params.indexed.base_space);
+ const byte *pcomp =
+ pcs->params.indexed.lookup.table.data + m * index;
+
+ switch (m) {
+ default:
+ return_error(gs_error_rangecheck);
+ case 4:
+ cc.paint.values[3] = pcomp[3] * (1.0 / 255.0);
+ case 3:
+ cc.paint.values[2] = pcomp[2] * (1.0 / 255.0);
+ cc.paint.values[1] = pcomp[1] * (1.0 / 255.0);
+ case 1:
+ cc.paint.values[0] = pcomp[0] * (1.0 / 255.0);
+ }
+ }
+ return (*pbcs->type->concretize_color) (&cc, pbcs, pconc, pis);
+}
diff --git a/pstoraster/gscolor2.h b/pstoraster/gscolor2.h
new file mode 100644
index 000000000..3ae2aef14
--- /dev/null
+++ b/pstoraster/gscolor2.h
@@ -0,0 +1,106 @@
+/* Copyright (C) 1992, 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$ */
+/* Client interface to Level 2 color facilities */
+/* (requires gscspace.h, gsmatrix.h) */
+
+#ifndef gscolor2_INCLUDED
+# define gscolor2_INCLUDED
+
+#include "gsptype1.h"
+
+/* ---------------- Graphics state ---------------- */
+
+/*
+ * Note that setcolorspace and setcolor copy the (top level of) their
+ * structure argument, so if the client allocated it on the heap, the
+ * client should free it after setting it in the graphics state.
+ */
+
+/* General color routines */
+const gs_color_space *gs_currentcolorspace(P1(const gs_state *));
+int gs_setcolorspace(P2(gs_state *, gs_color_space *));
+const gs_client_color *gs_currentcolor(P1(const gs_state *));
+int gs_setcolor(P2(gs_state *, const gs_client_color *));
+
+/* CIE-specific routines */
+#ifndef gs_cie_render_DEFINED
+# define gs_cie_render_DEFINED
+typedef struct gs_cie_render_s gs_cie_render;
+#endif
+const gs_cie_render *gs_currentcolorrendering(P1(const gs_state *));
+int gs_setcolorrendering(P2(gs_state *, gs_cie_render *));
+
+/* ---------------- Indexed color space ---------------- */
+
+/*
+ * Indexed color spaces.
+ *
+ * If the color space will use a procedure rather than a byte table,
+ * ptbl should be set to 0.
+ *
+ * Unlike most of the other color space constructors, this one initializes
+ * some of the fields of the colorspace. In the case in which a string table
+ * is used for mapping, it initializes the entire structure. Note that the
+ * client is responsible for the table memory in that case; the color space
+ * will not free it when the color space itself is released.
+ *
+ * For the case of an indexed color space based on a procedure, a default
+ * procedure will be provided that simply echoes the color values already in
+ * the palette; the client may override these procedures by use of
+ * gs_cspace_indexed_set_proc. If the client wishes to insert values into
+ * the palette, it should do so by using gs_cspace_indexed_value_array, and
+ * directly inserting the desired values into the array.
+ *
+ * If the client does insert values into the palette directly, the default
+ * procedures provided by the client are fairly efficient, and there are
+ * few instances in which the client would need to replace them.
+ */
+extern int gs_cspace_build_Indexed(
+ gs_color_space ** ppcspace,
+ const gs_color_space * pbase_cspace,
+ uint num_entries,
+ const gs_const_string * ptbl,
+ gs_memory_t * pmem
+);
+
+/* Return the number of entries in the palette of an indexed color space. */
+extern int gs_cspace_indexed_num_entries(P1(
+ const gs_color_space * pcspace
+ ));
+
+/* In the case of a procedure-based indexed color space, get a pointer to */
+/* the array of cached values. */
+extern float *gs_cspace_indexed_value_array(P1(
+ const gs_color_space * pcspace
+ ));
+
+/* Set the lookup procedure to be used for an Indexed color space. */
+extern int gs_cspace_indexed_set_proc(P2(
+ gs_color_space * pcspace,
+ int (*proc) (P3(const gs_indexed_params *, int, float *))
+ ));
+
+#endif /* gscolor2_INCLUDED */
diff --git a/pstoraster/gscolor3.c b/pstoraster/gscolor3.c
new file mode 100644
index 000000000..980d21d4c
--- /dev/null
+++ b/pstoraster/gscolor3.c
@@ -0,0 +1,70 @@
+/* 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$ */
+/* "Operators" for LanguageLevel 3 color facilities */
+#include "gx.h"
+#include "gserrors.h"
+#include "gscspace.h" /* for gscolor2.h */
+#include "gsmatrix.h" /* for gscolor2.h */
+#include "gscolor2.h"
+#include "gscolor3.h"
+#include "gspath.h"
+#include "gzstate.h"
+#include "gxshade.h"
+
+/* setsmoothness */
+int
+gs_setsmoothness(gs_state * pgs, floatp smoothness)
+{
+ pgs->smoothness =
+ (smoothness < 0 ? 0 : smoothness > 1 ? 1 : smoothness);
+ return 0;
+}
+
+/* currentsmoothness */
+float
+gs_currentsmoothness(const gs_state * pgs)
+{
+ return pgs->smoothness;
+}
+
+/* shfill */
+int
+gs_shfill(gs_state * pgs, const gs_shading_t * psh)
+{
+ int code = gs_gsave(pgs);
+
+ if (code < 0)
+ return code;
+ if ((code = gs_setcolorspace(pgs, psh->params.ColorSpace)) < 0 ||
+ (code = gs_clippath(pgs)) < 0 ||
+ (code = gs_shading_fill_path(psh, pgs->path,
+ gs_currentdevice(pgs),
+ (gs_imager_state *)pgs)) < 0
+ )
+ DO_NOTHING;
+ gs_grestore(pgs);
+ return code;
+}
diff --git a/pstoraster/gscolor3.h b/pstoraster/gscolor3.h
new file mode 100644
index 000000000..a166ace5a
--- /dev/null
+++ b/pstoraster/gscolor3.h
@@ -0,0 +1,41 @@
+/* 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$ */
+/* Client interface to LanguageLevel 3 color facilities */
+
+#ifndef gscolor3_INCLUDED
+# define gscolor3_INCLUDED
+
+/* Smooth shading */
+#ifndef gs_shading_t_DEFINED
+# define gs_shading_t_DEFINED
+typedef struct gs_shading_s gs_shading_t;
+#endif
+
+int gs_setsmoothness(P2(gs_state *, floatp));
+float gs_currentsmoothness(P1(const gs_state *));
+int gs_shfill(P2(gs_state *, const gs_shading_t *));
+
+#endif /* gscolor3_INCLUDED */
diff --git a/pstoraster/gscompt.h b/pstoraster/gscompt.h
new file mode 100644
index 000000000..afaa3340a
--- /dev/null
+++ b/pstoraster/gscompt.h
@@ -0,0 +1,59 @@
+/* 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$ */
+/* Abstract types for compositing objects */
+
+#ifndef gscompt_INCLUDED
+# define gscompt_INCLUDED
+
+/*
+ * Compositing is the next-to-last step in the rendering pipeline.
+ * It occurs after color correction but before halftoning (if needed).
+ *
+ * gs_composite_t is the abstract superclass for compositing functions such
+ * as RasterOp functions or alpha-based compositing. Concrete subclasses
+ * must provide a default implementation (presumably based on
+ * get_bits_rectangle and copy_color) for devices that provide no optimized
+ * implementation of their own.
+ *
+ * A client that wants to produce composited output asks the target device
+ * to create an appropriate compositing device based on the target device
+ * and the gs_composite_t (and possibly other elements of the imager state).
+ * If the target device doesn't have its own implementation for the
+ * requested function, format, and state, it passes the buck to the
+ * gs_composite_t, which may make further tests for special cases before
+ * creating and returning a compositing device that uses the default
+ * implementation.
+ */
+typedef struct gs_composite_s gs_composite_t;
+
+/*
+ * To enable fast cache lookup and equality testing, compositing functions,
+ * like halftones, black generation functions, etc., carry a unique ID (time
+ * stamp).
+ */
+gs_id gs_composite_id(P1(const gs_composite_t * pcte));
+
+#endif /* gscompt_INCLUDED */
diff --git a/pstoraster/gscoord.c b/pstoraster/gscoord.c
new file mode 100644
index 000000000..2ff98f9c2
--- /dev/null
+++ b/pstoraster/gscoord.c
@@ -0,0 +1,507 @@
+/* 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$ */
+/* Coordinate system operators for Ghostscript library */
+#include "math_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsccode.h" /* for gxfont.h */
+#include "gxfarith.h"
+#include "gxfixed.h"
+#include "gxmatrix.h"
+#include "gxfont.h" /* for char_tm */
+#include "gxpath.h" /* for gx_path_translate */
+#include "gzstate.h"
+#include "gxcoord.h" /* requires gsmatrix, gsstate */
+#include "gxdevice.h"
+
+/* Choose whether to enable the rounding code in update_ctm. */
+#define ROUND_CTM_FIXED 1
+
+/* Forward declarations */
+#ifdef DEBUG
+#define trace_ctm(pgs) trace_matrix_fixed(&(pgs)->ctm)
+private void trace_matrix_fixed(P1(const gs_matrix_fixed *));
+private void trace_matrix(P1(const gs_matrix *));
+
+#endif
+
+/* Macro for ensuring ctm_inverse is valid */
+#ifdef DEBUG
+# define print_inverse(pgs)\
+ if ( gs_debug_c('x') )\
+ dlprintf("[x]Inverting:\n"), trace_ctm(pgs), trace_matrix(&pgs->ctm_inverse)
+#else
+# define print_inverse(pgs) DO_NOTHING
+#endif
+#define ensure_inverse_valid(pgs)\
+ if ( !pgs->ctm_inverse_valid )\
+ { int code = ctm_set_inverse(pgs);\
+ if ( code < 0 ) return code;\
+ }
+
+private int
+ctm_set_inverse(gs_state * pgs)
+{
+ int code = gs_matrix_invert(&ctm_only(pgs), &pgs->ctm_inverse);
+
+ print_inverse(pgs);
+ if (code < 0)
+ return code;
+ pgs->ctm_inverse_valid = true;
+ return 0;
+}
+
+/* Machinery for updating fixed version of ctm. */
+/*
+ * We (conditionally) adjust the floating point translation
+ * so that it exactly matches the (rounded) fixed translation.
+ * This avoids certain unpleasant rounding anomalies, such as
+ * 0 0 moveto currentpoint not returning 0 0, and () stringwidth
+ * not returning 0 0.
+ */
+#if ROUND_CTM_FIXED
+# define update_t_fixed(mat, t, t_fixed, v)\
+ (set_float2fixed_vars((mat).t_fixed, v),\
+ set_fixed2float_var((mat).t, (mat).t_fixed))
+#else /* !ROUND_CTM_FIXED */
+# define update_t_fixed(mat, t, t_fixed, v)\
+ ((mat).t = (v),\
+ set_float2fixed_vars((mat).t_fixed, (mat).t))
+#endif /* (!)ROUND_CTM_FIXED */
+#define f_fits_in_fixed(f) f_fits_in_bits(f, fixed_int_bits)
+#define update_matrix_fixed(mat, xt, yt)\
+ ((mat).txy_fixed_valid = (f_fits_in_fixed(xt) && f_fits_in_fixed(yt) ?\
+ (update_t_fixed(mat, tx, tx_fixed, xt),\
+ update_t_fixed(mat, ty, ty_fixed, yt), true) :\
+ ((mat).tx = (xt), (mat).ty = (yt), false)))
+#define update_ctm(pgs, xt, yt)\
+ (pgs->ctm_inverse_valid = false,\
+ pgs->char_tm_valid = false,\
+ update_matrix_fixed(pgs->ctm, xt, yt))
+
+/* ------ Coordinate system definition ------ */
+
+int
+gs_initmatrix(gs_state * pgs)
+{
+ gs_matrix imat;
+
+ gs_defaultmatrix(pgs, &imat);
+ update_ctm(pgs, imat.tx, imat.ty);
+ set_ctm_only(pgs, imat);
+#ifdef DEBUG
+ if (gs_debug_c('x'))
+ dlprintf("[x]initmatrix:\n"), trace_ctm(pgs);
+#endif
+ return 0;
+}
+
+int
+gs_defaultmatrix(const gs_state * pgs, gs_matrix * pmat)
+{
+ gx_device *dev;
+
+ if (pgs->ctm_default_set) { /* set after Install */
+ *pmat = pgs->ctm_default;
+ return 1;
+ }
+ dev = gs_currentdevice_inline(pgs);
+ gs_deviceinitialmatrix(dev, pmat);
+ /* Add in the translation for the Margins. */
+ pmat->tx += dev->Margins[0] *
+ dev->HWResolution[0] / dev->MarginsHWResolution[0];
+ pmat->ty += dev->Margins[1] *
+ dev->HWResolution[1] / dev->MarginsHWResolution[1];
+ return 0;
+}
+
+int
+gs_setdefaultmatrix(gs_state * pgs, const gs_matrix * pmat)
+{
+ if (pmat == NULL)
+ pgs->ctm_default_set = false;
+ else {
+ pgs->ctm_default = *pmat;
+ pgs->ctm_default_set = true;
+ }
+ return 0;
+}
+
+int
+gs_currentmatrix(const gs_state * pgs, gs_matrix * pmat)
+{
+ *pmat = ctm_only(pgs);
+ return 0;
+}
+
+/* Set the current transformation matrix for rendering text. */
+/* Note that this may be based on a font other than the current font. */
+int
+gs_setcharmatrix(gs_state * pgs, const gs_matrix * pmat)
+{
+ gs_matrix cmat;
+ int code = gs_matrix_multiply(pmat, &ctm_only(pgs), &cmat);
+
+ if (code < 0)
+ return code;
+ update_matrix_fixed(pgs->char_tm, cmat.tx, cmat.ty);
+ char_tm_only(pgs) = cmat;
+#ifdef DEBUG
+ if (gs_debug_c('x'))
+ dlprintf("[x]setting char_tm:"), trace_matrix_fixed(&pgs->char_tm);
+#endif
+ pgs->char_tm_valid = true;
+ return 0;
+}
+
+/* Read (after possibly computing) the current transformation matrix */
+/* for rendering text. If force=true, update char_tm if it is invalid; */
+/* if force=false, don't update char_tm, and return an error code. */
+int
+gs_currentcharmatrix(gs_state * pgs, gs_matrix * ptm, bool force)
+{
+ if (!pgs->char_tm_valid) {
+ int code;
+
+ if (!force)
+ return_error(gs_error_undefinedresult);
+ code = gs_setcharmatrix(pgs, &pgs->font->FontMatrix);
+ if (code < 0)
+ return code;
+ }
+ if (ptm != NULL)
+ *ptm = char_tm_only(pgs);
+ return 0;
+}
+
+int
+gs_setmatrix(gs_state * pgs, const gs_matrix * pmat)
+{
+ update_ctm(pgs, pmat->tx, pmat->ty);
+ set_ctm_only(pgs, *pmat);
+#ifdef DEBUG
+ if (gs_debug_c('x'))
+ dlprintf("[x]setmatrix:\n"), trace_ctm(pgs);
+#endif
+ return 0;
+}
+
+int
+gs_imager_setmatrix(gs_imager_state * pis, const gs_matrix * pmat)
+{
+ update_matrix_fixed(pis->ctm, pmat->tx, pmat->ty);
+ set_ctm_only(pis, *pmat);
+#ifdef DEBUG
+ if (gs_debug_c('x'))
+ dlprintf("[x]imager_setmatrix:\n"), trace_ctm(pis);
+#endif
+ return 0;
+}
+
+int
+gs_settocharmatrix(gs_state * pgs)
+{
+ if (pgs->char_tm_valid) {
+ pgs->ctm = pgs->char_tm;
+ pgs->ctm_inverse_valid = false;
+ return 0;
+ } else
+ return_error(gs_error_undefinedresult);
+}
+
+int
+gs_translate(gs_state * pgs, floatp dx, floatp dy)
+{
+ gs_point pt;
+ int code;
+
+ if ((code = gs_distance_transform(dx, dy, &ctm_only(pgs), &pt)) < 0)
+ return code;
+ pt.x += pgs->ctm.tx;
+ pt.y += pgs->ctm.ty;
+ update_ctm(pgs, pt.x, pt.y);
+#ifdef DEBUG
+ if (gs_debug_c('x'))
+ dlprintf4("[x]translate: %f %f -> %f %f\n",
+ dx, dy, pt.x, pt.y),
+ trace_ctm(pgs);
+#endif
+ return 0;
+}
+
+int
+gs_scale(gs_state * pgs, floatp sx, floatp sy)
+{
+ pgs->ctm.xx *= sx;
+ pgs->ctm.xy *= sx;
+ pgs->ctm.yx *= sy;
+ pgs->ctm.yy *= sy;
+ pgs->ctm_inverse_valid = false, pgs->char_tm_valid = false;
+#ifdef DEBUG
+ if (gs_debug_c('x'))
+ dlprintf2("[x]scale: %f %f\n", sx, sy), trace_ctm(pgs);
+#endif
+ return 0;
+}
+
+int
+gs_rotate(gs_state * pgs, floatp ang)
+{
+ int code = gs_matrix_rotate(&ctm_only(pgs), ang,
+ &ctm_only_writable(pgs));
+
+ pgs->ctm_inverse_valid = false, pgs->char_tm_valid = false;
+#ifdef DEBUG
+ if (gs_debug_c('x'))
+ dlprintf1("[x]rotate: %f\n", ang), trace_ctm(pgs);
+#endif
+ return code;
+}
+
+int
+gs_concat(gs_state * pgs, const gs_matrix * pmat)
+{
+ gs_matrix cmat;
+ int code = gs_matrix_multiply(pmat, &ctm_only(pgs), &cmat);
+
+ if (code < 0)
+ return code;
+ update_ctm(pgs, cmat.tx, cmat.ty);
+ set_ctm_only(pgs, cmat);
+#ifdef DEBUG
+ if (gs_debug_c('x'))
+ dlprintf("[x]concat:\n"), trace_matrix(pmat), trace_ctm(pgs);
+#endif
+ return code;
+}
+
+/* ------ Coordinate transformation ------ */
+
+#define is_skewed(pmat) (!(is_xxyy(pmat) || is_xyyx(pmat)))
+
+int
+gs_transform(gs_state * pgs, floatp x, floatp y, gs_point * pt)
+{
+ return gs_point_transform(x, y, &ctm_only(pgs), pt);
+}
+
+int
+gs_dtransform(gs_state * pgs, floatp dx, floatp dy, gs_point * pt)
+{
+ return gs_distance_transform(dx, dy, &ctm_only(pgs), pt);
+}
+
+int
+gs_itransform(gs_state * pgs, floatp x, floatp y, gs_point * pt)
+{ /* If the matrix isn't skewed, we get more accurate results */
+ /* by using transform_inverse than by using the inverse matrix. */
+ if (!is_skewed(&pgs->ctm)) {
+ return gs_point_transform_inverse(x, y, &ctm_only(pgs), pt);
+ } else {
+ ensure_inverse_valid(pgs);
+ return gs_point_transform(x, y, &pgs->ctm_inverse, pt);
+ }
+}
+
+int
+gs_idtransform(gs_state * pgs, floatp dx, floatp dy, gs_point * pt)
+{ /* If the matrix isn't skewed, we get more accurate results */
+ /* by using transform_inverse than by using the inverse matrix. */
+ if (!is_skewed(&pgs->ctm)) {
+ return gs_distance_transform_inverse(dx, dy,
+ &ctm_only(pgs), pt);
+ } else {
+ ensure_inverse_valid(pgs);
+ return gs_distance_transform(dx, dy, &pgs->ctm_inverse, pt);
+ }
+}
+
+int
+gs_imager_idtransform(const gs_imager_state * pis, floatp dx, floatp dy,
+ gs_point * pt)
+{
+ return gs_distance_transform_inverse(dx, dy, &ctm_only(pis), pt);
+}
+
+/* ------ For internal use only ------ */
+
+/* Set the translation to a fixed value, and translate any existing path. */
+/* Used by gschar.c to prepare for a BuildChar or BuildGlyph procedure. */
+int
+gx_translate_to_fixed(register gs_state * pgs, fixed px, fixed py)
+{
+ double fpx = fixed2float(px);
+ double fdx = fpx - pgs->ctm.tx;
+ double fpy = fixed2float(py);
+ double fdy = fpy - pgs->ctm.ty;
+ fixed dx, dy;
+ int code;
+
+ if (pgs->ctm.txy_fixed_valid) {
+ dx = float2fixed(fdx);
+ dy = float2fixed(fdy);
+ code = gx_path_translate(pgs->path, dx, dy);
+ if (code < 0)
+ return code;
+ if (pgs->char_tm_valid && pgs->char_tm.txy_fixed_valid)
+ pgs->char_tm.tx_fixed += dx,
+ pgs->char_tm.ty_fixed += dy;
+ } else {
+ if (!gx_path_is_null(pgs->path))
+ return_error(gs_error_limitcheck);
+ }
+ pgs->ctm.tx = fpx;
+ pgs->ctm.tx_fixed = px;
+ pgs->ctm.ty = fpy;
+ pgs->ctm.ty_fixed = py;
+ pgs->ctm.txy_fixed_valid = true;
+ pgs->ctm_inverse_valid = false;
+ if (pgs->char_tm_valid) { /* Update char_tm now, leaving it valid. */
+ pgs->char_tm.tx += fdx;
+ pgs->char_tm.ty += fdy;
+ }
+#ifdef DEBUG
+ if (gs_debug_c('x')) {
+ dlprintf2("[x]translate_to_fixed %g, %g:\n",
+ fixed2float(px), fixed2float(py));
+ trace_ctm(pgs);
+ dlprintf("[x] char_tm:\n");
+ trace_matrix_fixed(&pgs->char_tm);
+ }
+#endif
+ return 0;
+}
+
+/* Scale the CTM and character matrix for oversampling. */
+int
+gx_scale_char_matrix(register gs_state * pgs, int sx, int sy)
+{
+#define scale_cxy(s, vx, vy)\
+ if ( s != 1 )\
+ { pgs->ctm.vx *= s;\
+ pgs->ctm.vy *= s;\
+ pgs->ctm_inverse_valid = false;\
+ if ( pgs->char_tm_valid )\
+ { pgs->char_tm.vx *= s;\
+ pgs->char_tm.vy *= s;\
+ }\
+ }
+ scale_cxy(sx, xx, yx);
+ scale_cxy(sy, xy, yy);
+#undef scale_cxy
+ if_debug2('x', "[x]char scale: %d %d\n", sx, sy);
+ return 0;
+}
+
+/* Compute the coefficients for fast fixed-point distance transformations */
+/* from a transformation matrix. */
+/* We should cache the coefficients with the ctm.... */
+int
+gx_matrix_to_fixed_coeff(const gs_matrix * pmat, register fixed_coeff * pfc,
+ int max_bits)
+{
+ gs_matrix ctm;
+ int scale = -10000;
+ int expt, shift;
+
+ ctm = *pmat;
+ pfc->skewed = 0;
+ if (!is_fzero(ctm.xx)) {
+ discard(frexp(ctm.xx, &scale));
+ }
+ if (!is_fzero(ctm.xy)) {
+ discard(frexp(ctm.xy, &expt));
+ if (expt > scale)
+ scale = expt;
+ pfc->skewed = 1;
+ }
+ if (!is_fzero(ctm.yx)) {
+ discard(frexp(ctm.yx, &expt));
+ if (expt > scale)
+ scale = expt;
+ pfc->skewed = 1;
+ }
+ if (!is_fzero(ctm.yy)) {
+ discard(frexp(ctm.yy, &expt));
+ if (expt > scale)
+ scale = expt;
+ }
+ scale = sizeof(long) * 8 - 1 - max_bits - scale;
+
+ shift = scale - _fixed_shift;
+ if (shift > 0) {
+ pfc->shift = shift;
+ pfc->round = (fixed) 1 << (shift - 1);
+ } else {
+ pfc->shift = 0;
+ pfc->round = 0;
+ scale -= shift;
+ }
+#define set_c(c)\
+ if ( is_fzero(ctm.c) ) pfc->c.f = 0, pfc->c.l = 0;\
+ else pfc->c.f = ldexp(ctm.c, _fixed_shift), pfc->c.l = (long)ldexp(ctm.c, scale)
+ set_c(xx);
+ set_c(xy);
+ set_c(yx);
+ set_c(yy);
+#ifdef DEBUG
+ if (gs_debug_c('x')) {
+ dlprintf6("[x]ctm: [%6g %6g %6g %6g %6g %6g]\n",
+ ctm.xx, ctm.xy, ctm.yx, ctm.yy, ctm.tx, ctm.ty);
+ dlprintf6(" scale=%d fc: [0x%lx 0x%lx 0x%lx 0x%lx] shift=%d\n",
+ scale, pfc->xx.l, pfc->xy.l, pfc->yx.l, pfc->yy.l,
+ pfc->shift);
+ }
+#endif
+ pfc->max_bits = max_bits;
+ return 0;
+}
+
+/* ------ Debugging printout ------ */
+
+#ifdef DEBUG
+
+/* Print a matrix */
+private void
+trace_matrix_fixed(const gs_matrix_fixed * pmat)
+{
+ trace_matrix((const gs_matrix *)pmat);
+ if (pmat->txy_fixed_valid) {
+ dprintf2("\t\tt_fixed: [%6g %6g]\n",
+ fixed2float(pmat->tx_fixed),
+ fixed2float(pmat->ty_fixed));
+ } else {
+ dputs("\t\tt_fixed not valid\n");
+ }
+}
+private void
+trace_matrix(register const gs_matrix * pmat)
+{
+ dlprintf6("\t[%6g %6g %6g %6g %6g %6g]\n",
+ pmat->xx, pmat->xy, pmat->yx, pmat->yy, pmat->tx, pmat->ty);
+}
+
+#endif
diff --git a/pstoraster/gscoord.h b/pstoraster/gscoord.h
new file mode 100644
index 000000000..9933182cd
--- /dev/null
+++ b/pstoraster/gscoord.h
@@ -0,0 +1,55 @@
+/* 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$ */
+/* Requires gsmatrix.h and gsstate.h */
+
+#ifndef gscoord_INCLUDED
+# define gscoord_INCLUDED
+
+/* Coordinate system modification */
+int gs_initmatrix(P1(gs_state *)), gs_defaultmatrix(P2(const gs_state *, gs_matrix *)),
+ gs_currentmatrix(P2(const gs_state *, gs_matrix *)), gs_setmatrix(P2(gs_state *, const gs_matrix *)),
+ gs_translate(P3(gs_state *, floatp, floatp)), gs_scale(P3(gs_state *, floatp, floatp)),
+ gs_rotate(P2(gs_state *, floatp)), gs_concat(P2(gs_state *, const gs_matrix *));
+
+/* Extensions */
+int gs_setdefaultmatrix(P2(gs_state *, const gs_matrix *)), gs_currentcharmatrix(P3(gs_state *, gs_matrix *, bool)),
+ gs_setcharmatrix(P2(gs_state *, const gs_matrix *)), gs_settocharmatrix(P1(gs_state *));
+
+/* Coordinate transformation */
+int gs_transform(P4(gs_state *, floatp, floatp, gs_point *)), gs_dtransform(P4(gs_state *, floatp, floatp, gs_point *)),
+ gs_itransform(P4(gs_state *, floatp, floatp, gs_point *)), gs_idtransform(P4(gs_state *, floatp, floatp, gs_point *));
+
+#ifndef gs_imager_state_DEFINED
+# define gs_imager_state_DEFINED
+typedef struct gs_imager_state_s gs_imager_state;
+
+#endif
+
+int gs_imager_setmatrix(P2(gs_imager_state *, const gs_matrix *));
+int gs_imager_idtransform(P4(const gs_imager_state *, floatp, floatp,
+ gs_point *));
+
+#endif /* gscoord_INCLUDED */
diff --git a/pstoraster/gscparam.c b/pstoraster/gscparam.c
new file mode 100644
index 000000000..ba951411a
--- /dev/null
+++ b/pstoraster/gscparam.c
@@ -0,0 +1,480 @@
+/* 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$ */
+/* Default implementation of parameter lists */
+#include "memory_.h"
+#include "string_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsparam.h"
+#include "gsstruct.h"
+
+/* Forward references */
+typedef union c_param_value_s {
+ GS_PARAM_VALUE_UNION(gs_c_param_list);
+} gs_c_param_value;
+/*typedef struct gs_c_param_s gs_c_param; *//* in gsparam.h */
+
+/* Define the GC type for a parameter list. */
+private_st_c_param_list();
+
+/* Lengths corresponding to various gs_param_type_xxx types */
+const byte gs_param_type_sizes[] = {
+ GS_PARAM_TYPE_SIZES(sizeof(gs_c_param_list))
+};
+
+/* Lengths of *actual* data-containing type pointed to or contained by gs_param_type_xxx's */
+const byte gs_param_type_base_sizes[] = {
+ GS_PARAM_TYPE_BASE_SIZES(0)
+};
+
+/*
+ * Define a parameter list element. We use gs_param_type_any to identify
+ * elements that have been requested but not yet written. The reading
+ * procedures must recognize such elements as undefined, and ignore them.
+ */
+struct gs_c_param_s {
+ gs_c_param *next;
+ gs_param_name key;
+ gs_c_param_value value;
+ gs_param_type type;
+ void *alternate_typed_data;
+};
+
+/* Parameter values aren't really simple, */
+/* but since parameter lists are transient, it doesn't matter. */
+gs_private_st_ptrs2(st_c_param, gs_c_param, "gs_c_param",
+ c_param_enum_ptrs, c_param_reloc_ptrs, next, alternate_typed_data);
+
+/* ---------------- Utilities ---------------- */
+
+private gs_c_param *
+c_param_find(const gs_c_param_list * plist, gs_param_name pkey, bool any)
+{
+ gs_c_param *pparam = plist->head;
+
+ for (; pparam != 0; pparam = pparam->next)
+ if (!strcmp(pparam->key, pkey))
+ return (pparam->type != gs_param_type_any || any ? pparam : 0);
+ return 0;
+}
+
+/* ---------------- Writing parameters to a list ---------------- */
+
+private param_proc_begin_xmit_collection(c_param_begin_write_collection);
+private param_proc_end_xmit_collection(c_param_end_write_collection);
+private param_proc_xmit_typed(c_param_write_typed);
+private param_proc_request(c_param_request);
+private param_proc_requested(c_param_requested);
+private const gs_param_list_procs c_write_procs =
+{
+ c_param_write_typed,
+ c_param_begin_write_collection,
+ c_param_end_write_collection,
+ NULL, /* get_next_key */
+ c_param_request,
+ c_param_requested
+};
+
+/* Initialize a list for writing. */
+void
+gs_c_param_list_write(gs_c_param_list * plist, gs_memory_t * mem)
+{
+ plist->procs = &c_write_procs;
+ plist->memory = mem;
+ plist->head = 0;
+ plist->count = 0;
+ plist->any_requested = false;
+ plist->coll_type = gs_param_collection_dict_any;
+}
+
+/* Release a list. */
+void
+gs_c_param_list_release(gs_c_param_list * plist)
+{
+ gs_c_param *pparam;
+
+ while ((pparam = plist->head) != 0) {
+ gs_c_param *next = pparam->next;
+
+ switch (pparam->type) {
+ case gs_param_type_dict:
+ case gs_param_type_dict_int_keys:
+ case gs_param_type_array:
+ gs_c_param_list_release(&pparam->value.d);
+ break;
+ case gs_param_type_string:
+ case gs_param_type_name:
+ case gs_param_type_int_array:
+ case gs_param_type_float_array:
+ case gs_param_type_string_array:
+ case gs_param_type_name_array:
+ if (!pparam->value.s.persistent)
+ gs_free_object(plist->memory, (void *)pparam->value.s.data,
+ "gs_c_param_list_release data");
+ break;
+ default:
+ break;
+ }
+ gs_free_object(plist->memory, pparam->alternate_typed_data,
+ "gs_c_param_list_release alternate data");
+ gs_free_object(plist->memory, pparam,
+ "gs_c_param_list_release entry");
+ plist->head = next;
+ plist->count--;
+ }
+}
+
+/* Add an entry to a list. Doesn't set: value, type, plist->head. */
+private gs_c_param *
+c_param_add(gs_c_param_list * plist, gs_param_name pkey)
+{
+ gs_c_param *pparam =
+ gs_alloc_struct(plist->memory, gs_c_param, &st_c_param,
+ "c_param_write entry");
+
+ if (pparam == 0)
+ return 0;
+ pparam->next = plist->head;
+ pparam->key = pkey;
+ pparam->alternate_typed_data = 0;
+ return pparam;
+}
+
+/* Write a dynamically typed parameter to a list. */
+private int
+c_param_write(gs_c_param_list * plist, gs_param_name pkey, void *pvalue,
+ gs_param_type type)
+{
+ unsigned top_level_sizeof = 0;
+ unsigned second_level_sizeof = 0;
+ gs_c_param *pparam = c_param_add(plist, pkey);
+
+ if (pparam == 0)
+ return_error(gs_error_VMerror);
+ memcpy(&pparam->value, pvalue, gs_param_type_sizes[(int)type]);
+ pparam->type = type;
+
+ /* Need deeper copies of data if it's not persistent */
+ switch (type) {
+ gs_param_string const *curr_string;
+ gs_param_string const *end_string;
+
+ case gs_param_type_string_array:
+ case gs_param_type_name_array:
+ /* Determine how much mem needed to hold actual string data */
+ curr_string = pparam->value.sa.data;
+ end_string = curr_string + pparam->value.sa.size;
+ for (; curr_string < end_string; ++curr_string)
+ if (!curr_string->persistent)
+ second_level_sizeof += curr_string->size;
+ /* fall thru */
+
+ case gs_param_type_string:
+ case gs_param_type_name:
+ case gs_param_type_int_array:
+ case gs_param_type_float_array:
+ if (!pparam->value.s.persistent) { /* Allocate & copy object pointed to by array or string */
+ byte *top_level_memory;
+
+ top_level_sizeof =
+ pparam->value.s.size * gs_param_type_base_sizes[type];
+ top_level_memory =
+ gs_alloc_bytes_immovable(plist->memory,
+ top_level_sizeof + second_level_sizeof,
+ "c_param_write data");
+ if (top_level_memory == 0) {
+ gs_free_object(plist->memory, pparam, "c_param_write entry");
+ return_error(gs_error_VMerror);
+ }
+ memcpy(top_level_memory, pparam->value.s.data, top_level_sizeof);
+ pparam->value.s.data = top_level_memory;
+
+ /* String/name arrays need to copy actual str data */
+
+ if (second_level_sizeof > 0) {
+ byte *second_level_memory =
+ top_level_memory + top_level_sizeof;
+
+ curr_string = pparam->value.sa.data;
+ end_string = curr_string + pparam->value.sa.size;
+ for (; curr_string < end_string; ++curr_string)
+ if (!curr_string->persistent) {
+ memcpy(second_level_memory,
+ curr_string->data, curr_string->size);
+ ((gs_param_string *) curr_string)->data
+ = second_level_memory;
+ second_level_memory += curr_string->size;
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ plist->head = pparam;
+ plist->count++;
+ return 0;
+}
+
+/* Individual writing routines. */
+private int
+c_param_begin_write_collection(gs_param_list * plist, gs_param_name pkey,
+ gs_param_dict * pvalue, gs_param_collection_type_t coll_type)
+{
+ gs_c_param_list *const cplist = (gs_c_param_list *)plist;
+ gs_c_param_list *dlist =
+ gs_alloc_struct(cplist->memory, gs_c_param_list, &st_c_param_list,
+ "c_param_begin_write_collection");
+
+ if (dlist == 0)
+ return_error(gs_error_VMerror);
+ gs_c_param_list_write(dlist, cplist->memory);
+ dlist->coll_type = coll_type;
+ pvalue->list = (gs_param_list *) dlist;
+ return 0;
+}
+private int
+c_param_end_write_collection(gs_param_list * plist, gs_param_name pkey,
+ gs_param_dict * pvalue)
+{
+ gs_c_param_list *const cplist = (gs_c_param_list *)plist;
+ gs_c_param_list *dlist = (gs_c_param_list *) pvalue->list;
+
+ return c_param_write(cplist, pkey, pvalue->list,
+ (dlist->coll_type == gs_param_collection_dict_int_keys ?
+ gs_param_type_dict_int_keys :
+ dlist->coll_type == gs_param_collection_array ?
+ gs_param_type_array : gs_param_type_dict));
+}
+private int
+c_param_write_typed(gs_param_list * plist, gs_param_name pkey,
+ gs_param_typed_value * pvalue)
+{
+ gs_c_param_list *const cplist = (gs_c_param_list *)plist;
+ gs_param_collection_type_t coll_type;
+
+ switch (pvalue->type) {
+ case gs_param_type_dict:
+ coll_type = gs_param_collection_dict_any;
+ break;
+ case gs_param_type_dict_int_keys:
+ coll_type = gs_param_collection_dict_int_keys;
+ break;
+ case gs_param_type_array:
+ coll_type = gs_param_collection_array;
+ break;
+ default:
+ return c_param_write(cplist, pkey, &pvalue->value, pvalue->type);
+ }
+ return c_param_begin_write_collection
+ (plist, pkey, &pvalue->value.d, coll_type);
+}
+
+/* Other procedures */
+
+private int
+c_param_request(gs_param_list * plist, gs_param_name pkey)
+{
+ gs_c_param_list *const cplist = (gs_c_param_list *)plist;
+ gs_c_param *pparam;
+
+ cplist->any_requested = true;
+ if (c_param_find(cplist, pkey, true))
+ return 0;
+ pparam = c_param_add(cplist, pkey);
+ if (pparam == 0)
+ return_error(gs_error_VMerror);
+ pparam->type = gs_param_type_any; /* mark as undefined */
+ cplist->head = pparam;
+ return 0;
+}
+
+private int
+c_param_requested(const gs_param_list * plist, gs_param_name pkey)
+{
+ const gs_c_param_list *const cplist = (const gs_c_param_list *)plist;
+
+ return (!cplist->any_requested ? -1 :
+ c_param_find(cplist, pkey, true) != 0);
+}
+
+/* ---------------- Reading from a list to parameters ---------------- */
+
+private param_proc_begin_xmit_collection(c_param_begin_read_collection);
+private param_proc_end_xmit_collection(c_param_end_read_collection);
+private param_proc_xmit_typed(c_param_read_typed);
+private param_proc_next_key(c_param_get_next_key);
+private param_proc_get_policy(c_param_read_get_policy);
+private param_proc_signal_error(c_param_read_signal_error);
+private param_proc_commit(c_param_read_commit);
+private const gs_param_list_procs c_read_procs =
+{
+ c_param_read_typed,
+ c_param_begin_read_collection,
+ c_param_end_read_collection,
+ c_param_get_next_key,
+ NULL, /* request, N/A */
+ NULL, /* requested, N/A */
+ c_param_read_get_policy,
+ c_param_read_signal_error,
+ c_param_read_commit
+};
+
+/* Switch a list from writing to reading. */
+void
+gs_c_param_list_read(gs_c_param_list * plist)
+{
+ plist->procs = &c_read_procs;
+}
+
+/* Generic routine for reading a parameter from a list. */
+
+private int
+c_param_read_typed(gs_param_list * plist, gs_param_name pkey,
+ gs_param_typed_value * pvalue)
+{
+ gs_c_param_list *const cplist = (gs_c_param_list *)plist;
+ gs_param_type req_type = pvalue->type;
+ gs_c_param *pparam = c_param_find(cplist, pkey, false);
+ int code;
+
+ if (pparam == 0)
+ return 1;
+ pvalue->type = pparam->type;
+ switch (pvalue->type) {
+ case gs_param_type_dict:
+ case gs_param_type_dict_int_keys:
+ case gs_param_type_array:
+ gs_c_param_list_read(&pparam->value.d);
+ pvalue->value.d.list = (gs_param_list *) & pparam->value.d;
+ pvalue->value.d.size = pparam->value.d.count;
+ return 0;
+ default:
+ break;
+ }
+ memcpy(&pvalue->value, &pparam->value,
+ gs_param_type_sizes[(int)pparam->type]);
+ code = param_coerce_typed(pvalue, req_type, NULL);
+/****** SHOULD LET param_coerce_typed DO THIS ******/
+ if (code == gs_error_typecheck &&
+ req_type == gs_param_type_float_array &&
+ pvalue->type == gs_param_type_int_array
+ ) {
+ /* Convert int array to float dest */
+ gs_param_float_array fa;
+ int element;
+
+ fa.size = pparam->value.ia.size;
+ fa.persistent = false;
+
+ if (pparam->alternate_typed_data == 0) {
+ if ((pparam->alternate_typed_data
+ = (void *)gs_alloc_bytes_immovable(cplist->memory,
+ fa.size * sizeof(float),
+ "gs_c_param_read alternate float array")) == 0)
+ return_error(gs_error_VMerror);
+
+ for (element = 0; element < fa.size; ++element)
+ ((float *)(pparam->alternate_typed_data))[element]
+ = (float)pparam->value.ia.data[element];
+ }
+ fa.data = (float *)pparam->alternate_typed_data;
+
+ pvalue->value.fa = fa;
+ return 0;
+ }
+ return code;
+}
+
+/* Individual reading routines. */
+private int
+c_param_begin_read_collection(gs_param_list * plist, gs_param_name pkey,
+ gs_param_dict * pvalue, gs_param_collection_type_t coll_type)
+{
+ gs_c_param_list *const cplist = (gs_c_param_list *)plist;
+ gs_c_param *pparam = c_param_find(cplist, pkey, false);
+
+ if (pparam == 0)
+ return 1;
+ switch (pparam->type) {
+ case gs_param_type_dict:
+ if (coll_type != gs_param_collection_dict_any)
+ return_error(gs_error_typecheck);
+ break;
+ case gs_param_type_dict_int_keys:
+ if (coll_type == gs_param_collection_array)
+ return_error(gs_error_typecheck);
+ break;
+ case gs_param_type_array:
+ break;
+ default:
+ return_error(gs_error_typecheck);
+ }
+ gs_c_param_list_read(&pparam->value.d);
+ pvalue->list = (gs_param_list *) & pparam->value.d;
+ pvalue->size = pparam->value.d.count;
+ return 0;
+}
+private int
+c_param_end_read_collection(gs_param_list * plist, gs_param_name pkey,
+ gs_param_dict * pvalue)
+{
+ return 0;
+}
+
+/* Other procedures */
+private int /* ret 0 ok, 1 if EOF, or -ve err */
+c_param_get_next_key(gs_param_list * plist, gs_param_enumerator_t * penum,
+ gs_param_key_t * key)
+{
+ gs_c_param_list *const cplist = (gs_c_param_list *)plist;
+ gs_c_param *pparam =
+ (penum->pvoid ? ((gs_c_param *) (penum->pvoid))->next :
+ cplist->head);
+
+ if (pparam == 0)
+ return 1;
+ penum->pvoid = pparam;
+ key->data = (const byte *)pparam->key; /* was const char * */
+ key->size = strlen(pparam->key);
+ return 0;
+}
+private int
+c_param_read_get_policy(gs_param_list * plist, gs_param_name pkey)
+{
+ return gs_param_policy_ignore;
+}
+private int
+c_param_read_signal_error(gs_param_list * plist, gs_param_name pkey, int code)
+{
+ return code;
+}
+private int
+c_param_read_commit(gs_param_list * plist)
+{
+ return 0;
+}
diff --git a/pstoraster/gscpixel.c b/pstoraster/gscpixel.c
new file mode 100644
index 000000000..82212d2db
--- /dev/null
+++ b/pstoraster/gscpixel.c
@@ -0,0 +1,89 @@
+/* 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$ */
+/* DevicePixel color space and operation definition */
+#include "gx.h"
+#include "gserrors.h"
+#include "gsrefct.h"
+#include "gxcspace.h"
+#include "gscpixel.h"
+#include "gxdevice.h"
+
+/* Define the DevicePixel color space type. */
+private cs_proc_restrict_color(gx_restrict_DevicePixel);
+private cs_proc_remap_concrete_color(gx_remap_concrete_DevicePixel);
+private cs_proc_concretize_color(gx_concretize_DevicePixel);
+private const gs_color_space_type gs_color_space_type_DevicePixel = {
+ gs_color_space_index_DevicePixel, true, false,
+ &st_base_color_space, gx_num_components_1,
+ gx_no_base_space,
+ gx_init_paint_1, gx_restrict_DevicePixel,
+ gx_same_concrete_space,
+ gx_concretize_DevicePixel, gx_remap_concrete_DevicePixel,
+ gx_default_remap_color, gx_no_install_cspace,
+ gx_no_adjust_cspace_count, gx_no_adjust_color_count
+};
+
+/* Create a DevicePixel color space. */
+void
+gs_cs_init_DevicePixel(gs_color_space * pcs, int depth)
+{
+ pcs->type = &gs_color_space_type_DevicePixel;
+ pcs->params.pixel.depth = depth;
+}
+
+/* ------ Internal routines ------ */
+
+/* Force a DevicePixel color into legal range. */
+private void
+gx_restrict_DevicePixel(gs_client_color * pcc, const gs_color_space * pcs)
+{
+ /****** NOT ENOUGH BITS IN float OR frac ******/
+ floatp pixel = pcc->paint.values[0];
+ ulong max_value = (1L << pcs->params.pixel.depth) - 1;
+
+ pcc->paint.values[0] = (pixel < 0 ? 0 : min(pixel, max_value));
+}
+
+
+/* Remap a DevicePixel color. */
+
+private int
+gx_concretize_DevicePixel(const gs_client_color * pc, const gs_color_space * pcs,
+ frac * pconc, const gs_imager_state * pis)
+{
+ /****** NOT ENOUGH BITS IN float OR frac ******/
+ pconc[0] = (frac) (ulong) pc->paint.values[0];
+ return 0;
+}
+
+private int
+gx_remap_concrete_DevicePixel(const frac * pconc,
+ gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
+ gs_color_select_t select)
+{
+ color_set_pure(pdc, pconc[0] & ((1 << dev->color_info.depth) - 1));
+ return 0;
+}
diff --git a/pstoraster/gscpixel.h b/pstoraster/gscpixel.h
new file mode 100644
index 000000000..da6cebcd8
--- /dev/null
+++ b/pstoraster/gscpixel.h
@@ -0,0 +1,34 @@
+/* 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$ */
+/* Requires gscspace.h */
+
+#ifndef gscpixel_INCLUDED
+# define gscpixel_INCLUDED
+
+/* Create a DevicePixel color space. */
+void gs_cs_init_DevicePixel(P2(gs_color_space * pcs, int depth));
+
+#endif /* gscpixel_INCLUDED */
diff --git a/pstoraster/gscpm.h b/pstoraster/gscpm.h
new file mode 100644
index 000000000..313ca6a51
--- /dev/null
+++ b/pstoraster/gscpm.h
@@ -0,0 +1,39 @@
+/* Copyright (C) 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of GNU Ghostscript.
+
+ GNU Ghostscript is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
+ to anyone for the consequences of using it or for whether it serves any
+ particular purpose or works at all, unless he says so in writing. Refer
+ to the GNU General Public License for full details.
+
+ Everyone is granted permission to copy, modify and redistribute GNU
+ Ghostscript, but only under the conditions described in the GNU General
+ Public License. A copy of this license is supposed to have been given
+ to you along with GNU Ghostscript so you can know your rights and
+ responsibilities. It should be in a file named COPYING. Among other
+ things, the copyright notice and this notice must be preserved on all
+ copies.
+
+ Aladdin Enterprises 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$ */
+/* Charpath mode definitions */
+
+#ifndef gscpm_INCLUDED
+# define gscpm_INCLUDED
+
+typedef enum {
+ cpm_show, /* *show (default, must be 0) */
+ cpm_false_charpath, /* false charpath */
+ cpm_true_charpath, /* true charpath */
+ cpm_false_charboxpath, /* false charboxpath (not standard PS) */
+ cpm_true_charboxpath /* true charboxpath (ditto) */
+} gs_char_path_mode;
+
+#endif /* gscpm_INCLUDED */
diff --git a/pstoraster/gscrd.c b/pstoraster/gscrd.c
new file mode 100644
index 000000000..70f3517a2
--- /dev/null
+++ b/pstoraster/gscrd.c
@@ -0,0 +1,350 @@
+/* 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$ */
+/* CIE color rendering dictionary creation */
+#include "math_.h"
+#include "memory_.h"
+#include "string_.h"
+#include "gx.h"
+#include "gscdefs.h" /* for gs_lib_device_list */
+#include "gsdevice.h"
+#include "gserrors.h"
+#include "gsmatrix.h" /* for gscolor2.h */
+#include "gsparam.h"
+#include "gxcspace.h"
+#include "gscolor2.h" /* for gs_set/currentcolorrendering */
+#include "gscrd.h"
+
+/* Import gs_lib_device_list() */
+extern_gs_lib_device_list();
+
+/* Allocator structure type */
+public_st_cie_render1();
+#define pcrd ((gs_cie_render *)vptr)
+private
+ENUM_PTRS_BEGIN(cie_render1_enum_ptrs) return 0;
+
+case 0:
+return ENUM_OBJ(pcrd->client_data);
+case 1:
+return ENUM_OBJ(pcrd->RenderTable.lookup.table);
+case 2:
+return (pcrd->RenderTable.lookup.table ?
+ ENUM_CONST_STRING(&pcrd->TransformPQR.proc_data) :
+ 0);
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(cie_render1_reloc_ptrs);
+RELOC_OBJ_VAR(pcrd->client_data);
+if (pcrd->RenderTable.lookup.table)
+{
+RELOC_OBJ_VAR(pcrd->RenderTable.lookup.table);
+RELOC_CONST_STRING_VAR(pcrd->TransformPQR.proc_data);
+}
+RELOC_PTRS_END
+#undef pcrd
+
+/* Default CRD procedures. */
+
+private int
+tpqr_identity(int index, floatp in, const gs_cie_wbsd * pwbsd,
+ gs_cie_render * pcrd, float *out)
+{
+ *out = in;
+ return 0;
+}
+
+private float
+render_identity(floatp in, const gs_cie_render * pcrd)
+{
+ return in;
+}
+private frac
+render_table_identity(byte in, const gs_cie_render * pcrd)
+{
+ return byte2frac(in);
+}
+
+/* Transformation procedures that just consult the cache. */
+
+#define clamp_index(index)\
+ index = (index < 0 ? 0 :\
+ index >= gx_cie_cache_size ? gx_cie_cache_size - 1 : index)
+
+private float
+EncodeABC_cached(floatp in, const gs_cie_render * pcrd, int i)
+{
+ const gx_cie_scalar_cache *pcache = &pcrd->caches.EncodeABC[i];
+
+ if (pcrd->RenderTable.lookup.table == 0) {
+ int index = (in - pcache->fracs.params.base) *
+ pcache->fracs.params.factor;
+
+ clamp_index(index);
+ return frac2float(pcache->fracs.values[index]);
+ } else {
+ /****** WRONG IF INTERPOLATING ******/
+ int index = (in - pcache->ints.params.base) *
+ pcache->ints.params.factor;
+ const gs_range *prange = &pcrd->RangeABC.ranges[i];
+ int m = pcrd->RenderTable.lookup.m;
+ int k = (i == 0 ? 1 : i == 1 ?
+ m * pcrd->RenderTable.lookup.dims[2] : m);
+
+ clamp_index(index);
+ return (double)(pcache->ints.values[index]) / k *
+ (prange->rmax - prange->rmin) / (gx_cie_cache_size - 1) +
+ prange->rmin;
+ }
+}
+private float
+EncodeABC_cached_A(floatp in, const gs_cie_render * pcrd)
+{
+ return EncodeABC_cached(in, pcrd, 0);
+}
+private float
+EncodeABC_cached_B(floatp in, const gs_cie_render * pcrd)
+{
+ return EncodeABC_cached(in, pcrd, 1);
+}
+private float
+EncodeABC_cached_C(floatp in, const gs_cie_render * pcrd)
+{
+ return EncodeABC_cached(in, pcrd, 2);
+}
+private float
+EncodeLMN_cached(floatp in, const gs_cie_render * pcrd, int i)
+{
+ const gx_cie_vector_cache *pcache = &pcrd->caches.EncodeLMN[i];
+ int index = (in - pcache->floats.params.base) *
+ pcache->floats.params.factor;
+
+ clamp_index(index);
+ /* Pick any one of u, v, w. We should probably pick the one */
+ /* with the largest coefficient.... */
+ return cie_cached2float(pcache->vecs.values[index].u) /
+ (i == 0 ? pcrd->MatrixABCEncode.cu.u :
+ i == 1 ? pcrd->MatrixABCEncode.cv.u :
+ pcrd->MatrixABCEncode.cw.u);
+}
+private float
+EncodeLMN_cached_L(floatp in, const gs_cie_render * pcrd)
+{
+ return EncodeLMN_cached(in, pcrd, 0);
+}
+private float
+EncodeLMN_cached_M(floatp in, const gs_cie_render * pcrd)
+{
+ return EncodeLMN_cached(in, pcrd, 1);
+}
+private float
+EncodeLMN_cached_N(floatp in, const gs_cie_render * pcrd)
+{
+ return EncodeLMN_cached(in, pcrd, 2);
+}
+
+private frac
+RTT_cached(byte in, const gs_cie_render * pcrd, int i)
+{
+ /****** NYI ******/
+ return byte2frac(in);
+}
+private frac
+RTT_cached_0(byte in, const gs_cie_render * pcrd)
+{
+ return RTT_cached(in, pcrd, 0);
+}
+private frac
+RTT_cached_1(byte in, const gs_cie_render * pcrd)
+{
+ return RTT_cached(in, pcrd, 1);
+}
+private frac
+RTT_cached_2(byte in, const gs_cie_render * pcrd)
+{
+ return RTT_cached(in, pcrd, 2);
+}
+private frac
+RTT_cached_3(byte in, const gs_cie_render * pcrd)
+{
+ return RTT_cached(in, pcrd, 3);
+}
+
+#undef clamp_index
+
+/* Define the TransformPQR trampoline procedure that looks up proc_name. */
+
+private int
+tpqr_do_lookup(gs_cie_render *pcrd, const gx_device *dev_proto)
+{
+ gx_device *dev;
+ gs_memory_t *mem = pcrd->rc.memory;
+ gs_c_param_list list;
+ gs_param_string proc_addr;
+ int code;
+
+ /* Device prototypes are const, so we must create a copy. */
+ code = gs_copydevice(&dev, dev_proto, mem);
+ if (code < 0)
+ return code;
+ gs_c_param_list_write(&list, mem);
+ code = param_request((gs_param_list *)&list,
+ pcrd->TransformPQR.proc_name);
+ if (code >= 0) {
+ code = gs_getdeviceparams(dev, (gs_param_list *)&list);
+ if (code >= 0) {
+ gs_c_param_list_read(&list);
+ code = param_read_string((gs_param_list *)&list,
+ pcrd->TransformPQR.proc_name,
+ &proc_addr);
+ if (code == 0 && proc_addr.size == sizeof(gs_cie_transform_proc)) {
+ memcpy(&pcrd->TransformPQR.proc, proc_addr.data,
+ sizeof(gs_cie_transform_proc));
+ } else
+ code = gs_note_error(gs_error_rangecheck);
+ }
+ }
+ gs_c_param_list_release(&list);
+ gs_free_object(mem, dev, "tpqr_do_lookup(device)");
+ return code;
+}
+private int
+tpqr_lookup(int index, floatp in, const gs_cie_wbsd * pwbsd,
+ gs_cie_render * pcrd, float *out)
+{
+ const gx_device *const *dev_list;
+ int count = gs_lib_device_list(&dev_list, NULL);
+ int i;
+ int code;
+
+ for (i = 0; i < count; ++i)
+ if (!strcmp(gs_devicename(dev_list[i]),
+ pcrd->TransformPQR.driver_name))
+ break;
+ if (i < count)
+ code = tpqr_do_lookup(pcrd, dev_list[i]);
+ else
+ code = gs_note_error(gs_error_undefined);
+ if (code < 0)
+ return code;
+ return pcrd->TransformPQR.proc(index, in, pwbsd, pcrd, out);
+}
+
+
+/* Default vectors. */
+const gs_cie_transform_proc3 TransformPQR_default = {
+ tpqr_identity,
+ 0, /* proc_name */
+ {0, 0}, /* proc_data */
+ 0 /* driver_name */
+};
+const gs_cie_transform_proc TransformPQR_lookup_proc_name = tpqr_lookup;
+const gs_cie_render_proc3 Encode_default = {
+ {render_identity, render_identity, render_identity}
+};
+const gs_cie_render_proc3 EncodeLMN_from_cache = {
+ {EncodeLMN_cached_L, EncodeLMN_cached_M, EncodeLMN_cached_N}
+};
+const gs_cie_render_proc3 EncodeABC_from_cache = {
+ {EncodeABC_cached_A, EncodeABC_cached_B, EncodeABC_cached_C}
+};
+const gs_cie_render_table_procs RenderTableT_default = {
+ {render_table_identity, render_table_identity, render_table_identity,
+ render_table_identity
+ }
+};
+const gs_cie_render_table_procs RenderTableT_from_cache = {
+ {RTT_cached_0, RTT_cached_1, RTT_cached_2, RTT_cached_3}
+};
+
+/*
+ * Allocate and minimally initialize a CRD. Note that this procedure sets
+ * the reference count of the structure to 1, not 0. gs_setcolorrendering
+ * will increment the reference count again, so unless you want the
+ * structure to stay allocated permanently (or until a garbage collection),
+ * you should call rc_decrement(pcrd, "client name") *after* calling
+ * gs_setcolorrendering.
+ */
+int
+gs_cie_render1_build(gs_cie_render ** ppcrd, gs_memory_t * mem,
+ client_name_t cname)
+{
+ gs_cie_render *pcrd;
+
+ rc_alloc_struct_1(pcrd, gs_cie_render, &st_cie_render1, mem,
+ return_error(gs_error_VMerror), cname);
+ /* Initialize pointers for the GC. */
+ pcrd->client_data = 0;
+ pcrd->RenderTable.lookup.table = 0;
+ pcrd->status = CIE_RENDER_STATUS_BUILT;
+ *ppcrd = pcrd;
+ return 0;
+}
+
+/*
+ * Initialize a CRD given all of the relevant parameters.
+ * Any of the pointers except WhitePoint may be zero, meaning
+ * use the default values.
+ *
+ * The actual point, matrix, range, and procedure values are copied into the
+ * CRD, but only the pointer to the color lookup table is copied.
+ */
+int
+gs_cie_render1_initialize(gs_cie_render * pcrd, void *client_data,
+ const gs_vector3 * WhitePoint,
+ const gs_vector3 * BlackPoint,
+ const gs_matrix3 * MatrixPQR,
+ const gs_range3 * RangePQR,
+ const gs_cie_transform_proc3 * TransformPQR,
+ const gs_matrix3 * MatrixLMN,
+ const gs_cie_render_proc3 * EncodeLMN,
+ const gs_range3 * RangeLMN,
+ const gs_matrix3 * MatrixABC,
+ const gs_cie_render_proc3 * EncodeABC,
+ const gs_range3 * RangeABC,
+ const gs_cie_render_table_t * RenderTable)
+{
+ pcrd->client_data = client_data;
+ pcrd->points.WhitePoint = *WhitePoint;
+ pcrd->points.BlackPoint =
+ *(BlackPoint ? BlackPoint : &BlackPoint_default);
+ pcrd->MatrixPQR = *(MatrixPQR ? MatrixPQR : &Matrix3_default);
+ pcrd->RangePQR = *(RangePQR ? RangePQR : &Range3_default);
+ pcrd->TransformPQR =
+ *(TransformPQR ? TransformPQR : &TransformPQR_default);
+ pcrd->MatrixLMN = *(MatrixLMN ? MatrixLMN : &Matrix3_default);
+ pcrd->EncodeLMN = *(EncodeLMN ? EncodeLMN : &Encode_default);
+ pcrd->RangeLMN = *(RangeLMN ? RangeLMN : &Range3_default);
+ pcrd->MatrixABC = *(MatrixABC ? MatrixABC : &Matrix3_default);
+ pcrd->EncodeABC = *(EncodeABC ? EncodeABC : &Encode_default);
+ pcrd->RangeABC = *(RangeABC ? RangeABC : &Range3_default);
+ if (RenderTable)
+ pcrd->RenderTable = *RenderTable;
+ else {
+ pcrd->RenderTable.lookup.table = 0;
+ pcrd->RenderTable.T = RenderTableT_default;
+ }
+ pcrd->status = CIE_RENDER_STATUS_BUILT;
+ return 0;
+}
diff --git a/pstoraster/gscrd.h b/pstoraster/gscrd.h
new file mode 100644
index 000000000..05f7c4a57
--- /dev/null
+++ b/pstoraster/gscrd.h
@@ -0,0 +1,75 @@
+/* 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 for CIE color rendering dictionary creation */
+
+#ifndef gscrd_INCLUDED
+# define gscrd_INCLUDED
+
+#include "gscie.h"
+
+/*
+ * Allocate and minimally initialize a CRD. Note that this procedure sets
+ * the reference count of the structure to 1, not 0. gs_setcolorrendering
+ * will increment the reference count again, so unless you want the
+ * structure to stay allocated permanently (or until a garbage collection),
+ * you should call rc_decrement(pcrd, "client name") *after* calling
+ * gs_setcolorrendering.
+ */
+int
+ gs_cie_render1_build(P3(gs_cie_render ** ppcrd, gs_memory_t * mem,
+ client_name_t cname));
+
+/*
+ * Initialize a CRD given all of the relevant parameters.
+ * Any of the pointers except WhitePoint may be zero, meaning
+ * use the default values.
+ *
+ * The actual point, matrix, range, and procedure values are copied into the
+ * CRD, but only the pointer to the color lookup table
+ * (RenderTable.lookup.table) is copied, not the table itself.
+ */
+int
+ gs_cie_render1_initialize(P14(gs_cie_render * pcrd, void *client_data,
+ const gs_vector3 * WhitePoint,
+ const gs_vector3 * BlackPoint,
+ const gs_matrix3 * MatrixPQR,
+ const gs_range3 * RangePQR,
+ const gs_cie_transform_proc3 * TransformPQR,
+ const gs_matrix3 * MatrixLMN,
+ const gs_cie_render_proc3 * EncodeLMN,
+ const gs_range3 * RangeLMN,
+ const gs_matrix3 * MatrixABC,
+ const gs_cie_render_proc3 * EncodeABC,
+ const gs_range3 * RangeABC,
+ const gs_cie_render_table_t * RenderTable));
+
+/*
+ * Set or access the client_data pointer in a CRD.
+ * The macro is an L-value.
+ */
+#define gs_cie_render_client_data(pcrd) ((pcrd)->client_data)
+
+#endif /* gscrd_INCLUDED */
diff --git a/pstoraster/gscrdp.c b/pstoraster/gscrdp.c
new file mode 100644
index 000000000..0a0273715
--- /dev/null
+++ b/pstoraster/gscrdp.c
@@ -0,0 +1,632 @@
+/* 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$ */
+/* CIE color rendering dictionary creation */
+#include "math_.h"
+#include "memory_.h"
+#include "gx.h"
+#include "gsdevice.h"
+#include "gserrors.h"
+#include "gsmatrix.h" /* for gscolor2.h */
+#include "gxcspace.h"
+#include "gscolor2.h" /* for gs_set/currentcolorrendering */
+#include "gscrdp.h"
+#include "gxarith.h"
+#include "gsmalloc.h"
+
+/* Define the CRD type that we use here. */
+#define CRD_TYPE 101
+
+/* ---------------- Writing ---------------- */
+
+/* Internal procedures for writing parameter values. */
+private void
+store_vector3(float *p, const gs_vector3 * pvec)
+{
+ p[0] = pvec->u, p[1] = pvec->v, p[2] = pvec->w;
+}
+private int
+write_floats(gs_param_list * plist, gs_param_name key,
+ const float *values, int size, gs_memory_t * mem)
+{
+ float *p = (float *)
+ gs_alloc_byte_array(mem, size, sizeof(float), "write_floats");
+ gs_param_float_array fa;
+
+ if (p == 0)
+ return_error(gs_error_VMerror);
+ memcpy(p, values, size * sizeof(float));
+
+ fa.data = p;
+ fa.size = size;
+ fa.persistent = true;
+ return param_write_float_array(plist, key, &fa);
+}
+private int
+write_vector3(gs_param_list * plist, gs_param_name key,
+ const gs_vector3 * pvec, gs_memory_t * mem)
+{
+ float values[3];
+
+ store_vector3(values, pvec);
+ return write_floats(plist, key, values, 3, mem);
+}
+private int
+write_matrix3(gs_param_list * plist, gs_param_name key,
+ const gs_matrix3 * pmat, gs_memory_t * mem)
+{
+ float values[9];
+
+ if (!memcmp(pmat, &Matrix3_default, sizeof(*pmat)))
+ return 0;
+ store_vector3(values, &pmat->cu);
+ store_vector3(values + 3, &pmat->cv);
+ store_vector3(values + 6, &pmat->cw);
+ return write_floats(plist, key, values, 9, mem);
+}
+private int
+write_range3(gs_param_list * plist, gs_param_name key,
+ const gs_range3 * prange, gs_memory_t * mem)
+{
+ float values[6];
+
+ if (!memcmp(prange, &Range3_default, sizeof(*prange)))
+ return 0;
+ values[0] = prange->ranges[0].rmin, values[1] = prange->ranges[0].rmax;
+ values[2] = prange->ranges[1].rmin, values[3] = prange->ranges[1].rmax;
+ values[4] = prange->ranges[2].rmin, values[5] = prange->ranges[2].rmax;
+ return write_floats(plist, key, values, 6, mem);
+}
+private int
+write_proc3(gs_param_list * plist, gs_param_name key,
+ const gs_cie_render * pcrd, const gs_cie_render_proc3 * procs,
+ const gs_range3 * domain, gs_memory_t * mem)
+{
+ float *values;
+ uint size = gx_cie_cache_size;
+ gs_param_float_array fa;
+ int i;
+
+ if (!memcmp(procs, &Encode_default, sizeof(*procs)))
+ return 0;
+ values = (float *)gs_alloc_byte_array(mem, size * 3, sizeof(float),
+ "write_proc3");
+
+ if (values == 0)
+ return_error(gs_error_VMerror);
+ for (i = 0; i < 3; ++i) {
+ double base = domain->ranges[i].rmin;
+ double scale = (domain->ranges[i].rmax - base) / (size - 1);
+ int j;
+
+ for (j = 0; j < size; ++j)
+ values[i * size + j] =
+ (*procs->procs[i]) (j * scale + base, pcrd);
+ }
+ fa.data = values;
+ fa.size = size * 3;
+ fa.persistent = true;
+ return param_write_float_array(plist, key, &fa);
+}
+
+/* Write a CRD as a device parameter. */
+int
+param_write_cie_render1(gs_param_list * plist, gs_param_name key,
+ const gs_cie_render * pcrd, gs_memory_t * mem)
+{
+ gs_param_dict dict;
+ int code, dcode;
+
+ dict.size = 20;
+ if ((code = param_begin_write_dict(plist, key, &dict, false)) < 0)
+ return code;
+ code = param_put_cie_render1(dict.list, pcrd, mem);
+ dcode = param_end_write_dict(plist, key, &dict);
+ return (code < 0 ? code : dcode);
+}
+
+/* Write a CRD directly to a parameter list. */
+int
+param_put_cie_render1(gs_param_list * plist, const gs_cie_render * pcrd,
+ gs_memory_t * mem)
+{
+ int crd_type = CRD_TYPE;
+ int code;
+
+ if (pcrd->TransformPQR.proc_name) {
+ gs_param_string pn, pd;
+
+ param_string_from_string(pn, pcrd->TransformPQR.proc_name);
+ pn.size++; /* include terminating null */
+ pd.data = pcrd->TransformPQR.proc_data.data;
+ pd.size = pcrd->TransformPQR.proc_data.size;
+ pd.persistent = true; /****** WRONG ******/
+ if ((code = param_write_name(plist, "TransformPQRName", &pn)) < 0 ||
+ (code = param_write_string(plist, "TransformPQRData", &pd)) < 0
+ )
+ return code;
+ }
+ else if (pcrd->TransformPQR.proc != TransformPQR_default.proc) {
+ /* We have no way to represent the procedure, so return an error. */
+ return_error(gs_error_rangecheck);
+ }
+ if ((code = param_write_int(plist, "ColorRenderingType", &crd_type)) < 0 ||
+ (code = write_vector3(plist, "WhitePoint", &pcrd->points.WhitePoint, mem)) < 0
+ )
+ return code;
+ if (memcmp(&pcrd->points.BlackPoint, &BlackPoint_default,
+ sizeof(pcrd->points.BlackPoint))) {
+ if ((code = write_vector3(plist, "BlackPoint", &pcrd->points.BlackPoint, mem)) < 0)
+ return code;
+ }
+ if ((code = write_matrix3(plist, "MatrixPQR", &pcrd->MatrixPQR, mem)) < 0 ||
+ (code = write_range3(plist, "RangePQR", &pcrd->RangePQR, mem)) < 0 ||
+ /* TransformPQR is handled separately */
+ (code = write_matrix3(plist, "MatrixLMN", &pcrd->MatrixLMN, mem)) < 0 ||
+ (code = write_proc3(plist, "EncodeLMNValues", pcrd,
+ &pcrd->EncodeLMN, &pcrd->DomainLMN, mem)) < 0 ||
+ (code = write_range3(plist, "RangeLMN", &pcrd->RangeLMN, mem)) < 0 ||
+ (code = write_matrix3(plist, "MatrixABC", &pcrd->MatrixABC, mem)) < 0 ||
+ (code = write_proc3(plist, "EncodeABCValues", pcrd,
+ &pcrd->EncodeABC, &pcrd->DomainABC, mem)) < 0 ||
+ (code = write_range3(plist, "RangeABC", &pcrd->RangeABC, mem)) < 0
+ )
+ return code;
+ if (pcrd->RenderTable.lookup.table) {
+ int n = pcrd->RenderTable.lookup.n;
+ int m = pcrd->RenderTable.lookup.m;
+ int na = pcrd->RenderTable.lookup.dims[0];
+ int *size = (int *)
+ gs_alloc_byte_array(mem, n + 1, sizeof(int), "RenderTableSize");
+
+ /*
+ * In principle, we should use gs_alloc_struct_array with a
+ * type descriptor for gs_param_string. However, it is widely
+ * assumed that parameter lists are transient, and don't require
+ * accurate GC information; so we can get away with allocating
+ * the string table as bytes.
+ */
+ gs_param_string *table =
+ (gs_param_string *)
+ gs_alloc_byte_array(mem, na, sizeof(gs_param_string),
+ "RenderTableTable");
+ gs_param_int_array ia;
+
+ if (size == 0 || table == 0)
+ code = gs_note_error(gs_error_VMerror);
+ else {
+ memcpy(size, pcrd->RenderTable.lookup.dims, sizeof(int) * n);
+
+ size[n] = m;
+ ia.data = size;
+ ia.size = n + 1;
+ ia.persistent = true;
+ code = param_write_int_array(plist, "RenderTableSize", &ia);
+ }
+ if (code >= 0) {
+ gs_param_string_array sa;
+ int a;
+
+ for (a = 0; a < na; ++a)
+ table[a].data = pcrd->RenderTable.lookup.table[a].data,
+ table[a].size = pcrd->RenderTable.lookup.table[a].size,
+ table[a].persistent = true;
+ sa.data = table;
+ sa.size = na;
+ sa.persistent = true;
+ code = param_write_string_array(plist, "RenderTableTable", &sa);
+ if (code >= 0 && !pcrd->caches.RenderTableT_is_identity) {
+ /****** WRITE RenderTableTValues LIKE write_proc3 ******/
+ uint size = gx_cie_cache_size;
+ float *values =
+ (float *)gs_alloc_byte_array(mem, size * m,
+ sizeof(float),
+ "write_proc3");
+ gs_param_float_array fa;
+ int i;
+
+ if (values == 0)
+ return_error(gs_error_VMerror);
+ for (i = 0; i < m; ++i) {
+ double scale = 255.0 / (size - 1);
+ int j;
+
+ for (j = 0; j < size; ++j)
+ values[i * size + j] =
+ frac2float((*pcrd->RenderTable.T.procs[i])
+ (j * scale, pcrd));
+ }
+ fa.data = values;
+ fa.size = size * m;
+ fa.persistent = true;
+ code = param_write_float_array(plist, "RenderTableTValues",
+ &fa);
+ }
+ }
+ if (code < 0) {
+ gs_free_object(mem, table, "RenderTableTable");
+ gs_free_object(mem, size, "RenderTableSize");
+ return code;
+ }
+ }
+ return code;
+}
+
+/* ---------------- Reading ---------------- */
+
+/* Internal procedures for reading parameter values. */
+private void
+load_vector3(gs_vector3 * pvec, const float *p)
+{
+ pvec->u = p[0], pvec->v = p[1], pvec->w = p[2];
+}
+private int
+read_floats(gs_param_list * plist, gs_param_name key, float *values, int count)
+{
+ gs_param_float_array fa;
+ int code = param_read_float_array(plist, key, &fa);
+
+ if (code)
+ return code;
+ if (fa.size != count)
+ return_error(gs_error_rangecheck);
+ memcpy(values, fa.data, sizeof(float) * count);
+
+ return 0;
+}
+private int
+read_vector3(gs_param_list * plist, gs_param_name key,
+ gs_vector3 * pvec, const gs_vector3 * dflt)
+{
+ float values[3];
+ int code = read_floats(plist, key, values, 3);
+
+ switch (code) {
+ case 1: /* not defined */
+ if (dflt)
+ *pvec = *dflt;
+ break;
+ case 0:
+ load_vector3(pvec, values);
+ default: /* error */
+ break;
+ }
+ return code;
+}
+private int
+read_matrix3(gs_param_list * plist, gs_param_name key, gs_matrix3 * pmat)
+{
+ float values[9];
+ int code = read_floats(plist, key, values, 9);
+
+ switch (code) {
+ case 1: /* not defined */
+ *pmat = Matrix3_default;
+ break;
+ case 0:
+ load_vector3(&pmat->cu, values);
+ load_vector3(&pmat->cv, values + 3);
+ load_vector3(&pmat->cw, values + 6);
+ default: /* error */
+ break;
+ }
+ return code;
+}
+private int
+read_range3(gs_param_list * plist, gs_param_name key, gs_range3 * prange)
+{
+ float values[6];
+ int code = read_floats(plist, key, values, 6);
+
+ switch (code) {
+ case 1: /* not defined */
+ *prange = Range3_default;
+ break;
+ case 0:
+ prange->ranges[0].rmin = values[0];
+ prange->ranges[0].rmax = values[1];
+ prange->ranges[1].rmin = values[2];
+ prange->ranges[1].rmax = values[3];
+ prange->ranges[2].rmin = values[4];
+ prange->ranges[2].rmax = values[5];
+ default: /* error */
+ break;
+ }
+ return code;
+}
+private int
+read_proc3(gs_param_list * plist, gs_param_name key,
+ float values[gx_cie_cache_size * 3])
+{
+ return read_floats(plist, key, values, gx_cie_cache_size * 3);
+}
+
+/* Read a CRD from a device parameter. */
+int
+gs_cie_render1_param_initialize(gs_cie_render * pcrd, gs_param_list * plist,
+ gs_param_name key, gx_device * dev)
+{
+ gs_param_dict dict;
+ int code = param_begin_read_dict(plist, key, &dict, false);
+ int dcode;
+
+ if (code < 0)
+ return code;
+ code = param_get_cie_render1(pcrd, dict.list, dev);
+ dcode = param_end_read_dict(plist, key, &dict);
+ if (code < 0)
+ return code;
+ if (dcode < 0)
+ return dcode;
+ gs_cie_render_init(pcrd);
+ gs_cie_render_sample(pcrd);
+ return gs_cie_render_complete(pcrd);
+}
+
+/* Define the structure for passing Encode values as "client data". */
+typedef struct encode_data_s {
+ float lmn[gx_cie_cache_size * 3]; /* EncodeLMN */
+ float abc[gx_cie_cache_size * 3]; /* EncodeABC */
+ float t[gx_cie_cache_size * 4]; /* RenderTable.T */
+} encode_data_t;
+
+/* Define procedures that retrieve the Encode values read from the list. */
+private float
+encode_from_data(floatp v, const float values[gx_cie_cache_size],
+ const gs_range * range)
+{
+ return (v <= range->rmin ? values[0] :
+ v >= range->rmax ? values[gx_cie_cache_size - 1] :
+ values[(int)((v - range->rmin) / (range->rmax - range->rmin) *
+ (gx_cie_cache_size - 1) + 0.5)]);
+}
+/*
+ * The repetitive boilerplate in the next 10 procedures really sticks in
+ * my craw, but I've got a mandate not to use macros....
+ */
+private float
+encode_lmn_0_from_data(floatp v, const gs_cie_render * pcrd)
+{
+ const encode_data_t *data = pcrd->client_data;
+
+ return encode_from_data(v, &data->lmn[0],
+ &pcrd->DomainLMN.ranges[0]);
+}
+private float
+encode_lmn_1_from_data(floatp v, const gs_cie_render * pcrd)
+{
+ const encode_data_t *data = pcrd->client_data;
+
+ return encode_from_data(v, &data->lmn[gx_cie_cache_size],
+ &pcrd->DomainLMN.ranges[1]);
+}
+private float
+encode_lmn_2_from_data(floatp v, const gs_cie_render * pcrd)
+{
+ const encode_data_t *data = pcrd->client_data;
+
+ return encode_from_data(v, &data->lmn[gx_cie_cache_size * 2],
+ &pcrd->DomainLMN.ranges[2]);
+}
+private float
+encode_abc_0_from_data(floatp v, const gs_cie_render * pcrd)
+{
+ const encode_data_t *data = pcrd->client_data;
+
+ return encode_from_data(v, &data->abc[0],
+ &pcrd->DomainABC.ranges[0]);
+}
+private float
+encode_abc_1_from_data(floatp v, const gs_cie_render * pcrd)
+{
+ const encode_data_t *data = pcrd->client_data;
+
+ return encode_from_data(v, &data->abc[gx_cie_cache_size],
+ &pcrd->DomainABC.ranges[1]);
+}
+private float
+encode_abc_2_from_data(floatp v, const gs_cie_render * pcrd)
+{
+ const encode_data_t *data = pcrd->client_data;
+
+ return encode_from_data(v, &data->abc[gx_cie_cache_size * 2],
+ &pcrd->DomainABC.ranges[2]);
+}
+private frac
+render_table_t_0_from_data(byte v, const gs_cie_render * pcrd)
+{
+ const encode_data_t *data = pcrd->client_data;
+
+ return float2frac(encode_from_data(v / 255.0,
+ &data->t[0],
+ &Range3_default.ranges[0]));
+}
+private frac
+render_table_t_1_from_data(byte v, const gs_cie_render * pcrd)
+{
+ const encode_data_t *data = pcrd->client_data;
+
+ return float2frac(encode_from_data(v / 255.0,
+ &data->t[gx_cie_cache_size],
+ &Range3_default.ranges[0]));
+}
+private frac
+render_table_t_2_from_data(byte v, const gs_cie_render * pcrd)
+{
+ const encode_data_t *data = pcrd->client_data;
+
+ return float2frac(encode_from_data(v / 255.0,
+ &data->t[gx_cie_cache_size * 2],
+ &Range3_default.ranges[0]));
+}
+private frac
+render_table_t_3_from_data(byte v, const gs_cie_render * pcrd)
+{
+ const encode_data_t *data = pcrd->client_data;
+
+ return float2frac(encode_from_data(v / 255.0,
+ &data->t[gx_cie_cache_size * 3],
+ &Range3_default.ranges[0]));
+}
+private const gs_cie_render_proc3 EncodeLMN_from_data = {
+ {encode_lmn_0_from_data, encode_lmn_1_from_data, encode_lmn_2_from_data}
+};
+private const gs_cie_render_proc3 EncodeABC_from_data = {
+ {encode_abc_0_from_data, encode_abc_1_from_data, encode_abc_2_from_data}
+};
+private const gs_cie_render_table_procs RenderTableT_from_data = {
+ {render_table_t_0_from_data, render_table_t_1_from_data,
+ render_table_t_2_from_data, render_table_t_3_from_data
+ }
+};
+
+/* Read a CRD directly from a parameter list. */
+int
+param_get_cie_render1(gs_cie_render * pcrd, gs_param_list * plist,
+ gx_device * dev)
+{
+ encode_data_t data;
+ gs_param_int_array rt_size;
+ int crd_type;
+ int code, code_lmn, code_abc, code_rt, code_t;
+ gs_param_string pname, pdata;
+
+ if ((code = param_read_int(plist, "ColorRenderingType", &crd_type)) < 0 ||
+ crd_type != CRD_TYPE ||
+ (code = read_vector3(plist, "WhitePoint", &pcrd->points.WhitePoint,
+ NULL)) < 0 ||
+ (code = read_vector3(plist, "BlackPoint", &pcrd->points.BlackPoint,
+ &BlackPoint_default)) < 0 ||
+ (code = read_matrix3(plist, "MatrixPQR", &pcrd->MatrixPQR)) < 0 ||
+ (code = read_range3(plist, "RangePQR", &pcrd->RangePQR)) < 0 ||
+ /* TransformPQR is handled specially below. */
+ (code = read_matrix3(plist, "MatrixLMN", &pcrd->MatrixLMN)) < 0 ||
+ (code_lmn = code =
+ read_proc3(plist, "EncodeLMNValues", data.lmn)) < 0 ||
+ (code = read_range3(plist, "RangeLMN", &pcrd->RangeLMN)) < 0 ||
+ (code = read_matrix3(plist, "MatrixABC", &pcrd->MatrixABC)) < 0 ||
+ (code_abc = code =
+ read_proc3(plist, "EncodeABCValues", data.abc)) < 0 ||
+ (code = read_range3(plist, "RangeABC", &pcrd->RangeABC)) < 0
+ )
+ return code;
+ /* Handle the sampled functions. */
+ switch (code = param_read_string(plist, "TransformPQRName", &pname)) {
+ default: /* error */
+ return code;
+ case 1: /* missing */
+ pcrd->TransformPQR = TransformPQR_default;
+ break;
+ case 0: /* specified */
+ /* The procedure name must be null-terminated: */
+ /* see param_put_cie_render1 above. */
+ if (pname.size < 1 || pname.data[pname.size - 1] != 0)
+ return_error(gs_error_rangecheck);
+ pcrd->TransformPQR.proc = TransformPQR_lookup_proc_name;
+ pcrd->TransformPQR.proc_name = (char *)pname.data;
+ switch (code = param_read_string(plist, "TransformPQRData", &pdata)) {
+ default: /* error */
+ return code;
+ case 1: /* missing */
+ pcrd->TransformPQR.proc_data.data = 0;
+ pcrd->TransformPQR.proc_data.size = 0;
+ break;
+ case 0:
+ pcrd->TransformPQR.proc_data.data = pdata.data;
+ pcrd->TransformPQR.proc_data.size = pdata.size;
+ }
+ pcrd->TransformPQR.driver_name = gs_devicename(dev);
+ break;
+ }
+ pcrd->client_data = &data;
+ if (code_lmn > 0)
+ pcrd->EncodeLMN = Encode_default;
+ else
+ pcrd->EncodeLMN = EncodeLMN_from_data;
+ if (code_abc > 0)
+ pcrd->EncodeABC = Encode_default;
+ else
+ pcrd->EncodeABC = EncodeABC_from_data;
+ code_rt = code = param_read_int_array(plist, "RenderTableSize", &rt_size);
+ if (code == 1) {
+ if (pcrd->RenderTable.lookup.table) {
+ gs_free_object(pcrd->rc.memory,
+ (void *)pcrd->RenderTable.lookup.table, /* break const */
+ "param_get_cie_render1(RenderTable)");
+ pcrd->RenderTable.lookup.table = 0;
+ }
+ pcrd->RenderTable.T = RenderTableT_default;
+ code_t = 1;
+ } else if (code < 0)
+ return code;
+ else if (rt_size.size != 4)
+ return_error(gs_error_rangecheck);
+ else {
+ gs_param_string_array rt_values;
+ gs_const_string *table;
+ int n, m, j;
+
+ code = param_read_string_array(plist, "RenderTableTable", &rt_values);
+ if (code < 0)
+ return code;
+ else if (code > 0 ||
+ rt_values.size != rt_size.data[3] *
+ rt_size.data[1] * rt_size.data[2])
+ return_error(gs_error_rangecheck);
+ pcrd->RenderTable.lookup.n = n = rt_size.size - 1;
+ pcrd->RenderTable.lookup.m = m = rt_size.data[n];
+ if (n > 4 || m > 4)
+ return_error(gs_error_rangecheck);
+ memcpy(pcrd->RenderTable.lookup.dims, rt_size.data, n * sizeof(int));
+ table = (gs_const_string *)gs_malloc(pcrd->RenderTable.lookup.dims[0],
+ sizeof(gs_const_string *),
+ "param_get_cie_render1");
+ for (j = 0; j < pcrd->RenderTable.lookup.dims[0]; ++j) {
+ table[j].data = rt_values.data[j].data;
+ table[j].size = rt_values.data[j].size;
+ }
+ pcrd->RenderTable.lookup.table = table;
+ pcrd->RenderTable.T = RenderTableT_from_data;
+ code_t = code = read_floats(plist, "RenderTableTValues", data.t,
+ gx_cie_cache_size * m);
+ if (code > 0)
+ pcrd->RenderTable.T = RenderTableT_default;
+ else if (code == 0)
+ pcrd->RenderTable.T = RenderTableT_from_data;
+ }
+ if ((code = gs_cie_render_init(pcrd)) >= 0 &&
+ (code = gs_cie_render_sample(pcrd)) >= 0
+ )
+ code = gs_cie_render_complete(pcrd);
+ /* Clean up before exiting. */
+ pcrd->client_data = 0;
+ if (code_lmn == 0)
+ pcrd->EncodeLMN = EncodeLMN_from_cache;
+ if (code_abc == 0)
+ pcrd->EncodeABC = EncodeABC_from_cache;
+ if (code_t == 0)
+ pcrd->RenderTable.T = RenderTableT_from_cache;
+ return code;
+}
diff --git a/pstoraster/gscrdp.h b/pstoraster/gscrdp.h
new file mode 100644
index 000000000..35f2a1d96
--- /dev/null
+++ b/pstoraster/gscrdp.h
@@ -0,0 +1,104 @@
+/* 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 for device-specified CRDs */
+
+#ifndef gscrdp_INCLUDED
+# define gscrdp_INCLUDED
+
+#include "gscie.h"
+#include "gsparam.h"
+
+/*
+ * A driver can provide any number of its own CRDs through (read-only)
+ * device parameters whose values are slightly modified PostScript-style
+ * dictionaries. The driver doesn't need to concern itself with how the
+ * parameters are encoded: it simply constructs a CRD and calls
+ * param_write_cie_render1.
+ */
+int param_write_cie_render1(P4(gs_param_list * plist, gs_param_name key,
+ const gs_cie_render * pcrd,
+ gs_memory_t * mem));
+
+/*
+ * For internal use, we also provide an API that writes the CRD directly
+ * into a parameter list, rather than as a named parameter in a larger
+ * list.
+ */
+int param_put_cie_render1(P3(gs_param_list * plist, const gs_cie_render * pcrd,
+ gs_memory_t * mem));
+
+/*
+ * Client code that wants to initialize a CRD from a device parameter
+ * uses the following complementary procedure. The customary way to
+ * use this is:
+
+ gs_c_param_list list;
+ ...
+ gs_c_param_list_write(&list, mem);
+ gs_c_param_request(&list, "ParamName");
+ code = gs_getdeviceparams(dev, &list);
+ << error if code < 0 >>
+ gs_c_param_list_read(&list);
+ code = gs_cie_render1_param_initialize(pcrd, &list, "ParamName", dev);
+ gs_c_param_list_release(&list);
+ << error if code < 0 >>
+
+ * where "ParamName" is the parameter name, e.g., "CRDDefault".
+ */
+int gs_cie_render1_param_initialize(P4(gs_cie_render * pcrd,
+ gs_param_list * plist,
+ gs_param_name key,
+ gx_device * dev));
+
+/*
+ * Again, we provide an internal procedure that doesn't involve a
+ * parameter name.
+ */
+int param_get_cie_render1(P3(gs_cie_render * pcrd,
+ gs_param_list * plist,
+ gx_device * dev));
+
+/*
+ * The actual representation of the CRD is a slightly modified PostScript
+ * ColorRenderingType 1 dictionary. THE FOLLOWING IS SUBJECT TO CHANGE
+ * WITHOUT NOTICE. Specifically, the following keys are different:
+ * ColorRenderingType = 101
+ * (Instead of TransformPQR = [T1 T2 T3]:)
+ * TransformPQRName = procedure name (a name)
+ * TransformPQRData = procedure data (a string)
+ * (Instead of EncodeLMN/ABC = [E1 E2 E3]:)
+ * EncodeLMN/ABCValues = [V1,1 V1,2 ... V3,N], where Vi,j is the
+ * j'th sampled value of the i'th encoding array, mapped linearly
+ * to the corresponding domain (see gscie.h)
+ * (Instead of RenderTable = [NA NB NC table m T1 ... Tm]:)
+ * RenderTableSize = [NA NB NC m]
+ * RenderTableTable = table (an array of strings)
+ * RenderTableTValues = [V1,1 V1,2 ... Vm,N] (see above)
+ * The PostScript setcolorrendering operator selects the correct operator
+ * according to the ColorRenderingType key.
+ */
+
+#endif /* gscrdp_INCLUDED */
diff --git a/pstoraster/gscrypt1.h b/pstoraster/gscrypt1.h
new file mode 100644
index 000000000..80e1c6660
--- /dev/null
+++ b/pstoraster/gscrypt1.h
@@ -0,0 +1,56 @@
+/* Copyright (C) 1990, 1992, 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$ */
+/* Interface to Adobe Type 1 encryption/decryption. */
+
+#ifndef gscrypt1_INCLUDED
+# define gscrypt1_INCLUDED
+
+/* Normal public interface */
+typedef ushort crypt_state;
+int gs_type1_encrypt(P4(byte * dest, const byte * src, uint len,
+ crypt_state * pstate));
+int gs_type1_decrypt(P4(byte * dest, const byte * src, uint len,
+ crypt_state * pstate));
+
+/* Define the encryption parameters and procedures. */
+#define crypt_c1 ((ushort)52845)
+#define crypt_c2 ((ushort)22719)
+/* c1 * c1' == 1 mod 2^16. */
+#define crypt_c1_inverse ((ushort)27493)
+#define encrypt_next(ch, state, chvar)\
+ (chvar = ((ch) ^ (state >> 8)),\
+ state = (chvar + state) * crypt_c1 + crypt_c2)
+#define decrypt_this(ch, state)\
+ ((ch) ^ (state >> 8))
+#define decrypt_next(ch, state, chvar)\
+ (chvar = decrypt_this(ch, state),\
+ decrypt_skip_next(ch, state))
+#define decrypt_skip_next(ch, state)\
+ (state = ((ch) + state) * crypt_c1 + crypt_c2)
+#define decrypt_skip_previous(ch, state)\
+ (state = (state - crypt_c2) * crypt_c1_inverse - (ch))
+
+#endif /* gscrypt1_INCLUDED */
diff --git a/pstoraster/gscscie.c b/pstoraster/gscscie.c
new file mode 100644
index 000000000..2b2dec89e
--- /dev/null
+++ b/pstoraster/gscscie.c
@@ -0,0 +1,374 @@
+/* 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$ */
+/* CIE color space management */
+#include "math_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gsmatrix.h" /* for gscolor2.h */
+#include "gxcspace.h"
+#include "gscolor2.h" /* for gs_set/currentcolorrendering */
+#include "gscie.h"
+#include "gxarith.h"
+#include "gxdevice.h" /* for gxcmap.h */
+#include "gxcmap.h"
+#include "gzstate.h"
+
+/* ---------------- Color space definition ---------------- */
+
+/* GC descriptors */
+private_st_cie_common();
+private_st_cie_common_elements();
+private_st_cie_a();
+private_st_cie_abc();
+private_st_cie_def();
+private_st_cie_defg();
+
+/* Define the CIE color space types. */
+/* We use CIExxx rather than CIEBasedxxx in some places because */
+/* gcc under VMS only retains 23 characters of procedure names, */
+/* and DEC C truncates all identifiers at 31 characters. */
+extern cs_proc_init_color(gx_init_CIE);
+private cs_proc_concrete_space(gx_concrete_space_CIE);
+private cs_proc_install_cspace(gx_install_CIE);
+
+/* CIEBasedDEFG */
+gs_private_st_ptrs1(st_color_space_CIEDEFG, gs_base_color_space,
+ "gs_color_space(CIEDEFG)", cs_CIEDEFG_enum_ptrs, cs_CIEDEFG_reloc_ptrs,
+ params.defg);
+extern cs_proc_restrict_color(gx_restrict_CIEDEFG);
+extern cs_proc_concretize_color(gx_concretize_CIEDEFG);
+extern cs_proc_install_cspace(gx_install_CIEDEFG);
+private cs_proc_adjust_cspace_count(gx_adjust_cspace_CIEDEFG);
+const gs_color_space_type gs_color_space_type_CIEDEFG = {
+ gs_color_space_index_CIEDEFG, true, true,
+ &st_color_space_CIEDEFG, gx_num_components_4,
+ gx_no_base_space,
+ gx_init_CIE, gx_restrict_CIEDEFG,
+ gx_concrete_space_CIE,
+ gx_concretize_CIEDEFG, NULL,
+ gx_default_remap_color, gx_install_CIE,
+ gx_adjust_cspace_CIEDEFG, gx_no_adjust_color_count
+};
+
+/* CIEBasedDEF */
+gs_private_st_ptrs1(st_color_space_CIEDEF, gs_base_color_space,
+ "gs_color_space(CIEDEF)", cs_CIEDEF_enum_ptrs, cs_CIEDEF_reloc_ptrs,
+ params.def);
+extern cs_proc_restrict_color(gx_restrict_CIEDEF);
+extern cs_proc_concretize_color(gx_concretize_CIEDEF);
+extern cs_proc_install_cspace(gx_install_CIEDEF);
+private cs_proc_adjust_cspace_count(gx_adjust_cspace_CIEDEF);
+const gs_color_space_type gs_color_space_type_CIEDEF = {
+ gs_color_space_index_CIEDEF, true, true,
+ &st_color_space_CIEDEF, gx_num_components_3,
+ gx_no_base_space,
+ gx_init_CIE, gx_restrict_CIEDEF,
+ gx_concrete_space_CIE,
+ gx_concretize_CIEDEF, NULL,
+ gx_default_remap_color, gx_install_CIE,
+ gx_adjust_cspace_CIEDEF, gx_no_adjust_color_count
+};
+
+/* CIEBasedABC */
+gs_private_st_ptrs1(st_color_space_CIEABC, gs_base_color_space,
+ "gs_color_space(CIEABC)", cs_CIEABC_enum_ptrs, cs_CIEABC_reloc_ptrs,
+ params.abc);
+cs_proc_restrict_color(gx_restrict_CIEABC);
+cs_proc_concretize_color(gx_concretize_CIEABC);
+cs_proc_install_cspace(gx_install_CIEABC);
+private cs_proc_adjust_cspace_count(gx_adjust_cspace_CIEABC);
+extern cs_proc_remap_color(gx_remap_CIEABC);
+const gs_color_space_type gs_color_space_type_CIEABC = {
+ gs_color_space_index_CIEABC, true, true,
+ &st_color_space_CIEABC, gx_num_components_3,
+ gx_no_base_space,
+ gx_init_CIE, gx_restrict_CIEABC,
+ gx_concrete_space_CIE,
+ gx_concretize_CIEABC, NULL,
+ gx_remap_CIEABC, gx_install_CIE,
+ gx_adjust_cspace_CIEABC, gx_no_adjust_color_count
+};
+
+/* CIEBasedA */
+gs_private_st_ptrs1(st_color_space_CIEA, gs_base_color_space,
+ "gs_color_space(CIEA)", cs_CIEA_enum_ptrs, cs_CIEA_reloc_ptrs,
+ params.a);
+cs_proc_restrict_color(gx_restrict_CIEA);
+cs_proc_concretize_color(gx_concretize_CIEA);
+cs_proc_install_cspace(gx_install_CIEA);
+private cs_proc_adjust_cspace_count(gx_adjust_cspace_CIEA);
+const gs_color_space_type gs_color_space_type_CIEA = {
+ gs_color_space_index_CIEA, true, true,
+ &st_color_space_CIEA, gx_num_components_1,
+ gx_no_base_space,
+ gx_init_CIE, gx_restrict_CIEA,
+ gx_concrete_space_CIE,
+ gx_concretize_CIEA, NULL,
+ gx_default_remap_color, gx_install_CIE,
+ gx_adjust_cspace_CIEA, gx_no_adjust_color_count
+};
+
+/* Determine the concrete space underlying a CIEBased space. */
+private const gs_color_space *
+gx_concrete_space_CIE(const gs_color_space * pcs, const gs_imager_state * pis)
+{
+ const gs_cie_render *pcie = pis->cie_render;
+
+ if (pcie == 0 || pcie->RenderTable.lookup.table == 0 ||
+ pcie->RenderTable.lookup.m == 3
+ )
+ return gs_cspace_DeviceRGB(pis);
+ else /* pcie->RenderTable.lookup.m == 4 */
+ return gs_cspace_DeviceCMYK(pis);
+}
+
+/* Install a CIE space in the graphics state. */
+/* We go through an extra level of procedure so that */
+/* interpreters can substitute their own installer. */
+private int
+gx_install_CIE(gs_color_space * pcs, gs_state * pgs)
+{
+ return (*pcs->params.a->common.install_cspace) (pcs, pgs);
+}
+
+/* Adjust reference counts for a CIE color space */
+private void
+gx_adjust_cspace_CIEDEFG(const gs_color_space * pcs, int delta)
+{
+ rc_adjust_const(pcs->params.defg, delta, "gx_adjust_cspace_CIEDEFG");
+}
+
+private void
+gx_adjust_cspace_CIEDEF(const gs_color_space * pcs, int delta)
+{
+ rc_adjust_const(pcs->params.def, delta, "gx_adjust_cspace_CIEDEF");
+}
+
+private void
+gx_adjust_cspace_CIEABC(const gs_color_space * pcs, int delta)
+{
+ rc_adjust_const(pcs->params.abc, delta, "gx_adjust_cspace_CIEABC");
+}
+
+private void
+gx_adjust_cspace_CIEA(const gs_color_space * pcs, int delta)
+{
+ rc_adjust_const(pcs->params.a, delta, "gx_adjust_cspace_CIEA");
+}
+
+/* ---------------- Procedures ---------------- */
+
+/* ------ Internal initializers ------ */
+
+/*
+ * Set up the default values for the CIE parameters that are common to
+ * all CIE color spaces.
+ *
+ * There is no default for the white point, so it is set equal to the
+ * black point. If anyone actually uses the color space in that form,
+ * the results are likely to be unsatisfactory.
+ */
+private void
+set_common_cie_defaults(gs_cie_common * pcommon, void *client_data)
+{
+ pcommon->RangeLMN = Range3_default;
+ pcommon->DecodeLMN = DecodeLMN_default;
+ pcommon->MatrixLMN = Matrix3_default;
+ pcommon->points.WhitePoint = BlackPoint_default;
+ pcommon->points.BlackPoint = BlackPoint_default;
+ pcommon->client_data = client_data;
+}
+
+/*
+ * Set defaults for a CIEBasedABC color space. This is also used for
+ * CIEBasedDEF and CIEBasedDEFG color spaces.
+ */
+private void
+set_cie_abc_defaults(gs_cie_abc * pabc, void *client_data)
+{
+ set_common_cie_defaults(&pabc->common, client_data);
+ pabc->RangeABC = Range3_default;
+ pabc->DecodeABC = DecodeABC_default;
+ pabc->MatrixABC = Matrix3_default;
+}
+
+/*
+ * Set up a default color lookup table for a CIEBasedDEF[G] space. There is
+ * no specified default for this structure, so the values used here (aside
+ * from the input and output component numbers) are intended only to make
+ * the system fail in a predictable manner.
+ */
+private void
+set_ctbl_defaults(gx_color_lookup_table * plktblp, int num_comps)
+{
+ int i;
+
+ plktblp->n = num_comps;
+ plktblp->m = 3; /* always output CIE ABC */
+ for (i = 0; i < countof(plktblp->dims); i++)
+ plktblp->dims[i] = 0;
+ plktblp->table = 0;
+}
+
+/*
+ * Allocate a color space and its parameter structure.
+ * Return 0 if VMerror, otherwise the parameter structure.
+ */
+private void *
+build_cie_space(gs_color_space ** ppcspace, const gs_color_space_type * pcstype,
+ gs_memory_type_ptr_t stype, gs_memory_t * pmem)
+{
+ gs_color_space *pcspace =
+ gs_alloc_struct(pmem, gs_color_space, &st_color_space,
+ "build_cie_space");
+ gs_cie_common_elements_t *pdata;
+
+ if (pcspace == 0)
+ return 0;
+ rc_alloc_struct_1(pdata, gs_cie_common_elements_t, stype, pmem,
+ {
+ gs_free_object(pmem, pcspace, "build_cie_space");
+ return 0;
+ }
+ ,
+ "build_cie_space(data)");
+ pcspace->pmem = pmem;
+ pcspace->type = pcstype;
+ *ppcspace = pcspace;
+ return (void *)pdata;
+}
+
+/* ------ Constructors ------ */
+
+int
+gs_cspace_build_CIEA(gs_color_space ** ppcspace, void *client_data,
+ gs_memory_t * pmem)
+{
+ gs_cie_a *pciea =
+ build_cie_space(ppcspace, &gs_color_space_type_CIEA, &st_cie_a, pmem);
+
+ if (pciea == 0)
+ return_error(gs_error_VMerror);
+
+ set_common_cie_defaults(&pciea->common, client_data);
+ pciea->common.install_cspace = gx_install_CIEA;
+ pciea->RangeA = RangeA_default;
+ pciea->DecodeA = DecodeA_default;
+ pciea->MatrixA = MatrixA_default;
+
+ (*ppcspace)->params.a = pciea;
+ return 0;
+}
+
+int
+gs_cspace_build_CIEABC(gs_color_space ** ppcspace, void *client_data,
+ gs_memory_t * pmem)
+{
+ gs_cie_abc *pabc =
+ build_cie_space(ppcspace, &gs_color_space_type_CIEABC, &st_cie_abc,
+ pmem);
+
+ if (pabc == 0)
+ return_error(gs_error_VMerror);
+
+ set_cie_abc_defaults(pabc, client_data);
+ pabc->common.install_cspace = gx_install_CIEABC;
+
+ (*ppcspace)->params.abc = pabc;
+ return 0;
+}
+
+int
+gs_cspace_build_CIEDEF(gs_color_space ** ppcspace, void *client_data,
+ gs_memory_t * pmem)
+{
+ gs_cie_def *pdef =
+ build_cie_space(ppcspace, &gs_color_space_type_CIEDEF, &st_cie_def,
+ pmem);
+
+ if (pdef == 0)
+ return_error(gs_error_VMerror);
+
+ set_cie_abc_defaults((gs_cie_abc *) pdef, client_data);
+ pdef->common.install_cspace = gx_install_CIEDEF;
+ pdef->RangeDEF = Range3_default;
+ pdef->DecodeDEF = DecodeDEF_default;
+ pdef->RangeHIJ = Range3_default;
+ set_ctbl_defaults(&pdef->Table, 3);
+
+ (*ppcspace)->params.def = pdef;
+ return 0;
+}
+
+int
+gs_cspace_build_CIEDEFG(gs_color_space ** ppcspace, void *client_data,
+ gs_memory_t * pmem)
+{
+ gs_cie_defg *pdefg =
+ build_cie_space(ppcspace, &gs_color_space_type_CIEDEFG, &st_cie_defg,
+ pmem);
+
+ if (pdefg == 0)
+ return_error(gs_error_VMerror);
+
+ set_cie_abc_defaults((gs_cie_abc *) pdefg, client_data);
+ pdefg->common.install_cspace = gx_install_CIEDEFG;
+ pdefg->RangeDEFG = Range4_default;
+ pdefg->DecodeDEFG = DecodeDEFG_default;
+ pdefg->RangeHIJK = Range4_default;
+ set_ctbl_defaults(&pdefg->Table, 4);
+
+ (*ppcspace)->params.defg = pdefg;
+ return 0;
+}
+
+/* ------ Accessors ------ */
+
+int
+gs_cie_defx_set_lookup_table(gs_color_space * pcspace, int *pdims,
+ const gs_const_string * ptable)
+{
+ gx_color_lookup_table *plktblp;
+
+ switch (gs_color_space_get_index(pcspace)) {
+ case gs_color_space_index_CIEDEF:
+ plktblp = &pcspace->params.def->Table;
+ break;
+ case gs_color_space_index_CIEDEFG:
+ plktblp = &pcspace->params.defg->Table;
+ plktblp->dims[3] = pdims[3];
+ break;
+ default:
+ return_error(gs_error_rangecheck);
+ }
+
+ plktblp->dims[0] = pdims[0];
+ plktblp->dims[1] = pdims[1];
+ plktblp->dims[2] = pdims[2];
+ plktblp->table = ptable;
+ return 0;
+}
diff --git a/pstoraster/gscsel.h b/pstoraster/gscsel.h
new file mode 100644
index 000000000..7609b84bb
--- /dev/null
+++ b/pstoraster/gscsel.h
@@ -0,0 +1,44 @@
+/* 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$ */
+/* Definitions for color operand selection */
+
+#ifndef gscsel_INCLUDED
+# define gscsel_INCLUDED
+
+/*
+ * Define whether we are mapping a "source" or a "texture" color for
+ * RasterOp. Right the source and texture only have separate halftone
+ * phases in the graphics state, but someday they might have more.
+ */
+typedef enum {
+ gs_color_select_all = -1, /* for setting only, not for reading */
+ gs_color_select_texture = 0, /* 0 is the one is used for currenthtphase */
+ gs_color_select_source = 1
+} gs_color_select_t;
+
+#define gs_color_select_count 2
+
+#endif /* gscsel_INCLUDED */
diff --git a/pstoraster/gscsepnm.h b/pstoraster/gscsepnm.h
new file mode 100644
index 000000000..7d59e2097
--- /dev/null
+++ b/pstoraster/gscsepnm.h
@@ -0,0 +1,54 @@
+/* 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$ */
+/* Standard color space separation names */
+
+#ifndef gscsepnm_INCLUDED
+# define gscsepnm_INCLUDED
+
+/*
+ * Define enumeration indices for the standard separation names, and the
+ * corresponding name strings. These are only used internally: in all
+ * externally accessible APIs, separations are defined either by a string
+ * name or by an opaque identifier.
+ *
+ * NB: the enumeration and the list of strings must be synchronized. */
+typedef enum {
+ gs_ht_separation_Default, /* must be first */
+ gs_ht_separation_Gray,
+ gs_ht_separation_Red,
+ gs_ht_separation_Green,
+ gs_ht_separation_Blue,
+ gs_ht_separation_Cyan,
+ gs_ht_separation_Magenta,
+ gs_ht_separation_Yellow,
+ gs_ht_separation_Black
+} gs_ht_separation_name;
+
+#define gs_ht_separation_name_strings \
+ "Default", "Gray", "Red", "Green", "Blue", \
+ "Cyan", "Magenta", "Yellow", "Black"
+
+#endif /* gscsepnm_INCLUDED */
diff --git a/pstoraster/gscsepr.c b/pstoraster/gscsepr.c
new file mode 100644
index 000000000..c03aae04c
--- /dev/null
+++ b/pstoraster/gscsepr.c
@@ -0,0 +1,352 @@
+/* Copyright (C) 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$ */
+/* Separation color space and operation definition */
+#include "gx.h"
+#include "gserrors.h"
+#include "gsrefct.h"
+#include "gsmatrix.h" /* for gscolor2.h */
+#include "gscsepr.h"
+#include "gxcspace.h"
+#include "gxfixed.h" /* for gxcolor2.h */
+#include "gxcolor2.h" /* for gs_indexed_map */
+#include "gzstate.h" /* for pgs->overprint */
+
+/* ---------------- Color space ---------------- */
+
+gs_private_st_composite(st_color_space_Separation, gs_paint_color_space,
+ "gs_color_space_Separation",
+ cs_Separation_enum_ptrs, cs_Separation_reloc_ptrs);
+
+/* Define the Separation color space type. */
+private cs_proc_base_space(gx_alt_space_Separation);
+private cs_proc_init_color(gx_init_Separation);
+private cs_proc_concrete_space(gx_concrete_space_Separation);
+private cs_proc_concretize_color(gx_concretize_Separation);
+private cs_proc_remap_concrete_color(gx_remap_concrete_Separation);
+private cs_proc_install_cspace(gx_install_Separation);
+private cs_proc_adjust_cspace_count(gx_adjust_cspace_Separation);
+const gs_color_space_type gs_color_space_type_Separation = {
+ gs_color_space_index_Separation, true, false,
+ &st_color_space_Separation, gx_num_components_1,
+ gx_alt_space_Separation,
+ gx_init_Separation, gx_restrict01_paint_1,
+ gx_concrete_space_Separation,
+ gx_concretize_Separation, gx_remap_concrete_Separation,
+ gx_default_remap_color, gx_install_Separation,
+ gx_adjust_cspace_Separation, gx_no_adjust_color_count
+};
+
+/* GC procedures */
+
+#define pcs ((gs_color_space *)vptr)
+
+private
+ENUM_PTRS_BEGIN(cs_Separation_enum_ptrs)
+{
+ return ENUM_USING(*pcs->params.separation.alt_space.type->stype,
+ &pcs->params.separation.alt_space,
+ sizeof(pcs->params.separation.alt_space), index - 1);
+}
+ENUM_PTR(0, gs_color_space, params.separation.map);
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(cs_Separation_reloc_ptrs)
+{
+ RELOC_PTR(gs_color_space, params.separation.map);
+ RELOC_USING(*pcs->params.separation.alt_space.type->stype,
+ &pcs->params.separation.alt_space,
+ sizeof(gs_base_color_space));
+}
+RELOC_PTRS_END
+
+#undef pcs
+
+/* Get the alternate space for a Separation space. */
+private const gs_color_space *
+gx_alt_space_Separation(const gs_color_space * pcs)
+{
+ return (const gs_color_space *)&(pcs->params.separation.alt_space);
+}
+
+/* Get the concrete space for a Separation space. */
+/* (We don't support concrete Separation spaces yet.) */
+private const gs_color_space *
+gx_concrete_space_Separation(const gs_color_space * pcs,
+ const gs_imager_state * pis)
+{
+ const gs_color_space *pacs =
+ (const gs_color_space *)&pcs->params.separation.alt_space;
+
+ return cs_concrete_space(pacs, pis);
+}
+
+/* Install a Separation color space. */
+private int
+gx_install_Separation(gs_color_space * pcs, gs_state * pgs)
+{
+ return (*pcs->params.separation.alt_space.type->install_cspace)
+ ((gs_color_space *) & pcs->params.separation.alt_space, pgs);
+}
+
+/* Adjust the reference count of a Separation color space. */
+private void
+gx_adjust_cspace_Separation(const gs_color_space * pcs, int delta)
+{
+ rc_adjust_const(pcs->params.separation.map, delta,
+ "gx_adjust_Separation");
+ (*pcs->params.separation.alt_space.type->adjust_cspace_count)
+ ((const gs_color_space *)&pcs->params.separation.alt_space, delta);
+}
+
+/* ------ Constructors/accessors ------ */
+
+/*
+ * The default separation tint transformation function. This will just return
+ * the information in the cache or, if the cache is of zero size, set all
+ * components in the alternative color space to 0.
+ *
+ * No special cases are provided for this routine, as the use of separations
+ * (particular in this form) is sufficiently rare to not have a significant
+ * performance impact.
+ */
+private int
+map_tint_value(const gs_separation_params * pcssepr, floatp in_val,
+ float *out_vals)
+{
+ int ncomps =
+ cs_num_components((const gs_color_space *)&pcssepr->alt_space);
+ int nentries = pcssepr->map->num_values / ncomps;
+ int indx;
+ const float *pv = pcssepr->map->values;
+ int i;
+
+ if (nentries == 0) {
+ for (i = 0; i < ncomps; i++)
+ out_vals[i] = 0.0;
+ return 0;
+ }
+ if (in_val > 1)
+ indx = nentries - 1;
+ else if (in_val <= 0)
+ indx = 0;
+ else
+ indx = (int)(in_val * nentries + 0.5);
+ pv += indx * ncomps;
+
+ for (i = 0; i < ncomps; i++)
+ out_vals[i] = pv[i];
+ return 0;
+}
+
+/*
+ * Allocate the indexed map required by a separation color space.
+ */
+private gs_indexed_map *
+alloc_separation_map(const gs_color_space * palt_cspace, int cache_size,
+ gs_memory_t * pmem)
+{
+ gs_indexed_map *pimap;
+
+ rc_alloc_struct_1(pimap, gs_indexed_map, &st_indexed_map, pmem,
+ return 0,
+ "gs_cspace_build_Separation"
+ );
+ pimap->rc.free = free_indexed_map;
+ pimap->proc.tint_transform = map_tint_value;
+
+ if (cache_size != 0) {
+ int num_comps = gs_color_space_num_components(palt_cspace);
+
+ cache_size *= num_comps;
+ pimap->num_values = cache_size;
+ pimap->values =
+ (float *)gs_alloc_byte_array(pmem, cache_size, sizeof(float),
+ "gs_cspace_build_Separation"
+ );
+
+ if (pimap->values == 0)
+ rc_decrement(pimap, "gs_cspace_build_Separation"); /* sets pimap = 0 */
+
+ } else {
+ pimap->num_values = 0;
+ pimap->values = 0;
+ }
+ return pimap;
+}
+
+/*
+ * Build a separation color space.
+ *
+ * The values array provided with separation color spaces is actually cached
+ * information, but filled in by the client. The alternative space is the
+ * color space in which the tint procedure will provide alternative colors.
+ */
+int
+gs_cspace_build_Separation(
+ gs_color_space ** ppcspace,
+ gs_separation_name sname,
+ const gs_color_space * palt_cspace,
+ int cache_size,
+ gs_memory_t * pmem
+)
+{
+ gs_color_space *pcspace = 0;
+ gs_separation_params *pcssepr = 0;
+ int code;
+
+ if (palt_cspace == 0 || !palt_cspace->type->can_be_alt_space)
+ return_error(gs_error_rangecheck);
+
+ code = gs_cspace_alloc(&pcspace, &gs_color_space_type_Separation, pmem);
+ if (code < 0)
+ return code;
+ pcssepr = &pcspace->params.separation;
+ pcssepr->map = alloc_separation_map(palt_cspace, cache_size, pmem);
+ if (pcssepr->map == 0) {
+ gs_free_object(pmem, pcspace, "gs_cspace_build_Separation");
+ return_error(gs_error_VMerror);
+ }
+ pcssepr->sname = sname;
+ gs_cspace_init_from((gs_color_space *) & pcssepr->alt_space, palt_cspace);
+ *ppcspace = pcspace;
+ return 0;
+}
+
+/*
+ * Get the cached value array for a separation color space. This will return
+ * a null pointer if the color space is not a separation color space, or if
+ * the separation color space has a cache size of 0.
+ */
+float *
+gs_cspace_get_separation_value_array(const gs_color_space * pcspace)
+{
+ if (gs_color_space_get_index(pcspace) != gs_color_space_index_Separation)
+ return 0;
+ return pcspace->params.separation.map->values;
+}
+
+/*
+ * Set the tint transformation procedure used by a Separation color space.
+ */
+int
+gs_cspace_set_tint_transform_proc(gs_color_space * pcspace,
+ int (*proc) (P3(const gs_separation_params *, floatp, float *)))
+{
+ if (gs_color_space_get_index(pcspace) != gs_color_space_index_Separation)
+ return_error(gs_error_rangecheck);
+ pcspace->params.separation.map->proc.tint_transform = proc;
+ return 0;
+}
+
+/* ---------------- Graphics state ---------------- */
+
+/* setoverprint */
+void
+gs_setoverprint(gs_state * pgs, bool ovp)
+{
+ pgs->overprint = ovp;
+}
+
+/* currentoverprint */
+bool
+gs_currentoverprint(const gs_state * pgs)
+{
+ return pgs->overprint;
+}
+
+/* ------ Internal procedures ------ */
+
+/* Initialize a Separation color. */
+
+private void
+gx_init_Separation(gs_client_color * pcc, const gs_color_space * pcs)
+{
+ pcc->paint.values[0] = 1.0;
+}
+
+/* Remap a Separation color. */
+
+private int
+gx_concretize_Separation(const gs_client_color * pc, const gs_color_space * pcs,
+ frac * pconc, const gs_imager_state * pis)
+{
+ float tint = pc->paint.values[0];
+ int code;
+ gs_client_color cc;
+ const gs_color_space *pacs =
+ (const gs_color_space *)&pcs->params.separation.alt_space;
+
+ if (tint < 0)
+ tint = 0;
+ else if (tint > 1)
+ tint = 1;
+ /* We always map into the alternate color space. */
+ code = (*pcs->params.separation.map->proc.tint_transform) (&pcs->params.separation, tint, &cc.paint.values[0]);
+ if (code < 0)
+ return code;
+ return (*pacs->type->concretize_color) (&cc, pacs, pconc, pis);
+}
+
+private int
+gx_remap_concrete_Separation(const frac * pconc,
+ gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
+ gs_color_select_t select)
+{ /* We don't support concrete Separation colors yet. */
+ return_error(gs_error_rangecheck);
+}
+
+/* ---------------- Notes on real Separation colors ---------------- */
+
+typedef ulong gs_separation; /* BOGUS */
+
+#define gs_no_separation ((gs_separation)(-1L))
+
+#define dev_proc_lookup_separation(proc)\
+ gs_separation proc(P4(gx_device *dev, const byte *sname, uint len,\
+ gx_color_value *num_levels))
+
+#define dev_proc_map_tint_color(proc)\
+ gx_color_index proc(P4(gx_device *dev, gs_separation sepr, bool overprint,\
+ gx_color_value tint))
+
+/*
+ * In principle, setting a Separation color space, or setting the device
+ * when the current color space is a Separation space, calls the
+ * lookup_separation device procedure to obtain the separation ID and
+ * the number of achievable levels. Currently, the only hooks for doing
+ * this are unsuitable: gx_set_cmap_procs isn't called when the color
+ * space changes, and doing it in gx_remap_Separation is inefficient.
+ * Probably the best approach is to call gx_set_cmap_procs whenever the
+ * color space changes. In fact, if we do this, we can probably short-cut
+ * two levels of procedure call in color remapping (gx_remap_color, by
+ * turning it into a macro, and gx_remap_DeviceXXX, by calling the
+ * cmap_proc procedure directly). Some care will be required for the
+ * implicit temporary resetting of the color space in [color]image.
+ *
+ * For actual remapping of Separation colors, we need cmap_separation_direct
+ * and cmap_separation_halftoned, just as for the other device color spaces.
+ * So we need to break apart gx_render_gray in gxdither.c so it can also
+ * do the job for separations.
+ */
diff --git a/pstoraster/gscsepr.h b/pstoraster/gscsepr.h
new file mode 100644
index 000000000..b719c60ca
--- /dev/null
+++ b/pstoraster/gscsepr.h
@@ -0,0 +1,74 @@
+/* Copyright (C) 1992, 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$ */
+/* Client interface to Separation color */
+
+#ifndef gscsepr_INCLUDED
+# define gscsepr_INCLUDED
+
+#include "gscspace.h"
+
+/* Graphics state */
+bool gs_currentoverprint(P1(const gs_state *));
+void gs_setoverprint(P2(gs_state *, bool));
+
+/*
+ * Separation color spaces.
+ *
+ * The API for creating Separation color space objects exposes the fact that
+ * they normally cache the results of sampling the tint_transform procedure,
+ * and use the cache to convert colors when necessary. When a language
+ * interpreter sets up a Separation space, it may either provide a
+ * tint_tranform procedure that will be called each time (specifying the
+ * cache size as 0), or it may fill in the cache directly and provide a
+ * dummy procedure.
+ *
+ * By default, the tint transformation procedure will simple return the
+ * entries in the cache. If this function is called when the cache size is
+ * 0, all color components in the alternative color space will be set to 0.
+ */
+extern int gs_cspace_build_Separation(
+ gs_color_space ** ppcspace,
+ gs_separation_name sname,
+ const gs_color_space * palt_cspace,
+ int cache_size,
+ gs_memory_t * pmem
+);
+
+/* Get the cached value array for a Separation color space. */
+extern float *gs_separation_value_array(P1(
+ const gs_color_space * pcspace
+ ));
+
+/* Set the tint transformation procedure for a separation color space. */
+extern int gs_cspace_set_tint_transform_proc(P2(
+ gs_color_space * pcspace,
+ int (*proc) (P3(const gs_separation_params *,
+ floatp,
+ float *
+ ))
+ ));
+
+#endif /* gscsepr_INCLUDED */
diff --git a/pstoraster/gscspace.c b/pstoraster/gscspace.c
new file mode 100644
index 000000000..16f52bf92
--- /dev/null
+++ b/pstoraster/gscspace.c
@@ -0,0 +1,237 @@
+/* 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$ */
+/* Color space operators and support */
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gsccolor.h"
+#include "gxcspace.h"
+#include "gxistate.h"
+
+/* Define the standard color space types. */
+extern cs_proc_remap_color(gx_remap_DeviceGray);
+extern cs_proc_concretize_color(gx_concretize_DeviceGray);
+extern cs_proc_remap_concrete_color(gx_remap_concrete_DGray);
+extern cs_proc_remap_color(gx_remap_DeviceRGB);
+extern cs_proc_concretize_color(gx_concretize_DeviceRGB);
+extern cs_proc_remap_concrete_color(gx_remap_concrete_DRGB);
+const gs_color_space_type gs_color_space_type_DeviceGray = {
+ gs_color_space_index_DeviceGray, true, true,
+ &st_base_color_space, gx_num_components_1,
+ gx_no_base_space,
+ gx_init_paint_1, gx_restrict01_paint_1,
+ gx_same_concrete_space,
+ gx_concretize_DeviceGray, gx_remap_concrete_DGray,
+ gx_remap_DeviceGray, gx_no_install_cspace,
+ gx_no_adjust_cspace_count, gx_no_adjust_color_count
+};
+const gs_color_space_type gs_color_space_type_DeviceRGB = {
+ gs_color_space_index_DeviceRGB, true, true,
+ &st_base_color_space, gx_num_components_3,
+ gx_no_base_space,
+ gx_init_paint_3, gx_restrict01_paint_3,
+ gx_same_concrete_space,
+ gx_concretize_DeviceRGB, gx_remap_concrete_DRGB,
+ gx_remap_DeviceRGB, gx_no_install_cspace,
+ gx_no_adjust_cspace_count, gx_no_adjust_color_count
+};
+
+/* Structure descriptors */
+public_st_color_space();
+public_st_base_color_space();
+
+/* Return the shared instances of the color spaces. */
+const gs_color_space *
+gs_cspace_DeviceGray(const gs_imager_state * pis)
+{
+ return gs_imager_state_shared(pis, cs_DeviceGray);
+}
+const gs_color_space *
+gs_cspace_DeviceRGB(const gs_imager_state * pis)
+{
+ return gs_imager_state_shared(pis, cs_DeviceRGB);
+}
+const gs_color_space *
+gs_cspace_DeviceCMYK(const gs_imager_state * pis)
+{
+ return gs_imager_state_shared(pis, cs_DeviceCMYK);
+}
+
+/* ------ Create/copy/destroy ------ */
+
+int
+gs_cspace_alloc(gs_color_space ** ppcspace,
+ const gs_color_space_type * pcstype,
+ gs_memory_t * mem)
+{
+ gs_color_space *pcspace =
+ gs_alloc_struct(mem, gs_color_space, &st_color_space,
+ "gs_cspace_alloc");
+
+ if (pcspace == 0)
+ return_error(gs_error_VMerror);
+ pcspace->pmem = mem;
+ pcspace->type = pcstype;
+ *ppcspace = pcspace;
+ return 0;
+}
+
+int
+gs_cspace_build_DeviceGray(gs_color_space ** ppcspace, gs_memory_t * pmem)
+{
+ return gs_cspace_alloc(ppcspace, &gs_color_space_type_DeviceGray, pmem);
+}
+int
+gs_cspace_build_DeviceRGB(gs_color_space ** ppcspace, gs_memory_t * pmem)
+{
+ return gs_cspace_alloc(ppcspace, &gs_color_space_type_DeviceRGB, pmem);
+}
+int
+gs_cspace_build_DeviceCMYK(gs_color_space ** ppcspace, gs_memory_t * pmem)
+{
+ return gs_cspace_alloc(ppcspace, &gs_color_space_type_DeviceCMYK, pmem);
+}
+
+/*
+ * Copy just enough of a color space object. This will do the right thing
+ * for copying color spaces into the base or alternate color space of a
+ * compound color space when legal, but it can't check that the operation is
+ * actually legal.
+ */
+inline private void
+cs_copy(gs_color_space *pcsto, const gs_color_space *pcsfrom)
+{
+ memcpy(pcsto, pcsfrom, pcsfrom->type->stype->ssize);
+}
+
+/* Copy a color space into one newly allocated by the caller. */
+void
+gs_cspace_init_from(gs_color_space * pcsto, const gs_color_space * pcsfrom)
+{
+ cs_copy(pcsto, pcsfrom);
+ (*pcsto->type->adjust_cspace_count)(pcsto, 1);
+}
+
+/* Assign a color space into a previously initialized one. */
+void
+gs_cspace_assign(gs_color_space * pdest, const gs_color_space * psrc)
+{
+ /* check for a = a */
+ if (pdest == psrc)
+ return;
+ (*psrc->type->adjust_cspace_count)(psrc, 1);
+ (*pdest->type->adjust_cspace_count)(pdest, -1);
+ cs_copy(pdest, psrc);
+}
+
+
+/* Prepare to free a color space. */
+void
+gs_cspace_release(gs_color_space * pcs)
+{
+ (*pcs->type->adjust_cspace_count)(pcs, -1);
+}
+
+/* ------ Accessors ------ */
+
+/* Get the index of a color space. */
+gs_color_space_index
+gs_color_space_get_index(const gs_color_space * pcs)
+{
+ return pcs->type->index;
+}
+
+/* Get the number of components in a color space. */
+int
+gs_color_space_num_components(const gs_color_space * pcs)
+{
+ return cs_num_components(pcs);
+}
+
+int
+gx_num_components_1(const gs_color_space * pcs)
+{
+ return 1;
+}
+int
+gx_num_components_3(const gs_color_space * pcs)
+{
+ return 3;
+}
+int
+gx_num_components_4(const gs_color_space * pcs)
+{
+ return 4;
+}
+
+/*
+ * For color spaces that have a base or alternative color space, return that
+ * color space. Otherwise return null.
+ */
+const gs_color_space *
+gs_cspace_base_space(const gs_color_space * pcspace)
+{
+ return cs_base_space(pcspace);
+}
+
+const gs_color_space *
+gx_no_base_space(const gs_color_space * pcspace)
+{
+ return NULL;
+}
+
+/* ------ Other implementation procedures ------ */
+
+/* Null color space installation procedure. */
+int
+gx_no_install_cspace(gs_color_space * pcs, gs_state * pgs)
+{
+ return 0;
+}
+
+/* Null reference count adjustment procedure. */
+void
+gx_no_adjust_cspace_count(const gs_color_space * pcs, int delta)
+{
+}
+
+/* GC procedures */
+
+#define pcs ((gs_color_space *)vptr)
+private
+ENUM_PTRS_BEGIN_PROC(color_space_enum_ptrs)
+{
+ return ENUM_USING(*pcs->type->stype, vptr, size, index);
+ ENUM_PTRS_END_PROC
+}
+private
+RELOC_PTRS_BEGIN(color_space_reloc_ptrs)
+{
+ RELOC_USING(*pcs->type->stype, vptr, size);
+}
+RELOC_PTRS_END
+#undef pcs
diff --git a/pstoraster/gscspace.h b/pstoraster/gscspace.h
new file mode 100644
index 000000000..ce66513a0
--- /dev/null
+++ b/pstoraster/gscspace.h
@@ -0,0 +1,400 @@
+/* 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$ */
+/* Client interface to color spaces */
+
+#ifndef gscspace_INCLUDED
+# define gscspace_INCLUDED
+
+#include "gsmemory.h"
+
+/*
+ * The handling of color spaces in the graphic library is somewhat
+ * awkward because of historical artifacts.
+ *
+ * The PostScript Level 1 (DeviceGray/RGB) color spaces, and the "Level
+ * 1 1/2" DeviceCMYK space, have no associated parameters. Therefore,
+ * they can be represented as simple objects (just a pointer to a type
+ * vector containing procedures and parameters). This was the original
+ * design.
+ *
+ * PostScript Level 2 and LanguageLevel 3 add two new kinds of color spaces:
+ * color spaces with parameters (CIEBased and DevicePixel spaces), and
+ * compound color spaces (Indexed, Separation, Pattern, and DeviceN spaces),
+ * which parameters that include specifying an alternate or underlying color
+ * space. To handle these spaces, we extended the original design to store
+ * scalar parameters (i.e., parameters other than the complex color
+ * transformation data for CIEBased spaces, the lookup table for Indexed
+ * spaces, and the list of component names for DeviceN spaces) in-line in
+ * the color space object. For compound spaces, this requires storing a
+ * color space in-line inside another color space, which is clearly
+ * impossible. Therefore, we defined a generality hierarchy for color
+ * spaces:
+ *
+ * - Base spaces (DeviceGray/RGB/CMYK/Pixel and CIEBased),
+ * whose parameters (if any) don't include other color spaces.
+ *
+ * - Direct spaces (base spaces + Separation and DeviceN), which
+ * may have a base space as an alternative space.
+ *
+ * - Paint spaces (direct spaces + Indexed), which may have a
+ * direct space as the underlying space.
+ *
+ * - General spaces (paint spaces + Pattern), which may have a
+ * paint space as the underlying space.
+ *
+ * With this approach, a general space can include a paint space stored
+ * in-line; a paint space (either in its own right or as the underlying
+ * space of a Pattern space) can include a direct space in-line; and a
+ * direct space can include a base space in-line.
+ *
+ * Note that because general, paint, direct, and base spaces are
+ * (necessarily) of different sizes, assigning (copying the top object of)
+ * color spaces must take into account the actual size of the color space
+ * being assigned. In principle, this also requires checking that the
+ * source object will actually fit into the destination. Currently we rely
+ * on the caller to ensure that this is the case; in fact, the current API
+ * (gs_cspace_init and gs_cspace_assign) doesn't even provide enough
+ * information to make the check.
+ *
+ * In retrospect, we might have gotten a simpler design without significant
+ * performance loss by always referencing underlying and alternate spaces
+ * through a pointer; however, at this point, the cost and risk of changing
+ * to such a design are too high.
+ *
+ * There are two aspects to memory management for color spaces: managing
+ * the color space objects themselves, and managing the non-scalar
+ * parameters that they reference (if any).
+ *
+ * - Color space objects per se have no special management properties:
+ * they can be allocated on the stack or on the heap, and freed by
+ * scope exit, explicit deallocation, or garbage collection.
+ *
+ * - Separately allocated (non-scalar) color space parameters are
+ * managed by reference counting. Currently we do this for the
+ * CIEBased spaces, and for the first-level parameters of Indexed and
+ * Separation spaces: clients must deal with deallocating the other
+ * parameter structures mentioned above, including the Indexed lookup
+ * table if any. This is clearly not a good situation, but we don't
+ * envision fixing it any time soon.
+ *
+ * Here is the information associated with the various color space
+ * structures. Note that DevicePixel, DeviceN, and the ability to use
+ * Separation or DeviceN spaces as the base space of an Indexed space
+ * are LanguageLevel 3 additions. Unfortunately, the terminology for the
+ * different levels of generality is confusing and inconsistent for
+ * historical reasons.
+ *
+ * For base spaces:
+ *
+ * Space Space parameters Color parameters
+ * ----- ---------------- ----------------
+ * DeviceGray (none) 1 real [0-1]
+ * DeviceRGB (none) 3 reals [0-1]
+ * DeviceCMYK (none) 4 reals [0-1]
+ * DevicePixel depth 1 int [up to depth bits]
+ * CIEBasedDEFG dictionary 4 reals
+ * CIEBasedDEF dictionary 3 reals
+ * CIEBasedABC dictionary 3 reals
+ * CIEBasedA dictionary 1 real
+ *
+ * For non-base direct spaces:
+ *
+ * Space Space parameters Color parameters
+ * ----- ---------------- ----------------
+ *
+ * Separation name, alt_space, tint_xform 1 real [0-1]
+ * DeviceN names, alt_space, tint_xform N reals
+ *
+ * For non-direct paint spaces:
+ *
+ * Space Space parameters Color parameters
+ * ----- ---------------- ----------------
+ * Indexed base_space, hival, lookup 1 int [0-hival]
+ *
+ * For non-paint spaces:
+ *
+ * Space Space parameters Color parameters
+ * ----- ---------------- ----------------
+ * Pattern colored: (none) dictionary
+ * uncolored: base_space dictionary + base space params */
+
+/* Color space type indices */
+typedef enum {
+
+ /* Supported in all configurations */
+ gs_color_space_index_DeviceGray = 0,
+ gs_color_space_index_DeviceRGB,
+
+ /* Supported in extended Level 1, and in Level 2 and above */
+ gs_color_space_index_DeviceCMYK,
+
+ /* Supported in LanguageLevel 3 only */
+ gs_color_space_index_DevicePixel,
+ gs_color_space_index_DeviceN,
+
+ /* Supported in Level 2 and above only */
+ /* DEC C truncates identifiers at 32 characters, so.... */
+ gs_color_space_index_CIEDEFG,
+ gs_color_space_index_CIEDEF,
+ gs_color_space_index_CIEABC,
+ gs_color_space_index_CIEA,
+ gs_color_space_index_Separation,
+ gs_color_space_index_Indexed,
+ gs_color_space_index_Pattern
+
+} gs_color_space_index;
+
+/* Define an abstract type for color space types (method structures). */
+typedef struct gs_color_space_type_s gs_color_space_type;
+
+/*
+ * The common part of all color spaces. This structure now includes a memory
+ * structure pointer, so that it may be released without providing this
+ * information separately. (type is a pointer to the structure of methods.)
+ *
+ * Note that all color space structures consist of the basic information and
+ * a union containing some additional information. The macro operand is that
+ * union.
+ */
+#define gs_cspace_common(param_union) \
+ const gs_color_space_type * type; \
+ gs_memory_t * pmem; \
+ union { \
+ param_union; \
+ } params
+
+/*
+ * Parameters for base color spaces. Of the base color spaces, only
+ * DevicePixel and CIE spaces have parameters: see gscie.h for the structure
+ * definitions for CIE space parameters.
+ */
+typedef struct gs_device_pixel_params_s {
+ int depth;
+} gs_device_pixel_params;
+typedef struct gs_cie_a_s gs_cie_a;
+typedef struct gs_cie_abc_s gs_cie_abc;
+typedef struct gs_cie_def_s gs_cie_def;
+typedef struct gs_cie_defg_s gs_cie_defg;
+
+#define gs_base_cspace_params \
+ gs_device_pixel_params pixel; \
+ gs_cie_defg * defg; \
+ gs_cie_def * def; \
+ gs_cie_abc * abc; \
+ gs_cie_a * a
+
+typedef struct gs_base_color_space_s {
+ gs_cspace_common(gs_base_cspace_params);
+} gs_base_color_space;
+
+#define gs_base_color_space_size sizeof(gs_base_color_space)
+
+/*
+ * Non-base direct color spaces: Separation and DeviceN spaces.
+ * These include a base alternative color space.
+ */
+typedef ulong gs_separation_name; /* BOGUS */
+typedef struct gs_indexed_map_s gs_indexed_map;
+
+typedef struct gs_separation_params_s {
+ gs_separation_name sname;
+ gs_base_color_space alt_space;
+ gs_indexed_map *map;
+} gs_separation_params;
+
+typedef struct gs_device_n_params_s gs_device_n_params;
+struct gs_device_n_params_s {
+ gs_separation_name *names;
+ uint num_components;
+ gs_base_color_space alt_space;
+ int (*tint_transform)
+ (P4(const gs_device_n_params * params, const float *in, float *out,
+ void *data));
+ void *tint_transform_data;
+};
+
+#define gs_direct_cspace_params \
+ gs_base_cspace_params; \
+ gs_separation_params separation; \
+ gs_device_n_params device_n
+
+typedef struct gs_direct_color_space_s {
+ gs_cspace_common(gs_direct_cspace_params);
+} gs_direct_color_space;
+
+#define gs_direct_color_space_size sizeof(gs_direct_color_space)
+
+/*
+ * Non-direct paint space: Indexed space.
+ *
+ * Note that for indexed color spaces, hival is the highest support index,
+ * which is one less than the number of entries in the palette (as defined
+ * in PostScript).
+ */
+
+typedef struct gs_indexed_params_s {
+ gs_direct_color_space base_space;
+ int hival; /* num_entries - 1 */
+ union {
+ gs_const_string table; /* size is implicit */
+ gs_indexed_map *map;
+ } lookup;
+ bool use_proc; /* 0 = use table, 1 = use proc & map */
+} gs_indexed_params;
+
+#define gs_paint_cspace_params \
+ gs_direct_cspace_params; \
+ gs_indexed_params indexed
+
+typedef struct gs_paint_color_space_s {
+ gs_cspace_common(gs_paint_cspace_params);
+} gs_paint_color_space;
+
+#define gs_paint_color_space_size sizeof(gs_paint_color_space)
+
+/*
+ * Pattern parameter set. This may contain an instances of a paintable
+ * color space. The boolean indicates if this is the case.
+ */
+typedef struct gs_pattern_params_s {
+ bool has_base_space;
+ gs_paint_color_space base_space;
+} gs_pattern_params;
+
+/*
+ * Fully general color spaces.
+ */
+struct gs_color_space_s {
+ gs_cspace_common(
+ gs_paint_cspace_params;
+ gs_pattern_params pattern
+ );
+};
+
+#define gs_pattern_color_space_size sizeof(gs_color_space)
+
+/*
+ * Define the abstract type for color space objects.
+ */
+#ifndef gs_color_space_DEFINED
+# define gs_color_space_DEFINED
+typedef struct gs_color_space_s gs_color_space;
+#endif
+
+ /*extern_st(st_color_space); *//* in gxcspace.h */
+#define public_st_color_space() /* in gscspace.c */ \
+ gs_public_st_composite( st_color_space, \
+ gs_color_space, \
+ "gs_color_space", \
+ color_space_enum_ptrs, \
+ color_space_reloc_ptrs \
+ )
+
+#define st_color_space_max_ptrs 2 /* 1 base + 1 indexed */
+
+/* ---------------- Procedures ---------------- */
+
+/* ------ Create/copy/destroy ------ */
+
+/*
+ * Note that many of the constructors take no parameters, and the
+ * remainder take only a few (CIE color spaces constructures take a
+ * client data pointer as an operand, the composite color space (Separation,
+ * Indexed, and Pattern) constructurs take the base space as an operand,
+ * and the Indexed color space constructors have a few additiona operands).
+ * This is done to conserve memory. If initialization values for all the
+ * color space parameters were provided to the constructors, these values
+ * would need to have some fairly generic format. Different clients gather
+ * this data in different forms, so they would need to allocate memory to
+ * convert it to the generic form, only to immediately release this memory
+ * once the construction is complete.
+ *
+ * The alternative approach employed here is to provide a number of access
+ * methods (macros) that return pointers to individual fields of the
+ * various color space structures. This requires exporting only fairly simple
+ * data structures, and so does not violate modularity too severely.
+ *
+ * NB: Of necessity, the macros provide access to modifiable structures. If
+ * these structures are modified after the color space object is first
+ * initialized, unpredictable and, most likely, undesirable results will
+ * occur.
+ *
+ * The constructors will return an integer, which is 0 on success and an
+ * error code on failure (gs_error_VMerror or gs_error_rangecheck).
+ */
+
+extern int
+ gs_cspace_build_DeviceGray(P2(gs_color_space ** ppcspace,
+ gs_memory_t * pmem)),
+ gs_cspace_build_DeviceRGB(P2(gs_color_space ** ppcspace,
+ gs_memory_t * pmem)),
+ gs_cspace_build_DeviceCMYK(P2(gs_color_space ** ppcspace,
+ gs_memory_t * pmem));
+
+/*
+ * We preallocate instances of the 3 device color spaces, and provide
+ * procedures that return them. Note that gs_cspace_DeviceCMYK() is
+ * defined even if CMYK color support is not included in this configuration.
+ */
+#ifndef gs_imager_state_DEFINED
+# define gs_imager_state_DEFINED
+typedef struct gs_imager_state_s gs_imager_state;
+#endif
+
+const gs_color_space * gs_cspace_DeviceGray(P1(const gs_imager_state * pis));
+const gs_color_space * gs_cspace_DeviceRGB(P1(const gs_imager_state * pis));
+const gs_color_space * gs_cspace_DeviceCMYK(P1(const gs_imager_state * pis));
+
+/* Copy a color space into one newly allocated by the caller. */
+void gs_cspace_init_from(P2(gs_color_space * pcsto,
+ const gs_color_space * pcsfrom));
+
+/* Assign a color space into a previously initialized one. */
+void cs_cspace_assign(P2(gs_color_space * pdest, const gs_color_space * psrc));
+
+/* Prepare to free a color space. */
+void gs_cspace_release(P1(gs_color_space * pcs));
+
+/* ------ Accessors ------ */
+
+/* Get the index of a color space. */
+gs_color_space_index gs_color_space_get_index(P1(const gs_color_space *));
+
+/* Get the number of components in a color space. */
+int gs_color_space_num_components(P1(const gs_color_space *));
+
+/*
+ * Get the base space of an Indexed or uncolored Pattern color space, or the
+ * alternate space of a Separation or DeviceN space. Return NULL if the
+ * color space does not have a base/alternative color space.
+ */
+const gs_color_space *gs_cspace_base_space(P1(const gs_color_space * pcspace));
+
+/* backwards compatibility */
+#define gs_color_space_indexed_base_space(pcspace)\
+ gs_cspace_base_space(pcspace)
+
+#endif /* gscspace_INCLUDED */
diff --git a/pstoraster/gsdcolor.h b/pstoraster/gsdcolor.h
new file mode 100644
index 000000000..3e0fae30d
--- /dev/null
+++ b/pstoraster/gsdcolor.h
@@ -0,0 +1,332 @@
+/* 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 color representation for drivers */
+
+#ifndef gsdcolor_INCLUDED
+# define gsdcolor_INCLUDED
+
+#include "gsccolor.h"
+#include "gxarith.h" /* for imod */
+#include "gxbitmap.h"
+#include "gxhttile.h"
+#include "gxcindex.h"
+
+#ifndef gx_device_color_DEFINED
+# define gx_device_color_DEFINED
+typedef struct gx_device_color_s gx_device_color;
+
+#endif
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * The definitions in the following section of the file are the only
+ * ones that should be used by read-only clients such as implementors
+ * of high-level driver functions.
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * A device color consists of a base color and an optional (tiled) mask.
+ * The base color may be a pure color, a binary halftone, or a colored
+ * bitmap (color halftone or colored Pattern). The mask is used for
+ * both colored and uncolored Patterns.
+ */
+
+/* Accessing a pure color. */
+#define gx_dc_is_pure(pdc)\
+ ((pdc)->type == gx_dc_type_pure)
+#define gx_dc_writes_pure(pdc, lop)\
+ (gx_dc_is_pure(pdc) && lop_no_S_is_T(lop))
+#define gx_dc_pure_color(pdc)\
+ ((pdc)->colors.pure)
+
+/* Accessing the phase of a halftone. */
+#define gx_dc_phase(pdc)\
+ ((pdc)->phase)
+
+/* Accessing a binary halftone. */
+#define gx_dc_is_binary_halftone(pdc)\
+ ((pdc)->type == gx_dc_type_ht_binary)
+#define gx_dc_binary_tile(pdc)\
+ (&(pdc)->colors.binary.b_tile->tiles)
+#define gx_dc_binary_color0(pdc)\
+ ((pdc)->colors.binary.color[0])
+#define gx_dc_binary_color1(pdc)\
+ ((pdc)->colors.binary.color[1])
+
+/* Accessing a colored halftone. */
+#define gx_dc_is_colored_halftone(pdc)\
+ ((pdc)->type == gx_dc_type_ht_colored)
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * The definitions in the following section of the file, plus the ones
+ * just above, are the only ones that should be used by clients that
+ * set as well as read device colors.
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#define color_is_set(pdc)\
+ ((pdc)->type != gx_dc_type_none)
+#define color_unset(pdc)\
+ ((pdc)->type = gx_dc_type_none)
+
+#define gx_dc_is_null(pdc)\
+ ((pdc)->type == gx_dc_type_null)
+#define color_is_null(pdc) gx_dc_is_null(pdc)
+#define color_set_null(pdc)\
+ ((pdc)->type = gx_dc_type_null)
+
+#define color_is_pure(pdc) gx_dc_is_pure(pdc)
+#define color_writes_pure(pdc, lop) gx_dc_writes_pure(pdc, lop)
+#define color_set_pure(pdc, color)\
+ ((pdc)->colors.pure = (color),\
+ (pdc)->type = gx_dc_type_pure)
+
+/* Set the phase to an offset from the tile origin. */
+#define color_set_phase(pdc, px, py)\
+ ((pdc)->phase.x = (px),\
+ (pdc)->phase.y = (py))
+/* Set the phase from the halftone phase in a graphics state. */
+#define color_set_phase_mod(pdc, px, py, tw, th)\
+ color_set_phase(pdc, imod(-(px), tw), imod(-(py), th))
+
+#define color_is_binary_halftone(pdc) gx_dc_is_binary_halftone(pdc)
+#define color_set_binary_halftone(pdc, ht, color0, color1, level)\
+ ((pdc)->colors.binary.b_ht = (ht),\
+ (pdc)->colors.binary.color[0] = (color0),\
+ (pdc)->colors.binary.color[1] = (color1),\
+ (pdc)->colors.binary.b_level = (level),\
+ (pdc)->type = gx_dc_type_ht_binary)
+#define color_set_binary_tile(pdc, color0, color1, tile)\
+ ((pdc)->colors.binary.b_ht = 0,\
+ (pdc)->colors.binary.color[0] = (color0),\
+ (pdc)->colors.binary.color[1] = (color1),\
+ (pdc)->colors.binary.b_tile = (tile),\
+ (pdc)->type = gx_dc_type_ht_binary)
+
+#define color_is_colored_halftone(pdc) gx_dc_is_colored_halftone(pdc)
+#define _color_set_c(pdc, i, b, l)\
+ ((pdc)->colors.colored.c_base[i] = (b),\
+ (pdc)->colors.colored.c_level[i] = (l))
+#define color_set_rgb_halftone(pdc, ht, br, lr, bg, lg, bb, lb, a)\
+ ((pdc)->colors.colored.c_ht = (ht),\
+ _color_set_c(pdc, 0, br, lr),\
+ _color_set_c(pdc, 1, bg, lg),\
+ _color_set_c(pdc, 2, bb, lb),\
+ (pdc)->colors.colored.alpha = (a),\
+ (pdc)->type = gx_dc_type_ht_colored)
+/* Some special clients set the individual components separately. */
+#define color_finish_set_cmyk_halftone(pdc, ht)\
+ ((pdc)->colors.colored.c_ht = (ht),\
+ (pdc)->colors.colored.alpha = max_ushort,\
+ (pdc)->type = gx_dc_type_ht_colored)
+#define color_set_cmyk_halftone(pdc, ht, bc, lc, bm, lm, by, ly, bk, lk)\
+ (_color_set_c(pdc, 0, bc, lc),\
+ _color_set_c(pdc, 1, bm, lm),\
+ _color_set_c(pdc, 2, by, ly),\
+ _color_set_c(pdc, 3, bk, lk),\
+ color_finish_set_cmyk_halftone(pdc, ht))
+
+/* Note that color_set_null_pattern doesn't set mask.ccolor. */
+#define color_set_null_pattern(pdc)\
+ ((pdc)->mask.id = gx_no_bitmap_id,\
+ (pdc)->mask.m_tile = 0,\
+ (pdc)->colors.pattern.p_tile = 0,\
+ (pdc)->type = gx_dc_type_pattern)
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * The remaining definitions are internal ones that are included in this
+ * file only because C's abstraction mechanisms aren't strong enough to
+ * allow us to keep them separate and still have in-line access to the
+ * commonly used members.
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Define opaque types for objects referenced by device colors. */
+
+#ifndef gx_ht_tile_DEFINED
+# define gx_ht_tile_DEFINED
+typedef struct gx_ht_tile_s gx_ht_tile;
+
+#endif
+
+#ifndef gx_device_halftone_DEFINED
+# define gx_device_halftone_DEFINED
+typedef struct gx_device_halftone_s gx_device_halftone;
+
+#endif
+
+#ifndef gx_color_tile_DEFINED
+# define gx_color_tile_DEFINED
+typedef struct gx_color_tile_s gx_color_tile;
+
+#endif
+
+/*
+ * The device color in the graphics state is computed from client color
+ * specifications, and kept current through changes in transfer function,
+ * device, and (if relevant) halftone phase.
+ * (gx_set_dev_color sets the device color if needed.)
+ * For binary halftones (and eventually colored halftones as well),
+ * the bitmaps are only cached, so internal clients (the painting operators)
+ * must call gx_color_load to ensure that the bitmap is available.
+ * Device color elements set by gx_color_load are marked with @ below.
+ *
+ * Base colors are represented as follows:
+ *
+ * Pure color (gx_dc_pure):
+ * colors.pure = the color;
+ * Binary halftone (gx_dc_ht_binary):
+ * colors.binary.b_ht = the device halftone;
+ * colors.binary.color[0] = the color for 0s (darker);
+ * colors.binary.color[1] = the color for 1s (lighter);
+ * colors.binary.b_level = the number of pixels to lighten,
+ * 0 < halftone_level < P, the number of pixels in the tile;
+ * @ colors.binary.b_tile points to an entry in the binary
+ * tile cache.
+ * Colored halftone (gx_dc_ht_colored):
+ * colors.colored.c_ht = the device halftone;
+ * colors.colored.c_level[0..N-1] = the halftone levels,
+ * like b_level;
+ * colors.colored.c_base[0..N-1] = the base colors;
+ * N=3 for RGB devices, 4 for CMYK devices;
+ * 0 <= c_level[i] < P;
+ * 0 <= c_base[i] <= dither_rgb;
+ * colors.colored.alpha = the opacity.
+ * Colored pattern (gx_dc_pattern):
+ * (mask is also set, see below)
+ * @ colors.pattern.p_tile points to a gx_color_tile in
+ * the pattern cache, or is NULL for a null pattern.
+ *
+ * The phase element is used for all colors except pure ones. It holds the
+ * negative of the graphics state halftone phase, modulo the halftone tile
+ * size.
+ *
+ * The mask elements of a device color are only used for patterns:
+ * Non-pattern:
+ * mask is unused.
+ * Pattern:
+ * mask.ccolor gives the original Pattern color (needed for
+ * reloading the pattern cache);
+ * mask.id gives the ID of the pattern (and its mask);
+ * mask.m_phase holds the negative of the graphics state
+ * halftone phase;
+ * @ mask.m_tile points to a gx_color_tile in the pattern cache,
+ * or is NULL for a pattern that doesn't require a mask.
+ * (The 'bits' of the tile are not accessed.)
+ * For colored patterns requiring a mask, p_tile and
+ * mask.m_tile point to the same cache entry.
+ * For masked colors, gx_set_dev_color replaces the type with a different
+ * type that applies the mask when painting. These types are not defined
+ * here, because they are only used in Level 2.
+ */
+
+/* Define the (opaque) type for device color types. */
+/* The name is an unfortunate anachronism. */
+typedef struct gx_device_color_type_s gx_device_color_type_t;
+typedef const gx_device_color_type_t *gx_device_color_type;
+
+struct gx_device_color_s {
+ /*
+ * Since some compilers don't allow static initialization of a
+ * union, we put the type first.
+ */
+ gx_device_color_type type;
+ /*
+ * See the comment above for descriptions of the members. We use
+ * b_, c_, and p_ member names because some old compilers don't
+ * allow the same name to be used for two different structure
+ * members even when it's unambiguous.
+ */
+ union _c {
+ gx_color_index pure;
+ struct _bin {
+ const gx_device_halftone *b_ht;
+ gx_color_index color[2];
+ uint b_level;
+ gx_ht_tile *b_tile;
+ } binary;
+ struct _col {
+ const gx_device_halftone *c_ht;
+ byte c_base[4];
+ uint c_level[4];
+ ushort /*gx_color_value */ alpha;
+ } colored;
+ struct _pat {
+ gx_color_tile *p_tile;
+ } /*(colored) */ pattern;
+ } colors;
+ gs_int_point phase;
+ struct _mask {
+ gs_client_color ccolor; /* needed for remapping pattern */
+ struct mp_ {
+ short x, y;
+ } m_phase;
+ gx_bitmap_id id;
+ gx_color_tile *m_tile;
+ } mask;
+};
+
+/*extern_st(st_device_color); *//* in gxdcolor.h */
+#define public_st_device_color() /* in gxcmap.c */\
+ gs_public_st_composite(st_device_color, gx_device_color, "gx_device_color",\
+ device_color_enum_ptrs, device_color_reloc_ptrs)
+#define st_device_color_max_ptrs 2
+
+/*
+ * Define the standard device color types.
+ * We define them here as pointers to the real types only because a few
+ * C compilers don't allow declaring externs with abstract struct types;
+ * we redefine them as macros in gxdcolor.h where the concrete type for
+ * gx_device_color_procs is available.
+ * We spell out the definition of gx_device_color type because some
+ * C compilers can't handle the typedef correctly.
+ */
+#ifndef gx_dc_type_none
+extern const gx_device_color_type_t *const gx_dc_type_none; /* gxdcolor.c */
+
+#endif
+#ifndef gx_dc_type_null
+extern const gx_device_color_type_t *const gx_dc_type_null; /* gxdcolor.c */
+
+#endif
+#ifndef gx_dc_type_pure
+extern const gx_device_color_type_t *const gx_dc_type_pure; /* gxdcolor.c */
+
+#endif
+ /*
+ * We don't declare gx_dc_pattern here, so as not to create
+ * a spurious external reference in Level 1 systems.
+ */
+#ifndef gx_dc_type_pattern
+ /*extern const gx_device_color_type_t * const gx_dc_type_pattern; *//* gspcolor.c */
+#endif
+#ifndef gx_dc_type_ht_binary
+extern const gx_device_color_type_t *const gx_dc_type_ht_binary; /* gxht.c */
+
+#endif
+#ifndef gx_dc_type_ht_colored
+extern const gx_device_color_type_t *const gx_dc_type_ht_colored; /* gxcht.c */
+
+#endif
+
+#endif /* gsdcolor_INCLUDED */
diff --git a/pstoraster/gsdevice.c b/pstoraster/gsdevice.c
new file mode 100644
index 000000000..ef73fd73d
--- /dev/null
+++ b/pstoraster/gsdevice.c
@@ -0,0 +1,570 @@
+/*
+ Copyright 1993-2002 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$ */
+/* Device operators for Ghostscript library */
+#include "ctype_.h"
+#include "memory_.h" /* for memcpy */
+#include "string_.h"
+#include "gx.h"
+#include "gscdefs.h" /* for gs_lib_device_list */
+#include "gserrors.h"
+#include "gp.h"
+#include "gsstruct.h"
+#include "gspath.h" /* gs_initclip prototype */
+#include "gspaint.h" /* gs_erasepage prototype */
+#include "gsmatrix.h" /* for gscoord.h */
+#include "gscoord.h" /* for gs_initmatrix */
+#include "gzstate.h"
+#include "gxcmap.h"
+#include "gxdevice.h"
+#include "gxdevmem.h"
+
+/* Include the extern for the device list. */
+extern_gs_lib_device_list();
+
+/* Finalization for devices: close the device if it is open. */
+void
+gx_device_finalize(void *vptr)
+{
+ discard(gs_closedevice((gx_device *) vptr));
+}
+
+/* GC procedures */
+#define fdev ((gx_device_forward *)vptr)
+private
+ENUM_PTRS_BEGIN(device_forward_enum_ptrs) return 0;
+
+case 0:
+ENUM_RETURN(gx_device_enum_ptr(fdev->target));
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(device_forward_reloc_ptrs)
+{
+ fdev->target = gx_device_reloc_ptr(fdev->target, gcst);
+}
+RELOC_PTRS_END
+#undef fdev
+
+/*
+ * Structure descriptors. These must follow the procedures, because
+ * we can't conveniently forward-declare the procedures.
+ * (See gxdevice.h for details.)
+ */
+public_st_device();
+public_st_device_forward();
+public_st_device_null();
+/* A fake descriptor for devices whose descriptor we can't find. */
+gs_private_st_complex_only(st_device_unknown, byte, "gx_device(unknown)",
+ 0, gs_no_struct_enum_ptrs, gs_no_struct_reloc_ptrs, gx_device_finalize);
+
+/* GC utilities */
+/* Enumerate or relocate a device pointer for a client. */
+gx_device *
+gx_device_enum_ptr(gx_device * dev)
+{
+ if (dev == 0 || dev->memory == 0)
+ return 0;
+ return dev;
+}
+gx_device *
+gx_device_reloc_ptr(gx_device * dev, gc_state_t * gcst)
+{
+ if (dev == 0 || dev->memory == 0)
+ return dev;
+ return RELOC_OBJ(dev); /* gcst implicit */
+}
+
+/* Set up the device procedures in the device structure. */
+/* Also copy old fields to new ones. */
+void
+gx_device_set_procs(gx_device * dev)
+{
+ if (dev->static_procs != 0) { /* 0 if already populated */
+ dev->procs = *dev->static_procs;
+ dev->static_procs = 0;
+ }
+}
+
+/* Flush buffered output to the device */
+int
+gs_flushpage(gs_state * pgs)
+{
+ gx_device *dev = gs_currentdevice(pgs);
+
+ return (*dev_proc(dev, sync_output)) (dev);
+}
+
+/* Make the device output the accumulated page description */
+int
+gs_copypage(gs_state * pgs)
+{
+ return gs_output_page(pgs, 1, 0);
+}
+int
+gs_output_page(gs_state * pgs, int num_copies, int flush)
+{
+ gx_device *dev = gs_currentdevice(pgs);
+ int code;
+
+ if (dev->IgnoreNumCopies)
+ num_copies = 1;
+ code = (*dev_proc(dev, output_page)) (dev, num_copies, flush);
+ if (code >= 0)
+ dev->PageCount += num_copies;
+ return code;
+}
+
+/* Copy scan lines from an image device */
+int
+gs_copyscanlines(gx_device * dev, int start_y, byte * data, uint size,
+ int *plines_copied, uint * pbytes_copied)
+{
+ uint line_size = gx_device_raster(dev, 0);
+ uint count = size / line_size;
+ uint i;
+ byte *dest = data;
+
+ for (i = 0; i < count; i++, dest += line_size) {
+ int code = (*dev_proc(dev, get_bits)) (dev, start_y + i, dest, NULL);
+
+ if (code < 0) {
+ /* Might just be an overrun. */
+ if (start_y + i == dev->height)
+ break;
+ return_error(code);
+ }
+ }
+ if (plines_copied != NULL)
+ *plines_copied = i;
+ if (pbytes_copied != NULL)
+ *pbytes_copied = i * line_size;
+ return 0;
+}
+
+/* Get the current device from the graphics state. */
+gx_device *
+gs_currentdevice(const gs_state * pgs)
+{
+ return pgs->device;
+}
+
+/* Get the name of a device. */
+const char *
+gs_devicename(const gx_device * dev)
+{
+ return dev->dname;
+}
+
+/* Get the initial matrix of a device. */
+void
+gs_deviceinitialmatrix(gx_device * dev, gs_matrix * pmat)
+{
+ fill_dev_proc(dev, get_initial_matrix, gx_default_get_initial_matrix);
+ (*dev_proc(dev, get_initial_matrix)) (dev, pmat);
+}
+
+/* Get the N'th device from the known device list */
+const gx_device *
+gs_getdevice(int index)
+{
+ const gx_device *const *list;
+ int count = gs_lib_device_list(&list, NULL);
+
+ if (index < 0 || index >= count)
+ return 0; /* index out of range */
+ return list[index];
+}
+
+/* Fill in the GC structure descriptor for a device. */
+/* This is only called during initialization. */
+void
+gx_device_make_struct_type(gs_memory_struct_type_t *st,
+ const gx_device *dev)
+{
+ const gx_device_procs *procs = dev->static_procs;
+ bool forward = false;
+
+ /*
+ * Try to figure out whether this is a forwarding device. All
+ * printer devices, and no other devices, have a null fill_rectangle
+ * procedure; for other devices, we look for a likely forwarding
+ * procedure in the vector. The algorithm isn't foolproof, but it's
+ * the best we can come up with.
+ */
+ if (procs == 0)
+ procs = &dev->procs;
+ if (procs->fill_rectangle == 0 ||
+ procs->get_xfont_procs == gx_forward_get_xfont_procs
+ )
+ forward = true;
+ if (forward)
+ *st = st_device_forward;
+ else
+ *st = st_device;
+ st->ssize = dev->params_size;
+}
+
+/* Clone an existing device. */
+int
+gs_copydevice(gx_device ** pnew_dev, const gx_device * dev, gs_memory_t * mem)
+{
+ gx_device *new_dev;
+ const gs_memory_struct_type_t *std = dev->stype;
+
+ /*
+ * Because command list devices have complicated internal pointer
+ * structures, we allocate all device instances as immovable.
+ */
+ if (std == 0) {
+ /*
+ * This is the statically allocated prototype. Find its
+ * structure descriptor.
+ */
+ const gx_device *const *list;
+ gs_memory_struct_type_t *st;
+ int count = gs_lib_device_list(&list, &st);
+ int i;
+
+ for (i = 0; list[i] != dev; ++i)
+ if (i == count) {
+ /*
+ * We can't find a structure descriptor for this device.
+ * Allocate it as bytes and hope for the best.
+ */
+ std = &st_device_unknown;
+ new_dev =
+ gs_alloc_struct_array_immovable(mem, dev->params_size,
+ gx_device, std,
+ "gs_copydevice(unknown)");
+ goto out;
+ }
+ std = st + i;
+ }
+ new_dev = gs_alloc_struct_immovable(mem, gx_device, std,
+ "gs_copydevice");
+out:
+ if (new_dev == 0)
+ return_error(gs_error_VMerror);
+ gx_device_init(new_dev, dev, mem, false);
+ new_dev->stype = std;
+ new_dev->is_open = false;
+ *pnew_dev = new_dev;
+ return 0;
+}
+
+/* Set the device in the graphics state */
+int
+gs_setdevice(gs_state * pgs, gx_device * dev)
+{
+ int code = gs_setdevice_no_erase(pgs, dev);
+
+ if (code == 1)
+ code = gs_erasepage(pgs);
+ return code;
+}
+int
+gs_setdevice_no_erase(gs_state * pgs, gx_device * dev)
+{
+ bool was_open = dev->is_open;
+ int code;
+
+ /* Initialize the device */
+ if (!was_open) {
+ gx_device_fill_in_procs(dev);
+ if (gs_device_is_memory(dev)) {
+ /* Set the target to the current device. */
+ gx_device *odev = gs_currentdevice_inline(pgs);
+
+ while (odev != 0 && gs_device_is_memory(odev))
+ odev = ((gx_device_memory *)odev)->target;
+ rc_assign(((gx_device_memory *)dev)->target, odev,
+ "set memory device(target)");
+ }
+ code = (*dev_proc(dev, open_device)) (dev);
+ if (code < 0)
+ return_error(code);
+ dev->is_open = true;
+ }
+ gs_setdevice_no_init(pgs, dev);
+ pgs->ctm_default_set = false;
+ if ((code = gs_initmatrix(pgs)) < 0 ||
+ (code = gs_initclip(pgs)) < 0
+ )
+ return code;
+ /* If we were in a charpath or a setcachedevice, */
+ /* we aren't any longer. */
+ pgs->in_cachedevice = 0;
+ pgs->in_charpath = (gs_char_path_mode) 0;
+ return (was_open ? 0 : 1);
+}
+int
+gs_setdevice_no_init(gs_state * pgs, gx_device * dev)
+{
+ /*
+ * Just set the device, possibly changing color space but no other
+ * device parameters.
+ */
+ rc_assign(pgs->device, dev, "gs_setdevice_no_init");
+ gx_set_cmap_procs((gs_imager_state *) pgs, dev);
+ gx_unset_dev_color(pgs);
+ return 0;
+}
+
+/* Initialize a just-allocated device. */
+void
+gx_device_init(gx_device * dev, const gx_device * proto, gs_memory_t * mem,
+ bool internal)
+{
+ memcpy(dev, proto, proto->params_size);
+ dev->memory = mem;
+ rc_init(dev, mem, (internal ? 0 : 1));
+}
+
+/* Make a null device. */
+void
+gs_make_null_device(gx_device_null * dev, gs_memory_t * mem)
+{
+ gx_device_init((gx_device *) dev, (const gx_device *)&gs_null_device,
+ mem, true);
+}
+
+/* Select a null device. */
+int
+gs_nulldevice(gs_state * pgs)
+{
+ if (pgs->device == 0 || !gx_device_is_null(pgs->device)) {
+ gx_device *ndev;
+ int code = gs_copydevice(&ndev, (gx_device *) & gs_null_device,
+ pgs->memory);
+
+ if (code < 0)
+ return code;
+ /*
+ * Internal devices have a reference count of 0, not 1,
+ * aside from references from graphics states.
+ */
+ rc_init(ndev, pgs->memory, 0);
+ return gs_setdevice_no_erase(pgs, ndev);
+ }
+ return 0;
+}
+
+/* Close a device. The client is responsible for ensuring that */
+/* this device is not current in any graphics state. */
+int
+gs_closedevice(gx_device * dev)
+{
+ int code = 0;
+
+ if (dev->is_open) {
+ code = (*dev_proc(dev, close_device)) (dev);
+ if (code < 0)
+ return_error(code);
+ dev->is_open = false;
+ }
+ return code;
+}
+
+/*
+ * Just set the device without any reinitializing.
+ * (For internal use only.)
+ */
+void
+gx_set_device_only(gs_state * pgs, gx_device * dev)
+{
+ rc_assign(pgs->device, dev, "gx_set_device_only");
+}
+
+/* Compute the size of one scan line for a device, */
+/* with or without padding to a word boundary. */
+uint
+gx_device_raster(const gx_device * dev, bool pad)
+{
+ ulong bits = (ulong) dev->width * dev->color_info.depth;
+
+ return (pad ? bitmap_raster(bits) : (uint) ((bits + 7) >> 3));
+}
+
+/* Adjust the resolution for devices that only have a fixed set of */
+/* geometries, so that the apparent size in inches remains constant. */
+/* If fit=1, the resolution is adjusted so that the entire image fits; */
+/* if fit=0, one dimension fits, but the other one is clipped. */
+int
+gx_device_adjust_resolution(gx_device * dev,
+ int actual_width, int actual_height, int fit)
+{
+ double width_ratio = (double)actual_width / dev->width;
+ double height_ratio = (double)actual_height / dev->height;
+ double ratio =
+ (fit ? min(width_ratio, height_ratio) :
+ max(width_ratio, height_ratio));
+
+ dev->x_pixels_per_inch *= ratio;
+ dev->y_pixels_per_inch *= ratio;
+ gx_device_set_width_height(dev, actual_width, actual_height);
+ return 0;
+}
+
+/* Set the HWMargins to values defined in inches. */
+/* If move_origin is true, also reset the Margins. */
+/* Note that this assumes a printer-type device (Y axis inverted). */
+void
+gx_device_set_margins(gx_device * dev, const float *margins /*[4] */ ,
+ bool move_origin)
+{
+ int i;
+
+ for (i = 0; i < 4; ++i)
+ dev->HWMargins[i] = margins[i] * 72.0;
+ if (move_origin) {
+ dev->Margins[0] = -margins[0] * dev->MarginsHWResolution[0];
+ dev->Margins[1] = -margins[3] * dev->MarginsHWResolution[1];
+ }
+
+ dev->width = (dev->PageSize[0] - dev->HWMargins[0] - dev->HWMargins[2]) *
+ dev->x_pixels_per_inch / 72.0 + 0.5;
+ dev->height = (dev->PageSize[1] - dev->HWMargins[1] - dev->HWMargins[3]) *
+ dev->y_pixels_per_inch / 72.0 + 0.5;
+}
+
+/* Set the width and height, updating PageSize to remain consistent. */
+void
+gx_device_set_width_height(gx_device * dev, int width, int height)
+{
+ dev->width = width - dev->x_pixels_per_inch *
+ (dev->HWMargins[0] + dev->HWMargins[2]) / 72.0;
+ dev->height = height - dev->y_pixels_per_inch *
+ (dev->HWMargins[1] + dev->HWMargins[3]) / 72.0;
+ dev->PageSize[0] = width * 72.0 / dev->x_pixels_per_inch;
+ dev->PageSize[1] = height * 72.0 / dev->y_pixels_per_inch;
+}
+
+/* Set the resolution, updating width and height to remain consistent. */
+void
+gx_device_set_resolution(gx_device * dev, floatp x_dpi, floatp y_dpi)
+{
+ dev->x_pixels_per_inch = x_dpi;
+ dev->y_pixels_per_inch = y_dpi;
+
+ dev->width = (dev->PageSize[0] - dev->HWMargins[0] - dev->HWMargins[2]) *
+ dev->x_pixels_per_inch / 72.0 + 0.5;
+ dev->height = (dev->PageSize[1] - dev->HWMargins[1] - dev->HWMargins[3]) *
+ dev->y_pixels_per_inch / 72.0 + 0.5;
+}
+
+/* Set the PageSize, updating width and height to remain consistent. */
+void
+gx_device_set_media_size(gx_device * dev, floatp media_width, floatp media_height)
+{
+ dev->PageSize[0] = media_width;
+ dev->PageSize[1] = media_height;
+
+ dev->width = (dev->PageSize[0] - dev->HWMargins[0] - dev->HWMargins[2]) *
+ dev->x_pixels_per_inch / 72.0 + 0.5;
+ dev->height = (dev->PageSize[1] - dev->HWMargins[1] - dev->HWMargins[3]) *
+ dev->y_pixels_per_inch / 72.0 + 0.5;
+}
+
+/*
+ * Copy device parameters back from a target. This copies all standard
+ * parameters related to page size and resolution, plus color_info.
+ */
+void
+gx_device_copy_params(gx_device *to, const gx_device *from)
+{
+#define COPY_PARAM(p) to->p = from->p
+#define COPY_ARRAY_PARAM(p) memcpy(to->p, from->p, sizeof(to->p))
+ COPY_PARAM(width);
+ COPY_PARAM(height);
+ COPY_ARRAY_PARAM(PageSize);
+ COPY_ARRAY_PARAM(ImagingBBox);
+ COPY_PARAM(ImagingBBox_set);
+ COPY_ARRAY_PARAM(HWResolution);
+ COPY_ARRAY_PARAM(MarginsHWResolution);
+ COPY_ARRAY_PARAM(Margins);
+ COPY_ARRAY_PARAM(HWMargins);
+ COPY_PARAM(color_info);
+#undef COPY_PARAM
+#undef COPY_ARRAY_PARAM
+}
+
+/* Open the output file for a device. */
+int
+gx_device_open_output_file(const gx_device * dev, const char *fname,
+ bool binary, bool positionable, FILE ** pfile)
+{
+ char pfname[gp_file_name_sizeof];
+ char pfmt[10];
+ const char *fsrc = fname;
+ char *fdest = pfname;
+ long count1 = dev->PageCount + 1;
+
+ if (!strcmp(fname, "-")) {
+ *pfile = stdout;
+ /* Force stdout to binary. */
+ return gp_setmode_binary(*pfile, true);
+ }
+/****** SHOULD RETURN rangecheck IF FILE NAME TOO LONG ******/
+ for (; *fsrc; ++fsrc) {
+ if (*fsrc != '%') {
+ *fdest++ = *fsrc;
+ continue;
+ }
+ if (fsrc[1] == '%') {
+ *fdest++ = '%';
+ ++fsrc;
+ continue;
+ } {
+ char *ffmt = pfmt;
+ bool use_long;
+
+/****** SHOULD CHECK FOR FORMAT TOO LONG ******/
+ while (!isalpha(*fsrc))
+ *ffmt++ = *fsrc++;
+ if ((use_long = (*fsrc == 'l')))
+ *ffmt++ = *fsrc++;
+ *ffmt = *fsrc;
+ ffmt[1] = 0;
+/****** SHOULD CHECK FOR LEGAL FORMATS ******/
+ sprintf(fdest, pfmt, (use_long ? count1 : (int)count1));
+ fdest += strlen(fdest);
+ }
+ }
+ *fdest = 0;
+ if (positionable && pfname[0] != '|') {
+ char fmode[4];
+
+ strcpy(fmode, gp_fmode_wb);
+ strcat(fmode, "+");
+ *pfile = gp_fopen(pfname, fmode);
+ if (*pfile)
+ return 0;
+ }
+ *pfile = gp_open_printer(pfname, binary);
+ if (*pfile)
+ return 0;
+ return_error(gs_error_invalidfileaccess);
+}
diff --git a/pstoraster/gsdevice.h b/pstoraster/gsdevice.h
new file mode 100644
index 000000000..6c8fd830d
--- /dev/null
+++ b/pstoraster/gsdevice.h
@@ -0,0 +1,103 @@
+/* Copyright (C) 1994, 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$ */
+/* Device and page control API */
+
+#ifndef gsdevice_INCLUDED
+# define gsdevice_INCLUDED
+
+#ifndef gx_device_DEFINED
+# define gx_device_DEFINED
+typedef struct gx_device_s gx_device;
+#endif
+
+#ifndef gx_device_memory_DEFINED
+# define gx_device_memory_DEFINED
+typedef struct gx_device_memory_s gx_device_memory;
+#endif
+
+#ifndef gs_matrix_DEFINED
+# define gs_matrix_DEFINED
+typedef struct gs_matrix_s gs_matrix;
+#endif
+
+#ifndef gs_param_list_DEFINED
+# define gs_param_list_DEFINED
+typedef struct gs_param_list_s gs_param_list;
+#endif
+
+#ifndef gs_state_DEFINED
+# define gs_state_DEFINED
+typedef struct gs_state_s gs_state;
+#endif
+
+int gs_flushpage(P1(gs_state *));
+int gs_copypage(P1(gs_state *));
+int gs_output_page(P3(gs_state *, int, int));
+int gs_copyscanlines(P6(gx_device *, int, byte *, uint, int *, uint *));
+const gx_device *gs_getdevice(P1(int));
+int gs_copydevice(P3(gx_device **, const gx_device *, gs_memory_t *));
+
+#define gs_makeimagedevice(pdev, pmat, w, h, colors, colors_size, mem)\
+ gs_makewordimagedevice(pdev, pmat, w, h, colors, colors_size, false, true, mem)
+int gs_makewordimagedevice(P9(gx_device ** pnew_dev, const gs_matrix * pmat,
+ uint width, uint height,
+ const byte * colors, int num_colors,
+ bool word_oriented, bool page_device,
+ gs_memory_t * mem));
+
+#define gs_initialize_imagedevice(mdev, pmat, w, h, colors, colors_size, mem)\
+ gs_initialize_wordimagedevice(mdev, pmat, w, h, colors, color_size, false, true, mem)
+int gs_initialize_wordimagedevice(P9(gx_device_memory * new_dev,
+ const gs_matrix * pmat,
+ uint width, uint height,
+ const byte * colors, int colors_size,
+ bool word_oriented, bool page_device,
+ gs_memory_t * mem));
+
+int gs_nulldevice(P1(gs_state *));
+int gs_setdevice(P2(gs_state *, gx_device *));
+int gs_setdevice_no_erase(P2(gs_state *, gx_device *)); /* returns 1 */
+ /* if erasepage required */
+int gs_setdevice_no_init(P2(gs_state *, gx_device *));
+gx_device *gs_currentdevice(P1(const gs_state *));
+
+/* gzstate.h redefines the following: */
+#ifndef gs_currentdevice_inline
+# define gs_currentdevice_inline(pgs) gs_currentdevice(pgs)
+#endif
+const char *gs_devicename(P1(const gx_device *));
+void gs_deviceinitialmatrix(P2(gx_device *, gs_matrix *));
+
+int gs_get_device_or_hardware_params(P3(gx_device *, gs_param_list *, bool));
+#define gs_getdeviceparams(dev, plist)\
+ gs_get_device_or_hardware_params(dev, plist, false)
+#define gs_gethardwareparams(dev, plist)\
+ gs_get_device_or_hardware_params(dev, plist, true)
+
+int gs_putdeviceparams(P2(gx_device *, gs_param_list *));
+int gs_closedevice(P1(gx_device *));
+
+#endif /* gsdevice_INCLUDED */
diff --git a/pstoraster/gsdevmem.c b/pstoraster/gsdevmem.c
new file mode 100644
index 000000000..0be8b55a4
--- /dev/null
+++ b/pstoraster/gsdevmem.c
@@ -0,0 +1,239 @@
+/* Copyright (C) 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of GNU Ghostscript.
+
+ GNU Ghostscript is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
+ to anyone for the consequences of using it or for whether it serves any
+ particular purpose or works at all, unless he says so in writing. Refer
+ to the GNU General Public License for full details.
+
+ Everyone is granted permission to copy, modify and redistribute GNU
+ Ghostscript, but only under the conditions described in the GNU General
+ Public License. A copy of this license is supposed to have been given
+ to you along with GNU Ghostscript so you can know your rights and
+ responsibilities. It should be in a file named COPYING. Among other
+ things, the copyright notice and this notice must be preserved on all
+ copies.
+
+ Aladdin Enterprises 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$ */
+/* Memory device creation for Ghostscript library */
+#include "math_.h" /* for fabs */
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gxarith.h"
+#include "gxdevice.h"
+#include "gxdevmem.h"
+
+/* Make a memory (image) device. */
+/* If colors_size = -16, -24, or -32, this is a true-color device; */
+/* otherwise, colors_size is the size of the palette in bytes */
+/* (2^N for gray scale, 3*2^N for RGB color). */
+/* We separate device allocation and initialization at customer request. */
+int
+gs_initialize_wordimagedevice(gx_device_memory * new_dev, const gs_matrix * pmat,
+ uint width, uint height, const byte * colors, int colors_size,
+ bool word_oriented, bool page_device, gs_memory_t * mem)
+{
+ const gx_device_memory *proto_dev;
+ int palette_count = colors_size;
+ int num_components = 1;
+ int pcount;
+ int bits_per_pixel;
+ float x_pixels_per_unit, y_pixels_per_unit;
+ byte palette[256 * 3];
+ byte *dev_palette;
+ bool has_color;
+
+ switch (colors_size) {
+ case 3 * 2:
+ palette_count = 2;
+ num_components = 3;
+ case 2:
+ bits_per_pixel = 1;
+ break;
+ case 3 * 4:
+ palette_count = 4;
+ num_components = 3;
+ case 4:
+ bits_per_pixel = 2;
+ break;
+ case 3 * 16:
+ palette_count = 16;
+ num_components = 3;
+ case 16:
+ bits_per_pixel = 4;
+ break;
+ case 3 * 256:
+ palette_count = 256;
+ num_components = 3;
+ case 256:
+ bits_per_pixel = 8;
+ break;
+ case -16:
+ bits_per_pixel = 16;
+ palette_count = 0;
+ break;
+ case -24:
+ bits_per_pixel = 24;
+ palette_count = 0;
+ break;
+ case -32:
+ bits_per_pixel = 32;
+ palette_count = 0;
+ break;
+ default:
+ return_error(gs_error_rangecheck);
+ }
+ proto_dev = (word_oriented ?
+ gdev_mem_word_device_for_bits(bits_per_pixel) :
+ gdev_mem_device_for_bits(bits_per_pixel));
+ if (proto_dev == 0) /* no suitable device */
+ return_error(gs_error_rangecheck);
+ pcount = palette_count * 3;
+ /* Check to make sure the palette contains white and black, */
+ /* and, if it has any colors, the six primaries. */
+ if (bits_per_pixel <= 8) {
+ const byte *p;
+ byte *q;
+ int primary_mask = 0;
+ int i;
+
+ has_color = false;
+ for (i = 0, p = colors, q = palette;
+ i < palette_count; i++, q += 3
+ ) {
+ int mask = 1;
+
+ switch (num_components) {
+ case 1: /* gray */
+ q[0] = q[1] = q[2] = *p++;
+ break;
+ default /* case 3 */ : /* RGB */
+ q[0] = p[0], q[1] = p[1], q[2] = p[2];
+ p += 3;
+ }
+#define shift_mask(b,n)\
+ switch ( b ) { case 0xff: mask <<= n; case 0: break; default: mask = 0; }
+ shift_mask(q[0], 4);
+ shift_mask(q[1], 2);
+ shift_mask(q[2], 1);
+#undef shift_mask
+ primary_mask |= mask;
+ if (q[0] != q[1] || q[0] != q[2])
+ has_color = true;
+ }
+ switch (primary_mask) {
+ case 129: /* just black and white */
+ if (has_color) /* color but no primaries */
+ return_error(gs_error_rangecheck);
+ case 255: /* full color */
+ break;
+ default:
+ return_error(gs_error_rangecheck);
+ }
+ } else
+ has_color = true;
+ /*
+ * The initial transformation matrix must map 1 user unit to
+ * 1/72". Let W and H be the width and height in pixels, and
+ * assume the initial matrix is of the form [A 0 0 B X Y].
+ * Then the size of the image in user units is (W/|A|,H/|B|),
+ * hence the size in inches is ((W/|A|)/72,(H/|B|)/72), so
+ * the number of pixels per inch is
+ * (W/((W/|A|)/72),H/((H/|B|)/72)), or (|A|*72,|B|*72).
+ * Similarly, if the initial matrix is [0 A B 0 X Y] for a 90
+ * or 270 degree rotation, the size of the image in user
+ * units is (W/|B|,H/|A|), so the pixels per inch are
+ * (|B|*72,|A|*72). We forbid non-orthogonal transformation
+ * matrices.
+ */
+ if (is_fzero2(pmat->xy, pmat->yx))
+ x_pixels_per_unit = pmat->xx, y_pixels_per_unit = pmat->yy;
+ else if (is_fzero2(pmat->xx, pmat->yy))
+ x_pixels_per_unit = pmat->yx, y_pixels_per_unit = pmat->xy;
+ else
+ return_error(gs_error_undefinedresult);
+ /* All checks done, allocate the device. */
+ if (bits_per_pixel != 1) {
+ dev_palette = gs_alloc_string(mem, pcount,
+ "gs_makeimagedevice(palette)");
+ if (dev_palette == 0)
+ return_error(gs_error_VMerror);
+ }
+ else
+ dev_palette = 0;
+
+ gs_make_mem_device(new_dev, proto_dev, mem,
+ (page_device ? 1 : -1), 0);
+ if (!has_color) {
+ new_dev->color_info.num_components = 1;
+ new_dev->color_info.max_color = 0;
+ new_dev->color_info.dither_colors = 0;
+ }
+ if (bits_per_pixel == 1) { /* Determine the polarity from the palette. */
+ /* This is somewhat bogus, but does the right thing */
+ /* in the only cases we care about. */
+ gdev_mem_mono_set_inverted(new_dev,
+ (palette[0] | palette[1] | palette[2]) != 0);
+ } else {
+ new_dev->palette.size = pcount;
+ new_dev->palette.data = dev_palette;
+ memcpy(dev_palette, palette, pcount);
+ }
+ new_dev->initial_matrix = *pmat;
+ new_dev->MarginsHWResolution[0] = new_dev->HWResolution[0] =
+ fabs(x_pixels_per_unit) * 72;
+ new_dev->MarginsHWResolution[1] = new_dev->HWResolution[1] =
+ fabs(y_pixels_per_unit) * 72;
+ gx_device_set_width_height((gx_device *) new_dev, width, height);
+ /* Set the ImagingBBox so we get a correct clipping region. */
+ {
+ gs_rect bbox;
+
+ bbox.p.x = 0;
+ bbox.p.y = 0;
+ bbox.q.x = width;
+ bbox.q.y = height;
+ gs_bbox_transform_inverse(&bbox, pmat, &bbox);
+ new_dev->ImagingBBox[0] = bbox.p.x;
+ new_dev->ImagingBBox[1] = bbox.p.y;
+ new_dev->ImagingBBox[2] = bbox.q.x;
+ new_dev->ImagingBBox[3] = bbox.q.y;
+ new_dev->ImagingBBox_set = true;
+ }
+ /* The bitmap will be allocated when the device is opened. */
+ new_dev->is_open = false;
+ new_dev->bitmap_memory = mem;
+ return 0;
+}
+
+int
+gs_makewordimagedevice(gx_device ** pnew_dev, const gs_matrix * pmat,
+ uint width, uint height, const byte * colors, int num_colors,
+ bool word_oriented, bool page_device, gs_memory_t * mem)
+{
+ int code;
+ gx_device_memory *pnew =
+ gs_alloc_struct(mem, gx_device_memory, &st_device_memory,
+ "gs_makeimagedevice(device)");
+
+ if (pnew == 0)
+ return_error(gs_error_VMerror);
+ code = gs_initialize_wordimagedevice(pnew, pmat, width, height,
+ colors, num_colors, word_oriented,
+ page_device, mem);
+ if (code < 0) {
+ gs_free_object(mem, pnew, "gs_makeimagedevice(device)");
+ return code;
+ }
+ *pnew_dev = (gx_device *) pnew;
+ return 0;
+}
diff --git a/pstoraster/gsdll.h b/pstoraster/gsdll.h
new file mode 100644
index 000000000..709aeb836
--- /dev/null
+++ b/pstoraster/gsdll.h
@@ -0,0 +1,145 @@
+/* Copyright (C) 1994-1996, Russell Lang. 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$ */
+
+#ifndef gsdll_INCLUDED
+# define gsdll_INCLUDED
+
+#ifndef _GSDLL_H
+#define _GSDLL_H
+
+#ifndef GSDLLEXPORT
+#define GSDLLEXPORT
+#endif
+
+#ifdef __WINDOWS__
+#define _Windows
+#endif
+
+/* type of exported functions */
+#ifdef _Windows
+#ifdef _WATCOM_
+#define GSDLLAPI GSDLLEXPORT
+#else
+#define GSDLLAPI CALLBACK GSDLLEXPORT
+#endif
+#else
+#ifdef __IBMC__
+#define GSDLLAPI _System
+#else
+#define GSDLLAPI
+#endif
+#endif
+
+#ifdef _Windows
+#define GSDLLCALLLINK
+#define GSFAR FAR
+#else
+#ifdef __IBMC__
+#define GSDLLCALLLINK _System
+#else
+#define GSDLLCALLLINK
+#endif
+#define GSFAR
+#endif
+
+/* global pointer to callback */
+typedef int (GSFAR * GSDLLCALLLINK GSDLL_CALLBACK) (int, char GSFAR *, unsigned long);
+extern GSDLL_CALLBACK pgsdll_callback;
+
+/* message values for callback */
+#define GSDLL_STDIN 1 /* get count characters to str from stdin */
+ /* return number of characters read */
+#define GSDLL_STDOUT 2 /* put count characters from str to stdout */
+ /* return number of characters written */
+#define GSDLL_DEVICE 3 /* device = str has been opened if count=1 */
+ /* or closed if count=0 */
+#define GSDLL_SYNC 4 /* sync_output for device str */
+#define GSDLL_PAGE 5 /* output_page for device str */
+#define GSDLL_SIZE 6 /* resize for device str */
+ /* LOWORD(count) is new xsize */
+ /* HIWORD(count) is new ysize */
+#define GSDLL_POLL 7 /* Called from gp_check_interrupt */
+ /* Can be used by caller to poll the message queue */
+ /* Normally returns 0 */
+ /* To abort gsdll_execute_cont(), return a */
+ /* non zero error code until gsdll_execute_cont() */
+ /* returns */
+
+/* return values from gsdll_init() */
+#define GSDLL_INIT_IN_USE 100 /* DLL is in use */
+#define GSDLL_INIT_QUIT 101 /* quit or EOF during init */
+ /* This is not an error. */
+ /* gsdll_exit() must not be called */
+
+
+/* DLL exported functions */
+/* for load time dynamic linking */
+int GSDLLAPI gsdll_revision(char GSFAR * GSFAR * product, char GSFAR * GSFAR * copyright, long GSFAR * gs_revision, long GSFAR * gs_revisiondate);
+int GSDLLAPI gsdll_init(GSDLL_CALLBACK callback, HWND hwnd, int argc, char GSFAR * GSFAR * argv);
+int GSDLLAPI gsdll_execute_begin(void);
+int GSDLLAPI gsdll_execute_cont(const char GSFAR * str, int len);
+int GSDLLAPI gsdll_execute_end(void);
+int GSDLLAPI gsdll_exit(void);
+int GSDLLAPI gsdll_lock_device(unsigned char *device, int flag);
+
+#ifdef _Windows
+HGLOBAL GSDLLAPI gsdll_copy_dib(unsigned char GSFAR * device);
+HPALETTE GSDLLAPI gsdll_copy_palette(unsigned char GSFAR * device);
+void GSDLLAPI gsdll_draw(unsigned char GSFAR * device, HDC hdc, LPRECT dest, LPRECT src);
+int GSDLLAPI gsdll_get_bitmap_row(unsigned char *device, LPBITMAPINFOHEADER pbmih,
+ LPRGBQUAD prgbquad, LPBYTE * ppbyte, unsigned int row);
+
+#else
+unsigned long gsdll_get_bitmap(unsigned char *device, unsigned char **pbitmap);
+
+#endif
+
+/* Function pointer typedefs */
+/* for run time dynamic linking */
+typedef int (GSDLLAPI * PFN_gsdll_revision) (char GSFAR * GSFAR *, char GSFAR * GSFAR *, long GSFAR *, long GSFAR *);
+typedef int (GSDLLAPI * PFN_gsdll_init) (GSDLL_CALLBACK, HWND, int argc, char GSFAR * GSFAR * argv);
+typedef int (GSDLLAPI * PFN_gsdll_execute_begin) (void);
+typedef int (GSDLLAPI * PFN_gsdll_execute_cont) (const char GSFAR * str, int len);
+typedef int (GSDLLAPI * PFN_gsdll_execute_end) (void);
+typedef int (GSDLLAPI * PFN_gsdll_exit) (void);
+typedef int (GSDLLAPI * PFN_gsdll_lock_device) (unsigned char GSFAR *, int);
+
+#ifdef _Windows
+typedef HGLOBAL(GSDLLAPI * PFN_gsdll_copy_dib) (unsigned char GSFAR *);
+typedef HPALETTE(GSDLLAPI * PFN_gsdll_copy_palette) (unsigned char GSFAR *);
+typedef void (GSDLLAPI * PFN_gsdll_draw) (unsigned char GSFAR *, HDC, LPRECT, LPRECT);
+typedef int (GSDLLAPI * PFN_gsdll_get_bitmap_row) (unsigned char *device, LPBITMAPINFOHEADER pbmih,
+ LPRGBQUAD prgbquad, LPBYTE * ppbyte, unsigned int row);
+
+#else
+typedef long (*GSDLLAPI PFN_gsdll_get_bitmap) (unsigned char *, unsigned char **);
+
+#endif
+
+#endif
+
+#endif /* gsdll_INCLUDED */
diff --git a/pstoraster/gsdparam.c b/pstoraster/gsdparam.c
new file mode 100644
index 000000000..9b533bc2e
--- /dev/null
+++ b/pstoraster/gsdparam.c
@@ -0,0 +1,782 @@
+/*
+ Copyright 1993-1999 by Easy Software Products.
+ Copyright (C) 1993, 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$ */
+/* Default device parameters for Ghostscript library */
+#include "memory_.h" /* for memcpy */
+#include "string_.h" /* for strlen */
+#include "gx.h"
+#include "gserrors.h"
+#include "gsparam.h"
+#include "gxdevice.h"
+#include "gxfixed.h"
+
+/* ================ Getting parameters ================ */
+
+/* Forward references */
+private bool param_HWColorMap(P2(gx_device *, byte *));
+
+/* Get the device parameters. */
+int
+gs_get_device_or_hardware_params(gx_device * dev, gs_param_list * plist,
+ bool is_hardware)
+{
+ gx_device_set_procs(dev);
+ fill_dev_proc(dev, get_params, gx_default_get_params);
+ fill_dev_proc(dev, get_page_device, gx_default_get_page_device);
+ fill_dev_proc(dev, get_alpha_bits, gx_default_get_alpha_bits);
+ return (is_hardware ?
+ (*dev_proc(dev, get_hardware_params)) (dev, plist) :
+ (*dev_proc(dev, get_params)) (dev, plist));
+}
+
+/* Standard ProcessColorModel values. */
+static const char *const pcmsa[] =
+{
+ "", "DeviceGray", "", "DeviceRGB", "DeviceCMYK"
+};
+
+/* Get standard parameters. */
+int
+gx_default_get_params(gx_device * dev, gs_param_list * plist)
+{
+ int code;
+
+ /* Standard page device parameters: */
+
+ gs_param_string dns, pcms;
+ gs_param_float_array msa, ibba, hwra, ma;
+
+#define set_param_array(a, d, s)\
+ (a.data = d, a.size = s, a.persistent = false);
+
+ /* Non-standard parameters: */
+
+ int colors = dev->color_info.num_components;
+ int depth = dev->color_info.depth;
+ int GrayValues = dev->color_info.max_gray + 1;
+ int HWSize[2];
+ gs_param_int_array hwsa;
+ gs_param_float_array hwma, mhwra;
+
+ /* Fill in page device parameters. */
+
+ param_string_from_string(dns, dev->dname);
+ {
+ const char *cms = pcmsa[colors];
+
+ /* We might have an uninitialized device with */
+ /* color_info.num_components = 0.... */
+ if (*cms != 0)
+ param_string_from_string(pcms, cms);
+ else
+ pcms.data = 0;
+ }
+ set_param_array(hwra, dev->HWResolution, 2);
+ set_param_array(msa, dev->PageSize, 2);
+ set_param_array(ibba, dev->ImagingBBox, 4);
+ set_param_array(ma, dev->Margins, 2);
+
+ /* Fill in non-standard parameters. */
+
+ HWSize[0] = dev->width;
+ HWSize[1] = dev->height;
+ set_param_array(hwsa, HWSize, 2);
+ set_param_array(hwma, dev->HWMargins, 4);
+ set_param_array(mhwra, dev->MarginsHWResolution, 2);
+
+ /* Transmit the values. */
+
+ if (!dev->NumCopies_set)
+ dev->NumCopies = 1;
+
+ /* Standard parameters */
+ if (
+ (code = param_write_name(plist, "OutputDevice", &dns)) < 0 ||
+ (code = param_write_float_array(plist, "PageSize", &msa)) < 0 ||
+ (code = (pcms.data == 0 ? 0 :
+ param_write_name(plist, "ProcessColorModel", &pcms))) < 0 ||
+ (code = param_write_float_array(plist, "HWResolution", &hwra)) < 0 ||
+ (code = (dev->ImagingBBox_set ?
+ param_write_float_array(plist, "ImagingBBox", &ibba) :
+ param_write_null(plist, "ImagingBBox"))) < 0 ||
+ (code = param_write_float_array(plist, "Margins", &ma)) < 0 ||
+ (code = (dev->NumCopies_set < 0 ||
+ (*dev_proc(dev, get_page_device))(dev) == 0 ? 0:
+ param_write_int(plist, "NumCopies", &dev->NumCopies))) < 0 ||
+
+ /* Non-standard parameters */
+
+ (code = param_write_int_array(plist, "HWSize", &hwsa)) < 0 ||
+ (code = param_write_float_array(plist, ".HWMargins", &hwma)) < 0 ||
+ (code = param_write_float_array(plist, ".MarginsHWResolution", &mhwra)) < 0 ||
+ (code = param_write_string(plist, "Name", &dns)) < 0 ||
+ (code = param_write_int(plist, "Colors", &colors)) < 0 ||
+ (code = param_write_int(plist, "BitsPerPixel", &depth)) < 0 ||
+ (code = param_write_int(plist, "GrayValues", &GrayValues)) < 0 ||
+ (code = param_write_long(plist, "PageCount", &dev->PageCount)) < 0 ||
+ (code = param_write_bool(plist, ".IgnoreNumCopies", &dev->IgnoreNumCopies)) < 0
+ )
+ return code;
+
+ /* Fill in color information. */
+
+ if (colors > 1) {
+ int RGBValues = dev->color_info.max_color + 1;
+ long ColorValues = 1L << depth;
+
+ if ((code = param_write_int(plist, "RedValues", &RGBValues)) < 0 ||
+ (code = param_write_int(plist, "GreenValues", &RGBValues)) < 0 ||
+ (code = param_write_int(plist, "BlueValues", &RGBValues)) < 0 ||
+ (code = param_write_long(plist, "ColorValues", &ColorValues)) < 0
+ )
+ return code;
+ }
+ if (param_requested(plist, "HWColorMap")) {
+ byte palette[3 << 8];
+
+ if (param_HWColorMap(dev, palette)) {
+ gs_param_string hwcms;
+
+ hwcms.data = palette, hwcms.size = colors << depth,
+ hwcms.persistent = false;
+ if ((code = param_write_string(plist, "HWColorMap", &hwcms)) < 0)
+ return code;
+ }
+ } {
+ int tab = (*dev_proc(dev, get_alpha_bits)) (dev, go_text);
+ int gab = (*dev_proc(dev, get_alpha_bits)) (dev, go_graphics);
+
+ if ((code = param_write_int(plist, "TextAlphaBits", &tab)) < 0 ||
+ (code = param_write_int(plist, "GraphicsAlphaBits", &gab)) < 0
+ )
+ return code;
+ }
+
+ return 0;
+}
+
+/* Get the color map for a device. Return true if there is one. */
+private bool
+param_HWColorMap(gx_device * dev, byte * palette /* 3 << 8 */ )
+{
+ int depth = dev->color_info.depth;
+ int colors = dev->color_info.num_components;
+
+ if (depth <= 8 && colors <= 3) {
+ byte *p = palette;
+ gx_color_value rgb[3];
+ gx_color_index i;
+
+ fill_dev_proc(dev, map_color_rgb, gx_default_map_color_rgb);
+ for (i = 0; (i >> depth) == 0; i++) {
+ int j;
+
+ if ((*dev_proc(dev, map_color_rgb)) (dev, i, rgb) < 0)
+ return false;
+ for (j = 0; j < colors; j++)
+ *p++ = gx_color_value_to_byte(rgb[j]);
+ }
+ return true;
+ }
+ return false;
+}
+
+/* Get hardware-detected parameters. Default action is no hardware params. */
+int
+gx_default_get_hardware_params(gx_device * dev, gs_param_list * plist)
+{
+ return 0;
+}
+
+/* ---------------- Input and output media ---------------- */
+
+/* Finish defining input or output media. */
+private int
+finish_media(gs_param_list * mlist, gs_param_name key, const char *media_type)
+{
+ int code = 0;
+
+ if (media_type != 0) {
+ gs_param_string as;
+
+ param_string_from_string(as, media_type);
+ code = param_write_string(mlist, key, &as);
+ }
+ return code;
+}
+
+/* Define input media. */
+
+const gdev_input_media_t gdev_input_media_default =
+{
+ gdev_input_media_default_values
+};
+
+int
+gdev_begin_input_media(gs_param_list * mlist, gs_param_dict * pdict,
+ int count)
+{
+ pdict->size = count;
+ return param_begin_write_dict(mlist, "InputAttributes", pdict, true);
+}
+
+int
+gdev_write_input_media(int index, gs_param_dict * pdict,
+ const gdev_input_media_t * pim)
+{
+ char key[25];
+ gs_param_dict mdict;
+ int code;
+ gs_param_string as;
+
+ sprintf(key, "%d", index);
+ mdict.size = 4;
+ code = param_begin_write_dict(pdict->list, key, &mdict, false);
+ if (code < 0)
+ return code;
+ if ((pim->PageSize[0] != 0 && pim->PageSize[1] != 0) ||
+ (pim->PageSize[2] != 0 && pim->PageSize[3] != 0)
+ ) {
+ gs_param_float_array psa;
+
+ psa.data = pim->PageSize;
+ psa.size =
+ (pim->PageSize[0] == pim->PageSize[2] &&
+ pim->PageSize[1] == pim->PageSize[3] ? 2 : 4);
+ psa.persistent = false;
+ code = param_write_float_array(mdict.list, "PageSize",
+ &psa);
+ if (code < 0)
+ return code;
+ }
+ if (pim->MediaColor != 0) {
+ param_string_from_string(as, pim->MediaColor);
+ code = param_write_string(mdict.list, "MediaColor",
+ &as);
+ if (code < 0)
+ return code;
+ }
+ if (pim->MediaWeight != 0) {
+ /*
+ * We do the following silly thing in order to avoid
+ * having to work around the 'const' in the arg list.
+ */
+ float weight = pim->MediaWeight;
+
+ code = param_write_float(mdict.list, "MediaWeight",
+ &weight);
+ if (code < 0)
+ return code;
+ }
+/* code = finish_media(mdict.list, "MediaType", pim->MediaType);
+ if (code < 0)
+ return code;*/
+ return param_end_write_dict(pdict->list, key, &mdict);
+}
+
+int
+gdev_write_input_page_size(int index, gs_param_dict * pdict,
+ floatp width_points, floatp height_points)
+{
+ gdev_input_media_t media;
+
+ media.PageSize[0] = media.PageSize[2] = width_points;
+ media.PageSize[1] = media.PageSize[3] = height_points;
+ media.MediaColor = 0;
+ media.MediaWeight = 0;
+ media.MediaType = 0;
+ return gdev_write_input_media(index, pdict, &media);
+}
+
+int
+gdev_end_input_media(gs_param_list * mlist, gs_param_dict * pdict)
+{
+ return param_end_write_dict(mlist, "InputAttributes", pdict);
+}
+
+/* Define output media. */
+
+const gdev_output_media_t gdev_output_media_default =
+{
+ gdev_output_media_default_values
+};
+
+int
+gdev_begin_output_media(gs_param_list * mlist, gs_param_dict * pdict,
+ int count)
+{
+ pdict->size = count;
+ return param_begin_write_dict(mlist, "OutputAttributes", pdict, true);
+}
+
+int
+gdev_write_output_media(int index, gs_param_dict * pdict,
+ const gdev_output_media_t * pom)
+{
+ char key[25];
+ gs_param_dict mdict;
+ int code;
+
+ sprintf(key, "%d", index);
+ mdict.size = 4;
+ code = param_begin_write_dict(pdict->list, key, &mdict, false);
+ if (code < 0)
+ return code;
+ code = finish_media(mdict.list, "OutputType", pom->OutputType);
+ if (code < 0)
+ return code;
+ return param_end_write_dict(pdict->list, key, &mdict);
+}
+
+int
+gdev_end_output_media(gs_param_list * mlist, gs_param_dict * pdict)
+{
+ return param_end_write_dict(mlist, "OutputAttributes", pdict);
+}
+
+/* ================ Putting parameters ================ */
+
+/* Forward references */
+private int param_PageSize(P4(gs_param_list *, gs_param_name,
+ const float *, gs_param_float_array *));
+
+#if 0 /****** not used ***** */
+private int param_check_bool(P4(gs_param_list *, gs_param_name, bool, bool));
+
+#endif /****** not used ***** */
+private int param_check_long(P4(gs_param_list *, gs_param_name, long, bool));
+
+#define param_check_int(plist, pname, ival, isdefined)\
+ param_check_long(plist, pname, (long)(ival), isdefined)
+private int param_check_bytes(P5(gs_param_list *, gs_param_name, const byte *, uint, bool));
+
+#define param_check_string(plist, pname, strg, isdefined)\
+ param_check_bytes(plist, pname, (const byte *)strg, strlen(strg), isdefined)
+
+/* Set the device parameters. */
+/* If the device was open and the put_params procedure closed it, */
+/* return 1; otherwise, return 0 or an error code as usual. */
+int
+gs_putdeviceparams(gx_device * dev, gs_param_list * plist)
+{
+ bool was_open = dev->is_open;
+ int code;
+
+ gx_device_set_procs(dev);
+ fill_dev_proc(dev, put_params, gx_default_put_params);
+ fill_dev_proc(dev, get_alpha_bits, gx_default_get_alpha_bits);
+ code = (*dev_proc(dev, put_params)) (dev, plist);
+ return (code < 0 ? code : was_open && !dev->is_open ? 1 : code);
+}
+
+/* Set standard parameters. */
+/* Note that setting the size or resolution closes the device. */
+/* Window devices that don't want this to happen must temporarily */
+/* set is_open to false before calling gx_default_put_params, */
+/* and then taking appropriate action afterwards. */
+int
+gx_default_put_params(gx_device * dev, gs_param_list * plist)
+{
+ int ecode = 0;
+ int code;
+ gs_param_name param_name;
+ gs_param_float_array hwra;
+ gs_param_int_array hwsa;
+ gs_param_float_array msa;
+ gs_param_float_array ma;
+ gs_param_float_array hwma;
+ gs_param_float_array mhwra;
+ int nci = dev->NumCopies;
+ int ncset = dev->NumCopies_set;
+
+ bool ignc = dev->IgnoreNumCopies;
+ gs_param_float_array ibba;
+ bool ibbnull = false;
+ int colors = dev->color_info.num_components;
+ int depth = dev->color_info.depth;
+ int GrayValues = dev->color_info.max_gray + 1;
+ int RGBValues = dev->color_info.max_color + 1;
+ long ColorValues = 1L << depth;
+ gs_param_string cms;
+
+#define BEGIN_ARRAY_PARAM(pread, pname, pa, psize, e)\
+ switch ( code = pread(plist, (param_name = pname), &(pa)) )\
+ {\
+ case 0:\
+ if ( (pa).size != psize )\
+ ecode = gs_note_error(gs_error_rangecheck);\
+ else {
+/* The body of the processing code goes here. */
+/* If it succeeds, it should do a 'break'; */
+/* if it fails, it should set ecode and fall through. */
+#define END_ARRAY_PARAM(pa, e)\
+ }\
+ goto e;\
+ default:\
+ ecode = code;\
+e: param_signal_error(plist, param_name, ecode);\
+ case 1:\
+ (pa).data = 0; /* mark as not filled */\
+ }
+
+ /*
+ * The HWResolution, HWSize, and PageSize parameters interact in
+ * the following way:
+ * 1. Setting HWResolution recomputes HWSize from PageSize.
+ * 2. Setting HWSize recomputes PageSize from HWResolution.
+ * 3. Setting PageSize recomputes HWSize from HWResolution.
+ * If more than one parameter is being set, we apply these rules
+ * in the order 1, 2, 3. This does the right thing in the most
+ * common case of setting more than one parameter, namely,
+ * setting both HWResolution and HWSize.
+ */
+
+ BEGIN_ARRAY_PARAM(param_read_float_array, "HWResolution", hwra, 2, hwre)
+ if (hwra.data[0] <= 0 || hwra.data[1] <= 0)
+ ecode = gs_note_error(gs_error_rangecheck);
+ else
+ break;
+ END_ARRAY_PARAM(hwra, hwre)
+ BEGIN_ARRAY_PARAM(param_read_int_array, "HWSize", hwsa, 2, hwsa)
+ /* We need a special check to handle the nullpage device, */
+ /* whose size is legitimately [0 0]. */
+ if ((hwsa.data[0] <= 0 && hwsa.data[0] != dev->width) ||
+ (hwsa.data[1] <= 0 && hwsa.data[1] != dev->height)
+ )
+ ecode = gs_note_error(gs_error_rangecheck);
+#define max_coord (max_fixed / fixed_1)
+#if max_coord < max_int
+ else if (hwsa.data[0] > max_coord || hwsa.data[1] > max_coord)
+ ecode = gs_note_error(gs_error_limitcheck);
+#endif
+#undef max_coord
+ else
+ break;
+ END_ARRAY_PARAM(hwsa, hwse) {
+ const float *res = (hwra.data == 0 ? dev->HWResolution : hwra.data);
+
+ /* MRS - Dropped questionable use of .PageSize attribute */
+ code = param_PageSize(plist, "PageSize", res, &msa);
+ if (code < 0)
+ ecode = code;
+ }
+
+ BEGIN_ARRAY_PARAM(param_read_float_array, "Margins", ma, 2, me)
+ break;
+ END_ARRAY_PARAM(ma, me)
+ BEGIN_ARRAY_PARAM(param_read_float_array, ".HWMargins", hwma, 4, hwme)
+ break;
+ END_ARRAY_PARAM(hwma, hwme)
+ /* MarginsHWResolution cannot be changed, only checked. */
+ BEGIN_ARRAY_PARAM(param_read_float_array, ".MarginsHWResolution", mhwra, 2, mhwre)
+ if (mhwra.data[0] != dev->MarginsHWResolution[0] ||
+ mhwra.data[1] != dev->MarginsHWResolution[1]
+ )
+ ecode = gs_note_error(gs_error_rangecheck);
+ else
+ break;
+ END_ARRAY_PARAM(mhwra, mhwre)
+ switch (code = param_read_bool(plist, (param_name = ".IgnoreNumCopies"), &ignc)) {
+ default:
+ ecode = code;
+ param_signal_error(plist, param_name, ecode);
+ case 0:
+ case 1:
+ break;
+ }
+ if (dev->NumCopies_set >= 0 &&
+ (*dev_proc(dev, get_page_device))(dev) != 0
+ ) {
+ switch (code = param_read_int(plist, (param_name = "NumCopies"), &nci)) {
+ case 0:
+ if (nci < 0)
+ ecode = gs_error_rangecheck;
+ else {
+ ncset = 1;
+ break;
+ }
+ goto nce;
+ default:
+ if ((code = param_read_null(plist, param_name)) == 0) {
+ ncset = 0;
+ break;
+ }
+ ecode = code; /* can't be 1 */
+nce:
+ param_signal_error(plist, param_name, ecode);
+ case 1:
+ break;
+ }
+ }
+
+
+ /* Ignore parameters that only have meaning for printers. */
+#define IGNORE_INT_PARAM(pname)\
+ { int igni;\
+ switch ( code = param_read_int(plist, (param_name = pname), &igni) )\
+ { default:\
+ ecode = code;\
+ param_signal_error(plist, param_name, ecode);\
+ case 0:\
+ case 1:\
+ break;\
+ }\
+ }
+ IGNORE_INT_PARAM("%MediaSource")
+ IGNORE_INT_PARAM("%MediaDestination")
+ switch (code = param_read_float_array(plist, (param_name = "ImagingBBox"), &ibba)) {
+ case 0:
+ if (ibba.size != 4 ||
+ ibba.data[2] < ibba.data[0] || ibba.data[3] < ibba.data[1]
+ )
+ ecode = gs_note_error(gs_error_rangecheck);
+ else
+ break;
+ goto ibbe;
+ default:
+ if ((code = param_read_null(plist, param_name)) == 0) {
+ ibbnull = true;
+ ibba.data = 0;
+ break;
+ }
+ ecode = code; /* can't be 1 */
+ ibbe:param_signal_error(plist, param_name, ecode);
+ case 1:
+ ibba.data = 0;
+ break;
+ }
+
+ /* Now check nominally read-only parameters. */
+ if ((code = param_check_string(plist, "OutputDevice", dev->dname, true)) < 0)
+ ecode = code;
+ if ((code = param_check_string(plist, "ProcessColorModel", pcmsa[colors], colors != 0)) < 0)
+ ecode = code;
+ if ((code = param_check_string(plist, "Name", dev->dname, true)) < 0)
+ ecode = code;
+ if ((code = param_check_int(plist, "Colors", colors, true)) < 0)
+ ecode = code;
+ if ((code = param_check_int(plist, "BitsPerPixel", depth, true)) < 0)
+ ecode = code;
+ if ((code = param_check_int(plist, "GrayValues", GrayValues, true)) < 0)
+ ecode = code;
+ if ((code = param_check_long(plist, "PageCount", dev->PageCount, true)) < 0)
+ ecode = code;
+ if ((code = param_check_int(plist, "RedValues", RGBValues, colors > 1)) < 0)
+ ecode = code;
+ if ((code = param_check_int(plist, "GreenValues", RGBValues, colors > 1)) < 0)
+ ecode = code;
+ if ((code = param_check_int(plist, "BlueValues", RGBValues, colors > 1)) < 0)
+ ecode = code;
+ if ((code = param_check_long(plist, "ColorValues", ColorValues, colors > 1)) < 0)
+ ecode = code;
+ if (param_read_string(plist, "HWColorMap", &cms) != 1) {
+ byte palette[3 << 8];
+
+ if (param_HWColorMap(dev, palette))
+ code = param_check_bytes(plist, "HWColorMap", palette,
+ colors << depth, true);
+ else
+ code = param_check_bytes(plist, "HWColorMap", 0, 0, false);
+ if (code < 0)
+ ecode = code;
+ }
+ if ((code =
+ param_check_int(plist, "TextAlphaBits",
+ (*dev_proc(dev, get_alpha_bits)) (dev, go_text),
+ true)) < 0
+ )
+ ecode = code;
+ if ((code =
+ param_check_int(plist, "GraphicsAlphaBits",
+ (*dev_proc(dev, get_alpha_bits)) (dev, go_graphics),
+ true)) < 0
+ )
+ ecode = code;
+
+ /* We must 'commit', in order to detect unknown parameters, */
+ /* even if there were errors. */
+ code = param_commit(plist);
+ if (ecode < 0)
+ return ecode;
+ if (code < 0)
+ return code;
+
+ /* Now actually make the changes. */
+ /* Changing resolution or page size requires closing the device, */
+ /* but changing margins or ImagingBBox does not. */
+ /* In order not to close and reopen the device unnecessarily, */
+ /* we check for replacing the values with the same ones. */
+
+ if (hwra.data != 0 &&
+ (dev->HWResolution[0] != hwra.data[0] ||
+ dev->HWResolution[1] != hwra.data[1])
+ ) {
+ if (dev->is_open)
+ gs_closedevice(dev);
+ gx_device_set_resolution(dev, hwra.data[0], hwra.data[1]);
+ }
+ if (hwsa.data != 0 &&
+ (dev->width != hwsa.data[0] ||
+ dev->height != hwsa.data[1])
+ ) {
+ if (dev->is_open)
+ gs_closedevice(dev);
+ gx_device_set_width_height(dev, hwsa.data[0], hwsa.data[1]);
+ }
+ if (msa.data != 0 &&
+ (dev->PageSize[0] != msa.data[0] ||
+ dev->PageSize[1] != msa.data[1])
+ ) {
+ if (dev->is_open)
+ gs_closedevice(dev);
+ gx_device_set_page_size(dev, msa.data[0], msa.data[1]);
+ }
+ if (ma.data != 0) {
+ dev->Margins[0] = ma.data[0];
+ dev->Margins[1] = ma.data[1];
+ }
+ if (hwma.data != 0) {
+ dev->HWMargins[0] = hwma.data[0];
+ dev->HWMargins[1] = hwma.data[1];
+ dev->HWMargins[2] = hwma.data[2];
+ dev->HWMargins[3] = hwma.data[3];
+ }
+ dev->NumCopies = nci;
+ dev->NumCopies_set = ncset;
+ dev->IgnoreNumCopies = ignc;
+ if (ibba.data != 0) {
+ dev->ImagingBBox[0] = ibba.data[0];
+ dev->ImagingBBox[1] = ibba.data[1];
+ dev->ImagingBBox[2] = ibba.data[2];
+ dev->ImagingBBox[3] = ibba.data[3];
+ dev->ImagingBBox_set = true;
+ } else if (ibbnull) {
+ dev->ImagingBBox_set = false;
+ }
+ return 0;
+}
+
+/* Read PageSize. */
+private int
+param_PageSize(gs_param_list * plist, gs_param_name pname,
+ const float *res, gs_param_float_array * pa)
+{
+ gs_param_name param_name;
+ int ecode = 0;
+ int code;
+
+ BEGIN_ARRAY_PARAM(param_read_float_array, pname, *pa, 2, mse)
+ float width_new = pa->data[0] * res[0] / 72;
+ float height_new = pa->data[1] * res[1] / 72;
+
+ if (width_new < 0 || height_new < 0)
+ ecode = gs_note_error(gs_error_rangecheck);
+#define max_coord (max_fixed / fixed_1)
+#if max_coord < max_int
+ else if (width_new > max_coord || height_new > max_coord)
+ ecode = gs_note_error(gs_error_limitcheck);
+#endif
+#undef max_coord
+ else
+ break;
+ END_ARRAY_PARAM(*pa, mse)
+ return ecode;
+}
+
+#if 0 /****** not used ***** */
+/* Check that a nominally read-only parameter is being set to */
+/* its existing value. */
+private int
+param_check_bool(gs_param_list * plist, gs_param_name pname, bool value,
+ bool defined)
+{
+ int code;
+ bool new_value;
+
+ switch (code = param_read_bool(plist, pname, &new_value)) {
+ case 0:
+ if (defined && new_value == value)
+ break;
+ code = gs_note_error(gs_error_rangecheck);
+ goto e;
+ default:
+ if (param_read_null(plist, pname) == 0)
+ return 1;
+ e:param_signal_error(plist, pname, code);
+ case 1:
+ ;
+ }
+ return code;
+}
+#endif /****** not used ***** */
+private int
+param_check_long(gs_param_list * plist, gs_param_name pname, long value,
+ bool defined)
+{
+ int code;
+ long new_value;
+
+ switch (code = param_read_long(plist, pname, &new_value)) {
+ case 0:
+ if (defined && new_value == value)
+ break;
+ code = gs_note_error(gs_error_rangecheck);
+ goto e;
+ default:
+ if (param_read_null(plist, pname) == 0)
+ return 1;
+ e:param_signal_error(plist, pname, code);
+ case 1:
+ ;
+ }
+ return code;
+}
+private int
+param_check_bytes(gs_param_list * plist, gs_param_name pname, const byte * str,
+ uint size, bool defined)
+{
+ int code;
+ gs_param_string new_value;
+
+ switch (code = param_read_string(plist, pname, &new_value)) {
+ case 0:
+ if (defined && new_value.size == size &&
+ !memcmp((const char *)str, (const char *)new_value.data,
+ size)
+ )
+ break;
+ code = gs_note_error(gs_error_rangecheck);
+ goto e;
+ default:
+ if (param_read_null(plist, pname) == 0)
+ return 1;
+ e:param_signal_error(plist, pname, code);
+ case 1:
+ ;
+ }
+ return code;
+}
diff --git a/pstoraster/gsdpnext.h b/pstoraster/gsdpnext.h
new file mode 100644
index 000000000..7a82ffe69
--- /dev/null
+++ b/pstoraster/gsdpnext.h
@@ -0,0 +1,34 @@
+/* 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$ */
+/* API for NeXT DPS facilities */
+
+#ifndef gsdpnext_INCLUDED
+# define gsdpnext_INCLUDED
+
+#include "gsalpha.h"
+#include "gsalphac.h"
+
+#endif /* gsdpnext_INCLUDED */
diff --git a/pstoraster/gsdps.h b/pstoraster/gsdps.h
new file mode 100644
index 000000000..e31a33bba
--- /dev/null
+++ b/pstoraster/gsdps.h
@@ -0,0 +1,40 @@
+/* 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$ */
+/* Client interface to Display PostScript facilities. */
+
+#ifndef gsdps_INCLUDED
+# define gsdps_INCLUDED
+
+/* Device-source images */
+#include "gsiparm2.h"
+
+/* View clipping */
+int gs_initviewclip(P1(gs_state *));
+int gs_eoviewclip(P1(gs_state *));
+int gs_viewclip(P1(gs_state *));
+int gs_viewclippath(P1(gs_state *));
+
+#endif /* gsdps_INCLUDED */
diff --git a/pstoraster/gsdps1.c b/pstoraster/gsdps1.c
new file mode 100644
index 000000000..e4707d003
--- /dev/null
+++ b/pstoraster/gsdps1.c
@@ -0,0 +1,242 @@
+/* Copyright (C) 1991, 1992, 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$ */
+/* Display PostScript graphics additions for Ghostscript library */
+#include "math_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsmatrix.h" /* for gscoord.h */
+#include "gscoord.h"
+#include "gspaint.h"
+#include "gxdevice.h"
+#include "gxfixed.h"
+#include "gxmatrix.h"
+#include "gspath.h"
+#include "gspath2.h" /* defines interface */
+#include "gzpath.h"
+#include "gzcpath.h"
+#include "gzstate.h"
+
+/*
+ * Define how much rounding slop setbbox should leave,
+ * in device coordinates. Because of rounding in transforming
+ * path coordinates to fixed point, the minimum realistic value is:
+ *
+ * #define box_rounding_slop_fixed (fixed_epsilon)
+ *
+ * But even this isn't enough to compensate for cumulative rounding error
+ * in rmoveto or rcurveto. Instead, we somewhat arbitrarily use:
+ */
+#define box_rounding_slop_fixed (fixed_epsilon * 3)
+
+/* ------ Graphics state ------ */
+
+/* Set the bounding box for the current path. */
+int
+gs_setbbox(gs_state * pgs, floatp llx, floatp lly, floatp urx, floatp ury)
+{
+ gs_rect ubox, dbox;
+ gs_fixed_rect obox, bbox;
+ gx_path *ppath = pgs->path;
+ int code;
+
+ if (llx > urx || lly > ury)
+ return_error(gs_error_rangecheck);
+ /* Transform box to device coordinates. */
+ ubox.p.x = llx;
+ ubox.p.y = lly;
+ ubox.q.x = urx;
+ ubox.q.y = ury;
+ if ((code = gs_bbox_transform(&ubox, &ctm_only(pgs), &dbox)) < 0)
+ return code;
+ /* Round the corners in opposite directions. */
+ /* Because we can't predict the magnitude of the dbox values, */
+ /* we add/subtract the slop after fixing. */
+ if (dbox.p.x < fixed2float(min_fixed + box_rounding_slop_fixed) ||
+ dbox.p.y < fixed2float(min_fixed + box_rounding_slop_fixed) ||
+ dbox.q.x >= fixed2float(max_fixed - box_rounding_slop_fixed + fixed_epsilon) ||
+ dbox.q.y >= fixed2float(max_fixed - box_rounding_slop_fixed + fixed_epsilon)
+ )
+ return_error(gs_error_limitcheck);
+ bbox.p.x =
+ (fixed) floor(dbox.p.x * fixed_scale) - box_rounding_slop_fixed;
+ bbox.p.y =
+ (fixed) floor(dbox.p.y * fixed_scale) - box_rounding_slop_fixed;
+ bbox.q.x =
+ (fixed) ceil(dbox.q.x * fixed_scale) + box_rounding_slop_fixed;
+ bbox.q.y =
+ (fixed) ceil(dbox.q.y * fixed_scale) + box_rounding_slop_fixed;
+ if (gx_path_bbox(ppath, &obox) >= 0) { /* Take the union of the bboxes. */
+ ppath->bbox.p.x = min(obox.p.x, bbox.p.x);
+ ppath->bbox.p.y = min(obox.p.y, bbox.p.y);
+ ppath->bbox.q.x = max(obox.q.x, bbox.q.x);
+ ppath->bbox.q.y = max(obox.q.y, bbox.q.y);
+ } else { /* empty path *//* Just set the bbox. */
+ ppath->bbox = bbox;
+ }
+ ppath->bbox_set = 1;
+ return 0;
+}
+
+/* ------ Rectangles ------ */
+
+/* Append a list of rectangles to a path. */
+int
+gs_rectappend(gs_state * pgs, const gs_rect * pr, uint count)
+{
+ for (; count != 0; count--, pr++) {
+ floatp px = pr->p.x, py = pr->p.y, qx = pr->q.x, qy = pr->q.y;
+ int code;
+
+ /* Ensure counter-clockwise drawing. */
+ if ((qx >= px) != (qy >= py))
+ qx = px, px = pr->q.x; /* swap x values */
+ if ((code = gs_moveto(pgs, px, py)) < 0 ||
+ (code = gs_lineto(pgs, qx, py)) < 0 ||
+ (code = gs_lineto(pgs, qx, qy)) < 0 ||
+ (code = gs_lineto(pgs, px, qy)) < 0 ||
+ (code = gs_closepath(pgs)) < 0
+ )
+ return code;
+ }
+ return 0;
+}
+
+/* Clip to a list of rectangles. */
+int
+gs_rectclip(gs_state * pgs, const gs_rect * pr, uint count)
+{
+ int code;
+ gx_path save;
+
+ gx_path_init_local(&save, pgs->memory);
+ gx_path_assign_preserve(&save, pgs->path);
+ gs_newpath(pgs);
+ if ((code = gs_rectappend(pgs, pr, count)) < 0 ||
+ (code = gs_clip(pgs)) < 0
+ ) {
+ gx_path_assign_free(pgs->path, &save);
+ return code;
+ }
+ gx_path_free(&save, "gs_rectclip");
+ gs_newpath(pgs);
+ return 0;
+}
+
+/* Fill a list of rectangles. */
+/* We take the trouble to do this efficiently in the simple cases. */
+int
+gs_rectfill(gs_state * pgs, const gs_rect * pr, uint count)
+{
+ const gs_rect *rlist = pr;
+ gx_clip_path *pcpath;
+ uint rcount = count;
+ int code;
+
+ gx_set_dev_color(pgs);
+ if ((is_fzero2(pgs->ctm.xy, pgs->ctm.yx) ||
+ is_fzero2(pgs->ctm.xx, pgs->ctm.yy)) &&
+ gx_effective_clip_path(pgs, &pcpath) >= 0 &&
+ clip_list_is_rectangle(gx_cpath_list(pcpath)) &&
+ gs_state_color_load(pgs) >= 0 &&
+ (*dev_proc(pgs->device, get_alpha_bits)) (pgs->device, go_graphics)
+ <= 1
+ ) {
+ uint i;
+ gs_fixed_rect clip_rect;
+
+ gx_cpath_inner_box(pcpath, &clip_rect);
+ for (i = 0; i < count; ++i) {
+ gs_fixed_point p, q;
+ gs_fixed_rect draw_rect;
+ int x, y, w, h;
+
+ if (gs_point_transform2fixed(&pgs->ctm, pr[i].p.x, pr[i].p.y, &p) < 0 ||
+ gs_point_transform2fixed(&pgs->ctm, pr[i].q.x, pr[i].q.y, &q) < 0
+ ) { /* Switch to the slow algorithm. */
+ goto slow;
+ }
+ draw_rect.p.x = min(p.x, q.x) - pgs->fill_adjust.x;
+ draw_rect.p.y = min(p.y, q.y) - pgs->fill_adjust.y;
+ draw_rect.q.x = max(p.x, q.x) + pgs->fill_adjust.x;
+ draw_rect.q.y = max(p.y, q.y) + pgs->fill_adjust.y;
+ rect_intersect(draw_rect, clip_rect);
+ x = fixed2int_pixround(draw_rect.p.x);
+ y = fixed2int_pixround(draw_rect.p.y);
+ w = fixed2int_pixround(draw_rect.q.x) - x;
+ h = fixed2int_pixround(draw_rect.q.y) - y;
+ if (w > 0 && h > 0) {
+ if (gx_fill_rectangle(x, y, w, h, pgs->dev_color, pgs) < 0)
+ goto slow;
+ }
+ }
+ return 0;
+ slow:rlist = pr + i;
+ rcount = count - i;
+ } {
+ bool do_save = !gx_path_is_null(pgs->path);
+
+ if (do_save) {
+ if ((code = gs_gsave(pgs)) < 0)
+ return code;
+ gs_newpath(pgs);
+ }
+ if ((code = gs_rectappend(pgs, rlist, rcount)) < 0 ||
+ (code = gs_fill(pgs)) < 0
+ )
+ DO_NOTHING;
+ if (do_save)
+ gs_grestore(pgs);
+ else if (code < 0)
+ gs_newpath(pgs);
+ }
+ return code;
+}
+
+/* Stroke a list of rectangles. */
+/* (We could do this a lot more efficiently.) */
+int
+gs_rectstroke(gs_state * pgs, const gs_rect * pr, uint count,
+ const gs_matrix * pmat)
+{
+ bool do_save = pmat != NULL || !gx_path_is_null(pgs->path);
+ int code;
+
+ if (do_save) {
+ if ((code = gs_gsave(pgs)) < 0)
+ return code;
+ gs_newpath(pgs);
+ }
+ if ((code = gs_rectappend(pgs, pr, count)) < 0 ||
+ (pmat != NULL && (code = gs_concat(pgs, pmat)) < 0) ||
+ (code = gs_stroke(pgs)) < 0
+ )
+ DO_NOTHING;
+ if (do_save)
+ gs_grestore(pgs);
+ else if (code < 0)
+ gs_newpath(pgs);
+ return code;
+}
diff --git a/pstoraster/gsdsrc.c b/pstoraster/gsdsrc.c
new file mode 100644
index 000000000..ea277bfc7
--- /dev/null
+++ b/pstoraster/gsdsrc.c
@@ -0,0 +1,121 @@
+/* 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$ */
+/* DataSource procedures */
+
+#include "memory_.h"
+#include "gx.h"
+#include "gsdsrc.h"
+#include "gserrors.h"
+#include "stream.h"
+
+/* GC descriptor */
+public_st_data_source();
+#define psrc ((gs_data_source_t *)vptr)
+private
+ENUM_PTRS_BEGIN(data_source_enum_ptrs)
+{
+ if (psrc->type == data_source_type_string)
+ ENUM_RETURN_CONST_STRING_PTR(gs_data_source_t, data.str);
+ else if (psrc->type == data_source_type_stream)
+ ENUM_RETURN_PTR(gs_data_source_t, data.strm);
+ else /* bytes or floats */
+ ENUM_RETURN_PTR(gs_data_source_t, data.str.data);
+}
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(data_source_reloc_ptrs)
+{
+ if (psrc->type == data_source_type_string)
+ RELOC_CONST_STRING_PTR(gs_data_source_t, data.str);
+ else if (psrc->type == data_source_type_stream)
+ RELOC_PTR(gs_data_source_t, data.strm);
+ else /* bytes or floats */
+ RELOC_PTR(gs_data_source_t, data.str.data);
+}
+RELOC_PTRS_END
+#undef psrc
+
+/* Access data from a string or a byte object. */
+/* Does *not* check bounds. */
+int
+data_source_access_string(const gs_data_source_t * psrc, ulong start,
+ uint length, byte * buf, const byte ** ptr)
+{
+ const byte *p = psrc->data.str.data + start;
+
+ if (ptr)
+ *ptr = p;
+ else
+ memcpy(buf, p, length);
+ return 0;
+}
+/* access_bytes is identical to access_string, but has a different */
+/* GC procedure. */
+int
+data_source_access_bytes(const gs_data_source_t * psrc, ulong start,
+ uint length, byte * buf, const byte ** ptr)
+{
+ const byte *p = psrc->data.str.data + start;
+
+ if (ptr)
+ *ptr = p;
+ else
+ memcpy(buf, p, length);
+ return 0;
+}
+
+/* Access data from a stream. */
+/* Returns gs_error_rangecheck if out of bounds. */
+int
+data_source_access_stream(const gs_data_source_t * psrc, ulong start,
+ uint length, byte * buf, const byte ** ptr)
+{
+ stream *s = psrc->data.strm;
+ const byte *p;
+
+ if (start >= s->position &&
+ (p = start - s->position + s->cbuf) + length <=
+ s->cursor.r.limit + 1
+ ) {
+ if (ptr)
+ *ptr = p;
+ else
+ memcpy(buf, p, length);
+ } else {
+ uint nread;
+ int code = sseek(s, start);
+
+ if (code < 0)
+ return_error(gs_error_rangecheck);
+ code = sgets(s, buf, length, &nread);
+ if (code < 0)
+ return_error(gs_error_rangecheck);
+ if (nread != length)
+ return_error(gs_error_rangecheck);
+ if (ptr)
+ *ptr = buf;
+ }
+ return 0;
+}
diff --git a/pstoraster/gsdsrc.h b/pstoraster/gsdsrc.h
new file mode 100644
index 000000000..bb6243941
--- /dev/null
+++ b/pstoraster/gsdsrc.h
@@ -0,0 +1,133 @@
+/* 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$ */
+/* DataSource definitions */
+
+#ifndef gsdsrc_INCLUDED
+# define gsdsrc_INCLUDED
+
+#include "gsstruct.h"
+
+/* ---------------- Types and structures ---------------- */
+
+/*
+ * A gs_data_source_t represents the data source for various constructs. It
+ * can be a string (either a gs_string or a byte-type object), a
+ * positionable, non-procedure-based stream, or an array of floats. An
+ * ordinary positionable file stream will do, as long as the client doesn't
+ * attempt to read past the EOF.
+ *
+ * The handling of floats is anomalous, but we don't see a good alternative
+ * at the moment.
+ */
+
+#ifndef stream_DEFINED
+# define stream_DEFINED
+typedef struct stream_s stream;
+
+#endif
+
+/*
+ * Prepare to access a block of data from a source. buf must be a client-
+ * supplied buffer of at least length bytes. If ptr == 0, always copy the
+ * data into buf. If ptr != 0, either copy the data into buf and set *ptr =
+ * buf, or set *ptr to point to the data (which might be invalidated by the
+ * next call). Note that this procedure may or may not do bounds checking.
+ */
+#define data_source_proc_access(proc)\
+ int proc(P5(const gs_data_source_t *psrc, ulong start, uint length,\
+ byte *buf, const byte **ptr))
+
+typedef enum {
+ data_source_type_string,
+ data_source_type_bytes,
+ data_source_type_floats,
+ data_source_type_stream
+} gs_data_source_type_t;
+typedef struct gs_data_source_s gs_data_source_t;
+struct gs_data_source_s {
+ data_source_proc_access((*access));
+ gs_data_source_type_t type;
+ union d_ {
+ gs_const_string str; /* also used for byte objects */
+ stream *strm;
+ } data;
+};
+
+#define data_source_access_only(psrc, start, length, buf, ptr)\
+ (*(psrc)->access)(psrc, (ulong)(start), length, buf, ptr)
+#define data_source_access(psrc, start, length, buf, ptr)\
+ BEGIN\
+ int code_ = data_source_access_only(psrc, start, length, buf, ptr);\
+ if ( code_ < 0 ) return code_;\
+ END
+#define data_source_copy_only(psrc, start, length, buf)\
+ data_source_access_only(psrc, start, length, buf, (const byte **)0)
+#define data_source_copy(psrc, start, length, buf)\
+ data_source_access(psrc, start, length, buf, (const byte **)0)
+
+/*
+ * Data sources are always embedded in other structures, but they do have
+ * pointers that need to be traced and relocated, so they do have a GC
+ * structure type.
+ */
+extern_st(st_data_source);
+#define public_st_data_source() /* in gsdsrc.c */\
+ gs_public_st_composite(st_data_source, gs_data_source_t, "gs_data_source_t",\
+ data_source_enum_ptrs, data_source_reloc_ptrs)
+#define st_data_source_max_ptrs 1
+
+/* ---------------- Procedures ---------------- */
+
+/* Initialize a data source of the various known types. */
+data_source_proc_access(data_source_access_string);
+#define data_source_init_string(psrc, strg)\
+ ((psrc)->type = data_source_type_string,\
+ (psrc)->data.str = strg, (psrc)->access = data_source_access_string)
+#define data_source_init_string2(psrc, bytes, len)\
+ ((psrc)->type = data_source_type_string,\
+ (psrc)->data.str.data = bytes, (psrc)->data.str.size = len,\
+ (psrc)->access = data_source_access_string)
+data_source_proc_access(data_source_access_bytes);
+#define data_source_init_bytes(psrc, bytes, len)\
+ ((psrc)->type = data_source_type_bytes,\
+ (psrc)->data.str.data = bytes, (psrc)->data.str.size = len,\
+ (psrc)->access = data_source_access_bytes)
+#define data_source_init_floats(psrc, floats, count)\
+ ((psrc)->type = data_source_type_floats,\
+ (psrc)->data.str.data = (byte *)floats,\
+ (psrc)->data.str.size = (count) * sizeof(float),\
+ (psrc)->access = data_source_access_bytes)
+data_source_proc_access(data_source_access_stream);
+#define data_source_init_stream(psrc, s)\
+ ((psrc)->type = data_source_type_stream,\
+ (psrc)->data.strm = s, (psrc)->access = data_source_access_stream)
+
+#define data_source_is_stream(dsource)\
+ ((dsource).type == data_source_type_stream)
+#define data_source_is_array(dsource)\
+ ((dsource).type == data_source_type_floats)
+
+#endif /* gsdsrc_INCLUDED */
diff --git a/pstoraster/gserror.h b/pstoraster/gserror.h
new file mode 100644
index 000000000..d90bcb279
--- /dev/null
+++ b/pstoraster/gserror.h
@@ -0,0 +1,42 @@
+/* Copyright (C) 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$ */
+/* Error return macros */
+
+#ifndef gserror_INCLUDED
+# define gserror_INCLUDED
+
+#ifdef DEBUG
+int gs_log_error(P3(int, const char *, int));
+
+#else
+# define gs_log_error(err, file, line) (err)
+#endif
+#define gs_note_error(err) gs_log_error(err, __FILE__, __LINE__)
+#define return_error(err) return gs_note_error(err)
+#define return_if_error(expr)\
+ BEGIN int code_ = (expr); if ( code_ < 0 ) return code_; END
+
+#endif /* gserror_INCLUDED */
diff --git a/pstoraster/gserrors.h b/pstoraster/gserrors.h
new file mode 100644
index 000000000..22bbeb32e
--- /dev/null
+++ b/pstoraster/gserrors.h
@@ -0,0 +1,56 @@
+/* Copyright (C) 1989, 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$ */
+/* Error code definitions */
+
+#ifndef gserrors_INCLUDED
+# define gserrors_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 gs_error_unknownerror (-1) /* unknown error */
+#define gs_error_interrupt (-6)
+#define gs_error_invalidaccess (-7)
+#define gs_error_invalidfileaccess (-9)
+#define gs_error_invalidfont (-10)
+#define gs_error_ioerror (-12)
+#define gs_error_limitcheck (-13)
+#define gs_error_nocurrentpoint (-14)
+#define gs_error_rangecheck (-15)
+#define gs_error_typecheck (-20)
+#define gs_error_undefined (-21)
+#define gs_error_undefinedfilename (-22)
+#define gs_error_undefinedresult (-23)
+#define gs_error_VMerror (-25)
+#define gs_error_unregistered (-29)
+
+#define gs_error_hit_detected (-99)
+
+#define gs_error_Fatal (-100)
+
+#endif /* gserrors_INCLUDED */
diff --git a/pstoraster/gsexit.h b/pstoraster/gsexit.h
new file mode 100644
index 000000000..57829a7d7
--- /dev/null
+++ b/pstoraster/gsexit.h
@@ -0,0 +1,41 @@
+/* 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$ */
+/* Declarations for exits */
+
+#ifndef gsexit_INCLUDED
+# define gsexit_INCLUDED
+
+void gs_exit_with_code(P2(int exit_status, int code));
+void gs_exit(P1(int exit_status));
+
+#define gs_abort() gs_exit(1)
+
+/* The only reason we export gs_exit_status is so that window systems */
+/* with alert boxes can know whether to pause before exiting if */
+/* the program terminates with an error. There must be a better way .... */
+extern int gs_exit_status;
+
+#endif /* gsexit_INCLUDED */
diff --git a/pstoraster/gsfcmap.c b/pstoraster/gsfcmap.c
new file mode 100644
index 000000000..b418a4aeb
--- /dev/null
+++ b/pstoraster/gsfcmap.c
@@ -0,0 +1,167 @@
+/* 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$ */
+/* CMap character decoding */
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gxfcmap.h"
+
+/* CMap structure descriptors */
+public_st_cmap();
+public_st_code_map();
+public_st_code_map_element();
+
+#define pcmap ((gx_code_map *)vptr)
+/* Because code maps can be elements of arrays, */
+/* their enum_ptrs procedure must never return 0 prematurely. */
+private
+ENUM_PTRS_BEGIN(code_map_enum_ptrs) return 0;
+ENUM_PTR(0, gx_code_map, cmap);
+case 1:
+switch (pcmap->type)
+{
+ case cmap_glyph:
+ (*pcmap->cmap->mark_glyph)(pcmap->data.glyph,
+ pcmap->cmap->mark_glyph_data);
+ default:
+ ENUM_RETURN(0);
+ case cmap_subtree:
+ ENUM_RETURN_PTR(gx_code_map, data.subtree);
+}
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(code_map_reloc_ptrs);
+switch (pcmap->type) {
+ case cmap_subtree:
+ RELOC_PTR(gx_code_map, data.subtree);
+ break;
+ default:
+ ;
+}
+RELOC_PTR(gx_code_map, cmap);
+RELOC_PTRS_END
+#undef pcmap
+
+/* CIDSystemInfo structure */
+public_st_cid_system_info();
+
+/* ---------------- Procedures ---------------- */
+
+/*
+ * Decode a character from a string using a code map, updating the index.
+ * Return 0 for a CID or name, N > 0 for a character code where N is the
+ * number of bytes in the code, or an error. For undefined characters,
+ * we set *pglyph = gs_no_glyph and return 0.
+ */
+private int
+code_map_decode_next(const gx_code_map * pcmap, const gs_const_string * str,
+ uint * pindex, uint * pfidx,
+ gs_char * pchr, gs_glyph * pglyph)
+{
+ const gx_code_map *map = pcmap;
+ uint chr = 0;
+
+ for (;;) {
+ int result;
+
+ if_debug1('J', "[J]cmap char = 0x%x: ", chr);
+ switch ((gx_code_map_type) map->type) {
+ case cmap_char_code:
+ if_debug0('J', "char code");
+ *pglyph = (gs_glyph)map->data.ccode;
+ result = map->num_bytes1 + 1;
+leaf: if (chr > map->last)
+ goto undef;
+ if (map->add_offset)
+ *pglyph += chr - map->first;
+ *pfidx = map->byte_data.font_index;
+ *pchr = chr & 0xff;
+ if_debug3('J', " 0x%lx, fidx %u, result %d\n",
+ *pglyph, *pfidx, result);
+ return result;
+ case cmap_glyph:
+ if_debug0('J', "glyph");
+ *pglyph = map->data.glyph;
+ result = 0;
+ goto leaf;
+ case cmap_subtree:
+ if_debug0('J', "subtree\n");
+ if (*pindex >= str->size)
+ return_error(gs_error_rangecheck);
+ chr = str->data[(*pindex)++];
+ if (chr >= map->data.subtree[0].first) {
+ /* Invariant: map[lo].first <= chr < map[hi].first. */
+ uint lo = 0, hi = map->byte_data.count1 + 1;
+
+ map = map->data.subtree;
+ while (lo + 1 < hi) {
+ uint mid = (lo + hi) >> 1;
+
+ if (chr >= map[mid].first)
+ lo = mid;
+ else
+ hi = mid;
+ }
+ map = &map[lo];
+ continue;
+ }
+undef: if_debug0('J', " undef\n");
+ *pchr = 0;
+ *pglyph = gs_no_glyph;
+ return 0;
+ default: /* (can't happen) */
+ if_debug0('J', "error!\n");
+ return_error(gs_error_invalidfont);
+ }
+ }
+}
+
+/*
+ * Decode a character from a string using a CMap.
+ * Return like code_map_decode_next.
+ */
+int
+gs_cmap_decode_next(const gs_cmap * pcmap, const gs_const_string * str,
+ uint * pindex, uint * pfidx,
+ gs_char * pchr, gs_glyph * pglyph)
+{
+ uint save_index = *pindex;
+ int code =
+ code_map_decode_next(&pcmap->def, str, pindex, pfidx, pchr, pglyph);
+
+ if (code != 0 || *pglyph != gs_no_glyph)
+ return code;
+ /* This is an undefined character. Use the notdef map. */
+ {
+ uint next_index = *pindex;
+
+ *pindex = save_index;
+ code =
+ code_map_decode_next(&pcmap->notdef, str, pindex, pfidx,
+ pchr, pglyph);
+ *pindex = next_index;
+ }
+ return code;
+}
diff --git a/pstoraster/gsfcmap.h b/pstoraster/gsfcmap.h
new file mode 100644
index 000000000..628a111a7
--- /dev/null
+++ b/pstoraster/gsfcmap.h
@@ -0,0 +1,69 @@
+/* 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$ */
+/* CMap data definition */
+/* Requires gsstruct.h */
+
+#ifndef gsfcmap_INCLUDED
+# define gsfcmap_INCLUDED
+
+#include "gsccode.h"
+
+/* Define the abstract type for a CMap. */
+#ifndef gs_cmap_DEFINED
+# define gs_cmap_DEFINED
+typedef struct gs_cmap_s gs_cmap;
+
+#endif
+
+/* We only need the structure descriptor for testing. */
+extern_st(st_cmap);
+
+/* Define the structure for CIDSystemInfo. */
+typedef struct gs_cid_system_info_s {
+ gs_const_string Registry;
+ gs_const_string Ordering;
+ int Supplement;
+} gs_cid_system_info;
+/* We only need the structure descriptor for embedding. */
+extern_st(st_cid_system_info);
+#define public_st_cid_system_info() /* in gsfcmap.c */\
+ gs_public_st_const_strings2(st_cid_system_info, gs_cid_system_info,\
+ "gs_cid_system_info", cid_si_enum_ptrs, cid_si_reloc_ptrs,\
+ Registry, Ordering)
+
+/* ---------------- Procedural interface ---------------- */
+
+/*
+ * Decode a character from a string using a CMap, updating the index.
+ * Return 0 for a CID or name, N > 0 for a character code where N is the
+ * number of bytes in the code, or an error. For undefined characters,
+ * we return CID 0.
+ */
+int gs_cmap_decode_next(P6(const gs_cmap * pcmap, const gs_const_string * str,
+ uint * pindex, uint * pfidx,
+ gs_char * pchr, gs_glyph * pglyph));
+
+#endif /* gsfcmap_INCLUDED */
diff --git a/pstoraster/gsflip.h b/pstoraster/gsflip.h
new file mode 100644
index 000000000..e1e19ab30
--- /dev/null
+++ b/pstoraster/gsflip.h
@@ -0,0 +1,46 @@
+/* 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$ */
+/* Interface to routines for "flipping" image data */
+
+#ifndef gsflip_INCLUDED
+# define gsflip_INCLUDED
+
+/*
+ * Convert line-based (MultipleDataSource) input to the chunky format
+ * used everywhere else.
+ *
+ * We store the output at buffer.
+ * Each row of input must consist of an integral number of pixels.
+ * In particular, for 12-bit input, nbytes must be 0 mod 3.
+ * offset is the amount to be added to each plane pointer.
+ * num_planes must be 3 or 4; bits_per_sample must be 1, 2, 4, 8, or 12.
+ * Returns -1 if num_planes or bits_per_sample is invalid, otherwise 0.
+ */
+extern int image_flip_planes(P6(byte * buffer, const byte ** planes,
+ uint offset, uint nbytes,
+ int num_planes, int bits_per_sample));
+
+#endif /* gsflip_INCLUDED */
diff --git a/pstoraster/gsfont.c b/pstoraster/gsfont.c
new file mode 100644
index 000000000..efa4204b3
--- /dev/null
+++ b/pstoraster/gsfont.c
@@ -0,0 +1,558 @@
+/* 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$ */
+/* Font operators for Ghostscript library */
+#include "gx.h"
+#include "memory_.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gxfixed.h"
+#include "gxmatrix.h"
+#include "gzstate.h" /* must precede gxdevice */
+#include "gxdevice.h" /* must precede gxfont */
+#include "gschar.h"
+#include "gxfont.h"
+#include "gxfcache.h"
+
+/* Imported procedures */
+void gs_purge_font_from_char_caches(P2(gs_font_dir *, const gs_font *));
+
+/* Define the sizes of the various aspects of the font/character cache. */
+/*** Big memory machines ***/
+#define smax_LARGE 50 /* smax - # of scaled fonts */
+#define bmax_LARGE 500000 /* bmax - space for cached chars */
+#define mmax_LARGE 200 /* mmax - # of cached font/matrix pairs */
+#define cmax_LARGE 5000 /* cmax - # of cached chars */
+#define blimit_LARGE 2500 /* blimit/upper - max size of a single cached char */
+/*** Small memory machines ***/
+#define smax_SMALL 20 /* smax - # of scaled fonts */
+#define bmax_SMALL 25000 /* bmax - space for cached chars */
+#define mmax_SMALL 40 /* mmax - # of cached font/matrix pairs */
+#define cmax_SMALL 500 /* cmax - # of cached chars */
+#define blimit_SMALL 100 /* blimit/upper - max size of a single cached char */
+
+private_st_font_dir();
+private struct_proc_enum_ptrs(font_enum_ptrs);
+private struct_proc_reloc_ptrs(font_reloc_ptrs);
+
+public_st_gs_font();
+public_st_gs_font_base();
+private_st_gs_font_ptr();
+public_st_gs_font_ptr_element();
+
+/*
+ * Garbage collection of fonts poses some special problems. On the one
+ * hand, we need to keep track of all existing base (not scaled) fonts,
+ * using the next/prev list whose head is the orig_fonts member of the font
+ * directory; on the other hand, we want these to be "weak" pointers that
+ * don't keep fonts in existence if the fonts aren't referenced from
+ * anywhere else. We accomplish this as follows:
+ *
+ * We don't trace through gs_font_dir.orig_fonts or gs_font.{next,prev}
+ * during the mark phase of the GC.
+ *
+ * When we finalize a base gs_font, we unlink it from the list. (A
+ * gs_font is a base font iff its base member points to itself.)
+ *
+ * We *do* relocate the orig_fonts and next/prev pointers during the
+ * relocation phase of the GC. */
+
+/* Font directory GC procedures */
+#define dir ((gs_font_dir *)vptr)
+private
+ENUM_PTRS_BEGIN(font_dir_enum_ptrs)
+{ /* Enumerate pointers from cached characters to f/m pairs, */
+ /* and mark the cached character glyphs. */
+ /* See gxfcache.h for why we do this here. */
+ uint cci = index - st_font_dir_max_ptrs;
+ uint offset, count;
+ uint tmask = dir->ccache.table_mask;
+
+ if (cci == 0)
+ offset = 0, count = 1;
+ else if (cci == dir->enum_index + 1)
+ offset = dir->enum_offset + 1, count = 1;
+ else
+ offset = 0, count = cci;
+ for (; offset <= tmask; ++offset) {
+ cached_char *cc = dir->ccache.table[offset];
+
+ if (cc != 0 && !--count) {
+ (*dir->ccache.mark_glyph)
+ (cc->code, dir->ccache.mark_glyph_data);
+ dir->enum_index = cci;
+ dir->enum_offset = offset;
+ ENUM_RETURN(cc_pair(cc) - cc->pair_index);
+ }
+ }
+}
+return 0;
+#define e1(i,elt) ENUM_PTR(i,gs_font_dir,elt);
+font_dir_do_ptrs(e1)
+#undef e1
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(font_dir_reloc_ptrs);
+ /* Relocate the pointers from cached characters to f/m pairs. */
+ /* See gxfcache.h for why we do this here. */
+{
+ int chi;
+
+ for (chi = dir->ccache.table_mask; chi >= 0; --chi) {
+ cached_char *cc = dir->ccache.table[chi];
+
+ if (cc != 0)
+ cc_set_pair_only(cc,
+ (cached_fm_pair *)
+ RELOC_OBJ(cc_pair(cc) - cc->pair_index) +
+ cc->pair_index);
+ }
+}
+ /* We have to relocate the cached characters before we */
+ /* relocate dir->ccache.table! */
+RELOC_PTR(gs_font_dir, orig_fonts);
+#define r1(i,elt) RELOC_PTR(gs_font_dir, elt);
+font_dir_do_ptrs(r1)
+#undef r1
+RELOC_PTRS_END
+#undef dir
+
+/* GC procedures for fonts */
+#define pfont ((gs_font *)vptr)
+/*
+ * When we finalize a base font, we unlink it from the orig_fonts list;
+ * when we finalize a scaled font, we unlink it from scaled_fonts.
+ * See above for more information.
+ */
+ void
+ gs_font_finalize(void *vptr)
+{
+ gs_font **ppfirst;
+ gs_font *next = pfont->next;
+ gs_font *prev = pfont->prev;
+
+ if_debug4('u', "[u]unlinking font 0x%lx, base=0x%lx, prev=0x%lx, next=0x%lx\n",
+ (ulong) pfont, (ulong) pfont->base, (ulong) prev, (ulong) next);
+ if (pfont->dir == 0)
+ ppfirst = 0;
+ else if (pfont->base == pfont)
+ ppfirst = &pfont->dir->orig_fonts;
+ else { /*
+ * Track the number of cached scaled fonts. Only decrement the
+ * count if we didn't do this already in gs_makefont.
+ */
+ if (next || prev || pfont->dir->scaled_fonts == pfont)
+ pfont->dir->ssize--;
+ ppfirst = &pfont->dir->scaled_fonts;
+ }
+ /*
+ * gs_purge_font may have unlinked this font already:
+ * don't unlink it twice.
+ */
+ if (next != 0 && next->prev == pfont)
+ next->prev = prev;
+ if (prev != 0) {
+ if (prev->next == pfont)
+ prev->next = next;
+ } else if (ppfirst != 0 && *ppfirst == pfont)
+ *ppfirst = next;
+}
+private
+ENUM_PTRS_BEGIN(font_enum_ptrs) return 0;
+
+ /* We don't enumerate next or prev of base fonts. */
+ /* See above for details. */
+case 0:
+ENUM_RETURN((pfont->base == pfont ? 0 : pfont->next));
+case 1:
+ENUM_RETURN((pfont->base == pfont ? 0 : pfont->prev));
+ENUM_PTR(2, gs_font, dir);
+ENUM_PTR(3, gs_font, base);
+ENUM_PTR(4, gs_font, client_data);
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(font_reloc_ptrs);
+ /* We *do* always relocate next and prev. */
+ /* Again, see above for details. */
+RELOC_PTR(gs_font, next);
+RELOC_PTR(gs_font, prev);
+RELOC_PTR(gs_font, dir);
+RELOC_PTR(gs_font, base);
+RELOC_PTR(gs_font, client_data);
+RELOC_PTRS_END
+#undef pfont
+
+/* Allocate a font directory */
+private bool
+cc_no_mark_glyph(gs_glyph glyph, void *ignore_data)
+{
+ return false;
+}
+gs_font_dir *
+gs_font_dir_alloc2(gs_memory_t * struct_mem, gs_memory_t * bits_mem)
+{
+ gs_font_dir *pdir = 0;
+
+#if !arch_small_memory
+# ifdef DEBUG
+ if (!gs_debug_c('.'))
+# endif
+ { /* Try allocating a very large cache. */
+ /* If this fails, allocate a small one. */
+ pdir = gs_font_dir_alloc2_limits(struct_mem, bits_mem,
+ smax_LARGE, bmax_LARGE, mmax_LARGE,
+ cmax_LARGE, blimit_LARGE);
+ }
+ if (pdir == 0)
+#endif
+ pdir = gs_font_dir_alloc2_limits(struct_mem, bits_mem,
+ smax_SMALL, bmax_SMALL, mmax_SMALL,
+ cmax_SMALL, blimit_SMALL);
+ if (pdir == 0)
+ return 0;
+ pdir->ccache.mark_glyph = cc_no_mark_glyph;
+ pdir->ccache.mark_glyph_data = 0;
+ return pdir;
+}
+gs_font_dir *
+gs_font_dir_alloc2_limits(gs_memory_t * struct_mem, gs_memory_t * bits_mem,
+ uint smax, uint bmax, uint mmax, uint cmax, uint upper)
+{
+ register gs_font_dir *pdir =
+ gs_alloc_struct(struct_mem, gs_font_dir, &st_font_dir,
+ "font_dir_alloc(dir)");
+ int code;
+
+ if (pdir == 0)
+ return 0;
+ code = gx_char_cache_alloc(struct_mem, bits_mem, pdir,
+ bmax, mmax, cmax, upper);
+ if (code < 0) {
+ gs_free_object(struct_mem, pdir, "font_dir_alloc(dir)");
+ return 0;
+ }
+ pdir->orig_fonts = 0;
+ pdir->scaled_fonts = 0;
+ pdir->ssize = 0;
+ pdir->smax = smax;
+ return pdir;
+}
+
+/* Macro for linking an element at the head of a chain */
+#define link_first(first, elt)\
+ if ( (elt->next = first) != NULL ) first->prev = elt;\
+ elt->prev = 0;\
+ first = elt
+
+/* definefont */
+/* Use this only for original (unscaled) fonts! */
+/* Note that it expects pfont->procs.define_font to be set already. */
+int
+gs_definefont(gs_font_dir * pdir, gs_font * pfont)
+{
+ int code;
+
+ pfont->dir = pdir;
+ pfont->base = pfont;
+ code = (*pfont->procs.define_font) (pdir, pfont);
+ if (code < 0) { /* Make sure we don't try to finalize this font. */
+ pfont->base = 0;
+ return code;
+ }
+ link_first(pdir->orig_fonts, pfont);
+ if_debug2('m', "[m]defining font 0x%lx, next=0x%lx\n",
+ (ulong) pfont, (ulong) pfont->next);
+ return 0;
+}
+/* Default (vacuous) definefont handler. */
+int
+gs_no_define_font(gs_font_dir * pdir, gs_font * pfont)
+{
+ return 0;
+}
+
+/* scalefont */
+int
+gs_scalefont(gs_font_dir * pdir, const gs_font * pfont, floatp scale,
+ gs_font ** ppfont)
+{
+ gs_matrix mat;
+
+ gs_make_scaling(scale, scale, &mat);
+ return gs_makefont(pdir, pfont, &mat, ppfont);
+}
+
+/* makefont */
+int
+gs_makefont(gs_font_dir * pdir, const gs_font * pfont,
+ const gs_matrix * pmat, gs_font ** ppfont)
+{
+#define pbfont ((const gs_font_base *)pfont)
+ int code;
+ gs_font *prev = 0;
+ gs_font *pf_out = pdir->scaled_fonts;
+ gs_memory_t *mem = pfont->memory;
+ gs_matrix newmat;
+ bool can_cache;
+
+ if ((code = gs_matrix_multiply(&pfont->FontMatrix, pmat, &newmat)) < 0)
+ return code;
+ /* Check for the font already being in the scaled font cache. */
+ /* Only attempt to share fonts if the current font has */
+ /* a valid UniqueID or XUID. */
+#ifdef DEBUG
+ if (gs_debug_c('m')) {
+ if (pfont->FontType == ft_composite)
+ dlprintf("[m]composite");
+ else if (uid_is_UniqueID(&pbfont->UID))
+ dlprintf1("[m]UniqueID=%ld", pbfont->UID.id);
+ else if (uid_is_XUID(&pbfont->UID))
+ dlprintf1("[m]XUID(%u)", (uint) (-pbfont->UID.id));
+ else
+ dlprintf("[m]no UID");
+ dprintf7(", FontType=%d,\n[m] new FontMatrix=[%g %g %g %g %g %g]\n",
+ pfont->FontType,
+ pmat->xx, pmat->xy, pmat->yx, pmat->yy,
+ pmat->tx, pmat->ty);
+ }
+#endif
+ /* The UID of a composite font is of no value in caching.... */
+ if (pfont->FontType != ft_composite &&
+ uid_is_valid(&pbfont->UID)
+ ) {
+ for (; pf_out != 0; prev = pf_out, pf_out = pf_out->next)
+ if (pf_out->FontType == pfont->FontType &&
+ pf_out->base == pfont->base &&
+ uid_equal(&((gs_font_base *) pf_out)->UID, &pbfont->UID) &&
+ pf_out->FontMatrix.xx == newmat.xx &&
+ pf_out->FontMatrix.xy == newmat.xy &&
+ pf_out->FontMatrix.yx == newmat.yx &&
+ pf_out->FontMatrix.yy == newmat.yy &&
+ pf_out->FontMatrix.tx == newmat.tx &&
+ pf_out->FontMatrix.ty == newmat.ty
+ ) {
+ *ppfont = pf_out;
+ if_debug1('m', "[m]found font=0x%lx\n", (ulong) pf_out);
+ return 0;
+ }
+ can_cache = true;
+ } else
+ can_cache = false;
+ pf_out = gs_alloc_struct(mem, gs_font, gs_object_type(mem, pfont),
+ "gs_makefont");
+ if (!pf_out)
+ return_error(gs_error_VMerror);
+ memcpy(pf_out, pfont, gs_object_size(mem, pfont));
+ pf_out->FontMatrix = newmat;
+ pf_out->client_data = 0;
+ pf_out->dir = pdir;
+ pf_out->base = pfont->base;
+ *ppfont = pf_out;
+ code = (*pf_out->procs.make_font) (pdir, pfont, pmat, ppfont);
+ if (code < 0)
+ return code;
+ if (can_cache) {
+ if (pdir->ssize >= pdir->smax && prev != 0) { /*
+ * We must discard a cached scaled font.
+ * prev points to the last (oldest) font.
+ * (We can't free it, because there might be
+ * other references to it.)
+ */
+ if_debug1('m', "[m]discarding font 0x%lx\n",
+ (ulong) prev);
+ if (prev->prev != 0)
+ prev->prev->next = 0;
+ else
+ pdir->scaled_fonts = 0;
+ pdir->ssize--;
+ prev->prev = 0;
+ if (prev->FontType != ft_composite) {
+ if_debug1('m', "[m]discarding UID 0x%lx\n",
+ (ulong) ((gs_font_base *) prev)->
+ UID.xvalues);
+ uid_free(&((gs_font_base *) prev)->UID,
+ prev->memory,
+ "gs_makefont(discarding)");
+ uid_set_invalid(&((gs_font_base *) prev)->UID);
+ }
+ }
+ pdir->ssize++;
+ link_first(pdir->scaled_fonts, pf_out);
+ } else { /* Prevent garbage pointers. */
+ pf_out->next = pf_out->prev = 0;
+ }
+ if_debug2('m', "[m]new font=0x%lx can_cache=%s\n",
+ (ulong) * ppfont, (can_cache ? "true" : "false"));
+ return 1;
+#undef pbfont
+}
+/* Default (vacuous) makefont handler. */
+int
+gs_no_make_font(gs_font_dir * pdir, const gs_font * pfont,
+ const gs_matrix * pmat, gs_font ** ppfont)
+{
+ return 0;
+}
+/* Makefont handler for base fonts, which must copy the XUID. */
+int
+gs_base_make_font(gs_font_dir * pdir, const gs_font * pfont,
+ const gs_matrix * pmat, gs_font ** ppfont)
+{
+#define pbfont ((gs_font_base *)*ppfont)
+ if (uid_is_XUID(&pbfont->UID)) {
+ uint xsize = uid_XUID_size(&pbfont->UID);
+ long *xvalues = (long *)
+ gs_alloc_byte_array(pbfont->memory, xsize, sizeof(long),
+ "gs_base_make_font(XUID)");
+
+ if (xvalues == 0)
+ return_error(gs_error_VMerror);
+ memcpy(xvalues, uid_XUID_values(&pbfont->UID),
+ xsize * sizeof(long));
+
+ pbfont->UID.xvalues = xvalues;
+ }
+#undef pbfont
+ return 0;
+}
+
+/* Set the current font. This is provided only for the benefit of cshow, */
+/* which must reset the current font without disturbing the root font. */
+void
+gs_set_currentfont(gs_state * pgs, gs_font * pfont)
+{
+ pgs->font = pfont;
+ pgs->char_tm_valid = false;
+}
+
+/* setfont */
+int
+gs_setfont(gs_state * pgs, gs_font * pfont)
+{
+ pgs->font = pgs->root_font = pfont;
+ pgs->char_tm_valid = false;
+ return 0;
+}
+
+/* currentfont */
+gs_font *
+gs_currentfont(const gs_state * pgs)
+{
+ return pgs->font;
+}
+
+/* rootfont */
+gs_font *
+gs_rootfont(const gs_state * pgs)
+{
+ return pgs->root_font;
+}
+
+/* cachestatus */
+void
+gs_cachestatus(register const gs_font_dir * pdir, register uint pstat[7])
+{
+ pstat[0] = pdir->ccache.bsize;
+ pstat[1] = pdir->ccache.bmax;
+ pstat[2] = pdir->fmcache.msize;
+ pstat[3] = pdir->fmcache.mmax;
+ pstat[4] = pdir->ccache.csize;
+ pstat[5] = pdir->ccache.cmax;
+ pstat[6] = pdir->ccache.upper;
+}
+
+/* setcacheparams */
+int
+gs_setcachesize(gs_font_dir * pdir, uint size)
+{ /* This doesn't delete anything from the cache yet. */
+ pdir->ccache.bmax = size;
+ return 0;
+}
+int
+gs_setcachelower(gs_font_dir * pdir, uint size)
+{
+ pdir->ccache.lower = size;
+ return 0;
+}
+int
+gs_setcacheupper(gs_font_dir * pdir, uint size)
+{
+ pdir->ccache.upper = size;
+ return 0;
+}
+
+/* currentcacheparams */
+uint
+gs_currentcachesize(const gs_font_dir * pdir)
+{
+ return pdir->ccache.bmax;
+}
+uint
+gs_currentcachelower(const gs_font_dir * pdir)
+{
+ return pdir->ccache.lower;
+}
+uint
+gs_currentcacheupper(const gs_font_dir * pdir)
+{
+ return pdir->ccache.upper;
+}
+
+/* Purge a font from all font- and character-related tables. */
+/* This is only used by restore (and, someday, the GC). */
+void
+gs_purge_font(gs_font * pfont)
+{
+ gs_font_dir *pdir = pfont->dir;
+ gs_font *pf;
+
+ /* Remove the font from its list (orig_fonts or scaled_fonts). */
+ gs_font *prev = pfont->prev;
+ gs_font *next = pfont->next;
+
+ if (next != 0)
+ next->prev = prev, pfont->next = 0;
+ if (prev != 0)
+ prev->next = next, pfont->prev = 0;
+ else if (pdir->orig_fonts == pfont)
+ pdir->orig_fonts = next;
+ else if (pdir->scaled_fonts == pfont)
+ pdir->scaled_fonts = next;
+ else { /* Shouldn't happen! */
+ lprintf1("purged font 0x%lx not found\n", (ulong) pfont);
+ }
+
+ /* Purge the font from the scaled font cache. */
+ for (pf = pdir->scaled_fonts; pf != 0;) {
+ if (pf->base == pfont) {
+ gs_purge_font(pf);
+ pf = pdir->scaled_fonts; /* start over */
+ } else
+ pf = pf->next;
+ }
+
+ /* Purge the font from the font/matrix pair cache, */
+ /* including all cached characters rendered with that font. */
+ gs_purge_font_from_char_caches(pdir, pfont);
+
+}
diff --git a/pstoraster/gsfont.h b/pstoraster/gsfont.h
new file mode 100644
index 000000000..8674d82e2
--- /dev/null
+++ b/pstoraster/gsfont.h
@@ -0,0 +1,87 @@
+/* Copyright (C) 1989, 1993, 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$ */
+/* Requires gsmatrix.h */
+
+#ifndef gsfont_INCLUDED
+# define gsfont_INCLUDED
+
+/* A 'font directory' object (to avoid making fonts global). */
+/* 'directory' is something of a misnomer: this structure */
+/* just keeps track of the defined fonts, and the scaled font and */
+/* rendered character caches. */
+#ifndef gs_font_dir_DEFINED
+# define gs_font_dir_DEFINED
+typedef struct gs_font_dir_s gs_font_dir;
+
+#endif
+
+/* Font objects */
+#ifndef gs_font_DEFINED
+# define gs_font_DEFINED
+typedef struct gs_font_s gs_font;
+
+#endif
+
+/* Initialization */
+/* These procedures return 0 if they fail. */
+gs_font_dir *gs_font_dir_alloc2(P2(gs_memory_t * struct_mem,
+ gs_memory_t * bits_mem));
+gs_font_dir *gs_font_dir_alloc2_limits(P7(gs_memory_t * struct_mem,
+ gs_memory_t * bits_mem,
+ uint smax, uint bmax, uint mmax,
+ uint cmax, uint upper));
+
+/* Backward compatibility */
+#define gs_font_dir_alloc(mem) gs_font_dir_alloc2(mem, mem)
+#define gs_font_dir_alloc_limits(mem, smax, bmax, mmax, cmax, upper)\
+ gs_font_dir_alloc2_limits(mem, mem, smax, bmax, mmax, cmax, upper)
+
+/* Font manipulations */
+/* Use gs_definefont only with original (unscaled) fonts! */
+int gs_definefont(P2(gs_font_dir *, gs_font *));
+
+/* gs_scalefont and gs_makefont return 0 if the scaled font */
+/* was already in the cache, 1 if a new font was created. */
+int gs_scalefont(P4(gs_font_dir *, const gs_font *, floatp, gs_font **));
+int gs_makefont(P4(gs_font_dir *, const gs_font *, const gs_matrix *, gs_font **));
+int gs_setfont(P2(gs_state *, gs_font *));
+gs_font *gs_currentfont(P1(const gs_state *));
+gs_font *gs_rootfont(P1(const gs_state *));
+void gs_set_currentfont(P2(gs_state *, gs_font *));
+void gs_purge_font(P1(gs_font *));
+
+/* Font cache parameter operations */
+void gs_cachestatus(P2(const gs_font_dir *, uint[7]));
+
+#define gs_setcachelimit(pdir,limit) gs_setcacheupper(pdir,limit)
+uint gs_currentcachesize(P1(const gs_font_dir *));
+int gs_setcachesize(P2(gs_font_dir *, uint));
+uint gs_currentcachelower(P1(const gs_font_dir *));
+int gs_setcachelower(P2(gs_font_dir *, uint));
+uint gs_currentcacheupper(P1(const gs_font_dir *));
+int gs_setcacheupper(P2(gs_font_dir *, uint));
+
+#endif /* gsfont_INCLUDED */
diff --git a/pstoraster/gsfont0.c b/pstoraster/gsfont0.c
new file mode 100644
index 000000000..95ca444b7
--- /dev/null
+++ b/pstoraster/gsfont0.c
@@ -0,0 +1,136 @@
+/* Copyright (C) 1994, 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$ */
+/* Composite font operations for Ghostscript library */
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gxfixed.h"
+#include "gsmatrix.h"
+#include "gxdevice.h"
+#include "gxdevmem.h"
+#include "gxchar.h"
+#include "gxfcache.h" /* gs_font_dir */
+#include "gxfont.h"
+#include "gxfont0.h"
+
+/* Structure descriptor */
+private struct_proc_enum_ptrs(font_type0_enum_ptrs);
+private struct_proc_reloc_ptrs(font_type0_reloc_ptrs);
+
+public_st_gs_font_type0();
+#define pfont ((gs_font_type0 *)vptr)
+private
+ENUM_PTRS_BEGIN(font_type0_enum_ptrs) ENUM_PREFIX(st_gs_font, gs_type0_data_max_ptrs);
+
+ENUM_PTR(0, gs_font_type0, data.Encoding);
+ENUM_PTR(1, gs_font_type0, data.FDepVector);
+case 2:
+switch (pfont->data.FMapType)
+{
+ case fmap_SubsVector:
+ENUM_RETURN_CONST_STRING_PTR(gs_font_type0,
+ data.SubsVector);
+ case fmap_CMap:
+ENUM_RETURN_PTR(gs_font_type0, data.CMap);
+ default:
+ENUM_RETURN(0);
+}
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(font_type0_reloc_ptrs) RELOC_PREFIX(st_gs_font);
+RELOC_PTR(gs_font_type0, data.Encoding);
+RELOC_PTR(gs_font_type0, data.FDepVector);
+switch (pfont->data.FMapType)
+{
+ case fmap_SubsVector:
+RELOC_CONST_STRING_PTR(gs_font_type0, data.SubsVector);
+break;
+ case fmap_CMap:
+RELOC_PTR(gs_font_type0, data.CMap);
+break;
+ default:
+;
+}
+RELOC_PTRS_END
+#undef pfont
+
+/* Adjust a composite font by concatenating a given matrix */
+/* to the FontMatrix of all descendant composite fonts. */
+private int
+gs_type0_adjust_matrix(gs_font_dir * pdir, gs_font_type0 * pfont,
+ const gs_matrix * pmat)
+{
+ gs_font **pdep = pfont->data.FDepVector;
+ uint fdep_size = pfont->data.fdep_size;
+ gs_font **ptdep;
+ uint i;
+
+ /* Check for any descendant composite fonts. */
+ for (i = 0; i < fdep_size; i++)
+ if (pdep[i]->FontType == ft_composite)
+ break;
+ if (i == fdep_size)
+ return 0;
+ ptdep = gs_alloc_struct_array(pfont->memory, fdep_size, gs_font *,
+ &st_gs_font_ptr_element,
+ "gs_type0_adjust_font(FDepVector)");
+ if (ptdep == 0)
+ return_error(gs_error_VMerror);
+ memcpy(ptdep, pdep, sizeof(gs_font *) * fdep_size);
+ for (; i < fdep_size; i++)
+ if (pdep[i]->FontType == ft_composite) {
+ int code = gs_makefont(pdir, pdep[i], pmat, &ptdep[i]);
+
+ if (code < 0)
+ return code;
+ }
+ pfont->data.FDepVector = ptdep;
+ return 0;
+}
+
+/* Finish defining a composite font, */
+/* by adjusting its descendants' FontMatrices. */
+int
+gs_type0_define_font(gs_font_dir * pdir, gs_font * pfont)
+{
+ const gs_matrix *pmat = &pfont->FontMatrix;
+
+ /* Check for the identity matrix, which is common in root fonts. */
+ if (pmat->xx == 1.0 && pmat->yy == 1.0 &&
+ pmat->xy == 0.0 && pmat->yx == 0.0 &&
+ pmat->tx == 0.0 && pmat->ty == 0.0
+ )
+ return 0;
+ return gs_type0_adjust_matrix(pdir, (gs_font_type0 *) pfont, pmat);
+}
+
+/* Finish scaling a composite font similarly. */
+int
+gs_type0_make_font(gs_font_dir * pdir, const gs_font * pfont,
+ const gs_matrix * pmat, gs_font ** ppfont)
+{
+ return gs_type0_adjust_matrix(pdir, (gs_font_type0 *) * ppfont, pmat);
+}
diff --git a/pstoraster/gsfunc.c b/pstoraster/gsfunc.c
new file mode 100644
index 000000000..f0c438c9e
--- /dev/null
+++ b/pstoraster/gsfunc.c
@@ -0,0 +1,78 @@
+/* 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$ */
+/* Generic Function support */
+#include "gx.h"
+#include "gserrors.h"
+#include "gxfunc.h"
+
+/* GC descriptor */
+public_st_function();
+
+/* Generic free_params implementation. */
+void
+fn_common_free_params(gs_function_params_t * params, gs_memory_t * mem)
+{
+ gs_free_object(mem, (void *)params->Range, "Range"); /* break const */
+ gs_free_object(mem, (void *)params->Domain, "Domain"); /* break const */
+}
+
+/* Generic free implementation. */
+void
+fn_common_free(gs_function_t * pfn, bool free_params, gs_memory_t * mem)
+{
+ if (free_params)
+ gs_function_free_params(pfn, mem);
+ gs_free_object(mem, pfn, "fn_xxx_free");
+}
+
+/* Free an array of subsidiary Functions. */
+void
+fn_free_functions(gs_function_t ** Functions, int count, gs_memory_t * mem)
+{
+ int i;
+
+ for (i = count; --i >= 0;)
+ gs_function_free(Functions[i], true, mem);
+ gs_free_object(mem, Functions, "Functions");
+}
+
+/* Check the values of m, n, Domain, and (if supplied) Range. */
+int
+fn_check_mnDR(const gs_function_params_t * params, int m, int n)
+{
+ int i;
+
+ if (m <= 0 || n <= 0)
+ return_error(gs_error_rangecheck);
+ for (i = 0; i < m; ++i)
+ if (params->Domain[2 * i] > params->Domain[2 * i + 1])
+ return_error(gs_error_rangecheck);
+ if (params->Range != 0)
+ for (i = 0; i < n; ++i)
+ if (params->Range[2 * i] > params->Range[2 * i + 1])
+ return_error(gs_error_rangecheck);
+ return 0;
+}
diff --git a/pstoraster/gsfunc.h b/pstoraster/gsfunc.h
new file mode 100644
index 000000000..e621918e3
--- /dev/null
+++ b/pstoraster/gsfunc.h
@@ -0,0 +1,136 @@
+/* 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$ */
+/* Generic definitions for Functions */
+
+#ifndef gsfunc_INCLUDED
+# define gsfunc_INCLUDED
+
+/* ---------------- Types and structures ---------------- */
+
+/*
+ * gs_function_type_t is defined as equivalent to int, rather than as an
+ * enum type, because we can't enumerate all its possible values here in the
+ * generic definitions.
+ */
+typedef int gs_function_type_t;
+
+/*
+ * Define information common to all Function types.
+ * We separate the private part from the parameters so that
+ * clients can create statically initialized parameter structures.
+ */
+#define gs_function_params_common\
+ int m; /* # of inputs */\
+ const float *Domain; /* 2 x m */\
+ int n; /* # of outputs */\
+ const float *Range /* 2 x n, optional except for type 0 */
+
+/* Define a generic function, for use as the target type of pointers. */
+typedef struct gs_function_params_s {
+ gs_function_params_common;
+} gs_function_params_t;
+typedef struct gs_function_s gs_function_t;
+typedef int (*fn_evaluate_proc_t)(P3(const gs_function_t * pfn,
+ const float *in, float *out));
+typedef int (*fn_is_monotonic_proc_t)(P4(const gs_function_t * pfn,
+ const float *lower,
+ const float *upper,
+ bool must_know));
+typedef void (*fn_free_params_proc_t)(P2(gs_function_params_t * params,
+ gs_memory_t * mem));
+typedef void (*fn_free_proc_t)(P3(gs_function_t * pfn,
+ bool free_params, gs_memory_t * mem));
+typedef struct gs_function_head_s {
+ gs_function_type_t type;
+ fn_evaluate_proc_t evaluate;
+ fn_is_monotonic_proc_t is_monotonic;
+ fn_free_params_proc_t free_params;
+ fn_free_proc_t free;
+} gs_function_head_t;
+struct gs_function_s {
+ gs_function_head_t head;
+ gs_function_params_t params;
+};
+
+#define FunctionType(pfn) ((pfn)->head.type)
+
+/*
+ * Each specific function type has a definition in its own header file
+ * for its parameter record. In order to keep names from overflowing
+ * various compilers' limits, we take the name of the function type and
+ * reduce it to the first and last letter of each word, e.g., for
+ * Sampled functions, XxYy is Sd.
+
+typedef struct gs_function_XxYy_params_s {
+ gs_function_params_common;
+ << P additional members >>
+} gs_function_XxYy_params_t;
+#define private_st_function_XxYy()\
+ gs_private_st_suffix_addP(st_function_XxYy, gs_function_XxYy_t,\
+ "gs_function_XxYy_t", function_XxYy_enum_ptrs, function_XxYy_reloc_ptrs,\
+ st_function, <<params.additional_members>>)
+
+ */
+
+/* ---------------- Procedures ---------------- */
+
+/*
+ * Each specific function type has a pair of procedures in its own
+ * header file, one to allocate and initialize an instance of that type,
+ * and one to free the parameters of that type.
+
+int gs_function_XxYy_init(P3(gs_function_t **ppfn,
+ const gs_function_XxYy_params_t *params,
+ gs_memory_t *mem));
+
+void gs_function_XxYy_free_params(P2(gs_function_XxYy_params_t *params,
+ gs_memory_t *mem));
+
+ */
+
+/* Evaluate a function. */
+#define gs_function_evaluate(pfn, in, out)\
+ (*(pfn)->head.evaluate)(pfn, in, out)
+
+/*
+ * Test whether a function is monotonic on a given (closed) interval. If
+ * must_know is true, returns 0 for false, 1 for true, gs_error_rangecheck
+ * if any part of the interval is outside the function's domain; if
+ * must_know is false, may also return gs_error_undefined to mean "can't
+ * determine quickly". If lower[i] > upper[i], the result is not defined.
+ */
+#define gs_function_is_monotonic(pfn, lower, upper, must_know)\
+ (*(pfn)->head.is_monotonic)(pfn, lower, upper, must_know)
+
+/* Free function parameters. */
+#define gs_function_free_params(pfn, mem)\
+ (*(pfn)->head.free_params)(&(pfn)->params, mem)
+
+/* Free a function's implementation, optionally including its parameters. */
+#define gs_function_free(pfn, free_params, mem)\
+ (*(pfn)->head.free)(pfn, free_params, mem)
+
+#endif /* gsfunc_INCLUDED */
diff --git a/pstoraster/gsfunc0.c b/pstoraster/gsfunc0.c
new file mode 100644
index 000000000..645426606
--- /dev/null
+++ b/pstoraster/gsfunc0.c
@@ -0,0 +1,347 @@
+/* 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$ */
+/* Implementation of FunctionType 0 (Sampled) Functions */
+#include "math_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsfunc0.h"
+#include "gxfarith.h"
+#include "gxfunc.h"
+
+typedef struct gs_function_Sd_s {
+ gs_function_head_t head;
+ gs_function_Sd_params_t params;
+} gs_function_Sd_t;
+
+private_st_function_Sd();
+
+/* Define the maximum plausible number of inputs and outputs */
+/* for a Sampled function. */
+#define max_Sd_m 16
+#define max_Sd_n 16
+
+/* Get one set of sample values. */
+#define SETUP_SAMPLES(bps, nbytes)\
+ int n = pfn->params.n;\
+ byte buf[max_Sd_n * ((bps + 7) >> 3)];\
+ const byte *p;\
+ int i;\
+\
+ data_source_access(&pfn->params.DataSource, offset >> 3,\
+ nbytes, buf, &p)
+
+private int
+fn_gets_1(const gs_function_Sd_t * pfn, ulong offset, uint * samples)
+{
+ SETUP_SAMPLES(1, ((offset & 7) + n + 7) >> 3);
+ for (i = 0; i < n; ++i) {
+ samples[i] = (*p >> (~offset & 7)) & 1;
+ if (!(++offset & 7))
+ p++;
+ }
+ return 0;
+}
+private int
+fn_gets_2(const gs_function_Sd_t * pfn, ulong offset, uint * samples)
+{
+ SETUP_SAMPLES(2, (((offset & 7) >> 1) + n + 3) >> 2);
+ for (i = 0; i < n; ++i) {
+ samples[i] = (*p >> (6 - (offset & 7))) & 3;
+ if (!((offset += 2) & 7))
+ p++;
+ }
+ return 0;
+}
+private int
+fn_gets_4(const gs_function_Sd_t * pfn, ulong offset, uint * samples)
+{
+ SETUP_SAMPLES(4, (((offset & 7) >> 2) + n + 1) >> 1);
+ for (i = 0; i < n; ++i) {
+ samples[i] = (offset & 4 ? *p++ & 0xf : *p >> 4);
+ }
+ return 0;
+}
+private int
+fn_gets_8(const gs_function_Sd_t * pfn, ulong offset, uint * samples)
+{
+ SETUP_SAMPLES(8, n);
+ for (i = 0; i < n; ++i) {
+ samples[i] = *p++;
+ }
+ return 0;
+}
+private int
+fn_gets_12(const gs_function_Sd_t * pfn, ulong offset, uint * samples)
+{
+ SETUP_SAMPLES(12, (((offset & 7) >> 2) + 3 * n + 1) >> 1);
+ for (i = 0; i < n; ++i) {
+ if (offset & 4)
+ samples[i] = ((*p & 0xf) << 8) + p[1], p += 2;
+ else
+ samples[i] = (*p << 4) + (p[1] >> 4), p++;
+ offset ^= 4;
+ }
+ return 0;
+}
+private int
+fn_gets_16(const gs_function_Sd_t * pfn, ulong offset, uint * samples)
+{
+ SETUP_SAMPLES(16, n * 2);
+ for (i = 0; i < n; ++i) {
+ samples[i] = (*p << 8) + p[1];
+ p += 2;
+ }
+ return 0;
+}
+private int
+fn_gets_24(const gs_function_Sd_t * pfn, ulong offset, uint * samples)
+{
+ SETUP_SAMPLES(24, n * 3);
+ for (i = 0; i < n; ++i) {
+ samples[i] = (*p << 16) + (p[1] << 8) + p[2];
+ p += 3;
+ }
+ return 0;
+}
+private int
+fn_gets_32(const gs_function_Sd_t * pfn, ulong offset, uint * samples)
+{
+ SETUP_SAMPLES(32, n * 4);
+ for (i = 0; i < n; ++i) {
+ samples[i] = (*p << 24) + (p[1] << 16) + (p[2] << 8) + p[3];
+ p += 4;
+ }
+ return 0;
+}
+
+private int (*const fn_get_samples[]) (P3(const gs_function_Sd_t * pfn,
+ ulong offset, uint * samples)) =
+{
+ 0, fn_gets_1, fn_gets_2, 0, fn_gets_4, 0, 0, 0,
+ fn_gets_8, 0, 0, 0, fn_gets_12, 0, 0, 0,
+ fn_gets_16, 0, 0, 0, 0, 0, 0, 0,
+ fn_gets_24, 0, 0, 0, 0, 0, 0, 0,
+ fn_gets_32
+};
+
+/* Calculate a result by multilinear interpolation. */
+private void
+fn_interpolate_linear(const gs_function_Sd_t *pfn, const float *fparts,
+ const ulong *factors, float *samples, ulong offset, int m)
+{
+ int j;
+
+top:
+ if (m == 0) {
+ uint sdata[max_Sd_n];
+
+ (*fn_get_samples[pfn->params.BitsPerSample])(pfn, offset, sdata);
+ for (j = pfn->params.n - 1; j >= 0; --j)
+ samples[j] = sdata[j];
+ } else {
+ float fpart = *fparts++;
+ float samples1[max_Sd_n];
+
+ if (is_fzero(fpart)) {
+ ++factors;
+ --m;
+ goto top;
+ }
+ fn_interpolate_linear(pfn, fparts, factors + 1, samples,
+ offset, m - 1);
+ fn_interpolate_linear(pfn, fparts, factors + 1, samples1,
+ offset + *factors, m - 1);
+ for (j = pfn->params.n - 1; j >= 0; --j)
+ samples[j] += (samples1[j] - samples[j]) * fpart;
+ }
+}
+
+/* Evaluate a Sampled function. */
+private int
+fn_Sd_evaluate(const gs_function_t * pfn_common, const float *in, float *out)
+{
+ const gs_function_Sd_t *pfn = (const gs_function_Sd_t *)pfn_common;
+ int bps = pfn->params.BitsPerSample;
+ ulong offset = 0;
+ int i;
+ float encoded[max_Sd_m];
+ ulong factors[max_Sd_m];
+ float samples[max_Sd_n];
+
+ /* Encode the input values. */
+
+ for (i = 0; i < pfn->params.m; ++i) {
+ float d0 = pfn->params.Domain[2 * i],
+ d1 = pfn->params.Domain[2 * i + 1];
+ float arg = in[i], enc;
+
+ if (arg < d0)
+ arg = d0;
+ else if (arg > d1)
+ arg = d1;
+ if (pfn->params.Encode) {
+ float e0 = pfn->params.Encode[2 * i];
+ float e1 = pfn->params.Encode[2 * i + 1];
+
+ enc = (arg - d0) * (e1 - e0) / (d1 - d0) + e0;
+ if (enc < 0)
+ encoded[i] = 0;
+ else if (enc >= pfn->params.Size[i] - 1)
+ encoded[i] = pfn->params.Size[i] - 1;
+ else
+ encoded[i] = enc;
+ } else {
+ /* arg is guaranteed to be in bounds, ergo so is enc */
+ encoded[i] = (arg - d0) * (pfn->params.Size[i] - 1) / (d1 - d0);
+ }
+ }
+
+ /* Look up and interpolate the output values. */
+
+ {
+ ulong factor = bps * pfn->params.n;
+
+ for (i = 0; i < pfn->params.m; factor *= pfn->params.Size[i++]) {
+ int ipart = (int)encoded[i];
+
+ offset += (factors[i] = factor) * ipart;
+ encoded[i] -= ipart;
+ }
+ }
+ /****** LINEAR INTERPOLATION ONLY ******/
+ fn_interpolate_linear(pfn, encoded, factors, samples, offset,
+ pfn->params.m);
+
+ /* Encode the output values. */
+
+ for (i = 0; i < pfn->params.n; offset += bps, ++i) {
+ float d0, d1, r0, r1, value;
+
+ if (pfn->params.Range)
+ r0 = pfn->params.Range[2 * i], r1 = pfn->params.Range[2 * i + 1];
+ else
+ r0 = 0, r1 = (1 << bps) - 1;
+ if (pfn->params.Decode)
+ d0 = pfn->params.Decode[2 * i], d1 = pfn->params.Decode[2 * i + 1];
+ else
+ d0 = r0, d1 = r1;
+
+ value = samples[i] * (d1 - d0) / ((1 << bps) - 1) + d0;
+ if (value < r0)
+ out[i] = r0;
+ else if (value > r1)
+ out[i] = r1;
+ else
+ out[i] = value;
+ }
+
+ return 0;
+}
+
+/* Test whether a Sampled function is monotonic. */
+/* Since this can be very time-consuming, we only do it if necessary. */
+private int
+fn_Sd_is_monotonic(const gs_function_t * pfn_common,
+ const float *lower, const float *upper, bool must_know)
+{
+ if (!must_know)
+ return gs_error_undefined; /* don't know */
+/****** NYI ******/
+ return gs_error_undefined;
+}
+
+/* Free the parameters of a Sampled function. */
+void
+gs_function_Sd_free_params(gs_function_Sd_params_t * params, gs_memory_t * mem)
+{
+ gs_free_object(mem, (void *)params->Size, "Size"); /* break const */
+ gs_free_object(mem, (void *)params->Decode, "Decode"); /* break const */
+ gs_free_object(mem, (void *)params->Encode, "Encode"); /* break const */
+ fn_common_free_params((gs_function_params_t *) params, mem);
+}
+
+/* Allocate and initialize a Sampled function. */
+int
+gs_function_Sd_init(gs_function_t ** ppfn,
+ const gs_function_Sd_params_t * params, gs_memory_t * mem)
+{
+ static const gs_function_head_t function_Sd_head =
+ {
+ function_type_Sampled,
+ (fn_evaluate_proc_t) fn_Sd_evaluate,
+ (fn_is_monotonic_proc_t) fn_Sd_is_monotonic,
+ (fn_free_params_proc_t) gs_function_Sd_free_params,
+ fn_common_free
+ };
+ int code;
+ int i;
+
+ *ppfn = 0; /* in case of error */
+ code = fn_check_mnDR((const gs_function_params_t *)params,
+ params->m, params->n);
+ if (code < 0)
+ return code;
+ if (params->m > max_Sd_m)
+ return_error(gs_error_limitcheck);
+ switch (params->Order) {
+ case 0: /* use default */
+ case 1:
+ case 3:
+ break;
+ default:
+ return_error(gs_error_rangecheck);
+ }
+ switch (params->BitsPerSample) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ case 12:
+ case 16:
+ case 24:
+ case 32:
+ break;
+ default:
+ return_error(gs_error_rangecheck);
+ }
+ for (i = 0; i < params->m; ++i)
+ if (params->Size[i] <= 0)
+ return_error(gs_error_rangecheck);
+ {
+ gs_function_Sd_t *pfn =
+ gs_alloc_struct(mem, gs_function_Sd_t, &st_function_Sd,
+ "gs_function_Sd_init");
+
+ if (pfn == 0)
+ return_error(gs_error_VMerror);
+ pfn->params = *params;
+ if (params->Order == 0)
+ pfn->params.Order = 1; /* default */
+ pfn->head = function_Sd_head;
+ *ppfn = (gs_function_t *) pfn;
+ }
+ return 0;
+}
diff --git a/pstoraster/gsfunc0.h b/pstoraster/gsfunc0.h
new file mode 100644
index 000000000..b423e0fa2
--- /dev/null
+++ b/pstoraster/gsfunc0.h
@@ -0,0 +1,66 @@
+/* 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$ */
+/* Definitions for FunctionType 0 (Sampled) Functions */
+
+#ifndef gsfunc0_INCLUDED
+# define gsfunc0_INCLUDED
+
+#include "gsfunc.h"
+#include "gsdsrc.h"
+
+/* ---------------- Types and structures ---------------- */
+
+/* Define the Function type. */
+#define function_type_Sampled 0
+
+/* Define Sampled functions. */
+typedef struct gs_function_Sd_params_s {
+ gs_function_params_common;
+ int Order; /* 1 or 3, optional */
+ gs_data_source_t DataSource;
+ int BitsPerSample; /* 1, 2, 4, 8, 12, 16, 24, 32 */
+ const float *Encode; /* 2 x m, optional */
+ const float *Decode; /* 2 x n, optional */
+ const int *Size; /* m */
+} gs_function_Sd_params_t;
+
+#define private_st_function_Sd() /* in gsfunc.c */\
+ gs_private_st_suffix_add3(st_function_Sd, gs_function_Sd_t,\
+ "gs_function_Sd_t", function_Sd_enum_ptrs, function_Sd_reloc_ptrs,\
+ st_function, params.Encode, params.Decode, params.Size)
+
+/* ---------------- Procedures ---------------- */
+
+/* Allocate and initialize a Sampled function. */
+int gs_function_Sd_init(P3(gs_function_t ** ppfn,
+ const gs_function_Sd_params_t * params,
+ gs_memory_t * mem));
+
+/* Free the parameters of a Sampled function. */
+void gs_function_Sd_free_params(P2(gs_function_Sd_params_t * params,
+ gs_memory_t * mem));
+
+#endif /* gsfunc0_INCLUDED */
diff --git a/pstoraster/gsfunc3.c b/pstoraster/gsfunc3.c
new file mode 100644
index 000000000..6e7e1d978
--- /dev/null
+++ b/pstoraster/gsfunc3.c
@@ -0,0 +1,361 @@
+/* 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$ */
+/* Implementation of LL3 Functions */
+#include "math_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsfunc3.h"
+#include "gxfunc.h"
+
+/* ---------------- Exponential Interpolation functions ---------------- */
+
+typedef struct gs_function_ElIn_s {
+ gs_function_head_t head;
+ gs_function_ElIn_params_t params;
+} gs_function_ElIn_t;
+
+private_st_function_ElIn();
+
+/* Evaluate an Exponential Interpolation function. */
+private int
+fn_ElIn_evaluate(const gs_function_t * pfn_common, const float *in, float *out)
+{
+ const gs_function_ElIn_t *const pfn =
+ (const gs_function_ElIn_t *)pfn_common;
+ double arg = in[0], raised;
+ int i;
+
+ if (arg < pfn->params.Domain[0])
+ arg = pfn->params.Domain[0];
+ else if (arg > pfn->params.Domain[1])
+ arg = pfn->params.Domain[1];
+ raised = pow(arg, pfn->params.N);
+ for (i = 0; i < pfn->params.n; ++i) {
+ float v0 = (pfn->params.C0 == 0 ? 0.0 : pfn->params.C0[i]);
+ float v1 = (pfn->params.C1 == 0 ? 1.0 : pfn->params.C1[i]);
+ double value = v0 + raised * (v1 - v0);
+
+ if (pfn->params.Range) {
+ float r0 = pfn->params.Range[2 * i],
+ r1 = pfn->params.Range[2 * i + 1];
+
+ if (value < r0)
+ value = r0;
+ else if (value > r1)
+ value = r1;
+ }
+ out[i] = value;
+ }
+ return 0;
+}
+
+/* Test whether an Exponential function is monotonic. (They always are.) */
+private int
+fn_ElIn_is_monotonic(const gs_function_t * pfn_common,
+ const float *lower, const float *upper, bool must_know)
+{
+ const gs_function_ElIn_t *const pfn =
+ (const gs_function_ElIn_t *)pfn_common;
+
+ if (lower[0] > pfn->params.Domain[1] ||
+ upper[0] < pfn->params.Domain[0]
+ )
+ return_error(gs_error_rangecheck);
+ return 1;
+}
+
+/* Free the parameters of an Exponential Interpolation function. */
+void
+gs_function_ElIn_free_params(gs_function_ElIn_params_t * params,
+ gs_memory_t * mem)
+{
+ gs_free_object(mem, (void *)params->C1, "C1"); /* break const */
+ gs_free_object(mem, (void *)params->C0, "C0"); /* break const */
+ fn_common_free_params((gs_function_params_t *) params, mem);
+}
+
+/* Allocate and initialize an Exponential Interpolation function. */
+int
+gs_function_ElIn_init(gs_function_t ** ppfn,
+ const gs_function_ElIn_params_t * params,
+ gs_memory_t * mem)
+{
+ static const gs_function_head_t function_ElIn_head =
+ {
+ function_type_ExponentialInterpolation,
+ (fn_evaluate_proc_t) fn_ElIn_evaluate,
+ (fn_is_monotonic_proc_t) fn_ElIn_is_monotonic,
+ (fn_free_params_proc_t) gs_function_ElIn_free_params,
+ fn_common_free
+ };
+ int code;
+
+ *ppfn = 0; /* in case of error */
+ code = fn_check_mnDR((const gs_function_params_t *)params, 1, params->n);
+ if (code < 0)
+ return code;
+ if ((params->C0 == 0 || params->C1 == 0) && params->n != 1)
+ return_error(gs_error_rangecheck);
+ if (params->N != floor(params->N)) {
+ /* Non-integral exponent, all inputs must be non-negative. */
+ if (params->Domain[0] < 0)
+ return_error(gs_error_rangecheck);
+ }
+ if (params->N < 0) {
+ /* Negative exponent, input must not be zero. */
+ if (params->Domain[0] <= 0 && params->Domain[1] >= 0)
+ return_error(gs_error_rangecheck);
+ } {
+ gs_function_ElIn_t *pfn =
+ gs_alloc_struct(mem, gs_function_ElIn_t, &st_function_ElIn,
+ "gs_function_ElIn_init");
+
+ if (pfn == 0)
+ return_error(gs_error_VMerror);
+ pfn->params = *params;
+ pfn->params.m = 1;
+ pfn->head = function_ElIn_head;
+ *ppfn = (gs_function_t *) pfn;
+ }
+ return 0;
+}
+
+/* ---------------- 1-Input Stitching functions ---------------- */
+
+typedef struct gs_function_1ItSg_s {
+ gs_function_head_t head;
+ gs_function_1ItSg_params_t params;
+} gs_function_1ItSg_t;
+
+private_st_function_1ItSg();
+
+/* Evaluate a 1-Input Stitching function. */
+private int
+fn_1ItSg_evaluate(const gs_function_t * pfn_common, const float *in, float *out)
+{
+ const gs_function_1ItSg_t *const pfn =
+ (const gs_function_1ItSg_t *)pfn_common;
+ float arg = in[0], b0, b1, e0, encoded;
+ int k = pfn->params.k;
+ int i;
+
+ if (arg < pfn->params.Domain[0]) {
+ arg = pfn->params.Domain[0];
+ i = 0;
+ } else if (arg > pfn->params.Domain[1]) {
+ arg = pfn->params.Domain[1];
+ i = k - 1;
+ } else {
+ for (i = 0; i < k - 1; ++i)
+ if (arg <= pfn->params.Bounds[i])
+ break;
+ }
+ b0 = (i == 0 ? pfn->params.Domain[0] : pfn->params.Bounds[i - 1]);
+ b1 = (i == k - 1 ? pfn->params.Domain[1] : pfn->params.Bounds[i]);
+ e0 = pfn->params.Encode[2 * i];
+ encoded =
+ (arg - b0) * (pfn->params.Encode[2 * i + 1] - e0) / (b1 - b0) + e0;
+ return gs_function_evaluate(pfn->params.Functions[i], &encoded, out);
+}
+
+/* Test whether a 1-Input Stitching function is monotonic. */
+private int
+fn_1ItSg_is_monotonic(const gs_function_t * pfn_common,
+ const float *lower, const float *upper, bool must_know)
+{
+ const gs_function_1ItSg_t *const pfn =
+ (const gs_function_1ItSg_t *)pfn_common;
+
+ if (lower[0] > pfn->params.Domain[1] ||
+ upper[0] < pfn->params.Domain[0]
+ )
+ return_error(gs_error_rangecheck);
+/****** NYI ******/
+ return gs_error_undefined;
+}
+
+/* Free the parameters of a 1-Input Stitching function. */
+void
+gs_function_1ItSg_free_params(gs_function_1ItSg_params_t * params,
+ gs_memory_t * mem)
+{
+ gs_free_object(mem, (void *)params->Encode, "Encode"); /* break const */
+ gs_free_object(mem, (void *)params->Bounds, "Bounds"); /* break const */
+ fn_free_functions((gs_function_t **) params->Functions, /* break const */
+ params->k, mem);
+ fn_common_free_params((gs_function_params_t *) params, mem);
+}
+
+/* Allocate and initialize a 1-Input Stitching function. */
+int
+gs_function_1ItSg_init(gs_function_t ** ppfn,
+ const gs_function_1ItSg_params_t * params, gs_memory_t * mem)
+{
+ static const gs_function_head_t function_1ItSg_head =
+ {
+ function_type_1InputStitching,
+ (fn_evaluate_proc_t) fn_1ItSg_evaluate,
+ (fn_is_monotonic_proc_t) fn_1ItSg_is_monotonic,
+ (fn_free_params_proc_t) gs_function_1ItSg_free_params,
+ fn_common_free
+ };
+ int n = (params->Range == 0 ? 0 : params->n);
+ float prev = params->Domain[0];
+ int i;
+
+ *ppfn = 0; /* in case of error */
+ for (i = 0; i < params->k; ++i) {
+ const gs_function_t *psubfn = params->Functions[i];
+
+ if (psubfn->params.m != 1)
+ return_error(gs_error_rangecheck);
+ if (n == 0)
+ n = psubfn->params.n;
+ else if (psubfn->params.n != n)
+ return_error(gs_error_rangecheck);
+ /* There are only k - 1 Bounds, not k. */
+ if (i < params->k - 1) {
+ if (params->Bounds[i] <= prev)
+ return_error(gs_error_rangecheck);
+ prev = params->Bounds[i];
+ }
+ }
+ if (params->Domain[1] < prev)
+ return_error(gs_error_rangecheck);
+ fn_check_mnDR((const gs_function_params_t *)params, 1, n);
+ {
+ gs_function_1ItSg_t *pfn =
+ gs_alloc_struct(mem, gs_function_1ItSg_t, &st_function_1ItSg,
+ "gs_function_1ItSg_init");
+
+ if (pfn == 0)
+ return_error(gs_error_VMerror);
+ pfn->params = *params;
+ pfn->params.m = 1;
+ pfn->params.n = n;
+ pfn->head = function_1ItSg_head;
+ *ppfn = (gs_function_t *) pfn;
+ }
+ return 0;
+}
+
+/* ---------------- Arrayed Output functions ---------------- */
+
+typedef struct gs_function_AdOt_s {
+ gs_function_head_t head;
+ gs_function_AdOt_params_t params;
+} gs_function_AdOt_t;
+
+private_st_function_AdOt();
+
+/* Evaluate an Arrayed Output function. */
+private int
+fn_AdOt_evaluate(const gs_function_t * pfn_common, const float *in, float *out)
+{
+ const gs_function_AdOt_t *const pfn =
+ (const gs_function_AdOt_t *)pfn_common;
+ int i;
+
+ for (i = 0; i < pfn->params.n; ++i) {
+ int code =
+ gs_function_evaluate(pfn->params.Functions[i], in, out + i);
+
+ if (code < 0)
+ return code;
+ }
+ return 0;
+}
+
+/* Test whether an Arrayed Output function is monotonic. */
+private int
+fn_AdOt_is_monotonic(const gs_function_t * pfn_common,
+ const float *lower, const float *upper, bool must_know)
+{
+ const gs_function_AdOt_t *const pfn =
+ (const gs_function_AdOt_t *)pfn_common;
+ int i;
+
+ for (i = 0; i < pfn->params.n; ++i) {
+ int code =
+ gs_function_is_monotonic(pfn->params.Functions[i], lower, upper,
+ must_know);
+
+ if (code <= 0)
+ return code;
+ }
+ return 1;
+}
+
+/* Free the parameters of an Arrayed Output function. */
+void
+gs_function_AdOt_free_params(gs_function_AdOt_params_t * params,
+ gs_memory_t * mem)
+{
+ fn_free_functions((gs_function_t **) params->Functions, /* break const */
+ params->n, mem);
+ fn_common_free_params((gs_function_params_t *) params, mem);
+}
+
+/* Allocate and initialize an Arrayed Output function. */
+int
+gs_function_AdOt_init(gs_function_t ** ppfn,
+ const gs_function_AdOt_params_t * params, gs_memory_t * mem)
+{
+ static const gs_function_head_t function_AdOt_head =
+ {
+ function_type_ArrayedOutput,
+ (fn_evaluate_proc_t) fn_AdOt_evaluate,
+ (fn_is_monotonic_proc_t) fn_AdOt_is_monotonic,
+ (fn_free_params_proc_t) gs_function_AdOt_free_params,
+ fn_common_free
+ };
+ int m = params->m, n = params->n;
+ int i;
+
+ *ppfn = 0; /* in case of error */
+ if (m <= 0 || n <= 0)
+ return_error(gs_error_rangecheck);
+ for (i = 0; i < n; ++i) {
+ const gs_function_t *psubfn = params->Functions[i];
+
+ if (psubfn->params.m != m || psubfn->params.n != 1)
+ return_error(gs_error_rangecheck);
+ }
+ {
+ gs_function_AdOt_t *pfn =
+ gs_alloc_struct(mem, gs_function_AdOt_t, &st_function_AdOt,
+ "gs_function_AdOt_init");
+
+ if (pfn == 0)
+ return_error(gs_error_VMerror);
+ pfn->params = *params;
+ pfn->params.Domain = 0;
+ pfn->params.Range = 0;
+ pfn->head = function_AdOt_head;
+ *ppfn = (gs_function_t *) pfn;
+ }
+ return 0;
+}
diff --git a/pstoraster/gsfunc3.h b/pstoraster/gsfunc3.h
new file mode 100644
index 000000000..1a35a6564
--- /dev/null
+++ b/pstoraster/gsfunc3.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$ */
+/* Definitions for LL3 Functions */
+
+#ifndef gsfunc3_INCLUDED
+# define gsfunc3_INCLUDED
+
+#include "gsfunc.h"
+#include "gsdsrc.h"
+
+/* ---------------- Types and structures ---------------- */
+
+/*
+ * Define the Function types.
+ * See gsfunc.h for why gs_function_type_t can't be an enum type.
+ */
+enum {
+ function_type_ExponentialInterpolation = 2,
+ function_type_1InputStitching = 3,
+ /* For internal use only */
+ function_type_ArrayedOutput = -1
+};
+
+/* Define Exponential Interpolation functions. */
+typedef struct gs_function_ElIn_params_s {
+ gs_function_params_common;
+ const float *C0; /* n, optional */
+ const float *C1; /* n, optional */
+ float N;
+} gs_function_ElIn_params_t;
+
+#define private_st_function_ElIn() /* in gsfunc.c */\
+ gs_private_st_suffix_add2(st_function_ElIn, gs_function_ElIn_t,\
+ "gs_function_ElIn_t", function_ElIn_enum_ptrs, function_ElIn_reloc_ptrs,\
+ st_function, params.C0, params.C1)
+
+/* Define 1-Input Stitching functions. */
+typedef struct gs_function_1ItSg_params_s {
+ gs_function_params_common;
+ int k;
+ const gs_function_t *const *Functions; /* k */
+ const float *Bounds; /* k - 1 */
+ const float *Encode; /* 2 x k */
+} gs_function_1ItSg_params_t;
+
+#define private_st_function_1ItSg() /* in gsfunc.c */\
+ gs_private_st_suffix_add3(st_function_1ItSg, gs_function_1ItSg_t,\
+ "gs_function_1ItSg_t", function_1ItSg_enum_ptrs, function_1ItSg_reloc_ptrs,\
+ st_function, params.Functions, params.Bounds, params.Encode)
+
+/*
+ * Define Arrayed Output functions. These consist of n m x 1 functions
+ * whose outputs are assembled into the output of the arrayed function.
+ * We use them to handle certain PostScript constructs that can accept
+ * either a single n-output function or n 1-output functions.
+ *
+ * Note that for this type, and only this type, both Domain and Range
+ * are ignored (0).
+ */
+typedef struct gs_function_AdOt_params_s {
+ gs_function_params_common;
+ const gs_function_t *const *Functions; /* n */
+} gs_function_AdOt_params_t;
+
+#define private_st_function_AdOt() /* in gsfunc.c */\
+ gs_private_st_suffix_add1(st_function_AdOt, gs_function_AdOt_t,\
+ "gs_function_AdOt_t", function_AdOt_enum_ptrs, function_AdOt_reloc_ptrs,\
+ st_function, params.Functions)
+
+/* ---------------- Procedures ---------------- */
+
+/* Allocate and initialize functions of specific types. */
+int gs_function_ElIn_init(P3(gs_function_t ** ppfn,
+ const gs_function_ElIn_params_t * params,
+ gs_memory_t * mem));
+int gs_function_1ItSg_init(P3(gs_function_t ** ppfn,
+ const gs_function_1ItSg_params_t * params,
+ gs_memory_t * mem));
+int gs_function_AdOt_init(P3(gs_function_t ** ppfn,
+ const gs_function_AdOt_params_t * params,
+ gs_memory_t * mem));
+
+/* Free parameters of specific types. */
+void gs_function_ElIn_free_params(P2(gs_function_ElIn_params_t * params,
+ gs_memory_t * mem));
+void gs_function_1ItSg_free_params(P2(gs_function_1ItSg_params_t * params,
+ gs_memory_t * mem));
+void gs_function_AdOt_free_params(P2(gs_function_AdOt_params_t * params,
+ gs_memory_t * mem));
+
+#endif /* gsfunc3_INCLUDED */
diff --git a/pstoraster/gsgc.h b/pstoraster/gsgc.h
new file mode 100644
index 000000000..56dc1482b
--- /dev/null
+++ b/pstoraster/gsgc.h
@@ -0,0 +1,91 @@
+/* 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$ */
+/* Library-level interface to garbage collector */
+
+/*
+ * This API is not strictly at the library level, since it references
+ * gs_ref_memory_t and the 4 PostScript memory spaces; however, the former
+ * concept already leaks into the library's standard allocator, and the
+ * latter is relatively small and harmless.
+ */
+
+#ifndef gsgc_INCLUDED
+# define gsgc_INCLUDED
+
+/*
+ * Define the VM space numbers, in increasing order of dynamism. Pointers
+ * from a higher-numbered space to the same or a lower-numbered space are
+ * always allowed, but not vice versa. Foreign space (the most static) is
+ * internal, the rest are visible to the programmer; the index of foreign
+ * space must be 0, so that we don't have to set any space bits in scalar
+ * refs (PostScript objects).
+ */
+typedef enum {
+ i_vm_foreign = 0, /* must be 0 */
+ i_vm_system,
+ i_vm_global,
+ i_vm_local,
+ i_vm_max = i_vm_local
+} i_vm_space;
+
+/* Define an array of allocators indexed by space. */
+#ifndef gs_ref_memory_DEFINED
+# define gs_ref_memory_DEFINED
+typedef struct gs_ref_memory_s gs_ref_memory_t;
+
+#endif
+/*
+ * r_space_bits is only defined in PostScript interpreters, but if it is
+ * defined, we want to make sure it's 2.
+ */
+#ifdef r_space_bits
+# if r_space_bits != 2
+Error_r_space_bits_is_not_2;
+# endif
+#endif
+typedef union vm_spaces_s {
+ gs_ref_memory_t *indexed[4 /*1 << r_space_bits */ ];
+ struct _ssn {
+ gs_ref_memory_t *foreign;
+ gs_ref_memory_t *system;
+ gs_ref_memory_t *global;
+ gs_ref_memory_t *local;
+ } named;
+} vm_spaces;
+
+/* By convention, the vm_spaces member of structures, and local variables */
+/* of type vm_spaces, are named spaces. */
+#define space_foreign spaces.named.foreign
+#define space_system spaces.named.system
+#define space_global spaces.named.global
+#define space_local spaces.named.local
+
+/*
+ * Define the top-level entry to the garbage collector.
+ */
+void gs_reclaim(P2(vm_spaces * pspaces, bool global));
+
+#endif /* gsgc_INCLUDED */
diff --git a/pstoraster/gshsb.c b/pstoraster/gshsb.c
new file mode 100644
index 000000000..6bd5479de
--- /dev/null
+++ b/pstoraster/gshsb.c
@@ -0,0 +1,171 @@
+/* Copyright (C) 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$ */
+/* HSB color operators for Ghostscript library */
+#include "gx.h"
+#include "gscolor.h"
+#include "gshsb.h" /* interface definition */
+#include "gxfrac.h"
+
+/* Forward references */
+private void color_hsb_to_rgb(P4(floatp h, floatp s, floatp b, float rgb[3]));
+private void color_rgb_to_hsb(P4(floatp r, floatp g, floatp b, float hsb[3]));
+
+/* Force a parameter into the range [0.0..1.0]. */
+#define force_unit(p) (p < 0.0 ? 0.0 : p > 1.0 ? 1.0 : p)
+
+/* sethsbcolor */
+int
+gs_sethsbcolor(gs_state * pgs, floatp h, floatp s, floatp b)
+{
+ float rgb[3];
+
+ color_hsb_to_rgb(force_unit(h), force_unit(s), force_unit(b), rgb);
+ return gs_setrgbcolor(pgs, rgb[0], rgb[1], rgb[2]);
+}
+
+/* currenthsbcolor */
+int
+gs_currenthsbcolor(const gs_state * pgs, float pr3[3])
+{
+ float rgb[3];
+
+ gs_currentrgbcolor(pgs, rgb);
+ color_rgb_to_hsb(rgb[0], rgb[1], rgb[2], pr3);
+ return 0;
+}
+
+/* ------ Internal routines ------ */
+
+/* Note: the color model conversion algorithms are taken from */
+/* Rogers, Procedural Elements for Computer Graphics, pp. 401-403. */
+
+/* Convert RGB to HSB. */
+private void
+color_rgb_to_hsb(floatp r, floatp g, floatp b, float hsb[3])
+{
+ frac red = float2frac(r), green = float2frac(g), blue = float2frac(b);
+
+#define rhue hsb[0]
+#define rsat hsb[1]
+#define rbri hsb[2]
+ if (red == green && green == blue) {
+ rhue = 0; /* arbitrary */
+ rsat = 0;
+ rbri = r; /* pick any one */
+ } else { /* Convert rgb to hsb */
+ frac V, Temp, diff;
+ long H;
+
+ V = (red > green ? red : green);
+ if (blue > V)
+ V = blue;
+ Temp = (red > green ? green : red);
+ if (blue < Temp)
+ Temp = blue;
+ diff = V - Temp;
+ if (V == red)
+ H = (green - blue) * frac_1_long / diff;
+ else if (V == green)
+ H = (blue - red) * frac_1_long / diff + 2 * frac_1_long;
+ else /* V == blue */
+ H = (red - green) * frac_1_long / diff + 4 * frac_1_long;
+ if (H < 0)
+ H += 6 * frac_1_long;
+ rhue = H / (frac_1 * 6.0);
+ rsat = diff / (float)V;
+ rbri = frac2float(V);
+ }
+#undef rhue
+#undef rsat
+#undef rbri
+}
+
+/* Convert HSB to RGB. */
+private void
+color_hsb_to_rgb(floatp hue, floatp saturation, floatp brightness, float rgb[3])
+{
+ if (saturation == 0) {
+ rgb[0] = rgb[1] = rgb[2] = brightness;
+ } else { /* Convert hsb to rgb. */
+ /* We rely on the fact that the product of two */
+ /* fracs fits into an unsigned long. */
+ floatp h6 = hue * 6;
+ ulong V = float2frac(brightness); /* force arithmetic to long */
+ frac S = float2frac(saturation);
+ int I = (int)h6;
+ ulong F = float2frac(h6 - I); /* ditto */
+
+ /* M = V*(1-S), N = V*(1-S*F), K = V*(1-S*(1-F)) = M-N+V */
+ frac M = V * (frac_1_long - S) / frac_1_long;
+ frac N = V * (frac_1_long - S * F / frac_1_long) / frac_1_long;
+ frac K = M - N + V;
+ frac R, G, B;
+
+ switch (I) {
+ default:
+ R = V;
+ G = K;
+ B = M;
+ break;
+ case 1:
+ R = N;
+ G = V;
+ B = M;
+ break;
+ case 2:
+ R = M;
+ G = V;
+ B = K;
+ break;
+ case 3:
+ R = M;
+ G = N;
+ B = V;
+ break;
+ case 4:
+ R = K;
+ G = M;
+ B = V;
+ break;
+ case 5:
+ R = V;
+ G = M;
+ B = N;
+ break;
+ }
+ rgb[0] = frac2float(R);
+ rgb[1] = frac2float(G);
+ rgb[2] = frac2float(B);
+#ifdef DEBUG
+ if (gs_debug_c('c')) {
+ dlprintf7("[c]hsb(%g,%g,%g)->VSFI(%ld,%d,%ld,%d)->\n",
+ hue, saturation, brightness, V, S, F, I);
+ dlprintf6(" RGB(%d,%d,%d)->rgb(%g,%g,%g)\n",
+ R, G, B, rgb[0], rgb[1], rgb[2]);
+ }
+#endif
+ }
+}
diff --git a/pstoraster/gshsb.h b/pstoraster/gshsb.h
new file mode 100644
index 000000000..c218711a6
--- /dev/null
+++ b/pstoraster/gshsb.h
@@ -0,0 +1,33 @@
+/* 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$ */
+/* Client interface to HSB color routines */
+
+#ifndef gshsb_INCLUDED
+# define gshsb_INCLUDED
+
+int gs_sethsbcolor(P4(gs_state *, floatp, floatp, floatp)), gs_currenthsbcolor(P2(const gs_state *, float[3]));
+
+#endif /* gshsb_INCLUDED */
diff --git a/pstoraster/gsht.c b/pstoraster/gsht.c
new file mode 100644
index 000000000..426dfe463
--- /dev/null
+++ b/pstoraster/gsht.c
@@ -0,0 +1,651 @@
+/* Copyright (C) 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$ */
+/* setscreen operator for Ghostscript library */
+#include "memory_.h"
+#include <stdlib.h> /* for qsort */
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gsutil.h" /* for gs_next_ids */
+#include "gxarith.h" /* for igcd */
+#include "gzstate.h"
+#include "gxdevice.h" /* for gzht.h */
+#include "gzht.h"
+
+/* Forward declarations */
+void gx_set_effective_transfer(P1(gs_state *));
+
+/* Structure types */
+public_st_ht_order();
+private_st_ht_order_component();
+public_st_ht_order_comp_element();
+public_st_halftone();
+public_st_device_halftone();
+
+/* GC procedures */
+
+#define hptr ((gs_halftone *)vptr)
+
+private
+ENUM_PTRS_BEGIN(halftone_enum_ptrs) return 0;
+
+case 0:
+switch (hptr->type)
+{
+ case ht_type_spot:
+ENUM_RETURN((hptr->params.spot.transfer == 0 ?
+ hptr->params.spot.transfer_closure.data :
+ 0));
+ case ht_type_threshold:
+ENUM_RETURN_CONST_STRING_PTR(gs_halftone, params.threshold.thresholds);
+ case ht_type_client_order:
+ENUM_RETURN(hptr->params.client_order.client_data);
+ case ht_type_multiple:
+ case ht_type_multiple_colorscreen:
+ENUM_RETURN(hptr->params.multiple.components);
+ case ht_type_none:
+ case ht_type_screen:
+ case ht_type_colorscreen:
+return 0;
+}
+case 1:
+switch (hptr->type) {
+ case ht_type_threshold:
+ ENUM_RETURN((hptr->params.threshold.transfer == 0 ?
+ hptr->params.threshold.transfer_closure.data :
+ 0));
+ case ht_type_client_order:
+ ENUM_RETURN(hptr->params.threshold.transfer_closure.data);
+ default:
+ return 0;
+}
+ENUM_PTRS_END
+
+private RELOC_PTRS_BEGIN(halftone_reloc_ptrs)
+{
+ switch (hptr->type) {
+ case ht_type_spot:
+ if (hptr->params.spot.transfer == 0)
+ RELOC_PTR(gs_halftone, params.spot.transfer_closure.data);
+ break;
+ case ht_type_threshold:
+ RELOC_CONST_STRING_PTR(gs_halftone, params.threshold.thresholds);
+ if (hptr->params.threshold.transfer == 0)
+ RELOC_PTR(gs_halftone, params.threshold.transfer_closure.data);
+ break;
+ case ht_type_client_order:
+ RELOC_PTR(gs_halftone, params.client_order.client_data);
+ RELOC_PTR(gs_halftone, params.client_order.transfer_closure.data);
+ break;
+ case ht_type_multiple:
+ case ht_type_multiple_colorscreen:
+ RELOC_PTR(gs_halftone, params.multiple.components);
+ break;
+ case ht_type_none:
+ case ht_type_screen:
+ case ht_type_colorscreen:
+ break;
+ }
+}
+RELOC_PTRS_END
+
+#undef hptr
+
+/* setscreen */
+int
+gs_setscreen(gs_state * pgs, gs_screen_halftone * phsp)
+{
+ gs_screen_enum senum;
+ int code = gx_ht_process_screen(&senum, pgs, phsp,
+ gs_currentaccuratescreens());
+
+ if (code < 0)
+ return code;
+ return gs_screen_install(&senum);
+}
+
+/* currentscreen */
+int
+gs_currentscreen(const gs_state * pgs, gs_screen_halftone * phsp)
+{
+ switch (pgs->halftone->type) {
+ case ht_type_screen:
+ *phsp = pgs->halftone->params.screen;
+ return 0;
+ case ht_type_colorscreen:
+ *phsp = pgs->halftone->params.colorscreen.screens.colored.gray;
+ return 0;
+ default:
+ return_error(gs_error_undefined);
+ }
+}
+
+/* .currentscreenlevels */
+int
+gs_currentscreenlevels(const gs_state * pgs)
+{
+ return pgs->dev_ht->order.num_levels;
+}
+
+/* .setscreenphase */
+int
+gx_imager_setscreenphase(gs_imager_state * pis, int x, int y,
+ gs_color_select_t select)
+{
+ if (select == gs_color_select_all) {
+ int i;
+
+ for (i = 0; i < gs_color_select_count; ++i)
+ gx_imager_setscreenphase(pis, x, y, (gs_color_select_t) i);
+ return 0;
+ } else if (select < 0 || select >= gs_color_select_count)
+ return_error(gs_error_rangecheck);
+ pis->screen_phase[select].x = x;
+ pis->screen_phase[select].y = y;
+ return 0;
+}
+int
+gs_setscreenphase(gs_state * pgs, int x, int y, gs_color_select_t select)
+{
+ int code = gx_imager_setscreenphase((gs_imager_state *) pgs, x, y,
+ select);
+
+ /*
+ * If we're only setting the source phase, we don't need to do
+ * unset_dev_color, because the source phase doesn't affect painting
+ * with the current color.
+ */
+ if (code >= 0 && (select == gs_color_select_texture ||
+ select == gs_color_select_all)
+ )
+ gx_unset_dev_color(pgs);
+ return code;
+}
+
+/* .currentscreenphase */
+int
+gs_currentscreenphase(const gs_state * pgs, gs_int_point * pphase,
+ gs_color_select_t select)
+{
+ if (select < 0 || select >= gs_color_select_count)
+ return_error(gs_error_rangecheck);
+ *pphase = pgs->screen_phase[select];
+ return 0;
+}
+
+/* currenthalftone */
+int
+gs_currenthalftone(gs_state * pgs, gs_halftone * pht)
+{
+ *pht = *pgs->halftone;
+ return 0;
+}
+
+/* ------ Internal routines ------ */
+
+/* Process one screen plane. */
+int
+gx_ht_process_screen_memory(gs_screen_enum * penum, gs_state * pgs,
+ gs_screen_halftone * phsp, bool accurate, gs_memory_t * mem)
+{
+ gs_point pt;
+ int code = gs_screen_init_memory(penum, pgs, phsp, accurate, mem);
+
+ if (code < 0)
+ return code;
+ while ((code = gs_screen_currentpoint(penum, &pt)) == 0)
+ if ((code = gs_screen_next(penum, (*phsp->spot_function) (pt.x, pt.y))) < 0)
+ return code;
+ return 0;
+}
+
+/* Internal procedure to allocate and initialize either an internally */
+/* generated or a client-defined halftone order. */
+private int
+gx_ht_alloc_ht_order(gx_ht_order * porder, uint width, uint height,
+ uint num_levels, uint num_bits, uint strip_shift, gs_memory_t * mem)
+{
+ gx_compute_cell_values(&porder->params);
+ porder->width = width;
+ porder->height = height;
+ porder->raster = bitmap_raster(width);
+ porder->shift = strip_shift;
+ porder->orig_height = porder->height;
+ porder->orig_shift = porder->shift;
+ porder->full_height = ht_order_full_height(porder);
+ porder->num_levels = num_levels;
+ porder->num_bits = num_bits;
+ porder->levels =
+ (uint *) gs_alloc_byte_array(mem, num_levels, sizeof(uint),
+ "ht order(levels)");
+ porder->bits =
+ (gx_ht_bit *) gs_alloc_byte_array(mem, num_bits, sizeof(gx_ht_bit),
+ "ht order(bits)");
+ if (porder->levels == 0 || porder->bits == 0) {
+ gs_free_object(mem, porder->bits, "ht order(bits)");
+ gs_free_object(mem, porder->levels, "ht order(levels)");
+ return_error(gs_error_VMerror);
+ }
+ porder->cache = 0;
+ porder->transfer = 0;
+ return 0;
+}
+
+/* Allocate and initialize the contents of a halftone order. */
+/* The client must have set the defining values in porder->params. */
+int
+gx_ht_alloc_order(gx_ht_order * porder, uint width, uint height,
+ uint strip_shift, uint num_levels, gs_memory_t * mem)
+{
+ gx_ht_order order;
+ int code;
+
+ order = *porder;
+ gx_compute_cell_values(&order.params);
+ code = gx_ht_alloc_ht_order(&order, width, height, num_levels,
+ width * height, strip_shift, mem);
+ if (code < 0)
+ return code;
+ *porder = order;
+ return 0;
+}
+
+/* Allocate and initialize the contents of a client-defined halftone order. */
+int
+gx_ht_alloc_client_order(gx_ht_order * porder, uint width, uint height,
+ uint num_levels, uint num_bits, gs_memory_t * mem)
+{
+ gx_ht_order order;
+ int code;
+
+ order = *porder;
+ order.params.M = width, order.params.N = 0;
+ order.params.R = 1;
+ order.params.M1 = height, order.params.N1 = 0;
+ order.params.R1 = 1;
+ gx_compute_cell_values(&order.params);
+ code = gx_ht_alloc_ht_order(&order, width, height, num_levels,
+ num_bits, 0, mem);
+ if (code < 0)
+ return code;
+ *porder = order;
+ return 0;
+}
+
+/* Compare keys ("masks", actually sample values) for qsort. */
+private int
+compare_samples(const void *p1, const void *p2)
+{
+ ht_sample_t m1 = ((const gx_ht_bit *)p1)->mask;
+ ht_sample_t m2 = ((const gx_ht_bit *)p2)->mask;
+
+ return (m1 < m2 ? -1 : m1 > m2 ? 1 : 0);
+}
+/* Sort the halftone order by sample value. */
+void
+gx_sort_ht_order(gx_ht_bit * recs, uint N)
+{
+ int i;
+
+ /* Tag each sample with its index, for sorting. */
+ for (i = 0; i < N; i++)
+ recs[i].offset = i;
+ qsort((void *)recs, N, sizeof(*recs), compare_samples);
+#ifdef DEBUG
+ if (gs_debug_c('H')) {
+ uint i;
+
+ dlputs("[H]Sorted samples:\n");
+ for (i = 0; i < N; i++)
+ dlprintf3("%5u: %5u: %u\n",
+ i, recs[i].offset, recs[i].mask);
+ }
+#endif
+}
+
+/*
+ * Construct the halftone order from a sampled spot function. Only width x
+ * strip samples have been filled in; we must replicate the resulting sorted
+ * order vertically, shifting it by shift each time. See gxdht.h regarding
+ * the invariants that must be restored.
+ */
+void
+gx_ht_construct_spot_order(gx_ht_order * porder)
+{
+ uint width = porder->width;
+ uint num_levels = porder->num_levels; /* = width x strip */
+ uint strip = num_levels / width;
+ gx_ht_bit *bits = porder->bits;
+ uint *levels = porder->levels;
+ uint shift = porder->orig_shift;
+ uint full_height = porder->full_height;
+ uint num_bits = porder->num_bits;
+ uint copies = num_bits / (width * strip);
+ gx_ht_bit *bp = bits + num_bits - 1;
+ uint i;
+
+ gx_sort_ht_order(bits, num_levels);
+ if_debug5('h',
+ "[h]spot order: num_levels=%u w=%u h=%u strip=%u shift=%u\n",
+ num_levels, width, porder->orig_height, strip, shift);
+ /* Fill in the levels array, replicating the bits vertically */
+ /* if needed. */
+ for (i = num_levels; i > 0;) {
+ uint offset = bits[--i].offset;
+ uint x = offset % width;
+ uint hy = offset - x;
+ uint k;
+
+ levels[i] = i * copies;
+ for (k = 0; k < copies;
+ k++, bp--, hy += num_levels, x = (x + width - shift) % width
+ )
+ bp->offset = hy + x;
+ }
+ /* If we have a complete halftone, restore the invariant. */
+ if (num_bits == width * full_height) {
+ porder->height = full_height;
+ porder->shift = 0;
+ }
+ gx_ht_construct_bits(porder);
+}
+
+/* Construct a single offset/mask. */
+void
+gx_ht_construct_bit(gx_ht_bit * bit, int width, int bit_num)
+{
+ uint padding = bitmap_raster(width) * 8 - width;
+ int pix = bit_num;
+ ht_mask_t mask;
+ byte *pb;
+
+ pix += pix / width * padding;
+ bit->offset = (pix >> 3) & -size_of(mask);
+ mask = (ht_mask_t) 1 << (~pix & (ht_mask_bits - 1));
+ /* Replicate the mask bits. */
+ pix = ht_mask_bits - width;
+ while ((pix -= width) >= 0)
+ mask |= mask >> width;
+ /* Store the mask, reversing bytes if necessary. */
+ bit->mask = 0;
+ for (pb = (byte *) & bit->mask + (sizeof(mask) - 1);
+ mask != 0;
+ mask >>= 8, pb--
+ )
+ *pb = (byte) mask;
+}
+
+/* Construct offset/masks from the whitening order. */
+/* porder->bits[i].offset contains the index of the bit position */
+/* that is i'th in the whitening order. */
+void
+gx_ht_construct_bits(gx_ht_order * porder)
+{
+ uint i;
+ gx_ht_bit *phb;
+
+ for (i = 0, phb = porder->bits; i < porder->num_bits; i++, phb++)
+ gx_ht_construct_bit(phb, porder->width, phb->offset);
+#ifdef DEBUG
+ if (gs_debug_c('H')) {
+ dlprintf1("[H]Halftone order bits 0x%lx:\n", (ulong) porder->bits);
+ for (i = 0, phb = porder->bits; i < porder->num_bits; i++, phb++)
+ dlprintf3("%4d: %u:0x%lx\n", i, phb->offset,
+ (ulong) phb->mask);
+ }
+#endif
+}
+
+/* Release a gx_device_halftone by freeing its components. */
+/* (Don't free the gx_device_halftone itself.) */
+void
+gx_ht_order_release(gx_ht_order * porder, gs_memory_t * mem, bool free_cache)
+{
+ if (free_cache && porder->cache)
+ gx_ht_free_cache(mem, porder->cache);
+ gs_free_object(mem, porder->transfer, "gx_ht_order_release(transfer)");
+ gs_free_object(mem, porder->bits, "gx_ht_order_release(bits)");
+ gs_free_object(mem, porder->levels, "gx_ht_order_release(levels)");
+}
+void
+gx_device_halftone_release(gx_device_halftone * pdht, gs_memory_t * mem)
+{
+ if (pdht->components) {
+ int i;
+
+ /* One of the components might be the same as the default */
+ /* order, so check that we don't free it twice. */
+ for (i = 0; i < pdht->num_comp; ++i)
+ if (pdht->components[i].corder.bits !=
+ pdht->order.bits
+ ) { /* Currently, all orders except the default one */
+ /* own their caches. */
+ gx_ht_order_release(&pdht->components[i].corder, mem, true);
+ }
+ gs_free_object(mem, pdht->components,
+ "gx_dev_ht_release(components)");
+ pdht->components = 0;
+ pdht->num_comp = 0;
+ }
+ gx_ht_order_release(&pdht->order, mem, false);
+}
+
+/* Install a device halftone in an imager state. */
+/* Note that this does not read or update the client halftone. */
+int
+gx_imager_dev_ht_install(gs_imager_state * pis,
+ const gx_device_halftone * pdht, gs_halftone_type type, const gx_device * dev)
+{
+ gx_device_halftone *pgdht = pis->dev_ht;
+
+ if ((ulong) pdht->order.raster * (pdht->order.num_bits /
+ pdht->order.width) > pis->ht_cache->bits_size
+ )
+ return_error(gs_error_limitcheck);
+ if (pgdht != 0 && pgdht->rc.ref_count == 1 &&
+ pgdht->rc.memory == pdht->rc.memory
+ ) { /* The current device halftone isn't shared. */
+ /* Just release its components. */
+ gx_device_halftone_release(pgdht, pgdht->rc.memory);
+ } else { /* The device halftone is shared or not yet allocated. */
+ rc_unshare_struct(pis->dev_ht, gx_device_halftone,
+ &st_device_halftone, pdht->rc.memory,
+ return_error(gs_error_VMerror),
+ "gx_imager_dev_ht_install");
+ pgdht = pis->dev_ht;
+ }
+ {
+ rc_header rc;
+
+ rc = pgdht->rc;
+ *pgdht = *pdht;
+ pgdht->rc = rc;
+ }
+ pgdht->id = gs_next_ids(1);
+ pgdht->type = type;
+ /* Clear the cache, to avoid confusion in case the address of */
+ /* a new order vector matches that of a (deallocated) old one. */
+ gx_ht_clear_cache(pis->ht_cache);
+ /* Set the color_indices according to the device color_info. */
+ /* Also compute the LCM of the primary color cell sizes. */
+ /* Note that for strip halftones, the "cell size" is the */
+ /* theoretical fully expanded size with shift = 0. */
+ if (pdht->components != 0) {
+ static const gs_ht_separation_name dcnames[5][4] =
+ {
+ {gs_ht_separation_Default}, /* not used */
+ {gs_ht_separation_Default, gs_ht_separation_Default,
+ gs_ht_separation_Default, gs_ht_separation_Gray
+ },
+ {gs_ht_separation_Default}, /* not used */
+ {gs_ht_separation_Red, gs_ht_separation_Green,
+ gs_ht_separation_Blue, gs_ht_separation_Default
+ },
+ {gs_ht_separation_Cyan, gs_ht_separation_Magenta,
+ gs_ht_separation_Yellow, gs_ht_separation_Black
+ }
+ };
+ static const gs_ht_separation_name cscnames[4] =
+ {gs_ht_separation_Red, gs_ht_separation_Green,
+ gs_ht_separation_Blue, gs_ht_separation_Default
+ };
+ int num_comps = dev->color_info.num_components;
+ const gs_ht_separation_name *cnames = dcnames[num_comps];
+ int lcm_width = 1, lcm_height = 1;
+ uint i;
+
+ /* Halftones set by setcolorscreen, and (we think) */
+ /* Type 2 and Type 4 halftones, are supposed to work */
+ /* for both RGB and CMYK, so we need a special check here. */
+ if (num_comps == 4 &&
+ (type == ht_type_colorscreen ||
+ type == ht_type_multiple_colorscreen)
+ )
+ cnames = cscnames;
+ if_debug4('h', "[h]dcnames=%lu,%lu,%lu,%lu\n",
+ (ulong) cnames[0], (ulong) cnames[1],
+ (ulong) cnames[2], (ulong) cnames[3]);
+ memset(pgdht->color_indices, 0, sizeof(pdht->color_indices));
+ for (i = 0; i < pdht->num_comp; i++) {
+ const gx_ht_order_component *pcomp =
+ &pdht->components[i];
+ int j;
+
+ if_debug2('h', "[h]cname[%d]=%lu\n",
+ i, (ulong) pcomp->cname);
+ for (j = 0; j < 4; j++) {
+ if (pcomp->cname == cnames[j]) {
+ if_debug2('h', "[h]color_indices[%d]=%d\n",
+ j, i);
+ pgdht->color_indices[j] = i;
+ }
+ }
+ }
+ /* Now do a second pass to compute the LCM. */
+ /* We have to do it this way in case some entry in */
+ /* color_indices is still 0. */
+ for (i = 0; i < 4; ++i) {
+ const gx_ht_order_component *pcomp =
+ &pdht->components[pgdht->color_indices[i]];
+ uint cw = pcomp->corder.width;
+ uint ch = pcomp->corder.full_height;
+ int dw = lcm_width / igcd(lcm_width, cw);
+ int dh = lcm_height / igcd(lcm_height, ch);
+
+ lcm_width = (cw > max_int / dw ? max_int : cw * dw);
+ lcm_height = (ch > max_int / dh ? max_int : ch * dh);
+ }
+ pgdht->lcm_width = lcm_width;
+ pgdht->lcm_height = lcm_height;
+ } else { /* Only one component. */
+ pgdht->lcm_width = pgdht->order.width;
+ pgdht->lcm_height = pgdht->order.full_height;
+ }
+ if_debug2('h', "[h]LCM=(%d,%d)\n",
+ pgdht->lcm_width, pgdht->lcm_height);
+ gx_imager_set_effective_xfer(pis);
+ return 0;
+}
+
+/*
+ * Install a new halftone in the graphics state. Note that we copy the top
+ * level of the gs_halftone and the gx_device_halftone, and take ownership
+ * of any substructures.
+ */
+int
+gx_ht_install(gs_state * pgs, const gs_halftone * pht,
+ const gx_device_halftone * pdht)
+{
+ gs_memory_t *mem = pht->rc.memory;
+ gs_halftone *old_ht = pgs->halftone;
+ gs_halftone *new_ht;
+ int code;
+
+ if (old_ht != 0 && old_ht->rc.memory == mem &&
+ old_ht->rc.ref_count == 1
+ )
+ new_ht = old_ht;
+ else
+ rc_alloc_struct_1(new_ht, gs_halftone, &st_halftone,
+ mem, return_error(gs_error_VMerror),
+ "gx_ht_install(new halftone)");
+ code = gx_imager_dev_ht_install((gs_imager_state *) pgs,
+ pdht, pht->type, gs_currentdevice_inline(pgs));
+ if (code < 0) {
+ if (new_ht != old_ht)
+ gs_free_object(mem, new_ht, "gx_ht_install(new halftone)");
+ return code;
+ }
+ if (new_ht != old_ht)
+ rc_decrement(old_ht, "gx_ht_install(old halftone)");
+ {
+ rc_header rc;
+
+ rc = new_ht->rc;
+ *new_ht = *pht;
+ new_ht->rc = rc;
+ }
+ pgs->halftone = new_ht;
+ gx_unset_dev_color(pgs);
+ return 0;
+}
+
+/* Reestablish the effective transfer functions, taking into account */
+/* any overrides from halftone dictionaries. */
+void
+gx_imager_set_effective_xfer(gs_imager_state * pis)
+{
+ const gx_device_halftone *pdht = pis->dev_ht;
+
+ pis->effective_transfer = pis->set_transfer; /* default */
+ if (pdht == 0)
+ return; /* not initialized yet */
+ if (pdht->components == 0) { /* Check for transfer function override in single halftone */
+ gx_transfer_map *pmap = pdht->order.transfer;
+
+ if (pmap != 0)
+ pis->effective_transfer.indexed[0] =
+ pis->effective_transfer.indexed[1] =
+ pis->effective_transfer.indexed[2] =
+ pis->effective_transfer.indexed[3] = pmap;
+ } else { /* Check in all 4 standard separations */
+ int i;
+
+ for (i = 0; i < 4; ++i) {
+ gx_transfer_map *pmap =
+ pdht->components[pdht->color_indices[i]].corder.
+ transfer;
+
+ if (pmap != 0)
+ pis->effective_transfer.indexed[i] = pmap;
+ }
+ }
+}
+void
+gx_set_effective_transfer(gs_state * pgs)
+{
+ gx_imager_set_effective_xfer((gs_imager_state *) pgs);
+}
diff --git a/pstoraster/gsht.h b/pstoraster/gsht.h
new file mode 100644
index 000000000..fd1682d19
--- /dev/null
+++ b/pstoraster/gsht.h
@@ -0,0 +1,78 @@
+/* Copyright (C) 1993, 1994, 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$ */
+/* Public interface to halftone functionality */
+
+#ifndef gsht_INCLUDED
+# define gsht_INCLUDED
+
+/* Client definition of (Type 1) halftones */
+typedef struct gs_screen_halftone_s {
+ float frequency;
+ float angle;
+ float (*spot_function) (P2(floatp, floatp));
+ /* setscreen or sethalftone sets these: */
+ /* (a Level 2 feature, but we include them in Level 1) */
+ float actual_frequency;
+ float actual_angle;
+} gs_screen_halftone;
+
+#define st_screen_halftone_max_ptrs 0
+
+/* Client definition of color (Type 2) halftones */
+typedef struct gs_colorscreen_halftone_s {
+ union _css {
+ gs_screen_halftone indexed[4];
+ struct _csc {
+ gs_screen_halftone red, green, blue, gray;
+ } colored;
+ } screens;
+} gs_colorscreen_halftone;
+
+#define st_colorscreen_halftone_max_ptrs 0
+
+/* Procedural interface */
+int gs_setscreen(P2(gs_state *, gs_screen_halftone *));
+int gs_currentscreen(P2(const gs_state *, gs_screen_halftone *));
+int gs_currentscreenlevels(P1(const gs_state *));
+
+/*
+ * Enumeration-style definition of a single screen. The client must:
+ * - probably, call gs_screen_enum_alloc;
+ * - call gs_screen_init;
+ * - in a loop,
+ * - call gs_screen_currentpoint; if it returns 1, exit;
+ * - call gs_screen_next;
+ * - if desired, call gs_screen_install to install the screen.
+ */
+typedef struct gs_screen_enum_s gs_screen_enum;
+gs_screen_enum *gs_screen_enum_alloc(P2(gs_memory_t *, client_name_t));
+int gs_screen_init(P3(gs_screen_enum *, gs_state *,
+ gs_screen_halftone *));
+int gs_screen_currentpoint(P2(gs_screen_enum *, gs_point *));
+int gs_screen_next(P2(gs_screen_enum *, floatp));
+int gs_screen_install(P1(gs_screen_enum *));
+
+#endif /* gsht_INCLUDED */
diff --git a/pstoraster/gsht1.c b/pstoraster/gsht1.c
new file mode 100644
index 000000000..f79afa730
--- /dev/null
+++ b/pstoraster/gsht1.c
@@ -0,0 +1,449 @@
+/* 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$ */
+/* Extended halftone operators for Ghostscript library */
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gsutil.h" /* for gs_next_ids */
+#include "gzstate.h"
+#include "gxdevice.h" /* for gzht.h */
+#include "gzht.h"
+
+/* Define the size of the halftone tile cache. */
+#define max_tile_bytes_LARGE 4096
+#define max_tile_bytes_SMALL 512
+#if arch_small_memory
+# define max_tile_cache_bytes max_tile_bytes_SMALL
+#else
+# define max_tile_cache_bytes\
+ (gs_debug_c('.') ? max_tile_bytes_SMALL : max_tile_bytes_LARGE)
+#endif
+
+/* Imports from gscolor.c */
+void load_transfer_map(P3(gs_state *, gx_transfer_map *, floatp));
+
+/* Forward declarations */
+private int process_spot(P4(gx_ht_order *, gs_state *,
+ gs_spot_halftone *, gs_memory_t *));
+private int process_threshold(P4(gx_ht_order *, gs_state *,
+ gs_threshold_halftone *, gs_memory_t *));
+private int process_client_order(P4(gx_ht_order *, gs_state *,
+ gs_client_order_halftone *, gs_memory_t *));
+
+/* Structure types */
+public_st_halftone_component();
+public_st_ht_component_element();
+
+/* GC procedures */
+
+#define hptr ((gs_halftone_component *)vptr)
+
+private
+ENUM_PTRS_BEGIN(halftone_component_enum_ptrs) return 0;
+
+case 0:
+switch (hptr->type)
+{
+ case ht_type_spot:
+ENUM_RETURN((hptr->params.spot.transfer == 0 ?
+ hptr->params.spot.transfer_closure.data :
+ 0));
+ case ht_type_threshold:
+ENUM_RETURN_CONST_STRING_PTR(gs_halftone_component,
+ params.threshold.thresholds);
+ case ht_type_client_order:
+ENUM_RETURN(hptr->params.client_order.client_data);
+ default: /* not possible */
+return 0;
+}
+case 1:
+switch (hptr->type) {
+ case ht_type_threshold:
+ ENUM_RETURN((hptr->params.threshold.transfer == 0 ?
+ hptr->params.threshold.transfer_closure.data :
+ 0));
+ case ht_type_client_order:
+ ENUM_RETURN(hptr->params.threshold.transfer_closure.data);
+ default:
+ return 0;
+}
+ENUM_PTRS_END
+
+private RELOC_PTRS_BEGIN(halftone_component_reloc_ptrs)
+{
+ switch (hptr->type) {
+ case ht_type_spot:
+ if (hptr->params.spot.transfer == 0)
+ RELOC_VAR(hptr->params.spot.transfer_closure.data);
+ break;
+ case ht_type_threshold:
+ RELOC_CONST_STRING_VAR(hptr->params.threshold.thresholds);
+ if (hptr->params.threshold.transfer == 0)
+ RELOC_VAR(hptr->params.threshold.transfer_closure.data);
+ break;
+ case ht_type_client_order:
+ RELOC_VAR(hptr->params.client_order.client_data);
+ RELOC_VAR(hptr->params.client_order.transfer_closure.data);
+ break;
+ default:
+ break;
+ }
+}
+RELOC_PTRS_END
+
+#undef hptr
+
+/* setcolorscreen */
+int
+gs_setcolorscreen(gs_state * pgs, gs_colorscreen_halftone * pht)
+{
+ gs_halftone ht;
+
+ ht.type = ht_type_colorscreen;
+ ht.params.colorscreen = *pht;
+ return gs_sethalftone(pgs, &ht);
+}
+
+/* currentcolorscreen */
+int
+gs_currentcolorscreen(gs_state * pgs, gs_colorscreen_halftone * pht)
+{
+ int code;
+
+ switch (pgs->halftone->type) {
+ case ht_type_colorscreen:
+ *pht = pgs->halftone->params.colorscreen;
+ return 0;
+ default:
+ code = gs_currentscreen(pgs, &pht->screens.colored.gray);
+ if (code < 0)
+ return code;
+ pht->screens.colored.red = pht->screens.colored.gray;
+ pht->screens.colored.green = pht->screens.colored.gray;
+ pht->screens.colored.blue = pht->screens.colored.gray;
+ return 0;
+ }
+}
+
+/* Set the halftone in the graphics state. */
+int
+gs_sethalftone(gs_state * pgs, gs_halftone * pht)
+{
+ gs_halftone ht;
+
+ ht = *pht;
+ ht.rc.memory = pgs->memory;
+ return gs_sethalftone_allocated(pgs, &ht);
+}
+int
+gs_sethalftone_allocated(gs_state * pgs, gs_halftone * pht)
+{
+ gx_device_halftone dev_ht;
+ int code = gs_sethalftone_prepare(pgs, pht, &dev_ht);
+
+ if (code < 0)
+ return code;
+ dev_ht.rc.memory = pht->rc.memory;
+ return gx_ht_install(pgs, pht, &dev_ht);
+}
+/* Prepare the halftone, but don't install it. */
+int
+gs_sethalftone_prepare(gs_state * pgs, gs_halftone * pht,
+ gx_device_halftone * pdht)
+{
+ gs_memory_t *mem = pht->rc.memory;
+ gx_ht_order_component *pocs = 0;
+ int code = 0;
+
+ switch (pht->type) {
+ case ht_type_colorscreen:
+ {
+ gs_screen_halftone *phc =
+ pht->params.colorscreen.screens.indexed;
+ static const gs_ht_separation_name cnames[4] =
+ {
+ gs_ht_separation_Default, gs_ht_separation_Red,
+ gs_ht_separation_Green, gs_ht_separation_Blue
+ };
+ static const int cindex[4] =
+ {3, 0, 1, 2};
+ int i;
+
+ pocs = gs_alloc_struct_array(mem, 4,
+ gx_ht_order_component,
+ &st_ht_order_component_element,
+ "gs_sethalftone");
+ if (pocs == 0)
+ return_error(gs_error_VMerror);
+ for (i = 0; i < 4; i++) {
+ gs_screen_enum senum;
+ int ci = cindex[i];
+ gx_ht_order_component *poc = &pocs[i];
+
+ code = gx_ht_process_screen_memory(&senum, pgs,
+ &phc[ci], gs_currentaccuratescreens(), mem);
+ if (code < 0)
+ break;
+#define sorder senum.order
+ poc->corder = sorder;
+ poc->cname = cnames[i];
+ if (i == 0) /* Gray = Default */
+ pdht->order = sorder;
+ else {
+ uint tile_bytes =
+ sorder.raster * (sorder.num_bits / sorder.width);
+ uint num_tiles =
+ max_tile_cache_bytes / tile_bytes + 1;
+ gx_ht_cache *pcache =
+ gx_ht_alloc_cache(mem, num_tiles,
+ tile_bytes * num_tiles);
+
+ if (pcache == 0) {
+ code = gs_note_error(gs_error_VMerror);
+ break;
+ }
+ poc->corder.cache = pcache;
+ gx_ht_init_cache(pcache, &poc->corder);
+ }
+#undef sorder
+ }
+ if (code < 0)
+ break;
+ pdht->components = pocs;
+ pdht->num_comp = 4;
+ }
+ break;
+ case ht_type_spot:
+ code = process_spot(&pdht->order, pgs, &pht->params.spot, mem);
+ if (code < 0)
+ return code;
+ pdht->components = 0;
+ break;
+ case ht_type_threshold:
+ code = process_threshold(&pdht->order, pgs,
+ &pht->params.threshold, mem);
+ if (code < 0)
+ return code;
+ pdht->components = 0;
+ break;
+ case ht_type_client_order:
+ code = process_client_order(&pdht->order, pgs,
+ &pht->params.client_order, mem);
+ if (code < 0)
+ return code;
+ pdht->components = 0;
+ break;
+ case ht_type_multiple:
+ case ht_type_multiple_colorscreen:
+ {
+ uint count = pht->params.multiple.num_comp;
+ bool have_Default = false;
+ uint i;
+ gs_halftone_component *phc = pht->params.multiple.components;
+ gx_ht_order_component *poc_next;
+
+ pocs = gs_alloc_struct_array(mem, count,
+ gx_ht_order_component,
+ &st_ht_order_component_element,
+ "gs_sethalftone");
+ if (pocs == 0)
+ return_error(gs_error_VMerror);
+ poc_next = pocs + 1;
+ for (i = 0; i < count; i++, phc++) {
+ gx_ht_order_component *poc;
+
+ if (phc->cname == gs_ht_separation_Default) {
+ if (have_Default) {
+ /* Duplicate Default */
+ code = gs_note_error(gs_error_rangecheck);
+ break;
+ }
+ poc = pocs;
+ have_Default = true;
+ } else if (i == count - 1 && !have_Default) {
+ /* No Default */
+ code = gs_note_error(gs_error_rangecheck);
+ break;
+ } else
+ poc = poc_next++;
+ poc->cname = phc->cname;
+ switch (phc->type) {
+ case ht_type_spot:
+ code = process_spot(&poc->corder, pgs,
+ &phc->params.spot, mem);
+ break;
+ case ht_type_threshold:
+ code = process_threshold(&poc->corder, pgs,
+ &phc->params.threshold, mem);
+ break;
+ case ht_type_client_order:
+ code = process_client_order(&poc->corder, pgs,
+ &phc->params.client_order, mem);
+ break;
+ default:
+ code = gs_note_error(gs_error_rangecheck);
+ break;
+ }
+ if (code < 0)
+ break;
+ if (poc != pocs) {
+ gx_ht_cache *pcache =
+ gx_ht_alloc_cache(mem, 1,
+ poc->corder.raster *
+ (poc->corder.num_bits /
+ poc->corder.width));
+
+ if (pcache == 0) {
+ code = gs_note_error(gs_error_VMerror);
+ break;
+ }
+ poc->corder.cache = pcache;
+ gx_ht_init_cache(pcache, &poc->corder);
+ }
+ }
+ if (code < 0)
+ break;
+ pdht->order = pocs[0].corder; /* Default */
+ if (count == 1) {
+ /* We have only a Default; */
+ /* we don't need components. */
+ gs_free_object(mem, pocs, "gs_sethalftone");
+ pdht->components = 0;
+ } else {
+ pdht->components = pocs;
+ pdht->num_comp = count;
+ }
+ }
+ break;
+ default:
+ return_error(gs_error_rangecheck);
+ }
+ if (code < 0)
+ gs_free_object(mem, pocs, "gs_sethalftone");
+ return code;
+}
+
+/* ------ Internal routines ------ */
+
+/* Process a transfer function override, if any. */
+private int
+process_transfer(gx_ht_order * porder, gs_state * pgs,
+ gs_mapping_proc proc, gs_mapping_closure_t * pmc,
+ gs_memory_t * mem)
+{
+ gx_transfer_map *pmap;
+
+ if (proc == 0 && pmc->proc == 0)
+ return 0;
+ pmap = gs_alloc_struct(mem, gx_transfer_map, &st_transfer_map,
+ "process_transfer");
+ if (pmap == 0)
+ return_error(gs_error_VMerror);
+ pmap->proc = proc; /* 0 => use closure */
+ pmap->closure = *pmc;
+ pmap->id = gs_next_ids(1);
+ load_transfer_map(pgs, pmap, 0.0);
+ porder->transfer = pmap;
+ return 0;
+}
+
+/* Process a spot plane. */
+private int
+process_spot(gx_ht_order * porder, gs_state * pgs,
+ gs_spot_halftone * phsp, gs_memory_t * mem)
+{
+ gs_screen_enum senum;
+
+ int code = gx_ht_process_screen_memory(&senum, pgs, &phsp->screen,
+ phsp->accurate_screens, mem);
+
+ if (code < 0)
+ return code;
+ *porder = senum.order;
+ return process_transfer(porder, pgs, phsp->transfer,
+ &phsp->transfer_closure, mem);
+}
+
+/* Process a threshold plane. */
+private int
+process_threshold(gx_ht_order * porder, gs_state * pgs,
+ gs_threshold_halftone * phtp, gs_memory_t * mem)
+{
+ int code;
+
+ porder->params.M = phtp->width, porder->params.N = 0;
+ porder->params.R = 1;
+ porder->params.M1 = phtp->height, porder->params.N1 = 0;
+ porder->params.R1 = 1;
+ code = gx_ht_alloc_order(porder, phtp->width, phtp->height,
+ 0, 256, mem);
+ if (code < 0)
+ return code;
+ gx_ht_construct_threshold_order(porder, phtp->thresholds.data);
+ return process_transfer(porder, pgs, phtp->transfer,
+ &phtp->transfer_closure, mem);
+}
+
+/* Construct the halftone order from a threshold array. */
+void
+gx_ht_construct_threshold_order(gx_ht_order * porder, const byte * thresholds)
+{
+ uint size = porder->num_bits;
+ uint *levels = porder->levels;
+ gx_ht_bit *bits = porder->bits;
+ uint i, j;
+
+ for (i = 0; i < size; i++)
+ bits[i].mask = max(1, thresholds[i]);
+ gx_sort_ht_order(bits, size);
+ /* We want to set levels[j] to the lowest value of i */
+ /* such that bits[i].mask > j. */
+ for (i = 0, j = 0; i < size; i++) {
+ if (bits[i].mask != j) {
+ if_debug3('h', "[h]levels[%u..%u] = %u\n",
+ j, (uint) bits[i].mask, i);
+ while (j < bits[i].mask)
+ levels[j++] = i;
+ }
+ }
+ while (j < 256)
+ levels[j++] = size;
+ gx_ht_construct_bits(porder);
+}
+
+/* Process a client-order plane. */
+private int
+process_client_order(gx_ht_order * porder, gs_state * pgs,
+ gs_client_order_halftone * phcop, gs_memory_t * mem)
+{
+ int code = (*phcop->procs->create_order) (porder, pgs, phcop, mem);
+
+ if (code < 0)
+ return code;
+ return process_transfer(porder, pgs, NULL,
+ &phcop->transfer_closure, mem);
+}
diff --git a/pstoraster/gsht1.h b/pstoraster/gsht1.h
new file mode 100644
index 000000000..05d220191
--- /dev/null
+++ b/pstoraster/gsht1.h
@@ -0,0 +1,60 @@
+/* Copyright (C) 1994, 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$ */
+/* Extended public interface to halftones */
+
+#ifndef gsht1_INCLUDED
+# define gsht1_INCLUDED
+
+#include "gsht.h"
+
+/* Procedural interface */
+int gs_setcolorscreen(P2(gs_state *, gs_colorscreen_halftone *));
+int gs_currentcolorscreen(P2(gs_state *, gs_colorscreen_halftone *));
+
+/*
+ * We include sethalftone here, even though it is a Level 2 feature,
+ * because it turns out to be convenient to define setcolorscreen
+ * using sethalftone.
+ */
+#ifndef gs_halftone_DEFINED
+# define gs_halftone_DEFINED
+typedef struct gs_halftone_s gs_halftone;
+
+#endif
+/*
+ * gs_halftone structures may have complex substructures. We provide two
+ * procedures for setting them. gs_halftone assumes that the gs_halftone
+ * structure and all its substructures was allocated with the same allocator
+ * as the gs_state; gs_halftone_allocated looks in the structure itself (the
+ * rc.memory member) to find the allocator that was used. Both procedures
+ * copy the top-level structure (using the appropriate allocator), but take
+ * ownership of the substructures.
+ */
+int gs_sethalftone(P2(gs_state *, gs_halftone *));
+int gs_sethalftone_allocated(P2(gs_state *, gs_halftone *));
+int gs_currenthalftone(P2(gs_state *, gs_halftone *));
+
+#endif /* gsht1_INCLUDED */
diff --git a/pstoraster/gshtscr.c b/pstoraster/gshtscr.c
new file mode 100644
index 000000000..dccb414d5
--- /dev/null
+++ b/pstoraster/gshtscr.c
@@ -0,0 +1,574 @@
+/* Copyright (C) 1993, 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$ */
+/* Screen (Type 1) halftone processing for Ghostscript library */
+#include "math_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gxarith.h"
+#include "gzstate.h"
+#include "gxdevice.h" /* for gzht.h */
+#include "gzht.h"
+
+/* Define whether to force all halftones to be strip halftones, */
+/* for debugging. */
+#define FORCE_STRIP_HALFTONES 0
+
+/* Structure descriptors */
+private_st_gs_screen_enum();
+
+/* GC procedures */
+#define eptr ((gs_screen_enum *)vptr)
+
+private
+ENUM_PTRS_BEGIN(screen_enum_enum_ptrs)
+{
+ if (index < 1 + st_ht_order_max_ptrs) {
+ gs_ptr_type_t ret =
+ ENUM_USING(st_ht_order, &eptr->order, sizeof(eptr->order),
+ index - 1);
+
+ if (ret == 0) /* don't stop early */
+ ENUM_RETURN(0);
+ return ret;
+ }
+ return ENUM_USING(st_halftone, &eptr->halftone, sizeof(eptr->halftone),
+ index - (1 + st_ht_order_max_ptrs));
+}
+ENUM_PTR(0, gs_screen_enum, pgs);
+ENUM_PTRS_END
+
+private RELOC_PTRS_BEGIN(screen_enum_reloc_ptrs)
+{
+ RELOC_PTR(gs_screen_enum, pgs);
+ RELOC_USING(st_halftone, &eptr->halftone, sizeof(gs_halftone));
+ RELOC_USING(st_ht_order, &eptr->order, sizeof(gx_ht_order));
+}
+RELOC_PTRS_END
+
+#undef eptr
+
+/* Define the default value of AccurateScreens that affects */
+/* setscreen and setcolorscreen. */
+private bool screen_accurate_screens;
+
+/* Default AccurateScreens control */
+void
+gs_setaccuratescreens(bool accurate)
+{
+ screen_accurate_screens = accurate;
+}
+bool
+gs_currentaccuratescreens(void)
+{
+ return screen_accurate_screens;
+}
+
+/* Define the MinScreenLevels user parameter similarly. */
+private uint screen_min_screen_levels;
+
+void
+gs_setminscreenlevels(uint levels)
+{
+ screen_min_screen_levels = levels;
+}
+uint
+gs_currentminscreenlevels(void)
+{
+ return screen_min_screen_levels;
+}
+
+/* Initialize the screen control statics at startup. */
+void
+gs_gshtscr_init(gs_memory_t *mem)
+{
+ gs_setaccuratescreens(false);
+ gs_setminscreenlevels(1);
+}
+
+/*
+ * The following implementation notes complement the general discussion of
+ * halftone tiles found in gxdht.h.
+ *
+ * Currently we allow R(') > 1 (i.e., multiple basic cells per multi-cell)
+ * only if AccurateScreens is true or if B (the number of pixels in a basic
+ * cell) < MinScreenLevels; if AccurateScreens is false and B >=
+ * MinScreenLevels, multi-cells and basic cells are the same.
+ *
+ * To find the smallest super-cell for a given multi-cell size, i.e., the
+ * smallest (absolute value) coordinates where the corners of multi-cells
+ * lie on the coordinate axes, we compute the values of i and j that give
+ * the minimum value of W by:
+ * D = gcd(abs(M'), abs(N)), i = M'/D, j = N/D, W = C / D,
+ * and similarly
+ * D' = gcd(abs(M), abs(N')), i' = N'/D', j' = M/D', W' = C / D'.
+ */
+
+/* Compute the derived values of a halftone tile. */
+void
+gx_compute_cell_values(gx_ht_cell_params_t * phcp)
+{
+ const int M = phcp->M, N = phcp->N, M1 = phcp->M1, N1 = phcp->N1;
+ const uint m = any_abs(M), n = any_abs(N);
+ const uint m1 = any_abs(M1), n1 = any_abs(N1);
+ const ulong C = phcp->C = (ulong) m * m1 + (ulong) n * n1;
+ const int D = igcd(m1, n);
+ const int D1 = igcd(m, n1);
+
+ phcp->D = D, phcp->D1 = D1;
+ phcp->W = C / D, phcp->W1 = C / D1;
+ /* Compute the shift value. */
+ /* If M1 or N is zero, the shift is zero. */
+ if (M1 && N) {
+ int h = 0, k = 0, dy = 0;
+ int shift;
+
+ /*
+ * There may be a faster way to do this: see Knuth vol. 2,
+ * section 4.5.2, Algorithm X (p. 302) and exercise 15
+ * (p. 315, solution p. 523).
+ */
+ while (dy != D)
+ if (dy > D) {
+ if (M1 > 0)
+ ++k;
+ else
+ --k;
+ dy -= m1;
+ } else {
+ if (N > 0)
+ ++h;
+ else
+ --h;
+ dy += n;
+ }
+ shift = h * M + k * N1;
+ /* We just computed what amounts to a right shift; */
+ /* what we want is a left shift. */
+ phcp->S = imod(-shift, phcp->W);
+ } else
+ phcp->S = 0;
+ if_debug12('h', "[h]MNR=(%d,%d)/%d, M'N'R'=(%d,%d)/%d => C=%lu, D=%d, D'=%d, W=%u, W'=%u, S=%d\n",
+ M, N, phcp->R, M1, N1, phcp->R1,
+ C, D, D1, phcp->W, phcp->W1, phcp->S);
+}
+
+/* Forward references */
+private int pick_cell_size(P6(gs_screen_halftone * ph,
+ const gs_matrix * pmat, ulong max_size, uint min_levels, bool accurate,
+ gx_ht_cell_params_t * phcp));
+
+/* Allocate a screen enumerator. */
+gs_screen_enum *
+gs_screen_enum_alloc(gs_memory_t * mem, client_name_t cname)
+{
+ return gs_alloc_struct(mem, gs_screen_enum, &st_gs_screen_enum, cname);
+}
+
+/* Set up for halftone sampling. */
+int
+gs_screen_init(gs_screen_enum * penum, gs_state * pgs,
+ gs_screen_halftone * phsp)
+{
+ return gs_screen_init_accurate(penum, pgs, phsp,
+ screen_accurate_screens);
+}
+int
+gs_screen_init_memory(gs_screen_enum * penum, gs_state * pgs,
+ gs_screen_halftone * phsp, bool accurate, gs_memory_t * mem)
+{
+ int code =
+ gs_screen_order_init_memory(&penum->order, pgs, phsp, accurate, mem);
+
+ if (code < 0)
+ return code;
+ return
+ gs_screen_enum_init_memory(penum, &penum->order, pgs, phsp, mem);
+}
+
+/* Allocate and initialize a spot screen. */
+/* This is the first half of gs_screen_init_accurate. */
+int
+gs_screen_order_init_memory(gx_ht_order * porder, const gs_state * pgs,
+ gs_screen_halftone * phsp, bool accurate, gs_memory_t * mem)
+{
+ gs_matrix imat;
+ ulong max_size = pgs->ht_cache->bits_size;
+ uint num_levels;
+ int code;
+
+ if (phsp->frequency < 0.1)
+ return_error(gs_error_rangecheck);
+ gs_deviceinitialmatrix(gs_currentdevice(pgs), &imat);
+ code = pick_cell_size(phsp, &imat, max_size,
+ screen_min_screen_levels, accurate,
+ &porder->params);
+ if (code < 0)
+ return code;
+ gx_compute_cell_values(&porder->params);
+ num_levels = porder->params.W * porder->params.D;
+#if !FORCE_STRIP_HALFTONES
+ if (((ulong)porder->params.W1 * bitmap_raster(porder->params.W) +
+ num_levels * sizeof(*porder->levels) +
+ porder->params.W * porder->params.W1 * sizeof(*porder->bits)) <=
+ max_size) {
+ /*
+ * Allocate an order for the entire tile, but only sample one
+ * strip. Note that this causes the order parameters to be
+ * self-inconsistent until gx_ht_construct_spot_order fixes them
+ * up: see gxdht.h for more information.
+ */
+ code = gx_ht_alloc_order(porder, porder->params.W,
+ porder->params.W1, 0,
+ num_levels, mem);
+ porder->height = porder->orig_height = porder->params.D;
+ porder->shift = porder->orig_shift = porder->params.S;
+ } else
+#endif
+ { /* Just allocate the order for a single strip. */
+ code = gx_ht_alloc_order(porder, porder->params.W,
+ porder->params.D, porder->params.S,
+ num_levels, mem);
+ }
+ if (code < 0)
+ return code;
+ return 0;
+}
+
+/*
+ * Given a desired frequency, angle, and minimum number of levels, a maximum
+ * cell size, and an AccurateScreens flag, pick values for M('), N('), and
+ * R('). We want to get a good fit to the requested frequency and angle,
+ * provide at least the requested minimum number of levels, and keep
+ * rendering as fast as possible; trading these criteria off against each
+ * other is what makes the code complicated.
+ *
+ * We compute trial values u and v from the original values of F and A.
+ * Normally these will not be integers. We then examine the 4 pairs of
+ * integers obtained by rounding each of u and v independently up or down,
+ * and pick the pair U, V that yields the closest match to the requested
+ * F and A values and doesn't require more than max_size storage for a
+ * single tile. If no pair
+ * yields an acceptably small W, we divide both u and v by 2 and try again.
+ * Then we run the equations backward to obtain the actual F and A.
+ * This is fairly easy given that we require either xx = yy = 0 or
+ * xy = yx = 0. In the former case, we have
+ * U = (72 / F * xx) * cos(A);
+ * V = (72 / F * yy) * sin(A);
+ * from which immediately
+ * A = arctan((V / yy) / (U / xx)),
+ * or equivalently
+ * A = arctan((V * xx) / (U * yy)).
+ * We can then obtain F as
+ * F = (72 * xx / U) * cos(A),
+ * or equivalently
+ * F = (72 * yy / V) * sin(A).
+ * For landscape devices, we replace xx by yx, yy by xy, and interchange
+ * sin and cos, resulting in
+ * A = arctan((U * xy) / (V * yx))
+ * and
+ * F = (72 * yx / U) * sin(A)
+ * or
+ * F = (72 * xy / V) * cos(A).
+ */
+/* ph->frequency and ph->angle are input parameters; */
+/* the routine sets ph->actual_frequency and ph->actual_angle. */
+private int
+pick_cell_size(gs_screen_halftone * ph, const gs_matrix * pmat, ulong max_size,
+ uint min_levels, bool accurate, gx_ht_cell_params_t * phcp)
+{
+ const bool landscape = (pmat->xy != 0.0 || pmat->yx != 0.0);
+
+ /* Account for a possibly reflected coordinate system. */
+ /* See gxstroke.c for the algorithm. */
+ const bool reflected = pmat->xy * pmat->yx > pmat->xx * pmat->yy;
+ const int reflection = (reflected ? -1 : 1);
+ const int rotation =
+ (landscape ? (pmat->yx < 0 ? 90 : -90) : pmat->xx < 0 ? 180 : 0);
+ const double f0 = ph->frequency, a0 = ph->angle;
+ const double T =
+ fabs((landscape ? pmat->yx / pmat->xy : pmat->xx / pmat->yy));
+ gs_point uv0;
+
+#define u0 uv0.x
+#define v0 uv0.y
+ int rt = 1;
+ double f = 0, a = 0;
+ double e_best = 1000;
+ bool better;
+
+ /*
+ * We need to find a vector in device space whose length is
+ * 1 inch / ph->frequency and whose angle is ph->angle.
+ * Because device pixels may not be square, we can't simply
+ * map the length to device space and then rotate it;
+ * instead, since we know that user space is uniform in X and Y,
+ * we calculate the correct angle in user space before rotation.
+ */
+
+ /* Compute trial values of u and v. */
+
+ {
+ gs_matrix rmat;
+
+ gs_make_rotation(a0 * reflection + rotation, &rmat);
+ gs_distance_transform(72.0 / f0, 0.0, &rmat, &uv0);
+ gs_distance_transform(u0, v0, pmat, &uv0);
+ if_debug10('h', "[h]Requested: f=%g a=%g mat=[%g %g %g %g] max_size=%lu min_levels=%u =>\n u=%g v=%g\n",
+ ph->frequency, ph->angle,
+ pmat->xx, pmat->xy, pmat->yx, pmat->yy,
+ max_size, min_levels, u0, v0);
+ }
+
+ /* Adjust u and v to reasonable values. */
+
+ if (u0 == 0 && v0 == 0)
+ return_error(gs_error_rangecheck);
+ while ((fabs(u0) + fabs(v0)) * rt < 4)
+ ++rt;
+ try_size:
+ better = false;
+ {
+ int m0 = (int)floor(u0 * rt + 0.0001);
+ int n0 = (int)floor(v0 * rt + 0.0001);
+ gx_ht_cell_params_t p;
+
+ p.R = p.R1 = rt;
+ for (p.M = m0 + 1; p.M >= m0; p.M--)
+ for (p.N = n0 + 1; p.N >= n0; p.N--) {
+ long raster, wt, wt_size;
+ double fr, ar, ft, at, f_diff, a_diff, f_err, a_err;
+
+ p.M1 = (int)floor(p.M / T + 0.5);
+ p.N1 = (int)floor(p.N * T + 0.5);
+ gx_compute_cell_values(&p);
+ if_debug3('h', "[h]trying m=%d, n=%d, r=%d\n", p.M, p.N, rt);
+ wt = p.W;
+ if (wt >= max_short)
+ continue;
+ /* Check the strip size, not the full tile size, */
+ /* against max_size. */
+ raster = bitmap_raster(wt);
+ if (raster > max_size / p.D || raster > max_long / wt)
+ continue;
+ wt_size = raster * wt;
+
+ /* Compute the corresponding values of F and A. */
+
+ if (landscape)
+ ar = atan2(p.M * pmat->xy, p.N * pmat->yx),
+ fr = 72.0 * (p.M == 0 ? pmat->xy / p.N * cos(ar) :
+ pmat->yx / p.M * sin(ar));
+ else
+ ar = atan2(p.N * pmat->xx, p.M * pmat->yy),
+ fr = 72.0 * (p.M == 0 ? pmat->yy / p.N * sin(ar) :
+ pmat->xx / p.M * cos(ar));
+ ft = fabs(fr) * rt;
+ /* Normalize the angle to the requested quadrant. */
+ at = (ar * radians_to_degrees - rotation) * reflection;
+ at -= floor(at / 180.0) * 180.0;
+ at += floor(a0 / 180.0) * 180.0;
+ f_diff = fabs(ft - f0);
+ a_diff = fabs(at - a0);
+ f_err = f_diff / fabs(f0);
+ /*
+ * We used to compute the percentage difference here:
+ * a_err = (a0 == 0 ? a_diff : a_diff / fabs(a0));
+ * but using the angle difference makes more sense:
+ */
+ a_err = a_diff;
+
+ if_debug5('h', " ==> d=%d, wt=%ld, wt_size=%ld, f=%g, a=%g\n",
+ p.D, wt, bitmap_raster(wt) * wt, ft, at);
+
+ /*
+ * Minimize angle and frequency error within the
+ * permitted maximum super-cell size.
+ */
+
+ {
+ double err = f_err * a_err;
+
+ if (err > e_best)
+ continue;
+ e_best = err;
+ }
+ *phcp = p;
+ f = ft, a = at;
+ better = true;
+ if_debug3('h', "*** best wt_size=%ld, f_diff=%g, a_diff=%g\n",
+ wt_size, f_diff, a_diff);
+ if (f_err <= 0.01 && a_err <= 0.01)
+ goto done;
+ }
+ }
+ if (phcp->C < min_levels) { /* We don't have enough levels yet. Keep going. */
+ ++rt;
+ goto try_size;
+ }
+ if (better) { /* If we want accurate screens, continue till we fail. */
+ if (accurate) {
+ ++rt;
+ goto try_size;
+ }
+ } else { /*
+ * We couldn't find an acceptable M and N. If R > 1,
+ * take what we've got; if R = 1, give up.
+ */
+ if (rt == 1)
+ return_error(gs_error_rangecheck);
+ }
+
+ /* Deliver the results. */
+ done:
+ if_debug5('h', "[h]Chosen: f=%g a=%g M=%d N=%d R=%d\n",
+ f, a, phcp->M, phcp->N, phcp->R);
+ ph->actual_frequency = f;
+ ph->actual_angle = a;
+ return 0;
+#undef u0
+#undef v0
+}
+
+/* Prepare to sample a spot screen. */
+/* This is the second half of gs_screen_init_accurate. */
+int
+gs_screen_enum_init_memory(gs_screen_enum * penum, const gx_ht_order * porder,
+ gs_state * pgs, gs_screen_halftone * phsp, gs_memory_t * mem)
+{
+ penum->pgs = pgs; /* ensure clean for GC */
+ penum->order = *porder;
+ penum->halftone.rc.memory = mem;
+ penum->halftone.type = ht_type_screen;
+ penum->halftone.params.screen = *phsp;
+ penum->x = penum->y = 0;
+ penum->strip = porder->num_levels / porder->width;
+ penum->shift = porder->shift;
+ /*
+ * We want a transformation matrix that maps the parallelogram
+ * (0,0), (U,V), (U-V',V+U'), (-V',U') to the square (+/-1, +/-1).
+ * If the coefficients are [a b c d e f] and we let
+ * u = U = M/R, v = V = N/R,
+ * r = -V' = -N'/R', s = U' = M'/R',
+ * then we just need to solve the equations:
+ * a*0 + c*0 + e = -1 b*0 + d*0 + f = -1
+ * a*u + c*v + e = 1 b*u + d*v + f = 1
+ * a*r + c*s + e = -1 b*r + d*s + f = 1
+ * This has the following solution:
+ * Q = 2 / (M*M' + N*N')
+ * a = Q * R * M'
+ * b = -Q * R' * N
+ * c = Q * R * N'
+ * d = Q * R' * M
+ * e = -1
+ * f = -1
+ */
+ {
+ const int M = porder->params.M, N = porder->params.N, R = porder->params.R;
+ const int M1 = porder->params.M1, N1 = porder->params.N1, R1 = porder->params.R1;
+ double Q = 2.0 / ((long)M * M1 + (long)N * N1);
+
+ penum->mat.xx = Q * (R * M1);
+ penum->mat.xy = Q * (-R1 * N);
+ penum->mat.yx = Q * (R * N1);
+ penum->mat.yy = Q * (R1 * M);
+ penum->mat.tx = -1.0;
+ penum->mat.ty = -1.0;
+ }
+ if_debug7('h', "[h]Screen: (%dx%d)/%d [%f %f %f %f]\n",
+ porder->width, porder->height, porder->params.R,
+ penum->mat.xx, penum->mat.xy,
+ penum->mat.yx, penum->mat.yy);
+ return 0;
+}
+
+/* Report current point for sampling */
+int
+gs_screen_currentpoint(gs_screen_enum * penum, gs_point * ppt)
+{
+ gs_point pt;
+ int code;
+
+ if (penum->y >= penum->strip) { /* all done */
+ gx_ht_construct_spot_order(&penum->order);
+ return 1;
+ }
+ /* We displace the sampled coordinates very slightly */
+ /* in order to reduce the likely number of points */
+ /* for which the spot function returns the same value. */
+ if ((code = gs_point_transform(penum->x + 0.501, penum->y + 0.498, &penum->mat, &pt)) < 0)
+ return code;
+ if (pt.x < -1.0)
+ pt.x += ((int)(-ceil(pt.x)) + 1) & ~1;
+ else if (pt.x >= 1.0)
+ pt.x -= ((int)pt.x + 1) & ~1;
+ if (pt.y < -1.0)
+ pt.y += ((int)(-ceil(pt.y)) + 1) & ~1;
+ else if (pt.y >= 1.0)
+ pt.y -= ((int)pt.y + 1) & ~1;
+ *ppt = pt;
+ return 0;
+}
+
+/* Record next halftone sample */
+int
+gs_screen_next(gs_screen_enum * penum, floatp value)
+{
+ ht_sample_t sample;
+ int width = penum->order.width;
+
+ if (value < -1.0 || value > 1.0)
+ return_error(gs_error_rangecheck);
+ /* The following statement was split into two */
+ /* to work around a bug in the Siemens C compiler. */
+ sample = (ht_sample_t) (value * max_ht_sample);
+ sample += max_ht_sample; /* convert from signed to biased */
+#ifdef DEBUG
+ if (gs_debug_c('H')) {
+ gs_point pt;
+
+ gs_screen_currentpoint(penum, &pt);
+ dlprintf6("[H]sample x=%d y=%d (%f,%f): %f -> %u\n",
+ penum->x, penum->y, pt.x, pt.y, value, sample);
+ }
+#endif
+ penum->order.bits[penum->y * width + penum->x].mask = sample;
+ if (++(penum->x) >= width)
+ penum->x = 0, ++(penum->y);
+ return 0;
+}
+
+/* Install a fully constructed screen in the gstate. */
+int
+gs_screen_install(gs_screen_enum * penum)
+{
+ gx_device_halftone dev_ht;
+
+ dev_ht.rc.memory = penum->halftone.rc.memory;
+ dev_ht.order = penum->order;
+ dev_ht.components = 0;
+ return gx_ht_install(penum->pgs, &penum->halftone, &dev_ht);
+}
diff --git a/pstoraster/gshtx.h b/pstoraster/gshtx.h
new file mode 100644
index 000000000..6e59644ba
--- /dev/null
+++ b/pstoraster/gshtx.h
@@ -0,0 +1,158 @@
+/* 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$ */
+/* High-level interface to stand-alone halftone/transfer objects */
+
+#ifndef gshtx_INCLUDED
+# define gshtx_INCLUDED
+
+#include "gsmemory.h"
+#include "gscsepnm.h"
+#include "gsht1.h"
+#include "gxtmap.h"
+
+/*
+ * The stand-alone halftone structures are opaque, and are placed in an opaque
+ * graphic state.
+ */
+
+/* Alias type names */
+#define gs_ht gs_halftone
+#define gs_spot_ht gs_spot_halftone
+#define gs_threshold_ht gs_threshold_halftone
+#define gs_ht_component gs_halftone_component
+#define gs_multiple_ht gs_multiple_halftone
+/* Alias GC descriptors */
+#define st_gs_ht st_halftone
+#define st_ht_comp_element st_ht_component_element
+/* Alias member names */
+#define ht_spot spot
+#define ht_threshold threshold
+#define ht_multiple multiple
+
+#ifndef gs_state_DEFINED
+# define gs_state_DEFINED
+typedef struct gs_state_s gs_state;
+
+#endif
+
+/*
+ * A "closure" form of gs_mapping_proc. This allows the procedure to access
+ * client data for the purpose of filling in the transfer information.
+ *
+ * As with PostScript transfer functions, the operand will be in the range
+ * [0, 1], and the result should be in the same range.
+ */
+typedef gs_mapping_closure_proc_t gs_ht_transfer_proc; /* see gxtmap.h */
+
+/*
+ * Constructor, destructor, assign, and copy routines for a gs_ht
+ * structure, and to install them in the graphic state.
+ *
+ * Notes:
+ *
+ * Construction of a gs_ht halftone requires two steps: creating the
+ * overall halftone, and creating each of the components. Client data
+ * must be provided for each of the latter steps.
+ *
+ * The type field of gs_ht halftones will always be ht_type_multiple;
+ * if only one component is required, this halftone will always be given
+ * the component name "Default".
+ *
+ * The type fields of the gs_ht_component structures pointed to by the
+ * gs_multiple_ht structure will have the value ht_type_spot or
+ * ht_type_threshold; the constructor routines will not build any
+ * other types.
+ *
+ * Individual component halftones of a gs_ht structure must always be
+ * provided with transfer functions.
+ *
+ * Releasing the gs_ht structure will NOT release the client data
+ * (the client must do that directly).
+ */
+
+extern int gs_ht_build(P3(gs_ht ** ppht, uint num_comps, gs_memory_t * pmem));
+
+extern int gs_ht_set_spot_comp(P9(
+ gs_ht * pht,
+ int component_index,
+ gs_ht_separation_name sepr_name,
+ float freq,
+ float angle,
+ float (*spot_func) (P2(floatp, floatp)),
+ bool accurate,
+ gs_ht_transfer_proc transfer,
+ const void *client_data
+ ));
+
+extern int gs_ht_set_threshold_comp(P8(
+ gs_ht * pht,
+ int component_index,
+ gs_ht_separation_name sepr_name,
+ int width,
+ int height,
+ const gs_const_string * thresholds,
+ gs_ht_transfer_proc transfer,
+ const void *client_data
+ ));
+
+/*
+ * This procedure specifies a (possibly non-monotonic) halftone of size
+ * width x height with num_levels different levels (including white, always
+ * all 0s, but excluding black, always all 1s). Each mask is in the form of
+ * a gs_bitmap, except that there is no row padding -- the 'raster' is
+ * ceil(width / 8).
+ *
+ * Note that the client is responsible for releasing the mask data.
+ */
+extern int gs_ht_set_mask_comp(P9(
+ gs_ht * pht,
+ int component_index,
+ gs_ht_separation_name sepr_name,
+ int width,
+ int height,
+ int num_levels,
+ const byte * masks, /* width x height x num_levels */
+ gs_ht_transfer_proc transfer,
+ const void *client_data
+ ));
+
+extern void gs_ht_reference(P1(gs_ht * pht));
+extern void gs_ht_release(P1(gs_ht * pht));
+
+#define gs_ht_assign(pto, pfrom) \
+ BEGIN \
+ gs_ht_reference(pfrom); \
+ if (pto != 0) \
+ gs_ht_release(pto); \
+ pto = pfrom; \
+ END
+
+#define gs_ht_init_ptr(pto, pfrom) \
+ BEGIN gs_ht_reference(pfrom); pto = pfrom; END
+
+extern int gs_ht_install(P2(gs_state * pgs, gs_ht * pht));
+
+#endif /* gshtx_INCLUDED */
diff --git a/pstoraster/gsimage.c b/pstoraster/gsimage.c
new file mode 100644
index 000000000..127c9ab20
--- /dev/null
+++ b/pstoraster/gsimage.c
@@ -0,0 +1,326 @@
+/* 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$ */
+/* Image setup procedures for Ghostscript library */
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gscspace.h"
+#include "gsmatrix.h" /* for gsiparam.h */
+#include "gsimage.h"
+#include "gxarith.h" /* for igcd */
+#include "gxdevice.h"
+#include "gxiparam.h"
+#include "gxpath.h" /* for gx_effective_clip_path */
+#include "gzstate.h"
+
+/* Define the enumeration state for this interface layer. */
+ /*typedef struct gs_image_enum_s gs_image_enum; *//* in gsimage.h */
+struct gs_image_enum_s {
+ /* The following are set at initialization time. */
+ gs_memory_t *memory;
+ gx_device *dev; /* if 0, just skip over the data */
+ gx_image_enum_common_t *info; /* driver bookkeeping structure */
+ int num_planes;
+ int width, height;
+ uint raster; /* bytes per row (per plane), no padding */
+ /* The following are updated dynamically. */
+ int plane_index; /* index of next plane of data */
+ int y;
+ uint pos; /* byte position within the scan line */
+ gs_const_string sources[gs_image_max_components]; /* source data */
+ gs_string rows[gs_image_max_components]; /* row buffers */
+ bool error;
+};
+
+gs_private_st_composite(st_gs_image_enum, gs_image_enum, "gs_image_enum",
+ gs_image_enum_enum_ptrs, gs_image_enum_reloc_ptrs);
+#define gs_image_enum_num_ptrs 2
+
+/* GC procedures */
+#define eptr ((gs_image_enum *)vptr)
+private
+ENUM_PTRS_BEGIN(gs_image_enum_enum_ptrs)
+{
+ /* Enumerate the data planes. */
+ index -= gs_image_enum_num_ptrs;
+ if (index < eptr->plane_index)
+ ENUM_RETURN_STRING_PTR(gs_image_enum, sources[index]);
+ index -= eptr->plane_index;
+ if (index < eptr->num_planes)
+ ENUM_RETURN_STRING_PTR(gs_image_enum, rows[index]);
+ return 0;
+}
+ENUM_PTR(0, gs_image_enum, dev);
+ENUM_PTR(1, gs_image_enum, info);
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(gs_image_enum_reloc_ptrs)
+{
+ int i;
+
+ RELOC_PTR(gs_image_enum, dev);
+ RELOC_PTR(gs_image_enum, info);
+ for (i = 0; i < eptr->plane_index; i++)
+ RELOC_CONST_STRING_PTR(gs_image_enum, sources[i]);
+ for (i = 0; i < eptr->num_planes; i++)
+ RELOC_STRING_PTR(gs_image_enum, rows[i]);
+}
+RELOC_PTRS_END
+#undef eptr
+
+/* Create an image enumerator given image parameters and a graphics state. */
+int
+gs_image_begin_typed(const gs_image_common_t * pic, gs_state * pgs,
+ bool uses_color, gx_image_enum_common_t ** ppie)
+{
+ gx_device *dev = gs_currentdevice(pgs);
+ gx_clip_path *pcpath;
+ int code = gx_effective_clip_path(pgs, &pcpath);
+
+ if (code < 0)
+ return code;
+ if (uses_color)
+ gx_set_dev_color(pgs);
+ return gx_device_begin_typed_image(dev, (const gs_imager_state *)pgs,
+ NULL, pic, NULL, pgs->dev_color, pcpath, pgs->memory, ppie);
+}
+
+/* Allocate an image enumerator. */
+private void
+image_enum_init(gs_image_enum * penum)
+{ /* Clean pointers for GC. */
+ int i;
+
+ penum->info = 0;
+ penum->dev = 0;
+ for (i = 0; i < countof(penum->sources); ++i) {
+ penum->sources[i].data = 0, penum->sources[i].size = 0;
+ penum->rows[i].data = 0, penum->rows[i].size = 0;
+ }
+}
+gs_image_enum *
+gs_image_enum_alloc(gs_memory_t * mem, client_name_t cname)
+{
+ gs_image_enum *penum =
+ gs_alloc_struct(mem, gs_image_enum, &st_gs_image_enum, cname);
+
+ if (penum != 0) {
+ penum->memory = mem;
+ image_enum_init(penum);
+ }
+ return penum;
+}
+
+/* Start processing an ImageType 1 image. */
+int
+gs_image_init(gs_image_enum * penum, const gs_image_t * pim, bool multi,
+ gs_state * pgs)
+{
+ gs_image_t image;
+ gx_image_enum_common_t *pie;
+ int code;
+
+ image = *pim;
+ if (image.ImageMask) {
+ image.ColorSpace = NULL;
+ if (pgs->in_cachedevice <= 1)
+ image.adjust = false;
+ } else {
+ if (pgs->in_cachedevice)
+ return_error(gs_error_undefined);
+ if (image.ColorSpace == NULL)
+ image.ColorSpace =
+ gs_cspace_DeviceGray((const gs_imager_state *)pgs);
+ }
+ code = gs_image_begin_typed((const gs_image_common_t *)&image, pgs,
+ image.ImageMask | image.CombineWithColor,
+ &pie);
+ if (code < 0)
+ return code;
+ return gs_image_common_init(penum, pie,
+ (const gs_data_image_t *)&image,
+ pgs->memory,
+ (pgs->in_charpath ? NULL :
+ gs_currentdevice_inline(pgs)));
+}
+/* Start processing a general image. */
+int
+gs_image_common_init(gs_image_enum * penum, gx_image_enum_common_t * pie,
+ const gs_data_image_t * pim, gs_memory_t * mem, gx_device * dev)
+{
+ if (pim->Width == 0 || pim->Height == 0) {
+ gx_image_end(pie, false);
+ return 1;
+ }
+ image_enum_init(penum);
+ penum->memory = mem;
+ penum->dev = dev;
+ penum->info = pie;
+ penum->num_planes = pie->num_planes;
+ penum->width = pim->Width;
+ penum->height = pim->Height;
+/****** ALL PLANES MUST HAVE SAME DEPTH FOR NOW ******/
+ penum->raster = (pim->Width * pie->plane_depths[0] + 7) >> 3;
+ /* Initialize the dynamic part of the state. */
+ penum->plane_index = 0;
+ penum->y = 0;
+ penum->pos = 0;
+ penum->error = false;
+ return 0;
+}
+
+/*
+ * Return the number of bytes of data per row per plane.
+ */
+uint
+gs_image_bytes_per_plane_row(const gs_image_enum * penum, int plane)
+{
+/****** IGNORE PLANE FOR NOW ******/
+ return penum->raster;
+}
+
+/* Process the next piece of an image. */
+private int
+copy_planes(gx_device * dev, gs_image_enum * penum, const byte ** planes,
+ int h)
+{
+ int code =
+ (penum->dev == 0 ? (penum->y + h < penum->height ? 0 : 1) :
+ gx_image_data(penum->info, planes, 0, penum->raster, h));
+
+ if (code < 0)
+ penum->error = true;
+ return code;
+}
+int
+gs_image_next(gs_image_enum * penum, const byte * dbytes, uint dsize,
+ uint * pused)
+{
+ gx_device *dev;
+ uint left;
+ int num_planes;
+ uint raster;
+ uint pos;
+ int code;
+
+ /*
+ * Handle the following differences between gs_image_next and
+ * the device image_data procedure:
+ *
+ * - image_data requires an array of planes; gs_image_next
+ * expects planes in successive calls.
+ *
+ * - image_data requires that each call pass entire rows;
+ * gs_image_next allows arbitrary amounts of data.
+ */
+ if (penum->plane_index != 0)
+ if (dsize != penum->sources[0].size)
+ return_error(gs_error_rangecheck);
+ penum->sources[penum->plane_index].data = dbytes;
+ penum->sources[penum->plane_index].size = dsize;
+ if (++(penum->plane_index) != penum->num_planes)
+ return 0;
+ /* We have a full set of planes. */
+ dev = penum->dev;
+ left = dsize;
+ num_planes = penum->num_planes;
+ raster = penum->raster;
+ pos = penum->pos;
+ code = 0;
+ while (left && penum->y < penum->height) {
+ const byte *planes[gs_image_max_components];
+ int i;
+
+ for (i = 0; i < num_planes; ++i)
+ planes[i] = penum->sources[i].data + dsize - left;
+ if (pos == 0 && left >= raster) { /* Pass (a) row(s) directly from the source. */
+ int h = left / raster;
+
+ if (h > penum->height - penum->y)
+ h = penum->height - penum->y;
+ code = copy_planes(dev, penum, planes, h);
+ if (code < 0)
+ break;
+ left -= raster * h;
+ penum->y += h;
+ } else { /* Buffer a partial row. */
+ uint count = min(left, raster - pos);
+
+ if (penum->rows[0].data == 0) { /* Allocate the row buffers. */
+ for (i = 0; i < num_planes; ++i) {
+ byte *row = gs_alloc_string(penum->memory, raster,
+ "gs_image_next(row)");
+
+ if (row == 0) {
+ code = gs_note_error(gs_error_VMerror);
+ while (--i >= 0) {
+ gs_free_string(penum->memory, penum->rows[i].data,
+ raster, "gs_image_next(row)");
+ penum->rows[i].data = 0;
+ penum->rows[i].size = 0;
+ }
+ break;
+ }
+ penum->rows[i].data = row;
+ penum->rows[i].size = raster;
+ }
+ if (code < 0)
+ break;
+ }
+ for (i = 0; i < num_planes; ++i)
+ memcpy(penum->rows[i].data + pos, planes[i], count);
+ pos += count;
+ left -= count;
+ if (pos == raster) {
+ for (i = 0; i < num_planes; ++i)
+ planes[i] = penum->rows[i].data;
+ code = copy_planes(dev, penum, planes, 1);
+ if (code < 0)
+ break;
+ pos = 0;
+ penum->y++;
+ }
+ }
+ }
+ penum->pos = pos;
+ penum->plane_index = 0;
+ *pused = dsize - left;
+ return code;
+}
+
+/* Clean up after processing an image. */
+void
+gs_image_cleanup(gs_image_enum * penum)
+{
+ int i;
+
+ for (i = 0; i < penum->num_planes; ++i)
+ gs_free_string(penum->memory, penum->rows[i].data,
+ penum->rows[i].size, "gs_image_cleanup(row)");
+ if (penum->dev != 0)
+ gx_image_end(penum->info, !penum->error);
+ /* Don't free the local enumerator -- the client does that. */
+}
diff --git a/pstoraster/gsimage.h b/pstoraster/gsimage.h
new file mode 100644
index 000000000..4f6e6b11e
--- /dev/null
+++ b/pstoraster/gsimage.h
@@ -0,0 +1,84 @@
+/* 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$ */
+/* Requires gsstate.h */
+
+#ifndef gsimage_INCLUDED
+# define gsimage_INCLUDED
+
+#include "gsiparam.h"
+
+/*
+ * Create an image enumerator given image parameters and a graphics state.
+ * This calls the device's begin_typed_image procedure with appropriate
+ * parameters. Note that this is an enumerator that requires entire
+ * rows of data, not the buffered enumerator used by the procedures below:
+ * for this reason, we may move the prototype elsewhere in the future.
+ */
+#ifndef gx_image_enum_common_t_DEFINED
+# define gx_image_enum_common_t_DEFINED
+typedef struct gx_image_enum_common_s gx_image_enum_common_t;
+
+#endif
+int gs_image_begin_typed(P4(const gs_image_common_t * pic, gs_state * pgs,
+ bool uses_color, gx_image_enum_common_t ** ppie));
+
+/*
+ * The image painting interface uses an enumeration style:
+ * the client initializes an enumerator, then supplies data incrementally.
+ */
+typedef struct gs_image_enum_s gs_image_enum;
+gs_image_enum *gs_image_enum_alloc(P2(gs_memory_t *, client_name_t));
+
+/*
+ * image_init returns 1 for an empty image, 0 normally, <0 on error.
+ * Note that image_init serves for both image and imagemask,
+ * depending on the value of ImageMask in the image structure.
+ */
+#ifndef gx_device_DEFINED
+# define gx_device_DEFINED
+typedef struct gx_device_s gx_device;
+
+#endif
+int gs_image_common_init(P5(gs_image_enum * penum, gx_image_enum_common_t * pie,
+ const gs_data_image_t * pim,
+ gs_memory_t * mem, gx_device * dev));
+int gs_image_init(P4(gs_image_enum * penum, const gs_image_t * pim,
+ bool MultipleDataSources, gs_state * pgs));
+int gs_image_next(P4(gs_image_enum * penum, const byte * dbytes,
+ uint dsize, uint * pused));
+
+/*
+ * Return the number of bytes of data per row
+ * (per plane, if MultipleDataSources is true).
+ */
+uint gs_image_bytes_per_plane_row(P2(const gs_image_enum * penum, int plane));
+
+#define gs_image_bytes_per_row(penum)\
+ gs_image_bytes_per_plane_row(penum, 0)
+/* Clean up after processing an image. */
+void gs_image_cleanup(P1(gs_image_enum * penum));
+
+#endif /* gsimage_INCLUDED */
diff --git a/pstoraster/gsimpath.c b/pstoraster/gsimpath.c
new file mode 100644
index 000000000..503398b1f
--- /dev/null
+++ b/pstoraster/gsimpath.c
@@ -0,0 +1,191 @@
+/* Copyright (C) 1989, 1992, 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 to outline conversion for Ghostscript library */
+#include "gx.h"
+#include "gserrors.h"
+#include "gsmatrix.h"
+#include "gsstate.h"
+#include "gspath.h"
+
+/* Define the state of the conversion process. */
+typedef struct {
+ /* The following are set at the beginning of the conversion. */
+ gs_state *pgs;
+ const byte *data; /* image data */
+ int width, height, raster;
+ /* The following are updated dynamically. */
+ int dx, dy; /* X/Y increment of current run */
+ int count; /* # of steps in current run */
+} status;
+
+/* Define the scaling for the path tracer. */
+/* It must be even. */
+#define outline_scale 4
+/* Define the length of the short strokes for turning corners. */
+#define step 1
+
+/* Forward declarations */
+private int get_pixel(P3(const status *, int, int));
+private int trace_from(P4(status *, int, int, int));
+private int add_dxdy(P4(status *, int, int, int));
+
+#define add_deltas(s, dx, dy, n)\
+ if ( (code = add_dxdy(s, dx, dy, n)) < 0 ) return code
+/* Append an outline derived from an image to the current path. */
+int
+gs_imagepath(gs_state * pgs, int width, int height, const byte * data)
+{
+ status stat;
+ status *out = &stat;
+ int code, x, y;
+
+ /* Initialize the state. */
+ stat.pgs = pgs;
+ stat.data = data;
+ stat.width = width;
+ stat.height = height;
+ stat.raster = (width + 7) / 8;
+ /* Trace the cells to form an outline. The trace goes in clockwise */
+ /* order, always starting by going west along a bottom edge. */
+ for (y = height - 1; y >= 0; y--)
+ for (x = width - 1; x >= 0; x--) {
+ if (get_pixel(out, x, y) && !get_pixel(out, x, y - 1) &&
+ (!get_pixel(out, x + 1, y) || get_pixel(out, x + 1, y - 1)) &&
+ !trace_from(out, x, y, 1)
+ ) { /* Found a starting point */
+ stat.count = 0;
+ stat.dx = stat.dy = 0;
+ if ((code = trace_from(out, x, y, 0)) < 0)
+ return code;
+ add_deltas(out, 0, 0, 1); /* force out last segment */
+ if ((code = gs_closepath(pgs)) < 0)
+ return code;
+ }
+ }
+ return 0;
+}
+
+/* Get a pixel from the data. Return 0 if outside the image. */
+private int
+get_pixel(register const status * out, int x, int y)
+{
+ if (x < 0 || x >= out->width || y < 0 || y >= out->height)
+ return 0;
+ return (out->data[y * out->raster + (x >> 3)] >> (~x & 7)) & 1;
+}
+
+/* Trace a path. If detect is true, don't draw, just return 1 if we ever */
+/* encounter a starting point whose x,y follows that of the initial point */
+/* in x-then-y scan order; if detect is false, actually draw the outline. */
+private int
+trace_from(register status * out, int x0, int y0, int detect)
+{
+ int x = x0, y = y0;
+ int dx = -1, dy = 0; /* initially going west */
+ int part = 0; /* how far along edge we are; */
+
+ /* initialized only to pacify gcc */
+ int code;
+
+ if (!detect) {
+ part = (get_pixel(out, x + 1, y - 1) ?
+ outline_scale - step : step);
+ code = gs_moveto(out->pgs,
+ x + 1 - part / (float)outline_scale,
+ (float)y);
+ if (code < 0)
+ return code;
+ }
+ while (1) { /* Relative to the current direction, */
+ /* -dy,dx is at +90 degrees (counter-clockwise); */
+ /* tx,ty is at +45 degrees; */
+ /* ty,-tx is at -45 degrees (clockwise); */
+ /* dy,-dx is at -90 degrees. */
+ int tx = dx - dy, ty = dy + dx;
+
+ if (get_pixel(out, x + tx, y + ty)) { /* Cell at 45 degrees is full, */
+ /* go counter-clockwise. */
+ if (!detect) { /* If this is a 90 degree corner set at a */
+ /* 45 degree angle, avoid backtracking. */
+ if (out->dx == ty && out->dy == -tx) {
+#define half_scale (outline_scale / 2 - step)
+ out->count -= half_scale;
+ add_deltas(out, tx, ty, outline_scale / 2);
+#undef half_scale
+ } else {
+ add_deltas(out, dx, dy, step - part);
+ add_deltas(out, tx, ty, outline_scale - step);
+ }
+ part = outline_scale - step;
+ }
+ x += tx, y += ty;
+ dx = -dy, dy += tx;
+ } else if (!get_pixel(out, x + dx, y + dy)) { /* Cell straight ahead is empty, go clockwise. */
+ if (!detect) {
+ add_deltas(out, dx, dy, outline_scale - step - part);
+ add_deltas(out, ty, -tx, step);
+ part = step;
+ }
+ dx = dy, dy -= ty;
+ } else { /* Neither of the above, go in same direction. */
+ if (!detect) {
+ add_deltas(out, dx, dy, outline_scale);
+ }
+ x += dx, y += dy;
+ }
+ if (dx == -step && dy == 0 && !(tx == -step && ty == -step)) { /* We just turned a corner and are going west, */
+ /* so the previous pixel is a starting point pixel. */
+ if (x == x0 && y == y0)
+ return 0;
+ if (detect && (y > y0 || (y == y0 && x > x0)))
+ return 1;
+ }
+ }
+}
+
+/* Add a (dx, dy) pair to the path being formed. */
+/* Accumulate successive segments in the same direction. */
+private int
+add_dxdy(register status * out, int dx, int dy, int count)
+{
+ if (count != 0) {
+ if (dx == out->dx && dy == out->dy)
+ out->count += count;
+ else {
+ if (out->count != 0) {
+ int code = gs_rlineto(out->pgs,
+ out->dx * out->count / (float)outline_scale,
+ out->dy * out->count / (float)outline_scale);
+
+ if (code < 0)
+ return code;
+ }
+ out->dx = dx, out->dy = dy;
+ out->count = count;
+ }
+ }
+ return 0;
+}
diff --git a/pstoraster/gsinit.c b/pstoraster/gsinit.c
new file mode 100644
index 000000000..eddb5aa1c
--- /dev/null
+++ b/pstoraster/gsinit.c
@@ -0,0 +1,79 @@
+/* Copyright (C) 1989, 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$ */
+/* Initialization for the imager */
+#include "stdio_.h"
+#include "memory_.h"
+#include "gdebug.h"
+#include "gscdefs.h"
+#include "gsmemory.h"
+#include "gsmalloc.h"
+#include "gp.h"
+#include "gslib.h" /* interface definition */
+
+/* Imported from gsmisc.c */
+extern FILE *gs_debug_out;
+
+/* Configuration information from gconfig.c. */
+extern_gx_init_table();
+
+/* Initialization to be done before anything else. */
+void
+gs_lib_init(FILE * debug_out)
+{
+ gs_lib_init1(gs_lib_init0(debug_out));
+}
+gs_memory_t *
+gs_lib_init0(FILE * debug_out)
+{
+ gs_memory_t *mem;
+
+ gs_debug_out = debug_out;
+ mem = (gs_memory_t *) gs_malloc_init();
+ /* Reset debugging flags */
+ memset(gs_debug, 0, 128);
+ gs_log_errors = 0;
+ return mem;
+}
+void
+gs_lib_init1(gs_memory_t * mem)
+{ /* Run configuration-specific initialization procedures. */
+ {
+ void (*const *ipp) (P1(gs_memory_t *));
+
+ for (ipp = gx_init_table; *ipp != 0; ++ipp)
+ (**ipp) (mem);
+ }
+}
+
+/* Clean up after execution. */
+void
+gs_lib_finit(int exit_status, int code)
+{
+ fflush(stderr); /* in case of error exit */
+ /* Do platform-specific cleanup. */
+ gp_exit(exit_status, code);
+ gs_malloc_release();
+}
diff --git a/pstoraster/gsio.h b/pstoraster/gsio.h
new file mode 100644
index 000000000..a5791961f
--- /dev/null
+++ b/pstoraster/gsio.h
@@ -0,0 +1,66 @@
+/* Copyright (C) 1989, 1990, 1993, 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$ */
+/* stdio redirection */
+
+#ifndef gsio_INCLUDED
+# define gsio_INCLUDED
+
+/* The library and interpreter never use stdin/out/err directly. */
+extern FILE *gs_stdin, *gs_stdout, *gs_stderr;
+
+/* Redefine all the relevant stdio functions to use the above. */
+/* Some functions we make illegal, rather than redefining them. */
+#undef stdin
+#define stdin gs_stdin
+#undef stdout
+#define stdout gs_stdout
+#undef stderr
+#define stderr gs_stderr
+#undef fgetchar
+#define fgetchar() fgetc(stdin)
+#undef fputchar
+#define fputchar(c) fputc(c, stdout)
+#undef getchar
+#define getchar() getc(stdin)
+#undef gets
+#define gets Function._gets_.unavailable
+/* We should do something about perror, but since many Unix systems */
+/* don't provide the strerror function, we can't. (No Aladdin-maintained */
+/* code uses perror.) */
+#undef printf
+#define printf Function._printf_.unavailable
+#undef putchar
+#define putchar(c) fputc(c, stdout)
+#undef puts
+#define puts(s) (fputs(s, stdout), putchar('\n'))
+#undef scanf
+#define scanf Function._scanf_.unavailable
+#undef vprintf
+#define vprintf Function._vprintf_.unavailable
+#undef vscanf
+#define vscanf Function._vscanf_.unavailable
+
+#endif /* gsio_INCLUDED */
diff --git a/pstoraster/gsiodev.c b/pstoraster/gsiodev.c
new file mode 100644
index 000000000..a140c365f
--- /dev/null
+++ b/pstoraster/gsiodev.c
@@ -0,0 +1,318 @@
+/* Copyright (C) 1993, 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$ */
+/* IODevice implementation for Ghostscript */
+#include "errno_.h"
+#include "string_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gp.h"
+#include "gscdefs.h"
+#include "gsparam.h"
+#include "gsstruct.h"
+#include "gxiodev.h"
+
+/* Import the IODevice table from gconf.c. */
+extern_gx_io_device_table();
+
+/* Define a table of local copies of the IODevices, */
+/* allocated at startup. This just postpones the day of reckoning.... */
+private gx_io_device **io_device_table;
+
+private_st_io_device();
+gs_private_st_ptr(st_io_device_ptr, gx_io_device *, "gx_io_device *",
+ iodev_ptr_enum_ptrs, iodev_ptr_reloc_ptrs);
+gs_private_st_element(st_io_device_ptr_element, gx_io_device *,
+ "gx_io_device *[]", iodev_ptr_elt_enum_ptrs, iodev_ptr_elt_reloc_ptrs,
+ st_io_device_ptr);
+
+/* Define the OS (%os%) device. */
+iodev_proc_fopen(iodev_os_fopen);
+iodev_proc_fclose(iodev_os_fclose);
+private iodev_proc_delete_file(os_delete);
+private iodev_proc_rename_file(os_rename);
+private iodev_proc_file_status(os_status);
+private iodev_proc_enumerate_files(os_enumerate);
+private iodev_proc_get_params(os_get_params);
+const gx_io_device gs_iodev_os =
+{
+ "%os%", "FileSystem",
+ {iodev_no_init, iodev_no_open_device,
+ NULL /*iodev_os_open_file */ , iodev_os_fopen, iodev_os_fclose,
+ os_delete, os_rename, os_status,
+ os_enumerate, gp_enumerate_files_next, gp_enumerate_files_close,
+ os_get_params, iodev_no_put_params
+ }
+};
+
+/* ------ Initialization ------ */
+
+void
+gs_iodev_init(gs_memory_t * mem)
+{ /* Make writable copies of all IODevices. */
+ gx_io_device **table =
+ gs_alloc_struct_array(mem, gx_io_device_table_count,
+ gx_io_device *, &st_io_device_ptr_element,
+ "gsiodev_init(table)");
+ uint i;
+
+ for (i = 0; i < gx_io_device_table_count; ++i) {
+ table[i] = gs_alloc_struct(mem, gx_io_device, &st_io_device,
+ "gsiodev_init");
+ memcpy(table[i], gx_io_device_table[i], sizeof(gx_io_device));
+ }
+ io_device_table = table;
+ gs_register_struct_root(mem, NULL, (void **)&io_device_table,
+ "io_device_table");
+ /* Run the one-time initialization of each IODevice. */
+ for (i = 0; i < gx_io_device_table_count; ++i)
+ (table[i]->procs.init) (table[i], mem);
+}
+
+/* ------ Default (unimplemented) IODevice procedures ------ */
+
+int
+iodev_no_init(gx_io_device * iodev, gs_memory_t * mem)
+{
+ return 0;
+}
+
+int
+iodev_no_open_device(gx_io_device * iodev, const char *access, stream ** ps,
+ gs_memory_t * mem)
+{
+ return_error(gs_error_invalidfileaccess);
+}
+
+int
+iodev_no_open_file(gx_io_device * iodev, const char *fname, uint namelen,
+ const char *access, stream ** ps, gs_memory_t * mem)
+{
+ return_error(gs_error_invalidfileaccess);
+}
+
+int
+iodev_no_fopen(gx_io_device * iodev, const char *fname, const char *access,
+ FILE ** pfile, char *rfname, uint rnamelen)
+{
+ return_error(gs_error_invalidfileaccess);
+}
+
+int
+iodev_no_fclose(gx_io_device * iodev, FILE * file)
+{
+ return_error(gs_error_ioerror);
+}
+
+int
+iodev_no_delete_file(gx_io_device * iodev, const char *fname)
+{
+ return_error(gs_error_invalidfileaccess);
+}
+
+int
+iodev_no_rename_file(gx_io_device * iodev, const char *from, const char *to)
+{
+ return_error(gs_error_invalidfileaccess);
+}
+
+int
+iodev_no_file_status(gx_io_device * iodev, const char *fname, struct stat *pstat)
+{
+ return_error(gs_error_undefinedfilename);
+}
+
+file_enum *
+iodev_no_enumerate_files(gx_io_device * iodev, const char *pat, uint patlen,
+ gs_memory_t * memory)
+{
+ return NULL;
+}
+
+int
+iodev_no_get_params(gx_io_device * iodev, gs_param_list * plist)
+{
+ return 0;
+}
+
+int
+iodev_no_put_params(gx_io_device * iodev, gs_param_list * plist)
+{
+ return param_commit(plist);
+}
+
+/* ------ %os% ------ */
+
+/* The fopen routine is exported for %null. */
+int
+iodev_os_fopen(gx_io_device * iodev, const char *fname, const char *access,
+ FILE ** pfile, char *rfname, uint rnamelen)
+{
+ errno = 0;
+ *pfile = gp_fopen(fname, access);
+ if (*pfile == NULL)
+ return_error(gs_fopen_errno_to_code(errno));
+ if (rfname != NULL)
+ strcpy(rfname, fname);
+ return 0;
+}
+
+/* The fclose routine is exported for %null. */
+int
+iodev_os_fclose(gx_io_device * iodev, FILE * file)
+{
+ fclose(file);
+ return 0;
+}
+
+private int
+os_delete(gx_io_device * iodev, const char *fname)
+{
+ return (unlink(fname) == 0 ? 0 : gs_error_ioerror);
+}
+
+private int
+os_rename(gx_io_device * iodev, const char *from, const char *to)
+{
+ return (rename(from, to) == 0 ? 0 : gs_error_ioerror);
+}
+
+private int
+os_status(gx_io_device * iodev, const char *fname, struct stat *pstat)
+{ /* The RS/6000 prototype for stat doesn't include const, */
+ /* so we have to explicitly remove the const modifier. */
+ return (stat((char *)fname, pstat) < 0 ? gs_error_undefinedfilename : 0);
+}
+
+private file_enum *
+os_enumerate(gx_io_device * iodev, const char *pat, uint patlen,
+ gs_memory_t * mem)
+{
+ return gp_enumerate_files_init(pat, patlen, mem);
+}
+
+private int
+os_get_params(gx_io_device * iodev, gs_param_list * plist)
+{ /* We aren't going to implement *all* of the Adobe parameters.... */
+ int code;
+ bool btrue = true;
+
+ if ((code = param_write_bool(plist, "HasNames", &btrue)) < 0)
+ return code;
+ return 0;
+}
+
+/* ------ Utilities ------ */
+
+/* Get the N'th IODevice from the known device table. */
+gx_io_device *
+gs_getiodevice(int index)
+{
+ if (index < 0 || index >= gx_io_device_table_count)
+ return 0; /* index out of range */
+ return io_device_table[index];
+}
+
+/* Look up an IODevice name. */
+/* The name may be either %device or %device%. */
+gx_io_device *
+gs_findiodevice(const byte * str, uint len)
+{
+ gx_io_device **pftab;
+
+ if (len > 1 && str[len - 1] == '%')
+ len--;
+ for (pftab = io_device_table; *pftab != NULL; pftab++) {
+ const char *dname = (*pftab)->dname;
+
+ if (strlen(dname) == len + 1 && !memcmp(str, dname, len))
+ return *pftab;
+ }
+ return 0;
+}
+
+/* ------ Accessors ------ */
+
+/* Get IODevice parameters. */
+int
+gs_getdevparams(gx_io_device * iodev, gs_param_list * plist)
+{ /* All IODevices have the Type parameter. */
+ gs_param_string ts;
+ int code;
+
+ param_string_from_string(ts, iodev->dtype);
+ code = param_write_name(plist, "Type", &ts);
+ if (code < 0)
+ return code;
+ return (*iodev->procs.get_params) (iodev, plist);
+}
+
+/* Put IODevice parameters. */
+int
+gs_putdevparams(gx_io_device * iodev, gs_param_list * plist)
+{
+ return (*iodev->procs.put_params) (iodev, plist);
+}
+
+/* Convert an OS error number to a PostScript error */
+/* if opening a file fails. */
+int
+gs_fopen_errno_to_code(int eno)
+{ /* Different OSs vary widely in their error codes. */
+ /* We try to cover as many variations as we know about. */
+ switch (eno) {
+#ifdef ENOENT
+ case ENOENT:
+ return_error(gs_error_undefinedfilename);
+#endif
+#ifdef ENOFILE
+# ifndef ENOENT
+# define ENOENT ENOFILE
+# endif
+# if ENOFILE != ENOENT
+ case ENOFILE:
+ return_error(gs_error_undefinedfilename);
+# endif
+#endif
+#ifdef ENAMETOOLONG
+ case ENAMETOOLONG:
+ return_error(gs_error_undefinedfilename);
+#endif
+#ifdef EACCES
+ case EACCES:
+ return_error(gs_error_invalidfileaccess);
+#endif
+#ifdef EMFILE
+ case EMFILE:
+ return_error(gs_error_limitcheck);
+#endif
+#ifdef ENFILE
+ case ENFILE:
+ return_error(gs_error_limitcheck);
+#endif
+ default:
+ return_error(gs_error_ioerror);
+ }
+}
diff --git a/pstoraster/gsiparam.h b/pstoraster/gsiparam.h
new file mode 100644
index 000000000..650295b78
--- /dev/null
+++ b/pstoraster/gsiparam.h
@@ -0,0 +1,289 @@
+/* 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$ */
+/* Image parameter definition */
+
+#ifndef gsiparam_INCLUDED
+# define gsiparam_INCLUDED
+
+#include "gsmatrix.h"
+
+/* ---------------- Image parameters ---------------- */
+
+/*
+ * Unfortunately, we defined the gs_image_t type as designating an ImageType
+ * 1 image or mask before we realized that there were going to be other
+ * ImageTypes. We could redefine this type to include a type field without
+ * perturbing clients, but it would break implementations of driver
+ * begin_image procedures, since they are currently only prepared to handle
+ * ImageType 1 images and would have to be modified to check the ImageType.
+ * Therefore, we use gs_image_common_t for an abstract image type, and
+ * gs_image<n>_t for the various ImageTypes.
+ */
+
+/*
+ * Define the data common to all image types. The type structure is
+ * opaque here, defined in gxiparam.h.
+ */
+#ifndef gx_image_type_DEFINED
+# define gx_image_type_DEFINED
+typedef struct gx_image_type_s gx_image_type_t;
+
+#endif
+#define gs_image_common\
+ const gx_image_type_t *type;\
+ /*\
+ * Define the transformation from user space to image space.\
+ */\
+ gs_matrix ImageMatrix
+typedef struct gs_image_common_s {
+ gs_image_common;
+} gs_image_common_t;
+
+#define public_st_gs_image_common() /* in gxiinit.c */\
+ gs_public_st_simple(st_gs_image_common, gs_image_common_t,\
+ "gs_image_common_t")
+
+/*
+ * Define the maximum number of components in image data. When we
+ * support DeviceN color spaces, we will have to rethink this.
+ * 5 is either CMYK + alpha or mask + CMYK.
+ */
+#define gs_image_max_components 5
+
+/*
+ * Define the structure for defining data common to ImageType 1 images,
+ * ImageType 3 DataDicts and MaskDicts, and ImageType 4 images -- i.e.,
+ * all the image types that use explicitly supplied data. It follows
+ * closely the discussion on pp. 219-223 of the PostScript Language
+ * Reference Manual, Second Edition, with the following exceptions:
+ *
+ * DataSource and MultipleDataSources are not members of this
+ * structure, since the structure doesn't take a position on
+ * how the data are actually supplied.
+ */
+#define gs_data_image_common\
+ gs_image_common;\
+ /*\
+ * Define the width of source image in pixels.\
+ */\
+ int Width;\
+ /*\
+ * Define the height of source image in pixels.\
+ */\
+ int Height;\
+ /*\
+ * Define B, the number of bits per pixel component.\
+ * Currently this must be 1 for masks.\
+ */\
+ int BitsPerComponent;\
+ /*\
+ * Define the linear remapping of the input values.\
+ * For the I'th pixel component, we start by treating\
+ * the B bits of component data as a fraction F between\
+ * 0 and 1; the actual component value is then\
+ * Decode[I*2] + F * (Decode[I*2+1] - Decode[I*2]).\
+ * For masks, only the first two entries are used;\
+ * they must be 1,0 for write-0s masks, 0,1 for write-1s.\
+ */\
+ float Decode[gs_image_max_components * 2];\
+ /*\
+ * Define whether to smooth the image.\
+ */\
+ bool Interpolate
+typedef struct gs_data_image_s {
+ gs_data_image_common;
+} gs_data_image_t;
+
+#define public_st_gs_data_image() /* in gxiinit.c */\
+ gs_public_st_simple(st_gs_data_image, gs_data_image_t,\
+ "gs_data_image_t")
+
+/*
+ * Define the data common to ImageType 1 images, ImageType 3 DataDicts,
+ * and ImageType 4 images -- i.e., all the image types that provide pixel
+ * (as opposed to mask) data. The following are added to the PostScript
+ * image parameters:
+ *
+ * format is not PostScript or PDF standard: it is normally derived
+ * from MultipleDataSources.
+ *
+ * ColorSpace is added from PDF.
+ *
+ * CombineWithColor is not PostScript or PDF standard: see the
+ * RasterOp section of language.doc for a discussion of
+ * CombineWithColor.
+ */
+typedef enum {
+ /* Single plane, chunky pixels. */
+ gs_image_format_chunky = 0,
+ /* num_components planes, chunky components. */
+ gs_image_format_component_planar = 1,
+ /* BitsPerComponent * num_components planes, 1 bit per plane */
+/****** NOT SUPPORTED YET, DO NOT USE ******/
+ gs_image_format_bit_planar = 2
+} gs_image_format_t;
+
+/* Define an opaque type for a color space. */
+#ifndef gs_color_space_DEFINED
+# define gs_color_space_DEFINED
+typedef struct gs_color_space_s gs_color_space;
+
+#endif
+
+#define gs_pixel_image_common\
+ gs_data_image_common;\
+ /*\
+ * Define how the pixels are divided up into planes.\
+ */\
+ gs_image_format_t format;\
+ /*\
+ * Define the source color space (must be NULL for masks).\
+ */\
+ const gs_color_space *ColorSpace;\
+ /*\
+ * Define whether to use the drawing color as the\
+ * "texture" for RasterOp. For more information,\
+ * see the discussion of RasterOp in language.doc.\
+ */\
+ bool CombineWithColor
+typedef struct gs_pixel_image_s {
+ gs_pixel_image_common;
+} gs_pixel_image_t;
+
+#define public_st_gs_pixel_image() /* in gxiinit.c */\
+ gs_public_st_ptrs1(st_gs_pixel_image, gs_pixel_image_t,\
+ "gs_data_image_t", pixel_image_enum_ptrs, pixel_image_reloc_ptrs,\
+ ColorSpace)
+
+/*
+ * Define an ImageType 1 image. ImageMask is an added member from PDF.
+ * adjust and Alpha are not PostScript or PDF standard.
+ */
+typedef enum {
+ /* No alpha. This must be 0 for true-false tests. */
+ gs_image_alpha_none = 0,
+ /* Alpha precedes color components. */
+ gs_image_alpha_first,
+ /* Alpha follows color components. */
+ gs_image_alpha_last
+} gs_image_alpha_t;
+
+typedef struct gs_image1_s {
+ gs_pixel_image_common;
+ /*
+ * Define whether this is a mask or a solid image.
+ * For masks, Alpha must be 'none'.
+ */
+ bool ImageMask;
+ /*
+ * Define whether to expand each destination pixel, to make
+ * masked characters look better. Only used for masks.
+ */
+ bool adjust;
+ /*
+ * Define whether there is an additional component providing
+ * alpha information for each pixel, in addition to the
+ * components implied by the color space.
+ */
+ gs_image_alpha_t Alpha;
+} gs_image1_t;
+
+/*
+ * In standard PostScript Level 1 and 2, this is the only defined ImageType.
+ */
+typedef gs_image1_t gs_image_t;
+
+/*
+ * Define procedures for initializing the standard forms of image structures
+ * to default values. Note that because these structures may add more
+ * members in the future, all clients constructing gs_*image*_t values
+ * *must* start by initializing the value by calling one of the following
+ * procedures. Note also that these procedures do not set the image type.
+ */
+void
+ /*
+ * Sets ImageMatrix to the identity matrix.
+ */
+ gs_image_common_t_init(P1(gs_image_common_t * pic)), /*
+ * Also sets Width = Height = 0, BitsPerComponent = 1,
+ * format = chunky, Interpolate = false.
+ * If num_components = N > 0, sets the first N elements of Decode to (0, 1);
+ * if num_components = N < 0, sets the first -N elements of Decode to (1, 0);
+ * if num_components = 0, doesn't set Decode.
+ */
+ gs_data_image_t_init(P2(gs_data_image_t * pim, int num_components)),
+ /*
+ * Also sets CombineWithColor = false, ColorSpace = color_space, Alpha =
+ * none. num_components is obtained from ColorSpace; if ColorSpace =
+ * NULL or ColorSpace is a Pattern space, num_components is taken as 0
+ * (Decode is not initialized).
+ */
+ gs_pixel_image_t_init(P2(gs_pixel_image_t * pim,
+ const gs_color_space * color_space));
+
+/*
+ * Initialize an ImageType 1 image (or imagemask). Also sets ImageMask,
+ * adjust, and Alpha, and the image type. For masks, write_1s = false
+ * paints 0s, write_1s = true paints 1s. This is consistent with the
+ * "polarity" operand of the PostScript imagemask operator.
+ */
+void gs_image_t_init(P2(gs_image_t * pim, const gs_color_space * pcs));
+void gs_image_t_init_mask(P2(gs_image_t * pim, bool write_1s));
+
+/* init_gray and init_color require a (const) imager state. */
+#define gs_image_t_init_gray(pim, pis)\
+ gs_image_t_init(pim, gs_cspace_DeviceGray(pis))
+#define gs_image_t_init_rgb(pim, pis)\
+ gs_image_t_init(pim, gs_cspace_DeviceRGB(pis))
+#define gs_image_t_init_cmyk(pim, pis)\
+ gs_image_t_init(pim, gs_cspace_DeviceCMYK(pis))
+
+/****** REMAINDER OF FILE UNDER CONSTRUCTION. PROCEED AT YOUR OWN RISK. ******/
+
+#if 0
+
+/* ---------------- Services ---------------- */
+
+/*
+ In order to make the driver's life easier, we provide the following callback
+ procedure:
+ */
+
+int gx_map_image_color(P5(gx_device * dev,
+ const gs_image_t * pim,
+ const gx_color_rendering_info * pcri,
+ const uint components[4],
+ gx_drawing_color * pdcolor));
+
+/*
+ Map a source color to a drawing color. The components are simply the pixel
+ component values from the input data, i.e., 1 to 4 B-bit numbers from the
+ source data. Return 0 if the operation succeeded, or a negative error code.
+ */
+
+#endif /*************************************************************** */
+
+#endif /* gsiparam_INCLUDED */
diff --git a/pstoraster/gsiparm2.h b/pstoraster/gsiparm2.h
new file mode 100644
index 000000000..f69875f30
--- /dev/null
+++ b/pstoraster/gsiparm2.h
@@ -0,0 +1,63 @@
+/* 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$ */
+/* ImageType 2 image parameter definition */
+
+#ifndef gsiparm2_INCLUDED
+# define gsiparm2_INCLUDED
+
+#include "gsiparam.h"
+
+/* Opaque type for a path */
+#ifndef gx_path_DEFINED
+# define gx_path_DEFINED
+typedef struct gx_path_s gx_path;
+#endif
+
+/*
+ * See Section 7.1 of the Adobe PostScript Version 3010 Supplement
+ * for a definition of ImageType 2 images.
+ */
+
+typedef struct gs_image2_s {
+ gs_image_common;
+ gs_state *DataSource;
+ float XOrigin, YOrigin;
+ float Width, Height;
+ /*
+ * If UnpaintedPath is not 0, any unpainted path will be appended to it.
+ */
+ gx_path *UnpaintedPath;
+ bool PixelCopy;
+} gs_image2_t;
+
+/*
+ * Initialize an ImageType 2 image. Defaults:
+ * UnpaintedPath = 0
+ * PixelCopy = false
+ */
+void gs_image2_t_init(P1(gs_image2_t * pim));
+
+#endif /* gsiparm2_INCLUDED */
diff --git a/pstoraster/gsiparm3.h b/pstoraster/gsiparm3.h
new file mode 100644
index 000000000..0f5272518
--- /dev/null
+++ b/pstoraster/gsiparm3.h
@@ -0,0 +1,67 @@
+/* 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$ */
+/* LanguageLevel 3 (ImageType 3 & 4) image parameter definition */
+
+#ifndef gsiparm3_INCLUDED
+# define gsiparm3_INCLUDED
+
+#include "gsiparam.h"
+
+/*
+ * See Section 4.3 of the Adobe PostScript Version 3010 Supplement
+ * for a definition of ImageType 3 and 4 images.
+ */
+
+/*
+ * If InterleaveType is 3, the data source for the mask is provided as an
+ * additional data source *before* the data sources for the pixel data. For
+ * both InterleaveType 2 and 3, the client is responsible for always
+ * providing mask data before the pixel data that it masks. (The
+ * implementation does not currently check this, but it should.)
+ */
+typedef enum {
+ interleave_chunky = 1,
+ interleave_scan_lines = 2,
+ interleave_separate_source = 3
+} gs_image3_interleave_type_t;
+typedef struct gs_image3_s {
+ gs_pixel_image_common; /* DataDict */
+ int InterleaveType;
+ gs_data_image_t MaskDict;
+} gs_image3_t;
+
+/* We export the GC descriptor because ImageType 4 subclasses it. */
+#define public_st_gs_image3() /* in gximage3.c */\
+ gs_public_st_suffix_add0(st_gs_image3, gs_image3_t, "gs_image3_t",\
+ image3_enum_ptrs, image3_reloc_ptrs, st_gs_pixel_image)
+
+/*
+ * Initialize an ImageType 3 image.
+ */
+void gs_image3_t_init(P3(gs_image3_t * pim, const gs_color_space * color_space,
+ gs_image3_interleave_type_t interleave_type));
+
+#endif /* gsiparm3_INCLUDED */
diff --git a/pstoraster/gsiparm4.h b/pstoraster/gsiparm4.h
new file mode 100644
index 000000000..6b9103cce
--- /dev/null
+++ b/pstoraster/gsiparm4.h
@@ -0,0 +1,59 @@
+/* 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$ */
+/* ImageType 4 image parameter definition */
+
+#ifndef gsiparm4_INCLUDED
+# define gsiparm4_INCLUDED
+
+#include "gsiparam.h"
+
+/*
+ * See Section 4.3 of the Adobe PostScript Version 3010 Supplement
+ * for a definition of ImageType 4 images.
+ */
+
+typedef struct gs_image4_s {
+ gs_pixel_image_common;
+ /*
+ * If MaskColor_is_range is false, the first N elements of
+ * MaskColor are sample values; if MaskColor_is_range is true,
+ * the first 2*N elements are ranges of sample values.
+ *
+ * Currently, the largest sample values supported by the library are 12
+ * bits, but eventually we want to support DevicePixel images with
+ * samples up to 32 bits as well.
+ */
+ bool MaskColor_is_range;
+ uint MaskColor[gs_image_max_components * 2];
+} gs_image4_t;
+
+/*
+ * Initialize an ImageType 4 image. Defaults:
+ * MaskColor_is_range = false
+ */
+void gs_image4_t_init(P2(gs_image4_t * pim, const gs_color_space * color_space));
+
+#endif /* gsiparm4_INCLUDED */
diff --git a/pstoraster/gsjconf.h b/pstoraster/gsjconf.h
new file mode 100644
index 000000000..758aceed6
--- /dev/null
+++ b/pstoraster/gsjconf.h
@@ -0,0 +1,81 @@
+/* Copyright (C) 1994, 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$ */
+/* jconfig.h file for Independent JPEG Group code */
+
+#ifndef gsjconf_INCLUDED
+# define gsjconf_INCLUDED
+
+/*
+ * We should have the following here:
+
+ #include "stdpre.h"
+
+ * But because of the directory structure used to build the IJG library, we
+ * actually concatenate stdpre.h on the front of this file instead to
+ * construct the jconfig.h file used for the compilation.
+ */
+
+#include "arch.h"
+
+/* See IJG's jconfig.doc for the contents of this file. */
+
+#ifdef __PROTOTYPES__
+# define HAVE_PROTOTYPES
+#endif
+
+#define HAVE_UNSIGNED_CHAR
+#define HAVE_UNSIGNED_SHORT
+#undef CHAR_IS_UNSIGNED
+
+#ifdef __STDC__ /* is this right? */
+# define HAVE_STDDEF_H
+# define HAVE_STDLIB_H
+#endif
+
+#undef NEED_BSD_STRINGS /* WRONG */
+#undef NEED_SYS_TYPES_H /* WRONG */
+#undef NEED_FAR_POINTERS
+#undef NEED_SHORT_EXTERNAL_NAMES
+
+#undef INCOMPLETE_TYPES_BROKEN
+
+/* The following is documented in jmemsys.h, not jconfig.doc. */
+#if arch_ints_are_short
+# undef MAX_ALLOC_CHUNK
+# define MAX_ALLOC_CHUNK 0xfff0
+#endif
+
+#ifdef JPEG_INTERNALS
+
+#if arch_arith_rshift == 0
+# define RIGHT_SHIFT_IS_UNSIGNED
+#else
+# undef RIGHT_SHIFT_IS_UNSIGNED
+#endif
+
+#endif /* JPEG_INTERNALS */
+
+#endif /* gsjconf_INCLUDED */
diff --git a/pstoraster/gsjmorec.h b/pstoraster/gsjmorec.h
new file mode 100644
index 000000000..8ddac547a
--- /dev/null
+++ b/pstoraster/gsjmorec.h
@@ -0,0 +1,59 @@
+/* Copyright (C) 1994, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of GNU Ghostscript.
+
+ GNU Ghostscript is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
+ to anyone for the consequences of using it or for whether it serves any
+ particular purpose or works at all, unless he says so in writing. Refer
+ to the GNU General Public License for full details.
+
+ Everyone is granted permission to copy, modify and redistribute GNU
+ Ghostscript, but only under the conditions described in the GNU General
+ Public License. A copy of this license is supposed to have been given
+ to you along with GNU Ghostscript so you can know your rights and
+ responsibilities. It should be in a file named COPYING. Among other
+ things, the copyright notice and this notice must be preserved on all
+ copies.
+
+ Aladdin Enterprises 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 Independent JPEG Group code jmorecfg.h */
+
+#ifndef gsjmorec_INCLUDED
+# define gsjmorec_INCLUDED
+
+#include "jmcorig.h"
+
+/* Remove unwanted / unneeded features. */
+#undef DCT_IFAST_SUPPORTED
+#if FPU_TYPE <= 0
+# undef DCT_FLOAT_SUPPORTED
+#endif
+#undef C_MULTISCAN_FILES_SUPPORTED
+#undef C_PROGRESSIVE_SUPPORTED
+#undef ENTROPY_OPT_SUPPORTED
+#undef INPUT_SMOOTHING_SUPPORTED
+
+/****** Comment out the next two lines to add progressive decoding. ******/
+#undef D_MULTISCAN_FILES_SUPPORTED
+#undef D_PROGRESSIVE_SUPPORTED
+
+#undef BLOCK_SMOOTHING_SUPPORTED
+#undef IDCT_SCALING_SUPPORTED
+#undef UPSAMPLE_SCALING_SUPPORTED
+#undef UPSAMPLE_MERGING_SUPPORTED
+#undef QUANT_1PASS_SUPPORTED
+#undef QUANT_2PASS_SUPPORTED
+/*
+ * Read "JPEG" files with up to 64 blocks/MCU for Adobe compatibility.
+ * Note that this #define will have no effect in pre-v6 IJG versions.
+ */
+#define D_MAX_BLOCKS_IN_MCU 64
+
+#endif /* gsjmorec_INCLUDED */
diff --git a/pstoraster/gslib.h b/pstoraster/gslib.h
new file mode 100644
index 000000000..bb33e9fd7
--- /dev/null
+++ b/pstoraster/gslib.h
@@ -0,0 +1,44 @@
+/* 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$ */
+/* Requires stdio.h, gsmemory.h */
+
+#ifndef gslib_INCLUDED
+# define gslib_INCLUDED
+
+/*
+ * Initialize the library. gs_lib_init does all of the initialization,
+ * using the C heap for initial allocation; if a client wants the library to
+ * use a different default allocator during initialization, it should call
+ * gs_lib_init0 and then gs_lib_init1.
+ */
+void gs_lib_init(P1(FILE * debug_out));
+gs_memory_t *gs_lib_init0(P1(FILE * debug_out));
+void gs_lib_init1(P1(gs_memory_t *));
+
+/* Clean up after execution. */
+void gs_lib_finit(P2(int exit_status, int code));
+
+#endif /* gslib_INCLUDED */
diff --git a/pstoraster/gsline.c b/pstoraster/gsline.c
new file mode 100644
index 000000000..e6bfdf372
--- /dev/null
+++ b/pstoraster/gsline.c
@@ -0,0 +1,340 @@
+/* Copyright (C) 1989, 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$ */
+/* Line parameter operators for Ghostscript library */
+#include "math_.h"
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gxfixed.h" /* ditto */
+#include "gxmatrix.h" /* for gzstate */
+#include "gzstate.h"
+#include "gsline.h" /* for prototypes */
+#include "gzline.h"
+
+/* ------ Device-independent parameters ------ */
+
+#define pgs_lp gs_currentlineparams_inline(pgs)
+
+/* setlinewidth */
+int
+gs_setlinewidth(gs_state * pgs, floatp width)
+{
+ gx_set_line_width(pgs_lp, width);
+ return 0;
+}
+
+/* currentlinewidth */
+float
+gs_currentlinewidth(const gs_state * pgs)
+{
+ return gx_current_line_width(pgs_lp);
+}
+
+/* setlinecap */
+int
+gs_setlinecap(gs_state * pgs, gs_line_cap cap)
+{
+ if ((uint) cap > gs_line_cap_max)
+ return_error(gs_error_rangecheck);
+ pgs_lp->cap = cap;
+ return 0;
+}
+
+/* currentlinecap */
+gs_line_cap
+gs_currentlinecap(const gs_state * pgs)
+{
+ return pgs_lp->cap;
+}
+
+/* setlinejoin */
+int
+gs_setlinejoin(gs_state * pgs, gs_line_join join)
+{
+ if ((uint) join > gs_line_join_max)
+ return_error(gs_error_rangecheck);
+ pgs_lp->join = join;
+ return 0;
+}
+
+/* currentlinejoin */
+gs_line_join
+gs_currentlinejoin(const gs_state * pgs)
+{
+ return pgs_lp->join;
+}
+
+/* setmiterlimit */
+int
+gx_set_miter_limit(gx_line_params * plp, floatp limit)
+{
+ if (limit < 1.0)
+ return_error(gs_error_rangecheck);
+ plp->miter_limit = limit;
+ /*
+ * Compute the miter check value. The supplied miter limit is an
+ * upper bound on 1/sin(phi/2); we convert this to a lower bound on
+ * tan(phi). Note that if phi > pi/2, this is negative. We use the
+ * half-angle and angle-sum formulas here to avoid the trig functions.
+ * We also need a special check for phi/2 close to pi/4.
+ * Some C compilers can't handle this as a conditional expression....
+ */
+ {
+ double limit_squared = limit * limit;
+
+ if (limit_squared < 2.0001 && limit_squared > 1.9999)
+ plp->miter_check = 1.0e6;
+ else
+ plp->miter_check =
+ sqrt(limit_squared - 1) * 2 / (limit_squared - 2);
+ }
+ return 0;
+}
+int
+gs_setmiterlimit(gs_state * pgs, floatp limit)
+{
+ return gx_set_miter_limit(pgs_lp, limit);
+}
+
+/* currentmiterlimit */
+float
+gs_currentmiterlimit(const gs_state * pgs)
+{
+ return pgs_lp->miter_limit;
+}
+
+/* setdash */
+int
+gx_set_dash(gx_dash_params * dash, const float *pattern, uint length,
+ floatp offset, gs_memory_t * mem)
+{
+ uint n = length;
+ const float *dfrom = pattern;
+ bool ink = true;
+ int index = 0;
+ float pattern_length = 0.0;
+ float dist_left;
+ float *ppat = dash->pattern;
+
+ /* Check the dash pattern. */
+ while (n--) {
+ float elt = *dfrom++;
+
+ if (elt < 0)
+ return_error(gs_error_rangecheck);
+ pattern_length += elt;
+ }
+ if (length == 0) { /* empty pattern */
+ dist_left = 0.0;
+ if (mem && ppat) {
+ gs_free_object(mem, ppat, "gx_set_dash(old pattern)");
+ ppat = 0;
+ }
+ } else {
+ uint size = length * sizeof(float);
+
+ if (pattern_length == 0)
+ return_error(gs_error_rangecheck);
+ /* Compute the initial index, ink_on, and distance left */
+ /* in the pattern, according to the offset. */
+#define f_mod(a, b) ((a) - floor((a) / (b)) * (b))
+ if (length & 1) { /* Odd and even repetitions of the pattern */
+ /* have opposite ink values! */
+ float length2 = pattern_length * 2;
+
+ dist_left = f_mod(offset, length2);
+ if (dist_left >= pattern_length)
+ dist_left -= pattern_length, ink = !ink;
+ } else
+ dist_left = f_mod(offset, pattern_length);
+ while ((dist_left -= pattern[index]) >= 0 &&
+ (dist_left > 0 || pattern[index] != 0)
+ )
+ ink = !ink, index++;
+ if (mem) {
+ if (ppat == 0)
+ ppat = (float *)gs_alloc_bytes(mem, size,
+ "gx_set_dash(pattern)");
+ else if (length != dash->pattern_size)
+ ppat = gs_resize_object(mem, ppat, size,
+ "gx_set_dash(pattern)");
+ if (ppat == 0)
+ return_error(gs_error_VMerror);
+ }
+ memcpy(ppat, pattern, length * sizeof(float));
+ }
+ dash->pattern = ppat;
+ dash->pattern_size = length;
+ dash->offset = offset;
+ dash->pattern_length = pattern_length;
+ dash->init_ink_on = ink;
+ dash->init_index = index;
+ dash->init_dist_left = -dist_left;
+ return 0;
+}
+int
+gs_setdash(gs_state * pgs, const float *pattern, uint length, floatp offset)
+{
+ return gx_set_dash(&pgs_lp->dash, pattern, length, offset,
+ pgs->memory);
+}
+
+/* currentdash */
+uint
+gs_currentdash_length(const gs_state * pgs)
+{
+ return pgs_lp->dash.pattern_size;
+}
+const float *
+gs_currentdash_pattern(const gs_state * pgs)
+{
+ return pgs_lp->dash.pattern;
+}
+float
+gs_currentdash_offset(const gs_state * pgs)
+{
+ return pgs_lp->dash.offset;
+}
+
+/* Internal accessor for line parameters */
+const gx_line_params *
+gs_currentlineparams(const gs_imager_state * pis)
+{
+ return gs_currentlineparams_inline(pis);
+}
+
+/* ------ Device-dependent parameters ------ */
+
+/* setflat */
+int
+gs_imager_setflat(gs_imager_state * pis, floatp flat)
+{
+ if (flat <= 0.2)
+ flat = 0.2;
+ else if (flat > 100)
+ flat = 100;
+ pis->flatness = flat;
+ return 0;
+}
+int
+gs_setflat(gs_state * pgs, floatp flat)
+{
+ return gs_imager_setflat((gs_imager_state *) pgs, flat);
+}
+
+/* currentflat */
+float
+gs_currentflat(const gs_state * pgs)
+{
+ return pgs->flatness;
+}
+
+/* setstrokeadjust */
+int
+gs_setstrokeadjust(gs_state * pgs, bool stroke_adjust)
+{
+ pgs->stroke_adjust = stroke_adjust;
+ return 0;
+}
+
+/* currentstrokeadjust */
+bool
+gs_currentstrokeadjust(const gs_state * pgs)
+{
+ return pgs->stroke_adjust;
+}
+
+/* ------ Extensions ------ */
+
+/* Device-independent */
+
+/* setdashadapt */
+void
+gs_setdashadapt(gs_state * pgs, bool adapt)
+{
+ pgs_lp->dash.adapt = adapt;
+}
+
+/* currentdashadapt */
+bool
+gs_imager_currentdashadapt(const gs_imager_state * pis)
+{
+ return gs_currentlineparams_inline(pis)->dash.adapt;
+}
+bool
+gs_currentdashadapt(const gs_state * pgs)
+{
+ return gs_imager_currentdashadapt((const gs_imager_state *)pgs);
+}
+
+/* Device-dependent */
+
+/* setaccuratecurves */
+void
+gs_setaccuratecurves(gs_state * pgs, bool accurate)
+{
+ pgs->accurate_curves = accurate;
+}
+
+/* currentaccuratecurves */
+bool
+gs_imager_currentaccuratecurves(const gs_imager_state * pis)
+{
+ return pis->accurate_curves;
+}
+bool
+gs_currentaccuratecurves(const gs_state * pgs)
+{
+ return gs_imager_currentaccuratecurves((const gs_imager_state *)pgs);
+}
+
+/* setdotlength */
+int
+gx_set_dot_length(gx_line_params * plp, floatp length, bool absolute)
+{
+ if (length < 0)
+ return_error(gs_error_rangecheck);
+ plp->dot_length = length;
+ plp->dot_length_absolute = absolute;
+ return 0;
+}
+int
+gs_setdotlength(gs_state * pgs, floatp length, bool absolute)
+{
+ return gx_set_dot_length(pgs_lp, length, absolute);
+}
+
+/* currentdotlength */
+float
+gs_currentdotlength(const gs_state * pgs)
+{
+ return pgs_lp->dot_length;
+}
+bool
+gs_currentdotlength_absolute(const gs_state * pgs)
+{
+ return pgs_lp->dot_length_absolute;
+}
diff --git a/pstoraster/gsline.h b/pstoraster/gsline.h
new file mode 100644
index 000000000..00e06bd81
--- /dev/null
+++ b/pstoraster/gsline.h
@@ -0,0 +1,75 @@
+/* Copyright (C) 1994, 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$ */
+/* Line parameter and quality definitions */
+
+#ifndef gsline_INCLUDED
+# define gsline_INCLUDED
+
+#include "gslparam.h"
+
+/* Procedures */
+int gs_setlinewidth(P2(gs_state *, floatp));
+float gs_currentlinewidth(P1(const gs_state *));
+int gs_setlinecap(P2(gs_state *, gs_line_cap));
+
+gs_line_cap
+gs_currentlinecap(P1(const gs_state *));
+int gs_setlinejoin(P2(gs_state *, gs_line_join));
+
+gs_line_join
+gs_currentlinejoin(P1(const gs_state *));
+int gs_setmiterlimit(P2(gs_state *, floatp));
+float gs_currentmiterlimit(P1(const gs_state *));
+int gs_setdash(P4(gs_state *, const float *, uint, floatp));
+uint gs_currentdash_length(P1(const gs_state *));
+const float *
+ gs_currentdash_pattern(P1(const gs_state *));
+float gs_currentdash_offset(P1(const gs_state *));
+int gs_setflat(P2(gs_state *, floatp));
+float gs_currentflat(P1(const gs_state *));
+int gs_setstrokeadjust(P2(gs_state *, bool));
+bool gs_currentstrokeadjust(P1(const gs_state *));
+
+/* Extensions */
+void gs_setaccuratecurves(P2(gs_state *, bool));
+bool gs_currentaccuratecurves(P1(const gs_state *));
+void gs_setdashadapt(P2(gs_state *, bool));
+bool gs_currentdashadapt(P1(const gs_state *));
+int gs_setdotlength(P3(gs_state *, floatp, bool));
+float gs_currentdotlength(P1(const gs_state *));
+bool gs_currentdotlength_absolute(P1(const gs_state *));
+
+/* Imager-level procedures */
+#ifndef gs_imager_state_DEFINED
+# define gs_imager_state_DEFINED
+typedef struct gs_imager_state_s gs_imager_state;
+
+#endif
+int gs_imager_setflat(P2(gs_imager_state *, floatp));
+bool gs_imager_currentdashadapt(P1(const gs_imager_state *));
+bool gs_imager_currentaccuratecurves(P1(const gs_imager_state *));
+
+#endif /* gsline_INCLUDED */
diff --git a/pstoraster/gslparam.h b/pstoraster/gslparam.h
new file mode 100644
index 000000000..17ae76488
--- /dev/null
+++ b/pstoraster/gslparam.h
@@ -0,0 +1,52 @@
+/* Copyright (C) 1995, 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$ */
+/* Line parameter definitions */
+
+#ifndef gslparam_INCLUDED
+# define gslparam_INCLUDED
+
+/* Line cap values */
+typedef enum {
+ gs_cap_butt = 0,
+ gs_cap_round = 1,
+ gs_cap_square = 2,
+ gs_cap_triangle = 3 /* not supported by PostScript */
+} gs_line_cap;
+
+#define gs_line_cap_max 3
+
+/* Line join values */
+typedef enum {
+ gs_join_miter = 0,
+ gs_join_round = 1,
+ gs_join_bevel = 2,
+ gs_join_none = 3, /* not supported by PostScript */
+ gs_join_triangle = 4 /* not supported by PostScript */
+} gs_line_join;
+
+#define gs_line_join_max 4
+
+#endif /* gslparam_INCLUDED */
diff --git a/pstoraster/gsmalloc.c b/pstoraster/gsmalloc.c
new file mode 100644
index 000000000..146576783
--- /dev/null
+++ b/pstoraster/gsmalloc.c
@@ -0,0 +1,398 @@
+/* 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$ */
+/* C heap allocator */
+#include "malloc_.h"
+#include "gdebug.h"
+#include "gstypes.h"
+#include "gsmemory.h"
+#include "gsmdebug.h"
+#include "gsstruct.h" /* for st_bytes */
+#include "gsmalloc.h"
+
+/* ------ Heap allocator ------ */
+
+/*
+ * An implementation of Ghostscript's memory manager interface
+ * that works directly with the C heap. We keep track of all allocated
+ * blocks so we can free them at cleanup time.
+ */
+/* Raw memory procedures */
+private gs_memory_proc_alloc_bytes(gs_heap_alloc_bytes);
+private gs_memory_proc_resize_object(gs_heap_resize_object);
+private gs_memory_proc_free_object(gs_heap_free_object);
+private gs_memory_proc_status(gs_heap_status);
+private gs_memory_proc_free_all(gs_heap_free_all);
+
+/* Object memory procedures */
+private gs_memory_proc_alloc_struct(gs_heap_alloc_struct);
+private gs_memory_proc_alloc_byte_array(gs_heap_alloc_byte_array);
+private gs_memory_proc_alloc_struct_array(gs_heap_alloc_struct_array);
+private gs_memory_proc_object_size(gs_heap_object_size);
+private gs_memory_proc_object_type(gs_heap_object_type);
+private gs_memory_proc_alloc_string(gs_heap_alloc_string);
+private gs_memory_proc_resize_string(gs_heap_resize_string);
+private gs_memory_proc_free_string(gs_heap_free_string);
+private gs_memory_proc_register_root(gs_heap_register_root);
+private gs_memory_proc_unregister_root(gs_heap_unregister_root);
+private gs_memory_proc_enable_free(gs_heap_enable_free);
+private const gs_memory_procs_t gs_malloc_memory_procs =
+{
+ /* Raw memory procedures */
+ gs_heap_alloc_bytes,
+ gs_heap_resize_object,
+ gs_heap_free_object,
+ gs_heap_status,
+ gs_heap_free_all,
+ gs_ignore_consolidate_free,
+ /* Object memory procedures */
+ gs_heap_alloc_bytes,
+ gs_heap_alloc_struct,
+ gs_heap_alloc_struct,
+ gs_heap_alloc_byte_array,
+ gs_heap_alloc_byte_array,
+ gs_heap_alloc_struct_array,
+ gs_heap_alloc_struct_array,
+ gs_heap_object_size,
+ gs_heap_object_type,
+ gs_heap_alloc_string,
+ gs_heap_alloc_string,
+ gs_heap_resize_string,
+ gs_heap_free_string,
+ gs_heap_register_root,
+ gs_heap_unregister_root,
+ gs_heap_enable_free
+};
+
+/* We must make sure that malloc_blocks leave the block aligned. */
+/*typedef struct gs_malloc_block_s gs_malloc_block_t; */
+#define malloc_block_data\
+ gs_malloc_block_t *next;\
+ gs_malloc_block_t *prev;\
+ uint size;\
+ gs_memory_type_ptr_t type;\
+ client_name_t cname
+struct malloc_block_data_s {
+ malloc_block_data;
+};
+struct gs_malloc_block_s {
+ malloc_block_data;
+/* ANSI C does not allow zero-size arrays, so we need the following */
+/* unnecessary and wasteful workaround: */
+#define _npad (-size_of(struct malloc_block_data_s) & 7)
+ byte _pad[(_npad == 0 ? 8 : _npad)]; /* pad to double */
+#undef _npad
+};
+
+/* Define the default allocator. */
+gs_malloc_memory_t *gs_malloc_memory_default;
+
+/* Initialize a malloc allocator. */
+private long heap_available(P0());
+gs_malloc_memory_t *
+gs_malloc_memory_init(void)
+{
+ gs_malloc_memory_t *mem = calloc(1, sizeof(gs_malloc_memory_t));
+
+ mem->procs = gs_malloc_memory_procs;
+ mem->allocated = 0;
+ mem->limit = max_long;
+ mem->used = 0;
+ mem->max_used = 0;
+ return mem;
+}
+/*
+ * Estimate the amount of available memory by probing with mallocs.
+ * We may under-estimate by a lot, but that's better than winding up with
+ * a seriously inflated address space. This is quite a hack!
+ */
+#define max_malloc_probes 20
+#define malloc_probe_size 64000
+private long
+heap_available(void)
+{
+ long avail = 0;
+ void *probes[max_malloc_probes];
+ uint n;
+
+ for (n = 0; n < max_malloc_probes; n++) {
+ if ((probes[n] = malloc(malloc_probe_size)) == 0)
+ break;
+ if_debug2('a', "[a]heap_available probe[%d]=0x%lx\n",
+ n, (ulong) probes[n]);
+ avail += malloc_probe_size;
+ }
+ while (n)
+ free(probes[--n]);
+ return avail;
+}
+
+/* Allocate various kinds of blocks. */
+private byte *
+gs_heap_alloc_bytes(gs_memory_t * mem, uint size, client_name_t cname)
+{
+ gs_malloc_memory_t *mmem = (gs_malloc_memory_t *) mem;
+ byte *ptr = 0;
+
+#ifdef DEBUG
+ const char *msg;
+ static const char *const ok_msg = "OK";
+
+# define set_msg(str) (msg = (str))
+#else
+# define set_msg(str) DO_NOTHING
+#endif
+
+ if (size > mmem->limit - sizeof(gs_malloc_block_t)) {
+ /* Definitely too large to allocate; also avoids overflow. */
+ set_msg("exceeded limit");
+ } else {
+ uint added = size + sizeof(gs_malloc_block_t);
+
+ if (mmem->limit - added < mmem->used)
+ set_msg("exceeded limit");
+ else if ((ptr = (byte *) calloc(1, added)) == 0)
+ set_msg("failed");
+ else {
+ gs_malloc_block_t *bp = (gs_malloc_block_t *) ptr;
+
+ if (mmem->allocated)
+ mmem->allocated->prev = bp;
+ bp->next = mmem->allocated;
+ bp->prev = 0;
+ bp->size = size;
+ bp->type = &st_bytes;
+ bp->cname = cname;
+ mmem->allocated = bp;
+ set_msg(ok_msg);
+ ptr = (byte *) (bp + 1);
+ gs_alloc_fill(ptr, gs_alloc_fill_alloc, size);
+ mmem->used += size + sizeof(gs_malloc_block_t);
+ if (mmem->used > mmem->max_used)
+ mmem->max_used = mmem->used;
+ }
+ }
+#ifdef DEBUG
+ if (gs_debug_c('a') || msg != ok_msg)
+ dlprintf4("[a+]gs_malloc(%s)(%u) = 0x%lx: %s\n",
+ client_name_string(cname), size, (ulong) ptr, msg);
+#endif
+ return ptr;
+#undef set_msg
+}
+private void *
+gs_heap_alloc_struct(gs_memory_t * mem, gs_memory_type_ptr_t pstype,
+ client_name_t cname)
+{
+ void *ptr =
+ gs_heap_alloc_bytes(mem, gs_struct_type_size(pstype), cname);
+
+ if (ptr == 0)
+ return 0;
+ ((gs_malloc_block_t *) ptr)[-1].type = pstype;
+ return ptr;
+}
+private byte *
+gs_heap_alloc_byte_array(gs_memory_t * mem, uint num_elements, uint elt_size,
+ client_name_t cname)
+{
+ ulong lsize = (ulong) num_elements * elt_size;
+
+ if (lsize != (uint) lsize)
+ return 0;
+ return gs_heap_alloc_bytes(mem, (uint) lsize, cname);
+}
+private void *
+gs_heap_alloc_struct_array(gs_memory_t * mem, uint num_elements,
+ gs_memory_type_ptr_t pstype, client_name_t cname)
+{
+ void *ptr =
+ gs_heap_alloc_byte_array(mem, num_elements,
+ gs_struct_type_size(pstype), cname);
+
+ if (ptr == 0)
+ return 0;
+ ((gs_malloc_block_t *) ptr)[-1].type = pstype;
+ return ptr;
+}
+private void *
+gs_heap_resize_object(gs_memory_t * mem, void *obj, uint new_num_elements,
+ client_name_t cname)
+{
+ gs_malloc_memory_t *mmem = (gs_malloc_memory_t *) mem;
+ gs_malloc_block_t *ptr = (gs_malloc_block_t *) obj - 1;
+ gs_memory_type_ptr_t pstype = ptr->type;
+ uint old_size = gs_object_size(mem, obj) + sizeof(gs_malloc_block_t);
+ uint new_size =
+ gs_struct_type_size(pstype) * new_num_elements +
+ sizeof(gs_malloc_block_t);
+ gs_malloc_block_t *new_ptr =
+ (gs_malloc_block_t *) gs_realloc(ptr, old_size, new_size);
+
+ if (new_ptr == 0)
+ return 0;
+ if (new_ptr->prev)
+ new_ptr->prev->next = new_ptr;
+ else
+ mmem->allocated = new_ptr;
+ if (new_ptr->next)
+ new_ptr->next->prev = new_ptr;
+ new_ptr->size = new_size - sizeof(gs_malloc_block_t);
+ mmem->used -= old_size;
+ mmem->used += new_size;
+ if (new_size > old_size)
+ gs_alloc_fill((byte *) new_ptr + old_size,
+ gs_alloc_fill_alloc, new_size - old_size);
+ return new_ptr + 1;
+}
+private uint
+gs_heap_object_size(gs_memory_t * mem, const void *ptr)
+{
+ return ((const gs_malloc_block_t *)ptr)[-1].size;
+}
+private gs_memory_type_ptr_t
+gs_heap_object_type(gs_memory_t * mem, const void *ptr)
+{
+ return ((const gs_malloc_block_t *)ptr)[-1].type;
+}
+private void
+gs_heap_free_object(gs_memory_t * mem, void *ptr, client_name_t cname)
+{
+ gs_malloc_memory_t *mmem = (gs_malloc_memory_t *) mem;
+ gs_malloc_block_t *bp = mmem->allocated;
+
+ if_debug3('a', "[a-]gs_free(%s) 0x%lx(%u)\n",
+ client_name_string(cname), (ulong) ptr,
+ (ptr == 0 ? 0 : ((gs_malloc_block_t *) ptr)[-1].size));
+ if (ptr == 0)
+ return;
+ if (ptr == bp + 1) {
+ mmem->allocated = bp->next;
+ mmem->used -= bp->size + sizeof(gs_malloc_block_t);
+
+ if (mmem->allocated)
+ mmem->allocated->prev = 0;
+ gs_alloc_fill(bp, gs_alloc_fill_free,
+ bp->size + sizeof(gs_malloc_block_t));
+ free(bp);
+ } else {
+ gs_malloc_block_t *np;
+
+ /*
+ * bp == 0 at this point is an error, but we'd rather have an
+ * error message than an invalid access.
+ */
+ if (bp) {
+ for (; (np = bp->next) != 0; bp = np) {
+ if (ptr == np + 1) {
+ bp->next = np->next;
+ if (np->next)
+ np->next->prev = bp;
+ mmem->used -= np->size + sizeof(gs_malloc_block_t);
+ gs_alloc_fill(np, gs_alloc_fill_free,
+ np->size + sizeof(gs_malloc_block_t));
+ free(np);
+ return;
+ }
+ }
+ }
+ lprintf2("%s: free 0x%lx not found!\n",
+ client_name_string(cname), (ulong) ptr);
+ free((char *)((gs_malloc_block_t *) ptr - 1));
+ }
+}
+private byte *
+gs_heap_alloc_string(gs_memory_t * mem, uint nbytes, client_name_t cname)
+{
+ return gs_heap_alloc_bytes(mem, nbytes, cname);
+}
+private byte *
+gs_heap_resize_string(gs_memory_t * mem, byte * data, uint old_num, uint new_num,
+ client_name_t cname)
+{
+ if (gs_heap_object_type(mem, data) != &st_bytes)
+ lprintf2("%s: resizing non-string 0x%lx!\n",
+ client_name_string(cname), (ulong) data);
+ return gs_heap_resize_object(mem, data, new_num, cname);
+}
+private void
+gs_heap_free_string(gs_memory_t * mem, byte * data, uint nbytes,
+ client_name_t cname)
+{
+ /****** SHOULD CHECK SIZE IF DEBUGGING ******/
+ gs_heap_free_object(mem, data, cname);
+}
+private int
+gs_heap_register_root(gs_memory_t * mem, gs_gc_root_t * rp,
+ gs_ptr_type_t ptype, void **up, client_name_t cname)
+{
+ return 0;
+}
+private void
+gs_heap_unregister_root(gs_memory_t * mem, gs_gc_root_t * rp,
+ client_name_t cname)
+{
+}
+private void
+gs_heap_status(gs_memory_t * mem, gs_memory_status_t * pstat)
+{
+ gs_malloc_memory_t *mmem = (gs_malloc_memory_t *) mem;
+
+ pstat->allocated = mmem->used + heap_available();
+ pstat->used = mmem->used;
+}
+private void
+gs_heap_enable_free(gs_memory_t * mem, bool enable)
+{
+ if (enable)
+ mem->procs.free_object = gs_heap_free_object,
+ mem->procs.free_string = gs_heap_free_string;
+ else
+ mem->procs.free_object = gs_ignore_free_object,
+ mem->procs.free_string = gs_ignore_free_string;
+}
+
+/* Release all memory acquired by this allocator. */
+private void
+gs_heap_free_all(gs_memory_t * mem, uint free_mask, client_name_t cname)
+{
+ gs_malloc_memory_t *const mmem = (gs_malloc_memory_t *) mem;
+
+ if (free_mask & FREE_ALL_DATA) {
+ gs_malloc_block_t *bp = mmem->allocated;
+ gs_malloc_block_t *np;
+
+ for (; bp != 0; bp = np) {
+ np = bp->next;
+ if_debug3('a', "[a]gs_heap_free_all(%s) 0x%lx(%u)\n",
+ client_name_string(bp->cname), (ulong) (bp + 1),
+ bp->size);
+ gs_alloc_fill(bp + 1, gs_alloc_fill_free, bp->size);
+ free(bp);
+ }
+ }
+ if (free_mask & FREE_ALL_ALLOCATOR)
+ free(mem);
+}
diff --git a/pstoraster/gsmalloc.h b/pstoraster/gsmalloc.h
new file mode 100644
index 000000000..076580640
--- /dev/null
+++ b/pstoraster/gsmalloc.h
@@ -0,0 +1,78 @@
+/* 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$ */
+/* Client interface to default (C heap) allocator */
+/* Requires gsmemory.h */
+
+#ifndef gsmalloc_INCLUDED
+# define gsmalloc_INCLUDED
+
+/* Define a memory manager that allocates directly from the C heap. */
+typedef struct gs_malloc_block_s gs_malloc_block_t;
+typedef struct gs_malloc_memory_s {
+ gs_memory_common;
+ gs_malloc_block_t *allocated;
+ long limit;
+ long used;
+ long max_used;
+} gs_malloc_memory_t;
+
+/* Allocate and initialize a malloc memory manager. */
+gs_malloc_memory_t *gs_malloc_memory_init(P0());
+
+/* Release all the allocated blocks, and free the memory manager. */
+/* The cast is unfortunate, but unavoidable. */
+#define gs_malloc_memory_release(mem)\
+ gs_memory_free_all((gs_memory_t *)mem, FREE_ALL_EVERYTHING,\
+ "gs_malloc_memory_release")
+
+/*
+ * Define a default allocator that allocates from the C heap.
+ * (We would really like to get rid of this.)
+ */
+extern gs_malloc_memory_t *gs_malloc_memory_default;
+#define gs_memory_default (*(gs_memory_t *)gs_malloc_memory_default)
+
+/*
+ * The following procedures are historical artifacts that we hope to
+ * get rid of someday.
+ */
+#define gs_malloc_init()\
+ (gs_malloc_memory_default = gs_malloc_memory_init())
+#define gs_malloc_release()\
+ (gs_malloc_memory_release(gs_malloc_memory_default),\
+ gs_malloc_memory_default = 0)
+#define gs_malloc(nelts, esize, cname)\
+ (void *)gs_alloc_byte_array(&gs_memory_default, nelts, esize, cname)
+#define gs_free(data, nelts, esize, cname)\
+ gs_free_object(&gs_memory_default, data, cname)
+
+/* Define an accessor for the limit on the total allocated heap space. */
+#define gs_malloc_limit (gs_malloc_memory_default->limit)
+
+/* Define an accessor for the maximum amount ever allocated from the heap. */
+#define gs_malloc_max (gs_malloc_memory_default->max_used)
+
+#endif /* gsmalloc_INCLUDED */
diff --git a/pstoraster/gsmatrix.c b/pstoraster/gsmatrix.c
new file mode 100644
index 000000000..c521558b8
--- /dev/null
+++ b/pstoraster/gsmatrix.c
@@ -0,0 +1,455 @@
+/* Copyright (C) 1989, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of GNU Ghostscript.
+
+ GNU Ghostscript is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
+ to anyone for the consequences of using it or for whether it serves any
+ particular purpose or works at all, unless he says so in writing. Refer
+ to the GNU General Public License for full details.
+
+ Everyone is granted permission to copy, modify and redistribute GNU
+ Ghostscript, but only under the conditions described in the GNU General
+ Public License. A copy of this license is supposed to have been given
+ to you along with GNU Ghostscript so you can know your rights and
+ responsibilities. It should be in a file named COPYING. Among other
+ things, the copyright notice and this notice must be preserved on all
+ copies.
+
+ Aladdin Enterprises 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$ */
+/* Matrix operators for Ghostscript library */
+#include "math_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gxfarith.h"
+#include "gxfixed.h"
+#include "gxmatrix.h"
+
+/* The identity matrix */
+private const gs_matrix gs_identity_matrix =
+{identity_matrix_body};
+
+/* ------ Matrix creation ------ */
+
+/* Create an identity matrix */
+void
+gs_make_identity(gs_matrix * pmat)
+{
+ *pmat = gs_identity_matrix;
+}
+
+/* Create a translation matrix */
+int
+gs_make_translation(floatp dx, floatp dy, gs_matrix * pmat)
+{
+ *pmat = gs_identity_matrix;
+ pmat->tx = dx;
+ pmat->ty = dy;
+ return 0;
+}
+
+/* Create a scaling matrix */
+int
+gs_make_scaling(floatp sx, floatp sy, gs_matrix * pmat)
+{
+ *pmat = gs_identity_matrix;
+ pmat->xx = sx;
+ pmat->yy = sy;
+ return 0;
+}
+
+/* Create a rotation matrix. */
+/* The angle is in degrees. */
+int
+gs_make_rotation(floatp ang, gs_matrix * pmat)
+{
+ gs_sincos_t sincos;
+
+ gs_sincos_degrees(ang, &sincos);
+ pmat->yy = pmat->xx = sincos.cos;
+ pmat->xy = sincos.sin;
+ pmat->yx = -sincos.sin;
+ pmat->tx = pmat->ty = 0.0;
+ return 0;
+}
+
+/* ------ Matrix arithmetic ------ */
+
+/* Multiply two matrices. We should check for floating exceptions, */
+/* but for the moment it's just too awkward. */
+/* Since this is used heavily, we check for shortcuts. */
+int
+gs_matrix_multiply(const gs_matrix * pm1, const gs_matrix * pm2, gs_matrix * pmr)
+{
+ double xx1 = pm1->xx, yy1 = pm1->yy;
+ double tx1 = pm1->tx, ty1 = pm1->ty;
+ double xx2 = pm2->xx, yy2 = pm2->yy;
+ double xy2 = pm2->xy, yx2 = pm2->yx;
+
+ if (is_xxyy(pm1)) {
+ pmr->tx = tx1 * xx2 + pm2->tx;
+ pmr->ty = ty1 * yy2 + pm2->ty;
+ if (is_fzero(xy2))
+ pmr->xy = 0;
+ else
+ pmr->xy = xx1 * xy2,
+ pmr->ty += tx1 * xy2;
+ pmr->xx = xx1 * xx2;
+ if (is_fzero(yx2))
+ pmr->yx = 0;
+ else
+ pmr->yx = yy1 * yx2,
+ pmr->tx += ty1 * yx2;
+ pmr->yy = yy1 * yy2;
+ } else {
+ double xy1 = pm1->xy, yx1 = pm1->yx;
+
+ pmr->xx = xx1 * xx2 + xy1 * yx2;
+ pmr->xy = xx1 * xy2 + xy1 * yy2;
+ pmr->yy = yx1 * xy2 + yy1 * yy2;
+ pmr->yx = yx1 * xx2 + yy1 * yx2;
+ pmr->tx = tx1 * xx2 + ty1 * yx2 + pm2->tx;
+ pmr->ty = tx1 * xy2 + ty1 * yy2 + pm2->ty;
+ }
+ return 0;
+}
+
+/* Invert a matrix. Return gs_error_undefinedresult if not invertible. */
+int
+gs_matrix_invert(const gs_matrix * pm, gs_matrix * pmr)
+{ /* We have to be careful about fetch/store order, */
+ /* because pm might be the same as pmr. */
+ if (is_xxyy(pm)) {
+ if (is_fzero(pm->xx) || is_fzero(pm->yy))
+ return_error(gs_error_undefinedresult);
+ pmr->tx = -(pmr->xx = 1.0 / pm->xx) * pm->tx;
+ pmr->xy = 0.0;
+ pmr->yx = 0.0;
+ pmr->ty = -(pmr->yy = 1.0 / pm->yy) * pm->ty;
+ } else {
+ double det = pm->xx * pm->yy - pm->xy * pm->yx;
+ double mxx = pm->xx, mtx = pm->tx;
+
+ if (det == 0)
+ return_error(gs_error_undefinedresult);
+ pmr->xx = pm->yy / det;
+ pmr->xy = -pm->xy / det;
+ pmr->yx = -pm->yx / det;
+ pmr->yy = mxx / det; /* xx is already changed */
+ pmr->tx = -(mtx * pmr->xx + pm->ty * pmr->yx);
+ pmr->ty = -(mtx * pmr->xy + pm->ty * pmr->yy); /* tx ditto */
+ }
+ return 0;
+}
+
+/* Translate a matrix, possibly in place. */
+int
+gs_matrix_translate(const gs_matrix * pm, floatp dx, floatp dy, gs_matrix * pmr)
+{
+ gs_point trans;
+ int code = gs_distance_transform(dx, dy, pm, &trans);
+
+ if (code < 0)
+ return code;
+ if (pmr != pm)
+ *pmr = *pm;
+ pmr->tx += trans.x;
+ pmr->ty += trans.y;
+ return 0;
+}
+
+/* Scale a matrix, possibly in place. */
+int
+gs_matrix_scale(const gs_matrix * pm, floatp sx, floatp sy, gs_matrix * pmr)
+{
+ pmr->xx = pm->xx * sx;
+ pmr->xy = pm->xy * sx;
+ pmr->yx = pm->yx * sy;
+ pmr->yy = pm->yy * sy;
+ if (pmr != pm) {
+ pmr->tx = pm->tx;
+ pmr->ty = pm->ty;
+ }
+ return 0;
+}
+
+/* Rotate a matrix, possibly in place. The angle is in degrees. */
+int
+gs_matrix_rotate(const gs_matrix * pm, floatp ang, gs_matrix * pmr)
+{
+ double mxx, mxy;
+ gs_sincos_t sincos;
+
+ gs_sincos_degrees(ang, &sincos);
+ mxx = pm->xx, mxy = pm->xy;
+ pmr->xx = sincos.cos * mxx + sincos.sin * pm->yx;
+ pmr->xy = sincos.cos * mxy + sincos.sin * pm->yy;
+ pmr->yx = sincos.cos * pm->yx - sincos.sin * mxx;
+ pmr->yy = sincos.cos * pm->yy - sincos.sin * mxy;
+ if (pmr != pm) {
+ pmr->tx = pm->tx;
+ pmr->ty = pm->ty;
+ }
+ return 0;
+}
+
+/* ------ Coordinate transformations (floating point) ------ */
+
+/* Note that all the transformation routines take separate */
+/* x and y arguments, but return their result in a point. */
+
+/* Transform a point. */
+int
+gs_point_transform(floatp x, floatp y, const gs_matrix * pmat,
+ gs_point * ppt)
+{
+ ppt->x = x * pmat->xx + pmat->tx;
+ ppt->y = y * pmat->yy + pmat->ty;
+ if (!is_fzero(pmat->yx))
+ ppt->x += y * pmat->yx;
+ if (!is_fzero(pmat->xy))
+ ppt->y += x * pmat->xy;
+ return 0;
+}
+
+/* Inverse-transform a point. */
+/* Return gs_error_undefinedresult if the matrix is not invertible. */
+int
+gs_point_transform_inverse(floatp x, floatp y, const gs_matrix * pmat,
+ gs_point * ppt)
+{
+ if (is_xxyy(pmat)) {
+ if (is_fzero(pmat->xx) || is_fzero(pmat->yy))
+ return_error(gs_error_undefinedresult);
+ ppt->x = (x - pmat->tx) / pmat->xx;
+ ppt->y = (y - pmat->ty) / pmat->yy;
+ return 0;
+ } else if (is_xyyx(pmat)) {
+ if (is_fzero(pmat->xy) || is_fzero(pmat->yx))
+ return_error(gs_error_undefinedresult);
+ ppt->x = (y - pmat->ty) / pmat->xy;
+ ppt->y = (x - pmat->tx) / pmat->yx;
+ return 0;
+ } else { /* There are faster ways to do this, */
+ /* but we won't implement one unless we have to. */
+ gs_matrix imat;
+ int code = gs_matrix_invert(pmat, &imat);
+
+ if (code < 0)
+ return code;
+ return gs_point_transform(x, y, &imat, ppt);
+ }
+}
+
+/* Transform a distance. */
+int
+gs_distance_transform(floatp dx, floatp dy, const gs_matrix * pmat,
+ gs_point * pdpt)
+{
+ pdpt->x = dx * pmat->xx;
+ pdpt->y = dy * pmat->yy;
+ if (!is_fzero(pmat->yx))
+ pdpt->x += dy * pmat->yx;
+ if (!is_fzero(pmat->xy))
+ pdpt->y += dx * pmat->xy;
+ return 0;
+}
+
+/* Inverse-transform a distance. */
+/* Return gs_error_undefinedresult if the matrix is not invertible. */
+int
+gs_distance_transform_inverse(floatp dx, floatp dy,
+ const gs_matrix * pmat, gs_point * pdpt)
+{
+ if (is_xxyy(pmat)) {
+ if (is_fzero(pmat->xx) || is_fzero(pmat->yy))
+ return_error(gs_error_undefinedresult);
+ pdpt->x = dx / pmat->xx;
+ pdpt->y = dy / pmat->yy;
+ } else if (is_xyyx(pmat)) {
+ if (is_fzero(pmat->xy) || is_fzero(pmat->yx))
+ return_error(gs_error_undefinedresult);
+ pdpt->x = dy / pmat->xy;
+ pdpt->y = dx / pmat->yx;
+ } else {
+ double det = pmat->xx * pmat->yy - pmat->xy * pmat->yx;
+
+ if (det == 0)
+ return_error(gs_error_undefinedresult);
+ pdpt->x = (dx * pmat->yy - dy * pmat->yx) / det;
+ pdpt->y = (dy * pmat->xx - dx * pmat->xy) / det;
+ }
+ return 0;
+}
+
+/* Compute the bounding box of 4 points. */
+int
+gs_points_bbox(const gs_point pts[4], gs_rect * pbox)
+{
+#define assign_min_max(vmin, vmax, v0, v1)\
+ if ( v0 < v1 ) vmin = v0, vmax = v1; else vmin = v1, vmax = v0
+#define assign_min_max_4(vmin, vmax, v0, v1, v2, v3)\
+ { double min01, max01, min23, max23;\
+ assign_min_max(min01, max01, v0, v1);\
+ assign_min_max(min23, max23, v2, v3);\
+ vmin = min(min01, min23);\
+ vmax = max(max01, max23);\
+ }
+ assign_min_max_4(pbox->p.x, pbox->q.x,
+ pts[0].x, pts[1].x, pts[2].x, pts[3].x);
+ assign_min_max_4(pbox->p.y, pbox->q.y,
+ pts[0].y, pts[1].y, pts[2].y, pts[3].y);
+#undef assign_min_max
+#undef assign_min_max_4
+ return 0;
+}
+
+/* Transform or inverse-transform a bounding box. */
+/* Return gs_error_undefinedresult if the matrix is not invertible. */
+private int
+bbox_transform_either_only(const gs_rect * pbox_in, const gs_matrix * pmat,
+ gs_point pts[4],
+ int (*point_xform) (P4(floatp, floatp, const gs_matrix *, gs_point *)))
+{
+ int code;
+
+ if ((code = (*point_xform) (pbox_in->p.x, pbox_in->p.y, pmat, &pts[0])) < 0 ||
+ (code = (*point_xform) (pbox_in->p.x, pbox_in->q.y, pmat, &pts[1])) < 0 ||
+ (code = (*point_xform) (pbox_in->q.x, pbox_in->p.y, pmat, &pts[2])) < 0 ||
+ (code = (*point_xform) (pbox_in->q.x, pbox_in->q.y, pmat, &pts[3])) < 0
+ )
+ DO_NOTHING;
+ return code;
+}
+
+private int
+bbox_transform_either(const gs_rect * pbox_in, const gs_matrix * pmat,
+ gs_rect * pbox_out,
+ int (*point_xform) (P4(floatp, floatp, const gs_matrix *, gs_point *)))
+{
+ int code;
+
+ /*
+ * In principle, we could transform only one point and two
+ * distance vectors; however, because of rounding, we will only
+ * get fully consistent results if we transform all 4 points.
+ * We must compute the max and min after transforming,
+ * since a rotation may be involved.
+ */
+ gs_point pts[4];
+
+ if ((code = bbox_transform_either_only(pbox_in, pmat, pts, point_xform)) < 0)
+ return code;
+ return gs_points_bbox(pts, pbox_out);
+}
+int
+gs_bbox_transform(const gs_rect * pbox_in, const gs_matrix * pmat,
+ gs_rect * pbox_out)
+{
+ return bbox_transform_either(pbox_in, pmat, pbox_out,
+ gs_point_transform);
+}
+int
+gs_bbox_transform_only(const gs_rect * pbox_in, const gs_matrix * pmat,
+ gs_point points[4])
+{
+ return bbox_transform_either_only(pbox_in, pmat, points,
+ gs_point_transform);
+}
+int
+gs_bbox_transform_inverse(const gs_rect * pbox_in, const gs_matrix * pmat,
+ gs_rect * pbox_out)
+{
+ return bbox_transform_either(pbox_in, pmat, pbox_out,
+ gs_point_transform_inverse);
+}
+
+/* ------ Coordinate transformations (to fixed point) ------ */
+
+#define f_fits_in_fixed(f) f_fits_in_bits(f, fixed_int_bits)
+
+/* Transform a point with a fixed-point result. */
+int
+gs_point_transform2fixed(const gs_matrix_fixed * pmat,
+ floatp x, floatp y, gs_fixed_point * ppt)
+{
+ fixed px, py, t;
+ double dtemp;
+ int code;
+
+ if (!pmat->txy_fixed_valid) { /* The translation is out of range. Do the */
+ /* computation in floating point, and convert to */
+ /* fixed at the end. */
+ gs_point fpt;
+
+ gs_point_transform(x, y, (const gs_matrix *)pmat, &fpt);
+ if (!(f_fits_in_fixed(fpt.x) && f_fits_in_fixed(fpt.y)))
+ return_error(gs_error_limitcheck);
+ ppt->x = float2fixed(fpt.x);
+ ppt->y = float2fixed(fpt.y);
+ return 0;
+ }
+ if (!is_fzero(pmat->xy)) { /* Hope for 90 degree rotation */
+ if ((code = set_dfmul2fixed_vars(px, y, pmat->yx, dtemp)) < 0 ||
+ (code = set_dfmul2fixed_vars(py, x, pmat->xy, dtemp)) < 0
+ )
+ return code;
+ if (!is_fzero(pmat->xx)) {
+ if ((code = set_dfmul2fixed_vars(t, x, pmat->xx, dtemp)) < 0)
+ return code;
+ px += t; /* should check for overflow */
+ }
+ if (!is_fzero(pmat->yy)) {
+ if ((code = set_dfmul2fixed_vars(t, y, pmat->yy, dtemp)) < 0)
+ return code;
+ py += t; /* should check for overflow */
+ }
+ } else {
+ if ((code = set_dfmul2fixed_vars(px, x, pmat->xx, dtemp)) < 0 ||
+ (code = set_dfmul2fixed_vars(py, y, pmat->yy, dtemp)) < 0
+ )
+ return code;
+ if (!is_fzero(pmat->yx)) {
+ if ((code = set_dfmul2fixed_vars(t, y, pmat->yx, dtemp)) < 0)
+ return code;
+ px += t; /* should check for overflow */
+ }
+ }
+ ppt->x = px + pmat->tx_fixed; /* should check for overflow */
+ ppt->y = py + pmat->ty_fixed; /* should check for overflow */
+ return 0;
+}
+
+/* Transform a distance with a fixed-point result. */
+int
+gs_distance_transform2fixed(const gs_matrix_fixed * pmat,
+ floatp dx, floatp dy, gs_fixed_point * ppt)
+{
+ fixed px, py, t;
+ double dtemp;
+ int code;
+
+ if ((code = set_dfmul2fixed_vars(px, dx, pmat->xx, dtemp)) < 0 ||
+ (code = set_dfmul2fixed_vars(py, dy, pmat->yy, dtemp)) < 0
+ )
+ return code;
+ if (!is_fzero(pmat->yx)) {
+ if ((code = set_dfmul2fixed_vars(t, dy, pmat->yx, dtemp)) < 0)
+ return code;
+ px += t; /* should check for overflow */
+ }
+ if (!is_fzero(pmat->xy)) {
+ if ((code = set_dfmul2fixed_vars(t, dx, pmat->xy, dtemp)) < 0)
+ return code;
+ py += t; /* should check for overflow */
+ }
+ ppt->x = px;
+ ppt->y = py;
+ return 0;
+}
diff --git a/pstoraster/gsmatrix.h b/pstoraster/gsmatrix.h
new file mode 100644
index 000000000..263c5e05f
--- /dev/null
+++ b/pstoraster/gsmatrix.h
@@ -0,0 +1,80 @@
+/* Copyright (C) 1989, 1995, 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$ */
+/* Definition of matrices and client interface to matrix routines */
+
+#ifndef gsmatrix_INCLUDED
+# define gsmatrix_INCLUDED
+
+/* See p. 65 of the PostScript manual for the semantics of */
+/* transformation matrices. */
+
+/* Structure for a transformation matrix. */
+#define _matrix_body\
+ float xx, xy, yx, yy, tx, ty
+struct gs_matrix_s {
+ _matrix_body;
+};
+
+#ifndef gs_matrix_DEFINED
+# define gs_matrix_DEFINED
+typedef struct gs_matrix_s gs_matrix;
+
+#endif
+/* Macro for initializing constant matrices */
+#define constant_matrix_body(xx, xy, yx, yy, tx, ty)\
+ (float)(xx), (float)(xy), (float)(yx),\
+ (float)(yy), (float)(tx), (float)(ty)
+
+/* Macros for testing whether matrix coefficients are zero, */
+/* for shortcuts when the matrix is simple. */
+#define is_xxyy(pmat) is_fzero2((pmat)->xy, (pmat)->yx)
+#define is_xyyx(pmat) is_fzero2((pmat)->xx, (pmat)->yy)
+
+/* The identity matrix (for structure initialization) */
+#define identity_matrix_body\
+ constant_matrix_body(1, 0, 0, 1, 0, 0)
+
+/* Matrix creation */
+void gs_make_identity(P1(gs_matrix *));
+int gs_make_translation(P3(floatp, floatp, gs_matrix *)), gs_make_scaling(P3(floatp, floatp, gs_matrix *)),
+ gs_make_rotation(P2(floatp, gs_matrix *));
+
+/* Matrix arithmetic */
+int gs_matrix_multiply(P3(const gs_matrix *, const gs_matrix *, gs_matrix *)),
+ gs_matrix_invert(P2(const gs_matrix *, gs_matrix *)), gs_matrix_translate(P4(const gs_matrix *, floatp, floatp, gs_matrix *)),
+ gs_matrix_scale(P4(const gs_matrix *, floatp, floatp, gs_matrix *)),
+ gs_matrix_rotate(P3(const gs_matrix *, floatp, gs_matrix *));
+
+/* Coordinate transformation */
+int gs_point_transform(P4(floatp, floatp, const gs_matrix *, gs_point *)),
+ gs_point_transform_inverse(P4(floatp, floatp, const gs_matrix *, gs_point *)),
+ gs_distance_transform(P4(floatp, floatp, const gs_matrix *, gs_point *)),
+ gs_distance_transform_inverse(P4(floatp, floatp, const gs_matrix *, gs_point *)),
+ gs_points_bbox(P2(const gs_point[4], gs_rect *)), gs_bbox_transform_only(P3(const gs_rect *, const gs_matrix *, gs_point[4])),
+ gs_bbox_transform(P3(const gs_rect *, const gs_matrix *, gs_rect *)),
+ gs_bbox_transform_inverse(P3(const gs_rect *, const gs_matrix *, gs_rect *));
+
+#endif /* gsmatrix_INCLUDED */
diff --git a/pstoraster/gsmdebug.h b/pstoraster/gsmdebug.h
new file mode 100644
index 000000000..467f13136
--- /dev/null
+++ b/pstoraster/gsmdebug.h
@@ -0,0 +1,54 @@
+/* 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$ */
+/* Requires gdebug.h (for gs_debug) */
+
+#ifndef gsmdebug_INCLUDED
+# define gsmdebug_INCLUDED
+
+/* Define the fill patterns used for debugging the allocator. */
+extern byte
+ gs_alloc_fill_alloc, /* allocated but not initialized */
+ gs_alloc_fill_block, /* locally allocated block */
+ gs_alloc_fill_collected, /* garbage collected */
+ gs_alloc_fill_deleted, /* locally deleted block */
+ gs_alloc_fill_free; /* freed */
+
+/* Define an alias for a specialized debugging flag */
+/* that used to be a separate variable. */
+#define gs_alloc_debug gs_debug['@']
+
+/* Conditionally fill unoccupied blocks with a pattern. */
+extern void gs_alloc_memset(P3(void *, int /*byte */ , ulong));
+
+#ifdef DEBUG
+# define gs_alloc_fill(ptr, fill, len)\
+ BEGIN if ( gs_alloc_debug ) gs_alloc_memset(ptr, fill, (ulong)(len)); END
+#else
+# define gs_alloc_fill(ptr, fill, len)\
+ DO_NOTHING
+#endif
+
+#endif /* gsmdebug_INCLUDED */
diff --git a/pstoraster/gsmemlok.h b/pstoraster/gsmemlok.h
new file mode 100644
index 000000000..f49e0d848
--- /dev/null
+++ b/pstoraster/gsmemlok.h
@@ -0,0 +1,64 @@
+/* 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 monitor-locked heap memory allocator */
+
+/* Initial version 2/1/98 by John Desrosiers (soho@crl.com) */
+
+#if !defined(gsmemlok_INCLUDED)
+ #define gsmemlok_INCLUDED
+
+#include "gsmemory.h"
+#include "gxsync.h"
+
+/*
+ * This allocator encapsulates another allocator with a mutex.
+ * Note that it does not keep track of memory that it acquires:
+ * thus free_all with FREE_ALL_DATA is a no-op.
+ */
+
+typedef struct gs_memory_locked_s {
+ gs_memory_common; /* interface outside world sees */
+ gs_memory_t *target; /* allocator to front */
+ gx_monitor_t *monitor; /* monitor to serialize access to functions */
+} gs_memory_locked_t;
+
+/* ---------- Public constructors/destructors ---------- */
+
+/* Initialize a locked memory manager. */
+int gs_memory_locked_init(P2(
+ gs_memory_locked_t * lmem, /* allocator to init */
+ gs_memory_t * target /* allocator to monitor lock */
+ ));
+
+/* Release a locked memory manager. */
+/* Note that this has no effect on the target. */
+#define gs_memory_locked_release(lmem)\
+ gs_memory_free_all(lmem, FREE_STRUCTURES, "gs_memory_locked_release")
+
+/* Get the target of a locked memory manager. */
+gs_memory_t * gs_memory_locked_target(P1(const gs_memory_locked_t *lmem));
+
+#endif /*!defined(gsmemlok_INCLUDED) */
diff --git a/pstoraster/gsmemory.c b/pstoraster/gsmemory.c
new file mode 100644
index 000000000..3012270fa
--- /dev/null
+++ b/pstoraster/gsmemory.c
@@ -0,0 +1,198 @@
+/*
+ Copyright 1993-1999 by Easy Software Products.
+ Copyright 1993, 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 allocator support */
+#include "memory_.h"
+#include "gstypes.h"
+#include "gsmemory.h"
+#include "gsmdebug.h"
+#include "gsrefct.h" /* to check prototype */
+#include "gsstruct.h" /* ditto */
+
+/* Define the fill patterns for unallocated memory. */
+byte gs_alloc_fill_alloc = 0xa1;
+byte gs_alloc_fill_block = 0xb1;
+byte gs_alloc_fill_collected = 0xc1;
+byte gs_alloc_fill_deleted = 0xd1;
+byte gs_alloc_fill_free = 0xf1;
+
+/* A 'structure' type descriptor for free blocks. */
+gs_public_st_simple(st_free, byte, "(free)");
+
+/* The 'structure' type descriptor for bytes. */
+gs_public_st_simple(st_bytes, byte, "bytes");
+
+/* The structure type descriptor for GC roots. */
+public_st_gc_root_t();
+
+/* The descriptors for elements and arrays of const strings. */
+private_st_const_string();
+public_st_const_string_element();
+
+/* Fill an unoccupied block with a pattern. */
+/* Note that the block size may be too large for a single memset. */
+void
+gs_alloc_memset(void *ptr, int /*byte */ fill, ulong lsize)
+{
+ ulong msize = lsize;
+ char *p = ptr;
+ int isize;
+
+ for (; msize; msize -= isize, p += isize) {
+ isize = min(msize, max_int);
+ memset(p, fill, isize);
+ }
+}
+
+/* Allocate a structure using a "raw memory" allocator. */
+void *
+gs_raw_alloc_struct_immovable(gs_raw_memory_t * rmem,
+ gs_memory_type_ptr_t pstype,
+ client_name_t cname)
+{
+ return gs_alloc_bytes_immovable(rmem, gs_struct_type_size(pstype), cname);
+}
+
+/* No-op freeing procedures */
+void
+gs_ignore_free_object(gs_memory_t * mem, void *data, client_name_t cname)
+{
+}
+void
+gs_ignore_free_string(gs_memory_t * mem, byte * data, uint nbytes,
+ client_name_t cname)
+{
+}
+
+/* No-op consolidation procedure */
+void
+gs_ignore_consolidate_free(gs_memory_t *mem)
+{
+}
+
+/* No-op pointer enumeration procedure */
+ENUM_PTRS_BEGIN_PROC(gs_no_struct_enum_ptrs)
+{
+ return 0;
+ ENUM_PTRS_END_PROC
+}
+
+/* No-op pointer relocation procedure */
+RELOC_PTRS_BEGIN(gs_no_struct_reloc_ptrs)
+{
+}
+RELOC_PTRS_END
+
+/* Get the size of a structure from the descriptor. */
+uint
+gs_struct_type_size(gs_memory_type_ptr_t pstype)
+{
+ return pstype->ssize;
+}
+
+/* Get the name of a structure from the descriptor. */
+struct_name_t
+gs_struct_type_name(gs_memory_type_ptr_t pstype)
+{
+ return pstype->sname;
+}
+
+/* Register a structure root. */
+int
+gs_register_struct_root(gs_memory_t *mem, gs_gc_root_t *root,
+ void **pp, client_name_t cname)
+{
+ return gs_register_root(mem, root, ptr_struct_type, pp, cname);
+}
+
+/* Normal freeing routine for reference-counted structures. */
+void
+rc_free_struct_only(gs_memory_t * mem, void *data, client_name_t cname)
+{
+ if (mem != 0)
+ gs_free_object(mem, data, cname);
+}
+
+/* ---------------- Basic-structure GC procedures ---------------- */
+
+/* Enumerate pointers */
+ENUM_PTRS_BEGIN_PROC(basic_enum_ptrs)
+{
+ const gc_struct_data_t *psd = pstype->proc_data;
+
+ if (index < psd->num_ptrs) {
+ const gc_ptr_element_t *ppe = &psd->ptrs[index];
+ char *pptr = (char *)vptr + ppe->offset;
+
+ switch ((gc_ptr_type_index_t)ppe->type) {
+ case GC_ELT_OBJ:
+ return ENUM_OBJ(*(void **)pptr);
+ case GC_ELT_STRING:
+ return ENUM_STRING((gs_string *) pptr);
+ case GC_ELT_CONST_STRING:
+ return ENUM_CONST_STRING((gs_string *) pptr);
+ case GC_ELT_REF:
+ return 0;
+ }
+ }
+ if (!psd->super_type)
+ return 0;
+ return ENUM_USING(*(psd->super_type),
+ (void *)((char *)vptr + psd->super_offset),
+ pstype->ssize, index - psd->num_ptrs);
+}
+ENUM_PTRS_END_PROC
+
+/* Relocate pointers */
+RELOC_PTRS_BEGIN(basic_reloc_ptrs)
+{
+ const gc_struct_data_t *psd = pstype->proc_data;
+ uint i;
+
+ for (i = 0; i < psd->num_ptrs; ++i) {
+ const gc_ptr_element_t *ppe = &psd->ptrs[i];
+ char *pptr = (char *)vptr + ppe->offset;
+
+ switch ((gc_ptr_type_index_t) ppe->type) {
+ case GC_ELT_OBJ:
+ RELOC_OBJ_VAR(*(void **)pptr);
+ break;
+ case GC_ELT_STRING:
+ RELOC_STRING_VAR(*(gs_string *)pptr);
+ break;
+ case GC_ELT_CONST_STRING:
+ RELOC_CONST_STRING_VAR(*(gs_const_string *)pptr);
+ break;
+ case GC_ELT_REF:
+ break;
+ }
+ }
+ if (psd->super_type)
+ RELOC_USING(*(psd->super_type),
+ (void *)((char *)vptr + psd->super_offset),
+ pstype->ssize);
+} RELOC_PTRS_END
diff --git a/pstoraster/gsmemory.h b/pstoraster/gsmemory.h
new file mode 100644
index 000000000..2b8e4c655
--- /dev/null
+++ b/pstoraster/gsmemory.h
@@ -0,0 +1,277 @@
+/* Copyright (C) 1993, 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$ */
+/* Client interface for memory allocation */
+
+/*
+ * The allocator knows about two basic kinds of memory: objects, which are
+ * aligned and cannot have pointers to their interior, and strings, which
+ * are not aligned and which can have interior references.
+ *
+ * The standard allocator is designed to interface to a garbage collector,
+ * although it does not include or call one. The allocator API recognizes
+ * that the garbage collector may move objects, relocating pointers to them;
+ * the API provides for allocating both movable (the default) and immovable
+ * objects. Clients must not attempt to resize immovable objects, and must
+ * not create references to substrings of immovable strings.
+ */
+
+#ifndef gsmemory_INCLUDED
+# define gsmemory_INCLUDED
+
+#include "gsmemraw.h"
+
+/* Define the opaque type for a structure descriptor. */
+typedef struct gs_memory_struct_type_s gs_memory_struct_type_t;
+typedef const gs_memory_struct_type_t *gs_memory_type_ptr_t;
+
+/* Define the opaque type for an allocator. */
+/* (The actual structure is defined later in this file.) */
+typedef struct gs_memory_s gs_memory_t;
+
+/* Define the opaque type for a pointer type. */
+typedef struct gs_ptr_procs_s gs_ptr_procs_t;
+typedef const gs_ptr_procs_t *gs_ptr_type_t;
+
+/* Define the opaque type for a GC root. */
+typedef struct gs_gc_root_s gs_gc_root_t;
+
+ /* Accessors for structure types. */
+
+typedef client_name_t struct_name_t;
+
+/* Get the size of a structure from the descriptor. */
+uint gs_struct_type_size(P1(gs_memory_type_ptr_t));
+
+/* Get the name of a structure from the descriptor. */
+struct_name_t gs_struct_type_name(P1(gs_memory_type_ptr_t));
+
+#define gs_struct_type_name_string(styp)\
+ ((const char *)gs_struct_type_name(styp))
+
+/*
+ * Define the memory manager procedural interface.
+ */
+typedef struct gs_memory_procs_s {
+
+ gs_raw_memory_procs(gs_memory_t); /* defined in gsmemraw.h */
+
+ /* Redefine inherited procedures with the new allocator type. */
+
+#define gs_memory_proc_alloc_bytes(proc)\
+ gs_memory_t_proc_alloc_bytes(proc, gs_memory_t)
+#define gs_memory_proc_resize_object(proc)\
+ gs_memory_t_proc_resize_object(proc, gs_memory_t)
+#define gs_memory_proc_free_object(proc)\
+ gs_memory_t_proc_free_object(proc, gs_memory_t)
+#define gs_memory_proc_status(proc)\
+ gs_memory_t_proc_status(proc, gs_memory_t)
+#define gs_memory_proc_free_all(proc)\
+ gs_memory_t_proc_free_all(proc, gs_memory_t)
+#define gs_memory_proc_consolidate_free(proc)\
+ gs_memory_t_proc_consolidate_free(proc, gs_memory_t)
+
+ /*
+ * Allocate possibly movable bytes. (We inherit allocating immovable
+ * bytes from the raw memory allocator.)
+ */
+
+#define gs_alloc_bytes(mem, nbytes, cname)\
+ (*(mem)->procs.alloc_bytes)(mem, nbytes, cname)
+ gs_memory_proc_alloc_bytes((*alloc_bytes));
+
+ /*
+ * Allocate a structure.
+ */
+
+#define gs_memory_proc_alloc_struct(proc)\
+ void *proc(P3(gs_memory_t *mem, gs_memory_type_ptr_t pstype,\
+ client_name_t cname))
+#define gs_alloc_struct(mem, typ, pstype, cname)\
+ (typ *)(*(mem)->procs.alloc_struct)(mem, pstype, cname)
+ gs_memory_proc_alloc_struct((*alloc_struct));
+#define gs_alloc_struct_immovable(mem, typ, pstype, cname)\
+ (typ *)(*(mem)->procs.alloc_struct_immovable)(mem, pstype, cname)
+ gs_memory_proc_alloc_struct((*alloc_struct_immovable));
+
+ /*
+ * Allocate an array of bytes.
+ */
+
+#define gs_memory_proc_alloc_byte_array(proc)\
+ byte *proc(P4(gs_memory_t *mem, uint num_elements, uint elt_size,\
+ client_name_t cname))
+#define gs_alloc_byte_array(mem, nelts, esize, cname)\
+ (*(mem)->procs.alloc_byte_array)(mem, nelts, esize, cname)
+ gs_memory_proc_alloc_byte_array((*alloc_byte_array));
+#define gs_alloc_byte_array_immovable(mem, nelts, esize, cname)\
+ (*(mem)->procs.alloc_byte_array_immovable)(mem, nelts, esize, cname)
+ gs_memory_proc_alloc_byte_array((*alloc_byte_array_immovable));
+
+ /*
+ * Allocate an array of structures.
+ */
+
+#define gs_memory_proc_alloc_struct_array(proc)\
+ void *proc(P4(gs_memory_t *mem, uint num_elements,\
+ gs_memory_type_ptr_t pstype, client_name_t cname))
+#define gs_alloc_struct_array(mem, nelts, typ, pstype, cname)\
+ (typ *)(*(mem)->procs.alloc_struct_array)(mem, nelts, pstype, cname)
+ gs_memory_proc_alloc_struct_array((*alloc_struct_array));
+#define gs_alloc_struct_array_immovable(mem, nelts, typ, pstype, cname)\
+ (typ *)(*(mem)->procs.alloc_struct_array_immovable)(mem, nelts, pstype, cname)
+ gs_memory_proc_alloc_struct_array((*alloc_struct_array_immovable));
+
+ /*
+ * Get the size of an object (anything except a string).
+ */
+
+#define gs_memory_proc_object_size(proc)\
+ uint proc(P2(gs_memory_t *mem, const void *obj))
+#define gs_object_size(mem, obj)\
+ (*(mem)->procs.object_size)(mem, obj)
+ gs_memory_proc_object_size((*object_size));
+
+ /*
+ * Get the type of an object (anything except a string).
+ * The value returned for byte objects is useful only for
+ * printing.
+ */
+
+#define gs_memory_proc_object_type(proc)\
+ gs_memory_type_ptr_t proc(P2(gs_memory_t *mem, const void *obj))
+#define gs_object_type(mem, obj)\
+ (*(mem)->procs.object_type)(mem, obj)
+ gs_memory_proc_object_type((*object_type));
+
+ /*
+ * Allocate a string (unaligned bytes).
+ */
+
+#define gs_memory_proc_alloc_string(proc)\
+ byte *proc(P3(gs_memory_t *mem, uint nbytes, client_name_t cname))
+#define gs_alloc_string(mem, nbytes, cname)\
+ (*(mem)->procs.alloc_string)(mem, nbytes, cname)
+ gs_memory_proc_alloc_string((*alloc_string));
+#define gs_alloc_string_immovable(mem, nbytes, cname)\
+ (*(mem)->procs.alloc_string_immovable)(mem, nbytes, cname)
+ gs_memory_proc_alloc_string((*alloc_string_immovable));
+
+ /*
+ * Resize a string.
+ */
+
+#define gs_memory_proc_resize_string(proc)\
+ byte *proc(P5(gs_memory_t *mem, byte *data, uint old_num, uint new_num,\
+ client_name_t cname))
+#define gs_resize_string(mem, data, oldn, newn, cname)\
+ (*(mem)->procs.resize_string)(mem, data, oldn, newn, cname)
+ gs_memory_proc_resize_string((*resize_string));
+
+ /*
+ * Free a string.
+ */
+
+#define gs_memory_proc_free_string(proc)\
+ void proc(P4(gs_memory_t *mem, byte *data, uint nbytes,\
+ client_name_t cname))
+#define gs_free_string(mem, data, nbytes, cname)\
+ (*(mem)->procs.free_string)(mem, data, nbytes, cname)
+ gs_memory_proc_free_string((*free_string));
+
+ /*
+ * Register a root for the garbage collector. root = NULL
+ * asks the memory manager to allocate the root object
+ * itself (immovable, in the manager's parent): this is the usual
+ * way to call this procedure.
+ */
+
+#define gs_memory_proc_register_root(proc)\
+ int proc(P5(gs_memory_t *mem, gs_gc_root_t *root, gs_ptr_type_t ptype,\
+ void **pp, client_name_t cname))
+#define gs_register_root(mem, root, ptype, pp, cname)\
+ (*(mem)->procs.register_root)(mem, root, ptype, pp, cname)
+ gs_memory_proc_register_root((*register_root));
+
+ /*
+ * Unregister a root. The root object itself will be freed iff
+ * it was allocated by gs_register_root.
+ */
+
+#define gs_memory_proc_unregister_root(proc)\
+ void proc(P3(gs_memory_t *mem, gs_gc_root_t *root, client_name_t cname))
+#define gs_unregister_root(mem, root, cname)\
+ (*(mem)->procs.unregister_root)(mem, root, cname)
+ gs_memory_proc_unregister_root((*unregister_root));
+
+ /*
+ * Enable or disable the freeing operations: when disabled,
+ * these operations return normally but do nothing. The
+ * garbage collector and the PostScript interpreter
+ * 'restore' operator need to temporarily disable the
+ * freeing functions of (an) allocator(s) while running
+ * finalization procedures.
+ */
+
+#define gs_memory_proc_enable_free(proc)\
+ void proc(P2(gs_memory_t *mem, bool enable))
+#define gs_enable_free(mem, enable)\
+ (*(mem)->procs.enable_free)(mem, enable)
+ gs_memory_proc_enable_free((*enable_free));
+
+} gs_memory_procs_t;
+
+/* Register a structure root. This just calls gs_register_root. */
+int gs_register_struct_root(P4(gs_memory_t *mem, gs_gc_root_t *root,
+ void **pp, client_name_t cname));
+
+/* Define no-op freeing procedures for use by enable_free. */
+gs_memory_proc_free_object(gs_ignore_free_object);
+gs_memory_proc_free_string(gs_ignore_free_string);
+
+/* Define a no-op consolidation procedure. */
+gs_memory_proc_consolidate_free(gs_ignore_consolidate_free);
+
+/*
+ * Allocate a structure using a "raw memory" allocator. Note that this does
+ * not retain the identity of the structure. Note also that it returns a
+ * void *, and does not take the type of the returned pointer as a
+ * parameter.
+ */
+void *gs_raw_alloc_struct_immovable(P3(gs_raw_memory_t * rmem,
+ gs_memory_type_ptr_t pstype,
+ client_name_t cname));
+
+/*
+ * Define an abstract allocator instance.
+ * Subclasses may have state as well.
+ */
+#define gs_memory_common\
+ gs_memory_procs_t procs
+struct gs_memory_s {
+ gs_memory_common;
+};
+
+#endif /* gsmemory_INCLUDED */
diff --git a/pstoraster/gsmemraw.h b/pstoraster/gsmemraw.h
new file mode 100644
index 000000000..019dd4ff2
--- /dev/null
+++ b/pstoraster/gsmemraw.h
@@ -0,0 +1,181 @@
+/* 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$ */
+/* Client interface for "raw memory" allocator */
+
+/* Initial version 02/03/1998 by John Desrosiers (soho@crl.com) */
+/* Completely rewritten 6/26/1998 by L. Peter Deutsch <ghost@aladdin.com> */
+
+#ifndef gsmemraw_INCLUDED
+# define gsmemraw_INCLUDED
+
+/*
+ * This interface provides minimal memory allocation and freeing capability.
+ * It is meant to be used for "wholesale" allocation of blocks -- typically,
+ * but not only, via malloc -- which are then divided up into "retail"
+ * objects. However, since it is a subset (superclass) of the "retail"
+ * interface defined in gsmemory.h, retail allocators implement it as
+ * well, and in fact the malloc interface defined in gsmalloc.h is used for
+ * both wholesale and retail allocation.
+ */
+
+/*
+ * Define the structure for reporting memory manager statistics.
+ */
+typedef struct gs_memory_status_s {
+ /*
+ * "Allocated" space is the total amount of space acquired from
+ * the parent of the memory manager. It includes space used for
+ * allocated data, space available for allocation, and overhead.
+ */
+ ulong allocated;
+ /*
+ * "Used" space is the amount of space used by allocated data
+ * plus overhead.
+ */
+ ulong used;
+} gs_memory_status_t;
+
+/* Define the abstract type for the memory manager. */
+typedef struct gs_raw_memory_s gs_raw_memory_t;
+
+/* Define the procedures for raw memory management. Memory managers have no
+ * standard constructor: each implementation defines its own, and is
+ * responsible for calling its superclass' initialization code first.
+ * Similarly, each implementation's destructor (release) must first take
+ * care of its own cleanup and then call the superclass' release.
+ */
+
+ /*
+ * Allocate bytes. The bytes are always aligned maximally
+ * if the processor requires alignment.
+ *
+ * Note that the object memory level can allocate bytes as
+ * either movable or immovable: raw memory blocks are
+ * always immovable.
+ */
+
+#define gs_memory_t_proc_alloc_bytes(proc, mem_t)\
+ byte *proc(P3(mem_t *mem, uint nbytes, client_name_t cname))
+
+#define gs_alloc_bytes_immovable(mem, nbytes, cname)\
+ ((mem)->procs.alloc_bytes_immovable(mem, nbytes, cname))
+
+ /*
+ * Resize an object to a new number of elements. At the raw
+ * memory level, the "element" is a byte; for object memory
+ * (gsmemory.h), the object may be an an array of either
+ * bytes or structures. The new size may be either larger
+ * or smaller than the old.
+ */
+
+#define gs_memory_t_proc_resize_object(proc, mem_t)\
+ void *proc(P4(mem_t *mem, void *obj, uint new_num_elements,\
+ client_name_t cname))
+
+#define gs_resize_object(mem, obj, newn, cname)\
+ ((mem)->procs.resize_object(mem, obj, newn, cname))
+
+ /*
+ * Free an object (at the object memory level, this includes
+ * everything except strings). Note: data == 0 must be
+ * allowed, and must be a no-op.
+ */
+
+#define gs_memory_t_proc_free_object(proc, mem_t)\
+ void proc(P3(mem_t *mem, void *data, client_name_t cname))
+
+#define gs_free_object(mem, data, cname)\
+ ((mem)->procs.free_object(mem, data, cname))
+
+ /*
+ * Report status (assigned, used).
+ */
+
+#define gs_memory_t_proc_status(proc, mem_t)\
+ void proc(P2(mem_t *mem, gs_memory_status_t *status))
+
+#define gs_memory_status(mem, pst)\
+ ((mem)->procs.status(mem, pst))
+
+ /*
+ * Free one or more of: data memory acquired by the allocator
+ * (FREE_ALL_DATA), overhead structures other than the
+ * allocator itself (FREE_ALL_STRUCTURES), and the allocator
+ * itself (FREE_ALL_ALLOCATOR). Note that this requires
+ * allocators to keep track of all the memory they have ever
+ * acquired, and where they acquired it.
+ */
+
+#define FREE_ALL_DATA 1
+#define FREE_ALL_STRUCTURES 2
+#define FREE_ALL_ALLOCATOR 4
+#define FREE_ALL_EVERYTHING\
+ (FREE_ALL_DATA | FREE_ALL_STRUCTURES | FREE_ALL_ALLOCATOR)
+
+#define gs_memory_t_proc_free_all(proc, mem_t)\
+ void proc(P3(mem_t *mem, uint free_mask, client_name_t cname))
+
+#define gs_memory_free_all(mem, free_mask, cname)\
+ ((mem)->procs.free_all(mem, free_mask, cname))
+/* Backward compatibility */
+#define gs_free_all(mem)\
+ gs_memory_free_all(mem, FREE_ALL_DATA, "(free_all)")
+
+ /*
+ * Consolidate free space. This may be used as part of (or
+ * as an alternative to) garbage collection, or before
+ * giving up on an attempt to allocate.
+ */
+
+#define gs_memory_t_proc_consolidate_free(proc, mem_t)\
+ void proc(P1(mem_t *mem))
+
+#define gs_consolidate_free(mem)\
+ ((mem)->procs.consolidate_free(mem))
+
+/* Define the members of the procedure structure. */
+#define gs_raw_memory_procs(mem_t)\
+ gs_memory_t_proc_alloc_bytes((*alloc_bytes_immovable), mem_t);\
+ gs_memory_t_proc_resize_object((*resize_object), mem_t);\
+ gs_memory_t_proc_free_object((*free_object), mem_t);\
+ gs_memory_t_proc_status((*status), mem_t);\
+ gs_memory_t_proc_free_all((*free_all), mem_t);\
+ gs_memory_t_proc_consolidate_free((*consolidate_free), mem_t)
+
+/* Define the procedure vector for a raw memory allocator. */
+typedef struct gs_raw_memory_procs_s {
+ gs_raw_memory_procs(gs_raw_memory_t);
+} gs_raw_memory_procs_t;
+
+/*
+ * Define an abstract raw-memory allocator instance.
+ * Subclasses may have state as well.
+ */
+struct gs_raw_memory_s {
+ gs_raw_memory_procs_t procs;
+};
+
+#endif /* gsmemraw_INCLUDED */
diff --git a/pstoraster/gsmisc.c b/pstoraster/gsmisc.c
new file mode 100644
index 000000000..ec43311ed
--- /dev/null
+++ b/pstoraster/gsmisc.c
@@ -0,0 +1,942 @@
+/*
+ Copyright 1993-2002 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$ */
+/* Miscellaneous utilities for Ghostscript library */
+#include "ctype_.h"
+#include "malloc_.h"
+#include "math_.h"
+#include "memory_.h"
+#include "string_.h"
+#include "gx.h"
+#include "gpcheck.h" /* for gs_return_check_interrupt */
+#include "gserrors.h"
+#include "gconfigv.h" /* for USE_ASM */
+#include "gxfarith.h"
+#include "gxfixed.h"
+
+/* Define private replacements for stdin, stdout, and stderr. */
+FILE *gs_stdin, *gs_stdout, *gs_stderr;
+
+/* Ghostscript writes debugging output to gs_debug_out. */
+/* We define gs_debug and gs_debug_out even if DEBUG isn't defined, */
+/* so that we can compile individual modules with DEBUG set. */
+char gs_debug[128];
+FILE *gs_debug_out;
+
+/* Test whether a given debugging option is selected. */
+/* Upper-case letters automatically include their lower-case counterpart. */
+bool
+gs_debug_c(int c)
+{
+ return
+ (c >= 'a' && c <= 'z' ? gs_debug[c] | gs_debug[c ^ 32] : gs_debug[c]);
+}
+
+/* Define the formats for debugging printout. */
+const char *const dprintf_file_and_line_format = "%10s(%4d): ";
+const char *const dprintf_file_only_format = "%10s(unkn): ";
+
+/*
+ * Define the trace printout procedures. We always include these, in case
+ * other modules were compiled with DEBUG set.
+ */
+private const char *
+dprintf_file_tail(const char *file)
+{
+ const char *tail = file + strlen(file);
+
+ while (tail > file &&
+ (isalnum(tail[-1]) || tail[-1] == '.' || tail[-1] == '_')
+ )
+ --tail;
+ return tail;
+}
+void
+dprintf_file_and_line(FILE * f, const char *file, int line)
+{
+ if (gs_debug['/'])
+ fprintf(f, dprintf_file_and_line_format,
+ dprintf_file_tail(file), line);
+}
+void
+dprintf_file(FILE * f, const char *file)
+{
+ if (gs_debug['/'])
+ fprintf(f, dprintf_file_only_format, dprintf_file_tail(file));
+}
+void
+eprintf_program_name(FILE * f, const char *program_name)
+{
+ if (program_name)
+ fprintf(f, "%s: ", program_name);
+}
+void
+lprintf_file_and_line(FILE * f, const char *file, int line)
+{
+ fprintf(f, "%s(%d): ", file, line);
+}
+void
+lprintf_file_only(FILE * f, const char *file)
+{
+ fprintf(f, "%s(?): ", file);
+}
+
+/* Log an error return. We always include this, in case other */
+/* modules were compiled with DEBUG set. */
+#undef gs_log_error /* in case DEBUG isn't set */
+int
+gs_log_error(int err, const char *file, int line)
+{
+ if (gs_log_errors) {
+ if (file == NULL)
+ dprintf1("Returning error %d.\n", err);
+ else
+ dprintf3("%s(%d): Returning error %d.\n",
+ (const char *)file, line, err);
+ }
+ return err;
+}
+
+/* Check for interrupts before a return. */
+int
+gs_return_check_interrupt(int code)
+{
+ if (code < 0)
+ return code;
+ {
+ int icode = gp_check_interrupts();
+
+ return (icode == 0 ? code :
+ gs_note_error((icode > 0 ? gs_error_interrupt : icode)));
+ }
+}
+
+/* ------ Substitutes for missing C library functions ------ */
+
+#ifdef memory__need_memmove /* see memory_.h */
+/* Copy bytes like memcpy, guaranteed to handle overlap correctly. */
+/* ANSI C defines the returned value as being the src argument, */
+/* but with the const restriction removed! */
+void *
+gs_memmove(void *dest, const void *src, size_t len)
+{
+ if (!len)
+ return (void *)src;
+#define bdest ((byte *)dest)
+#define bsrc ((const byte *)src)
+ /* We use len-1 for comparisons because adding len */
+ /* might produce an offset overflow on segmented systems. */
+ if (ptr_le(bdest, bsrc)) {
+ register byte *end = bdest + (len - 1);
+
+ if (ptr_le(bsrc, end)) { /* Source overlaps destination from above. */
+ register const byte *from = bsrc;
+ register byte *to = bdest;
+
+ for (;;) {
+ *to = *from;
+ if (to >= end) /* faster than = */
+ return (void *)src;
+ to++;
+ from++;
+ }
+ }
+ } else {
+ register const byte *from = bsrc + (len - 1);
+
+ if (ptr_le(bdest, from)) { /* Source overlaps destination from below. */
+ register const byte *end = bsrc;
+ register byte *to = bdest + (len - 1);
+
+ for (;;) {
+ *to = *from;
+ if (from <= end) /* faster than = */
+ return (void *)src;
+ to--;
+ from--;
+ }
+ }
+ }
+#undef bdest
+#undef bsrc
+ /* No overlap, it's safe to use memcpy. */
+ memcpy(dest, src, len);
+ return (void *)src;
+}
+#endif
+
+#ifdef memory__need_memchr /* see memory_.h */
+/* ch should obviously be char rather than int, */
+/* but the ANSI standard declaration uses int. */
+const char *
+gs_memchr(const char *ptr, int ch, size_t len)
+{
+ if (len > 0) {
+ register const char *p = ptr;
+ register uint count = len;
+
+ do {
+ if (*p == (char)ch)
+ return p;
+ p++;
+ } while (--count);
+ }
+ return 0;
+}
+#endif
+
+#ifdef memory__need_memset /* see memory_.h */
+/* ch should obviously be char rather than int, */
+/* but the ANSI standard declaration uses int. */
+void *
+gs_memset(void *dest, register int ch, size_t len)
+{
+ if (ch == 0)
+ bzero(dest, len);
+ else if (len > 0) {
+ register char *p = dest;
+ register uint count = len;
+
+ do {
+ *p++ = (char)ch;
+ } while (--count);
+ }
+ return dest;
+}
+#endif
+
+#ifdef malloc__need_realloc /* see malloc_.h */
+/* Some systems have non-working implementations of realloc. */
+void *
+gs_realloc(void *old_ptr, size_t old_size, size_t new_size)
+{
+ void *new_ptr;
+
+ /**** MRS - 64-bit align all data structures!!!!!!!!!!! ****/
+ new_size = (new_size + 7) & ~7;
+
+ if (new_size) {
+ new_ptr = calloc(1, new_size);
+ if (new_ptr == NULL)
+ return NULL;
+ } else
+ new_ptr = NULL;
+ /* We have to pass in the old size, since we have no way to */
+ /* determine it otherwise. */
+ if (old_ptr != NULL) {
+ if (new_ptr != NULL)
+ memcpy(new_ptr, old_ptr, min(old_size, new_size));
+ free(old_ptr);
+ }
+ return new_ptr;
+}
+#endif
+
+/* ------ Debugging support ------ */
+
+/* Dump a region of memory. */
+void
+debug_dump_bytes(const byte * from, const byte * to, const char *msg)
+{
+ const byte *p = from;
+
+ if (from < to && msg)
+ dprintf1("%s:\n", msg);
+ while (p != to) {
+ const byte *q = min(p + 16, to);
+
+ dprintf1("0x%lx:", (ulong) p);
+ while (p != q)
+ dprintf1(" %02x", *p++);
+ dputc('\n');
+ }
+}
+
+/* Dump a bitmap. */
+void
+debug_dump_bitmap(const byte * bits, uint raster, uint height, const char *msg)
+{
+ uint y;
+ const byte *data = bits;
+
+ for (y = 0; y < height; ++y, data += raster)
+ debug_dump_bytes(data, data + raster, (y == 0 ? msg : NULL));
+}
+
+/* Print a string. */
+void
+debug_print_string(const byte * chrs, uint len)
+{
+ uint i;
+
+ for (i = 0; i < len; i++)
+ dputc(chrs[i]);
+ fflush(dstderr);
+}
+
+/* ------ Arithmetic ------ */
+
+/* Compute M modulo N. Requires N > 0; guarantees 0 <= imod(M,N) < N, */
+/* regardless of the whims of the % operator for negative operands. */
+int
+imod(int m, int n)
+{
+ if (n <= 0)
+ return 0; /* sanity check */
+ if (m >= 0)
+ return m % n;
+ {
+ int r = -m % n;
+
+ return (r == 0 ? 0 : n - r);
+ }
+}
+
+/* Compute the GCD of two integers. */
+int
+igcd(int x, int y)
+{
+ int c = x, d = y;
+
+ if (c < 0)
+ c = -c;
+ if (d < 0)
+ d = -d;
+ while (c != 0 && d != 0)
+ if (c > d)
+ c %= d;
+ else
+ d %= c;
+ return d + c; /* at most one is non-zero */
+}
+
+#if defined(set_fmul2fixed_vars) && !USE_ASM
+
+/*
+ * Floating multiply with fixed result, for avoiding floating point in
+ * common coordinate transformations. Assumes IEEE representation,
+ * 16-bit short, 32-bit long. Optimized for the case where the first
+ * operand has no more than 16 mantissa bits, e.g., where it is a user space
+ * coordinate (which are often integers).
+ *
+ * The assembly language version of this code is actually faster than
+ * the FPU, if the code is compiled with FPU_TYPE=0 (which requires taking
+ * a trap on every FPU operation). If there is no FPU, the assembly
+ * language version of this code is over 10 times as fast as the emulated FPU.
+ */
+/* Some of the following code has been tweaked for the Borland 16-bit */
+/* compiler. The tweaks do not change the algorithms. */
+#if arch_ints_are_short && !defined(FOR80386)
+# define SHORT_ARITH
+#endif
+int
+set_fmul2fixed_(fixed * pr, long /*float */ a, long /*float */ b)
+{
+#ifdef SHORT_ARITH
+# define long_rsh8_ushort(x)\
+ (((ushort)(x) >> 8) | ((ushort)((ulong)(x) >> 16) << 8))
+# define utemp ushort
+#else
+# define long_rsh8_ushort(x) ((ushort)((x) >> 8))
+# define utemp ulong
+#endif
+ /* utemp may be either ushort or ulong. This is OK because */
+ /* we only use ma and mb in multiplications involving */
+ /* a long or ulong operand. */
+ utemp ma = long_rsh8_ushort(a) | 0x8000;
+ utemp mb = long_rsh8_ushort(b) | 0x8000;
+ int e = 260 + _fixed_shift - ((
+ (((uint) ((ulong) a >> 16)) & 0x7f80) +
+ (((uint) ((ulong) b >> 16)) & 0x7f80)
+ ) >> 7);
+ ulong p1 = ma * (b & 0xff);
+ ulong p = (ulong) ma * mb;
+
+#define p_bits (size_of(p) * 8)
+
+ if ((byte) a) { /* >16 mantissa bits */
+ ulong p2 = (a & 0xff) * mb;
+
+ p += ((((uint) (byte) a * (uint) (byte) b) >> 8) + p1 + p2) >> 8;
+ } else
+ p += p1 >> 8;
+ if ((uint) e < p_bits) /* e = -1 is possible */
+ p >>= e;
+ else if (e >= p_bits) { /* also detects a=0 or b=0 */
+ *pr = fixed_0;
+ return 0;
+ } else if (e >= -(p_bits - 1) || p >= 1L << (p_bits - 1 + e))
+ return_error(gs_error_limitcheck);
+ else
+ p <<= -e;
+ *pr = ((a ^ b) < 0 ? -p : p);
+ return 0;
+}
+int
+set_dfmul2fixed_(fixed * pr, ulong /*double lo */ xalo, long /*float */ b, long /*double hi */ xahi)
+{
+#ifdef SHORT_ARITH
+# define long_lsh3(x) ((((x) << 1) << 1) << 1)
+# define long_rsh(x,ng16) ((uint)((x) >> 16) >> (ng16 - 16))
+#else
+# define long_lsh3(x) ((x) << 3)
+# define long_rsh(x,ng16) ((x) >> ng16)
+#endif
+ return set_fmul2fixed_(pr,
+ (xahi & 0xc0000000) +
+ (long_lsh3(xahi) & 0x3ffffff8) +
+ long_rsh(xalo, 29),
+ b);
+}
+
+#endif
+
+#if USE_FPU_FIXED
+
+/*
+ * Convert from floating point to fixed point with scaling.
+ * These are efficient algorithms for FPU-less machines.
+ */
+#define mbits_float 23
+#define mbits_double 20
+int
+set_float2fixed_(fixed * pr, long /*float */ vf, int frac_bits)
+{
+ fixed mantissa;
+ int shift;
+
+ if (!(vf & 0x7f800000)) {
+ *pr = fixed_0;
+ return 0;
+ }
+ mantissa = (fixed) ((vf & 0x7fffff) | 0x800000);
+ shift = ((vf >> 23) & 255) - (127 + 23) + frac_bits;
+ if (shift >= 0) {
+ if (shift >= sizeof(fixed) * 8 - 24)
+ return_error(gs_error_limitcheck);
+ if (vf < 0)
+ mantissa = -mantissa;
+ *pr = (fixed) (mantissa << shift);
+ } else
+ *pr = (shift < -24 ? fixed_0 :
+ vf < 0 ? -(fixed) (mantissa >> -shift) : /* truncate */
+ (fixed) (mantissa >> -shift));
+ return 0;
+}
+int
+set_double2fixed_(fixed * pr, ulong /*double lo */ lo,
+ long /*double hi */ hi, int frac_bits)
+{
+ fixed mantissa;
+ int shift;
+
+ if (!(hi & 0x7ff00000)) {
+ *pr = fixed_0;
+ return 0;
+ }
+ /* We only use 31 bits of mantissa even if sizeof(long) > 4. */
+ mantissa = (fixed) (((hi & 0xfffff) << 10) | (lo >> 22) | 0x40000000);
+ shift = ((hi >> 20) & 2047) - (1023 + 30) + frac_bits;
+ if (shift > 0)
+ return_error(gs_error_limitcheck);
+ *pr = (shift < -30 ? fixed_0 :
+ hi < 0 ? -(fixed) (mantissa >> -shift) : /* truncate */
+ (fixed) (mantissa >> -shift));
+ return 0;
+}
+/*
+ * Given a fixed value x with fbits bits of fraction, set v to the mantissa
+ * (left-justified in 32 bits) and f to the exponent word of the
+ * corresponding floating-point value with mbits bits of mantissa in the
+ * first word. (The exponent part of f is biased by -1, because we add the
+ * top 1-bit of the mantissa to it.)
+ */
+static const byte f2f_shifts[] =
+{4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0};
+
+#define f2f_declare(v, f)\
+ ulong v;\
+ long f
+#define f2f(x, v, f, mbits, fbits)\
+ if ( x < 0 )\
+ f = 0xc0000000 + (29 << mbits) - ((long)fbits << mbits), v = -x;\
+ else\
+ f = 0x40000000 + (29 << mbits) - ((long)fbits << mbits), v = x;\
+ if ( v < 0x8000 )\
+ v <<= 15, f -= 15 << mbits;\
+ if ( v < 0x800000 )\
+ v <<= 8, f -= 8 << mbits;\
+ if ( v < 0x8000000 )\
+ v <<= 4, f -= 4 << mbits;\
+ { int shift = f2f_shifts[v >> 28];\
+ v <<= shift, f -= shift << mbits;\
+ }
+long
+fixed2float_(fixed x, int frac_bits)
+{
+ f2f_declare(v, f);
+
+ if (x == 0)
+ return 0;
+ f2f(x, v, f, mbits_float, frac_bits);
+ return f + (((v >> 7) + 1) >> 1);
+}
+void
+set_fixed2double_(double *pd, fixed x, int frac_bits)
+{
+ f2f_declare(v, f);
+
+ if (x == 0) {
+ ((long *)pd)[1 - arch_is_big_endian] = 0;
+ ((ulong *) pd)[arch_is_big_endian] = 0;
+ } else {
+ f2f(x, v, f, mbits_double, frac_bits);
+ ((long *)pd)[1 - arch_is_big_endian] = f + (v >> 11);
+ ((ulong *) pd)[arch_is_big_endian] = v << 21;
+ }
+}
+
+/*
+ * Compute A * B / C when 0 <= B < C and A * B exceeds (or might exceed)
+ * the capacity of a long.
+ */
+#ifdef DEBUG
+struct {
+ long mnanb, mnab, manb, mab, mnc, mdq, mde, mds, mqh, mql;
+} fmq_stat;
+
+# define mincr(x) ++fmq_stat.x
+#else
+# define mincr(x) DO_NOTHING
+#endif
+fixed
+fixed_mult_quo(fixed signed_A, fixed B, fixed C)
+{ /* First compute A * B in double-fixed precision. */
+ ulong A = (signed_A < 0 ? -signed_A : signed_A);
+ long msw;
+ ulong lsw;
+ ulong p1;
+
+#define num_bits (sizeof(fixed) * 8)
+#define half_bits (num_bits / 2)
+#define half_mask ((1L << half_bits) - 1)
+ if (B <= half_mask) {
+ if (A <= half_mask) {
+ fixed Q = (ulong) (A * B) / (ulong) C;
+
+ mincr(mnanb);
+ return (signed_A < 0 ? -Q : Q);
+ }
+ /*
+ * We might still have C <= half_mask, which we can
+ * handle with a simpler algorithm.
+ */
+ lsw = (A & half_mask) * B;
+ p1 = (A >> half_bits) * B;
+ if (C <= half_mask) {
+ ulong q0 = (p1 += lsw >> half_bits) / C;
+ ulong rem = ((p1 - C * q0) << half_bits) + (lsw & half_mask);
+ ulong Q = (q0 << half_bits) + rem / C;
+
+ mincr(mnc);
+ return (signed_A < 0 ? -Q : Q);
+ }
+ msw = p1 >> half_bits;
+ mincr(manb);
+ } else if (A <= half_mask) {
+ p1 = A * (B >> half_bits);
+ msw = p1 >> half_bits;
+ lsw = A * (B & half_mask);
+ mincr(mnab);
+ } else { /* We have to compute all 4 products. :-( */
+ ulong lo_A = A & half_mask;
+ ulong hi_A = A >> half_bits;
+ ulong lo_B = B & half_mask;
+ ulong hi_B = B >> half_bits;
+ ulong p1x = hi_A * lo_B;
+
+ msw = hi_A * hi_B;
+ lsw = lo_A * lo_B;
+ p1 = lo_A * hi_B;
+ if (p1 > max_ulong - p1x)
+ msw += 1L << half_bits;
+ p1 += p1x;
+ msw += p1 >> half_bits;
+ mincr(mab);
+ }
+ /* Finish up by adding the low half of p1 to the high half of lsw. */
+#if max_fixed < max_long
+ p1 &= half_mask;
+#endif
+ p1 <<= half_bits;
+ if (p1 > max_ulong - lsw)
+ msw++;
+ lsw += p1;
+ /*
+ * Now divide the double-length product by C. Note that we know msw
+ * < C (otherwise the quotient would overflow). Start by shifting
+ * (msw,lsw) and C left until C >= 1 << (num_bits - 1).
+ */
+ {
+ ulong denom = C;
+ int shift = 0;
+
+#define bits_4th (num_bits / 4)
+ if (denom < 1L << (num_bits - bits_4th)) {
+ mincr(mdq);
+ denom <<= bits_4th, shift += bits_4th;
+ }
+#undef bits_4th
+#define bits_8th (num_bits / 8)
+ if (denom < 1L << (num_bits - bits_8th)) {
+ mincr(mde);
+ denom <<= bits_8th, shift += bits_8th;
+ }
+#undef bits_8th
+ while (!(denom & (1L << (num_bits - 1)))) {
+ mincr(mds);
+ denom <<= 1, ++shift;
+ }
+ msw = (msw << shift) + (lsw >> (num_bits - shift));
+ lsw <<= shift;
+#if max_fixed < max_long
+ lsw &= (1L << (sizeof(fixed) * 8)) - 1;
+#endif
+ /* Compute a trial upper-half quotient. */
+ {
+ ulong hi_D = denom >> half_bits;
+ ulong lo_D = denom & half_mask;
+ ulong hi_Q = (ulong) msw / hi_D;
+
+ /* hi_Q might be too high by 1 or 2, but it isn't too low. */
+ ulong p0 = hi_Q * hi_D;
+ ulong p1 = hi_Q * lo_D;
+ ulong hi_P;
+
+ while ((hi_P = p0 + (p1 >> half_bits)) > msw ||
+ (hi_P == msw && ((p1 & half_mask) << half_bits) > lsw)
+ ) { /* hi_Q was too high by 1. */
+ --hi_Q;
+ p0 -= hi_D;
+ p1 -= lo_D;
+ mincr(mqh);
+ }
+ p1 = (p1 & half_mask) << half_bits;
+ if (p1 > lsw)
+ msw--;
+ lsw -= p1;
+ msw -= hi_P;
+ /* Now repeat to get the lower-half quotient. */
+ msw = (msw << half_bits) + (lsw >> half_bits);
+#if max_fixed < max_long
+ lsw &= half_mask;
+#endif
+ lsw <<= half_bits;
+ {
+ ulong lo_Q = (ulong) msw / hi_D;
+ long Q;
+
+ p1 = lo_Q * lo_D;
+ p0 = lo_Q * hi_D;
+ while ((hi_P = p0 + (p1 >> half_bits)) > msw ||
+ (hi_P == msw && ((p1 & half_mask) << half_bits) > lsw)
+ ) { /* lo_Q was too high by 1. */
+ --lo_Q;
+ p0 -= hi_D;
+ p1 -= lo_D;
+ mincr(mql);
+ }
+ Q = (hi_Q << half_bits) + lo_Q;
+ return (signed_A < 0 ? -Q : Q);
+ }
+ }
+ }
+#undef half_bits
+#undef half_mask
+}
+
+#endif
+
+/* Trace calls on sqrt when debugging. */
+#undef sqrt
+extern double sqrt(P1(double));
+double
+gs_sqrt(double x, const char *file, int line)
+{
+ if (gs_debug_c('~')) {
+ fprintf(stderr, "[~]sqrt(%g) at %s:%d\n",
+ x, (const char *)file, line);
+ fflush(stderr);
+ }
+ return sqrt(x);
+}
+
+/*
+ * Define sine and cosine functions that take angles in degrees rather than
+ * radians, and that are implemented efficiently on machines with slow
+ * (or no) floating point.
+ */
+#if USE_FPU < 0 /****** maybe should be <= 0 ? ***** */
+
+#define sin0 0.00000000000000000
+#define sin1 0.01745240643728351
+#define sin2 0.03489949670250097
+#define sin3 0.05233595624294383
+#define sin4 0.06975647374412530
+#define sin5 0.08715574274765817
+#define sin6 0.10452846326765346
+#define sin7 0.12186934340514748
+#define sin8 0.13917310096006544
+#define sin9 0.15643446504023087
+#define sin10 0.17364817766693033
+#define sin11 0.19080899537654480
+#define sin12 0.20791169081775931
+#define sin13 0.22495105434386498
+#define sin14 0.24192189559966773
+#define sin15 0.25881904510252074
+#define sin16 0.27563735581699916
+#define sin17 0.29237170472273671
+#define sin18 0.30901699437494740
+#define sin19 0.32556815445715670
+#define sin20 0.34202014332566871
+#define sin21 0.35836794954530027
+#define sin22 0.37460659341591201
+#define sin23 0.39073112848927377
+#define sin24 0.40673664307580015
+#define sin25 0.42261826174069944
+#define sin26 0.43837114678907740
+#define sin27 0.45399049973954675
+#define sin28 0.46947156278589081
+#define sin29 0.48480962024633706
+#define sin30 0.50000000000000000
+#define sin31 0.51503807491005416
+#define sin32 0.52991926423320490
+#define sin33 0.54463903501502708
+#define sin34 0.55919290347074679
+#define sin35 0.57357643635104605
+#define sin36 0.58778525229247314
+#define sin37 0.60181502315204827
+#define sin38 0.61566147532565829
+#define sin39 0.62932039104983739
+#define sin40 0.64278760968653925
+#define sin41 0.65605902899050728
+#define sin42 0.66913060635885824
+#define sin43 0.68199836006249848
+#define sin44 0.69465837045899725
+#define sin45 0.70710678118654746
+#define sin46 0.71933980033865108
+#define sin47 0.73135370161917046
+#define sin48 0.74314482547739413
+#define sin49 0.75470958022277201
+#define sin50 0.76604444311897801
+#define sin51 0.77714596145697090
+#define sin52 0.78801075360672190
+#define sin53 0.79863551004729283
+#define sin54 0.80901699437494745
+#define sin55 0.81915204428899180
+#define sin56 0.82903757255504174
+#define sin57 0.83867056794542394
+#define sin58 0.84804809615642596
+#define sin59 0.85716730070211222
+#define sin60 0.86602540378443860
+#define sin61 0.87461970713939574
+#define sin62 0.88294759285892688
+#define sin63 0.89100652418836779
+#define sin64 0.89879404629916704
+#define sin65 0.90630778703664994
+#define sin66 0.91354545764260087
+#define sin67 0.92050485345244037
+#define sin68 0.92718385456678731
+#define sin69 0.93358042649720174
+#define sin70 0.93969262078590832
+#define sin71 0.94551857559931674
+#define sin72 0.95105651629515353
+#define sin73 0.95630475596303544
+#define sin74 0.96126169593831889
+#define sin75 0.96592582628906831
+#define sin76 0.97029572627599647
+#define sin77 0.97437006478523525
+#define sin78 0.97814760073380558
+#define sin79 0.98162718344766398
+#define sin80 0.98480775301220802
+#define sin81 0.98768834059513777
+#define sin82 0.99026806874157036
+#define sin83 0.99254615164132198
+#define sin84 0.99452189536827329
+#define sin85 0.99619469809174555
+#define sin86 0.99756405025982420
+#define sin87 0.99862953475457383
+#define sin88 0.99939082701909576
+#define sin89 0.99984769515639127
+#define sin90 1.00000000000000000
+
+private const double sin_table[361] =
+{
+ sin0,
+ sin1, sin2, sin3, sin4, sin5, sin6, sin7, sin8, sin9, sin10,
+ sin11, sin12, sin13, sin14, sin15, sin16, sin17, sin18, sin19, sin20,
+ sin21, sin22, sin23, sin24, sin25, sin26, sin27, sin28, sin29, sin30,
+ sin31, sin32, sin33, sin34, sin35, sin36, sin37, sin38, sin39, sin40,
+ sin41, sin42, sin43, sin44, sin45, sin46, sin47, sin48, sin49, sin50,
+ sin51, sin52, sin53, sin54, sin55, sin56, sin57, sin58, sin59, sin60,
+ sin61, sin62, sin63, sin64, sin65, sin66, sin67, sin68, sin69, sin70,
+ sin71, sin72, sin73, sin74, sin75, sin76, sin77, sin78, sin79, sin80,
+ sin81, sin82, sin83, sin84, sin85, sin86, sin87, sin88, sin89, sin90,
+ sin89, sin88, sin87, sin86, sin85, sin84, sin83, sin82, sin81, sin80,
+ sin79, sin78, sin77, sin76, sin75, sin74, sin73, sin72, sin71, sin70,
+ sin69, sin68, sin67, sin66, sin65, sin64, sin63, sin62, sin61, sin60,
+ sin59, sin58, sin57, sin56, sin55, sin54, sin53, sin52, sin51, sin50,
+ sin49, sin48, sin47, sin46, sin45, sin44, sin43, sin42, sin41, sin40,
+ sin39, sin38, sin37, sin36, sin35, sin34, sin33, sin32, sin31, sin30,
+ sin29, sin28, sin27, sin26, sin25, sin24, sin23, sin22, sin21, sin20,
+ sin19, sin18, sin17, sin16, sin15, sin14, sin13, sin12, sin11, sin10,
+ sin9, sin8, sin7, sin6, sin5, sin4, sin3, sin2, sin1, sin0,
+ -sin1, -sin2, -sin3, -sin4, -sin5, -sin6, -sin7, -sin8, -sin9, -sin10,
+ -sin11, -sin12, -sin13, -sin14, -sin15, -sin16, -sin17, -sin18, -sin19, -sin20,
+ -sin21, -sin22, -sin23, -sin24, -sin25, -sin26, -sin27, -sin28, -sin29, -sin30,
+ -sin31, -sin32, -sin33, -sin34, -sin35, -sin36, -sin37, -sin38, -sin39, -sin40,
+ -sin41, -sin42, -sin43, -sin44, -sin45, -sin46, -sin47, -sin48, -sin49, -sin50,
+ -sin51, -sin52, -sin53, -sin54, -sin55, -sin56, -sin57, -sin58, -sin59, -sin60,
+ -sin61, -sin62, -sin63, -sin64, -sin65, -sin66, -sin67, -sin68, -sin69, -sin70,
+ -sin71, -sin72, -sin73, -sin74, -sin75, -sin76, -sin77, -sin78, -sin79, -sin80,
+ -sin81, -sin82, -sin83, -sin84, -sin85, -sin86, -sin87, -sin88, -sin89, -sin90,
+ -sin89, -sin88, -sin87, -sin86, -sin85, -sin84, -sin83, -sin82, -sin81, -sin80,
+ -sin79, -sin78, -sin77, -sin76, -sin75, -sin74, -sin73, -sin72, -sin71, -sin70,
+ -sin69, -sin68, -sin67, -sin66, -sin65, -sin64, -sin63, -sin62, -sin61, -sin60,
+ -sin59, -sin58, -sin57, -sin56, -sin55, -sin54, -sin53, -sin52, -sin51, -sin50,
+ -sin49, -sin48, -sin47, -sin46, -sin45, -sin44, -sin43, -sin42, -sin41, -sin40,
+ -sin39, -sin38, -sin37, -sin36, -sin35, -sin34, -sin33, -sin32, -sin31, -sin30,
+ -sin29, -sin28, -sin27, -sin26, -sin25, -sin24, -sin23, -sin22, -sin21, -sin20,
+ -sin19, -sin18, -sin17, -sin16, -sin15, -sin14, -sin13, -sin12, -sin11, -sin10,
+ -sin9, -sin8, -sin7, -sin6, -sin5, -sin4, -sin3, -sin2, -sin1, -sin0
+};
+
+double
+gs_sin_degrees(double ang)
+{
+ int ipart;
+
+ if (is_fneg(ang))
+ ang = 180 - ang;
+ ipart = (int)ang;
+ if (ipart >= 360) {
+ int arem = ipart % 360;
+
+ ang -= (ipart - arem);
+ ipart = arem;
+ }
+ return
+ (ang == ipart ? sin_table[ipart] :
+ sin_table[ipart] + (sin_table[ipart + 1] - sin_table[ipart]) *
+ (ang - ipart));
+}
+
+double
+gs_cos_degrees(double ang)
+{
+ int ipart;
+
+ if (is_fneg(ang))
+ ang = 90 - ang;
+ else
+ ang += 90;
+ ipart = (int)ang;
+ if (ipart >= 360) {
+ int arem = ipart % 360;
+
+ ang -= (ipart - arem);
+ ipart = arem;
+ }
+ return
+ (ang == ipart ? sin_table[ipart] :
+ sin_table[ipart] + (sin_table[ipart + 1] - sin_table[ipart]) *
+ (ang - ipart));
+}
+
+void
+gs_sincos_degrees(double ang, gs_sincos_t * psincos)
+{
+ psincos->sin = gs_sin_degrees(ang);
+ psincos->cos = gs_cos_degrees(ang);
+ psincos->orthogonal =
+ (is_fzero(psincos->sin) || is_fzero(psincos->cos));
+}
+
+#else /* we have floating point */
+
+static const int isincos[5] =
+{0, 1, 0, -1, 0};
+
+double
+gs_sin_degrees(double ang)
+{
+ double quot = ang / 90;
+
+ if (floor(quot) == quot) {
+ /*
+ * We need 4.0, rather than 4, here because of non-ANSI compilers.
+ * The & 3 is because quot might be negative.
+ */
+ return isincos[(int)fmod(quot, 4.0) & 3];
+ }
+ return sin(ang * (M_PI / 180));
+}
+
+double
+gs_cos_degrees(double ang)
+{
+ double quot = ang / 90;
+
+ if (floor(quot) == quot) {
+ /* See above re the following line. */
+ return isincos[((int)fmod(quot, 4.0) & 3) + 1];
+ }
+ return cos(ang * (M_PI / 180));
+}
+
+void
+gs_sincos_degrees(double ang, gs_sincos_t * psincos)
+{
+ double quot = ang / 90;
+
+ if (floor(quot) == quot) {
+ /* See above re the following line. */
+ int quads = (int)fmod(quot, 4.0) & 3;
+
+ psincos->sin = isincos[quads];
+ psincos->cos = isincos[quads + 1];
+ psincos->orthogonal = true;
+ } else {
+ double arad = ang * (M_PI / 180);
+
+ psincos->sin = sin(arad);
+ psincos->cos = cos(arad);
+ psincos->orthogonal = false;
+ }
+}
+
+#endif /* USE_FPU */
diff --git a/pstoraster/gsnorop.c b/pstoraster/gsnorop.c
new file mode 100644
index 000000000..7b891142d
--- /dev/null
+++ b/pstoraster/gsnorop.c
@@ -0,0 +1,119 @@
+/* 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$ */
+/* Stubs for unimplemented RasterOp */
+#include "gx.h"
+#include "gserrors.h"
+#include "gsrop.h"
+#include "gxdevcli.h"
+#include "gdevmrop.h"
+
+/* Stub accessors to logical operation in graphics state. */
+
+gs_logical_operation_t
+gs_current_logical_op(const gs_state * pgs)
+{
+ return lop_default;
+}
+
+int
+gs_set_logical_op(gs_state * pgs, gs_logical_operation_t lop)
+{
+ return (lop == lop_default ? 0 : gs_note_error(gs_error_rangecheck));
+}
+
+/* Stub RasterOp implementations for memory devices. */
+
+int
+mem_mono_strip_copy_rop(gx_device * dev,
+ const byte * sdata, int sourcex, uint sraster, gx_bitmap_id id,
+ const gx_color_index * scolors,
+ const gx_strip_bitmap * textures, const gx_color_index * tcolors,
+ int x, int y, int width, int height,
+ int phase_x, int phase_y, gs_logical_operation_t lop)
+{
+ return_error(gs_error_rangecheck);
+}
+
+int
+mem_gray_strip_copy_rop(gx_device * dev,
+ const byte * sdata, int sourcex, uint sraster, gx_bitmap_id id,
+ const gx_color_index * scolors,
+ const gx_strip_bitmap * textures, const gx_color_index * tcolors,
+ int x, int y, int width, int height,
+ int phase_x, int phase_y, gs_logical_operation_t lop)
+{
+ return_error(gs_error_rangecheck);
+}
+
+int
+mem_gray8_rgb24_strip_copy_rop(gx_device * dev,
+ const byte * sdata, int sourcex, uint sraster, gx_bitmap_id id,
+ const gx_color_index * scolors,
+ const gx_strip_bitmap * textures, const gx_color_index * tcolors,
+ int x, int y, int width, int height,
+ int phase_x, int phase_y, gs_logical_operation_t lop)
+{
+ return_error(gs_error_rangecheck);
+}
+
+/* Stub default implementations of device procedures. */
+
+int
+gx_default_copy_rop(gx_device * dev,
+ const byte * sdata, int sourcex, uint sraster, gx_bitmap_id id,
+ const gx_color_index * scolors,
+ const gx_tile_bitmap * texture, const gx_color_index * tcolors,
+ int x, int y, int width, int height,
+ int phase_x, int phase_y, gs_logical_operation_t lop)
+{
+ return_error(gs_error_unknownerror); /* not implemented */
+}
+
+int
+gx_default_strip_copy_rop(gx_device * dev,
+ const byte * sdata, int sourcex, uint sraster, gx_bitmap_id id,
+ const gx_color_index * scolors,
+ const gx_strip_bitmap * textures, const gx_color_index * tcolors,
+ int x, int y, int width, int height,
+ int phase_x, int phase_y, gs_logical_operation_t lop)
+{
+ return_error(gs_error_unknownerror); /* not implemented */
+}
+
+/* Stub RasterOp source devices. */
+
+int
+gx_alloc_rop_texture_device(gx_device_rop_texture ** prsdev, gs_memory_t * mem,
+ client_name_t cname)
+{
+ return_error(gs_error_rangecheck);
+}
+
+void
+gx_make_rop_texture_device(gx_device_rop_texture * dev, gx_device * target,
+ gs_logical_operation_t log_op, const gx_device_color * texture)
+{ /* Never called. */
+}
diff --git a/pstoraster/gspaint.c b/pstoraster/gspaint.c
new file mode 100644
index 000000000..af12ea2c5
--- /dev/null
+++ b/pstoraster/gspaint.c
@@ -0,0 +1,356 @@
+/* Copyright (C) 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$ */
+/* Painting procedures for Ghostscript library */
+#include "math_.h" /* for fabs */
+#include "gx.h"
+#include "gpcheck.h"
+#include "gserrors.h"
+#include "gsropt.h" /* for gxpaint.h */
+#include "gxfixed.h"
+#include "gxmatrix.h" /* for gs_state */
+#include "gspaint.h"
+#include "gspath.h"
+#include "gzpath.h"
+#include "gxpaint.h"
+#include "gzstate.h"
+#include "gxdevice.h"
+#include "gxdevmem.h"
+#include "gxcpath.h"
+
+/* Define the nominal size for alpha buffers. */
+#define abuf_nominal_SMALL 500
+#define abuf_nominal_LARGE 2000
+#if arch_small_memory
+# define abuf_nominal abuf_nominal_SMALL
+#else
+# define abuf_nominal\
+ (gs_debug_c('.') ? abuf_nominal_SMALL : abuf_nominal_LARGE)
+#endif
+
+/* Erase the page */
+int
+gs_erasepage(gs_state * pgs)
+{
+ /*
+ * We can't just fill with device white; we must take the
+ * transfer function into account.
+ */
+ int code;
+
+ if ((code = gs_gsave(pgs)) < 0)
+ return code;
+ if ((code = gs_setgray(pgs, 1.0)) >= 0) {
+ /* Fill the page directly, ignoring clipping. */
+ code = gs_fillpage(pgs);
+ }
+ gs_grestore(pgs);
+ return code;
+}
+
+/* Fill the page with the current color. */
+int
+gs_fillpage(gs_state * pgs)
+{
+ gx_device *dev;
+ int code;
+ gs_logical_operation_t save_lop;
+
+ gx_set_dev_color(pgs);
+ dev = gs_currentdevice(pgs);
+ /* Fill the page directly, ignoring clipping. */
+ /* Use the default RasterOp. */
+ save_lop = pgs->log_op;
+ gs_init_rop(pgs);
+ code = gx_fill_rectangle(0, 0, dev->width, dev->height,
+ pgs->dev_color, pgs);
+ pgs->log_op = save_lop;
+ if (code < 0)
+ return code;
+ return (*dev_proc(dev, sync_output)) (dev);
+}
+
+/*
+ * Determine the number of bits of alpha buffer for a stroke or fill.
+ * We should do alpha buffering iff this value is >1.
+ */
+private int
+alpha_buffer_bits(gs_state * pgs)
+{
+ gx_device *dev;
+
+ if (!color_is_pure(pgs->dev_color))
+ return 0;
+ dev = gs_currentdevice_inline(pgs);
+ if (gs_device_is_abuf(dev)) {
+ /* We're already writing into an alpha buffer. */
+ return 0;
+ }
+ return (*dev_proc(dev, get_alpha_bits)) (dev, go_graphics);
+}
+/*
+ * Set up an alpha buffer for a stroke or fill operation. Return 0
+ * if no buffer could be allocated, 1 if a buffer was installed,
+ * or the usual negative error code.
+ *
+ * The fill/stroke code sets up a clipping device if needed; however,
+ * since we scale up all the path coordinates, we either need to scale up
+ * the clipping region, or do clipping after, rather than before,
+ * alpha buffering. Either of these is a little inconvenient, but
+ * the former is less inconvenient.
+ */
+private int
+scale_paths(gs_state * pgs, int log2_scale_x, int log2_scale_y, bool do_path)
+{
+ if (do_path)
+ gx_path_scale_exp2(pgs->path, log2_scale_x, log2_scale_y);
+ gx_cpath_scale_exp2(pgs->clip_path, log2_scale_x, log2_scale_y);
+ if (pgs->view_clip != 0)
+ gx_cpath_scale_exp2(pgs->view_clip, log2_scale_x, log2_scale_y);
+ if (pgs->effective_clip_path != pgs->clip_path &&
+ pgs->effective_clip_path != pgs->view_clip
+ )
+ gx_cpath_scale_exp2(pgs->effective_clip_path,
+ log2_scale_x, log2_scale_y);
+ return 0;
+}
+private void
+scale_dash_pattern(gs_state * pgs, floatp scale)
+{
+ int i;
+
+ for (i = 0; i < pgs->line_params.dash.pattern_size; ++i)
+ pgs->line_params.dash.pattern[i] *= scale;
+ pgs->line_params.dash.offset *= scale;
+ pgs->line_params.dash.pattern_length *= scale;
+ pgs->line_params.dash.init_dist_left *= scale;
+ if (pgs->line_params.dot_length_absolute)
+ pgs->line_params.dot_length *= scale;
+}
+private int
+alpha_buffer_init(gs_state * pgs, fixed extra_x, fixed extra_y, int alpha_bits)
+{
+ gx_device *dev = gs_currentdevice_inline(pgs);
+ int log2_alpha_bits;
+ gs_fixed_rect bbox;
+ gs_int_rect ibox;
+ uint width, raster, band_space;
+ uint height;
+ gs_log2_scale_point log2_scale;
+ gs_memory_t *mem;
+ gx_device_memory *mdev;
+
+ log2_alpha_bits = alpha_bits >> 1; /* works for 1,2,4 */
+ log2_scale.x = log2_scale.y = log2_alpha_bits;
+ gx_path_bbox(pgs->path, &bbox);
+ ibox.p.x = fixed2int(bbox.p.x - extra_x) - 1;
+ ibox.p.y = fixed2int(bbox.p.y - extra_y) - 1;
+ ibox.q.x = fixed2int_ceiling(bbox.q.x + extra_x) + 1;
+ ibox.q.y = fixed2int_ceiling(bbox.q.y + extra_y) + 1;
+ width = (ibox.q.x - ibox.p.x) << log2_scale.x;
+ raster = bitmap_raster(width);
+ band_space = raster << log2_scale.y;
+ height = (abuf_nominal / band_space) << log2_scale.y;
+ if (height == 0)
+ height = 1 << log2_scale.y;
+ mem = pgs->memory;
+ mdev = gs_alloc_struct(mem, gx_device_memory, &st_device_memory,
+ "alpha_buffer_init");
+ if (mdev == 0)
+ return 0; /* if no room, don't buffer */
+ gs_make_mem_abuf_device(mdev, mem, dev, &log2_scale,
+ alpha_bits, ibox.p.x << log2_scale.x);
+ mdev->width = width;
+ mdev->height = height;
+ mdev->bitmap_memory = mem;
+ if ((*dev_proc(mdev, open_device)) ((gx_device *) mdev) < 0) {
+ /* No room for bits, punt. */
+ gs_free_object(mem, mdev, "alpha_buffer_init");
+ return 0;
+ }
+ gx_set_device_only(pgs, (gx_device *) mdev);
+ scale_paths(pgs, log2_scale.x, log2_scale.y, true);
+ return 1;
+}
+
+/* Release an alpha buffer. */
+private void
+alpha_buffer_release(gs_state * pgs, bool newpath)
+{
+ gx_device_memory *mdev =
+ (gx_device_memory *) gs_currentdevice_inline(pgs);
+
+ (*dev_proc(mdev, close_device)) ((gx_device *) mdev);
+ scale_paths(pgs, -mdev->log2_scale.x, -mdev->log2_scale.y,
+ !(newpath && !gx_path_is_shared(pgs->path)));
+ /* Reference counting will free mdev. */
+ gx_set_device_only(pgs, mdev->target);
+}
+
+/* Fill the current path using a specified rule. */
+private int
+fill_with_rule(gs_state * pgs, int rule)
+{
+ int code;
+
+ /* If we're inside a charpath, just merge the current path */
+ /* into the parent's path. */
+ if (pgs->in_charpath)
+ code = gx_path_add_char_path(pgs->show_gstate->path, pgs->path,
+ pgs->in_charpath);
+ else {
+ int abits, acode;
+
+ gx_set_dev_color(pgs);
+ code = gs_state_color_load(pgs);
+ if (code < 0)
+ return code;
+ abits = alpha_buffer_bits(pgs);
+ if (abits > 1) {
+ acode = alpha_buffer_init(pgs, pgs->fill_adjust.x,
+ pgs->fill_adjust.y, abits);
+ if (acode < 0)
+ return acode;
+ } else
+ acode = 0;
+ code = gx_fill_path(pgs->path, pgs->dev_color, pgs, rule,
+ pgs->fill_adjust.x, pgs->fill_adjust.y);
+ if (acode > 0)
+ alpha_buffer_release(pgs, code >= 0);
+ if (code >= 0)
+ gs_newpath(pgs);
+
+ }
+ return code;
+}
+/* Fill using the winding number rule */
+int
+gs_fill(gs_state * pgs)
+{
+ return fill_with_rule(pgs, gx_rule_winding_number);
+}
+/* Fill using the even/odd rule */
+int
+gs_eofill(gs_state * pgs)
+{
+ return fill_with_rule(pgs, gx_rule_even_odd);
+}
+
+/* Stroke the current path */
+int
+gs_stroke(gs_state * pgs)
+{
+ int code;
+
+ /*
+ * If we're inside a charpath, just merge the current path
+ * into the parent's path.
+ */
+ if (pgs->in_charpath) {
+ if (pgs->in_charpath == cpm_true_charpath) {
+ /*
+ * A stroke inside a true charpath should do the
+ * equivalent of strokepath.
+ */
+ code = gs_strokepath(pgs);
+ if (code < 0)
+ return code;
+ }
+ code = gx_path_add_char_path(pgs->show_gstate->path, pgs->path,
+ pgs->in_charpath);
+ } else {
+ int abits, acode;
+ float orig_width;
+
+ gx_set_dev_color(pgs);
+ code = gs_state_color_load(pgs);
+ if (code < 0)
+ return code;
+ abits = alpha_buffer_bits(pgs);
+ if (abits > 1) {
+ /*
+ * Expand the bounding box by the line width.
+ * This is expensive to compute, so we only do it
+ * if we know we're going to buffer.
+ */
+ float xxyy = fabs(pgs->ctm.xx) + fabs(pgs->ctm.yy);
+ float xyyx = fabs(pgs->ctm.xy) + fabs(pgs->ctm.yx);
+ float scale = 1 << (abits / 2);
+ float new_width =
+ (orig_width = gs_currentlinewidth(pgs)) * scale;
+ fixed extra_adjust =
+ float2fixed(max(xxyy, xyyx) * new_width / 2);
+ gx_path spath;
+
+ /* Scale up the line width and dash pattern. */
+ if (extra_adjust < fixed_1)
+ extra_adjust = fixed_1;
+ acode = alpha_buffer_init(pgs,
+ pgs->fill_adjust.x + extra_adjust,
+ pgs->fill_adjust.y + extra_adjust,
+ abits);
+ if (acode < 0)
+ return acode;
+ gs_setlinewidth(pgs, new_width);
+ scale_dash_pattern(pgs, scale);
+ /*
+ * The alpha-buffer device requires that we fill the
+ * entire path as a single unit.
+ */
+ gx_path_init_local(&spath, pgs->memory);
+ code = gx_stroke_add(pgs->path, &spath, pgs);
+ gs_setlinewidth(pgs, orig_width);
+ scale_dash_pattern(pgs, 1.0 / scale);
+ if (code >= 0)
+ code = gx_fill_path(&spath, pgs->dev_color, pgs,
+ gx_rule_winding_number,
+ pgs->fill_adjust.x,
+ pgs->fill_adjust.y);
+ gx_path_free(&spath, "gs_stroke");
+ if (acode > 0)
+ alpha_buffer_release(pgs, code >= 0);
+ } else
+ code = gx_stroke_fill(pgs->path, pgs);
+ if (code >= 0)
+ gs_newpath(pgs);
+ }
+ return code;
+}
+
+/* Compute the stroked outline of the current path */
+int
+gs_strokepath(gs_state * pgs)
+{
+ gx_path spath;
+ int code;
+
+ gx_path_init_local(&spath, pgs->memory);
+ code = gx_stroke_add(pgs->path, &spath, pgs);
+ if (code < 0) {
+ gx_path_free(&spath, "gs_strokepath");
+ return code;
+ }
+ return gx_path_assign_free(pgs->path, &spath);
+}
diff --git a/pstoraster/gspaint.h b/pstoraster/gspaint.h
new file mode 100644
index 000000000..e7c6df2c1
--- /dev/null
+++ b/pstoraster/gspaint.h
@@ -0,0 +1,38 @@
+/* Copyright (C) 1989, 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$ */
+/* Requires gsstate.h */
+
+#ifndef gspaint_INCLUDED
+# define gspaint_INCLUDED
+
+/* Painting */
+int gs_erasepage(P1(gs_state *)), gs_fillpage(P1(gs_state *)), gs_fill(P1(gs_state *)),
+ gs_eofill(P1(gs_state *)), gs_stroke(P1(gs_state *));
+
+/* Image tracing */
+int gs_imagepath(P4(gs_state *, int, int, const byte *));
+
+#endif /* gspaint_INCLUDED */
diff --git a/pstoraster/gsparam.c b/pstoraster/gsparam.c
new file mode 100644
index 000000000..6631f9651
--- /dev/null
+++ b/pstoraster/gsparam.c
@@ -0,0 +1,382 @@
+/* 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$ */
+/* Support for parameter lists */
+#include "memory_.h"
+#include "string_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsparam.h"
+#include "gsstruct.h"
+
+/* Reset a gs_param_key_t enumerator to its initial state */
+void
+param_init_enumerator(gs_param_enumerator_t * enumerator)
+{
+ memset(enumerator, 0, sizeof(*enumerator));
+}
+
+/* Transfer a collection of parameters. */
+private const byte xfer_item_sizes[] = {
+ GS_PARAM_TYPE_SIZES(0)
+};
+int
+gs_param_read_items(gs_param_list * plist, void *obj,
+ const gs_param_item_t * items)
+{
+ const gs_param_item_t *pi;
+ int ecode = 0;
+
+ for (pi = items; pi->key != 0; ++pi) {
+ const char *key = pi->key;
+ void *pvalue = (void *)((char *)obj + pi->offset);
+ gs_param_typed_value typed;
+ int code;
+
+ typed.type = pi->type;
+ code = param_read_requested_typed(plist, key, &typed);
+ switch (code) {
+ default: /* < 0 */
+ ecode = code;
+ case 1:
+ break;
+ case 0:
+ if (typed.type != pi->type) /* shouldn't happen! */
+ ecode = gs_note_error(gs_error_typecheck);
+ else
+ memcpy(pvalue, &typed.value, xfer_item_sizes[pi->type]);
+ }
+ }
+ return ecode;
+}
+int
+gs_param_write_items(gs_param_list * plist, const void *obj,
+ const void *default_obj, const gs_param_item_t * items)
+{
+ const gs_param_item_t *pi;
+ int ecode = 0;
+
+ for (pi = items; pi->key != 0; ++pi) {
+ const char *key = pi->key;
+ const void *pvalue = (const void *)((const char *)obj + pi->offset);
+ int size = xfer_item_sizes[pi->type];
+ gs_param_typed_value typed;
+ int code;
+
+ if (default_obj != 0 &&
+ !memcmp((const void *)((const char *)default_obj + pi->offset),
+ pvalue, size)
+ )
+ continue;
+ memcpy(&typed.value, pvalue, size);
+ typed.type = pi->type;
+ code = (*plist->procs->xmit_typed) (plist, key, &typed);
+ if (code < 0)
+ ecode = code;
+ }
+ return ecode;
+}
+
+/* Read a value, with coercion if requested, needed, and possible. */
+/* If mem != 0, we can coerce int arrays to float arrays. */
+int
+param_coerce_typed(gs_param_typed_value * pvalue, gs_param_type req_type,
+ gs_memory_t * mem)
+{
+ if (req_type == gs_param_type_any || pvalue->type == req_type)
+ return 0;
+ /*
+ * Look for coercion opportunities. It would be wonderful if we
+ * could convert int/float arrays and name/string arrays, but
+ * right now we can't. However, a 0-length heterogenous array
+ * will satisfy a request for any specific type.
+ */
+ switch (pvalue->type /* actual type */ ) {
+ case gs_param_type_int:
+ switch (req_type) {
+ case gs_param_type_long:
+ pvalue->value.l = pvalue->value.i;
+ goto ok;
+ case gs_param_type_float:
+ pvalue->value.f = (float)pvalue->value.l;
+ goto ok;
+ default:
+ break;
+ }
+ break;
+ case gs_param_type_long:
+ switch (req_type) {
+ case gs_param_type_int:
+#if arch_sizeof_int < arch_sizeof_long
+ if (pvalue->value.l != (int)pvalue->value.l)
+ return_error(gs_error_rangecheck);
+#endif
+ pvalue->value.i = (int)pvalue->value.l;
+ goto ok;
+ case gs_param_type_float:
+ pvalue->value.f = (float)pvalue->value.l;
+ goto ok;
+ default:
+ break;
+ }
+ break;
+ case gs_param_type_string:
+ if (req_type == gs_param_type_name)
+ goto ok;
+ break;
+ case gs_param_type_name:
+ if (req_type == gs_param_type_string)
+ goto ok;
+ break;
+ case gs_param_type_int_array:
+ switch (req_type) {
+ case gs_param_type_float_array:{
+ uint size = pvalue->value.ia.size;
+ float *fv;
+ uint i;
+
+ if (mem == 0)
+ break;
+ fv = (float *)gs_alloc_byte_array(mem, size, sizeof(float),
+ "int array => float array");
+
+ if (fv == 0)
+ return_error(gs_error_VMerror);
+ for (i = 0; i < size; ++i)
+ fv[i] = pvalue->value.ia.data[i];
+ pvalue->value.fa.data = fv;
+ pvalue->value.fa.persistent = false;
+ goto ok;
+ }
+ default:
+ break;
+ }
+ break;
+ case gs_param_type_string_array:
+ if (req_type == gs_param_type_name_array)
+ goto ok;
+ break;
+ case gs_param_type_name_array:
+ if (req_type == gs_param_type_string_array)
+ goto ok;
+ break;
+ case gs_param_type_array:
+ if (pvalue->value.d.size == 0 &&
+ (req_type == gs_param_type_int_array ||
+ req_type == gs_param_type_float_array ||
+ req_type == gs_param_type_string_array ||
+ req_type == gs_param_type_name_array)
+ )
+ goto ok;
+ break;
+ default:
+ break;
+ }
+ return_error(gs_error_typecheck);
+ ok:pvalue->type = req_type;
+ return 0;
+}
+int
+param_read_requested_typed(gs_param_list * plist, gs_param_name pkey,
+ gs_param_typed_value * pvalue)
+{
+ gs_param_type req_type = pvalue->type;
+ int code = (*plist->procs->xmit_typed) (plist, pkey, pvalue);
+
+ if (code != 0)
+ return code;
+ return param_coerce_typed(pvalue, req_type, plist->memory);
+}
+
+
+/* ---------------- Fixed-type reading procedures ---------------- */
+
+#define RETURN_READ_TYPED(alt, ptype)\
+ gs_param_typed_value typed;\
+ int code;\
+\
+ typed.type = ptype;\
+ code = param_read_requested_typed(plist, pkey, &typed);\
+ if ( code == 0 )\
+ *pvalue = typed.value.alt;\
+ return code
+
+int
+param_read_null(gs_param_list * plist, gs_param_name pkey)
+{
+ gs_param_typed_value typed;
+
+ typed.type = gs_param_type_null;
+ return param_read_requested_typed(plist, pkey, &typed);
+}
+int
+param_read_bool(gs_param_list * plist, gs_param_name pkey, bool * pvalue)
+{
+ RETURN_READ_TYPED(b, gs_param_type_bool);
+}
+int
+param_read_int(gs_param_list * plist, gs_param_name pkey, int *pvalue)
+{
+ RETURN_READ_TYPED(i, gs_param_type_int);
+}
+int
+param_read_long(gs_param_list * plist, gs_param_name pkey, long *pvalue)
+{
+ RETURN_READ_TYPED(l, gs_param_type_long);
+}
+int
+param_read_float(gs_param_list * plist, gs_param_name pkey, float *pvalue)
+{
+ RETURN_READ_TYPED(f, gs_param_type_float);
+}
+int
+param_read_string(gs_param_list * plist, gs_param_name pkey,
+ gs_param_string * pvalue)
+{
+ RETURN_READ_TYPED(s, gs_param_type_string);
+}
+int
+param_read_name(gs_param_list * plist, gs_param_name pkey,
+ gs_param_string * pvalue)
+{
+ RETURN_READ_TYPED(n, gs_param_type_string);
+}
+int
+param_read_int_array(gs_param_list * plist, gs_param_name pkey,
+ gs_param_int_array * pvalue)
+{
+ RETURN_READ_TYPED(ia, gs_param_type_int_array);
+}
+int
+param_read_float_array(gs_param_list * plist, gs_param_name pkey,
+ gs_param_float_array * pvalue)
+{
+ RETURN_READ_TYPED(fa, gs_param_type_float_array);
+}
+int
+param_read_string_array(gs_param_list * plist, gs_param_name pkey,
+ gs_param_string_array * pvalue)
+{
+ RETURN_READ_TYPED(sa, gs_param_type_string_array);
+}
+int
+param_read_name_array(gs_param_list * plist, gs_param_name pkey,
+ gs_param_string_array * pvalue)
+{
+ RETURN_READ_TYPED(na, gs_param_type_name_array);
+}
+
+#undef RETURN_READ_TYPED
+
+/* ---------------- Default writing procedures ---------------- */
+
+#define RETURN_WRITE_TYPED(alt, ptype)\
+ gs_param_typed_value typed;\
+\
+ typed.value.alt = *pvalue;\
+ typed.type = ptype;\
+ return param_write_typed(plist, pkey, &typed)
+
+int
+param_write_null(gs_param_list * plist, gs_param_name pkey)
+{
+ gs_param_typed_value typed;
+
+ typed.type = gs_param_type_null;
+ return param_write_typed(plist, pkey, &typed);
+}
+int
+param_write_bool(gs_param_list * plist, gs_param_name pkey, const bool * pvalue)
+{
+ RETURN_WRITE_TYPED(b, gs_param_type_bool);
+}
+int
+param_write_int(gs_param_list * plist, gs_param_name pkey, const int *pvalue)
+{
+ RETURN_WRITE_TYPED(i, gs_param_type_int);
+}
+int
+param_write_long(gs_param_list * plist, gs_param_name pkey, const long *pvalue)
+{
+ RETURN_WRITE_TYPED(l, gs_param_type_long);
+}
+int
+param_write_float(gs_param_list * plist, gs_param_name pkey,
+ const float *pvalue)
+{
+ RETURN_WRITE_TYPED(f, gs_param_type_float);
+}
+int
+param_write_string(gs_param_list * plist, gs_param_name pkey,
+ const gs_param_string * pvalue)
+{
+ RETURN_WRITE_TYPED(s, gs_param_type_string);
+}
+int
+param_write_name(gs_param_list * plist, gs_param_name pkey,
+ const gs_param_string * pvalue)
+{
+ RETURN_WRITE_TYPED(n, gs_param_type_string);
+}
+int
+param_write_int_array(gs_param_list * plist, gs_param_name pkey,
+ const gs_param_int_array * pvalue)
+{
+ RETURN_WRITE_TYPED(ia, gs_param_type_int_array);
+}
+int
+param_write_float_array(gs_param_list * plist, gs_param_name pkey,
+ const gs_param_float_array * pvalue)
+{
+ RETURN_WRITE_TYPED(fa, gs_param_type_float_array);
+}
+int
+param_write_string_array(gs_param_list * plist, gs_param_name pkey,
+ const gs_param_string_array * pvalue)
+{
+ RETURN_WRITE_TYPED(sa, gs_param_type_string_array);
+}
+int
+param_write_name_array(gs_param_list * plist, gs_param_name pkey,
+ const gs_param_string_array * pvalue)
+{
+ RETURN_WRITE_TYPED(na, gs_param_type_name_array);
+}
+
+#undef RETURN_WRITE_TYPED
+
+/* ---------------- Default request implementation ---------------- */
+
+int
+gs_param_request_default(gs_param_list * plist, gs_param_name pkey)
+{
+ return 0;
+}
+
+int
+gs_param_requested_default(const gs_param_list * plist, gs_param_name pkey)
+{
+ return -1; /* requested by default */
+}
diff --git a/pstoraster/gsparam.h b/pstoraster/gsparam.h
new file mode 100644
index 000000000..6b58e7f8a
--- /dev/null
+++ b/pstoraster/gsparam.h
@@ -0,0 +1,505 @@
+/* Copyright (C) 1993, 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$ */
+/* Client interface to parameter dictionaries */
+
+#ifndef gsparam_INCLUDED
+# define gsparam_INCLUDED
+
+/*
+ * Several interfaces use parameter dictionaries to communicate sets of
+ * (key, value) pairs between a client and an object with complex state.
+ * (Several of these correspond directly to similar interfaces in the
+ * PostScript language.) This file defines the API for parameter dictionaries.
+ */
+
+/* ---------------- Generic interfaces ---------------- */
+
+/* Define the abstract type for a parameter list. */
+#ifndef gs_param_list_DEFINED
+# define gs_param_list_DEFINED
+typedef struct gs_param_list_s gs_param_list;
+
+#endif
+
+/* Define the type for a parameter key name. */
+typedef const char *gs_param_name;
+
+/*
+ * Parameter values fall into three categories:
+ * - Scalar (null, Boolean, int, long, float);
+ * - Homogenous collection (string/name, int array, float array,
+ * string/name array);
+ * - Heterogenous collection (dictionary, int-keyed dictionary, array).
+ * Each category has its own representation and memory management issues.
+ */
+typedef enum {
+ /* Scalar */
+ gs_param_type_null, gs_param_type_bool, gs_param_type_int,
+ gs_param_type_long, gs_param_type_float,
+ /* Homogenous collection */
+ gs_param_type_string, gs_param_type_name,
+ gs_param_type_int_array, gs_param_type_float_array,
+ gs_param_type_string_array, gs_param_type_name_array,
+ /* Heterogenous collection */
+ gs_param_type_dict, gs_param_type_dict_int_keys, gs_param_type_array
+} gs_param_type;
+
+/* Define a "don't care" type for reading typed values. */
+#define gs_param_type_any ((gs_param_type)-1)
+
+/*
+ * Define the structures for homogenous collection values
+ * (string/name, integer array, or floating point array).
+ * The size is the number of elements, not the size in bytes.
+ * A value is persistent if it is defined as static const,
+ * or if it is allocated in garbage-collectable space and never freed.
+ */
+
+#define _param_array_struct(sname,etype)\
+ struct sname { const etype *data; uint size; bool persistent; }
+typedef _param_array_struct(gs_param_string_s, byte) gs_param_string;
+typedef _param_array_struct(gs_param_int_array_s, int) gs_param_int_array;
+typedef _param_array_struct(gs_param_float_array_s, float) gs_param_float_array;
+typedef _param_array_struct(gs_param_string_array_s, gs_param_string) gs_param_string_array;
+
+#define param_string_from_string(ps, str)\
+ (ps).data = (const byte *)(str), (ps).size = strlen((const char *)(ps).data),\
+ (ps).persistent = true
+
+/*
+ * Define the structure for heterogenous collection values (dictionaries
+ * and heterogenous arrays).
+ */
+typedef struct gs_param_collection_s {
+ gs_param_list *list;
+ uint size;
+} gs_param_collection;
+typedef gs_param_collection gs_param_dict;
+typedef gs_param_collection gs_param_array;
+
+/*
+ * Define the sizes of the various parameter value types, indexed by type.
+ */
+#define GS_PARAM_TYPE_SIZES(dict_size)\
+ 0, sizeof(bool), sizeof(int), sizeof(long), sizeof(float),\
+ sizeof(gs_param_string), sizeof(gs_param_string),\
+ sizeof(gs_param_int_array), sizeof(gs_param_float_array),\
+ sizeof(gs_param_string_array), sizeof(gs_param_string_array),\
+ (dict_size), (dict_size), (dict_size)
+/*
+ * Define the sizes of the underlying data types contained in or pointed
+ * to by the various value types.
+ */
+#define GS_PARAM_TYPE_BASE_SIZES(dict_elt_size)\
+ 0, sizeof(bool), sizeof(int), sizeof(long), sizeof(float),\
+ 1, 1, sizeof(int), sizeof(float),\
+ sizeof(gs_param_string), sizeof(gs_param_string),\
+ (dict_elt_size), (dict_elt_size), (dict_elt_size)
+
+/* Define tables with 0 for the sizes of the heterogenous collections. */
+extern const byte gs_param_type_sizes[];
+extern const byte gs_param_type_base_sizes[];
+
+/* Define a union capable of holding any parameter value. */
+#define GS_PARAM_VALUE_UNION(dict_type)\
+ bool b;\
+ int i;\
+ long l;\
+ float f;\
+ gs_param_string s;\
+ gs_param_string n;\
+ gs_param_int_array ia;\
+ gs_param_float_array fa;\
+ gs_param_string_array sa;\
+ gs_param_string_array na;\
+ dict_type d
+typedef union gs_param_value_s {
+ GS_PARAM_VALUE_UNION(gs_param_collection);
+} gs_param_value;
+
+/*
+ * Define a structure containing a dynamically typed value (a value along
+ * with its type). Since parameter lists are transient, we don't bother
+ * to create a GC descriptor for this.
+ */
+typedef struct gs_param_typed_value_s {
+ gs_param_value value;
+ gs_param_type type;
+} gs_param_typed_value;
+
+/*
+ * Define the representation alternatives for heterogenous collections.
+ * _any must be 0, for Boolean testing.
+ */
+typedef enum {
+
+ /* Create or accept a general dictionary. */
+
+ gs_param_collection_dict_any = 0,
+
+ /* Create a dictionary with integer string keys ("0", "1", ...); */
+ /* accept a dictionary with integer string keys, or a heterogenous */
+ /* array. */
+
+ gs_param_collection_dict_int_keys = 1,
+
+ /* Create an array if possible, otherwise a dictionary with integer */
+ /* string keys; accept the same types as dict_int_keys. */
+
+ gs_param_collection_array = 2
+
+} gs_param_collection_type_t;
+
+/*
+ * Define the 'policies' for handling out-of-range parameter values.
+ * This is not an enum, because some parameters may recognize other values.
+ */
+#define gs_param_policy_signal_error 0
+#define gs_param_policy_ignore 1
+#define gs_param_policy_consult_user 2
+
+/*
+ * Define an enumerator used to iterate through the keys in a list.
+ *
+ * All the members of the union must be used such that memset(0) entire
+ * union means 'beginning of enumeration'.
+ */
+typedef union gs_param_enumerator_s {
+ int intval;
+ long longval;
+ void *pvoid;
+ char *pchar;
+} gs_param_enumerator_t;
+typedef gs_const_string gs_param_key_t;
+
+/*
+ * Define the object procedures. Note that the same interface is used
+ * both for getting and for setting parameter values. (This is a bit
+ * of a hack, and we might change it someday.) The procedures return
+ * as follows:
+ * - 'reading' procedures ('put' operations from the client's viewpoint)
+ * return 1 for a missing parameter, 0 for a valid parameter, <0 on error.
+ * - 'writing' procedures ('get' operations from the client's viewpoint)
+ * return 0 or 1 if successful, <0 on error.
+ *
+ * A lazy implementation can use the default procedures for scalar and
+ * homogenous collection types: these just called xmit_typed.
+ */
+
+/*
+ * Transmitting variable-size objects requires some extra care.
+ * - When writing an array, string, name, or dictionary, the
+ * implementation (not the client) sets all the fields of the value.
+ * - When reading an array, string, or name, the client must set
+ * all the fields of the value.
+ * - When reading a dictionary, the client must set the size field
+ * before calling begin_write_dict; the implementation of begin_write_dict
+ * allocates the list.
+ */
+
+/*
+ * Setting parameters must use a "two-phase commit" policy. Specifically,
+ * any put_params procedure must observe the following discipline:
+
+ 1. For each parameter known to the device, ask the parameter list if
+ there is a new value, and if so, make all necessary validity checks. If any
+ check fails, call param_signal_error for that parameter, but continue to
+ check further parameters. Normally, this step should not alter the state of
+ the device; however, if the device allows changing any parameters that are
+ read-only by default (for example, BitsPerPixel or ProcessColorModel), or if
+ it replaces the default put_params behavior for any parameter (for example,
+ if it handles MediaSize or Resolution itself to forestall the normal closing
+ of the device when these are set), step 1 of put_params must change the
+ parameters in the device state, and step 2 must undo the changes if
+ returning an error.
+
+ 2. Call the "superclass" put_params routine. For printer devices,
+ this is gdev_prn_put_params; for other devices, it is gx_default_put_params.
+ Note that this must be done even if errors were detected in step 1. If this
+ routine returns an error code, or if step 1 detected an error, undo any
+ changes that step 1 made in the device state, and return the error code.
+
+ 3. Install the new parameter values in the device. If necessary,
+ close the device first; a higher-level routine (gs_putdeviceparams) will
+ reopen the device if necessary.
+
+ */
+
+typedef struct gs_param_list_procs_s {
+
+ /* Transmit a typed value. */
+ /*
+ * Note that read/write_typed do a begin_read/write_collection
+ * if the type is one of the heterogenous collection types.
+ * Note also that even for reading, the caller must set pvalue->type
+ * to the desired type or to gs_param_type_any.
+ */
+
+#define param_proc_xmit_typed(proc)\
+ int proc(P3(gs_param_list *, gs_param_name, gs_param_typed_value *))
+ param_proc_xmit_typed((*xmit_typed));
+ /* See below for param_read_[requested_]typed */
+#define param_write_typed(plist, pkey, pvalue)\
+ (*(plist)->procs->xmit_typed)(plist, pkey, pvalue)
+
+ /* Start transmitting a dictionary or heterogenous value. */
+
+#define param_proc_begin_xmit_collection(proc)\
+ int proc(P4(gs_param_list *, gs_param_name, gs_param_dict *,\
+ gs_param_collection_type_t))
+ param_proc_begin_xmit_collection((*begin_xmit_collection));
+#define param_begin_read_collection(plist, pkey, pvalue, coll_type)\
+ (*(plist)->procs->begin_xmit_collection)(plist, pkey, pvalue, coll_type)
+#define param_begin_read_dict(l, k, v, int_keys)\
+ param_begin_read_collection(l, k, v,\
+ (int_keys ? gs_param_collection_dict_int_keys :\
+ gs_param_collection_dict_any))
+#define param_begin_write_collection(plist, pkey, pvalue, coll_type)\
+ (*(plist)->procs->begin_xmit_collection)(plist, pkey, pvalue, coll_type)
+#define param_begin_write_dict(l, k, v, int_keys)\
+ param_begin_write_collection(l, k, v,\
+ (int_keys ? gs_param_collection_dict_int_keys :\
+ gs_param_collection_dict_any))
+
+ /* Finish transmitting a collection value. */
+
+#define param_proc_end_xmit_collection(proc)\
+ int proc(P3(gs_param_list *, gs_param_name, gs_param_dict *))
+ param_proc_end_xmit_collection((*end_xmit_collection));
+#define param_end_read_collection(plist, pkey, pvalue)\
+ (*(plist)->procs->end_xmit_collection)(plist, pkey, pvalue)
+#define param_end_read_dict(l, k, v) param_end_read_collection(l, k, v)
+#define param_end_write_collection(plist, pkey, pvalue)\
+ (*(plist)->procs->end_xmit_collection)(plist, pkey, pvalue)
+#define param_end_write_dict(l, k, v) param_end_write_collection(l, k, v)
+
+ /*
+ * Get the next key in sequence.
+ * (Only used when reading.)
+ * Use param_init_enumerator(...) to reset to first key.
+ */
+
+#define param_proc_next_key(proc)\
+ int proc(P3(gs_param_list *, gs_param_enumerator_t *, gs_param_key_t *))
+ param_proc_next_key((*next_key));
+#define param_get_next_key(plist, penum, pkey)\
+ (*(plist)->procs->next_key)(plist, penum, pkey)
+
+ /*
+ * Request a specific parameter. (Only used when writing, before
+ * writing any values.) If no specific parameters are requested,
+ * param_requested always returns -1; if specific parameters
+ * are requested, param_requested will return 1 for those,
+ * and may return either 0 or 1 for others.
+ */
+
+#define param_proc_request(proc)\
+ int proc(P2(gs_param_list *, gs_param_name))
+ param_proc_request((*request));
+
+#define param_request(plist, pkey)\
+ ((plist)->procs->request(plist, pkey))
+
+ /*
+ * Determine whether a given key has been requested. (Only used
+ * when writing.) A return value of -1 means that no specific
+ * parameters have been requested; 0 means specific parameters have
+ * been requested, but not this one; 1 means this parameter has
+ * been requested specifically.
+ */
+
+#define param_proc_requested(proc)\
+ int proc(P2(const gs_param_list *, gs_param_name))
+ param_proc_requested((*requested));
+#define param_requested(plist, pkey)\
+ (*(plist)->procs->requested)(plist, pkey)
+
+ /* Get the 'policy' associated with an out-of-range parameter value. */
+ /* (Only used when reading.) */
+
+#define param_proc_get_policy(proc)\
+ int proc(P2(gs_param_list *, gs_param_name))
+ param_proc_get_policy((*get_policy));
+#define param_get_policy(plist, pkey)\
+ (*(plist)->procs->get_policy)(plist, pkey)
+
+ /*
+ * Signal an error. (Only used when reading.)
+ * The procedure may return a different error code,
+ * or may return 0 indicating that the error is to be ignored.
+ */
+
+#define param_proc_signal_error(proc)\
+ int proc(P3(gs_param_list *, gs_param_name, int))
+ param_proc_signal_error((*signal_error));
+#define param_signal_error(plist, pkey, code)\
+ (*(plist)->procs->signal_error)(plist, pkey, code)
+#define param_return_error(plist, pkey, code)\
+ return_error(param_signal_error(plist, pkey, code))
+
+ /*
+ * "Commit" a set of changes. (Only used when reading.)
+ * This is called at the end of the first phase.
+ */
+
+#define param_proc_commit(proc)\
+ int proc(P1(gs_param_list *))
+ param_proc_commit((*commit));
+#define param_commit(plist)\
+ (*(plist)->procs->commit)(plist)
+
+} gs_param_list_procs;
+
+/* Transmit typed parameters. */
+int param_read_requested_typed(P3(gs_param_list *, gs_param_name,
+ gs_param_typed_value *));
+
+#define param_read_typed(plist, pkey, pvalue)\
+ ((pvalue)->type = gs_param_type_any,\
+ param_read_requested_typed(plist, pkey, pvalue))
+
+/* Transmit parameters of specific types. */
+int param_read_null(P2(gs_param_list *, gs_param_name));
+int param_write_null(P2(gs_param_list *, gs_param_name));
+int param_read_bool(P3(gs_param_list *, gs_param_name, bool *));
+int param_write_bool(P3(gs_param_list *, gs_param_name, const bool *));
+int param_read_int(P3(gs_param_list *, gs_param_name, int *));
+int param_write_int(P3(gs_param_list *, gs_param_name, const int *));
+int param_read_long(P3(gs_param_list *, gs_param_name, long *));
+int param_write_long(P3(gs_param_list *, gs_param_name, const long *));
+int param_read_float(P3(gs_param_list *, gs_param_name, float *));
+int param_write_float(P3(gs_param_list *, gs_param_name, const float *));
+int param_read_string(P3(gs_param_list *, gs_param_name, gs_param_string *));
+int param_write_string(P3(gs_param_list *, gs_param_name,
+ const gs_param_string *));
+int param_read_name(P3(gs_param_list *, gs_param_name, gs_param_string *));
+int param_write_name(P3(gs_param_list *, gs_param_name,
+ const gs_param_string *));
+int param_read_int_array(P3(gs_param_list *, gs_param_name,
+ gs_param_int_array *));
+int param_write_int_array(P3(gs_param_list *, gs_param_name,
+ const gs_param_int_array *));
+int param_read_float_array(P3(gs_param_list *, gs_param_name,
+ gs_param_float_array *));
+int param_write_float_array(P3(gs_param_list *, gs_param_name,
+ const gs_param_float_array *));
+int param_read_string_array(P3(gs_param_list *, gs_param_name,
+ gs_param_string_array *));
+int param_write_string_array(P3(gs_param_list *, gs_param_name,
+ const gs_param_string_array *));
+int param_read_name_array(P3(gs_param_list *, gs_param_name,
+ gs_param_string_array *));
+int param_write_name_array(P3(gs_param_list *, gs_param_name,
+ const gs_param_string_array *));
+
+/* Define an abstract parameter dictionary. Implementations are */
+/* concrete subclasses. */
+#define gs_param_list_common\
+ const gs_param_list_procs *procs;\
+ gs_memory_t *memory /* for allocating coerced arrays */
+struct gs_param_list_s {
+ gs_param_list_common;
+};
+
+/* Initialize a parameter list key enumerator. */
+void param_init_enumerator(P1(gs_param_enumerator_t * penum));
+
+/*
+ * The following interface provides a convenient way to read and set
+ * collections of parameters of any type other than dictionaries.
+ */
+
+typedef struct gs_param_item_s {
+ const char *key;
+ byte /*gs_param_type */ type;
+ short offset; /* offset of value in structure */
+} gs_param_item_t;
+#define gs_param_item_end { 0 } /* list terminator */
+/*
+ * Transfer a collection of parameters.
+ * For param_write_items, if a parameter value is equal to the value in
+ * the optional default_obj, the item isn't transferred.
+ */
+int gs_param_read_items(P3(gs_param_list * plist, void *obj,
+ const gs_param_item_t * items));
+int gs_param_write_items(P4(gs_param_list * plist, const void *obj,
+ const void *default_obj,
+ const gs_param_item_t * items));
+
+/* ---------------- Default implementation ---------------- */
+
+/*
+ * Provide default generic implementations of param_request and
+ * param_requested.
+ */
+param_proc_request(gs_param_request_default); /* does nothing */
+param_proc_requested(gs_param_requested_default); /* always returns true */
+
+/*
+ * Define a default implementation, intended to be usable easily
+ * from C code. The intended usage pattern is:
+ gs_c_param_list list;
+ [... other code here ...]
+ gs_c_param_list_write(&list, mem);
+ [As many as needed:]
+ code = param_write_XXX(&list, "ParamName", &param_value);
+ [Check code for <0]
+ gs_c_param_list_read(&list);
+ code = gs_putdeviceparams(dev, &list);
+ gs_c_param_list_release(&list);
+ [Check code for <0]
+ if ( code == 1 )
+ { code = (*dev_proc(dev, open_device))(dev);
+ [Check code for <0]
+ }
+ */
+
+typedef struct gs_c_param_s gs_c_param; /* opaque here */
+typedef struct gs_c_param_list_s {
+ gs_param_list_common;
+ gs_c_param *head;
+ uint count;
+ bool any_requested;
+ gs_param_collection_type_t coll_type;
+} gs_c_param_list;
+#define private_st_c_param_list() /* in gsparam.c */\
+ gs_private_st_ptrs1(st_c_param_list, gs_c_param_list, "c_param_list",\
+ c_param_list_enum_ptrs, c_param_list_reloc_ptrs, head)
+
+/* Clients normally allocate the gs_c_param_list on the stack. */
+void gs_c_param_list_write(P2(gs_c_param_list *, gs_memory_t *));
+void gs_c_param_list_read(P1(gs_c_param_list *)); /* switch to reading */
+void gs_c_param_list_release(P1(gs_c_param_list *));
+
+/*
+ * Internal procedure to read a value, with coercion if requested, needed,
+ * and possible. If mem != 0, we can coerce int arrays to float arrays, and
+ * possibly do other coercions later.
+ */
+int param_coerce_typed(P3(gs_param_typed_value * pvalue,
+ gs_param_type req_type, gs_memory_t * mem));
+
+#endif /* gsparam_INCLUDED */
diff --git a/pstoraster/gsparams.c b/pstoraster/gsparams.c
new file mode 100644
index 000000000..1c58c5a92
--- /dev/null
+++ b/pstoraster/gsparams.c
@@ -0,0 +1,417 @@
+/* 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 parameter list serializer & expander */
+
+/* Initial version 2/1/98 by John Desrosiers (soho@crl.com) */
+
+#include "gx.h"
+#include "memory_.h"
+#include "gserrors.h"
+#include "gsparams.h"
+
+/* ----------- Local Type Decl's ------------ */
+typedef struct {
+ byte *buf; /* current buffer ptr */
+ byte *buf_end; /* end of buffer */
+ unsigned total_sizeof; /* current # bytes in buf */
+} WriteBuffer;
+
+/* ---------- Forward refs ----------- */
+private void
+ align_to(P2(
+ const byte ** src, /* pointer to align */
+ unsigned alignment /* alignment, must be power of 2 */
+ ));
+private void
+ put_word(P2(
+ unsigned source, /* number to put to buffer */
+ WriteBuffer * dest /* destination descriptor */
+ ));
+private void
+ put_bytes(P3(
+ const byte * source, /* bytes to put to buffer */
+ unsigned source_sizeof, /* # bytes to put */
+ WriteBuffer * dest /* destination descriptor */
+ ));
+private void
+ put_alignment(P2(
+ unsigned alignment, /* alignment to match, must be power 2 */
+ WriteBuffer * dest /* destination descriptor */
+ ));
+
+/* Get word compressed with put_word */
+private unsigned /* decompressed word */
+ get_word(P1(
+ const byte ** src /* UPDATES: ptr to src buf ptr */
+ ));
+
+
+/* ------------ Serializer ------------ */
+/* Serialize the contents of a gs_param_list (including sub-dicts) */
+int /* ret -ve err, else # bytes needed to represent param list, whether */
+
+/* or not it actually fit into buffer. List was successully */
+
+/* serialized only if if this # is <= supplied buf size. */
+gs_param_list_serialize(
+ gs_param_list * list, /* root of list to serialize */
+ /* list MUST BE IN READ MODE */
+ byte * buf, /* destination buffer (can be 0) */
+ int buf_sizeof /* # bytes available in buf (can be 0) */
+)
+{
+ int code = 0;
+ int temp_code;
+ gs_param_enumerator_t key_enum;
+ gs_param_key_t key;
+ WriteBuffer write_buf;
+
+ write_buf.buf = buf;
+ write_buf.buf_end = buf + (buf ? buf_sizeof : 0);
+ write_buf.total_sizeof = 0;
+ param_init_enumerator(&key_enum);
+
+ /* Each item is serialized as ("word" means compressed word):
+ * word: key sizeof + 1, or 0 if end of list/dict
+ * word: data type(gs_param_type_xxx)
+ * byte[]: key, including trailing \0
+ * (if simple type)
+ * byte[]: unpacked representation of data
+ * (if simple array or string)
+ * byte[]: unpacked mem image of gs_param_xxx_array structure
+ * pad: to array alignment
+ * byte[]: data associated with array contents
+ * (if string/name array)
+ * byte[]: unpacked mem image of gs_param_string_array structure
+ * pad: to void *
+ * { gs_param_string structure mem image;
+ * data associated with string;
+ * } for each string in array
+ * (if dict/dict_int_keys)
+ * word: # of entries in dict,
+ * pad: to void *
+ * dict entries follow immediately until end-of-dict
+ *
+ * NB that this format is designed to allow using an input buffer
+ * as the direct source of data when expanding a gs_c_param_list
+ */
+ /* Enumerate all the keys; use keys to get their typed values */
+ while ((code = param_get_next_key(list, &key_enum, &key)) == 0) {
+ int value_top_sizeof;
+ int value_base_sizeof;
+
+ /* Get next datum & put its type & key to buffer */
+ gs_param_typed_value value;
+ char string_key[256];
+
+ if (sizeof(string_key) < key.size + 1) {
+ code = gs_note_error(gs_error_rangecheck);
+ break;
+ }
+ memcpy(string_key, key.data, key.size);
+ string_key[key.size] = 0;
+ if ((code = param_read_typed(list, string_key, &value)) != 0) {
+ code = code > 0 ? gs_note_error(gs_error_unknownerror) : code;
+ break;
+ }
+ put_word((unsigned)key.size + 1, &write_buf);
+ put_word((unsigned)value.type, &write_buf);
+ put_bytes((byte *) string_key, key.size + 1, &write_buf);
+
+ /* Put value & its size to buffer */
+ value_top_sizeof = gs_param_type_sizes[value.type];
+ value_base_sizeof = gs_param_type_base_sizes[value.type];
+ switch (value.type) {
+ case gs_param_type_null:
+ case gs_param_type_bool:
+ case gs_param_type_int:
+ case gs_param_type_long:
+ case gs_param_type_float:
+ put_bytes((byte *) & value.value, value_top_sizeof, &write_buf);
+ break;
+
+ case gs_param_type_string:
+ case gs_param_type_name:
+ case gs_param_type_int_array:
+ case gs_param_type_float_array:
+ put_bytes((byte *) & value.value, value_top_sizeof, &write_buf);
+ put_alignment(value_base_sizeof, &write_buf);
+ value_base_sizeof *= value.value.s.size;
+ put_bytes(value.value.s.data, value_base_sizeof, &write_buf);
+ break;
+
+ case gs_param_type_string_array:
+ case gs_param_type_name_array:
+ value_base_sizeof *= value.value.sa.size;
+ put_bytes((const byte *)&value.value, value_top_sizeof, &write_buf);
+ put_alignment(sizeof(void *), &write_buf);
+
+ put_bytes((const byte *)value.value.sa.data, value_base_sizeof,
+ &write_buf);
+ {
+ int str_count;
+ const gs_param_string *sa;
+
+ for (str_count = value.value.sa.size,
+ sa = value.value.sa.data; str_count-- > 0; ++sa)
+ put_bytes(sa->data, sa->size, &write_buf);
+ }
+ break;
+
+ case gs_param_type_dict:
+ case gs_param_type_dict_int_keys:
+ put_word(value.value.d.size, &write_buf);
+ put_alignment(sizeof(void *), &write_buf);
+
+ {
+ int bytes_written =
+ gs_param_list_serialize(value.value.d.list,
+ write_buf.buf,
+ write_buf.buf ? write_buf.buf_end - write_buf.buf : 0);
+
+ temp_code = param_end_read_dict(list,
+ (const char *)key.data,
+ &value.value.d);
+ if (bytes_written < 0)
+ code = bytes_written;
+ else {
+ code = temp_code;
+ if (bytes_written)
+ put_bytes(write_buf.buf, bytes_written, &write_buf);
+ }
+ }
+ break;
+
+ default:
+ code = gs_note_error(gs_error_unknownerror);
+ break;
+ }
+ if (code < 0)
+ break;
+ }
+
+ /* Write end marker, which is an (illegal) 0 key length */
+ if (code >= 0) {
+ put_word(0, &write_buf);
+ code = write_buf.total_sizeof;
+ }
+ return code;
+}
+
+
+/* ------------ Expander --------------- */
+/* Expand a buffer into a gs_param_list (including sub-dicts) */
+int /* ret -ve err, +ve # of chars read from buffer */
+gs_param_list_unserialize(
+ gs_param_list * list, /* root of list to expand to */
+ /* list MUST BE IN WRITE MODE */
+ const byte * buf /* source buffer */
+)
+{
+ int code = 0;
+ const byte *orig_buf = buf;
+
+ do {
+ gs_param_typed_value typed;
+ gs_param_name key;
+ unsigned key_sizeof;
+ int value_top_sizeof;
+ int value_base_sizeof;
+ int temp_code;
+ gs_param_type type;
+
+ /* key length, 0 indicates end of data */
+ key_sizeof = get_word(&buf);
+ if (key_sizeof == 0) /* end of data */
+ break;
+
+ /* data type */
+ type = (gs_param_type) get_word(&buf);
+
+ /* key */
+ key = (gs_param_name) buf;
+ buf += key_sizeof;
+
+ /* Data values */
+ value_top_sizeof = gs_param_type_sizes[type];
+ value_base_sizeof = gs_param_type_base_sizes[type];
+ typed.type = type;
+ if (type != gs_param_type_dict && type != gs_param_type_dict_int_keys) {
+ memcpy(&typed.value, buf, value_top_sizeof);
+ buf += value_top_sizeof;
+ }
+ switch (type) {
+ case gs_param_type_null:
+ case gs_param_type_bool:
+ case gs_param_type_int:
+ case gs_param_type_long:
+ case gs_param_type_float:
+ break;
+
+ case gs_param_type_string:
+ case gs_param_type_name:
+ case gs_param_type_int_array:
+ case gs_param_type_float_array:
+ align_to(&buf, value_base_sizeof);
+ typed.value.s.data = buf;
+ typed.value.s.persistent = false;
+ buf += typed.value.s.size * value_base_sizeof;
+ break;
+
+ case gs_param_type_string_array:
+ case gs_param_type_name_array:
+ align_to(&buf, sizeof(void *));
+
+ typed.value.sa.data = (const gs_param_string *)buf;
+ typed.value.sa.persistent = false;
+ buf += typed.value.s.size * value_base_sizeof;
+ {
+ int str_count;
+ gs_param_string *sa;
+
+ for (str_count = typed.value.sa.size,
+ sa = (gs_param_string *) typed.value.sa.data;
+ str_count-- > 0; ++sa) {
+ sa->data = buf;
+ sa->persistent = false;
+ buf += sa->size;
+ }
+ }
+ break;
+
+ case gs_param_type_dict:
+ case gs_param_type_dict_int_keys:
+ typed.value.d.size = get_word(&buf);
+ code = param_begin_write_dict
+ (list, key, &typed.value.d, type == gs_param_type_dict_int_keys);
+ if (code < 0)
+ break;
+ align_to(&buf, sizeof(void *));
+
+ code = gs_param_list_unserialize(typed.value.d.list, buf);
+ temp_code = param_end_write_dict(list, key, &typed.value.d);
+ if (code >= 0) {
+ buf += code;
+ code = temp_code;
+ }
+ break;
+
+ default:
+ code = gs_note_error(gs_error_unknownerror);
+ break;
+ }
+ if (code < 0)
+ break;
+ if (typed.type != gs_param_type_dict && typed.type != gs_param_type_dict_int_keys)
+ code = param_write_typed(list, key, &typed);
+ }
+ while (code >= 0);
+
+ return code >= 0 ? buf - orig_buf : code;
+}
+
+
+/* ---------- Utility functions -------- */
+
+/* Align a byte pointer on the next Nth byte */
+private void
+align_to(
+ const byte ** src, /* pointer to align */
+ unsigned alignment /* alignment, must be power of 2 */
+)
+{
+ *src += -(int)alignment_mod(*src, alignment) & (alignment - 1);
+}
+
+/* Put compressed word repr to a buffer */
+private void
+put_word(
+ unsigned source, /* number to put to buffer */
+ WriteBuffer * dest /* destination descriptor */
+)
+{
+ do {
+ byte chunk = source & 0x7f;
+
+ if (source >= 0x80)
+ chunk |= 0x80;
+ source >>= 7;
+ ++dest->total_sizeof;
+ if (dest->buf && dest->buf < dest->buf_end)
+ *dest->buf++ = chunk;
+ }
+ while (source != 0);
+}
+
+/* Put array of bytes to buffer */
+private void
+put_bytes(
+ const byte * source, /* bytes to put to buffer */
+ unsigned source_sizeof, /* # bytes to put */
+ WriteBuffer * dest /* destination descriptor */
+)
+{
+ dest->total_sizeof += source_sizeof;
+ if (dest->buf && dest->buf + source_sizeof <= dest->buf_end) {
+ if (dest->buf != source)
+ memcpy(dest->buf, source, source_sizeof);
+ dest->buf += source_sizeof;
+ }
+}
+
+/* Pad destination out to req'd alignment w/zeros */
+private void
+put_alignment(
+ unsigned alignment, /* alignment to match, must be power 2 */
+ WriteBuffer * dest /* destination descriptor */
+)
+{
+ static const byte zero =
+ {0};
+
+ while ((dest->total_sizeof & (alignment - 1)) != 0)
+ put_bytes(&zero, 1, dest);
+}
+
+/* Get word compressed with put_word */
+private unsigned /* decompressed word */
+get_word(
+ const byte ** src /* UPDATES: ptr to src buf ptr */
+)
+{
+ unsigned dest = 0;
+ byte chunk;
+ unsigned shift = 0;
+
+ do {
+ chunk = *(*src)++;
+ dest |= (chunk & 0x7f) << shift;
+ shift += 7;
+ }
+ while (chunk & 0x80);
+
+ return dest;
+}
diff --git a/pstoraster/gsparams.h b/pstoraster/gsparams.h
new file mode 100644
index 000000000..f655364e1
--- /dev/null
+++ b/pstoraster/gsparams.h
@@ -0,0 +1,77 @@
+/* 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$ */
+/* Serializer/expander for gs_parm_list's */
+
+#ifndef gsparams_INCLUDED
+# define gsparams_INCLUDED
+
+/* Initial version 2/1/98 by John Desrosiers (soho@crl.com) */
+/* 8/8/98 L. Peter Deutsch (ghost@aladdin.com) Completely redesigned
+ to use stream rather than buffer API (but retained former API for
+ compatibility as well). */
+
+#include "stream.h"
+#include "gsparam.h"
+
+#if 0 /****************/
+
+/* ------ Future interface, implemented in gsparam2.c ------ */
+
+/*
+ * Serialize the contents of a gs_param_list, including sub-collections,
+ * onto a stream. The list must be in READ mode.
+ */
+int gs_param_list_puts(P2(stream *dest, gs_param_list *list));
+
+/*
+ * Unserialize a parameter list, including sub-collections, from a stream.
+ * The list must be in WRITE mode.
+ */
+int gs_param_list_gets(P3(stream *src, gs_param_list *list, gs_memory_t *mem));
+
+#else /****************/
+
+/* ------ Present interface, implemented in gsparams.c ------ */
+
+/*
+ * Serialize a parameter list into a buffer. Return the actual number
+ * of bytes required to store the list, or a negative error code.
+ * The list was stored successfully iff the return value is positive and
+ * less than or equal to the buffer size. Note that the buffer may be
+ * NULL, in which case nothing is stored (but the size is still returned).
+ */
+int gs_param_list_serialize(P3(gs_param_list *list, byte *buf, int buf_size));
+
+/*
+ * Unserialize a parameter list from a buffer. Return the actual number
+ * of bytes occupied by the list, or a negative error code. The buffer
+ * must be void * aligned.
+ */
+int gs_param_list_unserialize(P2(gs_param_list *list, const byte *buf));
+
+#endif /****************/
+
+#endif /* gsparams_INCLUDED */
diff --git a/pstoraster/gspath.c b/pstoraster/gspath.c
new file mode 100644
index 000000000..845d24352
--- /dev/null
+++ b/pstoraster/gspath.c
@@ -0,0 +1,518 @@
+/* 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$ */
+/* Basic path routines for Ghostscript library */
+#include "gx.h"
+#include "gserrors.h"
+#include "gxfixed.h"
+#include "gxmatrix.h"
+#include "gscoord.h" /* requires gsmatrix.h */
+#include "gzstate.h"
+#include "gzpath.h"
+#include "gxdevice.h" /* for gxcpath.h */
+#include "gxdevmem.h" /* for gs_device_is_memory */
+#include "gzcpath.h"
+
+/* ------ Miscellaneous ------ */
+
+int
+gs_newpath(gs_state * pgs)
+{
+ return gx_path_new(pgs->path);
+}
+
+int
+gs_closepath(gs_state * pgs)
+{
+ gx_path *ppath = pgs->path;
+ int code = gx_path_close_subpath(ppath);
+
+ if (code < 0)
+ return code;
+ if (path_start_outside_range(ppath))
+ path_set_outside_position(ppath, ppath->outside_start.x,
+ ppath->outside_start.y);
+ return code;
+}
+
+int
+gs_upmergepath(gs_state * pgs)
+{
+ return gx_path_add_path(pgs->saved->path, pgs->path);
+}
+
+/* Get the current path (for internal use only). */
+gx_path *
+gx_current_path(const gs_state * pgs)
+{
+ return pgs->path;
+}
+
+/* ------ Points and lines ------ */
+
+/*
+ * Define clamped values for out-of-range coordinates.
+ * Currently the path drawing routines can't handle values
+ * close to the edge of the representable space.
+ */
+#define max_coord_fixed (max_fixed - int2fixed(1000)) /* arbitrary */
+#define min_coord_fixed (-max_coord_fixed)
+private void
+clamp_point(gs_fixed_point * ppt, floatp x, floatp y)
+{
+#define clamp_coord(xy)\
+ ppt->xy = (xy > fixed2float(max_coord_fixed) ? max_coord_fixed :\
+ xy < fixed2float(min_coord_fixed) ? min_coord_fixed :\
+ float2fixed(xy))
+ clamp_coord(x);
+ clamp_coord(y);
+#undef clamp_coord
+}
+
+int
+gs_currentpoint(const gs_state * pgs, gs_point * ppt)
+{
+ gx_path *ppath = pgs->path;
+ int code;
+ gs_fixed_point pt;
+
+ if (path_outside_range(ppath))
+ return gs_itransform((gs_state *) pgs,
+ ppath->outside_position.x,
+ ppath->outside_position.y, ppt);
+ code = gx_path_current_point(pgs->path, &pt);
+ if (code < 0)
+ return code;
+ return gs_itransform((gs_state *) pgs,
+ fixed2float(pt.x), fixed2float(pt.y), ppt);
+}
+
+int
+gs_moveto(gs_state * pgs, floatp x, floatp y)
+{
+ gx_path *ppath = pgs->path;
+ gs_fixed_point pt;
+ int code;
+
+ if ((code = gs_point_transform2fixed(&pgs->ctm, x, y, &pt)) < 0) {
+ if (pgs->clamp_coordinates) { /* Handle out-of-range coordinates. */
+ gs_point opt;
+
+ if (code != gs_error_limitcheck ||
+ (code = gs_transform(pgs, x, y, &opt)) < 0
+ )
+ return code;
+ clamp_point(&pt, opt.x, opt.y);
+ code = gx_path_add_point(ppath, pt.x, pt.y);
+ if (code < 0)
+ return code;
+ path_set_outside_position(ppath, opt.x, opt.y);
+ ppath->outside_start = ppath->outside_position;
+ ppath->start_flags = ppath->state_flags;
+ }
+ return code;
+ }
+ return gx_path_add_point(ppath, pt.x, pt.y);
+}
+
+int
+gs_rmoveto(gs_state * pgs, floatp x, floatp y)
+{
+ gs_fixed_point dpt;
+ int code;
+
+ if ((code = gs_distance_transform2fixed(&pgs->ctm, x, y, &dpt)) < 0 ||
+ (code = gx_path_add_relative_point(pgs->path, dpt.x, dpt.y)) < 0
+ ) { /* Handle all exceptional conditions here. */
+ gs_point upt;
+
+ if ((code = gs_currentpoint(pgs, &upt)) < 0)
+ return code;
+ return gs_moveto(pgs, upt.x + x, upt.y + y);
+ }
+ return code;
+}
+
+int
+gs_lineto(gs_state * pgs, floatp x, floatp y)
+{
+ gx_path *ppath = pgs->path;
+ int code;
+ gs_fixed_point pt;
+
+ if ((code = gs_point_transform2fixed(&pgs->ctm, x, y, &pt)) < 0) {
+ if (pgs->clamp_coordinates) { /* Handle out-of-range coordinates. */
+ gs_point opt;
+
+ if (code != gs_error_limitcheck ||
+ (code = gs_transform(pgs, x, y, &opt)) < 0
+ )
+ return code;
+ clamp_point(&pt, opt.x, opt.y);
+ code = gx_path_add_line(ppath, pt.x, pt.y);
+ if (code < 0)
+ return code;
+ path_set_outside_position(ppath, opt.x, opt.y);
+ }
+ return code;
+ }
+ return gx_path_add_line(pgs->path, pt.x, pt.y);
+}
+
+int
+gs_rlineto(gs_state * pgs, floatp x, floatp y)
+{
+ gx_path *ppath = pgs->path;
+ gs_fixed_point dpt;
+ fixed nx, ny;
+ int code;
+
+ if (!path_position_in_range(ppath) ||
+ (code = gs_distance_transform2fixed(&pgs->ctm, x, y, &dpt)) < 0 ||
+ /* Check for overflow in addition. */
+ (((nx = ppath->position.x + dpt.x) ^ dpt.x) < 0 &&
+ (ppath->position.x ^ dpt.x) >= 0) ||
+ (((ny = ppath->position.y + dpt.y) ^ dpt.y) < 0 &&
+ (ppath->position.y ^ dpt.y) >= 0) ||
+ (code = gx_path_add_line(ppath, nx, ny)) < 0
+ ) { /* Handle all exceptional conditions here. */
+ gs_point upt;
+
+ if ((code = gs_currentpoint(pgs, &upt)) < 0)
+ return code;
+ return gs_lineto(pgs, upt.x + x, upt.y + y);
+ }
+ return code;
+}
+
+/* ------ Curves ------ */
+
+int
+gs_curveto(gs_state * pgs,
+ floatp x1, floatp y1, floatp x2, floatp y2, floatp x3, floatp y3)
+{
+ gs_fixed_point p1, p2, p3;
+ int code1 = gs_point_transform2fixed(&pgs->ctm, x1, y1, &p1);
+ int code2 = gs_point_transform2fixed(&pgs->ctm, x2, y2, &p2);
+ int code3 = gs_point_transform2fixed(&pgs->ctm, x3, y3, &p3);
+ gx_path *ppath = pgs->path;
+
+ if ((code1 | code2 | code3) < 0) {
+ if (pgs->clamp_coordinates) { /* Handle out-of-range coordinates. */
+ gs_point opt1, opt2, opt3;
+ int code;
+
+ if ((code1 < 0 && code1 != gs_error_limitcheck) ||
+ (code1 = gs_transform(pgs, x1, y1, &opt1)) < 0
+ )
+ return code1;
+ if ((code2 < 0 && code2 != gs_error_limitcheck) ||
+ (code2 = gs_transform(pgs, x2, y2, &opt2)) < 0
+ )
+ return code2;
+ if ((code3 < 0 && code3 != gs_error_limitcheck) ||
+ (code3 = gs_transform(pgs, x3, y3, &opt3)) < 0
+ )
+ return code3;
+ clamp_point(&p1, opt1.x, opt1.y);
+ clamp_point(&p2, opt2.x, opt2.y);
+ clamp_point(&p3, opt3.x, opt3.y);
+ code = gx_path_add_curve(ppath,
+ p1.x, p1.y, p2.x, p2.y, p3.x, p3.y);
+ if (code < 0)
+ return code;
+ path_set_outside_position(ppath, opt3.x, opt3.y);
+ return code;
+ } else
+ return (code1 < 0 ? code1 : code2 < 0 ? code2 : code3);
+ }
+ return gx_path_add_curve(ppath,
+ p1.x, p1.y, p2.x, p2.y, p3.x, p3.y);
+}
+
+int
+gs_rcurveto(gs_state * pgs,
+ floatp dx1, floatp dy1, floatp dx2, floatp dy2, floatp dx3, floatp dy3)
+{
+ gx_path *ppath = pgs->path;
+ gs_fixed_point p1, p2, p3;
+ fixed ptx, pty;
+ int code;
+
+/****** SHOULD CHECK FOR OVERFLOW IN ADDITION ******/
+ if (!path_position_in_range(ppath) ||
+ (code = gs_distance_transform2fixed(&pgs->ctm, dx1, dy1, &p1)) < 0 ||
+ (code = gs_distance_transform2fixed(&pgs->ctm, dx2, dy2, &p2)) < 0 ||
+ (code = gs_distance_transform2fixed(&pgs->ctm, dx3, dy3, &p3)) < 0 ||
+ (ptx = ppath->position.x, pty = ppath->position.y,
+ code = gx_path_add_curve(ppath, ptx + p1.x, pty + p1.y,
+ ptx + p2.x, pty + p2.y,
+ ptx + p3.x, pty + p3.y)) < 0
+ ) { /* Handle all exceptional conditions here. */
+ gs_point upt;
+
+ if ((code = gs_currentpoint(pgs, &upt)) < 0)
+ return code;
+ return gs_curveto(pgs, upt.x + dx1, upt.y + dy1,
+ upt.x + dx2, upt.y + dy2,
+ upt.x + dx3, upt.y + dy3);
+ }
+ return code;
+}
+
+/* ------ Clipping ------ */
+
+/* Forward references */
+private int common_clip(P2(gs_state *, int));
+
+/*
+ * Return the effective clipping path of a graphics state. Sometimes this
+ * is the intersection of the clip path and the view clip path; sometimes it
+ * is just the clip path. We aren't sure what the correct algorithm is for
+ * this: for now, we use view clipping unless the current device is a memory
+ * device. This takes care of the most important case, where the current
+ * device is a cache device.
+ */
+int
+gx_effective_clip_path(gs_state * pgs, gx_clip_path ** ppcpath)
+{
+ gs_id view_clip_id =
+ (pgs->view_clip == 0 || pgs->view_clip->rule == 0 ? gs_no_id :
+ pgs->view_clip->id);
+
+ if (gs_device_is_memory(pgs->device)) {
+ *ppcpath = pgs->clip_path;
+ return 0;
+ }
+ if (pgs->effective_clip_id == pgs->clip_path->id &&
+ pgs->effective_view_clip_id == view_clip_id
+ ) {
+ *ppcpath = pgs->effective_clip_path;
+ return 0;
+ }
+ /* Update the cache. */
+ if (view_clip_id == gs_no_id) {
+ if (!pgs->effective_clip_shared)
+ gx_cpath_free(pgs->effective_clip_path, "gx_effective_clip_path");
+ pgs->effective_clip_path = pgs->clip_path;
+ pgs->effective_clip_shared = true;
+ } else {
+ gs_fixed_rect cbox, vcbox;
+
+ gx_cpath_inner_box(pgs->clip_path, &cbox);
+ gx_cpath_outer_box(pgs->view_clip, &vcbox);
+ if (rect_within(vcbox, cbox)) {
+ if (!pgs->effective_clip_shared)
+ gx_cpath_free(pgs->effective_clip_path,
+ "gx_effective_clip_path");
+ pgs->effective_clip_path = pgs->view_clip;
+ pgs->effective_clip_shared = true;
+ } else {
+ /* Construct the intersection of the two clip paths. */
+ int code;
+ gx_clip_path ipath;
+ gx_path vpath;
+ gx_clip_path *npath = pgs->effective_clip_path;
+
+ if (pgs->effective_clip_shared) {
+ npath = gx_cpath_alloc(pgs->memory, "gx_effective_clip_path");
+ if (npath == 0)
+ return_error(gs_error_VMerror);
+ }
+ gx_cpath_init_local(&ipath, pgs->memory);
+ code = gx_cpath_assign_preserve(&ipath, pgs->clip_path);
+ if (code < 0)
+ return code;
+ gx_path_init_local(&vpath, pgs->memory);
+ code = gx_cpath_to_path(pgs->view_clip, &vpath);
+ if (code < 0 ||
+ (code = gx_cpath_clip(pgs, &ipath, &vpath,
+ gx_rule_winding_number)) < 0 ||
+ (code = gx_cpath_assign_free(npath, &ipath)) < 0
+ )
+ DO_NOTHING;
+ gx_path_free(&vpath, "gx_effective_clip_path");
+ gx_cpath_free(&ipath, "gx_effective_clip_path");
+ if (code < 0)
+ return code;
+ pgs->effective_clip_path = npath;
+ pgs->effective_clip_shared = false;
+ }
+ }
+ pgs->effective_clip_id = pgs->clip_path->id;
+ pgs->effective_view_clip_id = view_clip_id;
+ *ppcpath = pgs->effective_clip_path;
+ return 0;
+}
+
+#ifdef DEBUG
+/* Note that we just set the clipping path (internal). */
+private void
+note_set_clip_path(const gs_state * pgs)
+{
+ if (gs_debug_c('P')) {
+ extern void gx_cpath_print(P1(const gx_clip_path *));
+
+ dlprintf("[P]Clipping path:\n");
+ gx_cpath_print(pgs->clip_path);
+ }
+}
+#else
+# define note_set_clip_path(pgs) DO_NOTHING
+#endif
+
+int
+gs_clippath(gs_state * pgs)
+{
+ gx_path cpath;
+ int code;
+
+ gx_path_init_local(&cpath, pgs->memory);
+ code = gx_cpath_to_path(pgs->clip_path, &cpath);
+ if (code >= 0)
+ code = gx_path_assign_free(pgs->path, &cpath);
+ if (code < 0)
+ gx_path_free(&cpath, "gs_clippath");
+ return code;
+}
+
+int
+gs_initclip(gs_state * pgs)
+{
+ gs_fixed_rect box;
+ int code = gx_default_clip_box(pgs, &box);
+
+ if (code < 0)
+ return code;
+ return gx_clip_to_rectangle(pgs, &box);
+}
+
+int
+gs_clip(gs_state * pgs)
+{
+ return common_clip(pgs, gx_rule_winding_number);
+}
+
+int
+gs_eoclip(gs_state * pgs)
+{
+ return common_clip(pgs, gx_rule_even_odd);
+}
+
+private int
+common_clip(gs_state * pgs, int rule)
+{
+ int code = gx_cpath_clip(pgs, pgs->clip_path, pgs->path, rule);
+ if (code < 0)
+ return code;
+ pgs->clip_path->rule = rule;
+ note_set_clip_path(pgs);
+ return 0;
+}
+
+int
+gs_setclipoutside(gs_state * pgs, bool outside)
+{
+ return gx_cpath_set_outside(pgs->clip_path, outside);
+}
+
+bool
+gs_currentclipoutside(const gs_state * pgs)
+{
+ return gx_cpath_is_outside(pgs->clip_path);
+}
+
+/* Establish a rectangle as the clipping path. */
+/* Used by initclip and by the character and Pattern cache logic. */
+int
+gx_clip_to_rectangle(gs_state * pgs, gs_fixed_rect * pbox)
+{
+ int code = gx_cpath_from_rectangle(pgs->clip_path, pbox);
+
+ if (code < 0)
+ return code;
+ pgs->clip_path->rule = gx_rule_winding_number;
+ note_set_clip_path(pgs);
+ return 0;
+}
+
+/* Set the clipping path to the current path, without intersecting. */
+/* This is very inefficient right now. */
+int
+gx_clip_to_path(gs_state * pgs)
+{
+ gs_fixed_rect bbox;
+ int code;
+
+ if ((code = gx_path_bbox(pgs->path, &bbox)) < 0 ||
+ (code = gx_clip_to_rectangle(pgs, &bbox)) < 0 ||
+ (code = gs_clip(pgs)) < 0
+ )
+ return code;
+ note_set_clip_path(pgs);
+ return 0;
+}
+
+/* Get the default clipping box. */
+int
+gx_default_clip_box(const gs_state * pgs, gs_fixed_rect * pbox)
+{
+ register gx_device *dev = gs_currentdevice(pgs);
+ gs_rect bbox;
+ gs_matrix imat;
+ int code;
+
+ if (dev->ImagingBBox_set) { /* Use the ImagingBBox, relative to default user space. */
+ gs_defaultmatrix(pgs, &imat);
+ bbox.p.x = dev->ImagingBBox[0];
+ bbox.p.y = dev->ImagingBBox[1];
+ bbox.q.x = dev->ImagingBBox[2];
+ bbox.q.y = dev->ImagingBBox[3];
+ } else { /* Use the PageSize indented by the HWMargins, */
+ /* relative to unrotated user space adjusted by */
+ /* the Margins. (We suspect this isn't quite right, */
+ /* but the whole issue of "margins" is such a mess that */
+ /* we don't think we can do any better.) */
+ (*dev_proc(dev, get_initial_matrix)) (dev, &imat);
+ /* Adjust for the Margins. */
+ imat.tx += dev->Margins[0] * dev->HWResolution[0] /
+ dev->MarginsHWResolution[0];
+ imat.ty += dev->Margins[1] * dev->HWResolution[1] /
+ dev->MarginsHWResolution[1];
+ bbox.p.x = dev->HWMargins[0];
+ bbox.p.y = dev->HWMargins[1];
+ bbox.q.x = dev->PageSize[0] - dev->HWMargins[2];
+ bbox.q.y = dev->PageSize[1] - dev->HWMargins[3];
+ }
+ code = gs_bbox_transform(&bbox, &imat, &bbox);
+ if (code < 0)
+ return code;
+ /* Round the clipping box so that it doesn't get ceilinged. */
+ pbox->p.x = fixed_rounded(float2fixed(bbox.p.x));
+ pbox->p.y = fixed_rounded(float2fixed(bbox.p.y));
+ pbox->q.x = fixed_rounded(float2fixed(bbox.q.x));
+ pbox->q.y = fixed_rounded(float2fixed(bbox.q.y));
+ return 0;
+}
diff --git a/pstoraster/gspath.h b/pstoraster/gspath.h
new file mode 100644
index 000000000..d736470c8
--- /dev/null
+++ b/pstoraster/gspath.h
@@ -0,0 +1,98 @@
+/* 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 gsstate.h */
+
+#ifndef gspath_INCLUDED
+# define gspath_INCLUDED
+
+#include "gspenum.h"
+
+/* Path constructors */
+int gs_newpath(P1(gs_state *)), gs_moveto(P3(gs_state *, floatp, floatp)),
+ gs_rmoveto(P3(gs_state *, floatp, floatp)), gs_lineto(P3(gs_state *, floatp, floatp)),
+ gs_rlineto(P3(gs_state *, floatp, floatp)), gs_arc(P6(gs_state *, floatp, floatp, floatp, floatp, floatp)),
+ gs_arcn(P6(gs_state *, floatp, floatp, floatp, floatp, floatp)), /*
+ * Because of an obscure bug in the IBM RS/6000 compiler, one (but not both)
+ * bool argument(s) for gs_arc_add must come before the floatp arguments.
+ */
+ gs_arc_add(P8(gs_state *, bool, floatp, floatp, floatp, floatp, floatp, bool)),
+ gs_arcto(P7(gs_state *, floatp, floatp, floatp, floatp, floatp, float[4])),
+ gs_curveto(P7(gs_state *, floatp, floatp, floatp, floatp, floatp, floatp)),
+ gs_rcurveto(P7(gs_state *, floatp, floatp, floatp, floatp, floatp, floatp)),
+ gs_closepath(P1(gs_state *));
+
+/* Imager-level procedures */
+#ifndef gs_imager_state_DEFINED
+# define gs_imager_state_DEFINED
+typedef struct gs_imager_state_s gs_imager_state;
+
+#endif
+#ifndef gx_path_DEFINED
+# define gx_path_DEFINED
+typedef struct gx_path_s gx_path;
+
+#endif
+int gs_imager_arc_add(P9(gx_path * ppath, gs_imager_state * pis,
+ bool clockwise, floatp axc, floatp ayc,
+ floatp arad, floatp aang1, floatp aang2,
+ bool add_line));
+
+#define gs_arc_add_inline(pgs, cw, axc, ayc, arad, aa1, aa2, add)\
+ gs_imager_arc_add((pgs)->path, (gs_imager_state *)(pgs),\
+ cw, axc, ayc, arad, aa1, aa2, add)
+
+/* Add the current path to the path in the previous graphics state. */
+int gs_upmergepath(P1(gs_state *));
+
+/* Path accessors and transformers */
+int gs_currentpoint(P2(const gs_state *, gs_point *)), gs_upathbbox(P3(gs_state *, gs_rect *, bool)),
+ gs_dashpath(P1(gs_state *)), gs_flattenpath(P1(gs_state *)), gs_reversepath(P1(gs_state *)),
+ gs_strokepath(P1(gs_state *));
+
+/* The extra argument for gs_upathbbox controls whether to include */
+/* a trailing moveto in the bounding box. */
+#define gs_pathbbox(pgs, prect)\
+ gs_upathbbox(pgs, prect, false)
+
+/* Path enumeration */
+
+/* This interface conditionally makes a copy of the path. */
+gs_path_enum *
+ gs_path_enum_alloc(P2(gs_memory_t *, client_name_t));
+int gs_path_enum_copy_init(P3(gs_path_enum *, const gs_state *, bool));
+
+#define gs_path_enum_init(penum, pgs)\
+ gs_path_enum_copy_init(penum, pgs, true)
+int gs_path_enum_next(P2(gs_path_enum *, gs_point[3])); /* 0 when done */
+void gs_path_enum_cleanup(P1(gs_path_enum *));
+
+/* Clipping */
+int gs_clippath(P1(gs_state *)), gs_initclip(P1(gs_state *)), gs_clip(P1(gs_state *)),
+ gs_eoclip(P1(gs_state *));
+int gs_setclipoutside(P2(gs_state *, bool));
+bool gs_currentclipoutside(P1(const gs_state *));
+
+#endif /* gspath_INCLUDED */
diff --git a/pstoraster/gspath1.c b/pstoraster/gspath1.c
new file mode 100644
index 000000000..893a4c1f9
--- /dev/null
+++ b/pstoraster/gspath1.c
@@ -0,0 +1,480 @@
+/* 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$ */
+/* Additional PostScript Level 1 path routines for Ghostscript library */
+#include "math_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gxfixed.h"
+#include "gxfarith.h"
+#include "gxmatrix.h"
+#include "gzstate.h"
+#include "gspath.h"
+#include "gzpath.h"
+#include "gscoord.h" /* gs_itransform prototype */
+
+/* ------ Arcs ------ */
+
+/* Conversion parameters */
+#define degrees_to_radians (M_PI / 180.0)
+
+typedef enum {
+ arc_nothing,
+ arc_moveto,
+ arc_lineto
+} arc_action;
+
+typedef struct arc_curve_params_s {
+ /* The following are set once. */
+ gx_path *ppath;
+ gs_imager_state *pis;
+ gs_point center; /* (not used by arc_add) */
+ double radius;
+ /* The following may be updated dynamically. */
+ arc_action action;
+ segment_notes notes;
+ gs_point p0, p3, pt;
+ gs_sincos_t sincos; /* (not used by arc_add) */
+ fixed angle; /* (not used by arc_add) */
+} arc_curve_params_t;
+
+/* Forward declarations */
+private int arc_add(P1(const arc_curve_params_t *));
+
+int
+gs_arc(gs_state * pgs,
+ floatp xc, floatp yc, floatp r, floatp ang1, floatp ang2)
+{
+ return gs_arc_add_inline(pgs, false, xc, yc, r, ang1, ang2, true);
+}
+
+int
+gs_arcn(gs_state * pgs,
+ floatp xc, floatp yc, floatp r, floatp ang1, floatp ang2)
+{
+ return gs_arc_add_inline(pgs, true, xc, yc, r, ang1, ang2, true);
+}
+
+int
+gs_arc_add(gs_state * pgs, bool clockwise, floatp axc, floatp ayc,
+ floatp arad, floatp aang1, floatp aang2, bool add_line)
+{
+ return gs_arc_add_inline(pgs, clockwise, axc, ayc, arad,
+ aang1, aang2, add_line);
+}
+
+/* Compute the next curve as part of an arc. */
+private int
+next_arc_curve(arc_curve_params_t * arc, fixed anext)
+{
+ bool ortho = arc->sincos.orthogonal;
+ double sin0 = arc->sincos.sin, cos0 = arc->sincos.cos;
+ double x0 = arc->p0.x = arc->p3.x;
+ double y0 = arc->p0.y = arc->p3.y;
+ double x3, y3;
+
+ gs_sincos_degrees(fixed2float(anext), &arc->sincos);
+ arc->p3.x = x3 =
+ arc->center.x + arc->radius * arc->sincos.cos;
+ arc->p3.y = y3 =
+ arc->center.y + arc->radius * arc->sincos.sin;
+ if (ortho && arc->sincos.orthogonal) {
+ /* The common tangent point is easy to compute. */
+ if (x0 == arc->center.x)
+ arc->pt.x = x3, arc->pt.y = y0;
+ else
+ arc->pt.x = x0, arc->pt.y = y3;
+ } else {
+ /* Do it the hard way. */
+ double trad = arc->radius *
+ tan(fixed2float(anext - arc->angle) *
+ (degrees_to_radians / 2));
+
+ arc->pt.x = x0 - trad * sin0;
+ arc->pt.y = y0 + trad * cos0;
+ }
+ arc->angle = anext;
+ return arc_add(arc);
+}
+
+int
+gs_imager_arc_add(gx_path * ppath, gs_imager_state * pis, bool clockwise,
+ floatp axc, floatp ayc, floatp arad, floatp aang1, floatp aang2,
+ bool add_line)
+{
+ double ar = arad;
+ fixed ang1 = float2fixed(aang1), ang2 = float2fixed(aang2), anext;
+ double ang1r; /* reduced angle */
+ arc_curve_params_t arc;
+ int code;
+
+ arc.ppath = ppath;
+ arc.pis = pis;
+ arc.center.x = axc;
+ arc.center.y = ayc;
+#define fixed_90 int2fixed(90)
+#define fixed_180 int2fixed(180)
+#define fixed_360 int2fixed(360)
+ if (ar < 0) {
+ ang1 += fixed_180;
+ ang2 += fixed_180;
+ ar = -ar;
+ }
+ arc.radius = ar;
+ arc.action = (add_line ? arc_lineto : arc_moveto);
+ arc.notes = sn_none;
+ ang1r = fixed2float(ang1 % fixed_360);
+ gs_sincos_degrees(ang1r, &arc.sincos);
+ arc.p3.x = axc + ar * arc.sincos.cos;
+ arc.p3.y = ayc + ar * arc.sincos.sin;
+ if (clockwise) {
+ while (ang1 < ang2)
+ ang2 -= fixed_360;
+ if (ang2 < 0) {
+ fixed adjust = round_up(-ang2, fixed_360);
+
+ ang1 += adjust, ang2 += adjust;
+ }
+ arc.angle = ang1;
+ /*
+ * Cut at multiples of 90 degrees. Invariant: ang1 >= ang2 >= 0.
+ */
+ while ((anext = round_down(arc.angle - fixed_epsilon, fixed_90)) > ang2) {
+ code = next_arc_curve(&arc, anext);
+ if (code < 0)
+ return code;
+ arc.action = arc_nothing;
+ arc.notes = sn_not_first;
+ }
+ } else {
+ while (ang2 < ang1)
+ ang2 += fixed_360;
+ if (ang1 < 0) {
+ fixed adjust = round_up(-ang1, fixed_360);
+
+ ang1 += adjust, ang2 += adjust;
+ }
+ arc.angle = ang1;
+ /*
+ * Cut at multiples of 90 degrees. Invariant: 0 <= ang1 <= ang2.
+ * We can't use round_up because of the inchoate definition of
+ * % and / for negative numbers.
+ */
+ while ((anext = round_up(arc.angle + fixed_epsilon, fixed_90)) < ang2) {
+ code = next_arc_curve(&arc, anext);
+ if (code < 0)
+ return code;
+ arc.action = arc_nothing;
+ arc.notes = sn_not_first;
+ }
+ }
+ /*
+ * Do the last curve of the arc.
+ */
+ return next_arc_curve(&arc, ang2);
+}
+
+int
+gs_arcto(gs_state * pgs,
+floatp ax1, floatp ay1, floatp ax2, floatp ay2, floatp arad, float retxy[4])
+{
+ double xt0, yt0, xt2, yt2;
+ gs_point up0;
+
+#define ax0 up0.x
+#define ay0 up0.y
+ /* Transform the current point back into user coordinates. */
+ int code = gs_currentpoint(pgs, &up0);
+
+ if (code < 0)
+ return code;
+ { /* Now we have to compute the tangent points. */
+ /* Basically, the idea is to compute the tangent */
+ /* of the bisector by using tan(x+y) and tan(z/2) */
+ /* formulas, without ever using any trig. */
+ double dx0 = ax0 - ax1, dy0 = ay0 - ay1;
+ double dx2 = ax2 - ax1, dy2 = ay2 - ay1;
+
+ /* Compute the squared lengths from p1 to p0 and p2. */
+ double sql0 = dx0 * dx0 + dy0 * dy0;
+ double sql2 = dx2 * dx2 + dy2 * dy2;
+
+ /* Compute the distance from p1 to the tangent points. */
+ /* This is the only messy part. */
+ double num = dy0 * dx2 - dy2 * dx0;
+ double denom = sqrt(sql0 * sql2) - (dx0 * dx2 + dy0 * dy2);
+
+ /* Check for collinear points. */
+ if (denom == 0) {
+ code = gs_lineto(pgs, ax1, ay1);
+ xt0 = xt2 = ax1;
+ yt0 = yt2 = ay1;
+ } else { /* not collinear */
+ double dist = fabs(arad * num / denom);
+ double l0 = dist / sqrt(sql0), l2 = dist / sqrt(sql2);
+ arc_curve_params_t arc;
+
+ arc.ppath = pgs->path;
+ arc.pis = (gs_imager_state *) pgs;
+ arc.radius = arad;
+ arc.action = arc_lineto;
+ arc.notes = sn_none;
+ if (arad < 0)
+ l0 = -l0, l2 = -l2;
+ arc.p0.x = xt0 = ax1 + dx0 * l0;
+ arc.p0.y = yt0 = ay1 + dy0 * l0;
+ arc.p3.x = xt2 = ax1 + dx2 * l2;
+ arc.p3.y = yt2 = ay1 + dy2 * l2;
+ arc.pt.x = ax1;
+ arc.pt.y = ay1;
+ code = arc_add(&arc);
+ }
+ }
+ if (retxy != 0) {
+ retxy[0] = xt0;
+ retxy[1] = yt0;
+ retxy[2] = xt2;
+ retxy[3] = yt2;
+ }
+ return code;
+}
+
+/* Internal routine for adding an arc to the path. */
+private int
+arc_add(const arc_curve_params_t * arc)
+{
+ gx_path *path = arc->ppath;
+ gs_imager_state *pis = arc->pis;
+ double r = arc->radius;
+ double x0 = arc->p0.x, y0 = arc->p0.y;
+ double x3 = arc->p3.x, y3 = arc->p3.y;
+ double xt = arc->pt.x, yt = arc->pt.y;
+ floatp dx = xt - x0, dy = yt - y0;
+ double dist = dx * dx + dy * dy;
+ double r2 = r * r;
+ floatp fraction;
+ gs_fixed_point p0, p3, pt, cpt;
+ int code;
+
+ /* Compute the fraction coefficient for the curve. */
+ /* See gx_path_add_partial_arc for details. */
+ if (dist >= r2 * 1.0e8) /* almost zero radius; */
+ /* the >= catches dist == r == 0 */
+ fraction = 0.0;
+ else
+ fraction = (4.0 / 3.0) / (1 + sqrt(1 + dist / r2));
+ if_debug8('r',
+ "[r]Arc f=%f p0=(%f,%f) pt=(%f,%f) p3=(%f,%f) action=%d\n",
+ fraction, x0, y0, xt, yt, x3, y3, (int)arc->action);
+ if ((code = gs_point_transform2fixed(&pis->ctm, x0, y0, &p0)) < 0 ||
+ (code = gs_point_transform2fixed(&pis->ctm, x3, y3, &p3)) < 0 ||
+ (code = gs_point_transform2fixed(&pis->ctm, xt, yt, &pt)) < 0 ||
+ (code =
+ (arc->action == arc_nothing ? 0 :
+ arc->action == arc_lineto &&
+ gx_path_current_point(path, &cpt) >= 0 ?
+ gx_path_add_line(path, p0.x, p0.y) :
+ /* action == arc_moveto */
+ gx_path_add_point(path, p0.x, p0.y))) < 0
+ )
+ return code;
+ return gx_path_add_partial_arc_notes(path, p3.x, p3.y, pt.x, pt.y,
+ fraction, arc->notes);
+}
+
+/* ------ Path transformers ------ */
+
+int
+gs_dashpath(gs_state * pgs)
+{
+ gx_path fpath;
+ int code;
+
+ if (gs_currentdash_length(pgs) == 0)
+ return 0; /* no dash pattern */
+ code = gs_flattenpath(pgs);
+ if (code < 0)
+ return code;
+ gx_path_init_local(&fpath, pgs->memory);
+ code = gx_path_add_dash_expansion(pgs->path, &fpath,
+ (gs_imager_state *) pgs);
+ if (code < 0) {
+ gx_path_free(&fpath, "gs_dashpath");
+ return code;
+ }
+ gx_path_assign_free(pgs->path, &fpath);
+ return 0;
+}
+
+int
+gs_flattenpath(gs_state * pgs)
+{
+ gx_path *ppath = pgs->path;
+ gx_path fpath;
+ int code;
+
+ if (!gx_path_has_curves(ppath))
+ return 0; /* nothing to do */
+ gx_path_init_local(&fpath, ppath->memory);
+ code = gx_path_add_flattened_accurate(ppath, &fpath, pgs->flatness,
+ pgs->accurate_curves);
+ if (code < 0) {
+ gx_path_free(&fpath, "gs_flattenpath");
+ return code;
+ }
+ gx_path_assign_free(ppath, &fpath);
+ return 0;
+}
+
+int
+gs_reversepath(gs_state * pgs)
+{
+ gx_path *ppath = pgs->path;
+ gx_path rpath;
+ int code;
+
+ gx_path_init_local(&rpath, ppath->memory);
+ code = gx_path_copy_reversed(ppath, &rpath);
+ if (code < 0) {
+ gx_path_free(&rpath, "gs_reversepath");
+ return code;
+ }
+ gx_path_assign_free(ppath, &rpath);
+ return 0;
+}
+
+/* ------ Accessors ------ */
+
+int
+gs_upathbbox(gs_state * pgs, gs_rect * pbox, bool include_moveto)
+{
+ gs_fixed_rect fbox; /* box in device coordinates */
+ gs_rect dbox;
+ int code = gx_path_bbox(pgs->path, &fbox);
+
+ if (code < 0)
+ return code;
+ /* If the path ends with a moveto and include_moveto is true, */
+ /* include the moveto in the bounding box. */
+ if (path_last_is_moveto(pgs->path) && include_moveto) {
+ gs_fixed_point pt;
+
+ gx_path_current_point_inline(pgs->path, &pt);
+ if (pt.x < fbox.p.x)
+ fbox.p.x = pt.x;
+ if (pt.y < fbox.p.y)
+ fbox.p.y = pt.y;
+ if (pt.x > fbox.q.x)
+ fbox.q.x = pt.x;
+ if (pt.y > fbox.q.y)
+ fbox.q.y = pt.y;
+ }
+ /* Transform the result back to user coordinates. */
+ dbox.p.x = fixed2float(fbox.p.x);
+ dbox.p.y = fixed2float(fbox.p.y);
+ dbox.q.x = fixed2float(fbox.q.x);
+ dbox.q.y = fixed2float(fbox.q.y);
+ return gs_bbox_transform_inverse(&dbox, &ctm_only(pgs), pbox);
+}
+
+/* ------ Enumerators ------ */
+
+/* Start enumerating a path */
+int
+gs_path_enum_copy_init(gs_path_enum * penum, const gs_state * pgs, bool copy)
+{
+ gs_memory_t *mem = pgs->memory;
+
+ if (copy) {
+ gx_path *copied_path =
+ gx_path_alloc(mem, "gs_path_enum_init");
+ int code;
+
+ if (copied_path == 0)
+ return_error(gs_error_VMerror);
+ code = gx_path_copy(pgs->path, copied_path);
+ if (code < 0) {
+ gx_path_free(copied_path, "gs_path_enum_init");
+ return code;
+ }
+ gx_path_enum_init(penum, copied_path);
+ penum->copied_path = copied_path;
+ } else {
+ gx_path_enum_init(penum, pgs->path);
+ }
+ penum->memory = mem;
+ gs_currentmatrix(pgs, &penum->mat);
+ return 0;
+}
+
+/* Enumerate the next element of a path. */
+/* If the path is finished, return 0; */
+/* otherwise, return the element type. */
+int
+gs_path_enum_next(gs_path_enum * penum, gs_point ppts[3])
+{
+ gs_fixed_point fpts[3];
+ int pe_op = gx_path_enum_next(penum, fpts);
+ int code;
+
+ switch (pe_op) {
+ case 0: /* all done */
+ case gs_pe_closepath:
+ break;
+ case gs_pe_curveto:
+ if ((code = gs_point_transform_inverse(
+ fixed2float(fpts[1].x),
+ fixed2float(fpts[1].y),
+ &penum->mat, &ppts[1])) < 0 ||
+ (code = gs_point_transform_inverse(
+ fixed2float(fpts[2].x),
+ fixed2float(fpts[2].y),
+ &penum->mat, &ppts[2])) < 0)
+ return code;
+ /* falls through */
+ case gs_pe_moveto:
+ case gs_pe_lineto:
+ if ((code = gs_point_transform_inverse(
+ fixed2float(fpts[0].x),
+ fixed2float(fpts[0].y),
+ &penum->mat, &ppts[0])) < 0)
+ return code;
+ default: /* error */
+ break;
+ }
+ return pe_op;
+}
+
+/* Clean up after a pathforall. */
+void
+gs_path_enum_cleanup(gs_path_enum * penum)
+{
+ if (penum->copied_path != 0) {
+ gx_path_free(penum->copied_path, "gs_path_enum_cleanup");
+ penum->path = 0;
+ penum->copied_path = 0;
+ }
+}
diff --git a/pstoraster/gspath2.h b/pstoraster/gspath2.h
new file mode 100644
index 000000000..c24074c86
--- /dev/null
+++ b/pstoraster/gspath2.h
@@ -0,0 +1,40 @@
+/* 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 gsmatrix.h */
+
+#ifndef gspath2_INCLUDED
+# define gspath2_INCLUDED
+
+/* Miscellaneous */
+int gs_setbbox(P5(gs_state *, floatp, floatp, floatp, floatp));
+
+/* Rectangles */
+int gs_rectappend(P3(gs_state *, const gs_rect *, uint));
+int gs_rectclip(P3(gs_state *, const gs_rect *, uint));
+int gs_rectfill(P3(gs_state *, const gs_rect *, uint));
+int gs_rectstroke(P4(gs_state *, const gs_rect *, uint, const gs_matrix *));
+
+#endif /* gspath2_INCLUDED */
diff --git a/pstoraster/gspcolor.c b/pstoraster/gspcolor.c
new file mode 100644
index 000000000..f5740b4ce
--- /dev/null
+++ b/pstoraster/gspcolor.c
@@ -0,0 +1,958 @@
+/* Copyright (C) 1993, 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$ */
+/* Pattern color operators and procedures for Ghostscript library */
+#include "math_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsrop.h"
+#include "gsstruct.h"
+#include "gsutil.h" /* for gs_next_ids */
+#include "gxarith.h"
+#include "gxfixed.h"
+#include "gxmatrix.h"
+#include "gxcoord.h" /* for gs_concat, gx_tr'_to_fixed */
+#include "gxcspace.h" /* for gscolor2.h */
+#include "gxcolor2.h"
+#include "gxdcolor.h"
+#include "gxdevice.h"
+#include "gxdevmem.h"
+#include "gxclip2.h"
+#include "gspath.h"
+#include "gxpath.h"
+#include "gxp1fill.h"
+#include "gxpcolor.h"
+#include "gzstate.h"
+#include "gsimage.h"
+#include "gsiparm4.h"
+
+/* GC descriptors */
+private_st_pattern1_template();
+public_st_pattern_instance();
+
+/* Import the Pattern reloading procedure from gxpcmap.c. */
+int gx_pattern_load(P4(gx_device_color *, const gs_imager_state *,
+ gx_device *, gs_color_select_t));
+
+/* Define the Pattern color space. */
+gs_private_st_composite(st_color_space_Pattern, gs_paint_color_space,
+ "gs_color_space_Pattern", cs_Pattern_enum_ptrs, cs_Pattern_reloc_ptrs);
+private cs_proc_num_components(gx_num_components_Pattern);
+private cs_proc_base_space(gx_base_space_Pattern);
+extern cs_proc_remap_color(gx_remap_Pattern);
+private cs_proc_init_color(gx_init_Pattern);
+private cs_proc_restrict_color(gx_restrict_Pattern);
+private cs_proc_install_cspace(gx_install_Pattern);
+private cs_proc_adjust_cspace_count(gx_adjust_cspace_Pattern);
+private cs_proc_adjust_color_count(gx_adjust_color_Pattern);
+const gs_color_space_type gs_color_space_type_Pattern = {
+ gs_color_space_index_Pattern, false, false,
+ &st_color_space_Pattern, gx_num_components_Pattern,
+ gx_base_space_Pattern,
+ gx_init_Pattern, gx_restrict_Pattern,
+ gx_no_concrete_space,
+ gx_no_concretize_color, NULL,
+ gx_remap_Pattern, gx_install_Pattern,
+ gx_adjust_cspace_Pattern, gx_adjust_color_Pattern
+};
+
+/*
+ * Build a PatternType 1 Pattern color space.
+ */
+int
+gs_cspace_build_Pattern1(gs_color_space ** ppcspace,
+ const gs_color_space * pbase_cspace, gs_memory_t * pmem)
+{
+ gs_color_space *pcspace = 0;
+ int code;
+
+ if (pbase_cspace != 0) {
+ if (gs_color_space_num_components(pcspace) < 0) /* Pattern space */
+ return_error(gs_error_rangecheck);
+ }
+ code = gs_cspace_alloc(&pcspace, &gs_color_space_type_Pattern, pmem);
+ if (code < 0)
+ return code;
+ if (pbase_cspace != 0) {
+ pcspace->params.pattern.has_base_space = true;
+ gs_cspace_init_from((gs_color_space *) & (pcspace->params.pattern.base_space),
+ pbase_cspace
+ );
+ } else
+ pcspace->params.pattern.has_base_space = false;
+ *ppcspace = pcspace;
+ return 0;
+}
+
+/* Initialize a PatternType 1 pattern template. */
+void
+gs_pattern1_init(gs_pattern1_template_t * ppat)
+{
+ uid_set_invalid(&ppat->uid);
+ ppat->PaintType = 0; /* mark as PatternType 1 but invalid */
+ ppat->client_data = 0; /* for GC */
+}
+
+/* makepattern */
+private int compute_inst_matrix(P3(gs_pattern_instance * pinst,
+ const gs_state * saved,
+ gs_rect * pbbox));
+private rc_free_proc(rc_free_pattern_instance);
+int
+gs_makepattern(gs_client_color * pcc, const gs_client_pattern * pcp,
+ const gs_matrix * pmat, gs_state * pgs, gs_memory_t * mem)
+{
+ gs_pattern_instance inst;
+ gs_pattern_instance *pinst;
+ gs_state *saved;
+ gs_rect bbox;
+ gs_fixed_rect cbox;
+ int code;
+
+ if (mem == 0)
+ mem = gs_state_memory(pgs);
+ rc_alloc_struct_1(pinst, gs_pattern_instance, &st_pattern_instance,
+ mem, return_error(gs_error_VMerror),
+ "gs_makepattern");
+ pinst->rc.free = rc_free_pattern_instance;
+ inst.rc = pinst->rc;
+ saved = gs_state_copy(pgs, mem);
+ if (saved == 0) {
+ code = gs_note_error(gs_error_VMerror);
+ goto finst;
+ }
+ gs_concat(saved, pmat);
+ gs_newpath(saved);
+ switch (pcp->PaintType) {
+ case 1: /* colored */
+ gs_set_logical_op(saved, lop_default);
+ break;
+ case 2: /* uncolored */
+ gx_set_device_color_1(saved);
+ break;
+ default:
+ code = gs_note_error(gs_error_rangecheck);
+ goto fsaved;
+ }
+ inst.template = *pcp;
+ inst.saved = saved;
+ code = compute_inst_matrix(&inst, saved, &bbox);
+ if (code < 0)
+ goto fsaved;
+#define mat inst.step_matrix
+ if_debug6('t', "[t]step_matrix=[%g %g %g %g %g %g]\n",
+ mat.xx, mat.xy, mat.yx, mat.yy, mat.tx, mat.ty);
+ /* Check for singular stepping matrix. */
+ if (fabs(mat.xx * mat.yy - mat.xy * mat.yx) < 1.0e-6) {
+ code = gs_note_error(gs_error_rangecheck);
+ goto fsaved;
+ }
+ if_debug4('t', "[t]bbox=(%g,%g),(%g,%g)\n",
+ bbox.p.x, bbox.p.y, bbox.q.x, bbox.q.y);
+ {
+ float bbw = bbox.q.x - bbox.p.x;
+ float bbh = bbox.q.y - bbox.p.y;
+
+ /* If the step and the size agree to within 1/2 pixel, */
+ /* make them the same. */
+ inst.size.x = (int)(bbw + 0.8); /* 0.8 is arbitrary */
+ inst.size.y = (int)(bbh + 0.8);
+ if (mat.xy == 0 && mat.yx == 0 &&
+ fabs(fabs(mat.xx) - bbw) < 0.5 &&
+ fabs(fabs(mat.yy) - bbh) < 0.5
+ ) {
+ gs_scale(saved, fabs(inst.size.x / mat.xx),
+ fabs(inst.size.y / mat.yy));
+ code = compute_inst_matrix(&inst, saved, &bbox);
+ if (code < 0)
+ goto fsaved;
+ if_debug2('t',
+ "[t]adjusted XStep & YStep to size=(%d,%d)\n",
+ inst.size.x, inst.size.y);
+ if_debug4('t', "[t]bbox=(%g,%g),(%g,%g)\n",
+ bbox.p.x, bbox.p.y, bbox.q.x, bbox.q.y);
+ }
+ }
+ if ((code = gs_bbox_transform_inverse(&bbox, &mat, &inst.bbox)) < 0)
+ goto fsaved;
+ if_debug4('t', "[t]ibbox=(%g,%g),(%g,%g)\n",
+ inst.bbox.p.x, inst.bbox.p.y, inst.bbox.q.x, inst.bbox.q.y);
+ inst.is_simple = (fabs(mat.xx) == inst.size.x && mat.xy == 0 &&
+ mat.yx == 0 && fabs(mat.yy) == inst.size.y);
+ if_debug6('t',
+ "[t]is_simple? xstep=(%g,%g) ystep=(%g,%g) size=(%d,%d)\n",
+ inst.step_matrix.xx, inst.step_matrix.xy,
+ inst.step_matrix.yx, inst.step_matrix.yy,
+ inst.size.x, inst.size.y);
+ /* Absent other information, instances always require a mask. */
+ inst.uses_mask = true;
+ gx_translate_to_fixed(saved, float2fixed(mat.tx - bbox.p.x),
+ float2fixed(mat.ty - bbox.p.y));
+ mat.tx = bbox.p.x;
+ mat.ty = bbox.p.y;
+#undef mat
+ cbox.p.x = fixed_0;
+ cbox.p.y = fixed_0;
+ cbox.q.x = int2fixed(inst.size.x);
+ cbox.q.y = int2fixed(inst.size.y);
+ code = gx_clip_to_rectangle(saved, &cbox);
+ if (code < 0)
+ goto fsaved;
+ inst.id = gs_next_ids(1);
+ *pinst = inst;
+ pcc->pattern = pinst;
+ return 0;
+#undef mat
+ fsaved:gs_state_free(saved);
+ finst:gs_free_object(mem, pinst, "gs_makepattern");
+ return code;
+}
+/* Compute the stepping matrix and device space instance bounding box */
+/* from the step values and the saved matrix. */
+private int
+compute_inst_matrix(gs_pattern_instance * pinst, const gs_state * saved,
+ gs_rect * pbbox)
+{
+ double xx = pinst->template.XStep * saved->ctm.xx;
+ double xy = pinst->template.XStep * saved->ctm.xy;
+ double yx = pinst->template.YStep * saved->ctm.yx;
+ double yy = pinst->template.YStep * saved->ctm.yy;
+
+ /* Adjust the stepping matrix so all coefficients are >= 0. */
+ if (xx == 0 || yy == 0) { /* We know that both xy and yx are non-zero. */
+ double temp;
+
+ temp = xx, xx = yx, yx = temp;
+ temp = xy, xy = yy, yy = temp;
+ }
+ if (xx < 0)
+ xx = -xx, xy = -xy;
+ if (yy < 0)
+ yx = -yx, yy = -yy;
+ /* Now xx > 0, yy > 0. */
+ pinst->step_matrix.xx = xx;
+ pinst->step_matrix.xy = xy;
+ pinst->step_matrix.yx = yx;
+ pinst->step_matrix.yy = yy;
+ pinst->step_matrix.tx = saved->ctm.tx;
+ pinst->step_matrix.ty = saved->ctm.ty;
+ return gs_bbox_transform(&pinst->template.BBox, &ctm_only(saved),
+ pbbox);
+}
+/* Free the saved gstate when freeing a Pattern instance. */
+private void
+rc_free_pattern_instance(gs_memory_t * mem, void *pinst_void,
+ client_name_t cname)
+{
+ gs_pattern_instance *pinst = pinst_void;
+
+ gs_state_free(pinst->saved);
+ rc_free_struct_only(mem, pinst_void, cname);
+}
+
+/* setpattern */
+int
+gs_setpattern(gs_state * pgs, const gs_client_color * pcc)
+{
+ int code = gs_setpatternspace(pgs);
+
+ if (code < 0)
+ return code;
+ return gs_setcolor(pgs, pcc);
+}
+
+/* setpatternspace */
+/* This does all the work of setpattern except for the final setcolor. */
+int
+gs_setpatternspace(gs_state * pgs)
+{
+ int code = 0;
+
+ if (pgs->color_space->type->index != gs_color_space_index_Pattern) {
+ gs_color_space cs;
+
+ cs.params.pattern.base_space =
+ *(gs_paint_color_space *) pgs->color_space;
+ cs.params.pattern.has_base_space = true;
+ cs.type = &gs_color_space_type_Pattern;
+ code = gs_setcolorspace(pgs, &cs);
+ }
+ return code;
+}
+
+/*
+ * Adjust the reference count of a pattern. This is intended to support
+ * applications (such as PCL) which maintain client colors outside of the
+ * graphic state. Since the pattern instance structure is opaque to these
+ * applications, they need some way to release or retain the instances as
+ * needed.
+ */
+void
+gs_pattern_reference(gs_client_color * pcc, int delta)
+{
+ if (pcc->pattern != 0)
+ rc_adjust(pcc->pattern, delta, "gs_pattern_reference");
+}
+
+/* getpattern */
+/* This is only intended for the benefit of pattern PaintProcs. */
+const gs_client_pattern *
+gs_getpattern(const gs_client_color * pcc)
+{
+ return &pcc->pattern->template;
+}
+
+/*
+ * Code for generating patterns from bitmaps and pixmaps.
+ */
+
+/*
+ * The following structures are realized here only because this is the
+ * first location in which they were needed. Otherwise, there is nothing
+ * about them that is specific to patterns.
+ */
+public_st_gs_bitmap();
+public_st_gs_tile_bitmap();
+public_st_gs_depth_bitmap();
+public_st_gs_tile_depth_bitmap();
+public_st_gx_strip_bitmap();
+
+/*
+ * Structure for holding a gs_depth_bitmap and the corresponding depth and
+ * colorspace information.
+ *
+ * The free_proc pointer is needed to hold the original value of the pattern
+ * instance free structure. This pointer in the pattern instance will be
+ * overwritten with free_pixmap_pattern, which will free the pixmap info
+ * structure when it is freed.
+ */
+typedef struct pixmap_info_s {
+ gs_depth_bitmap bitmap; /* must be first */
+ const gs_color_space *pcspace;
+ uint white_index;
+ void (*free_proc)( gs_memory_t *, void *, client_name_t );
+} pixmap_info;
+
+gs_private_st_suffix_add1(st_pixmap_info,
+ pixmap_info,
+ "pixmap info. struct",
+ pixmap_enum_ptr,
+ pixmap_reloc_ptr,
+ st_gs_depth_bitmap,
+ pcspace
+);
+
+#define st_pixmap_info_max_ptrs (1 + st_tile_bitmap_max_ptrs)
+
+/*
+ * Free routine for pattern instances created from pixmaps. This overwrites
+ * the free procedure originally stored in the pattern instance, and stores
+ * the pointer to that procedure in the pixmap_info structure. This procedure
+ * will call the original procedure, then free the pixmap_info structure.
+ *
+ * Note that this routine does NOT release the data in the original pixmap;
+ * that remains the responsibility of the client.
+ */
+ void
+free_pixmap_pattern(
+ gs_memory_t * pmem,
+ void * pvpinst,
+ client_name_t cname
+)
+{
+ gs_pattern_instance * pinst = (gs_pattern_instance *)pvpinst;
+ const pixmap_info * ppmap = pinst->template.client_data;
+
+ ppmap->free_proc(pmem, pvpinst, cname);
+ gs_free_object(pmem, (void *)ppmap, cname);
+}
+
+/*
+ * PaintProcs for bitmap and pixmap patterns.
+ */
+private int bitmap_paint(P4(gs_image_enum * pen, gs_data_image_t * pim,
+ const gs_depth_bitmap * pbitmap, gs_state * pgs));
+private int
+mask_PaintProc(const gs_client_color * pcolor, gs_state * pgs)
+{
+ const pixmap_info *ppmap = gs_getpattern(pcolor)->client_data;
+ const gs_depth_bitmap *pbitmap = &(ppmap->bitmap);
+ gs_image_enum *pen =
+ gs_image_enum_alloc(gs_state_memory(pgs), "mask_PaintProc");
+ gs_image1_t mask;
+
+ if (pen == 0)
+ return_error(gs_error_VMerror);
+ gs_image_t_init_mask(&mask, true);
+ mask.Width = pbitmap->size.x;
+ mask.Height = pbitmap->size.y;
+ gs_image_init(pen, &mask, false, pgs);
+ return bitmap_paint(pen, (gs_data_image_t *) & mask, pbitmap, pgs);
+}
+private int
+image_PaintProc(const gs_client_color * pcolor, gs_state * pgs)
+{
+ const pixmap_info *ppmap = gs_getpattern(pcolor)->client_data;
+ const gs_depth_bitmap *pbitmap = &(ppmap->bitmap);
+ gs_image_enum *pen =
+ gs_image_enum_alloc(gs_state_memory(pgs), "image_PaintProc");
+ const gs_color_space *pcspace =
+ (ppmap->pcspace == 0 ?
+ gs_cspace_DeviceGray((const gs_imager_state *)pgs) :
+ ppmap->pcspace);
+ gx_image_enum_common_t *pie;
+ gs_image4_t image;
+ int code;
+
+ if (pen == 0)
+ return_error(gs_error_VMerror);
+ gs_image4_t_init(&image, pcspace);
+ image.Width = pbitmap->size.x;
+ image.Height = pbitmap->size.y;
+ image.MaskColor_is_range = false;
+ image.MaskColor[0] = ppmap->white_index;
+ image.Decode[0] = 0;
+ image.Decode[1] = (1 << pbitmap->pix_depth) - 1;
+ image.BitsPerComponent = pbitmap->pix_depth;
+ /* backwards compatibility */
+ if (ppmap->pcspace == 0) {
+ image.Decode[0] = 1.0;
+ image.Decode[1] = 0.0;
+ }
+ code = gs_image_begin_typed((const gs_image_common_t *)&image, pgs,
+ false, &pie);
+ if (code < 0)
+ return code;
+ code = gs_image_common_init(pen, pie, (gs_data_image_t *) & image,
+ gs_state_memory(pgs),
+ (pgs->in_charpath ? NULL :
+ gs_currentdevice_inline(pgs)));
+ if (code < 0)
+ return code;
+ return bitmap_paint(pen, (gs_data_image_t *) & image, pbitmap, pgs);
+}
+/* Finish painting any kind of bitmap pattern. */
+private int
+bitmap_paint(gs_image_enum * pen, gs_data_image_t * pim,
+ const gs_depth_bitmap * pbitmap, gs_state * pgs)
+{
+ uint raster = pbitmap->raster;
+ uint nbytes = (pim->Width * pbitmap->pix_depth + 7) >> 3;
+ uint used;
+ const byte *dp = pbitmap->data;
+ int n;
+ int code = 0;
+
+ if (nbytes == raster)
+ code = gs_image_next(pen, dp, nbytes * pim->Height, &used);
+ else
+ for (n = pim->Height; n > 0 && code >= 0; dp += raster, --n)
+ code = gs_image_next(pen, dp, nbytes, &used);
+ gs_image_cleanup(pen);
+ gs_free_object(gs_state_memory(pgs), pen, "bitmap_paint");
+ return code;
+}
+
+/*
+ * Make a pattern from a bitmap or pixmap. The pattern may be colored or
+ * uncolored, as determined by the mask operand. This code is intended
+ * primarily for use by PCL.
+ *
+ * See the comment prior to the declaration of this function in gscolor2.h
+ * for further information.
+ */
+int
+gs_makepixmappattern(
+ gs_client_color * pcc,
+ const gs_depth_bitmap * pbitmap,
+ bool mask,
+ const gs_matrix * pmat,
+ long id,
+ const gs_color_space * pcspace,
+ uint white_index,
+ gs_state * pgs,
+ gs_memory_t * mem
+)
+{
+
+ gs_client_pattern pat;
+ pixmap_info *ppmap;
+ gs_matrix mat, smat;
+ int code;
+
+ /* check that the data is legitimate */
+ if ((mask) || (pcspace == 0)) {
+ if (pbitmap->pix_depth != 1)
+ return_error(gs_error_rangecheck);
+ pcspace = 0;
+ } else if (gs_color_space_get_index(pcspace) != gs_color_space_index_Indexed)
+ return_error(gs_error_rangecheck);
+ if (pbitmap->num_comps != 1)
+ return_error(gs_error_rangecheck);
+
+ /* allocate and initialize a pixmap_info structure for the paint proc */
+ if (mem == 0)
+ mem = gs_state_memory(pgs);
+ ppmap = gs_alloc_struct(mem,
+ pixmap_info,
+ &st_pixmap_info,
+ "makepximappattern"
+ );
+ if (ppmap == 0)
+ return_error(gs_error_VMerror);
+ ppmap->bitmap = *pbitmap;
+ ppmap->pcspace = pcspace;
+ ppmap->white_index = white_index;
+
+ /* set up the client pattern structure */
+ uid_set_UniqueID(&pat.uid, (id == no_UniqueID) ? gs_next_ids(1) : id);
+ pat.PaintType = (mask ? 2 : 1);
+ pat.TilingType = 1;
+ pat.BBox.p.x = 0;
+ pat.BBox.p.y = 0;
+ pat.BBox.q.x = pbitmap->size.x;
+ pat.BBox.q.y = pbitmap->size.y;
+ pat.XStep = pbitmap->size.x;
+ pat.YStep = pbitmap->size.y;
+ pat.PaintProc = (mask ? mask_PaintProc : image_PaintProc);
+ pat.client_data = ppmap;
+
+ /* set the ctm to be the identity */
+ gs_currentmatrix(pgs, &smat);
+ gs_make_identity(&mat);
+ gs_setmatrix(pgs, &mat);
+
+ /* build the pattern, restore the previous matrix */
+ if (pmat == NULL)
+ pmat = &mat;
+ if ((code = gs_makepattern(pcc, &pat, pmat, pgs, mem)) != 0)
+ gs_free_object(mem, ppmap, "makebitmappattern_xform");
+ else {
+ /*
+ * If this is not a masked pattern and if the white pixel index
+ * is outside of the representable range, we don't need to go to
+ * the trouble of accumulating a mask that will just be all 1s.
+ */
+ if (!mask && (white_index >= (1 << pbitmap->pix_depth)))
+ pcc->pattern->uses_mask = false;
+
+ /* overwrite the free procedure for the pattern instance */
+ ppmap->free_proc = pcc->pattern->rc.free;
+ pcc->pattern->rc.free = free_pixmap_pattern;
+ }
+ gs_setmatrix(pgs, &smat);
+ return code;
+}
+
+/*
+ * Backwards compatibility.
+ */
+int
+gs_makebitmappattern_xform(
+ gs_client_color * pcc,
+ const gx_tile_bitmap * ptile,
+ bool mask,
+ const gs_matrix * pmat,
+ long id,
+ gs_state * pgs,
+ gs_memory_t * mem
+)
+{
+ gs_depth_bitmap bitmap;
+
+ /* build the bitmap the size of one repetition */
+ bitmap.data = ptile->data;
+ bitmap.raster = ptile->raster;
+ bitmap.size.x = ptile->rep_width;
+ bitmap.size.y = ptile->rep_height;
+ bitmap.id = ptile->id; /* shouldn't matter */
+ bitmap.pix_depth = 1;
+ bitmap.num_comps = 1;
+
+ return gs_makepixmappattern(pcc, &bitmap, mask, pmat, id, 0, 0, pgs, mem);
+}
+
+
+/* ------ Color space implementation ------ */
+
+/*
+ * Defined the Pattern device color types. We need a masked analogue of
+ * each of the non-pattern types, to handle uncolored patterns. We use
+ * 'masked_fill_rect' instead of 'masked_fill_rectangle' in order to limit
+ * identifier lengths to 32 characters.
+ */
+private dev_color_proc_load(gx_dc_pattern_load);
+/*dev_color_proc_fill_rectangle(gx_dc_pattern_fill_rectangle); *//*gxp1fill.h */
+private dev_color_proc_equal(gx_dc_pattern_equal);
+private dev_color_proc_load(gx_dc_pure_masked_load);
+
+/*dev_color_proc_fill_rectangle(gx_dc_pure_masked_fill_rect); *//*gxp1fill.h */
+private dev_color_proc_equal(gx_dc_pure_masked_equal);
+private dev_color_proc_load(gx_dc_binary_masked_load);
+
+/*dev_color_proc_fill_rectangle(gx_dc_binary_masked_fill_rect); *//*gxp1fill.h */
+private dev_color_proc_equal(gx_dc_binary_masked_equal);
+private dev_color_proc_load(gx_dc_colored_masked_load);
+
+/*dev_color_proc_fill_rectangle(gx_dc_colored_masked_fill_rect); *//*gxp1fill.h */
+private dev_color_proc_equal(gx_dc_colored_masked_equal);
+
+/* The device color types are exported for gxpcmap.c. */
+gs_private_st_composite(st_dc_pattern, gx_device_color, "dc_pattern",
+ dc_pattern_enum_ptrs, dc_pattern_reloc_ptrs);
+const gx_device_color_type_t gx_dc_pattern = {
+ &st_dc_pattern,
+ gx_dc_pattern_load, gx_dc_pattern_fill_rectangle,
+ gx_dc_default_fill_masked, gx_dc_pattern_equal
+};
+
+extern_st(st_dc_ht_binary);
+gs_private_st_composite(st_dc_pure_masked, gx_device_color, "dc_pure_masked",
+ dc_masked_enum_ptrs, dc_masked_reloc_ptrs);
+const gx_device_color_type_t gx_dc_pure_masked = {
+ &st_dc_pure_masked,
+ gx_dc_pure_masked_load, gx_dc_pure_masked_fill_rect,
+ gx_dc_default_fill_masked, gx_dc_pure_masked_equal
+};
+
+gs_private_st_composite(st_dc_binary_masked, gx_device_color,
+ "dc_binary_masked", dc_binary_masked_enum_ptrs,
+ dc_binary_masked_reloc_ptrs);
+const gx_device_color_type_t gx_dc_binary_masked = {
+ &st_dc_binary_masked,
+ gx_dc_binary_masked_load, gx_dc_binary_masked_fill_rect,
+ gx_dc_default_fill_masked, gx_dc_binary_masked_equal
+};
+
+gs_private_st_composite_only(st_dc_colored_masked, gx_device_color,
+ "dc_colored_masked",
+ dc_masked_enum_ptrs, dc_masked_reloc_ptrs);
+const gx_device_color_type_t gx_dc_colored_masked = {
+ &st_dc_colored_masked,
+ gx_dc_colored_masked_load, gx_dc_colored_masked_fill_rect,
+ gx_dc_default_fill_masked, gx_dc_colored_masked_equal
+};
+
+#undef gx_dc_type_pattern
+const gx_device_color_type_t *const gx_dc_type_pattern = &gx_dc_pattern;
+#define gx_dc_type_pattern (&gx_dc_pattern)
+
+/* GC procedures */
+#define cptr ((gx_device_color *)vptr)
+private
+ENUM_PTRS_BEGIN(dc_pattern_enum_ptrs)
+{
+ return ENUM_USING(st_dc_pure_masked, vptr, size, index - 1);
+}
+case 0:
+{
+ gx_color_tile *tile = cptr->colors.pattern.p_tile;
+
+ ENUM_RETURN((tile == 0 ? tile : tile - tile->index));
+}
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(dc_pattern_reloc_ptrs)
+{
+ gx_color_tile *tile = cptr->colors.pattern.p_tile;
+
+ if (tile != 0) {
+ uint index = tile->index;
+
+ RELOC_TYPED_OFFSET_PTR(gx_device_color, colors.pattern.p_tile, index);
+ }
+ RELOC_USING(st_dc_pure_masked, vptr, size);
+}
+RELOC_PTRS_END
+private ENUM_PTRS_BEGIN(dc_masked_enum_ptrs) ENUM_SUPER(gx_device_color, st_client_color, mask.ccolor, 1);
+case 0:
+{
+ gx_color_tile *mask = cptr->mask.m_tile;
+
+ ENUM_RETURN((mask == 0 ? mask : mask - mask->index));
+}
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(dc_masked_reloc_ptrs)
+{
+ gx_color_tile *mask = cptr->mask.m_tile;
+
+ RELOC_SUPER(gx_device_color, st_client_color, mask.ccolor);
+ if (mask != 0) {
+ uint index = mask->index;
+
+ RELOC_TYPED_OFFSET_PTR(gx_device_color, mask.m_tile, index);
+ }
+}
+RELOC_PTRS_END
+private ENUM_PTRS_BEGIN(dc_binary_masked_enum_ptrs)
+{
+ return ENUM_USING(st_dc_ht_binary, vptr, size, index - 2);
+}
+case 0:
+case 1:
+return ENUM_USING(st_dc_pure_masked, vptr, size, index);
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(dc_binary_masked_reloc_ptrs)
+{
+ RELOC_USING(st_dc_pure_masked, vptr, size);
+ RELOC_USING(st_dc_ht_binary, vptr, size);
+}
+RELOC_PTRS_END
+#undef cptr
+
+/* Macros for pattern loading */
+#define FINISH_PATTERN_LOAD\
+ while ( !gx_pattern_cache_lookup(pdevc, pis, dev, select) )\
+ { code = gx_pattern_load(pdevc, pis, dev, select);\
+ if ( code < 0 ) break;\
+ }\
+ return code;
+
+/* Ensure that a colored Pattern is loaded in the cache. */
+private int
+gx_dc_pattern_load(gx_device_color * pdevc, const gs_imager_state * pis,
+ gx_device * dev, gs_color_select_t select)
+{
+ int code = 0;
+
+ FINISH_PATTERN_LOAD
+}
+/* Ensure that an uncolored Pattern is loaded in the cache. */
+private int
+gx_dc_pure_masked_load(gx_device_color * pdevc, const gs_imager_state * pis,
+ gx_device * dev, gs_color_select_t select)
+{
+ int code = (*gx_dc_type_data_pure.load) (pdevc, pis, dev, select);
+
+ if (code < 0)
+ return code;
+ FINISH_PATTERN_LOAD
+}
+private int
+gx_dc_binary_masked_load(gx_device_color * pdevc, const gs_imager_state * pis,
+ gx_device * dev, gs_color_select_t select)
+{
+ int code = (*gx_dc_type_data_ht_binary.load) (pdevc, pis, dev, select);
+
+ if (code < 0)
+ return code;
+ FINISH_PATTERN_LOAD
+}
+private int
+gx_dc_colored_masked_load(gx_device_color * pdevc, const gs_imager_state * pis,
+ gx_device * dev, gs_color_select_t select)
+{
+ int code = (*gx_dc_type_data_ht_colored.load) (pdevc, pis, dev, select);
+
+ if (code < 0)
+ return code;
+ FINISH_PATTERN_LOAD
+}
+
+/* Look up a pattern color in the cache. */
+bool
+gx_pattern_cache_lookup(gx_device_color * pdevc, const gs_imager_state * pis,
+ gx_device * dev, gs_color_select_t select)
+{
+ gx_pattern_cache *pcache = pis->pattern_cache;
+ gx_bitmap_id id = pdevc->mask.id;
+
+ if (id == gx_no_bitmap_id) {
+ color_set_null_pattern(pdevc);
+ return true;
+ }
+ if (pcache != 0) {
+ gx_color_tile *ctile = &pcache->tiles[id % pcache->num_tiles];
+
+ if (ctile->id == id &&
+ (pdevc->type != &gx_dc_pattern ||
+ ctile->depth == dev->color_info.depth)
+ ) {
+ int px = pis->screen_phase[select].x;
+ int py = pis->screen_phase[select].y;
+
+ if (pdevc->type == &gx_dc_pattern) { /* colored */
+ pdevc->colors.pattern.p_tile = ctile;
+ color_set_phase_mod(pdevc, px, py,
+ ctile->tbits.rep_width,
+ ctile->tbits.rep_height);
+ }
+ pdevc->mask.m_tile =
+ (ctile->tmask.data == 0 ? (gx_color_tile *) 0 :
+ ctile);
+ pdevc->mask.m_phase.x = -px;
+ pdevc->mask.m_phase.y = -py;
+ return true;
+ }
+ }
+ return false;
+}
+
+#undef FINISH_PATTERN_LOAD
+
+/* Compare two Pattern colors for equality. */
+private bool
+gx_dc_pattern_equal(const gx_device_color * pdevc1,
+ const gx_device_color * pdevc2)
+{
+ return pdevc2->type == pdevc1->type &&
+ pdevc1->phase.x == pdevc2->phase.x &&
+ pdevc1->phase.y == pdevc2->phase.y &&
+ pdevc1->mask.id == pdevc2->mask.id;
+}
+private bool
+gx_dc_pure_masked_equal(const gx_device_color * pdevc1,
+ const gx_device_color * pdevc2)
+{
+ return (*gx_dc_type_pure->equal) (pdevc1, pdevc2) &&
+ pdevc1->mask.id == pdevc2->mask.id;
+}
+private bool
+gx_dc_binary_masked_equal(const gx_device_color * pdevc1,
+ const gx_device_color * pdevc2)
+{
+ return (*gx_dc_type_ht_binary->equal) (pdevc1, pdevc2) &&
+ pdevc1->mask.id == pdevc2->mask.id;
+}
+private bool
+gx_dc_colored_masked_equal(const gx_device_color * pdevc1,
+ const gx_device_color * pdevc2)
+{
+ return (*gx_dc_type_ht_colored->equal) (pdevc1, pdevc2) &&
+ pdevc1->mask.id == pdevc2->mask.id;
+}
+
+/*
+ * Get the number of components in a Pattern color.
+ * For backward compatibility, and to distinguish Pattern color spaces
+ * from all others, we negate the result.
+ */
+private int
+gx_num_components_Pattern(const gs_color_space * pcs)
+{
+ return
+ (pcs->params.pattern.has_base_space ?
+ -1 - cs_num_components((const gs_color_space *)
+ &(pcs->params.pattern.base_space)) :
+ -1 /* Pattern dictionary only */ );
+}
+
+/* Get the base space of a Pattern color space. */
+private const gs_color_space *
+gx_base_space_Pattern(const gs_color_space * pcs)
+{
+ return
+ (pcs->params.pattern.has_base_space ?
+ (const gs_color_space *)&(pcs->params.pattern.base_space) :
+ NULL);
+}
+
+/* Initialize a Pattern color. */
+private void
+gx_init_Pattern(gs_client_color * pcc, const gs_color_space * pcs)
+{
+ if (pcs->params.pattern.has_base_space) {
+ const gs_color_space *pbcs =
+ (const gs_color_space *)&pcs->params.pattern.base_space;
+
+ cs_init_color(pcc, pbcs);
+ }
+ /*pcc->pattern = 0; *//* cs_full_init_color handles this */
+}
+
+/* Force a Pattern color into legal range. */
+/* Note that if the pattern is uncolored (PaintType = 2), */
+/* the color space must have a base space: we check this here only */
+/* to prevent accessing uninitialized data, but if there is no base space, */
+/* it is an error that we count on being detected elsewhere. */
+private void
+gx_restrict_Pattern(gs_client_color * pcc, const gs_color_space * pcs)
+{
+ if (pcc->pattern->template.PaintType == 2 &&
+ pcs->params.pattern.has_base_space
+ ) {
+ const gs_color_space *pbcs =
+ (const gs_color_space *)&pcs->params.pattern.base_space;
+
+ (*pbcs->type->restrict_color) (pcc, pbcs);
+ }
+}
+
+/* Install a Pattern color space. */
+private int
+gx_install_Pattern(gs_color_space * pcs, gs_state * pgs)
+{
+ if (!pcs->params.pattern.has_base_space)
+ return 0;
+ return (*pcs->params.pattern.base_space.type->install_cspace)
+ ((gs_color_space *) & pcs->params.pattern.base_space, pgs);
+}
+
+/* Adjust the reference counts for Pattern color spaces or colors. */
+private void
+gx_adjust_cspace_Pattern(const gs_color_space * pcs, int delta)
+{
+ if (pcs->params.pattern.has_base_space)
+ (*pcs->params.pattern.base_space.type->adjust_cspace_count)
+ ((const gs_color_space *)&pcs->params.pattern.base_space, delta);
+}
+
+private void
+gx_adjust_color_Pattern(const gs_client_color * pcc,
+ const gs_color_space * pcs, int delta)
+{
+ gs_pattern_instance *pinst = pcc->pattern;
+
+ rc_adjust_only(pinst, delta, "gx_adjust_color_Pattern");
+ if (pcs && pcs->params.pattern.has_base_space)
+ (*pcs->params.pattern.base_space.type->adjust_color_count)
+ (pcc, (const gs_color_space *)&pcs->params.pattern.base_space,
+ delta);
+}
+
+/* GC procedures */
+
+#define pcs ((gs_color_space *)vptr)
+
+private
+ENUM_PTRS_BEGIN_PROC(cs_Pattern_enum_ptrs)
+{
+ if (!pcs->params.pattern.has_base_space)
+ return 0;
+ return ENUM_USING(*pcs->params.pattern.base_space.type->stype,
+ &pcs->params.pattern.base_space,
+ sizeof(pcs->params.pattern.base_space), index);
+}
+ENUM_PTRS_END_PROC
+private RELOC_PTRS_BEGIN(cs_Pattern_reloc_ptrs)
+{
+ if (!pcs->params.pattern.has_base_space)
+ return;
+ RELOC_USING(*pcs->params.pattern.base_space.type->stype,
+ &pcs->params.pattern.base_space,
+ sizeof(gs_paint_color_space));
+}
+RELOC_PTRS_END
+
+#undef pcs
diff --git a/pstoraster/gspcolor.h b/pstoraster/gspcolor.h
new file mode 100644
index 000000000..fb6ad3f38
--- /dev/null
+++ b/pstoraster/gspcolor.h
@@ -0,0 +1,87 @@
+/* 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$ */
+/* Client interface to Pattern color */
+
+#ifndef gspcolor_INCLUDED
+# define gspcolor_INCLUDED
+
+#include "gsccolor.h"
+#include "gsuid.h"
+
+/* ---------------- Types and structures ---------------- */
+
+/*
+ * Unfortunately, we defined the gs_client_pattern structure before we
+ * realized that we would have to accommodate multiple PatternTypes.
+ * Consequently, we distinguish the different PatternTypes with a hack.
+ * We know that PatternType 1 patterns always have a positive PaintType.
+ * Therefore, we overlay the PaintType field of PatternType 1 patterns
+ * with the negative of the PatternType for generalized patterns.
+ * This allows us to distinguish PatternType 1 patterns from all others.
+ * This is a really bad hack, but doing anything else would require
+ * a non-backward-compatible change for clients, since we didn't
+ * require clients to use a procedure to initialize Patterns (another
+ * mistake, in retrospect, which we've now also fixed).
+ */
+
+/* General pattern template (called "prototype pattern" in Red Book) */
+typedef struct gs_pattern_type_s gs_pattern_type_t;
+
+#define gs_pattern_template_common\
+ gs_uid uid; /* must be first in case we ever subclass properly */\
+ int negPatternType; /* overlays PaintType, see above */\
+ const gs_pattern_type_t *type
+#define PatternType(ppt)\
+ ((ppt)->negPatternType < 0 ? -(ppt)->negPatternType : 1)
+typedef struct gs_pattern_template_s {
+ gs_pattern_template_common;
+} gs_pattern_template_t;
+
+/* ---------------- Procedures ---------------- */
+
+/* Set a Pattern color or a Pattern color space. */
+int gs_setpattern(P2(gs_state *, const gs_client_color *));
+int gs_setpatternspace(P1(gs_state *));
+
+/*
+ * The gs_memory_t argument for gs_make_pattern may be NULL, meaning use the
+ * same allocator as for the gs_state argument. Note that gs_make_pattern
+ * uses rc_alloc_struct_1 to allocate pattern instances.
+ */
+int gs_make_pattern(P5(gs_client_color *, const gs_pattern_template_t *,
+ const gs_matrix *, gs_state *, gs_memory_t *));
+const gs_pattern_template_t *gs_get_pattern(P1(const gs_client_color *));
+
+/*
+ * Adjust the reference count of a pattern. This is intended to support
+ * applications (such as PCL) which maintain client colors outside of the
+ * graphic state. Since the pattern instance structure is opaque to these
+ * applications, they need some way to release or retain the instances as
+ * needed.
+ */
+void gs_pattern_reference(P2(gs_client_color * pcc, int delta));
+
+#endif /* gspcolor_INCLUDED */
diff --git a/pstoraster/gspenum.h b/pstoraster/gspenum.h
new file mode 100644
index 000000000..935a25160
--- /dev/null
+++ b/pstoraster/gspenum.h
@@ -0,0 +1,40 @@
+/* Copyright (C) 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of GNU Ghostscript.
+
+ GNU Ghostscript is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
+ to anyone for the consequences of using it or for whether it serves any
+ particular purpose or works at all, unless he says so in writing. Refer
+ to the GNU General Public License for full details.
+
+ Everyone is granted permission to copy, modify and redistribute GNU
+ Ghostscript, but only under the conditions described in the GNU General
+ Public License. A copy of this license is supposed to have been given
+ to you along with GNU Ghostscript so you can know your rights and
+ responsibilities. It should be in a file named COPYING. Among other
+ things, the copyright notice and this notice must be preserved on all
+ copies.
+
+ Aladdin Enterprises 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 client interface to path enumeration */
+
+#ifndef gspenum_INCLUDED
+# define gspenum_INCLUDED
+
+/* Define the path element types. */
+#define gs_pe_moveto 1
+#define gs_pe_lineto 2
+#define gs_pe_curveto 3
+#define gs_pe_closepath 4
+
+/* Define an abstract type for the path enumerator. */
+typedef struct gs_path_enum_s gs_path_enum;
+
+#endif /* gspenum_INCLUDED */
diff --git a/pstoraster/gspmdrv.h b/pstoraster/gspmdrv.h
new file mode 100644
index 000000000..3e050cebf
--- /dev/null
+++ b/pstoraster/gspmdrv.h
@@ -0,0 +1,40 @@
+/* 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$ */
+/* Definitions common to gspmdrv.c and gspmdrv.rc */
+
+#ifndef gspmdrv_INCLUDED
+# define gspmdrv_INCLUDED
+
+#define GSPMDRV_VERSION "1994-02-09"
+
+#define IDM_ABOUT 5
+#define IDM_COPY 6
+
+#define IDD_ABOUT IDM_ABOUT
+
+#define ID_GSPMDRV 1000
+
+#endif /* gspmdrv_INCLUDED */
diff --git a/pstoraster/gsptype1.h b/pstoraster/gsptype1.h
new file mode 100644
index 000000000..38e81b3ba
--- /dev/null
+++ b/pstoraster/gsptype1.h
@@ -0,0 +1,143 @@
+/* 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$ */
+/* Client interface to PatternType 1 Patterns */
+
+#ifndef gsptype1_INCLUDED
+# define gsptype1_INCLUDED
+
+#include "gspcolor.h"
+#include "gxbitmap.h"
+
+/* ---------------- Types and structures ---------------- */
+
+/* PatternType 1 template */
+typedef struct gs_pattern1_template_s {
+ gs_uid uid; /* must be first, see gspcolor.h */
+ int PaintType; /* must be second, ditto */
+ int TilingType;
+ gs_rect BBox;
+ float XStep;
+ float YStep;
+ int (*PaintProc) (P2(const gs_client_color *, gs_state *));
+ void *client_data; /* additional client data */
+} gs_pattern1_template_t;
+
+#define private_st_pattern1_template() /* in gspcolor.c */\
+ gs_private_st_ptrs2(st_pattern1_template, gs_pattern1_template_t,\
+ "PatternType 1 template", pattern_template_enum_ptrs,\
+ pattern1_template_reloc_ptrs, uid.xvalues, client_data)
+/* Backward compatibility */
+typedef gs_pattern1_template_t gs_client_pattern;
+
+/* ---------------- Procedures ---------------- */
+
+/*
+ * Construct a PatternType 1 Pattern color space. If the base space is
+ * NULL, the color space can only be used with colored patterns.
+ */
+extern int gs_cspace_build_Pattern1(
+ gs_color_space ** ppcspace,
+ const gs_color_space * pbase_cspace,
+ gs_memory_t * pmem
+);
+
+/* Initialize a PatternType 1 pattern. */
+void gs_pattern1_init(P1(gs_pattern1_template_t *));
+
+#define gs_client_pattern_init(ppat) gs_pattern1_init(ppat)
+
+/*
+ * Define versions of make_pattern and get_pattern specifically for
+ * PatternType 1 patterns.
+ *
+ * The gs_memory_t argument for gs_makepattern may be NULL, meaning use the
+ * same allocator as for the gs_state argument. Note that gs_makepattern
+ * uses rc_alloc_struct_1 to allocate pattern instances.
+ */
+int gs_makepattern(P5(gs_client_color *, const gs_client_pattern *,
+ const gs_matrix *, gs_state *, gs_memory_t *));
+const gs_client_pattern *gs_getpattern(P1(const gs_client_color *));
+
+/*
+ * Make a pattern from a bitmap or pixmap. The pattern may be colored or
+ * uncolored, as determined by the mask operand. This code is intended
+ * primarily for use by PCL.
+ *
+ * By convention, if pmat is null the identity matrix will be used, and if
+ * id is no_UniqueID the code will assign a unique id. Thes conventions allow
+ * gs_makebitmappattern to be implemented as a macro. Also, if mem is a
+ * null pointer, the memory allocator for the graphic state is used.
+ *
+ * For mask patterns, pix_depth must be 1, while pcspace and white_index are
+ * ignored; the polarity of the mask considers ones part of the mask, while
+ * zeros are not. For colored patterns pspace must point to an indexed color
+ * space and the image must used the canoncial Decode array for this color
+ * space. For both cases no interpolation or adjustment is provided.
+ *
+ * For backwards compatibility, if mask is false, pcspace is null, and
+ * pix_depth is 1, the pattern will be rendered with a color space that maps
+ * 0 to white and 1 to black.
+ *
+ * The image must be described by a gx_tile_bitmap structure (this is actually
+ * somewhat awkward, but the only option available at the moment), and the
+ * pattern step will exactly match the image size. The client need not maintain
+ * the gx_tile_bitmap structure after the completion of this call, but the
+ * raw image data itself must be kept until the pattern is no longer needed.
+ *
+ * NB: For proper handling of transparency in PCL, there must be only a single
+ * white value accessed by the pattern image. If the palette contains
+ * multiple white values, the PCL component must remap the image data to
+ * ensure that all white indices are mapped to the single, given white
+ * index.
+ */
+extern int gs_makepixmappattern(gs_client_color * pcc,
+ const gs_depth_bitmap * pbitmap,
+ bool mask,
+ const gs_matrix * pmat,
+ long id,
+ const gs_color_space * pcspace,
+ uint white_index,
+ gs_state * pgs,
+ gs_memory_t * mem
+);
+
+/*
+ * Backwards compatibility feature, to allow the existing
+ * gs_makebitmappattern operation to still function.
+ */
+extern int gs_makebitmappattern_xform(gs_client_color * pcc,
+ const gx_tile_bitmap * ptile,
+ bool mask,
+ const gs_matrix * pmat,
+ long id,
+ gs_state * pgs,
+ gs_memory_t * mem
+);
+
+#define gs_makebitmappattern(pcc, tile, mask, pgs, mem) \
+ gs_makebitmappattern_xform(pcc, tile, mask, 0, no_UniqueID, pgs, mem)
+
+#endif /* gsptype1_INCLUDED */
diff --git a/pstoraster/gsptype2.h b/pstoraster/gsptype2.h
new file mode 100644
index 000000000..4dc1d5929
--- /dev/null
+++ b/pstoraster/gsptype2.h
@@ -0,0 +1,52 @@
+/* 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$ */
+/* Client interface to PatternType 2 Patterns */
+
+#ifndef gsptype2_INCLUDED
+# define gsptype2_INCLUDED
+
+#include "gspcolor.h"
+
+/* ---------------- Types and structures ---------------- */
+
+#ifndef gs_shading_t_DEFINED
+# define gs_shading_t_DEFINED
+typedef struct gs_shading_s gs_shading_t;
+
+#endif
+
+/* PatternType 2 template */
+typedef struct gs_pattern2_template_s {
+ gs_pattern_template_common;
+ const gs_shading_t *Shading;
+} gs_pattern2_template_t;
+
+/* ---------------- Procedures ---------------- */
+
+/* Initialize a PatternType 2 pattern. */
+void gs_pattern2_init(P1(gs_pattern2_template_t *));
+
+#endif /* gsptype2_INCLUDED */
diff --git a/pstoraster/gsrect.h b/pstoraster/gsrect.h
new file mode 100644
index 000000000..6fad11ad5
--- /dev/null
+++ b/pstoraster/gsrect.h
@@ -0,0 +1,61 @@
+/* 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$ */
+/* Rectangle utilities */
+
+#ifndef gsrect_INCLUDED
+# define gsrect_INCLUDED
+
+/* Check whether one rectangle is included entirely within another. */
+#define rect_within(inner, outer)\
+ (inner.q.y <= outer.q.y && inner.q.x <= outer.q.x &&\
+ inner.p.y >= outer.p.y && inner.p.x >= outer.p.x)
+
+/*
+ * Intersect two rectangles, replacing the first. The result may be
+ * anomalous (q < p) if the intersection is empty.
+ */
+#define rect_intersect(to, from)\
+ BEGIN\
+ if ( from.p.x > to.p.x ) to.p.x = from.p.x;\
+ if ( from.q.x < to.q.x ) to.q.x = from.q.x;\
+ if ( from.p.y > to.p.y ) to.p.y = from.p.y;\
+ if ( from.q.y < to.q.y ) to.q.y = from.q.y;\
+ END
+
+/*
+ * Calculate the difference of two rectangles, a list of up to 4 rectangles.
+ * Return the number of rectangles in the list, and set the first rectangle
+ * to the intersection. The resulting first rectangle is guaranteed not to
+ * be anomalous (q < p) iff it was not anomalous originally.
+ *
+ * Note that unlike the macros above, we need different versions of this
+ * depending on the data type of the individual values: we'll only implement
+ * the variations that we need.
+ */
+int int_rect_difference(P3(gs_int_rect * outer, const gs_int_rect * inner,
+ gs_int_rect * diffs /*[4] */ ));
+
+#endif /* gsrect_INCLUDED */
diff --git a/pstoraster/gsrefct.h b/pstoraster/gsrefct.h
new file mode 100644
index 000000000..49e536eaf
--- /dev/null
+++ b/pstoraster/gsrefct.h
@@ -0,0 +1,148 @@
+/* Copyright (C) 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$ */
+/* Reference counting definitions */
+
+#ifndef gsrefct_INCLUDED
+# define gsrefct_INCLUDED
+
+/*
+ * A reference-counted object must include the following header:
+ * rc_header rc;
+ * The header need not be the first element of the object.
+ */
+typedef struct rc_header_s rc_header;
+struct rc_header_s {
+ long ref_count;
+ gs_memory_t *memory;
+#define rc_free_proc(proc)\
+ void proc(P3(gs_memory_t *, void *, client_name_t))
+ rc_free_proc((*free));
+};
+
+/* ------ Allocate/free ------ */
+
+rc_free_proc(rc_free_struct_only);
+/* rc_init[_free] is only used to initialize stack-allocated structures. */
+#define rc_init_free(vp, mem, rcinit, proc)\
+ ((vp)->rc.ref_count = rcinit,\
+ (vp)->rc.memory = mem,\
+ (vp)->rc.free = proc)
+#define rc_init(vp, mem, rcinit)\
+ rc_init_free(vp, mem, rcinit, rc_free_struct_only)
+
+#define rc_alloc_struct_n(vp, typ, pstyp, mem, errstat, cname, rcinit)\
+ BEGIN\
+ if ( ((vp) = gs_alloc_struct(mem, typ, pstyp, cname)) == 0 ) {\
+ errstat;\
+ } else {\
+ rc_init(vp, mem, rcinit);\
+ }\
+ END
+#define rc_alloc_struct_0(vp, typ, pstype, mem, errstat, cname)\
+ rc_alloc_struct_n(vp, typ, pstype, mem, errstat, cname, 0)
+#define rc_alloc_struct_1(vp, typ, pstype, mem, errstat, cname)\
+ rc_alloc_struct_n(vp, typ, pstype, mem, errstat, cname, 1)
+
+#define rc_free_struct(vp, cname)\
+ (*(vp)->rc.free)((vp)->rc.memory, (void *)(vp), cname)
+
+/* ------ Reference counting ------ */
+
+/* Increment a reference count. */
+#define rc_increment(vp)\
+ BEGIN if ( (vp) != 0 ) (vp)->rc.ref_count++; END
+
+/* Increment a reference count, allocating the structure if necessary. */
+#define rc_allocate_struct(vp, typ, pstype, mem, errstat, cname)\
+ BEGIN\
+ if ( (vp) != 0 )\
+ (vp)->rc.ref_count++;\
+ else\
+ rc_alloc_struct_1(vp, typ, pstype, mem, errstat, cname);\
+ END
+
+/* Guarantee that a structure is allocated and is not shared. */
+#define rc_unshare_struct(vp, typ, pstype, mem, errstat, cname)\
+ BEGIN\
+ if ( (vp) == 0 || (vp)->rc.ref_count > 1 || (vp)->rc.memory != (mem) ) {\
+ typ *new;\
+ rc_alloc_struct_1(new, typ, pstype, mem, errstat, cname);\
+ if ( vp ) (vp)->rc.ref_count--;\
+ (vp) = new;\
+ }\
+ END
+
+/* Adjust a reference count either up or down. */
+#ifdef DEBUG
+# define rc_check_(vp)\
+ BEGIN\
+ if ( gs_debug_c('?') && (vp) != 0 && (vp)->rc.ref_count < 0 )\
+ lprintf2("0x%lx has ref_count of %ld!\n", (ulong)(vp),\
+ (vp)->rc.ref_count);\
+ END
+#else
+# define rc_check_(vp) DO_NOTHING
+#endif
+#define rc_adjust_(vp, delta, cname, body)\
+ BEGIN\
+ if ( (vp) != 0 && !((vp)->rc.ref_count += delta) ) {\
+ rc_free_struct(vp, cname);\
+ body;\
+ } else\
+ rc_check_(vp);\
+ END
+#define rc_adjust(vp, delta, cname)\
+ rc_adjust_(vp, delta, cname, (vp) = 0)
+#define rc_adjust_only(vp, delta, cname)\
+ rc_adjust_(vp, delta, cname, DO_NOTHING)
+#define rc_adjust_const(vp, delta, cname)\
+ rc_adjust_only(vp, delta, cname)
+#define rc_decrement(vp, cname)\
+ rc_adjust(vp, -1, cname)
+#define rc_decrement_only(vp, cname)\
+ rc_adjust_only(vp, -1, cname)
+
+/* Assign a pointer, adjusting reference counts. */
+#define rc_assign(vpto, vpfrom, cname)\
+ BEGIN\
+ if ( (vpto) != (vpfrom) ) {\
+ rc_decrement_only(vpto, cname);\
+ (vpto) = (vpfrom);\
+ rc_increment(vpto);\
+ }\
+ END
+/* Adjust reference counts for assigning a pointer, */
+/* but don't do the assignment. We use this before assigning */
+/* an entire structure containing reference-counted pointers. */
+#define rc_pre_assign(vpto, vpfrom, cname)\
+ BEGIN\
+ if ( (vpto) != (vpfrom) ) {\
+ rc_decrement_only(vpto, cname);\
+ rc_increment(vpfrom);\
+ }\
+ END
+
+#endif /* gsrefct_INCLUDED */
diff --git a/pstoraster/gsrop.h b/pstoraster/gsrop.h
new file mode 100644
index 000000000..7f524ebf4
--- /dev/null
+++ b/pstoraster/gsrop.h
@@ -0,0 +1,46 @@
+/* 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$ */
+/* RasterOp / transparency procedure interface */
+
+#ifndef gsrop_INCLUDED
+# define gsrop_INCLUDED
+
+#include "gsropt.h"
+
+/* Procedural interface */
+
+int gs_setrasterop(P2(gs_state *, gs_rop3_t));
+gs_rop3_t gs_currentrasterop(P1(const gs_state *));
+int gs_setsourcetransparent(P2(gs_state *, bool));
+bool gs_currentsourcetransparent(P1(const gs_state *));
+int gs_settexturetransparent(P2(gs_state *, bool));
+bool gs_currenttexturetransparent(P1(const gs_state *));
+
+/* Save/restore the combined logical operation. */
+gs_logical_operation_t gs_current_logical_op(P1(const gs_state *));
+int gs_set_logical_op(P2(gs_state *, gs_logical_operation_t));
+
+#endif /* gsrop_INCLUDED */
diff --git a/pstoraster/gsropc.h b/pstoraster/gsropc.h
new file mode 100644
index 000000000..c67fa89a9
--- /dev/null
+++ b/pstoraster/gsropc.h
@@ -0,0 +1,60 @@
+/* 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$ */
+/* RasterOp-compositing interface */
+
+#ifndef gsropc_INCLUDED
+# define gsropc_INCLUDED
+
+#include "gscompt.h"
+#include "gsropt.h"
+
+/*
+ * Define parameters for RasterOp-compositing.
+ * There are two kinds of RasterOp compositing operations.
+ * If texture == 0, the input data are the texture, and the source is
+ * implicitly all 0 (black). If texture != 0, it defines the texture,
+ * and the input data are the source. Note that in the latter case,
+ * the client (the caller of gs_create_composite_rop) promises that
+ * *texture will not change.
+ */
+
+#ifndef gx_device_color_DEFINED
+# define gx_device_color_DEFINED
+typedef struct gx_device_color_s gx_device_color;
+
+#endif
+
+typedef struct gs_composite_rop_params_s {
+ gs_logical_operation_t log_op;
+ const gx_device_color *texture;
+} gs_composite_rop_params_t;
+
+/* Create a RasterOp-compositing object. */
+int gs_create_composite_rop(P3(gs_composite_t ** ppcte,
+ const gs_composite_rop_params_t * params,
+ gs_memory_t * mem));
+
+#endif /* gsropc_INCLUDED */
diff --git a/pstoraster/gsropt.h b/pstoraster/gsropt.h
new file mode 100644
index 000000000..124a6b27f
--- /dev/null
+++ b/pstoraster/gsropt.h
@@ -0,0 +1,195 @@
+/* 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$ */
+/* RasterOp / transparency type definitions */
+
+#ifndef gsropt_INCLUDED
+# define gsropt_INCLUDED
+
+/*
+ * This file defines the types for some library extensions that are
+ * motivated by PCL5 and also made available for PostScript:
+ * RasterOp, source and pattern white-pixel transparency, and
+ * per-pixel "render algorithm" information.
+ */
+
+/*
+ * By the magic of Boolean algebra, we can operate on the rop codes using
+ * Boolean operators and get the right result. E.g., the value of
+ * (rop3_S & rop3_D) is the rop3 code for S & D. We just have to remember
+ * to mask results with rop2_1 or rop3_1 if necessary.
+ */
+
+/* 2-input RasterOp */
+typedef enum {
+ rop2_0 = 0,
+ rop2_S = 0xc, /* source */
+#define rop2_S_shift 2
+ rop2_D = 0xa, /* destination */
+#define rop2_D_shift 1
+ rop2_1 = 0xf,
+#define rop2_operand(shift, d, s)\
+ ((shift) == 2 ? (s) : (d))
+ rop2_default = rop2_S
+} gs_rop2_t;
+
+/*
+ * For the 3-input case, we follow H-P's inconsistent terminology:
+ * the transparency mode is called pattern transparency, but the third
+ * RasterOp operand is called texture, not pattern.
+ */
+
+/* 3-input RasterOp */
+typedef enum {
+ rop3_0 = 0,
+ rop3_T = 0xf0, /* texture */
+#define rop3_T_shift 4
+ rop3_S = 0xcc, /* source */
+#define rop3_S_shift 2
+ rop3_D = 0xaa, /* destination */
+#define rop3_D_shift 1
+ rop3_1 = 0xff,
+ rop3_default = rop3_T | rop3_S
+} gs_rop3_t;
+
+/* All the transformations on rop3s are designed so that */
+/* they can also be used on lops. The only place this costs anything */
+/* is in rop3_invert. */
+
+/*
+ * Invert an operand.
+ */
+#define rop3_invert_(op, mask, shift)\
+ ( (((op) & mask) >> shift) | (((op) & (rop3_1 - mask)) << shift) |\
+ ((op) & ~rop3_1) )
+#define rop3_invert_D(op) rop3_invert_(op, rop3_D, rop3_D_shift)
+#define rop3_invert_S(op) rop3_invert_(op, rop3_S, rop3_S_shift)
+#define rop3_invert_T(op) rop3_invert_(op, rop3_T, rop3_T_shift)
+/*
+ * Pin an operand to 0.
+ */
+#define rop3_know_0_(op, mask, shift)\
+ ( (((op) & (rop3_1 - mask)) << shift) | ((op) & ~mask) )
+#define rop3_know_D_0(op) rop3_know_0_(op, rop3_D, rop3_D_shift)
+#define rop3_know_S_0(op) rop3_know_0_(op, rop3_S, rop3_S_shift)
+#define rop3_know_T_0(op) rop3_know_0_(op, rop3_T, rop3_T_shift)
+/*
+ * Pin an operand to 1.
+ */
+#define rop3_know_1_(op, mask, shift)\
+ ( (((op) & mask) >> shift) | ((op) & ~(rop3_1 - mask)) )
+#define rop3_know_D_1(op) rop3_know_1_(op, rop3_D, rop3_D_shift)
+#define rop3_know_S_1(op) rop3_know_1_(op, rop3_S, rop3_S_shift)
+#define rop3_know_T_1(op) rop3_know_1_(op, rop3_T, rop3_T_shift)
+/*
+ * Swap S and T.
+ */
+#define rop3_swap_S_T(op)\
+ ( (((op) & rop3_S & ~rop3_T) << (rop3_T_shift - rop3_S_shift)) |\
+ (((op) & ~rop3_S & rop3_T) >> (rop3_T_shift - rop3_S_shift)) |\
+ ((op) & (~rop3_1 | (rop3_S ^ rop3_T))) )
+/*
+ * Account for transparency.
+ */
+#define rop3_use_D_when_0_(op, mask)\
+ (((op) & ~(rop3_1 - mask)) | (rop3_D & ~mask))
+#define rop3_use_D_when_1_(op, mask)\
+ (((op) & ~mask) | (rop3_D & mask))
+#define rop3_use_D_when_S_0(op) rop3_use_D_when_0_(op, rop3_S)
+#define rop3_use_D_when_S_1(op) rop3_use_D_when_1_(op, rop3_S)
+#define rop3_use_D_when_T_0(op) rop3_use_D_when_0_(op, rop3_T)
+#define rop3_use_D_when_T_1(op) rop3_use_D_when_1_(op, rop3_T)
+/*
+ * Invert the result.
+ */
+#define rop3_not(op) ((op) ^ rop3_1)
+/*
+ * Test whether an operand is used.
+ */
+#define rop3_uses_(op, mask, shift)\
+ ( ((((op) << shift) ^ (op)) & mask) != 0 )
+#define rop3_uses_D(op) rop3_uses_(op, rop3_D, rop3_D_shift)
+#define rop3_uses_S(op) rop3_uses_(op, rop3_S, rop3_S_shift)
+#define rop3_uses_T(op) rop3_uses_(op, rop3_T, rop3_T_shift)
+/*
+ * Test whether an operation is idempotent, i.e., whether
+ * f(D, S, T) = f(f(D, S, T), S, T). This is equivalent to the condition that
+ * for all values s and t, !( f(0,s,t) == 1 && f(1,s,t) == 0 ).
+ */
+#define rop3_is_idempotent(op)\
+ !( (op) & ~((op) << rop3_D_shift) & rop3_D )
+
+/* Transparency */
+#define source_transparent_default false
+#define pattern_transparent_default false
+
+/*
+ * We define a logical operation as a RasterOp, transparency flags,
+ * and render algorithm all packed into a single integer.
+ * In principle, we should use a structure, but most C implementations
+ * implement structure values very inefficiently.
+ */
+#define lop_rop(lop) ((gs_rop3_t)((lop) & 0xff)) /* must be low-order bits */
+#define lop_S_transparent 0x100
+#define lop_T_transparent 0x200
+#define lop_ral_shift 10
+#define lop_ral_mask 0xf
+typedef uint gs_logical_operation_t;
+
+#define lop_default\
+ (rop3_default |\
+ (source_transparent_default ? lop_S_transparent : 0) |\
+ (pattern_transparent_default ? lop_T_transparent : 0))
+
+ /* Test whether a logical operation uses S or T. */
+#define lop_uses_S(lop)\
+ (rop3_uses_S(lop) || ((lop) & lop_S_transparent))
+#define lop_uses_T(lop)\
+ (rop3_uses_T(lop) || ((lop) & lop_T_transparent))
+/* Test whether a logical operation just sets D = x if y = 0. */
+#define lop_no_T_is_S(lop)\
+ (((lop) & (lop_S_transparent | (rop3_1 - rop3_T))) == (rop3_S & ~rop3_T))
+#define lop_no_S_is_T(lop)\
+ (((lop) & (lop_T_transparent | (rop3_1 - rop3_S))) == (rop3_T & ~rop3_S))
+/* Test whether a logical operation is idempotent. */
+#define lop_is_idempotent(lop) rop3_is_idempotent(lop)
+
+/* Define the interface to the table of 256 RasterOp procedures. */
+typedef unsigned rop_operand;
+typedef rop_operand(*rop_proc) (P3(rop_operand D, rop_operand S, rop_operand T));
+
+/* Define the table of operand usage by the 256 RasterOp operations. */
+typedef enum {
+ rop_usage_none = 0,
+ rop_usage_D = 1,
+ rop_usage_S = 2,
+ rop_usage_DS = 3,
+ rop_usage_T = 4,
+ rop_usage_DT = 5,
+ rop_usage_ST = 6,
+ rop_usage_DST = 7
+} rop_usage_t;
+
+#endif /* gsropt_INCLUDED */
diff --git a/pstoraster/gsshade.c b/pstoraster/gsshade.c
new file mode 100644
index 000000000..00d2a95ff
--- /dev/null
+++ b/pstoraster/gsshade.c
@@ -0,0 +1,451 @@
+/* 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$ */
+/* Constructors for shadings */
+#include "gx.h"
+#include "gscspace.h"
+#include "gserrors.h"
+#include "gsstruct.h" /* for extern_st */
+#include "gxdevcli.h"
+#include "gxcpath.h"
+#include "gxistate.h"
+#include "gxpath.h"
+#include "gxshade.h"
+
+/* ================ Initialize shadings ================ */
+
+/* ---------------- Generic services ---------------- */
+
+/* GC descriptors */
+private_st_shading();
+private_st_shading_mesh();
+
+/* Check ColorSpace, BBox, and Function (if present). */
+/* Free variables: params. */
+private int
+check_CBFD(const gs_shading_params_t * params,
+ const gs_function_t * function, const float *domain, int m)
+{
+ int ncomp = gs_color_space_num_components(params->ColorSpace);
+
+ if (ncomp < 0 ||
+ (params->have_BBox &&
+ (params->BBox.p.x > params->BBox.q.x ||
+ params->BBox.p.y > params->BBox.q.y))
+ )
+ return_error(gs_error_rangecheck);
+ if (function != 0) {
+ if (function->params.m != m || function->params.n != ncomp)
+ return_error(gs_error_rangecheck);
+ /*
+ * The Adobe documentation says that the function's domain must
+ * be a superset of the domain defined in the shading dictionary.
+ * However, Adobe implementations apparently don't necessarily
+ * check this ahead of time; therefore, we do the same.
+ */
+#if 0 /*************** */
+ {
+ int i;
+
+ for (i = 0; i < m; ++i)
+ if (function->params.Domain[2 * i] > domain[2 * i] ||
+ function->params.Domain[2 * i + 1] < domain[2 * i + 1]
+ )
+ return_error(gs_error_rangecheck);
+ }
+#endif /*************** */
+ }
+ return 0;
+}
+
+/* Check parameters for a mesh shading. */
+private int
+check_mesh(const gs_shading_mesh_params_t * params)
+{
+ if (!data_source_is_array(params->DataSource)) {
+ int code = check_CBFD((const gs_shading_params_t *)params,
+ params->Function, params->Decode, 1);
+
+ if (code < 0)
+ return code;
+ switch (params->BitsPerCoordinate) {
+ case 1: case 2: case 4: case 8:
+ case 12: case 16: case 24: case 32:
+ break;
+ default:
+ return_error(gs_error_rangecheck);
+ }
+ switch (params->BitsPerComponent) {
+ case 1: case 2: case 4: case 8:
+ case 12: case 16:
+ break;
+ default:
+ return_error(gs_error_rangecheck);
+ }
+ }
+ return 0;
+}
+
+/* Check the BitsPerFlag value. Return the value or an error code. */
+private int
+check_BPF(const gs_data_source_t *pds, int bpf)
+{
+ if (data_source_is_array(*pds))
+ return 2;
+ switch (bpf) {
+ case 2: case 4: case 8:
+ return bpf;
+ default:
+ return_error(gs_error_rangecheck);
+ }
+}
+
+/* Initialize common shading parameters. */
+private void
+shading_params_init(gs_shading_params_t *params)
+{
+ params->ColorSpace = 0; /* must be set by client */
+ params->Background = 0;
+ params->have_BBox = false;
+ params->AntiAlias = false;
+}
+
+/* Initialize common mesh shading parameters. */
+private void
+mesh_shading_params_init(gs_shading_mesh_params_t *params)
+{
+ shading_params_init((gs_shading_params_t *)params);
+ data_source_init_floats(&params->DataSource, NULL, 0);/* client must set */
+ /* Client must set BitsPerCoordinate and BitsPerComponent */
+ /* if DataSource is not an array. */
+ params->Decode = 0;
+ params->Function = 0;
+}
+
+/* Allocate and initialize a shading. */
+/* Free variables: mem, params, ppsh, psh. */
+#define ALLOC_SHADING(sttype, stype, sfrproc, cname)\
+ BEGIN\
+ psh = gs_alloc_struct(mem, void, sttype, cname);\
+ if ( psh == 0 )\
+ return_error(gs_error_VMerror);\
+ psh->head.type = stype;\
+ psh->head.fill_rectangle = sfrproc;\
+ psh->params = *params;\
+ *ppsh = (gs_shading_t *)psh;\
+ END
+
+/* ---------------- Function-based shading ---------------- */
+
+private_st_shading_Fb();
+
+/* Initialize parameters for a Function-based shading. */
+void
+gs_shading_Fb_params_init(gs_shading_Fb_params_t * params)
+{
+ shading_params_init((gs_shading_params_t *)params);
+ params->Domain[0] = params->Domain[2] = 0;
+ params->Domain[1] = params->Domain[3] = 1;
+ gs_make_identity(&params->Matrix);
+ params->Function = 0; /* must be set by client */
+}
+
+/* Allocate and initialize a Function-based shading. */
+int
+gs_shading_Fb_init(gs_shading_t ** ppsh,
+ const gs_shading_Fb_params_t * params, gs_memory_t * mem)
+{
+ gs_shading_Fb_t *psh;
+ gs_matrix imat;
+ int code = check_CBFD((const gs_shading_params_t *)params,
+ params->Function, params->Domain, 2);
+
+ if (code < 0 ||
+ (code = gs_matrix_invert(&params->Matrix, &imat)) < 0
+ )
+ return code;
+ ALLOC_SHADING(&st_shading_Fb, shading_type_Function_based,
+ gs_shading_Fb_fill_rectangle, "gs_shading_Fb_init");
+ return 0;
+}
+
+/* ---------------- Axial shading ---------------- */
+
+private_st_shading_A();
+
+/* Initialize parameters for an Axial shading. */
+void
+gs_shading_A_params_init(gs_shading_A_params_t * params)
+{
+ shading_params_init((gs_shading_params_t *)params);
+ /* Coords must be set by client */
+ params->Domain[0] = 0;
+ params->Domain[1] = 1;
+ params->Function = 0; /* must be set by client */
+ params->Extend[0] = params->Extend[1] = false;
+}
+
+/* Allocate and initialize an Axial shading. */
+int
+gs_shading_A_init(gs_shading_t ** ppsh,
+ const gs_shading_A_params_t * params, gs_memory_t * mem)
+{
+ gs_shading_A_t *psh;
+ int code = check_CBFD((const gs_shading_params_t *)params,
+ params->Function, params->Domain, 1);
+
+ if (code < 0)
+ return code;
+ ALLOC_SHADING(&st_shading_A, shading_type_Axial,
+ gs_shading_A_fill_rectangle, "gs_shading_A_init");
+ return 0;
+}
+
+/* ---------------- Radial shading ---------------- */
+
+private_st_shading_R();
+
+/* Initialize parameters for a Radial shading. */
+void
+gs_shading_R_params_init(gs_shading_R_params_t * params)
+{
+ shading_params_init((gs_shading_params_t *)params);
+ /* Coords must be set by client */
+ params->Domain[0] = 0;
+ params->Domain[1] = 1;
+ params->Function = 0; /* must be set by client */
+ params->Extend[0] = params->Extend[1] = false;
+}
+
+/* Allocate and initialize a Radial shading. */
+int
+gs_shading_R_init(gs_shading_t ** ppsh,
+ const gs_shading_R_params_t * params, gs_memory_t * mem)
+{
+ gs_shading_R_t *psh;
+ int code = check_CBFD((const gs_shading_params_t *)params,
+ params->Function, params->Domain, 1);
+
+ if (code < 0)
+ return code;
+ if ((params->Domain != 0 && params->Domain[0] == params->Domain[1]) ||
+ params->Coords[2] < 0 || params->Coords[5] < 0
+ )
+ return_error(gs_error_rangecheck);
+ ALLOC_SHADING(&st_shading_R, shading_type_Radial,
+ gs_shading_R_fill_rectangle, "gs_shading_R_init");
+ return 0;
+}
+
+/* ---------------- Free-form Gouraud triangle mesh shading ---------------- */
+
+private_st_shading_FfGt();
+
+/* Initialize parameters for a Free-form Gouraud triangle mesh shading. */
+void
+gs_shading_FfGt_params_init(gs_shading_FfGt_params_t * params)
+{
+ mesh_shading_params_init((gs_shading_mesh_params_t *)params);
+ /* Client must set BitsPerFlag if DataSource is not an array. */
+}
+
+/* Allocate and initialize a Free-form Gouraud triangle mesh shading. */
+int
+gs_shading_FfGt_init(gs_shading_t ** ppsh,
+ const gs_shading_FfGt_params_t * params,
+ gs_memory_t * mem)
+{
+ gs_shading_FfGt_t *psh;
+ int code = check_mesh((const gs_shading_mesh_params_t *)params);
+ int bpf = check_BPF(&params->DataSource, params->BitsPerFlag);
+
+ if (code < 0)
+ return code;
+ if (bpf < 0)
+ return bpf;
+ if (params->Decode != 0 && params->Decode[0] == params->Decode[1])
+ return_error(gs_error_rangecheck);
+ ALLOC_SHADING(&st_shading_FfGt, shading_type_Free_form_Gouraud_triangle,
+ gs_shading_FfGt_fill_rectangle, "gs_shading_FfGt_init");
+ psh->params.BitsPerFlag = bpf;
+ return 0;
+}
+
+/* -------------- Lattice-form Gouraud triangle mesh shading -------------- */
+
+private_st_shading_LfGt();
+
+/* Initialize parameters for a Lattice-form Gouraud triangle mesh shading. */
+void
+gs_shading_LfGt_params_init(gs_shading_LfGt_params_t * params)
+{
+ mesh_shading_params_init((gs_shading_mesh_params_t *)params);
+ /* Client must set VerticesPerRow. */
+}
+
+/* Allocate and initialize a Lattice-form Gouraud triangle mesh shading. */
+int
+gs_shading_LfGt_init(gs_shading_t ** ppsh,
+ const gs_shading_LfGt_params_t * params, gs_memory_t * mem)
+{
+ gs_shading_LfGt_t *psh;
+ int code = check_mesh((const gs_shading_mesh_params_t *)params);
+
+ if (code < 0)
+ return code;
+ if (params->VerticesPerRow < 2)
+ return_error(gs_error_rangecheck);
+ ALLOC_SHADING(&st_shading_LfGt, shading_type_Lattice_form_Gouraud_triangle,
+ gs_shading_LfGt_fill_rectangle, "gs_shading_LfGt_init");
+ return 0;
+}
+
+/* ---------------- Coons patch mesh shading ---------------- */
+
+private_st_shading_Cp();
+
+/* Initialize parameters for a Coons patch mesh shading. */
+void
+gs_shading_Cp_params_init(gs_shading_Cp_params_t * params)
+{
+ mesh_shading_params_init((gs_shading_mesh_params_t *)params);
+ /* Client must set BitsPerFlag if DataSource is not an array. */
+}
+
+/* Allocate and initialize a Coons patch mesh shading. */
+int
+gs_shading_Cp_init(gs_shading_t ** ppsh,
+ const gs_shading_Cp_params_t * params, gs_memory_t * mem)
+{
+ gs_shading_Cp_t *psh;
+ int code = check_mesh((const gs_shading_mesh_params_t *)params);
+ int bpf = check_BPF(&params->DataSource, params->BitsPerFlag);
+
+ if (code < 0)
+ return code;
+ if (bpf < 0)
+ return bpf;
+ ALLOC_SHADING(&st_shading_Cp, shading_type_Coons_patch,
+ gs_shading_Cp_fill_rectangle, "gs_shading_Cp_init");
+ psh->params.BitsPerFlag = bpf;
+ return 0;
+}
+
+/* ---------------- Tensor product patch mesh shading ---------------- */
+
+private_st_shading_Tpp();
+
+/* Initialize parameters for a Tensor product patch mesh shading. */
+void
+gs_shading_Tpp_params_init(gs_shading_Tpp_params_t * params)
+{
+ mesh_shading_params_init((gs_shading_mesh_params_t *)params);
+ /* Client must set BitsPerFlag if DataSource is not an array. */
+}
+
+/* Allocate and initialize a Tensor product patch mesh shading. */
+int
+gs_shading_Tpp_init(gs_shading_t ** ppsh,
+ const gs_shading_Tpp_params_t * params, gs_memory_t * mem)
+{
+ gs_shading_Tpp_t *psh;
+ int code = check_mesh((const gs_shading_mesh_params_t *)params);
+ int bpf = check_BPF(&params->DataSource, params->BitsPerFlag);
+
+ if (code < 0)
+ return code;
+ if (bpf < 0)
+ return bpf;
+ ALLOC_SHADING(&st_shading_Tpp, shading_type_Tensor_product_patch,
+ gs_shading_Tpp_fill_rectangle, "gs_shading_Tpp_init");
+ psh->params.BitsPerFlag = bpf;
+ return 0;
+}
+
+/* ================ Shading rendering ================ */
+
+/* Fill a path with a shading. */
+int
+gs_shading_fill_path(const gs_shading_t *psh, const gx_path *ppath,
+ gx_device *orig_dev, gs_imager_state *pis)
+{
+ gs_memory_t *mem = pis->memory;
+ gx_device *dev = orig_dev;
+ gs_fixed_rect path_box;
+ gs_rect rect;
+ gx_clip_path *box_clip = 0;
+ gx_clip_path *path_clip = 0;
+ gx_device_clip box_dev, path_dev;
+ int code;
+
+#if 0 /****** NOT IMPLEMENTED YET *****/
+ if (psh->params.have_BBox) {
+ box_clip = gx_cpath_alloc(mem, "shading_fill_path(box_clip)");
+ if (box_clip == 0)
+ return_error(gs_error_VMerror);
+ /****** APPEND TRANSFORMED BOX ******/
+ gx_make_clip_device(&box_dev, &box_dev, box_clip->list);
+ box_dev.target = dev;
+ dev = &box_dev;
+ dev_proc(dev, open_device)(dev);
+ }
+#endif
+ dev_proc(dev, get_clipping_box)(dev, &path_box);
+#if 0 /****** NOT IMPLEMENTED YET *****/
+ if (ppath) {
+ if (psh->params.Background) {
+ /****** FILL BOX WITH BACKGROUND ******/
+ }
+ path_clip = gx_cpath_alloc(mem, "shading_fill_path(path_clip)");
+ if (path_clip == 0) {
+ code = gs_note_error(gs_error_VMerror);
+ goto out;
+ }
+ /****** SET CLIP PATH ******/
+ gx_make_clip_device(&path_dev, &path_dev, path_clip->list);
+ path_dev.target = dev;
+ dev = &path_dev;
+ dev_proc(dev, open_device)(dev);
+ dev_proc(dev, get_clipping_box)(dev, &path_box);
+ }
+#endif
+ {
+ gs_rect path_rect;
+ const gs_matrix *pmat = &ctm_only(pis);
+
+ path_rect.p.x = fixed2float(path_box.p.x);
+ path_rect.p.y = fixed2float(path_box.p.y);
+ path_rect.q.x = fixed2float(path_box.q.x);
+ path_rect.q.y = fixed2float(path_box.q.y);
+ gs_bbox_transform_inverse(&path_rect, pmat, &rect);
+ }
+ code = psh->head.fill_rectangle(psh, &rect, dev, pis);
+out:
+ if (path_clip)
+ gx_cpath_free(path_clip, "shading_fill_path(path_clip)");
+ if (box_clip)
+ gx_cpath_free(box_clip, "shading_fill_path(box_clip)");
+ return code;
+}
diff --git a/pstoraster/gsshade.h b/pstoraster/gsshade.h
new file mode 100644
index 000000000..5d3a78fa2
--- /dev/null
+++ b/pstoraster/gsshade.h
@@ -0,0 +1,255 @@
+/* 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$ */
+/* Definitions for shading */
+
+#ifndef gsshade_INCLUDED
+# define gsshade_INCLUDED
+
+#include "gsccolor.h"
+#include "gscspace.h"
+#include "gsdsrc.h"
+#include "gsfunc.h"
+#include "gsmatrix.h"
+
+/* ---------------- Types and structures ---------------- */
+
+/* Define the shading types. */
+typedef enum {
+ shading_type_Function_based = 1,
+ shading_type_Axial = 2,
+ shading_type_Radial = 3,
+ shading_type_Free_form_Gouraud_triangle = 4,
+ shading_type_Lattice_form_Gouraud_triangle = 5,
+ shading_type_Coons_patch = 6,
+ shading_type_Tensor_product_patch = 7
+} gs_shading_type_t;
+
+/*
+ * Define information common to all shading types. We separate the private
+ * part from the parameters so that clients can create parameter structures
+ * without having to know the structure of the implementation.
+ */
+#define gs_shading_params_common\
+ gs_color_space *ColorSpace;\
+ gs_client_color *Background;\
+ bool have_BBox;\
+ gs_rect BBox;\
+ bool AntiAlias
+
+typedef struct gs_shading_params_s {
+ gs_shading_params_common;
+} gs_shading_params_t;
+
+/* Define the type-specific procedures for shadings. */
+#ifndef gs_shading_t_DEFINED
+# define gs_shading_t_DEFINED
+typedef struct gs_shading_s gs_shading_t;
+#endif
+#ifndef gx_device_DEFINED
+# define gx_device_DEFINED
+typedef struct gx_device_s gx_device;
+#endif
+/*
+ * Fill a user space rectangle. This will paint every pixel that is in the
+ * intersection of the rectangle and the shading's geometry, but it may
+ * leave some pixels in the rectangle unpainted, and it may also paint
+ * outside the rectangle: the caller is responsible for setting up a
+ * clipping device if necessary.
+ */
+#define shading_fill_rectangle_proc(proc)\
+ int proc(P4(const gs_shading_t *psh, const gs_rect *rect, gx_device *dev,\
+ gs_imager_state *pis))
+typedef shading_fill_rectangle_proc((*shading_fill_rectangle_proc_t));
+typedef struct gs_shading_head_s {
+ gs_shading_type_t type;
+ shading_fill_rectangle_proc_t fill_rectangle;
+} gs_shading_head_t;
+
+/* Define a generic shading, for use as the target type of pointers. */
+struct gs_shading_s {
+ gs_shading_head_t head;
+ gs_shading_params_t params;
+};
+#define ShadingType(psh) ((psh)->head.type)
+#define private_st_shading() /* in gsshade.c */\
+ gs_private_st_ptrs2(st_shading, gs_shading_t, "gs_shading_t",\
+ shading_enum_ptrs, shading_reloc_ptrs,\
+ params.ColorSpace, params.Background)
+
+/* Define Function-based shading. */
+typedef struct gs_shading_Fb_params_s {
+ gs_shading_params_common;
+ float Domain[4];
+ gs_matrix Matrix;
+ gs_function_t *Function;
+} gs_shading_Fb_params_t;
+
+#define private_st_shading_Fb() /* in gsshade.c */\
+ gs_private_st_suffix_add1(st_shading_Fb, gs_shading_Fb_t,\
+ "gs_shading_Fb_t", shading_Fb_enum_ptrs, shading_Fb_reloc_ptrs,\
+ st_shading, params.Function)
+
+/* Define Axial shading. */
+typedef struct gs_shading_A_params_s {
+ gs_shading_params_common;
+ float Coords[4];
+ float Domain[2];
+ gs_function_t *Function;
+ bool Extend[2];
+} gs_shading_A_params_t;
+
+#define private_st_shading_A() /* in gsshade.c */\
+ gs_private_st_suffix_add1(st_shading_A, gs_shading_A_t,\
+ "gs_shading_A_t", shading_A_enum_ptrs, shading_A_reloc_ptrs,\
+ st_shading, params.Function)
+
+/* Define Radial shading. */
+typedef struct gs_shading_R_params_s {
+ gs_shading_params_common;
+ float Coords[6];
+ float Domain[2];
+ gs_function_t *Function;
+ bool Extend[2];
+} gs_shading_R_params_t;
+
+#define private_st_shading_R() /* in gsshade.c */\
+ gs_private_st_suffix_add1(st_shading_R, gs_shading_R_t,\
+ "gs_shading_R_t", shading_R_enum_ptrs, shading_R_reloc_ptrs,\
+ st_shading, params.Function)
+
+/* Define common parameters for mesh shading. */
+#define gs_shading_mesh_params_common\
+ gs_shading_params_common;\
+ gs_data_source_t DataSource;\
+ int BitsPerCoordinate;\
+ int BitsPerComponent;\
+ float *Decode;\
+ gs_function_t *Function
+/* The following are for internal use only. */
+typedef struct gs_shading_mesh_params_s {
+ gs_shading_mesh_params_common;
+} gs_shading_mesh_params_t;
+typedef struct gs_shading_mesh_s {
+ gs_shading_head_t head;
+ gs_shading_mesh_params_t params;
+} gs_shading_mesh_t;
+
+#define private_st_shading_mesh() /* in gsshade.c */\
+ gs_private_st_suffix_add2(st_shading_mesh, gs_shading_mesh_t,\
+ "gs_shading_mesh_t", shading_mesh_enum_ptrs, shading_mesh_reloc_ptrs,\
+ st_shading, params.Decode, params.Function)
+
+/* Define Free-form Gouraud triangle mesh shading. */
+typedef struct gs_shading_FfGt_params_s {
+ gs_shading_mesh_params_common;
+ int BitsPerFlag;
+} gs_shading_FfGt_params_t;
+
+#define private_st_shading_FfGt() /* in gsshade.c */\
+ gs_private_st_suffix_add0_local(st_shading_FfGt, gs_shading_FfGt_t,\
+ "gs_shading_FfGt_t", shading_mesh_enum_ptrs, shading_mesh_reloc_ptrs,\
+ st_shading_mesh)
+
+/* Define Lattice-form Gouraud triangle mesh shading. */
+typedef struct gs_shading_LfGt_params_s {
+ gs_shading_mesh_params_common;
+ int VerticesPerRow;
+} gs_shading_LfGt_params_t;
+
+#define private_st_shading_LfGt() /* in gsshade.c */\
+ gs_private_st_suffix_add0_local(st_shading_LfGt, gs_shading_LfGt_t,\
+ "gs_shading_LfGt_t", shading_mesh_enum_ptrs, shading_mesh_reloc_ptrs,\
+ st_shading_mesh)
+
+/* Define Coons patch mesh shading. */
+typedef struct gs_shading_Cp_params_s {
+ gs_shading_mesh_params_common;
+ int BitsPerFlag;
+} gs_shading_Cp_params_t;
+
+#define private_st_shading_Cp() /* in gsshade.c */\
+ gs_private_st_suffix_add0_local(st_shading_Cp, gs_shading_Cp_t,\
+ "gs_shading_Cp_t", shading_mesh_enum_ptrs, shading_mesh_reloc_ptrs,\
+ st_shading_mesh)
+
+/* Define Tensor product patch mesh shading. */
+typedef struct gs_shading_Tpp_params_s {
+ gs_shading_mesh_params_common;
+ int BitsPerFlag;
+} gs_shading_Tpp_params_t;
+
+#define private_st_shading_Tpp() /* in gsshade.c */\
+ gs_private_st_suffix_add0_local(st_shading_Tpp, gs_shading_Tpp_t,\
+ "gs_shading_Tpp_t", shading_mesh_enum_ptrs, shading_mesh_reloc_ptrs,\
+ st_shading_mesh)
+
+/* ---------------- Procedures ---------------- */
+
+/* Initialize shading parameters of specific types. */
+void gs_shading_Fb_params_init(P1(gs_shading_Fb_params_t * params));
+void gs_shading_A_params_init(P1(gs_shading_A_params_t * params));
+void gs_shading_R_params_init(P1(gs_shading_R_params_t * params));
+void gs_shading_FfGt_params_init(P1(gs_shading_FfGt_params_t * params));
+void gs_shading_LfGt_params_init(P1(gs_shading_LfGt_params_t * params));
+void gs_shading_Cp_params_init(P1(gs_shading_Cp_params_t * params));
+void gs_shading_Tpp_params_init(P1(gs_shading_Tpp_params_t * params));
+
+/* Create (initialize) shadings of specific types. */
+int gs_shading_Fb_init(P3(gs_shading_t ** ppsh,
+ const gs_shading_Fb_params_t * params,
+ gs_memory_t * mem));
+int gs_shading_A_init(P3(gs_shading_t ** ppsh,
+ const gs_shading_A_params_t * params,
+ gs_memory_t * mem));
+int gs_shading_R_init(P3(gs_shading_t ** ppsh,
+ const gs_shading_R_params_t * params,
+ gs_memory_t * mem));
+int gs_shading_FfGt_init(P3(gs_shading_t ** ppsh,
+ const gs_shading_FfGt_params_t * params,
+ gs_memory_t * mem));
+int gs_shading_LfGt_init(P3(gs_shading_t ** ppsh,
+ const gs_shading_LfGt_params_t * params,
+ gs_memory_t * mem));
+int gs_shading_Cp_init(P3(gs_shading_t ** ppsh,
+ const gs_shading_Cp_params_t * params,
+ gs_memory_t * mem));
+int gs_shading_Tpp_init(P3(gs_shading_t ** ppsh,
+ const gs_shading_Tpp_params_t * params,
+ gs_memory_t * mem));
+
+/*
+ * Fill a path with a shading. This is the only externally accessible
+ * procedure for rendering a shading. A NULL path means fill the
+ * shading's geometry (shfill).
+ */
+#ifndef gx_path_DEFINED
+# define gx_path_DEFINED
+typedef struct gx_path_s gx_path;
+#endif
+int gs_shading_fill_path(P4(const gs_shading_t *psh, const gx_path *ppath,
+ gx_device *dev, gs_imager_state *pis));
+
+#endif /* gsshade_INCLUDED */
diff --git a/pstoraster/gsstate.c b/pstoraster/gsstate.c
new file mode 100644
index 000000000..7a7a4157e
--- /dev/null
+++ b/pstoraster/gsstate.c
@@ -0,0 +1,1025 @@
+/* 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$ */
+/* Miscellaneous graphics state operators for Ghostscript library */
+#include "gx.h"
+#include "memory_.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gsutil.h" /* for gs_next_ids */
+#include "gzstate.h"
+#include "gxcspace.h" /* here for gscolor2.h */
+#include "gsalpha.h"
+#include "gscolor2.h"
+#include "gscoord.h" /* for gs_initmatrix */
+#include "gscie.h"
+#include "gxcmap.h"
+#include "gxdevice.h"
+#include "gxpcache.h"
+#include "gzht.h"
+#include "gzline.h"
+#include "gspath.h"
+#include "gzpath.h"
+#include "gzcpath.h"
+
+/* Imported values */
+/* The following should include a 'const', but for some reason */
+/* the Watcom compiler won't accept it, even though it happily accepts */
+/* the same construct everywhere else. */
+extern /*const */ gx_color_map_procs *const cmap_procs_default;
+
+/* Forward references */
+private gs_state *gstate_alloc(P3(gs_memory_t *, client_name_t,
+ const gs_state *));
+private gs_state *gstate_clone(P4(gs_state *, gs_memory_t *, client_name_t,
+ gs_state_copy_reason_t));
+private void gstate_free_contents(P1(gs_state *));
+private int gstate_copy(P4(gs_state *, const gs_state *,
+ gs_state_copy_reason_t, client_name_t));
+
+/*
+ * Graphics state storage management is complicated. There are many
+ * different classes of storage associated with a graphics state:
+ *
+ * (1) The gstate object itself. This includes some objects physically
+ * embedded within the gstate object, but because of garbage collection
+ * requirements, there are no embedded objects that can be
+ * referenced by non-transient pointers. We assume that the gstate
+ * stack "owns" its gstates and that we can free the top gstate when
+ * doing a restore.
+ *
+ * (2) Objects that are referenced directly by the gstate and whose lifetime
+ * is independent of the gstate. These are garbage collected, not
+ * reference counted, so we don't need to do anything special with them
+ * when manipulating gstates. Currently this includes:
+ * font, device
+ *
+ * (3) Objects that are referenced directly by the gstate, may be shared
+ * among gstates, and should disappear when no gstates reference them.
+ * These fall into two groups:
+ *
+ * (3a) Objects that are logically connected to individual gstates.
+ * We use reference counting to manage these. Currently these are:
+ * halftone, dev_ht, cie_render, black_generation,
+ * undercolor_removal, set_transfer.*, cie_joint_caches
+ * effective_transfer.* may point to some of the same objects as
+ * set_transfer.*, but don't contribute to the reference count.
+ * Similarly, dev_color may point to the dev_ht object. For
+ * simplicity, we initialize all of these pointers to 0 and then
+ * allocate the object itself when needed.
+ *
+ * (3b) Objects whose lifetimes are associated with something else.
+ * Currently these are:
+ * ht_cache, which is associated with the entire gstate
+ * stack, is allocated with the very first graphics state,
+ * and currently is never freed;
+ * pattern_cache, which is associated with the entire
+ * stack, is allocated when first needed, and currently
+ * is never freed;
+ * view_clip, which is associated with the current
+ * save level (effectively, with the gstate sub-stack
+ * back to the save) and is managed specially.
+ *
+ * (4) Objects that are referenced directly by exactly one gstate and that
+ * are not referenced (except transiently) from any other object.
+ * These fall into two groups:
+ *
+ * (4b) Objects allocated individually, for the given reason:
+ * line_params.dash.pattern (variable-length),
+ * color_space, path, clip_path, effective_clip.path,
+ * ccolor, dev_color
+ * (may be referenced from image enumerators or elsewhere)
+ *
+ * (4b) The "client data" for a gstate. For the interpreter, this is
+ * the refs associated with the gstate, such as the screen procedures.
+ * Client-supplied procedures manage client data.
+ *
+ * (5) Objects referenced indirectly from gstate objects of category (4),
+ * including objects that may also be referenced directly by the gstate.
+ * The individual routines that manipulate these are responsible
+ * for doing the right kind of reference counting or whatever.
+ * Currently:
+ * path, clip_path, and (if different from both clip_path
+ * and view_clip) effective_clip.path require
+ * gx_path_assign/free, which uses a reference count;
+ * color_space and ccolor require cs_adjust_color/cspace_count
+ * or cs_adjust_counts, which use a reference count;
+ * dev_color has no references to storage that it owns.
+ * We count on garbage collection or restore to deallocate
+ * sub-objects of halftone.
+ *
+ * Note that when after a gsave, the existing gstate references the related
+ * objects that we allocate at the same time, and the newly allocated gstate
+ * references the old related objects. Similarly, during a grestore, we
+ * free the related objects referenced by the current gstate, but after the
+ * grestore, we free the saved gstate, not the current one. However, when
+ * we allocate gstates off-stack, the newly allocated gstate does reference
+ * the newly allocated component objects. Note also that setgstate /
+ * currentgstate may produce gstates in which different allocators own
+ * different sub-objects; this is OK, because restore guarantees that there
+ * won't be any dangling pointers (as long as we don't allow pointers from
+ * global gstates to local objects).
+ */
+
+/*
+ * Enumerate the pointers in a graphics state, other than the ones in the
+ * imager state, and device, which must be handled specially.
+ */
+#define gs_state_do_ptrs(m)\
+ m(0,saved) m(1,path) m(2,clip_path) m(3,view_clip) m(4,effective_clip_path)\
+ m(5,color_space) m(6,ccolor) m(7,dev_color)\
+ m(8,font) m(9,root_font) m(10,show_gstate) /*m(---,device)*/\
+ m(11,client_data)
+#define gs_state_num_ptrs 12
+
+/*
+ * Define these elements of the graphics state that are allocated
+ * individually for each state, except for line_params.dash.pattern.
+ * Note that effective_clip_shared is not on the list.
+ */
+typedef struct gs_state_parts_s {
+ gx_path *path;
+ gx_clip_path *clip_path;
+ gx_clip_path *effective_clip_path;
+ gs_color_space *color_space;
+ gs_client_color *ccolor;
+ gx_device_color *dev_color;
+} gs_state_parts;
+
+#define GSTATE_ASSIGN_PARTS(pto, pfrom)\
+ ((pto)->path = (pfrom)->path, (pto)->clip_path = (pfrom)->clip_path,\
+ (pto)->effective_clip_path = (pfrom)->effective_clip_path,\
+ (pto)->color_space = (pfrom)->color_space,\
+ (pto)->ccolor = (pfrom)->ccolor, (pto)->dev_color = (pfrom)->dev_color)
+
+/* GC descriptors */
+private_st_line_params();
+private_st_imager_state();
+private_st_imager_state_shared();
+private_st_gs_state();
+
+/* GC procedures for gs_imager_state */
+#define pis ((gs_imager_state *)vptr)
+private
+ENUM_PTRS_BEGIN(imager_state_enum_ptrs) ENUM_SUPER(gs_imager_state, st_line_params, line_params, st_imager_state_num_ptrs - st_line_params_num_ptrs);
+
+ENUM_PTR(0, gs_imager_state, shared);
+#define e1(i,elt) ENUM_PTR(i+1,gs_imager_state,elt);
+gs_cr_state_do_ptrs(e1)
+#undef e1
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(imager_state_reloc_ptrs)
+{
+ RELOC_SUPER(gs_imager_state, st_line_params, line_params);
+ RELOC_PTR(gs_imager_state, shared);
+#define r1(i,elt) RELOC_PTR(gs_imager_state,elt);
+ gs_cr_state_do_ptrs(r1)
+#undef r1
+} RELOC_PTRS_END
+#undef pis
+
+/* GC procedures for gs_state */
+#define gsvptr ((gs_state *)vptr)
+private ENUM_PTRS_BEGIN(gs_state_enum_ptrs) ENUM_PREFIX(st_imager_state, gs_state_num_ptrs + 1);
+#define e1(i,elt) ENUM_PTR(i,gs_state,elt);
+gs_state_do_ptrs(e1)
+case gs_state_num_ptrs: /* handle device specially */
+ENUM_RETURN(gx_device_enum_ptr(gsvptr->device));
+#undef e1
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(gs_state_reloc_ptrs)
+{
+ RELOC_PREFIX(st_imager_state);
+ {
+#define r1(i,elt) RELOC_PTR(gs_state,elt);
+ gs_state_do_ptrs(r1)
+#undef r1
+ gsvptr->device = gx_device_reloc_ptr(gsvptr->device, gcst);
+ }
+}
+RELOC_PTRS_END
+#undef gsvptr
+
+/* Copy client data, using the copy_for procedure if available, */
+/* the copy procedure otherwise. */
+private int
+gstate_copy_client_data(gs_state * pgs, void *dto, void *dfrom,
+ gs_state_copy_reason_t reason)
+{
+ return (pgs->client_procs.copy_for != 0 ?
+ (*pgs->client_procs.copy_for) (dto, dfrom, reason) :
+ (*pgs->client_procs.copy) (dto, dfrom));
+}
+
+/* ------ Operations on the entire graphics state ------ */
+
+/* Initialize an imager state, other than the parts covered by */
+/* gs_imager_state_initial. */
+/* The halftone, dev_ht, and ht_cache elements are not set or used. */
+private float
+null_transfer(floatp gray, const gx_transfer_map * pmap)
+{
+ return gray;
+}
+private void
+rc_free_imager_shared(gs_memory_t * mem, void *data, client_name_t cname)
+{
+ gs_imager_state_shared_t * const shared =
+ (gs_imager_state_shared_t *)data;
+
+ if (shared->cs_DeviceCMYK) {
+ gs_cspace_release(shared->cs_DeviceCMYK);
+ gs_free_object(mem, shared->cs_DeviceCMYK, "shared DeviceCMYK");
+ }
+ if (shared->cs_DeviceRGB) {
+ gs_cspace_release(shared->cs_DeviceRGB);
+ gs_free_object(mem, shared->cs_DeviceRGB, "shared DeviceRGB");
+ }
+ if (shared->cs_DeviceGray) {
+ gs_cspace_release(shared->cs_DeviceGray);
+ gs_free_object(mem, shared->cs_DeviceGray, "shared DeviceGray");
+ }
+ rc_free_struct_only(mem, data, cname);
+}
+
+int
+gs_imager_state_initialize(gs_imager_state * pis, gs_memory_t * mem)
+{
+ pis->memory = mem;
+ /* Preallocate color spaces. */
+ {
+ int code;
+ gs_imager_state_shared_t *shared;
+
+ rc_alloc_struct_1(shared, gs_imager_state_shared_t,
+ &st_imager_state_shared, mem,
+ return_error(gs_error_VMerror),
+ "gs_imager_state_init(shared)");
+ shared->cs_DeviceGray = shared->cs_DeviceRGB =
+ shared->cs_DeviceCMYK = 0; /* in case we bail out */
+ shared->rc.free = rc_free_imager_shared;
+ if ((code = gs_cspace_build_DeviceGray(&shared->cs_DeviceGray, mem)) < 0 ||
+ (code = gs_cspace_build_DeviceRGB(&shared->cs_DeviceRGB, mem)) < 0 ||
+ (code = gs_cspace_build_DeviceCMYK(&shared->cs_DeviceCMYK, mem)) < 0
+ ) {
+ rc_free_imager_shared(mem, shared, "gs_imager_state_init(shared)");
+ return code;
+ }
+ pis->shared = shared;
+ }
+ /* Skip halftone */
+ {
+ int i;
+
+ for (i = 0; i < gs_color_select_count; ++i)
+ pis->screen_phase[i].x = pis->screen_phase[i].y = 0;
+ }
+ /* Skip dev_ht */
+ /* Skip ht_cache */
+ pis->cie_render = 0;
+ pis->black_generation = 0;
+ pis->undercolor_removal = 0;
+ /* Allocate an initial transfer map. */
+ rc_alloc_struct_n(pis->set_transfer.colored.gray,
+ gx_transfer_map, &st_transfer_map,
+ mem, return_error(gs_error_VMerror),
+ "gs_imager_state_init(transfer)", 4);
+ pis->set_transfer.colored.gray->proc = null_transfer;
+ pis->set_transfer.colored.gray->id = gs_next_ids(1);
+ pis->set_transfer.colored.gray->values[0] = frac_0;
+ pis->set_transfer.colored.red =
+ pis->set_transfer.colored.green =
+ pis->set_transfer.colored.blue =
+ pis->set_transfer.colored.gray;
+ pis->effective_transfer = pis->set_transfer;
+ pis->cie_joint_caches = 0;
+ pis->cmap_procs = cmap_procs_default;
+ pis->pattern_cache = 0;
+ return 0;
+}
+
+/* Release an imager state. */
+void
+gs_imager_state_release(gs_imager_state * pis)
+{
+ const char *const cname = "gs_imager_state_release";
+
+#define RCDECR(element)\
+ rc_decrement(pis->element, cname)
+
+ RCDECR(cie_joint_caches);
+ RCDECR(set_transfer.colored.gray);
+ RCDECR(set_transfer.colored.blue);
+ RCDECR(set_transfer.colored.green);
+ RCDECR(set_transfer.colored.red);
+ RCDECR(undercolor_removal);
+ RCDECR(black_generation);
+ RCDECR(cie_render);
+ RCDECR(shared);
+#undef RCDECR
+}
+
+/* Allocate and initialize a graphics state. */
+gs_state *
+gs_state_alloc(gs_memory_t * mem)
+{
+ gs_state *pgs = gstate_alloc(mem, "gs_state_alloc", NULL);
+
+ if (pgs == 0)
+ return 0;
+ {
+ static const gs_imager_state gstate_initial =
+ {
+ gs_imager_state_initial(1.0)
+ };
+
+ *(gs_imager_state *) pgs = gstate_initial;
+ }
+ /*
+ * Just enough of the state is initialized at this point
+ * that it's OK to call gs_state_free if an allocation fails.
+ */
+ rc_alloc_struct_1(pgs->halftone, gs_halftone, &st_halftone, mem,
+ goto fail, "gs_state_alloc(halftone)");
+ pgs->saved = 0;
+
+ /* Initialize the color rendering state. */
+
+ pgs->halftone->type = ht_type_none;
+ pgs->dev_ht = 0;
+ pgs->ht_cache = gx_ht_alloc_cache(mem,
+ gx_ht_cache_default_tiles(),
+ gx_ht_cache_default_bits());
+ gs_imager_state_initialize((gs_imager_state *) pgs, mem);
+ pgs->client_data = 0;
+
+ /* Initialize other things not covered by initgraphics */
+
+ pgs->path = gx_path_alloc(mem, "gs_state_alloc(path)");
+ pgs->clip_path = gx_cpath_alloc(mem, "gs_state_alloc(clip_path)");
+ pgs->view_clip = gx_cpath_alloc(mem, "gs_state_alloc(view_clip)");
+ pgs->view_clip->rule = 0; /* no clipping */
+ pgs->effective_clip_id = pgs->clip_path->id;
+ pgs->effective_view_clip_id = gs_no_id;
+ pgs->effective_clip_path = pgs->clip_path;
+ pgs->effective_clip_shared = true;
+ /* Initialize things so that gx_remap_color won't crash. */
+ pgs->color_space->type = &gs_color_space_type_DeviceGray;
+ gx_set_device_color_1(pgs);
+ pgs->overprint = false;
+ pgs->device = 0; /* setting device adjusts refcts */
+ gs_nulldevice(pgs);
+ gs_setalpha(pgs, 1.0);
+ gs_settransfer(pgs, null_transfer);
+ gs_setflat(pgs, 1.0);
+ gs_setfilladjust(pgs, 0.25, 0.25);
+ gs_setlimitclamp(pgs, false);
+ gs_setstrokeadjust(pgs, true);
+ pgs->font = 0; /* Not right, but acceptable until the */
+ /* PostScript code does the first setfont. */
+ pgs->root_font = 0; /* ditto */
+ pgs->in_cachedevice = 0;
+ pgs->in_charpath = (gs_char_path_mode) 0;
+ pgs->show_gstate = 0;
+ pgs->level = 0;
+ pgs->client_data = 0;
+ if (gs_initgraphics(pgs) < 0) {
+ /* Something went very wrong */
+ return 0;
+ }
+ return pgs;
+ fail:
+ gs_state_free(pgs);
+ return 0;
+}
+
+/* Set the client data in a graphics state. */
+/* This should only be done to a newly created state. */
+void
+gs_state_set_client(gs_state * pgs, void *pdata,
+ const gs_state_client_procs * pprocs)
+{
+ pgs->client_data = pdata;
+ pgs->client_procs = *pprocs;
+}
+
+/* Get the client data from a graphics state. */
+#undef gs_state_client_data /* gzstate.h makes this a macro */
+void *
+gs_state_client_data(const gs_state * pgs)
+{
+ return pgs->client_data;
+}
+
+/* Free a graphics state. */
+int
+gs_state_free(gs_state * pgs)
+{
+ gstate_free_contents(pgs);
+ gs_free_object(pgs->memory, pgs, "gs_state_free");
+ return 0;
+}
+
+/* Save the graphics state. */
+int
+gs_gsave(gs_state * pgs)
+{
+ gs_state *pnew = gstate_clone(pgs, pgs->memory, "gs_gsave",
+ copy_for_gsave);
+
+ if (pnew == 0)
+ return_error(gs_error_VMerror);
+ pgs->saved = pnew;
+ if (pgs->show_gstate == pgs)
+ pgs->show_gstate = pnew->show_gstate = pnew;
+ pgs->level++;
+ if_debug2('g', "[g]gsave -> 0x%lx, level = %d\n",
+ (ulong) pnew, pgs->level);
+ return 0;
+}
+
+/* Save the graphics state for a 'save'. */
+/* We cut the stack below the new gstate, and return the old one. */
+/* In addition to an ordinary gsave, we create a new view clip path. */
+int
+gs_gsave_for_save(gs_state * pgs, gs_state ** psaved)
+{
+ int code;
+ gx_clip_path *old_cpath = pgs->view_clip;
+ gx_clip_path *new_cpath;
+
+ if (old_cpath) {
+ new_cpath =
+ gx_cpath_alloc_shared(old_cpath, pgs->memory,
+ "gs_gsave_for_save(view_clip)");
+ if (new_cpath == 0)
+ return_error(gs_error_VMerror);
+ } else {
+ new_cpath = 0;
+ }
+ code = gs_gsave(pgs);
+ if (code < 0) {
+ if (new_cpath)
+ gx_cpath_free(new_cpath, "gs_gsave_for_save(view_clip)");
+ return code;
+ }
+ if (pgs->effective_clip_path == pgs->view_clip)
+ pgs->effective_clip_path = new_cpath;
+ pgs->view_clip = new_cpath;
+ /* Cut the stack so we can't grestore past here. */
+ *psaved = pgs->saved;
+ pgs->saved = 0;
+ return code;
+}
+
+/* Restore the graphics state. */
+int
+gs_grestore(gs_state * pgs)
+{
+ gs_state *saved = pgs->saved;
+ void *pdata = pgs->client_data;
+ void *sdata;
+
+ if_debug2('g', "[g]grestore 0x%lx, level was %d\n",
+ (ulong) saved, pgs->level);
+ if (!saved) /* shouldn't happen */
+ return gs_gsave(pgs);
+ sdata = saved->client_data;
+ if (saved->pattern_cache == 0)
+ saved->pattern_cache = pgs->pattern_cache;
+ /* Swap back the client data pointers. */
+ pgs->client_data = sdata;
+ saved->client_data = pdata;
+ if (pdata != 0 && sdata != 0)
+ gstate_copy_client_data(pgs, pdata, sdata, copy_for_grestore);
+ gstate_free_contents(pgs);
+ *pgs = *saved;
+ if (pgs->show_gstate == saved)
+ pgs->show_gstate = pgs;
+ gs_free_object(pgs->memory, saved, "gs_grestore");
+ if (pgs->saved)
+ return 0;
+ return gs_gsave(pgs);
+}
+
+/* Restore the graphics state for a 'restore', splicing the old stack */
+/* back on. Note that we actually do a grestoreall + 2 grestores. */
+int
+gs_grestoreall_for_restore(gs_state * pgs, gs_state * saved)
+{
+ int code;
+
+ while (pgs->saved->saved) {
+ code = gs_grestore(pgs);
+ if (code < 0)
+ return code;
+ }
+ /* Make sure we don't leave dangling pointers in the caches. */
+ gx_ht_clear_cache(pgs->ht_cache);
+ if (pgs->pattern_cache)
+ (*pgs->pattern_cache->free_all) (pgs->pattern_cache);
+ pgs->saved->saved = saved;
+ code = gs_grestore(pgs);
+ if (code < 0)
+ return code;
+ if (pgs->view_clip) {
+ gx_cpath_free(pgs->view_clip, "gs_grestoreall_for_restore");
+ pgs->view_clip = 0;
+ }
+ return gs_grestore(pgs);
+}
+
+
+/* Restore to the bottommost graphics state (at this save level). */
+int
+gs_grestoreall(gs_state * pgs)
+{
+ int code;
+
+ if (!pgs->saved) /* shouldn't happen */
+ return gs_gsave(pgs);
+ while (pgs->saved->saved) {
+ code = gs_grestore(pgs);
+ if (code < 0)
+ return code;
+ }
+ code = gs_grestore(pgs);
+ if (code < 0)
+ return code;
+ return code;
+}
+
+/* Allocate and return a new graphics state. */
+gs_state *
+gs_gstate(gs_state * pgs)
+{
+ return gs_state_copy(pgs, pgs->memory);
+}
+gs_state *
+gs_state_copy(gs_state * pgs, gs_memory_t * mem)
+{
+ gs_state *pnew;
+
+ /* Prevent 'capturing' the view clip path. */
+ gx_clip_path *view_clip = pgs->view_clip;
+
+ pgs->view_clip = 0;
+ pnew = gstate_clone(pgs, mem, "gs_gstate", copy_for_gstate);
+ pgs->view_clip = view_clip;
+ if (pnew == 0)
+ return 0;
+ pnew->saved = 0;
+ /*
+ * Prevent dangling references from the show_gstate pointer. If
+ * this context is its own show_gstate, set the pointer in the clone
+ * to point to the clone; otherwise, set the pointer in the clone to
+ * 0, and let gs_setgstate fix it up.
+ */
+ pnew->show_gstate =
+ (pgs->show_gstate == pgs ? pnew : 0);
+ return pnew;
+}
+
+/* Copy one previously allocated graphics state to another. */
+int
+gs_copygstate(gs_state * pto, const gs_state * pfrom)
+{
+ return gstate_copy(pto, pfrom, copy_for_copygstate, "gs_copygstate");
+}
+
+/* Copy the current graphics state to a previously allocated one. */
+int
+gs_currentgstate(gs_state * pto, const gs_state * pgs)
+{
+ int code =
+ gstate_copy(pto, pgs, copy_for_currentgstate, "gs_currentgstate");
+
+ if (code >= 0)
+ pto->view_clip = 0;
+ return code;
+}
+
+/* Restore the current graphics state from a previously allocated one. */
+int
+gs_setgstate(gs_state * pgs, const gs_state * pfrom)
+{
+ /*
+ * The implementation is the same as currentgstate,
+ * except we must preserve the saved pointer, the level,
+ * the view clip, and possibly the show_gstate.
+ */
+ gs_state *saved_show = pgs->show_gstate;
+ int level = pgs->level;
+ gx_clip_path *view_clip = pgs->view_clip;
+ int code;
+
+ pgs->view_clip = 0; /* prevent refcount decrementing */
+ code = gstate_copy(pgs, pfrom, copy_for_setgstate, "gs_setgstate");
+ if (code < 0)
+ return code;
+ pgs->level = level;
+ pgs->view_clip = view_clip;
+ pgs->show_gstate =
+ (pgs->show_gstate == pfrom ? pgs : saved_show);
+ return 0;
+}
+
+/* Get the allocator pointer of a graphics state. */
+/* This is provided only for the interpreter */
+/* and for color space implementation. */
+gs_memory_t *
+gs_state_memory(const gs_state * pgs)
+{
+ return pgs->memory;
+}
+
+/* Get the saved pointer of the graphics state. */
+/* This is provided only for Level 2 grestore. */
+gs_state *
+gs_state_saved(const gs_state * pgs)
+{
+ return pgs->saved;
+}
+
+/* Swap the saved pointer of the graphics state. */
+/* This is provided only for save/restore. */
+gs_state *
+gs_state_swap_saved(gs_state * pgs, gs_state * new_saved)
+{
+ gs_state *saved = pgs->saved;
+
+ pgs->saved = new_saved;
+ return saved;
+}
+
+/* Swap the memory pointer of the graphics state. */
+/* This is provided only for the interpreter. */
+gs_memory_t *
+gs_state_swap_memory(gs_state * pgs, gs_memory_t * mem)
+{
+ gs_memory_t *memory = pgs->memory;
+
+ pgs->memory = mem;
+ return memory;
+}
+
+/* ------ Operations on components ------ */
+
+/* Reset most of the graphics state */
+int
+gs_initgraphics(gs_state * pgs)
+{
+ int code;
+
+ gs_initmatrix(pgs);
+ if ((code = gs_newpath(pgs)) < 0 ||
+ (code = gs_initclip(pgs)) < 0 ||
+ (code = gs_setlinewidth(pgs, 1.0)) < 0 ||
+ (code = gs_setlinecap(pgs, gs_cap_butt)) < 0 ||
+ (code = gs_setlinejoin(pgs, gs_join_miter)) < 0 ||
+ (code = gs_setdash(pgs, (float *)0, 0, 0.0)) < 0 ||
+ (gs_setdashadapt(pgs, false),
+ (code = gs_setdotlength(pgs, 0.0, false))) < 0 ||
+ (code = gs_setgray(pgs, 0.0)) < 0 ||
+ (code = gs_setmiterlimit(pgs, 10.0)) < 0
+ )
+ return code;
+ gs_init_rop(pgs);
+ return 0;
+}
+
+/* setfilladjust */
+int
+gs_setfilladjust(gs_state * pgs, floatp adjust_x, floatp adjust_y)
+{
+#define CLAMP_TO_HALF(v)\
+ ((v) <= 0 ? fixed_0 : (v) >= 0.5 ? fixed_half : float2fixed(v));
+
+ pgs->fill_adjust.x = CLAMP_TO_HALF(adjust_x);
+ pgs->fill_adjust.y = CLAMP_TO_HALF(adjust_y);
+ return 0;
+#undef CLAMP_TO_HALF
+}
+
+/* currentfilladjust */
+int
+gs_currentfilladjust(const gs_state * pgs, gs_point * adjust)
+{
+ adjust->x = fixed2float(pgs->fill_adjust.x);
+ adjust->y = fixed2float(pgs->fill_adjust.y);
+ return 0;
+}
+
+/* setlimitclamp */
+void
+gs_setlimitclamp(gs_state * pgs, bool clamp)
+{
+ pgs->clamp_coordinates = clamp;
+}
+
+/* currentlimitclamp */
+bool
+gs_currentlimitclamp(const gs_state * pgs)
+{
+ return pgs->clamp_coordinates;
+}
+
+/* ------ Internal routines ------ */
+
+/* Free the privately allocated parts of a gstate. */
+private void
+gstate_free_parts(const gs_state * parts, gs_memory_t * mem, client_name_t cname)
+{
+ gs_free_object(mem, parts->dev_color, cname);
+ gs_free_object(mem, parts->ccolor, cname);
+ gs_free_object(mem, parts->color_space, cname);
+ if (!parts->effective_clip_shared)
+ gx_cpath_free(parts->effective_clip_path, cname);
+ gx_cpath_free(parts->clip_path, cname);
+ gx_path_free(parts->path, cname);
+}
+
+/* Allocate the privately allocated parts of a gstate. */
+private int
+gstate_alloc_parts(gs_state * parts, const gs_state * shared,
+ gs_memory_t * mem, client_name_t cname)
+{
+ parts->path =
+ (shared ?
+ gx_path_alloc_shared(shared->path, mem,
+ "gstate_alloc_parts(path)") :
+ gx_path_alloc(mem, "gstate_alloc_parts(path)"));
+ parts->clip_path =
+ (shared ?
+ gx_cpath_alloc_shared(shared->clip_path, mem,
+ "gstate_alloc_parts(clip_path)") :
+ gx_cpath_alloc(mem, "gstate_alloc_parts(clip_path)"));
+ if (!shared || shared->effective_clip_shared) {
+ parts->effective_clip_path = parts->clip_path;
+ parts->effective_clip_shared = true;
+ } else {
+ parts->effective_clip_path =
+ gx_cpath_alloc_shared(shared->effective_clip_path, mem,
+ "gstate_alloc_parts(effective_clip_path)");
+ parts->effective_clip_shared = false;
+ }
+ parts->color_space =
+ gs_alloc_struct(mem, gs_color_space, &st_color_space, cname);
+ parts->ccolor =
+ gs_alloc_struct(mem, gs_client_color, &st_client_color, cname);
+ parts->dev_color =
+ gs_alloc_struct(mem, gx_device_color, &st_device_color, cname);
+ if (parts->path == 0 || parts->clip_path == 0 ||
+ parts->effective_clip_path == 0 ||
+ parts->color_space == 0 || parts->ccolor == 0 ||
+ parts->dev_color == 0
+ ) {
+ gstate_free_parts(parts, mem, cname);
+ return_error(gs_error_VMerror);
+ }
+ return 0;
+}
+
+/*
+ * Allocate a gstate and its contents.
+ * If pfrom is not NULL, the path, clip_path, and (if distinct from both
+ * clip_path and view_clip) effective_clip_path share the segments of
+ * pfrom's corresponding path(s).
+ */
+private gs_state *
+gstate_alloc(gs_memory_t * mem, client_name_t cname, const gs_state * pfrom)
+{
+ gs_state *pgs =
+ gs_alloc_struct(mem, gs_state, &st_gs_state, cname);
+
+ if (pgs == 0)
+ return 0;
+ if (gstate_alloc_parts(pgs, pfrom, mem, cname) < 0) {
+ gs_free_object(mem, pgs, cname);
+ return 0;
+ }
+ pgs->memory = mem;
+ return pgs;
+}
+
+/* Copy the dash pattern from one gstate to another. */
+private int
+gstate_copy_dash(gs_state * pto, const gs_state * pfrom)
+{
+ return gs_setdash(pto, pfrom->line_params.dash.pattern,
+ pfrom->line_params.dash.pattern_size,
+ pfrom->line_params.dash.offset);
+}
+
+/* Clone an existing graphics state. */
+/* Return 0 if the allocation fails. */
+/* If reason is for_gsave, the clone refers to the old contents, */
+/* and we switch the old state to refer to the new contents. */
+private gs_state *
+gstate_clone(gs_state * pfrom, gs_memory_t * mem, client_name_t cname,
+ gs_state_copy_reason_t reason)
+{
+ gs_state *pgs = gstate_alloc(mem, cname, pfrom);
+ gs_state_parts parts;
+
+ if (pgs == 0)
+ return 0;
+ GSTATE_ASSIGN_PARTS(&parts, pgs);
+ *pgs = *pfrom;
+ /* Copy the dash pattern if necessary. */
+ if (pgs->line_params.dash.pattern) {
+ int code;
+
+ pgs->line_params.dash.pattern = 0; /* force allocation */
+ code = gstate_copy_dash(pgs, pfrom);
+ if (code < 0)
+ goto fail;
+ }
+ if (pgs->client_data != 0) {
+ void *pdata = pgs->client_data = (*pgs->client_procs.alloc) (mem);
+
+ if (pdata == 0 ||
+ gstate_copy_client_data(pgs, pdata, pfrom->client_data, reason) < 0
+ )
+ goto fail;
+ }
+ rc_increment(pgs->set_transfer.colored.gray);
+ rc_increment(pgs->set_transfer.colored.red);
+ rc_increment(pgs->set_transfer.colored.green);
+ rc_increment(pgs->set_transfer.colored.blue);
+ rc_increment(pgs->halftone);
+ rc_increment(pgs->dev_ht);
+ rc_increment(pgs->cie_render);
+ rc_increment(pgs->black_generation);
+ rc_increment(pgs->undercolor_removal);
+ rc_increment(pgs->cie_joint_caches);
+ rc_increment(pgs->device);
+ *parts.color_space = *pfrom->color_space;
+ *parts.ccolor = *pfrom->ccolor;
+ *parts.dev_color = *pfrom->dev_color;
+ if (reason == copy_for_gsave) {
+ float *dfrom = pfrom->line_params.dash.pattern;
+ float *dto = pgs->line_params.dash.pattern;
+
+ GSTATE_ASSIGN_PARTS(pfrom, &parts);
+ pgs->line_params.dash.pattern = dfrom;
+ pfrom->line_params.dash.pattern = dto;
+ } else {
+ GSTATE_ASSIGN_PARTS(pgs, &parts);
+ }
+ cs_adjust_counts(pgs, 1);
+ return pgs;
+ fail:
+ gs_free_object(mem, pgs->line_params.dash.pattern, cname);
+ GSTATE_ASSIGN_PARTS(pgs, &parts);
+ gstate_free_parts(pgs, mem, cname);
+ gs_free_object(mem, pgs, cname);
+ return 0;
+}
+
+/* Release the composite parts of a graphics state, */
+/* but not the state itself. */
+private void
+gstate_free_contents(gs_state * pgs)
+{
+ gs_memory_t *mem = pgs->memory;
+ gx_device_halftone *pdht = pgs->dev_ht;
+ const char *const cname = "gstate_free_contents";
+
+#define RCDECR(element)\
+ rc_decrement(pgs->element, cname)
+
+ RCDECR(device);
+ RCDECR(cie_joint_caches);
+ RCDECR(set_transfer.colored.gray);
+ RCDECR(set_transfer.colored.blue);
+ RCDECR(set_transfer.colored.green);
+ RCDECR(set_transfer.colored.red);
+ RCDECR(undercolor_removal);
+ RCDECR(black_generation);
+ RCDECR(cie_render);
+ if (pdht != 0 && pdht->rc.ref_count == 1) {
+ /* Make sure we don't leave dangling pointers in the cache. */
+ gx_ht_cache *pcache = pgs->ht_cache;
+
+ if (pcache->order.bits == pdht->order.bits ||
+ pcache->order.levels == pdht->order.levels
+ )
+ gx_ht_clear_cache(pcache);
+ gx_device_halftone_release(pdht, pdht->rc.memory);
+ }
+ RCDECR(dev_ht);
+ RCDECR(halftone);
+ cs_adjust_counts(pgs, -1);
+ if (pgs->client_data != 0)
+ (*pgs->client_procs.free) (pgs->client_data, mem);
+ gs_free_object(mem, pgs->line_params.dash.pattern, cname);
+ gstate_free_parts(pgs, mem, cname);
+#undef RCDECR
+}
+
+/* Copy one gstate to another. */
+private int
+gstate_copy(gs_state * pto, const gs_state * pfrom,
+ gs_state_copy_reason_t reason, client_name_t cname)
+{
+ gs_state_parts parts;
+
+ GSTATE_ASSIGN_PARTS(&parts, pto);
+ /* Copy the dash pattern if necessary. */
+ if (pfrom->line_params.dash.pattern || pto->line_params.dash.pattern) {
+ int code = gstate_copy_dash(pto, pfrom);
+
+ if (code < 0)
+ return code;
+ }
+ /*
+ * It's OK to decrement the counts before incrementing them,
+ * because anything that is going to survive has a count of
+ * at least 2 (pto and somewhere else) initially.
+ * Handle references from contents.
+ */
+ cs_adjust_counts(pto, -1);
+ gx_path_assign_preserve(pto->path, pfrom->path);
+ gx_cpath_assign_preserve(pto->clip_path, pfrom->clip_path);
+ /*
+ * effective_clip_shared will be copied, but we need to do the
+ * right thing with effective_clip_path.
+ */
+ if (pfrom->effective_clip_shared) {
+ /*
+ * pfrom->effective_clip_path is either pfrom->view_clip or
+ * pfrom->clip_path.
+ */
+ parts.effective_clip_path =
+ (pfrom->effective_clip_path == pfrom->view_clip ?
+ pto->view_clip : parts.clip_path);
+ } else
+ gx_cpath_assign_preserve(pto->effective_clip_path,
+ pfrom->effective_clip_path);
+ *parts.color_space = *pfrom->color_space;
+ *parts.ccolor = *pfrom->ccolor;
+ *parts.dev_color = *pfrom->dev_color;
+ cs_adjust_counts(pto, 1);
+ /* Handle references from gstate object. */
+#define RCCOPY(element)\
+ rc_pre_assign(pto->element, pfrom->element, cname)
+ RCCOPY(device);
+ RCCOPY(cie_joint_caches);
+ RCCOPY(set_transfer.colored.gray);
+ RCCOPY(set_transfer.colored.blue);
+ RCCOPY(set_transfer.colored.green);
+ RCCOPY(set_transfer.colored.red);
+ RCCOPY(undercolor_removal);
+ RCCOPY(black_generation);
+ RCCOPY(cie_render);
+ RCCOPY(dev_ht);
+ RCCOPY(halftone);
+ {
+ struct gx_pattern_cache_s *pcache = pto->pattern_cache;
+ void *pdata = pto->client_data;
+ gs_memory_t *mem = pto->memory;
+ gs_state *saved = pto->saved;
+ float *pattern = pto->line_params.dash.pattern;
+
+ *pto = *pfrom;
+ pto->client_data = pdata;
+ pto->memory = mem;
+ pto->saved = saved;
+ pto->line_params.dash.pattern = pattern;
+ if (pto->pattern_cache == 0)
+ pto->pattern_cache = pcache;
+ if (pfrom->client_data != 0) {
+ /* We need to break 'const' here. */
+ gstate_copy_client_data((gs_state *) pfrom, pdata,
+ pfrom->client_data, reason);
+ }
+ }
+ GSTATE_ASSIGN_PARTS(pto, &parts);
+#undef RCCOPY
+ pto->show_gstate =
+ (pfrom->show_gstate == pfrom ? pto : 0);
+ return 0;
+}
diff --git a/pstoraster/gsstate.h b/pstoraster/gsstate.h
new file mode 100644
index 000000000..65641a57f
--- /dev/null
+++ b/pstoraster/gsstate.h
@@ -0,0 +1,81 @@
+/* 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$ */
+/* Public graphics state API */
+
+#ifndef gsstate_INCLUDED
+# define gsstate_INCLUDED
+
+/* Opaque type for a graphics state */
+#ifndef gs_state_DEFINED
+# define gs_state_DEFINED
+typedef struct gs_state_s gs_state;
+
+#endif
+
+/* Initial allocation and freeing */
+gs_state *gs_state_alloc(P1(gs_memory_t *)); /* 0 if fails */
+int gs_state_free(P1(gs_state *));
+
+/* Initialization, saving, restoring, and copying */
+int gs_gsave(P1(gs_state *)), gs_grestore(P1(gs_state *)), gs_grestoreall(P1(gs_state *));
+int gs_gsave_for_save(P2(gs_state *, gs_state **)), gs_grestoreall_for_restore(P2(gs_state *, gs_state *));
+gs_state *gs_gstate(P1(gs_state *));
+gs_state *gs_state_copy(P2(gs_state *, gs_memory_t *));
+int gs_copygstate(P2(gs_state * /*to */ , const gs_state * /*from */ )),
+ gs_currentgstate(P2(gs_state * /*to */ , const gs_state * /*from */ )),
+ gs_setgstate(P2(gs_state * /*to */ , const gs_state * /*from */ ));
+int gs_initgraphics(P1(gs_state *));
+
+/* Device control */
+#include "gsdevice.h"
+
+/* Line parameters and quality */
+#include "gsline.h"
+
+/* Color and gray */
+#include "gscolor.h"
+
+/* Halftone screen */
+#include "gsht.h"
+#include "gscsel.h"
+int gs_setscreenphase(P4(gs_state *, int, int, gs_color_select_t));
+int gs_currentscreenphase(P3(const gs_state *, gs_int_point *,
+ gs_color_select_t));
+
+#define gs_sethalftonephase(pgs, px, py)\
+ gs_setscreenphase(pgs, px, py, gs_color_select_all)
+#define gs_currenthalftonephase(pgs, ppt)\
+ gs_currentscreenphase(pgs, ppt, 0)
+int gx_imager_setscreenphase(P4(gs_imager_state *, int, int,
+ gs_color_select_t));
+
+/* Miscellaneous */
+int gs_setfilladjust(P3(gs_state *, floatp, floatp));
+int gs_currentfilladjust(P2(const gs_state *, gs_point *));
+void gs_setlimitclamp(P2(gs_state *, bool));
+bool gs_currentlimitclamp(P1(const gs_state *));
+
+#endif /* gsstate_INCLUDED */
diff --git a/pstoraster/gsstruct.h b/pstoraster/gsstruct.h
new file mode 100644
index 000000000..f1d0ba825
--- /dev/null
+++ b/pstoraster/gsstruct.h
@@ -0,0 +1,970 @@
+/* Copyright (C) 1993, 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 Ghostscript modules that define allocatable structures */
+/* Requires gstypes.h */
+
+#ifndef gsstruct_INCLUDED
+# define gsstruct_INCLUDED
+
+/*
+ * Ghostscript structures are defined with names of the form (gs_)xxx_s,
+ * with a corresponding typedef of the form (gs_)xxx or (gs_)xxx_t.
+ * By extension, the structure descriptor is named st_[gs_]xxx.
+ * (Note that the descriptor name may omit the gs_ even if the type has it.)
+ * Structure descriptors are always allocated statically and are
+ * always const; they may be either public or private.
+ *
+ * In order to ensure that there is a descriptor for each structure type,
+ * we require, by convention, that the following always appear together
+ * if the structure is defined in a .h file:
+ * - The definition of the structure xxx_s;
+ * - If the descriptor is public, an extern_st(st_xxx);
+ * - The definition of a macro public_st_xxx() or private_st_xxx()
+ * that creates the actual descriptor.
+ * This convention makes the descriptor visible (if public) to any module
+ * that can see the structure definition. This is more liberal than
+ * we would like, but it is a reasonable compromise between restricting
+ * visibility and keeping all the definitional elements of a structure
+ * together. We require that there be no other externs for (public)
+ * structure descriptors; if the definer of a structure wants to make
+ * available the ability to create an instance but does not want to
+ * expose the structure definition, it must export a creator procedure.
+ *
+ * Because of bugs in some compilers' bookkeeping for undefined structure
+ * types, any file that uses extern_st must include gsstruct.h.
+ * (If it weren't for these bugs, the definition of extern_st could
+ * go in gsmemory.h.)
+ */
+#define extern_st(st) extern const gs_memory_struct_type_t st
+/*
+ * If the structure is defined in a .c file, we require that the following
+ * appear together:
+ * - The definition of the structure xxx_s;
+ * - The gs_private_st_xxx macro that creates the descriptor.
+ * Note that we only allow this if the structure is completely private
+ * to a single file. Again, the file must export a creator procedure
+ * if it wants external clients to be able to create instances.
+ *
+ * Some structures are embedded inside others. In order to be able to
+ * construct the composite pointer enumeration procedures, for such
+ * structures we must define not only the st_xxx descriptor, but also
+ * a st_xxx_max_ptrs constant that gives the maximum number of pointers
+ * the enumeration procedure will return. This is an unfortunate consequence
+ * of the method we have chosen for implementing pointer enumeration.
+ *
+ * Some structures may exist as elements of homogenous arrays.
+ * In order to be able to enumerate and relocate such arrays, we adopt
+ * the convention that the structure representing an element must be
+ * distinguished from the structure per se, and the name of the element
+ * structure always ends with "_element". Element structures cannot be
+ * embedded in other structures.
+ *
+ * Note that the definition of the xxx_s structure may be separate from
+ * the typedef for the type xxx(_t). This still allows us to have full
+ * structure type abstraction.
+ *
+ * Descriptor definitions are not required for structures to which
+ * no traceable pointers from garbage-collectable space will ever exist.
+ * For example, the struct that defines structure types themselves does not
+ * require a descriptor.
+ */
+
+/* An opaque type for an object header. */
+#ifndef obj_header_DEFINED
+# define obj_header_DEFINED
+typedef struct obj_header_s obj_header_t;
+
+#endif
+
+/* Define an opaque type for the garbage collector state. */
+typedef struct gc_state_s gc_state_t;
+
+/*
+ * Define pointer types, which define how to mark the referent of the
+ * pointer.
+ */
+/*typedef struct gs_ptr_procs_s gs_ptr_procs_t;*/ /* in gsmemory.h */
+struct gs_ptr_procs_s {
+
+ /* Unmark the referent of a pointer. */
+
+#define ptr_proc_unmark(proc)\
+ void proc(P2(void *, gc_state_t *))
+ ptr_proc_unmark((*unmark));
+
+ /* Mark the referent of a pointer. */
+ /* Return true iff it was unmarked before. */
+
+#define ptr_proc_mark(proc)\
+ bool proc(P2(void *, gc_state_t *))
+ ptr_proc_mark((*mark));
+
+ /* Relocate a pointer. */
+ /* Note that the argument is const, but the */
+ /* return value is not: this shifts the compiler */
+ /* 'discarding const' warning from the call sites */
+ /* (the reloc_ptr routines) to the implementations. */
+
+#define ptr_proc_reloc(proc, typ)\
+ typ *proc(P2(const typ *, gc_state_t *))
+ ptr_proc_reloc((*reloc), void);
+
+};
+/*typedef const gs_ptr_procs_t *gs_ptr_type_t;*/ /* in gsmemory.h */
+
+/* Define the pointer type for ordinary structure pointers. */
+extern const gs_ptr_procs_t ptr_struct_procs;
+#define ptr_struct_type (&ptr_struct_procs)
+
+/* Define the pointer types for a pointer to a gs_[const_]string. */
+extern const gs_ptr_procs_t ptr_string_procs;
+#define ptr_string_type (&ptr_string_procs)
+extern const gs_ptr_procs_t ptr_const_string_procs;
+#define ptr_const_string_type (&ptr_const_string_procs)
+
+/*
+ * Define the type for a GC root.
+ */
+/*typedef struct gs_gc_root_s gs_gc_root_t;*/ /* in gsmemory.h */
+struct gs_gc_root_s {
+ gs_gc_root_t *next;
+ gs_ptr_type_t ptype;
+ void **p;
+ bool free_on_unregister;
+};
+
+#define public_st_gc_root_t() /* in gsmemory.c */\
+ gs_public_st_ptrs1(st_gc_root_t, gs_gc_root_t, "gs_gc_root_t",\
+ gc_root_enum_ptrs, gc_root_reloc_ptrs, next)
+
+/* Print a root debugging message. */
+#define if_debug_root(c, msg, rp)\
+ if_debug4(c, "%s 0x%lx: 0x%lx -> 0x%lx\n",\
+ msg, (ulong)(rp), (ulong)(rp)->p, (ulong)*(rp)->p)
+
+/*
+ * We don't want to tie the allocator to using a single garbage collector,
+ * so we pass all the relevant GC procedures in to the structure pointer
+ * enumeration and relocation procedures. The GC state must begin with
+ * a pointer to the following procedure vector.
+ *
+ * By default, this is all the procedures we know about, but there are
+ * additional procedures defined in the interpreter for dealing with
+ * 'ref' objects.
+ */
+#define string_proc_reloc(proc)\
+ void proc(P2(gs_string *, gc_state_t *))
+#define const_string_proc_reloc(proc)\
+ void proc(P2(gs_const_string *, gc_state_t *))
+#define gc_procs_common\
+ /* Relocate a pointer to an object. */\
+ ptr_proc_reloc((*reloc_struct_ptr), void /*obj_header_t*/);\
+ /* Relocate a pointer to a string. */\
+ string_proc_reloc((*reloc_string));\
+ /* Relocate a pointer to a const string. */\
+ const_string_proc_reloc((*reloc_const_string))
+typedef struct gc_procs_common_s {
+ gc_procs_common;
+} gc_procs_common_t;
+
+#define gc_proc(gcst, proc) ((*(const gc_procs_common_t **)(gcst))->proc)
+
+/*
+ * The first argument of enum_ptrs procedures is logically const *.
+ * Unfortunately, actually declaring it as such would produce many compiler
+ * warnings from places that cast this argument to a non-const non-void
+ * pointer type. For the moment, we define EV_CONST as empty, with the
+ * intention of changing it to const at some future time.
+ */
+/*#define EV_CONST const */
+#define EV_CONST /* */
+
+/* Define the procedures for structure types. */
+
+ /* Clear the marks of a structure. */
+
+#define struct_proc_clear_marks(proc)\
+ void proc(P3(void /*obj_header_t*/ *pre, uint size,\
+ const gs_memory_struct_type_t *pstype))
+
+ /* Enumerate the pointers in a structure. */
+
+#define struct_proc_enum_ptrs(proc)\
+ gs_ptr_type_t proc(P6(EV_CONST void /*obj_header_t*/ *ptr, uint size,\
+ int index, const void **pep, const gs_memory_struct_type_t *pstype,\
+ gc_state_t *gcst))
+
+ /* Relocate all the pointers in this structure. */
+
+#define struct_proc_reloc_ptrs(proc)\
+ void proc(P4(void /*obj_header_t*/ *ptr, uint size,\
+ const gs_memory_struct_type_t *pstype, gc_state_t *gcst))
+
+ /*
+ * Finalize this structure just before freeing it.
+ * Finalization procedures must not allocate or resize
+ * any objects in any space managed by the allocator,
+ * and must not assume that any objects in such spaces
+ * referenced by this structure still exist. However,
+ * finalization procedures may free such objects, and
+ * may allocate, free, and reference objects allocated
+ * in other ways, such as objects allocated with malloc
+ * by libraries.
+ */
+
+#define struct_proc_finalize(proc)\
+ void proc(P1(void /*obj_header_t*/ *ptr))
+
+/*
+ * A descriptor for an object (structure) type.
+ */
+typedef struct struct_shared_procs_s struct_shared_procs_t;
+
+struct gs_memory_struct_type_s {
+ uint ssize;
+ struct_name_t sname;
+
+ /* ------ Procedures shared among many structure types. ------ */
+ /* Note that this pointer is usually 0. */
+
+ const struct_shared_procs_t *shared;
+
+ /* ------ Procedures specific to this structure type. ------ */
+
+ struct_proc_clear_marks((*clear_marks));
+ struct_proc_enum_ptrs((*enum_ptrs));
+ struct_proc_reloc_ptrs((*reloc_ptrs));
+ struct_proc_finalize((*finalize));
+
+ /* A pointer to additional data for the above procedures. */
+
+ const void *proc_data;
+
+};
+
+#define struct_type_name_string(pstype) ((const char *)((pstype)->sname))
+/* Default pointer processing */
+struct_proc_enum_ptrs(gs_no_struct_enum_ptrs);
+struct_proc_reloc_ptrs(gs_no_struct_reloc_ptrs);
+
+/* Define 'type' descriptors for some standard objects. */
+
+ /* Free blocks */
+
+extern_st(st_free);
+
+ /* Byte objects */
+
+extern_st(st_bytes);
+
+ /* GC roots */
+
+extern_st(st_gc_root_t);
+
+ /* Elements and arrays of const strings. */
+
+#define private_st_const_string()\
+ private const gc_ptr_element_t const_string_elts[] = {\
+ { GC_ELT_CONST_STRING, 0 }\
+ };\
+ gs__st_basic_with_final(private_st, st_const_string, gs_const_string,\
+ "gs_const_string", 1, const_string_elts, const_string_sdata, 0, 0, 0)
+
+extern_st(st_const_string_element);
+#define public_st_const_string_element()\
+ gs_public_st_element(st_const_string_element, gs_const_string,\
+ "gs_const_string[]", const_string_elt_enum_ptrs,\
+ const_string_elt_reloc_ptrs, st_const_string)
+
+/* ================ Macros for defining structure types ================ */
+
+#define public_st public const gs_memory_struct_type_t
+#define private_st private const gs_memory_struct_type_t
+
+/*
+ * As an alternative to defining different enum_ptrs and reloc_ptrs
+ * procedures for basic structure types that only have a fixed number of
+ * pointers and possibly a single supertype, we can define the type's GC
+ * information using stock procedures and a table. Each entry in the table
+ * defines one element of the structure.
+ */
+
+/* Define the pointer types of individual elements. */
+
+typedef enum {
+ GC_ELT_OBJ, /* obj * or const obj * */
+ GC_ELT_STRING, /* gs_string */
+ GC_ELT_CONST_STRING, /* gs_const_string */
+ GC_ELT_REF
+} gc_ptr_type_index_t;
+
+typedef struct gc_ptr_element_s {
+ ushort /*gc_ptr_type_index_t */ type;
+ ushort offset;
+} gc_ptr_element_t;
+
+#define GC_OBJ_ELT(typ, elt)\
+ { GC_ELT_OBJ, offset_of(typ, elt) }
+#define GC_OBJ_ELT2(typ, e1, e2)\
+ GC_OBJ_ELT(typ, e1), GC_OBJ_ELT(typ, e2)
+#define GC_OBJ_ELT3(typ, e1, e2, e3)\
+ GC_OBJ_ELT(typ, e1), GC_OBJ_ELT(typ, e2), GC_OBJ_ELT(typ, e3)
+#define GC_STRING_ELT(typ, elt)\
+ { GC_ELT_STRING, offset_of(typ, elt) }
+#define GC_CONST_STRING_ELT(typ, elt)\
+ { GC_ELT_CONST_STRING, offset_of(typ, elt) }
+#define GC_REF_ELT(typ, elt)\
+ { GC_ELT_REF, offset_of(typ, elt) }
+
+/* Define the complete table of descriptor data. */
+
+typedef struct gc_struct_data_s {
+ ushort num_ptrs;
+ ushort super_offset;
+ const gs_memory_struct_type_t *super_type; /* 0 if none */
+ const gc_ptr_element_t *ptrs;
+} gc_struct_data_t;
+
+/*
+ * Define the enum_ptrs and reloc_ptrs procedures, and the declaration
+ * macros, for table-specified structures. For such structures, the
+ * proc_data points to a gc_struct_data_t. The standard defining form
+ * is:
+
+ private const gc_ptr_element_t XXX[] = {
+ ... elements ...
+ };
+ gs_(private|public)_st_basic(stname, stype, sname, XXX, YYY, supst, supoff);
+
+ */
+struct_proc_enum_ptrs(basic_enum_ptrs);
+struct_proc_reloc_ptrs(basic_reloc_ptrs);
+
+#define gs__st_basic_with_final(scope_st, stname, stype, sname, nelts, elts, sdata, supst, supoff, pfinal)\
+ private const gc_struct_data_t sdata = {\
+ nelts, supoff, supst, elts\
+ };\
+ scope_st stname = {\
+ sizeof(stype), sname, 0, 0, basic_enum_ptrs, basic_reloc_ptrs,\
+ pfinal, &sdata\
+ }
+#define gs__st_basic_final(scope_st, stname, stype, sname, elts, sdata, supst, supoff, pfinal)\
+ gs__st_basic_with_final(scope_st, stname, stype, sname, countof(elts), elts, sdata, supst, supoff, pfinal)
+#define gs_public_st_basic_final(stname, stype, sname, elts, sdata, supst, supoff, pfinal)\
+ gs__st_basic_final(public_st, stname, stype, sname, elts, sdata, supst, supoff, pfinal)
+#define gs_private_st_basic_final(stname, stype, sname, elts, sdata, supst, supoff, pfinal)\
+ gs__st_basic_final(private_st, stname, stype, sname, elts, sdata, supst, supoff, pfinal)
+#define gs__st_basic(scope_st, stname, stype, sname, elts, sdata, supst, supoff)\
+ gs__st_basic_with_final(scope_st, stname, stype, sname, countof(elts), elts, sdata, supst, supoff, 0)
+#define gs_public_st_basic(stname, stype, sname, elts, sdata, supst, supoff)\
+ gs__st_basic(public_st, stname, stype, sname, elts, sdata, supst, supoff)
+#define gs_private_st_basic(stname, stype, sname, elts, sdata, supst, supoff)\
+ gs__st_basic(private_st, stname, stype, sname, elts, sdata, supst, supoff)
+
+/*
+ * The simplest kind of composite structure is one with a fixed set of
+ * pointers, each of which points to a struct. We provide macros for
+ * defining this kind of structure conveniently, either all at once in
+ * the structure definition macro, or using the following template:
+
+ ENUM_PTRS_BEGIN(xxx_enum_ptrs) return 0;
+ ... ENUM_PTR(i, xxx, elt); ...
+ ENUM_PTRS_END
+ RELOC_PTRS_BEGIN(xxx_reloc_ptrs) ;
+ ... RELOC_PTR(xxx, elt) ...
+ RELOC_PTRS_END
+
+ */
+/*
+ * We have to pull the 'private' outside the ENUM_PTRS_BEGIN and
+ * RELOC_PTRS_BEGIN macros because of a bug in the Borland C++ preprocessor.
+ * We also have to make sure there is more on the line after these
+ * macros, so as not to confuse ansi2knr.
+ */
+
+ /* Begin enumeration */
+
+#ifdef __PROTOTYPES__
+# define ENUM_PTRS_BEGIN_PROC(proc)\
+ gs_ptr_type_t proc(EV_CONST void *vptr, uint size, int index, const void **pep, const gs_memory_struct_type_t *pstype, gc_state_t *gcst)
+#else
+# define ENUM_PTRS_BEGIN_PROC(proc)\
+ gs_ptr_type_t proc(vptr, size, index, pep, pstype, gcst) EV_CONST void *vptr; uint size; int index; const void **pep; const gs_memory_struct_type_t *pstype; gc_state_t *gcst;
+#endif
+#define ENUM_PTRS_BEGIN(proc)\
+ ENUM_PTRS_BEGIN_PROC(proc) { switch ( index ) { default:
+
+ /* Enumerate elements */
+
+#define ENUM_OBJ(ptr) /* pointer to object */\
+ (*pep = (const void *)(ptr), ptr_struct_type)
+#define ENUM_STRING(ptr) /* pointer to gs_string */\
+ (*pep = (const void *)(ptr), ptr_string_type)
+#define ENUM_CONST_STRING(ptr) /* pointer to gs_const_string */\
+ (*pep = (const void *)(ptr), ptr_const_string_type)
+
+#define ENUM_OBJ_ELT(typ, elt)\
+ ENUM_OBJ(((const typ *)vptr)->elt)
+#define ENUM_STRING_ELT(typ, elt)\
+ ENUM_STRING(&((const typ *)vptr)->elt)
+#define ENUM_CONST_STRING_ELT(typ, elt)\
+ ENUM_CONST_STRING(&((const typ *)vptr)->elt)
+
+#define ENUM_PTR(i, typ, elt)\
+ case i: return ENUM_OBJ_ELT(typ, elt)
+#define ENUM_PTR3(i, typ, e1, e2, e3) /* just an abbreviation */\
+ ENUM_PTR(i, typ, e1); ENUM_PTR((i)+1, typ, e2); ENUM_PTR((i)+2, typ, e3)
+#define ENUM_STRING_PTR(i, typ, elt)\
+ case i: return ENUM_STRING_ELT(typ, elt)
+#define ENUM_CONST_STRING_PTR(i, typ, elt)\
+ case i: return ENUM_CONST_STRING_ELT(typ, elt)
+
+ /* End enumeration */
+
+#define ENUM_PTRS_END\
+ } /* mustn't fall through! */ ENUM_PTRS_END_PROC }
+#define ENUM_PTRS_END_PROC /* */
+
+ /* Begin relocation */
+
+#ifdef __PROTOTYPES__
+# define RELOC_PTRS_BEGIN(proc)\
+ void proc(void *vptr, uint size, const gs_memory_struct_type_t *pstype, gc_state_t *gcst) {
+#else
+# define RELOC_PTRS_BEGIN(proc)\
+ void proc(vptr, size, pstype, gcst) void *vptr; uint size; const gs_memory_struct_type_t *pstype; gc_state_t *gcst; {
+#endif
+
+ /* Relocate elements */
+
+#define RELOC_OBJ(ptr)\
+ (gc_proc(gcst, reloc_struct_ptr)((const void *)(ptr), gcst))
+#define RELOC_OBJ_VAR(ptrvar)\
+ (ptrvar = RELOC_OBJ(ptrvar))
+#define RELOC_STRING_VAR(ptrvar)\
+ (gc_proc(gcst, reloc_string)(&(ptrvar), gcst))
+#define RELOC_CONST_STRING_VAR(ptrvar)\
+ (gc_proc(gcst, reloc_const_string)(&(ptrvar), gcst))
+
+#define RELOC_OBJ_ELT(typ, elt)\
+ RELOC_VAR(((typ *)vptr)->elt)
+#define RELOC_STRING_ELT(typ, elt)\
+ RELOC_STRING_VAR(((typ *)vptr)->elt)
+#define RELOC_CONST_STRING_ELT(typ, elt)\
+ RELOC_CONST_STRING_VAR(((typ *)vptr)->elt)
+
+/* Relocate a pointer that points to a known offset within an object. */
+/* OFFSET is for byte offsets, TYPED_OFFSET is for element offsets. */
+#define RELOC_OFFSET_ELT(typ, elt, offset)\
+ ((typ *)vptr)->elt = (void *)\
+ ((char *)RELOC_OBJ((char *)((typ *)vptr)->elt - (offset)) +\
+ (offset))
+#define RELOC_TYPED_OFFSET_ELT(typ, elt, offset)\
+ (((typ *)vptr)->elt = (void *)RELOC_OBJ(((typ *)vptr)->elt - (offset)),\
+ ((typ *)vptr)->elt += (offset))
+
+ /* Backward compatibility */
+
+#define RELOC_VAR(ptrvar)\
+ RELOC_OBJ_VAR(ptrvar)
+#define RELOC_PTR(typ, elt)\
+ RELOC_OBJ_ELT(typ, elt)
+#define RELOC_PTR3(typ, e1, e2, e3) /* just an abbreviation */\
+ RELOC_PTR(typ,e1); RELOC_PTR(typ,e2); RELOC_PTR(typ,e3)
+#define RELOC_OFFSET_PTR(typ, elt, offset)\
+ RELOC_OFFSET_ELT(typ, elt, offset)
+#define RELOC_TYPED_OFFSET_PTR(typ, elt, offset)\
+ RELOC_TYPED_OFFSET_ELT(typ, elt, offset)
+#define RELOC_STRING_PTR(typ, elt)\
+ RELOC_STRING_ELT(typ, elt)
+#define RELOC_CONST_STRING_PTR(typ, elt)\
+ RELOC_CONST_STRING_ELT(typ, elt)
+
+ /* End relocation */
+
+#define RELOC_PTRS_END\
+ }
+
+ /* Subclass support */
+
+#define ENUM_USING(supst, ptr, size, index)\
+ (*(supst).enum_ptrs)(ptr, size, index, pep, &(supst), gcst)
+
+#define RELOC_USING(supst, ptr, size)\
+ (*(supst).reloc_ptrs)(ptr, size, &(supst), gcst)
+
+ /*
+ * Support for suffix subclasses. Special subclasses constructed
+ * 'by hand' may use this also.
+ */
+
+#define ENUM_PREFIX(supst, n)\
+ return ENUM_USING(supst, vptr, size, index-(n))
+
+#define RELOC_PREFIX(supst)\
+ RELOC_USING(supst, vptr, size)
+
+ /*
+ * Support for general subclasses.
+ */
+
+#define ENUM_SUPER_ELT(stype, supst, member, n)\
+ ENUM_USING(supst, &((EV_CONST stype *)vptr)->member, sizeof(((EV_CONST stype *)vptr)->member), index-(n))
+#define ENUM_SUPER(stype, supst, member, n)\
+ return ENUM_SUPER_ELT(stype, supst, member, n)
+
+#define RELOC_SUPER_ELT(stype, supst, member)\
+ RELOC_USING(supst, &((stype *)vptr)->member, sizeof(((stype *)vptr)->member))
+#define RELOC_SUPER(stype, supst, member)\
+ RELOC_SUPER_ELT(stype, supst, member)
+
+ /* Backward compatibility. */
+
+#define ENUM_RETURN(ptr) return ENUM_OBJ(ptr)
+#define ENUM_RETURN_PTR(typ, elt) return ENUM_OBJ_ELT(typ, elt)
+#define ENUM_RETURN_STRING_PTR(typ, elt) return ENUM_STRING_ELT(typ, elt)
+#define ENUM_RETURN_CONST_STRING(ptr) return ENUM_CONST_STRING(ptr)
+#define ENUM_RETURN_CONST_STRING_PTR(typ, elt) return ENUM_CONST_STRING_ELT(typ, elt)
+
+/* -------------- Simple structures (no internal pointers). -------------- */
+
+#define gs__st_simple(scope_st, stname, stype, sname)\
+ scope_st stname = { sizeof(stype), sname, 0, 0, gs_no_struct_enum_ptrs, gs_no_struct_reloc_ptrs, 0 }
+#define gs_public_st_simple(stname, stype, sname)\
+ gs__st_simple(public_st, stname, stype, sname)
+#define gs_private_st_simple(stname, stype, sname)\
+ gs__st_simple(private_st, stname, stype, sname)
+
+/* ---------------- Structures with explicit procedures. ---------------- */
+
+/*
+ * Boilerplate for clear_marks procedures.
+ */
+#ifdef __PROTOTYPES__
+# define CLEAR_MARKS_PROC(proc)\
+ void proc(void *vptr, uint size, const gs_memory_struct_type_t *pstype)
+#else
+# define CLEAR_MARKS_PROC(proc)\
+ void proc(vptr, size, pstype) void *vptr; uint size; const gs_memory_struct_type_t *pstype;
+#endif
+
+ /* Complex structures with their own clear_marks, */
+ /* enum, reloc, and finalize procedures. */
+
+#define gs__st_complex_only(scope_st, stname, stype, sname, pclear, penum, preloc, pfinal)\
+ scope_st stname = { sizeof(stype), sname, 0, pclear, penum, preloc, pfinal }
+#define gs_public_st_complex_only(stname, stype, sname, pclear, penum, preloc, pfinal)\
+ gs__st_complex_only(public_st, stname, stype, sname, pclear, penum, preloc, pfinal)
+#define gs_private_st_complex_only(stname, stype, sname, pclear, penum, preloc, pfinal)\
+ gs__st_complex_only(private_st, stname, stype, sname, pclear, penum, preloc, pfinal)
+
+#define gs__st_complex(scope_st, stname, stype, sname, pclear, penum, preloc, pfinal)\
+ private struct_proc_clear_marks(pclear);\
+ private struct_proc_enum_ptrs(penum);\
+ private struct_proc_reloc_ptrs(preloc);\
+ private struct_proc_finalize(pfinal);\
+ gs__st_complex_only(scope_st, stname, stype, sname, pclear, penum, preloc, pfinal)
+#define gs_public_st_complex(stname, stype, sname, pclear, penum, preloc, pfinal)\
+ gs__st_complex(public_st, stname, stype, sname, pclear, penum, preloc, pfinal)
+#define gs_private_st_complex(stname, stype, sname, pclear, penum, preloc, pfinal)\
+ gs__st_complex(private_st, stname, stype, sname, pclear, penum, preloc, pfinal)
+
+ /* Composite structures with their own enum and reloc procedures. */
+
+#define gs__st_composite(scope_st, stname, stype, sname, penum, preloc)\
+ private struct_proc_enum_ptrs(penum);\
+ private struct_proc_reloc_ptrs(preloc);\
+ gs__st_complex_only(scope_st, stname, stype, sname, 0, penum, preloc, 0)
+#define gs_public_st_composite(stname, stype, sname, penum, preloc)\
+ gs__st_composite(public_st, stname, stype, sname, penum, preloc)
+#define gs_private_st_composite(stname, stype, sname, penum, preloc)\
+ gs__st_composite(private_st, stname, stype, sname, penum, preloc)
+
+ /* Composite structures with finalization. */
+
+#define gs__st_composite_final(scope_st, stname, stype, sname, penum, preloc, pfinal)\
+ private struct_proc_enum_ptrs(penum);\
+ private struct_proc_reloc_ptrs(preloc);\
+ private struct_proc_finalize(pfinal);\
+ gs__st_complex_only(scope_st, stname, stype, sname, 0, penum, preloc, pfinal)
+#define gs_public_st_composite_final(stname, stype, sname, penum, preloc, pfinal)\
+ gs__st_composite_final(public_st, stname, stype, sname, penum, preloc, pfinal)
+#define gs_private_st_composite_final(stname, stype, sname, penum, preloc, pfinal)\
+ gs__st_composite_final(private_st, stname, stype, sname, penum, preloc, pfinal)
+
+ /* Composite structures with enum and reloc procedures */
+ /* already declared. */
+
+#define gs__st_composite_only(scope_st, stname, stype, sname, penum, preloc)\
+ gs__st_complex_only(scope_st, stname, stype, sname, 0, penum, preloc, 0)
+#define gs_public_st_composite_only(stname, stype, sname, penum, preloc)\
+ gs__st_composite_only(public_st, stname, stype, sname, penum, preloc)
+#define gs_private_st_composite_only(stname, stype, sname, penum, preloc)\
+ gs__st_composite_only(private_st, stname, stype, sname, penum, preloc)
+
+/* ---------------- Special kinds of structures ---------------- */
+
+ /* Element structures, for use in arrays of structures. */
+ /* Note that these require that the underlying structure's */
+ /* enum_ptrs procedure always return the same number of pointers. */
+
+#define gs__st_element(scope_st, stname, stype, sname, penum, preloc, basest)\
+ private ENUM_PTRS_BEGIN_PROC(penum) {\
+ uint count = size / (uint)sizeof(stype);\
+ if ( count == 0 ) return 0;\
+ return ENUM_USING(basest, (EV_CONST char *)vptr + (index % count) * sizeof(stype),\
+ sizeof(stype), index / count);\
+ } ENUM_PTRS_END_PROC\
+ private RELOC_PTRS_BEGIN(preloc) {\
+ uint count = size / (uint)sizeof(stype);\
+ for ( ; count; count--, vptr = (char *)vptr + sizeof(stype) )\
+ RELOC_USING(basest, vptr, sizeof(stype));\
+ } RELOC_PTRS_END\
+ gs__st_composite_only(scope_st, stname, stype, sname, penum, preloc)
+#define gs_public_st_element(stname, stype, sname, penum, preloc, basest)\
+ gs__st_element(public_st, stname, stype, sname, penum, preloc, basest)
+#define gs_private_st_element(stname, stype, sname, penum, preloc, basest)\
+ gs__st_element(private_st, stname, stype, sname, penum, preloc, basest)
+
+ /* A "structure" just consisting of a pointer. */
+ /* Note that in this case only, stype is a pointer type. */
+ /* Fortunately, C's bizarre 'const' syntax does what we want here. */
+
+#define gs__st_ptr(scope_st, stname, stype, sname, penum, preloc)\
+ private ENUM_PTRS_BEGIN(penum) return 0;\
+ case 0: return ENUM_OBJ(*(stype const *)vptr);\
+ ENUM_PTRS_END\
+ private RELOC_PTRS_BEGIN(preloc) ;\
+ RELOC_VAR(*(stype *)vptr);\
+ RELOC_PTRS_END\
+ gs__st_composite_only(scope_st, stname, stype, sname, penum, preloc)
+#define gs_public_st_ptr(stname, stype, sname, penum, preloc)\
+ gs__st_ptr(public_st, stname, stype, sname, penum, preloc)
+#define gs_private_st_ptr(stname, stype, sname, penum, preloc)\
+ gs__st_ptr(private_st, stname, stype, sname, penum, preloc)
+
+/* ---------- Ordinary structures with a fixed set of pointers ----------- */
+/* Note that we "cannibalize" the penum and preloc names for elts and sdata. */
+
+ /* Structures with 1 pointer. */
+
+#define gs__st_ptrs1(scope_st, stname, stype, sname, penum, preloc, e1)\
+ private const gc_ptr_element_t penum[] = {\
+ GC_OBJ_ELT(stype, e1)\
+ };\
+ gs__st_basic(scope_st, stname, stype, sname, penum, preloc, 0, 0)
+#define gs_public_st_ptrs1(stname, stype, sname, penum, preloc, e1)\
+ gs__st_ptrs1(public_st, stname, stype, sname, penum, preloc, e1)
+#define gs_private_st_ptrs1(stname, stype, sname, penum, preloc, e1)\
+ gs__st_ptrs1(private_st, stname, stype, sname, penum, preloc, e1)
+
+ /* Structures with 1 string. */
+
+#define gs__st_strings1(scope_st, stname, stype, sname, penum, preloc, e1)\
+ private const gc_ptr_element_t penum[] = {\
+ GC_STRING_ELT(stype, e1)\
+ };\
+ gs__st_basic(scope_st, stname, stype, sname, penum, preloc, 0, 0)
+#define gs_public_st_strings1(stname, stype, sname, penum, preloc, e1)\
+ gs__st_strings1(public_st, stname, stype, sname, penum, preloc, e1)
+#define gs_private_st_strings1(stname, stype, sname, penum, preloc, e1)\
+ gs__st_strings1(private_st, stname, stype, sname, penum, preloc, e1)
+
+ /* Structures with 1 const string. */
+
+#define gs__st_const_strings1(scope_st, stname, stype, sname, penum, preloc, e1)\
+ private const gc_ptr_element_t penum[] = {\
+ GC_CONST_STRING_ELT(stype, e1)\
+ };\
+ gs__st_basic(scope_st, stname, stype, sname, penum, preloc, 0, 0)
+#define gs_public_st_const_strings1(stname, stype, sname, penum, preloc, e1)\
+ gs__st_const_strings1(public_st, stname, stype, sname, penum, preloc, e1)
+#define gs_private_st_const_strings1(stname, stype, sname, penum, preloc, e1)\
+ gs__st_const_strings1(private_st, stname, stype, sname, penum, preloc, e1)
+
+ /* Structures with 1 pointer and 1 string. */
+
+#define gs__st_ptrs1_strings1(scope_st, stname, stype, sname, penum, preloc, e1, e2)\
+ private const gc_ptr_element_t penum[] = {\
+ GC_OBJ_ELT(stype, e1), GC_STRING_ELT(stype, e2)\
+ };\
+ gs__st_basic(scope_st, stname, stype, sname, penum, preloc, 0, 0)
+#define gs_public_st_ptrs1_strings1(stname, stype, sname, penum, preloc, e1, e2)\
+ gs__st_ptrs1_strings1(public_st, stname, stype, sname, penum, preloc, e1, e2)
+#define gs_private_st_ptrs1_strings1(stname, stype, sname, penum, preloc, e1, e2)\
+ gs__st_ptrs1_strings1(private_st, stname, stype, sname, penum, preloc, e1, e2)
+
+ /* Structures with 1 pointer and 2 strings. */
+
+#define gs__st_ptrs1_strings2(scope_st, stname, stype, sname, penum, preloc, e1, e2, e3)\
+ private const gc_ptr_element_t penum[] = {\
+ GC_OBJ_ELT(stype, e1), GC_STRING_ELT(stype, e2), GC_STRING_ELT(stype, e3)\
+ };\
+ gs__st_basic(scope_st, stname, stype, sname, penum, preloc, 0, 0)
+#define gs_public_st_ptrs1_strings2(stname, stype, sname, penum, preloc, e1, e2, e3)\
+ gs__st_ptrs1_strings2(public_st, stname, stype, sname, penum, preloc, e1, e2, e3)
+#define gs_private_st_ptrs1_strings2(stname, stype, sname, penum, preloc, e1, e2, e3)\
+ gs__st_ptrs1_strings2(private_st, stname, stype, sname, penum, preloc, e1, e2, e3)
+
+ /* Structures with 2 const strings. */
+
+#define gs__st_const_strings2(scope_st, stname, stype, sname, penum, preloc, e1, e2)\
+ private const gc_ptr_element_t penum[] = {\
+ GC_CONST_STRING_ELT(stype, e1), GC_CONST_STRING_ELT(stype, e2)\
+ };\
+ gs__st_basic(scope_st, stname, stype, sname, penum, preloc, 0, 0)
+#define gs_public_st_const_strings2(stname, stype, sname, penum, preloc, e1, e2)\
+ gs__st_const_strings2(public_st, stname, stype, sname, penum, preloc, e1, e2)
+#define gs_private_st_const_strings2(stname, stype, sname, penum, preloc, e1, e2)\
+ gs__st_const_strings2(private_st, stname, stype, sname, penum, preloc, e1, e2)
+
+ /* Structures with 2 pointers. */
+
+#define gs__st_ptrs2(scope_st, stname, stype, sname, penum, preloc, e1, e2)\
+ private const gc_ptr_element_t penum[] = {\
+ GC_OBJ_ELT2(stype, e1, e2)\
+ };\
+ gs__st_basic(scope_st, stname, stype, sname, penum, preloc, 0, 0)
+#define gs_public_st_ptrs2(stname, stype, sname, penum, preloc, e1, e2)\
+ gs__st_ptrs2(public_st, stname, stype, sname, penum, preloc, e1, e2)
+#define gs_private_st_ptrs2(stname, stype, sname, penum, preloc, e1, e2)\
+ gs__st_ptrs2(private_st, stname, stype, sname, penum, preloc, e1, e2)
+
+ /* Structures with 3 pointers. */
+
+#define gs__st_ptrs3(scope_st, stname, stype, sname, penum, preloc, e1, e2, e3)\
+ private const gc_ptr_element_t penum[] = {\
+ GC_OBJ_ELT3(stype, e1, e2, e3)\
+ };\
+ gs__st_basic(scope_st, stname, stype, sname, penum, preloc, 0, 0)
+#define gs_public_st_ptrs3(stname, stype, sname, penum, preloc, e1, e2, e3)\
+ gs__st_ptrs3(public_st, stname, stype, sname, penum, preloc, e1, e2, e3)
+#define gs_private_st_ptrs3(stname, stype, sname, penum, preloc, e1, e2, e3)\
+ gs__st_ptrs3(private_st, stname, stype, sname, penum, preloc, e1, e2, e3)
+
+ /* Structures with 4 pointers. */
+
+#define gs__st_ptrs4(scope_st, stname, stype, sname, penum, preloc, e1, e2, e3, e4)\
+ private const gc_ptr_element_t penum[] = {\
+ GC_OBJ_ELT3(stype, e1, e2, e3), GC_OBJ_ELT(stype, e4)\
+ };\
+ gs__st_basic(scope_st, stname, stype, sname, penum, preloc, 0, 0)
+#define gs_public_st_ptrs4(stname, stype, sname, penum, preloc, e1, e2, e3, e4)\
+ gs__st_ptrs4(public_st, stname, stype, sname, penum, preloc, e1, e2, e3, e4)
+#define gs_private_st_ptrs4(stname, stype, sname, penum, preloc, e1, e2, e3, e4)\
+ gs__st_ptrs4(private_st, stname, stype, sname, penum, preloc, e1, e2, e3, e4)
+
+ /* Structures with 5 pointers. */
+
+#define gs__st_ptrs5(scope_st, stname, stype, sname, penum, preloc, e1, e2, e3, e4, e5)\
+ private const gc_ptr_element_t penum[] = {\
+ GC_OBJ_ELT3(stype, e1, e2, e3), GC_OBJ_ELT2(stype, e4, e5)\
+ };\
+ gs__st_basic(scope_st, stname, stype, sname, penum, preloc, 0, 0)
+#define gs_public_st_ptrs5(stname, stype, sname, penum, preloc, e1, e2, e3, e4, e5)\
+ gs__st_ptrs5(public_st, stname, stype, sname, penum, preloc, e1, e2, e3, e4, e5)
+#define gs_private_st_ptrs5(stname, stype, sname, penum, preloc, e1, e2, e3, e4, e5)\
+ gs__st_ptrs5(private_st, stname, stype, sname, penum, preloc, e1, e2, e3, e4, e5)
+
+ /* Structures with 6 pointers. */
+
+#define gs__st_ptrs6(scope_st, stname, stype, sname, penum, preloc, e1, e2, e3, e4, e5, e6)\
+ private const gc_ptr_element_t penum[] = {\
+ GC_OBJ_ELT3(stype, e1, e2, e3), GC_OBJ_ELT3(stype, e4, e5, e6)\
+ };\
+ gs__st_basic(scope_st, stname, stype, sname, penum, preloc, 0, 0)
+#define gs_public_st_ptrs6(stname, stype, sname, penum, preloc, e1, e2, e3, e4, e5, e6)\
+ gs__st_ptrs6(public_st, stname, stype, sname, penum, preloc, e1, e2, e3, e4, e5, e6)
+#define gs_private_st_ptrs6(stname, stype, sname, penum, preloc, e1, e2, e3, e4, e5, e6)\
+ gs__st_ptrs6(private_st, stname, stype, sname, penum, preloc, e1, e2, e3, e4, e5, e6)
+
+/* ---------------- Suffix subclasses ---------------- */
+
+ /* Suffix subclasses with no additional pointers. */
+
+#define gs__st_suffix_add0(scope_st, stname, stype, sname, penum, preloc, supstname)\
+ gs__st_basic_with_final(scope_st, stname, stype, sname, 0, 0, preloc, &supstname, 0, 0)
+#define gs_public_st_suffix_add0(stname, stype, sname, penum, preloc, supstname)\
+ gs__st_suffix_add0(public_st, stname, stype, sname, penum, preloc, supstname)
+#define gs_private_st_suffix_add0(stname, stype, sname, penum, preloc, supstname)\
+ gs__st_suffix_add0(private_st, stname, stype, sname, penum, preloc, supstname)
+
+ /* Suffix subclasses with no additional pointers, */
+ /* and with the superclass defined earlier in the same file */
+ /* as a 'basic' type. */
+ /* In this case, we don't even need new procedures. */
+
+#define gs__st_suffix_add0_local(scope_st, stname, stype, sname, supenum, supreloc, supstname)\
+ scope_st stname = {\
+ sizeof(stype), sname, 0, 0, basic_enum_ptrs, basic_reloc_ptrs,\
+ 0, &supreloc\
+ }
+#define gs_public_st_suffix_add0_local(stname, stype, sname, supenum, supreloc, supstname)\
+ gs__st_suffix_add0_local(public_st, stname, stype, sname, supenum, supreloc, supstname)
+#define gs_private_st_suffix_add0_local(stname, stype, sname, supenum, supreloc, supstname)\
+ gs__st_suffix_add0_local(private_st, stname, stype, sname, supenum, supreloc, supstname)
+
+ /* Suffix subclasses with no additional pointers and finalization. */
+ /* This is a hack -- subclasses should inherit finalization, */
+ /* but that would require a superclass pointer in the descriptor, */
+ /* which would perturb things too much right now. */
+
+#define gs__st_suffix_add0_final(scope_st, stname, stype, sname, penum, preloc, pfinal, supstname)\
+ private ENUM_PTRS_BEGIN_PROC(penum) {\
+ ENUM_PREFIX(supstname, 0);\
+ } ENUM_PTRS_END_PROC\
+ private RELOC_PTRS_BEGIN(preloc) {\
+ RELOC_PREFIX(supstname);\
+ } RELOC_PTRS_END\
+ gs__st_complex_only(scope_st, stname, stype, sname, 0, penum, preloc, pfinal)
+#define gs_public_st_suffix_add0_final(stname, stype, sname, penum, preloc, pfinal, supstname)\
+ gs__st_suffix_add0_final(public_st, stname, stype, sname, penum, preloc, pfinal, supstname)
+#define gs_private_st_suffix_add0_final(stname, stype, sname, penum, preloc, pfinal, supstname)\
+ gs__st_suffix_add0_final(private_st, stname, stype, sname, penum, preloc, pfinal, supstname)
+
+ /* Suffix subclasses with 1 additional pointer. */
+
+#define gs__st_suffix_add1(scope_st, stname, stype, sname, penum, preloc, supstname, e1)\
+ private const gc_ptr_element_t penum[] = {\
+ GC_OBJ_ELT(stype, e1)\
+ };\
+ gs__st_basic(scope_st, stname, stype, sname, penum, preloc, &supstname, 0)
+#define gs_public_st_suffix_add1(stname, stype, sname, penum, preloc, supstname, e1)\
+ gs__st_suffix_add1(public_st, stname, stype, sname, penum, preloc, supstname, e1)
+#define gs_private_st_suffix_add1(stname, stype, sname, penum, preloc, supstname, e1)\
+ gs__st_suffix_add1(private_st, stname, stype, sname, penum, preloc, supstname, e1)
+
+ /* Suffix subclasses with 1 additional pointer and finalization. */
+ /* See above regarding finalization and subclasses. */
+
+#define gs__st_suffix_add1_final(scope_st, stname, stype, sname, penum, preloc, pfinal, supstname, e1)\
+ private const gc_ptr_element_t penum[] = {\
+ GC_OBJ_ELT(stype, e1)\
+ };\
+ gs__st_basic_final(scope_st, stname, stype, sname, penum, preloc, &supstname, 0, pfinal)
+#define gs_public_st_suffix_add1_final(stname, stype, sname, penum, preloc, pfinal, supstname, e1)\
+ gs__st_suffix_add1_final(public_st, stname, stype, sname, penum, preloc, pfinal, supstname, e1)
+#define gs_private_st_suffix_add1_final(stname, stype, sname, penum, preloc, pfinal, supstname, e1)\
+ gs__st_suffix_add1_final(private_st, stname, stype, sname, penum, preloc, pfinal, supstname, e1)
+
+ /* Suffix subclasses with 2 additional pointers. */
+
+#define gs__st_suffix_add2(scope_st, stname, stype, sname, penum, preloc, supstname, e1, e2)\
+ private const gc_ptr_element_t penum[] = {\
+ GC_OBJ_ELT2(stype, e1, e2)\
+ };\
+ gs__st_basic(scope_st, stname, stype, sname, penum, preloc, &supstname, 0)
+#define gs_public_st_suffix_add2(stname, stype, sname, penum, preloc, supstname, e1, e2)\
+ gs__st_suffix_add2(public_st, stname, stype, sname, penum, preloc, supstname, e1, e2)
+#define gs_private_st_suffix_add2(stname, stype, sname, penum, preloc, supstname, e1, e2)\
+ gs__st_suffix_add2(private_st, stname, stype, sname, penum, preloc, supstname, e1, e2)
+
+ /* Suffix subclasses with 2 additional pointers and finalization. */
+ /* See above regarding finalization and subclasses. */
+
+#define gs__st_suffix_add2_final(scope_st, stname, stype, sname, penum, preloc, pfinal, supstname, e1, e2)\
+ private const gc_ptr_element_t penum[] = {\
+ GC_OBJ_ELT2(stype, e1, e2)\
+ };\
+ gs__st_basic_final(scope_st, stname, stype, sname, penum, preloc, &supstname, 0, pfinal)
+#define gs_public_st_suffix_add2_final(stname, stype, sname, penum, preloc, pfinal, supstname, e1, e2)\
+ gs__st_suffix_add2_final(public_st, stname, stype, sname, penum, preloc, pfinal, supstname, e1, e2)
+#define gs_private_st_suffix_add2_final(stname, stype, sname, penum, preloc, pfinal, supstname, e1, e2)\
+ gs__st_suffix_add2_final(private_st, stname, stype, sname, penum, preloc, pfinal, supstname, e1, e2)
+
+ /* Suffix subclasses with 3 additional pointers. */
+
+#define gs__st_suffix_add3(scope_st, stname, stype, sname, penum, preloc, supstname, e1, e2, e3)\
+ private const gc_ptr_element_t penum[] = {\
+ GC_OBJ_ELT3(stype, e1, e2, e3)\
+ };\
+ gs__st_basic(scope_st, stname, stype, sname, penum, preloc, &supstname, 0)
+#define gs_public_st_suffix_add3(stname, stype, sname, penum, preloc, supstname, e1, e2, e3)\
+ gs__st_suffix_add3(public_st, stname, stype, sname, penum, preloc, supstname, e1, e2, e3)
+#define gs_private_st_suffix_add3(stname, stype, sname, penum, preloc, supstname, e1, e2, e3)\
+ gs__st_suffix_add3(private_st, stname, stype, sname, penum, preloc, supstname, e1, e2, e3)
+
+ /* Suffix subclasses with 3 additional pointers and finalization. */
+ /* See above regarding finalization and subclasses. */
+
+#define gs__st_suffix_add3_final(scope_st, stname, stype, sname, penum, preloc, pfinal, supstname, e1, e2, e3)\
+ private const gc_ptr_element_t penum[] = {\
+ GC_OBJ_ELT3(stype, e1, e2, e3)\
+ };\
+ gs__st_basic_final(scope_st, stname, stype, sname, penum, preloc, &supstname, 0, pfinal)
+#define gs_public_st_suffix_add3_final(stname, stype, sname, penum, preloc, pfinal, supstname, e1, e2, e3)\
+ gs__st_suffix_add3_final(public_st, stname, stype, sname, penum, preloc, pfinal, supstname, e1, e2, e3)
+#define gs_private_st_suffix_add3_final(stname, stype, sname, penum, preloc, pfinal, supstname, e1, e2, e3)\
+ gs__st_suffix_add3_final(private_st, stname, stype, sname, penum, preloc, pfinal, supstname, e1, e2, e3)
+
+ /* Suffix subclasses with 4 additional pointers. */
+
+#define gs__st_suffix_add4(scope_st, stname, stype, sname, penum, preloc, supstname, e1, e2, e3, e4)\
+ private const gc_ptr_element_t penum[] = {\
+ GC_OBJ_ELT3(stype, e1, e2, e3), GC_OBJ_ELT(stype, e4)\
+ };\
+ gs__st_basic(scope_st, stname, stype, sname, penum, preloc, &supstname, 0)
+#define gs_public_st_suffix_add4(stname, stype, sname, penum, preloc, supstname, e1, e2, e3, e4)\
+ gs__st_suffix_add4(public_st, stname, stype, sname, penum, preloc, supstname, e1, e2, e3, e4)
+#define gs_private_st_suffix_add4(stname, stype, sname, penum, preloc, supstname, e1, e2, e3, e4)\
+ gs__st_suffix_add4(private_st, stname, stype, sname, penum, preloc, supstname, e1, e2, e3, e4)
+
+/* ---------------- General subclasses ---------------- */
+
+ /* General subclasses with no additional pointers. */
+
+#define gs__st_ptrs_add0(scope_st, stname, stype, sname, penum, preloc, supstname, member)\
+ gs__st_basic_with_final(scope_st, stname, stype, sname, 0, 0, preloc, &supstname, offset_of(stype, member), 0)
+#define gs_public_st_ptrs_add0(stname, stype, sname, penum, preloc, supstname, member)\
+ gs__st_ptrs_add0(public_st, stname, stype, sname, penum, preloc, supstname, member)
+#define gs_private_st_ptrs_add0(stname, stype, sname, penum, preloc, supstname, member)\
+ gs__st_ptrs_add0(private_st, stname, stype, sname, penum, preloc, supstname, member)
+
+ /* General subclasses with 1 additional pointer. */
+
+#define gs__st_ptrs_add1(scope_st, stname, stype, sname, penum, preloc, supstname, member, e1)\
+ private const gc_ptr_element_t penum[] = {\
+ GC_OBJ_ELT(stype, e1)\
+ };\
+ gs__st_basic(scope_st, stname, stype, sname, penum, preloc, &supstname, offset_of(stype, member))
+#define gs_public_st_ptrs_add1(stname, stype, sname, penum, preloc, supstname, member, e1)\
+ gs__st_ptrs_add1(public_st, stname, stype, sname, penum, preloc, supstname, member, e1)
+#define gs_private_st_ptrs_add1(stname, stype, sname, penum, preloc, supstname, member, e1)\
+ gs__st_ptrs_add1(private_st, stname, stype, sname, penum, preloc, supstname, member, e1)
+
+ /* General subclasses with 2 additional pointers. */
+
+#define gs__st_ptrs_add2(scope_st, stname, stype, sname, penum, preloc, supstname, member, e1, e2)\
+ private const gc_ptr_element_t penum[] = {\
+ GC_OBJ_ELT2(stype, e1, e2)\
+ };\
+ gs__st_basic(scope_st, stname, stype, sname, penum, preloc, &supstname, offset_of(stype, member))
+#define gs_public_st_ptrs_add2(stname, stype, sname, penum, preloc, supstname, member, e1, e2)\
+ gs__st_ptrs_add2(public_st, stname, stype, sname, penum, preloc, supstname, member, e1, e2)
+#define gs_private_st_ptrs_add2(stname, stype, sname, penum, preloc, supstname, member, e1, e2)\
+ gs__st_ptrs_add2(private_st, stname, stype, sname, penum, preloc, supstname, member, e1, e2)
+
+#endif /* gsstruct_INCLUDED */
diff --git a/pstoraster/gstext.c b/pstoraster/gstext.c
new file mode 100644
index 000000000..9c91159c2
--- /dev/null
+++ b/pstoraster/gstext.c
@@ -0,0 +1,344 @@
+/* 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$ */
+/* Driver text interface support */
+#include "std.h"
+#include "gstypes.h"
+#include "gdebug.h"
+#include "gserror.h"
+#include "gserrors.h"
+#include "gsmemory.h"
+#include "gsstruct.h"
+#include "gstypes.h"
+#include "gxdevcli.h"
+#include "gxpath.h"
+#include "gxtext.h"
+#include "gzstate.h"
+
+/* GC descriptors */
+public_st_gs_text_params();
+public_st_gs_text_enum();
+
+#define tptr ((gs_text_params_t *)vptr)
+
+private
+ENUM_PTRS_BEGIN(text_params_enum_ptrs) return 0;
+
+case 0:
+if (tptr->operation & TEXT_FROM_STRING) {
+ /*
+ * We only need the string descriptor temporarily, but we can't
+ * put it in a local variable, because that would create a dangling
+ * pointer as soon as we return.
+ */
+ tptr->gc_string.data = tptr->data.bytes;
+ tptr->gc_string.size = tptr->size;
+ return ENUM_CONST_STRING(&tptr->gc_string);
+}
+if (tptr->operation & TEXT_FROM_BYTES)
+ return ENUM_OBJ(tptr->data.bytes);
+if (tptr->operation & TEXT_FROM_CHARS)
+ return ENUM_OBJ(tptr->data.chars);
+if (tptr->operation & TEXT_FROM_GLYPHS)
+ return ENUM_OBJ(tptr->data.glyphs);
+return ENUM_OBJ(NULL);
+case 1:
+return ENUM_OBJ(tptr->operation & TEXT_REPLACE_X_WIDTHS ?
+ tptr->x_widths : NULL);
+case 2:
+return ENUM_OBJ(tptr->operation & TEXT_REPLACE_Y_WIDTHS ?
+ tptr->y_widths : NULL);
+ENUM_PTRS_END
+
+private RELOC_PTRS_BEGIN(text_params_reloc_ptrs)
+{
+ if (tptr->operation & TEXT_FROM_STRING) {
+ gs_const_string str;
+
+ str.data = tptr->data.bytes;
+ str.size = tptr->size;
+ RELOC_CONST_STRING_VAR(str);
+ tptr->data.bytes = str.data;
+ } else if (tptr->operation & TEXT_FROM_BYTES)
+ RELOC_OBJ_VAR(tptr->data.bytes);
+ else if (tptr->operation & TEXT_FROM_CHARS)
+ RELOC_OBJ_VAR(tptr->data.chars);
+ else if (tptr->operation & TEXT_FROM_GLYPHS)
+ RELOC_OBJ_VAR(tptr->data.glyphs);
+ if (tptr->operation & TEXT_REPLACE_X_WIDTHS)
+ RELOC_OBJ_VAR(tptr->x_widths);
+ if (tptr->operation & TEXT_REPLACE_Y_WIDTHS)
+ RELOC_OBJ_VAR(tptr->y_widths);
+}
+RELOC_PTRS_END
+
+#undef tptr
+
+#define eptr ((gs_text_enum_t *)vptr)
+
+private ENUM_PTRS_BEGIN(text_enum_enum_ptrs) ENUM_USING(st_gs_text_params, &eptr->text, sizeof(eptr->text), index - 1);
+case 0:
+return ENUM_OBJ(gx_device_enum_ptr(eptr->dev));
+ENUM_PTRS_END
+
+private RELOC_PTRS_BEGIN(text_enum_reloc_ptrs)
+{
+ RELOC_USING(st_gs_text_params, &eptr->text, sizeof(eptr->text));
+ gx_device_reloc_ptr(eptr->dev, gcst);
+}
+RELOC_PTRS_END
+
+#undef eptr
+
+/* Begin processing text. */
+int
+gx_device_text_begin(gx_device * dev, gs_imager_state * pis,
+ const gs_text_params_t * text, const gs_font * font,
+ gx_path * path, /* unless DO_NONE & !RETURN_WIDTH */
+ const gx_device_color * pdcolor, /* DO_DRAW */
+ const gx_clip_path * pcpath, /* DO_DRAW */
+ gs_memory_t * mem, gs_text_enum_t ** ppte)
+{
+ if (TEXT_OPERATION_IS_INVALID(text->operation))
+ return_error(gs_error_rangecheck);
+ {
+ gx_path *tpath =
+ ((text->operation & TEXT_DO_NONE) &&
+ !(text->operation & TEXT_RETURN_WIDTH) ? 0 : path);
+ int code =
+ (*dev_proc(dev, text_begin))
+ (dev, pis, text, font, tpath,
+ (text->operation & TEXT_DO_DRAW ? pdcolor : 0),
+ (text->operation & TEXT_DO_DRAW ? pcpath : 0),
+ mem, ppte);
+ gs_text_enum_t *pte = *ppte;
+
+ if (code < 0)
+ return code;
+ pte->text = *text;
+ pte->dev = dev;
+ pte->index = 0;
+ return code;
+ }
+}
+
+/* Begin processing text based on a graphics state. */
+int
+gs_text_begin(gs_state * pgs, const gs_text_params_t * text,
+ gs_memory_t * mem, gs_text_enum_t ** ppte)
+{
+ gx_clip_path *pcpath = 0;
+
+ if (text->operation & TEXT_DO_DRAW) {
+ int code = gx_effective_clip_path(pgs, &pcpath);
+
+ if (code < 0)
+ return code;
+ gx_set_dev_color(pgs);
+ }
+ return gx_device_text_begin(pgs->device, (gs_imager_state *) pgs,
+ text, pgs->font, pgs->path, pgs->dev_color,
+ pcpath, mem, ppte);
+}
+
+/* Begin PostScript-equivalent text operations. */
+int
+gs_show_begin(gs_state * pgs, const byte * str, uint size,
+ gs_memory_t * mem, gs_text_enum_t ** ppte)
+{
+ gs_text_params_t text;
+
+ text.operation = TEXT_FROM_STRING | TEXT_DO_DRAW | TEXT_RETURN_WIDTH;
+ text.data.bytes = str, text.size = size;
+ return gs_text_begin(pgs, &text, mem, ppte);
+}
+int
+gs_ashow_begin(gs_state * pgs, floatp ax, floatp ay, const byte * str, uint size,
+ gs_memory_t * mem, gs_text_enum_t ** ppte)
+{
+ gs_text_params_t text;
+
+ text.operation = TEXT_FROM_STRING | TEXT_ADD_TO_ALL_WIDTHS |
+ TEXT_DO_DRAW | TEXT_RETURN_WIDTH;
+ text.data.bytes = str, text.size = size;
+ text.delta_all.x = ax;
+ text.delta_all.y = ay;
+ return gs_text_begin(pgs, &text, mem, ppte);
+}
+int
+gs_widthshow_begin(gs_state * pgs, floatp cx, floatp cy, gs_char chr,
+ const byte * str, uint size,
+ gs_memory_t * mem, gs_text_enum_t ** ppte)
+{
+ gs_text_params_t text;
+
+ text.operation = TEXT_FROM_STRING | TEXT_ADD_TO_SPACE_WIDTH |
+ TEXT_DO_DRAW | TEXT_RETURN_WIDTH;
+ text.data.bytes = str, text.size = size;
+ text.delta_space.x = cx;
+ text.delta_space.y = cy;
+ text.space.s_char = chr;
+ return gs_text_begin(pgs, &text, mem, ppte);
+}
+int
+gs_awidthshow_begin(gs_state * pgs, floatp cx, floatp cy, gs_char chr,
+ floatp ax, floatp ay, const byte * str, uint size,
+ gs_memory_t * mem, gs_text_enum_t ** ppte)
+{
+ gs_text_params_t text;
+
+ text.operation = TEXT_FROM_STRING |
+ TEXT_ADD_TO_ALL_WIDTHS | TEXT_ADD_TO_SPACE_WIDTH |
+ TEXT_DO_DRAW | TEXT_RETURN_WIDTH;
+ text.data.bytes = str, text.size = size;
+ text.delta_space.x = cx;
+ text.delta_space.y = cy;
+ text.space.s_char = chr;
+ text.delta_all.x = ax;
+ text.delta_all.y = ay;
+ return gs_text_begin(pgs, &text, mem, ppte);
+}
+int
+gs_kshow_begin(gs_state * pgs, const byte * str, uint size,
+ gs_memory_t * mem, gs_text_enum_t ** ppte)
+{
+ gs_text_params_t text;
+
+ text.operation = TEXT_FROM_STRING | TEXT_DO_DRAW | TEXT_INTERVENE |
+ TEXT_RETURN_WIDTH;
+ text.data.bytes = str, text.size = size;
+ return gs_text_begin(pgs, &text, mem, ppte);
+}
+int
+gs_xyshow_begin(gs_state * pgs, const byte * str, uint size,
+ const float *x_widths, const float *y_widths,
+ gs_memory_t * mem, gs_text_enum_t ** ppte)
+{
+ gs_text_params_t text;
+
+ text.operation = TEXT_FROM_STRING |
+ TEXT_REPLACE_X_WIDTHS | TEXT_REPLACE_Y_WIDTHS |
+ TEXT_DO_DRAW | TEXT_INTERVENE | TEXT_RETURN_WIDTH;
+ text.data.bytes = str, text.size = size;
+ text.x_widths = x_widths;
+ text.y_widths = y_widths;
+ return gs_text_begin(pgs, &text, mem, ppte);
+}
+int
+gs_glyphshow_begin(gs_state * pgs, gs_glyph glyph,
+ gs_memory_t * mem, gs_text_enum_t ** ppte)
+{
+ gs_text_params_t text;
+
+ /****** SET glyphs ******/
+ text.size = 1;
+ text.operation = TEXT_FROM_GLYPHS | TEXT_DO_DRAW | TEXT_RETURN_WIDTH;
+ return gs_text_begin(pgs, &text, mem, ppte);
+}
+int
+gs_cshow_begin(gs_state * pgs, const byte * str, uint size,
+ gs_memory_t * mem, gs_text_enum_t ** ppte)
+{
+ gs_text_params_t text;
+
+ text.operation = TEXT_FROM_STRING | TEXT_DO_NONE;
+ text.data.bytes = str, text.size = size;
+ return gs_text_begin(pgs, &text, mem, ppte);
+}
+int
+gs_stringwidth_begin(gs_state * pgs, const byte * str, uint size,
+ gs_memory_t * mem, gs_text_enum_t ** ppte)
+{
+ gs_text_params_t text;
+
+ text.operation = TEXT_FROM_STRING | TEXT_DO_NONE | TEXT_RETURN_WIDTH;
+ text.data.bytes = str, text.size = size;
+ return gs_text_begin(pgs, &text, mem, ppte);
+}
+int
+gs_charpath_begin(gs_state * pgs, const byte * str, uint size, bool stroke_path,
+ gs_memory_t * mem, gs_text_enum_t ** ppte)
+{
+ gs_text_params_t text;
+
+ text.operation = TEXT_FROM_STRING | TEXT_RETURN_WIDTH |
+ (stroke_path ? TEXT_DO_TRUE_CHARPATH : TEXT_DO_FALSE_CHARPATH);
+ text.data.bytes = str, text.size = size;
+ return gs_text_begin(pgs, &text, mem, ppte);
+}
+int
+gs_charboxpath_begin(gs_state * pgs, const byte * str, uint size,
+ bool stroke_path, gs_memory_t * mem, gs_text_enum_t ** ppte)
+{
+ gs_text_params_t text;
+
+ text.operation = TEXT_FROM_STRING | TEXT_RETURN_WIDTH |
+ (stroke_path ? TEXT_DO_TRUE_CHARBOXPATH : TEXT_DO_FALSE_CHARBOXPATH);
+ text.data.bytes = str, text.size = size;
+ return gs_text_begin(pgs, &text, mem, ppte);
+}
+int
+gs_glyphpath_begin(gs_state * pgs, gs_glyph glyph, bool stroke_path,
+ gs_memory_t * mem, gs_text_enum_t ** ppte)
+{
+ gs_text_params_t text;
+
+ text.operation = TEXT_FROM_GLYPHS | TEXT_RETURN_WIDTH |
+ (stroke_path ? TEXT_DO_TRUE_CHARPATH : TEXT_DO_FALSE_CHARPATH);
+ /****** SET glyphs ******/
+ text.size = 1;
+ return gs_text_begin(pgs, &text, mem, ppte);
+}
+
+/* Process text after 'begin'. */
+int
+gs_text_process(gs_text_enum_t * pte)
+{
+ return pte->procs->process(pte);
+}
+
+/* Set text metrics and optionally enable caching. */
+int
+gs_text_setcharwidth(gs_text_enum_t * pte, const double wxy[2])
+{
+ return pte->procs->set_cache(pte, wxy, TEXT_SET_CHAR_WIDTH);
+}
+int
+gs_text_setcachedevice(gs_text_enum_t * pte, const double wbox[6])
+{
+ return pte->procs->set_cache(pte, wbox, TEXT_SET_CACHE_DEVICE);
+}
+int
+gs_text_setcachedevice2(gs_text_enum_t * pte, const double wbox2[10])
+{
+ return pte->procs->set_cache(pte, wbox2, TEXT_SET_CACHE_DEVICE2);
+}
+
+/* Release the text processing structures. */
+void
+gs_text_release(gs_text_enum_t * pte, client_name_t cname)
+{
+ rc_decrement_only(pte, cname);
+}
diff --git a/pstoraster/gstext.h b/pstoraster/gstext.h
new file mode 100644
index 000000000..8dcd9211c
--- /dev/null
+++ b/pstoraster/gstext.h
@@ -0,0 +1,231 @@
+/* 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$ */
+/* Driver interface for text */
+
+#ifndef gstext_INCLUDED
+# define gstext_INCLUDED
+
+#include "gsccode.h"
+#include "gsrefct.h"
+
+/* EVERYTHING IN THIS FILE IS SUBJECT TO CHANGE WITHOUT NOTICE. */
+
+/*
+ * Note that like get_params and get_hardware_params, but unlike all other
+ * driver procedures, text display must return information to the generic
+ * code:
+ * *show except [x][y]show: the string escapement a.k.a. "width").
+ * charpath, .glyphpath: the entire character description.
+ * .charboxpath: the character bounding box.
+ */
+
+/*
+ * Define the set of possible text operations. While we define this as
+ * a bit mask for convenience in testing, only certain combinations are
+ * meaningful. Specifically, the following are errors:
+ * - No FROM or DO.
+ * The following are undefined:
+ * - More than one FROM or DO.
+ * - Both ADD_TO and REPLACE.
+ */
+#define TEXT_HAS_MORE_THAN_ONE_(op, any_)\
+ ( ((op) & any_) & (((op) & any_) - 1) )
+#define TEXT_OPERATION_IS_INVALID(op)\
+ (!((op) & TEXT_FROM_ANY_) ||\
+ !((op) & TEXT_DO_ANY_) ||\
+ TEXT_HAS_MORE_THAN_ONE_(op, TEXT_FROM_ANY_) ||\
+ TEXT_HAS_MORE_THAN_ONE_(op, TEXT_DO_ANY_) ||\
+ (((op) & TEXT_ADD_ANY_) && ((op) & TEXT_REPLACE_ANY_))\
+ )
+
+ /* Define the representation of the text itself. */
+#define TEXT_FROM_STRING 0x00001
+#define TEXT_FROM_BYTES 0x00002
+#define TEXT_FROM_CHARS 0x00004
+#define TEXT_FROM_GLYPHS 0x00008
+#define TEXT_FROM_ANY_ /* internal use only, see above */\
+ (TEXT_FROM_STRING | TEXT_FROM_BYTES | TEXT_FROM_CHARS | TEXT_FROM_GLYPHS)
+ /* Define how to compute escapements. */
+#define TEXT_ADD_TO_ALL_WIDTHS 0x00010
+#define TEXT_ADD_TO_SPACE_WIDTH 0x00020
+#define TEXT_ADD_ANY_ /* internal use only, see above */\
+ (TEXT_ADD_TO_ALL_WIDTHS | TEXT_ADD_TO_SPACE_WIDTH)
+#define TEXT_REPLACE_X_WIDTHS 0x00040
+#define TEXT_REPLACE_Y_WIDTHS 0x00080
+#define TEXT_REPLACE_ANY_ /* internal use only, see above */\
+ (TEXT_REPLACE_X_WIDTHS | TEXT_REPLACE_Y_WIDTHS)
+ /* Define what result should be produced. */
+#define TEXT_DO_NONE 0x00100 /* stringwidth or cshow only */
+#define TEXT_DO_DRAW 0x00200
+#define TEXT_DO_FALSE_CHARPATH 0x00400
+#define TEXT_DO_TRUE_CHARPATH 0x00800
+#define TEXT_DO_FALSE_CHARBOXPATH 0x01000
+#define TEXT_DO_TRUE_CHARBOXPATH 0x02000
+#define TEXT_DO_ANY_CHARPATH\
+ (TEXT_DO_FALSE_CHARPATH | TEXT_DO_TRUE_CHARPATH |\
+ TEXT_DO_FALSE_CHARBOXPATH | TEXT_DO_TRUE_CHARBOXPATH)
+#define TEXT_DO_ANY_ /* internal use only, see above */\
+ (TEXT_DO_NONE | TEXT_DO_DRAW | TEXT_DO_ANY_CHARPATH)
+ /* Define whether the client intervenes between characters. */
+#define TEXT_INTERVENE 0x10000
+ /* Define whether to return the width. */
+#define TEXT_RETURN_WIDTH 0x20000
+
+/*
+ * Define the structure of parameters passed in for text display.
+ * Note that the implementation does not modify any of these; the client
+ * must not modify them after initialization.
+ */
+typedef struct gs_text_params_s {
+ /* The client must set the following in all cases. */
+ uint operation; /* TEXT_xxx mask */
+ union sd_ {
+ const byte *bytes; /* FROM_STRING, FROM_BYTES */
+ const gs_char *chars; /* FROM_CHARS */
+ const gs_glyph *glyphs; /* FROM_GLYPHS */
+ } data;
+ uint size; /* number of data elements */
+ /* The following are used only in the indicated cases. */
+ gs_point delta_all; /* ADD_TO_ALL_WIDTHS */
+ gs_point delta_space; /* ADD_TO_SPACE_WIDTH */
+ union s_ {
+ gs_char s_char; /* ADD_TO_SPACE_WIDTH & !FROM_GLYPHS */
+ gs_glyph s_glyph; /* ADD_TO_SPACE_WIDTH & FROM_GLYPHS */
+ } space;
+ /* If x_widths == y_widths, widths are taken in pairs. */
+ /* Either one may be NULL, meaning widths = 0. */
+ const float *x_widths; /* REPLACE_X_WIDTHS */
+ const float *y_widths; /* REPLACE_Y_WIDTHS */
+ /* The following are for internal use only, not by clients. */
+ gs_const_string gc_string; /* for use only during GC */
+} gs_text_params_t;
+
+#define st_gs_text_params_max_ptrs 3
+/*extern_st(st_gs_text_params); */
+#define public_st_gs_text_params() /* in gstext.c */\
+ gs_public_st_composite(st_gs_text_params, gs_text_params_t,\
+ "gs_text_params", text_params_enum_ptrs, text_params_reloc_ptrs)
+
+/* Define the abstract type for the object procedures. */
+typedef struct gs_text_enum_procs_s gs_text_enum_procs_t;
+
+/*
+ * Define the common part of the structure that tracks the state of text
+ * display. All implementations of text_begin must allocate one of these
+ * using rc_alloc_struct_1; implementations may subclass and extend it.
+ * Note that it includes a copy of the text parameters.
+ */
+#ifndef gx_device_DEFINED
+# define gx_device_DEFINED
+typedef struct gx_device_s gx_device;
+
+#endif
+#define gs_text_enum_common\
+ /* The following are set at initialization, and const thereafter. */\
+ gs_text_params_t text;\
+ const gs_text_enum_procs_t *procs;\
+ gx_device *dev;\
+ /* The following change dynamically. */\
+ rc_header rc;\
+ uint index /* index within string */
+typedef struct gs_text_enum_s {
+ gs_text_enum_common;
+} gs_text_enum_t;
+
+#define st_gs_text_enum_max_ptrs st_gs_text_params_max_ptrs
+/*extern_st(st_gs_text_enum); */
+#define public_st_gs_text_enum() /* in gstext.c */\
+ gs_public_st_composite(st_gs_text_enum, gs_text_enum_t, "gs_text_enum_t",\
+ text_enum_enum_ptrs, text_enum_reloc_ptrs)
+
+/* Begin processing text. */
+/* Note that these take a graphics state argument. */
+#ifndef gs_state_DEFINED
+# define gs_state_DEFINED
+typedef struct gs_state_s gs_state;
+
+#endif
+int gs_text_begin(P4(gs_state * pgs, const gs_text_params_t * text,
+ gs_memory_t * mem, gs_text_enum_t ** ppenum));
+
+/* Begin the PostScript-equivalent text operators. */
+int
+ gs_show_begin(P5(gs_state *, const byte *, uint,
+ gs_memory_t *, gs_text_enum_t **)), gs_ashow_begin(P7(gs_state *, floatp, floatp, const byte *, uint,
+ gs_memory_t *, gs_text_enum_t **)),
+ gs_widthshow_begin(P8(gs_state *, floatp, floatp, gs_char,
+ const byte *, uint,
+ gs_memory_t *, gs_text_enum_t **)), gs_awidthshow_begin(P10(gs_state *, floatp, floatp, gs_char,
+ floatp, floatp, const byte *, uint,
+ gs_memory_t *, gs_text_enum_t **)),
+ gs_kshow_begin(P5(gs_state *, const byte *, uint,
+ gs_memory_t *, gs_text_enum_t **)), gs_xyshow_begin(P7(gs_state *, const byte *, uint,
+ const float *, const float *,
+ gs_memory_t *, gs_text_enum_t **)),
+ gs_glyphshow_begin(P4(gs_state *, gs_glyph,
+ gs_memory_t *, gs_text_enum_t **)), gs_cshow_begin(P5(gs_state *, const byte *, uint,
+ gs_memory_t *, gs_text_enum_t **)),
+ gs_stringwidth_begin(P5(gs_state *, const byte *, uint,
+ gs_memory_t *, gs_text_enum_t **)), gs_charpath_begin(P6(gs_state *, const byte *, uint, bool,
+ gs_memory_t *, gs_text_enum_t **)),
+ gs_glyphpath_begin(P5(gs_state *, gs_glyph, bool,
+ gs_memory_t *, gs_text_enum_t **)), gs_charboxpath_begin(P6(gs_state *, const byte *, uint, bool,
+ gs_memory_t *, gs_text_enum_t **));
+
+/*
+ * Define the possible return values from gs_text_process. The client
+ * should call text_process until it returns 0 (successful completion) or a
+ * negative (error) value.
+ */
+
+ /*
+ * The client must render a character: obtain the code from
+ * gs_show_current_char, do whatever is necessary, and then
+ * call gs_text_process again.
+ */
+#define TEXT_PROCESS_RENDER 1
+
+ /*
+ * The client has asked to intervene between characters.
+ * Obtain the previous and next codes from gs_show_previous_char
+ * and gs_kshow_next_char, do whatever is necessary, and then
+ * call gs_text_process again.
+ */
+#define TEXT_PROCESS_INTERVENE 2
+
+/* Process text after 'begin'. */
+int gs_text_process(P1(gs_text_enum_t * penum));
+
+/* Set text metrics and optionally enable caching. */
+int
+ gs_text_setcharwidth(P2(gs_text_enum_t * penum, const double wxy[2])),
+ gs_text_setcachedevice(P2(gs_text_enum_t * penum, const double wbox[6])),
+ gs_text_setcachedevice2(P2(gs_text_enum_t * penum, const double wbox2[10]));
+
+/* Release the text processing structures. */
+void gs_text_release(P2(gs_text_enum_t * penum, client_name_t cname));
+
+#endif /* gstext_INCLUDED */
diff --git a/pstoraster/gstrap.c b/pstoraster/gstrap.c
new file mode 100644
index 000000000..dfb63e833
--- /dev/null
+++ b/pstoraster/gstrap.c
@@ -0,0 +1,190 @@
+/* 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$ */
+/* Setting trapping parameters and zones */
+#include "string_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gstrap.h"
+
+/* Parameter utilities, copied from gdevpsdf.c. */
+/* These should be merged.... */
+
+/* Compare a C string and a gs_param_string. */
+private bool
+trap_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
+trap_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 (trap_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, integer, or float parameter. */
+private int
+trap_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;
+}
+private int
+trap_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;
+}
+private bool
+check_unit(float *pval)
+{
+ return (*pval >= 0 && *pval <= 1);
+}
+private bool
+check_positive(float *pval)
+{
+ return (*pval > 0);
+}
+private int
+trap_put_float_param(gs_param_list * plist, gs_param_name param_name,
+ float *pval, bool(*check) (P1(float *pval)), int ecode)
+{
+ int code;
+
+ switch (code = param_read_float(plist, param_name, pval)) {
+ case 0:
+ if ((*check) (pval))
+ return 0;
+ code = gs_error_rangecheck;
+ default:
+ ecode = code;
+ param_signal_error(plist, param_name, ecode);
+ break;
+ case 1:
+ break;
+ }
+ return ecode;
+}
+
+/* settrapparams */
+int
+gs_settrapparams(gs_trap_params_t * pparams, gs_param_list * plist)
+{
+ gs_trap_params_t params;
+ int ecode = 0;
+ static const char *const trap_placement_names[] =
+ {
+ gs_trap_placement_names, 0
+ };
+
+ params = *pparams;
+ ecode = trap_put_float_param(plist, "BlackColorLimit",
+ &params.BlackColorLimit,
+ check_unit, ecode);
+ ecode = trap_put_float_param(plist, "BlackDensityLimit",
+ &params.BlackDensityLimit,
+ check_positive, ecode);
+ ecode = trap_put_float_param(plist, "BlackWidth",
+ &params.BlackWidth,
+ check_positive, ecode);
+ ecode = trap_put_bool_param(plist, "Enabled",
+ &params.Enabled, ecode);
+ ecode = trap_put_bool_param(plist, "ImageInternalTrapping",
+ &params.ImageInternalTrapping, ecode);
+ ecode = trap_put_int_param(plist, "ImageResolution",
+ &params.ImageResolution, ecode);
+ if (params.ImageResolution <= 0)
+ param_signal_error(plist, "ImageResolution",
+ ecode = gs_error_rangecheck);
+ ecode = trap_put_bool_param(plist, "ImageToObjectTrapping",
+ &params.ImageToObjectTrapping, ecode);
+ {
+ int placement = params.ImageTrapPlacement;
+
+ ecode = trap_put_enum_param(plist, "ImageTrapPlacement",
+ &placement, trap_placement_names, ecode);
+ params.ImageTrapPlacement = placement;
+ }
+ ecode = trap_put_float_param(plist, "SlidingTrapLimit",
+ &params.SlidingTrapLimit,
+ check_unit, ecode);
+ ecode = trap_put_float_param(plist, "StepLimit",
+ &params.StepLimit, check_unit, ecode);
+ ecode = trap_put_float_param(plist, "TrapColorScaling",
+ &params.TrapColorScaling,
+ check_unit, ecode);
+ ecode = trap_put_float_param(plist, "TrapWidth",
+ &params.TrapWidth,
+ check_positive, ecode);
+ if (ecode < 0)
+ return ecode;
+ *pparams = params;
+ return 0;
+}
diff --git a/pstoraster/gstrap.h b/pstoraster/gstrap.h
new file mode 100644
index 000000000..9e2a303ce
--- /dev/null
+++ b/pstoraster/gstrap.h
@@ -0,0 +1,81 @@
+/* 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$ */
+/* Definitions for trapping parameters and zones */
+
+#ifndef gstrap_INCLUDED
+# define gstrap_INCLUDED
+
+#include "gsparam.h"
+
+/* ---------------- Types and structures ---------------- */
+
+/* Opaque type for a path */
+#ifndef gx_path_DEFINED
+# define gx_path_DEFINED
+typedef struct gx_path_s gx_path;
+
+#endif
+
+/* Define the placement of image traps. */
+typedef enum {
+ tp_Center,
+ tp_Choke,
+ tp_Spread,
+ tp_Normal
+} gs_trap_placement_t;
+
+#define gs_trap_placement_names\
+ "Center", "Choke", "Spread", "Normal"
+
+/* Define a trapping parameter set. */
+typedef struct gs_trap_params_s {
+ float BlackColorLimit; /* 0-1 */
+ float BlackDensityLimit; /* > 0 */
+ float BlackWidth; /* > 0 */
+ /* ColorantZoneDetails; */
+ bool Enabled;
+ /* HalftoneName; */
+ bool ImageInternalTrapping;
+ int ImageResolution;
+ bool ImageToObjectTrapping;
+ gs_trap_placement_t ImageTrapPlacement;
+ float SlidingTrapLimit; /* 0-1 */
+ float StepLimit; /* 0-1 */
+ float TrapColorScaling; /* 0-1 */
+ float TrapWidth; /* > 0 */
+} gs_trap_params_t;
+
+/* Define a trapping zone. ****** SUBJECT TO CHANGE ****** */
+typedef struct gs_trap_zone_s {
+ gs_trap_params_t params;
+ gx_path *zone;
+} gs_trap_zone_t;
+
+/* ---------------- Procedures ---------------- */
+
+int gs_settrapparams(P2(gs_trap_params_t * params, gs_param_list * list));
+
+#endif /* gstrap_INCLUDED */
diff --git a/pstoraster/gstype1.c b/pstoraster/gstype1.c
new file mode 100644
index 000000000..4a27b3177
--- /dev/null
+++ b/pstoraster/gstype1.c
@@ -0,0 +1,562 @@
+/* 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$ */
+/* Adobe Type 1 charstring interpreter */
+#include "math_.h"
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gxarith.h"
+#include "gxfixed.h"
+#include "gxmatrix.h"
+#include "gxcoord.h"
+#include "gxistate.h"
+#include "gzpath.h"
+#include "gxfont.h"
+#include "gxfont1.h"
+#include "gxtype1.h"
+
+/*
+ * Define whether to always do Flex segments as curves.
+ * This is only an issue because some old Adobe DPS fonts
+ * seem to violate the Flex specification in a way that requires this.
+ * We changed this from 1 to 0 in release 5.02: if it causes any
+ * problems, we'll implement a more sophisticated test.
+ */
+#define ALWAYS_DO_FLEX_AS_CURVE 0
+
+/* ------ Main interpreter ------ */
+
+/* Define a pointer to the charstring interpreter stack. */
+typedef fixed *cs_ptr;
+
+/*
+ * Continue interpreting a Type 1 charstring. If str != 0, it is taken as
+ * the byte string to interpret. Return 0 on successful completion, <0 on
+ * error, or >0 when client intervention is required (or allowed). The int*
+ * argument is where the othersubr # is stored for callothersubr.
+ */
+private int
+gs_type1_charstring_interpret(gs_type1_state * pcis,
+ const gs_const_string * str, int *pindex)
+{
+ gs_font_type1 *pfont = pcis->pfont;
+ gs_type1_data *pdata = &pfont->data;
+ bool encrypted = pdata->lenIV >= 0;
+ gs_op1_state s;
+ fixed cstack[ostack_size];
+
+#define cs0 cstack[0]
+#define ics0 fixed2int_var(cs0)
+#define cs1 cstack[1]
+#define ics1 fixed2int_var(cs1)
+#define cs2 cstack[2]
+#define ics2 fixed2int_var(cs2)
+#define cs3 cstack[3]
+#define ics3 fixed2int_var(cs3)
+#define cs4 cstack[4]
+#define ics4 fixed2int_var(cs4)
+#define cs5 cstack[5]
+#define ics5 fixed2int_var(cs5)
+ cs_ptr csp;
+
+#define clear csp = cstack - 1
+ ip_state *ipsp = &pcis->ipstack[pcis->ips_count - 1];
+ register const byte *cip;
+ register crypt_state state;
+ register int c;
+ int code = 0;
+ fixed ftx = pcis->origin.x, fty = pcis->origin.y;
+
+ switch (pcis->init_done) {
+ case -1:
+ break;
+ case 0:
+ gs_type1_finish_init(pcis, &s); /* sets sfc, ptx, pty, origin */
+ ftx = pcis->origin.x, fty = pcis->origin.y;
+ break;
+ default /*case 1 */ :
+ ptx = pcis->position.x;
+ pty = pcis->position.y;
+ sfc = pcis->fc;
+ }
+ sppath = pcis->path;
+ s.pcis = pcis;
+ init_cstack(cstack, csp, pcis);
+
+ if (str == 0)
+ goto cont;
+ ipsp->char_string = *str;
+ cip = str->data;
+ call:state = crypt_charstring_seed;
+ if (encrypted) {
+ int skip = pdata->lenIV;
+
+ /* Skip initial random bytes */
+ for (; skip > 0; ++cip, --skip)
+ decrypt_skip_next(*cip, state);
+ }
+ goto top;
+ cont:cip = ipsp->ip;
+ state = ipsp->dstate;
+ top:for (;;) {
+ uint c0 = *cip++;
+
+ charstring_next(c0, state, c, encrypted);
+ if (c >= c_num1) {
+ /* This is a number, decode it and push it on the stack. */
+
+ if (c < c_pos2_0) { /* 1-byte number */
+ decode_push_num1(csp, c);
+ } else if (c < cx_num4) { /* 2-byte number */
+ decode_push_num2(csp, c, cip, state, encrypted);
+ } else if (c == cx_num4) { /* 4-byte number */
+ long lw;
+
+ decode_num4(lw, cip, state, encrypted);
+ *++csp = int2fixed(lw);
+ if (lw != fixed2long(*csp))
+ return_error(gs_error_rangecheck);
+ } else /* not possible */
+ return_error(gs_error_invalidfont);
+ pushed:if_debug3('1', "[1]%d: (%d) %f\n",
+ (int)(csp - cstack), c, fixed2float(*csp));
+ continue;
+ }
+#ifdef DEBUG
+ if (gs_debug['1']) {
+ static const char *const c1names[] =
+ {char1_command_names};
+
+ if (c1names[c] == 0)
+ dlprintf2("[1]0x%lx: %02x??\n", (ulong) (cip - 1), c);
+ else
+ dlprintf3("[1]0x%lx: %02x %s\n", (ulong) (cip - 1), c,
+ c1names[c]);
+ }
+#endif
+ switch ((char_command) c) {
+#define cnext clear; goto top
+#define inext goto top
+
+ /* Commands with identical functions in Type 1 and Type 2, */
+ /* except for 'escape'. */
+
+ case c_undef0:
+ case c_undef2:
+ case c_undef17:
+ return_error(gs_error_invalidfont);
+ case c_callsubr:
+ c = fixed2int_var(*csp) + pdata->subroutineNumberBias;
+ code = (*pdata->procs->subr_data)
+ (pfont, c, false, &ipsp[1].char_string);
+ if (code < 0)
+ return_error(code);
+ --csp;
+ ipsp->ip = cip, ipsp->dstate = state;
+ ++ipsp;
+ cip = ipsp->char_string.data;
+ goto call;
+ case c_return:
+ --ipsp;
+ goto cont;
+ case c_undoc15:
+ /* See gstype1.h for information on this opcode. */
+ cnext;
+
+ /* Commands with similar but not identical functions */
+ /* in Type 1 and Type 2 charstrings. */
+
+ case cx_hstem:
+ apply_path_hints(pcis, false);
+ type1_hstem(pcis, cs0, cs1);
+ cnext;
+ case cx_vstem:
+ apply_path_hints(pcis, false);
+ type1_vstem(pcis, cs0, cs1);
+ cnext;
+ case cx_vmoveto:
+ cs1 = cs0;
+ cs0 = 0;
+ accum_y(cs1);
+ move: /* cs0 = dx, cs1 = dy for hint checking. */
+ if ((pcis->hint_next != 0 || path_is_drawing(sppath)) &&
+ pcis->flex_count == flex_max
+ )
+ apply_path_hints(pcis, true);
+ code = gx_path_add_point(sppath, ptx, pty);
+ goto cc;
+ case cx_rlineto:
+ accum_xy(cs0, cs1);
+ line: /* cs0 = dx, cs1 = dy for hint checking. */
+ code = gx_path_add_line(sppath, ptx, pty);
+ cc:if (code < 0)
+ return code;
+ pp:if_debug2('1', "[1]pt=(%g,%g)\n",
+ fixed2float(ptx), fixed2float(pty));
+ cnext;
+ case cx_hlineto:
+ accum_x(cs0);
+ cs1 = 0;
+ goto line;
+ case cx_vlineto:
+ cs1 = cs0;
+ cs0 = 0;
+ accum_y(cs1);
+ goto line;
+ case cx_rrcurveto:
+ code = gs_op1_rrcurveto(&s, cs0, cs1, cs2, cs3, cs4, cs5);
+ goto cc;
+ case cx_endchar:
+ code = gs_type1_endchar(pcis);
+ if (code == 1) {
+ /* do accent of seac */
+ spt = pcis->position;
+ ipsp = &pcis->ipstack[pcis->ips_count - 1];
+ cip = ipsp->char_string.data;
+ goto call;
+ }
+ return code;
+ case cx_rmoveto:
+ accum_xy(cs0, cs1);
+ goto move;
+ case cx_hmoveto:
+ accum_x(cs0);
+ cs1 = 0;
+ goto move;
+ case cx_vhcurveto:
+ {
+ gs_fixed_point pt1, pt2;
+ fixed ax0 = sppath->position.x - ptx;
+ fixed ay0 = sppath->position.y - pty;
+
+ accum_y(cs0);
+ pt1.x = ptx + ax0, pt1.y = pty + ay0;
+ accum_xy(cs1, cs2);
+ pt2.x = ptx, pt2.y = pty;
+ accum_x(cs3);
+ code = gx_path_add_curve(sppath, pt1.x, pt1.y, pt2.x, pt2.y, ptx, pty);
+ }
+ goto cc;
+ case cx_hvcurveto:
+ {
+ gs_fixed_point pt1, pt2;
+ fixed ax0 = sppath->position.x - ptx;
+ fixed ay0 = sppath->position.y - pty;
+
+ accum_x(cs0);
+ pt1.x = ptx + ax0, pt1.y = pty + ay0;
+ accum_xy(cs1, cs2);
+ pt2.x = ptx, pt2.y = pty;
+ accum_y(cs3);
+ code = gx_path_add_curve(sppath, pt1.x, pt1.y, pt2.x, pt2.y, ptx, pty);
+ }
+ goto cc;
+
+ /* Commands only recognized in Type 1 charstrings, */
+ /* plus 'escape'. */
+
+ case c1_closepath:
+ code = gs_op1_closepath(&s);
+ apply_path_hints(pcis, true);
+ goto cc;
+ case c1_hsbw:
+ gs_type1_sbw(pcis, cs0, fixed_0, cs1, fixed_0);
+rsbw: /* Give the caller the opportunity to intervene. */
+ pcis->os_count = 0; /* clear */
+ ipsp->ip = cip, ipsp->dstate = state;
+ pcis->ips_count = ipsp - &pcis->ipstack[0] + 1;
+ /* If we aren't in a seac, do nothing else now; */
+ /* finish_init will take care of the rest. */
+ if (pcis->init_done < 0) {
+ /* Finish init when we return. */
+ pcis->init_done = 0;
+ } else {
+ /* Accumulate the side bearing now, but don't do it */
+ /* a second time for the base character of a seac. */
+ if (pcis->seac_accent < 0)
+ accum_xy(pcis->lsb.x, pcis->lsb.y);
+ pcis->position.x = ptx;
+ pcis->position.y = pty;
+ }
+ return type1_result_sbw;
+ case cx_escape:
+ charstring_next(*cip, state, c, encrypted);
+ ++cip;
+#ifdef DEBUG
+ if (gs_debug['1'] && c < char1_extended_command_count) {
+ static const char *const ce1names[] =
+ {char1_extended_command_names};
+
+ if (ce1names[c] == 0)
+ dlprintf2("[1]0x%lx: %02x??\n", (ulong) (cip - 1), c);
+ else
+ dlprintf3("[1]0x%lx: %02x %s\n", (ulong) (cip - 1), c,
+ ce1names[c]);
+ }
+#endif
+ switch ((char1_extended_command) c) {
+ case ce1_dotsection:
+ pcis->dotsection_flag ^=
+ (dotsection_in ^ dotsection_out);
+ cnext;
+ case ce1_vstem3:
+ apply_path_hints(pcis, false);
+ if (!pcis->vstem3_set && pcis->fh.use_x_hints) {
+ center_vstem(pcis, pcis->lsb.x + cs2, cs3);
+ /* Adjust the current point */
+ /* (center_vstem handles everything else). */
+ ptx += pcis->vs_offset.x;
+ pty += pcis->vs_offset.y;
+ pcis->vstem3_set = true;
+ }
+ type1_vstem(pcis, cs0, cs1);
+ type1_vstem(pcis, cs2, cs3);
+ type1_vstem(pcis, cs4, cs5);
+ cnext;
+ case ce1_hstem3:
+ apply_path_hints(pcis, false);
+ type1_hstem(pcis, cs0, cs1);
+ type1_hstem(pcis, cs2, cs3);
+ type1_hstem(pcis, cs4, cs5);
+ cnext;
+ case ce1_seac:
+ code = gs_type1_seac(pcis, cstack + 1, cstack[0],
+ ipsp);
+ if (code != 0) {
+ *pindex = ics3;
+ return code;
+ }
+ clear;
+ cip = ipsp->char_string.data;
+ goto call;
+ case ce1_sbw:
+ gs_type1_sbw(pcis, cs0, cs1, cs2, cs3);
+ goto rsbw;
+ case ce1_div:
+ csp[-1] = float2fixed((float)csp[-1] / (float)*csp);
+ --csp;
+ goto pushed;
+ case ce1_undoc15:
+ /* See gstype1.h for information on this opcode. */
+ cnext;
+ case ce1_callothersubr:
+ {
+ int num_results;
+
+#define fpts pcis->flex_points
+ /* We must remember to pop both the othersubr # */
+ /* and the argument count off the stack. */
+ switch (*pindex = fixed2int_var(*csp)) {
+ case 0:
+ { /* We have to do something really sleazy */
+ /* here, namely, make it look as though */
+ /* the rmovetos never really happened, */
+ /* because we don't want to interrupt */
+ /* the current subpath. */
+ gs_fixed_point ept;
+
+#if defined(DEBUG) || !ALWAYS_DO_FLEX_AS_CURVE
+ fixed fheight = csp[-4];
+ gs_fixed_point hpt;
+
+#endif
+
+ if (pcis->flex_count != 8)
+ return_error(gs_error_invalidfont);
+ /* Assume the next two opcodes */
+ /* are `pop' `pop'. Unfortunately, some */
+ /* Monotype fonts put these in a Subr, */
+ /* so we can't just look ahead in the */
+ /* opcode stream. */
+ pcis->ignore_pops = 2;
+ csp[-4] = csp[-3] - pcis->asb_diff;
+ csp[-3] = csp[-2];
+ csp -= 3;
+ gx_path_current_point(sppath, &ept);
+ gx_path_add_point(sppath, fpts[0].x, fpts[0].y);
+ sppath->state_flags = /* <--- sleaze */
+ pcis->flex_path_state_flags;
+#if defined(DEBUG) || !ALWAYS_DO_FLEX_AS_CURVE
+ /* Decide whether to do the flex as a curve. */
+ hpt.x = fpts[1].x - fpts[4].x;
+ hpt.y = fpts[1].y - fpts[4].y;
+ if_debug3('1',
+ "[1]flex: d=(%g,%g), height=%g\n",
+ fixed2float(hpt.x), fixed2float(hpt.y),
+ fixed2float(fheight) / 100);
+#endif
+#if !ALWAYS_DO_FLEX_AS_CURVE /* See beginning of file. */
+ if (any_abs(hpt.x) + any_abs(hpt.y) <
+ fheight / 100
+ ) { /* Do the flex as a line. */
+ code = gx_path_add_line(sppath,
+ ept.x, ept.y);
+ } else
+#endif
+ { /* Do the flex as a curve. */
+ code = gx_path_add_curve(sppath,
+ fpts[2].x, fpts[2].y,
+ fpts[3].x, fpts[3].y,
+ fpts[4].x, fpts[4].y);
+ if (code < 0)
+ return code;
+ code = gx_path_add_curve(sppath,
+ fpts[5].x, fpts[5].y,
+ fpts[6].x, fpts[6].y,
+ fpts[7].x, fpts[7].y);
+ }
+ }
+ if (code < 0)
+ return code;
+ pcis->flex_count = flex_max; /* not inside flex */
+ inext;
+ case 1:
+ gx_path_current_point(sppath, &fpts[0]);
+ pcis->flex_path_state_flags = /* <--- more sleaze */
+ sppath->state_flags;
+ pcis->flex_count = 1;
+ csp -= 2;
+ inext;
+ case 2:
+ if (pcis->flex_count >= flex_max)
+ return_error(gs_error_invalidfont);
+ gx_path_current_point(sppath,
+ &fpts[pcis->flex_count++]);
+ csp -= 2;
+ inext;
+ case 3:
+ /* Assume the next opcode is a `pop'. */
+ /* See above as to why we don't just */
+ /* look ahead in the opcode stream. */
+ pcis->ignore_pops = 1;
+ replace_stem_hints(pcis);
+ csp -= 2;
+ inext;
+ case 14:
+ num_results = 1;
+ blend:{
+ int num_values = fixed2int_var(csp[-1]);
+ int k1 = num_values / num_results - 1;
+ int i, j;
+ cs_ptr base, deltas;
+
+ if (num_values < num_results ||
+ num_values % num_results != 0
+ )
+ return_error(gs_error_invalidfont);
+ base = csp - 1 - num_values;
+ deltas = base + num_results - 1;
+ for (j = 0; j < num_results;
+ j++, base++, deltas += k1
+ )
+ for (i = 1; i <= k1; i++)
+ *base += deltas[i] *
+ pdata->WeightVector.values[i];
+ csp = base - 1;
+ }
+ pcis->ignore_pops = num_results;
+ inext;
+ case 15:
+ num_results = 2;
+ goto blend;
+ case 16:
+ num_results = 3;
+ goto blend;
+ case 17:
+ num_results = 4;
+ goto blend;
+ case 18:
+ num_results = 6;
+ goto blend;
+ }
+ }
+#undef fpts
+ /* Not a recognized othersubr, */
+ /* let the client handle it. */
+ {
+ int scount = csp - cstack;
+ int n;
+
+ /* Copy the arguments to the caller's stack. */
+ if (scount < 1 || csp[-1] < 0 ||
+ csp[-1] > int2fixed(scount - 1)
+ )
+ return_error(gs_error_invalidfont);
+ n = fixed2int_var(csp[-1]);
+ code = (*pdata->procs->push) (pfont, csp - (n + 1), n);
+ if (code < 0)
+ return_error(code);
+ scount -= n + 1;
+ pcis->position.x = ptx;
+ pcis->position.y = pty;
+ apply_path_hints(pcis, false);
+ /* Exit to caller */
+ ipsp->ip = cip, ipsp->dstate = state;
+ pcis->os_count = scount;
+ pcis->ips_count = ipsp - &pcis->ipstack[0] + 1;
+ if (scount)
+ memcpy(pcis->ostack, cstack, scount * sizeof(fixed));
+ return type1_result_callothersubr;
+ }
+ case ce1_pop:
+ /* Check whether we're ignoring the pops after */
+ /* a known othersubr. */
+ if (pcis->ignore_pops != 0) {
+ pcis->ignore_pops--;
+ inext;
+ }
+ ++csp;
+ code = (*pdata->procs->pop) (pfont, csp);
+ if (code < 0)
+ return_error(code);
+ goto pushed;
+ case ce1_setcurrentpoint:
+ ptx = ftx, pty = fty;
+ cs0 += pcis->adxy.x;
+ cs1 += pcis->adxy.y;
+ accum_xy(cs0, cs1);
+ goto pp;
+ default:
+ return_error(gs_error_invalidfont);
+ }
+ /*NOTREACHED */
+
+ /* Fill up the dispatch up to 32. */
+
+ case_c1_undefs:
+ default: /* pacify compiler */
+ return_error(gs_error_invalidfont);
+ }
+ }
+}
+
+/* Register the interpreter. */
+void
+gs_gstype1_init(gs_memory_t * mem)
+{
+ gs_charstring_interpreter[1] = gs_type1_charstring_interpret;
+}
diff --git a/pstoraster/gstype1.h b/pstoraster/gstype1.h
new file mode 100644
index 000000000..e7c2e0c9f
--- /dev/null
+++ b/pstoraster/gstype1.h
@@ -0,0 +1,265 @@
+/* Copyright (C) 1990, 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$ */
+/* Client interface to Adobe Type 1 font routines */
+
+#ifndef gstype1_INCLUDED
+# define gstype1_INCLUDED
+
+/* ------ Normal client interface ------ */
+
+#define crypt_charstring_seed 4330
+typedef struct gs_type1_state_s gs_type1_state;
+
+#ifndef gx_path_DEFINED
+# define gx_path_DEFINED
+typedef struct gx_path_s gx_path;
+
+#endif
+#ifndef gs_show_enum_s_DEFINED
+struct gs_show_enum_s;
+
+#endif
+#ifndef gs_font_type1_DEFINED
+# define gs_font_type1_DEFINED
+typedef struct gs_font_type1_s gs_font_type1;
+
+#endif
+#ifndef gs_type1_data_s_DEFINED
+struct gs_type1_data_s;
+
+#endif
+int gs_type1_interp_init(P7(gs_type1_state * pcis, gs_imager_state * pis,
+ gx_path * ppath, const gs_log2_scale_point * pscale,
+ bool charpath_flag, int paint_type,
+ gs_font_type1 * pfont));
+void gs_type1_set_lsb(P2(gs_type1_state * pcis, const gs_point * psbpt));
+void gs_type1_set_width(P2(gs_type1_state * pcis, const gs_point * pwpt));
+
+/* Backward compatibility */
+#define gs_type1_init(pcis, penum, psbpt, charpath_flag, paint_type, pfont)\
+ (gs_type1_interp_init(pcis, (gs_imager_state *)((penum)->pgs),\
+ (penum)->pgs->path, &(penum)->log2_current_scale,\
+ charpath_flag, paint_type, pfont) |\
+ ((psbpt) == 0 ? 0 : (gs_type1_set_lsb(pcis, psbpt), 0)))
+/*
+ * Continue interpreting a Type 1 CharString. If str != 0, it is taken as
+ * the byte string to interpret. Return 0 on successful completion, <0 on
+ * error, or >0 when client intervention is required (or allowed). The int*
+ * argument is where the othersubr # is stored for callothersubr.
+ */
+#define type1_result_sbw 1 /* allow intervention after [h]sbw */
+#define type1_result_callothersubr 2
+
+int gs_type1_interpret(P3(gs_type1_state *, const gs_const_string *, int *));
+
+/* ------ CharString number representation ------ */
+
+/* Define the representation of integers used by both Type 1 and Type 2. */
+typedef enum {
+
+ /* Values from 32 to 246 represent small integers. */
+ c_num1 = 32,
+#define c_value_num1(ch) ((int)(byte)(ch) - 139)
+
+ /* The next 4 values represent 2-byte positive integers. */
+ c_pos2_0 = 247,
+ c_pos2_1 = 248,
+ c_pos2_2 = 249,
+ c_pos2_3 = 250,
+#define c_value_pos2(c1,c2)\
+ (((int)(byte)((c1) - (int)c_pos2_0) << 8) + (int)(byte)(c2) + 108)
+
+ /* The next 4 values represent 2-byte negative integers. */
+ c_neg2_0 = 251,
+ c_neg2_1 = 252,
+ c_neg2_2 = 253,
+ c_neg2_3 = 254
+#define c_value_neg2(c1,c2)\
+ -(((int)(byte)((c1) - (int)c_neg2_0) << 8) + (int)(byte)(c2) + 108)
+
+} char_num_command;
+
+/* ------ Type 1 & Type 2 CharString representation ------ */
+
+/*
+ * We define both the Type 1 and Type 2 operators here, because they
+ * overlap so much.
+ */
+typedef enum {
+
+ /* Commands with identical functions in Type 1 and Type 2 */
+ /* charstrings. */
+
+ c_undef0 = 0,
+ c_undef2 = 2,
+ c_callsubr = 10,
+ c_return = 11,
+ c_undoc15 = 15, /* An obsolete and undocumented */
+ /* command used in some very old */
+ /* Adobe fonts. */
+ c_undef17 = 17,
+
+ /* Commands with similar but not identical functions */
+ /* in Type 1 and Type 2 charstrings. */
+
+ cx_hstem = 1,
+ cx_vstem = 3,
+ cx_vmoveto = 4,
+ cx_rlineto = 5,
+ cx_hlineto = 6,
+ cx_vlineto = 7,
+ cx_rrcurveto = 8,
+ cx_escape = 12, /* extends the command set */
+ cx_endchar = 14,
+ cx_rmoveto = 21,
+ cx_hmoveto = 22,
+ cx_vhcurveto = 30,
+ cx_hvcurveto = 31,
+
+ cx_num4 = 255, /* 4-byte numbers */
+
+ /* Commands recognized only in Type 1 charstrings. */
+
+ c1_closepath = 9,
+ c1_hsbw = 13,
+
+ /* Commands not recognized in Type 1 charstrings. */
+
+#define case_c1_undefs\
+ case 16: case 18: case 19:\
+ case 20: case 23: case 24:\
+ case 25: case 26: case 27: case 28: case 29
+
+ /* Commands only recognized in Type 2 charstrings. */
+
+ c2_blend = 16,
+ c2_hstemhm = 18,
+ c2_hintmask = 19,
+ c2_cntrmask = 20,
+ c2_vstemhm = 23,
+ c2_rcurveline = 24,
+ c2_rlinecurve = 25,
+ c2_vvcurveto = 26,
+ c2_hhcurveto = 27,
+ c2_shortint = 28,
+ c2_callgsubr = 29
+
+ /* Commands not recognized in Type 2 charstrings. */
+
+#define case_c2_undefs\
+ case 9: case 13
+
+} char_command;
+
+#define char1_command_names\
+ 0, "hstem", 0, "vstem", "vmoveto",\
+ "rlineto", "hlineto", "vlineto", "rrcurveto", "closepath",\
+ "callsubr", "return", "(escape)", "hsbw", "endchar",\
+ "undoc15", 0, 0, 0, 0,\
+ 0, "rmoveto", "hmoveto", 0, 0,\
+ 0, 0, 0, 0, 0,\
+ "vhcurveto", "hvcurveto"
+#define char2_command_names\
+ 0, "hstem", 0, "vstem", "vmoveto",\
+ "rlineto", "hlineto", "vlineto", "rrcurveto", 0,\
+ "callsubr", "return", "(escape)", 0, "endchar",\
+ "undoc15", "blend", 0, "hstemhm", "hintmask",\
+ "cntrmask", "rmoveto", "hmoveto", "vstemhm", "rcurveline",\
+ "rlinecurve", "vvcurveto", "hhcurveto", "shortint", "callgsubr",\
+ "vhcurveto", "hvcurveto"
+
+/*
+ * Extended (escape) commands in Type 1 charstrings.
+ */
+typedef enum {
+ ce1_dotsection = 0,
+ ce1_vstem3 = 1,
+ ce1_hstem3 = 2,
+ ce1_seac = 6,
+ ce1_sbw = 7,
+ ce1_div = 12,
+ ce1_undoc15 = 15, /* An obsolete and undocumented */
+ /* command used in some very old */
+ /* Adobe fonts. */
+ ce1_callothersubr = 16,
+ ce1_pop = 17,
+ ce1_setcurrentpoint = 33
+} char1_extended_command;
+
+#define char1_extended_command_count 34
+#define char1_extended_command_names\
+ "dotsection", "vstem3", "hstem3", 0, 0,\
+ 0, "seac", "sbw", 0, 0,\
+ 0, 0, "div", 0, 0,\
+ "undoc15", "callothersubr", "pop", 0, 0,\
+ 0, 0, 0, 0, 0,\
+ 0, 0, 0, 0, 0,\
+ 0, 0, 0, "setcurrentpoint"
+
+/*
+ * Extended (escape) commands in Type 2 charstrings.
+ */
+typedef enum {
+ ce2_and = 3,
+ ce2_or = 4,
+ ce2_not = 5,
+ ce2_store = 8,
+ ce2_abs = 9,
+ ce2_add = 10,
+ ce2_sub = 11,
+ ce2_div = 12, /* same as ce1_div */
+ ce2_load = 13,
+ ce2_neg = 14,
+ ce2_eq = 15,
+ ce2_drop = 18,
+ ce2_put = 20,
+ ce2_get = 21,
+ ce2_ifelse = 22,
+ ce2_random = 23,
+ ce2_mul = 24,
+ ce2_sqrt = 26,
+ ce2_dup = 27,
+ ce2_exch = 28,
+ ce2_index = 29,
+ ce2_roll = 30,
+ ce2_hflex = 34,
+ ce2_flex = 35,
+ ce2_hflex1 = 36,
+ ce2_flex1 = 37
+} char2_extended_command;
+
+#define char2_extended_command_count 38
+#define char2_extended_command_names\
+ 0, 0, 0, "and", "or",\
+ "not", 0, 0, "store", "abs",\
+ "add", "sub", "div", "load", "neg",\
+ "eq", 0, 0, "drop", 0,\
+ "put", "get", "ifelse", "random", "mul",\
+ 0, "sqrt", "dup", "exch", "index",\
+ "roll", 0, 0, 0, "hflex",\
+ "flex", "hflex1", "flex1"
+
+#endif /* gstype1_INCLUDED */
diff --git a/pstoraster/gstype2.c b/pstoraster/gstype2.c
new file mode 100644
index 000000000..8da6b1fa5
--- /dev/null
+++ b/pstoraster/gstype2.c
@@ -0,0 +1,779 @@
+/*
+ Copyright 2001 by Easy Software Products
+ Copyright 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$ */
+/* Adobe Type 2 charstring interpreter */
+#include "math_.h"
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gxarith.h"
+#include "gxfixed.h"
+#include "gxmatrix.h"
+#include "gxcoord.h"
+#include "gxistate.h"
+#include "gzpath.h"
+#include "gxfont.h"
+#include "gxfont1.h"
+#include "gxtype1.h"
+
+/* NOTE: The following are not yet implemented:
+ * Registry items other than 0
+ * Counter masks (but they are parsed correctly)
+ * 'random' operator
+ */
+
+/* Define a pointer to the charstring interpreter stack. */
+typedef fixed *cs_ptr;
+
+/* ------ Internal routines ------ */
+
+/*
+ * Set the character width. This is provided as an optional extra operand
+ * on the stack for the first operator. After setting the width, we remove
+ * the extra operand, and back up the interpreter pointer so we will
+ * re-execute the operator when control re-enters the interpreter.
+ */
+#define check_first_operator(explicit_width)\
+ BEGIN\
+ if ( pcis->init_done < 0 )\
+ { ipsp->ip = cip, ipsp->dstate = state;\
+ return type2_sbw(pcis, csp, cstack, ipsp, explicit_width);\
+ }\
+ END
+private int
+type2_sbw(gs_type1_state * pcis, cs_ptr csp, cs_ptr cstack, ip_state * ipsp,
+ bool explicit_width)
+{
+ fixed wx;
+
+ if (explicit_width) {
+ wx = cstack[0] + pcis->pfont->data.nominalWidthX;
+ memmove(cstack, cstack + 1, (csp - cstack) * sizeof(*cstack));
+ --csp;
+ } else
+ wx = pcis->pfont->data.defaultWidthX;
+ gs_type1_sbw(pcis, fixed_0, fixed_0, wx, fixed_0);
+ /* Back up the interpretation pointer. */
+ {
+ ip_state *ipsp = &pcis->ipstack[pcis->ips_count - 1];
+
+ ipsp->ip--;
+ decrypt_skip_previous(*ipsp->ip, ipsp->dstate);
+ }
+ /* Save the interpreter state. */
+ pcis->os_count = csp + 1 - cstack;
+ pcis->ips_count = ipsp - &pcis->ipstack[0] + 1;
+ memcpy(pcis->ostack, cstack, pcis->os_count * sizeof(cstack[0]));
+ if (pcis->init_done < 0) { /* Finish init when we return. */
+ pcis->init_done = 0;
+ }
+ return type1_result_sbw;
+}
+private int
+type2_vstem(gs_type1_state * pcis, cs_ptr csp, cs_ptr cstack)
+{
+ fixed x = 0;
+ cs_ptr ap;
+
+ apply_path_hints(pcis, false);
+ for (ap = cstack; ap + 1 <= csp; x += ap[1], ap += 2)
+ type1_vstem(pcis, x += ap[0], ap[1]);
+ pcis->num_hints += (csp + 1 - cstack) >> 1;
+ return 0;
+}
+
+/* Enable only the hints selected by a mask. */
+private void
+enable_hints(stem_hint_table * psht, const byte * mask)
+{
+ stem_hint *table = &psht->data[0];
+ stem_hint *ph = table + psht->current;
+
+ for (ph = &table[psht->count]; --ph >= table;) {
+ ph->active = (mask[ph->index >> 3] & (0x80 >> (ph->index & 7))) != 0;
+ if_debug6('1', "[1] %s %u: %g(%g),%g(%g)\n",
+ (ph->active ? "enable" : "disable"), ph->index,
+ fixed2float(ph->v0), fixed2float(ph->dv0),
+ fixed2float(ph->v1), fixed2float(ph->dv1));
+ }
+}
+
+/* ------ Main interpreter ------ */
+
+/*
+ * Continue interpreting a Type 2 charstring. If str != 0, it is taken as
+ * the byte string to interpret. Return 0 on successful completion, <0 on
+ * error, or >0 when client intervention is required (or allowed). The int*
+ * argument is only for compatibility with the Type 1 charstring interpreter.
+ */
+private int
+gs_type2_charstring_interpret(gs_type1_state * pcis,
+ const gs_const_string * str, int *ignore_pindex)
+{
+ gs_font_type1 *pfont = pcis->pfont;
+ gs_type1_data *pdata = &pfont->data;
+ bool encrypted = pdata->lenIV >= 0;
+ gs_op1_state s;
+ fixed cstack[ostack_size];
+ cs_ptr csp;
+
+#define clear csp = cstack - 1
+ ip_state *ipsp = &pcis->ipstack[pcis->ips_count - 1];
+ register const byte *cip;
+ register crypt_state state;
+ register int c;
+ cs_ptr ap;
+ bool vertical;
+ int code = 0;
+
+/****** FAKE THE REGISTRY ******/
+ struct {
+ float *values;
+ uint size;
+ } Registry[1];
+
+ Registry[0].values = pcis->pfont->data.WeightVector.values;
+
+ switch (pcis->init_done) {
+ case -1:
+ break;
+ case 0:
+ gs_type1_finish_init(pcis, &s); /* sets sfc, ptx, pty, origin */
+ break;
+ default /*case 1 */ :
+ ptx = pcis->position.x;
+ pty = pcis->position.y;
+ sfc = pcis->fc;
+ }
+ sppath = pcis->path;
+ s.pcis = pcis;
+ init_cstack(cstack, csp, pcis);
+
+ if (str == 0)
+ goto cont;
+ ipsp->char_string = *str;
+ cip = str->data;
+ call:state = crypt_charstring_seed;
+ if (encrypted) {
+ int skip = pdata->lenIV;
+
+ /* Skip initial random bytes */
+ for (; skip > 0; ++cip, --skip)
+ decrypt_skip_next(*cip, state);
+ }
+ goto top;
+ cont:cip = ipsp->ip;
+ state = ipsp->dstate;
+ top:for (;;) {
+ uint c0 = *cip++;
+
+ charstring_next(c0, state, c, encrypted);
+ if (c >= c_num1) {
+ /* This is a number, decode it and push it on the stack. */
+
+ if (c < c_pos2_0) { /* 1-byte number */
+ decode_push_num1(csp, c);
+ } else if (c < cx_num4) { /* 2-byte number */
+ decode_push_num2(csp, c, cip, state, encrypted);
+ } else if (c == cx_num4) { /* 4-byte number */
+ long lw;
+
+ decode_num4(lw, cip, state, encrypted);
+ /* 32-bit numbers are 16:16. */
+ *++csp = arith_rshift(lw, 16 - _fixed_shift);
+ } else /* not possible */
+ return_error(gs_error_invalidfont);
+ pushed:if_debug3('1', "[1]%d: (%d) %f\n",
+ (int)(csp - cstack), c, fixed2float(*csp));
+ continue;
+ }
+#ifdef DEBUG
+ if (gs_debug['1']) {
+ static const char *const c2names[] =
+ {char2_command_names};
+
+ if (c2names[c] == 0)
+ dlprintf2("[1]0x%lx: %02x??\n", (ulong) (cip - 1), c);
+ else
+ dlprintf3("[1]0x%lx: %02x %s\n", (ulong) (cip - 1), c,
+ c2names[c]);
+ }
+#endif
+ switch ((char_command) c) {
+#define cnext clear; goto top
+
+ /* Commands with identical functions in Type 1 and Type 2, */
+ /* except for 'escape'. */
+
+ case c_undef0:
+ case c_undef2:
+ case c_undef17:
+ return_error(gs_error_invalidfont);
+ case c_callsubr:
+ c = fixed2int_var(*csp) + pdata->subroutineNumberBias;
+ code = (*pdata->procs->subr_data)
+ (pfont, c, false, &ipsp[1].char_string);
+ subr:if (code < 0)
+ return_error(code);
+ --csp;
+ ipsp->ip = cip, ipsp->dstate = state;
+ ++ipsp;
+ cip = ipsp->char_string.data;
+ goto call;
+ case c_return:
+ --ipsp;
+ goto cont;
+ case c_undoc15:
+ /* See gstype1.h for information on this opcode. */
+ cnext;
+
+ /* Commands with similar but not identical functions */
+ /* in Type 1 and Type 2 charstrings. */
+
+ case cx_hstem:
+ goto hstem;
+ case cx_vstem:
+ goto vstem;
+ case cx_vmoveto:
+ check_first_operator(csp > cstack);
+ /*** MRS: This is the first of many macro invocations;
+ *** Since these are encased in {} (previously an
+ *** empty do while(0) loop), we don't need the
+ *** trailing semicolon...
+ ***/
+ accum_y(*csp)
+ move:if ((pcis->hint_next != 0 || path_is_drawing(sppath)))
+ apply_path_hints(pcis, true);
+ code = gx_path_add_point(sppath, ptx, pty);
+ cc:if (code < 0)
+ return code;
+ goto pp;
+ case cx_rlineto:
+ for (ap = cstack; ap + 1 <= csp; ap += 2) {
+ accum_xy(ap[0], ap[1]);
+ code = gx_path_add_line(sppath, ptx, pty);
+ if (code < 0)
+ return code;
+ }
+ pp:if_debug2('1', "[1]pt=(%g,%g)\n",
+ fixed2float(ptx), fixed2float(pty));
+ cnext;
+ case cx_hlineto:
+ vertical = false;
+ goto hvl;
+ case cx_vlineto:
+ vertical = true;
+ hvl:for (ap = cstack; ap <= csp; vertical = !vertical, ++ap) {
+ if (vertical)
+ accum_y(*ap)
+ else
+ accum_x(*ap)
+ code = gx_path_add_line(sppath, ptx, pty);
+ if (code < 0)
+ return code;
+ }
+ goto pp;
+ case cx_rrcurveto:
+ for (ap = cstack; ap + 5 <= csp; ap += 6) {
+ code = gs_op1_rrcurveto(&s, ap[0], ap[1], ap[2],
+ ap[3], ap[4], ap[5]);
+ if (code < 0)
+ return code;
+ }
+ goto pp;
+ case cx_endchar:
+ /*
+ * It is an undocumented (!) feature of Type 2 CharStrings
+ * that if endchar is invoked with 4 or 5 operands, it is
+ * equivalent to the Type 1 seac operator! In this case,
+ * the asb operand of seac is missing: we assume it is
+ * the same as the l.s.b. of the accented character.
+ */
+ if (csp >= cstack + 3) {
+ check_first_operator(csp > cstack + 3);
+ code = gs_type1_seac(pcis, cstack, pcis->lsb.x, ipsp);
+ if (code < 0)
+ return code;
+ clear;
+ cip = ipsp->char_string.data;
+ goto call;
+ }
+ /*
+ * This might be the only operator in the charstring.
+ * In this case, there might be a width on the stack.
+ */
+ check_first_operator(csp >= cstack);
+ code = gs_type1_endchar(pcis);
+ if (code == 1) {
+ /*
+ * Reset the total hint count so that hintmask will
+ * parse its following data correctly.
+ * (gs_type1_endchar already reset the actual hint
+ * tables.)
+ */
+ pcis->num_hints = 0;
+ /* do accent of seac */
+ spt = pcis->position;
+ ipsp = &pcis->ipstack[pcis->ips_count - 1];
+ cip = ipsp->char_string.data;
+ goto call;
+ }
+ return code;
+ case cx_rmoveto:
+ check_first_operator(csp > cstack + 1);
+ accum_xy(csp[-1], *csp);
+ goto move;
+ case cx_hmoveto:
+ check_first_operator(csp > cstack);
+ accum_x(*csp)
+ goto move;
+ case cx_vhcurveto:
+ vertical = true;
+ goto hvc;
+ case cx_hvcurveto:
+ vertical = false;
+ hvc:for (ap = cstack; ap + 3 <= csp; vertical = !vertical, ap += 4) {
+ gs_fixed_point pt1, pt2;
+ fixed ax0 = sppath->position.x - ptx;
+ fixed ay0 = sppath->position.y - pty;
+
+ if (vertical)
+ accum_y(ap[0])
+ else
+ accum_x(ap[0])
+ pt1.x = ptx + ax0, pt1.y = pty + ay0;
+ accum_xy(ap[1], ap[2]);
+ pt2.x = ptx, pt2.y = pty;
+ if (vertical) {
+ if (ap + 4 == csp)
+ accum_xy(ap[3], ap[4]);
+ else
+ accum_x(ap[3])
+ } else {
+ if (ap + 4 == csp)
+ accum_xy(ap[4], ap[3]);
+ else
+ accum_y(ap[3])
+ }
+ code = gx_path_add_curve(sppath, pt1.x, pt1.y,
+ pt2.x, pt2.y, ptx, pty);
+ if (code < 0)
+ return code;
+ }
+ goto pp;
+
+ /***********************
+ * New Type 2 commands *
+ ***********************/
+
+ case c2_blend:
+ {
+ int n = fixed2int_var(*csp);
+ int num_values = csp - cstack;
+ gs_font_type1 *pfont = pcis->pfont;
+ int k = pfont->data.WeightVector.count;
+ int i, j;
+ cs_ptr base, deltas;
+
+ base = csp - 1 - num_values;
+ deltas = base + n - 1;
+ for (j = 0; j < n; j++, base++, deltas += k - 1)
+ for (i = 1; i < k; i++)
+ *base += deltas[i] * pfont->data.WeightVector.values[i];
+ }
+ cnext;
+ case c2_hstemhm:
+ pcis->have_hintmask = true;
+ hstem:check_first_operator(!((csp - cstack) & 1));
+ apply_path_hints(pcis, false);
+ {
+ fixed x = 0;
+
+ for (ap = cstack; ap + 1 <= csp; x += ap[1], ap += 2)
+ type1_hstem(pcis, x += ap[0], ap[1]);
+ }
+ pcis->num_hints += (csp + 1 - cstack) >> 1;
+ cnext;
+ case c2_hintmask:
+ /*
+ * A hintmask at the beginning of the CharString is
+ * equivalent to vstemhm + hintmask. For simplicity, we use
+ * this interpretation everywhere.
+ */
+ pcis->have_hintmask = true;
+ check_first_operator(!((csp - cstack) & 1));
+ type2_vstem(pcis, csp, cstack);
+ clear;
+ /* (falls through) */
+ case c2_cntrmask:
+ {
+ byte mask[max_total_stem_hints / 8];
+ int i;
+
+ if_debug3('1', "[1]mask[%d:%dv,%dh]", pcis->num_hints,
+ pcis->vstem_hints.count, pcis->hstem_hints.count);
+ for (i = 0; i < pcis->num_hints; ++cip, i += 8) {
+ charstring_next(*cip, state, mask[i >> 3], encrypted);
+ if_debug1('1', " 0x%02x", mask[i >> 3]);
+ }
+ if_debug0('1', "\n");
+ ipsp->ip = cip;
+ ipsp->dstate = state;
+ if (c == c2_cntrmask) {
+/****** NYI ******/
+ } else { /* hintmask or equivalent */
+ if_debug0('1', "[1]hstem hints:\n");
+ enable_hints(&pcis->hstem_hints, mask);
+ if_debug0('1', "[1]vstem hints:\n");
+ enable_hints(&pcis->vstem_hints, mask);
+ }
+ }
+ break;
+ case c2_vstemhm:
+ pcis->have_hintmask = true;
+ vstem:check_first_operator(!((csp - cstack) & 1));
+ type2_vstem(pcis, csp, cstack);
+ cnext;
+ case c2_rcurveline:
+ for (ap = cstack; ap + 5 <= csp; ap += 6) {
+ code = gs_op1_rrcurveto(&s, ap[0], ap[1], ap[2], ap[3],
+ ap[4], ap[5]);
+ if (code < 0)
+ return code;
+ }
+ accum_xy(ap[0], ap[1]);
+ code = gx_path_add_line(sppath, ptx, pty);
+ goto cc;
+ case c2_rlinecurve:
+ for (ap = cstack; ap + 7 <= csp; ap += 2) {
+ accum_xy(ap[0], ap[1]);
+ code = gx_path_add_line(sppath, ptx, pty);
+ if (code < 0)
+ return code;
+ }
+ code = gs_op1_rrcurveto(&s, ap[0], ap[1], ap[2], ap[3],
+ ap[4], ap[5]);
+ goto cc;
+ case c2_vvcurveto:
+ ap = cstack;
+ {
+ int n = csp + 1 - cstack;
+ fixed dxa = (n & 1 ? *ap++ : 0);
+
+ for (; ap + 3 <= csp; ap += 4) {
+ code = gs_op1_rrcurveto(&s, dxa, ap[0], ap[1], ap[2],
+ fixed_0, ap[3]);
+ if (code < 0)
+ return code;
+ dxa = 0;
+ }
+ }
+ goto pp;
+ case c2_hhcurveto:
+ ap = cstack;
+ {
+ int n = csp + 1 - cstack;
+ fixed dya = (n & 1 ? *ap++ : 0);
+
+ for (; ap + 3 <= csp; ap += 4) {
+ code = gs_op1_rrcurveto(&s, ap[0], dya, ap[1], ap[2],
+ ap[3], fixed_0);
+ if (code < 0)
+ return code;
+ dya = 0;
+ }
+ }
+ goto pp;
+ case c2_shortint:
+ {
+ int c1, c2;
+
+ charstring_next(*cip, state, c1, encrypted);
+ ++cip;
+ charstring_next(*cip, state, c2, encrypted);
+ ++cip;
+ *++csp = int2fixed((((c1 ^ 0x80) - 0x80) << 8) + c2);
+ }
+ goto pushed;
+ case c2_callgsubr:
+ c = fixed2int_var(*csp) + pdata->gsubrNumberBias;
+ code = (*pdata->procs->subr_data)
+ (pfont, c, true, &ipsp[1].char_string);
+ goto subr;
+ case cx_escape:
+ charstring_next(*cip, state, c, encrypted);
+ ++cip;
+#ifdef DEBUG
+ if (gs_debug['1'] && c < char2_extended_command_count) {
+ static const char *const ce2names[] =
+ {char2_extended_command_names};
+
+ if (ce2names[c] == 0)
+ dlprintf2("[1]0x%lx: %02x??\n", (ulong) (cip - 1), c);
+ else
+ dlprintf3("[1]0x%lx: %02x %s\n", (ulong) (cip - 1), c,
+ ce2names[c]);
+ }
+#endif
+ switch ((char2_extended_command) c) {
+ case ce2_and:
+ csp[-1] = ((csp[-1] != 0) & (*csp != 0) ? fixed_1 : 0);
+ --csp;
+ break;
+ case ce2_or:
+ csp[-1] = (csp[-1] | *csp ? fixed_1 : 0);
+ --csp;
+ break;
+ case ce2_not:
+ *csp = (*csp ? 0 : fixed_1);
+ break;
+ case ce2_store:
+ {
+ int i, n = fixed2int_var(*csp);
+ float *to = Registry[fixed2int_var(csp[-3])].values +
+ fixed2int_var(csp[-2]);
+ const fixed *from =
+ pcis->transient_array + fixed2int_var(csp[-1]);
+
+ for (i = 0; i < n; ++i)
+ to[i] = fixed2float(from[i]);
+ }
+ csp -= 4;
+ break;
+ case ce2_abs:
+ if (*csp < 0)
+ *csp = -*csp;
+ break;
+ case ce2_add:
+ csp[-1] += *csp;
+ --csp;
+ break;
+ case ce2_sub:
+ csp[-1] -= *csp;
+ --csp;
+ break;
+ case ce2_div:
+ csp[-1] = float2fixed((double)csp[-1] / *csp);
+ --csp;
+ break;
+ case ce2_load:
+ /* The specification says there is no j (starting index */
+ /* in registry array) argument.... */
+ {
+ int i, n = fixed2int_var(*csp);
+ const float *from = Registry[fixed2int_var(csp[-2])].values;
+ fixed *to =
+ pcis->transient_array + fixed2int_var(csp[-1]);
+
+ for (i = 0; i < n; ++i)
+ to[i] = float2fixed(from[i]);
+ }
+ csp -= 3;
+ break;
+ case ce2_neg:
+ *csp = -*csp;
+ break;
+ case ce2_eq:
+ csp[-1] = (csp[-1] == *csp ? fixed_1 : 0);
+ --csp;
+ break;
+ case ce2_drop:
+ --csp;
+ break;
+ case ce2_put:
+ pcis->transient_array[fixed2int_var(*csp)] = csp[-1];
+ csp -= 2;
+ break;
+ case ce2_get:
+ *csp = pcis->transient_array[fixed2int_var(*csp)];
+ break;
+ case ce2_ifelse:
+ if (csp[-1] > *csp)
+ csp[-3] = csp[-2];
+ csp -= 3;
+ break;
+ case ce2_random:
+ ++csp;
+ /****** NYI ******/
+ break;
+ case ce2_mul:
+ {
+ double prod = fixed2float(csp[-1]) * *csp;
+
+ csp[-1] =
+ (prod > max_fixed ? max_fixed :
+ prod < min_fixed ? min_fixed : prod);
+ }
+ --csp;
+ break;
+ case ce2_sqrt:
+ if (*csp >= 0)
+ *csp = float2fixed(sqrt(fixed2float(*csp)));
+ break;
+ case ce2_dup:
+ csp[1] = *csp;
+ ++csp;
+ break;
+ case ce2_exch:
+ {
+ fixed top = *csp;
+
+ *csp = csp[-1], csp[-1] = top;
+ }
+ break;
+ case ce2_index:
+ *csp =
+ (*csp < 0 ? csp[-1] : csp[-1 - fixed2int_var(csp[-1])]);
+ break;
+ case ce2_roll:
+ {
+ int distance = fixed2int_var(*csp);
+ int count = fixed2int_var(csp[-1]);
+ cs_ptr bot;
+
+ csp -= 2;
+ if (count < 0 || count > csp + 1 - cstack)
+ return_error(gs_error_invalidfont);
+ if (count == 0)
+ break;
+ if (distance < 0)
+ distance = count - (-distance % count);
+ bot = csp + 1 - count;
+ while (--distance >= 0) {
+ fixed top = *csp;
+
+ memmove(bot + 1, bot,
+ (count - 1) * sizeof(fixed));
+ *bot = top;
+ }
+ }
+ break;
+ case ce2_hflex:
+ csp[6] = fixed_half; /* fd/100 */
+ csp[4] = *csp, csp[5] = 0; /* dx6, dy6 */
+ csp[2] = csp[-1], csp[3] = -csp[-5]; /* dx5, dy5 */
+ *csp = csp[-2], csp[1] = 0; /* dx4, dy4 */
+ csp[-2] = csp[-3], csp[-1] = 0; /* dx3, dy3 */
+ csp[-3] = csp[-4], csp[-4] = csp[-5]; /* dx2, dy2 */
+ csp[-5] = 0; /* dy1 */
+ csp += 6;
+ goto flex;
+ case ce2_flex:
+ *csp /= 100; /* fd/100 */
+flex: {
+ fixed x_join = csp[-12] + csp[-10] + csp[-8];
+ fixed y_join = csp[-11] + csp[-9] + csp[-7];
+ fixed x_end = x_join + csp[-6] + csp[-4] + csp[-2];
+ fixed y_end = y_join + csp[-5] + csp[-3] + csp[-1];
+ gs_point join, end;
+ double flex_depth;
+
+ if ((code =
+ gs_distance_transform(fixed2float(x_join),
+ fixed2float(y_join),
+ &ctm_only(pcis->pis),
+ &join)) < 0 ||
+ (code =
+ gs_distance_transform(fixed2float(x_end),
+ fixed2float(y_end),
+ &ctm_only(pcis->pis),
+ &end)) < 0
+ )
+ return code;
+ /*
+ * Use the X or Y distance depending on whether
+ * the curve is more horizontal or more
+ * vertical.
+ */
+ if (any_abs(end.y) > any_abs(end.x))
+ flex_depth = join.x;
+ else
+ flex_depth = join.y;
+ if (fabs(flex_depth) < fixed2float(*csp)) {
+ /* Do flex as line. */
+ accum_xy(x_end, y_end);
+ code = gx_path_add_line(sppath, ptx, pty);
+ } else {
+ /*
+ * Do flex as curve. We can't jump to rrc,
+ * because the flex operators don't clear
+ * the stack (!).
+ */
+ code = gs_op1_rrcurveto(&s,
+ csp[-12], csp[-11], csp[-10],
+ csp[-9], csp[-8], csp[-7]);
+ if (code < 0)
+ return code;
+ code = gs_op1_rrcurveto(&s,
+ csp[-6], csp[-5], csp[-4],
+ csp[-3], csp[-2], csp[-1]);
+ }
+ if (code < 0)
+ return code;
+ csp -= 13;
+ }
+ cnext;
+ case ce2_hflex1:
+ csp[4] = fixed_half; /* fd/100 */
+ csp[2] = *csp, csp[3] = 0; /* dx6, dy6 */
+ *csp = csp[-2], csp[1] = csp[-1]; /* dx5, dy5 */
+ csp[-2] = csp[-3], csp[-1] = 0; /* dx4, dy4 */
+ csp[-3] = 0; /* dy3 */
+ csp += 4;
+ goto flex;
+ case ce2_flex1:
+ {
+ fixed dx = csp[-10] + csp[-8] + csp[-6] + csp[-4] + csp[-2];
+ fixed dy = csp[-9] + csp[-7] + csp[-5] + csp[-3] + csp[-1];
+
+ if (any_abs(dx) > any_abs(dy))
+ csp[1] = -dy; /* d6 is dx6 */
+ else
+ csp[1] = *csp, *csp = -dx; /* d6 is dy6 */
+ }
+ csp[2] = fixed_half; /* fd/100 */
+ csp += 2;
+ goto flex;
+ }
+ break;
+
+ /* Fill up the dispatch up to 32. */
+
+ case_c2_undefs:
+ default: /* pacify compiler */
+ return_error(gs_error_invalidfont);
+ }
+ }
+}
+
+/* Register the interpreter. */
+void
+gs_gstype2_init(gs_memory_t * mem)
+{
+ gs_charstring_interpreter[2] = gs_type2_charstring_interpret;
+}
diff --git a/pstoraster/gstype42.c b/pstoraster/gstype42.c
new file mode 100644
index 000000000..e30946d5c
--- /dev/null
+++ b/pstoraster/gstype42.c
@@ -0,0 +1,481 @@
+/* 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$ */
+/* Type 42 (TrueType) font library routines */
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gsccode.h"
+#include "gsmatrix.h"
+#include "gxfixed.h" /* for gxpath.h */
+#include "gxpath.h"
+#include "gxfont.h"
+#include "gxfont42.h"
+#include "gxistate.h"
+
+/*
+ * This Type 42 / TrueType rasterizer is about as primitive as it can be
+ * and still produce useful output. Here are some things it doesn't handle:
+ * - left side bearings;
+ * and, of course, instructions (hints).
+ */
+
+/* Structure descriptor */
+public_st_gs_font_type42();
+
+/* Set up a pointer to a substring of the font data. */
+/* Free variables: pfont, string_proc. */
+#define access(base, length, vptr)\
+ BEGIN\
+ code = (*string_proc)(pfont, (ulong)(base), length, &vptr);\
+ if ( code < 0 ) return code;\
+ END
+
+/* Get 2- or 4-byte quantities from a table. */
+#define u8(p) ((uint)((p)[0]))
+#define s8(p) (int)((u8(p) ^ 0x80) - 0x80)
+#define u16(p) (((uint)((p)[0]) << 8) + (p)[1])
+#define s16(p) (int)((u16(p) ^ 0x8000) - 0x8000)
+#define u32(p) (((ulong)u16(p) << 16) + u16((p) + 2))
+#define s32(p) (long)((u32(p) ^ 0x80000000) - 0x80000000)
+
+/* Define the default implementation for getting the outline data for */
+/* a glyph, using indexToLocFormat and the loca and glyf tables. */
+/* Set pglyph->data = 0 if the glyph is empty. */
+private int
+default_get_outline(gs_font_type42 * pfont, uint glyph_index,
+ gs_const_string * pglyph)
+{
+ int (*string_proc) (P4(gs_font_type42 *, ulong, uint, const byte **)) =
+ pfont->data.string_proc;
+ const byte *ploca;
+ ulong glyph_start;
+ uint glyph_length;
+ int code;
+
+ /*
+ * We can't assume that consecutive loca entries are stored
+ * contiguously in memory: we have to access each entry
+ * individually.
+ */
+ if (pfont->data.indexToLocFormat) {
+ access(pfont->data.loca + glyph_index * 4, 4, ploca);
+ glyph_start = u32(ploca);
+ access(pfont->data.loca + glyph_index * 4 + 4, 4, ploca);
+ glyph_length = u32(ploca) - glyph_start;
+ } else {
+ access(pfont->data.loca + glyph_index * 2, 2, ploca);
+ glyph_start = (ulong) u16(ploca) << 1;
+ access(pfont->data.loca + glyph_index * 2 + 2, 2, ploca);
+ glyph_length = ((ulong) u16(ploca) << 1) - glyph_start;
+ }
+ pglyph->size = glyph_length;
+ if (glyph_length == 0)
+ pglyph->data = 0;
+ else
+ access(pfont->data.glyf + glyph_start, glyph_length, pglyph->data);
+ return 0;
+}
+
+/* Initialize the cached values in a Type 42 font. */
+/* Note that this initializes get_outline as well. */
+int
+gs_type42_font_init(gs_font_type42 * pfont)
+{
+ int (*string_proc) (P4(gs_font_type42 *, ulong, uint, const byte **)) =
+ pfont->data.string_proc;
+ const byte *OffsetTable;
+ uint numTables;
+ const byte *TableDirectory;
+ uint i;
+ int code;
+ byte head_box[8];
+
+ access(0, 12, OffsetTable);
+ {
+ static const byte version1_0[4] = {0, 1, 0, 0};
+ static const byte * const version_true = (const byte *)"true";
+
+ if (memcmp(OffsetTable, version1_0, 4) &&
+ memcmp(OffsetTable, version_true, 4))
+ return_error(gs_error_invalidfont);
+ }
+ numTables = u16(OffsetTable + 4);
+ access(12, numTables * 16, TableDirectory);
+ /* Clear optional entries. */
+ pfont->data.numLongMetrics = 0;
+ for (i = 0; i < numTables; ++i) {
+ const byte *tab = TableDirectory + i * 16;
+ ulong offset = u32(tab + 8);
+
+ if (!memcmp(tab, "glyf", 4))
+ pfont->data.glyf = offset;
+ else if (!memcmp(tab, "head", 4)) {
+ const byte *head;
+
+ access(offset, 54, head);
+ pfont->data.unitsPerEm = u16(head + 18);
+ memcpy(head_box, head + 36, 8);
+ pfont->data.indexToLocFormat = u16(head + 50);
+ } else if (!memcmp(tab, "hhea", 4)) {
+ const byte *hhea;
+
+ access(offset, 36, hhea);
+ pfont->data.numLongMetrics = u16(hhea + 34);
+ } else if (!memcmp(tab, "hmtx", 4))
+ pfont->data.hmtx = offset,
+ pfont->data.hmtx_length = (uint) u32(tab + 12);
+ else if (!memcmp(tab, "loca", 4))
+ pfont->data.loca = offset;
+ }
+ /*
+ * If the font doesn't have a valid FontBBox, compute one from the
+ * 'head' information. Since the Adobe PostScript driver sometimes
+ * outputs garbage FontBBox values, we use a "reasonableness" check
+ * here.
+ */
+ if (pfont->FontBBox.p.x >= pfont->FontBBox.q.x ||
+ pfont->FontBBox.p.y >= pfont->FontBBox.q.y ||
+ pfont->FontBBox.p.x < -0.5 || pfont->FontBBox.p.x > 0.5 ||
+ pfont->FontBBox.p.y < -0.5 || pfont->FontBBox.p.y > 0.5
+ ) {
+ float upem = pfont->data.unitsPerEm;
+
+ pfont->FontBBox.p.x = s16(head_box) / upem;
+ pfont->FontBBox.p.y = s16(head_box + 2) / upem;
+ pfont->FontBBox.q.x = s16(head_box + 4) / upem;
+ pfont->FontBBox.q.y = s16(head_box + 6) / upem;
+ }
+ pfont->data.get_outline = default_get_outline;
+ return 0;
+}
+
+/* Get the metrics of a glyph. */
+int
+gs_type42_get_metrics(gs_font_type42 * pfont, uint glyph_index,
+ float psbw[4])
+{
+ int (*string_proc) (P4(gs_font_type42 *, ulong, uint, const byte **)) =
+ pfont->data.string_proc;
+ float scale = pfont->data.unitsPerEm;
+ uint widthx;
+ int lsbx;
+ int code;
+
+ {
+ uint num_metrics = pfont->data.numLongMetrics;
+ const byte *hmetrics;
+
+ if (glyph_index < num_metrics) {
+ access(pfont->data.hmtx + glyph_index * 4, 4, hmetrics);
+ widthx = u16(hmetrics);
+ lsbx = s16(hmetrics + 2);
+ } else {
+ uint offset = pfont->data.hmtx + (num_metrics - 1) * 4;
+ const byte *lsb;
+
+ access(offset, 4, hmetrics);
+ widthx = u16(hmetrics);
+ offset += 4 + (glyph_index - num_metrics) * 2;
+ if (offset >= pfont->data.hmtx_length)
+ offset = pfont->data.hmtx_length - 2;
+ access(offset, 2, lsb);
+ lsbx = s16(lsb);
+ }
+ }
+ psbw[0] = lsbx / scale;
+ psbw[1] = 0;
+ psbw[2] = widthx / scale;
+ psbw[3] = 0;
+ return 0;
+}
+
+/* Define the bits in the glyph flags. */
+#define gf_OnCurve 1
+#define gf_xShort 2
+#define gf_yShort 4
+#define gf_Repeat 8
+#define gf_xPos 16 /* xShort */
+#define gf_xSame 16 /* !xShort */
+#define gf_yPos 32 /* yShort */
+#define gf_ySame 32 /* !yShort */
+
+/* Define the bits in the component glyph flags. */
+#define cg_argsAreWords 1
+#define cg_argsAreXYValues 2
+#define cg_haveScale 8
+#define cg_moreComponents 32
+#define cg_haveXYScale 64
+#define cg_have2x2 128
+
+/* Forward references */
+private int append_outline(P4(uint glyph_index, const gs_matrix_fixed * pmat,
+ gx_path * ppath, gs_font_type42 * pfont));
+
+/* Append a TrueType outline to a path. */
+/* Note that this does not append the final moveto for the width. */
+int
+gs_type42_append(uint glyph_index, gs_imager_state * pis,
+ gx_path * ppath, const gs_log2_scale_point * pscale, bool charpath_flag,
+ int paint_type, gs_font_type42 * pfont)
+{
+ float sbw[4];
+
+ gs_type42_get_metrics(pfont, glyph_index, sbw);
+ /*
+ * This is where we should do something about the l.s.b., but I
+ * can't figure out from the TrueType documentation what it should
+ * be.
+ */
+ return append_outline(glyph_index, &pis->ctm, ppath, pfont);
+}
+
+/* Append a simple glyph outline. */
+private int
+append_simple(const byte * glyph, const gs_matrix_fixed * pmat, gx_path * ppath,
+ gs_font_type42 * pfont)
+{
+ int numContours = s16(glyph);
+ const byte *pends = glyph + 10;
+ const byte *pinstr = pends + numContours * 2;
+ const byte *pflags;
+ uint npoints;
+ const byte *pxc, *pyc;
+ int code;
+
+ if (numContours == 0)
+ return 0;
+ /*
+ * It appears that the only way to find the X and Y coordinate
+ * tables is to parse the flags. If this is true, it is an
+ * incredible piece of bad design.
+ */
+ {
+ const byte *pf = pflags = pinstr + 2 + u16(pinstr);
+ uint xbytes = npoints = u16(pinstr - 2) + 1;
+ uint np = npoints;
+
+ while (np > 0) {
+ byte flags = *pf++;
+ uint reps = (flags & gf_Repeat ? *pf++ + 1 : 1);
+
+ if (!(flags & gf_xShort)) {
+ if (flags & gf_xSame)
+ xbytes -= reps;
+ else
+ xbytes += reps;
+ }
+ np -= reps;
+ }
+ pxc = pf;
+ pyc = pxc + xbytes;
+ }
+
+ /* Interpret the contours. */
+
+ {
+ uint i, np;
+ gs_fixed_point pt;
+ float scale = pfont->data.unitsPerEm;
+ uint reps = 0;
+ byte flags;
+
+ gs_point_transform2fixed(pmat, 0.0, 0.0, &pt);
+ for (i = 0, np = 0; i < numContours; ++i) {
+ bool move = true;
+ uint last_point = u16(pends + i * 2);
+ float dx, dy;
+ int off_curve = 0;
+ gs_fixed_point start;
+ gs_fixed_point cpoints[3];
+
+ for (; np <= last_point; --reps, ++np) {
+ gs_fixed_point dpt;
+
+ if (reps == 0) {
+ flags = *pflags++;
+ reps = (flags & gf_Repeat ? *pflags++ + 1 : 1);
+ }
+ if (flags & gf_xShort)
+ dx = (flags & gf_xPos ? *pxc++ : -(int)*pxc++) / scale;
+ else if (!(flags & gf_xSame))
+ dx = s16(pxc) / scale, pxc += 2;
+ else
+ dx = 0;
+ if (flags & gf_yShort)
+ dy = (flags & gf_yPos ? *pyc++ : -(int)*pyc++) / scale;
+ else if (!(flags & gf_ySame))
+ dy = s16(pyc) / scale, pyc += 2;
+ else
+ dy = 0;
+ code = gs_distance_transform2fixed(pmat, dx, dy, &dpt);
+ if (code < 0)
+ return code;
+ pt.x += dpt.x, pt.y += dpt.y;
+#define control1(xy) cpoints[1].xy
+#define control2(xy) cpoints[2].xy
+#define control3off(xy) ((cpoints[1].xy + pt.xy) / 2)
+#define control4off(xy) ((cpoints[0].xy + 2 * cpoints[1].xy) / 3)
+#define control5off(xy) ((2 * cpoints[1].xy + cpoints[2].xy) / 3)
+#define control6off(xy) ((2 * cpoints[1].xy + pt.xy) / 3)
+#define control7off(xy) ((2 * cpoints[1].xy + start.xy) / 3)
+ if (move) {
+ if_debug2('1', "[1t]start (%g,%g)\n",
+ fixed2float(pt.x), fixed2float(pt.y));
+ start = pt;
+ code = gx_path_add_point(ppath, pt.x, pt.y);
+ cpoints[0] = pt;
+ move = false;
+ } else if (flags & gf_OnCurve) {
+ if_debug2('1', "[1t]ON (%g,%g)\n",
+ fixed2float(pt.x), fixed2float(pt.y));
+ if (off_curve)
+ code = gx_path_add_curve(ppath, control4off(x),
+ control4off(y), control6off(x),
+ control6off(y), pt.x, pt.y);
+ else
+ code = gx_path_add_line(ppath, pt.x, pt.y);
+ cpoints[0] = pt;
+ off_curve = 0;
+ } else {
+ if_debug2('1', "[1t]...off (%g,%g)\n",
+ fixed2float(pt.x), fixed2float(pt.y));
+ switch (off_curve++) {
+ default: /* >= 1 */
+ control2(x) = control3off(x);
+ control2(y) = control3off(y);
+ code = gx_path_add_curve(ppath,
+ control4off(x), control4off(y),
+ control5off(x), control5off(y),
+ control2(x), control2(y));
+ cpoints[0] = cpoints[2];
+ off_curve = 1;
+ /* falls through */
+ case 0:
+ cpoints[1] = pt;
+ }
+ }
+ if (code < 0)
+ return code;
+ }
+ if (off_curve)
+ code = gx_path_add_curve(ppath, control4off(x), control4off(y),
+ control7off(x), control7off(y),
+ start.x, start.y);
+ code = gx_path_close_subpath(ppath);
+ if (code < 0)
+ return code;
+ }
+ }
+ return 0;
+}
+
+/* Append a glyph outline. */
+private int
+append_outline(uint glyph_index, const gs_matrix_fixed * pmat, gx_path * ppath,
+ gs_font_type42 * pfont)
+{
+ gs_const_string glyph_string;
+
+#define glyph glyph_string.data
+ int numContours;
+ int code;
+
+ code = (*pfont->data.get_outline) (pfont, glyph_index, &glyph_string);
+ if (code < 0)
+ return code;
+ if (glyph == 0 || glyph_string.size == 0) /* empty glyph */
+ return 0;
+ numContours = s16(glyph);
+ if (numContours >= 0)
+ return append_simple(glyph, pmat, ppath, pfont);
+ if (numContours != -1)
+ return_error(gs_error_rangecheck);
+ /* This is a component glyph. Things get messy. */
+ {
+ uint flags;
+ float scale = pfont->data.unitsPerEm;
+
+ glyph += 10;
+ do {
+ uint comp_index = u16(glyph + 2);
+ gs_matrix_fixed mat;
+ gs_matrix scale_mat;
+
+ flags = u16(glyph);
+ glyph += 4;
+ mat = *pmat;
+ if (flags & cg_argsAreXYValues) {
+ int arg1, arg2;
+ gs_fixed_point pt;
+
+ if (flags & cg_argsAreWords)
+ arg1 = s16(glyph), arg2 = s16(glyph + 2), glyph += 4;
+ else
+ arg1 = s8(glyph), arg2 = s8(glyph + 1), glyph += 2;
+ gs_point_transform2fixed(pmat, arg1 / scale,
+ arg2 / scale, &pt);
+/****** HACK: WE KNOW ABOUT FIXED MATRICES ******/
+ mat.tx = fixed2float(mat.tx_fixed = pt.x);
+ mat.ty = fixed2float(mat.ty_fixed = pt.y);
+ } else {
+/****** WE DON'T HANDLE POINT MATCHING YET ******/
+ glyph += (flags & cg_argsAreWords ? 4 : 2);
+ }
+#define s2_14(p) (s16(p) / 16384.0)
+ if (flags & cg_haveScale) {
+ scale_mat.xx = scale_mat.yy = s2_14(glyph);
+ scale_mat.xy = scale_mat.yx = 0;
+ glyph += 2;
+ } else if (flags & cg_haveXYScale) {
+ scale_mat.xx = s2_14(glyph);
+ scale_mat.yy = s2_14(glyph + 2);
+ scale_mat.xy = scale_mat.yx = 0;
+ glyph += 4;
+ } else if (flags & cg_have2x2) {
+ scale_mat.xx = s2_14(glyph);
+ scale_mat.xy = s2_14(glyph + 2);
+ scale_mat.yx = s2_14(glyph + 4);
+ scale_mat.yy = s2_14(glyph + 6);
+ glyph += 8;
+ } else
+ goto no_scale;
+#undef s2_14
+ scale_mat.tx = 0;
+ scale_mat.ty = 0;
+ /* The scale doesn't affect mat.t{x,y}, so we don't */
+ /* need to update the fixed components. */
+ gs_matrix_multiply(&scale_mat, (const gs_matrix *)&mat,
+ (gs_matrix *) & mat);
+ no_scale:code = append_outline(comp_index, &mat, ppath, pfont);
+ if (code < 0)
+ return code;
+ }
+ while (flags & cg_moreComponents);
+ }
+ return 0;
+#undef glyph
+}
diff --git a/pstoraster/gstypes.h b/pstoraster/gstypes.h
new file mode 100644
index 000000000..8adcb1773
--- /dev/null
+++ b/pstoraster/gstypes.h
@@ -0,0 +1,86 @@
+/* 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$ */
+/* Miscellaneous common types for Ghostscript library */
+
+#ifndef gstypes_INCLUDED
+# define gstypes_INCLUDED
+
+/*
+ * Define a type used internally for unique IDs of various kinds
+ * (primarily, but not exclusively, character and halftone bitmaps).
+ * These IDs bear no relation to any other ID space; we generate them all
+ * ourselves.
+ */
+typedef ulong gs_id;
+
+#define gs_no_id 0L
+
+/*
+ * Define a sensible representation of a string, as opposed to
+ * the C char * type (which can't store arbitrary data, represent
+ * substrings, or perform concatenation without destroying aliases).
+ */
+typedef struct gs_string_s {
+ byte *data;
+ uint size;
+} gs_string;
+typedef struct gs_const_string_s {
+ const byte *data;
+ uint size;
+} gs_const_string;
+
+/*
+ * Define types for Cartesian points.
+ */
+typedef struct gs_point_s {
+ double x, y;
+} gs_point;
+typedef struct gs_int_point_s {
+ int x, y;
+} gs_int_point;
+
+/*
+ * Define a scale for oversampling. Clients don't actually use this,
+ * but this seemed like the handiest place for it.
+ */
+typedef struct gs_log2_scale_point_s {
+ int x, y;
+} gs_log2_scale_point;
+
+/*
+ * Define types for rectangles in the Cartesian plane.
+ * Note that rectangles are half-open, i.e.: their width is
+ * q.x-p.x and their height is q.y-p.y; they include the points
+ * (x,y) such that p.x<=x<q.x and p.y<=y<q.y.
+ */
+typedef struct gs_rect_s {
+ gs_point p, q; /* origin point, corner point */
+} gs_rect;
+typedef struct gs_int_rect_s {
+ gs_int_point p, q;
+} gs_int_rect;
+
+#endif /* gstypes_INCLUDED */
diff --git a/pstoraster/gsuid.h b/pstoraster/gsuid.h
new file mode 100644
index 000000000..8c6ceb5f4
--- /dev/null
+++ b/pstoraster/gsuid.h
@@ -0,0 +1,78 @@
+/* Copyright (C) 1992, 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$ */
+/* Unique id definitions for Ghostscript */
+
+#ifndef gsuid_INCLUDED
+# define gsuid_INCLUDED
+
+/* A unique id (uid) may be either a UniqueID or an XUID. */
+/* (XUIDs are a Level 2 feature.) */
+#ifndef gs_uid_DEFINED
+# define gs_uid_DEFINED
+typedef struct gs_uid_s gs_uid;
+
+#endif
+struct gs_uid_s {
+ /* id >= 0 is a UniqueID, xvalues is 0. */
+ /* id < 0 is an XUID, size of xvalues is -id. */
+ long id;
+ long *xvalues;
+};
+
+/*
+ * A UniqueID of no_UniqueID is an indication that there is no uid.
+ * Since we sometimes use gs_ids as UniqueIDs, we want to choose as large
+ * a (positive) value as possible for no_UniqueID.
+ */
+#define no_UniqueID max_long
+#define uid_is_valid(puid)\
+ ((puid)->id != no_UniqueID)
+#define uid_set_invalid(puid)\
+ ((puid)->id = no_UniqueID, (puid)->xvalues = 0)
+#define uid_is_UniqueID(puid)\
+ (((puid)->id & ~0xffffff) == 0)
+#define uid_is_XUID(puid)\
+ ((puid)->id < 0)
+
+/* Initialize a uid. */
+#define uid_set_UniqueID(puid, idv)\
+ ((puid)->id = idv, (puid)->xvalues = 0)
+#define uid_set_XUID(puid, pvalues, siz)\
+ ((puid)->id = -(long)(siz), (puid)->xvalues = pvalues)
+
+/* Get the size and the data of an XUID. */
+#define uid_XUID_size(puid) ((uint)(-(puid)->id))
+#define uid_XUID_values(puid) ((puid)->xvalues)
+
+/* Compare two uids for equality. */
+/* This could be a macro, but the Zortech compiler compiles it wrong. */
+bool uid_equal(P2(const gs_uid *, const gs_uid *)); /* in gsutil.c */
+
+/* Free the XUID array of a uid if necessary. */
+#define uid_free(puid, mem, cname)\
+ gs_free_object(mem, (puid)->xvalues, cname)
+
+#endif /* gsuid_INCLUDED */
diff --git a/pstoraster/gsutil.c b/pstoraster/gsutil.c
new file mode 100644
index 000000000..899ab1369
--- /dev/null
+++ b/pstoraster/gsutil.c
@@ -0,0 +1,285 @@
+/* Copyright (C) 1992, 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$ */
+/* Utilities for Ghostscript library */
+#include "string_.h"
+#include "memory_.h"
+#include "gstypes.h"
+#include "gconfigv.h" /* for USE_ASM */
+#include "gsmemory.h" /* for init procedure */
+#include "gsrect.h" /* for prototypes */
+#include "gsuid.h"
+#include "gsutil.h" /* for prototypes */
+
+/* ------ Unique IDs ------ */
+
+/* Generate a block of unique IDs. */
+static ulong gs_next_id;
+
+void
+gs_gsutil_init(gs_memory_t *mem)
+{
+ gs_next_id = 1;
+}
+
+ulong
+gs_next_ids(uint count)
+{
+ ulong id = gs_next_id;
+
+ gs_next_id += count;
+ return id;
+}
+
+/* ------ Memory utilities ------ */
+
+/* Transpose an 8 x 8 block of bits. line_size is the raster of */
+/* the input data. dist is the distance between output bytes. */
+/* This routine may be supplanted by assembly code. */
+#if !USE_ASM
+
+void
+memflip8x8(const byte * inp, int line_size, byte * outp, int dist)
+{
+ register uint ae, bf, cg, dh;
+
+ {
+ const byte *ptr4 = inp + (line_size << 2);
+
+ ae = ((uint) * inp << 8) + *ptr4;
+ inp += line_size, ptr4 += line_size;
+ bf = ((uint) * inp << 8) + *ptr4;
+ inp += line_size, ptr4 += line_size;
+ cg = ((uint) * inp << 8) + *ptr4;
+ inp += line_size, ptr4 += line_size;
+ dh = ((uint) * inp << 8) + *ptr4;
+ }
+
+ /* Check for all 8 bytes being the same. */
+ /* This is especially worth doing for the case where all are zero. */
+ if (ae == bf && ae == cg && ae == dh && (ae >> 8) == (ae & 0xff)) {
+ if (ae == 0)
+ goto store;
+ *outp = -((ae >> 7) & 1);
+ outp += dist;
+ *outp = -((ae >> 6) & 1);
+ outp += dist;
+ *outp = -((ae >> 5) & 1);
+ outp += dist;
+ *outp = -((ae >> 4) & 1);
+ outp += dist;
+ *outp = -((ae >> 3) & 1);
+ outp += dist;
+ *outp = -((ae >> 2) & 1);
+ outp += dist;
+ *outp = -((ae >> 1) & 1);
+ outp += dist;
+ *outp = -(ae & 1);
+ return;
+ } {
+ register uint temp;
+
+/* Transpose a block of bits between registers. */
+#define transpose(r,s,mask,shift)\
+ r ^= (temp = ((s >> shift) ^ r) & mask);\
+ s ^= temp << shift
+
+/* Transpose blocks of 4 x 4 */
+#define transpose4(r) transpose(r,r,0x00f0,4)
+ transpose4(ae);
+ transpose4(bf);
+ transpose4(cg);
+ transpose4(dh);
+
+/* Transpose blocks of 2 x 2 */
+ transpose(ae, cg, 0x3333, 2);
+ transpose(bf, dh, 0x3333, 2);
+
+/* Transpose blocks of 1 x 1 */
+ transpose(ae, bf, 0x5555, 1);
+ transpose(cg, dh, 0x5555, 1);
+
+ }
+
+ store:*outp = ae >> 8;
+ outp += dist;
+ *outp = bf >> 8;
+ outp += dist;
+ *outp = cg >> 8;
+ outp += dist;
+ *outp = dh >> 8;
+ outp += dist;
+ *outp = (byte) ae;
+ outp += dist;
+ *outp = (byte) bf;
+ outp += dist;
+ *outp = (byte) cg;
+ outp += dist;
+ *outp = (byte) dh;
+}
+
+#endif /* !USE_ASM */
+
+/* ------ String utilities ------ */
+
+/* Compare two strings, returning -1 if the first is less, */
+/* 0 if they are equal, and 1 if first is greater. */
+/* We can't use memcmp, because we always use unsigned characters. */
+int
+bytes_compare(const byte * s1, uint len1, const byte * s2, uint len2)
+{
+ register uint len = len1;
+
+ if (len2 < len)
+ len = len2;
+ {
+ register const byte *p1 = s1;
+ register const byte *p2 = s2;
+
+ while (len--)
+ if (*p1++ != *p2++)
+ return (p1[-1] < p2[-1] ? -1 : 1);
+ }
+ /* Now check for differing lengths */
+ return (len1 == len2 ? 0 : len1 < len2 ? -1 : 1);
+}
+
+/* Test whether a string matches a pattern with wildcards. */
+/* '*' = any substring, '?' = any character, '\' quotes next character. */
+private const string_match_params smp_default =
+{'*', '?', '\\', false};
+
+bool
+string_match(const byte * str, uint len, const byte * pstr, uint plen,
+ register const string_match_params * psmp)
+{
+ const byte *pback = 0;
+ const byte *spback = 0; /* initialized only to pacify gcc */
+ const byte *p = pstr, *pend = pstr + plen;
+ const byte *sp = str, *spend = str + len;
+
+ if (psmp == 0)
+ psmp = &smp_default;
+ again:while (p < pend) {
+ register byte ch = *p;
+
+ if (ch == psmp->any_substring) {
+ pback = ++p, spback = sp;
+ continue;
+ } else if (ch == psmp->any_char) {
+ if (sp == spend)
+ return false; /* str too short */
+ p++, sp++;
+ continue;
+ } else if (ch == psmp->quote_next) {
+ if (++p == pend)
+ return true; /* bad pattern */
+ ch = *p;
+ }
+ if (sp == spend)
+ return false; /* str too short */
+ if (*sp == ch ||
+ (psmp->ignore_case && (*sp ^ ch) == 0x20 &&
+ (ch &= ~0x20) >= 0x41 && ch <= 0x5a)
+ )
+ p++, sp++;
+ else if (pback == 0)
+ return false; /* no * to back up to */
+ else {
+ sp = ++spback;
+ p = pback;
+ }
+ }
+ if (sp < spend) { /* We got a match, but there are chars left over. */
+ /* If we can back up, back up to the only place that */
+ /* could produce a complete match, otherwise fail. */
+ if (pback == 0)
+ return false;
+ p = pback;
+ pback = 0;
+ sp = spend - (pend - p);
+ goto again;
+ }
+ return true;
+}
+
+/* ------ UID utilities ------ */
+
+/* Compare two UIDs for equality. */
+/* We know that at least one of them is valid. */
+bool
+uid_equal(register const gs_uid * puid1, register const gs_uid * puid2)
+{
+ if (puid1->id != puid2->id)
+ return false;
+ if (puid1->id >= 0)
+ return true; /* UniqueID */
+ return
+ !memcmp((const char *)puid1->xvalues,
+ (const char *)puid2->xvalues,
+ (uint) - (puid1->id) * sizeof(long));
+}
+
+/* ------ Rectangle utilities ------ */
+
+/*
+ * Calculate the difference of two rectangles, a list of up to 4 rectangles.
+ * Return the number of rectangles in the list, and set the first rectangle
+ * to the intersection.
+ */
+int
+int_rect_difference(gs_int_rect * outer, const gs_int_rect * inner,
+ gs_int_rect * diffs /*[4] */ )
+{
+ int x0 = outer->p.x, y0 = outer->p.y;
+ int x1 = outer->q.x, y1 = outer->q.y;
+ int count = 0;
+
+ if (y0 < inner->p.y) {
+ diffs[0].p.x = x0, diffs[0].p.y = y0;
+ diffs[0].q.x = x1, diffs[0].q.y = min(y1, inner->p.y);
+ outer->p.y = y0 = diffs[0].q.y;
+ ++count;
+ }
+ if (y1 > inner->q.y) {
+ diffs[count].p.x = x0, diffs[count].p.y = max(y0, inner->q.y);
+ diffs[count].q.x = x1, diffs[count].q.y = y1;
+ outer->q.y = y1 = diffs[count].p.y;
+ ++count;
+ }
+ if (x0 < inner->p.x) {
+ diffs[0].p.x = x0, diffs[0].p.y = y0;
+ diffs[0].q.x = min(x1, inner->p.x), diffs[0].q.y = y1;
+ outer->p.x = x0 = diffs[count].q.x;
+ ++count;
+ }
+ if (x1 > inner->q.x) {
+ diffs[count].p.x = max(x0, inner->q.x), diffs[count].p.y = y0;
+ diffs[count].q.x = x1, diffs[count].q.y = y1;
+ outer->q.x = x1 = diffs[count].p.x;
+ ++count;
+ }
+ return count;
+}
diff --git a/pstoraster/gsutil.h b/pstoraster/gsutil.h
new file mode 100644
index 000000000..756be1f7f
--- /dev/null
+++ b/pstoraster/gsutil.h
@@ -0,0 +1,67 @@
+/* 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$ */
+/* Prototypes for procedures in gsutil.c */
+
+#ifndef gsutil_INCLUDED
+# define gsutil_INCLUDED
+
+/* ------ Unique IDs ------ */
+
+/* Generate a block of unique IDs. */
+gs_id gs_next_ids(P1(uint count));
+
+/* ------ Memory utilities ------ */
+
+/* Transpose an 8 x 8 block of bits. */
+/* line_size is the raster of the input data; */
+/* dist is the distance between output bytes. */
+/* Dot matrix printers need this. */
+/* Note that with a negative dist value, */
+/* this will rotate an 8 x 8 block 90 degrees counter-clockwise. */
+void memflip8x8(P4(const byte * inp, int line_size, byte * outp, int dist));
+
+/* ------ String utilities ------ */
+
+/* Compare two strings, returning -1 if the first is less, */
+/* 0 if they are equal, and 1 if first is greater. */
+/* We can't use memcmp, because we always use unsigned characters. */
+int bytes_compare(P4(const byte * str1, uint len1,
+ const byte * str2, uint len2));
+
+/* Test whether a string matches a pattern with wildcards. */
+/* If psmp == NULL, use standard parameters: '*' = any substring, */
+/* '?' = any character, '\\' quotes next character, don't ignore case. */
+typedef struct string_match_params_s {
+ int any_substring; /* '*' */
+ int any_char; /* '?' */
+ int quote_next; /* '\\' */
+ bool ignore_case;
+} string_match_params;
+bool string_match(P5(const byte * str, uint len,
+ const byte * pstr, uint plen,
+ const string_match_params * psmp));
+
+#endif /* gsutil_INCLUDED */
diff --git a/pstoraster/gsxfont.h b/pstoraster/gsxfont.h
new file mode 100644
index 000000000..1968a4f98
--- /dev/null
+++ b/pstoraster/gsxfont.h
@@ -0,0 +1,45 @@
+/* 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$ */
+/* External font client definitions for Ghostscript library */
+
+#ifndef gsxfont_INCLUDED
+# define gsxfont_INCLUDED
+
+/* Define a character glyph identifier. This is opaque, probably an index */
+/* into the font. Glyph identifiers are font-specific. */
+typedef ulong gx_xglyph;
+
+#define gx_no_xglyph ((gx_xglyph)~0L)
+
+/* Structure for xfont procedures. */
+struct gx_xfont_procs_s;
+typedef struct gx_xfont_procs_s gx_xfont_procs;
+
+/* A generic xfont. */
+struct gx_xfont_s;
+typedef struct gx_xfont_s gx_xfont;
+
+#endif /* gsxfont_INCLUDED */
diff --git a/pstoraster/gx.h b/pstoraster/gx.h
new file mode 100644
index 000000000..42ca7efb9
--- /dev/null
+++ b/pstoraster/gx.h
@@ -0,0 +1,52 @@
+/* Copyright (C) 1989, 1991, 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 internal definitions for Ghostscript library */
+
+#ifndef gx_INCLUDED
+# define gx_INCLUDED
+
+#include "stdio_.h" /* includes std.h */
+#include "gserror.h"
+#include "gsio.h"
+#include "gstypes.h"
+#include "gsmemory.h"
+#include "gdebug.h"
+
+/* Define opaque types for the graphics state. */
+/* This is used so pervasively that we define it here, */
+/* rather than at a higher level as perhaps would be more appropriate. */
+#ifndef gs_imager_state_DEFINED
+# define gs_imager_state_DEFINED
+typedef struct gs_imager_state_s gs_imager_state;
+
+#endif
+#ifndef gs_state_DEFINED
+# define gs_state_DEFINED
+typedef struct gs_state_s gs_state;
+
+#endif
+
+#endif /* gx_INCLUDED */
diff --git a/pstoraster/gxacpath.c b/pstoraster/gxacpath.c
new file mode 100644
index 000000000..9f0b55c81
--- /dev/null
+++ b/pstoraster/gxacpath.c
@@ -0,0 +1,479 @@
+/* Copyright (C) 1993, 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$ */
+/* Accumulator for clipping paths */
+#include "gx.h"
+#include "gserrors.h"
+#include "gsrop.h"
+#include "gsstruct.h"
+#include "gsutil.h"
+#include "gsdcolor.h"
+#include "gxdevice.h"
+#include "gxfixed.h"
+#include "gzpath.h"
+#include "gxpaint.h"
+#include "gzcpath.h"
+#include "gzacpath.h"
+
+/* Imported procedures */
+extern gx_device *gs_currentdevice(P1(const gs_state *));
+extern float gs_currentflat(P1(const gs_state *));
+extern bool clip_list_validate(P1(const gx_clip_list *));
+
+/* Device procedures */
+private dev_proc_open_device(accum_open);
+private dev_proc_close_device(accum_close);
+private dev_proc_fill_rectangle(accum_fill_rectangle);
+
+/* The device descriptor */
+/* Many of these procedures won't be called; they are set to NULL. */
+private const gx_device_cpath_accum gs_cpath_accum_device =
+{std_device_std_body(gx_device_cpath_accum, 0, "clip list accumulator",
+ 0, 0, 1, 1),
+ {accum_open,
+ NULL,
+ NULL,
+ NULL,
+ accum_close,
+ NULL,
+ NULL,
+ accum_fill_rectangle,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ gx_default_fill_path,
+ gx_default_stroke_path,
+ NULL,
+ 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,
+ NULL,
+ NULL,
+ gx_get_largest_clipping_box,
+ gx_default_begin_typed_image,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ gx_default_text_begin
+ }
+};
+
+/* Start accumulating a clipping path. */
+void
+gx_cpath_accum_begin(gx_device_cpath_accum * padev, gs_memory_t * mem)
+{
+ gx_device_init((gx_device *) padev,
+ (const gx_device *) & gs_cpath_accum_device,
+ NULL /* allocated on stack */ , true);
+ padev->list_memory = mem;
+ (*dev_proc(padev, open_device)) ((gx_device *) padev);
+}
+
+void
+gx_cpath_accum_set_cbox(gx_device_cpath_accum * padev,
+ const gs_fixed_rect * pbox)
+{
+ padev->clip_box.p.x = fixed2int_var(pbox->p.x);
+ padev->clip_box.p.y = fixed2int_var(pbox->p.y);
+ padev->clip_box.q.x = fixed2int_var_ceiling(pbox->q.x);
+ padev->clip_box.q.y = fixed2int_var_ceiling(pbox->q.y);
+}
+
+/* Finish accumulating a clipping path. */
+int
+gx_cpath_accum_end(const gx_device_cpath_accum * padev, gx_clip_path * pcpath)
+{
+ int code = (*dev_proc(padev, close_device)) ((gx_device *) padev);
+ /* Make an entire clipping path so we can use cpath_assign. */
+ gx_clip_path apath;
+
+ if (code < 0)
+ return code;
+ gx_cpath_init_local(&apath, padev->list_memory);
+ apath.rect_list->list = padev->list;
+ apath.path.bbox.p.x = int2fixed(padev->bbox.p.x);
+ apath.path.bbox.p.y = int2fixed(padev->bbox.p.y);
+ apath.path.bbox.q.x = int2fixed(padev->bbox.q.x);
+ apath.path.bbox.q.y = int2fixed(padev->bbox.q.y);
+ /* Using the setbbox flag here is slightly bogus, */
+ /* but it's as good a way as any to indicate that */
+ /* the bbox is accurate. */
+ apath.path.bbox_set = 1;
+ /* Note that the result of the intersection might be */
+ /* a single rectangle. This will cause clip_path_is_rect.. */
+ /* to return true. This, in turn, requires that */
+ /* we set apath.inner_box correctly. */
+ if (clip_list_is_rectangle(&padev->list))
+ apath.inner_box = apath.path.bbox;
+ else {
+ /* The quick check must fail. */
+ apath.inner_box.p.x = apath.inner_box.p.y = 0;
+ apath.inner_box.q.x = apath.inner_box.q.y = 0;
+ }
+ gx_cpath_set_outer_box(&apath);
+ apath.path_valid = false;
+ apath.id = gs_next_ids(1); /* path changed => change id */
+ gx_cpath_assign_free(pcpath, &apath);
+ return 0;
+}
+
+/* Discard an accumulator in case of error. */
+void
+gx_cpath_accum_discard(gx_device_cpath_accum * padev)
+{
+ gx_clip_list_free(&padev->list, padev->list_memory);
+}
+
+/* Intersect two clipping paths using an accumulator. */
+int
+gx_cpath_intersect_slow(gs_state * pgs, gx_clip_path * pcpath, gx_path * ppath,
+ int rule)
+{
+ bool outside = gx_cpath_is_outside(pcpath);
+ gs_logical_operation_t save_lop = gs_current_logical_op(pgs);
+ gx_device_cpath_accum adev;
+ gx_device_color devc;
+ gx_fill_params params;
+ int code;
+
+ gx_cpath_accum_begin(&adev, pcpath->path.memory);
+ color_set_pure(&devc, 0); /* arbitrary, but not transparent */
+ gs_set_logical_op(pgs, lop_default);
+ params.rule = rule;
+ params.adjust.x = params.adjust.y = fixed_half;
+ params.flatness = gs_currentflat(pgs);
+ params.fill_zero_width = true;
+ code = gx_fill_path_only(ppath, (gx_device *) & adev,
+ (const gs_imager_state *)pgs,
+ &params, &devc, pcpath);
+ if (code < 0 || (code = gx_cpath_accum_end(&adev, pcpath)) < 0)
+ gx_cpath_accum_discard(&adev);
+ gx_cpath_set_outside(pcpath, outside);
+ gs_set_logical_op(pgs, save_lop);
+ return code;
+}
+
+/* ------ Device implementation ------ */
+
+/* Initialize the accumulation device. */
+private int
+accum_open(register gx_device * dev)
+{
+ gx_device_cpath_accum * const adev = (gx_device_cpath_accum *)dev;
+
+ gx_clip_list_init(&adev->list);
+ adev->bbox.p.x = adev->bbox.p.y = max_int;
+ adev->bbox.q.x = adev->bbox.q.y = min_int;
+ adev->clip_box.p.x = adev->clip_box.p.y = min_int;
+ adev->clip_box.q.x = adev->clip_box.q.y = max_int;
+ return 0;
+}
+
+/* Close the accumulation device. */
+private int
+accum_close(gx_device * dev)
+{
+#ifdef DEBUG
+ gx_device_cpath_accum * const adev = (gx_device_cpath_accum *)dev;
+
+ if (gs_debug_c('q')) {
+ gx_clip_rect *rp =
+ (adev->list.count <= 1 ? &adev->list.single : adev->list.head);
+
+ dlprintf4("[q]list at 0x%lx, count=%d, head=0x%lx, tail=0x%lx:\n",
+ (ulong) & adev->list, adev->list.count,
+ (ulong) adev->list.head, (ulong) adev->list.tail);
+ while (rp != 0) {
+ clip_rect_print('q', " ", rp);
+ rp = rp->next;
+ }
+ }
+ if (!clip_list_validate(&adev->list)) {
+ lprintf1("[q]Bad clip list 0x%lx!\n", (ulong) & adev->list);
+ return_error(gs_error_Fatal);
+ }
+#endif
+ return 0;
+}
+
+/* Accumulate one rectangle. */
+#undef adev
+/* Allocate a rectangle to be added to the list. */
+static const gx_clip_rect clip_head_rect =
+{0, 0, min_int, min_int, min_int, min_int};
+static const gx_clip_rect clip_tail_rect =
+{0, 0, max_int, max_int, max_int, max_int};
+private gx_clip_rect *
+accum_alloc_rect(gx_device_cpath_accum * adev)
+{
+ gs_memory_t *mem = adev->list_memory;
+ gx_clip_rect *ar = gs_alloc_struct(mem, gx_clip_rect, &st_clip_rect,
+ "accum_alloc_rect");
+
+ if (ar == 0)
+ return 0;
+ if (adev->list.count == 2) { /* We're switching from a single rectangle to a list. */
+ /* Allocate the head and tail entries. */
+ gx_clip_rect *head = ar;
+ gx_clip_rect *tail =
+ gs_alloc_struct(mem, gx_clip_rect, &st_clip_rect,
+ "accum_alloc_rect(tail)");
+ gx_clip_rect *single =
+ gs_alloc_struct(mem, gx_clip_rect, &st_clip_rect,
+ "accum_alloc_rect(single)");
+
+ ar = gs_alloc_struct(mem, gx_clip_rect, &st_clip_rect,
+ "accum_alloc_rect(head)");
+ if (tail == 0 || single == 0 || ar == 0) {
+ gs_free_object(mem, ar, "accum_alloc_rect");
+ gs_free_object(mem, single, "accum_alloc_rect(single)");
+ gs_free_object(mem, tail, "accum_alloc_rect(tail)");
+ gs_free_object(mem, head, "accum_alloc_rect(head)");
+ return 0;
+ }
+ *head = clip_head_rect;
+ head->next = single;
+ *single = adev->list.single;
+ single->prev = head;
+ single->next = tail;
+ *tail = clip_tail_rect;
+ tail->prev = single;
+ adev->list.head = head;
+ adev->list.tail = tail;
+ }
+ return ar;
+}
+#define accum_alloc(s, ar, px, py, qx, qy)\
+ if ( ++(adev->list.count) == 1 )\
+ ar = &adev->list.single;\
+ else if ( (ar = accum_alloc_rect(adev)) == 0 )\
+ return_error(gs_error_VMerror);\
+ accum_set(s, ar, px, py, qx, qy)
+#define accum_set(s, ar, px, py, qx, qy)\
+ (ar)->xmin = px, (ar)->ymin = py, (ar)->xmax = qx, (ar)->ymax = qy;\
+ clip_rect_print('Q', s, ar)
+/* Link or unlink a rectangle in the list. */
+#define accum_add_last(ar)\
+ accum_add_before(ar, adev->list.tail)
+#define accum_add_after(ar, rprev)\
+ ar->prev = (rprev), (ar->next = (rprev)->next)->prev = ar,\
+ (rprev)->next = ar
+#define accum_add_before(ar, rnext)\
+ (ar->prev = (rnext)->prev)->next = ar, ar->next = (rnext),\
+ (rnext)->prev = ar
+#define accum_remove(ar)\
+ ar->next->prev = ar->prev, ar->prev->next = ar->next
+/* Free a rectangle that was removed from the list. */
+#define accum_free(s, ar)\
+ if ( --(adev->list.count) )\
+ { clip_rect_print('Q', s, ar);\
+ gs_free_object(adev->list_memory, ar, "accum_rect");\
+ }
+/*
+ * Add a rectangle to the list. It would be wonderful if rectangles
+ * were always disjoint and always presented in the correct order,
+ * but they aren't: the fill loop works by trapezoids, not by scan lines,
+ * and may produce slightly overlapping rectangles because of "fattening".
+ * All we can count on is that they are approximately disjoint and
+ * approximately in order.
+ *
+ * Because of the way the fill loop handles a path that is just a single
+ * rectangle, we take special care to merge Y-adjacent rectangles when
+ * this is possible.
+ */
+private int
+accum_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
+ gx_color_index color)
+{
+ gx_device_cpath_accum * const adev = (gx_device_cpath_accum *)dev;
+ int xe = x + w, ye = y + h;
+ gx_clip_rect *nr;
+ gx_clip_rect *ar;
+ register gx_clip_rect *rptr;
+ int ymin, ymax;
+
+ /* Clip the rectangle being added. */
+ if (y < adev->clip_box.p.y)
+ y = adev->clip_box.p.y;
+ if (ye > adev->clip_box.q.y)
+ ye = adev->clip_box.q.y;
+ if (y >= ye)
+ return 0;
+ if (x < adev->clip_box.p.x)
+ x = adev->clip_box.p.x;
+ if (xe > adev->clip_box.q.x)
+ xe = adev->clip_box.q.x;
+ if (x >= xe)
+ return 0;
+
+ /* Update the bounding box. */
+ if (x < adev->bbox.p.x)
+ adev->bbox.p.x = x;
+ if (y < adev->bbox.p.y)
+ adev->bbox.p.y = y;
+ if (xe > adev->bbox.q.x)
+ adev->bbox.q.x = xe;
+ if (ye > adev->bbox.q.y)
+ adev->bbox.q.y = ye;
+
+ top:if (adev->list.count == 0) { /* very first rectangle */
+ adev->list.count = 1;
+ accum_set("single", &adev->list.single, x, y, xe, ye);
+ return 0;
+ }
+ if (adev->list.count == 1) /* check for Y merging */
+
+ {
+ rptr = &adev->list.single;
+ if (x == rptr->xmin && xe == rptr->xmax &&
+ y <= rptr->ymax && y >= rptr->ymin
+ ) {
+ if (ye > rptr->ymax)
+ rptr->ymax = ye;
+ return 0;
+ }
+ }
+ accum_alloc("accum", nr, x, y, xe, ye);
+ rptr = adev->list.tail->prev;
+ if (y >= rptr->ymax ||
+ (y == rptr->ymin && ye == rptr->ymax && x >= rptr->xmax)
+ ) {
+ accum_add_last(nr);
+ return 0;
+ }
+ /* Work backwards till we find the insertion point. */
+ while (ye <= rptr->ymin)
+ rptr = rptr->prev;
+ ymin = rptr->ymin;
+ ymax = rptr->ymax;
+ if (ye > ymax) {
+ if (y >= ymax) { /* Insert between two bands. */
+ accum_add_after(nr, rptr);
+ return 0;
+ }
+ /* Split off the top part of the new rectangle. */
+ accum_alloc("a.top", ar, x, ymax, xe, ye);
+ accum_add_after(ar, rptr);
+ ye = nr->ymax = ymax;
+ clip_rect_print('Q', " ymax", nr);
+ }
+ /* Here we know ymin < ye <= ymax; */
+ /* rptr points to the last node with this value of ymin/ymax. */
+ /* If necessary, split off the part of the existing band */
+ /* that is above the new band. */
+ if (ye < ymax) {
+ gx_clip_rect *rsplit = rptr;
+
+ while (rsplit->ymax == ymax) {
+ accum_alloc("s.top", ar, rsplit->xmin, ye, rsplit->xmax, ymax);
+ accum_add_after(ar, rptr);
+ rsplit->ymax = ye;
+ rsplit = rsplit->prev;
+ }
+ ymax = ye;
+ }
+ /* Now ye = ymax. If necessary, split off the part of the */
+ /* existing band that is below the new band. */
+ if (y > ymin) {
+ gx_clip_rect *rbot = rptr, *rsplit;
+
+ while (rbot->prev->ymin == ymin)
+ rbot = rbot->prev;
+ for (rsplit = rbot;;) {
+ accum_alloc("s.bot", ar, rsplit->xmin, ymin, rsplit->xmax, y);
+ accum_add_before(ar, rbot);
+ rsplit->ymin = y;
+ if (rsplit == rptr)
+ break;
+ rsplit = rsplit->next;
+ }
+ ymin = y;
+ }
+ /* Now y <= ymin as well. (y < ymin is possible.) */
+ nr->ymin = ymin;
+ /* Search for the X insertion point. */
+ for (; rptr->ymin == ymin; rptr = rptr->prev) {
+ if (xe < rptr->xmin)
+ continue; /* still too far to right */
+ if (x > rptr->xmax)
+ break; /* disjoint */
+ /* The new rectangle overlaps an existing one. Merge them. */
+ if (xe > rptr->xmax) {
+ rptr->xmax = nr->xmax; /* might be > xe if */
+ /* we already did a merge */
+ clip_rect_print('Q', "widen", rptr);
+ }
+ accum_free("free", nr);
+ if (x >= rptr->xmin)
+ goto out;
+ /* Might overlap other rectangles to the left. */
+ rptr->xmin = x;
+ nr = rptr;
+ accum_remove(rptr);
+ clip_rect_print('Q', "merge", nr);
+ }
+ accum_add_after(nr, rptr);
+ out: /* Check whether there are only 0 or 1 rectangles left. */
+ if (adev->list.count <= 1) { /* We're switching from a list to at most 1 rectangle. */
+ /* Free the head and tail entries. */
+ gs_memory_t *mem = adev->list_memory;
+ gx_clip_rect *single = adev->list.head->next;
+
+ if (single != adev->list.tail) {
+ adev->list.single = *single;
+ gs_free_object(mem, single, "accum_free_rect(single)");
+ adev->list.single.next = adev->list.single.prev = 0;
+ }
+ gs_free_object(mem, adev->list.tail, "accum_free_rect(tail)");
+ gs_free_object(mem, adev->list.head, "accum_free_rect(head)");
+ adev->list.head = 0;
+ adev->list.tail = 0;
+ }
+ /* Check whether there is still more of the new band to process. */
+ if (y < ymin) { /* Continue with the bottom part of the new rectangle. */
+ clip_rect_print('Q', " ymin", nr);
+ ye = ymin;
+ goto top;
+ }
+ return 0;
+}
diff --git a/pstoraster/gxalloc.h b/pstoraster/gxalloc.h
new file mode 100644
index 000000000..0a3e6c7c0
--- /dev/null
+++ b/pstoraster/gxalloc.h
@@ -0,0 +1,403 @@
+/* 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$ */
+/* Requires gsmemory.h, gsstruct.h */
+
+#ifndef gxalloc_INCLUDED
+# define gxalloc_INCLUDED
+
+#ifndef gs_ref_memory_DEFINED
+# define gs_ref_memory_DEFINED
+typedef struct gs_ref_memory_s gs_ref_memory_t;
+
+#endif
+
+#include "gsalloc.h"
+#include "gxobj.h"
+
+/* ================ Chunks ================ */
+
+/*
+ * We obtain memory from the operating system in `chunks'. A chunk
+ * may hold only a single large object (or string), or it may hold
+ * many objects (allocated from the bottom up, always aligned)
+ * and strings (allocated from the top down, not aligned).
+ */
+
+/*
+ * Refs are allocated in the bottom-up section, along with struct objects.
+ * In order to keep the overhead for refs small, we make consecutive
+ * blocks of refs into a single allocator object of type st_refs.
+ * To do this, we remember the start of the current ref object (if any),
+ * and the end of the last block of allocated refs. As long as
+ * the latter is equal to the top of the allocated area, we can add
+ * more refs to the current object; otherwise, we have to start a new one.
+ * We assume that sizeof(ref) % obj_align_mod == 0; this means that if we
+ * ever have to pad a block of refs, we never add as much as one entire ref.
+ */
+
+/*
+ * When we do a save, we create a new 'inner' chunk out of the remaining
+ * space in the currently active chunk. Inner chunks must not be freed
+ * by a restore.
+ *
+ * The garbage collector implements relocation for refs by scanning
+ * forward to a free object. Because of this, every ref object must end
+ * with a dummy ref that can hold the relocation for the last block.
+ * In order to put a reasonable upper bound on the scanning time, we
+ * limit the length of the objects that contain runs of refs.
+ */
+#define max_size_st_refs (50 * sizeof(ref))
+
+/*
+ * Strings carry some additional overhead for use by the GC.
+ * At the top of the chunk is a table of relocation values for
+ * 16N-character blocks of strings, where N is sizeof(uint).
+ * This table is aligned, by adding padding above it if necessary.
+ * Just below it is a mark table for the strings. This table is also aligned,
+ * to improve GC performance. The actual string data start below
+ * the mark table. These tables are not needed for a chunk that holds
+ * a single large (non-string) object, but they are needed for all other
+ * chunks, including chunks created to hold a single large string.
+ */
+
+/*
+ * Define the unit of data manipulation for marking strings.
+ */
+typedef uint string_mark_unit;
+
+#define log2_sizeof_string_mark_unit arch_log2_sizeof_int
+/*
+ * Define the quantum of relocation for strings, which determines
+ * the quantum for reserving space. This value must be a power of 2,
+ * must be at least sizeof(string_mark_unit) * 8, and (because of the
+ * unrolled loops in igcstr.c) currently must be equal to either 32 or 64.
+ */
+typedef uint string_reloc_offset;
+
+#define log2_string_data_quantum (arch_log2_sizeof_int + 4)
+#define string_data_quantum (1 << log2_string_data_quantum)
+/*
+ * Define the quantum for reserving string space, including data,
+ * marks, and relocation.
+ */
+#define string_space_quantum\
+ (string_data_quantum + (string_data_quantum / 8) +\
+ sizeof(string_reloc_offset))
+/*
+ * Compute the amount of space needed for a chunk that holds only
+ * a string of a given size.
+ */
+#define string_chunk_space(nbytes)\
+ (((nbytes) + (string_data_quantum - 1)) / string_data_quantum *\
+ string_space_quantum)
+/*
+ * Compute the number of string space quanta in a given amount of storage.
+ */
+#define string_space_quanta(spacebytes)\
+ ((spacebytes) / string_space_quantum)
+/*
+ * Compute the size of string marks for a given number of quanta.
+ */
+#define string_quanta_mark_size(nquanta)\
+ ((nquanta) * (string_data_quantum / 8))
+
+/*
+ * To allow the garbage collector to combine chunks, we store in the
+ * head of each chunk the address to which its contents will be moved.
+ */
+ /*typedef struct chunk_head_s chunk_head_t; *//* in gxobj.h */
+
+/* Structure for a chunk. */
+typedef struct chunk_s chunk_t;
+struct chunk_s {
+ chunk_head_t *chead; /* chunk head, bottom of chunk; */
+ /* csbase is an alias for chead */
+#define csbase(cp) ((byte *)(cp)->chead)
+ /* Note that allocation takes place both from the bottom up */
+ /* (aligned objects) and from the top down (strings). */
+ byte *cbase; /* bottom of chunk data area */
+ byte *cbot; /* bottom of free area */
+ /* (top of aligned objects) */
+ obj_header_t *rcur; /* current refs object, 0 if none */
+ byte *rtop; /* top of rcur */
+ byte *ctop; /* top of free area */
+ /* (bottom of strings) */
+ byte *climit; /* top of strings */
+ byte *cend; /* top of chunk */
+ chunk_t *cprev; /* chain chunks together, */
+ chunk_t *cnext; /* sorted by address */
+ chunk_t *outer; /* the chunk of which this is */
+ /* an inner chunk, if any */
+ uint inner_count; /* number of chunks of which this is */
+ /* the outer chunk, if any */
+ bool has_refs; /* true if any refs in chunk */
+ /*
+ * Free lists for single bytes in blocks of 1-3 bytes,
+ * one per 256 bytes in [csbase..climit). The chain
+ * pointer is a (1-byte) self-relative offset,
+ * terminated by a 0; obviously, the chain is sorted by
+ * increasing address. The free list pointers themselves
+ * are offsets relative to csbase.
+ *
+ * Note that these lists overlay the GC relocation table.
+ */
+ ushort *sfree1;
+ /*
+ * Free list for blocks of >= 4 bytes. Each block begins
+ * with a 2-byte size and a 2-byte next block pointer,
+ * both big-endian. This too is sorted in increasing address order.
+ */
+ ushort sfree;
+ /* The remaining members are for the GC. */
+ byte *odest; /* destination for objects */
+ byte *smark; /* mark bits for strings */
+ uint smark_size;
+ byte *sbase; /* base for computing smark offsets */
+ string_reloc_offset *sreloc; /* relocation for string blocks */
+ byte *sdest; /* destination for (top of) strings */
+ byte *rescan_bot; /* bottom of rescanning range if */
+ /* the GC mark stack overflows */
+ byte *rescan_top; /* top of range ditto */
+};
+
+/* The chunk descriptor is exported only for isave.c. */
+extern_st(st_chunk);
+#define public_st_chunk() /* in ialloc.c */\
+ gs_public_st_ptrs2(st_chunk, chunk_t, "chunk_t",\
+ chunk_enum_ptrs, chunk_reloc_ptrs, cprev, cnext)
+
+/*
+ * Macros for scanning a chunk linearly, with the following schema:
+ * SCAN_CHUNK_OBJECTS(cp) << declares pre, size >>
+ * << code for all objects -- size not set yet >>
+ * DO_LARGE
+ * << code for large objects >>
+ * DO_SMALL
+ * << code for small objects >>
+ * END_OBJECTS_SCAN
+ * If large and small objects are treated alike, one can use DO_ALL instead
+ * of DO_LARGE and DO_SMALL.
+ */
+#define SCAN_CHUNK_OBJECTS(cp)\
+ { obj_header_t *pre = (obj_header_t *)((cp)->cbase);\
+ obj_header_t *end = (obj_header_t *)((cp)->cbot);\
+ ulong size; /* long because of large objects */\
+ for ( ; pre < end;\
+ pre = (obj_header_t *)((char *)pre + obj_size_round(size))\
+ )\
+ {
+#define DO_LARGE\
+ if ( pre->o_large )\
+ { size = pre_obj_large_size(pre);\
+ {
+#define DO_SMALL\
+ }\
+ } else\
+ { size = pre_obj_small_size(pre);\
+ {
+#define DO_ALL\
+ { size = pre_obj_contents_size(pre);\
+ {
+#ifdef DEBUG
+# define END_OBJECTS_SCAN\
+ }\
+ }\
+ }\
+ if ( pre != end )\
+ { lprintf2("Chunk parsing error, 0x%lx != 0x%lx\n",\
+ (ulong)pre, (ulong)end);\
+ gs_exit(1);\
+ }\
+ }
+#else
+# define END_OBJECTS_SCAN\
+ }\
+ }\
+ }\
+ }
+#endif
+
+/* Initialize a chunk. */
+/* This is exported for save/restore. */
+void alloc_init_chunk(P5(chunk_t *, byte *, byte *, bool, chunk_t *));
+
+/* Initialize the string freelists in a chunk. */
+void alloc_init_free_strings(P1(chunk_t *));
+
+/* Find the chunk for a pointer. */
+/* Note that ptr_is_within_chunk returns true even if the pointer */
+/* is in an inner chunk of the chunk being tested. */
+#define ptr_is_within_chunk(ptr, cp)\
+ ptr_between((const byte *)(ptr), (cp)->cbase, (cp)->cend)
+#define ptr_is_in_inner_chunk(ptr, cp)\
+ ((cp)->inner_count != 0 &&\
+ ptr_between((const byte *)(ptr), (cp)->cbot, (cp)->ctop))
+#define ptr_is_in_chunk(ptr, cp)\
+ (ptr_is_within_chunk(ptr, cp) && !ptr_is_in_inner_chunk(ptr, cp))
+typedef struct chunk_locator_s {
+ const gs_ref_memory_t *memory; /* for head & tail of chain */
+ chunk_t *cp; /* one-element cache */
+} chunk_locator_t;
+bool chunk_locate_ptr(P2(const void *, chunk_locator_t *));
+
+#define chunk_locate(ptr, clp)\
+ (((clp)->cp != 0 && ptr_is_in_chunk(ptr, (clp)->cp)) ||\
+ chunk_locate_ptr(ptr, clp))
+
+/* Close up the current chunk. */
+/* This is exported for save/restore and for the GC. */
+void alloc_close_chunk(P1(gs_ref_memory_t * mem));
+
+/* Reopen the current chunk after a GC. */
+void alloc_open_chunk(P1(gs_ref_memory_t * mem));
+
+/* Insert or remove a chunk in the address-ordered chain. */
+/* These are exported for the GC. */
+void alloc_link_chunk(P2(chunk_t *, gs_ref_memory_t *));
+void alloc_unlink_chunk(P2(chunk_t *, gs_ref_memory_t *));
+
+/* Free a chunk. This is exported for save/restore and for the GC. */
+void alloc_free_chunk(P2(chunk_t *, gs_ref_memory_t *));
+
+/* Print a chunk debugging message. */
+/* Unfortunately, the ANSI C preprocessor doesn't allow us to */
+/* define the list of variables being printed as a macro. */
+#define dprintf_chunk_format\
+ "%s 0x%lx (0x%lx..0x%lx, 0x%lx..0x%lx..0x%lx)\n"
+#define dprintf_chunk(msg, cp)\
+ dprintf7(dprintf_chunk_format,\
+ msg, (ulong)(cp), (ulong)(cp)->cbase, (ulong)(cp)->cbot,\
+ (ulong)(cp)->ctop, (ulong)(cp)->climit, (ulong)(cp)->cend)
+#define if_debug_chunk(c, msg, cp)\
+ if_debug7(c, dprintf_chunk_format,\
+ msg, (ulong)(cp), (ulong)(cp)->cbase, (ulong)(cp)->cbot,\
+ (ulong)(cp)->ctop, (ulong)(cp)->climit, (ulong)(cp)->cend)
+
+/* ================ Allocator state ================ */
+
+/* Structures for save/restore (not defined here). */
+struct alloc_save_s;
+struct alloc_change_s;
+
+/* Stream structure, only needed for the streams member of the state. */
+#ifndef stream_DEFINED
+# define stream_DEFINED
+typedef struct stream_s stream;
+
+#endif
+
+/* Define the number of freelists. The index in the freelist array */
+/* is the ceiling of the size of the object contents (i.e., not including */
+/* the header) divided by obj_align_mod. */
+#define max_freelist_size 800 /* big enough for gstate & contents */
+#define num_freelists\
+ ((max_freelist_size + obj_align_mod - 1) / obj_align_mod + 1)
+
+/* Define the memory manager subclass for this allocator. */
+struct gs_ref_memory_s {
+ /* The following are set at initialization time. */
+ gs_memory_common;
+ gs_raw_memory_t *parent; /* for allocating chunks */
+ uint chunk_size;
+ uint large_size; /* min size to give large object */
+ /* its own chunk: must be */
+ /* 1 mod obj_align_mod */
+ gs_ref_memory_t *global; /* global VM for this allocator */
+ /* (may point to itself) */
+ uint space; /* a_local, a_global, a_system */
+ /* Callers can change the following dynamically */
+ /* (through a procedural interface). */
+ gs_memory_gc_status_t gc_status;
+ /* The following are updated dynamically. */
+ bool is_controlled; /* if true, this allocator doesn't manage */
+ /* its own chunks */
+ ulong limit; /* signal a VMerror when total */
+ /* allocated exceeds this */
+ chunk_t *cfirst; /* head of chunk list */
+ chunk_t *clast; /* tail of chunk list */
+ chunk_t cc; /* current chunk */
+ chunk_t *pcc; /* where to store cc */
+ chunk_locator_t cfreed; /* chunk where last object freed */
+ ulong allocated; /* total size of all chunks */
+ /* allocated at this save level */
+ long inherited; /* chunks allocated at outer save */
+ /* levels that should be counted */
+ /* towards the GC threshold */
+ /* (may be negative, but allocated + */
+ /* inherited >= 0 always) */
+ ulong gc_allocated; /* value of (allocated + */
+ /* previous_status.allocated) after last GC */
+ struct lost_ { /* space freed and 'lost' */
+ ulong objects;
+ ulong refs;
+ ulong strings;
+ } lost;
+ /*
+ * The following are for the interpreter's convenience: the
+ * library initializes them to 0 and then never touches them.
+ */
+ stream *streams;
+ /* Garbage collector information */
+ gs_gc_root_t *roots; /* roots for GC */
+ /* Sharing / saved state information */
+ int num_contexts; /* # of contexts sharing this VM */
+ struct alloc_change_s *changes;
+ struct alloc_save_s *saved;
+ struct alloc_save_s *reloc_saved; /* for GC */
+ gs_memory_status_t previous_status; /* total allocated & used */
+ /* in outer save levels */
+ /* We put the freelists last to keep the */
+ /* scalar offsets small. */
+ obj_header_t *freelists[num_freelists];
+};
+
+/* The descriptor for gs_ref_memory_t is exported only for */
+/* the alloc_save_t subclass; otherwise, it should be private. */
+extern_st(st_ref_memory);
+#define public_st_ref_memory() /* in gsalloc.c */\
+ gs_public_st_composite(st_ref_memory, gs_ref_memory_t,\
+ "gs_ref_memory", ref_memory_enum_ptrs, ref_memory_reloc_ptrs)
+#define st_ref_memory_max_ptrs 3 /* streams, changes, saved */
+
+/* Define the procedures for the standard allocator. */
+/* We export this for subclasses. */
+extern const gs_memory_procs_t gs_ref_memory_procs;
+
+/*
+ * Scan the chunks of an allocator:
+ * SCAN_MEM_CHUNKS(mem, cp)
+ * << code to process chunk cp >>
+ * END_CHUNKS_SCAN
+ */
+#define SCAN_MEM_CHUNKS(mem, cp)\
+ { chunk_t *cp = (mem)->cfirst;\
+ for ( ; cp != 0; cp = cp->cnext )\
+ {
+#define END_CHUNKS_SCAN\
+ }\
+ }
+
+#endif /* gxalloc_INCLUDED */
diff --git a/pstoraster/gxalpha.h b/pstoraster/gxalpha.h
new file mode 100644
index 000000000..c5d444e31
--- /dev/null
+++ b/pstoraster/gxalpha.h
@@ -0,0 +1,74 @@
+/* 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$ */
+/* Internal machinery for alpha channel support */
+
+#ifndef gxalpha_INCLUDED
+# define gxalpha_INCLUDED
+
+/*
+ * As discussed in the classic Porter & Duff paper on compositing,
+ * supporting alpha channel properly involves premultiplying color values
+ * that are associated with non-unity alpha values. After considerable
+ * thrashing around trying to read between the lines of the spotty NeXT
+ * documentation, we've concluded that the correct approach is to
+ * premultiply towards whatever the color value 0 represents in the device's
+ * native color space: black for DeviceGray and DeviceRGB (displays and some
+ * file formats), white for DeviceCMYK (color printers), with a special hack
+ * for monochrome printers TBD. This makes things very easy internally, at
+ * the expense of some inconsistency at the boundaries.
+ *
+ * For the record, the only places apparently affected by this decision
+ * are the following:
+ * - alphaimage, if it doesn't assume premultiplication (see below)
+ * - readimage
+ * - The cmap_rgb_alpha_ procedures in gxcmap.c
+ * - [color]image, if they are supposed to use currentalpha (see below)
+ * - The compositing code in gsalphac.c
+ *
+ * The NeXT documentation also is very unclear as to how readimage,
+ * alphaimage, and [color]image are supposed to work. Our current
+ * interpretation is the following:
+ *
+ * - readimage reads pixels exactly as the device stores them
+ * (converted into DeviceGray or DeviceRGB space if the device
+ * uses a palette). Pixels with non-unity alpha come out
+ * premultiplied, however the device stores them.
+ *
+ * - alphaimage assumes the pixels are premultiplied as appropriate
+ * for the relevant color space. This makes alphaimage and
+ * readimage complementary, i.e., the output of readimage is
+ * suitable as the input of alphaimage.
+ *
+ * - [color]image disregard currentalpha, and treat all input as
+ * opaque (alpha = 1). */
+/*
+ * Just in case we ever change our minds about the direction of
+ * premultiplication, uncommenting the following preprocessor definition is
+ * supposed to produce premultiplication towards white.
+ */
+/*#define PREMULTIPLY_TOWARDS_WHITE */
+
+#endif /* gxalpha_INCLUDED */
diff --git a/pstoraster/gxarith.h b/pstoraster/gxarith.h
new file mode 100644
index 000000000..69a6eace6
--- /dev/null
+++ b/pstoraster/gxarith.h
@@ -0,0 +1,84 @@
+/* Copyright (C) 1990, 1993, 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.
+*/
+
+#ifndef gxarith_INCLUDED
+# define gxarith_INCLUDED
+
+/*$Id$ */
+/* Arithmetic macros for Ghostscript library */
+
+/* Define an in-line abs function, good for any signed numeric type. */
+#define any_abs(x) ((x) < 0 ? -(x) : (x))
+
+/* Compute M modulo N. Requires N > 0; guarantees 0 <= imod(M,N) < N, */
+/* regardless of the whims of the % operator for negative operands. */
+int imod(P2(int m, int n));
+
+/* Compute the GCD of two integers. */
+int igcd(P2(int x, int y));
+
+/* Test whether an integral value fits in a given number of bits. */
+/* This works for all integral types. */
+#define fits_in_bits(i, n)\
+ (sizeof(i) <= sizeof(int) ? fits_in_ubits((i) + (1 << ((n) - 1)), (n) + 1) :\
+ fits_in_ubits((i) + (1L << ((n) - 1)), (n) + 1))
+#define fits_in_ubits(i, n) (((i) >> (n)) == 0)
+
+/*
+ * There are some floating point operations that can be implemented
+ * very efficiently on machines that have no floating point hardware,
+ * assuming IEEE representation and no range overflows.
+ * We define straightforward versions of them here, and alternate versions
+ * for no-floating-point machines in gxfarith.h.
+ */
+/* Test floating point values against constants. */
+#define is_fzero(f) ((f) == 0.0)
+#define is_fzero2(f1,f2) ((f1) == 0.0 && (f2) == 0.0)
+#define is_fneg(f) ((f) < 0.0)
+#define is_fge1(f) ((f) >= 1.0)
+/* Test whether a floating point value fits in a given number of bits. */
+#define f_fits_in_bits(f, n)\
+ ((f) >= -2.0 * (1L << ((n) - 2)) && (f) < 2.0 * (1L << ((n) - 2)))
+#define f_fits_in_ubits(f, n)\
+ ((f) >= 0 && (f) < 4.0 * (1L << ((n) - 2)))
+
+/*
+ * Define a macro for computing log2(n), where n=1,2,4,...,128.
+ * Because some compilers limit the total size of a statement,
+ * this macro must only mention n once. The macro should really
+ * only be used with compile-time constant arguments, but it will work
+ * even if n is an expression computed at run-time.
+ */
+#define small_exact_log2(n)\
+ ((uint)(05637042010L >> ((((n) % 11) - 1) * 3)) & 7)
+
+/*
+ * The following doesn't give rise to a macro, but is used in several
+ * places in Ghostscript. We observe that if M = 2^n-1 and V < M^2,
+ * then the quotient Q and remainder R can be computed as:
+ * Q = V / M = (V + (V >> n) + 1) >> n;
+ * R = V % M = (V + (V / M)) & M = V - (Q << n) + Q.
+ */
+
+#endif /* gxarith_INCLUDED */
diff --git a/pstoraster/gxband.h b/pstoraster/gxband.h
new file mode 100644
index 000000000..3fc9c7322
--- /dev/null
+++ b/pstoraster/gxband.h
@@ -0,0 +1,70 @@
+/* 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$ */
+/* Band-processing parameters for Ghostscript */
+
+#ifndef gxband_INCLUDED
+# define gxband_INCLUDED
+
+#include "gxclio.h"
+
+/*
+ * Define the parameters controlling banding.
+ */
+typedef struct gx_band_params_s {
+ int BandWidth; /* (optional) band width in pixels */
+ int BandHeight; /* (optional) */
+ long BandBufferSpace; /* (optional) */
+} gx_band_params;
+
+#define band_params_initial_values 0, 0, 0
+
+/*
+ * Define the information for a saved page.
+ */
+typedef struct gx_band_page_info_s {
+ char cfname[gp_file_name_sizeof]; /* command file name */
+ clist_file_ptr cfile; /* command file, normally 0 */
+ char bfname[gp_file_name_sizeof]; /* block file name */
+ clist_file_ptr bfile; /* block file, normally 0 */
+ uint tile_cache_size; /* size of tile cache */
+ long bfile_end_pos; /* ftell at end of bfile */
+ gx_band_params band_params; /* parameters used when writing band list */
+ /* (actual values, no 0s) */
+} gx_band_page_info;
+
+/*
+ * By convention, the structure member containing the above is called
+ * page_info. Define shorthand accessors for its members.
+ */
+#define page_cfile page_info.cfile
+#define page_cfname page_info.cfname
+#define page_bfile page_info.bfile
+#define page_bfname page_info.bfname
+#define page_tile_cache_size page_info.tile_cache_size
+#define page_bfile_end_pos page_info.bfile_end_pos
+#define page_band_height page_info.band_params.BandHeight
+
+#endif /* ndef gxband_INCLUDED */
diff --git a/pstoraster/gxbcache.c b/pstoraster/gxbcache.c
new file mode 100644
index 000000000..851548348
--- /dev/null
+++ b/pstoraster/gxbcache.c
@@ -0,0 +1,153 @@
+/* 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$ */
+/* Bitmap cache implementation */
+#include "memory_.h"
+#include "gx.h"
+#include "gsmdebug.h"
+#include "gxbcache.h"
+
+/* ------ Entire cache ------ */
+
+/* Initialize a cache. The caller must allocate and initialize */
+/* the first chunk. */
+void
+gx_bits_cache_init(gx_bits_cache * bc, gx_bits_cache_chunk * bck)
+{
+ bck->next = bck;
+ bc->chunks = bck;
+ bc->cnext = 0;
+ bc->bsize = 0;
+ bc->csize = 0;
+}
+
+/* ------ Chunks ------ */
+
+/* Initialize a chunk. The caller must allocate it and its data. */
+void
+gx_bits_cache_chunk_init(gx_bits_cache_chunk * bck, byte * data, uint size)
+{
+ bck->next = 0;
+ bck->data = data;
+ bck->size = size;
+ bck->allocated = 0;
+ if (data != 0) {
+ gx_cached_bits_head *cbh = (gx_cached_bits_head *) data;
+
+ cbh->size = size;
+ cb_head_set_free(cbh);
+ }
+}
+
+/* ------ Individual entries ------ */
+
+/* Attempt to allocate an entry. If successful, set *pcbh and return 0. */
+/* If there isn't enough room, set *pcbh to an entry requiring freeing, */
+/* or to 0 if we are at the end of the chunk, and return -1. */
+int
+gx_bits_cache_alloc(gx_bits_cache * bc, ulong lsize, gx_cached_bits_head ** pcbh)
+{
+#define ssize ((uint)lsize)
+ ulong lsize1 = lsize + sizeof(gx_cached_bits_head);
+
+#define ssize1 ((uint)lsize1)
+ uint cnext = bc->cnext;
+ gx_bits_cache_chunk *bck = bc->chunks;
+ uint left = bck->size - cnext;
+ gx_cached_bits_head *cbh;
+ gx_cached_bits_head *cbh_next;
+ uint fsize = 0;
+
+ if (lsize1 > bck->size - cnext && lsize != left) { /* Not enough room to allocate in this chunk. */
+ *pcbh = 0;
+ return -1;
+ }
+ /* Look for and/or free enough space. */
+ cbh = cbh_next = (gx_cached_bits_head *) (bck->data + cnext);
+ while (fsize < ssize1 && fsize != ssize) {
+ if (!cb_head_is_free(cbh_next)) { /* Ask the caller to free the entry. */
+ if (fsize)
+ cbh->size = fsize;
+ *pcbh = cbh_next;
+ return -1;
+ }
+ fsize += cbh_next->size;
+ if_debug2('K', "[K]merging free bits 0x%lx(%u)\n",
+ (ulong) cbh_next, cbh_next->size);
+ cbh_next = (gx_cached_bits_head *) ((byte *) cbh + fsize);
+ }
+ if (fsize > ssize) { /* fsize >= ssize1 */
+ cbh_next = (gx_cached_bits_head *) ((byte *) cbh + ssize);
+ cbh_next->size = fsize - ssize;
+ cb_head_set_free(cbh_next);
+ if_debug2('K', "[K]shortening bits 0x%lx by %u (initial)\n",
+ (ulong) cbh, fsize - ssize);
+ }
+ gs_alloc_fill(cbh, gs_alloc_fill_block, ssize);
+ cbh->size = ssize;
+ bc->bsize += ssize;
+ bc->csize++;
+ bc->cnext += ssize;
+ bck->allocated += ssize;
+ *pcbh = cbh;
+ return 0;
+#undef ssize
+#undef ssize1
+}
+
+/* Shorten an entry by a given amount. */
+void
+gx_bits_cache_shorten(gx_bits_cache * bc, gx_cached_bits_head * cbh,
+ uint diff, gx_bits_cache_chunk * bck)
+{
+ gx_cached_bits_head *next;
+
+ if ((byte *) cbh + cbh->size == bck->data + bc->cnext &&
+ bck == bc->chunks
+ )
+ bc->cnext -= diff;
+ bc->bsize -= diff;
+ bck->allocated -= diff;
+ cbh->size -= diff;
+ next = (gx_cached_bits_head *) ((byte *) cbh + cbh->size);
+ cb_head_set_free(next);
+ next->size = diff;
+}
+
+/* Free an entry. The caller is responsible for removing the entry */
+/* from any other structures (like a hash table). */
+void
+gx_bits_cache_free(gx_bits_cache * bc, gx_cached_bits_head * cbh,
+ gx_bits_cache_chunk * bck)
+{
+ uint size = cbh->size;
+
+ bc->csize--;
+ bc->bsize -= size;
+ bck->allocated -= size;
+ gs_alloc_fill(cbh, gs_alloc_fill_deleted, size);
+ cbh->size = size; /* gs_alloc_fill may have overwritten */
+ cb_head_set_free(cbh);
+}
diff --git a/pstoraster/gxbcache.h b/pstoraster/gxbcache.h
new file mode 100644
index 000000000..bbaea0c73
--- /dev/null
+++ b/pstoraster/gxbcache.h
@@ -0,0 +1,130 @@
+/* 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$ */
+/* Bitmap cache structures */
+
+#ifndef gxbcache_INCLUDED
+# define gxbcache_INCLUDED
+
+#include "gxbitmap.h"
+
+/*
+ * These structures are superclasses for a cache in which the 'value' is
+ * a bitmap. The structures defined here don't take any position about
+ * the nature of the 'key'.
+ */
+
+/* ---------------- Bitmap cache entry ---------------- */
+
+/*
+ * The cache may contain both used and free blocks.
+ * All blocks have a common header; free blocks have ONLY the header.
+ */
+typedef struct gx_cached_bits_head_s {
+ uint size; /* total block size in bytes */
+ uint depth; /* bits per pixel, free block if 0 */
+} gx_cached_bits_head;
+
+#define cb_head_is_free(cbh) ((cbh)->depth == 0)
+#define cb_head_set_free(cbh) ((cbh)->depth = 0)
+#define gx_cached_bits_common\
+ gx_cached_bits_head head; /* must be first */\
+ /* The rest of the entry is an abbreviation of */\
+ /* gx_strip_bitmap, sans data. */\
+ ushort width, height, shift;\
+ ushort raster;\
+ gx_bitmap_id id
+/* Define aliases for head members. */
+#define cb_depth head.depth
+/* Define aliases for common members formerly in the head. */
+#define cb_raster raster
+typedef struct gx_cached_bits_s {
+ gx_cached_bits_common;
+} gx_cached_bits;
+
+#define cb_is_free(cb) cb_head_is_free(&(cb)->head)
+/*
+ * Define the alignment of the gx_cached_bits structure. We must ensure
+ * that an immediately following bitmap will be properly aligned.
+ */
+#define align_cached_bits_mod\
+ (max(align_bitmap_mod, max(arch_align_ptr_mod, arch_align_long_mod)))
+
+/*
+ * We may allocate a bitmap cache in chunks, so as not to tie up memory
+ * prematurely if it isn't needed (or something else needs it more).
+ * Thus there is a structure for managing an entire cache, and another
+ * structure for managing each chunk.
+ */
+typedef struct gx_bits_cache_chunk_s gx_bits_cache_chunk;
+struct gx_bits_cache_chunk_s {
+ gx_bits_cache_chunk *next;
+ byte *data; /* gx_cached_bits_head * */
+ uint size;
+ uint allocated; /* amount of allocated data */
+};
+
+/* ---------------- Bitmap cache ---------------- */
+
+#define gx_bits_cache_common\
+ gx_bits_cache_chunk *chunks; /* current chunk in circular list */\
+ uint cnext; /* rover for allocating entries */\
+ /* in current chunk */\
+ uint bsize; /* total # of bytes for all entries */\
+ uint csize /* # of entries */
+typedef struct gx_bits_cache_s {
+ gx_bits_cache_common;
+} gx_bits_cache;
+
+/* ---------------- Procedural interface ---------------- */
+
+/* ------ Entire cache ------ */
+
+/* Initialize a cache. The caller must allocate and initialize */
+/* the first chunk. */
+void gx_bits_cache_init(P2(gx_bits_cache *, gx_bits_cache_chunk *));
+
+/* ------ Chunks ------ */
+
+/* Initialize a chunk. The caller must allocate it and its data. */
+void gx_bits_cache_chunk_init(P3(gx_bits_cache_chunk *, byte *, uint));
+
+/* ------ Individual entries ------ */
+
+/* Attempt to allocate an entry. If successful, set *pcbh and return 0. */
+/* If there isn't enough room, set *pcbh to an entry requiring freeing, */
+/* or to 0 if we are at the end of the chunk, and return -1. */
+int gx_bits_cache_alloc(P3(gx_bits_cache *, ulong, gx_cached_bits_head **));
+
+/* Shorten an entry by a given amount. */
+void gx_bits_cache_shorten(P4(gx_bits_cache *, gx_cached_bits_head *,
+ uint, gx_bits_cache_chunk *));
+
+/* Free an entry. The caller is responsible for removing the entry */
+/* from any other structures (like a hash table). */
+void gx_bits_cache_free(P3(gx_bits_cache *, gx_cached_bits_head *,
+ gx_bits_cache_chunk *));
+
+#endif /* gxbcache_INCLUDED */
diff --git a/pstoraster/gxbitfmt.h b/pstoraster/gxbitfmt.h
new file mode 100644
index 000000000..7c6039b6e
--- /dev/null
+++ b/pstoraster/gxbitfmt.h
@@ -0,0 +1,195 @@
+/* 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$ */
+/* Definitions for bitmap storage formats */
+
+#ifndef gxbitfmt_INCLUDED
+# define gxbitfmt_INCLUDED
+
+/*
+ * Several operations, such as the get_bits_rectangle driver procedure, can
+ * take and/or produce data in a flexible variety of formats; the ability to
+ * describe how bitmap data is stored is useful in other contexts as well.
+ * We define bitmap storage formats using a bit mask: this allows a
+ * procedure to ask for, or offer to provide, data in more than one format.
+ */
+
+typedef ulong gx_bitmap_format_t;
+
+ /*
+ * Define the supported color space alternatives.
+ */
+
+#define GB_COLORS_NATIVE (1L<<0) /* native representation (DevicePixel) */
+#define GB_COLORS_GRAY (1L<<1) /* DeviceGray */
+#define GB_COLORS_RGB (1L<<2) /* DeviceRGB */
+#define GB_COLORS_CMYK (1L<<3) /* DeviceCMYK */
+
+#define GB_COLORS_STANDARD_ALL\
+ (GB_COLORS_GRAY | GB_COLORS_RGB | GB_COLORS_CMYK)
+#define GB_COLORS_ALL\
+ (GB_COLORS_NATIVE | GB_COLORS_STANDARD_ALL)
+#define gb_colors_for_device(dev)\
+ ((dev)->color_info.num_components == 4 ? GB_COLORS_CMYK :\
+ (dev)->color_info.num_components == 3 ? GB_COLORS_RGB : GB_COLORS_GRAY)
+#define GB_COLORS_NAMES\
+ "colors_native", "colors_Gray", "colors_RGB", "colors_CMYK"
+
+ /*
+ * Define whether alpha information is included. For GB_COLORS_NATIVE,
+ * all values other than GB_ALPHA_NONE are equivalent.
+ */
+
+#define GB_ALPHA_NONE (1L<<4) /* no alpha */
+#define GB_ALPHA_FIRST (1L<<5) /* include alpha as first component */
+#define GB_ALPHA_LAST (1L<<6) /* include alpha as last component */
+ /*unused*/ /*(1L<<7)*/
+
+#define GB_ALPHA_ALL\
+ (GB_ALPHA_NONE | GB_ALPHA_FIRST | GB_ALPHA_LAST)
+#define GB_ALPHA_NAMES\
+ "alpha_none", "alpha_first", "alpha_last", "?alpha_unused?"
+
+ /*
+ * Define the supported depths per component for GB_COLORS_STANDARD.
+ */
+
+#define GB_DEPTH_1 (1L<<8)
+#define GB_DEPTH_2 (1L<<9)
+#define GB_DEPTH_4 (1L<<10)
+#define GB_DEPTH_8 (1L<<11)
+#define GB_DEPTH_12 (1L<<12)
+#define GB_DEPTH_16 (1L<<13)
+ /*unused1*/ /*(1L<<14)*/
+ /*unused2*/ /*(1L<<15)*/
+
+#define GB_DEPTH_ALL\
+ (GB_DEPTH_1 | GB_DEPTH_2 | GB_DEPTH_4 | GB_DEPTH_8 |\
+ GB_DEPTH_12 | GB_DEPTH_16)
+#define GB_DEPTH_NAMES\
+ "depth_1", "depth_2", "depth_4", "depth_8",\
+ "depth_12", "depth_16", "?depth_unused1?", "?depth_unused2?"
+
+/* Find the maximum depth of an options mask. */
+#define GB_OPTIONS_MAX_DEPTH(opt)\
+"\
+\000\001\002\002\004\004\004\004\010\010\010\010\010\010\010\010\
+\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\
+\020\020\020\020\020\020\020\020\020\020\020\020\020\020\020\020\
+\020\020\020\020\020\020\020\020\020\020\020\020\020\020\020\020\
+"[((opt) >> 8) & 0x3f]
+/* Find the depth of an options mask with exactly 1 bit set. */
+#define GB_OPTIONS_DEPTH(opt)\
+ ((((opt) >> 8) & 0xf) |\
+ "\000\000\014\020"[((opt) >> 12) & 3])
+
+ /*
+ * Define the supported packing formats. Currently, GB_PACKING_PLANAR is
+ * only partially supported, and GB_PACKING_BIT_PLANAR is hardly supported
+ * at all.
+ */
+
+#define GB_PACKING_CHUNKY (1L<<16)
+#define GB_PACKING_PLANAR (1L<<17) /* 1 plane per component */
+#define GB_PACKING_BIT_PLANAR (1L<<18) /* 1 plane per bit */
+ /*unused*/ /*(1L<<19)*/
+
+#define GB_PACKING_ALL\
+ (GB_PACKING_CHUNKY | GB_PACKING_PLANAR | GB_PACKING_BIT_PLANAR)
+#define GB_PACKING_NAMES\
+ "packing_chunky", "packing_planar", "packing_bit_planar", "?packing_unused?"
+
+ /*
+ * Define the possible methods of returning data.
+ */
+
+#define GB_RETURN_COPY (1L<<20) /* copy to client's buffer */
+#define GB_RETURN_POINTER (1L<<21) /* return pointers to data */
+
+#define GB_RETURN_ALL\
+ (GB_RETURN_COPY | GB_RETURN_POINTER)
+#define GB_RETURN_NAMES\
+ "return_copy", "return_pointer"
+
+ /*
+ * Define the allowable alignments. This is only relevant for
+ * GB_RETURN_POINTER: for GB_RETURN_COPY, any alignment is acceptable.
+ */
+
+#define GB_ALIGN_STANDARD (1L<<22) /* require standard bitmap alignment */
+#define GB_ALIGN_ANY (1L<<23) /* any alignment is acceptable */
+
+#define GB_ALIGN_ALL\
+ (GB_ALIGN_ANY | GB_ALIGN_STANDARD)
+#define GB_ALIGN_NAMES\
+ "align_any", "align_standard"
+
+ /*
+ * Define the allowable X offsets. GB_OFFSET_ANY is only relevant for
+ * GB_RETURN_POINTER: for GB_RETURN_COPY, clients must specify the
+ * offset so they know how much space to allocate.
+ */
+
+#define GB_OFFSET_0 (1L<<24) /* no offsetting */
+#define GB_OFFSET_SPECIFIED (1L<<25) /* client-specified offset */
+#define GB_OFFSET_ANY (1L<<26) /* any offset is acceptable */
+ /* (for GB_RETURN_POINTER only) */
+ /*unused*/ /*(1L<<27)*/
+
+#define GB_OFFSET_ALL\
+ (GB_OFFSET_0 | GB_OFFSET_SPECIFIED | GB_OFFSET_ANY)
+#define GB_OFFSET_NAMES\
+ "offset_0", "offset_specified", "offset_any", "?offset_unused?"
+
+ /*
+ * Define the allowable rasters. GB_RASTER_ANY is only relevant for
+ * GB_RETURN_POINTER, for the same reason as GB_OFFSET_ANY.
+ * Note also that if GB_ALIGN_STANDARD and GB_RASTER_SPECIFIED are
+ * both chosen and more than one scan line is being transferred,
+ * the raster value must also be aligned (i.e., 0 mod align_bitmap_mod).
+ * Implementors are not required to check this.
+ */
+
+ /*
+ * Standard raster is bitmap_raster(dev->width) for return_ptr,
+ * bitmap_raster(x_offset + width) for return_copy,
+ * padding per alignment.
+ */
+#define GB_RASTER_STANDARD (1L<<28)
+#define GB_RASTER_SPECIFIED (1L<<29) /* any client-specified raster */
+#define GB_RASTER_ANY (1L<<30) /* any raster is acceptable (for */
+ /* GB_RETURN_POINTER only) */
+
+#define GB_RASTER_ALL\
+ (GB_RASTER_STANDARD | GB_RASTER_SPECIFIED | GB_RASTER_ANY)
+#define GB_RASTER_NAMES\
+ "raster_standard", "raster_specified", "raster_any"
+
+/* Define names for debugging printout. */
+#define GX_BITMAP_FORMAT_NAMES\
+ GB_COLORS_NAMES, GB_ALPHA_NAMES, GB_DEPTH_NAMES, GB_PACKING_NAMES,\
+ GB_RETURN_NAMES, GB_ALIGN_NAMES, GB_OFFSET_NAMES, GB_RASTER_NAMES
+
+#endif /* gxbitfmt_INCLUDED */
diff --git a/pstoraster/gxbitmap.h b/pstoraster/gxbitmap.h
new file mode 100644
index 000000000..20802e9b4
--- /dev/null
+++ b/pstoraster/gxbitmap.h
@@ -0,0 +1,133 @@
+/* Copyright (C) 1989, 1993, 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 stored bitmaps for Ghostscript */
+
+#ifndef gxbitmap_INCLUDED
+# define gxbitmap_INCLUDED
+
+#include "gstypes.h" /* for gs_id */
+#include "gsbitmap.h"
+
+/* Define the gx version of a bitmap identifier. */
+typedef gs_bitmap_id gx_bitmap_id;
+
+/* Define the gx version of the "no identifier" value. */
+#define gx_no_bitmap_id gs_no_bitmap_id
+
+/*
+ * For gx_bitmap data, each scan line must start on a `word' (long)
+ * boundary, and hence is padded to a word boundary, although this should
+ * rarely be of concern, since the raster and width are specified
+ * individually.
+ */
+/* We assume arch_align_long_mod is 1-4 or 8. */
+#if arch_align_long_mod <= 4
+# define log2_align_bitmap_mod 2
+#else
+#if arch_align_long_mod == 8
+# define log2_align_bitmap_mod 3
+#endif
+#endif
+#define align_bitmap_mod (1 << log2_align_bitmap_mod)
+#define bitmap_raster(width_bits)\
+ ((uint)(((width_bits + (align_bitmap_mod * 8 - 1))\
+ >> (log2_align_bitmap_mod + 3)) << log2_align_bitmap_mod))
+
+/*
+ * Define the gx analogue of the basic bitmap structure. Note that since
+ * all scan lines must be aligned, the requirement on raster is:
+ * If size.y > 1,
+ * raster >= bitmap_raster(size.x * depth)
+ * raster % align_bitmap_mod = 0
+ */
+#define gx_bitmap_common gs_bitmap_common
+typedef struct gx_bitmap_s {
+ gx_bitmap_common;
+} gx_bitmap;
+
+/*
+ * Define the gx analogue of the tile bitmap structure. Note that if
+ * shift != 0 (for strip bitmaps, see below), size.y and rep_height
+ * mean something slightly different: see below for details.
+ */
+#define gx_tile_bitmap_common gs_tile_bitmap_common
+typedef struct gx_tile_bitmap_s {
+ gx_tile_bitmap_common;
+} gx_tile_bitmap;
+
+/*
+ * For halftones at arbitrary angles, we provide for storing the halftone
+ * data as a strip that must be shifted in X for different values of Y. For
+ * an ordinary (non-shifted) halftone that has a repetition width of W and a
+ * repetition height of H, the pixel at coordinate (X,Y) corresponds to
+ * halftone pixel (X mod W, Y mod H), ignoring phase; for a strip halftone
+ * with strip shift S and strip height H, the pixel at (X,Y) corresponds to
+ * halftone pixel ((X + S * floor(Y/H)) mod W, Y mod H). In other words,
+ * each Y increment of H shifts the strip left by S pixels.
+ *
+ * As for non-shifted tiles, a strip bitmap may include multiple copies
+ * in X or Y to reduce loop overhead. In this case, we must distinguish:
+ * - The height of an individual strip, which is the same as
+ * the height of the bitmap being replicated (rep_height, H);
+ * - The height of the entire bitmap (size.y).
+ * Similarly, we must distinguish:
+ * - The shift per strip (rep_shift, S);
+ * - The shift for the entire bitmap (shift).
+ * Note that shift = (rep_shift * size.y / rep_height) mod rep_width,
+ * so the shift member of the structure is only an accelerator. It is,
+ * however, an important one, since it indicates whether the overall
+ * bitmap requires shifting or not.
+ *
+ * Note that for shifted tiles, size.y is the size of the stored bitmap
+ * (1 or more strips), and NOT the height of the actual tile. The latter
+ * is not stored in the structure at all: it can be computed as H * W /
+ * gcd(S, W).
+ *
+ * If the bitmap consists of a multiple of W / gcd(S, W) copies in Y, the
+ * effective shift is zero, reducing it to a tile. For simplicity, we
+ * require that if shift is non-zero, the bitmap height be less than H * W /
+ * gcd(S, W). I.e., we don't allow strip bitmaps that are large enough to
+ * include a complete tile but that don't include an integral number of
+ * tiles. Requirements:
+ * rep_shift < rep_width
+ * shift = (rep_shift * (size.y / rep_height)) % rep_width
+ */
+#define gx_strip_bitmap_common\
+ gx_tile_bitmap_common;\
+ ushort rep_shift;\
+ ushort shift
+typedef struct gx_strip_bitmap_s {
+ gx_strip_bitmap_common;
+} gx_strip_bitmap;
+
+extern_st(st_gx_strip_bitmap);
+#define public_st_gx_strip_bitmap() /* in gspcolor.c */\
+ gs_public_st_suffix_add0_local(st_gx_strip_bitmap, gx_strip_bitmap,\
+ "gx_strip_bitmap", bitmap_enum_ptrs, bitmap_reloc_ptrs,\
+ st_gs_tile_bitmap)
+#define st_gx_strip_bitmap_max_ptrs 1
+
+#endif /* gxbitmap_INCLUDED */
diff --git a/pstoraster/gxbitops.h b/pstoraster/gxbitops.h
new file mode 100644
index 000000000..6b8b13d86
--- /dev/null
+++ b/pstoraster/gxbitops.h
@@ -0,0 +1,142 @@
+/* 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$ */
+/* Internal definitions for bitmap operations */
+
+#ifndef gxbitops_INCLUDED
+# define gxbitops_INCLUDED
+
+#include "gsbitops.h"
+
+/*
+ * Macros for processing bitmaps in the largest possible chunks.
+ * Bits within a byte are always stored big-endian;
+ * bytes are likewise stored in left-to-right order, i.e., big-endian.
+ * Note that this is the format used for the source of copy_mono.
+ * It used to be the case that bytes were stored in the natural
+ * platform order, and the client had force them into big-endian order
+ * by calling gdev_mem_ensure_byte_order, but this no longer necessary.
+ *
+ * Note that we use type uint for register variables holding a chunk:
+ * for this reason, the chunk size cannot be larger than uint.
+ */
+/* Generic macros for chunk accessing. */
+#define cbytes(ct) size_of(ct) /* sizeof may be unsigned */
+# define chunk_bytes cbytes(chunk)
+/* The clog2_bytes macro assumes that ints are 2, 4, or 8 bytes in size. */
+#define clog2_bytes(ct) (size_of(ct) == 8 ? 3 : size_of(ct)>>1)
+# define chunk_log2_bytes clog2_bytes(chunk)
+#define cbits(ct) (size_of(ct)*8) /* sizeof may be unsigned */
+# define chunk_bits cbits(chunk)
+#define clog2_bits(ct) (clog2_bytes(ct)+3)
+# define chunk_log2_bits clog2_bits(chunk)
+#define cbit_mask(ct) (cbits(ct)-1)
+# define chunk_bit_mask cbit_mask(chunk)
+#define calign_bytes(ct)\
+ (sizeof(ct) == 1 ? 1:\
+ sizeof(ct) == sizeof(short) ? arch_align_short_mod :\
+ sizeof(ct) == sizeof(int) ? arch_align_int_mod : arch_align_long_mod)
+# define chunk_align_bytes calign_bytes(chunk)
+#define calign_bit_mask(ct) (calign_bytes(ct)*8-1)
+# define chunk_align_bit_mask calign_bit_mask(chunk)
+/*
+ * The obvious definition for cmask is:
+ * #define cmask(ct) ((ct)~(ct)0)
+ * but this doesn't work on the VAX/VMS compiler, which fails to truncate
+ * the value to 16 bits when ct is ushort.
+ * Instead, we have to generate the mask with no extra 1-bits.
+ * We can't do this in the obvious way:
+ * #define cmask(ct) ((1 << (size_of(ct) * 8)) - 1)
+ * because some compilers won't allow a shift of the full type size.
+ * Instead, we have to do something really awkward:
+ */
+#define cmask(ct) ((ct) (((((ct)1 << (size_of(ct)*8-2)) - 1) << 2) + 3))
+# define chunk_all_bits cmask(chunk)
+/*
+ * The obvious definition for chi_bits is:
+ * #define chi_bits(ct,n) (cmask(ct)-(cmask(ct)>>(n)))
+ * but this doesn't work on the DEC/MIPS compilers.
+ * Instead, we have to restrict chi_bits to only working for values of n
+ * between 0 and cbits(ct)-1, and use
+ */
+#define chi_bits(ct,n) (ct)(~(ct)1 << (cbits(ct)-1 - (n)))
+# define chunk_hi_bits(n) chi_bits(chunk,n)
+
+/* Define whether this is a machine where chunks are long, */
+/* but the machine can't shift a long by its full width. */
+#define arch_cant_shift_full_chunk\
+ (arch_is_big_endian && !arch_ints_are_short && !arch_can_shift_full_long)
+
+/* Pointer arithmetic macros. */
+#define inc_ptr(ptr,delta)\
+ (ptr = (void *)((byte *)ptr + (delta)))
+
+/* Define macros for setting up left- and right-end masks. */
+/* These are used for monobit operations, and for filling */
+/* with 2- and 4-bit-per-pixel patterns. */
+
+/*
+ * Define the chunk size for monobit copying operations.
+ */
+#if arch_is_big_endian
+# define mono_copy_chunk uint
+# define set_mono_right_mask(var, w)\
+ (var = ((w) == chunk_bits ? chunk_all_bits : chunk_hi_bits(w)))
+/*
+ * We have to split the following statement because of a bug in the Xenix C
+ * compiler (it produces a signed rather than an unsigned shift if we don't
+ * split).
+ */
+# define set_mono_thin_mask(var, w, bit)\
+ set_mono_right_mask(var, w), var >>= (bit)
+/*
+ * We have to split the following statement in two because of a bug
+ * in the DEC VAX/VMS C compiler.
+ */
+# define set_mono_left_mask(var, bit)\
+ (var = chunk_all_bits, var >>= (bit))
+#else
+# define mono_copy_chunk bits16
+extern const bits16 mono_copy_masks[17];
+
+# if mono_fill_chunk_bytes == 2
+# define mono_fill_masks mono_copy_masks
+# else
+extern const bits32 mono_fill_masks[33];
+
+# endif
+/*
+ * We define mono_masks as either mono_fill_masks or
+ * mono_copy_masks before using the following macros.
+ */
+# define set_mono_left_mask(var, bit)\
+ (var = mono_masks[bit])
+# define set_mono_thin_mask(var, w, bit)\
+ (var = ~mono_masks[(w) + (bit)] & mono_masks[bit])
+# define set_mono_right_mask(var, ebit)\
+ (var = ~mono_masks[ebit])
+#endif
+
+#endif /* gxbitops_INCLUDED */
diff --git a/pstoraster/gxccache.c b/pstoraster/gxccache.c
new file mode 100644
index 000000000..f6dd01b94
--- /dev/null
+++ b/pstoraster/gxccache.c
@@ -0,0 +1,456 @@
+/* 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$ */
+/* Fast case character cache routines for Ghostscript library */
+#include "gx.h"
+#include "gpcheck.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gxfixed.h"
+#include "gxmatrix.h"
+#include "gzstate.h"
+#include "gzpath.h"
+#include "gxdevice.h"
+#include "gxdevmem.h"
+#include "gzcpath.h"
+#include "gxchar.h"
+#include "gxfont.h"
+#include "gxfcache.h"
+#include "gxxfont.h"
+#include "gscspace.h" /* for gsimage.h */
+#include "gsimage.h"
+#include "gxhttile.h"
+
+/* Forward references */
+private byte *compress_alpha_bits(P2(const cached_char *, gs_memory_t *));
+
+/* Define a scale factor of 1. */
+static const gs_log2_scale_point scale_log2_1 =
+{0, 0};
+
+/* Look up, and if necessary add, a font/matrix pair in the cache */
+cached_fm_pair *
+gx_lookup_fm_pair(gs_font * pfont, register const gs_state * pgs)
+{
+ float mxx = pgs->char_tm.xx, mxy = pgs->char_tm.xy, myx = pgs->char_tm.yx,
+ myy = pgs->char_tm.yy;
+ gs_font *font = pfont;
+ register gs_font_dir *dir = font->dir;
+ register cached_fm_pair *pair =
+ dir->fmcache.mdata + dir->fmcache.mnext;
+ int count = dir->fmcache.mmax;
+ gs_uid uid;
+
+ if (font->FontType == ft_composite || font->PaintType != 0) { /* We can't cache by UID alone. */
+ uid_set_invalid(&uid);
+ } else {
+ uid = ((gs_font_base *) font)->UID;
+ if (uid_is_valid(&uid))
+ font = 0;
+ }
+ while (count--) {
+ if (pair == dir->fmcache.mdata)
+ pair += dir->fmcache.mmax;
+ pair--;
+ /* We have either a non-zero font and an invalid UID, */
+ /* or a zero font and a valid UID. */
+ /* We have to break up the test */
+ /* because of a bug in the Zortech compiler. */
+ if (font != 0) {
+ if (pair->font != font)
+ continue;
+ } else {
+ if (!uid_equal(&pair->UID, &uid) ||
+ pair->FontType != pfont->FontType
+ )
+ continue;
+ }
+ if (pair->mxx == mxx && pair->mxy == mxy &&
+ pair->myx == myx && pair->myy == myy
+ ) {
+ if (pair->font == 0) {
+ pair->font = pfont;
+ if_debug2('k', "[k]updating pair 0x%lx with font 0x%lx\n",
+ (ulong) pair, (ulong) pfont);
+ } else {
+ if_debug2('k', "[k]found pair 0x%lx: font=0x%lx\n",
+ (ulong) pair, (ulong) pair->font);
+ }
+ return pair;
+ }
+ }
+ return gx_add_fm_pair(dir, pfont, &uid, pgs);
+}
+
+/* Look up a glyph in the cache. */
+/* The character depth must be either 1 or alt_depth. */
+/* Return the cached_char or 0. */
+cached_char *
+gx_lookup_cached_char(const gs_font * pfont, const cached_fm_pair * pair,
+ gs_glyph glyph, int wmode, int alt_depth)
+{
+ gs_font_dir *dir = pfont->dir;
+ uint chi = chars_head_index(glyph, pair);
+ register cached_char *cc;
+
+ while ((cc = dir->ccache.table[chi & dir->ccache.table_mask]) != 0) {
+ if (cc->code == glyph && cc_pair(cc) == pair &&
+ cc->wmode == wmode && (cc_depth(cc) == 1 || cc_depth(cc) == alt_depth)
+ ) {
+ if_debug4('K', "[K]found 0x%lx (depth=%d) for glyph=0x%lx, wmode=%d\n",
+ (ulong) cc, cc_depth(cc), (ulong) glyph, wmode);
+ return cc;
+ }
+ chi++;
+ }
+ if_debug3('K', "[K]not found: glyph=0x%lx, wmode=%d, alt_depth=%d\n",
+ (ulong) glyph, wmode, alt_depth);
+ return 0;
+}
+
+/* Look up a character in an external font. */
+/* Return the cached_char or 0. */
+cached_char *
+gx_lookup_xfont_char(const gs_state * pgs, cached_fm_pair * pair,
+gs_char chr, gs_glyph glyph, const gx_xfont_callbacks * callbacks, int wmode)
+{
+ gs_font *font = pair->font;
+ int enc_index;
+ gx_xfont *xf;
+ gx_xglyph xg;
+ gs_log2_scale_point log2_scale;
+ gs_point wxy;
+ gs_int_rect bbox;
+ cached_char *cc;
+
+ if (font == 0)
+ return NULL;
+ enc_index =
+ (font->FontType == ft_composite ? -1 :
+ ((gs_font_base *) font)->nearest_encoding_index);
+ if (!pair->xfont_tried) { /* Look for an xfont now. */
+ gx_lookup_xfont(pgs, pair, enc_index);
+ pair->xfont_tried = true;
+ }
+ xf = pair->xfont;
+ if (xf == 0)
+ return NULL;
+ {
+ const gx_xfont_procs *procs = xf->common.procs;
+
+ if (procs->char_xglyph2 == 0) { /* The xfont can't recognize reencoded fonts. */
+ /* Use the registered encoding only if this glyph */
+ /* is the same as the one in the registered encoding. */
+ if (enc_index >= 0 &&
+ (*callbacks->known_encode) (chr, enc_index) != glyph
+ )
+ enc_index = -1;
+ xg = (*procs->char_xglyph) (xf, chr, enc_index, glyph,
+ callbacks->glyph_name);
+ } else { /* The xfont can recognize reencoded fonts. */
+ xg = (*procs->char_xglyph2) (xf, chr, enc_index, glyph,
+ callbacks);
+ }
+ if (xg == gx_no_xglyph)
+ return NULL;
+ if ((*procs->char_metrics) (xf, xg, wmode, &wxy, &bbox) < 0)
+ return NULL;
+ }
+ log2_scale.x = log2_scale.y = 1;
+ cc = gx_alloc_char_bits(font->dir, NULL, NULL, bbox.q.x - bbox.p.x,
+ bbox.q.y - bbox.p.y, &log2_scale, 1);
+ if (cc == 0)
+ return NULL;
+ /* Success. Make the cache entry. */
+ cc->code = glyph;
+ cc->wmode = wmode;
+ cc->xglyph = xg;
+ cc->wxy.x = float2fixed(wxy.x);
+ cc->wxy.y = float2fixed(wxy.y);
+ cc->offset.x = int2fixed(-bbox.p.x);
+ cc->offset.y = int2fixed(-bbox.p.y);
+ if_debug5('k', "[k]xfont %s char %d/0x%x#0x%lx=>0x%lx\n",
+ font->font_name.chars, enc_index, (int)chr,
+ (ulong) glyph, (ulong) xg);
+ if_debug6('k', " wxy=(%g,%g) bbox=(%d,%d),(%d,%d)\n",
+ wxy.x, wxy.y, bbox.p.x, bbox.p.y, bbox.q.x, bbox.q.y);
+ gx_add_cached_char(font->dir, NULL, cc, pair, &scale_log2_1);
+ return cc;
+}
+
+/* Copy a cached character to the screen. */
+/* Assume the caller has already done gx_color_load. */
+/* Return 0 if OK, 1 if we couldn't do the operation but no error */
+/* should be signalled, or a negative error code. */
+int
+gx_image_cached_char(register gs_show_enum * penum, register cached_char * cc)
+{
+ register gs_state *pgs = penum->pgs;
+ gx_device_color *pdevc = pgs->dev_color;
+ int x, y, w, h, depth;
+ int code;
+ gs_fixed_point pt;
+ gx_device *dev = gs_currentdevice_inline(pgs);
+ gx_device *orig_dev = dev;
+ gx_device_clip cdev;
+ gx_xglyph xg = cc->xglyph;
+ gx_xfont *xf;
+ byte *bits;
+
+ top:code = gx_path_current_point_inline(pgs->path, &pt);
+ if (code < 0)
+ return code;
+ /*
+ * If the character doesn't lie entirely within the inner
+ * clipping rectangle, we set up an intermediate clipping device.
+ * Note that if the original device implements fill_mask, we may
+ * never actually use the clipping device.
+ */
+ pt.x -= cc->offset.x;
+ x = fixed2int_var_rounded(pt.x) + penum->ftx;
+ pt.y -= cc->offset.y;
+ y = fixed2int_var_rounded(pt.y) + penum->fty;
+ w = cc->width;
+ h = cc->height;
+#ifdef DEBUG
+ if (gs_debug_c('K')) {
+ if (cc_has_bits(cc))
+ debug_dump_bitmap(cc_bits(cc), cc_raster(cc), h,
+ "[K]bits");
+ else
+ dputs("[K]no bits\n");
+ dlprintf3("[K]copying 0x%lx, offset=(%g,%g)\n", (ulong) cc,
+ fixed2float(-cc->offset.x),
+ fixed2float(-cc->offset.y));
+ dlprintf6(" at (%g,%g)+(%d,%d)->(%d,%d)\n",
+ fixed2float(pt.x), fixed2float(pt.y),
+ penum->ftx, penum->fty, x, y);
+ }
+#endif
+ if ((x < penum->ibox.p.x || x + w > penum->ibox.q.x ||
+ y < penum->ibox.p.y || y + h > penum->ibox.q.y) &&
+ dev != (gx_device *) & cdev /* might be 2nd time around */
+ ) { /* Check for the character falling entirely outside */
+ /* the clipping region. */
+ gx_clip_path *pcpath;
+
+ if (x >= penum->obox.q.x || x + w <= penum->obox.p.x ||
+ y >= penum->obox.q.y || y + h <= penum->obox.p.y
+ )
+ return 0; /* nothing to do */
+ code = gx_effective_clip_path(pgs, &pcpath);
+ if (code < 0)
+ return code;
+ gx_make_clip_device(&cdev, &cdev, gx_cpath_list(pcpath));
+ cdev.target = dev;
+ dev = (gx_device *) & cdev;
+ (*dev_proc(dev, open_device)) (dev);
+ if_debug0('K', "[K](clipping)\n");
+ }
+ /* If an xfont can render this character, use it. */
+ if (xg != gx_no_xglyph && (xf = cc_pair(cc)->xfont) != 0) {
+ int cx = x + fixed2int(cc->offset.x);
+ int cy = y + fixed2int(cc->offset.y);
+
+ /*
+ * Note that we prefer a 1-bit xfont implementation over
+ * a multi-bit cached bitmap. Eventually we should change
+ * the xfont interface so it can deliver multi-bit bitmaps,
+ * or else implement oversampling for xfonts.
+ */
+ if (gs_color_writes_pure(pgs)) {
+ code = (*xf->common.procs->render_char) (xf, xg,
+ dev, cx, cy, pdevc->colors.pure, 0);
+ if_debug8('K', "[K]render_char display: xfont=0x%lx, glyph=0x%lx\n\tdev=0x%lx(%s) x,y=%d,%d, color=0x%lx => %d\n",
+ (ulong) xf, (ulong) xg, (ulong) dev,
+ dev->dname, cx, cy,
+ (ulong) pdevc->colors.pure, code);
+ if (code == 0)
+ return_check_interrupt(0);
+ }
+ /* Can't render directly. If we don't have a bitmap yet, */
+ /* get it from the xfont now. */
+ if (!cc_has_bits(cc)) {
+ gx_device_memory mdev;
+
+ gs_make_mem_mono_device(&mdev, 0, dev);
+ gx_open_cache_device(&mdev, cc);
+ code = (*xf->common.procs->render_char) (xf, xg,
+ (gx_device *) & mdev, cx - x, cy - y,
+ (gx_color_index) 1, 1);
+ if_debug7('K', "[K]render_char to bits: xfont=0x%lx, glyph=0x%lx\n\tdev=0x%lx(%s) x,y=%d,%d => %d\n",
+ (ulong) xf, (ulong) xg, (ulong) & mdev,
+ mdev.dname, cx - x, cy - y, code);
+ if (code != 0)
+ return_check_interrupt(1);
+ gx_add_char_bits(cc_pair(cc)->font->dir,
+ cc, &scale_log2_1);
+ /* gx_add_char_bits may change width, height, */
+ /* raster, and/or offset. It's easiest to */
+ /* start over from the top. Clear xg so that */
+ /* we don't waste time trying render_char again. */
+ xg = gx_no_xglyph;
+ goto top;
+ }
+ }
+ /*
+ * No xfont. Render from the cached bits. If the cached bits
+ * have more than 1 bit of alpha, and the color isn't pure or
+ * the copy_alpha operation fails, construct a single-bit mask
+ * by taking the high-order alpha bit.
+ */
+ bits = cc_bits(cc);
+ depth = cc_depth(cc);
+ if (dev_proc(orig_dev, fill_mask) != gx_default_fill_mask ||
+ !lop_no_S_is_T(pgs->log_op)
+ ) {
+ gx_clip_path *pcpath;
+
+ code = gx_effective_clip_path(pgs, &pcpath);
+ if (code >= 0) {
+ code = (*dev_proc(orig_dev, fill_mask))
+ (orig_dev, bits, 0, cc_raster(cc), cc->id,
+ x, y, w, h, pdevc, depth, pgs->log_op, pcpath);
+ if (code >= 0)
+ goto done;
+ }
+ } else if (gs_color_writes_pure(pgs)) {
+ gx_color_index color = pdevc->colors.pure;
+
+ if (depth > 1) {
+ code = (*dev_proc(dev, copy_alpha))
+ (dev, bits, 0, cc_raster(cc), cc->id,
+ x, y, w, h, color, depth);
+ if (code >= 0)
+ return_check_interrupt(0);
+ /* copy_alpha failed, construct a monobit mask. */
+ bits = compress_alpha_bits(cc, &gs_memory_default);
+ if (bits == 0)
+ return 1; /* VMerror, but recoverable */
+ }
+ code = (*dev_proc(dev, copy_mono))
+ (dev, bits, 0, cc_raster(cc), cc->id,
+ x, y, w, h, gx_no_color_index, pdevc->colors.pure);
+ goto done;
+ }
+ if (depth > 1) { /* Complex color or fill_mask / copy_alpha failed, */
+ /* construct a monobit mask. */
+ bits = compress_alpha_bits(cc, &gs_memory_default);
+ if (bits == 0)
+ return 1; /* VMerror, but recoverable */
+
+ } { /* Use imagemask to render the character. */
+ gs_memory_t *mem = &gs_memory_default;
+ gs_image_enum *pie =
+ gs_image_enum_alloc(mem, "image_char(image_enum)");
+ gs_image_t image;
+ int iy;
+ uint used;
+
+ if (pie == 0) {
+ if (bits != cc_bits(cc))
+ gs_free_object(&gs_memory_default, bits,
+ "compress_alpha_bits");
+ return 1; /* VMerror, but recoverable */
+ }
+ /* Make a matrix that will place the image */
+ /* at (x,y) with no transformation. */
+ gs_image_t_init_mask(&image, true);
+#define mat image.ImageMatrix
+ gs_make_translation((floatp) - x, (floatp) - y, &mat);
+ gs_matrix_multiply(&ctm_only(pgs), &mat, &mat);
+#undef mat
+ image.Width = w;
+ image.Height = h;
+ image.adjust = false;
+ code = gs_image_init(pie, &image, false, pgs);
+ switch (code) {
+ case 1: /* empty image */
+ code = 0;
+ default:
+ break;
+ case 0:
+ for (iy = 0; iy < h && code >= 0; iy++)
+ code = gs_image_next(pie, bits + iy * cc_raster(cc),
+ (w + 7) >> 3, &used);
+ gs_image_cleanup(pie);
+ }
+ gs_free_object(mem, pie, "image_char(image_enum)");
+ }
+ done:if (bits != cc_bits(cc))
+ gs_free_object(&gs_memory_default, bits, "compress_alpha_bits");
+ if (code > 0)
+ code = 0;
+ return_check_interrupt(code);
+}
+
+/* ------ Image manipulation ------ */
+
+/*
+ * Compress a mask with 2 or 4 bits of alpha to a monobit mask.
+ * Allocate and return the address of the monobit mask.
+ */
+private byte *
+compress_alpha_bits(const cached_char * cc, gs_memory_t * mem)
+{
+ const byte *data = cc_const_bits(cc);
+ uint width = cc->width;
+ uint height = cc->height;
+ int log2_scale = cc_depth(cc);
+ int scale = 1 << log2_scale;
+ uint sraster = cc_raster(cc);
+ uint sskip = sraster - ((width * scale + 7) >> 3);
+ uint draster = bitmap_raster(width);
+ uint dskip = draster - ((width + 7) >> 3);
+ byte *mask = gs_alloc_bytes(mem, draster * height,
+ "compress_alpha_bits");
+ const byte *sptr = data;
+ byte *dptr = mask;
+ uint h;
+
+ if (mask == 0)
+ return 0;
+ for (h = height; h; --h) {
+ byte sbit = 0x80;
+ byte d = 0;
+ byte dbit = 0x80;
+ uint w;
+
+ for (w = width; w; --w) {
+ if (*sptr & sbit)
+ d += dbit;
+ if (!(sbit >>= log2_scale))
+ sbit = 0x80, sptr++;
+ if (!(dbit >>= 1))
+ dbit = 0x80, dptr++, d = 0;
+ }
+ if (dbit != 0x80)
+ *dptr++ = d;
+ for (w = dskip; w != 0; --w)
+ *dptr++ = 0;
+ sptr += sskip;
+ }
+ return mask;
+}
diff --git a/pstoraster/gxccman.c b/pstoraster/gxccman.c
new file mode 100644
index 000000000..b2a42c402
--- /dev/null
+++ b/pstoraster/gxccman.c
@@ -0,0 +1,797 @@
+/* Copyright (C) 1989, 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$ */
+/* Character cache management routines for Ghostscript library */
+#include "gx.h"
+#include "memory_.h"
+#include "gpcheck.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gsbitops.h"
+#include "gsutil.h" /* for gs_next_ids */
+#include "gxfixed.h"
+#include "gxmatrix.h"
+#include "gzstate.h"
+#include "gzpath.h"
+#include "gxdevice.h"
+#include "gxdevmem.h"
+#include "gxchar.h"
+#include "gxfont.h"
+#include "gxfcache.h"
+#include "gxxfont.h"
+
+/* Define the descriptors for the cache structures. */
+private_st_cached_fm_pair();
+private_st_cached_fm_pair_elt();
+ /*private_st_cached_char(); *//* unused */
+private_st_cached_char_ptr(); /* unused */
+private_st_cached_char_ptr_elt();
+/* GC procedures */
+/* We do all the work in font_dir_enum/reloc_ptrs in gsfont.c. */
+/* See gxfcache.h for details. */
+private
+ENUM_PTRS_BEGIN(cc_ptr_enum_ptrs) return 0;
+
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(cc_ptr_reloc_ptrs)
+{
+}
+RELOC_PTRS_END
+
+/* Forward references */
+private gx_xfont * lookup_xfont_by_name(P6(gx_device *, const gx_xfont_procs *, gs_font_name *, int, const cached_fm_pair *, const gs_matrix *));
+private cached_char *alloc_char(P2(gs_font_dir *, ulong));
+private cached_char *alloc_char_in_chunk(P2(gs_font_dir *, ulong));
+private void hash_remove_cached_char(P2(gs_font_dir *, uint));
+private void shorten_cached_char(P3(gs_font_dir *, cached_char *, uint));
+
+/* ====== Initialization ====== */
+
+/* Allocate and initialize the character cache elements of a font directory. */
+int
+gx_char_cache_alloc(gs_memory_t * struct_mem, gs_memory_t * bits_mem,
+ gs_font_dir * pdir, uint bmax, uint mmax, uint cmax, uint upper)
+{ /* Since we use open hashing, we must increase cmax somewhat. */
+ uint chsize = (cmax + (cmax >> 1)) | 31;
+ cached_fm_pair *mdata;
+ cached_char **chars;
+
+ /* Round up chsize to a power of 2. */
+ while (chsize & (chsize + 1))
+ chsize |= chsize >> 1;
+ chsize++;
+ mdata = gs_alloc_struct_array(struct_mem, mmax, cached_fm_pair,
+ &st_cached_fm_pair_element,
+ "font_dir_alloc(mdata)");
+ chars = gs_alloc_struct_array(struct_mem, chsize, cached_char *,
+ &st_cached_char_ptr_element,
+ "font_dir_alloc(chars)");
+ if (mdata == 0 || chars == 0) {
+ gs_free_object(struct_mem, chars, "font_dir_alloc(chars)");
+ gs_free_object(struct_mem, mdata, "font_dir_alloc(mdata)");
+ return_error(gs_error_VMerror);
+ }
+ pdir->fmcache.mmax = mmax;
+ pdir->fmcache.mdata = mdata;
+ pdir->ccache.struct_memory = struct_mem;
+ pdir->ccache.bits_memory = bits_mem;
+ pdir->ccache.bmax = bmax;
+ pdir->ccache.cmax = cmax;
+ pdir->ccache.lower = upper / 10;
+ pdir->ccache.upper = upper;
+ pdir->ccache.table = chars;
+ pdir->ccache.table_mask = chsize - 1;
+ gx_char_cache_init(pdir);
+ return 0;
+}
+
+/* Initialize the character cache. */
+void
+gx_char_cache_init(register gs_font_dir * dir)
+{
+ int i;
+ cached_fm_pair *pair;
+ char_cache_chunk *cck = (char_cache_chunk *)
+ gs_alloc_bytes_immovable(dir->ccache.bits_memory,
+ sizeof(char_cache_chunk),
+ "initial_chunk");
+
+ dir->fmcache.msize = 0;
+ dir->fmcache.mnext = 0;
+ gx_bits_cache_chunk_init(cck, NULL, 0);
+ gx_bits_cache_init((gx_bits_cache *) & dir->ccache, cck);
+ dir->ccache.bspace = 0;
+ memset((char *)dir->ccache.table, 0,
+ (dir->ccache.table_mask + 1) * sizeof(cached_char *));
+ for (i = 0, pair = dir->fmcache.mdata;
+ i < dir->fmcache.mmax; i++, pair++
+ ) {
+ pair->index = i;
+ fm_pair_init(pair);
+ }
+}
+
+/* ====== Purging ====== */
+
+/* Purge from the character cache all entries selected by */
+/* a client-supplied procedure. */
+void
+gx_purge_selected_cached_chars(gs_font_dir * dir,
+ bool(*proc) (P2(cached_char *, void *)), void *proc_data)
+{
+ int chi;
+ int cmax = dir->ccache.table_mask;
+
+ for (chi = 0; chi <= cmax;) {
+ cached_char *cc = dir->ccache.table[chi];
+
+ if (cc != 0 && (*proc) (cc, proc_data)) {
+ hash_remove_cached_char(dir, chi);
+ gx_free_cached_char(dir, cc);
+ } else
+ chi++;
+ }
+}
+
+/* ====== Font-level routines ====== */
+
+/* Add a font/matrix pair to the cache. */
+/* (This is only exported for gxccache.c.) */
+cached_fm_pair *
+gx_add_fm_pair(register gs_font_dir * dir, gs_font * font, const gs_uid * puid,
+ const gs_state * pgs)
+{
+ register cached_fm_pair *pair =
+ dir->fmcache.mdata + dir->fmcache.mnext;
+ cached_fm_pair *mend =
+ dir->fmcache.mdata + dir->fmcache.mmax;
+
+ if (dir->fmcache.msize == dir->fmcache.mmax) { /* cache is full *//* Prefer an entry with num_chars == 0, if any. */
+ int count;
+
+ for (count = dir->fmcache.mmax;
+ --count >= 0 && pair->num_chars != 0;
+ )
+ if (++pair == mend)
+ pair = dir->fmcache.mdata;
+ gs_purge_fm_pair(dir, pair, 0);
+ } else { /* Look for an empty entry. (We know there is one.) */
+ while (!fm_pair_is_free(pair))
+ if (++pair == mend)
+ pair = dir->fmcache.mdata;
+ }
+ dir->fmcache.msize++;
+ dir->fmcache.mnext = pair + 1 - dir->fmcache.mdata;
+ if (dir->fmcache.mnext == dir->fmcache.mmax)
+ dir->fmcache.mnext = 0;
+ pair->font = font;
+ pair->UID = *puid;
+ pair->FontType = font->FontType;
+ /* The OSF/1 compiler doesn't like casting a pointer to */
+ /* a shorter int.... */
+ pair->hash = (uint) (ulong) pair % 549; /* scramble bits */
+ pair->mxx = pgs->char_tm.xx, pair->mxy = pgs->char_tm.xy;
+ pair->myx = pgs->char_tm.yx, pair->myy = pgs->char_tm.yy;
+ pair->num_chars = 0;
+ pair->xfont_tried = false;
+ pair->xfont = 0;
+ if_debug8('k', "[k]adding pair 0x%lx: font=0x%lx [%g %g %g %g] UID %ld, 0x%lx\n",
+ (ulong) pair, (ulong) font,
+ pair->mxx, pair->mxy, pair->myx, pair->myy,
+ (long)pair->UID.id, (ulong) pair->UID.xvalues);
+ return pair;
+}
+
+/* Look up the xfont for a font/matrix pair. */
+/* (This is only exported for gxccache.c.) */
+void
+gx_lookup_xfont(const gs_state * pgs, cached_fm_pair * pair, int encoding_index)
+{
+ gx_device *dev = gs_currentdevice(pgs);
+ gx_device *fdev = (*dev_proc(dev, get_xfont_device)) (dev);
+ gs_font *font = pair->font;
+ const gx_xfont_procs *procs = (*dev_proc(fdev, get_xfont_procs)) (fdev);
+ gx_xfont *xf = 0;
+
+ /* We mustn't attempt to use xfonts for stroked characters, */
+ /* because such characters go outside their bounding box. */
+ if (procs != 0 && font->PaintType == 0) {
+ gs_matrix mat;
+
+ mat.xx = pair->mxx, mat.xy = pair->mxy;
+ mat.yx = pair->myx, mat.yy = pair->myy;
+ mat.tx = 0, mat.ty = 0;
+ /* xfonts can outlive their invocations, */
+ /* but restore purges them properly. */
+ pair->memory = pgs->memory;
+ if (font->key_name.size != 0)
+ xf = lookup_xfont_by_name(fdev, procs,
+ &font->key_name, encoding_index,
+ pair, &mat);
+#define font_name_eq(pfn1,pfn2)\
+ ((pfn1)->size == (pfn2)->size && (pfn1)->size != 0 &&\
+ !memcmp((char *)(pfn1)->chars, (char *)(pfn2)->chars, (pfn1)->size))
+ if (xf == 0 && font->font_name.size != 0 &&
+ /* Avoid redundant lookup */
+ !font_name_eq(&font->font_name, &font->key_name)
+ )
+ xf = lookup_xfont_by_name(fdev, procs,
+ &font->font_name, encoding_index,
+ pair, &mat);
+ if (xf == 0 && font->FontType != ft_composite &&
+ uid_is_valid(&((gs_font_base *) font)->UID)
+ ) { /* Look for an original font with the same UID. */
+ gs_font_dir *pdir = font->dir;
+ gs_font *pfont;
+
+ for (pfont = pdir->orig_fonts; pfont != 0;
+ pfont = pfont->next
+ ) {
+ if (pfont->FontType != ft_composite &&
+ uid_equal(&((gs_font_base *) pfont)->UID,
+ &((gs_font_base *) font)->UID) &&
+ pfont->key_name.size != 0 &&
+ !font_name_eq(&font->key_name,
+ &pfont->key_name)
+ ) {
+ xf = lookup_xfont_by_name(fdev, procs,
+ &pfont->key_name,
+ encoding_index, pair, &mat);
+ if (xf != 0)
+ break;
+ }
+ }
+ }
+ }
+ pair->xfont = xf;
+}
+
+/* ------ Internal routines ------ */
+
+/* Purge from the caches all references to a given font/matrix pair, */
+/* or just characters that depend on its xfont. */
+#define cpair ((cached_fm_pair *)vpair)
+private bool
+purge_fm_pair_char(cached_char * cc, void *vpair)
+{
+ return cc_pair(cc) == cpair;
+}
+private bool
+purge_fm_pair_char_xfont(cached_char * cc, void *vpair)
+{
+ return cc_pair(cc) == cpair && cpair->xfont == 0 && !cc_has_bits(cc);
+}
+#undef cpair
+void
+gs_purge_fm_pair(gs_font_dir * dir, cached_fm_pair * pair, int xfont_only)
+{
+ if_debug2('k', "[k]purging pair 0x%lx%s\n",
+ (ulong) pair, (xfont_only ? " (xfont only)" : ""));
+ if (pair->xfont != 0) {
+ (*pair->xfont->common.procs->release) (pair->xfont,
+ pair->memory);
+ pair->xfont_tried = false;
+ pair->xfont = 0;
+ }
+ gx_purge_selected_cached_chars(dir,
+ (xfont_only ? purge_fm_pair_char_xfont :
+ purge_fm_pair_char),
+ pair);
+ if (!xfont_only) {
+#ifdef DEBUG
+ if (pair->num_chars != 0) {
+ lprintf1("Error in gs_purge_fm_pair: num_chars =%d\n",
+ pair->num_chars);
+ }
+#endif
+ fm_pair_set_free(pair);
+ dir->fmcache.msize--;
+ }
+}
+
+/* Look up an xfont by name. */
+/* The caller must already have done get_xfont_device to get the proper */
+/* device to pass as the first argument to lookup_font. */
+private gx_xfont *
+lookup_xfont_by_name(gx_device * fdev, const gx_xfont_procs * procs,
+ gs_font_name * pfstr, int encoding_index, const cached_fm_pair * pair,
+ const gs_matrix * pmat)
+{
+ gx_xfont *xf;
+
+ if_debug5('k', "[k]lookup xfont %s [%g %g %g %g]\n",
+ pfstr->chars, pmat->xx, pmat->xy, pmat->yx, pmat->yy);
+ xf = (*procs->lookup_font) (fdev,
+ &pfstr->chars[0], pfstr->size,
+ encoding_index, &pair->UID,
+ pmat, pair->memory);
+ if_debug1('k', "[k]... xfont=0x%lx\n", (ulong) xf);
+ return xf;
+}
+
+/* ====== Character-level routines ====== */
+
+/*
+ * Allocate storage for caching a rendered character with possible
+ * oversampling and/or alpha. Return the cached_char if OK, 0 if too big.
+ * If the character is being oversampled, make the size decision
+ * on the basis of the final (scaled-down) size.
+ *
+ * The iwidth and iheight parameters include scaling up for oversampling
+ * (multiplication by 1 << pscale->{x,y}.)
+ * The depth parameter is the final number of alpha bits;
+ * depth <= x scale * y scale.
+ * If dev == NULL, this is an xfont-only entry.
+ * If dev != NULL, set up the memory device(s); in this case, if dev2 is
+ * not NULL, dev should be an alpha-buffer device with dev2 (an alpha
+ * device) as target.
+ */
+cached_char *
+gx_alloc_char_bits(gs_font_dir * dir, gx_device_memory * dev,
+ gx_device_memory * dev2, ushort iwidth, ushort iheight,
+ const gs_log2_scale_point * pscale, int depth)
+{
+ int log2_xscale = pscale->x;
+ int log2_yscale = pscale->y;
+ int log2_depth = depth >> 1; /* works for 1,2,4 */
+ uint nwidth_bits = (iwidth >> log2_xscale) << log2_depth;
+ ulong isize, icdsize;
+ uint iraster;
+ cached_char *cc;
+ gx_device_memory mdev;
+ gx_device_memory *pdev = dev;
+ gx_device_memory *pdev2;
+
+ if (dev == NULL) {
+ mdev.memory = 0;
+ mdev.target = 0;
+ pdev = &mdev;
+ }
+ pdev2 = (dev2 == 0 ? pdev : dev2);
+
+ /* Compute the scaled-down bitmap size, and test against */
+ /* the maximum cachable character size. */
+
+ iraster = bitmap_raster(nwidth_bits);
+ if (iraster != 0 && iheight >> log2_yscale > dir->ccache.upper / iraster) {
+ if_debug5('k', "[k]no cache bits: scale=%dx%d, raster/scale=%u, height/scale=%u, upper=%u\n",
+ 1 << log2_xscale, 1 << log2_yscale,
+ iraster, iheight, dir->ccache.upper);
+ return 0; /* too big */
+ }
+ /* Compute the actual bitmap size(s) and allocate the bits. */
+ if (dev2 == 0) {
+ /* Render to a full (possibly oversampled) bitmap; */
+ /* compress (if needed) when done. */
+ rc_header rc;
+
+ /* Preserve the reference count, if any. */
+ rc = pdev->rc;
+ gs_make_mem_mono_device(pdev, pdev->memory, pdev->target);
+ pdev->rc = rc;
+ pdev->width = iwidth;
+ pdev->height = iheight;
+ isize = gdev_mem_bitmap_size(pdev);
+ } else {
+ /* Use an alpha-buffer device to compress as we go. */
+ rc_header rc;
+
+ /* Preserve the reference counts, if any. */
+ rc = dev2->rc;
+ gs_make_mem_alpha_device(dev2, dev2->memory, NULL, depth);
+ dev2->rc = rc;
+ dev2->width = iwidth >> log2_xscale;
+ dev2->height = iheight >> log2_yscale;
+ rc = dev->rc;
+ gs_make_mem_abuf_device(dev, dev->memory, (gx_device *) dev2,
+ pscale, depth, 0);
+ dev->rc = rc;
+ dev->width = iwidth;
+ dev->height = 2 << log2_yscale;
+ isize = gdev_mem_bitmap_size(dev) +
+ gdev_mem_bitmap_size(dev2);
+ }
+ icdsize = isize + sizeof_cached_char;
+ cc = alloc_char(dir, icdsize);
+ if (cc == 0)
+ return 0;
+ if_debug4('k', "[k]adding char 0x%lx:%u(%u,%u)\n",
+ (ulong) cc, (uint) icdsize, iwidth, iheight);
+
+ /* Fill in the entry. */
+
+ cc_set_depth(cc, depth);
+ cc->xglyph = gx_no_xglyph;
+ /* Set the width and height to those of the device. */
+ /* Note that if we are oversampling without an alpha buffer. */
+ /* these are not the final unscaled dimensions. */
+ cc->width = pdev2->width;
+ cc->height = pdev2->height;
+ cc->shift = 0;
+ cc_set_raster(cc, gdev_mem_raster(pdev2));
+ cc_set_pair_only(cc, 0); /* not linked in yet */
+ cc->id = gx_no_bitmap_id;
+
+ /* Open the cache device(s). */
+
+ if (dev2) { /* The second device is an alpha device that targets */
+ /* the real storage for the character. */
+ byte *bits = cc_bits(cc);
+ uint bsize = (uint) gdev_mem_bitmap_size(dev2);
+
+ memset(bits, 0, bsize);
+ dev2->base = bits;
+ (*dev_proc(dev2, open_device)) ((gx_device *) dev2);
+ dev->base = bits + bsize;
+ (*dev_proc(dev, open_device)) ((gx_device *) dev);
+ } else if (dev)
+ gx_open_cache_device(dev, cc);
+
+ return cc;
+}
+
+/* Open the cache device. */
+void
+gx_open_cache_device(gx_device_memory * dev, cached_char * cc)
+{
+ byte *bits = cc_bits(cc);
+
+ dev->width = cc->width;
+ dev->height = cc->height;
+ memset((char *)bits, 0, (uint) gdev_mem_bitmap_size(dev));
+ dev->base = bits;
+ (*dev_proc(dev, open_device)) ((gx_device *) dev); /* initialize */
+}
+
+/* Remove a character from the cache. */
+void
+gx_free_cached_char(gs_font_dir * dir, cached_char * cc)
+{
+ char_cache_chunk *cck = cc->chunk;
+
+ dir->ccache.chunks = cck;
+ dir->ccache.cnext = (byte *) cc - cck->data;
+ if (cc_pair(cc) != 0) { /* might be allocated but not added to table yet */
+ cc_pair(cc)->num_chars--;
+ }
+ if_debug2('k', "[k]freeing char 0x%lx, pair=0x%lx\n",
+ (ulong) cc, (ulong) cc_pair(cc));
+ gx_bits_cache_free((gx_bits_cache *) & dir->ccache, &cc->head, cck);
+}
+
+/* Add a character to the cache */
+void
+gx_add_cached_char(gs_font_dir * dir, gx_device_memory * dev,
+cached_char * cc, cached_fm_pair * pair, const gs_log2_scale_point * pscale)
+{
+ if_debug5('k', "[k]chaining char 0x%lx: pair=0x%lx, glyph=0x%lx, wmode=%d, depth=%d\n",
+ (ulong) cc, (ulong) pair, (ulong) cc->code,
+ cc->wmode, cc_depth(cc));
+ if (dev != NULL) {
+ static const gs_log2_scale_point no_scale =
+ {0, 0};
+
+ /* Close the device, to flush the alpha buffer if any. */
+ (*dev_proc(dev, close_device)) ((gx_device *) dev);
+ gx_add_char_bits(dir, cc,
+ (gs_device_is_abuf((gx_device *) dev) ?
+ &no_scale : pscale));
+ }
+ /* Add the new character to the hash table. */
+ {
+ uint chi = chars_head_index(cc->code, pair);
+
+ while (dir->ccache.table[chi &= dir->ccache.table_mask] != 0)
+ chi++;
+ dir->ccache.table[chi] = cc;
+ cc_set_pair(cc, pair);
+ pair->num_chars++;
+ }
+}
+
+/* Adjust the bits of a newly-rendered character, by unscaling */
+/* and compressing or converting to alpha values if necessary. */
+void
+gx_add_char_bits(gs_font_dir * dir, cached_char * cc,
+ const gs_log2_scale_point * plog2_scale)
+{
+ int log2_x = plog2_scale->x, log2_y = plog2_scale->y;
+ uint raster = cc_raster(cc);
+ byte *bits = cc_bits(cc);
+ int depth = cc_depth(cc);
+ int log2_depth = depth >> 1; /* works for 1,2,4 */
+ uint nwidth_bits, nraster;
+ gs_int_rect bbox;
+
+#ifdef DEBUG
+ if (cc->width % (1 << log2_x) != 0 ||
+ cc->height % (1 << log2_y) != 0
+ ) {
+ lprintf4("size %d,%d not multiple of scale %d,%d!\n",
+ cc->width, cc->height,
+ 1 << log2_x, 1 << log2_y);
+ cc->width &= -1 << log2_x;
+ cc->height &= -1 << log2_y;
+ }
+#endif
+
+ /*
+ * Compute the bounding box before compressing.
+ * We may have to scan more bits, but this is a lot faster than
+ * compressing the white space. Note that all bbox values are
+ * in bits, not pixels.
+ */
+
+ bits_bounding_box(bits, cc->height, raster, &bbox);
+
+ /*
+ * If the character was oversampled, compress it now.
+ * In this case we know that log2_depth <= log2_x.
+ * If the character was not oversampled, or if we converted
+ * oversampling to alpha dynamically (using an alpha buffer
+ * intermediate device), log2_x and log2_y are both zero,
+ * but in the latter case we may still have depth > 1.
+ */
+
+ if ((log2_x | log2_y) != 0) {
+ if_debug5('k', "[k]compressing %dx%d by %dx%d to depth=%d\n",
+ cc->width, cc->height, 1 << log2_x, 1 << log2_y,
+ depth);
+ if (gs_debug_c('K'))
+ debug_dump_bitmap(bits, raster, cc->height,
+ "[K]uncompressed bits");
+ /* Truncate/round the bbox to a multiple of the scale. */
+ {
+ int scale_x = 1 << log2_x;
+
+ bbox.p.x &= -scale_x;
+ bbox.q.x = (bbox.q.x + scale_x - 1) & -scale_x;
+ }
+ {
+ int scale_y = 1 << log2_y;
+
+ bbox.p.y &= -scale_y;
+ bbox.q.y = (bbox.q.y + scale_y - 1) & -scale_y;
+ }
+ cc->width = (bbox.q.x - bbox.p.x) >> log2_x;
+ cc->height = (bbox.q.y - bbox.p.y) >> log2_y;
+ nwidth_bits = cc->width << log2_depth;
+ nraster = bitmap_raster(nwidth_bits);
+ bits_compress_scaled(bits + raster * bbox.p.y, bbox.p.x,
+ cc->width << log2_x,
+ cc->height << log2_y,
+ raster,
+ bits, nraster, plog2_scale, log2_depth);
+ bbox.p.x >>= log2_x;
+ bbox.p.y >>= log2_y;
+ } else { /* No oversampling, just remove white space. */
+ const byte *from = bits + raster * bbox.p.y + (bbox.p.x >> 3);
+
+ cc->height = bbox.q.y - bbox.p.y;
+ /*
+ * We'd like to trim off left and right blank space,
+ * but currently we're only willing to move bytes, not bits.
+ * (If we ever want to do better, we must remember that
+ * we can only trim whole pixels, and a pixel may occupy
+ * more than one bit.)
+ */
+ bbox.p.x &= ~7; /* adjust to byte boundary */
+ bbox.p.x >>= log2_depth; /* bits => pixels */
+ bbox.q.x = (bbox.q.x + depth - 1) >> log2_depth; /* ditto */
+ cc->width = bbox.q.x - bbox.p.x;
+ nwidth_bits = cc->width << log2_depth;
+ nraster = bitmap_raster(nwidth_bits);
+ if (bbox.p.x != 0 || nraster != raster) { /* Move the bits down and over. */
+ byte *to = bits;
+ uint n = cc->height;
+
+ /* We'd like to move only
+ uint nbytes = (nwidth_bits + 7) >> 3;
+ * bytes per scan line, but unfortunately this drops
+ * the guaranteed zero padding at the end.
+ */
+
+ for (; n--; from += raster, to += nraster)
+ memmove(to, from, /*nbytes */ nraster);
+ } else if (bbox.p.y != 0) { /* Just move the bits down. */
+ memmove(bits, from, raster * cc->height);
+ }
+ }
+
+ /* Adjust the offsets to account for removed white space. */
+
+ cc->offset.x -= int2fixed(bbox.p.x);
+ cc->offset.y -= int2fixed(bbox.p.y);
+
+ /* Discard the memory device overhead that follows the bits, */
+ /* and any space reclaimed from unscaling or compression. */
+
+ cc_set_raster(cc, nraster);
+ {
+ uint diff = round_down(cc->head.size - sizeof_cached_char -
+ nraster * cc->height,
+ align_cached_char_mod);
+
+ if (diff >= sizeof(cached_char_head)) {
+ shorten_cached_char(dir, cc, diff);
+ if_debug2('K', "[K]shortening char 0x%lx by %u (adding)\n",
+ (ulong) cc, diff);
+ }
+ }
+
+ /* Assign a bitmap id. */
+
+ cc->id = gs_next_ids(1);
+}
+
+/* Purge from the caches all references to a given font. */
+void
+gs_purge_font_from_char_caches(gs_font_dir * dir, const gs_font * font)
+{
+ cached_fm_pair *pair = dir->fmcache.mdata;
+ int count = dir->fmcache.mmax;
+
+ if_debug1('k', "[k]purging font 0x%lx\n",
+ (ulong) font);
+ while (count--) {
+ if (pair->font == font) {
+ if (uid_is_valid(&pair->UID)) { /* Keep the entry. */
+ pair->font = 0;
+ } else
+ gs_purge_fm_pair(dir, pair, 0);
+ }
+ pair++;
+ }
+}
+
+/* ------ Internal routines ------ */
+
+/* Allocate data space for a cached character, adding a new chunk if needed. */
+private cached_char *
+alloc_char(gs_font_dir * dir, ulong icdsize)
+{ /* Try allocating at the current position first. */
+ cached_char *cc = alloc_char_in_chunk(dir, icdsize);
+
+ if (cc == 0) {
+ if (dir->ccache.bspace < dir->ccache.bmax) { /* Allocate another chunk. */
+ gs_memory_t *mem = dir->ccache.bits_memory;
+ char_cache_chunk *cck_prev = dir->ccache.chunks;
+ char_cache_chunk *cck;
+ uint cksize = dir->ccache.bmax / 5 + 1;
+ uint tsize = dir->ccache.bmax - dir->ccache.bspace;
+ byte *cdata;
+
+ if (cksize > tsize)
+ cksize = tsize;
+ if (icdsize + sizeof(cached_char_head) > cksize) {
+ if_debug2('k', "[k]no cache bits: cdsize+head=%lu, cksize=%u\n",
+ icdsize + sizeof(cached_char_head),
+ cksize);
+ return 0; /* wouldn't fit */
+ }
+ cck = (char_cache_chunk *)
+ gs_alloc_bytes_immovable(mem, sizeof(*cck),
+ "char cache chunk");
+ if (cck == 0)
+ return 0;
+ cdata =
+ gs_alloc_bytes_immovable(mem, cksize,
+ "char cache chunk(data)");
+ if (cdata == 0) {
+ gs_free_object(mem, cck, "char cache chunk");
+ return 0;
+ }
+ gx_bits_cache_chunk_init(cck, cdata, cksize);
+ cck->next = cck_prev->next;
+ cck_prev->next = cck;
+ dir->ccache.bspace += cksize;
+ dir->ccache.chunks = cck;
+ } else { /* Cycle through existing chunks. */
+ char_cache_chunk *cck_init = dir->ccache.chunks;
+ char_cache_chunk *cck = cck_init;
+
+ while ((dir->ccache.chunks = cck = cck->next) != cck_init) {
+ dir->ccache.cnext = 0;
+ cc = alloc_char_in_chunk(dir, icdsize);
+ if (cc != 0)
+ return cc;
+ }
+ }
+ dir->ccache.cnext = 0;
+ cc = alloc_char_in_chunk(dir, icdsize);
+ }
+ return cc;
+}
+
+/* Allocate a character in the current chunk. */
+private cached_char *
+alloc_char_in_chunk(gs_font_dir * dir, ulong icdsize)
+{
+ char_cache_chunk *cck = dir->ccache.chunks;
+ cached_char_head *cch;
+
+#define cc ((cached_char *)cch)
+
+ while (gx_bits_cache_alloc((gx_bits_cache *) & dir->ccache,
+ icdsize, &cch) < 0
+ ) {
+ if (cch == 0) { /* Not enough room to allocate in this chunk. */
+ return 0;
+ } { /* Free the character */
+ cached_fm_pair *pair = cc_pair(cc);
+
+ if (pair != 0) {
+ uint chi = chars_head_index(cc->code, pair);
+
+ while (dir->ccache.table[chi & dir->ccache.table_mask] != cc)
+ chi++;
+ hash_remove_cached_char(dir, chi);
+ }
+ gx_free_cached_char(dir, cc);
+ }
+ }
+ cc->chunk = cck;
+ cc->loc = (byte *) cc - cck->data;
+ return cc;
+#undef cc
+}
+
+/* Remove the cached_char at a given index in the hash table. */
+/* In order not to slow down lookup, we relocate following entries. */
+private void
+hash_remove_cached_char(gs_font_dir * dir, uint chi)
+{
+ uint mask = dir->ccache.table_mask;
+ uint from = ((chi &= mask) + 1) & mask;
+ cached_char *cc;
+
+ dir->ccache.table[chi] = 0;
+ while ((cc = dir->ccache.table[from]) != 0) { /* Loop invariants: chars[chi] == 0; */
+ /* chars[chi+1..from] != 0. */
+ uint fchi = chars_head_index(cc->code, cc_pair(cc));
+
+ /* If chi <= fchi < from, we relocate the character. */
+ /* Note that '<=' must take wraparound into account. */
+ if ((chi < from ? chi <= fchi && fchi < from :
+ chi <= fchi || fchi < from)
+ ) {
+ dir->ccache.table[chi] = cc;
+ dir->ccache.table[from] = 0;
+ chi = from;
+ }
+ from = (from + 1) & mask;
+ }
+}
+
+/* Shorten a cached character. */
+/* diff >= sizeof(cached_char_head). */
+private void
+shorten_cached_char(gs_font_dir * dir, cached_char * cc, uint diff)
+{
+ gx_bits_cache_shorten((gx_bits_cache *) & dir->ccache, &cc->head,
+ diff, cc->chunk);
+ if_debug2('K', "[K]shortening creates free block 0x%lx(%u)\n",
+ (ulong) ((byte *) cc + cc->head.size), diff);
+}
diff --git a/pstoraster/gxchar.h b/pstoraster/gxchar.h
new file mode 100644
index 000000000..682c42501
--- /dev/null
+++ b/pstoraster/gxchar.h
@@ -0,0 +1,190 @@
+/* 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$ */
+/* Internal character definition for Ghostscript library */
+/* Requires gsmatrix.h, gxfixed.h */
+
+#ifndef gxchar_INCLUDED
+# define gxchar_INCLUDED
+
+#include "gschar.h"
+#include "gxtext.h"
+
+/* The type of cached characters is opaque. */
+#ifndef cached_char_DEFINED
+# define cached_char_DEFINED
+typedef struct cached_char_s cached_char;
+
+#endif
+
+/* The type of cached font/matrix pairs is opaque. */
+#ifndef cached_fm_pair_DEFINED
+# define cached_fm_pair_DEFINED
+typedef struct cached_fm_pair_s cached_fm_pair;
+
+#endif
+
+/* The type of font objects is opaque. */
+#ifndef gs_font_DEFINED
+# define gs_font_DEFINED
+typedef struct gs_font_s gs_font;
+
+#endif
+
+/* The types of memory and null devices may be opaque. */
+#ifndef gx_device_memory_DEFINED
+# define gx_device_memory_DEFINED
+typedef struct gx_device_memory_s gx_device_memory;
+
+#endif
+#ifndef gx_device_null_DEFINED
+# define gx_device_null_DEFINED
+typedef struct gx_device_null_s gx_device_null;
+
+#endif
+
+/*
+ * Define the stack for composite fonts.
+ * If the current font is not composite, depth = -1.
+ * If the current font is composite, 0 <= depth <= max_font_depth.
+ * items[0] through items[depth] are occupied.
+ * items[0].font is the root font; items[0].index = 0.
+ * The root font must be composite, but may be of any map type.
+ * items[0..N-1] are modal composite fonts, for some N <= depth.
+ * items[N..depth-1] are non-modal composite fonts.
+ * items[depth] is a base (non-composite) font.
+ * Note that if depth >= 0, the font member of the graphics state
+ * for a base font BuildChar/Glyph is the same as items[depth].font.
+ */
+#define max_font_depth 5
+typedef struct gx_font_stack_item_s {
+ gs_font *font; /* font at this level */
+ uint index; /* index of this font in parent's */
+ /* Encoding */
+} gx_font_stack_item;
+typedef struct gx_font_stack_s {
+ int depth;
+ gx_font_stack_item items[1 + max_font_depth];
+} gx_font_stack;
+
+/* An enumeration object for string display. */
+typedef enum {
+ sws_none,
+ sws_cache, /* setcachedevice[2] */
+ sws_no_cache, /* setcharwidth */
+ sws_cache_width_only /* setcharwidth for xfont char */
+} show_width_status;
+struct gs_show_enum_s {
+ /* Put this first for subclassing. */
+ gs_text_enum_common; /* (procs, text, index) */
+
+#define SHOW_IS(penum, op_mask)\
+ (((penum)->text.operation & (op_mask)) != 0)
+#define SHOW_IS_ALL_OF(penum, op_mask)\
+ (((penum)->text.operation & (op_mask)) == (op_mask))
+ /*
+ * The comments next to the following macros indicate the
+ * corresponding test in pre-5.24 filesets.
+ */
+#define SHOW_IS_ADD_TO_ALL(penum) /* add */\
+ SHOW_IS(penum, TEXT_ADD_TO_ALL_WIDTHS)
+#define SHOW_IS_ADD_TO_SPACE(penum) /* wchr != no_char */\
+ SHOW_IS(penum, TEXT_ADD_TO_SPACE_WIDTH)
+#define SHOW_IS_DO_KERN(penum) /* do_kern */\
+ SHOW_IS(penum, TEXT_INTERVENE)
+#define SHOW_IS_XYCSHOW(penum) /* do_kern < 0 */\
+ (SHOW_IS_DO_KERN(penum) &&\
+ SHOW_IS(penum, TEXT_REPLACE_X_WIDTHS | TEXT_REPLACE_Y_WIDTHS | TEXT_DO_NONE))
+#define SHOW_IS_SLOW(penum) /* slow_show */\
+ SHOW_IS(penum, TEXT_ADD_TO_ALL_WIDTHS | TEXT_ADD_TO_SPACE_WIDTH | TEXT_INTERVENE)
+#define SHOW_IS_DRAWING(penum) /* !stringwidth_flag */\
+ !SHOW_IS(penum, TEXT_DO_NONE)
+#define SHOW_IS_STRINGWIDTH(penum) /* stringwidth_flag > 0 */\
+ SHOW_IS_ALL_OF(penum, TEXT_DO_NONE | TEXT_RETURN_WIDTH)
+
+ /* Following are set at creation time */
+ gs_state *pgs;
+ int level; /* save the level of pgs */
+ gs_char_path_mode charpath_flag;
+ gs_state *show_gstate; /* for setting pgs->show_gstate */
+ /* at returns/callouts */
+ int can_cache; /* -1 if can't use cache at all, */
+ /* 0 if can read but not load, */
+ /* 1 if can read and load */
+ gs_int_rect ibox; /* int version of quick-check */
+ /* (inner) clipping box */
+ gs_int_rect obox; /* int version of (outer) clip box */
+ int ftx, fty; /* transformed font translation */
+ /* Following are updated dynamically */
+ gs_glyph(*encode_char) (P3(gs_show_enum *, gs_font *, gs_char *));
+ /* copied from font, */
+ /* except for glyphshow */
+ gs_log2_scale_point log2_suggested_scale; /* suggested scaling */
+ /* factors for oversampling, */
+ /* based on FontBBox and CTM */
+ gx_device_memory *dev_cache; /* cache device */
+ gx_device_memory *dev_cache2; /* underlying alpha memory device, */
+ /* if dev_cache is an alpha buffer */
+ gx_device_null *dev_null; /* null device for stringwidth */
+ /*uint index; *//* index within string */
+ gs_char current_char; /* current char for render or move */
+ gs_glyph current_glyph; /* current glyph ditto */
+ gs_fixed_point wxy; /* width of current char */
+ /* in device coords */
+ gs_fixed_point origin; /* unrounded origin of current char */
+ /* in device coords, needed for */
+ /* charpath and WMode=1 */
+ cached_char *cc; /* being accumulated */
+ gs_point width; /* total width of string, set at end */
+ show_width_status width_status;
+ gs_log2_scale_point log2_current_scale;
+ gx_font_stack fstack;
+ int (*continue_proc) (P1(gs_show_enum *)); /* continuation procedure */
+};
+
+#define gs_show_enum_s_DEFINED
+#define private_st_gs_show_enum() /* in gschar.c */\
+ gs_private_st_composite(st_gs_show_enum, gs_show_enum, "gs_show_enum",\
+ show_enum_enum_ptrs, show_enum_reloc_ptrs)
+
+/* Cached character procedures (in gxccache.c and gxccman.c) */
+#ifndef gs_font_dir_DEFINED
+# define gs_font_dir_DEFINED
+typedef struct gs_font_dir_s gs_font_dir;
+
+#endif
+cached_char *
+ gx_alloc_char_bits(P7(gs_font_dir *, gx_device_memory *, gx_device_memory *, ushort, ushort, const gs_log2_scale_point *, int));
+void gx_open_cache_device(P2(gx_device_memory *, cached_char *));
+void gx_free_cached_char(P2(gs_font_dir *, cached_char *));
+void gx_add_cached_char(P5(gs_font_dir *, gx_device_memory *, cached_char *, cached_fm_pair *, const gs_log2_scale_point *));
+void gx_add_char_bits(P3(gs_font_dir *, cached_char *, const gs_log2_scale_point *));
+cached_char *
+ gx_lookup_cached_char(P5(const gs_font *, const cached_fm_pair *, gs_glyph, int, int));
+cached_char *
+ gx_lookup_xfont_char(P6(const gs_state *, cached_fm_pair *, gs_char, gs_glyph, const gx_xfont_callbacks *, int));
+int gx_image_cached_char(P2(gs_show_enum *, cached_char *));
+
+#endif /* gxchar_INCLUDED */
diff --git a/pstoraster/gxcht.c b/pstoraster/gxcht.c
new file mode 100644
index 000000000..88f4a3118
--- /dev/null
+++ b/pstoraster/gxcht.c
@@ -0,0 +1,710 @@
+/* Copyright (C) 1993, 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$ */
+/* Color halftone rendering for Ghostscript imaging library */
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsutil.h" /* for id generation */
+#include "gxarith.h"
+#include "gxfixed.h"
+#include "gxmatrix.h"
+#include "gxdevice.h"
+#include "gxcmap.h"
+#include "gxdcolor.h"
+#include "gxistate.h"
+#include "gzht.h"
+
+/* Define the size of the tile buffer allocated on the stack. */
+#define tile_longs_LARGE 256
+#define tile_longs_SMALL 64
+#if arch_small_memory
+# define tile_longs_allocated tile_longs_SMALL
+# define tile_longs tile_longs_SMALL
+#else
+# define tile_longs_allocated tile_longs_LARGE
+# define tile_longs\
+ (gs_debug_c('.') ? tile_longs_SMALL : tile_longs_LARGE)
+#endif
+
+/* Define the colored halftone device color type. */
+gs_private_st_ptrs1(st_dc_ht_colored, gx_device_color, "dc_ht_colored",
+ dc_ht_colored_enum_ptrs, dc_ht_colored_reloc_ptrs, colors.colored.c_ht);
+private dev_color_proc_load(gx_dc_ht_colored_load);
+private dev_color_proc_fill_rectangle(gx_dc_ht_colored_fill_rectangle);
+private dev_color_proc_equal(gx_dc_ht_colored_equal);
+const gx_device_color_type_t gx_dc_type_data_ht_colored = {
+ &st_dc_ht_colored,
+ gx_dc_ht_colored_load, gx_dc_ht_colored_fill_rectangle,
+ gx_dc_default_fill_masked, gx_dc_ht_colored_equal
+};
+#undef gx_dc_type_ht_colored
+const gx_device_color_type_t *const gx_dc_type_ht_colored =
+ &gx_dc_type_data_ht_colored;
+#define gx_dc_type_ht_colored (&gx_dc_type_data_ht_colored)
+
+/* Forward references. */
+private void set_ht_colors(P7(gx_color_index[16], gx_strip_bitmap *[4],
+ const gx_device_color *, gx_device *,
+ gx_ht_cache *[4], int, int *));
+private void set_color_ht(P9(gx_strip_bitmap *, int, int, int, int, int, int,
+ const gx_color_index[16],
+ const gx_strip_bitmap *[4]));
+
+/* Define a table for expanding 8x1 bits to 8x4. */
+private const bits32 expand_8x1_to_8x4[256] = {
+#define x16(c)\
+ c+0, c+1, c+0x10, c+0x11, c+0x100, c+0x101, c+0x110, c+0x111,\
+ c+0x1000, c+0x1001, c+0x1010, c+0x1011, c+0x1100, c+0x1101, c+0x1110, c+0x1111
+ x16(0x00000000), x16(0x00010000), x16(0x00100000), x16(0x00110000),
+ x16(0x01000000), x16(0x01010000), x16(0x01100000), x16(0x01110000),
+ x16(0x10000000), x16(0x10010000), x16(0x10100000), x16(0x10110000),
+ x16(0x11000000), x16(0x11010000), x16(0x11100000), x16(0x11110000)
+#undef x16
+};
+
+/* Prepare to use a colored halftone, by loading the default cache. */
+private int
+gx_dc_ht_colored_load(gx_device_color * pdevc, const gs_imager_state * pis,
+ gx_device * ignore_dev, gs_color_select_t select)
+{
+ gx_device_halftone *pdht = pis->dev_ht;
+ gx_ht_order *porder = &pdht->components[0].corder;
+ gx_ht_cache *pcache = pis->ht_cache;
+
+ if (pcache->order.bits != porder->bits)
+ gx_ht_init_cache(pcache, porder);
+ /* Set the cache pointers in the default order. */
+ pdht->order.cache = porder->cache = pcache;
+ return 0;
+}
+
+/* Fill a rectangle with a colored halftone. */
+/* Note that we treat this as "texture" for RasterOp. */
+private int
+gx_dc_ht_colored_fill_rectangle(const gx_device_color * pdevc,
+ int x, int y, int w, int h,
+ gx_device * dev, gs_logical_operation_t lop,
+ const gx_rop_source_t * source)
+{
+ ulong tbits[tile_longs_allocated];
+ const uint tile_bytes = tile_longs * size_of(long);
+ gx_strip_bitmap tiles;
+ gx_rop_source_t no_source;
+ const gx_device_halftone *pdht = pdevc->colors.colored.c_ht;
+ int depth = dev->color_info.depth;
+ int nplanes = dev->color_info.num_components;
+ gx_color_index colors[16];
+ gx_strip_bitmap *sbits[4];
+ gx_ht_cache *caches[4];
+ int code = 0;
+ int raster;
+ uint size_x;
+ int dw, dh;
+ int lw = pdht->lcm_width, lh = pdht->lcm_height;
+ int plane_mask;
+ bool no_rop;
+
+ if (w <= 0 || h <= 0)
+ return 0;
+ /* Colored halftone patterns are unconditionally opaque. */
+ lop &= ~lop_T_transparent;
+ tiles.data = (byte *) tbits;
+ if (pdht->components == 0)
+ caches[0] = caches[1] = caches[2] = caches[3] = pdht->order.cache;
+ else {
+ gx_ht_order_component *pocs = pdht->components;
+
+ caches[0] = pocs[pdht->color_indices[0]].corder.cache;
+ caches[1] = pocs[pdht->color_indices[1]].corder.cache;
+ caches[2] = pocs[pdht->color_indices[2]].corder.cache;
+ caches[3] = pocs[pdht->color_indices[3]].corder.cache;
+ }
+ set_ht_colors(colors, sbits, pdevc, dev, caches, nplanes, &plane_mask);
+ if (!(plane_mask & (plane_mask - 1))) {
+ /*
+ * At most one plane is not solid-color: we can treat this as a
+ * binary halftone (or, anomalously, a pure color).
+ */
+ gx_device_color devc;
+
+ if (plane_mask == 0 ) {
+ color_set_pure(&devc, colors[0]);
+ } else {
+ int plane = small_exact_log2(plane_mask);
+ gx_ht_tile tile;
+
+ tile.tiles = *sbits[plane]; /* already rendered */
+ tile.level = pdevc->colors.colored.c_level[plane];
+ color_set_binary_tile(&devc, colors[0], colors[plane_mask], &tile);
+ devc.phase = pdevc->phase;
+ }
+ return gx_device_color_fill_rectangle(&devc, x, y, w, h, dev, lop,
+ source);
+ }
+
+ no_rop = source == NULL && lop_no_S_is_T(lop);
+ /*
+ * If the LCM of the plane cell sizes is smaller than the rectangle
+ * being filled, compute a single tile and let tile_rectangle do the
+ * replication.
+ */
+ if ((w > lw || h > lh) &&
+ (raster = bitmap_raster(lw * depth)) <= tile_bytes / lh
+ ) {
+ /*
+ * The only reason we need to do fit_fill here is that if the
+ * device is a clipper, the caller might be counting on it to do
+ * all necessary clipping. Actually, we should clip against the
+ * device's clipping box, not the default....
+ */
+ fit_fill(dev, x, y, w, h);
+ /* Check to make sure we still have a big rectangle. */
+ if (w > lw || h > lh) {
+ tiles.raster = raster;
+ tiles.rep_width = tiles.size.x = lw;
+ tiles.rep_height = tiles.size.y = lh;
+ tiles.id = gs_next_ids(1);
+ tiles.rep_shift = tiles.shift = 0;
+ /* See below for why we need to cast bits. */
+ set_color_ht(&tiles, 0, 0, lw, lh,
+ depth, plane_mask, colors,
+ (const gx_strip_bitmap **)sbits);
+ if (no_rop)
+ return (*dev_proc(dev, strip_tile_rectangle)) (dev, &tiles,
+ x, y, w, h,
+ gx_no_color_index, gx_no_color_index,
+ pdevc->phase.x, pdevc->phase.y);
+ if (source == NULL)
+ set_rop_no_source(source, no_source, dev);
+ return (*dev_proc(dev, strip_copy_rop)) (dev, source->sdata,
+ source->sourcex, source->sraster, source->id,
+ (source->use_scolors ? source->scolors : NULL),
+ &tiles, NULL,
+ x, y, w, h,
+ pdevc->phase.x, pdevc->phase.y,
+ lop);
+ }
+ }
+ tiles.id = gx_no_bitmap_id;
+ size_x = w * depth;
+ raster = bitmap_raster(size_x);
+ if (raster > tile_bytes) {
+ /*
+ * We can't even do an entire line at once. See above for
+ * why we do the X equivalent of fit_fill here.
+ */
+ if (x < 0)
+ w += x, x = 0;
+ if (x > dev->width - w)
+ w = dev->width - x;
+ if (w <= 0)
+ return 0;
+ size_x = w * depth;
+ raster = bitmap_raster(size_x);
+ if (raster > tile_bytes) {
+ /* We'll have to do a partial line. */
+ dw = tile_bytes * 8 / depth;
+ size_x = dw * depth;
+ raster = bitmap_raster(size_x);
+ dh = 1;
+ goto fit;
+ }
+ }
+ /* Do as many lines as will fit. */
+ dw = w;
+ dh = tile_bytes / raster;
+ if (dh > h)
+ dh = h;
+fit: /* Now the tile will definitely fit. */
+ tiles.raster = raster;
+ tiles.rep_width = tiles.size.x = size_x / depth;
+ tiles.rep_shift = tiles.shift = 0;
+ while (w) {
+ int cy = y, ch = dh, left = h;
+
+ tiles.rep_height = tiles.size.y = ch;
+ for (;;) {
+ /*
+ * The cast in the following statement is bogus,
+ * but some compilers won't accept an array type,
+ * and won't accept the ** type without a cast.
+ */
+ set_color_ht(&tiles, x + pdevc->phase.x, cy + pdevc->phase.y,
+ dw, ch, depth, plane_mask, colors,
+ (const gx_strip_bitmap **)sbits);
+ if (no_rop) {
+ code = (*dev_proc(dev, copy_color))
+ (dev, tiles.data, 0, raster, gx_no_bitmap_id,
+ x, cy, dw, ch);
+ } else {
+ if (source == NULL)
+ set_rop_no_source(source, no_source, dev);
+ return (*dev_proc(dev, strip_copy_rop))
+ (dev, source->sdata, source->sourcex, source->sraster,
+ source->id,
+ (source->use_scolors ? source->scolors : NULL),
+ &tiles, NULL, x, cy, dw, ch, 0, 0, lop);
+ }
+ if (code < 0)
+ return code;
+ if (!(left -= ch))
+ break;
+ cy += ch;
+ if (ch > left)
+ tiles.rep_height = tiles.size.y = ch = left;
+ }
+ if (!(w -= dw))
+ break;
+ x += dw;
+ if (dw > w)
+ dw = w, tiles.rep_width = tiles.size.x = size_x / depth;
+ }
+ return code;
+}
+
+/*
+ * We construct color halftone tiles out of 3 or 4 "planes".
+ * Each plane specifies halftoning for one component (R/G/B or C/M/Y/K).
+ */
+
+private const ulong ht_no_bitmap_data[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0
+};
+private gx_strip_bitmap ht_no_bitmap;
+private const gx_strip_bitmap ht_no_bitmap_init = {
+ 0, sizeof(ulong),
+ {sizeof(ulong) * 8, countof(ht_no_bitmap_data)},
+ gx_no_bitmap_id, 1, 1, 0, 0
+};
+
+void
+gs_gxcht_init(gs_memory_t *mem)
+{
+ ht_no_bitmap = ht_no_bitmap_init;
+ ht_no_bitmap.data = (byte *)ht_no_bitmap_data; /* actually const */
+}
+
+/* Set up the colors and the individual plane halftone bitmaps. */
+private void
+set_ht_colors(gx_color_index colors[16], gx_strip_bitmap * sbits[4],
+ const gx_device_color * pdc, gx_device * dev,
+ gx_ht_cache * caches[4], int nplanes, int *pmask)
+{
+ gx_color_value v[2][4];
+ gx_color_value max_color = dev->color_info.dither_colors - 1;
+ int plane_mask = 0;
+ /*
+ * NB: the halftone orders are all set up for an additive color space.
+ * To use these work with a cmyk color space, it is necessary to
+ * invert both the color level and the color pair. Note that if the
+ * original color was provided an additive space, this will reverse
+ * (in an approximate sense) the color conversion performed to
+ * express the color in cmyk space.
+ */
+ bool invert = dev->color_info.num_components == 4; /****** HACK ******/
+
+#define set_plane_color(i)\
+ BEGIN\
+ uint q = pdc->colors.colored.c_base[i];\
+ uint r = pdc->colors.colored.c_level[i];\
+\
+ v[0][i] = fractional_color(q, max_color);\
+ if (r == 0)\
+ v[1][i] = v[0][i], sbits[i] = &ht_no_bitmap;\
+ else if (!invert) {\
+ v[1][i] = fractional_color(q + 1, max_color);\
+ sbits[i] = &gx_render_ht(caches[i], r)->tiles;\
+ plane_mask |= 1 << (i);\
+ } else { \
+ const gx_device_halftone * pdht = pdc->colors.colored.c_ht;\
+ int nlevels = 0; \
+ \
+ nlevels = pdht->components[pdht->color_indices[i]].corder.num_levels;\
+ v[1][i] = v[0][i]; \
+ v[0][i] = fractional_color(q + 1, max_color); \
+ sbits[i] = &gx_render_ht(caches[i], nlevels - r)->tiles; \
+ plane_mask |= 1 << (i); \
+ }\
+ END
+#define map8(m) m(0), m(1), m(2), m(3), m(4), m(5), m(6), m(7)
+ set_plane_color(0);
+ set_plane_color(1);
+ set_plane_color(2);
+ if (nplanes == 3) {
+#define map_rgb(i)\
+ colors[i] = map1rgb(v[(i) & 1][0], v[((i) & 2) >> 1][1], v[(i) >> 2][2])
+ gx_color_value alpha = pdc->colors.colored.alpha;
+
+ if (alpha == gx_max_color_value) {
+#ifdef DEBUG
+# define map1rgb(r, g, b) gx_map_rgb_color(dev, r, g, b)
+#else
+ dev_proc_map_rgb_color((*map)) =
+ dev_proc(dev, map_rgb_color);
+# define map1rgb(r, g, b) (*map)(dev, r, g, b)
+#endif
+ map8(map_rgb);
+#undef map1rgb
+ } else {
+#ifdef DEBUG
+# define map1rgb(r, g, b) gx_map_rgb_alpha_color(dev, r, g, b, alpha)
+#else
+ dev_proc_map_rgb_alpha_color((*map)) =
+ dev_proc(dev, map_rgb_alpha_color);
+# define map1rgb(r, g, b) (*map)(dev, r, g, b, alpha)
+#endif
+ map8(map_rgb);
+#undef map1rgb
+ }
+ } else {
+#define map_cmyk(i)\
+ colors[i] = map1cmyk(v[(i) & 1][0], v[((i) & 2) >> 1][1],\
+ v[((i) & 4) >> 2][2], v[(i) >> 3][3])
+#ifdef DEBUG
+# define map1cmyk(r, g, b, w) gx_map_cmyk_color(dev, r, g, b, w)
+#else
+ dev_proc_map_cmyk_color((*map)) =
+ dev_proc(dev, map_cmyk_color);
+# define map1cmyk(r, g, b, w) (*map)(dev, r, g, b, w)
+#endif
+ set_plane_color(3);
+ /*
+ * For CMYK output, especially if the input was RGB, it's
+ * common for one or more of the components to be zero.
+ * Each zero component can cut the cost of color mapping in
+ * half, so it's worth doing a little checking here.
+ */
+#define m(i) map_cmyk(i)
+ switch (plane_mask) {
+ case 15:
+ m(15); m(14); m(13); m(12);
+ m(11); m(10); m(9); m(8);
+ case 7:
+ m(7); m(6); m(5); m(4);
+c3: case 3:
+ m(3); m(2);
+c1: case 1:
+ m(1);
+ break;
+ case 14:
+ m(14); m(12); m(10); m(8);
+ case 6:
+ m(6); m(4);
+c2: case 2:
+ m(2);
+ break;
+ case 13:
+ m(13); m(12); m(9); m(8);
+ case 5:
+ m(5); m(4);
+ goto c1;
+ case 12:
+ m(12); m(8);
+ case 4:
+ m(4);
+ break;
+ case 11:
+ m(11); m(10); m(9); m(8);
+ goto c3;
+ case 10:
+ m(10); m(8);
+ goto c2;
+ case 9:
+ m(9); m(8);
+ goto c1;
+ case 8:
+ m(8);
+ break;
+ case 0:;
+ }
+ m(0);
+#undef m
+#undef map1cmyk
+ }
+#undef map8
+#undef set_plane_color
+ *pmask = plane_mask;
+}
+
+/* Define the bookkeeping structure for each plane of halftone rendering. */
+typedef struct tile_cursor_s {
+ int tile_shift; /* X shift per copy of tile */
+ int xoffset;
+ int xshift;
+ uint xbytes;
+ int xbits;
+ const byte *row;
+ const byte *tdata;
+ uint raster;
+ const byte *data;
+ int bit_shift;
+} tile_cursor_t;
+
+/* Initialize one plane cursor. */
+private void
+init_tile_cursor(int i, tile_cursor_t *ptc, const gx_strip_bitmap *btile,
+ int endx, int lasty)
+{
+ int tw = btile->size.x;
+ int bx = ((ptc->tile_shift = btile->shift) == 0 ? endx :
+ endx + lasty / btile->size.y * ptc->tile_shift) % tw;
+ int by = lasty % btile->size.y;
+
+ ptc->xoffset = bx >> 3;
+ ptc->xshift = 8 - (bx & 7);
+ ptc->xbytes = (tw - 1) >> 3;
+ ptc->xbits = ((tw - 1) & 7) + 1;
+ ptc->tdata = btile->data;
+ ptc->raster = btile->raster;
+ ptc->row = ptc->tdata + by * ptc->raster;
+ if_debug5('h', "[h]plane %d: size=%d,%d bx=%d by=%dn",
+ i, tw, btile->size.y, bx, by);
+}
+
+/* Render the combined halftone. */
+private void
+ set_color_ht(
+ gx_strip_bitmap * ctiles, /* the output tile; data, raster, size are set */
+ int px, /* the initial phase of the output tile */
+ int py,
+ int w, /* how much of the tile to set */
+ int h,
+ int depth, /* depth of tile (4, 8, 16, 24, 32) */
+ int plane_mask, /* which planes are halftoned */
+ const gx_color_index colors[16], /* the actual colors for the tile, */
+ /* actually [1 << nplanes] */
+ const gx_strip_bitmap * sbits[4] /* the bitmaps for the planes, */
+ /* actually [nplanes] */
+) {
+ /* Note that the planes are specified in the order RGB or CMYK, but */
+ /* the indices used for the internal colors array are BGR or KYMC. */
+
+ int x, y;
+ tile_cursor_t cursor[4];
+ int dbytes = depth >> 3;
+ uint dest_raster = ctiles->raster;
+ byte *dest_row =
+ ctiles->data + dest_raster * (h - 1) + (w * depth) / 8;
+
+ if_debug6('h',
+ "[h]color_ht: x=%d y=%d w=%d h=%d plane_mask=%d depth=%d\n",
+ px, py, w, h, plane_mask, depth);
+
+ /* Do one-time cursor initialization. */
+ {
+ int endx = w + px;
+ int lasty = h - 1 + py;
+
+ if (plane_mask & 1)
+ init_tile_cursor(0, &cursor[0], sbits[0], endx, lasty);
+ if (plane_mask & 2)
+ init_tile_cursor(1, &cursor[1], sbits[1], endx, lasty);
+ if (plane_mask & 4)
+ init_tile_cursor(2, &cursor[2], sbits[2], endx, lasty);
+ if (plane_mask & 8)
+ init_tile_cursor(3, &cursor[3], sbits[3], endx, lasty);
+ }
+
+ /* Now compute the actual tile. */
+ for (y = h; ; dest_row -= dest_raster) {
+ byte *dest = dest_row;
+
+#define set_row(c)\
+ (c.data = c.row + c.xoffset,\
+ c.bit_shift = c.xshift)
+ if (plane_mask & 1)
+ set_row(cursor[0]);
+ if (plane_mask & 2)
+ set_row(cursor[1]);
+ if (plane_mask & 4)
+ set_row(cursor[2]);
+ if (plane_mask & 8)
+ set_row(cursor[3]);
+#undef set_row
+ --y;
+ for (x = w; x > 0;) {
+ bits32 indices;
+ int nx, i;
+ register uint bits;
+
+/* Get the next byte's worth of bits. Note that there may be */
+/* excess bits set beyond the 8th. */
+#define next_bits(c)\
+{ if ( c.data > c.row )\
+ { bits = ((c.data[-1] << 8) | *c.data) >> c.bit_shift;\
+ c.data--;\
+ }\
+ else\
+ { bits = *c.data >> c.bit_shift;\
+ c.data += c.xbytes;\
+ if ( (c.bit_shift -= c.xbits) < 0 )\
+ { bits |= *c.data << -c.bit_shift;\
+ c.bit_shift += 8;\
+ }\
+ else\
+ { bits |= ((c.data[-1] << 8) | *c.data) >> c.bit_shift;\
+ c.data--;\
+ }\
+ }\
+}
+ if (plane_mask & 1) {
+ next_bits(cursor[0]);
+ indices = expand_8x1_to_8x4[bits & 0xff];
+ } else
+ indices = 0;
+ if (plane_mask & 2) {
+ next_bits(cursor[1]);
+ indices |= expand_8x1_to_8x4[bits & 0xff] << 1;
+ }
+ if (plane_mask & 4) {
+ next_bits(cursor[2]);
+ indices |= expand_8x1_to_8x4[bits & 0xff] << 2;
+ }
+ if (plane_mask & 8) {
+ next_bits(cursor[3]);
+ indices |= expand_8x1_to_8x4[bits & 0xff] << 3;
+ }
+#undef next_bits
+ nx = min(x, 8); /* 1 <= nx <= 8 */
+ x -= nx;
+ switch (dbytes) {
+ case 0: /* 4 */
+ i = nx;
+ if ((x + nx) & 1) {
+ /* First pixel is even nibble. */
+ *dest = (*dest & 0xf) +
+ ((byte)colors[indices & 0xf] << 4);
+ indices >>= 4;
+ --i;
+ }
+ /* Now 0 <= i <= 8. */
+ for (; (i -= 2) >= 0; indices >>= 8)
+ *--dest =
+ (byte)colors[indices & 0xf] +
+ ((byte)colors[(indices >> 4) & 0xf]
+ << 4);
+ /* Check for final odd nibble. */
+ if (i & 1)
+ *--dest = (byte)colors[indices & 0xf];
+ break;
+ case 4: /* 32 */
+ for (i = nx; --i >= 0; indices >>= 4) {
+ bits32 tcolor = (bits32)colors[indices & 0xf];
+
+ dest -= 4;
+ dest[3] = (byte)tcolor;
+ dest[2] = (byte)(tcolor >> 8);
+ tcolor >>= 16;
+ dest[1] = (byte)tcolor;
+ dest[0] = (byte)(tcolor >> 8);
+ }
+ break;
+ case 3: /* 24 */
+ for (i = nx; --i >= 0; indices >>= 4) {
+ bits32 tcolor = (bits32)colors[indices & 0xf];
+
+ dest -= 3;
+ dest[2] = (byte) tcolor;
+ dest[1] = (byte)(tcolor >> 8);
+ dest[0] = (byte)(tcolor >> 16);
+ }
+ break;
+ case 2: /* 16 */
+ for (i = nx; --i >= 0; indices >>= 4) {
+ uint tcolor =
+ (uint)colors[indices & 0xf];
+
+ dest -= 2;
+ dest[1] = (byte)tcolor;
+ dest[0] = (byte)(tcolor >> 8);
+ }
+ break;
+ case 1: /* 8 */
+ for (i = nx; --i >= 0; indices >>= 4)
+ *--dest = (byte)colors[indices & 0xf];
+ break;
+ }
+ }
+ if (y == 0)
+ break;
+
+#define step_row(c, i)\
+ BEGIN\
+ if ( c.row > c.tdata )\
+ c.row -= c.raster;\
+ else /* wrap around to end of tile, taking shift into account */\
+ { c.row += c.raster * (sbits[i]->size.y - 1);\
+ if ( c.tile_shift )\
+ { if ( (c.xshift += c.tile_shift) >= 8 )\
+ { if ( (c.xoffset -= c.xshift >> 3) < 0 )\
+ { /* wrap around in X */\
+ int bx = (c.xoffset << 3) + 8 - (c.xshift & 7) +\
+ sbits[i]->size.x;\
+ c.xoffset = bx >> 3;\
+ c.xshift = 8 - (bx & 7);\
+ }\
+ else\
+ c.xshift &= 7;\
+ }\
+ }\
+ }\
+ END
+
+ if (plane_mask & 1)
+ step_row(cursor[0], 0);
+ if (plane_mask & 2)
+ step_row(cursor[1], 1);
+ if (plane_mask & 4)
+ step_row(cursor[2], 2);
+ if (plane_mask & 8)
+ step_row(cursor[3], 3);
+#undef step_row
+ }
+}
+
+/* Compare two colored halftones for equality. */
+private bool
+gx_dc_ht_colored_equal(const gx_device_color * pdevc1,
+ const gx_device_color * pdevc2)
+{
+ uint num_comp;
+
+ if (pdevc2->type != pdevc1->type ||
+ pdevc1->colors.colored.c_ht != pdevc2->colors.colored.c_ht ||
+ pdevc1->colors.colored.alpha != pdevc2->colors.colored.alpha ||
+ pdevc1->phase.x != pdevc2->phase.x ||
+ pdevc1->phase.y != pdevc2->phase.y
+ )
+ return false;
+ num_comp = pdevc1->colors.colored.c_ht->num_comp;
+ return
+ !memcmp(pdevc1->colors.colored.c_base,
+ pdevc2->colors.colored.c_base,
+ num_comp * sizeof(pdevc1->colors.colored.c_base[0])) &&
+ !memcmp(pdevc1->colors.colored.c_level,
+ pdevc2->colors.colored.c_level,
+ num_comp * sizeof(pdevc1->colors.colored.c_level[0]));
+}
diff --git a/pstoraster/gxcindex.h b/pstoraster/gxcindex.h
new file mode 100644
index 000000000..195c28813
--- /dev/null
+++ b/pstoraster/gxcindex.h
@@ -0,0 +1,91 @@
+/* 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$ */
+/* Define the device color index type and macros */
+
+#ifndef gxcindex_INCLUDED
+# define gxcindex_INCLUDED
+
+#include "gsbitops.h" /* for sample_store macros */
+
+/*
+ * Internally, a (pure) device color is represented by opaque values of
+ * type gx_color_index, which are tied to the specific device. The driver
+ * maps between these values and RGB[alpha] or CMYK values. In this way,
+ * the driver can convert RGB values to its most natural color representation,
+ * and have the graphics library cache the result.
+ */
+
+/* Define the type for device color indices. */
+typedef unsigned long gx_color_index;
+
+#define arch_log2_sizeof_color_index arch_log2_sizeof_long
+#define arch_sizeof_color_index arch_sizeof_long
+
+/* Define the 'transparent' color index. */
+#define gx_no_color_index_value (-1) /* no cast -> can be used in #if */
+
+/* The SGI C compiler provided with Irix 5.2 gives error messages */
+/* if we use the proper definition of gx_no_color_index: */
+/*#define gx_no_color_index ((gx_color_index)gx_no_color_index_value) */
+/* Instead, we must spell out the typedef: */
+#define gx_no_color_index ((unsigned long)gx_no_color_index_value)
+
+/*
+ * Define macros for accumulating a scan line of a colored image.
+ * The usage is as follows:
+ * declare_line_accum(line, bpp, xo);
+ * for ( x = xo; x < xe; ++x )
+ * { << compute color at x >>
+ * line_accum(color, bpp);
+ * }
+ * line_accum_copy(dev, line, bpp, xo, xe, raster, y);
+ * This code must be enclosed in { }, since declare_line_accum declares
+ * variables. Supported values of bpp are 1, 2, 4, 8, 12, 16, 24, 32.
+ *
+ * Note that declare_line_accum declares the variables l_dptr, l_dbyte, l_dbit,
+ * and l_xprev. Other code in the loop may use these variables.
+ */
+#define declare_line_accum(line, bpp, xo)\
+ sample_store_declare_setup(l_dptr, l_dbit, l_dbyte, line, 0, bpp);\
+ int l_xprev = (xo)
+#define line_accum(color, bpp)\
+ sample_store_next32(color, l_dptr, l_dbit, bpp, l_dbyte)
+#define line_accum_skip(bpp)\
+ sample_store_skip_next(l_dptr, l_dbit, bpp, l_dbyte)
+#define line_accum_store(bpp)\
+ sample_store_flush(l_dptr, l_dbit, bpp, l_dbyte)
+#define line_accum_copy(dev, line, bpp, xo, xe, raster, y)\
+ if ( (xe) > l_xprev )\
+ { int code;\
+ line_accum_store(bpp);\
+ code = (*dev_proc(dev, copy_color))\
+ (dev, line, l_xprev - (xo), raster,\
+ gx_no_bitmap_id, l_xprev, y, (xe) - l_xprev, 1);\
+ if ( code < 0 )\
+ return code;\
+ }
+
+#endif /* gxcindex_INCLUDED */
diff --git a/pstoraster/gxclbits.c b/pstoraster/gxclbits.c
new file mode 100644
index 000000000..e827fa40a
--- /dev/null
+++ b/pstoraster/gxclbits.c
@@ -0,0 +1,740 @@
+/* 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$ */
+/* Halftone and bitmap writing for command lists */
+#include "memory_.h"
+#include "gx.h"
+#include "gpcheck.h"
+#include "gserrors.h"
+#include "gsbitops.h"
+#include "gxdevice.h"
+#include "gxdevmem.h" /* must precede gxcldev.h */
+#include "gxcldev.h"
+#include "gxfmap.h"
+
+/*
+ * Define when, if ever, to write character bitmaps in all bands.
+ * Set this to:
+ * 0 to always write in all bands;
+ * N to write in all bands when the character has been seen in N+1
+ * bands on a page;
+ * max_ushort to never write in all bands.
+ */
+#define CHAR_ALL_BANDS_COUNT max_ushort
+
+/* ------ Writing ------ */
+
+/*
+ * Determine the (possibly unpadded) width in bytes for writing a bitmap,
+ * per the algorithm in gxcldev.h. If compression_mask has any of the
+ * cmd_mask_compress_any bits set, we assume the bitmap will be compressed.
+ * Return the total size of the bitmap.
+ */
+uint
+clist_bitmap_bytes(uint width_bits, uint height, int compression_mask,
+ uint * width_bytes, uint * raster)
+{
+ uint full_raster = *raster = bitmap_raster(width_bits);
+ uint short_raster = (width_bits + 7) >> 3;
+ uint width_bytes_last;
+
+ if (compression_mask & cmd_mask_compress_any)
+ *width_bytes = width_bytes_last = full_raster;
+ else if (short_raster <= cmd_max_short_width_bytes ||
+ height <= 1 ||
+ (compression_mask & decompress_spread) != 0
+ )
+ *width_bytes = width_bytes_last = short_raster;
+ else
+ *width_bytes = full_raster, width_bytes_last = short_raster;
+ return
+ (height == 0 ? 0 : *width_bytes * (height - 1) + width_bytes_last);
+}
+
+/*
+ * Compress a bitmap, skipping extra padding bytes at the end of each row if
+ * necessary. We require height >= 1, raster >= bitmap_raster(width_bits).
+ */
+private int
+cmd_compress_bitmap(stream_state * st, const byte * data, uint width_bits,
+ uint raster, uint height, stream_cursor_write * pw)
+{
+ uint width_bytes = bitmap_raster(width_bits);
+ int status = 0;
+ stream_cursor_read r;
+
+ r.ptr = data - 1;
+ if (raster == width_bytes) {
+ r.limit = r.ptr + raster * height;
+ status = (*st->template->process) (st, &r, pw, true);
+ } else { /* Compress row-by-row. */
+ uint y;
+
+ for (y = 1; (r.limit = r.ptr + width_bytes), y < height; ++y) {
+ status = (*st->template->process) (st, &r, pw, false);
+ if (status)
+ break;
+ if (r.ptr != r.limit) { /* We don't attempt to handle compressors that */
+ /* require >1 input byte to make progress. */
+ status = -1;
+ break;
+ }
+ r.ptr += raster - width_bytes;
+ }
+ if (status == 0)
+ status = (*st->template->process) (st, &r, pw, true);
+ }
+ if (st->template->release)
+ (*st->template->release) (st);
+ return status;
+}
+
+/*
+ * Put a bitmap in the buffer, compressing if appropriate.
+ * pcls == 0 means put the bitmap in all bands.
+ * Return <0 if error, otherwise the compression method.
+ * A return value of gs_error_limitcheck means that the bitmap was too big
+ * to fit in the command reading buffer.
+ * Note that this leaves room for the command and initial arguments,
+ * but doesn't fill them in.
+ */
+int
+cmd_put_bits(gx_device_clist_writer * cldev, gx_clist_state * pcls,
+ const byte * data, uint width_bits, uint height, uint raster, int op_size,
+ int compression_mask, byte ** pdp, uint * psize)
+{
+ uint short_raster, full_raster;
+ uint short_size =
+ clist_bitmap_bytes(width_bits, height,
+ compression_mask & ~cmd_mask_compress_any,
+ &short_raster, &full_raster);
+ uint uncompressed_raster;
+ uint uncompressed_size =
+ clist_bitmap_bytes(width_bits, height, compression_mask,
+ &uncompressed_raster, &full_raster);
+ uint max_size = cbuf_size - op_size;
+ gs_memory_t *mem = (cldev->memory ? cldev->memory : &gs_memory_default);
+ byte *dp;
+ int compress = 0;
+
+ /*
+ * See if compressing the bits is possible and worthwhile.
+ * Currently we can't compress if the compressed data won't fit in
+ * the command reading buffer, or if the decompressed data won't fit
+ * in the buffer and decompress_elsewhere isn't set.
+ */
+ if (short_size >= 50 &&
+ (compression_mask & cmd_mask_compress_any) != 0 &&
+ (uncompressed_size <= max_size ||
+ (compression_mask & decompress_elsewhere) != 0)
+ ) {
+ union ss_ {
+ stream_state ss;
+ stream_CFE_state cf;
+ stream_RLE_state rl;
+ } sstate;
+ int code;
+
+ *psize = op_size + uncompressed_size;
+ code = (pcls != 0 ?
+ set_cmd_put_op(dp, cldev, pcls, 0, *psize) :
+ set_cmd_put_all_op(dp, cldev, 0, *psize));
+ if (code < 0)
+ return code;
+ cmd_uncount_op(0, *psize);
+ /*
+ * Note that we currently keep all the padding if we are
+ * compressing. This is ridiculous, but it's too hard to
+ * change right now.
+ */
+ if (compression_mask & (1 << cmd_compress_cfe)) {
+ /* Try CCITTFax compression. */
+ clist_cfe_init(&sstate.cf,
+ uncompressed_raster << 3 /*width_bits*/,
+ mem);
+ sstate.ss.template = &s_CFE_template;
+ compress = cmd_compress_cfe;
+ } else if (compression_mask & (1 << cmd_compress_rle)) {
+ /* Try RLE compression. */
+ clist_rle_init(&sstate.rl);
+ sstate.ss.template = &s_RLE_template;
+ compress = cmd_compress_rle;
+ }
+ if (compress) {
+ byte *wbase = dp + (op_size - 1);
+ stream_cursor_write w;
+
+ /*
+ * We can give up on compressing if we generate too much
+ * output to fit in the command reading buffer, or too
+ * much to make compression worthwhile.
+ */
+ uint wmax = min(uncompressed_size, max_size);
+ int status;
+
+ w.ptr = wbase;
+ w.limit = w.ptr + min(wmax, short_size >> 1);
+ status = cmd_compress_bitmap((stream_state *) & sstate, data,
+ uncompressed_raster << 3 /*width_bits */ ,
+ raster, height, &w);
+ if (status == 0) { /* Use compressed representation. */
+ uint wcount = w.ptr - wbase;
+
+ cmd_shorten_list_op(cldev,
+ (pcls ? &pcls->list : &cldev->band_range_list),
+ uncompressed_size - wcount);
+ *psize = op_size + wcount;
+ goto out;
+ }
+ }
+ if (uncompressed_size > max_size) {
+ cmd_shorten_list_op(cldev,
+ (pcls ? &pcls->list : &cldev->band_range_list),
+ *psize);
+ return_error(gs_error_limitcheck);
+ }
+ if (uncompressed_size != short_size) {
+ cmd_shorten_list_op(cldev,
+ (pcls ? &pcls->list : &cldev->band_range_list),
+ uncompressed_size - short_size);
+ *psize = op_size + short_size;
+ }
+ compress = 0;
+ } else if (uncompressed_size > max_size)
+ return_error(gs_error_limitcheck);
+ else {
+ int code;
+
+ *psize = op_size + short_size;
+ code = (pcls != 0 ?
+ set_cmd_put_op(dp, cldev, pcls, 0, *psize) :
+ set_cmd_put_all_op(dp, cldev, 0, *psize));
+ if (code < 0)
+ return code;
+ cmd_uncount_op(0, *psize);
+ }
+ bytes_copy_rectangle(dp + op_size, short_raster, data, raster,
+ short_raster, height);
+out:
+ *pdp = dp;
+ return compress;
+}
+
+/* Add a command to set the tile size and depth. */
+private uint
+cmd_size_tile_params(const gx_strip_bitmap * tile)
+{
+ return 2 + cmd_size_w(tile->rep_width) + cmd_size_w(tile->rep_height) +
+ (tile->rep_width == tile->size.x ? 0 :
+ cmd_size_w(tile->size.x / tile->rep_width)) +
+ (tile->rep_height == tile->size.y ? 0 :
+ cmd_size_w(tile->size.y / tile->rep_height)) +
+ (tile->rep_shift == 0 ? 0 : cmd_size_w(tile->rep_shift));
+}
+private void
+cmd_store_tile_params(byte * dp, const gx_strip_bitmap * tile, int depth,
+ uint csize)
+{
+ byte *p = dp + 2;
+ byte bd = depth - 1;
+
+ *dp = cmd_count_op(cmd_opv_set_tile_size, csize);
+ p = cmd_put_w(tile->rep_width, p);
+ p = cmd_put_w(tile->rep_height, p);
+ if (tile->rep_width != tile->size.x) {
+ p = cmd_put_w(tile->size.x / tile->rep_width, p);
+ bd |= 0x20;
+ }
+ if (tile->rep_height != tile->size.y) {
+ p = cmd_put_w(tile->size.y / tile->rep_height, p);
+ bd |= 0x40;
+ }
+ if (tile->rep_shift != 0) {
+ cmd_put_w(tile->rep_shift, p);
+ bd |= 0x80;
+ }
+ dp[1] = bd;
+}
+
+/* Add a command to set the tile index. */
+/* This is a relatively high-frequency operation, so we declare it `inline'. */
+inline private int
+cmd_put_tile_index(gx_device_clist_writer *cldev, gx_clist_state *pcls,
+ uint indx)
+{
+ int idelta = indx - pcls->tile_index + 8;
+ byte *dp;
+ int code;
+
+ if (!(idelta & ~15)) {
+ code = set_cmd_put_op(dp, cldev, pcls,
+ cmd_op_delta_tile_index + idelta, 1);
+ if (code < 0)
+ return code;
+ } else {
+ code = set_cmd_put_op(dp, cldev, pcls,
+ cmd_op_set_tile_index + (indx >> 8), 2);
+ if (code < 0)
+ return code;
+ dp[1] = indx & 0xff;
+ }
+ if_debug2('L', "[L]writing index=%u, offset=%lu\n",
+ indx, cldev->tile_table[indx].offset);
+ return 0;
+}
+
+/* If necessary, write out data for a single color map. */
+int
+cmd_put_color_map(gx_device_clist_writer * cldev, cmd_map_index map_index,
+ const gx_transfer_map * map, gs_id * pid)
+{
+ byte *dp;
+ int code;
+
+ if (map == 0) {
+ if (pid && *pid == gs_no_id)
+ return 0; /* no need to write */
+ code = set_cmd_put_all_op(dp, cldev, cmd_opv_set_misc, 2);
+ if (code < 0)
+ return code;
+ dp[1] = cmd_set_misc_map + map_index;
+ if (pid)
+ *pid = gs_no_id;
+ } else {
+ if (pid && map->id == *pid)
+ return 0; /* no need to write */
+ code = set_cmd_put_all_op(dp, cldev, cmd_opv_set_misc,
+ 2 + sizeof(map->values));
+ if (code < 0)
+ return code;
+ dp[1] = cmd_set_misc_map + 0x20 + map_index;
+ memcpy(dp + 2, map->values, sizeof(map->values));
+ if (pid)
+ *pid = map->id;
+ }
+ return 0;
+}
+
+/* ------ Tile cache management ------ */
+
+/* We want consecutive ids to map to consecutive hash slots if possible, */
+/* so we can use a delta representation when setting the index. */
+/* NB that we cannot emit 'delta' style tile indices if VM error recovery */
+/* is in effect, since reader & writer's tile indices may get out of phase */
+/* as a consequence of error recovery occurring. */
+#define tile_id_hash(id) (id)
+#define tile_hash_next(index) ((index) + 413) /* arbitrary large odd # */
+typedef struct tile_loc_s {
+ uint index;
+ tile_slot *tile;
+} tile_loc;
+
+/* Look up a tile or character in the cache. If found, set the index and */
+/* pointer; if not, set the index to the insertion point. */
+private bool
+clist_find_bits(gx_device_clist_writer * cldev, gx_bitmap_id id, tile_loc * ploc)
+{
+ uint index = tile_id_hash(id);
+ const tile_hash *table = cldev->tile_table;
+ uint mask = cldev->tile_hash_mask;
+ ulong offset;
+
+ for (; (offset = table[index &= mask].offset) != 0;
+ index = tile_hash_next(index)
+ ) {
+ tile_slot *tile = (tile_slot *) (cldev->data + offset);
+
+ if (tile->id == id) {
+ ploc->index = index;
+ ploc->tile = tile;
+ return true;
+ }
+ }
+ ploc->index = index;
+ return false;
+}
+
+/* Delete a tile from the cache. */
+private void
+clist_delete_tile(gx_device_clist_writer * cldev, tile_slot * slot)
+{
+ tile_hash *table = cldev->tile_table;
+ uint mask = cldev->tile_hash_mask;
+ uint index = slot->index;
+ ulong offset;
+
+ if_debug2('L', "[L]deleting index=%u, offset=%lu\n",
+ index, (ulong) ((byte *) slot - cldev->data));
+ gx_bits_cache_free(&cldev->bits, (gx_cached_bits_head *) slot,
+ &cldev->chunk);
+ table[index].offset = 0;
+ /* Delete the entry from the hash table. */
+ /* We'd like to move up any later entries, so that we don't need */
+ /* a deleted mark, but it's too difficult to note this in the */
+ /* band list, so instead, we just delete any entries that */
+ /* would need to be moved. */
+ while ((offset = table[index = tile_hash_next(index) & mask].offset) != 0) {
+ tile_slot *tile = (tile_slot *) (cldev->data + offset);
+ tile_loc loc;
+
+ if (!clist_find_bits(cldev, tile->id, &loc)) { /* We didn't find it, so it should be moved into a slot */
+ /* that we just vacated; instead, delete it. */
+ if_debug2('L', "[L]move-deleting index=%u, offset=%lu\n",
+ index, offset);
+ gx_bits_cache_free(&cldev->bits,
+ (gx_cached_bits_head *) (cldev->data + offset),
+ &cldev->chunk);
+ table[index].offset = 0;
+ }
+ }
+}
+
+/* Add a tile to the cache. */
+/* tile->raster holds the raster for the replicated tile; */
+/* we pass the raster of the actual data separately. */
+private int
+clist_add_tile(gx_device_clist_writer * cldev, const gx_strip_bitmap * tiles,
+ uint sraster, int depth)
+{
+ uint raster = tiles->raster;
+ uint size_bytes = raster * tiles->size.y;
+ uint tsize =
+ sizeof(tile_slot) + cldev->tile_band_mask_size + size_bytes;
+ gx_cached_bits_head *slot_head;
+
+#define slot ((tile_slot *)slot_head)
+
+ if (cldev->bits.csize == cldev->tile_max_count) { /* Don't let the hash table get too full: delete an entry. */
+ /* Since gx_bits_cache_alloc returns an entry to delete when */
+ /* it fails, just force it to fail. */
+ gx_bits_cache_alloc(&cldev->bits, (ulong) cldev->chunk.size,
+ &slot_head);
+ if (slot_head == 0) { /* Wrap around and retry. */
+ cldev->bits.cnext = 0;
+ gx_bits_cache_alloc(&cldev->bits, (ulong) cldev->chunk.size,
+ &slot_head);
+#ifdef DEBUG
+ if (slot_head == 0) {
+ lprintf("No entry to delete!\n");
+ return_error(gs_error_Fatal);
+ }
+#endif
+ }
+ clist_delete_tile(cldev, slot);
+ }
+ /* Allocate the space for the new entry, deleting entries as needed. */
+ while (gx_bits_cache_alloc(&cldev->bits, (ulong) tsize, &slot_head) < 0) {
+ if (slot_head == 0) { /* Wrap around. */
+ if (cldev->bits.cnext == 0) { /* Too big to fit. We should probably detect this */
+ /* sooner, since if we get here, we've cleared the */
+ /* cache. */
+ return_error(gs_error_limitcheck);
+ }
+ cldev->bits.cnext = 0;
+ } else
+ clist_delete_tile(cldev, slot);
+ }
+ /* Fill in the entry. */
+ slot->cb_depth = depth;
+ slot->cb_raster = raster;
+ slot->width = tiles->rep_width;
+ slot->height = tiles->rep_height;
+ slot->shift = slot->rep_shift = tiles->rep_shift;
+ slot->x_reps = slot->y_reps = 1;
+ slot->id = tiles->id;
+ memset(ts_mask(slot), 0, cldev->tile_band_mask_size);
+ bytes_copy_rectangle(ts_bits(cldev, slot), raster,
+ tiles->data, sraster,
+ (tiles->rep_width * depth + 7) >> 3,
+ tiles->rep_height);
+ /* Make the hash table entry. */
+ {
+ tile_loc loc;
+
+#ifdef DEBUG
+ if (clist_find_bits(cldev, tiles->id, &loc))
+ lprintf1("clist_find_bits(0x%lx) should have failed!\n",
+ (ulong) tiles->id);
+#else
+ clist_find_bits(cldev, tiles->id, &loc); /* always fails */
+#endif
+ slot->index = loc.index;
+ cldev->tile_table[loc.index].offset =
+ (byte *) slot_head - cldev->data;
+ if_debug2('L', "[L]adding index=%u, offset=%lu\n",
+ loc.index, cldev->tile_table[loc.index].offset);
+ }
+ slot->num_bands = 0;
+ return 0;
+}
+
+/* ------ Driver procedure support ------ */
+
+/* Change the tile parameters (size and depth). */
+/* Currently we do this for all bands at once. */
+private void
+clist_new_tile_params(gx_strip_bitmap * new_tile, const gx_strip_bitmap * tiles,
+ int depth, const gx_device_clist_writer * cldev)
+{ /*
+ * Adjust the replication factors. If we can, we replicate
+ * the tile in X up to 32 bytes, and then in Y up to 4 copies,
+ * as long as we don't exceed a total tile size of 256 bytes,
+ * or more than 255 repetitions in X or Y, or make the tile so
+ * large that not all possible tiles will fit in the cache.
+ * Also, don't attempt Y replication if shifting is required.
+ */
+#define max_tile_reps_x 255
+#define max_tile_bytes_x 32
+#define max_tile_reps_y 4
+#define max_tile_bytes 256
+ uint rep_width = tiles->rep_width;
+ uint rep_height = tiles->rep_height;
+ uint rep_width_bits = rep_width * depth;
+ uint tile_overhead =
+ sizeof(tile_slot) + cldev->tile_band_mask_size;
+ uint max_bytes = cldev->chunk.size / (rep_width_bits * rep_height);
+
+ max_bytes -= min(max_bytes, tile_overhead);
+ if (max_bytes > max_tile_bytes)
+ max_bytes = max_tile_bytes;
+ *new_tile = *tiles;
+ {
+ uint max_bits_x = max_bytes * 8 / rep_height;
+ uint reps_x =
+ min(max_bits_x, max_tile_bytes_x * 8) / rep_width_bits;
+ uint reps_y;
+
+ while (reps_x > max_tile_reps_x)
+ reps_x >>= 1;
+ new_tile->size.x = max(reps_x, 1) * rep_width;
+ new_tile->raster = bitmap_raster(new_tile->size.x * depth);
+ if (tiles->shift != 0)
+ reps_y = 1;
+ else {
+ reps_y = max_bytes / (new_tile->raster * rep_height);
+ if (reps_y > max_tile_reps_y)
+ reps_y = max_tile_reps_y;
+ else if (reps_y < 1)
+ reps_y = 1;
+ }
+ new_tile->size.y = reps_y * rep_height;
+ }
+#undef max_tile_reps_x
+#undef max_tile_bytes_x
+#undef max_tile_reps_y
+#undef max_tile_bytes
+}
+
+/* Change tile for clist_tile_rectangle. */
+int
+clist_change_tile(gx_device_clist_writer * cldev, gx_clist_state * pcls,
+ const gx_strip_bitmap * tiles, int depth)
+{
+ tile_loc loc;
+ int code;
+
+#define tile_params_differ(cldev, tiles, depth)\
+ ((tiles)->rep_width != (cldev)->tile_params.rep_width ||\
+ (tiles)->rep_height != (cldev)->tile_params.rep_height ||\
+ (tiles)->rep_shift != (cldev)->tile_params.rep_shift ||\
+ (depth) != (cldev)->tile_depth)
+
+ top:if (clist_find_bits(cldev, tiles->id, &loc)) { /* The bitmap is in the cache. Check whether this band */
+ /* knows about it. */
+ int band_index = pcls - cldev->states;
+ byte *bptr = ts_mask(loc.tile) + (band_index >> 3);
+ byte bmask = 1 << (band_index & 7);
+
+ if (*bptr & bmask) { /* Already known. Just set the index. */
+ if (pcls->tile_index == loc.index)
+ return 0;
+ cmd_put_tile_index(cldev, pcls, loc.index);
+ } else {
+ uint extra = 0;
+
+ if tile_params_differ
+ (cldev, tiles, depth) { /*
+ * We have a cached tile whose parameters differ from
+ * the current ones. Because of the way tile IDs are
+ * managed, this is currently only possible when mixing
+ * Patterns and halftones, but if we didn't generate new
+ * IDs each time the main halftone cache needed to be
+ * refreshed, this could also happen simply from
+ * switching screens.
+ */
+ int band;
+
+ clist_new_tile_params(&cldev->tile_params, tiles, depth,
+ cldev);
+ cldev->tile_depth = depth;
+ /* No band knows about the new parameters. */
+ for (band = cldev->tile_known_min;
+ band <= cldev->tile_known_max;
+ ++band
+ )
+ cldev->states[band].known &= ~tile_params_known;
+ cldev->tile_known_min = cldev->nbands;
+ cldev->tile_known_max = -1;
+ }
+ if (!(pcls->known & tile_params_known)) { /* We're going to have to write the tile parameters. */
+ extra = cmd_size_tile_params(&cldev->tile_params);
+ } { /*
+ * This band doesn't know this tile yet, so output the
+ * bits. Note that the offset we write is the one used by
+ * the reading phase, not the writing phase. Note also
+ * that the size of the cached and written tile may differ
+ * from that of the client's tile. Finally, note that
+ * this tile's size parameters are guaranteed to be
+ * compatible with those stored in the device
+ * (cldev->tile_params).
+ */
+ ulong offset = (byte *) loc.tile - cldev->chunk.data;
+ uint rsize =
+ extra + 1 + cmd_size_w(loc.index) + cmd_size_w(offset);
+ byte *dp;
+ uint csize;
+ int code =
+ cmd_put_bits(cldev, pcls, ts_bits(cldev, loc.tile),
+ tiles->rep_width * depth, tiles->rep_height,
+ loc.tile->cb_raster, rsize,
+ (cldev->tile_params.size.x > tiles->rep_width ?
+ decompress_elsewhere | decompress_spread :
+ decompress_elsewhere),
+ &dp, &csize);
+
+ if (code < 0)
+ return code;
+ if (extra) { /* Write the tile parameters before writing the bits. */
+ cmd_store_tile_params(dp, &cldev->tile_params, depth,
+ extra);
+ dp += extra;
+ /* This band now knows the parameters. */
+ pcls->known |= tile_params_known;
+ if (band_index < cldev->tile_known_min)
+ cldev->tile_known_min = band_index;
+ if (band_index > cldev->tile_known_max)
+ cldev->tile_known_max = band_index;
+ }
+ *dp = cmd_count_op(cmd_opv_set_tile_bits, csize - extra);
+ dp++;
+ dp = cmd_put_w(loc.index, dp);
+ cmd_put_w(offset, dp);
+ *bptr |= bmask;
+ loc.tile->num_bands++;
+ }
+ }
+ pcls->tile_index = loc.index;
+ pcls->tile_id = loc.tile->id;
+ return 0;
+ }
+ /* The tile is not in the cache, add it. */
+ {
+ gx_strip_bitmap new_tile;
+ gx_strip_bitmap *ptile;
+
+ /* Ensure that the tile size is compatible. */
+ if (tile_params_differ(cldev, tiles, depth)) { /* We'll reset cldev->tile_params when we write the bits. */
+ clist_new_tile_params(&new_tile, tiles, depth, cldev);
+ ptile = &new_tile;
+ } else {
+ cldev->tile_params.id = tiles->id;
+ cldev->tile_params.data = tiles->data;
+ ptile = &cldev->tile_params;
+ }
+ code = clist_add_tile(cldev, ptile, tiles->raster, depth);
+ if (code < 0)
+ return code;
+ }
+ goto top;
+#undef tile_params_differ
+}
+
+/* Change "tile" for clist_copy_*. tiles->[rep_]shift must be zero. */
+int
+clist_change_bits(gx_device_clist_writer * cldev, gx_clist_state * pcls,
+ const gx_strip_bitmap * tiles, int depth)
+{
+ tile_loc loc;
+ int code;
+
+ top:if (clist_find_bits(cldev, tiles->id, &loc)) { /* The bitmap is in the cache. Check whether this band */
+ /* knows about it. */
+ uint band_index = pcls - cldev->states;
+ byte *bptr = ts_mask(loc.tile) + (band_index >> 3);
+ byte bmask = 1 << (band_index & 7);
+
+ if (*bptr & bmask) { /* Already known. Just set the index. */
+ if (pcls->tile_index == loc.index)
+ return 0;
+ cmd_put_tile_index(cldev, pcls, loc.index);
+ } else { /* Not known yet. Output the bits. */
+ /* Note that the offset we write is the one used by */
+ /* the reading phase, not the writing phase. */
+ ulong offset = (byte *) loc.tile - cldev->chunk.data;
+ uint rsize = 2 + cmd_size_w(loc.tile->width) +
+ cmd_size_w(loc.tile->height) + cmd_size_w(loc.index) +
+ cmd_size_w(offset);
+ byte *dp;
+ uint csize;
+ gx_clist_state *bit_pcls = pcls;
+ int code;
+
+ if (loc.tile->num_bands == CHAR_ALL_BANDS_COUNT)
+ bit_pcls = NULL;
+ code = cmd_put_bits(cldev, bit_pcls, ts_bits(cldev, loc.tile),
+ loc.tile->width * depth,
+ loc.tile->height, loc.tile->cb_raster,
+ rsize,
+ (1 << cmd_compress_cfe) | decompress_elsewhere,
+ &dp, &csize);
+
+ if (code < 0)
+ return code;
+ *dp = cmd_count_op(cmd_opv_set_bits, csize);
+ dp[1] = (depth << 2) + code;
+ dp += 2;
+ dp = cmd_put_w(loc.tile->width, dp);
+ dp = cmd_put_w(loc.tile->height, dp);
+ dp = cmd_put_w(loc.index, dp);
+ cmd_put_w(offset, dp);
+ if (bit_pcls == NULL) {
+ memset(ts_mask(loc.tile), 0xff,
+ cldev->tile_band_mask_size);
+ loc.tile->num_bands = cldev->nbands;
+ } else {
+ *bptr |= bmask;
+ loc.tile->num_bands++;
+ }
+ }
+ pcls->tile_index = loc.index;
+ pcls->tile_id = loc.tile->id;
+ return 0;
+ }
+ /* The tile is not in the cache. */
+ code = clist_add_tile(cldev, tiles, tiles->raster, depth);
+ if (code < 0)
+ return code;
+ goto top;
+}
diff --git a/pstoraster/gxcldev.h b/pstoraster/gxcldev.h
new file mode 100644
index 000000000..9d1d02d73
--- /dev/null
+++ b/pstoraster/gxcldev.h
@@ -0,0 +1,727 @@
+/* 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$ */
+/* Internal definitions for Ghostscript command lists. */
+
+#ifndef gxcldev_INCLUDED
+# define gxcldev_INCLUDED
+
+#include "gsropt.h"
+#include "gxht.h" /* for gxdht.h */
+#include "gxtmap.h" /* ditto */
+#include "gxdht.h" /* for halftones */
+#include "strimpl.h" /* for compressed bitmaps */
+#include "scfx.h" /* ditto */
+#include "srlx.h" /* ditto */
+
+/* ---------------- Commands ---------------- */
+
+/* Define the compression modes for bitmaps. */
+/*#define cmd_compress_none 0 *//* (implicit) */
+#define cmd_compress_rle 1
+#define clist_rle_init(ss)\
+ BEGIN\
+ s_RLE_set_defaults_inline(ss);\
+ s_RLE_init_inline(ss);\
+ END
+#define clist_rld_init(ss)\
+ BEGIN\
+ s_RLD_set_defaults_inline(ss);\
+ s_RLD_init_inline(ss);\
+ END
+#define cmd_compress_cfe 2
+#define clist_cf_init(ss, width, mem)\
+ BEGIN\
+ (ss)->memory = (mem);\
+ (ss)->K = -1;\
+ (ss)->Columns = (width);\
+ (ss)->EndOfBlock = false;\
+ (ss)->BlackIs1 = true;\
+ (ss)->DecodedByteAlign = align_bitmap_mod;\
+ END
+#define clist_cfe_init(ss, width, mem)\
+ BEGIN\
+ s_CFE_set_defaults_inline(ss);\
+ clist_cf_init(ss, width, mem);\
+ (*s_CFE_template.init)((stream_state *)(ss));\
+ END
+#define clist_cfd_init(ss, width, height, mem)\
+ BEGIN\
+ (*s_CFD_template.set_defaults)((stream_state *)ss);\
+ clist_cf_init(ss, width, mem);\
+ (ss)->Rows = (height);\
+ (*s_CFD_template.init)((stream_state *)(ss));\
+ END
+#define cmd_mask_compress_any\
+ ((1 << cmd_compress_rle) | (1 << cmd_compress_cfe))
+
+/*
+ * A command always consists of an operation followed by operands;
+ * the syntax of the operands depends on the operation.
+ * In the operation definitions below:
+ * + (prefixed) means the operand is in the low 4 bits of the opcode.
+ * # means a variable-size operand encoded with the variable-size
+ * integer encoding.
+ * % means a variable-size operand encoded with the variable-size
+ * fixed coordinate encoding.
+ * $ means a color sized according to the device depth.
+ * <> means the operand size depends on other state information
+ * and/or previous operands.
+ */
+typedef enum {
+ cmd_op_misc = 0x00, /* (see below) */
+ cmd_opv_end_run = 0x00, /* (nothing) */
+ cmd_opv_set_tile_size = 0x01, /* rs?(1)nry?(1)nrx?(1)depth-1(5), */
+ /* rep_width#, rep_height#, */
+ /* [, nreps_x#][, nreps_y #] */
+ /* [, rep_shift#] */
+ cmd_opv_set_tile_phase = 0x02, /* x#, y# */
+ cmd_opv_set_tile_bits = 0x03, /* index#, offset#, <bits> */
+ cmd_opv_set_bits = 0x04, /* depth*4+compress, width#, height#, */
+ /* index#, offset#, <bits> */
+ cmd_opv_set_tile_color = 0x05, /* (nothing; next set/delta_color */
+ /* refers to tile) */
+ cmd_opv_set_misc = 0x06,
+#define cmd_set_misc_lop (0 << 6) /* 00: lop_lsb(6), lop_msb# */
+#define cmd_set_misc_data_x (1 << 6) /* 01: more(1)dx_lsb(5)[, dx_msb#] */
+#define cmd_set_misc_map (2 << 6) /* 10: non-0(1)map_index(5) */
+ /* [, n x frac] */
+#define cmd_set_misc_halftone (3 << 6) /* 11: type(6), num_comp# */
+ cmd_opv_enable_lop = 0x07, /* (nothing) */
+ cmd_opv_disable_lop = 0x08, /* (nothing) */
+ cmd_opv_set_ht_order = 0x09, /* component+1#[, cname#], */
+ /* width#, height#, raster#, */
+ /* shift#, num_levels#, num_bits# */
+ cmd_opv_set_ht_data = 0x0a, /* n, n x (uint|gx_ht_bit) */
+ cmd_opv_end_page = 0x0b, /* (nothing) */
+ cmd_opv_delta2_color0 = 0x0c, /* dr5dg6db5 or dc4dm4dy4dk4 */
+#define cmd_delta2_24_bias 0x00102010
+#define cmd_delta2_24_mask 0x001f3f1f
+#define cmd_delta2_32_bias 0x08080808
+#define cmd_delta2_32_mask 0x0f0f0f0f
+ cmd_opv_delta2_color1 = 0x0d, /* <<same as color0>> */
+ cmd_opv_set_copy_color = 0x0e, /* (nothing) */
+ cmd_opv_set_copy_alpha = 0x0f, /* (nothing) */
+ cmd_op_set_color0 = 0x10, /* +15 = transparent | */
+ /* +0, color$ | +dcolor+8 | */
+ /* +dr4, dg4db4 | */
+ /* +dc3dm1, dm2dy3dk3 */
+ cmd_op_set_color1 = 0x20, /* <<same as color0>> */
+#define cmd_delta1_24_bias 0x00080808
+#define cmd_delta1_24_mask 0x000f0f0f
+#define cmd_delta1_32_bias 0x04040404
+#define cmd_delta1_32_mask 0x07070707
+ cmd_op_fill_rect = 0x30, /* +dy2dh2, x#, w# | +0, rect# */
+ cmd_op_fill_rect_short = 0x40, /* +dh, dx, dw | +0, rect_short */
+ cmd_op_fill_rect_tiny = 0x50, /* +dw+0, rect_tiny | +dw+8 */
+ cmd_op_tile_rect = 0x60, /* +dy2dh2, x#, w# | +0, rect# */
+ cmd_op_tile_rect_short = 0x70, /* +dh, dx, dw | +0, rect_short */
+ cmd_op_tile_rect_tiny = 0x80, /* +dw+0, rect_tiny | +dw+8 */
+ cmd_op_copy_mono = 0x90, /* +compress, x#, y#, (w+data_x)#, */
+ /* h#, <bits> | */
+#define cmd_copy_ht_color 4
+ /* +4+compress, x#, y#, (w+data_x)#, */
+ /* h#, <bits> | */
+#define cmd_copy_use_tile 8
+ /* +8 (use tile), x#, y# | */
+ /* +12 (use tile), x#, y# */
+ cmd_op_copy_color_alpha = 0xa0, /* (same as copy_mono, except: */
+ /* if color, ignore ht_color; */
+ /* if alpha & !use_tile, depth is */
+ /* first operand) */
+ cmd_op_delta_tile_index = 0xb0, /* +delta+8 */
+ cmd_op_set_tile_index = 0xc0 /* +index[11:8], index[7:0] */
+} gx_cmd_op;
+
+#define cmd_op_name_strings\
+ "(misc)", "set_color[0]", "set_color[1]", "fill_rect",\
+ "fill_rect_short", "fill_rect_tiny", "tile_rect", "tile_rect_short",\
+ "tile_rect_tiny", "copy_mono", "copy_color_alpha", "delta_tile_index",\
+ "set_tile_index", "(misc2)", "(segment)", "(path)"
+
+#define cmd_misc_op_name_strings\
+ "end_run", "set_tile_size", "set_tile_phase", "set_tile_bits",\
+ "set_bits", "set_tile_color", "set_misc", "enable_lop",\
+ "disable_lop", "set_ht_order", "set_ht_data", "end_page",\
+ "delta2_color0", "delta2_color1", "set_copy_color", "set_copy_alpha",
+
+#ifdef DEBUG
+extern const char *const cmd_op_names[16];
+extern const char *const *const cmd_sub_op_names[16];
+#endif
+
+/*
+ * Define the size of the largest command, not counting any bitmap or
+ * similar variable-length operands.
+ * The variable-size integer encoding is little-endian. The low 7 bits
+ * of each byte contain data; the top bit is 1 for all but the last byte.
+ */
+#define cmd_max_intsize(siz)\
+ (((siz) * 8 + 6) / 7)
+#define cmd_largest_size\
+ (2 + (1 + cmd_max_dash) * sizeof(float))
+
+/* ---------------- Command parameters ---------------- */
+
+/* Rectangle */
+typedef struct {
+ int x, y, width, height;
+} gx_cmd_rect;
+
+/* Short rectangle */
+typedef struct {
+ byte dx, dwidth, dy, dheight; /* dy and dheight are optional */
+} gx_cmd_rect_short;
+
+#define cmd_min_short (-128)
+#define cmd_max_short 127
+/* Tiny rectangle */
+#define cmd_min_dw_tiny (-4)
+#define cmd_max_dw_tiny 3
+typedef struct {
+ unsigned dx:4;
+ unsigned dy:4;
+} gx_cmd_rect_tiny;
+
+#define cmd_min_dxy_tiny (-8)
+#define cmd_max_dxy_tiny 7
+
+/*
+ * When we write bitmaps, we remove raster padding selectively:
+ * - If the bitmap is compressed, we don't remove any padding;
+ * - If the width is <= 6 bytes, we remove all the padding;
+ * - If the bitmap is only 1 scan line high, we remove the padding;
+ * - If the bitmap is going to be replicated horizontally (see the
+ * definition of decompress_spread below), we remove the padding;
+ * - Otherwise, we remove the padding only from the last scan line.
+ */
+#define cmd_max_short_width_bytes 6
+#define cmd_max_short_width_bits (cmd_max_short_width_bytes * 8)
+/*
+ * Determine the (possibly unpadded) width in bytes for writing a bitmap,
+ * per the algorithm just outlined. If compression_mask has any of the
+ * cmd_mask_compress_any bits set, we assume the bitmap will be compressed.
+ * Return the total size of the bitmap.
+ */
+uint clist_bitmap_bytes(P5(uint width_bits, uint height,
+ int compression_mask,
+ uint * width_bytes, uint * raster));
+
+/*
+ * For halftone cells, we always write an unreplicated bitmap, but we
+ * reserve cache space for the reading pass based on the replicated size.
+ * See the clist_change_tile procedure for the algorithm that chooses the
+ * replication factors.
+ */
+
+/* ---------------- Block file entries ---------------- */
+
+typedef struct cmd_block_s {
+ int band_min, band_max;
+#define cmd_band_end (-1) /* end of band file */
+ long pos; /* starting position in cfile */
+} cmd_block;
+
+/* ---------------- Band state ---------------- */
+
+/* Define the prefix on each command run in the writing buffer. */
+typedef struct cmd_prefix_s cmd_prefix;
+struct cmd_prefix_s {
+ cmd_prefix *next;
+ uint size;
+};
+
+/* Define the pointers for managing a list of command runs in the buffer. */
+/* There is one of these for each band, plus one for band-range commands. */
+typedef struct cmd_list_s {
+ cmd_prefix *head, *tail; /* list of commands for band */
+} cmd_list;
+
+/* Remember the current state of one band when writing or reading. */
+struct gx_clist_state_s {
+ gx_color_index colors[2]; /* most recent colors */
+ uint tile_index; /* most recent tile index */
+ gx_bitmap_id tile_id; /* most recent tile id */
+/* Since tile table entries may be deleted and/or moved at any time, */
+/* the following is the only reliable way to check whether tile_index */
+/* references a particular tile id: */
+#define cls_has_tile_id(cldev, pcls, tid, offset_temp)\
+ ((pcls)->tile_id == (tid) &&\
+ (offset_temp = cldev->tile_table[(pcls)->tile_index].offset) != 0 &&\
+ ((tile_slot *)(cldev->data + offset_temp))->id == (tid))
+ gs_int_point tile_phase; /* most recent tile phase */
+ gx_color_index tile_colors[2]; /* most recent tile colors */
+ gx_cmd_rect rect; /* most recent rectangle */
+ gs_logical_operation_t lop; /* most recent logical op */
+ short lop_enabled; /* 0 = don't use lop, 1 = use lop, */
+ /* -1 is used internally */
+ short clip_enabled; /* 0 = don't clip, 1 = do clip, */
+ /* -1 is used internally */
+ ushort color_is_alpha; /* (Boolean) for copy_color_alpha */
+ ushort known; /* flags for whether this band */
+ /* knows various misc. parameters */
+ /* We assign 'known' flags here from the high end; */
+ /* gxclpath.h assigns them from the low end. */
+#define tile_params_known (1<<15)
+#define begin_image_known (1<<14) /* gxclimag.c */
+#define initial_known 0x3fff /* exclude tile & image params */
+ /* Following are only used when writing */
+ cmd_list list; /* list of commands for band */
+ /* Following is set when writing, read when reading */
+ ulong cost; /* cost of rendering the band */
+};
+
+/**** MRS: We need to include this here instead of the top to avoid lots of
+ **** pointer errors. Why the f**k does GS have to define so many
+ **** interdependent structures?!?
+ ****/
+#include "gxclist.h"
+
+/* The initial values for a band state */
+/*static const gx_clist_state cls_initial */
+#define cls_initial_values\
+ { gx_no_color_index, gx_no_color_index },\
+ 0, gx_no_bitmap_id,\
+ { 0, 0 }, { gx_no_color_index, gx_no_color_index },\
+ { 0, 0, 0, 0 }, lop_default, 0, 0, 0, initial_known,\
+ { 0, 0 }, 0
+
+/* Define the size of the command buffer used for reading. */
+/* This is needed to split up operations with a large amount of data, */
+/* primarily large copy_ operations. */
+#define cbuf_size 800
+
+/* ---------------- Driver procedure support ---------------- */
+
+/*
+ * The procedures and macros defined here are used when writing
+ * (gxclist.c, gxclbits.c, gxclimag.c, gxclpath.c, gxclrect.c).
+ * Note that none of the cmd_put_xxx procedures do VMerror recovery;
+ * they convert low-memory warnings to VMerror errors.
+ */
+
+/* ------ Exported by gxclist.c ------ */
+
+/*
+ * Error recovery procedures for writer-side VMerrors, for async rendering
+ * support. This logic assumes that the command list file and/or the
+ * renderer allocate memory from the same pool as the writer. Hence, when
+ * the writer runs out of memory, it tries to pause and let the renderer run
+ * for a while in hope that enough memory will be freed by it to allow the
+ * writer to allocate enough memory to proceed. Once a VMerror is detected,
+ * error recovery proceeds in two escalating stages:
+ *
+ * 1) The recovery logic repeatedly calls clist_VMerror_recover(), which
+ * waits until the next page has finished rendering. The recovery logic
+ * keeps calling clist_VMerror_recover() until enough memory is freed,
+ * or until clist_VMerror_recover() signals that no more pages
+ * remain to be rendered.
+ *
+ * 2) If enough memory is not free, the recovery logic calls
+ * clist_VMerror_recover_flush() once. This routine terminates and
+ * flushes out the partially-completed page that the writer is currently
+ * writing to the command file, then waits for the partial page to finish
+ * rendering. It then opens up a new command list "file" and resets the
+ * state of the command list machinery to an initial state as if a new
+ * page were beginning.
+ *
+ * If insufficient memory is available after the 2nd step, the situation
+ * is the same as if it ocurred in a non-async setup: the writer program
+ * simply used up too much memory and cannot continue.
+ *
+ * The first stage of error recovery (no flush) is performed without
+ * flushing out the current page, so failing commands can simply be
+ * restarted after such recovery. This is not true of 2nd stage recovery
+ * (flush): as part of its operation, the flush resets the state of both
+ * writer and renderer to initial values. In this event, the recovery logic
+ * which called clist_try_recover_VMerror_flush() must force any pertinent
+ * state information to be re-emitted before re-issuing the failing command.
+ *
+ * In case of a VMerror, the internal procedures that support the driver
+ * procedures simply return the error code: they do not attempt recovery.
+ * Note that all such procedures must take care that (1) they don't update
+ * any writer state to reflect information written to the band list unless
+ * the write actually succeeds, and (2) they are idempotent, since they may
+ * be re-executed after first-stage VMerror recovery.
+ *
+ * Error recovery is only performed by the driver procedures themselves
+ * (fill_rectangle, copy_mono, fill_path, etc.) and a few other procedures
+ * at the same level of control. The implementation of error recovery is
+ * packaged up in the FOR_RECTS et al macros defined below, but -- as noted
+ * above -- recovery is not fully transparent. Other routines which perform
+ * error recovery are those which open the device, begin a new page, or
+ * reopen the device (put_params).
+ */
+int clist_VMerror_recover(P2(gx_device_clist_writer *, int));
+int clist_VMerror_recover_flush(P2(gx_device_clist_writer *, int));
+
+/* Write out device parameters. */
+int cmd_put_params(P2(gx_device_clist_writer *, gs_param_list *));
+
+/* Conditionally keep command statistics. */
+#ifdef DEBUG
+int cmd_count_op(P2(int op, uint size));
+void cmd_uncount_op(P2(int op, uint size));
+# define cmd_count_add1(v) (v++)
+#else
+# define cmd_count_op(op, size) (op)
+# define cmd_uncount_op(op, size) DO_NOTHING
+# define cmd_count_add1(v) DO_NOTHING
+#endif
+
+/* Add a command to the appropriate band list, */
+/* and allocate space for its data. */
+byte *cmd_put_list_op(P3(gx_device_clist_writer * cldev, cmd_list * pcl, uint size));
+
+#ifdef DEBUG
+byte *cmd_put_op(P3(gx_device_clist_writer * cldev, gx_clist_state * pcls, uint size));
+#else
+# define cmd_put_op(cldev, pcls, size)\
+ cmd_put_list_op(cldev, &(pcls)->list, size)
+#endif
+/* Call cmd_put_op and update stats if no error occurs. */
+#define set_cmd_put_op(dp, cldev, pcls, op, csize)\
+ ( (dp = cmd_put_op(cldev, pcls, csize)) == 0 ?\
+ (cldev)->error_code :\
+ (*dp = cmd_count_op(op, csize), 0) )
+
+/* Add a command for all bands or a range of bands. */
+byte *cmd_put_range_op(P4(gx_device_clist_writer * cldev, int band_min,
+ int band_max, uint size));
+
+#define cmd_put_all_op(cldev, size)\
+ cmd_put_range_op(cldev, 0, (cldev)->nbands - 1, size)
+/* Call cmd_put_all/range_op and update stats if no error occurs. */
+#define set_cmd_put_range_op(dp, cldev, op, bmin, bmax, csize)\
+ ( (dp = cmd_put_range_op(cldev, bmin, bmax, csize)) == 0 ?\
+ (cldev)->error_code :\
+ (*dp = cmd_count_op(op, csize), 0) )
+#define set_cmd_put_all_op(dp, cldev, op, csize)\
+ set_cmd_put_range_op(dp, cldev, op, 0, (cldev)->nbands - 1, csize)
+
+/* Shorten the last allocated command. */
+/* Note that this does not adjust the statistics. */
+#define cmd_shorten_list_op(cldev, pcls, delta)\
+ ((pcls)->tail->size -= (delta), (cldev)->cnext -= (delta))
+#define cmd_shorten_op(cldev, pcls, delta)\
+ cmd_shorten_list_op(cldev, &(pcls)->list, delta)
+
+/* Write out the buffered commands, and reset the buffer. */
+/* Return 0 if OK, 1 if OK with low-memory warning, */
+/* or the usual negative error code. */
+int cmd_write_buffer(P2(gx_device_clist_writer * cldev, byte cmd_end));
+
+/* End a page by flushing the buffer and terminating the command list. */
+int clist_end_page(P1(gx_device_clist_writer *));
+
+/* Compute the # of bytes required to represent a variable-size integer. */
+/* (This works for negative integers also; they are written as though */
+/* they were unsigned.) */
+int cmd_size_w(P1(uint));
+
+#define w1byte(w) (!((w) & ~0x7f))
+#define w2byte(w) (!((w) & ~0x3fff))
+#define cmd_sizew(w)\
+ (w1byte(w) ? 1 : w2byte(w) ? 2 : cmd_size_w((uint)(w)))
+#define cmd_size2w(wx,wy)\
+ (w1byte((wx) | (wy)) ? 2 :\
+ cmd_size_w((uint)(wx)) + cmd_size_w((uint)(wy)))
+#define cmd_sizexy(xy) cmd_size2w((xy).x, (xy).y)
+#define cmd_sizew_max ((sizeof(uint) * 8 + 6) / 7)
+
+/* Put a variable-size integer in the buffer. */
+byte *cmd_put_w(P2(uint, byte *));
+
+#define cmd_putw(w,dp)\
+ (w1byte(w) ? (*dp = w, ++dp) :\
+ w2byte(w) ? (*dp = (w) | 0x80, dp[1] = (w) >> 7, dp += 2) :\
+ (dp = cmd_put_w((uint)(w), dp)))
+#define cmd_put2w(wx,wy,dp)\
+ (w1byte((wx) | (wy)) ? (dp[0] = (wx), dp[1] = (wy), dp += 2) :\
+ (dp = cmd_put_w((uint)(wy), cmd_put_w((uint)(wx), dp))))
+#define cmd_putxy(xy,dp) cmd_put2w((xy).x, (xy).y, dp)
+
+/* Put out a command to set a color. */
+typedef struct {
+ byte set_op;
+ byte delta2_op;
+ bool tile_color;
+} clist_select_color_t;
+extern const clist_select_color_t
+ clist_select_color0, clist_select_color1, clist_select_tile_color0,
+ clist_select_tile_color1;
+int cmd_put_color(P5(gx_device_clist_writer * cldev, gx_clist_state * pcls,
+ const clist_select_color_t * select,
+ gx_color_index color, gx_color_index * pcolor));
+
+#define cmd_set_color0(dev, pcls, color0)\
+ cmd_put_color(dev, pcls, &clist_select_color0, color0, &(pcls)->colors[0])
+#define cmd_set_color1(dev, pcls, color1)\
+ cmd_put_color(dev, pcls, &clist_select_color1, color1, &(pcls)->colors[1])
+
+/* Put out a command to set the tile colors. */
+int cmd_set_tile_colors(P4(gx_device_clist_writer *cldev,
+ gx_clist_state * pcls,
+ gx_color_index color0, gx_color_index color1));
+
+/* Put out a command to set the tile phase. */
+int cmd_set_tile_phase(P4(gx_device_clist_writer *cldev,
+ gx_clist_state * pcls,
+ int px, int py));
+
+/* Enable or disable the logical operation. */
+int cmd_put_enable_lop(P3(gx_device_clist_writer *, gx_clist_state *, int));
+#define cmd_do_enable_lop(cldev, pcls, enable)\
+ ( (pcls)->lop_enabled == ((enable) ^ 1) &&\
+ cmd_put_enable_lop(cldev, pcls, enable) < 0 ?\
+ (cldev)->error_code : 0 )
+#define cmd_enable_lop(cldev, pcls)\
+ cmd_do_enable_lop(cldev, pcls, 1)
+#define cmd_disable_lop(cldev, pcls)\
+ cmd_do_enable_lop(cldev, pcls, 0)
+
+/* Enable or disable clipping. */
+int cmd_put_enable_clip(P3(gx_device_clist_writer *, gx_clist_state *, int));
+
+#define cmd_do_enable_clip(cldev, pcls, enable)\
+ ( (pcls)->clip_enabled == ((enable) ^ 1) &&\
+ cmd_put_enable_clip(cldev, pcls, enable) < 0 ?\
+ (cldev)->error_code : 0 )
+#define cmd_enable_clip(cldev, pcls)\
+ cmd_do_enable_clip(cldev, pcls, 1)
+#define cmd_disable_clip(cldev, pcls)\
+ cmd_do_enable_clip(cldev, pcls, 0)
+
+/* Write a command to set the logical operation. */
+int cmd_set_lop(P3(gx_device_clist_writer *, gx_clist_state *,
+ gs_logical_operation_t));
+
+/* Disable (if default) or enable the logical operation, setting it if */
+/* needed. */
+int cmd_update_lop(P3(gx_device_clist_writer *, gx_clist_state *,
+ gs_logical_operation_t));
+
+/*
+ * Define macros for dividing up an operation into bands, per the
+ * template
+
+ FOR_RECTS {
+ ... process rectangle x, y, width, height in band pcls ...
+ } END_RECTS;
+
+ * Note that FOR_RECTS resets y and height. It is OK for the code that
+ * processes each band to reset height to a smaller (positive) value; the
+ * vertical subdivision code in copy_mono, copy_color, and copy_alpha makes
+ * use of this. The band processing code may `continue' (to reduce nesting
+ * of conditionals).
+ *
+ * If the processing code detects an error that may be a recoverable
+ * VMerror, the code may call ERROR_RECT(), which will attempt to fix the
+ * VMerror by flushing and closing the band and resetting the imager state,
+ * and then restart emitting the entire band. Before flushing the file, the
+ * 'on_error' clause of END_RECTS_ON_ERROR (defaults to the constant 1 if
+ * END_RECT is used) is evaluated and tested. The 'on_error' clause enables
+ * mop-up actions to be executed before flushing, and/or selectively
+ * inhibits the flush, close, reset and restart process. Similarly, the
+ * 'after_recovering' clause of END_RECTS_ON_ERROR allows an action to get
+ * performed after successfully recovering.
+ *
+ * The band processing code may wrap an operation with TRY_RECT { ... }
+ * HANDLE_RECT_UNLESS(code, unless_action) (or HANDLE_RECT(code)). This will
+ * perform local first-stage VMerror recovery, by waiting for some memory to
+ * become free and then retrying the failed operation starting at the
+ * TRY_RECT. If local recovery is unsuccessful, the local recovery code
+ * calls ERROR_RECT.
+ *
+ * In a few cases, the band processing code calls other driver procedures
+ * (e.g., clist_copy_mono calls itself recursively if it must split up the
+ * operation into smaller pieces) or other procedures that may attempt
+ * VMerror recovery. In such cases, the recursive call must not attempt
+ * second-stage VMerror recovery, since the caller would have no way of
+ * knowing that the writer state had been reset. Such recursive calls
+ * should be wrapped in NEST_RECT { ... } UNNEST_RECT, which causes
+ * ERROR_RECT simply to return the error code rather than attempting
+ * recovery. (TRY/HANDLE_RECT will still attempt local recovery, as
+ * described above, but this is harmless since it is transparent.) By
+ * convention, calls to cmd_put_xxx or cmd_set_xxx never attempt recovery
+ * and so never require NEST_RECTs.
+ *
+ * If a put_params call fails, the device will be left in a closed state,
+ * but higher-level code won't notice this fact. We flag this by setting
+ * permanent_error, which prevents writing to the command list.
+ */
+
+/**** MRS: Added cast to cdev->states since size of gx_clist_state is unknown ****/
+#define FOR_RECTS\
+ BEGIN\
+ int yend = y + height;\
+ int band_height = cdev->page_band_height;\
+ int band_code;\
+\
+ if (cdev->permanent_error < 0)\
+ return (cdev->permanent_error);\
+ do {\
+ int band = y / band_height;\
+ gx_clist_state *pcls = ((struct gx_clist_state_s *)cdev->states) + band;\
+ int band_end = (band + 1) * band_height;\
+\
+ height = min(band_end, yend) - y;\
+retry_rect:\
+ ;
+#define NEST_RECT ++cdev->driver_call_nesting;
+#define UNNEST_RECT --cdev->driver_call_nesting
+#define ERROR_RECT(code_value)\
+ BEGIN\
+ band_code = (code_value);\
+ goto error_in_rect;\
+ END
+#define TRY_RECT\
+ BEGIN\
+ do
+#define HANDLE_RECT_UNLESS(codevar, unless_clause)\
+ while (codevar < 0 &&\
+ !(codevar = clist_VMerror_recover(cdev, (codevar)))\
+ );\
+ if (codevar < 0 && !(unless_clause))\
+ ERROR_RECT(codevar);\
+ END
+#define HANDLE_RECT(codevar)\
+ HANDLE_RECT_UNLESS(codevar, 0)
+#define END_RECTS_ON_ERROR(retry_cleanup, is_error, after_recovering)\
+ continue;\
+error_in_rect:\
+ if (cdev->error_is_retryable) {\
+ retry_cleanup;\
+ if ((is_error) &&\
+ cdev->driver_call_nesting == 0 &&\
+ (band_code =\
+ clist_VMerror_recover_flush(cdev, band_code)) >= 0 &&\
+ (after_recovering)\
+ )\
+ goto retry_rect;\
+ }\
+ return band_code;\
+ } while ((y += height) < yend);\
+ END
+#define END_RECTS END_RECTS_ON_ERROR(DO_NOTHING, 1, 1)
+
+/* ------ Exported by gxclrect.c ------ */
+
+/* Put out a fill or tile rectangle command. */
+int cmd_write_rect_cmd(P7(gx_device_clist_writer * cldev,
+ gx_clist_state * pcls,
+ int op, int x, int y, int width, int height));
+
+/* ------ Exported by gxclbits.c ------ */
+
+/*
+ * Put a bitmap in the buffer, compressing if appropriate.
+ * pcls == 0 means put the bitmap in all bands.
+ * Return <0 if error, otherwise the compression method.
+ * A return value of gs_error_limitcheck means that the bitmap was too big
+ * to fit in the command reading buffer.
+ * Note that this leaves room for the command and initial arguments,
+ * but doesn't fill them in.
+ *
+ * If decompress_elsewhere is set in the compression_mask, it is OK
+ * to write out a compressed bitmap whose decompressed size is too large
+ * to fit in the command reading buffer. (This is OK when reading a
+ * cached bitmap, but not a bitmap for a one-time copy operation.)
+ */
+#define decompress_elsewhere 0x100
+/*
+ * If decompress_spread is set, the decompressed data will be spread out
+ * for replication, so we drop all the padding even if the width is
+ * greater than cmd_max_short_width_bytes (see above).
+ */
+#define decompress_spread 0x200
+
+int cmd_put_bits(P10(gx_device_clist_writer * cldev, gx_clist_state * pcls,
+ const byte * data, uint width_bits, uint height,
+ uint raster, int op_size, int compression_mask,
+ byte ** pdp, uint * psize));
+
+/*
+ * Put out commands for a color map (transfer function, black generation, or
+ * undercolor removal). If pid != 0, write the map only if its ID differs
+ * from the current one, and update the saved ID in the case.
+ */
+typedef enum {
+ cmd_map_transfer = 0, /* all transfer functions */
+ cmd_map_transfer_0, /* transfer[0] */
+ cmd_map_transfer_1, /* transfer[1] */
+ cmd_map_transfer_2, /* transfer[2] */
+ cmd_map_transfer_3, /* transfer[3] */
+ cmd_map_ht_transfer, /* transfer fn of most recent halftone order */
+ cmd_map_black_generation,
+ cmd_map_undercolor_removal
+} cmd_map_index;
+int cmd_put_color_map(P4(gx_device_clist_writer * cldev,
+ cmd_map_index map_index,
+ const gx_transfer_map * map, gs_id * pid));
+
+/*
+ * Change tiles for clist_tile_rectangle. (We make this a separate
+ * procedure primarily for readability.)
+ */
+int clist_change_tile(P4(gx_device_clist_writer * cldev, gx_clist_state * pcls,
+ const gx_strip_bitmap * tiles, int depth));
+
+/*
+ * Change "tile" for clist_copy_*. Only uses tiles->{data, id, raster,
+ * rep_width, rep_height}. tiles->[rep_]shift must be zero.
+ */
+int clist_change_bits(P4(gx_device_clist_writer * cldev, gx_clist_state * pcls,
+ const gx_strip_bitmap * tiles, int depth));
+
+/* ------ Exported by gxclimag.c ------ */
+
+/*
+ * Add commands to represent a full (device) halftone.
+ * (This routine should probably be in some other module.)
+ * ****** Note: the type parameter is now unnecessary, because device
+ * halftones record the type. ******
+ */
+int cmd_put_halftone(P3(gx_device_clist_writer * cldev,
+ const gx_device_halftone * pdht, gs_halftone_type type));
+
+/* ------ Exported by gxclrast.c for gxclread.c ------ */
+
+/*
+ * Define whether we are actually rendering a band, or just executing
+ * the put_params that occurs at the beginning of each page.
+ */
+typedef enum {
+ playback_action_render,
+ playback_action_setup
+} clist_playback_action;
+
+/* Play back and rasterize one band. */
+int clist_playback_band(P7(clist_playback_action action,
+ gx_device_clist_reader *cdev,
+ stream *s, gx_device *target,
+ int x0, int y0, gs_memory_t *mem));
+
+#endif /* gxcldev_INCLUDED */
diff --git a/pstoraster/gxclimag.c b/pstoraster/gxclimag.c
new file mode 100644
index 000000000..6209c95ca
--- /dev/null
+++ b/pstoraster/gxclimag.c
@@ -0,0 +1,1316 @@
+/* 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$ */
+/* Higher-level image operations for band lists */
+#include "math_.h"
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gscspace.h"
+#include "gxarith.h"
+#include "gxdevice.h"
+#include "gxdevmem.h" /* must precede gxcldev.h */
+#include "gxcldev.h"
+#include "gxclpath.h"
+#include "gxfmap.h"
+#include "gxiparam.h"
+#include "gxpath.h"
+#include "strimpl.h" /* for siscale.h */
+#include "siscale.h"
+
+/* Define whether we should use high-level images. */
+/* (See below for additional restrictions.) */
+static bool USE_HL_IMAGES = true;
+
+/* Forward references */
+private int cmd_put_color_mapping(P3(gx_device_clist_writer * cldev,
+ const gs_imager_state * pis,
+ bool write_rgb_to_cmyk));
+private bool check_rect_for_trivial_clip(P5(
+ const gx_clip_path *pcpath, /* May be NULL, clip to evaluate */
+ int px, int py, int qx, int qy /* corners of box to test */
+));
+
+/* ------ Driver procedures ------ */
+
+int
+clist_fill_mask(gx_device * dev,
+ const byte * data, int data_x, int raster, gx_bitmap_id id,
+ int x, int y, int width, int height,
+ const gx_drawing_color * pdcolor, int depth,
+ gs_logical_operation_t lop, const gx_clip_path * pcpath)
+{
+ gx_device_clist_writer * const cdev =
+ &((gx_device_clist *)dev)->writer;
+ const byte *orig_data = data; /* for writing tile */
+ int orig_data_x = data_x; /* ditto */
+ int orig_x = x; /* ditto */
+ int orig_width = width; /* ditto */
+ int orig_height = height; /* ditto */
+ int log2_depth = depth >> 1; /* works for 1,2,4 */
+ int y0;
+ int data_x_bit;
+ byte copy_op =
+ (depth > 1 ? cmd_op_copy_color_alpha :
+ gx_dc_is_pure(pdcolor) ? cmd_op_copy_mono :
+ cmd_op_copy_mono + cmd_copy_ht_color);
+
+ fit_copy(dev, data, data_x, raster, id, x, y, width, height);
+ y0 = y; /* must do after fit_copy */
+
+ /* If non-trivial clipping & complex clipping disabled, default */
+ if ((cdev->disable_mask & clist_disable_complex_clip) &&
+ !check_rect_for_trivial_clip(pcpath, x, y, x + width, y + height)
+ )
+ return gx_default_fill_mask(dev, data, data_x, raster, id,
+ x, y, width, height, pdcolor, depth,
+ lop, pcpath);
+ if (cmd_check_clip_path(cdev, pcpath))
+ cmd_clear_known(cdev, clip_path_known);
+ data_x_bit = data_x << log2_depth;
+ FOR_RECTS {
+ int dx = (data_x_bit & 7) >> log2_depth;
+ const byte *row = data + (y - y0) * raster + (data_x_bit >> 3);
+ int code;
+
+ TRY_RECT {
+ code = cmd_update_lop(cdev, pcls, lop);
+ } HANDLE_RECT(code);
+ if (depth > 1 && !pcls->color_is_alpha) {
+ byte *dp;
+
+ TRY_RECT {
+ code =
+ set_cmd_put_op(dp, cdev, pcls, cmd_opv_set_copy_alpha, 1);
+ } HANDLE_RECT(code);
+ pcls->color_is_alpha = 1;
+ }
+ TRY_RECT {
+ code = cmd_do_write_unknown(cdev, pcls, clip_path_known);
+ if (code >= 0)
+ code = cmd_do_enable_clip(cdev, pcls, pcpath != NULL);
+ } HANDLE_RECT(code);
+ TRY_RECT {
+ code = cmd_put_drawing_color(cdev, pcls, pdcolor);
+ } HANDLE_RECT(code);
+ /*
+ * Unfortunately, painting a character with a halftone requires the
+ * use of two bitmaps, a situation that we can neither represent in
+ * the band list nor guarantee will both be present in the tile
+ * cache; in this case, we always write the bits of the character.
+ *
+ * We could handle more RasterOp cases here directly, but it
+ * doesn't seem worth the trouble right now.
+ */
+ if (id != gx_no_bitmap_id && gx_dc_is_pure(pdcolor) &&
+ lop == lop_default
+ ) { /* This is a character. ****** WRONG IF HALFTONE CELL. ***** */
+ /* Put it in the cache if possible. */
+ ulong offset_temp;
+
+ if (!cls_has_tile_id(cdev, pcls, id, offset_temp)) {
+ gx_strip_bitmap tile;
+
+ tile.data = (byte *) orig_data; /* actually const */
+ tile.raster = raster;
+ tile.size.x = tile.rep_width = orig_width;
+ tile.size.y = tile.rep_height = orig_height;
+ tile.rep_shift = tile.shift = 0;
+ tile.id = id;
+ TRY_RECT {
+ code = clist_change_bits(cdev, pcls, &tile, depth);
+ } HANDLE_RECT_UNLESS(code,
+ (code != gs_error_VMerror || !cdev->error_is_retryable) );
+ if (code < 0) {
+ /* Something went wrong; just copy the bits. */
+ goto copy;
+ }
+ } {
+ gx_cmd_rect rect;
+ int rsize;
+ byte op = copy_op + cmd_copy_use_tile;
+ byte *dp;
+
+ /* Output a command to copy the entire character. */
+ /* It will be truncated properly per band. */
+ rect.x = orig_x, rect.y = y0;
+ rect.width = orig_width, rect.height = yend - y0;
+ rsize = 1 + cmd_sizexy(rect);
+ TRY_RECT {
+ code = 0;
+ if (orig_data_x) {
+ int dx_msb = orig_data_x >> 5;
+
+ code = set_cmd_put_op(dp, cdev, pcls, cmd_opv_set_misc,
+ 2 + cmd_size_w(dx_msb));
+ if (code >= 0) {
+ if (dx_msb) {
+ dp[1] = cmd_set_misc_data_x + 0x20 +
+ (orig_data_x & 0x1f);
+ cmd_put_w(dx_msb, dp + 2);
+ } else
+ dp[1] = cmd_set_misc_data_x + orig_data_x;
+ }
+ }
+ if (code >= 0)
+ code = set_cmd_put_op(dp, cdev, pcls, op, rsize);
+ } HANDLE_RECT(code);
+ dp++;
+ cmd_putxy(rect, dp);
+ pcls->rect = rect;
+ goto end;
+ }
+ }
+copy: /*
+ * The default fill_mask implementation uses strip_copy_rop;
+ * this is exactly what we want.
+ */
+ TRY_RECT {
+ NEST_RECT {
+ code = gx_default_fill_mask(dev, row, dx, raster,
+ (y == y0 && height == orig_height &&
+ dx == orig_data_x ? id :
+ gx_no_bitmap_id),
+ x, y, width, height, pdcolor,
+ depth, lop, pcpath);
+ } UNNEST_RECT;
+ } HANDLE_RECT(code);
+end:
+ ;
+ } END_RECTS;
+ return 0;
+}
+
+/* ------ Bitmap image driver procedures ------ */
+
+/* Define the structure for keeping track of progress through an image. */
+typedef struct clist_image_enum_s {
+ gx_image_enum_common;
+ /* Arguments of begin_image */
+ gs_memory_t *memory;
+ gs_image_t image;
+ gx_drawing_color dcolor;
+ gs_int_rect rect;
+ const gs_imager_state *pis;
+ const gx_clip_path *pcpath;
+ /* Set at creation time */
+ gx_image_enum_common_t *default_info;
+ gs_image_format_t format;
+ gs_int_point support; /* extra source pixels for interpolation */
+ int bits_per_plane; /* bits per pixel per plane */
+ gs_matrix matrix; /* image space -> device space */
+ bool uses_color;
+ byte color_space;
+ int ymin, ymax;
+ bool map_rgb_to_cmyk;
+ /* begin_image command prepared & ready to output */
+ byte begin_image_command[3 + 2 * cmd_sizew_max + 14 * sizeof(float) +
+ 4 * cmd_sizew_max];
+ int begin_image_command_length;
+ /* Updated dynamically */
+ int y;
+ bool color_map_is_known;
+} clist_image_enum;
+
+/* We can disregard the pointers in the writer by allocating */
+/* the image enumerator as immovable. This is a hack, of course. */
+gs_private_st_ptrs1(st_clist_image_enum, clist_image_enum, "clist_image_enum",
+ clist_image_enum_enum_ptrs, clist_image_enum_reloc_ptrs, default_info);
+
+private image_enum_proc_plane_data(clist_image_plane_data);
+private image_enum_proc_end_image(clist_image_end_image);
+private const gx_image_enum_procs_t clist_image_enum_procs =
+{
+ clist_image_plane_data, clist_image_end_image
+};
+
+/* Forward declarations */
+private bool image_band_box(P5(gx_device * dev, const clist_image_enum * pie,
+ int y, int h, gs_int_rect * pbox));
+private int begin_image_command(P5(byte *cbuf, const gs_image_t *pim,
+ gs_image_format_t format,
+ int num_components, bool indexed));
+private int cmd_image_plane_data(P7(gx_device_clist_writer * cldev,
+ gx_clist_state * pcls,
+ const gx_image_plane_t * planes,
+ const gx_image_enum_common_t * pie,
+ uint bytes_per_plane,
+ const uint * offsets, int h));
+private uint clist_image_unknowns(P2(gx_device *dev,
+ const clist_image_enum *pie));
+private int write_image_end_all(P2(gx_device *dev,
+ const clist_image_enum *pie));
+
+/*
+ * Since currently we are limited to writing a single subrectangle of the
+ * image for each band, images that are rotated by angles other than
+ * multiples of 90 degrees may wind up writing many copies of the data.
+ * Eventually we will fix this by breaking up the image into multiple
+ * subrectangles, but for now, don't use the high-level approach if it would
+ * cause the data to explode because of this.
+ */
+private bool
+image_matrix_ok_to_band(const gs_matrix * pmat)
+{
+ /* Don't band if the matrix is (nearly) singular. */
+ if (fabs(pmat->xx * pmat->yy - pmat->xy * pmat->yx) < 0.001)
+ return false;
+ if (is_xxyy(pmat) || is_xyyx(pmat))
+ return true;
+ return false;
+}
+
+/* Start processing an image. */
+int
+clist_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)
+{
+ gx_device_clist_writer * const cdev =
+ &((gx_device_clist *)dev)->writer;
+ clist_image_enum *pie;
+ int base_index;
+ bool indexed;
+ int num_components;
+ int bits_per_pixel;
+ bool uses_color;
+ bool varying_depths = false;
+ gs_matrix mat;
+ gs_rect sbox, dbox;
+ bool use_default_image;
+ int code;
+
+ /* See above for why we allocate the enumerator as immovable. */
+ pie = gs_alloc_struct_immovable(mem, clist_image_enum,
+ &st_clist_image_enum,
+ "clist_begin_image");
+ if (pie == 0)
+ return_error(gs_error_VMerror);
+ pie->memory = mem;
+ *pinfo = (gx_image_enum_common_t *) pie;
+ /* num_planes and plane_depths[] are set later, */
+ /* by gx_image_enum_common_init. */
+ if (pim->ImageMask) {
+ base_index = gs_color_space_index_DeviceGray; /* arbitrary */
+ indexed = false;
+ num_components = 1;
+ uses_color = true;
+ } else {
+ const gs_color_space *pcs = pim->ColorSpace;
+
+ base_index = gs_color_space_get_index(pcs);
+ if (base_index == gs_color_space_index_Indexed) {
+ const gs_color_space *pbcs =
+ gs_color_space_indexed_base_space(pcs);
+
+ indexed = true;
+ base_index = gs_color_space_get_index(pbcs);
+ num_components = 1;
+ } else {
+ indexed = false;
+ num_components = gs_color_space_num_components(pcs);
+ }
+ uses_color = pim->CombineWithColor && rop3_uses_T(pis->log_op);
+ }
+ code = gx_image_enum_common_init((gx_image_enum_common_t *) pie,
+ (const gs_image_common_t *) pim,
+ &clist_image_enum_procs, dev,
+ pim->BitsPerComponent,
+ num_components, format);
+ {
+ int i;
+
+ for (i = 1; i < pie->num_planes; ++i)
+ varying_depths |= pie->plane_depths[i] != pie->plane_depths[0];
+ }
+ use_default_image =
+ (code < 0 ||
+ !USE_HL_IMAGES || /* Always use the default. */
+ (cdev->disable_mask & clist_disable_hl_image) ||
+ cdev->image_enum_id != gs_no_id || /* Can't handle nested images */
+ /****** CAN'T HANDLE CIE COLOR YET ******/
+ base_index > gs_color_space_index_DeviceCMYK ||
+ /****** CAN'T HANDLE INDEXED COLOR (READING MAP) ******/
+ indexed ||
+ /****** CAN'T HANDLE NON-PURE COLORS YET ******/
+ (uses_color && !gx_dc_is_pure(pdcolor)) ||
+ /****** CAN'T HANDLE IMAGES WITH ALPHA YET ******/
+ pim->Alpha ||
+ /****** CAN'T HANDLE IMAGES WITH IRREGULAR DEPTHS ******/
+ varying_depths ||
+ (code = gs_matrix_invert(&pim->ImageMatrix, &mat)) < 0 ||
+ (code = gs_matrix_multiply(&mat, &ctm_only(pis), &mat)) < 0 ||
+ !(cdev->disable_mask & clist_disable_nonrect_hl_image ?
+ (is_xxyy(&mat) || is_xyyx(&mat)) :
+ image_matrix_ok_to_band(&mat))
+ );
+ if (!use_default_image) {
+ int bytes_per_plane, bytes_per_row;
+
+ bits_per_pixel = pim->BitsPerComponent * num_components;
+ pie->default_info = 0;
+ pie->image = *pim;
+ pie->dcolor = *pdcolor;
+ if (prect)
+ pie->rect = *prect;
+ else {
+ pie->rect.p.x = 0, pie->rect.p.y = 0;
+ pie->rect.q.x = pim->Width, pie->rect.q.y = pim->Height;
+ }
+ pie->pis = pis;
+ pie->pcpath = pcpath;
+ pie->format = format;
+ pie->bits_per_plane = bits_per_pixel / pie->num_planes;
+ pie->matrix = mat;
+ pie->uses_color = uses_color;
+ pie->color_space = (base_index << 4) |
+ (indexed ? (pim->ColorSpace->params.indexed.use_proc ? 12 : 8) : 0);
+ pie->y = pie->rect.p.y;
+
+ /* Image row has to fit in cmd writer's buffer */
+ bytes_per_plane =
+ (pim->Width * pie->bits_per_plane + 7) >> 3;
+ bytes_per_row = bytes_per_plane * pie->num_planes;
+ bytes_per_row = max(bytes_per_row, 1);
+ use_default_image = cmd_largest_size + bytes_per_row >
+ cdev->cend - cdev->cbuf;
+ }
+ if (!use_default_image) {
+ sbox.p.x = pie->rect.p.x;
+ sbox.p.y = pie->rect.p.y;
+ sbox.q.x = pie->rect.q.x;
+ sbox.q.y = pie->rect.q.y;
+ gs_bbox_transform(&sbox, &mat, &dbox);
+
+ if (cdev->disable_mask & clist_disable_complex_clip)
+ use_default_image =
+ !check_rect_for_trivial_clip( pcpath,
+ (int)(dbox.p.x), (int)(dbox.p.y),
+ (int)ceil(dbox.q.x), (int)ceil(dbox.q.y) );
+ }
+ pie->map_rgb_to_cmyk = dev->color_info.num_components == 4 &&
+ base_index == gs_color_space_index_DeviceRGB;
+ pie->color_map_is_known = false;
+ if (use_default_image) {
+ int code = gx_default_begin_image(dev, pis, pim, format, prect,
+ pdcolor, pcpath, mem,
+ &pie->default_info);
+
+ if (code < 0)
+ gs_free_object(mem, pie, "clist_begin_image");
+ return code;
+ }
+
+ /* Create the begin_image command. */
+
+ pie->begin_image_command_length =
+ begin_image_command(pie->begin_image_command, pim, format,
+ num_components, indexed);
+ if (pim->Interpolate)
+ pie->support.x = pie->support.y = max_support + 1;
+ else
+ pie->support.x = pie->support.y = 0;
+ sbox.p.x = pie->rect.p.x - pie->support.x;
+ sbox.p.y = pie->rect.p.y - pie->support.y;
+ sbox.q.x = pie->rect.q.x + pie->support.x;
+ sbox.q.y = pie->rect.q.y + pie->support.y;
+ gs_bbox_transform(&sbox, &pie->matrix, &dbox);
+ {
+ int y0 = (int)floor(dbox.p.y - 0.51); /* adjust + rounding slop */
+ int y1 = (int)ceil(dbox.q.y + 0.51); /* ditto */
+
+ pie->ymin = max(y0, 0);
+ pie->ymax = min(y1, dev->height);
+ }
+
+ /*
+ * Make sure the CTM, color space, and clipping region (and, for
+ * masked images or images with CombineWithColor, the current color)
+ * are known at the time of the begin_image command.
+ */
+ cmd_clear_known(cdev, clist_image_unknowns(dev, pie) | begin_image_known);
+
+ cdev->image_enum_id = pie->id;
+ return 0;
+}
+
+/* Process the next piece of an image. */
+private int
+clist_image_plane_data(gx_device * dev,
+ gx_image_enum_common_t * info, const gx_image_plane_t * planes, int yh)
+{
+ gx_device_clist_writer * const cdev =
+ &((gx_device_clist *)dev)->writer;
+ clist_image_enum *pie = (clist_image_enum *) info;
+ gs_rect sbox, dbox;
+ int y0, y1;
+ int y, height; /* for BEGIN/END_RECT */
+ int code;
+
+ if (pie->default_info)
+ return gx_image_plane_data(pie->default_info, planes, yh);
+#ifdef DEBUG
+ if (pie->id != cdev->image_enum_id) {
+ lprintf2("end_image id = %lu != clist image id = %lu!\n",
+ (ulong) pie->id, (ulong) cdev->image_enum_id);
+ return_error(gs_error_Fatal);
+ }
+#endif
+ /****** CAN'T HANDLE VARYING data_x VALUES YET ******/
+ {
+ int i;
+
+ for (i = 1; i < info->num_planes; ++i)
+ if (planes[i].data_x != planes[0].data_x)
+ return_error(gs_error_rangecheck);
+ }
+ sbox.p.x = pie->rect.p.x - pie->support.x;
+ sbox.p.y = (y0 = pie->y) - pie->support.y;
+ sbox.q.x = pie->rect.q.x + pie->support.x;
+ sbox.q.y = (y1 = pie->y += yh) + pie->support.y;
+ gs_bbox_transform(&sbox, &pie->matrix, &dbox);
+ /*
+ * In order to keep the band list consistent, we must write out
+ * the image data in precisely those bands whose begin_image
+ * Y range includes the respective image scan lines. Because of
+ * rounding, we must expand the dbox by a little extra, and then
+ * use image_band_box to calculate the precise range for each band.
+ * This is slow, but we don't see any faster way to do it in the
+ * general case.
+ */
+ {
+ int ry0 = (int)floor(dbox.p.y) - 2;
+ int ry1 = (int)ceil(dbox.q.y) + 2;
+ int band_height = cdev->page_band_height;
+
+ /*
+ * Make sure we don't go beyond the Y range determined at
+ * begin_image time.
+ */
+ if (ry0 < pie->ymin)
+ ry0 = pie->ymin;
+ if (ry1 > pie->ymax)
+ ry1 = pie->ymax;
+ y = ry0 / band_height * band_height;
+ height = min(round_up(ry1, band_height), dev->height) - y;
+ }
+
+ FOR_RECTS {
+ /*
+ * Just transmit the subset of the data that intersects this band.
+ * Note that y and height always define a complete band.
+ */
+ gs_int_rect ibox;
+#define bx0 ibox.p.x
+#define by0 ibox.p.y
+#define bx1 ibox.q.x
+#define by1 ibox.q.y
+ int bpp = pie->bits_per_plane;
+ int num_planes = pie->num_planes;
+ uint offsets[gs_image_max_components];
+ int i, iy, ih, xskip, nrows;
+ uint bytes_per_plane, bytes_per_row, rows_per_cmd;
+
+ if (!image_band_box(dev, pie, y, height, &ibox))
+ continue;
+
+ /* Write out begin_image & its preamble for this band */
+ if (!(pcls->known & begin_image_known)) {
+ gs_logical_operation_t lop = pie->pis->log_op;
+ byte *dp;
+ gs_int_rect entire_box;
+ byte cb = pie->begin_image_command[0];
+ byte *bp = pie->begin_image_command +
+ pie->begin_image_command_length;
+ uint len;
+ uint band_ymax, band_ymin;
+
+ /* Compute intersection of entire band & entire image src rect */
+ band_ymax = min(band_end, pie->ymax);
+ band_ymin = max(band_end - band_height, pie->ymin);
+ if (!image_band_box(dev, pie, band_ymin,
+ band_ymax - band_ymin, &entire_box))
+ continue;
+
+ /* Make sure the imager state is up to date. */
+ TRY_RECT {
+ code = (pie->color_map_is_known ? 0 :
+ cmd_put_color_mapping(cdev, pie->pis,
+ pie->map_rgb_to_cmyk));
+ pie->color_map_is_known = true;
+ if (code >= 0)
+ code = cmd_do_write_unknown(cdev, pcls,
+ ctm_known | clip_path_known | color_space_known);
+ if (code >= 0)
+ code = cmd_do_enable_clip(cdev, pcls, pie->pcpath != NULL);
+ if (code >= 0)
+ code = cmd_update_lop(cdev, pcls, lop);
+ } HANDLE_RECT(code);
+ if (pie->uses_color) {
+ TRY_RECT {
+ code = cmd_put_drawing_color(cdev, pcls, &pie->dcolor);
+ } HANDLE_RECT(code);
+ }
+ if (entire_box.p.x != 0 || entire_box.p.y != 0 ||
+ entire_box.q.x != pie->image.Width ||
+ entire_box.q.y != pie->image.Height
+ ) {
+ cb |= 1 << 0;
+ cmd_put2w(entire_box.p.x, entire_box.p.y, bp);
+ cmd_put2w(pie->image.Width - entire_box.q.x,
+ pie->image.Height - entire_box.q.y, bp);
+ }
+ len = bp - pie->begin_image_command;
+ TRY_RECT {
+ code =
+ set_cmd_put_op(dp, cdev, pcls, cmd_opv_begin_image,
+ 1 + len);
+ } HANDLE_RECT(code);
+ dp[1] = cb;
+ memcpy(dp + 2, pie->begin_image_command + 1, len - 1);
+
+ /* Mark band's begin_image as known */
+ pcls->known |= begin_image_known;
+ }
+
+ if (by0 < y0)
+ by0 = y0;
+ if (by1 > y1)
+ by1 = y1;
+ /*
+ * Make sure we're skipping an integral number of pixels, by
+ * truncating the initial X coordinate to the next lower
+ * value that is an exact multiple of a byte.
+ */
+ xskip = bx0 & -(int)"\001\010\004\010\002\010\004\010"[bpp & 7];
+ for (i = 0; i < num_planes; ++i)
+ offsets[i] = (by0 - y0) * planes[i].raster + ((xskip * bpp) >> 3);
+ xskip = bx0 - xskip;
+ bytes_per_plane = ((xskip + bx1 - bx0) * bpp + 7) >> 3;
+ bytes_per_row = bytes_per_plane * pie->num_planes;
+ rows_per_cmd =
+ (cbuf_size - cmd_largest_size) / max(bytes_per_row, 1);
+
+ if (rows_per_cmd == 0) { /* The reader will have to buffer a row separately. */
+ rows_per_cmd = 1;
+ }
+ for (iy = by0, ih = by1 - by0; ih > 0; iy += nrows, ih -= nrows) {
+ nrows = min(ih, rows_per_cmd);
+ TRY_RECT {
+ code = cmd_image_plane_data(cdev, pcls, planes, info,
+ bytes_per_plane, offsets, nrows);
+ } HANDLE_RECT(code);
+ for (i = 0; i < num_planes; ++i)
+ offsets[i] += planes[i].raster * nrows;
+ }
+#undef bx0
+#undef by0
+#undef bx1
+#undef by1
+ } END_RECTS_ON_ERROR(\
+ BEGIN\
+ ++cdev->ignore_lo_mem_warnings;\
+ NEST_RECT {\
+ code = write_image_end_all(dev, pie);\
+ } UNNEST_RECT;\
+ --cdev->ignore_lo_mem_warnings;\
+ END,\
+ (code < 0 ? (band_code = code) : code) >= 0,\
+ (cmd_clear_known(cdev,\
+ clist_image_unknowns(dev, pie) | begin_image_known),\
+ pie->color_map_is_known = false, true)\
+ );
+ /* Update sub-rect in case memory exhaustion forced end_image */
+ if (!pie->image.Interpolate)
+ pie->rect.p.y += yh; /* interpolate & mem recovery currently incompat */
+ return pie->y >= pie->rect.q.y;
+}
+
+/* Clean up by releasing the buffers. */
+private int
+clist_image_end_image(gx_device * dev, gx_image_enum_common_t * info,
+ bool draw_last)
+{
+ gx_device_clist_writer * const cdev =
+ &((gx_device_clist *)dev)->writer;
+ clist_image_enum *pie = (clist_image_enum *) info;
+ int code;
+
+ if (pie->default_info)
+ code = gx_default_end_image(dev, pie->default_info, draw_last);
+ else {
+#ifdef DEBUG
+ if (pie->id != cdev->image_enum_id) {
+ lprintf2("end_image id = %lu != clist image id = %lu!\n",
+ (ulong) pie->id, (ulong) cdev->image_enum_id);
+ return_error(gs_error_Fatal);
+ }
+#endif
+ NEST_RECT {
+ do {
+ code = write_image_end_all(dev, pie);
+ } while (code < 0 && cdev->error_is_retryable &&
+ (code = clist_VMerror_recover(cdev, code)) >= 0
+ );
+ /* if couldn't write successsfully, do a hard flush */
+ if (code < 0 && cdev->error_is_retryable) {
+ int retry_code;
+ ++cdev->ignore_lo_mem_warnings;
+ retry_code = write_image_end_all(dev, pie); /* force it out */
+ --cdev->ignore_lo_mem_warnings;
+ if (retry_code >= 0 && cdev->driver_call_nesting == 0)
+ code = clist_VMerror_recover_flush(cdev, code);
+ }
+ } UNNEST_RECT;
+ cdev->image_enum_id = gs_no_id;
+ }
+ gs_free_object(pie->memory, pie, "clist_image_end_image");
+ return code;
+}
+
+/* Start processing a general image. */
+int
+clist_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 * mem, gx_image_enum_common_t ** pinfo)
+{
+ /****** NYI ******/
+ return gx_default_begin_typed_image(dev, pis, pmat, pim, prect,
+ pdcolor, pcpath, mem, pinfo);
+}
+
+/* Create a compositor device. */
+int
+clist_create_compositor(gx_device * dev,
+ gx_device ** pcdev, const gs_composite_t * pcte,
+ const gs_imager_state * pis, gs_memory_t * mem)
+{
+ /****** NYI ******/
+ return gx_no_create_compositor(dev, pcdev, pcte, pis, mem);
+}
+
+/* ------ Utilities ------ */
+
+/* Add commands to represent a halftone order. */
+private int
+cmd_put_ht_order(gx_device_clist_writer * cldev, const gx_ht_order * porder,
+ gs_ht_separation_name cname,
+ int component /* -1 = default/gray/black screen */ )
+{
+ byte command[cmd_max_intsize(sizeof(long)) * 8];
+ byte *cp;
+ uint len;
+ byte *dp;
+ uint i, n;
+ int code;
+
+ /* Put out the order parameters. */
+ cp = cmd_put_w(component + 1, command);
+ if (component >= 0)
+ cp = cmd_put_w(cname, cp);
+ cp = cmd_put_w(porder->width, cp);
+ cp = cmd_put_w(porder->height, cp);
+ cp = cmd_put_w(porder->raster, cp);
+ cp = cmd_put_w(porder->shift, cp);
+ cp = cmd_put_w(porder->num_levels, cp);
+ cp = cmd_put_w(porder->num_bits, cp);
+ len = cp - command;
+ code = set_cmd_put_all_op(dp, cldev, cmd_opv_set_ht_order, len + 1);
+ if (code < 0)
+ return code;
+ memcpy(dp + 1, command, len);
+
+ /* Put out the transfer function, if any. */
+ code = cmd_put_color_map(cldev, cmd_map_ht_transfer, porder->transfer,
+ NULL);
+ if (code < 0)
+ return code;
+
+ /* Put out the levels array. */
+#define nlevels min((cbuf_size - 2) / sizeof(*porder->levels), 255)
+ for (i = 0; i < porder->num_levels; i += n) {
+ n = porder->num_levels - i;
+ if (n > nlevels)
+ n = nlevels;
+ code = set_cmd_put_all_op(dp, cldev, cmd_opv_set_ht_data,
+ 2 + n * sizeof(*porder->levels));
+ if (code < 0)
+ return code;
+ dp[1] = n;
+ memcpy(dp + 2, porder->levels + i, n * sizeof(*porder->levels));
+ }
+#undef nlevels
+
+ /* Put out the bits array. */
+#define nbits min((cbuf_size - 2) / sizeof(*porder->bits), 255)
+ for (i = 0; i < porder->num_bits; i += n) {
+ n = porder->num_bits - i;
+ if (n > nbits)
+ n = nbits;
+ code = set_cmd_put_all_op(dp, cldev, cmd_opv_set_ht_data,
+ 2 + n * sizeof(*porder->bits));
+ if (code < 0)
+ return code;
+ dp[1] = n;
+ memcpy(dp + 2, porder->bits + i, n * sizeof(*porder->bits));
+ }
+#undef nbits
+
+ return 0;
+}
+
+/* Add commands to represent a full (device) halftone. */
+/* We put out the default/gray/black screen last so that the reading */
+/* pass can recognize the end of the halftone. */
+int
+cmd_put_halftone(gx_device_clist_writer * cldev, const gx_device_halftone * pdht,
+ gs_halftone_type type)
+{
+ uint num_comp = (pdht->components == 0 ? 0 : pdht->num_comp);
+
+ {
+ byte *dp;
+ int code = set_cmd_put_all_op(dp, cldev, cmd_opv_set_misc,
+ 2 + cmd_size_w(num_comp));
+
+ if (code < 0)
+ return code;
+ dp[1] = cmd_set_misc_halftone + type;
+ cmd_put_w(num_comp, dp + 2);
+ }
+ if (num_comp == 0)
+ return cmd_put_ht_order(cldev, &pdht->order,
+ gs_ht_separation_Default, -1);
+ {
+ int i;
+
+ for (i = num_comp; --i >= 0;) {
+ int code = cmd_put_ht_order(cldev, &pdht->components[i].corder,
+ pdht->components[i].cname, i);
+
+ if (code < 0)
+ return code;
+ }
+ }
+ return 0;
+}
+
+/* Write out any necessary color mapping data. */
+private int
+cmd_put_color_mapping(gx_device_clist_writer * cldev,
+ const gs_imager_state * pis, bool write_rgb_to_cmyk)
+{
+ int code;
+ const gx_device_halftone *pdht = pis->dev_ht;
+
+ /* Put out the halftone. */
+ if (pdht->id != cldev->device_halftone_id) {
+ code = cmd_put_halftone(cldev, pdht, pis->halftone->type);
+ if (code < 0)
+ return code;
+ cldev->device_halftone_id = pdht->id;
+ }
+ /* If we need to map RGB to CMYK, put out b.g. and u.c.r. */
+ if (write_rgb_to_cmyk) {
+ code = cmd_put_color_map(cldev, cmd_map_black_generation,
+ pis->black_generation,
+ &cldev->black_generation_id);
+ if (code < 0)
+ return code;
+ code = cmd_put_color_map(cldev, cmd_map_undercolor_removal,
+ pis->undercolor_removal,
+ &cldev->undercolor_removal_id);
+ if (code < 0)
+ return code;
+ }
+ /* Now put out the transfer functions. */
+ {
+ uint which = 0;
+ bool all_same = true;
+ int i;
+
+ for (i = 0; i < countof(cldev->transfer_ids); ++i) {
+ if (pis->effective_transfer.indexed[i]->id !=
+ cldev->transfer_ids[i]
+ )
+ which |= 1 << i;
+ if (pis->effective_transfer.indexed[i]->id !=
+ pis->effective_transfer.indexed[0]->id
+ )
+ all_same = false;
+ }
+ /* There are 3 cases for transfer functions: nothing to write, */
+ /* a single function, and multiple functions. */
+ if (which == 0)
+ return 0;
+ if (which == (1 << countof(cldev->transfer_ids)) - 1 && all_same) {
+ code = cmd_put_color_map(cldev, cmd_map_transfer,
+ pis->effective_transfer.indexed[0],
+ &cldev->transfer_ids[0]);
+ if (code < 0)
+ return code;
+ for (i = 1; i < countof(cldev->transfer_ids); ++i)
+ cldev->transfer_ids[i] = cldev->transfer_ids[0];
+ } else
+ for (i = 0; i < countof(cldev->transfer_ids); ++i) {
+ code = cmd_put_color_map(cldev,
+ (cmd_map_index) (cmd_map_transfer_0 + i),
+ pis->effective_transfer.indexed[i],
+ &cldev->transfer_ids[i]);
+ if (code < 0)
+ return code;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Compute the subrectangle of an image that intersects a band;
+ * return false if it is empty.
+ * It is OK for this to be too large; in fact, with the present
+ * algorithm, it will be quite a bit too large if the transformation isn't
+ * well-behaved ("well-behaved" meaning either xy = yx = 0 or xx = yy = 0).
+ */
+#define I_FLOOR(x) ((int)floor(x))
+#define I_CEIL(x) ((int)ceil(x))
+private void
+box_merge_point(gs_int_rect * pbox, floatp x, floatp y)
+{
+ int t;
+
+ if ((t = I_FLOOR(x)) < pbox->p.x)
+ pbox->p.x = t;
+ if ((t = I_CEIL(x)) > pbox->q.x)
+ pbox->q.x = t;
+ if ((t = I_FLOOR(y)) < pbox->p.y)
+ pbox->p.y = t;
+ if ((t = I_CEIL(y)) > pbox->q.y)
+ pbox->q.y = t;
+}
+private bool
+image_band_box(gx_device * dev, const clist_image_enum * pie, int y, int h,
+ gs_int_rect * pbox)
+{
+ fixed by0 = int2fixed(y);
+ fixed by1 = int2fixed(y + h);
+ int
+ px = pie->rect.p.x, py = pie->rect.p.y, qx = pie->rect.q.x, qy = pie->rect.q.y;
+ gs_fixed_rect cbox; /* device clipping box */
+ gs_rect bbox; /* cbox intersected with band */
+
+ /* Intersect the device clipping box and the band. */
+ (*dev_proc(dev, get_clipping_box)) (dev, &cbox);
+ /* The fixed_half here is to allow for adjustment. */
+ bbox.p.x = fixed2float(cbox.p.x - fixed_half);
+ bbox.q.x = fixed2float(cbox.q.x + fixed_half);
+ bbox.p.y = fixed2float(max(cbox.p.y, by0) - fixed_half);
+ bbox.q.y = fixed2float(min(cbox.q.y, by1) + fixed_half);
+#ifdef DEBUG
+ if (gs_debug_c('b')) {
+ dlprintf6("[b]band box for (%d,%d),(%d,%d), band (%d,%d) =>\n",
+ px, py, qx, qy, y, y + h);
+ dlprintf10(" (%g,%g),(%g,%g), matrix=[%g %g %g %g %g %g]\n",
+ bbox.p.x, bbox.p.y, bbox.q.x, bbox.q.y,
+ pie->matrix.xx, pie->matrix.xy, pie->matrix.yx,
+ pie->matrix.yy, pie->matrix.tx, pie->matrix.ty);
+ }
+#endif
+ if (is_xxyy(&pie->matrix) || is_xyyx(&pie->matrix)) {
+ /*
+ * The inverse transform of the band is a rectangle aligned with
+ * the coordinate axes, so we can just intersect it with the
+ * image subrectangle.
+ */
+ gs_rect ibox; /* bbox transformed back to image space */
+
+ if (gs_bbox_transform_inverse(&bbox, &pie->matrix, &ibox) < 0)
+ return false;
+ pbox->p.x = max(px, I_FLOOR(ibox.p.x));
+ pbox->q.x = min(qx, I_CEIL(ibox.q.x));
+ pbox->p.y = max(py, I_FLOOR(ibox.p.y));
+ pbox->q.y = min(qy, I_CEIL(ibox.q.y));
+ } else {
+ /*
+ * The inverse transform of the band is not aligned with the
+ * axes, i.e., is a general parallelogram. To compute an exact
+ * bounding box, we need to find the intersections of this
+ * parallelogram with the image subrectangle.
+ *
+ * There is probably a much more efficient way to do this
+ * computation, but we don't know what it is.
+ */
+ gs_point rect[4];
+ gs_point corners[5];
+ int i;
+
+ /* Store the corners of the image rectangle. */
+ rect[0].x = rect[3].x = px;
+ rect[1].x = rect[2].x = qx;
+ rect[0].y = rect[1].y = py;
+ rect[2].y = rect[3].y = qy;
+ /*
+ * Compute the corners of the clipped band in image space. If
+ * the matrix is singular or an overflow occurs, the result will
+ * be nonsense: in this case, there isn't anything useful we
+ * can do, so return an empty intersection.
+ */
+ if (gs_point_transform_inverse(bbox.p.x, bbox.p.y, &pie->matrix,
+ &corners[0]) < 0 ||
+ gs_point_transform_inverse(bbox.q.x, bbox.p.y, &pie->matrix,
+ &corners[1]) < 0 ||
+ gs_point_transform_inverse(bbox.q.x, bbox.q.y, &pie->matrix,
+ &corners[2]) < 0 ||
+ gs_point_transform_inverse(bbox.p.x, bbox.q.y, &pie->matrix,
+ &corners[3]) < 0
+ ) {
+ if_debug0('b', "[b]can't inverse-transform a band corner!\n");
+ return false;
+ }
+ corners[4] = corners[0];
+ pbox->p.x = qx, pbox->p.y = qy;
+ pbox->q.x = px, pbox->q.y = py;
+ /*
+ * We iterate over both the image rectangle and the band
+ * parallelogram in a single loop for convenience, even though
+ * there is no coupling between the two.
+ */
+ for (i = 0; i < 4; ++i) {
+ gs_point pa, pt;
+ double dx, dy;
+
+ /* Check the image corner for being inside the band. */
+ pa = rect[i];
+ gs_point_transform(pa.x, pa.y, &pie->matrix, &pt);
+ if (pt.x >= bbox.p.x && pt.x <= bbox.q.x &&
+ pt.y >= bbox.p.y && pt.y <= bbox.q.y
+ )
+ box_merge_point(pbox, pa.x, pa.y);
+ /* Check the band corner for being inside the image. */
+ pa = corners[i];
+ if (pa.x >= px && pa.x <= qx && pa.y >= py && pa.y <= qy)
+ box_merge_point(pbox, pa.x, pa.y);
+ /* Check for intersections of band edges with image edges. */
+ dx = corners[i + 1].x - pa.x;
+ dy = corners[i + 1].y - pa.y;
+#define in_range(t, tc, p, q)\
+ (0 <= t && t <= 1 && (t = tc) >= p && t <= q)
+ if (dx != 0) {
+ double t = (px - pa.x) / dx;
+
+ if_debug3('b', " (px) t=%g => (%d,%g)\n",
+ t, px, pa.y + t * dy);
+ if (in_range(t, pa.y + t * dy, py, qy))
+ box_merge_point(pbox, (floatp) px, t);
+ t = (qx - pa.x) / dx;
+ if_debug3('b', " (qx) t=%g => (%d,%g)\n",
+ t, qx, pa.y + t * dy);
+ if (in_range(t, pa.y + t * dy, py, qy))
+ box_merge_point(pbox, (floatp) qx, t);
+ }
+ if (dy != 0) {
+ double t = (py - pa.y) / dy;
+
+ if_debug3('b', " (py) t=%g => (%g,%d)\n",
+ t, pa.x + t * dx, py);
+ if (in_range(t, pa.x + t * dx, px, qx))
+ box_merge_point(pbox, t, (floatp) py);
+ t = (qy - pa.y) / dy;
+ if_debug3('b', " (qy) t=%g => (%g,%d)\n",
+ t, pa.x + t * dx, qy);
+ if (in_range(t, pa.x + t * dx, px, qx))
+ box_merge_point(pbox, t, (floatp) qy);
+ }
+#undef in_range
+ }
+ }
+ if_debug4('b', " => (%d,%d),(%d,%d)\n", pbox->p.x, pbox->p.y,
+ pbox->q.x, pbox->q.y);
+ /*
+ * If necessary, add pixels around the edges so we will have
+ * enough information to do interpolation.
+ */
+ if ((pbox->p.x -= pie->support.x) < pie->rect.p.x)
+ pbox->p.x = pie->rect.p.x;
+ if ((pbox->p.y -= pie->support.y) < pie->rect.p.y)
+ pbox->p.y = pie->rect.p.y;
+ if ((pbox->q.x += pie->support.x) > pie->rect.q.x)
+ pbox->q.x = pie->rect.q.x;
+ if ((pbox->q.y += pie->support.y) > pie->rect.q.y)
+ pbox->q.y = pie->rect.q.y;
+ return (pbox->p.x < pbox->q.x && pbox->p.y < pbox->q.y);
+}
+
+/* Determine which image-related properties are unknown */
+private uint /* mask of unknown properties(see pcls->known) */
+clist_image_unknowns(gx_device *dev, const clist_image_enum *pie)
+{
+ gx_device_clist_writer * const cdev =
+ &((gx_device_clist *)dev)->writer;
+ const gs_imager_state *const pis = pie->pis;
+ uint unknown = 0;
+
+ /*
+ * Determine if the CTM, color space, and clipping region (and, for
+ * masked images or images with CombineWithColor, the current color)
+ * are unknown. Set the device state in anticipation of the values
+ * becoming known.
+ */
+ if (cdev->imager_state.ctm.xx != pis->ctm.xx ||
+ cdev->imager_state.ctm.xy != pis->ctm.xy ||
+ cdev->imager_state.ctm.yx != pis->ctm.yx ||
+ cdev->imager_state.ctm.yy != pis->ctm.yy ||
+ cdev->imager_state.ctm.tx != pis->ctm.tx ||
+ cdev->imager_state.ctm.ty != pis->ctm.ty
+ ) {
+ unknown |= ctm_known;
+ cdev->imager_state.ctm = pis->ctm;
+ }
+ /****** hival CHECK IS NOT SUFFICIENT ******/
+ if (cdev->color_space != pie->color_space ||
+ ((cdev->color_space & 8) != 0 &&
+ cdev->indexed_params.hival !=
+ pie->image.ColorSpace->params.indexed.hival)
+ ) {
+ unknown |= color_space_known;
+ cdev->color_space = pie->color_space;
+ if (cdev->color_space & 8)
+ cdev->indexed_params = pie->image.ColorSpace->params.indexed;
+ }
+ if (cmd_check_clip_path(cdev, pie->pcpath))
+ unknown |= clip_path_known;
+
+ return unknown;
+}
+
+/* Construct the begin_image command. */
+private int
+begin_image_command(byte *cbuf, const gs_image_t *pim,
+ gs_image_format_t format, int num_components,
+ bool indexed)
+{
+ byte *cp;
+ byte b;
+
+ if (pim->ImageMask)
+ b = 0;
+ else
+ switch (pim->BitsPerComponent) {
+ case 1:
+ b = 1 << 5;
+ break;
+ case 2:
+ b = 2 << 5;
+ break;
+ case 4:
+ b = 3 << 5;
+ break;
+ case 8:
+ b = 4 << 5;
+ break;
+ case 12:
+ b = 5 << 5;
+ break;
+ default:
+ return_error(gs_error_rangecheck);
+ }
+ {
+ byte b2 = 0;
+
+ if (format != gs_image_format_chunky) {
+ b |= 1 << 4;
+ b2 |= format << 6;
+ }
+ if (pim->Interpolate) {
+ b |= 1 << 4;
+ b2 |= 1 << 5;
+ }
+ if (pim->Alpha) {
+ b |= 1 << 4;
+ b2 |= pim->Alpha << 3;
+ }
+ if (b & (1 << 4)) {
+ cbuf[1] = b2;
+ cp = cbuf + 2;
+ } else
+ cp = cbuf + 1;
+ }
+ cmd_put2w(pim->Width, pim->Height, cp);
+ if (!(pim->ImageMatrix.xx == pim->Width &&
+ pim->ImageMatrix.xy == 0 &&
+ pim->ImageMatrix.yx == 0 &&
+ pim->ImageMatrix.yy == -pim->Height &&
+ pim->ImageMatrix.tx == 0 &&
+ pim->ImageMatrix.ty == pim->Height
+ )
+ ) {
+ b |= 1 << 3;
+ cp = cmd_for_matrix(cp, &pim->ImageMatrix);
+ }
+ {
+ static const float base_decode[8] = {
+ 0, 1, 0, 1, 0, 1, 0, 1
+ };
+ float indexed_decode[2];
+ const float *default_decode = base_decode;
+ int num_decode = num_components * 2;
+ int i;
+
+ if (indexed) {
+ indexed_decode[0] = 0;
+ indexed_decode[1] = (1 << pim->BitsPerComponent) - 1;
+ default_decode = indexed_decode;
+ }
+ for (i = 0; i < num_decode; ++i)
+ if (pim->Decode[i] != default_decode[i])
+ break;
+ if (i != num_decode) {
+ byte *pdb = cp++;
+ byte dflags = 0;
+
+ b |= 1 << 2;
+ for (i = 0; i < num_decode; i += 2) {
+ float u = pim->Decode[i], v = pim->Decode[i + 1];
+
+ dflags <<= 2;
+ if (u == 0 && v == default_decode[i + 1]);
+ else if (u == default_decode[i + 1] && v == 0)
+ dflags += 1;
+ else {
+ if (u != 0) {
+ dflags++;
+ memcpy(cp, &u, sizeof(float));
+ cp += sizeof(float);
+ }
+ dflags += 2;
+ memcpy(cp, &v, sizeof(float));
+ cp += sizeof(float);
+ }
+ }
+ *pdb = dflags << (8 - num_decode);
+ }
+ }
+ if ((pim->ImageMask ? pim->adjust : pim->CombineWithColor))
+ b |= 1 << 1;
+ cbuf[0] = b;
+ return cp - cbuf;
+}
+
+/* Write data for a partial image. */
+private int
+cmd_image_plane_data(gx_device_clist_writer * cldev, gx_clist_state * pcls,
+ const gx_image_plane_t * planes, const gx_image_enum_common_t * pie,
+ uint bytes_per_plane, const uint * offsets, int h)
+{
+ int data_x = planes[0].data_x;
+ uint nbytes = bytes_per_plane * pie->num_planes * h;
+ uint len = 1 + cmd_size2w(h, bytes_per_plane) + nbytes;
+ byte *dp;
+ uint offset = 0;
+ int plane, i;
+ int code;
+
+ if (data_x) {
+ code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_misc, 2);
+ if (code < 0)
+ return code;
+ dp[1] = cmd_set_misc_data_x + (data_x & 7);
+ offset = ((data_x & ~7) * cldev->color_info.depth) >> 3;
+ }
+ code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_image_data, len);
+ if (code < 0)
+ return code;
+ dp++;
+ cmd_put2w(h, bytes_per_plane, dp);
+ for (plane = 0; plane < pie->num_planes; ++plane)
+ for (i = 0; i < h; ++i) {
+ memcpy(dp,
+ planes[plane].data + i * planes[plane].raster +
+ offsets[plane] + offset,
+ bytes_per_plane);
+ dp += bytes_per_plane;
+ }
+ return 0;
+}
+
+/* Write image_end commands into all bands */
+private int /* ret 0 ok, else -ve error status */
+write_image_end_all(gx_device *dev, const clist_image_enum *pie)
+{
+ gx_device_clist_writer * const cdev =
+ &((gx_device_clist *)dev)->writer;
+ int code;
+ int y = pie->ymin;
+ int height = pie->ymax - y;
+
+ FOR_RECTS {
+ byte *dp;
+
+ if (!(pcls->known & begin_image_known))
+ continue;
+ TRY_RECT {
+ if_debug1('L', "[L]image_end for band %d\n", band);
+ code = set_cmd_put_op(dp, cdev, pcls, cmd_opv_image_data, 2);
+ } HANDLE_RECT(code);
+ dp[1] = 0; /* EOD */
+ pcls->known ^= begin_image_known;
+ } END_RECTS;
+ return 0;
+}
+
+/*
+ * Compare a rectangle vs. clip path. Return true if there is no clipping
+ * path, if the rectangle is unclipped, or if the clipping path is a
+ * rectangle and intersects the given rectangle.
+ */
+private bool
+check_rect_for_trivial_clip(
+ const gx_clip_path *pcpath, /* May be NULL, clip to evaluate */
+ int px, int py, int qx, int qy /* corners of box to test */
+)
+{
+ gs_fixed_rect obox;
+ gs_fixed_rect imgbox;
+
+ if (!pcpath)
+ return true;
+
+ imgbox.p.x = int2fixed(px);
+ imgbox.p.y = int2fixed(py);
+ imgbox.q.x = int2fixed(qx);
+ imgbox.q.y = int2fixed(qy);
+ if (gx_cpath_includes_rectangle(pcpath,
+ imgbox.p.x, imgbox.p.y,
+ imgbox.q.x, imgbox.q.y))
+ return true;
+
+ return (gx_cpath_outer_box(pcpath, &obox) /* cpath is rectangle */ &&
+ obox.p.x <= imgbox.q.x && obox.q.x >= imgbox.p.x &&
+ obox.p.y <= imgbox.q.y && obox.q.y >= imgbox.p.y );
+}
diff --git a/pstoraster/gxclio.h b/pstoraster/gxclio.h
new file mode 100644
index 000000000..c695c5d95
--- /dev/null
+++ b/pstoraster/gxclio.h
@@ -0,0 +1,104 @@
+/* Copyright (C) 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$ */
+/* I/O interface for command lists */
+
+#ifndef gxclio_INCLUDED
+# define gxclio_INCLUDED
+
+#include "gp.h" /* for gp_file_name_sizeof */
+
+/*
+ * There are two implementations of the I/O interface for command lists --
+ * one suitable for embedded systems, which stores the "files" in RAM, and
+ * one suitable for other systems, which uses an external file system --
+ * with the choice made at compile/link time. This header file defines the
+ * API between the command list code proper and its I/O interface.
+ */
+
+typedef void *clist_file_ptr; /* We can't do any better than this. */
+
+/* ---------------- Open/close/unlink ---------------- */
+
+/*
+ * If *fname = 0, generate and store a new scratch file name; otherwise,
+ * open an existing file. Only modes "r" and "w+" are supported,
+ * and only binary data (but the caller must append the "b" if needed).
+ * Mode "r" with *fname = 0 is an error.
+ */
+int clist_fopen(P6(char fname[gp_file_name_sizeof], const char *fmode,
+ clist_file_ptr * pcf,
+ gs_memory_t * mem, gs_memory_t *data_mem,
+ bool ok_to_compress));
+
+/*
+ * Close a file, optionally deleting it.
+ */
+int clist_fclose(P3(clist_file_ptr cf, const char *fname, bool delete));
+
+/*
+ * Delete a file.
+ */
+int clist_unlink(P1(const char *fname));
+
+/* ---------------- Writing ---------------- */
+
+/* clist_space_available returns min(requested, available). */
+long clist_space_available(P1(long requested));
+
+int clist_fwrite_chars(P3(const void *data, uint len, clist_file_ptr cf));
+
+/* ---------------- Reading ---------------- */
+
+int clist_fread_chars(P3(void *data, uint len, clist_file_ptr cf));
+
+/* ---------------- Position/status ---------------- */
+
+/*
+ * Set the low-memory warning threshold. clist_ferror_code will return 1
+ * if fewer than this many bytes of memory are left for storing band data.
+ */
+int clist_set_memory_warning(P2(clist_file_ptr cf, int bytes_left));
+
+/*
+ * clist_ferror_code returns a negative error code per gserrors.h, not a
+ * Boolean; 0 means no error, 1 means low-memory warning.
+ */
+int clist_ferror_code(P1(clist_file_ptr cf));
+
+long clist_ftell(P1(clist_file_ptr cf));
+
+/*
+ * We pass the file name to clist_rewind and clist_fseek in case the
+ * implementation has to close and reopen the file. (clist_fseek with
+ * offset = 0 and mode = SEEK_END indicates we are about to append.)
+ */
+void clist_rewind(P3(clist_file_ptr cf, bool discard_data,
+ const char *fname));
+
+int clist_fseek(P4(clist_file_ptr cf, long offset, int mode,
+ const char *fname));
+
+#endif /* gxclio_INCLUDED */
diff --git a/pstoraster/gxclip.c b/pstoraster/gxclip.c
new file mode 100644
index 000000000..d4139961c
--- /dev/null
+++ b/pstoraster/gxclip.c
@@ -0,0 +1,582 @@
+/* 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$ */
+/* Implementation of (path-based) clipping */
+#include "gx.h"
+#include "gxdevice.h"
+#include "gxclip.h"
+#include "gzpath.h"
+#include "gzcpath.h"
+
+/* Define whether to look for vertical clipping regions. */
+#define CHECK_VERTICAL_CLIPPING
+
+/* ------ Rectangle list clipper ------ */
+
+/* Device for clipping with a region. */
+/* We forward non-drawing operations, but we must be sure to intercept */
+/* all drawing operations. */
+private dev_proc_open_device(clip_open);
+private dev_proc_fill_rectangle(clip_fill_rectangle);
+private dev_proc_copy_mono(clip_copy_mono);
+private dev_proc_copy_color(clip_copy_color);
+private dev_proc_copy_alpha(clip_copy_alpha);
+private dev_proc_fill_mask(clip_fill_mask);
+private dev_proc_strip_tile_rectangle(clip_strip_tile_rectangle);
+private dev_proc_strip_copy_rop(clip_strip_copy_rop);
+private dev_proc_get_clipping_box(clip_get_clipping_box);
+private dev_proc_get_bits_rectangle(clip_get_bits_rectangle);
+
+/* The device descriptor. */
+private const gx_device_clip gs_clip_device =
+{std_device_std_body(gx_device_clip, 0, "clipper",
+ 0, 0, 1, 1),
+ {clip_open,
+ 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,
+ clip_fill_rectangle,
+ gx_default_tile_rectangle,
+ clip_copy_mono,
+ clip_copy_color,
+ gx_default_draw_line,
+ gx_default_get_bits,
+ gx_forward_get_params,
+ gx_forward_put_params,
+ gx_forward_map_cmyk_color,
+ gx_forward_get_xfont_procs,
+ gx_forward_get_xfont_device,
+ gx_forward_map_rgb_alpha_color,
+ gx_forward_get_page_device,
+ gx_forward_get_alpha_bits,
+ clip_copy_alpha,
+ gx_forward_get_band,
+ gx_default_copy_rop,
+ gx_default_fill_path,
+ gx_default_stroke_path,
+ clip_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,
+ clip_strip_tile_rectangle,
+ clip_strip_copy_rop,
+ clip_get_clipping_box,
+ gx_default_begin_typed_image,
+ clip_get_bits_rectangle,
+ gx_forward_map_color_rgb_alpha,
+ gx_no_create_compositor,
+ gx_forward_get_hardware_params,
+ gx_default_text_begin
+ }
+};
+
+/* Make a clipping device. */
+void
+gx_make_clip_translate_device(gx_device_clip * dev, void *container,
+ const gx_clip_list * list, int tx, int ty)
+{
+ gx_device_init((gx_device *) dev, (gx_device *) & gs_clip_device,
+ NULL, true);
+ dev->list = *list;
+ dev->translation.x = tx;
+ dev->translation.y = ty;
+}
+void
+gx_make_clip_path_device(gx_device_clip * dev, const gx_clip_path * pcpath)
+{
+ gx_make_clip_device(dev, NULL, gx_cpath_list(pcpath));
+}
+
+/* Define debugging statistics for the clipping loops. */
+#ifdef DEBUG
+struct stats_clip_s {
+ long
+ loops, in, down, up, x, no_x;
+} stats_clip;
+private uint clip_interval = 10000;
+
+# define INCR(v) (++(stats_clip.v))
+# define INCR_THEN(v, e) (INCR(v), (e))
+#else
+# define INCR(v) DO_NOTHING
+# define INCR_THEN(v, e) (e)
+#endif
+
+/*
+ * Enumerate the rectangles of the x,w,y,h argument that fall within
+ * the clipping region.
+ */
+private int
+clip_enumerate(gx_device_clip * rdev,
+ int (*process) (P5(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec)),
+ clip_callback_data_t * pccd)
+{
+ gx_clip_rect *rptr = rdev->current; /* const within algorithm */
+ const int x = pccd->x, y = pccd->y;
+ const int xe = x + pccd->w, ye = y + pccd->h;
+ int xc, xec, yc, yec, yep;
+ int code;
+
+#ifdef DEBUG
+ if (INCR(loops) % clip_interval == 0)
+ if_debug6('q',
+ "[q]loops=%ld in=%ld down=%ld up=%ld x=%ld no_x=%ld\n", \
+ stats_clip.loops, stats_clip.in,
+ stats_clip.down, stats_clip.up,
+ stats_clip.x, stats_clip.no_x);
+#endif
+ if (pccd->w <= 0 || pccd->h <= 0)
+ return 0;
+ /* Check for the region being entirely within the current rectangle. */
+ if (!rdev->list.outside) {
+ if (y >= rptr->ymin && ye <= rptr->ymax &&
+ x >= rptr->xmin && xe <= rptr->xmax
+ ) {
+ return INCR_THEN(in, (*process) (pccd, x, y, xe, ye));
+ }
+ }
+ /*
+ * Warp the cursor forward or backward to the first rectangle row
+ * that could include a given y value. Assumes rptr is set, and
+ * updates it. Specifically, after this loop, either rptr == 0 (if
+ * the y value is greater than all y values in the list), or y <
+ * rptr->ymax and either rptr->prev == 0 or y >= rptr->prev->ymax.
+ * Note that y <= rptr->ymin is possible.
+ *
+ * In the first case below, the while loop is safe because if there
+ * is more than one rectangle, there is a 'stopper' at the end of
+ * the list.
+ */
+ if (y >= rptr->ymax) {
+ if ((rptr = rptr->next) != 0)
+ while (INCR_THEN(up, y >= rptr->ymax))
+ rptr = rptr->next;
+ } else
+ while (rptr->prev != 0 && y < rptr->prev->ymax)
+ INCR_THEN(down, rptr = rptr->prev);
+ if (rptr == 0 || (yc = rptr->ymin) >= ye) {
+ if (rdev->list.count > 1)
+ rdev->current =
+ (rptr != 0 ? rptr :
+ y >= rdev->current->ymax ? rdev->list.tail :
+ rdev->list.head);
+ if (rdev->list.outside) {
+ return (*process) (pccd, x, y, xe, ye);
+ } else
+ return 0;
+ }
+ rdev->current = rptr;
+ if (yc < y)
+ yc = y;
+ if (rdev->list.outside) {
+ for (yep = y;;) {
+ const int ymax = rptr->ymax;
+
+ xc = x;
+ if (yc > yep) {
+ yec = yc, yc = yep;
+ xec = xe;
+ code = (*process) (pccd, xc, yc, xec, yec);
+ if (code < 0)
+ return code;
+ yc = yec;
+ }
+ yec = min(ymax, ye);
+ do {
+ xec = rptr->xmin;
+ if (xec > xc) {
+ if (xec > xe)
+ xec = xe;
+ code = (*process) (pccd, xc, yc, xec, yec);
+ if (code < 0)
+ return code;
+ xc = rptr->xmax;
+ if (xc >= xe)
+ xc = max_int;
+ } else {
+ xec = rptr->xmax;
+ if (xec > xc)
+ xc = xec;
+ }
+ }
+ while ((rptr = rptr->next) != 0 && rptr->ymax == ymax);
+ if (xc < xe) {
+ xec = xe;
+ code = (*process) (pccd, xc, yc, xec, yec);
+ if (code < 0)
+ return code;
+ }
+ yep = yec;
+ if (rptr == 0 || (yc = rptr->ymin) >= ye)
+ break;
+ }
+ if (yep < ye) {
+ xc = x, xec = xe, yc = yep, yec = ye;
+ code = (*process) (pccd, xc, yc, xec, yec);
+ if (code < 0)
+ return code;
+ }
+ } else /* !outside */
+ for (;;) {
+ const int ymax = rptr->ymax;
+ gx_clip_rect *nptr;
+
+ yec = min(ymax, ye);
+ if_debug2('Q', "[Q]yc=%d yec=%d\n", yc, yec);
+ do {
+ xc = rptr->xmin;
+ xec = rptr->xmax;
+ if (xc < x)
+ xc = x;
+ if (xec > xe)
+ xec = xe;
+ if (xec > xc) {
+ clip_rect_print('Q', "match", rptr);
+ if_debug2('Q', "[Q]xc=%d xec=%d\n", xc, xec);
+ INCR(x);
+/*
+ * Conditionally look ahead to detect unclipped vertical strips. This is
+ * really only valuable for 90 degree rotated images or (nearly-)vertical
+ * lines with convex clipping regions; if we ever change images to use
+ * source buffering and destination-oriented enumeration, we could probably
+ * take out the code here with no adverse effects.
+ */
+#ifdef CHECK_VERTICAL_CLIPPING
+ if (xec - xc == pccd->w) { /* full width */
+ /* Look ahead for a vertical swath. */
+ while ((nptr = rptr->next) != 0 &&
+ nptr->ymin == yec &&
+ nptr->ymax <= ye &&
+ nptr->xmin <= x &&
+ nptr->xmax >= xe
+ )
+ yec = nptr->ymax, rptr = nptr;
+ } else
+ nptr = rptr->next;
+#else
+ nptr = rptr->next;
+#endif
+ code = (*process) (pccd, xc, yc, xec, yec);
+ if (code < 0)
+ return code;
+ } else {
+ INCR_THEN(no_x, nptr = rptr->next);
+ }
+ }
+ while ((rptr = nptr) != 0 && rptr->ymax == ymax);
+ if (rptr == 0 || (yec = rptr->ymin) >= ye)
+ break;
+ yc = yec;
+ }
+ return 0;
+}
+
+/* Open a clipping device */
+private int
+clip_open(register gx_device * dev)
+{
+ gx_device_clip *rdev = (gx_device_clip *) dev;
+ gx_device *tdev = rdev->target;
+
+ /* Initialize the cursor. */
+ rdev->current =
+ (rdev->list.head == 0 ? &rdev->list.single : rdev->list.head);
+ rdev->color_info = tdev->color_info;
+ rdev->width = tdev->width;
+ rdev->height = tdev->height;
+ return 0;
+}
+
+/* Fill a rectangle */
+int
+clip_call_fill_rectangle(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec)
+{
+ return (*dev_proc(pccd->tdev, fill_rectangle))
+ (pccd->tdev, xc, yc, xec - xc, yec - yc, pccd->color[0]);
+}
+private int
+clip_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
+ gx_color_index color)
+{
+ gx_device_clip *rdev = (gx_device_clip *) dev;
+ clip_callback_data_t ccdata;
+
+ x += rdev->translation.x;
+ y += rdev->translation.y;
+ ccdata.tdev = rdev->target;
+ ccdata.color[0] = color;
+ ccdata.x = x, ccdata.y = y, ccdata.w = w, ccdata.h = h;
+ return clip_enumerate(rdev, clip_call_fill_rectangle, &ccdata);
+}
+
+/* Copy a monochrome rectangle */
+int
+clip_call_copy_mono(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec)
+{
+ return (*dev_proc(pccd->tdev, copy_mono))
+ (pccd->tdev, pccd->data + (yc - pccd->y) * pccd->raster,
+ pccd->sourcex + xc - pccd->x, pccd->raster, gx_no_bitmap_id,
+ xc, yc, xec - xc, yec - yc, pccd->color[0], pccd->color[1]);
+}
+private int
+clip_copy_mono(gx_device * dev,
+ const byte * data, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h,
+ gx_color_index color0, gx_color_index color1)
+{
+ gx_device_clip *rdev = (gx_device_clip *) dev;
+ clip_callback_data_t ccdata;
+
+ x += rdev->translation.x;
+ y += rdev->translation.y;
+ ccdata.tdev = rdev->target;
+ ccdata.data = data, ccdata.sourcex = sourcex, ccdata.raster = raster;
+ ccdata.color[0] = color0, ccdata.color[1] = color1;
+ ccdata.x = x, ccdata.y = y, ccdata.w = w, ccdata.h = h;
+ return clip_enumerate(rdev, clip_call_copy_mono, &ccdata);
+}
+
+/* Copy a color rectangle */
+int
+clip_call_copy_color(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec)
+{
+ return (*dev_proc(pccd->tdev, copy_color))
+ (pccd->tdev, pccd->data + (yc - pccd->y) * pccd->raster,
+ pccd->sourcex + xc - pccd->x, pccd->raster, gx_no_bitmap_id,
+ xc, yc, xec - xc, yec - yc);
+}
+private int
+clip_copy_color(gx_device * dev,
+ const byte * data, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{
+ gx_device_clip *rdev = (gx_device_clip *) dev;
+ clip_callback_data_t ccdata;
+
+ x += rdev->translation.x;
+ y += rdev->translation.y;
+ ccdata.tdev = rdev->target;
+ ccdata.data = data, ccdata.sourcex = sourcex, ccdata.raster = raster;
+ ccdata.x = x, ccdata.y = y, ccdata.w = w, ccdata.h = h;
+ return clip_enumerate(rdev, clip_call_copy_color, &ccdata);
+}
+
+/* Copy a rectangle with alpha */
+int
+clip_call_copy_alpha(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec)
+{
+ return (*dev_proc(pccd->tdev, copy_alpha))
+ (pccd->tdev, pccd->data + (yc - pccd->y) * pccd->raster,
+ pccd->sourcex + xc - pccd->x, pccd->raster, gx_no_bitmap_id,
+ xc, yc, xec - xc, yec - yc, pccd->color[0], pccd->depth);
+}
+private int
+clip_copy_alpha(gx_device * dev,
+ const byte * data, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h,
+ gx_color_index color, int depth)
+{
+ gx_device_clip *rdev = (gx_device_clip *) dev;
+ clip_callback_data_t ccdata;
+
+ x += rdev->translation.x;
+ y += rdev->translation.y;
+ ccdata.tdev = rdev->target;
+ ccdata.data = data, ccdata.sourcex = sourcex, ccdata.raster = raster;
+ ccdata.x = x, ccdata.y = y, ccdata.w = w, ccdata.h = h;
+ ccdata.color[0] = color, ccdata.depth = depth;
+ return clip_enumerate(rdev, clip_call_copy_alpha, &ccdata);
+}
+
+/* Fill a region defined by a mask. */
+int
+clip_call_fill_mask(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec)
+{
+ return (*dev_proc(pccd->tdev, fill_mask))
+ (pccd->tdev, pccd->data + (yc - pccd->y) * pccd->raster,
+ pccd->sourcex + xc - pccd->x, pccd->raster, gx_no_bitmap_id,
+ xc, yc, xec - xc, yec - yc, pccd->pdcolor, pccd->depth,
+ pccd->lop, NULL);
+}
+private int
+clip_fill_mask(gx_device * dev,
+ const byte * data, int sourcex, 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_clip *rdev = (gx_device_clip *) dev;
+ clip_callback_data_t ccdata;
+
+ if (pcpath != 0)
+ return gx_default_fill_mask(dev, data, sourcex, raster, id,
+ x, y, w, h, pdcolor, depth, lop,
+ pcpath);
+ x += rdev->translation.x;
+ y += rdev->translation.y;
+ ccdata.tdev = rdev->target;
+ ccdata.x = x, ccdata.y = y, ccdata.w = w, ccdata.h = h;
+ ccdata.data = data, ccdata.sourcex = sourcex, ccdata.raster = raster;
+ ccdata.pdcolor = pdcolor, ccdata.depth = depth, ccdata.lop = lop;
+ return clip_enumerate(rdev, clip_call_fill_mask, &ccdata);
+}
+
+/* Strip-tile a rectangle. */
+int
+clip_call_strip_tile_rectangle(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec)
+{
+ return (*dev_proc(pccd->tdev, strip_tile_rectangle))
+ (pccd->tdev, pccd->tiles, xc, yc, xec - xc, yec - yc,
+ pccd->color[0], pccd->color[1], pccd->phase.x, pccd->phase.y);
+}
+private int
+clip_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 phase_x, int phase_y)
+{
+ gx_device_clip *rdev = (gx_device_clip *) dev;
+ clip_callback_data_t ccdata;
+
+ x += rdev->translation.x;
+ y += rdev->translation.y;
+ ccdata.tdev = rdev->target;
+ ccdata.x = x, ccdata.y = y, ccdata.w = w, ccdata.h = h;
+ ccdata.tiles = tiles;
+ ccdata.color[0] = color0, ccdata.color[1] = color1;
+ ccdata.phase.x = phase_x, ccdata.phase.y = phase_y;
+ return clip_enumerate(rdev, clip_call_strip_tile_rectangle, &ccdata);
+}
+
+/* Copy a rectangle with RasterOp and strip texture. */
+int
+clip_call_strip_copy_rop(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec)
+{
+ return (*dev_proc(pccd->tdev, strip_copy_rop))
+ (pccd->tdev, pccd->data + (yc - pccd->y) * pccd->raster,
+ pccd->sourcex + xc - pccd->x, pccd->raster, gx_no_bitmap_id,
+ pccd->scolors, pccd->textures, pccd->tcolors,
+ xc, yc, xec - xc, yec - yc, pccd->phase.x, pccd->phase.y,
+ pccd->lop);
+}
+private int
+clip_strip_copy_rop(gx_device * dev,
+ const byte * sdata, int sourcex, uint raster, 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_clip *rdev = (gx_device_clip *) dev;
+ clip_callback_data_t ccdata;
+
+ x += rdev->translation.x;
+ y += rdev->translation.y;
+ ccdata.tdev = rdev->target;
+ ccdata.x = x, ccdata.y = y, ccdata.w = w, ccdata.h = h;
+ ccdata.data = sdata, ccdata.sourcex = sourcex, ccdata.raster = raster;
+ ccdata.scolors = scolors, ccdata.textures = textures,
+ ccdata.tcolors = tcolors;
+ ccdata.phase.x = phase_x, ccdata.phase.y = phase_y, ccdata.lop = lop;
+ return clip_enumerate(rdev, clip_call_strip_copy_rop, &ccdata);
+}
+
+/* Get the (outer) clipping box, in client coordinates. */
+private void
+clip_get_clipping_box(gx_device * dev, gs_fixed_rect * pbox)
+{
+ gx_device_clip *rdev = (gx_device_clip *) dev;
+ gx_device *tdev = rdev->target;
+ gs_fixed_rect tbox, cbox;
+ fixed tx = int2fixed(rdev->translation.x), ty = int2fixed(rdev->translation.y);
+
+ (*dev_proc(tdev, get_clipping_box)) (tdev, &tbox);
+ /*
+ * To get an accurate clipping box quickly in all cases, we should
+ * save the outer box from the clipping path. However,
+ * this is not currently (or even always guaranteed to be)
+ * available. Instead, we compromise: if there is more than one
+ * rectangle in the list, we return accurate Y values (which are
+ * easy to obtain, because the list is Y-sorted) but copy the
+ * X values from the target.
+ */
+ if (rdev->list.outside || rdev->list.count == 0) {
+ cbox = tbox;
+ } else if (rdev->list.count == 1) {
+ cbox.p.x = int2fixed(rdev->list.single.xmin);
+ cbox.p.y = int2fixed(rdev->list.single.ymin);
+ cbox.q.x = int2fixed(rdev->list.single.xmax);
+ cbox.q.y = int2fixed(rdev->list.single.ymax);
+ } else { /* The head and tail elements are dummies.... */
+ cbox.p.x = tbox.p.x;
+ cbox.p.y = int2fixed(rdev->list.head->next->ymin);
+ cbox.q.x = tbox.q.x;
+ cbox.q.y = int2fixed(rdev->list.tail->prev->ymax);
+ }
+ rect_intersect(tbox, cbox);
+ if (tbox.p.x != min_fixed)
+ tbox.p.x -= tx;
+ if (tbox.p.y != min_fixed)
+ tbox.p.y -= ty;
+ if (tbox.q.x != max_fixed)
+ tbox.q.x -= tx;
+ if (tbox.q.y != max_fixed)
+ tbox.q.y -= ty;
+ *pbox = tbox;
+}
+
+/* Get bits back from the device. */
+private int
+clip_get_bits_rectangle(gx_device * dev, const gs_int_rect * prect,
+ gs_get_bits_params_t * params, gs_int_rect ** unread)
+{
+ gx_device_clip *rdev = (gx_device_clip *) dev;
+ gx_device *tdev = rdev->target;
+ int tx = rdev->translation.x, ty = rdev->translation.y;
+ gs_int_rect rect;
+ int code;
+
+ rect.p.x = prect->p.x - tx, rect.p.y = prect->p.y - ty;
+ rect.q.x = prect->q.x - tx, rect.q.y = prect->q.y - ty;
+ code = (*dev_proc(tdev, get_bits_rectangle))
+ (tdev, &rect, params, unread);
+ if (code > 0) {
+ /* Adjust unread rectangle coordinates */
+ gs_int_rect *list = *unread;
+ int i;
+
+ for (i = 0; i < code; ++list, ++i) {
+ list->p.x += tx, list->p.y += ty;
+ list->q.x += tx, list->q.y += ty;
+ }
+ }
+ return code;
+}
diff --git a/pstoraster/gxclip.h b/pstoraster/gxclip.h
new file mode 100644
index 000000000..ef13576e1
--- /dev/null
+++ b/pstoraster/gxclip.h
@@ -0,0 +1,75 @@
+/* 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$ */
+/* Internal definitions for clipping */
+
+#ifndef gxclip_INCLUDED
+# define gxclip_INCLUDED
+
+/*
+ * Both rectangle list and mask clipping use callback procedures to process
+ * each rectangle selected by the clipping region. They share both the
+ * callback procedures themselves and the structure that provides closure
+ * data for these procedures. We define a single closure structure, rather
+ * than one per client/callback, just to reduce source code clutter. The
+ * comments below show which clients use each member.
+ */
+typedef struct clip_callback_data_s {
+ /*
+ * The original driver procedure stores the following of its arguments
+ * that the callback procedure or the clipping algorithm needs.
+ */
+ gx_device *tdev; /* target device (always set) */
+ int x, y, w, h; /* (always set) */
+ gx_color_index color[2]; /* (all but copy_color) */
+ const byte *data; /* copy_*, fill_mask */
+ int sourcex; /* ibid. */
+ uint raster; /* ibid. */
+ int depth; /* copy_alpha, fill_mask */
+ const gx_drawing_color *pdcolor; /* fill_mask */
+ gs_logical_operation_t lop; /* fill_mask, strip_copy_rop */
+ const gx_clip_path *pcpath; /* fill_mask */
+ const gx_strip_bitmap *tiles; /* strip_tile_rectangle */
+ gs_int_point phase; /* strip_* */
+ const gx_color_index *scolors; /* strip_copy_rop */
+ const gx_strip_bitmap *textures; /* ibid. */
+ const gx_color_index *tcolors; /* ibid. */
+} clip_callback_data_t;
+
+/* Declare the callback procedures. */
+int
+ clip_call_fill_rectangle(P5(clip_callback_data_t * pccd,
+ int xc, int yc, int xec, int yec)), clip_call_copy_mono(P5(clip_callback_data_t * pccd,
+ int xc, int yc, int xec, int yec)),
+ clip_call_copy_color(P5(clip_callback_data_t * pccd,
+ int xc, int yc, int xec, int yec)), clip_call_copy_alpha(P5(clip_callback_data_t * pccd,
+ int xc, int yc, int xec, int yec)),
+ clip_call_fill_mask(P5(clip_callback_data_t * pccd,
+ int xc, int yc, int xec, int yec)), clip_call_strip_tile_rectangle(P5(clip_callback_data_t * pccd,
+ int xc, int yc, int xec, int yec)),
+ clip_call_strip_copy_rop(P5(clip_callback_data_t * pccd,
+ int xc, int yc, int xec, int yec));
+
+#endif /* gxclip_INCLUDED */
diff --git a/pstoraster/gxclip2.c b/pstoraster/gxclip2.c
new file mode 100644
index 000000000..22ef30e06
--- /dev/null
+++ b/pstoraster/gxclip2.c
@@ -0,0 +1,306 @@
+/* Copyright (C) 1993, 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$ */
+/* Mask clipping for patterns */
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gxdevice.h"
+#include "gxdevmem.h"
+#include "gxclip2.h"
+
+private_st_device_tile_clip();
+
+/* Device procedures */
+private dev_proc_fill_rectangle(tile_clip_fill_rectangle);
+private dev_proc_copy_mono(tile_clip_copy_mono);
+private dev_proc_copy_color(tile_clip_copy_color);
+private dev_proc_copy_alpha(tile_clip_copy_alpha);
+private dev_proc_strip_copy_rop(tile_clip_strip_copy_rop);
+
+/* The device descriptor. */
+private const gx_device_tile_clip gs_tile_clip_device =
+{std_device_std_body_open(gx_device_tile_clip, 0, "tile clipper",
+ 0, 0, 1, 1),
+ {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,
+ tile_clip_fill_rectangle,
+ gx_default_tile_rectangle,
+ tile_clip_copy_mono,
+ tile_clip_copy_color,
+ gx_default_draw_line,
+ gx_forward_get_bits,
+ gx_forward_get_params,
+ gx_forward_put_params,
+ gx_forward_map_cmyk_color,
+ gx_forward_get_xfont_procs,
+ gx_forward_get_xfont_device,
+ gx_forward_map_rgb_alpha_color,
+ gx_forward_get_page_device,
+ gx_forward_get_alpha_bits,
+ tile_clip_copy_alpha,
+ gx_forward_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,
+ gx_default_strip_tile_rectangle,
+ tile_clip_strip_copy_rop,
+ gx_forward_get_clipping_box,
+ gx_default_begin_typed_image,
+ gx_forward_get_bits_rectangle,
+ gx_forward_map_color_rgb_alpha,
+ gx_no_create_compositor,
+ gx_forward_get_hardware_params,
+ gx_default_text_begin
+ }
+};
+
+/* Initialize a tile clipping device from a mask. */
+int
+tile_clip_initialize(gx_device_tile_clip * cdev, const gx_strip_bitmap * tiles,
+ gx_device * tdev, int px, int py)
+{
+ int code =
+ gx_mask_clip_initialize(cdev, &gs_tile_clip_device,
+ (const gx_bitmap *)tiles,
+ tdev, 0, 0); /* phase will be reset */
+
+ if (code >= 0) {
+ cdev->tiles = *tiles;
+ tile_clip_set_phase(cdev, px, py);
+ }
+ return code;
+}
+
+/* Set the phase of the tile. */
+void
+tile_clip_set_phase(gx_device_tile_clip * cdev, int px, int py)
+{
+ cdev->phase.x = px;
+ cdev->phase.y = py;
+}
+
+/* Fill a rectangle by tiling with the mask. */
+private int
+tile_clip_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
+ gx_color_index color)
+{
+ gx_device_tile_clip *cdev = (gx_device_tile_clip *) dev;
+ gx_device *tdev = cdev->target;
+
+ return (*dev_proc(tdev, strip_tile_rectangle)) (tdev, &cdev->tiles,
+ x, y, w, h,
+ gx_no_color_index, color, cdev->phase.x, cdev->phase.y);
+}
+
+/* Calculate the X offset corresponding to a given Y, taking the phase */
+/* and shift into account. */
+#define x_offset(ty, cdev)\
+ ((cdev)->phase.x + (((ty) + (cdev)->phase.y) / (cdev)->tiles.rep_height) *\
+ (cdev)->tiles.rep_shift)
+
+/* Copy a monochrome bitmap. We divide it up into maximal chunks */
+/* that line up with a single tile, and then do the obvious Boolean */
+/* combination of the tile mask and the source. */
+private int
+tile_clip_copy_mono(gx_device * dev,
+ const byte * data, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h,
+ gx_color_index color0, gx_color_index color1)
+{
+ gx_device_tile_clip *cdev = (gx_device_tile_clip *) dev;
+ gx_color_index color, mcolor0, mcolor1;
+ int ty, ny;
+ int code;
+
+ setup_mask_copy_mono(cdev, color, mcolor0, mcolor1);
+ for (ty = y; ty < y + h; ty += ny) {
+ int tx, nx;
+ int cy = (ty + cdev->phase.y) % cdev->tiles.rep_height;
+ int xoff = x_offset(ty, cdev);
+
+ ny = min(y + h - ty, cdev->tiles.size.y - cy);
+ if (ny > cdev->mdev.height)
+ ny = cdev->mdev.height;
+ for (tx = x; tx < x + w; tx += nx) {
+ int cx = (tx + xoff) % cdev->tiles.rep_width;
+
+ nx = min(x + w - tx, cdev->tiles.size.x - cx);
+ /* Copy a tile slice to the memory device buffer. */
+ memcpy(cdev->buffer.bytes,
+ cdev->tiles.data + cy * cdev->tiles.raster,
+ cdev->tiles.raster * ny);
+ /* Intersect the tile with the source data. */
+ /* mcolor0 and mcolor1 invert the data if needed. */
+ /* This call can't fail. */
+ (*dev_proc(&cdev->mdev, copy_mono)) ((gx_device *) & cdev->mdev,
+ data + (ty - y) * raster, sourcex + tx - x,
+ raster, gx_no_bitmap_id,
+ cx, 0, nx, ny, mcolor0, mcolor1);
+ /* Now copy the color through the double mask. */
+ code = (*dev_proc(cdev->target, copy_mono)) (cdev->target,
+ cdev->buffer.bytes, cx, cdev->tiles.raster,
+ gx_no_bitmap_id,
+ tx, ty, nx, ny, gx_no_color_index, color);
+ if (code < 0)
+ return code;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Define the skeleton for the other copying operations. We can't use the
+ * BitBlt tricks: we have to scan for runs of 1s. There are many obvious
+ * ways to speed this up; we'll implement some if we need to. The schema
+ * is:
+ * FOR_RUNS(data_row, tx1, tx, ty) {
+ * ... process the run ([tx1,tx),ty) ...
+ * } END_FOR_RUNS();
+ * Free variables: cdev, data, sourcex, raster, x, y, w, h.
+ */
+#define t_next(tx)\
+ BEGIN {\
+ if ( ++cx == cdev->tiles.size.x )\
+ cx = 0, tp = tile_row, tbit = 0x80;\
+ else if ( (tbit >>= 1) == 0 )\
+ tp++, tbit = 0x80;\
+ tx++;\
+ } END
+#define FOR_RUNS(data_row, tx1, tx, ty)\
+ const byte *data_row = data;\
+ int cy = (y + cdev->phase.y) % cdev->tiles.rep_height;\
+ const byte *tile_row = cdev->tiles.data + cy * cdev->tiles.raster;\
+ int ty;\
+\
+ for ( ty = y; ty < y + h; ty++, data_row += raster ) {\
+ int cx = (x + x_offset(ty, cdev)) % cdev->tiles.rep_width;\
+ const byte *tp = tile_row + (cx >> 3);\
+ byte tbit = 0x80 >> (cx & 7);\
+ int tx;\
+\
+ for ( tx = x; tx < x + w; ) {\
+ int tx1;\
+\
+ /* Skip a run of 0s. */\
+ while ( tx < x + w && (*tp & tbit) == 0 )\
+ t_next(tx);\
+ if ( tx == x + w )\
+ break;\
+ /* Scan a run of 1s. */\
+ tx1 = tx;\
+ do {\
+ t_next(tx);\
+ } while ( tx < x + w && (*tp & tbit) != 0 );\
+ if_debug3('T', "[T]run x=(%d,%d), y=%d\n", tx1, tx, ty);
+/* (body goes here) */
+#define END_FOR_RUNS()\
+ }\
+ if ( ++cy == cdev->tiles.size.y )\
+ cy = 0, tile_row = cdev->tiles.data;\
+ else\
+ tile_row += cdev->tiles.raster;\
+ }
+
+/* Copy a color rectangle. */
+private int
+tile_clip_copy_color(gx_device * dev,
+ const byte * data, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{
+ gx_device_tile_clip *cdev = (gx_device_tile_clip *) dev;
+
+ FOR_RUNS(data_row, txrun, tx, ty) {
+ /* Copy the run. */
+ int code = (*dev_proc(cdev->target, copy_color))
+ (cdev->target, data_row, sourcex + txrun - x, raster,
+ gx_no_bitmap_id, txrun, ty, tx - txrun, 1);
+
+ if (code < 0)
+ return code;
+ }
+ END_FOR_RUNS();
+ return 0;
+}
+
+/* Copy an alpha rectangle similarly. */
+private int
+tile_clip_copy_alpha(gx_device * dev,
+ const byte * data, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h, gx_color_index color, int depth)
+{
+ gx_device_tile_clip *cdev = (gx_device_tile_clip *) dev;
+
+ FOR_RUNS(data_row, txrun, tx, ty) {
+ /* Copy the run. */
+ int code = (*dev_proc(cdev->target, copy_alpha))
+ (cdev->target, data_row, sourcex + txrun - x, raster,
+ gx_no_bitmap_id, txrun, ty, tx - txrun, 1, color, depth);
+
+ if (code < 0)
+ return code;
+ }
+ END_FOR_RUNS();
+ return 0;
+}
+
+/* Copy a RasterOp rectangle similarly. */
+private int
+tile_clip_strip_copy_rop(gx_device * dev,
+ const byte * data, int sourcex, uint raster, 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_tile_clip *cdev = (gx_device_tile_clip *) dev;
+
+ FOR_RUNS(data_row, txrun, tx, ty) {
+ /* Copy the run. */
+ int code = (*dev_proc(cdev->target, strip_copy_rop))
+ (cdev->target, data_row, sourcex + txrun - x, raster,
+ gx_no_bitmap_id, scolors, textures, tcolors,
+ txrun, ty, tx - txrun, 1, phase_x, phase_y, lop);
+
+ if (code < 0)
+ return code;
+ }
+ END_FOR_RUNS();
+ return 0;
+}
diff --git a/pstoraster/gxclip2.h b/pstoraster/gxclip2.h
new file mode 100644
index 000000000..c89def430
--- /dev/null
+++ b/pstoraster/gxclip2.h
@@ -0,0 +1,55 @@
+/* Copyright (C) 1993, 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$ */
+/* Tiled mask clipping device and interface */
+
+#ifndef gxclip2_INCLUDED
+# define gxclip2_INCLUDED
+
+#include "gxmclip.h"
+
+/* The structure for tile clipping is the same as for simple mask clipping. */
+typedef gx_device_mask_clip gx_device_tile_clip;
+
+#define private_st_device_tile_clip() /* in gxclip2.c */\
+ gs_private_st_suffix_add0(st_device_tile_clip, gx_device_tile_clip,\
+ "gx_device_tile_clip", device_tile_clip_enum_ptrs,\
+ device_tile_clip_reloc_ptrs, st_device_mask_clip)
+
+/*
+ * Initialize a tile clipping device from a mask.
+ * We supply an explicit phase.
+ */
+int tile_clip_initialize(P5(gx_device_tile_clip * cdev,
+ const gx_strip_bitmap * tiles,
+ gx_device * tdev, int px, int py));
+
+/*
+ * Set the phase of the tile -- used in the tiling loop when
+ * the tile doesn't simply fill the plane.
+ */
+void tile_clip_set_phase(P3(gx_device_tile_clip * cdev, int px, int py));
+
+#endif /* gxclip2_INCLUDED */
diff --git a/pstoraster/gxclipm.c b/pstoraster/gxclipm.c
new file mode 100644
index 000000000..73e1802ed
--- /dev/null
+++ b/pstoraster/gxclipm.c
@@ -0,0 +1,309 @@
+/* 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$ */
+/* Mask clipping device */
+#include "memory_.h"
+#include "gx.h"
+#include "gxdevice.h"
+#include "gxdevmem.h"
+#include "gxclipm.h"
+
+/* Device procedures */
+private dev_proc_fill_rectangle(mask_clip_fill_rectangle);
+private dev_proc_copy_mono(mask_clip_copy_mono);
+private dev_proc_copy_color(mask_clip_copy_color);
+private dev_proc_copy_alpha(mask_clip_copy_alpha);
+private dev_proc_strip_copy_rop(mask_clip_strip_copy_rop);
+private dev_proc_get_clipping_box(mask_clip_get_clipping_box);
+
+/* The device descriptor. */
+const gx_device_mask_clip gs_mask_clip_device =
+{std_device_std_body_open(gx_device_mask_clip, 0, "mask clipper",
+ 0, 0, 1, 1),
+ {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,
+ mask_clip_fill_rectangle,
+ gx_default_tile_rectangle,
+ mask_clip_copy_mono,
+ mask_clip_copy_color,
+ gx_default_draw_line,
+ gx_forward_get_bits,
+ gx_forward_get_params,
+ gx_forward_put_params,
+ gx_forward_map_cmyk_color,
+ gx_forward_get_xfont_procs,
+ gx_forward_get_xfont_device,
+ gx_forward_map_rgb_alpha_color,
+ gx_forward_get_page_device,
+ gx_forward_get_alpha_bits,
+ mask_clip_copy_alpha,
+ gx_forward_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,
+ gx_default_strip_tile_rectangle,
+ mask_clip_strip_copy_rop,
+ mask_clip_get_clipping_box,
+ gx_default_begin_typed_image,
+ gx_forward_get_bits_rectangle,
+ gx_forward_map_color_rgb_alpha,
+ gx_no_create_compositor,
+ gx_forward_get_hardware_params,
+ gx_default_text_begin
+ }
+};
+
+/* Fill a rectangle by painting through the mask. */
+private int
+mask_clip_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
+ gx_color_index color)
+{
+ gx_device_mask_clip *cdev = (gx_device_mask_clip *) dev;
+ gx_device *tdev = cdev->target;
+
+ /* Clip the rectangle to the region covered by the mask. */
+ int mx0 = x + cdev->phase.x, my0 = y + cdev->phase.y;
+ int mx1 = mx0 + w, my1 = my0 + h;
+
+ if (mx0 < 0)
+ mx0 = 0;
+ if (my0 < 0)
+ my0 = 0;
+ if (mx1 > cdev->tiles.size.x)
+ mx1 = cdev->tiles.size.x;
+ if (my1 > cdev->tiles.size.y)
+ my1 = cdev->tiles.size.y;
+ return (*dev_proc(tdev, copy_mono))
+ (tdev, cdev->tiles.data + my0 * cdev->tiles.raster, mx0,
+ cdev->tiles.raster, cdev->tiles.id,
+ mx0 - cdev->phase.x, my0 - cdev->phase.y,
+ mx1 - mx0, my1 - my0, gx_no_color_index, color);
+}
+
+/*
+ * Clip the rectangle for a copy operation.
+ * Sets m{x,y}{0,1} to the region in the mask coordinate system;
+ * subtract cdev->phase.{x,y} to get target coordinates.
+ * Sets sdata, sx to adjusted values of data, sourcex.
+ * References cdev, data, sourcex, raster, x, y, w, h.
+ */
+#define DECLARE_MASK_COPY\
+ const byte *sdata;\
+ int sx, mx0, my0, mx1, my1
+#define FIT_MASK_COPY(data, sourcex, raster, vx, vy, vw, vh)\
+ BEGIN\
+ sdata = data, sx = sourcex;\
+ mx0 = vx + cdev->phase.x, my0 = vy + cdev->phase.y;\
+ mx1 = mx0 + vw, my1 = my0 + vh;\
+ if ( mx0 < 0 )\
+ sx -= mx0, mx0 = 0;\
+ if ( my0 < 0 )\
+ sdata -= my0 * raster, my0 = 0;\
+ if ( mx1 > cdev->tiles.size.x )\
+ mx1 = cdev->tiles.size.x;\
+ if ( my1 > cdev->tiles.size.y )\
+ my1 = cdev->tiles.size.y;\
+ END
+
+/* Copy a monochrome bitmap by playing Boolean games. */
+private int
+mask_clip_copy_mono(gx_device * dev,
+ const byte * data, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h,
+ gx_color_index color0, gx_color_index color1)
+{
+ gx_device_mask_clip *cdev = (gx_device_mask_clip *) dev;
+ gx_device *tdev = cdev->target;
+ gx_color_index color, mcolor0, mcolor1;
+
+ DECLARE_MASK_COPY;
+ int cy, ny;
+ int code;
+
+ setup_mask_copy_mono(cdev, color, mcolor0, mcolor1);
+ FIT_MASK_COPY(data, sourcex, raster, x, y, w, h);
+ for (cy = my0; cy < my1; cy += ny) {
+ int ty = cy - cdev->phase.y;
+ int cx, nx;
+
+ ny = my1 - cy;
+ if (ny > cdev->mdev.height)
+ ny = cdev->mdev.height;
+ for (cx = mx0; cx < mx1; cx += nx) {
+ int tx = cx - cdev->phase.x;
+
+ nx = mx1 - cx; /* also should be min */
+ /* Copy a tile slice to the memory device buffer. */
+ memcpy(cdev->buffer.bytes,
+ cdev->tiles.data + cy * cdev->tiles.raster,
+ cdev->tiles.raster * ny);
+ /* Intersect the tile with the source data. */
+ /* mcolor0 and mcolor1 invert the data if needed. */
+ /* This call can't fail. */
+ (*dev_proc(&cdev->mdev, copy_mono)) ((gx_device *) & cdev->mdev,
+ sdata + (ty - y) * raster, sx + tx - x,
+ raster, gx_no_bitmap_id,
+ cx, 0, nx, ny, mcolor0, mcolor1);
+ /* Now copy the color through the double mask. */
+ code = (*dev_proc(tdev, copy_mono)) (cdev->target,
+ cdev->buffer.bytes, cx, cdev->tiles.raster,
+ gx_no_bitmap_id,
+ tx, ty, nx, ny, gx_no_color_index, color);
+ if (code < 0)
+ return code;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Define the run enumerator for the other copying operations. We can't use
+ * the BitBlt tricks: we have to scan for runs of 1s. There are obvious
+ * ways to speed this up; we'll implement some if we need to.
+ */
+private int
+clip_runs_enumerate(gx_device_mask_clip * cdev,
+ int (*process) (P5(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec)),
+ clip_callback_data_t * pccd)
+{
+ DECLARE_MASK_COPY;
+ int cy;
+ const byte *tile_row;
+
+ FIT_MASK_COPY(pccd->data, pccd->sourcex, pccd->raster,
+ pccd->x, pccd->y, pccd->w, pccd->h);
+ tile_row = cdev->tiles.data + my0 * cdev->tiles.raster + (mx0 >> 3);
+ for (cy = my0; cy < my1; cy++) {
+ int cx = mx0;
+ const byte *tp = tile_row;
+ byte tbit = 0x80 >> (cx & 7);
+
+ while (cx < mx1) {
+ int tx1, tx, ty;
+ int code;
+
+ /* Skip a run of 0s. */
+ while (cx < mx1 && (*tp & tbit) == 0) {
+ if ((tbit >>= 1) == 0)
+ tp++, tbit = 0x80;
+ ++cx;
+ }
+ if (cx == mx1)
+ break;
+ /* Scan a run of 1s. */
+ tx1 = cx - cdev->phase.x;
+ do {
+ if ((tbit >>= 1) == 0)
+ tp++, tbit = 0x80;
+ ++cx;
+ } while (cx < mx1 && (*tp & tbit) != 0);
+ tx = cx - cdev->phase.x;
+ ty = cy - cdev->phase.y;
+ code = (*process) (pccd, tx1, ty, tx, ty + 1);
+ if (code < 0)
+ return code;
+ }
+ tile_row += cdev->tiles.raster;
+ }
+ return 0;
+}
+
+/* Copy a color rectangle */
+private int
+mask_clip_copy_color(gx_device * dev,
+ const byte * data, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h)
+{
+ gx_device_mask_clip *cdev = (gx_device_mask_clip *) dev;
+ clip_callback_data_t ccdata;
+
+ ccdata.tdev = cdev->target;
+ ccdata.data = data, ccdata.sourcex = sourcex, ccdata.raster = raster;
+ ccdata.x = x, ccdata.y = y, ccdata.w = w, ccdata.h = h;
+ return clip_runs_enumerate(cdev, clip_call_copy_color, &ccdata);
+}
+
+/* Copy a rectangle with alpha */
+private int
+mask_clip_copy_alpha(gx_device * dev,
+ const byte * data, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h, gx_color_index color, int depth)
+{
+ gx_device_mask_clip *cdev = (gx_device_mask_clip *) dev;
+ clip_callback_data_t ccdata;
+
+ ccdata.tdev = cdev->target;
+ ccdata.data = data, ccdata.sourcex = sourcex, ccdata.raster = raster;
+ ccdata.x = x, ccdata.y = y, ccdata.w = w, ccdata.h = h;
+ ccdata.color[0] = color, ccdata.depth = depth;
+ return clip_runs_enumerate(cdev, clip_call_copy_alpha, &ccdata);
+}
+
+private int
+mask_clip_strip_copy_rop(gx_device * dev,
+ const byte * data, int sourcex, uint raster, 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_mask_clip *cdev = (gx_device_mask_clip *) dev;
+ clip_callback_data_t ccdata;
+
+ ccdata.tdev = cdev->target;
+ ccdata.x = x, ccdata.y = y, ccdata.w = w, ccdata.h = h;
+ ccdata.data = data, ccdata.sourcex = sourcex, ccdata.raster = raster;
+ ccdata.scolors = scolors, ccdata.textures = textures,
+ ccdata.tcolors = tcolors;
+ ccdata.phase.x = phase_x, ccdata.phase.y = phase_y, ccdata.lop = lop;
+ return clip_runs_enumerate(cdev, clip_call_strip_copy_rop, &ccdata);
+}
+
+private void
+mask_clip_get_clipping_box(gx_device * dev, gs_fixed_rect * pbox)
+{
+ gx_device_mask_clip *cdev = (gx_device_mask_clip *) dev;
+ gx_device *tdev = cdev->target;
+ gs_fixed_rect tbox;
+
+ (*dev_proc(tdev, get_clipping_box)) (tdev, &tbox);
+ pbox->p.x = tbox.p.x - cdev->phase.x;
+ pbox->p.y = tbox.p.y - cdev->phase.y;
+ pbox->q.x = tbox.q.x - cdev->phase.x;
+ pbox->q.y = tbox.q.y - cdev->phase.y;
+}
diff --git a/pstoraster/gxclipm.h b/pstoraster/gxclipm.h
new file mode 100644
index 000000000..84755640d
--- /dev/null
+++ b/pstoraster/gxclipm.h
@@ -0,0 +1,35 @@
+/* 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$ */
+/* Requires gsstruct.h, gxdevice.h, gxdevmem.h */
+
+#ifndef gxclipm_INCLUDED
+# define gxclipm_INCLUDED
+
+#include "gxmclip.h"
+
+extern const gx_device_mask_clip gs_mask_clip_device;
+
+#endif /* gxclipm_INCLUDED */
diff --git a/pstoraster/gxclist.c b/pstoraster/gxclist.c
new file mode 100644
index 000000000..e9aa30e94
--- /dev/null
+++ b/pstoraster/gxclist.c
@@ -0,0 +1,734 @@
+/*
+ Copyright 1993-2002 by Easy Software Products.
+ Copyright 1991, 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$ */
+/* Command list document- and page-level code. */
+#include "memory_.h"
+#include "string_.h"
+#include "gx.h"
+#include "gp.h"
+#include "gpcheck.h"
+#include "gserrors.h"
+#include "gxdevice.h"
+#include "gxdevmem.h" /* must precede gxcldev.h */
+#include "gxcldev.h"
+#include "gxclpath.h"
+#include "gsparams.h"
+
+/* Forward declarations of driver procedures */
+private dev_proc_open_device(clist_open);
+private dev_proc_output_page(clist_output_page);
+private dev_proc_close_device(clist_close);
+private dev_proc_get_band(clist_get_band);
+
+/* In gxclrect.c */
+extern dev_proc_fill_rectangle(clist_fill_rectangle);
+extern dev_proc_copy_mono(clist_copy_mono);
+extern dev_proc_copy_color(clist_copy_color);
+extern dev_proc_copy_alpha(clist_copy_alpha);
+extern dev_proc_strip_tile_rectangle(clist_strip_tile_rectangle);
+extern dev_proc_strip_copy_rop(clist_strip_copy_rop);
+
+/* In gxclpath.c */
+extern dev_proc_fill_path(clist_fill_path);
+extern dev_proc_stroke_path(clist_stroke_path);
+
+/* In gxclimag.c */
+extern dev_proc_fill_mask(clist_fill_mask);
+extern dev_proc_begin_image(clist_begin_image);
+extern dev_proc_begin_typed_image(clist_begin_typed_image);
+extern dev_proc_create_compositor(clist_create_compositor);
+
+/* In gxclread.c */
+extern dev_proc_get_bits_rectangle(clist_get_bits_rectangle);
+
+/* Other forward declarations */
+private int clist_put_current_params(P1(gx_device_clist_writer *cldev));
+
+/* The device procedures */
+const gx_device_procs gs_clist_device_procs = {
+ clist_open,
+ gx_forward_get_initial_matrix,
+ gx_default_sync_output,
+ clist_output_page,
+ clist_close,
+ gx_forward_map_rgb_color,
+ gx_forward_map_color_rgb,
+ clist_fill_rectangle,
+ gx_default_tile_rectangle,
+ clist_copy_mono,
+ clist_copy_color,
+ gx_default_draw_line,
+ gx_default_get_bits,
+ gx_forward_get_params,
+ gx_forward_put_params,
+ gx_forward_map_cmyk_color,
+ gx_forward_get_xfont_procs,
+ gx_forward_get_xfont_device,
+ gx_forward_map_rgb_alpha_color,
+ gx_forward_get_page_device,
+ gx_forward_get_alpha_bits,
+ clist_copy_alpha,
+ clist_get_band,
+ gx_default_copy_rop,
+ clist_fill_path,
+ clist_stroke_path,
+ clist_fill_mask,
+ gx_default_fill_trapezoid,
+ gx_default_fill_parallelogram,
+ gx_default_fill_triangle,
+ gx_default_draw_thin_line,
+ clist_begin_image,
+ gx_default_image_data,
+ gx_default_end_image,
+ clist_strip_tile_rectangle,
+ clist_strip_copy_rop,
+ gx_forward_get_clipping_box,
+ clist_begin_typed_image,
+ clist_get_bits_rectangle,
+ gx_forward_map_color_rgb_alpha,
+ clist_create_compositor,
+ gx_forward_get_hardware_params,
+ gx_default_text_begin
+};
+
+/* ------ Define the command set and syntax ------ */
+
+/* Initialization for imager state. */
+/* The initial scale is arbitrary. */
+const gs_imager_state clist_imager_state_initial =
+{gs_imager_state_initial(300.0 / 72.0)};
+
+/*
+ * The buffer area (data, data_size) holds a bitmap cache when both writing
+ * and reading. The rest of the space is used for the command buffer and
+ * band state bookkeeping when writing, and for the rendering buffer (image
+ * device) when reading. For the moment, we divide the space up
+ * arbitrarily, except that we allocate less space for the bitmap cache if
+ * the device doesn't need halftoning.
+ *
+ * All the routines for allocating tables in the buffer are idempotent, so
+ * they can be used to check whether a given-size buffer is large enough.
+ */
+
+/*
+ * Calculate the desired size for the tile cache.
+ */
+private uint
+clist_tile_cache_size(const gx_device * target, uint data_size)
+{
+ uint bits_size =
+ (data_size / 5) & -align_cached_bits_mod; /* arbitrary */
+
+ if (!gx_device_must_halftone(target)) { /* No halftones -- cache holds only Patterns & characters. */
+ bits_size -= bits_size >> 2;
+ }
+#define min_bits_size 1024
+ if (bits_size < min_bits_size)
+ bits_size = min_bits_size;
+#undef min_bits_size
+ return bits_size;
+}
+
+/*
+ * Initialize the allocation for the tile cache. Sets: tile_hash_mask,
+ * tile_max_count, tile_table, chunk (structure), bits (structure).
+ */
+private int
+clist_init_tile_cache(gx_device * dev, byte * init_data, ulong data_size)
+{
+ gx_device_clist_writer * const cdev =
+ &((gx_device_clist *)dev)->writer;
+ byte *data = init_data;
+ uint bits_size = data_size;
+ /*
+ * Partition the bits area between the hash table and the actual
+ * bitmaps. The per-bitmap overhead is about 24 bytes; if the
+ * average character size is 10 points, its bitmap takes about 24 +
+ * 0.5 * 10/72 * xdpi * 10/72 * ydpi / 8 bytes (the 0.5 being a
+ * fudge factor to account for characters being narrower than they
+ * are tall), which gives us a guideline for the size of the hash
+ * table.
+ */
+ uint avg_char_size =
+ (uint) (dev->x_pixels_per_inch * dev->y_pixels_per_inch *
+ (0.5 * 10 / 72 * 10 / 72 / 8)) + 24;
+ uint hc = bits_size / avg_char_size;
+ uint hsize;
+
+ while ((hc + 1) & hc)
+ hc |= hc >> 1; /* make mask (power of 2 - 1) */
+ if (hc < 0xff)
+ hc = 0xff; /* make allowance for halftone tiles */
+ else if (hc > 0xfff)
+ hc = 0xfff; /* cmd_op_set_tile_index has 12-bit operand */
+ /* Make sure the tables will fit. */
+ while (hc >= 3 && (hsize = (hc + 1) * sizeof(tile_hash)) >= bits_size)
+ hc >>= 1;
+ if (hc < 3)
+ return_error(gs_error_rangecheck);
+ cdev->tile_hash_mask = hc;
+ cdev->tile_max_count = hc - (hc >> 2);
+ cdev->tile_table = (tile_hash *) data;
+ data += hsize;
+ bits_size -= hsize;
+ gx_bits_cache_chunk_init(&cdev->chunk, data, bits_size);
+ gx_bits_cache_init(&cdev->bits, &cdev->chunk);
+ return 0;
+}
+
+/*
+ * Initialize the allocation for the bands. Requires: target. Sets:
+ * page_band_height (=page_info.band_params.BandHeight), nbands.
+ */
+private int
+clist_init_bands(gx_device * dev, uint data_size, int band_width,
+ int band_height)
+{
+ gx_device_clist_writer * const cdev =
+ &((gx_device_clist *)dev)->writer;
+ gx_device *target = cdev->target;
+ int nbands;
+
+ if (gdev_mem_data_size((gx_device_memory *) target, band_width,
+ band_height) > data_size
+ )
+ return_error(gs_error_rangecheck);
+ cdev->page_band_height = band_height;
+ nbands = (target->height + band_height - 1) / band_height;
+ cdev->nbands = nbands;
+#ifdef DEBUG
+ if (gs_debug_c('l') | gs_debug_c(':'))
+ dlprintf4("[:]width=%d, band_width=%d, band_height=%d, nbands=%d\n",
+ target->width, band_width, band_height, nbands);
+#endif
+ return 0;
+}
+
+/*
+ * Initialize the allocation for the band states, which are used only
+ * when writing. Requires: nbands. Sets: states, cbuf, cend.
+ */
+private int
+clist_init_states(gx_device * dev, byte * init_data, uint data_size)
+{
+ gx_device_clist_writer * const cdev =
+ &((gx_device_clist *)dev)->writer;
+ ulong state_size = cdev->nbands * (ulong) sizeof(gx_clist_state);
+
+ fprintf(stderr, "DEBUG: init_data = %p for cdev->states!\n", init_data);
+
+ /*
+ * The +100 in the next line is bogus, but we don't know what the
+ * real check should be. We're effectively assuring that at least 100
+ * bytes will be available to buffer command operands.
+ */
+ if (state_size + sizeof(cmd_prefix) + cmd_largest_size + 100 > data_size)
+ return_error(gs_error_rangecheck);
+ cdev->states = (gx_clist_state *) init_data;
+ cdev->cbuf = init_data + state_size;
+ cdev->cend = init_data + data_size;
+ return 0;
+}
+
+/*
+ * Initialize all the data allocations. Requires: target. Sets:
+ * page_tile_cache_size, page_info.band_params.BandWidth,
+ * page_info.band_params.BandBufferSpace, + see above.
+ */
+private int
+clist_init_data(gx_device * dev, byte * init_data, uint data_size)
+{
+ gx_device_clist_writer * const cdev =
+ &((gx_device_clist *)dev)->writer;
+ gx_device *target = cdev->target;
+ const int band_width =
+ cdev->page_info.band_params.BandWidth =
+ (cdev->band_params.BandWidth ? cdev->band_params.BandWidth :
+ target->width);
+ int band_height = cdev->band_params.BandHeight;
+ const uint band_space =
+ cdev->page_info.band_params.BandBufferSpace =
+ (cdev->band_params.BandBufferSpace ?
+ cdev->band_params.BandBufferSpace : data_size);
+ byte *data = init_data;
+ uint size = band_space;
+ uint bits_size;
+ int code;
+
+ if (band_height) { /*
+ * The band height is fixed, so the band buffer requirement
+ * is completely determined.
+ */
+ uint band_data_size =
+ gdev_mem_data_size((gx_device_memory *) target,
+ band_width, band_height);
+
+ if (band_data_size >= band_space)
+ return_error(gs_error_rangecheck);
+ bits_size = min(band_space - band_data_size, data_size >> 1);
+ /**** MRS - make sure bits_size is 64-bit aligned for clist data!!! ****/
+ bits_size = (bits_size + 7) & ~7;
+ } else { /*
+ * Choose the largest band height that will fit in the
+ * rendering-time buffer.
+ */
+ bits_size = clist_tile_cache_size(target, band_space);
+ bits_size = min(bits_size, data_size >> 1);
+ /**** MRS - make sure bits_size is 64-bit aligned for clist data!!! ****/
+ bits_size = (bits_size + 7) & ~7;
+ band_height = gdev_mem_max_height((gx_device_memory *) target,
+ band_width,
+ band_space - bits_size);
+ if (band_height == 0)
+ return_error(gs_error_rangecheck);
+ }
+ code = clist_init_tile_cache(dev, data, bits_size);
+ if (code < 0)
+ return code;
+ cdev->page_tile_cache_size = bits_size;
+ data += bits_size;
+ size -= bits_size;
+ code = clist_init_bands(dev, size, band_width, band_height);
+ if (code < 0)
+ return code;
+ return clist_init_states(dev, data, data_size - bits_size);
+}
+/*
+ * Reset the device state (for writing). This routine requires only
+ * data, data_size, and target to be set, and is idempotent.
+ */
+private int
+clist_reset(gx_device * dev)
+{
+ gx_device_clist_writer * const cdev =
+ &((gx_device_clist *)dev)->writer;
+ int code = clist_init_data(dev, cdev->data, cdev->data_size);
+ int nbands;
+
+ if (code < 0)
+ return (cdev->permanent_error = code);
+ /* Now initialize the rest of the state. */
+ cdev->permanent_error = 0;
+ nbands = cdev->nbands;
+ cdev->ymin = cdev->ymax = -1; /* render_init not done yet */
+ memset(cdev->tile_table, 0, (cdev->tile_hash_mask + 1) *
+ sizeof(*cdev->tile_table));
+ cdev->cnext = cdev->cbuf;
+ cdev->ccl = 0;
+ cdev->band_range_list.head = cdev->band_range_list.tail = 0;
+ cdev->band_range_min = 0;
+ cdev->band_range_max = nbands - 1;
+ {
+ int band;
+ gx_clist_state *states = cdev->states;
+
+ for (band = 0; band < nbands; band++, states++) {
+ static const gx_clist_state cls_initial =
+ {cls_initial_values};
+
+ *states = cls_initial;
+ }
+ }
+ /*
+ * Round up the size of the per-tile band mask so that the bits,
+ * which follow it, stay aligned.
+ */
+ cdev->tile_band_mask_size =
+ ((nbands + (align_bitmap_mod * 8 - 1)) >> 3) &
+ ~(align_bitmap_mod - 1);
+ /*
+ * Initialize the all-band parameters to impossible values,
+ * to force them to be written the first time they are used.
+ */
+ memset(&cdev->tile_params, 0, sizeof(cdev->tile_params));
+ cdev->tile_depth = 0;
+ cdev->tile_known_min = nbands;
+ cdev->tile_known_max = -1;
+ cdev->imager_state = clist_imager_state_initial;
+ cdev->clip_path = NULL;
+ cdev->clip_path_id = gs_no_id;
+ cdev->color_space = 0;
+ {
+ int i;
+
+ for (i = 0; i < countof(cdev->transfer_ids); ++i)
+ cdev->transfer_ids[i] = gs_no_id;
+ }
+ cdev->black_generation_id = gs_no_id;
+ cdev->undercolor_removal_id = gs_no_id;
+ cdev->device_halftone_id = gs_no_id;
+ return 0;
+}
+/*
+ * Initialize the device state (for writing). This routine requires only
+ * data, data_size, and target to be set, and is idempotent.
+ */
+private int
+clist_init(gx_device * dev)
+{
+ gx_device_clist_writer * const cdev =
+ &((gx_device_clist *)dev)->writer;
+ int code = clist_reset(dev);
+
+ if (code >= 0) {
+ cdev->image_enum_id = gs_no_id;
+ cdev->error_is_retryable = 0;
+ cdev->driver_call_nesting = 0;
+ cdev->ignore_lo_mem_warnings = 0;
+ }
+ return code;
+}
+
+/* (Re)init open band files for output (set block size, etc). */
+private int /* ret 0 ok, -ve error code */
+clist_reinit_output_file(gx_device *dev)
+{ gx_device_clist_writer * const cdev =
+ &((gx_device_clist *)dev)->writer;
+ int code = 0;
+
+ /* bfile needs to guarantee cmd_blocks for: 1 band range, nbands */
+ /* & terminating entry */
+ int b_block = sizeof(cmd_block) * (cdev->nbands + 2);
+
+ /* cfile needs to guarantee one writer buffer */
+ /* + one end_clip cmd (if during image's clip path setup) */
+ /* + an end_image cmd for each band (if during image) */
+ /* + end_cmds for each band and one band range */
+ int c_block
+ = cdev->cend - cdev->cbuf + 2 + cdev->nbands * 2 + (cdev->nbands + 1);
+
+ /* All this is for partial page rendering's benefit, do only */
+ /* if partial page rendering is available */
+ if ( clist_test_VMerror_recoverable(cdev) )
+ { if (cdev->page_bfile != 0)
+ code = clist_set_memory_warning(cdev->page_bfile, b_block);
+ if (code >= 0 && cdev->page_cfile != 0)
+ code = clist_set_memory_warning(cdev->page_cfile, c_block);
+ }
+ return code;
+}
+
+/* Write out the current parameters that must be at the head of each page */
+/* if async rendering is in effect */
+private int
+clist_emit_page_header(gx_device *dev)
+{
+ gx_device_clist_writer * const cdev =
+ &((gx_device_clist *)dev)->writer;
+ int code = 0;
+
+ if ( (cdev->disable_mask & clist_disable_pass_thru_params) )
+ { do
+ if ( ( code = clist_put_current_params(cdev) ) >= 0 )
+ break;
+ while ( ( code = clist_VMerror_recover(cdev, code) ) < 0 );
+ cdev->permanent_error = (code < 0) ? code : 0;
+ if (cdev->permanent_error < 0)
+ cdev->error_is_retryable = 0;
+ }
+ return code;
+}
+
+/* Open the device's bandfiles */
+private int
+clist_open_output_file(gx_device *dev)
+{
+ gx_device_clist_writer * const cdev =
+ &((gx_device_clist *)dev)->writer;
+ char fmode[4];
+ int code;
+
+ if (cdev->do_not_open_or_close_bandfiles)
+ return 0; /* external bandfile open/close managed externally */
+ cdev->page_cfile = 0; /* in case of failure */
+ cdev->page_bfile = 0; /* ditto */
+ code = clist_init(dev);
+ if (code < 0)
+ return code;
+ strcpy(fmode, "w+");
+ strcat(fmode, gp_fmode_binary_suffix);
+ cdev->page_cfname[0] = 0; /* create a new file */
+ cdev->page_bfname[0] = 0; /* ditto */
+ cdev->page_bfile_end_pos = 0;
+ if ((code = clist_fopen(cdev->page_cfname, fmode, &cdev->page_cfile,
+ cdev->bandlist_memory, cdev->bandlist_memory,
+ true)) < 0 ||
+ (code = clist_fopen(cdev->page_bfname, fmode, &cdev->page_bfile,
+ cdev->bandlist_memory, cdev->bandlist_memory,
+ true)) < 0 ||
+ (code = clist_reinit_output_file(dev)) < 0
+ ) {
+ clist_close_output_file(dev);
+ cdev->permanent_error = code;
+ cdev->error_is_retryable = 0;
+ }
+ return code;
+}
+
+/* Close the device by freeing the temporary files. */
+/* Note that this does not deallocate the buffer. */
+int
+clist_close_output_file(gx_device *dev)
+{
+ gx_device_clist_writer * const cdev =
+ &((gx_device_clist *)dev)->writer;
+
+ if (cdev->page_cfile != NULL) {
+ clist_fclose(cdev->page_cfile, cdev->page_cfname, true);
+ cdev->page_cfile = NULL;
+ }
+ if (cdev->page_bfile != NULL) {
+ clist_fclose(cdev->page_bfile, cdev->page_bfname, true);
+ cdev->page_bfile = NULL;
+ }
+ return 0;
+}
+
+/* Open the device by initializing the device state and opening the */
+/* scratch files. */
+private int
+clist_open(gx_device *dev)
+{
+ gx_device_clist_writer * const cdev =
+ &((gx_device_clist *)dev)->writer;
+ int code;
+
+ cdev->permanent_error = 0;
+ code = clist_init(dev);
+ if (code < 0)
+ return code;
+ code = clist_open_output_file(dev);
+ if ( code >= 0)
+ code = clist_emit_page_header(dev);
+ return code;
+}
+
+private int
+clist_close(gx_device *dev)
+{
+ gx_device_clist_writer * const cdev =
+ &((gx_device_clist *)dev)->writer;
+
+ if (cdev->do_not_open_or_close_bandfiles)
+ return 0;
+ return clist_close_output_file(dev);
+}
+
+/* The output_page procedure should never be called! */
+private int
+clist_output_page(gx_device * dev, int num_copies, int flush)
+{
+ return_error(gs_error_Fatal);
+}
+
+/* Reset (or prepare to append to) the command list after printing a page. */
+int
+clist_finish_page(gx_device *dev, bool flush)
+{
+ gx_device_clist_writer * const cdev =
+ &((gx_device_clist *)dev)->writer;
+ int code;
+
+ if (flush) {
+ if (cdev->page_cfile != 0)
+ clist_rewind(cdev->page_cfile, true, cdev->page_cfname);
+ if (cdev->page_bfile != 0)
+ clist_rewind(cdev->page_bfile, true, cdev->page_bfname);
+ cdev->page_bfile_end_pos = 0;
+ } else {
+ if (cdev->page_cfile != 0)
+ clist_fseek(cdev->page_cfile, 0L, SEEK_END, cdev->page_cfname);
+ if (cdev->page_bfile != 0)
+ clist_fseek(cdev->page_bfile, 0L, SEEK_END, cdev->page_bfname);
+ }
+ code = clist_init(dev); /* reinitialize */
+ if (code >= 0)
+ code = clist_reinit_output_file(dev);
+ if (code >= 0)
+ code = clist_emit_page_header(dev);
+
+ return code;
+}
+
+/* ------ Writing ------ */
+
+/* End a page by flushing the buffer and terminating the command list. */
+int /* ret 0 all-ok, -ve error code, or +1 ok w/low-mem warning */
+clist_end_page(gx_device_clist_writer * cldev)
+{
+ int code = cmd_write_buffer(cldev, cmd_opv_end_page);
+ cmd_block cb;
+ int ecode = 0;
+
+ if (code >= 0) {
+ /*
+ * Write the terminating entry in the block file.
+ * Note that because of copypage, there may be many such entries.
+ */
+ cb.band_min = cb.band_max = cmd_band_end;
+ cb.pos = (cldev->page_cfile == 0 ? 0 : clist_ftell(cldev->page_cfile));
+ clist_fwrite_chars(&cb, sizeof(cb), cldev->page_bfile);
+ cldev->page_bfile_end_pos = clist_ftell(cldev->page_bfile);
+ }
+ if (code >= 0) {
+ ecode |= code;
+ cldev->page_bfile_end_pos = clist_ftell(cldev->page_bfile);
+ }
+ if (code < 0)
+ ecode = code;
+
+ /* Reset warning margin to 0 to release reserve memory if mem files */
+ if (cldev->page_bfile != 0)
+ clist_set_memory_warning(cldev->page_bfile, 0);
+ if (cldev->page_cfile != 0)
+ clist_set_memory_warning(cldev->page_cfile, 0);
+
+#ifdef DEBUG
+ if (gs_debug_c('l') | gs_debug_c(':'))
+ dlprintf2("[:]clist_end_page at cfile=%ld, bfile=%ld\n",
+ cb.pos, cldev->page_bfile_end_pos);
+#endif
+ return 0;
+}
+
+/* Recover recoverable VM error if possible without flushing */
+int /* ret -ve err, >= 0 if recovered w/# = cnt pages left in page queue */
+clist_VMerror_recover(gx_device_clist_writer *cldev,
+ int old_error_code)
+{
+ int code = old_error_code;
+ int pages_remain;
+
+ if (!clist_test_VMerror_recoverable(cldev) ||
+ !cldev->error_is_retryable ||
+ old_error_code != gs_error_VMerror
+ )
+ return old_error_code;
+
+ /* Do some rendering, return if enough memory is now free */
+ do {
+ pages_remain =
+ (*cldev->free_up_bandlist_memory)( (gx_device *)cldev, false );
+ if (pages_remain < 0) {
+ code = pages_remain; /* abort, error or interrupt req */
+ break;
+ }
+ if (clist_reinit_output_file( (gx_device *)cldev ) == 0) {
+ code = pages_remain; /* got enough memory to continue */
+ break;
+ }
+ } while (pages_remain);
+
+ if_debug1('L', "[L]soft flush of command list, status: %d\n", code);
+ return code;
+}
+
+/* If recoverable VM error, flush & try to recover it */
+int /* ret 0 ok, else -ve error */
+clist_VMerror_recover_flush(gx_device_clist_writer *cldev,
+ int old_error_code)
+{
+ int free_code = 0;
+ int reset_code = 0;
+ int code;
+
+ /* If the device has the ability to render partial pages, flush
+ * out the bandlist, and reset the writing state. Then, get the
+ * device to render this band. When done, see if there's now enough
+ * memory to satisfy the minimum low-memory guarantees. If not,
+ * get the device to render some more. If there's nothing left to
+ * render & still insufficient memory, declare an error condition.
+ */
+ if (!clist_test_VMerror_recoverable(cldev) ||
+ old_error_code != gs_error_VMerror
+ )
+ return old_error_code; /* sorry, don't have any means to recover this error */
+ free_code = (*cldev->free_up_bandlist_memory)( (gx_device *)cldev, true );
+
+ /* Reset the state of bands to "don't know anything" */
+ reset_code = clist_reset( (gx_device *)cldev );
+ if (reset_code >= 0)
+ reset_code = clist_open_output_file( (gx_device *)cldev );
+ if ( reset_code >= 0 &&
+ (cldev->disable_mask & clist_disable_pass_thru_params)
+ )
+ reset_code = clist_put_current_params(cldev);
+ if (reset_code < 0) {
+ cldev->permanent_error = reset_code;
+ cldev->error_is_retryable = 0;
+ }
+
+ code = (reset_code < 0 ? reset_code : free_code < 0 ? old_error_code : 0);
+ if_debug1('L', "[L]hard flush of command list, status: %d\n", code);
+ return code;
+}
+
+/* Write the target device's current parameter list */
+private int /* ret 0 all ok, -ve error */
+clist_put_current_params(gx_device_clist_writer *cldev)
+{
+ gx_device *target = cldev->target;
+ gs_c_param_list param_list;
+ int code;
+
+ /*
+ * If a put_params call fails, the device will be left in a closed
+ * state, but higher-level code won't notice this fact. We flag this by
+ * setting permanent_error, which prevents writing to the command list.
+ */
+
+ if (cldev->permanent_error)
+ return cldev->permanent_error;
+ gs_c_param_list_write(&param_list, cldev->memory);
+ code = (*dev_proc(target, get_params))
+ (target, (gs_param_list *)&param_list);
+ if (code >= 0) {
+ gs_c_param_list_read(&param_list);
+ code = cmd_put_params( cldev, (gs_param_list *)&param_list );
+ }
+ gs_c_param_list_release(&param_list);
+
+ return code;
+}
+
+/* ---------------- Driver interface ---------------- */
+
+private int
+clist_get_band(gx_device * dev, int y, int *band_start)
+{
+ gx_device_clist_writer * const cdev =
+ &((gx_device_clist *)dev)->writer;
+ int band_height = cdev->page_band_height;
+ int start;
+
+ if (y < 0)
+ y = 0;
+ else if (y >= dev->height)
+ y = dev->height;
+ *band_start = start = y - y % band_height;
+ return min(dev->height - start, band_height);
+}
diff --git a/pstoraster/gxclist.h b/pstoraster/gxclist.h
new file mode 100644
index 000000000..9168721d7
--- /dev/null
+++ b/pstoraster/gxclist.h
@@ -0,0 +1,299 @@
+/* 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$ */
+/* Command list definitions for Ghostscript. */
+/* Requires gxdevice.h and gxdevmem.h */
+
+#ifndef gxclist_INCLUDED
+# define gxclist_INCLUDED
+
+#include "gscspace.h"
+#include "gxband.h"
+#include "gxbcache.h"
+#include "gxclio.h"
+#include "gxistate.h"
+
+/*
+ * A command list is essentially a compressed list of driver calls.
+ * Command lists are used to record an image that must be rendered in bands
+ * for high-resolution and/or limited-memory printers.
+ *
+ * Command lists work in two phases. The first phase records driver calls,
+ * sorting them according to the band(s) they affect. The second phase
+ * reads back the commands band-by-band to create the bitmap images.
+ * When opened, a command list is in the recording state; it switches
+ * automatically from recording to reading when its get_bits procedure
+ * is called. Currently, there is a hack to reopen the device after
+ * each page is processed, in order to switch back to recording.
+ */
+
+/*
+ * The command list contains both commands for particular bands (the vast
+ * majority) and commands that apply to a range of bands. In order to
+ * synchronize the two, we maintain the following invariant for buffered
+ * commands:
+ *
+ * If there are any band-range commands in the buffer, they are the
+ * first commands in the buffer, before any specific-band commands.
+ *
+ * To maintain this invariant, whenever we are about to put an band-range
+ * command in the buffer, we check to see if the buffer already has any
+ * band-range commands in it, and if so, whether they are the last commands
+ * in the buffer and are for the same range; if the answer to any of these
+ * questions is negative, we flush the buffer.
+ */
+
+/* ---------------- Public structures ---------------- */
+
+/*
+ * Define a saved page object. This consists of a snapshot of the device
+ * structure, information about the page per se, and the num_copies
+ * parameter of output_page.
+ */
+typedef struct gx_saved_page_s {
+ gx_device device;
+ char dname[8 + 1]; /* device name for checking */
+ gx_band_page_info info;
+ int num_copies;
+} gx_saved_page;
+
+/*
+ * Define a saved page placed at a particular (X,Y) offset for rendering.
+ */
+typedef struct gx_placed_page_s {
+ gx_saved_page *page;
+ gs_int_point offset;
+} gx_placed_page;
+
+/*
+ * Define a procedure to cause some bandlist memory to be freed up,
+ * probably by rendering current bandlist contents.
+ */
+#define proc_free_up_bandlist_memory(proc)\
+ int proc(P2(gx_device *dev, bool flush_current))
+
+/* ---------------- Internal structures ---------------- */
+
+/*
+ * Currently, halftoning occurs during the first phase, producing calls
+ * to tile_rectangle. Both phases keep a cache of recently seen bitmaps
+ * (halftone cells and characters), which allows writing only a short cache
+ * index in the command list rather than the entire bitmap.
+ *
+ * We keep only a single cache for all bands, but since the second phase
+ * reads the command lists for each band separately, we have to keep track
+ * for each cache entry E and band B whether the definition of E has been
+ * written into B's list. We do this with a bit mask in each entry.
+ *
+ * Eventually, we will replace this entire arrangement with one in which
+ * we pass the actual halftone screen (whitening order) to all bands
+ * through the command list, and halftoning occurs on the second phase.
+ * This not only will shrink the command list, but will allow us to apply
+ * other rendering algorithms such as error diffusion in the second phase.
+ */
+typedef struct {
+ ulong offset; /* writing: offset from cdev->data, */
+ /* 0 means unused */
+ /* reading: offset from cdev->chunk.data */
+} tile_hash;
+typedef struct {
+ gx_cached_bits_common;
+ /* To save space, instead of storing rep_width and rep_height, */
+ /* we store width / rep_width and height / rep_height. */
+ byte x_reps, y_reps;
+ ushort rep_shift;
+ ushort index; /* index in table (hash table when writing) */
+ ushort num_bands; /* # of 1-bits in the band mask */
+ /* byte band_mask[]; */
+#define ts_mask(pts) (byte *)((pts) + 1)
+ /* byte bits[]; */
+#define ts_bits(cldev,pts) (ts_mask(pts) + (cldev)->tile_band_mask_size)
+} tile_slot;
+
+
+/*
+ * In order to keep the per-band state down to a reasonable size,
+ * we store only a single set of the imager state parameters;
+ * for each parameter, each band has a flag that says whether that band
+ * 'knows' the current value of the parameters.
+ */
+extern const gs_imager_state clist_imager_state_initial;
+
+/*
+ * Define the main structure for holding command list state.
+ * Unless otherwise noted, all elements are used in both the writing (first)
+ * and reading (second) phase.
+ */
+typedef struct gx_clist_state_s gx_clist_state;
+
+#define gx_device_clist_common_members\
+ gx_device_forward_common; /* (see gxdevice.h) */\
+ /* Following must be set before writing or reading. */\
+ /* See gx_device_clist_writer, below, for more that must be init'd */\
+ /* gx_device *target; */ /* device for which commands */\
+ /* are being buffered */\
+ dev_proc_make_buffer_device((*make_buffer_device));\
+ gs_memory_t *bandlist_memory; /* allocator for in-memory bandlist files */\
+ byte *data; /* buffer area */\
+ uint data_size; /* size of buffer */\
+ gx_band_params band_params; /* band buffering parameters */\
+ bool do_not_open_or_close_bandfiles; /* if true, do not open/close bandfiles */\
+ /* Following are used for both writing and reading. */\
+ gx_bits_cache_chunk chunk; /* the only chunk of bits */\
+ gx_bits_cache bits;\
+ uint tile_hash_mask; /* size of tile hash table -1 */\
+ uint tile_band_mask_size; /* size of band mask preceding */\
+ /* each tile in the cache */\
+ tile_hash *tile_table; /* table for tile cache: */\
+ /* see tile_hash above */\
+ /* (a hash table when writing) */\
+ int ymin, ymax; /* current band, <0 when writing */\
+ /* Following are set when writing, read when reading. */\
+ gx_band_page_info page_info; /* page information */\
+ int nbands /* # of bands */
+
+typedef struct gx_device_clist_common_s {
+ gx_device_clist_common_members;
+} gx_device_clist_common;
+
+#define clist_band_height(cldev) ((cldev)->page_info.band_height)
+#define clist_cfname(cldev) ((cldev)->page_info.cfname)
+#define clist_cfile(cldev) ((cldev)->page_info.cfile)
+#define clist_bfname(cldev) ((cldev)->page_info.bfname)
+#define clist_bfile(cldev) ((cldev)->page_info.bfile)
+
+/* Define the length of the longest dash pattern we are willing to store. */
+/* (Strokes with longer patterns are converted to fills.) */
+#define cmd_max_dash 11
+
+/* Define the state of a band list when writing. */
+typedef struct gx_device_clist_writer_s {
+ gx_device_clist_common_members; /* (must be first) */
+ int error_code; /* error returned by cmd_put_op */
+ gx_clist_state *states; /* current state of each band */
+ byte *cbuf; /* start of command buffer */
+ byte *cnext; /* next slot in command buffer */
+ byte *cend; /* end of command buffer */
+ cmd_list *ccl; /* &clist_state.list of last command */
+ cmd_list band_range_list; /* list of band-range commands */
+ int band_range_min, band_range_max; /* range for list */
+ uint tile_max_size; /* max size of a single tile (bytes) */
+ uint tile_max_count; /* max # of hash table entries */
+ gx_strip_bitmap tile_params; /* current tile parameters */
+ int tile_depth; /* current tile depth */
+ int tile_known_min, tile_known_max;
+ /* range of bands that knows the */
+ /* current tile parameters */
+ gs_imager_state imager_state; /* current values of imager params */
+ float dash_pattern[cmd_max_dash]; /* current dash pattern */
+ const gx_clip_path *clip_path; /* current clip path */
+ gs_id clip_path_id; /* id of current clip path */
+ byte color_space; /* current color space identifier */
+ /* (only used for images) */
+ gs_indexed_params indexed_params; /* current indexed space parameters */
+ /* (ditto) */
+ gs_id transfer_ids[4]; /* ids of transfer maps */
+ gs_id black_generation_id; /* id of black generation map */
+ gs_id undercolor_removal_id; /* id of u.c.r. map */
+ gs_id device_halftone_id; /* id of device halftone */
+ gs_id image_enum_id; /* non-0 if we are inside an image */
+ /* that we are passing through */
+ int error_is_retryable; /* Extra status used to distinguish hard VMerrors */
+ /* from warnings upgraded to VMerrors. */
+ /* T if err ret'd by cmd_put_op et al can be retried */
+ int permanent_error; /* if < 0, error only cleared by clist_reset() */
+ int driver_call_nesting; /* nesting level of non-retryable driver calls */
+ int ignore_lo_mem_warnings; /* ignore warnings from clist file/mem */
+ /* Following must be set before writing */
+ proc_free_up_bandlist_memory((*free_up_bandlist_memory)); /* if nz, proc to free some bandlist memory */
+ int disable_mask; /* mask of routines to disable clist_disable_xxx */
+} gx_device_clist_writer;
+
+/* Bits for gx_device_clist_writer.disable_mask. Bit set disables behavior */
+#define clist_disable_fill_path (1 << 0)
+#define clist_disable_stroke_path (1 << 1)
+#define clist_disable_hl_image (1 << 2)
+#define clist_disable_complex_clip (1 << 3)
+#define clist_disable_nonrect_hl_image (1 << 4)
+#define clist_disable_pass_thru_params (1 << 5) /* disable EXCEPT at top of page */
+
+/* Define the state of a band list when reading. */
+/* For normal rasterizing, pages and num_pages are both 0. */
+typedef struct gx_device_clist_reader_s {
+ gx_device_clist_common_members; /* (must be first) */
+ const gx_placed_page *pages;
+ int num_pages;
+} gx_device_clist_reader;
+
+typedef union gx_device_clist_s {
+ gx_device_clist_common common;
+ gx_device_clist_reader reader;
+ gx_device_clist_writer writer;
+} gx_device_clist;
+
+/* setup before opening clist device */
+#define clist_init_params(xclist, xdata, xdata_size, xtarget, xmake_buffer, xband_params, xexternal, xmemory, xfree_bandlist, xdisable)\
+ (xclist)->common.data = (xdata);\
+ (xclist)->common.data_size = (xdata_size);\
+ (xclist)->common.target = (xtarget);\
+ (xclist)->common.make_buffer_device = (xmake_buffer);\
+ (xclist)->common.band_params = (xband_params);\
+ (xclist)->common.do_not_open_or_close_bandfiles = (xexternal);\
+ (xclist)->common.bandlist_memory = (xmemory);\
+ (xclist)->writer.free_up_bandlist_memory = (xfree_bandlist);\
+ (xclist)->writer.disable_mask = (xdisable)
+
+/* Determine whether this clist device is able to recover VMerrors */
+#define clist_test_VMerror_recoverable(cldev)\
+ ((cldev)->free_up_bandlist_memory != 0)
+
+/* The device template itself is never used, only the procedures. */
+extern const gx_device_procs gs_clist_device_procs;
+
+/* Reset (or prepare to append to) the command list after printing a page. */
+int clist_finish_page(P2(gx_device * dev, bool flush));
+
+/* Force bandfiles closed */
+int clist_close_output_file(P1(gx_device *dev));
+
+/* 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
+
+/* Do device setup from params passed in the command list. */
+int clist_setup_params(P1(gx_device *dev));
+
+/* Do more rendering to a client-supplied memory image, return results */
+int clist_get_overlay_bits(P4(gx_device_printer *pdev, int y, int line_count,
+ byte *data));
+
+/* Find out where the band buffer for a given line is going to fall on the */
+/* next call to get_bits. */
+int clist_locate_overlay_buffer(P3(gx_device_printer *pdev, int y,
+ byte **pdata));
+
+#endif /* gxclist_INCLUDED */
diff --git a/pstoraster/gxclmem.c b/pstoraster/gxclmem.c
new file mode 100644
index 000000000..e2e1c00d0
--- /dev/null
+++ b/pstoraster/gxclmem.c
@@ -0,0 +1,1151 @@
+/* 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$ */
+/* RAM-based command list implementation */
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsmalloc.h" /* for gs_memory_default */
+#include "gxclmem.h"
+#include <config.h>
+
+/*
+ * Based on: memfile.c Version: 1.4 3/21/95 14:59:33 by Ray Johnston.
+ * Copyright assigned to Aladdin Enterprises.
+ */
+
+/*****************************************************************************
+
+ This package is more or less optimal for use by the clist routines, with
+ a couple of the more likely to change "tuning" parameters given in the
+ two macros below -- NEED_TO_COMPRESS and GET_NUM_RAW_BUFFERS. Usually
+ the NEED_TO_COMPRESS decision will be deferred as long as possible based
+ on some total system free RAM space remaining.
+
+ The data structures are in "memfile.h", and the primary 'tuning' parameter
+ is MEMFILE_DATA_SIZE. This should not be too small to keep the overhead
+ ratio of the block structures to the clist data small. A value of 16384
+ is probably in the ballpark.
+
+ The concept is that a memory based "file" is created initially without
+ compression, with index blocks every MEMFILE_DATA_SIZE of the file. The
+ primary blocks (used by the memfile_fseek logic) for indexing into the
+ file are called 'logical' (LOG_MEMFILE_BLK) and the data in stored in a
+ different block called a 'physical' block (PHYS_MEMFILE_BLK). When the
+ file is not yet compressed, indicated by (f->phys_curr==NULL), then there
+ is one physical block for each logical block. The physical block also has
+ the 'data_limit' set to NULL if the data is not compressed. Thus when a
+ file is not compressed there is one physical block for each logical block.
+
+COMPRESSION.
+
+ When compression is triggered for a file then all of the blocks except
+ the last are compressed. Compression will result in a physical block
+ that holds data for more than one logical block. Each logical block now
+ points to the start of compressed data in a physical block with the
+ 'phys_pdata' pointer. The 'data_limit' pointer in the physical block is
+ where the compression logic stopped storing data (as stream data
+ compressors are allowed to do). The data for the logical block may span
+ to the next physical block. Once physical blocks are compressed, they are
+ chained together using the 'link' field.
+
+ The 'f->phys_curr' points to the block being filled by compression, with
+ the 'f->wt.ptr' pointing to the last byte filled in the block. These are
+ used during subsequent compression when the last logical block of the
+ file fills the physical block.
+
+DECOMPRESSION.
+
+ During reading the clist, if the logical block points to an uncompressed
+ physical block, then 'memfile_get_pdata' simply sets the 'pdata' and the
+ 'pdata_end' pointers. If the logical block was compressed, then it may
+ still be resident in a cache of decompression buffers. The number of these
+ decompression buffers is not critical -- even one is enough, but having
+ more may prevent decompressing blocks more than once (a cache_miss). The
+ number of decompression buffers, called "raw" buffers, that are attempted
+ to allocate can be changed with the GET_NUM_RAW_BUFFERS macro, but no
+ error occurs if less than that number can be allocated.
+
+ If the logical block still resides in a decompression cache buffer, then
+ the 'raw_block' will identify the block. If the data for a logical block
+ only exists in compressed form, then the "tail" of the list of decompression
+ buffers is re-used, marking the 'raw_block' of the logical block that was
+ previously associated with this data to NULL.
+
+ Whichever raw decompression buffer is accessed is moved to the head of the
+ decompression buffer list in order to keep the tail of the list as the
+ "least recently used".
+
+ There are some DEBUG global static variables used to count the number of
+ cache hits "tot_cache_hits" and the number of times a logical block is
+ decompressed "tot_cache_miss". Note that the actual number of cache miss
+ events is 'f->log_length/MEMFILE_DATA_SIZE - tot_cache_miss' since we
+ assume that every logical block must be decmpressed at least once.
+
+ Empirical results so far indicate that if one cache raw buffer for every
+ 32 logical blocks, then the hit/miss ratio exceeds 99%. Of course, the
+ number of raw buffers should be more than 1 if possible, and in many
+ implementations (single threaded), the memory usage does not increase
+ during the page output step so almost all of memory can be used for
+ these raw buffers to prevent the likelihood of a cache miss.
+
+ Of course, this is dependent on reasonably efficient clist blocking
+ during writing which is dependent on the data and on the BufferSpace
+ value which determines the number of clist band data buffers available.
+ Empirical testing shows that the overall efficiency is best if the
+ BufferSpace value is 1,000,000 (as in the original Ghostscript source).
+ [Note: I expected to be able to use smaller buffer sizes for some cases,
+ but this resulted in a high level of thrashing...RJJ]
+
+LIMITATIONS.
+
+ The most serious limitation is caused by the way 'memfile_fwrite' decides
+ to free up and re-initialize a file. If memfile_fwrite is called after
+ a seek to any location except the start of the file, then an error is
+ issued since logic is not present to properly free up on a partial file.
+ This is not a problem as used by the 'clist' logic since rewind is used
+ to position to the start of a file when re-using it after an 'erasepage'.
+
+ Since the 'clist' logic always traverses the clist using fseek's to ever
+ increasing locations, no optimizations of backward seeks was implemented.
+ This would be relatively easy with back chain links or bi-directional
+ "X-OR" pointer information to link the logical block chain. The rewind
+ function is optimal and moves directly to the start of the file.
+
+********************************************************************************/
+
+/*
+ The need to compress should be conditional on the amount of available
+ memory, but we don't have a way to communicate this to these routines.
+ Instead, we simply start compressing when we've allocated more than
+ COMPRESSION_THRESHOLD amount of data. The threshold should be at
+ least as large as the fixed overhead of the compressor plus the
+ decompressor, plus the expected compressed size of a block that size.
+ */
+private const long COMPRESSION_THRESHOLD = 300000;
+
+#define NEED_TO_COMPRESS(f)\
+ ((f)->ok_to_compress && (f)->total_space > COMPRESSION_THRESHOLD)
+
+ /* FOR NOW ALLOCATE 1 raw buffer for every 32 blocks (at least 8) */
+#define GET_NUM_RAW_BUFFERS( f ) \
+ max(f->log_length/MEMFILE_DATA_SIZE/32, 8)
+
+#define MALLOC(f, siz, cname)\
+ (void *)gs_alloc_bytes((f)->data_memory, siz, cname)
+#define FREE(f, obj, cname)\
+ (gs_free_object((f)->data_memory, obj, cname),\
+ (f)->total_space -= sizeof(*(obj)))
+
+/* Structure descriptor for GC */
+private_st_MEMFILE();
+
+ /* forward references */
+private void memfile_free_mem(P1(MEMFILE * f));
+private int memfile_init_empty(P1(MEMFILE * f));
+
+/************************************************/
+/* #define DEBUG /- force statistics -/ */
+/************************************************/
+
+#ifdef DEBUG
+long tot_compressed;
+long tot_raw;
+long tot_cache_miss;
+long tot_cache_hits;
+long tot_swap_out;
+
+/*
+ The following pointers are here only for helping with a dumb debugger
+ that can't inspect local variables!
+ */
+byte *decomp_wt_ptr0, *decomp_wt_limit0;
+const byte *decomp_rd_ptr0, *decomp_rd_limit0;
+byte *decomp_wt_ptr1, *decomp_wt_limit1;
+const byte *decomp_rd_ptr1, *decomp_rd_limit1;
+
+#endif
+
+/* ----------------------------- Memory Allocation --------------------- */
+void * /* allocated memory's address, 0 if failure */
+allocateWithReserve(
+ MEMFILE *f, /* file to allocate mem to */
+ int sizeofBlock, /* size of block to allocate */
+ int *return_code, /* RET 0 ok, -ve GS-style error, or +1 if OK but low memory */
+ const char *allocName, /* name to allocate by */
+ const char *errorMessage /* error message to print */
+)
+{
+ int code = 0; /* assume success */
+ void *block = MALLOC(f, sizeofBlock, allocName);
+
+ if (block == NULL) {
+ /* Try to recover block from reserve */
+ if (sizeofBlock == sizeof(LOG_MEMFILE_BLK)) {
+ if (f->reserveLogBlockCount > 0) {
+ block = f->reserveLogBlockChain;
+ f->reserveLogBlockChain = f->reserveLogBlockChain->link;
+ --f->reserveLogBlockCount;
+ }
+ } else if (sizeofBlock == sizeof(PHYS_MEMFILE_BLK) ||
+ sizeofBlock == sizeof(RAW_BUFFER)
+ ) {
+ if (f->reservePhysBlockCount > 0) {
+ block = f->reservePhysBlockChain;
+ f->reservePhysBlockChain = f->reservePhysBlockChain->link;
+ --f->reservePhysBlockCount;
+ }
+ }
+ if (block != NULL)
+ code = 1; /* successful, but allocated from reserve */
+ }
+ if (block != NULL)
+ f->total_space += sizeofBlock;
+ else
+ code = gs_note_error(gs_error_VMerror);
+ *return_code = code;
+ return block;
+}
+
+/* ---------------- Open/close/unlink ---------------- */
+
+int
+memfile_fopen(char fname[gp_file_name_sizeof], const char *fmode,
+ clist_file_ptr /*MEMFILE * */ * pf,
+ gs_memory_t *mem, gs_memory_t *data_mem, bool ok_to_compress)
+{
+ MEMFILE *f = 0;
+ int code = 0;
+
+ /* We don't implement reopening an existing file. */
+ if (fname[0] != 0 || fmode[0] != 'w') {
+ code = gs_note_error(gs_error_invalidfileaccess);
+ goto finish;
+ }
+
+ /* There is no need to set fname in this implementation, */
+ /* but we do it anyway. */
+ fname[0] = (ok_to_compress ? 'a' : 'b');
+ fname[1] = 0;
+
+ f = gs_alloc_struct(mem, MEMFILE, &st_MEMFILE,
+ "memfile_open_scratch(MEMFILE)");
+ if (f == NULL) {
+ eprintf1("memfile_open_scratch(%s): gs_alloc_struct failed\n", fname);
+ code = gs_note_error(gs_error_VMerror);
+ goto finish;
+ }
+ f->memory = mem;
+ f->data_memory = data_mem;
+ /* init an empty file, BEFORE allocating de/compress state */
+ f->compress_state = 0; /* make clean for GC, or alloc'n failure */
+ f->decompress_state = 0;
+ f->total_space = 0;
+ f->reservePhysBlockChain = NULL;
+ f->reservePhysBlockCount = 0;
+ f->reserveLogBlockChain = NULL;
+ f->reserveLogBlockCount = 0;
+ /* init an empty file */
+ if ((code = memfile_init_empty(f)) < 0)
+ goto finish;
+ if ((code = memfile_set_memory_warning(f, 0)) < 0)
+ goto finish;
+ /*
+ * Disregard the ok_to_compress flag, since the size threshold gives us
+ * a much better criterion for deciding when compression is appropriate.
+ */
+#ifdef HAVE_LIBZ
+ f->ok_to_compress = /*ok_to_compress */ true;
+#else
+ f->ok_to_compress = false;
+#endif /* HAVE_LIBZ */
+ f->compress_state = 0; /* make clean for GC */
+ f->decompress_state = 0;
+ if (f->ok_to_compress) {
+ const stream_state *compress_proto = clist_compressor_state(NULL);
+ const stream_state *decompress_proto = clist_decompressor_state(NULL);
+ const stream_template *compress_template = compress_proto->template;
+ const stream_template *decompress_template = decompress_proto->template;
+
+ f->compress_state =
+ gs_alloc_struct(mem, stream_state, compress_template->stype,
+ "memfile_open_scratch(compress_state)");
+ f->decompress_state =
+ gs_alloc_struct(mem, stream_state, decompress_template->stype,
+ "memfile_open_scratch(decompress_state)");
+ if (f->compress_state == 0 || f->decompress_state == 0) {
+ eprintf1("memfile_open_scratch(%s): gs_alloc_struct failed\n", fname);
+ code = gs_note_error(gs_error_VMerror);
+ goto finish;
+ }
+ memcpy(f->compress_state, compress_proto,
+ gs_struct_type_size(compress_template->stype));
+ f->compress_state->memory = mem;
+ memcpy(f->decompress_state, decompress_proto,
+ gs_struct_type_size(decompress_template->stype));
+ f->decompress_state->memory = mem;
+ if (compress_template->set_defaults)
+ (*compress_template->set_defaults) (f->compress_state);
+ if (decompress_template->set_defaults)
+ (*decompress_template->set_defaults) (f->decompress_state);
+ }
+ f->total_space = 0;
+
+#ifdef DEBUG
+ /* If this is the start, init some statistics. */
+ /* Hack: we know the 'a' file is opened first. */
+ if (*fname == 'a') {
+ tot_compressed = 0;
+ tot_raw = 0;
+ tot_cache_miss = 0;
+ tot_cache_hits = 0;
+ tot_swap_out = 0;
+ }
+#endif
+finish:
+ if (code < 0) {
+ /* return failure, clean up memory before leaving */
+ if (f != NULL)
+ memfile_fclose((clist_file_ptr)f, fname, true);
+ } else {
+ /* return success */
+ *pf = f;
+ }
+ return code;
+}
+
+int
+memfile_fclose(clist_file_ptr cf, const char *fname, bool delete)
+{
+ MEMFILE *const f = (MEMFILE *)cf;
+
+ /* We don't implement closing without deletion. */
+ if (!delete)
+ return_error(gs_error_invalidfileaccess);
+ memfile_free_mem(f);
+
+ /* Free reserve blocks; don't do it in memfile_free_mem because */
+ /* that routine gets called to reinit file */
+ while (f->reserveLogBlockChain != NULL) {
+ LOG_MEMFILE_BLK *block = f->reserveLogBlockChain;
+
+ f->reserveLogBlockChain = block->link;
+ FREE(f, block, "memfile_set_block_size");
+ }
+ while (f->reservePhysBlockChain != NULL) {
+ PHYS_MEMFILE_BLK *block = f->reservePhysBlockChain;
+
+ f->reservePhysBlockChain = block->link;
+ FREE(f, block, "memfile_set_block_size");
+ }
+
+ /* deallocate de/compress state */
+ gs_free_object(f->memory, f->decompress_state,
+ "memfile_close_and_unlink(decompress_state)");
+ gs_free_object(f->memory, f->compress_state,
+ "memfile_close_and_unlink(compress_state)");
+
+ /* deallocate the memfile object proper */
+ gs_free_object(f->memory, f, "memfile_close_and_unlink(MEMFILE)");
+ return 0;
+}
+
+int
+memfile_unlink(const char *fname)
+{
+ /*
+ * Since we have no way to represent a memfile other than by the
+ * pointer, we don't (can't) implement unlinking.
+ */
+ return_error(gs_error_invalidfileaccess);
+}
+
+/* ---------------- Writing ---------------- */
+
+/* Pre-alloc enough reserve mem blox to guarantee a write of N bytes will succeed */
+int /* returns 0 ok, gs_error_VMerror if insufficient */
+memfile_set_memory_warning(clist_file_ptr cf, int bytes_left)
+{
+ MEMFILE *const f = (MEMFILE *)cf;
+ int code = 0;
+ /*
+ * Determine req'd memory block count from bytes_left.
+ * Allocate enough phys & log blocks to hold bytes_left
+ * + 1 phys blk for compress_log_blk + 1 phys blk for decompress.
+ */
+ int logNeeded =
+ (bytes_left + MEMFILE_DATA_SIZE - 1) / MEMFILE_DATA_SIZE;
+ int physNeeded = logNeeded;
+
+ if (bytes_left > 0)
+ ++physNeeded;
+ if (f->raw_head == NULL)
+ ++physNeeded; /* have yet to allocate read buffers */
+
+ /* Allocate or free memory depending on need */
+ while (logNeeded > f->reserveLogBlockCount) {
+ LOG_MEMFILE_BLK *block =
+ MALLOC( f, sizeof(LOG_MEMFILE_BLK), "memfile_set_block_size" );
+
+ if (block == NULL) {
+ code = gs_note_error(gs_error_VMerror);
+ goto finish;
+ }
+ block->link = f->reserveLogBlockChain;
+ f->reserveLogBlockChain = block;
+ ++f->reserveLogBlockCount;
+ }
+ while (logNeeded < f->reserveLogBlockCount) {
+ LOG_MEMFILE_BLK *block = f->reserveLogBlockChain;
+
+ f->reserveLogBlockChain = block->link;
+ FREE(f, block, "memfile_set_block_size");
+ --f->reserveLogBlockCount;
+ }
+ while (physNeeded > f->reservePhysBlockCount) {
+ PHYS_MEMFILE_BLK *block =
+ MALLOC( f,
+ max( sizeof(PHYS_MEMFILE_BLK), sizeof(RAW_BUFFER) ),
+ "memfile_set_block_size");
+
+ if (block == NULL) {
+ code = gs_note_error(gs_error_VMerror);
+ goto finish;
+ }
+ block->link = f->reservePhysBlockChain;
+ f->reservePhysBlockChain = block;
+ ++f->reservePhysBlockCount;
+ }
+ while (physNeeded < f->reservePhysBlockCount) {
+ PHYS_MEMFILE_BLK *block = f->reservePhysBlockChain;
+
+ f->reservePhysBlockChain = block->link;
+ FREE(f, block, "memfile_set_block_size");
+ --f->reservePhysBlockCount;
+ }
+ f->error_code = 0; /* memfile_set_block_size is how user resets this */
+finish:
+ return code;
+}
+
+private int
+compress_log_blk(MEMFILE * f, LOG_MEMFILE_BLK * bp)
+{
+ int status;
+ int ecode = 0; /* accumulate low-memory warnings */
+ int code;
+ long compressed_size;
+ byte *start_ptr;
+ PHYS_MEMFILE_BLK *newphys;
+
+ /* compress this block */
+ f->rd.ptr = (const byte *)(bp->phys_blk->data) - 1;
+ f->rd.limit = f->rd.ptr + MEMFILE_DATA_SIZE;
+
+ bp->phys_blk = f->phys_curr;
+ bp->phys_pdata = (char *)(f->wt.ptr) + 1;
+ if (f->compress_state->template->reinit != 0)
+ (*f->compress_state->template->reinit)(f->compress_state);
+ compressed_size = 0;
+
+ start_ptr = f->wt.ptr;
+ status = (*f->compress_state->template->process)(f->compress_state,
+ &(f->rd), &(f->wt), true);
+ bp->phys_blk->data_limit = (char *)(f->wt.ptr);
+
+ if (status == 1) { /* More output space needed (see strimpl.h) */
+ /* allocate another physical block, then compress remainder */
+ compressed_size = f->wt.limit - start_ptr;
+ newphys =
+ allocateWithReserve(f, sizeof(*newphys), &code, "memfile newphys",
+ "compress_log_blk : MALLOC for 'newphys' failed\n");
+ if (code < 0)
+ return code;
+ ecode |= code; /* accumulate any low-memory warnings */
+ newphys->link = NULL;
+ bp->phys_blk->link = newphys;
+ f->phys_curr = newphys;
+ f->wt.ptr = (byte *) (newphys->data) - 1;
+ f->wt.limit = f->wt.ptr + MEMFILE_DATA_SIZE;
+
+ start_ptr = f->wt.ptr;
+ status =
+ (*f->compress_state->template->process)(f->compress_state,
+ &(f->rd), &(f->wt), true);
+ if (status != 0) {
+ /*
+ * You'd think the above line is a bug, but in real life 1 src
+ * block never ends up getting split across 3 dest blocks.
+ */
+ /* CHANGE memfile_set_memory_warning if this assumption changes. */
+ eprintf("Compression required more than one full block!\n");
+ return_error(gs_error_Fatal);
+ }
+ newphys->data_limit = (char *)(f->wt.ptr);
+ }
+ compressed_size += f->wt.ptr - start_ptr;
+ if (compressed_size > MEMFILE_DATA_SIZE) {
+ eprintf2("\nCompression didn't - raw=%d, compressed=%ld\n",
+ MEMFILE_DATA_SIZE, compressed_size);
+ }
+#ifdef DEBUG
+ tot_compressed += compressed_size;
+#endif
+ return (status < 0 ? gs_note_error(gs_error_ioerror) : ecode);
+} /* end "compress_log_blk()" */
+
+/* Internal (private) routine to handle end of logical block */
+private int /* ret 0 ok, -ve error, or +ve low-memory warning */
+memfile_next_blk(MEMFILE * f)
+{
+ LOG_MEMFILE_BLK *bp = f->log_curr_blk;
+ LOG_MEMFILE_BLK *newbp;
+ PHYS_MEMFILE_BLK *newphys, *oldphys;
+ int ecode = 0; /* accumulate low-memory warnings */
+ int code;
+
+ if (f->phys_curr == NULL) { /* means NOT compressing */
+ /* allocate a new block */
+ newphys =
+ allocateWithReserve(f, sizeof(*newphys), &code, "memfile newphys",
+ "memfile_next_blk: MALLOC 1 for 'newphys' failed\n");
+ if (code < 0)
+ return code;
+ ecode |= code; /* accumulate low-mem warnings */
+ newphys->link = NULL;
+ newphys->data_limit = NULL; /* raw */
+
+ newbp =
+ allocateWithReserve(f, sizeof(*newbp), &code, "memfile newbp",
+ "memfile_next_blk: MALLOC 1 for 'newbp' failed\n");
+ if (code < 0) {
+ FREE(f, newphys, "memfile newphys");
+ return code;
+ }
+ ecode |= code; /* accumulate low-mem warnings */
+ bp->link = newbp;
+ newbp->link = NULL;
+ newbp->raw_block = NULL;
+ f->log_curr_blk = newbp;
+
+#ifdef HAVE_LIBZ
+ /* check if need to start compressing */
+ if (NEED_TO_COMPRESS(f)) {
+ if_debug0(':', "[:]Beginning compression\n");
+ /* compress the entire file up to this point */
+ if (!f->compressor_initialized) {
+ int code = 0;
+
+ if (f->compress_state->template->init != 0)
+ code = (*f->compress_state->template->init) (f->compress_state);
+ if (code < 0)
+ return_error(gs_error_VMerror); /****** BOGUS ******/
+ if (f->decompress_state->template->init != 0)
+ code = (*f->decompress_state->template->init)
+ (f->decompress_state);
+ if (code < 0)
+ return_error(gs_error_VMerror); /****** BOGUS ******/
+ f->compressor_initialized = true;
+ }
+ /* Write into the new physical block we just allocated, */
+ /* replace it after the loop (after some blocks are freed) */
+ f->phys_curr = newphys;
+ f->wt.ptr = (byte *) (newphys->data) - 1;
+ f->wt.limit = f->wt.ptr + MEMFILE_DATA_SIZE;
+ bp = f->log_head;
+ while (bp != newbp) { /* don't compress last block */
+ int code;
+
+ oldphys = bp->phys_blk;
+ if ((code = compress_log_blk(f, bp)) < 0)
+ return code;
+ ecode |= code;
+ FREE(f, oldphys, "memfile_next_blk(oldphys)");
+ bp = bp->link;
+ } /* end while( ) compress loop */
+ /* Allocate a physical block for this (last) logical block */
+ newphys =
+ allocateWithReserve(f, sizeof(*newphys), &code,
+ "memfile newphys",
+ "memfile_next_blk: MALLOC 2 for 'newphys' failed\n");
+ if (code < 0)
+ return code;
+ ecode |= code; /* accumulate low-mem warnings */
+ newphys->link = NULL;
+ newphys->data_limit = NULL; /* raw */
+
+ } /* end convert file to compressed */
+#endif /* HAVE_LIBZ */
+ newbp->phys_blk = newphys;
+ f->pdata = newphys->data;
+ f->pdata_end = newphys->data + MEMFILE_DATA_SIZE;
+ } /* end if NOT compressing */
+#ifdef HAVE_LIBZ
+ /* File IS being compressed */
+ else {
+ int code;
+
+ oldphys = bp->phys_blk; /* save raw phys block ID */
+ /* compresses bp on phys list */
+ if ((code = compress_log_blk(f, bp)) < 0)
+ return code;
+ ecode |= code;
+ newbp =
+ allocateWithReserve(f, sizeof(*newbp), &code, "memfile newbp",
+ "memfile_next_blk: MALLOC 2 for 'newbp' failed\n");
+ if (code < 0)
+ return code;
+ ecode |= code;
+ bp->link = newbp;
+ newbp->link = NULL;
+ newbp->raw_block = NULL;
+ /* Re-use the raw phys block for this new logical blk */
+ newbp->phys_blk = oldphys;
+ f->pdata = oldphys->data;
+ f->pdata_end = f->pdata + MEMFILE_DATA_SIZE;
+ f->log_curr_blk = newbp;
+ } /* end else (when we are compressing) */
+#endif /* HAVE_LIBZ */
+
+ return (ecode);
+}
+
+int /* returns # of chars actually written */
+memfile_fwrite_chars(const void *data, uint len, clist_file_ptr cf)
+{
+ const char *str = (const char *)data;
+ MEMFILE *f = (MEMFILE *) cf;
+ uint count = len;
+ int ecode;
+
+ /* check if we are writing to the start of the file. If so, then */
+ /* free the file memory and re-initialize it (frees memory) */
+ if (f->log_curr_pos == 0) {
+ int code;
+
+ memfile_free_mem(f);
+ if ((code = memfile_init_empty(f)) < 0) {
+ f->error_code = code;
+ return 0;
+ }
+ }
+ if (f->log_curr_blk->link != 0) {
+ eprintf(" Write file truncate -- need to free physical blocks.\n");
+ }
+ while (count) {
+ uint move_count = f->pdata_end - f->pdata;
+
+ if (move_count == 0) {
+ if ((ecode = memfile_next_blk(f)) != 0) {
+ f->error_code = ecode;
+ if (ecode < 0)
+ return 0;
+ }
+ } else {
+ if (move_count > count)
+ move_count = count;
+ memmove(f->pdata, str, move_count);
+ f->pdata += move_count;
+ str += move_count;
+ count -= move_count;
+ }
+ }
+ f->log_curr_pos += len;
+ f->log_length = f->log_curr_pos; /* truncate length to here */
+#ifdef DEBUG
+ tot_raw += len;
+#endif
+ return (len);
+}
+
+/* */
+/* Internal routine to set the f->pdata and f->pdata_end pointers */
+/* for the current logical block f->log_curr_blk */
+/* */
+/* If data only exists in compressed form, allocate a raw buffer */
+/* and decompress it. */
+/* */
+
+private int
+memfile_get_pdata(MEMFILE * f)
+{
+ int i, num_raw_buffers, status;
+ LOG_MEMFILE_BLK *bp = f->log_curr_blk;
+
+ if (bp->phys_blk->data_limit == NULL) {
+ /* Not compressed, return this data pointer */
+ f->pdata = (bp->phys_blk)->data;
+ i = f->log_curr_pos % MEMFILE_DATA_SIZE; /* pos within block */
+ i = f->log_curr_pos - i; /* base of block */
+ if (i + MEMFILE_DATA_SIZE > f->log_length)
+ f->pdata_end = f->pdata + f->log_length - i;
+ else
+ f->pdata_end = f->pdata + MEMFILE_DATA_SIZE;
+ }
+#ifdef HAVE_LIBZ
+ else {
+ /* data was compressed */
+ if (f->raw_head == NULL) {
+ /* need to allocate the raw buffer pool */
+ num_raw_buffers = GET_NUM_RAW_BUFFERS(f);
+ if (f->reservePhysBlockCount) {
+ /* HACK: allocate reserve block that's been reserved for
+ * decompression. This buffer's block was pre-allocated to make
+ * sure we won't come up short here. Take from chain instead of
+ * allocateWithReserve() since this buf would just be wasted if
+ * allowed to remain preallocated. */
+ f->raw_head = (RAW_BUFFER *)f->reservePhysBlockChain;
+ f->reservePhysBlockChain = f->reservePhysBlockChain->link;
+ --f->reservePhysBlockCount;
+ } else {
+ int code;
+
+ f->raw_head =
+ allocateWithReserve(f, sizeof(*f->raw_head), &code,
+ "memfile raw buffer",
+ "memfile_get_pdata: MALLOC for 'raw_head' failed\n");
+ if (code < 0)
+ return code;
+ }
+ f->raw_head->back = NULL;
+ f->raw_tail = f->raw_head;
+ f->raw_tail->log_blk = NULL;
+ for (i = 0; i < num_raw_buffers; i++) {
+ f->raw_tail->fwd = (RAW_BUFFER *) MALLOC(f, sizeof(RAW_BUFFER),
+ "memfile raw buffer");
+ /* if MALLOC fails, then just stop allocating */
+ if (!f->raw_tail->fwd)
+ break;
+ f->total_space += sizeof(RAW_BUFFER);
+ f->raw_tail->fwd->back = f->raw_tail;
+ f->raw_tail = f->raw_tail->fwd;
+ f->raw_tail->log_blk = NULL;
+ }
+ f->raw_tail->fwd = NULL;
+ num_raw_buffers = i + 1; /* if MALLOC failed, then OK */
+ if_debug1(':', "[:]Number of raw buffers allocated=%d\n",
+ num_raw_buffers);
+ } /* end allocating the raw buffer pool (first time only) */
+ if (bp->raw_block == NULL) {
+#ifdef DEBUG
+ tot_cache_miss++; /* count every decompress */
+#endif
+ /* find a raw buffer and decompress */
+ if (f->raw_tail->log_blk != NULL) {
+ /* This block was in use, grab it */
+#ifdef DEBUG
+ tot_swap_out++;
+#endif
+ f->raw_tail->log_blk->raw_block = NULL; /* data no longer here */
+ f->raw_tail->log_blk = NULL;
+ }
+ /* Use the last raw block in the chain (the oldest) */
+ f->raw_tail->back->fwd = NULL; /* disconnect from tail */
+ f->raw_tail->fwd = f->raw_head; /* new head */
+ f->raw_head->back = f->raw_tail;
+ f->raw_tail = f->raw_tail->back;
+ f->raw_head = f->raw_head->back;
+ f->raw_head->back = NULL;
+ f->raw_head->log_blk = bp;
+
+ /* Decompress the data into this raw block */
+ /* Initialize the decompressor */
+ if (f->decompress_state->template->reinit != 0)
+ (*f->decompress_state->template->reinit) (f->decompress_state);
+ /* Set pointers and call the decompress routine */
+ f->wt.ptr = (byte *) (f->raw_head->data) - 1;
+ f->wt.limit = f->wt.ptr + MEMFILE_DATA_SIZE;
+ f->rd.ptr = (const byte *)(bp->phys_pdata) - 1;
+ f->rd.limit = (const byte *)bp->phys_blk->data_limit;
+#ifdef DEBUG
+ decomp_wt_ptr0 = f->wt.ptr;
+ decomp_wt_limit0 = f->wt.limit;
+ decomp_rd_ptr0 = f->rd.ptr;
+ decomp_rd_limit0 = f->rd.limit;
+#endif
+ status = (*f->decompress_state->template->process)
+ (f->decompress_state, &(f->rd), &(f->wt), true);
+ if (status == 0) { /* More input data needed */
+ /* switch to next block and continue decompress */
+ int back_up = 0; /* adjust pointer backwards */
+
+ if (f->rd.ptr != f->rd.limit) {
+ /* transfer remainder bytes from the previous block */
+ back_up = f->rd.limit - f->rd.ptr;
+ for (i = 0; i < back_up; i++)
+ *(bp->phys_blk->link->data - back_up + i) = *++f->rd.ptr;
+ }
+ f->rd.ptr = (const byte *)bp->phys_blk->link->data - back_up - 1;
+ f->rd.limit = (const byte *)bp->phys_blk->link->data_limit;
+#ifdef DEBUG
+ decomp_wt_ptr1 = f->wt.ptr;
+ decomp_wt_limit1 = f->wt.limit;
+ decomp_rd_ptr1 = f->rd.ptr;
+ decomp_rd_limit1 = f->rd.limit;
+#endif
+ status = (*f->decompress_state->template->process)
+ (f->decompress_state, &(f->rd), &(f->wt), true);
+ if (status == 0) {
+ eprintf("Decompression required more than one full block!\n");
+ return_error(gs_error_Fatal);
+ }
+ }
+ bp->raw_block = f->raw_head; /* point to raw block */
+ }
+ /* end if( raw_block == NULL ) meaning need to decompress data */
+ else {
+ /* data exists in the raw data cache, if not raw_head, move it */
+ if (bp->raw_block != f->raw_head) {
+ /* move to raw_head */
+ /* prev.fwd = this.fwd */
+ bp->raw_block->back->fwd = bp->raw_block->fwd;
+ if (bp->raw_block->fwd != NULL)
+ /* next.back = this.back */
+ bp->raw_block->fwd->back = bp->raw_block->back;
+ else
+ f->raw_tail = bp->raw_block->back; /* tail = prev */
+ f->raw_head->back = bp->raw_block; /* head.back = this */
+ bp->raw_block->fwd = f->raw_head; /* this.fwd = orig head */
+ f->raw_head = bp->raw_block; /* head = this */
+ f->raw_head->back = NULL; /* this.back = NULL */
+#ifdef DEBUG
+ tot_cache_hits++; /* counting here prevents repeats since */
+ /* won't count if already at head */
+#endif
+ }
+ }
+ f->pdata = bp->raw_block->data;
+ f->pdata_end = f->pdata + MEMFILE_DATA_SIZE;
+ /* NOTE: last block is never compressed, so a compressed block */
+ /* is always full size. */
+ } /* end else (when data was compressed) */
+#endif /* HAVE_LIBZ */
+
+ return (0);
+}
+
+/* ---------------- Reading ---------------- */
+
+int
+memfile_fread_chars(void *data, uint len, clist_file_ptr cf)
+{
+ char *str = (char *)data;
+ MEMFILE *f = (MEMFILE *) cf;
+ uint count = len, num_read, move_count;
+
+ num_read = f->log_length - f->log_curr_pos;
+ if (count > num_read)
+ count = num_read;
+ num_read = count;
+
+ while (count) {
+ f->log_curr_pos++; /* move into next byte */
+ if (f->pdata == f->pdata_end) {
+ f->log_curr_blk = (f->log_curr_blk)->link;
+ memfile_get_pdata(f);
+ }
+ move_count = f->pdata_end - f->pdata;
+ if (move_count > count)
+ move_count = count;
+ f->log_curr_pos += move_count - 1; /* new position */
+ memmove(str, f->pdata, move_count);
+ str += move_count;
+ f->pdata += move_count;
+ count -= move_count;
+ }
+
+ return (num_read);
+}
+
+/* ---------------- Position/status ---------------- */
+
+int
+memfile_ferror_code(clist_file_ptr cf)
+{
+ return (((MEMFILE *) cf)->error_code); /* errors stored here */
+}
+
+long
+memfile_ftell(clist_file_ptr cf)
+{
+ return (((MEMFILE *) cf)->log_curr_pos);
+}
+
+void
+memfile_rewind(clist_file_ptr cf, bool discard_data, const char *ignore_fname)
+{
+ MEMFILE *f = (MEMFILE *) cf;
+
+ if (discard_data) {
+ memfile_free_mem(f);
+ /* We have to call memfile_init_empty to preserve invariants. */
+ memfile_init_empty(f);
+ } else {
+ f->log_curr_blk = f->log_head;
+ f->log_curr_pos = 0;
+ memfile_get_pdata(f);
+ }
+}
+
+int
+memfile_fseek(clist_file_ptr cf, long offset, int mode, const char *ignore_fname)
+{
+ MEMFILE *f = (MEMFILE *) cf;
+ long i, block_num, new_pos;
+
+ switch (mode) {
+ case SEEK_SET: /* offset from the beginning of the file */
+ new_pos = offset;
+ break;
+
+ case SEEK_CUR: /* offset from the current position in the file */
+ new_pos = offset + f->log_curr_pos;
+ break;
+
+ case SEEK_END: /* offset back from the end of the file */
+ new_pos = f->log_length - offset;
+ break;
+
+ default:
+ return (-1);
+ }
+ if (new_pos < 0 || new_pos > f->log_length)
+ return -1;
+ if ((f->pdata == f->pdata_end) && (f->log_curr_blk->link != NULL)) {
+ /* log_curr_blk is actually one block behind log_curr_pos */
+ f->log_curr_blk = f->log_curr_blk->link;
+ }
+ block_num = new_pos / MEMFILE_DATA_SIZE;
+ i = f->log_curr_pos / MEMFILE_DATA_SIZE;
+ if (block_num < i) { /* if moving backwards, start at beginning */
+ f->log_curr_blk = f->log_head;
+ i = 0;
+ }
+ for (; i < block_num; i++) {
+ f->log_curr_blk = f->log_curr_blk->link;
+ }
+ f->log_curr_pos = new_pos;
+ memfile_get_pdata(f); /* pointers to start of block */
+ f->pdata += new_pos - (block_num * MEMFILE_DATA_SIZE);
+
+ return 0; /* return "normal" status */
+}
+
+/* ---------------- Internal routines ---------------- */
+
+private void
+memfile_free_mem(MEMFILE * f)
+{
+ LOG_MEMFILE_BLK *bp, *tmpbp;
+
+#ifdef DEBUG
+ /* output some diagnostics about the effectiveness */
+ if (tot_raw > 100) {
+ if_debug2(':', "[:]tot_raw=%ld, tot_compressed=%ld\n",
+ tot_raw, tot_compressed);
+ }
+ if (tot_cache_hits != 0) {
+ if_debug3(':', "[:]Cache hits=%ld, cache misses=%ld, swapouts=%ld\n",
+ tot_cache_hits,
+ tot_cache_miss - (f->log_length / MEMFILE_DATA_SIZE),
+ tot_swap_out);
+ }
+ tot_raw = 0;
+ tot_compressed = 0;
+ tot_cache_hits = 0;
+ tot_cache_miss = 0;
+ tot_swap_out = 0;
+#endif
+
+ /* Free up memory that was allocated for the memfile */
+ bp = f->log_head;
+
+/******************************************************************
+ * The following was the original algorithm here. This algorithm has a bug:
+ * the second loop references the physical blocks again after they have been
+ * freed.
+ ******************************************************************/
+
+#if 0 /**************** *************** */
+
+ if (bp != NULL) {
+ /* Free the physical blocks that make up the compressed data */
+ PHYS_MEMFILE_BLK *pphys = (f->log_head)->phys_blk;
+
+ if (pphys->data_limit != NULL) {
+ /* the data was compressed, free the chain of blocks */
+ while (pphys != NULL) {
+ PHYS_MEMFILE_BLK *tmpphys = pphys->link;
+
+ FREE(f, pphys, "memfile_free_mem(pphys)");
+ pphys = tmpphys;
+ }
+ }
+ }
+ /* free the logical blocks */
+ while (bp != NULL) {
+ /* if this logical block was not compressed, free the phys_blk */
+ if (bp->phys_blk->data_limit == NULL) {
+ FREE(f, bp->phys_blk, "memfile_free_mem(phys_blk)");
+ }
+ tmpbp = bp->link;
+ FREE(f, bp, "memfile_free_mem(log_blk)");
+ bp = tmpbp;
+ }
+
+#else /**************** *************** */
+# if 1 /**************** *************** */
+
+/****************************************************************
+ * This algorithm is correct (we think).
+ ****************************************************************/
+
+ if (bp != NULL) {
+ /* Null out phys_blk pointers to compressed data. */
+ PHYS_MEMFILE_BLK *pphys = bp->phys_blk;
+
+ {
+ for (tmpbp = bp; tmpbp != NULL; tmpbp = tmpbp->link)
+ if (tmpbp->phys_blk->data_limit != NULL)
+ tmpbp->phys_blk = 0;
+ }
+ /* Free the physical blocks that make up the compressed data */
+ if (pphys->data_limit != NULL) {
+ /* the data was compressed, free the chain of blocks */
+ while (pphys != NULL) {
+ PHYS_MEMFILE_BLK *tmpphys = pphys->link;
+
+ FREE(f, pphys, "memfile_free_mem(pphys)");
+ pphys = tmpphys;
+ }
+ }
+ }
+ /* Now free the logical blocks, and any uncompressed physical blocks. */
+ while (bp != NULL) {
+ if (bp->phys_blk != NULL) {
+ FREE(f, bp->phys_blk, "memfile_free_mem(phys_blk)");
+ }
+ tmpbp = bp->link;
+ FREE(f, bp, "memfile_free_mem(log_blk)");
+ bp = tmpbp;
+ }
+
+/***********************************************************************
+ * This algorithm appears to be both simpler and free of the bug that
+ * occasionally causes the older one to reference freed blocks; but in
+ * fact it can miss blocks, because the very last compressed logical block
+ * can have spill into a second physical block, which is not referenced by
+ * any logical block.
+ ***********************************************************************/
+
+# else /**************** *************** */
+
+ {
+ PHYS_MEMFILE_BLK *prev_phys = 0;
+
+ while (bp != NULL) {
+ PHYS_MEMFILE_BLK *phys = bp->phys_blk;
+
+ if (phys != prev_phys) {
+ FREE(f, phys, "memfile_free_mem(phys_blk)");
+ prev_phys = phys;
+ }
+ tmpbp = bp->link;
+ FREE(f, bp, "memfile_free_mem(log_blk)");
+ bp = tmpbp;
+ }
+ }
+
+# endif /**************** *************** */
+#endif /**************** *************** */
+
+ f->log_head = NULL;
+
+#ifdef HAVE_LIBZ
+ /* Free any internal compressor state. */
+ if (f->compressor_initialized) {
+ if (f->decompress_state->template->release != 0)
+ (*f->decompress_state->template->release) (f->decompress_state);
+ if (f->compress_state->template->release != 0)
+ (*f->compress_state->template->release) (f->compress_state);
+ f->compressor_initialized = false;
+ }
+#endif /* HAVE_LIBZ */
+
+ /* free the raw buffers */
+ while (f->raw_head != NULL) {
+ RAW_BUFFER *tmpraw = f->raw_head->fwd;
+
+ FREE(f, f->raw_head, "memfile_free_mem(raw)");
+ f->raw_head = tmpraw;
+ }
+}
+
+private int
+memfile_init_empty(MEMFILE * f)
+{
+ PHYS_MEMFILE_BLK *pphys;
+ LOG_MEMFILE_BLK *plog;
+
+ /* Zero out key fields so that allocation failure will be unwindable */
+ f->phys_curr = NULL; /* flag as file not compressed */
+ f->log_head = NULL;
+ f->log_curr_blk = NULL;
+ f->log_curr_pos = 0;
+ f->log_length = 0;
+ f->raw_head = NULL;
+ f->compressor_initialized = false;
+ f->total_space = 0;
+
+ /* File empty - get a physical mem block (includes the buffer area) */
+ pphys = MALLOC(f, sizeof(*pphys), "memfile pphys");
+ if (!pphys) {
+ eprintf("memfile_init_empty: MALLOC for 'pphys' failed\n");
+ return_error(gs_error_VMerror);
+ }
+ f->total_space += sizeof(*pphys);
+ pphys->data_limit = NULL; /* raw data for now */
+
+ /* Get logical mem block to go with physical one */
+ plog = (LOG_MEMFILE_BLK *)MALLOC( f, sizeof(*plog), "memfile_init_empty" );
+ if (plog == NULL) {
+ FREE(f, pphys, "memfile_init_empty");
+ eprintf("memfile_init_empty: MALLOC for log_curr_blk failed\n");
+ return_error(gs_error_VMerror);
+ }
+ f->total_space += sizeof(*plog);
+ f->log_head = f->log_curr_blk = plog;
+ f->log_curr_blk->link = NULL;
+ f->log_curr_blk->phys_blk = pphys;
+ f->log_curr_blk->phys_pdata = NULL;
+ f->log_curr_blk->raw_block = NULL;
+
+ f->pdata = pphys->data;
+ f->pdata_end = f->pdata + MEMFILE_DATA_SIZE;
+
+ f->error_code = 0;
+
+ return 0;
+}
diff --git a/pstoraster/gxclmem.h b/pstoraster/gxclmem.h
new file mode 100644
index 000000000..88b125991
--- /dev/null
+++ b/pstoraster/gxclmem.h
@@ -0,0 +1,155 @@
+/* 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$ */
+/* Definitions and declarations for clist implementation in memory. */
+
+#ifndef gxclmem_INCLUDED
+# define gxclmem_INCLUDED
+
+#include "gxclio.h" /* defines interface */
+#include "strimpl.h" /* stream structures */
+
+/*
+ * The best values of MEMFILE_DATA_SIZE are slightly less than a power of 2,
+ * to allow typical malloc implementations to allocate in units of a power
+ * of 2 rather than having to go slightly over.
+ */
+#define MEMFILE_DATA_SIZE (16384 - 160)
+
+ /* ============================================================ */
+ /* */
+ /* Memfile structure definitions. */
+ /* */
+ /* The PHYS structures are the elements actually allocated in */
+ /* RAM, containing the compressed data (or optionally raw data) */
+ /* */
+ /* There can be several LOG (logical) elements per physical */
+ /* element, depending on the compression. The MEMFILE pdata */
+ /* item always points into a raw block of data. */
+ /* */
+ /* ============================================================ */
+
+typedef struct RAW_BUFFER {
+ struct RAW_BUFFER *fwd, *back;
+ struct LOG_MEMFILE_BLK *log_blk;
+ char data[MEMFILE_DATA_SIZE];
+} RAW_BUFFER;
+
+typedef struct PHYS_MEMFILE_BLK {
+ struct PHYS_MEMFILE_BLK *link;
+ char *data_limit; /* end of data when compressed */
+ /* NULL if not compressed */
+ char data_spare[4]; /* used during de-compress */
+ char data[MEMFILE_DATA_SIZE];
+} PHYS_MEMFILE_BLK;
+
+typedef struct LOG_MEMFILE_BLK {
+ struct LOG_MEMFILE_BLK *link;
+ PHYS_MEMFILE_BLK *phys_blk;
+ char *phys_pdata;
+ RAW_BUFFER *raw_block; /* or NULL */
+} LOG_MEMFILE_BLK;
+
+typedef struct MEMFILE {
+ gs_memory_t *memory; /* storage allocator */
+ gs_memory_t *data_memory; /* storage allocator for data */
+ bool ok_to_compress; /* if true, OK to compress this file */
+ /*
+ * Reserve memory blocks: these are used to guarantee that a
+ * given-sized write (or sequence of writes) will always succeed.
+ * More specifically, the guarantee is that N bytes can successfully
+ * be written after a low-memory warning is first returned by
+ * fwrite. The reserve of N bytes for a given file is (re)allocated
+ * by a successful call to memfile_set_memory_warning(N). Fwrite
+ * allocates memory only from the reserve when its normal allocation
+ * attempts fail; in such cases, it allocates blocks from the
+ * reserve pool as needed and completes normally, but returns a
+ * low-memory warning status. Once a low-memory warning has been
+ * returned, fwrite will continue to attempt to allocate memory from
+ * the usual allocator on subsequent fwrites, but does *not* try to
+ * "top up" the reserve if becomes available -- only an explicit
+ * memfile_set_memory_warning does so.
+ */
+ PHYS_MEMFILE_BLK *reservePhysBlockChain; /* chain of reserve phys blks */
+ int reservePhysBlockCount; /* count of entries on reservePhysBlockChain */
+ LOG_MEMFILE_BLK *reserveLogBlockChain; /* chain of reserve log blks */
+ int reserveLogBlockCount; /* count of entries on reserveLogBlockChain */
+ /* logical file properties */
+ LOG_MEMFILE_BLK *log_head;
+ LOG_MEMFILE_BLK *log_curr_blk;
+ long log_length; /* updated during write */
+ long log_curr_pos; /* updated during seek, close, read */
+ char *pdata; /* raw data */
+ char *pdata_end;
+ /* physical file properties */
+ long total_space; /* so we know when to start compress */
+ PHYS_MEMFILE_BLK *phys_curr; /* NULL if not compressing */
+ RAW_BUFFER *raw_head, *raw_tail;
+ int error_code; /* used by CLIST_ferror */
+ stream_cursor_read rd; /* use .ptr, .limit */
+ stream_cursor_write wt; /* use .ptr, .limit */
+ bool compressor_initialized;
+ stream_state *compress_state;
+ stream_state *decompress_state;
+} MEMFILE;
+
+/*
+ * Only the MEMFILE and stream_state structures are GC-compatible, so we
+ * allocate all the other structures on the C heap.
+ */
+
+#define private_st_MEMFILE() /* in gxclmem.c */\
+ gs_private_st_ptrs2(st_MEMFILE, MEMFILE, "MEMFILE",\
+ MEMFILE_enum_ptrs, MEMFILE_reloc_ptrs, compress_state, decompress_state)
+
+/* Make the memfile_... operations aliases for the clist_... operations. */
+
+#define memfile_fopen(fname, fmode, pcf, mem, data_mem, compress)\
+ clist_fopen(fname, fmode, pcf, mem, data_mem, compress)
+#define memfile_fclose(cf, fname, delete)\
+ clist_fclose(cf, fname, delete)
+#define memfile_unlink(fname)\
+ clist_unlink(fname)
+
+#define memfile_space_available(req)\
+ clist_space_available(req)
+#define memfile_fwrite_chars(data, len, cf)\
+ clist_fwrite_chars(data, len, cf)
+
+#define memfile_fread_chars(data, len, cf)\
+ clist_fread_chars(data, len, cf)
+
+#define memfile_set_memory_warning(cf, nbytes) clist_set_memory_warning(cf, nbytes)
+#define memfile_ferror_code(cf) clist_ferror_code(cf)
+#define memfile_ftell(cf) clist_ftell(cf)
+#define memfile_rewind(cf, discard, fname) clist_rewind(cf, discard, fname)
+#define memfile_fseek(cf, offset, mode, fname) clist_fseek(cf, offset, mode, fname)
+
+/* Declare the procedures for returning the prototype filter states */
+/* for compressing and decompressing the band list. */
+const stream_state *clist_compressor_state(P1(void *));
+const stream_state *clist_decompressor_state(P1(void *));
+
+#endif /* gxclmem_INCLUDED */
diff --git a/pstoraster/gxclpage.c b/pstoraster/gxclpage.c
new file mode 100644
index 000000000..bcf242c58
--- /dev/null
+++ b/pstoraster/gxclpage.c
@@ -0,0 +1,127 @@
+/* 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$ */
+/* Page object management */
+#include "gdevprn.h"
+#include "gxcldev.h"
+#include "gxclpage.h"
+
+/* Save a page. */
+int
+gdev_prn_save_page(gx_device_printer * pdev, gx_saved_page * page,
+ int num_copies)
+{
+ /* Make sure we are banding. */
+ if (!pdev->buffer_space)
+ return_error(gs_error_rangecheck);
+ if (strlen(pdev->dname) >= sizeof(page->dname))
+ return_error(gs_error_limitcheck);
+ {
+ gx_device_clist_writer * const pcldev =
+ (gx_device_clist_writer *)pdev;
+ int code;
+
+ if ((code = clist_end_page(pcldev)) < 0 ||
+ (code = clist_fclose(pcldev->page_cfile, pcldev->page_cfname, false)) < 0 ||
+ (code = clist_fclose(pcldev->page_bfile, pcldev->page_bfname, false)) < 0
+ )
+ return code;
+ /* Save the device information. */
+ memcpy(&page->device, pdev, sizeof(gx_device));
+ strcpy(page->dname, pdev->dname);
+ /* Save the page information. */
+ page->info = pcldev->page_info;
+ page->info.cfile = 0;
+ page->info.bfile = 0;
+ }
+ /* Save other information. */
+ page->num_copies = num_copies;
+ return (*gs_clist_device_procs.open_device) ((gx_device *) pdev);
+}
+
+/* Render an array of saved pages. */
+int
+gdev_prn_render_pages(gx_device_printer * pdev,
+ const gx_placed_page * ppages, int count)
+{
+ gx_device_clist_reader * const pcldev =
+ (gx_device_clist_reader *)pdev;
+
+ /* Check to make sure the pages are compatible with the device. */
+ {
+ int i;
+ gx_band_params params;
+
+ for (i = 0; i < count; ++i) {
+ const gx_saved_page *page = ppages[i].page;
+
+ /* We would like to fully check the color representation, */
+ /* but we don't have enough information to do that. */
+ if (strcmp(page->dname, pdev->dname) != 0 ||
+ memcmp(&page->device.color_info, &pdev->color_info,
+ sizeof(pdev->color_info)) != 0
+ )
+ return_error(gs_error_rangecheck);
+ /* Currently we don't allow translation in Y. */
+ if (ppages[i].offset.y != 0)
+ return_error(gs_error_rangecheck);
+ /* Make sure the band parameters are compatible. */
+ if (page->info.band_params.BandBufferSpace !=
+ pdev->buffer_space ||
+ page->info.band_params.BandWidth !=
+ pdev->width
+ )
+ return_error(gs_error_rangecheck);
+ /* Currently we require all band heights to be the same. */
+ if (i == 0)
+ params = page->info.band_params;
+ else if (page->info.band_params.BandHeight !=
+ params.BandHeight
+ )
+ return_error(gs_error_rangecheck);
+ }
+ }
+ /* Set up the page list in the device. */
+ /****** SHOULD FACTOR THIS OUT OF clist_render_init ******/
+ pcldev->ymin = pcldev->ymax = 0;
+ pcldev->pages = ppages;
+ pcldev->num_pages = count;
+ /* Render the pages. */
+ {
+ int code = (*dev_proc(pdev, output_page))
+ ((gx_device *) pdev, ppages[0].page->num_copies, true);
+
+ /* Delete the temporary files. */
+ int i;
+
+ for (i = 0; i < count; ++i) {
+ const gx_saved_page *page = ppages[i].page;
+
+ clist_unlink(page->info.cfname);
+ clist_unlink(page->info.bfname);
+ }
+ return code;
+ }
+}
diff --git a/pstoraster/gxclpage.h b/pstoraster/gxclpage.h
new file mode 100644
index 000000000..f54aaf734
--- /dev/null
+++ b/pstoraster/gxclpage.h
@@ -0,0 +1,63 @@
+/* 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$ */
+/* Requires gdevprn.h, gxclist.h */
+
+#ifndef gxclpage_INCLUDED
+# define gxclpage_INCLUDED
+
+#include "gxclio.h"
+
+/* ---------------- Procedures ---------------- */
+
+/*
+ * Package up the current page in a banding device as a page object.
+ * The client must provide storage for the page object.
+ * The client may retain the object in memory, or may write it on a file
+ * for later retrieval; in the latter case, the client should free the
+ * in-memory structure.
+ */
+int gdev_prn_save_page(P3(gx_device_printer * pdev, gx_saved_page * page,
+ int num_copies));
+
+/*
+ * Render an array of saved pages by setting up a modified get_bits
+ * procedure and then calling the device's normal output_page procedure.
+ * Any current page in the device's buffers is lost.
+ * The (0,0) point of each saved page is translated to the corresponding
+ * specified offset on the combined page. (Currently the Y offset must be 0.)
+ * The client is responsible for freeing the saved and placed pages.
+ *
+ * Note that the device instance for rendering need not be, and normally is
+ * not, the same as the device from which the pages were saved, but it must
+ * be an instance of the same device. The client is responsible for
+ * ensuring that the rendering device's buffer size (BufferSpace value) is
+ * the same as the BandBufferSpace value of all the saved pages, and that
+ * the device width is the same as the BandWidth value of the saved pages.
+ */
+int gdev_prn_render_pages(P3(gx_device_printer * pdev,
+ const gx_placed_page * ppages, int count));
+
+#endif /* gxclpage_INCLUDED */
diff --git a/pstoraster/gxclpath.c b/pstoraster/gxclpath.c
new file mode 100644
index 000000000..fed4478a7
--- /dev/null
+++ b/pstoraster/gxclpath.c
@@ -0,0 +1,1198 @@
+/* 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$ */
+/* Higher-level path operations for band lists */
+#include "math_.h"
+#include "memory_.h"
+#include "gx.h"
+#include "gpcheck.h"
+#include "gserrors.h"
+#include "gxdevice.h"
+#include "gxdevmem.h" /* must precede gxcldev.h */
+#include "gxcldev.h"
+#include "gxclpath.h"
+#include "gxcolor2.h"
+#include "gxpaint.h" /* for gx_fill/stroke_params */
+#include "gzpath.h"
+#include "gzcpath.h"
+
+/* Statistics */
+#ifdef DEBUG
+ulong stats_cmd_diffs[5];
+#endif
+
+/* Forward declarations */
+private int cmd_put_path(P8(gx_device_clist_writer * cldev,
+ gx_clist_state * pcls, const gx_path * ppath, fixed ymin, fixed ymax, byte op,
+ bool implicit_close, segment_notes keep_notes));
+
+/* ------ Utilities ------ */
+
+/* Write out the color for filling, stroking, or masking. */
+/* We should be able to share this with clist_tile_rectangle, */
+/* but I don't see how to do it without adding a level of procedure. */
+int
+cmd_put_drawing_color(gx_device_clist_writer * cldev, gx_clist_state * pcls,
+ const gx_drawing_color * pdcolor)
+{
+ const gx_strip_bitmap *tile;
+ gx_color_index color0, color1;
+ ulong offset_temp;
+
+ if (gx_dc_is_pure(pdcolor)) {
+ gx_color_index color1 = gx_dc_pure_color(pdcolor);
+
+ if (color1 != pcls->colors[1]) {
+ int code = cmd_set_color1(cldev, pcls, color1);
+
+ if (code < 0)
+ return code;
+ }
+ return cmd_dc_type_pure;
+ }
+ /* Any non-pure color will require the phase. */
+ {
+ int px = pdcolor->phase.x, py = pdcolor->phase.y;
+
+ if (px != pcls->tile_phase.x || py != pcls->tile_phase.y) {
+ int code = cmd_set_tile_phase(cldev, pcls, px, py);
+
+ if (code < 0)
+ return code;
+ }
+ }
+ if (gx_dc_is_binary_halftone(pdcolor)) {
+ tile = gx_dc_binary_tile(pdcolor);
+ color0 = gx_dc_binary_color0(pdcolor);
+ color1 = gx_dc_binary_color1(pdcolor);
+ /* Set up tile and colors as for clist_tile_rectangle. */
+ if (!cls_has_tile_id(cldev, pcls, tile->id, offset_temp)) {
+ int depth =
+ (color1 == gx_no_color_index &&
+ color0 == gx_no_color_index ?
+ cldev->color_info.depth : 1);
+
+ if (tile->id == gx_no_bitmap_id ||
+ clist_change_tile(cldev, pcls, tile, depth) < 0
+ )
+ return_error(-1); /* can't cache tile */
+ }
+ if (color1 != pcls->tile_colors[1] ||
+ color0 != pcls->tile_colors[0]
+ ) {
+ int code = cmd_set_tile_colors(cldev, pcls, color0, color1);
+
+ if (code < 0)
+ return code;
+ }
+ return cmd_dc_type_ht;
+ } else if (gx_dc_is_colored_halftone(pdcolor)) {
+ const gx_device_halftone *pdht = pdcolor->colors.colored.c_ht;
+ int num_comp = pdht->num_comp;
+ byte buf[4 + 4 * cmd_max_intsize(sizeof(pdcolor->colors.colored.c_level[0]))];
+ byte *bp = buf;
+ int i;
+ uint short_bases = 0;
+ ulong bases = 0;
+ byte *dp;
+ int code;
+
+ /****** HOW TO TELL IF COLOR IS ALREADY SET? ******/
+ if (pdht->id != cldev->device_halftone_id) {
+ int code = cmd_put_halftone(cldev, pdht, pdht->type);
+
+ if (code < 0)
+ return code;
+ cldev->device_halftone_id = pdht->id;
+ }
+ for (i = 0; i < num_comp; ++i) {
+ uint base = pdcolor->colors.colored.c_base[i];
+
+ if (base > 31)
+ return_error(gs_error_rangecheck);
+ bases |= base << ((3 - i) * 5);
+ short_bases |= base << (3 - i);
+ }
+ if (bases & 0xf7bde) { /* Some base value requires more than 1 bit. */
+ *bp++ = 0x10 + (byte) (bases >> 16);
+ *bp++ = (byte) (bases >> 8);
+ *bp++ = (byte) bases;
+ } else { /* The bases all fit in 1 bit each. */
+ *bp++ = 0x00 + (byte) short_bases;
+ }
+ for (i = 0; i < num_comp; ++i)
+ bp = cmd_put_w((uint) pdcolor->colors.colored.c_level[i], bp);
+ /****** IGNORE alpha ******/
+ code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_color, bp - buf + 1);
+ if (code < 0)
+ return code;
+ memcpy(dp + 1, buf, bp - buf);
+ return cmd_dc_type_color;
+ } else
+ return_error(-1);
+}
+
+/* Clear (a) specific 'known' flag(s) for all bands. */
+/* We must do this whenever the value of a 'known' parameter changes. */
+void
+cmd_clear_known(gx_device_clist_writer * cldev, uint known)
+{
+ ushort unknown = ~known;
+ gx_clist_state *pcls = cldev->states;
+ int i;
+
+ for (i = cldev->nbands - 1; i >= 0; i --, pcls ++)
+ pcls->known &= unknown;
+}
+
+/* Check whether we need to change the clipping path in the device. */
+bool
+cmd_check_clip_path(gx_device_clist_writer * cldev, const gx_clip_path * pcpath)
+{
+ if (pcpath == NULL)
+ return false;
+ /* The clip path might have moved in memory, so even if the */
+ /* ids match, update the pointer. */
+ cldev->clip_path = pcpath;
+ if (pcpath->id == cldev->clip_path_id)
+ return false;
+ cldev->clip_path_id = pcpath->id;
+ return true;
+}
+
+/* Construct the parameters for writing out a matrix. */
+/* We need a buffer of at least 1 + 6 * sizeof(float) bytes. */
+byte *
+cmd_for_matrix(byte * cbuf, const gs_matrix * pmat)
+{
+ byte *cp = cbuf + 1;
+ byte b = 0;
+ float coeffs[6];
+ int i;
+
+ coeffs[0] = pmat->xx;
+ coeffs[1] = pmat->xy;
+ coeffs[2] = pmat->yx;
+ coeffs[3] = pmat->yy;
+ coeffs[4] = pmat->tx;
+ coeffs[5] = pmat->ty;
+ for (i = 0; i < 4; i += 2) {
+ float u = coeffs[i], v = coeffs[i ^ 3];
+
+ b <<= 2;
+ if (u != 0 || v != 0) {
+ memcpy(cp, &u, sizeof(float));
+ cp += sizeof(float);
+
+ if (v == u)
+ b += 1;
+ else if (v == -u)
+ b += 2;
+ else {
+ b += 3;
+ memcpy(cp, &v, sizeof(float));
+ cp += sizeof(float);
+ }
+ }
+ }
+ for (; i < 6; ++i) {
+ float v = coeffs[i];
+
+ b <<= 1;
+ if (v != 0) {
+ ++b;
+ memcpy(cp, &v, sizeof(float));
+ cp += sizeof(float);
+ }
+ }
+ cbuf[0] = b << 2;
+ return cp;
+}
+
+/* Write out values of any unknown parameters. */
+int
+cmd_write_unknown(gx_device_clist_writer * cldev, gx_clist_state * pcls,
+ uint must_know)
+{
+ ushort unknown = ~pcls->known & must_know;
+ byte *dp;
+ int code;
+
+ if (unknown & flatness_known) {
+ code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_flatness,
+ 1 + sizeof(float));
+ if (code < 0)
+ return code;
+ memcpy(dp + 1, &cldev->imager_state.flatness, sizeof(float));
+ pcls->known |= flatness_known;
+ }
+ if (unknown & fill_adjust_known) {
+ code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_fill_adjust,
+ 1 + sizeof(fixed) * 2);
+ if (code < 0)
+ return code;
+ memcpy(dp + 1, &cldev->imager_state.fill_adjust.x, sizeof(fixed));
+ memcpy(dp + 1 + sizeof(fixed), &cldev->imager_state.fill_adjust.y, sizeof(fixed));
+ pcls->known |= fill_adjust_known;
+ }
+ if (unknown & ctm_known) {
+ byte cbuf[1 + 6 * sizeof(float)];
+ uint len =
+ cmd_for_matrix(cbuf,
+ (const gs_matrix *)&cldev->imager_state.ctm) - cbuf;
+
+ code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_ctm, len + 1);
+ if (code < 0)
+ return code;
+ memcpy(dp + 1, cbuf, len);
+ pcls->known |= ctm_known;
+ }
+ if (unknown & line_width_known) {
+ float width =
+ gx_current_line_width(&cldev->imager_state.line_params);
+
+ code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_line_width,
+ 1 + sizeof(width));
+ if (code < 0)
+ return code;
+ memcpy(dp + 1, &width, sizeof(width));
+ pcls->known |= line_width_known;
+ }
+ if (unknown & miter_limit_known) {
+ code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_miter_limit,
+ 1 + sizeof(float));
+ if (code < 0)
+ return code;
+ memcpy(dp + 1, &cldev->imager_state.line_params.miter_limit,
+ sizeof(float));
+ pcls->known |= miter_limit_known;
+ }
+ if (unknown & misc0_known) {
+ code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_misc2, 2);
+ if (code < 0)
+ return code;
+ dp[1] = cmd_set_misc2_cap_join +
+ (cldev->imager_state.line_params.cap << 3) +
+ cldev->imager_state.line_params.join;
+ pcls->known |= misc0_known;
+ }
+ if (unknown & misc1_known) {
+ code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_misc2, 2);
+ if (code < 0)
+ return code;
+ dp[1] = cmd_set_misc2_ac_op_sa +
+ (cldev->imager_state.accurate_curves ? 4 : 0) +
+ (cldev->imager_state.overprint ? 2 : 0) +
+ (cldev->imager_state.stroke_adjust ? 1 : 0);
+ pcls->known |= misc1_known;
+ }
+ if (unknown & dash_known) {
+ int n = cldev->imager_state.line_params.dash.pattern_size;
+
+ code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_dash,
+ 2 + (n + 2) * sizeof(float));
+ if (code < 0)
+ return code;
+ dp[1] = n + (cldev->imager_state.line_params.dash.adapt ? 0x80 : 0) +
+ (cldev->imager_state.line_params.dot_length_absolute ? 0x40 : 0);
+ memcpy(dp + 2, &cldev->imager_state.line_params.dot_length,
+ sizeof(float));
+ memcpy(dp + 2 + sizeof(float),
+ &cldev->imager_state.line_params.dash.offset,
+ sizeof(float));
+ if (n != 0)
+ memcpy(dp + 2 + sizeof(float) * 2,
+ cldev->imager_state.line_params.dash.pattern,
+ n * sizeof(float));
+ pcls->known |= dash_known;
+ }
+ if (unknown & alpha_known) {
+ code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_misc2,
+ 2 + sizeof(cldev->imager_state.alpha));
+ if (code < 0)
+ return code;
+ dp[1] = cmd_set_misc2_alpha;
+ memcpy(dp + 2, &cldev->imager_state.alpha,
+ sizeof(cldev->imager_state.alpha));
+ pcls->known |= alpha_known;
+ }
+ if (unknown & clip_path_known) {
+ /*
+ * We can write out the clipping path either as rectangles
+ * or as a real (filled) path.
+ */
+ const gx_clip_path *pcpath = cldev->clip_path;
+ int band_height = cldev->page_band_height;
+ int ymin = (pcls - cldev->states) * band_height;
+ int ymax = min(ymin + band_height, cldev->height);
+ gs_fixed_rect box;
+ bool punt_to_outer_box = false;
+ int code;
+
+ code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_begin_clip, 1);
+ if (code < 0)
+ return code;
+ if (pcpath->path_valid) {
+ if (gx_path_is_rectangle(&pcpath->path, &box) &&
+ fixed_is_int(box.p.x | box.p.y | box.q.x | box.q.y)
+ ) {
+ /* Write the path as a rectangle. */
+ code = cmd_write_rect_cmd(cldev, pcls, cmd_op_fill_rect,
+ fixed2int_var(box.p.x),
+ fixed2int_var(box.p.y),
+ fixed2int(box.q.x - box.p.x),
+ fixed2int(box.q.y - box.p.y));
+ } else if ( !(cldev->disable_mask & clist_disable_complex_clip) ) {
+ /* Write the path. */
+ code = cmd_put_path(cldev, pcls, &pcpath->path,
+ int2fixed(ymin - 1),
+ int2fixed(ymax + 1),
+ (pcpath->rule == gx_rule_even_odd ?
+ cmd_opv_eofill : cmd_opv_fill),
+ true, sn_not_first);
+ } else {
+ /* Complex paths disabled: write outer box as clip */
+ punt_to_outer_box = true;
+ }
+ } else { /* Write out the rectangles. */
+ const gx_clip_list *list = gx_cpath_list(pcpath);
+ const gx_clip_rect *prect = list->head;
+
+ if (prect == 0)
+ prect = &list->single;
+ else if (cldev->disable_mask & clist_disable_complex_clip)
+ punt_to_outer_box = true;
+ if (!punt_to_outer_box) {
+ for (; prect != 0 && code >= 0; prect = prect->next)
+ if (prect->xmax > prect->xmin &&
+ prect->ymin < ymax && prect->ymax > ymin
+ ) {
+ code =
+ cmd_write_rect_cmd(cldev, pcls, cmd_op_fill_rect,
+ prect->xmin, prect->ymin,
+ prect->xmax - prect->xmin,
+ prect->ymax - prect->ymin);
+ }
+ }
+ }
+ if (punt_to_outer_box) {
+ /* Clip is complex, but disabled. Write out the outer box */
+ gs_fixed_rect box;
+
+ gx_cpath_outer_box(pcpath, &box);
+ box.p.x = fixed_floor(box.p.x);
+ box.p.y = fixed_floor(box.p.y);
+ code = cmd_write_rect_cmd(cldev, pcls, cmd_op_fill_rect,
+ fixed2int_var(box.p.x),
+ fixed2int_var(box.p.y),
+ fixed2int_ceiling(box.q.x - box.p.x),
+ fixed2int_ceiling(box.q.y - box.p.y));
+ }
+ {
+ int end_code =
+ set_cmd_put_op(dp, cldev, pcls, cmd_opv_end_clip, 2);
+
+ if (code >= 0)
+ code = end_code; /* take the first failure seen */
+ if (end_code < 0 && cldev->error_is_retryable) {
+ /*
+ * end_clip has to work despite lo-mem to maintain consistency.
+ * This isn't error recovery, but just to prevent dangling
+ * cmd_opv_begin_clip's.
+ */
+ ++cldev->ignore_lo_mem_warnings;
+ end_code =
+ set_cmd_put_op(dp, cldev, pcls, cmd_opv_end_clip, 2);
+ --cldev->ignore_lo_mem_warnings;
+ }
+ if (end_code >= 0)
+ dp[1] = (gx_cpath_is_outside(pcpath) ? 1 : 0);
+ }
+ if (code < 0)
+ return code;
+ pcls->clip_enabled = 1;
+ pcls->known |= clip_path_known;
+ }
+ if (unknown & color_space_known) {
+ byte *dp;
+
+ if (cldev->color_space & 8) { /* indexed */
+ uint num_values = (cldev->indexed_params.hival + 1) *
+ gs_color_space_num_components(
+ (const gs_color_space *)&cldev->indexed_params.base_space);
+ bool use_proc = cldev->color_space & 4;
+ const void *map_data;
+ uint map_size;
+
+ if (use_proc) {
+ map_data = cldev->indexed_params.lookup.map->values;
+ map_size = num_values *
+ sizeof(cldev->indexed_params.lookup.map->values[0]);
+ } else {
+ map_data = cldev->indexed_params.lookup.table.data;
+ map_size = num_values;
+ }
+ code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_color_space,
+ 2 + cmd_sizew(cldev->indexed_params.hival) + map_size);
+ if (code < 0)
+ return code;
+ memcpy(cmd_put_w(cldev->indexed_params.hival, dp + 2),
+ map_data, map_size);
+ } else {
+ code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_color_space, 2);
+ if (code < 0)
+ return code;
+ }
+ dp[1] = cldev->color_space;
+ pcls->known |= color_space_known;
+ }
+ return 0;
+}
+
+/* ------ Driver procedures ------ */
+
+int
+clist_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_clist_writer * const cdev =
+ &((gx_device_clist *)dev)->writer;
+ uint unknown = 0;
+ int y, height, y0, y1;
+ gs_logical_operation_t lop = pis->log_op;
+ byte op = (byte)
+ (params->rule == gx_rule_even_odd ?
+ cmd_opv_eofill : cmd_opv_fill);
+ gs_fixed_point adjust;
+
+ if ( (cdev->disable_mask & clist_disable_fill_path) ||
+ gs_debug_c(',')
+ ) {
+ /* Disable path-based banding. */
+ return gx_default_fill_path(dev, pis, ppath, params, pdcolor,
+ pcpath);
+ }
+ adjust = params->adjust;
+ {
+ gs_fixed_rect bbox;
+
+ gx_path_bbox(ppath, &bbox);
+ y = fixed2int(bbox.p.y) - 1;
+ height = fixed2int_ceiling(bbox.q.y) - y + 1;
+ fit_fill_y(dev, y, height);
+ fit_fill_h(dev, y, height);
+ if (height <= 0)
+ return 0;
+ }
+ y0 = y;
+ y1 = y + height;
+ if (cdev->imager_state.flatness != params->flatness) {
+ unknown |= flatness_known;
+ cdev->imager_state.flatness = params->flatness;
+ }
+ if (cdev->imager_state.fill_adjust.x != adjust.x ||
+ cdev->imager_state.fill_adjust.y != adjust.y
+ ) {
+ unknown |= fill_adjust_known;
+ cdev->imager_state.fill_adjust = adjust;
+ }
+ if (cdev->imager_state.alpha != pis->alpha) {
+ unknown |= alpha_known;
+ state_update(alpha);
+ }
+ if (cmd_check_clip_path(cdev, pcpath))
+ unknown |= clip_path_known;
+ if (unknown)
+ cmd_clear_known(cdev, unknown);
+ FOR_RECTS {
+ int code =
+ cmd_do_write_unknown(cdev, pcls,
+ flatness_known | fill_adjust_known |
+ alpha_known | clip_path_known);
+
+ if (code < 0)
+ return code;
+ if ((code = cmd_do_enable_clip(cdev, pcls, pcpath != NULL)) < 0 ||
+ (code = cmd_update_lop(cdev, pcls, lop)) < 0
+ )
+ return code;
+ code = cmd_put_drawing_color(cdev, pcls, pdcolor);
+ if (code < 0) { /* Something went wrong, use the default implementation. */
+ return gx_default_fill_path(dev, pis, ppath, params, pdcolor,
+ pcpath);
+ }
+ code = cmd_put_path(cdev, pcls, ppath,
+ int2fixed(max(y - 1, y0)),
+ int2fixed(min(y + height + 1, y1)),
+ op + code, /* cmd_dc_type */
+ true, sn_none /* fill doesn't need the notes */ );
+ if (code < 0)
+ return code;
+ } END_RECTS;
+ return 0;
+}
+
+int
+clist_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_clist_writer * const cdev =
+ &((gx_device_clist *)dev)->writer;
+ int pattern_size = pis->line_params.dash.pattern_size;
+ uint unknown = 0;
+ gs_fixed_rect bbox;
+ gs_fixed_point expansion;
+ int adjust_y;
+ int y, height, y0, y1;
+ gs_logical_operation_t lop = pis->log_op;
+
+ if ((cdev->disable_mask & clist_disable_stroke_path) ||
+ gs_debug_c(',')
+ ) {
+ /* Disable path-based banding. */
+ return gx_default_stroke_path(dev, pis, ppath, params, pdcolor,
+ pcpath);
+ }
+ gx_path_bbox(ppath, &bbox);
+ /* We must use the supplied imager state, not our saved one, */
+ /* for computing the stroke expansion. */
+ if (gx_stroke_path_expansion(pis, ppath, &expansion) < 0) {
+ /* Expansion is too large: use the entire page. */
+ adjust_y = 0;
+ y = 0;
+ height = dev->height;
+ } else {
+ adjust_y = fixed2int_ceiling(expansion.y) + 1;
+ y = fixed2int(bbox.p.y) - adjust_y;
+ height = fixed2int_ceiling(bbox.q.y) - y + adjust_y;
+ fit_fill_y(dev, y, height);
+ fit_fill_h(dev, y, height);
+ if (height <= 0)
+ return 0;
+ }
+ y0 = y;
+ y1 = y + height;
+ /* Check the dash pattern, since we bail out if */
+ /* the pattern is too large. */
+ cdev->imager_state.line_params.dash.pattern = cdev->dash_pattern;
+ if (cdev->imager_state.line_params.dash.pattern_size != pattern_size ||
+ (pattern_size != 0 &&
+ memcmp(cdev->imager_state.line_params.dash.pattern,
+ pis->line_params.dash.pattern,
+ pattern_size * sizeof(float))) ||
+ cdev->imager_state.line_params.dash.offset !=
+ pis->line_params.dash.offset ||
+ cdev->imager_state.line_params.dash.adapt !=
+ pis->line_params.dash.adapt ||
+ cdev->imager_state.line_params.dot_length !=
+ pis->line_params.dot_length ||
+ cdev->imager_state.line_params.dot_length_absolute !=
+ pis->line_params.dot_length_absolute
+ ) { /* Bail out if the dash pattern is too long. */
+ if (pattern_size > cmd_max_dash)
+ return gx_default_stroke_path(dev, pis, ppath, params,
+ pdcolor, pcpath);
+ unknown |= dash_known;
+ gx_set_dash(&cdev->imager_state.line_params.dash,
+ pis->line_params.dash.pattern,
+ pis->line_params.dash.pattern_size,
+ pis->line_params.dash.offset, NULL);
+ gx_set_dash_adapt(&cdev->imager_state.line_params.dash,
+ pis->line_params.dash.adapt);
+ gx_set_dot_length(&cdev->imager_state.line_params,
+ pis->line_params.dot_length,
+ pis->line_params.dot_length_absolute);
+ }
+ if (state_neq(flatness)) {
+ unknown |= flatness_known;
+ state_update(flatness);
+ }
+ if (state_neq(fill_adjust.x) || state_neq(fill_adjust.y)) {
+ unknown |= fill_adjust_known;
+ state_update(fill_adjust);
+ }
+ if (state_neq(ctm.xx) || state_neq(ctm.xy) ||
+ state_neq(ctm.yx) || state_neq(ctm.yy) ||
+ /* We don't actually need tx or ty, but we don't want to bother */
+ /* tracking them separately from the other coefficients. */
+ state_neq(ctm.tx) || state_neq(ctm.ty)
+ ) {
+ unknown |= ctm_known;
+ state_update(ctm);
+ }
+ if (state_neq(line_params.half_width)) {
+ unknown |= line_width_known;
+ state_update(line_params.half_width);
+ }
+ if (state_neq(line_params.miter_limit)) {
+ unknown |= miter_limit_known;
+ gx_set_miter_limit(&cdev->imager_state.line_params,
+ pis->line_params.miter_limit);
+ }
+ if (state_neq(line_params.cap) || state_neq(line_params.join)) {
+ unknown |= misc0_known;
+ state_update(line_params.cap);
+ state_update(line_params.join);
+ }
+ if (state_neq(accurate_curves) || state_neq(overprint) ||
+ state_neq(stroke_adjust)
+ ) {
+ unknown |= misc1_known;
+ state_update(accurate_curves);
+ state_update(overprint);
+ state_update(stroke_adjust);
+ }
+ if (cdev->imager_state.alpha != pis->alpha) {
+ unknown |= alpha_known;
+ state_update(alpha);
+ }
+ if (cmd_check_clip_path(cdev, pcpath))
+ unknown |= clip_path_known;
+ if (unknown)
+ cmd_clear_known(cdev, unknown);
+ FOR_RECTS {
+ int code;
+
+ if ((code = cmd_do_write_unknown(cdev, pcls, stroke_all_known)) < 0 ||
+ (code = cmd_do_enable_clip(cdev, pcls, pcpath != NULL)) < 0 ||
+ (code = cmd_update_lop(cdev, pcls, lop)) < 0
+ )
+ return code;
+ code = cmd_put_drawing_color(cdev, pcls, pdcolor);
+ if (code < 0) {
+ /* Something went wrong, use the default implementation. */
+ return gx_default_stroke_path(dev, pis, ppath, params, pdcolor,
+ pcpath);
+ }
+ {
+ fixed ymin, ymax;
+
+ /*
+ * If a dash pattern is active, we can't skip segments
+ * outside the clipping region, because that would throw off
+ * the pattern.
+ */
+ if (pattern_size == 0)
+ ymin = int2fixed(max(y - adjust_y, y0)),
+ ymax = int2fixed(min(y + height + adjust_y, y1));
+ else
+ ymin = min_fixed,
+ ymax = max_fixed;
+ code = cmd_put_path(cdev, pcls, ppath, ymin, ymax,
+ cmd_opv_stroke + code, /* cmd_dc_type */
+ false, (segment_notes) ~ 0);
+ if (code < 0)
+ return code;
+ }
+ } END_RECTS;
+ return 0;
+}
+
+/* ------ Path utilities ------ */
+
+/* Define the state bookkeeping for writing path segments. */
+typedef struct cmd_segment_writer_s {
+ /* Set at initialization */
+ gx_device_clist_writer *cldev;
+ gx_clist_state *pcls;
+ /* Updated dynamically */
+ segment_notes notes;
+ byte *dp;
+ int len;
+ gs_fixed_point delta_first;
+ byte cmd[6 * (1 + sizeof(fixed))];
+}
+cmd_segment_writer;
+
+/* Put out a path segment command. */
+private int
+cmd_put_segment(cmd_segment_writer * psw, byte op,
+ const fixed * operands, segment_notes notes)
+{
+ const fixed *optr = operands;
+
+ /* Fetch num_operands before possible command merging. */
+ int i = clist_segment_op_num_operands[op & 0xf];
+ byte *q = psw->cmd - 1;
+
+#ifdef DEBUG
+ if (gs_debug_c('L')) {
+ int j;
+
+ dlprintf2("[L] %s:%d:", cmd_sub_op_names[op >> 4][op & 0xf],
+ (int)notes);
+ for (j = 0; j < i; ++j)
+ dprintf1(" %g", fixed2float(operands[j]));
+ dputs("\n");
+ }
+#endif
+
+ /* Merge or shorten commands if possible. */
+ if (op == cmd_opv_rlineto) {
+ if (operands[0] == 0)
+ op = cmd_opv_vlineto, optr = ++operands, i = 1;
+ else if (operands[1] == 0)
+ op = cmd_opv_hlineto, i = 1;
+ else
+ switch (*psw->dp) {
+ case cmd_opv_rmoveto:
+ psw->delta_first.x = operands[0];
+ psw->delta_first.y = operands[1];
+ op = cmd_opv_rmlineto;
+ merge:cmd_uncount_op(*psw->dp, psw->len);
+ cmd_shorten_op(psw->cldev, psw->pcls, psw->len); /* delete it */
+ q += psw->len - 1;
+ break;
+ case cmd_opv_rmlineto:
+ if (notes != psw->notes)
+ break;
+ op = cmd_opv_rm2lineto;
+ goto merge;
+ case cmd_opv_rm2lineto:
+ if (notes != psw->notes)
+ break;
+ if (operands[0] == -psw->delta_first.x &&
+ operands[1] == -psw->delta_first.y
+ ) {
+ cmd_uncount_op(cmd_opv_rm2lineto, psw->len);
+ *psw->dp = cmd_count_op(cmd_opv_rm3lineto, psw->len);
+ return 0;
+ }
+ break;
+ default:
+ ;
+ }
+ }
+ for (; --i >= 0; ++optr) {
+ fixed d = *optr, d2;
+
+ if (is_bits(d, _fixed_shift + 11) &&
+ !(d & (float2fixed(0.25) - 1))
+ ) {
+ cmd_count_add1(stats_cmd_diffs[3]);
+ d = ((d >> (_fixed_shift - 2)) & 0x1fff) + 0xc000;
+ q += 2;
+ } else if (is_bits(d, 19) && i > 0 && is_bits(d2 = optr[1], 19)) {
+ cmd_count_add1(stats_cmd_diffs[0]);
+ q[1] = (byte) ((d >> 13) & 0x3f);
+ q[2] = (byte) (d >> 5);
+ q[3] = (byte) ((d << 3) + ((d2 >> 16) & 7));
+ q[4] = (byte) (d2 >> 8);
+ q[5] = (byte) d2;
+ q += 5;
+ --i, ++optr;
+ continue;
+ } else if (is_bits(d, 22)) {
+ cmd_count_add1(stats_cmd_diffs[1]);
+ q[1] = (byte) (((d >> 16) & 0x3f) + 0x40);
+ q += 3;
+ } else if (is_bits(d, 30)) {
+ cmd_count_add1(stats_cmd_diffs[2]);
+ q[1] = (byte) (((d >> 24) & 0x3f) + 0x80);
+ q[2] = (byte) (d >> 16);
+ q += 4;
+ } else {
+ int b;
+
+ cmd_count_add1(stats_cmd_diffs[4]);
+ *++q = 0xe0;
+ for (b = sizeof(fixed) - 1; b > 1; --b)
+ *++q = (byte) (d >> (b * 8));
+ q += 2;
+ }
+ q[-1] = (byte) (d >> 8);
+ *q = (byte) d;
+ }
+ if (notes != psw->notes) {
+ byte *dp;
+ int code =
+ set_cmd_put_op(dp, psw->cldev, psw->pcls, cmd_opv_set_misc2, 2);
+
+ if (code < 0)
+ return code;
+ dp[1] = cmd_set_misc2_notes + notes;
+ psw->notes = notes;
+ } {
+ int len = q + 2 - psw->cmd;
+ byte *dp;
+ int code = set_cmd_put_op(dp, psw->cldev, psw->pcls, op, len);
+
+ if (code < 0)
+ return code;
+ memcpy(dp + 1, psw->cmd, len - 1);
+ psw->len = len;
+ psw->dp = dp;
+ }
+ return 0;
+}
+/* Put out a line segment command. */
+#define cmd_put_rmoveto(psw, operands)\
+ cmd_put_segment(psw, cmd_opv_rmoveto, operands, sn_none)
+#define cmd_put_rlineto(psw, operands, notes)\
+ cmd_put_segment(psw, cmd_opv_rlineto, operands, notes)
+
+/*
+ * Write a path. We go to a lot of trouble to omit segments that are
+ * entirely outside the band.
+ */
+private int
+cmd_put_path(gx_device_clist_writer * cldev, gx_clist_state * pcls,
+ const gx_path * ppath, fixed ymin, fixed ymax, byte path_op,
+ bool implicit_close, segment_notes keep_notes)
+{
+ gs_path_enum cenum;
+ cmd_segment_writer writer;
+
+ /*
+ * initial_op is logically const, so we declare it as such,
+ * since some systems really dislike non-const statics.
+ * This entails an otherwise pointless cast in set_first_point().
+ */
+ static const byte initial_op = cmd_opv_end_run;
+
+ /*
+ * We define the 'side' of a point according to its Y value as
+ * follows:
+ */
+#define which_side(y) ((y) < ymin ? -1 : (y) >= ymax ? 1 : 0)
+
+ /*
+ * While writing a subpath, we need to keep track of any segments
+ * skipped at the beginning of the subpath and any segments skipped
+ * just before the current segment. We do this with two sets of
+ * state variables, one that tracks the actual path segments and one
+ * that tracks the emitted segments.
+ *
+ * The following track the actual segments:
+ */
+
+ /*
+ * The point and side of the last moveto (skipped if
+ * start_side != 0):
+ */
+ gs_fixed_point start;
+ int start_side;
+
+ /*
+ * Whether any lines or curves were skipped immediately
+ * following the moveto:
+ */
+ bool start_skip;
+
+ /* The side of the last point: */
+ int side;
+
+ /* The last point with side != 0: */
+ gs_fixed_point out;
+
+ /* If the last out-going segment was a lineto, */
+ /* its notes: */
+ segment_notes out_notes;
+
+ /*
+ * The following track the emitted segments:
+ */
+
+ /* The last point emitted: */
+ fixed px = int2fixed(pcls->rect.x);
+ fixed py = int2fixed(pcls->rect.y);
+
+ /* The point of the last emitted moveto: */
+ gs_fixed_point first;
+
+ /* Information about the last emitted operation: */
+ int open = 0; /* -1 if last was moveto, 1 if line/curveto, */
+
+ /* 0 if newpath/closepath */
+
+
+ if_debug4('p', "[p]initial (%g,%g), clip [%g..%g)\n",
+ fixed2float(px), fixed2float(py),
+ fixed2float(ymin), fixed2float(ymax));
+ gx_path_enum_init(&cenum, ppath);
+ writer.cldev = cldev;
+ writer.pcls = pcls;
+ writer.notes = sn_none;
+#define set_first_point() (writer.dp = (byte *)&initial_op)
+#define first_point() (writer.dp == &initial_op)
+ set_first_point();
+ for (;;) {
+ fixed vs[6];
+
+#define A vs[0]
+#define B vs[1]
+#define C vs[2]
+#define D vs[3]
+#define E vs[4]
+#define F vs[5]
+ int pe_op = gx_path_enum_next(&cenum, (gs_fixed_point *) vs);
+ byte *dp;
+ int code;
+
+ switch (pe_op) {
+ case 0:
+ /* If the path is open and needs an implicit close, */
+ /* do the close and then come here again. */
+ if (open > 0 && implicit_close)
+ goto close;
+ /* All done. */
+ pcls->rect.x = fixed2int_var(px);
+ pcls->rect.y = fixed2int_var(py);
+ if_debug2('p', "[p]final (%d,%d)\n",
+ pcls->rect.x, pcls->rect.y);
+ return set_cmd_put_op(dp, cldev, pcls, path_op, 1);
+ case gs_pe_moveto:
+ /* If the path is open and needs an implicit close, */
+ /* do a closepath and then redo the moveto. */
+ if (open > 0 && implicit_close) {
+ gx_path_enum_backup(&cenum);
+ goto close;
+ }
+ open = -1;
+ start.x = A, start.y = B;
+ start_skip = false;
+ if ((start_side = side = which_side(B)) != 0) {
+ out.x = A, out.y = B;
+ if_debug3('p', "[p]skip moveto (%g,%g) side %d\n",
+ fixed2float(out.x), fixed2float(out.y),
+ side);
+ continue;
+ }
+ C = A - px, D = B - py;
+ first.x = px = A, first.y = py = B;
+ code = cmd_put_rmoveto(&writer, &C);
+ if_debug2('p', "[p]moveto (%g,%g)\n",
+ fixed2float(px), fixed2float(py));
+ break;
+ case gs_pe_lineto:
+ {
+ int next_side = which_side(B);
+ segment_notes notes =
+ gx_path_enum_notes(&cenum) & keep_notes;
+
+ if (next_side == side && side != 0) { /* Skip a line completely outside the clip region. */
+ if (open < 0)
+ start_skip = true;
+ out.x = A, out.y = B;
+ out_notes = notes;
+ if_debug3('p', "[p]skip lineto (%g,%g) side %d\n",
+ fixed2float(out.x), fixed2float(out.y),
+ side);
+ continue;
+ }
+ /* If we skipped any segments, put out a moveto/lineto. */
+ if (side && (px != out.x || py != out.y || first_point())) {
+ C = out.x - px, D = out.y - py;
+ if (open < 0) {
+ first = out;
+ code = cmd_put_rmoveto(&writer, &C);
+ } else
+ code = cmd_put_rlineto(&writer, &C, out_notes);
+ if (code < 0)
+ return code;
+ px = out.x, py = out.y;
+ if_debug3('p', "[p]catchup %s (%g,%g) for line\n",
+ (open < 0 ? "moveto" : "lineto"),
+ fixed2float(px), fixed2float(py));
+ }
+ if ((side = next_side) != 0) { /* Note a vertex going outside the clip region. */
+ out.x = A, out.y = B;
+ }
+ C = A - px, D = B - py;
+ px = A, py = B;
+ open = 1;
+ code = cmd_put_rlineto(&writer, &C, notes);
+ }
+ if_debug3('p', "[p]lineto (%g,%g) side %d\n",
+ fixed2float(px), fixed2float(py), side);
+ break;
+ case gs_pe_closepath:
+#ifdef DEBUG
+ {
+ gs_path_enum cpenum;
+ gs_fixed_point cvs[3];
+ int op;
+
+ cpenum = cenum;
+ switch (op = gx_path_enum_next(&cpenum, cvs)) {
+ case 0:
+ case gs_pe_moveto:
+ break;
+ default:
+ lprintf1("closepath followed by %d, not end/moveto!\n",
+ op);
+ }
+ }
+#endif
+ /* A closepath may require drawing an explicit line if */
+ /* we skipped any segments at the beginning of the path. */
+ close:if (side != start_side) { /* If we skipped any segments, put out a moveto/lineto. */
+ if (side && (px != out.x || py != out.y || first_point())) {
+ C = out.x - px, D = out.y - py;
+ code = cmd_put_rlineto(&writer, &C, out_notes);
+ if (code < 0)
+ return code;
+ px = out.x, py = out.y;
+ if_debug2('p', "[p]catchup line (%g,%g) for close\n",
+ fixed2float(px), fixed2float(py));
+ }
+ if (open > 0 && start_skip) { /* Draw the closing line back to the start. */
+ C = start.x - px, D = start.y - py;
+ code = cmd_put_rlineto(&writer, &C, sn_none);
+ if (code < 0)
+ return code;
+ px = start.x, py = start.y;
+ if_debug2('p', "[p]draw close to (%g,%g)\n",
+ fixed2float(px), fixed2float(py));
+ }
+ }
+ /*
+ * We don't bother to update side because we know that the
+ * next element after a closepath, if any, must be a moveto.
+ * We must handle explicitly the possibility that the entire
+ * subpath was skipped.
+ */
+ if (implicit_close || open <= 0) {
+ open = 0;
+ /*
+ * Force writing an explicit moveto if the next subpath
+ * starts with a moveto to the same point where this one
+ * ends.
+ */
+ set_first_point();
+ continue;
+ }
+ open = 0;
+ px = first.x, py = first.y;
+ code = cmd_put_segment(&writer, cmd_opv_closepath, &A, sn_none);
+ if_debug0('p', "[p]close\n");
+ break;
+ case gs_pe_curveto:
+ {
+ segment_notes notes =
+ gx_path_enum_notes(&cenum) & keep_notes;
+
+ {
+ fixed bpy, bqy;
+ int all_side, out_side;
+
+ /* Compute the Y bounds for the clipping check. */
+ if (B < D)
+ bpy = B, bqy = D;
+ else
+ bpy = D, bqy = B;
+ if (F < bpy)
+ bpy = F;
+ else if (F > bqy)
+ bqy = F;
+ all_side = (bqy < ymin ? -1 : bpy > ymax ? 1 : 0);
+ if (all_side != 0) {
+ if (all_side == side) { /* Skip a curve entirely outside the clip region. */
+ if (open < 0)
+ start_skip = true;
+ out.x = E, out.y = F;
+ out_notes = notes;
+ if_debug3('p', "[p]skip curveto (%g,%g) side %d\n",
+ fixed2float(out.x), fixed2float(out.y),
+ side);
+ continue;
+ }
+ out_side = all_side;
+ } else
+ out_side = which_side(F);
+ /* If we skipped any segments, put out a moveto/lineto. */
+ if (side && (px != out.x || py != out.y || first_point())) {
+ fixed diff[2];
+
+ diff[0] = out.x - px, diff[1] = out.y - py;
+ if (open < 0) {
+ first = out;
+ code = cmd_put_rmoveto(&writer, diff);
+ } else
+ code = cmd_put_rlineto(&writer, diff, out_notes);
+ if (code < 0)
+ return code;
+ px = out.x, py = out.y;
+ if_debug3('p', "[p]catchup %s (%g,%g) for curve\n",
+ (open < 0 ? "moveto" : "lineto"),
+ fixed2float(px), fixed2float(py));
+ }
+ if ((side = out_side) != 0) { /* Note a vertex going outside the clip region. */
+ out.x = E, out.y = F;
+ }
+ }
+ {
+ fixed nx = E, ny = F;
+ const fixed *optr = vs;
+ byte op;
+
+ if_debug7('p', "[p]curveto (%g,%g; %g,%g; %g,%g) side %d\n",
+ fixed2float(A), fixed2float(B),
+ fixed2float(C), fixed2float(D),
+ fixed2float(E), fixed2float(F), side);
+ E -= C, F -= D;
+ C -= A, D -= B;
+ A -= px, B -= py;
+ if (B == 0 && E == 0) {
+ B = A, E = F, optr++, op = cmd_opv_hvcurveto;
+ if ((B ^ D) >= 0) {
+ if (C == D && E == B)
+ op = cmd_opv_hqcurveto;
+ } else if (C == -D && E == -B)
+ C = D, op = cmd_opv_hqcurveto;
+ } else if (A == 0 && F == 0) {
+ optr++, op = cmd_opv_vhcurveto;
+ if ((B ^ C) >= 0) {
+ if (D == C && E == B)
+ op = cmd_opv_vqcurveto;
+ } else if (D == -C && E == -B)
+ op = cmd_opv_vqcurveto;
+ } else if (A == 0 && B == 0)
+ optr += 2, op = cmd_opv_nrcurveto;
+ else if (E == 0 && F == 0)
+ op = cmd_opv_rncurveto;
+ else
+ op = cmd_opv_rrcurveto;
+ px = nx, py = ny;
+ open = 1;
+ code = cmd_put_segment(&writer, op, optr, notes);
+ }
+ }
+ break;
+ default:
+ return_error(gs_error_rangecheck);
+ }
+ if (code < 0)
+ return code;
+#undef A
+#undef B
+#undef C
+#undef D
+#undef E
+#undef F
+ }
+}
diff --git a/pstoraster/gxclpath.h b/pstoraster/gxclpath.h
new file mode 100644
index 000000000..2e1899216
--- /dev/null
+++ b/pstoraster/gxclpath.h
@@ -0,0 +1,207 @@
+/* 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$ */
+/* Extends (requires) gxcldev.h */
+
+#ifndef gxclpath_INCLUDED
+# define gxclpath_INCLUDED
+
+#include "gxfixed.h" /* for gzpath.h */
+
+/* Define the flags indicating whether a band knows the current values of */
+/* various miscellaneous parameters (pcls->known). */
+#define flatness_known (1<<0)
+#define fill_adjust_known (1<<1)
+#define ctm_known (1<<2)
+#define line_width_known (1<<3)
+#define miter_limit_known (1<<4)
+#define misc0_known (1<<5)
+#define misc1_known (1<<6)
+#define dash_known (1<<7)
+#define alpha_known (1<<8)
+#define clip_path_known (1<<9)
+#define stroke_all_known ((1<<10)-1)
+#define color_space_known (1<<10)
+/*#define all_known ((1<<11)-1) */
+
+/* Define the drawing color types for distinguishing different */
+/* fill/stroke command variations. */
+typedef enum {
+ cmd_dc_type_pure = 0,
+ cmd_dc_type_ht = 1,
+ cmd_dc_type_color = 2
+} cmd_dc_type;
+
+/* Extend the command set. See gxcldev.h for more information. */
+typedef enum {
+ cmd_op_misc2 = 0xd0, /* (see below) */
+ cmd_opv_set_flatness = 0xd0, /* flatness(float) */
+ cmd_opv_set_fill_adjust = 0xd1, /* adjust_x/y(fixed) */
+ cmd_opv_set_ctm = 0xd2, /* (0=0,0, 1=V,V, 2=V,-V, 3=U,V)x */
+ /* (xx+yy,yx+xy)(0=0, 1=V)x(tx,ty), */
+ /* 0..5 x coeff(float) */
+ cmd_opv_set_line_width = 0xd3, /* width(float) */
+ cmd_opv_set_misc2 = 0xd4,
+#define cmd_set_misc2_cap_join (0 << 6) /* 00: cap(3)join(3) */
+#define cmd_set_misc2_ac_op_sa (1 << 6) /* 01: 0(3)acc.curves(1)overprint(1) */
+ /* stroke_adj(1) */
+#define cmd_set_misc2_notes (2 << 6) /* 10: seg.notes(6) */
+#define cmd_set_misc2_alpha (3 << 6) /* 11: -unused-, alpha */
+ cmd_opv_set_miter_limit = 0xd5, /* miter limit(float) */
+ cmd_opv_set_dash = 0xd6, /* adapt(1)abs.dot(1)n(6), dot */
+ /* length(float), offset(float), */
+ /* n x (float) */
+ cmd_opv_enable_clip = 0xd7, /* (nothing) */
+ cmd_opv_disable_clip = 0xd8, /* (nothing) */
+ cmd_opv_begin_clip = 0xd9, /* (nothing) */
+ cmd_opv_end_clip = 0xda, /* outside? */
+ cmd_opv_set_color_space = 0xdb, /* base(4)Indexed?(2)0(3) */
+ /* [, hival#, table|map] */
+ cmd_opv_begin_image = 0xdc, /* BPCi(3)(0=mask) */
+ /* more params(1) */
+ /* Matrix?(1)Decode?(1) */
+ /* adjust/CombineWithColor(1) */
+ /* rect?(1), */
+ /* [format(2)Interpolate(1)Alpha(2) */
+ /* 0(3),] width#, height#, */
+ /* [, aabbcd00, 0..6 x coeff(float)] */
+ /* [, (0=default, 1=swapped default, */
+ /* 2=0,V, 3=U,V)x4, */
+ /* 0..8 x decode(float)], */
+ /* [, x0#, w-x1#, y0#, h-y1#] */
+ cmd_opv_image_data = 0xdd, /* height# (premature EOD if 0), */
+ /* raster#, <data> */
+ cmd_opv_set_color = 0xde, /* (0000abcd | */
+ /* 0001aaaa abbbbbcc cccddddd), */
+ /* (3|4) x level#: colored halftone */
+ /* with base colors a,b,c,d */
+ cmd_opv_put_params = 0xdf, /* (nothing) */
+ cmd_op_segment = 0xe0, /* (see below) */
+ cmd_opv_rmoveto = 0xe0, /* dx%, dy% */
+ cmd_opv_rlineto = 0xe1, /* dx%, dy% */
+ cmd_opv_hlineto = 0xe2, /* dx% */
+ cmd_opv_vlineto = 0xe3, /* dy% */
+ cmd_opv_rrcurveto = 0xe4, /* dx1%,dy1%, dx2%,dy2%, dx3%,dy3% */
+ cmd_opv_hvcurveto = 0xe5, /* dx1%, dx2%,dy2%, dy3% */
+ cmd_opv_vhcurveto = 0xe6, /* dy1%, dx2%,dy2%, dx3% */
+ cmd_opv_nrcurveto = 0xe7, /* dx2%,dy2%, dx3%,dy3% */
+ cmd_opv_rncurveto = 0xe8, /* dx1%,dy1%, dx2%,dy2% */
+ cmd_opv_rmlineto = 0xe9, /* dx1%,dy1%, dx2%,dy2% */
+ cmd_opv_rm2lineto = 0xea, /* dx1%,dy1%, dx2%,dy2%, dx3%,dy3% */
+ cmd_opv_rm3lineto = 0xeb, /* dx1%,dy1%, dx2%,dy2%, dx3%,dy3%, */
+ /* [-dx2,-dy2 implicit] */
+ cmd_opv_vqcurveto = 0xec, /* dy1%, dx2%[,dy2=dx2 with sign */
+ /* of dy1, dx3=dy1 with sign of dx2] */
+ cmd_opv_hqcurveto = 0xed, /* dx1%, [dx2=dy2 with sign */
+ /* of dx1,]%dy2, [dy3=dx1 with sign */
+ /* of dy2] */
+ cmd_opv_closepath = 0xee, /* (nothing) */
+ cmd_op_path = 0xf0, /* (see below) */
+ /* The path drawing commands come in groups: */
+ /* each group consists of a base command plus an offset */
+ /* which is a cmd_dc_type. */
+ cmd_opv_fill = 0xf0,
+ cmd_opv_htfill = 0xf1,
+ cmd_opv_colorfill = 0xf2,
+ cmd_opv_eofill = 0xf3,
+ cmd_opv_hteofill = 0xf4,
+ cmd_opv_coloreofill = 0xf5,
+ cmd_opv_stroke = 0xf6,
+ cmd_opv_htstroke = 0xf7,
+ cmd_opv_colorstroke = 0xf8
+} gx_cmd_xop;
+
+static const byte clist_segment_op_num_operands[] =
+{2, 2, 1, 1, 6, 4, 4, 4, 4, 4, 6, 6, 2, 2, 0
+};
+
+#define cmd_misc2_op_name_strings\
+ "set_flatness", "set_fill_adjust", "set_ctm", "set_line_width",\
+ "set_misc2", "set_miter_limit", "set_dash", "enable_clip",\
+ "disable_clip", "begin_clip", "end_clip", "set_color_space",\
+ "begin_image", "image_data", "set_color", "put_params"
+
+#define cmd_segment_op_name_strings\
+ "rmoveto", "rlineto", "hlineto", "vlineto",\
+ "rrcurveto", "hvcurveto", "vhcurveto", "nrcurveto",\
+ "rncurveto", "rmlineto", "rm2lineto", "rm3lineto",\
+ "vqcurveto", "hqcurveto", "closepath", "?ef?"
+
+#define cmd_path_op_name_strings\
+ "fill", "htfill", "colorfill", "eofill",\
+ "hteofill", "coloreofill", "stroke", "htstroke",\
+ "colorstroke", "?f9?", "?fa?", "?fb?",\
+ "?fc?", "?fd?", "?fe?", "?ff?"
+
+/*
+ * We represent path coordinates as 'fixed' values in a variable-length,
+ * relative form (s/t = sign, x/y = integer, f/g = fraction):
+ * 00sxxxxx xfffffff ffffftyy yyyygggg gggggggg
+ * 01sxxxxx xxxxffff ffffffff
+ * 10sxxxxx xxxxxxxx xxxxffff ffffffff
+ * 110sxxxx xxxxxxff
+ * 111----- (a full-size `fixed' value)
+ */
+#define is_bits(d, n) !(((d) + ((fixed)1 << ((n) - 1))) & (-(fixed)1 << (n)))
+
+/* ---------------- Driver procedure support ---------------- */
+
+/* The procedures and macros defined here are used when writing */
+/* (gxclimag.c, gxclpath.c). */
+
+/* Compare and update members of the imager state. */
+#define state_neq(member)\
+ cdev->imager_state.member != pis->member
+#define state_update(member)\
+ cdev->imager_state.member = pis->member
+
+/* ------ Exported by gxclpath.c ------ */
+
+/* Write out the color for filling, stroking, or masking. */
+/* Return a cmd_dc_type. */
+int cmd_put_drawing_color(P3(gx_device_clist_writer * cldev,
+ gx_clist_state * pcls,
+ const gx_drawing_color * pdcolor));
+
+/* Clear (a) specific 'known' flag(s) for all bands. */
+/* We must do this whenever the value of a 'known' parameter changes. */
+void cmd_clear_known(P2(gx_device_clist_writer * cldev, uint known));
+
+/* Write out values of any unknown parameters. */
+#define cmd_do_write_unknown(cldev, pcls, must_know)\
+ ( ~((pcls)->known) & (must_know) ?\
+ cmd_write_unknown(cldev, pcls, must_know) : 0 )
+int cmd_write_unknown(P3(gx_device_clist_writer * cldev, gx_clist_state * pcls,
+ uint must_know));
+
+/* Check whether we need to change the clipping path in the device. */
+bool cmd_check_clip_path(P2(gx_device_clist_writer * cldev,
+ const gx_clip_path * pcpath));
+
+/* Construct the parameters for writing out a matrix. */
+/* We need a buffer of at least 1 + 6 * sizeof(float) bytes. */
+byte *cmd_for_matrix(P2(byte * cbuf, const gs_matrix * pmat));
+
+#endif /* gxclpath_INCLUDED */
diff --git a/pstoraster/gxclrast.c b/pstoraster/gxclrast.c
new file mode 100644
index 000000000..99569045a
--- /dev/null
+++ b/pstoraster/gxclrast.c
@@ -0,0 +1,2333 @@
+/*
+ Copyright 2001 by Easy Software Products.
+ Copyright 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$ */
+/* Command list interpreter/rasterizer */
+#include "memory_.h"
+#include "gx.h"
+#include "gp.h" /* for gp_fmode_rb */
+#include "gpcheck.h"
+#include "gserrors.h"
+#include "gsbitops.h"
+#include "gsparams.h"
+#include "gsstate.h" /* (should only be imager state) */
+#include "gxdcolor.h"
+#include "gxdevice.h"
+#include "gscoord.h" /* requires gsmatrix.h */
+#include "gsdevice.h" /* for gs_deviceinitialmatrix */
+#include "gxdevmem.h" /* must precede gxcldev.h */
+#include "gxcldev.h"
+#include "gxclpath.h"
+#include "gxcmap.h"
+#include "gxcspace.h" /* for gs_color_space_type */
+#include "gxgetbit.h"
+#include "gxpaint.h" /* for gx_fill/stroke_params */
+#include "gxhttile.h"
+#include "gdevht.h"
+#include "gzpath.h"
+#include "gzcpath.h"
+#include "gzacpath.h"
+#include "stream.h"
+#include "strimpl.h"
+
+/* We need color space types for constructing temporary color spaces. */
+extern const gs_color_space_type gs_color_space_type_Indexed;
+
+/* Print a bitmap for tracing */
+#ifdef DEBUG
+private void
+cmd_print_bits(const byte * data, int width, int height, int raster)
+{
+ int i, j;
+
+ dlprintf3("[L]width=%d, height=%d, raster=%d\n",
+ width, height, raster);
+ for (i = 0; i < height; i++) {
+ const byte *row = data + i * raster;
+
+ dlprintf("[L]");
+ for (j = 0; j < raster; j++)
+ dprintf1(" %02x", row[j]);
+ dputc('\n');
+ }
+}
+#else
+# define cmd_print_bits(data, width, height, raster) DO_NOTHING
+#endif
+
+/* Get a variable-length integer operand. */
+#define cmd_getw(var, p)\
+ BEGIN\
+ if ( *p < 0x80 ) var = *p++;\
+ else { const byte *_cbp; var = cmd_get_w(p, &_cbp); p = _cbp; }\
+ END
+private long
+cmd_get_w(const byte * p, const byte ** rp)
+{
+ long val = *p++ & 0x7f;
+ int shift = 7;
+
+ for (; val += (long)(*p & 0x7f) << shift, *p++ > 0x7f; shift += 7);
+ *rp = p;
+ return val;
+}
+
+/*
+ * Define the structure for keeping track of the command reading buffer.
+ *
+ * The ptr member is only used for passing the current pointer to, and
+ * receiving an updated pointer from, commands implemented as separate
+ * procedures: normally it is kept in a register.
+ */
+typedef struct command_buf_s {
+ byte *data; /* actual buffer, guaranteed aligned */
+ uint size;
+ const byte *ptr; /* next byte to be read (see above) */
+ const byte *limit; /* refill warning point */
+ const byte *end; /* byte just beyond valid data */
+ stream *s; /* for refilling buffer */
+ int end_status;
+} command_buf_t;
+
+/* Set the end of a command buffer. */
+private void
+set_cb_end(command_buf_t *pcb, const byte *end)
+{
+ pcb->end = end;
+ pcb->limit = pcb->data + (pcb->size - cmd_largest_size + 1);
+ if ( pcb->limit > pcb->end )
+ pcb->limit = pcb->end;
+}
+
+/* Read more data into a command buffer. */
+private const byte *
+top_up_cbuf(command_buf_t *pcb, const byte *cbp)
+{
+ uint nread;
+ byte *cb_top = pcb->data + (pcb->end - cbp);
+
+ memmove(pcb->data, cbp, pcb->end - cbp);
+ nread = pcb->end - cb_top;
+ pcb->end_status = sgets(pcb->s, cb_top, nread, &nread);
+ if ( nread == 0 ) {
+ /* No data for this band at all. */
+ *cb_top = cmd_opv_end_run;
+ nread = 1;
+ }
+ set_cb_end(pcb, cb_top + nread);
+ process_interrupts();
+ return pcb->data;
+}
+
+/* Read data from the command buffer and stream. */
+private const byte *
+cmd_read_data(command_buf_t *pcb, byte *ptr, uint rsize, const byte *cbp)
+{
+ if (pcb->end - cbp >= rsize) {
+ memcpy(ptr, cbp, rsize);
+ return cbp + rsize;
+ } else {
+ uint cleft = pcb->end - cbp;
+ uint rleft = rsize - cleft;
+
+ memcpy(ptr, cbp, cleft);
+ sgets(pcb->s, ptr + cleft, rleft, &rleft);
+ return pcb->end;
+ }
+}
+#define cmd_read(ptr, rsize, cbp)\
+ cbp = cmd_read_data(&cbuf, ptr, rsize, cbp)
+
+/* Read a fixed-size value from the command buffer. */
+inline private const byte *
+cmd_copy_value(void *pvar, int var_size, const byte *cbp)
+{
+ memcpy(pvar, cbp, var_size);
+ return cbp + var_size;
+}
+#define cmd_get_value(var, cbp)\
+ cbp = cmd_copy_value(&var, sizeof(var), cbp)
+
+/*
+ * Render one band to a specified target device. Note that if
+ * action == setup, target may be 0.
+ */
+private int read_set_tile_size(P2(command_buf_t *pcb, tile_slot *bits));
+private int read_set_bits(P8(command_buf_t *pcb, tile_slot *bits,
+ int compress, gx_clist_state *pcls,
+ gx_strip_bitmap *tile, tile_slot **pslot,
+ gx_device_clist_reader *cdev, gs_memory_t *mem));
+private int read_set_ht_order(P4(command_buf_t *pcb, gx_device_halftone *pdht,
+ gx_ht_order **pporder, gs_memory_t *mem));
+private int read_set_ht_data(P8(command_buf_t *pcb, uint *pdata_index,
+ gx_ht_order *porder, gx_device_halftone *pdht,
+ gs_halftone_type halftone_type,
+ gs_imager_state *pis,
+ gx_device_clist_reader *cdev,
+ gs_memory_t *mem));
+private int read_begin_image(P5(command_buf_t *pcb, gs_image_t *pim,
+ int *pnum_planes, gs_int_rect *prect,
+ const gs_color_space *pcs));
+private int read_put_params(P3(command_buf_t *pcb,
+ gx_device_clist_reader *cdev,
+ gs_memory_t *mem));
+
+private const byte *cmd_read_rect(P3(int, gx_cmd_rect *, const byte *));
+private const byte *cmd_read_matrix(P2(gs_matrix *, const byte *));
+private const byte *cmd_read_short_bits(P6(command_buf_t *pcb, byte *data,
+ int width_bytes, int height,
+ uint raster, const byte *cbp));
+private int cmd_select_map(P7(cmd_map_index, bool, gs_imager_state *,
+ gx_ht_order *, frac **, uint *, gs_memory_t *));
+private int cmd_resize_halftone(P3(gx_device_halftone *, uint, gs_memory_t *));
+private int clist_decode_segment(P7(gx_path *, int, fixed[6],
+ gs_fixed_point *, int, int,
+ segment_notes));
+
+int
+clist_playback_band(clist_playback_action playback_action,
+ gx_device_clist_reader *cdev, stream *s,
+ gx_device *target, int x0, int y0, gs_memory_t * mem)
+{
+ /* cbuf must be maximally aligned, but still be a byte *. */
+ typedef union { void *p; double d; long l; } aligner_t;
+ aligner_t cbuf_storage[cbuf_size / sizeof(aligner_t) + 1];
+ command_buf_t cbuf;
+ /* data_bits is for short copy_* bits and copy_* compressed, */
+ /* must be aligned */
+#define data_bits_size cbuf_size
+ byte *data_bits;
+ register const byte *cbp;
+ int dev_depth = cdev->color_info.depth;
+ int dev_depth_bytes = (dev_depth + 7) >> 3;
+ gx_device *tdev;
+ gx_clist_state state;
+ gx_color_index *set_colors;
+ tile_slot *state_slot;
+ gx_strip_bitmap state_tile; /* parameters for reading tiles */
+ tile_slot tile_bits; /* parameters of current tile */
+ gs_int_point tile_phase;
+ gx_path path;
+ bool in_path;
+ gs_fixed_point ppos;
+ gx_clip_path clip_path;
+ bool use_clip;
+ gx_clip_path *pcpath;
+ gx_device_cpath_accum clip_accum;
+ gs_fixed_rect target_box;
+ struct _cas {
+ bool lop_enabled;
+ gs_fixed_point fill_adjust;
+ } clip_save;
+ gs_imager_state imager_state;
+ gx_device_color dev_color;
+ float dash_pattern[cmd_max_dash];
+ gx_fill_params fill_params;
+ gx_stroke_params stroke_params;
+ gx_device_halftone dev_ht;
+ gs_halftone_type halftone_type;
+ gx_ht_order *porder;
+ uint ht_data_index;
+ gs_image_t image;
+ int image_num_planes;
+ gs_int_rect image_rect;
+ gs_color_space color_space; /* only used for indexed spaces */
+ const gs_color_space *pcs;
+ gx_image_enum_common_t *image_info;
+ segment_notes notes;
+ int data_x;
+ int code = 0;
+
+ cbuf.data = (byte *)cbuf_storage;
+ cbuf.size = cbuf_size;
+ cbuf.s = s;
+ cbuf.end_status = 0;
+ set_cb_end(&cbuf, cbuf.data + cbuf.size);
+ cbp = cbuf.end;
+in: /* Initialize for a new page. */
+ tdev = target;
+ set_colors = state.colors;
+ use_clip = false;
+ pcpath = NULL;
+ notes = sn_none;
+ data_x = 0;
+ {
+ static const gx_clist_state cls_initial = { cls_initial_values };
+
+ state = cls_initial;
+ }
+ state_tile.id = gx_no_bitmap_id;
+ state_tile.shift = state_tile.rep_shift = 0;
+ tile_phase.x = x0;
+ tile_phase.y = y0;
+ gx_path_init_local(&path, mem);
+ in_path = false;
+ /*
+ * Initialize the clipping region to the full page.
+ * (Since we also initialize use_clip to false, this is arbitrary.)
+ */
+ {
+ gs_fixed_rect cbox;
+
+ gx_cpath_init_local(&clip_path, mem);
+ cbox.p.x = 0;
+ cbox.p.y = 0;
+ cbox.q.x = cdev->width;
+ cbox.q.y = cdev->height;
+ gx_cpath_from_rectangle(&clip_path, &cbox);
+ }
+ if (target != 0)
+ (*dev_proc(target, get_clipping_box))(target, &target_box);
+ imager_state = clist_imager_state_initial;
+ imager_state.line_params.dash.pattern = dash_pattern;
+ code = gs_imager_state_initialize(&imager_state, mem);
+ if (code < 0)
+ goto out;
+ imager_state.halftone = 0; /* never referenced */
+ memset(&dev_ht, 0, sizeof(dev_ht));
+ dev_ht.order.levels = 0; /* clear pointers explicitly, just in case */
+ dev_ht.order.bits = 0;
+ dev_ht.order.transfer = 0;
+ dev_ht.components = 0;
+ imager_state.dev_ht = &dev_ht;
+ imager_state.ht_cache = 0;
+ if (tdev != 0)
+ gx_set_cmap_procs(&imager_state, tdev);
+ gx_imager_setscreenphase(&imager_state, -x0, -y0, gs_color_select_all);
+ halftone_type = ht_type_none;
+ fill_params.fill_zero_width = false;
+ pcs = gs_cspace_DeviceGray(&imager_state);
+ data_bits = gs_alloc_bytes(mem, data_bits_size,
+ "clist_playback_band(data_bits)");
+ if (data_bits == 0) {
+ code = gs_note_error(gs_error_VMerror);
+ goto out;
+ }
+ while (code >= 0) {
+ int op;
+ int compress, depth, raster;
+ byte *source;
+ gx_color_index colors[2];
+ gx_color_index *pcolor;
+ gs_logical_operation_t log_op;
+ tile_slot bits; /* parameters for reading bits */
+
+ /* Make sure the buffer contains a full command. */
+ if (cbp >= cbuf.limit) {
+ if (cbuf.end_status < 0) { /* End of file or error. */
+ if (cbp == cbuf.end) {
+ code = (cbuf.end_status == EOFC ? 0 :
+ gs_note_error(gs_error_ioerror));
+ break;
+ }
+ } else {
+ cbp = top_up_cbuf(&cbuf, cbp);
+ }
+ }
+ op = *cbp++;
+#ifdef DEBUG
+ if (gs_debug_c('L')) {
+ const char *const *sub = cmd_sub_op_names[op >> 4];
+
+ if (sub)
+ dlprintf1("[L]%s:", sub[op & 0xf]);
+ else
+ dlprintf2("[L]%s %d:", cmd_op_names[op >> 4], op & 0xf);
+ }
+#endif
+ switch (op >> 4) {
+ case cmd_op_misc >> 4:
+ switch (op) {
+ case cmd_opv_end_run:
+ if_debug0('L', "\n");
+ continue;
+ case cmd_opv_set_tile_size:
+ cbuf.ptr = cbp;
+ code = read_set_tile_size(&cbuf, &tile_bits);
+ cbp = cbuf.ptr;
+ if (code < 0)
+ goto out;
+ continue;
+ case cmd_opv_set_tile_phase:
+ cmd_getw(state.tile_phase.x, cbp);
+ cmd_getw(state.tile_phase.y, cbp);
+ if_debug2('L', " (%d,%d)\n",
+ state.tile_phase.x,
+ state.tile_phase.y);
+ goto set_phase;
+ case cmd_opv_set_tile_bits:
+ bits = tile_bits;
+ compress = 0;
+ stb:
+ cbuf.ptr = cbp;
+ code = read_set_bits(&cbuf, &bits, compress,
+ &state, &state_tile, &state_slot,
+ cdev, mem);
+ cbp = cbuf.ptr;
+ if (code < 0)
+ goto out;
+ goto stp;
+ case cmd_opv_set_bits:
+ compress = *cbp & 3;
+ bits.cb_depth = *cbp++ >> 2;
+ cmd_getw(bits.width, cbp);
+ cmd_getw(bits.height, cbp);
+ if_debug4('L', " compress=%d depth=%d size=(%d,%d)",
+ compress, bits.cb_depth,
+ bits.width, bits.height);
+ bits.cb_raster =
+ bitmap_raster(bits.width * bits.cb_depth);
+ bits.x_reps = bits.y_reps = 1;
+ bits.shift = bits.rep_shift = 0;
+ goto stb;
+ case cmd_opv_set_tile_color:
+ set_colors = state.tile_colors;
+ if_debug0('L', "\n");
+ continue;
+ case cmd_opv_set_misc:
+ {
+ uint cb = *cbp++;
+
+ switch (cb >> 6) {
+ case cmd_set_misc_lop >> 6:
+ cmd_getw(state.lop, cbp);
+ state.lop = (state.lop << 6) + (cb & 0x3f);
+ if_debug1('L', " lop=0x%x\n", state.lop);
+ if (state.lop_enabled)
+ imager_state.log_op = state.lop;
+ break;
+ case cmd_set_misc_data_x >> 6:
+ if (cb & 0x20)
+ cmd_getw(data_x, cbp) /* MRS: No trailing ; */
+ else
+ data_x = 0;
+ data_x = (data_x << 5) + (cb & 0x1f);
+ if_debug1('L', " data_x=%d\n", data_x);
+ break;
+ case cmd_set_misc_map >> 6:
+ {
+ frac *mdata;
+ uint count;
+
+ code = cmd_select_map(cb & 0x1f,
+ cb & 0x20,
+ &imager_state,
+ porder, &mdata,
+ &count, mem);
+
+ if (code < 0)
+ goto out;
+ if (mdata) {
+ cmd_read((byte *) mdata, count, cbp);
+#ifdef DEBUG
+ if (gs_debug_c('L')) {
+ uint i;
+
+ for (i = 0; i < count / sizeof(*mdata); ++i)
+ dprintf1(" 0x%04x", mdata[i]);
+ dputc('\n');
+ }
+ } else {
+ if_debug0('L', " none\n");
+#endif
+ }
+ }
+ /* Recompute the effective transfer, */
+ /* in case this was a transfer map. */
+ gx_imager_set_effective_xfer(
+ &imager_state);
+ break;
+ case cmd_set_misc_halftone >> 6:
+ halftone_type = cb & 0x3f;
+ {
+ uint num_comp;
+
+ cmd_getw(num_comp, cbp);
+ if_debug2('L', " halftone type=%d num_comp=%u\n",
+ halftone_type, num_comp);
+ code = cmd_resize_halftone(&dev_ht,
+ num_comp, mem);
+ if (code < 0)
+ goto out;
+ }
+ break;
+ default:
+ goto bad_op;
+ }
+ }
+ continue;
+ case cmd_opv_enable_lop:
+ state.lop_enabled = true;
+ imager_state.log_op = state.lop;
+ if_debug0('L', "\n");
+ continue;
+ case cmd_opv_disable_lop:
+ state.lop_enabled = false;
+ imager_state.log_op = lop_default;
+ if_debug0('L', "\n");
+ continue;
+ case cmd_opv_set_ht_order:
+ cbuf.ptr = cbp;
+ code = read_set_ht_order(&cbuf, &dev_ht, &porder, mem);
+ cbp = cbuf.ptr;
+ if (code < 0)
+ goto out;
+ ht_data_index = 0;
+ /*
+ * Free the relevant cache, because its sizes
+ * are probably not correct any more.
+ */
+ {
+ gx_ht_cache *pcache = porder->cache;
+
+ if (pcache) {
+ if (pcache != imager_state.ht_cache)
+ gx_ht_free_cache(mem, pcache);
+ porder->cache = 0;
+ }
+ }
+ continue;
+ case cmd_opv_set_ht_data:
+ cbuf.ptr = cbp;
+ code = read_set_ht_data(&cbuf, &ht_data_index, porder,
+ &dev_ht, halftone_type,
+ &imager_state, cdev, mem);
+ cbp = cbuf.ptr;
+ if (code < 0)
+ goto out;
+ continue;
+ case cmd_opv_end_page:
+ if_debug0('L', "\n");
+ /*
+ * Do end-of-page cleanup, then reinitialize if
+ * there are more pages to come.
+ */
+ goto out;
+ case cmd_opv_delta2_color0:
+ pcolor = &set_colors[0];
+ goto delta2_c;
+ case cmd_opv_delta2_color1:
+ pcolor = &set_colors[1];
+ delta2_c:set_colors = state.colors;
+ {
+ gx_color_index b = ((uint) * cbp << 8) + cbp[1];
+
+ cbp += 2;
+ if (dev_depth > 24)
+ *pcolor +=
+ ((b & 0xf000) << 12) + ((b & 0x0f00) << 8) +
+ ((b & 0x00f0) << 4) + (b & 0x000f) -
+ cmd_delta2_32_bias;
+ else
+ *pcolor +=
+ ((b & 0xf800) << 5) + ((b & 0x07e0) << 3) +
+ (b & 0x001f) - cmd_delta2_24_bias;
+ }
+ if_debug1('L', " 0x%lx\n", *pcolor);
+ continue;
+ case cmd_opv_set_copy_color:
+ state.color_is_alpha = 0;
+ if_debug0('L', "\n");
+ continue;
+ case cmd_opv_set_copy_alpha:
+ state.color_is_alpha = 1;
+ if_debug0('L', "\n");
+ continue;
+ default:
+ goto bad_op;
+ }
+ /*NOTREACHED */
+ case cmd_op_set_color0 >> 4:
+ pcolor = &set_colors[0];
+ goto set_color;
+ case cmd_op_set_color1 >> 4:
+ pcolor = &set_colors[1];
+ set_color:set_colors = state.colors;
+ switch (op & 0xf) {
+ case 0:
+ break;
+ case 15: /* special handling because this may */
+ /* require more bits than depth */
+ *pcolor = gx_no_color_index;
+ goto setc;
+ default:
+ switch (dev_depth_bytes) {
+ case 4:
+ {
+ gx_color_index b =
+ ((gx_color_index) (op & 0xf) << 8) + *cbp++;
+
+ *pcolor +=
+ ((b & 07000) << 15) + ((b & 0700) << 10) +
+ ((b & 070) << 5) + (b & 7) -
+ cmd_delta1_32_bias;
+ goto setc;
+ }
+ case 3:
+ {
+ gx_color_index b = *cbp++;
+
+ *pcolor +=
+ ((gx_color_index) (op & 0xf) << 16) +
+ ((b & 0xf0) << 4) + (b & 0x0f) -
+ cmd_delta1_24_bias;
+ goto setc;
+ }
+ case 2:
+ break;
+ case 1:
+ *pcolor += (gx_color_index) (op & 0xf) - 8;
+ goto setc;
+ }
+ }
+ {
+ gx_color_index color = 0;
+
+ switch (dev_depth_bytes) {
+ case 4:
+ color |= (gx_color_index) * cbp++ << 24;
+ case 3:
+ color |= (gx_color_index) * cbp++ << 16;
+ case 2:
+ color |= (gx_color_index) * cbp++ << 8;
+ case 1:
+ color |= (gx_color_index) * cbp++;
+ }
+ *pcolor = color;
+ }
+ setc:if_debug1('L', " 0x%lx\n", *pcolor);
+ continue;
+ case cmd_op_fill_rect >> 4:
+ case cmd_op_tile_rect >> 4:
+ cbp = cmd_read_rect(op, &state.rect, cbp);
+ break;
+ case cmd_op_fill_rect_short >> 4:
+ case cmd_op_tile_rect_short >> 4:
+ state.rect.x += *cbp + cmd_min_short;
+ state.rect.width += cbp[1] + cmd_min_short;
+ if (op & 0xf) {
+ state.rect.height += (op & 0xf) + cmd_min_dxy_tiny;
+ cbp += 2;
+ } else {
+ state.rect.y += cbp[2] + cmd_min_short;
+ state.rect.height += cbp[3] + cmd_min_short;
+ cbp += 4;
+ }
+ break;
+ case cmd_op_fill_rect_tiny >> 4:
+ case cmd_op_tile_rect_tiny >> 4:
+ if (op & 8)
+ state.rect.x += state.rect.width;
+ else {
+ int txy = *cbp++;
+
+ state.rect.x += (txy >> 4) + cmd_min_dxy_tiny;
+ state.rect.y += (txy & 0xf) + cmd_min_dxy_tiny;
+ }
+ state.rect.width += (op & 7) + cmd_min_dw_tiny;
+ break;
+ case cmd_op_copy_mono >> 4:
+ depth = 1;
+ goto copy;
+ case cmd_op_copy_color_alpha >> 4:
+ if (state.color_is_alpha) {
+ if (!(op & 8))
+ depth = *cbp++;
+ } else
+ depth = dev_depth;
+ copy:cmd_getw(state.rect.x, cbp);
+ cmd_getw(state.rect.y, cbp);
+ if (op & 8) { /* Use the current "tile". */
+#ifdef DEBUG
+ if (state_slot->index != state.tile_index) {
+ lprintf2("state_slot->index = %d, state.tile_index = %d!\n",
+ state_slot->index,
+ state.tile_index);
+ code = gs_note_error(gs_error_ioerror);
+ goto out;
+ }
+#endif
+ depth = state_slot->cb_depth;
+ state.rect.width = state_slot->width;
+ state.rect.height = state_slot->height;
+ raster = state_slot->cb_raster;
+ source = (byte *) (state_slot + 1);
+ } else { /* Read width, height, bits. */
+ /* depth was set already. */
+ uint width_bits, width_bytes;
+ uint bytes;
+
+ cmd_getw(state.rect.width, cbp);
+ cmd_getw(state.rect.height, cbp);
+ width_bits = state.rect.width * depth;
+ bytes =
+ clist_bitmap_bytes(width_bits,
+ state.rect.height,
+ op & 3, &width_bytes,
+ (uint *)&raster);
+ /* copy_mono and copy_color/alpha */
+ /* ensure that the bits will fit in a single buffer, */
+ /* even after decompression if compressed. */
+#ifdef DEBUG
+ if (bytes > cbuf_size) {
+ lprintf6("bitmap size exceeds buffer! width=%d raster=%d height=%d\n file pos %ld buf pos %d/%d\n",
+ state.rect.width, raster,
+ state.rect.height,
+ stell(s), (int)(cbp - cbuf.data),
+ (int)(cbuf.end - cbuf.data));
+ code = gs_note_error(gs_error_ioerror);
+ goto out;
+ }
+#endif
+ if (op & 3) { /* Decompress the image data. */
+ stream_cursor_read r;
+ stream_cursor_write w;
+
+ /* We don't know the data length a priori, */
+ /* so to be conservative, we read */
+ /* the uncompressed size. */
+ uint cleft = cbuf.end - cbp;
+
+ if (cleft < bytes) {
+ uint nread = cbuf_size - cleft;
+
+ memmove(cbuf.data, cbp, cleft);
+ cbuf.end_status = sgets(s, cbuf.data + cleft, nread, &nread);
+ set_cb_end(&cbuf, cbuf.data + cleft + nread);
+ cbp = cbuf.data;
+ }
+ r.ptr = cbp - 1;
+ r.limit = cbuf.end - 1;
+ w.ptr = data_bits - 1;
+ w.limit = w.ptr + data_bits_size;
+ switch (op & 3) {
+ case cmd_compress_rle:
+ {
+ stream_RLD_state sstate;
+
+ clist_rld_init(&sstate);
+ /* The process procedure can't fail. */
+ (*s_RLD_template.process)
+ ((stream_state *)&sstate, &r, &w, true);
+ }
+ break;
+ case cmd_compress_cfe:
+ {
+ stream_CFD_state sstate;
+
+ clist_cfd_init(&sstate,
+ width_bytes << 3 /*state.rect.width */ ,
+ state.rect.height, mem);
+ /* The process procedure can't fail. */
+ (*s_CFD_template.process)
+ ((stream_state *)&sstate, &r, &w, true);
+ (*s_CFD_template.release)
+ ((stream_state *)&sstate);
+ }
+ break;
+ default:
+ goto bad_op;
+ }
+ cbp = r.ptr + 1;
+ source = data_bits;
+ } else if (state.rect.height > 1 &&
+ width_bytes != raster
+ ) {
+ source = data_bits;
+ cbp = cmd_read_short_bits(&cbuf, source, width_bytes,
+ state.rect.height,
+ raster, cbp);
+ } else {
+ cmd_read(cbuf.data, bytes, cbp);
+ source = cbuf.data;
+ }
+#ifdef DEBUG
+ if (gs_debug_c('L')) {
+ dprintf2(" depth=%d, data_x=%d\n",
+ depth, data_x);
+ cmd_print_bits(source, state.rect.width,
+ state.rect.height, raster);
+ }
+#endif
+ }
+ break;
+ case cmd_op_delta_tile_index >> 4:
+ state.tile_index += (int)(op & 0xf) - 8;
+ goto sti;
+ case cmd_op_set_tile_index >> 4:
+ state.tile_index =
+ ((op & 0xf) << 8) + *cbp++;
+ sti:state_slot =
+ (tile_slot *) (cdev->chunk.data +
+ cdev->tile_table[state.tile_index].offset);
+ if_debug2('L', " index=%u offset=%lu\n",
+ state.tile_index,
+ cdev->tile_table[state.tile_index].offset);
+ state_tile.data = (byte *) (state_slot + 1);
+ stp:state_tile.size.x = state_slot->width;
+ state_tile.size.y = state_slot->height;
+ state_tile.raster = state_slot->cb_raster;
+ state_tile.rep_width = state_tile.size.x /
+ state_slot->x_reps;
+ state_tile.rep_height = state_tile.size.y /
+ state_slot->y_reps;
+ state_tile.rep_shift = state_slot->rep_shift;
+ state_tile.shift = state_slot->shift;
+ set_phase:tile_phase.x =
+ (state.tile_phase.x + x0) % state_tile.size.x;
+ /*
+ * The true tile height for shifted tiles is not
+ * size.y: see gxbitmap.h for the computation.
+ */
+ {
+ int full_height;
+
+ if (state_tile.shift == 0)
+ full_height = state_tile.size.y;
+ else
+ full_height = state_tile.rep_height *
+ (state_tile.rep_width /
+ igcd(state_tile.rep_shift,
+ state_tile.rep_width));
+ tile_phase.y =
+ (state.tile_phase.y + y0) % full_height;
+ }
+ gx_imager_setscreenphase(&imager_state,
+ -(state.tile_phase.x + x0),
+ -(state.tile_phase.y + y0),
+ gs_color_select_all);
+ continue;
+ case cmd_op_misc2 >> 4:
+ switch (op) {
+ case cmd_opv_set_flatness:
+ cmd_get_value(imager_state.flatness, cbp);
+ if_debug1('L', " %g\n", imager_state.flatness);
+ continue;
+ case cmd_opv_set_fill_adjust:
+ cmd_get_value(imager_state.fill_adjust.x, cbp);
+ cmd_get_value(imager_state.fill_adjust.y, cbp);
+ if_debug2('L', " (%g,%g)\n",
+ fixed2float(imager_state.fill_adjust.x),
+ fixed2float(imager_state.fill_adjust.y));
+ continue;
+ case cmd_opv_set_ctm:
+ {
+ gs_matrix mat;
+
+ cbp = cmd_read_matrix(&mat, cbp);
+ mat.tx -= x0;
+ mat.ty -= y0;
+ gs_imager_setmatrix(&imager_state, &mat);
+ if_debug6('L', " [%g %g %g %g %g %g]\n",
+ mat.xx, mat.xy, mat.yx, mat.yy,
+ mat.tx, mat.ty);
+ }
+ continue;
+ case cmd_opv_set_line_width:
+ {
+ float width;
+
+ cmd_get_value(width, cbp);
+ if_debug1('L', " %g\n", width);
+ gx_set_line_width(&imager_state.line_params, width);
+ }
+ continue;
+ case cmd_opv_set_misc2:
+ {
+ uint cb = *cbp;
+
+ switch (cb >> 6) {
+ case cmd_set_misc2_cap_join >> 6:
+ imager_state.line_params.cap =
+ (gs_line_cap) ((cb >> 3) & 7);
+ imager_state.line_params.join =
+ (gs_line_join) (cb & 7);
+ if_debug2('L', " cap=%d join=%d\n",
+ imager_state.line_params.cap,
+ imager_state.line_params.join);
+ break;
+ case cmd_set_misc2_ac_op_sa >> 6:
+ imager_state.accurate_curves =
+ (cb & 4) != 0;
+ imager_state.overprint = (cb & 2) != 0;
+ imager_state.stroke_adjust = cb & 1;
+ if_debug3('L', " AC=%d OP=%d SA=%d\n",
+ imager_state.accurate_curves,
+ imager_state.overprint,
+ imager_state.stroke_adjust);
+ break;
+ case cmd_set_misc2_notes >> 6:
+ notes = (segment_notes) (cb & 0x3f);
+ if_debug1('L', " notes=%d\n", notes);
+ break;
+ case cmd_set_misc2_alpha >> 6:
+ memcpy(&imager_state.alpha, cbp + 1,
+ sizeof(imager_state.alpha));
+ cbp += sizeof(imager_state.alpha);
+ break;
+ default:
+ goto bad_op;
+ }
+ }
+ cbp++;
+ continue;
+ case cmd_opv_set_miter_limit:
+ {
+ float limit;
+
+ cmd_get_value(limit, cbp);
+ if_debug1('L', " %g\n", limit);
+ gx_set_miter_limit(&imager_state.line_params, limit);
+ }
+ continue;
+ case cmd_opv_set_dash:
+ {
+ int nb = *cbp++;
+ int n = nb & 0x3f;
+ float dot_length, offset;
+
+ cmd_get_value(dot_length, cbp);
+ cmd_get_value(offset, cbp);
+ memcpy(dash_pattern, cbp, n * sizeof(float));
+
+ gx_set_dash(&imager_state.line_params.dash,
+ dash_pattern, n, offset,
+ NULL);
+ gx_set_dash_adapt(&imager_state.line_params.dash,
+ (nb & 0x80) != 0);
+ gx_set_dot_length(&imager_state.line_params,
+ dot_length,
+ (nb & 0x40) != 0);
+#ifdef DEBUG
+ if (gs_debug_c('L')) {
+ int i;
+
+ dprintf4(" dot=%g(mode %d) adapt=%d offset=%g [",
+ dot_length,
+ (nb & 0x40) != 0,
+ (nb & 0x80) != 0, offset);
+ for (i = 0; i < n; ++i)
+ dprintf1("%g ", dash_pattern[i]);
+ dputs("]\n");
+ }
+#endif
+ cbp += n * sizeof(float);
+ }
+ break;
+ case cmd_opv_enable_clip:
+ pcpath = (use_clip ? &clip_path : NULL);
+ if_debug0('L', "\n");
+ break;
+ case cmd_opv_disable_clip:
+ pcpath = NULL;
+ if_debug0('L', "\n");
+ break;
+ case cmd_opv_begin_clip:
+ pcpath = NULL;
+ if_debug0('L', "\n");
+ code = gx_cpath_reset(&clip_path);
+ if (code < 0)
+ goto out;
+ gx_cpath_accum_begin(&clip_accum, mem);
+ gx_cpath_accum_set_cbox(&clip_accum,
+ &target_box);
+ tdev = (gx_device *)&clip_accum;
+ clip_save.lop_enabled = state.lop_enabled;
+ clip_save.fill_adjust =
+ imager_state.fill_adjust;
+ state.lop_enabled = false;
+ imager_state.log_op = lop_default;
+ imager_state.fill_adjust.x =
+ imager_state.fill_adjust.y = fixed_half;
+ break;
+ case cmd_opv_end_clip:
+ if_debug0('L', "\n");
+ gx_cpath_accum_end(&clip_accum, &clip_path);
+ gx_cpath_set_outside(&clip_path, *cbp++);
+ tdev = target;
+ /*
+ * If the entire band falls within the clip
+ * path, no clipping is needed.
+ */
+ {
+ gs_fixed_rect cbox;
+
+ gx_cpath_inner_box(&clip_path, &cbox);
+ use_clip =
+ !(cbox.p.x <= target_box.p.x &&
+ cbox.q.x >= target_box.q.x &&
+ cbox.p.y <= target_box.p.y &&
+ cbox.q.y >= target_box.q.y);
+ }
+ pcpath = (use_clip ? &clip_path : NULL);
+ state.lop_enabled = clip_save.lop_enabled;
+ imager_state.log_op =
+ (state.lop_enabled ? state.lop :
+ lop_default);
+ imager_state.fill_adjust =
+ clip_save.fill_adjust;
+ break;
+ case cmd_opv_set_color_space:
+ {
+ byte b = *cbp++;
+ int index = b >> 4;
+
+ if_debug2('L', " %d%s\n", index,
+ (b & 8 ? " (indexed)" : ""));
+ switch (index) {
+ case gs_color_space_index_DeviceGray:
+ pcs = gs_cspace_DeviceGray(&imager_state);
+ break;
+ case gs_color_space_index_DeviceRGB:
+ pcs = gs_cspace_DeviceRGB(&imager_state);
+ break;
+ case gs_color_space_index_DeviceCMYK:
+ pcs = gs_cspace_DeviceCMYK(&imager_state);
+ break;
+ default:
+ goto bad_op; /* others are NYI */
+ }
+ if (b & 8) {
+#if 0 /****************/
+ int num_comp =
+ gs_color_space_num_components(pcs);
+
+ /****** SET map ******/
+#endif /****************/
+ color_space.type =
+ &gs_color_space_type_Indexed;
+ color_space.params.indexed.base_space.type =
+ pcs->type;
+ cmd_getw(color_space.params.indexed.hival,
+ cbp);
+ color_space.params.indexed.use_proc =
+ (b & 4) != 0;
+ pcs = &color_space;
+ }
+ }
+ break;
+ case cmd_opv_begin_image:
+ cbuf.ptr = cbp;
+ code = read_begin_image(&cbuf, &image,
+ &image_num_planes,
+ &image_rect, pcs);
+ cbp = cbuf.ptr;
+ if (code < 0)
+ goto out;
+ {
+ gx_drawing_color devc;
+
+ color_set_pure(&devc, state.colors[1]);
+ code = (*dev_proc(tdev, begin_image))
+ (tdev, &imager_state, &image, image.format,
+ &image_rect, &devc, pcpath, mem,
+ &image_info);
+ if (code < 0)
+ goto out;
+ }
+ break;
+ case cmd_opv_image_data:
+ {
+ uint height;
+
+ cmd_getw(height, cbp);
+ if (height == 0) {
+ if_debug0('L', " done image\n");
+ code = gx_image_end(image_info, true);
+ } else {
+ uint bytes_per_plane, nbytes;
+ const byte *data;
+ byte *data_on_heap = 0;
+ const byte *planes[64];
+
+/****** DOESN'T HANDLE #PLANES YET *****/
+
+ cmd_getw(bytes_per_plane, cbp);
+ if_debug2('L', " height=%u raster=%u\n",
+ height, bytes_per_plane);
+ nbytes = bytes_per_plane *
+ image_num_planes * height;
+ if ( cbuf.end - cbp < nbytes)
+ cbp = top_up_cbuf(&cbuf, cbp);
+ if (cbuf.end - cbp >= nbytes) {
+ data = cbp;
+ cbp += nbytes;
+ } else {
+ uint cleft = cbuf.end - cbp;
+ uint rleft = nbytes - cleft;
+ byte *rdata;
+
+ if (nbytes > cbuf.end - cbuf.data) { /* Allocate a separate buffer. */
+ rdata = data_on_heap =
+ gs_alloc_bytes(mem, nbytes,
+ "clist image_data");
+ if (rdata == 0) {
+ code = gs_note_error(gs_error_VMerror);
+ goto out;
+ }
+ } else
+ rdata = cbuf.data;
+ memmove(rdata, cbp, cleft);
+ sgets(s, rdata + cleft, rleft,
+ &rleft);
+ data = rdata;
+ cbp = cbuf.end; /* force refill */
+ }
+#ifdef DEBUG
+ if (gs_debug_c('L'))
+ cmd_print_bits(data, image_rect.q.x -
+ image_rect.p.x,
+ image_num_planes * height,
+ bytes_per_plane);
+#endif
+ {
+ int plane;
+
+ for (plane = 0;
+ plane < image_num_planes;
+ ++plane
+ )
+ planes[plane] = data +
+ bytes_per_plane * height * plane;
+ }
+ code = gx_image_data(image_info, planes,
+ data_x, bytes_per_plane,
+ height);
+ if (data_on_heap)
+ gs_free_object(mem, data_on_heap,
+ "clist image_data");
+ data_x = 0;
+ }
+ }
+ if (code < 0)
+ goto out;
+ continue;
+ case cmd_opv_set_color:
+ {
+#define dcb dev_color.colors.colored.c_base
+#define dcl dev_color.colors.colored.c_level
+ byte b = *cbp++;
+ int i;
+
+ switch (b >> 4) {
+ case 0:
+ dcb[0] = (b >> 3) & 1;
+ dcb[1] = (b >> 2) & 1;
+ dcb[2] = (b >> 1) & 1;
+ dcb[3] = b & 1;
+ break;
+ case 1:
+ dcb[0] = ((b & 0xf) << 1) + (*cbp >> 7);
+ dcb[1] = (*cbp >> 2) & 0x1f;
+ dcb[2] = ((*cbp & 3) << 3) + (cbp[1] >> 5);
+ dcb[3] = cbp[1] & 0x1f;
+ cbp += 2;
+ break;
+ default:
+ goto bad_op;
+ }
+ for (i = 0; i < imager_state.dev_ht->num_comp; ++i)
+ cmd_getw(dcl[i], cbp);
+ if_debug10('L', " format %d num_comp=%d base=(%u,%u,%u,%u) level=(%u,%u,%u,%u)\n",
+ b >> 4,
+ imager_state.dev_ht->num_comp,
+ dcb[0], dcb[1], dcb[2], dcb[3],
+ dcl[0], dcl[1], dcl[2], dcl[3]);
+ color_finish_set_cmyk_halftone(&dev_color,
+ imager_state.dev_ht);
+#undef dcb
+#undef dcl
+ }
+ continue;
+ case cmd_opv_put_params:
+ cbuf.ptr = cbp;
+ code = read_put_params(&cbuf, cdev, mem);
+ cbp = cbuf.ptr;
+ if (code > 0)
+ break; /* empty list */
+ if (code < 0)
+ goto out;
+ if (playback_action == playback_action_setup)
+ goto out;
+ break;
+ default:
+ goto bad_op;
+ }
+ continue;
+ case cmd_op_segment >> 4:
+ {
+ fixed vs[6];
+ int i, code;
+
+ if (!in_path) {
+ ppos.x = int2fixed(state.rect.x);
+ ppos.y = int2fixed(state.rect.y);
+ if_debug2('L', " (%d,%d)", state.rect.x,
+ state.rect.y);
+ notes = sn_none;
+ in_path = true;
+ }
+ for (i = 0;
+ i < clist_segment_op_num_operands[op & 0xf];
+ ++i
+ ) {
+ fixed v;
+ int b = *cbp;
+
+ switch (b >> 5) {
+ case 0:
+ case 1:
+ vs[i++] =
+ ((fixed) ((b ^ 0x20) - 0x20) << 13) +
+ ((int)cbp[1] << 5) + (cbp[2] >> 3);
+ if_debug1('L', " %g", fixed2float(vs[i - 1]));
+ cbp += 2;
+ v = (int)((*cbp & 7) ^ 4) - 4;
+ break;
+ case 2:
+ case 3:
+ v = (b ^ 0x60) - 0x20;
+ break;
+ case 4:
+ case 5:
+ /*
+ * Without the following cast, C's
+ * brain-damaged coercion rules cause the
+ * result to be considered unsigned, and not
+ * sign-extended on machines where
+ * sizeof(long) > sizeof(int).
+ */
+ v = (((b ^ 0xa0) - 0x20) << 8) + (int)*++cbp;
+ break;
+ case 6:
+ v = (b ^ 0xd0) - 0x10;
+ vs[i] =
+ ((v << 8) + cbp[1]) << (_fixed_shift - 2);
+ if_debug1('L', " %g", fixed2float(vs[i]));
+ cbp += 2;
+ continue;
+ default /*case 7 */ :
+ v = (int)(*++cbp ^ 0x80) - 0x80;
+ for (b = 0; b < sizeof(fixed) - 3; ++b)
+ v = (v << 8) + *++cbp;
+ break;
+ }
+ cbp += 3;
+ /* Absent the cast in the next statement, */
+ /* the Borland C++ 4.5 compiler incorrectly */
+ /* sign-extends the result of the shift. */
+ vs[i] = (v << 16) + (uint) (cbp[-2] << 8) + cbp[-1];
+ if_debug1('L', " %g", fixed2float(vs[i]));
+ }
+ if_debug0('L', "\n");
+ code = clist_decode_segment(&path, op, vs, &ppos,
+ x0, y0, notes);
+ if (code < 0)
+ goto out;
+ }
+ continue;
+ case cmd_op_path >> 4:
+ {
+ gx_device_color devc;
+ gx_device_color *pdevc;
+ gx_ht_tile ht_tile;
+
+ if_debug0('L', "\n");
+ switch (op) {
+ case cmd_opv_fill:
+ fill_params.rule = gx_rule_winding_number;
+ goto fill_pure;
+ case cmd_opv_eofill:
+ fill_params.rule = gx_rule_even_odd;
+ fill_pure:color_set_pure(&devc, state.colors[1]);
+ pdevc = &devc;
+ goto fill;
+ case cmd_opv_htfill:
+ fill_params.rule = gx_rule_winding_number;
+ goto fill_ht;
+ case cmd_opv_hteofill:
+ fill_params.rule = gx_rule_even_odd;
+ fill_ht:ht_tile.tiles = state_tile;
+ color_set_binary_tile(&devc,
+ state.tile_colors[0],
+ state.tile_colors[1],
+ &ht_tile);
+ pdevc = &devc;
+ pdevc->phase = tile_phase;
+ goto fill;
+ case cmd_opv_colorfill:
+ fill_params.rule = gx_rule_winding_number;
+ goto fill_color;
+ case cmd_opv_coloreofill:
+ fill_params.rule = gx_rule_even_odd;
+ fill_color:pdevc = &dev_color;
+ pdevc->phase = tile_phase;
+ code =
+ gx_color_load(pdevc, &imager_state, tdev);
+ if (code < 0)
+ break;
+ fill:fill_params.adjust = imager_state.fill_adjust;
+ fill_params.flatness = imager_state.flatness;
+ code = gx_fill_path_only(&path, tdev,
+ &imager_state,
+ &fill_params,
+ pdevc, pcpath);
+ break;
+ case cmd_opv_stroke:
+ color_set_pure(&devc, state.colors[1]);
+ pdevc = &devc;
+ goto stroke;
+ case cmd_opv_htstroke:
+ ht_tile.tiles = state_tile;
+ color_set_binary_tile(&devc,
+ state.tile_colors[0],
+ state.tile_colors[1],
+ &ht_tile);
+ pdevc = &devc;
+ pdevc->phase = tile_phase;
+ goto stroke;
+ case cmd_opv_colorstroke:
+ pdevc = &dev_color;
+ pdevc->phase = tile_phase;
+ code =
+ gx_color_load(pdevc, &imager_state, tdev);
+ if (code < 0)
+ break;
+ stroke:stroke_params.flatness = imager_state.flatness;
+ code = gx_stroke_path_only(&path,
+ (gx_path *) 0, tdev,
+ &imager_state, &stroke_params,
+ pdevc, pcpath);
+ break;
+ default:
+ goto bad_op;
+ }
+ }
+ if (in_path) { /* path might be empty! */
+ state.rect.x = fixed2int_var(ppos.x);
+ state.rect.y = fixed2int_var(ppos.y);
+ in_path = false;
+ }
+ gx_path_free(&path, "clist_render_band");
+ gx_path_init_local(&path, mem);
+ if (code < 0)
+ goto out;
+ continue;
+ default:
+ bad_op:lprintf5("Bad op %02x band y0 = %d file pos %ld buf pos %d/%d\n",
+ op, y0, stell(s), (int)(cbp - cbuf.data), (int)(cbuf.end - cbuf.data));
+ {
+ const byte *pp;
+
+ for (pp = cbuf.data; pp < cbuf.end; pp += 10) {
+ dlprintf1("%4d:", (int)(pp - cbuf.data));
+ dprintf10(" %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ pp[0], pp[1], pp[2], pp[3], pp[4],
+ pp[5], pp[6], pp[7], pp[8], pp[9]);
+ }
+ }
+ code = gs_note_error(gs_error_Fatal);
+ goto out;
+ }
+ if_debug4('L', " x=%d y=%d w=%d h=%d\n",
+ state.rect.x, state.rect.y, state.rect.width,
+ state.rect.height);
+ switch (op >> 4) {
+ case cmd_op_fill_rect >> 4:
+ case cmd_op_fill_rect_short >> 4:
+ case cmd_op_fill_rect_tiny >> 4:
+ if (!state.lop_enabled) {
+ code = (*dev_proc(tdev, fill_rectangle))
+ (tdev, state.rect.x - x0, state.rect.y - y0,
+ state.rect.width, state.rect.height,
+ state.colors[1]);
+ break;
+ }
+ source = NULL;
+ data_x = 0;
+ raster = 0;
+ colors[0] = colors[1] = state.colors[1];
+ log_op = state.lop;
+ pcolor = colors;
+ do_rop:code = (*dev_proc(tdev, strip_copy_rop))
+ (tdev, source, data_x, raster, gx_no_bitmap_id,
+ pcolor, &state_tile,
+ (state.tile_colors[0] == gx_no_color_index &&
+ state.tile_colors[1] == gx_no_color_index ?
+ NULL : state.tile_colors),
+ state.rect.x - x0, state.rect.y - y0,
+ state.rect.width - data_x, state.rect.height,
+ tile_phase.x, tile_phase.y, log_op);
+ data_x = 0;
+ break;
+ case cmd_op_tile_rect >> 4:
+ case cmd_op_tile_rect_short >> 4:
+ case cmd_op_tile_rect_tiny >> 4:
+ /* Currently we don't use lop with tile_rectangle. */
+ code = (*dev_proc(tdev, strip_tile_rectangle))
+ (tdev, &state_tile,
+ state.rect.x - x0, state.rect.y - y0,
+ state.rect.width, state.rect.height,
+ state.tile_colors[0], state.tile_colors[1],
+ tile_phase.x, tile_phase.y);
+ break;
+ case cmd_op_copy_mono >> 4:
+ if (state.lop_enabled) {
+ pcolor = state.colors;
+ log_op = state.lop;
+ goto do_rop;
+ }
+ if ((op & cmd_copy_use_tile) || pcpath != NULL) { /*
+ * This call of copy_mono originated as a call
+ * of fill_mask.
+ */
+ gx_drawing_color dcolor;
+ gx_ht_tile ht_tile;
+
+ if (op & cmd_copy_ht_color) { /* Screwy C assignment rules don't allow: */
+ /* dcolor.colors = state.tile_colors; */
+ ht_tile.tiles = state_tile;
+ color_set_binary_tile(&dcolor,
+ state.tile_colors[0],
+ state.tile_colors[1], &ht_tile);
+ dcolor.phase = tile_phase;
+ } else {
+ color_set_pure(&dcolor, state.colors[1]);
+ }
+ code = (*dev_proc(tdev, fill_mask))
+ (tdev, source, data_x, raster, gx_no_bitmap_id,
+ state.rect.x - x0, state.rect.y - y0,
+ state.rect.width - data_x, state.rect.height,
+ &dcolor, 1, imager_state.log_op, pcpath);
+ } else
+ code = (*dev_proc(tdev, copy_mono))
+ (tdev, source, data_x, raster, gx_no_bitmap_id,
+ state.rect.x - x0, state.rect.y - y0,
+ state.rect.width - data_x, state.rect.height,
+ state.colors[0], state.colors[1]);
+ data_x = 0;
+ break;
+ case cmd_op_copy_color_alpha >> 4:
+ if (state.color_is_alpha) {
+/****** CAN'T DO ROP WITH ALPHA ******/
+ code = (*dev_proc(tdev, copy_alpha))
+ (tdev, source, data_x, raster, gx_no_bitmap_id,
+ state.rect.x - x0, state.rect.y - y0,
+ state.rect.width - data_x, state.rect.height,
+ state.colors[1], depth);
+ } else {
+ if (state.lop_enabled) {
+ pcolor = NULL;
+ log_op = state.lop;
+ goto do_rop;
+ }
+ code = (*dev_proc(tdev, copy_color))
+ (tdev, source, data_x, raster, gx_no_bitmap_id,
+ state.rect.x - x0, state.rect.y - y0,
+ state.rect.width - data_x, state.rect.height);
+ }
+ data_x = 0;
+ break;
+ default: /* can't happen */
+ goto bad_op;
+ }
+ }
+ /* Clean up before we exit. */
+ out:gx_cpath_free(&clip_path, "clist_render_band exit");
+ gx_path_free(&path, "clist_render_band exit");
+ if (imager_state.ht_cache)
+ gx_ht_free_cache(mem, imager_state.ht_cache);
+ gx_device_halftone_release(&dev_ht, mem);
+ gs_imager_state_release(&imager_state);
+ gs_free_object(mem, data_bits, "clist_playback_band(data_bits)");
+ if (code < 0)
+ return_error(code);
+ /* Check whether we have more pages to process. */
+ if (playback_action != playback_action_setup &&
+ (cbp < cbuf.end || !seofp(s))
+ )
+ goto in;
+ return code;
+}
+
+/* ---------------- Individual commands ---------------- */
+
+/*
+ * These single-use procedures implement a few large individual commands,
+ * primarily for readability but also to avoid overflowing compilers'
+ * optimization limits. They all take the command buffer as their first
+ * parameter (pcb), assume that the current buffer pointer is in pcb->ptr,
+ * and update it there.
+ */
+
+private int
+read_set_tile_size(command_buf_t *pcb, tile_slot *bits)
+{
+ const byte *cbp = pcb->ptr;
+ uint rep_width, rep_height;
+ byte bd = *cbp++;
+
+ bits->cb_depth = (bd & 31) + 1;
+ cmd_getw(rep_width, cbp);
+ cmd_getw(rep_height, cbp);
+ if (bd & 0x20) {
+ cmd_getw(bits->x_reps, cbp);
+ bits->width = rep_width * bits->x_reps;
+ } else {
+ bits->x_reps = 1;
+ bits->width = rep_width;
+ }
+ if (bd & 0x40) {
+ cmd_getw(bits->y_reps, cbp);
+ bits->height = rep_height * bits->y_reps;
+ } else {
+ bits->y_reps = 1;
+ bits->height = rep_height;
+ }
+ if (bd & 0x80)
+ cmd_getw(bits->rep_shift, cbp) /* MRS: No trailing ; */
+ else
+ bits->rep_shift = 0;
+ if_debug6('L', " depth=%d size=(%d,%d), rep_size=(%d,%d), rep_shift=%d\n",
+ bits->cb_depth, bits->width,
+ bits->height, rep_width,
+ rep_height, bits->rep_shift);
+ bits->shift =
+ (bits->rep_shift == 0 ? 0 :
+ (bits->rep_shift * (bits->height / rep_height)) % rep_width);
+ bits->cb_raster = bitmap_raster(bits->width * bits->cb_depth);
+ pcb->ptr = cbp;
+ return 0;
+}
+
+private int
+read_set_bits(command_buf_t *pcb, tile_slot *bits, int compress,
+ gx_clist_state *pcls, gx_strip_bitmap *tile, tile_slot **pslot,
+ gx_device_clist_reader *cdev, gs_memory_t *mem)
+{
+ const byte *cbp = pcb->ptr;
+ uint rep_width = bits->width / bits->x_reps;
+ uint rep_height = bits->height / bits->y_reps;
+ uint index;
+ ulong offset;
+ uint width_bits = rep_width * bits->cb_depth;
+ uint width_bytes;
+ uint raster;
+ uint bytes =
+ clist_bitmap_bytes(width_bits, rep_height,
+ compress |
+ (rep_width < bits->width ?
+ decompress_spread : 0) |
+ decompress_elsewhere,
+ &width_bytes,
+ (uint *)&raster);
+ byte *data;
+ tile_slot *slot;
+
+ cmd_getw(index, cbp);
+ cmd_getw(offset, cbp);
+ if_debug2('L', " index=%d offset=%lu\n", pcls->tile_index, offset);
+ pcls->tile_index = index;
+ cdev->tile_table[pcls->tile_index].offset = offset;
+ slot = (tile_slot *)(cdev->chunk.data + offset);
+ *pslot = slot;
+ *slot = *bits;
+ tile->data = data = (byte *)(slot + 1);
+#ifdef DEBUG
+ slot->index = pcls->tile_index;
+#endif
+ if (compress) {
+ /*
+ * Decompress the image data. We'd like to share this code with the
+ * similar code in copy_*, but right now we don't see how.
+ */
+ stream_cursor_read r;
+ stream_cursor_write w;
+ /*
+ * We don't know the data length a priori, so to be conservative, we
+ * read the uncompressed size.
+ */
+ uint cleft = pcb->end - cbp;
+
+ if (cleft < bytes) {
+ uint nread = cbuf_size - cleft;
+
+ memmove(pcb->data, cbp, cleft);
+ pcb->end_status = sgets(pcb->s, pcb->data + cleft, nread, &nread);
+ set_cb_end(pcb, pcb->data + cleft + nread);
+ cbp = pcb->data;
+ }
+ r.ptr = cbp - 1;
+ r.limit = pcb->end - 1;
+ w.ptr = data - 1;
+ w.limit = w.ptr + bytes;
+ switch (compress) {
+ case cmd_compress_rle:
+ {
+ stream_RLD_state sstate;
+
+ clist_rld_init(&sstate);
+ (*s_RLD_template.process)
+ ((stream_state *)&sstate, &r, &w, true);
+ }
+ break;
+ case cmd_compress_cfe:
+ {
+ stream_CFD_state sstate;
+
+ clist_cfd_init(&sstate,
+ width_bytes << 3 /*width_bits */ ,
+ rep_height, mem);
+ (*s_CFD_template.process)
+ ((stream_state *)&sstate, &r, &w, true);
+ (*s_CFD_template.release)
+ ((stream_state *)&sstate);
+ }
+ break;
+ default:
+ return_error(gs_error_unregistered);
+ }
+ cbp = r.ptr + 1;
+ } else if (rep_height > 1 && width_bytes != bits->cb_raster) {
+ cbp = cmd_read_short_bits(pcb, data,
+ width_bytes, rep_height,
+ bits->cb_raster, cbp);
+ } else {
+ cbp = cmd_read_data(pcb, data, bytes, cbp);
+ }
+ if (bits->width > rep_width)
+ bits_replicate_horizontally(data,
+ rep_width * bits->cb_depth, rep_height,
+ bits->cb_raster,
+ bits->width * bits->cb_depth,
+ bits->cb_raster);
+ if (bits->height > rep_height)
+ bits_replicate_vertically(data,
+ rep_height, bits->cb_raster,
+ bits->height);
+#ifdef DEBUG
+ if (gs_debug_c('L'))
+ cmd_print_bits(data, bits->width, bits->height, bits->cb_raster);
+#endif
+ pcb->ptr = cbp;
+ return 0;
+}
+
+private int
+read_set_ht_order(command_buf_t *pcb, gx_device_halftone *pdht,
+ gx_ht_order **pporder, gs_memory_t *mem)
+{
+ const byte *cbp = pcb->ptr;
+ gx_ht_order *porder;
+ uint *levels;
+ gx_ht_bit *bits;
+ int index;
+ gx_ht_order new_order;
+
+ cmd_getw(index, cbp);
+ if (index == 0)
+ porder = &pdht->order;
+ else {
+ gx_ht_order_component *pcomp = &pdht->components[index - 1];
+
+ cmd_getw(pcomp->cname, cbp);
+ if_debug1('L', " cname=%lu", (ulong) pcomp->cname);
+ porder = &pcomp->corder;
+ }
+ *pporder = porder;
+ new_order = *porder;
+ cmd_getw(new_order.width, cbp);
+ cmd_getw(new_order.height, cbp);
+ cmd_getw(new_order.raster, cbp);
+ cmd_getw(new_order.shift, cbp);
+ cmd_getw(new_order.num_levels, cbp);
+ cmd_getw(new_order.num_bits, cbp);
+ pcb->ptr = cbp;
+ if_debug7('L', " index=%d size=(%d,%d) raster=%d shift=%d num_levels=%d num_bits=%d\n",
+ index, new_order.width, new_order.height,
+ new_order.raster, new_order.shift,
+ new_order.num_levels, new_order.num_bits);
+ levels = porder->levels;
+ bits = porder->bits;
+ /*
+ * Note that for resizing a byte array, the element size is 1 byte,
+ * not the element size given to alloc_byte_array!
+ */
+ if (new_order.num_levels > porder->num_levels) {
+ if (levels == 0)
+ levels = (uint *) gs_alloc_byte_array(mem, new_order.num_levels,
+ sizeof(*levels),
+ "ht order(levels)");
+ else
+ levels = gs_resize_object(mem, levels,
+ new_order.num_levels * sizeof(*levels),
+ "ht order(levels)");
+ if (levels == 0)
+ return_error(gs_error_VMerror);
+ /* Update porder in case we bail out. */
+ porder->levels = levels;
+ porder->num_levels = new_order.num_levels;
+ }
+ if (new_order.num_bits > porder->num_bits) {
+ if (bits == 0)
+ bits = (gx_ht_bit *) gs_alloc_byte_array(mem, new_order.num_bits,
+ sizeof(*bits),
+ "ht order(bits)");
+ else
+ bits = gs_resize_object(mem, bits,
+ new_order.num_bits * sizeof(*bits),
+ "ht order(bits)");
+ if (bits == 0)
+ return_error(gs_error_VMerror);
+ }
+ *porder = new_order;
+ porder->levels = levels;
+ porder->bits = bits;
+ porder->full_height = ht_order_full_height(porder);
+ return 0;
+}
+
+private int
+read_set_ht_data(command_buf_t *pcb, uint *pdata_index, gx_ht_order *porder,
+ gx_device_halftone *pdht, gs_halftone_type halftone_type,
+ gs_imager_state *pis, gx_device_clist_reader *cdev,
+ gs_memory_t *mem)
+{
+ const byte *cbp = pcb->ptr;
+ int n = *cbp++;
+
+ if (*pdata_index < porder->num_levels) { /* Setting levels */
+ byte *lptr = (byte *)(porder->levels + *pdata_index);
+
+ cbp = cmd_read_data(pcb, lptr, n * sizeof(*porder->levels), cbp);
+#ifdef DEBUG
+ if (gs_debug_c('L')) {
+ int i;
+
+ dprintf1(" levels[%u]", *pdata_index);
+ for (i = 0; i < n; ++i)
+ dprintf1(" %u",
+ porder->levels[*pdata_index + i]);
+ dputc('\n');
+ }
+#endif
+ } else { /* Setting bits */
+ byte *bptr = (byte *)
+ (porder->bits + (*pdata_index - porder->num_levels));
+
+ cbp = cmd_read_data(pcb, bptr, n * sizeof(*porder->bits), cbp);
+#ifdef DEBUG
+ if (gs_debug_c('L')) {
+ int i;
+
+ dprintf1(" bits[%u]", *pdata_index - porder->num_levels);
+ for (i = 0; i < n; ++i) {
+ const gx_ht_bit *pb =
+ &porder->bits[*pdata_index - porder->num_levels + i];
+
+ dprintf2(" (%u,0x%lx)",
+ pb->offset,
+ (ulong) pb->mask);
+ }
+ dputc('\n');
+ }
+#endif
+ }
+ *pdata_index += n;
+ /* If this is the end of the data, */
+ /* install the (device) halftone. */
+ if (porder ==
+ (pdht->components != 0 ?
+ &pdht->components[0].corder :
+ &pdht->order) &&
+ *pdata_index == porder->num_levels + porder->num_bits
+ ) { /* Make sure we have a halftone cache. */
+ uint i;
+
+ if (pis->ht_cache == 0) {
+ gx_ht_cache *pcache =
+ gx_ht_alloc_cache(mem,
+ porder->num_levels + 2,
+ gx_ht_cache_default_bits());
+
+ if (pcache == 0)
+ return_error(gs_error_VMerror);
+ pis->ht_cache = pcache;
+ }
+ for (i = 1; i < pdht->num_comp; ++i) {
+ gx_ht_order *pco = &pdht->components[i].corder;
+
+ if (!pco->cache) {
+ gx_ht_cache *pcache =
+ gx_ht_alloc_cache(mem, 1,
+ pco->raster * (pco->num_bits /
+ pco->width));
+
+ if (pcache == 0)
+ return_error(gs_error_VMerror);
+ pco->cache = pcache;
+ gx_ht_init_cache(pco->cache, pco);
+ }
+ }
+ if (pdht->num_comp) {
+ pdht->components[0].corder.cache = pis->ht_cache;
+ pdht->order = pdht->components[0].corder;
+ }
+ gx_imager_dev_ht_install(pis, pdht, halftone_type,
+ (const gx_device *)cdev);
+ }
+ pcb->ptr = cbp;
+ return 0;
+}
+
+private int
+read_begin_image(command_buf_t *pcb, gs_image_t *pim, int *pnum_planes,
+ gs_int_rect *prect, const gs_color_space *pcs)
+{
+ const byte *cbp = pcb->ptr;
+ byte b = *cbp++;
+ int bpci = b >> 5;
+ static const byte bpc[6] = {1, 1, 2, 4, 8, 12};
+ int num_components;
+ gs_image_format_t format;
+
+ if (bpci == 0)
+ gs_image_t_init_mask(pim, false);
+ else
+ gs_image_t_init(pim, pcs);
+ if (b & (1 << 4)) {
+ byte b2 = *cbp++;
+
+ format = b2 >> 6;
+ pim->Interpolate = (b2 & (1 << 5)) != 0;
+ pim->Alpha = (gs_image_alpha_t) ((b2 >> 3) & 3);
+ } else {
+ format = gs_image_format_chunky;
+ }
+ pim->format = format;
+ cmd_getw(pim->Width, cbp);
+ cmd_getw(pim->Height, cbp);
+ if_debug4('L', " BPCi=%d I=%d size=(%d,%d)",
+ bpci, (b & 0x10) != 0, pim->Width, pim->Height);
+ if (b & (1 << 3)) { /* Non-standard ImageMatrix */
+ cbp = cmd_read_matrix(
+ &pim->ImageMatrix, cbp);
+ if_debug6('L', " matrix=[%g %g %g %g %g %g]",
+ pim->ImageMatrix.xx, pim->ImageMatrix.xy,
+ pim->ImageMatrix.yx, pim->ImageMatrix.yy,
+ pim->ImageMatrix.tx, pim->ImageMatrix.ty);
+ } else {
+ pim->ImageMatrix.xx = pim->Width;
+ pim->ImageMatrix.xy = 0;
+ pim->ImageMatrix.yx = 0;
+ pim->ImageMatrix.yy = -pim->Height;
+ pim->ImageMatrix.tx = 0;
+ pim->ImageMatrix.ty = pim->Height;
+ }
+ pim->BitsPerComponent = bpc[bpci];
+ if (bpci == 0) {
+ num_components = 1;
+ } else {
+ pim->ColorSpace = pcs;
+ if (gs_color_space_get_index(pcs) == gs_color_space_index_Indexed) {
+ pim->Decode[0] = 0;
+ pim->Decode[1] = (1 << pim->BitsPerComponent) - 1;
+ } else {
+ static const float decode01[] = {
+ 0, 1, 0, 1, 0, 1, 0, 1, 0, 1
+ };
+
+ memcpy(pim->Decode, decode01, sizeof(pim->Decode));
+ }
+ num_components = gs_color_space_num_components(pcs);
+ }
+ switch (format) {
+ case gs_image_format_chunky:
+ *pnum_planes = 1;
+ break;
+ case gs_image_format_component_planar:
+ *pnum_planes = num_components;
+ break;
+ case gs_image_format_bit_planar:
+ *pnum_planes = num_components * pim->BitsPerComponent;
+ break;
+ default:
+ return_error(gs_error_unregistered);
+ }
+ if (b & (1 << 2)) { /* Non-standard Decode */
+ byte dflags = *cbp++;
+ int i;
+
+ for (i = 0; i < num_components * 2; dflags <<= 2, i += 2)
+ switch ((dflags >> 6) & 3) {
+ case 0: /* default */
+ break;
+ case 1: /* swapped default */
+ pim->Decode[i] = pim->Decode[i + 1];
+ pim->Decode[i + 1] = 0;
+ break;
+ case 3:
+ cmd_get_value(pim->Decode[i], cbp);
+ /* falls through */
+ case 2:
+ cmd_get_value(pim->Decode[i + 1], cbp);
+ }
+#ifdef DEBUG
+ if (gs_debug_c('L')) {
+ dputs(" decode=[");
+ for (i = 0; i < num_components * 2; ++i)
+ dprintf1("%g ", pim->Decode[i]);
+ dputc(']');
+ }
+#endif
+ }
+ pim->adjust = false;
+ if (b & (1 << 1)) {
+ if (pim->ImageMask)
+ pim->adjust = true;
+ else
+ pim->CombineWithColor = true;
+ if_debug1('L', " %s",
+ (pim->ImageMask ? " adjust" : " CWC"));
+ }
+ if (b & (1 << 0)) { /* Non-standard rectangle */
+ uint diff;
+
+ cmd_getw(prect->p.x, cbp);
+ cmd_getw(prect->p.y, cbp);
+ cmd_getw(diff, cbp);
+ prect->q.x = pim->Width - diff;
+ cmd_getw(diff, cbp);
+ prect->q.y = pim->Height - diff;
+ if_debug4('L', " rect=(%d,%d),(%d,%d)",
+ prect->p.x, prect->p.y,
+ prect->q.x, prect->q.y);
+ } else {
+ prect->p.x = 0;
+ prect->p.y = 0;
+ prect->q.x = pim->Width;
+ prect->q.y = pim->Height;
+ }
+ if_debug0('L', "\n");
+ pcb->ptr = cbp;
+ return 0;
+}
+
+private int
+read_put_params(command_buf_t *pcb, gx_device_clist_reader *cdev,
+ gs_memory_t *mem)
+{
+ const byte *cbp = pcb->ptr;
+ gs_c_param_list param_list;
+ uint cleft;
+ uint rleft;
+ bool alloc_data_on_heap = false;
+ byte *param_buf;
+ uint param_length;
+ int code = 0;
+
+ cmd_get_value(param_length, cbp);
+ if_debug1('L', " length=%d\n", param_length);
+ if (param_length == 0) {
+ code = 1; /* empty list */
+ goto out;
+ }
+
+ /* Make sure entire serialized param list is in cbuf */
+ /* + force void* alignment */
+ cbp = top_up_cbuf(pcb, cbp);
+ if (pcb->end - cbp >= param_length) {
+ param_buf = (byte *)cbp;
+ cbp += param_length;
+ } else {
+ /* NOTE: param_buf must be maximally aligned */
+ param_buf = gs_alloc_bytes(mem, param_length,
+ "clist put_params");
+ if (param_buf == 0) {
+ code = gs_note_error(gs_error_VMerror);
+ goto out;
+ }
+ alloc_data_on_heap = true;
+ cleft = pcb->end - cbp;
+ rleft = param_length - cleft;
+ memmove(param_buf, cbp, cleft);
+ pcb->end_status = sgets(pcb->s, param_buf + cleft, rleft, &rleft);
+ cbp = pcb->end; /* force refill */
+ }
+
+ /*
+ * Create a gs_c_param_list & expand into it.
+ * NB that gs_c_param_list doesn't copy objects into
+ * it, but rather keeps *pointers* to what's passed.
+ * That's OK because the serialized format keeps enough
+ * space to hold expanded versions of the structures,
+ * but this means we cannot deallocate source buffer
+ * until the gs_c_param_list is deleted.
+ */
+ gs_c_param_list_write(&param_list, mem);
+ code = gs_param_list_unserialize
+ ( (gs_param_list *)&param_list, param_buf );
+ if (code >= 0 && code != param_length)
+ code = gs_error_unknownerror; /* must match */
+ if (code >= 0) {
+ gs_c_param_list_read(&param_list);
+ code = (*dev_proc(cdev, put_params))
+ ((gx_device *)cdev, (gs_param_list *)&param_list);
+ }
+ gs_c_param_list_release(&param_list);
+ if (alloc_data_on_heap)
+ gs_free_object(mem, param_buf, "clist put_params");
+
+out:
+ pcb->ptr = cbp;
+ return code;
+}
+
+/* ---------------- Utilities ---------------- */
+
+/* Read and unpack a short bitmap */
+private const byte *
+cmd_read_short_bits(command_buf_t *pcb, byte *data, int width_bytes,
+ int height, uint raster, const byte *cbp)
+{
+ uint bytes = width_bytes * height;
+ const byte *pdata = data /*src*/ + bytes;
+ byte *udata = data /*dest*/ + height * raster;
+
+ cbp = cmd_read_data(pcb, data, width_bytes * height, cbp);
+ while (--height >= 0) {
+ udata -= raster, pdata -= width_bytes;
+ switch (width_bytes) {
+ default:
+ memmove(udata, pdata, width_bytes);
+ break;
+ case 6:
+ udata[5] = pdata[5];
+ case 5:
+ udata[4] = pdata[4];
+ case 4:
+ udata[3] = pdata[3];
+ case 3:
+ udata[2] = pdata[2];
+ case 2:
+ udata[1] = pdata[1];
+ case 1:
+ udata[0] = pdata[0];
+ case 0:; /* shouldn't happen */
+ }
+ }
+ return cbp;
+}
+
+/* Read a rectangle. */
+private const byte *
+cmd_read_rect(int op, gx_cmd_rect * prect, const byte * cbp)
+{
+ cmd_getw(prect->x, cbp);
+ if (op & 0xf)
+ prect->y += ((op >> 2) & 3) - 2;
+ else {
+ cmd_getw(prect->y, cbp);
+ }
+ cmd_getw(prect->width, cbp);
+ if (op & 0xf)
+ prect->height += (op & 3) - 2;
+ else {
+ cmd_getw(prect->height, cbp);
+ }
+ return cbp;
+}
+
+/* Read a transformation matrix. */
+private const byte *
+cmd_read_matrix(gs_matrix * pmat, const byte * cbp)
+{
+ byte b = *cbp++;
+ float coeff[6];
+ int i;
+
+ for (i = 0; i < 4; i += 2, b <<= 2)
+ if (!(b & 0xc0))
+ coeff[i] = coeff[i ^ 3] = 0.0;
+ else {
+ float value;
+
+ cmd_get_value(value, cbp);
+ coeff[i] = value;
+ switch ((b >> 6) & 3) {
+ case 1:
+ coeff[i ^ 3] = value;
+ break;
+ case 2:
+ coeff[i ^ 3] = -value;
+ break;
+ case 3:
+ cmd_get_value(coeff[i ^ 3], cbp);
+ }
+ }
+ for (; i < 6; ++i, b <<= 1)
+ if (b & 0x80) {
+ cmd_get_value(coeff[i], cbp);
+ } else
+ coeff[i] = 0.0;
+ pmat->xx = coeff[0];
+ pmat->xy = coeff[1];
+ pmat->yx = coeff[2];
+ pmat->yy = coeff[3];
+ pmat->tx = coeff[4];
+ pmat->ty = coeff[5];
+ return cbp;
+}
+
+/* Select a map for loading with data. */
+/* load = false is not possible for cmd_map_transfer*. */
+private int
+cmd_select_map(cmd_map_index map_index, bool load, gs_imager_state * pis,
+ gx_ht_order * porder, frac ** pmdata, uint * pcount, gs_memory_t * mem)
+{
+ gx_transfer_map *map;
+ gx_transfer_map **pmap;
+ const char *cname;
+
+ switch (map_index) {
+ case cmd_map_transfer:
+ if_debug0('L', " transfer");
+ map = pis->set_transfer.colored.gray;
+ pis->effective_transfer.indexed[0] =
+ pis->effective_transfer.indexed[1] =
+ pis->effective_transfer.indexed[2] =
+ pis->effective_transfer.indexed[3] =
+ map;
+ break;
+ case cmd_map_transfer_0:
+ case cmd_map_transfer_1:
+ case cmd_map_transfer_2:
+ case cmd_map_transfer_3:
+ {
+ int i = map_index - cmd_map_transfer_0;
+
+ if_debug1('L', " transfer[%d]", i);
+ rc_unshare_struct(pis->set_transfer.indexed[i], gx_transfer_map,
+ &st_transfer_map, mem,
+ return_error(gs_error_VMerror),
+ "cmd_select_map(transfer)");
+ map = pis->set_transfer.indexed[i];
+ pis->effective_transfer.indexed[i] = map;
+ }
+ break;
+ case cmd_map_ht_transfer:
+ if_debug0('L', " ht transfer");
+ /* Halftone transfer maps are never shared, but */
+ /* rc_unshare_struct is a good way to get one allocated */
+ /* if it hasn't been yet. */
+ pmap = &porder->transfer;
+ cname = "cmd_select_map(ht transfer)";
+ goto alloc;
+ case cmd_map_black_generation:
+ if_debug0('L', " black generation");
+ pmap = &pis->black_generation;
+ cname = "cmd_select_map(black generation)";
+ goto alloc;
+ case cmd_map_undercolor_removal:
+ if_debug0('L', " undercolor removal");
+ pmap = &pis->undercolor_removal;
+ cname = "cmd_select_map(undercolor removal)";
+alloc: if (!load) {
+ rc_decrement(*pmap, cname);
+ *pmap = 0;
+ *pmdata = 0;
+ *pcount = 0;
+ return 0;
+ }
+ rc_unshare_struct(*pmap, gx_transfer_map, &st_transfer_map,
+ mem, return_error(gs_error_VMerror), cname);
+ map = *pmap;
+ break;
+ default:
+ *pmdata = 0;
+ return 0;
+ }
+ map->proc = gs_mapped_transfer;
+ *pmdata = map->values;
+ *pcount = sizeof(map->values);
+ return 0;
+}
+
+/* Resize the halftone components array if necessary. */
+private int
+cmd_resize_halftone(gx_device_halftone * pdht, uint num_comp,
+ gs_memory_t * mem)
+{
+ if (num_comp != pdht->num_comp) {
+ gx_ht_order_component *pcomp;
+
+ /*
+ * We must be careful not to shrink or free the components array
+ * before releasing any relevant elements.
+ */
+ if (num_comp < pdht->num_comp) {
+ uint i;
+
+ /* Don't release the default order. */
+ for (i = pdht->num_comp; i-- > num_comp;)
+ if (pdht->components[i].corder.bits != pdht->order.bits)
+ gx_ht_order_release(&pdht->components[i].corder, mem, true);
+ if (num_comp == 0) {
+ gs_free_object(mem, pdht->components, "cmd_resize_halftone");
+ pcomp = 0;
+ } else {
+ pcomp = gs_resize_object(mem, pdht->components, num_comp,
+ "cmd_resize_halftone");
+ if (pcomp == 0) {
+ pdht->num_comp = num_comp; /* attempt consistency */
+ return_error(gs_error_VMerror);
+ }
+ }
+ } else {
+ /* num_comp > pdht->num_comp */
+ if (pdht->num_comp == 0)
+ pcomp = gs_alloc_struct_array(mem, num_comp,
+ gx_ht_order_component,
+ &st_ht_order_component_element,
+ "cmd_resize_halftone");
+ else
+ pcomp = gs_resize_object(mem, pdht->components, num_comp,
+ "cmd_resize_halftone");
+ if (pcomp == 0)
+ return_error(gs_error_VMerror);
+ memset(&pcomp[pdht->num_comp], 0,
+ sizeof(*pcomp) * (num_comp - pdht->num_comp));
+ }
+ pdht->num_comp = num_comp;
+ pdht->components = pcomp;
+ }
+ return 0;
+}
+
+/* ------ Path operations ------ */
+
+/* Decode a path segment. */
+private int
+clist_decode_segment(gx_path * ppath, int op, fixed vs[6],
+ gs_fixed_point * ppos, int x0, int y0, segment_notes notes)
+{
+ fixed px = ppos->x - int2fixed(x0);
+ fixed py = ppos->y - int2fixed(y0);
+ int code;
+
+#define A vs[0]
+#define B vs[1]
+#define C vs[2]
+#define D vs[3]
+#define E vs[4]
+#define F vs[5]
+
+ switch (op) {
+ case cmd_opv_rmoveto:
+ code = gx_path_add_point(ppath, px += A, py += B);
+ break;
+ case cmd_opv_rlineto:
+ code = gx_path_add_line_notes(ppath, px += A, py += B, notes);
+ break;
+ case cmd_opv_hlineto:
+ code = gx_path_add_line_notes(ppath, px += A, py, notes);
+ break;
+ case cmd_opv_vlineto:
+ code = gx_path_add_line_notes(ppath, px, py += A, notes);
+ break;
+ case cmd_opv_rrcurveto: /* a b c d e f => a b a+c b+d a+c+e b+d+f */
+ E += (C += A);
+ F += (D += B);
+curve: code = gx_path_add_curve_notes(ppath, px + A, py + B,
+ px + C, py + D,
+ px + E, py + F, notes);
+ px += E, py += F;
+ break;
+ case cmd_opv_hvcurveto: /* a b c d => a 0 a+b c a+b c+d */
+hvc: F = C + D, D = C, E = C = A + B, B = 0;
+ goto curve;
+ case cmd_opv_vhcurveto: /* a b c d => 0 a b a+c b+d a+c */
+vhc: E = B + D, F = D = A + C, C = B, B = A, A = 0;
+ goto curve;
+ case cmd_opv_nrcurveto: /* a b c d => 0 0 a b a+c b+d */
+ F = B + D, E = A + C, D = B, C = A, B = A = 0;
+ goto curve;
+ case cmd_opv_rncurveto: /* a b c d => a b a+c b+d a+c b+d */
+ F = D += B, E = C += A;
+ goto curve;
+ case cmd_opv_rmlineto:
+ if ((code = gx_path_add_point(ppath, px += A, py += B)) < 0)
+ break;
+ code = gx_path_add_line_notes(ppath, px += C, py += D, notes);
+ break;
+ case cmd_opv_rm2lineto:
+ if ((code = gx_path_add_point(ppath, px += A, py += B)) < 0 ||
+ (code = gx_path_add_line_notes(ppath, px += C, py += D,
+ notes)) < 0
+ )
+ break;
+ code = gx_path_add_line_notes(ppath, px += E, py += F, notes);
+ break;
+ case cmd_opv_vqcurveto: /* a b => VH a b TS(a,b) TS(b,a) */
+ if ((A ^ B) < 0)
+ C = -B, D = -A;
+ else
+ C = B, D = A;
+ goto vhc;
+ case cmd_opv_hqcurveto: /* a b => HV a TS(a,b) b TS(b,a) */
+ if ((A ^ B) < 0)
+ D = -A, C = B, B = -B;
+ else
+ D = A, C = B;
+ goto hvc;
+ case cmd_opv_rm3lineto:
+ if ((code = gx_path_add_point(ppath, px += A, py += B)) < 0 ||
+ (code = gx_path_add_line_notes(ppath, px += C, py += D,
+ notes)) < 0 ||
+ (code = gx_path_add_line_notes(ppath, px += E, py += F,
+ notes)) < 0
+ )
+ break;
+ code = gx_path_add_line_notes(ppath, px -= C, py -= D, notes);
+ break;
+ case cmd_opv_closepath:
+ code = gx_path_close_subpath(ppath);
+ gx_path_current_point(ppath, (gs_fixed_point *) vs);
+ px = A, py = B;
+ break;
+ default:
+ return_error(gs_error_rangecheck);
+ }
+#undef A
+#undef B
+#undef C
+#undef D
+#undef E
+#undef F
+ ppos->x = px + int2fixed(x0);
+ ppos->y = py + int2fixed(y0);
+ return code;
+}
diff --git a/pstoraster/gxclread.c b/pstoraster/gxclread.c
new file mode 100644
index 000000000..d6085e472
--- /dev/null
+++ b/pstoraster/gxclread.c
@@ -0,0 +1,517 @@
+/*
+ Copyright 1993-1999 by Easy Software Products.
+ Copyright (C) 1991, 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$ */
+/* Command list reading for Ghostscript. */
+#include "memory_.h"
+#include "gx.h"
+#include "gp.h" /* for gp_fmode_rb */
+#include "gpcheck.h"
+#include "gserrors.h"
+#include "gxdevice.h"
+#include "gscoord.h" /* requires gsmatrix.h */
+#include "gsdevice.h" /* for gs_deviceinitialmatrix */
+#include "gxdevmem.h" /* must precede gxcldev.h */
+#include "gxcldev.h"
+#include "gxgetbit.h"
+#include "gxhttile.h"
+#include "gdevht.h"
+#include "stream.h"
+#include "strimpl.h"
+
+/* ------ Band file reading stream ------ */
+
+/*
+ * To separate banding per se from command list interpretation,
+ * we make the command list interpreter simply read from a stream.
+ * When we are actually doing banding, the stream filters the band file
+ * and only passes through the commands for the current band (or band
+ * ranges that include the current band).
+ */
+typedef struct stream_band_read_state_s {
+ stream_state_common;
+ gx_band_page_info page_info;
+ int band;
+ uint left; /* amount of data left in this run */
+ cmd_block b_this;
+} stream_band_read_state;
+
+private int
+s_band_read_init(stream_state * st)
+{
+ stream_band_read_state *const ss = (stream_band_read_state *) st;
+
+ ss->left = 0;
+ ss->b_this.band_min = 0;
+ ss->b_this.band_max = 0;
+ ss->b_this.pos = 0;
+ clist_rewind(ss->page_bfile, false, ss->page_bfname);
+ return 0;
+}
+
+private int
+s_band_read_process(stream_state * st, stream_cursor_read * ignore_pr,
+ stream_cursor_write * pw, bool last)
+{
+ stream_band_read_state *const ss = (stream_band_read_state *) st;
+ register byte *q = pw->ptr;
+ byte *wlimit = pw->limit;
+ clist_file_ptr cfile = ss->page_cfile;
+ clist_file_ptr bfile = ss->page_bfile;
+ uint left = ss->left;
+ int status = 1;
+ uint count;
+
+ while ((count = wlimit - q) != 0) {
+ if (left) { /* Read more data for the current run. */
+ if (count > left)
+ count = left;
+ clist_fread_chars(q + 1, count, cfile);
+ if (clist_ferror_code(cfile) < 0) {
+ status = ERRC;
+ break;
+ }
+ q += count;
+ left -= count;
+ process_interrupts();
+ continue;
+ }
+ rb: /* Scan for the next run for this band (or a band range */
+ /* that includes the current band). */
+ if (ss->b_this.band_min == cmd_band_end &&
+ clist_ftell(bfile) == ss->page_bfile_end_pos
+ ) {
+ status = EOFC;
+ break;
+ } {
+ int bmin = ss->b_this.band_min;
+ int bmax = ss->b_this.band_max;
+ long pos = ss->b_this.pos;
+
+ clist_fread_chars(&ss->b_this, sizeof(ss->b_this), bfile);
+ if (!(ss->band >= bmin && ss->band <= bmax))
+ goto rb;
+ clist_fseek(cfile, pos, SEEK_SET, ss->page_cfname);
+ left = (uint) (ss->b_this.pos - pos);
+ if_debug5('l', "[l]reading for bands (%d,%d) at bfile %ld, cfile %ld, length %u\n",
+ bmin, bmax,
+ clist_ftell(bfile) - 2 * sizeof(ss->b_this),
+ pos, left);
+ }
+ }
+ pw->ptr = q;
+ ss->left = left;
+ return status;
+}
+
+/* Stream template */
+const stream_template s_band_read_template = {
+ &st_stream_state, s_band_read_init, s_band_read_process, 1, cbuf_size
+};
+
+
+/* ------ Reading/rendering ------ */
+
+/* Forward references */
+
+private int clist_render_init(P1(gx_device_clist *));
+private int clist_playback_file_band(P7(clist_playback_action action,
+ gx_device_clist_reader *cdev,
+ gx_band_page_info *page_info,
+ gx_device *target,
+ int band, int x0, int y0));
+private int clist_rasterize_lines(P6(gx_device *dev, int y, int lineCount,
+ byte *data_in, gx_device_memory *mdev,
+ int *pmy));
+
+/*
+ * Do device setup from params stored in command list. This is only for
+ * async rendering & assumes that the first command in every command list
+ * is a put_params command which sets all space-related parameters to the
+ * value they will have for the duration of that command list.
+ */
+int
+clist_setup_params(gx_device *dev)
+{
+ gx_device_clist_reader * const crdev =
+ &((gx_device_clist *)dev)->reader;
+ int code = clist_render_init((gx_device_clist *)dev);
+ if ( code < 0 )
+ return code;
+
+ code = clist_playback_file_band(playback_action_setup,
+ crdev, &crdev->page_info, 0, 0, 0, 0);
+
+ /* put_params may have reinitialized device into a writer */
+ clist_render_init((gx_device_clist *)dev);
+
+ return code;
+}
+
+/* Find out where the band buffer for a given line is going to fall on the */
+/* next call to get_bits. */
+/****** THIS IS WRONG: IT DUPLICATES CODE INSIDE make_buffer_device
+ ****** AND ASSUMES THAT make_buffer_device JUST SETS UP A MEMORY DEVICE.
+ ******/
+int /* rets # lines from y till end of buffer, or -ve error code */
+clist_locate_overlay_buffer(gx_device_printer *pdev, int y, byte **data)
+{
+ gx_device_clist_reader * const crdev =
+ &((gx_device_clist *)pdev)->reader;
+ gx_device * const dev = (gx_device *)pdev;
+ gx_device *target = crdev->target;
+
+ uint raster = gdev_mem_raster(target);
+ byte *mdata = crdev->data + crdev->page_tile_cache_size;
+ int band_height = crdev->page_band_height;
+ int band = y / band_height;
+ int band_begin_line = band * band_height;
+ int bytes_from_band_begin_to_line = (y - band_begin_line) * raster;
+ int band_end_line = band_begin_line + band_height;
+
+ if (band_end_line > dev->height)
+ band_end_line = dev->height;
+
+ /* Make sure device will rasterize on next get_bits or get_overlay_bits */
+ if ( crdev->ymin >= 0 )
+ crdev->ymin = crdev->ymax = 0;
+
+ *data = mdata + bytes_from_band_begin_to_line;
+ return band_end_line - y; /* # lines remaining in this band */
+}
+
+/* Do more rendering to a client-supplied memory image, return results */
+int
+clist_get_overlay_bits(gx_device_printer *pdev, int y, int line_count,
+ byte *data)
+{
+ gx_device_clist_reader * const crdev =
+ &((gx_device_clist *)pdev)->reader;
+ byte *data_orig = data;
+ gx_device * const dev = (gx_device *)pdev;
+ gx_device *target = crdev->target;
+ uint raster = gdev_mem_raster(target);
+ int lines_left = line_count;
+
+ /* May have to render more than once to cover requested line range */
+ while (lines_left > 0) {
+ gx_device_memory mdev;
+ int my;
+ byte *data_transformed;
+ int line_count_rasterized =
+ clist_rasterize_lines(dev, y, lines_left, data_orig, &mdev, &my);
+ uint byte_count_rasterized = raster * line_count_rasterized;
+
+ if (line_count_rasterized < 0)
+ return line_count_rasterized;
+ data_transformed = mdev.base + raster * my;
+ if (data_orig != data_transformed)
+ memcpy(data_orig, data_transformed, byte_count_rasterized);
+ data_orig += byte_count_rasterized;
+ lines_left -= line_count_rasterized;
+ }
+ return 0;
+}
+
+/* Copy a rasterized rectangle to the client, rasterizing if needed. */
+int
+clist_get_bits_rectangle(gx_device *dev, const gs_int_rect * prect,
+ gs_get_bits_params_t *params, gs_int_rect **unread)
+{
+ gs_get_bits_options_t options = params->options;
+ int y = prect->p.y;
+ int end_y = prect->q.y;
+ int line_count = end_y - y;
+ gs_int_rect band_rect;
+ int lines_rasterized;
+ gx_device_memory mdev;
+ int my;
+ int code;
+
+ if (prect->p.x < 0 || prect->q.x > dev->width ||
+ y < 0 || end_y > dev->height
+ )
+ return_error(gs_error_rangecheck);
+ if (line_count <= 0 || prect->p.x >= prect->q.x)
+ return 0;
+ code = clist_rasterize_lines(dev, y, line_count, NULL, &mdev, &my);
+ if (code < 0)
+ return code;
+ lines_rasterized = min(code, line_count);
+ /* Return as much of the rectangle as falls within the rasterized lines. */
+ band_rect = *prect;
+ band_rect.p.y = my;
+ band_rect.q.y = my + lines_rasterized;
+ code = (*dev_proc(&mdev, get_bits_rectangle))
+ ((gx_device *)&mdev, &band_rect, params, unread);
+ if (code < 0 || lines_rasterized == line_count)
+ return code;
+ /*
+ * We'll have to return the rectangle in pieces. Force GB_RETURN_COPY
+ * rather than GB_RETURN_POINTER, and require all subsequent pieces to
+ * use the same values as the first piece for all of the other format
+ * options. If copying isn't allowed, or if there are any unread
+ * rectangles, punt.
+ */
+ if (!(options & GB_RETURN_COPY) || code > 0)
+ return gx_default_get_bits_rectangle(dev, prect, params, unread);
+ options = params->options;
+ if (!(options & GB_RETURN_COPY)) {
+ /* Redo the first piece with copying. */
+ params->options = options =
+ (params->options & ~GB_RETURN_ALL) | GB_RETURN_COPY;
+ lines_rasterized = 0;
+ }
+ {
+ gs_get_bits_params_t band_params;
+ int num_planes =
+ (options & GB_PACKING_CHUNKY ? 1 :
+ options & GB_PACKING_PLANAR ? mdev.color_info.num_components :
+ options & GB_PACKING_BIT_PLANAR ? mdev.color_info.depth :
+ 0 /****** NOT POSSIBLE ******/);
+ uint raster = gdev_mem_raster(&mdev);
+
+ band_params = *params;
+ while ((y += lines_rasterized) < end_y) {
+ int i;
+
+ /* Increment data pointers by lines_rasterized. */
+ for (i = 0; i < num_planes; ++i)
+ band_params.data[i] += raster * lines_rasterized;
+ line_count = end_y - y;
+ code = clist_rasterize_lines(dev, y, line_count, NULL, &mdev, &my);
+ if (code < 0)
+ return code;
+ lines_rasterized = min(code, line_count);
+ band_rect.p.y = my;
+ band_rect.q.y = my + lines_rasterized;
+ code = (*dev_proc(&mdev, get_bits_rectangle))
+ ((gx_device *)&mdev, &band_rect, &band_params, unread);
+ if (code < 0)
+ return code;
+ params->options = options = band_params.options;
+ if (lines_rasterized == line_count)
+ return code;
+ }
+ }
+ return 0;
+}
+
+/* Copy scan lines to the client. This is where rendering gets done. */
+/* Processes min(requested # lines, # lines available thru end of band) */
+private int /* returns -ve error code, or # scan lines copied */
+clist_rasterize_lines(gx_device *dev, int y, int line_count, byte *data_in,
+ gx_device_memory *mdev, int *pmy)
+{
+ gx_device_clist_reader * const crdev =
+ &((gx_device_clist *)dev)->reader;
+ gx_device *target = crdev->target;
+ uint raster = gx_device_raster(target, true);
+ byte *mdata = crdev->data + crdev->page_tile_cache_size;
+ gx_device *tdev = (gx_device *)mdev;
+ int code;
+
+ /* Initialize for rendering if we haven't done so yet. */
+ if (crdev->ymin < 0) {
+ code = clist_end_page(&((gx_device_clist *)crdev)->writer);
+ if ( code < 0 )
+ return code;
+ code = clist_render_init((gx_device_clist *)dev);
+ if ( code < 0 )
+ return code;
+#if 0 /* **************** */
+ gx_device_ht hdev;
+
+ code = clist_render_init((gx_device_clist *) dev, &hdev);
+ if (code < 0)
+ return code;
+ if (code != 0) {
+ hdev.target = tdev;
+ tdev = (gx_device *) & hdev;
+ }
+#endif /* **************** */
+ }
+
+ /* Render a band if necessary, and copy it incrementally. */
+ code = (*crdev->make_buffer_device)(mdev, target, 0, true);
+ if (code < 0)
+ return code;
+ mdev->width = target->width;
+ mdev->raster = raster;
+ if (data_in || !(y >= crdev->ymin && y < crdev->ymax)) {
+ const gx_placed_page *ppages = crdev->pages;
+ int num_pages = crdev->num_pages;
+ gx_saved_page current_page;
+ gx_placed_page placed_page;
+ int band_height = crdev->page_band_height;
+ int band = y / band_height;
+ int band_begin_line = band * band_height;
+ int band_end_line = band_begin_line + band_height;
+ int i;
+
+ if (band_end_line > dev->height)
+ band_end_line = dev->height;
+ /* Clip line_count to current band */
+ if (line_count > band_end_line - y)
+ line_count = band_end_line - y;
+
+ if (y < 0 || y > dev->height)
+ return_error(gs_error_rangecheck);
+ /****** QUESTIONABLE, BUT BETTER THAN OMITTING ******/
+ mdev->color_info = dev->color_info;
+ mdev->base = mdata;
+ /*
+ * The matrix in the memory device is irrelevant,
+ * because all we do with the device is call the device-level
+ * output procedures, but we may as well set it to
+ * something halfway reasonable.
+ */
+ gs_deviceinitialmatrix(target, &mdev->initial_matrix);
+ mdev->height = band_height;
+ (*dev_proc(mdev, open_device))((gx_device *)mdev);
+ if_debug1('l', "[l]rendering band %d\n", band);
+ /*
+ * Unfortunately, there is currently no way to get a mem
+ * device to rasterize into a given memory space, since
+ * a mem device's memory space must also contain internal
+ * structures.
+ */
+ if (data_in)
+ memcpy(mdev->base + (y - band_begin_line) * raster,
+ data_in, line_count * raster);
+ /*
+ * If we aren't rendering saved pages, do the current one.
+ * Note that this is the only case in which we may encounter
+ * a gx_saved_page with non-zero cfile or bfile.
+ */
+ if (ppages == 0) {
+ current_page.info = crdev->page_info;
+ placed_page.page = &current_page;
+ placed_page.offset.x = placed_page.offset.y = 0;
+ ppages = &placed_page;
+ num_pages = 1;
+ }
+ for (i = 0; i < num_pages; ++i) {
+ const gx_placed_page *ppage = &ppages[i];
+
+ code = clist_playback_file_band(playback_action_render,
+ crdev, &ppage->page->info, tdev,
+ band, -ppage->offset.x,
+ band * mdev->height);
+ if ( code < 0 )
+ break;
+ }
+ /* Reset the band boundaries now, so that we don't get */
+ /* an infinite loop. */
+ crdev->ymin = band_begin_line;
+ crdev->ymax = band_end_line;
+ if (code < 0)
+ return code;
+ *pmy = y - crdev->ymin;
+ } else {
+ /* Just fill in enough of the memory device to access the
+ * already-rasterized scan lines; in particular, only set up scan
+ * line pointers for the requested Y range.
+ */
+ mdev->base = mdata + (y - crdev->ymin) * raster;
+ mdev->height = crdev->ymax - y;
+ gdev_mem_open_scan_lines(mdev, min(line_count, mdev->height));
+ *pmy = 0;
+ }
+ return (line_count > crdev->ymax - y ? crdev->ymax - y : line_count);
+}
+
+/* Initialize for reading. */
+private int
+clist_render_init(gx_device_clist *dev /******, gx_device_ht *hdev ******/)
+{
+ gx_device_clist_reader * const crdev = &dev->reader;
+
+ crdev->ymin = crdev->ymax = 0;
+ /* For normal rasterizing, pages and num_pages are zero. */
+ crdev->pages = 0;
+ crdev->num_pages = 0;
+ return 0;
+}
+
+/* Playback the band file, taking the indicated action w/ its contents. */
+private int
+clist_playback_file_band(clist_playback_action action,
+ gx_device_clist_reader *cdev,
+ gx_band_page_info *page_info, gx_device *target,
+ int band, int x0, int y0)
+{
+ int code = 0;
+ int opened_bfile = 0;
+ int opened_cfile = 0;
+
+ /* We have to pick some allocator for rendering.... */
+ gs_memory_t *mem =
+ (cdev->memory != 0 ? cdev->memory : &gs_memory_default);
+
+ /* setup stream */
+ stream_band_read_state rs;
+ rs.template = &s_band_read_template;
+ rs.memory = 0;
+ rs.band = band;
+ rs.page_info = *page_info;
+
+ /* If this is a saved page, open the files. */
+ if (rs.page_cfile == 0) {
+ code = clist_fopen(rs.page_cfname,
+ gp_fmode_rb, &rs.page_cfile, cdev->bandlist_memory,
+ cdev->bandlist_memory, true);
+ opened_cfile = (code >= 0);
+ }
+ if (rs.page_bfile == 0 && code >= 0) {
+ code = clist_fopen(rs.page_bfname,
+ gp_fmode_rb, &rs.page_bfile, cdev->bandlist_memory,
+ cdev->bandlist_memory, false);
+ opened_bfile = (code >= 0);
+ }
+ if (rs.page_cfile != 0 && rs.page_bfile != 0) {
+ stream s;
+ byte sbuf[cbuf_size];
+ static const stream_procs no_procs = {
+ s_std_noavailable, s_std_noseek, s_std_read_reset,
+ s_std_read_flush, s_std_close, s_band_read_process
+ };
+
+ s_band_read_init((stream_state *)&rs);
+ s_std_init(&s, sbuf, cbuf_size, &no_procs, s_mode_read);
+ s.foreign = 1;
+ s.state = (stream_state *)&rs;
+ code = clist_playback_band(action, cdev, &s, target, -x0, y0, mem);
+ }
+
+ /* Close the files if we just opened them. */
+ if (opened_bfile && rs.page_bfile != 0)
+ clist_fclose(rs.page_bfile, rs.page_bfname, false);
+ if (opened_cfile && rs.page_cfile != 0)
+ clist_fclose(rs.page_cfile, rs.page_cfname, false);
+
+ return code;
+}
diff --git a/pstoraster/gxclrect.c b/pstoraster/gxclrect.c
new file mode 100644
index 000000000..080cc41db
--- /dev/null
+++ b/pstoraster/gxclrect.c
@@ -0,0 +1,656 @@
+/* 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$ */
+/* Rectangle-oriented command writing for command list */
+#include "gx.h"
+#include "gserrors.h"
+#include "gsutil.h" /* for gs_next_ids */
+#include "gxdevice.h"
+#include "gxdevmem.h" /* must precede gxcldev.h */
+#include "gxcldev.h"
+
+/* ---------------- Writing utilities ---------------- */
+
+#define cmd_set_rect(rect)\
+ ((rect).x = x, (rect).y = y,\
+ (rect).width = width, (rect).height = height)
+
+/* Write a rectangle. */
+private int
+cmd_size_rect(register const gx_cmd_rect * prect)
+{
+ return
+ cmd_sizew(prect->x) + cmd_sizew(prect->y) +
+ cmd_sizew(prect->width) + cmd_sizew(prect->height);
+}
+private byte *
+cmd_put_rect(register const gx_cmd_rect * prect, register byte * dp)
+{
+ cmd_putw(prect->x, dp);
+ cmd_putw(prect->y, dp);
+ cmd_putw(prect->width, dp);
+ cmd_putw(prect->height, dp);
+ return dp;
+}
+
+int
+cmd_write_rect_cmd(gx_device_clist_writer * cldev, gx_clist_state * pcls,
+ int op, int x, int y, int width, int height)
+{
+ int dx = x - pcls->rect.x;
+ int dy = y - pcls->rect.y;
+ int dwidth = width - pcls->rect.width;
+ int dheight = height - pcls->rect.height;
+ byte *dp;
+ int code;
+
+#define check_range_xy(rmin, rmax)\
+ ((unsigned)(dx - rmin) <= (rmax - rmin) &&\
+ (unsigned)(dy - rmin) <= (rmax - rmin))
+#define check_range_w(rmin, rmax)\
+ ((unsigned)(dwidth - rmin) <= (rmax - rmin))
+#define check_ranges(rmin, rmax)\
+ (check_range_xy(rmin, rmax) && check_range_w(rmin, rmax) &&\
+ (unsigned)(dheight - rmin) <= (rmax - rmin))
+ cmd_set_rect(pcls->rect);
+ if (dheight == 0 && check_range_w(cmd_min_dw_tiny, cmd_max_dw_tiny) &&
+ check_range_xy(cmd_min_dxy_tiny, cmd_max_dxy_tiny)
+ ) {
+ byte op_tiny = op + 0x20 + dwidth - cmd_min_dw_tiny;
+
+ if (dx == width - dwidth && dy == 0) {
+ code = set_cmd_put_op(dp, cldev, pcls, op_tiny + 8, 1);
+ if (code < 0)
+ return code;
+ } else {
+ code = set_cmd_put_op(dp, cldev, pcls, op_tiny, 2);
+ if (code < 0)
+ return code;
+ dp[1] = (dx << 4) + dy - (cmd_min_dxy_tiny * 0x11);
+ }
+ }
+#define rmin cmd_min_short
+#define rmax cmd_max_short
+ else if (check_ranges(rmin, rmax)) {
+ int dh = dheight - cmd_min_dxy_tiny;
+
+ if ((unsigned)dh <= cmd_max_dxy_tiny - cmd_min_dxy_tiny &&
+ dh != 0 && dy == 0
+ ) {
+ op += dh;
+ code = set_cmd_put_op(dp, cldev, pcls, op + 0x10, 3);
+ if (code < 0)
+ return code;
+ if_debug3('L', " rs2:%d,%d,0,%d\n",
+ dx, dwidth, dheight);
+ } else {
+ code = set_cmd_put_op(dp, cldev, pcls, op + 0x10, 5);
+ if (code < 0)
+ return code;
+ if_debug4('L', " rs4:%d,%d,%d,%d\n",
+ dx, dwidth, dy, dheight);
+ dp[3] = dy - rmin;
+ dp[4] = dheight - rmin;
+ }
+ dp[1] = dx - rmin;
+ dp[2] = dwidth - rmin;
+ }
+#undef rmin
+#undef rmax
+ else if (dy >= -2 && dy <= 1 && dheight >= -2 && dheight <= 1 &&
+ (dy + dheight) != -4
+ ) {
+ int rcsize = 1 + cmd_sizew(x) + cmd_sizew(width);
+
+ code = set_cmd_put_op(dp, cldev, pcls,
+ op + ((dy + 2) << 2) + dheight + 2, rcsize);
+ if (code < 0)
+ return code;
+ ++dp;
+ cmd_put2w(x, width, dp);
+ } else {
+ int rcsize = 1 + cmd_size_rect(&pcls->rect);
+
+ code = set_cmd_put_op(dp, cldev, pcls, op, rcsize);
+ if (code < 0)
+ return code;
+ if_debug5('L', " r%d:%d,%d,%d,%d\n",
+ rcsize - 1, dx, dwidth, dy, dheight);
+ cmd_put_rect(&pcls->rect, dp + 1);
+ }
+ return 0;
+}
+
+/* ---------------- Driver procedures ---------------- */
+
+int
+clist_fill_rectangle(gx_device * dev, int x, int y, int width, int height,
+ gx_color_index color)
+{
+ gx_device_clist_writer * const cdev =
+ &((gx_device_clist *)dev)->writer;
+ int code;
+
+ fit_fill(dev, x, y, width, height);
+ FOR_RECTS {
+ TRY_RECT {
+ code = cmd_disable_lop(cdev, pcls);
+ if (code >= 0 && color != pcls->colors[1])
+ code = cmd_put_color(cdev, pcls, &clist_select_color1,
+ color, &pcls->colors[1]);
+ if (code >= 0)
+ code = cmd_write_rect_cmd(cdev, pcls, cmd_op_fill_rect, x, y,
+ width, height);
+ } HANDLE_RECT(code);
+ } END_RECTS;
+ return 0;
+}
+
+int
+clist_strip_tile_rectangle(gx_device * dev, const gx_strip_bitmap * tile,
+ int x, int y, int width, int height,
+ gx_color_index color0, gx_color_index color1, int px, int py)
+{
+ gx_device_clist_writer * const cdev =
+ &((gx_device_clist *)dev)->writer;
+ int depth =
+ (color1 == gx_no_color_index && color0 == gx_no_color_index ?
+ dev->color_info.depth : 1);
+ int code;
+
+ fit_fill(dev, x, y, width, height);
+ FOR_RECTS {
+ ulong offset_temp;
+
+ TRY_RECT {
+ code = cmd_disable_lop(cdev, pcls);
+ } HANDLE_RECT(code);
+ if (!cls_has_tile_id(cdev, pcls, tile->id, offset_temp)) {
+ code = 0;
+ if (tile->id != gx_no_bitmap_id) {
+ TRY_RECT {
+ code = clist_change_tile(cdev, pcls, tile, depth);
+ } HANDLE_RECT_UNLESS(code,
+ (code != gs_error_VMerror || !cdev->error_is_retryable));
+ }
+ if (code < 0) {
+ /* ok if gx_default... does retries internally: */
+ /* it's self-sufficient */
+ code = gx_default_strip_tile_rectangle(dev, tile,
+ x, y, width, height,
+ color0, color1,
+ px, py);
+ if (code < 0)
+ ERROR_RECT(code);
+ goto endr;
+ }
+ }
+ TRY_RECT {
+ code = 0;
+ if (color0 != pcls->tile_colors[0] || color1 != pcls->tile_colors[1])
+ code = cmd_set_tile_colors(cdev, pcls, color0, color1);
+ if (px != pcls->tile_phase.x || py != pcls->tile_phase.y) {
+ if (code >= 0)
+ code = cmd_set_tile_phase(cdev, pcls, px, py);
+ }
+ if (code >= 0)
+ code = cmd_write_rect_cmd(cdev, pcls, cmd_op_tile_rect, x, y,
+ width, height);
+ } HANDLE_RECT(code);
+endr:;
+ } END_RECTS;
+ return 0;
+}
+
+int
+clist_copy_mono(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 color0, gx_color_index color1)
+{
+ gx_device_clist_writer * const cdev =
+ &((gx_device_clist *)dev)->writer;
+ int y0;
+ gx_bitmap_id orig_id = id;
+
+ fit_copy(dev, data, data_x, raster, id, x, y, width, height);
+ y0 = y;
+ FOR_RECTS {
+ int dx = data_x & 7;
+ int w1 = dx + width;
+ const byte *row = data + (y - y0) * raster + (data_x >> 3);
+ int code;
+
+ TRY_RECT {
+ code = cmd_disable_lop(cdev, pcls);
+ if (code >= 0)
+ code = cmd_disable_clip(cdev, pcls);
+ if (color0 != pcls->colors[0] && code >= 0)
+ code = cmd_set_color0(cdev, pcls, color0);
+ if (color1 != pcls->colors[1] && code >= 0)
+ code = cmd_set_color1(cdev, pcls, color1);
+ } HANDLE_RECT(code);
+ /* Don't bother to check for a possible cache hit: */
+ /* tile_rectangle and fill_mask handle those cases. */
+copy:{
+ gx_cmd_rect rect;
+ int rsize;
+ byte op = (byte) cmd_op_copy_mono;
+ byte *dp;
+ uint csize;
+ uint compress;
+ int code;
+
+ rect.x = x, rect.y = y;
+ rect.width = w1, rect.height = height;
+ rsize = (dx ? 3 : 1) + cmd_size_rect(&rect);
+ TRY_RECT {
+ code = cmd_put_bits(cdev, pcls, row, w1, height, raster,
+ rsize, (orig_id == gx_no_bitmap_id ?
+ 1 << cmd_compress_rle :
+ cmd_mask_compress_any),
+ &dp, &csize);
+ } HANDLE_RECT_UNLESS(code, code == gs_error_limitcheck);
+ compress = (uint)code;
+ if (code < 0) {
+ /* The bitmap was too large; split up the transfer. */
+ if (height > 1) {
+ /*
+ * Split the transfer by reducing the height.
+ * See the comment above FOR_RECTS in gxcldev.h.
+ */
+ height >>= 1;
+ goto copy;
+ } else {
+ /* Split a single (very long) row. */
+ int w2 = w1 >> 1;
+
+ NEST_RECT {
+ code = clist_copy_mono(dev, row, dx,
+ raster, gx_no_bitmap_id, x, y,
+ w2, 1, color0, color1);
+ if (code >= 0)
+ code = clist_copy_mono(dev, row, dx + w2,
+ raster, gx_no_bitmap_id,
+ x + w2, y,
+ w1 - w2, 1, color0, color1);
+ } UNNEST_RECT;
+ if (code < 0)
+ ERROR_RECT(code);
+ continue;
+ }
+ }
+ op += compress;
+ if (dx) {
+ *dp++ = cmd_count_op(cmd_opv_set_misc, 2);
+ *dp++ = cmd_set_misc_data_x + dx;
+ }
+ *dp++ = cmd_count_op(op, csize);
+ cmd_put2w(x, y, dp);
+ cmd_put2w(w1, height, dp);
+ pcls->rect = rect;
+ }
+ } END_RECTS;
+ return 0;
+}
+
+int
+clist_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)
+{
+ gx_device_clist_writer * const cdev =
+ &((gx_device_clist *)dev)->writer;
+ int depth = dev->color_info.depth;
+ int y0;
+ int data_x_bit;
+
+ fit_copy(dev, data, data_x, raster, id, x, y, width, height);
+ y0 = y;
+ data_x_bit = data_x * depth;
+ FOR_RECTS {
+ int dx = (data_x_bit & 7) / depth;
+ int w1 = dx + width;
+ const byte *row = data + (y - y0) * raster + (data_x_bit >> 3);
+ int code;
+
+ TRY_RECT {
+ code = cmd_disable_lop(cdev, pcls);
+ if (code >= 0)
+ code = cmd_disable_clip(cdev, pcls);
+ } HANDLE_RECT(code);
+ if (pcls->color_is_alpha) {
+ byte *dp;
+
+ TRY_RECT {
+ code =
+ set_cmd_put_op(dp, cdev, pcls, cmd_opv_set_copy_color, 1);
+ } HANDLE_RECT(code);
+ pcls->color_is_alpha = 0;
+ }
+copy:{
+ gx_cmd_rect rect;
+ int rsize;
+ byte op = (byte) cmd_op_copy_color_alpha;
+ byte *dp;
+ uint csize;
+ uint compress;
+
+ rect.x = x, rect.y = y;
+ rect.width = w1, rect.height = height;
+ rsize = (dx ? 3 : 1) + cmd_size_rect(&rect);
+ TRY_RECT {
+ code = cmd_put_bits(cdev, pcls, row, w1 * depth,
+ height, raster, rsize,
+ 1 << cmd_compress_rle, &dp, &csize);
+ } HANDLE_RECT_UNLESS(code, code == gs_error_limitcheck);
+ compress = (uint)code;
+ if (code < 0) {
+ /* The bitmap was too large; split up the transfer. */
+ if (height > 1) {
+ /* Split the transfer by reducing the height.
+ * See the comment above FOR_RECTS in gxcldev.h.
+ */
+ height >>= 1;
+ goto copy;
+ } else {
+ /* Split a single (very long) row. */
+ int w2 = w1 >> 1;
+
+ NEST_RECT {
+ code = clist_copy_color(dev, row, dx,
+ raster, gx_no_bitmap_id,
+ x, y, w2, 1);
+ if (code >= 0)
+ code = clist_copy_color(dev, row, dx + w2,
+ raster, gx_no_bitmap_id,
+ x + w2, y, w1 - w2, 1);
+ } UNNEST_RECT;
+ if (code < 0)
+ ERROR_RECT(code);
+ continue;
+ }
+ }
+ op += compress;
+ if (dx) {
+ *dp++ = cmd_count_op(cmd_opv_set_misc, 2);
+ *dp++ = cmd_set_misc_data_x + dx;
+ }
+ *dp++ = cmd_count_op(op, csize);
+ cmd_put2w(x, y, dp);
+ cmd_put2w(w1, height, dp);
+ pcls->rect = rect;
+ }
+ } END_RECTS;
+ return 0;
+}
+
+int
+clist_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)
+{
+ gx_device_clist_writer * const cdev =
+ &((gx_device_clist *)dev)->writer;
+ /* I don't like copying the entire body of clist_copy_color */
+ /* just to change 2 arguments and 1 opcode, */
+ /* but I don't see any alternative that doesn't require */
+ /* another level of procedure call even in the common case. */
+ int log2_depth = depth >> 1; /* works for 1,2,4 */
+ int y0;
+ int data_x_bit;
+
+ fit_copy(dev, data, data_x, raster, id, x, y, width, height);
+ y0 = y;
+ data_x_bit = data_x << log2_depth;
+ FOR_RECTS {
+ int dx = (data_x_bit & 7) >> log2_depth;
+ int w1 = dx + width;
+ const byte *row = data + (y - y0) * raster + (data_x_bit >> 3);
+ int code;
+
+ TRY_RECT {
+ code = cmd_disable_lop(cdev, pcls);
+ if (code >= 0)
+ code = cmd_disable_clip(cdev, pcls);
+ } HANDLE_RECT(code);
+ if (!pcls->color_is_alpha) {
+ byte *dp;
+
+ TRY_RECT {
+ code =
+ set_cmd_put_op(dp, cdev, pcls, cmd_opv_set_copy_alpha, 1);
+ } HANDLE_RECT(code);
+ pcls->color_is_alpha = 1;
+ }
+ if (color != pcls->colors[1]) {
+ TRY_RECT {
+ code = cmd_set_color1(cdev, pcls, color);
+ } HANDLE_RECT(code);
+ }
+copy:{
+ gx_cmd_rect rect;
+ int rsize;
+ byte op = (byte) cmd_op_copy_color_alpha;
+ byte *dp;
+ uint csize;
+ uint compress;
+
+ rect.x = x, rect.y = y;
+ rect.width = w1, rect.height = height;
+ rsize = (dx ? 4 : 2) + cmd_size_rect(&rect);
+ TRY_RECT {
+ code = cmd_put_bits(cdev, pcls, row, w1 << log2_depth,
+ height, raster, rsize,
+ 1 << cmd_compress_rle, &dp, &csize);
+ } HANDLE_RECT_UNLESS(code, code == gs_error_limitcheck);
+ compress = (uint)code;
+ if (code < 0) {
+ /* The bitmap was too large; split up the transfer. */
+ if (height > 1) {
+ /* Split the transfer by reducing the height.
+ * See the comment above FOR_RECTS in gxcldev.h.
+ */
+ height >>= 1;
+ goto copy;
+ } else {
+ /* Split a single (very long) row. */
+ int w2 = w1 >> 1;
+
+ NEST_RECT {
+ code = clist_copy_alpha(dev, row, dx,
+ raster, gx_no_bitmap_id, x, y,
+ w2, 1, color, depth);
+ if (code >= 0)
+ code = clist_copy_alpha(dev, row, dx + w2,
+ raster, gx_no_bitmap_id,
+ x + w2, y, w1 - w2, 1,
+ color, depth);
+ } UNNEST_RECT;
+ if (code < 0)
+ ERROR_RECT(code);
+ continue;
+ }
+ }
+ op += compress;
+ if (dx) {
+ *dp++ = cmd_count_op(cmd_opv_set_misc, 2);
+ *dp++ = cmd_set_misc_data_x + dx;
+ }
+ *dp++ = cmd_count_op(op, csize);
+ *dp++ = depth;
+ cmd_put2w(x, y, dp);
+ cmd_put2w(w1, height, dp);
+ pcls->rect = rect;
+ }
+ } END_RECTS;
+ return 0;
+}
+
+int
+clist_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_clist_writer * const cdev =
+ &((gx_device_clist *)dev)->writer;
+ gs_rop3_t rop = lop_rop(lop);
+ gx_strip_bitmap tile_with_id;
+ const gx_strip_bitmap *tiles = textures;
+ int y0;
+
+ if (scolors != 0 && scolors[0] != scolors[1]) {
+ fit_fill(dev, x, y, width, height);
+ } else {
+ fit_copy(dev, sdata, sourcex, sraster, id, x, y, width, height);
+ }
+ y0 = y;
+ /*
+ * We shouldn't need to put the logic below inside FOR/END_RECTS,
+ * but the lop_enabled flags are per-band.
+ */
+ FOR_RECTS {
+ const byte *row = sdata + (y - y0) * sraster;
+ int code;
+
+ if (rop3_uses_T(rop)) {
+ if (tcolors == 0 || tcolors[0] != tcolors[1]) {
+ ulong offset_temp;
+
+ if (!cls_has_tile_id(cdev, pcls, tiles->id, offset_temp)) {
+ /* Change tile. If there is no id, generate one. */
+ if (tiles->id == gx_no_bitmap_id) {
+ tile_with_id = *tiles;
+ tile_with_id.id = gs_next_ids(1);
+ tiles = &tile_with_id;
+ }
+ TRY_RECT {
+ code = clist_change_tile(cdev, pcls, tiles,
+ (tcolors != 0 ? 1 :
+ dev->color_info.depth));
+ } HANDLE_RECT_UNLESS(code, code == gs_error_limitcheck);
+ if (code < 0) {
+ /*
+ * The error is a limitcheck: we have a tile that
+ * is too big to fit in the command reading buffer.
+ * For now, just divide up the transfer into scan
+ * lines. (If a single scan line won't fit, punt.)
+ * Eventually, we'll need a way to transfer the tile
+ * in pieces.
+ */
+ uint rep_height = tiles->rep_height;
+ gs_id ids;
+ gx_strip_bitmap line_tile;
+ int iy;
+
+ if (rep_height == 1 ||
+ /****** CAN'T HANDLE SHIFT YET ******/
+ tiles->rep_shift != 0
+ )
+ return code;
+ /*
+ * Allocate enough fake IDs, since the inner call on
+ * clist_strip_copy_rop will need them anyway.
+ */
+ ids = gs_next_ids(min(height, rep_height));
+ line_tile = *tiles;
+ line_tile.size.y = 1;
+ line_tile.rep_height = 1;
+ for (iy = 0; iy < height; ++iy) {
+ line_tile.data = tiles->data + line_tile.raster *
+ ((y + iy + phase_y) % rep_height);
+ line_tile.id = ids + (iy % rep_height);
+ /*
+ * Note that since we're only transferring
+ * a single scan line, phase_y is irrelevant;
+ * we may as well use the current tile phase
+ * so we don't have to write extra commands.
+ */
+ NEST_RECT {
+ code = clist_strip_copy_rop(dev,
+ (sdata == 0 ? 0 : row + iy * sraster),
+ sourcex, sraster,
+ gx_no_bitmap_id, scolors,
+ &line_tile, tcolors,
+ x, y + iy, width, 1,
+ phase_x, pcls->tile_phase.y, lop);
+ } UNNEST_RECT;
+ if (code < 0)
+ ERROR_RECT(code);
+ }
+ continue;
+ }
+ if (phase_x != pcls->tile_phase.x ||
+ phase_y != pcls->tile_phase.y
+ ) {
+ TRY_RECT {
+ code = cmd_set_tile_phase(cdev, pcls, phase_x,
+ phase_y);
+ } HANDLE_RECT(code);
+ }
+ }
+ }
+ /* Set the tile colors. */
+ TRY_RECT {
+ code =
+ (tcolors != 0 ?
+ cmd_set_tile_colors(cdev, pcls, tcolors[0], tcolors[1]) :
+ cmd_set_tile_colors(cdev, pcls, gx_no_color_index,
+ gx_no_color_index));
+ } HANDLE_RECT(code);
+ }
+ TRY_RECT {
+ code = 0;
+ if (lop != pcls->lop)
+ code = cmd_set_lop(cdev, pcls, lop);
+ if (code >= 0)
+ code = cmd_enable_lop(cdev, pcls);
+ } HANDLE_RECT(code);
+
+ /* Set lop_enabled to -1 so that fill_rectangle / copy_* */
+ /* won't attempt to set it to 0. */
+ pcls->lop_enabled = -1;
+ NEST_RECT {
+ if (scolors != 0) {
+ if (scolors[0] == scolors[1])
+ code = clist_fill_rectangle(dev, x, y, width, height,
+ scolors[1]);
+ else
+ code = clist_copy_mono(dev, row, sourcex, sraster, id,
+ x, y, width, height,
+ scolors[0], scolors[1]);
+ } else
+ code = clist_copy_color(dev, row, sourcex, sraster, id,
+ x, y, width, height);
+ } UNNEST_RECT;
+ pcls->lop_enabled = 1;
+ if (code < 0)
+ ERROR_RECT(code);
+ } END_RECTS;
+ return 0;
+}
diff --git a/pstoraster/gxclutil.c b/pstoraster/gxclutil.c
new file mode 100644
index 000000000..e61433e29
--- /dev/null
+++ b/pstoraster/gxclutil.c
@@ -0,0 +1,616 @@
+/* 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$ */
+/* Command list writing utilities. */
+
+#include "memory_.h"
+#include "string_.h"
+#include "gx.h"
+#include "gp.h"
+#include "gpcheck.h"
+#include "gserrors.h"
+#include "gxdevice.h"
+#include "gxdevmem.h" /* must precede gxcldev.h */
+#include "gxcldev.h"
+#include "gxclpath.h"
+#include "gsparams.h"
+
+/* ---------------- Statistics ---------------- */
+
+#ifdef DEBUG
+const char *const cmd_op_names[16] =
+{cmd_op_name_strings};
+private const char *const cmd_misc_op_names[16] =
+{cmd_misc_op_name_strings};
+private const char *const cmd_misc2_op_names[16] =
+{cmd_misc2_op_name_strings};
+private const char *const cmd_segment_op_names[16] =
+{cmd_segment_op_name_strings};
+private const char *const cmd_path_op_names[16] =
+{cmd_path_op_name_strings};
+const char *const *const cmd_sub_op_names[16] =
+{cmd_misc_op_names, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, cmd_misc2_op_names, cmd_segment_op_names, cmd_path_op_names
+};
+struct stats_cmd_s {
+ ulong op_counts[256];
+ ulong op_sizes[256];
+ ulong tile_reset, tile_found, tile_added;
+ ulong same_band, other_band;
+} stats_cmd;
+extern ulong stats_cmd_diffs[5]; /* in gxclpath.c */
+int
+cmd_count_op(int op, uint size)
+{
+ stats_cmd.op_counts[op]++;
+ stats_cmd.op_sizes[op] += size;
+ if (gs_debug_c('L')) {
+ const char *const *sub = cmd_sub_op_names[op >> 4];
+
+ if (sub)
+ dlprintf2(", %s(%u)\n", sub[op & 0xf], size);
+ else
+ dlprintf3(", %s %d(%u)\n", cmd_op_names[op >> 4], op & 0xf,
+ size);
+ fflush(dstderr);
+ }
+ return op;
+}
+void
+cmd_uncount_op(int op, uint size)
+{
+ stats_cmd.op_counts[op]--;
+ stats_cmd.op_sizes[op] -= size;
+}
+#endif
+
+/* Print statistics. */
+#ifdef DEBUG
+void
+cmd_print_stats(void)
+{
+ int ci, cj;
+
+ dlprintf3("[l]counts: reset = %lu, found = %lu, added = %lu\n",
+ stats_cmd.tile_reset, stats_cmd.tile_found,
+ stats_cmd.tile_added);
+ dlprintf5(" diff 2.5 = %lu, 3 = %lu, 4 = %lu, 2 = %lu, >4 = %lu\n",
+ stats_cmd_diffs[0], stats_cmd_diffs[1], stats_cmd_diffs[2],
+ stats_cmd_diffs[3], stats_cmd_diffs[4]);
+ dlprintf2(" same_band = %lu, other_band = %lu\n",
+ stats_cmd.same_band, stats_cmd.other_band);
+ for (ci = 0; ci < 0x100; ci += 0x10) {
+ const char *const *sub = cmd_sub_op_names[ci >> 4];
+
+ if (sub != 0) {
+ dlprintf1("[l] %s =", cmd_op_names[ci >> 4]);
+ for (cj = ci; cj < ci + 0x10; cj += 2)
+ dprintf6("\n\t%s = %lu(%lu), %s = %lu(%lu)",
+ sub[cj - ci],
+ stats_cmd.op_counts[cj], stats_cmd.op_sizes[cj],
+ sub[cj - ci + 1],
+ stats_cmd.op_counts[cj + 1], stats_cmd.op_sizes[cj + 1]);
+ } else {
+ ulong tcounts = 0, tsizes = 0;
+
+ for (cj = ci; cj < ci + 0x10; cj++)
+ tcounts += stats_cmd.op_counts[cj],
+ tsizes += stats_cmd.op_sizes[cj];
+ dlprintf3("[l] %s (%lu,%lu) =\n\t",
+ cmd_op_names[ci >> 4], tcounts, tsizes);
+ for (cj = ci; cj < ci + 0x10; cj++)
+ if (stats_cmd.op_counts[cj] == 0)
+ dputs(" -");
+ else
+ dprintf2(" %lu(%lu)", stats_cmd.op_counts[cj],
+ stats_cmd.op_sizes[cj]);
+ }
+ dputs("\n");
+ }
+}
+#endif /* DEBUG */
+
+/* ---------------- Writing utilities ---------------- */
+
+/* Write the commands for one band or band range. */
+private int /* ret 0 all ok, -ve error code, or +1 ok w/low-mem warning */
+cmd_write_band(gx_device_clist_writer * cldev, int band_min, int band_max,
+ cmd_list * pcl, byte cmd_end)
+{
+ const cmd_prefix *cp = pcl->head;
+ int code_b = 0;
+ int code_c = 0;
+
+ if (cp != 0 || cmd_end != cmd_opv_end_run) {
+ clist_file_ptr cfile = cldev->page_cfile;
+ clist_file_ptr bfile = cldev->page_bfile;
+ cmd_block cb;
+ byte end = cmd_count_op(cmd_end, 1);
+
+ if (cfile == 0 || bfile == 0)
+ return_error(gs_error_ioerror);
+ cb.band_min = band_min;
+ cb.band_max = band_max;
+ cb.pos = clist_ftell(cfile);
+ if_debug3('l', "[l]writing for bands (%d,%d) at %ld\n",
+ band_min, band_max, cb.pos);
+ clist_fwrite_chars(&cb, sizeof(cb), bfile);
+ if (cp != 0) {
+ pcl->tail->next = 0; /* terminate the list */
+ for (; cp != 0; cp = cp->next) {
+#ifdef DEBUG
+ if ((const byte *)cp < cldev->cbuf ||
+ (const byte *)cp >= cldev->cend ||
+ cp->size > cldev->cend - (const byte *)cp
+ ) {
+ lprintf1("cmd_write_band error at 0x%lx\n", (ulong) cp);
+ return_error(gs_error_Fatal);
+ }
+#endif
+ clist_fwrite_chars(cp + 1, cp->size, cfile);
+ }
+ pcl->head = pcl->tail = 0;
+ }
+ clist_fwrite_chars(&end, 1, cfile);
+ process_interrupts();
+ code_b = clist_ferror_code(bfile);
+ code_c = clist_ferror_code(cfile);
+ if (code_b < 0)
+ return_error(code_b);
+ if (code_c < 0)
+ return_error(code_c);
+ }
+ return code_b | code_c;
+}
+
+/* Write out the buffered commands, and reset the buffer. */
+int /* ret 0 all-ok, -ve error code, or +1 ok w/low-mem warning */
+cmd_write_buffer(gx_device_clist_writer * cldev, byte cmd_end)
+{
+ int nbands = cldev->nbands;
+ gx_clist_state *pcls;
+ int band;
+ int code = cmd_write_band(cldev, cldev->band_range_min,
+ cldev->band_range_max,
+ &cldev->band_range_list, cmd_opv_end_run);
+ int warning = code;
+
+ for (band = 0, pcls = cldev->states;
+ code >= 0 && band < nbands; band++, pcls++
+ ) {
+ code = cmd_write_band(cldev, band, band, &pcls->list, cmd_end);
+ warning |= code;
+ }
+ /* If an error occurred, finish cleaning up the pointers. */
+ for (; band < nbands; band++, pcls++)
+ pcls->list.head = pcls->list.tail = 0;
+ cldev->cnext = cldev->cbuf;
+ cldev->ccl = 0;
+#ifdef DEBUG
+ if (gs_debug_c('l'))
+ cmd_print_stats();
+#endif
+ return_check_interrupt(code != 0 ? code : warning);
+}
+
+/*
+ * Add a command to the appropriate band list, and allocate space for its
+ * data. Return the pointer to the data area. If an error or (low-memory
+ * warning) occurs, set cldev->error_code and return 0.
+ */
+#define cmd_headroom (sizeof(cmd_prefix) + arch_align_ptr_mod)
+byte *
+cmd_put_list_op(gx_device_clist_writer * cldev, cmd_list * pcl, uint size)
+{
+ byte *dp = cldev->cnext;
+
+ if (size + cmd_headroom > cldev->cend - dp) {
+ if ((cldev->error_code =
+ cmd_write_buffer(cldev, cmd_opv_end_run)) != 0) {
+ if (cldev->error_code < 0)
+ cldev->error_is_retryable = 0; /* hard error */
+ else {
+ /* upgrade lo-mem warning into an error */
+ if (!cldev->ignore_lo_mem_warnings)
+ cldev->error_code = gs_note_error(gs_error_VMerror);
+ cldev->error_is_retryable = 1;
+ }
+ return 0;
+ }
+ else
+ return cmd_put_list_op(cldev, pcl, size);
+ }
+ if (cldev->ccl == pcl) { /* We're adding another command for the same band. */
+ /* Tack it onto the end of the previous one. */
+ cmd_count_add1(stats_cmd.same_band);
+#ifdef DEBUG
+ if (pcl->tail->size > dp - (byte *) (pcl->tail + 1)) {
+ lprintf1("cmd_put_list_op error at 0x%lx\n", (ulong) pcl->tail);
+ }
+#endif
+ pcl->tail->size += size;
+ } else {
+ /* Skip to an appropriate alignment boundary. */
+ /* (We assume the command buffer itself is aligned.) */
+ cmd_prefix *cp = (cmd_prefix *)
+ (dp + ((cldev->cbuf - dp) & (arch_align_ptr_mod - 1)));
+
+ cmd_count_add1(stats_cmd.other_band);
+ dp = (byte *) (cp + 1);
+ if (pcl->tail != 0) {
+#ifdef DEBUG
+ if (pcl->tail < pcl->head ||
+ pcl->tail->size > dp - (byte *) (pcl->tail + 1)
+ ) {
+ lprintf1("cmd_put_list_op error at 0x%lx\n",
+ (ulong) pcl->tail);
+ }
+#endif
+ pcl->tail->next = cp;
+ } else
+ pcl->head = cp;
+ pcl->tail = cp;
+ cldev->ccl = pcl;
+ cp->size = size;
+ }
+ cldev->cnext = dp + size;
+ return dp;
+}
+#ifdef DEBUG
+byte *
+cmd_put_op(gx_device_clist_writer * cldev, gx_clist_state * pcls, uint size)
+{
+ if_debug3('L', "[L]band %d: size=%u, left=%u",
+ (int)(pcls - cldev->states),
+ size, (uint) (cldev->cend - cldev->cnext));
+ return cmd_put_list_op(cldev, &pcls->list, size);
+}
+#endif
+
+/* Add a command for a range of bands. */
+byte *
+cmd_put_range_op(gx_device_clist_writer * cldev, int band_min, int band_max,
+ uint size)
+{
+ if_debug4('L', "[L]band range(%d,%d): size=%u, left=%u",
+ band_min, band_max, size,
+ (uint)(cldev->cend - cldev->cnext));
+ if (cldev->ccl != 0 &&
+ (cldev->ccl != &cldev->band_range_list ||
+ band_min != cldev->band_range_min ||
+ band_max != cldev->band_range_max)
+ ) {
+ if ((cldev->error_code = cmd_write_buffer(cldev, cmd_opv_end_run)) != 0) {
+ if (cldev->error_code < 0)
+ cldev->error_is_retryable = 0; /* hard error */
+ else {
+ /* upgrade lo-mem warning into an error */
+ cldev->error_code = gs_error_VMerror;
+ cldev->error_is_retryable = 1;
+ }
+ return 0;
+ }
+ cldev->band_range_min = band_min;
+ cldev->band_range_max = band_max;
+ }
+ return cmd_put_list_op(cldev, &cldev->band_range_list, size);
+}
+
+/* Write a variable-size positive integer. */
+int
+cmd_size_w(register uint w)
+{
+ register int size = 1;
+
+ while (w > 0x7f)
+ w >>= 7, size++;
+ return size;
+}
+byte *
+cmd_put_w(register uint w, register byte * dp)
+{
+ while (w > 0x7f)
+ *dp++ = w | 0x80, w >>= 7;
+ *dp = w;
+ return dp + 1;
+}
+
+/* Define the encodings of the different settable colors. */
+const clist_select_color_t
+ clist_select_color0 = {cmd_op_set_color0, cmd_opv_delta2_color0, 0},
+ clist_select_color1 = {cmd_op_set_color1, cmd_opv_delta2_color1, 0},
+ clist_select_tile_color0 = {cmd_op_set_color0, cmd_opv_delta2_color0, 1},
+ clist_select_tile_color1 = {cmd_op_set_color1, cmd_opv_delta2_color1, 1};
+int
+cmd_put_color(gx_device_clist_writer * cldev, gx_clist_state * pcls,
+ const clist_select_color_t * select,
+ gx_color_index color, gx_color_index * pcolor)
+{
+ byte *dp;
+ long diff = (long)color - (long)(*pcolor);
+ byte op, op_delta2;
+ int code;
+
+ if (diff == 0)
+ return 0;
+ if (select->tile_color) {
+ code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_tile_color, 1);
+ if (code < 0)
+ return code;
+ }
+ op = select->set_op;
+ op_delta2 = select->delta2_op;
+ if (color == gx_no_color_index) {
+ /*
+ * We must handle this specially, because it may take more
+ * bytes than the color depth.
+ */
+ code = set_cmd_put_op(dp, cldev, pcls, op + 15, 1);
+ if (code < 0)
+ return code;
+ } else {
+ long delta;
+ byte operand;
+
+ switch ((cldev->color_info.depth + 15) >> 3) {
+ case 5:
+ if (!((delta = diff + cmd_delta1_32_bias) &
+ ~cmd_delta1_32_mask) &&
+ (operand =
+ (byte) ((delta >> 23) + ((delta >> 18) & 1))) != 0 &&
+ operand != 15
+ ) {
+ code = set_cmd_put_op(dp, cldev, pcls,
+ (byte) (op + operand), 2);
+ if (code < 0)
+ return code;
+ dp[1] = (byte) (((delta >> 10) & 0300) +
+ (delta >> 5) + delta);
+ break;
+ }
+ if (!((delta = diff + cmd_delta2_32_bias) &
+ ~cmd_delta2_32_mask)
+ ) {
+ code = set_cmd_put_op(dp, cldev, pcls, op_delta2, 3);
+ if (code < 0)
+ return code;
+ dp[1] = (byte) ((delta >> 20) + (delta >> 16));
+ dp[2] = (byte) ((delta >> 4) + delta);
+ break;
+ }
+ code = set_cmd_put_op(dp, cldev, pcls, op, 5);
+ if (code < 0)
+ return code;
+ *++dp = (byte) (color >> 24);
+ goto b3;
+ case 4:
+ if (!((delta = diff + cmd_delta1_24_bias) &
+ ~cmd_delta1_24_mask) &&
+ (operand = (byte) (delta >> 16)) != 0 &&
+ operand != 15
+ ) {
+ code = set_cmd_put_op(dp, cldev, pcls,
+ (byte) (op + operand), 2);
+ if (code < 0)
+ return code;
+ dp[1] = (byte) ((delta >> 4) + delta);
+ break;
+ }
+ if (!((delta = diff + cmd_delta2_24_bias) &
+ ~cmd_delta2_24_mask)
+ ) {
+ code = set_cmd_put_op(dp, cldev, pcls, op_delta2, 3);
+ if (code < 0)
+ return code;
+ dp[1] = ((byte) (delta >> 13) & 0xf8) +
+ ((byte) (delta >> 11) & 7);
+ dp[2] = (byte) (((delta >> 3) & 0xe0) + delta);
+ break;
+ }
+ code = set_cmd_put_op(dp, cldev, pcls, op, 4);
+ if (code < 0)
+ return code;
+b3: *++dp = (byte) (color >> 16);
+ goto b2;
+ case 3:
+ code = set_cmd_put_op(dp, cldev, pcls, op, 3);
+ if (code < 0)
+ return code;
+b2: *++dp = (byte) (color >> 8);
+ goto b1;
+ case 2:
+ if (diff >= -7 && diff < 7) {
+ code = set_cmd_put_op(dp, cldev, pcls,
+ op + (int)diff + 8, 1);
+ if (code < 0)
+ return code;
+ break;
+ }
+ code = set_cmd_put_op(dp, cldev, pcls, op, 2);
+ if (code < 0)
+ return code;
+b1: dp[1] = (byte) color;
+ }
+ }
+ *pcolor = color;
+ return 0;
+}
+
+/* Put out a command to set the tile colors. */
+int
+cmd_set_tile_colors(gx_device_clist_writer * cldev, gx_clist_state * pcls,
+ gx_color_index color0, gx_color_index color1)
+{
+ int code = 0;
+
+ if (color0 != pcls->tile_colors[0]) {
+ code = cmd_put_color(cldev, pcls,
+ &clist_select_tile_color0,
+ color0, &pcls->tile_colors[0]);
+ if (code != 0)
+ return code;
+ }
+ if (color1 != pcls->tile_colors[1])
+ code = cmd_put_color(cldev, pcls,
+ &clist_select_tile_color1,
+ color1, &pcls->tile_colors[1]);
+ return code;
+}
+
+/* Put out a command to set the tile phase. */
+int
+cmd_set_tile_phase(gx_device_clist_writer * cldev, gx_clist_state * pcls,
+ int px, int py)
+{
+ int pcsize;
+ byte *dp;
+ int code;
+
+ pcsize = 1 + cmd_size2w(px, py);
+ code =
+ set_cmd_put_op(dp, cldev, pcls, (byte)cmd_opv_set_tile_phase, pcsize);
+ if (code < 0)
+ return code;
+ ++dp;
+ pcls->tile_phase.x = px;
+ pcls->tile_phase.y = py;
+ cmd_putxy(pcls->tile_phase, dp);
+ return 0;
+}
+
+/* Write a command to enable or disable the logical operation. */
+int
+cmd_put_enable_lop(gx_device_clist_writer * cldev, gx_clist_state * pcls,
+ int enable)
+{
+ byte *dp;
+ int code = set_cmd_put_op(dp, cldev, pcls,
+ (byte)(enable ? cmd_opv_enable_lop :
+ cmd_opv_disable_lop),
+ 1);
+
+ if (code < 0)
+ return code;
+ pcls->lop_enabled = enable;
+ return 0;
+}
+
+/* Write a command to enable or disable clipping. */
+/* This routine is only called if the path extensions are included. */
+int
+cmd_put_enable_clip(gx_device_clist_writer * cldev, gx_clist_state * pcls,
+ int enable)
+{
+ byte *dp;
+ int code = set_cmd_put_op(dp, cldev, pcls,
+ (byte)(enable ? cmd_opv_enable_clip :
+ cmd_opv_disable_clip),
+ 1);
+
+ if (code < 0)
+ return code;
+ pcls->clip_enabled = enable;
+ return 0;
+}
+
+/* Write a command to set the logical operation. */
+int
+cmd_set_lop(gx_device_clist_writer * cldev, gx_clist_state * pcls,
+ gs_logical_operation_t lop)
+{
+ byte *dp;
+ uint lop_msb = lop >> 6;
+ int code = set_cmd_put_op(dp, cldev, pcls,
+ cmd_opv_set_misc, 2 + cmd_size_w(lop_msb));
+
+ if (code < 0)
+ return code;
+ dp[1] = cmd_set_misc_lop + (lop & 0x3f);
+ cmd_put_w(lop_msb, dp + 2);
+ pcls->lop = lop;
+ return 0;
+}
+
+/* Disable (if default) or enable the logical operation, setting it if */
+/* needed. */
+int
+cmd_update_lop(gx_device_clist_writer *cldev, gx_clist_state *pcls,
+ gs_logical_operation_t lop)
+{
+ int code;
+
+ if (lop == lop_default)
+ return cmd_disable_lop(cldev, pcls);
+ code = cmd_set_lop(cldev, pcls, lop);
+ if (code < 0)
+ return code;
+ return cmd_enable_lop(cldev, pcls);
+}
+
+/* Write a parameter list */
+int /* ret 0 all ok, -ve error */
+cmd_put_params(gx_device_clist_writer *cldev,
+ gs_param_list *param_list) /* NB open for READ */
+{
+ byte *dp;
+ int code;
+ byte local_buf[512]; /* arbitrary */
+ int param_length;
+
+ /* Get serialized list's length + try to get it into local var if it fits. */
+ param_length = code =
+ gs_param_list_serialize(param_list, local_buf, sizeof(local_buf));
+ if (param_length > 0) {
+ /* Get cmd buffer space for serialized */
+ code = set_cmd_put_all_op(dp, cldev, cmd_opv_put_params,
+ 1 + sizeof(unsigned) + param_length);
+ if (code < 0)
+ return code;
+
+ /* write param list to cmd list: needs to all fit in cmd buffer */
+ if_debug1('l', "[l]put_params, length=%d\n", param_length);
+ ++dp;
+ memcpy(dp, &param_length, sizeof(unsigned));
+ dp += sizeof(unsigned);
+ if (param_length > sizeof(local_buf)) {
+ int old_param_length = param_length;
+
+ param_length = code =
+ gs_param_list_serialize(param_list, dp, old_param_length);
+ if (param_length >= 0)
+ code = (old_param_length != param_length ?
+ gs_note_error(gs_error_unknownerror) : 0);
+ if (code < 0) {
+ /* error serializing: back out by writing a 0-length parm list */
+ memset(dp - sizeof(unsigned), 0, sizeof(unsigned));
+ cmd_shorten_list_op(cldev, &cldev->band_range_list,
+ old_param_length);
+ }
+ } else
+ memcpy(dp, local_buf, param_length); /* did this when computing length */
+ }
+ return code;
+}
diff --git a/pstoraster/gxclzlib.c b/pstoraster/gxclzlib.c
new file mode 100644
index 000000000..8b2edbd18
--- /dev/null
+++ b/pstoraster/gxclzlib.c
@@ -0,0 +1,76 @@
+/*
+ Copyright 1993-2002 by Easy Software Products
+ 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.
+*/
+
+#include <config.h>
+/*$Id$ */
+/* zlib filter initialization for RAM-based band lists */
+/* Must be compiled with -I$(ZSRCDIR) */
+#include "std.h"
+#include "gstypes.h"
+#include "gsmemory.h"
+#include "gxclmem.h"
+
+#ifdef HAVE_LIBZ
+#include "szlibx.h"
+
+private stream_zlib_state cl_zlibE_state;
+private stream_zlib_state cl_zlibD_state;
+
+/* Initialize the states to be copied. */
+void
+gs_cl_zlib_init(gs_memory_t * mem)
+{
+ s_zlib_set_defaults((stream_state *) & cl_zlibE_state);
+ cl_zlibE_state.no_wrapper = true;
+ cl_zlibE_state.template = &s_zlibE_template;
+ s_zlib_set_defaults((stream_state *) & cl_zlibD_state);
+ cl_zlibD_state.no_wrapper = true;
+ cl_zlibD_state.template = &s_zlibD_template;
+}
+
+/* Return the prototypes for compressing/decompressing the band list. */
+const stream_state *
+clist_compressor_state(void *client_data)
+{
+ return (const stream_state *)&cl_zlibE_state;
+}
+const stream_state *
+clist_decompressor_state(void *client_data)
+{
+ return (const stream_state *)&cl_zlibD_state;
+}
+#else
+const stream_state *
+clist_compressor_state(void *client_data)
+{
+ return (const stream_state *)0;
+}
+const stream_state *
+clist_decompressor_state(void *client_data)
+{
+ return (const stream_state *)0;
+}
+#endif /* HAVE_LIBZ */
diff --git a/pstoraster/gxcmap.c b/pstoraster/gxcmap.c
new file mode 100644
index 000000000..99ec9c5ed
--- /dev/null
+++ b/pstoraster/gxcmap.c
@@ -0,0 +1,890 @@
+/* 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$ */
+/* Color mapping for Ghostscript */
+#include "gx.h"
+#include "gserrors.h"
+#include "gsccolor.h"
+#include "gxalpha.h"
+#include "gxcspace.h"
+#include "gxfarith.h"
+#include "gxfrac.h"
+#include "gxdcconv.h"
+#include "gxdevice.h"
+#include "gxcmap.h"
+#include "gxlum.h"
+#include "gzstate.h"
+#include "gxdither.h"
+
+/* Structure descriptor */
+public_st_device_color();
+#define cptr ((gx_device_color *)vptr)
+private
+ENUM_PTRS_BEGIN(device_color_enum_ptrs)
+{
+ return ENUM_USING(*cptr->type->stype, vptr, size, index);
+}
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(device_color_reloc_ptrs)
+{
+ RELOC_USING(*cptr->type->stype, vptr, size);
+}
+RELOC_PTRS_END
+#undef cptr
+
+/* ------ Trace device mapping procedures ------ */
+
+/* If DEBUG is defined, these procedures substitute for direct calls */
+/* on the device map_{rgb,cmyk}_color procedures. */
+
+gx_color_index
+gx_proc_map_rgb_color(gx_device * dev,
+ gx_color_value vr, gx_color_value vg, gx_color_value vb)
+{
+ gx_color_index cindex =
+ (*dev_proc(dev, map_rgb_color)) (dev, vr, vg, vb);
+
+ if_debug5('C', "%s [C]RGB %u,%u,%u -> color 0x%lx\n",
+ dev->dname, (uint) vr, (uint) vg, (uint) vb, (ulong) cindex);
+ return cindex;
+}
+
+gx_color_index
+gx_proc_map_rgb_alpha_color(gx_device * dev,
+ gx_color_value vr, gx_color_value vg, gx_color_value vb, gx_color_value va)
+{
+ gx_color_index cindex =
+ (*dev_proc(dev, map_rgb_alpha_color)) (dev, vr, vg, vb, va);
+
+ if_debug6('C', "[C]%s RGBA %u,%u,%u,%u -> color 0x%lx\n",
+ dev->dname, (uint) vr, (uint) vg, (uint) vb, (uint) va,
+ (ulong) cindex);
+ return cindex;
+}
+
+gx_color_index
+gx_proc_map_cmyk_color(gx_device * dev,
+ gx_color_value vc, gx_color_value vm, gx_color_value vy, gx_color_value vk)
+{
+ gx_color_index cindex =
+ (*dev_proc(dev, map_cmyk_color)) (dev, vc, vm, vy, vk);
+
+ if_debug6('C', "[C]%s CMYK %u,%u,%u,%u -> color 0x%lx\n",
+ dev->dname, (uint) vc, (uint) vm, (uint) vy, (uint) vk,
+ (ulong) cindex);
+ return cindex;
+}
+
+/* ---------------- Device color rendering ---------------- */
+
+private cmap_proc_gray(cmap_gray_halftoned);
+private cmap_proc_gray(cmap_gray_direct);
+private cmap_proc_gray(cmap_gray_to_rgb_halftoned);
+private cmap_proc_gray(cmap_gray_to_rgb_direct);
+private cmap_proc_gray(cmap_gray_to_cmyk_halftoned);
+private cmap_proc_gray(cmap_gray_to_cmyk_direct);
+private cmap_proc_rgb(cmap_rgb_halftoned);
+private cmap_proc_rgb(cmap_rgb_direct);
+private cmap_proc_rgb(cmap_rgb_to_gray_halftoned);
+private cmap_proc_rgb(cmap_rgb_to_gray_direct);
+private cmap_proc_rgb(cmap_rgb_to_cmyk);
+
+#define cmap_cmyk_halftoned cmap_cmyk_direct
+private cmap_proc_cmyk(cmap_cmyk_direct);
+private cmap_proc_cmyk(cmap_cmyk_to_gray);
+private cmap_proc_cmyk(cmap_cmyk_to_rgb);
+private cmap_proc_rgb_alpha(cmap_rgb_alpha_halftoned);
+private cmap_proc_rgb_alpha(cmap_rgb_alpha_direct);
+
+/* Procedure names are only guaranteed unique to 23 characters.... */
+private cmap_proc_rgb_alpha(cmap_rgb_alpha2gray_halftoned);
+private cmap_proc_rgb_alpha(cmap_rgb_alpha2gray_direct);
+private cmap_proc_rgb_alpha(cmap_rgb_alpha_to_cmyk);
+
+private const gx_color_map_procs
+ cmap_gray_few =
+{cmap_gray_halftoned, cmap_rgb_to_gray_halftoned, cmap_cmyk_to_gray,
+ cmap_rgb_alpha2gray_halftoned
+}, cmap_gray_many =
+{cmap_gray_direct, cmap_rgb_to_gray_direct, cmap_cmyk_to_gray,
+ cmap_rgb_alpha2gray_direct
+}, cmap_rgb_few =
+{cmap_gray_to_rgb_halftoned, cmap_rgb_halftoned, cmap_cmyk_to_rgb,
+ cmap_rgb_alpha_halftoned
+}, cmap_rgb_many =
+{cmap_gray_to_rgb_direct, cmap_rgb_direct, cmap_cmyk_to_rgb,
+ cmap_rgb_alpha_direct
+}, cmap_cmyk_few =
+{cmap_gray_to_cmyk_halftoned, cmap_rgb_to_cmyk, cmap_cmyk_halftoned,
+ cmap_rgb_alpha_to_cmyk
+}, cmap_cmyk_many =
+{cmap_gray_to_cmyk_direct, cmap_rgb_to_cmyk, cmap_cmyk_direct,
+ cmap_rgb_alpha_to_cmyk
+};
+
+const gx_color_map_procs *const cmap_procs_default = &cmap_gray_many;
+
+private const gx_color_map_procs *const cmap_few[] =
+{
+ 0, &cmap_gray_few, 0, &cmap_rgb_few, &cmap_cmyk_few
+};
+
+private const gx_color_map_procs *const cmap_many[] =
+{
+ 0, &cmap_gray_many, 0, &cmap_rgb_many, &cmap_cmyk_many
+};
+
+/* Determine the color mapping procedures for a device. */
+const gx_color_map_procs *
+gx_device_cmap_procs(const gx_device * dev)
+{
+ return (gx_device_must_halftone(dev) ? cmap_few : cmap_many)
+ [dev->color_info.num_components];
+}
+
+/* Set the color mapping procedures in the graphics state. */
+void
+gx_set_cmap_procs(gs_imager_state * pis, const gx_device * dev)
+{
+ pis->cmap_procs = gx_device_cmap_procs(dev);
+}
+
+/* Remap the color in the graphics state. */
+int
+gx_remap_color(gs_state * pgs)
+{
+ const gs_color_space *pcs = pgs->color_space;
+
+ /* The current color in the graphics state is always used for */
+ /* the texture, never for the source. */
+ return (*pcs->type->remap_color) (pgs->ccolor, pcs, pgs->dev_color,
+ (gs_imager_state *) pgs, pgs->device,
+ gs_color_select_texture);
+}
+
+/* Indicate that a color space has no underlying concrete space. */
+const gs_color_space *
+gx_no_concrete_space(const gs_color_space * pcs, const gs_imager_state * pis)
+{
+ return NULL;
+}
+
+/* Indicate that a color space is concrete. */
+const gs_color_space *
+gx_same_concrete_space(const gs_color_space * pcs, const gs_imager_state * pis)
+{
+ return pcs;
+}
+
+/* Indicate that a color cannot be concretized. */
+int
+gx_no_concretize_color(const gs_client_color * pcc, const gs_color_space * pcs,
+ frac * pconc, const gs_imager_state * pis)
+{
+ return_error(gs_error_rangecheck);
+}
+
+/* By default, remap a color by concretizing it and then */
+/* remapping the concrete color. */
+int
+gx_default_remap_color(const gs_client_color * pcc, const gs_color_space * pcs,
+ gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
+ gs_color_select_t select)
+{
+ frac conc[4];
+ const gs_color_space *pconcs;
+ int code = (*pcs->type->concretize_color) (pcc, pcs, conc, pis);
+
+ if (code < 0)
+ return code;
+ pconcs = cs_concrete_space(pcs, pis);
+ return (*pconcs->type->remap_concrete_color) (conc, pdc, pis, dev,
+ select);
+}
+
+/* Color remappers for the standard color spaces. */
+/* Note that we use D... instead of Device... in some places because */
+/* gcc under VMS only retains 23 characters of procedure names. */
+
+#define unit_frac(v, ftemp)\
+ (ftemp = (v),\
+ (is_fneg(ftemp) ? frac_0 : is_fge1(ftemp) ? frac_1 : float2frac(ftemp)))
+
+/* DeviceGray */
+int
+gx_concretize_DeviceGray(const gs_client_color * pc, const gs_color_space * pcs,
+ frac * pconc, const gs_imager_state * pis)
+{
+ float ftemp;
+
+ pconc[0] = unit_frac(pc->paint.values[0], ftemp);
+ return 0;
+}
+int
+gx_remap_concrete_DGray(const frac * pconc,
+ gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
+ gs_color_select_t select)
+{
+ if (pis->alpha == gx_max_color_value)
+ (*pis->cmap_procs->map_gray)
+ (pconc[0], pdc, pis, dev, select);
+ else
+ (*pis->cmap_procs->map_rgb_alpha)
+ (pconc[0], pconc[0], pconc[0], cv2frac(pis->alpha),
+ pdc, pis, dev, select);
+ return 0;
+}
+int
+gx_remap_DeviceGray(const gs_client_color * pc, const gs_color_space * pcs,
+ gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
+ gs_color_select_t select)
+{
+ float ftemp;
+ frac fgray = unit_frac(pc->paint.values[0], ftemp);
+
+ if (pis->alpha == gx_max_color_value)
+ (*pis->cmap_procs->map_gray)
+ (fgray, pdc, pis, dev, select);
+ else
+ (*pis->cmap_procs->map_rgb_alpha)
+ (fgray, fgray, fgray, cv2frac(pis->alpha), pdc, pis, dev, select);
+ return 0;
+}
+
+/* DeviceRGB */
+int
+gx_concretize_DeviceRGB(const gs_client_color * pc, const gs_color_space * pcs,
+ frac * pconc, const gs_imager_state * pis)
+{
+ float ftemp;
+
+ pconc[0] = unit_frac(pc->paint.values[0], ftemp);
+ pconc[1] = unit_frac(pc->paint.values[1], ftemp);
+ pconc[2] = unit_frac(pc->paint.values[2], ftemp);
+ return 0;
+}
+int
+gx_remap_concrete_DRGB(const frac * pconc,
+ gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
+ gs_color_select_t select)
+{
+ if (pis->alpha == gx_max_color_value)
+ gx_remap_concrete_rgb(pconc[0], pconc[1], pconc[2],
+ pdc, pis, dev, select);
+ else
+ gx_remap_concrete_rgb_alpha(pconc[0], pconc[1], pconc[2],
+ cv2frac(pis->alpha),
+ pdc, pis, dev, select);
+ return 0;
+}
+int
+gx_remap_DeviceRGB(const gs_client_color * pc, const gs_color_space * pcs,
+ gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
+ gs_color_select_t select)
+{
+ float ftemp;
+ frac fred = unit_frac(pc->paint.values[0], ftemp), fgreen = unit_frac(pc->paint.values[1], ftemp),
+ fblue = unit_frac(pc->paint.values[2], ftemp);
+
+ if (pis->alpha == gx_max_color_value)
+ gx_remap_concrete_rgb(fred, fgreen, fblue,
+ pdc, pis, dev, select);
+ else
+ gx_remap_concrete_rgb_alpha(fred, fgreen, fblue, cv2frac(pis->alpha),
+ pdc, pis, dev, select);
+ return 0;
+}
+
+/* DeviceCMYK */
+int
+gx_concretize_DeviceCMYK(const gs_client_color * pc, const gs_color_space * pcs,
+ frac * pconc, const gs_imager_state * pis)
+{
+ float ftemp;
+
+ pconc[0] = unit_frac(pc->paint.values[0], ftemp);
+ pconc[1] = unit_frac(pc->paint.values[1], ftemp);
+ pconc[2] = unit_frac(pc->paint.values[2], ftemp);
+ pconc[3] = unit_frac(pc->paint.values[3], ftemp);
+ return 0;
+}
+int
+gx_remap_concrete_DCMYK(const frac * pconc,
+ gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
+ gs_color_select_t select)
+{
+/****** IGNORE alpha ******/
+ gx_remap_concrete_cmyk(pconc[0], pconc[1], pconc[2], pconc[3], pdc,
+ pis, dev, select);
+ return 0;
+}
+int
+gx_remap_DeviceCMYK(const gs_client_color * pc, const gs_color_space * pcs,
+ gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
+ gs_color_select_t select)
+{
+/****** IGNORE alpha ******/
+ float ft0, ft1, ft2, ft3;
+
+ gx_remap_concrete_cmyk(unit_frac(pc->paint.values[0], ft0),
+ unit_frac(pc->paint.values[1], ft1),
+ unit_frac(pc->paint.values[2], ft2),
+ unit_frac(pc->paint.values[3], ft3),
+ pdc, pis, dev, select);
+ return 0;
+}
+
+/* ------ Render Gray color. ------ */
+
+private void
+cmap_gray_halftoned(frac gray, gx_device_color * pdc,
+ const gs_imager_state * pis, gx_device * dev, gs_color_select_t select)
+{
+ if (gx_render_gray(gx_map_color_frac(pis, gray, effective_transfer.colored.gray), pdc, pis, dev, select) == 1)
+ gx_color_load_select(pdc, pis, dev, select);
+}
+
+private void
+cmap_gray_direct(frac gray, gx_device_color * pdc, const gs_imager_state * pis,
+ gx_device * dev, gs_color_select_t select)
+{
+ frac mgray = gx_map_color_frac(pis, gray, effective_transfer.colored.gray);
+ gx_color_value cv_gray = frac2cv(mgray);
+ gx_color_index color =
+ (pis->alpha == gx_max_color_value ?
+ gx_map_rgb_color(dev, cv_gray, cv_gray, cv_gray) :
+ gx_map_rgb_alpha_color(dev, cv_gray, cv_gray, cv_gray, pis->alpha));
+
+ if (color == gx_no_color_index) {
+ if (gx_render_gray(mgray, pdc, pis, dev, select) == 1)
+ gx_color_load_select(pdc, pis, dev, select);
+ return;
+ }
+ color_set_pure(pdc, color);
+}
+
+private void
+cmap_gray_to_rgb_halftoned(frac gray, gx_device_color * pdc,
+ const gs_imager_state * pis, gx_device * dev, gs_color_select_t select)
+{
+ cmap_rgb_halftoned(gray, gray, gray, pdc, pis, dev, select);
+}
+
+private void
+cmap_gray_to_rgb_direct(frac gray, gx_device_color * pdc,
+ const gs_imager_state * pis, gx_device * dev, gs_color_select_t select)
+{
+ cmap_rgb_direct(gray, gray, gray, pdc, pis, dev, select);
+}
+
+private void
+cmap_gray_to_cmyk_halftoned(frac gray, gx_device_color * pdc,
+ const gs_imager_state * pis, gx_device * dev, gs_color_select_t select)
+{ /*
+ * Per the last paragraph of section 6.3 (p. 309) of the
+ * PostScript Language Reference Manual, 2nd Edition,
+ * we must bypass the C, M, and Y transfer functions in this case.
+ */
+ frac mgray = gx_map_color_frac(pis, gray, effective_transfer.colored.gray);
+
+ if (gx_render_gray(mgray, pdc, pis, dev, select) == 1)
+ gx_color_load_select(pdc, pis, dev, select);
+}
+
+private void
+cmap_gray_to_cmyk_direct(frac gray, gx_device_color * pdc,
+ const gs_imager_state * pis, gx_device * dev, gs_color_select_t select)
+{ /*
+ * Per the last paragraph of section 6.3 (p. 309) of the
+ * PostScript Language Reference Manual, 2nd Edition,
+ * we must bypass the C, M, and Y transfer functions in this case.
+ */
+ frac mgray = gx_map_color_frac(pis, gray, effective_transfer.colored.gray);
+ frac mblack = frac_1 - mgray;
+ gx_color_index color =
+ gx_map_cmyk_color(dev,
+ frac2cv(frac_0), frac2cv(frac_0),
+ frac2cv(frac_0), frac2cv(mblack));
+
+ if (color != gx_no_color_index) {
+ color_set_pure(pdc, color);
+ return;
+ }
+ if (gx_render_gray(mgray, pdc, pis, dev, select) == 1)
+ gx_color_load_select(pdc, pis, dev, select);
+}
+
+/* ------ Render RGB color. ------ */
+
+/*
+ * This code should test r == g and g == b and then use the gray
+ * rendering procedures. The Adobe documentation allows this:
+ * conversion between color spaces occurs before the transfer function
+ * and halftoning. However, output from FrameMaker (mis)uses the
+ * transfer function to provide the equivalent of indexed color;
+ * it requires the color components to be passed through unchanged.
+ * For this reason, we have to make the check after the transfer
+ * function rather than before.
+ *
+ * Since this procedure is used so heavily, we duplicate most of its code
+ * rather than making a text for color_info.max_color >= 31.
+ */
+
+private void
+cmap_rgb_halftoned(frac r, frac g, frac b, gx_device_color * pdc,
+ const gs_imager_state * pis, gx_device * dev, gs_color_select_t select)
+{
+ frac mred = gx_map_color_frac(pis, r, effective_transfer.colored.red);
+ frac mgreen = gx_map_color_frac(pis, g, effective_transfer.colored.green);
+ frac mblue = gx_map_color_frac(pis, b, effective_transfer.colored.blue);
+
+ if ((mred == mgreen && mred == mblue ? /* gray shade */
+ gx_render_gray(mred, pdc, pis, dev, select) :
+ gx_render_rgb(mred, mgreen, mblue, pdc, pis, dev, select)) == 1)
+ gx_color_load_select(pdc, pis, dev, select);
+}
+
+private void
+cmap_rgb_direct(frac r, frac g, frac b, gx_device_color * pdc,
+ const gs_imager_state * pis, gx_device * dev, gs_color_select_t select)
+{
+ frac mred = gx_map_color_frac(pis, r, effective_transfer.colored.red);
+ frac mgreen = gx_map_color_frac(pis, g, effective_transfer.colored.green);
+ frac mblue = gx_map_color_frac(pis, b, effective_transfer.colored.blue);
+ gx_color_index color =
+ (pis->alpha == gx_max_color_value ?
+ gx_map_rgb_color(dev, frac2cv(mred), frac2cv(mgreen),
+ frac2cv(mblue)) :
+ gx_map_rgb_alpha_color(dev, frac2cv(mred), frac2cv(mgreen),
+ frac2cv(mblue), pis->alpha));
+
+ if (color != gx_no_color_index) {
+ color_set_pure(pdc, color);
+ return;
+ }
+ if ((mred == mgreen && mred == mblue ? /* gray shade */
+ gx_render_gray(mred, pdc, pis, dev, select) :
+ gx_render_rgb(mred, mgreen, mblue, pdc, pis, dev, select)) == 1)
+ gx_color_load_select(pdc, pis, dev, select);
+}
+
+private void
+cmap_rgb_to_gray_halftoned(frac r, frac g, frac b, gx_device_color * pdc,
+ const gs_imager_state * pis, gx_device * dev, gs_color_select_t select)
+{
+ cmap_gray_halftoned(color_rgb_to_gray(r, g, b, pis), pdc, pis, dev, select);
+}
+
+private void
+cmap_rgb_to_gray_direct(frac r, frac g, frac b, gx_device_color * pdc,
+ const gs_imager_state * pis, gx_device * dev, gs_color_select_t select)
+{
+ cmap_gray_direct(color_rgb_to_gray(r, g, b, pis), pdc, pis, dev, select);
+}
+
+private void
+cmap_rgb_to_cmyk(frac r, frac g, frac b, gx_device_color * pdc,
+ const gs_imager_state * pis, gx_device * dev, gs_color_select_t select)
+{
+ frac cmyk[4];
+
+ color_rgb_to_cmyk(r, g, b, pis, cmyk);
+ (*pis->cmap_procs->map_cmyk) (cmyk[0], cmyk[1], cmyk[2], cmyk[3], pdc, pis, dev, select);
+}
+
+/* ------ Render CMYK color. ------ */
+
+private void
+cmap_cmyk_to_gray(frac c, frac m, frac y, frac k, gx_device_color * pdc,
+ const gs_imager_state * pis, gx_device * dev, gs_color_select_t select)
+{
+ (*pis->cmap_procs->map_gray) (color_cmyk_to_gray(c, m, y, k, pis), pdc, pis, dev, select);
+}
+
+private void
+cmap_cmyk_direct(frac c, frac m, frac y, frac k, gx_device_color * pdc,
+ const gs_imager_state * pis, gx_device * dev, gs_color_select_t select)
+{
+ frac mcyan = frac_1 - gx_map_color_frac(pis, frac_1 - c, effective_transfer.colored.red);
+ frac mmagenta = frac_1 - gx_map_color_frac(pis, frac_1 - m, effective_transfer.colored.green);
+ frac myellow = frac_1 - gx_map_color_frac(pis, frac_1 - y, effective_transfer.colored.blue);
+ frac mblack = frac_1 - gx_map_color_frac(pis, frac_1 - k, effective_transfer.colored.gray);
+
+ /* We make a test for direct vs. halftoned, rather than */
+ /* duplicating most of the code of this procedure. */
+ if (!gx_color_device_must_halftone(dev)) {
+ gx_color_index color =
+ gx_map_cmyk_color(dev,
+ frac2cv(mcyan), frac2cv(mmagenta),
+ frac2cv(myellow), frac2cv(mblack));
+
+ if (color != gx_no_color_index) {
+ color_set_pure(pdc, color);
+ return;
+ }
+ }
+ /* Don't convert colors with C = M = Y to gray shades: */
+ /* on a CMYK device, this may produce quite different output. */
+ if (gx_render_cmyk(mcyan, mmagenta, myellow, mblack, pdc, pis, dev, select) == 1)
+ gx_color_load_select(pdc, pis, dev, select);
+}
+
+private void
+cmap_cmyk_to_rgb(frac c, frac m, frac y, frac k, gx_device_color * pdc,
+ const gs_imager_state * pis, gx_device * dev, gs_color_select_t select)
+{
+ frac rgb[3];
+
+ color_cmyk_to_rgb(c, m, y, k, pis, rgb);
+ (*pis->cmap_procs->map_rgb) (rgb[0], rgb[1], rgb[2], pdc, pis, dev, select);
+}
+
+/* ------ Render RGB+alpha color. ------ */
+
+#ifdef PREMULTIPLY_TOWARDS_WHITE
+# define alpha_bias_value frac_1 - alpha
+# define alpha_bias(v) ((v) + alpha_bias_value
+#else
+# define alpha_bias(v) (v)
+#endif
+
+private void
+cmap_rgb_alpha2gray_halftoned(frac r, frac g, frac b, frac alpha,
+ gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
+ gs_color_select_t select)
+{
+ frac gray = color_rgb_to_gray(r, g, b, pis);
+
+ if (alpha != frac_1) /* premultiply */
+ gray = alpha_bias((frac) ((long)gray * alpha / frac_1));
+ if (gx_render_gray_alpha(gx_map_color_frac(pis, gray, effective_transfer.colored.gray), frac2cv(alpha), pdc, pis, dev, select) == 1)
+ gx_color_load_select(pdc, pis, dev, select);
+}
+
+private void
+cmap_rgb_alpha2gray_direct(frac r, frac g, frac b, frac alpha,
+ gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
+ gs_color_select_t select)
+{
+ frac gray = color_rgb_to_gray(r, g, b, pis);
+
+ if (alpha != frac_1) /* premultiply */
+ gray = alpha_bias((frac) ((long)gray * alpha / frac_1));
+ {
+ frac mgray =
+ gx_map_color_frac(pis, gray, effective_transfer.colored.gray);
+ gx_color_value cv_gray = frac2cv(mgray);
+ gx_color_index color =
+ (alpha == frac_1 ?
+ gx_map_rgb_color(dev, cv_gray, cv_gray, cv_gray) :
+ gx_map_rgb_alpha_color(dev, cv_gray, cv_gray, cv_gray, frac2cv(alpha)));
+
+ if (color == gx_no_color_index) {
+ if (gx_render_gray_alpha(mgray, frac2cv(alpha), pdc, pis, dev, select) == 1)
+ gx_color_load_select(pdc, pis, dev, select);
+ return;
+ }
+ color_set_pure(pdc, color);
+ }
+}
+
+private void
+cmap_rgb_alpha_halftoned(frac r, frac g, frac b, frac alpha,
+ gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
+ gs_color_select_t select)
+{
+ frac red = r, green = g, blue = b;
+
+ if (alpha != frac_1) { /* premultiply */
+ red = alpha_bias((frac) ((long)red * alpha / frac_1));
+ green = alpha_bias((frac) ((long)green * alpha / frac_1));
+ blue = alpha_bias((frac) ((long)blue * alpha / frac_1));
+ } {
+ frac mred =
+ gx_map_color_frac(pis, red, effective_transfer.colored.red);
+ frac mgreen =
+ gx_map_color_frac(pis, green, effective_transfer.colored.green);
+ frac mblue =
+ gx_map_color_frac(pis, blue, effective_transfer.colored.blue);
+ gx_color_value cv_alpha = frac2cv(alpha);
+
+ if ((mred == mgreen && mred == mblue ? /* gray shade */
+ gx_render_gray_alpha(mred, cv_alpha, pdc, pis, dev, select) :
+ gx_render_rgb_alpha(mred, mgreen, mblue, cv_alpha, pdc, pis, dev, select)) == 1)
+ gx_color_load_select(pdc, pis, dev, select);
+ }
+}
+
+private void
+cmap_rgb_alpha_direct(frac r, frac g, frac b, frac alpha, gx_device_color * pdc,
+ const gs_imager_state * pis, gx_device * dev, gs_color_select_t select)
+{
+ frac red = r, green = g, blue = b;
+
+ if (alpha != frac_1) { /* premultiply */
+ red = alpha_bias((frac) ((long)red * alpha / frac_1));
+ green = alpha_bias((frac) ((long)green * alpha / frac_1));
+ blue = alpha_bias((frac) ((long)blue * alpha / frac_1));
+ } {
+ frac mred =
+ gx_map_color_frac(pis, red, effective_transfer.colored.red);
+ frac mgreen =
+ gx_map_color_frac(pis, green, effective_transfer.colored.green);
+ frac mblue =
+ gx_map_color_frac(pis, blue, effective_transfer.colored.blue);
+ gx_color_value cv_alpha = frac2cv(alpha);
+ gx_color_index color =
+ (cv_alpha == gx_max_color_value ?
+ gx_map_rgb_color(dev, frac2cv(mred), frac2cv(mgreen),
+ frac2cv(mblue)) :
+ gx_map_rgb_alpha_color(dev, frac2cv(mred), frac2cv(mgreen),
+ frac2cv(mblue), cv_alpha));
+
+ if (color != gx_no_color_index) {
+ color_set_pure(pdc, color);
+ return;
+ }
+ if ((mred == mgreen && mred == mblue ? /* gray shade */
+ gx_render_gray_alpha(mred, cv_alpha, pdc, pis, dev, select) :
+ gx_render_rgb_alpha(mred, mgreen, mblue, cv_alpha, pdc, pis, dev, select)) == 1)
+ gx_color_load_select(pdc, pis, dev, select);
+ }
+}
+
+/* Currently CMYK devices can't handle alpha. */
+/* Just multiply the values towards white. */
+private void
+cmap_rgb_alpha_to_cmyk(frac r, frac g, frac b, frac alpha,
+ gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
+ gs_color_select_t select)
+{
+#ifdef PREMULTIPLY_TOWARDS_WHITE
+# undef alpha_bias_value
+ frac alpha_bias_value = frac_1 - alpha;
+
+#endif
+
+ cmap_rgb_to_cmyk(alpha_bias((frac) ((long)r * alpha / frac_1)),
+ alpha_bias((frac) ((long)g * alpha / frac_1)),
+ alpha_bias((frac) ((long)b * alpha / frac_1)),
+ pdc, pis, dev, select);
+}
+
+#undef alpha_bias
+#undef alpha_bias_value
+
+/* ------ Transfer function mapping ------ */
+
+/* Define the generic transfer function for the library layer. */
+/* This just returns what's already in the map. */
+float
+gs_mapped_transfer(floatp value, const gx_transfer_map * pmap)
+{
+ return gx_map_color_float(pmap, value);
+}
+
+#if FRAC_MAP_INTERPOLATE /* NOTA BENE */
+
+/* Map a color fraction through a transfer map. */
+/* We only use this if we are interpolating. */
+frac
+gx_color_frac_map(frac cv, const frac * values)
+{
+#define cp_frac_bits (frac_bits - log2_transfer_map_size)
+ int cmi = frac2bits_floor(cv, log2_transfer_map_size);
+ frac mv = values[cmi];
+ int rem, mdv;
+
+ /* Interpolate between two adjacent values if needed. */
+ rem = cv - bits2frac(cmi, log2_transfer_map_size);
+ if (rem == 0)
+ return mv;
+ mdv = values[cmi + 1] - mv;
+#if arch_ints_are_short
+ /* Only use long multiplication if necessary. */
+ if (mdv < -1 << (16 - cp_frac_bits) ||
+ mdv > 1 << (16 - cp_frac_bits)
+ )
+ return mv + (uint) (((ulong) rem * mdv) >> cp_frac_bits);
+#endif
+ return mv + ((rem * mdv) >> cp_frac_bits);
+#undef cp_frac_bits
+}
+
+#endif /* FRAC_MAP_INTERPOLATE */
+
+/* ------ Default device color mapping ------ */
+
+/* RGB mapping for black-and-white devices */
+
+/* White-on-black */
+gx_color_index
+gx_default_w_b_map_rgb_color(gx_device * dev,
+ gx_color_value r, gx_color_value g, gx_color_value b)
+{ /* Map values >= 1/2 to 1, < 1/2 to 0. */
+ return ((r | g | b) > gx_max_color_value / 2 ?
+ (gx_color_index) 1 : (gx_color_index) 0);
+}
+int
+gx_default_w_b_map_color_rgb(gx_device * dev, gx_color_index color,
+ gx_color_value prgb[3])
+{ /* Map 1 to max_value, 0 to 0. */
+ prgb[0] = prgb[1] = prgb[2] = -(gx_color_value) color;
+ return 0;
+}
+/* Black-on-white */
+gx_color_index
+gx_default_b_w_map_rgb_color(gx_device * dev,
+ gx_color_value r, gx_color_value g, gx_color_value b)
+{ /* Map values >= 1/2 to 0, < 1/2 to 1. */
+ return ((r | g | b) > gx_max_color_value / 2 ?
+ (gx_color_index) 0 : (gx_color_index) 1);
+}
+int
+gx_default_b_w_map_color_rgb(gx_device * dev, gx_color_index color,
+ gx_color_value prgb[3])
+{ /* Map 0 to max_value, 1 to 0. */
+ prgb[0] = prgb[1] = prgb[2] = -((gx_color_value) color ^ 1);
+ return 0;
+}
+
+/* RGB mapping for gray-scale devices */
+
+gx_color_index
+gx_default_gray_map_rgb_color(gx_device * dev,
+ gx_color_value r, gx_color_value g, gx_color_value b)
+{ /* We round the value rather than truncating it. */
+ gx_color_value gray =
+ (((r * (ulong) lum_red_weight) +
+ (g * (ulong) lum_green_weight) +
+ (b * (ulong) lum_blue_weight) +
+ (lum_all_weights / 2)) / lum_all_weights
+ * dev->color_info.max_gray +
+ (gx_max_color_value / 2)) / gx_max_color_value;
+
+ return gray;
+}
+
+int
+gx_default_gray_map_color_rgb(gx_device * dev, gx_color_index color,
+ gx_color_value prgb[3])
+{
+ gx_color_value gray =
+ color * gx_max_color_value / dev->color_info.max_gray;
+
+ prgb[0] = gray;
+ prgb[1] = gray;
+ prgb[2] = gray;
+ return 0;
+}
+
+/* RGB mapping for 24-bit true (RGB) color devices */
+
+gx_color_index
+gx_default_rgb_map_rgb_color(gx_device * dev,
+ gx_color_value r, gx_color_value g, gx_color_value b)
+{
+ if (dev->color_info.depth == 24)
+ return gx_color_value_to_byte(b) +
+ ((uint) gx_color_value_to_byte(g) << 8) +
+ ((ulong) gx_color_value_to_byte(r) << 16);
+ else {
+ uint bits_per_color = dev->color_info.depth / 3;
+ ulong max_value = (1 << bits_per_color) - 1;
+
+ return ((r * max_value / gx_max_color_value) << (bits_per_color * 2)) +
+ ((g * max_value / gx_max_color_value) << (bits_per_color)) +
+ (b * max_value / gx_max_color_value);
+ }
+}
+
+/* Map a color index to a r-g-b color. */
+int
+gx_default_rgb_map_color_rgb(gx_device * dev, gx_color_index color,
+ gx_color_value prgb[3])
+{
+ if (dev->color_info.depth == 24) {
+ prgb[0] = gx_color_value_from_byte(color >> 16);
+ prgb[1] = gx_color_value_from_byte((color >> 8) & 0xff);
+ prgb[2] = gx_color_value_from_byte(color & 0xff);
+ } else {
+ uint bits_per_color = dev->color_info.depth / 3;
+ uint color_mask = (1 << bits_per_color) - 1;
+
+ prgb[0] = ((color >> (bits_per_color * 2)) & color_mask) *
+ (ulong) gx_max_color_value / color_mask;
+ prgb[1] = ((color >> (bits_per_color)) & color_mask) *
+ (ulong) gx_max_color_value / color_mask;
+ prgb[2] = (color & color_mask) *
+ (ulong) gx_max_color_value / color_mask;
+ }
+ return 0;
+}
+
+/* CMYK mapping for RGB devices (should never be called!) */
+
+gx_color_index
+gx_default_map_cmyk_color(gx_device * dev,
+ gx_color_value c, gx_color_value m, gx_color_value y, gx_color_value k)
+{ /* Convert to RGB */
+ frac rgb[3];
+
+ color_cmyk_to_rgb(cv2frac(c), cv2frac(m), cv2frac(y), cv2frac(k),
+ NULL, rgb);
+ return gx_map_rgb_color(dev, frac2cv(rgb[0]),
+ frac2cv(rgb[1]), frac2cv(rgb[2]));
+}
+
+/* CMYK mapping for CMYK devices */
+
+gx_color_index
+gx_default_cmyk_map_cmyk_color(gx_device * dev,
+ gx_color_value c, gx_color_value m, gx_color_value y, gx_color_value k)
+{
+ gx_color_index color =
+ (gx_color_value_to_byte(k) +
+ ((uint) gx_color_value_to_byte(y) << 8)) +
+ ((ulong) (gx_color_value_to_byte(m) +
+ ((uint) gx_color_value_to_byte(c) << 8)) << 16);
+
+ return (color == gx_no_color_index ? color ^ 1 : color);
+}
+
+/* Default mapping between RGB+alpha and RGB. */
+
+gx_color_index
+gx_default_map_rgb_alpha_color(gx_device * dev,
+ gx_color_value r, gx_color_value g, gx_color_value b, gx_color_value alpha)
+{ /* Colors have been premultiplied: we don't need to do it here. */
+ return gx_map_rgb_color(dev, r, g, b);
+}
+
+int
+gx_default_map_color_rgb_alpha(gx_device * dev, gx_color_index color,
+ gx_color_value prgba[4])
+{
+ prgba[3] = gx_max_color_value; /* alpha = 1 */
+ return (*dev_proc(dev, map_color_rgb)) (dev, color, prgba);
+}
diff --git a/pstoraster/gxcmap.h b/pstoraster/gxcmap.h
new file mode 100644
index 000000000..89b3e09d5
--- /dev/null
+++ b/pstoraster/gxcmap.h
@@ -0,0 +1,101 @@
+/* Copyright (C) 1989, 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$ */
+/* Requires gxdcolor.h, gxdevice.h. */
+
+#ifndef gxcmap_INCLUDED
+# define gxcmap_INCLUDED
+
+#include "gscsel.h"
+#include "gxfmap.h"
+
+/* Procedures for rendering colors specified by fractions. */
+
+#define cmap_proc_gray(proc)\
+ void proc(P5(frac, gx_device_color *, const gs_imager_state *,\
+ gx_device *, gs_color_select_t))
+#define cmap_proc_rgb(proc)\
+ void proc(P7(frac, frac, frac, gx_device_color *, const gs_imager_state *,\
+ gx_device *, gs_color_select_t))
+#define cmap_proc_cmyk(proc)\
+ void proc(P8(frac, frac, frac, frac, gx_device_color *,\
+ const gs_imager_state *, gx_device *, gs_color_select_t))
+#define cmap_proc_rgb_alpha(proc)\
+ void proc(P8(frac, frac, frac, frac, gx_device_color *,\
+ const gs_imager_state *, gx_device *, gs_color_select_t))
+
+/* Because of a bug in the Watcom C compiler, */
+/* we have to split the struct from the typedef. */
+struct gx_color_map_procs_s {
+ cmap_proc_gray((*map_gray));
+ cmap_proc_rgb((*map_rgb));
+ cmap_proc_cmyk((*map_cmyk));
+ cmap_proc_rgb_alpha((*map_rgb_alpha));
+};
+typedef struct gx_color_map_procs_s gx_color_map_procs;
+
+/* Determine the color mapping procedures for a device. */
+const gx_color_map_procs *gx_device_cmap_procs(P1(const gx_device *));
+
+/* Set the color mapping procedures in the graphics state. */
+/* This is only needed when switching devices. */
+void gx_set_cmap_procs(P2(gs_imager_state *, const gx_device *));
+
+/* Remap a concrete (frac) RGB or CMYK color. */
+/* These cannot fail, and do not return a value. */
+#define gx_remap_concrete_rgb(cr, cg, cb, pdc, pgs, dev, select)\
+ (*pgs->cmap_procs->map_rgb)(cr, cg, cb, pdc, pgs, dev, select)
+#define gx_remap_concrete_cmyk(cc, cm, cy, ck, pdc, pgs, dev, select)\
+ (*pgs->cmap_procs->map_cmyk)(cc, cm, cy, ck, pdc, pgs, dev, select)
+#define gx_remap_concrete_rgb_alpha(cr, cg, cb, ca, pdc, pgs, dev, select)\
+ (*pgs->cmap_procs->map_rgb_alpha)(cr, cg, cb, ca, pdc, pgs, dev, select)
+
+/* Map a color, with optional tracing if we are debugging. */
+#ifdef DEBUG
+/* Use procedures in gxcmap.c */
+#include "gxcvalue.h"
+gx_color_index gx_proc_map_rgb_color(P4(gx_device *,
+ gx_color_value, gx_color_value, gx_color_value));
+gx_color_index gx_proc_map_rgb_alpha_color(P5(gx_device *,
+ gx_color_value, gx_color_value, gx_color_value, gx_color_value));
+gx_color_index gx_proc_map_cmyk_color(P5(gx_device *,
+ gx_color_value, gx_color_value, gx_color_value, gx_color_value));
+
+# define gx_map_rgb_color(dev, vr, vg, vb)\
+ gx_proc_map_rgb_color(dev, vr, vg, vb)
+# define gx_map_rgb_alpha_color(dev, vr, vg, vb, va)\
+ gx_proc_map_rgb_alpha_color(dev, vr, vg, vb, va)
+# define gx_map_cmyk_color(dev, vc, vm, vy, vk)\
+ gx_proc_map_cmyk_color(dev, vc, vm, vy, vk)
+#else
+# define gx_map_rgb_color(dev, vr, vg, vb)\
+ (*dev_proc(dev, map_rgb_color))(dev, vr, vg, vb)
+# define gx_map_rgb_alpha_color(dev, vr, vg, vb, va)\
+ (*dev_proc(dev, map_rgb_alpha_color))(dev, vr, vg, vb, va)
+# define gx_map_cmyk_color(dev, vc, vm, vy, vk)\
+ (*dev_proc(dev, map_cmyk_color))(dev, vc, vm, vy, vk)
+#endif
+
+#endif /* gxcmap_INCLUDED */
diff --git a/pstoraster/gxcolor2.h b/pstoraster/gxcolor2.h
new file mode 100644
index 000000000..45a8ea2df
--- /dev/null
+++ b/pstoraster/gxcolor2.h
@@ -0,0 +1,98 @@
+/* Copyright (C) 1993, 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$ */
+/* Internal definitions for Level 2 color routines */
+/* Requires gsstruct.h, gxfixed.h */
+
+#ifndef gxcolor2_INCLUDED
+# define gxcolor2_INCLUDED
+
+#include "gscolor2.h"
+#include "gsrefct.h"
+#include "gxbitmap.h"
+
+/* Cache for Indexed color with procedure, or Separation color. */
+struct gs_indexed_map_s {
+ rc_header rc;
+ union {
+ int (*lookup_index) (P3(const gs_indexed_params *, int, float *));
+ int (*tint_transform) (P3(const gs_separation_params *, floatp, float *));
+ } proc;
+ uint num_values; /* base_space->type->num_components * (hival + 1) */
+ float *values; /* actually [num_values] */
+};
+
+extern_st(st_indexed_map);
+#define public_st_indexed_map() /* in gscolor2.c */\
+ gs_public_st_ptrs1(st_indexed_map, gs_indexed_map, "gs_indexed_map",\
+ indexed_map_enum_ptrs, indexed_map_reloc_ptrs, values)
+
+/* Allocate an indexed map and its values. */
+int alloc_indexed_map(P4(gs_indexed_map ** ppmap, int num_values,
+ gs_memory_t * mem, client_name_t cname));
+
+/* Free an indexed map and its values when the reference count goes to 0. */
+rc_free_proc(free_indexed_map);
+
+/*
+ * We define 'tiling space' as the space in which (0,0) is the origin of
+ * the key pattern cell and in which coordinate (i,j) is displaced by
+ * i * XStep + j * YStep from the origin. In this space, it is easy to
+ * compute a (rectangular) set of tile copies that cover a (rectangular)
+ * region to be tiled. Note that since all we care about is that the
+ * stepping matrix (the transformation from tiling space to device space)
+ * yield the right set of coordinates for integral X and Y values, we can
+ * adjust it to make the tiling computation easier; in particular, we can
+ * arrange it so that all 4 transformation factors are non-negative.
+ */
+
+/* Implementation of Pattern instances. */
+struct gs_pattern_instance_s {
+ rc_header rc;
+ gs_client_pattern template;
+ /* Following are created by makepattern */
+ gs_state *saved;
+ gs_matrix step_matrix; /* tiling space -> device space */
+ gs_rect bbox; /* bbox of tile in tiling space */
+ bool is_simple; /* true if xstep/ystep = tile size */
+ /*
+ * uses_mask is always true for PostScript patterns, but is false
+ * for bitmap patterns that don't have explicit transparent pixels.
+ */
+ bool uses_mask; /* if true, pattern mask must be created */
+ gs_int_point size; /* in device coordinates */
+ gx_bitmap_id id; /* key for cached bitmap */
+ /* (= id of mask) */
+};
+
+/* The following is only public for a type test in the interpreter */
+/* (.buildpattern operator). */
+extern_st(st_pattern_instance);
+#define public_st_pattern_instance() /* in gspcolor.c */\
+ gs_public_st_ptrs_add1(st_pattern_instance, gs_pattern_instance,\
+ "pattern instance", pattern_instance_enum_ptrs,\
+ pattern_instance_reloc_ptrs, st_pattern1_template, template, saved)
+
+#endif /* gxcolor2_INCLUDED */
diff --git a/pstoraster/gxcomp.h b/pstoraster/gxcomp.h
new file mode 100644
index 000000000..d2927b280
--- /dev/null
+++ b/pstoraster/gxcomp.h
@@ -0,0 +1,113 @@
+/* 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$ */
+/* Definitions for implementing compositing functions */
+
+#ifndef gxcomp_INCLUDED
+# define gxcomp_INCLUDED
+
+#include "gscompt.h"
+#include "gsrefct.h"
+#include "gxbitfmt.h"
+
+/*
+ * Define the abstract superclass for all compositing function types.
+ */
+ /*typedef struct gs_composite_s gs_composite_t; *//* in gscompt.h */
+
+#ifndef gs_imager_state_DEFINED
+# define gs_imager_state_DEFINED
+typedef struct gs_imager_state_s gs_imager_state;
+
+#endif
+
+#ifndef gx_device_DEFINED
+# define gx_device_DEFINED
+typedef struct gx_device_s gx_device;
+
+#endif
+
+typedef struct gs_composite_type_procs_s {
+
+ /*
+ * Create the default compositor for a compositing function.
+ */
+#define composite_create_default_compositor_proc(proc)\
+ int proc(P5(const gs_composite_t *pcte, gx_device **pcdev,\
+ gx_device *dev, const gs_imager_state *pis, gs_memory_t *mem))
+ composite_create_default_compositor_proc((*create_default_compositor));
+
+ /*
+ * Test whether this function is equal to another one.
+ */
+#define composite_equal_proc(proc)\
+ bool proc(P2(const gs_composite_t *pcte, const gs_composite_t *pcte2))
+ composite_equal_proc((*equal));
+
+ /*
+ * Convert the representation of this function to a string
+ * for writing in a command list. *psize is the amount of space
+ * available. If it is large enough, the procedure sets *psize
+ * to the amount used and returns 0; if it is not large enough,
+ * the procedure sets *psize to the amount needed and returns a
+ * rangecheck error; in the case of any other error, *psize is
+ * not changed.
+ */
+#define composite_write_proc(proc)\
+ int proc(P3(const gs_composite_t *pcte, byte *data, uint *psize))
+ composite_write_proc((*write));
+
+ /*
+ * Convert the string representation of a function back to
+ * a structure, allocating the structure.
+ */
+#define composite_read_proc(proc)\
+ int proc(P4(gs_composite_t **ppcte, const byte *data, uint size,\
+ gs_memory_t *mem))
+ composite_read_proc((*read));
+
+} gs_composite_type_procs_t;
+typedef struct gs_composite_type_s {
+ gs_composite_type_procs_t procs;
+} gs_composite_type_t;
+
+/*
+ * Compositing objects are reference-counted, because graphics states will
+ * eventually reference them. Note that the common part has no
+ * garbage-collectible pointers and is never actually instantiated, so no
+ * structure type is needed for it.
+ */
+#define gs_composite_common\
+ const gs_composite_type_t *type;\
+ gs_id id; /* see gscompt.h */\
+ rc_header rc
+struct gs_composite_s {
+ gs_composite_common;
+};
+
+/* Replace a procedure with a macro. */
+#define gs_composite_id(pcte) ((pcte)->id)
+
+#endif /* gxcomp_INCLUDED */
diff --git a/pstoraster/gxcoord.h b/pstoraster/gxcoord.h
new file mode 100644
index 000000000..b341bde89
--- /dev/null
+++ b/pstoraster/gxcoord.h
@@ -0,0 +1,44 @@
+/* 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 gxmatrix.h and gzstate.h */
+
+#ifndef gxcoord_INCLUDED
+# define gxcoord_INCLUDED
+
+#include "gscoord.h"
+
+/* Set the translation to a fixed value, and translate any existing path. */
+/* Used by gschar.c to prepare for a BuildChar or BuildGlyph procedure. */
+int gx_translate_to_fixed(P3(gs_state *, fixed, fixed));
+
+/* Scale the CTM and character matrix for oversampling. */
+int gx_scale_char_matrix(P3(gs_state *, int, int));
+
+/* Compute the coefficients for fast fixed-point distance transformations */
+/* from a transformation matrix. */
+int gx_matrix_to_fixed_coeff(P3(const gs_matrix *, fixed_coeff *, int));
+
+#endif /* gxcoord_INCLUDED */
diff --git a/pstoraster/gxcpath.c b/pstoraster/gxcpath.c
new file mode 100644
index 000000000..e4e980bf8
--- /dev/null
+++ b/pstoraster/gxcpath.c
@@ -0,0 +1,962 @@
+/* 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$ */
+/* Implementation of clipping paths, other than actual clipping */
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gsutil.h"
+#include "gsline.h"
+#include "gxdevice.h"
+#include "gxfixed.h"
+#include "gscoord.h" /* needs gsmatrix.h */
+#include "gxstate.h"
+#include "gzpath.h"
+#include "gzcpath.h"
+
+/* Imported from gxacpath.c */
+extern int gx_cpath_intersect_slow(P4(gs_state *, gx_clip_path *,
+ gx_path *, int));
+
+/* Forward references */
+private void gx_clip_list_from_rectangle(P2(gx_clip_list *, gs_fixed_rect *));
+
+/* Other structure types */
+public_st_clip_rect();
+private_st_clip_list();
+public_st_clip_path();
+private_st_clip_rect_list();
+public_st_device_clip();
+private_st_cpath_enum();
+
+/* GC procedures for gx_clip_path */
+#define cptr ((gx_clip_path *)vptr)
+private
+ENUM_PTRS_BEGIN(clip_path_enum_ptrs) return ENUM_USING(st_path, &cptr->path, sizeof(cptr->path), index - 1);
+
+case 0:
+ENUM_RETURN((cptr->rect_list == &cptr->local_list ? 0 :
+ cptr->rect_list));
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(clip_path_reloc_ptrs)
+{
+ if (cptr->rect_list != &cptr->local_list)
+ RELOC_VAR(cptr->rect_list);
+ RELOC_USING(st_path, &cptr->path, sizeof(gx_path));
+}
+RELOC_PTRS_END
+#undef cptr
+
+/* GC procedures for gx_device_clip */
+#define cptr ((gx_device_clip *)vptr)
+private ENUM_PTRS_BEGIN(device_clip_enum_ptrs)
+{
+ if (index < st_clip_list_max_ptrs + 1)
+ return ENUM_USING(st_clip_list, &cptr->list,
+ sizeof(gx_clip_list), index - 1);
+ return ENUM_USING(st_device_forward, vptr,
+ sizeof(gx_device_forward),
+ index - (st_clip_list_max_ptrs + 1));
+}
+case 0:
+ENUM_RETURN((cptr->current == &cptr->list.single ? NULL :
+ (void *)cptr->current));
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(device_clip_reloc_ptrs)
+{
+ if (cptr->current == &cptr->list.single)
+ cptr->current = &((gx_device_clip *)RELOC_OBJ(vptr))->list.single;
+ else
+ RELOC_PTR(gx_device_clip, current);
+ RELOC_USING(st_clip_list, &cptr->list, sizeof(gx_clip_list));
+ RELOC_USING(st_device_forward, vptr, sizeof(gx_device_forward));
+}
+RELOC_PTRS_END
+#undef cptr
+
+/* Define an empty clip list. */
+private const gx_clip_list clip_list_empty =
+{
+ {0, 0, min_int, max_int, 0, 0},
+ 0, 0, 0, 0 /*false */
+};
+
+/* Debugging */
+
+#ifdef DEBUG
+/* Validate a clipping path. */
+bool /* only exported for gxacpath.c */
+clip_list_validate(const gx_clip_list * clp)
+{
+ if (clp->count <= 1)
+ return (clp->head == 0 && clp->tail == 0 &&
+ clp->single.next == 0 && clp->single.prev == 0);
+ else {
+ const gx_clip_rect *prev = clp->head;
+ const gx_clip_rect *ptr;
+ bool ok = true;
+
+ while ((ptr = prev->next) != 0) {
+ if (ptr->ymin > ptr->ymax || ptr->xmin > ptr->xmax ||
+ !(ptr->ymin >= prev->ymax ||
+ (ptr->ymin == prev->ymin &&
+ ptr->ymax == prev->ymax &&
+ ptr->xmin >= prev->xmax)) ||
+ ptr->prev != prev
+ ) {
+ clip_rect_print('q', "WRONG:", ptr);
+ ok = false;
+ }
+ prev = ptr;
+ }
+ return ok && prev == clp->tail;
+ }
+}
+#endif
+
+/* ------ Clipping path memory management ------ */
+
+private rc_free_proc(rc_free_cpath_list);
+private rc_free_proc(rc_free_cpath_list_local);
+
+/* Initialize those parts of the contents of a clip path that aren't */
+/* part of the path. */
+private void
+cpath_init_rectangle(gx_clip_path * pcpath, gs_fixed_rect * pbox)
+{
+ gx_clip_list_from_rectangle(&pcpath->rect_list->list, pbox);
+ pcpath->inner_box = *pbox;
+ pcpath->path_valid = false;
+ pcpath->path.bbox = *pbox;
+ gx_cpath_set_outer_box(pcpath);
+ pcpath->id = gs_next_ids(1); /* path changed => change id */
+}
+private void
+cpath_init_own_contents(gx_clip_path * pcpath)
+{ /* We could make null_rect static, but then it couldn't be const. */
+ gs_fixed_rect null_rect;
+
+ null_rect.p.x = null_rect.p.y = null_rect.q.x = null_rect.q.y = 0;
+ cpath_init_rectangle(pcpath, &null_rect);
+}
+private void
+cpath_share_own_contents(gx_clip_path * pcpath, const gx_clip_path * shared)
+{
+ pcpath->inner_box = shared->inner_box;
+ pcpath->path_valid = shared->path_valid;
+ pcpath->outer_box = shared->outer_box;
+ pcpath->id = shared->id;
+}
+
+/* Allocate only the segments of a clipping path on the heap. */
+private int
+cpath_alloc_list(gx_clip_rect_list ** prlist, gs_memory_t * mem,
+ client_name_t cname)
+{
+ rc_alloc_struct_1(*prlist, gx_clip_rect_list, &st_clip_rect_list, mem,
+ return_error(gs_error_VMerror), cname);
+ (*prlist)->rc.free = rc_free_cpath_list;
+ return 0;
+}
+int
+gx_cpath_init_contained_shared(gx_clip_path * pcpath,
+ const gx_clip_path * shared, gs_memory_t * mem, client_name_t cname)
+{
+ if (shared) {
+ if (shared->path.segments == &shared->path.local_segments) {
+ lprintf1("Attempt to share (local) segments of clip path 0x%lx!\n",
+ (ulong) shared);
+ return_error(gs_error_Fatal);
+ }
+ *pcpath = *shared;
+ pcpath->path.memory = mem;
+ pcpath->path.allocation = path_allocated_contained;
+ rc_increment(pcpath->path.segments);
+ rc_increment(pcpath->rect_list);
+ } else {
+ int code = cpath_alloc_list(&pcpath->rect_list, mem, cname);
+
+ if (code < 0)
+ return code;
+ code = gx_path_alloc_contained(&pcpath->path, mem, cname);
+ if (code < 0) {
+ gs_free_object(mem, pcpath->rect_list, cname);
+ pcpath->rect_list = 0;
+ return code;
+ }
+ cpath_init_own_contents(pcpath);
+ }
+ return 0;
+}
+#define gx_cpath_alloc_contents(pcpath, shared, mem, cname)\
+ gx_cpath_init_contained_shared(pcpath, shared, mem, cname)
+
+/* Allocate all of a clipping path on the heap. */
+gx_clip_path *
+gx_cpath_alloc_shared(const gx_clip_path * shared, gs_memory_t * mem,
+ client_name_t cname)
+{
+ gx_clip_path *pcpath =
+ gs_alloc_struct(mem, gx_clip_path, &st_clip_path, cname);
+ int code;
+
+ if (pcpath == 0)
+ return 0;
+ code = gx_cpath_alloc_contents(pcpath, shared, mem, cname);
+ if (code < 0) {
+ gs_free_object(mem, pcpath, cname);
+ return 0;
+ }
+ pcpath->path.allocation = path_allocated_on_heap;
+ return pcpath;
+}
+
+/* Initialize a stack-allocated clipping path. */
+int
+gx_cpath_init_local_shared(gx_clip_path * pcpath, const gx_clip_path * shared,
+ gs_memory_t * mem)
+{
+ if (shared) {
+ if (shared->path.segments == &shared->path.local_segments) {
+ lprintf1("Attempt to share (local) segments of clip path 0x%lx!\n",
+ (ulong) shared);
+ return_error(gs_error_Fatal);
+ }
+ pcpath->path = shared->path;
+ pcpath->path.allocation = path_allocated_on_stack;
+ rc_increment(pcpath->path.segments);
+ pcpath->rect_list = shared->rect_list;
+ rc_increment(pcpath->rect_list);
+ cpath_share_own_contents(pcpath, shared);
+ } else {
+ gx_path_init_local(&pcpath->path, mem);
+ rc_init_free(&pcpath->local_list, mem, 1, rc_free_cpath_list_local);
+ pcpath->rect_list = &pcpath->local_list;
+ cpath_init_own_contents(pcpath);
+ }
+ return 0;
+}
+
+/* Unshare a clipping path. */
+int
+gx_cpath_unshare(gx_clip_path * pcpath)
+{
+ int code = gx_path_unshare(&pcpath->path);
+ gx_clip_rect_list *rlist = pcpath->rect_list;
+
+ if (code < 0)
+ return code;
+ if (rlist->rc.ref_count > 1) {
+ int code = cpath_alloc_list(&pcpath->rect_list, pcpath->path.memory,
+ "gx_cpath_unshare");
+
+ if (code < 0)
+ return code;
+ /* Copy the rectangle list. */
+/**************** NYI ****************/
+ rc_decrement(rlist, "gx_cpath_unshare");
+ }
+ return code;
+}
+
+/* Free a clipping path. */
+void
+gx_cpath_free(gx_clip_path * pcpath, client_name_t cname)
+{
+ rc_decrement(pcpath->rect_list, cname);
+ /* Clean up pointers for GC. */
+ pcpath->rect_list = 0;
+ {
+ gx_path_allocation_t alloc = pcpath->path.allocation;
+
+ if (alloc == path_allocated_on_heap) {
+ pcpath->path.allocation = path_allocated_contained;
+ gx_path_free(&pcpath->path, cname);
+ gs_free_object(pcpath->path.memory, pcpath, cname);
+ } else
+ gx_path_free(&pcpath->path, cname);
+ }
+}
+
+/* Assign a clipping path, preserving the source. */
+int
+gx_cpath_assign_preserve(gx_clip_path * pcpto, gx_clip_path * pcpfrom)
+{
+ int code = gx_path_assign_preserve(&pcpto->path, &pcpfrom->path);
+ gx_clip_rect_list *fromlist = pcpfrom->rect_list;
+ gx_clip_rect_list *tolist = pcpto->rect_list;
+ gx_path path;
+
+ if (code < 0)
+ return 0;
+ if (fromlist == &pcpfrom->local_list) {
+ /* We can't use pcpfrom's list object. */
+ if (tolist == &pcpto->local_list || tolist->rc.ref_count > 1) {
+ /* We can't use pcpto's list either. Allocate a new one. */
+ int code = cpath_alloc_list(&tolist, tolist->rc.memory,
+ "gx_cpath_assign");
+
+ if (code < 0)
+ return code;
+ rc_decrement(pcpto->rect_list, "gx_cpath_assign");
+ } else {
+ /* Use pcpto's list object. */
+ rc_free_cpath_list_local(tolist->rc.memory, tolist,
+ "gx_cpath_assign");
+ }
+ tolist->list = fromlist->list;
+ pcpfrom->rect_list = tolist;
+ rc_increment(tolist);
+ } else {
+ /* We can use pcpfrom's list object. */
+ rc_increment(fromlist);
+ rc_decrement(pcpto->rect_list, "gx_cpath_assign");
+ }
+ path = pcpto->path, *pcpto = *pcpfrom, pcpto->path = path;
+ return 0;
+}
+
+/* Assign a clipping path, releasing the source. */
+int
+gx_cpath_assign_free(gx_clip_path * pcpto, gx_clip_path * pcpfrom)
+{ /* For right now, just do assign + free. */
+ int code = gx_cpath_assign_preserve(pcpto, pcpfrom);
+
+ if (code < 0)
+ return 0;
+ gx_cpath_free(pcpfrom, "gx_cpath_assign_free");
+ return 0;
+}
+
+/* Free the clipping list when its reference count goes to zero. */
+private void
+rc_free_cpath_list_local(gs_memory_t * mem, void *vrlist,
+ client_name_t cname)
+{
+ gx_clip_rect_list *rlist = (gx_clip_rect_list *) vrlist;
+
+ gx_clip_list_free(&rlist->list, mem);
+}
+private void
+rc_free_cpath_list(gs_memory_t * mem, void *vrlist, client_name_t cname)
+{
+ rc_free_cpath_list_local(mem, vrlist, cname);
+ gs_free_object(mem, vrlist, cname);
+}
+
+/* ------ Clipping path accessing ------ */
+
+/* Return the path of a clipping path. */
+int
+gx_cpath_to_path(gx_clip_path * pcpath, gx_path * ppath)
+{
+ if (!pcpath->path_valid) {
+ /* Synthesize a path. */
+ gs_cpath_enum cenum;
+ gs_fixed_point pts[3];
+ gx_path rpath;
+ int code;
+
+ gx_path_init_local(&rpath, pcpath->path.memory);
+ gx_cpath_enum_init(&cenum, pcpath);
+ while ((code = gx_cpath_enum_next(&cenum, pts)) != 0) {
+ switch (code) {
+ case gs_pe_moveto:
+ code = gx_path_add_point(&rpath, pts[0].x, pts[0].y);
+ break;
+ case gs_pe_lineto:
+ code = gx_path_add_line_notes(&rpath, pts[0].x, pts[0].y,
+ gx_cpath_enum_notes(&cenum));
+ break;
+ case gs_pe_curveto:
+ code = gx_path_add_curve_notes(&rpath, pts[0].x, pts[0].y,
+ pts[1].x, pts[1].y,
+ pts[2].x, pts[2].y,
+ gx_cpath_enum_notes(&cenum));
+ break;
+ case gs_pe_closepath:
+ code = gx_path_close_subpath_notes(&rpath,
+ gx_cpath_enum_notes(&cenum));
+ break;
+ default:
+ if (code >= 0)
+ code = gs_note_error(gs_error_unregistered);
+ }
+ if (code < 0)
+ break;
+ }
+ if (code >= 0)
+ code = gx_path_assign_free(&pcpath->path, &rpath);
+ if (code < 0) {
+ gx_path_free(&rpath, "gx_cpath_to_path error");
+ return code;
+ }
+ pcpath->path_valid = true;
+ }
+ return gx_path_assign_preserve(ppath, &pcpath->path);
+}
+
+/* Return the inner and outer check rectangles for a clipping path. */
+/* Return true iff the path is a rectangle. */
+/* Note that these must return something strange if we are using */
+/* outside clipping. */
+bool
+gx_cpath_inner_box(const gx_clip_path * pcpath, gs_fixed_rect * pbox)
+{
+ if (gx_cpath_is_outside(pcpath)) {
+ pbox->p.x = pbox->p.y = pbox->q.x = pbox->q.y = 0;
+ return false;
+ } else {
+ *pbox = pcpath->inner_box;
+ return clip_list_is_rectangle(gx_cpath_list(pcpath));
+ }
+}
+bool
+gx_cpath_outer_box(const gx_clip_path * pcpath, gs_fixed_rect * pbox)
+{
+ if (gx_cpath_is_outside(pcpath)) {
+ pbox->p.x = pbox->p.y = min_fixed;
+ pbox->q.x = pbox->q.y = max_fixed;
+ return false;
+ } else {
+ *pbox = pcpath->outer_box;
+ return clip_list_is_rectangle(gx_cpath_list(pcpath));
+ }
+}
+
+/* Test if a clipping path includes a rectangle. */
+/* The rectangle need not be oriented correctly, i.e. x0 > x1 is OK. */
+bool
+gx_cpath_includes_rectangle(register const gx_clip_path * pcpath,
+ fixed x0, fixed y0, fixed x1, fixed y1)
+{
+ return
+ (x0 <= x1 ?
+ (pcpath->inner_box.p.x <= x0 && x1 <= pcpath->inner_box.q.x) :
+ (pcpath->inner_box.p.x <= x1 && x0 <= pcpath->inner_box.q.x)) &&
+ (y0 <= y1 ?
+ (pcpath->inner_box.p.y <= y0 && y1 <= pcpath->inner_box.q.y) :
+ (pcpath->inner_box.p.y <= y1 && y0 <= pcpath->inner_box.q.y));
+}
+
+/* Set the current outsideness of a clipping path. */
+int
+gx_cpath_set_outside(gx_clip_path * pcpath, bool outside)
+{
+ if (outside != gx_cpath_list(pcpath)->outside) {
+ pcpath->id = gs_next_ids(1); /* path changed => change id */
+ gx_cpath_list(pcpath)->outside = outside;
+ }
+ return 0;
+}
+
+/* Return the current outsideness of a clipping path. */
+bool
+gx_cpath_is_outside(const gx_clip_path * pcpath)
+{
+ return gx_cpath_list(pcpath)->outside;
+}
+
+/* Set the outer clipping box to the path bounding box, */
+/* expanded to pixel boundaries. */
+void
+gx_cpath_set_outer_box(gx_clip_path * pcpath)
+{
+ pcpath->outer_box.p.x = fixed_floor(pcpath->path.bbox.p.x);
+ pcpath->outer_box.p.y = fixed_floor(pcpath->path.bbox.p.y);
+ pcpath->outer_box.q.x = fixed_ceiling(pcpath->path.bbox.q.x);
+ pcpath->outer_box.q.y = fixed_ceiling(pcpath->path.bbox.q.y);
+}
+
+/* ------ Clipping path setting ------ */
+
+/* Create a rectangular clipping path. */
+/* The supplied rectangle may not be oriented correctly, */
+/* but it will be oriented correctly upon return. */
+private int
+cpath_set_rectangle(gx_clip_path * pcpath, gs_fixed_rect * pbox)
+{
+ gx_clip_rect_list *rlist = pcpath->rect_list;
+
+ if (rlist->rc.ref_count <= 1)
+ gx_clip_list_free(&rlist->list, rlist->rc.memory);
+ else {
+ int code = cpath_alloc_list(&pcpath->rect_list, pcpath->path.memory,
+ "gx_cpath_from_rectangle");
+
+ if (code < 0)
+ return code;
+ rc_decrement(rlist, "gx_cpath_from_rectangle");
+ rlist = pcpath->rect_list;
+ }
+ cpath_init_rectangle(pcpath, pbox);
+ return 0;
+}
+int
+gx_cpath_from_rectangle(gx_clip_path * pcpath, gs_fixed_rect * pbox)
+{
+ int code = gx_path_new(&pcpath->path);
+
+ if (code < 0)
+ return code;
+ return cpath_set_rectangle(pcpath, pbox);
+}
+int
+gx_cpath_reset(gx_clip_path * pcpath)
+{
+ gs_fixed_rect null_rect;
+
+ null_rect.p.x = null_rect.p.y = null_rect.q.x = null_rect.q.y = 0;
+ return gx_cpath_from_rectangle(pcpath, &null_rect);
+}
+
+/* Intersect a new clipping path with an old one. */
+/* Flatten the new path first (in a copy) if necessary. */
+int
+gx_cpath_clip(gs_state *pgs, gx_clip_path *pcpath, gx_path *ppath_orig,
+ int rule)
+{
+ gx_path fpath;
+ gx_path *ppath = ppath_orig;
+ gs_fixed_rect old_box, new_box;
+ int code;
+
+ /* Flatten the path if necessary. */
+ if (gx_path_has_curves_inline(ppath)) {
+ gx_path_init_local(&fpath, gs_state_memory(pgs));
+ code = gx_path_add_flattened_accurate(ppath, &fpath,
+ gs_currentflat(pgs),
+ gs_currentaccuratecurves(pgs));
+ if (code < 0)
+ return code;
+ ppath = &fpath;
+ }
+ /**************** SHOULD CHANGE THIS TO KEEP PATH ****************/
+ if (gx_cpath_inner_box(pcpath, &old_box) &&
+ ((code = gx_path_is_rectangle(ppath, &new_box)) ||
+ gx_path_is_void(ppath))
+ ) {
+ bool changed = false;
+ bool outside = gx_cpath_is_outside(pcpath);
+
+ if (!code) {
+ /* The new path is void. */
+ if (gx_path_current_point(ppath, &new_box.p) < 0) {
+ /* Use the user space origin (arbitrarily). */
+ gs_point origin;
+
+ gs_transform(pgs, 0.0, 0.0, &origin);
+ new_box.p.x = float2fixed(origin.x);
+ new_box.p.y = float2fixed(origin.y);
+ changed = true;
+ }
+ new_box.q = new_box.p;
+ } else {
+ /* Intersect the two rectangles if necessary. */
+ if (old_box.p.x > new_box.p.x)
+ new_box.p.x = old_box.p.x, changed = true;
+ if (old_box.p.y > new_box.p.y)
+ new_box.p.y = old_box.p.y, changed = true;
+ if (old_box.q.x < new_box.q.x)
+ new_box.q.x = old_box.q.x, changed = true;
+ if (old_box.q.y < new_box.q.y)
+ new_box.q.y = old_box.q.y, changed = true;
+ /* Check for a degenerate rectangle. */
+ if (new_box.q.x < new_box.p.x)
+ new_box.q.x = new_box.p.x;
+ if (new_box.q.y < new_box.p.y)
+ new_box.q.y = new_box.p.y;
+ }
+ if (changed) {
+ /* Defer constructing the path. */
+ gx_path_new(&pcpath->path);
+ pcpath->path_valid = false;
+ } else {
+ gx_path_assign_preserve(&pcpath->path, ppath);
+ pcpath->path_valid = true;
+ }
+ ppath->bbox = new_box;
+ cpath_set_rectangle(pcpath, &new_box);
+ pcpath->rect_list->list.outside = outside;
+ } else {
+ /* Existing clip path is not a rectangle. Intersect the slow way. */
+ bool path_valid =
+ gx_cpath_inner_box(pcpath, &old_box) &&
+ gx_path_bbox(ppath, &new_box) >= 0 &&
+ gx_cpath_includes_rectangle(pcpath,
+ new_box.p.x, new_box.p.y,
+ new_box.q.x, new_box.q.y);
+
+ code = gx_cpath_intersect_slow(pgs, pcpath, ppath, rule);
+ if (code >= 0 && path_valid) {
+ gx_path_assign_preserve(&pcpath->path, ppath_orig);
+ pcpath->path_valid = true;
+ }
+ }
+ if (ppath != ppath_orig)
+ gx_path_free(ppath, "gx_cpath_clip");
+ return code;
+}
+
+/* Scale a clipping path by a power of 2. */
+int
+gx_cpath_scale_exp2(gx_clip_path * pcpath, int log2_scale_x, int log2_scale_y)
+{
+ int code =
+ gx_path_scale_exp2(&pcpath->path, log2_scale_x, log2_scale_y);
+ gx_clip_list *list = gx_cpath_list(pcpath);
+ gx_clip_rect *pr;
+
+ if (code < 0)
+ return code;
+ /* Scale the fixed entries. */
+ gx_rect_scale_exp2(&pcpath->inner_box, log2_scale_x, log2_scale_y);
+ gx_rect_scale_exp2(&pcpath->outer_box, log2_scale_x, log2_scale_y);
+ /* Scale the clipping list. */
+ pr = list->head;
+ if (pr == 0)
+ pr = &list->single;
+ for (; pr != 0; pr = pr->next)
+ if (pr != list->head && pr != list->tail) {
+#define scale_v(v, s)\
+ if ( pr->v != min_int && pr->v != max_int )\
+ pr->v = (s >= 0 ? pr->v << s : pr->v >> -s)
+ scale_v(xmin, log2_scale_x);
+ scale_v(xmax, log2_scale_x);
+ scale_v(ymin, log2_scale_y);
+ scale_v(ymax, log2_scale_y);
+#undef scale_v
+ }
+ pcpath->id = gs_next_ids(1); /* path changed => change id */
+ return 0;
+}
+
+/* ------ Clipping list routines ------ */
+
+/* Initialize a clip list. */
+void
+gx_clip_list_init(gx_clip_list * clp)
+{
+ *clp = clip_list_empty;
+}
+
+/* Initialize a clip list to a rectangle. */
+/* The supplied rectangle may not be oriented correctly, */
+/* but it will be oriented correctly upon return. */
+private void
+gx_clip_list_from_rectangle(register gx_clip_list * clp,
+ register gs_fixed_rect * rp)
+{
+ gx_clip_list_init(clp);
+ if (rp->p.x > rp->q.x) {
+ fixed t = rp->p.x;
+
+ rp->p.x = rp->q.x;
+ rp->q.x = t;
+ }
+ if (rp->p.y > rp->q.y) {
+ fixed t = rp->p.y;
+
+ rp->p.y = rp->q.y;
+ rp->q.y = t;
+ }
+ clp->single.xmin = fixed2int_var(rp->p.x);
+ clp->single.ymin = fixed2int_var(rp->p.y);
+ clp->single.xmax = fixed2int_var_ceiling(rp->q.x);
+ clp->single.ymax = fixed2int_var_ceiling(rp->q.y);
+ clp->count = 1;
+ clp->outside = false;
+}
+
+/* Start enumerating a clipping path. */
+int
+gx_cpath_enum_init(gs_cpath_enum * penum, gx_clip_path * pcpath)
+{
+ if ((penum->using_path = pcpath->path_valid)) {
+ gx_path_enum_init(&penum->path_enum, &pcpath->path);
+ penum->rp = penum->visit = 0;
+ } else {
+ gx_path empty_path;
+ gx_clip_list *clp = gx_cpath_list(pcpath);
+ gx_clip_rect *head = (clp->count <= 1 ? &clp->single : clp->head);
+ gx_clip_rect *rp;
+
+ /* Initialize the pointers in the path_enum properly. */
+ gx_path_init_local(&empty_path, pcpath->path.memory);
+ gx_path_enum_init(&penum->path_enum, &empty_path);
+ penum->visit = head;
+ for (rp = head; rp != 0; rp = rp->next)
+ rp->to_visit =
+ (rp->xmin < rp->xmax && rp->ymin < rp->ymax ?
+ visit_left | visit_right : 0);
+ penum->rp = 0; /* scan will initialize */
+ penum->any_rectangles = false;
+ penum->state = cpe_scan;
+ penum->have_line = false;
+ }
+ return 0;
+}
+
+/* Enumerate the next segment of a clipping path. */
+/* In general, this produces a path made up of zillions of tiny lines. */
+int
+gx_cpath_enum_next(gs_cpath_enum * penum, gs_fixed_point pts[3])
+{
+ if (penum->using_path)
+ return gx_path_enum_next(&penum->path_enum, pts);
+#define set_pt(xi, yi)\
+ (pts[0].x = int2fixed(xi), pts[0].y = int2fixed(yi))
+#define set_line(xi, yi)\
+ (penum->line_end.x = (xi), penum->line_end.y = (yi), penum->have_line = true)
+ if (penum->have_line) {
+ set_pt(penum->line_end.x, penum->line_end.y);
+ penum->have_line = false;
+ return gs_pe_lineto;
+ } {
+ gx_clip_rect *visit = penum->visit;
+ gx_clip_rect *rp = penum->rp;
+ cpe_visit_t first_visit = penum->first_visit;
+ cpe_state_t state = penum->state;
+ gx_clip_rect *look;
+ int code;
+
+ switch (state) {
+
+ case cpe_scan:
+ /* Look for the start of an edge to trace. */
+ for (; visit != 0; visit = visit->next) {
+ if (visit->to_visit & visit_left) {
+ set_pt(visit->xmin, visit->ymin);
+ first_visit = visit_left;
+ state = cpe_left;
+ } else if (visit->to_visit & visit_right) {
+ set_pt(visit->xmax, visit->ymax);
+ first_visit = visit_right;
+ state = cpe_right;
+ } else
+ continue;
+ rp = visit;
+ code = gs_pe_moveto;
+ penum->any_rectangles = true;
+ goto out;
+ }
+ /* We've enumerated all the edges. */
+ state = cpe_done;
+ if (!penum->any_rectangles) {
+ /* We didn't have any rectangles. */
+ set_pt(fixed_0, fixed_0);
+ code = gs_pe_moveto;
+ break;
+ }
+ /* falls through */
+
+ case cpe_done:
+ /* All done. */
+ code = 0;
+ break;
+
+/* We can't use the BEGIN ... END hack here: we need to be able to break. */
+#define return_line(px, py)\
+ set_pt(px, py); code = gs_pe_lineto; break
+
+ case cpe_left:
+
+ left: /* Trace upward along a left edge. */
+ /* We're at the lower left corner of rp. */
+ rp->to_visit &= ~visit_left;
+ /* Look for an adjacent rectangle above rp. */
+ for (look = rp;
+ (look = look->next) != 0 &&
+ (look->ymin == rp->ymin ||
+ (look->ymin == rp->ymax && look->xmax <= rp->xmin));
+ );
+ /* Now we know look->ymin >= rp->ymax. */
+ if (look == 0 || look->ymin > rp->ymax ||
+ look->xmin >= rp->xmax
+ ) { /* No adjacent rectangle, switch directions. */
+ state =
+ (rp == visit && first_visit == visit_right ? cpe_close :
+ (set_line(rp->xmax, rp->ymax), cpe_right));
+ return_line(rp->xmin, rp->ymax);
+ }
+ /* We found an adjacent rectangle. */
+ /* See if it also adjoins a rectangle to the left of rp. */
+ {
+ gx_clip_rect *prev = rp->prev;
+ gx_clip_rect *cur = rp;
+
+ if (prev != 0 && prev->ymax == rp->ymax &&
+ look->xmin < prev->xmax
+ ) { /* There's an adjoining rectangle as well. */
+ /* Switch directions. */
+ rp = prev;
+ state =
+ (rp == visit && first_visit == visit_right ? cpe_close :
+ (set_line(prev->xmax, prev->ymax), cpe_right));
+ return_line(cur->xmin, cur->ymax);
+ }
+ rp = look;
+ if (rp == visit && first_visit == visit_left)
+ state = cpe_close;
+ else if (rp->xmin == cur->xmin)
+ goto left;
+ else
+ set_line(rp->xmin, rp->ymin);
+ return_line(cur->xmin, cur->ymax);
+ }
+
+ case cpe_right:
+
+ right: /* Trace downward along a right edge. */
+ /* We're at the upper right corner of rp. */
+ rp->to_visit &= ~visit_right;
+ /* Look for an adjacent rectangle below rp. */
+ for (look = rp;
+ (look = look->prev) != 0 &&
+ (look->ymax == rp->ymax ||
+ (look->ymax == rp->ymin && look->xmin >= rp->xmax));
+ );
+ /* Now we know look->ymax <= rp->ymin. */
+ if (look == 0 || look->ymax < rp->ymin ||
+ look->xmax <= rp->xmin
+ ) { /* No adjacent rectangle, switch directions. */
+ state =
+ (rp == visit && first_visit == visit_left ? cpe_close :
+ (set_line(rp->xmin, rp->ymin), cpe_left));
+ return_line(rp->xmax, rp->ymin);
+ }
+ /* We found an adjacent rectangle. */
+ /* See if it also adjoins a rectangle to the right of rp. */
+ {
+ gx_clip_rect *next = rp->next;
+ gx_clip_rect *cur = rp;
+
+ if (next != 0 && next->ymin == rp->ymin &&
+ look->xmax > next->xmin
+ ) { /* There's an adjoining rectangle as well. */
+ /* Switch directions. */
+ rp = next;
+ state =
+ (rp == visit && first_visit == visit_left ? cpe_close :
+ (set_line(next->xmin, next->ymin), cpe_left));
+ return_line(cur->xmax, cur->ymin);
+ }
+ rp = look;
+ if (rp == visit && first_visit == visit_right)
+ state = cpe_close;
+ else if (rp->xmax == cur->xmax)
+ goto right;
+ else
+ set_line(rp->xmax, rp->ymax);
+ return_line(cur->xmax, cur->ymin);
+ }
+
+#undef return_line
+
+ case cpe_close:
+ /* We've gone all the way around an edge. */
+ code = gs_pe_closepath;
+ state = cpe_scan;
+ break;
+
+ default:
+ return_error(gs_error_unknownerror);
+ }
+
+ out: /* Store the state before exiting. */
+ penum->visit = visit;
+ penum->rp = rp;
+ penum->first_visit = first_visit;
+ penum->state = state;
+ return code;
+ }
+#undef set_pt
+#undef set_line
+}
+segment_notes
+gx_cpath_enum_notes(const gs_cpath_enum * penum)
+{
+ return sn_none;
+}
+
+/* Free a clip list. */
+void
+gx_clip_list_free(gx_clip_list * clp, gs_memory_t * mem)
+{
+ gx_clip_rect *rp = clp->tail;
+
+ while (rp != 0) {
+ gx_clip_rect *prev = rp->prev;
+
+ gs_free_object(mem, rp, "gx_clip_list_free");
+ rp = prev;
+ }
+ gx_clip_list_init(clp);
+}
+
+/* ------ Debugging printout ------ */
+
+#ifdef DEBUG
+
+/* Print a clipping path */
+void
+gx_cpath_print(const gx_clip_path * pcpath)
+{
+ const gx_clip_rect *pr;
+ const gx_clip_list *list = gx_cpath_list(pcpath);
+
+ if (pcpath->path_valid)
+ gx_path_print(&pcpath->path);
+ else
+ dlputs(" (path not valid)\n");
+ dlprintf4(" inner_box=(%g,%g),(%g,%g)\n",
+ fixed2float(pcpath->inner_box.p.x),
+ fixed2float(pcpath->inner_box.p.y),
+ fixed2float(pcpath->inner_box.q.x),
+ fixed2float(pcpath->inner_box.q.y));
+ dlprintf4(" outer_box=(%g,%g),(%g,%g)",
+ fixed2float(pcpath->outer_box.p.x),
+ fixed2float(pcpath->outer_box.p.y),
+ fixed2float(pcpath->outer_box.q.x),
+ fixed2float(pcpath->outer_box.q.y));
+ dprintf4(" rule=%d outside=%d count=%d list.refct=%ld\n",
+ pcpath->rule, list->outside, list->count,
+ pcpath->rect_list->rc.ref_count);
+ switch (list->count) {
+ case 0:
+ pr = 0;
+ break;
+ case 1:
+ pr = &list->single;
+ break;
+ default:
+ pr = list->head;
+ }
+ for (; pr != 0; pr = pr->next)
+ dlprintf4(" rect: (%d,%d),(%d,%d)\n",
+ pr->xmin, pr->ymin, pr->xmax, pr->ymax);
+}
+
+#endif /* DEBUG */
diff --git a/pstoraster/gxcpath.h b/pstoraster/gxcpath.h
new file mode 100644
index 000000000..04d358196
--- /dev/null
+++ b/pstoraster/gxcpath.h
@@ -0,0 +1,134 @@
+/* Copyright (C) 1991, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of GNU Ghostscript.
+
+ GNU Ghostscript is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
+ to anyone for the consequences of using it or for whether it serves any
+ particular purpose or works at all, unless he says so in writing. Refer
+ to the GNU General Public License for full details.
+
+ Everyone is granted permission to copy, modify and redistribute GNU
+ Ghostscript, but only under the conditions described in the GNU General
+ Public License. A copy of this license is supposed to have been given
+ to you along with GNU Ghostscript so you can know your rights and
+ responsibilities. It should be in a file named COPYING. Among other
+ things, the copyright notice and this notice must be preserved on all
+ copies.
+
+ Aladdin Enterprises 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 gxcpath_INCLUDED
+# define gxcpath_INCLUDED
+
+/* We expose the implementation of clipping lists so that clients */
+/* can allocate clipping lists or devices on the stack. */
+
+/*
+ * For clipping, a path is represented as a list of rectangles.
+ * Normally, a path is created as a list of segments;
+ * installing it as a clipping path creates the rectangle list.
+ * However, when the clipping path originates in some other way
+ * (e.g., from initclip, or for clipping a cached character),
+ * or if it is a non-trivial intersection of two paths,
+ * the resulting clipping path exists only as a rectangle list;
+ * clippath constructs the segment representation if needed.
+ * Note that even if the path only exists as a rectangle list,
+ * its bounding box (path.bbox) is still correct.
+ */
+
+/*
+ * Rectangle list structure.
+ * Consecutive gx_clip_rect entries either have the same Y values,
+ * or ymin of this entry >= ymax of the previous entry.
+ */
+typedef struct gx_clip_rect_s gx_clip_rect;
+struct gx_clip_rect_s {
+ gx_clip_rect *next, *prev;
+ int ymin, ymax; /* ymax > ymin */
+ int xmin, xmax; /* xmax > xmin */
+ byte to_visit; /* bookkeeping for gs_clippath */
+};
+
+/* The descriptor is public only for gxacpath.c. */
+extern_st(st_clip_rect);
+#define public_st_clip_rect() /* in gxcpath.c */\
+ gs_public_st_ptrs2(st_clip_rect, gx_clip_rect, "clip_rect",\
+ clip_rect_enum_ptrs, clip_rect_reloc_ptrs, next, prev)
+#define st_clip_rect_max_ptrs 2
+
+/*
+ * A clip list may consist either of a single rectangle,
+ * with null head and tail, or a list of rectangles. In the latter case,
+ * there is a dummy head entry with p.x = q.x to cover Y values
+ * starting at min_int, and a dummy tail entry to cover Y values
+ * ending at max_int. This eliminates the need for end tests.
+ */
+#ifndef gx_clip_list_DEFINED
+# define gx_clip_list_DEFINED
+typedef struct gx_clip_list_s gx_clip_list;
+
+#endif
+struct gx_clip_list_s {
+ gx_clip_rect single; /* (has next = prev = 0) */
+ gx_clip_rect *head;
+ gx_clip_rect *tail;
+ int count; /* # of rectangles not counting */
+ /* head or tail */
+ bool outside; /* if true, clip to outside of list */
+ /* rather than inside */
+};
+
+#define private_st_clip_list() /* in gxcpath.c */\
+ gs_private_st_ptrs2(st_clip_list, gx_clip_list, "clip_list",\
+ clip_list_enum_ptrs, clip_list_reloc_ptrs, head, tail)
+#define st_clip_list_max_ptrs 2 /* head, tail */
+#define clip_list_is_rectangle(clp) ((clp)->count <= 1)
+
+/*
+ * Clipping devices provide for translation before clipping.
+ * This ability, a late addition, currently is used only in a few
+ * situations that require breaking up a transfer into pieces,
+ * but we suspect it could be used more widely.
+ */
+typedef struct gx_device_clip_s {
+ gx_device_forward_common; /* target is set by client */
+ gx_clip_list list; /* set by client */
+ gx_clip_rect *current; /* cursor in list */
+ gs_int_point translation;
+} gx_device_clip;
+
+extern_st(st_device_clip);
+#define public_st_device_clip() /* in gxcpath.c */\
+ gs_public_st_composite(st_device_clip, gx_device_clip,\
+ "gx_device_clip", device_clip_enum_ptrs, device_clip_reloc_ptrs)
+void gx_make_clip_translate_device(P5(gx_device_clip * dev, void *container,
+ const gx_clip_list * list, int tx, int ty));
+
+#define gx_make_clip_device(dev, container, list)\
+ gx_make_clip_translate_device(dev, container, list, 0, 0)
+void gx_make_clip_path_device(P2(gx_device_clip *, const gx_clip_path *));
+
+#define clip_rect_print(ch, str, ar)\
+ if_debug7(ch, "[%c]%s 0x%lx: (%d,%d),(%d,%d)\n", ch, str, (ulong)ar,\
+ (ar)->xmin, (ar)->ymin, (ar)->xmax, (ar)->ymax)
+
+/* Routines exported from gxcpath.c for gxacpath.c */
+
+/* Initialize a clip list. */
+void gx_clip_list_init(P1(gx_clip_list *));
+
+/* Free a clip list. */
+void gx_clip_list_free(P2(gx_clip_list *, gs_memory_t *));
+
+/* Set the outer box for a clipping path from its bounding box. */
+void gx_cpath_set_outer_box(P1(gx_clip_path *));
+
+#endif /* gxcpath_INCLUDED */
diff --git a/pstoraster/gxcspace.h b/pstoraster/gxcspace.h
new file mode 100644
index 000000000..8737e3a2a
--- /dev/null
+++ b/pstoraster/gxcspace.h
@@ -0,0 +1,237 @@
+/* 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$ */
+/* Implementation of color spaces */
+/* Requires gsstruct.h */
+
+#ifndef gxcspace_INCLUDED
+# define gxcspace_INCLUDED
+
+#include "gscspace.h" /* client interface */
+#include "gsccolor.h"
+#include "gscsel.h"
+#include "gxfrac.h" /* for concrete colors */
+
+/* Define opaque types. */
+
+#ifndef gx_device_color_DEFINED
+# define gx_device_color_DEFINED
+typedef struct gx_device_color_s gx_device_color;
+
+#endif
+
+#ifndef gx_device_DEFINED
+# define gx_device_DEFINED
+typedef struct gx_device_s gx_device;
+
+#endif
+
+/* Color space types (classes): */
+/*typedef struct gs_color_space_type_s gs_color_space_type; */
+struct gs_color_space_type_s {
+
+ gs_color_space_index index;
+
+ /*
+ * Define whether the space can be the base space for an Indexed
+ * color space or the alternate space for a Separation or DeviceN
+ * color space.
+ */
+
+ bool can_be_base_space;
+ bool can_be_alt_space;
+
+ /*
+ * Define the true structure type for this variant of the color
+ * space union.
+ */
+
+ gs_memory_type_ptr_t stype;
+
+ /* ------ Procedures ------ */
+
+ /*
+ * Define the number of components in a color of this space. For
+ * Pattern spaces, where the number of components depends on the
+ * underlying space, this value is -1 for colored Patterns,
+ * -N-1 for uncolored Patterns, where N is the number of components
+ * in the base space.
+ */
+
+#define cs_proc_num_components(proc)\
+ int proc(P1(const gs_color_space *))
+#define cs_num_components(pcs)\
+ (*(pcs)->type->num_components)(pcs)
+ cs_proc_num_components((*num_components));
+
+ /*
+ * Return the base or alternate color space underlying this one.
+ * Only defined for Indexed, Separation, DeviceN, and
+ * uncolored Pattern spaces; returns NULL for all others.
+ */
+
+#define cs_proc_base_space(proc)\
+ const gs_color_space *proc(P1(const gs_color_space *))
+#define cs_base_space(pcs)\
+ (*(pcs)->type->base_space)(pcs)
+ cs_proc_base_space((*base_space));
+
+ /* Construct the initial color value for this space. */
+
+#define cs_proc_init_color(proc)\
+ void proc(P2(gs_client_color *, const gs_color_space *))
+#define cs_init_color(pcc, pcs)\
+ (*(pcs)->type->init_color)(pcc, pcs)
+#define cs_full_init_color(pcc, pcs)\
+ ((pcc)->pattern = 0, cs_init_color(pcc, pcs))
+ cs_proc_init_color((*init_color));
+
+ /* Force a client color into its legal range. */
+
+#define cs_proc_restrict_color(proc)\
+ void proc(P2(gs_client_color *, const gs_color_space *))
+ cs_proc_restrict_color((*restrict_color));
+
+ /* Return the concrete color space underlying this one. */
+ /* (Not defined for Pattern spaces.) */
+
+#define cs_proc_concrete_space(proc)\
+ const gs_color_space *proc(P2(const gs_color_space *,\
+ const gs_imager_state *))
+#define cs_concrete_space(pcs, pis)\
+ (*(pcs)->type->concrete_space)(pcs, pis)
+ cs_proc_concrete_space((*concrete_space));
+
+ /*
+ * Reduce a color to a concrete color. A concrete color is one
+ * that the device can handle directly (possibly with halftoning):
+ * a DeviceGray/RGB/CMYK/Pixel color, or a Separation or DeviceN
+ * color that does not use the alternate space.
+ * (Not defined for Pattern spaces.)
+ */
+
+#define cs_proc_concretize_color(proc)\
+ int proc(P4(const gs_client_color *, const gs_color_space *,\
+ frac *, const gs_imager_state *))
+#define cs_concretize_color(pcc, pcs, values, pis)\
+ (*(pcs)->type->concretize_color)(pcc, pcs, values, pis)
+ cs_proc_concretize_color((*concretize_color));
+
+ /* Map a concrete color to a device color. */
+ /* (Only defined for concrete color spaces.) */
+
+#define cs_proc_remap_concrete_color(proc)\
+ int proc(P5(const frac *, gx_device_color *, const gs_imager_state *,\
+ gx_device *, gs_color_select_t))
+ cs_proc_remap_concrete_color((*remap_concrete_color));
+
+ /* Map a color directly to a device color. */
+
+#define cs_proc_remap_color(proc)\
+ int proc(P6(const gs_client_color *, const gs_color_space *,\
+ gx_device_color *, const gs_imager_state *, gx_device *,\
+ gs_color_select_t))
+ cs_proc_remap_color((*remap_color));
+
+ /* Install the color space in a graphics state. */
+
+#define cs_proc_install_cspace(proc)\
+ int proc(P2(gs_color_space *, gs_state *))
+ cs_proc_install_cspace((*install_cspace));
+
+ /* Adjust reference counts of indirect color space components. */
+
+#define cs_proc_adjust_cspace_count(proc)\
+ void proc(P2(const gs_color_space *, int))
+#define cs_adjust_cspace_count(pgs, delta)\
+ (*(pgs)->color_space->type->adjust_cspace_count)((pgs)->color_space, delta)
+ cs_proc_adjust_cspace_count((*adjust_cspace_count));
+
+ /* Adjust reference counts of indirect color components. */
+ /*
+ * Note: the color space argument may be NULL, which indicates that the
+ * caller warrants that any subsidiary colors don't have allocation
+ * issues. This is a hack for an application that needs to be able to
+ * release Pattern colors.
+ */
+
+#define cs_proc_adjust_color_count(proc)\
+ void proc(P3(const gs_client_color *, const gs_color_space *, int))
+#define cs_adjust_color_count(pgs, delta)\
+ (*(pgs)->color_space->type->adjust_color_count)\
+ ((pgs)->ccolor, (pgs)->color_space, delta)
+ cs_proc_adjust_color_count((*adjust_color_count));
+
+/* Adjust both reference counts. */
+#define cs_adjust_counts(pgs, delta)\
+ (cs_adjust_color_count(pgs, delta), cs_adjust_cspace_count(pgs, delta))
+
+};
+
+/* Standard color space structure types */
+extern_st(st_base_color_space);
+#define public_st_base_color_space() /* in gscspace.c */\
+ gs_public_st_simple(st_base_color_space, gs_base_color_space,\
+ "gs_base_color_space")
+/*extern_st(st_paint_color_space); *//* (not needed) */
+
+/* Standard color space procedures */
+cs_proc_num_components(gx_num_components_1);
+cs_proc_num_components(gx_num_components_3);
+cs_proc_num_components(gx_num_components_4);
+cs_proc_base_space(gx_no_base_space);
+cs_proc_init_color(gx_init_paint_1);
+cs_proc_init_color(gx_init_paint_3);
+cs_proc_init_color(gx_init_paint_4);
+cs_proc_restrict_color(gx_restrict01_paint_1);
+cs_proc_restrict_color(gx_restrict01_paint_3);
+cs_proc_restrict_color(gx_restrict01_paint_4);
+cs_proc_concrete_space(gx_no_concrete_space);
+cs_proc_concrete_space(gx_same_concrete_space);
+cs_proc_concretize_color(gx_no_concretize_color);
+cs_proc_remap_color(gx_default_remap_color);
+cs_proc_install_cspace(gx_no_install_cspace);
+cs_proc_adjust_cspace_count(gx_no_adjust_cspace_count);
+cs_proc_adjust_color_count(gx_no_adjust_color_count);
+
+/* Standard color space types */
+extern const gs_color_space_type
+ gs_color_space_type_DeviceGray,
+ gs_color_space_type_DeviceRGB,
+ gs_color_space_type_DeviceCMYK;
+
+/* Define the allocator type for color spaces. */
+extern_st(st_color_space);
+
+/*
+ * Allocate a color space and initialize its type and memory fields.
+ * This is only used by color space implementations.
+ */
+
+int gs_cspace_alloc(P3(gs_color_space **ppcspace,
+ const gs_color_space_type *pcstype,
+ gs_memory_t *mem));
+
+#endif /* gxcspace_INCLUDED */
diff --git a/pstoraster/gxctable.c b/pstoraster/gxctable.c
new file mode 100644
index 000000000..f7a53b722
--- /dev/null
+++ b/pstoraster/gxctable.c
@@ -0,0 +1,146 @@
+/* Copyright (C) 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of GNU Ghostscript.
+
+ GNU Ghostscript is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
+ to anyone for the consequences of using it or for whether it serves any
+ particular purpose or works at all, unless he says so in writing. Refer
+ to the GNU General Public License for full details.
+
+ Everyone is granted permission to copy, modify and redistribute GNU
+ Ghostscript, but only under the conditions described in the GNU General
+ Public License. A copy of this license is supposed to have been given
+ to you along with GNU Ghostscript so you can know your rights and
+ responsibilities. It should be in a file named COPYING. Among other
+ things, the copyright notice and this notice must be preserved on all
+ copies.
+
+ Aladdin Enterprises 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$ */
+/* Color table lookup and interpolation */
+#include "gx.h"
+#include "gxfixed.h"
+#include "gxfrac.h"
+#include "gxctable.h"
+
+/* See gxctable.h for the API and structure definitions. */
+
+/*
+ * Define an implementation that simply picks the nearest value without
+ * any interpolation.
+ */
+void
+gx_color_interpolate_nearest(const fixed * pi,
+ const gx_color_lookup_table * pclt, frac * pv)
+{
+ const int *pdim = pclt->dims;
+ int m = pclt->m;
+ const gs_const_string *table = pclt->table;
+
+ if (pclt->n > 3) {
+ table += fixed2int_var_rounded(pi[0]) * pdim[1];
+ ++pi, ++pdim;
+ } {
+ int ic = fixed2int_var_rounded(pi[2]);
+ int ib = fixed2int_var_rounded(pi[1]);
+ int ia = fixed2int_var_rounded(pi[0]);
+ const byte *p = pclt->table[ia].data + (ib * pdim[2] + ic) * m;
+ int j;
+
+ for (j = 0; j < m; ++j, ++p)
+ pv[j] = byte2frac(*p);
+ }
+}
+
+/*
+ * Define an implementation that uses trilinear interpolation.
+ */
+void
+gx_color_interpolate_linear(const fixed * pi,
+ const gx_color_lookup_table * pclt, frac * pv)
+{
+ const int *pdim = pclt->dims;
+ int m = pclt->m;
+
+ if (pclt->n > 3) { /* Do two 3-D interpolations, */
+ /* and then interpolate between them. */
+ gx_color_lookup_table clt3;
+ frac vx[4];
+ int ix = fixed2int_var(pi[0]);
+ fixed fx = fixed_fraction(pi[0]);
+ int j;
+
+ clt3.n = 3;
+ /*clt3.dims[0] = pdim[1]; *//* not used */
+ clt3.dims[1] = pdim[2];
+ clt3.dims[2] = pdim[3];
+ clt3.m = m;
+ clt3.table = pclt->table + ix * pdim[1];
+ gx_color_interpolate_linear(pi + 1, &clt3, pv);
+ if (ix == pdim[0] - 1)
+ return;
+ clt3.table += pdim[1];
+ gx_color_interpolate_linear(pi + 1, &clt3, vx);
+ for (j = 0; j < m; ++j)
+ pv[j] += (frac) arith_rshift((long)fx * (vx[j] - pv[j]),
+ _fixed_shift);
+ } else {
+ int ic = fixed2int_var(pi[2]);
+ fixed fc = fixed_fraction(pi[2]);
+ uint dc1 = (ic == pdim[2] - 1 ? 0 : m);
+ int ib = fixed2int_var(pi[1]);
+ fixed fb = fixed_fraction(pi[1]);
+ uint db1 = (ib == pdim[1] - 1 ? 0 : pdim[2] * m);
+ uint dbc = (ib * pdim[2] + ic) * m;
+ uint dbc1 = db1 + dc1;
+ int ia = fixed2int_var(pi[0]);
+ fixed fa = fixed_fraction(pi[0]);
+ const byte *pa0 = pclt->table[ia].data + dbc;
+ const byte *pa1 =
+ (ia == pdim[0] - 1 ? pa0 : pclt->table[ia + 1].data + dbc);
+ int j;
+
+ /* The values to be interpolated are */
+ /* pa{0,1}[{0,db1,dc1,dbc1}]. */
+ for (j = 0; j < m; ++j, ++pa0, ++pa1) {
+ frac v000 = byte2frac(pa0[0]);
+ frac v001 = byte2frac(pa0[dc1]);
+ frac v010 = byte2frac(pa0[db1]);
+ frac v011 = byte2frac(pa0[dbc1]);
+ frac v100 = byte2frac(pa1[0]);
+ frac v101 = byte2frac(pa1[dc1]);
+ frac v110 = byte2frac(pa1[db1]);
+ frac v111 = byte2frac(pa1[dbc1]);
+
+ frac v00 = v000 +
+ (frac) arith_rshift((long)fc * (v001 - v000),
+ _fixed_shift);
+ frac v01 = v010 +
+ (frac) arith_rshift((long)fc * (v011 - v010),
+ _fixed_shift);
+ frac v10 = v100 +
+ (frac) arith_rshift((long)fc * (v101 - v100),
+ _fixed_shift);
+ frac v11 = v110 +
+ (frac) arith_rshift((long)fc * (v111 - v110),
+ _fixed_shift);
+
+ frac v0 = v00 +
+ (frac) arith_rshift((long)fb * (v01 - v00),
+ _fixed_shift);
+ frac v1 = v10 +
+ (frac) arith_rshift((long)fb * (v11 - v10),
+ _fixed_shift);
+
+ pv[j] = v0 +
+ (frac) arith_rshift((long)fa * (v1 - v0),
+ _fixed_shift);
+ }
+ }
+}
diff --git a/pstoraster/gxctable.h b/pstoraster/gxctable.h
new file mode 100644
index 000000000..237f47cdd
--- /dev/null
+++ b/pstoraster/gxctable.h
@@ -0,0 +1,70 @@
+/* Copyright (C) 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of GNU Ghostscript.
+
+ GNU Ghostscript is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
+ to anyone for the consequences of using it or for whether it serves any
+ particular purpose or works at all, unless he says so in writing. Refer
+ to the GNU General Public License for full details.
+
+ Everyone is granted permission to copy, modify and redistribute GNU
+ Ghostscript, but only under the conditions described in the GNU General
+ Public License. A copy of this license is supposed to have been given
+ to you along with GNU Ghostscript so you can know your rights and
+ responsibilities. It should be in a file named COPYING. Among other
+ things, the copyright notice and this notice must be preserved on all
+ copies.
+
+ Aladdin Enterprises 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 color table lookup and interpolation */
+
+#ifndef gxctable_INCLUDED
+# define gxctable_INCLUDED
+
+#include "gxfixed.h"
+#include "gxfrac.h"
+
+/*
+ * Define a 3- or 4-D color lookup table.
+ * n is the number of dimensions (input indices), 3 or 4.
+ * dims[0..n-1] are the table dimensions.
+ * m is the number of output values, 3 or 4.
+ * For n = 3:
+ * table[i], 0 <= i < dims[0], point to strings of length
+ * dims[1] x dims[2] x m.
+ * For n = 4:
+ * table[i], 0 <= i < dims[0] x dims[1], points to strings of length
+ * dims[2] x dims[3] x m.
+ * It isn't really necessary to store the size of each string, since
+ * they're all the same size, but it makes things a lot easier for the GC.
+ */
+typedef struct gx_color_lookup_table_s {
+ int n;
+ int dims[4]; /* [ndims] */
+ int m;
+ const gs_const_string *table;
+} gx_color_lookup_table;
+
+/*
+ * Interpolate in a 3- or 4-D color lookup table.
+ * pi[0..n-1] are the table indices, guaranteed to be in the ranges
+ * [0..dims[n]-1] respectively.
+ * Return interpolated values in pv[0..m-1].
+ */
+
+/* Return the nearest value without interpolation. */
+void gx_color_interpolate_nearest(P3(const fixed * pi,
+ const gx_color_lookup_table * pclt, frac * pv));
+
+/* Use trilinear interpolation. */
+void gx_color_interpolate_linear(P3(const fixed * pi,
+ const gx_color_lookup_table * pclt, frac * pv));
+
+#endif /* gxctable_INCLUDED */
diff --git a/pstoraster/gxcvalue.h b/pstoraster/gxcvalue.h
new file mode 100644
index 000000000..f919415ed
--- /dev/null
+++ b/pstoraster/gxcvalue.h
@@ -0,0 +1,48 @@
+/* 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$ */
+/* Definition of device color values */
+
+#ifndef gxcvalue_INCLUDED
+# define gxcvalue_INCLUDED
+
+/* Define the type for gray or RGB values at the driver interface. */
+typedef unsigned short gx_color_value;
+
+#define arch_sizeof_gx_color_value arch_sizeof_short
+/* We might use less than the full range someday. */
+/* ...bits must lie between 8 and 16. */
+#define gx_color_value_bits (sizeof(gx_color_value) * 8)
+#define gx_max_color_value ((gx_color_value)((1L << gx_color_value_bits) - 1))
+#define gx_color_value_to_byte(cv)\
+ ((cv) >> (gx_color_value_bits - 8))
+#define gx_color_value_from_byte(cb)\
+ (((cb) << (gx_color_value_bits - 8)) + ((cb) >> (16 - gx_color_value_bits)))
+
+/* Convert between gx_color_values and fracs. */
+#define frac2cv(fr) frac2ushort(fr)
+#define cv2frac(cv) ushort2frac(cv)
+
+#endif /* gxcvalue_INCLUDED */
diff --git a/pstoraster/gxdcconv.c b/pstoraster/gxdcconv.c
new file mode 100644
index 000000000..97a055d86
--- /dev/null
+++ b/pstoraster/gxdcconv.c
@@ -0,0 +1,162 @@
+/* Copyright (C) 1992, 1995, 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$ */
+/* Conversion between device color spaces for Ghostscript */
+#include "gx.h"
+#include "gsdcolor.h" /* for gxcmap.h */
+#include "gxdcconv.h" /* interface */
+#include "gxdevice.h" /* for gxcmap.h */
+#include "gxcmap.h"
+#include "gxfarith.h"
+#include "gxlum.h"
+#include "gxistate.h"
+
+/*
+ * The CMYK to RGB algorithms specified by Adobe are, e.g.,
+ * R = 1.0 - min(1.0, C + K)
+ * C = max(0.0, min(1.0, 1 - R - UCR))
+ * but we get much better results with
+ * R = (1.0 - C) * (1.0 - K)
+ * C = max(0.0, min(1.0, 1 - R / (1 - UCR)))
+ * For utmost compatibility, we offer the Adobe algorithms as an option:
+ */
+#define USE_ADOBE_CMYK_RGB
+
+/* ------ Color space conversion ------ */
+
+/* Only 4 of the 6 conversions are implemented here; */
+/* the other 2 (Gray to RGB/CMYK) are trivial. */
+
+/* Convert RGB to Gray. */
+frac
+color_rgb_to_gray(frac r, frac g, frac b, const gs_imager_state * pis)
+{
+ return (r * (unsigned long)lum_red_weight +
+ g * (unsigned long)lum_green_weight +
+ b * (unsigned long)lum_blue_weight +
+ (lum_all_weights / 2))
+ / lum_all_weights;
+}
+
+/* Convert RGB to CMYK. */
+/* Note that this involves black generation and undercolor removal. */
+void
+color_rgb_to_cmyk(frac r, frac g, frac b, const gs_imager_state * pis,
+ frac cmyk[4])
+{
+ frac c = frac_1 - r, m = frac_1 - g, y = frac_1 - b;
+ frac k = (c < m ? min(c, y) : min(m, y));
+
+ /* The default UCR and BG functions are pretty arbitrary.... */
+ frac bg =
+ (pis->black_generation == NULL ? frac_0 :
+ gx_map_color_frac(pis, k, black_generation));
+ signed_frac ucr =
+ (pis->undercolor_removal == NULL ? frac_0 :
+ gx_map_color_frac(pis, k, undercolor_removal));
+
+ if (ucr == frac_1)
+ cmyk[0] = cmyk[1] = cmyk[2] = 0;
+ else {
+#ifdef USE_ADOBE_CMYK_RGB
+ /* C = max(0.0, min(1.0, 1 - R - UCR)), etc. */
+ signed_frac not_ucr = (ucr < 0 ? frac_1 + ucr : frac_1);
+
+ cmyk[0] = (c < ucr ? frac_0 : c > not_ucr ? frac_1 : c - ucr);
+ cmyk[1] = (m < ucr ? frac_0 : m > not_ucr ? frac_1 : m - ucr);
+ cmyk[2] = (y < ucr ? frac_0 : y > not_ucr ? frac_1 : y - ucr);
+#else
+ /* C = max(0.0, min(1.0, 1 - R / (1 - UCR))), etc. */
+ float denom = frac2float(frac_1 - ucr); /* unscaled */
+ float v;
+
+ v = (float)frac_1 - r / denom; /* unscaled */
+ cmyk[0] =
+ (is_fneg(v) ? frac_0 : v >= (float)frac_1 ? frac_1 : (frac) v);
+ v = (float)frac_1 - g / denom; /* unscaled */
+ cmyk[1] =
+ (is_fneg(v) ? frac_0 : v >= (float)frac_1 ? frac_1 : (frac) v);
+ v = (float)frac_1 - b / denom; /* unscaled */
+ cmyk[2] =
+ (is_fneg(v) ? frac_0 : v >= (float)frac_1 ? frac_1 : (frac) v);
+#endif
+ }
+ cmyk[3] = bg;
+ if_debug7('c', "[c]RGB 0x%x,0x%x,0x%x -> CMYK 0x%x,0x%x,0x%x,0x%x\n",
+ r, g, b, cmyk[0], cmyk[1], cmyk[2], cmyk[3]);
+}
+
+/* Convert CMYK to Gray. */
+frac
+color_cmyk_to_gray(frac c, frac m, frac y, frac k, const gs_imager_state * pis)
+{
+ frac not_gray = color_rgb_to_gray(c, m, y, pis);
+
+ return (not_gray > frac_1 - k ? /* gray + k > 1.0 */
+ frac_0 : frac_1 - (not_gray + k));
+}
+
+/* Convert CMYK to RGB. */
+void
+color_cmyk_to_rgb(frac c, frac m, frac y, frac k, const gs_imager_state * pis,
+ frac rgb[3])
+{
+ switch (k) {
+ case frac_0:
+ rgb[0] = frac_1 - c;
+ rgb[1] = frac_1 - m;
+ rgb[2] = frac_1 - y;
+ break;
+ case frac_1:
+ rgb[0] = rgb[1] = rgb[2] = frac_0;
+ break;
+ default:
+ {
+#ifdef USE_ADOBE_CMYK_RGB
+ /* R = 1.0 - min(1.0, C + K), etc. */
+ frac not_k = frac_1 - k;
+
+ rgb[0] = (c > not_k ? frac_0 : not_k - c);
+ rgb[1] = (m > not_k ? frac_0 : not_k - m);
+ rgb[2] = (y > not_k ? frac_0 : not_k - y);
+#else
+ /* R = (1.0 - C) * (1.0 - K), etc. */
+ ulong not_k = frac_1 - k;
+
+ /* Compute not_k * (frac_1 - v) / frac_1 efficiently. */
+ ulong prod;
+
+#define deduct_black(v)\
+ (prod = (frac_1 - (v)) * not_k, frac_1_quo(prod))
+ rgb[0] = deduct_black(c);
+ rgb[1] = deduct_black(m);
+ rgb[2] = deduct_black(y);
+#undef deduct_black
+#endif
+ }
+ }
+ if_debug7('c', "[c]CMYK 0x%x,0x%x,0x%x,0x%x -> RGB 0x%x,0x%x,0x%x\n",
+ c, m, y, k, rgb[0], rgb[1], rgb[2]);
+}
diff --git a/pstoraster/gxdcconv.h b/pstoraster/gxdcconv.h
new file mode 100644
index 000000000..f38f8eeab
--- /dev/null
+++ b/pstoraster/gxdcconv.h
@@ -0,0 +1,43 @@
+/* Copyright (C) 1992, 1993, 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$ */
+/* Internal device color conversion interfaces */
+
+#ifndef gxdcconv_INCLUDED
+# define gxdcconv_INCLUDED
+
+#include "gxfrac.h"
+
+/* Color space conversion routines */
+frac color_rgb_to_gray(P4(frac r, frac g, frac b,
+ const gs_imager_state * pis));
+void color_rgb_to_cmyk(P5(frac r, frac g, frac b,
+ const gs_imager_state * pis, frac cmyk[4]));
+frac color_cmyk_to_gray(P5(frac c, frac m, frac y, frac k,
+ const gs_imager_state * pis));
+void color_cmyk_to_rgb(P6(frac c, frac m, frac y, frac k,
+ const gs_imager_state * pis, frac rgb[3]));
+
+#endif /* gxdcconv_INCLUDED */
diff --git a/pstoraster/gxdcolor.c b/pstoraster/gxdcolor.c
new file mode 100644
index 000000000..00da3d9af
--- /dev/null
+++ b/pstoraster/gxdcolor.c
@@ -0,0 +1,339 @@
+/* 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$ */
+/* Pure and null device color implementation */
+#include "gx.h"
+#include "gserrors.h"
+#include "gsbittab.h"
+#include "gxdcolor.h"
+#include "gxdevice.h"
+
+/* Define the standard device color types. */
+
+/* 'none' means the color is not defined. */
+private dev_color_proc_load(gx_dc_no_load);
+private dev_color_proc_fill_rectangle(gx_dc_no_fill_rectangle);
+private dev_color_proc_fill_masked(gx_dc_no_fill_masked);
+private dev_color_proc_equal(gx_dc_no_equal);
+const gx_device_color_type_t gx_dc_type_data_none = {
+ &st_bytes,
+ gx_dc_no_load, gx_dc_no_fill_rectangle, gx_dc_no_fill_masked,
+ gx_dc_no_equal
+};
+#undef gx_dc_type_none
+const gx_device_color_type_t *const gx_dc_type_none = &gx_dc_type_data_none;
+#define gx_dc_type_none (&gx_dc_type_data_none)
+
+/* 'null' means the color has no effect when used for drawing. */
+private dev_color_proc_load(gx_dc_null_load);
+private dev_color_proc_fill_rectangle(gx_dc_null_fill_rectangle);
+private dev_color_proc_fill_masked(gx_dc_null_fill_masked);
+private dev_color_proc_equal(gx_dc_null_equal);
+const gx_device_color_type_t gx_dc_type_data_null = {
+ &st_bytes,
+ gx_dc_null_load, gx_dc_null_fill_rectangle, gx_dc_null_fill_masked,
+ gx_dc_null_equal
+};
+#undef gx_dc_type_null
+const gx_device_color_type_t *const gx_dc_type_null = &gx_dc_type_data_null;
+#define gx_dc_type_null (&gx_dc_type_data_null)
+
+private dev_color_proc_load(gx_dc_pure_load);
+private dev_color_proc_fill_rectangle(gx_dc_pure_fill_rectangle);
+private dev_color_proc_fill_masked(gx_dc_pure_fill_masked);
+private dev_color_proc_equal(gx_dc_pure_equal);
+const gx_device_color_type_t gx_dc_type_data_pure = {
+ &st_bytes,
+ gx_dc_pure_load, gx_dc_pure_fill_rectangle, gx_dc_pure_fill_masked,
+ gx_dc_pure_equal
+};
+#undef gx_dc_type_pure
+const gx_device_color_type_t *const gx_dc_type_pure = &gx_dc_type_data_pure;
+#define gx_dc_type_pure (&gx_dc_type_data_pure)
+
+/*
+ * Get the black and white pixel values of a device. The documentation for
+ * the driver API says that map_rgb_color will do the right thing on CMYK
+ * devices. Unfortunately, that isn't true at present, and fixing it is too
+ * much work.
+ */
+gx_color_index
+gx_device_black(gx_device *dev)
+{
+ return
+ (dev->color_info.num_components == 4 ?
+ (*dev_proc(dev, map_cmyk_color))
+ (dev, (gx_color_index)0, (gx_color_index)0, (gx_color_index)0,
+ gx_max_color_value) :
+ (*dev_proc(dev, map_rgb_color))
+ (dev, (gx_color_index)0, (gx_color_index)0, (gx_color_index)0));
+}
+gx_color_index
+gx_device_white(gx_device *dev)
+{
+ return
+ (dev->color_info.num_components == 4 ?
+ (*dev_proc(dev, map_cmyk_color))
+ (dev, (gx_color_index)0, (gx_color_index)0, (gx_color_index)0,
+ (gx_color_index)0) :
+ (*dev_proc(dev, map_rgb_color))
+ (dev, gx_max_color_value, gx_max_color_value, gx_max_color_value));
+}
+
+/* Set a null RasterOp source. */
+private const gx_rop_source_t gx_rop_no_source_0 = {gx_rop_no_source_body(0)};
+void
+gx_set_rop_no_source(const gx_rop_source_t **psource,
+ gx_rop_source_t *pno_source, gx_device *dev)
+{
+ gx_color_index black = gx_device_black(dev);
+
+ if ( black == 0 )
+ *psource = &gx_rop_no_source_0;
+ else {
+ *pno_source = gx_rop_no_source_0;
+ gx_rop_source_set_color(pno_source, black);
+ *psource = pno_source;
+ }
+}
+
+/* ------ Undefined color ------ */
+
+private int
+gx_dc_no_load(gx_device_color *pdevc, const gs_imager_state *ignore_pis,
+ gx_device *ignore_dev, gs_color_select_t ignore_select)
+{
+ return 0;
+}
+
+private int
+gx_dc_no_fill_rectangle(const gx_device_color *pdevc, int x, int y,
+ int w, int h, gx_device *dev,
+ gs_logical_operation_t lop,
+ const gx_rop_source_t *source)
+{
+ gx_device_color filler;
+
+ if (w <= 0 || h <= 0)
+ return 0;
+ if (lop_uses_T(lop))
+ return_error(gs_error_Fatal);
+ color_set_pure(&filler, 0); /* any valid value for dev will do */
+ return gx_dc_pure_fill_rectangle(&filler, x, y, w, h, dev, lop, source);
+}
+
+private int
+gx_dc_no_fill_masked(const gx_device_color *pdevc, const byte *data,
+ int data_x, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h, gx_device *dev,
+ gs_logical_operation_t lop, bool invert)
+{
+ if (w <= 0 || h <= 0)
+ return 0;
+ return_error(gs_error_Fatal);
+}
+
+private bool
+gx_dc_no_equal(const gx_device_color *pdevc1, const gx_device_color *pdevc2)
+{
+ return false;
+}
+
+/* ------ Null color ------ */
+
+private int
+gx_dc_null_load(gx_device_color *pdevc, const gs_imager_state *ignore_pis,
+ gx_device *ignore_dev, gs_color_select_t ignore_select)
+{
+ return 0;
+}
+
+private int
+gx_dc_null_fill_rectangle(const gx_device_color * pdevc, int x, int y,
+ int w, int h, gx_device * dev,
+ gs_logical_operation_t lop,
+ const gx_rop_source_t * source)
+{
+ return 0;
+}
+
+private int
+gx_dc_null_fill_masked(const gx_device_color * pdevc, const byte * data,
+ int data_x, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h, gx_device * dev,
+ gs_logical_operation_t lop, bool invert)
+{
+ return 0;
+}
+
+private bool
+gx_dc_null_equal(const gx_device_color * pdevc1, const gx_device_color * pdevc2)
+{
+ return pdevc2->type == pdevc1->type;
+}
+
+/* ------ Pure color ------ */
+
+private int
+gx_dc_pure_load(gx_device_color * pdevc, const gs_imager_state * ignore_pis,
+ gx_device * ignore_dev, gs_color_select_t ignore_select)
+{
+ return 0;
+}
+
+/* Fill a rectangle with a pure color. */
+/* Note that we treat this as "texture" for RasterOp. */
+private int
+gx_dc_pure_fill_rectangle(const gx_device_color * pdevc, int x, int y,
+ int w, int h, gx_device * dev, gs_logical_operation_t lop,
+ const gx_rop_source_t * source)
+{
+ if (source == NULL && lop_no_S_is_T(lop))
+ return (*dev_proc(dev, fill_rectangle)) (dev, x, y, w, h,
+ pdevc->colors.pure);
+ {
+ gx_color_index colors[2];
+ gx_rop_source_t no_source;
+
+ colors[0] = colors[1] = pdevc->colors.pure;
+ if (source == NULL)
+ set_rop_no_source(source, no_source, dev);
+ return (*dev_proc(dev, strip_copy_rop))
+ (dev, source->sdata, source->sourcex, source->sraster,
+ source->id, (source->use_scolors ? source->scolors : NULL),
+ NULL /*arbitrary */ , colors, x, y, w, h, 0, 0, lop);
+ }
+}
+
+/* Fill a mask with a pure color. */
+/* Note that there is no source in this case: the mask is the source. */
+private int
+gx_dc_pure_fill_masked(const gx_device_color * pdevc, const byte * data,
+ int data_x, int raster, gx_bitmap_id id, int x, int y, int w, int h,
+ gx_device * dev, gs_logical_operation_t lop, bool invert)
+{
+ if (lop_no_S_is_T(lop)) {
+ gx_color_index color0, color1;
+
+ if (invert)
+ color0 = pdevc->colors.pure, color1 = gx_no_color_index;
+ else
+ color1 = pdevc->colors.pure, color0 = gx_no_color_index;
+ return (*dev_proc(dev, copy_mono))
+ (dev, data, data_x, raster, id, x, y, w, h, color0, color1);
+ } {
+ gx_color_index scolors[2];
+ gx_color_index tcolors[2];
+
+ scolors[0] = gx_device_black(dev);
+ scolors[1] = gx_device_white(dev);
+ tcolors[0] = tcolors[1] = pdevc->colors.pure;
+ return (*dev_proc(dev, strip_copy_rop))
+ (dev, data, data_x, raster, id, scolors,
+ NULL, tcolors, x, y, w, h, 0, 0,
+ (invert ? rop3_invert_S(lop) : lop) | lop_S_transparent);
+ }
+}
+
+private bool
+gx_dc_pure_equal(const gx_device_color * pdevc1, const gx_device_color * pdevc2)
+{
+ return pdevc2->type == pdevc1->type &&
+ gx_dc_pure_color(pdevc1) == gx_dc_pure_color(pdevc2);
+}
+
+/* ------ Default implementations ------ */
+
+/* Fill a mask with a color by parsing the mask into rectangles. */
+int
+gx_dc_default_fill_masked(const gx_device_color * pdevc, const byte * data,
+ int data_x, int raster, gx_bitmap_id id, int x, int y, int w, int h,
+ gx_device * dev, gs_logical_operation_t lop, bool invert)
+{
+ int lbit = data_x & 7;
+ const byte *row = data + (data_x >> 3);
+ uint one = (invert ? 0 : 0xff);
+ uint zero = one ^ 0xff;
+ int iy;
+
+ for (iy = 0; iy < h; ++iy, row += raster) {
+ const byte *p = row;
+ int bit = lbit;
+ int left = w;
+ int l0;
+
+ while (left) {
+ int run, code;
+
+ /* Skip a run of zeros. */
+ run = byte_bit_run_length[bit][*p ^ one];
+ if (run) {
+ if (run < 8) {
+ if (run >= left)
+ break; /* end of row while skipping */
+ bit += run, left -= run;
+ } else if ((run -= 8) >= left)
+ break; /* end of row while skipping */
+ else {
+ left -= run;
+ ++p;
+ while (left > 8 && *p == zero)
+ left -= 8, ++p;
+ run = byte_bit_run_length_0[*p ^ one];
+ if (run >= left) /* run < 8 unless very last byte */
+ break; /* end of row while skipping */
+ else
+ bit = run & 7, left -= run;
+ }
+ }
+ l0 = left;
+ /* Scan a run of ones, and then paint it. */
+ run = byte_bit_run_length[bit][*p ^ zero];
+ if (run < 8) {
+ if (run >= left)
+ left = 0;
+ else
+ bit += run, left -= run;
+ } else if ((run -= 8) >= left)
+ left = 0;
+ else {
+ left -= run;
+ ++p;
+ while (left > 8 && *p == one)
+ left -= 8, ++p;
+ run = byte_bit_run_length_0[*p ^ zero];
+ if (run >= left) /* run < 8 unless very last byte */
+ left = 0;
+ else
+ bit = run & 7, left -= run;
+ }
+ code = gx_device_color_fill_rectangle(pdevc,
+ x + w - l0, y + iy, l0 - left, 1, dev, lop, NULL);
+ if (code < 0)
+ return code;
+ }
+ }
+ return 0;
+}
diff --git a/pstoraster/gxdcolor.h b/pstoraster/gxdcolor.h
new file mode 100644
index 000000000..015652e24
--- /dev/null
+++ b/pstoraster/gxdcolor.h
@@ -0,0 +1,199 @@
+/* Copyright (C) 1993, 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$ */
+/* Device color representation for Ghostscript */
+
+#ifndef gxdcolor_INCLUDED
+# define gxdcolor_INCLUDED
+
+#include "gscsel.h"
+#include "gsdcolor.h"
+#include "gsropt.h"
+#include "gsstruct.h" /* for extern_st, GC procs */
+
+/* Define opaque types. */
+
+#ifndef gx_device_DEFINED
+# define gx_device_DEFINED
+typedef struct gx_device_s gx_device;
+
+#endif
+
+/*
+ * Define a source structure for RasterOp.
+ */
+typedef struct gx_rop_source_s {
+ const byte *sdata;
+ int sourcex;
+ uint sraster;
+ gx_bitmap_id id;
+ gx_color_index scolors[2];
+ bool use_scolors;
+} gx_rop_source_t;
+
+/*
+ * Note that the following definition depends on the gx_color_index for
+ * black, which may not be 0. Clients must check this and construct
+ * a different null source if necessary.
+ */
+#define gx_rop_no_source_body(black_pixel)\
+ NULL, 0, 0, gx_no_bitmap_id, {black_pixel, black_pixel}, true
+#define gx_rop_source_set_color(prs, pixel)\
+ ((prs)->scolors[0] = (prs)->scolors[1] = (pixel))
+void gx_set_rop_no_source(P3(const gx_rop_source_t **psource,
+ gx_rop_source_t *pno_source, gx_device *dev));
+#define set_rop_no_source(source, no_source, dev)\
+ gx_set_rop_no_source(&(source), &(no_source), dev)
+
+/*
+ * Define the device color structure per se.
+ */
+
+/* The typedef is in gsdcolor.h. */
+/*typedef struct gx_device_color_type_s gx_device_color_type_t; */
+struct gx_device_color_type_s {
+
+ /*
+ * In order to simplify memory management, we use a union, but since
+ * different variants may have different pointer tracing procedures,
+ * we have to define a separate GC structure type for each variant.
+ */
+
+ gs_memory_type_ptr_t stype;
+
+ /*
+ * If necessary and possible, load the halftone or Pattern cache
+ * with the rendering of this color.
+ */
+
+#define dev_color_proc_load(proc)\
+ int proc(P4(gx_device_color *pdevc, const gs_imager_state *pis,\
+ gx_device *dev, gs_color_select_t select))
+ dev_color_proc_load((*load));
+
+ /*
+ * Fill a rectangle with the color.
+ * We pass the device separately so that pattern fills can
+ * substitute a tiled mask clipping device.
+ */
+
+#define dev_color_proc_fill_rectangle(proc)\
+ int proc(P8(const gx_device_color *pdevc, int x, int y, int w, int h,\
+ gx_device *dev, gs_logical_operation_t lop, const gx_rop_source_t *source))
+ dev_color_proc_fill_rectangle((*fill_rectangle));
+
+ /*
+ * Fill a masked region with a color. Nearly all device colors
+ * use the default implementation, which simply parses the mask
+ * into rectangles and calls fill_rectangle. Note that in this
+ * case there is no RasterOp source: the mask is the source.
+ */
+
+#define dev_color_proc_fill_masked(proc)\
+ int proc(P12(const gx_device_color *pdevc, const byte *data, int data_x,\
+ int raster, gx_bitmap_id id, int x, int y, int w, int h,\
+ gx_device *dev, gs_logical_operation_t lop, bool invert))
+ dev_color_proc_fill_masked((*fill_masked));
+
+ /*
+ * Test whether this color is equal to another.
+ */
+
+#define dev_color_proc_equal(proc)\
+ bool proc(P2(const gx_device_color *pdevc1, const gx_device_color *pdevc2))
+ dev_color_proc_equal((*equal));
+
+};
+
+/* Define the default implementation of fill_masked. */
+dev_color_proc_fill_masked(gx_dc_default_fill_masked);
+
+extern_st(st_device_color);
+/* public_st_device_color() is defined in gsdcolor.h */
+
+/* Define the standard device color types. */
+/* See gsdcolor.h for details. */
+extern const gx_device_color_type_t
+#define gx_dc_type_none (&gx_dc_type_data_none)
+ gx_dc_type_data_none, /* gxdcolor.c */
+#define gx_dc_type_null (&gx_dc_type_data_null)
+ gx_dc_type_data_null, /* gxdcolor.c */
+#define gx_dc_type_pure (&gx_dc_type_data_pure)
+ gx_dc_type_data_pure, /* gxdcolor.c */
+/*#define gx_dc_type_pattern (&gx_dc_type_data_pattern) */
+ /*gx_dc_type_data_pattern, *//* gspcolor.c */
+#define gx_dc_type_ht_binary (&gx_dc_type_data_ht_binary)
+ gx_dc_type_data_ht_binary, /* gxht.c */
+#define gx_dc_type_ht_colored (&gx_dc_type_data_ht_colored)
+ gx_dc_type_data_ht_colored; /* gxcht.c */
+
+#define gs_color_writes_pure(pgs)\
+ color_writes_pure((pgs)->dev_color, (pgs)->log_op)
+
+/* Set up device color 1 for writing into a mask cache */
+/* (e.g., the character cache). */
+void gx_set_device_color_1(P1(gs_state * pgs));
+
+/* Get the black and white pixel values of a device. */
+gx_color_index gx_device_black(P1(gx_device *dev));
+gx_color_index gx_device_white(P1(gx_device *dev));
+
+/* Remap the color if necessary. */
+int gx_remap_color(P1(gs_state *));
+
+#define gx_set_dev_color(pgs)\
+ if ( !color_is_set((pgs)->dev_color) )\
+ { int code_dc = gx_remap_color(pgs);\
+ if ( code_dc != 0 ) return code_dc;\
+ }
+
+/* Indicate that the device color needs remapping. */
+#define gx_unset_dev_color(pgs)\
+ color_unset((pgs)->dev_color)
+
+/* Load the halftone cache in preparation for drawing. */
+#define gx_color_load_select(pdevc, pis, dev, select)\
+ (*(pdevc)->type->load)(pdevc, pis, dev, select)
+#define gx_color_load(pdevc, pis, dev)\
+ gx_color_load_select(pdevc, pis, dev, gs_color_select_texture)
+#define gs_state_color_load(pgs)\
+ gx_color_load((pgs)->dev_color, (const gs_imager_state *)(pgs),\
+ (pgs)->device)
+
+/* Fill a rectangle with a color. */
+#define gx_device_color_fill_rectangle(pdevc, x, y, w, h, dev, lop, source)\
+ (*(pdevc)->type->fill_rectangle)(pdevc, x, y, w, h, dev, lop, source)
+#define gx_fill_rectangle_device_rop(x, y, w, h, pdevc, dev, lop)\
+ gx_device_color_fill_rectangle(pdevc, x, y, w, h, dev, lop, NULL)
+#define gx_fill_rectangle_rop(x, y, w, h, pdevc, lop, pgs)\
+ gx_fill_rectangle_device_rop(x, y, w, h, pdevc, (pgs)->device, lop)
+#define gx_fill_rectangle(x, y, w, h, pdevc, pgs)\
+ gx_fill_rectangle_rop(x, y, w, h, pdevc, (pgs)->log_op, pgs)
+
+/* Test device colors for equality. */
+#define gx_device_color_equal(pdevc1, pdevc2)\
+ (((pdevc1)->type->equal)(pdevc1, pdevc2))
+
+#endif /* gxdcolor_INCLUDED */
diff --git a/pstoraster/gxdda.h b/pstoraster/gxdda.h
new file mode 100644
index 000000000..e0fe391e1
--- /dev/null
+++ b/pstoraster/gxdda.h
@@ -0,0 +1,158 @@
+/* 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$ */
+/* Requires gxfixed.h */
+
+#ifndef gxdda_INCLUDED
+# define gxdda_INCLUDED
+
+/*
+ * We use the familiar Bresenham DDA algorithm for several purposes:
+ * - tracking the edges when filling trapezoids;
+ * - tracking the current pixel corner coordinates when rasterizing
+ * skewed or rotated images;
+ * - converting curves to sequences of lines (this is a 3rd-order
+ * DDA, the others are 1st-order);
+ * - perhaps someday for drawing single-pixel lines.
+ * In the case of trapezoids, lines, and curves, we need to use
+ * the DDA to find the integer X values at integer+0.5 values of Y;
+ * in the case of images, we use DDAs to compute the (fixed)
+ * X and Y values at (integer) source pixel corners.
+ *
+ * The purpose of the DDA is to compute the exact values Q(i) = floor(i*D/N)
+ * for increasing integers i, 0 <= i <= N. D is considered to be an
+ * integer, although it may actually be a fixed. For the algorithm,
+ * we maintain i*D/N as Q + (N-R)/N where Q and R are integers, 0 < R <= N,
+ * with the following auxiliary values:
+ * dQ = floor(D/N)
+ * dR = D mod N (0 <= dR < N)
+ * NdR = N - dR
+ * Then at each iteration we do:
+ * Q += dQ;
+ * if ( R > dR ) R -= dR; else ++Q, R += NdR;
+ * These formulas work regardless of the sign of D, and never let R go
+ * out of range.
+ */
+/* In the following structure definitions, ntype must be an unsigned type. */
+#define dda_state_struct(sname, dtype, ntype)\
+ struct sname { dtype Q; ntype R; }
+#define dda_step_struct(sname, dtype, ntype)\
+ struct sname { dtype dQ; ntype dR, NdR; }
+/* DDA with fixed Q and (unsigned) integer N */
+typedef
+dda_state_struct(_a, fixed, uint) gx_dda_state_fixed;
+ typedef dda_step_struct(_e, fixed, uint) gx_dda_step_fixed;
+ typedef struct gx_dda_fixed_s {
+ gx_dda_state_fixed state;
+ gx_dda_step_fixed step;
+ } gx_dda_fixed;
+/*
+ * Define a pair of DDAs for iterating along an arbitrary line.
+ */
+ typedef struct gx_dda_fixed_point_s {
+ gx_dda_fixed x, y;
+ } gx_dda_fixed_point;
+/*
+ * Initialize a DDA. The sign test is needed only because C doesn't
+ * provide reliable definitions of / and % for integers (!!!).
+ */
+#define dda_init_state(dstate, init, N)\
+ (dstate).Q = (init), (dstate).R = (N)
+#define dda_init_step(dstep, D, N)\
+ if ( (N) == 0 )\
+ (dstep).dQ = 0, (dstep).dR = 0;\
+ else if ( (D) < 0 )\
+ { (dstep).dQ = -(-(D) / (N));\
+ if ( ((dstep).dR = -(D) % (N)) != 0 )\
+ --(dstep).dQ, (dstep).dR = (N) - (dstep).dR;\
+ }\
+ else\
+ { (dstep).dQ = (D) / (N); (dstep).dR = (D) % (N); }\
+ (dstep).NdR = (N) - (dstep).dR
+#define dda_init(dda, init, D, N)\
+ dda_init_state((dda).state, init, N);\
+ dda_init_step((dda).step, D, N)
+/*
+ * Compute the sum of two DDA steps with the same D and N.
+ * Note that since dR + NdR = N, this quantity must be the same in both
+ * fromstep and tostep.
+ */
+#define dda_step_add(tostep, fromstep)\
+ (tostep).dQ +=\
+ ((tostep).dR < (fromstep).NdR ?\
+ ((tostep).dR += (fromstep).dR, (tostep).NdR -= (fromstep).dR,\
+ (fromstep).dQ) :\
+ ((tostep).dR -= (fromstep).NdR, (tostep).NdR += (fromstep).NdR,\
+ (fromstep).dQ + 1))
+/*
+ * Return the current value in a DDA.
+ */
+#define dda_state_current(dstate) (dstate).Q
+#define dda_current(dda) dda_state_current((dda).state)
+#define dda_current_fixed2int(dda)\
+ fixed2int_var(dda_state_current((dda).state))
+/*
+ * Increment a DDA to the next point.
+ * Returns the updated current value.
+ */
+#define dda_state_next(dstate, dstep)\
+ (dstate).Q +=\
+ ((dstate).R > (dstep).dR ?\
+ ((dstate).R -= (dstep).dR, (dstep).dQ) :\
+ ((dstate).R += (dstep).NdR, (dstep).dQ + 1))
+#define dda_next(dda) dda_state_next((dda).state, (dda).step)
+/*
+ * Back up a DDA to the previous point.
+ * Returns the updated current value.
+ */
+#define dda_state_previous(dstate, dstep)\
+ (dstate).Q -=\
+ ((dstate).R <= (dstep).NdR ?\
+ ((dstate).R += (dstep).dR, (dstep).dQ) :\
+ ((dstate).R -= (dstep).NdR, (dstep).dQ + 1))
+#define dda_previous(dda) dda_state_previous((dda).state, (dda).step)
+/*
+ * Advance a DDA by an arbitrary number of steps.
+ * This implementation is very inefficient; we'll improve it if needed.
+ */
+#define dda_state_advance(dstate, dstep, nsteps)\
+ BEGIN\
+ uint n_ = (nsteps);\
+ (dstate).Q += (dstep).dQ * (nsteps);\
+ while ( n_-- )\
+ if ( (dstate).R > (dstep).dR ) (dstate).R -= (dstep).dR;\
+ else (dstate).R += (dstep).NdR, (dstate).Q++;\
+ END
+#define dda_advance(dda, nsteps)\
+ dda_state_advance((dda).state, (dda).step, nsteps)
+/*
+ * Translate the position of a DDA by a given amount.
+ */
+#define dda_state_translate(dstate, delta)\
+ ((dstate).Q += (delta))
+#define dda_translate(dda, delta)\
+ dda_state_translate((dda).state, delta)
+
+#endif /* gxdda_INCLUDED */
diff --git a/pstoraster/gxdevcli.h b/pstoraster/gxdevcli.h
new file mode 100644
index 000000000..53a4eefc2
--- /dev/null
+++ b/pstoraster/gxdevcli.h
@@ -0,0 +1,877 @@
+/* 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$ */
+/* Definitions for device clients */
+
+#ifndef gxdevcli_INCLUDED
+# define gxdevcli_INCLUDED
+
+#include "std.h" /* for FILE */
+#include "gscompt.h"
+#include "gsdcolor.h"
+#include "gsmatrix.h"
+#include "gsiparam.h" /* requires gsmatrix.h */
+#include "gsrefct.h"
+#include "gsropt.h"
+#include "gsstruct.h"
+#include "gsxfont.h"
+#include "gxbitmap.h"
+#include "gxcindex.h"
+#include "gxcvalue.h"
+#include "gxfixed.h"
+#include "gxtext.h"
+
+/* See Drivers.htm for documentation of the driver interface. */
+
+#ifndef gx_device_DEFINED
+# define gx_device_DEFINED
+typedef struct gx_device_s gx_device;
+
+#endif
+
+/* ---------------- Auxiliary types and structures ---------------- */
+
+/* We need at least an abstract type for a graphics state, */
+/* which is passed to the page device procedures. */
+#ifndef gs_state_DEFINED
+# define gs_state_DEFINED
+typedef struct gs_state_s gs_state;
+
+#endif
+
+/* We need abstract types for paths and fill/stroke parameters, */
+/* for the path-oriented device procedures. */
+#ifndef gx_path_DEFINED
+# define gx_path_DEFINED
+typedef struct gx_path_s gx_path;
+
+#endif
+#ifndef gx_clip_path_DEFINED
+# define gx_clip_path_DEFINED
+typedef struct gx_clip_path_s gx_clip_path;
+
+#endif
+#ifndef gx_fill_params_DEFINED
+# define gx_fill_params_DEFINED
+typedef struct gx_fill_params_s gx_fill_params;
+
+#endif
+#ifndef gx_stroke_params_DEFINED
+# define gx_stroke_params_DEFINED
+typedef struct gx_stroke_params_s gx_stroke_params;
+
+#endif
+#ifndef gs_imager_state_DEFINED
+# define gs_imager_state_DEFINED
+typedef struct gs_imager_state_s gs_imager_state;
+
+#endif
+/* We need an abstract type for the image enumeration state, */
+/* for begin[_typed]_image. */
+#ifndef gx_image_enum_common_t_DEFINED
+# define gx_image_enum_common_t_DEFINED
+typedef struct gx_image_enum_common_s gx_image_enum_common_t;
+
+#endif
+
+/* Define the type for colors passed to the higher-level procedures. */
+typedef gx_device_color gx_drawing_color;
+
+/* Define a type for telling get_alpha_bits what kind of object */
+/* is being rendered. */
+typedef enum {
+ go_text,
+ go_graphics
+} graphics_object_type;
+
+/* Define an edge of a trapezoid. Requirement: end.y >= start.y. */
+typedef struct gs_fixed_edge_s {
+ gs_fixed_point start;
+ gs_fixed_point end;
+} gs_fixed_edge;
+
+/* Define the parameters passed to get_bits_rectangle. */
+#ifndef gs_get_bits_params_DEFINED
+# define gs_get_bits_params_DEFINED
+typedef struct gs_get_bits_params_s gs_get_bits_params_t;
+#endif
+
+/* Define the structure for device color capabilities. */
+typedef struct gx_device_color_info_s {
+ int num_components; /* doesn't include alpha: */
+ /* 0 = alpha only, 1 = gray only, */
+ /* 3 = RGB, 4 = CMYK */
+ int depth; /* # of bits per pixel */
+ gx_color_value max_gray; /* # of distinct gray levels -1 */
+ gx_color_value max_color; /* # of distinct color levels -1 */
+ /* (only relevant if num_comp. > 1) */
+ gx_color_value dither_grays; /* size of gray ramp for dithering */
+ gx_color_value dither_colors; /* size of color cube ditto */
+ /* (only relevant if num_comp. > 1) */
+} gx_device_color_info;
+
+#define dci_values(nc,depth,mg,mc,dg,dc) { nc, depth, mg, mc, dg, dc }
+#define dci_std_color(color_bits)\
+ dci_values(\
+ (color_bits == 32 ? 4 : color_bits > 1 ? 3 : 1),\
+ ((color_bits > 1) & (color_bits < 8) ? 8 : color_bits),\
+ (color_bits >= 8 ? 255 : 1),\
+ (color_bits >= 8 ? 255 : color_bits > 1 ? 1 : 0),\
+ (color_bits >= 8 ? 5 : 2),\
+ (color_bits >= 8 ? 5 : color_bits > 1 ? 2 : 0)\
+ )
+#define dci_black_and_white dci_std_color(1)
+#define dci_black_and_white_() dci_black_and_white
+#define dci_color(depth,maxv,dither)\
+ dci_values(3, depth, maxv, maxv, dither, dither)
+#define gx_device_has_color(dev) ((dev)->color_info.num_components > 1)
+
+/* Structure for device procedures. */
+typedef struct gx_device_procs_s gx_device_procs;
+
+/* Structure for page device procedures. */
+/* Note that these take the graphics state as a parameter. */
+typedef struct gx_page_device_procs_s {
+
+#define dev_page_proc_install(proc)\
+ int proc(P2(gx_device *dev, gs_state *pgs))
+ dev_page_proc_install((*install));
+
+#define dev_page_proc_begin_page(proc)\
+ int proc(P2(gx_device *dev, gs_state *pgs))
+ dev_page_proc_begin_page((*begin_page));
+
+#define dev_page_proc_end_page(proc)\
+ int proc(P3(gx_device *dev, int reason, gs_state *pgs))
+ dev_page_proc_end_page((*end_page));
+
+} gx_page_device_procs;
+
+/* Default procedures */
+dev_page_proc_install(gx_default_install);
+dev_page_proc_begin_page(gx_default_begin_page);
+dev_page_proc_end_page(gx_default_end_page);
+
+/* ---------------- Device structure ---------------- */
+
+/*
+ * Define the generic device structure. The device procedures can
+ * have two different configurations:
+ *
+ * - Statically initialized devices predating release 2.8.1
+ * set the static_procs pointer to point to a separate procedure record,
+ * and do not initialize procs.
+ *
+ * - Statically initialized devices starting with release 2.8.1,
+ * and all dynamically created device instances,
+ * set the static_procs pointer to 0, and initialize procs.
+ *
+ * The gx_device_set_procs procedure converts the first of these to
+ * the second, which is what all client code starting in 2.8.1 expects
+ * (using the procs record, not the static_procs pointer, to call the
+ * driver procedures).
+ *
+ * The choice of the name Margins (rather than, say, HWOffset), and the
+ * specification in terms of a default device resolution rather than
+ * 1/72" units, are due to Adobe.
+ *
+ * ****** NOTE: If you define any subclasses of gx_device, you *must* define
+ * ****** the finalization procedure as gx_device_finalize. Finalization
+ * ****** procedures are not automatically inherited.
+ */
+#define gx_device_common\
+ int params_size; /* OBSOLETE if stype != 0: */\
+ /* size of this structure */\
+ const gx_device_procs *static_procs; /* OBSOLETE */\
+ /* pointer to procs */\
+ const char *dname; /* the device name */\
+ gs_memory_t *memory; /* (0 iff static prototype) */\
+ gs_memory_type_ptr_t stype; /* memory manager structure type, */\
+ /* 0 iff static prototype */\
+ rc_header rc; /* reference count from gstates, */\
+ /* +1 if not internal device */\
+ bool is_open; /* true if device has been opened */\
+ int max_fill_band; /* limit on band size for fill, */\
+ /* must be 0 or a power of 2 */\
+ /* (see gdevabuf.c for more info) */\
+ gx_device_color_info color_info; /* color information */\
+ int width; /* width in pixels */\
+ int height; /* height in pixels */\
+ float PageSize[2]; /* media dimensions in points */\
+ float ImagingBBox[4]; /* imageable region in points */\
+ bool ImagingBBox_set;\
+ float HWResolution[2]; /* resolution, dots per inch */\
+ float MarginsHWResolution[2]; /* resolution for Margins */\
+ float Margins[2]; /* offset of physical page corner */\
+ /* from device coordinate (0,0), */\
+ /* in units given by MarginsHWResolution */\
+ float HWMargins[4]; /* margins around imageable area, */\
+ /* in default user units ("points") */\
+ long PageCount; /* number of pages written */\
+ long ShowpageCount; /* number of calls on showpage */\
+ int NumCopies;\
+ bool NumCopies_set;\
+ bool IgnoreNumCopies; /* if true, force num_copies = 1 */\
+ gx_page_device_procs page_procs; /* must be last */\
+ /* end of std_device_body */\
+ gx_device_procs procs /* object procedures */
+#define x_pixels_per_inch HWResolution[0]
+#define y_pixels_per_inch HWResolution[1]
+#define offset_margin_values(x, y, left, bot, right, top)\
+ {x, y}, {left, bot, right, top}
+#define margin_values(left, bot, right, top)\
+ offset_margin_values(0, 0, left, bot, right, top)
+#define no_margins margin_values(0, 0, 0, 0)
+#define no_margins_() no_margins
+/* Define macros that give the page offset ("Margins") in inches. */
+#define dev_x_offset(dev) ((dev)->Margins[0] / (dev)->MarginsHWResolution[0])
+#define dev_y_offset(dev) ((dev)->Margins[1] / (dev)->MarginsHWResolution[1])
+#define dev_y_offset_points(dev) (dev_y_offset(dev) * 72.0)
+/* Note that left/right/top/bottom are defined relative to */
+/* the physical paper, not the coordinate system. */
+/* For backward compatibility, we define macros that give */
+/* the margins in inches. */
+#define dev_l_margin(dev) ((dev)->HWMargins[0] / 72.0)
+#define dev_b_margin(dev) ((dev)->HWMargins[1] / 72.0)
+#define dev_b_margin_points(dev) ((dev)->HWMargins[1])
+#define dev_r_margin(dev) ((dev)->HWMargins[2] / 72.0)
+#define dev_t_margin(dev) ((dev)->HWMargins[3] / 72.0)
+#define dev_t_margin_points(dev) ((dev)->HWMargins[3])
+/* The extra () are to prevent premature expansion. */
+#define open_init_closed() 0 /*false*/, 0 /* max_fill_band */
+#define open_init_open() 1 /*true*/, 0 /* max_fill_band */
+/* Accessors for device procedures */
+#define dev_proc(dev, p) ((dev)->procs.p)
+#define set_dev_proc(dev, p, proc) ((dev)->procs.p = (proc))
+#define fill_dev_proc(dev, p, dproc)\
+ if ( dev_proc(dev, p) == 0 ) set_dev_proc(dev, p, dproc)
+#define assign_dev_procs(todev, fromdev)\
+ ((todev)->procs = (fromdev)->procs)
+
+/* ---------------- Device procedures ---------------- */
+
+/* Define an opaque type for parameter lists. */
+#ifndef gs_param_list_DEFINED
+# define gs_param_list_DEFINED
+typedef struct gs_param_list_s gs_param_list;
+
+#endif
+
+/*
+ * Definition of device procedures.
+ * Note that the gx_device * argument is not declared const,
+ * because many drivers maintain dynamic state in the device structure.
+ * Note also that the structure is defined as a template, so that
+ * we can instantiate it with device subclasses.
+ * Because C doesn't have real templates, we must do this with macros.
+ */
+
+/* Define macros for declaring device procedures. */
+
+#define dev_t_proc_open_device(proc, dev_t)\
+ int proc(P1(dev_t *dev))
+#define dev_proc_open_device(proc)\
+ dev_t_proc_open_device(proc, gx_device)
+
+#define dev_t_proc_get_initial_matrix(proc, dev_t)\
+ void proc(P2(dev_t *dev, gs_matrix *pmat))
+#define dev_proc_get_initial_matrix(proc)\
+ dev_t_proc_get_initial_matrix(proc, gx_device)
+
+#define dev_t_proc_sync_output(proc, dev_t)\
+ int proc(P1(dev_t *dev))
+#define dev_proc_sync_output(proc)\
+ dev_t_proc_sync_output(proc, gx_device)
+
+#define dev_t_proc_output_page(proc, dev_t)\
+ int proc(P3(dev_t *dev, int num_copies, int flush))
+#define dev_proc_output_page(proc)\
+ dev_t_proc_output_page(proc, gx_device)
+
+#define dev_t_proc_close_device(proc, dev_t)\
+ int proc(P1(dev_t *dev))
+#define dev_proc_close_device(proc)\
+ dev_t_proc_close_device(proc, gx_device)
+
+#define dev_t_proc_map_rgb_color(proc, dev_t)\
+ gx_color_index proc(P4(dev_t *dev,\
+ gx_color_value red, gx_color_value green, gx_color_value blue))
+#define dev_proc_map_rgb_color(proc)\
+ dev_t_proc_map_rgb_color(proc, gx_device)
+
+#define dev_t_proc_map_color_rgb(proc, dev_t)\
+ int proc(P3(dev_t *dev,\
+ gx_color_index color, gx_color_value rgb[3]))
+#define dev_proc_map_color_rgb(proc)\
+ dev_t_proc_map_color_rgb(proc, gx_device)
+
+#define dev_t_proc_fill_rectangle(proc, dev_t)\
+ int proc(P6(dev_t *dev,\
+ int x, int y, int width, int height, gx_color_index color))
+#define dev_proc_fill_rectangle(proc)\
+ dev_t_proc_fill_rectangle(proc, gx_device)
+
+#define dev_t_proc_tile_rectangle(proc, dev_t)\
+ int proc(P10(dev_t *dev,\
+ const gx_tile_bitmap *tile, int x, int y, int width, int height,\
+ gx_color_index color0, gx_color_index color1,\
+ int phase_x, int phase_y))
+#define dev_proc_tile_rectangle(proc)\
+ dev_t_proc_tile_rectangle(proc, gx_device)
+
+#define dev_t_proc_copy_mono(proc, dev_t)\
+ int proc(P11(dev_t *dev,\
+ const byte *data, int data_x, int raster, gx_bitmap_id id,\
+ int x, int y, int width, int height,\
+ gx_color_index color0, gx_color_index color1))
+#define dev_proc_copy_mono(proc)\
+ dev_t_proc_copy_mono(proc, gx_device)
+
+#define dev_t_proc_copy_color(proc, dev_t)\
+ int proc(P9(dev_t *dev,\
+ const byte *data, int data_x, int raster, gx_bitmap_id id,\
+ int x, int y, int width, int height))
+#define dev_proc_copy_color(proc)\
+ dev_t_proc_copy_color(proc, gx_device)
+
+ /* OBSOLETED in release 3.66 */
+
+#define dev_t_proc_draw_line(proc, dev_t)\
+ int proc(P6(dev_t *dev,\
+ int x0, int y0, int x1, int y1, gx_color_index color))
+#define dev_proc_draw_line(proc)\
+ dev_t_proc_draw_line(proc, gx_device)
+
+ /* Added in release 2.4 */
+
+#define dev_t_proc_get_bits(proc, dev_t)\
+ int proc(P4(dev_t *dev,\
+ int y, byte *data, byte **actual_data))
+#define dev_proc_get_bits(proc)\
+ dev_t_proc_get_bits(proc, gx_device)
+
+ /* Added in release 2.4, changed in 2.8, */
+ /* renamed in 2.9.6 */
+
+#define dev_t_proc_get_params(proc, dev_t)\
+ int proc(P2(dev_t *dev, gs_param_list *plist))
+#define dev_proc_get_params(proc)\
+ dev_t_proc_get_params(proc, gx_device)
+
+#define dev_t_proc_put_params(proc, dev_t)\
+ int proc(P2(dev_t *dev, gs_param_list *plist))
+#define dev_proc_put_params(proc)\
+ dev_t_proc_put_params(proc, gx_device)
+
+ /* Added in release 2.6 */
+
+#define dev_t_proc_map_cmyk_color(proc, dev_t)\
+ gx_color_index proc(P5(dev_t *dev,\
+ gx_color_value cyan, gx_color_value magenta, gx_color_value yellow,\
+ gx_color_value black))
+#define dev_proc_map_cmyk_color(proc)\
+ dev_t_proc_map_cmyk_color(proc, gx_device)
+
+#define dev_t_proc_get_xfont_procs(proc, dev_t)\
+ const gx_xfont_procs *proc(P1(dev_t *dev))
+#define dev_proc_get_xfont_procs(proc)\
+ dev_t_proc_get_xfont_procs(proc, gx_device)
+
+ /* Added in release 2.6.1 */
+
+#define dev_t_proc_get_xfont_device(proc, dev_t)\
+ gx_device *proc(P1(dev_t *dev))
+#define dev_proc_get_xfont_device(proc)\
+ dev_t_proc_get_xfont_device(proc, gx_device)
+
+ /* Added in release 2.7.1 */
+
+#define dev_t_proc_map_rgb_alpha_color(proc, dev_t)\
+ gx_color_index proc(P5(dev_t *dev,\
+ gx_color_value red, gx_color_value green, gx_color_value blue,\
+ gx_color_value alpha))
+#define dev_proc_map_rgb_alpha_color(proc)\
+ dev_t_proc_map_rgb_alpha_color(proc, gx_device)
+
+ /* Added in release 2.8.1 */
+
+#define dev_t_proc_get_page_device(proc, dev_t)\
+ gx_device *proc(P1(dev_t *dev))
+#define dev_proc_get_page_device(proc)\
+ dev_t_proc_get_page_device(proc, gx_device)
+
+ /* Added in release 3.20 */
+
+#define dev_t_proc_get_alpha_bits(proc, dev_t)\
+ int proc(P2(dev_t *dev, graphics_object_type type))
+#define dev_proc_get_alpha_bits(proc)\
+ dev_t_proc_get_alpha_bits(proc, gx_device)
+
+#define dev_t_proc_copy_alpha(proc, dev_t)\
+ int proc(P11(dev_t *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))
+#define dev_proc_copy_alpha(proc)\
+ dev_t_proc_copy_alpha(proc, gx_device)
+
+ /* Added in release 3.38 */
+
+#define dev_t_proc_get_band(proc, dev_t)\
+ int proc(P3(dev_t *dev, int y, int *band_start))
+#define dev_proc_get_band(proc)\
+ dev_t_proc_get_band(proc, gx_device)
+
+ /* Added in release 3.44 */
+
+#define dev_t_proc_copy_rop(proc, dev_t)\
+ int proc(P15(dev_t *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))
+#define dev_proc_copy_rop(proc)\
+ dev_t_proc_copy_rop(proc, gx_device)
+
+ /* Added in release 3.60, changed in 3.68. */
+
+#define dev_t_proc_fill_path(proc, dev_t)\
+ int proc(P6(dev_t *dev,\
+ const gs_imager_state *pis, gx_path *ppath,\
+ const gx_fill_params *params,\
+ const gx_drawing_color *pdcolor, const gx_clip_path *pcpath))
+#define dev_proc_fill_path(proc)\
+ dev_t_proc_fill_path(proc, gx_device)
+
+#define dev_t_proc_stroke_path(proc, dev_t)\
+ int proc(P6(dev_t *dev,\
+ const gs_imager_state *pis, gx_path *ppath,\
+ const gx_stroke_params *params,\
+ const gx_drawing_color *pdcolor, const gx_clip_path *pcpath))
+#define dev_proc_stroke_path(proc)\
+ dev_t_proc_stroke_path(proc, gx_device)
+
+ /* Added in release 3.60 */
+
+#define dev_t_proc_fill_mask(proc, dev_t)\
+ int proc(P13(dev_t *dev,\
+ const byte *data, int data_x, int raster, gx_bitmap_id id,\
+ int x, int y, int width, int height,\
+ const gx_drawing_color *pdcolor, int depth,\
+ gs_logical_operation_t lop, const gx_clip_path *pcpath))
+#define dev_proc_fill_mask(proc)\
+ dev_t_proc_fill_mask(proc, gx_device)
+
+ /* Added in release 3.66, changed in 3.69 */
+
+#define dev_t_proc_fill_trapezoid(proc, dev_t)\
+ int proc(P8(dev_t *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))
+#define dev_proc_fill_trapezoid(proc)\
+ dev_t_proc_fill_trapezoid(proc, gx_device)
+
+#define dev_t_proc_fill_parallelogram(proc, dev_t)\
+ int proc(P9(dev_t *dev,\
+ fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by,\
+ const gx_drawing_color *pdcolor, gs_logical_operation_t lop))
+#define dev_proc_fill_parallelogram(proc)\
+ dev_t_proc_fill_parallelogram(proc, gx_device)
+
+#define dev_t_proc_fill_triangle(proc, dev_t)\
+ int proc(P9(dev_t *dev,\
+ fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by,\
+ const gx_drawing_color *pdcolor, gs_logical_operation_t lop))
+#define dev_proc_fill_triangle(proc)\
+ dev_t_proc_fill_triangle(proc, gx_device)
+
+#define dev_t_proc_draw_thin_line(proc, dev_t)\
+ int proc(P7(dev_t *dev,\
+ fixed fx0, fixed fy0, fixed fx1, fixed fy1,\
+ const gx_drawing_color *pdcolor, gs_logical_operation_t lop))
+#define dev_proc_draw_thin_line(proc)\
+ dev_t_proc_draw_thin_line(proc, gx_device)
+
+ /* Added in release 3.66 (as stubs); */
+ /* changed in 3.68; */
+ /* begin_image and image_data changed in 4.30, */
+ /* begin_image changed in 5.23. */
+
+#define dev_t_proc_begin_image(proc, dev_t)\
+ int proc(P9(dev_t *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))
+#define dev_proc_begin_image(proc)\
+ dev_t_proc_begin_image(proc, gx_device)
+
+ /* OBSOLETED in release 5.23 */
+
+#define dev_t_proc_image_data(proc, dev_t)\
+ int proc(P6(dev_t *dev,\
+ gx_image_enum_common_t *info, const byte **planes, int data_x,\
+ uint raster, int height))
+#define dev_proc_image_data(proc)\
+ dev_t_proc_image_data(proc, gx_device)
+
+ /* OBSOLETED in release 5.23 */
+
+#define dev_t_proc_end_image(proc, dev_t)\
+ int proc(P3(dev_t *dev,\
+ gx_image_enum_common_t *info, bool draw_last))
+#define dev_proc_end_image(proc)\
+ dev_t_proc_end_image(proc, gx_device)
+
+ /* Added in release 3.68 */
+
+#define dev_t_proc_strip_tile_rectangle(proc, dev_t)\
+ int proc(P10(dev_t *dev,\
+ const gx_strip_bitmap *tiles, int x, int y, int width, int height,\
+ gx_color_index color0, gx_color_index color1,\
+ int phase_x, int phase_y))
+#define dev_proc_strip_tile_rectangle(proc)\
+ dev_t_proc_strip_tile_rectangle(proc, gx_device)
+
+#define dev_t_proc_strip_copy_rop(proc, dev_t)\
+ int proc(P15(dev_t *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))
+#define dev_proc_strip_copy_rop(proc)\
+ dev_t_proc_strip_copy_rop(proc, gx_device)
+
+ /* Added in release 4.20 */
+
+#define dev_t_proc_get_clipping_box(proc, dev_t)\
+ void proc(P2(dev_t *dev, gs_fixed_rect *pbox))
+#define dev_proc_get_clipping_box(proc)\
+ dev_t_proc_get_clipping_box(proc, gx_device)
+
+ /* Added in release 5.20, changed in 5.23 */
+
+#define dev_t_proc_begin_typed_image(proc, dev_t)\
+ int proc(P9(dev_t *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))
+#define dev_proc_begin_typed_image(proc)\
+ dev_t_proc_begin_typed_image(proc, gx_device)
+
+ /* Added in release 5.20 */
+
+#define dev_t_proc_get_bits_rectangle(proc, dev_t)\
+ int proc(P4(dev_t *dev, const gs_int_rect *prect,\
+ gs_get_bits_params_t *params, gs_int_rect **unread))
+#define dev_proc_get_bits_rectangle(proc)\
+ dev_t_proc_get_bits_rectangle(proc, gx_device)
+
+#define dev_t_proc_map_color_rgb_alpha(proc, dev_t)\
+ int proc(P3(dev_t *dev,\
+ gx_color_index color, gx_color_value rgba[4]))
+#define dev_proc_map_color_rgb_alpha(proc)\
+ dev_t_proc_map_color_rgb_alpha(proc, gx_device)
+
+#define dev_t_proc_create_compositor(proc, dev_t)\
+ int proc(P5(dev_t *dev,\
+ gx_device **pcdev, const gs_composite_t *pcte,\
+ const gs_imager_state *pis, gs_memory_t *memory))
+#define dev_proc_create_compositor(proc)\
+ dev_t_proc_create_compositor(proc, gx_device)\
+
+ /* Added in release 5.23 */
+
+#define dev_t_proc_get_hardware_params(proc, dev_t)\
+ int proc(P2(dev_t *dev, gs_param_list *plist))
+#define dev_proc_get_hardware_params(proc)\
+ dev_t_proc_get_hardware_params(proc, gx_device)
+
+ /* Added in release 5.24 */
+
+ /* ... text_begin ... see gxtext.h for definition */
+
+/* Define the device procedure vector template proper. */
+
+#define gx_device_proc_struct(dev_t)\
+{ dev_t_proc_open_device((*open_device), dev_t);\
+ dev_t_proc_get_initial_matrix((*get_initial_matrix), dev_t);\
+ dev_t_proc_sync_output((*sync_output), dev_t);\
+ dev_t_proc_output_page((*output_page), dev_t);\
+ dev_t_proc_close_device((*close_device), dev_t);\
+ dev_t_proc_map_rgb_color((*map_rgb_color), dev_t);\
+ dev_t_proc_map_color_rgb((*map_color_rgb), dev_t);\
+ dev_t_proc_fill_rectangle((*fill_rectangle), dev_t);\
+ dev_t_proc_tile_rectangle((*tile_rectangle), dev_t);\
+ dev_t_proc_copy_mono((*copy_mono), dev_t);\
+ dev_t_proc_copy_color((*copy_color), dev_t);\
+ dev_t_proc_draw_line((*obsolete_draw_line), dev_t);\
+ dev_t_proc_get_bits((*get_bits), dev_t);\
+ dev_t_proc_get_params((*get_params), dev_t);\
+ dev_t_proc_put_params((*put_params), dev_t);\
+ dev_t_proc_map_cmyk_color((*map_cmyk_color), dev_t);\
+ dev_t_proc_get_xfont_procs((*get_xfont_procs), dev_t);\
+ dev_t_proc_get_xfont_device((*get_xfont_device), dev_t);\
+ dev_t_proc_map_rgb_alpha_color((*map_rgb_alpha_color), dev_t);\
+ dev_t_proc_get_page_device((*get_page_device), dev_t);\
+ dev_t_proc_get_alpha_bits((*get_alpha_bits), dev_t);\
+ dev_t_proc_copy_alpha((*copy_alpha), dev_t);\
+ dev_t_proc_get_band((*get_band), dev_t);\
+ dev_t_proc_copy_rop((*copy_rop), dev_t);\
+ dev_t_proc_fill_path((*fill_path), dev_t);\
+ dev_t_proc_stroke_path((*stroke_path), dev_t);\
+ dev_t_proc_fill_mask((*fill_mask), dev_t);\
+ dev_t_proc_fill_trapezoid((*fill_trapezoid), dev_t);\
+ dev_t_proc_fill_parallelogram((*fill_parallelogram), dev_t);\
+ dev_t_proc_fill_triangle((*fill_triangle), dev_t);\
+ dev_t_proc_draw_thin_line((*draw_thin_line), dev_t);\
+ dev_t_proc_begin_image((*begin_image), dev_t);\
+ dev_t_proc_image_data((*image_data), dev_t);\
+ dev_t_proc_end_image((*end_image), dev_t);\
+ dev_t_proc_strip_tile_rectangle((*strip_tile_rectangle), dev_t);\
+ dev_t_proc_strip_copy_rop((*strip_copy_rop), dev_t);\
+ dev_t_proc_get_clipping_box((*get_clipping_box), dev_t);\
+ dev_t_proc_begin_typed_image((*begin_typed_image), dev_t);\
+ dev_t_proc_get_bits_rectangle((*get_bits_rectangle), dev_t);\
+ dev_t_proc_map_color_rgb_alpha((*map_color_rgb_alpha), dev_t);\
+ dev_t_proc_create_compositor((*create_compositor), dev_t);\
+ dev_t_proc_get_hardware_params((*get_hardware_params), dev_t);\
+ dev_t_proc_text_begin((*text_begin), dev_t);\
+}
+/*
+ * Provide procedures for passing image data. image_data and end_image
+ * are the equivalents of the obsolete driver procedures. image_plane_data
+ * was originally planned as a driver procedure, but is now associated with
+ * the image enumerator, like the other two.
+ */
+
+typedef struct gx_image_plane_s {
+ const byte *data;
+ int data_x;
+ uint raster;
+} gx_image_plane_t;
+
+#define image_enum_proc_plane_data(proc)\
+ int proc(P4(gx_device *dev,\
+ gx_image_enum_common_t *info, const gx_image_plane_t *planes,\
+ int height))
+#define gx_device_begin_image(dev, pis, pim, format, prect, pdcolor, pcpath, memory, pinfo)\
+ ((*dev_proc(dev, begin_image))\
+ (dev, pis, pim, format, prect, pdcolor, pcpath, memory, pinfo))
+#define gx_device_begin_typed_image(dev, pis, pmat, pim, prect, pdcolor, pcpath, memory, pinfo)\
+ ((*dev_proc(dev, begin_typed_image))\
+ (dev, pis, pmat, pim, prect, pdcolor, pcpath, memory, pinfo))
+
+/*
+ * The driver-like procedures gx_device_{image_data, image_plane_data,
+ * end_image} are now DEPRECATED and will eventually be removed.
+ * Their replacements no longer take an ignored dev argument.
+ */
+int gx_image_data(P5(gx_image_enum_common_t *info, const byte **planes,
+ int data_x, uint raster, int height));
+int gx_image_plane_data(P3(gx_image_enum_common_t *info,
+ const gx_image_plane_t *planes, int height));
+int gx_image_end(P2(gx_image_enum_common_t *info, bool draw_last));
+
+#define gx_device_image_data(dev, info, planes, data_x, raster, height)\
+ gx_image_data(info, planes, data_x, raster, height)
+#define gx_device_image_plane_data(dev, info, planes, height)\
+ gx_image_plane_data(info, planes, height)
+#define gx_device_end_image(dev, info, draw_last)\
+ gx_image_end(info, draw_last)
+
+/* A generic device procedure record. */
+struct gx_device_procs_s gx_device_proc_struct(gx_device);
+
+/*
+ * Define a procedure for setting up a memory device for buffering output
+ * for a given device. This is only used by band devices, but we define it
+ * here for convenience. The default implementation just calls
+ * gs_make_mem_device. Possibly this should be a generic device
+ * procedure....
+ */
+#ifndef gx_device_memory_DEFINED
+# define gx_device_memory_DEFINED
+typedef struct gx_device_memory_s gx_device_memory;
+
+#endif
+#define dev_proc_make_buffer_device(proc)\
+ int proc(P4(gx_device_memory *, gx_device *, gs_memory_t *, bool))
+dev_proc_make_buffer_device(gx_default_make_buffer_device);
+
+/*
+ * Define unaligned analogues of the copy_xxx procedures.
+ * These are slower than the standard procedures, which require
+ * aligned bitmaps, and also are not portable to non-byte-addressed machines.
+ *
+ * We allow both unaligned data and unaligned scan line widths;
+ * however, we do require that both of these be aligned modulo the largest
+ * power of 2 bytes that divides the data depth, i.e.:
+ * depth alignment
+ * <= 8 1
+ * 16 2
+ * 24 1
+ * 32 4
+ */
+dev_proc_copy_mono(gx_copy_mono_unaligned);
+dev_proc_copy_color(gx_copy_color_unaligned);
+dev_proc_copy_alpha(gx_copy_alpha_unaligned);
+
+/* A generic device */
+struct gx_device_s {
+ gx_device_common;
+};
+
+extern_st(st_device);
+struct_proc_finalize(gx_device_finalize); /* public for subclasses */
+/* We use vacuous enum/reloc procedures, rather than 0, so that */
+/* gx_device can have subclasses. */
+#define public_st_device() /* in gsdevice.c */\
+ gs_public_st_complex_only(st_device, gx_device, "gx_device",\
+ 0, gs_no_struct_enum_ptrs, gs_no_struct_reloc_ptrs, gx_device_finalize)
+#define st_device_max_ptrs 0
+
+/* Enumerate or relocate a pointer to a device. */
+/* These take the containing space into account properly. */
+gx_device *gx_device_enum_ptr(P1(gx_device *));
+gx_device *gx_device_reloc_ptr(P2(gx_device *, gc_state_t *));
+
+/* Define typedefs for some of the device procedures, because */
+/* ansi2knr can't handle dev_proc_xxx((*xxx)) in a formal argument list. */
+typedef dev_proc_map_rgb_color((*dev_proc_map_rgb_color_t));
+typedef dev_proc_map_color_rgb((*dev_proc_map_color_rgb_t));
+
+/*
+ * A forwarding device forwards all non-display operations, and possibly
+ * some imaging operations (possibly transformed in some way), to another
+ * device called the "target". This is used for many different purposes
+ * internally, including clipping, banding, image and pattern accumulation,
+ * compositing, halftoning, and the null device.
+ */
+#define gx_device_forward_common\
+ gx_device_common;\
+ gx_device *target
+/* A generic forwarding device. */
+typedef struct gx_device_forward_s {
+ gx_device_forward_common;
+} gx_device_forward;
+
+extern_st(st_device_forward);
+#define public_st_device_forward() /* in gsdevice.c */\
+ gs_public_st_complex_only(st_device_forward, gx_device_forward,\
+ "gx_device_forward", 0, device_forward_enum_ptrs,\
+ device_forward_reloc_ptrs, gx_device_finalize)
+#define st_device_forward_max_ptrs (st_device_max_ptrs + 1)
+
+/* A null device. This is used to temporarily disable output. */
+#ifndef gx_device_null_DEFINED
+# define gx_device_null_DEFINED
+typedef struct gx_device_null_s gx_device_null;
+
+#endif
+struct gx_device_null_s {
+ gx_device_forward_common;
+};
+extern const gx_device_null gs_null_device;
+
+#define gx_device_is_null(dev)\
+ ((dev)->dname == gs_null_device.dname)
+extern_st(st_device_null);
+#define public_st_device_null() /* in gsdevice.c */\
+ gs_public_st_complex_only(st_device_null, gx_device_null,\
+ "gx_device_null", 0, device_forward_enum_ptrs,\
+ device_forward_reloc_ptrs, gx_device_finalize)
+#define st_device_null_max_ptrs st_device_forward_max_ptrs
+
+/*
+ * Initialize a just-allocated device from a prototype.
+ * internal = true means initialize the reference count to 0,
+ * false means initialize to 1.
+ */
+void gx_device_init(P4(gx_device * dev, const gx_device * proto,
+ gs_memory_t * mem, bool internal));
+
+/* Make a null device. */
+/* The gs_memory_t argument is 0 if the device is temporary and local, */
+/* or the allocator that was used to allocate it if it is a real object. */
+void gs_make_null_device(P2(gx_device_null *, gs_memory_t *));
+
+/* Calculate the raster (number of bytes in a scan line), */
+/* with byte or word padding. */
+uint gx_device_raster(P2(const gx_device * dev, bool pad_to_word));
+
+/* Adjust the resolution for devices that only have a fixed set of */
+/* geometries, so that the apparent size in inches remains constant. */
+/* If fit=1, the resolution is adjusted so that the entire image fits; */
+/* if fit=0, one dimension fits, but the other one is clipped. */
+int gx_device_adjust_resolution(P4(gx_device * dev, int actual_width, int actual_height, int fit));
+
+/* Set the HWMargins to values defined in inches. */
+/* If move_origin is true, also reset the Margins. */
+void gx_device_set_margins(P3(gx_device * dev, const float *margins /*[4] */ ,
+ bool move_origin));
+
+/* Set the width and height (in pixels), updating PageSize. */
+void gx_device_set_width_height(P3(gx_device * dev, int width, int height));
+
+/* Set the resolution (in pixels per inch), updating width and height. */
+void gx_device_set_resolution(P3(gx_device * dev, floatp x_dpi, floatp y_dpi));
+
+/* Set the PageSize (in 1/72" units), updating width and height. */
+void gx_device_set_media_size(P3(gx_device * dev, floatp media_width, floatp media_height));
+
+/****** BACKWARD COMPATIBILITY ******/
+#define gx_device_set_page_size(dev, w, h)\
+ gx_device_set_media_size(dev, w, h)
+
+/*
+ * Temporarily install a null device, or a special device such as
+ * a clipping or cache device.
+ */
+void gx_set_device_only(P2(gs_state *, gx_device *));
+
+/* Close a device. */
+int gs_closedevice(P1(gx_device *));
+
+/* ------ Device types (an unused concept right now) ------ */
+
+#define dev_type_proc_initialize(proc)\
+ int proc(P1(gx_device *))
+
+typedef struct gx_device_type_s {
+ gs_memory_type_ptr_t stype;
+ dev_type_proc_initialize((*initialize));
+} gx_device_type;
+
+#define device_type(dtname, stype, initproc)\
+private dev_type_proc_initialize(initproc);\
+const gx_device_type dtname = { &stype, initproc }
+
+/*dev_type_proc_initialize(gdev_initialize); */
+
+#endif /* gxdevcli_INCLUDED */
diff --git a/pstoraster/gxdevice.h b/pstoraster/gxdevice.h
new file mode 100644
index 000000000..b0fb7b38b
--- /dev/null
+++ b/pstoraster/gxdevice.h
@@ -0,0 +1,453 @@
+/* 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$ */
+/* Definitions for device implementors */
+
+#ifndef gxdevice_INCLUDED
+# define gxdevice_INCLUDED
+
+#include "stdio_.h" /* for FILE */
+#include "gxdevcli.h"
+#include "gsparam.h"
+/*
+ * Drivers still use gs_malloc and gs_free, so include the interface for
+ * these. (Eventually they should go away.)
+ */
+#include "gsmalloc.h"
+
+/* ---------------- Auxiliary types and structures ---------------- */
+
+/* Define default pages sizes. */
+/* U.S. letter paper (8.5" x 11"). */
+#define DEFAULT_WIDTH_10THS_US_LETTER 85
+#define DEFAULT_HEIGHT_10THS_US_LETTER 110
+/* A4 paper (210mm x 297mm). The dimensions are off by a few mm.... */
+#define DEFAULT_WIDTH_10THS_A4 83
+#define DEFAULT_HEIGHT_10THS_A4 117
+/* Choose a default. A4 may be set in the makefile. */
+#ifdef A4
+# define DEFAULT_WIDTH_10THS DEFAULT_WIDTH_10THS_A4
+# define DEFAULT_HEIGHT_10THS DEFAULT_HEIGHT_10THS_A4
+#else
+# define DEFAULT_WIDTH_10THS DEFAULT_WIDTH_10THS_US_LETTER
+# define DEFAULT_HEIGHT_10THS DEFAULT_HEIGHT_10THS_US_LETTER
+#endif
+
+/* ---------------- Device structure ---------------- */
+
+/*
+ * To insulate statically defined device templates from the
+ * consequences of changes in the device structure, the following macros
+ * must be used for generating initialized device structures.
+ *
+ * The computations of page width and height in pixels should really be
+ * ((int)(page_width_inches*x_dpi))
+ * but some compilers (the Ultrix 3.X pcc compiler and the HPUX compiler)
+ * can't cast a computed float to an int. That's why we specify
+ * the page width and height in inches/10 instead of inches.
+ *
+ * Note that the macro is broken up so as to be usable for devices that
+ * add further initialized state to the generic device.
+ * Note also that the macro does not initialize procs, which is
+ * the next element of the structure.
+ */
+#define std_device_part1_(devtype, ptr_procs, dev_name, stype, open_init)\
+ sizeof(devtype), ptr_procs, dev_name,\
+ 0 /*memory*/, stype, { 0 } /*rc*/,\
+ open_init() /*is_open, max_fill_band */
+/* color_info goes here */
+/*
+ * The MetroWerks compiler has some bizarre bug that produces a spurious
+ * error message if the width and/or height are defined as 0 below,
+ * unless we use the +/- workaround in the next macro.
+ */
+#define std_device_part2_(width, height, x_dpi, y_dpi)\
+ width, height,\
+ { (((width) * 72.0 + 0.5) - 0.5) / (x_dpi),\
+ (((height) * 72.0 + 0.5) - 0.5) / (y_dpi) },\
+ { 0, 0, 0, 0 }, 0/*false*/, { x_dpi, y_dpi }, { x_dpi, y_dpi }
+/* offsets and margins go here */
+#define std_device_part3_()\
+ 0, 0, 1, 0/*false*/, 0/*false*/,\
+ { gx_default_install, gx_default_begin_page, gx_default_end_page }
+/*
+ * We need a number of different variants of the std_device_ macro simply
+ * because we can't pass the color_info or offsets/margins
+ * as macro arguments, which in turn is because of the early macro
+ * expansion issue noted in stdpre.h. The basic variants are:
+ * ...body_with_macros_, which uses 0-argument macros to supply
+ * open_init, color_info, and offsets/margins;
+ * ...full_body, which takes 12 values (6 for dci_values,
+ * 6 for offsets/margins);
+ * ...color_full_body, which takes 9 values (3 for dci_color,
+ * 6 for margins/offset).
+ * ...std_color_full_body, which takes 7 values (1 for dci_std_color,
+ * 6 for margins/offset).
+ *
+ */
+#define std_device_body_with_macros_(dtype, pprocs, dname, stype, w, h, xdpi, ydpi, open_init, dci_macro, margins_macro)\
+ std_device_part1_(dtype, pprocs, dname, stype, open_init),\
+ dci_macro(),\
+ std_device_part2_(w, h, xdpi, ydpi),\
+ margins_macro(),\
+ std_device_part3_()
+
+#define std_device_std_body(dtype, pprocs, dname, w, h, xdpi, ydpi)\
+ std_device_body_with_macros_(dtype, pprocs, dname, 0,\
+ w, h, xdpi, ydpi,\
+ open_init_closed, dci_black_and_white_, no_margins_)
+
+#define std_device_std_body_type_open(dtype, pprocs, dname, stype, w, h, xdpi, ydpi)\
+ std_device_body_with_macros_(dtype, pprocs, dname, stype,\
+ w, h, xdpi, ydpi,\
+ open_init_open, dci_black_and_white_, no_margins_)
+
+#define std_device_std_body_open(dtype, pprocs, dname, w, h, xdpi, ydpi)\
+ std_device_std_body_type_open(dtype, pprocs, dname, 0, w, h, xdpi, ydpi)
+
+#define std_device_full_body(dtype, pprocs, dname, w, h, xdpi, ydpi, ncomp, depth, mg, mc, dg, dc, xoff, yoff, lm, bm, rm, tm)\
+ std_device_part1_(dtype, pprocs, dname, 0, open_init_closed),\
+ dci_values(ncomp, depth, mg, mc, dg, dc),\
+ std_device_part2_(w, h, xdpi, ydpi),\
+ offset_margin_values(xoff, yoff, lm, bm, rm, tm),\
+ std_device_part3_()
+
+#define std_device_dci_type_body(dtype, pprocs, dname, stype, w, h, xdpi, ydpi, ncomp, depth, mg, mc, dg, dc)\
+ std_device_part1_(dtype, pprocs, dname, stype, open_init_closed),\
+ dci_values(ncomp, depth, mg, mc, dg, dc),\
+ std_device_part2_(w, h, xdpi, ydpi),\
+ offset_margin_values(0, 0, 0, 0, 0, 0),\
+ std_device_part3_()
+
+#define std_device_dci_body(dtype, pprocs, dname, w, h, xdpi, ydpi, ncomp, depth, mg, mc, dg, dc)\
+ std_device_dci_type_body(dtype, pprocs, dname, 0,\
+ w, h, xdpi, ydpi, ncomp, depth, mg, mc, dg, dc)
+
+#define std_device_color_full_body(dtype, pprocs, dname, w, h, xdpi, ydpi, depth, max_value, dither, xoff, yoff, lm, bm, rm, tm)\
+ std_device_part1_(dtype, pprocs, dname, 0, open_init_closed),\
+ dci_color(depth, max_value, dither),\
+ std_device_part2_(w, h, xdpi, ydpi),\
+ offset_margin_values(xoff, yoff, lm, bm, rm, tm),\
+ std_device_part3_()
+
+#define std_device_color_body(dtype, pprocs, dname, w, h, xdpi, ydpi, depth, max_value, dither)\
+ std_device_color_full_body(dtype, pprocs, dname,\
+ w, h, xdpi, ydpi,\
+ depth, max_value, dither,\
+ 0, 0, 0, 0, 0, 0)
+
+#define std_device_color_stype_body(dtype, pprocs, dname, stype, w, h, xdpi, ydpi, depth, max_value, dither)\
+ std_device_part1_(dtype, pprocs, dname, stype, open_init_closed),\
+ dci_color(depth, max_value, dither),\
+ std_device_part2_(w, h, xdpi, ydpi),\
+ offset_margin_values(0, 0, 0, 0, 0, 0),\
+ std_device_part3_()
+
+#define std_device_std_color_full_body(dtype, pprocs, dname, w, h, xdpi, ydpi, depth, xoff, yoff, lm, bm, rm, tm)\
+ std_device_part1_(dtype, pprocs, dname, 0, open_init_closed),\
+ dci_std_color(depth),\
+ std_device_part2_(w, h, xdpi, ydpi),\
+ offset_margin_values(xoff, yoff, lm, bm, rm, tm),\
+ std_device_part3_()
+
+/* ---------------- Default implementations ---------------- */
+
+/* Default implementations of optional procedures. */
+/* Note that the default map_xxx_color routines assume white_on_black. */
+dev_proc_open_device(gx_default_open_device);
+dev_proc_get_initial_matrix(gx_default_get_initial_matrix);
+dev_proc_get_initial_matrix(gx_upright_get_initial_matrix);
+dev_proc_sync_output(gx_default_sync_output);
+dev_proc_output_page(gx_default_output_page);
+dev_proc_close_device(gx_default_close_device);
+dev_proc_map_rgb_color(gx_default_w_b_map_rgb_color);
+dev_proc_map_color_rgb(gx_default_w_b_map_color_rgb);
+#define gx_default_map_rgb_color gx_default_w_b_map_rgb_color
+#define gx_default_map_color_rgb gx_default_w_b_map_color_rgb
+dev_proc_tile_rectangle(gx_default_tile_rectangle);
+dev_proc_copy_mono(gx_default_copy_mono);
+dev_proc_copy_color(gx_default_copy_color);
+dev_proc_draw_line(gx_default_draw_line);
+dev_proc_get_bits(gx_no_get_bits); /* gives error */
+dev_proc_get_bits(gx_default_get_bits);
+dev_proc_get_params(gx_default_get_params);
+dev_proc_put_params(gx_default_put_params);
+dev_proc_map_cmyk_color(gx_default_map_cmyk_color);
+dev_proc_get_xfont_procs(gx_default_get_xfont_procs);
+dev_proc_get_xfont_device(gx_default_get_xfont_device);
+dev_proc_map_rgb_alpha_color(gx_default_map_rgb_alpha_color);
+dev_proc_get_page_device(gx_default_get_page_device); /* returns NULL */
+dev_proc_get_page_device(gx_page_device_get_page_device); /* returns dev */
+dev_proc_get_alpha_bits(gx_default_get_alpha_bits);
+dev_proc_copy_alpha(gx_no_copy_alpha); /* gives error */
+dev_proc_copy_alpha(gx_default_copy_alpha);
+dev_proc_get_band(gx_default_get_band);
+dev_proc_copy_rop(gx_no_copy_rop); /* gives error */
+dev_proc_copy_rop(gx_default_copy_rop);
+dev_proc_fill_path(gx_default_fill_path);
+dev_proc_stroke_path(gx_default_stroke_path);
+dev_proc_fill_mask(gx_default_fill_mask);
+dev_proc_fill_trapezoid(gx_default_fill_trapezoid);
+dev_proc_fill_parallelogram(gx_default_fill_parallelogram);
+dev_proc_fill_triangle(gx_default_fill_triangle);
+dev_proc_draw_thin_line(gx_default_draw_thin_line);
+dev_proc_begin_image(gx_default_begin_image);
+dev_proc_image_data(gx_default_image_data);
+dev_proc_end_image(gx_default_end_image);
+dev_proc_strip_tile_rectangle(gx_default_strip_tile_rectangle);
+dev_proc_strip_copy_rop(gx_no_strip_copy_rop); /* gives error */
+dev_proc_strip_copy_rop(gx_default_strip_copy_rop);
+dev_proc_get_clipping_box(gx_default_get_clipping_box);
+dev_proc_get_clipping_box(gx_get_largest_clipping_box);
+dev_proc_begin_typed_image(gx_default_begin_typed_image);
+dev_proc_get_bits_rectangle(gx_no_get_bits_rectangle); /* gives error */
+dev_proc_get_bits_rectangle(gx_default_get_bits_rectangle);
+dev_proc_map_color_rgb_alpha(gx_default_map_color_rgb_alpha);
+dev_proc_create_compositor(gx_no_create_compositor);
+/* default is for ordinary "leaf" devices, non_imaging is for */
+/* devices that only care about coverage and not contents. */
+dev_proc_create_compositor(gx_default_create_compositor);
+dev_proc_create_compositor(gx_non_imaging_create_compositor);
+dev_proc_get_hardware_params(gx_default_get_hardware_params);
+dev_proc_text_begin(gx_default_text_begin);
+
+/* Color mapping routines for black-on-white, gray scale, true RGB, */
+/* and true CMYK color. */
+dev_proc_map_rgb_color(gx_default_b_w_map_rgb_color);
+dev_proc_map_color_rgb(gx_default_b_w_map_color_rgb);
+dev_proc_map_rgb_color(gx_default_gray_map_rgb_color);
+dev_proc_map_color_rgb(gx_default_gray_map_color_rgb);
+dev_proc_map_rgb_color(gx_default_rgb_map_rgb_color);
+dev_proc_map_color_rgb(gx_default_rgb_map_color_rgb);
+dev_proc_map_cmyk_color(gx_default_cmyk_map_cmyk_color);
+
+/* Default implementations for forwarding devices */
+dev_proc_get_initial_matrix(gx_forward_get_initial_matrix);
+dev_proc_sync_output(gx_forward_sync_output);
+dev_proc_output_page(gx_forward_output_page);
+dev_proc_map_rgb_color(gx_forward_map_rgb_color);
+dev_proc_map_color_rgb(gx_forward_map_color_rgb);
+dev_proc_fill_rectangle(gx_forward_fill_rectangle);
+dev_proc_tile_rectangle(gx_forward_tile_rectangle);
+dev_proc_copy_mono(gx_forward_copy_mono);
+dev_proc_copy_color(gx_forward_copy_color);
+dev_proc_get_bits(gx_forward_get_bits);
+dev_proc_get_params(gx_forward_get_params);
+dev_proc_put_params(gx_forward_put_params);
+dev_proc_map_cmyk_color(gx_forward_map_cmyk_color);
+dev_proc_get_xfont_procs(gx_forward_get_xfont_procs);
+dev_proc_get_xfont_device(gx_forward_get_xfont_device);
+dev_proc_map_rgb_alpha_color(gx_forward_map_rgb_alpha_color);
+dev_proc_get_page_device(gx_forward_get_page_device);
+dev_proc_get_alpha_bits(gx_forward_get_alpha_bits);
+dev_proc_copy_alpha(gx_forward_copy_alpha);
+dev_proc_get_band(gx_forward_get_band);
+dev_proc_copy_rop(gx_forward_copy_rop);
+dev_proc_fill_path(gx_forward_fill_path);
+dev_proc_stroke_path(gx_forward_stroke_path);
+dev_proc_fill_mask(gx_forward_fill_mask);
+dev_proc_fill_trapezoid(gx_forward_fill_trapezoid);
+dev_proc_fill_parallelogram(gx_forward_fill_parallelogram);
+dev_proc_fill_triangle(gx_forward_fill_triangle);
+dev_proc_draw_thin_line(gx_forward_draw_thin_line);
+dev_proc_begin_image(gx_forward_begin_image);
+#define gx_forward_image_data gx_default_image_data
+#define gx_forward_end_image gx_default_end_image
+dev_proc_strip_tile_rectangle(gx_forward_strip_tile_rectangle);
+dev_proc_strip_copy_rop(gx_forward_strip_copy_rop);
+dev_proc_get_clipping_box(gx_forward_get_clipping_box);
+dev_proc_begin_typed_image(gx_forward_begin_typed_image);
+dev_proc_get_bits_rectangle(gx_forward_get_bits_rectangle);
+dev_proc_map_color_rgb_alpha(gx_forward_map_color_rgb_alpha);
+/* There is no forward_create_compositor (see Drivers.htm). */
+dev_proc_get_hardware_params(gx_forward_get_hardware_params);
+dev_proc_text_begin(gx_forward_text_begin);
+
+/* ---------------- Implementation utilities ---------------- */
+
+/* Fill in the GC structure descriptor for a device. */
+/* This is only called during initialization. */
+void gx_device_make_struct_type(P2(gs_memory_struct_type_t *,
+ const gx_device *));
+
+/* Convert the device procedures to the proper form (see above). */
+void gx_device_set_procs(P1(gx_device *));
+
+/* Fill in defaulted procedures in a device procedure record. */
+void gx_device_fill_in_procs(P1(gx_device *));
+void gx_device_forward_fill_in_procs(P1(gx_device_forward *));
+
+/* Forward the color mapping procedures from a device to its target. */
+void gx_device_forward_color_procs(P1(gx_device_forward *));
+
+/*
+ * Copy device parameters back from a target. This copies all standard
+ * parameters related to page size and resolution, plus color_info.
+ */
+void gx_device_copy_params(P2(gx_device *to, const gx_device *from));
+
+/* Open the output file for a device. */
+int gx_device_open_output_file(P5(const gx_device * dev, const char *fname,
+ bool binary, bool positionable,
+ FILE ** pfile));
+
+/*
+ * Determine whether a given device needs to halftone. Eventually this
+ * should take an imager state as an additional argument.
+ */
+#define gx_device_must_halftone(dev)\
+ ((gx_device_has_color(dev) ? (dev)->color_info.max_color :\
+ (dev)->color_info.max_gray) < 31)
+#define gx_color_device_must_halftone(dev)\
+ ((dev)->color_info.max_gray < 31)
+
+/*
+ * Device procedures that draw into rectangles need to clip the coordinates
+ * to the rectangle ((0,0),(dev->width,dev->height)). The following macros
+ * do the clipping. They assume that the arguments of the procedure are
+ * named dev, x, y, w, and h, and may modify the arguments (other than dev).
+ *
+ * For procedures that fill a region, dev, x, y, w, and h are the only
+ * relevant arguments. For procedures that copy bitmaps, see below.
+ *
+ * The following group of macros for region-filling procedures clips
+ * specific edges of the supplied rectangle, as indicated by the macro name.
+ */
+#define fit_fill_xy(dev, x, y, w, h)\
+ BEGIN\
+ if ( (x | y) < 0 ) {\
+ if ( x < 0 )\
+ w += x, x = 0;\
+ if ( y < 0 )\
+ h += y, y = 0;\
+ }\
+ END
+#define fit_fill_y(dev, y, h)\
+ BEGIN\
+ if ( y < 0 )\
+ h += y, y = 0;\
+ END
+#define fit_fill_w(dev, x, w)\
+ BEGIN\
+ if ( w > dev->width - x )\
+ w = dev->width - x;\
+ END
+#define fit_fill_h(dev, y, h)\
+ BEGIN\
+ if ( h > dev->height - y )\
+ h = dev->height - y;\
+ END
+#define fit_fill_xywh(dev, x, y, w, h)\
+ BEGIN\
+ fit_fill_xy(dev, x, y, w, h);\
+ fit_fill_w(dev, x, w);\
+ fit_fill_h(dev, y, h);\
+ END
+/*
+ * Clip all edges, and return from the procedure if the result is empty.
+ */
+#define fit_fill(dev, x, y, w, h)\
+ BEGIN\
+ fit_fill_xywh(dev, x, y, w, h);\
+ if ( w <= 0 || h <= 0 )\
+ return 0;\
+ END
+
+/*
+ * For driver procedures that copy bitmaps (e.g., copy_mono, copy_color),
+ * clipping the destination region also may require adjusting the pointer to
+ * the source data. In addition to dev, x, y, w, and h, the clipping macros
+ * for these procedures reference data, data_x, raster, and id; they may
+ * modify the values of data, data_x, and id.
+ *
+ * Clip the edges indicated by the macro name.
+ */
+#define fit_copy_xyw(dev, data, data_x, raster, id, x, y, w, h)\
+ BEGIN\
+ if ( (x | y) < 0 ) {\
+ if ( x < 0 )\
+ w += x, data_x -= x, x = 0;\
+ if ( y < 0 )\
+ h += y, data -= y * raster, id = gx_no_bitmap_id, y = 0;\
+ }\
+ if ( w > dev->width - x )\
+ w = dev->width - x;\
+ END
+/*
+ * Clip all edges, and return from the procedure if the result is empty.
+ */
+#define fit_copy(dev, data, data_x, raster, id, x, y, w, h)\
+ BEGIN\
+ fit_copy_xyw(dev, data, data_x, raster, id, x, y, w, h);\
+ if ( h > dev->height - y )\
+ h = dev->height - y;\
+ if ( w <= 0 || h <= 0 )\
+ return 0;\
+ END
+
+/* ---------------- Media parameters ---------------- */
+
+/* Define the InputAttributes and OutputAttributes of a device. */
+/* The device get_params procedure would call these. */
+
+typedef struct gdev_input_media_s {
+ float PageSize[4]; /* nota bene */
+ const char *MediaColor;
+ float MediaWeight;
+ const char *MediaType;
+} gdev_input_media_t;
+
+#define gdev_input_media_default_values { 0, 0, 0, 0 }, 0, 0, 0
+extern const gdev_input_media_t gdev_input_media_default;
+
+void gdev_input_media_init(P1(gdev_input_media_t * pim));
+
+int gdev_begin_input_media(P3(gs_param_list * mlist, gs_param_dict * pdict,
+ int count));
+
+int gdev_write_input_page_size(P4(int index, gs_param_dict * pdict,
+ floatp width_points, floatp height_points));
+
+int gdev_write_input_media(P3(int index, gs_param_dict * pdict,
+ const gdev_input_media_t * pim));
+
+int gdev_end_input_media(P2(gs_param_list * mlist, gs_param_dict * pdict));
+
+typedef struct gdev_output_media_s {
+ const char *OutputType;
+} gdev_output_media_t;
+
+#define gdev_output_media_default_values 0
+extern const gdev_output_media_t gdev_output_media_default;
+
+int gdev_begin_output_media(P3(gs_param_list * mlist, gs_param_dict * pdict,
+ int count));
+
+int gdev_write_output_media(P3(int index, gs_param_dict * pdict,
+ const gdev_output_media_t * pom));
+
+int gdev_end_output_media(P2(gs_param_list * mlist, gs_param_dict * pdict));
+
+#endif /* gxdevice_INCLUDED */
diff --git a/pstoraster/gxdevmem.h b/pstoraster/gxdevmem.h
new file mode 100644
index 000000000..c10d3d667
--- /dev/null
+++ b/pstoraster/gxdevmem.h
@@ -0,0 +1,170 @@
+/* Copyright (C) 1989, 1995, 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$ */
+/* Requires gxdevice.h */
+
+#ifndef gxdevmem_INCLUDED
+# define gxdevmem_INCLUDED
+
+/*
+ * A 'memory' device is essentially a stored bitmap.
+ * There are several different kinds: 1-bit black and white,
+ * 2-, 4-, and 8-bit mapped color, 16- and 24-bit RGB color,
+ * and 32-bit CMYK color. (16-bit uses 5/6/5 bits per color.)
+ * All use the same structure, since it's so awkward to get the effect of
+ * subclasses in C.
+ *
+ * Memory devices come in two flavors: standard, which always stores bytes
+ * big-endian, and word-oriented, which stores bytes in the machine order
+ * within 32-bit "words". The source data for copy_mono and
+ * copy_color must be in big-endian order, and since memory devices
+ * also are guaranteed to allocate the bitmap consecutively,
+ * the bitmap of a standard memory device can serve directly as input
+ * to copy_mono or copy_color operations. This is not true of word-oriented
+ * memory devices, which are provided only in response to a request by
+ * a customer with their own image processing library that uses this format.
+ */
+#ifndef gx_device_memory_DEFINED
+# define gx_device_memory_DEFINED
+typedef struct gx_device_memory_s gx_device_memory;
+
+#endif
+
+struct gx_device_memory_s {
+ gx_device_forward_common; /* (see gxdevice.h) */
+ gs_matrix initial_matrix; /* the initial transformation */
+ uint raster; /* bytes per scan line, */
+ /* filled in by 'open' */
+ bool foreign_bits; /* if true, bits are not in */
+ /* GC-able space */
+ byte *base;
+ byte **line_ptrs; /* scan line pointers */
+#define scan_line_base(dev,y) ((dev)->line_ptrs[y])
+ /* If the bitmap_memory pointer is non-zero, it is used for */
+ /* allocating the bitmap when the device is opened, */
+ /* and freeing it when the device is closed. */
+ gs_memory_t *bitmap_memory;
+ /* Following is used for mapped color, */
+ /* including 1-bit devices (to specify polarity). */
+ gs_const_string palette; /* RGB triples */
+ /* Following is only used for 24-bit color. */
+ struct _c24 {
+ gx_color_index rgb; /* cache key */
+ bits32 rgbr, gbrg, brgb; /* cache value */
+ } color24;
+ /* Following are only used for alpha buffers. */
+ /* The client initializes those marked with $; */
+ /* they don't change after initialization. */
+ gs_log2_scale_point log2_scale; /* $ oversampling scale factors */
+ int log2_alpha_bits; /* $ log2 of # of alpha bits being produced */
+ int mapped_x; /* $ X value mapped to buffer X=0 */
+ int mapped_y; /* lowest Y value mapped to buffer */
+ int mapped_height; /* # of Y values mapped to buffer */
+ int mapped_start; /* local Y value corresponding to mapped_y */
+ gx_color_index save_color; /* last (only) color displayed */
+};
+
+extern_st(st_device_memory);
+#define public_st_device_memory() /* in gdevmem.c */\
+ gs_public_st_composite(st_device_memory, gx_device_memory,\
+ "gx_device_memory", device_memory_enum_ptrs, device_memory_reloc_ptrs)
+#define st_device_memory_max_ptrs (st_device_forward_max_ptrs + 2)
+#define mem_device_init_private\
+ { identity_matrix_body }, /* initial matrix (filled in) */\
+ 0, /* raster (filled in) */\
+ true, /* foreign_bits (default) */\
+ (byte *)0, /* base (filled in) */\
+ (byte **)0, /* line_ptrs (filled in by mem_open) */\
+ 0, /* bitmap_memory */\
+ { (byte *)0, 0 }, /* palette (filled in for color) */\
+ { gx_no_color_index }, /* color24 */\
+ { 0, 0 }, 0, /* scale, log2_alpha_bits */\
+ 0, 0, 0, 0, /* mapped_* */\
+ gx_no_color_index /* save_color */
+
+/*
+ * Memory devices may have special setup requirements.
+ * In particular, it may not be obvious how much space to allocate
+ * for the bitmap. Here is the routine that computes this
+ * from the width and height.
+ */
+ulong gdev_mem_data_size(P3(const gx_device_memory *, int, int));
+
+#define gdev_mem_bitmap_size(mdev)\
+ gdev_mem_data_size(mdev, (mdev)->width, (mdev)->height)
+/*
+ * Do the inverse computation: given the device width and a buffer size,
+ * compute the maximum height.
+ */
+int gdev_mem_max_height(P3(const gx_device_memory *, int, ulong));
+
+/*
+ * Compute the raster (data bytes per line) similarly.
+ */
+#define gdev_mem_raster(mdev)\
+ gx_device_raster((const gx_device *)(mdev), true)
+
+/* Determine 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(P1(int));
+
+/* Determine the word-oriented memory device for a given depth. */
+const gx_device_memory *gdev_mem_word_device_for_bits(P1(int));
+
+/* Make a memory device. */
+/* mem is 0 if the device is temporary and local, */
+/* or the allocator that was used to allocate it if it is a real object. */
+/* page_device is 1 if the device should be a page device, */
+/* 0 if it should propagate this property from its target, or */
+/* -1 if it should not be a page device. */
+void gs_make_mem_mono_device(P3(gx_device_memory * mdev, gs_memory_t * mem,
+ gx_device * target));
+void gs_make_mem_device(P5(gx_device_memory * mdev,
+ const gx_device_memory * mdproto,
+ gs_memory_t * mem, int page_device,
+ gx_device * target));
+void gs_make_mem_abuf_device(P6(gx_device_memory * adev, gs_memory_t * mem,
+ gx_device * target,
+ const gs_log2_scale_point * pscale,
+ int alpha_bits, int mapped_x));
+void gs_make_mem_alpha_device(P4(gx_device_memory * adev, gs_memory_t * mem,
+ gx_device * target, int alpha_bits));
+
+/*
+ * Open a memory device, only setting line pointers to a subset of its
+ * scan lines. Banding devices use this (see gxclread.c).
+ */
+int gdev_mem_open_scan_lines(P2(gx_device_memory *mdev, int setup_height));
+
+/* Define whether a monobit memory device is inverted (black=1). */
+void gdev_mem_mono_set_inverted(P2(gx_device_memory * mdev, bool black_is_1));
+
+/* Test whether a device is a memory device. */
+bool gs_device_is_memory(P1(const gx_device *));
+
+/* Test whether a device is an alpha-buffering device. */
+bool gs_device_is_abuf(P1(const gx_device *));
+
+#endif /* gxdevmem_INCLUDED */
diff --git a/pstoraster/gxdevrop.h b/pstoraster/gxdevrop.h
new file mode 100644
index 000000000..037fb33f6
--- /dev/null
+++ b/pstoraster/gxdevrop.h
@@ -0,0 +1,35 @@
+/* Copyright (C) 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$ */
+/* Extension of gxdevice.h for RasterOp */
+
+#ifndef gxdevrop_INCLUDED
+# define gxdevrop_INCLUDED
+
+/* Define an unaligned implementation of [strip_]copy_rop. */
+dev_proc_copy_rop(gx_copy_rop_unaligned);
+dev_proc_strip_copy_rop(gx_strip_copy_rop_unaligned);
+
+#endif /* gxdevrop_INCLUDED */
diff --git a/pstoraster/gxdht.h b/pstoraster/gxdht.h
new file mode 100644
index 000000000..cceda256d
--- /dev/null
+++ b/pstoraster/gxdht.h
@@ -0,0 +1,272 @@
+/* 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$ */
+/* Definition of device halftones */
+
+#ifndef gxdht_INCLUDED
+# define gxdht_INCLUDED
+
+#include "gsrefct.h"
+#include "gscsepnm.h"
+#include "gxarith.h" /* for igcd */
+#include "gxhttype.h"
+
+/*
+ * We represent a halftone tile as a rectangular super-cell consisting of
+ * multiple copies of a multi-cell whose corners lie on integral
+ * coordinates, which in turn is a parallelogram (normally square) array of
+ * basic parallelogram (normally square) cells whose corners lie on rational
+ * coordinates.
+ *
+ * Let T be the aspect ratio (ratio of physical pixel height to physical
+ * pixel width), which is abs(xx/yy) for portrait devices and abs(yx/xy) for
+ * landscape devices. We characterize the basic cell by four rational
+ * numbers U(') = M(')/R(') and V(') = N(')/R(') where R(') is positive, at
+ * least one of U and V (and the corresponding one of U' and V') is
+ * non-zero, and U' is approximately U/T and V' is approximately V*T; these
+ * numbers define the vertices of the basic cell at device space coordinates
+ * (0,0), (U,V), (U-V',U'+V), and (-V',U'); then the multi-cell is defined
+ * similarly by M(') and N('). From these definitions, the basic cell has
+ * an area of B = U*U' + V*V' = (M*M' + N*N') / R*R' pixels, and the
+ * multi-cell has an area of C = B * R*R' = M*M' + N*N' pixels.
+ *
+ * If the coefficients of the default device transformation matrix are xx,
+ * xy, yx, and yy, then U and V are related to the frequency F and the angle
+ * A by:
+ * P = 72 / F;
+ * U = P * (xx * cos(A) + yx * sin(A));
+ * V = P * (xy * cos(A) + yy * sin(A)).
+ *
+ * We can tile the plane with any rectangular super-cell that consists of
+ * repetitions of the multi-cell and whose corners coincide with multi-cell
+ * coordinates (0,0). We observe that for any integers i, j such that i*N -
+ * j*M' = 0, a multi-cell corner lies on the X axis at W = i*M + j*N';
+ * similarly, if i'*M - j'*N' = 0, a corner lies on the Y axis at W' = i'*N
+ * + j'*M'. Then the super-cell occupies Z = W * W' pixels, consisting of Z
+ * / C multi-cells or Z / B basic cells. The trick in all this is to find
+ * values of F and A that aren't too far from the requested ones, and that
+ * yield a manageably small value for Z.
+ *
+ * Note that the super-cell only has to be so large because we want to use
+ * it directly to tile the plane. In fact, we can decompose it into W' / D
+ * horizontal strips of width W and height D, shifted horizontally with
+ * respect to each other by S pixels, where we compute S by finding h and k
+ * such that h*N - k*M' = D and then S = h*M + k*N'. The halftone setup
+ * routines only generate a single strip of samples, and let
+ * gx_ht_construct_spot_order construct the rest. If W' is large, we
+ * actually keep only one strip, and let the strip_tile_rectangle routines
+ * do the shifting at rendering time.
+ */
+typedef struct gx_ht_cell_params_s {
+ /* Defining values. M * M1 != 0 or N * N1 != 0; R > 0, R1 > 0. */
+ /* R and D are short rather than ushort so that we don't get */
+ /* unsigned results from arithmetic. */
+ short M, N, R;
+ short M1, N1, R1;
+ /* Derived values. */
+ ulong C;
+ short D, D1;
+ uint W, W1;
+ int S;
+} gx_ht_cell_params_t;
+
+/* Compute the derived values from the defining values. */
+void gx_compute_cell_values(P1(gx_ht_cell_params_t *));
+
+/*
+ * The whitening order is represented by a pair of arrays.
+ * The levels array contains an integer (an index into the bits array)
+ * for each distinct halftone level, indicating how many pixels should be
+ * whitened for that level; levels[0] = 0, levels[i] <= levels[i+1], and
+ * levels[num_levels-1] <= num_bits.
+ * The bits array contains an (offset,mask) pair for each pixel in the tile.
+ * bits[i].offset is the (properly aligned) byte index of a pixel
+ * in the tile; bits[i].mask is the mask to be or'ed into this byte and
+ * following ones. This is arranged so it will work properly on
+ * either big- or little-endian machines, and with different mask widths.
+ */
+/* The mask width must be at least as wide as uint, */
+/* and must not be wider than the width implied by align_bitmap_mod. */
+typedef uint ht_mask_t;
+
+#define ht_mask_bits (sizeof(ht_mask_t) * 8)
+typedef struct gx_ht_bit_s {
+ uint offset;
+ ht_mask_t mask;
+} gx_ht_bit;
+
+/* During sampling, bits[i].mask is used to hold a normalized sample value. */
+typedef ht_mask_t ht_sample_t;
+
+/* The following awkward expression avoids integer overflow. */
+#define max_ht_sample (ht_sample_t)(((1 << (ht_mask_bits - 2)) - 1) * 2 + 1)
+
+/*
+ * Define the internal representation of a halftone order.
+ * Note that it may include a cached transfer function.
+ *
+ * Halftone orders exist in two slightly different configurations, strip and
+ * complete. In a complete order, shift = 0 and full_height = height; in a
+ * strip order, shift != 0 and full_height is the height of a fully expanded
+ * halftone made up of enough shifted strip copies to get back to a zero
+ * shift. In other words, full_height is a cached value, but it is an
+ * important one, since it is the modulus used for computing the
+ * tile-relative phase. Requirements:
+ * width > 0, height > 0, multiple > 0
+ * raster >= bitmap_raster(width)
+ * 0 <= shift < width
+ * num_bits = width * height
+ * For complete orders:
+ * full_height = height
+ * For strip orders:
+ * full_height = height * width / gcd(width, shift)
+ * Note that during the sampling of a complete spot halftone, these
+ * invariants may be violated; in particular, it is possible that shift != 0
+ * and height < full_height, even though num_bits and num_levels reflect the
+ * full height. In this case, the invariant is restored (by resetting
+ * shift and height) when sampling is finished. However, we must save the
+ * original height and shift values used for sampling, since sometimes we
+ * run the "finishing" routines more than once. (This is ugly, but it's
+ * too hard to fix.)
+ *
+ * See gxbitmap.h for more details about strip halftones.
+ */
+typedef struct gx_ht_cache_s gx_ht_cache;
+
+#ifndef gx_ht_order_DEFINED
+# define gx_ht_order_DEFINED
+typedef struct gx_ht_order_s gx_ht_order;
+
+#endif
+struct gx_ht_order_s {
+ gx_ht_cell_params_t params; /* parameters defining the cells */
+ ushort width;
+ ushort height;
+ ushort raster;
+ ushort shift;
+ ushort orig_height;
+ ushort orig_shift;
+ uint full_height;
+ uint num_levels; /* = levels size */
+ uint num_bits; /* = bits size = width * height */
+ uint *levels;
+ gx_ht_bit *bits;
+ gx_ht_cache *cache; /* cache to use */
+ gx_transfer_map *transfer; /* TransferFunction or 0 */
+};
+
+#define ht_order_is_complete(porder)\
+ ((porder)->shift == 0)
+#define ht_order_full_height(porder)\
+ ((porder)->shift == 0 ? (porder)->height :\
+ (porder)->width / igcd((porder)->width, (porder)->shift) *\
+ (porder)->height)
+
+/* We only export st_ht_order for use in st_screen_enum. */
+extern_st(st_ht_order);
+#define public_st_ht_order() /* in gsht.c */\
+ gs_public_st_ptrs4(st_ht_order, gx_ht_order, "gx_ht_order",\
+ ht_order_enum_ptrs, ht_order_reloc_ptrs, levels, bits, cache, transfer)
+#define st_ht_order_max_ptrs 4
+
+/*
+ * Define a device halftone. This consists of one or more orders.
+ * If components = 0, then order is the only current halftone screen
+ * (set by setscreen, Type 1 sethalftone, Type 3 sethalftone, or
+ * Type 5 sethalftone with only a Default). Otherwise, order is the
+ * gray or black screen (for gray/RGB or CMYK devices respectively),
+ * and components is an array of gx_ht_order_components parallel to
+ * the components of the client halftone (set by setcolorscreen or
+ * Type 5 sethalftone).
+ *
+ * Multi-component halftone orders may be required even in Level 1 systems,
+ * because they are needed for setcolorscreen.
+ *
+ * NOTE: it is assumed that all subsidiary structures of device halftones
+ * (the components array, and the bits, levels, cache, and transfer members
+ * of any gx_ht_orders, both the default order and any component orders) are
+ * allocated with the same allocator as the device halftone itself.
+ */
+typedef struct gx_ht_order_component_s {
+ gx_ht_order corder;
+ gs_ht_separation_name cname;
+} gx_ht_order_component;
+
+#define private_st_ht_order_component() /* in gsht.c */\
+ gs_private_st_ptrs_add0(st_ht_order_component, gx_ht_order_component,\
+ "gx_ht_order_component", ht_order_component_enum_ptrs,\
+ ht_order_component_reloc_ptrs, st_ht_order, corder)
+#define st_ht_order_component_max_ptrs st_ht_order_max_ptrs
+/* We only export st_ht_order_component_element for use in banding. */
+extern_st(st_ht_order_component_element);
+#define public_st_ht_order_comp_element() /* in gsht.c */\
+ gs_public_st_element(st_ht_order_component_element, gx_ht_order_component,\
+ "gx_ht_order_component[]", ht_order_element_enum_ptrs,\
+ ht_order_element_reloc_ptrs, st_ht_order_component)
+
+#ifndef gx_device_halftone_DEFINED
+# define gx_device_halftone_DEFINED
+typedef struct gx_device_halftone_s gx_device_halftone;
+
+#endif
+
+/*
+ * color_indices is a cache that gives the indices in components of
+ * the screens for the 1, 3, or 4 primary color(s). These indices are
+ * always in the same order, namely:
+ * -,-,-,W(gray)
+ * R,G,B,-
+ * C,M,Y,K
+ */
+struct gx_device_halftone_s {
+ gx_ht_order order; /* must be first, for subclassing */
+ rc_header rc;
+ gs_id id; /* the id changes whenever the data change */
+ /*
+ * We have to keep the halftone type so that we can pass it
+ * through the band list for gx_imager_dev_ht_install.
+ */
+ gs_halftone_type type;
+ gx_ht_order_component *components;
+ uint num_comp;
+ /* The following are computed from the above. */
+ uint color_indices[4];
+ int lcm_width, lcm_height; /* LCM of primary color tile sizes, */
+ /* max_int if overflowed */
+};
+
+extern_st(st_device_halftone);
+#define public_st_device_halftone() /* in gsht.c */\
+ gs_public_st_ptrs_add1(st_device_halftone, gx_device_halftone,\
+ "gx_device_halftone", device_halftone_enum_ptrs,\
+ device_halftone_reloc_ptrs, st_ht_order, order, components)
+#define st_device_halftone_max_ptrs (st_ht_order_max_ptrs + 1)
+
+/* Release a gx_device_halftone by freeing its components. */
+/* (Don't free the gx_device_halftone itself.) */
+void gx_device_halftone_release(P2(gx_device_halftone * pdht,
+ gs_memory_t * mem));
+
+#endif /* gxdht_INCLUDED */
diff --git a/pstoraster/gxdither.c b/pstoraster/gxdither.c
new file mode 100644
index 000000000..b76b4fae1
--- /dev/null
+++ b/pstoraster/gxdither.c
@@ -0,0 +1,502 @@
+/* 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$ */
+#include "gx.h"
+#include "gsstruct.h"
+#include "gsdcolor.h"
+#include "gxdevice.h"
+#include "gxlum.h"
+#include "gxcmap.h"
+#include "gxdither.h"
+#include "gzht.h"
+
+/*
+ * The procedures in this file use halftoning (if necessary)
+ * to implement a given device color that has already gone through
+ * the transfer function. There are two major cases: gray and color.
+ * Gray halftoning always uses a binary screen. Color halftoning
+ * uses either a fast algorithm with a binary screen that produces
+ * relatively poor approximations, or a very slow algorithm with a
+ * general colored screen (or screens) that faithfully implements
+ * the Adobe specifications.
+ */
+
+/* Tables for fast computation of fractional color levels. */
+/* We have to put the table before any uses of it because of a bug */
+/* in the VAX C compiler. */
+/* We have to split up the definition of the table itself because of a bug */
+/* in the IBM AIX 3.2 C compiler. */
+private const gx_color_value
+ q0[] =
+{0};
+private const gx_color_value
+ q1[] =
+{0, frac_color_(1, 1)};
+private const gx_color_value
+ q2[] =
+{0, frac_color_(1, 2), frac_color_(2, 2)};
+private const gx_color_value
+ q3[] =
+{0, frac_color_(1, 3), frac_color_(2, 3), frac_color_(3, 3)};
+private const gx_color_value
+ q4[] =
+{0, frac_color_(1, 4), frac_color_(2, 4), frac_color_(3, 4), frac_color_(4, 4)};
+private const gx_color_value
+ q5[] =
+{0, frac_color_(1, 5), frac_color_(2, 5), frac_color_(3, 5), frac_color_(4, 5), frac_color_(5, 5)};
+private const gx_color_value
+ q6[] =
+{0, frac_color_(1, 6), frac_color_(2, 6), frac_color_(3, 6), frac_color_(4, 6), frac_color_(5, 6), frac_color_(6, 6)};
+private const gx_color_value
+ q7[] =
+{0, frac_color_(1, 7), frac_color_(2, 7), frac_color_(3, 7), frac_color_(4, 7), frac_color_(5, 7), frac_color_(6, 7), frac_color_(7, 7)};
+
+/* We export fc_color_quo for the fractional_color macro in gzht.h. */
+const gx_color_value *const fc_color_quo[8] =
+{q0, q1, q2, q3, q4, q5, q6, q7};
+
+/* Render a gray, possibly by halftoning. */
+int
+gx_render_device_gray(frac gray, gx_color_value alpha, gx_device_color * pdevc,
+ gx_device * dev, const gx_device_halftone * pdht,
+ const gs_int_point * ht_phase)
+{
+ bool cmyk = dev->color_info.num_components == 4;
+
+/* Make a special check for black and white. */
+ if (alpha == gx_max_color_value) {
+ gx_color_value lum;
+
+ switch (gray) {
+ case frac_0:
+ lum = 0;
+ goto bw;
+ case frac_1:
+ lum = gx_max_color_value;
+ bw:color_set_pure(pdevc,
+ (cmyk ?
+ gx_map_cmyk_color(dev, 0, 0, 0,
+ gx_max_color_value - lum) :
+ gx_map_rgb_color(dev, lum, lum, lum)));
+ return 0;
+ default:
+ ;
+ }
+ }
+/* get a few handy values */
+ {
+ uint max_value = dev->color_info.dither_grays - 1;
+ unsigned long hsize = (unsigned)pdht->order.num_levels;
+ unsigned long nshades = hsize * max_value + 1;
+ unsigned long lx = (nshades * gray) / (frac_1_long + 1);
+ uint v = lx / hsize;
+ gx_color_value lum = fractional_color(v, max_value);
+ gx_color_index color1;
+ int level = lx % hsize;
+
+ /* The following should be a conditional expression, */
+ /* but the DECStation 3100 Ultrix 4.3 compiler */
+ /* generates bad code for it. */
+#define set_color_lum(col, lum)\
+ if ( cmyk )\
+ col = gx_map_cmyk_color(dev, 0, 0, 0,\
+ gx_max_color_value - lum);\
+ else if ( alpha == gx_max_color_value )\
+ col = gx_map_rgb_color(dev, lum, lum, lum);\
+ else\
+ col = gx_map_rgb_alpha_color(dev, lum, lum, lum, alpha)
+ set_color_lum(color1, lum);
+ if_debug5('c', "[c]gray=0x%x --> (%d+%d/%lu)/%d\n",
+ (unsigned)gray, v, level, hsize, max_value + 1);
+ if (level == 0) { /* Close enough to a pure color, */
+ /* no dithering needed. */
+ color_set_pure(pdevc, color1);
+ return 0;
+ } else {
+ gx_color_index color2;
+
+ v++;
+ lum = fractional_color(v, max_value);
+ set_color_lum(color2, lum);
+ color_set_binary_halftone(pdevc, pdht,
+ color1, color2, level);
+ color_set_phase_mod(pdevc, ht_phase->x, ht_phase->y,
+ pdht->order.width,
+ pdht->order.full_height);
+ return 1;
+ }
+ }
+}
+
+/*
+ * Color dithering for Ghostscript. The underlying device imaging model
+ * supports dithering between two colors to generate intermediate shades.
+ *
+ * If the device has high quality colors (at least 32 values
+ * per axis), we ask it to map the color directly.
+ *
+ * Otherwise, things are a bit more complicated. If the device
+ * supports N shades of each R, G and B independently, there are a total
+ * of N*N*N colors. These colors form a 3-D grid in a cubical color
+ * space. The following dithering technique works by locating the
+ * color we want in this 3-D color grid and finding the eight colors
+ * that surround it. In the case of dithering into 8 colors with 1
+ * bit for each red, green and blue, these eight colors will always
+ * be the same.
+ *
+ * Now we consider all possible diagonal paths between the eight colors
+ * and chose the path that runs closest to our desired color in 3-D
+ * color space. There are 28 such paths. Then we find the position
+ * on the path that is closest to our color.
+ *
+ * The search is made faster by always reflecting our color into
+ * the bottom octant of the cube and comparing it to 7 paths.
+ * After the best path and the best position on that path are found,
+ * the results are reflected back into the original color space.
+ *
+ * NOTE: This code has been tested for B/W and Color imaging with
+ * 1, 2, 3 and 8 bits per component.
+ *
+ * --- original code by Paul Haeberli @ Silicon Graphics - 1990
+ * --- extensively revised by L. Peter Deutsch, Aladdin Enterprises
+ *
+ * lpd 3/14/94: added support for CMYK.
+ */
+
+/*
+ * The weights are arbitrary, as long as their ratios are correct
+ * and they will fit into the difference between a ulong and a frac
+ * with room to spare. By making WEIGHT1 and WEIGHT4 powers of 2,
+ * we can turn some multiplies into shifts.
+ */
+#define WNUM 128000
+#define WEIGHT1 (ulong)(WNUM/1000) /* 1.0 */
+#define WEIGHT2 (ulong)(WNUM/1414) /* 1/sqrt(2.0) */
+#define WEIGHT3 (ulong)(WNUM/1732) /* 1/sqrt(3.0) */
+#define WEIGHT4 (ulong)(WNUM/2000) /* 1/sqrt(4.0) */
+
+#define DIAG_R (0x1)
+#define DIAG_G (0x2)
+#define DIAG_B (0x4)
+#define DIAG_W (0x8)
+#define DIAG_RG (0x3)
+#define DIAG_GB (0x6)
+#define DIAG_BR (0x5)
+#define DIAG_RGB (0x7)
+#define DIAG_RGBW (0xf)
+
+/* What should we do about the W/K component? For the moment, */
+/* we ignore it in the luminance computation. */
+#define lum_white_weight 0
+private const unsigned short lum_w[16] =
+{
+ (0 * lum_blue_weight + 0 * lum_green_weight + 0 * lum_red_weight + 0 * lum_white_weight),
+ (0 * lum_blue_weight + 0 * lum_green_weight + 1 * lum_red_weight + 0 * lum_white_weight),
+ (0 * lum_blue_weight + 1 * lum_green_weight + 0 * lum_red_weight + 0 * lum_white_weight),
+ (0 * lum_blue_weight + 1 * lum_green_weight + 1 * lum_red_weight + 0 * lum_white_weight),
+ (1 * lum_blue_weight + 0 * lum_green_weight + 0 * lum_red_weight + 0 * lum_white_weight),
+ (1 * lum_blue_weight + 0 * lum_green_weight + 1 * lum_red_weight + 0 * lum_white_weight),
+ (1 * lum_blue_weight + 1 * lum_green_weight + 0 * lum_red_weight + 0 * lum_white_weight),
+ (1 * lum_blue_weight + 1 * lum_green_weight + 1 * lum_red_weight + 0 * lum_white_weight),
+ (0 * lum_blue_weight + 0 * lum_green_weight + 0 * lum_red_weight + 1 * lum_white_weight),
+ (0 * lum_blue_weight + 0 * lum_green_weight + 1 * lum_red_weight + 1 * lum_white_weight),
+ (0 * lum_blue_weight + 1 * lum_green_weight + 0 * lum_red_weight + 1 * lum_white_weight),
+ (0 * lum_blue_weight + 1 * lum_green_weight + 1 * lum_red_weight + 1 * lum_white_weight),
+ (1 * lum_blue_weight + 0 * lum_green_weight + 0 * lum_red_weight + 1 * lum_white_weight),
+ (1 * lum_blue_weight + 0 * lum_green_weight + 1 * lum_red_weight + 1 * lum_white_weight),
+ (1 * lum_blue_weight + 1 * lum_green_weight + 0 * lum_red_weight + 1 * lum_white_weight),
+ (1 * lum_blue_weight + 1 * lum_green_weight + 1 * lum_red_weight + 1 * lum_white_weight)
+};
+
+/* Render RGB or CMYK, possibly by halftoning. */
+/* If we are rendering RGB, white is ignored. */
+/* If we are rendering CMYK, red/green/blue/white are actually */
+/* cyan/magenta/yellow/black. */
+int
+gx_render_device_color(frac red, frac green, frac blue, frac white, bool cmyk,
+ gx_color_value alpha, gx_device_color * pdevc, gx_device * dev,
+ const gx_device_halftone * pdht, const gs_int_point * ht_phase)
+{
+ uint max_value = dev->color_info.dither_colors - 1;
+ uint num_levels = pdht->order.num_levels;
+ frac rem_r, rem_g, rem_b, rem_w;
+ uint r, g, b, w;
+ gx_color_value vr, vg, vb, vw;
+
+#define map_color_rgb()\
+ (alpha == gx_max_color_value ?\
+ gx_map_rgb_color(dev, vr, vg, vb) :\
+ gx_map_rgb_alpha_color(dev, vr, vg, vb, alpha))
+#define map_color_cmyk()\
+ gx_map_cmyk_color(dev, vr, vg, vb, vw)
+#define map_color()\
+ (cmyk ? map_color_cmyk() : map_color_rgb())
+
+ /* Compute the quotient and remainder of each color component */
+ /* with the actual number of available colors. */
+ switch (max_value) {
+ case 1: /* 8 or 16 colors */
+ if (red == frac_1)
+ rem_r = 0, r = 1;
+ else
+ rem_r = red, r = 0;
+ if (green == frac_1)
+ rem_g = 0, g = 1;
+ else
+ rem_g = green, g = 0;
+ if (blue == frac_1)
+ rem_b = 0, b = 1;
+ else
+ rem_b = blue, b = 0;
+ if (white == frac_1)
+ rem_w = 0, w = 1;
+ else
+ rem_w = white, w = 0;
+ break;
+ default:
+ {
+ ulong want_r, want_g, want_b, want_w;
+ want_r = (ulong) max_value *red;
+
+ r = frac_1_quo(want_r);
+ rem_r = frac_1_rem(want_r, r);
+ want_g = (ulong) max_value *green;
+
+ g = frac_1_quo(want_g);
+ rem_g = frac_1_rem(want_g, g);
+ want_b = (ulong) max_value *blue;
+
+ b = frac_1_quo(want_b);
+ rem_b = frac_1_rem(want_b, b);
+ want_w = (ulong) max_value *white;
+
+ w = frac_1_quo(want_w);
+ rem_w = frac_1_rem(want_w, w);
+ }
+ }
+
+ /* Check for no dithering required */
+ if (!(rem_r | rem_g | rem_b | rem_w)) {
+ vr = fractional_color(r, max_value);
+ vg = fractional_color(g, max_value);
+ vb = fractional_color(b, max_value);
+ vw = fractional_color(w, max_value);
+ color_set_pure(pdevc, map_color());
+ return 0;
+ }
+ if_debug12('c', "[c]rgbw=0x%x,0x%x,0x%x,0x%x -->\n %x+0x%x,%x+0x%x,%x+0x%x,%x+0x%x -->\n",
+ (unsigned)red, (unsigned)green, (unsigned)blue, (unsigned)white,
+ (unsigned)r, (unsigned)rem_r, (unsigned)g, (unsigned)rem_g,
+ (unsigned)b, (unsigned)rem_b, (unsigned)w, (unsigned)rem_w);
+
+ /* Dithering is required. Choose between two algorithms. */
+
+ if (pdht->components != 0 && dev->color_info.depth >= 4) { /* Someone went to the trouble of setting different */
+ /* screens for the different components. */
+ /* Use the slow, general colored halftone algorithm. */
+#define rgb_rem(rem_v, i)\
+ (rem_v * (ulong)(pdht->components[pdht->color_indices[i]].corder.num_levels) / frac_1)
+ uint lr = rgb_rem(rem_r, 0), lg = rgb_rem(rem_g, 1), lb = rgb_rem(rem_b, 2);
+
+ if (cmyk)
+ color_set_cmyk_halftone(pdevc, pdht, r, lr, g, lg, b, lb,
+ w, rgb_rem(rem_w, 3));
+ else
+ color_set_rgb_halftone(pdevc, pdht, r, lr, g, lg, b, lb, alpha);
+ color_set_phase_mod(pdevc, ht_phase->x, ht_phase->y,
+ pdht->lcm_width, pdht->lcm_height);
+#undef rgb_rem
+ return 1;
+ }
+ /* Fast, approximate binary halftone algorithm. */
+
+ {
+ ulong hsize = num_levels;
+ int adjust_r, adjust_b, adjust_g, adjust_w;
+ gx_color_index color1;
+ frac amax, amin;
+ ulong fmax, cmax;
+ int axisc, facec, cubec, diagc;
+ unsigned short lum_invert;
+ ulong dot1, dot2, dot3, dot4;
+ int level;
+ int code;
+
+/* Flip the remainder color into the 0, 0, 0 octant. */
+ lum_invert = 0;
+#define half (frac_1/2)
+ if (rem_r > half)
+ rem_r = frac_1 - rem_r,
+ adjust_r = -1, r++, lum_invert += lum_red_weight * 2;
+ else
+ adjust_r = 1;
+ if (rem_g > half)
+ rem_g = frac_1 - rem_g,
+ adjust_g = -1, g++, lum_invert += lum_green_weight * 2;
+ else
+ adjust_g = 1;
+ if (rem_b > half)
+ rem_b = frac_1 - rem_b,
+ adjust_b = -1, b++, lum_invert += lum_blue_weight * 2;
+ else
+ adjust_b = 1;
+ vr = fractional_color(r, max_value);
+ vg = fractional_color(g, max_value);
+ vb = fractional_color(b, max_value);
+ if (cmyk) {
+ if (rem_w > half)
+ rem_w = frac_1 - rem_w,
+ adjust_w = -1, b++, lum_invert += lum_white_weight * 2;
+ else
+ adjust_w = 1;
+ vw = fractional_color(w, max_value);
+ color1 = map_color_cmyk();
+ } else
+ color1 = map_color_rgb();
+
+/*
+ * Dot the color with each axis to find the best one of 15;
+ * find the color at the end of the axis chosen.
+ */
+ cmax = (ulong) rem_r + rem_g + rem_b;
+ dot4 = cmax + rem_w;
+ if (rem_g > rem_r) {
+ if (rem_b > rem_g)
+ amax = rem_b, axisc = DIAG_B;
+ else
+ amax = rem_g, axisc = DIAG_G;
+ if (rem_b > rem_r)
+ amin = rem_r, fmax = (ulong) rem_g + rem_b, facec = DIAG_GB;
+ else
+ amin = rem_b, fmax = (ulong) rem_r + rem_g, facec = DIAG_RG;
+ } else {
+ if (rem_b > rem_r)
+ amax = rem_b, axisc = DIAG_B;
+ else
+ amax = rem_r, axisc = DIAG_R;
+ if (rem_b > rem_g)
+ amin = rem_g, fmax = (ulong) rem_b + rem_r, facec = DIAG_BR;
+ else
+ amin = rem_b, fmax = (ulong) rem_r + rem_g, facec = DIAG_RG;
+ }
+ if (rem_w > amin) {
+ cmax = fmax + rem_w, cubec = facec + DIAG_W;
+ if (rem_w > amax)
+ fmax = (ulong) amax + rem_w, facec = axisc + DIAG_W,
+ amax = rem_w, axisc = DIAG_W;
+ else if (rem_w > fmax - amax)
+ fmax = (ulong) amax + rem_w, facec = axisc + DIAG_W;
+ } else
+ cubec = DIAG_RGB;
+
+ dot1 = amax * WEIGHT1;
+ dot2 = fmax * WEIGHT2;
+ dot3 = cmax * WEIGHT3;
+ /*dot4 see above */
+#define use_axis()\
+ diagc = axisc, level = (hsize * amax + (frac_1_long / 2)) / frac_1_long
+#define use_face()\
+ diagc = facec, level = (hsize * fmax + frac_1_long) / (2 * frac_1_long)
+#define use_cube()\
+ diagc = cubec, level = (hsize * cmax + (3 * frac_1_long / 2)) / (3 * frac_1_long)
+#define use_tesseract()\
+ diagc = DIAG_RGBW, level = (hsize * dot4 + (2 * frac_1_long)) / (4 * frac_1_long)
+ if (dot1 > dot2) {
+ if (dot3 > dot1) {
+ if (dot4 * WEIGHT4 > dot3)
+ use_tesseract();
+ else
+ use_cube();
+ } else {
+ if (dot4 * WEIGHT4 > dot1)
+ use_tesseract();
+ else
+ use_axis();
+ }
+ } else {
+ if (dot3 > dot2) {
+ if (dot4 * WEIGHT4 > dot3)
+ use_tesseract();
+ else
+ use_cube();
+ } else {
+ if (dot4 * WEIGHT4 > dot2)
+ use_tesseract();
+ else
+ use_face();
+ }
+ };
+
+ if_debug12('c', " %x+0x%x,%x+0x%x,%x+0x%x,%x+0x%x; adjust=%d,%d,%d,%d\n",
+ (unsigned)r, (unsigned)rem_r, (unsigned)g, (unsigned)rem_g,
+ (unsigned)b, (unsigned)rem_b, (unsigned)w, (unsigned)rem_w,
+ adjust_r, adjust_g, adjust_b, adjust_w);
+
+ if (level == 0) {
+ color_set_pure(pdevc, color1);
+ code = 0;
+ } else {
+ gx_color_index color2;
+
+/* construct the second color, inverting back to original space if needed */
+ if (diagc & DIAG_R)
+ r += adjust_r;
+ if (diagc & DIAG_G)
+ g += adjust_g;
+ if (diagc & DIAG_B)
+ b += adjust_b;
+/* get the second device color, sorting by luminance */
+ vr = fractional_color(r, max_value);
+ vg = fractional_color(g, max_value);
+ vb = fractional_color(b, max_value);
+ if (cmyk) {
+ if (diagc & DIAG_W)
+ w += adjust_w;
+ vw = fractional_color(w, max_value);
+ color2 = map_color_cmyk();
+ } else
+ color2 = map_color_rgb();
+ if (level == num_levels) { /* This can only happen through rounding.... */
+ color_set_pure(pdevc, color2);
+ code = 0;
+ } else {
+ if (lum_w[diagc] < lum_invert)
+ color_set_binary_halftone(pdevc, pdht, color2, color1, hsize - level);
+ else
+ color_set_binary_halftone(pdevc, pdht, color1, color2, level);
+ color_set_phase_mod(pdevc, ht_phase->x, ht_phase->y,
+ pdht->order.width,
+ pdht->order.full_height);
+ code = 1;
+ }
+ }
+
+ if_debug7('c', "[c]diagc=%d; colors=0x%lx,0x%lx; level=%d/%d; lum=%d,diag=%d\n",
+ diagc, (ulong) pdevc->colors.binary.color[0],
+ (ulong) pdevc->colors.binary.color[1],
+ level, (unsigned)hsize, lum_invert, lum_w[diagc]);
+ return code;
+ }
+}
diff --git a/pstoraster/gxdither.h b/pstoraster/gxdither.h
new file mode 100644
index 000000000..803333f32
--- /dev/null
+++ b/pstoraster/gxdither.h
@@ -0,0 +1,76 @@
+/* Copyright (C) 1994, 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$ */
+/* Interface to gxdither.c */
+
+#ifndef gxdither_INCLUDED
+# define gxdither_INCLUDED
+
+#ifndef gx_device_halftone_DEFINED
+# define gx_device_halftone_DEFINED
+typedef struct gx_device_halftone_s gx_device_halftone;
+
+#endif
+
+/*
+ * Note that in the procedures below, the colors are specified by fracs,
+ * but the alpha value is a gx_color_value. This is a design flaw that
+ * we might be able to fix eventually.
+ */
+
+/* Render a gray, possibly by halftoning. */
+/* Return 0 if complete, 1 if caller must do gx_color_load, <0 on error. */
+int gx_render_device_gray(P6(frac gray, gx_color_value alpha,
+ gx_device_color * pdevc, gx_device * dev,
+ const gx_device_halftone * dev_ht,
+ const gs_int_point * ht_phase));
+
+#define gx_render_gray_alpha(gray, alpha, pdevc, pis, dev, select)\
+ gx_render_device_gray(gray, alpha, pdevc, dev, pis->dev_ht,\
+ &pis->screen_phase[select])
+#define gx_render_gray(gray, pdevc, pis, dev, select)\
+ gx_render_gray_alpha(gray, pis->alpha, pdevc, pis, dev, select)
+
+/* Render a color, possibly by halftoning. */
+/* Return as for gx_render_[device_]gray. */
+int gx_render_device_color(P10(frac red, frac green, frac blue, frac white,
+ bool cmyk, gx_color_value alpha,
+ gx_device_color * pdevc, gx_device * dev,
+ const gx_device_halftone * pdht,
+ const gs_int_point * ht_phase));
+
+#define gx_render_color_alpha(r, g, b, w, a, cmyk, pdevc, pis, dev, select)\
+ gx_render_device_color(r, g, b, w, cmyk, a, pdevc, dev,\
+ pis->dev_ht, &pis->screen_phase[select])
+#define gx_render_color(r, g, b, w, cmyk, pdevc, pis, dev, select)\
+ gx_render_color_alpha(r, g, b, w, pis->alpha, cmyk, pdevc, pis, dev, select)
+#define gx_render_rgb(r, g, b, pdevc, pis, dev, select)\
+ gx_render_color(r, g, b, frac_0, false, pdevc, pis, dev, select)
+#define gx_render_cmyk(c, m, y, k, pdevc, pis, dev, select)\
+ gx_render_color(c, m, y, k, true, pdevc, pis, dev, select)
+#define gx_render_rgb_alpha(r, g, b, a, pdevc, pis, dev, select)\
+ gx_render_color_alpha(r, g, b, frac_0, a, false, pdevc, pis, dev, select)
+
+#endif /* gxdither_INCLUDED */
diff --git a/pstoraster/gxfarith.h b/pstoraster/gxfarith.h
new file mode 100644
index 000000000..002d0187a
--- /dev/null
+++ b/pstoraster/gxfarith.h
@@ -0,0 +1,144 @@
+/* Copyright (C) 1993, 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$ */
+/* Floating point arithmetic macros for Ghostscript library */
+
+#ifndef gxfarith_INCLUDED
+# define gxfarith_INCLUDED
+
+#include "gconfigv.h" /* for USE_FPU */
+#include "gxarith.h"
+
+/*
+ * The following macros replace the ones in gxarith.h on machines
+ * that are likely to have very slow floating point.
+ *
+ * None of these macros would be necessary if compilers had a clue
+ * about generating good floating point comparisons on machines with
+ * slow (or no) floating point hardware.
+ */
+
+# if USE_FPU <= 0 && arch_floats_are_IEEE && (arch_sizeof_float == arch_sizeof_int || arch_sizeof_float == arch_sizeof_long)
+
+# if arch_sizeof_float == arch_sizeof_int
+typedef int _f_int_t;
+typedef uint _f_uint_t;
+
+# else /* arch_sizeof_float == arch_sizeof_long */
+typedef long _f_int_t;
+typedef ulong _f_uint_t;
+
+# endif
+# define _f_as_int(f) *(_f_int_t *)(&(f))
+# define _f_as_uint(f) *(_f_uint_t *)(&(f))
+
+# if arch_sizeof_double == arch_sizeof_int
+# define _d_int_t int
+# else
+# if arch_sizeof_double == arch_sizeof_long
+# define _d_int_t long
+# endif
+# endif
+# define _d_uint_t unsigned _d_int_t
+# define _d_as_int(f) *(_d_int_t *)(&(d))
+# define _d_as_uint(f) *(_d_uint_t *)(&(d))
+
+# define _ftest(v,f,n)\
+ (sizeof(v)==sizeof(float)?(f):(n))
+# ifdef _d_int_t
+# define _fdtest(v,f,d,n)\
+ (sizeof(v)==sizeof(float)?(f):sizeof(v)==sizeof(double)?(d):(n))
+# else
+# define _fdtest(v,f,d,n)\
+ _ftest(v,f,n)
+# endif
+
+# undef is_fzero
+# define is_fzero(f) /* must handle both +0 and -0 */\
+ _fdtest(f, (_f_as_int(f) << 1) == 0, (_d_as_int(f) << 1) == 0,\
+ (f) == 0.0)
+
+# undef is_fzero2
+# define is_fzero2(f1,f2)\
+ (sizeof(f1) == sizeof(float) && sizeof(f2) == sizeof(float) ?\
+ ((_f_as_int(f1) | _f_as_int(f2)) << 1) == 0 :\
+ (f1) == 0.0 && (f2) == 0.0)
+
+# undef is_fneg
+# if arch_is_big_endian
+# define _is_fnegb(f) (*(byte *)&(f) >= 0x80)
+# else
+# define _is_fnegb(f) (((byte *)&(f))[sizeof(f) - 1] >= 0x80)
+# endif
+# if arch_sizeof_float == arch_sizeof_int
+# define is_fneg(f)\
+ (sizeof(f) == sizeof(float) ? _f_as_int(f) < 0 :\
+ _is_fnegb(f))
+# else
+# define is_fneg(f) _is_fnegb(f)
+# endif
+
+# define IEEE_expt 0x7f800000 /* IEEE exponent mask */
+# define IEEE_f1 0x3f800000 /* IEEE 1.0 */
+
+# undef is_fge1
+# if arch_sizeof_float == arch_sizeof_int
+# define is_fge1(f)\
+ (sizeof(f) == sizeof(float) ?\
+ (_f_as_int(f)) >= IEEE_f1 :\
+ (f) >= 1.0)
+# else /* arch_sizeof_float == arch_sizeof_long */
+# define is_fge1(f)\
+ (sizeof(f) == sizeof(float) ?\
+ (int)(_f_as_int(f) >> 16) >= (IEEE_f1 >> 16) :\
+ (f) >= 1.0)
+# endif
+
+# undef f_fits_in_ubits
+# undef f_fits_in_bits
+# define _f_bits(n) (4.0 * (1L << ((n) - 2)))
+# define f_fits_in_ubits(f, n)\
+ _ftest(f, _f_as_uint(f) < (_f_uint_t)IEEE_f1 + ((_f_uint_t)(n) << 23),\
+ (f) >= 0 && (f) < _f_bits(n))
+# define f_fits_in_bits(f, n)\
+ _ftest(f, (_f_as_uint(f) & IEEE_expt) < IEEE_f1 + ((_f_uint_t)((n)-1) << 23),\
+ (f) >= -_f_bits((n)-1) && (f) < _f_bits((n)-1))
+
+# endif /* USE_FPU <= 0 & ... */
+
+/*
+ * Define sine and cosine functions that take angles in degrees rather than
+ * radians, hit exact values at multiples of 90 degrees, and are implemented
+ * efficiently on machines with slow (or no) floating point.
+ */
+double gs_sin_degrees(P1(double angle));
+double gs_cos_degrees(P1(double angle));
+typedef struct gs_sincos_s {
+ double sin, cos;
+ bool orthogonal; /* angle is multiple of 90 degrees */
+} gs_sincos_t;
+void gs_sincos_degrees(P2(double angle, gs_sincos_t * psincos));
+
+#endif /* gxfarith_INCLUDED */
diff --git a/pstoraster/gxfcache.h b/pstoraster/gxfcache.h
new file mode 100644
index 000000000..93dbf657d
--- /dev/null
+++ b/pstoraster/gxfcache.h
@@ -0,0 +1,270 @@
+/* Copyright (C) 1992, 1995, 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$ */
+/* Requires gsfont.h */
+
+#ifndef gxfcache_INCLUDED
+# define gxfcache_INCLUDED
+
+#include "gsuid.h"
+#include "gsxfont.h"
+#include "gxbcache.h"
+#include "gxftype.h"
+
+/* ------ Font/matrix pair cache entry ------ */
+
+#ifndef cached_fm_pair_DEFINED
+# define cached_fm_pair_DEFINED
+typedef struct cached_fm_pair_s cached_fm_pair;
+
+#endif
+
+/*
+ * Define the entry for a cached (font,matrix) pair. If the UID
+ * is valid, the font pointer may be 0, since we keep entries even for
+ * fonts unloaded by a restore if they have valid UIDs; in this case,
+ * we also need the FontType as part of the key.
+ * Note that because of the dependency on StrokeWidth, we can't cache
+ * fonts with non-zero PaintType.
+ * We can't use the address of the pair for the hash value,
+ * since the GC may move pairs in storage, so we create a hash
+ * when we allocate the pair initially.
+ */
+struct cached_fm_pair_s {
+ gs_font *font; /* base font */
+ gs_uid UID; /* font UniqueID or XUID */
+ font_type FontType; /* (part of key if UID is valid) */
+ uint hash; /* hash for this pair */
+ float mxx, mxy, myx, myy; /* transformation */
+ int num_chars; /* # of cached chars with this */
+ /* f/m pair */
+ bool xfont_tried; /* true if we looked up an xfont */
+ gx_xfont *xfont; /* the xfont (if any) */
+ gs_memory_t *memory; /* the allocator for the xfont */
+ uint index; /* index of this pair in mdata */
+};
+
+#define private_st_cached_fm_pair() /* in gxccman.c */\
+ gs_private_st_ptrs3(st_cached_fm_pair, cached_fm_pair,\
+ "cached_fm_pair", fm_pair_enum_ptrs, fm_pair_reloc_ptrs,\
+ font, UID.xvalues, xfont)
+#define private_st_cached_fm_pair_elt() /* in gxccman.c */\
+ gs_private_st_element(st_cached_fm_pair_element, cached_fm_pair,\
+ "cached_fm_pair[]", fm_pair_element_enum_ptrs, fm_pair_element_reloc_ptrs,\
+ st_cached_fm_pair)
+/* If font == 0 and UID is invalid, this is a free entry. */
+#define fm_pair_is_free(pair)\
+ ((pair)->font == 0 && !uid_is_valid(&(pair)->UID))
+#define fm_pair_set_free(pair)\
+ ((pair)->font = 0, uid_set_invalid(&(pair)->UID))
+#define fm_pair_init(pair)\
+ (fm_pair_set_free(pair), (pair)->xfont_tried = false, (pair)->xfont = 0)
+
+/* The font/matrix pair cache itself. */
+typedef struct fm_pair_cache_s {
+ uint msize, mmax; /* # of cached font/matrix pairs */
+ cached_fm_pair *mdata;
+ uint mnext; /* rover for allocating font/matrix pairs */
+} fm_pair_cache;
+
+/* ------ Character cache entry ------- */
+
+/* Define the allocation chunk type. */
+typedef gx_bits_cache_chunk char_cache_chunk;
+
+/*
+ * This is a subclass of the entry in a general bitmap cache.
+ * The character cache contains both used and free blocks.
+ * All blocks have a common header; free blocks have ONLY the header.
+ */
+typedef gx_cached_bits_head cached_char_head;
+
+#define cc_head_is_free(cch) cb_head_is_free(cch)
+#define cc_head_set_free(cch) cb_head_set_free(cch)
+/*
+ * Define the cache entry for an individual character.
+ * The bits, if any, immediately follow the structure;
+ * characters with only xfont definitions may not have bits.
+ * An entry is 'real' if it is not free and if pair != 0.
+ * We maintain the invariant that at least one of the following must be true
+ * for all real entries:
+ * - cc_has_bits(cc);
+ * - cc->xglyph != gx_no_xglyph && cc_pair(cc)->xfont != 0.
+ */
+#ifndef cached_char_DEFINED
+# define cached_char_DEFINED
+typedef struct cached_char_s cached_char;
+
+#endif
+struct cached_char_s {
+
+ /* The code, font/matrix pair, wmode, and depth */
+ /* are the 'key' in the cache. */
+ /* gx_cached_bits_common includes depth. */
+
+ gx_cached_bits_common; /* (must be first) */
+#define cc_depth(cc) ((cc)->cb_depth)
+#define cc_set_depth(cc, d) ((cc)->cb_depth = (d))
+ cached_fm_pair *pair;
+#define cc_pair(cc) ((cc)->pair)
+#define cc_set_pair_only(cc, p) ((cc)->pair = (p))
+ gs_glyph code; /* glyph code */
+ byte wmode; /* writing mode (0 or 1) */
+
+ /* The following are neither 'key' nor 'value'. */
+
+ char_cache_chunk *chunk; /* chunk where this char */
+ /* is allocated */
+ uint loc; /* relative location in chunk */
+ uint pair_index; /* index of pair in mdata */
+
+ /* The rest of the structure is the 'value'. */
+ /* gx_cached_bits_common has width, height, raster, */
+ /* shift (not used here), id. */
+
+#define cc_raster(cc) ((cc)->raster)
+#define cc_set_raster(cc, r) ((cc)->raster = (r))
+ gx_xglyph xglyph; /* the xglyph for the xfont, if any */
+ gs_fixed_point wxy; /* width in device coords */
+ gs_fixed_point offset; /* (-llx, -lly) in device coords */
+};
+
+#define cc_is_free(cc) cc_head_is_free(&(cc)->head)
+#define cc_set_free(cc) cc_head_set_free(&(cc)->head)
+#define cc_set_pair(cc, p)\
+ ((cc)->pair_index = ((cc)->pair = (p))->index)
+#define cc_has_bits(cc) ((cc)->id != gx_no_bitmap_id)
+/*
+ * Memory management for cached_chars is a little unusual.
+ * cached_chars are never instantiated on their own; a pointer to
+ * a cached_char points into the middle of a cache chunk.
+ * Consequently, such pointers can't be traced or relocated
+ * in the usual way. What we do instead is allocate the cache
+ * outside garbage-collectable space; we do all the tracing and relocating
+ * of pointers *from* the cache (currently only the head.pair pointer)
+ * when we trace or relocate the font "directory" that owns the cache.
+ *
+ * Since cached_chars are (currently) never instantiated on their own,
+ * they only have a descriptor so that cached_char_ptr can trace them.
+ */
+#define private_st_cached_char() /* in gxccman.c */\
+ gs_private_st_composite(st_cached_char, cached_char, "cached_char",\
+ cached_char_enum_ptrs, cached_char_reloc_ptrs)
+#define private_st_cached_char_ptr() /* in gxccman.c */\
+ gs_private_st_composite(st_cached_char_ptr, cached_char *,\
+ "cached_char *", cc_ptr_enum_ptrs, cc_ptr_reloc_ptrs)
+#define private_st_cached_char_ptr_elt() /* in gxccman.c */\
+ gs_private_st_element(st_cached_char_ptr_element, cached_char *,\
+ "cached_char *[]", cc_ptr_element_enum_ptrs, cc_ptr_element_reloc_ptrs,\
+ st_cached_char_ptr)
+
+/*
+ * Define the alignment and size of the cache structures.
+ */
+#define align_cached_char_mod align_cached_bits_mod
+#define sizeof_cached_char\
+ round_up(sizeof(cached_char), align_cached_char_mod)
+#define cc_bits(cc) ((byte *)(cc) + sizeof_cached_char)
+#define cc_const_bits(cc) ((const byte *)(cc) + sizeof_cached_char)
+
+/* Define the hash index for a (glyph, fm_pair) key. */
+#define chars_head_index(glyph, pair)\
+ ((uint)(glyph) * 59 + (pair)->hash * 73) /* scramble it a bit */
+
+/* ------ Character cache ------ */
+
+/*
+ * So that we can find all the entries in the cache without
+ * following chains of pointers, we use open hashing rather than
+ * chained hashing for the lookup table.
+ */
+typedef struct char_cache_s {
+ /* gx_bits_cache_common provides chunks, cnext, */
+ /* bsize, csize. */
+ gx_bits_cache_common;
+ gs_memory_t *struct_memory;
+ gs_memory_t *bits_memory;
+ cached_char **table; /* hash table */
+ uint table_mask; /* (a power of 2 -1) */
+ uint bmax; /* max bsize */
+ uint cmax; /* max csize */
+ uint bspace; /* space allocated for chunks */
+ uint lower; /* min size at which cached chars */
+ /* should be stored compressed */
+ uint upper; /* max size of a single cached char */
+ gs_glyph_mark_proc_t mark_glyph;
+ void *mark_glyph_data; /* closure data */
+} char_cache;
+
+/* ------ Font/character cache ------ */
+
+/* A font "directory" (font/character cache manager). */
+struct gs_font_dir_s {
+
+ /* Original (unscaled) fonts */
+
+ gs_font *orig_fonts;
+
+ /* Scaled font cache */
+
+ gs_font *scaled_fonts; /* list of recently scaled fonts */
+ uint ssize, smax;
+
+ /* Font/matrix pair cache */
+
+ fm_pair_cache fmcache;
+
+ /* Character cache */
+
+ char_cache ccache;
+ /* Scanning cache for GC */
+ uint enum_index; /* index (N) */
+ uint enum_offset; /* ccache.table[offset] is N'th non-zero entry */
+};
+
+#define private_st_font_dir() /* in gsfont.c */\
+ gs_private_st_composite(st_font_dir, gs_font_dir, "gs_font_dir",\
+ font_dir_enum_ptrs, font_dir_reloc_ptrs)
+
+/* Enumerate the pointers in a font directory, except for orig_fonts. */
+#define font_dir_do_ptrs(m)\
+ /*m(-,orig_fonts)*/ m(0,scaled_fonts) m(1,fmcache.mdata)\
+ m(2,ccache.table) m(3,ccache.mark_glyph_data)
+#define st_font_dir_max_ptrs 4
+
+/* Character cache procedures (in gxccache.c and gxccman.c) */
+int gx_char_cache_alloc(P7(gs_memory_t * struct_mem, gs_memory_t * bits_mem,
+ gs_font_dir * pdir, uint bmax, uint mmax,
+ uint cmax, uint upper));
+void gx_char_cache_init(P1(gs_font_dir *));
+void gx_purge_selected_cached_chars(P3(gs_font_dir *, bool(*)(P2(cached_char *, void *)), void *));
+cached_fm_pair *
+ gx_lookup_fm_pair(P2(gs_font *, const gs_state *));
+cached_fm_pair *
+ gx_add_fm_pair(P4(gs_font_dir *, gs_font *, const gs_uid *, const gs_state *));
+void gx_lookup_xfont(P3(const gs_state *, cached_fm_pair *, int));
+void gs_purge_fm_pair(P3(gs_font_dir *, cached_fm_pair *, int));
+
+#endif /* gxfcache_INCLUDED */
diff --git a/pstoraster/gxfcmap.h b/pstoraster/gxfcmap.h
new file mode 100644
index 000000000..dc3d64a21
--- /dev/null
+++ b/pstoraster/gxfcmap.h
@@ -0,0 +1,101 @@
+/* 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$ */
+/* Internal CMap data definition */
+
+/* This file should be called gxcmap.h, except that name is already used. */
+
+#ifndef gxfcmap_INCLUDED
+# define gxfcmap_INCLUDED
+
+#include "gsfcmap.h"
+#include "gsuid.h"
+
+/*
+ * The main body of data in a CMap is two code maps, one for defined
+ * characters, one for notdefs. Each code map is a multi-level tree,
+ * one level per byte decoded from the input string. Each node of
+ * the tree may be:
+ * a character code (1-4 bytes)
+ * a character name (gs_glyph)
+ * a CID (gs_glyph)
+ * a subtree
+ */
+typedef enum {
+ cmap_char_code,
+ cmap_glyph, /* character name or CID */
+ cmap_subtree
+} gx_code_map_type;
+typedef struct gx_code_map_s gx_code_map;
+struct gx_code_map_s {
+ byte first; /* first char code covered by this node */
+ byte last; /* last char code ditto */
+ uint /*gx_code_map_type */ type:2;
+ uint num_bytes1:2; /* # of bytes -1 for char_code */
+ uint /*bool */ add_offset:1; /* if set, add char - first to ccode / glyph */
+ /* We would like to combine the two unions into a union of structs, */
+ /* but no compiler seems to do the right thing about packing. */
+ union bd_ {
+ byte font_index; /* for leaf, font index */
+ /* (only non-zero if rearranged font) */
+ byte count1; /* for subtree, # of entries -1 */
+ } byte_data;
+ union d_ {
+ gs_char ccode; /* num_bytes bytes */
+ gs_glyph glyph;
+ gx_code_map *subtree; /* [count] */
+ } data;
+ gs_cmap *cmap; /* point back to CMap for GC mark proc */
+};
+
+/* The GC information for a gx_code_map is complex, because names must be */
+/* traced. */
+extern_st(st_code_map);
+extern_st(st_code_map_element);
+#define public_st_code_map() /* in gsfcmap.c */\
+ gs_public_st_composite(st_code_map, gx_code_map, "gx_code_map",\
+ code_map_enum_ptrs, code_map_reloc_ptrs)
+#define public_st_code_map_element() /* in gsfcmap.c */\
+ gs_public_st_element(st_code_map_element, gx_code_map, "gx_code_map[]",\
+ code_map_elt_enum_ptrs, code_map_elt_reloc_ptrs, st_code_map)
+
+/* A CMap proper is relatively simple. */
+struct gs_cmap_s {
+ gs_cid_system_info CIDSystemInfo; /* must be first */
+ gs_uid uid;
+ int WMode;
+ gx_code_map def; /* defined characters (cmap_subtree) */
+ gx_code_map notdef; /* notdef characters (cmap_subtree) */
+ gs_glyph_mark_proc_t mark_glyph; /* glyph marking procedure for GC */
+ void *mark_glyph_data; /* closure data */
+};
+
+/*extern_st(st_cmap); */
+#define public_st_cmap() /* in gsfcmap.c */\
+ gs_public_st_suffix_add4(st_cmap, gs_cmap, "gs_cmap",\
+ cmap_enum_ptrs, cmap_reloc_ptrs, st_cid_system_info,\
+ uid.xvalues, def.data.subtree, notdef.data.subtree, mark_glyph_data)
+
+#endif /* gxfcmap_INCLUDED */
diff --git a/pstoraster/gxfill.c b/pstoraster/gxfill.c
new file mode 100644
index 000000000..caf23647e
--- /dev/null
+++ b/pstoraster/gxfill.c
@@ -0,0 +1,1543 @@
+/* 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$ */
+/* Lower-level path filling procedures */
+#include "math_.h" /* for floor in fixed_mult_quo */
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gxfixed.h"
+#include "gxdevice.h"
+#include "gzpath.h"
+#include "gzcpath.h"
+#include "gxdcolor.h"
+#include "gxhttile.h"
+#include "gxistate.h"
+#include "gxpaint.h" /* for prototypes */
+
+/* Define which fill algorithm(s) to use. */
+#define FILL_SCAN_LINES
+#define FILL_CURVES
+#define FILL_TRAPEZOIDS
+
+/* Define the structure for keeping track of active lines. */
+typedef struct active_line_s active_line;
+struct active_line_s {
+ gs_fixed_point start; /* x,y where line starts */
+ gs_fixed_point end; /* x,y where line ends */
+ gs_fixed_point diff; /* end - start */
+#define al_dx(alp) ((alp)->diff.x)
+#define al_dy(alp) ((alp)->diff.y)
+ fixed y_fast_max; /* can do x_at_y in fixed point */
+ /* if y <= y_fast_max */
+#define set_al_points(alp, startp, endp)\
+ (alp)->diff.x = (endp).x - (startp).x,\
+ (alp)->y_fast_max = max_fixed /\
+ (((alp)->diff.x >= 0 ? (alp)->diff.x : -(alp)->diff.x) | 1) + (startp).y,\
+ (alp)->diff.y = (endp).y - (startp).y,\
+ (alp)->start = startp, (alp)->end = endp
+#define al_x_at_y(alp, yv)\
+ ((yv) == (alp)->end.y ? (alp)->end.x :\
+ ((yv) <= (alp)->y_fast_max ?\
+ ((yv) - (alp)->start.y) * al_dx(alp) / al_dy(alp) :\
+ (INCR_EXPR(slow_x),\
+ fixed_mult_quo(al_dx(alp), (yv) - (alp)->start.y, al_dy(alp)))) +\
+ (alp)->start.x)
+ fixed x_current; /* current x position */
+ fixed x_next; /* x position at end of band */
+ const segment *pseg; /* endpoint of this line */
+ int direction; /* direction of line segment */
+#define dir_up 1
+#define dir_horizontal 0 /* (these are handled specially) */
+#define dir_down (-1)
+ int curve_k; /* # of subdivisions for curves, */
+ /* -1 for lines */
+ curve_cursor cursor; /* cursor for curves, */
+ /* unused for lines */
+/* "Pending" lines (not reached in the Y ordering yet) use next and prev */
+/* to order lines by increasing starting Y. "Active" lines (being scanned) */
+/* use next and prev to order lines by increasing current X, or if the */
+/* current Xs are equal, by increasing final X. */
+ active_line *prev, *next;
+/* Link together active_lines allocated individually */
+ active_line *alloc_next;
+};
+
+/*
+ * The active_line structure isn't really simple, but since its instances
+ * only exist temporarily during a fill operation, we don't have to
+ * worry about a garbage collection occurring.
+ */
+gs_private_st_simple(st_active_line, active_line, "active_line");
+
+/* Define the ordering criterion for active lines. */
+/* The xc argument is a copy of lp2->x_current. */
+#define x_precedes(lp1, lp2, xc)\
+ (lp1->x_current < xc || (lp1->x_current == xc &&\
+ (lp1->start.x > lp2->start.x || lp1->end.x < lp2->end.x)))
+
+#ifdef DEBUG
+/* Internal procedures for printing and checking active lines. */
+private void
+print_active_line(const char *label, const active_line * alp)
+{
+ dlprintf5("[f]%s 0x%lx(%d): x_current=%f x_next=%f\n",
+ label, (ulong) alp, alp->direction,
+ fixed2float(alp->x_current), fixed2float(alp->x_next));
+ dlprintf5(" start=(%f,%f) pt_end=0x%lx(%f,%f)\n",
+ fixed2float(alp->start.x), fixed2float(alp->start.y),
+ (ulong) alp->pseg,
+ fixed2float(alp->end.x), fixed2float(alp->end.y));
+ dlprintf2(" prev=0x%lx next=0x%lx\n",
+ (ulong) alp->prev, (ulong) alp->next);
+}
+private void
+print_line_list(const active_line * flp)
+{
+ const active_line *lp;
+
+ for (lp = flp; lp != 0; lp = lp->next) {
+ fixed xc = lp->x_current, xn = lp->x_next;
+
+ dlprintf3("[f]0x%lx(%d): x_current/next=%g",
+ (ulong) lp, lp->direction,
+ fixed2float(xc));
+ if (xn != xc)
+ dprintf1("/%g", fixed2float(xn));
+ dputc('\n');
+ }
+}
+#define print_al(label,alp)\
+ if ( gs_debug_c('F') ) print_active_line(label, alp)
+private int
+check_line_list(const active_line * flp)
+{
+ const active_line *alp;
+
+ if (flp != 0)
+ for (alp = flp->prev->next; alp != 0; alp = alp->next)
+ if (alp->next != 0 && alp->next->x_current < alp->x_current) {
+ lprintf("[f]Lines out of order!\n");
+ print_active_line(" 1:", alp);
+ print_active_line(" 2:", alp->next);
+ return_error(gs_error_Fatal);
+ }
+ return 0;
+}
+#else
+#define print_al(label,alp) DO_NOTHING
+#endif
+
+/* Line list structure */
+struct line_list_s {
+ gs_memory_t *memory;
+ active_line *active_area; /* allocated active_line list */
+ active_line *next_active; /* next allocation slot */
+ active_line *limit; /* limit of local allocation */
+ int close_count; /* # of added closing lines */
+ active_line *y_list; /* Y-sorted list of pending lines */
+ active_line *y_line; /* most recently inserted line */
+ active_line x_head; /* X-sorted list of active lines */
+#define x_list x_head.next
+ /* Put the arrays last so the scalars will have */
+ /* small displacements. */
+ /* Allocate a few active_lines locally */
+ /* to avoid round trips through the allocator. */
+#if arch_small_memory
+# define max_local_active 5 /* don't overburden the stack */
+#else
+# define max_local_active 20
+#endif
+ active_line local_active[max_local_active];
+};
+typedef struct line_list_s line_list;
+typedef line_list *ll_ptr;
+
+/* Forward declarations */
+private void init_line_list(P2(ll_ptr, gs_memory_t *));
+private void unclose_path(P2(gx_path *, int));
+private void free_line_list(P1(ll_ptr));
+private int add_y_list(P5(gx_path *, ll_ptr, fixed, fixed,
+ const gs_fixed_rect *));
+private int add_y_line(P4(const segment *, const segment *, int, ll_ptr));
+private void insert_x_new(P2(active_line *, ll_ptr));
+private bool end_x_line(P1(active_line *));
+
+#define fill_loop_proc(proc)\
+int proc(P11(ll_ptr, gx_device *,\
+ const gx_fill_params *, const gx_device_color *, gs_logical_operation_t,\
+ const gs_fixed_rect *, fixed, fixed, fixed, fixed, fixed))
+private fill_loop_proc(fill_loop_by_scan_lines);
+private fill_loop_proc(fill_loop_by_trapezoids);
+
+/* Statistics */
+#ifdef DEBUG
+struct stats_fill_s {
+ long
+ fill, fill_alloc, y_up, y_down, horiz, x_step, slow_x, iter, find_y,
+ band, band_step, band_fill, afill, slant, slant_shallow, sfill;
+} stats_fill;
+
+# define INCR(x) (++(stats_fill.x))
+# define INCR_EXPR(x) INCR(x)
+# define INCR_BY(x,n) (stats_fill.x += (n))
+#else
+# define INCR(x) DO_NOTHING
+# define INCR_EXPR(x) discard(0)
+# define INCR_BY(x,n) DO_NOTHING
+#endif
+
+/*
+ * This is the general path filling algorithm.
+ * It uses the center-of-pixel rule for filling.
+ * We can implement Microsoft's upper-left-corner-of-pixel rule
+ * by subtracting (0.5, 0.5) from all the coordinates in the path.
+ *
+ * The adjust parameters are a hack for keeping regions
+ * from coming out too faint: they specify an amount by which to expand
+ * the sides of every filled region.
+ * Setting adjust = fixed_half is supposed to produce the effect of Adobe's
+ * any-part-of-pixel rule, but it doesn't quite, because of the
+ * closed/open interval rule for regions. We detect this as a special case
+ * and do the slightly ugly things necessary to make it work.
+ */
+
+/*
+ * Tweak the fill adjustment if necessary so that (nearly) empty
+ * rectangles are guaranteed to produce some output. This is a hack
+ * to work around a bug in the Microsoft Windows PostScript driver,
+ * which draws thin lines by filling zero-width rectangles, and in
+ * some other drivers that try to fill epsilon-width rectangles.
+ */
+void
+gx_adjust_if_empty(const gs_fixed_rect * pbox, gs_fixed_point * adjust)
+{
+ const fixed
+ dx = pbox->q.x - pbox->p.x, dy = pbox->q.y - pbox->p.y;
+
+ if (dx < fixed_half && dy >= int2fixed(2)) {
+ adjust->x = arith_rshift_1(fixed_1 + fixed_epsilon - dx);
+ if_debug1('f', "[f]thin adjust_x=%g\n",
+ fixed2float(adjust->x));
+ } else if (dy < fixed_half && dx >= int2fixed(2)) {
+ adjust->y = arith_rshift_1(fixed_1 + fixed_epsilon - dy);
+ if_debug1('f', "[f]thin adjust_y=%g\n",
+ fixed2float(adjust->y));
+ }
+}
+
+/*
+ * Fill a path. This is the default implementation of the driver
+ * fill_path procedure.
+ */
+int
+gx_default_fill_path(gx_device * pdev, const gs_imager_state * pis,
+ gx_path * ppath, const gx_fill_params * params,
+ const gx_device_color * pdevc, const gx_clip_path * pcpath)
+{
+ gs_fixed_point adjust;
+
+#define adjust_x adjust.x
+#define adjust_y adjust.y
+ gs_logical_operation_t lop = pis->log_op;
+ gs_fixed_rect ibox, bbox;
+ gx_device_clip cdev;
+ gx_device *dev = pdev;
+ gx_device *save_dev = dev;
+ gx_path ffpath;
+ gx_path *pfpath;
+ int code;
+ fixed adjust_left, adjust_right, adjust_below, adjust_above;
+ int max_fill_band = dev->max_fill_band;
+
+#define no_band_mask ((fixed)(-1) << (sizeof(fixed) * 8 - 1))
+ bool fill_by_trapezoids;
+ line_list lst;
+
+ adjust = params->adjust;
+ /*
+ * Compute the bounding box before we flatten the path.
+ * This can save a lot of time if the path has curves.
+ * If the path is neither fully within nor fully outside
+ * the quick-check boxes, we could recompute the bounding box
+ * and make the checks again after flattening the path,
+ * but right now we don't bother.
+ */
+ gx_path_bbox(ppath, &ibox);
+ if (params->fill_zero_width)
+ gx_adjust_if_empty(&ibox, &adjust);
+ /* Check the bounding boxes. */
+ if_debug6('f', "[f]adjust=%g,%g bbox=(%g,%g),(%g,%g)\n",
+ fixed2float(adjust_x), fixed2float(adjust_y),
+ fixed2float(ibox.p.x), fixed2float(ibox.p.y),
+ fixed2float(ibox.q.x), fixed2float(ibox.q.y));
+ if (pcpath)
+ gx_cpath_inner_box(pcpath, &bbox);
+ else
+ (*dev_proc(dev, get_clipping_box)) (dev, &bbox);
+ if (!rect_within(ibox, bbox)) { /*
+ * Intersect the path box and the clip bounding box.
+ * If the intersection is empty, this fill is a no-op.
+ */
+ if (pcpath)
+ gx_cpath_outer_box(pcpath, &bbox);
+ if_debug4('f', " outer_box=(%g,%g),(%g,%g)\n",
+ fixed2float(bbox.p.x), fixed2float(bbox.p.y),
+ fixed2float(bbox.q.x), fixed2float(bbox.q.y));
+ rect_intersect(ibox, bbox);
+ if (ibox.p.x - adjust_x >= ibox.q.x + adjust_x ||
+ ibox.p.y - adjust_y >= ibox.q.y + adjust_y
+ ) { /* Intersection of boxes is empty! */
+ return 0;
+ }
+#undef adjust_x
+#undef adjust_y
+ /*
+ * The path is neither entirely inside the inner clip box
+ * nor entirely outside the outer clip box.
+ * If we had to flatten the path, this is where we would
+ * recompute its bbox and make the tests again,
+ * but we don't bother right now.
+ *
+ * If there is a clipping path, set up a clipping device.
+ */
+ if (pcpath) {
+ dev = (gx_device *) & cdev;
+ gx_make_clip_device(&cdev, &cdev, gx_cpath_list(pcpath));
+ cdev.target = save_dev;
+ cdev.max_fill_band = save_dev->max_fill_band;
+ (*dev_proc(dev, open_device)) (dev);
+ }
+ }
+ /*
+ * Compute the proper adjustment values.
+ * To get the effect of the any-part-of-pixel rule,
+ * we may have to tweak them slightly.
+ * NOTE: We changed the adjust_right/above value from 0.5+epsilon
+ * to 0.5 in release 5.01; even though this does the right thing
+ * in every case we could imagine, we aren't confident that it's
+ * correct. (The old values were definitely incorrect, since they
+ * caused 1-pixel-wide/high objects to color 2 pixels even if
+ * they fell exactly on pixel boundaries.)
+ */
+ if (adjust.x == fixed_half)
+ adjust_left = fixed_half - fixed_epsilon,
+ adjust_right = fixed_half /* + fixed_epsilon */ ; /* see above */
+ else
+ adjust_left = adjust_right = adjust.x;
+ if (adjust.y == fixed_half)
+ adjust_below = fixed_half - fixed_epsilon,
+ adjust_above = fixed_half /* + fixed_epsilon */ ; /* see above */
+ else
+ adjust_below = adjust_above = adjust.y;
+ /* Initialize the active line list. */
+ init_line_list(&lst, ppath->memory);
+ /*
+ * We have a choice of two different filling algorithms:
+ * scan-line-based and trapezoid-based. They compare as follows:
+ *
+ * Scan Trap
+ * ---- ----
+ * no +yes perfectly accurate Y adjustment
+ * skip +draw 0-height horizontal lines
+ * slow +fast rectangles
+ * +fast slow curves
+ * +yes no write pixels at most once
+ *
+ * Normally we use the scan line algorithm for characters, where
+ * curve speed is important and no Y adjustment is involved, and for
+ * non-idempotent RasterOps, where double pixel writing must be
+ * avoided, and the trapezoid algorithm otherwise.
+ */
+#define double_write_ok lop_is_idempotent(lop)
+#ifdef FILL_SCAN_LINES
+# ifdef FILL_TRAPEZOIDS
+ fill_by_trapezoids =
+ ((adjust_below | adjust_above) != 0 || !gx_path_has_curves(ppath) ||
+ params->flatness >= 1.0) && double_write_ok;
+# else
+ fill_by_trapezoids = false;
+# endif
+#else
+ fill_by_trapezoids = double_write_ok;
+#endif
+#undef double_write_ok
+ /*
+ * Pre-process curves. When filling by trapezoids, we need to
+ * flatten the path completely; when filling by scan lines, we only
+ * need to monotonize it, unless FILL_CURVES is undefined.
+ */
+ gx_path_init_local(&ffpath, ppath->memory);
+ if (!gx_path_has_curves(ppath)) /* don't need to flatten */
+ pfpath = ppath;
+ else
+#ifdef FILL_CURVES
+ if (fill_by_trapezoids) {
+ gx_path_init_local(&ffpath, ppath->memory);
+ code = gx_path_add_flattened_accurate(ppath, &ffpath,
+ params->flatness,
+ pis->accurate_curves);
+ if (code < 0)
+ return code;
+ pfpath = &ffpath;
+ } else if (gx_path_is_monotonic(ppath))
+ pfpath = ppath;
+ else {
+ gx_path_init_local(&ffpath, ppath->memory);
+ code = gx_path_add_monotonized(ppath, &ffpath);
+ if (code < 0)
+ return code;
+ pfpath = &ffpath;
+ }
+#else
+ {
+ gx_path_init_local(&ffpath, ppath->memory);
+ code = gx_path_add_flattened_accurate(ppath, &ffpath,
+ params->flatness,
+ pis->accurate_curves);
+ if (code < 0)
+ return code;
+ pfpath = &ffpath;
+ }
+#endif
+ if ((code = add_y_list(pfpath, &lst, adjust_below, adjust_above, &ibox)) < 0)
+ goto nope;
+ {
+ fill_loop_proc((*fill_loop));
+
+ /* Some short-sighted compilers won't allow a conditional here.... */
+ if (fill_by_trapezoids)
+ fill_loop = fill_loop_by_trapezoids;
+ else
+ fill_loop = fill_loop_by_scan_lines;
+ code = (*fill_loop)
+ (&lst, dev, params, pdevc, lop, &ibox,
+ adjust_left, adjust_right, adjust_below, adjust_above,
+ (max_fill_band == 0 ? no_band_mask : int2fixed(-max_fill_band)));
+ }
+ nope:if (lst.close_count != 0)
+ unclose_path(pfpath, lst.close_count);
+ free_line_list(&lst);
+ if (pfpath != ppath) /* had to flatten */
+ gx_path_free(pfpath, "gx_default_fill_path(flattened path)");
+#ifdef DEBUG
+ if (gs_debug_c('f')) {
+ dlputs("[f] # alloc up down horiz step slowx iter find band bstep bfill\n");
+ dlprintf5(" %5ld %5ld %5ld %5ld %5ld",
+ stats_fill.fill, stats_fill.fill_alloc,
+ stats_fill.y_up, stats_fill.y_down,
+ stats_fill.horiz);
+ dlprintf4(" %5ld %5ld %5ld %5ld",
+ stats_fill.x_step, stats_fill.slow_x,
+ stats_fill.iter, stats_fill.find_y);
+ dlprintf3(" %5ld %5ld %5ld\n",
+ stats_fill.band, stats_fill.band_step,
+ stats_fill.band_fill);
+ dlputs("[f] afill slant shall sfill\n");
+ dlprintf4(" %5ld %5ld %5ld %5ld\n",
+ stats_fill.afill, stats_fill.slant,
+ stats_fill.slant_shallow, stats_fill.sfill);
+ }
+#endif
+ return code;
+}
+
+/* Initialize the line list for a path. */
+private void
+init_line_list(ll_ptr ll, gs_memory_t * mem)
+{
+ ll->memory = mem;
+ ll->active_area = 0;
+ ll->next_active = ll->local_active;
+ ll->limit = ll->next_active + max_local_active;
+ ll->close_count = 0;
+ ll->y_list = 0;
+ ll->y_line = 0;
+ INCR(fill);
+}
+
+/* Unlink any line_close segments added temporarily. */
+private void
+unclose_path(gx_path * ppath, int count)
+{
+ subpath *psub;
+
+ for (psub = ppath->first_subpath; count != 0;
+ psub = (subpath *) psub->last->next
+ )
+ if (psub->last == (segment *) & psub->closer) {
+ segment *prev = psub->closer.prev, *next = psub->closer.next;
+
+ prev->next = next;
+ if (next)
+ next->prev = prev;
+ psub->last = prev;
+ count--;
+ }
+}
+
+/* Free the line list. */
+private void
+free_line_list(ll_ptr ll)
+{
+ gs_memory_t *mem = ll->memory;
+ active_line *alp;
+
+ /* Free any individually allocated active_lines. */
+ while ((alp = ll->active_area) != 0) {
+ active_line *next = alp->alloc_next;
+
+ gs_free_object(mem, alp, "active line");
+ ll->active_area = next;
+ }
+}
+
+/*
+ * Construct a Y-sorted list of segments for rasterizing a path. We assume
+ * the path is non-empty. Only include non-horizontal lines or (monotonic)
+ * curve segments where one endpoint is locally Y-minimal, and horizontal
+ * lines that might color some additional pixels.
+ */
+private int
+add_y_list(gx_path * ppath, ll_ptr ll, fixed adjust_below, fixed adjust_above,
+ const gs_fixed_rect * pbox)
+{
+ register segment *pseg = (segment *) ppath->first_subpath;
+ int close_count = 0;
+
+ /* fixed xmin = pbox->p.x; *//* not currently used */
+ fixed ymin = pbox->p.y;
+
+ /* fixed xmax = pbox->q.x; *//* not currently used */
+ fixed ymax = pbox->q.y;
+ int code;
+
+ while (pseg) { /* We know that pseg points to a subpath head (s_start). */
+ subpath *psub = (subpath *) pseg;
+ segment *plast = psub->last;
+ int dir = 2; /* hack to skip first segment */
+ int first_dir, prev_dir;
+ segment *prev;
+
+ if (plast->type != s_line_close) { /* Create a fake s_line_close */
+ line_close_segment *lp = &psub->closer;
+ segment *next = plast->next;
+
+ lp->next = next;
+ lp->prev = plast;
+ plast->next = (segment *) lp;
+ if (next)
+ next->prev = (segment *) lp;
+ lp->type = s_line_close;
+ lp->pt = psub->pt;
+ lp->sub = psub;
+ psub->last = plast = (segment *) lp;
+ ll->close_count++;
+ }
+ while ((prev_dir = dir, prev = pseg,
+ (pseg = pseg->next) != 0 && pseg->type != s_start)
+ ) { /*
+ * This element is either a line or a monotonic
+ * curve segment.
+ */
+ fixed iy = pseg->pt.y;
+ fixed py = prev->pt.y;
+
+ /*
+ * Segments falling entirely outside the ibox in Y
+ * are treated as though they were horizontal, *
+ * i.e., they are never put on the list.
+ */
+#define compute_dir(xo, xe, yo, ye)\
+ (ye > yo ? (ye <= ymin || yo >= ymax ? 0 : dir_up) :\
+ ye < yo ? (yo <= ymin || ye >= ymax ? 0 : dir_down) :\
+ 2)
+#define add_dir_lines(prev2, prev, this, pdir, dir)\
+ if ( pdir )\
+ { if ( (code = add_y_line(prev2, prev, pdir, ll)) < 0 ) return code; }\
+ if ( dir )\
+ { if ( (code = add_y_line(prev, this, dir, ll)) < 0 ) return code; }
+ dir = compute_dir(prev->pt.x, pseg->pt.x, py, iy);
+ if (dir == 2) { /* Put horizontal lines on the list */
+ /* if they would color any pixels. */
+ if (fixed2int_pixround(iy - adjust_below) <
+ fixed2int_pixround(iy + adjust_above)
+ ) {
+ INCR(horiz);
+ if ((code = add_y_line(prev, pseg,
+ dir_horizontal, ll)) < 0
+ )
+ return code;
+ }
+ dir = 0;
+ }
+ if (dir > prev_dir) {
+ add_dir_lines(prev->prev, prev, pseg, prev_dir, dir);
+ } else if (prev_dir == 2) /* first segment */
+ first_dir = dir;
+ if (pseg == plast) { /*
+ * We skipped the first segment of the
+ * subpath, so the last segment must receive
+ * special consideration. Note that we have
+ * `closed' all subpaths.
+ */
+ if (first_dir > dir) {
+ add_dir_lines(prev, pseg, psub->next,
+ dir, first_dir);
+ }
+ }
+ }
+#undef compute_dir
+#undef add_dir_lines
+ }
+ return close_count;
+}
+/*
+ * Internal routine to test a segment and add it to the pending list if
+ * appropriate.
+ */
+private int
+add_y_line(const segment * prev_lp, const segment * lp, int dir, ll_ptr ll)
+{
+ gs_fixed_point this, prev;
+ register active_line *alp = ll->next_active;
+ fixed y_start;
+
+ if (alp == ll->limit) { /* Allocate separately */
+ alp = gs_alloc_struct(ll->memory, active_line,
+ &st_active_line, "active line");
+ if (alp == 0)
+ return_error(gs_error_VMerror);
+ alp->alloc_next = ll->active_area;
+ ll->active_area = alp;
+ INCR(fill_alloc);
+ } else
+ ll->next_active++;
+ this.x = lp->pt.x;
+ this.y = lp->pt.y;
+ prev.x = prev_lp->pt.x;
+ prev.y = prev_lp->pt.y;
+ switch ((alp->direction = dir)) {
+ case dir_up:
+ y_start = prev.y;
+ set_al_points(alp, prev, this);
+ alp->pseg = lp;
+ break;
+ case dir_down:
+ y_start = this.y;
+ set_al_points(alp, this, prev);
+ alp->pseg = prev_lp;
+ break;
+ case dir_horizontal:
+ y_start = this.y; /* = prev.y */
+ alp->start = prev;
+ alp->end = this;
+ /* Don't need to set dx or y_fast_max */
+ alp->pseg = prev_lp; /* may not need this either */
+ break;
+ }
+ /* Insert the new line in the Y ordering */
+ {
+ register active_line *yp = ll->y_line;
+ register active_line *nyp;
+
+ if (yp == 0) {
+ alp->next = alp->prev = 0;
+ ll->y_list = alp;
+ } else if (y_start >= yp->start.y) { /* Insert the new line after y_line */
+ while (INCR_EXPR(y_up),
+ ((nyp = yp->next) != NULL &&
+ y_start > nyp->start.y)
+ )
+ yp = nyp;
+ alp->next = nyp;
+ alp->prev = yp;
+ yp->next = alp;
+ if (nyp)
+ nyp->prev = alp;
+ } else { /* Insert the new line before y_line */
+ while (INCR_EXPR(y_down),
+ ((nyp = yp->prev) != NULL &&
+ y_start < nyp->start.y)
+ )
+ yp = nyp;
+ alp->prev = nyp;
+ alp->next = yp;
+ yp->prev = alp;
+ if (nyp)
+ nyp->next = alp;
+ else
+ ll->y_list = alp;
+ }
+ }
+ ll->y_line = alp;
+ print_al("add ", alp);
+ return 0;
+}
+
+/* ---------------- Filling loop utilities ---------------- */
+
+/* Insert a newly active line in the X ordering. */
+private void
+insert_x_new(active_line * alp, ll_ptr ll)
+{
+ register active_line *next;
+ register active_line *prev = &ll->x_head;
+ register fixed x = alp->start.x;
+
+ alp->x_current = x;
+ while (INCR_EXPR(x_step),
+ (next = prev->next) != 0 && x_precedes(next, alp, x)
+ )
+ prev = next;
+ alp->next = next;
+ alp->prev = prev;
+ if (next != 0)
+ next->prev = alp;
+ prev->next = alp;
+}
+
+/* Handle a line segment that just ended. Return true iff this was */
+/* the end of a line sequence. */
+private bool
+end_x_line(active_line * alp)
+{
+ const segment *pseg = alp->pseg;
+
+ /*
+ * The computation of next relies on the fact that
+ * all subpaths have been closed. When we cycle
+ * around to the other end of a subpath, we must be
+ * sure not to process the start/end point twice.
+ */
+ const segment *next =
+ (alp->direction == dir_up ?
+ ( /* Upward line, go forward along path. */
+ pseg->type == s_line_close ? /* end of subpath */
+ ((const line_close_segment *)pseg)->sub->next :
+ pseg->next) :
+ ( /* Downward line, go backward along path. */
+ pseg->type == s_start ? /* start of subpath */
+ ((const subpath *)pseg)->last->prev :
+ pseg->prev)
+ );
+ gs_fixed_point npt;
+
+ npt.y = next->pt.y;
+ if_debug5('F', "[F]ended 0x%lx: pseg=0x%lx y=%f next=0x%lx npt.y=%f\n",
+ (ulong) alp, (ulong) pseg, fixed2float(pseg->pt.y),
+ (ulong) next, fixed2float(npt.y));
+ if (npt.y <= pseg->pt.y) { /* End of a line sequence */
+ active_line *nlp = alp->next;
+
+ alp->prev->next = nlp;
+ if (nlp)
+ nlp->prev = alp->prev;
+ if_debug1('F', "[F]drop 0x%lx\n", (ulong) alp);
+ return true;
+ }
+ alp->pseg = next;
+ npt.x = next->pt.x;
+ set_al_points(alp, alp->end, npt);
+ print_al("repl", alp);
+ return false;
+}
+
+#define loop_fill_rectangle(x, y, w, h)\
+ gx_fill_rectangle_device_rop(x, y, w, h, pdevc, dev, lop)
+#define loop_fill_rectangle_direct(x, y, w, h)\
+ (fill_direct ?\
+ (*fill_rect)(dev, x, y, w, h, cindex) :\
+ gx_fill_rectangle_device_rop(x, y, w, h, pdevc, dev, lop))
+
+/* ---------------- Scan line filling loop ---------------- */
+
+/* Forward references */
+private void set_scan_line_points(P2(active_line *, fixed));
+
+/* Main filling loop. */
+private int
+fill_loop_by_scan_lines(ll_ptr ll, gx_device * dev,
+ const gx_fill_params * params, const gx_device_color * pdevc,
+ gs_logical_operation_t lop, const gs_fixed_rect * pbox,
+ fixed adjust_left, fixed adjust_right,
+ fixed adjust_below, fixed adjust_above, fixed band_mask)
+{
+ int rule = params->rule;
+ fixed fixed_flat = float2fixed(params->flatness);
+ bool fill_direct = color_writes_pure(pdevc, lop);
+ gx_color_index cindex;
+
+ dev_proc_fill_rectangle((*fill_rect));
+ active_line *yll = ll->y_list;
+ fixed y_limit = pbox->q.y;
+ fixed y;
+
+ /*
+ * The meaning of adjust_below (B) and adjust_above (A) is that
+ * the pixels that would normally be painted at coordinate Y get
+ * "smeared" to coordinates Y-B through Y+A-epsilon, inclusive.
+ * This is equivalent to saying that the pixels actually painted
+ * at coordinate Y are those contributed by scan lines Y-A+epsilon
+ * through Y+B, inclusive, or up to Y+B+epsilon, half-open.
+ * (A = B = 0 is a special case, equivalent to B = 0, A = epsilon.)
+ */
+ fixed look_below =
+ (adjust_above == fixed_0 ? fixed_0 : adjust_above - fixed_epsilon);
+ fixed look_above =
+ adjust_below + fixed_epsilon;
+ fixed look_height = look_above + look_below;
+ bool do_adjust = look_height > fixed_epsilon;
+
+ if (yll == 0) /* empty list */
+ return 0;
+ if (fill_direct)
+ cindex = pdevc->colors.pure,
+ fill_rect = dev_proc(dev, fill_rectangle);
+#define next_pixel_center(y)\
+ (fixed_pixround(y) + fixed_half)
+ y = next_pixel_center(yll->start.y) - look_below; /* first Y sample point */
+ ll->x_list = 0;
+ ll->x_head.x_current = min_fixed; /* stop backward scan */
+ while (1) {
+ active_line *alp, *nlp;
+ fixed x;
+ fixed ya = y + look_height;
+
+ INCR(iter);
+ /* Move newly active lines from y to x list. */
+ while (yll != 0 && yll->start.y < ya) {
+ active_line *ynext = yll->next; /* insert smashes next/prev links */
+
+ if (yll->direction == dir_horizontal) { /* Ignore for now. */
+ } else {
+ insert_x_new(yll, ll);
+ set_scan_line_points(yll, fixed_flat);
+ }
+ yll = ynext;
+ }
+ /* Check whether we've reached the maximum y. */
+ if (y >= y_limit)
+ break;
+ if (ll->x_list == 0) { /* No active lines, skip to next start */
+ if (yll == 0)
+ break; /* no lines left */
+ y = next_pixel_center(yll->start.y) - look_below;
+ continue;
+ }
+ /* Update active lines to y. */
+ x = min_fixed;
+ for (alp = ll->x_list; alp != 0; alp = nlp) {
+ fixed nx;
+
+ nlp = alp->next;
+ e:if (alp->end.y <= y) {
+ if (end_x_line(alp))
+ continue;
+ set_scan_line_points(alp, fixed_flat);
+ goto e;
+ }
+ /* Note that if Y adjustment is in effect, */
+ /* alp->start.y might be greater than y. */
+ nx = alp->x_current =
+ (alp->start.y >= y ? alp->start.x :
+ alp->curve_k < 0 ?
+ al_x_at_y(alp, y) :
+ gx_curve_x_at_y(&alp->cursor, y));
+ if (nx < x) { /* Move this line backward in the list. */
+ active_line *ilp = alp;
+
+ while (nx < (ilp = ilp->prev)->x_current);
+ /* Now ilp->x_current <= nx < ilp->next->x_cur. */
+ alp->prev->next = alp->next;
+ if (alp->next)
+ alp->next->prev = alp->prev;
+ if (ilp->next)
+ ilp->next->prev = alp;
+ alp->next = ilp->next;
+ ilp->next = alp;
+ alp->prev = ilp;
+ continue;
+ }
+ x = nx;
+ }
+
+ /* Fill inside regions at y. */
+ {
+ int inside = 0;
+ int x1_prev = min_int;
+
+ /* rule = -1 for winding number rule, i.e. */
+ /* we are inside if the winding number is non-zero; */
+ /* rule = 1 for even-odd rule, i.e. */
+ /* we are inside if the winding number is odd. */
+#define inside_path_p() ((inside & rule) != 0)
+ INCR(band);
+ for (alp = ll->x_list; alp != 0; alp = alp->next) { /* We're outside a filled region. */
+ int x0 = fixed2int_pixround(alp->x_current -
+ adjust_left);
+
+ /*
+ * This doesn't handle lines that cross
+ * within the adjustment region, but it's a
+ * good start.
+ */
+ if (do_adjust && alp->end.x < alp->start.x) {
+ fixed xa = (alp->end.y < ya ? alp->end.x :
+ alp->curve_k < 0 ?
+ al_x_at_y(alp, ya) :
+ gx_curve_x_at_y(&alp->cursor,
+ ya));
+ int x0a = fixed2int_pixround(xa -
+ adjust_left);
+
+ if (x0a < x0)
+ x0 = x0a;
+ }
+ for (;;) { /* We're inside a filled region. */
+ print_al("step", alp);
+ INCR(band_step);
+ inside += alp->direction;
+ if (!inside_path_p())
+ break;
+ /*
+ * Since we're dealing with closed
+ * paths, the test for alp == 0
+ * shouldn't be needed, but we may have
+ * omitted lines that are to the right
+ * of the clipping region. */
+ if ((alp = alp->next) == 0)
+ goto out;
+ }
+#undef inside_path_p
+ /*
+ * We just went from inside to outside, so
+ * fill the region. Avoid writing pixels
+ * twice.
+ */
+
+ if (x0 < x1_prev)
+ x0 = x1_prev;
+ {
+ int x1 = fixed2int_rounded(alp->x_current +
+ adjust_right);
+
+ if (do_adjust && alp->end.x > alp->start.x) {
+ fixed xa = (alp->end.y < ya ?
+ alp->end.x :
+ alp->curve_k < 0 ?
+ al_x_at_y(alp, ya) :
+ gx_curve_x_at_y(&alp->cursor,
+ ya));
+ int x1a = fixed2int_rounded(xa +
+ adjust_right);
+
+ if (x1a > x1)
+ x1 = x1a;
+ }
+ if (x1 > x0) {
+ int code =
+ loop_fill_rectangle_direct(x0,
+ fixed2int_var(y),
+ x1 - x0, 1);
+
+ if_debug3('F', "[F]drawing [%d:%d),%d\n",
+ x0, x1, fixed2int_var(y));
+ if (code < 0)
+ return code;
+ x1_prev = x1;
+ }
+ }
+ }
+ out:;
+ }
+ y += fixed_1;
+ }
+ return 0;
+}
+
+private void
+set_scan_line_points(active_line * alp, fixed fixed_flat)
+{
+ const segment *pseg = alp->pseg;
+ const gs_fixed_point *pp0;
+
+ if (alp->direction < 0) {
+ pseg =
+ (pseg->type == s_line_close ?
+ ((const line_close_segment *)pseg)->sub->next :
+ pseg->next);
+ if (pseg->type != s_curve) {
+ alp->curve_k = -1;
+ return;
+ }
+ pp0 = &alp->end;
+ } else {
+ if (pseg->type != s_curve) {
+ alp->curve_k = -1;
+ return;
+ }
+ pp0 = &alp->start;
+ }
+#define pcseg ((const curve_segment *)pseg)
+ alp->curve_k =
+ gx_curve_log2_samples(pp0->x, pp0->y, pcseg, fixed_flat);
+ gx_curve_cursor_init(&alp->cursor, pp0->x, pp0->y, pcseg,
+ alp->curve_k);
+#undef pcseg
+}
+
+/* ---------------- Trapezoid filling loop ---------------- */
+
+/* Forward references */
+private int fill_slant_adjust(P12(fixed, fixed, fixed, fixed, fixed,
+ fixed, fixed, fixed, const gs_fixed_rect *,
+ const gx_device_color *, gx_device *, gs_logical_operation_t));
+private void resort_x_line(P1(active_line *));
+
+/****** PATCH ******/
+#define loop_fill_trapezoid_fixed(fx0, fw0, fy0, fx1, fw1, fh)\
+ loop_fill_trap(dev, fx0, fw0, fy0, fx1, fw1, fh, pbox, pdevc, lop)
+private int
+loop_fill_trap(gx_device * dev, fixed fx0, fixed fw0, fixed fy0,
+ fixed fx1, fixed fw1, fixed fh, const gs_fixed_rect * pbox,
+ const gx_device_color * pdevc, gs_logical_operation_t lop)
+{
+ fixed fy1 = fy0 + fh;
+ fixed ybot = max(fy0, pbox->p.y);
+ fixed ytop = min(fy1, pbox->q.y);
+ gs_fixed_edge left, right;
+
+ if (ybot >= ytop)
+ return 0;
+ left.start.y = right.start.y = fy0;
+ left.end.y = right.end.y = fy1;
+ right.start.x = (left.start.x = fx0) + fw0;
+ right.end.x = (left.end.x = fx1) + fw1;
+ return (*dev_proc(dev, fill_trapezoid))
+ (dev, &left, &right, ybot, ytop, false, pdevc, lop);
+}
+/****** END PATCH ******/
+
+/* Main filling loop. Takes lines off of y_list and adds them to */
+/* x_list as needed. band_mask limits the size of each band, */
+/* by requiring that ((y1 - 1) & band_mask) == (y0 & band_mask). */
+private int
+fill_loop_by_trapezoids(ll_ptr ll, gx_device * dev,
+ const gx_fill_params * params, const gx_device_color * pdevc,
+ gs_logical_operation_t lop, const gs_fixed_rect * pbox,
+ fixed adjust_left, fixed adjust_right,
+ fixed adjust_below, fixed adjust_above, fixed band_mask)
+{
+ int rule = params->rule;
+ const fixed y_limit = pbox->q.y;
+ active_line *yll = ll->y_list;
+ fixed y;
+ int code;
+ bool fill_direct = color_writes_pure(pdevc, lop);
+ gx_color_index cindex;
+
+ dev_proc_fill_rectangle((*fill_rect));
+/*
+ * Define a faster test for
+ * fixed2int_pixround(y - below) != fixed2int_pixround(y + above)
+ * where we know
+ * 0 <= below <= _fixed_pixround_v,
+ * 0 <= above <= min(fixed_half, fixed_1 - below).
+ * Subtracting out the integer parts, this is equivalent to
+ * fixed2int_pixround(fixed_fraction(y) - below) !=
+ * fixed2int_pixround(fixed_fraction(y) + above)
+ * or to
+ * fixed2int(fixed_fraction(y) + _fixed_pixround_v - below) !=
+ * fixed2int(fixed_fraction(y) + _fixed_pixround_v + above)
+ * Letting A = _fixed_pixround_v - below and B = _fixed_pixround_v + above,
+ * we can rewrite this as
+ * fixed2int(fixed_fraction(y) + A) != fixed2int(fixed_fraction(y) + B)
+ * Because of the range constraints given above, this is true precisely when
+ * fixed_fraction(y) + A < fixed_1 && fixed_fraction(y) + B >= fixed_1
+ * or equivalently
+ * fixed_fraction(y + B) < B - A.
+ * i.e.
+ * fixed_fraction(y + _fixed_pixround_v + above) < below + above
+ */
+ fixed y_span_delta = _fixed_pixround_v + adjust_above;
+ fixed y_span_limit = adjust_below + adjust_above;
+
+#define adjusted_y_spans_pixel(y)\
+ fixed_fraction((y) + y_span_delta) < y_span_limit
+
+ if (yll == 0)
+ return 0; /* empty list */
+ if (fill_direct)
+ cindex = pdevc->colors.pure,
+ fill_rect = dev_proc(dev, fill_rectangle);
+ y = yll->start.y; /* first Y value */
+ ll->x_list = 0;
+ ll->x_head.x_current = min_fixed; /* stop backward scan */
+ while (1) {
+ fixed y1;
+ active_line *endp, *alp, *stopx;
+ fixed x;
+ int draw;
+
+ INCR(iter);
+ /* Move newly active lines from y to x list. */
+ while (yll != 0 && yll->start.y == y) {
+ active_line *ynext = yll->next; /* insert smashes next/prev links */
+
+ if (yll->direction == dir_horizontal) { /* This is a hack to make sure that */
+ /* isolated horizontal lines get stroked. */
+ int yi = fixed2int_pixround(y - adjust_below);
+ int xi, wi;
+
+ if (yll->start.x <= yll->end.x)
+ xi = fixed2int_pixround(yll->start.x -
+ adjust_left),
+ wi = fixed2int_pixround(yll->end.x +
+ adjust_right) - xi;
+ else
+ xi = fixed2int_pixround(yll->end.x -
+ adjust_left),
+ wi = fixed2int_pixround(yll->start.x +
+ adjust_right) - xi;
+ code = loop_fill_rectangle_direct(xi, yi, wi, 1);
+ if (code < 0)
+ return code;
+ } else
+ insert_x_new(yll, ll);
+ yll = ynext;
+ }
+ /* Check whether we've reached the maximum y. */
+ if (y >= y_limit)
+ break;
+ if (ll->x_list == 0) { /* No active lines, skip to next start */
+ if (yll == 0)
+ break; /* no lines left */
+ y = yll->start.y;
+ continue;
+ }
+ /* Find the next evaluation point. */
+ /* Start by finding the smallest y value */
+ /* at which any currently active line ends */
+ /* (or the next to-be-active line begins). */
+ y1 = (yll != 0 ? yll->start.y : y_limit);
+ /* Make sure we don't exceed the maximum band height. */
+ {
+ fixed y_band = y | ~band_mask;
+
+ if (y1 > y_band)
+ y1 = y_band + 1;
+ }
+ for (alp = ll->x_list; alp != 0; alp = alp->next)
+ if (alp->end.y < y1)
+ y1 = alp->end.y;
+#ifdef DEBUG
+ if (gs_debug_c('F')) {
+ dlprintf2("[F]before loop: y=%f y1=%f:\n",
+ fixed2float(y), fixed2float(y1));
+ print_line_list(ll->x_list);
+ }
+#endif
+ /* Now look for line intersections before y1. */
+ x = min_fixed;
+#define have_pixels()\
+ (fixed_pixround(y - adjust_below) < fixed_pixround(y1 + adjust_above))
+ draw = (have_pixels()? 1 : -1);
+ /*
+ * Loop invariants:
+ * alp = endp->next;
+ * for all lines lp from stopx up to alp,
+ * lp->x_next = al_x_at_y(lp, y1).
+ */
+ for (alp = stopx = ll->x_list;
+ INCR_EXPR(find_y), alp != 0;
+ endp = alp, alp = alp->next
+ ) {
+ fixed nx = al_x_at_y(alp, y1);
+ fixed dx_old, dx_den;
+
+ /* Check for intersecting lines. */
+ if (nx >= x)
+ x = nx;
+ else if
+ (draw >= 0 && /* don't bother if no pixels */
+ (dx_old = alp->x_current - endp->x_current) >= 0 &&
+ (dx_den = dx_old + endp->x_next - nx) > dx_old
+ ) { /* Make a good guess at the intersection */
+ /* Y value using only local information. */
+ fixed dy = y1 - y, y_new;
+
+ if_debug3('f', "[f]cross: dy=%g, dx_old=%g, dx_new=%g\n",
+ fixed2float(dy), fixed2float(dx_old),
+ fixed2float(dx_den - dx_old));
+ /* Do the computation in single precision */
+ /* if the values are small enough. */
+ y_new =
+ ((dy | dx_old) < 1L << (size_of(fixed) * 4 - 1) ?
+ dy * dx_old / dx_den :
+ fixed_mult_quo(dy, dx_old, dx_den))
+ + y;
+ /* The crossing value doesn't have to be */
+ /* very accurate, but it does have to be */
+ /* greater than y and less than y1. */
+ if_debug3('f', "[f]cross y=%g, y_new=%g, y1=%g\n",
+ fixed2float(y), fixed2float(y_new),
+ fixed2float(y1));
+ stopx = alp;
+ if (y_new <= y)
+ y_new = y + 1;
+ if (y_new < y1) {
+ y1 = y_new;
+ nx = al_x_at_y(alp, y1);
+ draw = 0;
+ }
+ if (nx > x)
+ x = nx;
+ }
+ alp->x_next = nx;
+ }
+ /* Recompute next_x for lines before the intersection. */
+ for (alp = ll->x_list; alp != stopx; alp = alp->next)
+ alp->x_next = al_x_at_y(alp, y1);
+#ifdef DEBUG
+ if (gs_debug_c('F')) {
+ dlprintf1("[F]after loop: y1=%f\n", fixed2float(y1));
+ print_line_list(ll->x_list);
+ }
+#endif
+ /* Fill a multi-trapezoid band for the active lines. */
+ /* Don't bother if no pixel centers lie within the band. */
+ if (draw > 0 || (draw == 0 && have_pixels())) {
+
+/*******************************************************************/
+/* For readability, we start indenting from the left margin again. */
+/*******************************************************************/
+
+ fixed height = y1 - y;
+ fixed xlbot, xltop; /* as of last "outside" line */
+ int inside = 0;
+ active_line *nlp;
+
+ INCR(band);
+ for (x = min_fixed, alp = ll->x_list; alp != 0; alp = nlp) {
+ fixed xbot = alp->x_current;
+ fixed xtop = alp->x_current = alp->x_next;
+
+#define nx xtop
+ fixed wtop;
+ int xi, xli;
+ int code;
+
+ print_al("step", alp);
+ INCR(band_step);
+ nlp = alp->next;
+ /* Handle ended or out-of-order lines. After this, */
+ /* the only member of alp we use is alp->direction. */
+ if (alp->end.y != y1 || !end_x_line(alp)) {
+ if (nx <= x)
+ resort_x_line(alp);
+ else
+ x = nx;
+ }
+#undef nx
+ /* rule = -1 for winding number rule, i.e. */
+ /* we are inside if the winding number is non-zero; */
+ /* rule = 1 for even-odd rule, i.e. */
+ /* we are inside if the winding number is odd. */
+#define inside_path_p() ((inside & rule) != 0)
+ if (!inside_path_p()) { /* i.e., outside */
+ inside += alp->direction;
+ if (inside_path_p()) /* about to go in */
+ xlbot = xbot, xltop = xtop;
+ continue;
+ }
+ /* We're inside a region being filled. */
+ inside += alp->direction;
+ if (inside_path_p()) /* not about to go out */
+ continue;
+#undef inside_path_p
+ /* We just went from inside to outside, so fill the region. */
+ wtop = xtop - xltop;
+ INCR(band_fill);
+ /* If lines are temporarily out of */
+ /* order, wtop might be negative. */
+ /* Patch this up now. */
+ if (wtop < 0) {
+ if_debug2('f', "[f]patch %g,%g\n",
+ fixed2float(xltop), fixed2float(xtop));
+ xtop = xltop += arith_rshift(wtop, 1);
+ wtop = 0;
+ }
+ if ((adjust_left | adjust_right) != 0) {
+ xlbot -= adjust_left;
+ xbot += adjust_right;
+ xltop -= adjust_left;
+ xtop += adjust_right;
+ wtop = xtop - xltop;
+ }
+ if ((xli = fixed2int_var_pixround(xltop)) ==
+ fixed2int_var_pixround(xlbot) &&
+ (xi = fixed2int_var_pixround(xtop)) ==
+ fixed2int_var_pixround(xbot)
+ ) { /* Rectangle. */
+ int yi = fixed2int_pixround(y - adjust_below);
+ int wi = fixed2int_pixround(y1 + adjust_above) - yi;
+
+ code = loop_fill_rectangle_direct(xli, yi,
+ xi - xli, wi);
+ } else if ((adjust_below | adjust_above) != 0) { /*
+ * We want to get the effect of filling an area whose
+ * outline is formed by dragging a square of side adj2
+ * along the border of the trapezoid. This is *not*
+ * equivalent to simply expanding the corners by
+ * adjust: There are 3 cases needing different
+ * algorithms, plus rectangles as a fast special case.
+ */
+ fixed wbot = xbot - xlbot;
+
+ if (xltop <= xlbot) {
+ if (xtop >= xbot) { /* Top wider than bottom. */
+ code = loop_fill_trapezoid_fixed(
+ xlbot, wbot, y - adjust_below,
+ xltop, wtop, height);
+ if (adjusted_y_spans_pixel(y1)) {
+ if (code < 0)
+ return code;
+ INCR(afill);
+ code = loop_fill_rectangle_direct(
+ xli, fixed2int_pixround(y1 - adjust_below),
+ fixed2int_var_pixround(xtop) - xli, 1);
+ }
+ } else { /* Slanted trapezoid. */
+ code = fill_slant_adjust(xlbot, xbot, y,
+ xltop, xtop, height, adjust_below,
+ adjust_above, pbox,
+ pdevc, dev, lop);
+ }
+ } else {
+ if (xtop <= xbot) { /* Bottom wider than top. */
+ if (adjusted_y_spans_pixel(y)) {
+ INCR(afill);
+ xli = fixed2int_var_pixround(xlbot);
+ code = loop_fill_rectangle_direct(
+ xli, fixed2int_pixround(y - adjust_below),
+ fixed2int_var_pixround(xbot) - xli, 1);
+ if (code < 0)
+ return code;
+ }
+ code = loop_fill_trapezoid_fixed(
+ xlbot, wbot, y + adjust_above,
+ xltop, wtop, height);
+ } else { /* Slanted trapezoid. */
+ code = fill_slant_adjust(xlbot, xbot, y,
+ xltop, xtop, height, adjust_below,
+ adjust_above, pbox,
+ pdevc, dev, lop);
+ }
+ }
+ } else /* No Y adjustment. */
+ code = loop_fill_trapezoid_fixed(xlbot, xbot - xlbot,
+ y, xltop, wtop, height);
+ if (code < 0)
+ return code;
+ }
+
+/**************************************************************/
+/* End of section requiring less indentation for readability. */
+/**************************************************************/
+
+ } else { /* Just scan for ended or out-of-order lines. */
+ active_line *nlp;
+
+ for (x = min_fixed, alp = ll->x_list; alp != 0;
+ alp = nlp
+ ) {
+ fixed nx = alp->x_current = alp->x_next;
+
+ nlp = alp->next;
+ if_debug4('F',
+ "[F]check 0x%lx,x=%g 0x%lx,x=%g\n",
+ (ulong) alp->prev, fixed2float(x),
+ (ulong) alp, fixed2float(nx));
+ if (alp->end.y == y1) {
+ if (end_x_line(alp))
+ continue;
+ }
+ if (nx <= x)
+ resort_x_line(alp);
+ else
+ x = nx;
+ }
+ }
+#ifdef DEBUG
+ if (gs_debug_c('f')) {
+ int code = check_line_list(ll->x_list);
+
+ if (code < 0)
+ return code;
+ }
+#endif
+ y = y1;
+ }
+ return 0;
+}
+
+/*
+ * Handle the case of a slanted trapezoid with adjustment.
+ * To do this exactly right requires filling a central trapezoid
+ * (or rectangle) plus two horizontal almost-rectangles.
+ */
+private int
+fill_slant_adjust(fixed xlbot, fixed xbot, fixed y,
+ fixed xltop, fixed xtop, fixed height, fixed adjust_below,
+ fixed adjust_above, const gs_fixed_rect * pbox,
+ const gx_device_color * pdevc, gx_device * dev,
+ gs_logical_operation_t lop)
+{
+ fixed y1 = y + height;
+
+ dev_proc_fill_trapezoid((*fill_trap)) =
+ dev_proc(dev, fill_trapezoid);
+ const fixed yb = y - adjust_below;
+ const fixed ya = y + adjust_above;
+ const fixed y1b = y1 - adjust_below;
+ const fixed y1a = y1 + adjust_above;
+ const gs_fixed_edge *plbot;
+ const gs_fixed_edge *prbot;
+ const gs_fixed_edge *pltop;
+ const gs_fixed_edge *prtop;
+ gs_fixed_edge vert_left, slant_left, vert_right, slant_right;
+ int code;
+
+ INCR(slant);
+
+ /* Set up all the edges, even though we may not need them all. */
+
+ if (xlbot < xltop) { /* && xbot < xtop */
+ vert_left.start.x = vert_left.end.x = xlbot;
+ vert_left.start.y = yb, vert_left.end.y = ya;
+ vert_right.start.x = vert_right.end.x = xtop;
+ vert_right.start.y = y1b, vert_right.end.y = y1a;
+ slant_left.start.y = ya, slant_left.end.y = y1a;
+ slant_right.start.y = yb, slant_right.end.y = y1b;
+ plbot = &vert_left, prbot = &slant_right,
+ pltop = &slant_left, prtop = &vert_right;
+ } else {
+ vert_left.start.x = vert_left.end.x = xltop;
+ vert_left.start.y = y1b, vert_left.end.y = y1a;
+ vert_right.start.x = vert_right.end.x = xbot;
+ vert_right.start.y = yb, vert_right.end.y = ya;
+ slant_left.start.y = yb, slant_left.end.y = y1b;
+ slant_right.start.y = ya, slant_right.end.y = y1a;
+ plbot = &slant_left, prbot = &vert_right,
+ pltop = &vert_left, prtop = &slant_right;
+ }
+ slant_left.start.x = xlbot, slant_left.end.x = xltop;
+ slant_right.start.x = xbot, slant_right.end.x = xtop;
+
+ if (ya >= y1b) { /*
+ * The upper and lower adjustment bands overlap.
+ * Since the entire entity is less than 2 pixels high
+ * in this case, we could handle it very efficiently
+ * with no more than 2 rectangle fills, but for right now
+ * we don't attempt to do this.
+ */
+ int iyb = fixed2int_var_pixround(yb);
+ int iya = fixed2int_var_pixround(ya);
+ int iy1b = fixed2int_var_pixround(y1b);
+ int iy1a = fixed2int_var_pixround(y1a);
+
+ INCR(slant_shallow);
+ if (iy1b > iyb) {
+ code = (*fill_trap) (dev, plbot, prbot,
+ yb, y1b, false, pdevc, lop);
+ if (code < 0)
+ return code;
+ }
+ if (iya > iy1b) {
+ int ix = fixed2int_var_pixround(vert_left.start.x);
+ int iw = fixed2int_var_pixround(vert_right.start.x) - ix;
+
+ code = loop_fill_rectangle(ix, iy1b, iw, iya - iy1b);
+ if (code < 0)
+ return code;
+ }
+ if (iy1a > iya)
+ code = (*fill_trap) (dev, pltop, prtop,
+ ya, y1a, false, pdevc, lop);
+ else
+ code = 0;
+ } else { /*
+ * Clip the trapezoid if possible. This can save a lot
+ * of work when filling paths that cross band boundaries.
+ */
+ fixed yac;
+
+ if (pbox->p.y < ya) {
+ code = (*fill_trap) (dev, plbot, prbot,
+ yb, ya, false, pdevc, lop);
+ if (code < 0)
+ return code;
+ yac = ya;
+ } else
+ yac = pbox->p.y;
+ if (pbox->q.y > y1b) {
+ code = (*fill_trap) (dev, &slant_left, &slant_right,
+ yac, y1b, false, pdevc, lop);
+ if (code < 0)
+ return code;
+ code = (*fill_trap) (dev, pltop, prtop,
+ y1b, y1a, false, pdevc, lop);
+ } else
+ code = (*fill_trap) (dev, &slant_left, &slant_right,
+ yac, pbox->q.y, false, pdevc, lop);
+ }
+ return code;
+}
+
+/* Re-sort the x list by moving alp backward to its proper spot. */
+private void
+resort_x_line(active_line * alp)
+{
+ active_line *prev = alp->prev;
+ active_line *next = alp->next;
+ fixed nx = alp->x_current;
+
+ prev->next = next;
+ if (next)
+ next->prev = prev;
+ while (!x_precedes(prev, alp, nx)) {
+ if_debug2('f', "[f]swap 0x%lx,0x%lx\n",
+ (ulong) alp, (ulong) prev);
+ next = prev, prev = prev->prev;
+ }
+ alp->next = next;
+ alp->prev = prev;
+ /* next might be null, if alp was in */
+ /* the correct spot already. */
+ if (next)
+ next->prev = alp;
+ prev->next = alp;
+}
diff --git a/pstoraster/gxfixed.h b/pstoraster/gxfixed.h
new file mode 100644
index 000000000..fcd334e81
--- /dev/null
+++ b/pstoraster/gxfixed.h
@@ -0,0 +1,248 @@
+/* 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$ */
+/* Fixed-point arithmetic for Ghostscript */
+
+#ifndef gxfixed_INCLUDED
+# define gxfixed_INCLUDED
+
+/*
+ * Coordinates are generally represented internally by fixed-point
+ * quantities: integers lose accuracy in crucial places,
+ * and floating point arithmetic is slow.
+ */
+typedef long fixed;
+typedef ulong ufixed; /* only used in a very few places */
+
+#define max_fixed max_long
+#define min_fixed min_long
+#define fixed_0 0L
+#define fixed_epsilon 1L
+/*
+ * 12 bits of fraction provides both the necessary accuracy and
+ * a sufficiently large range of coordinates.
+ */
+#define _fixed_shift 12
+#define fixed_fraction_bits _fixed_shift
+#define fixed_int_bits (sizeof(fixed) * 8 - _fixed_shift)
+#define fixed_scale (1<<_fixed_shift)
+#define _fixed_rshift(x) arith_rshift(x,_fixed_shift)
+#define _fixed_round_v (fixed_scale>>1)
+#define _fixed_fraction_v (fixed_scale-1)
+/*
+ * We use a center-of-pixel filling rule; Adobe specifies that coordinates
+ * designate half-open regions. Because of this, we need special rounding
+ * to go from a coordinate to the pixel it falls in. We use the term
+ * "pixel rounding" for this kind of rounding.
+ */
+#define _fixed_pixround_v (_fixed_round_v - fixed_epsilon)
+
+/*
+ * Most operations can be done directly on fixed-point quantities:
+ * addition, subtraction, shifting, multiplication or division by
+ * (integer) constants; assignment, assignment with zero;
+ * comparison, comparison against zero.
+ * Multiplication and division by floats is OK if the result is
+ * explicitly cast back to fixed.
+ * Conversion to and from int and float types must be done explicitly.
+ * Note that if we are casting a fixed to a float in a context where
+ * only ratios and not actual values are involved, we don't need to take
+ * the scale factor into account: we can simply cast to float directly.
+ */
+#define int2fixed(i) ((fixed)(i)<<_fixed_shift)
+/* Define some useful constants. */
+/* Avoid casts, so strict ANSI compilers will accept them in #ifs. */
+#define fixed_1 (fixed_epsilon << _fixed_shift)
+#define fixed_half (fixed_1 >> 1)
+/*
+ * On 16-bit systems, we can convert fixed variables to ints more efficiently
+ * than general fixed quantities. For this reason, we define two separate
+ * sets of conversion macros.
+ */
+#define fixed2int(x) ((int)_fixed_rshift(x))
+#define fixed2int_rounded(x) ((int)_fixed_rshift((x)+_fixed_round_v))
+#define fixed2int_ceiling(x) ((int)_fixed_rshift((x)+_fixed_fraction_v))
+#define fixed_pre_pixround(x) ((x)+_fixed_pixround_v)
+#define fixed2int_pixround(x) fixed2int(fixed_pre_pixround(x))
+#define fixed_is_int(x) !((x)&_fixed_fraction_v)
+#if arch_ints_are_short & !arch_is_big_endian
+/* Do some of the shifting and extraction ourselves. */
+# define _fixed_hi(x) *((uint *)&(x)+1)
+# define _fixed_lo(x) *((uint *)&(x))
+# define fixed2int_var(x)\
+ ((int)((_fixed_hi(x) << (16-_fixed_shift)) +\
+ (_fixed_lo(x) >> _fixed_shift)))
+# define fixed2int_var_rounded(x)\
+ ((int)((_fixed_hi(x) << (16-_fixed_shift)) +\
+ (((_fixed_lo(x) >> (_fixed_shift-1))+1)>>1)))
+# define fixed2int_var_ceiling(x)\
+ (fixed2int_var(x) -\
+ arith_rshift((int)-(_fixed_lo(x) & _fixed_fraction_v), _fixed_shift))
+#else
+/* Use reasonable definitions. */
+# define fixed2int_var(x) fixed2int(x)
+# define fixed2int_var_rounded(x) fixed2int_rounded(x)
+# define fixed2int_var_ceiling(x) fixed2int_ceiling(x)
+#endif
+#define fixed2int_var_pixround(x) fixed2int_pixround(x)
+#define fixed2long(x) ((long)_fixed_rshift(x))
+#define fixed2long_rounded(x) ((long)_fixed_rshift((x)+_fixed_round_v))
+#define fixed2long_ceiling(x) ((long)_fixed_rshift((x)+_fixed_fraction_v))
+#define fixed2long_pixround(x) ((long)_fixed_rshift((x)+_fixed_pixround_v))
+#define float2fixed(f) ((fixed)((f)*(float)fixed_scale))
+/* Note that fixed2float actually produces a double result. */
+#define fixed2float(x) ((x)*(1.0/fixed_scale))
+
+/* Rounding and truncation on fixeds */
+#define fixed_floor(x) ((x)&(-1L<<_fixed_shift))
+#define fixed_rounded(x) (((x)+_fixed_round_v)&(-1L<<_fixed_shift))
+#define fixed_ceiling(x) (((x)+_fixed_fraction_v)&(-1L<<_fixed_shift))
+#define fixed_pixround(x) (((x)+_fixed_pixround_v)&(-1L<<_fixed_shift))
+#define fixed_fraction(x) ((int)(x)&_fixed_fraction_v)
+/* I don't see how to do truncation towards 0 so easily.... */
+#define fixed_truncated(x) ((x) < 0 ? fixed_ceiling(x) : fixed_floor(x))
+
+/* Define the largest and smallest integer values that fit in a fixed. */
+#if arch_sizeof_int == arch_sizeof_long
+# define max_int_in_fixed fixed2int(max_fixed)
+# define min_int_in_fixed fixed2int(min_fixed)
+#else
+# define max_int_in_fixed max_int
+# define min_int_in_fixed min_int
+#endif
+
+#ifdef USE_FPU
+# define USE_FPU_FIXED (USE_FPU < 0 && arch_floats_are_IEEE && arch_sizeof_long == 4)
+#else
+# define USE_FPU_FIXED 0
+#endif
+
+/*
+ * Define a procedure for computing a * b / c when b and c are non-negative,
+ * b < c, and a * b exceeds (or might exceed) the capacity of a long.
+ * It's really annoying that C doesn't provide any way to get at
+ * the double-length multiply/divide instructions that almost all hardware
+ * provides....
+ */
+
+#if USE_FPU_FIXED
+fixed fixed_mult_quo(P3(fixed A, fixed B, fixed C));
+
+#else
+# define fixed_mult_quo(fixed_a, fixed_b, fixed_c)\
+ ((fixed)floor((double)(fixed_a) * (fixed_b) / (fixed_c)))
+#endif
+
+/*
+ * Transforming coordinates involves multiplying two floats, or a float
+ * and a double, and then converting the result to a fixed. Since this
+ * operation is so common, we provide an alternative implementation of it
+ * on machines that use IEEE floating point representation but don't have
+ * floating point hardware. The implementation may be in either C or
+ * assembler.
+ */
+
+/*
+ * set_fmul2fixed_vars(R, FA, FB, dtemp) computes R = FA * FB:
+ * R is a fixed, FA and FB are floats (not doubles), and
+ * dtemp is a temporary double.
+ * set_dfmul2fixed_vars(R, DA, FB, dtemp) computes R = DA * FB:
+ * R is a fixed, DA is a double, FB is a float, and
+ * dtemp is a temporary double.
+ * R, FA, FB, and DA must be variables, not expressions.
+ */
+#if USE_FPU_FIXED && arch_sizeof_short == 2
+int set_fmul2fixed_(P3(fixed *, long, long));
+
+#define set_fmul2fixed_vars(vr,vfa,vfb,dtemp)\
+ set_fmul2fixed_(&vr, *(long *)&vfa, *(long *)&vfb)
+int set_dfmul2fixed_(P4(fixed *, ulong, long, long));
+
+# if arch_is_big_endian
+# define set_dfmul2fixed_vars(vr,vda,vfb,dtemp)\
+ set_dfmul2fixed_(&vr, ((ulong *)&vda)[1], *(long *)&vfb, *(long *)&vda)
+# else
+# define set_dfmul2fixed_vars(vr,vda,vfb,dtemp)\
+ set_dfmul2fixed_(&vr, *(ulong *)&vda, *(long *)&vfb, ((long *)&vda)[1])
+# endif
+#else /* don't bother */
+# define set_fmul2fixed_vars(vr,vfa,vfb,dtemp)\
+ (dtemp = (vfa) * (vfb),\
+ (f_fits_in_bits(dtemp, fixed_int_bits) ? (vr = float2fixed(dtemp), 0) :\
+ gs_note_error(gs_error_limitcheck)))
+# define set_dfmul2fixed_vars(vr,vda,vfb,dtemp)\
+ (dtemp = (vda) * (vfb),\
+ (f_fits_in_bits(dtemp, fixed_int_bits) ? (vr = float2fixed(dtemp), 0) :\
+ gs_note_error(gs_error_limitcheck)))
+#endif
+/*
+ * set_float2fixed_vars(R, F) does the equivalent of R = float2fixed(F):
+ * R is a fixed, F is a float or a double.
+ * set_fixed2float_var(R, V) does the equivalent of R = fixed2float(V):
+ * R is a float or a double, V is a fixed.
+ * set_ldexp_fixed2double(R, V, E) does the equivalent of R=ldexp((double)V,E):
+ * R is a double, V is a fixed, E is an int.
+ * R and F must be variables, not expressions; V and E may be expressions.
+ */
+#if USE_FPU_FIXED
+int set_float2fixed_(P3(fixed *, long, int));
+int set_double2fixed_(P4(fixed *, ulong, long, int));
+
+# define set_float2fixed_vars(vr,vf)\
+ (sizeof(vf) == sizeof(float) ?\
+ set_float2fixed_(&vr, *(long *)&vf, fixed_fraction_bits) :\
+ set_double2fixed_(&vr, ((ulong *)&vf)[arch_is_big_endian],\
+ ((long *)&vf)[1 - arch_is_big_endian],\
+ fixed_fraction_bits))
+long fixed2float_(P2(fixed, int));
+void set_fixed2double_(P3(double *, fixed, int));
+
+# define set_fixed2float_var(vf,x)\
+ (sizeof(vf) == sizeof(float) ?\
+ (*(long *)&vf = fixed2float_(x, fixed_fraction_bits), 0) :\
+ (set_fixed2double_(&vf, x, fixed_fraction_bits), 0))
+#define set_ldexp_fixed2double(vd, x, exp)\
+ set_fixed2double_(&vd, x, -(exp))
+#else
+# define set_float2fixed_vars(vr,vf)\
+ (f_fits_in_bits(vf, fixed_int_bits) ? (vr = float2fixed(vf), 0) :\
+ gs_note_error(gs_error_limitcheck))
+# define set_fixed2float_var(vf,x)\
+ (vf = fixed2float(x), 0)
+# define set_ldexp_fixed2double(vd, x, exp)\
+ discard(vd = ldexp((double)(x), exp))
+#endif
+
+/* A point with fixed coordinates */
+typedef struct gs_fixed_point_s {
+ fixed x, y;
+} gs_fixed_point;
+
+/* A rectangle with fixed coordinates */
+typedef struct gs_fixed_rect_s {
+ gs_fixed_point p, q;
+} gs_fixed_rect;
+
+#endif /* gxfixed_INCLUDED */
diff --git a/pstoraster/gxfmap.h b/pstoraster/gxfmap.h
new file mode 100644
index 000000000..6f24952f4
--- /dev/null
+++ b/pstoraster/gxfmap.h
@@ -0,0 +1,105 @@
+/* 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$ */
+/* Fraction map representation for Ghostscript */
+
+#ifndef gxfmap_INCLUDED
+# define gxfmap_INCLUDED
+
+#include "gsrefct.h"
+#include "gxfrac.h"
+#include "gxtmap.h"
+
+/*
+ * Define a cached map from fracs to fracs. Level 1 uses this only
+ * for the transfer function; level 2 also uses it for black generation
+ * and undercolor removal. Note that reference counting macros must
+ * be used to allocate, free, and assign references to gx_transfer_maps.
+ *
+ * NOTE: proc and closure are redundant. Eventually closure will replace
+ * proc. For now, things are in an uneasy intermediate state where
+ * proc = 0 means use closure.
+ */
+/* log2... must not be greater than frac_bits, and must be least 8. */
+#define log2_transfer_map_size 8
+#define transfer_map_size (1 << log2_transfer_map_size)
+ /*typedef struct gx_transfer_map_s gx_transfer_map; *//* in gxtmap.h */
+struct gx_transfer_map_s {
+ rc_header rc;
+ gs_mapping_proc proc; /* typedef is in gxtmap.h */
+ gs_mapping_closure_t closure; /* SEE ABOVE */
+ /* The id changes whenever the map or function changes. */
+ gs_id id;
+ frac values[transfer_map_size];
+};
+
+extern_st(st_transfer_map);
+#define public_st_transfer_map() /* in gscolor.c */\
+ gs_public_st_composite(st_transfer_map, gx_transfer_map, "gx_transfer_map",\
+ transfer_map_enum_ptrs, transfer_map_reloc_ptrs)
+
+/*
+ * Map a color fraction through a transfer map. If the map is small,
+ * we interpolate; if it is large, we don't, and save a lot of time.
+ */
+#define FRAC_MAP_INTERPOLATE (log2_transfer_map_size <= 8)
+#if FRAC_MAP_INTERPOLATE
+
+frac gx_color_frac_map(P2(frac, const frac *)); /* in gxcmap.c */
+
+# define gx_map_color_frac(pgs,cf,m)\
+ gx_color_frac_map(cf, &pgs->m->values[0])
+
+#else /* !FRAC_MAP_INTERPOLATE */
+
+/* Do the lookup in-line. */
+# define gx_map_color_frac(pgs,cf,m)\
+ (pgs->m->values[frac2bits(cf, log2_transfer_map_size)])
+
+#endif /* (!)FRAC_MAP_INTERPOLATE */
+
+/* Map a color fraction expressed as a byte through a transfer map. */
+/* (We don't use this anywhere right now.) */
+/****************
+#if log2_transfer_map_size <= 8
+# define byte_to_tmx(b) ((b) >> (8 - log2_transfer_map_size))
+#else
+# define byte_to_tmx(b)\
+ (((b) << (log2_transfer_map_size - 8)) +\
+ ((b) >> (16 - log2_transfer_map_size)))
+#endif
+#define gx_map_color_frac_byte(pgs,b,m)\
+ (pgs->m->values[byte_to_tmx(b)])
+ ****************/
+
+/* Map a floating point value through a transfer map. */
+#define gx_map_color_float(pmap,v)\
+ ((pmap)->values[(int)((v) * transfer_map_size + 0.5)] / frac_1_float)
+
+/* Define a mapping procedure that just looks up the value in the cache. */
+/* (It is equivalent to gx_map_color_float with the arguments swapped.) */
+float gs_mapped_transfer(P2(floatp, const gx_transfer_map *));
+
+#endif /* gxfmap_INCLUDED */
diff --git a/pstoraster/gxfont.h b/pstoraster/gxfont.h
new file mode 100644
index 000000000..c8b562110
--- /dev/null
+++ b/pstoraster/gxfont.h
@@ -0,0 +1,224 @@
+/* Copyright (C) 1989, 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$ */
+/* Requires gsmatrix.h, gxdevice.h */
+
+#ifndef gxfont_INCLUDED
+# define gxfont_INCLUDED
+
+#include "gsccode.h"
+#include "gsfont.h"
+#include "gsuid.h"
+#include "gsstruct.h" /* for extern_st */
+#include "gxftype.h"
+
+/* A font object as seen by clients. */
+/* See the PostScript Language Reference Manual for details. */
+
+#ifndef gs_show_enum_DEFINED
+# define gs_show_enum_DEFINED
+typedef struct gs_show_enum_s gs_show_enum;
+
+#endif
+
+/*
+ * Fonts are "objects" to a limited extent, in that some of their
+ * behavior is provided by a record of procedures in the font.
+ * However, adding new types of fonts (subclasses) is not supported well.
+ */
+
+typedef struct gs_font_procs_s {
+
+ /*
+ * Define any needed procedure for initializing the composite
+ * font stack in a show enumerator. This is a no-op for
+ * all but composite fonts.
+ */
+
+#define font_proc_init_fstack(proc)\
+ int proc(P2(gs_show_enum *, gs_font *))
+ font_proc_init_fstack((*init_fstack));
+
+ /*
+ * Define the font's algorithm for getting the next character from
+ * a string being shown. This is trivial, except for composite fonts.
+ * Returns 0 if the current (base) font didn't change,
+ * 1 if it did change, 2 if there are no more characters,
+ * or an error code.
+ *
+ * This procedure is OBSOLETE as of release 4.61, superseded by
+ * next_glyph; however, we have to continue supporting it for
+ * backward compatibility.
+ */
+
+#define font_proc_next_char(proc)\
+ int proc(P2(gs_show_enum *, gs_char *))
+ font_proc_next_char((*next_char));
+
+ /* A client-supplied character encoding procedure. */
+
+#define font_proc_encode_char(proc)\
+ gs_glyph proc(P3(gs_show_enum *, gs_font *, gs_char *))
+ font_proc_encode_char((*encode_char));
+
+ /*
+ * A client-supplied BuildChar/BuildGlyph procedure.
+ * The gs_char may be gs_no_char (for BuildGlyph), or the gs_glyph
+ * may be gs_no_glyph (for BuildChar), but not both.
+ */
+
+#define font_proc_build_char(proc)\
+ int proc(P5(gs_show_enum *, gs_state *, gs_font *, gs_char, gs_glyph))
+ font_proc_build_char((*build_char));
+
+ /* Callback procedures for external font rasterizers */
+ /* (see gsccode.h for details.) */
+
+ gx_xfont_callbacks callbacks;
+ /*gs_proc_glyph_name((*glyph_name)); */
+
+ /*
+ * Define any special handling of gs_definefont.
+ * We break this out so it can be different for composite fonts.
+ */
+
+#define font_proc_define_font(proc)\
+ int proc(P2(gs_font_dir *, gs_font *))
+ font_proc_define_font((*define_font));
+
+ /*
+ * Define any special handling of gs_makefont.
+ * We break this out so it can be different for composite fonts.
+ */
+
+#define font_proc_make_font(proc)\
+ int proc(P4(gs_font_dir *, const gs_font *, const gs_matrix *,\
+ gs_font **))
+ font_proc_make_font((*make_font));
+
+ /*
+ * Define the font's algorithm for getting the next character or
+ * glyph from a string being shown. We only use this if the
+ * next_char procedure is 0 (for backward compatibility).
+ */
+
+#define font_proc_next_glyph(proc)\
+ int proc(P3(gs_show_enum *, gs_char *, gs_glyph *))
+ font_proc_next_glyph((*next_glyph));
+
+} gs_font_procs;
+
+/* Default font procedures */
+font_proc_init_fstack(gs_default_init_fstack);
+font_proc_next_char(gs_default_next_char);
+font_proc_encode_char(gs_no_encode_char);
+font_proc_build_char(gs_no_build_char);
+font_proc_define_font(gs_no_define_font);
+font_proc_make_font(gs_no_make_font);
+font_proc_make_font(gs_base_make_font);
+font_proc_next_glyph(gs_default_next_glyph);
+
+/* The font names are only needed for xfont lookup. */
+typedef struct gs_font_name_s {
+#define gs_font_name_max 47 /* must be >= 40 */
+ /* The +1 is so we can null-terminate for debugging printout. */
+ byte chars[gs_font_name_max + 1];
+ uint size;
+} gs_font_name;
+
+/*
+ * Define a generic font. We include PaintType and StrokeWidth here because
+ * they affect rendering algorithms outside the Type 1 font machinery.
+ *
+ * ****** NOTE: If you define any subclasses of gs_font, you *must* define
+ * ****** the finalization procedure as gs_font_finalize. Finalization
+ * ****** procedures are not automatically inherited.
+ */
+#define gs_font_common\
+ gs_font *next, *prev; /* chain for original font list or */\
+ /* scaled font cache */\
+ gs_memory_t *memory; /* allocator for this font */\
+ gs_font_dir *dir; /* directory where registered */\
+ gs_font *base; /* original (unscaled) base font */\
+ void *client_data; /* additional client data */\
+ gs_matrix FontMatrix;\
+ font_type FontType;\
+ bool BitmapWidths;\
+ fbit_type ExactSize, InBetweenSize, TransformedChar;\
+ int WMode; /* 0 or 1 */\
+ int PaintType; /* PaintType for Type 1/4/42 fonts, */\
+ /* 0 for others */\
+ float StrokeWidth; /* StrokeWidth for Type 1/4/42 */\
+ /* fonts (if present), 0 for others */\
+ gs_font_procs procs;\
+ /* We store both the FontDirectory key (key_name) and, */\
+ /* if present, the FontName (font_name). */\
+ gs_font_name key_name, font_name
+ /*typedef struct gs_font_s gs_font; *//* in gsfont.h and other places */
+struct gs_font_s {
+ gs_font_common;
+};
+
+extern_st(st_gs_font); /* (abstract) */
+struct_proc_finalize(gs_font_finalize); /* public for concrete subclasses */
+#define public_st_gs_font() /* in gsfont.c */\
+ gs_public_st_complex_only(st_gs_font, gs_font, "gs_font",\
+ 0, font_enum_ptrs, font_reloc_ptrs, gs_font_finalize)
+#define st_gs_font_max_ptrs 5
+#define private_st_gs_font_ptr() /* in gsfont.c */\
+ gs_private_st_ptr(st_gs_font_ptr, gs_font *, "gs_font *",\
+ font_ptr_enum_ptrs, font_ptr_reloc_ptrs)
+#define st_gs_font_ptr_max_ptrs 1
+extern_st(st_gs_font_ptr_element);
+#define public_st_gs_font_ptr_element() /* in gsfont.c */\
+ gs_public_st_element(st_gs_font_ptr_element, gs_font *, "gs_font *[]",\
+ font_ptr_element_enum_ptrs, font_ptr_element_reloc_ptrs, st_gs_font_ptr)
+
+/* Define a base (not composite) font. */
+#define gs_font_base_common\
+ gs_font_common;\
+ gs_rect FontBBox;\
+ gs_uid UID;\
+ int encoding_index; /* 0=Std, 1=ISOLatin1, 2=Symbol, */\
+ /* 3=Dingbats, -1=other */\
+ int nearest_encoding_index /* (may be >= 0 even if */\
+ /* encoding_index = -1) */
+#ifndef gs_font_base_DEFINED
+# define gs_font_base_DEFINED
+typedef struct gs_font_base_s gs_font_base;
+
+#endif
+struct gs_font_base_s {
+ gs_font_base_common;
+};
+
+extern_st(st_gs_font_base);
+#define public_st_gs_font_base() /* in gsfont.c */\
+ gs_public_st_suffix_add1_final(st_gs_font_base, gs_font_base,\
+ "gs_font_base", font_base_enum_ptrs, font_base_reloc_ptrs,\
+ gs_font_finalize, st_gs_font, UID.xvalues)
+#define st_gs_font_base_max_ptrs (st_gs_font_max_ptrs + 1)
+
+#endif /* gxfont_INCLUDED */
diff --git a/pstoraster/gxfont0.h b/pstoraster/gxfont0.h
new file mode 100644
index 000000000..4e56110d9
--- /dev/null
+++ b/pstoraster/gxfont0.h
@@ -0,0 +1,81 @@
+/* Copyright (C) 1994, 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$ */
+/* Type 0 (composite) font data definition */
+
+#ifndef gxfont0_INCLUDED
+# define gxfont0_INCLUDED
+
+/* Define the composite font mapping types. */
+/* These numbers must be the same as the values of FMapType */
+/* in type 0 font dictionaries. */
+typedef enum {
+ fmap_8_8 = 2,
+ fmap_escape = 3,
+ fmap_1_7 = 4,
+ fmap_9_7 = 5,
+ fmap_SubsVector = 6,
+ fmap_double_escape = 7,
+ fmap_shift = 8,
+ fmap_CMap = 9
+} fmap_type;
+
+#define fmap_type_min 2
+#define fmap_type_max 9
+#define fmap_type_is_modal(fmt)\
+ ((fmt) == fmap_escape || (fmt) == fmap_double_escape || (fmt) == fmap_shift)
+
+/* This is the type-specific information for a type 0 (composite) gs_font. */
+#ifndef gs_cmap_DEFINED
+# define gs_cmap_DEFINED
+typedef struct gs_cmap_s gs_cmap;
+
+#endif
+typedef struct gs_type0_data_s {
+ fmap_type FMapType;
+ byte EscChar, ShiftIn, ShiftOut;
+ gs_const_string SubsVector; /* fmap_SubsVector only */
+ uint subs_size; /* bytes per entry */
+ uint subs_width; /* # of entries */
+ uint *Encoding;
+ uint encoding_size;
+ gs_font **FDepVector;
+ uint fdep_size;
+ const gs_cmap *CMap; /* fmap_CMap only */
+} gs_type0_data;
+
+#define gs_type0_data_max_ptrs 3
+
+typedef struct gs_font_type0_s {
+ gs_font_common;
+ gs_type0_data data;
+} gs_font_type0;
+
+extern_st(st_gs_font_type0);
+#define public_st_gs_font_type0() /* in gsfont0.c */\
+ gs_public_st_complex_only(st_gs_font_type0, gs_font_type0, "gs_font_type0",\
+ 0, font_type0_enum_ptrs, font_type0_reloc_ptrs, gs_font_finalize)
+
+#endif /* gxfont0_INCLUDED */
diff --git a/pstoraster/gxfont1.h b/pstoraster/gxfont1.h
new file mode 100644
index 000000000..a19f76342
--- /dev/null
+++ b/pstoraster/gxfont1.h
@@ -0,0 +1,158 @@
+/* Copyright (C) 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$ */
+/* Type 1 font data definition (including Type 2 charstrings) */
+
+#ifndef gxfont1_INCLUDED
+# define gxfont1_INCLUDED
+
+
+/*
+ * This is the type-specific information for an Adobe Type 1 font.
+ * It also includes the information for Type 2 charstrings, because
+ * there isn't very much of it and it's less trouble to include here.
+ */
+
+#ifndef gs_font_type1_DEFINED
+# define gs_font_type1_DEFINED
+typedef struct gs_font_type1_s gs_font_type1;
+
+#endif
+
+/*
+ * The zone_table values should be ints, according to the Adobe
+ * specification, but some fonts have arbitrary floats here.
+ */
+#define zone_table(size)\
+ struct {\
+ int count;\
+ float values[(size)*2];\
+ }
+#define float_array(size)\
+ struct {\
+ int count;\
+ float values[size];\
+ }
+#define stem_table(size)\
+ float_array(size)
+
+typedef struct gs_type1_data_s gs_type1_data;
+
+typedef struct gs_type1_data_procs_s {
+
+ /* Get the data for any glyph. */
+
+ int (*glyph_data) (P3(gs_font_type1 * pfont, gs_glyph glyph,
+ gs_const_string * pgdata));
+
+ /* Get the data for a Subr. */
+
+ int (*subr_data) (P4(gs_font_type1 * pfont, int subr_num, bool global,
+ gs_const_string * psdata));
+
+ /* Get the data for a seac character. */
+
+ int (*seac_data) (P3(gs_font_type1 * pfont, int ccode,
+ gs_const_string * pcdata));
+
+ /*
+ * Get the next glyph. index = 0 means return the first one; a
+ * returned index of 0 means the enumeration is finished.
+ */
+
+ int (*next_glyph) (P3(gs_font_type1 * pfont, int *pindex,
+ gs_glyph * pglyph));
+
+ /* Push (a) value(s) onto the client ('PostScript') stack. */
+
+ int (*push) (P3(gs_font_type1 * pfont, const fixed * values, int count));
+
+ /* Pop a value from the client stack. */
+
+ int (*pop) (P2(gs_font_type1 * pfont, fixed * value));
+
+} gs_type1_data_procs_t;
+
+/*
+ * The garbage collector really doesn't want the client data pointer
+ * from a gs_type1_state to point to the gs_type1_data in the middle of
+ * a gs_font_type1, so we make the client data pointer (which is passed
+ * to the callback procedures) point to the gs_font_type1 itself.
+ */
+struct gs_type1_data_s {
+ /*int PaintType; *//* in gs_font_common */
+ int CharstringType; /* 1 or 2 */
+ const gs_type1_data_procs_t *procs;
+ void *proc_data; /* data for procs */
+ int lenIV; /* -1 means no encryption */
+ /* (undocumented feature!) */
+ uint subroutineNumberBias; /* added to operand of callsubr */
+ /* (undocumented feature!) */
+ /* Type 2 charstring additions */
+ uint gsubrNumberBias; /* added to operand of callgsubr */
+ long initialRandomSeed;
+ fixed defaultWidthX;
+ fixed nominalWidthX;
+ /* For a description of the following hint information, */
+ /* see chapter 5 of the "Adobe Type 1 Font Format" book. */
+ int BlueFuzz;
+ float BlueScale;
+ float BlueShift;
+#define max_BlueValues 7
+ zone_table(max_BlueValues) BlueValues;
+ float ExpansionFactor;
+ bool ForceBold;
+#define max_FamilyBlues 7
+ zone_table(max_FamilyBlues) FamilyBlues;
+#define max_FamilyOtherBlues 5
+ zone_table(max_FamilyOtherBlues) FamilyOtherBlues;
+ int LanguageGroup;
+#define max_OtherBlues 5
+ zone_table(max_OtherBlues) OtherBlues;
+ bool RndStemUp;
+ stem_table(1) StdHW;
+ stem_table(1) StdVW;
+#define max_StemSnap 12
+ stem_table(max_StemSnap) StemSnapH;
+ stem_table(max_StemSnap) StemSnapV;
+ /* Additional information for Multiple Master fonts */
+#define max_WeightVector 16
+ float_array(max_WeightVector) WeightVector;
+};
+
+#define gs_type1_data_s_DEFINED
+
+struct gs_font_type1_s {
+ gs_font_base_common;
+ gs_type1_data data;
+};
+
+extern_st(st_gs_font_type1);
+#define public_st_gs_font_type1() /* in gstype1.c */\
+ gs_public_st_suffix_add1_final(st_gs_font_type1, gs_font_type1,\
+ "gs_font_type1", font_type1_enum_ptrs, font_type1_reloc_ptrs,\
+ gs_font_finalize, st_gs_font_base, data.proc_data)
+
+#endif /* gxfont1_INCLUDED */
diff --git a/pstoraster/gxfont42.h b/pstoraster/gxfont42.h
new file mode 100644
index 000000000..dd9b5152d
--- /dev/null
+++ b/pstoraster/gxfont42.h
@@ -0,0 +1,72 @@
+/* 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$ */
+/* Type 42 font data definition */
+
+#ifndef gxfont42_INCLUDED
+# define gxfont42_INCLUDED
+
+/* This is the type-specific information for a Type 42 (TrueType) font. */
+
+typedef struct gs_type42_data_s gs_type42_data;
+
+#ifndef gs_font_type42_DEFINED
+# define gs_font_type42_DEFINED
+typedef struct gs_font_type42_s gs_font_type42;
+
+#endif
+struct gs_type42_data_s {
+ /* The following are set by the client. */
+ int (*string_proc) (P4(gs_font_type42 *, ulong, uint, const byte **));
+ void *proc_data; /* data for procedures */
+ /* The following are initialized by ...font_init, */
+ /* but may be reset by the client. */
+ int (*get_outline) (P3(gs_font_type42 *, uint, gs_const_string *));
+ /* The following are cached values. */
+ ulong glyf; /* offset to glyf table */
+ uint unitsPerEm; /* from head */
+ uint indexToLocFormat; /* from head */
+ uint numLongMetrics; /* from hhea */
+ ulong hmtx; /* offset to hmtx table */
+ uint hmtx_length; /* length of hmtx table */
+ ulong loca; /* offset to loca table */
+};
+struct gs_font_type42_s {
+ gs_font_base_common;
+ gs_type42_data data;
+};
+
+extern_st(st_gs_font_type42);
+#define public_st_gs_font_type42() /* in gstype42.c */\
+ gs_public_st_suffix_add1_final(st_gs_font_type42, gs_font_type42,\
+ "gs_font_type42", font_type42_enum_ptrs, font_type42_reloc_ptrs,\
+ gs_font_finalize, st_gs_font_base, data.proc_data)
+
+/* Because a Type 42 font contains so many cached values, */
+/* we provide a procedure to initialize them from the font data. */
+/* Note that this initializes get_outline as well. */
+int gs_type42_font_init(P1(gs_font_type42 *));
+
+#endif /* gxfont42_INCLUDED */
diff --git a/pstoraster/gxfrac.h b/pstoraster/gxfrac.h
new file mode 100644
index 000000000..aaa4500e7
--- /dev/null
+++ b/pstoraster/gxfrac.h
@@ -0,0 +1,98 @@
+/* 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$ */
+/* Fraction representation for Ghostscript */
+
+#ifndef gxfrac_INCLUDED
+# define gxfrac_INCLUDED
+
+/*
+ * Represent a fraction in [0.0..1.0].
+ * Note that the 1.0 endpoint is included.
+ * Since undercolor removal requires a signed frac,
+ * we limit fracs to 15 bits rather than 16.
+ */
+typedef short frac;
+typedef short signed_frac;
+
+#define arch_log2_sizeof_frac arch_log2_sizeof_short
+#define arch_sizeof_frac arch_sizeof_short
+#define frac_bits 15
+#define frac_0 ((frac)0)
+/* The following definition of frac_1 allows exact representation of */
+/* almost all common fractions (e.g., N/360 for 0<=N<=360). */
+#define frac_1_0bits 3
+#define frac_1 ((frac)0x7ff8)
+#define frac_1_long ((long)frac_1)
+#define frac_1_float ((float)frac_1)
+/* Conversion between fracs and floats. */
+#define frac2float(fr) ((fr) / frac_1_float)
+#define float2frac(fl) ((frac)(((fl) + 0.5 / frac_1_float) * frac_1_float))
+
+/*
+ * Conversion between unsigned fracs and bytes (or, in general,
+ * shorter integers) representing fractions. This is highly dependent
+ * on the definition of frac_1 above.
+ */
+#define _frac2s(fr)\
+ (((fr) >> (frac_bits - frac_1_0bits)) + (fr))
+#define frac2bits(fr, nb)\
+ ((uint)(_frac2s(fr) >> (frac_bits - (nb))))
+#define frac2byte(fr) ((byte)frac2bits(fr, 8))
+/* bits2frac requires frac_bits / 2 <= nb <= frac_bits. */
+#define bits2frac(v, nb) ((frac)(\
+ ((frac)(v) << (frac_bits - (nb))) +\
+ ((v) >> ((nb) * 2 - frac_bits)) -\
+ ((v) >> ((nb) - frac_1_0bits)) ))
+#define byte2frac(b) bits2frac(b, 8)
+/* Produce a result that is guaranteed to convert back to a frac */
+/* not exceeding the original value fr. */
+#define frac2bits_floor(fr, nb)\
+ ((uint)((_frac2s(fr) - (_frac2s(fr) >> (nb))) >> (frac_bits - (nb))))
+/*
+ * Conversion between fracs and unsigned shorts.
+ */
+#define ushort_bits (arch_sizeof_short * 8)
+#define frac2ushort(fr) ((ushort)(\
+ ((fr) << (ushort_bits - frac_bits)) +\
+ ((fr) >> (frac_bits * 2 - ushort_bits - frac_1_0bits)) ))
+#define ushort2frac(us) ((frac)(\
+ ((us) >> (ushort_bits - frac_bits)) -\
+ ((us) >> (ushort_bits - frac_1_0bits)) ))
+/*
+ * Compute the quotient Q = floor(P / frac_1),
+ * where P is the (ulong) product of a uint or ushort V and a frac F.
+ * See gxarith.h for the underlying algorithm.
+ */
+#define frac_1_quo(p)\
+ ( (((p) >> frac_1_0bits) + ((p) >> frac_bits) + 1) >> (frac_bits - frac_1_0bits) )
+/*
+ * Compute the remainder similarly, having already computed the quotient.
+ * This is, of course, P - Q * frac_1.
+ */
+#define frac_1_rem(p, q)\
+ ((frac)( (uint)(p) - ((q) << frac_bits) + ((q) << frac_1_0bits) ))
+
+#endif /* gxfrac_INCLUDED */
diff --git a/pstoraster/gxftype.h b/pstoraster/gxftype.h
new file mode 100644
index 000000000..13c32c41d
--- /dev/null
+++ b/pstoraster/gxftype.h
@@ -0,0 +1,57 @@
+/* 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$ */
+/* Definition of font type and bitmap font behavior */
+
+#ifndef gxftype_INCLUDED
+# define gxftype_INCLUDED
+
+/* Define the known font types. */
+/* These numbers must be the same as the values of FontType */
+/* in font dictionaries. */
+typedef enum {
+ ft_composite = 0,
+ ft_encrypted = 1,
+ ft_CFF = 2,
+ ft_user_defined = 3,
+ ft_disk_based = 4,
+ ft_CID_encrypted = 9, /* CIDFontType 0 */
+ ft_CID_user_defined = 10, /* CIDFontType 1 */
+ ft_CID_TrueType = 11, /* CIDFontType 2 */
+ ft_Chameleon = 14,
+ ft_CID_bitmap = 32, /* CIDFontType 4 */
+ ft_TrueType = 42
+} font_type;
+
+/* Define the bitmap font behaviors. */
+/* These numbers must be the same as the values of the ExactSize, */
+/* InBetweenSize, and TransformedChar entries in font dictionaries. */
+typedef enum {
+ fbit_use_outlines = 0,
+ fbit_use_bitmaps = 1,
+ fbit_transform_bitmaps = 2
+} fbit_type;
+
+#endif /* gxftype_INCLUDED */
diff --git a/pstoraster/gxfunc.h b/pstoraster/gxfunc.h
new file mode 100644
index 000000000..c199bb1ef
--- /dev/null
+++ b/pstoraster/gxfunc.h
@@ -0,0 +1,56 @@
+/* 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$ */
+/* Internal definitions for Functions */
+
+#ifndef gxfunc_INCLUDED
+# define gxfunc_INCLUDED
+
+#include "gsfunc.h"
+#include "gsstruct.h"
+
+/* ---------------- Types and structures ---------------- */
+
+/* Define the generic Function structure type. This is never instantiated. */
+extern_st(st_function);
+#define public_st_function() /* in gsfunc.c */\
+ gs_public_st_ptrs2(st_function, gs_function_t, "gs_function_t",\
+ function_enum_ptrs, function_reloc_ptrs, params.Domain, params.Range)
+
+/* ---------------- Internal procedures ---------------- */
+
+/* Generic free_params implementation. */
+void fn_common_free_params(P2(gs_function_params_t * params, gs_memory_t * mem));
+
+/* Generic free implementation. */
+void fn_common_free(P3(gs_function_t * pfn, bool free_params, gs_memory_t * mem));
+
+/* Free an array of subsidiary Functions. */
+void fn_free_functions(P3(gs_function_t ** Functions, int count, gs_memory_t * mem));
+
+/* Check the values of m, n, Domain, and (if supplied) Range. */
+int fn_check_mnDR(P3(const gs_function_params_t * params, int m, int n));
+
+#endif /* gxfunc_INCLUDED */
diff --git a/pstoraster/gxgetbit.h b/pstoraster/gxgetbit.h
new file mode 100644
index 000000000..5bc8bc06b
--- /dev/null
+++ b/pstoraster/gxgetbit.h
@@ -0,0 +1,101 @@
+/* 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$ */
+/* Interface for get_bits_rectangle driver procedure */
+
+#ifndef gxgetbit_INCLUDED
+# define gxgetbit_INCLUDED
+
+#include "gxbitfmt.h"
+
+/* The parameter record typedef is also in gxdevcli.h. */
+#ifndef gs_get_bits_params_DEFINED
+# define gs_get_bits_params_DEFINED
+typedef struct gs_get_bits_params_s gs_get_bits_params_t;
+#endif
+
+/*
+ * We define the options for get_bits_rectangle here in a separate file
+ * so that the great majority of driver implementors and clients, which
+ * don't care about the details, don't need to be recompiled if the set
+ * of options changes.
+ */
+typedef gx_bitmap_format_t gs_get_bits_options_t;
+
+/*
+ * Define the parameter record passed to get_bits_rectangle.
+ * get_bits_rectangle may update members of this structure if
+ * the options allow it to choose their values, and always updates options
+ * to indicate what options were actually used (1 option per group).
+ */
+struct gs_get_bits_params_s {
+ gs_get_bits_options_t options;
+ byte *data[32];
+ int x_offset; /* in returned data */
+ uint raster;
+};
+
+/*
+ * gx_bitmap_format_t defines the options passed to get_bits_rectangle,
+ * which indicate which formats are acceptable for the returned data. If
+ * successful, get_bits_rectangle sets the options member of the parameter
+ * record to indicate what options were chosen -- 1 per group, and never the
+ * _ANY option. Note that the chosen option is not necessarily one that
+ * appeared in the original options: for example, if GB_RASTER_ANY is the
+ * only raster option originally set, the chosen option will be
+ * GB_RASTER_STANDARD or GB_RASTER_SPECIFIED.
+ *
+ * If the options mask is 0, get_bits_rectangle must set it to the
+ * complete set of supported options and return an error. This allows
+ * clients to determine what options are supported without actually doing
+ * a transfer.
+ *
+ * All devices must support at least one option in each group, and must
+ * support GB_COLORS_NATIVE.
+ *
+ * NOTE: the current default implementation supports only the following
+ * options in their respective groups (i.e., any other options must be
+ * supported directly by the device):
+ * GB_DEPTH_8
+ * GB_PACKING_CHUNKY
+ * GB_RETURN_COPY
+ * The current default implementation also requires that all devices
+ * support GB_PACKING_CHUNKY. */
+
+/* ---------------- Procedures ---------------- */
+
+/* Try to implement get_bits_rectangle by returning a pointer. */
+int gx_get_bits_return_pointer(P6(gx_device * dev, int x, int h,
+ gs_get_bits_params_t * params,
+ gs_get_bits_options_t stored,
+ byte * stored_base));
+
+/* Implement get_bits_rectangle by copying. */
+int gx_get_bits_copy(P8(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));
+
+#endif /* gxgetbit_INCLUDED */
diff --git a/pstoraster/gxhint1.c b/pstoraster/gxhint1.c
new file mode 100644
index 000000000..a5f005fb5
--- /dev/null
+++ b/pstoraster/gxhint1.c
@@ -0,0 +1,275 @@
+/* Copyright (C) 1990, 1992, 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$ */
+/* Font level hints for Type 1 fonts */
+#include "gx.h"
+#include "gserrors.h"
+#include "gxarith.h"
+#include "gxfixed.h"
+#include "gxmatrix.h"
+#include "gxfont.h"
+#include "gxfont1.h"
+#include "gxtype1.h"
+
+/* Define whether to use font hints. */
+/* Only set this to false for debugging the hint machinery. */
+static bool USE_HINTS = true;
+
+/* ------ Initialization ------ */
+
+typedef zone_table(1) a_zone_table;
+typedef stem_table(1) a_stem_table;
+private void
+ compute_snaps(P6(const gs_matrix_fixed *, const a_stem_table *,
+ stem_snap_table *, int, int, const char *));
+private alignment_zone *
+ compute_zones(P6(const gs_matrix_fixed *, const font_hints *,
+ const a_zone_table *, const a_zone_table *, alignment_zone *, int));
+private int
+ transform_zone(P4(const gs_matrix_fixed *, const font_hints *,
+ const float *, alignment_zone *));
+
+/* Reset the font-level hints. */
+void
+reset_font_hints(font_hints * pfh, const gs_log2_scale_point * plog2_scale)
+{
+ set_pixel_scale(&pfh->scale.x, plog2_scale->x);
+ set_pixel_scale(&pfh->scale.y, plog2_scale->y);
+ pfh->axes_swapped = pfh->x_inverted = pfh->y_inverted = false;
+ pfh->use_x_hints = pfh->use_y_hints = false;
+ pfh->snap_h.count = pfh->snap_v.count = 0;
+ pfh->a_zone_count = 0;
+}
+
+/* Compute the font-level hints from the font and the matrix. */
+/* We should cache this with the font/matrix pair.... */
+void
+compute_font_hints(font_hints * pfh, const gs_matrix_fixed * pmat,
+ const gs_log2_scale_point * plog2_scale, const gs_type1_data * pdata)
+{
+ alignment_zone *zp = &pfh->a_zones[0];
+
+ reset_font_hints(pfh, plog2_scale);
+ /* Figure out which hints, if any, to use, */
+ /* and the orientation of the axes. */
+ if (is_fzero(pmat->xy))
+ pfh->y_inverted = is_fneg(pmat->yy),
+ pfh->use_y_hints = USE_HINTS;
+ else if (is_fzero(pmat->xx))
+ pfh->y_inverted = is_fneg(pmat->xy),
+ pfh->axes_swapped = true,
+ pfh->use_y_hints = USE_HINTS;
+ if (is_fzero(pmat->yx))
+ pfh->x_inverted = is_fneg(pmat->xx),
+ pfh->use_x_hints = USE_HINTS;
+ else if (is_fzero(pmat->yy))
+ pfh->x_inverted = is_fneg(pmat->yx),
+ pfh->axes_swapped = true,
+ pfh->use_x_hints = USE_HINTS;
+ if_debug6('y', "[y]ctm=[%g %g %g %g %g %g]\n",
+ pmat->xx, pmat->xy, pmat->yx, pmat->yy,
+ pmat->tx, pmat->ty);
+ if_debug7('y', "[y]scale=%d/%d, swapped=%d, x/y_hints=%d,%d, x/y_inverted=%d,%d\n",
+ 1 << plog2_scale->x, 1 << plog2_scale->y,
+ pfh->axes_swapped, pfh->use_x_hints, pfh->use_y_hints,
+ pfh->x_inverted, pfh->y_inverted);
+ /* Transform the actual hints. */
+ if (pfh->use_x_hints) {
+ compute_snaps(pmat, (const a_stem_table *)&pdata->StdHW,
+ &pfh->snap_h, 0, pfh->axes_swapped, "h");
+ compute_snaps(pmat, (const a_stem_table *)&pdata->StemSnapH,
+ &pfh->snap_h, 0, pfh->axes_swapped, "h");
+ }
+ if (pfh->use_y_hints) {
+ gs_fixed_point vw;
+ fixed *vp = (pfh->axes_swapped ? &vw.x : &vw.y);
+ pixel_scale *psp =
+ (pfh->axes_swapped ? &pfh->scale.x : &pfh->scale.y);
+
+ /* Convert BlueFuzz to device pixels. */
+ if (gs_distance_transform2fixed(pmat, 0.0,
+ (float)pdata->BlueFuzz,
+ &vw) < 0
+ )
+ vw.x = vw.y = fixed_0;
+ pfh->blue_fuzz = any_abs(*vp);
+ /*
+ * Decide whether to suppress overshoots. The formula in
+ * section 5.6 of the "Adobe Type 1 Font Format" says that
+ * at 300 dpi, if BlueScale = (P - 0.49) / 240, overshoot
+ * suppression turns off at point sizes at least P, i.e.:
+ * P >= BlueScale * 240 + 0.49.
+ * At 300 dpi, P = |CTM.yy| / (300/72), so the condition is
+ * equivalent to
+ * |CTM.yy| >= BlueScale * 1000 + 2.0417,
+ * or
+ * BlueScale >= (|CTM.yy| - 2.0417) / 1000.
+ * Since *pmat is the concatenation of the FontMatrix and
+ * CTM, if we assume a 1000-unit scale, this is equivalent to
+ * BlueScale >= |pmat->yy| - 0.00020417.
+ * Since the constant term is slightly smaller than
+ * fixed_epsilon, we just disregard it.
+ *
+ * According to the same section of the Adobe documentation,
+ * there is a requirement that BlueScale times the maximum
+ * alignment zone height must be less than 1. We enforced
+ * this when the font was constructed (in zfont1.c).
+ */
+ if (gs_distance_transform2fixed(pmat, 0.0, 1.0, &vw) < 0)
+ vw.x = vw.y = fixed_0;
+ pfh->suppress_overshoot =
+ fixed2float(any_abs(*vp) >> psp->log2_unit) <
+ pdata->BlueScale;
+ if (gs_distance_transform2fixed(pmat, 0.0, pdata->BlueShift,
+ &vw) < 0
+ )
+ vw.x = vw.y = fixed_0;
+ pfh->blue_shift = any_abs(*vp);
+ /*
+ * Don't let the blue shift exceed half a pixel.
+ * See the discussion of BlueShift in section 5.7 of the
+ * "Adobe Type 1 Font Format" book.
+ */
+ if (pfh->blue_shift > psp->half)
+ pfh->blue_shift = psp->half;
+ if_debug6('y', "[y]blue_fuzz=%d->%g, blue_scale=%g, blue_shift=%g->%g, sup_ov=%d\n",
+ pdata->BlueFuzz, fixed2float(pfh->blue_fuzz),
+ pdata->BlueScale,
+ pdata->BlueShift, fixed2float(pfh->blue_shift),
+ pfh->suppress_overshoot);
+ zp = compute_zones(pmat, pfh,
+ (const a_zone_table *)&pdata->BlueValues,
+ (const a_zone_table *)&pdata->FamilyBlues,
+ zp, 1);
+ zp = compute_zones(pmat, pfh,
+ (const a_zone_table *)&pdata->OtherBlues,
+ (const a_zone_table *)&pdata->FamilyOtherBlues,
+ zp, max_OtherBlues);
+ compute_snaps(pmat, (const a_stem_table *)&pdata->StdVW,
+ &pfh->snap_v, 1, !pfh->axes_swapped, "v");
+ compute_snaps(pmat, (const a_stem_table *)&pdata->StemSnapV,
+ &pfh->snap_v, 1, !pfh->axes_swapped, "v");
+ }
+ pfh->a_zone_count = zp - &pfh->a_zones[0];
+}
+
+/* Transform one set of stem snap widths. */
+private void
+compute_snaps(const gs_matrix_fixed * pmat, const a_stem_table * pst,
+ stem_snap_table * psst, int from_y, int to_y, const char *tname)
+{
+ gs_fixed_point wxy;
+ fixed *wp = (to_y ? &wxy.y : &wxy.x);
+ int i;
+ int j = psst->count;
+
+ for (i = 0; i < pst->count; i++) {
+ float w = pst->values[i];
+ int code =
+ (from_y ?
+ gs_distance_transform2fixed(pmat, 0.0, w, &wxy) :
+ gs_distance_transform2fixed(pmat, w, 0.0, &wxy)
+ );
+
+ if (code < 0)
+ continue;
+ psst->data[j] = any_abs(*wp);
+ if_debug3('y', "[y]snap_%s[%d]=%g\n", tname, j,
+ fixed2float(psst->data[j]));
+ j++;
+ }
+ psst->count = j;
+}
+
+/* Compute the alignment zones for one set of 'blue' values. */
+private alignment_zone *
+compute_zones(const gs_matrix_fixed * pmat, const font_hints * pfh,
+ const a_zone_table * blues, const a_zone_table * family_blues,
+ alignment_zone * zp, int bottom_count)
+{
+ int i;
+ fixed fuzz = pfh->blue_fuzz;
+ int inverted =
+ (pfh->axes_swapped ? pfh->x_inverted : pfh->y_inverted);
+
+ for (i = 0; i < blues->count; i += 2) {
+ const float *vp = &blues->values[i];
+
+ zp->is_top_zone = i >> 1 >= bottom_count;
+ if (transform_zone(pmat, pfh, vp, zp) < 0)
+ continue;
+ if_debug5('y', "[y]blues[%d]=%g,%g -> %g,%g\n",
+ i >> 1, vp[0], vp[1],
+ fixed2float(zp->v0), fixed2float(zp->v1));
+ if (i < family_blues->count) { /* Check whether family blues should supersede. */
+ alignment_zone fz;
+ const float *fvp = &family_blues->values[i];
+ fixed unit = (pfh->axes_swapped ?
+ pfh->scale.x.unit : pfh->scale.y.unit);
+ fixed diff;
+
+ if (transform_zone(pmat, pfh, fvp, &fz) < 0)
+ continue;
+ if_debug5('y', "[y]f_blues[%d]=%g,%g -> %g,%g\n",
+ i >> 1, fvp[0], fvp[1],
+ fixed2float(fz.v0), fixed2float(fz.v1));
+ diff = (zp->v1 - zp->v0) - (fz.v1 - fz.v0);
+ if (diff > -unit && diff < unit)
+ zp->v0 = fz.v0, zp->v1 = fz.v1;
+ }
+ /* Compute the flat position, and add the fuzz. */
+ if ((inverted ? zp->is_top_zone : !zp->is_top_zone))
+ zp->flat = zp->v1, zp->v0 -= fuzz;
+ else
+ zp->flat = zp->v0, zp->v1 += fuzz;
+ zp++;
+ }
+ return zp;
+}
+
+/* Transform a single alignment zone to device coordinates, */
+/* taking axis swapping into account. */
+private int
+transform_zone(const gs_matrix_fixed * pmat, const font_hints * pfh,
+ const float *vp, alignment_zone * zp)
+{
+ gs_fixed_point p0, p1;
+ fixed v0, v1;
+ int code;
+
+ if ((code = gs_point_transform2fixed(pmat, 0.0, vp[0], &p0)) < 0 ||
+ (code = gs_point_transform2fixed(pmat, 0.0, vp[1], &p1)) < 0
+ )
+ return code;
+ if (pfh->axes_swapped)
+ v0 = p0.x, v1 = p1.x;
+ else
+ v0 = p0.y, v1 = p1.y;
+ if (v0 <= v1)
+ zp->v0 = v0, zp->v1 = v1;
+ else
+ zp->v0 = v1, zp->v1 = v0;
+ return 0;
+}
diff --git a/pstoraster/gxhint2.c b/pstoraster/gxhint2.c
new file mode 100644
index 000000000..f438d85fe
--- /dev/null
+++ b/pstoraster/gxhint2.c
@@ -0,0 +1,397 @@
+/* Copyright (C) 1990, 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$ */
+/* Character level hints for Type 1 fonts. */
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gxarith.h"
+#include "gxfixed.h"
+#include "gxmatrix.h"
+#include "gxfont.h"
+#include "gxfont1.h"
+#include "gxtype1.h"
+
+/* Define the tolerance for testing whether a point is in a zone, */
+/* in device pixels. (Maybe this should be variable?) */
+#define stem_tolerance float2fixed(0.05)
+
+/* Forward references */
+
+private stem_hint *type1_stem(P4(const gs_type1_state *, stem_hint_table *, fixed, fixed));
+private fixed find_snap(P3(fixed, const stem_snap_table *, const pixel_scale *));
+private alignment_zone *find_zone(P3(gs_type1_state *, fixed, fixed));
+
+/* Reset the stem hints. */
+void
+reset_stem_hints(gs_type1_state * pcis)
+{
+ pcis->hstem_hints.count = pcis->hstem_hints.replaced_count = 0;
+ pcis->vstem_hints.count = pcis->vstem_hints.replaced_count = 0;
+ update_stem_hints(pcis);
+}
+
+/* Prepare to replace the stem hints. */
+private void
+save_replaced_hints(stem_hint_table * psht)
+{
+ int rep_count = min(psht->replaced_count + psht->count, max_stems);
+
+ memmove(&psht->data[max_stems - rep_count], &psht->data[0],
+ psht->count * sizeof(psht->data[0]));
+ psht->replaced_count = rep_count;
+ psht->count = psht->current = 0;
+}
+void
+type1_replace_stem_hints(gs_type1_state * pcis)
+{
+ if_debug2('y', "[y]saving hints: %d hstem, %d vstem\n",
+ pcis->hstem_hints.count, pcis->vstem_hints.count);
+ save_replaced_hints(&pcis->hstem_hints);
+ save_replaced_hints(&pcis->vstem_hints);
+ if_debug2('y', "[y]total saved hints: %d hstem, %d vstem\n",
+ pcis->hstem_hints.replaced_count,
+ pcis->vstem_hints.replaced_count);
+}
+
+/* Update the internal stem hint pointers after moving or copying the state. */
+void
+update_stem_hints(gs_type1_state * pcis)
+{
+ pcis->hstem_hints.current = 0;
+ pcis->vstem_hints.current = 0;
+}
+
+/* ------ Add hints ------ */
+
+#undef c_fixed
+#define c_fixed(d, c) m_fixed(d, c, pcis->fc, max_coeff_bits)
+
+#define if_debug_print_add_stem(chr, msg, psht, psh, c, dc, v, dv)\
+ if_debug10(chr, "%s %d/%d: %g,%g -> %g(%g)%g ; d = %g,%g\n",\
+ msg, (int)((psh) - &(psht)->data[0]), (psht)->count,\
+ fixed2float(c), fixed2float(dc),\
+ fixed2float(v), fixed2float(dv), fixed2float((v) + (dv)),\
+ fixed2float((psh)->dv0), fixed2float((psh)->dv1))
+
+/* Compute and store the adjusted stem coordinates. */
+private void
+store_stem_deltas(const stem_hint_table * psht, stem_hint * psh,
+ const pixel_scale * psp, fixed v, fixed dv, fixed adj_dv)
+{ /*
+ * We want to align the stem so its edges fall on pixel boundaries
+ * (possibly "big pixel" boundaries if we are oversampling),
+ * but if hint replacement has occurred, we must shift edges in a
+ * consistent way. This is a real nuisance, but I don't see how
+ * to avoid it; if we don't do it, we get bizarre anomalies like
+ * disappearing stems.
+ */
+ const stem_hint *psh0 = 0;
+ const stem_hint *psh1 = 0;
+ int i;
+
+ /*
+ * If we ever had a hint with the same edge(s), align this one
+ * the same way.
+ */
+ for (i = max_stems - psht->replaced_count; i < max_stems; ++i) {
+ const stem_hint *ph = &psht->data[i];
+
+ if (ph == psh)
+ continue;
+ if (ph->v0 == psh->v0)
+ psh0 = ph;
+ if (ph->v1 == psh->v1)
+ psh1 = ph;
+ }
+ for (i = 0; i < psht->count; ++i) {
+ const stem_hint *ph = &psht->data[i];
+
+ if (ph == psh)
+ continue;
+ if (ph->v0 == psh->v0)
+ psh0 = ph;
+ if (ph->v1 == psh->v1)
+ psh1 = ph;
+ }
+ if (psh0 != 0) {
+ psh->dv0 = psh0->dv0;
+ if (psh1 != 0) { /* Both edges are determined. */
+ psh->dv1 = psh1->dv1;
+ } else { /* Only the lower edge is determined. */
+ psh->dv1 = psh->dv0 + adj_dv - dv;
+ }
+ } else if (psh1 != 0) { /* Only the upper edge is determined. */
+ psh->dv1 = psh1->dv1;
+ psh->dv0 = psh->dv1 + adj_dv - dv;
+ } else { /* Neither edge is determined. */
+ fixed diff2_dv = arith_rshift_1(adj_dv - dv);
+ fixed edge = v - diff2_dv;
+ fixed diff_v = scaled_rounded(edge, psp) - edge;
+
+ psh->dv0 = diff_v - diff2_dv;
+ psh->dv1 = diff_v + diff2_dv;
+ }
+}
+
+/* Add a horizontal stem hint. */
+void
+type1_do_hstem(gs_type1_state * pcis, fixed y, fixed dy,
+ const gs_matrix_fixed * pmat)
+{
+ stem_hint *psh;
+ alignment_zone *pz;
+ const pixel_scale *psp;
+ fixed v, dv, adj_dv;
+ fixed vtop, vbot;
+
+ if (!pcis->fh.use_y_hints || !pmat->txy_fixed_valid)
+ return;
+ y += pcis->lsb.y + pcis->adxy.y;
+ if (pcis->fh.axes_swapped) {
+ psp = &pcis->scale.x;
+ v = pcis->vs_offset.x + c_fixed(y, yx) + pmat->tx_fixed;
+ dv = c_fixed(dy, yx);
+ } else {
+ psp = &pcis->scale.y;
+ v = pcis->vs_offset.y + c_fixed(y, yy) + pmat->ty_fixed;
+ dv = c_fixed(dy, yy);
+ }
+ if (dy < 0)
+ vbot = v + dv, vtop = v;
+ else
+ vbot = v, vtop = v + dv;
+ if (dv < 0)
+ v += dv, dv = -dv;
+ psh = type1_stem(pcis, &pcis->hstem_hints, v, dv);
+ if (psh == 0)
+ return;
+ adj_dv = find_snap(dv, &pcis->fh.snap_h, psp);
+ pz = find_zone(pcis, vbot, vtop);
+ if (pz != 0) { /* Use the alignment zone to align the outer stem edge. */
+ int inverted =
+ (pcis->fh.axes_swapped ? pcis->fh.x_inverted : pcis->fh.y_inverted);
+ int adjust_v1 =
+ (inverted ? !pz->is_top_zone : pz->is_top_zone);
+ fixed flat_v = pz->flat;
+ fixed overshoot =
+ (pz->is_top_zone ? vtop - flat_v : flat_v - vbot);
+ fixed pos_over =
+ (inverted ? -overshoot : overshoot);
+ fixed ddv = adj_dv - dv;
+ fixed shift = scaled_rounded(flat_v, psp) - flat_v;
+
+ if (pos_over > 0) {
+ if (pos_over < pcis->fh.blue_shift || pcis->fh.suppress_overshoot) { /* Character is small, suppress overshoot. */
+ if_debug0('y', "[y]suppress overshoot\n");
+ if (pz->is_top_zone)
+ shift -= overshoot;
+ else
+ shift += overshoot;
+ } else if (pos_over < psp->unit) { /* Enforce overshoot. */
+ if_debug0('y', "[y]enforce overshoot\n");
+ if (overshoot < 0)
+ overshoot = -psp->unit - overshoot;
+ else
+ overshoot = psp->unit - overshoot;
+ if (pz->is_top_zone)
+ shift += overshoot;
+ else
+ shift -= overshoot;
+ }
+ }
+ if (adjust_v1)
+ psh->dv1 = shift, psh->dv0 = shift - ddv;
+ else
+ psh->dv0 = shift, psh->dv1 = shift + ddv;
+ if_debug2('y', "[y]flat_v = %g, overshoot = %g for:\n",
+ fixed2float(flat_v), fixed2float(overshoot));
+ } else { /* Align the stem so its edges fall on pixel boundaries. */
+ store_stem_deltas(&pcis->hstem_hints, psh, psp, v, dv, adj_dv);
+ }
+ if_debug_print_add_stem('y', "[y]hstem", &pcis->hstem_hints, psh,
+ y, dy, v, dv);
+}
+
+/* Add a vertical stem hint. */
+void
+type1_do_vstem(gs_type1_state * pcis, fixed x, fixed dx,
+ const gs_matrix_fixed * pmat)
+{
+ stem_hint *psh;
+ const pixel_scale *psp;
+ fixed v, dv, adj_dv;
+
+ if (!pcis->fh.use_x_hints)
+ return;
+ x += pcis->lsb.x + pcis->adxy.x;
+ if (pcis->fh.axes_swapped) {
+ psp = &pcis->scale.y;
+ v = pcis->vs_offset.y + c_fixed(x, xy) + pmat->ty_fixed;
+ dv = c_fixed(dx, xy);
+ } else {
+ psp = &pcis->scale.x;
+ v = pcis->vs_offset.x + c_fixed(x, xx) + pmat->tx_fixed;
+ dv = c_fixed(dx, xx);
+ }
+ if (dv < 0)
+ v += dv, dv = -dv;
+ psh = type1_stem(pcis, &pcis->vstem_hints, v, dv);
+ if (psh == 0)
+ return;
+ adj_dv = find_snap(dv, &pcis->fh.snap_v, psp);
+ if (pcis->pfont->data.ForceBold && adj_dv < psp->unit)
+ adj_dv = psp->unit;
+ /* Align the stem so its edges fall on pixel boundaries. */
+ store_stem_deltas(&pcis->vstem_hints, psh, psp, v, dv, adj_dv);
+ if_debug_print_add_stem('y', "[y]vstem", &pcis->vstem_hints, psh,
+ x, dx, v, dv);
+}
+
+/* Adjust the character center for a vstem3. */
+/****** NEEDS UPDATING FOR SCALE ******/
+void
+type1_do_center_vstem(gs_type1_state * pcis, fixed x0, fixed dx,
+ const gs_matrix_fixed * pmat)
+{
+ fixed x1 = x0 + dx;
+ gs_fixed_point pt0, pt1, width;
+ fixed center, int_width;
+ fixed *psxy;
+
+ if (gs_point_transform2fixed(pmat, fixed2float(x0), 0.0, &pt0) < 0 ||
+ gs_point_transform2fixed(pmat, fixed2float(x1), 0.0, &pt1) < 0
+ ) { /* Punt. */
+ return;
+ }
+ width.x = pt0.x - pt1.x;
+ if (width.x < 0)
+ width.x = -width.x;
+ width.y = pt0.y - pt1.y;
+ if (width.y < 0)
+ width.y = -width.y;
+ if (width.y < float2fixed(0.05)) { /* Vertical on device */
+ center = arith_rshift_1(pt0.x + pt1.x);
+ int_width = fixed_rounded(width.x);
+ psxy = &pcis->vs_offset.x;
+ } else { /* Horizontal on device */
+ center = arith_rshift_1(pt0.y + pt1.y);
+ int_width = fixed_rounded(width.y);
+ psxy = &pcis->vs_offset.y;
+ }
+ if (int_width == fixed_0 || (int_width & fixed_1) == 0) { /* Odd width, center stem over pixel. */
+ *psxy = fixed_floor(center) + fixed_half - center;
+ } else { /* Even width, center stem between pixels. */
+ *psxy = fixed_rounded(center) - center;
+ }
+ /* We can't fix up the current point here, */
+ /* but we can fix up everything else. */
+/****** TO BE COMPLETED ******/
+}
+
+/* Add a stem hint, keeping the table sorted. */
+/* We know that d >= 0. */
+/* Return the stem hint pointer, or 0 if the table is full. */
+private stem_hint *
+type1_stem(const gs_type1_state * pcis, stem_hint_table * psht,
+ fixed v0, fixed d)
+{
+ stem_hint *bot = &psht->data[0];
+ stem_hint *top = bot + psht->count;
+
+ if (psht->count >= max_stems)
+ return 0;
+ while (top > bot && v0 < top[-1].v0) {
+ *top = top[-1];
+ top--;
+ }
+ /* Add a little fuzz for insideness testing. */
+ top->v0 = v0 - stem_tolerance;
+ top->v1 = v0 + d + stem_tolerance;
+ top->index = pcis->hstem_hints.count + pcis->vstem_hints.count;
+ top->active = true;
+ psht->count++;
+ return top;
+}
+
+/* Compute the adjusted width of a stem. */
+/* The value returned is always a multiple of scale.unit. */
+private fixed
+find_snap(fixed dv, const stem_snap_table * psst, const pixel_scale * pps)
+{ /* We aren't sure why a maximum difference of pps->half */
+ /* works better than pps->unit, but it does. */
+#define max_snap_distance (pps->half)
+ fixed best = max_snap_distance;
+ fixed adj_dv;
+ int i;
+
+ for (i = 0; i < psst->count; i++) {
+ fixed diff = psst->data[i] - dv;
+
+ if (any_abs(diff) < any_abs(best)) {
+ if_debug3('Y', "[Y]possibly snap %g to [%d]%g\n",
+ fixed2float(dv), i,
+ fixed2float(psst->data[i]));
+ best = diff;
+ }
+ }
+ adj_dv = scaled_rounded((any_abs(best) < max_snap_distance ?
+ dv + best : dv),
+ pps);
+ if (adj_dv == 0)
+ adj_dv = pps->unit;
+#ifdef DEBUG
+ if (adj_dv == dv)
+ if_debug1('Y', "[Y]no snap %g\n", fixed2float(dv));
+ else
+ if_debug2('Y', "[Y]snap %g to %g\n",
+ fixed2float(dv), fixed2float(adj_dv));
+#endif
+ return adj_dv;
+#undef max_snap_distance
+}
+
+/* Find the applicable alignment zone for a stem, if any. */
+/* vbot and vtop are the bottom and top of the stem, */
+/* but without interchanging if the y axis is inverted. */
+private alignment_zone *
+find_zone(gs_type1_state * pcis, fixed vbot, fixed vtop)
+{
+ alignment_zone *pz;
+
+ for (pz = &pcis->fh.a_zones[pcis->fh.a_zone_count];
+ --pz >= &pcis->fh.a_zones[0];
+ ) {
+ fixed v = (pz->is_top_zone ? vtop : vbot);
+
+ if (v >= pz->v0 && v <= pz->v1) {
+ if_debug2('Y', "[Y]stem crosses %s-zone %d\n",
+ (pz->is_top_zone ? "top" : "bottom"),
+ (int)(pz - &pcis->fh.a_zones[0]));
+ return pz;
+ }
+ }
+ return 0;
+}
diff --git a/pstoraster/gxhint3.c b/pstoraster/gxhint3.c
new file mode 100644
index 000000000..ea3e0bda1
--- /dev/null
+++ b/pstoraster/gxhint3.c
@@ -0,0 +1,560 @@
+/* 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$ */
+/* Apply hints for Type 1 fonts. */
+#include "math_.h" /* for floor in fixed_mult_quo */
+#include "gx.h"
+#include "gserrors.h"
+#include "gxarith.h"
+#include "gxfixed.h"
+#include "gxmatrix.h"
+#include "gxfont.h"
+#include "gxfont1.h"
+#include "gxtype1.h"
+#include "gzpath.h"
+
+/* ------ Path hints ------ */
+
+/* Forward references */
+private void
+ apply_hstem_hints(P3(gs_type1_state *, int, gs_fixed_point *)), apply_vstem_hints(P3(gs_type1_state *, int, gs_fixed_point *));
+
+
+/*
+ * Apply hints along a newly added tail of a subpath.
+ * Path segments require hints as follows:
+ * Nearly vertical line: vstem hints at both ends.
+ * Nearly horizontal line: hstem hints at both ends.
+ * Curve with nearly vertical/horizontal start/end:
+ * vstem/hstem hints at start/end.
+ * We also must take care to handle the implicit closing line for
+ * subpaths that aren't explicitly closed.
+ *
+ * Note that "upper" and "lower" refer to device coordinates, which are
+ * what we use throughout the Type 1 code; however, "horizontal" and
+ * "vertical" refer to the character space coordinate system.
+ */
+#define HINT_VERT_LOWER 1
+#define HINT_VERT_UPPER 2 /* must be > lower */
+#define HINT_VERT (HINT_VERT_LOWER | HINT_VERT_UPPER)
+#define HINT_HORZ_LOWER 4
+#define HINT_HORZ_UPPER 8 /* must be > lower */
+#define HINT_HORZ (HINT_HORZ_LOWER | HINT_HORZ_UPPER)
+#define NEARLY_AXIAL(dmajor, dminor)\
+ ((dminor) <= (dmajor) >> 4)
+
+/*
+ * Determine which types of hints, if any, are applicable to a given
+ * line segment.
+ */
+private int
+line_hints(const gs_type1_state * pcis, const gs_fixed_point * p0,
+ const gs_fixed_point * p1)
+{
+ fixed dx = p1->x - p0->x;
+ fixed dy = p1->y - p0->y;
+ fixed adx, ady;
+ bool xi = pcis->fh.x_inverted, yi = pcis->fh.y_inverted;
+ int hints;
+
+ /*
+ * To figure out which side of the stem we are on, we assume that the
+ * inside of the filled area is always to the left of the edge, i.e.,
+ * edges moving in -X or +Y in character space are on the "upper" side
+ * of the stem, while edges moving by +X or -Y are on the "lower" side.
+ * (See section 3.5 of the Adobe Type 1 Font Format book.)
+ */
+
+ /*
+ * Map the deltas back into character space. This is essentially an
+ * inverse-distance-transform with the combined matrix, but we don't
+ * bother to undo the scaling, since it only matters for the axiality
+ * test and we don't care about situations where X and Y scaling are
+ * radically different.
+ */
+ if (xi)
+ dx = -dx;
+ if (yi)
+ dy = -dy;
+ if (pcis->fh.axes_swapped) {
+ fixed t = dx;
+ int ti = xi;
+
+ dx = dy, xi = yi;
+ dy = t, yi = ti;
+ }
+ adx = any_abs(dx);
+ ady = any_abs(dy);
+ /*
+ * Note that since upper/lower refer to device space, we must
+ * interchange them if the corresponding axis is inverted.
+ */
+ if (dy != 0 && NEARLY_AXIAL(ady, adx)) {
+ hints = (dy > 0 ? HINT_VERT_UPPER : HINT_VERT_LOWER);
+ if (xi)
+ hints ^= (HINT_VERT_LOWER | HINT_VERT_UPPER);
+ } else if (dx != 0 && NEARLY_AXIAL(adx, ady)) {
+ hints = (dx < 0 ? HINT_HORZ_UPPER : HINT_HORZ_LOWER);
+ if (yi)
+ hints ^= (HINT_HORZ_LOWER | HINT_HORZ_UPPER);
+ } else
+ hints = 0;
+ if_debug7('y', "[y]hint from 0x%lx(%1.4f,%1.4f) to 0x%lx(%1.4f,%1.4f) = %d\n",
+ (ulong) p0, fixed2float(p0->x), fixed2float(p0->y),
+ (ulong) p1, fixed2float(p1->x), fixed2float(p1->y),
+ hints);
+ return hints;
+}
+
+/* Apply hints at a point. Optionally return the amount of adjustment. */
+private void
+apply_hints_at(gs_type1_state * pcis, int hints, gs_fixed_point * ppt,
+ gs_fixed_point * pdiff)
+{
+ fixed px = ppt->x, py = ppt->y;
+
+ if_debug4('y', "[y]applying hints %d to 0x%lx(%1.4f,%1.4f) ...\n",
+ hints, (ulong) ppt, fixed2float(px), fixed2float(py));
+ if ((hints & HINT_VERT) != 0 &&
+ (pcis->vstem_hints.count & pcis->dotsection_flag) != 0
+ )
+ apply_vstem_hints(pcis, (hints & HINT_VERT_UPPER) -
+ (hints & HINT_VERT_LOWER), ppt);
+ if ((hints & HINT_HORZ) != 0 &&
+ (pcis->hstem_hints.count & pcis->dotsection_flag) != 0
+ )
+ apply_hstem_hints(pcis, (hints & HINT_HORZ_UPPER) -
+ (hints & HINT_HORZ_LOWER), ppt);
+ if (pdiff != NULL)
+ pdiff->x = ppt->x - px,
+ pdiff->y = ppt->y - py;
+ /* Here is where we would round *ppt to the nearest quarter-pixel */
+ /* if we wanted to. */
+ if_debug2('y', "[y] ... => (%1.4f,%1.4f)\n",
+ fixed2float(ppt->x), fixed2float(ppt->y));
+}
+
+/* Add a hint delta to a point. */
+#ifndef DEBUG
+inline
+#endif
+private void
+add_hint_diff(gs_fixed_point * ppt, gs_fixed_point delta)
+{
+ if_debug7('y', "[y]adding diff (%1.4f,%1.4f) to 0x%lx(%1.4f,%1.4f) => (%1.4f,%1.4f)\n",
+ fixed2float(delta.x), fixed2float(delta.y), (ulong) ppt,
+ fixed2float(ppt->x), fixed2float(ppt->y),
+ fixed2float(ppt->x + delta.x), fixed2float(ppt->y + delta.y));
+ ppt->x += delta.x;
+ ppt->y += delta.y;
+}
+
+/* Test whether a line is null. */
+inline private bool
+line_is_null(gs_fixed_point p0, gs_fixed_point p1)
+{
+ return (any_abs(p1.x - p0.x) + any_abs(p1.y - p0.y) < fixed_epsilon * 4);
+}
+
+/*
+ * Adjust the other control points of a curve proportionately when moving
+ * one end. The Boolean argument indicates whether the point being
+ * adjusted is the one nearer the point that was moved.
+ */
+private fixed
+scale_delta(fixed diff, fixed dv, fixed lv, bool nearer)
+{
+ if (dv == 0)
+ return 0;
+ /*
+ * fixed_mult_quo requires non-negative 2nd and 3rd arguments,
+ * and also 2nd argument < 3rd argument.
+ * If it weren't for that, we would just use it directly.
+ *
+ * lv = 0 is implausible, but we have to allow for it.
+ */
+ if (lv == 0)
+ return (nearer ? diff : fixed_0);
+ if (lv < 0)
+ lv = -lv, dv = -dv;
+ if (dv < 0)
+ dv = -dv, diff = -diff;
+ /*
+ * If dv > lv, there has been some kind of anomaly similar to
+ * the lv = 0 case.
+ */
+ if (dv >= lv)
+ return (nearer ? diff : fixed_0);
+ else
+ return fixed_mult_quo(diff, dv, lv);
+}
+private void
+adjust_curve_start(curve_segment * pcseg, const gs_fixed_point * pdiff)
+{
+ fixed dx = pdiff->x, dy = pdiff->y;
+ fixed end_x = pcseg->pt.x, end_y = pcseg->pt.y;
+ const segment *prev = pcseg->prev;
+ fixed lx = end_x - (prev->pt.x - dx), ly = end_y - (prev->pt.y - dy);
+ gs_fixed_point delta;
+
+ delta.x = scale_delta(end_x - pcseg->p1.x, dx, lx, true);
+ delta.y = scale_delta(end_y - pcseg->p1.y, dy, ly, true);
+ add_hint_diff(&pcseg->p1, delta);
+ delta.x = scale_delta(end_x - pcseg->p2.x, dx, lx, false);
+ delta.y = scale_delta(end_y - pcseg->p2.y, dy, ly, false);
+ add_hint_diff(&pcseg->p2, delta);
+}
+private void
+adjust_curve_end(curve_segment * pcseg, const gs_fixed_point * pdiff)
+{
+ fixed dx = pdiff->x, dy = pdiff->y;
+ const segment *prev = pcseg->prev;
+ fixed start_x = prev->pt.x, start_y = prev->pt.y;
+ fixed lx = pcseg->pt.x - dx - start_x, ly = pcseg->pt.y - dy - start_y;
+ gs_fixed_point delta;
+
+ delta.x = scale_delta(pcseg->p1.x - start_x, dx, lx, false);
+ delta.y = scale_delta(pcseg->p1.y - start_y, dy, ly, false);
+ add_hint_diff(&pcseg->p1, delta);
+ delta.x = scale_delta(pcseg->p2.x - start_x, dx, lx, true);
+ delta.y = scale_delta(pcseg->p2.y - start_y, dy, ly, true);
+ add_hint_diff(&pcseg->p2, delta);
+}
+
+/*
+ * Propagate a final wraparound hint back through any null line segments
+ * to a possible curve. pseg_last.pt has already been adjusted.
+ */
+private void
+apply_final_hint(segment * pseg_last, const gs_fixed_point * pdiff)
+{
+ segment *pseg;
+
+ for (pseg = pseg_last;; pseg = pseg->prev) {
+ segment *prev = pseg->prev;
+
+ switch (pseg->type) {
+ case s_curve:
+ adjust_curve_end(((curve_segment *) pseg), pdiff);
+ return;
+ case s_line:
+ case s_line_close:
+ if (!line_is_null(prev->pt, pseg->pt))
+ return;
+ add_hint_diff(&prev->pt, *pdiff);
+ break;
+ default: /* s_start */
+ return;
+ }
+ }
+}
+
+/*
+ * Handle the end of the subpath wrapping around to the start. This is
+ * ugly, messy code that we should be able to improve, but I neither see how
+ * to do it nor understand how the IBM Type 1 rasterizer can produce such
+ * good results without doing anything like this.
+ *
+ * This is a separate procedure only for readability: it is only called
+ * from one place in the next procedure.
+ */
+private void
+apply_wrapped_hints(gs_type1_state * pcis, subpath * psub, segment * pseg,
+ int hints, gs_fixed_point * pdiff)
+{
+ /* Some fonts don't use closepath when they should.... */
+ fixed ctemp;
+ bool closed =
+ (pseg->type == s_line_close ||
+ ((ctemp = pseg->pt.x - psub->pt.x,
+ any_abs(ctemp) < float2fixed(0.1)) &&
+ (ctemp = pseg->pt.y - psub->pt.y,
+ any_abs(ctemp) < float2fixed(0.1))));
+ segment *const pfirst = psub->next;
+ int hints_first = pcis->hints_initial;
+
+ if (closed) {
+ /*
+ * Apply the union of the hints at both the end (pseg) and the start
+ * (psub) of the subpath. Note that we have already applied hints
+ * at the end, and hints_first at the start. However, because of
+ * hint replacement, the points might differ even if hints ==
+ * hints_first. In this case, the initial hints take priority,
+ * because the initial segment was laid down first.
+ */
+ int do_x, do_y;
+ gs_fixed_point diff2;
+
+ if_debug2('y', "[y]closing closed, hints=%d, hints_first=%d\n",
+ hints, hints_first);
+ if (pcis->fh.axes_swapped)
+ do_x = HINT_HORZ, do_y = HINT_VERT;
+ else
+ do_x = HINT_VERT, do_y = HINT_HORZ;
+ {
+ /* Apply hints_first - hints to the end. */
+ int hints_end = hints_first & ~hints;
+
+ diff2.x =
+ (hints_end & do_x ?
+ psub->pt.x - pcis->unmoved_start.x : 0);
+ diff2.y =
+ (hints_end & do_y ?
+ psub->pt.y - pcis->unmoved_start.y : 0);
+ }
+ {
+ /* Apply hints - hints_first to the start. */
+ int hints_start = hints & ~hints_first;
+
+ pdiff->x =
+ (hints_start & do_x ?
+ pseg->pt.x - pcis->unmoved_end.x : 0);
+ pdiff->y =
+ (hints_start & do_y ?
+ pseg->pt.y - pcis->unmoved_end.y : 0);
+ }
+ add_hint_diff(&pseg->pt, diff2);
+ apply_final_hint(pseg, &diff2);
+ add_hint_diff(&psub->pt, *pdiff);
+ /*
+ * Now align the initial and final points, to deal with hint
+ * replacement.
+ */
+ diff2.x = psub->pt.x - pseg->pt.x;
+ diff2.y = psub->pt.y - pseg->pt.y;
+ if (diff2.x || diff2.y) {
+ /* Force the points to coincide. */
+ pseg->pt = psub->pt;
+ apply_final_hint(pseg, &diff2);
+ }
+ } else {
+ int hints_close =
+ line_hints(pcis, &pcis->unmoved_end, &pcis->unmoved_start);
+
+ hints_close &= ~(hints | hints_first);
+ if_debug3('y', "[y]closing open, hints=%d, hints_close=%d, hints_first=%d\n",
+ hints, hints_close, hints_first);
+ if (hints_close) {
+ apply_hints_at(pcis, hints_close, &pseg->pt, pdiff);
+ apply_final_hint(pseg, pdiff);
+ apply_hints_at(pcis, hints_close, &psub->pt, pdiff);
+ } else
+ pdiff->x = pdiff->y = 0;
+ }
+ if (pfirst->type == s_curve)
+ adjust_curve_start((curve_segment *) pfirst, pdiff);
+}
+
+/*
+ * Apply hints along a subpath. If closing is true, consider the subpath
+ * closed; if not, we may add more to the subpath later. In the latter case,
+ * don't do anything if the subpath is closed, because we already applied
+ * the hints.
+ */
+void
+type1_apply_path_hints(gs_type1_state * pcis, bool closing, gx_path * ppath)
+{
+ segment *pseg = pcis->hint_next;
+ segment *pnext;
+ subpath *const psub = ppath->current_subpath;
+
+ /*
+ * hints holds the set of hints that have already been applied (if
+ * applicable) to pseg->pt, and hence should not be applied again.
+ */
+ int hints = pcis->hints_pending;
+ gs_fixed_point diff;
+
+ /*
+ * Since unknown OtherSubrs call apply_path_hints before returning
+ * to the client, and since OtherSubrs may be invoked before the
+ * [h]sbw is seen, it's possible that init_done < 0, i.e., the path
+ * and hint members of the state haven't been set up yet. In this
+ * case, we know there are no relevant hints.
+ */
+ if (pcis->init_done < 0)
+ return;
+ if (pseg == 0) {
+ /* Start at the beginning of the subpath. */
+ if (psub == 0)
+ return;
+ if (psub->is_closed && !closing)
+ return;
+ pseg = (segment *) psub;
+ if (pseg->next == 0)
+ return;
+ hints = 0;
+ pcis->unmoved_start = psub->pt;
+ pcis->unmoved_end = psub->pt;
+ } else
+ hints = pcis->hints_pending;
+ diff.x = diff.y = 0;
+ for (; (pnext = pseg->next) != 0; pseg = pnext) {
+ int hints_next;
+
+ /*
+ * Apply hints to the end of the previous segment (pseg)
+ * and the beginning of this one (pnext).
+ */
+ gs_fixed_point dseg;
+
+ switch (pnext->type) {
+ case s_curve:{
+ curve_segment *const pnext_curve = (curve_segment *) pnext;
+ int hints_first =
+ line_hints(pcis, &pcis->unmoved_end,
+ &pnext_curve->p1) & ~hints;
+ gs_fixed_point diff2;
+
+ if (pseg == (segment *) psub)
+ pcis->hints_initial = hints_first;
+ if (hints_first)
+ apply_hints_at(pcis, hints_first, &pseg->pt, &dseg);
+ else
+ dseg.x = dseg.y = 0;
+ diff2.x = pseg->pt.x - pcis->unmoved_end.x;
+ diff2.y = pseg->pt.y - pcis->unmoved_end.y;
+ hints_next = line_hints(pcis, &pnext_curve->p2, &pnext->pt);
+ adjust_curve_start(pnext_curve, &diff2);
+ if (hints_next) {
+ apply_hints_at(pcis, hints_next, &pnext_curve->p2, &diff);
+ pcis->unmoved_end = pnext->pt;
+ add_hint_diff(&pnext->pt, diff);
+ } else
+ pcis->unmoved_end = pnext->pt;
+ break;
+ }
+ case s_line_close:
+ /* Undo any initial hints propagated to the end. */
+ pnext->pt = pcis->unmoved_start;
+ default: /* s_line, s_line_close */
+ if (line_is_null(pnext->pt, pcis->unmoved_end)) {
+ /* This is a null line, just move it. */
+ hints_next = hints;
+ dseg.x = dseg.y = 0; /* don't move p2 again */
+ } else {
+ hints_next =
+ line_hints(pcis, &pcis->unmoved_end, &pnext->pt);
+ if (hints_next & ~hints)
+ apply_hints_at(pcis, hints_next & ~hints,
+ &pseg->pt, &dseg);
+ else
+ dseg.x = dseg.y = 0;
+ }
+ if (pseg == (segment *) psub)
+ pcis->hints_initial = hints_next;
+ pcis->unmoved_end = pnext->pt;
+ if (hints_next)
+ apply_hints_at(pcis, hints_next, &pnext->pt, NULL);
+ }
+ if (pseg->type == s_curve)
+ adjust_curve_end((curve_segment *) pseg, &dseg);
+ hints = hints_next;
+ }
+ if (closing) {
+ apply_wrapped_hints(pcis, psub, pseg, hints, &diff);
+ pcis->hint_next = 0;
+ pcis->hints_pending = 0;
+ } else {
+ pcis->hint_next = pseg;
+ pcis->hints_pending = hints;
+ }
+}
+
+/* ------ Individual hints ------ */
+
+private const stem_hint *search_hints(P2(stem_hint_table *, fixed));
+
+/*
+ * Adjust a point according to the relevant hints.
+ * dx or dy is > 0 for the upper edge, < 0 for the lower.
+ * The caller is responsible for checking use_hstem_hints or use_vstem_hints
+ * and not calling the find_xxx_hints routine if this is false.
+ * Note that if use_x/y_hints is false, no entries ever get made
+ * in the stem hint tables, so these routines will not get called.
+ */
+
+private void
+apply_vstem_hints(gs_type1_state * pcis, int dy, gs_fixed_point * ppt)
+{
+ fixed *pv = (pcis->fh.axes_swapped ? &ppt->y : &ppt->x);
+ const stem_hint *ph = search_hints(&pcis->vstem_hints, *pv);
+
+ if (ph != 0) {
+ if_debug3('Y', "[Y]use vstem %d: %1.4f (%s)",
+ (int)(ph - &pcis->vstem_hints.data[0]),
+ fixed2float(*pv),
+ (dy == 0 ? "?!" : dy > 0 ? "upper" : "lower"));
+#ifdef DEBUG
+ if (dy == 0) {
+ lprintf("dy == 0 in apply_vstem_hints!\n");
+ return;
+ }
+#endif
+ *pv += (dy > 0 ? ph->dv1 : ph->dv0);
+ if_debug1('Y', " -> %1.4f\n", fixed2float(*pv));
+ }
+}
+
+private void
+apply_hstem_hints(gs_type1_state * pcis, int dx, gs_fixed_point * ppt)
+{
+ fixed *pv = (pcis->fh.axes_swapped ? &ppt->x : &ppt->y);
+ const stem_hint *ph = search_hints(&pcis->hstem_hints, *pv);
+
+ if (ph != 0) {
+ if_debug3('Y', "[Y]use hstem %d: %1.4f (%s)",
+ (int)(ph - &pcis->hstem_hints.data[0]),
+ fixed2float(*pv),
+ (dx == 0 ? "?!" : dx > 0 ? "upper" : "lower"));
+#ifdef DEBUG
+ if (dx == 0) {
+ lprintf("dx == 0 in apply_vstem_hints!\n");
+ return;
+ }
+#endif
+ *pv += (dx > 0 ? ph->dv1 : ph->dv0);
+ if_debug1('Y', " -> %1.4f\n", fixed2float(*pv));
+ }
+}
+
+/* Search one hint table for an adjustment. */
+private const stem_hint *
+search_hints(stem_hint_table * psht, fixed v)
+{
+ const stem_hint *table = &psht->data[0];
+ const stem_hint *ph = table + psht->current;
+
+ if (v >= ph->v0 && v <= ph->v1 && ph->active)
+ return ph;
+ /* We don't bother with binary or even up/down search, */
+ /* because there won't be very many hints. */
+ for (ph = &table[psht->count]; --ph >= table;)
+ if (v >= ph->v0 && v <= ph->v1 && ph->active) {
+ psht->current = ph - table;
+ return ph;
+ }
+ return 0;
+}
diff --git a/pstoraster/gxht.c b/pstoraster/gxht.c
new file mode 100644
index 000000000..7b03ddba9
--- /dev/null
+++ b/pstoraster/gxht.c
@@ -0,0 +1,532 @@
+/* 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$ */
+/* Halftone rendering routines for Ghostscript imaging library */
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gsbitops.h"
+#include "gsutil.h" /* for gs_next_ids */
+#include "gxdcolor.h"
+#include "gxfixed.h"
+#include "gxdevice.h" /* for gzht.h */
+#include "gxistate.h"
+#include "gzht.h"
+
+/* Define the sizes of the halftone cache. */
+#define max_cached_tiles_HUGE 5000 /* not used */
+#define max_ht_bits_HUGE 1000000 /* not used */
+#define max_cached_tiles_LARGE 577
+#define max_ht_bits_LARGE 100000
+#define max_cached_tiles_SMALL 25
+#define max_ht_bits_SMALL 1000
+
+/* Define the binary halftone device color type. */
+/* The type descriptor must be public for Pattern types. */
+gs_public_st_composite(st_dc_ht_binary, gx_device_color, "dc_ht_binary",
+ dc_ht_binary_enum_ptrs, dc_ht_binary_reloc_ptrs);
+private dev_color_proc_load(gx_dc_ht_binary_load);
+private dev_color_proc_fill_rectangle(gx_dc_ht_binary_fill_rectangle);
+private dev_color_proc_equal(gx_dc_ht_binary_equal);
+const gx_device_color_type_t
+ gx_dc_type_data_ht_binary =
+{&st_dc_ht_binary,
+ gx_dc_ht_binary_load, gx_dc_ht_binary_fill_rectangle,
+ gx_dc_default_fill_masked, gx_dc_ht_binary_equal
+};
+
+#undef gx_dc_type_ht_binary
+const gx_device_color_type_t *const gx_dc_type_ht_binary =
+&gx_dc_type_data_ht_binary;
+
+#define gx_dc_type_ht_binary (&gx_dc_type_data_ht_binary)
+/* GC procedures */
+#define cptr ((gx_device_color *)vptr)
+private
+ENUM_PTRS_BEGIN(dc_ht_binary_enum_ptrs) return 0;
+
+ENUM_PTR(0, gx_device_color, colors.binary.b_ht);
+case 1:
+{
+ gx_ht_tile *tile = cptr->colors.binary.b_tile;
+
+ ENUM_RETURN(tile - tile->index);
+}
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(dc_ht_binary_reloc_ptrs)
+{
+ uint index = cptr->colors.binary.b_tile->index;
+
+ RELOC_PTR(gx_device_color, colors.binary.b_ht);
+ RELOC_TYPED_OFFSET_PTR(gx_device_color, colors.binary.b_tile, index);
+}
+RELOC_PTRS_END
+#undef cptr
+
+/* Other GC procedures */
+private_st_ht_tiles();
+private
+ENUM_PTRS_BEGIN_PROC(ht_tiles_enum_ptrs)
+{
+ return 0;
+}
+ENUM_PTRS_END_PROC
+private RELOC_PTRS_BEGIN(ht_tiles_reloc_ptrs)
+{
+ /* Reset the bitmap pointers in the tiles. */
+ /* We know the first tile points to the base of the bits. */
+ gx_ht_tile *ht_tiles = vptr;
+ byte *bits = ht_tiles->tiles.data;
+ uint diff;
+
+ if (bits == 0)
+ return;
+ RELOC_VAR(bits);
+ if (size == size_of(gx_ht_tile)) { /* only 1 tile */
+ ht_tiles->tiles.data = bits;
+ return;
+ }
+ diff = ht_tiles[1].tiles.data - ht_tiles[0].tiles.data;
+ for (; size; ht_tiles++, size -= size_of(gx_ht_tile), bits += diff) {
+ ht_tiles->tiles.data = bits;
+ }
+}
+RELOC_PTRS_END
+private_st_ht_cache();
+
+/* Return the default sizes of the halftone cache. */
+uint
+gx_ht_cache_default_tiles(void)
+{
+#if arch_small_memory
+ return max_cached_tiles_SMALL;
+#else
+ return (gs_debug_c('.') ? max_cached_tiles_SMALL :
+ max_cached_tiles_LARGE);
+#endif
+}
+uint
+gx_ht_cache_default_bits(void)
+{
+#if arch_small_memory
+ return max_ht_bits_SMALL;
+#else
+ return (gs_debug_c('.') ? max_ht_bits_SMALL :
+ max_ht_bits_LARGE);
+#endif
+}
+
+/* Allocate a halftone cache. */
+gx_ht_cache *
+gx_ht_alloc_cache(gs_memory_t * mem, uint max_tiles, uint max_bits)
+{
+ gx_ht_cache *pcache =
+ gs_alloc_struct(mem, gx_ht_cache, &st_ht_cache,
+ "alloc_ht_cache(struct)");
+ byte *tbits =
+ gs_alloc_bytes(mem, max_bits, "alloc_ht_cache(bits)");
+ gx_ht_tile *ht_tiles =
+ gs_alloc_struct_array(mem, max_tiles, gx_ht_tile, &st_ht_tiles,
+ "alloc_ht_cache(ht_tiles)");
+
+ if (pcache == 0 || tbits == 0 || ht_tiles == 0) {
+ gs_free_object(mem, ht_tiles, "alloc_ht_cache(ht_tiles)");
+ gs_free_object(mem, tbits, "alloc_ht_cache(bits)");
+ gs_free_object(mem, pcache, "alloc_ht_cache(struct)");
+ return 0;
+ }
+ pcache->bits = tbits;
+ pcache->bits_size = max_bits;
+ pcache->ht_tiles = ht_tiles;
+ pcache->num_tiles = max_tiles;
+ pcache->order.cache = pcache;
+ pcache->order.transfer = 0;
+ gx_ht_clear_cache(pcache);
+ return pcache;
+}
+
+/* Free a halftone cache. */
+void
+gx_ht_free_cache(gs_memory_t * mem, gx_ht_cache * pcache)
+{
+ gs_free_object(mem, pcache->ht_tiles, "free_ht_cache(ht_tiles)");
+ gs_free_object(mem, pcache->bits, "free_ht_cache(bits)");
+ gs_free_object(mem, pcache, "free_ht_cache(struct)");
+}
+
+/* Make the cache order current, and return whether */
+/* there is room for all possible tiles in the cache. */
+bool
+gx_check_tile_cache(const gs_imager_state * pis)
+{
+ const gx_ht_order *porder = &pis->dev_ht->order;
+ gx_ht_cache *pcache = pis->ht_cache;
+
+ if (pcache == 0 || pis->dev_ht == 0)
+ return false; /* no halftone or cache */
+ if (pcache->order.bits != porder->bits)
+ gx_ht_init_cache(pcache, porder);
+ return pcache->levels_per_tile == 1;
+}
+
+/*
+ * Determine whether a given (width, y, height) might fit into a single
+ * (non-strip) tile. If so, return the byte offset of the appropriate row
+ * from the beginning of the tile, and set *ppx to the x phase offset
+ * within the tile; if not, return -1.
+ */
+int
+gx_check_tile_size(const gs_imager_state * pis, int w, int y, int h,
+ gs_color_select_t select, int *ppx)
+{
+ int tsy;
+ const gx_strip_bitmap *ptile0;
+
+ if (pis->ht_cache == 0)
+ return -1; /* no halftone cache */
+ ptile0 = &pis->ht_cache->ht_tiles[0].tiles; /* a typical tile */
+ if (h > ptile0->rep_height || w > ptile0->rep_width ||
+ ptile0->shift != 0
+ )
+ return -1;
+ tsy = (y + imod(-pis->screen_phase[select].y, ptile0->rep_height)) %
+ ptile0->rep_height;
+ if (tsy + h > ptile0->size.y)
+ return -1;
+ /* Tile fits in Y, might fit in X. */
+ *ppx = imod(-pis->screen_phase[select].x, ptile0->rep_width);
+ return tsy * ptile0->raster;
+}
+
+/* Render a given level into a halftone cache. */
+private int render_ht(P4(gx_ht_tile *, int, const gx_ht_order *,
+ gx_bitmap_id));
+gx_ht_tile *
+gx_render_ht(gx_ht_cache * pcache, int b_level)
+{
+ const gx_ht_order *porder = &pcache->order;
+ int level = porder->levels[b_level];
+ gx_ht_tile *bt = &pcache->ht_tiles[level / pcache->levels_per_tile];
+
+ if (bt->level != level) {
+ int code = render_ht(bt, level, porder, pcache->base_id + b_level);
+
+ if (code < 0)
+ return 0;
+ }
+ return bt;
+}
+
+/* Load the device color into the halftone cache if needed. */
+private int
+gx_dc_ht_binary_load(gx_device_color * pdevc, const gs_imager_state * pis,
+ gx_device * dev, gs_color_select_t select)
+{
+ const gx_ht_order *porder = &pis->dev_ht->order;
+ gx_ht_cache *pcache = pis->ht_cache;
+
+ if (pcache->order.bits != porder->bits)
+ gx_ht_init_cache(pcache, porder);
+ /* Expand gx_render_ht inline for speed. */
+ {
+ int b_level = pdevc->colors.binary.b_level;
+ int level = porder->levels[b_level];
+ gx_ht_tile *bt = &pcache->ht_tiles[level / pcache->levels_per_tile];
+
+ if (bt->level != level) {
+ int code = render_ht(bt, level, porder,
+ pcache->base_id + b_level);
+
+ if (code < 0)
+ return_error(gs_error_Fatal);
+ }
+ pdevc->colors.binary.b_tile = bt;
+ }
+ return 0;
+}
+
+/* Fill a rectangle with a binary halftone. */
+/* Note that we treat this as "texture" for RasterOp. */
+private int
+gx_dc_ht_binary_fill_rectangle(const gx_device_color * pdevc, int x, int y,
+ int w, int h, gx_device * dev, gs_logical_operation_t lop,
+ const gx_rop_source_t * source)
+{
+ gx_rop_source_t no_source;
+
+ /*
+ * Observation of H-P devices and documentation yields confusing
+ * evidence about whether white pixels in halftones are always
+ * opaque. It appears that for black-and-white devices, these
+ * pixels are *not* opaque.
+ */
+ if (dev->color_info.depth > 1)
+ lop &= ~lop_T_transparent;
+ if (source == NULL && lop_no_S_is_T(lop))
+ return (*dev_proc(dev, strip_tile_rectangle)) (dev,
+ &pdevc->colors.binary.b_tile->tiles,
+ x, y, w, h, pdevc->colors.binary.color[0],
+ pdevc->colors.binary.color[1],
+ pdevc->phase.x, pdevc->phase.y);
+ /* Adjust the logical operation per transparent colors. */
+ if (pdevc->colors.binary.color[0] == gx_no_color_index)
+ lop = rop3_use_D_when_T_0(lop);
+ if (pdevc->colors.binary.color[1] == gx_no_color_index)
+ lop = rop3_use_D_when_T_1(lop);
+ if (source == NULL)
+ set_rop_no_source(source, no_source, dev);
+ return (*dev_proc(dev, strip_copy_rop)) (dev, source->sdata,
+ source->sourcex, source->sraster, source->id,
+ (source->use_scolors ? source->scolors : NULL),
+ &pdevc->colors.binary.b_tile->tiles,
+ pdevc->colors.binary.color,
+ x, y, w, h, pdevc->phase.x, pdevc->phase.y,
+ lop);
+}
+
+/* Compare two binary halftones for equality. */
+private bool
+gx_dc_ht_binary_equal(const gx_device_color * pdevc1,
+ const gx_device_color * pdevc2)
+{
+ return pdevc2->type == pdevc1->type &&
+ pdevc1->phase.x == pdevc2->phase.x &&
+ pdevc1->phase.y == pdevc2->phase.y &&
+ gx_dc_binary_color0(pdevc1) == gx_dc_binary_color0(pdevc2) &&
+ gx_dc_binary_color1(pdevc1) == gx_dc_binary_color1(pdevc2) &&
+ pdevc1->colors.binary.b_level == pdevc2->colors.binary.b_level;
+}
+
+/* Initialize the tile cache for a given screen. */
+/* Cache as many different levels as will fit. */
+void
+gx_ht_init_cache(gx_ht_cache * pcache, const gx_ht_order * porder)
+{
+ uint width = porder->width;
+ uint height = porder->height;
+ uint size = width * height + 1;
+ int width_unit =
+ (width <= ht_mask_bits / 2 ? ht_mask_bits / width * width :
+ width);
+ int height_unit = height;
+ uint raster = porder->raster;
+ uint tile_bytes = raster * height;
+ uint shift = porder->shift;
+ int num_cached;
+ int i;
+ byte *tbits = pcache->bits;
+
+ /* Non-monotonic halftones may have more bits than size. */
+ if (porder->num_bits >= size)
+ size = porder->num_bits + 1;
+ /* Make sure num_cached is within bounds */
+ num_cached = pcache->bits_size / tile_bytes;
+ if (num_cached > size)
+ num_cached = size;
+ if (num_cached > pcache->num_tiles)
+ num_cached = pcache->num_tiles;
+ if (num_cached == size &&
+ tile_bytes * num_cached <= pcache->bits_size / 2
+ ) { /*
+ * We can afford to replicate every tile in the cache,
+ * which will reduce breakage when tiling. Since
+ * horizontal breakage is more expensive than vertical,
+ * and since wide shallow fills are more common than
+ * narrow deep fills, we replicate the tile horizontally.
+ * We do have to be careful not to replicate the tile
+ * to an absurdly large size, however.
+ */
+ uint rep_raster =
+ ((pcache->bits_size / num_cached) / height) &
+ ~(align_bitmap_mod - 1);
+ uint rep_count = rep_raster * 8 / width;
+
+ /*
+ * There's no real value in replicating the tile
+ * beyond the point where the byte width of the replicated
+ * tile is a multiple of a long.
+ */
+ if (rep_count > sizeof(ulong) * 8)
+ rep_count = sizeof(ulong) * 8;
+ width_unit = width * rep_count;
+ raster = bitmap_raster(width_unit);
+ tile_bytes = raster * height;
+ }
+ pcache->base_id = gs_next_ids(porder->num_levels + 1);
+ pcache->order = *porder;
+ pcache->num_cached = num_cached;
+ pcache->levels_per_tile = (size + num_cached - 1) / num_cached;
+ memset(tbits, 0, pcache->bits_size);
+ for (i = 0; i < num_cached; i++, tbits += tile_bytes) {
+ register gx_ht_tile *bt = &pcache->ht_tiles[i];
+
+ bt->level = 0;
+ bt->index = i;
+ bt->tiles.data = tbits;
+ bt->tiles.raster = raster;
+ bt->tiles.size.x = width_unit;
+ bt->tiles.size.y = height_unit;
+ bt->tiles.rep_width = width;
+ bt->tiles.rep_height = height;
+ bt->tiles.shift = bt->tiles.rep_shift = shift;
+ }
+}
+
+/*
+ * Compute and save the rendering of a given gray level
+ * with the current halftone. The cache holds multiple tiles,
+ * where each tile covers a range of possible levels.
+ * We adjust the tile whose range includes the desired level incrementally;
+ * this saves a lot of time for the average image, where gray levels
+ * don't change abruptly. Note that the "level" is the number of bits,
+ * not the index in the levels vector.
+ */
+private int
+render_ht(gx_ht_tile * pbt, int level /* [1..num_bits-1] */ ,
+ const gx_ht_order * porder, gx_bitmap_id new_id)
+{
+ int old_level = pbt->level;
+ register gx_ht_bit *p = &porder->bits[old_level];
+ register byte *data = pbt->tiles.data;
+
+ if_debug7('H', "[H]Halftone cache slot 0x%lx: old=%d, new=%d, w=%d(%d), h=%d(%d):\n",
+ (ulong) data, old_level, level,
+ pbt->tiles.size.x, porder->width,
+ pbt->tiles.size.y, porder->num_bits / porder->width);
+#ifdef DEBUG
+ if (level < 0 || level > porder->num_bits) {
+ lprintf3("Error in render_ht: level=%d, old_level=%d, num_bits=%d\n", level, old_level, porder->num_bits);
+ return_error(gs_error_Fatal);
+ }
+#endif
+ /* Invert bits between the two pointers. */
+ /* Note that we can use the same loop to turn bits either */
+ /* on or off, using xor. */
+ /* The Borland compiler generates truly dreadful code */
+ /* if we don't assign the offset to a temporary. */
+#if arch_ints_are_short
+# define invert_data(i)\
+ { uint off = p[i].offset; *(ht_mask_t *)&data[off] ^= p[i].mask; }
+#else
+# define invert_data(i) *(ht_mask_t *)&data[p[i].offset] ^= p[i].mask
+#endif
+#ifdef DEBUG
+# define invert(i)\
+ { if_debug3('H', "[H]invert level=%d offset=%u mask=0x%x\n",\
+ (int)(p + i - porder->bits), p[i].offset, p[i].mask);\
+ invert_data(i);\
+ }
+#else
+# define invert(i) invert_data(i)
+#endif
+ sw:switch (level - old_level) {
+ default:
+ if (level > old_level) {
+ invert(0);
+ invert(1);
+ invert(2);
+ invert(3);
+ p += 4;
+ old_level += 4;
+ } else {
+ invert(-1);
+ invert(-2);
+ invert(-3);
+ invert(-4);
+ p -= 4;
+ old_level -= 4;
+ }
+ goto sw;
+ case 7:
+ invert(6);
+ case 6:
+ invert(5);
+ case 5:
+ invert(4);
+ case 4:
+ invert(3);
+ case 3:
+ invert(2);
+ case 2:
+ invert(1);
+ case 1:
+ invert(0);
+ case 0:
+ break; /* Shouldn't happen! */
+ case -7:
+ invert(-7);
+ case -6:
+ invert(-6);
+ case -5:
+ invert(-5);
+ case -4:
+ invert(-4);
+ case -3:
+ invert(-3);
+ case -2:
+ invert(-2);
+ case -1:
+ invert(-1);
+ }
+#undef invert
+ pbt->level = level;
+ pbt->tiles.id = new_id;
+ /*
+ * Check whether we want to replicate the tile in the cache.
+ * Since we only do this when all the renderings will fit
+ * in the cache, we only do it once per level, and it doesn't
+ * have to be very efficient.
+ */
+ /****** TEST IS WRONG if width > rep_width but tile.raster ==
+ ****** order raster.
+ ******/
+ if (pbt->tiles.raster > porder->raster)
+ bits_replicate_horizontally(data, pbt->tiles.rep_width,
+ pbt->tiles.rep_height, porder->raster,
+ pbt->tiles.size.x, pbt->tiles.raster);
+ if (pbt->tiles.size.y > pbt->tiles.rep_height &&
+ pbt->tiles.shift == 0
+ )
+ bits_replicate_vertically(data, pbt->tiles.rep_height,
+ pbt->tiles.raster, pbt->tiles.size.y);
+#ifdef DEBUG
+ if (gs_debug_c('H')) {
+ const byte *p = pbt->tiles.data;
+ int wb = pbt->tiles.raster;
+ const byte *ptr = p + wb * pbt->tiles.size.y;
+
+ while (p < ptr) {
+ dprintf8(" %d%d%d%d%d%d%d%d",
+ *p >> 7, (*p >> 6) & 1, (*p >> 5) & 1,
+ (*p >> 4) & 1, (*p >> 3) & 1, (*p >> 2) & 1,
+ (*p >> 1) & 1, *p & 1);
+ if ((++p - data) % wb == 0)
+ dputc('\n');
+ }
+ }
+#endif
+ return 0;
+}
diff --git a/pstoraster/gxht.h b/pstoraster/gxht.h
new file mode 100644
index 000000000..8a86c0928
--- /dev/null
+++ b/pstoraster/gxht.h
@@ -0,0 +1,222 @@
+/* Copyright (C) 1993, 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$ */
+/* Rest of (client) halftone definitions */
+
+#ifndef gxht_INCLUDED
+# define gxht_INCLUDED
+
+#include "gscsepnm.h"
+#include "gsht1.h"
+#include "gsrefct.h"
+#include "gxhttype.h"
+#include "gxtmap.h"
+
+/*
+ * Halftone types. Note that for this implementation there are only
+ * spot functions, thresholds, and multi-component halftones; the peculiar
+ * colored halftones supported by PostScript (HalftoneType's 2 and 4) are
+ * not supported.
+ *
+ * NB1: While this code supports relocation of the client data, it will not
+ * free that data when the halftone is released. The client must handle
+ * that task directly.
+ *
+ * NB2: The garbage collection code will deal with the user provided data as
+ * a structure pointer allocated on the heap. The client must make
+ * certain this is the case.
+ *
+ * There is, somewhat unfortunately, no identifier applied to these
+ * halftones. This reflects the origin of this graphics library as a set
+ * of routines for use by a PostScript interpreter.
+ *
+ * In PostScript, halftone objects do not exist in an identified form outside
+ * of the graphic state. Though Level 2 and PostScript 3 support halftone
+ * dictionaries, these are neither read-only structures nor tagged
+ * by a unique identifier. Hence, they are not suitable for use as cache keys.
+ * Caching of halftones for PostScript is confined to the graphic state,
+ * and this holds true for the graphic library as well.
+ *
+ * Note also that implementing a generalized halftone cache is not trivial,
+ * as the device-specific representation of spot halftones depends on the
+ * default transformation for the device, and more generally the device
+ * specific representation of halftones may depend on the sense of the device
+ * (additive or subtract). Hence, a halftone cache would need to be keyed
+ * by device. (This is not an issue when caching halftones in the graphic
+ * state as the device is also a component of the graphic state).
+ */
+
+/*
+ * Note that the transfer_closure members will replace transfer sometime
+ * in the future. For the moment, transfer_closure is only used if
+ * transfer = 0.
+ */
+
+/* Type 1 halftone. This is just a Level 1 halftone with */
+/* a few extra members. */
+typedef struct gs_spot_halftone_s {
+ gs_screen_halftone screen;
+ bool accurate_screens;
+ gs_mapping_proc transfer; /* OBSOLETE */
+ gs_mapping_closure_t transfer_closure;
+} gs_spot_halftone;
+
+#define st_spot_halftone_max_ptrs st_screen_halftone_max_ptrs + 1
+
+/* Type 3 halftone. */
+typedef struct gs_threshold_halftone_s {
+ int width;
+ int height;
+ gs_const_string thresholds;
+ gs_mapping_proc transfer; /* OBSOLETE */
+ gs_mapping_closure_t transfer_closure;
+} gs_threshold_halftone;
+
+#define st_threshold_halftone_max_ptrs 2
+
+/* Client-defined halftone that generates a halftone order. */
+typedef struct gs_client_order_halftone_s gs_client_order_halftone;
+
+#ifndef gx_ht_order_DEFINED
+# define gx_ht_order_DEFINED
+typedef struct gx_ht_order_s gx_ht_order;
+
+#endif
+typedef struct gs_client_order_ht_procs_s {
+
+ /*
+ * Allocate and fill in the order. gx_ht_alloc_client_order
+ * (see gzht.h) does everything but fill in the actual data.
+ */
+
+ int (*create_order) (P4(gx_ht_order * porder,
+ gs_state * pgs,
+ const gs_client_order_halftone * phcop,
+ gs_memory_t * mem));
+
+} gs_client_order_ht_procs_t;
+struct gs_client_order_halftone_s {
+ int width;
+ int height;
+ int num_levels;
+ const gs_client_order_ht_procs_t *procs;
+ const void *client_data;
+ gs_mapping_closure_t transfer_closure;
+};
+
+#define st_client_order_halftone_max_ptrs 2
+
+/* Define the elements of a Type 5 halftone. */
+typedef struct gs_halftone_component_s {
+ gs_ht_separation_name cname;
+ gs_halftone_type type;
+ union {
+ gs_spot_halftone spot; /* Type 1 */
+ gs_threshold_halftone threshold; /* Type 3 */
+ gs_client_order_halftone client_order; /* client order */
+ } params;
+} gs_halftone_component;
+
+extern_st(st_halftone_component);
+#define public_st_halftone_component() /* in gsht1.c */\
+ gs_public_st_composite(st_halftone_component, gs_halftone_component,\
+ "gs_halftone_component", halftone_component_enum_ptrs,\
+ halftone_component_reloc_ptrs)
+extern_st(st_ht_component_element);
+#define public_st_ht_component_element() /* in gsht1.c */\
+ gs_public_st_element(st_ht_component_element, gs_halftone_component,\
+ "gs_halftone_component[]", ht_comp_elt_enum_ptrs, ht_comp_elt_reloc_ptrs,\
+ st_halftone_component)
+#define st_halftone_component_max_ptrs\
+ max(max(st_spot_halftone_max_ptrs, st_threshold_halftone_max_ptrs),\
+ st_client_order_halftone_max_ptrs)
+
+/* Define the Type 5 halftone itself. */
+typedef struct gs_multiple_halftone_s {
+ gs_halftone_component *components;
+ uint num_comp;
+} gs_multiple_halftone;
+
+#define st_multiple_halftone_max_ptrs 1
+
+/*
+ * The halftone stored in the graphics state is the union of
+ * setscreen, setcolorscreen, Type 1, Type 3, and Type 5.
+ *
+ * NOTE: it is assumed that all subsidiary structures of halftones (the
+ * threshold array(s) for Type 3 halftones or halftone components, and the
+ * components array for Type 5 halftones) are allocated with the same
+ * allocator as the halftone structure itself.
+ */
+struct gs_halftone_s {
+ gs_halftone_type type;
+ rc_header rc;
+ union {
+ gs_screen_halftone screen; /* setscreen */
+ gs_colorscreen_halftone colorscreen; /* setcolorscreen */
+ gs_spot_halftone spot; /* Type 1 */
+ gs_threshold_halftone threshold; /* Type 3 */
+ gs_client_order_halftone client_order; /* client order */
+ gs_multiple_halftone multiple; /* Type 5 */
+ } params;
+};
+
+extern_st(st_halftone);
+#define public_st_halftone() /* in gsht.c */\
+ gs_public_st_composite(st_halftone, gs_halftone, "gs_halftone",\
+ halftone_enum_ptrs, halftone_reloc_ptrs)
+#define st_halftone_max_ptrs\
+ max(max(st_screen_halftone_max_ptrs, st_colorscreen_halftone_max_ptrs),\
+ max(max(st_spot_halftone_max_ptrs, st_threshold_halftone_max_ptrs),\
+ max(st_client_order_halftone_max_ptrs,\
+ st_multiple_halftone_max_ptrs)))
+
+/* Procedural interface for AccurateScreens */
+
+/*
+ * Set/get the default AccurateScreens value (for set[color]screen).
+ * Note that this value is stored in a static variable.
+ */
+void gs_setaccuratescreens(P1(bool));
+bool gs_currentaccuratescreens(P0());
+
+/* Initiate screen sampling with optional AccurateScreens. */
+int gs_screen_init_memory(P5(gs_screen_enum *, gs_state *,
+ gs_screen_halftone *, bool, gs_memory_t *));
+
+#define gs_screen_init_accurate(penum, pgs, phsp, accurate)\
+ gs_screen_init_memory(penum, pgs, phsp, accurate, pgs->memory)
+
+/* Procedural interface for MinScreenLevels (a Ghostscript extension) */
+
+/*
+ * Set/get the MinScreenLevels value.
+ *
+ * Note that this value is stored in a static variable.
+ */
+void gs_setminscreenlevels(P1(uint));
+uint gs_currentminscreenlevels(P0());
+
+#endif /* gxht_INCLUDED */
diff --git a/pstoraster/gxhttile.h b/pstoraster/gxhttile.h
new file mode 100644
index 000000000..f72f7ad3b
--- /dev/null
+++ b/pstoraster/gxhttile.h
@@ -0,0 +1,54 @@
+/* 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$ */
+/* Halftone tile definition */
+/* Requires gxbitmap.h */
+
+#ifndef gxhttile_INCLUDED
+# define gxhttile_INCLUDED
+
+/*
+ * A halftone tile is just an ordinary bitmap tile, plus a couple of other
+ * items associated with managing its existence in a tile cache.
+ * (See gzht.h for details.) We define this in its own file so that
+ * clients of gx_device_color can access it.
+ */
+
+#ifndef gx_ht_tile_DEFINED
+# define gx_ht_tile_DEFINED
+typedef struct gx_ht_tile_s gx_ht_tile;
+
+#endif
+
+struct gx_ht_tile_s {
+ gx_strip_bitmap tiles; /* the currently rendered tile */
+ int level; /* the cached gray level, i.e. */
+ /* the number of spots whitened, */
+ /* or -1 if the cache is empty */
+ uint index; /* the index of the tile within */
+ /* the cache (for GC) */
+};
+
+#endif /* gxhttile_INCLUDED */
diff --git a/pstoraster/gxhttype.h b/pstoraster/gxhttype.h
new file mode 100644
index 000000000..d39200ac4
--- /dev/null
+++ b/pstoraster/gxhttype.h
@@ -0,0 +1,45 @@
+/* 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$ */
+/* Client halftone type enumeration */
+
+#ifndef gxhttype_INCLUDED
+# define gxhttype_INCLUDED
+
+/* Halftone types */
+typedef enum {
+ ht_type_none, /* is this needed? */
+ ht_type_screen, /* set by setscreen */
+ ht_type_colorscreen, /* set by setcolorscreen */
+ ht_type_spot, /* Type 1 halftone dictionary */
+ ht_type_threshold, /* Type 3 halftone dictionary */
+ ht_type_multiple, /* Type 5 halftone dictionary */
+ ht_type_multiple_colorscreen, /* Type 5 halftone dictionary */
+ /* created from Type 2 or Type 4 */
+ /* halftone dictionary */
+ ht_type_client_order /* client-defined, creating a gx_ht_order */
+} gs_halftone_type;
+
+#endif /* gxhttype_INCLUDED */
diff --git a/pstoraster/gxi12bit.c b/pstoraster/gxi12bit.c
new file mode 100644
index 000000000..e5f40b550
--- /dev/null
+++ b/pstoraster/gxi12bit.c
@@ -0,0 +1,300 @@
+/* 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$ */
+/* 12-bit image procedures */
+#include "gx.h"
+#include "memory_.h"
+#include "gpcheck.h"
+#include "gserrors.h"
+#include "gxfixed.h"
+#include "gxfrac.h"
+#include "gxarith.h"
+#include "gxmatrix.h"
+#include "gsccolor.h"
+#include "gspaint.h"
+#include "gxdevice.h"
+#include "gxcmap.h"
+#include "gxdcolor.h"
+#include "gxistate.h"
+#include "gzpath.h"
+#include "gxdevmem.h"
+#include "gxcpath.h"
+#include "gximage.h"
+
+/* ---------------- Unpacking procedures ---------------- */
+
+private const byte *
+sample_unpack_12(byte * bptr, int *pdata_x, const byte * data,
+ int data_x, uint dsize, const sample_lookup_t * ignore_ptab,
+ int spread)
+{
+ register frac *bufp = (frac *) bptr;
+ uint dskip = (data_x >> 1) * 3;
+ const byte *psrc = data + dskip;
+#define inc_bufp(bp, n) bp = (frac *)((byte *)(bp) + (n))
+ uint sample;
+ int left = dsize - dskip;
+
+ if ((data_x & 1) && left > 0)
+ switch (left) {
+ default:
+ sample = ((uint) (psrc[1] & 0xf) << 8) + psrc[2];
+ *bufp = bits2frac(sample, 12);
+ inc_bufp(bufp, spread);
+ psrc += 3;
+ left -= 3;
+ break;
+ case 2: /* xxxxxxxx xxxxdddd */
+ *bufp = (psrc[1] & 0xf) * (frac_1 / 15);
+ case 1: /* xxxxxxxx */
+ left = 0;
+ }
+ while (left >= 3) {
+ sample = ((uint) * psrc << 4) + (psrc[1] >> 4);
+ *bufp = bits2frac(sample, 12);
+ inc_bufp(bufp, spread);
+ sample = ((uint) (psrc[1] & 0xf) << 8) + psrc[2];
+ *bufp = bits2frac(sample, 12);
+ inc_bufp(bufp, spread);
+ psrc += 3;
+ left -= 3;
+ }
+ /* Handle trailing bytes. */
+ switch (left) {
+ case 2: /* dddddddd ddddxxxx */
+ sample = ((uint) * psrc << 4) + (psrc[1] >> 4);
+ *bufp = bits2frac(sample, 12);
+ inc_bufp(bufp, spread);
+ *bufp = (psrc[1] & 0xf) * (frac_1 / 15);
+ break;
+ case 1: /* dddddddd */
+ sample = (uint) * psrc << 4;
+ *bufp = bits2frac(sample, 12);
+ break;
+ case 0: /* Nothing more to do. */
+ ;
+ }
+ *pdata_x = 0;
+ return bptr;
+}
+
+/* ------ Strategy procedure ------ */
+
+/* Use special (slow) logic for 12-bit source values. */
+private irender_proc(image_render_frac);
+private irender_proc_t
+image_strategy_frac(gx_image_enum * penum)
+{
+ if (penum->bps > 8) {
+ if_debug0('b', "[b]render=frac\n");
+ return image_render_frac;
+ }
+ return 0;
+}
+
+void
+gs_gxi12bit_init(gs_memory_t * mem)
+{
+ image_strategies.fracs = image_strategy_frac;
+ sample_unpack_12_proc = sample_unpack_12;
+}
+
+/* ---------------- Rendering procedures ---------------- */
+
+/* ------ Rendering for 12-bit samples ------ */
+
+/* Render an image with more than 8 bits per sample. */
+/* The samples have been expanded into fracs. */
+#define longs_per_4_fracs (arch_sizeof_frac * 4 / arch_sizeof_long)
+typedef union {
+ frac v[4];
+ long all[longs_per_4_fracs]; /* for fast comparison */
+} color_fracs;
+
+#if longs_per_4_fracs == 1
+# define color_frac_eq(f1, f2)\
+ ((f1).all[0] == (f2).all[0])
+#else
+#if longs_per_4_fracs == 2
+# define color_frac_eq(f1, f2)\
+ ((f1).all[0] == (f2).all[0] && (f1).all[1] == (f2).all[1])
+#endif
+#endif
+private int
+image_render_frac(gx_image_enum * penum, const byte * buffer, int data_x,
+ uint w, int h, gx_device * dev)
+{
+ const gs_imager_state *pis = penum->pis;
+ gs_logical_operation_t lop = penum->log_op;
+ gx_dda_fixed_point pnext;
+ image_posture posture = penum->posture;
+ fixed xl, ytf;
+ fixed pdyx, pdyy; /* edge of parallelogram */
+ int yt = penum->yci, iht = penum->hci;
+ const gs_color_space *pcs = penum->pcs;
+ cs_proc_remap_color((*remap_color)) = pcs->type->remap_color;
+ gs_client_color cc;
+ int device_color = penum->device_color;
+ const gx_color_map_procs *cmap_procs = gx_device_cmap_procs(dev);
+ cmap_proc_rgb((*map_rgb)) = cmap_procs->map_rgb;
+ cmap_proc_cmyk((*map_cmyk)) = cmap_procs->map_cmyk;
+ gx_device_color devc1, devc2;
+ gx_device_color *pdevc = &devc1;
+ gx_device_color *pdevc_next = &devc2;
+ int spp = penum->spp;
+ const frac *psrc = (const frac *)buffer + data_x * spp;
+ fixed xrun; /* x at start of run */
+ int irun; /* int xrun */
+ fixed yrun; /* y ditto */
+ color_fracs run; /* run value */
+ color_fracs next; /* next sample value */
+ const frac *bufend = psrc + w;
+ int code;
+
+ if (h == 0)
+ return 0;
+ pnext = penum->dda.pixel0;
+ xrun = xl = dda_current(pnext.x);
+ irun = fixed2int_var_rounded(xrun);
+ yrun = ytf = dda_current(pnext.y);
+ pdyx = dda_current(penum->dda.row.x) - penum->cur.x;
+ pdyy = dda_current(penum->dda.row.y) - penum->cur.y;
+ if_debug4('b', "[b]y=%d w=%d xt=%f yt=%f\n",
+ penum->y, w, fixed2float(xl), fixed2float(ytf));
+ run.v[0] = run.v[1] = run.v[2] = run.v[3] = 0;
+ next.v[0] = next.v[1] = next.v[2] = next.v[3] = 0;
+ cc.paint.values[0] = cc.paint.values[1] =
+ cc.paint.values[2] = cc.paint.values[3] = 0;
+ cc.pattern = 0;
+ (*remap_color) (&cc, pcs, pdevc, pis, dev, gs_color_select_source);
+ run.v[0] = ~psrc[0]; /* force remap */
+
+ while (psrc < bufend) {
+ next.v[0] = psrc[0];
+ switch (spp) {
+ case 4: /* cmyk */
+ next.v[1] = psrc[1];
+ next.v[2] = psrc[2];
+ next.v[3] = psrc[3];
+ psrc += 4;
+ if (color_frac_eq(next, run))
+ goto inc;
+ if (device_color) {
+ (*map_cmyk) (next.v[0], next.v[1],
+ next.v[2], next.v[3],
+ pdevc_next, pis, dev,
+ gs_color_select_source);
+ goto f;
+ }
+ decode_frac(next.v[0], cc, 0);
+ decode_frac(next.v[1], cc, 1);
+ decode_frac(next.v[2], cc, 2);
+ decode_frac(next.v[3], cc, 3);
+ if_debug4('B', "[B]cc[0..3]=%g,%g,%g,%g\n",
+ cc.paint.values[0], cc.paint.values[1],
+ cc.paint.values[2], cc.paint.values[3]);
+ if_debug1('B', "[B]cc[3]=%g\n",
+ cc.paint.values[3]);
+ break;
+ case 3: /* rgb */
+ next.v[1] = psrc[1];
+ next.v[2] = psrc[2];
+ psrc += 3;
+ if (color_frac_eq(next, run))
+ goto inc;
+ if (device_color) {
+ (*map_rgb) (next.v[0], next.v[1],
+ next.v[2], pdevc_next, pis, dev,
+ gs_color_select_source);
+ goto f;
+ }
+ decode_frac(next.v[0], cc, 0);
+ decode_frac(next.v[1], cc, 1);
+ decode_frac(next.v[2], cc, 2);
+ if_debug3('B', "[B]cc[0..2]=%g,%g,%g\n",
+ cc.paint.values[0], cc.paint.values[1],
+ cc.paint.values[2]);
+ break;
+ case 1: /* gray */
+ psrc++;
+ if (next.v[0] == run.v[0])
+ goto inc;
+ if (device_color) {
+ (*map_rgb) (next.v[0], next.v[0],
+ next.v[0], pdevc_next, pis, dev,
+ gs_color_select_source);
+ goto f;
+ }
+ decode_frac(next.v[0], cc, 0);
+ if_debug1('B', "[B]cc[0]=%g\n",
+ cc.paint.values[0]);
+ break;
+ }
+ (*remap_color) (&cc, pcs, pdevc_next, pis, dev,
+ gs_color_select_source);
+f:
+ if_debug7('B', "[B]0x%x,0x%x,0x%x,0x%x -> %ld,%ld,0x%lx\n",
+ next.v[0], next.v[1], next.v[2], next.v[3],
+ pdevc_next->colors.binary.color[0],
+ pdevc_next->colors.binary.color[1],
+ (ulong) pdevc_next->type);
+ /* Even though the supplied colors don't match, */
+ /* the device colors might. */
+ if (!dev_color_eq(devc1, devc2)) {
+ /* Fill the region between xrun/irun and xl */
+ gx_device_color *ptemp;
+
+ if (posture != image_portrait) { /* Parallelogram */
+ code = (*dev_proc(dev, fill_parallelogram))
+ (dev, xrun, yrun,
+ xl - xrun, ytf - yrun, pdyx, pdyy,
+ pdevc, lop);
+ } else { /* Rectangle */
+ int xi = irun;
+ int wi = (irun = fixed2int_var_rounded(xl)) - xi;
+
+ if (wi < 0)
+ xi += wi, wi = -wi;
+ code = gx_fill_rectangle_device_rop(xi, yt,
+ wi, iht, pdevc, dev, lop);
+ }
+ if (code < 0)
+ return code;
+ ptemp = pdevc;
+ pdevc = pdevc_next;
+ pdevc_next = ptemp;
+ xrun = xl;
+ yrun = ytf;
+ }
+ run = next;
+inc:
+ xl = dda_next(pnext.x);
+ ytf = dda_next(pnext.y);
+ }
+ /* Fill the final run. */
+ code = (*dev_proc(dev, fill_parallelogram))
+ (dev, xrun, yrun, xl - xrun, ytf - yrun, pdyx, pdyy, pdevc, lop);
+ return (code < 0 ? code : 1);
+}
diff --git a/pstoraster/gxicolor.c b/pstoraster/gxicolor.c
new file mode 100644
index 000000000..ac2ab49ef
--- /dev/null
+++ b/pstoraster/gxicolor.c
@@ -0,0 +1,307 @@
+/* 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$ */
+/* Color image rendering */
+#include "gx.h"
+#include "memory_.h"
+#include "gpcheck.h"
+#include "gserrors.h"
+#include "gxfixed.h"
+#include "gxfrac.h"
+#include "gxarith.h"
+#include "gxmatrix.h"
+#include "gsccolor.h"
+#include "gspaint.h"
+#include "gzstate.h"
+#include "gxdevice.h"
+#include "gxcmap.h"
+#include "gxdcconv.h"
+#include "gxdcolor.h"
+#include "gxistate.h"
+#include "gzpath.h"
+#include "gxdevmem.h"
+#include "gxcpath.h"
+#include "gximage.h"
+
+/* ------ Strategy procedure ------ */
+
+private irender_proc(image_render_color);
+private irender_proc_t
+image_strategy_color(gx_image_enum * penum)
+{
+ return image_render_color;
+}
+
+void
+gs_gxicolor_init(gs_memory_t * mem)
+{
+ image_strategies.color = image_strategy_color;
+}
+
+/* ------ Rendering procedures ------ */
+
+/* Render a color image with 8 or fewer bits per sample. */
+typedef union {
+ byte v[4];
+ bits32 all; /* for fast comparison & clearing */
+} color_samples;
+private int
+image_render_color(gx_image_enum * penum, const byte * buffer, int data_x,
+ uint w, int h, gx_device * dev)
+{
+ const gs_imager_state *pis = penum->pis;
+ gs_logical_operation_t lop = penum->log_op;
+ gx_dda_fixed_point pnext;
+ image_posture posture = penum->posture;
+ fixed xprev, yprev;
+ fixed pdyx, pdyy; /* edge of parallelogram */
+ int vci, vdi;
+ const gs_color_space *pcs = penum->pcs;
+ cs_proc_remap_color((*remap_color)) = pcs->type->remap_color;
+ gs_client_color cc;
+ bool device_color = penum->device_color;
+ const gx_color_map_procs *cmap_procs = gx_device_cmap_procs(dev);
+ cmap_proc_rgb((*map_3)) = cmap_procs->map_rgb;
+ cmap_proc_cmyk((*map_4)) =
+ (penum->alpha ? cmap_procs->map_rgb_alpha : cmap_procs->map_cmyk);
+ gx_image_clue *pic = &penum->clues[0];
+#define pdevc (&pic->dev_color)
+ gx_image_clue *pic_next = &penum->clues[1];
+#define pdevc_next (&pic_next->dev_color)
+ gx_image_clue empty_clue;
+ gx_image_clue clue_temp;
+ int spp = penum->spp;
+ const byte *psrc = buffer + data_x * spp;
+ fixed xrun; /* x at start of run */
+ fixed yrun; /* y ditto */
+ int irun; /* int x/rrun */
+ color_samples run; /* run value */
+ color_samples next; /* next sample value */
+ const byte *bufend = psrc + w;
+ bool use_cache = spp * penum->bps <= 12;
+ int code = 0;
+
+ if (h == 0)
+ return 0;
+ pnext = penum->dda.pixel0;
+ xrun = xprev = dda_current(pnext.x);
+ yrun = yprev = dda_current(pnext.y);
+ pdyx = dda_current(penum->dda.row.x) - penum->cur.x;
+ pdyy = dda_current(penum->dda.row.y) - penum->cur.y;
+ switch (posture) {
+ case image_portrait:
+ vci = penum->yci, vdi = penum->hci;
+ irun = fixed2int_var_rounded(xrun);
+ break;
+ case image_landscape:
+ vci = penum->xci, vdi = penum->wci;
+ irun = fixed2int_var_rounded(yrun);
+ break;
+ default:
+ break;
+ }
+
+ if_debug4('b', "[b]y=%d w=%d xt=%f yt=%f\n",
+ penum->y, w, fixed2float(xprev), fixed2float(yprev));
+ run.all = 0;
+ next.all = 0;
+ /* Ensure that we don't get any false dev_color_eq hits. */
+ if (use_cache) {
+ color_set_pure(&empty_clue.dev_color, gx_no_color_index);
+ pic = &empty_clue;
+ }
+ cc.paint.values[0] = cc.paint.values[1] =
+ cc.paint.values[2] = cc.paint.values[3] = 0;
+ cc.pattern = 0;
+ run.v[0] = ~psrc[0]; /* force remap */
+ while (psrc < bufend) {
+ dda_next(pnext.x);
+ dda_next(pnext.y);
+#define CLUE_HASH3(penum, next)\
+ &penum->clues[(next.v[0] + (next.v[1] << 2) + (next.v[2] << 4)) & 255];
+#define CLUE_HASH4(penum, next)\
+ &penum->clues[(next.v[0] + (next.v[1] << 2) + (next.v[2] << 4) +\
+ (next.v[3] << 6)) & 255]
+
+ if (spp == 4) { /* cmyk or rgba */
+ next.v[0] = psrc[0];
+ next.v[1] = psrc[1];
+ next.v[2] = psrc[2];
+ next.v[3] = psrc[3];
+ psrc += 4;
+map4: if (next.all == run.all)
+ goto inc;
+ if (use_cache) {
+ pic_next = CLUE_HASH4(penum, next);
+ if (pic_next->key == next.all)
+ goto f;
+ /*
+ * If we are really unlucky, pic_next == pic,
+ * so mapping this color would clobber the one
+ * we're about to use for filling the run.
+ */
+ if (pic_next == pic) {
+ clue_temp = *pic;
+ pic = &clue_temp;
+ }
+ pic_next->key = next.all;
+ }
+ if (device_color) {
+ (*map_4)(byte2frac(next.v[0]), byte2frac(next.v[1]),
+ byte2frac(next.v[2]), byte2frac(next.v[3]),
+ pdevc_next, pis, dev,
+ gs_color_select_source);
+ goto mapped;
+ }
+ decode_sample(next.v[3], cc, 3);
+ if_debug1('B', "[B]cc[3]=%g\n", cc.paint.values[3]);
+ } else if (spp == 3) { /* rgb */
+ next.v[0] = psrc[0];
+ next.v[1] = psrc[1];
+ next.v[2] = psrc[2];
+ psrc += 3;
+ if (next.all == run.all)
+ goto inc;
+ if (use_cache) {
+ pic_next = CLUE_HASH3(penum, next);
+ if (pic_next->key == next.all)
+ goto f;
+ /* See above re the following check. */
+ if (pic_next == pic) {
+ clue_temp = *pic;
+ pic = &clue_temp;
+ }
+ pic_next->key = next.all;
+ }
+ if (device_color) {
+ (*map_3)(byte2frac(next.v[0]), byte2frac(next.v[1]),
+ byte2frac(next.v[2]),
+ pdevc_next, pis, dev,
+ gs_color_select_source);
+ goto mapped;
+ }
+ } else if (spp == 2) { /* gray+alpha */
+ next.v[2] = next.v[1] = next.v[0] = psrc[0];
+ next.v[3] = psrc[1];
+ psrc += 2;
+ goto map4;
+ } else { /* spp == 5, cmyk+alpha */
+ /* Convert CMYK to RGB. */
+ frac rgb[3];
+
+ color_cmyk_to_rgb(byte2frac(psrc[0]), byte2frac(psrc[1]),
+ byte2frac(psrc[2]), byte2frac(psrc[3]),
+ pis, rgb);
+ /*
+ * It seems silly to do all this converting between
+ * fracs and bytes, but that's what the current
+ * APIs require.
+ */
+ next.v[0] = frac2byte(rgb[0]);
+ next.v[1] = frac2byte(rgb[1]);
+ next.v[2] = frac2byte(rgb[2]);
+ next.v[3] = psrc[4];
+ psrc += 5;
+ goto map4;
+ }
+ decode_sample(next.v[0], cc, 0);
+ decode_sample(next.v[1], cc, 1);
+ decode_sample(next.v[2], cc, 2);
+ if_debug3('B', "[B]cc[0..2]=%g,%g,%g\n",
+ cc.paint.values[0], cc.paint.values[1],
+ cc.paint.values[2]);
+ (*remap_color) (&cc, pcs, pdevc_next, pis, dev,
+ gs_color_select_source);
+mapped: if (pic == pic_next)
+ goto fill;
+f: if_debug7('B', "[B]0x%x,0x%x,0x%x,0x%x -> %ld,%ld,0x%lx\n",
+ next.v[0], next.v[1], next.v[2], next.v[3],
+ pdevc_next->colors.binary.color[0],
+ pdevc_next->colors.binary.color[1],
+ (ulong) pdevc_next->type);
+ /* Even though the supplied colors don't match, */
+ /* the device colors might. */
+ if (dev_color_eq(*pdevc, *pdevc_next))
+ goto set;
+fill: /* Fill the region between */
+ /* xrun/irun and xprev */
+ switch (posture) {
+ case image_portrait:
+ { /* Rectangle */
+ int xi = irun;
+ int wi =
+ (irun = fixed2int_var_rounded(xprev)) - xi;
+
+ if (wi < 0)
+ xi += wi, wi = -wi;
+ if (wi > 0)
+ code = gx_fill_rectangle_device_rop(xi, vci, wi, vdi,
+ pdevc, dev, lop);
+ xrun = xprev; /* for sake of final run */
+ }
+ break;
+ case image_landscape:
+ { /* 90 degree rotated rectangle */
+ int yi = irun;
+ int hi =
+ (irun = fixed2int_var_rounded(yprev)) - yi;
+
+ if (hi < 0)
+ yi += hi, hi = -hi;
+ if (hi > 0)
+ code = gx_fill_rectangle_device_rop(vci, yi, vdi, hi,
+ pdevc, dev, lop);
+ yrun = yprev; /* for sake of final run */
+ }
+ break;
+ default:
+ { /* Parallelogram */
+ code = (*dev_proc(dev, fill_parallelogram))
+ (dev, xrun, yrun,
+ xprev - xrun, yprev - yrun, pdyx, pdyy,
+ pdevc, lop);
+ xrun = xprev;
+ yrun = yprev;
+ }
+ }
+ if (code < 0)
+ return code;
+ if (use_cache)
+ pic = pic_next;
+ else {
+ gx_image_clue *ptemp = pic;
+
+ pic = pic_next;
+ pic_next = ptemp;
+ }
+set: run.all = next.all;
+inc: xprev = dda_current(pnext.x);
+ yprev = dda_current(pnext.y); /* harmless if no skew */
+ }
+ /* Fill the last run. */
+ code = (*dev_proc(dev, fill_parallelogram))
+ (dev, xrun, yrun, xprev - xrun, yprev - yrun, pdyx, pdyy, pdevc, lop);
+ return (code < 0 ? code : 1);
+}
diff --git a/pstoraster/gxidata.c b/pstoraster/gxidata.c
new file mode 100644
index 000000000..58d32540e
--- /dev/null
+++ b/pstoraster/gxidata.c
@@ -0,0 +1,255 @@
+/* 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$ */
+/* Generic image enumeration and cleanup */
+#include "gx.h"
+#include "memory_.h"
+#include "gserrors.h"
+#include "gxdevice.h"
+#include "gxcpath.h"
+#include "gximage.h"
+
+/* Process the next piece of an ImageType 1 image. */
+int
+gx_image1_plane_data(gx_device * dev, gx_image_enum_common_t * info,
+ const gx_image_plane_t * planes, int height)
+{
+ gx_image_enum *penum = (gx_image_enum *) info;
+ int y = penum->y;
+ int y_end = min(y + height, penum->rect.h);
+ int width_spp = penum->rect.w * penum->spp;
+ int num_planes = penum->num_planes;
+
+#define bcount(plane) /* bytes per data row */\
+ (((penum->rect.w + (plane).data_x) * penum->spp / num_planes * penum->bps\
+ + 7) >> 3)
+ fixed adjust = penum->adjust;
+ ulong offsets[gs_image_max_components];
+ int ignore_data_x;
+ int code;
+
+ if (height == 0)
+ return 0;
+
+ /* Set up the clipping and/or RasterOp device if needed. */
+
+ if (penum->clip_dev) {
+ gx_device_clip *cdev = penum->clip_dev;
+
+ cdev->target = dev;
+ dev = (gx_device *) cdev;
+ }
+ if (penum->rop_dev) {
+ gx_device_rop_texture *rtdev = penum->rop_dev;
+
+ ((gx_device_forward *) rtdev)->target = dev;
+ dev = (gx_device *) rtdev;
+ }
+ /* Now render complete rows. */
+
+ memset(offsets, 0, num_planes * sizeof(offsets[0]));
+ for (; penum->y < y_end; penum->y++) {
+ int px;
+
+ /*
+ * Normally, we unpack the data into the buffer, but if
+ * there is only one plane and we don't need to expand the
+ * input samples, we may use the data directly.
+ */
+ int sourcex = planes[0].data_x;
+ const byte *buffer =
+ (*penum->unpack) (penum->buffer, &sourcex,
+ planes[0].data + offsets[0],
+ planes[0].data_x, bcount(planes[0]),
+ &penum->map[0].table, penum->spread);
+
+ offsets[0] += planes[0].raster;
+ for (px = 1; px < num_planes; ++px) {
+ (*penum->unpack) (penum->buffer + (px << penum->log2_xbytes),
+ &ignore_data_x,
+ planes[px].data + offsets[px],
+ planes[px].data_x, bcount(planes[px]),
+ &penum->map[px].table, penum->spread);
+ offsets[px] += planes[px].raster;
+ }
+#ifdef DEBUG
+ if (gs_debug_c('B')) {
+ int i, n = width_spp;
+
+ dlputs("[B]row:");
+ for (i = 0; i < n; i++)
+ dprintf1(" %02x", buffer[i]);
+ dputs("\n");
+ }
+#endif
+ penum->cur.x = dda_current(penum->dda.row.x);
+ dda_next(penum->dda.row.x);
+ penum->cur.y = dda_current(penum->dda.row.y);
+ dda_next(penum->dda.row.y);
+ if (!penum->interpolate)
+ switch (penum->posture) {
+ case image_portrait:
+ { /* Precompute integer y and height, */
+ /* and check for clipping. */
+ fixed yc = penum->cur.y, yn = dda_current(penum->dda.row.y);
+
+ if (yn < yc) {
+ fixed temp = yn;
+
+ yn = yc;
+ yc = temp;
+ }
+ yc -= adjust;
+ if (yc >= penum->clip_outer.q.y)
+ goto mt;
+ yn += adjust;
+ if (yn <= penum->clip_outer.p.y)
+ goto mt;
+ penum->yci = fixed2int_pixround(yc);
+ penum->hci = fixed2int_pixround(yn) - penum->yci;
+ if (penum->hci == 0)
+ goto mt;
+ }
+ break;
+ case image_landscape:
+ { /* Check for no pixel centers in x. */
+ fixed xc = penum->cur.x, xn = dda_current(penum->dda.row.x);
+
+ if (xn < xc) {
+ fixed temp = xn;
+
+ xn = xc;
+ xc = temp;
+ }
+ xc -= adjust;
+ if (xc >= penum->clip_outer.q.x)
+ goto mt;
+ xn += adjust;
+ if (xn <= penum->clip_outer.p.x)
+ goto mt;
+ penum->xci = fixed2int_pixround(xc);
+ penum->wci = fixed2int_pixround(xn) - penum->xci;
+ if (penum->wci == 0)
+ goto mt;
+ }
+ break;
+ case image_skewed:
+ ;
+ }
+ dda_translate(penum->dda.pixel0.x,
+ penum->cur.x - penum->prev.x);
+ dda_translate(penum->dda.pixel0.y,
+ penum->cur.y - penum->prev.y);
+ penum->prev = penum->cur;
+ code = (*penum->render) (penum, buffer, sourcex, width_spp, 1,
+ dev);
+ if (code < 0)
+ goto err;
+ mt:;
+ }
+ if (penum->y < penum->rect.h) {
+ code = 0;
+ goto out;
+ }
+ /* End of data. Render any left-over buffered data. */
+ code = gx_image1_flush(info);
+ if (code < 0) {
+ penum->y--;
+ goto err;
+ }
+ code = 1;
+ goto out;
+ err: /* Error or interrupt, restore original state. */
+ while (penum->y > y) {
+ dda_previous(penum->dda.row.x);
+ dda_previous(penum->dda.row.y);
+ --(penum->y);
+ }
+ /* Note that caller must call end_image */
+ /* for both error and normal termination. */
+ out:return code;
+}
+
+/* Flush any buffered data. */
+int
+gx_image1_flush(gx_image_enum_common_t * info)
+{
+ gx_image_enum *penum = (gx_image_enum *)info;
+ int width_spp = penum->rect.w * penum->spp;
+ fixed adjust = penum->adjust;
+
+ penum->cur.x = dda_current(penum->dda.row.x);
+ penum->cur.y = dda_current(penum->dda.row.y);
+ switch (penum->posture) {
+ case image_portrait:
+ {
+ fixed yc = penum->cur.y;
+
+ penum->yci = fixed2int_rounded(yc - adjust);
+ penum->hci = fixed2int_rounded(yc + adjust) - penum->yci;
+ }
+ break;
+ case image_landscape:
+ {
+ fixed xc = penum->cur.x;
+
+ penum->xci = fixed2int_rounded(xc - adjust);
+ penum->wci = fixed2int_rounded(xc + adjust) - penum->xci;
+ }
+ break;
+ case image_skewed: /* pacify compilers */
+ ;
+ }
+ dda_translate(penum->dda.pixel0.x, penum->cur.x - penum->prev.x);
+ dda_translate(penum->dda.pixel0.y, penum->cur.y - penum->prev.y);
+ penum->prev = penum->cur;
+ return (*penum->render)(penum, NULL, 0, width_spp, 0, penum->dev);
+}
+
+/* Clean up by releasing the buffers. */
+/* Currently we ignore draw_last. */
+int
+gx_image1_end_image(gx_device *ignore_dev, gx_image_enum_common_t * info,
+ bool draw_last)
+{
+ gx_image_enum *penum = (gx_image_enum *) info;
+ gs_memory_t *mem = penum->memory;
+ stream_IScale_state *scaler = penum->scaler;
+
+#ifdef DEBUG
+ if_debug2('b', "[b]%send_image, y=%d\n",
+ (penum->y < penum->rect.h ? "premature " : ""), penum->y);
+#endif
+ gs_free_object(mem, penum->rop_dev, "image RasterOp");
+ gs_free_object(mem, penum->clip_dev, "image clipper");
+ if (scaler != 0) {
+ (*s_IScale_template.release) ((stream_state *) scaler);
+ gs_free_object(mem, scaler, "image scaler state");
+ }
+ gs_free_object(mem, penum->line, "image line");
+ gs_free_object(mem, penum->buffer, "image buffer");
+ gs_free_object(mem, penum, "gx_default_end_image");
+ return 0;
+}
diff --git a/pstoraster/gxifast.c b/pstoraster/gxifast.c
new file mode 100644
index 000000000..cb7008241
--- /dev/null
+++ b/pstoraster/gxifast.c
@@ -0,0 +1,716 @@
+/* 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$ */
+/* Fast monochrome image rendering */
+#include "gx.h"
+#include "memory_.h"
+#include "gpcheck.h"
+#include "gsbittab.h"
+#include "gserrors.h"
+#include "gxfixed.h"
+#include "gxarith.h"
+#include "gxmatrix.h"
+#include "gsccolor.h"
+#include "gspaint.h"
+#include "gsutil.h"
+#include "gxdevice.h"
+#include "gxcmap.h"
+#include "gxdcolor.h"
+#include "gxistate.h"
+#include "gzpath.h"
+#include "gxdevmem.h"
+#include "gdevmem.h" /* for mem_mono_device */
+#include "gxcpath.h"
+#include "gximage.h"
+#include "gzht.h"
+
+/* Conditionally include statistics code. */
+#ifdef DEBUG
+# define STATS
+#endif
+
+/* ------ Strategy procedure ------ */
+
+/* Use special fast logic for portrait or landscape black-and-white images. */
+private irender_proc(image_render_simple);
+private irender_proc(image_render_landscape);
+private irender_proc_t
+image_strategy_simple(gx_image_enum * penum)
+{
+ irender_proc_t rproc;
+ fixed ox = dda_current(penum->dda.pixel0.x);
+ fixed oy = dda_current(penum->dda.pixel0.y);
+
+ if (penum->use_rop || penum->spp != 1 || penum->bps != 1)
+ return 0;
+ switch (penum->posture) {
+ case image_portrait:
+ { /* Use fast portrait algorithm. */
+ long dev_width =
+ fixed2long_pixround(ox + penum->x_extent.x) -
+ fixed2long_pixround(ox);
+
+ if (dev_width != penum->rect.w) {
+ /*
+ * Add an extra align_bitmap_mod of padding so that
+ * we can align scaled rows with the device.
+ */
+ long line_size =
+ bitmap_raster(any_abs(dev_width)) + align_bitmap_mod;
+
+ if (penum->adjust != 0 || line_size > max_uint)
+ return 0;
+ /* Must buffer a scan line. */
+ penum->line_width = any_abs(dev_width);
+ penum->line_size = (uint) line_size;
+ penum->line = gs_alloc_bytes(penum->memory,
+ penum->line_size, "image line");
+ if (penum->line == 0) {
+ gx_default_end_image(penum->dev,
+ (gx_image_enum_common_t *)penum,
+ false);
+ return 0;
+ }
+ }
+ if_debug2('b', "[b]render=simple, unpack=copy; rect.w=%d, dev_width=%ld\n",
+ penum->rect.w, dev_width);
+ rproc = image_render_simple;
+ break;
+ }
+ case image_landscape:
+ { /* Use fast landscape algorithm. */
+ long dev_width =
+ fixed2long_pixround(oy + penum->x_extent.y) -
+ fixed2long_pixround(oy);
+ long line_size =
+ (dev_width = any_abs(dev_width),
+ bitmap_raster(dev_width) * 8 +
+ round_up(dev_width, 8) * align_bitmap_mod);
+
+ if ((dev_width != penum->rect.w && penum->adjust != 0) ||
+ line_size > max_uint
+ )
+ return 0;
+ /* Must buffer a group of 8N scan lines. */
+ penum->line_width = dev_width;
+ penum->line_size = (uint) line_size;
+ penum->line = gs_alloc_bytes(penum->memory,
+ penum->line_size, "image line");
+ if (penum->line == 0) {
+ gx_default_end_image(penum->dev,
+ (gx_image_enum_common_t *) penum,
+ false);
+ return 0;
+ }
+ penum->xi_next = penum->line_xy = fixed2int_var_rounded(ox);
+ if_debug3('b', "[b]render=landscape, unpack=copy; rect.w=%d, dev_width=%ld, line_size=%ld\n",
+ penum->rect.w, dev_width, line_size);
+ rproc = image_render_landscape;
+ /* Precompute values needed for rasterizing. */
+ penum->dxy =
+ float2fixed(penum->matrix.xy +
+ fixed2float(fixed_epsilon) / 2);
+ break;
+ }
+ default:
+ return 0;
+ }
+ /* Precompute values needed for rasterizing. */
+ penum->dxx =
+ float2fixed(penum->matrix.xx + fixed2float(fixed_epsilon) / 2);
+ /*
+ * We don't want to spread the samples, but we have to reset unpack_bps
+ * to prevent the buffer pointer from being incremented by 8 bytes per
+ * input byte.
+ */
+ penum->unpack = sample_unpack_copy;
+ penum->unpack_bps = 8;
+ return rproc;
+}
+
+void
+gs_gxifast_init(gs_memory_t * mem)
+{
+ image_strategies.simple = image_strategy_simple;
+}
+
+/* ------ Rendering procedures ------ */
+
+/*
+ * Scale (and possibly reverse) one scan line of a monobit image.
+ * This is used for both portrait and landscape image processing.
+ * We pass in an x offset (0 <= line_x < align_bitmap_mod * 8) so that
+ * we can align the result with the eventual device X.
+ *
+ * To be precise, the input to this routine is the w bits starting at
+ * bit data_x in buffer. These w bits expand to abs(x_extent) bits,
+ * either inverted (zero = 0xff) or not (zero = 0), starting at bit
+ * line_x in line which corresponds to coordinate
+ * fixed2int_pixround(xcur + min(x_extent, 0)). Note that the entire
+ * bytes containing the first and last output bits are affected: the
+ * other bits in those bytes are set to zero (i.e., the value of the
+ * 'zero' argument).
+ */
+#ifdef STATS
+struct stats_image_fast_s {
+ long
+ calls, all0s, all1s, runs, lbit0, byte00, byte01, byte02, byte03,
+ byte04, rbit0, lbit1, byte1, rbit1, thin, thin2, nwide, bwide,
+ nfill, bfill;
+} stats_image_fast;
+# define INCS(stat) ++stats_image_fast.stat
+# define ADDS(stat, n) stats_image_fast.stat += n
+#else
+# define INCS(stat) DO_NOTHING
+# define ADDS(stat, n) DO_NOTHING
+#endif
+inline private void
+fill_row(byte *line, int line_x, uint raster, int value)
+{
+ memset(line + (line_x >> 3), value, raster - (line_x >> 3));
+}
+private void
+image_simple_expand(byte * line, int line_x, uint raster,
+ const byte * buffer, int data_x, uint w,
+ fixed xcur, fixed x_extent, byte zero /* 0 or 0xff */ )
+{
+ int dbitx = data_x & 7;
+ byte sbit = 0x80 >> dbitx;
+ byte sbitmask = 0xff >> dbitx;
+ uint wx = dbitx + w;
+ gx_dda_fixed xl;
+ gx_dda_step_fixed dxx4, dxx8, dxx16, dxx24, dxx32;
+ register const byte *psrc = buffer + (data_x >> 3);
+
+ /*
+ * The following 3 variables define the end of the input data row.
+ * We would put them in a struct, except that no compiler that we
+ * know of will optimize individual struct members as though they
+ * were simple variables (e.g., by putting them in registers).
+ *
+ * endp points to the byte that contains the bit just beyond the
+ * end of the row. endx gives the bit number of this bit within
+ * the byte, with 0 being the *least* significant bit. endbit is
+ * a mask for this bit.
+ */
+ const byte *endp = psrc + (wx >> 3);
+ int endx = ~wx & 7;
+ byte endbit = 1 << endx;
+
+ /*
+ * The following 3 variables do the same for start of the last run
+ * of the input row (think of it as a pointer to just beyond the
+ * end of the next-to-last run).
+ */
+ const byte *stop = endp;
+ int stopx;
+ byte stopbit = endbit;
+ byte data;
+ byte one = ~zero;
+ fixed xl0;
+
+ if (w == 0)
+ return;
+ INCS(calls);
+
+ /* Scan backward for the last transition. */
+ if (stopbit == 0x80)
+ --stop, stopbit = 1;
+ else
+ stopbit <<= 1;
+ /* Now (stop, stopbit) give the last bit of the row. */
+ {
+ byte stopmask = -stopbit << 1;
+ byte last = *stop;
+
+ if (stop == psrc) /* only 1 input byte */
+ stopmask &= sbitmask;
+ if (last & stopbit) {
+ /* The last bit is a 1: look for a 0-to-1 transition. */
+ if (~last & stopmask) { /* Transition in last byte. */
+ last |= stopbit - 1;
+ } else { /* No transition in the last byte. */
+ while (stop > psrc && stop[-1] == 0xff)
+ --stop;
+ if (stop == psrc ||
+ (stop == psrc + 1 && !(~*psrc & sbitmask))
+ ) {
+ /* The input is all 1s. Clear the row and exit. */
+ INCS(all1s);
+ fill_row(line, line_x, raster, one);
+ return;
+ }
+ last = *--stop;
+ }
+ stopx = byte_bit_run_length_0[byte_reverse_bits[last]] - 1;
+ } else {
+ /* The last bit is a 0: look for a 1-to-0 transition. */
+ if (last & stopmask) { /* Transition in last byte. */
+ last &= -stopbit;
+ } else { /* No transition in the last byte. */
+ while (stop > psrc && stop[-1] == 0)
+ --stop;
+ if (stop == psrc ||
+ (stop == psrc + 1 && !(*psrc & sbitmask))
+ ) {
+ /* The input is all 0s. Clear the row and exit. */
+ INCS(all0s);
+ fill_row(line, line_x, raster, zero);
+ return;
+ }
+ last = *--stop;
+ }
+ stopx = byte_bit_run_length_0[byte_reverse_bits[last ^ 0xff]] - 1;
+ }
+ if (stopx < 0)
+ stopx = 7, ++stop;
+ stopbit = 1 << stopx;
+ }
+
+ /* Pre-clear the row. */
+ fill_row(line, line_x, raster, zero);
+
+ /* Set up the DDAs. */
+ xl0 =
+ (x_extent >= 0 ?
+ fixed_fraction(fixed_pre_pixround(xcur)) :
+ fixed_fraction(fixed_pre_pixround(xcur + x_extent)) - x_extent);
+ xl0 += int2fixed(line_x);
+ dda_init(xl, xl0, x_extent, w);
+ dxx4 = xl.step;
+ dda_step_add(dxx4, xl.step);
+ dda_step_add(dxx4, dxx4);
+ dxx8 = dxx4;
+ dda_step_add(dxx8, dxx4);
+ dxx16 = dxx8;
+ dda_step_add(dxx16, dxx8);
+ dxx24 = dxx16;
+ dda_step_add(dxx24, dxx8);
+ dxx32 = dxx24;
+ dda_step_add(dxx32, dxx8);
+
+ /*
+ * Loop invariants:
+ * data = *psrc;
+ * sbit = 1 << n, 0<=n<=7.
+ */
+ for (data = *psrc;;) {
+ int x0, n, bit;
+ byte *bp;
+ static const byte lmasks[9] = {
+ 0xff, 0x7f, 0x3f, 0x1f, 0xf, 7, 3, 1, 0
+ };
+ static const byte rmasks[9] = {
+ 0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
+ };
+
+ INCS(runs);
+
+ /* Scan a run of zeros. */
+ data ^= 0xff; /* invert */
+ while (data & sbit) {
+ dda_next(xl);
+ sbit >>= 1;
+ INCS(lbit0);
+ }
+ if (!sbit) { /* Scan a run of zero bytes. */
+sw: if ((data = psrc[1]) != 0) {
+ psrc++;
+ INCS(byte00);
+ } else if ((data = psrc[2]) != 0) {
+ dda_state_next(xl.state, dxx8);
+ psrc += 2;
+ INCS(byte01);
+ } else if ((data = psrc[3]) != 0) {
+ dda_state_next(xl.state, dxx16);
+ psrc += 3;
+ INCS(byte02);
+ } else if ((data = psrc[4]) != 0) {
+ dda_state_next(xl.state, dxx24);
+ psrc += 4;
+ INCS(byte03);
+ } else {
+ dda_state_next(xl.state, dxx32);
+ psrc += 4;
+ INCS(byte04);
+ goto sw;
+ }
+ if (data > 0xf)
+ sbit = 0x80;
+ else {
+ sbit = 0x08;
+ dda_state_next(xl.state, dxx4);
+ }
+ data ^= 0xff; /* invert */
+ while (data & sbit) {
+ dda_next(xl);
+ sbit >>= 1;
+ INCS(rbit0);
+ }
+ }
+ x0 = dda_current_fixed2int(xl);
+ if (psrc >= stop && sbit == stopbit) {
+ /*
+ * We've scanned the last run of 0s.
+ * Prepare to fill the final run of 1s.
+ */
+ n = fixed2int(xl0 + x_extent) - x0;
+ } else { /* Scan a run of ones. */
+ /* We know the current bit is a one. */
+ data ^= 0xff; /* un-invert */
+ do {
+ dda_next(xl);
+ sbit >>= 1;
+ INCS(lbit1);
+ }
+ while (data & sbit);
+ if (!sbit) { /* Scan a run of 0xff bytes. */
+ while ((data = *++psrc) == 0xff) {
+ dda_state_next(xl.state, dxx8);
+ INCS(byte1);
+ }
+ if (data < 0xf0)
+ sbit = 0x80;
+ else {
+ sbit = 0x08;
+ dda_state_next(xl.state, dxx4);
+ }
+ while (data & sbit) {
+ dda_next(xl);
+ sbit >>= 1;
+ INCS(rbit1);
+ }
+ }
+ n = dda_current_fixed2int(xl) - x0;
+ }
+
+ /* Fill the run in the scan line. */
+ if (n < 0)
+ x0 += n, n = -n;
+ bp = line + (x0 >> 3);
+ bit = x0 & 7;
+ if ((n += bit) <= 8) {
+ *bp ^= lmasks[bit] - lmasks[n];
+ INCS(thin);
+ } else if ((n -= 8) <= 8) {
+ *bp ^= lmasks[bit];
+ bp[1] ^= rmasks[n];
+ INCS(thin2);
+ } else {
+ *bp++ ^= lmasks[bit];
+ if (n >= 56) {
+ int nb = n >> 3;
+
+ memset(bp, one, nb);
+ bp += nb;
+ INCS(nwide);
+ ADDS(bwide, nb);
+ } else {
+ ADDS(bfill, n >> 3);
+ while ((n -= 8) >= 0)
+ *bp++ = one;
+ INCS(nfill);
+ }
+ *bp ^= rmasks[n & 7];
+ }
+ if (psrc >= stop && sbit == stopbit)
+ break;
+ }
+}
+
+/* Copy one rendered scan line to the device. */
+private int
+copy_portrait(gx_image_enum * penum, const byte * data, int dx, int raster,
+ int x, int y, int w, int h, gx_device * dev)
+{
+ const gx_device_color *pdc0;
+ const gx_device_color *pdc1;
+ uint align = alignment_mod(data, align_bitmap_mod);
+
+ /*
+ * We know that the lookup table maps 1 bit to 1 bit,
+ * so it can only have 2 states: straight-through or invert.
+ */
+ if (penum->map[0].table.lookup4x1to32[0])
+ pdc0 = &penum->icolor1, pdc1 = &penum->icolor0;
+ else
+ pdc0 = &penum->icolor0, pdc1 = &penum->icolor1;
+ data -= align;
+ dx += align << 3;
+ if (gx_dc_is_pure(pdc0) && gx_dc_is_pure(pdc1)) {
+ /* Just use copy_mono. */
+ dev_proc_copy_mono((*copy_mono)) =
+ (h == 1 || (raster & (align_bitmap_mod - 1)) == 0 ?
+ dev_proc(dev, copy_mono) : gx_copy_mono_unaligned);
+ return (*copy_mono)
+ (dev, data, dx, raster, gx_no_bitmap_id,
+ x, y, w, h, pdc0->colors.pure, pdc1->colors.pure);
+ }
+ /*
+ * At least one color isn't pure: if the other one is transparent, use
+ * the opaque color's fill_masked procedure. Note that we use a
+ * slightly unusual representation for transparent here (per
+ * gx_begin_image1): a pure color with pixel value gx_no_color_index.
+ */
+ {
+ const gx_device_color *pdc;
+ bool invert;
+
+#define DC_IS_NULL(pdc)\
+ (gx_dc_is_pure(pdc) && (pdc)->colors.pure == gx_no_color_index)
+
+ if (DC_IS_NULL(pdc1)) {
+ pdc = pdc0;
+ invert = true;
+ } else {
+ if (!DC_IS_NULL(pdc0)) {
+ int code = gx_device_color_fill_rectangle
+ (pdc0, x, y, w, h, dev, lop_default, NULL);
+
+ if (code < 0)
+ return code;
+ }
+ pdc = pdc1;
+ invert = false;
+ }
+
+#undef DC_IS_NULL
+
+ return (*pdc->type->fill_masked)
+ (pdc, data, dx, raster, gx_no_bitmap_id, x, y, w, h,
+ dev, lop_default, invert);
+
+ }
+}
+
+/* Rendering procedure for a monobit image with no */
+/* skew or rotation and pure colors. */
+private int
+image_render_simple(gx_image_enum * penum, const byte * buffer, int data_x,
+ uint w, int h, gx_device * dev)
+{
+ dev_proc_copy_mono((*copy_mono)) = dev_proc(dev, copy_mono);
+ const fixed dxx = penum->dxx;
+ const byte *line;
+ uint line_width, line_size;
+ int line_x;
+ fixed xcur = dda_current(penum->dda.pixel0.x);
+ int ix = fixed2int_pixround(xcur);
+ const int iy = penum->yci, ih = penum->hci;
+ const gx_device_color * const pdc0 = &penum->icolor0;
+ const gx_device_color * const pdc1 = &penum->icolor1;
+ int dy;
+
+ if (h == 0)
+ return 0;
+ if (penum->line == 0) { /* A direct BitBlt is possible. */
+ line = buffer;
+ line_size = (w + 7) >> 3;
+ line_width = w;
+ line_x = 0;
+ } else if (copy_mono == dev_proc(&mem_mono_device, copy_mono) &&
+ dxx > 0 && gx_dc_is_pure(pdc1) && gx_dc_is_pure(pdc0) &&
+ /* We know the colors must be (0,1) or (1,0). */
+ (pdc0->colors.pure ^ pdc1->colors.pure) == 1 &&
+ !penum->clip_image
+ ) {
+ /* Do the operation directly into the memory device bitmap. */
+ int ixr = fixed2int_pixround(xcur + penum->x_extent.x) - 1;
+ int line_ix;
+ int ib_left = ix >> 3, ib_right = ixr >> 3;
+ byte *scan_line = scan_line_base((gx_device_memory *) dev, iy);
+ byte save_left, save_right, mask;
+
+ line_x = ix & (align_bitmap_mod * 8 - 1);
+ line_ix = ix - line_x;
+ line_size = (ixr >> 3) + 1 - (line_ix >> 3);
+ line_width = ixr + 1 - ix;
+ /* We must save and restore any unmodified bits in */
+ /* the two edge bytes. */
+ save_left = scan_line[ib_left];
+ save_right = scan_line[ib_right];
+ image_simple_expand(scan_line + (line_ix >> 3), line_x,
+ line_size, buffer, data_x, w, xcur,
+ penum->x_extent.x,
+ ((pdc0->colors.pure == 0) !=
+ (penum->map[0].table.lookup4x1to32[0] == 0) ?
+ 0xff : 0));
+ if (ix & 7)
+ mask = (byte) (0xff00 >> (ix & 7)),
+ scan_line[ib_left] =
+ (save_left & mask) + (scan_line[ib_left] & ~mask);
+ if ((ixr + 1) & 7)
+ mask = (byte) (0xff00 >> ((ixr + 1) & 7)),
+ scan_line[ib_right] =
+ (scan_line[ib_right] & mask) + (save_right & ~mask);
+ if (ih <= 1)
+ return 1;
+ /****** MAY BE UNALIGNED ******/
+ line = scan_line + (line_ix >> 3);
+ if (dxx < 0)
+ ix -= line_width;
+ for (dy = 1; dy < ih; dy++) {
+ int code = (*copy_mono)
+ (dev, line, line_x, line_size, gx_no_bitmap_id,
+ ix, iy + dy, line_width, 1,
+ (gx_color_index)0, (gx_color_index)1);
+
+ if (code < 0)
+ return code;
+ }
+ return 0;
+ } else {
+ line = penum->line;
+ line_size = penum->line_size;
+ line_width = penum->line_width;
+ line_x = ix & (align_bitmap_mod * 8 - 1);
+ image_simple_expand(penum->line, line_x, line_size,
+ buffer, data_x, w, xcur,
+ penum->x_extent.x, 0);
+ }
+
+ /* Finally, transfer the scan line to the device. */
+ if (dxx < 0)
+ ix -= line_width;
+ for (dy = 0; dy < ih; dy++) {
+ int code = copy_portrait(penum, line, line_x, line_size,
+ ix, iy + dy, line_width, 1, dev);
+
+ if (code < 0)
+ return code;
+ }
+
+ return 1;
+}
+
+/* Rendering procedure for a 90 degree rotated monobit image */
+/* with pure colors. We buffer and then flip 8 scan lines at a time. */
+private int copy_landscape(P5(gx_image_enum *, int, int, bool, gx_device *));
+private int
+image_render_landscape(gx_image_enum * penum, const byte * buffer, int data_x,
+ uint w, int h, gx_device * dev)
+{
+ byte *line = penum->line;
+ uint raster = bitmap_raster(penum->line_width);
+ int ix = penum->xci, iw = penum->wci;
+ int xinc, xmod;
+ byte *row;
+ const byte *orig_row = 0;
+ bool y_neg = penum->dxy < 0;
+
+ if (is_fneg(penum->matrix.yx))
+ ix += iw, iw = -iw, xinc = -1;
+ else
+ xinc = 1;
+ /*
+ * Because of clipping, there may be discontinuous jumps in the values
+ * of ix (xci). If this happens, or if we are at the end of the data or
+ * a client has requested flushing, flush the flipping buffer.
+ */
+ if (ix != penum->xi_next || h == 0) {
+ int xi = penum->xi_next;
+ int code =
+ (xinc > 0 ?
+ copy_landscape(penum, penum->line_xy, xi, y_neg, dev) :
+ copy_landscape(penum, xi, penum->line_xy, y_neg, dev));
+
+ if (code < 0)
+ return code;
+ penum->line_xy = ix;
+ if (h == 0)
+ return code;
+ }
+ for (; iw != 0; iw -= xinc) {
+ if (xinc < 0)
+ --ix;
+ xmod = ix & 7;
+ row = line + xmod * raster;
+ if (orig_row == 0) {
+ image_simple_expand(row, 0, raster,
+ buffer, data_x, w,
+ dda_current(penum->dda.pixel0.y),
+ penum->x_extent.y, 0);
+ orig_row = row;
+ } else
+ memcpy(row, orig_row, raster);
+ if (xinc > 0) {
+ ++ix;
+ if (xmod == 7) {
+ int code =
+ copy_landscape(penum, penum->line_xy, ix, y_neg, dev);
+
+ if (code < 0)
+ return code;
+ orig_row = 0;
+ penum->line_xy = ix;
+ }
+ } else {
+ if (xmod == 0) {
+ int code =
+ copy_landscape(penum, ix, penum->line_xy, y_neg, dev);
+
+ if (code < 0)
+ return code;
+ orig_row = 0;
+ penum->line_xy = ix;
+ }
+ }
+ }
+ penum->xi_next = ix;
+ return 0;
+}
+
+/* Flip and copy one group of scan lines. */
+private int
+copy_landscape(gx_image_enum * penum, int x0, int x1, bool y_neg,
+ gx_device * dev)
+{
+ byte *line = penum->line;
+ uint line_width = penum->line_width;
+ uint raster = bitmap_raster(line_width);
+ byte *flipped = line + raster * 8;
+ int w = x1 - x0;
+ int y = fixed2int_pixround(dda_current(penum->dda.pixel0.y));
+
+ if (w == 0 || line_width == 0)
+ return 0;
+ /* Flip the buffered data from raster x 8 to align_bitmap_mod x */
+ /* line_width. */
+ if (line_width > 0) {
+ int i;
+
+ for (i = (line_width - 1) >> 3; i >= 0; --i)
+ memflip8x8(line + i, raster,
+ flipped + (i << (log2_align_bitmap_mod + 3)),
+ align_bitmap_mod);
+ }
+ /* Transfer the scan lines to the device. */
+ if (w < 0)
+ x0 = x1, w = -w;
+ if (y_neg)
+ y -= line_width;
+ return copy_portrait(penum, flipped, x0 & 7, align_bitmap_mod,
+ x0, y, w, line_width, dev);
+}
diff --git a/pstoraster/gxiinit.c b/pstoraster/gxiinit.c
new file mode 100644
index 000000000..4b799417c
--- /dev/null
+++ b/pstoraster/gxiinit.c
@@ -0,0 +1,921 @@
+/* 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$ */
+/* Image setup procedures for Ghostscript library */
+#include "gx.h"
+#include "math_.h"
+#include "memory_.h"
+#include "gpcheck.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gsutil.h"
+#include "gxfixed.h"
+#include "gxfrac.h"
+#include "gxarith.h"
+#include "gxmatrix.h"
+#include "gsccolor.h"
+#include "gspaint.h"
+#include "gzstate.h"
+#include "gxdevice.h"
+#include "gzpath.h"
+#include "gzcpath.h"
+#include "gxdevmem.h"
+#include "gximage.h"
+#include "gxiparam.h"
+#include "gdevmrop.h"
+
+/* ---------------- Generic image support ---------------- */
+
+/* Initialize the common parts of image structures. */
+void
+gs_image_common_t_init(gs_image_common_t * pic)
+{
+ gs_make_identity(&pic->ImageMatrix);
+}
+void
+gs_data_image_t_init(gs_data_image_t * pim, int num_components)
+{
+ int i;
+
+ gs_image_common_t_init((gs_image_common_t *) pim);
+ pim->Width = pim->Height = 0;
+ pim->BitsPerComponent = 1;
+ if (num_components >= 0) {
+ for (i = 0; i < num_components * 2; i += 2)
+ pim->Decode[i] = 0, pim->Decode[i + 1] = 1;
+ } else {
+ for (i = 0; i < num_components * -2; i += 2)
+ pim->Decode[i] = 1, pim->Decode[i + 1] = 0;
+ }
+ pim->Interpolate = false;
+}
+void
+gs_pixel_image_t_init(gs_pixel_image_t * pim, const gs_color_space * color_space)
+{
+ int num_components;
+
+ if (color_space == 0 ||
+ (num_components =
+ gs_color_space_num_components(color_space)) < 0
+ )
+ num_components = 0;
+ gs_data_image_t_init((gs_data_image_t *) pim, num_components);
+ pim->format = gs_image_format_chunky;
+ pim->ColorSpace = color_space;
+ pim->CombineWithColor = false;
+}
+
+/* Initialize the common part of an image-processing enumerator. */
+int
+gx_image_enum_common_init(gx_image_enum_common_t * piec,
+ const gs_image_common_t * pic, const gx_image_enum_procs_t * piep,
+ gx_device * dev, int bits_per_component, int num_components,
+ gs_image_format_t format)
+{
+ piec->image_type = pic->type;
+ piec->procs = piep;
+ piec->dev = dev;
+ piec->id = gs_next_ids(1);
+ switch (format) {
+ case gs_image_format_chunky:
+ piec->num_planes = 1;
+ piec->plane_depths[0] = bits_per_component * num_components;
+ break;
+ case gs_image_format_component_planar:
+ piec->num_planes = num_components;
+ {
+ int i;
+
+ for (i = 0; i < num_components; ++i)
+ piec->plane_depths[i] = bits_per_component;
+ }
+ break;
+ case gs_image_format_bit_planar:
+ piec->num_planes = bits_per_component * num_components;
+ {
+ int i;
+
+ for (i = 0; i < piec->num_planes; ++i)
+ piec->plane_depths[i] = 1;
+ }
+#if 0 /* **************** */
+ break;
+#endif /* **************** */
+ default:
+ return_error(gs_error_rangecheck);
+ }
+ return 0;
+}
+
+/* ---------------- ImageType 1 images ---------------- */
+
+/* Structure descriptors */
+private_st_gx_image_enum();
+public_st_gs_image_common();
+public_st_gs_data_image();
+public_st_gs_pixel_image();
+
+/* Strategy procedures */
+gx_image_strategies_t image_strategies;
+
+/* Define the image type for ImageType 1 images. */
+private const gx_image_type_t image1_type = {
+ gx_begin_image1, gx_data_image_source_size, 1
+};
+private const gx_image_enum_procs_t image1_enum_procs = {
+ gx_image1_plane_data, gx_image1_end_image, gx_image1_flush
+};
+
+/* Define the procedures for initializing gs_image_ts to default values. */
+void
+gs_image_t_init(gs_image_t * pim, const gs_color_space * color_space)
+{
+ gs_pixel_image_t_init((gs_pixel_image_t *) pim, color_space);
+ pim->type = &image1_type;
+ pim->ImageMask = pim->adjust = (color_space == NULL);
+ pim->Alpha = gs_image_alpha_none;
+}
+void
+gs_image_t_init_mask(gs_image_t * pim, bool write_1s)
+{
+ gs_image_t_init(pim, NULL);
+ if (write_1s)
+ pim->Decode[0] = 1, pim->Decode[1] = 0;
+ else
+ pim->Decode[0] = 0, pim->Decode[1] = 1;
+}
+
+/* Compute the source size of an ordinary image with explicit data. */
+int
+gx_data_image_source_size(const gs_imager_state * pis,
+ const gs_image_common_t * pim, gs_int_point * psize)
+{
+ const gs_data_image_t *pdi = (const gs_data_image_t *)pim;
+
+ psize->x = pdi->Width;
+ psize->y = pdi->Height;
+ return 0;
+}
+
+/* Process the next piece of an image with no source data. */
+/* This procedure should never be called. */
+int
+gx_no_image_plane_data(gx_device * dev,
+ gx_image_enum_common_t * info, const gx_image_plane_t * planes, int height)
+{
+ return_error(gs_error_Fatal);
+}
+
+/* Clean up after processing an image with no source data. */
+/* This procedure may be called, but should do nothing. */
+int
+gx_ignore_end_image(gx_device * dev, gx_image_enum_common_t * info,
+ bool draw_last)
+{
+ return 0;
+}
+
+/* GC procedures */
+#define eptr ((gx_image_enum *)vptr)
+private
+ENUM_PTRS_BEGIN(image_enum_enum_ptrs)
+{
+ int bps;
+ gs_ptr_type_t ret;
+
+ /* Enumerate the used members of clues.dev_color. */
+ index -= gx_image_enum_num_ptrs;
+ bps = eptr->unpack_bps;
+ if (eptr->spp != 1)
+ bps = 8;
+ else if (bps > 8 || eptr->unpack == sample_unpack_copy)
+ bps = 1;
+ if (index >= (1 << bps) * st_device_color_max_ptrs) /* done */
+ return 0;
+ ret = ENUM_USING(st_device_color,
+ &eptr->clues[(index / st_device_color_max_ptrs) *
+ (255 / ((1 << bps) - 1))].dev_color,
+ sizeof(eptr->clues[0].dev_color),
+ index % st_device_color_max_ptrs);
+ if (ret == 0) /* don't stop early */
+ ENUM_RETURN(0);
+ return ret;
+}
+#define e1(i,elt) ENUM_PTR(i,gx_image_enum,elt);
+gx_image_enum_do_ptrs(e1)
+#undef e1
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(image_enum_reloc_ptrs)
+{
+ int i;
+
+#define r1(i,elt) RELOC_PTR(gx_image_enum,elt);
+ gx_image_enum_do_ptrs(r1)
+#undef r1
+ {
+ int bps = eptr->unpack_bps;
+
+ if (eptr->spp != 1)
+ bps = 8;
+ else if (bps > 8 || eptr->unpack == sample_unpack_copy)
+ bps = 1;
+ for (i = 0; i <= 255; i += 255 / ((1 << bps) - 1))
+ RELOC_USING(st_device_color,
+ &eptr->clues[i].dev_color, sizeof(gx_device_color));
+ }
+}
+RELOC_PTRS_END
+#undef eptr
+
+/* Forward declarations */
+private int color_draws_b_w(P2(gx_device * dev,
+ const gx_drawing_color * pdcolor));
+private void image_init_map(P3(byte * map, int map_size, const float *decode));
+private void image_init_colors(P9(gx_image_enum * penum, int bps, int spp,
+ bool multi, const float *decode,
+ const gs_imager_state * pis, gx_device * dev,
+ const gs_color_space * pcs, bool * pdcb));
+
+/* Procedures for unpacking the input data into bytes or fracs. */
+ /*extern sample_unpack_proc(sample_unpack_copy); *//* declared above */
+extern sample_unpack_proc(sample_unpack_1);
+extern sample_unpack_proc(sample_unpack_2);
+extern sample_unpack_proc(sample_unpack_4);
+extern sample_unpack_proc(sample_unpack_8);
+
+sample_unpack_proc((*sample_unpack_12_proc)); /* optional */
+
+/* Start processing an ImageType 1 image. */
+/* Note that since this is actually a begin_typed_image procedure, */
+/* the type of pim is the more abstract one. */
+int
+gx_begin_image1(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 * mem, gx_image_enum_common_t ** pinfo)
+{
+ const gs_image_t *pim = (const gs_image_t *)pic;
+ gs_image_format_t format = pim->format;
+ gx_image_enum *penum;
+ const int width = pim->Width;
+ const int height = pim->Height;
+ const int bps = pim->BitsPerComponent;
+ bool masked = pim->ImageMask;
+ const float *decode = pim->Decode;
+ bool multi;
+ int index_bps;
+ const gs_color_space *pcs = pim->ColorSpace;
+ gs_logical_operation_t lop = (pis ? pis->log_op : lop_default);
+ int code;
+ gs_matrix mat;
+ int log2_xbytes = (bps <= 8 ? 0 : arch_log2_sizeof_frac);
+ int spp, nplanes, spread;
+ uint bsize;
+ byte *buffer;
+ fixed mtx, mty;
+ gs_fixed_point row_extent, col_extent, x_extent, y_extent;
+ bool device_color;
+ gs_fixed_rect obox, cbox;
+ fixed adjust;
+
+ if (width < 0 || height < 0)
+ return_error(gs_error_rangecheck);
+ switch (format) {
+ case gs_image_format_chunky:
+ multi = false;
+ break;
+ case gs_image_format_component_planar:
+ multi = true;
+ break;
+ default:
+ return_error(gs_error_rangecheck);
+ }
+ switch (bps) {
+ case 1:
+ index_bps = 0;
+ break;
+ case 2:
+ index_bps = 1;
+ break;
+ case 4:
+ index_bps = 2;
+ break;
+ case 8:
+ index_bps = 3;
+ break;
+ case 12:
+ index_bps = 4;
+ break;
+ default:
+ return_error(gs_error_rangecheck);
+ }
+ if (prect) {
+ if (prect->p.x < 0 || prect->p.y < 0 ||
+ prect->q.x < prect->p.x || prect->q.y < prect->p.y ||
+ prect->q.x > width || prect->q.y > height
+ )
+ return_error(gs_error_rangecheck);
+ }
+ if (pmat == 0)
+ pmat = &ctm_only(pis);
+ if ((code = gs_matrix_invert(&pim->ImageMatrix, &mat)) < 0 ||
+ (code = gs_matrix_multiply(&mat, pmat, &mat)) < 0 ||
+ (code =
+ gs_distance_transform2fixed((const gs_matrix_fixed *)&mat,
+ (floatp) width, (floatp) 0,
+ &row_extent)) < 0 ||
+ (code =
+ gs_distance_transform2fixed((const gs_matrix_fixed *)&mat,
+ (floatp) 0, (floatp) height,
+ &col_extent)) < 0
+ )
+ return code;
+ penum = gs_alloc_struct(mem, gx_image_enum, &st_gx_image_enum,
+ "gx_default_begin_image");
+ if (penum == 0)
+ return_error(gs_error_VMerror);
+ gx_image_enum_common_init((gx_image_enum_common_t *) penum, pic,
+ &image1_enum_procs, dev, bps,
+ (masked ? 1 : cs_num_components(pcs)),
+ format);
+ if (prect) {
+ penum->rect.x = prect->p.x, penum->rect.y = prect->p.y;
+ penum->rect.w = prect->q.x - prect->p.x,
+ penum->rect.h = prect->q.y - prect->p.y;
+ if ((code =
+ gs_distance_transform2fixed((const gs_matrix_fixed *)&mat,
+ (floatp) penum->rect.w, (floatp) 0,
+ &x_extent)) < 0 ||
+ (code =
+ gs_distance_transform2fixed((const gs_matrix_fixed *)&mat,
+ (floatp) 0, (floatp) penum->rect.h,
+ &y_extent)) < 0
+ ) {
+ gs_free_object(mem, penum, "gx_default_begin_image");
+ return code;
+ }
+ } else {
+ penum->rect.x = 0, penum->rect.y = 0;
+ penum->rect.w = width, penum->rect.h = height;
+ x_extent = row_extent;
+ y_extent = col_extent;
+ }
+ if ((penum->masked = masked)) { /* This is imagemask. */
+ if (bps != 1 || multi || pcs != NULL || pim->Alpha ||
+ !((decode[0] == 0.0 && decode[1] == 1.0) ||
+ (decode[0] == 1.0 && decode[1] == 0.0))
+ ) {
+ gs_free_object(mem, penum, "gx_default_begin_image");
+ return_error(gs_error_rangecheck);
+ }
+ /* Initialize color entries 0 and 255. */
+ color_set_pure(&penum->icolor0, gx_no_color_index);
+ penum->icolor1 = *pdcolor;
+ memcpy(&penum->map[0].table.lookup4x1to32[0],
+ (decode[0] == 0 ? lookup4x1to32_inverted :
+ lookup4x1to32_identity),
+ 16 * 4);
+ penum->map[0].decoding = sd_none;
+ spp = 1;
+ adjust = (pim->adjust ? float2fixed(0.25) : fixed_0);
+ lop = rop3_know_S_0(lop);
+ } else { /* This is image, not imagemask. */
+ const gs_color_space_type *pcst = pcs->type;
+ int b_w_color;
+
+ spp = cs_num_components(pcs);
+ if (spp < 0) { /* Pattern not allowed */
+ gs_free_object(mem, penum, "gx_default_begin_image");
+ return_error(gs_error_rangecheck);
+ }
+ if (pim->Alpha)
+ ++spp;
+ if (spp == 1)
+ multi = false;
+ device_color = (*pcst->concrete_space) (pcs, pis) == pcs;
+ image_init_colors(penum, bps, spp, multi, decode, pis, dev,
+ pcs, &device_color);
+ adjust = fixed_0;
+ /* Try to transform non-default RasterOps to something */
+ /* that we implement less expensively. */
+ if (!pim->CombineWithColor)
+ lop = rop3_know_T_0(lop) & ~lop_T_transparent;
+ else {
+ if (rop3_uses_T(lop))
+ switch (color_draws_b_w(dev, pdcolor)) {
+ case 0:
+ lop = rop3_know_T_0(lop);
+ break;
+ case 1:
+ lop = rop3_know_T_1(lop);
+ break;
+ default:
+ ;
+ }
+ }
+ if (lop != rop3_S && /* if best case, no more work needed */
+ !rop3_uses_T(lop) && bps == 1 && spp == 1 &&
+ (b_w_color =
+ color_draws_b_w(dev, &penum->icolor0)) >= 0 &&
+ color_draws_b_w(dev, &penum->icolor1) == (b_w_color ^ 1)
+ ) {
+ if (b_w_color) { /* Swap the colors and invert the RasterOp source. */
+ gx_device_color dcolor;
+
+ dcolor = penum->icolor0;
+ penum->icolor0 = penum->icolor1;
+ penum->icolor1 = dcolor;
+ lop = rop3_invert_S(lop);
+ }
+ /*
+ * At this point, we know that the source pixels
+ * correspond directly to the S input for the raster op,
+ * i.e., icolor0 is black and icolor1 is white.
+ */
+ switch (lop) {
+ case rop3_D & rop3_S:
+ /* Implement this as an inverted mask writing 0s. */
+ penum->icolor1 = penum->icolor0;
+ /* (falls through) */
+ case rop3_D | rop3_not(rop3_S):
+ /* Implement this as an inverted mask writing 1s. */
+ memcpy(&penum->map[0].table.lookup4x1to32[0],
+ lookup4x1to32_inverted, 16 * 4);
+ rmask: /* Fill in the remaining parameters for a mask. */
+ penum->masked = masked = true;
+ color_set_pure(&penum->icolor0, gx_no_color_index);
+ penum->map[0].decoding = sd_none;
+ lop = rop3_T;
+ break;
+ case rop3_D & rop3_not(rop3_S):
+ /* Implement this as a mask writing 0s. */
+ penum->icolor1 = penum->icolor0;
+ /* (falls through) */
+ case rop3_D | rop3_S:
+ /* Implement this as a mask writing 1s. */
+ memcpy(&penum->map[0].table.lookup4x1to32[0],
+ lookup4x1to32_identity, 16 * 4);
+ goto rmask;
+ default:
+ ;
+ }
+ }
+ }
+ penum->device_color = device_color;
+ /*
+ * Adjust width upward for unpacking up to 7 trailing bits in
+ * the row, plus 1 byte for end-of-run, plus up to 7 leading
+ * bits for data_x offset within a packed byte.
+ */
+ bsize = ((bps > 8 ? width * 2 : width) + 15) * spp;
+ buffer = gs_alloc_bytes(mem, bsize, "image buffer");
+ if (buffer == 0) {
+ gs_free_object(mem, penum, "gx_default_begin_image");
+ return_error(gs_error_VMerror);
+ }
+ penum->bps = bps;
+ penum->unpack_bps = bps;
+ penum->log2_xbytes = log2_xbytes;
+ penum->spp = spp;
+ penum->alpha = pim->Alpha;
+ nplanes = (multi ? spp : 1);
+ penum->num_planes = nplanes;
+ spread = nplanes << log2_xbytes;
+ penum->spread = spread;
+ penum->matrix = mat;
+ penum->x_extent = x_extent;
+ penum->y_extent = y_extent;
+ penum->posture =
+ ((x_extent.y | y_extent.x) == 0 ? image_portrait :
+ (x_extent.x | y_extent.y) == 0 ? image_landscape :
+ image_skewed);
+ mtx = float2fixed(mat.tx);
+ mty = float2fixed(mat.ty);
+ penum->pis = pis;
+ penum->pcs = pcs;
+ penum->memory = mem;
+ penum->buffer = buffer;
+ penum->buffer_size = bsize;
+ penum->line = 0;
+ penum->line_size = 0;
+ /*
+ * If we're asked to interpolate in a partial image, we have to
+ * assume that the client either really only is interested in
+ * the given sub-image, or else is constructing output out of
+ * overlapping pieces.
+ */
+ penum->interpolate = pim->Interpolate;
+ penum->use_rop = lop != (masked ? rop3_T : rop3_S);
+#ifdef DEBUG
+ if (gs_debug_c('*')) {
+ if (penum->use_rop)
+ dprintf1("[%03x]", lop);
+ dprintf5("%c%d%c%dx%d ",
+ (masked ? (color_is_pure(pdcolor) ? 'm' : 'h') : 'i'),
+ bps,
+ (penum->posture == image_portrait ? ' ' :
+ penum->posture == image_landscape ? 'L' : 'T'),
+ width, height);
+ }
+#endif
+ penum->slow_loop = 0;
+ if (pcpath == 0) {
+ (*dev_proc(dev, get_clipping_box)) (dev, &obox);
+ cbox = obox;
+ penum->clip_image = 0;
+ } else
+ penum->clip_image =
+ (gx_cpath_outer_box(pcpath, &obox) | /* not || */
+ gx_cpath_inner_box(pcpath, &cbox) ?
+ 0 : image_clip_region);
+ penum->clip_outer = obox;
+ penum->clip_inner = cbox;
+ penum->log_op = rop3_T; /* rop device takes care of this */
+ penum->clip_dev = 0; /* in case we bail out */
+ penum->rop_dev = 0; /* ditto */
+ penum->scaler = 0; /* ditto */
+ /*
+ * If all four extrema of the image fall within the clipping
+ * rectangle, clipping is never required. When making this check,
+ * we must carefully take into account the fact that we only care
+ * about pixel centers.
+ */
+ {
+ fixed
+ epx = min(row_extent.x, 0) + min(col_extent.x, 0),
+ eqx = max(row_extent.x, 0) + max(col_extent.x, 0),
+ epy = min(row_extent.y, 0) + min(col_extent.y, 0),
+ eqy = max(row_extent.y, 0) + max(col_extent.y, 0);
+
+ {
+ int hwx, hwy;
+
+ switch (penum->posture) {
+ case image_portrait:
+ hwx = width, hwy = height;
+ break;
+ case image_landscape:
+ hwx = height, hwy = width;
+ break;
+ default:
+ hwx = hwy = 0;
+ }
+ /*
+ * If the image is only 1 sample wide or high,
+ * and is less than 1 device pixel wide or high,
+ * move it slightly so that it covers pixel centers.
+ * This is a hack to work around a bug in some old
+ * versions of TeX/dvips, which use 1-bit-high images
+ * to draw horizontal and vertical lines without
+ * positioning them properly.
+ */
+ if (hwx == 1 && eqx - epx < fixed_1) {
+ fixed diff =
+ arith_rshift_1(row_extent.x + col_extent.x);
+
+ mtx = (((mtx + diff) | fixed_half) & -fixed_half) - diff;
+ }
+ if (hwy == 1 && eqy - epy < fixed_1) {
+ fixed diff =
+ arith_rshift_1(row_extent.y + col_extent.y);
+
+ mty = (((mty + diff) | fixed_half) & -fixed_half) - diff;
+ }
+ }
+ if_debug5('b', "[b]Image: %sspp=%d, bps=%d, mt=(%g,%g)\n",
+ (masked? "masked, " : ""), spp, bps,
+ fixed2float(mtx), fixed2float(mty));
+ if_debug9('b',
+ "[b] cbox=(%g,%g),(%g,%g), obox=(%g,%g),(%g,%g), clip_image=0x%x\n",
+ fixed2float(cbox.p.x), fixed2float(cbox.p.y),
+ fixed2float(cbox.q.x), fixed2float(cbox.q.y),
+ fixed2float(obox.p.x), fixed2float(obox.p.y),
+ fixed2float(obox.q.x), fixed2float(obox.q.y),
+ penum->clip_image);
+ dda_init(penum->dda.row.x, mtx, col_extent.x, height);
+ dda_init(penum->dda.row.y, mty, col_extent.y, height);
+ if (penum->rect.y) {
+ dda_advance(penum->dda.row.x, penum->rect.y);
+ dda_advance(penum->dda.row.y, penum->rect.y);
+ }
+ penum->cur.x = penum->prev.x = dda_current(penum->dda.row.x);
+ penum->cur.y = penum->prev.y = dda_current(penum->dda.row.y);
+ dda_init(penum->dda.pixel0.x, penum->cur.x, row_extent.x,
+ width);
+ dda_init(penum->dda.pixel0.y, penum->cur.y, row_extent.y,
+ width);
+ if (penum->rect.x) {
+ dda_advance(penum->dda.pixel0.x, penum->rect.x);
+ dda_advance(penum->dda.pixel0.y, penum->rect.x);
+ } {
+ fixed ox = dda_current(penum->dda.pixel0.x);
+ fixed oy = dda_current(penum->dda.pixel0.y);
+
+ if (!penum->clip_image) /* i.e., not clip region */
+ penum->clip_image =
+ (fixed_pixround(ox + epx) < fixed_pixround(cbox.p.x) ?
+ image_clip_xmin : 0) +
+ (fixed_pixround(ox + eqx) >= fixed_pixround(cbox.q.x) ?
+ image_clip_xmax : 0) +
+ (fixed_pixround(oy + epy) < fixed_pixround(cbox.p.y) ?
+ image_clip_ymin : 0) +
+ (fixed_pixround(oy + eqy) >= fixed_pixround(cbox.q.y) ?
+ image_clip_ymax : 0);
+ }
+ }
+ penum->y = 0;
+ penum->adjust = adjust;
+ {
+ static const sample_unpack_proc_t procs[4] =
+ {
+ sample_unpack_1, sample_unpack_2,
+ sample_unpack_4, sample_unpack_8
+ };
+
+ if (index_bps == 4) {
+ if ((penum->unpack = sample_unpack_12_proc) == 0) { /* 12-bit samples are not supported. */
+ gx_default_end_image(dev,
+ (gx_image_enum_common_t *) penum,
+ false);
+ return_error(gs_error_rangecheck);
+ }
+ } else {
+ penum->unpack = procs[index_bps];
+ if_debug1('b', "[b]unpack=%d\n", bps);
+ }
+#define use_strategy(sp)\
+ (image_strategies.sp != 0 &&\
+ (penum->render = (*image_strategies.sp)(penum)) != 0)
+ if (
+ use_strategy(interpolate) ||
+ use_strategy(simple) ||
+ use_strategy(fracs) ||
+ use_strategy(mono) ||
+ use_strategy(color)
+ )
+ DO_NOTHING;
+#undef use_strategy
+ else { /* No available strategy can handle this image. */
+ gx_default_end_image(dev, (gx_image_enum_common_t *) penum,
+ false);
+ return_error(gs_error_rangecheck);
+ }
+ }
+ if (penum->clip_image && pcpath) { /* Set up the clipping device. */
+ gx_device_clip *cdev =
+ gs_alloc_struct(mem, gx_device_clip,
+ &st_device_clip, "image clipper");
+
+ if (cdev == 0) {
+ gx_default_end_image(dev,
+ (gx_image_enum_common_t *) penum,
+ false);
+ return_error(gs_error_VMerror);
+ }
+ gx_make_clip_device(cdev, cdev, gx_cpath_list(pcpath));
+ cdev->target = dev;
+ (*dev_proc(cdev, open_device)) ((gx_device *) cdev);
+ penum->clip_dev = cdev;
+ }
+ if (penum->use_rop) { /* Set up the RasterOp source device. */
+ gx_device_rop_texture *rtdev;
+
+ code = gx_alloc_rop_texture_device(&rtdev, mem,
+ "image RasterOp");
+ if (code < 0) {
+ gx_default_end_image(dev, (gx_image_enum_common_t *) penum,
+ false);
+ return code;
+ }
+ gx_make_rop_texture_device(rtdev,
+ (penum->clip_dev != 0 ?
+ (gx_device *) penum->clip_dev :
+ dev), lop, pdcolor);
+ penum->rop_dev = rtdev;
+ }
+#ifdef DEBUG
+ if (gs_debug_c('b')) {
+ dlprintf2("[b]Image: w=%d h=%d", width, height);
+ if (prect)
+ dprintf4(" ((%d,%d),(%d,%d))",
+ prect->p.x, prect->p.y, prect->q.x, prect->q.y);
+ dprintf6(" [%g %g %g %g %g %g]\n",
+ mat.xx, mat.xy, mat.yx, mat.yy, mat.tx, mat.ty);
+ }
+#endif
+ *pinfo = (gx_image_enum_common_t *) penum;
+ return 0;
+}
+
+/* If a drawing color is black or white, return 0 or 1 respectively, */
+/* otherwise return -1. */
+private int
+color_draws_b_w(gx_device * dev, const gx_drawing_color * pdcolor)
+{
+ if (color_is_pure(pdcolor)) {
+ gx_color_value rgb[3];
+
+ (*dev_proc(dev, map_color_rgb)) (dev, gx_dc_pure_color(pdcolor),
+ rgb);
+ if (!(rgb[0] | rgb[1] | rgb[2]))
+ return 0;
+ if ((rgb[0] & rgb[1] & rgb[2]) == gx_max_color_value)
+ return 1;
+ }
+ return -1;
+}
+
+/* Initialize the color mapping tables for a non-mask image. */
+private void
+image_init_colors(gx_image_enum * penum, int bps, int spp, bool multi,
+ const float *decode /*[spp*2] */ , const gs_imager_state * pis, gx_device * dev,
+ const gs_color_space * pcs, bool * pdcb)
+{
+ int ci;
+ static const float default_decode[] =
+ {
+ 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0
+ };
+
+ /* Initialize the color table */
+
+#define ictype(i)\
+ penum->clues[i].dev_color.type
+ switch ((spp == 1 ? bps : 8)) {
+ case 8: /* includes all color images */
+ {
+ register gx_image_clue *pcht = &penum->clues[0];
+ register int n = 64;
+
+ do {
+ pcht[0].dev_color.type =
+ pcht[1].dev_color.type =
+ pcht[2].dev_color.type =
+ pcht[3].dev_color.type =
+ gx_dc_type_none;
+ pcht[0].key = pcht[1].key =
+ pcht[2].key = pcht[3].key = 0;
+ pcht += 4;
+ }
+ while (--n > 0);
+ penum->clues[0].key = 1; /* guarantee no hit */
+ break;
+ }
+ case 4:
+ ictype(17) = ictype(2 * 17) = ictype(3 * 17) =
+ ictype(4 * 17) = ictype(6 * 17) = ictype(7 * 17) =
+ ictype(8 * 17) = ictype(9 * 17) = ictype(11 * 17) =
+ ictype(12 * 17) = ictype(13 * 17) = ictype(14 * 17) =
+ gx_dc_type_none;
+ /* falls through */
+ case 2:
+ ictype(5 * 17) = ictype(10 * 17) = gx_dc_type_none;
+#undef ictype
+ }
+
+ /* Initialize the maps from samples to intensities. */
+
+ for (ci = 0; ci < spp; ci++) {
+ sample_map *pmap = &penum->map[ci];
+
+ /* If the decoding is [0 1] or [1 0], we can fold it */
+ /* into the expansion of the sample values; */
+ /* otherwise, we have to use the floating point method. */
+
+ const float *this_decode = &decode[ci * 2];
+ const float *map_decode; /* decoding used to */
+
+ /* construct the expansion map */
+
+ const float *real_decode; /* decoding for */
+
+ /* expanded samples */
+
+ bool no_decode;
+
+ map_decode = real_decode = this_decode;
+ if (map_decode[0] == 0.0 && map_decode[1] == 1.0)
+ no_decode = true;
+ else if (map_decode[0] == 1.0 && map_decode[1] == 0.0)
+ no_decode = true,
+ real_decode = default_decode;
+ else
+ no_decode = false,
+ *pdcb = false,
+ map_decode = default_decode;
+ if (bps > 2 || multi) {
+ if (bps <= 8)
+ image_init_map(&pmap->table.lookup8[0], 1 << bps,
+ map_decode);
+ } else { /* The map index encompasses more than one pixel. */
+ byte map[4];
+ register int i;
+
+ image_init_map(&map[0], 1 << bps, map_decode);
+ switch (bps) {
+ case 1:
+ {
+ register bits32 *p = &pmap->table.lookup4x1to32[0];
+
+ if (map[0] == 0 && map[1] == 0xff)
+ memcpy((byte *) p, lookup4x1to32_identity, 16 * 4);
+ else if (map[0] == 0xff && map[1] == 0)
+ memcpy((byte *) p, lookup4x1to32_inverted, 16 * 4);
+ else
+ for (i = 0; i < 16; i++, p++)
+ ((byte *) p)[0] = map[i >> 3],
+ ((byte *) p)[1] = map[(i >> 2) & 1],
+ ((byte *) p)[2] = map[(i >> 1) & 1],
+ ((byte *) p)[3] = map[i & 1];
+ }
+ break;
+ case 2:
+ {
+ register bits16 *p = &pmap->table.lookup2x2to16[0];
+
+ for (i = 0; i < 16; i++, p++)
+ ((byte *) p)[0] = map[i >> 2],
+ ((byte *) p)[1] = map[i & 3];
+ }
+ break;
+ }
+ }
+ pmap->decode_base /* = decode_lookup[0] */ = real_decode[0];
+ pmap->decode_factor =
+ (real_decode[1] - real_decode[0]) /
+ (bps <= 8 ? 255.0 : (float)frac_1);
+ pmap->decode_max /* = decode_lookup[15] */ = real_decode[1];
+ if (no_decode)
+ pmap->decoding = sd_none;
+ else if (bps <= 4) {
+ int step = 15 / ((1 << bps) - 1);
+ int i;
+
+ pmap->decoding = sd_lookup;
+ for (i = 15 - step; i > 0; i -= step)
+ pmap->decode_lookup[i] = pmap->decode_base +
+ i * (255.0 / 15) * pmap->decode_factor;
+ } else
+ pmap->decoding = sd_compute;
+ if (spp == 1) { /* and ci == 0 *//* Pre-map entries 0 and 255. */
+ gs_client_color cc;
+
+ cc.paint.values[0] = real_decode[0];
+ (*pcs->type->remap_color) (&cc, pcs, &penum->icolor0,
+ pis, dev, gs_color_select_source);
+ cc.paint.values[0] = real_decode[1];
+ (*pcs->type->remap_color) (&cc, pcs, &penum->icolor1,
+ pis, dev, gs_color_select_source);
+ }
+ }
+
+}
+/* Construct a mapping table for sample values. */
+/* map_size is 2, 4, 16, or 256. Note that 255 % (map_size - 1) == 0, */
+/* so the division 0xffffL / (map_size - 1) is always exact. */
+private void
+image_init_map(byte * map, int map_size, const float *decode)
+{
+ float min_v = decode[0];
+ float diff_v = decode[1] - min_v;
+
+ if (diff_v == 1 || diff_v == -1) { /* We can do the stepping with integers, without overflow. */
+ byte *limit = map + map_size;
+ uint value = min_v * 0xffffL;
+ int diff = diff_v * (0xffffL / (map_size - 1));
+
+ for (; map != limit; map++, value += diff)
+ *map = value >> 8;
+ } else { /* Step in floating point, with clamping. */
+ int i;
+
+ for (i = 0; i < map_size; ++i) {
+ int value = (int)((min_v + diff_v * i / (map_size - 1)) * 255);
+
+ map[i] = (value < 0 ? 0 : value > 255 ? 255 : value);
+ }
+ }
+}
diff --git a/pstoraster/gximage.h b/pstoraster/gximage.h
new file mode 100644
index 000000000..ea28e40e2
--- /dev/null
+++ b/pstoraster/gximage.h
@@ -0,0 +1,283 @@
+/* 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 gxcpath.h, gxdevmem.h, gxdcolor.h, gzpath.h */
+
+#ifndef gximage_INCLUDED
+# define gximage_INCLUDED
+
+#include "gsiparam.h"
+#include "gxcspace.h"
+#include "strimpl.h" /* for siscale.h */
+#include "siscale.h"
+#include "gxdda.h"
+#include "gxiparam.h"
+#include "gxsample.h"
+
+/* Define the abstract type for the image enumerator state. */
+typedef struct gx_image_enum_s gx_image_enum;
+
+/*
+ * Incoming samples may go through two different transformations:
+ *
+ * - For N-bit input samples with N <= 8, N-to-8-bit expansion
+ * may involve a lookup map. Currently this map is either an
+ * identity function or a subtraction from 1 (inversion).
+ *
+ * - The 8-bit or frac expanded sample may undergo decoding (a linear
+ * transformation) before being handed off to the color mapping
+ * machinery.
+ *
+ * If the decoding function's range is [0..1], we fold it into the
+ * expansion lookup; otherwise we must compute it separately.
+ * For speed, we distinguish 3 different cases of the decoding step:
+ */
+typedef enum {
+ sd_none, /* decoded during expansion */
+ sd_lookup, /* use lookup_decode table */
+ sd_compute /* compute using base and factor */
+} sample_decoding;
+typedef struct sample_map_s {
+
+ sample_lookup_t table;
+
+ /* If an 8-bit fraction doesn't represent the decoded value */
+ /* accurately enough, but the samples have 4 bits or fewer, */
+ /* we precompute the decoded values into a table. */
+ /* Different entries are used depending on bits/sample: */
+ /* 1,8,12 bits/sample: 0,15 */
+ /* 2 bits/sample: 0,5,10,15 */
+ /* 4 bits/sample: all */
+
+ float decode_lookup[16];
+#define decode_base decode_lookup[0]
+#define decode_max decode_lookup[15]
+
+ /* In the worst case, we have to do the decoding on the fly. */
+ /* The value is base + sample * factor, where the sample is */
+ /* an 8-bit (unsigned) integer or a frac. */
+
+ double decode_factor;
+
+ sample_decoding decoding;
+
+} sample_map;
+
+/* Decode an 8-bit sample into a floating point color component. */
+/* penum points to the gx_image_enum structure. */
+#define decode_sample(sample_value, cc, i)\
+ switch ( penum->map[i].decoding )\
+ {\
+ case sd_none:\
+ cc.paint.values[i] = (sample_value) * (1.0 / 255.0); /* faster than / */\
+ break;\
+ case sd_lookup: /* <= 4 significant bits */\
+ cc.paint.values[i] =\
+ penum->map[i].decode_lookup[(sample_value) >> 4];\
+ break;\
+ case sd_compute:\
+ cc.paint.values[i] =\
+ penum->map[i].decode_base + (sample_value) * penum->map[i].decode_factor;\
+ }
+
+/* Decode a frac value similarly. */
+#define decode_frac(frac_value, cc, i)\
+ cc.paint.values[i] =\
+ penum->map[i].decode_base + (frac_value) * penum->map[i].decode_factor
+
+/*
+ * Declare the variable that holds the 12-bit unpacking procedure
+ * if 12-bit samples are supported.
+ */
+extern sample_unpack_proc((*sample_unpack_12_proc));
+
+/*
+ * Define the interface for routines used to render a (source) scan line.
+ * If the buffer is the original client's input data, it may be unaligned;
+ * otherwise, it will always be aligned.
+ *
+ * The image_render procedures work on fully expanded, complete rows. These
+ * take a height argument, which is an integer >= 0; they return a negative
+ * code, or the number of rows actually processed (which may be less than
+ * the height). height = 0 is a special call to indicate that there is no
+ * more input data; this is necessary because the last scan lines of the
+ * source data may not produce any output.
+ */
+#define irender_proc(proc)\
+ int proc(P6(gx_image_enum *penum, const byte *buffer, int data_x,\
+ uint w, int h, gx_device *dev))
+typedef irender_proc((*irender_proc_t));
+
+/*
+ * Define 'strategy' procedures for selecting imaging methods. Strategies
+ * are called in the order in which they are declared below, so each one may
+ * assume that all the previous ones failed. If a strategy succeeds, it may
+ * update the enumerator structure as well as returning the rendering
+ * procedure.
+ *
+ * Note that strategies are defined by procedure members of a structure, so
+ * that they may be omitted from configurations where they are not desired.
+ */
+#define image_strategy_proc(proc)\
+ irender_proc_t proc(P1(gx_image_enum *penum))
+typedef image_strategy_proc((*image_strategy_proc_t));
+typedef struct gx_image_strategies_s {
+ image_strategy_proc_t interpolate;
+ image_strategy_proc_t simple;
+ image_strategy_proc_t fracs;
+ image_strategy_proc_t mono;
+ image_strategy_proc_t color;
+} gx_image_strategies_t;
+extern gx_image_strategies_t image_strategies;
+
+/* Define the distinct postures of an image. */
+/* Each posture includes its reflected variant. */
+typedef enum {
+ image_portrait = 0, /* 0 or 180 degrees */
+ image_landscape, /* 90 or 270 degrees */
+ image_skewed /* any other transformation */
+} image_posture;
+
+/* Define an entry in the image color table. For single-source-plane */
+/* images, the table index is the sample value, and the key is not used; */
+/* for multiple-plane (color) images, the table index is a hash of the key, */
+/* which is the concatenation of the source pixel components. */
+/* "Clue" = Color LookUp Entry (by analogy with CLUT). */
+typedef struct gx_image_clue_s {
+ gx_device_color dev_color;
+ bits32 key;
+} gx_image_clue;
+
+/* Main state structure */
+
+#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_image_enum_s {
+ gx_image_enum_common;
+ /* We really want the map structure to be long-aligned, */
+ /* so we choose shorter types for some flags. */
+ /* Following are set at structure initialization */
+ byte bps; /* bits per sample: 1, 2, 4, 8, 12 */
+ byte unpack_bps; /* bps for computing unpack proc, */
+ /* set to 8 if no unpacking */
+ byte log2_xbytes; /* log2(bytes per expanded sample): */
+ /* 0 if bps <= 8, log2(sizeof(frac)) */
+ /* if bps > 8 */
+ byte spp; /* samples per pixel: 1, 3, or 4 */
+ /* (1, 2, 3, 4, or 5 if alpha is allowed) */
+ gs_image_alpha_t alpha; /* Alpha from image structure */
+ /*byte num_planes; *//* spp if colors are separated, */
+ /* 1 otherwise (in common part) */
+ byte spread; /* num_planes << log2_xbytes */
+ byte masked; /* 0 = [color]image, 1 = imagemask */
+ byte interpolate; /* true if Interpolate requested */
+ gs_matrix matrix; /* image space -> device space */
+ struct r_ {
+ int x, y, w, h; /* subrectangle being rendered */
+ } rect;
+ gs_fixed_point x_extent, y_extent; /* extent of one row of rect */
+ sample_unpack_proc((*unpack));
+ irender_proc((*render));
+ const gs_imager_state *pis;
+ const gs_color_space *pcs; /* color space of image */
+ gs_memory_t *memory;
+ byte *buffer; /* for expanding samples to a */
+ /* byte or frac */
+ uint buffer_size;
+ byte *line; /* buffer for an output scan line */
+ uint line_size;
+ uint line_width; /* width of line in device pixels */
+ image_posture posture;
+ byte use_rop; /* true if CombineWithColor requested */
+ byte clip_image; /* mask, see below */
+ /* Either we are clipping to a rectangle, in which case */
+ /* the individual x/y flags may be set, or we are clipping */
+ /* to a general region, in which case only clip_region */
+ /* is set. */
+#define image_clip_xmin 1
+#define image_clip_xmax 2
+#define image_clip_ymin 4
+#define image_clip_ymax 8
+#define image_clip_region 0x10
+ byte slow_loop; /* true if must use slower loop */
+ /* (if needed) */
+ byte device_color; /* true if device color space and */
+ /* standard decoding */
+ gs_fixed_rect clip_outer; /* outer box of clip path */
+ gs_fixed_rect clip_inner; /* inner box of clip path */
+ gs_logical_operation_t log_op; /* logical operation */
+ fixed adjust; /* adjustment when rendering */
+ /* characters */
+ fixed dxx, dxy; /* fixed versions of matrix */
+ /* components (as needed) */
+ gx_device_clip *clip_dev; /* clipping device (if needed) */
+ gx_device_rop_texture *rop_dev; /* RasterOp device (if needed) */
+ stream_IScale_state *scaler; /* scale state for */
+ /* Interpolate (if needed) */
+ /* Following are updated dynamically */
+ int y; /* next source y */
+ gs_fixed_point cur, prev; /* device x, y of current & */
+ /* previous row */
+ struct dd_ {
+ gx_dda_fixed_point row; /* DDA for row origin, has been */
+ /* advanced when render proc called */
+ gx_dda_fixed_point pixel0; /* DDA for first pixel of row */
+ } dda;
+ int line_xy; /* x or y value at start of buffered line */
+ int xi_next; /* expected xci of next row */
+ /* (landscape only) */
+ gs_int_point xyi; /* integer origin of row */
+ /* (Interpolate only) */
+ int yci, hci; /* integer y & h of row (portrait) */
+ int xci, wci; /* integer x & w of row (landscape) */
+ /* The maps are set at initialization. We put them here */
+ /* so that the scalars will have smaller offsets. */
+ sample_map map[5]; /* 4 colors + alpha */
+ /* Entries 0 and 255 of the following are set at initialization */
+ /* for monochrome images; other entries are updated dynamically. */
+ gx_image_clue clues[256];
+#define icolor0 clues[0].dev_color
+#define icolor1 clues[255].dev_color
+};
+
+/* Enumerate the pointers in an image enumerator. */
+#define gx_image_enum_do_ptrs(m)\
+ m(0,pis) m(1,pcs) m(2,dev) m(3,buffer) m(4,line)\
+ m(5,clip_dev) m(6,rop_dev) m(7,scaler)
+#define gx_image_enum_num_ptrs 8
+#define private_st_gx_image_enum() /* in gsimage.c */\
+ gs_private_st_composite(st_gx_image_enum, gx_image_enum, "gx_image_enum",\
+ image_enum_enum_ptrs, image_enum_reloc_ptrs)
+
+/* Compare two device colors for equality. */
+/* We can special-case this for speed later if we care. */
+#define dev_color_eq(devc1, devc2)\
+ gx_device_color_equal(&(devc1), &(devc2))
+
+#endif /* gximage_INCLUDED */
diff --git a/pstoraster/gximage3.c b/pstoraster/gximage3.c
new file mode 100644
index 000000000..38e348177
--- /dev/null
+++ b/pstoraster/gximage3.c
@@ -0,0 +1,429 @@
+/* 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$ */
+/* ImageType 3 image implementation */
+#include "math_.h" /* for ceil, floor */
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsbitops.h"
+#include "gscspace.h"
+#include "gsiparm3.h"
+#include "gsstruct.h"
+#include "gxdevice.h"
+#include "gxdevmem.h"
+#include "gxclipm.h"
+#include "gxiparam.h"
+#include "gxistate.h"
+
+/* Forward references */
+private dev_proc_begin_typed_image(gx_begin_image3);
+private image_enum_proc_plane_data(gx_image3_plane_data);
+private image_enum_proc_end_image(gx_image3_end_image);
+
+/* GC descriptor */
+extern_st(st_gs_pixel_image);
+public_st_gs_image3();
+
+/* Define the image type for ImageType 3 images. */
+private const gx_image_type_t image3_type = {
+ gx_begin_image3, gx_data_image_source_size, 3
+};
+private const gx_image_enum_procs_t image3_enum_procs = {
+ gx_image3_plane_data, gx_image3_end_image
+};
+
+/* Initialize an ImageType 3 image. */
+void
+gs_image3_t_init(gs_image3_t * pim, const gs_color_space * color_space,
+ gs_image3_interleave_type_t interleave_type)
+{
+ gs_pixel_image_t_init((gs_pixel_image_t *) pim, color_space);
+ pim->type = &image3_type;
+ pim->InterleaveType = interleave_type;
+ gs_data_image_t_init(&pim->MaskDict, -1);
+}
+
+/*
+ * We implement ImageType 3 images by interposing a mask clipper in
+ * front of an ordinary ImageType 1 image. Note that we build up the
+ * mask row-by-row as we are processing the image.
+ */
+typedef struct gx_image3_enum_s {
+ gx_image_enum_common;
+ gx_device_memory *mdev;
+ gx_device_mask_clip *pcdev;
+ gx_image_enum_common_t *pixel_info;
+ gx_image_enum_common_t *mask_info;
+ gs_image3_interleave_type_t InterleaveType;
+ int num_components; /* (not counting mask) */
+ int bpc; /* BitsPerComponent */
+ gs_memory_t *memory;
+ int mask_width;
+ int pixel_width;
+ byte *pixel_data; /* (if chunky) */
+ byte *mask_data; /* (if chunky) */
+ int y; /* counts up to max(p'height, m'height) */
+ int pixel_height;
+ int mask_height;
+} gx_image3_enum_t;
+
+gs_private_st_ptrs6(st_image3_enum, gx_image3_enum_t, "gx_image3_enum_t",
+ image3_enum_enum_ptrs, image3_enum_reloc_ptrs,
+ mdev, pcdev, pixel_info, mask_info, pixel_data, mask_data);
+
+/* Begin an ImageType 3 image. */
+private int
+gx_begin_image3(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 * mem, gx_image_enum_common_t ** pinfo)
+{
+ const gs_image3_t *pim = (const gs_image3_t *)pic;
+ gx_image3_enum_t *penum;
+ gx_device_memory *mdev;
+ gx_device_mask_clip *pcdev;
+ gs_image_t i_pixel, i_mask;
+ gs_matrix mat;
+ gs_rect mrect;
+ gs_int_point origin;
+ int code;
+
+ /* Validate the parameters. */
+ if (pim->Height <= 0 || pim->MaskDict.Height <= 0)
+ return_error(gs_error_rangecheck);
+ switch (pim->InterleaveType) {
+ default:
+ return_error(gs_error_rangecheck);
+ case interleave_chunky:
+ if (pim->MaskDict.Width != pim->Width ||
+ pim->MaskDict.Height != pim->Height ||
+ pim->MaskDict.BitsPerComponent != pim->BitsPerComponent ||
+ pim->format != gs_image_format_chunky
+ )
+ return_error(gs_error_rangecheck);
+ break;
+ case interleave_scan_lines:
+ if (pim->MaskDict.Height % pim->Height != 0 &&
+ pim->Height % pim->MaskDict.Height != 0
+ )
+ return_error(gs_error_rangecheck);
+ /* falls through */
+ case interleave_separate_source:
+ if (pim->MaskDict.BitsPerComponent != 1)
+ return_error(gs_error_rangecheck);
+ }
+ /****** CHECK FOR COMPATIBLE ImageMatrix ******/
+ penum = gs_alloc_struct(mem, gx_image3_enum_t, &st_image3_enum,
+ "gx_begin_image3");
+ if (penum == 0)
+ return_error(gs_error_VMerror);
+ penum->num_components =
+ gs_color_space_num_components(pim->ColorSpace);
+ gx_image_enum_common_init((gx_image_enum_common_t *) penum,
+ pic, &image3_enum_procs, dev,
+ pim->BitsPerComponent,
+ 1 + penum->num_components,
+ pim->format);
+ if (prect)
+ penum->pixel_width = prect->q.x - prect->p.x,
+ penum->y = prect->p.y,
+ penum->pixel_height = prect->q.y - prect->p.y;
+ else
+ penum->pixel_width = pim->Width,
+ penum->y = 0,
+ penum->pixel_height = pim->Height;
+ penum->mask_width = pim->MaskDict.Width;
+ penum->mask_height = pim->MaskDict.Height;
+ penum->mdev = mdev =
+ gs_alloc_struct(mem, gx_device_memory, &st_device_memory,
+ "gx_begin_image3(mdev)");
+ if (mdev == 0)
+ goto out1;
+ penum->pcdev = pcdev =
+ gs_alloc_struct(mem, gx_device_mask_clip, &st_device_mask_clip,
+ "gx_begin_image3(pcdev)");
+ if (pcdev == 0)
+ goto out2;
+ penum->mask_info = 0;
+ penum->pixel_info = 0;
+ penum->mask_data = 0;
+ penum->pixel_data = 0;
+ if (pim->InterleaveType == interleave_chunky) {
+ /* Allocate row buffers for the mask and pixel data. */
+ penum->pixel_data =
+ gs_alloc_bytes(mem,
+ (penum->pixel_width * pim->BitsPerComponent *
+ penum->num_components + 7) >> 3,
+ "gx_begin_image3(pixel_data)");
+ penum->mask_data =
+ gs_alloc_bytes(mem, (penum->mask_width + 7) >> 3,
+ "gx_begin_image3(mask_data)");
+ if (penum->pixel_data == 0 || penum->mask_data == 0)
+ goto out3;
+ }
+ penum->InterleaveType = pim->InterleaveType;
+ penum->bpc = pim->BitsPerComponent;
+ penum->memory = mem;
+ gs_make_mem_mono_device(mdev, mem, NULL);
+ mdev->bitmap_memory = mem;
+ mrect.p.x = mrect.p.y = 0;
+ mrect.q.x = pim->MaskDict.Width;
+ mrect.q.y = pim->MaskDict.Height;
+ if (pmat == 0)
+ pmat = &ctm_only(pis);
+ if ((code = gs_matrix_invert(&pim->MaskDict.ImageMatrix, &mat)) < 0 ||
+ (code = gs_matrix_multiply(&mat, pmat, &mat)) < 0 ||
+ (code = gs_bbox_transform(&mrect, &mat, &mrect)) < 0
+ )
+ return code;
+ origin.x = floor(mrect.p.x);
+ mdev->width = (int)ceil(mrect.q.x) - origin.x;
+ origin.y = floor(mrect.p.y);
+ mdev->height = (int)ceil(mrect.q.y) - origin.y;
+ gx_device_fill_in_procs((gx_device *) mdev);
+ code = (*dev_proc(mdev, open_device)) ((gx_device *) mdev);
+ if (code < 0)
+ goto out3;
+ mdev->is_open = true;
+ {
+ gx_strip_bitmap bits; /* only gx_bitmap */
+
+ bits.data = mdev->base;
+ bits.raster = mdev->raster;
+ bits.size.x = mdev->width;
+ bits.size.y = mdev->height;
+ bits.id = gx_no_bitmap_id;
+ code = gx_mask_clip_initialize(pcdev, &gs_mask_clip_device,
+ (const gx_bitmap *)&bits, dev,
+ origin.x, origin.y);
+ if (code < 0)
+ goto out4;
+ pcdev->tiles = bits;
+ }
+ gs_image_t_init_mask(&i_mask, false);
+ i_mask.adjust = false;
+ {
+ const gx_image_type_t *type1 = i_mask.type;
+
+ *(gs_data_image_t *)&i_mask = pim->MaskDict;
+ i_mask.type = type1;
+ }
+ {
+ gx_drawing_color dcolor;
+ gs_matrix m_mat;
+
+ (*dev_proc(mdev, fill_rectangle))
+ ((gx_device *) mdev, 0, 0, mdev->width, mdev->height,
+ (gx_color_index) 0);
+ color_set_pure(&dcolor, 1);
+ /*
+ * Adjust the translation for rendering the mask to include a
+ * negative translation by origin.{x,y} in device space.
+ */
+ m_mat = *pmat;
+ m_mat.tx -= origin.x;
+ m_mat.ty -= origin.y;
+ /*
+ * Note that pis = NULL here, since we don't want to have to
+ * create another imager state with default log_op, etc.
+ */
+ code = gx_device_begin_typed_image((gx_device *)mdev, NULL, &m_mat,
+ (const gs_image_common_t *)&i_mask,
+ prect, &dcolor, NULL, mem,
+ &penum->mask_info);
+ if (code < 0)
+ goto out5;
+ }
+ gs_image_t_init(&i_pixel, pim->ColorSpace);
+ {
+ const gx_image_type_t *type1 = i_pixel.type;
+
+ *(gs_pixel_image_t *)&i_pixel = *(const gs_pixel_image_t *)pim;
+ i_pixel.type = type1;
+ }
+ code = gx_device_begin_typed_image((gx_device *) pcdev, pis, pmat,
+ (const gs_image_common_t *)&i_pixel,
+ prect, pdcolor, pcpath, mem, &penum->pixel_info);
+ if (code < 0)
+ goto out6;
+ /*
+ * Compute num_planes and plane_depths from the values in the
+ * enumerators for the mask and the image data.
+ */
+ if (pim->InterleaveType == interleave_chunky) {
+ /* Add the mask data to the depth of the image data. */
+ penum->num_planes = 1;
+ penum->plane_depths[0] =
+ penum->pixel_info->plane_depths[0] *
+ (penum->num_components + 1) / penum->num_components;
+ } else {
+ /* Insert the mask data as a separate plane before the image data. */
+ penum->num_planes = penum->pixel_info->num_planes + 1;
+ penum->plane_depths[0] = 1;
+ memcpy(&penum->plane_depths[1], &penum->pixel_info->plane_depths[0],
+ (penum->num_planes - 1) * sizeof(penum->plane_depths[0]));
+ }
+ *pinfo = (gx_image_enum_common_t *) penum;
+ return 0;
+ out6:gx_image_end(penum->mask_info, false);
+ out5:gs_closedevice((gx_device *) pcdev);
+ out4:gs_closedevice((gx_device *) mdev);
+ out3:gs_free_object(mem, pcdev, "gx_begin_image3(pcdev)");
+ out2:gs_free_object(mem, mdev, "gx_begin_image3(mdev)");
+ out1:gs_free_object(mem, penum->mask_data, "gx_begin_image3(mask_data)");
+ gs_free_object(mem, penum->pixel_data, "gx_begin_image3(pixel_data)");
+ gs_free_object(mem, penum, "gx_begin_image3");
+ code = gs_note_error(gs_error_VMerror);
+ out:return code;
+}
+
+/* Process the next piece of an ImageType 3 image. */
+private int
+gx_image3_plane_data(gx_device * dev,
+ gx_image_enum_common_t * info, const gx_image_plane_t * planes, int height)
+{
+ gx_image3_enum_t *penum = (gx_image3_enum_t *) info;
+ int pixel_height = penum->pixel_height;
+ int mask_height = penum->mask_height;
+ int image_height = max(pixel_height, mask_height);
+ int h = min(height, image_height - penum->y);
+ const gx_image_plane_t *pixel_planes;
+ gx_image_plane_t pixel_plane, mask_plane;
+
+ switch (penum->InterleaveType) {
+ case interleave_chunky:
+ if (h <= 0)
+ return 0;
+ if (h > 1) {
+ /* Do the operation one row at a time. */
+ mask_plane = planes[0];
+ do {
+ int code = gx_image3_plane_data(dev, info, &mask_plane, 1);
+
+ if (code < 0)
+ return code;
+ mask_plane.data += mask_plane.raster;
+ } while (--h);
+ return 0;
+ } {
+ /* Pull apart the source data and the mask data. */
+ int bpc = penum->bpc;
+ int num_components = penum->num_components;
+ int width = penum->pixel_width;
+
+ /* We do this in the simplest (not fastest) way for now. */
+ uint bit_x = bpc * (num_components + 1) * planes[0].data_x;
+
+ sample_load_declare_setup(sptr, sbit,
+ planes[0].data + (bit_x >> 3),
+ bit_x & 7, bpc);
+ sample_store_declare_setup(mptr, mbit, mbbyte, penum->mask_data,
+ 0, 1);
+ sample_store_declare_setup(pptr, pbit, pbbyte, penum->pixel_data,
+ 0, bpc);
+ int x;
+
+ mask_plane.data = mptr;
+ mask_plane.data_x = 0;
+ /* raster doesn't matter */
+ pixel_plane.data = pptr;
+ pixel_plane.data_x = 0;
+ /* raster doesn't matter */
+ pixel_planes = &pixel_plane;
+ for (x = 0; x < width; ++x) {
+ uint value;
+ int i;
+
+ sample_load_next12(value, sptr, sbit, bpc);
+ sample_store_next12(value != 0, mptr, mbit, 1, mbbyte);
+ for (i = 0; i < num_components; ++i) {
+ sample_load_next12(value, sptr, sbit, bpc);
+ sample_store_next12(value, pptr, pbit, bpc, pbbyte);
+ }
+ }
+ sample_store_flush(mptr, mbit, 1, mbbyte);
+ sample_store_flush(pptr, pbit, bpc, pbbyte);
+ }
+ break;
+ case interleave_scan_lines:
+ case interleave_separate_source:
+ mask_plane = planes[0];
+ pixel_planes = planes + 1;
+ break;
+ default: /* not possible */
+ return_error(gs_error_rangecheck);
+ }
+ /*
+ * Process the mask data first, so it will set up the mask
+ * device for clipping the pixel data.
+ */
+ if (mask_plane.data) {
+ int code = gx_image_plane_data(penum->mask_info, &mask_plane, h);
+
+ if (code < 0)
+ return code;
+ }
+ if (pixel_planes[0].data) {
+ int code;
+
+ /*
+ * If necessary, flush any buffered mask data to the mask clipping
+ * device.
+ */
+ if (penum->mask_info->procs->flush)
+ (*penum->mask_info->procs->flush)(penum->mask_info);
+ code = gx_image_plane_data(penum->pixel_info, pixel_planes, h);
+ if (code < 0)
+ return code;
+ penum->y += h;
+ }
+ return penum->y >= image_height;
+}
+
+/* Clean up after processing an ImageType 3 image. */
+private int
+gx_image3_end_image(gx_device * dev, gx_image_enum_common_t * info,
+ bool draw_last)
+{
+ gx_image3_enum_t *penum = (gx_image3_enum_t *) info;
+ gs_memory_t *mem = penum->memory;
+ gx_device_memory *mdev = penum->mdev;
+ int mcode = gx_image_end(penum->mask_info, draw_last);
+ gx_device_mask_clip *pcdev = penum->pcdev;
+ int pcode = gx_image_end(penum->pixel_info, draw_last);
+
+ gs_closedevice((gx_device *) pcdev);
+ gs_closedevice((gx_device *) mdev);
+ gs_free_object(mem, penum->mask_data,
+ "gx_image3_end_image(mask_data)");
+ gs_free_object(mem, penum->pixel_data,
+ "gx_image3_end_image(pixel_data)");
+ gs_free_object(mem, pcdev, "gx_image3_end_image(pcdev)");
+ gs_free_object(mem, mdev, "gx_image3_end_image(mdev)");
+ gs_free_object(mem, penum, "gx_image3_end_image");
+ return (pcode < 0 ? pcode : mcode);
+}
diff --git a/pstoraster/gximage4.c b/pstoraster/gximage4.c
new file mode 100644
index 000000000..14dee709e
--- /dev/null
+++ b/pstoraster/gximage4.c
@@ -0,0 +1,297 @@
+/* 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$ */
+/* ImageType 4 image implementation */
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gscspace.h"
+#include "gsiparm3.h"
+#include "gsiparm4.h"
+#include "gxiparam.h"
+
+/* Forward references */
+private dev_proc_begin_typed_image(gx_begin_image4);
+private image_enum_proc_plane_data(gx_image4_plane_data);
+private image_enum_proc_end_image(gx_image4_end_image);
+
+/* Define the image type for ImageType 4 images. */
+private const gx_image_type_t image4_type = {
+ gx_begin_image4, gx_data_image_source_size, 4
+};
+private const gx_image_enum_procs_t image4_enum_procs = {
+ gx_image4_plane_data, gx_image4_end_image
+};
+
+/* Initialize an ImageType 4 image. */
+void
+gs_image4_t_init(gs_image4_t * pim, const gs_color_space * color_space)
+{
+ gs_pixel_image_t_init((gs_pixel_image_t *) pim, color_space);
+ pim->type = &image4_type;
+ pim->MaskColor_is_range = false;
+}
+
+/*
+ * We implement ImageType 4 using ImageType 3 (or, if the image is known
+ * to be completely opaque, ImageType 1).
+ */
+typedef struct gx_image4_enum_s {
+ gx_image_enum_common;
+ int num_components;
+ int bpc; /* BitsPerComponent */
+ uint values[gs_image_max_components * 2];
+ gs_memory_t *memory;
+ gx_image_enum_common_t *info; /* info for image3 or image1 */
+ byte *mask; /* one scan line of mask data, 0 if image1 */
+ uint mask_size;
+ int width;
+ int y;
+ int height;
+} gx_image4_enum_t;
+
+gs_private_st_ptrs2(st_image4_enum, gx_image4_enum_t, "gx_image4_enum_t",
+ image4_enum_enum_ptrs, image4_enum_reloc_ptrs, info, mask);
+
+/* Begin an ImageType 4 image. */
+private int
+gx_begin_image4(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 * mem, gx_image_enum_common_t ** pinfo)
+{
+ const gs_image4_t *pim = (const gs_image4_t *)pic;
+ int num_components = gs_color_space_num_components(pim->ColorSpace);
+ bool opaque = false;
+ gx_image4_enum_t *penum;
+ uint mask_size = (pim->Width + 7) >> 3;
+ byte *mask = 0;
+ int code;
+
+ penum = gs_alloc_struct(mem, gx_image4_enum_t, &st_image4_enum,
+ "gx_begin_image4");
+ if (penum == 0)
+ return_error(gs_error_VMerror);
+ gx_image_enum_common_init((gx_image_enum_common_t *) penum,
+ pic, &image4_enum_procs, dev,
+ pim->BitsPerComponent,
+ num_components, pim->format);
+ penum->memory = mem;
+ {
+ uint max_value = (1 << pim->BitsPerComponent) - 1;
+ int i;
+
+ for (i = 0; i < num_components * 2; i += 2) {
+ uint c0, c1;
+
+ if (pim->MaskColor_is_range)
+ c0 = pim->MaskColor[i], c1 = pim->MaskColor[i + 1];
+ else
+ c0 = c1 = pim->MaskColor[i >> 1];
+
+ if (c1 > max_value)
+ c1 = max_value;
+ if (c0 > c1) {
+ opaque = true;
+ break;
+ }
+ penum->values[i] = c0;
+ penum->values[i + 1] = c1;
+ }
+ }
+ if (opaque) {
+ /*
+ * This image doesn't need masking at all, since at least one of
+ * the transparency keys can never be matched. Process it as an
+ * ImageType 1 image.
+ */
+ const gx_image_type_t *type;
+ gs_image1_t image1;
+
+ gs_image_t_init(&image1, pim->ColorSpace);
+ type = image1.type;
+ *(gs_pixel_image_t *)&image1 =
+ *(const gs_pixel_image_t *)pim;
+ image1.type = type;
+ penum->mask = 0; /* indicates opaque image */
+ code = gx_device_begin_typed_image(dev, pis, pmat,
+ (gs_image_common_t *)&image1,
+ prect, pdcolor, pcpath, mem, &penum->info);
+ } else if ((mask = gs_alloc_bytes(mem, mask_size,
+ "gx_begin_image4(mask)")) == 0
+ ) {
+ code = gs_note_error(gs_error_VMerror);
+ } else {
+ gs_image3_t image3;
+
+ penum->num_components = num_components;
+ gs_image3_t_init(&image3, pim->ColorSpace, interleave_scan_lines);
+ {
+ const gx_image_type_t *type = image3.type;
+
+ *(gs_pixel_image_t *)&image3 =
+ *(const gs_pixel_image_t *)pim;
+ image3.type = type;
+ }
+ *(gs_data_image_t *)&image3.MaskDict =
+ *(const gs_data_image_t *)pim;
+ image3.MaskDict.BitsPerComponent = 1;
+ /*
+ * The interpretation of Decode is backwards from the sensible
+ * one, but it's an Adobe convention that is now too hard to
+ * change in the code.
+ */
+ image3.MaskDict.Decode[0] = 1;
+ image3.MaskDict.Decode[1] = 0;
+ image3.MaskDict.Interpolate = false;
+ penum->bpc = pim->BitsPerComponent;
+ penum->mask = mask;
+ penum->mask_size = mask_size;
+ if (prect)
+ penum->width = prect->q.x - prect->p.x,
+ penum->y = prect->p.y, penum->height = prect->q.y - prect->p.y;
+ else
+ penum->width = pim->Width,
+ penum->y = 0, penum->height = pim->Height;
+ code = gx_device_begin_typed_image(dev, pis, pmat,
+ (const gs_image_common_t *)&image3,
+ prect, pdcolor, pcpath, mem, &penum->info);
+ }
+ if (code < 0) {
+ gs_free_object(mem, mask, "gx_begin_image4(mask)");
+ gs_free_object(mem, penum, "gx_begin_image4");
+ } else
+ *pinfo = (gx_image_enum_common_t *) penum;
+ return code;
+}
+
+/* Process the next piece of an ImageType 4 image. */
+/* We disregard the depth in the image planes: BitsPerComponent prevails. */
+private int
+gx_image4_plane_data(gx_device * dev,
+ gx_image_enum_common_t * info, const gx_image_plane_t * planes, int height)
+{
+ gx_image4_enum_t *penum = (gx_image4_enum_t *) info;
+ int num_planes = penum->num_planes;
+ int bpc = penum->bpc;
+ int spp = (num_planes > 1 ? 1 : penum->num_components);
+ byte *mask = penum->mask;
+ uint mask_size = (penum->width + 7) >> 3;
+ gx_image_plane_t sources[gs_image_max_components];
+ int h = min(height, penum->height - penum->y);
+
+ if (penum->mask == 0) /* opaque image */
+ return gx_image_plane_data(penum->info, planes, height);
+ if (mask_size > penum->mask_size) {
+ mask = gs_resize_object(penum->memory, mask, mask_size,
+ "gx_image4_data(resize mask)");
+ if (mask == 0)
+ return_error(gs_error_VMerror);
+ penum->mask = mask;
+ penum->mask_size = mask_size;
+ }
+ sources[0].data = mask;
+ sources[0].data_x = 0;
+ sources[0].raster = mask_size;
+ memcpy(sources + 1, planes, num_planes * sizeof(planes[0]));
+ for (; h > 0; ++(penum->y), --h) {
+ int pi;
+ int code;
+
+ memset(mask, 0, (penum->width + 7) >> 3);
+ for (pi = 0; pi < num_planes; ++pi) {
+ byte *mptr = mask;
+ byte mbit = 0x80;
+ uint sx_bit = sources[pi + 1].data_x * bpc;
+ const byte *sptr = sources[pi + 1].data + (sx_bit >> 3);
+ uint sx_shift = sx_bit & 7;
+ int ix;
+
+#define advance_sx()\
+ BEGIN\
+ if ( (sx_shift += bpc) >= 8 ) {\
+ sptr += sx_shift >> 3;\
+ sx_shift &= 7;\
+ }\
+ END
+
+ for (ix = 0; ix < penum->width; ++ix) {
+ int ci;
+
+ for (ci = 0; ci < spp; ++ci) {
+ /*
+ * The following odd-looking computation is, in fact,
+ * correct both for chunky (pi = 0) and planar (ci = 0)
+ * data formats.
+ */
+ int vi = (ci + pi) * 2;
+ uint sample;
+
+ if (bpc <= 8) {
+ sample = (*sptr >> (8 - sx_shift - bpc)) &
+ ((1 << bpc) - 1);
+ } else {
+ /* bpc == 12 */
+ if (sx_shift /* == 4 */ )
+ sample = ((*sptr & 0xf) << 8) + sptr[1];
+ else
+ sample = (*sptr << 8) + (sptr[1] >> 4);
+ }
+ if (sample < penum->values[vi] ||
+ sample > penum->values[vi + 1]
+ )
+ *mptr |= mbit;
+ advance_sx();
+ }
+ if ((mbit >>= 1) == 0)
+ mbit = 0x80, ++mptr;
+ }
+ }
+ code = gx_image_plane_data(penum->info, sources, 1);
+ if (code < 0)
+ return code;
+ for (pi = 1; pi <= num_planes; ++pi)
+ sources[pi].data += sources[pi].raster;
+ }
+#undef advance_sx
+ return penum->y >= penum->height;
+}
+
+/* Clean up after processing an ImageType 4 image. */
+private int
+gx_image4_end_image(gx_device * dev, gx_image_enum_common_t * info,
+ bool draw_last)
+{
+ gx_image4_enum_t *penum = (gx_image4_enum_t *) info;
+ gs_memory_t *mem = penum->memory;
+
+ /* Finish processing the ImageType 3 (or 1) image. */
+ int code = gx_image_end(penum->info, draw_last);
+
+ gs_free_object(mem, penum->mask, "gx_image4_end_image(mask)");
+ gs_free_object(mem, penum, "gx_image4_end_image");
+ return code;
+}
diff --git a/pstoraster/gximono.c b/pstoraster/gximono.c
new file mode 100644
index 000000000..13eb57e50
--- /dev/null
+++ b/pstoraster/gximono.c
@@ -0,0 +1,586 @@
+/* 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$ */
+/* General mono-component image rendering */
+#include "gx.h"
+#include "memory_.h"
+#include "gpcheck.h"
+#include "gserrors.h"
+#include "gxfixed.h"
+#include "gxarith.h"
+#include "gxmatrix.h"
+#include "gsccolor.h"
+#include "gspaint.h"
+#include "gsutil.h"
+#include "gxdevice.h"
+#include "gxcmap.h"
+#include "gxdcolor.h"
+#include "gxistate.h"
+#include "gzpath.h"
+#include "gxdevmem.h"
+#include "gdevmem.h" /* for mem_mono_device */
+#include "gxcpath.h"
+#include "gximage.h"
+#include "gzht.h"
+
+/* ------ Strategy procedure ------ */
+
+/* We can bypass X clipping for portrait mono-component images. */
+private irender_proc(image_render_mono);
+private irender_proc_t
+image_strategy_mono(gx_image_enum * penum)
+{
+ /*
+ * Use the slow loop for imagemask with a halftone,
+ * or for a non-default logical operation.
+ */
+ penum->slow_loop =
+ (penum->masked && !color_is_pure(&penum->icolor1)) ||
+ penum->use_rop;
+ if (penum->spp == 1) {
+ if (!(penum->slow_loop || penum->posture != image_portrait))
+ penum->clip_image &= ~(image_clip_xmin | image_clip_xmax);
+ if_debug0('b', "[b]render=mono\n");
+ /* Precompute values needed for rasterizing. */
+ penum->dxx =
+ float2fixed(penum->matrix.xx + fixed2float(fixed_epsilon) / 2);
+ return image_render_mono;
+ }
+ return 0;
+}
+
+void
+gs_gximono_init(gs_memory_t * mem)
+{
+ image_strategies.mono = image_strategy_mono;
+}
+
+/* ------ Rendering procedure ------ */
+
+/* Provide a fake map_gray procedure for the DevicePixel color space. */
+private void
+no_map_gray(frac pixel, gx_device_color * pdc, const gs_imager_state * pis,
+ gx_device * dev, gs_color_select_t select)
+{
+ color_set_pure(pdc, frac2byte(pixel));
+}
+
+/*
+ * Rendering procedure for general mono-component images, dealing with
+ * multiple bit-per-sample images, general transformations, and arbitrary
+ * single-component color spaces (DeviceGray, DevicePixel, CIEBasedA,
+ * Separation, Indexed). This procedure handles a single scan line.
+ */
+private int
+image_render_mono(gx_image_enum * penum, const byte * buffer, int data_x,
+ uint w, int h, gx_device * dev)
+{
+ const gs_imager_state *pis = penum->pis;
+ gs_logical_operation_t lop = penum->log_op;
+ const bool masked = penum->masked;
+ const gs_color_space *pcs; /* only set for non-masks */
+ cmap_proc_gray((*map_gray)); /* ditto */
+ cs_proc_remap_color((*remap_color)); /* ditto */
+ gs_client_color cc;
+ gx_device_color *pdevc = &penum->icolor1; /* color for masking */
+ /*
+ * Make sure the cache setup matches the graphics state. Also determine
+ * whether all tiles fit in the cache. We may bypass the latter check
+ * for masked images with a pure color.
+ */
+ bool tiles_fit = (pis ? gx_check_tile_cache(pis) : false);
+/*
+ * Free variables of IMAGE_SET_GRAY:
+ * Read: penum, pis, dev, tiles_fit
+ * Set: pdevc, code, cc
+ */
+#define IMAGE_SET_GRAY(sample_value)\
+ BEGIN\
+ pdevc = &penum->clues[sample_value].dev_color;\
+ if (!color_is_set(pdevc)) {\
+ if (penum->device_color)\
+ (*map_gray)(byte2frac(sample_value), pdevc, pis, dev, gs_color_select_source);\
+ else {\
+ decode_sample(sample_value, cc, 0);\
+ (*remap_color)(&cc, pcs, pdevc, pis, dev, gs_color_select_source);\
+ }\
+ } else if (!color_is_pure(pdevc)) {\
+ if (!tiles_fit) {\
+ code = gx_color_load_select(pdevc, pis, dev, gs_color_select_source);\
+ if ( code < 0 ) return code;\
+ }\
+ }\
+ END
+ gx_dda_fixed_point next; /* (y not used in fast loop) */
+ gx_dda_step_fixed dxx2, dxx3, dxx4; /* (not used in all loops) */
+ register const byte *psrc = buffer + data_x;
+ const byte *endp = psrc + w;
+ const byte *stop = endp;
+ fixed xrun; /* x at start of run */
+ register byte run; /* run value */
+ int htrun = (masked ? 255 : -2); /* halftone run value */
+ int code = 0;
+
+ if (h == 0)
+ return 0;
+ next = penum->dda.pixel0;
+ xrun = dda_current(next.x);
+ if (!masked) {
+ pcs = penum->pcs; /* (may not be set for masks) */
+ if (penum->device_color)
+ map_gray =
+ (gs_color_space_get_index(pcs) ==
+ gs_color_space_index_DeviceGray ?
+ gx_device_cmap_procs(dev)->map_gray :
+ no_map_gray /*DevicePixel */ );
+ else
+ remap_color = pcs->type->remap_color;
+ }
+ run = *psrc;
+ /* Find the last transition in the input. */
+ {
+ byte last = stop[-1];
+
+ while (stop > psrc && stop[-1] == last)
+ --stop;
+ }
+ if (penum->slow_loop || penum->posture != image_portrait) {
+
+ /**************************************************************
+ * Slow case (skewed, rotated, or imagemask with a halftone). *
+ **************************************************************/
+
+ fixed yrun;
+ const fixed pdyx = dda_current(penum->dda.row.x) - penum->cur.x;
+ const fixed pdyy = dda_current(penum->dda.row.y) - penum->cur.y;
+ dev_proc_fill_parallelogram((*fill_pgram)) =
+ dev_proc(dev, fill_parallelogram);
+
+#define xl dda_current(next.x)
+#define ytf dda_current(next.y)
+ yrun = ytf;
+ if (masked) {
+
+ /**********************
+ * Slow case, masked. *
+ **********************/
+
+ pdevc = &penum->icolor1;
+ code = gx_color_load(pdevc, pis, dev);
+ if (code < 0)
+ return code;
+ if (stop <= psrc)
+ goto last;
+ if (penum->posture == image_portrait) {
+
+ /********************************
+ * Slow case, masked, portrait. *
+ ********************************/
+
+ /*
+ * We don't have to worry about the Y DDA, and the fill
+ * regions are rectangles. Calculate multiples of the DDA
+ * step.
+ */
+ fixed ax =
+ (penum->matrix.xx < 0 ? -penum->adjust : penum->adjust);
+ fixed ay =
+ (pdyy < 0 ? -penum->adjust : penum->adjust);
+ fixed dyy = pdyy + (ay << 1);
+
+ yrun -= ay;
+ dda_translate(next.x, -ax);
+ ax <<= 1;
+ dxx2 = next.x.step;
+ dda_step_add(dxx2, next.x.step);
+ dxx3 = dxx2;
+ dda_step_add(dxx3, next.x.step);
+ dxx4 = dxx3;
+ dda_step_add(dxx4, next.x.step);
+ for (;;) { /* Skip a run of zeros. */
+ while (!psrc[0])
+ if (!psrc[1]) {
+ if (!psrc[2]) {
+ if (!psrc[3]) {
+ psrc += 4;
+ dda_state_next(next.x.state, dxx4);
+ continue;
+ }
+ psrc += 3;
+ dda_state_next(next.x.state, dxx3);
+ break;
+ }
+ psrc += 2;
+ dda_state_next(next.x.state, dxx2);
+ break;
+ } else {
+ ++psrc;
+ dda_next(next.x);
+ break;
+ }
+ xrun = xl;
+ if (psrc >= stop)
+ break;
+ for (; *psrc; ++psrc)
+ dda_next(next.x);
+ code = (*fill_pgram)(dev, xrun, yrun,
+ xl - xrun + ax, fixed_0, fixed_0, dyy,
+ pdevc, lop);
+ if (code < 0)
+ return code;
+ if (psrc >= stop)
+ break;
+ }
+
+ } else if (penum->posture == image_landscape) {
+
+ /*********************************
+ * Slow case, masked, landscape. *
+ *********************************/
+
+ /*
+ * We don't have to worry about the X DDA. However, we do
+ * have to take adjustment into account. We don't bother to
+ * optimize this as heavily as the portrait case.
+ */
+ fixed ax =
+ (pdyx < 0 ? -penum->adjust : penum->adjust);
+ fixed dyx = pdyx + (ax << 1);
+ fixed ay =
+ (penum->matrix.xy < 0 ? -penum->adjust : penum->adjust);
+
+ xrun -= ax;
+ dda_translate(next.y, -ay);
+ ay <<= 1;
+ for (;;) {
+ for (; !*psrc; ++psrc)
+ dda_next(next.y);
+ yrun = ytf;
+ if (psrc >= stop)
+ break;
+ for (; *psrc; ++psrc)
+ dda_next(next.y);
+ code = (*fill_pgram)(dev, xrun, yrun, fixed_0,
+ ytf - yrun + ay, dyx, fixed_0,
+ pdevc, lop);
+ if (code < 0)
+ return code;
+ if (psrc >= stop)
+ break;
+ }
+
+ } else {
+
+ /**************************************
+ * Slow case, masked, not orthogonal. *
+ **************************************/
+
+ for (;;) {
+ for (; !*psrc; ++psrc) {
+ dda_next(next.x);
+ dda_next(next.y);
+ }
+ yrun = ytf;
+ xrun = xl;
+ if (psrc >= stop)
+ break;
+ for (; *psrc; ++psrc) {
+ dda_next(next.x);
+ dda_next(next.y);
+ }
+ code = (*fill_pgram)(dev, xrun, yrun, xl - xrun,
+ ytf - yrun, pdyx, pdyy, pdevc, lop);
+ if (code < 0)
+ return code;
+ if (psrc >= stop)
+ break;
+ }
+
+ }
+
+ } else if (penum->posture == image_portrait ||
+ penum->posture == image_landscape
+ ) {
+
+ /**************************************
+ * Slow case, not masked, orthogonal. *
+ **************************************/
+
+ /* In this case, we can fill runs quickly. */
+ /****** DOESN'T DO ADJUSTMENT ******/
+ if (stop <= psrc)
+ goto last;
+ for (;;) {
+ if (*psrc != run) {
+ if (run != htrun) {
+ htrun = run;
+ IMAGE_SET_GRAY(run);
+ }
+ code = (*fill_pgram)(dev, xrun, yrun, xl - xrun,
+ ytf - yrun, pdyx, pdyy,
+ pdevc, lop);
+ if (code < 0)
+ return code;
+ yrun = ytf;
+ xrun = xl;
+ if (psrc >= stop)
+ break;
+ run = *psrc;
+ }
+ psrc++;
+ dda_next(next.x);
+ dda_next(next.y);
+ }
+ } else {
+
+ /******************************************
+ * Slow case, not masked, not orthogonal. *
+ ******************************************/
+
+ /*
+ * Since we have to check for the end after every pixel
+ * anyway, we may as well avoid the last-run code.
+ */
+ stop = endp;
+ for (;;) {
+ /* We can't skip large constant regions quickly, */
+ /* because this leads to rounding errors. */
+ /* Just fill the region between xrun and xl. */
+ psrc++;
+ if (run != htrun) {
+ htrun = run;
+ IMAGE_SET_GRAY(run);
+ }
+ code = (*fill_pgram) (dev, xrun, yrun, xl - xrun,
+ ytf - yrun, pdyx, pdyy, pdevc, lop);
+ if (code < 0)
+ return code;
+ yrun = ytf;
+ xrun = xl;
+ if (psrc > stop) {
+ --psrc;
+ break;
+ }
+ run = psrc[-1];
+ dda_next(next.x);
+ dda_next(next.y); /* harmless if no skew */
+ }
+
+ }
+ /* Fill the last run. */
+ last:if (stop < endp && (*stop || !masked)) {
+ if (!masked) {
+ IMAGE_SET_GRAY(*stop);
+ }
+ dda_advance(next.x, endp - stop);
+ dda_advance(next.y, endp - stop);
+ code = (*fill_pgram) (dev, xrun, yrun, xl - xrun,
+ ytf - yrun, pdyx, pdyy, pdevc, lop);
+ }
+#undef xl
+#undef ytf
+
+ } else {
+
+ /**********************************************************
+ * Fast case: no skew, and not imagemask with a halftone. *
+ **********************************************************/
+
+ const fixed adjust = penum->adjust;
+ const fixed dxx = penum->dxx;
+ fixed xa = (dxx >= 0 ? adjust : -adjust);
+ const int yt = penum->yci, iht = penum->hci;
+
+ dev_proc_fill_rectangle((*fill_proc)) =
+ dev_proc(dev, fill_rectangle);
+ dev_proc_strip_tile_rectangle((*tile_proc)) =
+ dev_proc(dev, strip_tile_rectangle);
+ dev_proc_copy_mono((*copy_mono_proc)) =
+ dev_proc(dev, copy_mono);
+ /*
+ * If each pixel is likely to fit in a single halftone tile,
+ * determine that now (tile_offset = offset of row within tile).
+ * Don't do this for band devices; they handle halftone fills
+ * more efficiently than copy_mono.
+ */
+ int bstart;
+ int phase_x;
+ int tile_offset =
+ ((*dev_proc(dev, get_band)) (dev, yt, &bstart) == 0 ?
+ gx_check_tile_size(pis,
+ fixed2int_ceiling(any_abs(dxx) + (xa << 1)),
+ yt, iht, gs_color_select_source, &phase_x) :
+ -1);
+ int xmin = fixed2int_pixround(penum->clip_outer.p.x);
+ int xmax = fixed2int_pixround(penum->clip_outer.q.x);
+
+#define xl dda_current(next.x)
+ /* Fold the adjustment into xrun and xl, */
+ /* including the +0.5-epsilon for rounding. */
+ xrun = xrun - xa + (fixed_half - fixed_epsilon);
+ dda_translate(next.x, xa + (fixed_half - fixed_epsilon));
+ xa <<= 1;
+ /* Calculate multiples of the DDA step. */
+ dxx2 = next.x.step;
+ dda_step_add(dxx2, next.x.step);
+ dxx3 = dxx2;
+ dda_step_add(dxx3, next.x.step);
+ dxx4 = dxx3;
+ dda_step_add(dxx4, next.x.step);
+ if (stop > psrc)
+ for (;;) { /* Skip large constant regions quickly, */
+ /* but don't slow down transitions too much. */
+ skf:if (psrc[0] == run) {
+ if (psrc[1] == run) {
+ if (psrc[2] == run) {
+ if (psrc[3] == run) {
+ psrc += 4;
+ dda_state_next(next.x.state, dxx4);
+ goto skf;
+ } else {
+ psrc += 4;
+ dda_state_next(next.x.state, dxx3);
+ }
+ } else {
+ psrc += 3;
+ dda_state_next(next.x.state, dxx2);
+ }
+ } else {
+ psrc += 2;
+ dda_next(next.x);
+ }
+ } else
+ psrc++;
+ { /* Now fill the region between xrun and xl. */
+ int xi = fixed2int_var(xrun);
+ int wi = fixed2int_var(xl) - xi;
+ int xei, tsx;
+ const gx_strip_bitmap *tile;
+
+ if (wi <= 0) {
+ if (wi == 0)
+ goto mt;
+ xi += wi, wi = -wi;
+ }
+ if ((xei = xi + wi) > xmax || xi < xmin) { /* Do X clipping */
+ if (xi < xmin)
+ wi -= xmin - xi, xi = xmin;
+ if (xei > xmax)
+ wi -= xei - xmax;
+ if (wi <= 0)
+ goto mt;
+ }
+ switch (run) {
+ case 0:
+ if (masked)
+ goto mt;
+ if (!color_is_pure(&penum->icolor0))
+ goto ht;
+ code = (*fill_proc) (dev, xi, yt, wi, iht,
+ penum->icolor0.colors.pure);
+ break;
+ case 255: /* just for speed */
+ if (!color_is_pure(&penum->icolor1))
+ goto ht;
+ code = (*fill_proc) (dev, xi, yt, wi, iht,
+ penum->icolor1.colors.pure);
+ break;
+ default:
+ ht: /* Use halftone if needed */
+ if (run != htrun) {
+ IMAGE_SET_GRAY(run);
+ htrun = run;
+ }
+ /* We open-code gx_fill_rectangle, */
+ /* because we've done some of the work for */
+ /* halftone tiles in advance. */
+ if (color_is_pure(pdevc)) {
+ code = (*fill_proc) (dev, xi, yt, wi, iht,
+ pdevc->colors.pure);
+ } else if (!color_is_binary_halftone(pdevc)) {
+ code =
+ gx_fill_rectangle_device_rop(xi, yt, wi, iht,
+ pdevc, dev, lop);
+ } else if (tile_offset >= 0 &&
+ (tile = &pdevc->colors.binary.b_tile->tiles,
+ (tsx = (xi + phase_x) % tile->rep_width) + wi <= tile->size.x)
+ ) { /* The pixel(s) fit(s) in a single (binary) tile. */
+ byte *row = tile->data + tile_offset;
+
+ code = (*copy_mono_proc)
+ (dev, row, tsx, tile->raster, gx_no_bitmap_id,
+ xi, yt, wi, iht,
+ pdevc->colors.binary.color[0],
+ pdevc->colors.binary.color[1]);
+ } else {
+ code = (*tile_proc) (dev,
+ &pdevc->colors.binary.b_tile->tiles,
+ xi, yt, wi, iht,
+ pdevc->colors.binary.color[0],
+ pdevc->colors.binary.color[1],
+ pdevc->phase.x, pdevc->phase.y);
+ }
+ }
+ if (code < 0)
+ return code;
+ mt:xrun = xl - xa; /* original xa << 1 */
+ if (psrc > stop) {
+ --psrc;
+ break;
+ }
+ run = psrc[-1];
+ }
+ dda_next(next.x);
+ }
+ /* Fill the last run. */
+ if (*stop != 0 || !masked) {
+ int xi = fixed2int_var(xrun);
+ int wi, xei;
+
+ dda_advance(next.x, endp - stop);
+ wi = fixed2int_var(xl) - xi;
+ if (wi <= 0) {
+ if (wi == 0)
+ goto lmt;
+ xi += wi, wi = -wi;
+ }
+ if ((xei = xi + wi) > xmax || xi < xmin) { /* Do X clipping */
+ if (xi < xmin)
+ wi -= xmin - xi, xi = xmin;
+ if (xei > xmax)
+ wi -= xei - xmax;
+ if (wi <= 0)
+ goto lmt;
+ }
+ IMAGE_SET_GRAY(*stop);
+ code = gx_fill_rectangle_device_rop(xi, yt, wi, iht,
+ pdevc, dev, lop);
+ lmt:;
+ }
+
+ }
+#undef xl
+ return (code < 0 ? code : 1);
+}
diff --git a/pstoraster/gxiodev.h b/pstoraster/gxiodev.h
new file mode 100644
index 000000000..0176b07e6
--- /dev/null
+++ b/pstoraster/gxiodev.h
@@ -0,0 +1,190 @@
+/* Copyright (C) 1993, 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$ */
+/* Requires gsmemory.h */
+
+#ifndef gxiodev_INCLUDED
+# define gxiodev_INCLUDED
+
+#include "stat_.h"
+
+/*
+ * Note that IODevices are not the same as Ghostscript output devices.
+ * See section 3.8.2 of the PostScript Language Reference Manual,
+ * Second Edition, for more information.
+ */
+
+typedef struct gx_io_device_s gx_io_device; /* defined here */
+typedef struct gx_io_device_procs_s gx_io_device_procs; /* defined here */
+
+/* The IODevice table is defined in gconfig.c; its extern is in gscdefs.h. */
+
+#ifndef file_enum_DEFINED /* also defined in gp.h */
+# define file_enum_DEFINED
+struct file_enum_s; /* opaque to client, defined by implementors */
+typedef struct file_enum_s file_enum;
+
+#endif
+
+/* Define an opaque type for parameter lists. */
+#ifndef gs_param_list_DEFINED
+# define gs_param_list_DEFINED
+typedef struct gs_param_list_s gs_param_list;
+
+#endif
+
+/* Define an opaque type for streams. */
+#ifndef stream_DEFINED
+# define stream_DEFINED
+typedef struct stream_s stream;
+
+#endif
+
+/* Definition of IODevice procedures */
+/* Note that file names for fopen, delete, rename, and status */
+/* are C strings, not pointer + length. */
+/* Note also that "streams" are a higher-level concept; */
+/* the open_device and open_file procedures are normally NULL. */
+
+struct gx_io_device_procs_s {
+
+#define iodev_proc_init(proc)\
+ int proc(P2(gx_io_device *iodev, gs_memory_t *mem))
+ iodev_proc_init((*init)); /* one-time initialization */
+
+#define iodev_proc_open_device(proc)\
+ int proc(P4(gx_io_device *iodev, const char *access, stream **ps,\
+ gs_memory_t *mem))
+ iodev_proc_open_device((*open_device));
+
+#define iodev_proc_open_file(proc)\
+ int proc(P6(gx_io_device *iodev, const char *fname, uint namelen,\
+ const char *access, stream **ps, gs_memory_t *mem))
+ iodev_proc_open_file((*open_file));
+
+ /* fopen was changed in release 2.9.6, */
+ /* and again in 3.20 to return the real fname separately */
+
+#define iodev_proc_fopen(proc)\
+ int proc(P6(gx_io_device *iodev, const char *fname, const char *access,\
+ FILE **pfile, char *rfname, uint rnamelen))
+ iodev_proc_fopen((*fopen));
+
+#define iodev_proc_fclose(proc)\
+ int proc(P2(gx_io_device *iodev, FILE *file))
+ iodev_proc_fclose((*fclose));
+
+#define iodev_proc_delete_file(proc)\
+ int proc(P2(gx_io_device *iodev, const char *fname))
+ iodev_proc_delete_file((*delete_file));
+
+#define iodev_proc_rename_file(proc)\
+ int proc(P3(gx_io_device *iodev, const char *from, const char *to))
+ iodev_proc_rename_file((*rename_file));
+
+#define iodev_proc_file_status(proc)\
+ int proc(P3(gx_io_device *iodev, const char *fname, struct stat *pstat))
+ iodev_proc_file_status((*file_status));
+
+#define iodev_proc_enumerate_files(proc)\
+ file_enum *proc(P4(gx_io_device *iodev, const char *pat, uint patlen,\
+ gs_memory_t *mem))
+ iodev_proc_enumerate_files((*enumerate_files));
+
+#define iodev_proc_enumerate_next(proc)\
+ uint proc(P3(file_enum *pfen, char *ptr, uint maxlen))
+ iodev_proc_enumerate_next((*enumerate_next));
+
+#define iodev_proc_enumerate_close(proc)\
+ void proc(P1(file_enum *pfen))
+ iodev_proc_enumerate_close((*enumerate_close));
+
+ /* Added in release 2.9 */
+
+#define iodev_proc_get_params(proc)\
+ int proc(P2(gx_io_device *iodev, gs_param_list *plist))
+ iodev_proc_get_params((*get_params));
+
+#define iodev_proc_put_params(proc)\
+ int proc(P2(gx_io_device *iodev, gs_param_list *plist))
+ iodev_proc_put_params((*put_params));
+
+};
+
+/* The following typedef is needed because ansi2knr can't handle */
+/* iodev_proc_fopen((*procname)) in a formal argument list. */
+typedef iodev_proc_fopen((*iodev_proc_fopen_t));
+
+/* Default implementations of procedures */
+iodev_proc_init(iodev_no_init);
+iodev_proc_open_device(iodev_no_open_device);
+iodev_proc_open_file(iodev_no_open_file);
+iodev_proc_fopen(iodev_no_fopen);
+iodev_proc_fclose(iodev_no_fclose);
+iodev_proc_delete_file(iodev_no_delete_file);
+iodev_proc_rename_file(iodev_no_rename_file);
+iodev_proc_file_status(iodev_no_file_status);
+iodev_proc_enumerate_files(iodev_no_enumerate_files);
+iodev_proc_get_params(iodev_no_get_params);
+iodev_proc_put_params(iodev_no_put_params);
+/* The %os% implemention of fopen and fclose. */
+/* These are exported for pipes and for %null. */
+iodev_proc_fopen(iodev_os_fopen);
+iodev_proc_fclose(iodev_os_fclose);
+
+/* Get the N'th IODevice. */
+gx_io_device *gs_getiodevice(P1(int));
+
+#define iodev_default (gs_getiodevice(0))
+
+/* Look up an IODevice name. */
+gx_io_device *gs_findiodevice(P2(const byte *, uint));
+
+/* Get and put IODevice parameters. */
+int gs_getdevparams(P2(gx_io_device *, gs_param_list *));
+int gs_putdevparams(P2(gx_io_device *, gs_param_list *));
+
+/* Convert an OS error number to a PostScript error */
+/* if opening a file fails. */
+int gs_fopen_errno_to_code(P1(int));
+
+/* Test whether a string is equal to a character. */
+/* (This is used for access testing in file_open procedures.) */
+#define streq1(str, chr)\
+ ((str)[0] == (chr) && (str)[1] == 0)
+
+/* Finally, the IODevice structure itself. */
+struct gx_io_device_s {
+ const char *dname; /* the IODevice name */
+ const char *dtype; /* the type returned by c'devparams */
+ gx_io_device_procs procs;
+ void *state; /* (if the IODevice has state) */
+};
+
+#define private_st_io_device() /* in gsiodev.c */\
+ gs_private_st_ptrs1(st_io_device, gx_io_device, "gx_io_device",\
+ io_device_enum_ptrs, io_device_reloc_ptrs, state)
+
+#endif /* gxiodev_INCLUDED */
diff --git a/pstoraster/gxiparam.h b/pstoraster/gxiparam.h
new file mode 100644
index 000000000..7ef10c1ef
--- /dev/null
+++ b/pstoraster/gxiparam.h
@@ -0,0 +1,172 @@
+/* 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$ */
+/* Definitions for implementors of image types */
+
+#ifndef gxiparam_INCLUDED
+# define gxiparam_INCLUDED
+
+#include "gxdevcli.h"
+
+#ifndef gx_image_enum_common_t_DEFINED
+# define gx_image_enum_common_t_DEFINED
+typedef struct gx_image_enum_common_s gx_image_enum_common_t;
+
+#endif
+
+/*
+ * Define the procedures associated with an image enumerator.
+ *
+ * Note that image_plane_data and end_image used to be device procedures;
+ * they still take the device argument first for compatibility. However, in
+ * order to make forwarding begin_image work, the intermediary routines
+ * gx_image_[plane_]data and gx_image_end substitute the device from the
+ * enumerator for the explicit device argument, which is ignored.
+ * Eventually we should fix this by removing the device argument from
+ * gx_device..., just as we have done for text enumeration; but this would
+ * have caused major difficulties with 5.1x retrofitting of this code, and
+ * it's too much work to fix right now. ****** FIX THIS SOMEDAY ******
+ */
+typedef struct gx_image_enum_procs_s {
+
+ /*
+ * Pass the next batch of data for processing.
+ * image_enum_proc_plane_data is defined in gxdevcli.h.
+ */
+
+ image_enum_proc_plane_data((*plane_data));
+
+ /*
+ * End processing an image. We keep this procedure as the last one that
+ * requires initialization, so that we can detect obsolete static
+ * initializers. dev_proc_end_image is defined in gxdevcli.h.
+ */
+#define image_enum_proc_end_image(proc)\
+ dev_proc_end_image(proc)
+
+ image_enum_proc_end_image((*end_image));
+
+ /*
+ * Flush any intermediate buffers to the target device.
+ * We need this for situations where two images interact
+ * (currently, only the mask and the data of ImageType 3).
+ * This procedure is optional (may be 0).
+ */
+#define image_enum_proc_flush(proc)\
+ int proc(P1(gx_image_enum_common_t *info))
+
+ image_enum_proc_flush((*flush));
+
+} gx_image_enum_procs_t;
+
+/*
+ * Define the common prefix of the image enumerator structure. All
+ * implementations of begin[_typed]_image must initialize all of the members
+ * of this structure, by calling gx_image_enum_common_init and then filling
+ * in whatever else they need to.
+ *
+ * Note that the structure includes a unique ID, so that the banding
+ * machinery could in principle keep track of multiple enumerations that may
+ * be in progress simultaneously.
+ */
+#define gx_image_enum_common\
+ const gx_image_type_t *image_type;\
+ const gx_image_enum_procs_t *procs;\
+ gx_device *dev;\
+ gs_id id;\
+ int num_planes;\
+ int plane_depths[gs_image_max_components] /* [num_planes] */
+struct gx_image_enum_common_s {
+ gx_image_enum_common;
+};
+
+/*extern_st(st_gx_image_enum_common); */
+#define public_st_gx_image_enum_common() /* in gdevddrw.c */\
+ gs_public_st_composite(st_gx_image_enum_common, gx_image_enum_common_t,\
+ "gx_image_enum_common_t",\
+ image_enum_common_enum_ptrs, image_enum_common_reloc_ptrs)
+
+/*
+ * Initialize the common part of an image enumerator.
+ */
+int gx_image_enum_common_init(P7(gx_image_enum_common_t * piec,
+ const gs_image_common_t * pic,
+ const gx_image_enum_procs_t * piep,
+ gx_device * dev,
+ int bits_per_component, int num_components,
+ gs_image_format_t format));
+
+/*
+ * Define the structure for defining image types. An image type includes
+ * not only the ImageType index, but also the default implementation of
+ * begin_typed_image.
+ */
+#ifndef gx_image_type_DEFINED
+# define gx_image_type_DEFINED
+typedef struct gx_image_type_s gx_image_type_t;
+#endif
+struct gx_image_type_s {
+
+ dev_proc_begin_typed_image((*begin_typed_image));
+
+ /*
+ * Compute the width and height of the source data. For images with
+ * explicit data, this information is in the gs_data_image_t
+ * structure, but ImageType 2 images must compute it.
+ */
+#define image_proc_source_size(proc)\
+ int proc(P3(const gs_imager_state *pis, const gs_image_common_t *pim,\
+ gs_int_point *psize))
+
+ image_proc_source_size((*source_size));
+
+ /*
+ * We put index last so that if we add more procedures and some
+ * implementor fails to initialize them, we'll get a type error.
+ */
+ int index; /* PostScript ImageType */
+};
+
+/*
+ * Define the procedure for getting the source size of an image with
+ * explicit data.
+ */
+image_proc_source_size(gx_data_image_source_size);
+/*
+ * Define image_plane_data and end_image procedures for image types that
+ * don't have any source data (ImageType 2 and composite images).
+ */
+image_enum_proc_plane_data(gx_no_plane_data);
+image_enum_proc_end_image(gx_ignore_end_image);
+/*
+ * Define the procedures and type data for ImageType 1 images,
+ * which are always included.
+ */
+dev_proc_begin_typed_image(gx_begin_image1);
+image_enum_proc_plane_data(gx_image1_plane_data);
+image_enum_proc_end_image(gx_image1_end_image);
+image_enum_proc_flush(gx_image1_flush);
+
+#endif /* gxiparam_INCLUDED */
diff --git a/pstoraster/gxiscale.c b/pstoraster/gxiscale.c
new file mode 100644
index 000000000..3264b79c6
--- /dev/null
+++ b/pstoraster/gxiscale.c
@@ -0,0 +1,256 @@
+/* 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$ */
+/* Interpolated image procedures */
+#include "gx.h"
+#include "math_.h"
+#include "memory_.h"
+#include "gpcheck.h"
+#include "gserrors.h"
+#include "gxfixed.h"
+#include "gxfrac.h"
+#include "gxarith.h"
+#include "gxmatrix.h"
+#include "gsccolor.h"
+#include "gspaint.h"
+#include "gxdevice.h"
+#include "gxcmap.h"
+#include "gxdcolor.h"
+#include "gxistate.h"
+#include "gzpath.h"
+#include "gxdevmem.h"
+#include "gxcpath.h"
+#include "gximage.h"
+
+/* ------ Strategy procedure ------ */
+
+/* If we're interpolating, use special logic. */
+private irender_proc(image_render_interpolate);
+private irender_proc_t
+image_strategy_interpolate(gx_image_enum * penum)
+{
+ const gs_imager_state *pis = penum->pis;
+ gs_memory_t *mem = penum->memory;
+ stream_IScale_state iss;
+ stream_IScale_state *pss;
+ byte *line;
+ const gs_color_space *pcs = penum->pcs;
+ const gs_color_space *pccs;
+ gs_point dst_xy;
+
+ if (!penum->interpolate)
+ return 0;
+ if (penum->posture != image_portrait || penum->masked ||
+ penum->alpha
+ ) {
+ /* We can't handle these cases yet. Punt. */
+ penum->interpolate = false;
+ return 0;
+ }
+ iss.memory = mem;
+ /* Non-ANSI compilers require the following casts: */
+ gs_distance_transform((float)penum->rect.w, (float)penum->rect.h,
+ &penum->matrix, &dst_xy);
+ if (penum->bps <= 8 && penum->device_color) {
+ iss.BitsPerComponentIn = 8;
+ iss.MaxValueIn = 0xff;
+ } else {
+ iss.BitsPerComponentIn = sizeof(frac) * 8;
+ iss.MaxValueIn = frac_1;
+ }
+ iss.BitsPerComponentOut = sizeof(frac) * 8;
+ iss.MaxValueOut = frac_1;
+ iss.WidthOut = (int)ceil(fabs(dst_xy.x));
+ iss.HeightOut = (int)ceil(fabs(dst_xy.y));
+ iss.WidthIn = penum->rect.w;
+ iss.HeightIn = penum->rect.h;
+ pccs = cs_concrete_space(pcs, pis);
+ iss.Colors = cs_num_components(pccs);
+ /* Allocate a buffer for one source/destination line. */
+ {
+ uint in_size =
+ iss.WidthIn * iss.Colors * (iss.BitsPerComponentIn / 8);
+ uint out_size =
+ iss.WidthOut * iss.Colors *
+ max(iss.BitsPerComponentOut / 8, sizeof(gx_color_index));
+
+ line = gs_alloc_bytes(mem, max(in_size, out_size),
+ "image scale src line");
+ }
+ pss = gs_alloc_struct(mem, stream_IScale_state,
+ &st_IScale_state, "image scale state");
+ if (line == 0 || pss == 0 ||
+ (*pss = iss,
+ (*s_IScale_template.init) ((stream_state *) pss) < 0)
+ ) {
+ gs_free_object(mem, pss, "image scale state");
+ gs_free_object(mem, line, "image scale src line");
+ /* Try again without interpolation. */
+ penum->interpolate = false;
+ return 0;
+ }
+ penum->line = line;
+ penum->scaler = pss;
+ penum->line_xy = 0;
+ {
+ gx_dda_fixed x0;
+
+ x0 = penum->dda.pixel0.x;
+ if (penum->matrix.xx < 0)
+ dda_advance(x0, penum->rect.w);
+ penum->xyi.x = fixed2int_pixround(dda_current(x0));
+ }
+ penum->xyi.y = fixed2int_pixround(dda_current(penum->dda.pixel0.y));
+ if_debug0('b', "[b]render=interpolate\n");
+ return image_render_interpolate;
+}
+
+void
+gs_gxiscale_init(gs_memory_t * mem)
+{
+ image_strategies.interpolate = image_strategy_interpolate;
+}
+
+/* ------ Rendering for interpolated images ------ */
+
+private int
+image_render_interpolate(gx_image_enum * penum, const byte * buffer,
+ int data_x, uint iw, int h, gx_device * dev)
+{
+ stream_IScale_state *pss = penum->scaler;
+ const gs_imager_state *pis = penum->pis;
+ const gs_color_space *pcs = penum->pcs;
+ gs_logical_operation_t lop = penum->log_op;
+ int c = pss->Colors;
+ stream_cursor_read r;
+ stream_cursor_write w;
+
+ if (h != 0) {
+ /* Convert the unpacked data to concrete values in */
+ /* the source buffer. */
+ uint row_size = pss->WidthIn * c * pss->sizeofPixelIn;
+ const byte *bdata = buffer + data_x * c * pss->sizeofPixelIn;
+
+ if (pss->sizeofPixelIn == 1) {
+ /* Easy case: 8-bit device color values. */
+ r.ptr = bdata - 1;
+ } else {
+ /* Messy case: concretize each sample. */
+ int bps = penum->bps;
+ int dc = penum->spp;
+ const byte *pdata = bdata;
+ frac *psrc = (frac *) penum->line;
+ gs_client_color cc;
+ int i;
+
+ r.ptr = (byte *) psrc - 1;
+ for (i = 0; i < pss->WidthIn; i++, psrc += c) {
+ int j;
+
+ if (bps <= 8)
+ for (j = 0; j < dc; ++pdata, ++j) {
+ decode_sample(*pdata, cc, j);
+ } else /* bps == 12 */
+ for (j = 0; j < dc; pdata += sizeof(frac), ++j) {
+ decode_frac(*(const frac *)pdata, cc, j);
+ }
+ (*pcs->type->concretize_color) (&cc, pcs, psrc,
+ pis);
+ }
+ }
+ r.limit = r.ptr + row_size;
+ } else /* h == 0 */
+ r.ptr = 0, r.limit = 0;
+
+ /*
+ * Process input and/or collect output. By construction, the pixels are
+ * 1-for-1 with the device, but the Y coordinate might be inverted.
+ */
+
+ {
+ int xo = penum->xyi.x;
+ int yo = penum->xyi.y;
+ int width = pss->WidthOut;
+ int dy;
+ const gs_color_space *pconcs = cs_concrete_space(pcs, pis);
+ int bpp = dev->color_info.depth;
+ uint raster = bitmap_raster(width * bpp);
+
+ if (penum->matrix.yy > 0)
+ dy = 1;
+ else
+ dy = -1, yo--;
+ for (;;) {
+ int ry = yo + penum->line_xy * dy;
+ int x;
+ const frac *psrc;
+ gx_device_color devc;
+ int code;
+
+ declare_line_accum(penum->line, bpp, xo);
+
+ w.limit = penum->line + width * c *
+ sizeof(gx_color_index) - 1;
+ w.ptr = w.limit - width * c *
+ (sizeof(gx_color_index) - pss->sizeofPixelOut);
+ psrc = (const frac *)(w.ptr + 1);
+ code = (*s_IScale_template.process)
+ ((stream_state *) pss, &r, &w, h == 0);
+ if (code < 0 && code != EOFC)
+ return_error(gs_error_ioerror);
+ if (w.ptr == w.limit) {
+ for (x = xo; x < xo + width; x++, psrc += c) {
+ (*pconcs->type->remap_concrete_color)
+ (psrc, &devc, pis, dev,
+ gs_color_select_source);
+ if (color_is_pure(&devc)) {
+ /* Just pack colors into a scan line. */
+ gx_color_index color = devc.colors.pure;
+
+ line_accum(color, bpp);
+ } else {
+ int rcode;
+
+ line_accum_copy(dev, penum->line, bpp,
+ xo, x, raster, ry);
+ rcode = gx_fill_rectangle_device_rop(x, ry,
+ 1, 1, &devc, dev, lop);
+ if (rcode < 0)
+ return rcode;
+ line_accum_skip(bpp);
+ l_xprev = x + 1;
+ }
+ }
+ line_accum_copy(dev, penum->line, bpp,
+ xo, x, raster, ry);
+ penum->line_xy++;
+ }
+ if ((code == 0 && r.ptr == r.limit) || code == EOFC)
+ break;
+ }
+ }
+
+ return (h == 0 ? 0 : 1);
+}
diff --git a/pstoraster/gxistate.h b/pstoraster/gxistate.h
new file mode 100644
index 000000000..4575e2125
--- /dev/null
+++ b/pstoraster/gxistate.h
@@ -0,0 +1,251 @@
+/* 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$ */
+/* Imager state definition */
+
+#ifndef gxistate_INCLUDED
+# define gxistate_INCLUDED
+
+#include "gscsel.h"
+#include "gsrefct.h"
+#include "gsropt.h"
+#include "gxcvalue.h"
+#include "gxfixed.h"
+#include "gxline.h"
+#include "gxmatrix.h"
+#include "gxtmap.h"
+
+/*
+ * Define the subset of the PostScript graphics state that the imager
+ * library API needs. The definition of this subset is subject to change
+ * as we come to understand better the boundary between the imager and
+ * the interpreter. In particular, the imager state currently INCLUDES
+ * the following:
+ * line parameters: cap, join, miter limit, dash pattern
+ * transformation matrix (CTM)
+ * logical operation: RasterOp, transparency
+ * color modification: alpha, rendering algorithm
+ * overprint flag
+ * rendering tweaks: flatness, fill adjustment, stroke adjust flag,
+ * accurate curves flag, shading smoothness
+ * color rendering information:
+ * halftone, halftone phases
+ * transfer functions
+ * black generation, undercolor removal
+ * CIE rendering tables
+ * halftone and pattern caches
+ * The imager state currently EXCLUDES the following:
+ * graphics state stack
+ * default CTM
+ * path
+ * clipping path
+ * color specification: color, color space
+ * font
+ * device
+ * caches for many of the above
+ */
+
+/*
+ * Define the color rendering state information.
+ * This should be a separate object (or at least a substructure),
+ * but doing this would require editing too much code.
+ */
+
+/* Opaque types referenced by the color rendering state. */
+#ifndef gs_halftone_DEFINED
+# define gs_halftone_DEFINED
+typedef struct gs_halftone_s gs_halftone;
+
+#endif
+#ifndef gx_device_color_DEFINED
+# define gx_device_color_DEFINED
+typedef struct gx_device_color_s gx_device_color;
+
+#endif
+#ifndef gx_device_halftone_DEFINED
+# define gx_device_halftone_DEFINED
+typedef struct gx_device_halftone_s gx_device_halftone;
+
+#endif
+
+/*
+ * We need some special memory management for the components of a
+ * c.r. state, as indicated by the following notations on the elements:
+ * (RC) means the element is reference-counted.
+ * (Shared) means the element is shared among an arbitrary number of
+ * c.r. states and is never freed.
+ * (Owned) means exactly one c.r. state references the element,
+ * and it is guaranteed that no references to it will outlive
+ * the c.r. state itself.
+ */
+
+/* Define the interior structure of a transfer function. */
+typedef struct gx_transfer_colored_s {
+ /* The components must be in this order: */
+ gx_transfer_map *red; /* (RC) */
+ gx_transfer_map *green; /* (RC) */
+ gx_transfer_map *blue; /* (RC) */
+ gx_transfer_map *gray; /* (RC) */
+} gx_transfer_colored;
+typedef union gx_transfer_s {
+ gx_transfer_map *indexed[4]; /* (RC) */
+ gx_transfer_colored colored;
+} gx_transfer;
+
+#define gs_color_rendering_state_common\
+\
+ /* Halftone screen: */\
+\
+ gs_halftone *halftone; /* (RC) */\
+ gs_int_point screen_phase[gs_color_select_count];\
+ /* dev_ht depends on halftone and device resolution. */\
+ gx_device_halftone *dev_ht; /* (Owned) */\
+ /* The contents of ht_cache depend on dev_ht. */\
+ struct gx_ht_cache_s *ht_cache; /* (Shared) by all gstates */\
+\
+ /* Color (device-dependent): */\
+\
+ struct gs_cie_render_s *cie_render; /* (RC) may be 0 */\
+ gx_transfer_map *black_generation; /* (RC) may be 0 */\
+ gx_transfer_map *undercolor_removal; /* (RC) may be 0 */\
+ /* set_transfer holds the transfer functions specified by */\
+ /* set[color]transfer; effective_transfer includes the */\
+ /* effects of overrides by TransferFunctions in halftone */\
+ /* dictionaries. (In Level 1 systems, set_transfer and */\
+ /* effective_transfer are always the same.) */\
+ gx_transfer set_transfer; /* members are (RC) */\
+ gx_transfer effective_transfer; /* see below */\
+\
+ /* Color caches: */\
+\
+ /* cie_joint_caches depend on cie_render and */\
+ /* the color space. */\
+ struct gx_cie_joint_caches_s *cie_joint_caches; /* (RC) */\
+ /* cmap_procs depend on the device's color_info. */\
+ const struct gx_color_map_procs_s *cmap_procs; /* static */\
+ /* The contents of pattern_cache depend on the */\
+ /* the color space and the device's color_info and */\
+ /* resolution. */\
+ struct gx_pattern_cache_s *pattern_cache /* (Shared) by all gstates */
+
+/*
+ * Enumerate the reference-counted pointers in a c.r. state. Note that
+ * effective_transfer doesn't contribute to the reference count: it points
+ * either to the same objects as set_transfer, or to objects in a halftone
+ * structure that someone else worries about.
+ */
+#define gs_cr_state_do_rc_ptrs(m)\
+ m(halftone) m(cie_render) m(black_generation) m(undercolor_removal)\
+ m(set_transfer.colored.red) m(set_transfer.colored.green)\
+ m(set_transfer.colored.blue) m(set_transfer.colored.gray)\
+ m(cie_joint_caches)
+
+/* Enumerate the pointers in a c.r. state. */
+#define gs_cr_state_do_ptrs(m)\
+ m(0,halftone) m(1,dev_ht) m(2,ht_cache)\
+ m(3,cie_render) m(4,black_generation) m(5,undercolor_removal)\
+ m(6,set_transfer.colored.red) m(7,set_transfer.colored.green)\
+ m(8,set_transfer.colored.blue) m(9,set_transfer.colored.gray)\
+ m(10,effective_transfer.colored.red) m(11,effective_transfer.colored.green)\
+ m(12,effective_transfer.colored.blue) m(13,effective_transfer.colored.gray)\
+ m(14,cie_joint_caches) m(15,pattern_cache)
+#define st_cr_state_num_ptrs 16
+
+/*
+ * Define constant values that can be allocated once and shared among
+ * all imager states in an address space.
+ */
+#ifndef gs_color_space_DEFINED
+# define gs_color_space_DEFINED
+typedef struct gs_color_space_s gs_color_space;
+
+#endif
+typedef struct gs_imager_state_shared_s {
+ rc_header rc;
+ gs_color_space *cs_DeviceGray;
+ gs_color_space *cs_DeviceRGB;
+ gs_color_space *cs_DeviceCMYK;
+} gs_imager_state_shared_t;
+
+#define private_st_imager_state_shared() /* in gsstate.c */\
+ gs_private_st_ptrs3(st_imager_state_shared, gs_imager_state_shared_t,\
+ "gs_imager_state_shared", imager_state_shared_enum_ptrs,\
+ imager_state_shared_reloc_ptrs, cs_DeviceGray, cs_DeviceRGB, cs_DeviceCMYK)
+
+/* Define the imager state structure itself. */
+#define gs_imager_state_common\
+ gs_memory_t *memory;\
+ gs_imager_state_shared_t *shared;\
+ gx_line_params line_params;\
+ gs_matrix_fixed ctm;\
+ gs_logical_operation_t log_op;\
+ gx_color_value alpha;\
+ bool overprint;\
+ float flatness;\
+ gs_fixed_point fill_adjust; /* fattening for fill */\
+ bool stroke_adjust;\
+ bool accurate_curves;\
+ float smoothness;\
+ gs_color_rendering_state_common
+#define gs_imager_state_shared(pis, elt) ((pis)->shared->elt)
+#define st_imager_state_num_ptrs\
+ (st_line_params_num_ptrs + st_cr_state_num_ptrs + 1)
+/* Access macros */
+#define ctm_only(pis) (*(const gs_matrix *)&(pis)->ctm)
+#define ctm_only_writable(pis) (*(gs_matrix *)&(pis)->ctm)
+#define set_ctm_only(pis, mat) (*(gs_matrix *)&(pis)->ctm = (mat))
+#define gs_init_rop(pis) ((pis)->log_op = lop_default)
+#define gs_currentlineparams_inline(pis) (&(pis)->line_params)
+
+#ifndef gs_imager_state_DEFINED
+# define gs_imager_state_DEFINED
+typedef struct gs_imager_state_s gs_imager_state;
+
+#endif
+
+struct gs_imager_state_s {
+ gs_imager_state_common;
+};
+
+/* Initialization for gs_imager_state */
+#define gs_imager_state_initial(scale)\
+ 0, 0, { gx_line_params_initial },\
+ { scale, 0.0, 0.0, -(scale), 0.0, 0.0 },\
+ lop_default, gx_max_color_value, 0/*false*/, 1.0,\
+ { fixed_half, fixed_half }, 0/*false*/, 0/*false*/, 1.0
+
+#define private_st_imager_state() /* in gsstate.c */\
+ gs_private_st_composite(st_imager_state, gs_imager_state, "gs_imager_state",\
+ imager_state_enum_ptrs, imager_state_reloc_ptrs)
+
+/* Initialize an imager state, other than the parts covered by */
+/* gs_imager_state_initial. */
+/* The halftone, dev_ht, and ht_cache elements are not set or used. */
+int gs_imager_state_initialize(P2(gs_imager_state * pis, gs_memory_t * mem));
+
+/* Release an imager state. */
+void gs_imager_state_release(P1(gs_imager_state * pis));
+
+#endif /* gxistate_INCLUDED */
diff --git a/pstoraster/gxline.h b/pstoraster/gxline.h
new file mode 100644
index 000000000..138fc8967
--- /dev/null
+++ b/pstoraster/gxline.h
@@ -0,0 +1,81 @@
+/* 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$ */
+/* Private line parameter definitions */
+
+#ifndef gxline_INCLUDED
+# define gxline_INCLUDED
+
+#include "gslparam.h"
+
+/* Line parameter structures */
+/* gx_dash_params are never instantiated by themselves. */
+typedef struct gx_dash_params_s {
+ float *pattern;
+ uint pattern_size;
+ float offset;
+ bool adapt;
+ /* The rest of the parameters are computed from the above */
+ float pattern_length; /* total of all pattern elements */
+ bool init_ink_on; /* true if ink is initially on */
+ int init_index; /* initial index in pattern */
+ float init_dist_left;
+} gx_dash_params;
+
+#define gx_dash_params_initial\
+ NULL, 0, 0.0, 0/*false*/, 0.0, 1/*true*/, 0, 0.0
+typedef struct gx_line_params_s {
+ float half_width; /* one-half line width */
+ gs_line_cap cap;
+ gs_line_join join;
+ float miter_limit;
+ float miter_check; /* computed from miter limit, */
+ /* see gx_set_miter_limit and */
+ /* gs_stroke */
+ float dot_length;
+ bool dot_length_absolute; /* if true, dot_length is 1/72" units */
+ gx_dash_params dash;
+} gx_line_params;
+
+#define gx_set_line_width(plp, wid)\
+ ((plp)->half_width = (wid) / 2)
+#define gx_current_line_width(plp)\
+ ((plp)->half_width * 2)
+int gx_set_miter_limit(P2(gx_line_params *, floatp));
+
+#define gx_current_miter_limit(plp)\
+ ((plp)->miter_limit)
+int gx_set_dash(P5(gx_dash_params *, const float *, uint, floatp,
+ gs_memory_t *));
+
+#define gx_set_dash_adapt(pdp, adpt) ((pdp)->adapt = (adpt))
+int gx_set_dot_length(P3(gx_line_params *, floatp, bool));
+
+/* See gsline.c for the computation of miter_check. */
+#define gx_line_params_initial\
+ 0.0, gs_cap_butt, gs_join_miter, 10.0, 0.20305866, 0.0, 0/*false*/,\
+ { gx_dash_params_initial }
+
+#endif /* gxline_INCLUDED */
diff --git a/pstoraster/gxlum.h b/pstoraster/gxlum.h
new file mode 100644
index 000000000..e4f1cbc59
--- /dev/null
+++ b/pstoraster/gxlum.h
@@ -0,0 +1,50 @@
+/*
+ Copyright 1993-1999 by Easy Software Products.
+ 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$ */
+/* Luminance computation parameters for Ghostscript */
+
+#ifndef gxlum_INCLUDED
+# define gxlum_INCLUDED
+
+/*
+ * Color weights used for computing luminance.
+ *
+ * The original ones used here were for NTSC video displays. Of course,
+ * if you want to print instead of display things are different...
+ */
+#ifdef NTSC_LUM
+# define lum_red_weight 30
+# define lum_green_weight 59
+# define lum_blue_weight 11
+#else
+# define lum_red_weight 31
+# define lum_green_weight 61
+# define lum_blue_weight 8
+#endif /* NTSC_LUN */
+#define lum_all_weights (lum_red_weight + lum_green_weight + lum_blue_weight)
+
+#endif /* gxlum_INCLUDED */
diff --git a/pstoraster/gxmatrix.h b/pstoraster/gxmatrix.h
new file mode 100644
index 000000000..01b9df532
--- /dev/null
+++ b/pstoraster/gxmatrix.h
@@ -0,0 +1,83 @@
+/* Copyright (C) 1989, 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$ */
+/* Internal matrix routines for Ghostscript library */
+
+#ifndef gxmatrix_INCLUDED
+# define gxmatrix_INCLUDED
+
+#include "gsmatrix.h"
+
+/*
+ * Define a matrix with a cached fixed-point copy of the translation.
+ * This is only used by a few routines in gscoord.c; they are responsible
+ * for ensuring the validity of the cache. Note that the floating point
+ * tx/ty values may be too large to fit in a fixed values; txy_fixed_valid
+ * is false if this is the case, and true otherwise.
+ */
+typedef struct gs_matrix_fixed_s {
+ _matrix_body;
+ fixed tx_fixed, ty_fixed;
+ bool txy_fixed_valid;
+} gs_matrix_fixed;
+
+/* Coordinate transformations to fixed point. */
+int gs_point_transform2fixed(P4(const gs_matrix_fixed *, floatp, floatp,
+ gs_fixed_point *));
+int gs_distance_transform2fixed(P4(const gs_matrix_fixed *, floatp, floatp,
+ gs_fixed_point *));
+
+/*
+ * Define the fixed-point coefficient structure for avoiding
+ * floating point in coordinate transformations.
+ * Currently this is used only by the Type 1 font interpreter.
+ * The setup is in gscoord.c.
+ */
+typedef struct {
+ long l;
+ fixed f;
+} coeff1;
+typedef struct {
+ coeff1 xx, xy, yx, yy;
+ int skewed;
+ int shift; /* see m_fixed */
+ int max_bits; /* max bits of coefficient */
+ fixed round; /* ditto */
+} fixed_coeff;
+
+/*
+ * Multiply a fixed whose integer part usually does not exceed max_bits
+ * in magnitude by a coefficient from a fixed_coeff.
+ * We can use a faster algorithm if the fixed is an integer within
+ * a range that doesn't cause the multiplication to overflow an int.
+ */
+#define m_fixed(v, c, fc, maxb)\
+ (((v) + (fixed_1 << (maxb - 1))) &\
+ ((-fixed_1 << maxb) | _fixed_fraction_v) ? /* out of range, or has fraction */\
+ (fixed2int_var(v) * (fc).c.f +\
+ arith_rshift(fixed_fraction(v) * (fc).c.f + fixed_half, _fixed_shift)) :\
+ arith_rshift(fixed2int_var(v) * (fc).c.l + (fc).round, (fc).shift))
+
+#endif /* gxmatrix_INCLUDED */
diff --git a/pstoraster/gxmclip.c b/pstoraster/gxmclip.c
new file mode 100644
index 000000000..a2694318c
--- /dev/null
+++ b/pstoraster/gxmclip.c
@@ -0,0 +1,116 @@
+/* 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$ */
+/* Mask clipping support */
+#include "gx.h"
+#include "gxdevice.h"
+#include "gxdevmem.h"
+#include "gxmclip.h"
+
+/* Structure descriptor */
+public_st_device_mask_clip();
+
+/* GC procedures */
+#define mcdev ((gx_device_mask_clip *)vptr)
+
+private ENUM_PTRS_BEGIN(device_mask_clip_enum_ptrs)
+{
+ if (index < st_gx_strip_bitmap_max_ptrs) {
+ return ENUM_USING(st_gx_strip_bitmap, &mcdev->tiles,
+ sizeof(mcdev->tiles), index);
+ }
+ index -= st_gx_strip_bitmap_max_ptrs;
+ if (index < st_device_memory_max_ptrs) {
+ return ENUM_USING(st_device_memory, &mcdev->mdev,
+ sizeof(mcdev->mdev), index);
+ }
+ ENUM_PREFIX(st_device_forward, st_device_memory_max_ptrs);
+}
+ENUM_PTRS_END
+
+private RELOC_PTRS_BEGIN(device_mask_clip_reloc_ptrs)
+{
+ RELOC_PREFIX(st_device_forward);
+ RELOC_USING(st_gx_strip_bitmap, &mcdev->tiles, sizeof(mcdev->tiles));
+ RELOC_USING(st_device_memory, &mcdev->mdev, sizeof(mcdev->mdev));
+ if (mcdev->mdev.base != 0) {
+ /*
+ * Update the line pointers specially, since they point into the
+ * buffer that is part of the mask clipping device itself.
+ */
+ long diff = (char *)RELOC_OBJ(mcdev) - (char *)mcdev;
+ int i;
+
+ for (i = 0; i < mcdev->mdev.height; ++i)
+ mcdev->mdev.line_ptrs[i] += diff;
+ mcdev->mdev.base = mcdev->mdev.line_ptrs[0];
+ mcdev->mdev.line_ptrs =
+ (void *)((char *)(mcdev->mdev.line_ptrs) + diff);
+ }
+}
+RELOC_PTRS_END
+
+#undef mcdev
+
+/* Initialize a mask clipping device. */
+int
+gx_mask_clip_initialize(gx_device_mask_clip * cdev,
+ const gx_device_mask_clip * proto,
+ const gx_bitmap * bits, gx_device * tdev,
+ int tx, int ty)
+{
+ int buffer_width = bits->size.x;
+ int buffer_height =
+ tile_clip_buffer_size / (bits->raster + sizeof(byte *));
+
+ gx_device_init((gx_device *)cdev, (const gx_device *)proto,
+ NULL, true);
+ cdev->width = tdev->width;
+ cdev->height = tdev->height;
+ cdev->color_info = tdev->color_info;
+ cdev->target = tdev;
+ cdev->phase.x = -tx;
+ cdev->phase.y = -ty;
+ if (buffer_height > bits->size.y)
+ buffer_height = bits->size.y;
+ gs_make_mem_mono_device(&cdev->mdev, 0, 0);
+ for (;;) {
+ if (buffer_height <= 0) {
+ /*
+ * The tile is too wide to buffer even one scan line.
+ * We could do copy_mono in chunks, but for now, we punt.
+ */
+ cdev->mdev.base = 0;
+ return 0;
+ }
+ cdev->mdev.width = buffer_width;
+ cdev->mdev.height = buffer_height;
+ if (gdev_mem_bitmap_size(&cdev->mdev) <= tile_clip_buffer_size)
+ break;
+ buffer_height--;
+ }
+ cdev->mdev.base = cdev->buffer.bytes;
+ return (*dev_proc(&cdev->mdev, open_device))((gx_device *)&cdev->mdev);
+}
diff --git a/pstoraster/gxmclip.h b/pstoraster/gxmclip.h
new file mode 100644
index 000000000..b56a0195b
--- /dev/null
+++ b/pstoraster/gxmclip.h
@@ -0,0 +1,111 @@
+/* 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$ */
+/* Mask clipping device and interface */
+/* Requires gxdevice.h, gxdevmem.h */
+
+#ifndef gxmclip_INCLUDED
+# define gxmclip_INCLUDED
+
+#include "gxclip.h"
+
+/*
+ * ImageType 3 images and Patterns that don't completely fill their
+ * bounding box require the ability to clip against a mask.
+ * The interface declared here doesn't take a position on whether
+ * the mask will be used only in one position (ImageType 3) or in
+ * multiple positions for tiling (Patterns).
+ *
+ * All the information in this file is logically private, but we must expose
+ * the structure definition so that clients can allocate instances in the
+ * stack frame.
+ */
+
+#define tile_clip_buffer_request 300
+#define tile_clip_buffer_size\
+ ((tile_clip_buffer_request / arch_sizeof_long) * arch_sizeof_long)
+typedef struct gx_device_mask_clip_s {
+ gx_device_forward_common; /* target is set by client */
+ gx_strip_bitmap tiles;
+ gx_device_memory mdev; /* for tile buffer for copy_mono */
+ gs_int_point phase; /* device space origin relative */
+ /* to tile (backwards from gstate phase) */
+ /* Ensure that the buffer is long-aligned. */
+ union _b {
+ byte bytes[tile_clip_buffer_size];
+ ulong longs[tile_clip_buffer_size / arch_sizeof_long];
+ } buffer;
+} gx_device_mask_clip;
+
+extern_st(st_device_mask_clip);
+#define public_st_device_mask_clip() /* in gxmclip.c */\
+ gs_public_st_composite(st_device_mask_clip, gx_device_mask_clip,\
+ "gx_device_mask_clip", device_mask_clip_enum_ptrs,\
+ device_mask_clip_reloc_ptrs)
+
+/*
+ * Internal routine to initialize a mask clipping device.
+ * We supply an explicit device space origin or phase.
+ * Note that this procedure does not set cdev->tiles.
+ */
+int gx_mask_clip_initialize(P6(gx_device_mask_clip * cdev,
+ const gx_device_mask_clip * proto,
+ const gx_bitmap * bits, gx_device * tdev,
+ int tx, int ty));
+
+/*
+ * Prepare colors for a copy_mono operation.
+ * The arguments of copy_mono are free variables:
+ * dev, data, sourcex, raster, id, x, y, w, y, color0, color1.
+ */
+#define setup_mask_copy_mono(cdev, color, mcolor0, mcolor1)\
+ BEGIN\
+ if ( cdev->mdev.base == 0 ) {\
+ /*\
+ * The tile was too large for us to buffer even one scan line.\
+ * Punt to the very, very slow default implementation of\
+ * copy_mono.\
+ */\
+ return gx_default_copy_mono(dev, data, sourcex, raster, id,\
+ x, y, w, h, color0, color1);\
+ }\
+ if ( color1 != gx_no_color_index ) {\
+ if ( color0 != gx_no_color_index ) {\
+ /* Pre-fill with color0. */\
+ code =\
+ (*dev_proc(dev, fill_rectangle))(dev, x, y, w, h, color0);\
+ if ( code < 0 )\
+ return code;\
+ }\
+ color = color1;\
+ mcolor0 = 0, mcolor1 = gx_no_color_index;\
+ } else if ( color0 != gx_no_color_index ) {\
+ color = color0;\
+ mcolor0 = gx_no_color_index, mcolor1 = 0;\
+ } else\
+ return 0;\
+ END
+
+#endif /* gxmclip_INCLUDED */
diff --git a/pstoraster/gxobj.h b/pstoraster/gxobj.h
new file mode 100644
index 000000000..8d395a713
--- /dev/null
+++ b/pstoraster/gxobj.h
@@ -0,0 +1,230 @@
+/* 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$ */
+/* Memory manager implementation structures for Ghostscript */
+
+#ifndef gxobj_INCLUDED
+# define gxobj_INCLUDED
+
+#include "gxbitmap.h"
+
+/* ================ Objects ================ */
+
+/*
+ * Object headers come in a number of different varieties.
+ * All arise from the same basic form, which is
+ -l- -lmsize/mark/back-
+ -size-
+ -type/reloc-
+ * l (large) is a single bit. The size of lmsize/mark/back, size, and type
+ * varies according to the environment. On machines with N:16 segmented
+ * addressing, 16-bit ints, and no alignment requirement more severe than
+ * 2 bytes, we can fit an object header into 8 bytes by making the first
+ * two fields only 16 bits wide. On all other machines, we let the
+ * lmsize/mark/back field be 1 bit shorter than a uint, and round the header
+ * size up to the next multiple of the most severe alignment restriction
+ * (4 or 8 bytes). Miraculously, we can do all this without any case testing.
+ *
+ * The mark/back field is used for the mark during the marking phase of
+ * garbage collection, and for a back pointer value during the compaction
+ * phase. Since we want to be able to collect local VM independently of
+ * global VM, we need two different distinguished mark values:
+ * - For local objects that have not been traced and should be freed
+ * (compacted out), we use 1...11 in the mark field (o_unmarked).
+ * - For global objects that have not been traced but should be kept,
+ * we use 1...10 in the mark field (o_untraced).
+ * Note that neither of these values is a possible real relocation value.
+ *
+ * The lmsize field of large objects overlaps mark and back, so we must
+ * handle these functions for large objects in some other way.
+ * Since large objects cannot be moved or relocated, we don't need the
+ * back field for them; we allocate 2 bits for the 3 mark values.
+ */
+/*
+ * The back pointer's meaning depends on whether the object is
+ * free (unmarked) or in use (marked):
+ * - In free objects, the back pointer is an offset from the object
+ * header back to a chunk_head_t structure that contains the location
+ * to which all the data in this chunk will get moved; the reloc field
+ * contains the amount by which the following run of useful objects
+ * will be relocated downwards.
+ * - In useful objects, the back pointer is an offset from the object
+ * back to the previous free object; the reloc field is not used (it
+ * overlays the type field).
+ * These two cases can be distinguished when scanning a chunk linearly,
+ * but when simply examining an object via a pointer, the chunk pointer
+ * is also needed.
+ */
+#define obj_flag_bits 1
+#define obj_mb_bits (arch_sizeof_int * 8 - obj_flag_bits)
+#define obj_ls_bits (obj_mb_bits - 2)
+#define o_unmarked (((uint)1 << obj_mb_bits) - 1)
+#define o_l_unmarked (o_unmarked & 3)
+#define o_set_unmarked_large(pp) (pp)->o_lmark = o_l_unmarked
+#define o_set_unmarked(pp)\
+ if ( (pp)->o_large ) o_set_unmarked_large(pp);\
+ else (pp)->o_smark = o_unmarked
+#define o_is_unmarked_large(pp) ((pp)->o_lmark == o_l_unmarked)
+#define o_is_unmarked(pp)\
+ ((pp)->o_large ? o_is_unmarked_large(pp) :\
+ ((pp)->o_smark == o_unmarked))
+#define o_untraced (((uint)1 << obj_mb_bits) - 2)
+#define o_l_untraced (o_untraced & 3)
+#define o_set_untraced(pp)\
+ if ( (pp)->o_large ) (pp)->o_lmark = o_l_untraced;\
+ else (pp)->o_smark = o_untraced
+#define o_is_untraced(pp)\
+ ((pp)->o_large ? (pp)->o_lmark == o_l_untraced :\
+ ((pp)->o_smark == o_untraced))
+#define o_marked 0
+#define o_mark_large(pp) (pp)->o_lmark = o_marked
+#define o_mark(pp)\
+ if ( (pp)->o_large ) o_mark_large(pp);\
+ else (pp)->o_smark = o_marked
+#define obj_back_shift obj_flag_bits
+#define obj_back_scale (1 << obj_back_shift)
+typedef struct obj_header_data_s {
+ union _f {
+ struct _h {
+ unsigned large:1;
+ } h;
+ struct _l {
+ unsigned _:1, lmark:2, lsize:obj_ls_bits;
+ } l;
+ struct _m {
+ unsigned _:1, smark:obj_mb_bits;
+ } m;
+ struct _b {
+ unsigned _:1, back:obj_mb_bits;
+ } b;
+ } f;
+ uint size;
+ union _t {
+ gs_memory_type_ptr_t type;
+ uint reloc;
+ } t;
+} obj_header_data_t;
+
+/*
+ * Define the alignment modulus for aligned objects. We assume all
+ * alignment values are powers of 2; we can avoid nested 'max'es that way.
+ * The final | is because back pointer values are divided by obj_back_scale,
+ * so objects must be aligned at least 0 mod obj_back_scale.
+ */
+#define obj_align_mod\
+ (((arch_align_long_mod - 1) | (arch_align_ptr_mod - 1) |\
+ (arch_align_double_mod - 1) | (align_bitmap_mod - 1) |\
+ (obj_back_scale - 1)) + 1)
+/* The only possible values for obj_align_mod are 4, 8, or 16.... */
+#if obj_align_mod == 4
+# define log2_obj_align_mod 2
+#else
+#if obj_align_mod == 8
+# define log2_obj_align_mod 3
+#else
+#if obj_align_mod == 16
+# define log2_obj_align_mod 4
+#endif
+#endif
+#endif
+#define obj_align_mask (obj_align_mod-1)
+#define obj_align_round(siz)\
+ (uint)(((siz) + obj_align_mask) & -obj_align_mod)
+#define obj_size_round(siz)\
+ obj_align_round((siz) + sizeof(obj_header_t))
+
+/* Define the real object header type, taking alignment into account. */
+struct obj_header_s { /* must be a struct because of forward reference */
+ union _d {
+ obj_header_data_t o;
+ byte _pad[round_up(sizeof(obj_header_data_t), obj_align_mod)];
+ }
+ d;
+};
+
+/* Define some reasonable abbreviations for the fields. */
+#define o_large d.o.f.h.large
+#define o_lsize d.o.f.l.lsize
+#define o_lmark d.o.f.l.lmark
+#define o_back d.o.f.b.back
+#define o_smark d.o.f.m.smark
+#define o_size d.o.size
+#define o_type d.o.t.type
+#define o_nreloc d.o.t.reloc
+
+/*
+ * The macros for getting the sizes of objects all take pointers to
+ * the object header, for use when scanning storage linearly.
+ */
+#define pre_obj_small_size(pp)\
+ ((pp)->o_size)
+
+#if arch_sizeof_long > arch_sizeof_int
+
+ /* Large objects need to use o_lsize. */
+
+#define pre_obj_large_size(pp)\
+ (((ulong)(pp)->o_lsize << (arch_sizeof_int * 8)) + (pp)->o_size)
+#define pre_obj_set_large_size(pp, lsize)\
+ ((pp)->o_lsize = (lsize) >> (arch_sizeof_int * 8),\
+ (pp)->o_size = (uint)(lsize))
+#define pre_obj_contents_size(pp)\
+ ((pp)->o_large ? pre_obj_large_size(pp) : pre_obj_small_size(pp))
+
+#else
+
+ /* Large objects don't need to use o_lsize. */
+
+#define pre_obj_large_size(pp)\
+ pre_obj_small_size(pp)
+#define pre_obj_set_large_size(pp, lsize)\
+ ((pp)->o_lsize = 0,\
+ (pp)->o_size = (lsize))
+#define pre_obj_contents_size(pp)\
+ pre_obj_small_size(pp)
+
+#endif
+
+#define pre_obj_rounded_size(pp)\
+ obj_size_round(pre_obj_contents_size(pp))
+#define pre_obj_next(pp)\
+ ((obj_header_t *)((byte *)(pp) + obj_align_round(\
+ pre_obj_contents_size(pp) + sizeof(obj_header_t) )))
+
+/*
+ * Define the header that free objects point back to when relocating.
+ * Every chunk, including inner chunks, has one of these.
+ */
+typedef struct chunk_head_s {
+ byte *dest; /* destination for objects */
+#if obj_align_mod > arch_sizeof_ptr
+ byte *_pad[obj_align_mod / arch_sizeof_ptr - 1];
+#endif
+ obj_header_t free; /* header for a free object, */
+ /* in case the first real object */
+ /* is in use */
+} chunk_head_t;
+
+#endif /* gxobj_INCLUDED */
diff --git a/pstoraster/gxop1.h b/pstoraster/gxop1.h
new file mode 100644
index 000000000..82b1cc96b
--- /dev/null
+++ b/pstoraster/gxop1.h
@@ -0,0 +1,81 @@
+/* Copyright (C) 1991, 1992, 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$ */
+/* Type 1 state shared between interpreter and compiled fonts. */
+
+#ifndef gxop1_INCLUDED
+# define gxop1_INCLUDED
+
+/*
+ * The current point (px,py) in the Type 1 interpreter state is not
+ * necessarily the same as the current position in the path being built up.
+ * Specifically, (px,py) may not reflect adjustments for hinting,
+ * whereas the current path position does reflect those adjustments.
+ */
+
+/* Define the shared Type 1 interpreter state. */
+#define max_coeff_bits 11 /* max coefficient in char space */
+typedef struct gs_op1_state_s {
+ struct gx_path_s *ppath;
+ struct gs_type1_state_s *pcis;
+ fixed_coeff fc;
+ gs_fixed_point co; /* character origin (device space) */
+ gs_fixed_point p; /* current point (device space) */
+} gs_op1_state;
+typedef gs_op1_state *is_ptr;
+
+/* Define the state used by operator procedures. */
+/* These macros refer to a current instance (s) of gs_op1_state. */
+#define sppath s.ppath
+#define sfc s.fc
+#define spt s.p
+#define ptx s.p.x
+#define pty s.p.y
+
+/* Accumulate relative coordinates */
+/****** THESE ARE NOT ACCURATE FOR NON-INTEGER DELTAS. ******/
+/* This probably doesn't make any difference in practice. */
+#define c_fixed(d, c) m_fixed(d, c, sfc, max_coeff_bits)
+#define accum_x(dx)\
+ BEGIN\
+ ptx += c_fixed(dx, xx);\
+ if ( sfc.skewed ) pty += c_fixed(dx, xy);\
+ END
+#define accum_y(dy)\
+ BEGIN\
+ pty += c_fixed(dy, yy);\
+ if ( sfc.skewed ) ptx += c_fixed(dy, yx);\
+ END
+void accum_xy_proc(P3(is_ptr ps, fixed dx, fixed dy));
+
+#define accum_xy(dx,dy)\
+ accum_xy_proc(&s, dx, dy)
+
+/* Define operator procedures. */
+int gs_op1_closepath(P1(is_ptr ps));
+int gs_op1_rrcurveto(P7(is_ptr ps, fixed dx1, fixed dy1,
+ fixed dx2, fixed dy2, fixed dx3, fixed dy3));
+
+#endif /* gxop1_INCLUDED */
diff --git a/pstoraster/gxp1fill.c b/pstoraster/gxp1fill.c
new file mode 100644
index 000000000..5c3fe1ca3
--- /dev/null
+++ b/pstoraster/gxp1fill.c
@@ -0,0 +1,374 @@
+/* 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$ */
+/* PatternType 1 filling algorithms */
+#include "math_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsrop.h"
+#include "gsmatrix.h"
+#include "gxcspace.h" /* for gscolor2.h */
+#include "gxcolor2.h"
+#include "gxdcolor.h"
+#include "gxdevcli.h"
+#include "gxdevmem.h"
+#include "gxclip2.h"
+#include "gxpcolor.h"
+#include "gxp1fill.h"
+
+/* Define the state for tile filling. */
+typedef struct tile_fill_state_s {
+
+ /* Original arguments */
+
+ const gx_device_color *pdevc; /* pattern color */
+ int x0, y0, w0, h0;
+ gs_logical_operation_t lop;
+ const gx_rop_source_t *source;
+
+ /* Variables set at initialization */
+
+ gx_device_tile_clip cdev;
+ gx_device *pcdev; /* original device or &cdev */
+ const gx_strip_bitmap *tmask;
+
+ /* Following are only for uncolored patterns */
+
+ dev_color_proc_fill_rectangle((*fill_rectangle));
+
+ /* Following are only for colored patterns */
+
+ const gx_rop_source_t *rop_source;
+ gx_device *orig_dev;
+ int xoff, yoff; /* set dynamically */
+
+} tile_fill_state_t;
+
+/* Initialize the filling state. */
+private int
+tile_fill_init(tile_fill_state_t * ptfs, const gx_device_color * pdevc,
+ gx_device * dev)
+{
+ gx_color_tile *m_tile = pdevc->mask.m_tile;
+
+ ptfs->pdevc = pdevc;
+ if (m_tile == 0) { /* no clipping */
+ ptfs->pcdev = dev;
+ return 0;
+ }
+ ptfs->pcdev = (gx_device *) & ptfs->cdev;
+ ptfs->tmask = &m_tile->tmask;
+ return tile_clip_initialize(&ptfs->cdev, ptfs->tmask, dev, 0, 0);
+}
+
+/*
+ * Fill with non-standard X and Y stepping.
+ * ptile is pdevc->colors.pattern.{m,p}_tile.
+ * tbits_or_tmask is whichever of tbits and tmask is supplying
+ * the tile size.
+ * This implementation could be sped up considerably!
+ */
+private int
+tile_by_steps(tile_fill_state_t * ptfs, int x0, int y0, int w0, int h0,
+ const gx_color_tile * ptile,
+ const gx_strip_bitmap * tbits_or_tmask,
+ int (*fill_proc) (P5(const tile_fill_state_t * ptfs,
+ int x, int y, int w, int h)))
+{
+ int x1 = x0 + w0, y1 = y0 + h0;
+ int i0, i1, j0, j1, i, j;
+ gs_matrix step_matrix; /* translated by phase */
+ int code;
+
+ ptfs->x0 = x0, ptfs->w0 = w0;
+ ptfs->y0 = y0, ptfs->h0 = h0;
+ step_matrix = ptile->step_matrix;
+ {
+ gs_rect bbox; /* bounding box in device space */
+ gs_rect ibbox; /* bounding box in stepping space */
+ double bbw = ptile->bbox.q.x - ptile->bbox.p.x;
+ double bbh = ptile->bbox.q.y - ptile->bbox.p.y;
+
+ bbox.p.x = x0, bbox.p.y = y0;
+ bbox.q.x = x1, bbox.q.y = y1;
+ gs_bbox_transform_inverse(&bbox, &step_matrix, &ibbox);
+ if_debug10('T',
+ "[T]x,y=(%d,%d) w,h=(%d,%d) => (%g,%g),(%g,%g), offset=(%g,%g)\n",
+ x0, y0, w0, h0,
+ ibbox.p.x, ibbox.p.y, ibbox.q.x, ibbox.q.y,
+ step_matrix.tx, step_matrix.ty);
+ i0 = (int)ceil(ibbox.p.x - bbw - 0.000001);
+ i1 = (int)floor(ibbox.q.x + 0.000001);
+ j0 = (int)ceil(ibbox.p.y - bbh - 0.000001);
+ j1 = (int)floor(ibbox.q.y + 0.000001);
+ }
+ if_debug4('T', "[T]i=(%d,%d) j=(%d,%d)\n", i0, i1, j0, j1);
+ for (i = i0; i <= i1; i++)
+ for (j = j0; j <= j1; j++) {
+ int x = (int)(step_matrix.xx * i +
+ step_matrix.yx * j + step_matrix.tx);
+ int y = (int)(step_matrix.xy * i +
+ step_matrix.yy * j + step_matrix.ty);
+ int w = tbits_or_tmask->size.x;
+ int h = tbits_or_tmask->size.y;
+ int xoff, yoff;
+
+ if_debug4('T', "[T]i=%d j=%d x,y=(%d,%d)", i, j, x, y);
+ if (x < x0)
+ xoff = x0 - x, x = x0, w -= xoff;
+ else
+ xoff = 0;
+ if (y < y0)
+ yoff = y0 - y, y = y0, h -= yoff;
+ else
+ yoff = 0;
+ if (x + w > x1)
+ w = x1 - x;
+ if (y + h > y1)
+ h = y1 - y;
+ if_debug6('T', "=>(%d,%d) w,h=(%d,%d) x/yoff=(%d,%d)\n",
+ x, y, w, h, xoff, yoff);
+ if (w > 0 && h > 0) {
+ if (ptfs->pcdev == (gx_device *) & ptfs->cdev)
+ tile_clip_set_phase(&ptfs->cdev,
+ imod(xoff - x, ptfs->tmask->rep_width),
+ imod(yoff - y, ptfs->tmask->rep_height));
+ /* Set the offsets for colored pattern fills */
+ ptfs->xoff = xoff;
+ ptfs->yoff = yoff;
+ code = (*fill_proc) (ptfs, x, y, w, h);
+ if (code < 0)
+ return code;
+ }
+ }
+ return 0;
+}
+
+/* Fill a rectangle with a colored Pattern. */
+/* Note that we treat this as "texture" for RasterOp. */
+private int
+tile_colored_fill(const tile_fill_state_t * ptfs,
+ int x, int y, int w, int h)
+{
+ gx_color_tile *ptile = ptfs->pdevc->colors.pattern.p_tile;
+ gs_logical_operation_t lop = ptfs->lop;
+ const gx_rop_source_t *source = ptfs->source;
+ const gx_rop_source_t *rop_source = ptfs->rop_source;
+ gx_device *dev = ptfs->orig_dev;
+ int xoff = ptfs->xoff, yoff = ptfs->yoff;
+ gx_strip_bitmap *bits = &ptile->tbits;
+ const byte *data = bits->data;
+ bool full_transfer = (w == ptfs->w0 && h == ptfs->h0);
+ gx_bitmap_id source_id =
+ (full_transfer ? rop_source->id : gx_no_bitmap_id);
+ int code;
+
+ if (source == NULL && lop_no_S_is_T(lop))
+ code = (*dev_proc(ptfs->pcdev, copy_color))
+ (ptfs->pcdev, data + bits->raster * yoff, xoff,
+ bits->raster,
+ (full_transfer ? bits->id : gx_no_bitmap_id),
+ x, y, w, h);
+ else {
+ gx_strip_bitmap data_tile;
+
+ data_tile.data = (byte *) data; /* actually const */
+ data_tile.raster = bits->raster;
+ data_tile.size.x = data_tile.rep_width = ptile->tbits.size.x;
+ data_tile.size.y = data_tile.rep_height = ptile->tbits.size.y;
+ data_tile.id = bits->id;
+ data_tile.shift = data_tile.rep_shift = 0;
+ code = (*dev_proc(dev, strip_copy_rop))
+ (dev,
+ rop_source->sdata + (y - ptfs->y0) * rop_source->sraster,
+ rop_source->sourcex + (x - ptfs->x0),
+ rop_source->sraster, source_id,
+ (rop_source->use_scolors ? rop_source->scolors : NULL),
+ &data_tile, NULL,
+ x, y, w, h,
+ imod(xoff - x, data_tile.rep_width),
+ imod(yoff - y, data_tile.rep_height),
+ lop);
+ }
+ return code;
+}
+int
+gx_dc_pattern_fill_rectangle(const gx_device_color * pdevc, int x, int y,
+ int w, int h, gx_device * dev,
+ gs_logical_operation_t lop,
+ const gx_rop_source_t * source)
+{
+ gx_color_tile *ptile = pdevc->colors.pattern.p_tile;
+ const gx_rop_source_t *rop_source = source;
+ gx_rop_source_t no_source;
+ gx_strip_bitmap *bits;
+ tile_fill_state_t state;
+ int code;
+
+ if (ptile == 0) /* null pattern */
+ return 0;
+ if (rop_source == NULL)
+ set_rop_no_source(rop_source, no_source, dev);
+ bits = &ptile->tbits;
+ code = tile_fill_init(&state, pdevc, dev);
+ if (code < 0)
+ return code;
+ if (ptile->is_simple) {
+ int px = imod(-(int)(ptile->step_matrix.tx + 0.5), bits->rep_width);
+ int py = imod(-(int)(ptile->step_matrix.ty + 0.5), bits->rep_height);
+
+ if (state.pcdev != dev)
+ tile_clip_set_phase(&state.cdev, px, py);
+ if (source == NULL && lop_no_S_is_T(lop))
+ code = (*dev_proc(state.pcdev, strip_tile_rectangle))
+ (state.pcdev, bits, x, y, w, h,
+ gx_no_color_index, gx_no_color_index, px, py);
+ else
+ code = (*dev_proc(state.pcdev, strip_copy_rop))
+ (state.pcdev,
+ rop_source->sdata, rop_source->sourcex,
+ rop_source->sraster, rop_source->id,
+ (rop_source->use_scolors ? rop_source->scolors : NULL),
+ bits, NULL, x, y, w, h, px, py, lop);
+ } else {
+ state.lop = lop;
+ state.source = source;
+ state.rop_source = rop_source;
+ state.orig_dev = dev;
+ code = tile_by_steps(&state, x, y, w, h, ptile,
+ &ptile->tbits, tile_colored_fill);
+ }
+ return code;
+}
+
+/* Fill a rectangle with an uncolored Pattern. */
+/* Note that we treat this as "texture" for RasterOp. */
+private int
+tile_masked_fill(const tile_fill_state_t * ptfs,
+ int x, int y, int w, int h)
+{
+ if (ptfs->source == NULL)
+ return (*ptfs->fill_rectangle)
+ (ptfs->pdevc, x, y, w, h, ptfs->pcdev, ptfs->lop, NULL);
+ else {
+ const gx_rop_source_t *source = ptfs->source;
+ gx_rop_source_t step_source;
+
+ step_source.sdata = source->sdata + (y - ptfs->y0) * source->sraster;
+ step_source.sourcex = source->sourcex + (x - ptfs->x0);
+ step_source.sraster = source->sraster;
+ step_source.id = (w == ptfs->w0 && h == ptfs->h0 ?
+ source->id : gx_no_bitmap_id);
+ step_source.scolors[0] = source->scolors[0];
+ step_source.scolors[1] = source->scolors[1];
+ step_source.use_scolors = source->use_scolors;
+ return (*ptfs->fill_rectangle)
+ (ptfs->pdevc, x, y, w, h, ptfs->pcdev, ptfs->lop, &step_source);
+ }
+}
+int
+gx_dc_pure_masked_fill_rect(const gx_device_color * pdevc,
+ int x, int y, int w, int h, gx_device * dev,
+ gs_logical_operation_t lop,
+ const gx_rop_source_t * source)
+{
+ gx_color_tile *ptile = pdevc->mask.m_tile;
+ tile_fill_state_t state;
+ int code;
+
+ /*
+ * This routine should never be called if there is no masking,
+ * but we leave the checks below just in case.
+ */
+ code = tile_fill_init(&state, pdevc, dev);
+ if (code < 0)
+ return code;
+ if (state.pcdev != dev) {
+ int px = imod(-(int)(ptile->step_matrix.tx + 0.5),
+ ptile->tmask.rep_width);
+ int py = imod(-(int)(ptile->step_matrix.ty + 0.5),
+ ptile->tmask.rep_height);
+
+ tile_clip_set_phase(&state.cdev, px, py);
+ }
+ if (state.pcdev == dev || ptile->is_simple)
+ return (*gx_dc_type_data_pure.fill_rectangle)
+ (pdevc, x, y, w, h, state.pcdev, lop, source);
+ else {
+ state.lop = lop;
+ state.source = source;
+ state.fill_rectangle = gx_dc_type_data_pure.fill_rectangle;
+ return tile_by_steps(&state, x, y, w, h, ptile, &ptile->tmask,
+ tile_masked_fill);
+ }
+}
+int
+gx_dc_binary_masked_fill_rect(const gx_device_color * pdevc,
+ int x, int y, int w, int h, gx_device * dev,
+ gs_logical_operation_t lop,
+ const gx_rop_source_t * source)
+{
+ gx_color_tile *ptile = pdevc->mask.m_tile;
+ tile_fill_state_t state;
+ int code;
+
+ code = tile_fill_init(&state, pdevc, dev);
+ if (code < 0)
+ return code;
+ if (state.pcdev == dev || ptile->is_simple)
+ return (*gx_dc_type_data_ht_binary.fill_rectangle)
+ (pdevc, x, y, w, h, state.pcdev, lop, source);
+ else {
+ state.lop = lop;
+ state.source = source;
+ state.fill_rectangle = gx_dc_type_data_ht_binary.fill_rectangle;
+ return tile_by_steps(&state, x, y, w, h, ptile, &ptile->tmask,
+ tile_masked_fill);
+ }
+}
+int
+gx_dc_colored_masked_fill_rect(const gx_device_color * pdevc,
+ int x, int y, int w, int h, gx_device * dev,
+ gs_logical_operation_t lop,
+ const gx_rop_source_t * source)
+{
+ gx_color_tile *ptile = pdevc->mask.m_tile;
+ tile_fill_state_t state;
+ int code;
+
+ code = tile_fill_init(&state, pdevc, dev);
+ if (code < 0)
+ return code;
+ if (state.pcdev == dev || ptile->is_simple)
+ return (*gx_dc_type_data_ht_colored.fill_rectangle)
+ (pdevc, x, y, w, h, state.pcdev, lop, source);
+ else {
+ state.lop = lop;
+ state.source = source;
+ state.fill_rectangle = gx_dc_type_data_ht_colored.fill_rectangle;
+ return tile_by_steps(&state, x, y, w, h, ptile, &ptile->tmask,
+ tile_masked_fill);
+ }
+}
diff --git a/pstoraster/gxp1fill.h b/pstoraster/gxp1fill.h
new file mode 100644
index 000000000..5a35d8c44
--- /dev/null
+++ b/pstoraster/gxp1fill.h
@@ -0,0 +1,40 @@
+/* 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$ */
+/* PatternType 1 filling algorithm interface */
+
+#ifndef gxp1fill_INCLUDED
+# define gxp1fill_INCLUDED
+
+/*
+ * We use 'masked_fill_rect' instead of 'masked_fill_rectangle'
+ * in order to limit identifier lengths to 32 characters.
+ */
+dev_color_proc_fill_rectangle(gx_dc_pattern_fill_rectangle);
+dev_color_proc_fill_rectangle(gx_dc_pure_masked_fill_rect);
+dev_color_proc_fill_rectangle(gx_dc_binary_masked_fill_rect);
+dev_color_proc_fill_rectangle(gx_dc_colored_masked_fill_rect);
+
+#endif /* gxp1fill_INCLUDED */
diff --git a/pstoraster/gxpageq.h b/pstoraster/gxpageq.h
new file mode 100644
index 000000000..cd0100c8f
--- /dev/null
+++ b/pstoraster/gxpageq.h
@@ -0,0 +1,192 @@
+/* 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$ */
+/* Page queue implementation */
+
+/* Initial version 2/1/98 by John Desrosiers (soho@crl.com) */
+/* 7/17/98 L. Peter Deutsch (ghost@aladdin.com) edited to conform to
+ Ghostscript coding standards */
+/* 8/7/98 ghost@aladdin.com fixed bugs in #define st_... statements */
+
+#ifndef gxpageq_INCLUDED
+# define gxpageq_INCLUDED
+
+# include "gsmemory.h"
+# include "gxband.h"
+# include "gxsync.h"
+
+/* --------------- Data type definitions --------------------- */
+
+typedef enum {
+ gx_page_queue_action_partial_page,
+ gx_page_queue_action_full_page,
+ gx_page_queue_action_copy_page,
+ gx_page_queue_action_terminate
+} gx_page_queue_action_t;
+
+#ifndef gx_page_queue_DEFINED
+# define gx_page_queue_DEFINED
+typedef struct gx_page_queue_s gx_page_queue;
+#endif
+
+/*
+ * Define a page queue entry object.
+ */
+typedef struct gx_page_queue_entry_s {
+ gx_band_page_info page_info;
+ gx_page_queue_action_t action; /* action code */
+ int num_copies; /* number of copies to render */
+ struct gx_page_queue_entry_s *next; /* link to next in queue */
+ gx_page_queue *queue; /* link to queue the entry is in */
+} gx_page_queue_entry;
+
+#define private_st_gx_page_queue_entry()\
+ gs_private_st_ptrs2(st_gx_page_queue_entry, gx_page_queue_entry,\
+ "gx_page_queue_entry",\
+ gx_page_queue_entry_enum_ptrs, gx_page_queue_entry_reloc_ptrs,\
+ next, queue)
+
+/*
+ * Define the structure used to manage a page queue
+ * A page queue is a monitor-locked FIFO which holds completed command
+ * list files ready for rendering.
+ */
+struct gx_page_queue_s {
+ gs_memory_t *memory; /* allocator used to allocate entries */
+ gx_monitor_t *monitor; /* used to serialize access to this structure */
+ int entry_count; /* # elements in page_queue */
+ bool dequeue_in_progress; /* true between start/ & end_dequeue */
+ gx_semaphore_t *render_req_sema; /* sema signalled when page queued */
+ bool enable_render_done_signal; /* enable signals to render_done_sema */
+ gx_semaphore_t *render_done_sema; /* semaphore signaled when (partial) page rendered */
+ gx_page_queue_entry *last_in; /* if <> 0, Last-in queue entry */
+ gx_page_queue_entry *first_in; /* if <> 0, First-in queue entry */
+ gx_page_queue_entry *reserve_entry; /* spare allocation */
+};
+
+#define private_st_gx_page_queue()\
+ gs_private_st_ptrs4(st_gx_page_queue, gx_page_queue, "gx_page_queue",\
+ gx_page_queue_enum_ptrs, gx_page_queue_reloc_ptrs,\
+ monitor, first_in, last_in, reserve_entry);
+
+/* -------------- Public Procedure Declaraions --------------------- */
+
+/* Allocate a page queue. */
+gx_page_queue *gx_page_queue_alloc(P1(gs_memory_t *mem));
+
+/* All page queue entries must be allocated by this routine. Allocated */
+/* entries are initialized & ready to go */
+/* rets ptr to allocated object, 0 if VM error */
+gx_page_queue_entry *
+gx_page_queue_entry_alloc(P1(
+ gx_page_queue * queue /* queue that entry is being alloc'd for */
+ ));
+
+/* All page queues entries must be destroyed by this routine */
+void gx_page_queue_entry_free(P1(
+ gx_page_queue_entry * entry /* entry to free up */
+ ));
+
+/* Init a page queue; this must be done before it can be used. This routine */
+/* allocates & inits various necessary structures and will fail if insufficient */
+/* memory is available. */
+/* -ve error code, or 0 */
+int gx_page_queue_init(P2(
+ gx_page_queue * queue, /* page queue to init */
+ gs_memory_t * memory /* allocator for dynamic memory */
+ ));
+
+/* Destroy a page queue which was initialized by gx_page_queue_init. Any */
+/* page queue entries in the queue are released and destroyed; dynamic */
+/* allocations are released. */
+void gx_page_queue_dnit(P1(
+ gx_page_queue * queue /* page queue to dnit */
+ ));
+
+/* If there are any pages in queue, wait until one of them finishes rendering. */
+/* Typically called by writer's out-of-memory error handlers that want to wait */
+/* until some memory has been freed. */
+/* rets 0 if no pages were waiting for rendering, 1 if actually waited */
+int gx_page_queue_wait_one_page(P1(
+ gx_page_queue * queue /* queue to wait on */
+ ));
+
+/* Wait until all (if any) pages in queue have finished rendering. Typically */
+/* called by writer operations which need to drain the page queue before */
+/* continuing. */
+void gx_page_queue_wait_until_empty(P1(
+ gx_page_queue * queue /* page queue to wait on */
+ ));
+
+/* Add a pageq queue entry to the end of the page queue. If an unsatisfied */
+/* reader thread has an outstanding gx_page_queue_start_deque(), wake it up. */
+void gx_page_queue_enqueue(P1(
+ gx_page_queue_entry * entry /* entry to add */
+ ));
+
+/* Allocate & construct a pageq entry, then to the end of the pageq as */
+/* in gx_page_queue_enqueue. If unable to allocate a new pageq entry, uses */
+/* the pre-allocated reserve entry held in the pageq. When using the reserve */
+/* pageq entry, wait until enough pages have been rendered to allocate a new */
+/* reserve for next time -- this should always succeed & returns eFatal if not. */
+/* Unless the reserve was used, does not wait for any rendering to complete. */
+/* Typically called by writer when it has a (partial) page ready for rendering. */
+/* rets 0 ok, gs_error_Fatal if error */
+int gx_page_queue_add_page(P4(
+ gx_page_queue * queue, /* page queue to add to */
+ gx_page_queue_action_t action, /* action code to queue */
+ const gx_band_page_info * page_info, /* bandinfo incl. bandlist */
+ int page_count /* # of copies to print if final "print,"
+ /* 0 if partial page, -1 if cancel */
+ ));
+
+/* Retrieve the least-recently added queue entry from the pageq. If no */
+/* entry is available, waits on a signal from gx_page_queue_enqueue. Must */
+/* eventually be followed by a call to gx_page_queue_finish_dequeue for the */
+/* same pageq entry. */
+/* Even though the pageq is actually removed from the pageq, a mark is made in */
+/* the pageq to indicate that the pageq is not "empty" until the */
+/* gx_page_queue_finish_dequeue; this is for the benefit of */
+/* gx_page_queue_wait_???, since the completing the current page's rendering */
+/* may free more memory. */
+/* Typically called by renderer thread loop, which looks like: */
+/* do */
+/* { gx_page_queue_start_deqeueue(...); */
+/* render_retrieved_entry(...); */
+/* gx_page_queue_finish_dequeue(...); */
+/* } */
+/* while (some condition); */
+gx_page_queue_entry * /* removed entry */
+gx_page_queue_start_dequeue(P1(
+ gx_page_queue * queue /* page queue to retrieve from */
+ ));
+
+/* Free the pageq entry, then signal any waiting threads. */
+/* Typically used to indicate completion of rendering the pageq entry. */
+void gx_page_queue_finish_dequeue(P1(
+ gx_page_queue_entry * entry /* entry that was retrieved to delete */
+ ));
+
+#endif /*!defined(gxpageq_h_INCLUDED) */
diff --git a/pstoraster/gxpaint.c b/pstoraster/gxpaint.c
new file mode 100644
index 000000000..3ac973619
--- /dev/null
+++ b/pstoraster/gxpaint.c
@@ -0,0 +1,81 @@
+/* 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$ */
+/* Graphics-state-aware fill and stroke procedures */
+#include "gx.h"
+#include "gzstate.h"
+#include "gxdevice.h"
+#include "gxhttile.h"
+#include "gxpaint.h"
+#include "gxpath.h"
+
+/* Fill a path. */
+int
+gx_fill_path(gx_path * ppath, gx_device_color * pdevc, gs_state * pgs,
+ int rule, fixed adjust_x, fixed adjust_y)
+{
+ gx_device *dev = gs_currentdevice_inline(pgs);
+ gx_clip_path *pcpath;
+ int code = gx_effective_clip_path(pgs, &pcpath);
+ gx_fill_params params;
+
+ if (code < 0)
+ return code;
+ params.rule = rule;
+ params.adjust.x = adjust_x;
+ params.adjust.y = adjust_y;
+ params.flatness = (pgs->in_cachedevice > 1 ? 0.0 : pgs->flatness);
+ params.fill_zero_width = (adjust_x | adjust_y) != 0;
+ return (*dev_proc(dev, fill_path))
+ (dev, (const gs_imager_state *)pgs, ppath, &params, pdevc, pcpath);
+}
+
+/* Stroke a path for drawing or saving. */
+int
+gx_stroke_fill(gx_path * ppath, gs_state * pgs)
+{
+ gx_device *dev = gs_currentdevice_inline(pgs);
+ gx_clip_path *pcpath;
+ int code = gx_effective_clip_path(pgs, &pcpath);
+ gx_stroke_params params;
+
+ if (code < 0)
+ return code;
+ params.flatness = (pgs->in_cachedevice > 1 ? 0.0 : pgs->flatness);
+ return (*dev_proc(dev, stroke_path))
+ (dev, (const gs_imager_state *)pgs, ppath, &params,
+ pgs->dev_color, pcpath);
+}
+
+int
+gx_stroke_add(gx_path * ppath, gx_path * to_path, gs_state * pgs)
+{
+ gx_stroke_params params;
+
+ params.flatness = (pgs->in_cachedevice > 1 ? 0.0 : pgs->flatness);
+ return gx_stroke_path_only(ppath, to_path, pgs->device,
+ (const gs_imager_state *)pgs,
+ &params, NULL, NULL);
+}
diff --git a/pstoraster/gxpaint.h b/pstoraster/gxpaint.h
new file mode 100644
index 000000000..17afc1d05
--- /dev/null
+++ b/pstoraster/gxpaint.h
@@ -0,0 +1,125 @@
+/* Copyright (C) 1994, 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$ */
+/* Requires gsropt.h, gxfixed.h, gxpath.h */
+
+#ifndef gxpaint_INCLUDED
+# define gxpaint_INCLUDED
+
+#ifndef gs_imager_state_DEFINED
+# define gs_imager_state_DEFINED
+typedef struct gs_imager_state_s gs_imager_state;
+
+#endif
+
+#ifndef gs_state_DEFINED
+# define gs_state_DEFINED
+typedef struct gs_state_s gs_state;
+
+#endif
+
+#ifndef gx_device_DEFINED
+# define gx_device_DEFINED
+typedef struct gx_device_s gx_device;
+
+#endif
+
+#ifndef gx_device_color_DEFINED
+# define gx_device_color_DEFINED
+typedef struct gx_device_color_s gx_device_color;
+
+#endif
+
+/* ------ Graphics-state-aware procedures ------ */
+
+/*
+ * The following procedures use information from the graphics state.
+ * They are implemented in gxpaint.c.
+ */
+
+int gx_fill_path(P6(gx_path * ppath, gx_device_color * pdevc, gs_state * pgs,
+ int rule, fixed adjust_x, fixed adjust_y));
+int gx_stroke_fill(P2(gx_path * ppath, gs_state * pgs));
+int gx_stroke_add(P3(gx_path * ppath, gx_path * to_path, gs_state * pgs));
+
+/* ------ Imager procedures ------ */
+
+/*
+ * Tweak the fill adjustment if necessary so that (nearly) empty
+ * rectangles are guaranteed to produce some output.
+ */
+void gx_adjust_if_empty(P2(const gs_fixed_rect *, gs_fixed_point *));
+
+/*
+ * Compute the amount by which to expand a stroked bounding box to account
+ * for line width, caps and joins. If the amount is too large to fit in
+ * a gs_fixed_point, return gs_error_limitcheck.
+ */
+int gx_stroke_path_expansion(P3(const gs_imager_state *,
+ const gx_path *, gs_fixed_point *));
+
+/* Backward compatibility */
+#define gx_stroke_expansion(pis, ppt)\
+ gx_stroke_path_expansion(pis, (const gx_path *)0, ppt)
+
+/*
+ * The following procedures do not need a graphics state.
+ * These procedures are implemented in gxfill.c and gxstroke.c.
+ */
+
+/* Define the parameters passed to the imager's filling routine. */
+#ifndef gx_fill_params_DEFINED
+# define gx_fill_params_DEFINED
+typedef struct gx_fill_params_s gx_fill_params;
+
+#endif
+struct gx_fill_params_s {
+ int rule; /* -1 = winding #, 1 = even/odd */
+ gs_fixed_point adjust;
+ float flatness;
+ bool fill_zero_width; /* if true, make zero-width/height */
+ /* rectangles one pixel wide/high */
+};
+
+#define gx_fill_path_only(ppath, dev, pis, params, pdevc, pcpath)\
+ (*dev_proc(dev, fill_path))(dev, pis, ppath, params, pdevc, pcpath)
+
+/* Define the parameters passed to the imager's stroke routine. */
+#ifndef gx_stroke_params_DEFINED
+# define gx_stroke_params_DEFINED
+typedef struct gx_stroke_params_s gx_stroke_params;
+
+#endif
+struct gx_stroke_params_s {
+ float flatness;
+};
+
+int gx_stroke_path_only(P7(gx_path * ppath, gx_path * to_path, gx_device * dev,
+ const gs_imager_state * pis,
+ const gx_stroke_params * params,
+ const gx_device_color * pdevc,
+ const gx_clip_path * pcpath));
+
+#endif /* gxpaint_INCLUDED */
diff --git a/pstoraster/gxpath.c b/pstoraster/gxpath.c
new file mode 100644
index 000000000..bf94c2299
--- /dev/null
+++ b/pstoraster/gxpath.c
@@ -0,0 +1,829 @@
+/* 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$ */
+/* Internal path management routines for Ghostscript library */
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gxfixed.h"
+#include "gzpath.h"
+
+/* These routines all assume that all points are */
+/* already in device coordinates, and in fixed representation. */
+/* As usual, they return either 0 or a (negative) error code. */
+
+/* Forward references */
+private int path_alloc_copy(P1(gx_path *));
+private int gx_path_new_subpath(P1(gx_path *));
+
+#ifdef DEBUG
+private void gx_print_segment(P1(const segment *));
+
+# define trace_segment(msg, pseg)\
+ if ( gs_debug_c('P') ) dlprintf(msg), gx_print_segment(pseg);
+#else
+# define trace_segment(msg, pseg) DO_NOTHING
+#endif
+
+/* Check a point against a preset bounding box. */
+#define outside_bbox(ppath, px, py)\
+ (px < ppath->bbox.p.x || px > ppath->bbox.q.x ||\
+ py < ppath->bbox.p.y || py > ppath->bbox.q.y)
+#define check_in_bbox(ppath, px, py)\
+ if ( outside_bbox(ppath, px, py) )\
+ return_error(gs_error_rangecheck)
+
+/* Structure descriptors for paths and path segment types. */
+public_st_path();
+private_st_path_segments();
+private_st_segment();
+private_st_line();
+private_st_line_close();
+private_st_curve();
+private_st_subpath();
+
+/* ------ Initialize/free paths ------ */
+
+private rc_free_proc(rc_free_path_segments);
+private rc_free_proc(rc_free_path_segments_local);
+
+private void
+gx_path_init_contents(gx_path * ppath)
+{
+ ppath->box_last = 0;
+ ppath->first_subpath = ppath->current_subpath = 0;
+ ppath->subpath_count = 0;
+ ppath->curve_count = 0;
+ path_update_newpath(ppath);
+ ppath->bbox_set = 0;
+}
+
+/*
+ * Initialize a path contained in an already-heap-allocated object,
+ * optionally allocating its segments.
+ */
+private int
+path_alloc_segments(gx_path_segments ** ppsegs, gs_memory_t * mem,
+ client_name_t cname)
+{
+ rc_alloc_struct_1(*ppsegs, gx_path_segments, &st_path_segments,
+ mem, return_error(gs_error_VMerror), cname);
+ (*ppsegs)->rc.free = rc_free_path_segments;
+ return 0;
+}
+int
+gx_path_init_contained_shared(gx_path * ppath, const gx_path * shared,
+ gs_memory_t * mem, client_name_t cname)
+{
+ if (shared) {
+ if (shared->segments == &shared->local_segments) {
+ lprintf1("Attempt to share (local) segments of path 0x%lx!\n",
+ (ulong) shared);
+ return_error(gs_error_Fatal);
+ }
+ *ppath = *shared;
+ rc_increment(ppath->segments);
+ } else {
+ int code = path_alloc_segments(&ppath->segments, mem, cname);
+
+ if (code < 0)
+ return code;
+ gx_path_init_contents(ppath);
+ }
+ ppath->memory = mem;
+ ppath->allocation = path_allocated_contained;
+ return 0;
+}
+
+/*
+ * Allocate a path on the heap, and initialize it. If shared is NULL,
+ * allocate a segments object; if shared is an existing path, share its
+ * segments.
+ */
+gx_path *
+gx_path_alloc_shared(const gx_path * shared, gs_memory_t * mem,
+ client_name_t cname)
+{
+ gx_path *ppath = gs_alloc_struct(mem, gx_path, &st_path, cname);
+
+ if (ppath == 0)
+ return 0;
+ if (shared) {
+ if (shared->segments == &shared->local_segments) {
+ lprintf1("Attempt to share (local) segments of path 0x%lx!\n",
+ (ulong) shared);
+ gs_free_object(mem, ppath, cname);
+ return 0;
+ }
+ *ppath = *shared;
+ rc_increment(ppath->segments);
+ } else {
+ int code = path_alloc_segments(&ppath->segments, mem, cname);
+
+ if (code < 0) {
+ gs_free_object(mem, ppath, cname);
+ return 0;
+ }
+ gx_path_init_contents(ppath);
+ }
+ ppath->memory = mem;
+ ppath->allocation = path_allocated_on_heap;
+ return ppath;
+}
+
+/*
+ * Initialize a stack-allocated path. This doesn't allocate anything,
+ * but may still share the segments.
+ */
+int
+gx_path_init_local_shared(gx_path * ppath, const gx_path * shared,
+ gs_memory_t * mem)
+{
+ if (shared) {
+ if (shared->segments == &shared->local_segments) {
+ lprintf1("Attempt to share (local) segments of path 0x%lx!\n",
+ (ulong) shared);
+ return_error(gs_error_Fatal);
+ }
+ *ppath = *shared;
+ rc_increment(ppath->segments);
+ } else {
+ rc_init_free(&ppath->local_segments, mem, 1,
+ rc_free_path_segments_local);
+ ppath->segments = &ppath->local_segments;
+ gx_path_init_contents(ppath);
+ }
+ ppath->memory = mem;
+ ppath->allocation = path_allocated_on_stack;
+ return 0;
+}
+
+/*
+ * Ensure that a path owns its segments, by copying the segments if
+ * they currently have multiple references.
+ */
+int
+gx_path_unshare(gx_path * ppath)
+{
+ int code = 0;
+
+ if (gx_path_is_shared(ppath))
+ code = path_alloc_copy(ppath);
+ return code;
+}
+
+/*
+ * Free a path by releasing its segments if they have no more references.
+ * This also frees the path object iff it was allocated by gx_path_alloc.
+ */
+void
+gx_path_free(gx_path * ppath, client_name_t cname)
+{
+ rc_decrement(ppath->segments, cname);
+ /* Clean up pointers for GC. */
+ ppath->box_last = 0;
+ ppath->segments = 0; /* Nota bene */
+ if (ppath->allocation == path_allocated_on_heap)
+ gs_free_object(ppath->memory, ppath, cname);
+}
+
+/*
+ * Assign one path to another, adjusting reference counts appropriately.
+ * Note that this requires that segments of the two paths (but not the path
+ * objects themselves) were allocated with the same allocator. Note also
+ * that since it does the equivalent of a gx_path_new(ppto), it may allocate
+ * a new segments object for ppto.
+ */
+int
+gx_path_assign_preserve(gx_path * ppto, gx_path * ppfrom)
+{
+ gx_path_segments *fromsegs = ppfrom->segments;
+ gx_path_segments *tosegs = ppto->segments;
+ gs_memory_t *mem = ppto->memory;
+ gx_path_allocation_t allocation = ppto->allocation;
+
+ if (fromsegs == &ppfrom->local_segments) {
+ /* We can't use ppfrom's segments object. */
+ if (tosegs == &ppto->local_segments || gx_path_is_shared(ppto)) {
+ /* We can't use ppto's segments either. Allocate a new one. */
+ int code = path_alloc_segments(&tosegs, ppto->memory,
+ "gx_path_assign");
+
+ if (code < 0)
+ return code;
+ rc_decrement(ppto->segments, "gx_path_assign");
+ } else {
+ /* Use ppto's segments object. */
+ rc_free_path_segments_local(tosegs->rc.memory, tosegs,
+ "gx_path_assign");
+ }
+ tosegs->contents = fromsegs->contents;
+ ppfrom->segments = tosegs;
+ rc_increment(tosegs); /* for reference from ppfrom */
+ } else {
+ /* We can use ppfrom's segments object. */
+ rc_increment(fromsegs);
+ rc_decrement(tosegs, "gx_path_assign");
+ }
+ *ppto = *ppfrom;
+ ppto->memory = mem;
+ ppto->allocation = allocation;
+ return 0;
+}
+
+/*
+ * Assign one path to another and free the first path at the same time.
+ * (This may do less work than assign_preserve + free.)
+ */
+int
+gx_path_assign_free(gx_path * ppto, gx_path * ppfrom)
+{ /*
+ * Detect the special case where both paths have non-shared local
+ * segments, since we can avoid allocating new segments in this
+ * case.
+ */
+ if (ppto->segments == &ppto->local_segments &&
+ ppfrom->segments == &ppfrom->local_segments &&
+ !gx_path_is_shared(ppto)
+ ) {
+#define fromsegs (&ppfrom->local_segments)
+#define tosegs (&ppto->local_segments)
+ gs_memory_t *mem = ppto->memory;
+ gx_path_allocation_t allocation = ppto->allocation;
+
+ rc_free_path_segments_local(tosegs->rc.memory, tosegs,
+ "gx_path_assign_free");
+ /* We record a bogus reference to fromsegs, which */
+ /* gx_path_free will undo. */
+ *ppto = *ppfrom;
+ rc_increment(fromsegs);
+ ppto->segments = tosegs;
+ ppto->memory = mem;
+ ppto->allocation = allocation;
+#undef fromsegs
+#undef tosegs
+ } else {
+ /* In all other cases, just do assign + free. */
+ int code = gx_path_assign_preserve(ppto, ppfrom);
+
+ if (code < 0)
+ return code;
+ }
+ gx_path_free(ppfrom, "gx_path_assign_free");
+ return 0;
+}
+
+/*
+ * Free the segments of a path when their reference count goes to zero.
+ * We do this in reverse order so as to maximize LIFO allocator behavior.
+ * We don't have to worry about cleaning up pointers, because we're about
+ * to free the segments object.
+ */
+private void
+rc_free_path_segments_local(gs_memory_t * mem, void *vpsegs,
+ client_name_t cname)
+{
+ gx_path_segments *psegs = (gx_path_segments *) vpsegs;
+ segment *pseg;
+
+ if (psegs->contents.subpath_first == 0)
+ return; /* empty path */
+ pseg = (segment *) psegs->contents.subpath_current->last;
+ while (pseg) {
+ segment *prev = pseg->prev;
+
+ trace_segment("[P]release", pseg);
+ gs_free_object(mem, pseg, cname);
+ pseg = prev;
+ }
+}
+private void
+rc_free_path_segments(gs_memory_t * mem, void *vpsegs, client_name_t cname)
+{
+ rc_free_path_segments_local(mem, vpsegs, cname);
+ gs_free_object(mem, vpsegs, cname);
+}
+
+/* ------ Incremental path building ------ */
+
+/* Guarantee that a path's segments are not shared with any other path. */
+#define path_unshare(ppath)\
+ BEGIN\
+ if ( gx_path_is_shared(ppath) ) {\
+ int code_;\
+ if( (code_ = path_alloc_copy(ppath)) < 0 ) return code_;\
+ }\
+ END
+
+/* Macro for opening the current subpath. */
+/* ppath points to the path; sets psub to ppath->current_subpath. */
+#define path_open()\
+ BEGIN\
+ if ( !path_is_drawing(ppath) ) {\
+ int code_;\
+ if ( !path_position_valid(ppath) )\
+ return_error(gs_error_nocurrentpoint);\
+ code_ = gx_path_new_subpath(ppath);\
+ if ( code_ < 0 ) return code_;\
+ }\
+ END
+
+/* Macros for allocating path segments. */
+/* Note that they assume that ppath points to the path. */
+/* We have to split the macro into two because of limitations */
+/* on the size of a single statement (sigh). */
+#define path_alloc_segment(pseg,ctype,pstype,stype,snotes,cname)\
+ path_unshare(ppath);\
+ psub = ppath->current_subpath;\
+ if( !(pseg = gs_alloc_struct(ppath->memory, ctype, pstype, cname)) )\
+ return_error(gs_error_VMerror);\
+ pseg->type = stype, pseg->notes = snotes, pseg->next = 0
+#define path_alloc_link(pseg)\
+ { segment *prev = psub->last;\
+ prev->next = (segment *)pseg;\
+ pseg->prev = prev;\
+ psub->last = (segment *)pseg;\
+ }
+
+/* Make a new path (newpath). */
+int
+gx_path_new(gx_path * ppath)
+{
+ gx_path_segments *psegs = ppath->segments;
+
+ if (gx_path_is_shared(ppath)) {
+ int code = path_alloc_segments(&ppath->segments, ppath->memory,
+ "gx_path_new");
+
+ if (code < 0)
+ return code;
+ rc_decrement(psegs, "gx_path_new");
+ } else {
+ rc_free_path_segments_local(psegs->rc.memory, psegs, "gx_path_new");
+ }
+ gx_path_init_contents(ppath);
+ return 0;
+}
+
+/* Open a new subpath. */
+/* The client must invoke path_update_xxx. */
+private int
+gx_path_new_subpath(gx_path * ppath)
+{
+ subpath *psub;
+ subpath *spp;
+
+ path_alloc_segment(spp, subpath, &st_subpath, s_start, sn_none,
+ "gx_path_new_subpath");
+ spp->last = (segment *) spp;
+ spp->curve_count = 0;
+ spp->is_closed = 0;
+ spp->pt = ppath->position;
+ if (!psub) { /* first subpath */
+ ppath->first_subpath = spp;
+ spp->prev = 0;
+ } else {
+ segment *prev = psub->last;
+
+ prev->next = (segment *) spp;
+ spp->prev = prev;
+ }
+ ppath->current_subpath = spp;
+ ppath->subpath_count++;
+ trace_segment("[P]", (const segment *)spp);
+ return 0;
+}
+
+/* Add a point to the current path (moveto). */
+int
+gx_path_add_point(gx_path * ppath, fixed x, fixed y)
+{
+ if (ppath->bbox_set)
+ check_in_bbox(ppath, x, y);
+ ppath->position.x = x;
+ ppath->position.y = y;
+ path_update_moveto(ppath);
+ return 0;
+}
+
+/* Add a relative point to the current path (rmoveto). */
+int
+gx_path_add_relative_point(gx_path * ppath, fixed dx, fixed dy)
+{
+ if (!path_position_in_range(ppath))
+ return_error((path_position_valid(ppath) ? gs_error_limitcheck :
+ gs_error_nocurrentpoint));
+ {
+ fixed nx = ppath->position.x + dx, ny = ppath->position.y + dy;
+
+ /* Check for overflow in addition. */
+ if (((nx ^ dx) < 0 && (ppath->position.x ^ dx) >= 0) ||
+ ((ny ^ dy) < 0 && (ppath->position.y ^ dy) >= 0)
+ )
+ return_error(gs_error_limitcheck);
+ if (ppath->bbox_set)
+ check_in_bbox(ppath, nx, ny);
+ ppath->position.x = nx;
+ ppath->position.y = ny;
+ }
+ path_update_moveto(ppath);
+ return 0;
+}
+
+/* Set the segment point and the current point in the path. */
+/* Assumes ppath points to the path. */
+#define path_set_point(pseg, fx, fy)\
+ (pseg)->pt.x = ppath->position.x = (fx),\
+ (pseg)->pt.y = ppath->position.y = (fy)
+
+/* Add a line to the current path (lineto). */
+int
+gx_path_add_line_notes(gx_path * ppath, fixed x, fixed y, segment_notes notes)
+{
+ subpath *psub;
+ line_segment *lp;
+
+ if (ppath->bbox_set)
+ check_in_bbox(ppath, x, y);
+ path_open();
+ path_alloc_segment(lp, line_segment, &st_line, s_line, notes,
+ "gx_path_add_line");
+ path_alloc_link(lp);
+ path_set_point(lp, x, y);
+ path_update_draw(ppath);
+ trace_segment("[P]", (segment *) lp);
+ return 0;
+}
+
+/* Add multiple lines to the current path. */
+/* Note that all lines have the same notes. */
+int
+gx_path_add_lines_notes(gx_path * ppath, const gs_fixed_point * ppts, int count,
+ segment_notes notes)
+{
+ subpath *psub;
+ segment *prev;
+ line_segment *lp = 0;
+ int i;
+ int code = 0;
+
+ if (count <= 0)
+ return 0;
+ path_unshare(ppath);
+ path_open();
+ psub = ppath->current_subpath;
+ prev = psub->last;
+ /* We could do better than the following, but this is a start. */
+ /* Note that we don't make any attempt to undo partial additions */
+ /* if we fail partway through; this is equivalent to what would */
+ /* happen with multiple calls on gx_path_add_line. */
+ for (i = 0; i < count; i++) {
+ fixed x = ppts[i].x;
+ fixed y = ppts[i].y;
+ line_segment *next;
+
+ if (ppath->bbox_set && outside_bbox(ppath, x, y)) {
+ code = gs_note_error(gs_error_rangecheck);
+ break;
+ }
+ if (!(next = gs_alloc_struct(ppath->memory, line_segment,
+ &st_line, "gx_path_add_lines"))
+ ) {
+ code = gs_note_error(gs_error_VMerror);
+ break;
+ }
+ lp = next;
+ lp->type = s_line;
+ lp->notes = notes;
+ prev->next = (segment *) lp;
+ lp->prev = prev;
+ lp->pt.x = x;
+ lp->pt.y = y;
+ prev = (segment *) lp;
+ trace_segment("[P]", (segment *) lp);
+ }
+ if (lp != 0)
+ ppath->position.x = lp->pt.x,
+ ppath->position.y = lp->pt.y,
+ psub->last = (segment *) lp,
+ lp->next = 0,
+ path_update_draw(ppath);
+ return code;
+}
+
+/* Add a rectangle to the current path. */
+/* This is a special case of adding a closed polygon. */
+int
+gx_path_add_rectangle(gx_path * ppath, fixed x0, fixed y0, fixed x1, fixed y1)
+{
+ gs_fixed_point pts[3];
+ int code;
+
+ pts[0].x = x0;
+ pts[1].x = pts[2].x = x1;
+ pts[2].y = y0;
+ pts[0].y = pts[1].y = y1;
+ if ((code = gx_path_add_point(ppath, x0, y0)) < 0 ||
+ (code = gx_path_add_lines(ppath, pts, 3)) < 0 ||
+ (code = gx_path_close_subpath(ppath)) < 0
+ )
+ return code;
+ return 0;
+}
+
+/* Add a curve to the current path (curveto). */
+int
+gx_path_add_curve_notes(gx_path * ppath,
+ fixed x1, fixed y1, fixed x2, fixed y2, fixed x3, fixed y3,
+ segment_notes notes)
+{
+ subpath *psub;
+ curve_segment *lp;
+
+ if (ppath->bbox_set) {
+ check_in_bbox(ppath, x1, y1);
+ check_in_bbox(ppath, x2, y2);
+ check_in_bbox(ppath, x3, y3);
+ }
+ path_open();
+ path_alloc_segment(lp, curve_segment, &st_curve, s_curve, notes,
+ "gx_path_add_curve");
+ path_alloc_link(lp);
+ lp->p1.x = x1;
+ lp->p1.y = y1;
+ lp->p2.x = x2;
+ lp->p2.y = y2;
+ path_set_point(lp, x3, y3);
+ psub->curve_count++;
+ ppath->curve_count++;
+ path_update_draw(ppath);
+ trace_segment("[P]", (segment *) lp);
+ return 0;
+}
+
+/*
+ * Add an approximation of an arc to the current path.
+ * The current point of the path is the initial point of the arc;
+ * parameters are the final point of the arc
+ * and the point at which the extended tangents meet.
+ * We require that the arc be less than a semicircle.
+ * The arc may go either clockwise or counterclockwise.
+ * The approximation is a very simple one: a single curve
+ * whose other two control points are a fraction F of the way
+ * to the intersection of the tangents, where
+ * F = (4/3)(1 / (1 + sqrt(1+(d/r)^2)))
+ * where r is the radius and d is the distance from either tangent
+ * point to the intersection of the tangents. This produces
+ * a curve whose center point, as well as its ends, lies on
+ * the desired arc.
+ *
+ * Because F has to be computed in user space, we let the client
+ * compute it and pass it in as an argument.
+ */
+int
+gx_path_add_partial_arc_notes(gx_path * ppath,
+fixed x3, fixed y3, fixed xt, fixed yt, floatp fraction, segment_notes notes)
+{
+ fixed x0 = ppath->position.x, y0 = ppath->position.y;
+
+ return gx_path_add_curve_notes(ppath,
+ x0 + (fixed) ((xt - x0) * fraction),
+ y0 + (fixed) ((yt - y0) * fraction),
+ x3 + (fixed) ((xt - x3) * fraction),
+ y3 + (fixed) ((yt - y3) * fraction),
+ x3, y3, notes | sn_from_arc);
+}
+
+/* Append a path to another path, and reset the first path. */
+/* Currently this is only used to append a path to its parent */
+/* (the path in the previous graphics context). */
+int
+gx_path_add_path(gx_path * ppath, gx_path * ppfrom)
+{
+ path_unshare(ppfrom);
+ path_unshare(ppath);
+ if (ppfrom->first_subpath) { /* i.e. ppfrom not empty */
+ if (ppath->first_subpath) { /* i.e. ppath not empty */
+ subpath *psub = ppath->current_subpath;
+ segment *pseg = psub->last;
+ subpath *pfsub = ppfrom->first_subpath;
+
+ pseg->next = (segment *) pfsub;
+ pfsub->prev = pseg;
+ } else
+ ppath->first_subpath = ppfrom->first_subpath;
+ ppath->current_subpath = ppfrom->current_subpath;
+ ppath->subpath_count += ppfrom->subpath_count;
+ ppath->curve_count += ppfrom->curve_count;
+ }
+ /* Transfer the remaining state. */
+ ppath->position = ppfrom->position;
+ ppath->outside_position = ppfrom->outside_position;
+ ppath->state_flags = ppfrom->state_flags;
+ /* Reset the source path. */
+ gx_path_init_contents(ppfrom);
+ return 0;
+}
+
+/* Add a path or its bounding box to the enclosing path, */
+/* and reset the first path. Only used for implementing charpath and its */
+/* relatives. */
+int
+gx_path_add_char_path(gx_path * to_path, gx_path * from_path,
+ gs_char_path_mode mode)
+{
+ int code;
+ gs_fixed_rect bbox;
+
+ switch (mode) {
+ default: /* shouldn't happen! */
+ gx_path_new(from_path);
+ return 0;
+ case cpm_true_charpath:
+ case cpm_false_charpath:
+ return gx_path_add_path(to_path, from_path);
+ case cpm_true_charboxpath:
+ gx_path_bbox(from_path, &bbox);
+ code = gx_path_add_rectangle(to_path, bbox.p.x, bbox.p.y,
+ bbox.q.x, bbox.q.y);
+ break;
+ case cpm_false_charboxpath:
+ gx_path_bbox(from_path, &bbox);
+ code = gx_path_add_point(to_path, bbox.p.x, bbox.p.y);
+ if (code >= 0)
+ code = gx_path_add_line(to_path, bbox.q.x, bbox.q.y);
+ break;
+ }
+ if (code < 0)
+ return code;
+ gx_path_new(from_path);
+ return 0;
+}
+
+/* Close the current subpath. */
+int
+gx_path_close_subpath_notes(gx_path * ppath, segment_notes notes)
+{
+ subpath *psub;
+ line_close_segment *lp;
+ int code;
+
+ if (!path_subpath_open(ppath))
+ return 0;
+ if (path_last_is_moveto(ppath)) { /* The last operation was a moveto: create a subpath. */
+ code = gx_path_new_subpath(ppath);
+ if (code < 0)
+ return code;
+ }
+ path_alloc_segment(lp, line_close_segment, &st_line_close,
+ s_line_close, notes, "gx_path_close_subpath");
+ path_alloc_link(lp);
+ path_set_point(lp, psub->pt.x, psub->pt.y);
+ lp->sub = psub;
+ psub->is_closed = 1;
+ path_update_closepath(ppath);
+ trace_segment("[P]", (segment *) lp);
+ return 0;
+}
+
+/* Remove the last line from the current subpath, and then close it. */
+/* The Type 1 font hinting routines use this if a path ends with */
+/* a line to the start followed by a closepath. */
+int
+gx_path_pop_close_notes(gx_path * ppath, segment_notes notes)
+{
+ subpath *psub = ppath->current_subpath;
+ segment *pseg;
+ segment *prev;
+
+ if (psub == 0 || (pseg = psub->last) == 0 ||
+ pseg->type != s_line
+ )
+ return_error(gs_error_unknownerror);
+ prev = pseg->prev;
+ prev->next = 0;
+ psub->last = prev;
+ gs_free_object(ppath->memory, pseg, "gx_path_pop_close_subpath");
+ return gx_path_close_subpath_notes(ppath, notes);
+}
+
+/* ------ Internal routines ------ */
+
+/*
+ * Copy the current path, because it was shared.
+ */
+private int
+path_alloc_copy(gx_path * ppath)
+{
+ gx_path path_new;
+ int code;
+
+ gx_path_init_local(&path_new, ppath->memory);
+ code = gx_path_copy(ppath, &path_new);
+ if (code < 0) {
+ gx_path_free(&path_new, "path_alloc_copy error");
+ return code;
+ }
+ return gx_path_assign_free(ppath, &path_new);
+}
+
+/* ------ Debugging printout ------ */
+
+#ifdef DEBUG
+
+/* Print out a path with a label */
+void
+gx_dump_path(const gx_path * ppath, const char *tag)
+{
+ dlprintf2("[P]Path 0x%lx %s:\n", (ulong) ppath, tag);
+ gx_path_print(ppath);
+}
+
+/* Print a path */
+void
+gx_path_print(const gx_path * ppath)
+{
+ const segment *pseg = (const segment *)ppath->first_subpath;
+
+ dlprintf5(" state_flags=%d subpaths=%d, curves=%d, point=(%f,%f)\n",
+ ppath->state_flags, ppath->subpath_count, ppath->curve_count,
+ fixed2float(ppath->position.x),
+ fixed2float(ppath->position.y));
+ dlprintf5(" box=(%f,%f),(%f,%f) last=0x%lx\n",
+ fixed2float(ppath->bbox.p.x), fixed2float(ppath->bbox.p.y),
+ fixed2float(ppath->bbox.q.x), fixed2float(ppath->bbox.q.y),
+ (ulong) ppath->box_last);
+ dlprintf4(" segments=0x%lx (refct=%ld, first=0x%lx, current=0x%lx)\n",
+ (ulong) ppath->segments, (long)ppath->segments->rc.ref_count,
+ (ulong) ppath->segments->contents.subpath_first,
+ (ulong) ppath->segments->contents.subpath_current);
+ while (pseg) {
+ dlputs("");
+ gx_print_segment(pseg);
+ pseg = pseg->next;
+ }
+}
+private void
+gx_print_segment(const segment * pseg)
+{
+ double px = fixed2float(pseg->pt.x);
+ double py = fixed2float(pseg->pt.y);
+ char out[80];
+
+ sprintf(out, " 0x%lx<0x%lx,0x%lx>:%u",
+ (ulong) pseg, (ulong) pseg->prev, (ulong) pseg->next, pseg->notes);
+ switch (pseg->type) {
+ case s_start:{
+ const subpath *const psub = (const subpath *)pseg;
+
+ dprintf5("%s: %1.4f %1.4f moveto\t%% #curves=%d last=0x%lx\n",
+ out, px, py, psub->curve_count, (ulong) psub->last);
+ break;
+ }
+ case s_curve:{
+ const curve_segment *const pcur = (const curve_segment *)pseg;
+
+ dprintf7("%s: %1.4f %1.4f %1.4f %1.4f %1.4f %1.4f curveto\n",
+ out, fixed2float(pcur->p1.x), fixed2float(pcur->p1.y),
+ fixed2float(pcur->p2.x), fixed2float(pcur->p2.y), px, py);
+ break;
+ }
+ case s_line:
+ dprintf3("%s: %1.4f %1.4f lineto\n", out, px, py);
+ break;
+ case s_line_close:{
+ const line_close_segment *const plc =
+ (const line_close_segment *)pseg;
+
+ dprintf4("%s: closepath\t%% %1.4f %1.4f 0x%lx\n",
+ out, px, py, (ulong) (plc->sub));
+ break;
+ }
+ default:
+ dprintf4("%s: %1.4f %1.4f <type 0x%x>\n", out, px, py, pseg->type);
+ }
+}
+
+#endif /* DEBUG */
diff --git a/pstoraster/gxpath.h b/pstoraster/gxpath.h
new file mode 100644
index 000000000..88516e103
--- /dev/null
+++ b/pstoraster/gxpath.h
@@ -0,0 +1,317 @@
+/* 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 gxfixed.h */
+
+#ifndef gxpath_INCLUDED
+# define gxpath_INCLUDED
+
+#include "gscpm.h"
+#include "gslparam.h"
+#include "gspenum.h"
+#include "gsrect.h"
+
+/* The routines and types in this interface use */
+/* device, rather than user, coordinates, and fixed-point, */
+/* rather than floating, representation. */
+
+/* Opaque type for a path */
+#ifndef gx_path_DEFINED
+# define gx_path_DEFINED
+typedef struct gx_path_s gx_path;
+
+#endif
+
+/* Define the two insideness rules */
+#define gx_rule_winding_number (-1)
+#define gx_rule_even_odd 1
+
+/* Define 'notes' that describe the role of a path segment. */
+/* These are only for internal use; a normal segment's notes are 0. */
+typedef enum {
+ sn_none = 0,
+ sn_not_first = 1, /* segment is in curve/arc and not first */
+ sn_from_arc = 2 /* segment is part of an arc */
+} segment_notes;
+
+/* Debugging routines */
+#ifdef DEBUG
+void gx_dump_path(P2(const gx_path *, const char *));
+void gx_path_print(P1(const gx_path *));
+
+#endif
+
+/* Path memory management */
+
+/*
+ * Path memory management is unfortunately a little tricky. The
+ * implementation details are in gzpath.h: we only present the API here.
+ *
+ * Path objects per se may be allocated in 3 different ways: on the
+ * C stack, as separate objects in the heap, or (for the graphics state
+ * only) contained in a larger heap-allocated object.
+ *
+ * Any number of paths may share segments. The segments are stored in
+ * their own, reference-counted object, and are freed when there are no
+ * more references to that object.
+ */
+
+/*
+ * Allocate a path on the heap, and initialize it. If shared is NULL,
+ * allocate a segments object; if shared is an existing path, share its
+ * segments.
+ */
+gx_path *gx_path_alloc_shared(P3(const gx_path * shared, gs_memory_t * mem,
+ client_name_t cname));
+
+#define gx_path_alloc(mem, cname)\
+ gx_path_alloc_shared(NULL, mem, cname)
+/*
+ * Initialize a path contained in an already-heap-allocated object,
+ * optionally allocating its segments.
+ */
+int gx_path_init_contained_shared(P4(gx_path * ppath, const gx_path * shared,
+ gs_memory_t * mem, client_name_t cname));
+
+#define gx_path_alloc_contained(ppath, mem, cname)\
+ gx_path_init_contained_shared(ppath, NULL, mem, cname)
+/*
+ * Initialize a stack-allocated path. This doesn't allocate anything,
+ * but may still share the segments. Note that it returns an error if
+ * asked to share the segments of another local path.
+ */
+int gx_path_init_local_shared(P3(gx_path * ppath, const gx_path * shared,
+ gs_memory_t * mem));
+
+#define gx_path_init_local(ppath, mem)\
+ (void)gx_path_init_local_shared(ppath, NULL, mem) /* can't fail */
+
+/*
+ * Ensure that a path owns its segments, by copying the segments if
+ * they currently have multiple references.
+ */
+int gx_path_unshare(P1(gx_path * ppath));
+
+/*
+ * Free a path by releasing its segments if they have no more references.
+ * This also frees the path object iff it was allocated by gx_path_alloc.
+ */
+void gx_path_free(P2(gx_path * ppath, client_name_t cname));
+
+/*
+ * Assign one path to another, adjusting reference counts appropriately.
+ * Note that this requires that segments of the two paths (but not the path
+ * objects themselves) were allocated with the same allocator. Note also
+ * that if ppfrom is stack-allocated, ppto is not, and ppto's segments are
+ * currently shared, gx_path_assign must do the equivalent of a
+ * gx_path_new(ppto), which allocates a new segments object for ppto.
+ */
+int gx_path_assign_preserve(P2(gx_path * ppto, gx_path * ppfrom));
+
+/*
+ * Assign one path to another and free the first path at the same time.
+ * (This may do less work than assign_preserve + free.)
+ */
+int gx_path_assign_free(P2(gx_path * ppto, gx_path * ppfrom));
+
+/* Path constructors */
+/* Note that all path constructors have an implicit initial gx_path_unshare. */
+
+int gx_path_new(P1(gx_path *)),
+ gx_path_add_point(P3(gx_path *, fixed, fixed)),
+ gx_path_add_relative_point(P3(gx_path *, fixed, fixed)),
+ gx_path_add_line_notes(P4(gx_path *, fixed, fixed, segment_notes)),
+ gx_path_add_lines_notes(P4(gx_path *, const gs_fixed_point *, int, segment_notes)),
+ gx_path_add_rectangle(P5(gx_path *, fixed, fixed, fixed, fixed)),
+ gx_path_add_char_path(P3(gx_path *, gx_path *, gs_char_path_mode)),
+ gx_path_add_curve_notes(P8(gx_path *, fixed, fixed, fixed, fixed, fixed, fixed, segment_notes)),
+ gx_path_add_partial_arc_notes(P7(gx_path *, fixed, fixed, fixed, fixed, floatp, segment_notes)),
+ gx_path_add_path(P2(gx_path *, gx_path *)),
+ gx_path_close_subpath_notes(P2(gx_path *, segment_notes)),
+ /* We have to remove the 'subpath' from the following name */
+ /* to keep it unique in the first 23 characters. */
+ gx_path_pop_close_notes(P2(gx_path *, segment_notes));
+
+/* The last argument to gx_path_add_partial_arc is a fraction for computing */
+/* the curve parameters. Here is the correct value for quarter-circles. */
+/* (stroke uses this to draw round caps and joins.) */
+#define quarter_arc_fraction 0.552285
+/*
+ * Backward-compatible constructors that don't take a notes argument.
+ */
+#define gx_path_add_line(ppath, x, y)\
+ gx_path_add_line_notes(ppath, x, y, sn_none)
+#define gx_path_add_lines(ppath, pts, count)\
+ gx_path_add_lines_notes(ppath, pts, count, sn_none)
+#define gx_path_add_curve(ppath, x1, y1, x2, y2, x3, y3)\
+ gx_path_add_curve_notes(ppath, x1, y1, x2, y2, x3, y3, sn_none)
+#define gx_path_add_partial_arc(ppath, x3, y3, xt, yt, fraction)\
+ gx_path_add_partial_arc_notes(ppath, x3, y3, xt, yt, fraction, sn_none)
+#define gx_path_close_subpath(ppath)\
+ gx_path_close_subpath_notes(ppath, sn_none)
+#define gx_path_pop_close_subpath(ppath)\
+ gx_path_pop_close_notes(ppath, sn_none)
+
+/* Path accessors */
+
+gx_path *gx_current_path(P1(const gs_state *));
+int gx_path_current_point(P2(const gx_path *, gs_fixed_point *)),
+ gx_path_bbox(P2(gx_path *, gs_fixed_rect *));
+bool gx_path_has_curves(P1(const gx_path *)),
+ gx_path_is_void(P1(const gx_path *)), /* no segments */
+ gx_path_is_null(P1(const gx_path *)), /* nothing at all */
+ gx_path_is_monotonic(P1(const gx_path *));
+typedef enum {
+ prt_none = 0,
+ prt_open = 1, /* only 3 sides */
+ prt_fake_closed = 2, /* 4 lines, no closepath */
+ prt_closed = 3 /* 3 or 4 lines + closepath */
+} gx_path_rectangular_type;
+
+gx_path_rectangular_type
+gx_path_is_rectangular(P2(const gx_path *, gs_fixed_rect *));
+
+#define gx_path_is_rectangle(ppath, pbox)\
+ (gx_path_is_rectangular(ppath, pbox) != prt_none)
+/* Inline versions of the above */
+#define gx_path_is_null_inline(ppath)\
+ (gx_path_is_void(ppath) && !path_position_valid(ppath))
+
+/* Path transformers */
+
+/* gx_path_copy_reducing is internal. */
+typedef enum {
+ pco_none = 0,
+ pco_monotonize = 1, /* make curves monotonic */
+ pco_accurate = 2 /* flatten with accurate tangents at ends */
+} gx_path_copy_options;
+int gx_path_copy_reducing(P4(const gx_path * ppath_old, gx_path * ppath_new,
+ fixed fixed_flatness,
+ gx_path_copy_options options));
+
+#define gx_path_copy(old, new)\
+ gx_path_copy_reducing(old, new, max_fixed, pco_none)
+#define gx_path_add_flattened(old, new, flatness)\
+ gx_path_copy_reducing(old, new, float2fixed(flatness), pco_none)
+#define gx_path_add_flattened_accurate(old, new, flatness, accurate)\
+ gx_path_copy_reducing(old, new, float2fixed(flatness),\
+ (accurate ? pco_accurate : pco_none))
+#define gx_path_add_monotonized(old, new)\
+ gx_path_copy_reducing(old, new, max_fixed, pco_monotonize)
+int gx_path_add_dash_expansion(P3(const gx_path * /*old */ , gx_path * /*new */ , const gs_imager_state *)),
+ gx_path_copy_reversed(P2(const gx_path * /*old */ , gx_path * /*new */ )),
+ gx_path_translate(P3(gx_path *, fixed, fixed)),
+ gx_path_scale_exp2(P3(gx_path *, int, int));
+void gx_point_scale_exp2(P3(gs_fixed_point *, int, int)), gx_rect_scale_exp2(P3(gs_fixed_rect *, int, int));
+
+/* Path enumerator */
+
+/* This interface does not make a copy of the path. */
+/* Do not use gs_path_enum_cleanup with this interface! */
+int gx_path_enum_init(P2(gs_path_enum *, const gx_path *));
+int gx_path_enum_next(P2(gs_path_enum *, gs_fixed_point[3])); /* 0 when done */
+
+segment_notes
+gx_path_enum_notes(P1(const gs_path_enum *));
+bool gx_path_enum_backup(P1(gs_path_enum *));
+
+/* ------ Clipping paths ------ */
+
+/* Opaque type for a clipping path */
+#ifndef gx_clip_path_DEFINED
+# define gx_clip_path_DEFINED
+typedef struct gx_clip_path_s gx_clip_path;
+
+#endif
+
+/* Graphics state clipping */
+int gx_clip_to_rectangle(P2(gs_state *, gs_fixed_rect *));
+int gx_clip_to_path(P1(gs_state *));
+int gx_default_clip_box(P2(const gs_state *, gs_fixed_rect *));
+int gx_effective_clip_path(P2(gs_state *, gx_clip_path **));
+
+/* Opaque type for a clip list. */
+#ifndef gx_clip_list_DEFINED
+# define gx_clip_list_DEFINED
+typedef struct gx_clip_list_s gx_clip_list;
+
+#endif
+
+/* Opaque type for a clipping path enumerator. */
+typedef struct gs_cpath_enum_s gs_cpath_enum;
+
+/*
+ * Provide similar memory management for clip paths to what we have for
+ * paths (see above for details).
+ */
+gx_clip_path *gx_cpath_alloc_shared(P3(const gx_clip_path * shared,
+ gs_memory_t * mem,
+ client_name_t cname));
+
+#define gx_cpath_alloc(mem, cname)\
+ gx_cpath_alloc_shared(NULL, mem, cname)
+int gx_cpath_init_contained_shared(P4(gx_clip_path * pcpath,
+ const gx_clip_path * shared,
+ gs_memory_t * mem,
+ client_name_t cname));
+
+#define gx_cpath_alloc_contained(pcpath, mem, cname)\
+ gx_cpath_init_contained_shared(pcpath, NULL, mem, cname)
+int gx_cpath_init_local_shared(P3(gx_clip_path * pcpath,
+ const gx_clip_path * shared,
+ gs_memory_t * mem));
+
+#define gx_cpath_init_local(pcpath, mem)\
+ (void)gx_cpath_init_local_shared(pcpath, NULL, mem) /* can't fail */
+int gx_cpath_unshare(P1(gx_clip_path * pcpath));
+void gx_cpath_free(P2(gx_clip_path * pcpath, client_name_t cname));
+int gx_cpath_assign_preserve(P2(gx_clip_path * pcpto, gx_clip_path * pcpfrom));
+int gx_cpath_assign_free(P2(gx_clip_path * pcpto, gx_clip_path * pcpfrom));
+
+/* Clip path constructors and accessors */
+
+int
+ gx_cpath_reset(P1(gx_clip_path *)), /* from_rectangle ((0,0),(0,0)) */
+ gx_cpath_from_rectangle(P2(gx_clip_path *, gs_fixed_rect *)),
+ gx_cpath_clip(P4(gs_state *, gx_clip_path *, gx_path *, int)),
+ gx_cpath_scale_exp2(P3(gx_clip_path *, int, int)),
+ gx_cpath_to_path(P2(gx_clip_path *, gx_path *));
+bool
+ gx_cpath_inner_box(P2(const gx_clip_path *, gs_fixed_rect *)),
+ gx_cpath_outer_box(P2(const gx_clip_path *, gs_fixed_rect *)),
+ gx_cpath_includes_rectangle(P5(const gx_clip_path *, fixed, fixed,
+ fixed, fixed));
+int gx_cpath_set_outside(P2(gx_clip_path *, bool));
+bool gx_cpath_is_outside(P1(const gx_clip_path *));
+
+/* Enumerate a clipping path. This interface does not copy the path. */
+/* However, it does write into the path's "visited" flags. */
+int gx_cpath_enum_init(P2(gs_cpath_enum *, gx_clip_path *));
+int gx_cpath_enum_next(P2(gs_cpath_enum *, gs_fixed_point[3])); /* 0 when done */
+
+segment_notes
+gx_cpath_enum_notes(P1(const gs_cpath_enum *));
+
+#endif /* gxpath_INCLUDED */
diff --git a/pstoraster/gxpath2.c b/pstoraster/gxpath2.c
new file mode 100644
index 000000000..a033e7151
--- /dev/null
+++ b/pstoraster/gxpath2.c
@@ -0,0 +1,487 @@
+/* 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$ */
+/* Path tracing procedures for Ghostscript library */
+#include "math_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gxfixed.h"
+#include "gxarith.h"
+#include "gzpath.h"
+
+/* Define the enumeration structure. */
+public_st_path_enum();
+
+/* Read the current point of a path. */
+int
+gx_path_current_point(const gx_path * ppath, gs_fixed_point * ppt)
+{
+ if (!path_position_valid(ppath))
+ return_error(gs_error_nocurrentpoint);
+ /* Copying the coordinates individually */
+ /* is much faster on a PC, and almost as fast on other machines.... */
+ ppt->x = ppath->position.x, ppt->y = ppath->position.y;
+ return 0;
+}
+
+/* Read the bounding box of a path. */
+/* Note that if the last element of the path is a moveto, */
+/* the bounding box does not include this point, */
+/* unless this is the only element of the path. */
+int
+gx_path_bbox(gx_path * ppath, gs_fixed_rect * pbox)
+{
+ if (ppath->bbox_set) { /* The bounding box was set by setbbox. */
+ *pbox = ppath->bbox;
+ return 0;
+ }
+ if (ppath->first_subpath == 0) { /* The path is empty, use the current point if any. */
+ int code = gx_path_current_point(ppath, &pbox->p);
+
+ if (code < 0) { /*
+ * Don't return garbage, in case the caller doesn't
+ * check the return code.
+ */
+ pbox->p.x = pbox->p.y = 0;
+ }
+ pbox->q = pbox->p;
+ return code;
+ }
+ /* The stored bounding box may not be up to date. */
+ /* Correct it now if necessary. */
+ if (ppath->box_last == ppath->current_subpath->last) { /* Box is up to date */
+ *pbox = ppath->bbox;
+ } else {
+ gs_fixed_rect box;
+ const segment *pseg = ppath->box_last;
+
+ if (pseg == 0) { /* box is uninitialized */
+ pseg = (const segment *)ppath->first_subpath;
+ box.p.x = box.q.x = pseg->pt.x;
+ box.p.y = box.q.y = pseg->pt.y;
+ } else {
+ box = ppath->bbox;
+ pseg = pseg->next;
+ }
+/* Macro for adjusting the bounding box when adding a point */
+#define adjust_bbox(pt)\
+ if ( (pt).x < box.p.x ) box.p.x = (pt).x;\
+ else if ( (pt).x > box.q.x ) box.q.x = (pt).x;\
+ if ( (pt).y < box.p.y ) box.p.y = (pt).y;\
+ else if ( (pt).y > box.q.y ) box.q.y = (pt).y
+ while (pseg) {
+ switch (pseg->type) {
+ case s_curve:
+#define pcurve ((const curve_segment *)pseg)
+ adjust_bbox(pcurve->p1);
+ adjust_bbox(pcurve->p2);
+#undef pcurve
+ /* falls through */
+ default:
+ adjust_bbox(pseg->pt);
+ }
+ pseg = pseg->next;
+ }
+#undef adjust_bbox
+ ppath->bbox = box;
+ ppath->box_last = ppath->current_subpath->last;
+ *pbox = box;
+ }
+ return 0;
+}
+
+/* Test if a path has any curves. */
+#undef gx_path_has_curves
+bool
+gx_path_has_curves(const gx_path * ppath)
+{
+ return gx_path_has_curves_inline(ppath);
+}
+#define gx_path_has_curves(ppath)\
+ gx_path_has_curves_inline(ppath)
+
+/* Test if a path has no segments. */
+#undef gx_path_is_void
+bool
+gx_path_is_void(const gx_path * ppath)
+{
+ return gx_path_is_void_inline(ppath);
+}
+#define gx_path_is_void(ppath)\
+ gx_path_is_void_inline(ppath)
+
+/* Test if a path has no elements at all. */
+bool
+gx_path_is_null(const gx_path * ppath)
+{
+ return gx_path_is_null_inline(ppath);
+}
+
+/*
+ * Test if a subpath is a rectangle; if so, return its bounding box
+ * and the start of the next subpath.
+ * Note that this must recognize:
+ * ordinary closed rectangles (M, L, L, L, C);
+ * open rectangles (M, L, L, L);
+ * rectangles closed with lineto (Mo, L, L, L, Lo);
+ * rectangles closed with *both* lineto and closepath (bad PostScript,
+ * but unfortunately not rare) (Mo, L, L, L, Lo, C).
+ */
+gx_path_rectangular_type
+gx_subpath_is_rectangular(const subpath * pseg0, gs_fixed_rect * pbox,
+ const subpath ** ppnext)
+{
+ const segment *pseg1, *pseg2, *pseg3, *pseg4;
+ gx_path_rectangular_type type;
+
+ if (pseg0->curve_count == 0 &&
+ (pseg1 = pseg0->next) != 0 &&
+ (pseg2 = pseg1->next) != 0 &&
+ (pseg3 = pseg2->next) != 0
+ ) {
+ if ((pseg4 = pseg3->next) == 0 || pseg4->type == s_start)
+ type = prt_open; /* M, L, L, L */
+ else if (pseg4->type != s_line) /* must be s_line_close */
+ type = prt_closed; /* M, L, L, L, C */
+ else if (pseg4->pt.x != pseg0->pt.x ||
+ pseg4->pt.y != pseg0->pt.y
+ )
+ return prt_none;
+ else if (pseg4->next == 0 || pseg4->next->type == s_start)
+ type = prt_fake_closed; /* Mo, L, L, L, Lo */
+ else if (pseg4->next->type != s_line) /* must be s_line_close */
+ type = prt_closed; /* Mo, L, L, L, Lo, C */
+ else
+ return prt_none;
+ {
+ fixed x0 = pseg0->pt.x, y0 = pseg0->pt.y;
+ fixed x2 = pseg2->pt.x, y2 = pseg2->pt.y;
+
+ if ((x0 == pseg1->pt.x && pseg1->pt.y == y2 &&
+ x2 == pseg3->pt.x && pseg3->pt.y == y0) ||
+ (x0 == pseg3->pt.x && pseg3->pt.y == y2 &&
+ x2 == pseg1->pt.x && pseg1->pt.y == y0)
+ ) { /* Path is a rectangle. Return the bounding box. */
+ if (x0 < x2)
+ pbox->p.x = x0, pbox->q.x = x2;
+ else
+ pbox->p.x = x2, pbox->q.x = x0;
+ if (y0 < y2)
+ pbox->p.y = y0, pbox->q.y = y2;
+ else
+ pbox->p.y = y2, pbox->q.y = y0;
+ while (pseg4 != 0 && pseg4->type != s_start)
+ pseg4 = pseg4->next;
+ *ppnext = (const subpath *)pseg4;
+ return type;
+ }
+ }
+ }
+ return prt_none;
+}
+/* Test if an entire path to be filled is a rectangle. */
+gx_path_rectangular_type
+gx_path_is_rectangular(const gx_path * ppath, gs_fixed_rect * pbox)
+{
+ const subpath *pnext;
+
+ return
+ (gx_path_subpath_count(ppath) == 1 ?
+ gx_subpath_is_rectangular(ppath->first_subpath, pbox, &pnext) :
+ prt_none);
+}
+
+/* Translate an already-constructed path (in device space). */
+/* Don't bother to update the cbox. */
+int
+gx_path_translate(gx_path * ppath, fixed dx, fixed dy)
+{
+ segment *pseg;
+
+#define update_xy(pt)\
+ pt.x += dx, pt.y += dy
+ if (ppath->box_last != 0) {
+ update_xy(ppath->bbox.p);
+ update_xy(ppath->bbox.q);
+ }
+ if (path_position_valid(ppath))
+ update_xy(ppath->position);
+ for (pseg = (segment *) (ppath->first_subpath); pseg != 0;
+ pseg = pseg->next
+ )
+ switch (pseg->type) {
+ case s_curve:
+#define pcseg ((curve_segment *)pseg)
+ update_xy(pcseg->p1);
+ update_xy(pcseg->p2);
+#undef pcseg
+ default:
+ update_xy(pseg->pt);
+ }
+#undef update_xy
+ return 0;
+}
+
+/* Scale an existing path by a power of 2 (positive or negative). */
+void
+gx_point_scale_exp2(gs_fixed_point * pt, int sx, int sy)
+{
+ if (sx >= 0)
+ pt->x <<= sx;
+ else
+ pt->x >>= -sx;
+ if (sy >= 0)
+ pt->y <<= sy;
+ else
+ pt->y >>= -sy;
+}
+void
+gx_rect_scale_exp2(gs_fixed_rect * pr, int sx, int sy)
+{
+ gx_point_scale_exp2(&pr->p, sx, sy);
+ gx_point_scale_exp2(&pr->q, sx, sy);
+}
+int
+gx_path_scale_exp2(gx_path * ppath, int log2_scale_x, int log2_scale_y)
+{
+ segment *pseg;
+
+ gx_rect_scale_exp2(&ppath->bbox, log2_scale_x, log2_scale_y);
+#define update_xy(pt) gx_point_scale_exp2(&pt, log2_scale_x, log2_scale_y)
+ update_xy(ppath->position);
+ for (pseg = (segment *) (ppath->first_subpath); pseg != 0;
+ pseg = pseg->next
+ )
+ switch (pseg->type) {
+ case s_curve:
+#define pcseg ((curve_segment *)pseg)
+ update_xy(pcseg->p1);
+ update_xy(pcseg->p2);
+#undef pcseg
+ default:
+ update_xy(pseg->pt);
+ }
+#undef update_xy
+ return 0;
+}
+
+/*
+ * Reverse a path. We know ppath != ppath_old.
+ * NOTE: in releases 5.01 and earlier, the implicit line added by closepath
+ * became the first segment of the reversed path. Starting in release
+ * 5.02, the code follows the Adobe implementation, in which this line
+ * becomes the *last* segment of the reversed path. This can produce some
+ * quite counter-intuitive results.
+ */
+int
+gx_path_copy_reversed(const gx_path * ppath_old, gx_path * ppath)
+{
+ const subpath *psub = ppath_old->first_subpath;
+ int code;
+
+#ifdef DEBUG
+ if (gs_debug_c('P'))
+ gx_dump_path(ppath_old, "before reversepath");
+#endif
+ nsp:while (psub) {
+ const segment *pseg = psub->last;
+ const segment *prev;
+ segment_notes prev_notes =
+ (pseg == (const segment *)psub ? sn_none :
+ psub->next->notes);
+ segment_notes notes;
+
+ if (!psub->is_closed) {
+ code = gx_path_add_point(ppath, pseg->pt.x, pseg->pt.y);
+ if (code < 0)
+ return code;
+ }
+ for (;; pseg = prev, prev_notes = notes) {
+ prev = pseg->prev;
+ notes = pseg->notes;
+ prev_notes = (prev_notes & sn_not_first) |
+ (notes & ~sn_not_first);
+ switch (pseg->type) {
+ case s_start:
+ /* Finished subpath */
+ if (psub->is_closed) {
+ code =
+ gx_path_close_subpath_notes(ppath,
+ prev_notes);
+ if (code < 0)
+ return code;
+ }
+ psub = (const subpath *)psub->last->next;
+ goto nsp;
+ case s_curve:
+ {
+ const curve_segment *pc =
+ (const curve_segment *)pseg;
+
+ code = gx_path_add_curve_notes(ppath,
+ pc->p2.x, pc->p2.y,
+ pc->p1.x, pc->p1.y,
+ prev->pt.x, prev->pt.y, prev_notes);
+ break;
+ }
+ case s_line:
+ code = gx_path_add_line_notes(ppath,
+ prev->pt.x, prev->pt.y, prev_notes);
+ break;
+ case s_line_close:
+ /* Skip the closing line. */
+ code = gx_path_add_point(ppath, prev->pt.x,
+ prev->pt.y);
+ break;
+ }
+ if (code < 0)
+ return code;
+ }
+ /* not reached */
+ }
+#undef sn_not_end
+ if (ppath_old->first_subpath == 0 &&
+ path_last_is_moveto(ppath_old)
+ ) { /* The path consists only of a single moveto. */
+ code = gx_path_add_point(ppath, ppath_old->position.x,
+ ppath_old->position.y);
+ if (code < 0)
+ return code;
+ }
+#ifdef DEBUG
+ if (gs_debug_c('P'))
+ gx_dump_path(ppath, "after reversepath");
+#endif
+ return 0;
+}
+
+/* ------ Path enumeration ------ */
+
+/* Allocate a path enumerator. */
+gs_path_enum *
+gs_path_enum_alloc(gs_memory_t * mem, client_name_t cname)
+{
+ return gs_alloc_struct(mem, gs_path_enum, &st_path_enum, cname);
+}
+
+/* Start enumerating a path. */
+int
+gx_path_enum_init(gs_path_enum * penum, const gx_path * ppath)
+{
+ penum->memory = 0; /* path not copied */
+ penum->path = ppath;
+ penum->copied_path = 0; /* not copied */
+ penum->pseg = (const segment *)ppath->first_subpath;
+ penum->moveto_done = false;
+ penum->notes = sn_none;
+ return 0;
+}
+
+/* Enumerate the next element of a path. */
+/* If the path is finished, return 0; */
+/* otherwise, return the element type. */
+int
+gx_path_enum_next(gs_path_enum * penum, gs_fixed_point ppts[3])
+{
+ const segment *pseg = penum->pseg;
+
+ if (pseg == 0) { /* We've enumerated all the segments, but there might be */
+ /* a trailing moveto. */
+ const gx_path *ppath = penum->path;
+
+ if (path_last_is_moveto(ppath) && !penum->moveto_done) { /* Handle a trailing moveto */
+ penum->moveto_done = true;
+ penum->notes = sn_none;
+ ppts[0] = ppath->position;
+ return gs_pe_moveto;
+ }
+ return 0;
+ }
+ penum->pseg = pseg->next;
+ penum->notes = pseg->notes;
+ switch (pseg->type) {
+ case s_start:
+ ppts[0] = pseg->pt;
+ return gs_pe_moveto;
+ case s_line:
+ ppts[0] = pseg->pt;
+ return gs_pe_lineto;
+ case s_line_close:
+ ppts[0] = pseg->pt;
+ return gs_pe_closepath;
+ case s_curve:
+#define pcseg ((const curve_segment *)pseg)
+ ppts[0] = pcseg->p1;
+ ppts[1] = pcseg->p2;
+ ppts[2] = pseg->pt;
+ return gs_pe_curveto;
+#undef pcseg
+ default:
+ lprintf1("bad type %x in gx_path_enum_next!\n", pseg->type);
+ return_error(gs_error_Fatal);
+ }
+}
+
+/* Return the notes from the last-enumerated segment. */
+segment_notes
+gx_path_enum_notes(const gs_path_enum * penum)
+{
+ return penum->notes;
+}
+
+/* Back up 1 element in the path being enumerated. */
+/* Return true if successful, false if we are at the beginning of the path. */
+/* This implementation allows backing up multiple times, */
+/* but no client currently relies on this. */
+bool
+gx_path_enum_backup(gs_path_enum * penum)
+{
+ const segment *pseg = penum->pseg;
+
+ if (pseg != 0) {
+ if ((pseg = pseg->prev) == 0)
+ return false;
+ penum->pseg = pseg;
+ return true;
+ }
+ /* We're at the end of the path. Check to see whether */
+ /* we need to back up over a trailing moveto. */
+ {
+ const gx_path *ppath = penum->path;
+
+ if (path_last_is_moveto(ppath) && penum->moveto_done) { /* Back up over the trailing moveto. */
+ penum->moveto_done = false;
+ return true;
+ } {
+ const subpath *psub = ppath->current_subpath;
+
+ if (psub == 0) /* empty path */
+ return false;
+ /* Back up to the last segment of the last subpath. */
+ penum->pseg = psub->last;
+ return true;
+ }
+ }
+}
diff --git a/pstoraster/gxpcache.h b/pstoraster/gxpcache.h
new file mode 100644
index 000000000..b4f81a65e
--- /dev/null
+++ b/pstoraster/gxpcache.h
@@ -0,0 +1,61 @@
+/* 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$ */
+/* Definition of Pattern cache */
+
+#ifndef gxpcache_INCLUDED
+# define gxpcache_INCLUDED
+
+/*
+ * Define a cache for rendered Patterns. This is currently an open
+ * hash table with single probing (no reprobing) and round-robin
+ * replacement. Obviously, we can do better in both areas.
+ */
+#ifndef gx_pattern_cache_DEFINED
+# define gx_pattern_cache_DEFINED
+typedef struct gx_pattern_cache_s gx_pattern_cache;
+
+#endif
+#ifndef gx_color_tile_DEFINED
+# define gx_color_tile_DEFINED
+typedef struct gx_color_tile_s gx_color_tile;
+
+#endif
+struct gx_pattern_cache_s {
+ gs_memory_t *memory;
+ gx_color_tile *tiles;
+ uint num_tiles;
+ uint tiles_used;
+ uint next; /* round-robin index */
+ ulong bits_used;
+ ulong max_bits;
+ void (*free_all) (P1(gx_pattern_cache *));
+};
+
+#define private_st_pattern_cache() /* in gxpcmap.c */\
+ gs_private_st_ptrs1(st_pattern_cache, gx_pattern_cache,\
+ "gx_pattern_cache", pattern_cache_enum, pattern_cache_reloc, tiles)
+
+#endif /* gxpcache_INCLUDED */
diff --git a/pstoraster/gxpcmap.c b/pstoraster/gxpcmap.c
new file mode 100644
index 000000000..e43530af5
--- /dev/null
+++ b/pstoraster/gxpcmap.c
@@ -0,0 +1,666 @@
+/* Copyright (C) 1993, 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$ */
+/* Pattern color mapping for Ghostscript library */
+#include "math_.h"
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gsutil.h" /* for gs_next_ids */
+#include "gxfixed.h"
+#include "gxmatrix.h"
+#include "gxcspace.h" /* for gscolor2.h */
+#include "gxcolor2.h"
+#include "gxdcolor.h"
+#include "gxdevice.h"
+#include "gxdevmem.h"
+#include "gxpcolor.h"
+#include "gzstate.h"
+#include "gzpath.h" /* for tweaking sharing flags */
+#include "gzcpath.h" /* ditto */
+
+/* Define the default size of the Pattern cache. */
+#define max_cached_patterns_LARGE 50
+#define max_pattern_bits_LARGE 100000
+#define max_cached_patterns_SMALL 5
+#define max_pattern_bits_SMALL 1000
+uint
+gx_pat_cache_default_tiles(void)
+{
+#if arch_small_memory
+ return max_cached_patterns_SMALL;
+#else
+ return (gs_debug_c('.') ? max_cached_patterns_SMALL :
+ max_cached_patterns_LARGE);
+#endif
+}
+ulong
+gx_pat_cache_default_bits(void)
+{
+#if arch_small_memory
+ return max_pattern_bits_SMALL;
+#else
+ return (gs_debug_c('.') ? max_pattern_bits_SMALL :
+ max_pattern_bits_LARGE);
+#endif
+}
+
+/* Define the structures for Pattern rendering and caching. */
+private_st_color_tile();
+private_st_color_tile_element();
+private_st_pattern_cache();
+private_st_device_pattern_accum();
+
+/* ------ Pattern rendering ------ */
+
+/* Device procedures */
+private dev_proc_open_device(pattern_accum_open);
+private dev_proc_close_device(pattern_accum_close);
+private dev_proc_fill_rectangle(pattern_accum_fill_rectangle);
+private dev_proc_copy_mono(pattern_accum_copy_mono);
+private dev_proc_copy_color(pattern_accum_copy_color);
+private dev_proc_get_bits_rectangle(pattern_accum_get_bits_rectangle);
+
+/* The device descriptor */
+private const gx_device_pattern_accum gs_pattern_accum_device =
+{std_device_std_body_open(gx_device_pattern_accum, 0,
+ "pattern accumulator",
+ 0, 0, 72, 72),
+ { /*
+ * NOTE: all drawing procedures must be defaulted,
+ * not forwarded.
+ */
+ pattern_accum_open,
+ NULL,
+ NULL,
+ NULL,
+ pattern_accum_close,
+ NULL,
+ NULL,
+ pattern_accum_fill_rectangle,
+ gx_default_tile_rectangle,
+ pattern_accum_copy_mono,
+ pattern_accum_copy_color,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ gx_default_copy_alpha,
+ NULL,
+ 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,
+ gx_default_strip_tile_rectangle,
+ gx_default_strip_copy_rop,
+ gx_get_largest_clipping_box,
+ gx_default_begin_typed_image,
+ pattern_accum_get_bits_rectangle,
+ NULL,
+ NULL,
+ NULL,
+ gx_default_text_begin
+ },
+ 0, /* target */
+ 0, 0, 0, 0 /* bitmap_memory, bits, mask, instance */
+};
+
+/* Allocate a pattern accumulator, with an initial refct of 0. */
+gx_device_pattern_accum *
+gx_pattern_accum_alloc(gs_memory_t * mem, client_name_t cname)
+{
+ gx_device_pattern_accum *adev =
+ gs_alloc_struct(mem, gx_device_pattern_accum,
+ &st_device_pattern_accum, cname);
+
+ if (adev == 0)
+ return 0;
+ gx_device_init((gx_device *) adev,
+ (const gx_device *)&gs_pattern_accum_device,
+ mem, true);
+ gx_device_forward_fill_in_procs((gx_device_forward *) adev); /* (should only do once) */
+ return adev;
+}
+
+/*
+ * Initialize a pattern accumulator.
+ * Client must already have set instance and bitmap_memory.
+ *
+ * Note that mask and bits accumulators are only created if necessary.
+ */
+private int
+pattern_accum_open(gx_device * dev)
+{
+ gx_device_pattern_accum *const padev = (gx_device_pattern_accum *) dev;
+ const gs_pattern_instance *pinst = padev->instance;
+ gs_memory_t *mem = padev->bitmap_memory;
+ gx_device_memory *mask = 0;
+ gx_device_memory *bits = 0;
+ /*
+ * The client should preset the target, because the device for which the
+ * pattern is being rendered may not (in general, will not) be the same
+ * as the one that was current when the pattern was instantiated.
+ */
+ gx_device *target =
+ (padev->target == 0 ? gs_currentdevice(pinst->saved) :
+ padev->target);
+ int width = pinst->size.x;
+ int height = pinst->size.y;
+ int code = 0;
+ bool mask_open = false;
+
+#define PDSET(dev)\
+ (dev)->width = width, (dev)->height = height,\
+ (dev)->x_pixels_per_inch = target->x_pixels_per_inch,\
+ (dev)->y_pixels_per_inch = target->y_pixels_per_inch
+
+ PDSET(padev);
+ padev->color_info = target->color_info;
+
+ if (pinst->uses_mask) {
+ mask = gs_alloc_struct( mem,
+ gx_device_memory,
+ &st_device_memory,
+ "pattern_accum_open(mask)"
+ );
+ if (mask == 0)
+ return_error(gs_error_VMerror);
+ gs_make_mem_mono_device(mask, mem, 0);
+ PDSET(mask);
+ mask->bitmap_memory = mem;
+ mask->base = 0;
+ code = (*dev_proc(mask, open_device)) ((gx_device *) mask);
+ if (code >= 0) {
+ mask_open = true;
+ memset(mask->base, 0, mask->raster * mask->height);
+ }
+ }
+
+ if (code >= 0) {
+ switch (pinst->template.PaintType) {
+ case 2: /* uncolored */
+ padev->target = target;
+ break;
+ case 1: /* colored */
+ bits = gs_alloc_struct(mem, gx_device_memory,
+ &st_device_memory,
+ "pattern_accum_open(bits)");
+ if (bits == 0)
+ code = gs_note_error(gs_error_VMerror);
+ else {
+ padev->target = (gx_device *) bits;
+ gs_make_mem_device(bits,
+ gdev_mem_device_for_bits(target->color_info.depth),
+ mem, -1, target);
+ PDSET(bits);
+#undef PDSET
+ bits->color_info = target->color_info;
+ bits->bitmap_memory = mem;
+ code = (*dev_proc(bits, open_device)) ((gx_device *) bits);
+ }
+ }
+ }
+ if (code < 0) {
+ if (bits != 0)
+ gs_free_object(mem, bits, "pattern_accum_open(bits)");
+ if (mask != 0) {
+ if (mask_open)
+ (*dev_proc(mask, close_device)) ((gx_device *) mask);
+ gs_free_object(mem, mask, "pattern_accum_open(mask)");
+ }
+ return code;
+ }
+ padev->mask = mask;
+ padev->bits = bits;
+ return code;
+}
+
+/* Close an accumulator and free the bits. */
+private int
+pattern_accum_close(gx_device * dev)
+{
+ gx_device_pattern_accum *const padev = (gx_device_pattern_accum *) dev;
+ gs_memory_t *mem = padev->bitmap_memory;
+
+ if (padev->bits != 0) {
+ (*dev_proc(padev->bits, close_device)) ((gx_device *) padev->bits);
+ gs_free_object(mem, padev->bits, "pattern_accum_close(bits)");
+ padev->bits = 0;
+ }
+ if (padev->mask != 0) {
+ (*dev_proc(padev->mask, close_device)) ((gx_device *) padev->mask);
+ gs_free_object(mem, padev->mask, "pattern_accum_close(mask)");
+ padev->mask = 0;
+ }
+ return 0;
+}
+
+/* Fill a rectangle */
+private int
+pattern_accum_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
+ gx_color_index color)
+{
+ gx_device_pattern_accum *const padev = (gx_device_pattern_accum *) dev;
+
+ if (padev->bits)
+ (*dev_proc(padev->target, fill_rectangle))
+ (padev->target, x, y, w, h, color);
+ if (padev->mask)
+ return (*dev_proc(padev->mask, fill_rectangle))
+ ((gx_device *) padev->mask, x, y, w, h, (gx_color_index) 1);
+ else
+ return 0;
+}
+
+/* Copy a monochrome bitmap. */
+private int
+pattern_accum_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 color0, gx_color_index color1)
+{
+ gx_device_pattern_accum *const padev = (gx_device_pattern_accum *) dev;
+
+ if (padev->bits)
+ (*dev_proc(padev->target, copy_mono))
+ (padev->target, data, data_x, raster, id, x, y, w, h,
+ color0, color1);
+ if (padev->mask) {
+ if (color0 != gx_no_color_index)
+ color0 = 1;
+ if (color1 != gx_no_color_index)
+ color1 = 1;
+ if (color0 == 1 && color1 == 1)
+ return (*dev_proc(padev->mask, fill_rectangle))
+ ((gx_device *) padev->mask, x, y, w, h, (gx_color_index) 1);
+ else
+ return (*dev_proc(padev->mask, copy_mono))
+ ((gx_device *) padev->mask, data, data_x, raster, id, x, y, w, h,
+ color0, color1);
+ } else
+ return 0;
+}
+
+/* Copy a color bitmap. */
+private int
+pattern_accum_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)
+{
+ gx_device_pattern_accum *const padev = (gx_device_pattern_accum *) dev;
+
+ if (padev->bits)
+ (*dev_proc(padev->target, copy_color))
+ (padev->target, data, data_x, raster, id, x, y, w, h);
+ if (padev->mask)
+ return (*dev_proc(padev->mask, fill_rectangle))
+ ((gx_device *) padev->mask, x, y, w, h, (gx_color_index) 1);
+ else
+ return 0;
+}
+
+/* Read back a rectangle of bits. */
+/****** SHOULD USE MASK TO DEFINE UNREAD AREA *****/
+private int
+pattern_accum_get_bits_rectangle(gx_device * dev, const gs_int_rect * prect,
+ gs_get_bits_params_t * params, gs_int_rect ** unread)
+{
+ gx_device_pattern_accum *const padev = (gx_device_pattern_accum *) dev;
+
+ return (*dev_proc(padev->target, get_bits_rectangle))
+ (padev->target, prect, params, unread);
+}
+
+/* ------ Color space implementation ------ */
+
+/* Free all entries in a pattern cache. */
+private bool
+pattern_cache_choose_all(gx_color_tile * ctile, void *proc_data)
+{
+ return true;
+}
+private void
+pattern_cache_free_all(gx_pattern_cache * pcache)
+{
+ gx_pattern_cache_winnow(pcache, pattern_cache_choose_all, NULL);
+}
+
+/* Allocate a Pattern cache. */
+gx_pattern_cache *
+gx_pattern_alloc_cache(gs_memory_t * mem, uint num_tiles, ulong max_bits)
+{
+ gx_pattern_cache *pcache =
+ gs_alloc_struct(mem, gx_pattern_cache, &st_pattern_cache,
+ "pattern_cache_alloc(struct)");
+ gx_color_tile *tiles =
+ gs_alloc_struct_array(mem, num_tiles, gx_color_tile,
+ &st_color_tile_element,
+ "pattern_cache_alloc(tiles)");
+ uint i;
+
+ if (pcache == 0 || tiles == 0) {
+ gs_free_object(mem, tiles, "pattern_cache_alloc(tiles)");
+ gs_free_object(mem, pcache, "pattern_cache_alloc(struct)");
+ return 0;
+ }
+ pcache->memory = mem;
+ pcache->tiles = tiles;
+ pcache->num_tiles = num_tiles;
+ pcache->tiles_used = 0;
+ pcache->next = 0;
+ pcache->bits_used = 0;
+ pcache->max_bits = max_bits;
+ pcache->free_all = pattern_cache_free_all;
+ for (i = 0; i < num_tiles; tiles++, i++) {
+ tiles->id = gx_no_bitmap_id;
+ /* Clear the pointers to pacify the GC. */
+ uid_set_invalid(&tiles->uid);
+ tiles->tbits.data = 0;
+ tiles->tmask.data = 0;
+ tiles->index = i;
+ }
+ return pcache;
+}
+/* Ensure that an imager has a Pattern cache. */
+private int
+ensure_pattern_cache(gs_imager_state * pis)
+{
+ if (pis->pattern_cache == 0) {
+ gx_pattern_cache *pcache =
+ gx_pattern_alloc_cache(pis->memory,
+ gx_pat_cache_default_tiles(),
+ gx_pat_cache_default_bits());
+
+ if (pcache == 0)
+ return_error(gs_error_VMerror);
+ pis->pattern_cache = pcache;
+ }
+ return 0;
+}
+
+/* Get and set the Pattern cache in a gstate. */
+gx_pattern_cache *
+gstate_pattern_cache(gs_state * pgs)
+{
+ return pgs->pattern_cache;
+}
+void
+gstate_set_pattern_cache(gs_state * pgs, gx_pattern_cache * pcache)
+{
+ pgs->pattern_cache = pcache;
+}
+
+/* Free a Pattern cache entry. */
+private void
+gx_pattern_cache_free_entry(gx_pattern_cache * pcache, gx_color_tile * ctile)
+{
+ gx_device_memory mdev;
+
+ if (ctile->id != gx_no_bitmap_id) {
+ if (ctile->tmask.data != 0) {
+ mdev.width = ctile->tmask.size.x;
+ mdev.height = ctile->tmask.size.y;
+ mdev.color_info.depth = 1;
+ pcache->bits_used -= gdev_mem_bitmap_size(&mdev);
+ gs_free_object(pcache->memory, ctile->tmask.data,
+ "free_pattern_cache_entry(mask data)");
+ ctile->tmask.data = 0; /* for GC */
+ }
+ if (ctile->tbits.data != 0) {
+ mdev.width = ctile->tbits.size.x;
+ mdev.height = ctile->tbits.size.y;
+ mdev.color_info.depth = ctile->depth;
+ pcache->bits_used -= gdev_mem_bitmap_size(&mdev);
+ gs_free_object(pcache->memory, ctile->tbits.data,
+ "free_pattern_cache_entry(bits data)");
+ ctile->tbits.data = 0; /* for GC */
+ }
+ ctile->id = gx_no_bitmap_id;
+ pcache->tiles_used--;
+ }
+}
+
+/* Add a Pattern cache entry. This is exported for the interpreter. */
+/* Note that this does not free any of the data in the accumulator */
+/* device, but it may zero out the bitmap_memory pointers to prevent */
+/* the accumulated bitmaps from being freed when the device is closed. */
+private void make_bitmap(P3(gx_strip_bitmap *, const gx_device_memory *, gx_bitmap_id));
+int
+gx_pattern_cache_add_entry(gs_imager_state * pis,
+ gx_device_pattern_accum * padev, gx_color_tile ** pctile)
+{
+ gx_device_memory *mbits = padev->bits;
+ gx_device_memory *mmask = padev->mask;
+ const gs_pattern_instance *pinst = padev->instance;
+ gx_pattern_cache *pcache;
+ ulong used = 0;
+ gx_bitmap_id id = pinst->id;
+ gx_color_tile *ctile;
+ int code = ensure_pattern_cache(pis);
+
+ if (code < 0)
+ return code;
+ pcache = pis->pattern_cache;
+ /*
+ * Check whether the pattern completely fills its box.
+ * If so, we can avoid the expensive masking operations
+ * when using the pattern.
+ */
+ if (mmask != 0) {
+ int y;
+
+ for (y = 0; y < mmask->height; y++) {
+ const byte *row = scan_line_base(mmask, y);
+ int w;
+
+ for (w = mmask->width; w > 8; w -= 8)
+ if (*row++ != 0xff)
+ goto keep;
+ if ((*row | (0xff >> w)) != 0xff)
+ goto keep;
+ }
+ /* We don't need a mask. */
+ mmask = 0;
+ keep:;
+ }
+ if (mbits != 0)
+ used += gdev_mem_bitmap_size(mbits);
+ if (mmask != 0)
+ used += gdev_mem_bitmap_size(mmask);
+ ctile = &pcache->tiles[id % pcache->num_tiles];
+ gx_pattern_cache_free_entry(pcache, ctile);
+ while (pcache->bits_used + used > pcache->max_bits &&
+ pcache->bits_used != 0 /* allow 1 oversized entry (?) */
+ ) {
+ pcache->next = (pcache->next + 1) % pcache->num_tiles;
+ gx_pattern_cache_free_entry(pcache, &pcache->tiles[pcache->next]);
+ }
+ ctile->id = id;
+ ctile->depth = padev->color_info.depth;
+ ctile->uid = pinst->template.uid;
+ ctile->tiling_type = pinst->template.TilingType;
+ ctile->step_matrix = pinst->step_matrix;
+ ctile->bbox = pinst->bbox;
+ ctile->is_simple = pinst->is_simple;
+ if (mbits != 0) {
+ make_bitmap(&ctile->tbits, mbits, gs_next_ids(1));
+ mbits->bitmap_memory = 0; /* don't free the bits */
+ } else
+ ctile->tbits.data = 0;
+ if (mmask != 0) {
+ make_bitmap(&ctile->tmask, mmask, id);
+ mmask->bitmap_memory = 0; /* don't free the bits */
+ } else
+ ctile->tmask.data = 0;
+ pcache->bits_used += used;
+ pcache->tiles_used++;
+ *pctile = ctile;
+ return 0;
+}
+private void
+make_bitmap(register gx_strip_bitmap * pbm, const gx_device_memory * mdev,
+ gx_bitmap_id id)
+{
+ pbm->data = mdev->base;
+ pbm->raster = mdev->raster;
+ pbm->rep_width = pbm->size.x = mdev->width;
+ pbm->rep_height = pbm->size.y = mdev->height;
+ pbm->id = id;
+ pbm->rep_shift = pbm->shift = 0;
+}
+
+/* Purge selected entries from the pattern cache. */
+void
+gx_pattern_cache_winnow(gx_pattern_cache * pcache,
+ bool(*proc) (P2(gx_color_tile * ctile, void *proc_data)), void *proc_data)
+{
+ uint i;
+
+ if (pcache == 0) /* no cache created yet */
+ return;
+ for (i = 0; i < pcache->num_tiles; ++i) {
+ gx_color_tile *ctile = &pcache->tiles[i];
+
+ if (ctile->id != gx_no_bitmap_id && (*proc) (ctile, proc_data))
+ gx_pattern_cache_free_entry(pcache, ctile);
+ }
+}
+
+/* Reload a (non-null) Pattern color into the cache. */
+/* *pdc is already set, except for colors.pattern.p_tile and mask.m_tile. */
+int
+gx_pattern_load(gx_device_color * pdc, const gs_imager_state * pis,
+ gx_device * dev, gs_color_select_t select)
+{
+ gx_device_pattern_accum adev;
+ gs_pattern_instance *pinst = pdc->mask.ccolor.pattern;
+ gs_state *saved;
+ gx_color_tile *ctile;
+ gs_memory_t *mem = pis->memory;
+ int code;
+
+ if (gx_pattern_cache_lookup(pdc, pis, dev, select))
+ return 0;
+ /* We REALLY don't like the following cast.... */
+ code = ensure_pattern_cache((gs_imager_state *) pis);
+ if (code < 0)
+ return code;
+ gx_device_init((gx_device *) & adev,
+ (const gx_device *)&gs_pattern_accum_device,
+ NULL, true);
+ gx_device_forward_fill_in_procs((gx_device_forward *) & adev); /* (should only do once) */
+ adev.target = dev;
+ adev.instance = pinst;
+ adev.bitmap_memory = mem;
+ code = (*dev_proc(&adev, open_device)) ((gx_device *) & adev);
+ if (code < 0)
+ return code;
+ saved = gs_gstate(pinst->saved);
+ if (saved == 0)
+ return_error(gs_error_VMerror);
+ if (saved->pattern_cache == 0)
+ saved->pattern_cache = pis->pattern_cache;
+ gx_set_device_only(saved, (gx_device *) & adev);
+ code = (*pinst->template.PaintProc) (&pdc->mask.ccolor, saved);
+ if (code < 0) {
+ (*dev_proc(&adev, close_device)) ((gx_device *) & adev);
+ gs_state_free(saved);
+ return code;
+ }
+ /* We REALLY don't like the following cast.... */
+ code = gx_pattern_cache_add_entry((gs_imager_state *) pis, &adev,
+ &ctile);
+ if (code >= 0) {
+ if (!gx_pattern_cache_lookup(pdc, pis, dev, select)) {
+ lprintf("Pattern cache lookup failed after insertion!\n");
+ code = gs_note_error(gs_error_Fatal);
+ }
+ }
+ /* Free the bookkeeping structures, except for the bits and mask */
+ /* iff they are still needed. */
+ (*dev_proc(&adev, close_device)) ((gx_device *) & adev);
+#ifdef DEBUG
+ if (gs_debug_c('B')) {
+ if (adev.mask)
+ debug_dump_bitmap(adev.mask->base, adev.mask->raster,
+ adev.mask->height, "[B]Pattern mask");
+ if (adev.bits)
+ debug_dump_bitmap(((gx_device_memory *) adev.target)->base,
+ ((gx_device_memory *) adev.target)->raster,
+ adev.target->height, "[B]Pattern bits");
+ }
+#endif
+ gs_state_free(saved);
+ return code;
+}
+
+/* Remap a Pattern color. */
+cs_proc_remap_color(gx_remap_Pattern); /* check the prototype */
+int
+gx_remap_Pattern(const gs_client_color * pc, const gs_color_space * pcs,
+ gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
+ gs_color_select_t select)
+{
+ gs_pattern_instance *pinst = pc->pattern;
+ int code;
+
+ pdc->mask.ccolor = *pc;
+ if (pinst == 0) {
+ /* Null pattern */
+ color_set_null_pattern(pdc);
+ return 0;
+ }
+ if (pinst->template.PaintType == 2) { /* uncolored */
+ code = (*pcs->params.pattern.base_space.type->remap_color)
+ (pc, (const gs_color_space *)&pcs->params.pattern.base_space,
+ pdc, pis, dev, select);
+ if (code < 0)
+ return code;
+ if (pdc->type == gx_dc_type_pure)
+ pdc->type = &gx_dc_pure_masked;
+ else if (pdc->type == gx_dc_type_ht_binary)
+ pdc->type = &gx_dc_binary_masked;
+ else if (pdc->type == gx_dc_type_ht_colored)
+ pdc->type = &gx_dc_colored_masked;
+ else
+ return_error(gs_error_unregistered);
+ } else
+ color_set_null_pattern(pdc);
+ pdc->mask.id = pinst->id;
+ pdc->mask.m_tile = 0;
+ return gx_pattern_load(pdc, pis, dev, select);
+}
diff --git a/pstoraster/gxpcolor.h b/pstoraster/gxpcolor.h
new file mode 100644
index 000000000..9b3a0f124
--- /dev/null
+++ b/pstoraster/gxpcolor.h
@@ -0,0 +1,138 @@
+/* Copyright (C) 1993, 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$ */
+/* Requires gsmatrix.h, gxdevice.h, gxdevmem.h, gxcolor2.h, gxdcolor.h */
+
+#ifndef gxpcolor_INCLUDED
+# define gxpcolor_INCLUDED
+
+#include "gxpcache.h"
+
+/*
+ * Define the Pattern device color types. There is one type for
+ * colored patterns, and one uncolored pattern type for each non-Pattern
+ * device color type.
+ */
+extern const gx_device_color_type_t
+ gx_dc_pattern, gx_dc_pure_masked, gx_dc_binary_masked, gx_dc_colored_masked;
+
+#define gx_dc_type_pattern (&gx_dc_pattern)
+
+/*
+ * Define a color tile, an entry in the rendered Pattern cache (and
+ * eventually in the colored halftone cache). Note that the depth is
+ * not sufficient to ensure that the rendering matches a given device;
+ * however, we don't currently have an object that represents the
+ * abstraction of a 'color representation'.
+ */
+struct gx_color_tile_s {
+ /* ------ The following are the 'key' in the cache. ------ */
+ /* Note that the id is a generated instance ID, */
+ /* and has no relation to the template's gs_uid. */
+ gx_bitmap_id id;
+ int depth;
+ /* We do, however, copy the template's gs_uid, */
+ /* for use in selective cache purging. */
+ gs_uid uid;
+ /* ------ The following are the cache 'value'. ------ */
+ /* Note that if tbits and tmask both have data != 0, */
+ /* both must have the same rep_shift. */
+/****** NON-ZERO shift VALUES ARE NOT SUPPORTED YET. ******/
+ int tiling_type; /* TilingType */
+ gs_matrix step_matrix; /* tiling space -> device space, */
+ /* see gxcolor2.h for details */
+ gs_rect bbox; /* bbox of tile in tiling space */
+ gx_strip_bitmap tbits; /* data = 0 if uncolored */
+ gx_strip_bitmap tmask; /* data = 0 if no mask */
+ /* (i.e., the mask is all 1's) */
+ bool is_simple; /* true if xstep/ystep = tile size */
+ /* The following is neither key nor value. */
+ uint index; /* the index of the tile within */
+ /* the cache (for GC) */
+};
+
+#define private_st_color_tile() /* in gxpcmap.c */\
+ gs_private_st_ptrs2(st_color_tile, gx_color_tile, "gx_color_tile",\
+ color_tile_enum_ptrs, color_tile_reloc_ptrs, tbits.data, tmask.data)
+#define private_st_color_tile_element() /* in gxpcmap.c */\
+ gs_private_st_element(st_color_tile_element, gx_color_tile,\
+ "gx_color_tile[]", color_tile_elt_enum_ptrs, color_tile_elt_reloc_ptrs,\
+ st_color_tile)
+
+/* Define the Pattern cache. */
+ /*#include "gxpcache.h" *//* (above) */
+
+/* Allocate a Pattern cache. */
+/* We shorten the procedure names because some VMS compilers */
+/* truncate names to 23 characters. */
+uint gx_pat_cache_default_tiles(P0());
+ulong gx_pat_cache_default_bits(P0());
+gx_pattern_cache *gx_pattern_alloc_cache(P3(gs_memory_t *, uint, ulong));
+
+/* Get or set the Pattern cache in a gstate. */
+gx_pattern_cache *gstate_pattern_cache(P1(gs_state *));
+void gstate_set_pattern_cache(P2(gs_state *, gx_pattern_cache *));
+
+/*
+ * Define a device for accumulating the rendering of a Pattern.
+ * This is actually a wrapper for two other devices: one that accumulates
+ * the actual pattern image (if this is a colored pattern), and one that
+ * accumulates a mask defining which pixels in the image are set.
+ */
+typedef struct gx_device_pattern_accum_s {
+ gx_device_forward_common;
+ /* Client sets these before opening */
+ gs_memory_t *bitmap_memory;
+ const gs_pattern_instance *instance;
+ /* open sets these */
+ gx_device_memory *bits; /* target also points to bits */
+ gx_device_memory *mask;
+} gx_device_pattern_accum;
+
+#define private_st_device_pattern_accum() /* in gxpcmap.c */\
+ gs_private_st_suffix_add3(st_device_pattern_accum, gx_device_pattern_accum,\
+ "pattern accumulator", pattern_accum_enum, pattern_accum_reloc,\
+ st_device_forward, instance, bits, mask)
+
+/* Allocate a pattern accumulator. */
+gx_device_pattern_accum *gx_pattern_accum_alloc(P2(gs_memory_t * memory, client_name_t));
+
+/* Add an accumulated pattern to the cache. */
+/* Note that this does not free any of the data in the accumulator */
+/* device, but it may zero out the bitmap_memory pointers to prevent */
+/* the accumulated bitmaps from being freed when the device is closed. */
+int gx_pattern_cache_add_entry(P3(gs_imager_state *, gx_device_pattern_accum *,
+ gx_color_tile **));
+
+/* Look up a pattern color in the cache. */
+bool gx_pattern_cache_lookup(P4(gx_device_color *, const gs_imager_state *,
+ gx_device *, gs_color_select_t));
+
+/* Purge selected entries from the pattern cache. */
+void gx_pattern_cache_winnow(P3(gx_pattern_cache *,
+ bool (*)(P2(gx_color_tile *, void *)),
+ void *));
+
+#endif /* gxpcolor_INCLUDED */
diff --git a/pstoraster/gxpcopy.c b/pstoraster/gxpcopy.c
new file mode 100644
index 000000000..cf917f10e
--- /dev/null
+++ b/pstoraster/gxpcopy.c
@@ -0,0 +1,824 @@
+/* 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$ */
+/* Path copying and flattening */
+#include "math_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gconfigv.h" /* for USE_FPU */
+#include "gxfixed.h"
+#include "gxfarith.h"
+#include "gzpath.h"
+
+/* Forward declarations */
+private void adjust_point_to_tangent(P3(segment *, const segment *,
+ const gs_fixed_point *));
+private int monotonize_internal(P2(gx_path *, const curve_segment *));
+
+/* Copy a path, optionally flattening or monotonizing it. */
+/* If the copy fails, free the new path. */
+int
+gx_path_copy_reducing(const gx_path * ppath_old, gx_path * ppath,
+ fixed fixed_flatness, gx_path_copy_options options)
+{
+ const segment *pseg;
+
+ /*
+ * Since we're going to be adding to the path, unshare it
+ * before we start.
+ */
+ int code = gx_path_unshare(ppath);
+
+ if (code < 0)
+ return code;
+#ifdef DEBUG
+ if (gs_debug_c('P'))
+ gx_dump_path(ppath_old, "before reducing");
+#endif
+ pseg = (const segment *)(ppath_old->first_subpath);
+ while (pseg) {
+ switch (pseg->type) {
+ case s_start:
+ code = gx_path_add_point(ppath,
+ pseg->pt.x, pseg->pt.y);
+ break;
+ case s_curve:
+ {
+ const curve_segment *pc = (const curve_segment *)pseg;
+
+ if (fixed_flatness == max_fixed) { /* don't flatten */
+ if (options & pco_monotonize)
+ code = monotonize_internal(ppath, pc);
+ else
+ code = gx_path_add_curve_notes(ppath,
+ pc->p1.x, pc->p1.y, pc->p2.x, pc->p2.y,
+ pc->pt.x, pc->pt.y, pseg->notes);
+ } else {
+ fixed x0 = ppath->position.x;
+ fixed y0 = ppath->position.y;
+ int k = gx_curve_log2_samples(x0, y0, pc,
+ fixed_flatness);
+ segment_notes notes = pseg->notes;
+ segment *start;
+ curve_segment cseg;
+
+ if (options & pco_accurate) { /* Add an extra line, which will become */
+ /* the tangent segment. */
+ code = gx_path_add_line_notes(ppath, x0, y0,
+ notes);
+ if (code < 0)
+ break;
+ start = ppath->current_subpath->last;
+ notes |= sn_not_first;
+ }
+ cseg = *pc;
+ code = gx_flatten_sample(ppath, k, &cseg, notes);
+ if (options & pco_accurate) { /*
+ * Adjust the first and last segments so that
+ * they line up with the tangents.
+ */
+ segment *end = ppath->current_subpath->last;
+
+ if (code < 0 ||
+ (code = gx_path_add_line_notes(ppath,
+ ppath->position.x,
+ ppath->position.y,
+ pseg->notes | sn_not_first)) < 0
+ )
+ break;
+ adjust_point_to_tangent(start, start->next,
+ &pc->p1);
+ adjust_point_to_tangent(end, end->prev,
+ &pc->p2);
+ }
+ }
+ break;
+ }
+ case s_line:
+ code = gx_path_add_line_notes(ppath,
+ pseg->pt.x, pseg->pt.y, pseg->notes);
+ break;
+ case s_line_close:
+ code = gx_path_close_subpath(ppath);
+ break;
+ default: /* can't happen */
+ code = gs_note_error(gs_error_unregistered);
+ }
+ if (code < 0) {
+ gx_path_new(ppath);
+ return code;
+ }
+ pseg = pseg->next;
+ }
+ if (path_last_is_moveto(ppath_old))
+ gx_path_add_point(ppath, ppath_old->position.x,
+ ppath_old->position.y);
+#ifdef DEBUG
+ if (gs_debug_c('P'))
+ gx_dump_path(ppath, "after reducing");
+#endif
+ return 0;
+}
+
+/*
+ * Adjust one end of a line (the first or last line of a flattened curve)
+ * so it falls on the curve tangent. The closest point on the line from
+ * (0,0) to (C,D) to a point (U,V) -- i.e., the point on the line at which
+ * a perpendicular line from the point intersects it -- is given by
+ * T = (C*U + D*V) / (C^2 + D^2)
+ * (X,Y) = (C*T,D*T)
+ * However, any smaller value of T will also work: the one we actually
+ * use is 0.25 * the value we just derived. We must check that
+ * numerical instabilities don't lead to a negative value of T.
+ */
+private void
+adjust_point_to_tangent(segment * pseg, const segment * next,
+ const gs_fixed_point * p1)
+{
+ const fixed x0 = pseg->pt.x, y0 = pseg->pt.y;
+ const fixed fC = p1->x - x0, fD = p1->y - y0;
+
+ /*
+ * By far the commonest case is that the end of the curve is
+ * horizontal or vertical. Check for this specially, because
+ * we can handle it with far less work (and no floating point).
+ */
+ if (fC == 0) {
+ /* Vertical tangent. */
+ const fixed DT = arith_rshift(next->pt.y - y0, 2);
+
+ if (fD == 0)
+ return; /* anomalous case */
+ if_debug1('2', "[2]adjusting vertical: DT = %g\n",
+ fixed2float(DT));
+ if (DT > 0)
+ pseg->pt.y = DT + y0;
+ } else if (fD == 0) {
+ /* Horizontal tangent. */
+ const fixed CT = arith_rshift(next->pt.x - x0, 2);
+
+ if_debug1('2', "[2]adjusting horizontal: CT = %g\n",
+ fixed2float(CT));
+ if (CT > 0)
+ pseg->pt.x = CT + x0;
+ } else {
+ /* General case. */
+ const double C = fC, D = fD;
+ const double T = (C * (next->pt.x - x0) + D * (next->pt.y - y0)) /
+ (C * C + D * D);
+
+ if_debug3('2', "[2]adjusting: C = %g, D = %g, T = %g\n",
+ C, D, T);
+ if (T > 0) {
+ pseg->pt.x = arith_rshift((fixed) (C * T), 2) + x0;
+ pseg->pt.y = arith_rshift((fixed) (D * T), 2) + y0;
+ }
+ }
+}
+
+/* ---------------- Curve flattening ---------------- */
+
+#define x1 pc->p1.x
+#define y1 pc->p1.y
+#define x2 pc->p2.x
+#define y2 pc->p2.y
+#define x3 pc->pt.x
+#define y3 pc->pt.y
+
+#ifdef DEBUG
+private void
+dprint_curve(const char *str, fixed x0, fixed y0, const curve_segment * pc)
+{
+ dlprintf9("%s p0=(%g,%g) p1=(%g,%g) p2=(%g,%g) p3=(%g,%g)\n",
+ str, fixed2float(x0), fixed2float(y0),
+ fixed2float(pc->p1.x), fixed2float(pc->p1.y),
+ fixed2float(pc->p2.x), fixed2float(pc->p2.y),
+ fixed2float(pc->pt.x), fixed2float(pc->pt.y));
+}
+#endif
+
+/* Initialize a cursor for rasterizing a monotonic curve. */
+void
+gx_curve_cursor_init(curve_cursor * prc, fixed x0, fixed y0,
+ const curve_segment * pc, int k)
+{
+ fixed v01, v12;
+ int k2 = k + k, k3 = k2 + k;
+
+#define bits_fit(v, n)\
+ (any_abs(v) <= max_fixed >> (n))
+/* The +2s are because of t3d and t2d, see below. */
+#define coeffs_fit(a, b, c)\
+ (k3 <= sizeof(fixed) * 8 - 3 &&\
+ bits_fit(a, k3 + 2) && bits_fit(b, k2 + 2) && bits_fit(c, k + 1))
+
+ prc->k = k;
+ prc->p0.x = x0, prc->p0.y = y0;
+ prc->pc = pc;
+ /* Compute prc->a..c taking into account reversal of xy0/3 */
+ /* in curve_x_at_y. */
+ {
+ fixed w0, w1, w2, w3;
+
+ if (y0 < y3)
+ w0 = x0, w1 = x1, w2 = x2, w3 = x3;
+ else
+ w0 = x3, w1 = x2, w2 = x1, w3 = x0;
+ curve_points_to_coefficients(w0, w1, w2, w3,
+ prc->a, prc->b, prc->c, v01, v12);
+ }
+ prc->double_set = false;
+ prc->fixed_limit =
+ (coeffs_fit(prc->a, prc->b, prc->c) ? (1 << k) - 1 : -1);
+ /* Initialize the cache. */
+ prc->cache.ky0 = prc->cache.ky3 = y0;
+ prc->cache.xl = x0;
+ prc->cache.xd = 0;
+}
+
+/*
+ * Determine the X value on a monotonic curve at a given Y value. It turns
+ * out that we use so few points on the curve that it's actually faster to
+ * locate the desired point by recursive subdivision each time than to try
+ * to keep a cursor that we move incrementally. What's even more surprising
+ * is that if floating point arithmetic is reasonably fast, it's faster to
+ * compute the X value at the desired point explicitly than to do the
+ * recursive subdivision on X as well as Y.
+ */
+#define SUBDIVIDE_X USE_FPU_FIXED
+fixed
+gx_curve_x_at_y(curve_cursor * prc, fixed y)
+{
+ fixed xl, xd;
+ fixed yd, yrel;
+
+ /* Check the cache before doing anything else. */
+ if (y >= prc->cache.ky0 && y <= prc->cache.ky3) {
+ yd = prc->cache.ky3 - prc->cache.ky0;
+ yrel = y - prc->cache.ky0;
+ xl = prc->cache.xl;
+ xd = prc->cache.xd;
+ goto done;
+ } {
+#define x0 prc->p0.x
+#define y0 prc->p0.y
+ const curve_segment *pc = prc->pc;
+
+ /* Reduce case testing by ensuring y3 >= y0. */
+ fixed cy0 = y0, cy1, cy2, cy3 = y3;
+ fixed cx0;
+
+#if SUBDIVIDE_X
+ fixed cx1, cx2, cx3;
+
+#else
+ int t = 0;
+
+#endif
+ int k, i;
+
+ if (cy0 > cy3)
+ cx0 = x3,
+#if SUBDIVIDE_X
+ cx1 = x2, cx2 = x1, cx3 = x0,
+#endif
+ cy0 = y3, cy1 = y2, cy2 = y1, cy3 = y0;
+ else
+ cx0 = x0,
+#if SUBDIVIDE_X
+ cx1 = x1, cx2 = x2, cx3 = x3,
+#endif
+ cy1 = y1, cy2 = y2;
+#define midpoint_fast(a,b)\
+ arith_rshift_1((a) + (b) + 1)
+ for (i = k = prc->k; i > 0; --i) {
+ fixed ym = midpoint_fast(cy1, cy2);
+ fixed yn = ym + arith_rshift(cy0 - cy1 - cy2 + cy3 + 4, 3);
+
+#if SUBDIVIDE_X
+ fixed xm = midpoint_fast(cx1, cx2);
+ fixed xn = xm + arith_rshift(cx0 - cx1 - cx2 + cx3 + 4, 3);
+
+#else
+ t <<= 1;
+#endif
+
+ if (y < yn)
+#if SUBDIVIDE_X
+ cx1 = midpoint_fast(cx0, cx1),
+ cx2 = midpoint_fast(cx1, xm),
+ cx3 = xn,
+#endif
+ cy1 = midpoint_fast(cy0, cy1),
+ cy2 = midpoint_fast(cy1, ym),
+ cy3 = yn;
+ else
+#if SUBDIVIDE_X
+ cx2 = midpoint_fast(cx2, cx3),
+ cx1 = midpoint_fast(xm, cx2),
+ cx0 = xn,
+#else
+ t++,
+#endif
+ cy2 = midpoint_fast(cy2, cy3),
+ cy1 = midpoint_fast(ym, cy2),
+ cy0 = yn;
+ }
+#if SUBDIVIDE_X
+ xl = cx0;
+ xd = cx3 - cx0;
+#else
+ {
+ fixed a = prc->a, b = prc->b, c = prc->c;
+
+/* We must use (1 << k) >> 1 instead of 1 << (k - 1) in case k == 0. */
+#define compute_fixed(a, b, c)\
+ arith_rshift(arith_rshift(arith_rshift(a * t3, k) + b * t2, k)\
+ + c * t + ((1 << k) >> 1), k)
+#define compute_diff_fixed(a, b, c)\
+ arith_rshift(arith_rshift(arith_rshift(a * t3d, k) + b * t2d, k)\
+ + c, k)
+
+ /* use multiply if possible */
+#define np2(n) (1.0 / (1L << (n)))
+ static const double k_denom[11] =
+ {np2(0), np2(1), np2(2), np2(3), np2(4),
+ np2(5), np2(6), np2(7), np2(8), np2(9), np2(10)
+ };
+ static const double k2_denom[11] =
+ {np2(0), np2(2), np2(4), np2(6), np2(8),
+ np2(10), np2(12), np2(14), np2(16), np2(18), np2(20)
+ };
+ static const double k3_denom[11] =
+ {np2(0), np2(3), np2(6), np2(9), np2(12),
+ np2(15), np2(18), np2(21), np2(24), np2(27), np2(30)
+ };
+ double den1, den2;
+
+#undef np2
+
+#define setup_floating(da, db, dc, a, b, c)\
+ (k >= countof(k_denom) ?\
+ (den1 = ldexp(1.0, -k),\
+ den2 = den1 * den1,\
+ da = (den2 * den1) * a,\
+ db = den2 * b,\
+ dc = den1 * c) :\
+ (da = k3_denom[k] * a,\
+ db = k2_denom[k] * b,\
+ dc = k_denom[k] * c))
+#define compute_floating(da, db, dc)\
+ ((fixed)(da * t3 + db * t2 + dc * t + 0.5))
+#define compute_diff_floating(da, db, dc)\
+ ((fixed)(da * t3d + db * t2d + dc))
+
+ if (t <= prc->fixed_limit) { /* We can do everything in integer/fixed point. */
+ int t2 = t * t, t3 = t2 * t;
+ int t3d = (t2 + t) * 3 + 1, t2d = t + t + 1;
+
+ xl = compute_fixed(a, b, c) + cx0;
+ xd = compute_diff_fixed(a, b, c);
+#ifdef DEBUG
+ {
+ double fa, fb, fc;
+ fixed xlf, xdf;
+
+ setup_floating(fa, fb, fc, a, b, c);
+ xlf = compute_floating(fa, fb, fc) + cx0;
+ xdf = compute_diff_floating(fa, fb, fc);
+ if (any_abs(xlf - xl) > fixed_epsilon ||
+ any_abs(xdf - xd) > fixed_epsilon
+ )
+ dlprintf9("Curve points differ: k=%d t=%d a,b,c=%g,%g,%g\n xl,xd fixed=%g,%g floating=%g,%g\n",
+ k, t,
+ fixed2float(a), fixed2float(b), fixed2float(c),
+ fixed2float(xl), fixed2float(xd),
+ fixed2float(xlf), fixed2float(xdf));
+/*xl = xlf, xd = xdf; */
+ }
+#endif
+ } else { /*
+ * Either t3 (and maybe t2) won't fit in an int, or more
+ * likely the result of the multiplies won't fit.
+ */
+#define fa prc->da
+#define fb prc->db
+#define fc prc->dc
+ if (!prc->double_set) {
+ setup_floating(fa, fb, fc, a, b, c);
+ prc->double_set = true;
+ }
+ if (t < 1L << ((sizeof(long) * 8 - 1) / 3)) { /*
+ * t3 (and maybe t2) might not fit in an int, but they
+ * will fit in a long. If we have slow floating point,
+ * do the computation in double-precision fixed point,
+ * otherwise do it in fixed point.
+ */
+ long t2 = (long)t * t, t3 = t2 * t;
+ long t3d = (t2 + t) * 3 + 1, t2d = t + t + 1;
+
+ xl = compute_floating(fa, fb, fc) + cx0;
+ xd = compute_diff_floating(fa, fb, fc);
+ } else { /*
+ * t3 (and maybe t2) don't even fit in a long.
+ * Do the entire computation in floating point.
+ */
+ double t2 = (double)t * t, t3 = t2 * t;
+ double t3d = (t2 + t) * 3 + 1, t2d = t + t + 1;
+
+ xl = compute_floating(fa, fb, fc) + cx0;
+ xd = compute_diff_floating(fa, fb, fc);
+ }
+#undef fa
+#undef fb
+#undef fc
+ }
+ }
+#endif /* (!)SUBDIVIDE_X */
+
+ /* Update the cache. */
+ prc->cache.ky0 = cy0;
+ prc->cache.ky3 = cy3;
+ prc->cache.xl = xl;
+ prc->cache.xd = xd;
+ yd = cy3 - cy0;
+ yrel = y - cy0;
+#undef x0
+#undef y0
+ }
+ done:
+ /*
+ * Now interpolate linearly between current and next.
+ * We know that 0 <= yrel < yd.
+ * It's unlikely but possible that cy0 = y = cy3:
+ * handle this case specially.
+ */
+ if (yrel == 0)
+ return xl;
+ /*
+ * Compute in fixed point if possible.
+ */
+#define half_fixed_bits ((fixed)1 << (sizeof(fixed) * 4))
+ if (yrel < half_fixed_bits) {
+ if (xd >= 0) {
+ if (xd < half_fixed_bits)
+ return (ufixed) xd *(ufixed) yrel / (ufixed) yd + xl;
+ } else {
+ if (xd > -half_fixed_bits)
+ return -(fixed) ((ufixed) (-xd) * (ufixed) yrel / (ufixed) yd) + xl;
+ }
+ }
+#undef half_fixed_bits
+ return fixed_mult_quo(xd, yrel, yd) + xl;
+}
+
+#undef x1
+#undef y1
+#undef x2
+#undef y2
+#undef x3
+#undef y3
+
+/* ---------------- Monotonic curves ---------------- */
+
+/* Test whether a path is free of non-monotonic curves. */
+bool
+gx_path_is_monotonic(const gx_path * ppath)
+{
+ const segment *pseg = (const segment *)(ppath->first_subpath);
+ gs_fixed_point pt0;
+
+ while (pseg) {
+ switch (pseg->type) {
+ case s_start:
+ {
+ const subpath *psub = (const subpath *)pseg;
+
+ /* Skip subpaths without curves. */
+ if (!psub->curve_count)
+ pseg = psub->last;
+ }
+ break;
+ case s_curve:
+ {
+ const curve_segment *pc = (const curve_segment *)pseg;
+ double t[2];
+ int nz = gx_curve_monotonic_points(pt0.y,
+ pc->p1.y, pc->p2.y, pc->pt.y, t);
+
+ if (nz != 0)
+ return false;
+ nz = gx_curve_monotonic_points(pt0.x,
+ pc->p1.x, pc->p2.x, pc->pt.x, t);
+ if (nz != 0)
+ return false;
+ }
+ break;
+ default:
+ ;
+ }
+ pt0 = pseg->pt;
+ pseg = pseg->next;
+ }
+ return true;
+}
+
+/* Monotonize a curve, by splitting it if necessary. */
+/* In the worst case, this could split the curve into 9 pieces. */
+private int
+monotonize_internal(gx_path * ppath, const curve_segment * pc)
+{
+ fixed x0 = ppath->position.x, y0 = ppath->position.y;
+ segment_notes notes = pc->notes;
+ double t[2];
+
+#define max_segs 9
+ curve_segment cs[max_segs];
+ const curve_segment *pcs;
+ curve_segment *pcd;
+ int i, j, nseg;
+ int nz;
+
+ /* Monotonize in Y. */
+ nz = gx_curve_monotonic_points(y0, pc->p1.y, pc->p2.y, pc->pt.y, t);
+ nseg = max_segs - 1 - nz;
+ pcd = cs + nseg;
+ if (nz == 0)
+ *pcd = *pc;
+ else {
+ gx_curve_split(x0, y0, pc, t[0], pcd, pcd + 1);
+ if (nz == 2)
+ gx_curve_split(pcd->pt.x, pcd->pt.y, pcd + 1,
+ (t[1] - t[0]) / (1 - t[0]),
+ pcd + 1, pcd + 2);
+ }
+
+ /* Monotonize in X. */
+ for (pcs = pcd, pcd = cs, j = nseg; j < max_segs; ++pcs, ++j) {
+ nz = gx_curve_monotonic_points(x0, pcs->p1.x, pcs->p2.x,
+ pcs->pt.x, t);
+
+ if (nz == 0)
+ *pcd = *pcs;
+ else {
+ gx_curve_split(x0, y0, pcs, t[0], pcd, pcd + 1);
+ if (nz == 2)
+ gx_curve_split(pcd->pt.x, pcd->pt.y, pcd + 1,
+ (t[1] - t[0]) / (1 - t[0]),
+ pcd + 1, pcd + 2);
+ }
+ pcd += nz + 1;
+ x0 = pcd[-1].pt.x;
+ y0 = pcd[-1].pt.y;
+ }
+ nseg = pcd - cs;
+
+ /* Add the segment(s) to the output. */
+#ifdef DEBUG
+ if (gs_debug_c('2')) {
+ int pi;
+ gs_fixed_point pp0;
+
+ pp0 = ppath->position;
+ if (nseg == 1)
+ dprint_curve("[2]No split", pp0.x, pp0.y, pc);
+ else {
+ dlprintf1("[2]Split into %d segments:\n", nseg);
+ dprint_curve("[2]Original", pp0.x, pp0.y, pc);
+ for (pi = 0; pi < nseg; ++pi) {
+ dprint_curve("[2] =>", pp0.x, pp0.y, cs + pi);
+ pp0 = cs[pi].pt;
+ }
+ }
+ }
+#endif
+ for (pcs = cs, i = 0; i < nseg; ++pcs, ++i) {
+ int code = gx_path_add_curve_notes(ppath, pcs->p1.x, pcs->p1.y,
+ pcs->p2.x, pcs->p2.y,
+ pcs->pt.x, pcs->pt.y,
+ notes |
+ (i > 0 ? sn_not_first :
+ sn_none));
+
+ if (code < 0)
+ return code;
+ }
+
+ return 0;
+}
+
+/*
+ * Split a curve if necessary into pieces that are monotonic in X or Y as a
+ * function of the curve parameter t. This allows us to rasterize curves
+ * directly without pre-flattening. This takes a fair amount of analysis....
+ * Store the values of t of the split points in pst[0] and pst[1]. Return
+ * the number of split points (0, 1, or 2).
+ */
+int
+gx_curve_monotonic_points(fixed v0, fixed v1, fixed v2, fixed v3,
+ double pst[2])
+{
+ /*
+ Let
+ v(t) = a*t^3 + b*t^2 + c*t + d, 0 <= t <= 1.
+ Then
+ dv(t) = 3*a*t^2 + 2*b*t + c.
+ v(t) has a local minimum or maximum (or inflection point)
+ precisely where dv(t) = 0. Now the roots of dv(t) = 0 (i.e.,
+ the zeros of dv(t)) are at
+ t = ( -2*b +/- sqrt(4*b^2 - 12*a*c) ) / 6*a
+ = ( -b +/- sqrt(b^2 - 3*a*c) ) / 3*a
+ (Note that real roots exist iff b^2 >= 3*a*c.)
+ We want to know if these lie in the range (0..1).
+ (The endpoints don't count.) Call such a root a "valid zero."
+ Since computing the roots is expensive, we would like to have
+ some cheap tests to filter out cases where they don't exist
+ (i.e., where the curve is already monotonic).
+ */
+ fixed v01, v12, a, b, c, b2, a3;
+ fixed dv_end, b2abs, a3abs;
+
+ curve_points_to_coefficients(v0, v1, v2, v3, a, b, c, v01, v12);
+ b2 = b << 1;
+ a3 = (a << 1) + a;
+ /*
+ If a = 0, the only possible zero is t = -c / 2*b.
+ This zero is valid iff sign(c) != sign(b) and 0 < |c| < 2*|b|.
+ */
+ if (a == 0) {
+ if ((b ^ c) < 0 && any_abs(c) < any_abs(b2) && c != 0) {
+ *pst = (double)(-c) / b2;
+ return 1;
+ } else
+ return 0;
+ }
+ /*
+ Iff a curve is horizontal at t = 0, c = 0. In this case,
+ there can be at most one other zero, at -2*b / 3*a.
+ This zero is valid iff sign(a) != sign(b) and 0 < 2*|b| < 3*|a|.
+ */
+ if (c == 0) {
+ if ((a ^ b) < 0 && any_abs(b2) < any_abs(a3) && b != 0) {
+ *pst = (double)(-b2) / a3;
+ return 1;
+ } else
+ return 0;
+ }
+ /*
+ Similarly, iff a curve is horizontal at t = 1, 3*a + 2*b + c = 0.
+ In this case, there can be at most one other zero,
+ at -1 - 2*b / 3*a, iff sign(a) != sign(b) and 1 < -2*b / 3*a < 2,
+ i.e., 3*|a| < 2*|b| < 6*|a|.
+ */
+ else if ((dv_end = a3 + b2 + c) == 0) {
+ if ((a ^ b) < 0 &&
+ (b2abs = any_abs(b2)) > (a3abs = any_abs(a3)) &&
+ b2abs < a3abs << 1
+ ) {
+ *pst = (double)(-b2 - a3) / a3;
+ return 1;
+ } else
+ return 0;
+ }
+ /*
+ If sign(dv_end) != sign(c), at least one valid zero exists,
+ since dv(0) and dv(1) have opposite signs and hence
+ dv(t) must be zero somewhere in the interval [0..1].
+ */
+ else if ((dv_end ^ c) < 0);
+ /*
+ If sign(a) = sign(b), no valid zero exists,
+ since dv is monotonic on [0..1] and has the same sign
+ at both endpoints.
+ */
+ else if ((a ^ b) >= 0)
+ return 0;
+ /*
+ Otherwise, dv(t) may be non-monotonic on [0..1]; it has valid zeros
+ iff its sign anywhere in this interval is different from its sign
+ at the endpoints, which occurs iff it has an extremum in this
+ interval and the extremum is of the opposite sign from c.
+ To find this out, we look for the local extremum of dv(t)
+ by observing
+ d2v(t) = 6*a*t + 2*b
+ which has a zero only at
+ t1 = -b / 3*a
+ Now if t1 <= 0 or t1 >= 1, no valid zero exists.
+ Note that we just determined that sign(a) != sign(b), so we know t1 > 0.
+ */
+ else if (any_abs(b) >= any_abs(a3))
+ return 0;
+ /*
+ Otherwise, we just go ahead with the computation of the roots,
+ and test them for being in the correct range. Note that a valid
+ zero is an inflection point of v(t) iff d2v(t) = 0; we don't
+ bother to check for this case, since it's rare.
+ */
+ {
+ double nbf = (double)(-b);
+ double a3f = (double)a3;
+ double radicand = nbf * nbf - a3f * c;
+
+ if (radicand < 0) {
+ if_debug1('2', "[2]negative radicand = %g\n", radicand);
+ return 0;
+ } {
+ double root = sqrt(radicand);
+ int nzeros = 0;
+ double z = (nbf - root) / a3f;
+
+ /*
+ * We need to return the zeros in the correct order.
+ * We know that root is non-negative, but a3f may be either
+ * positive or negative, so we need to check the ordering
+ * explicitly.
+ */
+ if_debug2('2', "[2]zeros at %g, %g\n", z, (nbf + root) / a3f);
+ if (z > 0 && z < 1)
+ *pst = z, nzeros = 1;
+ if (root != 0) {
+ z = (nbf + root) / a3f;
+ if (z > 0 && z < 1) {
+ if (nzeros && a3f < 0) /* order is reversed */
+ pst[1] = *pst, *pst = z;
+ else
+ pst[nzeros] = z;
+ nzeros++;
+ }
+ }
+ return nzeros;
+ }
+ }
+}
+
+/*
+ * Split a curve at an arbitrary point t. The above midpoint split is a
+ * special case of this with t = 0.5.
+ */
+void
+gx_curve_split(fixed x0, fixed y0, const curve_segment * pc, double t,
+ curve_segment * pc1, curve_segment * pc2)
+{ /*
+ * If the original function was v(t), we want to compute the points
+ * for the functions v1(T) = v(t * T) and v2(T) = v(t + (1 - t) * T).
+ * Straightforwardly,
+ * v1(T) = a*t^3*T^3 + b*t^2*T^2 + c*t*T + d
+ * i.e.
+ * a1 = a*t^3, b1 = b*t^2, c1 = c*t, d1 = d.
+ * Similarly,
+ * v2(T) = a*[t + (1-t)*T]^3 + b*[t + (1-t)*T]^2 +
+ * c*[t + (1-t)*T] + d
+ * = a*[(1-t)^3*T^3 + 3*t*(1-t)^2*T^2 + 3*t^2*(1-t)*T +
+ * t^3] + b*[(1-t)^2*T^2 + 2*t*(1-t)*T + t^2] +
+ * c*[(1-t)*T + t] + d
+ * = a*(1-t)^3*T^3 + [a*3*t + b]*(1-t)^2*T^2 +
+ * [a*3*t^2 + b*2*t + c]*(1-t)*T +
+ * a*t^3 + b*t^2 + c*t + d
+ * We do this in the simplest way, namely, we convert the points to
+ * coefficients, do the arithmetic, and convert back. It would
+ * obviously be faster to do the arithmetic directly on the points,
+ * as the midpoint code does; this is just an implementation issue
+ * that we can revisit if necessary.
+ */
+ double t2 = t * t, t3 = t2 * t;
+ double omt = 1 - t, omt2 = omt * omt, omt3 = omt2 * omt;
+ fixed v01, v12, a, b, c, na, nb, nc;
+
+ if_debug1('2', "[2]splitting at t = %g\n", t);
+#define compute_seg(v0, v)\
+ curve_points_to_coefficients(v0, pc->p1.v, pc->p2.v, pc->pt.v,\
+ a, b, c, v01, v12);\
+ na = (fixed)(a * t3), nb = (fixed)(b * t2), nc = (fixed)(c * t);\
+ curve_coefficients_to_points(na, nb, nc, v0,\
+ pc1->p1.v, pc1->p2.v, pc1->pt.v);\
+ na = (fixed)(a * omt3);\
+ nb = (fixed)((a * t * 3 + b) * omt2);\
+ nc = (fixed)((a * t2 * 3 + b * 2 * t + c) * omt);\
+ curve_coefficients_to_points(na, nb, nc, pc1->pt.v,\
+ pc2->p1.v, pc2->p2.v, pc2->pt.v)
+ compute_seg(x0, x);
+ compute_seg(y0, y);
+#undef compute_seg
+}
diff --git a/pstoraster/gxpdash.c b/pstoraster/gxpdash.c
new file mode 100644
index 000000000..72d0f93f4
--- /dev/null
+++ b/pstoraster/gxpdash.c
@@ -0,0 +1,189 @@
+/* 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$ */
+/* Dash expansion for paths */
+#include "math_.h"
+#include "gx.h"
+#include "gsmatrix.h" /* for gscoord.h */
+#include "gscoord.h"
+#include "gxfixed.h"
+#include "gsline.h"
+#include "gzline.h"
+#include "gzpath.h"
+
+/* Expand a dashed path into explicit segments. */
+/* The path contains no curves. */
+private int subpath_expand_dashes(P4(const subpath *, gx_path *,
+ const gs_imager_state *,
+ const gx_dash_params *));
+int
+gx_path_add_dash_expansion(const gx_path * ppath_old, gx_path * ppath,
+ const gs_imager_state * pis)
+{
+ const subpath *psub;
+ const gx_dash_params *dash = &gs_currentlineparams(pis)->dash;
+ int code = 0;
+
+ if (dash->pattern_size == 0)
+ return gx_path_copy(ppath_old, ppath);
+ for (psub = ppath_old->first_subpath; psub != 0 && code >= 0;
+ psub = (const subpath *)psub->last->next
+ )
+ code = subpath_expand_dashes(psub, ppath, pis, dash);
+ return code;
+}
+
+private int
+subpath_expand_dashes(const subpath * psub, gx_path * ppath,
+ const gs_imager_state * pis, const gx_dash_params * dash)
+{
+ const float *pattern = dash->pattern;
+ int count, index;
+ bool ink_on;
+ float elt_length;
+ fixed x0 = psub->pt.x, y0 = psub->pt.y;
+ fixed x, y;
+ const segment *pseg;
+ int wrap = (dash->init_ink_on && psub->is_closed ? -1 : 0);
+ int drawing = wrap;
+ segment_notes notes = ~sn_not_first;
+ int code;
+
+ if ((code = gx_path_add_point(ppath, x0, y0)) < 0)
+ return code;
+ /*
+ * To do the right thing at the beginning of a closed path, we have
+ * to skip any initial line, and then redo it at the end of the
+ * path. Drawing = -1 while skipping, 0 while drawing normally, and
+ * 1 on the second round. Note that drawing != 0 implies ink_on.
+ */
+ top:count = dash->pattern_size;
+ ink_on = dash->init_ink_on;
+ index = dash->init_index;
+ elt_length = dash->init_dist_left;
+ x = x0, y = y0;
+ pseg = (const segment *)psub;
+ while ((pseg = pseg->next) != 0 && pseg->type != s_start) {
+ fixed sx = pseg->pt.x, sy = pseg->pt.y;
+ fixed udx = sx - x, udy = sy - y;
+ double length, dx, dy;
+ double scale = 1;
+ double left;
+
+ if (!(udx | udy)) /* degenerate */
+ dx = 0, dy = 0, length = 0;
+ else {
+ gs_point d;
+
+ dx = udx, dy = udy; /* scaled as fixed */
+ gs_imager_idtransform(pis, dx, dy, &d);
+ length = hypot(d.x, d.y) * (1.0 / fixed_1);
+ if (gs_imager_currentdashadapt(pis)) {
+ double reps = length / dash->pattern_length;
+
+ scale = reps / ceil(reps);
+ /* Ensure we're starting at the start of a */
+ /* repetition. (This shouldn't be necessary, */
+ /* but it is.) */
+ count = dash->pattern_size;
+ ink_on = dash->init_ink_on;
+ index = dash->init_index;
+ elt_length = dash->init_dist_left * scale;
+ }
+ }
+ left = length;
+ while (left > elt_length) { /* We are using up the line segment. */
+ double fraction = elt_length / length;
+ fixed nx = x + (fixed) (dx * fraction);
+ fixed ny = y + (fixed) (dy * fraction);
+
+ if (ink_on) {
+ if (drawing >= 0)
+ code = gx_path_add_line_notes(ppath, nx, ny,
+ notes & pseg->notes);
+ notes |= sn_not_first;
+ } else {
+ if (drawing > 0) /* done */
+ return 0;
+ code = gx_path_add_point(ppath, nx, ny);
+ notes &= ~sn_not_first;
+ drawing = 0;
+ }
+ if (code < 0)
+ return code;
+ left -= elt_length;
+ ink_on = !ink_on;
+ if (++index == count)
+ index = 0;
+ elt_length = pattern[index] * scale;
+ x = nx, y = ny;
+ }
+ elt_length -= left;
+ /* Handle the last dash of a segment. */
+ on:if (ink_on) {
+ if (drawing >= 0) {
+ code =
+ (pseg->type == s_line_close && drawing > 0 ?
+ gx_path_close_subpath_notes(ppath,
+ notes & pseg->notes) :
+ gx_path_add_line_notes(ppath, sx, sy,
+ notes & pseg->notes));
+ notes |= sn_not_first;
+ }
+ } else {
+ code = gx_path_add_point(ppath, sx, sy);
+ notes &= ~sn_not_first;
+ if (elt_length < fixed2float(fixed_epsilon) &&
+ (pseg->next == 0 || pseg->next->type == s_start)
+ ) { /*
+ * Ink is off, but we're within epsilon of the end
+ * of the dash element, and at the end of the
+ * subpath. "Stretch" a little so we get a dot.
+ */
+ if (code < 0)
+ return code;
+ elt_length = 0;
+ ink_on = true;
+ if (++index == count)
+ index = 0;
+ elt_length = pattern[index] * scale;
+ goto on;
+ }
+ if (drawing > 0) /* done */
+ return code;
+ drawing = 0;
+ }
+ if (code < 0)
+ return code;
+ x = sx, y = sy;
+ }
+ /* Check for wraparound. */
+ if (wrap && drawing <= 0) { /* We skipped some initial lines. */
+ /* Go back and do them now. */
+ drawing = 1;
+ goto top;
+ }
+ return 0;
+}
diff --git a/pstoraster/gxpflat.c b/pstoraster/gxpflat.c
new file mode 100644
index 000000000..f5c962285
--- /dev/null
+++ b/pstoraster/gxpflat.c
@@ -0,0 +1,455 @@
+/* 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$ */
+/* Path flattening algorithms */
+#include "gx.h"
+#include "gxarith.h"
+#include "gxfixed.h"
+#include "gzpath.h"
+
+/* Define whether to merge nearly collinear line segments when flattening */
+/* curves. This is very good for performance, but we feel a little */
+/* uneasy about its effects on character appearance. */
+#define MERGE_COLLINEAR_SEGMENTS 1
+
+/* ---------------- Curve flattening ---------------- */
+
+#define x1 pc->p1.x
+#define y1 pc->p1.y
+#define x2 pc->p2.x
+#define y2 pc->p2.y
+#define x3 pc->pt.x
+#define y3 pc->pt.y
+
+/*
+ * To calculate how many points to sample along a path in order to
+ * approximate it to the desired degree of flatness, we define
+ * dist((x,y)) = abs(x) + abs(y);
+ * then the number of points we need is
+ * N = 1 + sqrt(3/4 * D / flatness),
+ * where
+ * D = max(dist(p0 - 2*p1 + p2), dist(p1 - 2*p2 + p3)).
+ * Since we are going to use a power of 2 for the number of intervals,
+ * we can avoid the square root by letting
+ * N = 1 + 2^(ceiling(log2(3/4 * D / flatness) / 2)).
+ * (Reference: DEC Paris Research Laboratory report #1, May 1989.)
+ *
+ * We treat two cases specially. First, if the curve is very
+ * short, we halve the flatness, to avoid turning short shallow curves
+ * into short straight lines. Second, if the curve forms part of a
+ * character (indicated by flatness = 0), we let
+ * N = 1 + 2 * max(abs(x3-x0), abs(y3-y0)).
+ * This is probably too conservative, but it produces good results.
+ */
+int
+gx_curve_log2_samples(fixed x0, fixed y0, const curve_segment * pc,
+ fixed fixed_flat)
+{
+ fixed
+ x03 = x3 - x0,
+ y03 = y3 - y0;
+ int k;
+
+ if (x03 < 0)
+ x03 = -x03;
+ if (y03 < 0)
+ y03 = -y03;
+ if ((x03 | y03) < int2fixed(16))
+ fixed_flat >>= 1;
+ if (fixed_flat == 0) { /* Use the conservative method. */
+ fixed m = max(x03, y03);
+
+ for (k = 1; m > fixed_1;)
+ k++, m >>= 1;
+ } else {
+ const fixed
+ x12 = x1 - x2, y12 = y1 - y2, dx0 = x0 - x1 - x12, dy0 = y0 - y1 - y12,
+ dx1 = x12 - x2 + x3, dy1 = y12 - y2 + y3, adx0 = any_abs(dx0),
+ ady0 = any_abs(dy0), adx1 = any_abs(dx1), ady1 = any_abs(dy1);
+
+ fixed
+ d = max(adx0, adx1) + max(ady0, ady1);
+ /*
+ * The following statement is split up to work around a
+ * bug in the gcc 2.7.2 optimizer on H-P RISC systems.
+ */
+ uint qtmp = d - (d >> 2) /* 3/4 * D */ +fixed_flat - 1;
+ uint q = qtmp / fixed_flat;
+
+ if_debug6('2', "[2]d01=%g,%g d12=%g,%g d23=%g,%g\n",
+ fixed2float(x1 - x0), fixed2float(y1 - y0),
+ fixed2float(-x12), fixed2float(-y12),
+ fixed2float(x3 - x2), fixed2float(y3 - y2));
+ if_debug2('2', " D=%f, flat=%f,",
+ fixed2float(d), fixed2float(fixed_flat));
+ /* Now we want to set k = ceiling(log2(q) / 2). */
+ for (k = 0; q > 1;)
+ k++, q = (q + 3) >> 2;
+ if_debug1('2', " k=%d\n", k);
+ }
+ return k;
+}
+
+/*
+ * Define the maximum number of points for sampling if we want accurate
+ * rasterizing. 2^(k_sample_max*3)-1 must fit into a uint with a bit
+ * to spare; also, we must be able to compute 1/2^(3*k) by table lookup.
+ */
+#define k_sample_max min((size_of(int) * 8 - 1) / 3, 10)
+
+/*
+ * Split a curve segment into two pieces at the (parametric) midpoint.
+ * Algorithm is from "The Beta2-split: A special case of the Beta-spline
+ * Curve and Surface Representation," B. A. Barsky and A. D. DeRose, IEEE,
+ * 1985, courtesy of Crispin Goswell.
+ */
+private void
+split_curve_midpoint(fixed x0, fixed y0, const curve_segment * pc,
+ curve_segment * pc1, curve_segment * pc2)
+{ /*
+ * We have to define midpoint carefully to avoid overflow.
+ * (If it overflows, something really pathological is going
+ * on, but we could get infinite recursion that way....)
+ */
+#define midpoint(a,b)\
+ (arith_rshift_1(a) + arith_rshift_1(b) + ((a) & (b) & 1) + 1)
+ fixed x12 = midpoint(x1, x2);
+ fixed y12 = midpoint(y1, y2);
+
+ /*
+ * pc1 or pc2 may be the same as pc, so we must be a little careful
+ * about the order in which we store the results.
+ */
+ pc1->p1.x = midpoint(x0, x1);
+ pc1->p1.y = midpoint(y0, y1);
+ pc2->p2.x = midpoint(x2, x3);
+ pc2->p2.y = midpoint(y2, y3);
+ pc1->p2.x = midpoint(pc1->p1.x, x12);
+ pc1->p2.y = midpoint(pc1->p1.y, y12);
+ pc2->p1.x = midpoint(x12, pc2->p2.x);
+ pc2->p1.y = midpoint(y12, pc2->p2.y);
+ if (pc2 != pc)
+ pc2->pt.x = pc->pt.x,
+ pc2->pt.y = pc->pt.y;
+ pc1->pt.x = midpoint(pc1->p2.x, pc2->p1.x);
+ pc1->pt.y = midpoint(pc1->p2.y, pc2->p1.y);
+#undef midpoint
+}
+
+/*
+ * Flatten a segment of the path by repeated sampling.
+ * 2^k is the number of lines to produce (i.e., the number of points - 1,
+ * including the endpoints); we require k >= 1.
+ * If k or any of the coefficient values are too large,
+ * use recursive subdivision to whittle them down.
+ */
+int
+gx_flatten_sample(gx_path * ppath, int k, curve_segment * pc,
+ segment_notes notes)
+{
+ fixed x0, y0;
+
+ /* x1 ... y3 were defined above */
+ fixed cx, bx, ax, cy, by, ay;
+ fixed ptx, pty;
+ fixed x, y;
+
+ /*
+ * We can compute successive values by finite differences,
+ * using the formulas:
+ x(t) =
+ a*t^3 + b*t^2 + c*t + d =>
+ dx(t) = x(t+e)-x(t) =
+ a*(3*t^2*e + 3*t*e^2 + e^3) + b*(2*t*e + e^2) + c*e =
+ (3*a*e)*t^2 + (3*a*e^2 + 2*b*e)*t + (a*e^3 + b*e^2 + c*e) =>
+ d2x(t) = dx(t+e)-dx(t) =
+ (3*a*e)*(2*t*e + e^2) + (3*a*e^2 + 2*b*e)*e =
+ (6*a*e^2)*t + (6*a*e^3 + 2*b*e^2) =>
+ d3x(t) = d2x(t+e)-d2x(t) =
+ 6*a*e^3;
+ x(0) = d, dx(0) = (a*e^3 + b*e^2 + c*e),
+ d2x(0) = 6*a*e^3 + 2*b*e^2;
+ * In these formulas, e = 1/2^k; of course, there are separate
+ * computations for the x and y values.
+ *
+ * There is a tradeoff in doing the above computation in fixed
+ * point. If we separate out the constant term (d) and require that
+ * all the other values fit in a long, then on a 32-bit machine with
+ * 12 bits of fraction in a fixed, k = 4 implies a maximum curve
+ * size of 128 pixels; anything larger requires subdividing the
+ * curve. On the other hand, doing the computations in explicit
+ * double precision slows down the loop by a factor of 3 or so. We
+ * found to our surprise that the latter is actually faster, because
+ * the additional subdivisions cost more than the slower loop.
+ *
+ * We represent each quantity as I+R/M, where I is an "integer" and
+ * the "remainder" R lies in the range 0 <= R < M=2^(3*k). Note
+ * that R may temporarily exceed M; for this reason, we require that
+ * M have at least one free high-order bit. To reduce the number of
+ * variables, we don't actually compute M, only M-1 (rmask). */
+ uint i;
+ uint rmask; /* M-1 */
+ fixed idx, idy, id2x, id2y, id3x, id3y; /* I */
+ uint rx, ry, rdx, rdy, rd2x, rd2y, rd3x, rd3y; /* R */
+ gs_fixed_point *ppt;
+
+#define max_points 50 /* arbitrary */
+ gs_fixed_point points[max_points + 1];
+
+ top:x0 = ppath->position.x;
+ y0 = ppath->position.y;
+#ifdef DEBUG
+ if (gs_debug_c('3')) {
+ dlprintf4("[3]x0=%f y0=%f x1=%f y1=%f\n",
+ fixed2float(x0), fixed2float(y0),
+ fixed2float(x1), fixed2float(y1));
+ dlprintf5(" x2=%f y2=%f x3=%f y3=%f k=%d\n",
+ fixed2float(x2), fixed2float(y2),
+ fixed2float(x3), fixed2float(y3), k);
+ }
+#endif
+ {
+ fixed x01, x12, y01, y12;
+
+ curve_points_to_coefficients(x0, x1, x2, x3, ax, bx, cx,
+ x01, x12);
+ curve_points_to_coefficients(y0, y1, y2, y3, ay, by, cy,
+ y01, y12);
+ }
+
+ if_debug6('3', "[3]ax=%f bx=%f cx=%f\n ay=%f by=%f cy=%f\n",
+ fixed2float(ax), fixed2float(bx), fixed2float(cx),
+ fixed2float(ay), fixed2float(by), fixed2float(cy));
+#define max_fast (max_fixed / 6)
+#define min_fast (-max_fast)
+#define in_range(v) (v < max_fast && v > min_fast)
+ if (k == 0) { /* The curve is very short, or anomalous in some way. */
+ /* Just add a line and exit. */
+ return gx_path_add_line_notes(ppath, x3, y3, notes);
+ }
+ if (k <= k_sample_max &&
+ in_range(ax) && in_range(ay) &&
+ in_range(bx) && in_range(by) &&
+ in_range(cx) && in_range(cy)
+ ) {
+ x = x0, y = y0;
+ rx = ry = 0;
+ ppt = points;
+ /* Fast check for n == 3, a common special case */
+ /* for small characters. */
+ if (k == 1) {
+#define poly2(a,b,c)\
+ arith_rshift_1(arith_rshift_1(arith_rshift_1(a) + b) + c)
+ x += poly2(ax, bx, cx);
+ y += poly2(ay, by, cy);
+#undef poly2
+ if_debug2('3', "[3]dx=%f, dy=%f\n",
+ fixed2float(x - x0), fixed2float(y - y0));
+ if_debug3('3', "[3]%s x=%g, y=%g\n",
+ (((x ^ x0) | (y ^ y0)) & float2fixed(-0.5) ?
+ "add" : "skip"),
+ fixed2float(x), fixed2float(y));
+ if (((x ^ x0) | (y ^ y0)) & float2fixed(-0.5))
+ ppt->x = ptx = x,
+ ppt->y = pty = y,
+ ppt++;
+ goto last;
+ } else {
+ fixed bx2 = bx << 1, by2 = by << 1;
+ fixed ax6 = ((ax << 1) + ax) << 1, ay6 = ((ay << 1) + ay) << 1;
+
+#define adjust_rem(r, q)\
+ if ( r > rmask ) q ++, r &= rmask
+ const int k2 = k << 1;
+ const int k3 = k2 + k;
+
+ rmask = (1 << k3) - 1;
+ /* We can compute all the remainders as ints, */
+ /* because we know they don't exceed M. */
+ /* cx/y terms */
+ idx = arith_rshift(cx, k),
+ idy = arith_rshift(cy, k);
+ rdx = ((uint) cx << k2) & rmask,
+ rdy = ((uint) cy << k2) & rmask;
+ /* bx/y terms */
+ id2x = arith_rshift(bx2, k2),
+ id2y = arith_rshift(by2, k2);
+ rd2x = ((uint) bx2 << k) & rmask,
+ rd2y = ((uint) by2 << k) & rmask;
+ idx += arith_rshift_1(id2x),
+ idy += arith_rshift_1(id2y);
+ rdx += ((uint) bx << k) & rmask,
+ rdy += ((uint) by << k) & rmask;
+ adjust_rem(rdx, idx);
+ adjust_rem(rdy, idy);
+ /* ax/y terms */
+ idx += arith_rshift(ax, k3),
+ idy += arith_rshift(ay, k3);
+ rdx += (uint) ax & rmask,
+ rdy += (uint) ay & rmask;
+ adjust_rem(rdx, idx);
+ adjust_rem(rdy, idy);
+ id2x += id3x = arith_rshift(ax6, k3),
+ id2y += id3y = arith_rshift(ay6, k3);
+ rd2x += rd3x = (uint) ax6 & rmask,
+ rd2y += rd3y = (uint) ay6 & rmask;
+ adjust_rem(rd2x, id2x);
+ adjust_rem(rd2y, id2y);
+#undef adjust_rem
+ }
+ } else { /*
+ * Curve is too long. Break into two pieces and recur.
+ */
+ curve_segment cseg;
+ int code;
+
+ k--;
+ split_curve_midpoint(x0, y0, pc, &cseg, pc);
+ code = gx_flatten_sample(ppath, k, &cseg, notes);
+ if (code < 0)
+ return code;
+ notes |= sn_not_first;
+ goto top;
+ }
+ if_debug1('2', "[2]sampling k=%d\n", k);
+ ptx = x0, pty = y0;
+ for (i = (1 << k) - 1;;) {
+ int code;
+
+#ifdef DEBUG
+ if (gs_debug_c('3')) {
+ dlprintf4("[3]dx=%f+%d, dy=%f+%d\n",
+ fixed2float(idx), rdx,
+ fixed2float(idy), rdy);
+ dlprintf4(" d2x=%f+%d, d2y=%f+%d\n",
+ fixed2float(id2x), rd2x,
+ fixed2float(id2y), rd2y);
+ dlprintf4(" d3x=%f+%d, d3y=%f+%d\n",
+ fixed2float(id3x), rd3x,
+ fixed2float(id3y), rd3y);
+ }
+#endif
+#define accum(i, r, di, dr)\
+ if ( (r += dr) > rmask ) r &= rmask, i += di + 1;\
+ else i += di
+ accum(x, rx, idx, rdx);
+ accum(y, ry, idy, rdy);
+ if_debug3('3', "[3]%s x=%g, y=%g\n",
+ (((x ^ ptx) | (y ^ pty)) & float2fixed(-0.5) ?
+ "add" : "skip"),
+ fixed2float(x), fixed2float(y));
+ /*
+ * Skip very short segments -- those that lie entirely within
+ * a square half-pixel. Also merge nearly collinear
+ * segments -- those where one coordinate of all three points
+ * (the two endpoints and the midpoint) lie within the same
+ * half-pixel and both coordinates are monotonic.
+ * Note that ptx/y, the midpoint, is the same as ppt[-1].x/y;
+ * the previous point is ppt[-2].x/y.
+ */
+#define coord_near(v, ptv)\
+ (!( ((v) ^ (ptv)) & float2fixed(-0.5) ))
+#define coords_in_order(v0, v1, v2)\
+ ( (((v1) - (v0)) ^ ((v2) - (v1))) >= 0 )
+ if (coord_near(x, ptx)) { /* X coordinates are within a half-pixel. */
+ if (coord_near(y, pty))
+ goto skip; /* short segment */
+#if MERGE_COLLINEAR_SEGMENTS
+ /* Check for collinear segments. */
+ if (ppt > points + 1 && coord_near(x, ppt[-2].x) &&
+ coords_in_order(ppt[-2].x, ptx, x) &&
+ coords_in_order(ppt[-2].y, pty, y)
+ )
+ --ppt; /* remove middle point */
+#endif
+ } else if (coord_near(y, pty)) { /* Y coordinates are within a half-pixel. */
+#if MERGE_COLLINEAR_SEGMENTS
+ /* Check for collinear segments. */
+ if (ppt > points + 1 && coord_near(y, ppt[-2].y) &&
+ coords_in_order(ppt[-2].x, ptx, x) &&
+ coords_in_order(ppt[-2].y, pty, y)
+ )
+ --ppt; /* remove middle point */
+#endif
+ }
+#undef coord_near
+#undef coords_in_order
+ /* Add a line. */
+ if (ppt == &points[max_points]) {
+ if (notes & sn_not_first)
+ code = gx_path_add_lines_notes(ppath, points, max_points,
+ notes);
+ else {
+ code = gx_path_add_line_notes(ppath, points[0].x,
+ points[0].y, notes);
+ if (code < 0)
+ return code;
+ code = gx_path_add_lines_notes(ppath, points,
+ max_points - 1, notes | sn_not_first);
+ }
+ if (code < 0)
+ return code;
+ ppt = points;
+ notes |= sn_not_first;
+ }
+ ppt->x = ptx = x;
+ ppt->y = pty = y;
+ ppt++;
+ skip:if (--i == 0)
+ break; /* don't bother with last accum */
+ accum(idx, rdx, id2x, rd2x);
+ accum(id2x, rd2x, id3x, rd3x);
+ accum(idy, rdy, id2y, rd2y);
+ accum(id2y, rd2y, id3y, rd3y);
+#undef accum
+ }
+ last:if_debug2('3', "[3]last x=%g, y=%g\n",
+ fixed2float(x3), fixed2float(y3));
+ if (ppt > points) {
+ int count = ppt + 1 - points;
+ gs_fixed_point *pts = points;
+
+ if (!(notes & sn_not_first)) {
+ int code = gx_path_add_line_notes(ppath,
+ points[0].x, points[0].y,
+ notes);
+
+ if (code < 0)
+ return code;
+ ++pts, --count;
+ notes |= sn_not_first;
+ }
+ ppt->x = x3, ppt->y = y3;
+ return gx_path_add_lines_notes(ppath, pts, count, notes);
+ }
+ return gx_path_add_line_notes(ppath, x3, y3, notes);
+}
+
+#undef x1
+#undef y1
+#undef x2
+#undef y2
+#undef x3
+#undef y3
diff --git a/pstoraster/gxropc.h b/pstoraster/gxropc.h
new file mode 100644
index 000000000..48f8b2aa2
--- /dev/null
+++ b/pstoraster/gxropc.h
@@ -0,0 +1,53 @@
+/* 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$ */
+/* Internals for RasterOp compositing */
+
+#ifndef gxropc_INCLUDED
+# define gxropc_INCLUDED
+
+#include "gsropc.h"
+#include "gxcomp.h"
+
+/* Define RasterOp-compositing objects. */
+typedef struct gs_composite_rop_s {
+ gs_composite_common;
+ gs_composite_rop_params_t params;
+} gs_composite_rop_t;
+
+#define private_st_composite_rop() /* in gsropc.c */\
+ gs_private_st_ptrs1(st_composite_rop, gs_composite_rop_t,\
+ "gs_composite_rop_t", composite_rop_enum_ptrs, composite_rop_reloc_ptrs,\
+ params.texture)
+
+/*
+ * Initialize a RasterOp compositing function from parameters.
+ * We make this visible so that clients can allocate gs_composite_rop_t
+ * objects on the stack, to reduce memory manager overhead.
+ */
+void gx_init_composite_rop(P2(gs_composite_rop_t * pcte,
+ const gs_composite_rop_params_t * params));
+
+#endif /* gxropc_INCLUDED */
diff --git a/pstoraster/gxsample.c b/pstoraster/gxsample.c
new file mode 100644
index 000000000..e8f0bdd28
--- /dev/null
+++ b/pstoraster/gxsample.c
@@ -0,0 +1,211 @@
+/* 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$ */
+/* Sample unpacking procedures */
+#include "gx.h"
+#include "gxsample.h"
+
+/* ---------------- Lookup tables ---------------- */
+
+/*
+ * Define standard tables for spreading 1-bit input data.
+ * Note that these depend on the end-orientation of the CPU.
+ * We can't simply define them as byte arrays, because
+ * they might not wind up properly long- or short-aligned.
+ */
+#define map4tox(z,a,b,c,d)\
+ z, z^a, z^b, z^(a+b),\
+ z^c, z^(a+c), z^(b+c), z^(a+b+c),\
+ z^d, z^(a+d), z^(b+d), z^(a+b+d),\
+ z^(c+d), z^(a+c+d), z^(b+c+d), z^(a+b+c+d)
+#if arch_is_big_endian
+const bits32 lookup4x1to32_identity[16] =
+{map4tox(0L, 0xffL, 0xff00L, 0xff0000L, 0xff000000L)};
+const bits32 lookup4x1to32_inverted[16] =
+{map4tox(0xffffffffL, 0xffL, 0xff00L, 0xff0000L, 0xff000000L)};
+
+#else /* !arch_is_big_endian */
+const bits32 lookup4x1to32_identity[16] =
+{map4tox(0L, 0xff000000L, 0xff0000L, 0xff00L, 0xffL)};
+const bits32 lookup4x1to32_inverted[16] =
+{map4tox(0xffffffffL, 0xff000000L, 0xff0000L, 0xff00L, 0xffL)};
+
+#endif
+
+/* ---------------- Unpacking procedures ---------------- */
+
+const byte *
+sample_unpack_copy(byte * bptr, int *pdata_x, const byte * data, int data_x,
+ uint dsize, const sample_lookup_t * ignore_ptab, int spread)
+{ /* We're going to use the data right away, so no copying is needed. */
+ *pdata_x = data_x;
+ return data;
+}
+
+const byte *
+sample_unpack_1(byte * bptr, int *pdata_x, const byte * data, int data_x,
+ uint dsize, const sample_lookup_t * ptab, int spread)
+{
+ const byte *psrc = data + (data_x >> 3);
+ int left = dsize - (data_x >> 3);
+
+ if (spread == 1) {
+ bits32 *bufp = (bits32 *) bptr;
+ const bits32 *map = &ptab->lookup4x1to32[0];
+ uint b;
+
+ if (left & 1) {
+ b = psrc[0];
+ bufp[0] = map[b >> 4];
+ bufp[1] = map[b & 0xf];
+ psrc++, bufp += 2;
+ }
+ left >>= 1;
+ while (left--) {
+ b = psrc[0];
+ bufp[0] = map[b >> 4];
+ bufp[1] = map[b & 0xf];
+ b = psrc[1];
+ bufp[2] = map[b >> 4];
+ bufp[3] = map[b & 0xf];
+ psrc += 2, bufp += 4;
+ }
+ } else {
+ byte *bufp = bptr;
+ const byte *map = &ptab->lookup8[0];
+
+ while (left--) {
+ uint b = *psrc++;
+
+ *bufp = map[b >> 7];
+ bufp += spread;
+ *bufp = map[(b >> 6) & 1];
+ bufp += spread;
+ *bufp = map[(b >> 5) & 1];
+ bufp += spread;
+ *bufp = map[(b >> 4) & 1];
+ bufp += spread;
+ *bufp = map[(b >> 3) & 1];
+ bufp += spread;
+ *bufp = map[(b >> 2) & 1];
+ bufp += spread;
+ *bufp = map[(b >> 1) & 1];
+ bufp += spread;
+ *bufp = map[b & 1];
+ bufp += spread;
+ }
+ }
+ *pdata_x = data_x & 7;
+ return bptr;
+}
+
+const byte *
+sample_unpack_2(byte * bptr, int *pdata_x, const byte * data, int data_x,
+ uint dsize, const sample_lookup_t * ptab, int spread)
+{
+ const byte *psrc = data + (data_x >> 2);
+ int left = dsize - (data_x >> 2);
+
+ if (spread == 1) {
+ bits16 *bufp = (bits16 *) bptr;
+ const bits16 *map = &ptab->lookup2x2to16[0];
+
+ while (left--) {
+ uint b = *psrc++;
+
+ *bufp++ = map[b >> 4];
+ *bufp++ = map[b & 0xf];
+ }
+ } else {
+ byte *bufp = bptr;
+ const byte *map = &ptab->lookup8[0];
+
+ while (left--) {
+ unsigned b = *psrc++;
+
+ *bufp = map[b >> 6];
+ bufp += spread;
+ *bufp = map[(b >> 4) & 3];
+ bufp += spread;
+ *bufp = map[(b >> 2) & 3];
+ bufp += spread;
+ *bufp = map[b & 3];
+ bufp += spread;
+ }
+ }
+ *pdata_x = data_x & 3;
+ return bptr;
+}
+
+const byte *
+sample_unpack_4(byte * bptr, int *pdata_x, const byte * data, int data_x,
+ uint dsize, const sample_lookup_t * ptab, int spread)
+{
+ byte *bufp = bptr;
+ const byte *psrc = data + (data_x >> 1);
+ int left = dsize - (data_x >> 1);
+ const byte *map = &ptab->lookup8[0];
+
+ while (left--) {
+ uint b = *psrc++;
+
+ *bufp = map[b >> 4];
+ bufp += spread;
+ *bufp = map[b & 0xf];
+ bufp += spread;
+ }
+ *pdata_x = data_x & 1;
+ return bptr;
+}
+
+const byte *
+sample_unpack_8(byte * bptr, int *pdata_x, const byte * data, int data_x,
+ uint dsize, const sample_lookup_t * ptab, int spread)
+{
+ byte *bufp = bptr;
+ const byte *psrc = data + data_x;
+
+ *pdata_x = 0;
+ if (spread == 1) {
+ if (ptab->lookup8[0] != 0 ||
+ ptab->lookup8[255] != 255
+ ) {
+ uint left = dsize - data_x;
+ const byte *map = &ptab->lookup8[0];
+
+ while (left--)
+ *bufp++ = map[*psrc++];
+ } else { /* No copying needed, and we'll use the data right away. */
+ return psrc;
+ }
+ } else {
+ int left = dsize - data_x;
+ const byte *map = &ptab->lookup8[0];
+
+ for (; left--; psrc++, bufp += spread)
+ *bufp = map[*psrc];
+ }
+ return bptr;
+}
diff --git a/pstoraster/gxsample.h b/pstoraster/gxsample.h
new file mode 100644
index 000000000..81447d82a
--- /dev/null
+++ b/pstoraster/gxsample.h
@@ -0,0 +1,87 @@
+/* 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$ */
+/* Sample lookup and expansion */
+
+#ifndef gxsample_INCLUDED
+# define gxsample_INCLUDED
+
+/*
+ * The following union implements the expansion of sample
+ * values from N bits to 8, and a possible linear transformation.
+ */
+typedef union sample_lookup_s {
+ bits32 lookup4x1to32[16]; /* 1 bit/sample, not spreading */
+ bits16 lookup2x2to16[16]; /* 2 bits/sample, not spreading */
+ byte lookup8[256]; /* 1 bit/sample, spreading [2] */
+ /* 2 bits/sample, spreading [4] */
+ /* 4 bits/sample [16] */
+ /* 8 bits/sample [256] */
+} sample_lookup_t;
+
+/*
+ * Define identity and inverted expansion lookups for 1-bit input values.
+ * These can be cast to a const sample_lookup_t.
+ */
+extern const bits32 lookup4x1to32_identity[16];
+
+#define sample_lookup_1_identity\
+ ((const sample_lookup_t *)lookup4x1to32_identity)
+extern const bits32 lookup4x1to32_inverted[16];
+
+#define sample_lookup_1_inverted\
+ ((const sample_lookup_t *)lookup4x1to32_inverted)
+
+/*
+ * Define procedures to unpack and shuffle image data samples. The Unix C
+ * compiler can't handle typedefs for procedure (as opposed to
+ * pointer-to-procedure) types, so we have to do it with macros instead.
+ *
+ * The original data start at sample data_x relative to data.
+ * bptr points to the buffer normally used to deliver the unpacked data.
+ * The unpacked data are at sample *pdata_x relative to the return value.
+ *
+ * Note that this procedure may return either a pointer to the buffer, or
+ * a pointer to the original data.
+ */
+#define sample_unpack_proc(proc)\
+ const byte *proc(P7(byte *bptr, int *pdata_x, const byte *data, int data_x,\
+ uint dsize, const sample_lookup_t *ptab, int spread))
+typedef sample_unpack_proc((*sample_unpack_proc_t));
+
+/*
+ * Declare the 1-for-1 unpacking procedure.
+ */
+sample_unpack_proc(sample_unpack_copy);
+/*
+ * Declare unpacking procedures for 1, 2, 4, and 8 bits per pixel,
+ * with optional spreading of the result.
+ */
+sample_unpack_proc(sample_unpack_1);
+sample_unpack_proc(sample_unpack_2);
+sample_unpack_proc(sample_unpack_4);
+sample_unpack_proc(sample_unpack_8);
+
+#endif /* gxsample_INCLUDED */
diff --git a/pstoraster/gxshade.c b/pstoraster/gxshade.c
new file mode 100644
index 000000000..f1891dd90
--- /dev/null
+++ b/pstoraster/gxshade.c
@@ -0,0 +1,348 @@
+/* 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$ */
+/* Shading rendering support */
+#include "math_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsrect.h"
+#include "gxcspace.h"
+#include "gscie.h" /* requires gscspace.h */
+#include "gxdevcli.h"
+#include "gxistate.h"
+#include "gxdht.h" /* for computing # of different colors */
+#include "gxpaint.h"
+#include "gxshade.h"
+
+/* ================ Packed coordinate streams ================ */
+
+/* Forward references */
+private int cs_next_packed_value(P3(shade_coord_stream_t *, int, uint *));
+private int cs_next_array_value(P3(shade_coord_stream_t *, int, uint *));
+private int cs_next_packed_decoded(P4(shade_coord_stream_t *, int,
+ const float[2], float *));
+private int cs_next_array_decoded(P4(shade_coord_stream_t *, int,
+ const float[2], float *));
+
+/* Initialize a packed value stream. */
+void
+shade_next_init(shade_coord_stream_t * cs,
+ const gs_shading_mesh_params_t * params,
+ const gs_imager_state * pis)
+{
+ cs->params = params;
+ cs->pctm = &pis->ctm;
+ if (data_source_is_stream(params->DataSource)) {
+ cs->s = params->DataSource.data.strm;
+ } else {
+ sread_string(&cs->ds, params->DataSource.data.str.data,
+ params->DataSource.data.str.size);
+ cs->s = &cs->ds;
+ }
+ if (data_source_is_array(params->DataSource)) {
+ cs->get_value = cs_next_array_value;
+ cs->get_decoded = cs_next_array_decoded;
+ } else {
+ cs->get_value = cs_next_packed_value;
+ cs->get_decoded = cs_next_packed_decoded;
+ }
+ cs->left = 0;
+}
+
+/* Get the next (integer) value from a packed value stream. */
+/* 1 <= num_bits <= sizeof(uint) * 8. */
+private int
+cs_next_packed_value(shade_coord_stream_t * cs, int num_bits, uint * pvalue)
+{
+ uint bits = cs->bits;
+ int left = cs->left;
+
+ if (left >= num_bits) {
+ /* We can satisfy this request with the current buffered bits. */
+ cs->left = left -= num_bits;
+ *pvalue = (bits >> left) & ((1 << num_bits) - 1);
+ } else {
+ /* We need more bits. */
+ int needed = num_bits - left;
+ uint value = bits & ((1 << left) - 1); /* all the remaining bits */
+
+ for (; needed >= 8; needed -= 8) {
+ int b = sgetc(cs->s);
+
+ if (b < 0)
+ return_error(gs_error_rangecheck);
+ value = (value << 8) + b;
+ }
+ if (needed == 0) {
+ cs->left = 0;
+ *pvalue = value;
+ } else {
+ int b = sgetc(cs->s);
+
+ if (b < 0)
+ return_error(gs_error_rangecheck);
+ cs->bits = b;
+ cs->left = left = 8 - needed;
+ *pvalue = (value << needed) + (b >> left);
+ }
+ }
+ return 0;
+}
+
+/* Get the next (integer) value from an unpacked array. */
+private int
+cs_next_array_value(shade_coord_stream_t * cs, int num_bits, uint * pvalue)
+{
+ float value;
+ uint read;
+
+ if (sgets(cs->s, (byte *)&value, sizeof(float), &read) < 0 ||
+ read != sizeof(float) || value < 0 || value >= (1 << num_bits) ||
+ value != (int)value
+ )
+ return_error(gs_error_rangecheck);
+ *pvalue = (uint) value;
+ return 0;
+}
+
+/* Get the next decoded floating point value. */
+private int
+cs_next_packed_decoded(shade_coord_stream_t * cs, int num_bits,
+ const float decode[2], float *pvalue)
+{
+ uint value;
+ int code = cs->get_value(cs, num_bits, &value);
+ double max_value = (double)(uint) ((1 << num_bits) - 1);
+
+ if (code < 0)
+ return code;
+ *pvalue =
+ (decode == 0 ? value / max_value :
+ decode[0] + value * (decode[1] - decode[0]) / max_value);
+ return 0;
+}
+
+/* Get the next floating point value from an array, without decoding. */
+private int
+cs_next_array_decoded(shade_coord_stream_t * cs, int num_bits,
+ const float decode[2], float *pvalue)
+{
+ float value;
+ uint read;
+
+ if (sgets(cs->s, (byte *)&value, sizeof(float), &read) < 0 ||
+ read != sizeof(float)
+ )
+ return_error(gs_error_rangecheck);
+ *pvalue = value;
+ return 0;
+}
+
+/* Get the next flag value. */
+/* Note that this always starts a new data byte. */
+int
+shade_next_flag(shade_coord_stream_t * cs, int BitsPerFlag)
+{
+ uint flag;
+ int code;
+
+ cs->left = 0; /* start a new byte if packed */
+ code = cs->get_value(cs, BitsPerFlag, &flag);
+ return (code < 0 ? code : flag);
+}
+
+/* Get one or more coordinate pairs. */
+int
+shade_next_coords(shade_coord_stream_t * cs, gs_fixed_point * ppt,
+ int num_points)
+{
+ int num_bits = cs->params->BitsPerCoordinate;
+ const float *decode = cs->params->Decode;
+ int code = 0;
+ int i;
+
+ for (i = 0; i < num_points; ++i) {
+ float x, y;
+
+ if ((code = cs->get_decoded(cs, num_bits, decode, &x)) < 0 ||
+ (code = cs->get_decoded(cs, num_bits, decode, &y)) < 0 ||
+ (code = gs_point_transform2fixed(cs->pctm, x, y, &ppt[i])) < 0
+ )
+ break;
+ }
+ return code;
+}
+
+/* Get a color. Currently all this does is look up Indexed colors. */
+int
+shade_next_color(shade_coord_stream_t * cs, float *pc)
+{
+ const float *decode = cs->params->Decode + 4; /* skip coord decode */
+ const gs_color_space *pcs = cs->params->ColorSpace;
+ gs_color_space_index index = gs_color_space_get_index(pcs);
+ int num_bits = cs->params->BitsPerComponent;
+
+ if (index == gs_color_space_index_Indexed) {
+ uint i;
+ int code = cs->get_value(cs, num_bits, &i);
+
+ if (code < 0)
+ return code;
+ /****** DO INDEXED LOOKUP TO pc[] ******/
+ } else {
+ int i, code;
+ int ncomp = gs_color_space_num_components(pcs);
+
+ for (i = 0; i < ncomp; ++i)
+ if ((code = cs->get_decoded(cs, num_bits, decode + i * 2, &pc[i])) < 0)
+ return code;
+ }
+ return 0;
+}
+
+/* Get the next vertex for a mesh element. */
+int
+shade_next_vertex(shade_coord_stream_t * cs, mesh_vertex_t * vertex)
+{
+ int code = shade_next_coords(cs, &vertex->p, 1);
+
+ if (code >= 0)
+ code = shade_next_color(cs, vertex->cc);
+ return code;
+}
+
+/* ================ Shading rendering ================ */
+
+/* Initialize the common parts of the recursion state. */
+void
+shade_init_fill_state(shading_fill_state_t * pfs, const gs_shading_t * psh,
+ gx_device * dev, gs_imager_state * pis)
+{
+ const gs_color_space *pcs = psh->params.ColorSpace;
+ float max_error = pis->smoothness;
+ /*
+ * There's no point in trying to achieve smoothness beyond what
+ * the device can implement, i.e., the number of representable
+ * colors times the number of halftone levels.
+ */
+ long num_colors =
+ max(dev->color_info.max_gray, dev->color_info.max_color) + 1;
+ const gs_range *ranges = 0;
+ int ci;
+
+ pfs->dev = dev;
+ pfs->pis = pis;
+ pfs->num_components = gs_color_space_num_components(pcs);
+top:
+ switch ( gs_color_space_get_index(pcs) )
+ {
+ case gs_color_space_index_Indexed:
+ pcs = gs_cspace_base_space(pcs);
+ goto top;
+ case gs_color_space_index_CIEDEFG:
+ ranges = pcs->params.defg->RangeDEFG.ranges;
+ break;
+ case gs_color_space_index_CIEDEF:
+ ranges = pcs->params.def->RangeDEF.ranges;
+ break;
+ case gs_color_space_index_CIEABC:
+ ranges = pcs->params.abc->RangeABC.ranges;
+ break;
+ case gs_color_space_index_CIEA:
+ ranges = &pcs->params.a->RangeA;
+ break;
+ default:
+ break;
+ }
+ if (num_colors <= 32) {
+ /****** WRONG FOR MULTI-PLANE HALFTONES ******/
+ num_colors *= pis->dev_ht->order.num_levels;
+ }
+ if (max_error < 1.0 / num_colors)
+ max_error = 1.0 / num_colors;
+ for (ci = 0; ci < pfs->num_components; ++ci)
+ pfs->cc_max_error[ci] =
+ (ranges == 0 ? max_error :
+ max_error * (ranges[ci].rmax - ranges[ci].rmin));
+}
+
+/* Transform a bounding box into device space. */
+int
+shade_bbox_transform2fixed(const gs_rect * rect, const gs_imager_state * pis,
+ gs_fixed_rect * rfixed)
+{
+ gs_rect dev_rect;
+ int code = gs_bbox_transform(rect, &ctm_only(pis), &dev_rect);
+
+ if (code >= 0) {
+ rfixed->p.x = float2fixed(dev_rect.p.x);
+ rfixed->p.y = float2fixed(dev_rect.p.y);
+ rfixed->q.x = float2fixed(dev_rect.q.x);
+ rfixed->q.y = float2fixed(dev_rect.q.y);
+ }
+ return code;
+}
+
+/* Check whether 4 colors fall within the smoothness criterion. */
+bool
+shade_colors4_converge(const gs_client_color cc[4],
+ const shading_fill_state_t * pfs)
+{
+ int ci;
+
+ for (ci = 0; ci < pfs->num_components; ++ci) {
+ float
+ c0 = cc[0].paint.values[ci], c1 = cc[1].paint.values[ci],
+ c2 = cc[2].paint.values[ci], c3 = cc[3].paint.values[ci];
+ float min01, max01, min23, max23;
+
+ if (c0 < c1)
+ min01 = c0, max01 = c1;
+ else
+ min01 = c1, max01 = c0;
+ if (c2 < c3)
+ min23 = c2, max23 = c3;
+ else
+ min23 = c3, max23 = c2;
+ if (max(max01, max23) - min(min01, min23) > pfs->cc_max_error[ci])
+ return false;
+ }
+ return true;
+}
+
+/* Fill one piece of a shading. */
+int
+shade_fill_path(const shading_fill_state_t * pfs, gx_path * ppath,
+ gx_device_color * pdevc)
+{
+ gx_fill_params params;
+
+ params.rule = -1; /* irrelevant */
+ params.adjust = pfs->pis->fill_adjust;
+ params.flatness = 0; /* irrelevant */
+ params.fill_zero_width = false;
+ return (*dev_proc(pfs->dev, fill_path)) (pfs->dev, pfs->pis, ppath,
+ &params, pdevc, NULL);
+}
diff --git a/pstoraster/gxshade.h b/pstoraster/gxshade.h
new file mode 100644
index 000000000..20ebb15d3
--- /dev/null
+++ b/pstoraster/gxshade.h
@@ -0,0 +1,247 @@
+/* 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$ */
+/* Internal definitions for shading rendering */
+
+#ifndef gxshade_INCLUDED
+# define gxshade_INCLUDED
+
+#include "gsshade.h"
+#include "gxfixed.h" /* for gxmatrix.h */
+#include "gxmatrix.h" /* for gs_matrix_fixed */
+#include "stream.h"
+
+/*
+ All shadings are defined with respect to some parameter that varies
+ continuously over some range; the shading defines a mapping from the
+ parameter values to colors and user space coordinates. Here are the
+ mappings for the 7 currently defined shading types:
+
+ Type Param space Param => color Param => User space
+ ---- ----------- -------------- -------------------
+ 1 2-D Domain Function Matrix
+ 2 1-D Domain Function + Extend perp. to Coords
+ 3 1-D Domain Function + Extend circles per Coords
+ 4,5 triangle x Gouraud interp. on Gouraud interp. on
+ 2-D in tri. Decode => corner triangle corners
+ values => Function
+ 6 patch x (u,v) Decode => bilinear Sc + Sd - Sb on each patch
+ in patch interp. on corner
+ values => Function
+ 7 see 6 see 6 Sum(i) Sum(j) Pij*Bi(u)*Bj(v)
+
+ To be able to render a portion of a shading usefully, we must be able to
+ do two things:
+
+ - Determine what range of parameter values is sufficient to cover
+ the region being filled;
+
+ - Evaluate the color at enough points to fill the region (in
+ device space).
+
+ Note that the latter may be implemented by a mix of evaluation and
+ interpolation, especially for types 3, 6, and 7 where an exact mapping
+ may be prohibitively expensive.
+
+ Except for type 3, where circles turn into ellipses, the CTM can get
+ folded into the parameter => user space mapping, since in all other
+ cases, the mapping space is closed under linear transformations of
+ the output.
+ */
+
+/* Define types and rendering procedures for the individual shadings. */
+typedef struct gs_shading_Fb_s {
+ gs_shading_head_t head;
+ gs_shading_Fb_params_t params;
+} gs_shading_Fb_t;
+shading_fill_rectangle_proc(gs_shading_Fb_fill_rectangle);
+
+typedef struct gs_shading_A_s {
+ gs_shading_head_t head;
+ gs_shading_A_params_t params;
+} gs_shading_A_t;
+shading_fill_rectangle_proc(gs_shading_A_fill_rectangle);
+
+typedef struct gs_shading_R_s {
+ gs_shading_head_t head;
+ gs_shading_R_params_t params;
+} gs_shading_R_t;
+shading_fill_rectangle_proc(gs_shading_R_fill_rectangle);
+
+typedef struct gs_shading_FfGt_s {
+ gs_shading_head_t head;
+ gs_shading_FfGt_params_t params;
+} gs_shading_FfGt_t;
+shading_fill_rectangle_proc(gs_shading_FfGt_fill_rectangle);
+
+typedef struct gs_shading_LfGt_s {
+ gs_shading_head_t head;
+ gs_shading_LfGt_params_t params;
+} gs_shading_LfGt_t;
+shading_fill_rectangle_proc(gs_shading_LfGt_fill_rectangle);
+
+typedef struct gs_shading_Cp_s {
+ gs_shading_head_t head;
+ gs_shading_Cp_params_t params;
+} gs_shading_Cp_t;
+shading_fill_rectangle_proc(gs_shading_Cp_fill_rectangle);
+
+typedef struct gs_shading_Tpp_s {
+ gs_shading_head_t head;
+ gs_shading_Tpp_params_t params;
+} gs_shading_Tpp_t;
+shading_fill_rectangle_proc(gs_shading_Tpp_fill_rectangle);
+
+/* We should probably get this from somewhere else.... */
+#define max_color_components 4
+
+/* Define a stream for decoding packed coordinate values. */
+typedef struct shade_coord_stream_s shade_coord_stream_t;
+struct shade_coord_stream_s {
+ stream ds; /* stream if DataSource isn't one already -- */
+ /* first for GC-ability (maybe unneeded?) */
+ stream *s; /* DataSource or &ds */
+ uint bits; /* shifted bits of current byte */
+ int left; /* # of bits left in bits */
+ const gs_shading_mesh_params_t *params;
+ const gs_matrix_fixed *pctm;
+ int (*get_value)(P3(shade_coord_stream_t *cs, int num_bits, uint *pvalue));
+ int (*get_decoded)(P4(shade_coord_stream_t *cs, int num_bits,
+ const float decode[2], float *pvalue));
+};
+
+/* Define one vertex of a mesh. */
+typedef struct mesh_vertex_s {
+ gs_fixed_point p;
+ float cc[max_color_components];
+} mesh_vertex_t;
+
+/* Initialize a packed value stream. */
+void shade_next_init(P3(shade_coord_stream_t * cs,
+ const gs_shading_mesh_params_t * params,
+ const gs_imager_state * pis));
+
+/* Get the next flag value. */
+int shade_next_flag(P2(shade_coord_stream_t * cs, int BitsPerFlag));
+
+/* Get one or more coordinate pairs. */
+int shade_next_coords(P3(shade_coord_stream_t * cs, gs_fixed_point * ppt,
+ int num_points));
+
+/* Get a color. Currently all this does is look up Indexed colors. */
+int shade_next_color(P2(shade_coord_stream_t * cs, float *pc));
+
+/* Get the next vertex for a mesh element. */
+int shade_next_vertex(P2(shade_coord_stream_t * cs, mesh_vertex_t * vertex));
+
+/*
+ Currently, all shading fill procedures follow the same algorithm:
+
+ - Conservatively inverse-transform the rectangle being filled to a linear
+ or rectangular range of values in the parameter space.
+
+ - Compute the color values at the extrema of the range.
+
+ - If possible, compute the parameter range corresponding to a single
+ device pixel.
+
+ - Recursively do the following, passing the parameter range and extremal
+ color values as the recursion arguments:
+
+ - If the color values are equal to within the tolerance given by the
+ smoothness in the graphics state, or if the range of parameters maps
+ to a single device pixel, fill the range with the (0) or (0,0) color.
+
+ - Otherwise, subdivide and recurse. If the parameter range is 2-D,
+ subdivide the axis with the largest color difference.
+
+ For shadings based on a function, if the function is not monotonic, the
+ smoothness test must only be applied when the parameter range extrema are
+ all interpolated from the same entries in the Function. (We don't
+ currently do this.)
+
+ */
+
+/* Define the common structure for recursive subdivision. */
+#define shading_fill_state_common\
+ gx_device *dev;\
+ gs_imager_state *pis;\
+ int num_components; /* # of color components */\
+ float cc_max_error[max_color_components]
+typedef struct shading_fill_state_s {
+ shading_fill_state_common;
+} shading_fill_state_t;
+
+/* Initialize the common parts of the recursion state. */
+void shade_init_fill_state(P4(shading_fill_state_t * pfs,
+ const gs_shading_t * psh, gx_device * dev,
+ gs_imager_state * pis));
+
+/* Transform a bounding box into device space. */
+int shade_bbox_transform2fixed(P3(const gs_rect * rect,
+ const gs_imager_state * pis,
+ gs_fixed_rect * rfixed));
+
+/* Check whether 4 colors fall within the smoothness criterion. */
+bool shade_colors4_converge(P2(const gs_client_color cc[4],
+ const shading_fill_state_t * pfs));
+
+/* Fill one piece of a shading. */
+#ifndef gx_device_color_DEFINED
+# define gx_device_color_DEFINED
+typedef struct gx_device_color_s gx_device_color;
+#endif
+int shade_fill_path(P3(const shading_fill_state_t * pfs, gx_path * ppath,
+ gx_device_color * pdevc));
+
+#endif /* gxshade_INCLUDED */
+
+#if 0 /*************************************************************** */
+
+/*
+ * Here is a sketch of what will be needed to generalize Patterns for
+ * (the) new PatternType(s).
+ */
+typedef struct gs_pattern_instance_s {
+ rc_header rc; /* ?? */
+ const gs_pattern_type_t *type;
+ gs_uid XUID; /* ?? */
+ gs_state *saved; /* ?? */
+ void *data;
+} gs_pattern_instance_t;
+typedef struct gs_pattern1_instance_data_s {
+ ...
+} gs_pattern1_instance_data_t;
+
+#define gs_pattern2_instance_data_common\
+ const gs_shading_t *shading;\
+ gx_device_color *background;\
+ const gs_color_space *color_space;\
+ gs_matrix param_to_device_matrix
+typedef struct gs_pattern2_instance_data_common_s {
+ gs_pattern2_instance_data_common;
+} gs_pattern2_instance_data_common_t;
+
+#endif /*************************************************************** */
diff --git a/pstoraster/gxshade1.c b/pstoraster/gxshade1.c
new file mode 100644
index 000000000..9fb9f8fc7
--- /dev/null
+++ b/pstoraster/gxshade1.c
@@ -0,0 +1,527 @@
+/* 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$ */
+/* Rendering for non-mesh shadings */
+#include "math_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsmatrix.h" /* for gscoord.h */
+#include "gscoord.h"
+#include "gspath.h"
+#include "gxcspace.h"
+#include "gxdcolor.h"
+#include "gxfarith.h"
+#include "gxfixed.h"
+#include "gxistate.h"
+#include "gxpath.h"
+#include "gxshade.h"
+
+/* ================ Utilities ================ */
+
+/* Check whether 2 colors fall within the smoothness criterion. */
+private bool
+shade_colors2_converge(const gs_client_color cc[2],
+ const shading_fill_state_t * pfs)
+{
+ int ci;
+
+ for (ci = pfs->num_components - 1; ci >= 0; --ci)
+ if (fabs(cc[1].paint.values[ci] - cc[0].paint.values[ci]) >
+ pfs->cc_max_error[ci]
+ )
+ return false;
+ return true;
+}
+
+/* Fill a user space rectangle that is also a device space rectangle. */
+private int
+shade_fill_device_rectangle(const shading_fill_state_t * pfs,
+ const gs_fixed_point * p0,
+ const gs_fixed_point * p1,
+ gx_device_color * pdevc)
+{
+ gs_imager_state *pis = pfs->pis;
+ fixed xmin, ymin, xmax, ymax;
+ int x, y;
+
+ if (p0->x < p1->x)
+ xmin = p0->x, xmax = p1->x;
+ else
+ xmin = p1->x, xmax = p0->x;
+ if (p0->y < p1->y)
+ ymin = p0->y, ymax = p1->y;
+ else
+ ymin = p1->y, ymax = p0->y;
+ /****** NOT QUITE RIGHT FOR PIXROUND ******/
+ xmin -= pis->fill_adjust.x;
+ xmax += pis->fill_adjust.x;
+ ymin -= pis->fill_adjust.y;
+ ymax += pis->fill_adjust.y;
+ x = fixed2int_var(xmin);
+ y = fixed2int_var(ymin);
+ return
+ gx_fill_rectangle_device_rop(x, y,
+ fixed2int_var(xmax) - x,
+ fixed2int_var(ymax) - y,
+ pdevc, pfs->dev, pis->log_op);
+}
+
+/* ================ Specific shadings ================ */
+
+/* ---------------- Function-based shading ---------------- */
+
+typedef struct Fb_fill_state_s {
+ shading_fill_state_common;
+ const gs_shading_Fb_t *psh;
+ gs_matrix_fixed ptm; /* parameter space -> device space */
+ bool orthogonal; /* true iff ptm is xxyy or xyyx */
+} Fb_fill_state_t;
+
+private int
+Fb_fill_region(const Fb_fill_state_t * pfs, gs_client_color cc[4],
+ floatp x0, floatp y0, floatp x1, floatp y1)
+{
+ const gs_shading_Fb_t * const psh = pfs->psh;
+ gs_imager_state *pis = pfs->pis;
+
+top:
+ if (!shade_colors4_converge(cc, (const shading_fill_state_t *)pfs)) {
+ /*
+ * The colors don't converge. Does the region color more than
+ * a single pixel?
+ */
+ gs_rect region;
+
+ region.p.x = x0, region.p.y = y0;
+ region.q.x = x1, region.q.y = y1;
+ gs_bbox_transform(&region, (const gs_matrix *)&pfs->ptm, &region);
+ if (region.q.x - region.p.x > 1 || region.q.y - region.p.y > 1)
+ goto recur;
+ {
+ /*
+ * More precisely, does the bounding box of the region,
+ * taking fill adjustment into account, span more than 1
+ * pixel center in either X or Y?
+ */
+ fixed ax = pis->fill_adjust.x;
+ int nx =
+ fixed2int_pixround(float2fixed(region.q.x) + ax) -
+ fixed2int_pixround(float2fixed(region.p.x) - ax);
+ fixed ay = pis->fill_adjust.y;
+ int ny =
+ fixed2int_pixround(float2fixed(region.q.y) + ay) -
+ fixed2int_pixround(float2fixed(region.p.y) - ay);
+
+ if ((nx > 1 && ny != 0) || (ny > 1 && nx != 0))
+ goto recur;
+ }
+ /* We could do the 1-pixel case a lot faster! */
+ }
+ /* Fill the region with the color. */
+ {
+ gx_device_color dev_color;
+ const gs_color_space *pcs = psh->params.ColorSpace;
+ gs_fixed_point pts[4];
+ int code;
+
+ if_debug0('|', "[|]... filling region\n");
+ (*pcs->type->restrict_color)(&cc[0], pcs);
+ (*pcs->type->remap_color)(&cc[0], pcs, &dev_color, pis,
+ pfs->dev, gs_color_select_texture);
+ gs_point_transform2fixed(&pfs->ptm, x0, y0, &pts[0]);
+ gs_point_transform2fixed(&pfs->ptm, x1, y1, &pts[2]);
+ if (pfs->orthogonal) {
+ code =
+ shade_fill_device_rectangle((const shading_fill_state_t *)pfs,
+ &pts[0], &pts[2], &dev_color);
+ } else {
+ gx_path *ppath = gx_path_alloc(pis->memory, "Fb_fill");
+
+ gs_point_transform2fixed(&pfs->ptm, x1, y0, &pts[1]);
+ gs_point_transform2fixed(&pfs->ptm, x0, y1, &pts[3]);
+ gx_path_add_point(ppath, pts[0].x, pts[0].y);
+ gx_path_add_lines(ppath, pts + 1, 3);
+ code = shade_fill_path((const shading_fill_state_t *)pfs,
+ ppath, &dev_color);
+ gx_path_free(ppath, "Fb_fill");
+ }
+ return code;
+ }
+
+ /*
+ * No luck. Subdivide the region and recur.
+ *
+ * We should subdivide on the axis that has the largest color
+ * discrepancy, but for now we subdivide on the axis with the
+ * largest coordinate difference.
+ */
+recur:
+ {
+ gs_client_color mid[2];
+ gs_client_color rcc[4];
+ gs_function_t *pfn = psh->params.Function;
+ float v[2];
+ int code;
+
+ if (y1 - y0 > x1 - x0) {
+ /* Subdivide in Y. */
+ float ym = (y0 + y1) * 0.5;
+
+ if_debug1('|', "[|]dividing at y=%g\n", ym);
+ v[1] = ym;
+ v[0] = x0;
+ code = gs_function_evaluate(pfn, v, mid[0].paint.values);
+ if (code < 0)
+ return code;
+ v[0] = x1;
+ code = gs_function_evaluate(pfn, v, mid[1].paint.values);
+ if (code < 0)
+ return code;
+ rcc[0].paint = cc[0].paint;
+ rcc[1].paint = cc[1].paint;
+ rcc[2].paint = mid[0].paint;
+ rcc[3].paint = mid[1].paint;
+ code = Fb_fill_region(pfs, rcc, x0, y0, x1, ym);
+ cc[0].paint = mid[0].paint;
+ cc[1].paint = mid[1].paint;
+ y0 = ym;
+ } else {
+ /* Subdivide in X. */
+ float xm = (x0 + x1) * 0.5;
+
+ if_debug1('|', "[|]dividing at x=%g\n", xm);
+ v[0] = xm;
+ v[1] = y0;
+ code = gs_function_evaluate(pfn, v, mid[0].paint.values);
+ if (code < 0)
+ return code;
+ v[1] = y1;
+ code = gs_function_evaluate(pfn, v, mid[1].paint.values);
+ if (code < 0)
+ return code;
+ rcc[0].paint = cc[0].paint;
+ rcc[1].paint = mid[0].paint;
+ rcc[2].paint = cc[2].paint;
+ rcc[3].paint = mid[1].paint;
+ code = Fb_fill_region(pfs, rcc, x0, y0, xm, y1);
+ cc[0].paint = mid[0].paint;
+ cc[2].paint = mid[1].paint;
+ x0 = xm;
+ }
+ if (code < 0)
+ return code;
+ }
+ goto top;
+}
+
+int
+gs_shading_Fb_fill_rectangle(const gs_shading_t * psh0, const gs_rect * rect,
+ gx_device * dev, gs_imager_state * pis)
+{
+ const gs_shading_Fb_t * const psh = (const gs_shading_Fb_t *)psh0;
+ gs_matrix save_ctm;
+ int xi, yi, code;
+ float x[2], y[2];
+ Fb_fill_state_t state;
+ gs_client_color cc[4];
+
+ shade_init_fill_state((shading_fill_state_t *) & state, psh0, dev, pis);
+ state.psh = psh;
+ /****** HACK FOR FIXED-POINT MATRIX MULTIPLY ******/
+ gs_currentmatrix((gs_state *) pis, &save_ctm);
+ gs_concat((gs_state *) pis, &psh->params.Matrix);
+ state.ptm = pis->ctm;
+ gs_setmatrix((gs_state *) pis, &save_ctm);
+ state.orthogonal = is_xxyy(&state.ptm) || is_xyyx(&state.ptm);
+ /* Compute the parameter X and Y ranges. */
+ {
+ gs_rect pbox;
+
+ gs_bbox_transform_inverse(rect, &psh->params.Matrix, &pbox);
+ x[0] = max(pbox.p.x, psh->params.Domain[0]);
+ x[1] = min(pbox.q.x, psh->params.Domain[1]);
+ y[0] = max(pbox.p.y, psh->params.Domain[2]);
+ y[1] = min(pbox.q.y, psh->params.Domain[3]);
+ }
+ for (xi = 0; xi < 2; ++xi)
+ for (yi = 0; yi < 2; ++yi) {
+ float v[2];
+
+ v[0] = x[xi], v[1] = y[yi];
+ gs_function_evaluate(psh->params.Function, v,
+ cc[yi * 2 + xi].paint.values);
+ }
+ code = Fb_fill_region(&state, cc, x[0], y[0], x[1], y[1]);
+ return code;
+}
+
+/* ---------------- Axial shading ---------------- */
+
+typedef struct A_fill_state_s {
+ shading_fill_state_common;
+ const gs_shading_A_t *psh;
+ gs_rect rect;
+ gs_point delta;
+ double length, dd;
+} A_fill_state_t;
+
+/* Note t0 and t1 vary over [0..1], not the Domain. */
+private int
+A_fill_region(const A_fill_state_t * pfs, gs_client_color cc[2],
+ floatp t0, floatp t1)
+{
+ const gs_shading_A_t * const psh = pfs->psh;
+
+top:
+ if (!shade_colors2_converge(cc, (const shading_fill_state_t *)pfs)) {
+ /*
+ * The colors don't converge. Is the stripe less than 1 pixel wide?
+ */
+ if (pfs->length * (t1 - t0) > 1)
+ goto recur;
+ }
+ /* Fill the region with the color. */
+ {
+ gx_device_color dev_color;
+ const gs_color_space *pcs = psh->params.ColorSpace;
+ gs_imager_state *pis = pfs->pis;
+ double
+ x0 = psh->params.Coords[0] + pfs->delta.x * t0,
+ y0 = psh->params.Coords[1] + pfs->delta.y * t0;
+ double
+ x1 = psh->params.Coords[0] + pfs->delta.x * t1,
+ y1 = psh->params.Coords[1] + pfs->delta.y * t1;
+ gs_fixed_point pts[4];
+ int code;
+
+ (*pcs->type->restrict_color)(&cc[0], pcs);
+ (*pcs->type->remap_color)(&cc[0], pcs, &dev_color, pis,
+ pfs->dev, gs_color_select_texture);
+ if (x0 == x1) {
+ /* Stripe is horizontal. */
+ x0 = pfs->rect.p.x;
+ x1 = pfs->rect.q.x;
+ } else if (y0 == y1) {
+ /* Stripe is vertical. */
+ y0 = pfs->rect.p.y;
+ y1 = pfs->rect.q.y;
+ } else {
+ /*
+ * Stripe is neither horizontal nor vertical.
+ * Extend it to the edges of the rectangle.
+ */
+ gx_path *ppath = gx_path_alloc(pis->memory, "A_fill");
+ double dist = max(pfs->rect.q.x - pfs->rect.p.x,
+ pfs->rect.q.y - pfs->rect.p.y);
+ double denom = hypot(pfs->delta.x, pfs->delta.y);
+ double dx = dist * pfs->delta.y / denom,
+ dy = -dist * pfs->delta.x / denom;
+
+ if_debug6('|', "[|]p0=(%g,%g), p1=(%g,%g), dxy=(%g,%g)\n",
+ x0, y0, x1, y1, dx, dy);
+ gs_point_transform2fixed(&pis->ctm, x0 - dx, y0 - dy, &pts[0]);
+ gs_point_transform2fixed(&pis->ctm, x0 + dx, y0 + dy, &pts[1]);
+ gs_point_transform2fixed(&pis->ctm, x1 + dx, y1 + dy, &pts[2]);
+ gs_point_transform2fixed(&pis->ctm, x1 - dx, y1 - dy, &pts[3]);
+ gx_path_add_point(ppath, pts[0].x, pts[0].y);
+ gx_path_add_lines(ppath, pts + 1, 3);
+ code = shade_fill_path((const shading_fill_state_t *)pfs,
+ ppath, &dev_color);
+ gx_path_free(ppath, "A_fill");
+ return code;
+ }
+ /* Stripe is horizontal or vertical. */
+ gs_point_transform2fixed(&pis->ctm, x0, y0, &pts[0]);
+ gs_point_transform2fixed(&pis->ctm, x1, y1, &pts[1]);
+ return
+ shade_fill_device_rectangle((const shading_fill_state_t *)pfs,
+ &pts[0], &pts[1], &dev_color);
+ }
+
+ /*
+ * No luck. Subdivide the interval and recur.
+ */
+recur:
+ {
+ gs_client_color ccm, rcc[2];
+ gs_function_t *pfn = psh->params.Function;
+ float tm = (t0 + t1) * 0.5;
+ float dm = tm * pfs->dd + psh->params.Domain[0];
+
+ gs_function_evaluate(pfn, &dm, ccm.paint.values);
+ rcc[0].paint = cc[0].paint;
+ rcc[1].paint = ccm.paint;
+ A_fill_region(pfs, rcc, t0, tm);
+ cc[0].paint = ccm.paint;
+ t0 = tm;
+ goto top;
+ }
+}
+
+int
+gs_shading_A_fill_rectangle(const gs_shading_t * psh0, const gs_rect * rect,
+ gx_device * dev, gs_imager_state * pis)
+{
+ const gs_shading_A_t *const psh = (const gs_shading_A_t *)psh0;
+ A_fill_state_t state;
+ gs_client_color cc[2];
+ float d0 = psh->params.Domain[0], d1 = psh->params.Domain[1], dd = d1 - d0;
+ float t[2];
+ gs_point dist;
+ int i;
+
+ shade_init_fill_state((shading_fill_state_t *) & state, psh0, dev, pis);
+ state.psh = psh;
+ state.rect = *rect;
+ /* Compute the parameter range. */
+ t[0] = d0;
+ t[1] = d1;
+/****** INTERSECT Domain WITH rect ******/
+ for (i = 0; i < 2; ++i)
+ gs_function_evaluate(psh->params.Function, &t[i],
+ cc[i].paint.values);
+ state.delta.x = psh->params.Coords[2] - psh->params.Coords[0];
+ state.delta.y = psh->params.Coords[3] - psh->params.Coords[1];
+ gs_distance_transform(state.delta.x, state.delta.y, &ctm_only(pis),
+ &dist);
+ state.length = hypot(dist.x, dist.y); /* device space line length */
+ state.dd = dd;
+/****** DOESN'T HANDLE Extend ******/
+ return A_fill_region(&state, cc, (t[0] - d0) / dd, (t[1] - d0) / dd);
+}
+
+/* ---------------- Radial shading ---------------- */
+
+typedef struct R_fill_state_s {
+ shading_fill_state_common;
+ const gs_shading_R_t *psh;
+ gs_rect rect;
+ gs_point delta;
+ double dr, width, dd;
+} R_fill_state_t;
+
+/* Note t0 and t1 vary over [0..1], not the Domain. */
+private int
+R_fill_region(const R_fill_state_t * pfs, gs_client_color cc[2],
+ floatp t0, floatp t1)
+{
+ const gs_shading_R_t * const psh = pfs->psh;
+
+top:
+ if (!shade_colors2_converge(cc, (const shading_fill_state_t *)pfs)) {
+ /*
+ * The colors don't converge. Is the annulus less than 1 pixel wide?
+ */
+ if (pfs->width * (t1 - t0) > 1)
+ goto recur;
+ /* We could do the 1-pixel case a lot faster! */
+ }
+ /* Fill the region with the color. */
+ {
+ gx_device_color dev_color;
+ const gs_color_space *pcs = psh->params.ColorSpace;
+ gs_imager_state *pis = pfs->pis;
+ double
+ x0 = psh->params.Coords[0] + pfs->delta.x * t0,
+ y0 = psh->params.Coords[1] + pfs->delta.y * t0,
+ r0 = psh->params.Coords[2] + pfs->dr * t0;
+ double
+ x1 = psh->params.Coords[0] + pfs->delta.x * t1,
+ y1 = psh->params.Coords[1] + pfs->delta.y * t1,
+ r1 = psh->params.Coords[2] + pfs->dr * t1;
+ gx_path *ppath = gx_path_alloc(pis->memory, "R_fill");
+ int code;
+
+ (*pcs->type->restrict_color)(&cc[0], pcs);
+ (*pcs->type->remap_color)(&cc[0], pcs, &dev_color, pis,
+ pfs->dev, gs_color_select_texture);
+ if ((code = gs_imager_arc_add(ppath, pis, false, x0, y0, r0,
+ 0.0, 360.0, false)) >= 0 &&
+ (code = gs_imager_arc_add(ppath, pis, true, x1, y1, r1,
+ 0.0, 360.0, false)) >= 0
+ ) {
+ code = shade_fill_path((const shading_fill_state_t *)pfs,
+ ppath, &dev_color);
+ }
+ gx_path_free(ppath, "R_fill");
+ return code;
+ }
+
+ /*
+ * No luck. Subdivide the interval and recur.
+ */
+recur:
+ {
+ gs_client_color ccm, rcc[2];
+ gs_function_t *pfn = psh->params.Function;
+ float tm = (t0 + t1) * 0.5;
+ float dm = tm * pfs->dd + psh->params.Domain[0];
+
+ gs_function_evaluate(pfn, &dm, ccm.paint.values);
+ rcc[0].paint = cc[0].paint;
+ rcc[1].paint = ccm.paint;
+ R_fill_region(pfs, rcc, t0, tm);
+ cc[0].paint = ccm.paint;
+ t0 = tm;
+ goto top;
+ }
+}
+
+int
+gs_shading_R_fill_rectangle(const gs_shading_t * psh0, const gs_rect * rect,
+ gx_device * dev, gs_imager_state * pis)
+{
+ const gs_shading_R_t *const psh = (const gs_shading_R_t *)psh0;
+ R_fill_state_t state;
+ gs_client_color cc[2];
+ float d0 = psh->params.Domain[0], d1 = psh->params.Domain[1], dd = d1 - d0;
+ float t[2];
+ int i;
+
+ shade_init_fill_state((shading_fill_state_t *) & state, psh0, dev, pis);
+ state.psh = psh;
+ state.rect = *rect;
+ /* Compute the parameter range. */
+ t[0] = d0;
+ t[1] = d1;
+/****** INTERSECT Domain WITH rect ******/
+ for (i = 0; i < 2; ++i)
+ gs_function_evaluate(psh->params.Function, &t[i],
+ cc[i].paint.values);
+ state.delta.x = psh->params.Coords[3] - psh->params.Coords[0];
+ state.delta.y = psh->params.Coords[4] - psh->params.Coords[1];
+ state.dr = psh->params.Coords[5] - psh->params.Coords[2];
+ /*
+ * Compute the annulus width in its thickest direction. This is
+ * only used for a conservative check, so it can be pretty crude
+ * (and it is!).
+ */
+ state.width =
+ (fabs(pis->ctm.xx) + fabs(pis->ctm.xy) + fabs(pis->ctm.yx) +
+ fabs(pis->ctm.yy)) * fabs(state.dr);
+ state.dd = dd;
+/****** DOESN'T HANDLE Extend ******/
+ return R_fill_region(&state, cc, (t[0] - d0) / dd, (t[1] - d0) / dd);
+}
diff --git a/pstoraster/gxshade4.c b/pstoraster/gxshade4.c
new file mode 100644
index 000000000..f4daab43d
--- /dev/null
+++ b/pstoraster/gxshade4.c
@@ -0,0 +1,285 @@
+/* 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$ */
+/* Rendering for Gouraud triangle shadings */
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsmatrix.h" /* for gscoord.h */
+#include "gscoord.h"
+#include "gxcspace.h"
+#include "gxdcolor.h"
+#include "gxdevcli.h"
+#include "gxistate.h"
+#include "gxpath.h"
+#include "gxshade.h"
+#include "gxshade4.h"
+
+/* ---------------- Triangle mesh filling ---------------- */
+
+/* Initialize the fill state for triangle shading. */
+void
+mesh_init_fill_state(mesh_fill_state_t * pfs, const gs_shading_mesh_t * psh,
+ const gs_rect * rect, gx_device * dev,
+ gs_imager_state * pis)
+{
+ shade_init_fill_state((shading_fill_state_t *) pfs,
+ (const gs_shading_t *)psh, dev, pis);
+ pfs->pshm = psh;
+ shade_bbox_transform2fixed(rect, pis, &pfs->rect);
+}
+
+#define SET_MIN_MAX_3(vmin, vmax, a, b, c)\
+ if ( a < b ) vmin = a, vmax = b; else vmin = b, vmax = a;\
+ if ( c < vmin ) vmin = c; else if ( c > vmax ) vmax = c
+
+int
+mesh_fill_triangle(const mesh_fill_state_t * pfs, const mesh_vertex_t *va,
+ const mesh_vertex_t *vb, const mesh_vertex_t *vc,
+ bool check)
+{
+ const gs_shading_mesh_t *psh = pfs->pshm;
+ int ci;
+
+ /*
+ * Fill the triangle with vertices at va->p, vb->p, and vc->p
+ * with color va->cc.
+ * If check is true, check for whether the triangle is entirely
+ * inside the rectangle, entirely outside, or partly inside;
+ * if check is false, assume the triangle is entirely inside.
+ */
+ if (check) {
+ fixed xmin, ymin, xmax, ymax;
+
+ SET_MIN_MAX_3(xmin, xmax, va->p.x, vb->p.x, vc->p.x);
+ SET_MIN_MAX_3(ymin, ymax, va->p.y, vb->p.y, vc->p.y);
+ if (xmin >= pfs->rect.p.x && xmax <= pfs->rect.q.x &&
+ ymin >= pfs->rect.p.y && ymax <= pfs->rect.q.y
+ ) {
+ /* The triangle is entirely inside the rectangle. */
+ check = false;
+ } else if (xmin >= pfs->rect.q.x || xmax <= pfs->rect.p.x ||
+ ymin >= pfs->rect.q.y || ymax <= pfs->rect.p.y
+ ) {
+ /* The triangle is entirely outside the rectangle. */
+ return 0;
+ }
+ }
+ /* Check whether the colors fall within the smoothness criterion. */
+ for (ci = 0; ci < pfs->num_components; ++ci) {
+ float c0 = va->cc[ci], c1 = vb->cc[ci], c2 = vc->cc[ci];
+ float cmin, cmax;
+
+ SET_MIN_MAX_3(cmin, cmax, c0, c1, c2);
+ if (cmax - cmin > pfs->cc_max_error[ci])
+ goto recur;
+ }
+ /* Fill the triangle with the color. */
+ {
+ gx_device_color dev_color;
+ const gs_color_space *pcs = psh->params.ColorSpace;
+ gs_imager_state *pis = pfs->pis;
+ gs_client_color fcc;
+ int code;
+
+ memcpy(&fcc.paint, va->cc, sizeof(fcc.paint));
+ (*pcs->type->restrict_color)(&fcc, pcs);
+ (*pcs->type->remap_color)(&fcc, pcs, &dev_color, pis,
+ pfs->dev, gs_color_select_texture);
+/****** SHOULD ADD adjust ON ANY OUTSIDE EDGES ******/
+#if 0
+ {
+ gx_path *ppath = gx_path_alloc(pis->memory, "Gt_fill");
+
+ gx_path_add_point(ppath, va->p.x, va->p.y);
+ gx_path_add_line(ppath, vb->p.x, vb->p.y);
+ gx_path_add_line(ppath, vc->p.x, vc->p.y);
+ code = shade_fill_path((const shading_fill_state_t *)pfs,
+ ppath, &dev_color);
+ gx_path_free(ppath, "Gt_fill");
+ }
+#else
+ code = (*dev_proc(pfs->dev, fill_triangle))
+ (pfs->dev, va->p.x, va->p.y,
+ vb->p.x - va->p.x, vb->p.y - va->p.y,
+ vc->p.x - va->p.x, vc->p.y - va->p.y,
+ &dev_color, pis->log_op);
+#endif
+ return code;
+ }
+ /*
+ * Subdivide the triangle and recur. The only subdivision method
+ * that doesn't seem to create anomalous shapes divides the
+ * triangle in 4, using the midpoints of each side.
+ */
+recur:
+ {
+ mesh_vertex_t vab, vac, vbc;
+ int i;
+ int code;
+
+#define MIDPOINT_FAST(a,b) arith_rshift_1((a) + (b) + 1)
+ vab.p.x = MIDPOINT_FAST(va->p.x, vb->p.x);
+ vab.p.y = MIDPOINT_FAST(va->p.y, vb->p.y);
+ vac.p.x = MIDPOINT_FAST(va->p.x, vc->p.x);
+ vac.p.y = MIDPOINT_FAST(va->p.y, vc->p.y);
+ vbc.p.x = MIDPOINT_FAST(vb->p.x, vc->p.x);
+ vbc.p.y = MIDPOINT_FAST(vb->p.y, vc->p.y);
+#undef MIDPOINT_FAST
+ for (i = 0; i < pfs->num_components; ++i) {
+ float ta = va->cc[i], tb = vb->cc[i], tc = vc->cc[i];
+
+ vab.cc[i] = (ta + tb) * 0.5;
+ vac.cc[i] = (ta + tc) * 0.5;
+ vbc.cc[i] = (tb + tc) * 0.5;
+ }
+ /* Do the "A" triangle. */
+ code = mesh_fill_triangle(pfs, va, &vab, &vac, check);
+ if (code < 0)
+ return code;
+ /* Do the central triangle. */
+ code = mesh_fill_triangle(pfs, &vab, &vac, &vbc, check);
+ if (code < 0)
+ return code;
+ /* Do the "C" triangle. */
+ code = mesh_fill_triangle(pfs, &vac, &vbc, vc, check);
+ if (code < 0)
+ return code;
+ /* Do the "B" triangle. */
+ return mesh_fill_triangle(pfs, &vab, vb, &vbc, check);
+ }
+}
+
+/* ---------------- Gouraud triangle shadings ---------------- */
+
+private int
+Gt_next_vertex(const gs_shading_mesh_t * psh, shade_coord_stream_t * cs,
+ mesh_vertex_t * vertex)
+{
+ int code = shade_next_vertex(cs, vertex);
+
+ if (code >= 0 && psh->params.Function) {
+ /* Decode the color with the function. */
+ code = gs_function_evaluate(psh->params.Function, vertex->cc,
+ vertex->cc);
+ }
+ return code;
+}
+
+inline private int
+Gt_fill_triangle(const mesh_fill_state_t * pfs, const mesh_vertex_t * va,
+ const mesh_vertex_t * vb, const mesh_vertex_t * vc)
+{
+ return mesh_fill_triangle(pfs, va, vb, vc, true);
+}
+
+int
+gs_shading_FfGt_fill_rectangle(const gs_shading_t * psh0, const gs_rect * rect,
+ gx_device * dev, gs_imager_state * pis)
+{
+ const gs_shading_FfGt_t * const psh = (const gs_shading_FfGt_t *)psh0;
+ mesh_fill_state_t state;
+ shade_coord_stream_t cs;
+ int num_bits = psh->params.BitsPerFlag;
+ int flag;
+ mesh_vertex_t va, vb, vc;
+
+ mesh_init_fill_state(&state, (const gs_shading_mesh_t *)psh, rect,
+ dev, pis);
+ shade_next_init(&cs, (const gs_shading_mesh_params_t *)&psh->params,
+ pis);
+ while ((flag = shade_next_flag(&cs, num_bits)) >= 0) {
+ int code;
+
+ switch (flag) {
+ default:
+ return_error(gs_error_rangecheck);
+ case 0:
+ if ((code = Gt_next_vertex(state.pshm, &cs, &va)) < 0 ||
+ (code = shade_next_flag(&cs, num_bits)) < 0 ||
+ (code = Gt_next_vertex(state.pshm, &cs, &vb)) < 0 ||
+ (code = shade_next_flag(&cs, num_bits)) < 0
+ )
+ return code;
+ goto v2;
+ case 1:
+ va = vb;
+ case 2:
+ vb = vc;
+v2: if ((code = Gt_next_vertex(state.pshm, &cs, &vc)) < 0 ||
+ (code = Gt_fill_triangle(&state, &va, &vb, &vc)) < 0
+ )
+ return code;
+ }
+ }
+ return 0;
+}
+
+int
+gs_shading_LfGt_fill_rectangle(const gs_shading_t * psh0, const gs_rect * rect,
+ gx_device * dev, gs_imager_state * pis)
+{
+ const gs_shading_LfGt_t * const psh = (const gs_shading_LfGt_t *)psh0;
+ mesh_fill_state_t state;
+ shade_coord_stream_t cs;
+ mesh_vertex_t *vertex;
+ mesh_vertex_t next;
+ int per_row = psh->params.VerticesPerRow;
+ int i, code = 0;
+
+ mesh_init_fill_state(&state, (const gs_shading_mesh_t *)psh, rect,
+ dev, pis);
+ shade_next_init(&cs, (const gs_shading_mesh_params_t *)&psh->params,
+ pis);
+ vertex = (mesh_vertex_t *)
+ gs_alloc_byte_array(pis->memory, per_row, sizeof(*vertex),
+ "gs_shading_LfGt_render");
+ if (vertex == 0)
+ return_error(gs_error_VMerror);
+ for (i = 0; i < per_row; ++i)
+ if ((code = Gt_next_vertex(state.pshm, &cs, &vertex[i])) < 0)
+ goto out;
+ while (!seofp(cs.s)) {
+ code = Gt_next_vertex(state.pshm, &cs, &next);
+ if (code < 0)
+ goto out;
+ for (i = 1; i < per_row; ++i) {
+ code = Gt_fill_triangle(&state, &vertex[i - 1], &vertex[i], &next);
+ if (code < 0)
+ goto out;
+ vertex[i - 1] = next;
+ code = Gt_next_vertex(state.pshm, &cs, &next);
+ if (code < 0)
+ goto out;
+ code = Gt_fill_triangle(&state, &vertex[i], &vertex[i - 1], &next);
+ if (code < 0)
+ goto out;
+ }
+ vertex[per_row - 1] = next;
+ }
+out:
+ gs_free_object(pis->memory, vertex, "gs_shading_LfGt_render");
+ return code;
+}
diff --git a/pstoraster/gxshade4.h b/pstoraster/gxshade4.h
new file mode 100644
index 000000000..5a6189468
--- /dev/null
+++ b/pstoraster/gxshade4.h
@@ -0,0 +1,58 @@
+/* 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$ */
+/* Internal definitions for triangle shading rendering */
+
+#ifndef gxshade4_INCLUDED
+# define gxshade4_INCLUDED
+
+/*
+ * Define the fill state structure for triangle shadings. This is used
+ * both for the Gouraud triangle shading types and for the Coons and
+ * tensor patch types.
+ *
+ * The shading pointer is named pshm rather than psh in case subclasses
+ * also want to store a pointer of a more specific type.
+ */
+#define mesh_fill_state_common\
+ shading_fill_state_common;\
+ const gs_shading_mesh_t *pshm;\
+ gs_fixed_rect rect
+typedef struct mesh_fill_state_s {
+ mesh_fill_state_common;
+} mesh_fill_state_t;
+
+/* Initialize the fill state for triangle shading. */
+void mesh_init_fill_state(P5(mesh_fill_state_t * pfs,
+ const gs_shading_mesh_t * psh,
+ const gs_rect * rect,
+ gx_device * dev, gs_imager_state * pis));
+
+/* Fill one triangle in a mesh. */
+int mesh_fill_triangle(P5(const mesh_fill_state_t * pfs,
+ const mesh_vertex_t *va, const mesh_vertex_t *vb,
+ const mesh_vertex_t *vc, bool check_clipping));
+
+#endif /* gxshade4_INCLUDED */
diff --git a/pstoraster/gxshade6.c b/pstoraster/gxshade6.c
new file mode 100644
index 000000000..4934e33e8
--- /dev/null
+++ b/pstoraster/gxshade6.c
@@ -0,0 +1,566 @@
+/* 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$ */
+/* Rendering for Coons and tensor patch shadings */
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsmatrix.h" /* for gscoord.h */
+#include "gscoord.h"
+#include "gxcspace.h"
+#include "gxdcolor.h"
+#include "gxistate.h"
+#include "gxshade.h"
+#include "gxshade4.h"
+#include "gzpath.h"
+
+/* ================ Utilities ================ */
+
+/* Define one segment (vertex and next control points) of a curve. */
+typedef struct patch_curve_s {
+ mesh_vertex_t vertex;
+ gs_fixed_point control[2];
+} patch_curve_t;
+
+/* Get colors for patch vertices. */
+private int
+shade_next_colors(shade_coord_stream_t * cs, patch_curve_t * curves,
+ int num_vertices)
+{
+ int i, code = 0;
+
+ for (i = 0; i < num_vertices && code >= 0; ++i)
+ code = shade_next_color(cs, curves[i].vertex.cc);
+ return code;
+}
+
+/* Get a Bezier or tensor patch element. */
+private int
+shade_next_curve(shade_coord_stream_t * cs, patch_curve_t * curve)
+{
+ int code = shade_next_coords(cs, &curve->vertex.p, 1);
+
+ if (code >= 0)
+ code = shade_next_coords(cs, curve->control,
+ countof(curve->control));
+ return code;
+}
+
+/* Define a color to be used in curve rendering. */
+/* This may be a real client color, or a parametric function argument. */
+typedef struct patch_color_s {
+ float t; /* parametric value */
+ gs_client_color cc;
+} patch_color_t;
+
+/*
+ * Parse the next patch out of the input stream. Return 1 if done,
+ * 0 if patch, <0 on error.
+ */
+private int
+shade_next_patch(shade_coord_stream_t * cs, int BitsPerFlag,
+patch_curve_t curve[4], gs_fixed_point interior[4] /* 0 for Coons patch */ )
+{
+ int flag = shade_next_flag(cs, BitsPerFlag);
+ int num_colors, code;
+
+ if (flag < 0)
+ return 1; /* no more data */
+ switch (flag & 3) {
+ default:
+ return_error(gs_error_rangecheck); /* not possible */
+ case 0:
+ if ((code = shade_next_curve(cs, &curve[0])) < 0 ||
+ (code = shade_next_coords(cs, &curve[1].vertex.p, 1)) < 0
+ )
+ return code;
+ num_colors = 4;
+ goto vx;
+ case 1:
+ curve[0] = curve[1], curve[1].vertex = curve[2].vertex;
+ goto v3;
+ case 2:
+ curve[0] = curve[2], curve[1].vertex = curve[3].vertex;
+ goto v3;
+ case 3:
+ curve[1].vertex = curve[0].vertex, curve[0] = curve[3];
+v3: num_colors = 2;
+vx: if ((code = shade_next_coords(cs, curve[1].control, 2)) < 0 ||
+ (code = shade_next_curve(cs, &curve[2])) < 0 ||
+ (code = shade_next_curve(cs, &curve[3])) < 0 ||
+ (interior != 0 &&
+ (code = shade_next_coords(cs, interior, 4)) < 0) ||
+ (code = shade_next_colors(cs, &curve[4 - num_colors],
+ num_colors)) < 0
+ )
+ return code;
+ }
+ return 0;
+}
+
+/* Define the common state for rendering Coons and tensor patches. */
+typedef struct patch_fill_state_s {
+ mesh_fill_state_common;
+ const gs_function_t *Function;
+} patch_fill_state_t;
+
+/* Calculate the interpolated color at a given point. */
+/* Note that we must do this twice for bilinear interpolation. */
+private void
+patch_interpolate_color(patch_color_t * ppc, const patch_color_t * ppc0,
+ const patch_color_t * ppc1, const patch_fill_state_t * pfs, floatp t)
+{
+ if (pfs->Function)
+ ppc->t = ppc0->t + t * (ppc1->t - ppc0->t);
+ else {
+ int ci;
+
+ for (ci = pfs->num_components - 1; ci >= 0; --ci)
+ ppc->cc.paint.values[ci] =
+ ppc0->cc.paint.values[ci] +
+ t * (ppc1->cc.paint.values[ci] - ppc0->cc.paint.values[ci]);
+ }
+}
+
+/* Resolve a patch color using the Function if necessary. */
+private void
+patch_resolve_color(patch_color_t * ppc, const patch_fill_state_t * pfs)
+{
+ if (pfs->Function)
+ gs_function_evaluate(pfs->Function, &ppc->t, ppc->cc.paint.values);
+}
+
+/* ================ Specific shadings ================ */
+
+/*
+ * The curves are stored in a clockwise or counter-clockwise order that maps
+ * to the patch definition in a non-intuitive way:
+ */
+/* The starting points of the curves: */
+#define C1START 0
+#define D1START 0
+#define C2START 3
+#define D2START 1
+/* The control points of the curves (x means reversed order): */
+#define C1CTRL 0
+#define D1XCTRL 3
+#define C2XCTRL 2
+#define D2CTRL 1
+/* The end points of the curves: */
+#define C1END 1
+#define D1END 3
+#define C2END 2
+#define D2END 2
+
+/* ---------------- Common code ---------------- */
+
+/* Evaluate a curve at a given point. */
+private void
+curve_eval(gs_fixed_point * pt, const gs_fixed_point * p0,
+ const gs_fixed_point * p1, const gs_fixed_point * p2,
+ const gs_fixed_point * p3, floatp t)
+{
+ fixed a, b, c, d;
+ fixed t01, t12;
+
+ d = p0->x;
+ curve_points_to_coefficients(d, p1->x, p2->x, p3->x,
+ a, b, c, t01, t12);
+ pt->x = (fixed) (((a * t + b) * t + c) * t + d);
+ d = p0->y;
+ curve_points_to_coefficients(d, p1->y, p2->y, p3->y,
+ a, b, c, t01, t12);
+ pt->y = (fixed) (((a * t + b) * t + c) * t + d);
+ if_debug3('2', "[2]t=%g => (%g,%g)\n", t, fixed2float(pt->x),
+ fixed2float(pt->y));
+}
+
+/*
+ * Merge two arrays of splits, sorted in increasing order.
+ * Return the number of entries in the result, which might be less than
+ * n1 + n2 (if an a1 entry is equal to an a2 entry).
+ * a1 or a2 may overlap out as long as a1 - out >= n2 or a2 - out >= n1
+ * respectively.
+ */
+private int
+merge_splits(double *out, const double *a1, int n1, const double *a2, int n2)
+{
+ double *p = out;
+ int i1 = 0, i2 = 0;
+
+ /*
+ * We would like to write the body of the loop as an assignement
+ * with a conditional expression on the right, but gcc 2.7.2.3
+ * generates incorrect code if we do this.
+ */
+ while (i1 < n1 || i2 < n2)
+ if (i1 == n1)
+ *p++ = a2[i2++];
+ else if (i2 == n2 || a1[i1] < a2[i2])
+ *p++ = a1[i1++];
+ else if (a1[i1] > a2[i2])
+ *p++ = a2[i2++];
+ else
+ i1++, *p++ = a2[i2++];
+ return p - out;
+}
+
+/* Split a curve in both X and Y. Return the number of split points. */
+private int
+split_xy(double out[4], const patch_curve_t * curve, const gs_fixed_point * p3)
+{
+ double tx[2], ty[2];
+
+ return merge_splits(out, tx,
+ gx_curve_monotonic_points(curve->vertex.p.x,
+ curve->control[0].x,
+ curve->control[1].x,
+ p3->x, tx),
+ ty,
+ gx_curve_monotonic_points(curve->vertex.p.y,
+ curve->control[0].y,
+ curve->control[1].y,
+ p3->y, ty));
+}
+
+/*
+ * Compute the joint split points of 2 curves.
+ * Return the number of split points.
+ */
+private int
+split2_xy(double out[8], const patch_curve_t * curve1,
+ const gs_fixed_point * p31, const patch_curve_t * curve2,
+ const gs_fixed_point * p32)
+{
+ double t1[4], t2[4];
+
+ return merge_splits(out, t1, split_xy(t1, curve1, p31),
+ t2, split_xy(t2, curve2, p32));
+}
+
+private int
+patch_fill(const patch_fill_state_t * pfs, const patch_curve_t curve[4],
+ const gs_fixed_point interior[4],
+ void (*transform) (P5(gs_fixed_point *, const patch_curve_t[4],
+ const gs_fixed_point[4], floatp, floatp)))
+{ /*
+ * The specification says the output must appear to be produced in
+ * order of increasing values of v, and for equal v, in order of
+ * increasing u. However, all we actually have to do is follow this
+ * order with respect to sub-patches that might overlap, which can
+ * only occur as a result of non-monotonic curves; we can render
+ * each monotonic sub-patch in any order we want. Therefore, we
+ * begin by breaking up the patch into pieces that are monotonic
+ * with respect to all 4 edges. Since each edge has no more than
+ * 2 X and 2 Y split points (for a total of 4), taking both edges
+ * together we have a maximum of 8 split points for each axis.
+ *
+ * The current documentation doesn't say how the 4 curves
+ * correspond to the 'u' or 'v' edges. Pending clarification from
+ * Adobe, we assume the 1st and 3rd are the 'u' edges and the
+ * 2nd and 4th are the 'v' edges.
+ ****** CHECK AGAINST UPDATED DOC ******
+ */
+ double u[9], v[9];
+ int nu = split2_xy(u, &curve[0], &curve[1].vertex.p,
+ &curve[2], &curve[3].vertex.p);
+ int nv = split2_xy(v, &curve[1], &curve[2].vertex.p,
+ &curve[3], &curve[0].vertex.p);
+ int iu, iv, ju, jv, ku, kv;
+ double du, dv;
+ double v0, v1, vn, u0, u1, un;
+ patch_color_t c0, c1, c2, c3;
+ /*
+ * At some future time, we should set check = false if the curves
+ * fall entirely within the bounding rectangle. (Only a small
+ * performance optimization, to avoid making this check for each
+ * triangle.)
+ */
+ bool check = true;
+
+#ifdef DEBUG
+ if (gs_debug_c('2')) {
+ int k;
+
+ dlputs("[2]patch curves:\n");
+ for (k = 0; k < 4; ++k)
+ dprintf6(" (%g,%g) (%g,%g)(%g,%g)\n",
+ fixed2float(curve[k].vertex.p.x),
+ fixed2float(curve[k].vertex.p.y),
+ fixed2float(curve[k].control[0].x),
+ fixed2float(curve[k].control[0].y),
+ fixed2float(curve[k].control[1].x),
+ fixed2float(curve[k].control[1].y));
+ }
+#endif
+ /* Add boundary values to simplify the iteration. */
+ u[nu] = 1;
+ v[nv] = 1;
+
+ /*
+ * We're going to fill the curves by flattening them and then filling
+ * the resulting triangles. Start by computing the number of
+ * segments required for flattening each side of the patch.
+ */
+ {
+ fixed flatness = float2fixed(pfs->pis->flatness);
+ int i;
+ int log2_k[4];
+
+ for (i = 0; i < 4; ++i) {
+ curve_segment cseg;
+
+ cseg.p1 = curve[i].control[0];
+ cseg.p2 = curve[i].control[1];
+ cseg.pt = curve[(i + 1) & 3].vertex.p;
+ log2_k[i] =
+ gx_curve_log2_samples(curve[i].vertex.p.x, curve[i].vertex.p.y,
+ &cseg, flatness);
+ }
+ ku = 1 << max(log2_k[0], log2_k[2]);
+ kv = 1 << max(log2_k[1], log2_k[3]);
+ }
+ /*
+ * Since ku and kv are powers of 2, and since log2(k) is surely less
+ * than the number of bits in the mantissa of a double, 1/k ...
+ * (k-1)/k can all be represented exactly as doubles.
+ */
+ du = 1.0 / ku;
+ dv = 1.0 / kv;
+
+ /* Precompute the colors at the corners. */
+
+#define PATCH_SET_COLOR(c, v)\
+ if ( pfs->Function ) c.t = v.cc[0];\
+ else memcpy(c.cc.paint.values, v.cc, sizeof(c.cc.paint.values))
+
+ PATCH_SET_COLOR(c0, curve[0].vertex);
+ PATCH_SET_COLOR(c1, curve[1].vertex);
+ PATCH_SET_COLOR(c2, curve[2].vertex);
+ PATCH_SET_COLOR(c3, curve[3].vertex);
+
+#undef PATCH_SET_COLOR
+
+ /* Now iterate over the sub-patches. */
+ for (iv = 0, jv = 0, v0 = 0, v1 = vn = dv; jv < kv; v0 = v1, v1 = vn) {
+ patch_color_t cv[4];
+
+ /* Subdivide the interval if it crosses a split point. */
+
+#define CHECK_SPLIT(ix, jx, x1, xn, dx, ax)\
+ if (x1 > ax[ix])\
+ x1 = ax[ix++];\
+ else {\
+ xn += dx;\
+ jx++;\
+ if (x1 == ax[ix])\
+ ix++;\
+ }
+
+ CHECK_SPLIT(iv, jv, v1, vn, dv, v);
+
+ patch_interpolate_color(&cv[0], &c0, &c3, pfs, v0);
+ patch_interpolate_color(&cv[1], &c0, &c3, pfs, v1);
+ patch_interpolate_color(&cv[2], &c1, &c2, pfs, v0);
+ patch_interpolate_color(&cv[3], &c1, &c2, pfs, v1);
+
+ for (iu = 0, ju = 0, u0 = 0, u1 = un = du; ju < ku; u0 = u1, u1 = un) {
+ patch_color_t cu[4];
+ int code;
+
+ CHECK_SPLIT(iu, ju, u1, un, du, u);
+
+#undef CHECK_SPLIT
+
+ patch_interpolate_color(&cu[0], &cv[0], &cv[2], pfs, u0);
+ patch_resolve_color(&cu[0], pfs);
+ patch_interpolate_color(&cu[1], &cv[0], &cv[2], pfs, u1);
+ patch_resolve_color(&cu[1], pfs);
+ patch_interpolate_color(&cu[2], &cv[1], &cv[3], pfs, u1);
+ patch_resolve_color(&cu[2], pfs);
+ patch_interpolate_color(&cu[3], &cv[1], &cv[3], pfs, u0);
+ patch_resolve_color(&cu[3], pfs);
+ if_debug6('2', "[2]u[%d]=(%g,%g), v[%d]=(%g,%g)\n",
+ iu, u0, u1, iv, v0, v1);
+
+ /* Fill the sub-patch given by ((u0,v0),(u1,v1)). */
+ {
+ mesh_vertex_t mv[4];
+
+ (*transform)(&mv[0].p, curve, interior, u0, v0);
+ (*transform)(&mv[1].p, curve, interior, u1, v0);
+ (*transform)(&mv[2].p, curve, interior, u1, v1);
+ (*transform)(&mv[3].p, curve, interior, u0, v1);
+ memcpy(&mv[0].cc, cu[0].cc.paint.values, sizeof(mv[0].cc));
+ memcpy(&mv[1].cc, cu[1].cc.paint.values, sizeof(mv[1].cc));
+ memcpy(&mv[2].cc, cu[2].cc.paint.values, sizeof(mv[2].cc));
+ memcpy(&mv[3].cc, cu[3].cc.paint.values, sizeof(mv[3].cc));
+ code = mesh_fill_triangle((const mesh_fill_state_t *)pfs,
+ &mv[0], &mv[1], &mv[2], check);
+ if (code < 0)
+ return code;
+ code = mesh_fill_triangle((const mesh_fill_state_t *)pfs,
+ &mv[2], &mv[3], &mv[0], check);
+ if (code < 0)
+ return code;
+ }
+ }
+ }
+ return 0;
+}
+
+/* ---------------- Coons patch shading ---------------- */
+
+/* Calculate the device-space coordinate corresponding to (u,v). */
+private void
+Cp_transform(gs_fixed_point * pt, const patch_curve_t curve[4],
+ const gs_fixed_point ignore_interior[4], floatp u, floatp v)
+{
+ double co_u = 1.0 - u, co_v = 1.0 - v;
+ gs_fixed_point c1u, d1v, c2u, d2v;
+
+ curve_eval(&c1u, &curve[C1START].vertex.p,
+ &curve[C1CTRL].control[0], &curve[C1CTRL].control[1],
+ &curve[C1END].vertex.p, u);
+ curve_eval(&d1v, &curve[D1START].vertex.p,
+ &curve[D1XCTRL].control[1], &curve[D1XCTRL].control[0],
+ &curve[D1END].vertex.p, v);
+ curve_eval(&c2u, &curve[C2START].vertex.p,
+ &curve[C2XCTRL].control[1], &curve[C2XCTRL].control[0],
+ &curve[C2END].vertex.p, u);
+ curve_eval(&d2v, &curve[D2START].vertex.p,
+ &curve[D2CTRL].control[0], &curve[D2CTRL].control[1],
+ &curve[D2END].vertex.p, v);
+#define COMPUTE_COORD(xy)\
+ pt->xy = (fixed)\
+ ((co_v * c1u.xy + v * c2u.xy) + (co_u * d1v.xy + u * d2v.xy) -\
+ (co_v * (co_u * curve[C1START].vertex.p.xy +\
+ u * curve[C1END].vertex.p.xy) +\
+ v * (co_u * curve[C2START].vertex.p.xy +\
+ u * curve[C2END].vertex.p.xy)))
+ COMPUTE_COORD(x);
+ COMPUTE_COORD(y);
+#undef COMPUTE_COORD
+ if_debug4('2', "[2](u=%g,v=%g) => (%g,%g)\n",
+ u, v, fixed2float(pt->x), fixed2float(pt->y));
+}
+
+int
+gs_shading_Cp_fill_rectangle(const gs_shading_t * psh0, const gs_rect * rect,
+ gx_device * dev, gs_imager_state * pis)
+{
+ const gs_shading_Cp_t * const psh = (const gs_shading_Cp_t *)psh0;
+ patch_fill_state_t state;
+ shade_coord_stream_t cs;
+ patch_curve_t curve[4];
+ int code;
+
+ mesh_init_fill_state((mesh_fill_state_t *) & state,
+ (const gs_shading_mesh_t *)psh0, rect, dev, pis);
+ state.Function = psh->params.Function;
+ shade_next_init(&cs, (const gs_shading_mesh_params_t *)&psh->params,
+ pis);
+ while ((code = shade_next_patch(&cs, psh->params.BitsPerFlag,
+ curve, NULL)) == 0 &&
+ (code = patch_fill(&state, curve, NULL, Cp_transform)) >= 0
+ )
+ DO_NOTHING;
+ return min(code, 0);
+}
+
+/* ---------------- Tensor product patch shading ---------------- */
+
+/* Calculate the device-space coordinate corresponding to (u,v). */
+private void
+Tpp_transform(gs_fixed_point * pt, const patch_curve_t curve[4],
+ const gs_fixed_point interior[4], floatp u, floatp v)
+{
+ double Bu[4], Bv[4];
+ gs_fixed_point pts[4][4];
+ int i, j;
+ fixed x = 0, y = 0;
+
+ /* Compute the Bernstein polynomials of u and v. */
+ {
+ double u2 = u * u, co_u = 1.0 - u, co_u2 = co_u * co_u;
+ double v2 = v * v, co_v = 1.0 - v, co_v2 = co_v * co_v;
+
+ Bu[0] = co_u * co_u2, Bu[1] = 3 * u * co_u2,
+ Bu[2] = 3 * u2 * co_u, Bu[3] = u * u2;
+ Bv[0] = co_v * co_v2, Bv[1] = 3 * v * co_v2,
+ Bv[2] = 3 * v2 * co_v, Bv[3] = v * v2;
+ }
+
+ /* Arrange the points into an indexable order. */
+ pts[0][0] = curve[0].vertex.p;
+ pts[1][0] = curve[0].control[0];
+ pts[2][0] = curve[0].control[1];
+ pts[3][0] = curve[1].vertex.p;
+ pts[3][1] = curve[1].control[0];
+ pts[3][2] = curve[1].control[1];
+ pts[3][3] = curve[2].vertex.p;
+ pts[2][3] = curve[2].control[0];
+ pts[1][3] = curve[2].control[1];
+ pts[0][3] = curve[3].vertex.p;
+ pts[0][2] = curve[3].control[0];
+ pts[0][1] = curve[3].control[1];
+ pts[1][1] = interior[0];
+ pts[2][1] = interior[1];
+ pts[2][2] = interior[2];
+ pts[1][2] = interior[3];
+
+ /* Now compute the actual point. */
+ for (i = 0; i < 4; ++i)
+ for (j = 0; j < 4; ++j) {
+ double coeff = Bu[i] * Bv[j];
+
+ x += pts[i][j].x * coeff, y += pts[i][j].y * coeff;
+ }
+ pt->x = x, pt->y = y;
+}
+
+int
+gs_shading_Tpp_fill_rectangle(const gs_shading_t * psh0, const gs_rect * rect,
+ gx_device * dev, gs_imager_state * pis)
+{
+ const gs_shading_Tpp_t * const psh = (const gs_shading_Tpp_t *)psh0;
+ patch_fill_state_t state;
+ shade_coord_stream_t cs;
+ patch_curve_t curve[4];
+ gs_fixed_point interior[4];
+ int code;
+
+ mesh_init_fill_state((mesh_fill_state_t *) & state,
+ (const gs_shading_mesh_t *)psh0, rect, dev, pis);
+ state.Function = psh->params.Function;
+ shade_next_init(&cs, (const gs_shading_mesh_params_t *)&psh->params,
+ pis);
+ while ((code = shade_next_patch(&cs, psh->params.BitsPerFlag,
+ curve, interior)) == 0 &&
+ (code = patch_fill(&state, curve, interior, Tpp_transform)) >= 0
+ )
+ DO_NOTHING;
+ return min(code, 0);
+}
diff --git a/pstoraster/gxstate.h b/pstoraster/gxstate.h
new file mode 100644
index 000000000..49ea57a91
--- /dev/null
+++ b/pstoraster/gxstate.h
@@ -0,0 +1,86 @@
+/* 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$ */
+/* Internal graphics state API */
+
+#ifndef gxstate_INCLUDED
+# define gxstate_INCLUDED
+
+/* Opaque type for a graphics state */
+#ifndef gs_state_DEFINED
+# define gs_state_DEFINED
+typedef struct gs_state_s gs_state;
+
+#endif
+
+/*
+ * The interfaces in this file are for internal use only, primarily by the
+ * interpreter. They are not guaranteed to remain stable from one release
+ * to another.
+ */
+
+/* Memory and save/restore management */
+gs_memory_t *gs_state_memory(P1(const gs_state *));
+gs_state *gs_state_saved(P1(const gs_state *));
+gs_state *gs_state_swap_saved(P2(gs_state *, gs_state *));
+gs_memory_t *gs_state_swap_memory(P2(gs_state *, gs_memory_t *));
+
+/*
+ * "Client data" interface for graphics states.
+ *
+ * As of release 4.36, the copy procedure is superseded by copy_for
+ * (although it will still be called if there is no copy_for procedure).
+ */
+typedef void *(*gs_state_alloc_proc_t) (P1(gs_memory_t * mem));
+typedef int (*gs_state_copy_proc_t) (P2(void *to, const void *from));
+typedef void (*gs_state_free_proc_t) (P2(void *old, gs_memory_t * mem));
+typedef enum {
+ copy_for_gsave, /* from = current, to = new(saved) */
+ copy_for_grestore, /* from = saved, to = current */
+ copy_for_gstate, /* from = current, to = new(copy) */
+ copy_for_setgstate, /* from = stored, to = current */
+ copy_for_copygstate, /* from & to are specified explicitly */
+ copy_for_currentgstate /* from = current, to = stored */
+} gs_state_copy_reason_t;
+
+/* Note that the 'from' argument of copy_for is not const. */
+/* This is deliberate -- some clients need this. */
+typedef int (*gs_state_copy_for_proc_t) (P3(void *to, void *from,
+ gs_state_copy_reason_t reason));
+typedef struct gs_state_client_procs_s {
+ gs_state_alloc_proc_t alloc;
+ gs_state_copy_proc_t copy;
+ gs_state_free_proc_t free;
+ gs_state_copy_for_proc_t copy_for;
+} gs_state_client_procs;
+void gs_state_set_client(P3(gs_state *, void *, const gs_state_client_procs *));
+
+/* gzstate.h redefines the following: */
+#ifndef gs_state_client_data
+void *gs_state_client_data(P1(const gs_state *));
+
+#endif
+
+#endif /* gxstate_INCLUDED */
diff --git a/pstoraster/gxstroke.c b/pstoraster/gxstroke.c
new file mode 100644
index 000000000..77ff1094d
--- /dev/null
+++ b/pstoraster/gxstroke.c
@@ -0,0 +1,1319 @@
+/* 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$ */
+/* Path stroking procedures for Ghostscript library */
+#include "math_.h"
+#include "gx.h"
+#include "gpcheck.h"
+#include "gserrors.h"
+#include "gsdcolor.h"
+#include "gxfixed.h"
+#include "gxfarith.h"
+#include "gxmatrix.h"
+#include "gscoord.h"
+#include "gsdevice.h"
+#include "gxdevice.h"
+#include "gxhttile.h"
+#include "gxistate.h"
+#include "gzline.h"
+#include "gzpath.h"
+#include "gzcpath.h"
+#include "gxpaint.h"
+
+/*
+ * We don't really know whether it's a good idea to take fill adjustment
+ * into account for stroking. Disregarding it means that strokes
+ * come out thinner than fills; observing it produces heavy-looking
+ * strokes at low resolutions. But in any case, we must disregard it
+ * when stroking zero-width lines.
+ */
+#define USE_FILL_ADJUSTMENT
+
+#ifdef USE_FILL_ADJUSTMENT
+# define stroke_adjustment(thin, pis, xy)\
+ (thin ? fixed_0 : (pis)->fill_adjust.xy)
+#else
+# define stroke_adjustment(thin, pis, xy) fixed_0
+#endif
+
+/*
+ * For some reason, we commented out the optimization for portrait,
+ * landscape, and uniform (non-scaled) transformations. We have no record
+ * of why we did this, and we don't know what bugs re-enabling it may
+ * introduce.
+ */
+#define OPTIMIZE_ORIENTATION
+
+/*
+ * Compute the amount by which to expand a stroked bounding box to account
+ * for line width, caps and joins. Because of square caps and miter and
+ * triangular joins, the maximum expansion on each side (in user space) is
+ * K * line_width/2
+ * where K is determined as follows:
+ * If the path is only a single line segment, K = 1;
+ * if triangular joins, K = 2;
+ * if miter joins, K = miter_limit;
+ * otherwise, K = 1.
+ * If the amount is too large to fit in a gs_fixed_point, return
+ * gs_error_limitcheck.
+ *
+ * If the miter limit is very large, the foregoing computation will produce
+ * a result that is much too large; we would like to tighten this up at
+ * some point in the future.
+ */
+int
+gx_stroke_path_expansion(const gs_imager_state * pis, const gx_path * ppath,
+ gs_fixed_point * ppt)
+{
+ const subpath *psub = ppath->first_subpath;
+ const segment *pseg;
+ double expand =
+ (!gx_path_has_curves(ppath) && gx_path_subpath_count(ppath) <= 1 &&
+ (psub == 0 || (pseg = psub->next) == 0 ||
+ (pseg = pseg->next) == 0 || pseg->type == s_line_close) ? 1.0 :
+ pis->line_params.join == gs_join_miter ?
+ pis->line_params.miter_limit :
+ pis->line_params.join == gs_join_triangle ? 2.0 : 1.0) *
+ pis->line_params.half_width;
+
+ /* Short-cut gs_bbox_transform. */
+ float cx1 = pis->ctm.xx + pis->ctm.yx;
+ float cy1 = pis->ctm.xy + pis->ctm.yy;
+ float cx2 = pis->ctm.xx - pis->ctm.yx;
+ float cy2 = pis->ctm.xy - pis->ctm.yy;
+
+ if (cx1 < 0)
+ cx1 = -cx1;
+ if (cy1 < 0)
+ cy1 = -cy1;
+ if (cx2 < 0)
+ cx2 = -cx2;
+ if (cy2 < 0)
+ cy2 = -cy2;
+ {
+ float exx = expand * max(cx1, cx2);
+ float exy = expand * max(cy1, cy2);
+ int code = set_float2fixed_vars(ppt->x, exx);
+
+ if (code < 0)
+ return code;
+ return set_float2fixed_vars(ppt->y, exy);
+ }
+}
+
+/*
+ * Structure for a partial line (passed to the drawing routine).
+ * Two of these are required to do joins right.
+ * Each endpoint includes the two ends of the cap as well,
+ * and the deltas for square, round, and triangular cap computation.
+ *
+ * The two base values for computing the caps of a partial line are the
+ * width and the end cap delta. The width value is one-half the line
+ * width (suitably transformed) at 90 degrees counter-clockwise
+ * (in device space, but with "90 degrees" interpreted in *user*
+ * coordinates) at the end (as opposed to the origin) of the line.
+ * The cdelta value is one-half the transformed line width in the same
+ * direction as the line. From these, we compute two other values at each
+ * end of the line: co and ce, which are the ends of the cap.
+ * Note that the cdelta values at o are the negatives of the values at e,
+ * as are the offsets from p to co and ce.
+ *
+ * Initially, only o.p, e.p, e.cdelta, width, and thin are set.
+ * compute_caps fills in the rest.
+ */
+typedef gs_fixed_point *p_ptr;
+typedef struct endpoint_s {
+ gs_fixed_point p; /* the end of the line */
+ gs_fixed_point co, ce; /* ends of the cap, p +/- width */
+ gs_fixed_point cdelta; /* +/- cap length */
+} endpoint;
+typedef endpoint *ep_ptr;
+typedef const endpoint *const_ep_ptr;
+typedef struct partial_line_s {
+ endpoint o; /* starting coordinate */
+ endpoint e; /* ending coordinate */
+ gs_fixed_point width; /* one-half line width, see above */
+ bool thin; /* true if minimum-width line */
+} partial_line;
+typedef partial_line *pl_ptr;
+
+/* Assign a point. Some compilers would do this with very slow code */
+/* if we simply implemented it as an assignment. */
+#define ASSIGN_POINT(pp, p)\
+ ((pp)->x = (p).x, (pp)->y = (p).y)
+
+/* Other forward declarations */
+private bool width_is_thin(P1(pl_ptr));
+private void adjust_stroke(P3(pl_ptr, const gs_imager_state *, bool));
+private int line_join_points(P5(const gx_line_params * pgs_lp,
+ pl_ptr plp, pl_ptr nplp,
+ gs_fixed_point * join_points,
+ const gs_matrix * pmat));
+private void compute_caps(P1(pl_ptr));
+private int add_points(P4(gx_path *, const gs_fixed_point *,
+ int, bool));
+private int add_round_cap(P2(gx_path *, const_ep_ptr));
+private int cap_points(P3(gs_line_cap, const_ep_ptr,
+ gs_fixed_point * /*[3] */ ));
+
+/* Define the default implementation of the device stroke_path procedure. */
+int
+gx_default_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 gx_stroke_path_only(ppath, (gx_path *) 0, dev, pis, params,
+ pdcolor, pcpath);
+}
+
+/* Fill a partial stroked path. Free variables: */
+/* to_path, stroke_path_body, fill_params, always_thin, pis, dev, pdevc, */
+/* code, ppath, exit(label). */
+#define fill_stroke_path(thin)\
+ if(to_path==&stroke_path_body && !gx_path_is_void(&stroke_path_body)) {\
+ fill_params.adjust.x = stroke_adjustment(thin, pis, x);\
+ fill_params.adjust.y = stroke_adjustment(thin, pis, y);\
+ code = gx_fill_path_only(to_path, dev, pis, &fill_params, pdevc, NULL);\
+ gx_path_free(&stroke_path_body, "fill_stroke_path");\
+ if ( code < 0 ) goto exit;\
+ gx_path_init_local(&stroke_path_body, ppath->memory);\
+ }
+
+/*
+ * Define the internal procedures that stroke a partial_line
+ * (the first pl_ptr argument). If both partial_lines are non-null,
+ * the procedure creates an appropriate join; otherwise, the procedure
+ * creates an end cap. If the first int is 0, the procedure also starts
+ * with an appropriate cap.
+ */
+#define stroke_line_proc(proc)\
+ int proc(P10(gx_path *, int, pl_ptr, pl_ptr, const gx_device_color *,\
+ gx_device *, const gs_imager_state *,\
+ const gx_stroke_params *, const gs_fixed_rect *, int))
+typedef stroke_line_proc((*stroke_line_proc_t));
+
+private stroke_line_proc(stroke_add);
+private stroke_line_proc(stroke_fill);
+
+/* Define the orientations we handle specially. */
+typedef enum {
+ orient_other = 0,
+ orient_portrait, /* [xx 0 0 yy tx ty] */
+ orient_landscape /* [0 xy yx 0 tx ty] */
+} orientation;
+
+/*
+ * Stroke a path. If to_path != 0, append the stroke outline to it;
+ * if to_path == 0, draw the strokes on dev.
+ *
+ * Note that gx_stroke_path_only with to_path != NULL may clip the path to
+ * the clipping path, as for to_path == NULL. This is almost never
+ * what is wanted.
+ */
+int
+gx_stroke_path_only(gx_path * ppath, gx_path * to_path, gx_device * pdev,
+ const gs_imager_state * pis, const gx_stroke_params * params,
+ const gx_device_color * pdevc, const gx_clip_path * pcpath)
+{
+ stroke_line_proc_t line_proc =
+ (to_path == 0 ? stroke_fill : stroke_add);
+ gs_fixed_rect ibox, cbox;
+ gx_device_clip cdev;
+ gx_device *dev = pdev;
+ int code = 0;
+ gx_fill_params fill_params;
+ const gx_line_params *pgs_lp = gs_currentlineparams_inline(pis);
+ int dash_count = pgs_lp->dash.pattern_size;
+ gx_path fpath, dpath;
+ gx_path stroke_path_body;
+ const gx_path *spath;
+ float xx = pis->ctm.xx, xy = pis->ctm.xy;
+ float yx = pis->ctm.yx, yy = pis->ctm.yy;
+
+ /*
+ * We are dealing with a reflected coordinate system
+ * if transform(1,0) is counter-clockwise from transform(0,1).
+ * See the note in stroke_add for the algorithm.
+ */
+ int uniform;
+ bool reflected;
+ orientation orient =
+ (
+#ifdef OPTIMIZE_ORIENTATION
+ is_fzero2(xy, yx) ?
+ (uniform = (xx == yy ? 1 : xx == -yy ? -1 : 0),
+ reflected = (uniform ? uniform < 0 : (xx < 0) != (yy < 0)),
+ orient_portrait) :
+ is_fzero2(xx, yy) ?
+ (uniform = (xy == yx ? -1 : xy == -yx ? 1 : 0),
+ reflected = (uniform ? uniform < 0 : (xy < 0) == (yx < 0)),
+ orient_landscape) :
+ /* We should optimize uniform rotated coordinate systems */
+ /* here as well, but we don't. */
+#endif
+ (uniform = 0,
+ reflected = xy * yx > xx * yy,
+ orient_other));
+ segment_notes not_first =
+ (!is_fzero(pis->line_params.dot_length) ? sn_not_first : sn_none);
+ float line_width = pgs_lp->half_width; /* (*half* the line width) */
+ bool always_thin;
+ double line_width_and_scale, device_line_width_scale;
+ double device_dot_length = pgs_lp->dot_length * fixed_1;
+ const subpath *psub;
+
+#ifdef DEBUG
+ if (gs_debug_c('o')) {
+ int count = pgs_lp->dash.pattern_size;
+ int i;
+
+ dlprintf3("[o]half_width=%f, cap=%d, join=%d,\n",
+ pgs_lp->half_width, (int)pgs_lp->cap, (int)pgs_lp->join);
+ dlprintf2(" miter_limit=%f, miter_check=%f,\n",
+ pgs_lp->miter_limit, pgs_lp->miter_check);
+ dlprintf1(" dash pattern=%d", count);
+ for (i = 0; i < count; i++)
+ dprintf1(",%f", pgs_lp->dash.pattern[i]);
+ dputs(",\n");
+ dlprintf4("\toffset=%f, init(ink_on=%d, index=%d, dist_left=%f)\n",
+ pgs_lp->dash.offset, pgs_lp->dash.init_ink_on,
+ pgs_lp->dash.init_index, pgs_lp->dash.init_dist_left);
+ }
+#endif
+
+ gx_path_bbox(ppath, &ibox);
+ /* Expand the path bounding box by the scaled line width. */
+ {
+ gs_fixed_point expansion;
+
+ if (gx_stroke_path_expansion(pis, ppath, &expansion) < 0) {
+ /* The expansion is so large it caused a limitcheck. */
+ ibox.p.x = ibox.p.y = min_fixed;
+ ibox.q.x = ibox.q.y = max_fixed;
+ } else {
+ expansion.x += pis->fill_adjust.x;
+ expansion.y += pis->fill_adjust.y;
+ /*
+ * It's theoretically possible for the following computations to
+ * overflow, so we need to check for this.
+ */
+ ibox.p.x = (ibox.p.x < min_fixed + expansion.x ? min_fixed :
+ ibox.p.x - expansion.x);
+ ibox.p.y = (ibox.p.y < min_fixed + expansion.y ? min_fixed :
+ ibox.p.y - expansion.y);
+ ibox.q.x = (ibox.q.x > max_fixed - expansion.x ? max_fixed :
+ ibox.q.x + expansion.x);
+ ibox.q.y = (ibox.q.y > max_fixed - expansion.y ? max_fixed :
+ ibox.q.y + expansion.y);
+ }
+ }
+ /* Check the expanded bounding box against the clipping regions. */
+ if (pcpath)
+ gx_cpath_inner_box(pcpath, &cbox);
+ else if (pdevc)
+ (*dev_proc(dev, get_clipping_box)) (dev, &cbox);
+ else {
+ /* This is strokepath, not stroke. Don't clip. */
+ cbox = ibox;
+ }
+ if (!rect_within(ibox, cbox)) {
+ /* Intersect the path box and the clip bounding box. */
+ /* If the intersection is empty, this call is a no-op. */
+ gs_fixed_rect bbox;
+
+ if (pcpath) {
+ gx_cpath_outer_box(pcpath, &bbox);
+ if_debug4('f', " outer_box=(%g,%g),(%g,%g)\n",
+ fixed2float(bbox.p.x), fixed2float(bbox.p.y),
+ fixed2float(bbox.q.x), fixed2float(bbox.q.y));
+ rect_intersect(ibox, bbox);
+ } else
+ rect_intersect(ibox, cbox);
+ if (ibox.p.x >= ibox.q.x || ibox.p.y >= ibox.q.y) {
+ /* Intersection of boxes is empty! */
+ return 0;
+ }
+ /*
+ * The path is neither entirely inside the inner clip box
+ * nor entirely outside the outer clip box.
+ * If we had to flatten the path, this is where we would
+ * recompute its bbox and make the tests again,
+ * but we don't bother right now.
+ *
+ * If there is a clipping path, set up a clipping device.
+ */
+ if (pcpath) {
+ gx_make_clip_device(&cdev, &cdev, gx_cpath_list(pcpath));
+ cdev.target = dev;
+ cdev.max_fill_band = dev->max_fill_band;
+ dev = (gx_device *) & cdev;
+ (*dev_proc(dev, open_device)) (dev);
+ }
+ }
+ fill_params.rule = gx_rule_winding_number;
+ fill_params.flatness = pis->flatness;
+#ifdef USE_FILL_ADJUSTMENT
+ fill_params.fill_zero_width =
+ (pis->fill_adjust.x | pis->fill_adjust.y) != 0;
+#else
+ fill_params.fill_zero_width = false;
+#endif
+ if (line_width < 0)
+ line_width = -line_width;
+ line_width_and_scale = line_width * (double)int2fixed(1);
+ if (is_fzero(line_width))
+ always_thin = true;
+ else {
+ float xa, ya;
+
+ switch (orient) {
+ case orient_portrait:
+ xa = xx, ya = yy;
+ goto sat;
+ case orient_landscape:
+ xa = xy, ya = yx;
+ sat:
+ if (xa < 0)
+ xa = -xa;
+ if (ya < 0)
+ ya = -ya;
+ always_thin = (max(xa, ya) * line_width < 0.5);
+ if (!always_thin && uniform) { /* Precompute a value we'll need later. */
+ device_line_width_scale = line_width_and_scale * xa;
+ }
+ break;
+ default:
+ {
+ /* The check is more complicated, but it's worth it. */
+ double xsq = xx * xx + xy * xy;
+ double ysq = yx * yx + yy * yy;
+ double cross = xx * yx + xy * yy;
+
+ if (cross < 0)
+ cross = 0;
+ always_thin =
+ ((max(xsq, ysq) + cross) * line_width * line_width
+ < 0.25);
+ }
+ }
+ }
+ if_debug7('o', "[o]ctm=(%g,%g,%g,%g,%g,%g) thin=%d\n",
+ xx, xy, yx, yy, pis->ctm.tx, pis->ctm.ty, always_thin);
+ if (device_dot_length != 0) {
+ /*
+ * Compute the dot length in device space. We can't do this
+ * quite right for non-uniform coordinate systems; too bad.
+ */
+ gs_matrix mat;
+ const gs_matrix *pmat;
+
+ if (pgs_lp->dot_length_absolute) {
+ gs_deviceinitialmatrix(pdev, &mat);
+ pmat = &mat;
+ } else
+ pmat = (const gs_matrix *)&pis->ctm;
+ device_dot_length *= fabs(pmat->xy) + fabs(pmat->yy);
+ }
+ /* Start by flattening the path. We should do this on-the-fly.... */
+ if (!gx_path_has_curves(ppath)) { /* don't need to flatten */
+ if (!ppath->first_subpath)
+ return 0;
+ spath = ppath;
+ } else {
+ gx_path_init_local(&fpath, ppath->memory);
+ if ((code = gx_path_add_flattened_accurate(ppath, &fpath,
+ params->flatness, pis->accurate_curves)) < 0
+ )
+ return code;
+ spath = &fpath;
+ }
+ if (dash_count) {
+ gx_path_init_local(&dpath, ppath->memory);
+ code = gx_path_add_dash_expansion(spath, &dpath, pis);
+ if (code < 0)
+ goto exf;
+ spath = &dpath;
+ }
+ if (to_path == 0) {
+ /* We might try to defer this if it's expensive.... */
+ to_path = &stroke_path_body;
+ gx_path_init_local(&stroke_path_body, ppath->memory);
+ }
+ for (psub = spath->first_subpath; psub != 0;) {
+ int index = 0;
+ const segment *pseg = (const segment *)psub;
+ fixed x = pseg->pt.x;
+ fixed y = pseg->pt.y;
+ bool is_closed = ((const subpath *)pseg)->is_closed;
+ partial_line pl, pl_prev, pl_first;
+
+ while ((pseg = pseg->next) != 0 &&
+ pseg->type != s_start
+ ) {
+ /* Compute the width parameters in device space. */
+ /* We work with unscaled values, for speed. */
+ fixed sx = pseg->pt.x, udx = sx - x;
+ fixed sy = pseg->pt.y, udy = sy - y;
+
+ pl.o.p.x = x, pl.o.p.y = y;
+ d:pl.e.p.x = sx, pl.e.p.y = sy;
+ if (!(udx | udy)) { /* degenerate */
+ /*
+ * If this is the first segment of the subpath,
+ * check the entire subpath for degeneracy.
+ * Otherwise, ignore the degenerate segment.
+ */
+ if (index != 0)
+ continue;
+ /* Check for a degenerate subpath. */
+ while ((pseg = pseg->next) != 0 &&
+ pseg->type != s_start
+ ) {
+ sx = pseg->pt.x, udx = sx - x;
+ sy = pseg->pt.y, udy = sy - y;
+ if (udx | udy)
+ goto d;
+ }
+ /*
+ * The entire subpath is degenerate, but it includes
+ * more than one point. If we are using round caps or
+ * the dot length is non-zero, draw the caps, otherwise
+ * do nothing.
+ */
+ if (!(pgs_lp->cap == gs_cap_round ||
+ pgs_lp->dot_length != 0)
+ )
+ break;
+ /*
+ * Orient the dot according to the previous segment if
+ * any, or else the next segment if any, or else a
+ * vertical line.
+ */
+ {
+ const segment *end = psub->prev;
+
+ if (end != 0 && (end->pt.x != x || end->pt.y != y))
+ sx = end->pt.x, sy = end->pt.y;
+ else if (pseg != 0 &&
+ (pseg->pt.x != x || pseg->pt.y != y)
+ )
+ sx = pseg->pt.x, sy = pseg->pt.y;
+ }
+ /*
+ * Compute the properly oriented dot length, and then
+ * draw the dot like a very short line.
+ */
+ udx = sx - x, udy = sy - y;
+ if ((udx | udy) == 0)
+ udy = fixed_1;
+ {
+ double scale = device_dot_length /
+ hypot((double)udx, (double)udy);
+
+ /*
+ * If we're using butt caps, make sure the "line" is
+ * long enough to show up.
+ */
+ if (pgs_lp->cap == gs_cap_butt) {
+ fixed dmax = max(any_abs(udx), any_abs(udy));
+
+ if (dmax * scale < fixed_1)
+ scale = (float)fixed_1 / dmax;
+ }
+ udx = (fixed) (udx * scale);
+ udy = (fixed) (udy * scale);
+ if ((udx | udy) == 0)
+ udy = fixed_epsilon;
+ sx = x + udx;
+ sy = y + udy;
+ }
+ /*
+ * Back up 1 segment to keep the bookkeeping straight.
+ */
+ pseg = (pseg != 0 ? pseg->prev : psub->last);
+ goto d;
+ }
+ if (always_thin) {
+ pl.e.cdelta.x = pl.e.cdelta.y = 0;
+ pl.width.x = pl.width.y = 0;
+ pl.thin = true;
+ } else {
+ if (uniform != 0) {
+ /* We can save a lot of work in this case. */
+ /* We know orient != orient_other. */
+ float dpx = udx, dpy = udy;
+ float wl = device_line_width_scale /
+ hypot(dpx, dpy);
+
+ pl.e.cdelta.x = (fixed) (dpx * wl);
+ pl.e.cdelta.y = (fixed) (dpy * wl);
+ /* The width is the cap delta rotated by */
+ /* 90 degrees. */
+ pl.width.x = -pl.e.cdelta.y,
+ pl.width.y = pl.e.cdelta.x;
+ pl.thin = false; /* if not always_thin, */
+ /* then never thin. */
+
+ } else {
+ gs_point dpt; /* unscaled */
+ float wl;
+
+ gs_imager_idtransform(pis,
+ (float)udx, (float)udy, &dpt);
+ wl = line_width_and_scale /
+ hypot(dpt.x, dpt.y);
+ /* Construct the width vector in */
+ /* user space, still unscaled. */
+ dpt.x *= wl;
+ dpt.y *= wl;
+ /*
+ * We now compute both perpendicular
+ * and (optionally) parallel half-widths,
+ * as deltas in device space. We use
+ * a fixed-point, unscaled version of
+ * gs_dtransform. The second computation
+ * folds in a 90-degree rotation (in user
+ * space, before transforming) in the
+ * direction that corresponds to counter-
+ * clockwise in device space.
+ */
+ pl.e.cdelta.x = (fixed) (dpt.x * xx);
+ pl.e.cdelta.y = (fixed) (dpt.y * yy);
+ if (orient != orient_portrait)
+ pl.e.cdelta.x += (fixed) (dpt.y * yx),
+ pl.e.cdelta.y += (fixed) (dpt.x * xy);
+ if (!reflected)
+ dpt.x = -dpt.x, dpt.y = -dpt.y;
+ pl.width.x = (fixed) (dpt.y * xx),
+ pl.width.y = -(fixed) (dpt.x * yy);
+ if (orient != orient_portrait)
+ pl.width.x -= (fixed) (dpt.x * yx),
+ pl.width.y += (fixed) (dpt.y * xy);
+ pl.thin = width_is_thin(&pl);
+ }
+ if (!pl.thin) {
+ adjust_stroke(&pl, pis, false);
+ compute_caps(&pl);
+ }
+ }
+ if (index++) {
+ int first;
+ pl_ptr lptr;
+
+ if (pgs_lp->join == gs_join_none &&
+ !(pseg->notes & not_first)
+ ) {
+ /* Fake the end of a subpath so we get */
+ /* caps instead of joins. */
+ first = 0;
+ lptr = 0;
+ index = 1;
+ } else {
+ first = (is_closed ? 1 : index - 2);
+ lptr = &pl;
+ }
+ code = (*line_proc) (to_path, first, &pl_prev, lptr,
+ pdevc, dev, pis, params, &cbox,
+ uniform);
+ if (code < 0)
+ goto exit;
+ fill_stroke_path(always_thin);
+ } else
+ pl_first = pl;
+ pl_prev = pl;
+ x = sx, y = sy;
+ }
+ if (index) {
+ /* If closed, join back to start, else cap. */
+ /* For some reason, the Borland compiler requires the cast */
+ /* in the following statement. */
+ pl_ptr lptr =
+ (!is_closed ||
+ (pgs_lp->join == gs_join_none &&
+ !((pseg == 0 ? (const segment *)spath->first_subpath :
+ pseg)->notes & not_first)) ?
+ (pl_ptr) 0 : (pl_ptr) & pl_first);
+
+ code = (*line_proc) (to_path, index - 1, &pl_prev, lptr,
+ pdevc, dev, pis, params, &cbox, uniform);
+ if (code < 0)
+ goto exit;
+ fill_stroke_path(always_thin);
+ }
+ psub = (const subpath *)pseg;
+ }
+ exit:
+ if (to_path == &stroke_path_body)
+ gx_path_free(&stroke_path_body, "gx_stroke_path_only error"); /* (only needed if error) */
+ if (dash_count)
+ gx_path_free(&dpath, "gx_stroke_path exit(dash path)");
+ exf:
+ if (ppath->curve_count)
+ gx_path_free(&fpath, "gx_stroke_path exit(flattened path)");
+ return code;
+}
+
+/* ------ Internal routines ------ */
+
+/*
+ * Test whether a line is thin, i.e., whether the half-width, measured
+ * perpendicular to the line in device space, is less than 0.5 pixel.
+ * Unfortunately, the width values we computed are perpendicular to the
+ * line in *user* space, so we may have to do some extra work.
+ */
+private bool
+width_is_thin(pl_ptr plp)
+{
+ fixed dx, dy, wx = plp->width.x, wy = plp->width.y;
+
+ /* If the line is horizontal or vertical, things are easy. */
+ if ((dy = plp->e.p.y - plp->o.p.y) == 0)
+ return any_abs(wy) < fixed_half;
+ if ((dx = plp->e.p.x - plp->o.p.x) == 0)
+ return any_abs(wx) < fixed_half;
+
+ /*
+ * If both horizontal and vertical widths are less than
+ * 0.5, the line is thin.
+ */
+ if (any_abs(wx) < fixed_half && any_abs(wy) < fixed_half)
+ return true;
+
+ /*
+ * We have to do this the hard way, by actually computing the
+ * perpendicular distance. The distance from the point (U,V)
+ * from a line from (0,0) to (C,D) is
+ * abs(C*V - D*U) / sqrt(C^2 + D^2)
+ * In this case, (U,V) is plp->width, and (C,D) is (dx,dy).
+ */
+ {
+ double C = dx, D = dy;
+ double num = C * wy - D * wx;
+ double denom = hypot(C, D);
+
+ /* both num and denom are scaled by fixed_scale^2, */
+ /* so we don't need to do any de-scaling for the test. */
+ return fabs(num) < denom * 0.5;
+ }
+}
+
+/* Adjust the endpoints and width of a stroke segment */
+/* to achieve more uniform rendering. */
+/* Only o.p, e.p, e.cdelta, and width have been set. */
+private void
+adjust_stroke(pl_ptr plp, const gs_imager_state * pis, bool thin)
+{
+ fixed *pw;
+ fixed *pov;
+ fixed *pev;
+ fixed w, w2;
+ fixed adj2;
+
+ if (!pis->stroke_adjust && plp->width.x != 0 && plp->width.y != 0)
+ return; /* don't adjust */
+ if (any_abs(plp->width.x) < any_abs(plp->width.y)) {
+ /* More horizontal stroke */
+ pw = &plp->width.y, pov = &plp->o.p.y, pev = &plp->e.p.y;
+ adj2 = stroke_adjustment(thin, pis, y) << 1;
+ } else {
+ /* More vertical stroke */
+ pw = &plp->width.x, pov = &plp->o.p.x, pev = &plp->e.p.x;
+ adj2 = stroke_adjustment(thin, pis, x) << 1;
+ }
+ /* Round the larger component of the width up or down, */
+ /* whichever way produces a result closer to the correct width. */
+ /* Note that just rounding the larger component */
+ /* may not produce the correct result. */
+ w = *pw;
+ w2 = fixed_rounded(w << 1); /* full line width */
+ if (w2 == 0 && *pw != 0) {
+ /* Make sure thin lines don't disappear. */
+ w2 = (*pw < 0 ? -fixed_1 + adj2 : fixed_1 - adj2);
+ *pw = arith_rshift_1(w2);
+ }
+ /* Only adjust the endpoints if the line is horizontal or vertical. */
+ if (*pov == *pev) {
+ /* We're going to round the endpoint coordinates, so */
+ /* take the fill adjustment into account now. */
+ if (w >= 0)
+ w2 += adj2;
+ else
+ w2 = adj2 - w2;
+ if (w2 & fixed_1) /* odd width, move to half-pixel */
+ *pov = *pev = fixed_floor(*pov) + fixed_half;
+ else /* even width, move to pixel */
+ *pov = *pev = fixed_rounded(*pov);
+
+ }
+}
+
+/* Compute the intersection of two lines. This is a messy algorithm */
+/* that somehow ought to be useful in more places than just here.... */
+/* If the lines are (nearly) parallel, return -1 without setting *pi; */
+/* otherwise, return 0 if the intersection is beyond *pp1 and *pp2 in */
+/* the direction determined by *pd1 and *pd2, and 1 otherwise. */
+private int
+line_intersect(
+ p_ptr pp1, /* point on 1st line */
+ p_ptr pd1, /* slope of 1st line (dx,dy) */
+ p_ptr pp2, /* point on 2nd line */
+ p_ptr pd2, /* slope of 2nd line */
+ p_ptr pi)
+{ /* return intersection here */
+ /* We don't have to do any scaling, the factors all work out right. */
+ float u1 = pd1->x, v1 = pd1->y;
+ float u2 = pd2->x, v2 = pd2->y;
+ double denom = u1 * v2 - u2 * v1;
+ float xdiff = pp2->x - pp1->x;
+ float ydiff = pp2->y - pp1->y;
+ double f1;
+ double max_result = any_abs(denom) * (double)max_fixed;
+
+#ifdef DEBUG
+ if (gs_debug_c('O')) {
+ dlprintf4("[o]Intersect %f,%f(%f/%f)",
+ fixed2float(pp1->x), fixed2float(pp1->y),
+ fixed2float(pd1->x), fixed2float(pd1->y));
+ dlprintf4(" & %f,%f(%f/%f),\n",
+ fixed2float(pp2->x), fixed2float(pp2->y),
+ fixed2float(pd2->x), fixed2float(pd2->y));
+ dlprintf3("\txdiff=%f ydiff=%f denom=%f ->\n",
+ xdiff, ydiff, denom);
+ }
+#endif
+ /* Check for degenerate result. */
+ if (any_abs(xdiff) >= max_result || any_abs(ydiff) >= max_result) {
+ /* The lines are nearly parallel, */
+ /* or one of them has zero length. Punt. */
+ if_debug0('O', "\tdegenerate!\n");
+ return -1;
+ }
+ f1 = (v2 * xdiff - u2 * ydiff) / denom;
+ pi->x = pp1->x + (fixed) (f1 * u1);
+ pi->y = pp1->y + (fixed) (f1 * v1);
+ if_debug2('O', "\t%f,%f\n",
+ fixed2float(pi->x), fixed2float(pi->y));
+ return (f1 >= 0 && (v1 * xdiff >= u1 * ydiff ? denom >= 0 : denom < 0) ? 0 : 1);
+}
+
+/* Set up the width and delta parameters for a thin line. */
+/* We only approximate the width and height. */
+private void
+set_thin_widths(register pl_ptr plp)
+{
+ fixed dx = plp->e.p.x - plp->o.p.x, dy = plp->e.p.y - plp->o.p.y;
+
+#define TRSIGN(v, c) ((v) >= 0 ? (c) : -(c))
+ if (any_abs(dx) > any_abs(dy)) {
+ plp->width.x = plp->e.cdelta.y = 0;
+ plp->width.y = plp->e.cdelta.x = TRSIGN(dx, fixed_half);
+ } else {
+ plp->width.y = plp->e.cdelta.x = 0;
+ plp->width.x = -(plp->e.cdelta.y = TRSIGN(dy, fixed_half));
+ }
+#undef TRSIGN
+}
+
+/* Draw a line on the device. */
+/* Treat no join the same as a bevel join. */
+private int
+stroke_fill(gx_path * ppath, int first, register pl_ptr plp, pl_ptr nplp,
+const gx_device_color * pdevc, gx_device * dev, const gs_imager_state * pis,
+ const gx_stroke_params * params, const gs_fixed_rect * pbbox,
+ int uniform)
+{
+ const fixed lix = plp->o.p.x;
+ const fixed liy = plp->o.p.y;
+ const fixed litox = plp->e.p.x;
+ const fixed litoy = plp->e.p.y;
+
+ if (plp->thin) {
+ /* Minimum-width line, don't have to be careful. */
+ /* We do have to check for the entire line being */
+ /* within the clipping rectangle, allowing for some */
+ /* slop at the ends. */
+ fixed x0 = lix, y0 = liy;
+ fixed x1 = litox, y1 = litoy;
+ fixed t;
+
+#define slop int2fixed(2)
+ if (x0 > x1)
+ t = x0, x0 = x1 - slop, x1 = t + slop;
+ else
+ x0 -= slop, x1 += slop;
+ if (y0 > y1)
+ t = y0, y0 = y1 - slop, y1 = t + slop;
+ else
+ y0 -= slop, y1 += slop;
+#undef slop
+
+ if (pbbox->p.x <= x0 && x1 <= pbbox->q.x &&
+ pbbox->p.y <= y0 && y1 <= pbbox->q.y
+ )
+ return (*dev_proc(dev, draw_thin_line)) (dev,
+ lix, liy, litox, litoy,
+ pdevc, pis->log_op);
+ /* We didn't set up the endpoint parameters before, */
+ /* because the line was thin. stroke_add will do this. */
+ }
+ /* Check for being able to fill directly. */
+ {
+ const gx_line_params *pgs_lp = gs_currentlineparams_inline(pis);
+ gs_line_cap cap = pgs_lp->cap;
+ gs_line_join join = pgs_lp->join;
+
+ if (!plp->thin && (nplp == 0 || !nplp->thin)
+ && ((first != 0 && nplp != 0) || cap == gs_cap_butt
+ || cap == gs_cap_square)
+ && (join == gs_join_bevel || join == gs_join_miter ||
+ join == gs_join_none)
+ && (pis->fill_adjust.x | pis->fill_adjust.y) == 0
+ && lop_is_idempotent(pis->log_op)
+ ) {
+ gs_fixed_point points[6];
+ int npoints, code;
+
+ npoints = cap_points((first == 0 ? cap : gs_cap_butt),
+ &plp->o, points);
+ if (nplp == 0)
+ code = cap_points(cap, &plp->e, points + npoints);
+ else
+ code = line_join_points(pgs_lp, plp, nplp, points + npoints,
+ (uniform ? (gs_matrix *) 0 :
+ &ctm_only(pis)));
+ if (code < 0)
+ return code;
+ if (nplp != 0) {
+ if (join == gs_join_miter) {
+ /* Make sure we have a bevel and not a miter. */
+ if (!(points[2].x == plp->e.co.x &&
+ points[2].y == plp->e.co.y &&
+ points[5].x == plp->e.ce.x &&
+ points[5].y == plp->e.ce.y)
+ )
+ goto fill;
+ } {
+ const gs_fixed_point *bevel = points + 2;
+
+ /* Identify which 3 points define the bevel triangle. */
+ if (points[3].x == nplp->o.p.x &&
+ points[3].y == nplp->o.p.y
+ )
+ ++bevel;
+ /* Fill the bevel. */
+ code = (*dev_proc(dev, fill_triangle)) (dev,
+ bevel->x, bevel->y,
+ bevel[1].x - bevel->x, bevel[1].y - bevel->y,
+ bevel[2].x - bevel->x, bevel[2].y - bevel->y,
+ pdevc, pis->log_op);
+ if (code < 0)
+ return code;
+ }
+ }
+ /* Fill the body of the stroke. */
+ return (*dev_proc(dev, fill_parallelogram)) (dev,
+ points[1].x, points[1].y,
+ points[0].x - points[1].x,
+ points[0].y - points[1].y,
+ points[2].x - points[1].x,
+ points[2].y - points[1].y,
+ pdevc, pis->log_op);
+ fill:
+ code = add_points(ppath, points, npoints + code, true);
+ if (code < 0)
+ return code;
+ return gx_path_close_subpath(ppath);
+ }
+ }
+ /* General case: construct a path for the fill algorithm. */
+ return stroke_add(ppath, first, plp, nplp, pdevc, dev, pis, params,
+ pbbox, uniform);
+}
+
+/* Add a segment to the path. This handles all the complex cases. */
+private int
+stroke_add(gx_path * ppath, int first, register pl_ptr plp, pl_ptr nplp,
+const gx_device_color * pdevc, gx_device * dev, const gs_imager_state * pis,
+ const gx_stroke_params * params, const gs_fixed_rect * ignore_pbbox,
+ int uniform)
+{
+ const gx_line_params *pgs_lp = gs_currentlineparams_inline(pis);
+ gs_fixed_point points[8];
+ int npoints;
+ int code;
+ bool moveto_first = true;
+
+ if (plp->thin) {
+ /* We didn't set up the endpoint parameters before, */
+ /* because the line was thin. Do it now. */
+ set_thin_widths(plp);
+ adjust_stroke(plp, pis, true);
+ compute_caps(plp);
+ }
+ /* Create an initial cap if desired. */
+ if (first == 0 && pgs_lp->cap == gs_cap_round) {
+ if ((code = gx_path_add_point(ppath, plp->o.co.x, plp->o.co.y)) < 0 ||
+ (code = add_round_cap(ppath, &plp->o)) < 0
+ )
+ return code;
+ npoints = 0;
+ moveto_first = false;
+ } else {
+ if ((npoints = cap_points((first == 0 ? pgs_lp->cap : gs_cap_butt), &plp->o, points)) < 0)
+ return npoints;
+ }
+ if (nplp == 0) {
+ /* Add a final cap. */
+ if (pgs_lp->cap == gs_cap_round) {
+ ASSIGN_POINT(&points[npoints], plp->e.co);
+ ++npoints;
+ if ((code = add_points(ppath, points, npoints, moveto_first)) < 0)
+ return code;
+ code = add_round_cap(ppath, &plp->e);
+ goto done;
+ }
+ code = cap_points(pgs_lp->cap, &plp->e, points + npoints);
+ } else if (pgs_lp->join == gs_join_round) {
+ ASSIGN_POINT(&points[npoints], plp->e.co);
+ ++npoints;
+ if ((code = add_points(ppath, points, npoints, moveto_first)) < 0)
+ return code;
+ code = add_round_cap(ppath, &plp->e);
+ goto done;
+ } else if (nplp->thin) /* no join */
+ code = cap_points(gs_cap_butt, &plp->e, points + npoints);
+ else /* non-round join */
+ code = line_join_points(pgs_lp, plp, nplp, points + npoints,
+ (uniform ? (gs_matrix *) 0 : &ctm_only(pis)));
+ if (code < 0)
+ return code;
+ code = add_points(ppath, points, npoints + code, moveto_first);
+ done:
+ if (code < 0)
+ return code;
+ return gx_path_close_subpath(ppath);
+}
+
+/* Add lines with a possible initial moveto. */
+private int
+add_points(gx_path * ppath, const gs_fixed_point * points, int npoints,
+ bool moveto_first)
+{
+ if (moveto_first) {
+ int code = gx_path_add_point(ppath, points[0].x, points[0].y);
+
+ if (code < 0)
+ return code;
+ return gx_path_add_lines(ppath, points + 1, npoints - 1);
+ } else
+ return gx_path_add_lines(ppath, points, npoints);
+}
+
+/* ---------------- Join computation ---------------- */
+
+/* Compute the points for a bevel, miter, or triangle join. */
+/* Treat no join the same as a bevel join. */
+/* If pmat != 0, we must inverse-transform the distances for */
+/* the miter check. */
+private int
+line_join_points(const gx_line_params * pgs_lp, pl_ptr plp, pl_ptr nplp,
+ gs_fixed_point * join_points, const gs_matrix * pmat)
+{
+ gs_line_join join = pgs_lp->join;
+
+#define jp1 join_points[0]
+#define np1 join_points[1]
+#define np2 join_points[2]
+#define jp2 join_points[3]
+#define jpx join_points[4]
+ /*
+ * Set np to whichever of nplp->o.co or .ce is outside
+ * the current line. We observe that the point (x2,y2)
+ * is counter-clockwise from (x1,y1), relative to the origin,
+ * iff
+ * (arctan(y2/x2) - arctan(y1/x1)) mod 2*pi < pi,
+ * taking the signs of xi and yi into account to determine
+ * the quadrants of the results. It turns out that
+ * even though arctan is monotonic only in the 4th/1st
+ * quadrants and the 2nd/3rd quadrants, case analysis on
+ * the signs of xi and yi demonstrates that this test
+ * is equivalent to the much less expensive test
+ * x1 * y2 > x2 * y1
+ * in all cases.
+ *
+ * In the present instance, x1,y1 are plp->width,
+ * x2,y2 are nplp->width, and the origin is
+ * their common point (plp->e.p, nplp->o.p).
+ * ccw will be true iff nplp.o.co (nplp.o.p + width) is
+ * counter-clockwise from plp.e.ce (plp.e.p + width),
+ * in which case we want tan(a-b) rather than tan(b-a).
+ *
+ * We make the test using double arithmetic only because
+ * the !@#&^*% C language doesn't give us access to
+ * the double-width-result multiplication operation
+ * that almost all CPUs provide!
+ */
+ bool ccw =
+ (double)(plp->width.x) * /* x1 */
+ (nplp->width.y) > /* y2 */
+ (double)(nplp->width.x) * /* x2 */
+ (plp->width.y);
+ p_ptr outp, np;
+
+ /* Initialize for a bevel join. */
+ ASSIGN_POINT(&jp1, plp->e.co);
+ ASSIGN_POINT(&jp2, plp->e.ce);
+
+ /*
+ * Because of stroke adjustment, it is possible that
+ * plp->e.p != nplp->o.p. For that reason, we must use
+ * nplp->o.p as np1 or np2.
+ */
+ if (!ccw) {
+ outp = &jp2;
+ ASSIGN_POINT(&np2, nplp->o.co);
+ ASSIGN_POINT(&np1, nplp->o.p);
+ np = &np2;
+ } else {
+ outp = &jp1;
+ ASSIGN_POINT(&np1, nplp->o.ce);
+ ASSIGN_POINT(&np2, nplp->o.p);
+ np = &np1;
+ }
+ if_debug1('O', "[o]use %s\n", (ccw ? "co (ccw)" : "ce (cw)"));
+
+ /* Handle triangular joins now. */
+ if (join == gs_join_triangle) {
+ fixed tpx = outp->x - nplp->o.p.x + np->x;
+ fixed tpy = outp->y - nplp->o.p.y + np->y;
+
+ ASSIGN_POINT(&jpx, jp2);
+ if (!ccw) {
+ /* Insert tp between np2 and jp2. */
+ jp2.x = tpx, jp2.y = tpy;
+ } else {
+ /* Insert tp between jp1 and np1. */
+ ASSIGN_POINT(&jp2, np2);
+ ASSIGN_POINT(&np2, np1);
+ np1.x = tpx, np1.y = tpy;
+ }
+ return 5;
+ }
+ /*
+ * Don't bother with the miter check if the two
+ * points to be joined are very close together,
+ * namely, in the same square half-pixel.
+ */
+ if (join == gs_join_miter &&
+ !(fixed2long(outp->x << 1) == fixed2long(np->x << 1) &&
+ fixed2long(outp->y << 1) == fixed2long(np->y << 1))
+ ) {
+ /*
+ * Check whether a miter join is appropriate.
+ * Let a, b be the angles of the two lines.
+ * We check tan(a-b) against the miter_check
+ * by using the following formula:
+ * If tan(a)=u1/v1 and tan(b)=u2/v2, then
+ * tan(a-b) = (u1*v2 - u2*v1) / (u1*u2 + v1*v2).
+ *
+ * We can do all the computations unscaled,
+ * because we're only concerned with ratios.
+ * However, if we have a non-uniform coordinate
+ * system (indicated by pmat != 0), we must do the
+ * computations in user space.
+ */
+ float check = pgs_lp->miter_check;
+ double u1 = plp->e.cdelta.y, v1 = plp->e.cdelta.x;
+ double u2 = nplp->o.cdelta.y, v2 = nplp->o.cdelta.x;
+ double num, denom;
+
+ if (pmat) {
+ gs_point pt;
+
+ gs_distance_transform_inverse(v1, u1, pmat, &pt);
+ v1 = pt.x, u1 = pt.y;
+ gs_distance_transform_inverse(v2, u2, pmat, &pt);
+ v2 = pt.x, u2 = pt.y;
+ /*
+ * We need to recompute ccw according to the
+ * relative positions of the lines in user space.
+ * We repeat the computation described above,
+ * using the cdelta values instead of the widths.
+ * Because the definition of ccw above is inverted
+ * from the intuitive one (for historical reasons),
+ * we actually have to do the test backwards.
+ */
+ ccw = v1 * u2 < v2 * u1;
+#ifdef DEBUG
+ {
+ double a1 = atan2(u1, v1), a2 = atan2(u2, v2), dif = a1 - a2;
+
+ if (dif < 0)
+ dif += 2 * M_PI;
+ else if (dif >= 2 * M_PI)
+ dif -= 2 * M_PI;
+ if (dif != 0 && (dif < M_PI) != ccw)
+ lprintf8("ccw wrong: tan(a1=%g)=%g/%g, tan(a2=%g)=%g,%g, dif=%g, ccw=%d\n",
+ a1, u1, v1, a2, u2, v2, dif, ccw);
+ }
+#endif
+ }
+ num = u1 * v2 - u2 * v1;
+ denom = u1 * u2 + v1 * v2;
+ /*
+ * We will want either tan(a-b) or tan(b-a)
+ * depending on the orientations of the lines.
+ * Fortunately we know the relative orientations already.
+ */
+ if (!ccw) /* have plp - nplp, want vice versa */
+ num = -num;
+#ifdef DEBUG
+ if (gs_debug_c('O')) {
+ dlprintf4("[o]Miter check: u1/v1=%f/%f, u2/v2=%f/%f,\n",
+ u1, v1, u2, v2);
+ dlprintf3(" num=%f, denom=%f, check=%f\n",
+ num, denom, check);
+ }
+#endif
+ /*
+ * If we define T = num / denom, then we want to use
+ * a miter join iff arctan(T) >= arctan(check).
+ * We know that both of these angles are in the 1st
+ * or 2nd quadrant, and since arctan is monotonic
+ * within each quadrant, we can do the comparisons
+ * on T and check directly, taking signs into account
+ * as follows:
+ * sign(T) sign(check) atan(T) >= atan(check)
+ * ------- ----------- ----------------------
+ * + + T >= check
+ * - + true
+ * + - false
+ * - - T >= check
+ */
+ if (denom < 0)
+ num = -num, denom = -denom;
+ /* Now denom >= 0, so sign(num) = sign(T). */
+ if (check > 0 ?
+ (num < 0 || num >= denom * check) :
+ (num < 0 && num >= denom * check)
+ ) {
+ /* OK to use a miter join. */
+ gs_fixed_point mpt;
+
+ if_debug0('O', " ... passes.\n");
+ /* Compute the intersection of */
+ /* the extended edge lines. */
+ if (line_intersect(outp, &plp->e.cdelta, np,
+ &nplp->o.cdelta, &mpt) == 0
+ )
+ ASSIGN_POINT(outp, mpt);
+ }
+ }
+ return 4;
+}
+/* ---------------- Cap computations ---------------- */
+
+/* Compute the endpoints of the two caps of a segment. */
+/* Only o.p, e.p, width, and cdelta have been set. */
+private void
+compute_caps(register pl_ptr plp)
+{
+ fixed wx2 = plp->width.x;
+ fixed wy2 = plp->width.y;
+
+ plp->o.co.x = plp->o.p.x + wx2, plp->o.co.y = plp->o.p.y + wy2;
+ plp->o.cdelta.x = -plp->e.cdelta.x,
+ plp->o.cdelta.y = -plp->e.cdelta.y;
+ plp->o.ce.x = plp->o.p.x - wx2, plp->o.ce.y = plp->o.p.y - wy2;
+ plp->e.co.x = plp->e.p.x - wx2, plp->e.co.y = plp->e.p.y - wy2;
+ plp->e.ce.x = plp->e.p.x + wx2, plp->e.ce.y = plp->e.p.y + wy2;
+#ifdef DEBUG
+ if (gs_debug_c('O')) {
+ dlprintf4("[o]Stroke o=(%f,%f) e=(%f,%f)\n",
+ fixed2float(plp->o.p.x), fixed2float(plp->o.p.y),
+ fixed2float(plp->e.p.x), fixed2float(plp->e.p.y));
+ dlprintf4("\twxy=(%f,%f) lxy=(%f,%f)\n",
+ fixed2float(wx2), fixed2float(wy2),
+ fixed2float(plp->e.cdelta.x),
+ fixed2float(plp->e.cdelta.y));
+ }
+#endif
+}
+
+#define px endp->p.x
+#define py endp->p.y
+#define xo endp->co.x
+#define yo endp->co.y
+#define xe endp->ce.x
+#define ye endp->ce.y
+#define cdx endp->cdelta.x
+#define cdy endp->cdelta.y
+
+/* Add a round cap to a path. */
+/* Assume the current point is the cap origin (endp->co). */
+private int
+add_round_cap(gx_path * ppath, const_ep_ptr endp)
+{
+ fixed xm = px + cdx;
+ fixed ym = py + cdy;
+ int code;
+
+ if ((code = gx_path_add_partial_arc(ppath, xm, ym,
+ xo + cdx, yo + cdy, quarter_arc_fraction)) < 0 ||
+ (code = gx_path_add_partial_arc(ppath, xe, ye,
+ xe + cdx, ye + cdy, quarter_arc_fraction)) < 0
+ )
+ return code;
+ return 0;
+}
+
+/* Compute the points for a non-round cap. */
+/* Return the number of points. */
+private int
+cap_points(gs_line_cap type, const_ep_ptr endp,
+ gs_fixed_point * pts /* [3] */ )
+{
+#define PUT_POINT(i, px, py)\
+ pts[i].x = (px), pts[i].y = (py)
+ switch (type) {
+ case gs_cap_butt:
+ PUT_POINT(0, xo, yo);
+ PUT_POINT(1, xe, ye);
+ return 2;
+ case gs_cap_square:
+ PUT_POINT(0, xo + cdx, yo + cdy);
+ PUT_POINT(1, xe + cdx, ye + cdy);
+ return 2;
+ case gs_cap_triangle: /* (not supported by PostScript) */
+ PUT_POINT(0, xo, yo);
+ PUT_POINT(1, px + cdx, py + cdy);
+ PUT_POINT(2, xe, ye);
+ return 3;
+ default: /* can't happen */
+ return_error(gs_error_unregistered);
+ }
+#undef PUT_POINT
+}
diff --git a/pstoraster/gxsync.h b/pstoraster/gxsync.h
new file mode 100644
index 000000000..9f6446a68
--- /dev/null
+++ b/pstoraster/gxsync.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 synchronization primitives */
+
+/* Initial version 2/1/98 by John Desrosiers (soho@crl.com) */
+
+#if !defined(gxsync_INCLUDED)
+ #define gxsync_INCLUDED
+
+#include "gpsync.h"
+#include "gsmemory.h"
+
+/* This module abstracts the platform-specific synchronization primitives. */
+/* Since these routines will see heavy use, performance is important. */
+
+/* ----- Semaphore interface ----- */
+/* These have the usual queued, counting semaphore semantics: at init time, */
+/* the event count is set to 0 ('wait' will wait until 1st signal). */
+typedef struct gx_semaphore_s {
+ gs_memory_t *memory; /* allocator to free memory */
+ gp_semaphore native; /* MUST BE LAST last since length is undef'd */
+ /* platform-dep impl, len is gp_semaphore_sizeof() */
+} gx_semaphore_t;
+
+gx_semaphore_t * /* returns a new semaphore, 0 if error */
+ gx_semaphore_alloc(P1(
+ gs_memory_t * memory /* memory allocator to use */
+ ));
+void
+ gx_semaphore_free(P1(
+ gx_semaphore_t * sema /* semaphore to delete */
+ ));
+
+ #define gx_semaphore_wait(sema) gp_semaphore_wait(&(sema)->native)
+ #define gx_semaphore_signal(sema) gp_semaphore_signal(&(sema)->native)
+
+
+/* ----- Monitor interface ----- */
+/* These have the usual monitor semantics: at init time, */
+/* the event count is set to 1 (1st 'enter' succeeds immediately). */
+typedef struct gx_monitor_s {
+ gs_memory_t *memory; /* allocator to free memory */
+ gp_monitor native; /* platform-dep impl, len is gp_monitor_sizeof() */
+} gx_monitor_t;
+
+gx_monitor_t * /* returns a new monitor, 0 if error */
+ gx_monitor_alloc(P1(
+ gs_memory_t * memory /* memory allocator to use */
+ ));
+void
+ gx_monitor_free(P1(
+ gx_monitor_t * mon /* monitor to delete */
+ ));
+
+ #define gx_monitor_enter(sema) gp_monitor_enter(&(sema)->native)
+ #define gx_monitor_leave(sema) gp_monitor_leave(&(sema)->native)
+
+#endif /* !defined(gxsync_INCLUDED) */
diff --git a/pstoraster/gxtext.h b/pstoraster/gxtext.h
new file mode 100644
index 000000000..d1d51e314
--- /dev/null
+++ b/pstoraster/gxtext.h
@@ -0,0 +1,121 @@
+/* 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$ */
+/* Driver text interface implementation support */
+
+#ifndef gxtext_INCLUDED
+# define gxtext_INCLUDED
+
+#include "gstext.h"
+
+/* EVERYTHING IN THIS FILE IS SUBJECT TO CHANGE WITHOUT NOTICE. */
+
+/*
+ * Define the control parameter for setting text metrics.
+ */
+typedef enum {
+ TEXT_SET_CHAR_WIDTH,
+ TEXT_SET_CACHE_DEVICE,
+ TEXT_SET_CACHE_DEVICE2
+} gs_text_cache_control_t;
+
+/*
+ * Define the procedures associated with text display.
+ */
+struct gs_text_enum_procs_s {
+
+ /*
+ * Process the text. Then client should call this repeatedly until
+ * it returns <= 0. (> 0 means the client must intervene.)
+ */
+
+#define text_enum_proc_process(proc)\
+ int proc(P1(gs_text_enum_t *penum))
+
+ text_enum_proc_process((*process));
+
+ /*
+ * Set the character width and optionally bounding box,
+ * and enable caching.
+ */
+
+#define text_enum_proc_set_cache(proc)\
+ int proc(P3(gs_text_enum_t *penum, const double *values,\
+ gs_text_cache_control_t control))
+
+ text_enum_proc_set_cache((*set_cache));
+
+};
+
+/* Abstract types */
+#ifndef gs_imager_state_DEFINED
+# define gs_imager_state_DEFINED
+typedef struct gs_imager_state_s gs_imager_state;
+
+#endif
+#ifndef gx_device_color_DEFINED
+# define gx_device_color_DEFINED
+typedef struct gx_device_color_s gx_device_color;
+
+#endif
+#ifndef gs_font_DEFINED
+# define gs_font_DEFINED
+typedef struct gs_font_s gs_font;
+
+#endif
+#ifndef gx_path_DEFINED
+# define gx_path_DEFINED
+typedef struct gx_path_s gx_path;
+
+#endif
+#ifndef gx_clip_path_DEFINED
+# define gx_clip_path_DEFINED
+typedef struct gx_clip_path_s gx_clip_path;
+
+#endif
+
+/*
+ * Define the driver procedure for text.
+ */
+#define dev_t_proc_text_begin(proc, dev_t)\
+ int proc(P9(dev_t *dev,\
+ gs_imager_state *pis,\
+ const gs_text_params_t *text,\
+ const gs_font *font,\
+ gx_path *path, /* unless DO_NONE & !RETURN_WIDTH */\
+ const gx_device_color *pdcolor, /* DO_DRAW */\
+ const gx_clip_path *pcpath, /* DO_DRAW */\
+ gs_memory_t *memory,\
+ gs_text_enum_t **ppenum))
+#define dev_proc_text_begin(proc)\
+ dev_t_proc_text_begin(proc, gx_device)
+
+/*
+ * Begin processing text. This calls the device procedure, and also
+ * initializes the common parts of the enumerator.
+ */
+dev_proc_text_begin(gx_device_text_begin);
+
+#endif /* gxtext_INCLUDED */
diff --git a/pstoraster/gxtmap.h b/pstoraster/gxtmap.h
new file mode 100644
index 000000000..bb5c0b29e
--- /dev/null
+++ b/pstoraster/gxtmap.h
@@ -0,0 +1,58 @@
+/* Copyright (C) 1994, 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 transfer mapping function */
+/* (also used for black generation and undercolor removal) */
+
+#ifndef gxtmap_INCLUDED
+# define gxtmap_INCLUDED
+
+/* Common definition for mapping procedures. */
+/* These are used for transfer functions, black generation, */
+/* and undercolor removal. */
+/* gx_transfer_map should probably be renamed gx_mapping_cache.... */
+
+/* Define an abstract type for a transfer map. */
+typedef struct gx_transfer_map_s gx_transfer_map;
+
+/*
+ * Define the type of a mapping procedure. There are two forms of this.
+ * The original form passed only the transfer map itself as an argument:
+ */
+typedef float (*gs_mapping_proc) (P2(floatp, const gx_transfer_map *));
+
+/*
+ * Later, we recognized that this procedure should really be a general
+ * closure:
+ */
+typedef float (*gs_mapping_closure_proc_t) (P3(floatp value,
+ const gx_transfer_map * pmap,
+ const void *proc_data));
+typedef struct gs_mapping_closure_s {
+ gs_mapping_closure_proc_t proc;
+ const void *data;
+} gs_mapping_closure_t;
+
+#endif /* gxtmap_INCLUDED */
diff --git a/pstoraster/gxtype1.c b/pstoraster/gxtype1.c
new file mode 100644
index 000000000..fccd3c0e3
--- /dev/null
+++ b/pstoraster/gxtype1.c
@@ -0,0 +1,518 @@
+/* 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$ */
+/* Adobe Type 1 font interpreter support */
+#include "math_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsccode.h"
+#include "gsline.h"
+#include "gsstruct.h"
+#include "gxarith.h"
+#include "gxfixed.h"
+#include "gxistate.h"
+#include "gxmatrix.h"
+#include "gxcoord.h"
+#include "gxfont.h"
+#include "gxfont1.h"
+#include "gxtype1.h"
+#include "gzpath.h"
+
+/*
+ * The routines in this file are used for both Type 1 and Type 2
+ * charstring interpreters.
+ */
+
+/*
+ * Define whether or not to force hints to "big pixel" boundaries
+ * when rasterizing at higher resolution. With the current algorithms,
+ * a value of 1 is better for devices without alpha capability,
+ * but 0 is better if alpha is available.
+ */
+#define FORCE_HINTS_TO_BIG_PIXELS 1
+
+/* Structure descriptor */
+public_st_gs_font_type1();
+
+/* Encrypt a string. */
+int
+gs_type1_encrypt(byte * dest, const byte * src, uint len, crypt_state * pstate)
+{
+ register crypt_state state = *pstate;
+ register const byte *from = src;
+ register byte *to = dest;
+ register uint count = len;
+
+ while (count) {
+ encrypt_next(*from, state, *to);
+ from++, to++, count--;
+ }
+ *pstate = state;
+ return 0;
+}
+/* Decrypt a string. */
+int
+gs_type1_decrypt(byte * dest, const byte * src, uint len, crypt_state * pstate)
+{
+ register crypt_state state = *pstate;
+ register const byte *from = src;
+ register byte *to = dest;
+ register uint count = len;
+
+ while (count) { /* If from == to, we can't use the obvious */
+ /* decrypt_next(*from, state, *to); */
+ register byte ch = *from++;
+
+ decrypt_next(ch, state, *to);
+ to++, count--;
+ }
+ *pstate = state;
+ return 0;
+}
+
+/* Define the structure type for a Type 1 interpreter state. */
+public_st_gs_type1_state();
+/* GC procedures */
+#define pcis ((gs_type1_state *)vptr)
+private
+ENUM_PTRS_BEGIN(gs_type1_state_enum_ptrs)
+{
+ if (index < pcis->ips_count + 3) {
+ ENUM_RETURN_CONST_STRING_PTR(gs_type1_state,
+ ipstack[index - 3].char_string);
+ }
+ return 0;
+}
+ENUM_PTR(0, gs_type1_state, pfont);
+ENUM_PTR(1, gs_type1_state, pis);
+ENUM_PTR(2, gs_type1_state, path);
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(gs_type1_state_reloc_ptrs)
+{
+ int i;
+
+ RELOC_PTR(gs_type1_state, pfont);
+ RELOC_PTR(gs_type1_state, pis);
+ RELOC_PTR(gs_type1_state, path);
+ for (i = 0; i < pcis->ips_count; i++) {
+ ip_state *ipsp = &pcis->ipstack[i];
+ int diff = ipsp->ip - ipsp->char_string.data;
+
+ RELOC_CONST_STRING_VAR(ipsp->char_string);
+ ipsp->ip = ipsp->char_string.data + diff;
+ }
+} RELOC_PTRS_END
+#undef pcis
+
+/* ------ Interpreter entry point ------ */
+
+private int
+gs_no_charstring_interpret(gs_type1_state * pcis, const gs_const_string * str,
+ int *pindex)
+{
+ return_error(gs_error_rangecheck);
+}
+int (*gs_charstring_interpreter[3])
+ (P3(gs_type1_state * pcis, const gs_const_string * str, int *pindex)) = {
+ gs_no_charstring_interpret,
+ gs_no_charstring_interpret,
+ gs_no_charstring_interpret
+};
+
+/*
+ * Continue interpreting a Type 1 charstring. If str != 0, it is taken as
+ * the byte string to interpret. Return 0 on successful completion, <0 on
+ * error, or >0 when client intervention is required (or allowed). The int*
+ * argument is where the othersubr # is stored for callothersubr.
+ */
+int
+gs_type1_interpret(gs_type1_state * pcis, const gs_const_string * str,
+ int *pindex)
+{
+ return (*gs_charstring_interpreter[pcis->pfont->data.CharstringType])
+ (pcis, str, pindex);
+}
+
+/* ------ Interpreter services ------ */
+
+#define s (*ps)
+
+/* We export this for the Type 2 charstring interpreter. */
+void
+accum_xy_proc(register is_ptr ps, fixed dx, fixed dy)
+{
+ ptx += c_fixed(dx, xx),
+ pty += c_fixed(dy, yy);
+ if (sfc.skewed)
+ ptx += c_fixed(dy, yx),
+ pty += c_fixed(dx, xy);
+}
+
+/* Initialize a Type 1 interpreter. */
+/* The caller must supply a string to the first call of gs_type1_interpret. */
+int
+gs_type1_interp_init(register gs_type1_state * pcis, gs_imager_state * pis,
+ gx_path * ppath, const gs_log2_scale_point * pscale, bool charpath_flag,
+ int paint_type, gs_font_type1 * pfont)
+{
+ static const gs_log2_scale_point no_scale =
+ {0, 0};
+ const gs_log2_scale_point *plog2_scale =
+ (FORCE_HINTS_TO_BIG_PIXELS ? pscale : &no_scale);
+
+ pcis->pfont = pfont;
+ pcis->pis = pis;
+ pcis->path = ppath;
+ /*
+ * charpath_flag controls coordinate rounding, hinting, and
+ * flatness enhancement. If we allow it to be set to true,
+ * charpath may produce results quite different from show.
+ */
+ pcis->charpath_flag = false /*charpath_flag */ ;
+ pcis->paint_type = paint_type;
+ pcis->os_count = 0;
+ pcis->ips_count = 1;
+ pcis->ipstack[0].ip = 0;
+ pcis->ipstack[0].char_string.data = 0;
+ pcis->ipstack[0].char_string.size = 0;
+ pcis->ignore_pops = 0;
+ pcis->init_done = -1;
+ pcis->sb_set = false;
+ pcis->width_set = false;
+ pcis->have_hintmask = false;
+ pcis->num_hints = 0;
+ pcis->seac_accent = -1;
+
+ /* Set the sampling scale. */
+ set_pixel_scale(&pcis->scale.x, plog2_scale->x);
+ set_pixel_scale(&pcis->scale.y, plog2_scale->y);
+
+ return 0;
+}
+/* Preset the left side bearing and/or width. */
+void
+gs_type1_set_lsb(gs_type1_state * pcis, const gs_point * psbpt)
+{
+ pcis->lsb.x = float2fixed(psbpt->x);
+ pcis->lsb.y = float2fixed(psbpt->y);
+ pcis->sb_set = true;
+}
+void
+gs_type1_set_width(gs_type1_state * pcis, const gs_point * pwpt)
+{
+ pcis->width.x = float2fixed(pwpt->x);
+ pcis->width.y = float2fixed(pwpt->y);
+ pcis->width_set = true;
+}
+/* Finish initializing the interpreter if we are actually rasterizing */
+/* the character, as opposed to just computing the side bearing and width. */
+void
+gs_type1_finish_init(gs_type1_state * pcis, gs_op1_state * ps)
+{
+ gs_imager_state *pis = pcis->pis;
+
+ /* Set up the fixed version of the transformation. */
+ gx_matrix_to_fixed_coeff(&ctm_only(pis), &pcis->fc, max_coeff_bits);
+ sfc = pcis->fc;
+
+ /* Set the current point of the path to the origin, */
+ /* in anticipation of the initial [h]sbw. */
+ {
+ gx_path *ppath = pcis->path;
+
+ ptx = pcis->origin.x = ppath->position.x;
+ pty = pcis->origin.y = ppath->position.y;
+ }
+
+ /* Initialize hint-related scalars. */
+ pcis->asb_diff = pcis->adxy.x = pcis->adxy.y = 0;
+ pcis->flex_count = flex_max; /* not in Flex */
+ pcis->dotsection_flag = dotsection_out;
+ pcis->vstem3_set = false;
+ pcis->vs_offset.x = pcis->vs_offset.y = 0;
+ pcis->hints_initial = 0; /* probably not needed */
+ pcis->hint_next = 0;
+ pcis->hints_pending = 0;
+
+ /* Assimilate the hints proper. */
+ {
+ gs_log2_scale_point log2_scale;
+
+ log2_scale.x = pcis->scale.x.log2_unit;
+ log2_scale.y = pcis->scale.y.log2_unit;
+ if (pcis->charpath_flag)
+ reset_font_hints(&pcis->fh, &log2_scale);
+ else
+ compute_font_hints(&pcis->fh, &pis->ctm, &log2_scale,
+ &pcis->pfont->data);
+ }
+ reset_stem_hints(pcis);
+
+ /*
+ * Set the flatness to a value that is likely to produce reasonably
+ * good-looking curves, regardless of its current value in the
+ * graphics state. If the character is very small, set the flatness
+ * to zero, which will produce very accurate curves.
+ */
+ {
+ float cxx = fabs(pis->ctm.xx), cyy = fabs(pis->ctm.yy);
+
+ if (cyy < cxx)
+ cxx = cyy;
+ if (!is_xxyy(&pis->ctm)) {
+ float cxy = fabs(pis->ctm.xy), cyx = fabs(pis->ctm.yx);
+
+ if (cxy < cxx)
+ cxx = cxy;
+ if (cyx < cxx)
+ cxx = cyx;
+ }
+ /* Don't let the flatness be worse than the default. */
+ if (cxx > pis->flatness)
+ cxx = pis->flatness;
+ /* If the character is tiny, force accurate curves. */
+ if (cxx < 0.2)
+ cxx = 0;
+ pcis->flatness = cxx;
+ }
+
+ /* Move to the side bearing point. */
+ accum_xy(pcis->lsb.x, pcis->lsb.y);
+ pcis->position.x = ptx;
+ pcis->position.y = pty;
+
+ pcis->init_done = 1;
+}
+
+/* ------ Operator procedures ------ */
+
+/* We put these before the interpreter to save having to write */
+/* prototypes for all of them. */
+
+int
+gs_op1_closepath(register is_ptr ps)
+{ /* Note that this does NOT reset the current point! */
+ gx_path *ppath = sppath;
+ subpath *psub;
+ segment *pseg;
+ fixed dx, dy;
+ int code;
+
+ /* Check for and suppress a microscopic closing line. */
+ if ((psub = ppath->current_subpath) != 0 &&
+ (pseg = psub->last) != 0 &&
+ (dx = pseg->pt.x - psub->pt.x,
+ any_abs(dx) < float2fixed(0.1)) &&
+ (dy = pseg->pt.y - psub->pt.y,
+ any_abs(dy) < float2fixed(0.1))
+ )
+ switch (pseg->type) {
+ case s_line:
+ code = gx_path_pop_close_subpath(sppath);
+ break;
+ case s_curve:
+ /*
+ * Unfortunately, there is no "s_curve_close". (Maybe there
+ * should be?) Just adjust the final point of the curve so it
+ * is identical to the closing point.
+ */
+ pseg->pt = psub->pt;
+#define pcseg ((curve_segment *)pseg)
+ pcseg->p2.x -= dx;
+ pcseg->p2.y -= dy;
+#undef pcseg
+ /* falls through */
+ default:
+ /* What else could it be?? */
+ code = gx_path_close_subpath(sppath);
+ } else
+ code = gx_path_close_subpath(sppath);
+ if (code < 0)
+ return code;
+ return gx_path_add_point(ppath, ptx, pty); /* put the point where it was */
+}
+
+int
+gs_op1_rrcurveto(register is_ptr ps, fixed dx1, fixed dy1,
+ fixed dx2, fixed dy2, fixed dx3, fixed dy3)
+{
+ gs_fixed_point pt1, pt2;
+ fixed ax0 = sppath->position.x - ptx;
+ fixed ay0 = sppath->position.y - pty;
+
+ accum_xy(dx1, dy1);
+ pt1.x = ptx + ax0, pt1.y = pty + ay0;
+ accum_xy(dx2, dy2);
+ pt2.x = ptx, pt2.y = pty;
+ accum_xy(dx3, dy3);
+ return gx_path_add_curve(sppath, pt1.x, pt1.y, pt2.x, pt2.y, ptx, pty);
+}
+
+#undef s
+
+/* Record the side bearing and character width. */
+int
+gs_type1_sbw(gs_type1_state * pcis, fixed lsbx, fixed lsby, fixed wx, fixed wy)
+{
+ if (!pcis->sb_set)
+ pcis->lsb.x = lsbx, pcis->lsb.y = lsby,
+ pcis->sb_set = true; /* needed for accented chars */
+ if (!pcis->width_set)
+ pcis->width.x = wx, pcis->width.y = wy,
+ pcis->width_set = true;
+ if_debug4('1', "[1]sb=(%g,%g) w=(%g,%g)\n",
+ fixed2float(pcis->lsb.x), fixed2float(pcis->lsb.y),
+ fixed2float(pcis->width.x), fixed2float(pcis->width.y));
+ return 0;
+}
+
+/*
+ * Handle a seac. Do the base character now; when it finishes (detected
+ * in endchar), do the accent. Note that we pass only 4 operands on the
+ * stack, and pass asb separately.
+ */
+int
+gs_type1_seac(gs_type1_state * pcis, const fixed * cstack, fixed asb,
+ ip_state * ipsp)
+{
+ gs_font_type1 *pfont = pcis->pfont;
+ gs_const_string bcstr;
+ int code;
+
+ /* Save away all the operands. */
+ pcis->seac_accent = fixed2int_var(cstack[3]);
+ pcis->save_asb = asb - pcis->lsb.x;
+ pcis->save_adxy.x = cstack[0];
+ pcis->save_adxy.y = cstack[1];
+ pcis->os_count = 0; /* clear */
+ /* Ask the caller to provide the base character's CharString. */
+ code = (*pfont->data.procs->seac_data)
+ (pfont, fixed2int_var(cstack[2]), &bcstr);
+ if (code != 0)
+ return code;
+ /* Continue with the supplied string. */
+ ipsp->char_string = bcstr;
+ return 0;
+}
+
+/*
+ * Handle the end of a character. Return 0 if this is really the end of a
+ * character, or 1 if we still have to process the accent of a seac.
+ * In the latter case, the interpreter control stack has been set up to
+ * point to the start of the accent's CharString; the caller must
+ * also set ptx/y to pcis->position.x/y.
+ */
+int
+gs_type1_endchar(gs_type1_state * pcis)
+{
+ gs_imager_state *pis = pcis->pis;
+ gx_path *ppath = pcis->path;
+
+ if (pcis->seac_accent >= 0) { /* We just finished the base character of a seac. */
+ /* Do the accent. */
+ gs_font_type1 *pfont = pcis->pfont;
+ gs_op1_state s;
+ gs_const_string astr;
+ int achar = pcis->seac_accent;
+ int code;
+
+ pcis->seac_accent = -1;
+ /* Reset the coordinate system origin */
+ sfc = pcis->fc;
+ ptx = pcis->origin.x, pty = pcis->origin.y;
+ pcis->asb_diff = pcis->save_asb;
+ pcis->adxy = pcis->save_adxy;
+ /*
+ * We're going to add in the lsb of the accented character when
+ * we encounter its [h]sbw, so don't do it now.
+ */
+ accum_xy(pcis->adxy.x, pcis->adxy.y);
+ ppath->position.x = pcis->position.x = ptx;
+ ppath->position.y = pcis->position.y = pty;
+ pcis->os_count = 0; /* clear */
+ /* Clear the ipstack, in case the base character */
+ /* ended inside a subroutine. */
+ pcis->ips_count = 1;
+ /* Remove any base character hints. */
+ reset_stem_hints(pcis);
+ /* Ask the caller to provide the accent's CharString. */
+ code = (*pfont->data.procs->seac_data) (pfont, achar, &astr);
+ if (code < 0)
+ return code;
+ /* Continue with the supplied string. */
+ pcis->ips_count = 1;
+ pcis->ipstack[0].char_string = astr;
+ return 1;
+ }
+ if (pcis->hint_next != 0 || path_is_drawing(ppath))
+ apply_path_hints(pcis, true);
+ /* Set the current point to the character origin */
+ /* plus the width. */
+ {
+ gs_fixed_point pt;
+
+ gs_point_transform2fixed(&pis->ctm,
+ fixed2float(pcis->width.x),
+ fixed2float(pcis->width.y),
+ &pt);
+ gx_path_add_point(ppath, pt.x, pt.y);
+ }
+ if (pcis->scale.x.log2_unit + pcis->scale.y.log2_unit == 0) { /*
+ * Tweak up the fill adjustment. This is a hack for when
+ * we can't oversample. The values here are based entirely
+ * on experience, not theory, and are designed primarily
+ * for displays and low-resolution fax.
+ */
+ gs_fixed_rect bbox;
+ int dx, dy, dmax;
+
+ gx_path_bbox(ppath, &bbox);
+ dx = fixed2int_ceiling(bbox.q.x - bbox.p.x);
+ dy = fixed2int_ceiling(bbox.q.y - bbox.p.y);
+ dmax = max(dx, dy);
+ if (pcis->fh.snap_h.count || pcis->fh.snap_v.count ||
+ pcis->fh.a_zone_count
+ ) { /* We have hints. Only tweak up a little at */
+ /* very small sizes, to help nearly-vertical */
+ /* or nearly-horizontal diagonals. */
+ pis->fill_adjust.x = pis->fill_adjust.y =
+ (dmax < 15 ? float2fixed(0.15) :
+ dmax < 25 ? float2fixed(0.1) :
+ fixed_0);
+ } else { /* No hints. Tweak a little more to compensate */
+ /* for lack of snapping to pixel grid. */
+ pis->fill_adjust.x = pis->fill_adjust.y =
+ (dmax < 10 ? float2fixed(0.2) :
+ dmax < 25 ? float2fixed(0.1) :
+ float2fixed(0.05));
+ }
+ } else { /* Don't do any adjusting. */
+ pis->fill_adjust.x = pis->fill_adjust.y = fixed_0;
+ }
+ /* Set the flatness for curve rendering. */
+ if (!pcis->charpath_flag)
+ gs_imager_setflat(pis, pcis->flatness);
+ return 0;
+}
diff --git a/pstoraster/gxtype1.h b/pstoraster/gxtype1.h
new file mode 100644
index 000000000..8e393741b
--- /dev/null
+++ b/pstoraster/gxtype1.h
@@ -0,0 +1,346 @@
+/* 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$ */
+/* Private Adobe Type 1 / Type 2 charstring interpreter definitions */
+
+#ifndef gxtype1_INCLUDED
+# define gxtype1_INCLUDED
+
+#include "gscrypt1.h"
+#include "gstype1.h"
+#include "gxop1.h"
+
+/* This file defines the structures for the state of a Type 1 / */
+/* Type 2 charstring interpreter. */
+
+/*
+ * Because of oversampling, one pixel in the Type 1 interpreter may
+ * correspond to several device pixels. This is also true of the hint data,
+ * since the CTM reflects the transformation to the oversampled space.
+ * To help keep the font level hints separated from the character level hints,
+ * we store the scaling factor separately with each set of hints.
+ */
+typedef struct pixel_scale_s {
+ fixed unit; /* # of pixels per device pixel */
+ fixed half; /* unit / 2 */
+ int log2_unit; /* log2(unit / fixed_1) */
+} pixel_scale;
+typedef struct point_scale_s {
+ pixel_scale x, y;
+} point_scale;
+
+#define set_pixel_scale(pps, log2)\
+ (pps)->unit = ((pps)->half = fixed_half << ((pps)->log2_unit = log2)) << 1
+#define scaled_rounded(v, pps)\
+ (((v) + (pps)->half) & -(pps)->unit)
+
+/* ------ Font level hints ------ */
+
+/* Define the standard stem width tables. */
+/* Each table is sorted, since the StemSnap arrays are sorted. */
+#define max_snaps (1 + max_StemSnap)
+typedef struct {
+ int count;
+ fixed data[max_snaps];
+} stem_snap_table;
+
+/* Define the alignment zone structure. */
+/* These are in device coordinates also. */
+#define max_a_zones (max_BlueValues + max_OtherBlues)
+typedef struct {
+ int is_top_zone;
+ fixed v0, v1; /* range for testing */
+ fixed flat; /* flat position */
+} alignment_zone;
+
+/* Define the structure for hints that depend only on the font and CTM, */
+/* not on the individual character. Eventually these should be cached */
+/* with the font/matrix pair. */
+typedef struct font_hints_s {
+ bool axes_swapped; /* true if x & y axes interchanged */
+ /* (only set if using hints) */
+ bool x_inverted, y_inverted; /* true if axis is inverted */
+ bool use_x_hints; /* true if we should use hints */
+ /* for char space x coords (vstem) */
+ bool use_y_hints; /* true if we should use hints */
+ /* for char space y coords (hstem) */
+ point_scale scale; /* oversampling scale */
+ stem_snap_table snap_h; /* StdHW, StemSnapH */
+ stem_snap_table snap_v; /* StdVW, StemSnapV */
+ fixed blue_fuzz, blue_shift; /* alignment zone parameters */
+ /* in device pixels */
+ bool suppress_overshoot; /* (computed from BlueScale) */
+ int a_zone_count; /* # of alignment zones */
+ alignment_zone a_zones[max_a_zones]; /* the alignment zones */
+} font_hints;
+
+/* ------ Character level hints ------ */
+
+/*
+ * Define the stem hint tables. Each stem hint table is kept sorted.
+ * Stem hints are in device coordinates. We have to retain replaced hints
+ * so that we can make consistent rounding choices for stem edges.
+ * This is clunky, but I don't see any other way to do it.
+ *
+ * The Type 2 charstring documentation says that the total number of hints
+ * is limited to 96, but since we store horizontal and vertical hints
+ * separately, we must set max_stems large enough to allow either one to
+ * get this big.
+ */
+#define max_total_stem_hints 96
+#define max_stems 96
+typedef struct {
+ fixed v0, v1; /* coordinates (widened a little) */
+ fixed dv0, dv1; /* adjustment values */
+ ushort index; /* sequential index of hint, */
+ /* needed for implementing hintmask */
+ ushort active; /* true if hint is active (hintmask) */
+} stem_hint;
+typedef struct {
+ int count;
+ int current; /* cache cursor for search */
+ /*
+ * For dotsection and Type 1 Charstring hint replacement,
+ * we store active hints at the bottom of the table, and
+ * replaced hints at the top.
+ */
+ int replaced_count; /* # of replaced hints at top */
+ stem_hint data[max_stems];
+} stem_hint_table;
+
+/* ------ Interpreter state ------ */
+
+/* Define the control state of the interpreter. */
+/* This is what must be saved and restored */
+/* when calling a CharString subroutine. */
+typedef struct {
+ const byte *ip;
+ crypt_state dstate;
+ gs_const_string char_string; /* original CharString or Subr, */
+ /* for GC */
+} ip_state;
+
+/* Get the next byte from a CharString. It may or may not be encrypted. */
+#define charstring_this(ch, state, encrypted)\
+ (encrypted ? decrypt_this(ch, state) : ch)
+#define charstring_next(ch, state, chvar, encrypted)\
+ (encrypted ? (chvar = decrypt_this(ch, state),\
+ decrypt_skip_next(ch, state)) :\
+ (chvar = ch))
+#define charstring_skip_next(ch, state, encrypted)\
+ (encrypted ? decrypt_skip_next(ch, state) : 0)
+
+#ifndef gx_path_DEFINED
+# define gx_path_DEFINED
+typedef struct gx_path_s gx_path;
+
+#endif
+
+#ifndef segment_DEFINED
+# define segment_DEFINED
+typedef struct segment_s segment;
+
+#endif
+
+/* This is the full state of the Type 1 interpreter. */
+#define ostack_size 48 /* per Type 2 documentation */
+#define ipstack_size 10 /* per documentation */
+struct gs_type1_state_s {
+ /* The following are set at initialization */
+ gs_font_type1 *pfont; /* font-specific data */
+ gs_imager_state *pis; /* imager state */
+ gx_path *path; /* path for appending */
+ bool charpath_flag; /* false if show, true if charpath */
+ int paint_type; /* 0/3 for fill, 1/2 for stroke */
+ fixed_coeff fc; /* cached fixed coefficients */
+ float flatness; /* flatness for character curves */
+ point_scale scale; /* oversampling scale */
+ font_hints fh; /* font-level hints */
+ gs_fixed_point origin; /* character origin */
+ /* The following are updated dynamically */
+ fixed ostack[ostack_size]; /* the Type 1 operand stack */
+ int os_count; /* # of occupied stack entries */
+ ip_state ipstack[ipstack_size + 1]; /* control stack */
+ int ips_count; /* # of occupied entries */
+ int init_done; /* -1 if not done & not needed, */
+ /* 0 if not done & needed, 1 if done */
+ bool sb_set; /* true if lsb is preset */
+ bool width_set; /* true if width is set (for */
+ /* seac components) */
+ bool have_hintmask; /* true if using a hint mask */
+ /* (Type 2 charstrings only) */
+ int num_hints; /* number of hints (Type 2 only) */
+ gs_fixed_point lsb; /* left side bearing (char coords) */
+ gs_fixed_point width; /* character width (char coords) */
+ int seac_accent; /* accent character code for seac, */
+ /* or -1 */
+ fixed save_asb; /* save seac asb */
+ gs_fixed_point save_adxy; /* save seac adx/ady */
+ fixed asb_diff; /* seac asb - accented char lsb.x, */
+ /* needed to adjust Flex endpoint */
+ gs_fixed_point adxy; /* seac accent displacement, */
+ /* needed to adjust currentpoint */
+ gs_fixed_point position; /* save unadjusted position */
+ /* when returning temporarily */
+ /* to caller */
+ int flex_path_state_flags; /* record whether path was open */
+ /* at start of Flex section */
+#define flex_max 8
+ gs_fixed_point flex_points[flex_max]; /* points for Flex */
+ int flex_count;
+ int ignore_pops; /* # of pops to ignore (after */
+ /* a known othersubr call) */
+ /* The following are set dynamically. */
+#define dotsection_in 0
+#define dotsection_out (-1)
+ int dotsection_flag; /* 0 if inside dotsection, */
+ /* -1 if outside */
+ bool vstem3_set; /* true if vstem3 seen */
+ gs_fixed_point vs_offset; /* device space offset for centering */
+ /* middle stem of vstem3 */
+ int hints_initial; /* hints applied to initial point */
+ /* of subpath */
+ gs_fixed_point unmoved_start; /* original initial point of subpath */
+ segment *hint_next; /* last segment where hints have */
+ /* been applied, 0 means none of */
+ /* current subpath has been hinted */
+ int hints_pending; /* hints applied to end of hint_next */
+ gs_fixed_point unmoved_end; /* original hint_next->pt */
+ stem_hint_table hstem_hints; /* horizontal stem hints */
+ stem_hint_table vstem_hints; /* vertical stem hints */
+ fixed transient_array[32]; /* Type 2 transient array, */
+ /* will be variable-size someday */
+};
+
+extern_st(st_gs_type1_state);
+#define public_st_gs_type1_state() /* in gstype1.c */\
+ gs_public_st_composite(st_gs_type1_state, gs_type1_state, "gs_type1_state",\
+ gs_type1_state_enum_ptrs, gs_type1_state_reloc_ptrs)
+
+/* ------ Shared Type 1 / Type 2 interpreter fragments ------ */
+
+/* Declare the array of charstring interpreters, indexed by CharstringType. */
+extern int (*gs_charstring_interpreter[3])
+ (P3(gs_type1_state * pcis, const gs_const_string * str, int *pindex));
+
+/* Copy the operand stack out of the saved state. */
+#define init_cstack(cstack, csp, pcis)\
+ BEGIN\
+ if ( pcis->os_count == 0 )\
+ csp = cstack - 1;\
+ else\
+ { memcpy(cstack, pcis->ostack, pcis->os_count * sizeof(fixed));\
+ csp = &cstack[pcis->os_count - 1];\
+ }\
+ END
+
+/* Decode and push a 1-byte number. */
+#define decode_push_num1(csp, c)\
+ (*++csp = int2fixed(c_value_num1(c)))
+
+/* Decode and push a 2-byte number. */
+#define decode_push_num2(csp, c, cip, state, encrypted)\
+ BEGIN\
+ uint c2 = *cip++;\
+ int cn;\
+\
+ cn = charstring_this(c2, state, encrypted);\
+ if ( c < c_neg2_0 )\
+ { if_debug2('1', "[1] (%d)+%d\n", c_value_pos2(c, 0), cn);\
+ *++csp = int2fixed(c_value_pos2(c, 0) + (int)cn);\
+ }\
+ else\
+ { if_debug2('1', "[1] (%d)-%d\n", c_value_neg2(c, 0), cn);\
+ *++csp = int2fixed(c_value_neg2(c, 0) - (int)cn);\
+ }\
+ charstring_skip_next(c2, state, encrypted);\
+ END
+
+/* Decode a 4-byte number, but don't push it, because Type 1 and Type 2 */
+/* charstrings scale it differently. */
+#if arch_sizeof_long > 4
+# define sign_extend_num4(lw)\
+ lw = (lw ^ 0x80000000L) - 0x80000000L
+#else
+# define sign_extend_num4(lw) DO_NOTHING
+#endif
+#define decode_num4(lw, cip, state, encrypted)\
+ BEGIN\
+ int i;\
+ uint c4;\
+\
+ lw = 0;\
+ for ( i = 4; --i >= 0; )\
+ { charstring_next(*cip, state, c4, encrypted);\
+ lw = (lw << 8) + c4;\
+ cip++;\
+ }\
+ sign_extend_num4(lw);\
+ END
+
+/* ------ Shared Type 1 / Type 2 charstring utilities ------ */
+
+void gs_type1_finish_init(P2(gs_type1_state * pcis, is_ptr ps));
+
+int gs_type1_sbw(P5(gs_type1_state * pcis, fixed sbx, fixed sby,
+ fixed wx, fixed wy));
+
+int gs_type1_seac(P4(gs_type1_state * pcis, const fixed * cstack,
+ fixed asb_diff, ip_state * ipsp));
+
+int gs_type1_endchar(P1(gs_type1_state * pcis));
+
+/* ----- Interface between main Type 1 interpreter and hint routines ----- */
+
+/* Font level hints */
+void reset_font_hints(P2(font_hints *, const gs_log2_scale_point *));
+void compute_font_hints(P4(font_hints *, const gs_matrix_fixed *,
+ const gs_log2_scale_point *,
+ const gs_type1_data *));
+
+/* Character level hints */
+void reset_stem_hints(P1(gs_type1_state *)), update_stem_hints(P1(gs_type1_state *)),
+ type1_replace_stem_hints(P1(gs_type1_state *)),
+#define replace_stem_hints(pcis)\
+ (apply_path_hints(pcis, false),\
+ type1_replace_stem_hints(pcis))
+ type1_apply_path_hints(P3(gs_type1_state *, bool, gx_path *)),
+#define apply_path_hints(pcis, closing)\
+ type1_apply_path_hints(pcis, closing, pcis->path)
+ type1_do_hstem(P4(gs_type1_state *, fixed, fixed,
+ const gs_matrix_fixed *)),
+#define type1_hstem(pcis, y, dy)\
+ type1_do_hstem(pcis, y, dy, &(pcis)->pis->ctm)
+ type1_do_vstem(P4(gs_type1_state *, fixed, fixed,
+ const gs_matrix_fixed *)),
+#define type1_vstem(pcis, x, dx)\
+ type1_do_vstem(pcis, x, dx, &(pcis)->pis->ctm)
+ type1_do_center_vstem(P4(gs_type1_state *, fixed, fixed,
+ const gs_matrix_fixed *));
+
+#define center_vstem(pcis, x0, dx)\
+ type1_do_center_vstem(pcis, x0, dx, &(pcis)->pis->ctm)
+
+#endif /* gxtype1_INCLUDED */
diff --git a/pstoraster/gxxfont.h b/pstoraster/gxxfont.h
new file mode 100644
index 000000000..ae119d0f3
--- /dev/null
+++ b/pstoraster/gxxfont.h
@@ -0,0 +1,180 @@
+/* Copyright (C) 1992, 1993, 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$ */
+/* External font interface for Ghostscript library */
+
+#ifndef gxxfont_INCLUDED
+# define gxxfont_INCLUDED
+
+#include "gsccode.h"
+#include "gsmatrix.h"
+#include "gsuid.h"
+#include "gsxfont.h"
+
+/*
+ * Design issues for external fonts
+ *
+ * 1. Where do xfonts come from: a device or a font service?
+ *
+ * 2. Is a given xfont associated with a particular device, or with a
+ * class of devices, which may have different output media?
+ * (Specifically, Windows displays vs. printers.)
+ *
+ * 3. Is an xfont a handle that must be interpreted by its originator,
+ * or an object with its own set of operations?
+ *
+ * 4. Are xfonts always transformation-specific, or is there such a thing
+ * as a scalable xfont?
+ *
+ * 5. What is the meaning of the transformation matrix supplied when
+ * asking for an xfont?
+ *
+ * Answers (for the current design)
+ *
+ * 1. Devices supply xfonts. Internal devices (image, null, clipping,
+ * command list, tracing) forward font requests to a real underlying
+ * device. File format devices should do the same, but right now
+ * they don't.
+ *
+ * 2. An xfont is not associated with anything: it just provides bitmaps.
+ * Since xfonts are only used at small sizes and low resolutions,
+ * tuning differences for different output media aren't likely to be
+ * an issue.
+ *
+ * 3. Xfonts are objects. They are allocated by their originator, and
+ * (currently) only freed by `restore'.
+ *
+ * 4. Xfonts are always transformation-specific. This may lead to some
+ * clutter, but it's very unlikely that a document will have enough
+ * different transformed versions of a single font for this to be a
+ * problem in practice.
+ *
+ * 5. The transformation matrix is the CTM within the BuildChar or BuildGlyph
+ * procedure. This maps a 1000x1000 square to the intended character size
+ * (assuming the base font uses the usual 1000-unit scaling).
+ */
+
+/* The definitions for xfonts are very similar to those for devices. */
+
+/* Structure for generic xfonts. */
+typedef struct gx_xfont_common_s {
+ const gx_xfont_procs *procs;
+} gx_xfont_common;
+
+/* A generic xfont. */
+struct gx_xfont_s {
+ gx_xfont_common common;
+};
+
+/* Definition of xfont procedures. */
+
+struct gx_xfont_procs_s {
+
+ /* Look up a font name, UniqueID, and matrix, and return */
+ /* an xfont. */
+
+ /* NOTE: even though this is defined as an xfont_proc, */
+ /* it is actually a `factory' procedure, the only one that */
+ /* does not take an xfont * as its first argument. */
+
+#define xfont_proc_lookup_font(proc)\
+ gx_xfont *proc(P7(gx_device *dev, const byte *fname, uint len,\
+ int encoding_index, const gs_uid *puid, const gs_matrix *pmat,\
+ gs_memory_t *mem))
+ xfont_proc_lookup_font((*lookup_font));
+
+ /* Convert a character name to an xglyph code. */
+ /* encoding_index is 0 for StandardEncoding, */
+ /* 1 for ISOLatin1Encoding, 2 for SymbolEncoding, */
+ /* and -1 for any other encoding. Either chr or glyph */
+ /* may be absent (gs_no_char/glyph), but not both. */
+ /* OBSOLETE as of release 3.43, but still supported. */
+
+#define xfont_proc_char_xglyph(proc)\
+ gx_xglyph proc(P5(gx_xfont *xf, gs_char chr, int encoding_index,\
+ gs_glyph glyph, gs_proc_glyph_name((*glyph_name))))
+ xfont_proc_char_xglyph((*char_xglyph));
+
+ /* Get the metrics for a character. */
+ /* Note: pwidth changed in release 2.9.7. */
+
+#define xfont_proc_char_metrics(proc)\
+ int proc(P5(gx_xfont *xf, gx_xglyph xg, int wmode,\
+ gs_point *pwidth, gs_int_rect *pbbox))
+ xfont_proc_char_metrics((*char_metrics));
+
+ /* Render a character. */
+ /* (x,y) corresponds to the character origin. */
+ /* The target may be any Ghostscript device. */
+
+#define xfont_proc_render_char(proc)\
+ int proc(P7(gx_xfont *xf, gx_xglyph xg, gx_device *target,\
+ int x, int y, gx_color_index color, int required))
+ xfont_proc_render_char((*render_char));
+
+ /* Release any external resources associated with an xfont. */
+ /* If mprocs is not NULL, also free any storage */
+ /* allocated by lookup_font (including the xfont itself). */
+
+#define xfont_proc_release(proc)\
+ int proc(P2(gx_xfont *xf, gs_memory_t *mem))
+ xfont_proc_release((*release));
+
+ /* Convert a character name to an xglyph code. */
+ /* This is the same as char_xglyph, except that */
+ /* it takes a vector of callback procedures. */
+ /* (New in release 3.43.) */
+
+#define xfont_proc_char_xglyph2(proc)\
+ gx_xglyph proc(P5(gx_xfont *xf, gs_char chr, int encoding_index,\
+ gs_glyph glyph, const gx_xfont_callbacks *callbacks))
+ xfont_proc_char_xglyph2((*char_xglyph2));
+
+};
+
+/*
+ * Since xfonts are garbage-collectable, they need structure descriptors.
+ * Fortunately, the common part of an xfont contains no pointers to
+ * GC-managed space, so simple xfonts can use gs_private_st_simple.
+ * The following macro will serve for an xfont with only one pointer,
+ * to its device:
+ */
+#define gs__st_dev_ptrs1(scope_st, stname, stype, sname, penum, preloc, de)\
+ private ENUM_PTRS_BEGIN(penum) return 0;\
+ case 0: ENUM_RETURN(gx_device_enum_ptr((gx_device *)(((stype *)vptr)->de)));\
+ ENUM_PTRS_END\
+ private RELOC_PTRS_BEGIN(preloc) ;\
+ ((stype *)vptr)->de = (void *)gx_device_reloc_ptr((gx_device *)(((stype *)vptr)->de), gcst);\
+ RELOC_PTRS_END\
+ gs__st_composite_only(scope_st, stname, stype, sname, penum, preloc)
+/*
+ * We probably don't ever want xfont descriptors to be public....
+ #define gs_public_st_dev_ptrs1(stname, stype, sname, penum, preloc, de)\
+ gs__st_dev_ptrs1(public_st, stname, stype, sname, penum, preloc, de)
+ */
+#define gs_private_st_dev_ptrs1(stname, stype, sname, penum, preloc, de)\
+ gs__st_dev_ptrs1(private_st, stname, stype, sname, penum, preloc, de)
+
+#endif /* gxxfont_INCLUDED */
diff --git a/pstoraster/gzacpath.h b/pstoraster/gzacpath.h
new file mode 100644
index 000000000..11d07187f
--- /dev/null
+++ b/pstoraster/gzacpath.h
@@ -0,0 +1,60 @@
+/* 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$ */
+/* Requires gxdevice.h, gzcpath.h */
+
+#ifndef gzacpath_INCLUDED
+# define gzacpath_INCLUDED
+
+/*
+ * Device for accumulating a rectangle list. This device can clip
+ * the list being accumulated with a clipping rectangle on the fly:
+ * we use this to clip clipping paths to band boundaries when
+ * rendering a band list.
+ */
+typedef struct gx_device_cpath_accum_s {
+ gx_device_common;
+ gs_memory_t *list_memory;
+ gs_int_rect clip_box;
+ gs_int_rect bbox;
+ gx_clip_list list;
+} gx_device_cpath_accum;
+
+/* Start accumulating a clipping path. */
+void gx_cpath_accum_begin(P2(gx_device_cpath_accum * padev, gs_memory_t * mem));
+
+/* Set the accumulator's clipping box. */
+void gx_cpath_accum_set_cbox(P2(gx_device_cpath_accum * padev,
+ const gs_fixed_rect * pbox));
+
+/* Finish accumulating a clipping path. */
+/* Note that this releases the old contents of the clipping path. */
+int gx_cpath_accum_end(P2(const gx_device_cpath_accum * padev,
+ gx_clip_path * pcpath));
+
+/* Discard an accumulator in case of error. */
+void gx_cpath_accum_discard(P1(gx_device_cpath_accum * padev));
+
+#endif /* gzacpath_INCLUDED */
diff --git a/pstoraster/gzcpath.h b/pstoraster/gzcpath.h
new file mode 100644
index 000000000..e9f108d77
--- /dev/null
+++ b/pstoraster/gzcpath.h
@@ -0,0 +1,106 @@
+/* Copyright (C) 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$ */
+/* Requires gzpath.h. */
+
+#ifndef gzcpath_INCLUDED
+# define gzcpath_INCLUDED
+
+#include "gxcpath.h"
+
+/*
+ * The reference counting considerations for clip paths are the same as
+ * for paths. We need a separate reference count for the clip list,
+ * since its existence and lifetime are not necessarily the same as
+ * those of the path.
+ */
+
+typedef struct gx_clip_rect_list_s {
+ rc_header rc;
+ gx_clip_list list;
+} gx_clip_rect_list;
+
+#define private_st_clip_rect_list() /* in gxcpath.c */\
+ gs_private_st_ptrs_add0(st_clip_rect_list, gx_clip_rect_list,\
+ "gx_clip_rect_list", clip_rect_list_enum_ptrs, clip_rect_list_reloc_ptrs,\
+ st_clip_list, list)
+
+/* gx_clip_path is a 'subclass' of gx_path. */
+struct gx_clip_path_s {
+ gx_path path;
+ gx_clip_rect_list local_list;
+ int rule; /* rule for insideness of path */
+ /* Anything within the inner_box is guaranteed to fall */
+ /* entirely within the clipping path. */
+ gs_fixed_rect inner_box;
+ /* Anything outside the outer_box is guaranteed to fall */
+ /* entirely outside the clipping path. This is the same */
+ /* as the path bounding box, widened to pixel boundaries. */
+ gs_fixed_rect outer_box;
+ gx_clip_rect_list *rect_list;
+ bool path_valid; /* path representation is valid */
+ /* The id changes whenever the clipping region changes. */
+ gs_id id;
+};
+
+extern_st(st_clip_path);
+#define public_st_clip_path() /* in gxcpath.c */\
+ gs_public_st_composite(st_clip_path, gx_clip_path, "clip_path",\
+ clip_path_enum_ptrs, clip_path_reloc_ptrs)
+#define st_clip_path_max_ptrs (st_path_max_ptrs + 1)
+
+/* Inline accessors. */
+#define gx_cpath_is_shared(pcpath)\
+ ((pcpath)->rect_list->rc.ref_count > 1)
+#define gx_cpath_list(pcpath)\
+ (&(pcpath)->rect_list->list)
+
+/* Define the structure for enumerating a clipping list. */
+typedef enum {
+ visit_left = 1,
+ visit_right = 2
+} cpe_visit_t;
+typedef enum {
+ cpe_scan, cpe_left, cpe_right, cpe_close, cpe_done
+} cpe_state_t;
+struct gs_cpath_enum_s {
+ gs_path_enum path_enum; /* used iff clipping path exists as a path, */
+ /* must be first for subclassing */
+ bool using_path;
+ gx_clip_rect *visit; /* scan pointer for finding next start */
+ gx_clip_rect *rp; /* scan pointer for current rectangle */
+ cpe_visit_t first_visit;
+ cpe_state_t state;
+ bool have_line;
+ gs_int_point line_end;
+ bool any_rectangles;
+};
+
+#define private_st_cpath_enum() /* in gxcpath.c */\
+ gs_private_st_suffix_add2(st_cpath_enum, gs_cpath_enum, "gs_cpath_enum",\
+ cpath_enum_enum_ptrs, cpath_enum_reloc_ptrs, st_path_enum,\
+ visit, rp)
+
+#endif /* gzcpath_INCLUDED */
diff --git a/pstoraster/gzht.h b/pstoraster/gzht.h
new file mode 100644
index 000000000..49f5fc2e2
--- /dev/null
+++ b/pstoraster/gzht.h
@@ -0,0 +1,203 @@
+/* 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 gxdevice.h, gxdcolor.h */
+
+#ifndef gzht_INCLUDED
+# define gzht_INCLUDED
+
+#include "gscsel.h"
+#include "gxht.h"
+#include "gxfmap.h"
+#include "gxdht.h"
+#include "gxhttile.h"
+
+/* Sort a sampled halftone order by sample value. */
+void gx_sort_ht_order(P2(gx_ht_bit *, uint));
+
+/* (Internal) procedures for constructing halftone orders. */
+int gx_ht_alloc_order(P6(gx_ht_order * porder, uint width, uint height,
+ uint strip_shift, uint num_levels, gs_memory_t * mem));
+int gx_ht_alloc_client_order(P6(gx_ht_order * porder, uint width, uint height,
+ uint num_levels, uint num_bits, gs_memory_t * mem));
+void gx_ht_construct_spot_order(P1(gx_ht_order *));
+void gx_ht_construct_threshold_order(P2(gx_ht_order *, const byte *));
+void gx_ht_construct_bit(P3(gx_ht_bit * bit, int width, int bit_num));
+void gx_ht_construct_bits(P1(gx_ht_order *));
+
+/* Halftone enumeration structure */
+struct gs_screen_enum_s {
+ gs_halftone halftone; /* supplied by client */
+ gx_ht_order order;
+ gs_matrix mat; /* for mapping device x,y to rotated cell */
+ int x, y;
+ int strip, shift;
+ gs_state *pgs;
+};
+
+#define private_st_gs_screen_enum() /* in gshtscr.c */\
+ gs_private_st_composite(st_gs_screen_enum, gs_screen_enum,\
+ "gs_screen_enum", screen_enum_enum_ptrs, screen_enum_reloc_ptrs)
+/* order.levels, order.bits, pgs) */
+
+/* Prepare a device halftone for installation, but don't install it. */
+int gs_sethalftone_prepare(P3(gs_state *, gs_halftone *,
+ gx_device_halftone *));
+
+/* Allocate and initialize a spot screen. */
+/* This is the first half of gs_screen_init_accurate/memory. */
+int gs_screen_order_init_memory(P5(gx_ht_order *, const gs_state *,
+ gs_screen_halftone *, bool, gs_memory_t *));
+
+#define gs_screen_order_init(porder, pgs, phsp, accurate)\
+ gs_screen_order_init_memory(porder, pgs, phsp, accurate, pgs->memory)
+
+/* Prepare to sample a spot screen. */
+/* This is the second half of gs_screen_init_accurate/memory. */
+int gs_screen_enum_init_memory(P5(gs_screen_enum *, const gx_ht_order *,
+ gs_state *, gs_screen_halftone *,
+ gs_memory_t *));
+
+#define gs_screen_enum_init(penum, porder, pgs, phsp)\
+ gs_screen_enum_init_memory(penum, porder, pgs, phsp, pgs->memory)
+
+/* Process an entire screen plane. */
+int gx_ht_process_screen_memory(P5(gs_screen_enum * penum, gs_state * pgs,
+ gs_screen_halftone * phsp, bool accurate,
+ gs_memory_t * mem));
+
+#define gx_ht_process_screen(penum, pgs, phsp, accurate)\
+ gx_ht_process_screen_memory(penum, pgs, phsp, accurate, pgs->memory)
+
+/*
+ * We don't want to remember all the values of the halftone screen,
+ * because they would take up space proportional to P^3, where P is
+ * the number of pixels in a cell. Instead, we pick some number N of
+ * patterns to cache. Each cache slot covers a range of (P+1)/N
+ * different gray levels: we "slide" the contents of the slot back and
+ * forth within this range by incrementally adding and dropping 1-bits.
+ * N>=0 (obviously); N<=P+1 (likewise); also, so that we can simplify things
+ * by preallocating the bookkeeping information for the cache, we define
+ * a constant max_cached_tiles which is an a priori maximum value for N.
+ *
+ * Note that the raster for each tile must be a multiple of bitmap_align_mod,
+ * to satisfy the copy_mono device routine, even though a multiple of
+ * sizeof(ht_mask_t) would otherwise be sufficient.
+ */
+
+struct gx_ht_cache_s {
+ /* The following are set when the cache is created. */
+ byte *bits; /* the base of the bits */
+ uint bits_size; /* the space available for bits */
+ gx_ht_tile *ht_tiles; /* the base of the tiles */
+ uint num_tiles; /* the number of tiles allocated */
+ /* The following are reset each time the cache is initialized */
+ /* for a new screen. */
+ gx_ht_order order; /* the cached order vector */
+ int num_cached; /* actual # of cached tiles */
+ int levels_per_tile; /* # of levels per cached tile */
+ gx_bitmap_id base_id; /* the base id, to which */
+ /* we add the halftone level */
+};
+
+/* We don't mark from the tiles pointer, and we relocate the tiles en masse. */
+#define private_st_ht_tiles() /* in gxht.c */\
+ gs_private_st_composite(st_ht_tiles, gx_ht_tile, "ht tiles",\
+ ht_tiles_enum_ptrs, ht_tiles_reloc_ptrs)
+#define private_st_ht_cache() /* in gxht.c */\
+ gs_private_st_ptrs_add2(st_ht_cache, gx_ht_cache, "ht cache",\
+ ht_cache_enum_ptrs, ht_cache_reloc_ptrs,\
+ st_ht_order, order, bits, ht_tiles)
+
+/* Compute a fractional color for dithering, the correctly rounded */
+/* quotient f * max_gx_color_value / maxv. */
+#define frac_color_(f, maxv)\
+ (gx_color_value)(((f) * (0xffffL * 2) + maxv) / (maxv * 2))
+extern const gx_color_value *const fc_color_quo[8];
+
+#define fractional_color(f, maxv)\
+ ((maxv) <= 7 ? fc_color_quo[maxv][f] : frac_color_(f, maxv))
+
+/* ------ Halftone cache procedures ------ */
+
+/* Allocate/free a halftone cache. */
+uint gx_ht_cache_default_tiles(P0());
+uint gx_ht_cache_default_bits(P0());
+gx_ht_cache *gx_ht_alloc_cache(P3(gs_memory_t *, uint, uint));
+void gx_ht_free_cache(P2(gs_memory_t *, gx_ht_cache *));
+
+/* Clear a halftone cache. */
+#define gx_ht_clear_cache(pcache)\
+ ((pcache)->order.levels = 0, (pcache)->order.bits = 0,\
+ (pcache)->ht_tiles[0].tiles.data = 0)
+
+/* Initialize a halftone cache with a given order. */
+void gx_ht_init_cache(P2(gx_ht_cache *, const gx_ht_order *));
+
+/* Make the cache order current, and return whether */
+/* there is room for all possible tiles in the cache. */
+bool gx_check_tile_cache(P1(const gs_imager_state *));
+
+/* Determine whether a given (width, y, height) might fit into a */
+/* single tile. If so, return the byte offset of the appropriate row */
+/* from the beginning of the tile, and set *ppx to the x phase offset */
+/* within the tile; if not, return -1. */
+int gx_check_tile_size(P6(const gs_imager_state * pis, int w, int y, int h,
+ gs_color_select_t select, int *ppx));
+
+/* Make a given level current in a halftone cache. */
+gx_ht_tile *gx_render_ht(P2(gx_ht_cache *, int));
+
+/* ------ Device halftone management ------ */
+
+/* Release a gx_ht_order by freeing its components. */
+/* (Don't free the gx_device_halftone itself.) */
+void gx_ht_order_release(P3(gx_ht_order * porder, gs_memory_t * mem, bool free_cache));
+
+/*
+ * Install a device halftone in an imager state.
+ * Note that this does not read or update the client halftone.
+ */
+int gx_imager_dev_ht_install(P4(gs_imager_state * pis,
+ const gx_device_halftone * pdht,
+ gs_halftone_type type,
+ const gx_device * dev));
+
+/*
+ * Install a new halftone in the graphics state. Note that we copy the top
+ * level of the gs_halftone and the gx_device_halftone, and take ownership
+ * of any substructures.
+ */
+int gx_ht_install(P3(gs_state *, const gs_halftone *,
+ const gx_device_halftone *));
+
+/* Reestablish the effective transfer functions, taking into account */
+/* any overrides from halftone dictionaries. */
+/* Some compilers object to names longer than 31 characters.... */
+void gx_imager_set_effective_xfer(P1(gs_imager_state * pis));
+void gx_set_effective_transfer(P1(gs_state * pgs));
+
+
+#endif /* gzht_INCLUDED */
diff --git a/pstoraster/gzline.h b/pstoraster/gzline.h
new file mode 100644
index 000000000..f50d39641
--- /dev/null
+++ b/pstoraster/gzline.h
@@ -0,0 +1,41 @@
+/* Copyright (C) 1989, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of GNU Ghostscript.
+
+ GNU Ghostscript is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
+ to anyone for the consequences of using it or for whether it serves any
+ particular purpose or works at all, unless he says so in writing. Refer
+ to the GNU General Public License for full details.
+
+ Everyone is granted permission to copy, modify and redistribute GNU
+ Ghostscript, but only under the conditions described in the GNU General
+ Public License. A copy of this license is supposed to have been given
+ to you along with GNU Ghostscript so you can know your rights and
+ responsibilities. It should be in a file named COPYING. Among other
+ things, the copyright notice and this notice must be preserved on all
+ copies.
+
+ Aladdin Enterprises 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$ */
+/* Line parameter implementation */
+
+#ifndef gzline_INCLUDED
+# define gzline_INCLUDED
+
+#include "gxline.h"
+
+#define private_st_line_params() /* in gsstate.c */\
+ gs_private_st_ptrs1(st_line_params, gx_line_params, "line_params",\
+ line_params_enum_ptrs, line_params_reloc_ptrs, dash.pattern)
+#define st_line_params_num_ptrs 1
+
+/* Internal accessor for line parameters in graphics state */
+const gx_line_params *gs_currentlineparams(P1(const gs_imager_state *));
+
+#endif /* gzline_INCLUDED */
diff --git a/pstoraster/gzpath.h b/pstoraster/gzpath.h
new file mode 100644
index 000000000..26c6f2121
--- /dev/null
+++ b/pstoraster/gzpath.h
@@ -0,0 +1,385 @@
+/* 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$ */
+/* Requires gxfixed.h */
+
+#ifndef gzpath_INCLUDED
+# define gzpath_INCLUDED
+
+#include "gxpath.h"
+#include "gsmatrix.h"
+#include "gsrefct.h"
+#include "gsstruct.h" /* for extern_st */
+
+/*
+ * Paths are represented as a linked list of line or curve segments,
+ * similar to what pathforall reports.
+ */
+
+/*
+ * Define path segment types: segment start, line, or Bezier curve.
+ * We have a special type for the line added by closepath.
+ */
+typedef enum {
+ s_start,
+ s_line,
+ s_line_close,
+ s_curve
+} segment_type;
+
+/* Define the common structure for all segments. */
+#define segment_common\
+ segment *prev;\
+ segment *next;\
+ ushort /*segment_type*/ type;\
+ ushort /*segment_notes*/ notes;\
+ gs_fixed_point pt; /* initial point for starts, */\
+ /* final point for others */
+
+/* Forward declarations for structure types */
+#ifndef segment_DEFINED
+# define segment_DEFINED
+typedef struct segment_s segment;
+
+#endif
+typedef struct subpath_s subpath;
+
+/*
+ * Define a generic segment. This is never instantiated,
+ * but we define a descriptor anyway for the benefit of subclasses.
+ */
+struct segment_s {
+ segment_common
+};
+
+#define private_st_segment() /* in gxpath.c */\
+ gs_private_st_ptrs2(st_segment, struct segment_s, "segment",\
+ segment_enum_ptrs, segment_reloc_ptrs, prev, next)
+
+/* Line segments have no special data. */
+typedef struct {
+ segment_common
+} line_segment;
+
+#define private_st_line() /* in gxpath.c */\
+ gs_private_st_suffix_add0(st_line, line_segment, "line",\
+ line_enum_ptrs, line_reloc_ptrs, st_segment)
+
+/* Line_close segments are for the lines appended by closepath. */
+/* They point back to the subpath being closed. */
+typedef struct {
+ segment_common
+ subpath * sub;
+} line_close_segment;
+
+#define private_st_line_close() /* in gxpath.c */\
+ gs_private_st_suffix_add1(st_line_close, line_close_segment, "close",\
+ close_enum_ptrs, close_reloc_ptrs, st_segment, sub)
+
+/*
+ * We use two different representations for curve segments: one defined by
+ * two endpoints (p0, p3) and two control points (p1, p2), and one defined
+ * by two sets of parametric cubic coefficients (ax ... dy). Here is how
+ * they are related (v = x or y). We spell out some multiplies by 3 for
+ * the benefit of compilers too simple to optimize this.
+ */
+#define curve_points_to_coefficients(v0, v1, v2, v3, a, b, c, t01, t12)\
+ (/*d = (v0),*/\
+ t01 = (v1) - (v0), c = (t01 << 1) + t01,\
+ t12 = (v2) - (v1), b = (t12 << 1) + t12 - c,\
+ a = (v3) - b - c - (v0))
+/*
+ * or conversely
+ */
+#define curve_coefficients_to_points(a, b, c, d, v1, v2, v3)\
+ (/*v0 = (d),*/\
+ v1 = (d) + ((c) / 3),\
+ v2 = v1 + (((b) + (c)) / 3),\
+ v3 = (a) + (b) + (c) + (d))
+
+/* Curve segments store the control points. */
+typedef struct {
+ segment_common
+ gs_fixed_point p1, p2;
+} curve_segment;
+
+#define private_st_curve() /* in gxpath.c */\
+ gs_private_st_suffix_add0_local(st_curve, curve_segment, "curve",\
+ segment_enum_ptrs, segment_reloc_ptrs, st_segment)
+
+/*
+ * Define a start segment. This serves as the head of a subpath.
+ * The closer is only used temporarily when filling,
+ * to close an open subpath.
+ */
+struct subpath_s {
+ segment_common
+ segment * last; /* last segment of subpath, */
+ /* points back to here if empty */
+ int curve_count; /* # of curves */
+ line_close_segment closer;
+ char /*bool */ is_closed; /* true if subpath is closed */
+};
+
+#define private_st_subpath() /* in gxpath.c */\
+ gs_private_st_suffix_add1(st_subpath, subpath, "subpath",\
+ subpath_enum_ptrs, subpath_reloc_ptrs, st_segment, last)
+
+/* Test whether a subpath is a rectangle; if so, also return */
+/* the start of the next subpath. */
+gx_path_rectangular_type
+gx_subpath_is_rectangular(P3(const subpath * pstart, gs_fixed_rect * pbox,
+ const subpath ** ppnext));
+
+#define gx_subpath_is_rectangle(pstart, pbox, ppnext)\
+ (gx_subpath_is_rectangular(pstart, pbox, ppnext) != prt_none)
+
+/* Curve manipulation */
+
+/* Return the smallest value k such that 2^k segments will approximate */
+/* the curve to within the desired flatness. */
+int gx_curve_log2_samples(P4(fixed, fixed, const curve_segment *, fixed));
+
+/*
+ * If necessary, find the values of t (never more than 2) which split the
+ * curve into monotonic parts. Return the number of split points.
+ */
+int gx_curve_monotonic_points(P5(fixed, fixed, fixed, fixed, double[2]));
+
+/* Split a curve at an arbitrary value of t. */
+void gx_curve_split(P6(fixed, fixed, const curve_segment *, double,
+ curve_segment *, curve_segment *));
+
+/* Flatten a partial curve by sampling (internal procedure). */
+int gx_flatten_sample(P4(gx_path *, int, curve_segment *, segment_notes));
+
+/* Initialize a cursor for rasterizing a monotonic curve. */
+typedef struct curve_cursor_s {
+ /* Following are set at initialization */
+ int k; /* 2^k segments */
+ gs_fixed_point p0; /* starting point */
+ const curve_segment *pc; /* other points */
+ fixed a, b, c; /* curve coefficients */
+ double da, db, dc; /* scaled double versions of a, b, c */
+ bool double_set; /* true if da/b/c set */
+ int fixed_limit; /* can do in fixed point if t <= limit */
+ /* Following are updated dynamically. */
+ struct ccc_ { /* one-element cache */
+ fixed ky0, ky3; /* key (range) */
+ fixed xl, xd; /* value */
+ } cache;
+} curve_cursor;
+void gx_curve_cursor_init(P5(curve_cursor * prc, fixed x0, fixed y0,
+ const curve_segment * pc, int k));
+
+/* Return the value of X at a given Y value on a monotonic curve. */
+/* y must lie between prc->p0.y and prc->pt.y. */
+fixed gx_curve_x_at_y(P2(curve_cursor * prc, fixed y));
+
+/*
+ * The path state flags reflect the most recent operation on the path
+ * as follows:
+ * Operation position_valid subpath_open is_drawing
+ * newpath no no no
+ * moveto yes yes no
+ * lineto/curveto yes yes yes
+ * closepath yes no no
+ * If position_valid is true, outside_range reflects whether the most
+ * recent operation went outside of the representable coordinate range.
+ * If this is the case, the corresponding member of position (x and/or y)
+ * is min_fixed or max_fixed, and outside_position is the true position.
+ */
+/*
+ */
+typedef enum {
+ /* Individual flags. These may be or'ed together, per above. */
+ psf_position_valid = 1,
+ psf_subpath_open = 2,
+ psf_is_drawing = 4,
+ psf_outside_range = 8,
+ /* Values stored by path building operations. */
+ psf_last_newpath = 0,
+ psf_last_moveto = psf_position_valid | psf_subpath_open,
+ psf_last_draw = psf_position_valid | psf_subpath_open | psf_is_drawing,
+ psf_last_closepath = psf_position_valid
+} gx_path_state_flags;
+
+/*
+ * Individual tests
+ */
+#define path_position_valid(ppath)\
+ (((ppath)->state_flags & psf_position_valid) != 0)
+#define path_subpath_open(ppath)\
+ (((ppath)->state_flags & psf_subpath_open) != 0)
+#define path_is_drawing(ppath)\
+ (((ppath)->state_flags & psf_is_drawing) != 0)
+#define path_outside_range(ppath)\
+ (((ppath)->state_flags & psf_outside_range) != 0)
+/*
+ * Composite tests
+ */
+#define path_last_is_moveto(ppath)\
+ (((ppath)->state_flags & ~psf_outside_range) == psf_last_moveto)
+#define path_position_in_range(ppath)\
+ (((ppath)->state_flags & (psf_position_valid + psf_outside_range)) ==\
+ psf_position_valid)
+#define path_start_outside_range(ppath)\
+ ((ppath)->state_flags != 0 &&\
+ ((ppath)->start_flags & psf_outside_range) != 0)
+/*
+ * Updating operations
+ */
+#define path_update_newpath(ppath)\
+ ((ppath)->state_flags = psf_last_newpath)
+#define path_update_moveto(ppath)\
+ ((ppath)->state_flags = (ppath)->start_flags = psf_last_moveto)
+#define path_update_draw(ppath)\
+ ((ppath)->state_flags = psf_last_draw)
+#define path_update_closepath(ppath)\
+ ((ppath)->state_flags = psf_last_closepath)
+#define path_set_outside_position(ppath, px, py)\
+ ((ppath)->outside_position.x = (px),\
+ (ppath)->outside_position.y = (py),\
+ (ppath)->state_flags |= psf_outside_range)
+
+/*
+ * In order to be able to reclaim path segments at the right time, we need
+ * to reference-count them. To minimize disruption, we would like to do
+ * this by creating a structure (gx_path_segments) consisting of only a
+ * reference count that counts the number of paths that share the same
+ * segments. (Logically, we should put the segments themselves --
+ * first/last_subpath, subpath/curve_count -- in this object, but that would
+ * cause too much disruption to existing code.) However, we need to put at
+ * least first_subpath and current_subpath in this structure so that we can
+ * free the segments when the reference count becomes zero.
+ */
+typedef struct gx_path_segments_s {
+ rc_header rc;
+ struct psc_ {
+ subpath *subpath_first;
+ subpath *subpath_current;
+ } contents;
+} gx_path_segments;
+
+#define private_st_path_segments() /* in gxpath.c */\
+ gs_private_st_ptrs2(st_path_segments, gx_path_segments, "path segments",\
+ path_segments_enum_ptrs, path_segments_reloc_ptrs,\
+ contents.subpath_first, contents.subpath_current)
+
+/* Record how a path was allocated, so freeing will do the right thing. */
+typedef enum {
+ path_allocated_on_stack, /* on stack */
+ path_allocated_contained, /* inside another object */
+ path_allocated_on_heap /* on the heap */
+} gx_path_allocation_t;
+
+/* Here is the actual structure of a path. */
+struct gx_path_s {
+ /*
+ * In order to be able to have temporary paths allocated entirely
+ * on the stack, we include a segments structure within the path,
+ * used only for this purpose. In order to avoid having the
+ * path's segments pointer point into the middle of an object,
+ * the segments structure must come first.
+ *
+ * Note that since local_segments is used only for temporary paths
+ * on the stack, and not for path structures in allocated memory,
+ * we don't declare any pointers in it for the GC. (As it happens,
+ * there aren't any such pointers at the moment, but this could
+ * change.)
+ */
+ gx_path_segments local_segments;
+ gs_memory_t *memory;
+ gx_path_allocation_t allocation; /* how this path was allocated */
+ gx_path_segments *segments;
+ gs_fixed_rect bbox; /* bounding box (in device space) */
+ segment *box_last; /* bbox incorporates segments */
+ /* up to & including this one */
+#define first_subpath segments->contents.subpath_first /* (hack) */
+#define current_subpath segments->contents.subpath_current /* (ditto) */
+ int subpath_count;
+ int curve_count;
+ gs_fixed_point position; /* current position */
+ gs_point outside_position; /* position if outside_range is set */
+ gs_point outside_start; /* outside_position of last moveto */
+ byte /*gx_path_state_flags */ start_flags; /* flags of moveto */
+ byte /*gx_path_state_flags */ state_flags; /* (see above) */
+ byte /*bool */ bbox_set; /* true if setbbox is in effect */
+};
+
+/* st_path should be private, but it's needed for the clip_path subclass. */
+extern_st(st_path);
+#define public_st_path() /* in gxpath.c */\
+ gs_public_st_ptrs2(st_path, gx_path, "path",\
+ path_enum_ptrs, path_reloc_ptrs, segments, box_last)
+#define st_path_max_ptrs 2
+
+/* Path enumeration structure */
+struct gs_path_enum_s {
+ gs_memory_t *memory;
+ gs_matrix mat; /* CTM for inverse-transforming points */
+ const segment *pseg;
+ const gx_path *path; /* path being enumerated */
+ gx_path *copied_path; /* if the path was copied, this is the */
+ /* the same as path, to be released */
+ /* when done enumerating */
+ bool moveto_done; /* have we reported a final moveto yet? */
+ segment_notes notes; /* notes from most recent segment */
+};
+
+/* We export st_path_enum only so that st_cpath_enum can subclass it. */
+extern_st(st_path_enum);
+#define public_st_path_enum() /* in gxpath2.c */\
+ gs_public_st_ptrs3(st_path_enum, gs_path_enum, "gs_path_enum",\
+ path_enum_enum_ptrs, path_enum_reloc_ptrs, pseg, path, copied_path)
+
+/* Inline path accessors. */
+#define gx_path_has_curves_inline(ppath)\
+ ((ppath)->curve_count != 0)
+#define gx_path_has_curves(ppath)\
+ gx_path_has_curves_inline(ppath)
+#define gx_path_is_void_inline(ppath)\
+ ((ppath)->first_subpath == 0)
+#define gx_path_is_void(ppath)\
+ gx_path_is_void_inline(ppath)
+#define gx_path_subpath_count(ppath)\
+ ((ppath)->subpath_count)
+#define gx_path_is_shared(ppath)\
+ ((ppath)->segments->rc.ref_count > 1)
+
+/* Macros equivalent to a few heavily used procedures. */
+/* Be aware that these macros may evaluate arguments more than once. */
+#define gx_path_current_point_inline(ppath,ppt)\
+ ( !path_position_valid(ppath) ? gs_note_error(gs_error_nocurrentpoint) :\
+ ((ppt)->x = ppath->position.x, (ppt)->y = ppath->position.y, 0) )
+/* ...rel_point rather than ...relative_point is because */
+/* some compilers dislike identifiers of >31 characters. */
+#define gx_path_add_rel_point_inline(ppath,dx,dy)\
+ ( !path_position_in_range(ppath) || ppath->bbox_set ?\
+ gx_path_add_relative_point(ppath, dx, dy) :\
+ (ppath->position.x += dx, ppath->position.y += dy,\
+ path_update_moveto(ppath), 0) )
+
+#endif /* gzpath_INCLUDED */
diff --git a/pstoraster/gzstate.h b/pstoraster/gzstate.h
new file mode 100644
index 000000000..0a189911b
--- /dev/null
+++ b/pstoraster/gzstate.h
@@ -0,0 +1,137 @@
+/* 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$ */
+/* Private graphics state definition for Ghostscript library */
+
+#ifndef gzstate_INCLUDED
+# define gzstate_INCLUDED
+
+#include "gscpm.h"
+#include "gsrefct.h"
+#include "gxdcolor.h"
+#include "gxistate.h"
+#include "gsstate.h"
+#include "gxstate.h"
+
+/* Opaque types referenced by the graphics state. */
+#ifndef gx_path_DEFINED
+# define gx_path_DEFINED
+typedef struct gx_path_s gx_path;
+
+#endif
+#ifndef gx_clip_path_DEFINED
+# define gx_clip_path_DEFINED
+typedef struct gx_clip_path_s gx_clip_path;
+
+#endif
+#ifndef gs_color_space_DEFINED
+# define gs_color_space_DEFINED
+typedef struct gs_color_space_s gs_color_space;
+
+#endif
+#ifndef gs_client_color_DEFINED
+# define gs_client_color_DEFINED
+typedef struct gs_client_color_s gs_client_color;
+
+#endif
+#ifndef gs_font_DEFINED
+# define gs_font_DEFINED
+typedef struct gs_font_s gs_font;
+
+#endif
+
+/* Graphics state structure. */
+
+struct gs_state_s {
+ gs_imager_state_common; /* imager state, must be first */
+ gs_state *saved; /* previous state from gsave */
+
+ /* Transformation: */
+
+ gs_matrix ctm_inverse;
+ bool ctm_inverse_valid; /* true if ctm_inverse = ctm^-1 */
+ gs_matrix ctm_default;
+ bool ctm_default_set; /* if true, use ctm_default; */
+ /* if false, ask device */
+
+ /* Paths: */
+
+ gx_path *path;
+ gx_clip_path *clip_path;
+ gx_clip_path *view_clip; /* (may be 0, or have rule = 0) */
+ bool clamp_coordinates; /* if true, clamp out-of-range */
+ /* coordinates; if false, */
+ /* report a limitcheck */
+ /* Effective clip path cache */
+ gs_id effective_clip_id; /* (key) clip path id */
+ gs_id effective_view_clip_id; /* (key) view clip path id */
+ gx_clip_path *effective_clip_path; /* (value) effective clip path, */
+ /* possibly = clip_path or view_clip */
+ bool effective_clip_shared; /* true iff e.c.p. = c.p. or v.c. */
+
+ /* Color (device-independent): */
+
+ gs_color_space *color_space;
+ gs_client_color *ccolor;
+
+ /* Color caches: */
+
+ gx_device_color *dev_color;
+
+ /* Font: */
+
+ gs_font *font;
+ gs_font *root_font;
+ gs_matrix_fixed char_tm; /* font matrix * ctm */
+#define char_tm_only(pgs) *(gs_matrix *)&(pgs)->char_tm
+ bool char_tm_valid; /* true if char_tm is valid */
+ byte in_cachedevice; /* 0 if not in setcachedevice, */
+ /* 1 if in setcachedevice but not */
+ /* actually caching, */
+ /* 2 if in setcachedevice and */
+ /* actually caching */
+ gs_char_path_mode in_charpath; /* (see gscpm.h) */
+ gs_state *show_gstate; /* gstate when show was invoked */
+ /* (so charpath can append to path) */
+
+ /* Other stuff: */
+
+ int level; /* incremented by 1 per gsave */
+ gx_device *device;
+#undef gs_currentdevice_inline
+#define gs_currentdevice_inline(pgs) ((pgs)->device)
+
+ /* Client data: */
+
+ void *client_data;
+#define gs_state_client_data(pgs) ((pgs)->client_data)
+ gs_state_client_procs client_procs;
+};
+
+#define private_st_gs_state() /* in gsstate.c */\
+ gs_private_st_composite(st_gs_state, gs_state, "gs_state",\
+ gs_state_enum_ptrs, gs_state_reloc_ptrs)
+
+#endif /* gzstate_INCLUDED */
diff --git a/pstoraster/ialloc.c b/pstoraster/ialloc.c
new file mode 100644
index 000000000..9caf55b61
--- /dev/null
+++ b/pstoraster/ialloc.c
@@ -0,0 +1,314 @@
+/* Copyright (C) 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$ */
+/* Memory allocator for Ghostscript interpreter */
+#include "gx.h"
+#include "memory_.h"
+#include "errors.h"
+#include "gsstruct.h"
+#include "gxarith.h" /* for small_exact_log2 */
+#include "iref.h" /* must precede iastate.h */
+#include "iastate.h"
+#include "ipacked.h"
+#include "iutil.h"
+#include "ivmspace.h"
+#include "store.h"
+
+/*
+ * Define global and local instances.
+ */
+gs_dual_memory_t gs_imemory;
+
+/* Initialize the allocator */
+void
+ialloc_init(gs_raw_memory_t * rmem, uint chunk_size, bool level2)
+{
+ gs_ref_memory_t *ilmem = ialloc_alloc_state(rmem, chunk_size);
+ gs_ref_memory_t *igmem =
+ (level2 ?
+ ialloc_alloc_state(rmem, chunk_size) :
+ ilmem);
+ gs_ref_memory_t *ismem = ialloc_alloc_state(rmem, chunk_size);
+ int i;
+
+ for (i = 0; i < countof(gs_imemory.spaces.indexed); i++)
+ gs_imemory.spaces.indexed[i] = 0;
+ gs_imemory.space_local = ilmem;
+ gs_imemory.space_global = igmem;
+ gs_imemory.space_system = ismem;
+ gs_imemory.reclaim = 0;
+ /* Level 1 systems have only local VM. */
+ igmem->space = avm_global;
+ ilmem->space = avm_local; /* overrides if ilmem == igmem */
+ igmem->global = ilmem->global = igmem;
+
+ ismem->space = avm_system;
+ ialloc_set_space(&gs_imemory, avm_global);
+}
+
+/* ================ Local/global VM ================ */
+
+/* Get the space attribute of an allocator */
+uint
+imemory_space(gs_ref_memory_t * iimem)
+{
+ return iimem->space;
+}
+
+/* Select the allocation space. */
+void
+ialloc_set_space(gs_dual_memory_t * dmem, uint space)
+{
+ gs_ref_memory_t *mem = dmem->spaces.indexed[space >> r_space_shift];
+
+ dmem->current = mem;
+ dmem->current_space = mem->space;
+}
+
+/* Reset the requests. */
+void
+ialloc_reset_requested(gs_dual_memory_t * dmem)
+{
+ dmem->space_system->gc_status.requested = 0;
+ dmem->space_global->gc_status.requested = 0;
+ dmem->space_local->gc_status.requested = 0;
+}
+
+/* ================ Refs ================ */
+
+/* Register a ref root. */
+int
+gs_register_ref_root(gs_memory_t *mem, gs_gc_root_t *root,
+ void **pp, client_name_t cname)
+{
+ return gs_register_root(mem, root, ptr_ref_type, pp, cname);
+}
+
+/*
+ * As noted in iastate.h, every run of refs has an extra ref at the end
+ * to hold relocation information for the garbage collector;
+ * since sizeof(ref) % obj_align_mod == 0, we never need to
+ * allocate any additional padding space at the end of the block.
+ */
+
+/* Allocate an array of refs. */
+int
+gs_alloc_ref_array(gs_ref_memory_t * mem, ref * parr, uint attrs,
+ uint num_refs, client_name_t cname)
+{
+ ref *obj;
+
+ /* If we're allocating a run of refs already, */
+ /* and we aren't about to overflow the maximum run length, use it. */
+ if (mem->cc.rtop == mem->cc.cbot &&
+ num_refs < (mem->cc.ctop - mem->cc.cbot) / sizeof(ref) &&
+ mem->cc.rtop - (byte *) mem->cc.rcur + num_refs * sizeof(ref) <
+ max_size_st_refs
+ ) {
+ ref *end;
+
+ obj = (ref *) mem->cc.rtop - 1; /* back up over last ref */
+ if_debug4('A', "[a%d:+$ ]%s(%u) = 0x%lx\n", mem->space,
+ client_name_string(cname), num_refs, (ulong) obj);
+ mem->cc.rcur[-1].o_size += num_refs * sizeof(ref);
+ end = (ref *) (mem->cc.rtop = mem->cc.cbot +=
+ num_refs * sizeof(ref));
+ make_mark(end - 1);
+ } else {
+ /*
+ * Allocate a new run. We have to distinguish 3 cases:
+ * - Same chunk: pcc unchanged, end == cc.cbot.
+ * - Large chunk: pcc unchanged, end != cc.cbot.
+ * - New chunk: pcc changed.
+ */
+ chunk_t *pcc = mem->pcc;
+ ref *end;
+
+ obj = gs_alloc_struct_array((gs_memory_t *) mem, num_refs + 1,
+ ref, &st_refs, cname);
+ if (obj == 0)
+ return_error(e_VMerror);
+ /* Set the terminating ref now. */
+ end = (ref *) obj + num_refs;
+ make_mark(end);
+ /* Set has_refs in the chunk. */
+ if (mem->pcc != pcc || mem->cc.cbot == (byte *) (end + 1)) {
+ /* Ordinary chunk. */
+ mem->cc.rcur = (obj_header_t *) obj;
+ mem->cc.rtop = (byte *) (end + 1);
+ mem->cc.has_refs = true;
+ } else {
+ /* Large chunk. */
+ /* This happens only for very large arrays, */
+ /* so it doesn't need to be cheap. */
+ chunk_locator_t cl;
+
+ cl.memory = mem;
+ cl.cp = mem->clast;
+ chunk_locate_ptr(obj, &cl);
+ cl.cp->has_refs = true;
+ }
+ }
+ make_array(parr, attrs | mem->space, num_refs, obj);
+ return 0;
+}
+
+/* Resize an array of refs. Currently this is only implemented */
+/* for shrinking, not for growing. */
+int
+gs_resize_ref_array(gs_ref_memory_t * mem, ref * parr,
+ uint new_num_refs, client_name_t cname)
+{
+ uint old_num_refs = r_size(parr);
+ uint diff;
+ ref *obj = parr->value.refs;
+
+ if (new_num_refs > old_num_refs || !r_has_type(parr, t_array))
+ return_error(e_Fatal);
+ diff = old_num_refs - new_num_refs;
+ /* Check for LIFO. See gs_free_ref_array for more details. */
+ if (mem->cc.rtop == mem->cc.cbot &&
+ (byte *) (obj + (old_num_refs + 1)) == mem->cc.rtop
+ ) {
+ /* Shorten the refs object. */
+ ref *end = (ref *) (mem->cc.cbot = mem->cc.rtop -=
+ diff * sizeof(ref));
+
+ if_debug4('A', "[a%d:<$ ]%s(%u) 0x%lx\n", mem->space,
+ client_name_string(cname), diff, (ulong) obj);
+ mem->cc.rcur[-1].o_size -= diff * sizeof(ref);
+ make_mark(end - 1);
+ } else {
+ /* Punt. */
+ if_debug4('A', "[a%d:<$#]%s(%u) 0x%lx\n", mem->space,
+ client_name_string(cname), diff, (ulong) obj);
+ mem->lost.refs += diff * sizeof(ref);
+ }
+ r_set_size(parr, new_num_refs);
+ return 0;
+}
+
+/* Deallocate an array of refs. Only do this if LIFO, or if */
+/* the array occupies an entire chunk by itself. */
+void
+gs_free_ref_array(gs_ref_memory_t * mem, ref * parr, client_name_t cname)
+{
+ uint num_refs = r_size(parr);
+ ref *obj = parr->value.refs;
+
+ /*
+ * Compute the storage size of the array, and check for LIFO
+ * freeing or a separate chunk. Note that the array might be packed;
+ * for the moment, if it's anything but a t_array, punt.
+ * The +1s are for the extra ref for the GC.
+ */
+ if (!r_has_type(parr, t_array))
+ DO_NOTHING; /* don't look for special cases */
+ else if (mem->cc.rtop == mem->cc.cbot &&
+ (byte *) (obj + (num_refs + 1)) == mem->cc.rtop
+ ) {
+ if ((obj_header_t *) obj == mem->cc.rcur) {
+ /* Deallocate the entire refs object. */
+ gs_free_object((gs_memory_t *) mem, obj, cname);
+ mem->cc.rcur = 0;
+ mem->cc.rtop = 0;
+ } else {
+ /* Deallocate it at the end of the refs object. */
+ if_debug4('A', "[a%d:-$ ]%s(%u) 0x%lx\n",
+ mem->space, client_name_string(cname),
+ num_refs, (ulong) obj);
+ mem->cc.rcur[-1].o_size -= num_refs * sizeof(ref);
+ mem->cc.rtop = mem->cc.cbot = (byte *) (obj + 1);
+ make_mark(obj);
+ }
+ return;
+ } else if (num_refs >= (mem->large_size / arch_sizeof_ref - 1)) {
+ /* See if this array has a chunk all to itself. */
+ /* We only make this check when freeing very large objects, */
+ /* so it doesn't need to be cheap. */
+ chunk_locator_t cl;
+
+ cl.memory = mem;
+ cl.cp = mem->clast;
+ if (chunk_locate_ptr(obj, &cl) &&
+ obj == (ref *) ((obj_header_t *) (cl.cp->cbase) + 1) &&
+ (byte *) (obj + (num_refs + 1)) == cl.cp->cend
+ ) {
+ /* Free the chunk. */
+ if_debug4('a', "[a%d:-$L]%s(%u) 0x%lx\n",
+ mem->space, client_name_string(cname),
+ num_refs, (ulong) obj);
+ alloc_free_chunk(cl.cp, mem);
+ return;
+ }
+ }
+ /* Punt, but fill the array with nulls so that there won't be */
+ /* dangling references to confuse the garbage collector. */
+ if_debug4('A', "[a%d:-$#]%s(%u) 0x%lx\n", mem->space,
+ client_name_string(cname), num_refs, (ulong) obj);
+ {
+ uint size;
+
+ switch (r_type(parr)) {
+ case t_shortarray:
+ size = num_refs * sizeof(ref_packed);
+ break;
+ case t_mixedarray:{
+ /* We have to parse the array to compute the storage size. */
+ uint i = 0;
+ const ref_packed *p = parr->value.packed;
+
+ for (; i < num_refs; ++i)
+ p = packed_next(p);
+ size = (const byte *)p - (const byte *)parr->value.packed;
+ break;
+ }
+ case t_array:
+ size = num_refs * sizeof(ref);
+ break;
+ default:
+ lprintf3("Unknown type 0x%x in free_ref_array(%u,0x%lx)!",
+ r_type(parr), num_refs, (ulong) obj);
+ return;
+ }
+ /* If there are any leftover packed elements, we don't */
+ /* worry about them, since they can't be dangling references. */
+ refset_null(obj, size / sizeof(ref));
+ mem->lost.refs += size;
+ }
+}
+
+/* Allocate a string ref. */
+int
+gs_alloc_string_ref(gs_ref_memory_t * mem, ref * psref,
+ uint attrs, uint nbytes, client_name_t cname)
+{
+ byte *str = gs_alloc_string((gs_memory_t *) mem, nbytes, cname);
+
+ if (str == 0)
+ return_error(e_VMerror);
+ make_string(psref, attrs | mem->space, nbytes, str);
+ return 0;
+}
diff --git a/pstoraster/ialloc.h b/pstoraster/ialloc.h
new file mode 100644
index 000000000..b24b574dd
--- /dev/null
+++ b/pstoraster/ialloc.h
@@ -0,0 +1,125 @@
+/* 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$ */
+/* Interface to Ghostscript interpreter memory allocator */
+
+#ifndef ialloc_INCLUDED
+# define ialloc_INCLUDED
+
+#include "imemory.h"
+
+/*
+ * Define the interpreter memory manager instance.
+ */
+extern gs_dual_memory_t gs_imemory;
+
+#define idmemory (&gs_imemory)
+#define iimemory (gs_imemory.current)
+#define imemory ((gs_memory_t *)iimemory)
+#define iimemory_local (gs_imemory.space_local)
+#define imemory_local ((gs_memory_t *)iimemory_local)
+#define iimemory_global (gs_imemory.space_global)
+#define imemory_global ((gs_memory_t *)iimemory_global)
+#define iimemory_system (gs_imemory.space_system)
+#define imemory_system ((gs_memory_t *)iimemory_system)
+
+/*
+ * Aliases for invoking the standard allocator interface.
+ */
+#define ialloc_bytes(nbytes, cname)\
+ gs_alloc_bytes(imemory, nbytes, cname)
+#define ialloc_struct(typ, pstype, cname)\
+ gs_alloc_struct(imemory, typ, pstype, cname)
+#define ialloc_byte_array(nelts, esize, cname)\
+ gs_alloc_byte_array(imemory, nelts, esize, cname)
+#define ialloc_struct_array(nelts, typ, pstype, cname)\
+ gs_alloc_struct_array(imemory, nelts, typ, pstype, cname)
+#define ifree_object(data, cname)\
+ gs_free_object(imemory, data, cname)
+#define ialloc_string(nbytes, cname)\
+ gs_alloc_string(imemory, nbytes, cname)
+#define ifree_string(data, nbytes, cname)\
+ gs_free_string(imemory, data, nbytes, cname)
+
+/* Initialize the interpreter's allocator. */
+void ialloc_init(P3(gs_raw_memory_t *, uint, bool));
+
+/* Resize a string. */
+#define iresize_string(data, oldn, newn, cname)\
+ gs_resize_string(imemory, data, oldn, newn, cname)
+
+/* ------ Internal routines ------ */
+
+/* Reset the request values that identify the cause of a GC. */
+void ialloc_reset_requested(P1(gs_dual_memory_t *));
+
+/* Validate the contents of memory. */
+void ialloc_validate_spaces(P1(const gs_dual_memory_t *));
+
+#define ivalidate_spaces() ialloc_validate_spaces(idmemory)
+
+/*
+ * Local/global VM management.
+ */
+
+/* Get the space attribute of the current allocator. */
+#define ialloc_space(dmem) ((dmem)->current_space)
+#define icurrent_space ialloc_space(idmemory)
+extern uint imemory_space(P1(gs_ref_memory_t *));
+
+/* Select the allocation space. */
+void ialloc_set_space(P2(gs_dual_memory_t *, uint));
+
+/*
+ * Ref-related facilities.
+ */
+
+#ifdef r_type /* i.e., we know about refs */
+
+/* Allocate and free ref arrays. */
+#define ialloc_ref_array(paref, attrs, nrefs, cname)\
+ gs_alloc_ref_array(iimemory, paref, attrs, nrefs, cname)
+#define iresize_ref_array(paref, nrefs, cname)\
+ gs_resize_ref_array(iimemory, paref, nrefs, cname)
+#define ifree_ref_array(paref, cname)\
+ gs_free_ref_array(iimemory, paref, cname)
+
+/* Allocate a string ref. */
+#define ialloc_string_ref(psref, attrs, nbytes, cname)\
+ gs_alloc_string_ref(iimemory, psref, attrs, nbytes, cname)
+
+/* Make a ref for a newly allocated structure. */
+#define make_istruct(pref,attrs,ptr)\
+ make_struct(pref, (attrs) | icurrent_space, ptr)
+#define make_istruct_new(pref,attrs,ptr)\
+ make_struct_new(pref, (attrs) | icurrent_space, ptr)
+#define make_iastruct(pref,attrs,ptr)\
+ make_astruct(pref, (attrs) | icurrent_space, ptr)
+#define make_iastruct_new(pref,attrs,ptr)\
+ make_astruct_new(pref, (attrs) | icurrent_space, ptr)
+
+#endif /* ifdef r_type */
+
+#endif /* ialloc_INCLUDED */
diff --git a/pstoraster/iastate.h b/pstoraster/iastate.h
new file mode 100644
index 000000000..4fbfe892a
--- /dev/null
+++ b/pstoraster/iastate.h
@@ -0,0 +1,35 @@
+/* Copyright (C) 1993, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of GNU Ghostscript.
+
+ GNU Ghostscript is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
+ to anyone for the consequences of using it or for whether it serves any
+ particular purpose or works at all, unless he says so in writing. Refer
+ to the GNU General Public License for full details.
+
+ Everyone is granted permission to copy, modify and redistribute GNU
+ Ghostscript, but only under the conditions described in the GNU General
+ Public License. A copy of this license is supposed to have been given
+ to you along with GNU Ghostscript so you can know your rights and
+ responsibilities. It should be in a file named COPYING. Among other
+ things, the copyright notice and this notice must be preserved on all
+ copies.
+
+ Aladdin Enterprises 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 gsmemory.h, gsstruct.h */
+
+#ifndef iastate_INCLUDED
+# define iastate_INCLUDED
+
+#include "gxalloc.h"
+#include "istruct.h"
+#include "ialloc.h"
+
+#endif /* iastate_INCLUDED */
diff --git a/pstoraster/iastruct.h b/pstoraster/iastruct.h
new file mode 100644
index 000000000..11080d0fd
--- /dev/null
+++ b/pstoraster/iastruct.h
@@ -0,0 +1,34 @@
+/* Copyright (C) 1993, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of GNU Ghostscript.
+
+ GNU Ghostscript is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
+ to anyone for the consequences of using it or for whether it serves any
+ particular purpose or works at all, unless he says so in writing. Refer
+ to the GNU General Public License for full details.
+
+ Everyone is granted permission to copy, modify and redistribute GNU
+ Ghostscript, but only under the conditions described in the GNU General
+ Public License. A copy of this license is supposed to have been given
+ to you along with GNU Ghostscript so you can know your rights and
+ responsibilities. It should be in a file named COPYING. Among other
+ things, the copyright notice and this notice must be preserved on all
+ copies.
+
+ Aladdin Enterprises 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 memory manager implementation structures */
+
+#ifndef iastruct_INCLUDED
+# define iastruct_INCLUDED
+
+#include "gxobj.h"
+#include "ialloc.h"
+
+#endif /* iastruct_INCLUDED */
diff --git a/pstoraster/ibnum.c b/pstoraster/ibnum.c
new file mode 100644
index 000000000..e48c8105d
--- /dev/null
+++ b/pstoraster/ibnum.c
@@ -0,0 +1,222 @@
+/* Copyright (C) 1990, 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$ */
+/* Level 2 encoded number reading utilities for Ghostscript */
+#include "math_.h"
+#include "memory_.h"
+#include "ghost.h"
+#include "errors.h"
+#include "stream.h"
+#include "ibnum.h"
+#include "imemory.h" /* for iutil.h */
+#include "iutil.h"
+
+/* Define the number of bytes for a given format of encoded number. */
+const byte enc_num_bytes[] = {
+ enc_num_bytes_values
+};
+
+/* ------ Encoded number reading ------ */
+
+/* Set up to read from an encoded number array/string. */
+/* Return <0 for error, or a number format. */
+int
+num_array_format(const ref * op)
+{
+ switch (r_type(op)) {
+ case t_string:
+ {
+ /* Check that this is a legitimate encoded number string. */
+ const byte *bp = op->value.bytes;
+ int format;
+
+ if (r_size(op) < 4 || bp[0] != bt_num_array_value)
+ return_error(e_rangecheck);
+ format = bp[1];
+ if (!num_is_valid(format) ||
+ sdecodeshort(bp + 2, format) !=
+ (r_size(op) - 4) / encoded_number_bytes(format)
+ )
+ return_error(e_rangecheck);
+ return format;
+ }
+ case t_array:
+ case t_mixedarray:
+ case t_shortarray:
+ return num_array;
+ default:
+ return_error(e_typecheck);
+ }
+}
+
+/* Get the number of elements in an encoded number array/string. */
+uint
+num_array_size(const ref * op, int format)
+{
+ return (format == num_array ? r_size(op) :
+ (r_size(op) - 4) / encoded_number_bytes(format));
+}
+
+/* Get an encoded number from an array/string according to the given format. */
+/* Put the value in np->value.{intval,realval}. */
+/* Return t_int if integer, t_real if real, t_null if end of stream, */
+/* or an error if the format is invalid. */
+int
+num_array_get(const ref * op, int format, uint index, ref * np)
+{
+ if (format == num_array) {
+ int code = array_get(op, (long)index, np);
+
+ if (code < 0)
+ return t_null;
+ switch (r_type(np)) {
+ case t_integer:
+ return t_integer;
+ case t_real:
+ return t_real;
+ default:
+ return_error(e_rangecheck);
+ }
+ } else {
+ uint nbytes = encoded_number_bytes(format);
+
+ if (index >= (r_size(op) - 4) / nbytes)
+ return t_null;
+ return sdecode_number(op->value.bytes + 4 + index * nbytes,
+ format, np);
+ }
+}
+
+/* Internal routine to decode a number in a given format. */
+/* Same returns as sget_encoded_number. */
+static const double binary_scale[32] = {
+#define EXPN2(n) (0.5 / (1L << (n-1)))
+ 1.0, EXPN2(1), EXPN2(2), EXPN2(3),
+ EXPN2(4), EXPN2(5), EXPN2(6), EXPN2(7),
+ EXPN2(8), EXPN2(9), EXPN2(10), EXPN2(11),
+ EXPN2(12), EXPN2(13), EXPN2(14), EXPN2(15),
+ EXPN2(16), EXPN2(17), EXPN2(18), EXPN2(19),
+ EXPN2(20), EXPN2(21), EXPN2(22), EXPN2(23),
+ EXPN2(24), EXPN2(25), EXPN2(26), EXPN2(27),
+ EXPN2(28), EXPN2(29), EXPN2(30), EXPN2(31)
+#undef EXPN2
+};
+int
+sdecode_number(const byte * str, int format, ref * np)
+{
+ switch (format & 0x170) {
+ case num_int32:
+ case num_int32 + 16:
+ if ((format & 31) == 0) {
+ np->value.intval = sdecodelong(str, format);
+ return t_integer;
+ } else {
+ np->value.realval =
+ (double)sdecodelong(str, format) *
+ binary_scale[format & 31];
+ return t_real;
+ }
+ case num_int16:
+ if ((format & 15) == 0) {
+ np->value.intval = sdecodeshort(str, format);
+ return t_integer;
+ } else {
+ np->value.realval =
+ sdecodeshort(str, format) *
+ binary_scale[format & 15];
+ return t_real;
+ }
+ case num_float:
+ np->value.realval = sdecodefloat(str, format);
+ return t_real;
+ default:
+ return_error(e_syntaxerror); /* invalid format?? */
+ }
+}
+
+/* ------ Decode number ------ */
+
+/* Decode encoded numbers from a string according to format. */
+
+/* Decode a (16-bit, signed or unsigned) short. */
+uint
+sdecodeushort(const byte * p, int format)
+{
+ int a = p[0], b = p[1];
+
+ return (num_is_lsb(format) ? (b << 8) + a : (a << 8) + b);
+}
+int
+sdecodeshort(const byte * p, int format)
+{
+ int v = (int)sdecodeushort(p, format);
+
+ return (v & 0x7fff) - (v & 0x8000);
+}
+
+/* Decode a (32-bit, signed) long. */
+long
+sdecodelong(const byte * p, int format)
+{
+ int a = p[0], b = p[1], c = p[2], d = p[3];
+ long v = (num_is_lsb(format) ?
+ ((long)d << 24) + ((long)c << 16) + (b << 8) + a :
+ ((long)a << 24) + ((long)b << 16) + (c << 8) + d);
+
+ /*
+ * The following is only needed if sizeof(long) > 4, but it does
+ * no harm if sizeof(long) == 4.
+ */
+ return (v ^ 0x80000000L) - 0x80000000L;
+}
+
+/* Decode a float. We assume that native floats occupy 32 bits. */
+float
+sdecodefloat(const byte * p, int format)
+{
+ bits32 lnum = (bits32) sdecodelong(p, format);
+ float fnum;
+
+#if !arch_floats_are_IEEE
+ if (format != num_float_native) {
+ /* We know IEEE floats take 32 bits. */
+ /* Convert IEEE float to native float. */
+ int sign_expt = lnum >> 23;
+ int expt = sign_expt & 0xff;
+ long mant = lnum & 0x7fffff;
+
+ if (expt == 0 && mant == 0)
+ fnum = 0;
+ else {
+ mant += 0x800000;
+ fnum = (float)ldexp((float)mant, expt - 127 - 24);
+ }
+ if (sign_expt & 0x100)
+ fnum = -fnum;
+ } else
+#endif
+ fnum = *(float *)&lnum;
+ return fnum;
+}
diff --git a/pstoraster/ibnum.h b/pstoraster/ibnum.h
new file mode 100644
index 000000000..7d91fadfb
--- /dev/null
+++ b/pstoraster/ibnum.h
@@ -0,0 +1,71 @@
+/* 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$ */
+/* Requires stream.h */
+
+#ifndef ibnum_INCLUDED
+# define ibnum_INCLUDED
+
+/* Define the byte that begins an encoded number string. */
+/* (This is the same as the value of bt_num_array in btoken.h.) */
+#define bt_num_array_value 149
+
+/* Homogenous number array formats. */
+/* The default for numbers is big-endian. */
+#define num_int32 0 /* [0..31] */
+#define num_int16 32 /* [32..47] */
+#define num_float 48
+#define num_float_IEEE num_float
+#define num_float_native (num_float + 1)
+#define num_msb 0
+#define num_lsb 128
+#define num_is_lsb(format) ((format) >= num_lsb)
+#define num_is_valid(format) (((format) & 127) <= 49)
+/* Special "format" for reading from an array. */
+/* num_msb/lsb is not used in this case. */
+#define num_array 256
+/* Define the number of bytes for a given format of encoded number. */
+extern const byte enc_num_bytes[]; /* in ibnum.c */
+
+#define enc_num_bytes_values\
+ 4, 4, 2, 4, 0, 0, 0, 0,\
+ 4, 4, 2, 4, 0, 0, 0, 0,\
+ sizeof(ref)
+#define encoded_number_bytes(format)\
+ (enc_num_bytes[(format) >> 4])
+
+/* Read from an array or encoded number string. */
+int num_array_format(P1(const ref *)); /* returns format or error */
+uint num_array_size(P2(const ref *, int));
+int num_array_get(P4(const ref *, int, uint, ref *));
+
+/* Decode a number from a string with appropriate byte swapping. */
+int sdecode_number(P3(const byte *, int, ref *));
+int sdecodeshort(P2(const byte *, int));
+uint sdecodeushort(P2(const byte *, int));
+long sdecodelong(P2(const byte *, int));
+float sdecodefloat(P2(const byte *, int));
+
+#endif /* ibnum_INCLUDED */
diff --git a/pstoraster/iccinit0.c b/pstoraster/iccinit0.c
new file mode 100644
index 000000000..c7b60c7a3
--- /dev/null
+++ b/pstoraster/iccinit0.c
@@ -0,0 +1,31 @@
+/* Copyright (C) 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of GNU Ghostscript.
+
+ GNU Ghostscript is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
+ to anyone for the consequences of using it or for whether it serves any
+ particular purpose or works at all, unless he says so in writing. Refer
+ to the GNU General Public License for full details.
+
+ Everyone is granted permission to copy, modify and redistribute GNU
+ Ghostscript, but only under the conditions described in the GNU General
+ Public License. A copy of this license is supposed to have been given
+ to you along with GNU Ghostscript so you can know your rights and
+ responsibilities. It should be in a file named COPYING. Among other
+ things, the copyright notice and this notice must be preserved on all
+ copies.
+
+ Aladdin Enterprises 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$ */
+/* Initialization string for non-compiled initialization */
+#include "stdpre.h"
+
+/* gsmain.c recognizes an empty init string specially. */
+const byte gs_init_string[] = { 0 };
+const uint gs_init_string_sizeof = 0;
diff --git a/pstoraster/ichar.h b/pstoraster/ichar.h
new file mode 100644
index 000000000..fcc34e879
--- /dev/null
+++ b/pstoraster/ichar.h
@@ -0,0 +1,72 @@
+/* Copyright (C) 1994, 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$ */
+/* Requires gxchar.h */
+
+#ifndef ichar_INCLUDED
+# define ichar_INCLUDED
+
+/*
+ * All the character rendering operators use the execution stack
+ * for loop control -- see estack.h for details.
+ * The information pushed by these operators is as follows:
+ * the enumerator (t_struct, a gs_show_enum);
+ * a slot for the procedure for kshow or cshow (probably t_array) or
+ * the string or array for [x][y]show (t_string or t_array);
+ * a slot for the string/array index for [x][y]show (t_integer);
+ * a slot for the saved o-stack depth for cshow or stringwidth,
+ * and for error recovery (t_integer);
+ * a slot for the saved d-stack depth ditto (t_integer);
+ * a slot for the saved gstate level ditto (t_integer);
+ * the procedure to be called at the end of the enumeration
+ * (t_operator, but called directly, not by the interpreter);
+ * the usual e-stack mark (t_null).
+ */
+#define snumpush 8
+#define esenum(ep) r_ptr(ep, gs_show_enum)
+#define senum esenum(esp)
+#define esslot(ep) ((ep)[-1])
+#define sslot esslot(esp)
+#define essindex(ep) ((ep)[-2])
+#define ssindex essindex(esp)
+#define esodepth(ep) ((ep)[-3])
+#define sodepth esodepth(esp)
+#define esddepth(ep) ((ep)[-4])
+#define sddepth esddepth(esp)
+#define esgslevel(ep) ((ep)[-5])
+#define sgslevel esgslevel(esp)
+#define eseproc(ep) ((ep)[-6])
+#define seproc eseproc(esp)
+
+/* Procedures exported by zchar.c for zchar1.c, zchar2.c, and/or zcharcid.c. */
+gs_show_enum *op_show_find(P0());
+int op_show_setup(P2(os_ptr, gs_show_enum **));
+int op_show_enum_setup(P2(os_ptr, gs_show_enum **));
+void op_show_finish_setup(P3(gs_show_enum *, int, op_proc_p));
+int op_show_continue(P1(os_ptr));
+int op_show_continue_dispatch(P2(os_ptr, int));
+int op_show_free(P1(int));
+
+#endif /* ichar_INCLUDED */
diff --git a/pstoraster/icharout.h b/pstoraster/icharout.h
new file mode 100644
index 000000000..2e8993466
--- /dev/null
+++ b/pstoraster/icharout.h
@@ -0,0 +1,59 @@
+/* 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$ */
+/* Interface to zcharout.c */
+
+#ifndef icharout_INCLUDED
+# define icharout_INCLUDED
+
+/* Execute an outline defined by a PostScript procedure. */
+int zchar_exec_char_proc(P1(os_ptr));
+
+/*
+ * Get the metrics for a character from the Metrics dictionary of a base
+ * font. If present, store the l.s.b. in psbw[0,1] and the width in
+ * psbw[2,3].
+ */
+typedef enum {
+ metricsNone = 0,
+ metricsWidthOnly = 1,
+ metricsSideBearingAndWidth = 2
+} metrics_present;
+int /*metrics_present*/
+ zchar_get_metrics(P3(const gs_font_base * pbfont, const ref * pcnref,
+ double psbw[4]));
+
+/*
+ * Consult Metrics2 and CDevProc, and call setcachedevice[2]. Return
+ * o_push_estack if we had to call a CDevProc, or if we are skipping the
+ * rendering process (only getting the metrics).
+ */
+int zchar_set_cache(P8(os_ptr op, const gs_font_base * pbfont,
+ const ref * pcnref, const double psb[2],
+ const double pwidth[2], const gs_rect * pbbox,
+ int (*cont_fill) (P1(os_ptr)),
+ int (*cont_stroke) (P1(os_ptr))));
+
+#endif /* icharout_INCLUDED */
diff --git a/pstoraster/icie.h b/pstoraster/icie.h
new file mode 100644
index 000000000..69ec0fa93
--- /dev/null
+++ b/pstoraster/icie.h
@@ -0,0 +1,96 @@
+/* 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$ */
+/* Internal definitions for interpreter CIE color handling */
+
+#ifndef icie_INCLUDED
+# define icie_INCLUDED
+
+/*
+ * All of the routines below are exported by zcie.c for zcrd.c,
+ * except for cie_cache_joint which is exported by zcrd.c for zcie.c.
+ */
+
+/* ------ Parameter acquisition ------ */
+
+/* Get a range array parameter from a dictionary. */
+/* We know that count <= 4. */
+int dict_ranges_param(P4(const ref * pdref, const char *kstr, int count,
+ gs_range * prange));
+
+/* Get 3 ranges from a dictionary. */
+#define dict_range3_param(pdref, kstr, prange3)\
+ dict_ranges_param(pdref, kstr, 3, (prange3)->ranges)
+
+/* Get a 3x3 matrix parameter from a dictionary. */
+#define dict_matrix3_param(op, kstr, pmat)\
+ dict_float_array_param(op, kstr, 9, (float *)pmat,\
+ (const float *)&Matrix3_default)
+#define matrix3_ok 9
+
+/* Get an array of procedures from a dictionary. */
+/* We know count <= countof(empty_procs). */
+int dict_proc_array_param(P4(const ref * pdict, const char *kstr,
+ uint count, ref * pparray));
+
+/* Get 3 procedures from a dictionary. */
+#define dict_proc3_param(op, kstr, pparray)\
+ dict_proc_array_param(op, kstr, 3, pparray)
+
+/* Get WhitePoint and BlackPoint values. */
+int cie_points_param(P2(const ref * pdref, gs_cie_wb * pwb));
+
+/* Process a 3- or 4-dimensional lookup table from a dictionary. */
+/* The caller has set pclt->n and pclt->m. */
+/* ptref is known to be a readable array of size at least n+1. */
+int cie_table_param(P3(const ref * ptable, gx_color_lookup_table * pclt,
+ gs_memory_t * mem));
+
+/* ------ Internal routines ------ */
+
+int cie_cache_push_finish(P3(int (*finish_proc) (P1(os_ptr)),
+ gs_ref_memory_t * imem, void *data));
+int cie_prepare_cache(P6(const gs_range * domain, const ref * proc,
+ cie_cache_floats * pcache, void *container,
+ gs_ref_memory_t * imem, client_name_t cname));
+int cie_prepare_caches_4(P9(const gs_range * domains, const ref * procs,
+ cie_cache_floats * pc0,
+ cie_cache_floats * pc1,
+ cie_cache_floats * pc2,
+ cie_cache_floats * pc3 /* may be 0 */,
+ void *container,
+ gs_ref_memory_t * imem, client_name_t cname));
+#define cie_prepare_cache3(d3,p3,c3,pcie,imem,cname)\
+ cie_prepare_caches_4((d3)->ranges, p3,\
+ &(c3)->floats, &(c3)[1].floats, &(c3)[2].floats,\
+ NULL, pcie, imem, cname)
+#define cie_prepare_cache4(d4,p4,c4,pcie,imem,cname)\
+ cie_prepare_caches_4((d4)->ranges, p4,\
+ &(c4)->floats, &(c4)[1].floats, &(c4)[2].floats,\
+ &(c4)[3].floats, pcie, imem, cname)
+
+int cie_cache_joint(P2(const ref_cie_render_procs *, gs_state *));
+
+#endif /* icie_INCLUDED */
diff --git a/pstoraster/icolor.h b/pstoraster/icolor.h
new file mode 100644
index 000000000..ea12e0b9b
--- /dev/null
+++ b/pstoraster/icolor.h
@@ -0,0 +1,54 @@
+/* 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$ */
+/* Declarations for transfer function & similar cache remapping */
+
+#ifndef icolor_INCLUDED
+# define icolor_INCLUDED
+
+/* Define the number of stack slots needed for zcolor_remap_one. */
+/* The client is responsible for doing check_e/ostack or the equivalent */
+/* before calling zcolor_remap_one. */
+extern const int zcolor_remap_one_ostack;
+extern const int zcolor_remap_one_estack;
+
+/* Schedule the sampling and reloading of a cache. */
+int zcolor_remap_one(P5(const ref *, os_ptr, gx_transfer_map *,
+ const gs_state *, int (*)(P1(os_ptr))));
+
+/* Reload a cache with entries in [0..1] after sampling. */
+int zcolor_remap_one_finish(P1(os_ptr));
+
+/* Reload a cache with entries in [-1..1] after sampling. */
+int zcolor_remap_one_signed_finish(P1(os_ptr));
+
+/* Recompute the effective transfer functions and invalidate the current */
+/* color after cache reloading. */
+int zcolor_reset_transfer(P1(os_ptr));
+
+/* Invalidate the current color after cache reloading. */
+int zcolor_remap_color(P1(os_ptr));
+
+#endif /* icolor_INCLUDED */
diff --git a/pstoraster/iconfig.c b/pstoraster/iconfig.c
new file mode 100644
index 000000000..ca60afb2b
--- /dev/null
+++ b/pstoraster/iconfig.c
@@ -0,0 +1,74 @@
+/* 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$ */
+/* Configuration-dependent tables and initialization for interpreter */
+#include "stdio_.h" /* stdio for stream.h */
+#include "gstypes.h"
+#include "gsmemory.h" /* for iminst.h */
+#include "gconf.h"
+#include "iref.h"
+#include "ivmspace.h"
+#include "opdef.h"
+#include "iminst.h"
+
+/* Define the default values for an interpreter instance. */
+const gs_main_instance gs_main_instance_init_values =
+{gs_main_instance_default_init_values};
+
+/* Set up the .ps file name string array. */
+/* We fill in the lengths at initialization time. */
+#define ref_(t) struct { struct tas_s tas; t value; }
+#define string_(s,len)\
+ { { (t_string<<r_type_shift) + a_readonly + avm_foreign, len }, s },
+#define psfile_(fns,len) string_(fns,len)
+const ref_(const char *) gs_init_file_array[] = {
+#include "gconf.h"
+ string_(0, 0)
+};
+#undef psfile_
+
+/* Set up the emulator name string array similarly. */
+#define emulator_(ems,len) string_(ems,len)
+const ref_(const char *) gs_emulator_name_array[] = {
+#include "gconf.h"
+ string_(0, 0)
+};
+#undef emulator_
+
+/* Initialize the operators. */
+ /* Declare the externs. */
+#define oper_(xx_op_defs) extern const op_def xx_op_defs[];
+#include "gconf.h"
+oper_(interp_op_defs) /* Interpreter operators */
+#undef oper_
+
+const op_def *const op_defs_all[] = {
+ /* Create the table. */
+#define oper_(defs) defs,
+#include "gconf.h"
+ oper_(interp_op_defs) /* Interpreter operators */
+#undef oper_
+ 0
+};
diff --git a/pstoraster/icontext.c b/pstoraster/icontext.c
new file mode 100644
index 000000000..84f00f2ec
--- /dev/null
+++ b/pstoraster/icontext.c
@@ -0,0 +1,275 @@
+/* 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$ */
+/* Context state operations */
+#include "ghost.h"
+#include "gsstruct.h" /* for gxalloc.h */
+#include "gxalloc.h"
+#include "errors.h"
+#include "stream.h" /* for files.h */
+#include "files.h"
+#include "idict.h"
+#include "igstate.h"
+#include "icontext.h"
+#include "interp.h"
+#include "isave.h"
+#include "dstack.h"
+#include "estack.h"
+#include "ostack.h"
+#include "store.h"
+
+/* Define the initial stack sizes. */
+#define DSTACK_INITIAL 20
+#define ESTACK_INITIAL 250
+#define OSTACK_INITIAL 200
+
+/* Per-context state stored in statics */
+extern ref ref_array_packing;
+extern ref ref_binary_object_format;
+extern long zrand_state;
+
+ /*extern ref ref_stdio[3]; *//* in files.h */
+
+/* Initialization procedures */
+void zrand_state_init(P1(long *));
+
+/* GC descriptors */
+extern_st(st_ref_stack);
+#define pcst ((gs_context_state_t *)vptr)
+private
+CLEAR_MARKS_PROC(context_state_clear_marks)
+{
+ r_clear_attrs(&pcst->userparams, l_mark);
+}
+private
+ENUM_PTRS_BEGIN(context_state_enum_ptrs) return 0;
+
+ENUM_PTR3(0, gs_context_state_t, dstack, estack, ostack);
+ENUM_PTR3(3, gs_context_state_t, pgs, stdio[0].value.pstruct,
+ stdio[1].value.pstruct);
+case 6:
+ENUM_RETURN_REF(&pcst->userparams);
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(context_state_reloc_ptrs);
+RELOC_PTR3(gs_context_state_t, dstack, estack, ostack);
+RELOC_PTR3(gs_context_state_t, pgs, stdio[0].value.pstruct,
+ stdio[1].value.pstruct);
+RELOC_REF_VAR(pcst->userparams);
+r_clear_attrs(&pcst->userparams, l_mark);
+RELOC_PTRS_END
+#undef pcst
+public_st_context_state();
+
+/* Allocate the state of a context. */
+ int
+ context_state_alloc(gs_context_state_t ** ppcst,
+ const gs_dual_memory_t * dmem)
+{
+ gs_ref_memory_t *mem = dmem->space_local;
+ gs_context_state_t *pcst = *ppcst;
+ int code;
+ int i;
+
+ if (pcst == 0) {
+ pcst = gs_alloc_struct((gs_memory_t *) mem, gs_context_state_t,
+ &st_context_state, "context_state_alloc");
+ if (pcst == 0)
+ return_error(e_VMerror);
+ }
+ code = gs_interp_alloc_stacks(mem, pcst);
+ if (code < 0)
+ goto x0;
+ pcst->pgs = int_gstate_alloc(mem);
+ if (pcst->pgs == 0) {
+ code = gs_note_error(e_VMerror);
+ goto x1;
+ }
+ pcst->memory = *dmem;
+ make_false(&pcst->array_packing);
+ make_int(&pcst->binary_object_format, 0);
+ zrand_state_init(&pcst->rand_state);
+ pcst->usertime_total = 0;
+ pcst->keep_usertime = false;
+ { /*
+ * Create an empty userparams dictionary of the right size.
+ * If we can't determine the size, pick an arbitrary one.
+ */
+ ref *puserparams;
+ uint size;
+
+ if (dict_find_string(systemdict, "userparams", &puserparams) >= 0)
+ size = dict_length(puserparams);
+ else
+ size = 20;
+ code = dict_alloc(pcst->memory.space_local, size, &pcst->userparams);
+ if (code < 0)
+ goto x2;
+ /* PostScript code initializes the user parameters. */
+ }
+ /* The initial stdio values are bogus.... */
+ make_file(&pcst->stdio[0], 0, 1, invalid_file_entry);
+ make_file(&pcst->stdio[1], 0, 1, invalid_file_entry);
+ for (i = countof(pcst->memory.spaces.indexed); --i >= 0;)
+ if (dmem->spaces.indexed[i] != 0)
+ ++(dmem->spaces.indexed[i]->num_contexts);
+ *ppcst = pcst;
+ return 0;
+ x2:gs_state_free(pcst->pgs);
+ x1:gs_interp_free_stacks(mem, pcst);
+ x0:if (*ppcst == 0)
+ gs_free_object((gs_memory_t *) mem, pcst, "context_state_alloc");
+ return code;
+}
+
+/* Load the interpreter state from a context. */
+int
+context_state_load(const gs_context_state_t * pcst)
+{
+ gs_ref_memory_t *lmem = iimemory_local;
+ uint space = r_space(systemdict);
+ int code;
+
+ d_stack = *pcst->dstack;
+ e_stack = *pcst->estack;
+ o_stack = *pcst->ostack;
+ igs = pcst->pgs;
+ gs_imemory = pcst->memory;
+ ref_array_packing = pcst->array_packing;
+ ref_binary_object_format = pcst->binary_object_format;
+ zrand_state = pcst->rand_state;
+ /*
+ * Set systemdict.userparams to the saved copy, and then
+ * set the actual user parameters. Be careful to disable both
+ * space checking and save checking while we do this.
+ */
+ r_set_space(systemdict, avm_max);
+ alloc_set_not_in_save(idmemory);
+ code = dict_put_string(systemdict, "userparams", &pcst->userparams);
+ if (code >= 0)
+ code = set_user_params(&pcst->userparams);
+ ref_stdio[0] = pcst->stdio[0];
+ ref_stdio[1] = pcst->stdio[1];
+ if (iimemory_local != lmem) {
+ /*
+ * Switch references in systemdict to local objects.
+ * userdict.localdicts holds these objects.
+ */
+ const ref *puserdict =
+ ref_stack_index(&d_stack, ref_stack_count(&d_stack) - 1 -
+ dstack_userdict_index);
+ ref *plocaldicts;
+
+ if (dict_find_string(puserdict, "localdicts", &plocaldicts) > 0 &&
+ r_has_type(plocaldicts, t_dictionary)
+ ) {
+ dict_copy(plocaldicts, systemdict);
+ }
+ }
+ r_set_space(systemdict, space);
+ if (idmemory->save_level > 0)
+ alloc_set_in_save(idmemory);
+ esfile_clear_cache();
+ dict_set_top(); /* reload dict stack cache */
+ return code;
+}
+
+/* Store the interpreter state in a context. */
+int
+context_state_store(gs_context_state_t * pcst)
+{
+ ref_stack_cleanup(&d_stack);
+ ref_stack_cleanup(&e_stack);
+ ref_stack_cleanup(&o_stack);
+ *pcst->dstack = d_stack;
+ *pcst->estack = e_stack;
+ *pcst->ostack = o_stack;
+ pcst->pgs = igs;
+ pcst->memory = gs_imemory;
+ pcst->array_packing = ref_array_packing;
+ pcst->binary_object_format = ref_binary_object_format;
+ pcst->rand_state = zrand_state;
+ /*
+ * The user parameters in systemdict.userparams are kept
+ * up to date by PostScript code, but we still need to save
+ * systemdict.userparams to get the correct l_new flag.
+ */
+ {
+ ref *puserparams;
+
+ if (dict_find_string(systemdict, "userparams", &puserparams) < 0)
+ return_error(e_Fatal);
+ pcst->userparams = *puserparams;
+ }
+ pcst->stdio[0] = ref_stdio[0];
+ pcst->stdio[1] = ref_stdio[1];
+ return 0;
+}
+
+/* Free the state of a context. */
+bool
+context_state_free(gs_context_state_t * pcst)
+{
+ gs_ref_memory_t *mem = pcst->memory.space_local;
+ int freed = 0;
+ int i;
+
+ /*
+ * If this context is the last one referencing a particular VM
+ * (local / global / system), free the entire VM space;
+ * otherwise, just free the context-related structures.
+ */
+ for (i = countof(pcst->memory.spaces.indexed); --i >= 0;) {
+ if (pcst->memory.spaces.indexed[i] != 0 &&
+ !--(pcst->memory.spaces.indexed[i]->num_contexts)
+ ) {
+/****** FREE THE ENTIRE SPACE ******/
+ freed |= 1 << i;
+ }
+ }
+ /*
+ * If we freed any spaces at all, we must have freed the local
+ * VM where the context structure and its substructures were
+ * allocated.
+ */
+ if (freed)
+ return freed;
+ {
+ gs_state *pgs = pcst->pgs;
+
+ gs_grestoreall(pgs);
+ /* Patch the saved pointer so we can do the last grestore. */
+ {
+ gs_state *saved = gs_state_saved(pgs);
+
+ gs_state_swap_saved(saved, saved);
+ }
+ gs_grestore(pgs);
+ gs_state_swap_saved(pgs, (gs_state *) 0);
+ gs_state_free(pgs);
+ }
+/****** FREE USERPARAMS ******/
+ gs_interp_free_stacks(mem, pcst);
+ return false;
+}
diff --git a/pstoraster/icontext.h b/pstoraster/icontext.h
new file mode 100644
index 000000000..b0152924d
--- /dev/null
+++ b/pstoraster/icontext.h
@@ -0,0 +1,59 @@
+/* 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$ */
+/* Externally visible context state */
+/* Requires iref.h, stdio_.h */
+
+#ifndef icontext_INCLUDED
+# define icontext_INCLUDED
+
+#include "gsstruct.h" /* for extern_st */
+#include "icstate.h"
+
+/* Declare the GC descriptor for context states. */
+extern_st(st_context_state);
+
+/*
+ * Define the procedure for resetting user parameters when switching
+ * contexts. This is defined in either zusparam.c or inouparm.c.
+ */
+extern int set_user_params(P1(const ref * paramdict));
+
+/* Allocate the state of a context, always in local VM. */
+/* If *ppcst == 0, allocate the state object as well. */
+int context_state_alloc(P2(gs_context_state_t ** ppcst,
+ const gs_dual_memory_t * dmem));
+
+/* Load the state of the interpreter from a context. */
+int context_state_load(P1(const gs_context_state_t *));
+
+/* Store the state of the interpreter into a context. */
+int context_state_store(P1(gs_context_state_t *));
+
+/* Free the contents of the state of a context, always to its local VM. */
+/* Return a mask of which of its VMs, if any, we freed. */
+int context_state_free(P1(gs_context_state_t *));
+
+#endif /* icontext_INCLUDED */
diff --git a/pstoraster/icsmap.h b/pstoraster/icsmap.h
new file mode 100644
index 000000000..9521052fb
--- /dev/null
+++ b/pstoraster/icsmap.h
@@ -0,0 +1,45 @@
+/* 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$ */
+/* Interface to shared routines for loading the cached color space maps. */
+
+#ifndef icsmap_INCLUDED
+# define icsmap_INCLUDED
+
+/*
+ * Set up to load a cached map for an Indexed or substituted Separation
+ * color space. The implementation is in zcsindex.c. When the map1
+ * procedure is called, the following structure is on the e_stack:
+ */
+#define num_csme 5
+# define csme_num_components (-4) /* t_integer */
+# define csme_map (-3) /* t_struct (bytes) */
+# define csme_proc (-2) /* -procedure- */
+# define csme_hival (-1) /* t_integer */
+# define csme_index 0 /* t_integer */
+int zcs_begin_map(P5(gs_indexed_map ** pmap, const ref * pproc, int num_entries,
+ const gs_base_color_space * base_space, int (*map1) (P1(os_ptr))));
+
+#endif /* icsmap_INCLUDED */
diff --git a/pstoraster/icstate.h b/pstoraster/icstate.h
new file mode 100644
index 000000000..1183e9d04
--- /dev/null
+++ b/pstoraster/icstate.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$ */
+/* Externally visible context state */
+/* Requires iref.h */
+
+#ifndef icstate_INCLUDED
+# define icstate_INCLUDED
+
+#include "imemory.h"
+
+/*
+ * Define the externally visible state of an interpreter context.
+ * If we aren't supporting Display PostScript features, there is only
+ * a single context.
+ */
+#ifndef gs_context_state_t_DEFINED
+# define gs_context_state_t_DEFINED
+typedef struct gs_context_state_s gs_context_state_t;
+#endif
+#ifndef ref_stack_DEFINED
+# define ref_stack_DEFINED
+typedef struct ref_stack_s ref_stack;
+#endif
+struct gs_context_state_s {
+ ref_stack *dstack;
+ ref_stack *estack;
+ ref_stack *ostack;
+ gs_state *pgs;
+ gs_dual_memory_t memory;
+ ref array_packing; /* t_boolean */
+ ref binary_object_format; /* t_integer */
+ long rand_state; /* (not in Red Book) */
+ long usertime_total; /* total accumulated usertime, */
+ /* not counting current time if running */
+ bool keep_usertime; /* true if context ever executed usertime */
+ /* View clipping is handled in the graphics state. */
+ ref userparams; /* t_dictionary */
+ ref stdio[2]; /* t_file */
+};
+
+/*
+ * We make st_context_state public because interp.c must allocate one,
+ * and zcontext.c must subclass it.
+ */
+/*extern_st(st_context_state); *//* in icontext.h */
+#define public_st_context_state() /* in icontext.c */\
+ gs_public_st_complex_only(st_context_state, gs_context_state_t,\
+ "gs_context_state_t", context_state_clear_marks,\
+ context_state_enum_ptrs, context_state_reloc_ptrs, 0)
+
+#endif /* icstate_INCLUDED */
diff --git a/pstoraster/idebug.c b/pstoraster/idebug.c
new file mode 100644
index 000000000..a472c5b76
--- /dev/null
+++ b/pstoraster/idebug.c
@@ -0,0 +1,299 @@
+/* Copyright (C) 1989, 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$ */
+/* Debugging support for Ghostscript interpreter */
+/* This file must always be compiled with DEBUG set. */
+#undef DEBUG
+#define DEBUG
+#include "string_.h"
+#include "ghost.h"
+#include "ialloc.h" /* for imemory for getting struct type */
+#include "idebug.h" /* defines interface */
+#include "idict.h"
+#include "iname.h"
+#include "ipacked.h"
+#include "istack.h"
+#include "iutil.h"
+#include "ivmspace.h"
+#include "opdef.h"
+
+/* Table of type name strings */
+static const char *const type_strings[] =
+{type_print_strings};
+
+/* First unassigned type index */
+extern const int tx_next_index; /* in interp.c */
+
+/* Print a name. */
+void
+debug_print_name(const ref * pnref)
+{
+ ref sref;
+
+ name_string_ref(pnref, &sref);
+ debug_print_string(sref.value.const_bytes, r_size(&sref));
+}
+
+/* Print a ref. */
+private void
+debug_print_full_ref(const ref * pref)
+{
+ unsigned size = r_size(pref);
+ ref nref;
+
+ dprintf1("(%x)", r_type_attrs(pref));
+ switch (r_type(pref)) {
+ case t_array:
+ dprintf2("array(%u)0x%lx", size, (ulong) pref->value.refs);
+ break;
+ case t_astruct:
+ goto strct;
+ case t_boolean:
+ dprintf1("boolean %x", pref->value.boolval);
+ break;
+ case t_device:
+ dprintf1("device 0x%lx", (ulong) pref->value.pdevice);
+ break;
+ case t_dictionary:
+ dprintf3("dict(%u/%u)0x%lx",
+ dict_length(pref), dict_maxlength(pref),
+ (ulong) pref->value.pdict);
+ break;
+ case t_file:
+ dprintf1("file 0x%lx", (ulong) pref->value.pfile);
+ break;
+ case t_fontID:
+ goto strct;
+ case t_integer:
+ dprintf1("int %ld", pref->value.intval);
+ break;
+ case t_mark:
+ dprintf("mark");
+ break;
+ case t_mixedarray:
+ dprintf2("mixed packedarray(%u)0x%lx", size,
+ (ulong) pref->value.packed);
+ break;
+ case t_name:
+ dprintf2("name(0x%lx#%u)", (ulong) pref->value.pname,
+ name_index(pref));
+ debug_print_name(pref);
+ break;
+ case t_null:
+ dprintf("null");
+ break;
+ case t_oparray:
+ dprintf2("op_array(%u)0x%lx:", size, (ulong) pref->value.const_refs);
+ {
+ const op_array_table *opt = op_index_op_array_table(size);
+
+ name_index_ref(opt->nx_table[size - opt->base_index], &nref);
+ }
+ debug_print_name(&nref);
+ break;
+ case t_operator:
+ dprintf1("op(%u", size);
+ if (size > 0 && size < op_def_count) /* just in case */
+ dprintf1(":%s", (const char *)(op_def_table[size]->oname + 1));
+ dprintf1(")0x%lx", (ulong) pref->value.opproc);
+ break;
+ case t_real:
+ dprintf1("real %f", pref->value.realval);
+ break;
+ case t_save:
+ dprintf1("save %lu", pref->value.saveid);
+ break;
+ case t_shortarray:
+ dprintf2("short packedarray(%u)0x%lx", size,
+ (ulong) pref->value.packed);
+ break;
+ case t_string:
+ dprintf2("string(%u)0x%lx", size, (ulong) pref->value.bytes);
+ break;
+ case t_struct:
+ strct:{
+ obj_header_t *obj = (obj_header_t *) pref->value.pstruct;
+
+ dprintf2("struct %s 0x%lx",
+ (r_is_foreign(pref) ? "-foreign-" :
+ gs_struct_type_name_string(gs_object_type(imemory, obj))),
+ (ulong) obj);
+ }
+ break;
+ default:
+ dprintf1("type 0x%x", r_type(pref));
+ }
+}
+private void
+debug_print_packed_ref(const ref_packed * pref)
+{
+ ushort elt = *pref & packed_value_mask;
+ ref nref;
+
+ switch (*pref >> r_packed_type_shift) {
+ case pt_executable_operator:
+ dprintf("<op_name>");
+ op_index_ref(elt, &nref);
+ debug_print_ref(&nref);
+ break;
+ case pt_integer:
+ dprintf1("<int> %d", (int)elt + packed_min_intval);
+ break;
+ case pt_literal_name:
+ dprintf("<lit_name>");
+ goto ptn;
+ case pt_executable_name:
+ dprintf("<exec_name>");
+ ptn:name_index_ref(elt, &nref);
+ dprintf2("(0x%lx#%u)", (ulong) nref.value.pname, elt);
+ debug_print_name(&nref);
+ break;
+ default:
+ dprintf2("<packed_%d?>0x%x", *pref >> r_packed_type_shift, elt);
+ }
+}
+void
+debug_print_ref(const ref * pref)
+{
+ if (r_is_packed(pref))
+ debug_print_packed_ref((const ref_packed *)pref);
+ else
+ debug_print_full_ref(pref);
+ fflush(dstderr);
+}
+
+/* Dump one ref. */
+void
+debug_dump_one_ref(const ref * p)
+{
+ uint attrs = r_type_attrs(p);
+ uint type = r_type(p);
+ static const attr_print_mask apm[] =
+ {attr_print_masks,
+ {0, 0, 0}};
+ const attr_print_mask *ap = apm;
+
+#define buf_size 30
+ char buf[buf_size + 1];
+ uint plen;
+
+ if (type >= tx_next_index)
+ dprintf1("0x%02x?? ", type);
+ else if (type >= t_next_index)
+ dprintf("opr* ");
+ else
+ dprintf1("%s ", type_strings[type]);
+ for (; ap->mask; ++ap)
+ if ((attrs & ap->mask) == ap->value)
+ dputc(ap->print);
+ dprintf2(" 0x%04x 0x%08lx", r_size(p), *(const ulong *)&p->value);
+ if (obj_cvs(p, (byte *) buf, countof(buf) - 1, &plen, NULL) >= 0 &&
+ ((buf[plen] = 0), strcmp(buf, "--nostringval--"))
+ )
+ dprintf1(" = %s", buf);
+ fflush(dstderr);
+}
+
+/* Dump a region of memory containing refs. */
+void
+debug_dump_refs(const ref * from, uint size, const char *msg)
+{
+ const ref *p = from;
+ uint count = size;
+
+ if (size && msg)
+ dprintf2("%s at 0x%lx:\n", msg, (ulong) from);
+ while (count--) { /* The double cast in the next line is to pacify some */
+ /* unreasonably picky compilers. */
+ dprintf2("..%04x: 0x%04x ", (uint) (ulong) p & 0xffff,
+ r_type_attrs(p));
+ debug_dump_one_ref(p);
+ dputc('\n');
+ p++;
+ }
+}
+
+/* Dump a stack. */
+void
+debug_dump_stack(const ref_stack * pstack, const char *msg)
+{
+ uint i;
+ const char *m = msg;
+
+ for (i = ref_stack_count(pstack); i != 0;) {
+ const ref *p = ref_stack_index(pstack, --i);
+
+ if (m)
+ dprintf2("%s at 0x%lx:\n", m, (ulong) pstack),
+ m = NULL;
+ dprintf2("0x%lx: 0x%02x ", (ulong) p, r_type(p));
+ debug_dump_one_ref(p);
+ dputc('\n');
+ }
+}
+
+/* Dump an array. */
+void
+debug_dump_array(const ref * array)
+{
+ const ref_packed *pp;
+ unsigned int type = r_type(array);
+ uint len;
+
+ switch (type) {
+ default:
+ dprintf2("%s at 0x%lx isn't an array.\n",
+ (type < countof(type_strings) ?
+ type_strings[type] : "????"),
+ (ulong) array);
+ return;
+ case t_oparray:
+ /* This isn't really an array, but we'd like to see */
+ /* its contents anyway. */
+ debug_dump_array(array->value.const_refs);
+ return;
+ case t_array:
+ case t_mixedarray:
+ case t_shortarray:
+ ;
+ }
+
+ /* This "packed" loop works for all array-types. */
+ for (len = r_size(array), pp = array->value.packed;
+ len > 0;
+ len--, pp = packed_next(pp)) {
+ ref temp;
+
+ packed_get(pp, &temp);
+ /* The double cast in the next line is to pacify some */
+ /* unreasonably picky compilers. */
+ dprintf3("..%04x%c 0x%02x ",
+ (uint) (ulong) pp & 0xffff,
+ ((r_is_packed(pp)) ? '*' : ':'),
+ r_type(&temp));
+ debug_dump_one_ref(&temp);
+ dputc('\n');
+ }
+}
diff --git a/pstoraster/idebug.h b/pstoraster/idebug.h
new file mode 100644
index 000000000..bd03b4cfd
--- /dev/null
+++ b/pstoraster/idebug.h
@@ -0,0 +1,48 @@
+/* Copyright (C) 1994, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of GNU Ghostscript.
+
+ GNU Ghostscript is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
+ to anyone for the consequences of using it or for whether it serves any
+ particular purpose or works at all, unless he says so in writing. Refer
+ to the GNU General Public License for full details.
+
+ Everyone is granted permission to copy, modify and redistribute GNU
+ Ghostscript, but only under the conditions described in the GNU General
+ Public License. A copy of this license is supposed to have been given
+ to you along with GNU Ghostscript so you can know your rights and
+ responsibilities. It should be in a file named COPYING. Among other
+ things, the copyright notice and this notice must be preserved on all
+ copies.
+
+ Aladdin Enterprises 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$ */
+/* Prototypes for debugging procedures in idebug.c */
+
+#ifndef idebug_INCLUDED
+# define idebug_INCLUDED
+
+/* Print individual values. */
+void debug_print_name(P1(const ref *));
+void debug_print_ref(P1(const ref *));
+
+/* Dump regions of memory. */
+void debug_dump_one_ref(P1(const ref *));
+void debug_dump_refs(P3(const ref * from, uint size, const char *msg));
+void debug_dump_array(P1(const ref * array));
+
+/* Dump a stack. Using this requires istack.h. */
+#ifndef ref_stack_DEFINED
+typedef struct ref_stack_s ref_stack; /* also defined in istack.h */
+
+# define ref_stack_DEFINED
+#endif
+void debug_dump_stack(P2(const ref_stack * pstack, const char *msg));
+
+#endif /* idebug_INCLUDED */
diff --git a/pstoraster/idict.c b/pstoraster/idict.c
new file mode 100644
index 000000000..d10107340
--- /dev/null
+++ b/pstoraster/idict.c
@@ -0,0 +1,780 @@
+/*
+ Copyright 1993-2002 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$ */
+/* Dictionary implementation */
+#include "string_.h" /* for strlen */
+#include "ghost.h"
+#include "errors.h"
+#include "imemory.h"
+#include "idebug.h" /* for debug_print_name */
+#include "inamedef.h"
+#include "iname.h"
+#include "ipacked.h"
+#include "isave.h" /* for value cache in names */
+#include "store.h"
+#include "idict.h" /* interface definition */
+#include "idictdef.h"
+#include "iutil.h"
+#include "ivmspace.h" /* for store check */
+
+/*
+ * Dictionaries per se aren't supposed to know anything about the
+ * dictionary stack, let alone the interpreter's dictionary stack.
+ * Unfortunately, there is are two design couplings between them:
+ * dictionary stacks cache some of the elements of their top dictionary
+ * (requiring updating when that dictionary grows or is unpacked),
+ * and names may cache a pointer to their definition (requiring a
+ * check whether a dictionary appears on the dictionary stack).
+ * Therefore, we patch in a few relevant definitions here.
+ ****** WE'D REALLY LIKE TO FIX THIS, BUT WE DON'T SEE HOW. ******
+ */
+#include "idstack.h"
+/* The following are copied from dstack.h. */
+extern dict_stack_t idict_stack;
+
+#define systemdict (&idict_stack.system_dict)
+#define dict_set_top() dstack_set_top(&idict_stack);
+#define dict_is_permanent_on_dstack(pdict)\
+ dstack_dict_is_permanent(&idict_stack, pdict)
+
+/*
+ * Define the size of the largest valid dictionary.
+ * This is limited by the size field of the keys and values refs,
+ * and by the enumeration interface, which requires the size to
+ * fit in an int. As it happens, max_array_size will always be
+ * smaller than max_int.
+ */
+const uint dict_max_size = max_array_size - 1;
+
+/* Define whether dictionaries expand automatically when full. */
+bool dict_auto_expand = false;
+
+/* Define whether dictionaries are packed by default. */
+bool dict_default_pack = true;
+
+/* Forward references */
+private int dict_create_contents(P3(uint size, const ref * pdref, bool pack));
+
+/* Debugging statistics */
+#ifdef DEBUG
+long dn_lookups; /* total lookups */
+long dn_1probe; /* successful lookups on only 1 probe */
+long dn_2probe; /* successful lookups on 2 probes */
+
+/* Wrapper for dict_find */
+int real_dict_find(P3(const ref * pdref, const ref * key, ref ** ppvalue));
+int
+dict_find(const ref * pdref, const ref * pkey, ref ** ppvalue)
+{
+ dict *pdict = pdref->value.pdict;
+ int code = real_dict_find(pdref, pkey, ppvalue);
+
+ dn_lookups++;
+ if (r_has_type(pkey, t_name) && dict_is_packed(pdict)) {
+ uint nidx = name_index(pkey);
+ uint hash =
+ dict_hash_mod(dict_name_index_hash(nidx), npairs(pdict)) + 1;
+
+ if (pdict->keys.value.packed[hash] ==
+ pt_tag(pt_literal_name) + nidx
+ )
+ dn_1probe++;
+ else if (pdict->keys.value.packed[hash - 1] ==
+ pt_tag(pt_literal_name) + nidx
+ )
+ dn_2probe++;
+ }
+ /* Do the cheap flag test before the expensive remainder test. */
+ if (gs_debug_c('d') && !(dn_lookups % 1000))
+ dlprintf3("[d]lookups=%ld 1probe=%ld 2probe=%ld\n",
+ dn_lookups, dn_1probe, dn_2probe);
+ return code;
+}
+#define dict_find real_dict_find
+#endif
+
+/* Round up the size of a dictionary. Return 0 if too large. */
+uint
+dict_round_size_small(uint rsize)
+{
+ return (rsize > dict_max_size ? 0 : rsize);
+}
+uint
+dict_round_size_large(uint rsize)
+{ /* Round up to a power of 2 if not huge. */
+ /* If the addition overflows, the new rsize will be zero, */
+ /* which will (correctly) be interpreted as a limitcheck. */
+ if (rsize > dict_max_non_huge)
+ return (rsize > dict_max_size ? 0 : rsize);
+ while (rsize & (rsize - 1))
+ rsize = (rsize | (rsize - 1)) + 1;
+ return (rsize <= dict_max_size ? rsize : dict_max_non_huge);
+}
+
+/* Create a dictionary using the given allocator. */
+int
+dict_alloc(gs_ref_memory_t * mem, uint size, ref * pdref)
+{
+ ref arr;
+ int code =
+ gs_alloc_ref_array(mem, &arr, a_all, sizeof(dict) / sizeof(ref),
+ "dict_alloc");
+ dict *pdict;
+ ref dref;
+
+ if (code < 0)
+ return code;
+ pdict = (dict *) arr.value.refs;
+ make_tav_new(&dref, t_dictionary, r_space(&arr) | a_all,
+ pdict, pdict);
+ make_struct(&pdict->memory, avm_foreign, mem);
+ code = dict_create_contents(size, &dref, dict_default_pack);
+ if (code < 0) {
+ gs_free_ref_array(mem, &arr, "dict_alloc");
+ return code;
+ }
+ *pdref = dref;
+ return 0;
+}
+/* Create unpacked keys for a dictionary. */
+/* The keys are allocated using the same allocator as the dictionary. */
+private int
+dict_create_unpacked_keys(uint asize, const ref * pdref)
+{
+ dict *pdict = pdref->value.pdict;
+ gs_ref_memory_t *mem = dict_memory(pdict);
+ int code;
+
+ code = gs_alloc_ref_array(mem, &pdict->keys, a_all, asize,
+ "dict_create_unpacked_keys");
+ if (code >= 0) {
+ ref *kp = pdict->keys.value.refs;
+
+ ref_mark_new(&pdict->keys);
+ refset_null(kp, asize);
+ r_set_attrs(kp, a_executable); /* wraparound entry */
+ }
+ return code;
+}
+/* Create the contents (keys and values) of a newly allocated dictionary. */
+/* Allocate in the current VM space, which is assumed to be the same as */
+/* the VM space where the dictionary is allocated. */
+private int
+dict_create_contents(uint size, const ref * pdref, bool pack)
+{
+ dict *pdict = pdref->value.pdict;
+ gs_ref_memory_t *mem = dict_memory(pdict);
+ uint asize = dict_round_size((size == 0 ? 1 : size));
+ int code;
+ uint i;
+
+ if (asize == 0 || asize > max_array_size - 1) /* too large */
+ return_error(e_limitcheck);
+ asize++; /* allow room for wraparound entry */
+ code = gs_alloc_ref_array(mem, &pdict->values, a_all, asize,
+ "dict_create_contents(values)");
+ if (code < 0)
+ return code;
+ ref_mark_new(&pdict->values);
+ refset_null(pdict->values.value.refs, asize);
+ if (pack) {
+ uint ksize = (asize + packed_per_ref - 1) / packed_per_ref;
+ ref arr;
+ ref_packed *pkp;
+ ref_packed *pzp;
+
+ code = gs_alloc_ref_array(mem, &arr, a_all, ksize,
+ "dict_create_contents(packed keys)");
+ if (code < 0)
+ return code;
+ pkp = (ref_packed *) arr.value.refs;
+ make_tasv_new(&pdict->keys, t_shortarray,
+ r_space(&arr) | a_all,
+ asize, packed, pkp);
+
+ /**** MRS - unrolled loop to avoid SGI compiler bug ****/
+ for (pzp = pkp, i = 0; i < asize; i++ )
+ *pzp++ = packed_key_empty;
+ for (; i % packed_per_ref; i++ )
+ *pzp++ = packed_key_empty;
+
+ *pkp = packed_key_deleted; /* wraparound entry */
+ } else { /* not packed */
+ int code = dict_create_unpacked_keys(asize, pdref);
+
+ if (code < 0)
+ return code;
+ }
+ make_int_new(&pdict->count, 0);
+ make_int_new(&pdict->maxlength, size);
+ return 0;
+}
+
+/*
+ * Ensure that a dictionary uses the unpacked representation for keys.
+ * We can't just use dict_resize, because the values slots mustn't move.
+ */
+int
+dict_unpack(ref * pdref)
+{
+ dict *pdict = pdref->value.pdict;
+
+ if (!dict_is_packed(pdict))
+ return 0; /* nothing to do */
+ {
+ uint count = nslots(pdict);
+ const ref_packed *okp = pdict->keys.value.packed;
+ ref old_keys;
+ int code;
+ ref *nkp;
+
+ old_keys = pdict->keys;
+ if (ref_must_save(&old_keys))
+ ref_do_save(pdref, &pdict->keys, "dict_unpack(keys)");
+ code = dict_create_unpacked_keys(count, pdref);
+ if (code < 0)
+ return code;
+ for (nkp = pdict->keys.value.refs; count--; okp++, nkp++)
+ if (r_packed_is_name(okp)) {
+ packed_get(okp, nkp);
+ ref_mark_new(nkp);
+ } else if (*okp == packed_key_deleted)
+ r_set_attrs(nkp, a_executable);
+ if (!ref_must_save(&old_keys))
+ gs_free_ref_array(dict_memory(pdict), &old_keys,
+ "dict_unpack(old keys)");
+ dict_set_top(); /* just in case */
+ }
+ return 0;
+}
+
+/*
+ * Look up a key in a dictionary. Store a pointer to the value slot
+ * where found, or to the (value) slot for inserting.
+ * Return 1 if found, 0 if not and there is room for a new entry,
+ * or e_dictfull if the dictionary is full and the key is missing.
+ * The caller is responsible for ensuring key is not a null.
+ */
+int
+dict_find(const ref * pdref, const ref * pkey,
+ ref ** ppvalue /* result is stored here */ )
+{
+ dict *pdict = pdref->value.pdict;
+ uint size = npairs(pdict);
+ register int etype;
+ uint nidx;
+ ref_packed kpack;
+ uint hash;
+ int ktype;
+
+ /* Compute hash. The only types we bother with are strings, */
+ /* names, and (unlikely, but worth checking for) integers. */
+ switch (r_type(pkey)) {
+ case t_name:
+ nidx = name_index(pkey);
+ nh:hash = dict_name_index_hash(nidx);
+ kpack = packed_name_key(nidx);
+ ktype = t_name;
+ break;
+ case t_string: /* convert to a name first */
+ {
+ ref nref;
+ int code;
+
+ if (!r_has_attr(pkey, a_read))
+ return_error(e_invalidaccess);
+ code = name_ref(pkey->value.bytes, r_size(pkey), &nref, 1);
+ if (code < 0)
+ return code;
+ nidx = name_index(&nref);
+ }
+ goto nh;
+ case t_integer:
+ hash = (uint) pkey->value.intval * 30503;
+ kpack = packed_key_impossible;
+ ktype = -1;
+ nidx = 0; /* only to pacify gcc */
+ break;
+ case t_null: /* not allowed as a key */
+ return_error(e_typecheck);
+ default:
+ hash = r_btype(pkey) * 99; /* yech */
+ kpack = packed_key_impossible;
+ ktype = -1;
+ nidx = 0; /* only to pacify gcc */
+ }
+ /* Search the dictionary */
+ if (dict_is_packed(pdict)) {
+ const ref_packed *pslot = 0;
+
+ packed_search_1(*ppvalue = packed_search_value_pointer,
+ return 1,
+ if (pslot == 0) pslot = kp, goto miss);
+ packed_search_2(*ppvalue = packed_search_value_pointer,
+ return 1,
+ if (pslot == 0) pslot = kp, goto miss);
+ /*
+ * Double wraparound, dict is full.
+ * Note that even if there was an empty slot (pslot != 0),
+ * we must return dictfull if length = maxlength.
+ */
+ if (pslot == 0 || d_length(pdict) == d_maxlength(pdict))
+ return (e_dictfull);
+ *ppvalue = pdict->values.value.refs + (pslot - kbot);
+ return 0;
+ miss: /* Key is missing, not double wrap. See above re dictfull. */
+ if (d_length(pdict) == d_maxlength(pdict))
+ return (e_dictfull);
+ if (pslot == 0)
+ pslot = kp;
+ *ppvalue = pdict->values.value.refs + (pslot - kbot);
+ return 0;
+ } else {
+ ref *kbot = pdict->keys.value.refs;
+ register ref *kp;
+ ref *pslot = 0;
+ int wrap = 0;
+
+ for (kp = kbot + dict_hash_mod(hash, size) + 2;;) {
+ --kp;
+ if ((etype = r_type(kp)) == ktype) { /* Fast comparison if both keys are names */
+ if (name_index(kp) == nidx) {
+ *ppvalue = pdict->values.value.refs + (kp - kbot);
+ return 1;
+ }
+ } else if (etype == t_null) { /* Empty, deleted, or wraparound. */
+ /* Figure out which. */
+ if (kp == kbot) { /* wrap */
+ if (wrap++) { /* wrapped twice */
+ if (pslot == 0)
+ return (e_dictfull);
+ break;
+ }
+ kp += size + 1;
+ } else if (r_has_attr(kp, a_executable)) { /* Deleted entry, save the slot. */
+ if (pslot == 0)
+ pslot = kp;
+ } else /* key not found */
+ break;
+ } else {
+ if (obj_eq(kp, pkey)) {
+ *ppvalue = pdict->values.value.refs + (kp - kbot);
+ return 1;
+ }
+ }
+ }
+ if (d_length(pdict) == d_maxlength(pdict))
+ return (e_dictfull);
+ *ppvalue = pdict->values.value.refs +
+ ((pslot != 0 ? pslot : kp) - kbot);
+ return 0;
+ }
+}
+
+/*
+ * Look up a (constant) C string in a dictionary.
+ * Return 1 if found, <= 0 if not.
+ */
+int
+dict_find_string(const ref * pdref, const char *kstr, ref ** ppvalue)
+{
+ int code;
+ ref kname;
+
+ if ((code = name_ref((const byte *)kstr, strlen(kstr), &kname, -1)) < 0)
+ return code;
+ return dict_find(pdref, &kname, ppvalue);
+}
+
+/*
+ * Enter a key-value pair in a dictionary.
+ * See idict.h for the possible return values.
+ */
+int
+dict_put(ref * pdref /* t_dictionary */ , const ref * pkey, const ref * pvalue)
+{
+ int rcode = 0;
+ int code;
+ ref *pvslot;
+
+ /* Check the value. */
+ store_check_dest(pdref, pvalue);
+ top:if ((code = dict_find(pdref, pkey, &pvslot)) <= 0) { /* not found *//* Check for overflow */
+ dict *pdict = pdref->value.pdict;
+ ref kname;
+ uint index;
+
+ switch (code) {
+ case 0:
+ break;
+ case e_dictfull:
+ if (!dict_auto_expand)
+ return_error(e_dictfull);
+ code = dict_grow(pdref);
+ if (code < 0)
+ return code;
+ goto top; /* keep things simple */
+ default: /* e_typecheck */
+ return code;
+ }
+ index = pvslot - pdict->values.value.refs;
+ /* If the key is a string, convert it to a name. */
+ if (r_has_type(pkey, t_string)) {
+ int code;
+
+ if (!r_has_attr(pkey, a_read))
+ return_error(e_invalidaccess);
+ code = name_from_string(pkey, &kname);
+ if (code < 0)
+ return code;
+ pkey = &kname;
+ }
+ if (dict_is_packed(pdict)) {
+ ref_packed *kp;
+
+ if (!r_has_type(pkey, t_name) ||
+ name_index(pkey) > packed_name_max_index
+ ) { /* Change to unpacked representation. */
+ int code = dict_unpack(pdref);
+
+ if (code < 0)
+ return code;
+ goto top;
+ }
+ kp = (ref_packed *) (pdict->keys.value.packed + index);
+ if (ref_must_save(&pdict->keys)) { /* See initial comment for why it is safe */
+ /* not to save the change if the keys */
+ /* array itself is new. */
+ ref_do_save(&pdict->keys, kp, "dict_put(key)");
+ }
+ *kp = pt_tag(pt_literal_name) + name_index(pkey);
+ } else {
+ ref *kp = pdict->keys.value.refs + index;
+
+ if_debug2('d', "[d]0x%lx: fill key at 0x%lx\n",
+ (ulong) pdict, (ulong) kp);
+ store_check_dest(pdref, pkey);
+ ref_assign_old(&pdict->keys, kp, pkey,
+ "dict_put(key)"); /* set key of pair */
+ }
+ ref_save(pdref, &pdict->count, "dict_put(count)");
+ pdict->count.value.intval++;
+ /* If the key is a name, update its 1-element cache. */
+ if (r_has_type(pkey, t_name)) {
+ name *pname = pkey->value.pname;
+
+ if (pname->pvalue == pv_no_defn &&
+ (pdict == systemdict->value.pdict ||
+ dict_is_permanent_on_dstack(pdref)) &&
+ /* Only set the cache if we aren't inside */
+ /* a save. This way, we never have to */
+ /* undo setting the cache. */
+ alloc_save_level(idmemory) == 0
+ ) { /* Set the cache. */
+ if_debug0('d', "[d]set cache\n");
+ pname->pvalue = pvslot;
+ } else { /* The cache can't be used. */
+ if_debug0('d', "[d]no cache\n");
+ pname->pvalue = pv_other;
+ }
+ }
+ rcode = 1;
+ }
+ if_debug8('d', "[d]0x%lx: put key 0x%lx 0x%lx\n value at 0x%lx: old 0x%lx 0x%lx, new 0x%lx 0x%lx\n",
+ (ulong) pdref->value.pdict,
+ ((const ulong *)pkey)[0], ((const ulong *)pkey)[1],
+ (ulong) pvslot,
+ ((const ulong *)pvslot)[0], ((const ulong *)pvslot)[1],
+ ((const ulong *)pvalue)[0], ((const ulong *)pvalue)[1]);
+ ref_assign_old(&pdref->value.pdict->values, pvslot, pvalue,
+ "dict_put(value)");
+ return rcode;
+}
+
+/*
+ * Enter a key-value pair where the key is a (constant) C string.
+ */
+int
+dict_put_string(ref * pdref, const char *kstr, const ref * pvalue)
+{
+ int code;
+ ref kname;
+
+ if ((code = name_ref((const byte *)kstr, strlen(kstr), &kname, 0)) < 0)
+ return code;
+ return dict_put(pdref, &kname, pvalue);
+}
+
+/* Remove an element from a dictionary. */
+int
+dict_undef(ref * pdref, const ref * pkey)
+{
+ ref *pvslot;
+ dict *pdict;
+ uint index;
+
+ if (dict_find(pdref, pkey, &pvslot) <= 0)
+ return (e_undefined);
+ /* Remove the entry from the dictionary. */
+ pdict = pdref->value.pdict;
+ index = pvslot - pdict->values.value.refs;
+ if (dict_is_packed(pdict)) {
+ ref_packed *pkp =
+ (ref_packed *) (pdict->keys.value.packed + index);
+
+ /* See the initial comment for why it is safe not to save */
+ /* the change if the keys array itself is new. */
+ if (ref_must_save(&pdict->keys))
+ ref_do_save(&pdict->keys, pkp, "dict_undef(key)");
+ /* Accumulating deleted entries slows down lookup. */
+ /* Detect the easy case where we can use an empty entry */
+ /* rather than a deleted one, namely, when the next entry */
+ /* in the probe order is empty. */
+ if (pkp[-1] == packed_key_empty)
+ *pkp = packed_key_empty;
+ else
+ *pkp = packed_key_deleted;
+ } else { /* not packed */
+ ref *kp = pdict->keys.value.refs + index;
+
+ make_null_old(&pdict->keys, kp, "dict_undef(key)");
+ /* Accumulating deleted entries slows down lookup. */
+ /* Detect the easy case where we can use an empty entry */
+ /* rather than a deleted one, namely, when the next entry */
+ /* in the probe order is empty. */
+ if (!r_has_type(kp - 1, t_null) || /* full entry */
+ r_has_attr(kp - 1, a_executable) /* deleted or wraparound */
+ )
+ r_set_attrs(kp, a_executable); /* mark as deleted */
+ }
+ ref_save(pdref, &pdict->count, "dict_undef(count)");
+ pdict->count.value.intval--;
+ /* If the key is a name, update its 1-element cache. */
+ if (r_has_type(pkey, t_name)) {
+ name *pname = pkey->value.pname;
+
+ if (pv_valid(pname->pvalue)) {
+#ifdef DEBUG
+ /* Check the the cache is correct. */
+ if (!dict_is_permanent_on_dstack(pdref))
+ lprintf1("dict_undef: cached name value pointer 0x%lx is incorrect!\n",
+ (ulong) pname->pvalue);
+#endif
+ /* Clear the cache */
+ pname->pvalue = pv_no_defn;
+ }
+ }
+ make_null_old(&pdict->values, pvslot, "dict_undef(value)");
+ return 0;
+}
+
+/* Return the number of elements in a dictionary. */
+uint
+dict_length(const ref * pdref /* t_dictionary */ )
+{
+ return d_length(pdref->value.pdict);
+}
+
+/* Return the capacity of a dictionary. */
+uint
+dict_maxlength(const ref * pdref /* t_dictionary */ )
+{
+ return d_maxlength(pdref->value.pdict);
+}
+
+/* Return the maximum index of a slot within a dictionary. */
+uint
+dict_max_index(const ref * pdref /* t_dictionary */ )
+{
+ return npairs(pdref->value.pdict) - 1;
+}
+
+/* Copy one dictionary into another. */
+/* If new_only is true, only copy entries whose keys */
+/* aren't already present in the destination. */
+int
+dict_copy_entries(const ref * pdrfrom /* t_dictionary */ ,
+ ref * pdrto /* t_dictionary */ , bool new_only)
+{
+ int space = r_space(pdrto);
+ int index;
+ ref elt[2];
+ ref *pvslot;
+ int code;
+
+ if (space != avm_max) { /* Do the store check before starting the copy. */
+ index = dict_first(pdrfrom);
+ while ((index = dict_next(pdrfrom, index, elt)) >= 0)
+ if (!new_only || dict_find(pdrto, &elt[0], &pvslot) <= 0) {
+ store_check_space(space, &elt[0]);
+ store_check_space(space, &elt[1]);
+ }
+ }
+ /* Now copy the contents. */
+ index = dict_first(pdrfrom);
+ while ((index = dict_next(pdrfrom, index, elt)) >= 0) {
+ if (new_only && dict_find(pdrto, &elt[0], &pvslot) > 0)
+ continue;
+ if ((code = dict_put(pdrto, &elt[0], &elt[1])) < 0)
+ return code;
+ }
+ return 0;
+}
+
+/* Resize a dictionary. */
+int
+dict_resize(ref * pdref, uint new_size)
+{
+ dict *pdict = pdref->value.pdict;
+ gs_ref_memory_t *mem = dict_memory(pdict);
+ dict dnew;
+ ref drto;
+ int code;
+
+ if (new_size < d_length(pdict)) {
+ if (!dict_auto_expand)
+ return_error(e_dictfull);
+ new_size = d_length(pdict);
+ }
+ make_tav_new(&drto, t_dictionary, r_space(pdref) | a_all,
+ pdict, &dnew);
+ dnew.memory = pdict->memory;
+ if ((code = dict_create_contents(new_size, &drto, dict_is_packed(pdict))) < 0)
+ return code;
+ /* We must suppress the store check, in case we are expanding */
+ /* systemdict or another global dictionary that is allowed */
+ /* to reference local objects. */
+ r_set_space(&drto, avm_local);
+ dict_copy(pdref, &drto); /* can't fail */
+ /* Save or free the old dictionary. */
+ if (ref_must_save(&pdict->values))
+ ref_do_save(pdref, &pdict->values, "dict_resize(values)");
+ else
+ gs_free_ref_array(mem, &pdict->values, "dict_resize(old values)");
+ if (ref_must_save(&pdict->keys))
+ ref_do_save(pdref, &pdict->keys, "dict_resize(keys)");
+ else
+ gs_free_ref_array(mem, &pdict->keys, "dict_resize(old keys)");
+ ref_assign(&pdict->keys, &dnew.keys);
+ ref_assign(&pdict->values, &dnew.values);
+ ref_save(pdref, &pdict->maxlength, "dict_resize(maxlength)");
+ d_set_maxlength(pdict, new_size);
+ dict_set_top(); /* just in case this is the top dict */
+ return 0;
+}
+
+/* Grow a dictionary for dict_put. */
+int
+dict_grow(ref * pdref)
+{
+ dict *pdict = pdref->value.pdict;
+
+ /* We might have maxlength < npairs, if */
+ /* dict_round_size increased the size. */
+ ulong new_size = (ulong) d_maxlength(pdict) * 3 / 2 + 2;
+
+#if arch_sizeof_int < arch_sizeof_long
+ if (new_size > max_uint)
+ new_size = max_uint;
+#endif
+ if (new_size > npairs(pdict)) {
+ int code = dict_resize(pdref, (uint) new_size);
+
+ if (code >= 0)
+ return code;
+ /* new_size was too big. */
+ if (npairs(pdict) < dict_max_size) {
+ code = dict_resize(pdref, dict_max_size);
+ if (code >= 0)
+ return code;
+ }
+ if (npairs(pdict) == d_maxlength(pdict)) { /* Can't do it. */
+ return code;
+ }
+ /* We can't grow to new_size, but we can grow to npairs. */
+ new_size = npairs(pdict);
+ }
+ /* maxlength < npairs, we can grow in place */
+ ref_save(pdref, &pdict->maxlength, "dict_put(maxlength)");
+ d_set_maxlength(pdict, new_size);
+ return 0;
+}
+
+/* Prepare to enumerate a dictionary. */
+int
+dict_first(const ref * pdref)
+{
+ return (int)nslots(pdref->value.pdict);
+}
+
+/* Enumerate the next element of a dictionary. */
+int
+dict_next(const ref * pdref, int index, ref * eltp /* ref eltp[2] */ )
+{
+ dict *pdict = pdref->value.pdict;
+ ref *vp = pdict->values.value.refs + index;
+
+ while (vp--, --index >= 0) {
+ array_get(&pdict->keys, (long)index, eltp);
+ /* Make sure this is a valid entry. */
+ if (r_has_type(eltp, t_name) ||
+ (!dict_is_packed(pdict) && !r_has_type(eltp, t_null))
+ ) {
+ eltp[1] = *vp;
+ if_debug6('d', "[d]0x%lx: index %d: %lx %lx, %lx %lx\n",
+ (ulong) pdict, index,
+ ((ulong *) eltp)[0], ((ulong *) eltp)[1],
+ ((ulong *) vp)[0], ((ulong *) vp)[1]);
+ return index;
+ }
+ }
+ return -1; /* no more elements */
+}
+
+/* Return the index of a value within a dictionary. */
+int
+dict_value_index(const ref * pdref, const ref * pvalue)
+{
+ return (int)(pvalue - pdref->value.pdict->values.value.refs - 1);
+}
+
+/* Return the entry at a given index within a dictionary. */
+/* If the index designates an unoccupied entry, return e_undefined. */
+int
+dict_index_entry(const ref * pdref, int index, ref * eltp /* ref eltp[2] */ )
+{
+ const dict *pdict = pdref->value.pdict;
+
+ array_get(&pdict->keys, (long)(index + 1), eltp);
+ if (r_has_type(eltp, t_name) ||
+ (!dict_is_packed(pdict) && !r_has_type(eltp, t_null))
+ ) {
+ eltp[1] = pdict->values.value.refs[index + 1];
+ return 0;
+ }
+ return e_undefined;
+}
diff --git a/pstoraster/idict.h b/pstoraster/idict.h
new file mode 100644
index 000000000..7f1925ed9
--- /dev/null
+++ b/pstoraster/idict.h
@@ -0,0 +1,268 @@
+/* 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$ */
+/* Interfaces for Ghostscript dictionary package */
+
+#ifndef idict_INCLUDED
+# define idict_INCLUDED
+
+/*
+ * Contrary to our usual practice, we expose the (first-level)
+ * representation of a dictionary in the interface file,
+ * because it is so important that access checking go fast.
+ * The access attributes for the dictionary are stored in
+ * the values ref.
+ */
+struct dict_s {
+ ref values; /* t_array, values */
+ ref keys; /* t_shortarray or t_array, keys */
+ ref count; /* t_integer, count of occupied entries */
+ /* (length) */
+ ref maxlength; /* t_integer, maxlength as seen by client. */
+ ref memory; /* foreign t_struct, the allocator that */
+ /* created this dictionary */
+#define dict_memory(pdict) r_ptr(&(pdict)->memory, gs_ref_memory_t)
+};
+
+/*
+ * Define the maximum size of a dictionary.
+ */
+extern const uint dict_max_size;
+
+/*
+ * Define whether dictionaries expand automatically when full. Note that
+ * if dict_auto_expand is true, dict_put, dict_copy, dict_resize, and
+ * dict_grow cannot return e_dictfull; however, they can return e_VMerror.
+ * (dict_find can return e_dictfull even if dict_auto_expand is true.)
+ */
+extern bool dict_auto_expand;
+
+/*
+ * Create a dictionary.
+ */
+#ifndef gs_ref_memory_DEFINED
+# define gs_ref_memory_DEFINED
+typedef struct gs_ref_memory_s gs_ref_memory_t;
+
+#endif
+int dict_alloc(P3(gs_ref_memory_t *, uint maxlength, ref * pdref));
+
+#define dict_create(maxlen, pdref)\
+ dict_alloc(iimemory, maxlen, pdref)
+
+/*
+ * Return a pointer to a ref that holds the access attributes
+ * for a dictionary.
+ */
+#define dict_access_ref(pdref) (&(pdref)->value.pdict->values)
+/*
+ * Check a dictionary for read or write permission.
+ * Note: this does NOT check the type of its operand!
+ */
+#define check_dict_read(dref) check_read(*dict_access_ref(&dref))
+#define check_dict_write(dref) check_write(*dict_access_ref(&dref))
+
+/*
+ * Look up a key in a dictionary. Store a pointer to the value slot
+ * where found, or to the (value) slot for inserting.
+ * The caller is responsible for checking that the dictionary is readable.
+ * Return 1 if found, 0 if not and there is room for a new entry,
+ * Failure returns:
+ * e_typecheck if the key is null;
+ * e_invalidaccess if the key is a string lacking read access;
+ * e_VMerror or e_limitcheck if the key is a string and the corresponding
+ * error occurs from attempting to convert it to a name;
+ * e_dictfull if the dictionary is full and the key is missing.
+ */
+int dict_find(P3(const ref * pdref, const ref * key, ref ** ppvalue));
+
+/*
+ * Look up a (constant) C string in a dictionary.
+ * Return 1 if found, <= 0 if not.
+ */
+int dict_find_string(P3(const ref * pdref, const char *kstr, ref ** ppvalue));
+
+/*
+ * Enter a key-value pair in a dictionary.
+ * The caller is responsible for checking that the dictionary is writable.
+ * Return 1 if this was a new entry, 0 if this replaced an existing entry.
+ * Failure returns are as for dict_find, except that e_dictfull doesn't
+ * occur if the dictionary is full but expandable, plus:
+ * e_invalidaccess for an attempt to store a younger key or value into
+ * an older dictionary;
+ * e_VMerror if a VMerror occurred while trying to expand the
+ * dictionary.
+ */
+int dict_put(P3(ref * pdref, const ref * key, const ref * pvalue));
+
+/*
+ * Enter a key-value pair where the key is a (constant) C string.
+ */
+int dict_put_string(P3(ref * pdref, const char *kstr, const ref * pvalue));
+
+/*
+ * Remove a key-value pair from a dictionary.
+ * Return 0 or e_undefined.
+ */
+int dict_undef(P2(ref * pdref, const ref * key));
+
+/*
+ * Return the number of elements in a dictionary.
+ */
+uint dict_length(P1(const ref * pdref));
+
+/*
+ * Return the capacity of a dictionary.
+ */
+uint dict_maxlength(P1(const ref * pdref));
+
+/*
+ * Return the maximum index of a slot within a dictionary.
+ * Note that this may be greater than maxlength.
+ */
+uint dict_max_index(P1(const ref * pdref));
+
+/*
+ * Copy one dictionary into another.
+ * Return 0 or e_dictfull.
+ * If new_only is true, only copy entries whose keys
+ * aren't already present in the destination.
+ */
+int dict_copy_entries(P3(const ref * dfrom, ref * dto, bool new_only));
+
+#define dict_copy(dfrom, dto) dict_copy_entries(dfrom, dto, false)
+#define dict_copy_new(dfrom, dto) dict_copy_entries(dfrom, dto, true)
+
+/*
+ * Grow or shrink a dictionary.
+ * Return 0, e_dictfull, or e_VMerror.
+ */
+int dict_resize(P2(ref * pdref, uint newmaxlength));
+
+/*
+ * Grow a dictionary in the same way as dict_put does.
+ * We export this for some special-case code in zop_def.
+ */
+int dict_grow(P1(ref * pdref));
+
+/*
+ * Ensure that a dictionary uses the unpacked representation for keys.
+ * (This is of no interest to ordinary clients.)
+ */
+int dict_unpack(P1(ref * pdref));
+
+/*
+ * Prepare to enumerate a dictionary.
+ * Return an integer suitable for the first call to dict_next.
+ */
+int dict_first(P1(const ref * pdref));
+
+/*
+ * Enumerate the next element of a dictionary.
+ * index is initially the result of a call on dict_first.
+ * Either store a key and value at eltp[0] and eltp[1]
+ * and return an updated index, or return -1
+ * to signal that there are no more elements in the dictionary.
+ */
+int dict_next(P3(const ref * pdref, int index, ref * eltp));
+
+/*
+ * Given a value pointer return by dict_find, return an index that
+ * identifies the entry within the dictionary. (This may, but need not,
+ * be the same as the index returned by dict_next.)
+ * The index is in the range [0..max_index-1].
+ */
+int dict_value_index(P2(const ref * pdref, const ref * pvalue));
+
+/*
+ * Given an index in [0..max_index-1], as returned by dict_value_index,
+ * return the key and value, as returned by dict_next.
+ * If the index designates an unoccupied entry, return e_undefined.
+ */
+int dict_index_entry(P3(const ref * pdref, int index, ref * eltp));
+
+/*
+ * The following are some internal details that are used in both the
+ * implementation and some high-performance clients.
+ */
+
+/* On machines with reasonable amounts of memory, we round up dictionary
+ * sizes to the next power of 2 whenever possible, to allow us to use
+ * masking rather than division for computing the hash index.
+ * Unfortunately, if we required this, it would cut the maximum size of a
+ * dictionary in half. Therefore, on such machines, we distinguish
+ * "huge" dictionaries (dictionaries whose size is larger than the largest
+ * power of 2 less than dict_max_size) as a special case:
+ *
+ * - If the top dictionary on the stack is huge, we set the dtop
+ * parameters so that the fast inline lookup will always fail.
+ *
+ * - For general lookup, we use the slower hash_mod algorithm for
+ * huge dictionaries.
+ */
+#define dict_max_non_huge ((uint)(max_array_size / 2 + 1))
+
+/* Define the hashing function for names. */
+/* We don't have to scramble the index, because */
+/* indices are assigned in a scattered order (see name_ref in iname.c). */
+#define dict_name_index_hash(nidx) (nidx)
+
+/* Hash an arbitrary non-negative or unsigned integer into a dictionary. */
+#define dict_hash_mod_rem(hash, size) ((hash) % (size))
+#define dict_hash_mod_mask(hash, size) ((hash) & ((size) - 1))
+#define dict_hash_mod_small(hash, size) dict_hash_mod_rem(hash, size)
+#define dict_hash_mod_inline_small(hash, size) dict_hash_mod_rem(hash, size)
+#define dict_hash_mod_large(hash, size)\
+ (size > dict_max_non_huge ? dict_hash_mod_rem(hash, size) :\
+ dict_hash_mod_mask(hash, size))
+#define dict_hash_mod_inline_large(hash, size) dict_hash_mod_mask(hash, size)
+/* Round up the requested size of a dictionary. Return 0 if too big. */
+uint dict_round_size_small(P1(uint rsize));
+uint dict_round_size_large(P1(uint rsize));
+
+/* Choose the algorithms depending on the size of memory. */
+#if arch_small_memory
+# define dict_hash_mod(h, s) dict_hash_mod_small(h, s)
+# define dict_hash_mod_inline(h, s) dict_hash_mod_inline_small(h, s)
+# define dict_round_size(s) dict_round_size_small(s)
+#else
+# ifdef DEBUG
+# define dict_hash_mod(h, s)\
+ (gs_debug_c('.') ? dict_hash_mod_small(h, s) :\
+ dict_hash_mod_large(h, s))
+# define dict_hash_mod_inline(h, s)\
+ (gs_debug_c('.') ? dict_hash_mod_inline_small(h, s) :\
+ dict_hash_mod_inline_large(h, s))
+# define dict_round_size(s)\
+ (gs_debug_c('.') ? dict_round_size_small(s) :\
+ dict_round_size_large(s))
+# else
+# define dict_hash_mod(h, s) dict_hash_mod_large(h, s)
+# define dict_hash_mod_inline(h, s) dict_hash_mod_inline_large(h, s)
+# define dict_round_size(s) dict_round_size_large(s)
+# endif
+#endif
+
+#endif /* idict_INCLUDED */
diff --git a/pstoraster/idictdef.h b/pstoraster/idictdef.h
new file mode 100644
index 000000000..68abe42ad
--- /dev/null
+++ b/pstoraster/idictdef.h
@@ -0,0 +1,128 @@
+/* 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$ */
+/* Internals of dictionary implementation */
+
+#ifndef idictdef_INCLUDED
+# define idictdef_INCLUDED
+
+/*
+ * A dictionary of capacity M is a structure containing the following
+ * elements (refs):
+ *
+ * keys - a t_shortarray or t_array of M+1 elements, containing
+ * the keys.
+ *
+ * values - a t_array of M+1 elements, containing the values.
+ *
+ * count - a t_integer whose value tells how many entries are
+ * occupied (N).
+ *
+ * maxlength - a t_integer whose value gives the client's view of
+ * the capacity (C). C may be less than M (see below).
+ *
+ * memory - a foreign t_struct referencing the allocator used to
+ * create this dictionary, which will also be used to expand or
+ * unpack it if necessary.
+ *
+ * C < M is possible because on large-memory systems, we usually round up M
+ * so that M is a power of 2 (see idict.h for details); this allows us to
+ * use masking rather than division for computing the initial hash probe.
+ * However, C is always the maxlength specified by the client, so clients
+ * get a consistent story.
+ *
+ * As noted above, the keys may be either in packed or unpacked form.
+ * The markers for unused and deleted entries are different in the two forms.
+ * In the packed form:
+ * unused entries contain packed_key_empty;
+ * deleted entries contain packed_key_deleted.
+ * In the unpacked form:
+ * unused entries contain a literal null;
+ * deleted entries contain an executable null.
+ *
+ * The first entry is always marked deleted, to reduce the cost of the
+ * wrap-around check.
+ *
+ * Note that if the keys slot in the dictionary is new,
+ * all the key slots are new (more recent than the last save).
+ * We use this fact to avoid saving stores into packed keys
+ * for newly created dictionaries.
+ *
+ * Note that name keys with indices above packed_name_max_index require using
+ * the unpacked form. */
+#define dict_is_packed(dct) r_has_type(&(dct)->keys, t_shortarray)
+#define packed_key_empty (pt_tag(pt_integer) + 0)
+#define packed_key_deleted (pt_tag(pt_integer) + 1)
+#define packed_key_impossible pt_tag(pt_full_ref) /* never matches */
+#define packed_name_key(nidx)\
+ ((nidx) <= packed_name_max_index ? pt_tag(pt_literal_name) + (nidx) :\
+ packed_key_impossible)
+/*
+ * Using a special mark for deleted entries causes lookup time to degrade
+ * as entries are inserted and deleted. This is not a problem, because
+ * entries are almost never deleted.
+ */
+#define d_maxlength(dct) ((uint)((dct)->maxlength.value.intval))
+#define d_set_maxlength(dct,siz) ((dct)->maxlength.value.intval = (siz))
+#define nslots(dct) r_size(&(dct)->values)
+#define npairs(dct) (nslots(dct) - 1)
+#define d_length(dct) ((uint)((dct)->count.value.intval))
+
+/*
+ * Define macros for searching a packed dictionary. Free variables:
+ * ref_packed kpack - holds the packed key.
+ * uint hash - holds the hash of the name.
+ * dict *pdict - points to the dictionary.
+ * uint size - holds npairs(pdict).
+ * Note that the macro is *not* enclosed in {}, so that we can access
+ * the values of kbot and kp after leaving the loop.
+ *
+ * We break the macro into two to avoid overflowing some preprocessors.
+ */
+/* packed_search_body also uses kp and kbot as free variables. */
+#define packed_search_value_pointer (pdict->values.value.refs + (kp - kbot))
+#define packed_search_body(found1,found2,del,miss)\
+ { if_debug2('D', "[D]probe 0x%lx: 0x%x\n", (ulong)kp, *kp);\
+ if ( *kp == kpack )\
+ { found1;\
+ found2;\
+ }\
+ else if ( !r_packed_is_name(kp) )\
+ { /* Empty, deleted, or wraparound. Figure out which. */\
+ if ( *kp == packed_key_empty ) miss;\
+ if ( kp == kbot ) break; /* wrap */\
+ else { del; }\
+ }\
+ }
+#define packed_search_1(found1,found2,del,miss)\
+ const ref_packed *kbot = pdict->keys.value.packed;\
+ register const ref_packed *kp;\
+ for ( kp = kbot + dict_hash_mod(hash, size) + 1; ; kp-- )\
+ packed_search_body(found1,found2,del,miss)
+#define packed_search_2(found1,found2,del,miss)\
+ for ( kp += size; ; kp-- )\
+ packed_search_body(found1,found2,del,miss)
+
+#endif /* idictdef_INCLUDED */
diff --git a/pstoraster/idparam.c b/pstoraster/idparam.c
new file mode 100644
index 000000000..842f29dba
--- /dev/null
+++ b/pstoraster/idparam.c
@@ -0,0 +1,371 @@
+/* Copyright (C) 1992, 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$ */
+/* Utilities for getting parameters out of dictionaries. */
+#include "memory_.h"
+#include "string_.h" /* for strlen */
+#include "ghost.h"
+#include "errors.h"
+#include "gsmatrix.h" /* for dict_matrix_param */
+#include "gsuid.h"
+#include "idict.h"
+#include "idparam.h" /* interface definition */
+#include "ilevel.h"
+#include "imemory.h" /* for iutil.h */
+#include "iname.h"
+#include "iutil.h"
+#include "oper.h" /* for check_proc */
+#include "store.h" /* for making empty proc */
+
+/* Get a Boolean parameter from a dictionary. */
+/* Return 0 if found, 1 if defaulted, <0 if wrong type. */
+int
+dict_bool_param(const ref * pdict, const char *kstr,
+ bool defaultval, bool * pvalue)
+{
+ ref *pdval;
+
+ if (pdict == 0 || dict_find_string(pdict, kstr, &pdval) <= 0) {
+ *pvalue = defaultval;
+ return 1;
+ }
+ if (!r_has_type(pdval, t_boolean))
+ return_error(e_typecheck);
+ *pvalue = pdval->value.boolval;
+ return 0;
+}
+
+/* Get an integer or null parameter from a dictionary. */
+/* Return 0 if found, 1 if defaulted, <0 if invalid. */
+/* If the parameter is null, return 2 without setting *pvalue. */
+/* Note that the default value may be out of range, in which case */
+/* a missing value will return e_rangecheck rather than 1. */
+int
+dict_int_null_param(const ref * pdict, const char *kstr, int minval,
+ int maxval, int defaultval, int *pvalue)
+{
+ ref *pdval;
+ int code;
+ long ival;
+
+ if (pdict == 0 || dict_find_string(pdict, kstr, &pdval) <= 0) {
+ ival = defaultval;
+ code = 1;
+ } else {
+ switch (r_type(pdval)) {
+ case t_integer:
+ ival = pdval->value.intval;
+ break;
+ case t_real:
+ /* Allow an integral real, because Fontographer */
+ /* (which violates the Adobe specs in other ways */
+ /* as well) sometimes generates output that */
+ /* needs this. */
+ if (pdval->value.realval < minval || pdval->value.realval > maxval)
+ return_error(e_rangecheck);
+ ival = (long)pdval->value.realval;
+ if (ival != pdval->value.realval)
+ return_error(e_rangecheck);
+ break;
+ case t_null:
+ return 2;
+ default:
+ return_error(e_typecheck);
+ }
+ code = 0;
+ }
+ if (ival < minval || ival > maxval)
+ return_error(e_rangecheck);
+ *pvalue = (int)ival;
+ return code;
+}
+/* Get an integer parameter from a dictionary. */
+/* Return like dict_int_null_param, but return e_typecheck for null. */
+int
+dict_int_param(const ref * pdict, const char *kstr, int minval, int maxval,
+ int defaultval, int *pvalue)
+{
+ int code = dict_int_null_param(pdict, kstr, minval, maxval,
+ defaultval, pvalue);
+
+ return (code == 2 ? gs_note_error(e_typecheck) : code);
+}
+
+/* Get an unsigned integer parameter from a dictionary. */
+/* Return 0 if found, 1 if defaulted, <0 if invalid. */
+/* Note that the default value may be out of range, in which case */
+/* a missing value will return e_rangecheck rather than 1. */
+int
+dict_uint_param(const ref * pdict, const char *kstr,
+ uint minval, uint maxval, uint defaultval, uint * pvalue)
+{
+ ref *pdval;
+ int code;
+ uint ival;
+
+ if (pdict == 0 || dict_find_string(pdict, kstr, &pdval) <= 0) {
+ ival = defaultval;
+ code = 1;
+ } else {
+ check_type_only(*pdval, t_integer);
+ if (pdval->value.intval != (uint) pdval->value.intval)
+ return_error(e_rangecheck);
+ ival = (uint) pdval->value.intval;
+ code = 0;
+ }
+ if (ival < minval || ival > maxval)
+ return_error(e_rangecheck);
+ *pvalue = ival;
+ return code;
+}
+
+/* Get a float parameter from a dictionary. */
+/* Return 0 if found, 1 if defaulted, <0 if wrong type. */
+int
+dict_float_param(const ref * pdict, const char *kstr,
+ floatp defaultval, float *pvalue)
+{
+ ref *pdval;
+
+ if (pdict == 0 || dict_find_string(pdict, kstr, &pdval) <= 0) {
+ *pvalue = defaultval;
+ return 1;
+ }
+ switch (r_type(pdval)) {
+ case t_integer:
+ *pvalue = pdval->value.intval;
+ return 0;
+ case t_real:
+ *pvalue = pdval->value.realval;
+ return 0;
+ }
+ return_error(e_typecheck);
+}
+
+/* Get an integer array from a dictionary. */
+/* Return the element count if OK, 0 if missing, <0 if invalid. */
+int
+dict_int_array_param(const ref * pdict, const char *kstr,
+ uint maxlen, int *ivec)
+{
+ ref *pdval;
+ const ref *pa;
+ int *pi = ivec;
+ uint size;
+ int i;
+
+ if (pdict == 0 || dict_find_string(pdict, kstr, &pdval) <= 0)
+ return 0;
+ if (!r_has_type(pdval, t_array))
+ return_error(e_typecheck);
+ size = r_size(pdval);
+ if (size > maxlen)
+ return_error(e_limitcheck);
+ pa = pdval->value.const_refs;
+ for (i = 0; i < size; i++, pa++, pi++) { /* See dict_int_param above for why we allow reals here. */
+ switch (r_type(pa)) {
+ case t_integer:
+ if (pa->value.intval != (int)pa->value.intval)
+ return_error(e_rangecheck);
+ *pi = (int)pa->value.intval;
+ break;
+ case t_real:
+ if (pa->value.realval < min_int ||
+ pa->value.realval > max_int ||
+ pa->value.realval != (int)pa->value.realval
+ )
+ return_error(e_rangecheck);
+ *pi = (int)pa->value.realval;
+ break;
+ default:
+ return_error(e_typecheck);
+ }
+ }
+ return size;
+}
+
+/* Get a float array from a dictionary. */
+/* Return the element count if OK, <0 if invalid. */
+/* If the parameter is missing, then if defaultvec is NULL, return 0; */
+/* if defaultvec is not NULL, copy it into fvec (maxlen elements) */
+/* and return maxlen. */
+int
+dict_float_array_param(const ref * pdict, const char *kstr,
+ uint maxlen, float *fvec, const float *defaultvec)
+{
+ ref *pdval;
+ uint size;
+ int code;
+
+ if (pdict == 0 || dict_find_string(pdict, kstr, &pdval) <= 0) {
+ if (defaultvec == NULL)
+ return 0;
+ memcpy(fvec, defaultvec, maxlen * sizeof(float));
+
+ return maxlen;
+ }
+ if (!r_has_type(pdval, t_array))
+ return_error(e_typecheck);
+ size = r_size(pdval);
+ if (size > maxlen)
+ return_error(e_limitcheck);
+ code = float_params(pdval->value.refs + size - 1, size, fvec);
+ return (code >= 0 ? size : code);
+}
+
+/*
+ * Get a procedure from a dictionary. If the key is missing,
+ * defaultval = false means substitute t__invalid;
+ * defaultval = true means substitute an empty procedure.
+ * In either case, return 1.
+ */
+int
+dict_proc_param(const ref * pdict, const char *kstr, ref * pproc,
+ bool defaultval)
+{
+ ref *pdval;
+
+ if (pdict == 0 || dict_find_string(pdict, kstr, &pdval) <= 0) {
+ if (defaultval)
+ make_empty_const_array(pproc, a_readonly + a_executable);
+ else
+ make_t(pproc, t__invalid);
+ return 1;
+ }
+ check_proc(*pdval);
+ *pproc = *pdval;
+ return 0;
+}
+
+/* Get a matrix from a dictionary. */
+int
+dict_matrix_param(const ref * pdict, const char *kstr, gs_matrix * pmat)
+{
+ ref *pdval;
+
+ if (pdict == 0 || dict_find_string(pdict, kstr, &pdval) <= 0)
+ return_error(e_typecheck);
+ return read_matrix(pdval, pmat);
+}
+
+/* Get a UniqueID or XUID from a dictionary. */
+/* Return 0 if UniqueID, 1 if XUID, <0 if error. */
+/* If there is no uid, return default. */
+int
+dict_uid_param(const ref * pdict, gs_uid * puid, int defaultval,
+ gs_memory_t * mem)
+{
+ ref *puniqueid;
+
+ if (pdict == 0) {
+ uid_set_invalid(puid);
+ return defaultval;
+ }
+ /* In a Level 2 environment, check for XUID first. */
+ if (level2_enabled &&
+ dict_find_string(pdict, "XUID", &puniqueid) > 0
+ ) {
+ long *xvalues;
+ uint size, i;
+
+ if (!r_has_type(puniqueid, t_array))
+ return_error(e_typecheck);
+ size = r_size(puniqueid);
+ if (size == 0)
+ return_error(e_rangecheck);
+ xvalues = (long *)gs_alloc_byte_array(mem, size, sizeof(long),
+ "get XUID");
+
+ if (xvalues == 0)
+ return_error(e_VMerror);
+ /* Get the values from the XUID array. */
+ for (i = 0; i < size; i++) {
+ const ref *pvalue = puniqueid->value.const_refs + i;
+
+ if (!r_has_type(pvalue, t_integer)) {
+ gs_free_object(mem, xvalues, "get XUID");
+ return_error(e_typecheck);
+ }
+ xvalues[i] = pvalue->value.intval;
+ }
+ uid_set_XUID(puid, xvalues, size);
+ return 1;
+ }
+ /* If no UniqueID entry, set the UID to invalid, */
+ /* because UniqueID need not be present in all fonts, */
+ /* and if it is, the legal range is 0 to 2^24-1. */
+ if (dict_find_string(pdict, "UniqueID", &puniqueid) <= 0) {
+ uid_set_invalid(puid);
+ return defaultval;
+ } else {
+ if (!r_has_type(puniqueid, t_integer) ||
+ puniqueid->value.intval < 0 ||
+ puniqueid->value.intval > 0xffffffL
+ )
+ return_error(e_rangecheck);
+ /* Apparently fonts created by Fontographer often have */
+ /* a UniqueID of 0, contrary to Adobe's specifications. */
+ /* Treat 0 as equivalent to -1 (no UniqueID). */
+ if (puniqueid->value.intval == 0) {
+ uid_set_invalid(puid);
+ return defaultval;
+ } else
+ uid_set_UniqueID(puid, puniqueid->value.intval);
+ }
+ return 0;
+}
+
+/* Check that a UID in a dictionary is equal to an existing, valid UID. */
+bool
+dict_check_uid_param(const ref * pdict, const gs_uid * puid)
+{
+ ref *puniqueid;
+
+ if (uid_is_XUID(puid)) {
+ uint size = uid_XUID_size(puid);
+ uint i;
+
+ if (dict_find_string(pdict, "XUID", &puniqueid) <= 0)
+ return false;
+ if (!r_has_type(puniqueid, t_array) ||
+ r_size(puniqueid) != size
+ )
+ return false;
+ for (i = 0; i < size; i++) {
+ const ref *pvalue = puniqueid->value.const_refs + i;
+
+ if (!r_has_type(pvalue, t_integer))
+ return false;
+ if (pvalue->value.intval != uid_XUID_values(puid)[i])
+ return false;
+ }
+ return true;
+ } else {
+ if (dict_find_string(pdict, "UniqueID", &puniqueid) <= 0)
+ return false;
+ return (r_has_type(puniqueid, t_integer) &&
+ puniqueid->value.intval == puid->id);
+ }
+}
diff --git a/pstoraster/idparam.h b/pstoraster/idparam.h
new file mode 100644
index 000000000..cf01cff1f
--- /dev/null
+++ b/pstoraster/idparam.h
@@ -0,0 +1,90 @@
+/* Copyright (C) 1992, 1993, 1994, 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 idparam.c */
+
+#ifndef idparam_INCLUDED
+# define idparam_INCLUDED
+
+#ifndef gs_matrix_DEFINED
+# define gs_matrix_DEFINED
+typedef struct gs_matrix_s gs_matrix;
+
+#endif
+
+#ifndef gs_uid_DEFINED
+# define gs_uid_DEFINED
+typedef struct gs_uid_s gs_uid;
+
+#endif
+
+/*
+ * Unless otherwise noted, all the following routines return 0 for
+ * a valid parameter, 1 for a defaulted parameter, or <0 on error.
+ *
+ * Note that all the dictionary parameter routines take a C string,
+ * not a t_name ref *. Even though this is slower, it means that
+ * the GC doesn't have to worry about finding statically declared
+ * name refs, and we have that many fewer static variables.
+ *
+ * All these routines allow pdict == NULL, which they treat the same as
+ * pdict referring to an empty dictionary. Routines with "null" in their
+ * name return 2 if the parameter is null, without setting *pvalue.
+ */
+int dict_bool_param(P4(const ref * pdict, const char *kstr,
+ bool defaultval, bool * pvalue));
+int dict_int_param(P6(const ref * pdict, const char *kstr,
+ int minval, int maxval, int defaultval, int *pvalue));
+int dict_int_null_param(P6(const ref * pdict, const char *kstr,
+ int minval, int maxval, int defaultval,
+ int *pvalue));
+int dict_uint_param(P6(const ref * pdict, const char *kstr,
+ uint minval, uint maxval, uint defaultval,
+ uint * pvalue));
+int dict_float_param(P4(const ref * pdict, const char *kstr,
+ floatp defaultval, float *pvalue));
+int dict_int_array_param(P4(const ref * pdict, const char *kstr,
+ uint maxlen, int *ivec));
+int dict_float_array_param(P5(const ref * pdict, const char *kstr,
+ uint maxlen, float *fvec,
+ const float *defaultvec));
+
+/*
+ * For dict_proc_param,
+ * defaultval = false means substitute t__invalid;
+ * defaultval = true means substitute an empty procedure.
+ * In either case, return 1.
+ */
+int dict_proc_param(P4(const ref * pdict, const char *kstr, ref * pproc,
+ bool defaultval));
+int dict_matrix_param(P3(const ref * pdict, const char *kstr,
+ gs_matrix * pmat));
+int dict_uid_param(P4(const ref * pdict, gs_uid * puid, int defaultval,
+ gs_memory_t * mem));
+
+/* Check that a UID in a dictionary is equal to an existing, valid UID. */
+bool dict_check_uid_param(P2(const ref * pdict, const gs_uid * puid));
+
+#endif /* idparam_INCLUDED */
diff --git a/pstoraster/idstack.c b/pstoraster/idstack.c
new file mode 100644
index 000000000..744dde405
--- /dev/null
+++ b/pstoraster/idstack.c
@@ -0,0 +1,249 @@
+/* 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$ */
+/* Implementation of dictionary stacks */
+#include "ghost.h"
+#include "idict.h"
+#include "idictdef.h"
+#include "idstack.h"
+#include "inamedef.h"
+#include "iname.h"
+#include "ipacked.h"
+#include "iutil.h"
+#include "ivmspace.h"
+
+/* Debugging statistics */
+#ifdef DEBUG
+#include "idebug.h"
+long ds_lookups; /* total lookups */
+long ds_1probe; /* successful lookups on only 1 probe */
+long ds_2probe; /* successful lookups on 2 probes */
+
+/* Wrapper for dstack_find_name_by_index */
+ref *real_dstack_find_name_by_index(P2(dict_stack_t * pds, uint nidx));
+ref *
+dstack_find_name_by_index(dict_stack_t * pds, uint nidx)
+{
+ ref *pvalue = real_dstack_find_name_by_index(pds, nidx);
+ dict *pdict = pds->stack.p->value.pdict;
+
+ ds_lookups++;
+ if (dict_is_packed(pdict)) {
+ uint hash =
+ dict_hash_mod(dict_name_index_hash(nidx), npairs(pdict)) + 1;
+
+ if (pdict->keys.value.packed[hash] ==
+ pt_tag(pt_literal_name) + nidx
+ )
+ ds_1probe++;
+ else if (pdict->keys.value.packed[hash - 1] ==
+ pt_tag(pt_literal_name) + nidx
+ )
+ ds_2probe++;
+ }
+ /* Do the cheap flag test before the expensive remainder test. */
+ if (gs_debug_c('d') && !(ds_lookups % 1000))
+ dlprintf3("[d]lookups=%ld 1probe=%ld 2probe=%ld\n",
+ ds_lookups, ds_1probe, ds_2probe);
+ return pvalue;
+}
+#define dstack_find_name_by_index real_dstack_find_name_by_index
+#endif
+
+/* Check whether a dictionary is one of the permanent ones on the d-stack. */
+bool
+dstack_dict_is_permanent(const dict_stack_t * pds, const ref * pdref)
+{
+ dict *pdict = pdref->value.pdict;
+ int i;
+
+ if (pds->stack.extension_size == 0) { /* Only one block of d-stack. */
+ for (i = 0; i < pds->min_size; ++i)
+ if (pds->stack.bot[i].value.pdict == pdict)
+ return true;
+ } else { /* More than one block of d-stack. */
+ uint count = ref_stack_count(&pds->stack);
+
+ for (i = count - pds->min_size; i < count; ++i)
+ if (ref_stack_index(&pds->stack, i)->value.pdict == pdict)
+ return true;
+ }
+ return false;
+}
+
+/*
+ * Look up a name on the dictionary stack.
+ * Return the pointer to the value if found, 0 if not.
+ */
+ref *
+dstack_find_name_by_index(dict_stack_t * pds, uint nidx)
+{
+ ds_ptr pdref = pds->stack.p;
+
+/* Since we know the hash function is the identity function, */
+/* there's no point in allocating a separate variable for it. */
+#define hash dict_name_index_hash(nidx)
+ ref_packed kpack = packed_name_key(nidx);
+
+ do {
+ dict *pdict = pdref->value.pdict;
+ uint size = npairs(pdict);
+
+#ifdef DEBUG
+ if (gs_debug_c('D')) {
+ ref dnref;
+
+ name_index_ref(nidx, &dnref);
+ dlputs("[D]lookup ");
+ debug_print_name(&dnref);
+ dprintf3(" in 0x%lx(%u/%u)\n",
+ (ulong) pdict, dict_length(pdref),
+ dict_maxlength(pdref));
+ }
+#endif
+ if (dict_is_packed(pdict)) {
+ packed_search_1(DO_NOTHING,
+ return packed_search_value_pointer,
+ DO_NOTHING, goto miss);
+ packed_search_2(DO_NOTHING,
+ return packed_search_value_pointer,
+ DO_NOTHING, break);
+ miss:;
+ } else {
+ ref *kbot = pdict->keys.value.refs;
+ register ref *kp;
+ int wrap = 0;
+
+ /* Search the dictionary */
+ for (kp = kbot + dict_hash_mod(hash, size) + 2;;) {
+ --kp;
+ if (r_has_type(kp, t_name)) {
+ if (name_index(kp) == nidx)
+ return pdict->values.value.refs +
+ (kp - kbot);
+ } else if (r_has_type(kp, t_null)) { /* Empty, deleted, or wraparound. */
+ /* Figure out which. */
+ if (!r_has_attr(kp, a_executable))
+ break;
+ if (kp == kbot) { /* wrap */
+ if (wrap++)
+ break; /* 2 wraps */
+ kp += size + 1;
+ }
+ }
+ }
+ }
+ }
+ while (pdref-- > pds->stack.bot);
+ /* The name isn't in the top dictionary block. */
+ /* If there are other blocks, search them now (more slowly). */
+ if (!pds->stack.extension_size) /* no more blocks */
+ return (ref *) 0;
+ { /* We could use the STACK_LOOP macros, but for now, */
+ /* we'll do things the simplest way. */
+ ref key;
+ uint i = pds->stack.p + 1 - pds->stack.bot;
+ uint size = ref_stack_count(&pds->stack);
+ ref *pvalue;
+
+ name_index_ref(nidx, &key);
+ for (; i < size; i++) {
+ if (dict_find(ref_stack_index(&pds->stack, i),
+ &key, &pvalue) > 0
+ )
+ return pvalue;
+ }
+ }
+ return (ref *) 0;
+#undef hash
+}
+
+/* Set the cached values computed from the top entry on the dstack. */
+/* See idstack.h for details. */
+private const ref_packed no_packed_keys[2] =
+{packed_key_deleted, packed_key_empty};
+void
+dstack_set_top(dict_stack_t * pds)
+{
+ ds_ptr dsp = pds->stack.p;
+ dict *pdict = dsp->value.pdict;
+
+ if_debug3('d', "[d]dsp = 0x%lx -> 0x%lx, key array type = %d\n",
+ (ulong) dsp, (ulong) pdict, r_type(&pdict->keys));
+ if (dict_is_packed(pdict) &&
+ r_has_attr(dict_access_ref(dsp), a_read)
+ ) {
+ pds->top_keys = pdict->keys.value.packed;
+ pds->top_npairs = npairs(pdict);
+ pds->top_values = pdict->values.value.refs;
+ } else {
+ pds->top_keys = no_packed_keys;
+ pds->top_npairs = 1;
+ }
+ if (!r_has_attr(dict_access_ref(dsp), a_write))
+ pds->def_space = -1;
+ else
+ pds->def_space = r_space(dsp);
+}
+
+/* After a garbage collection, scan the permanent dictionaries and */
+/* update the cached value pointers in names. */
+void
+dstack_gc_cleanup(dict_stack_t * pds)
+{
+ uint count = ref_stack_count(&pds->stack);
+ uint dsi;
+
+ for (dsi = pds->min_size; dsi > 0; --dsi) {
+ const dict *pdict =
+ ref_stack_index(&pds->stack, count - dsi)->value.pdict;
+ uint size = nslots(pdict);
+ ref *pvalue = pdict->values.value.refs;
+ uint i;
+
+ for (i = 0; i < size; ++i, ++pvalue) {
+ ref key;
+ ref *old_pvalue;
+
+ array_get(&pdict->keys, (long)i, &key);
+ if (r_has_type(&key, t_name) &&
+ pv_valid(old_pvalue = key.value.pname->pvalue)
+ ) { /*
+ * The name only has a single definition,
+ * so it must be this one. Check to see if
+ * no relocation is actually needed; if so,
+ * we can skip the entire dictionary.
+ */
+ if (old_pvalue == pvalue) {
+ if_debug1('d', "[d]skipping dstack entry %d\n",
+ dsi - 1);
+ break;
+ }
+ /* Update the value pointer. */
+ key.value.pname->pvalue = pvalue;
+ }
+ }
+ }
+}
diff --git a/pstoraster/idstack.h b/pstoraster/idstack.h
new file mode 100644
index 000000000..887b10eb3
--- /dev/null
+++ b/pstoraster/idstack.h
@@ -0,0 +1,125 @@
+/* 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 dictionary stack API */
+
+#ifndef idstack_INCLUDED
+# define idstack_INCLUDED
+
+#include "istack.h"
+
+/* Define the dictionary stack structure. */
+typedef struct dict_stack_s {
+
+ ref_stack stack; /* the actual stack of dictionaries */
+
+/*
+ * Switching between Level 1 and Level 2 involves inserting and removing
+ * globaldict on the dictionary stack. Instead of truly inserting and
+ * removing entries, we replace globaldict by a copy of systemdict in
+ * Level 1 mode. min_dstack_size, the minimum number of entries, does not
+ * change depending on language level; the countdictstack and dictstack
+ * operators must take this into account.
+ */
+ uint min_size; /* size of stack after clearing */
+
+ int userdict_index; /* index of userdict on stack */
+
+/*
+ * Cache a value for fast checking of def operations.
+ * If the top entry on the dictionary stack is a writable dictionary,
+ * dsspace is the space of the dictionary; if it is a non-writable
+ * dictionary, dsspace = -1. Then def is legal precisely if
+ * r_space(pvalue) <= dsspace. Note that in order for this trick to work,
+ * the result of r_space must be a signed integer; some compilers treat
+ * enums as unsigned, probably in violation of the ANSI standard.
+ */
+ int def_space;
+
+/*
+ * Cache values for fast name lookup. If the top entry on the dictionary
+ * stack is a readable dictionary with packed keys, dtop_keys, dtop_npairs,
+ * and dtop_values are keys.value.packed, npairs, and values.value.refs
+ * for that dictionary; otherwise, these variables point to a dummy
+ * empty dictionary.
+ */
+ const ref_packed *top_keys;
+ uint top_npairs;
+ ref *top_values;
+
+/*
+ * Cache a copy of the bottom entry on the stack, which is never deleted.
+ */
+ ref system_dict;
+
+} dict_stack_t;
+
+/*
+ * Reset the cached top values. Every routine that alters the
+ * dictionary stack (including changing the protection or size of the
+ * top dictionary on the stack) must call this.
+ */
+void dstack_set_top(P1(dict_stack_t *));
+
+/* Check whether a dictionary is one of the permanent ones on the d-stack. */
+bool dstack_dict_is_permanent(P2(const dict_stack_t *, const ref *));
+
+/* Define the type of pointers into the dictionary stack. */
+typedef s_ptr ds_ptr;
+typedef const_s_ptr const_ds_ptr;
+
+/* Clean up a dictionary stack after a garbage collection. */
+void dstack_gc_cleanup(P1(dict_stack_t *));
+
+/*
+ * Define a special fast entry for name lookup on a dictionary stack.
+ * The key is known to be a name; search the entire dict stack.
+ * Return the pointer to the value slot.
+ * If the name isn't found, just return 0.
+ */
+ref *dstack_find_name_by_index(P2(dict_stack_t *, uint));
+
+/*
+ * Define an extra-fast macro for name lookup, optimized for
+ * a single-probe lookup in the top dictionary on the stack.
+ * Amazingly enough, this seems to hit over 90% of the time
+ * (aside from operators, of course, which are handled either with
+ * the special cache pointer or with 'bind').
+ */
+#define dstack_find_name_by_index_inline(pds,nidx,htemp)\
+ ((pds)->top_keys[htemp = dict_hash_mod_inline(dict_name_index_hash(nidx),\
+ (pds)->top_npairs) + 1] == pt_tag(pt_literal_name) + (nidx) ?\
+ (pds)->top_values + htemp : dstack_find_name_by_index(pds, nidx))
+/*
+ * Define a similar macro that only checks the top dictionary on the stack.
+ */
+#define if_dstack_find_name_by_index_top(pds,nidx,htemp,pvslot)\
+ if ( (((pds)->top_keys[htemp = dict_hash_mod_inline(dict_name_index_hash(nidx),\
+ (pds)->top_npairs) + 1] == pt_tag(pt_literal_name) + (nidx)) ?\
+ ((pvslot) = (pds)->top_values + (htemp), 1) :\
+ 0)\
+ )
+
+#endif /* idstack_INCLUDED */
diff --git a/pstoraster/iestack.h b/pstoraster/iestack.h
new file mode 100644
index 000000000..751f99bcd
--- /dev/null
+++ b/pstoraster/iestack.h
@@ -0,0 +1,56 @@
+/* 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$ */
+/* Generic execution stack API */
+
+#ifndef iestack_INCLUDED
+# define iestack_INCLUDED
+
+#include "istack.h"
+
+/* Define the execution stack structure. */
+typedef struct exec_stack_s {
+
+ ref_stack stack; /* the actual execution stack */
+
+/*
+ * To improve performance, we cache the currentfile pointer
+ * (i.e., `shallow-bind' it in Lisp terminology). The invariant is as
+ * follows: either esfile points to the currentfile slot on the estack
+ * (i.e., the topmost slot with an executable file), or it is 0.
+ * To maintain the invariant, it is sufficient that whenever a routine
+ * pushes or pops anything on the estack, if the object *might* be
+ * an executable file, invoke esfile_clear_cache(); alternatively,
+ * immediately after pushing an object, invoke esfile_check_cache().
+ */
+ ref *current_file;
+
+} exec_stack_t;
+
+/* Define pointers into the execution stack. */
+typedef s_ptr es_ptr;
+typedef const_s_ptr const_es_ptr;
+
+#endif /* iestack_INCLUDED */
diff --git a/pstoraster/ifilter.h b/pstoraster/ifilter.h
new file mode 100644
index 000000000..9d0803bd7
--- /dev/null
+++ b/pstoraster/ifilter.h
@@ -0,0 +1,89 @@
+/* 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$ */
+/* Requires oper.h, stream.h, strimpl.h */
+
+#ifndef ifilter_INCLUDED
+# define ifilter_INCLUDED
+
+#include "istream.h"
+#include "ivmspace.h"
+
+/*
+ * Define the utility procedures for creating filters.
+ * Note that a filter will be allocated in global VM iff the source/target
+ * and all relevant parameters (if any) are in global VM.
+ */
+int filter_read(P5(
+ /* Operand stack pointer that was passed to zfxxx operator */
+ os_ptr op,
+ /* # of parameters to pop off o-stack, */
+ /* not counting the source/target */
+ int npop,
+ /* Template for stream */
+ const stream_template * template,
+ /* Initialized s_xxx_state, 0 if no separate state */
+ stream_state * st,
+ /* Max of space attributes of all parameters referenced by */
+ /* the state, 0 if no such parameters */
+ uint space
+ ));
+int filter_write(P5(os_ptr op, int npop, const stream_template * template,
+ stream_state * st, uint space));
+
+/*
+ * Define a simplified interface for streams with no parameters or state.
+ * These procedures also pop the top o-stack element if it is a dictionary.
+ */
+int filter_read_simple(P2(os_ptr op, const stream_template * template));
+int filter_write_simple(P2(os_ptr op, const stream_template * template));
+
+/* Mark a filter stream as temporary. */
+/* See stream.h for the meaning of is_temp. */
+void filter_mark_temp(P2(const ref * fop, int is_temp));
+
+/* Define a standard report_error procedure for filters, */
+/* that records the error message in $error.errorinfo. */
+stream_proc_report_error(filter_report_error);
+
+/*
+ * Define the state of a procedure-based stream.
+ * Note that procedure-based streams are defined at the Ghostscript
+ * interpreter level, unlike all other stream types which depend only
+ * on the stream package and the memory manager.
+ */
+typedef struct stream_proc_state_s {
+ stream_state_common;
+ bool eof;
+ uint index; /* current index within data */
+ ref proc;
+ ref data;
+} stream_proc_state;
+
+#define private_st_stream_proc_state() /* in zfproc.c */\
+ gs_private_st_complex_only(st_sproc_state, stream_proc_state,\
+ "procedure stream state", sproc_clear_marks, sproc_enum_ptrs, sproc_reloc_ptrs, 0)
+
+#endif /* ifilter_INCLUDED */
diff --git a/pstoraster/ifont.h b/pstoraster/ifont.h
new file mode 100644
index 000000000..857a18741
--- /dev/null
+++ b/pstoraster/ifont.h
@@ -0,0 +1,97 @@
+/* Copyright (C) 1989, 1991, 1993, 1994, 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$ */
+/* Interpreter internal font representation */
+
+#ifndef ifont_INCLUDED
+# define ifont_INCLUDED
+
+#include "gsccode.h" /* for gs_glyph */
+#include "gsstruct.h" /* for extern_st */
+
+/* The external definition of fonts is given in the PostScript manual, */
+/* pp. 91-93. */
+
+/* The structure given below is 'client data' from the viewpoint */
+/* of the library. font-type objects (t_struct/st_font, "t_fontID") */
+/* point directly to a gs_font. */
+
+typedef struct font_data_s {
+ ref dict; /* font dictionary object */
+ ref BuildChar;
+ ref BuildGlyph;
+ ref Encoding;
+ ref CharStrings;
+ union _fs {
+ struct _f1 {
+ ref OtherSubrs; /* from Private dictionary */
+ ref Subrs; /* from Private dictionary */
+ ref GlobalSubrs; /* from Private dictionary, */
+ /* for Type 2 charstrings */
+ } type1;
+ struct _f42 {
+ ref sfnts;
+ ref GlyphDirectory;
+ } type42;
+ } u;
+} font_data;
+
+/*
+ * Even though the interpreter's part of the font data actually
+ * consists of refs, allocating it as refs tends to create sandbars;
+ * since it is always allocated and freed as a unit, we can treat it
+ * as an ordinary structure.
+ */
+/* st_font_data is exported for zdefault_make_font in zfont.c. */
+extern_st(st_font_data);
+#define public_st_font_data() /* in zfont2.c */\
+ gs_public_st_ref_struct(st_font_data, font_data, "font_data")
+#define pfont_data(pfont) ((font_data *)((pfont)->client_data))
+#define pfont_dict(pfont) (&pfont_data(pfont)->dict)
+
+/* Registered encodings, for the benefit of platform fonts, `seac', */
+/* and compiled font initialization. */
+/* This is a t_array ref that points to the encodings. */
+#define registered_Encodings_countof 5
+extern ref registered_Encodings;
+
+#define registered_Encoding(i) (registered_Encodings.value.refs[i])
+#define StandardEncoding registered_Encoding(0)
+
+/* Internal procedures shared between modules */
+
+/* In zchar.c */
+int font_bbox_param(P2(const ref * pfdict, double bbox[4]));
+
+/* In zfont.c */
+#ifndef gs_font_DEFINED
+# define gs_font_DEFINED
+typedef struct gs_font_s gs_font;
+
+#endif
+int font_param(P2(const ref * pfdict, gs_font ** ppfont));
+bool zfont_mark_glyph_name(P2(gs_glyph glyph, void *ignore_data));
+
+#endif /* ifont_INCLUDED */
diff --git a/pstoraster/ifunc.h b/pstoraster/ifunc.h
new file mode 100644
index 000000000..26c4c2fc0
--- /dev/null
+++ b/pstoraster/ifunc.h
@@ -0,0 +1,58 @@
+/* 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$ */
+/* Internal interpreter interfaces for Functions */
+
+#ifndef ifunc_INCLUDED
+# define ifunc_INCLUDED
+
+/* Define build procedures for the various function types. */
+#define build_function_proc(proc)\
+ int proc(P4(const_os_ptr op, const gs_function_params_t *params, int depth,\
+ gs_function_t **ppfn))
+build_function_proc(build_function_undefined);
+
+/* Define the table of build procedures, indexed by FunctionType. */
+extern build_function_proc((*build_function_procs[5]));
+
+/* Build a function structure from a PostScript dictionary. */
+int fn_build_sub_function(P3(const ref * op, gs_function_t ** ppfn, int depth));
+
+#define fn_build_function(op, ppfn)\
+ fn_build_sub_function(op, ppfn, 0)
+
+/* Allocate an array of function objects. */
+int ialloc_function_array(P2(uint count, gs_function_t *** pFunctions));
+
+/*
+ * Collect a heap-allocated array of floats. If the key is missing, set
+ * *pparray = 0 and return 0; otherwise set *pparray and return the number
+ * of elements. Note that 0-length arrays are acceptable, so if the value
+ * returned is 0, the caller must check whether *pparray == 0.
+ */
+int fn_build_float_array(P5(const ref * op, const char *kstr, bool required,
+ bool even, const float **pparray));
+
+#endif /* ifunc_INCLUDED */
diff --git a/pstoraster/igc.c b/pstoraster/igc.c
new file mode 100644
index 000000000..9305e77e1
--- /dev/null
+++ b/pstoraster/igc.c
@@ -0,0 +1,1316 @@
+/* Copyright (C) 1993, 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$ */
+/* Garbage collector for Ghostscript */
+#include "memory_.h"
+#include "ghost.h"
+#include "errors.h"
+#include "gsexit.h"
+#include "gsmdebug.h"
+#include "gsstruct.h"
+#include "gsutil.h"
+#include "iastate.h"
+#include "isave.h"
+#include "isstate.h"
+#include "idict.h"
+#include "ipacked.h"
+#include "istruct.h"
+#include "igc.h"
+#include "igcstr.h"
+#include "inamedef.h"
+#include "opdef.h" /* for marking oparray names */
+
+/* Define whether to force all garbage collections to be global. */
+private bool I_FORCE_GLOBAL_GC = false;
+
+/* Define whether to bypass the collector entirely. */
+private bool I_BYPASS_GC = false;
+
+/* Avoid including all of iname.h. */
+extern name_table *the_gs_name_table;
+
+/* Define an entry on the mark stack. */
+typedef struct {
+ void *ptr;
+ uint index;
+ bool is_refs;
+} ms_entry;
+
+/* Define (a segment of) the mark stack. */
+/* entries[0] has ptr = 0 to indicate the bottom of the stack. */
+/* count additional entries follow this structure. */
+typedef struct gc_mark_stack_s gc_mark_stack;
+struct gc_mark_stack_s {
+ gc_mark_stack *prev;
+ gc_mark_stack *next;
+ uint count;
+ bool on_heap; /* if true, allocated during GC */
+ ms_entry entries[1];
+};
+
+/* Define the mark stack sizing parameters. */
+#define ms_size_default 100 /* default, allocated on C stack */
+/* This should probably be defined as a parameter somewhere.... */
+#define ms_size_desired /* for additional allocation */\
+ ((max_ushort - sizeof(gc_mark_stack)) / sizeof(ms_entry) - 10)
+#define ms_size_min 50 /* min size for segment in free block */
+
+/* Forward references */
+private void gc_init_mark_stack(P2(gc_mark_stack *, uint));
+private void gc_objects_clear_marks(P1(chunk_t *));
+private void gc_unmark_names(P1(name_table *));
+private int gc_trace(P3(gs_gc_root_t *, gc_state_t *, gc_mark_stack *));
+private int gc_rescan_chunk(P3(chunk_t *, gc_state_t *, gc_mark_stack *));
+private int gc_trace_chunk(P3(chunk_t *, gc_state_t *, gc_mark_stack *));
+private bool gc_trace_finish(P1(gc_state_t *));
+private void gc_clear_reloc(P1(chunk_t *));
+private void gc_objects_set_reloc(P1(chunk_t *));
+private void gc_do_reloc(P3(chunk_t *, gs_ref_memory_t *, gc_state_t *));
+private void gc_objects_compact(P2(chunk_t *, gc_state_t *));
+private void gc_free_empty_chunks(P1(gs_ref_memory_t *));
+
+/* Forward references for pointer types */
+private ptr_proc_unmark(ptr_struct_unmark);
+private ptr_proc_mark(ptr_struct_mark);
+private ptr_proc_unmark(ptr_string_unmark);
+private ptr_proc_mark(ptr_string_mark);
+
+ /*ptr_proc_unmark(ptr_ref_unmark); *//* in igc.h */
+ /*ptr_proc_mark(ptr_ref_mark); *//* in igc.h */
+private ptr_proc_reloc(igc_reloc_struct_ptr, void);
+
+string_proc_reloc(igc_reloc_string); /* in igcstr.c */
+const_string_proc_reloc(igc_reloc_const_string); /* in igcstr.c */
+ptr_proc_reloc(igc_reloc_ref_ptr, ref_packed); /* in igcref.c */
+refs_proc_reloc(igc_reloc_refs); /* in igcref.c */
+
+/* Define this GC's procedure vector. */
+private const gc_procs_with_refs_t igc_procs =
+{
+ igc_reloc_struct_ptr, igc_reloc_string, igc_reloc_const_string,
+ igc_reloc_ref_ptr, igc_reloc_refs
+};
+
+/* Pointer type descriptors. */
+/* Note that the trace/mark routine has special knowledge of ptr_ref_type */
+/* and ptr_struct_type -- it assumes that no other types have embedded */
+/* pointers. Note also that the reloc procedures for string and ref */
+/* pointers are never called. */
+typedef ptr_proc_reloc((*ptr_proc_reloc_t), void);
+const gs_ptr_procs_t ptr_struct_procs =
+{ptr_struct_unmark, ptr_struct_mark, (ptr_proc_reloc_t) igc_reloc_struct_ptr};
+const gs_ptr_procs_t ptr_string_procs =
+{ptr_string_unmark, ptr_string_mark, NULL};
+const gs_ptr_procs_t ptr_const_string_procs =
+{ptr_string_unmark, ptr_string_mark, NULL};
+const gs_ptr_procs_t ptr_ref_procs =
+{ptr_ref_unmark, ptr_ref_mark, NULL};
+
+/* ------ Main program ------ */
+
+/* Top level of garbage collector. */
+#ifdef DEBUG
+private void
+end_phase(const char *str)
+{
+ if (gs_debug_c('6')) {
+ dlprintf1("[6]---------------- end %s ----------------\n",
+ (const char *)str);
+ fflush(dstderr);
+ }
+}
+static const char *const depth_dots_string = "..........";
+private const char *
+depth_dots(const ms_entry * sp, const gc_mark_stack * pms)
+{
+ int depth = sp - pms->entries - 1;
+ const gc_mark_stack *pss = pms;
+
+ while ((pss = pss->prev) != 0)
+ depth += pss->count - 1;
+ return depth_dots_string + (depth >= 10 ? 0 : 10 - depth);
+}
+#else
+# define end_phase(str) DO_NOTHING
+#endif
+void
+gs_reclaim(vm_spaces * pspaces, bool global)
+{
+ vm_spaces spaces;
+
+#define nspaces (i_vm_max + 1)
+ gs_gc_root_t space_roots[nspaces];
+ int max_trace; /* max space to trace */
+ int min_collect; /* min space to collect */
+ int ispace;
+ gs_ref_memory_t *mem;
+ chunk_t *cp;
+ gs_gc_root_t *rp;
+ gc_state_t state;
+ struct _msd {
+ gc_mark_stack stack;
+ ms_entry body[ms_size_default];
+ } ms_default;
+ gc_mark_stack *mark_stack = &ms_default.stack;
+
+ /* Optionally force global GC for debugging. */
+ if (I_FORCE_GLOBAL_GC)
+ global = true;
+
+ /* Determine which spaces we are collecting. */
+ spaces = *pspaces;
+ if (space_global != space_local)
+ max_trace = i_vm_local;
+ else
+ max_trace = i_vm_global;
+ min_collect = (global ? 1 : max_trace);
+
+#define for_spaces(i, n)\
+ for ( i = 1; i <= n; ++i )
+#define for_collected_spaces(i)\
+ for ( i = min_collect; i <= max_trace; ++i )
+#define for_space_mems(i, mem)\
+ for ( mem = spaces.indexed[i]; mem != 0; mem = &mem->saved->state )
+#define for_mem_chunks(mem, cp)\
+ for ( cp = (mem)->cfirst; cp != 0; cp = cp->cnext )
+#define for_space_chunks(i, mem, cp)\
+ for_space_mems(i, mem) for_mem_chunks(mem, cp)
+#define for_chunks(n, mem, cp)\
+ for_spaces(ispace, n) for_space_chunks(ispace, mem, cp)
+#define for_collected_chunks(mem, cp)\
+ for_collected_spaces(ispace) for_space_chunks(ispace, mem, cp)
+#define for_roots(n, mem, rp)\
+ for_spaces(ispace, n)\
+ for ( mem = spaces.indexed[ispace], rp = mem->roots; rp != 0; rp = rp->next )
+
+ /* Initialize the state. */
+ state.procs = &igc_procs;
+ state.loc.memory = spaces.named.global; /* any one will do */
+
+ state.loc.cp = 0;
+ state.spaces = spaces;
+ state.min_collect = min_collect << r_space_shift;
+ state.relocating_untraced = false;
+ state.heap = state.loc.memory->parent;
+ state.ntable = the_gs_name_table;
+
+ /* Register the allocators themselves as roots, */
+ /* so we mark and relocate the change and save lists properly. */
+
+ for_spaces(ispace, max_trace)
+ gs_register_struct_root((gs_memory_t *) spaces.indexed[ispace],
+ &space_roots[ispace],
+ (void **)&spaces.indexed[ispace],
+ "gc_top_level");
+
+ end_phase("register space roots");
+
+#ifdef DEBUG
+
+ /* Pre-validate the state. This shouldn't be necessary.... */
+
+ for_spaces(ispace, max_trace)
+ ialloc_validate_memory(spaces.indexed[ispace], &state);
+
+ end_phase("pre-validate pointers");
+
+#endif
+
+ if (I_BYPASS_GC) { /* Don't collect at all. */
+ goto no_collect;
+ }
+ /* Clear marks in spaces to be collected. */
+
+ for_collected_spaces(ispace)
+ for_space_chunks(ispace, mem, cp) {
+ gc_objects_clear_marks(cp);
+ gc_strings_set_marks(cp, false);
+ }
+
+ end_phase("clear chunk marks");
+
+ /* Clear the marks of roots. We must do this explicitly, */
+ /* since some roots are not in any chunk. */
+
+ for_roots(max_trace, mem, rp) {
+ void *vptr = *rp->p;
+
+ if_debug_root('6', "[6]unmarking root", rp);
+ (*rp->ptype->unmark) (vptr, &state);
+ }
+
+ end_phase("clear root marks");
+
+ if (global)
+ gc_unmark_names(state.ntable);
+
+ /* Initialize the (default) mark stack. */
+
+ gc_init_mark_stack(&ms_default.stack, ms_size_default);
+ ms_default.stack.prev = 0;
+ ms_default.stack.on_heap = false;
+
+ /* Add all large-enough free blocks to the mark stack. */
+ /* Also initialize the rescan pointers. */
+
+ {
+ gc_mark_stack *end = mark_stack;
+
+ for_chunks(max_trace, mem, cp) {
+ uint avail = cp->ctop - cp->cbot;
+
+ if (avail >= sizeof(gc_mark_stack) + sizeof(ms_entry) *
+ ms_size_min &&
+ !cp->inner_count
+ ) {
+ gc_mark_stack *pms = (gc_mark_stack *) cp->cbot;
+
+ gc_init_mark_stack(pms, (avail - sizeof(gc_mark_stack)) /
+ sizeof(ms_entry));
+ end->next = pms;
+ pms->prev = end;
+ pms->on_heap = false;
+ if_debug2('6', "[6]adding free 0x%lx(%u) to mark stack\n",
+ (ulong) pms, pms->count);
+ }
+ cp->rescan_bot = cp->cend;
+ cp->rescan_top = cp->cbase;
+ }
+ }
+
+ /* Mark reachable objects. */
+
+ {
+ int more = 0;
+
+ /* Mark from roots. */
+
+ for_roots(max_trace, mem, rp) {
+ if_debug_root('6', "[6]marking root", rp);
+ more |= gc_trace(rp, &state, mark_stack);
+ }
+
+ end_phase("mark");
+
+ /* If this is a local GC, mark from non-local chunks. */
+
+ if (!global)
+ for_chunks(min_collect - 1, mem, cp)
+ more |= gc_trace_chunk(cp, &state, mark_stack);
+
+ /* Handle mark stack overflow. */
+
+ while (more < 0) { /* stack overflowed */
+ more = 0;
+ for_chunks(max_trace, mem, cp)
+ more |= gc_rescan_chunk(cp, &state, mark_stack);
+ }
+
+ end_phase("mark overflow");
+ }
+
+ /* Free the mark stack. */
+
+ {
+ gc_mark_stack *pms = mark_stack;
+
+ while (pms->next)
+ pms = pms->next;
+ while (pms) {
+ gc_mark_stack *prev = pms->prev;
+
+ if (pms->on_heap)
+ gs_free_object(state.heap, pms, "gc mark stack");
+ else
+ gs_alloc_fill(pms, gs_alloc_fill_free,
+ sizeof(*pms) + sizeof(ms_entry) * pms->count);
+ pms = prev;
+ }
+ }
+
+ end_phase("free mark stack");
+
+ if (global) {
+ gc_trace_finish(&state);
+ names_trace_finish(state.ntable, &state);
+
+ end_phase("finish trace");
+ }
+ /* Clear marks and relocation in spaces that are only being traced. */
+ /* We have to clear the marks first, because we want the */
+ /* relocation to wind up as o_untraced, not o_unmarked. */
+
+ for_chunks(min_collect - 1, mem, cp)
+ gc_objects_clear_marks(cp);
+
+ end_phase("post-clear marks");
+
+ for_chunks(min_collect - 1, mem, cp)
+ gc_clear_reloc(cp);
+
+ end_phase("clear reloc");
+
+ /* Set the relocation of roots outside any chunk to o_untraced, */
+ /* so we won't try to relocate pointers to them. */
+ /* (Currently, there aren't any.) */
+
+ /* Disable freeing in the allocators of the spaces we are */
+ /* collecting, so finalization procedures won't cause problems. */
+ {
+ int i;
+
+ for_collected_spaces(i)
+ gs_enable_free((gs_memory_t *) spaces.indexed[i], false);
+ }
+
+ /* Compute relocation based on marks, in the spaces */
+ /* we are going to compact. Also finalize freed objects. */
+
+ for_collected_chunks(mem, cp) {
+ gc_objects_set_reloc(cp);
+ gc_strings_set_reloc(cp);
+ }
+
+ /* Re-enable freeing. */
+ {
+ int i;
+
+ for_collected_spaces(i)
+ gs_enable_free((gs_memory_t *) spaces.indexed[i], true);
+ }
+
+ end_phase("set reloc");
+
+ /* Relocate pointers. */
+
+ state.relocating_untraced = true;
+ for_chunks(min_collect - 1, mem, cp)
+ gc_do_reloc(cp, mem, &state);
+ state.relocating_untraced = false;
+ for_collected_chunks(mem, cp)
+ gc_do_reloc(cp, mem, &state);
+
+ end_phase("relocate chunks");
+
+ for_roots(max_trace, mem, rp) {
+ if_debug3('6', "[6]relocating root 0x%lx: 0x%lx -> 0x%lx\n",
+ (ulong) rp, (ulong) rp->p, (ulong) * rp->p);
+ if (rp->ptype == ptr_ref_type) {
+ ref *pref = (ref *) * rp->p;
+
+ igc_reloc_refs((ref_packed *) pref,
+ (ref_packed *) (pref + 1),
+ &state);
+ } else
+ *rp->p = (*rp->ptype->reloc) (*rp->p, &state);
+ if_debug3('6', "[6]relocated root 0x%lx: 0x%lx -> 0x%lx\n",
+ (ulong) rp, (ulong) rp->p, (ulong) * rp->p);
+ }
+
+ end_phase("relocate roots");
+
+ /* Compact data. We only do this for spaces we are collecting. */
+
+ for_collected_spaces(ispace) {
+ for_space_mems(ispace, mem) {
+ for_mem_chunks(mem, cp) {
+ if_debug_chunk('6', "[6]compacting chunk", cp);
+ gc_objects_compact(cp, &state);
+ gc_strings_compact(cp);
+ if_debug_chunk('6', "[6]after compaction:", cp);
+ if (mem->pcc == cp)
+ mem->cc = *cp;
+ }
+ mem->saved = mem->reloc_saved;
+ ialloc_reset_free(mem);
+ }
+ }
+
+ end_phase("compact");
+
+ /* Free empty chunks. */
+
+ for_collected_spaces(ispace)
+ for_space_mems(ispace, mem)
+ gc_free_empty_chunks(mem);
+
+ end_phase("free empty chunks");
+
+ /*
+ * Update previous_status to reflect any freed chunks,
+ * and set inherited to the negative of allocated,
+ * so it has no effect. We must update previous_status by
+ * working back-to-front along the save chain, using pointer reversal.
+ * (We could update inherited in any order, since it only uses
+ * information local to the individual save level.)
+ */
+
+ for_collected_spaces(ispace) { /* Reverse the pointers. */
+ alloc_save_t *curr;
+ alloc_save_t *prev = 0;
+ alloc_save_t *next;
+ gs_memory_status_t total;
+
+ for (curr = spaces.indexed[ispace]->saved; curr != 0;
+ prev = curr, curr = next
+ ) {
+ next = curr->state.saved;
+ curr->state.saved = prev;
+ }
+ /* Now work the other way, accumulating the values. */
+ total.allocated = 0, total.used = 0;
+ for (curr = prev, prev = 0; curr != 0;
+ prev = curr, curr = next
+ ) {
+ mem = &curr->state;
+ next = mem->saved;
+ mem->saved = prev;
+ mem->previous_status = total;
+ if_debug3('6',
+ "[6]0x%lx previous allocated=%lu, used=%lu\n",
+ (ulong) mem, total.allocated, total.used);
+ gs_memory_status((gs_memory_t *) mem, &total);
+ mem->gc_allocated = mem->allocated + total.allocated;
+ mem->inherited = -mem->allocated;
+ }
+ mem = spaces.indexed[ispace];
+ mem->previous_status = total;
+ mem->gc_allocated = mem->allocated + total.allocated;
+ if_debug3('6', "[6]0x%lx previous allocated=%lu, used=%lu\n",
+ (ulong) mem, total.allocated, total.used);
+ }
+
+ end_phase("update stats");
+
+ no_collect:
+
+ /* Unregister the allocator roots. */
+
+ for_spaces(ispace, max_trace)
+ gs_unregister_root((gs_memory_t *) spaces.indexed[ispace],
+ &space_roots[ispace], "gc_top_level");
+
+ end_phase("unregister space roots");
+
+#ifdef DEBUG
+
+ /* Validate the state. This shouldn't be necessary.... */
+
+ for_spaces(ispace, max_trace)
+ ialloc_validate_memory(spaces.indexed[ispace], &state);
+
+ end_phase("validate pointers");
+
+#endif
+}
+
+/* ------ Debugging utilities ------ */
+
+/* Validate a pointer to an object header. */
+#ifdef DEBUG
+# define debug_check_object(pre, cp, gcst)\
+ ialloc_validate_object((pre) + 1, cp, gcst)
+#else
+# define debug_check_object(pre, cp, gcst) DO_NOTHING
+#endif
+
+/* ------ Unmarking phase ------ */
+
+/* Unmark a single struct. */
+private void
+ptr_struct_unmark(void *vptr, gc_state_t * ignored)
+{
+ if (vptr != 0)
+ o_set_unmarked(((obj_header_t *) vptr - 1));
+}
+
+/* Unmark a single string. */
+private void
+ptr_string_unmark(void *vptr, gc_state_t * gcst)
+{
+ discard(gc_string_mark(((gs_string *) vptr)->data,
+ ((gs_string *) vptr)->size,
+ false, gcst));
+}
+
+/* Unmark the objects in a chunk. */
+private void
+gc_objects_clear_marks(chunk_t * cp)
+{
+ if_debug_chunk('6', "[6]unmarking chunk", cp);
+ SCAN_CHUNK_OBJECTS(cp)
+ DO_ALL
+ struct_proc_clear_marks((*proc)) =
+ pre->o_type->clear_marks;
+#ifdef DEBUG
+ if (pre->o_type != &st_free)
+ debug_check_object(pre, cp, NULL);
+#endif
+ if_debug3('7', " [7](un)marking %s(%lu) 0x%lx\n",
+ struct_type_name_string(pre->o_type),
+ (ulong) size, (ulong) pre);
+ o_set_unmarked(pre);
+ if (proc != 0)
+ (*proc) (pre + 1, size, pre->o_type);
+ END_OBJECTS_SCAN
+}
+
+/* Mark 0- and 1-character names, and those referenced from the */
+/* op_array_nx_table, and unmark all the rest. */
+private void
+gc_unmark_names(name_table * nt)
+{
+ register uint i;
+
+ names_unmark_all(nt);
+ for (i = 0; i < op_array_table_global.count; i++) {
+ name_index_t nidx = op_array_table_global.nx_table[i];
+
+ names_index_ptr(nt, nidx)->mark = 1;
+ }
+ for (i = 0; i < op_array_table_local.count; i++) {
+ name_index_t nidx = op_array_table_local.nx_table[i];
+
+ names_index_ptr(nt, nidx)->mark = 1;
+ }
+}
+
+/* ------ Marking phase ------ */
+
+/* Initialize (a segment of) the mark stack. */
+private void
+gc_init_mark_stack(gc_mark_stack * pms, uint count)
+{
+ pms->next = 0;
+ pms->count = count;
+ pms->entries[0].ptr = 0;
+ pms->entries[0].index = 0;
+ pms->entries[0].is_refs = false;
+}
+
+/* Mark starting from all marked objects in the interval of a chunk */
+/* needing rescanning. */
+private int
+gc_rescan_chunk(chunk_t * cp, gc_state_t * pstate, gc_mark_stack * pmstack)
+{
+ byte *sbot = cp->rescan_bot;
+ byte *stop = cp->rescan_top;
+ gs_gc_root_t root;
+ void *comp;
+ int more = 0;
+
+ if (sbot > stop)
+ return 0;
+ root.p = &comp;
+ if_debug_chunk('6', "[6]rescanning chunk", cp);
+ cp->rescan_bot = cp->cend;
+ cp->rescan_top = cp->cbase;
+ SCAN_CHUNK_OBJECTS(cp)
+ DO_ALL
+ if ((byte *) (pre + 1) + size < sbot);
+ else if ((byte *) (pre + 1) > stop)
+ return more; /* 'break' won't work here */
+ else {
+ if_debug2('7', " [7]scanning/marking 0x%lx(%lu)\n",
+ (ulong) pre, (ulong) size);
+ if (pre->o_type == &st_refs) {
+ ref_packed *rp = (ref_packed *) (pre + 1);
+ char *end = (char *)rp + size;
+
+ root.ptype = ptr_ref_type;
+ while ((char *)rp < end) {
+ comp = rp;
+ if (r_is_packed(rp)) {
+ if (r_has_pmark(rp)) {
+ r_clear_pmark(rp);
+ more |= gc_trace(&root, pstate,
+ pmstack);
+ }
+ rp++;
+ } else {
+ if (r_has_attr((ref *) rp, l_mark)) {
+ r_clear_attrs((ref *) rp, l_mark);
+ more |= gc_trace(&root, pstate,
+ pmstack);
+ }
+ rp += packed_per_ref;
+ }
+ }
+ } else if (!o_is_unmarked(pre)) {
+ struct_proc_clear_marks((*proc)) =
+ pre->o_type->clear_marks;
+ root.ptype = ptr_struct_type;
+ comp = pre + 1;
+ if (!o_is_untraced(pre))
+ o_set_unmarked(pre);
+ if (proc != 0)
+ (*proc) (comp, size, pre->o_type);
+ more |= gc_trace(&root, pstate, pmstack);
+ }
+ }
+ END_OBJECTS_SCAN
+ return more;
+}
+
+/* Mark starting from all the objects in a chunk. */
+/* We assume that pstate->min_collect > avm_system, */
+/* so we don't have to trace names. */
+private int
+gc_trace_chunk(chunk_t * cp, gc_state_t * pstate, gc_mark_stack * pmstack)
+{
+ gs_gc_root_t root;
+ void *comp;
+ int more = 0;
+ int min_trace = pstate->min_collect;
+
+ root.p = &comp;
+ if_debug_chunk('6', "[6]marking from chunk", cp);
+ SCAN_CHUNK_OBJECTS(cp)
+ DO_ALL
+ {
+ if_debug2('7', " [7]scanning/marking 0x%lx(%lu)\n",
+ (ulong) pre, (ulong) size);
+ if (pre->o_type == &st_refs) {
+ ref_packed *rp = (ref_packed *) (pre + 1);
+ char *end = (char *)rp + size;
+
+ root.ptype = ptr_ref_type;
+ while ((char *)rp < end) {
+ comp = rp;
+ if (r_is_packed(rp)) { /* No packed refs need tracing. */
+ rp++;
+ } else {
+ if (r_space((ref *) rp) >= min_trace) {
+ r_clear_attrs((ref *) rp, l_mark);
+ more |= gc_trace(&root, pstate,
+ pmstack);
+ }
+ rp += packed_per_ref;
+ }
+ }
+ } else if (!o_is_unmarked(pre)) {
+ if (!o_is_untraced(pre))
+ o_set_unmarked(pre);
+ if (pre->o_type != &st_free) {
+ struct_proc_clear_marks((*proc)) =
+ pre->o_type->clear_marks;
+
+ root.ptype = ptr_struct_type;
+ comp = pre + 1;
+ if (proc != 0)
+ (*proc) (comp, size, pre->o_type);
+ more |= gc_trace(&root, pstate, pmstack);
+ }
+ }
+ }
+ END_OBJECTS_SCAN
+ return more;
+}
+
+/* Recursively mark from a (root) pointer. */
+/* Return -1 if we overflowed the mark stack, */
+/* 0 if we completed successfully without marking any new objects, */
+/* 1 if we completed and marked some new objects. */
+private int gc_extend_stack(P2(gc_mark_stack *, gc_state_t *));
+private int
+gc_trace(gs_gc_root_t * rp, gc_state_t * pstate, gc_mark_stack * pmstack)
+{
+ int min_trace = pstate->min_collect;
+ gc_mark_stack *pms = pmstack;
+ ms_entry *sp = pms->entries + 1;
+
+ /* We stop the mark stack 1 entry early, because we store into */
+ /* the entry beyond the top. */
+ ms_entry *stop = sp + pms->count - 2;
+ int new = 0;
+ void *nptr = *rp->p;
+ name_table *nt = pstate->ntable;
+
+#define mark_name(nidx, pname)\
+ { if ( !pname->mark )\
+ { pname->mark = 1;\
+ new |= 1;\
+ if_debug2('8', " [8]marked name 0x%lx(%u)\n", (ulong)pname, nidx);\
+ }\
+ }
+
+ if (nptr == 0)
+ return 0;
+
+ /* Initialize the stack */
+ sp->ptr = nptr;
+ if (rp->ptype == ptr_ref_type)
+ sp->index = 1, sp->is_refs = true;
+ else {
+ sp->index = 0, sp->is_refs = false;
+ if ((*rp->ptype->mark) (nptr, pstate))
+ new |= 1;
+ }
+ for (;;) {
+ gs_ptr_type_t ptp;
+
+ /*
+ * The following should really be an if..else, but that
+ * would force unnecessary is_refs tests.
+ */
+ if (sp->is_refs)
+ goto do_refs;
+
+ /* ---------------- Structure ---------------- */
+
+ do_struct:
+ {
+ obj_header_t *ptr = sp->ptr;
+
+ struct_proc_enum_ptrs((*mproc));
+
+ if (ptr == 0) { /* We've reached the bottom of a stack segment. */
+ pms = pms->prev;
+ if (pms == 0)
+ break; /* all done */
+ stop = pms->entries + pms->count - 1;
+ sp = stop;
+ continue;
+ }
+ debug_check_object(ptr - 1, NULL, NULL);
+ ts:if_debug4('7', " [7]%smarking %s 0x%lx[%u]",
+ depth_dots(sp, pms),
+ struct_type_name_string(ptr[-1].o_type),
+ (ulong) ptr, sp->index);
+ mproc = ptr[-1].o_type->enum_ptrs;
+ /* The cast in the following statement is the one */
+ /* place we need to break 'const' to make the */
+ /* template for pointer enumeration work. */
+ if (mproc == gs_no_struct_enum_ptrs ||
+ (ptp = (*mproc)
+ (ptr, pre_obj_contents_size(ptr - 1),
+ sp->index, (const void **)&nptr,
+ ptr[-1].o_type, pstate)) == 0
+ ) {
+ if_debug0('7', " - done\n");
+ sp--;
+ continue;
+ }
+ sp->index++;
+ if_debug1('7', " = 0x%lx\n", (ulong) nptr);
+ /* Descend into nptr, whose pointer type is ptp. */
+ if (ptp == ptr_struct_type) {
+ sp[1].index = 0;
+ sp[1].is_refs = false;
+ if (sp == stop)
+ goto push;
+ if (!ptr_struct_mark(nptr, pstate))
+ goto ts;
+ new |= 1;
+ (++sp)->ptr = nptr;
+ goto do_struct;
+ } else if (ptp == ptr_ref_type) {
+ sp[1].index = 1;
+ sp[1].is_refs = true;
+ if (sp == stop)
+ goto push;
+ new |= 1;
+ (++sp)->ptr = nptr;
+ goto do_refs;
+ } else { /* We assume this is some non-pointer- */
+ /* containing type. */
+ if ((*ptp->mark) (nptr, pstate))
+ new |= 1;
+ goto ts;
+ }
+ }
+
+ /* ---------------- Refs ---------------- */
+
+ do_refs:
+ {
+ ref_packed *pptr = sp->ptr;
+ ref *rptr;
+
+ tr:if (!sp->index) {
+ --sp;
+ continue;
+ }
+ --(sp->index);
+ if_debug3('8', " [8]%smarking refs 0x%lx[%u]\n",
+ depth_dots(sp, pms), (ulong) pptr, sp->index);
+ if (r_is_packed((ref *) pptr)) {
+ if (!r_has_pmark(pptr)) {
+ r_set_pmark(pptr);
+ new |= 1;
+ if (r_packed_is_name(pptr)) {
+ name_index_t nidx = packed_name_index(pptr);
+ name *pname = names_index_ptr(nt, nidx);
+
+ mark_name(nidx, pname);
+ }
+ }
+ ++pptr;
+ goto tr;
+ }
+ if (r_has_attr((ref *) pptr, l_mark)) {
+ pptr = (ref_packed *) ((ref *) pptr + 1);
+ goto tr;
+ }
+ rptr = (ref *) pptr; /* * const beyond here */
+ r_set_attrs(rptr, l_mark);
+ new |= 1;
+ if (r_space(rptr) < min_trace) { /* Note that this always picks up all scalars. */
+ pptr = (ref_packed *) (rptr + 1);
+ goto tr;
+ }
+ sp->ptr = rptr + 1;
+ switch (r_type(rptr)) {
+ /* Struct cases */
+ case t_file:
+ nptr = rptr->value.pfile;
+ rs:sp[1].is_refs = false;
+ sp[1].index = 0;
+ if (sp == stop) {
+ ptp = ptr_struct_type;
+ break;
+ }
+ if (!ptr_struct_mark(nptr, pstate))
+ goto nr;
+ new |= 1;
+ (++sp)->ptr = nptr;
+ goto do_struct;
+ case t_device:
+ nptr = rptr->value.pdevice;
+ goto rs;
+ case t_fontID:
+ case t_struct:
+ case t_astruct:
+ nptr = rptr->value.pstruct;
+ goto rs;
+ /* Non-trivial non-struct cases */
+ case t_dictionary:
+ nptr = rptr->value.pdict;
+ sp[1].index = sizeof(dict) / sizeof(ref);
+ goto rrp;
+ case t_array:
+ nptr = rptr->value.refs;
+ rr:if ((sp[1].index = r_size(rptr)) == 0) { /* Set the base pointer to 0, */
+ /* so we never try to relocate it. */
+ rptr->value.refs = 0;
+ goto nr;
+ }
+ rrp:
+ rrc:sp[1].is_refs = true;
+ if (sp == stop)
+ break;
+ new |= 1;
+ (++sp)->ptr = nptr;
+ goto do_refs;
+ case t_mixedarray:
+ case t_shortarray:
+ nptr = (void *)rptr->value.packed; /* discard const */
+ goto rr;
+ case t_name:
+ mark_name(names_index(nt, rptr), rptr->value.pname);
+ nr:pptr = (ref_packed *) (rptr + 1);
+ goto tr;
+ case t_string:
+ if (gc_string_mark(rptr->value.bytes, r_size(rptr), true, pstate))
+ new |= 1;
+ goto nr;
+ case t_oparray:
+ nptr = (void *)rptr->value.const_refs; /* discard const */
+ sp[1].index = 1;
+ goto rrc;
+ default:
+ goto nr;
+ }
+ }
+
+ /* ---------------- Recursion ---------------- */
+
+ push:
+ if (sp == stop) { /* The current segment is full. */
+ int new_added = gc_extend_stack(pms, pstate);
+
+ if (new_added) {
+ new |= new_added;
+ continue;
+ }
+ pms = pms->next;
+ stop = pms->entries + pms->count - 1;
+ pms->entries[1] = sp[1];
+ sp = pms->entries;
+ }
+ /* index and is_refs are already set */
+ if (!sp[1].is_refs) {
+ if (!(*ptp->mark) (nptr, pstate))
+ continue;
+ new |= 1;
+ }
+ (++sp)->ptr = nptr;
+ }
+ return new;
+}
+/* Link to, attempting to allocate if necessary, */
+/* another chunk of mark stack. */
+private int
+gc_extend_stack(gc_mark_stack * pms, gc_state_t * pstate)
+{
+ if (pms->next == 0) { /* Try to allocate another segment. */
+ uint count;
+
+ for (count = ms_size_desired; count >= ms_size_min; count >>= 1) {
+ pms->next = (gc_mark_stack *)
+ gs_alloc_bytes_immovable(pstate->heap,
+ sizeof(gc_mark_stack) +
+ sizeof(ms_entry) * count,
+ "gc mark stack");
+ if (pms->next != 0)
+ break;
+ }
+ if (pms->next == 0) { /* The mark stack overflowed. */
+ ms_entry *sp = pms->entries + pms->count - 1;
+ byte *cptr = sp->ptr; /* container */
+ chunk_t *cp = gc_locate(cptr, pstate);
+ int new = 1;
+
+ if (cp == 0) { /* We were tracing outside collectible */
+ /* storage. This can't happen. */
+ lprintf1("mark stack overflowed while outside collectible space at 0x%lx!\n",
+ (ulong) cptr);
+ gs_abort();
+ }
+ if (cptr < cp->rescan_bot)
+ cp->rescan_bot = cptr, new = -1;
+ if (cptr > cp->rescan_top)
+ cp->rescan_top = cptr, new = -1;
+ return new;
+ }
+ gc_init_mark_stack(pms->next, count);
+ pms->next->prev = pms;
+ pms->next->on_heap = true;
+ }
+ return 0;
+}
+
+/* Mark a struct. Return true if new mark. */
+private bool
+ptr_struct_mark(void *vptr, gc_state_t * ignored)
+{
+ obj_header_t *ptr = vptr;
+
+ if (vptr == 0)
+ return false;
+ ptr--; /* point to header */
+ if (!o_is_unmarked(ptr))
+ return false;
+ o_mark(ptr);
+ return true;
+}
+
+/* Mark a string. Return true if new mark. */
+private bool
+ptr_string_mark(void *vptr, gc_state_t * gcst)
+{
+ return gc_string_mark(((gs_string *) vptr)->data,
+ ((gs_string *) vptr)->size,
+ true, gcst);
+}
+
+/* Finish tracing by marking names. */
+private bool
+gc_trace_finish(gc_state_t * pstate)
+{
+ name_table *nt = pstate->ntable;
+ name_index_t nidx = 0;
+ bool marked = false;
+
+ while ((nidx = names_next_valid_index(nt, nidx)) != 0) {
+ name *pname = names_index_ptr(nt, nidx);
+
+ if (pname->mark) {
+ if (!pname->foreign_string &&
+ gc_string_mark(pname->string_bytes, pname->string_size,
+ true, pstate)
+ )
+ marked = true;
+ marked |=
+ ptr_struct_mark(names_index_ptr_sub_table(nt, nidx, pname),
+ pstate);
+ }
+ }
+ return marked;
+}
+
+/* ------ Relocation planning phase ------ */
+
+/* Initialize the relocation information in the chunk header. */
+private void
+gc_init_reloc(chunk_t * cp)
+{
+ chunk_head_t *chead = cp->chead;
+
+ chead->dest = cp->cbase;
+ chead->free.o_back =
+ offset_of(chunk_head_t, free) >> obj_back_shift;
+ chead->free.o_size = sizeof(obj_header_t);
+ chead->free.o_nreloc = 0;
+}
+
+/* Set marks and clear relocation for chunks that won't be compacted. */
+private void
+gc_clear_reloc(chunk_t * cp)
+{
+ byte *pfree = (byte *) & cp->chead->free;
+
+ gc_init_reloc(cp);
+ SCAN_CHUNK_OBJECTS(cp)
+ DO_ALL
+ const struct_shared_procs_t *procs =
+ pre->o_type->shared;
+
+ if (procs != 0)
+ (*procs->clear_reloc) (pre, size);
+ o_set_untraced(pre);
+ if (!pre->o_large)
+ pre->o_back = ((byte *) pre - pfree) >> obj_back_shift;
+ END_OBJECTS_SCAN
+ gc_strings_set_marks(cp, true);
+ gc_strings_clear_reloc(cp);
+}
+
+/* Set the relocation for the objects in a chunk. */
+/* This will never be called for a chunk with any o_untraced objects. */
+private void
+gc_objects_set_reloc(chunk_t * cp)
+{
+ uint reloc = 0;
+ chunk_head_t *chead = cp->chead;
+ byte *pfree = (byte *) & chead->free; /* most recent free object */
+
+ if_debug_chunk('6', "[6]setting reloc for chunk", cp);
+ gc_init_reloc(cp);
+ SCAN_CHUNK_OBJECTS(cp)
+ DO_ALL
+ struct_proc_finalize((*finalize));
+ const struct_shared_procs_t *procs =
+ pre->o_type->shared;
+
+ if ((procs == 0 ? o_is_unmarked(pre) :
+ !(*procs->set_reloc) (pre, reloc, size))
+ ) { /* Free object */
+ reloc += sizeof(obj_header_t) + obj_align_round(size);
+ if ((finalize = pre->o_type->finalize) != 0) {
+ if_debug2('u', "[u]GC finalizing %s 0x%lx\n",
+ struct_type_name_string(pre->o_type),
+ (ulong) (pre + 1));
+ (*finalize) (pre + 1);
+ }
+ if (pre->o_large) { /* We should chop this up into small */
+ /* free blocks, but there's no value */
+ /* in doing this right now. */
+ o_set_unmarked_large(pre);
+ } else {
+ pfree = (byte *) pre;
+ pre->o_back =
+ (pfree - (byte *) chead) >> obj_back_shift;
+ pre->o_nreloc = reloc;
+ }
+ if_debug3('7', " [7]at 0x%lx, unmarked %lu, new reloc = %u\n",
+ (ulong) pre, (ulong) size, reloc);
+ } else { /* Useful object */
+ debug_check_object(pre, cp, NULL);
+ if (pre->o_large) {
+ if (o_is_unmarked_large(pre))
+ o_mark_large(pre);
+ } else
+ pre->o_back =
+ ((byte *) pre - pfree) >> obj_back_shift;
+ }
+ END_OBJECTS_SCAN
+#ifdef DEBUG
+ if (reloc != 0) {
+ if_debug1('6', "[6]freed %u", reloc);
+ if_debug_chunk('6', " in", cp);
+ }
+#endif
+}
+
+/* ------ Relocation phase ------ */
+
+/* Relocate the pointers in all the objects in a chunk. */
+private void
+gc_do_reloc(chunk_t * cp, gs_ref_memory_t * mem, gc_state_t * pstate)
+{
+ chunk_head_t *chead = cp->chead;
+
+ if_debug_chunk('6', "[6]relocating in chunk", cp);
+ SCAN_CHUNK_OBJECTS(cp)
+ DO_ALL
+ /* We need to relocate the pointers in an object iff */
+ /* it is o_untraced, or it is a useful object. */
+ /* An object is free iff its back pointer points to */
+ /* the chunk_head structure. */
+ if (o_is_untraced(pre) ||
+ (pre->o_large ? !o_is_unmarked(pre) :
+ pre->o_back << obj_back_shift !=
+ (byte *) pre - (byte *) chead)
+ ) {
+ struct_proc_reloc_ptrs((*proc)) =
+ pre->o_type->reloc_ptrs;
+
+ if_debug3('7',
+ " [7]relocating ptrs in %s(%lu) 0x%lx\n",
+ struct_type_name_string(pre->o_type),
+ (ulong) size, (ulong) pre);
+ if (proc != 0)
+ (*proc) (pre + 1, size, pre->o_type, pstate);
+ }
+ END_OBJECTS_SCAN
+}
+
+/* Print pointer relocation if debugging. */
+/* We have to provide this procedure even if DEBUG is not defined, */
+/* in case one of the other GC modules was compiled with DEBUG. */
+void *
+print_reloc_proc(const void *obj, const char *cname, void *robj)
+{
+ if_debug3('9', " [9]relocate %s * 0x%lx to 0x%lx\n",
+ cname, (ulong) obj, (ulong) robj);
+ return robj;
+}
+
+/* Relocate a pointer to an (aligned) object. */
+/* See gsmemory.h for why the argument is const and the result is not. */
+private void /*obj_header_t */ *
+igc_reloc_struct_ptr(const void /*obj_header_t */ *obj, gc_state_t * gcst)
+{
+ const obj_header_t *const optr = (const obj_header_t *)obj;
+ const void *robj;
+
+ if (obj == 0)
+ return print_reloc(obj, "NULL", 0);
+ debug_check_object(optr - 1, NULL, gcst);
+ /* The following should be a conditional expression, */
+ /* but Sun's cc compiler can't handle it. */
+ if (optr[-1].o_large)
+ robj = obj;
+ else {
+ uint back = optr[-1].o_back;
+
+ if (back == o_untraced)
+ robj = obj;
+ else {
+#ifdef DEBUG
+ /* Do some sanity checking. */
+ if (back > gcst->space_local->chunk_size >> obj_back_shift) {
+ lprintf2("Invalid back pointer %u at 0x%lx!\n",
+ back, (ulong) obj);
+ gs_abort();
+ }
+#endif
+ {
+ const obj_header_t *pfree = (const obj_header_t *)
+ ((const char *)(optr - 1) -
+ (back << obj_back_shift));
+ const chunk_head_t *chead = (const chunk_head_t *)
+ ((const char *)pfree -
+ (pfree->o_back << obj_back_shift));
+
+ robj = chead->dest +
+ ((const char *)obj - (const char *)(chead + 1) -
+ pfree->o_nreloc);
+ }
+ }
+ }
+ return print_reloc(obj,
+ struct_type_name_string(optr[-1].o_type),
+ (void *)robj); /* discard const */
+}
+
+/* ------ Compaction phase ------ */
+
+/* Compact the objects in a chunk. */
+/* This will never be called for a chunk with any o_untraced objects. */
+private void
+gc_objects_compact(chunk_t * cp, gc_state_t * gcst)
+{
+ chunk_head_t *chead = cp->chead;
+ obj_header_t *dpre = (obj_header_t *) chead->dest;
+
+ SCAN_CHUNK_OBJECTS(cp)
+ DO_ALL
+ /* An object is free iff its back pointer points to */
+ /* the chunk_head structure. */
+ if ((pre->o_large ? !o_is_unmarked(pre) :
+ pre->o_back << obj_back_shift !=
+ (byte *) pre - (byte *) chead)
+ ) {
+ const struct_shared_procs_t *procs =
+ pre->o_type->shared;
+
+ debug_check_object(pre, cp, gcst);
+ if_debug4('7',
+ " [7]compacting %s 0x%lx(%lu) to 0x%lx\n",
+ struct_type_name_string(pre->o_type),
+ (ulong) pre, (ulong) size, (ulong) dpre);
+ if (procs == 0) {
+ if (dpre != pre)
+ memmove(dpre, pre,
+ sizeof(obj_header_t) + size);
+ } else
+ (*procs->compact) (pre, dpre, size);
+ dpre = (obj_header_t *)
+ ((byte *) dpre + obj_size_round(size));
+ }
+ END_OBJECTS_SCAN
+ if (cp->outer == 0 && chead->dest != cp->cbase)
+ dpre = (obj_header_t *) cp->cbase; /* compacted this chunk into another */
+ gs_alloc_fill(dpre, gs_alloc_fill_collected, cp->cbot - (byte *) dpre);
+ cp->cbot = (byte *) dpre;
+ cp->rcur = 0;
+ cp->rtop = 0; /* just to be sure */
+}
+
+/* ------ Cleanup ------ */
+
+/* Free empty chunks. */
+private void
+gc_free_empty_chunks(gs_ref_memory_t * mem)
+{
+ chunk_t *cp;
+ chunk_t *csucc;
+
+ /* Free the chunks in reverse order, */
+ /* to encourage LIFO behavior. */
+ for (cp = mem->clast; cp != 0; cp = csucc) { /* Make sure this isn't an inner chunk, */
+ /* or a chunk that has inner chunks. */
+ csucc = cp->cprev; /* save before freeing */
+ if (cp->cbot == cp->cbase && cp->ctop == cp->climit &&
+ cp->outer == 0 && cp->inner_count == 0
+ ) {
+ alloc_free_chunk(cp, mem);
+ if (mem->pcc == cp)
+ mem->pcc = 0;
+ }
+ }
+}
diff --git a/pstoraster/igc.h b/pstoraster/igc.h
new file mode 100644
index 000000000..876edc8f9
--- /dev/null
+++ b/pstoraster/igc.h
@@ -0,0 +1,102 @@
+/* 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$ */
+/* Internal interfaces in Ghostscript GC */
+
+#ifndef igc_INCLUDED
+# define igc_INCLUDED
+
+#include "istruct.h"
+
+/* Define the procedures shared among a "genus" of structures. */
+/* Currently there are only two genera: refs, and all other structures. */
+struct struct_shared_procs_s {
+
+ /* Clear the relocation information in an object. */
+
+#define gc_proc_clear_reloc(proc)\
+ void proc(P2(obj_header_t *pre, uint size))
+ gc_proc_clear_reloc((*clear_reloc));
+
+ /* Compute any internal relocation for a marked object. */
+ /* Return true if the object should be kept. */
+ /* The reloc argument shouldn't be required, */
+ /* but we need it for ref objects. */
+
+#define gc_proc_set_reloc(proc)\
+ bool proc(P3(obj_header_t *pre, uint reloc, uint size))
+ gc_proc_set_reloc((*set_reloc));
+
+ /* Compact an object. */
+
+#define gc_proc_compact(proc)\
+ void proc(P3(obj_header_t *pre, obj_header_t *dpre, uint size))
+ gc_proc_compact((*compact));
+
+};
+
+/* Define the structure for holding GC state. */
+ /*typedef struct gc_state_s gc_state_t; *//* in gsstruct.h */
+#ifndef name_table_DEFINED
+# define name_table_DEFINED
+typedef struct name_table_s name_table;
+
+#endif
+struct gc_state_s {
+ const gc_procs_with_refs_t *procs; /* must be first */
+ chunk_locator_t loc;
+ vm_spaces spaces;
+ int min_collect; /* avm_space */
+ bool relocating_untraced; /* if true, we're relocating */
+ /* pointers from untraced spaces */
+ gs_raw_memory_t *heap; /* for extending mark stack */
+ name_table *ntable; /* (implicitly referenced by names) */
+};
+
+/* Exported by igcref.c for igc.c */
+void ptr_ref_unmark(P2(void *, gc_state_t *));
+bool ptr_ref_mark(P2(void *, gc_state_t *));
+
+/*ref_packed *gs_reloc_ref_ptr(P2(const ref_packed *, gc_state_t *)); */
+
+/* Exported by ilocate.c for igc.c */
+void ialloc_validate_memory(P2(const gs_ref_memory_t *, gc_state_t *));
+void ialloc_validate_chunk(P2(const chunk_t *, gc_state_t *));
+void ialloc_validate_object(P3(const obj_header_t *, const chunk_t *,
+ gc_state_t *));
+
+/* Macro for returning a relocated pointer */
+#ifdef DEBUG
+void *print_reloc_proc(P3(const void *obj, const char *cname, void *robj));
+
+# define print_reloc(obj, cname, nobj)\
+ (gs_debug_c('9') ? print_reloc_proc(obj, cname, nobj) :\
+ (void *)(nobj))
+#else
+# define print_reloc(obj, cname, nobj)\
+ (void *)(nobj)
+#endif
+
+#endif /* igc_INCLUDED */
diff --git a/pstoraster/igcref.c b/pstoraster/igcref.c
new file mode 100644
index 000000000..ed98849fc
--- /dev/null
+++ b/pstoraster/igcref.c
@@ -0,0 +1,681 @@
+/* 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$ */
+/* ref garbage collector for Ghostscript */
+#include "memory_.h"
+#include "ghost.h"
+#include "gsexit.h"
+#include "gsstruct.h" /* for gxalloc.h included by iastate.h */
+#include "iname.h"
+#include "iastate.h"
+#include "idebug.h"
+#include "igc.h"
+#include "ipacked.h"
+#include "store.h" /* for ref_assign_inline */
+
+/* Define whether to trace every step of relocating ref pointers. */
+#if 0
+# define rputc(c) dputc(c)
+#else
+# define rputc(c) DO_NOTHING
+#endif
+
+/* Forward references */
+ptr_proc_reloc(igc_reloc_ref_ptr, ref_packed);
+refs_proc_reloc(igc_reloc_refs);
+
+/*
+ * Define the 'structure' type descriptor for refs.
+ * This is special because it has different shared procs.
+ */
+private gc_proc_clear_reloc(refs_clear_reloc);
+private gc_proc_set_reloc(refs_set_reloc);
+private gc_proc_compact(refs_compact);
+private const struct_shared_procs_t refs_shared_procs =
+{refs_clear_reloc, refs_set_reloc, refs_compact};
+private struct_proc_clear_marks(refs_clear_marks);
+private struct_proc_reloc_ptrs(refs_do_reloc);
+const gs_memory_struct_type_t st_refs =
+{sizeof(ref), "refs", &refs_shared_procs, refs_clear_marks, 0, refs_do_reloc};
+
+/*
+ * Define the GC procedures for structs that actually contain refs.
+ * These are special because the shared refs_* procedures
+ * are never called. Instead, we unmark the individual refs in clear_marks,
+ * disregard refs_*_reloc (because we will never relocate a ptr_ref_type
+ * pointer pointing into the structure), disregard refs_compact (because
+ * compaction is never required), and remove the marks in reloc_ptrs.
+ * See also the comment about ptr_ref_type in imemory.h.
+ */
+CLEAR_MARKS_PROC(ref_struct_clear_marks)
+{
+ ref *pref = (ref *) vptr;
+ ref *end = (ref *) ((char *)vptr + size);
+
+ for (; pref < end; pref++)
+ r_clear_attrs(pref, l_mark);
+}
+ENUM_PTRS_BEGIN_PROC(ref_struct_enum_ptrs)
+{
+ if (index >= size / sizeof(ref))
+ return 0;
+ *pep = (ref *) vptr + index;
+ return ptr_ref_type;
+ ENUM_PTRS_END_PROC
+}
+RELOC_PTRS_BEGIN(ref_struct_reloc_ptrs)
+{
+ ref *beg = vptr;
+ ref *end = (ref *) ((char *)vptr + size);
+
+ igc_reloc_refs((ref_packed *) beg, (ref_packed *) end, gcst);
+ ref_struct_clear_marks(vptr, size, pstype);
+} RELOC_PTRS_END
+
+/* ------ Unmarking phase ------ */
+
+/* Unmark a single ref. */
+void
+ptr_ref_unmark(void *vptr, gc_state_t * ignored)
+{
+ if (r_is_packed((ref *) vptr))
+ r_clear_pmark((ref_packed *) vptr);
+ else
+ r_clear_attrs((ref *) vptr, l_mark);
+}
+
+/* Unmarking routine for ref objects. */
+private void
+refs_clear_marks(void /*obj_header_t */ *vptr, uint size,
+ const gs_memory_struct_type_t * pstype)
+{
+ ref_packed *rp = (ref_packed *) vptr;
+ ref_packed *end = (ref_packed *) ((byte *) vptr + size);
+
+ /* Since the last ref is full-size, we only need to check for */
+ /* the end of the block when we see one of those. */
+ for (;;) {
+ if (r_is_packed(rp)) {
+#ifdef DEBUG
+ if (gs_debug_c('8')) {
+ dlprintf1(" [8]unmark packed 0x%lx ", (ulong) rp);
+ debug_print_ref((const ref *)rp);
+ dputs("\n");
+ }
+#endif
+ r_clear_pmark(rp);
+ rp++;
+ } else { /* full-size ref */
+#ifdef DEBUG
+ if (gs_debug_c('8')) {
+ dlprintf1(" [8]unmark ref 0x%lx ", (ulong) rp);
+ debug_print_ref((ref *) rp);
+ dputs("\n");
+ }
+#endif
+ r_clear_attrs((ref *) rp, l_mark);
+ rp += packed_per_ref;
+ if (rp >= (ref_packed *) end)
+ break;
+ }
+ }
+}
+
+/* ------ Marking phase ------ */
+
+/* Mark a ref. Return true if new mark. */
+bool
+ptr_ref_mark(void *vptr, gc_state_t * ignored)
+{
+ if (r_is_packed(vptr)) {
+ if (r_has_pmark((ref_packed *) vptr))
+ return false;
+ r_set_pmark((ref_packed *) vptr);
+ } else {
+ if (r_has_attr((ref *) vptr, l_mark))
+ return false;
+ r_set_attrs((ref *) vptr, l_mark);
+ }
+ return true;
+}
+
+/* ------ Relocation planning phase ------ */
+
+/*
+ * We store relocation in the size field of refs that don't use it,
+ * so that we don't have to scan all the way to an unmarked object.
+ * We must avoid nulls, which sometimes have useful information
+ * in their size fields, and the types above t_next_index, which are
+ * actually operators in disguise and also use the size field.
+ */
+
+/* Clear the relocation for a ref object. */
+private void
+refs_clear_reloc(obj_header_t * hdr, uint size)
+{
+ register ref_packed *rp = (ref_packed *) (hdr + 1);
+ ref_packed *end = (ref_packed *) ((byte *) rp + size);
+
+ while (rp < end) {
+ if (r_is_packed(rp))
+ rp++;
+ else { /* full-size ref *//* Store the relocation here if possible. */
+ if (!ref_type_uses_size_or_null(r_type((ref *) rp))) {
+ if_debug1('8',
+ " [8]clearing reloc at 0x%lx\n",
+ (ulong) rp);
+ r_set_size((ref *) rp, 0);
+ }
+ rp += packed_per_ref;
+ }
+ }
+}
+
+/* Set the relocation for a ref object. */
+private bool
+refs_set_reloc(obj_header_t * hdr, uint reloc, uint size)
+{
+ ref_packed *rp = (ref_packed *) (hdr + 1);
+ ref_packed *end = (ref_packed *) ((byte *) rp + size);
+ uint freed = 0;
+
+ /*
+ * We have to be careful to keep refs aligned properly.
+ * For the moment, we do this by either keeping or discarding
+ * an entire (aligned) block of align_packed_per_ref packed elements
+ * as a unit. We know that align_packed_per_ref <= packed_per_ref,
+ * and we also know that packed refs are always allocated in blocks
+ * of align_packed_per_ref, so this makes things relatively easy.
+ */
+ while (rp < end) {
+ if (r_is_packed(rp)) {
+#if align_packed_per_ref == 1
+ if (r_has_pmark(rp)) {
+ if_debug1('8',
+ " [8]packed ref 0x%lx is marked\n",
+ (ulong) rp);
+ rp++;
+ } else {
+#else
+ int i;
+
+ /*
+ * Note: align_packed_per_ref is typically
+ * 2 or 4 for 32-bit processors.
+ */
+#define all_marked (align_packed_per_ref * lp_mark)
+# if align_packed_per_ref == 2
+# if arch_sizeof_long == arch_sizeof_short * 2
+# undef all_marked
+# define all_marked ( ((long)lp_mark << (sizeof(short) * 8)) + lp_mark )
+# define marked (*(long *)rp & all_marked)
+# else
+# define marked ((*rp & lp_mark) + (rp[1] & lp_mark))
+# endif
+# else
+# if align_packed_per_ref == 4
+# define marked ((*rp & lp_mark) + (rp[1] & lp_mark) +\
+ (rp[2] & lp_mark) + (rp[3] & lp_mark))
+# else
+ uint marked = *rp & lp_mark;
+
+ for (i = 1; i < align_packed_per_ref; i++)
+ marked += rp[i] & lp_mark;
+# endif
+# endif
+ /*
+ * Now marked is lp_mark * the number of marked
+ * packed refs in the aligned block, except for
+ * a couple of special cases above.
+ */
+ switch (marked) {
+ case all_marked:
+ if_debug2('8',
+ " [8]packed refs 0x%lx..0x%lx are marked\n",
+ (ulong) rp,
+ (ulong) (rp + (align_packed_per_ref - 1)));
+ rp += align_packed_per_ref;
+ break;
+ default:
+ /* At least one packed ref in the block */
+ /* is marked: Keep the whole block. */
+ for (i = align_packed_per_ref; i--; rp++) {
+ r_set_pmark(rp);
+ if_debug1('8',
+ " [8]packed ref 0x%lx is marked\n",
+ (ulong) rp);
+ }
+ break;
+ case 0:
+#endif
+ if_debug2('8', " [8]%d packed ref(s) at 0x%lx are unmarked\n",
+ align_packed_per_ref, (ulong) rp);
+ {
+ uint rel = reloc + freed;
+
+ /* Change this to an integer so we can */
+ /* store the relocation here. */
+ *rp = pt_tag(pt_integer) +
+ min(rel, packed_max_value);
+ }
+ rp += align_packed_per_ref;
+ freed += sizeof(ref_packed) * align_packed_per_ref;
+ }
+ } else { /* full-size ref */
+ uint rel = reloc + freed;
+
+ /* The following assignment is logically */
+ /* unnecessary; we do it only for convenience */
+ /* in debugging. */
+ ref *pref = (ref *) rp;
+
+ if (!r_has_attr(pref, l_mark)) {
+ if_debug1('8', " [8]ref 0x%lx is unmarked\n",
+ (ulong) pref);
+ /* Change this to a mark so we can */
+ /* store the relocation. */
+ r_set_type(pref, t_mark);
+ r_set_size(pref, rel);
+ freed += sizeof(ref);
+ } else {
+ if_debug1('8', " [8]ref 0x%lx is marked\n",
+ (ulong) pref);
+ /* Store the relocation here if possible. */
+ if (!ref_type_uses_size_or_null(r_type(pref))) {
+ if_debug2('8', " [8]storing reloc %u at 0x%lx\n",
+ rel, (ulong) pref);
+ r_set_size(pref, rel);
+ }
+ }
+ rp += packed_per_ref;
+ }
+ }
+ if_debug3('7', " [7]at end of refs 0x%lx, size = %u, freed = %u\n",
+ (ulong) (hdr + 1), size, freed);
+ if (freed == size)
+ return false;
+#if arch_sizeof_int > arch_sizeof_short
+ /*
+ * If the final relocation can't fit in the r_size field
+ * (which can't happen if the object shares a chunk with
+ * any other objects, so we know reloc = 0 in this case),
+ * we have to keep the entire object unless there are no
+ * references to any ref in it.
+ */
+ if (freed <= max_ushort)
+ return true;
+ /*
+ * We have to mark all surviving refs, but we also must
+ * overwrite any non-surviving refs with something that
+ * doesn't contain any pointers.
+ */
+ rp = (ref_packed *) (hdr + 1);
+ while (rp < end) {
+ if (r_is_packed(rp)) {
+ if (!r_has_pmark(rp))
+ *rp = pt_tag(pt_integer) | lp_mark;
+ ++rp;
+ } else { /* The following assignment is logically */
+ /* unnecessary; we do it only for convenience */
+ /* in debugging. */
+ ref *pref = (ref *) rp;
+
+ if (!r_has_attr(pref, l_mark)) {
+ r_set_type_attrs(pref, t_mark, l_mark);
+ r_set_size(pref, reloc);
+ } else {
+ if (!ref_type_uses_size_or_null(r_type(pref)))
+ r_set_size(pref, reloc);
+ }
+ rp += packed_per_ref;
+ }
+ }
+ /* The last ref has to remain unmarked. */
+ r_clear_attrs((ref *) rp - 1, l_mark);
+#endif
+ return true;
+}
+
+/* ------ Relocation phase ------ */
+
+/* Relocate all the pointers in a block of refs. */
+private void
+refs_do_reloc(void /*obj_header_t */ *vptr, uint size,
+ const gs_memory_struct_type_t * pstype, gc_state_t * gcst)
+{
+ igc_reloc_refs((ref_packed *) vptr,
+ (ref_packed *) ((char *)vptr + size),
+ gcst);
+}
+/* Relocate the contents of a block of refs. */
+/* If gcst->relocating_untraced is true, we are relocating pointers from an */
+/* untraced space, so relocate all refs, not just marked ones. */
+void
+igc_reloc_refs(ref_packed * from, ref_packed * to, gc_state_t * gcst)
+{
+ int min_trace = gcst->min_collect;
+ ref_packed *rp = from;
+ bool do_all = gcst->relocating_untraced;
+
+ while (rp < to) {
+ ref *pref;
+
+ if (r_is_packed(rp)) {
+ rp++;
+ continue;
+ }
+ /* The following assignment is logically unnecessary; */
+ /* we do it only for convenience in debugging. */
+ pref = (ref *) rp;
+ if_debug3('8', " [8]relocating %s %d ref at 0x%lx\n",
+ (r_has_attr(pref, l_mark) ? "marked" : "unmarked"),
+ r_btype(pref), (ulong) pref);
+ if ((r_has_attr(pref, l_mark) || do_all) &&
+ r_space(pref) >= min_trace
+ )
+ switch (r_type(pref)) {
+ /* Struct cases */
+ case t_file:
+ RELOC_VAR(pref->value.pfile);
+ break;
+ case t_device:
+ RELOC_VAR(pref->value.pdevice);
+ break;
+ case t_fontID:
+ case t_struct:
+ case t_astruct:
+ RELOC_VAR(pref->value.pstruct);
+ break;
+ /* Non-trivial non-struct cases */
+ case t_dictionary:
+ rputc('d');
+ pref->value.pdict =
+ (dict *) igc_reloc_ref_ptr((ref_packed *) pref->value.pdict, gcst);
+ break;
+ case t_array:
+ {
+ uint size = r_size(pref);
+
+ if (size != 0) { /* value.refs might be NULL *//*
+ * If the array is large, we allocated it in its
+ * own object (at least originally -- this might
+ * be a pointer to a subarray.) In this case,
+ * we know it is the only object in its
+ * containing st_refs object, so we know that
+ * the mark containing the relocation appears
+ * just after it.
+ */
+ if (size < max_size_st_refs / sizeof(ref)) {
+ rputc('a');
+ pref->value.refs =
+ (ref *) igc_reloc_ref_ptr(
+ (ref_packed *) pref->value.refs, gcst);
+ } else {
+ rputc('A');
+ /*
+ * See the t_shortarray case below for why we
+ * decrement size.
+ */
+ --size;
+ pref->value.refs =
+ (ref *) igc_reloc_ref_ptr(
+ (ref_packed *) (pref->value.refs + size),
+ gcst) - size;
+ }
+ }
+ }
+ break;
+ case t_mixedarray:
+ if (r_size(pref) != 0) { /* value.refs might be NULL */
+ rputc('m');
+ pref->value.packed =
+ igc_reloc_ref_ptr(pref->value.packed, gcst);
+ }
+ break;
+ case t_shortarray:
+ {
+ uint size = r_size(pref);
+
+ /*
+ * Since we know that igc_reloc_ref_ptr works by
+ * scanning forward, and we know that all the
+ * elements of this array itself are marked, we can
+ * save some scanning time by relocating the pointer
+ * to the end of the array rather than the
+ * beginning.
+ */
+ if (size != 0) { /* value.refs might be NULL */
+ rputc('s');
+ /*
+ * igc_reloc_ref_ptr has to be able to determine
+ * whether the pointer points into a space that
+ * isn't being collected. It does this by
+ * checking whether the referent of the pointer
+ * is marked. For this reason, we have to pass
+ * a pointer to the last real element of the
+ * array, rather than just beyond it.
+ */
+ --size;
+ pref->value.packed =
+ igc_reloc_ref_ptr(pref->value.packed + size,
+ gcst) - size;
+ }
+ }
+ break;
+ case t_name:
+ {
+ void *psub = name_ref_sub_table(pref);
+ void *rsub = RELOC_OBJ(psub); /* gcst implicit */
+
+ pref->value.pname = (name *)
+ ((char *)rsub + ((char *)pref->value.pname - (char *)psub));
+ } break;
+ case t_string:
+ {
+ gs_string str;
+
+ str.data = pref->value.bytes;
+ str.size = r_size(pref);
+
+ RELOC_STRING_VAR(str);
+ pref->value.bytes = str.data;
+ }
+ break;
+ case t_oparray:
+ rputc('o');
+ pref->value.const_refs =
+ (const ref *)igc_reloc_ref_ptr((const ref_packed *)pref->value.const_refs, gcst);
+ break;
+ }
+ rp += packed_per_ref;
+ }
+}
+
+/* Relocate a pointer to a ref. */
+/* See gsmemory.h for why the argument is const and the result is not. */
+ref_packed *
+igc_reloc_ref_ptr(const ref_packed * prp, gc_state_t * ignored)
+{ /*
+ * Search forward for relocation. This algorithm is intrinsically
+ * very inefficient; we hope eventually to replace it with a better
+ * one.
+ */
+ register const ref_packed *rp = prp;
+ uint dec = 0;
+
+ /*
+ * Iff this pointer points into a space that wasn't traced,
+ * the referent won't be marked. In this case, we shouldn't
+ * do any relocation. Check for this first.
+ */
+ if (r_is_packed(rp)) {
+ if (!r_has_pmark(rp))
+ return (ref_packed *) rp;
+ } else {
+ if (!r_has_attr((const ref *)rp, l_mark))
+ return (ref_packed *) rp;
+ }
+ for (;;) {
+ if (r_is_packed(rp)) { /*
+ * Normally, an unmarked packed ref will be an
+ * integer whose value is the amount of relocation.
+ * However, the relocation value might have been
+ * too large to fit. If this is the case, for
+ * each such unmarked packed ref we pass over,
+ * we have to decrement the final relocation.
+ */
+ rputc((*PACKED(rp) & lp_mark ? '1' : '0'));
+ if (!(*PACKED(rp) & lp_mark)) {
+ if (*PACKED(rp) != pt_tag(pt_integer) + packed_max_value) {
+ /* This is a stored reloacation value. */
+ rputc('\n');
+ return print_reloc(prp, "ref",
+ (ref_packed *)
+ ((const char *)prp -
+ (*rp & packed_value_mask) + dec));
+ }
+ /*
+ * We know this is the first of an aligned block
+ * of packed refs. Skip over the entire block,
+ * decrementing the final relocation.
+ */
+ dec += sizeof(ref_packed) * align_packed_per_ref;
+ rp += align_packed_per_ref;
+ } else
+ rp++;
+ continue;
+ }
+ if (!ref_type_uses_size_or_null(r_type((const ref *)rp))) { /* reloc is in r_size */
+ rputc('\n');
+ return print_reloc(prp, "ref",
+ (ref_packed *)
+ (r_size((const ref *)rp) == 0 ? prp :
+ (const ref_packed *)((const char *)prp - r_size((const ref *)rp) + dec)));
+ }
+ rputc('u');
+ rp += packed_per_ref;
+ }
+}
+
+/* ------ Compaction phase ------ */
+
+/* Compact a ref object. */
+/* Remove the marks at the same time. */
+private void
+refs_compact(obj_header_t * pre, obj_header_t * dpre, uint size)
+{
+ ref_packed *dest;
+ ref_packed *src;
+ ref_packed *end;
+ uint new_size;
+
+ src = (ref_packed *) (pre + 1);
+ end = (ref_packed *) ((byte *) src + size);
+ /*
+ * We know that a block of refs always ends with an unmarked
+ * full-size ref, so we only need to check for reaching the end
+ * of the block when we see one of those.
+ */
+ if (dpre == pre) /* Loop while we don't need to copy. */
+ for (;;) {
+ if (r_is_packed(src)) {
+ if (!r_has_pmark(src))
+ break;
+ if_debug1('8', " [8]packed ref 0x%lx \"copied\"\n",
+ (ulong) src);
+ *src &= ~lp_mark;
+ src++;
+ } else { /* full-size ref */
+ if (!r_has_attr((ref *) src, l_mark))
+ break;
+ if_debug1('8', " [8]ref 0x%lx \"copied\"\n",
+ (ulong) src);
+ r_clear_attrs((ref *) src, l_mark);
+ src += packed_per_ref;
+ }
+ } else
+ *dpre = *pre;
+ dest = (ref_packed *) ((char *)dpre + ((char *)src - (char *)pre));
+ for (;;) {
+ if (r_is_packed(src)) {
+ if (r_has_pmark(src)) {
+ if_debug2('8', " [8]packed ref 0x%lx copied to 0x%lx\n",
+ (ulong) src, (ulong) dest);
+ *dest++ = *PACKED(src) & ~lp_mark;
+ }
+ src++;
+ } else { /* full-size ref */
+ if (r_has_attr((ref *) src, l_mark)) {
+ ref rtemp;
+
+ if_debug2('8', " [8]ref 0x%lx copied to 0x%lx\n",
+ (ulong) src, (ulong) dest);
+ /* We can't just use ref_assign_inline, */
+ /* because the source and destination */
+ /* might overlap! */
+ ref_assign_inline(&rtemp, (ref *) src);
+ r_clear_attrs(&rtemp, l_mark);
+ ref_assign_inline((ref *) dest, &rtemp);
+ dest += packed_per_ref;
+ src += packed_per_ref;
+ } else { /* check for end of block */
+ src += packed_per_ref;
+ if (src >= end)
+ break;
+ }
+ }
+ }
+ new_size = (byte *) dest - (byte *) (dpre + 1) + sizeof(ref);
+#ifdef DEBUG
+ /* Check that the relocation came out OK. */
+ /* NOTE: this check only works within a single chunk. */
+ if ((byte *) src - (byte *) dest != r_size((ref *) src - 1) + sizeof(ref)) {
+ lprintf3("Reloc error for refs 0x%lx: reloc = %lu, stored = %u\n",
+ (ulong) dpre, (ulong) ((byte *) src - (byte *) dest),
+ (uint) r_size((ref *) src - 1));
+ gs_exit(1);
+ }
+#endif
+ /* Pad to a multiple of sizeof(ref). */
+ while (new_size & (sizeof(ref) - 1))
+ *dest++ = pt_tag(pt_integer),
+ new_size += sizeof(ref_packed);
+ /* We want to make the newly freed space into a free block, */
+ /* but we can only do this if we have enough room. */
+ if (size - new_size < sizeof(obj_header_t)) { /* Not enough room. Pad to original size. */
+ while (new_size < size)
+ *dest++ = pt_tag(pt_integer),
+ new_size += sizeof(ref_packed);
+ } else {
+ obj_header_t *pfree = (obj_header_t *) ((ref *) dest + 1);
+
+ pfree->o_large = 0;
+ pfree->o_size = size - new_size - sizeof(obj_header_t);
+ pfree->o_type = &st_bytes;
+ }
+ /* Re-create the final ref. */
+ r_set_type((ref *) dest, t_integer);
+ dpre->o_size = new_size;
+}
diff --git a/pstoraster/igcstr.c b/pstoraster/igcstr.c
new file mode 100644
index 000000000..1847ab51c
--- /dev/null
+++ b/pstoraster/igcstr.c
@@ -0,0 +1,393 @@
+/* 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$ */
+/* String GC routines for Ghostscript */
+#include "memory_.h"
+#include "ghost.h"
+#include "gsmdebug.h"
+#include "gsstruct.h"
+#include "iastate.h"
+#include "igcstr.h"
+
+/* Forward references */
+private bool gc_mark_string(P4(const byte *, uint, bool, const chunk_t *));
+
+/* (Un)mark the strings in a chunk. */
+void
+gc_strings_set_marks(chunk_t * cp, bool mark)
+{
+ if (cp->smark != 0) {
+ if_debug3('6', "[6]clearing string marks 0x%lx[%u] to %d\n",
+ (ulong) cp->smark, cp->smark_size, (int)mark);
+ memset(cp->smark, 0, cp->smark_size);
+ if (mark)
+ gc_mark_string(cp->sbase, cp->climit - cp->sbase, true, cp);
+ }
+}
+
+/* We mark strings a word at a time. */
+typedef string_mark_unit bword;
+
+#define bword_log2_bytes log2_sizeof_string_mark_unit
+#define bword_bytes (1 << bword_log2_bytes)
+#define bword_log2_bits (bword_log2_bytes + 3)
+#define bword_bits (1 << bword_log2_bits)
+#define bword_1s (~(bword)0)
+/* Compensate for byte order reversal if necessary. */
+#if arch_is_big_endian
+# if bword_bytes == 2
+# define bword_swap_bytes(m) m = (m << 8) | (m >> 8)
+# else /* bword_bytes == 4 */
+# define bword_swap_bytes(m)\
+ m = (m << 24) | ((m & 0xff00) << 8) | ((m >> 8) & 0xff00) | (m >> 24)
+# endif
+#else
+# define bword_swap_bytes(m) DO_NOTHING
+#endif
+
+/* (Un)mark a string in a known chunk. Return true iff any new marks. */
+private bool
+gc_mark_string(const byte * ptr, uint size, bool set, const chunk_t * cp)
+{
+ uint offset = ptr - cp->sbase;
+ bword *bp = (bword *) (cp->smark + ((offset & -bword_bits) >> 3));
+ uint bn = offset & (bword_bits - 1);
+ bword m = bword_1s << bn;
+ uint left = size;
+ bword marks = 0;
+
+ bword_swap_bytes(m);
+ if (set) {
+ if (left + bn >= bword_bits) {
+ marks |= ~*bp & m;
+ *bp |= m;
+ m = bword_1s, left -= bword_bits - bn, bp++;
+ while (left >= bword_bits) {
+ marks |= ~*bp;
+ *bp = bword_1s;
+ left -= bword_bits, bp++;
+ }
+ }
+ if (left) {
+ bword_swap_bytes(m);
+ m -= m << left;
+ bword_swap_bytes(m);
+ marks |= ~*bp & m;
+ *bp |= m;
+ }
+ } else {
+ if (left + bn >= bword_bits) {
+ *bp &= ~m;
+ m = bword_1s, left -= bword_bits - bn, bp++;
+ if (left >= bword_bits * 5) {
+ memset(bp, 0, (left & -bword_bits) >> 3);
+ bp += left >> bword_log2_bits;
+ left &= bword_bits - 1;
+ } else
+ while (left >= bword_bits) {
+ *bp = 0;
+ left -= bword_bits, bp++;
+ }
+ }
+ if (left) {
+ bword_swap_bytes(m);
+ m -= m << left;
+ bword_swap_bytes(m);
+ *bp &= ~m;
+ }
+ }
+ return marks != 0;
+}
+
+/* Mark a string. Return true if any new marks. */
+bool
+gc_string_mark(const byte * ptr, uint size, bool set, gc_state_t * gcst)
+{
+ const chunk_t *cp;
+ bool marks;
+
+ if (size == 0)
+ return false;
+#define dprintstr()\
+ dputc('('); fwrite(ptr, 1, min(size, 20), dstderr);\
+ dputs((size <= 20 ? ")" : "...)"))
+ if (!(cp = gc_locate(ptr, gcst))) { /* not in a chunk */
+#ifdef DEBUG
+ if (gs_debug_c('5')) {
+ dlprintf2("[5]0x%lx[%u]", (ulong) ptr, size);
+ dprintstr();
+ dputs(" not in a chunk\n");
+ }
+#endif
+ return false;
+ }
+ if (cp->smark == 0) /* not marking strings */
+ return false;
+#ifdef DEBUG
+ if (ptr < cp->ctop) {
+ lprintf4("String pointer 0x%lx[%u] outside [0x%lx..0x%lx)\n",
+ (ulong) ptr, size, (ulong) cp->ctop, (ulong) cp->climit);
+ return false;
+ } else if (ptr + size > cp->climit) { /*
+ * If this is the bottommost string in a chunk that has
+ * an inner chunk, the string's starting address is both
+ * cp->ctop of the outer chunk and cp->climit of the inner;
+ * gc_locate may incorrectly attribute the string to the
+ * inner chunk because of this. This doesn't affect
+ * marking or relocation, since the machinery for these
+ * is all associated with the outermost chunk,
+ * but it can cause the validity check to fail.
+ * Check for this case now.
+ */
+ const chunk_t *scp = cp;
+
+ while (ptr == scp->climit && scp->outer != 0)
+ scp = scp->outer;
+ if (ptr + size > scp->climit) {
+ lprintf4("String pointer 0x%lx[%u] outside [0x%lx..0x%lx)\n",
+ (ulong) ptr, size,
+ (ulong) scp->ctop, (ulong) scp->climit);
+ return false;
+ }
+ }
+#endif
+ marks = gc_mark_string(ptr, size, set, cp);
+#ifdef DEBUG
+ if (gs_debug_c('5')) {
+ dlprintf4("[5]%s%smarked 0x%lx[%u]",
+ (marks ? "" : "already "), (set ? "" : "un"),
+ (ulong) ptr, size);
+ dprintstr();
+ dputc('\n');
+ }
+#endif
+ return marks;
+}
+
+/* Clear the relocation for strings. */
+/* This requires setting the marks. */
+void
+gc_strings_clear_reloc(chunk_t * cp)
+{
+ if (cp->sreloc != 0) {
+ gc_strings_set_marks(cp, true);
+ if_debug1('6', "[6]clearing string reloc 0x%lx\n",
+ (ulong) cp->sreloc);
+ gc_strings_set_reloc(cp);
+ }
+}
+
+/* Count the 0-bits in a byte. */
+private const byte count_zero_bits_table[256] =
+{
+#define o4(n) n,n-1,n-1,n-2
+#define o16(n) o4(n),o4(n-1),o4(n-1),o4(n-2)
+#define o64(n) o16(n),o16(n-1),o16(n-1),o16(n-2)
+ o64(8), o64(7), o64(7), o64(6)
+};
+
+#define byte_count_zero_bits(byt)\
+ (uint)(count_zero_bits_table[byt])
+#define byte_count_one_bits(byt)\
+ (uint)(8 - count_zero_bits_table[byt])
+
+/* Set the relocation for the strings in a chunk. */
+/* The sreloc table stores the relocated offset from climit for */
+/* the beginning of each block of string_data_quantum characters. */
+void
+gc_strings_set_reloc(chunk_t * cp)
+{
+ if (cp->sreloc != 0 && cp->smark != 0) {
+ byte *bot = cp->ctop;
+ byte *top = cp->climit;
+ uint count =
+ (top - bot + (string_data_quantum - 1)) >>
+ log2_string_data_quantum;
+ string_reloc_offset *relp =
+ cp->sreloc +
+ (cp->smark_size >> (log2_string_data_quantum - 3));
+ register byte *bitp = cp->smark + cp->smark_size;
+ register string_reloc_offset reloc = 0;
+
+ while (count--) {
+ bitp -= string_data_quantum / 8;
+ reloc += string_data_quantum -
+ byte_count_zero_bits(bitp[0]);
+ reloc -= byte_count_zero_bits(bitp[1]);
+ reloc -= byte_count_zero_bits(bitp[2]);
+ reloc -= byte_count_zero_bits(bitp[3]);
+#if log2_string_data_quantum > 5
+ reloc -= byte_count_zero_bits(bitp[4]);
+ reloc -= byte_count_zero_bits(bitp[5]);
+ reloc -= byte_count_zero_bits(bitp[6]);
+ reloc -= byte_count_zero_bits(bitp[7]);
+#endif
+ *--relp = reloc;
+ }
+ }
+ cp->sdest = cp->climit;
+}
+
+/* Relocate a string pointer. */
+void
+igc_reloc_string(gs_string * sptr, gc_state_t * gcst)
+{
+ byte *ptr;
+ const chunk_t *cp;
+ uint offset;
+ uint reloc;
+ const byte *bitp;
+ byte byt;
+
+ if (sptr->size == 0) {
+ sptr->data = 0;
+ return;
+ }
+ ptr = sptr->data;
+ if (!(cp = gc_locate(ptr, gcst))) /* not in a chunk */
+ return;
+ if (cp->sreloc == 0 || cp->smark == 0) /* not marking strings */
+ return;
+ offset = ptr - cp->sbase;
+ reloc = cp->sreloc[offset >> log2_string_data_quantum];
+ bitp = &cp->smark[offset >> 3];
+ switch (offset & (string_data_quantum - 8)) {
+#if log2_string_data_quantum > 5
+ case 56:
+ reloc -= byte_count_one_bits(bitp[-7]);
+ case 48:
+ reloc -= byte_count_one_bits(bitp[-6]);
+ case 40:
+ reloc -= byte_count_one_bits(bitp[-5]);
+ case 32:
+ reloc -= byte_count_one_bits(bitp[-4]);
+#endif
+ case 24:
+ reloc -= byte_count_one_bits(bitp[-3]);
+ case 16:
+ reloc -= byte_count_one_bits(bitp[-2]);
+ case 8:
+ reloc -= byte_count_one_bits(bitp[-1]);
+ }
+ byt = *bitp & (0xff >> (8 - (offset & 7)));
+ reloc -= byte_count_one_bits(byt);
+ if_debug2('5', "[5]relocate string 0x%lx to 0x%lx\n",
+ (ulong) ptr, (ulong) (cp->sdest - reloc));
+ sptr->data = cp->sdest - reloc;
+}
+void
+igc_reloc_const_string(gs_const_string * sptr, gc_state_t * gcst)
+{ /* We assume the representation of byte * and const byte * is */
+ /* the same.... */
+ igc_reloc_string((gs_string *) sptr, gcst);
+}
+
+/* Compact the strings in a chunk. */
+void
+gc_strings_compact(chunk_t * cp)
+{
+ if (cp->smark != 0) {
+ byte *hi = cp->climit;
+ byte *lo = cp->ctop;
+ register const byte *from = hi;
+ register byte *to = hi;
+ register const byte *bp = cp->smark + cp->smark_size;
+
+#ifdef DEBUG
+ if (gs_debug_c('4') || gs_debug_c('5')) {
+ byte *base = cp->sbase;
+ uint i = (lo - base) & -string_data_quantum;
+ uint n = round_up(hi - base, string_data_quantum);
+
+#define R 16
+ for (; i < n; i += R) {
+ uint j;
+
+ dlprintf1("[4]0x%lx: ", (ulong) (base + i));
+ for (j = i; j < i + R; j++) {
+ byte ch = base[j];
+
+ if (ch <= 31) {
+ dputc('^');
+ dputc(ch + 0100);
+ } else
+ dputc(ch);
+ }
+ dputc(' ');
+ for (j = i; j < i + R; j++)
+ dputc((cp->smark[j >> 3] & (1 << (j & 7)) ?
+ '+' : '.'));
+#undef R
+ if (!(i & (string_data_quantum - 1)))
+ dprintf1(" %u", cp->sreloc[i >> log2_string_data_quantum]);
+ dputc('\n');
+ }
+ }
+#endif
+ while (from > lo) {
+ register byte b = *--bp;
+
+ from -= 8;
+ switch (b) {
+ case 0xff:
+ to -= 8;
+ if (to != from) {
+ to[7] = from[7];
+ to[6] = from[6];
+ to[5] = from[5];
+ to[4] = from[4];
+ to[3] = from[3];
+ to[2] = from[2];
+ to[1] = from[1];
+ to[0] = from[0];
+ }
+ break;
+ default:
+ if (b & 0x80)
+ *--to = from[7];
+ if (b & 0x40)
+ *--to = from[6];
+ if (b & 0x20)
+ *--to = from[5];
+ if (b & 0x10)
+ *--to = from[4];
+ if (b & 8)
+ *--to = from[3];
+ if (b & 4)
+ *--to = from[2];
+ if (b & 2)
+ *--to = from[1];
+ if (b & 1)
+ *--to = from[0];
+ /* falls through */
+ case 0:
+ ;
+ }
+ }
+ gs_alloc_fill(cp->ctop, gs_alloc_fill_collected,
+ to - cp->ctop);
+ cp->ctop = to;
+ }
+}
diff --git a/pstoraster/igcstr.h b/pstoraster/igcstr.h
new file mode 100644
index 000000000..3d980e720
--- /dev/null
+++ b/pstoraster/igcstr.h
@@ -0,0 +1,41 @@
+/* Copyright (C) 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of GNU Ghostscript.
+
+ GNU Ghostscript is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
+ to anyone for the consequences of using it or for whether it serves any
+ particular purpose or works at all, unless he says so in writing. Refer
+ to the GNU General Public License for full details.
+
+ Everyone is granted permission to copy, modify and redistribute GNU
+ Ghostscript, but only under the conditions described in the GNU General
+ Public License. A copy of this license is supposed to have been given
+ to you along with GNU Ghostscript so you can know your rights and
+ responsibilities. It should be in a file named COPYING. Among other
+ things, the copyright notice and this notice must be preserved on all
+ copies.
+
+ Aladdin Enterprises 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 interface to string garbage collector */
+
+#ifndef igcstr_INCLUDED
+# define igcstr_INCLUDED
+
+/* Exported by ilocate.c for igcstr.c */
+chunk_t *gc_locate(P2(const void *, gc_state_t *));
+
+/* Exported by igcstr.c for igc.c */
+void gc_strings_set_marks(P2(chunk_t *, bool));
+bool gc_string_mark(P4(const byte *, uint, bool, gc_state_t *));
+void gc_strings_clear_reloc(P1(chunk_t *));
+void gc_strings_set_reloc(P1(chunk_t *));
+void gc_strings_compact(P1(chunk_t *));
+
+#endif /* igcstr_INCLUDED */
diff --git a/pstoraster/igstate.h b/pstoraster/igstate.h
new file mode 100644
index 000000000..18675c4a6
--- /dev/null
+++ b/pstoraster/igstate.h
@@ -0,0 +1,181 @@
+/* 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$ */
+/* Ghostscript interpreter graphics state definition */
+
+#ifndef igstate_INCLUDED
+# define igstate_INCLUDED
+
+#include "gsstate.h"
+#include "gxstate.h" /* for 'client data' access */
+#include "istruct.h" /* for gstate obj definition */
+
+/*
+ * From the interpreter's point of view, the graphics state is largely opaque,
+ * i.e., the interpreter is just another client of the library.
+ * The interpreter does require additional items in the graphics state;
+ * these are "client data" from the library's point of view.
+ * Most of the complexity in this added state comes from
+ * the parameters associated with the various Level 2 color spaces.
+ * Note that the added information consists entirely of refs.
+ */
+
+/*
+ * The interpreter represents graphics state objects in a slightly
+ * unnatural way, namely, by a t_astruct ref that points to an object
+ * of type st_igstate_obj, which is essentially a t_struct ref that in turn
+ * points to a real graphics state (object of type st_gs_state).
+ * We do this so that save and restore can manipulate the intermediate
+ * object and not have to worry about copying entire gs_states.
+ *
+ * Because a number of different operators must test whether an object
+ * is a gstate, we make an exception to our convention of declaring
+ * structure descriptors only in the place where the structure itself
+ * is defined (see gsstruct.h for more information on this).
+ */
+typedef struct igstate_obj_s {
+ ref gstate; /* t_struct / st_gs_state */
+} igstate_obj;
+
+extern_st(st_igstate_obj);
+#define public_st_igstate_obj() /* in zdps1.c */\
+ gs_public_st_ref_struct(st_igstate_obj, igstate_obj, "gstatetype")
+#define igstate_ptr(rp) r_ptr(&r_ptr(rp, igstate_obj)->gstate, gs_state)
+
+/* DeviceN names and tint transform */
+typedef struct ref_device_n_params_s {
+ ref layer_names, tint_transform;
+} ref_device_n_params;
+
+/* CIE transformation procedures */
+typedef struct ref_cie_procs_s {
+ union {
+ ref DEFG;
+ ref DEF;
+ } PreDecode;
+ union {
+ ref ABC;
+ ref A;
+ } Decode;
+ ref DecodeLMN;
+} ref_cie_procs;
+
+/* CIE rendering transformation procedures */
+typedef struct ref_cie_render_procs_s {
+ ref TransformPQR, EncodeLMN, EncodeABC, RenderTableT;
+} ref_cie_render_procs;
+
+/* Separation name and tint transform */
+typedef struct ref_separation_params_s {
+ ref layer_name, tint_transform;
+} ref_separation_params;
+
+/* All color space parameters. */
+/* All of these are optional. */
+/* Note that they may actually be the parameters for an underlying or */
+/* alternate space for a special space. */
+typedef struct ref_color_procs_s {
+ ref_cie_procs cie;
+ union {
+ ref_device_n_params device_n;
+ ref_separation_params separation;
+ ref index_proc;
+ } special;
+} ref_color_procs;
+typedef struct ref_colorspace_s {
+ ref array; /* color space (array), */
+ /* only relevant if the current */
+ /* color space has parameters associated with it. */
+ ref_color_procs procs; /* associated procedures/parameters, */
+ /* only relevant for DeviceN, CIE, Separation, Indexed/CIE, */
+ /* Indexed with procedure, or a Pattern with one of these. */
+} ref_colorspace;
+
+typedef struct int_gstate_s {
+ ref dash_pattern; /* (array) */
+ /* Screen_procs are only relevant if setscreen was */
+ /* executed more recently than sethalftone */
+ /* (for this graphics context). */
+ union {
+ ref indexed[4];
+ struct {
+ /* The components must be in this order: */
+ ref red, green, blue, gray;
+ } colored;
+ } screen_procs, /* halftone screen procedures */
+ transfer_procs; /* transfer procedures */
+ ref black_generation; /* (procedure) */
+ ref undercolor_removal; /* (procedure) */
+ ref_colorspace colorspace;
+ /* Pattern is only relevant if the current color space */
+ /* is a pattern space. */
+ ref pattern; /* pattern (dictionary) */
+ struct {
+ ref dict; /* CIE color rendering dictionary */
+ ref_cie_render_procs procs; /* (see above) */
+ } colorrendering;
+ /* Halftone is only relevant if sethalftone was executed */
+ /* more recently than setscreen for this graphics context. */
+ /* setscreen sets it to null. */
+ ref halftone; /* halftone (dictionary) */
+ /* Pagedevice is only relevant if setpagedevice was */
+ /* executed more recently than nulldevice, setcachedevice, */
+ /* or setdevice with a non-page device (for this */
+ /* graphics context). If the current device is not a */
+ /* page device, pagedevice is null. */
+ ref pagedevice; /* page device (dictionary|null) */
+} int_gstate;
+
+#define clear_pagedevice(pigs) make_null(&(pigs)->pagedevice)
+/*
+ * Even though the interpreter's part of the graphics state actually
+ * consists of refs, allocating it as refs tends to create sandbars;
+ * since it is always allocated and freed as a unit, we can treat it
+ * as an ordinary structure.
+ */
+#define private_st_int_gstate() /* in zgstate.c */\
+ gs_private_st_ref_struct(st_int_gstate, int_gstate, "int_gstate")
+
+/* Enumerate the refs in an int_gstate. */
+/* Since all the elements of an int_gstate are refs, this is simple. */
+#define int_gstate_map_refs(p,m)\
+ { register ref *rp_ = (ref *)(p);\
+ register int i = sizeof(int_gstate) / sizeof(ref);\
+ do { m(rp_); ++rp_; } while ( --i );\
+ }
+
+/* Create the gstate for a new context. */
+/* We export this so that fork can use it. */
+gs_state *int_gstate_alloc(P1(gs_ref_memory_t * mem));
+
+/* Get the int_gstate from a gs_state. */
+#define gs_int_gstate(pgs) ((int_gstate *)gs_state_client_data(pgs))
+
+/* The current instances. */
+extern gs_state *igs;
+
+#define istate gs_int_gstate(igs)
+
+#endif /* igstate_INCLUDED */
diff --git a/pstoraster/iht.h b/pstoraster/iht.h
new file mode 100644
index 000000000..56eb8d41b
--- /dev/null
+++ b/pstoraster/iht.h
@@ -0,0 +1,37 @@
+/* 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$ */
+/* Procedures exported by zht.c for zht1.c and zht2.c */
+
+#ifndef iht_INCLUDED
+# define iht_INCLUDED
+
+int zscreen_params(P2(os_ptr op, gs_screen_halftone * phs));
+
+int zscreen_enum_init(P7(os_ptr op, const gx_ht_order * porder,
+ gs_screen_halftone * phs, ref * pproc, int npop,
+ int (*finish_proc) (P1(os_ptr)), gs_memory_t * mem));
+
+#endif /* iht_INCLUDED */
diff --git a/pstoraster/iimage.h b/pstoraster/iimage.h
new file mode 100644
index 000000000..f4fed3ee1
--- /dev/null
+++ b/pstoraster/iimage.h
@@ -0,0 +1,46 @@
+/* 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 gscspace.h, gxiparam.h */
+
+#ifndef iimage_INCLUDED
+# define iimage_INCLUDED
+
+/* These procedures are exported by zimage.c for other modules. */
+
+/* Exported for zcolor1.c and zdpnext.c */
+int zimage_opaque_setup(P5(os_ptr op, bool multi, gs_image_alpha_t alpha,
+ const gs_color_space * pcs, int npop));
+
+/* Exported for zimage2.c */
+int zimage_setup(P4(const gs_pixel_image_t * pim, const ref * sources,
+ bool uses_color, int npop));
+
+/* Exported for zcolor3.c */
+int zimage_data_setup(P4(const gs_pixel_image_t * pim,
+ gx_image_enum_common_t * pie,
+ const ref * sources, int npop));
+
+#endif /* iimage_INCLUDED */
diff --git a/pstoraster/iimage2.h b/pstoraster/iimage2.h
new file mode 100644
index 000000000..c9554dbe4
--- /dev/null
+++ b/pstoraster/iimage2.h
@@ -0,0 +1,50 @@
+/* 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$ */
+/* Requires gsiparam.h */
+
+#ifndef iimage2_INCLUDED
+# define iimage2_INCLUDED
+
+/* These procedures are exported by zimage2.c for other modules. */
+
+/*
+ * Define a structure for image parameters other than those defined
+ * in the gs_*image*_t structure.
+ */
+typedef struct image_params_s {
+ bool MultipleDataSources;
+ ref DataSource[gs_image_max_components];
+ const float *pDecode;
+} image_params;
+
+/* Extract and check parameters for an image. */
+int data_image_params(P6(const ref * op, gs_data_image_t * pim,
+ image_params * pip, bool require_DataSource,
+ int num_components, int max_bits_per_component));
+int pixel_image_params(P4(const ref * op, gs_pixel_image_t * pim,
+ image_params * pip, int max_bits_per_component));
+
+#endif /* iimage2_INCLUDED */
diff --git a/pstoraster/iinit.c b/pstoraster/iinit.c
new file mode 100644
index 000000000..d2c919d35
--- /dev/null
+++ b/pstoraster/iinit.c
@@ -0,0 +1,511 @@
+/* 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$ */
+/* Initialize internally known objects for Ghostscript interpreter */
+#include "string_.h"
+#include "ghost.h"
+#include "gscdefs.h"
+#include "gsexit.h"
+#include "gsstruct.h"
+#include "errors.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "dstack.h"
+#include "ilevel.h"
+#include "iname.h"
+#include "interp.h"
+#include "ipacked.h"
+#include "iparray.h"
+#include "iutil.h"
+#include "ivmspace.h"
+#include "opdef.h"
+#include "store.h"
+
+/* Implementation parameters. */
+/*
+ * Define the (initial) sizes of the various system dictionaries. We want
+ * the sizes to be prime numbers large enough to cover all the operators,
+ * plus everything in the init files, even if all the optional features are
+ * selected. Note that these sizes must be large enough to get us through
+ * initialization, since we start up in Level 1 mode where dictionaries
+ * don't expand automatically.
+ */
+/* The size of systemdict can be set in the makefile. */
+#ifndef SYSTEMDICT_SIZE
+# define SYSTEMDICT_SIZE 601
+#endif
+#ifndef SYSTEMDICT_LEVEL2_SIZE
+# define SYSTEMDICT_LEVEL2_SIZE 941
+#endif
+/* The size of level2dict, if applicable, can be set in the makefile. */
+#ifndef LEVEL2DICT_SIZE
+# define LEVEL2DICT_SIZE 233
+#endif
+/* Ditto the size of ll3dict. */
+#ifndef LL3DICT_SIZE
+# define LL3DICT_SIZE 43
+#endif
+/* Ditto the size of filterdict. */
+#ifndef FILTERDICT_SIZE
+# define FILTERDICT_SIZE 43
+#endif
+/* Define an arbitrary size for the operator procedure tables. */
+#ifndef OP_ARRAY_TABLE_SIZE
+# define OP_ARRAY_TABLE_SIZE 180
+#endif
+#ifndef OP_ARRAY_TABLE_GLOBAL_SIZE
+# define OP_ARRAY_TABLE_GLOBAL_SIZE OP_ARRAY_TABLE_SIZE
+#endif
+#ifndef OP_ARRAY_TABLE_LOCAL_SIZE
+# define OP_ARRAY_TABLE_LOCAL_SIZE (OP_ARRAY_TABLE_SIZE / 2)
+#endif
+#define OP_ARRAY_TABLE_TOTAL_SIZE\
+ (OP_ARRAY_TABLE_GLOBAL_SIZE + OP_ARRAY_TABLE_LOCAL_SIZE)
+
+/* Define the list of error names. */
+const char *const gs_error_names[] =
+{
+ ERROR_NAMES
+};
+
+/* The operator tables */
+const op_def **op_def_table;
+uint op_def_count;
+op_array_table op_array_table_global, op_array_table_local; /* definitions of `operator' procedures */
+
+/* Enter a name and value into a dictionary. */
+void
+initial_enter_name_in(const char *nstr, const ref * pref, ref * pdict)
+{
+ int code = dict_put_string(pdict, nstr, pref);
+
+ if (code < 0) {
+ lprintf4("initial_enter failed (%d), entering /%s in -dict:%u/%u-\n",
+ code, nstr, dict_length(pdict), dict_maxlength(pdict));
+ gs_exit(1);
+ }
+}
+void
+initial_enter_name(const char *nstr, const ref * pref)
+{
+ initial_enter_name_in(nstr, pref, systemdict);
+}
+
+/* Remove a name from systemdict. */
+void
+initial_remove_name(const char *nstr)
+{
+ ref nref;
+
+ if (name_ref((const byte *)nstr, strlen(nstr), &nref, -1) >= 0)
+ dict_undef(systemdict, &nref);
+}
+
+/* Create a name. Fatal error if it fails. */
+private void
+name_enter(const char *str, ref * pref)
+{
+ if (name_enter_string(str, pref) != 0) {
+ lprintf1("name_enter failed - %s\n", str);
+ gs_exit(1);
+ }
+}
+
+/* Define the names and sizes of the initial dictionaries. */
+/* The names are used to create references in systemdict. */
+const struct {
+ const char *name;
+ uint size;
+ bool local;
+} initial_dictionaries[] = {
+#ifdef INITIAL_DICTIONARIES
+ INITIAL_DICTIONARIES
+#else
+ /* systemdict is created and named automagically */
+ {
+ "level2dict", LEVEL2DICT_SIZE, false
+ },
+ {
+ "ll3dict", LL3DICT_SIZE, false
+ },
+ {
+ "globaldict", 0, false
+ },
+ {
+ "userdict", 0, true
+ },
+ {
+ "filterdict", FILTERDICT_SIZE, false
+ },
+#endif
+};
+/* systemdict and globaldict are magically inserted at the bottom */
+const char *const initial_dstack[] =
+{
+#ifdef INITIAL_DSTACK
+ INITIAL_DSTACK
+#else
+ "userdict"
+#endif
+};
+
+#define MIN_DSTACK_SIZE (countof(initial_dstack) + 1) /* +1 for systemdict */
+
+
+/* Detect whether we have any Level 2 operators. */
+/* We export this for gs_init1 in imain.c. */
+/* This is very slow, but we only call it a couple of times. */
+bool
+gs_have_level2(void)
+{
+ const op_def *const *tptr;
+
+ for (tptr = op_defs_all; *tptr != 0; ++tptr) {
+ const op_def *def;
+
+ for (def = *tptr; def->oname != 0; ++def)
+ if (op_def_is_begin_dict(def) &&
+ !strcmp(def->oname, "level2dict")
+ )
+ return true;
+ }
+ return false;
+}
+
+/* Create an initial dictionary if necessary. */
+private ref *
+make_initial_dict(const char *iname, ref idicts[])
+{
+ int i;
+
+ /* systemdict was created specially. */
+ if (!strcmp(iname, "systemdict"))
+ return systemdict;
+ for (i = 0; i < countof(initial_dictionaries); i++) {
+ const char *dname = initial_dictionaries[i].name;
+ const int dsize = initial_dictionaries[i].size;
+
+ if (!strcmp(iname, dname)) {
+ ref *dref = &idicts[i];
+
+ if (r_has_type(dref, t_null)) {
+ gs_ref_memory_t *mem =
+ (initial_dictionaries[i].local ?
+ iimemory_local : iimemory_global);
+ int code = dict_alloc(mem, dsize, dref);
+
+ if (code < 0)
+ return 0; /* disaster */
+ }
+ return dref;
+ }
+ }
+
+ /*
+ * Name mentioned in some op_def, but not in initial_dictionaries.
+ * Punt.
+ */
+ return 0;
+}
+
+/* Initialize objects other than operators. In particular, */
+/* initialize the dictionaries that hold operator definitions. */
+void
+obj_init(void)
+{
+ bool level2 = gs_have_level2();
+
+ /* Initialize the language level. */
+ make_int(&ref_language_level, 1);
+
+ /*
+ * Create systemdict. The context machinery requires that
+ * we do this before initializing the interpreter.
+ */
+ dict_alloc(iimemory_global,
+ (level2 ? SYSTEMDICT_LEVEL2_SIZE : SYSTEMDICT_SIZE),
+ systemdict);
+
+ /* Initialize the interpreter. */
+ gs_interp_init();
+
+ {
+#define icount countof(initial_dictionaries)
+ ref idicts[icount];
+ int i;
+ const op_def *const *tptr;
+
+ min_dstack_size = MIN_DSTACK_SIZE;
+
+ refset_null(idicts, icount);
+
+ /* Put systemdict on the dictionary stack. */
+ if (level2) {
+ dsp += 2;
+ /*
+ * For the moment, let globaldict be an alias for systemdict.
+ */
+ dsp[-1] = *systemdict;
+ min_dstack_size++;
+ } else {
+ ++dsp;
+ }
+ *dsp = *systemdict;
+
+ /* Create dictionaries which are to be homes for operators. */
+ for (tptr = op_defs_all; *tptr != 0; tptr++) {
+ const op_def *def;
+
+ for (def = *tptr; def->oname != 0; def++)
+ if (op_def_is_begin_dict(def))
+ make_initial_dict(def->oname, idicts);
+ }
+
+ /* Set up the initial dstack. */
+ for (i = 0; i < countof(initial_dstack); i++) {
+ const char *dname = initial_dstack[i];
+
+ ++dsp;
+ if (!strcmp(dname, "userdict"))
+ dstack_userdict_index = dsp - dsbot;
+ ref_assign(dsp, make_initial_dict(dname, idicts));
+ }
+
+ /* Enter names of referenced initial dictionaries into systemdict. */
+ initial_enter_name("systemdict", systemdict);
+ for (i = 0; i < icount; i++) {
+ ref *idict = &idicts[i];
+
+ if (!r_has_type(idict, t_null)) { /*
+ * Note that we enter the dictionary in systemdict
+ * even if it is in local VM. There is a special
+ * provision in the garbage collector for this:
+ * see ivmspace.h for more information.
+ * In order to do this, we must temporarily
+ * identify systemdict as local, so that the
+ * store check in dict_put won't fail.
+ */
+ uint save_space = r_space(systemdict);
+
+ r_set_space(systemdict, avm_local);
+ initial_enter_name(initial_dictionaries[i].name,
+ idict);
+ r_set_space(systemdict, save_space);
+ }
+ }
+#undef icount
+ }
+
+ gs_interp_reset();
+
+ {
+ ref vtemp;
+
+ make_null(&vtemp);
+ initial_enter_name("null", &vtemp);
+ make_true(&vtemp);
+ initial_enter_name("true", &vtemp);
+ make_false(&vtemp);
+ initial_enter_name("false", &vtemp);
+ }
+
+ /* Create the error name table */
+ {
+ int n = countof(gs_error_names) - 1;
+ int i;
+ ref era;
+
+ ialloc_ref_array(&era, a_readonly, n, "ErrorNames");
+ for (i = 0; i < n; i++)
+ name_enter((const char *)gs_error_names[i],
+ era.value.refs + i);
+ initial_enter_name("ErrorNames", &era);
+ }
+}
+
+/* Run the initialization procedures of the individual operator files. */
+void
+zop_init(void)
+{
+ const op_def *const *tptr;
+
+ /* Because of a bug in Sun's SC1.0 compiler, */
+ /* we have to spell out the typedef for op_def_ptr here: */
+ const op_def *def;
+
+ for (tptr = op_defs_all; *tptr != 0; tptr++) {
+ for (def = *tptr; def->oname != 0; def++)
+ DO_NOTHING;
+ if (def->proc != 0)
+ ((void (*)(P0()))(def->proc)) ();
+ }
+
+ /* Initialize the predefined names other than operators. */
+ /* Do this here in case op_init changed any of them. */
+ {
+ ref vtemp;
+
+ make_const_string(&vtemp, a_readonly | avm_foreign,
+ strlen(gs_copyright),
+ (const byte *)gs_copyright);
+ initial_enter_name("copyright", &vtemp);
+ make_const_string(&vtemp, a_readonly | avm_foreign,
+ strlen(gs_product),
+ (const byte *)gs_product);
+ initial_enter_name("product", &vtemp);
+ make_int(&vtemp, gs_revision);
+ initial_enter_name("revision", &vtemp);
+ make_int(&vtemp, gs_revisiondate);
+ initial_enter_name("revisiondate", &vtemp);
+ }
+}
+
+/* Create an op_array table. */
+private int
+alloc_op_array_table(uint size, uint space, op_array_table * opt)
+{
+ uint save_space = ialloc_space(idmemory);
+ int code;
+
+ ialloc_set_space(idmemory, space);
+ code = ialloc_ref_array(&opt->table, a_readonly, size,
+ "op_array table");
+ ialloc_set_space(idmemory, save_space);
+ if (code < 0)
+ return code;
+ refset_null(opt->table.value.refs, size);
+ opt->nx_table =
+ (ushort *) ialloc_byte_array(size, sizeof(ushort),
+ "op_array nx_table");
+ if (opt->nx_table == 0)
+ return_error(e_VMerror);
+ opt->count = 0;
+ opt->root_p = &opt->table;
+ opt->attrs = space | a_executable;
+ return 0;
+}
+
+/* Initialize the operator table. */
+void
+op_init(void)
+{
+ int count = 1;
+ const op_def *const *tptr;
+ const op_def *def;
+ const char *nstr;
+
+ /* Do a first pass just to count the operators. */
+
+ for (tptr = op_defs_all; *tptr != 0; tptr++) {
+ for (def = *tptr; def->oname != 0; def++)
+ if (!op_def_is_begin_dict(def))
+ count++;
+ }
+
+ /* Do a second pass to construct the operator table, */
+ /* and enter the operators into the appropriate dictionary. */
+
+ /* Because of a bug in Sun's SC1.0 compiler, */
+ /* we have to spell out the typedef for op_def_ptr here: */
+ op_def_table =
+ (const op_def **)ialloc_byte_array(count, sizeof(const op_def *),
+ "op_init(op_def_table)");
+
+ op_def_count = count;
+ for (count = 0; count <= gs_interp_num_special_ops; count++)
+ op_def_table[count] = 0;
+ count = gs_interp_num_special_ops + 1; /* leave space for magic entries */
+ for (tptr = op_defs_all; *tptr != 0; tptr++) {
+ ref *pdict = systemdict;
+
+ for (def = *tptr; (nstr = def->oname) != 0; def++)
+ if (op_def_is_begin_dict(def)) {
+ ref nref;
+ int code = name_ref((const byte *)nstr, strlen(nstr),
+ &nref, -1);
+
+ if (code != 0)
+ gs_abort();
+ if (!dict_find(systemdict, &nref, &pdict))
+ gs_abort();
+ if (!r_has_type(pdict, t_dictionary))
+ gs_abort();
+ } else {
+ ref oper;
+ uint opidx;
+
+ gs_interp_make_oper(&oper, def->proc, count);
+ opidx = r_size(&oper);
+ /* The first character of the name is a digit */
+ /* giving the minimum acceptable number of operands. */
+ /* Check to make sure it's within bounds. */
+ if (*nstr - '0' > gs_interp_max_op_num_args)
+ gs_abort();
+ nstr++;
+ /* Don't enter internal operators into */
+ /* the dictionary. */
+ if (*nstr != '%')
+ initial_enter_name_in(nstr, &oper, pdict);
+ op_def_table[opidx] = def;
+ if (opidx == count)
+ count++;
+ }
+ }
+ /* All of the built-ins had better be defined somewhere, */
+ /* or things like op_find_index will choke. */
+ for (count = 1; count <= gs_interp_num_special_ops; count++)
+ if (op_def_table[count] == 0)
+ gs_abort();
+ gs_register_struct_root(imemory, NULL, (void **)&op_def_table,
+ "op_def_table");
+
+ /* Allocate the tables for `operator' procedures. */
+ /* Make one of them local so we can have local operators. */
+
+ if (alloc_op_array_table(OP_ARRAY_TABLE_GLOBAL_SIZE,
+ avm_global, &op_array_table_global) < 0)
+ gs_abort();
+ op_array_table_global.base_index = op_def_count;
+ gs_register_ref_root(imemory, NULL,
+ (void **)&op_array_table_global.root_p,
+ "op_array_table(global)");
+ gs_register_struct_root(imemory, NULL,
+ (void **)&op_array_table_global.nx_table,
+ "op_array nx_table(global)");
+
+ if (alloc_op_array_table(OP_ARRAY_TABLE_LOCAL_SIZE,
+ avm_local, &op_array_table_local) < 0)
+ gs_abort();
+ op_array_table_local.base_index =
+ op_array_table_global.base_index +
+ r_size(&op_array_table_global.table);
+ gs_register_ref_root(imemory, NULL,
+ (void **)&op_array_table_local.root_p,
+ "op_array_table(local)");
+ gs_register_struct_root(imemory, NULL,
+ (void **)&op_array_table_local.nx_table,
+ "op_array nx_table(local)");
+
+}
diff --git a/pstoraster/ilevel.h b/pstoraster/ilevel.h
new file mode 100644
index 000000000..a7b90c54f
--- /dev/null
+++ b/pstoraster/ilevel.h
@@ -0,0 +1,39 @@
+/* Copyright (C) 1992, 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 language level interface */
+
+#ifndef ilevel_INCLUDED
+# define ilevel_INCLUDED
+
+/* The current interpreter language level */
+extern ref ref_language_level;
+
+#define LANGUAGE_LEVEL ((int)ref_language_level.value.intval)
+#define LL2_ENABLED (LANGUAGE_LEVEL >= 2)
+#define LL3_ENABLED (LANGUAGE_LEVEL >= 3)
+#define level2_enabled LL2_ENABLED /* backward compatibility */
+
+#endif /* ilevel_INCLUDED */
diff --git a/pstoraster/ilocate.c b/pstoraster/ilocate.c
new file mode 100644
index 000000000..8ae5ddaf7
--- /dev/null
+++ b/pstoraster/ilocate.c
@@ -0,0 +1,439 @@
+/* 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$ */
+/* Object locating and validating for Ghostscript memory manager */
+#include "ghost.h"
+#include "memory_.h"
+#include "errors.h"
+#include "gsexit.h"
+#include "gsstruct.h"
+#include "iastate.h"
+#include "idict.h"
+#include "igc.h" /* for gc_state_t */
+#include "igcstr.h" /* for prototype */
+#include "iname.h"
+#include "ipacked.h"
+#include "isstate.h"
+#include "iutil.h" /* for packed_get */
+#include "ivmspace.h"
+#include "store.h"
+
+/* ================ Locating ================ */
+
+/* Locate a pointer in the chunks of a space being collected. */
+/* This is only used for string garbage collection and for debugging. */
+chunk_t *
+gc_locate(const void *ptr, gc_state_t * gcst)
+{
+ const gs_ref_memory_t *mem;
+
+ if (chunk_locate(ptr, &gcst->loc))
+ return gcst->loc.cp;
+ mem = gcst->loc.memory;
+
+ /* Try the other space, if there is one. */
+
+ if (gcst->space_local != gcst->space_global) {
+ gcst->loc.memory =
+ (mem->space == avm_local ? gcst->space_global : gcst->space_local);
+ gcst->loc.cp = 0;
+ if (chunk_locate(ptr, &gcst->loc))
+ return gcst->loc.cp;
+ /* Try other save levels of this space. */
+ while (gcst->loc.memory->saved != 0) {
+ gcst->loc.memory = &gcst->loc.memory->saved->state;
+ gcst->loc.cp = 0;
+ if (chunk_locate(ptr, &gcst->loc))
+ return gcst->loc.cp;
+ }
+ }
+
+ /*
+ * Try system space. This is simpler because it isn't subject to
+ * save/restore.
+ */
+
+ if (mem != gcst->space_system) {
+ gcst->loc.memory = gcst->space_system;
+ gcst->loc.cp = 0;
+ if (chunk_locate(ptr, &gcst->loc))
+ return gcst->loc.cp;
+ }
+
+ /*
+ * Try other save levels of the initial space, or of global space if the
+ * original space was system space. In the latter case, try all
+ * levels.
+ */
+
+ gcst->loc.memory =
+ (mem == gcst->space_system || mem->space == avm_global ?
+ gcst->space_global : gcst->space_local);
+ for (;;) {
+ if (gcst->loc.memory != mem) { /* don't do twice */
+ gcst->loc.cp = 0;
+ if (chunk_locate(ptr, &gcst->loc))
+ return gcst->loc.cp;
+ }
+ if (gcst->loc.memory->saved == 0)
+ break;
+ gcst->loc.memory = &gcst->loc.memory->saved->state;
+ }
+
+ /* Restore locator to a legal state. */
+
+ gcst->loc.memory = mem;
+ gcst->loc.cp = 0;
+ return 0;
+}
+
+/* ================ Debugging ================ */
+
+#ifdef DEBUG
+
+/* Validate the contents of an allocator. */
+void
+ialloc_validate_spaces(const gs_dual_memory_t * dmem)
+{
+ int i;
+ gc_state_t state;
+ struct sm_ {
+ chunk_t cc;
+ uint rsize;
+ ref rlast;
+ } save[countof(dmem->spaces.indexed)];
+
+ state.spaces = dmem->spaces;
+ state.loc.memory = state.spaces.named.local;
+ state.loc.cp = 0;
+
+ /* Save everything we need to reset temporarily. */
+
+ for (i = 0; i < countof(save); i++)
+ if (dmem->spaces.indexed[i] != 0) {
+ gs_ref_memory_t *mem = dmem->spaces.indexed[i];
+ chunk_t *pcc = mem->pcc;
+ obj_header_t *rcur = mem->cc.rcur;
+
+ if (pcc != 0) {
+ save[i].cc = *pcc;
+ *pcc = mem->cc;
+ }
+ if (rcur != 0) {
+ save[i].rsize = rcur[-1].o_size;
+ rcur[-1].o_size = mem->cc.rtop - (byte *) rcur;
+ /* Create the final ref, reserved for the GC. */
+ save[i].rlast = ((ref *) mem->cc.rtop)[-1];
+ make_mark((ref *) mem->cc.rtop - 1);
+ }
+ }
+
+ /* Validate memory. */
+
+ for (i = 0; i < countof(save); i++)
+ if (dmem->spaces.indexed[i] != 0)
+ ialloc_validate_memory(dmem->spaces.indexed[i], &state);
+
+ /* Undo temporary changes. */
+
+ for (i = 0; i < countof(save); i++)
+ if (dmem->spaces.indexed[i] != 0) {
+ gs_ref_memory_t *mem = dmem->spaces.indexed[i];
+ chunk_t *pcc = mem->pcc;
+ obj_header_t *rcur = mem->cc.rcur;
+
+ if (rcur != 0) {
+ rcur[-1].o_size = save[i].rsize;
+ ((ref *) mem->cc.rtop)[-1] = save[i].rlast;
+ }
+ if (pcc != 0)
+ *pcc = save[i].cc;
+ }
+}
+void
+ialloc_validate_memory(const gs_ref_memory_t * mem, gc_state_t * gcst)
+{
+ const gs_ref_memory_t *smem;
+ int level;
+
+ for (smem = mem, level = 0; smem != 0;
+ smem = &smem->saved->state, --level
+ ) {
+ const chunk_t *cp;
+ int i;
+
+ if_debug3('6', "[6]validating memory 0x%lx, space %d, level %d\n",
+ (ulong) mem, mem->space, level);
+ /* Validate chunks. */
+ for (cp = smem->cfirst; cp != 0; cp = cp->cnext)
+ ialloc_validate_chunk(cp, gcst);
+ /* Validate freelists. */
+ for (i = 0; i < num_freelists; ++i) {
+ uint free_size = i << log2_obj_align_mod;
+ const obj_header_t *pfree;
+
+ for (pfree = mem->freelists[i]; pfree != 0;
+ pfree = *(const obj_header_t * const *)pfree
+ ) {
+ uint size = pfree[-1].o_size;
+
+ if (pfree[-1].o_type != &st_free) {
+ lprintf3("Non-free object 0x%lx(%u) on freelist %i!\n",
+ (ulong) pfree, size, i);
+ break;
+ }
+ if (size < free_size - obj_align_mask || size > free_size) {
+ lprintf3("Object 0x%lx(%u) size wrong on freelist %i!\n",
+ (ulong) pfree, size, i);
+ break;
+ }
+ }
+ }
+ };
+}
+
+/* Check the validity of an object's size. */
+inline private bool
+object_size_valid(const obj_header_t * pre, uint size, const chunk_t * cp)
+{
+ return (pre->o_large ? (const byte *)pre == cp->cbase :
+ size <= cp->ctop - (const byte *)(pre + 1));
+}
+
+/* Validate all the objects in a chunk. */
+private void ialloc_validate_ref(P2(const ref *, gc_state_t *));
+void
+ialloc_validate_chunk(const chunk_t * cp, gc_state_t * gcst)
+{
+ if_debug_chunk('6', "[6]validating chunk", cp);
+ SCAN_CHUNK_OBJECTS(cp);
+ DO_ALL
+ if (pre->o_type == &st_free) {
+ if (!object_size_valid(pre, size, cp))
+ lprintf3("Bad free object 0x%lx(%lu), in chunk 0x%lx!\n",
+ (ulong) (pre + 1), (ulong) size, (ulong) cp);
+ } else
+ ialloc_validate_object(pre + 1, cp, gcst);
+ if_debug3('7', " [7]validating %s(%lu) 0x%lx\n",
+ struct_type_name_string(pre->o_type),
+ (ulong) size, (ulong) pre);
+ if (pre->o_type == &st_refs) {
+ const ref_packed *rp = (const ref_packed *)(pre + 1);
+ const char *end = (const char *)rp + size;
+
+ while ((const char *)rp < end)
+ if (r_is_packed(rp)) {
+ ref unpacked;
+
+ packed_get(rp, &unpacked);
+ ialloc_validate_ref(&unpacked, gcst);
+ rp++;
+ } else {
+ ialloc_validate_ref((const ref *)rp, gcst);
+ rp += packed_per_ref;
+ }
+ } else {
+ struct_proc_enum_ptrs((*proc)) = pre->o_type->enum_ptrs;
+ uint index = 0;
+ const void *ptr;
+ gs_ptr_type_t ptype;
+
+ if (proc != gs_no_struct_enum_ptrs)
+ for (; (ptype = (*proc) (pre + 1, size, index, &ptr, pre->o_type, NULL)) != 0; ++index)
+ if (ptr == 0)
+ DO_NOTHING;
+ else if (ptype == ptr_struct_type)
+ ialloc_validate_object(ptr, NULL, gcst);
+ else if (ptype == ptr_ref_type)
+ ialloc_validate_ref(ptr, gcst);
+ }
+ END_OBJECTS_SCAN
+}
+/* Validate a ref. */
+private void
+ialloc_validate_ref(const ref * pref, gc_state_t * gcst)
+{
+ const void *optr;
+ const ref *rptr;
+ const char *tname;
+ uint size;
+
+ if (!gs_debug_c('?'))
+ return; /* no check */
+ if (r_space(pref) == avm_foreign)
+ return;
+ switch (r_type(pref)) {
+ case t_file:
+ optr = pref->value.pfile;
+ goto cks;
+ case t_device:
+ optr = pref->value.pdevice;
+ goto cks;
+ case t_fontID:
+ case t_struct:
+ case t_astruct:
+ optr = pref->value.pstruct;
+cks: if (optr != 0)
+ ialloc_validate_object(optr, NULL, gcst);
+ break;
+ case t_name:
+ if (name_index_ptr(r_size(pref)) != pref->value.pname) {
+ lprintf3("At 0x%lx, bad name %u, pname = 0x%lx\n",
+ (ulong) pref, (uint) r_size(pref),
+ (ulong) pref->value.pname);
+ break;
+ } {
+ ref sref;
+
+ name_string_ref(pref, &sref);
+ if (r_space(&sref) != avm_foreign &&
+ !gc_locate(sref.value.const_bytes, gcst)
+ ) {
+ lprintf4("At 0x%lx, bad name %u, pname = 0x%lx, string 0x%lx not in any chunk\n",
+ (ulong) pref, (uint) r_size(pref),
+ (ulong) pref->value.pname,
+ (ulong) sref.value.const_bytes);
+ }
+ }
+ break;
+ case t_string:
+ if (r_size(pref) != 0 && !gc_locate(pref->value.bytes, gcst))
+ lprintf3("At 0x%lx, string ptr 0x%lx[%u] not in any chunk\n",
+ (ulong) pref, (ulong) pref->value.bytes,
+ (uint) r_size(pref));
+ break;
+ case t_array:
+ if (r_size(pref) == 0)
+ break;
+ rptr = pref->value.refs;
+ size = r_size(pref);
+ tname = "array";
+cka: if (!gc_locate(rptr, gcst)) {
+ lprintf3("At 0x%lx, %s 0x%lx not in any chunk\n",
+ (ulong) pref, tname, (ulong) rptr);
+ break;
+ } {
+ uint i;
+
+ for (i = 0; i < size; ++i) {
+ const ref *elt = rptr + i;
+
+ if (r_is_packed(elt))
+ lprintf5("At 0x%lx, %s 0x%lx[%u] element %u is not a ref\n",
+ (ulong) pref, tname, (ulong) rptr, size, i);
+ }
+ }
+ break;
+ case t_shortarray:
+ case t_mixedarray:
+ if (r_size(pref) == 0)
+ break;
+ optr = pref->value.packed;
+ if (!gc_locate(optr, gcst))
+ lprintf2("At 0x%lx, packed array 0x%lx not in any chunk\n",
+ (ulong) pref, (ulong) optr);
+ break;
+ case t_dictionary:
+ {
+ const dict *pdict = pref->value.pdict;
+
+ if (!r_has_type(&pdict->values, t_array) ||
+ !r_is_array(&pdict->keys) ||
+ !r_has_type(&pdict->count, t_integer) ||
+ !r_has_type(&pdict->maxlength, t_integer)
+ )
+ lprintf2("At 0x%lx, invalid dict 0x%lx\n",
+ (ulong) pref, (ulong) pdict);
+ rptr = (const ref *)pdict;
+ }
+ size = sizeof(dict) / sizeof(ref);
+ tname = "dict";
+ goto cka;
+ }
+}
+
+/* Validate an object. */
+void
+ialloc_validate_object(const obj_header_t * ptr, const chunk_t * cp,
+ gc_state_t * gcst)
+{
+ const obj_header_t *pre = ptr - 1;
+ ulong size = pre_obj_contents_size(pre);
+ gs_memory_type_ptr_t otype = pre->o_type;
+ const char *oname;
+
+ if (!gs_debug_c('?'))
+ return; /* no check */
+ if (cp == 0 && gcst != 0) {
+ gc_state_t st;
+
+ st = *gcst; /* no side effects! */
+ if (!(cp = gc_locate(pre, &st))) {
+ lprintf1("Object 0x%lx not in any chunk!\n",
+ (ulong) ptr);
+ return; /*gs_abort(); */
+ }
+ }
+ if (otype == &st_free) {
+ lprintf3("Reference to free object 0x%lx(%lu), in chunk 0x%lx!\n",
+ (ulong) ptr, (ulong) size, (ulong) cp);
+ gs_abort();
+ }
+ if ((cp != 0 && !object_size_valid(pre, size, cp)) ||
+ otype->ssize == 0 ||
+ size % otype->ssize != 0 ||
+ (oname = struct_type_name_string(otype),
+ *oname < 33 || *oname > 126)
+ ) {
+ lprintf4("Bad object 0x%lx(%lu), ssize = %u, in chunk 0x%lx!\n",
+ (ulong) ptr, (ulong) size, otype->ssize, (ulong) cp);
+ gs_abort();
+ }
+}
+
+#else /* !DEBUG */
+
+void
+ialloc_validate_spaces(const gs_dual_memory_t * dmem)
+{
+}
+
+void
+ialloc_validate_memory(const gs_ref_memory_t * mem, gc_state_t * gcst)
+{
+}
+
+void
+ialloc_validate_chunk(const chunk_t * cp, gc_state_t * gcst)
+{
+}
+
+void
+ialloc_validate_object(const obj_header_t * ptr, const chunk_t * cp,
+ gc_state_t * gcst)
+{
+}
+
+#endif /* (!)DEBUG */
diff --git a/pstoraster/imain.c b/pstoraster/imain.c
new file mode 100644
index 000000000..642715643
--- /dev/null
+++ b/pstoraster/imain.c
@@ -0,0 +1,664 @@
+/* Copyright (C) 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$ */
+/* Common support for interpreter front ends */
+#include "memory_.h"
+#include "string_.h"
+/* Capture stdin/out/err before gs.h redefines them. */
+#include <stdio.h>
+void
+gs_get_real_stdio(FILE * stdfiles[3])
+{
+ stdfiles[0] = stdin;
+ stdfiles[1] = stdout;
+ stdfiles[2] = stderr;
+}
+#include "ghost.h"
+#include "gp.h"
+#include "gslib.h"
+#include "gsmatrix.h" /* for gxdevice.h */
+#include "gsutil.h" /* for bytes_compare */
+#include "gxdevice.h"
+#include "errors.h"
+#include "oper.h"
+#include "idebug.h"
+#include "idict.h"
+#include "iname.h" /* for name_init */
+#include "dstack.h"
+#include "estack.h"
+#include "ostack.h" /* put here for files.h */
+#include "stream.h" /* for files.h */
+#include "files.h"
+#include "ialloc.h"
+#include "strimpl.h" /* for sfilter.h */
+#include "sfilter.h" /* for iscan.h */
+#include "iscan.h"
+#include "main.h"
+#include "store.h"
+#include "isave.h" /* for prototypes */
+#include "interp.h"
+#include "ivmspace.h"
+
+/* ------ Exported data ------ */
+
+/* Define the default instance of the interpreter. */
+/* Currently, this is the *only possible* instance, because most of */
+/* the places that need to take an explicit instance argument don't. */
+private gs_main_instance the_gs_main_instance;
+gs_main_instance *
+gs_main_instance_default(void)
+{ /* Determine whether the instance has been initialized. */
+ if (the_gs_main_instance.memory_chunk_size == 0)
+ the_gs_main_instance = gs_main_instance_init_values;
+ return &the_gs_main_instance;
+}
+
+/* The only reason we export gs_exit_status is so that window systems */
+/* with alert boxes can know whether to pause before exiting if */
+/* the program terminates with an error. There must be a better way .... */
+int gs_exit_status;
+
+/* Define the interpreter's name table. We'll move it somewhere better */
+/* eventually.... */
+name_table *the_gs_name_table;
+
+/* ------ Imported data ------ */
+
+/* Configuration information imported from gconfig.c and iinit.c. */
+extern const char *gs_init_file;
+extern const byte gs_init_string[];
+extern const uint gs_init_string_sizeof;
+extern const ref gs_init_file_array[];
+extern const ref gs_emulator_name_array[];
+
+/* ------ Forward references ------ */
+
+private int gs_run_init_file(P3(gs_main_instance *, int *, ref *));
+private void print_resource_usage(P3(const gs_main_instance *,
+ gs_dual_memory_t *,
+ const char *));
+
+/* ------ Initialization ------ */
+
+/* A handy way to declare and execute an initialization procedure: */
+#define call_init(proc)\
+BEGIN extern void proc(P0()); proc(); END
+
+/* Initialization to be done before anything else. */
+void
+gs_main_init0(gs_main_instance * minst, FILE * in, FILE * out, FILE * err,
+ int max_lib_paths)
+{
+ gs_memory_t *heap;
+
+ /* Set our versions of stdin/out/err. */
+ gs_stdin = minst->fstdin = in;
+ gs_stdout = minst->fstdout = out;
+ gs_stderr = minst->fstderr = err;
+ /* Do platform-dependent initialization. */
+ /* We have to do this as the very first thing, */
+ /* because it detects attempts to run 80N86 executables (N>0) */
+ /* on incompatible processors. */
+ gp_init();
+ gp_get_usertime(minst->base_time);
+ /* Initialize the imager. */
+ heap = gs_lib_init0(gs_stdout);
+ minst->heap = heap;
+ /* Initialize the file search paths. */
+ make_array(&minst->lib_path.container, avm_foreign, max_lib_paths,
+ (ref *) gs_alloc_byte_array(heap, max_lib_paths, sizeof(ref),
+ "lib_path array"));
+ make_array(&minst->lib_path.list, avm_foreign | a_readonly, 0,
+ minst->lib_path.container.value.refs);
+ minst->lib_path.env = 0;
+ minst->lib_path.final = 0;
+ minst->lib_path.count = 0;
+ minst->user_errors = 1;
+ minst->init_done = 0;
+}
+
+/* Initialization to be done before constructing any objects. */
+void
+gs_main_init1(gs_main_instance * minst)
+{
+ if (minst->init_done < 1) {
+ {
+ extern bool gs_have_level2(P0());
+
+ ialloc_init((gs_raw_memory_t *) & gs_memory_default,
+ minst->memory_chunk_size,
+ gs_have_level2());
+ gs_lib_init1((gs_memory_t *) imemory_system);
+ alloc_save_init(idmemory);
+ }
+ {
+ gs_memory_t *mem = imemory_system;
+ name_table *nt = names_init(minst->name_table_size, mem);
+
+ if (nt == 0) {
+ puts("name_init failed");
+ gs_exit(1);
+ }
+ the_gs_name_table = nt;
+ gs_register_struct_root(mem, NULL, (void **)&the_gs_name_table,
+ "the_gs_name_table");
+ }
+ call_init(obj_init); /* requires name_init */
+ minst->init_done = 1;
+ }
+}
+
+/* Initialization to be done before running any files. */
+private void
+init2_make_string_array(const ref * srefs, const char *aname)
+{
+ const ref *ifp = srefs;
+ ref ifa;
+
+ for (; ifp->value.bytes != 0; ifp++);
+ make_tasv(&ifa, t_array, a_readonly | avm_foreign,
+ ifp - srefs, const_refs, srefs);
+ initial_enter_name(aname, &ifa);
+}
+void
+gs_main_init2(gs_main_instance * minst)
+{
+ gs_main_init1(minst);
+ if (minst->init_done < 2) {
+ int code, exit_code;
+ ref error_object;
+
+ call_init(igs_init);
+ call_init(zop_init);
+ {
+ extern void gs_iodev_init(P1(gs_memory_t *));
+
+ gs_iodev_init(imemory);
+ }
+ call_init(op_init); /* requires obj_init */
+
+ /* Set up the array of additional initialization files. */
+ init2_make_string_array(gs_init_file_array, "INITFILES");
+ /* Set up the array of emulator names. */
+ init2_make_string_array(gs_emulator_name_array, "EMULATORS");
+ /* Pass the search path. */
+ initial_enter_name("LIBPATH", &minst->lib_path.list);
+
+ /* Execute the standard initialization file. */
+ code = gs_run_init_file(minst, &exit_code, &error_object);
+ if (code < 0) {
+ if (code != e_Fatal)
+ gs_debug_dump_stack(code, &error_object);
+ gs_exit_with_code((exit_code ? exit_code : 2), code);
+ }
+ minst->init_done = 2;
+ }
+ if (gs_debug_c(':'))
+ print_resource_usage(minst, &gs_imemory, "Start");
+}
+
+/* ------ Search paths ------ */
+
+/* Internal routine to add a set of directories to a search list. */
+/* Returns 0 or an error code. */
+private int
+file_path_add(gs_file_path * pfp, const char *dirs)
+{
+ uint len = r_size(&pfp->list);
+ const char *dpath = dirs;
+
+ if (dirs == 0)
+ return 0;
+ for (;;) { /* Find the end of the next directory name. */
+ const char *npath = dpath;
+
+ while (*npath != 0 && *npath != gp_file_name_list_separator)
+ npath++;
+ if (npath > dpath) {
+ if (len == r_size(&pfp->container))
+ return_error(e_limitcheck);
+ make_const_string(&pfp->container.value.refs[len],
+ avm_foreign | a_readonly,
+ npath - dpath, (const byte *)dpath);
+ ++len;
+ }
+ if (!*npath)
+ break;
+ dpath = npath + 1;
+ }
+ r_set_size(&pfp->list, len);
+ return 0;
+}
+
+/* Add a library search path to the list. */
+void
+gs_main_add_lib_path(gs_main_instance * minst, const char *lpath)
+{ /* Account for the possibility that the first element */
+ /* is gp_current_directory name added by set_lib_paths. */
+ int first_is_here =
+ (r_size(&minst->lib_path.list) != 0 &&
+ minst->lib_path.container.value.refs[0].value.bytes ==
+ (const byte *)gp_current_directory_name ? 1 : 0);
+
+ r_set_size(&minst->lib_path.list, minst->lib_path.count +
+ first_is_here);
+ file_path_add(&minst->lib_path, lpath);
+ minst->lib_path.count = r_size(&minst->lib_path.list) - first_is_here;
+ gs_main_set_lib_paths(minst);
+}
+
+/* ------ Execution ------ */
+
+/* Complete the list of library search paths. */
+/* This may involve adding or removing the current directory */
+/* as the first element. */
+void
+gs_main_set_lib_paths(gs_main_instance * minst)
+{
+ ref *paths = minst->lib_path.container.value.refs;
+ int first_is_here =
+ (r_size(&minst->lib_path.list) != 0 &&
+ paths[0].value.bytes == (const byte *)gp_current_directory_name ? 1 : 0);
+ int count = minst->lib_path.count;
+
+ if (minst->search_here_first) {
+ if (!(first_is_here ||
+ (r_size(&minst->lib_path.list) != 0 &&
+ !bytes_compare((const byte *)gp_current_directory_name,
+ strlen(gp_current_directory_name),
+ paths[0].value.bytes,
+ r_size(&paths[0]))))
+ ) {
+ memmove(paths + 1, paths, count * sizeof(*paths));
+ make_const_string(paths, avm_foreign | a_readonly,
+ strlen(gp_current_directory_name),
+ (const byte *)gp_current_directory_name);
+ }
+ } else {
+ if (first_is_here)
+ memmove(paths, paths + 1, count * sizeof(*paths));
+ }
+ r_set_size(&minst->lib_path.list,
+ count + (minst->search_here_first ? 1 : 0));
+ if (minst->lib_path.env != 0)
+ file_path_add(&minst->lib_path, minst->lib_path.env);
+ if (minst->lib_path.final != 0)
+ file_path_add(&minst->lib_path, minst->lib_path.final);
+}
+
+/* Open a file, using the search paths. */
+int
+gs_main_lib_open(gs_main_instance * minst, const char *file_name, ref * pfile)
+{ /* This is a separate procedure only to avoid tying up */
+ /* extra stack space while running the file. */
+#define maxfn 200
+ byte fn[maxfn];
+ uint len;
+
+ return lib_file_open(file_name, strlen(file_name), fn, maxfn,
+ &len, pfile);
+}
+
+/* Open and execute a file. */
+int
+gs_main_run_file(gs_main_instance * minst, const char *file_name, int user_errors, int *pexit_code, ref * perror_object)
+{
+ ref initial_file;
+ int code = gs_main_run_file_open(minst, file_name, &initial_file);
+
+ if (code < 0)
+ return code;
+ return gs_interpret(&initial_file, user_errors, pexit_code, perror_object);
+}
+int
+gs_main_run_file_open(gs_main_instance * minst, const char *file_name, ref * pfref)
+{
+ gs_main_set_lib_paths(minst);
+ if (gs_main_lib_open(minst, file_name, pfref) < 0) {
+ eprintf1("Can't find initialization file %s.\n", file_name);
+ return_error(e_Fatal);
+ }
+ r_set_attrs(pfref, a_execute + a_executable);
+ return 0;
+}
+
+/* Open and run the very first initialization file. */
+private int
+gs_run_init_file(gs_main_instance * minst, int *pexit_code, ref * perror_object)
+{
+ ref ifile;
+ ref first_token;
+ int code;
+ scanner_state state;
+
+ gs_main_set_lib_paths(minst);
+ if (gs_init_string_sizeof == 0) { /* Read from gs_init_file. */
+ code = gs_main_run_file_open(minst, gs_init_file, &ifile);
+ } else { /* Read from gs_init_string. */
+ code = file_read_string(gs_init_string, gs_init_string_sizeof,
+ &ifile);
+ }
+ if (code < 0) {
+ *pexit_code = 255;
+ return code;
+ }
+ /* Check to make sure the first token is an integer */
+ /* (for the version number check.) */
+ scanner_state_init(&state, false);
+ code = scan_token(ifile.value.pfile, &first_token, &state);
+ if (code != 0 || !r_has_type(&first_token, t_integer)) {
+ eprintf1("Initialization file %s does not begin with an integer.\n", gs_init_file);
+ *pexit_code = 255;
+ return_error(e_Fatal);
+ }
+ *++osp = first_token;
+ r_set_attrs(&ifile, a_executable);
+ return gs_interpret(&ifile, minst->user_errors,
+ pexit_code, perror_object);
+}
+
+/* Run a string. */
+int
+gs_main_run_string(gs_main_instance * minst, const char *str, int user_errors,
+ int *pexit_code, ref * perror_object)
+{
+ return gs_main_run_string_with_length(minst, str, (uint) strlen(str),
+ user_errors,
+ pexit_code, perror_object);
+}
+int
+gs_main_run_string_with_length(gs_main_instance * minst, const char *str,
+ uint length, int user_errors, int *pexit_code, ref * perror_object)
+{
+ int code;
+
+ code = gs_main_run_string_begin(minst, user_errors,
+ pexit_code, perror_object);
+ if (code < 0)
+ return code;
+ code = gs_main_run_string_continue(minst, str, length, user_errors,
+ pexit_code, perror_object);
+ if (code != e_NeedInput)
+ return code;
+ return gs_main_run_string_end(minst, user_errors,
+ pexit_code, perror_object);
+}
+
+/* Set up for a suspendable run_string. */
+int
+gs_main_run_string_begin(gs_main_instance * minst, int user_errors,
+ int *pexit_code, ref * perror_object)
+{
+ const char *setup = ".runstringbegin";
+ ref rstr;
+ int code;
+
+ gs_main_set_lib_paths(minst);
+ make_const_string(&rstr, avm_foreign | a_readonly | a_executable,
+ strlen(setup), (const byte *)setup);
+ code = gs_interpret(&rstr, user_errors, pexit_code, perror_object);
+ return (code == e_NeedInput ? 0 : code == 0 ? e_Fatal : code);
+}
+/* Continue running a string with the option of suspending. */
+int
+gs_main_run_string_continue(gs_main_instance * minst, const char *str,
+ uint length, int user_errors, int *pexit_code, ref * perror_object)
+{
+ ref rstr;
+
+ if (length == 0)
+ return 0; /* empty string signals EOF */
+ make_const_string(&rstr, avm_foreign | a_readonly, length,
+ (const byte *)str);
+ return gs_interpret(&rstr, user_errors, pexit_code, perror_object);
+}
+/* Signal EOF when suspended. */
+int
+gs_main_run_string_end(gs_main_instance * minst, int user_errors,
+ int *pexit_code, ref * perror_object)
+{
+ ref rstr;
+
+ make_empty_const_string(&rstr, avm_foreign | a_readonly);
+ return gs_interpret(&rstr, user_errors, pexit_code, perror_object);
+}
+
+/* ------ Operand stack access ------ */
+
+/* These are built for comfort, not for speed. */
+
+private int
+push_value(ref * pvalue)
+{
+ int code = ref_stack_push(&o_stack, 1);
+
+ if (code < 0)
+ return code;
+ *ref_stack_index(&o_stack, 0L) = *pvalue;
+ return 0;
+}
+
+int
+gs_push_boolean(gs_main_instance * minst, bool value)
+{
+ ref vref;
+
+ make_bool(&vref, value);
+ return push_value(&vref);
+}
+
+int
+gs_push_integer(gs_main_instance * minst, long value)
+{
+ ref vref;
+
+ make_int(&vref, value);
+ return push_value(&vref);
+}
+
+int
+gs_push_real(gs_main_instance * minst, floatp value)
+{
+ ref vref;
+
+ make_real(&vref, value);
+ return push_value(&vref);
+}
+
+int
+gs_push_string(gs_main_instance * minst, byte * chars, uint length,
+ bool read_only)
+{
+ ref vref;
+
+ make_string(&vref, avm_foreign | (read_only ? a_readonly : a_all),
+ length, (byte *) chars);
+ return push_value(&vref);
+}
+
+private int
+pop_value(ref * pvalue)
+{
+ if (!ref_stack_count(&o_stack))
+ return_error(e_stackunderflow);
+ *pvalue = *ref_stack_index(&o_stack, 0L);
+ return 0;
+}
+
+int
+gs_pop_boolean(gs_main_instance * minst, bool * result)
+{
+ ref vref;
+ int code = pop_value(&vref);
+
+ if (code < 0)
+ return code;
+ check_type_only(vref, t_boolean);
+ *result = vref.value.boolval;
+ ref_stack_pop(&o_stack, 1);
+ return 0;
+}
+
+int
+gs_pop_integer(gs_main_instance * minst, long *result)
+{
+ ref vref;
+ int code = pop_value(&vref);
+
+ if (code < 0)
+ return code;
+ check_type_only(vref, t_integer);
+ *result = vref.value.intval;
+ ref_stack_pop(&o_stack, 1);
+ return 0;
+}
+
+int
+gs_pop_real(gs_main_instance * minst, float *result)
+{
+ ref vref;
+ int code = pop_value(&vref);
+
+ if (code < 0)
+ return code;
+ switch (r_type(&vref)) {
+ case t_real:
+ *result = vref.value.realval;
+ break;
+ case t_integer:
+ *result = vref.value.intval;
+ break;
+ default:
+ return_error(e_typecheck);
+ }
+ ref_stack_pop(&o_stack, 1);
+ return 0;
+}
+
+int
+gs_pop_string(gs_main_instance * minst, gs_string * result)
+{
+ ref vref;
+ int code = pop_value(&vref);
+
+ if (code < 0)
+ return code;
+ switch (r_type(&vref)) {
+ case t_name:
+ name_string_ref(&vref, &vref);
+ code = 1;
+ goto rstr;
+ case t_string:
+ code = (r_has_attr(&vref, a_write) ? 0 : 1);
+ rstr:result->data = vref.value.bytes;
+ result->size = r_size(&vref);
+ break;
+ default:
+ return_error(e_typecheck);
+ }
+ ref_stack_pop(&o_stack, 1);
+ return code;
+}
+
+/* ------ Termination ------ */
+
+/* Free all resources and exit. */
+void
+gs_main_finit(gs_main_instance * minst, int exit_status, int code)
+{ /*
+ * Previous versions of this code closed the devices in the
+ * device list here. Since these devices are now prototypes,
+ * they cannot be opened, so they do not need to be closed;
+ * alloc_restore_all will close dynamically allocated devices.
+ */
+ gs_exit_status = exit_status; /* see above */
+
+ if (gs_debug_c(':'))
+ print_resource_usage(minst, &gs_imemory, "Final");
+ /* Do the equivalent of a restore "past the bottom". */
+ /* This will release all memory, close all open files, etc. */
+ if (minst->init_done >= 1)
+ alloc_restore_all(idmemory);
+ gs_lib_finit(exit_status, code);
+}
+void
+gs_exit_with_code(int exit_status, int code)
+{
+ gs_finit(exit_status, code);
+ gp_do_exit(exit_status);
+}
+void
+gs_exit(int exit_status)
+{
+ gs_exit_with_code(exit_status, 0);
+}
+
+/* ------ Debugging ------ */
+
+/* Print resource usage statistics. */
+private void
+print_resource_usage(const gs_main_instance * minst, gs_dual_memory_t * dmem,
+ const char *msg)
+{
+ ulong allocated = 0, used = 0;
+ long utime[2];
+
+ gp_get_usertime(utime);
+ {
+ int i;
+
+ for (i = 0; i < countof(dmem->spaces.indexed); ++i) {
+ gs_ref_memory_t *mem = dmem->spaces.indexed[i];
+
+ if (mem != 0 && (i == 0 || mem != dmem->spaces.indexed[i - 1])) {
+ gs_memory_status_t status;
+
+ gs_memory_status((gs_memory_t *) mem, &status);
+ allocated += status.allocated;
+ used += status.used;
+ }
+ }
+ }
+ dprintf4("%% %s time = %g, memory allocated = %lu, used = %lu\n",
+ msg, utime[0] - minst->base_time[0] +
+ (utime[1] - minst->base_time[1]) / 1000000000.0,
+ allocated, used);
+}
+
+/* Dump the stacks after interpretation */
+void
+gs_debug_dump_stack(int code, ref * perror_object)
+{
+ zflush(osp); /* force out buffered output */
+ dprintf1("\nUnexpected interpreter error %d.\n", code);
+ if (perror_object != 0) {
+ dputs("Error object: ");
+ debug_print_ref(perror_object);
+ dputc('\n');
+ }
+ debug_dump_stack(&o_stack, "Operand stack");
+ debug_dump_stack(&e_stack, "Execution stack");
+ debug_dump_stack(&d_stack, "Dictionary stack");
+}
diff --git a/pstoraster/imain.h b/pstoraster/imain.h
new file mode 100644
index 000000000..fb1eac51d
--- /dev/null
+++ b/pstoraster/imain.h
@@ -0,0 +1,276 @@
+/* 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$ */
+/* Interface to imain.c */
+/* Requires <stdio.h>, stdpre.h, gsmemory.h, gstypes.h, iref.h */
+
+#ifndef imain_INCLUDED
+# define imain_INCLUDED
+
+#include "gsexit.h" /* exported by imain.c */
+
+/*
+ * This file defines the intended API between client front ends
+ * (such as imainarg.c, the command-line-driven front end)
+ * and imain.c, which provides top-level control of the interpreter.
+ */
+
+/* ================ Types ================ */
+
+/*
+ * Currently, the interpreter has a lot of static variables, but
+ * eventually it will have none, so that clients will be able to make
+ * multiple instances of it. In anticipation of this, many of the
+ * top-level API calls take an interpreter instance (gs_main_instance *)
+ * as their first argument.
+ */
+#ifndef gs_main_instance_DEFINED
+# define gs_main_instance_DEFINED
+typedef struct gs_main_instance_s gs_main_instance;
+
+#endif
+
+/* ================ Exported procedures from imain.c ================ */
+
+/* ---------------- Instance creation ---------------- */
+
+/*
+ * As noted above, multiple instances are not supported yet:
+ */
+/*gs_main_instance *gs_main_alloc_instance(P1(gs_memory_t *)); */
+/*
+ * Instead, we provide only a default instance:
+ */
+gs_main_instance *gs_main_instance_default(P0());
+
+/* ---------------- Initialization ---------------- */
+
+/*
+ * The interpreter requires three initialization steps, called init0,
+ * init1, and init2. These steps must be done in that order, but
+ * init1 may be omitted.
+ */
+
+/*
+ * Since gsio.h (which is included in many other header files)
+ * redefines stdin/out/err, callers need a way to get the "real"
+ * stdio files to pass to init0 if they wish to do so.
+ */
+void gs_get_real_stdio(P1(FILE * stdfiles[3]));
+
+/*
+ * init0 records the files to be used for stdio, and initializes the
+ * graphics library, the file search paths, and other instance data.
+ */
+void gs_main_init0(P5(gs_main_instance * minst, FILE * in, FILE * out, FILE * err,
+ int max_lib_paths));
+
+/*
+ * init1 initializes the memory manager and other internal data
+ * structures such as the name table, the token scanner tables,
+ * dictionaries such as systemdict, and the interpreter stacks.
+ */
+void gs_main_init1(P1(gs_main_instance * minst));
+
+/*
+ * init2 finishes preparing the interpreter for use by running
+ * initialization files with PostScript procedure definitions.
+ */
+void gs_main_init2(P1(gs_main_instance * minst));
+
+/*
+ * The runlibfile operator uses a search path, as described in
+ * use.doc, for looking up file names. Each interpreter instance has
+ * its own search path. The following call adds a directory or set of
+ * directories to the search path; it is equivalent to the -I command
+ * line switch. It may be called any time after init0.
+ */
+void gs_main_add_lib_path(P2(gs_main_instance * minst, const char *path));
+
+/*
+ * Under certain internal conditions, the search path may temporarily
+ * be in an inconsistent state; gs_main_set_lib_paths takes care of
+ * this. Clients should never need to call this procedure, and
+ * eventually it may be removed.
+ */
+void gs_main_set_lib_paths(P1(gs_main_instance * minst));
+
+/*
+ * Open a PostScript file using the search path. Clients should
+ * never need to call this procedure, since gs_main_run_file opens the
+ * file itself, and eventually the procedure may be removed.
+ */
+int gs_main_lib_open(P3(gs_main_instance * minst, const char *fname,
+ ref * pfile));
+
+/*
+ * Here we summarize the C API calls that correspond to some of the
+ * most common command line switches documented in use.doc, to help
+ * clients who are familiar with the command line and are starting to
+ * use the API.
+ *
+ * -d/D, -s/S (for setting device parameters like OutputFile)
+ * Use the C API for device parameters documented near the
+ * end of gsparam.h.
+ *
+ * -d/D (for setting Boolean parameters like NOPAUSE)
+ * { ref vtrue;
+ * make_true(&vtrue);
+ * dict_put_string(systemdict, "NOPAUSE", &vtrue);
+ * }
+ * -I
+ * Use gs_main_add_lib_path, documented above.
+ *
+ * -A, -A-
+ * Set gs_debug['@'] = 1 or 0 respectively.
+ * -E, -E-
+ * Set gs_debug['#'] = 1 or 0 respectively.
+ * -Z..., -Z-...
+ * Set gs_debug[c] = 1 or 0 respectively for each character
+ * c in the string.
+ */
+
+/* ---------------- Execution ---------------- */
+
+/*
+ * After initializing the interpreter, clients may pass it files or
+ * strings to be interpreted. There are four ways to do this:
+ * - Pass a file name (gs_main_run_file);
+ * - Pass a C string (gs_main_run_string);
+ * - Pass a string defined by pointer and length
+ * (gs_main_run_string_with_length);
+ * - Pass strings piece-by-piece
+ * (gs_main_run_string_begin/continue/end).
+ *
+ * The value returned by the first three of these calls is
+ * 0 if the interpreter ran to completion, e_Quit for a normal quit,
+ * or e_Fatal for a non-zero quit or a fatal error.
+ * e_Fatal stores the exit code in the third argument.
+ * The str argument of gs_main_run_string[_with_length] must be allocated
+ * in non-garbage-collectable space (e.g., by malloc or gs_malloc,
+ * or statically).
+ */
+int gs_main_run_file(P5(gs_main_instance * minst,
+ const char *fname,
+ int user_errors, int *pexit_code,
+ ref * perror_object));
+int gs_main_run_string(P5(gs_main_instance * minst,
+ const char *str,
+ int user_errors, int *pexit_code,
+ ref * perror_object));
+int gs_main_run_string_with_length(P6(gs_main_instance * minst,
+ const char *str, uint length,
+ int user_errors, int *pexit_code,
+ ref * perror_object));
+
+/*
+ * Open the file for gs_main_run_file. This is an internal routine
+ * that is only exported for some special clients.
+ */
+int gs_main_run_file_open(P3(gs_main_instance * minst,
+ const char *file_name, ref * pfref));
+
+/*
+ * The next 3 procedures provide for feeding input to the interpreter
+ * in arbitrary chunks, unlike run_string, which requires that each string
+ * be a properly formed PostScript program fragment. To use them:
+ * Call run_string_begin.
+ * Call run_string_continue as many times as desired,
+ * stopping if it returns anything other than e_NeedInput.
+ * If run_string_continue didn't indicate an error or a quit
+ * (i.e., a return value other than e_NeedInput), call run_string_end
+ * to provide an EOF indication.
+ * Note that run_string_continue takes a pointer and a length, like
+ * run_string_with_length.
+ */
+int gs_main_run_string_begin(P4(gs_main_instance * minst, int user_errors,
+ int *pexit_code, ref * perror_object));
+int gs_main_run_string_continue(P6(gs_main_instance * minst,
+ const char *str, uint length,
+ int user_errors, int *pexit_code,
+ ref * perror_object));
+int gs_main_run_string_end(P4(gs_main_instance * minst, int user_errors,
+ int *pexit_code, ref * perror_object));
+
+/* ---------------- Operand stack access ---------------- */
+
+/*
+ * The following procedures are not used in normal operation;
+ * they exist only to allow clients driving the interpreter through the
+ * gs_main_run_xxx procedures to push parameters quickly and to get results
+ * back. The push procedures return 0, e_stackoverflow, or e_VMerror;
+ * the pop procedures return 0, e_stackunderflow, or e_typecheck.
+ *
+ * Procedures to push values on the operand stack:
+ */
+int gs_push_boolean(P2(gs_main_instance * minst, bool value));
+int gs_push_integer(P2(gs_main_instance * minst, long value));
+int gs_push_real(P2(gs_main_instance * minst, floatp value));
+int gs_push_string(P4(gs_main_instance * minst, byte * chars, uint length,
+ bool read_only));
+
+/*
+ * Procedures to pop values from the operand stack:
+ */
+int gs_pop_boolean(P2(gs_main_instance * minst, bool * result));
+int gs_pop_integer(P2(gs_main_instance * minst, long *result));
+int gs_pop_real(P2(gs_main_instance * minst, float *result));
+
+/* gs_pop_string returns 1 if the string is read-only. */
+int gs_pop_string(P2(gs_main_instance * minst, gs_string * result));
+
+/* ---------------- Debugging ---------------- */
+
+/*
+ * Print an error mesage including the error code, error object (if any),
+ * and operand and execution stacks in hex. Clients will probably
+ * never call this.
+ */
+void gs_debug_dump_stack(P2(int code, ref * perror_object));
+
+/* ---------------- Termination ---------------- */
+
+/*
+ * Terminate the interpreter by closing all devices and releasing all
+ * allocated memory. Currently, because of some technical problems
+ * with statically initialized data, it is not possible to reinitialize
+ * the interpreter after terminating it; we plan to fix this as soon as
+ * possible.
+ *
+ * Note that calling gs_exit (defined in gsexit.h) automatically calls
+ * gs_main_finit for the default instance.
+ */
+void gs_main_finit(P3(gs_main_instance * minst, int exit_status, int code));
+
+/* ================ Other exported procedures ================ */
+
+/*
+ * Define an internal interface to the interpreter. Clients do not
+ * normally use this.
+ */
+int gs_interpret(P4(ref * pref, int user_errors, int *pexit_code,
+ ref * perror_object));
+
+#endif /* imain_INCLUDED */
diff --git a/pstoraster/imainarg.c b/pstoraster/imainarg.c
new file mode 100644
index 000000000..dd1e02939
--- /dev/null
+++ b/pstoraster/imainarg.c
@@ -0,0 +1,849 @@
+/* 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$ */
+/* Command line parsing and dispatching */
+#include "ctype_.h"
+#include "memory_.h"
+#include "string_.h"
+#include "ghost.h"
+#include "gp.h"
+#include "gsargs.h"
+#include "gscdefs.h"
+#include "gsmalloc.h" /* for gs_malloc_limit */
+#include "gsmdebug.h"
+#include "gxdevice.h"
+#include "gxdevmem.h"
+#include "gsdevice.h"
+#include "stream.h"
+#include "errors.h"
+#include "estack.h"
+#include "ialloc.h"
+#include "strimpl.h" /* for sfilter.h */
+#include "sfilter.h" /* for iscan.h */
+#include "ostack.h" /* must precede iscan.h */
+#include "iscan.h"
+#include "imain.h"
+#include "imainarg.h"
+#include "iminst.h"
+#include "iname.h"
+#include "store.h"
+#include "files.h" /* requires stream.h */
+#include "interp.h"
+#include "iutil.h"
+#include "ivmspace.h"
+
+/* Import operator procedures */
+extern int zflush(P1(os_ptr));
+extern int zflushpage(P1(os_ptr));
+
+#ifndef GS_LIB
+# define GS_LIB "GS_LIB"
+#endif
+
+#ifndef GS_OPTIONS
+# define GS_OPTIONS "GS_OPTIONS"
+#endif
+
+#ifndef GS_MAX_LIB_DIRS
+# define GS_MAX_LIB_DIRS 25
+#endif
+
+#ifndef GS_BUG_MAILBOX
+# define GS_BUG_MAILBOX "ghost@aladdin.com"
+#endif
+
+#define MAX_BUFFERED_SIZE 1024
+
+/* Note: sscanf incorrectly defines its first argument as char * */
+/* rather than const char *. This accounts for the ugly casts below. */
+
+/* Redefine puts to use fprintf, so it will work even without stdio. */
+#undef puts
+private void
+fpputs(const char *str)
+{
+ fprintf(stderr, "%s\n", str);
+}
+#define puts(str) fpputs(str)
+
+/* Other imported data */
+extern const char *const gs_doc_directory;
+extern const char *const gs_lib_default_path;
+extern const ref gs_emulator_name_array[];
+
+/* Forward references */
+#define runInit 1
+#define runFlush 2
+#define runBuffer 4
+private int swproc(P3(gs_main_instance *, const char *, arg_list *));
+private void argproc(P2(gs_main_instance *, const char *));
+private void run_buffered(P2(gs_main_instance *, const char *));
+private int esc_strlen(P1(const char *));
+private void esc_strcat(P2(char *, const char *));
+private void runarg(P5(gs_main_instance *, const char *, const char *, const char *, int));
+private void run_string(P3(gs_main_instance *, const char *, int));
+private void run_finish(P3(int, int, ref *));
+
+/* Forward references for help printout */
+private void print_help(P1(gs_main_instance *));
+private void print_revision(P0());
+private void print_version(P0());
+private void print_usage(P0());
+private void print_devices(P0());
+private void print_emulators(P0());
+private void print_paths(P1(gs_main_instance *));
+private void print_help_trailer(P0());
+
+/* ------ Main program ------ */
+
+/* Process the command line with a given instance. */
+private FILE *
+gs_main_arg_fopen(const char *fname, void *vminst)
+{
+ gs_main_set_lib_paths((gs_main_instance *) vminst);
+ return lib_fopen(fname);
+}
+#define arg_heap_copy(str) arg_copy(str, &gs_memory_default)
+int
+gs_main_init_with_args(gs_main_instance * minst, int argc, char *argv[])
+{
+ const char *arg;
+ arg_list args;
+ FILE *stdfiles[3];
+
+ gs_get_real_stdio(stdfiles);
+ arg_init(&args, (const char **)argv, argc,
+ gs_main_arg_fopen, (void *)minst);
+ gs_main_init0(minst, stdfiles[0], stdfiles[1], stdfiles[2],
+ GS_MAX_LIB_DIRS);
+ {
+ int len = 0;
+ int code = gp_getenv(GS_LIB, (char *)0, &len);
+
+ if (code < 0) { /* key present, value doesn't fit */
+ char *path = (char *)gs_alloc_bytes(minst->heap, len, "GS_LIB");
+
+ gp_getenv(GS_LIB, path, &len); /* can't fail */
+ minst->lib_path.env = path;
+ }
+ }
+ minst->lib_path.final = gs_lib_default_path;
+ gs_main_set_lib_paths(minst);
+ /* Prescan the command line for --help and --version. */
+ {
+ int i;
+ bool helping = false;
+
+ for (i = 1; i < argc; ++i)
+ if (!strcmp(argv[i], "--")) { /* A PostScript program will be interpreting all the */
+ /* remaining switches, so stop scanning. */
+ helping = false;
+ break;
+ } else if (!strcmp(argv[i], "--help")) {
+ print_help(minst);
+ helping = true;
+ } else if (!strcmp(argv[i], "--version")) {
+ print_version();
+ puts(""); /* \n */
+ helping = true;
+ }
+ if (helping)
+ gs_exit(gs_exit_INFO);
+ }
+ /* Execute files named in the command line, */
+ /* processing options along the way. */
+ /* Wait until the first file name (or the end */
+ /* of the line) to finish initialization. */
+ minst->run_start = true;
+
+ {
+ int len = 0;
+ int code = gp_getenv(GS_OPTIONS, (char *)0, &len);
+
+ if (code < 0) { /* key present, value doesn't fit */
+ char *opts =
+ (char *)gs_alloc_bytes(minst->heap, len, "GS_OPTIONS");
+
+ gp_getenv(GS_OPTIONS, opts, &len); /* can't fail */
+ arg_push_memory_string(&args, opts, minst->heap);
+ }
+ }
+ while ((arg = arg_next(&args)) != 0) {
+ switch (*arg) {
+ case '-':
+ if (swproc(minst, arg, &args) < 0)
+ fprintf(stderr,
+ "Unknown switch %s - ignoring\n", arg);
+ break;
+ default:
+ argproc(minst, arg);
+ }
+ }
+
+ gs_main_init2(minst);
+
+ return 0;
+}
+
+/* Run the 'start' procedure (after processing the command line). */
+/* Note that this procedure exits rather than returning. */
+void
+gs_main_run_start(gs_main_instance * minst)
+{
+ run_string(minst, "systemdict /start get exec", runFlush);
+}
+
+/* Process switches */
+private int
+swproc(gs_main_instance * minst, const char *arg, arg_list * pal)
+{
+ char sw = arg[1];
+ ref vtrue;
+
+ make_true(&vtrue);
+ arg += 2; /* skip - and letter */
+ switch (sw) {
+ default:
+ return -1;
+ case 0: /* read stdin as a file */
+ minst->run_start = false; /* don't run 'start' */
+ /* Set NOPAUSE so showpage won't try to read from stdin. */
+ swproc(minst, "-dNOPAUSE", pal);
+ gs_main_init2(minst); /* Finish initialization */
+ /* We delete this only to make Ghostview work properly. */
+/**************** This is WRONG. ****************/
+ /*gs_stdin_is_interactive = false; */
+ run_string(minst, ".runstdin", runFlush);
+ break;
+ case '-': /* run with command line args */
+ case '+':
+ pal->expand_ats = false;
+ case '@': /* ditto with @-expansion */
+ {
+ const char *psarg = arg_next(pal);
+
+ if (psarg == 0) {
+ fprintf(stderr, "Usage: gs ... -%c file.ps arg1 ... argn\n", sw);
+ arg_finit(pal);
+ gs_exit(1);
+ }
+ psarg = arg_heap_copy(psarg);
+ gs_main_init2(minst);
+ run_string(minst, "userdict/ARGUMENTS[", 0);
+ while ((arg = arg_next(pal)) != 0)
+ runarg(minst, "", arg_heap_copy(arg), "", runInit);
+ runarg(minst, "]put", psarg, ".runfile", runInit | runFlush);
+ gs_exit(0);
+ }
+ case 'A': /* trace allocator */
+ switch (*arg) {
+ case 0:
+ gs_alloc_debug = 1;
+ break;
+ case '-':
+ gs_alloc_debug = 0;
+ break;
+ default:
+ puts("-A may only be followed by -");
+ gs_exit(1);
+ }
+ break;
+ case 'B': /* set run_string buffer size */
+ if (*arg == '-')
+ minst->run_buffer_size = 0;
+ else {
+ uint bsize;
+
+ if (sscanf((const char *)arg, "%u", &bsize) != 1 ||
+ bsize <= 0 || bsize > MAX_BUFFERED_SIZE
+ ) {
+ fprintf(stderr, "-B must be followed by - or size between 1 and %u\n", MAX_BUFFERED_SIZE);
+ gs_exit(1);
+ }
+ minst->run_buffer_size = bsize;
+ }
+ break;
+ case 'c': /* code follows */
+ {
+ bool ats = pal->expand_ats;
+
+ gs_main_init2(minst);
+ pal->expand_ats = false;
+ while ((arg = arg_next(pal)) != 0) {
+ char *sarg;
+
+ if (arg[0] == '@' ||
+ (arg[0] == '-' && !isdigit(arg[1]))
+ )
+ break;
+ sarg = arg_heap_copy(arg);
+ runarg(minst, "", sarg, ".runstring", 0);
+ }
+ if (arg != 0)
+ arg_push_string(pal, arg_heap_copy(arg));
+ pal->expand_ats = ats;
+ break;
+ }
+ case 'E': /* log errors */
+ switch (*arg) {
+ case 0:
+ gs_log_errors = 1;
+ break;
+ case '-':
+ gs_log_errors = 0;
+ break;
+ default:
+ puts("-E may only be followed by -");
+ gs_exit(1);
+ }
+ break;
+ case 'f': /* run file of arbitrary name */
+ if (*arg != 0)
+ argproc(minst, arg);
+ break;
+ case 'F': /* run file with buffer_size = 1 */
+ if (!*arg) {
+ puts("-F requires a file name");
+ gs_exit(1);
+ } {
+ uint bsize = minst->run_buffer_size;
+
+ minst->run_buffer_size = 1;
+ argproc(minst, arg);
+ minst->run_buffer_size = bsize;
+ }
+ break;
+ case 'g': /* define device geometry */
+ {
+ long width, height;
+ ref value;
+
+ gs_main_init1(minst);
+ if (sscanf((const char *)arg, "%ldx%ld", &width, &height) != 2) {
+ puts("-g must be followed by <width>x<height>");
+ gs_exit(1);
+ }
+ make_int(&value, width);
+ initial_enter_name("DEVICEWIDTH", &value);
+ make_int(&value, height);
+ initial_enter_name("DEVICEHEIGHT", &value);
+ initial_enter_name("FIXEDMEDIA", &vtrue);
+ break;
+ }
+ case 'h': /* print help */
+ case '?': /* ditto */
+ print_help(minst);
+ gs_exit(gs_exit_INFO);
+ case 'I': /* specify search path */
+ gs_main_add_lib_path(minst, arg_heap_copy(arg));
+ break;
+ case 'K': /* set malloc limit */
+ {
+ long msize = 0;
+
+ sscanf((const char *)arg, "%ld", &msize);
+ if (msize <= 0 || msize > max_long >> 10) {
+ fprintf(stderr, "-K<numK> must have 1 <= numK <= %ld\n",
+ max_long >> 10);
+ gs_exit(1);
+ }
+ gs_malloc_limit = msize << 10;
+ }
+ break;
+ case 'M': /* set memory allocation increment */
+ {
+ unsigned msize = 0;
+
+ sscanf((const char *)arg, "%u", &msize);
+#if arch_ints_are_short
+ if (msize <= 0 || msize >= 64) {
+ puts("-M must be between 1 and 63");
+ gs_exit(1);
+ }
+#endif
+ minst->memory_chunk_size = msize << 10;
+ }
+ break;
+ case 'N': /* set size of name table */
+ {
+ unsigned nsize = 0;
+
+ sscanf((const char *)arg, "%d", &nsize);
+#if arch_ints_are_short
+ if (nsize < 2 || nsize > 64) {
+ puts("-N must be between 2 and 64");
+ gs_exit(1);
+ }
+#endif
+ minst->name_table_size = (ulong) nsize << 10;
+ }
+ break;
+ case 'P': /* choose whether search '.' first */
+ if (!strcmp(arg, ""))
+ minst->search_here_first = true;
+ else if (!strcmp(arg, "-"))
+ minst->search_here_first = false;
+ else {
+ puts("Only -P or -P- is allowed.");
+ gs_exit(1);
+ }
+ break;
+ case 'q': /* quiet startup */
+ gs_main_init1(minst);
+ initial_enter_name("QUIET", &vtrue);
+ break;
+ case 'r': /* define device resolution */
+ {
+ float xres, yres;
+ ref value;
+
+ gs_main_init1(minst);
+ switch (sscanf((const char *)arg, "%fx%f", &xres, &yres)) {
+ default:
+ puts("-r must be followed by <res> or <xres>x<yres>");
+ gs_exit(1);
+ case 1: /* -r<res> */
+ yres = xres;
+ case 2: /* -r<xres>x<yres> */
+ make_real(&value, xres);
+ initial_enter_name("DEVICEXRESOLUTION", &value);
+ make_real(&value, yres);
+ initial_enter_name("DEVICEYRESOLUTION", &value);
+ initial_enter_name("FIXEDRESOLUTION", &vtrue);
+ }
+ break;
+ }
+ case 'D': /* define name */
+ case 'd':
+ case 'S': /* define name as string */
+ case 's':
+ {
+ char *adef = arg_heap_copy(arg);
+ char *eqp = strchr(adef, '=');
+ bool isd = (sw == 'D' || sw == 'd');
+ ref value;
+
+ if (eqp == NULL)
+ eqp = strchr(adef, '#');
+ /* Initialize the object memory, scanner, and */
+ /* name table now if needed. */
+ gs_main_init1(minst);
+ if (eqp == adef) {
+ puts("Usage: -dname, -dname=token, -sname=string");
+ gs_exit(1);
+ }
+ if (eqp == NULL) {
+ if (isd)
+ make_true(&value);
+ else
+ make_empty_string(&value, a_readonly);
+ } else {
+ int code;
+ uint space = icurrent_space;
+
+ *eqp++ = 0;
+ ialloc_set_space(idmemory, avm_system);
+ if (isd) {
+ stream astream;
+ scanner_state state;
+
+ sread_string(&astream,
+ (const byte *)eqp, strlen(eqp));
+ scanner_state_init(&state, false);
+ code = scan_token(&astream, &value, &state);
+ if (code) {
+ puts("-dname= must be followed by a valid token");
+ gs_exit(1);
+ }
+ if (r_has_type_attrs(&value, t_name,
+ a_executable)) {
+ ref nsref;
+
+ name_string_ref(&value, &nsref);
+#define string_is(nsref, str, len)\
+ (r_size(&(nsref)) == (len) &&\
+ !strncmp((const char *)(nsref).value.const_bytes, str, (len)))
+ if (string_is(nsref, "null", 4))
+ make_null(&value);
+ else if (string_is(nsref, "true", 4))
+ make_true(&value);
+ else if (string_is(nsref, "false", 5))
+ make_false(&value);
+ else {
+ puts("-dvar=name requires name=null, true, or false");
+ gs_exit(1);
+ }
+#undef name_is_string
+ }
+ } else {
+ int len = strlen(eqp);
+ char *str =
+ (char *)gs_alloc_bytes(minst->heap,
+ (uint) len, "-s");
+
+ if (str == 0) {
+ lprintf("Out of memory!\n");
+ gs_exit(1);
+ }
+ memcpy(str, eqp, len);
+ make_const_string(&value,
+ a_readonly | avm_foreign,
+ len, (const byte *)str);
+ }
+ ialloc_set_space(idmemory, space);
+ }
+ /* Enter the name in systemdict. */
+ initial_enter_name(adef, &value);
+ break;
+ }
+ case 'u': /* undefine name */
+ if (!*arg) {
+ puts("-u requires a name to undefine.");
+ gs_exit(1);
+ }
+ gs_main_init1(minst);
+ initial_remove_name(arg);
+ break;
+ case 'v': /* print revision */
+ print_revision();
+ gs_exit(0);
+/*#ifdef DEBUG */
+ /*
+ * Here we provide a place for inserting debugging code that can be
+ * run in place of the normal interpreter code.
+ */
+ case 'X':
+ gs_main_init2(minst);
+ {
+ int xec; /* exit_code */
+ ref xeo; /* error_object */
+
+#define start_x()\
+ gs_main_run_string_begin(minst, 1, &xec, &xeo)
+#define run_x(str)\
+ gs_main_run_string_continue(minst, str, strlen(str), 1, &xec, &xeo)
+#define stop_x()\
+ gs_main_run_string_end(minst, 1, &xec, &xeo)
+ start_x();
+ run_x("\216\003abc");
+ run_x("== flush\n");
+ stop_x();
+ }
+ gs_exit(0);
+/*#endif */
+ case 'Z':
+ {
+ byte value = (*arg == '-' ? (++arg, 0) : 0xff);
+
+ while (*arg)
+ gs_debug[*arg++ & 127] = value;
+ }
+ break;
+ }
+ return 0;
+}
+
+/* Define versions of strlen and strcat that encode strings in hex. */
+/* This is so we can enter escaped characters regardless of whether */
+/* the Level 1 convention of ignoring \s in strings-within-strings */
+/* is being observed (sigh). */
+private int
+esc_strlen(const char *str)
+{
+ return strlen(str) * 2 + 2;
+}
+private void
+esc_strcat(char *dest, const char *src)
+{
+ char *d = dest + strlen(dest);
+ const char *p;
+ static const char *const hex = "0123456789abcdef";
+
+ *d++ = '<';
+ for (p = src; *p; p++) {
+ byte c = (byte) * p;
+
+ *d++ = hex[c >> 4];
+ *d++ = hex[c & 0xf];
+ }
+ *d++ = '>';
+ *d = 0;
+}
+
+/* Process file names */
+private void
+argproc(gs_main_instance * minst, const char *arg)
+{
+ if (minst->run_buffer_size) {
+ /* Run file with run_string. */
+ run_buffered(minst, arg);
+ } else {
+ /* Run file directly in the normal way. */
+ runarg(minst, "", arg, ".runfile", runInit | runFlush);
+ }
+}
+private void
+run_buffered(gs_main_instance * minst, const char *arg)
+{
+ FILE *in = gp_fopen(arg, gp_fmode_rb);
+ int exit_code;
+ ref error_object;
+ int code;
+
+ if (in == 0) {
+ fprintf(stderr, "Unable to open %s for reading", arg);
+ gs_exit(1);
+ }
+ gs_main_init2(minst);
+ code = gs_main_run_string_begin(minst, minst->user_errors,
+ &exit_code, &error_object);
+ if (!code) {
+ char buf[MAX_BUFFERED_SIZE];
+ int count;
+
+ code = e_NeedInput;
+ while ((count = fread(buf, 1, minst->run_buffer_size, in)) > 0) {
+ code = gs_main_run_string_continue(minst, buf, count,
+ minst->user_errors,
+ &exit_code, &error_object);
+ if (code != e_NeedInput)
+ break;
+ }
+ if (code == e_NeedInput) {
+ code = gs_main_run_string_end(minst, minst->user_errors,
+ &exit_code, &error_object);
+ }
+ }
+ fclose(in);
+ zflush(osp);
+ zflushpage(osp);
+ run_finish(code, exit_code, &error_object);
+}
+private void
+runarg(gs_main_instance * minst, const char *pre, const char *arg,
+ const char *post, int options)
+{
+ int len = strlen(pre) + esc_strlen(arg) + strlen(post) + 1;
+ char *line;
+
+ if (options & runInit)
+ gs_main_init2(minst); /* Finish initialization */
+ line = (char *)gs_alloc_bytes(minst->heap, len, "argproc");
+ if (line == 0) {
+ lprintf("Out of memory!\n");
+ gs_exit(1);
+ }
+ strcpy(line, pre);
+ esc_strcat(line, arg);
+ strcat(line, post);
+ run_string(minst, line, options);
+}
+private void
+run_string(gs_main_instance * minst, const char *str, int options)
+{
+ int exit_code;
+ ref error_object;
+ int code = gs_main_run_string(minst, str, minst->user_errors,
+ &exit_code, &error_object);
+
+ if ((options & runFlush) || code != 0) {
+ zflush(osp); /* flush stdout */
+ zflushpage(osp); /* force display update */
+ }
+ run_finish(code, exit_code, &error_object);
+}
+private void
+run_finish(int code, int exit_code, ref * perror_object)
+{
+ switch (code) {
+ case 0:
+ break;
+ case e_Quit:
+ gs_exit(0);
+ case e_Fatal:
+ eprintf1("Unrecoverable error, exit code %d\n", exit_code);
+ gs_exit(exit_code);
+ default:
+ gs_debug_dump_stack(code, perror_object);
+ gs_exit_with_code(255, code);
+ }
+}
+
+/* ---------------- Print information ---------------- */
+
+/*
+ * Help strings. We have to break them up into parts, because
+ * the Watcom compiler has a limit of 510 characters for a single token.
+ * For PC displays, we want to limit the strings to 24 lines.
+ */
+private const char help_usage1[] = "\
+Usage: gs [switches] [file1.ps file2.ps ...]\n\
+Most frequently used switches: (you can use # in place of =)\n\
+ -dNOPAUSE no pause after page | -q `quiet', fewer messages\n\
+ -g<width>x<height> page size in pixels | -r<res> pixels/inch resolution\n";
+private const char help_usage2[] = "\
+ -sDEVICE=<devname> select device | -dBATCH exit after last file\n\
+ -sOutputFile=<file> select output file: - for stdout, |command for pipe,\n\
+ embed %d or %ld for page #\n";
+private const char help_trailer[] = "\
+For more information, see %s%sUse.htm.\n\
+Report bugs to %s, using the form in Bug-form.htm.\n";
+private const char help_devices[] = "Available devices:";
+private const char help_emulators[] = "Input formats:";
+private const char help_paths[] = "Search path:";
+
+/* Print the standard help message. */
+private void
+print_help(gs_main_instance * minst)
+{
+ print_revision();
+ print_usage();
+ print_emulators();
+ print_devices();
+ print_paths(minst);
+ print_help_trailer();
+}
+
+/* Print the revision, revision date, and copyright. */
+private void
+print_revision(void)
+{
+ fprintf(stderr, "%s ", gs_product);
+ print_version();
+ fprintf(stderr, " (%d-%d-%d)\n%s\n",
+ (int)(gs_revisiondate / 10000),
+ (int)(gs_revisiondate / 100 % 100),
+ (int)(gs_revisiondate % 100),
+ gs_copyright);
+}
+
+/* Print the version number. */
+private void
+print_version(void)
+{
+ fprintf(stderr, "%d.%02d",
+ (int)(gs_revision / 100),
+ (int)(gs_revision % 100));
+}
+
+/* Print usage information. */
+private void
+print_usage(void)
+{
+ fprintf(stderr, "%s", help_usage1);
+ fprintf(stderr, "%s", help_usage2);
+}
+
+/* Print the list of available devices. */
+private void
+print_devices(void)
+{
+ fprintf(stderr, "%s", help_devices);
+ {
+ int i;
+ int pos = 100;
+ const gx_device *pdev;
+
+ for (i = 0; (pdev = gs_getdevice(i)) != 0; i++) {
+ const char *dname = gs_devicename(pdev);
+ int len = strlen(dname);
+
+ if (pos + 1 + len > 76)
+ fprintf(stderr, "\n "), pos = 2;
+ fprintf(stderr, " %s", dname);
+ pos += 1 + len;
+ }
+ }
+ fprintf(stderr, "\n");
+}
+
+/* Print the list of language emulators. */
+private void
+print_emulators(void)
+{
+ fprintf(stderr, "%s", help_emulators);
+ {
+ const ref *pes;
+
+ for (pes = gs_emulator_name_array;
+ pes->value.const_bytes != 0; pes++
+ )
+ fprintf(stderr, " %s", pes->value.const_bytes);
+ }
+ fprintf(stderr, "\n");
+}
+
+/* Print the search paths. */
+private void
+print_paths(gs_main_instance * minst)
+{
+ fprintf(stderr, "%s", help_paths);
+ gs_main_set_lib_paths(minst);
+ {
+ uint count = r_size(&minst->lib_path.list);
+ uint i;
+ int pos = 100;
+ char fsepr[3];
+
+ fsepr[0] = ' ', fsepr[1] = gp_file_name_list_separator,
+ fsepr[2] = 0;
+ for (i = 0; i < count; ++i) {
+ const ref *prdir =
+ minst->lib_path.list.value.refs + i;
+ uint len = r_size(prdir);
+ const char *sepr = (i == count - 1 ? "" : fsepr);
+
+ if (1 + pos + strlen(sepr) + len > 76)
+ fprintf(stderr, "\n "), pos = 2;
+ fprintf(stderr, " ");
+ /*
+ * This is really ugly, but it's necessary.
+ * We wish we could just do:
+ fwrite(prdir->value.bytes, 1, len, stdout);
+ */
+ {
+ const char *p = (const char *)prdir->value.bytes;
+ uint j;
+
+ for (j = len; j; j--)
+ fprintf(stderr, "%c", *p++);
+ }
+ fprintf(stderr, sepr);
+ pos += 1 + len + strlen(sepr);
+ }
+ }
+ fprintf(stderr, "\n");
+}
+
+/* Print the help trailer. */
+private void
+print_help_trailer(void)
+{
+ fprintf(stderr, help_trailer, gs_doc_directory,
+ gp_file_name_concat_string(gs_doc_directory,
+ strlen(gs_doc_directory),
+ "Use.htm", 7),
+ GS_BUG_MAILBOX);
+}
diff --git a/pstoraster/imainarg.h b/pstoraster/imainarg.h
new file mode 100644
index 000000000..d135f2b52
--- /dev/null
+++ b/pstoraster/imainarg.h
@@ -0,0 +1,54 @@
+/* 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$ */
+/* argv/argc interface to imainarg.c */
+
+#ifndef imainarg_INCLUDED
+# define imainarg_INCLUDED
+
+/* Define an opaque type for an interpreter instance. See imain.h. */
+#ifndef gs_main_instance_DEFINED
+# define gs_main_instance_DEFINED
+typedef struct gs_main_instance_s gs_main_instance;
+
+#endif
+
+/*
+ * As a shortcut for very high-level clients, we define a single call
+ * that does the equivalent of command line invocation, passing argc
+ * and argv. This call includes calling init0 through init2.
+ * argv should really be const char *[], but ANSI C requires writable
+ * strings (which, however, it forbids the callee to modify!).
+ */
+int gs_main_init_with_args(P3(gs_main_instance * minst, int argc,
+ char *argv[]));
+
+/*
+ * Run the 'start' procedure (after processing the command line).
+ * Note that this procedure exits rather than returning.
+ */
+void gs_main_run_start(P1(gs_main_instance * minst));
+
+#endif /* imainarg_INCLUDED */
diff --git a/pstoraster/imemory.h b/pstoraster/imemory.h
new file mode 100644
index 000000000..40e7b69c9
--- /dev/null
+++ b/pstoraster/imemory.h
@@ -0,0 +1,99 @@
+/* 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$ */
+/* Ghostscript memory allocator extensions for interpreter level */
+
+#ifndef imemory_INCLUDED
+# define imemory_INCLUDED
+
+#include "ivmspace.h"
+
+/*
+ * The interpreter level of Ghostscript defines a "subclass" extension
+ * of the allocator interface in gsmemory.h, by adding the ability to
+ * allocate and free arrays of refs, and by adding the distinction
+ * between local, global, and system allocation.
+ */
+
+#include "gsalloc.h"
+
+#ifndef gs_ref_memory_DEFINED
+# define gs_ref_memory_DEFINED
+typedef struct gs_ref_memory_s gs_ref_memory_t;
+#endif
+
+ /* Allocate a ref array. */
+
+int gs_alloc_ref_array(P5(gs_ref_memory_t * mem, ref * paref,
+ uint attrs, uint num_refs, client_name_t cname));
+
+ /* Resize a ref array. */
+ /* Currently this is only implemented for shrinking, */
+ /* not growing. */
+
+int gs_resize_ref_array(P4(gs_ref_memory_t * mem, ref * paref,
+ uint new_num_refs, client_name_t cname));
+
+ /* Free a ref array. */
+
+void gs_free_ref_array(P3(gs_ref_memory_t * mem, ref * paref,
+ client_name_t cname));
+
+ /* Allocate a string ref. */
+
+int gs_alloc_string_ref(P5(gs_ref_memory_t * mem, ref * psref,
+ uint attrs, uint nbytes, client_name_t cname));
+
+/* Register a ref root. This just calls gs_register_root. */
+/* Note that ref roots are a little peculiar: they assume that */
+/* the ref * that they point to points to a *statically* allocated ref. */
+int gs_register_ref_root(P4(gs_memory_t *mem, gs_gc_root_t *root,
+ void **pp, client_name_t cname));
+
+
+/*
+ * The interpreter allocator can allocate in either local or global VM,
+ * and can switch between the two dynamically. In Level 1 configurations,
+ * global VM is the same as local; however, this is *not* currently true in
+ * a Level 2 system running in Level 1 mode. In addition, there is a third
+ * VM space, system VM, that exists in both modes and is used for objects
+ * that must not be affected by even the outermost save/restore (stack
+ * segments and names).
+ */
+typedef struct gs_dual_memory_s gs_dual_memory_t;
+struct gs_dual_memory_s {
+ gs_ref_memory_t *current; /* = ...global or ...local */
+ vm_spaces spaces; /* system, global, local */
+ uint current_space; /* = current->space */
+ /* Save/restore machinery */
+ int save_level;
+ /* Garbage collection hook */
+ int (*reclaim) (P2(gs_dual_memory_t *, int));
+ /* Masks for store checking, see isave.h. */
+ uint test_mask;
+ uint new_mask;
+};
+
+#endif /* imemory_INCLUDED */
diff --git a/pstoraster/iminst.h b/pstoraster/iminst.h
new file mode 100644
index 000000000..3b671f95c
--- /dev/null
+++ b/pstoraster/iminst.h
@@ -0,0 +1,92 @@
+/* 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$ */
+/* Definition of interpreter instance */
+/* Requires stdio_.h, gsmemory.h, iref.h */
+
+#ifndef iminst_INCLUDED
+# define iminst_INCLUDED
+
+#ifndef gs_main_instance_DEFINED
+# define gs_main_instance_DEFINED
+typedef struct gs_main_instance_s gs_main_instance;
+
+#endif
+
+/*
+ * Define the structure of a search path. Currently there is only one,
+ * but there might be more someday.
+ *
+ * container - an array large enough to hold the specified maximum
+ * number of directories. Both the array and all the strings in it are
+ * in the 'foreign' VM space.
+ * list - the initial interval of container that defines the actual
+ * search list.
+ * env - the contents of an environment variable, implicitly added
+ * at the end of the list; may be 0.
+ * final - the final set of directories specified in the makefile;
+ * may be 0.
+ * count - the number of elements in the list, excluding a possible
+ * initial '.', env, and final.
+ */
+typedef struct gs_file_path_s {
+ ref container;
+ ref list;
+ const char *env;
+ const char *final;
+ uint count;
+} gs_file_path;
+
+/*
+ * Here is where we actually define the structure of interpreter instances.
+ * Clients should not reference any of the members.
+ */
+struct gs_main_instance_s {
+ /* The following are set during initialization. */
+ FILE *fstdin;
+ FILE *fstdout;
+ FILE *fstderr;
+ gs_memory_t *heap; /* (C) heap allocator */
+ uint memory_chunk_size; /* 'wholesale' allocation unit */
+ ulong name_table_size;
+ uint run_buffer_size;
+ int init_done; /* highest init done so far */
+ int user_errors; /* define what to do with errors */
+ bool search_here_first; /* if true, make '.' first lib dir */
+ bool run_start; /* if true, run 'start' after */
+ /* processing command line */
+ gs_file_path lib_path; /* library search list (GS_LIB) */
+ long base_time[2]; /* starting usertime */
+};
+
+/*
+ * Note that any file that uses the following definition of default values
+ * must include gconfig.h, because of SEARCH_HERE_FIRST.
+ */
+#define gs_main_instance_default_init_values\
+ 0, 0, 0, 0, 20000, 0, 0, -1, 0, SEARCH_HERE_FIRST, 1
+extern const gs_main_instance gs_main_instance_init_values;
+
+#endif /* iminst_INCLUDED */
diff --git a/pstoraster/iname.c b/pstoraster/iname.c
new file mode 100644
index 000000000..118ff15f2
--- /dev/null
+++ b/pstoraster/iname.c
@@ -0,0 +1,637 @@
+/* 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$ */
+/* Name lookup for Ghostscript interpreter */
+#include "memory_.h"
+#include "string_.h"
+#include "ghost.h"
+#include "gsstruct.h"
+#include "gxobj.h" /* for o_set_unmarked */
+#include "errors.h"
+#include "inamedef.h"
+#include "imemory.h" /* for isave.h */
+#include "isave.h"
+#include "store.h"
+
+/* Public values */
+const uint name_max_string = max_name_string;
+
+/* In the code below, we use the hashing method described in */
+/* "Fast Hashing of Variable-Length Text Strings" by Peter K. Pearson, */
+/* pp. 677-680, CACM 33(6), June 1990. */
+
+/* Define a pseudo-random permutation of the integers 0..255. */
+/* Pearson's article claims this permutation gave good results. */
+private const byte hash_permutation[256] =
+{
+ 1, 87, 49, 12, 176, 178, 102, 166, 121, 193, 6, 84, 249, 230, 44, 163,
+ 14, 197, 213, 181, 161, 85, 218, 80, 64, 239, 24, 226, 236, 142, 38, 200,
+ 110, 177, 104, 103, 141, 253, 255, 50, 77, 101, 81, 18, 45, 96, 31, 222,
+ 25, 107, 190, 70, 86, 237, 240, 34, 72, 242, 20, 214, 244, 227, 149, 235,
+ 97, 234, 57, 22, 60, 250, 82, 175, 208, 5, 127, 199, 111, 62, 135, 248,
+ 174, 169, 211, 58, 66, 154, 106, 195, 245, 171, 17, 187, 182, 179, 0, 243,
+ 132, 56, 148, 75, 128, 133, 158, 100, 130, 126, 91, 13, 153, 246, 216, 219,
+ 119, 68, 223, 78, 83, 88, 201, 99, 122, 11, 92, 32, 136, 114, 52, 10,
+ 138, 30, 48, 183, 156, 35, 61, 26, 143, 74, 251, 94, 129, 162, 63, 152,
+ 170, 7, 115, 167, 241, 206, 3, 150, 55, 59, 151, 220, 90, 53, 23, 131,
+ 125, 173, 15, 238, 79, 95, 89, 16, 105, 137, 225, 224, 217, 160, 37, 123,
+ 118, 73, 2, 157, 46, 116, 9, 145, 134, 228, 207, 212, 202, 215, 69, 229,
+ 27, 188, 67, 124, 168, 252, 42, 4, 29, 108, 21, 247, 19, 205, 39, 203,
+ 233, 40, 186, 147, 198, 192, 155, 33, 164, 191, 98, 204, 165, 180, 117, 76,
+ 140, 36, 210, 172, 41, 54, 159, 8, 185, 232, 113, 196, 231, 47, 146, 120,
+ 51, 65, 28, 144, 254, 221, 93, 189, 194, 139, 112, 43, 71, 109, 184, 209
+};
+
+/*
+ * Definitions and structure for the name table.
+ * Entry 0 is left unused.
+ * The entry with count = 1 is the entry for the 0-length name.
+ * The next nt_1char_size entries (in count order) are 1-character names.
+ */
+#define nt_1char_size 128
+#define nt_1char_first 2
+private const byte nt_1char_names[128] =
+{
+#define q8(n) n,n+1,n+2,n+3,n+4,n+5,n+6,n+7
+#define q32(n) q8(n),q8(n+8),q8(n+16),q8(n+24)
+ q32(0), q32(32), q32(64), q32(96)
+#undef q8
+};
+
+/* Structure descriptors */
+gs_private_st_composite(st_name_sub_table, name_sub_table, "name_sub_table",
+ name_sub_enum_ptrs, name_sub_reloc_ptrs);
+gs_private_st_composite(st_name_table, name_table, "name_table",
+ name_table_enum_ptrs, name_table_reloc_ptrs);
+
+/* Forward references */
+private int name_alloc_sub(P1(name_table *));
+private void name_scan_sub(P3(name_table *, uint, bool));
+
+/* Debugging printout */
+#ifdef DEBUG
+private void
+name_print(const char *msg, name * pname, uint nidx, const int *pflag)
+{
+ const byte *ptr = pname->string_bytes;
+
+ dlprintf1("[n]%s", msg);
+ if (pflag)
+ dprintf1("(%d)", *pflag);
+ dprintf2(" (0x%lx#%u)", (ulong) pname, nidx);
+ debug_print_string(ptr, pname->string_size);
+ dprintf2("(0x%lx,%u)\n", (ulong) ptr, pname->string_size);
+}
+# define if_debug_name(msg, pname, nidx, pflag)\
+ if ( gs_debug_c('n') ) name_print(msg, pname, nidx, pflag)
+#else
+# define if_debug_name(msg, pname, nidx, pflag) DO_NOTHING
+#endif
+
+/* Initialize a name table */
+name_table *
+names_init(ulong count, gs_memory_t * mem)
+{
+ register int i;
+ name_table *nt;
+
+ if (count == 0)
+ count = max_name_count + 1L;
+ else if (count - 1 > max_name_count)
+ return 0;
+ nt =
+ gs_alloc_struct(mem, name_table, &st_name_table, "name_init(nt)");
+ memset(nt, 0, sizeof(name_table));
+ nt->max_sub_count =
+ ((count - 1) | nt_sub_index_mask) >> nt_log2_sub_size;
+ nt->memory = mem;
+ /* Initialize the one-character names. */
+ /* Start by creating the necessary sub-tables. */
+ for (i = 0; i < nt_1char_first + nt_1char_size; i += nt_sub_size)
+ name_alloc_sub(nt);
+ for (i = -1; i < nt_1char_size; i++) {
+ uint ncnt = nt_1char_first + i;
+ uint nidx = name_count_to_index(ncnt);
+ register name *pname = names_index_ptr_inline(nt, nidx);
+
+ if (i < 0)
+ pname->string_bytes = nt_1char_names,
+ pname->string_size = 0;
+ else
+ pname->string_bytes = nt_1char_names + i,
+ pname->string_size = 1;
+ pname->foreign_string = 1;
+ pname->mark = 1;
+ pname->pvalue = pv_no_defn;
+ }
+ /* Reconstruct the free list. */
+ nt->free = 0;
+ names_trace_finish(nt, NULL);
+ return nt;
+}
+
+/* Get the allocator for the name table. */
+gs_memory_t *
+names_memory(const name_table * nt)
+{
+ return nt->memory;
+}
+
+/* Look up or enter a name in the table. */
+/* Return 0 or an error code. */
+/* The return may overlap the characters of the string! */
+/* See iname.h for the meaning of enterflag. */
+int
+names_ref(name_table * nt, const byte * ptr, uint size, ref * pref, int enterflag)
+{
+ register name *pname;
+ uint nidx;
+ uint *phash;
+
+ /* Compute a hash for the string. */
+ {
+ uint hash;
+ const byte *p = ptr;
+ uint n = size;
+
+ /* Make a special check for 1-character names. */
+ switch (size) {
+ case 0:
+ nidx = name_count_to_index(1);
+ pname = names_index_ptr_inline(nt, nidx);
+ goto mkn;
+ case 1:
+ if (*p < nt_1char_size) {
+ hash = *p + nt_1char_first;
+ nidx = name_count_to_index(hash);
+ pname = names_index_ptr_inline(nt, nidx);
+ goto mkn;
+ }
+ /* falls through */
+ default:
+ hash = hash_permutation[*p++];
+ while (--n > 0)
+ hash = (hash << 8) |
+ hash_permutation[(byte) hash ^ *p++];
+ }
+ phash = nt->hash + (hash & (nt_hash_size - 1));
+ }
+
+ for (nidx = *phash; nidx != 0;
+ nidx = name_next_index(nidx, pname)
+ ) {
+ pname = names_index_ptr_inline(nt, nidx);
+ if (pname->string_size == size &&
+ !memcmp_inline(ptr, pname->string_bytes, size)
+ )
+ goto mkn;
+ }
+ /* Name was not in the table. Make a new entry. */
+ if (enterflag < 0)
+ return_error(e_undefined);
+ if (size > max_name_string)
+ return_error(e_limitcheck);
+ nidx = nt->free;
+ if (nidx == 0) {
+ int code = name_alloc_sub(nt);
+
+ if (code < 0)
+ return code;
+ nidx = nt->free;
+ }
+ pname = name_index_ptr_inline(nt, nidx);
+ if (enterflag == 1) {
+ byte *cptr = (byte *) gs_alloc_string(nt->memory, size,
+ "names_ref(string)");
+
+ if (cptr == 0)
+ return_error(e_VMerror);
+ memcpy(cptr, ptr, size);
+ pname->string_bytes = cptr;
+ pname->foreign_string = 0;
+ } else {
+ pname->string_bytes = ptr;
+ pname->foreign_string = (enterflag == 0 ? 1 : 0);
+ }
+ pname->string_size = size;
+ pname->pvalue = pv_no_defn;
+ nt->free = name_next_index(nidx, pname);
+ set_name_next_index(nidx, pname, *phash);
+ *phash = nidx;
+ if_debug_name("new name", pname, nidx, &enterflag);
+ mkn:make_name(pref, nidx, pname);
+ return 0;
+}
+
+/* Get the string for a name. */
+void
+names_string_ref(const name_table * nt, const ref * pnref /* t_name */ ,
+ ref * psref /* result, t_string */ )
+{
+ name *pname = pnref->value.pname;
+
+ make_const_string(psref,
+ (pname->foreign_string ? avm_foreign :
+ imemory_space((gs_ref_memory_t *) nt->memory))
+ | a_readonly,
+ pname->string_size,
+ (const byte *)pname->string_bytes);
+}
+
+/* Convert a t_string object to a name. */
+/* Copy the executable attribute. */
+int
+names_from_string(name_table * nt, const ref * psref, ref * pnref)
+{
+ int exec = r_has_attr(psref, a_executable);
+ int code = names_ref(nt, psref->value.bytes, r_size(psref), pnref, 1);
+
+ if (code < 0)
+ return code;
+ if (exec)
+ r_set_attrs(pnref, a_executable);
+ return code;
+}
+
+/* Enter a (permanently allocated) C string as a name. */
+int
+names_enter_string(name_table * nt, const char *str, ref * pref)
+{
+ return names_ref(nt, (const byte *)str, strlen(str), pref, 0);
+}
+
+/* Invalidate the value cache for a name. */
+void
+names_invalidate_value_cache(name_table * nt, const ref * pnref)
+{
+ pnref->value.pname->pvalue = pv_other;
+}
+
+/* Convert between names and indices. */
+#undef names_index
+name_index_t
+names_index(const name_table * nt, const ref * pnref)
+{
+ return names_index_inline(nt, pnref);
+}
+void
+names_index_ref(const name_table * nt, name_index_t index, ref * pnref)
+{
+ names_index_ref_inline(nt, index, pnref);
+}
+name *
+names_index_ptr(const name_table * nt, name_index_t index)
+{
+ return names_index_ptr_inline(nt, index);
+}
+
+/* Get the index of the next valid name. */
+/* The argument is 0 or a valid index. */
+/* Return 0 if there are no more. */
+name_index_t
+names_next_valid_index(name_table * nt, name_index_t nidx)
+{
+ name_sub_table *sub = nt->sub_tables[nidx >> nt_log2_sub_size];
+ name *pname;
+
+ do {
+ ++nidx;
+ if ((nidx & nt_sub_index_mask) == 0)
+ for (;; nidx += nt_sub_size) {
+ if ((nidx >> nt_log2_sub_size) >= nt->sub_count)
+ return 0;
+ sub = nt->sub_tables[nidx >> nt_log2_sub_size];
+ if (sub != 0)
+ break;
+ }
+ pname = &sub->names[nidx & nt_sub_index_mask];
+ }
+ while (pname->string_bytes == 0);
+ return nidx;
+}
+
+/* ------ Garbage collection ------ */
+
+/* Unmark all names, except for 1-character permanent names, */
+/* before a garbage collection. */
+void
+names_unmark_all(name_table * nt)
+{
+ uint si;
+ name_sub_table *sub;
+
+ for (si = 0; si < nt->sub_count; ++si)
+ if ((sub = nt->sub_tables[si]) != 0) {
+ uint i;
+
+ for (i = 0; i < nt_sub_size; ++i)
+ sub->names[i].mark = 0;
+ } {
+ uint ncnt;
+
+ for (ncnt = 1; ncnt <= nt_1char_size; ++ncnt)
+ names_index_ptr(nt, name_count_to_index(ncnt))->mark = 1;
+ }
+}
+
+/* Mark a name. Return true if new mark. We export this so we can mark */
+/* character names in the character cache. */
+bool
+names_mark_index(name_table * nt, name_index_t nidx)
+{
+ name *pname = names_index_ptr(nt, nidx);
+
+ if (pname->mark)
+ return false;
+ pname->mark = 1;
+ return true;
+}
+
+/* Get the object (sub-table) containing a name. */
+/* The garbage collector needs this so it can relocate pointers to names. */
+void /*obj_header_t */ *
+names_ref_sub_table(name_table * nt, const ref * pnref)
+{ /* When this procedure is called, the pointers from the name table */
+ /* to the sub-tables may or may not have been relocated already, */
+ /* so we can't use them. Instead, we have to work backwards from */
+ /* the name pointer itself. */
+ return pnref->value.pname - (names_index_inline(nt, pnref) & nt_sub_index_mask);
+}
+void /*obj_header_t */ *
+names_index_ptr_sub_table(name_table * nt, name_index_t index, name * pname)
+{
+ return pname - (index & nt_sub_index_mask);
+}
+
+/*
+ * Clean up the name table after the trace/mark phase of a garbage
+ * collection, by removing names that aren't marked. gcst == NULL indicates
+ * we're doing this for initialization or restore rather than for a GC.
+ */
+void
+names_trace_finish(name_table * nt, gc_state_t * gcst)
+{
+ uint *phash = &nt->hash[0];
+ uint i;
+
+ for (i = 0; i < nt_hash_size; phash++, i++) {
+ name_index_t prev = 0;
+ name *pnprev;
+ name_index_t nidx = *phash;
+
+ while (nidx != 0) {
+ name *pname = names_index_ptr_inline(nt, nidx);
+ name_index_t next = name_next_index(nidx, pname);
+
+ if (pname->mark) {
+ prev = nidx;
+ pnprev = pname;
+ } else {
+ if_debug_name("GC remove name", pname, nidx,
+ NULL);
+ /* Zero out the string data for the GC. */
+ pname->string_bytes = 0;
+ pname->string_size = 0;
+ if (prev == 0)
+ *phash = next;
+ else
+ set_name_next_index(prev, pnprev, next);
+ }
+ nidx = next;
+ }
+ }
+ /* Reconstruct the free list. */
+ nt->free = 0;
+ for (i = nt->sub_count; i--;) {
+ name_sub_table *sub = nt->sub_tables[i];
+
+ if (sub != 0) {
+ name_scan_sub(nt, i, true);
+ if (nt->sub_tables[i] == 0 && gcst != 0) { /* Mark the just-freed sub-table as unmarked. */
+ o_set_unmarked((obj_header_t *) sub - 1);
+ }
+ }
+ if (i == 0)
+ break;
+ }
+ nt->sub_next = 0;
+}
+
+/* ------ Save/restore ------ */
+
+/* Clean up the name table before a restore. */
+/* Currently, this is never called, because the name table is allocated */
+/* in system VM. However, for a Level 1 system, we might choose to */
+/* allocate the name table in global VM; in this case, this routine */
+/* would be called before doing the global part of a top-level restore. */
+/* Currently we don't make any attempt to optimize this. */
+void
+names_restore(name_table * nt, alloc_save_t * save)
+{ /* We simply mark all names older than the save, */
+ /* and let names_trace_finish sort everything out. */
+ uint si;
+
+ for (si = 0; si < nt->sub_count; ++si)
+ if (nt->sub_tables[si] != 0) {
+ uint i;
+
+ for (i = 0; i < nt_sub_size; ++i) {
+ name *pname =
+ names_index_ptr_inline(nt, (si << nt_log2_sub_size) + i);
+
+ if (pname->string_bytes == 0)
+ pname->mark = 0;
+ else if (pname->foreign_string)
+ pname->mark = 1;
+ else
+ pname->mark =
+ !alloc_is_since_save(pname->string_bytes, save);
+ }
+ }
+ names_trace_finish(nt, NULL);
+}
+
+/* ------ Internal procedures ------ */
+
+/* Allocate the next sub-table. */
+private int
+name_alloc_sub(name_table * nt)
+{
+ uint sub_index = nt->sub_next;
+ name_sub_table *sub;
+
+ for (;; ++sub_index) {
+ if (sub_index > nt->max_sub_count)
+ return_error(e_limitcheck);
+ if (nt->sub_tables[sub_index] == 0)
+ break;
+ }
+ nt->sub_next = sub_index + 1;
+ if (nt->sub_next > nt->sub_count)
+ nt->sub_count = nt->sub_next;
+ sub = gs_alloc_struct(nt->memory, name_sub_table, &st_name_sub_table,
+ "name_alloc_sub");
+ if (sub == 0)
+ return_error(e_VMerror);
+ memset(sub, 0, sizeof(name_sub_table));
+ /* The following code is only used if EXTEND_NAMES is non-zero. */
+#if name_extension_bits > 0
+ if (sub_index >= 0x10000L >> nt_log2_sub_size) {
+ /* Fill in my_extension in all the newly created names. */
+ uint extn = sub_index >> (16 - nt_log2_sub_size);
+ int i;
+
+ for (i = 0; i < nt_sub_size; ++i)
+ set_name_extension(&sub->names[i], extn);
+ }
+#endif
+ nt->sub_tables[sub_index] = sub;
+ /* Add the newly allocated entries to the free list. */
+ /* Note that the free list will only be properly sorted if */
+ /* it was empty initially. */
+ name_scan_sub(nt, sub_index, false);
+#ifdef DEBUG
+ if (gs_debug_c('n')) { /* Print the lengths of the hash chains. */
+ int i0;
+
+ for (i0 = 0; i0 < nt_hash_size; i0 += 16) {
+ int i;
+
+ dlprintf1("[n]chain %d:", i0);
+ for (i = i0; i < i0 + 16; i++) {
+ int n = 0;
+ uint nidx;
+
+ for (nidx = nt->hash[i]; nidx != 0;
+ nidx = name_next_index(nidx, name_index_ptr_inline(nt, nidx))
+ )
+ n++;
+ dprintf1(" %d", n);
+ }
+ dputc('\n');
+ }
+ }
+#endif
+ return 0;
+}
+
+/* Scan a sub-table and add unmarked entries to the free list. */
+/* We add the entries in decreasing count order, so the free list */
+/* will stay sorted. If all entries are unmarked and free_empty is true, */
+/* free the sub-table. */
+private void
+name_scan_sub(name_table * nt, uint sub_index, bool free_empty)
+{
+ name_sub_table *sub = nt->sub_tables[sub_index];
+ uint free = nt->free;
+ uint nbase = sub_index << nt_log2_sub_size;
+ uint ncnt = nbase + (nt_sub_size - 1);
+ bool keep = !free_empty;
+
+ if (sub == 0)
+ return;
+ if (nbase == 0)
+ nbase = 1, keep = true; /* don't free name 0 */
+ for (;; --ncnt) {
+ uint nidx = name_count_to_index(ncnt);
+ name *pname = &sub->names[nidx & nt_sub_index_mask];
+
+ if (pname->mark)
+ keep = true;
+ else {
+ set_name_next_index(nidx, pname, free);
+ free = nidx;
+ }
+ if (ncnt == nbase)
+ break;
+ }
+ if (keep)
+ nt->free = free;
+ else { /* No marked entries, free the sub-table. */
+ gs_free_object(nt->memory, sub, "name_scan_sub");
+ nt->sub_tables[sub_index] = 0;
+ if (sub_index == nt->sub_count - 1) {
+ /* Back up over a final run of deleted sub-tables. */
+ do {
+ --sub_index;
+ } while (nt->sub_tables[sub_index] == 0);
+ nt->sub_count = sub_index + 1;
+ if (nt->sub_next > sub_index)
+ nt->sub_next = sub_index;
+ } else if (nt->sub_next == sub_index)
+ nt->sub_next--;
+ }
+}
+
+/* Garbage collector enumeration and relocation procedures. */
+#define ntptr ((name_table *)vptr)
+private
+ENUM_PTRS_BEGIN_PROC(name_table_enum_ptrs)
+{
+ if (index >= ntptr->sub_count)
+ return 0;
+ ENUM_RETURN(ntptr->sub_tables[index]);
+}
+ENUM_PTRS_END_PROC
+private RELOC_PTRS_BEGIN(name_table_reloc_ptrs)
+{
+ name_sub_table **sub = ntptr->sub_tables;
+ uint sub_count = ntptr->sub_count;
+ uint i;
+
+ /* Now we can relocate the sub-table pointers. */
+ for (i = 0; i < sub_count; i++, sub++)
+ RELOC_VAR(*sub);
+ /*
+ * We also need to relocate the cached value pointers.
+ * We don't do this here, but in a separate scan over the
+ * permanent dictionaries, at the very end of garbage collection.
+ */
+}
+RELOC_PTRS_END
+#undef ntptr
+
+private ENUM_PTRS_BEGIN_PROC(name_sub_enum_ptrs)
+{
+ return 0;
+}
+ENUM_PTRS_END_PROC
+private RELOC_PTRS_BEGIN(name_sub_reloc_ptrs)
+{
+ name *pname = ((name_sub_table *) vptr)->names;
+ uint i;
+
+ for (i = 0; i < nt_sub_size; ++pname, ++i) {
+ if (pname->string_bytes != 0 && !pname->foreign_string) {
+ gs_const_string nstr;
+
+ nstr.data = pname->string_bytes;
+ nstr.size = pname->string_size;
+ RELOC_CONST_STRING_VAR(nstr);
+ pname->string_bytes = nstr.data;
+ }
+ }
+}
+RELOC_PTRS_END
diff --git a/pstoraster/iname.h b/pstoraster/iname.h
new file mode 100644
index 000000000..134221646
--- /dev/null
+++ b/pstoraster/iname.h
@@ -0,0 +1,105 @@
+/* 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$ */
+/* Interpreter's name table interface */
+
+#ifndef iname_INCLUDED
+# define iname_INCLUDED
+
+#include "inames.h"
+
+/*
+ * This file defines those parts of the name table API that refer to the
+ * interpreter's distinguished instance. Procedures in this file begin
+ * with name_.
+ */
+
+/* ---------------- Procedural interface ---------------- */
+
+/* Define the interpreter's name table. */
+extern name_table *the_gs_name_table;
+
+/* Backward compatibility */
+#define the_name_table() ((const name_table *)the_gs_name_table)
+
+/* Get the allocator for the name table. */
+#define name_memory()\
+ names_memory(the_gs_name_table)
+
+/*
+ * Look up and/or enter a name in the name table.
+ * See inames.h for the values of enterflag, and the possible return values.
+ */
+#define name_ref(ptr, size, pnref, enterflag)\
+ names_ref(the_gs_name_table, ptr, size, pnref, enterflag)
+#define name_string_ref(pnref, psref)\
+ names_string_ref(the_gs_name_table, pnref, psref)
+/*
+ * name_enter_string calls name_ref with a (permanent) C string.
+ */
+#define name_enter_string(str, pnref)\
+ names_enter_string(the_gs_name_table,str, pnref)
+/*
+ * name_from_string essentially implements cvn.
+ * It always enters the name, and copies the executable attribute.
+ */
+#define name_from_string(psref, pnref)\
+ names_from_string(the_gs_name_table, psref, pnref)
+
+/* Compare two names for equality. */
+#define name_eq(pnref1, pnref2)\
+ names_eq(pnref1, pnref2)
+
+/* Invalidate the value cache for a name. */
+#define name_invalidate_value_cache(pnref)\
+ names_invalidate_value_cache(the_gs_name_table, pnref)
+
+/* Convert between names and indices. */
+#define name_index(pnref) /* ref => index */\
+ names_index(the_gs_name_table, pnref)
+#define name_index_ptr(nidx) /* index => name */\
+ names_index_ptr(the_gs_name_table, nidx)
+#define name_index_ref(nidx, pnref) /* index => ref */\
+ names_index_ref(the_gs_name_table, nidx, pnref)
+
+/* Get the index of the next valid name. */
+/* The argument is 0 or a valid index. */
+/* Return 0 if there are no more. */
+#define name_next_valid_index(nidx)\
+ names_next_valid_index(the_gs_name_table, nidx)
+
+/* Mark a name for the garbage collector. */
+/* Return true if this is a new mark. */
+#define name_mark_index(nidx)\
+ names_mark_index(the_gs_name_table, nidx)
+
+/* Get the object (sub-table) containing a name. */
+/* The garbage collector needs this so it can relocate pointers to names. */
+#define name_ref_sub_table(pnref)\
+ names_ref_sub_table(the_gs_name_table, pnref)
+#define name_index_ptr_sub_table(nidx, pnref)\
+ names_index_ptr_sub_table(the_gs_name_table, nidx, pnref)
+
+#endif /* iname_INCLUDED */
diff --git a/pstoraster/inamedef.h b/pstoraster/inamedef.h
new file mode 100644
index 000000000..4feb52279
--- /dev/null
+++ b/pstoraster/inamedef.h
@@ -0,0 +1,230 @@
+/* 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$ */
+/* Name table definition */
+
+#ifndef inamedef_INCLUDED
+# define inamedef_INCLUDED
+
+#include "inames.h"
+#include "gconfigv.h" /* defines EXTEND_NAMES */
+#include "gsstruct.h" /* for gc_state_t */
+
+/*
+ * The name table machinery has two slightly different configurations:
+ * a faster one that limits the total number of names to 64K and allows
+ * names up to 16K in size, and a slightly slower one that limits
+ * the total to 4M and restricts names to 256 characters.
+ */
+#if arch_sizeof_int < 4
+# undef EXTEND_NAMES /* no extended names if ints are short */
+#endif
+#ifndef EXTEND_NAMES /* # of bits beyond 16 */
+# define EXTEND_NAMES 0
+#endif
+#define max_name_extension_bits 6
+#if EXTEND_NAMES > max_name_extension_bits
+# undef EXTEND_NAMES
+# define EXTEND_NAMES max_name_extension_bits
+#endif
+/*
+ * We capture the small algorithmic differences between these two
+ * configurations entirely in this header file;
+ * the implementation doesn't need any conditionals on EXTEND_NAMES.
+ */
+#define max_name_index (uint)((0x10000 << EXTEND_NAMES) - 1)
+/* As explained below, we distinguish name indices from name counts. */
+#define max_name_count max_name_index
+
+/* ---------------- Structure definitions ---------------- */
+
+/*
+ * Define the structure of a name. The next_index "pointer" is used for
+ * the chained hash table in the name_table, and also for the list of
+ * free names. The pvalue member implements an important optimization
+ * to avoid lookup for operator and other global names.
+ */
+struct name_s {
+ ushort next_index; /* (low bits of) next name in chain or 0 */
+ unsigned foreign_string:1; /* string is allocated statically */
+ unsigned mark:1; /* GC mark bit */
+#if EXTEND_NAMES
+# define name_extension_bits 6
+ unsigned my_extension:name_extension_bits; /* high-order bits */
+# define set_name_extension(pname, xbits) ((pname)->my_extension = xbits)
+#else
+# define name_extension_bits 0
+# define set_name_extension(name, xbits) DO_NOTHING
+#endif
+ /* of index for this name */
+#define name_string_size_bits (14 - name_extension_bits)
+#define max_name_string ((1 << name_string_size_bits) - 1)
+ unsigned string_size:name_string_size_bits;
+ const byte *string_bytes;
+/* pvalue specifies the definition status of the name: */
+/* pvalue == pv_no_defn: no definitions */
+#define pv_no_defn ((ref *)0)
+/* pvalue == pv_other: other status */
+#define pv_other ((ref *)1)
+/* pvalue != pv_no_defn, pvalue != pv_other: pvalue is valid */
+#define pv_valid(pvalue) ((unsigned long)(pvalue) > 1)
+ ref *pvalue; /* if only defined in systemdict */
+ /* or userdict, this points to */
+ /* the value */
+};
+
+ /*typedef struct name_s name; *//* in iref.h */
+
+/*
+ * Define the structure of a name table. Normally we would make this
+ * an opaque type, but we want to be able to in-line some of the
+ * access procedures.
+ *
+ * The name table is a two-level indexed table, consisting of
+ * sub-tables of size nt_sub_size each.
+ *
+ * First we define the name sub-table structure.
+ */
+#define nt_log2_sub_size (7 + (EXTEND_NAMES / 2))
+# define nt_sub_size (1 << nt_log2_sub_size)
+# define nt_sub_index_mask (nt_sub_size - 1)
+typedef struct name_sub_table_s {
+ name names[nt_sub_size]; /* must be first */
+#if EXTEND_NAMES
+ byte next_index_extension[nt_sub_size]; /* high-order bits */
+ /* of next_index */
+# define name_next_index(nidx, pname)\
+ ( (((name_sub_table *)((pname) - ((nidx) & nt_sub_index_mask)))->\
+ next_index_extension[(nidx) & nt_sub_index_mask] << 16) +\
+ ((pname)->next_index)\
+ )
+# define set_name_next_index(nidx, pname, next)\
+ ( ((name_sub_table *)((pname) - ((nidx) & nt_sub_index_mask)))->\
+ next_index_extension[(nidx) & nt_sub_index_mask] =\
+ (byte)((next) >> 16),\
+ (pname)->next_index = (ushort)(next)\
+ )
+#else /* !EXTEND_NAMES */
+# define name_next_index(nidx, pname)\
+ ((pname)->next_index)
+# define set_name_next_index(nidx, pname, next)\
+ ((pname)->next_index = (next))
+#endif /* (!)EXTEND_NAMES */
+} name_sub_table;
+
+/*
+ * Now define the name table itself.
+ * This must be made visible so that the interpreter can use the
+ * inline macros defined below.
+ */
+#define nt_hash_size (1024 << (EXTEND_NAMES / 2)) /* must be a power of 2 */
+struct name_table_s {
+ uint free; /* head of free list, which is sorted in */
+ /* increasing count (not index) order */
+ uint sub_next; /* index of next sub-table to allocate */
+ /* if not already allocated */
+ uint sub_count; /* index of highest allocated sub-table +1 */
+ uint max_sub_count; /* max allowable value of sub_count */
+ gs_memory_t *memory;
+ uint hash[nt_hash_size];
+ name_sub_table *sub_tables[max_name_index / nt_sub_size + 1];
+};
+
+ /*typedef struct name_table_s name_table; *//* in inames.h */
+
+/* ---------------- Procedural interface ---------------- */
+
+/* Convert between names and indices. Note that the inline versions, */
+/* but not the procedure versions, take a name_table argument. */
+ /* ref => index */
+#if EXTEND_NAMES
+# define names_index_inline(nt_ignored, pnref)\
+ ( ((uint)((pnref)->value.pname->my_extension) << 16) + r_size(pnref) )
+#else
+# define names_index_inline(nt_ignored, pnref) r_size(pnref)
+#endif
+#define names_index(nt_ignored, pnref) names_index_inline(nt_ignored, pnref)
+ /* index => name */
+#define names_index_ptr_inline(nt, nidx)\
+ ((nt)->sub_tables[(nidx) >> nt_log2_sub_size]->names + ((nidx) & nt_sub_index_mask))
+ /* index => ref */
+#define names_index_ref_inline(nt, nidx, pnref)\
+ make_name(pnref, nidx, names_index_ptr_inline(nt, nidx));
+/* Backward compatibility */
+#define name_index_inline(pnref) names_index_inline(ignored, pnref)
+#define name_index_ptr_inline(nt, pnref) names_index_ptr_inline(nt, pnref)
+#define name_index_ref_inline(nt, nidx, pnref)\
+ names_index_ref_inline(nt, nidx, pnref)
+
+ /* name => ref */
+/* We have to set the space to system so that the garbage collector */
+/* won't think names are foreign and therefore untraceable. */
+#define make_name(pnref, nidx, pnm)\
+ make_tasv(pnref, t_name, avm_system, (ushort)(nidx), pname, pnm)
+
+/* ------ Garbage collection ------ */
+
+/* Unmark all names, except for 1-character permanent names, */
+/* before a garbage collection. */
+void names_unmark_all(P1(name_table * nt));
+
+/* Finish tracing the name table by putting free names on the free list. */
+void names_trace_finish(P2(name_table * nt, gc_state_t * gcst));
+
+/* ------ Save/restore ------ */
+
+/* Clean up the name table before a restore, */
+/* by removing names whose count is less than old_count. */
+#ifndef alloc_save_t_DEFINED /* also in isave.h */
+typedef struct alloc_save_s alloc_save_t;
+
+# define alloc_save_t_DEFINED
+#endif
+void names_restore(P2(name_table * nt, alloc_save_t * save));
+
+/* ---------------- Name count/index maintenance ---------------- */
+
+/*
+ * We scramble the assignment order within a sub-table, so that
+ * dictionary lookup doesn't have to scramble the index.
+ * The scrambling algorithm must have three properties:
+ * - It must map 0 to 0;
+ * - It must only scramble the sub-table index;
+ * - It must be a permutation on the sub-table index.
+ * Something very simple works just fine.
+ */
+#define name_count_to_index(cnt)\
+ (((cnt) & (-nt_sub_size)) +\
+ (((cnt) * 59) & nt_sub_index_mask))
+/*
+ * The reverse permutation requires finding a number R such that
+ * 59*R = 1 mod nt_sub_size. For nt_sub_size any power of 2 up to 2048,
+ * R = 243 will work. Currently, this is only needed for debugging printout.
+ */
+#define name_index_to_count(nidx)\
+ (((nidx) & (-nt_sub_size)) +\
+ (((nidx) * 243) & nt_sub_index_mask))
+
+#endif /* inamedef_INCLUDED */
diff --git a/pstoraster/inames.h b/pstoraster/inames.h
new file mode 100644
index 000000000..7eb6e4633
--- /dev/null
+++ b/pstoraster/inames.h
@@ -0,0 +1,114 @@
+/* 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$ */
+/* Name table interface */
+
+#ifndef inames_INCLUDED
+# define inames_INCLUDED
+
+/*
+ * This file defines those parts of the name table API that depend neither
+ * on the implementation nor on the existence of a single distinguished
+ * instance. Procedures in this file begin with names_.
+ */
+
+/* ---------------- Interface types ---------------- */
+
+#ifndef name_table_DEFINED
+# define name_table_DEFINED
+typedef struct name_table_s name_table;
+
+#endif
+
+typedef uint name_index_t;
+
+/* ---------------- Constant values ---------------- */
+
+extern const uint name_max_string;
+
+/* ---------------- Procedural interface ---------------- */
+
+/* Allocate and initialize a name table. */
+name_table *names_init(P2(ulong size, gs_memory_t * mem));
+
+/* Get the allocator for a name table. */
+gs_memory_t *names_memory(P1(const name_table * nt));
+
+/*
+ * Look up and/or enter a name in the name table.
+ * The values of enterflag are:
+ * -1 -- don't enter (return an error) if missing;
+ * 0 -- enter if missing, don't copy the string, which was allocated
+ * statically;
+ * 1 -- enter if missing, copy the string;
+ * 2 -- enter if missing, don't copy the string, which was already
+ * allocated dynamically (using the names_memory allocator).
+ * Possible errors: VMerror, limitcheck (if string is too long or if
+ * we have assigned all possible name indices).
+ */
+int names_ref(P5(name_table * nt, const byte * ptr, uint size, ref * pnref,
+ int enterflag));
+void names_string_ref(P3(const name_table * nt, const ref * pnref, ref * psref));
+
+/*
+ * names_enter_string calls names_ref with a (permanent) C string.
+ */
+int names_enter_string(P3(name_table * nt, const char *str, ref * pnref));
+
+/*
+ * names_from_string essentially implements cvn.
+ * It always enters the name, and copies the executable attribute.
+ */
+int names_from_string(P3(name_table * nt, const ref * psref, ref * pnref));
+
+/* Compare two names for equality. */
+#define names_eq(pnref1, pnref2)\
+ ((pnref1)->value.pname == (pnref2)->value.pname)
+
+/* Invalidate the value cache for a name. */
+void names_invalidate_value_cache(P2(name_table * nt, const ref * pnref));
+
+/* Convert between names and indices. */
+name_index_t names_index(P2(const name_table * nt, const ref * pnref)); /* ref => index */
+name *names_index_ptr(P2(const name_table * nt, name_index_t nidx)); /* index => name */
+void names_index_ref(P3(const name_table * nt, name_index_t nidx, ref * pnref)); /* index => ref */
+
+/* Get the index of the next valid name. */
+/* The argument is 0 or a valid index. */
+/* Return 0 if there are no more. */
+name_index_t names_next_valid_index(P2(name_table * nt, name_index_t nidx));
+
+/* Mark a name for the garbage collector. */
+/* Return true if this is a new mark. */
+bool names_mark_index(P2(name_table * nt, name_index_t nidx));
+
+/* Get the object (sub-table) containing a name. */
+/* The garbage collector needs this so it can relocate pointers to names. */
+void /*obj_header_t */ *
+ names_ref_sub_table(P2(name_table * nt, const ref * pnref));
+void /*obj_header_t */ *
+ names_index_ptr_sub_table(P3(name_table * nt, name_index_t nidx, name * pname));
+
+#endif /* inames_INCLUDED */
diff --git a/pstoraster/interp.c b/pstoraster/interp.c
new file mode 100644
index 000000000..0cf33ba9a
--- /dev/null
+++ b/pstoraster/interp.c
@@ -0,0 +1,1554 @@
+/* Copyright (C) 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$ */
+/* Ghostscript language interpreter */
+#include "memory_.h"
+#include "string_.h"
+#include "ghost.h"
+#include "gsstruct.h" /* for iastruct.h */
+#include "stream.h"
+#include "errors.h"
+#include "estack.h"
+#include "ialloc.h"
+#include "iastruct.h"
+#include "icontext.h"
+#include "inamedef.h"
+#include "iname.h" /* for the_name_table */
+#include "interp.h"
+#include "ipacked.h"
+#include "ostack.h" /* must precede iscan.h */
+#include "strimpl.h" /* for sfilter.h */
+#include "sfilter.h" /* for iscan.h */
+#include "iscan.h"
+#include "idict.h"
+#include "isave.h"
+#include "istack.h"
+#include "iutil.h" /* for array_get */
+#include "ivmspace.h"
+#include "dstack.h"
+#include "files.h" /* for file_check_read */
+#include "oper.h"
+#include "store.h"
+
+/*
+ * We may or may not optimize the handling of the special fast operators
+ * in packed arrays. If we do this, they run much faster when packed, but
+ * slightly slower when not packed.
+ */
+#define PACKED_SPECIAL_OPS 1
+
+/*
+ * Pseudo-operators (procedures of type t_oparray) record
+ * the operand and dictionary stack pointers, and restore them if an error
+ * occurs during the execution of the procedure and if the procedure hasn't
+ * (net) decreased the depth of the stack. While this obviously doesn't
+ * do all the work of restoring the state if a pseudo-operator gets an
+ * error, it's a big help. The only downside is that pseudo-operators run
+ * a little slower.
+ */
+
+/* Imported operator procedures */
+extern int zop_add(P1(os_ptr));
+extern int zop_def(P1(os_ptr));
+extern int zop_sub(P1(os_ptr));
+
+/* Other imported procedures */
+extern int ztokenexec_continue(P1(os_ptr));
+
+/*
+ * The procedure to call if an operator requests rescheduling.
+ * This causes an error unless the context machinery has been installed.
+ */
+private int
+no_reschedule(void)
+{
+ return_error(e_invalidcontext);
+}
+int (*gs_interp_reschedule_proc) (P0()) = no_reschedule;
+
+/*
+ * The procedure to call for time-slicing.
+ * This is a no-op unless the context machinery has been installed.
+ */
+int
+no_time_slice_proc(void)
+{
+ return 0;
+}
+int (*gs_interp_time_slice_proc) (P0()) = no_time_slice_proc;
+
+/*
+ * The number of interpreter "ticks" between calls on the time_slice_proc.
+ * Currently, the clock ticks before each operator, and at each
+ * procedure return.
+ */
+int gs_interp_time_slice_ticks = 0x7fff;
+
+/*
+ * Apply an operator. When debugging, we route all operator calls
+ * through a procedure.
+ */
+#ifdef DEBUG
+private int
+call_operator(int (*op_proc) (P1(os_ptr)), os_ptr op)
+{
+ int code = (*op_proc) (op);
+
+ return code;
+}
+#else
+# define call_operator(proc, op) ((*(proc))(op))
+#endif
+
+/* Forward references */
+private int estack_underflow(P1(os_ptr));
+private int interp(P2(ref *, ref *));
+private int interp_exit(P1(os_ptr));
+private void set_gc_signal(P2(int *, int));
+private int copy_stack(P2(const ref_stack *, ref *));
+private int oparray_pop(P1(os_ptr));
+private int oparray_cleanup(P1(os_ptr));
+
+/* Stack sizes */
+
+/* The maximum stack sizes may all be set in the makefile. */
+
+/*
+ * Define the initial maximum size of the operand stack (MaxOpStack
+ * user parameter).
+ */
+#ifndef MAX_OSTACK
+# define MAX_OSTACK 800
+#endif
+/*
+ * The minimum block size for extending the operand stack is the larger of:
+ * - the maximum number of parameters to an operator
+ * (currently setcolorscreen, with 12 parameters);
+ * - the maximum number of values pushed by an operator
+ * (currently setcolortransfer, which calls zcolor_remap_one 4 times
+ * and therefore pushes 16 values).
+ */
+#define MIN_BLOCK_OSTACK 16
+const int gs_interp_max_op_num_args = MIN_BLOCK_OSTACK; /* for iinit.c */
+
+/*
+ * Define the initial maximum size of the execution stack (MaxExecStack
+ * user parameter).
+ */
+#ifndef MAX_ESTACK
+# define MAX_ESTACK 250
+#endif
+/*
+ * The minimum block size for extending the execution stack is the largest
+ * size of a contiguous block surrounding an e-stack mark, currently ???.
+ * At least, that's what the minimum value would be if we supported
+ * multi-block estacks, which we currently don't.
+ */
+#define MIN_BLOCK_ESTACK MAX_ESTACK
+
+/*
+ * Define the initial maximum size of the dictionary stack (MaxDictStack
+ * user parameter). Again, this is also currently the block size for
+ * extending the d-stack.
+ */
+#ifndef MAX_DSTACK
+# define MAX_DSTACK 20
+#endif
+/*
+ * The minimum block size for extending the dictionary stack is the number
+ * of permanent entries on the dictionary stack, currently 3.
+ */
+#define MIN_BLOCK_DSTACK 3
+
+/* Interpreter state variables */
+ref ref_language_level; /* 1 or 2, set by iinit.c */
+
+/* See estack.h for a description of the execution stack. */
+
+/* The logic for managing icount and iref below assumes that */
+/* there are no control operators which pop and then push */
+/* information on the execution stack. */
+
+/* Stacks */
+extern_st(st_ref_stack);
+#define OS_GUARD_UNDER 10
+#define OS_GUARD_OVER 10
+#define OS_REFS_SIZE(body_size)\
+ (stack_block_refs + OS_GUARD_UNDER + (body_size) + OS_GUARD_OVER)
+op_stack_t iop_stack;
+
+#define ES_GUARD_UNDER 1
+#define ES_GUARD_OVER 10
+#define ES_REFS_SIZE(body_size)\
+ (stack_block_refs + ES_GUARD_UNDER + (body_size) + ES_GUARD_OVER)
+exec_stack_t iexec_stack;
+
+#define DS_REFS_SIZE(body_size)\
+ (stack_block_refs + (body_size))
+dict_stack_t idict_stack;
+
+ /*#define d_stack (idict_stack.stack) *//* in dstack.h */
+
+/* Define a pointer to the current interpreter context state. */
+gs_context_state_t *gs_interp_context_state_current;
+
+/* Extended types. The interpreter may replace the type of operators */
+/* in procedures with these, to speed up the interpretation loop. */
+/****** NOTE: If you add or change entries in this list, */
+/****** you must change the three dispatches in the interpreter loop. */
+/* The operator procedures are declared in opextern.h. */
+#define tx_op t_next_index
+private const op_proc_p special_ops[] =
+{
+ zadd, zdef, zdup, zexch, zif, zifelse, zindex, zpop, zroll, zsub
+};
+typedef enum {
+ tx_op_add = tx_op,
+ tx_op_def,
+ tx_op_dup,
+ tx_op_exch,
+ tx_op_if,
+ tx_op_ifelse,
+ tx_op_index,
+ tx_op_pop,
+ tx_op_roll,
+ tx_op_sub,
+ tx_next_op
+} special_op_types;
+
+#define num_special_ops ((int)tx_next_op - tx_op)
+const int gs_interp_num_special_ops = num_special_ops; /* for iinit.c */
+const int tx_next_index = tx_next_op;
+
+#define make_null_proc(pref)\
+ make_empty_const_array(pref, a_executable + a_readonly)
+
+/* Initialize the interpreter. */
+void
+gs_interp_init(void)
+{ /* Create and initialize a ocntext state. */
+ gs_context_state_t *pcst = 0;
+ int code = context_state_alloc(&pcst, &gs_imemory);
+
+ if (code < 0 || (code = context_state_load(pcst)) < 0) {
+ lprintf1("Fatal error %d in gs_interp_init!", code);
+/****** ABORT ******/
+ }
+ gs_interp_context_state_current = pcst;
+ gs_register_struct_root(imemory_local, NULL,
+ (void **)&gs_interp_context_state_current,
+ "gs_interp_init(gs_icst_root)");
+}
+/*
+ * Create initial stacks for the interpreter.
+ * We export this for creating new contexts.
+ */
+int
+gs_interp_alloc_stacks(gs_ref_memory_t * smem, gs_context_state_t * pcst)
+{
+ ref stk;
+
+#define REFS_SIZE_OSTACK OS_REFS_SIZE(MAX_OSTACK)
+#define REFS_SIZE_ESTACK ES_REFS_SIZE(MAX_ESTACK)
+#define REFS_SIZE_DSTACK DS_REFS_SIZE(MAX_DSTACK)
+ gs_alloc_ref_array(smem, &stk, 0,
+ REFS_SIZE_OSTACK + REFS_SIZE_ESTACK +
+ REFS_SIZE_DSTACK, "gs_interp_alloc_stacks");
+
+ {
+ ref_stack *pos = pcst->ostack =
+ gs_alloc_struct((gs_memory_t *) smem, ref_stack, &st_ref_stack,
+ "gs_interp_alloc_stacks(ostack)");
+
+ r_set_size(&stk, REFS_SIZE_OSTACK);
+ ref_stack_init(pos, &stk, OS_GUARD_UNDER, OS_GUARD_OVER, NULL,
+ smem);
+ pos->underflow_error = e_stackunderflow;
+ pos->overflow_error = e_stackoverflow;
+ ref_stack_set_max_count(pos, MAX_OSTACK);
+ }
+
+ {
+ ref_stack *pes = pcst->estack =
+ gs_alloc_struct((gs_memory_t *) smem, ref_stack, &st_ref_stack,
+ "gs_interp_alloc_stacks(estack)");
+ ref euop;
+
+ stk.value.refs += REFS_SIZE_OSTACK;
+ r_set_size(&stk, REFS_SIZE_ESTACK);
+ make_oper(&euop, 0, estack_underflow);
+ ref_stack_init(pes, &stk, ES_GUARD_UNDER, ES_GUARD_OVER, &euop,
+ smem);
+ pes->underflow_error = e_ExecStackUnderflow;
+ pes->overflow_error = e_execstackoverflow;
+/**************** E-STACK EXPANSION IS NYI. ****************/
+ pes->allow_expansion = false;
+ ref_stack_set_max_count(pes, MAX_ESTACK);
+ }
+
+ {
+ ref_stack *pds = pcst->dstack =
+ gs_alloc_struct((gs_memory_t *) smem, ref_stack, &st_ref_stack,
+ "gs_interp_alloc_stacks(dstack)");
+
+ stk.value.refs += REFS_SIZE_ESTACK;
+ r_set_size(&stk, REFS_SIZE_DSTACK);
+ ref_stack_init(pds, &stk, 0, 0, NULL, smem);
+ pds->underflow_error = e_dictstackunderflow;
+ pds->overflow_error = e_dictstackoverflow;
+ ref_stack_set_max_count(pds, MAX_DSTACK);
+ }
+
+#undef REFS_SIZE_OSTACK
+#undef REFS_SIZE_ESTACK
+#undef REFS_SIZE_DSTACK
+ return 0;
+}
+/*
+ * Free the stacks when destroying a context. This is the inverse of
+ * create_stacks.
+ */
+void
+gs_interp_free_stacks(gs_ref_memory_t * smem, gs_context_state_t * pcst)
+{ /* Free the stacks in inverse order of allocation. */
+ ref_stack_free(pcst->dstack, (gs_memory_t *) smem,
+ "gs_interp_free_stacks(dstack)");
+ ref_stack_free(pcst->estack, (gs_memory_t *) smem,
+ "gs_interp_free_stacks(estack)");
+ ref_stack_free(pcst->ostack, (gs_memory_t *) smem,
+ "gs_interp_free_stacks(ostack)");
+}
+void
+gs_interp_reset(void)
+{ /* Reset the stacks. */
+ ref_stack_clear(&o_stack);
+ ref_stack_clear(&e_stack);
+ esp++;
+ make_oper(esp, 0, interp_exit);
+ ref_stack_pop_to(&d_stack, min_dstack_size);
+ dict_set_top();
+}
+/* Report an e-stack block underflow. The bottom guard slots of */
+/* e-stack blocks contain a pointer to this procedure. */
+private int
+estack_underflow(os_ptr op)
+{
+ return e_ExecStackUnderflow;
+}
+
+/*
+ * Create an operator during initialization.
+ * If operator is hard-coded into the interpreter,
+ * assign it a special type and index.
+ */
+void
+gs_interp_make_oper(ref * opref, op_proc_p proc, int idx)
+{
+ register int i = num_special_ops;
+
+ while (--i >= 0 && proc != special_ops[i]);
+ if (i >= 0)
+ make_tasv(opref, tx_op + i, a_executable, i + 1, opproc, proc);
+ else
+ make_tasv(opref, t_operator, a_executable, idx, opproc, proc);
+}
+
+/*
+ * Invoke the interpreter. If execution completes normally, return 0.
+ * If an error occurs, the action depends on user_errors as follows:
+ * user_errors < 0: always return an error code.
+ * user_errors >= 0: let the PostScript machinery handle all errors.
+ * (This will eventually result in a fatal error if no 'stopped'
+ * is active.)
+ * In case of a quit or a fatal error, also store the exit code.
+ */
+private int gs_call_interp(P4(ref *, int, int *, ref *));
+int
+gs_interpret(ref * pref, int user_errors, int *pexit_code, ref * perror_object)
+{
+ gs_gc_root_t error_root;
+ int code;
+
+ gs_register_ref_root(imemory_system, &error_root,
+ (void **)&perror_object, "gs_interpret");
+ /* Initialize the error object in case of GC. */
+ make_null(perror_object);
+ code = gs_call_interp(pref, user_errors, pexit_code, perror_object);
+ gs_unregister_root(imemory_system, &error_root, "gs_interpret");
+ /* Avoid a dangling reference to a stack-allocated GC signal. */
+ set_gc_signal(NULL, 0);
+ return code;
+}
+private int
+gs_call_interp(ref * pref, int user_errors, int *pexit_code, ref * perror_object)
+{
+ ref *epref = pref;
+ ref doref;
+ ref *perrordict;
+ ref error_name;
+ int code, ccode;
+ ref saref;
+ int gc_signal = 0;
+
+ *pexit_code = 0;
+ ialloc_reset_requested(idmemory);
+ again:o_stack.requested = e_stack.requested = d_stack.requested = 0;
+ while (gc_signal) { /* Some routine below triggered a GC. */
+ gs_gc_root_t epref_root;
+
+ gc_signal = 0;
+ /* Make sure that doref will get relocated properly if */
+ /* a garbage collection happens with epref == &doref. */
+ gs_register_ref_root(imemory_system, &epref_root,
+ (void **)&epref,
+ "gs_call_interpret(epref)");
+ code = (*idmemory->reclaim) (idmemory, -1);
+ gs_unregister_root(imemory_system, &epref_root,
+ "gs_call_interpret(epref)");
+ if (code < 0)
+ return code;
+ }
+ code = interp(epref, perror_object);
+ /* Prevent a dangling reference to the GC signal in ticks_left */
+ /* in the frame of interp, but be prepared to do a GC if */
+ /* an allocation in this routine asks for it. */
+ set_gc_signal(&gc_signal, 1);
+ if (esp < esbot) /* popped guard entry */
+ esp = esbot;
+ switch (code) {
+ case e_Fatal:
+ *pexit_code = 255;
+ return code;
+ case e_Quit:
+ *perror_object = osp[-1];
+ *pexit_code = code = osp->value.intval;
+ osp -= 2;
+ return
+ (code == 0 ? e_Quit :
+ code < 0 && code > -100 ? code : e_Fatal);
+ case e_InterpreterExit:
+ return 0;
+ case e_ExecStackUnderflow:
+/****** WRONG -- must keep mark blocks intact ******/
+ ref_stack_pop_block(&e_stack);
+ doref = *perror_object;
+ epref = &doref;
+ goto again;
+ case e_VMreclaim:
+ /* Do the GC and continue. */
+ code = (*idmemory->reclaim) (idmemory,
+ (osp->value.intval == 2 ?
+ avm_global : avm_local));
+/****** What if code < 0? ******/
+ make_oper(&doref, 0, zpop);
+ epref = &doref;
+ goto again;
+ case e_NeedInput:
+ return code;
+ }
+ /* Adjust osp in case of operand stack underflow */
+ if (osp < osbot - 1)
+ osp = osbot - 1;
+ /* We have to handle stack over/underflow specially, because */
+ /* we might be able to recover by adding or removing a block. */
+ switch (code) {
+ case e_dictstackoverflow:
+ if (ref_stack_extend(&d_stack, d_stack.requested) >= 0) {
+ dict_set_top();
+ doref = *perror_object;
+ epref = &doref;
+ goto again;
+ }
+ if (osp >= ostop) {
+ if ((ccode = ref_stack_extend(&o_stack, 1)) < 0)
+ return ccode;
+ }
+ ccode = copy_stack(&d_stack, &saref);
+ if (ccode < 0)
+ return ccode;
+ ref_stack_pop_to(&d_stack, min_dstack_size);
+ dict_set_top();
+ *++osp = saref;
+ break;
+ case e_dictstackunderflow:
+ if (ref_stack_pop_block(&d_stack) >= 0) {
+ dict_set_top();
+ doref = *perror_object;
+ epref = &doref;
+ goto again;
+ }
+ break;
+ case e_execstackoverflow:
+ /* We don't have to handle this specially: */
+ /* The only places that could generate it */
+ /* use check_estack, which does a ref_stack_extend, */
+ /* so if we get this error, it's a real one. */
+ if (osp >= ostop) {
+ if ((ccode = ref_stack_extend(&o_stack, 1)) < 0)
+ return ccode;
+ }
+ ccode = copy_stack(&e_stack, &saref);
+ if (ccode < 0)
+ return ccode;
+ {
+ uint count = ref_stack_count(&e_stack);
+ long limit = ref_stack_max_count(&e_stack) - 10;
+
+ if (count > limit)
+ pop_estack(count - limit);
+ }
+ *++osp = saref;
+ break;
+ case e_stackoverflow:
+ if (ref_stack_extend(&o_stack, o_stack.requested) >= 0) { /* We can't just re-execute the object, because */
+ /* it might be a procedure being pushed as a */
+ /* literal. We check for this case specially. */
+ doref = *perror_object;
+ if (r_is_proc(&doref)) {
+ *++osp = doref;
+ make_null_proc(&doref);
+ }
+ epref = &doref;
+ goto again;
+ }
+ ccode = copy_stack(&o_stack, &saref);
+ if (ccode < 0)
+ return ccode;
+ ref_stack_clear(&o_stack);
+ *++osp = saref;
+ break;
+ case e_stackunderflow:
+ if (ref_stack_pop_block(&o_stack) >= 0) {
+ doref = *perror_object;
+ epref = &doref;
+ goto again;
+ }
+ break;
+ }
+ if (user_errors < 0)
+ return code;
+ if (gs_errorname(code, &error_name) < 0)
+ return code; /* out-of-range error code! */
+ if (dict_find_string(systemdict, "errordict", &perrordict) <= 0 ||
+ dict_find(perrordict, &error_name, &epref) <= 0
+ )
+ return code; /* error name not in errordict??? */
+ doref = *epref;
+ epref = &doref;
+ /* Push the error object on the operand stack if appropriate. */
+ if (!error_is_interrupt(code))
+ *++osp = *perror_object;
+ goto again;
+}
+private int
+interp_exit(os_ptr op)
+{
+ return e_InterpreterExit;
+}
+
+/* Set the GC signal for all VMs. */
+private void
+set_gc_signal(int *psignal, int value)
+{
+ gs_memory_gc_status_t stat;
+ int i;
+
+ for (i = 0; i < countof(idmemory->spaces.indexed); i++) {
+ gs_ref_memory_t *mem = idmemory->spaces.indexed[i];
+
+ if (mem != 0) {
+ gs_memory_gc_status(mem, &stat);
+ stat.psignal = psignal;
+ stat.signal_value = value;
+ gs_memory_set_gc_status(mem, &stat);
+ }
+ }
+}
+
+/* Copy the contents of an overflowed stack into a (local) array. */
+private int
+copy_stack(const ref_stack * pstack, ref * arr)
+{
+ uint size = ref_stack_count(pstack);
+ uint save_space = ialloc_space(idmemory);
+ int code;
+
+ ialloc_set_space(idmemory, avm_local);
+ code = ialloc_ref_array(arr, a_all, size, "copy_stack");
+ if (code >= 0)
+ code = ref_stack_store(pstack, arr, size, 0, 1, true, "copy_stack");
+ ialloc_set_space(idmemory, save_space);
+ return code;
+}
+
+/* Get the name corresponding to an error number. */
+int
+gs_errorname(int code, ref * perror_name)
+{
+ ref *perrordict, *pErrorNames;
+
+ if (dict_find_string(systemdict, "errordict", &perrordict) <= 0 ||
+ dict_find_string(systemdict, "ErrorNames", &pErrorNames) <= 0
+ )
+ return_error(e_undefined); /* errordict or ErrorNames not found?! */
+ return array_get(pErrorNames, (long)(-code - 1), perror_name);
+}
+
+/* Store an error string in $error.errorinfo. */
+/* This routine is here because of the proximity to the error handler. */
+int
+gs_errorinfo_put_string(const char *str)
+{
+ ref rstr;
+ ref *pderror;
+ int code = string_to_ref(str, &rstr, iimemory, "gs_errorinfo_put_string");
+
+ if (code < 0)
+ return code;
+ if (dict_find_string(systemdict, "$error", &pderror) <= 0 ||
+ !r_has_type(pderror, t_dictionary) ||
+ dict_put_string(pderror, "errorinfo", &rstr) < 0
+ )
+ return_error(e_Fatal);
+ return 0;
+}
+
+/* Main interpreter. */
+/* If execution terminates normally, return e_InterpreterExit. */
+/* If an error occurs, leave the current object in *perror_object */
+/* and return a (negative) error code. */
+private int
+interp(ref * pref /* object to interpret */ , ref * perror_object)
+{ /*
+ * Note that iref is declared as a ref *, but it may actually be
+ * a ref_packed *.
+ */
+ register const ref *iref = pref;
+ register int icount = 0; /* # of consecutive tokens at iref */
+ register os_ptr iosp = osp; /* private copy of osp */
+ register es_ptr iesp = esp; /* private copy of esp */
+ int code;
+ ref token; /* token read from file or string, */
+
+ /* must be declared in this scope */
+ register const ref *pvalue;
+ os_ptr whichp;
+
+ /*
+ * We have to make the error information into a struct;
+ * otherwise, the Watcom compiler will assign it to registers
+ * strictly on the basis of textual frequency.
+ * We also have to use ref_assign_inline everywhere, and
+ * avoid direct assignments of refs, so that esi and edi
+ * will remain available on Intel processors.
+ */
+ struct interp_error_s {
+ int code;
+ int line;
+ const ref *obj;
+ ref full;
+ } ierror;
+
+ /*
+ * Get a pointer to the name table so that we can use the
+ * inline version of name_index_ref.
+ */
+ const name_table *const int_nt = the_name_table();
+
+#define set_error(ecode)\
+ { ierror.code = ecode; ierror.line = __LINE__; }
+#define return_with_error(ecode, objp)\
+ { set_error(ecode); ierror.obj = objp; goto rwe; }
+#define return_with_error_iref(ecode)\
+ { set_error(ecode); goto rwei; }
+#define return_with_code_iref()\
+ { ierror.line = __LINE__; goto rweci; }
+#define return_with_error_code_op(nargs)\
+ return_with_code_iref()
+#define return_with_stackoverflow(objp)\
+ { o_stack.requested = 1; return_with_error(e_stackoverflow, objp); }
+#define return_with_stackoverflow_iref()\
+ { o_stack.requested = 1; return_with_error_iref(e_stackoverflow); }
+ int ticks_left = gs_interp_time_slice_ticks;
+
+ /*
+ * If we exceed the VMThreshold, set ticks_left to -1
+ * to alert the interpreter that we need to garbage collect.
+ */
+ set_gc_signal(&ticks_left, -100);
+
+ esfile_clear_cache();
+ /*
+ * From here on, if icount > 0, iref and icount correspond
+ * to the top entry on the execution stack: icount is the count
+ * of sequential entries remaining AFTER the current one.
+ */
+#define add1_short(pref) (const ref *)((const ushort *)(pref) + 1)
+#define add1_either(pref) (r_is_packed(pref) ? add1_short(pref) : (pref) + 1)
+#define store_state(ep)\
+ ( icount > 0 ? (ep->value.const_refs = iref + 1, r_set_size(ep, icount)) : 0 )
+#define store_state_short(ep)\
+ ( icount > 0 ? (ep->value.const_refs = add1_short(iref), r_set_size(ep, icount)) : 0 )
+#define store_state_either(ep)\
+ ( icount > 0 ? (ep->value.const_refs = add1_either(iref), r_set_size(ep, icount)) : 0 )
+#define next()\
+ if ( --icount > 0 ) { iref++; goto top; } else goto out
+#define next_short()\
+ if ( --icount <= 0 ) { if ( icount < 0 ) goto up; iesp--; }\
+ iref = add1_short(iref); goto top
+#define next_either()\
+ if ( --icount <= 0 ) { if ( icount < 0 ) goto up; iesp--; }\
+ iref = add1_either(iref); goto top
+
+#if !PACKED_SPECIAL_OPS
+# undef next_either
+# define next_either() next()
+# undef store_state_either
+# define store_state_either(ep) store_state(ep)
+#endif
+
+ /* We want to recognize executable arrays here, */
+ /* so we push the argument on the estack and enter */
+ /* the loop at the bottom. */
+ if (iesp >= estop)
+ return_with_error(e_execstackoverflow, pref);
+ ++iesp;
+ ref_assign_inline(iesp, pref);
+ goto bot;
+ top: /*
+ * This is the top of the interpreter loop.
+ * iref points to the ref being interpreted.
+ * Note that this might be an element of a packed array,
+ * not a real ref: we carefully arranged the first 16 bits of
+ * a ref and of a packed array element so they could be distinguished
+ * from each other. (See ghost.h and packed.h for more detail.)
+ */
+#ifdef DEBUG
+ /* Do a little validation on the top o-stack entry. */
+ if (iosp >= osbot &&
+ (r_type(iosp) == t__invalid || r_type(iosp) >= tx_next_op)
+ ) {
+ lprintf("Invalid value on o-stack!\n");
+ return_with_error_iref(e_Fatal);
+ }
+ if (gs_debug['I'] ||
+ (gs_debug['i'] &&
+ (r_is_packed(iref) ?
+ r_packed_is_name((const ref_packed *)iref) :
+ r_has_type(iref, t_name)))
+ ) {
+ void debug_print_ref(P1(const ref *));
+ os_ptr save_osp = osp; /* avoid side-effects */
+ es_ptr save_esp = esp;
+ int edepth;
+ char depth[10];
+
+ osp = iosp;
+ esp = iesp;
+ edepth = ref_stack_count(&e_stack);
+ sprintf(depth, "%2d", edepth);
+ dputs(depth);
+ for (edepth -= strlen(depth); edepth >= 5; edepth -= 5)
+ dputc('*'); /* indent */
+ for (; edepth > 0; --edepth)
+ dputc('.');
+ dlprintf3("0x%lx(%d)<%d>: ",
+ (ulong) iref, icount, ref_stack_count(&o_stack));
+ debug_print_ref(iref);
+ if (iosp >= osbot) {
+ dputs(" // ");
+ debug_print_ref(iosp);
+ }
+ dputc('\n');
+ osp = save_osp;
+ esp = save_esp;
+ fflush(dstderr);
+ }
+#endif
+/* Objects that have attributes (arrays, dictionaries, files, and strings) */
+/* use lit and exec; other objects use plain and plain_exec. */
+#define lit(t) type_xe_value(t, a_execute)
+#define exec(t) type_xe_value(t, a_execute + a_executable)
+#define nox(t) type_xe_value(t, 0)
+#define nox_exec(t) type_xe_value(t, a_executable)
+#define plain(t) type_xe_value(t, 0)
+#define plain_exec(t) type_xe_value(t, a_executable)
+ /*
+ * We have to populate enough cases of the switch statement to force
+ * some compilers to use a dispatch rather than a testing loop.
+ * What a nuisance!
+ */
+ switch (r_type_xe(iref)) {
+ /* Access errors. */
+#define cases_invalid()\
+ case plain(t__invalid): case plain_exec(t__invalid)
+ cases_invalid():
+ return_with_error_iref(e_Fatal);
+#define cases_nox()\
+ case nox_exec(t_array): case nox_exec(t_dictionary):\
+ case nox_exec(t_file): case nox_exec(t_string):\
+ case nox_exec(t_mixedarray): case nox_exec(t_shortarray)
+ cases_nox():
+ return_with_error_iref(e_invalidaccess);
+ /*
+ * Literal objects. We have to enumerate all the types.
+ * In fact, we have to include some extra plain_exec entries
+ * just to populate the switch. We break them up into groups
+ * to avoid overflowing some preprocessors.
+ */
+#define cases_lit_1()\
+ case lit(t_array): case nox(t_array):\
+ case plain(t_boolean): case plain_exec(t_boolean):\
+ case lit(t_dictionary): case nox(t_dictionary)
+#define cases_lit_2()\
+ case lit(t_file): case nox(t_file):\
+ case plain(t_fontID): case plain_exec(t_fontID):\
+ case plain(t_integer): case plain_exec(t_integer):\
+ case plain(t_mark): case plain_exec(t_mark)
+#define cases_lit_3()\
+ case plain(t_name):\
+ case plain(t_null):\
+ case plain(t_oparray):\
+ case plain(t_operator)
+#define cases_lit_4()\
+ case plain(t_real): case plain_exec(t_real):\
+ case plain(t_save): case plain_exec(t_save):\
+ case lit(t_string): case nox(t_string)
+#define cases_lit_5()\
+ case lit(t_mixedarray): case nox(t_mixedarray):\
+ case lit(t_shortarray): case nox(t_shortarray):\
+ case plain(t_device): case plain_exec(t_device):\
+ case plain(t_struct): case plain_exec(t_struct):\
+ case plain(t_astruct): case plain_exec(t_astruct)
+ /* Executable arrays are treated as literals in direct execution. */
+#define cases_lit_array()\
+ case exec(t_array): case exec(t_mixedarray): case exec(t_shortarray)
+ cases_lit_1():
+ cases_lit_2():
+ cases_lit_3():
+ cases_lit_4():
+ cases_lit_5():
+ cases_lit_array():
+ break;
+ /* Special operators. */
+ case plain_exec(tx_op_add):
+ x_add:if ((code = zop_add(iosp)) < 0)
+ return_with_error_code_op(2);
+ iosp--;
+ next_either();
+ case plain_exec(tx_op_def):
+ x_def:if ((code = zop_def(iosp)) < 0)
+ return_with_error_code_op(2);
+ iosp -= 2;
+ next_either();
+ case plain_exec(tx_op_dup):
+ x_dup:if (iosp < osbot)
+ return_with_error_iref(e_stackunderflow);
+ if (iosp >= ostop)
+ return_with_stackoverflow_iref();
+ iosp++;
+ ref_assign_inline(iosp, iosp - 1);
+ next_either();
+ case plain_exec(tx_op_exch):
+ x_exch:if (iosp <= osbot)
+ return_with_error_iref(e_stackunderflow);
+ ref_assign_inline(&token, iosp);
+ ref_assign_inline(iosp, iosp - 1);
+ ref_assign_inline(iosp - 1, &token);
+ next_either();
+ case plain_exec(tx_op_if):
+ x_if:if (!r_has_type(iosp - 1, t_boolean))
+ return_with_error_iref((iosp <= osbot ?
+ e_stackunderflow : e_typecheck));
+ if (!r_is_proc(iosp))
+ return_with_error_iref(check_proc_failed(iosp));
+ if (!iosp[-1].value.boolval) {
+ iosp -= 2;
+ next_either();
+ }
+ if (iesp >= estop)
+ return_with_error_iref(e_execstackoverflow);
+ store_state_either(iesp);
+ whichp = iosp;
+ iosp -= 2;
+ goto ifup;
+ case plain_exec(tx_op_ifelse):
+ x_ifelse:if (!r_has_type(iosp - 2, t_boolean))
+ return_with_error_iref((iosp < osbot + 2 ?
+ e_stackunderflow : e_typecheck));
+ if (!r_is_proc(iosp - 1))
+ return_with_error_iref(check_proc_failed(iosp - 1));
+ if (!r_is_proc(iosp))
+ return_with_error_iref(check_proc_failed(iosp));
+ if (iesp >= estop)
+ return_with_error_iref(e_execstackoverflow);
+ store_state_either(iesp);
+ whichp = (iosp[-2].value.boolval ? iosp - 1 : iosp);
+ iosp -= 3;
+ /* Open code "up" for the array case(s) */
+ ifup:if ((icount = r_size(whichp) - 1) <= 0) {
+ if (icount < 0)
+ goto up; /* 0-element proc */
+ iref = whichp->value.refs; /* 1-element proc */
+ if (--ticks_left > 0)
+ goto top;
+ }
+ ++iesp;
+ /* Do a ref_assign, but also set iref. */
+ iesp->tas = whichp->tas;
+ iref = iesp->value.refs = whichp->value.refs;
+ if (--ticks_left > 0)
+ goto top;
+ goto slice;
+ case plain_exec(tx_op_index):
+ x_index:osp = iosp; /* zindex references o_stack */
+ if ((code = zindex(iosp)) < 0)
+ return_with_error_code_op(1);
+ next_either();
+ case plain_exec(tx_op_pop):
+ x_pop:if (iosp < osbot)
+ return_with_error_iref(e_stackunderflow);
+ iosp--;
+ next_either();
+ case plain_exec(tx_op_roll):
+ x_roll:osp = iosp; /* zroll references o_stack */
+ if ((code = zroll(iosp)) < 0)
+ return_with_error_code_op(2);
+ iosp -= 2;
+ next_either();
+ case plain_exec(tx_op_sub):
+ x_sub:if ((code = zop_sub(iosp)) < 0)
+ return_with_error_code_op(2);
+ iosp--;
+ next_either();
+ /* Executable types. */
+ case plain_exec(t_null):
+ goto bot;
+ case plain_exec(t_oparray):
+ /* Replace with the definition and go again. */
+ pvalue = (const ref *)iref->value.const_refs;
+ opst: /* Prepare to call a t_oparray procedure in *pvalue. */
+ store_state(iesp);
+ oppr: /* Record the stack depths in case of failure. */
+ if (iesp >= estop - 3)
+ return_with_error_iref(e_execstackoverflow);
+ iesp += 4;
+ osp = iosp; /* ref_stack_count_inline needs this */
+ make_mark_estack(iesp - 3, es_other, oparray_cleanup);
+ make_int(iesp - 2, ref_stack_count_inline(&o_stack));
+ make_int(iesp - 1, ref_stack_count_inline(&d_stack));
+ make_op_estack(iesp, oparray_pop);
+ goto pr;
+ prst: /* Prepare to call the procedure (array) in *pvalue. */
+ store_state(iesp);
+ pr: /* Call the array in *pvalue. State has been stored. */
+ if ((icount = r_size(pvalue) - 1) <= 0) {
+ if (icount < 0)
+ goto up; /* 0-element proc */
+ iref = pvalue->value.refs; /* 1-element proc */
+ if (--ticks_left > 0)
+ goto top;
+ }
+ if (iesp >= estop)
+ return_with_error_iref(e_execstackoverflow);
+ ++iesp;
+ /* Do a ref_assign, but also set iref. */
+ iesp->tas = pvalue->tas;
+ iref = iesp->value.refs = pvalue->value.refs;
+ if (--ticks_left > 0)
+ goto top;
+ goto slice;
+ case plain_exec(t_operator):
+ if (--ticks_left <= 0) { /* The following doesn't work, */
+ /* and I can't figure out why. */
+/****** goto sst; ******/
+ }
+ esp = iesp; /* save for operator */
+ osp = iosp; /* ditto */
+ /* Operator routines take osp as an argument. */
+ /* This is just a convenience, since they adjust */
+ /* osp themselves to reflect the results. */
+ /* Operators that (net) push information on the */
+ /* operand stack must check for overflow: */
+ /* this normally happens automatically through */
+ /* the push macro (in oper.h). */
+ /* Operators that do not typecheck their operands, */
+ /* or take a variable number of arguments, */
+ /* must check explicitly for stack underflow. */
+ /* (See oper.h for more detail.) */
+ /* Note that each case must set iosp = osp: */
+ /* this is so we can switch on code without having to */
+ /* store it and reload it (for dumb compilers). */
+ switch (code = call_operator(real_opproc(iref), iosp)) {
+ case 0: /* normal case */
+ case 1: /* alternative success case */
+ iosp = osp;
+ next();
+ case o_push_estack: /* store the state and go to up */
+ store_state(iesp);
+ opush:iosp = osp;
+ iesp = esp;
+ if (--ticks_left > 0)
+ goto up;
+ goto slice;
+ case o_pop_estack: /* just go to up */
+ opop:iosp = osp;
+ if (esp == iesp)
+ goto bot;
+ iesp = esp;
+ goto up;
+ case o_reschedule:
+ store_state(iesp);
+ goto res;
+ case e_InsertProc:
+ store_state(iesp);
+ oeinsert:ref_assign_inline(iesp + 1, iref);
+ /* esp = iesp + 2; *esp = the procedure */
+ iesp = esp;
+ goto up;
+ }
+ iosp = osp;
+ iesp = esp;
+ return_with_code_iref();
+ case plain_exec(t_name):
+ pvalue = iref->value.pname->pvalue;
+ if (!pv_valid(pvalue)) {
+ uint nidx = names_index(int_nt, iref);
+ uint htemp;
+
+ if ((pvalue = dict_find_name_by_index_inline(nidx, htemp)) == 0)
+ return_with_error_iref(e_undefined);
+ }
+ /* Dispatch on the type of the value. */
+ /* Again, we have to over-populate the switch. */
+ switch (r_type_xe(pvalue)) {
+ cases_invalid():
+ return_with_error_iref(e_Fatal);
+ cases_nox(): /* access errors */
+ return_with_error_iref(e_invalidaccess);
+ cases_lit_1():
+ cases_lit_2():
+ cases_lit_3():
+ cases_lit_4():
+ cases_lit_5():
+ /* Just push the value */
+ if (iosp >= ostop)
+ return_with_stackoverflow(pvalue);
+ ++iosp;
+ ref_assign_inline(iosp, pvalue);
+ next();
+ case exec(t_array):
+ case exec(t_mixedarray):
+ case exec(t_shortarray):
+ /* This is an executable procedure, execute it. */
+ goto prst;
+ case plain_exec(tx_op_add):
+ goto x_add;
+ case plain_exec(tx_op_def):
+ goto x_def;
+ case plain_exec(tx_op_dup):
+ goto x_dup;
+ case plain_exec(tx_op_exch):
+ goto x_exch;
+ case plain_exec(tx_op_if):
+ goto x_if;
+ case plain_exec(tx_op_ifelse):
+ goto x_ifelse;
+ case plain_exec(tx_op_index):
+ goto x_index;
+ case plain_exec(tx_op_pop):
+ goto x_pop;
+ case plain_exec(tx_op_roll):
+ goto x_roll;
+ case plain_exec(tx_op_sub):
+ goto x_sub;
+ case plain_exec(t_null):
+ goto bot;
+ case plain_exec(t_oparray):
+ pvalue = (const ref *)pvalue->value.const_refs;
+ goto opst;
+ case plain_exec(t_operator):
+ { /* Shortcut for operators. */
+ /* See above for the logic. */
+ if (--ticks_left <= 0) { /* The following doesn't work, */
+ /* and I can't figure out why. */
+/****** goto sst; ******/
+ }
+ esp = iesp;
+ osp = iosp;
+ switch (code = call_operator(real_opproc(pvalue), iosp)) {
+ case 0: /* normal case */
+ case 1: /* alternative success case */
+ iosp = osp;
+ next();
+ case o_push_estack:
+ store_state(iesp);
+ goto opush;
+ case o_pop_estack:
+ goto opop;
+ case o_reschedule:
+ store_state(iesp);
+ goto res;
+ case e_InsertProc:
+ store_state(iesp);
+ goto oeinsert;
+ }
+ iosp = osp;
+ iesp = esp;
+ return_with_error(code, pvalue);
+ }
+ case plain_exec(t_name):
+ case exec(t_file):
+ case exec(t_string):
+ default:
+ /* Not a procedure, reinterpret it. */
+ store_state(iesp);
+ icount = 0;
+ iref = pvalue;
+ goto top;
+ }
+ case exec(t_file):
+ { /* Executable file. Read the next token and interpret it. */
+ stream *s;
+ scanner_state sstate;
+
+ check_read_known_file(s, iref, return_with_error_iref);
+ rt:if (iosp >= ostop) /* check early */
+ return_with_stackoverflow_iref();
+ osp = iosp; /* scan_token uses ostack */
+ scanner_state_init(&sstate, false);
+ again:code = scan_token(s, &token, &sstate);
+ iosp = osp; /* ditto */
+ switch (code) {
+ case 0: /* read a token */
+ /* It's worth checking for literals, which make up */
+ /* the majority of input tokens, before storing the */
+ /* state on the e-stack. Note that because of //, */
+ /* the token may have *any* type and attributes. */
+ /* Note also that executable arrays aren't executed */
+ /* at the top level -- they're treated as literals. */
+ if (!r_has_attr(&token, a_executable) ||
+ r_is_array(&token)
+ ) { /* If scan_token used the o-stack, */
+ /* we know we can do a push now; if not, */
+ /* the pre-check is still valid. */
+ iosp++;
+ ref_assign_inline(iosp, &token);
+ goto rt;
+ }
+ store_state(iesp);
+ /* Push the file on the e-stack */
+ if (iesp >= estop)
+ return_with_error_iref(e_execstackoverflow);
+ esfile_set_cache(++iesp);
+ ref_assign_inline(iesp, iref);
+ iref = &token;
+ icount = 0;
+ goto top;
+ case scan_EOF: /* end of file */
+ esfile_clear_cache();
+ goto bot;
+ case scan_BOS:
+ /* Binary object sequences */
+ /* ARE executed at the top level. */
+ store_state(iesp);
+ /* Push the file on the e-stack */
+ if (iesp >= estop)
+ return_with_error_iref(e_execstackoverflow);
+ esfile_set_cache(++iesp);
+ ref_assign_inline(iesp, iref);
+ pvalue = &token;
+ goto pr;
+ case scan_Refill:
+ store_state(iesp);
+ /* iref may point into the exec stack; */
+ /* save its referent now. */
+ ref_assign_inline(&token, iref);
+ /* Push the file on the e-stack */
+ if (iesp >= estop)
+ return_with_error_iref(e_execstackoverflow);
+ ++iesp;
+ ref_assign_inline(iesp, &token);
+ esp = iesp;
+ osp = iosp;
+ code = scan_handle_refill(&token, &sstate, true, true,
+ ztokenexec_continue);
+ iosp = osp;
+ iesp = esp;
+ switch (code) {
+ case 0:
+ iesp--; /* don't push the file */
+ goto again; /* stacks are unchanged */
+ case o_push_estack:
+ esfile_clear_cache();
+ if (--ticks_left > 0)
+ goto up;
+ goto slice;
+ }
+ /* must be an error */
+ iesp--; /* don't push the file */
+ default: /* error */
+ return_with_code_iref();
+ }
+ }
+ case exec(t_string):
+ { /* Executable string. Read a token and interpret it. */
+ stream ss;
+ scanner_state sstate;
+
+ scanner_state_init(&sstate, true);
+ sread_string(&ss, iref->value.bytes, r_size(iref));
+ osp = iosp; /* scan_token uses ostack */
+ code = scan_token(&ss, &token, &sstate);
+ iosp = osp; /* ditto */
+ switch (code) {
+ case 0: /* read a token */
+ case scan_BOS: /* binary object sequence */
+ store_state(iesp);
+ /* If the updated string isn't empty, push it back */
+ /* on the e-stack. */
+ {
+ uint size = sbufavailable(&ss);
+
+ if (size) {
+ if (iesp >= estop)
+ return_with_error_iref(e_execstackoverflow);
+ ++iesp;
+ iesp->tas.type_attrs = iref->tas.type_attrs;
+ iesp->value.const_bytes = sbufptr(&ss);
+ r_set_size(iesp, size);
+ }
+ }
+ if (code == 0) {
+ iref = &token;
+ icount = 0;
+ goto top;
+ }
+ /* Handle BOS specially */
+ pvalue = &token;
+ goto pr;
+ case scan_EOF: /* end of string */
+ goto bot;
+ case scan_Refill: /* error */
+ code = gs_note_error(e_syntaxerror);
+ default: /* error */
+ return_with_code_iref();
+ }
+ }
+ /* Handle packed arrays here by re-dispatching. */
+ /* This also picks up some anomalous cases of non-packed arrays. */
+ default:
+ {
+ uint index;
+
+ switch (*PACKED(iref) >> r_packed_type_shift) {
+ case pt_full_ref:
+ case pt_full_ref + 1:
+ if (iosp >= ostop)
+ return_with_stackoverflow_iref();
+ /* We know this can't be an executable object */
+ /* requiring special handling, so we just push it. */
+ ++iosp;
+ /* We know that refs are properly aligned: */
+ /* see packed.h for details. */
+ ref_assign_inline(iosp, iref);
+ next();
+ case pt_executable_operator:
+ index = *PACKED(iref) & packed_value_mask;
+ if (--ticks_left <= 0) { /* The following doesn't work, */
+ /* and I can't figure out why. */
+/****** goto sst_short; ******/
+ }
+ if (!op_index_is_operator(index)) {
+ store_state_short(iesp);
+ /* Call the operator procedure. */
+ index -= op_def_count;
+ pvalue = (const ref *)
+ (index < r_size(&op_array_table_global.table) ?
+ op_array_table_global.table.value.const_refs +
+ index :
+ op_array_table_local.table.value.const_refs +
+ (index - r_size(&op_array_table_global.table)));
+ goto oppr;
+ }
+ /* See the main plain_exec(t_operator) case */
+ /* for details of what happens here. */
+#if PACKED_SPECIAL_OPS
+ /*
+ * We arranged in iinit.c that the special ops
+ * have operator indices starting at 1.
+ *
+ * The (int) cast in the next line is required
+ * because some compilers don't allow arithmetic
+ * involving two different enumerated types.
+ */
+# define case_xop(xop) case xop - (int)tx_op + 1
+ switch (index) {
+ case_xop(tx_op_add):goto x_add;
+ case_xop(tx_op_def):goto x_def;
+ case_xop(tx_op_dup):goto x_dup;
+ case_xop(tx_op_exch):goto x_exch;
+ case_xop(tx_op_if):goto x_if;
+ case_xop(tx_op_ifelse):goto x_ifelse;
+ case_xop(tx_op_index):goto x_index;
+ case_xop(tx_op_pop):goto x_pop;
+ case_xop(tx_op_roll):goto x_roll;
+ case_xop(tx_op_sub):goto x_sub;
+ case 0: /* for dumb compilers */
+ default:
+ ;
+ }
+# undef case_xop
+#endif
+ esp = iesp;
+ osp = iosp;
+ switch (code = call_operator(op_index_proc(index), iosp)) {
+ case 0:
+ case 1:
+ iosp = osp;
+ next_short();
+ case o_push_estack:
+ store_state_short(iesp);
+ goto opush;
+ case o_pop_estack:
+ iosp = osp;
+ if (esp == iesp) {
+ next_short();
+ }
+ iesp = esp;
+ goto up;
+ case o_reschedule:
+ store_state_short(iesp);
+ goto res;
+ case e_InsertProc:
+ store_state_short(iesp);
+ packed_get((const ref_packed *)iref, iesp + 1);
+ /* esp = iesp + 2; *esp = the procedure */
+ iesp = esp;
+ goto up;
+ }
+ iosp = osp;
+ iesp = esp;
+ return_with_code_iref();
+ case pt_integer:
+ if (iosp >= ostop)
+ return_with_stackoverflow_iref();
+ ++iosp;
+ make_int(iosp,
+ (*PACKED(iref) & packed_int_mask) +
+ packed_min_intval);
+ next_short();
+ case pt_literal_name:
+ {
+ uint nidx = *PACKED(iref) & packed_value_mask;
+
+ if (iosp >= ostop)
+ return_with_stackoverflow_iref();
+ ++iosp;
+ name_index_ref_inline(int_nt, nidx, iosp);
+ next_short();
+ }
+ case pt_executable_name:
+ {
+ uint nidx =
+ (uint) * PACKED(iref) & packed_value_mask;
+
+ pvalue = name_index_ptr_inline(int_nt, nidx)->pvalue;
+ if (!pv_valid(pvalue)) {
+ uint htemp;
+
+ if ((pvalue = dict_find_name_by_index_inline(nidx, htemp)) == 0) {
+ names_index_ref(int_nt, nidx, &token);
+ return_with_error(e_undefined, &token);
+ }
+ }
+ if (r_has_masked_attrs(pvalue, a_execute, a_execute + a_executable)) { /* Literal, push it. */
+ if (iosp >= ostop)
+ return_with_stackoverflow_iref();
+ ++iosp;
+ ref_assign_inline(iosp, pvalue);
+ next_short();
+ }
+ if (r_is_proc(pvalue)) { /* This is an executable procedure, */
+ /* execute it. */
+ store_state_short(iesp);
+ goto pr;
+ }
+ /* Not a literal or procedure, reinterpret it. */
+ store_state_short(iesp);
+ icount = 0;
+ iref = pvalue;
+ goto top;
+ }
+ /* default can't happen here */
+ }
+ }
+ }
+ /* Literal type, just push it. */
+ if (iosp >= ostop)
+ return_with_stackoverflow_iref();
+ ++iosp;
+ ref_assign_inline(iosp, iref);
+ bot:next();
+ out: /* At most 1 more token in the current procedure. */
+ /* (We already decremented icount.) */
+ if (!icount) { /* Pop the execution stack for tail recursion. */
+ iesp--;
+ iref++;
+ goto top;
+ }
+ up:if (--ticks_left < 0)
+ goto slice;
+ /* See if there is anything left on the execution stack. */
+ if (!r_is_proc(iesp)) {
+ iref = iesp--;
+ icount = 0;
+ goto top;
+ }
+ iref = iesp->value.refs; /* next element of array */
+ icount = r_size(iesp) - 1;
+ if (icount <= 0) { /* <= 1 more elements */
+ iesp--; /* pop, or tail recursion */
+ if (icount < 0)
+ goto up;
+ }
+ goto top;
+ res: /* Some operator has asked for context rescheduling. */
+ /* We've done a store_state. */
+ code = (*gs_interp_reschedule_proc) ();
+ sched: /* We've just called a scheduling procedure. */
+ /* The interpreter state is in memory; iref is not current. */
+ if (code < 0) {
+ set_error(code);
+ /*
+ * We need a real object to return as the error object.
+ * (It only has to last long enough to store in
+ * *perror_object.)
+ */
+ make_null_proc(&ierror.full);
+ ierror.obj = iref = &ierror.full;
+ goto error_exit;
+ }
+ /* Reload state information from memory. */
+ iosp = osp;
+ iesp = esp;
+ goto up;
+#if 0 /****** ****** ***** */
+ sst: /* Time-slice, but push the current object first. */
+ store_state(iesp);
+ if (iesp >= estop)
+ return_with_error_iref(e_execstackoverflow);
+ iesp++;
+ ref_assign_inline(iesp, iref);
+#endif /****** ****** ***** */
+ slice: /* It's time to time-slice or garbage collect. */
+ /* iref is not live, so we don't need to do a store_state. */
+ osp = iosp;
+ esp = iesp;
+ /* If ticks_left <= -100, we need to GC now. */
+ if (ticks_left <= -100) { /* We need to garbage collect now. */
+ code = (*idmemory->reclaim) (idmemory, -1);
+ } else
+ code = (*gs_interp_time_slice_proc) ();
+ ticks_left = gs_interp_time_slice_ticks;
+ goto sched;
+
+ /* Error exits. */
+
+ rweci:
+ ierror.code = code;
+ rwei:
+ ierror.obj = iref;
+ rwe:
+ if (!r_is_packed(iref))
+ store_state(iesp);
+ else { /*
+ * We need a real object to return as the error object.
+ * (It only has to last long enough to store in
+ * *perror_object.)
+ */
+ packed_get((const ref_packed *)ierror.obj, &ierror.full);
+ store_state_short(iesp);
+ if (iref == ierror.obj)
+ iref = &ierror.full;
+ ierror.obj = &ierror.full;
+ }
+ error_exit:
+ if (error_is_interrupt(ierror.code)) { /* We must push the current object being interpreted */
+ /* back on the e-stack so it will be re-executed. */
+ /* Currently, this is always an executable operator, */
+ /* but it might be something else someday if we check */
+ /* for interrupts in the interpreter loop itself. */
+ if (iesp >= estop)
+ code = e_execstackoverflow;
+ else {
+ iesp++;
+ ref_assign_inline(iesp, iref);
+ }
+ }
+ esp = iesp;
+ osp = iosp;
+ ref_assign_inline(perror_object, ierror.obj);
+ return gs_log_error(ierror.code, __FILE__, ierror.line);
+
+}
+
+/* Pop the bookkeeping information for a normal exit from a t_oparray. */
+private int
+oparray_pop(os_ptr op)
+{
+ esp -= 3;
+ return o_pop_estack;
+}
+
+/* Restore the stack pointers after an error inside a t_oparray procedure. */
+/* This procedure is called only from pop_estack. */
+private int
+oparray_cleanup(os_ptr op)
+{ /* esp points just below the cleanup procedure. */
+ es_ptr ep = esp;
+ uint ocount_old = (uint) ep[2].value.intval;
+ uint dcount_old = (uint) ep[3].value.intval;
+ uint ocount = ref_stack_count(&o_stack);
+ uint dcount = ref_stack_count(&d_stack);
+
+ if (ocount > ocount_old)
+ ref_stack_pop(&o_stack, ocount - ocount_old);
+ if (dcount > dcount_old) {
+ ref_stack_pop(&d_stack, dcount - dcount_old);
+ dict_set_top();
+ }
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def interp_op_defs[] =
+{
+ /* Internal operators */
+ {"0%interp_exit", interp_exit},
+ {"0%oparray_pop", oparray_pop},
+ op_def_end(0)
+};
diff --git a/pstoraster/interp.h b/pstoraster/interp.h
new file mode 100644
index 000000000..0182b5ad9
--- /dev/null
+++ b/pstoraster/interp.h
@@ -0,0 +1,95 @@
+/* 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$ */
+/* Internal interfaces to interp.c and iinit.c */
+
+#ifndef interp_INCLUDED
+# define interp_INCLUDED
+
+/* ------ iinit.c ------ */
+
+/* Enter a name and value into systemdict. */
+void initial_enter_name(P2(const char *, const ref *));
+
+/* Remove a name from systemdict. */
+void initial_remove_name(P1(const char *));
+
+/* ------ interp.c ------ */
+
+/*
+ * Maximum number of arguments (and results) for an operator,
+ * determined by operand stack block size.
+ */
+extern const int gs_interp_max_op_num_args;
+
+/*
+ * Number of slots to reserve at the start of op_def_table for
+ * operators which are hard-coded into the interpreter loop.
+ */
+extern const int gs_interp_num_special_ops;
+
+/*
+ * Create an operator during initialization.
+ * If operator is hard-coded into the interpreter,
+ * assign it a special type and index.
+ */
+void gs_interp_make_oper(P3(ref * opref, op_proc_p, int index));
+
+/* Get the name corresponding to an error number. */
+int gs_errorname(P2(int, ref *));
+
+/* Put a string in $error /errorinfo. */
+int gs_errorinfo_put_string(P1(const char *));
+
+/* Initialize the interpreter. */
+void gs_interp_init(P0());
+
+#ifndef gs_context_state_t_DEFINED
+# define gs_context_state_t_DEFINED
+typedef struct gs_context_state_s gs_context_state_t;
+
+#endif
+
+/* Define a pointer to the current interpreter context state. */
+extern gs_context_state_t *gs_interp_context_state_current;
+
+/*
+ * Create initial stacks for the interpreter.
+ * We export this for creating new contexts.
+ */
+int gs_interp_alloc_stacks(P2(gs_ref_memory_t * smem,
+ gs_context_state_t * pcst));
+
+/*
+ * Free the stacks when destroying a context. This is the inverse of
+ * create_stacks.
+ */
+void gs_interp_free_stacks(P2(gs_ref_memory_t * smem,
+ gs_context_state_t * pcst));
+
+/* Reset the interpreter. */
+void gs_interp_reset(P0());
+
+#endif /* interp_INCLUDED */
diff --git a/pstoraster/iostack.h b/pstoraster/iostack.h
new file mode 100644
index 000000000..ab3ae86fa
--- /dev/null
+++ b/pstoraster/iostack.h
@@ -0,0 +1,45 @@
+/* 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 operand stack API */
+
+#ifndef iostack_INCLUDED
+# define iostack_INCLUDED
+
+#include "istack.h"
+
+/* Define pointers into the operand stack. */
+typedef s_ptr os_ptr;
+typedef const_s_ptr const_os_ptr;
+
+/* Define the operand stack structure. */
+/* Currently this is just a generic ref stack. */
+typedef struct op_stack_s {
+
+ ref_stack stack; /* the actual operand stack */
+
+} op_stack_t;
+
+#endif /* iostack_INCLUDED */
diff --git a/pstoraster/ipacked.h b/pstoraster/ipacked.h
new file mode 100644
index 000000000..69681753e
--- /dev/null
+++ b/pstoraster/ipacked.h
@@ -0,0 +1,159 @@
+/* Copyright (C) 1991, 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$ */
+/* Packed array format for Ghostscript */
+
+#ifndef ipacked_INCLUDED
+# define ipacked_INCLUDED
+
+/*
+
+ In a packed array, an element may either be a 2-byte ref_packed or a
+ full-size ref (8 or 16 bytes). We carefully arrange the first two bytes,
+ which are either an entire ref_packed or the type_attrs member of a ref,
+ so that we can distinguish the 2 forms. The encoding:
+
+ 00tttttt exrwsfnm full-size ref
+ 010mjjjj jjjjjjjj executable operator (so bind can work)
+ 011mvvvv vvvvvvvv integer (biased by packed_min_intval)
+ 100m---- -------- (not used)
+ 101m---- -------- (not used)
+ 110miiii iiiiiiii literal name
+ 111miiii iiiiiiii executable name
+
+ The m bit is the mark bit for the garbage collector.
+
+ ****** Note for the future: We could get packed tokens into the first-level
+ ****** interpreter dispatch by changing to the following representation:
+
+ 000ttttt exrwsfnm full-size ref
+ m0100jjj jjjjjjjj executable operator (so bind can work)
+ m0101vvv vvvvvvvv integer (biased by packed_min_intval)
+ m011iiii iiiiiiii literal name
+ m100iiii iiiiiiii executable name
+ m101---- -------- (not used)
+ m11----- -------- (not used)
+
+ ****** We aren't going to do this for a while.
+
+ The jjj index of executable operators is either the index of the operator
+ in the op_def_table, if the index is less than op_def_count, or the index
+ of the definition in the op_array_table (subtracting op_def_count first).
+
+ The iii index of names is the one that the name machinery already
+ maintains. A name whose index is larger than will fit in the packed
+ representation must be represented as a full-size ref.
+
+ There are two packed array types, t_mixedarray and t_shortarray. A
+ t_mixedarray can have a mix of packed and full-size elements; a
+ t_shortarray has all packed elements. The 'size' of a packed array is the
+ number of elements, not the number of bytes it occupies.
+
+ Packed array elements can be distinguished from full-size elements, so we
+ allow the interpreter to simply execute all the different kinds of arrays
+ directly. However, if we really allowed free mixing of packed and
+ full-size elements, this could lead to unaligned placement of full-size
+ refs; some machines can't handle unaligned accesses of this kind. To
+ guarantee that full-size elements in mixed arrays are always properly
+ aligned, if a full-size ref must be aligned at an address which is 0 mod
+ N, we convert up to N/2-1 preceding packed elements into full-size
+ elements, when creating the array, so that the alignment is preserved.
+ The only code this actually affects is in make_packed_array and in the
+ code for compacting refs in the garbage collector.
+
+ Note that code in zpacked.c and interp.c knows more about the
+ representation of packed elements than the definitions in this file would
+ imply. Read the code carefully if you change the representation.
+
+ */
+
+#define r_packed_type_shift 13
+#define r_packed_value_bits 12
+typedef enum {
+ pt_full_ref = 0,
+#define pt_min_packed 2
+ pt_executable_operator = 2,
+ pt_integer = 3,
+ pt_unused1 = 4,
+ pt_unused2 = 5,
+#define pt_min_name 6
+ pt_literal_name = 6,
+#define pt_min_exec_name 7
+ pt_executable_name = 7
+} packed_type;
+
+/*
+ * Hackery on top of hackery.
+ *
+ * I'll note in the beginning that this whole packed mechanism is not
+ * strictly conforming, so it's not surprising at all that it runs
+ * into problems somewhere.
+ *
+ * This is used where its pref operand may be a ref_packed, not necessarily
+ * aligned as strictly as a full-size ref. The DEC C compiler, and possibly
+ * others, may compile code assuming that pref is ref-aligned. Therefore, we
+ * explicitly cast the pointer to a less-strictly-aligned type. In order to
+ * convince the compiler, we have to do the cast before indexing into the
+ * structure.
+ */
+#ifdef __GNUC__
+/* GCC looks through the cast as if it weren't there. It turns out that
+ copying the value to a properly declared variable is convincing. Use
+ a bit of other GCC magic to make this transparent. */
+#define PACKED(pref) ({ushort *_T_ = (ushort *)(pref); _T_; })
+#else
+#define PACKED(pref) ((ushort *)(pref))
+#endif
+
+#define packed_per_ref (sizeof(ref) / sizeof(ref_packed))
+#define align_packed_per_ref\
+ (arch_align_ref_mod / arch_align_short_mod)
+#define pt_tag(pt) ((ref_packed)(pt) << r_packed_type_shift)
+#define packed_value_mask ((1 << r_packed_value_bits) - 1)
+#define packed_max_value packed_value_mask
+#define r_is_packed(rp) (*PACKED(rp) >= pt_tag(pt_min_packed))
+/* Names */
+#define r_packed_is_name(prp) (*PACKED(prp) >= pt_tag(pt_min_name))
+#define r_packed_is_exec_name(prp) (*PACKED(prp) >= pt_tag(pt_min_exec_name))
+#define packed_name_max_index packed_max_value
+#define packed_name_index(prp) (*PACKED(prp) & packed_value_mask)
+/* Integers */
+#define packed_min_intval (-(1 << (r_packed_value_bits - 1)))
+#define packed_max_intval ((1 << (r_packed_value_bits - 1)) - 1)
+#define packed_int_mask packed_value_mask
+
+/* Packed ref marking */
+#define lp_mark_shift 12
+#define lp_mark (1 << lp_mark_shift)
+#define r_has_pmark(rp) (*PACKED(rp) & lp_mark)
+#define r_set_pmark(rp) (*PACKED(rp) |= lp_mark)
+#define r_clear_pmark(rp) (*PACKED(rp) &= ~lp_mark)
+#define r_store_pmark(rp,pm) (*PACKED(rp) = (*PACKED(rp) & ~lp_mark) | (pm))
+
+/* Advance to the next element in a packed array. */
+#define packed_next(prp)\
+ (r_is_packed(prp) ? prp + 1 : prp + packed_per_ref)
+
+#endif /* ipacked_INCLUDED */
diff --git a/pstoraster/iparam.c b/pstoraster/iparam.c
new file mode 100644
index 000000000..26c6321b6
--- /dev/null
+++ b/pstoraster/iparam.c
@@ -0,0 +1,1080 @@
+/* Copyright (C) 1993, 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$ */
+/* Interpreter implementations of parameter dictionaries */
+#include "memory_.h"
+#include "string_.h"
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h" /* for check_type */
+#include "opcheck.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "imemory.h" /* for iutil.h */
+#include "iname.h"
+#include "istack.h"
+#include "iparam.h"
+#include "iutil.h" /* for num_params */
+#include "ivmspace.h"
+#include "store.h"
+
+/* ================ Utilities ================ */
+
+/* Convert a key to a ref. */
+private int
+ref_param_key(const iparam_list * plist, gs_param_name pkey, ref * pkref)
+{
+ if (plist->int_keys) {
+ long key;
+
+ if (sscanf(pkey, "%ld", &key) != 1)
+ return_error(e_rangecheck);
+ make_int(pkref, key);
+ return 0;
+ } else
+ return name_ref((const byte *)pkey, strlen(pkey), pkref, 0);
+}
+
+/* Fill in a gs_param_key_t from a name or int ref. */
+private int
+ref_to_key(const ref * pref, gs_param_key_t * key)
+{
+ if (r_has_type(pref, t_name)) {
+ ref nref;
+
+ name_string_ref(pref, &nref);
+ key->data = nref.value.const_bytes;
+ key->size = r_size(&nref);
+ } else if (r_has_type(pref, t_integer)) {
+ char istr[22]; /* big enough for signed 64-bit value */
+ int len;
+ byte *buf;
+
+ sprintf(istr, "%ld", pref->value.intval);
+ len = strlen(istr);
+ /* GC will take care of freeing this: */
+ buf = ialloc_string(len, "ref_to_key");
+ if (!buf)
+ return_error(e_VMerror);
+ key->data = buf;
+ key->size = len;
+ } else
+ return_error(e_typecheck);
+ return 0;
+}
+
+/* ================ Writing parameters to refs ================ */
+
+/* ---------------- Generic writing procedures ---------------- */
+
+private param_proc_begin_xmit_collection(ref_param_begin_write_collection);
+private param_proc_end_xmit_collection(ref_param_end_write_collection);
+private param_proc_xmit_typed(ref_param_write_typed);
+private param_proc_next_key(ref_param_get_next_key);
+private param_proc_requested(ref_param_requested);
+private const gs_param_list_procs ref_write_procs =
+{
+ ref_param_write_typed,
+ ref_param_begin_write_collection,
+ ref_param_end_write_collection,
+ ref_param_get_next_key,
+ NULL, /* request */
+ ref_param_requested
+};
+private int ref_array_param_requested(P5(const gs_param_list *, gs_param_name,
+ ref *, uint, client_name_t));
+private int ref_param_write(P3(iparam_list *, gs_param_name, const ref *));
+private int ref_param_write_string_value(P2(ref *, const gs_param_string *));
+private int ref_param_write_name_value(P2(ref *, const gs_param_string *));
+private int
+ref_param_make_int(ref * pe, const void *pvalue, uint i)
+{
+ make_int_new(pe, ((const gs_param_int_array *)pvalue)->data[i]);
+ return 0;
+}
+private int
+ref_param_make_float(ref * pe, const void *pvalue, uint i)
+{
+ make_real_new(pe, ((const gs_param_float_array *)pvalue)->data[i]);
+ return 0;
+}
+private int
+ref_param_make_string(ref * pe, const void *pvalue, uint i)
+{
+ return ref_param_write_string_value(pe,
+ &((const gs_param_string_array *)pvalue)->data[i]);
+}
+private int
+ref_param_make_name(ref * pe, const void *pvalue, uint i)
+{
+ return ref_param_write_name_value(pe,
+ &((const gs_param_string_array *)pvalue)->data[i]);
+}
+private int
+ref_param_write_typed_array(gs_param_list * plist, gs_param_name pkey,
+ void *pvalue, uint count,
+ int (*make) (P3(ref *, const void *, uint)))
+{
+ iparam_list *const iplist = (iparam_list *) plist;
+ ref value;
+ uint i;
+ ref *pe;
+ int code;
+
+ if ((code = ref_array_param_requested(plist, pkey, &value, count,
+ "ref_param_write_typed_array")) <= 0)
+ return code;
+ for (i = 0, pe = value.value.refs; i < count; ++i, ++pe)
+ if ((code = (*make) (pe, pvalue, i)) < 0)
+ return code;
+ return ref_param_write(iplist, pkey, &value);
+}
+private int
+ref_param_begin_write_collection(gs_param_list * plist, gs_param_name pkey,
+ gs_param_dict * pvalue,
+ gs_param_collection_type_t coll_type)
+{
+ dict_param_list *dlist =
+ (dict_param_list *) ialloc_bytes(size_of(dict_param_list),
+ "ref_param_begin_write_collection");
+ int code;
+
+ if (dlist == 0)
+ return_error(e_VMerror);
+ if (coll_type != gs_param_collection_array) {
+ ref dref;
+
+ code = dict_create(pvalue->size, &dref);
+ if (code >= 0) {
+ code = dict_param_list_write(dlist, &dref, NULL);
+ dlist->int_keys = coll_type == gs_param_collection_dict_int_keys;
+ }
+ } else {
+ ref aref;
+
+ code = ialloc_ref_array(&aref, a_all, pvalue->size,
+ "ref_param_begin_write_collection");
+ if (code >= 0)
+ code = array_indexed_param_list_write(dlist, &aref, NULL);
+ }
+ if (code < 0)
+ ifree_object(dlist, "ref_param_begin_write_collection");
+ else
+ pvalue->list = (gs_param_list *) dlist;
+ return code;
+}
+private int
+ref_param_end_write_collection(gs_param_list * plist, gs_param_name pkey,
+ gs_param_dict * pvalue)
+{
+ iparam_list *const iplist = (iparam_list *) plist;
+ int code = ref_param_write(iplist, pkey,
+ &((dict_param_list *) pvalue->list)->dict);
+
+ ifree_object(pvalue->list, "ref_param_end_write_collection");
+ return code;
+}
+private int
+ref_param_write_typed(gs_param_list * plist, gs_param_name pkey,
+ gs_param_typed_value * pvalue)
+{
+ iparam_list *const iplist = (iparam_list *) plist;
+ ref value;
+ int code = 0;
+
+ switch (pvalue->type) {
+ case gs_param_type_null:
+ make_null(&value);
+ break;
+ case gs_param_type_bool:
+ make_bool(&value, pvalue->value.b);
+ break;
+ case gs_param_type_int:
+ make_int(&value, pvalue->value.i);
+ break;
+ case gs_param_type_long:
+ make_int(&value, pvalue->value.l);
+ break;
+ case gs_param_type_float:
+ make_real(&value, pvalue->value.f);
+ break;
+ case gs_param_type_string:
+ if (!ref_param_requested(plist, pkey))
+ return 0;
+ code = ref_param_write_string_value(&value, &pvalue->value.s);
+ break;
+ case gs_param_type_name:
+ if (!ref_param_requested(plist, pkey))
+ return 0;
+ code = ref_param_write_name_value(&value, &pvalue->value.n);
+ break;
+ case gs_param_type_int_array:
+ return ref_param_write_typed_array(plist, pkey, &pvalue->value.ia,
+ pvalue->value.ia.size,
+ ref_param_make_int);
+ case gs_param_type_float_array:
+ return ref_param_write_typed_array(plist, pkey, &pvalue->value.fa,
+ pvalue->value.fa.size,
+ ref_param_make_float);
+ case gs_param_type_string_array:
+ return ref_param_write_typed_array(plist, pkey, &pvalue->value.sa,
+ pvalue->value.sa.size,
+ ref_param_make_string);
+ case gs_param_type_name_array:
+ return ref_param_write_typed_array(plist, pkey, &pvalue->value.na,
+ pvalue->value.na.size,
+ ref_param_make_name);
+ case gs_param_type_dict:
+ case gs_param_type_dict_int_keys:
+ case gs_param_type_array:
+ return ref_param_begin_write_collection(plist, pkey,
+ &pvalue->value.d,
+ (gs_param_collection_type_t)(pvalue->type - gs_param_type_dict));
+ default:
+ return_error(e_typecheck);
+ }
+ if (code < 0)
+ return code;
+ return ref_param_write(iplist, pkey, &value);
+}
+
+/* Check whether a given parameter was requested. */
+private int
+ref_param_requested(const gs_param_list * plist, gs_param_name pkey)
+{
+ const iparam_list *const ciplist = (const iparam_list *)plist;
+ ref kref;
+ ref *ignore_value;
+
+ if (!r_has_type(&ciplist->u.w.wanted, t_dictionary))
+ return -1;
+ if (ref_param_key(ciplist, pkey, &kref) < 0)
+ return -1; /* catch it later */
+ return (dict_find(&ciplist->u.w.wanted, &kref, &ignore_value) > 0);
+}
+
+/* Check whether an array parameter is wanted, and allocate it if so. */
+/* Return <0 on error, 0 if not wanted, 1 if wanted. */
+private int
+ref_array_param_requested(const gs_param_list * plist, gs_param_name pkey,
+ ref * pvalue, uint size, client_name_t cname)
+{
+ int code;
+
+ if (!ref_param_requested(plist, pkey))
+ return 0;
+ code = ialloc_ref_array(pvalue, a_all, size, cname);
+ return (code < 0 ? code : 1);
+}
+
+/* ---------------- Internal routines ---------------- */
+
+/* Prepare to write a string value. */
+private int
+ref_param_write_string_value(ref * pref, const gs_param_string * pvalue)
+{
+ const byte *pdata = pvalue->data;
+ uint n = pvalue->size;
+
+ if (pvalue->persistent)
+ make_const_string(pref, a_readonly | avm_foreign, n, pdata);
+ else {
+ byte *pstr = ialloc_string(n, "ref_param_write_string");
+
+ if (pstr == 0)
+ return_error(e_VMerror);
+ memcpy(pstr, pdata, n);
+ make_string(pref, a_readonly | icurrent_space, n, pstr);
+ }
+ return 0;
+}
+
+/* Prepare to write a name value. */
+private int
+ref_param_write_name_value(ref * pref, const gs_param_string * pvalue)
+{
+ return name_ref(pvalue->data, pvalue->size, pref,
+ (pvalue->persistent ? 0 : 1));
+}
+
+/* Generic routine for writing a ref parameter. */
+private int
+ref_param_write(iparam_list * plist, gs_param_name pkey, const ref * pvalue)
+{
+ ref kref;
+ int code;
+
+ if (!ref_param_requested((gs_param_list *) plist, pkey))
+ return 0;
+ code = ref_param_key(plist, pkey, &kref);
+ if (code < 0)
+ return code;
+ return (*plist->u.w.write) (plist, &kref, pvalue);
+}
+
+/* ---------------- Implementations ---------------- */
+
+/* Initialize for writing parameters. */
+private void
+ref_param_write_init(iparam_list * plist, const ref * pwanted)
+{
+ plist->procs = &ref_write_procs;
+ plist->memory = imemory;
+ if (pwanted == 0)
+ make_null(&plist->u.w.wanted);
+ else
+ plist->u.w.wanted = *pwanted;
+ plist->results = 0;
+ plist->int_keys = false;
+}
+
+/* Implementation for getting parameters to a stack. */
+private int
+stack_param_write(iparam_list * plist, const ref * pkey, const ref * pvalue)
+{
+ stack_param_list *const splist = (stack_param_list *) plist;
+ ref_stack *pstack = splist->pstack;
+ s_ptr p = pstack->p;
+
+ if (pstack->top - p < 2) {
+ int code = ref_stack_push(pstack, 2);
+
+ if (code < 0)
+ return code;
+ *ref_stack_index(pstack, 1) = *pkey;
+ p = pstack->p;
+ } else {
+ pstack->p = p += 2;
+ p[-1] = *pkey;
+ }
+ *p = *pvalue;
+ splist->count++;
+ return 0;
+}
+
+/* Implementation for enumerating parameters on a stack */
+private int /* ret 0 ok, 1 if EOF, or -ve err */
+stack_param_enumerate(iparam_list * plist, gs_param_enumerator_t * penum,
+ gs_param_key_t * key, ref_type * type)
+{
+ int code;
+ stack_param_list *const splist = (stack_param_list *) plist;
+ long index = penum->intval;
+ ref *stack_element;
+
+ do {
+ stack_element =
+ ref_stack_index(splist->pstack, index + 1 + splist->skip);
+ if (!stack_element)
+ return 1;
+ } while (index += 2, !r_has_type(stack_element, t_name));
+ *type = r_type(stack_element);
+ code = ref_to_key(stack_element, key);
+ penum->intval = index;
+ return code;
+}
+
+int
+stack_param_list_write(stack_param_list * plist, ref_stack * pstack,
+ const ref * pwanted)
+{
+ plist->u.w.write = stack_param_write;
+ ref_param_write_init((iparam_list *) plist, pwanted);
+ plist->enumerate = stack_param_enumerate;
+ plist->pstack = pstack;
+ plist->skip = 0;
+ plist->count = 0;
+ return 0;
+}
+
+/* Implementation for getting parameters to a dictionary. */
+private int
+dict_param_write(iparam_list * plist, const ref * pkey, const ref * pvalue)
+{
+ int code = dict_put(&((dict_param_list *) plist)->dict, pkey, pvalue);
+
+ return min(code, 0);
+}
+
+/* Implementation for enumerating parameters in a dictionary */
+private int /* ret 0 ok, 1 if EOF, or -ve err */
+dict_param_enumerate(iparam_list * plist, gs_param_enumerator_t * penum,
+ gs_param_key_t * key, ref_type * type)
+{
+ ref elt[2];
+ int code;
+ dict_param_list *const pdlist = (dict_param_list *) plist;
+ int index =
+ (penum->intval != 0 ? penum->intval : dict_first(&pdlist->dict));
+
+ index = dict_next(&pdlist->dict, index, elt);
+ if (index < 0)
+ return 1;
+ *type = r_type(&elt[1]);
+ code = ref_to_key(&elt[1], key);
+ penum->intval = index;
+ return code;
+}
+
+int
+dict_param_list_write(dict_param_list * plist, ref * pdict, const ref * pwanted)
+{
+ check_dict_write(*pdict);
+ plist->u.w.write = dict_param_write;
+ plist->enumerate = dict_param_enumerate;
+ ref_param_write_init((iparam_list *) plist, pwanted);
+ plist->dict = *pdict;
+ return 0;
+}
+
+/* Implementation for getting parameters to an indexed array. */
+private int
+array_indexed_param_write(iparam_list * plist, const ref * pkey,
+ const ref * pvalue)
+{
+ const ref *const arr = &((dict_param_list *) plist)->dict;
+ ref *eltp;
+
+ if (!r_has_type(pkey, t_integer))
+ return_error(e_typecheck);
+ check_int_ltu(*pkey, r_size(arr));
+ store_check_dest(arr, pvalue);
+ eltp = arr->value.refs + pkey->value.intval;
+ ref_assign_old(arr, eltp, pvalue, "array_indexed_param_write");
+ return 0;
+}
+int
+array_indexed_param_list_write(dict_param_list * plist, ref * parray,
+ const ref * pwanted)
+{
+ check_array(*parray);
+ check_write(*parray);
+ plist->u.w.write = array_indexed_param_write;
+ ref_param_write_init((iparam_list *) plist, pwanted);
+ plist->dict = *parray;
+ plist->int_keys = true;
+ return 0;
+}
+
+/* ================ Reading refs to parameters ================ */
+
+/* ---------------- Generic reading procedures ---------------- */
+
+private param_proc_begin_xmit_collection(ref_param_begin_read_collection);
+private param_proc_end_xmit_collection(ref_param_end_read_collection);
+private param_proc_xmit_typed(ref_param_read_typed);
+
+/*private param_proc_next_key(ref_param_get_next_key); already dec'ld above */
+private param_proc_get_policy(ref_param_read_get_policy);
+private param_proc_signal_error(ref_param_read_signal_error);
+private param_proc_commit(ref_param_read_commit);
+private const gs_param_list_procs ref_read_procs =
+{
+ ref_param_read_typed,
+ ref_param_begin_read_collection,
+ ref_param_end_read_collection,
+ ref_param_get_next_key,
+ NULL, /* request */
+ NULL, /* requested */
+ ref_param_read_get_policy,
+ ref_param_read_signal_error,
+ ref_param_read_commit
+};
+private int ref_param_read(P4(iparam_list *, gs_param_name,
+ iparam_loc *, int));
+private int ref_param_read_string_value(P2(const iparam_loc *,
+ gs_param_string *));
+private int ref_param_read_array(P3(iparam_list *, gs_param_name,
+ iparam_loc *));
+
+#define iparam_note_error(loc, code)\
+ gs_note_error(*(loc).presult = code)
+#define iparam_check_type(loc, typ)\
+ if ( !r_has_type((loc).pvalue, typ) )\
+ return iparam_note_error(loc, e_typecheck)
+#define iparam_check_read(loc)\
+ if ( !r_has_attr((loc).pvalue, a_read) )\
+ return iparam_note_error(loc, e_invalidaccess)
+
+private int
+ref_param_read_int_array(gs_param_list * plist, gs_param_name pkey,
+ gs_param_int_array * pvalue)
+{
+ iparam_list *const iplist = (iparam_list *) plist;
+ iparam_loc loc;
+ int code = ref_param_read_array(iplist, pkey, &loc);
+ int *piv;
+ uint size;
+ long i;
+
+ if (code != 0)
+ return code;
+ size = r_size(loc.pvalue);
+ piv = (int *)ialloc_byte_array(size, sizeof(int),
+ "ref_param_read_int_array");
+
+ if (piv == 0)
+ return_error(e_VMerror);
+ for (i = 0; i < size; i++) {
+ ref elt;
+
+ array_get(loc.pvalue, i, &elt);
+ if (!r_has_type(&elt, t_integer)) {
+ code = gs_note_error(e_typecheck);
+ break;
+ }
+#if arch_sizeof_int < arch_sizeof_long
+ if (elt.value.intval != (int)elt.value.intval) {
+ code = gs_note_error(e_rangecheck);
+ break;
+ }
+#endif
+ piv[i] = (int)elt.value.intval;
+ }
+ if (code < 0) {
+ ifree_object(piv, "ref_param_read_int_array");
+ return (*loc.presult = code);
+ }
+ pvalue->data = piv;
+ pvalue->size = size;
+ pvalue->persistent = true;
+ return 0;
+}
+private int
+ref_param_read_float_array(gs_param_list * plist, gs_param_name pkey,
+ gs_param_float_array * pvalue)
+{
+ iparam_list *const iplist = (iparam_list *) plist;
+ iparam_loc loc;
+ ref aref, elt;
+ int code = ref_param_read_array(iplist, pkey, &loc);
+ float *pfv;
+ uint size;
+ long i;
+
+ if (code != 0)
+ return code;
+ size = r_size(loc.pvalue);
+ pfv = (float *)ialloc_byte_array(size, sizeof(float),
+ "ref_param_read_float_array");
+
+ if (pfv == 0)
+ return_error(e_VMerror);
+ aref = *loc.pvalue;
+ loc.pvalue = &elt;
+ for (i = 0; code >= 0 && i < size; i++) {
+ array_get(&aref, i, &elt);
+ code = float_param(&elt, pfv + i);
+ }
+ if (code < 0) {
+ ifree_object(pfv, "ref_read_float_array_param");
+ return (*loc.presult = code);
+ }
+ pvalue->data = pfv;
+ pvalue->size = size;
+ pvalue->persistent = true;
+ return 0;
+}
+private int
+ref_param_read_string_array(gs_param_list * plist, gs_param_name pkey,
+ gs_param_string_array * pvalue)
+{
+ iparam_list *const iplist = (iparam_list *) plist;
+ iparam_loc loc;
+ ref aref, elt;
+ int code = ref_param_read_array(iplist, pkey, &loc);
+ gs_param_string *psv;
+ uint size;
+ long i;
+
+ if (code != 0)
+ return code;
+ size = r_size(loc.pvalue);
+ psv =
+ (gs_param_string *) ialloc_byte_array(size, sizeof(gs_param_string),
+ "ref_param_read_string_array");
+ if (psv == 0)
+ return_error(e_VMerror);
+ aref = *loc.pvalue;
+ loc.pvalue = &elt;
+ for (i = 0; code >= 0 && i < size; i++) {
+ array_get(&aref, i, &elt);
+ code = ref_param_read_string_value(&loc, psv + i);
+ }
+ if (code < 0) {
+ ifree_object(psv, "ref_param_read_string_array");
+ return (*loc.presult = code);
+ }
+ pvalue->data = psv;
+ pvalue->size = size;
+ pvalue->persistent = true;
+ return 0;
+}
+private int
+ref_param_begin_read_collection(gs_param_list * plist, gs_param_name pkey,
+ gs_param_dict * pvalue,
+ gs_param_collection_type_t coll_type)
+{
+ iparam_list *const iplist = (iparam_list *) plist;
+ iparam_loc loc;
+ bool int_keys = coll_type != 0;
+ int code = ref_param_read(iplist, pkey, &loc, -1);
+ dict_param_list *dlist;
+
+ if (code != 0)
+ return code;
+ dlist = (dict_param_list *)
+ ialloc_bytes(size_of(dict_param_list),
+ "ref_param_begin_read_collection");
+ if (dlist == 0)
+ return_error(e_VMerror);
+ if (r_has_type(loc.pvalue, t_dictionary)) {
+ code = dict_param_list_read(dlist, loc.pvalue, NULL, false);
+ dlist->int_keys = int_keys;
+ if (code >= 0)
+ pvalue->size = dict_length(loc.pvalue);
+ } else if (int_keys && r_is_array(loc.pvalue)) {
+ code = array_indexed_param_list_read(dlist, loc.pvalue, NULL, false);
+ if (code >= 0)
+ pvalue->size = r_size(loc.pvalue);
+ } else
+ code = gs_note_error(e_typecheck);
+ if (code < 0) {
+ ifree_object(dlist, "ref_param_begin_write_collection");
+ return iparam_note_error(loc, code);
+ }
+ pvalue->list = (gs_param_list *) dlist;
+ return 0;
+}
+private int
+ref_param_end_read_collection(gs_param_list * plist, gs_param_name pkey,
+ gs_param_dict * pvalue)
+{
+ iparam_list_release((dict_param_list *) pvalue->list);
+ ifree_object(pvalue->list, "ref_param_end_read_collection");
+ return 0;
+}
+private int
+ref_param_read_typed(gs_param_list * plist, gs_param_name pkey,
+ gs_param_typed_value * pvalue)
+{
+ iparam_list *const iplist = (iparam_list *) plist;
+ iparam_loc loc;
+ ref elt;
+ int code = ref_param_read(iplist, pkey, &loc, -1);
+
+ if (code != 0)
+ return code;
+ switch (r_type(loc.pvalue)) {
+ case t_array:
+ case t_mixedarray:
+ case t_shortarray:
+ iparam_check_read(loc);
+ if (r_size(loc.pvalue) <= 0) {
+ /* 0-length array; can't get type info */
+ pvalue->type = gs_param_type_array;
+ pvalue->value.d.list = 0;
+ pvalue->value.d.size = 0;
+ return 0;
+ }
+ /* Get array type based on type of 1st element of array */
+ array_get(loc.pvalue, 0, &elt);
+ switch (r_type(&elt)) { /* redundant key lookup, but cached */
+ case t_integer:
+ pvalue->type = gs_param_type_int_array;
+ return ref_param_read_int_array(plist, pkey, &pvalue->value.ia);
+ case t_real:
+ pvalue->type = gs_param_type_float_array;
+ return ref_param_read_float_array(plist, pkey, &pvalue->value.fa);
+ case t_string:
+ pvalue->type = gs_param_type_string_array;
+ return ref_param_read_string_array(plist, pkey, &pvalue->value.sa);
+ case t_name:
+ pvalue->type = gs_param_type_name_array;
+ return ref_param_read_string_array(plist, pkey, &pvalue->value.na);
+ default:
+ break;
+ }
+ return gs_note_error(e_typecheck);
+ case t_boolean:
+ pvalue->type = gs_param_type_bool;
+ pvalue->value.b = loc.pvalue->value.boolval;
+ return 0;
+ case t_dictionary:
+ code = ref_param_begin_read_collection(plist, pkey,
+ &pvalue->value.d, gs_param_collection_dict_any);
+ if (code < 0)
+ return code;
+ pvalue->type = gs_param_type_dict;
+
+ /* fixup new dict's type & int_keys field if contents have int keys */
+ {
+ gs_param_enumerator_t enumr;
+ gs_param_key_t key;
+ ref_type keytype;
+
+ param_init_enumerator(&enumr);
+ if (!(*((iparam_list *) plist)->enumerate)
+ ((iparam_list *) pvalue->value.d.list, &enumr, &key, &keytype)
+ && keytype == t_integer) {
+ ((dict_param_list *) pvalue->value.d.list)->int_keys = 1;
+ pvalue->type = gs_param_type_dict_int_keys;
+ }
+ }
+ return 0;
+ case t_integer:
+ pvalue->type = gs_param_type_long;
+ pvalue->value.l = loc.pvalue->value.intval;
+ return 0;
+ case t_name:
+ pvalue->type = gs_param_type_name;
+ return ref_param_read_string_value(&loc, &pvalue->value.n);
+ case t_null:
+ pvalue->type = gs_param_type_null;
+ return 0;
+ case t_real:
+ pvalue->value.f = loc.pvalue->value.realval;
+ pvalue->type = gs_param_type_float;
+ return 0;
+ case t_string:
+ pvalue->type = gs_param_type_string;
+ return ref_param_read_string_value(&loc, &pvalue->value.s);
+ default:
+ break;
+ }
+ return gs_note_error(e_typecheck);
+}
+
+private int
+ref_param_read_get_policy(gs_param_list * plist, gs_param_name pkey)
+{
+ iparam_list *const iplist = (iparam_list *) plist;
+ ref *pvalue;
+
+ if (!(r_has_type(&iplist->u.r.policies, t_dictionary) &&
+ dict_find_string(&iplist->u.r.policies, pkey, &pvalue) > 0 &&
+ r_has_type(pvalue, t_integer))
+ )
+ return gs_param_policy_ignore;
+ return (int)pvalue->value.intval;
+}
+private int
+ref_param_read_signal_error(gs_param_list * plist, gs_param_name pkey, int code)
+{
+ iparam_list *const iplist = (iparam_list *) plist;
+ iparam_loc loc;
+
+ ref_param_read(iplist, pkey, &loc, -1); /* can't fail */
+ *loc.presult = code;
+ switch (ref_param_read_get_policy(plist, pkey)) {
+ case gs_param_policy_ignore:
+ return 0;
+ case gs_param_policy_consult_user:
+ return_error(e_configurationerror);
+ default:
+ return code;
+ }
+}
+private int
+ref_param_read_commit(gs_param_list * plist)
+{
+ iparam_list *const iplist = (iparam_list *) plist;
+ int i;
+ int ecode = 0;
+
+ if (!iplist->u.r.require_all)
+ return 0;
+ /* Check to make sure that all parameters were actually read. */
+ for (i = 0; i < iplist->count; ++i)
+ if (iplist->results[i] == 0)
+ iplist->results[i] = ecode = gs_note_error(e_undefined);
+ return ecode;
+}
+private int
+ref_param_get_next_key(gs_param_list * plist, gs_param_enumerator_t * penum,
+ gs_param_key_t * key)
+{
+ ref_type keytype; /* result not needed here */
+ iparam_list *const pilist = (iparam_list *) plist;
+
+ return (*pilist->enumerate) (pilist, penum, key, &keytype);
+}
+
+/* ---------------- Internal routines ---------------- */
+
+/* Read a string value. */
+private int
+ref_param_read_string_value(const iparam_loc * ploc, gs_param_string * pvalue)
+{
+ const ref *pref = ploc->pvalue;
+ ref nref;
+
+ switch (r_type(pref)) {
+ case t_name:
+ name_string_ref(pref, &nref);
+ pref = &nref;
+ pvalue->persistent = true;
+ goto s;
+ case t_string:
+ iparam_check_read(*ploc);
+ pvalue->persistent = false;
+ s:pvalue->data = pref->value.const_bytes;
+ pvalue->size = r_size(pref);
+ break;
+ default:
+ return iparam_note_error(*ploc, e_typecheck);
+ }
+ return 0;
+}
+
+/* Read an array (or packed array) parameter. */
+private int
+ref_param_read_array(iparam_list * plist, gs_param_name pkey, iparam_loc * ploc)
+{
+ int code = ref_param_read(plist, pkey, ploc, -1);
+
+ if (code != 0)
+ return code;
+ if (!r_is_array(ploc->pvalue))
+ return iparam_note_error(*ploc, e_typecheck);
+ iparam_check_read(*ploc);
+ return 0;
+}
+
+/* Generic routine for reading a ref parameter. */
+private int
+ref_param_read(iparam_list * plist, gs_param_name pkey, iparam_loc * ploc,
+ int type)
+{
+ iparam_list *const iplist = (iparam_list *) plist;
+ ref kref;
+ int code = ref_param_key(plist, pkey, &kref);
+
+ if (code < 0)
+ return code;
+ code = (*plist->u.r.read) (iplist, &kref, ploc);
+ if (code != 0)
+ return code;
+ if (type >= 0)
+ iparam_check_type(*ploc, type);
+ return 0;
+}
+
+/* ---------------- Implementations ---------------- */
+
+/* Implementation for putting parameters from an empty collection. */
+private int
+empty_param_read(iparam_list * plist, const ref * pkey, iparam_loc * ploc)
+{
+ return 1;
+}
+
+/* Initialize for reading parameters. */
+private int
+ref_param_read_init(iparam_list * plist, uint count, const ref * ppolicies,
+ bool require_all)
+{
+ plist->procs = &ref_read_procs;
+ plist->memory = imemory;
+ if (ppolicies == 0)
+ make_null(&plist->u.r.policies);
+ else
+ plist->u.r.policies = *ppolicies;
+ plist->u.r.require_all = require_all;
+ plist->count = count;
+ plist->results =
+ (int *)ialloc_byte_array(count, sizeof(int), "ref_param_read_init");
+
+ if (plist->results == 0)
+ return_error(e_VMerror);
+ memset(plist->results, 0, count * sizeof(int));
+
+ plist->int_keys = false;
+ return 0;
+}
+
+/* Implementation for putting parameters from an indexed array. */
+private int
+array_indexed_param_read(iparam_list * plist, const ref * pkey, iparam_loc * ploc)
+{
+ ref *const arr = &((dict_param_list *) plist)->dict;
+
+ check_type(*pkey, t_integer);
+ if (pkey->value.intval < 0 || pkey->value.intval >= r_size(arr))
+ return 1;
+ ploc->pvalue = arr->value.refs + pkey->value.intval;
+ ploc->presult = &plist->results[pkey->value.intval];
+ *ploc->presult = 1;
+ return 0;
+}
+int
+array_indexed_param_list_read(dict_param_list * plist, const ref * parray,
+ const ref * ppolicies, bool require_all)
+{
+ iparam_list *const iplist = (iparam_list *) plist;
+ int code;
+
+ check_read_type(*parray, t_array);
+ plist->u.r.read = array_indexed_param_read;
+ plist->dict = *parray;
+ code = ref_param_read_init(iplist, r_size(parray), ppolicies,
+ require_all);
+ plist->int_keys = true;
+ return code;
+}
+
+/* Implementation for putting parameters from an array. */
+private int
+array_param_read(iparam_list * plist, const ref * pkey, iparam_loc * ploc)
+{
+ ref *bot = ((array_param_list *) plist)->bot;
+ ref *ptr = bot;
+ ref *top = ((array_param_list *) plist)->top;
+
+ for (; ptr < top; ptr += 2) {
+ if (r_has_type(ptr, t_name) && name_eq(ptr, pkey)) {
+ ploc->pvalue = ptr + 1;
+ ploc->presult = &plist->results[ptr - bot];
+ *ploc->presult = 1;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/* Implementation for enumerating parameters in an array */
+private int /* ret 0 ok, 1 if EOF, or -ve err */
+array_param_enumerate(iparam_list * plist, gs_param_enumerator_t * penum,
+ gs_param_key_t * key, ref_type * type)
+{
+ int index = penum->intval;
+ ref *bot = ((array_param_list *) plist)->bot;
+ ref *ptr = bot + index;
+ ref *top = ((array_param_list *) plist)->top;
+
+ for (; ptr < top; ptr += 2) {
+ index += 2;
+
+ if (r_has_type(ptr, t_name)) {
+ int code = ref_to_key(ptr, key);
+
+ *type = r_type(ptr);
+ penum->intval = index;
+ return code;
+ }
+ }
+ return 1;
+}
+
+int
+array_param_list_read(array_param_list * plist, ref * bot, uint count,
+ const ref * ppolicies, bool require_all)
+{
+ iparam_list *const iplist = (iparam_list *) plist;
+
+ if (count & 1)
+ return_error(e_rangecheck);
+ plist->u.r.read = array_param_read;
+ plist->enumerate = array_param_enumerate;
+ plist->bot = bot;
+ plist->top = bot + count;
+ return ref_param_read_init(iplist, count, ppolicies, require_all);
+}
+
+/* Implementation for putting parameters from a stack. */
+private int
+stack_param_read(iparam_list * plist, const ref * pkey, iparam_loc * ploc)
+{
+ stack_param_list *const splist = (stack_param_list *) plist;
+ ref_stack *pstack = splist->pstack;
+
+ /* This implementation is slow, but it probably doesn't matter. */
+ uint index = splist->skip + 1;
+ uint count = splist->count;
+
+ for (; count; count--, index += 2) {
+ const ref *p = ref_stack_index(pstack, index);
+
+ if (r_has_type(p, t_name) && name_eq(p, pkey)) {
+ ploc->pvalue = ref_stack_index(pstack, index - 1);
+ ploc->presult = &plist->results[count - 1];
+ *ploc->presult = 1;
+ return 0;
+ }
+ }
+ return 1;
+}
+int
+stack_param_list_read(stack_param_list * plist, ref_stack * pstack, uint skip,
+ const ref * ppolicies, bool require_all)
+{
+ iparam_list *const iplist = (iparam_list *) plist;
+ uint count = ref_stack_counttomark(pstack);
+
+ if (count == 0)
+ return_error(e_unmatchedmark);
+ count -= skip + 1;
+ if (count & 1)
+ return_error(e_rangecheck);
+ plist->u.r.read = stack_param_read;
+ plist->enumerate = stack_param_enumerate;
+ plist->pstack = pstack;
+ plist->skip = skip;
+ return ref_param_read_init(iplist, count >> 1, ppolicies, require_all);
+}
+
+/* Implementation for putting parameters from a dictionary. */
+private int
+dict_param_read(iparam_list * plist, const ref * pkey, iparam_loc * ploc)
+{
+ ref const *spdict = &((dict_param_list *) plist)->dict;
+ int code = dict_find(spdict, pkey, &ploc->pvalue);
+
+ if (code != 1)
+ return 1;
+ ploc->presult =
+ &plist->results[dict_value_index(spdict, ploc->pvalue)];
+ *ploc->presult = 1;
+ return 0;
+}
+int
+dict_param_list_read(dict_param_list * plist, const ref * pdict,
+ const ref * ppolicies, bool require_all)
+{
+ iparam_list *const iplist = (iparam_list *) plist;
+ uint count;
+
+ if (pdict == 0) {
+ plist->u.r.read = empty_param_read;
+ count = 0;
+ } else {
+ check_dict_read(*pdict);
+ plist->u.r.read = dict_param_read;
+ plist->dict = *pdict;
+ count = dict_max_index(pdict) + 1;
+ }
+ plist->enumerate = dict_param_enumerate;
+ return ref_param_read_init(iplist, count, ppolicies, require_all);
+}
diff --git a/pstoraster/iparam.h b/pstoraster/iparam.h
new file mode 100644
index 000000000..bec2b4160
--- /dev/null
+++ b/pstoraster/iparam.h
@@ -0,0 +1,118 @@
+/* Copyright (C) 1993, 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 ialloc.h, istack.h */
+
+#ifndef iparam_INCLUDED
+# define iparam_INCLUDED
+
+#include "gsparam.h"
+
+/*
+ * This file defines the interface to iparam.c, which provides
+ * several implementations of the parameter dictionary interface
+ * defined in gsparam.h:
+ * - an implementation using dictionary objects;
+ * - an implementation using name/value pairs in an array;
+ * - an implementation using name/value pairs on a stack.
+ *
+ * When reading ('putting'), these implementations keep track of
+ * which parameters have been referenced and which have caused errors.
+ * The results array contains 0 for a parameter that has not been accessed,
+ * 1 for a parameter accessed without error, or <0 for an error.
+ */
+
+typedef struct iparam_loc_s {
+ ref *pvalue; /* (actually const) */
+ int *presult;
+} iparam_loc;
+
+#define iparam_list_common\
+ gs_param_list_common;\
+ union {\
+ struct { /* reading */\
+ int (*read)(P3(iparam_list *, const ref *, iparam_loc *));\
+ ref policies; /* policy dictionary or null */\
+ bool require_all; /* if true, require all params to be known */\
+ } r;\
+ struct { /* writing */\
+ int (*write)(P3(iparam_list *, const ref *, const ref *));\
+ ref wanted; /* desired keys or null */\
+ } w;\
+ } u;\
+ int (*enumerate)(P4(iparam_list *, gs_param_enumerator_t *, gs_param_key_t *, ref_type *));\
+ int *results; /* (only used when reading, 0 when writing) */\
+ uint count; /* # of key/value pairs */\
+ bool int_keys /* if true, keys are integers */
+typedef struct iparam_list_s iparam_list;
+struct iparam_list_s {
+ iparam_list_common;
+};
+
+typedef struct dict_param_list_s {
+ iparam_list_common;
+ ref dict; /* dictionary or array */
+} dict_param_list;
+typedef struct array_param_list_s {
+ iparam_list_common;
+ ref *bot;
+ ref *top;
+} array_param_list;
+
+/* For stack lists, the bottom of the list is just above a mark. */
+typedef struct stack_param_list_s {
+ iparam_list_common;
+ ref_stack *pstack;
+ uint skip; /* # of top items to skip (reading only) */
+} stack_param_list;
+
+/* Procedural interface */
+/*
+ * For dict_param_list_read (only), the second parameter may be NULL,
+ * equivalent to an empty dictionary.
+ * The 3rd (const ref *) parameter is the policies dictionary when reading,
+ * or the key selection dictionary when writing; it may be NULL in either case.
+ * If the bool parameter is true, if there are any unqueried parameters,
+ * the commit procedure will return an e_undefined error.
+ */
+int dict_param_list_read(P4(dict_param_list *, const ref * /*t_dictionary */ ,
+ const ref *, bool));
+int dict_param_list_write(P3(dict_param_list *, ref * /*t_dictionary */ ,
+ const ref *));
+int array_indexed_param_list_read(P4(dict_param_list *, const ref * /*t_*array */ ,
+ const ref *, bool));
+int array_indexed_param_list_write(P3(dict_param_list *, ref * /*t_*array */ ,
+ const ref *));
+int array_param_list_read(P5(array_param_list *, ref *, uint,
+ const ref *, bool));
+int stack_param_list_read(P5(stack_param_list *, ref_stack *, uint,
+ const ref *, bool));
+int stack_param_list_write(P3(stack_param_list *, ref_stack *,
+ const ref *));
+
+#define iparam_list_release(plist)\
+ ifree_object((plist)->results, "iparam_list_release")
+
+#endif /* iparam_INCLUDED */
diff --git a/pstoraster/iparray.h b/pstoraster/iparray.h
new file mode 100644
index 000000000..ce86b5f0e
--- /dev/null
+++ b/pstoraster/iparray.h
@@ -0,0 +1,42 @@
+/* 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$ */
+/* Packed array constructor for Ghostscript */
+
+#ifndef iparray_INCLUDED
+# define iparray_INCLUDED
+
+/*
+ * The only reason to put this in a separate header is that it requires
+ * both ipacked.h and istack.h; putting it in either one would make it
+ * depend on the other one. There must be a better way....
+ */
+
+/* Procedures implemented in zpacked.c */
+
+/* Make a packed array from the top N elements of a stack. */
+int make_packed_array(P4(ref *, ref_stack *, uint, client_name_t));
+
+#endif /* iparray_INCLUDED */
diff --git a/pstoraster/ireclaim.c b/pstoraster/ireclaim.c
new file mode 100644
index 000000000..eb2433132
--- /dev/null
+++ b/pstoraster/ireclaim.c
@@ -0,0 +1,163 @@
+/* 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$ */
+/* Interpreter's interface to garbage collector */
+#include "ghost.h"
+#include "errors.h"
+#include "gsstruct.h"
+#include "iastate.h"
+#include "icontext.h"
+#include "interp.h"
+#include "isave.h" /* for isstate.h */
+#include "isstate.h" /* for mem->saved->state */
+#include "dstack.h" /* for dsbot, dsp, dict_set_top */
+#include "estack.h" /* for esbot, esp */
+#include "ostack.h" /* for osbot, osp */
+#include "opdef.h" /* for defining init procedure */
+#include "store.h" /* for make_array */
+
+/* Import preparation and cleanup routines. */
+extern void ialloc_gc_prepare(P1(gs_ref_memory_t *));
+
+/* Forward references */
+private void gs_vmreclaim(P2(gs_dual_memory_t *, bool));
+
+/* Initialize the GC hook in the allocator. */
+private int ireclaim(P2(gs_dual_memory_t *, int));
+private void
+ireclaim_init(void)
+{
+ gs_imemory.reclaim = ireclaim;
+}
+
+/* GC hook called when the allocator returns a VMerror (space = -1), */
+/* or for vmreclaim (space = the space to collect). */
+private int
+ireclaim(gs_dual_memory_t * dmem, int space)
+{
+ bool global;
+ gs_ref_memory_t *mem;
+
+ if (space < 0) { /* Determine which allocator got the VMerror. */
+ gs_memory_status_t stats;
+ int i;
+
+ mem = dmem->space_global; /* just in case */
+ for (i = 0; i < countof(dmem->spaces.indexed); ++i) {
+ mem = dmem->spaces.indexed[i];
+ if (mem == 0)
+ continue;
+ if (mem->gc_status.requested > 0)
+ break;
+ }
+ gs_memory_status((gs_memory_t *) mem, &stats);
+ if (stats.allocated >= mem->gc_status.max_vm) { /* We can't satisfy this request within max_vm. */
+ return_error(e_VMerror);
+ }
+ } else {
+ mem = dmem->spaces.indexed[space >> r_space_shift];
+ }
+ if_debug3('0', "[0]GC called, space=%d, requestor=%d, requested=%ld\n",
+ space, mem->space, (long)mem->gc_status.requested);
+ global = mem->space != avm_local;
+ gs_vmreclaim(dmem, global);
+
+ ialloc_set_limit(mem);
+ ialloc_reset_requested(dmem);
+ return 0;
+}
+
+/* Interpreter entry to garbage collector. */
+private void
+gs_vmreclaim(gs_dual_memory_t * dmem, bool global)
+{
+ gs_ref_memory_t *lmem = dmem->space_local;
+ gs_ref_memory_t *gmem = dmem->space_global;
+ gs_ref_memory_t *smem = dmem->space_system;
+ int code = context_state_store(gs_interp_context_state_current);
+
+/****** ABORT IF code < 0 ******/
+ alloc_close_chunk(lmem);
+ if (gmem != lmem)
+ alloc_close_chunk(gmem);
+ alloc_close_chunk(smem);
+
+ /* Prune the file list so it won't retain potentially collectible */
+ /* files. */
+
+ {
+ int i;
+
+ for (i = (global ? i_vm_system : i_vm_local);
+ i < countof(dmem->spaces.indexed);
+ ++i
+ ) {
+ gs_ref_memory_t *mem = dmem->spaces.indexed[i];
+
+ if (mem == 0 || (i > 0 && mem == dmem->spaces.indexed[i - 1]))
+ continue;
+ for (;; mem = &mem->saved->state) {
+ ialloc_gc_prepare(mem);
+ if (mem->saved == 0)
+ break;
+ }
+ }
+ }
+
+ /* Do the actual collection. */
+
+ gs_reclaim(&dmem->spaces, global);
+
+ /* Reload the context state. */
+
+ code = context_state_load(gs_interp_context_state_current);
+/****** ABORT IF code < 0 ******/
+
+ /* Update the cached value pointers in names. */
+
+ dicts_gc_cleanup();
+
+ /* Reopen the active chunks. */
+
+ alloc_open_chunk(smem);
+ if (gmem != lmem)
+ alloc_open_chunk(gmem);
+ alloc_open_chunk(lmem);
+
+ /* Update caches not handled by context_state_load. */
+
+ {
+ uint dcount = ref_stack_count(&d_stack);
+
+ *systemdict = *ref_stack_index(&d_stack, dcount - 1);
+ }
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def ireclaim_l2_op_defs[] =
+{
+ op_def_end(ireclaim_init)
+};
diff --git a/pstoraster/iref.h b/pstoraster/iref.h
new file mode 100644
index 000000000..ce4abf37c
--- /dev/null
+++ b/pstoraster/iref.h
@@ -0,0 +1,431 @@
+/* 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$ */
+/* Object structure and type definitions for Ghostscript */
+
+#ifndef iref_INCLUDED
+# define iref_INCLUDED
+
+/* The typedef for object references */
+typedef struct ref_s ref;
+
+/* The typedef for packed object references. This is opaque here: */
+/* the details are in packed.h. */
+typedef ushort ref_packed;
+
+#define log2_sizeof_ref_packed arch_log2_sizeof_short
+#define sizeof_ref_packed (1 << log2_sizeof_ref_packed)
+
+/*
+ * Define the object types.
+ * The types marked with @ are composite and hence use the a_space field;
+ * objects of all other types must have a_space cleared.
+ * The types marked with ! behave differently in the interpreter
+ * depending on whether they are executable or literal.
+ * The types marked with + use the read/write/execute
+ * attributes; the rest only use the executable attribute.
+ * The types marked with # use the size field.
+ */
+typedef enum {
+
+/*
+ * Type 0 must be left unassigned, so that the type (and type_attrs)
+ * of a valid ref will never be zero. This speeds up simultaneous
+ * type/space checking in def (see dstack.h for details) and a similar
+ * check in ref_save (see store.h for details). We may as well use
+ * type 0 for t__invalid, which will never appear in a real ref.
+ *
+ * The "invalid" type is only used in a few special places: the guard
+ * entries at the bottom of the o-stack that detect stack underflow,
+ * and (eventually) the ref that the cached value pointer in names points to
+ * if the binding isn't known. It never appears on a stack or in a
+ * program-visible data structure.
+ */
+
+ t__invalid, /* (no value) */
+ t_boolean, /* value.boolval */
+ t_dictionary, /* @ + value.pdict */
+ t_file, /* @!+# value.pfile, uses size for id */
+
+/*
+ * The 4 array types must be kept together, and must start at
+ * a multiple of 4, for the sake of r_is_array and r_is_proc (see below).
+ */
+
+#define _t_array_span 4
+ t_array, /* @!+# value.refs */
+ /* The following are the two implementations of */
+ /* packed arrays. */
+ t_mixedarray, /* @!+# value.packed */
+ t_shortarray, /* @!+# value.packed */
+ t_unused_array_, /* (an unused array type) */
+
+/*
+ * t_[a]struct is an "umbrella" for other types that are represented by
+ * allocated objects (structures). Objects of these types are composite
+ * and hence use the a_local attribute. The type name is taken from
+ * the allocator template for the structure. t_astruct objects use the
+ * access attributes; t_struct objects do not. Neither t_struct nor
+ * t_astruct objects use the size.
+ *
+ * t_struct is currently used for the following PostScript types:
+ * condition, lock.
+ * We could use it for fontIDs, except that they may have subclasses.
+ * Eventually it will also be used for the new 'device' type.
+ * t_astruct is currently used for the following PostScript types:
+ * gstate.
+ *
+ * The 2 structure types must be kept together, and must start at
+ * a multiple of 2, for the sake of r_has_stype (see below).
+ */
+
+#define _t_struct_span 2
+ t_struct, /* @ value.pstruct */
+ t_astruct, /* @ + value.pstruct */
+
+/*
+ * We now continue with individual types.
+ */
+ t_fontID, /* @ value.pstruct */
+ t_integer, /* value.intval */
+ t_mark, /* (no value) */
+/*
+ * Name objects use the a_space field because they really are composite
+ * objects internally.
+ */
+ t_name, /* @! # value.pname, uses size for index */
+ t_null, /* ! # (value.opproc, uses size for mark */
+ /* type, on e-stack only) */
+/*
+ * Operator objects use the a_space field because they may actually be
+ * disguised procedures. (Real operators always have a_space = 0.)
+ */
+ t_operator, /* @! # value.opproc, uses size for index */
+ t_real, /* value.realval */
+ t_save, /* value.saveid, see isave.h for why */
+ /* this isn't a t_struct */
+ t_string, /* @!+# value.bytes */
+/*
+ * The following are extensions to the PostScript type set.
+ * When adding new types, be sure to edit:
+ * - type_name_strings, type_print_strings, and type_properties below;
+ * - the table in gs_init.ps (==only operator);
+ * - the printing routine in idebug.c;
+ * - the dispatches in igc.c, igcref.c, and interp.c;
+ * - obj_eq in iutil.c;
+ * - restore_check_stack in zvmem.c.
+ */
+ t_device, /* @ + value.pdevice */
+ t_oparray, /* @! # value.const_refs, uses size */
+ /* for index */
+ t_next_index
+/*** first available index ***/
+} ref_type;
+
+/*
+ * The interpreter uses types starting at t_next_index for representing
+ * a few high-frequency operators.
+ * Since there are no operations specifically on operators,
+ * there is no need for any operators to check specifically for these
+ * types. The r_btype macro takes care of the conversion when required.
+ */
+ /*extern const int tx_next_index; *//* in interp.c */
+/*
+ * Define a table giving properties of types, similar to the table used
+ * by the isxxx functions (macros) in <ctype.h>.
+ */
+#define _rtype_uses_access 1 /* type uses w/r/x attributes */
+#define _rtype_uses_size 2
+#define _rtype_is_null 4
+#define _rtype_is_dictionary 8
+extern const byte ref_type_properties[1 << 6]; /* r_type_bits */
+
+#define ref_type_properties_data\
+ 0, /* t__invalid */\
+ 0, /* t_boolean */\
+ _rtype_uses_access | _rtype_is_dictionary, /* t_dictionary */\
+ _rtype_uses_access | _rtype_uses_size, /* t_file */\
+ _rtype_uses_access | _rtype_uses_size, /* t_array */\
+ _rtype_uses_access | _rtype_uses_size, /* t_mixedarray */\
+ _rtype_uses_access | _rtype_uses_size, /* t_shortarray */\
+ _rtype_uses_access | _rtype_uses_size, /* (unused array type) */\
+ 0, /* t_struct */\
+ _rtype_uses_access, /* t_astruct */\
+ 0, /* t_fontID */\
+ 0, /* t_integer */\
+ 0, /* t_mark */\
+ _rtype_uses_size, /* t_name */\
+ _rtype_is_null, /* t_null, uses size only on e-stack */\
+ _rtype_uses_size, /* t_operator */\
+ 0, /* t_real */\
+ 0, /* t_save */\
+ _rtype_uses_access | _rtype_uses_size, /* t_string */\
+ _rtype_uses_access, /* t_device */\
+ _rtype_uses_size, /* t_oparray */\
+ /*\
+ * The remaining types are the extended pseudo-types used by the\
+ * interpreter for operators. We need to fill up the table.\
+ */\
+ _rtype_uses_size,_rtype_uses_size,_rtype_uses_size, /*24*/\
+ _rtype_uses_size,_rtype_uses_size,_rtype_uses_size,_rtype_uses_size, /*28*/\
+ _rtype_uses_size,_rtype_uses_size,_rtype_uses_size,_rtype_uses_size, /*32*/\
+ _rtype_uses_size,_rtype_uses_size,_rtype_uses_size,_rtype_uses_size, /*36*/\
+ _rtype_uses_size,_rtype_uses_size,_rtype_uses_size,_rtype_uses_size, /*40*/\
+ _rtype_uses_size,_rtype_uses_size,_rtype_uses_size,_rtype_uses_size, /*44*/\
+ _rtype_uses_size,_rtype_uses_size,_rtype_uses_size,_rtype_uses_size, /*48*/\
+ _rtype_uses_size,_rtype_uses_size,_rtype_uses_size,_rtype_uses_size, /*52*/\
+ _rtype_uses_size,_rtype_uses_size,_rtype_uses_size,_rtype_uses_size, /*56*/\
+ _rtype_uses_size,_rtype_uses_size,_rtype_uses_size,_rtype_uses_size, /*60*/\
+ _rtype_uses_size,_rtype_uses_size,_rtype_uses_size,_rtype_uses_size /*64 */
+#define _rtype_has(rtype,props)\
+ ((ref_type_properties[rtype] & (props)) != 0)
+#define ref_type_uses_access(rtype)\
+ _rtype_has(rtype, _rtype_uses_access)
+#define ref_type_uses_size(rtype)\
+ _rtype_has(rtype, _rtype_uses_size)
+#define ref_type_uses_size_or_null(rtype)\
+ _rtype_has(rtype, _rtype_uses_size | _rtype_is_null)
+/*
+ * Define the type names for debugging printout.
+ * All names must be the same length, so that columns will line up.
+ */
+#define type_print_strings\
+ "INVL","bool","dict","file",\
+ "arry","mpry","spry","u?ry",\
+ "STRC","ASTR",\
+ "font","int ","mark","name","null",\
+ "oper","real","save","str ",\
+ "devc","opry"
+/*
+ * Define the type names for the type operator.
+ */
+#define type_name_strings\
+ 0,"booleantype","dicttype","filetype",\
+ "arraytype","packedarraytype","packedarraytype","arraytype",\
+ 0,0,\
+ "fonttype","integertype","marktype","nametype","nulltype",\
+ "operatortype","realtype","savetype","stringtype",\
+ "devicetype","operatortype"
+
+/*
+ * The following factors affect the encoding of attributes:
+ *
+ * - The packed array format requires the high-order bits of the
+ * type/attributes field to be 0. (see packed.h)
+ *
+ * - The interpreter wants the type, executable bit, and execute
+ * permission to be adjacent, and in that order from high to low.
+ *
+ * - Type testing is most efficient if the type is in a byte by itself.
+ *
+ * The layout given below results in the most efficient code overall.
+ */
+
+/* Location attributes. */
+/* Note that these are associated with the *location*, not with the */
+/* ref that is *stored* in that location. */
+#define l_mark 1 /* mark for garbage collector */
+#define l_new 2 /* stored into since last save */
+/* Attributes visible at the PostScript language level. */
+/* Reserve bits for VM space information (defined in ivmspace.h). */
+#define r_space_bits 2
+#define r_space_shift 2
+#define a_write 0x10
+#define a_read 0x20
+#define a_execute 0x40
+#define a_executable 0x80
+#define a_readonly (a_read+a_execute)
+#define a_all (a_write+a_read+a_execute)
+#define r_type_shift 8
+#define r_type_bits 6
+
+/* Define the attribute names for debugging printout. */
+/* Each entry has the form <mask, value, character>. */
+typedef struct attr_print_mask_s {
+ ushort mask;
+ ushort value;
+ char print;
+} attr_print_mask;
+
+#define attr_print_flag(m,c)\
+ {m,m,c},{m,0,'-'}
+#define attr_print_space(v,c)\
+ {((1<<r_space_bits)-1)<<r_space_shift,v,c}
+#define attr_print_masks\
+ attr_print_flag(l_mark,'m'),\
+ attr_print_flag(l_new,'n'),\
+ attr_print_space(avm_foreign,'F'),\
+ attr_print_space(avm_system,'S'),\
+ attr_print_space(avm_global,'G'),\
+ attr_print_space(avm_local,'L'),\
+ attr_print_flag(a_write,'w'),\
+ attr_print_flag(a_read,'r'),\
+ attr_print_flag(a_execute,'x'),\
+ attr_print_flag(a_executable,'e'),\
+ attr_print_flag(0x4000,'?'),\
+ attr_print_flag(0x8000,'?')
+
+/* Abstract types */
+typedef struct dict_s dict;
+typedef struct name_s name;
+
+#ifndef stream_DEFINED
+# define stream_DEFINED
+typedef struct stream_s stream;
+
+#endif
+#ifndef gx_device_DEFINED
+# define gx_device_DEFINED
+typedef struct gx_device_s gx_device;
+
+#endif
+#ifndef obj_header_DEFINED
+# define obj_header_DEFINED
+typedef struct obj_header_s obj_header_t;
+
+#endif
+/* We duplicate the definition of os_ptr (a.k.a. s_ptr) here */
+/* so that we can have an accurate typedef for op_proc */
+/* without having to drag in istack.h and ostack.h. */
+typedef int (*op_proc_p) (P1(ref *));
+
+/* real_opproc is a holdover.... */
+#define real_opproc(pref) ((pref)->value.opproc)
+
+/* Object reference */
+/*
+ * Note that because of the way packed arrays are represented,
+ * the type_attrs member must be the first one in the ref structure.
+ */
+struct tas_s {
+ ushort type_attrs;
+ ushort rsize;
+};
+struct ref_s {
+
+ struct tas_s tas;
+
+#define r_size(rp) ((rp)->tas.rsize)
+#define r_inc_size(rp,inc) ((rp)->tas.rsize += (inc))
+#define r_dec_size(rp,dec) ((rp)->tas.rsize -= (dec))
+#define r_set_size(rp,siz) ((rp)->tas.rsize = (siz))
+/* type_attrs is a single element for fast dispatching in the interpreter */
+#if r_type_shift == 8
+# if arch_is_big_endian
+# define r_type(rp) (((const byte *)&((rp)->tas.type_attrs))[sizeof(ushort)-2])
+# else
+# define r_type(rp) (((const byte *)&((rp)->tas.type_attrs))[1])
+# endif
+# define r_has_type(rp,typ) (r_type(rp) == (typ))
+#else
+# define r_type(rp) ((rp)->tas.type_attrs >> r_type_shift)
+# define r_has_type(rp,typ) r_has_type_attrs(rp,typ,0) /* see below */
+#endif
+/* A special macro for testing arrayhood. */
+#define r_is_array(rp) _r_has_masked_type_attrs(rp,t_array,_t_array_span,0)
+#define r_set_type(rp,typ) ((rp)->tas.type_attrs = (typ) << r_type_shift)
+#define r_btype(rp)\
+ ((rp)->tas.type_attrs >= (t_next_index << r_type_shift) ?\
+ t_operator : r_type(rp))
+#define r_type_xe_shift (r_type_shift - 2)
+#define type_xe_(tas) ((tas) >> r_type_xe_shift) /* internal use only */
+/* The r_type_xe macro is used in (and only in) the main interpreter loop,
+ * where its rp operand may be a ref_packed, not necessarily aligned as
+ * strictly as a full-size ref. */
+#define r_type_xe(rp)\
+ type_xe_(PACKED(rp)[offset_of(ref, tas.type_attrs) / sizeof(ushort)])
+#define type_xe_value(t,xe) type_xe_(((t) << r_type_shift) + (xe))
+#define r_type_attrs(rp) ((rp)->tas.type_attrs) /* reading only */
+#define r_has_attrs(rp,mask) !(~r_type_attrs(rp) & (mask))
+#define r_has_masked_attrs(rp,attrs,mask)\
+ ((r_type_attrs(rp) & (mask)) == (attrs))
+#define r_has_attr(rp,mask1) /* optimize 1-bit case */\
+ (r_type_attrs(rp) & (mask1))
+/* The following macro is not for external use. */
+#define _r_has_masked_type_attrs(rp,typ,tspan,mask)\
+ (((rp)->tas.type_attrs &\
+ ((((1 << r_type_bits) - (tspan)) << r_type_shift) + (mask))) ==\
+ (((typ) << r_type_shift) + (mask)))
+#define r_has_type_attrs(rp,typ,mask)\
+ _r_has_masked_type_attrs(rp,typ,1,mask)
+/* A special macro for testing procedurehood. */
+#define r_is_proc(rp)\
+ _r_has_masked_type_attrs(rp,t_array,_t_array_span,a_execute+a_executable)
+#define r_set_attrs(rp,mask) ((rp)->tas.type_attrs |= (mask))
+#define r_clear_attrs(rp,mask) ((rp)->tas.type_attrs &= ~(mask))
+#define r_store_attrs(rp,mask,attrs)\
+ ((rp)->tas.type_attrs = ((rp)->tas.type_attrs & ~(mask)) | (attrs))
+#define r_copy_attrs(rp,mask,sp)\
+ r_store_attrs(rp,mask,(sp)->tas.type_attrs & (mask))
+#define r_set_type_attrs(rp,typ,mask)\
+ ((rp)->tas.type_attrs = ((typ) << r_type_shift) + (mask))
+/* Macros for t_[a]struct objects. */
+#define r_is_struct(rp) _r_has_masked_type_attrs(rp,t_struct,_t_struct_span,0)
+#define r_has_stype(rp,mem,styp)\
+ (r_is_struct(rp) && gs_object_type(mem, (rp)->value.pstruct) == &styp)
+#define r_ptr(rp,typ) ((typ *)((rp)->value.pstruct))
+#define r_set_ptr(rp,ptr) ((rp)->value.pstruct = (obj_header_t *)(ptr))
+
+ union v { /* name the union to keep gdb happy */
+ long intval;
+ ushort boolval;
+ float realval;
+ ulong saveid;
+ byte *bytes;
+ const byte *const_bytes;
+ ref *refs;
+ const ref *const_refs;
+ name *pname;
+ const name *const_pname;
+ dict *pdict;
+ const dict *const_pdict;
+ const ref_packed *packed;
+ op_proc_p opproc;
+ struct stream_s *pfile;
+ struct gx_device_s *pdevice;
+ obj_header_t *pstruct;
+ } value;
+};
+
+/* Define data for initializing an empty array or string. */
+#define empty_ref_data(type, attrs)\
+ { /*tas*/ { /*type_attrs*/ ((type) << r_type_shift) | (attrs),\
+ /*rsize*/ 0 } }
+
+/* Define the size of a ref. */
+#define arch_sizeof_ref sizeof(ref)
+/* Define the required alignment for refs. */
+/* We assume all alignment values are powers of 2. */
+#define arch_align_ref_mod\
+ (((arch_align_long_mod - 1) | (arch_align_float_mod - 1) |\
+ (arch_align_ptr_mod - 1)) + 1)
+
+/* Define the maximum size of an array or a string. */
+/* The maximum array size is determined by the fact that */
+/* the allocator cannot allocate a block larger than max_uint. */
+#define max_array_size (max_ushort & (max_uint / (uint)arch_sizeof_ref))
+#define max_string_size max_ushort
+
+#endif /* iref_INCLUDED */
diff --git a/pstoraster/isave.c b/pstoraster/isave.c
new file mode 100644
index 000000000..d8e352912
--- /dev/null
+++ b/pstoraster/isave.c
@@ -0,0 +1,1070 @@
+/* Copyright (C) 1993, 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$ */
+/* Save/restore manager for Ghostscript interpreter */
+#include "ghost.h"
+#include "memory_.h"
+#include "errors.h"
+#include "gsexit.h"
+#include "gsstruct.h"
+#include "stream.h" /* for linking for forgetsave */
+#include "iastate.h"
+#include "inamedef.h"
+#include "iname.h"
+#include "ipacked.h"
+#include "isave.h"
+#include "isstate.h"
+#include "store.h" /* for ref_assign */
+#include "ivmspace.h"
+#include "gsutil.h" /* gs_next_ids prototype */
+
+/* Imported save/restore routines */
+extern void font_restore(P1(const alloc_save_t *));
+
+/* Structure descriptor */
+private_st_alloc_save();
+
+/* Define the maximum amount of data we are willing to scan repeatedly -- */
+/* see below for details. */
+private const long max_repeated_scan = 100000;
+
+/* Some compilers try to substitute macro args in string literals! */
+#define print_save(str, spacen, sav)\
+ if_debug5('u', "[u]%s space %u 0x%lx: cdata = 0x%lx, id = %lu\n",\
+ str, spacen, (ulong)(sav), (ulong)(sav)->client_data, (ulong)(sav)->id);
+
+/*
+ * The logic for saving and restoring the state is complex.
+ * Both the changes to individual objects, and the overall state
+ * of the memory manager, must be saved and restored.
+ */
+
+/*
+ * To save the state of the memory manager:
+ * Save the state of the current chunk in which we are allocating.
+ * Shrink the current chunk to its inner unallocated region.
+ * Save and reset the free block chains.
+ * By doing this, we guarantee that no object older than the save
+ * can be freed.
+ *
+ * To restore the state of the memory manager:
+ * Free all chunks newer than the save, and the descriptor for
+ * the inner chunk created by the save.
+ * Make current the chunk that was current at the time of the save.
+ * Restore the state of the current chunk.
+ *
+ * In addition to save ("start transaction") and restore ("abort transaction"),
+ * we support forgetting a save ("commit transation"). To forget a save:
+ * Reassign to the next outer save all chunks newer than the save.
+ * Free the descriptor for the inner chunk, updating its outer chunk
+ * to reflect additional allocations in the inner chunk.
+ * Concatenate the free block chains with those of the outer save.
+ */
+
+/*
+ * For saving changes to individual objects, we add an "attribute" bit
+ * (l_new) that logically belongs to the slot where the ref is stored,
+ * not to the ref itself. The bit means "the contents of this slot
+ * have been changed, or the slot was allocated, since the last save."
+ * To keep track of changes since the save, we associate a chain of
+ * <slot, old_contents> pairs that remembers the old contents of slots.
+ *
+ * When creating an object, if the save level is non-zero:
+ * Set l_new in all slots.
+ *
+ * When storing into a slot, if the save level is non-zero:
+ * If l_new isn't set, save the address and contents of the slot
+ * on the current contents chain.
+ * Set l_new after storing the new value.
+ *
+ * To do a save:
+ * If the save level is non-zero:
+ * Reset l_new in all slots on the contents chain, and in all
+ * objects created since the previous save.
+ * Push the head of the contents chain, and reset the chain to empty.
+ *
+ * To do a restore:
+ * Check all the stacks to make sure they don't contain references
+ * to objects created since the save.
+ * Restore all the slots on the contents chain.
+ * Pop the contents chain head.
+ * If the save level is now non-zero:
+ * Scan the newly restored contents chain, and set l_new in all
+ * the slots it references.
+ * Scan all objects created since the previous save, and set
+ * l_new in all the slots of each object.
+ *
+ * To forget a save:
+ * If the save level is greater than 1:
+ * Set l_new as for a restore, per the next outer save.
+ * Concatenate the next outer contents chain to the end of
+ * the current one.
+ * If the save level is 1:
+ * Reset l_new as for a save.
+ * Free the contents chain.
+ */
+
+/*
+ * A consequence of the foregoing algorithms is that the cost of a save
+ * is proportional to the total amount of data allocated since the previous
+ * save. If a PostScript program reads in a large amount of setup code
+ * and then uses save/restore heavily, each save/restore will be expensive.
+ * To mitigate this, we check to see how much data we are scanning at a save;
+ * if it is large, we do a second, invisible save. This greatly reduces
+ * the cost of inner saves, at the expense of possibly saving some changes
+ * twice that otherwise would only have to be saved once.
+ */
+
+/*
+ * The presence of global and local VM complicates the situation further.
+ * There is a separate save chain and contents chain for each VM space.
+ * When multiple contexts are fully implemented, save and restore will have
+ * the following effects, according to the privacy status of the current
+ * context's global and local VM:
+ * Private global, private local:
+ * The outermost save saves both global and local VM;
+ * otherwise, save only saves local VM.
+ * Shared global, private local:
+ * Save only saves local VM.
+ * Shared global, shared local:
+ * Save only saves local VM, and suspends all other contexts
+ * sharing the same local VM until the matching restore.
+ * Since we do not currently implement multiple contexts, only the first
+ * case is relevant.
+ *
+ * Note that when saving the contents of a slot, the choice of chain
+ * is determined by the VM space in which the slot is allocated,
+ * not by the current allocation mode.
+ */
+
+/*
+ * Structure for saved change chain for save/restore. Because of the
+ * garbage collector, we need to distinguish the cases where the change
+ * is in a static object, a dynamic ref, or a dynamic struct.
+ */
+typedef struct alloc_change_s alloc_change_t;
+struct alloc_change_s {
+ alloc_change_t *next;
+ ref_packed *where;
+ ref contents;
+#define ac_offset_static (-2) /* static object */
+#define ac_offset_ref (-1) /* dynamic ref */
+ short offset; /* if >= 0, offset within struct */
+};
+
+#define ptr ((alloc_change_t *)vptr)
+private
+CLEAR_MARKS_PROC(change_clear_marks)
+{
+ if (r_is_packed(&ptr->contents))
+ r_clear_pmark((ref_packed *) & ptr->contents);
+ else
+ r_clear_attrs(&ptr->contents, l_mark);
+}
+private
+ENUM_PTRS_BEGIN(change_enum_ptrs) return 0;
+
+ENUM_PTR(0, alloc_change_t, next);
+case 1:
+if (ptr->offset >= 0)
+ ENUM_RETURN((byte *) ptr->where - ptr->offset);
+else
+ ENUM_RETURN_REF(ptr->where);
+case 2:
+ENUM_RETURN_REF(&ptr->contents);
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(change_reloc_ptrs)
+{
+ RELOC_VAR(ptr->next);
+ switch (ptr->offset) {
+ case ac_offset_static:
+ break;
+ case ac_offset_ref:
+ RELOC_REF_PTR_VAR(ptr->where);
+ break;
+ default:
+ {
+ byte *obj = (byte *) ptr->where - ptr->offset;
+
+ RELOC_VAR(obj);
+ ptr->where = (ref_packed *) (obj + ptr->offset);
+ }
+ break;
+ }
+ if (r_is_packed(&ptr->contents))
+ r_clear_pmark((ref_packed *) & ptr->contents);
+ else {
+ RELOC_REF_VAR(ptr->contents);
+ r_clear_attrs(&ptr->contents, l_mark);
+ }
+}
+RELOC_PTRS_END
+#undef ptr
+gs_private_st_complex_only(st_alloc_change, alloc_change_t, "alloc_change",
+ change_clear_marks, change_enum_ptrs, change_reloc_ptrs, 0);
+
+/* Debugging printout */
+#ifdef DEBUG
+private void
+alloc_save_print(alloc_change_t * cp, bool print_current)
+{
+ dprintf2(" 0x%lx: 0x%lx: ", (ulong) cp, (ulong) cp->where);
+ if (r_is_packed(&cp->contents)) {
+ if (print_current)
+ dprintf2("saved=%x cur=%x\n", *(ref_packed *) & cp->contents,
+ *cp->where);
+ else
+ dprintf1("%x\n", *(ref_packed *) & cp->contents);
+ } else {
+ if (print_current)
+ dprintf6("saved=%x %x %lx cur=%x %x %lx\n",
+ r_type_attrs(&cp->contents), r_size(&cp->contents),
+ (ulong) cp->contents.value.intval,
+ r_type_attrs((ref *) cp->where),
+ r_size((ref *) cp->where),
+ (ulong) ((ref *) cp->where)->value.intval);
+ else
+ dprintf3("%x %x %lx\n",
+ r_type_attrs(&cp->contents), r_size(&cp->contents),
+ (ulong) cp->contents.value.intval);
+ }
+}
+#endif
+
+/* Forward references */
+private void restore_resources(P2(alloc_save_t *, gs_ref_memory_t *));
+private void restore_free(P1(gs_ref_memory_t *));
+private long save_set_new(P2(gs_ref_memory_t *, bool));
+private void save_set_new_changes(P2(gs_ref_memory_t *, bool));
+
+/* Initialize the save/restore machinery. */
+void
+alloc_save_init(gs_dual_memory_t * dmem)
+{
+ dmem->save_level = 0;
+ alloc_set_not_in_save(dmem);
+}
+
+/* Record that we are in a save. */
+void
+alloc_set_in_save(gs_dual_memory_t *dmem)
+{
+ dmem->test_mask = dmem->new_mask = l_new;
+}
+
+/* Record that we are not in a save. */
+void
+alloc_set_not_in_save(gs_dual_memory_t *dmem)
+{
+ dmem->test_mask = ~0;
+ dmem->new_mask = 0;
+}
+
+/* Save the state. */
+private alloc_save_t *alloc_save_space(P2(gs_ref_memory_t *,
+ gs_dual_memory_t *));
+
+ulong
+alloc_save_state(gs_dual_memory_t * dmem, void *cdata)
+{
+ gs_ref_memory_t *lmem = dmem->space_local;
+ gs_ref_memory_t *gmem = dmem->space_global;
+ ulong sid = gs_next_ids(2);
+
+#define alloc_free_save(mem, s, scn, icn)\
+ { chunk_t *inner = (mem)->pcc;\
+ gs_free_object((gs_memory_t *)(mem), s, scn);\
+ gs_free_object((mem)->parent, inner, icn);\
+ }
+ bool global =
+ dmem->save_level == 0 && gmem != lmem &&
+ gmem->num_contexts == 1;
+ alloc_save_t *gsave =
+ (global ? alloc_save_space(gmem, dmem) : (alloc_save_t *) 0);
+ alloc_save_t *lsave = alloc_save_space(lmem, dmem);
+
+ if (lsave == 0 || (global &&gsave == 0)) {
+ if (lsave != 0)
+ alloc_free_save(lmem, lsave, "alloc_save_state(local save)",
+ "alloc_save_state(local inner)");
+ if (gsave != 0)
+ alloc_free_save(gmem, gsave, "alloc_save_state(global save)",
+ "alloc_save_state(global inner)");
+ return 0;
+ }
+#undef alloc_free_save
+ if (gsave != 0) {
+ gsave->id = sid + 1;
+ gsave->client_data = 0;
+ print_save("save", gmem->space, gsave);
+ /* Restore names when we do the local restore. */
+ lsave->restore_names = gsave->restore_names;
+ gsave->restore_names = false;
+ }
+ lsave->id = sid;
+ lsave->client_data = cdata;
+ print_save("save", lmem->space, lsave);
+ /* Reset the l_new attribute in all slots. The only slots that */
+ /* can have the attribute set are the ones on the changes chain, */
+ /* and ones in objects allocated since the last save. */
+ if (dmem->save_level != 0) {
+ long scanned = save_set_new(&lsave->state, false);
+
+ if (scanned > max_repeated_scan) { /* Do a second, invisible save. */
+ alloc_save_t *rsave;
+
+ rsave = alloc_save_space(lmem, dmem);
+ if (rsave != 0) {
+ rsave->id = sid;
+ rsave->client_data = cdata;
+ print_save("save", lmem->space, rsave);
+ lsave->id = 0; /* mark as invisible */
+ lsave->client_data = 0;
+ /* Inherit the allocated space count -- */
+ /* we need this for triggering a GC. */
+ rsave->state.inherited =
+ lsave->state.allocated +
+ lsave->state.inherited;
+ lmem->inherited = rsave->state.inherited;
+ print_save("save", lmem->space, lsave);
+ }
+ }
+ }
+ dmem->save_level++;
+ alloc_set_in_save(dmem);
+ return sid;
+}
+/* Save the state of one space (global or local). */
+private alloc_save_t *
+alloc_save_space(gs_ref_memory_t * mem, gs_dual_memory_t * dmem)
+{
+ gs_ref_memory_t save_mem;
+ alloc_save_t *save;
+ chunk_t *inner = 0;
+
+ if (mem->cc.ctop - mem->cc.cbot > sizeof(chunk_head_t)) {
+ inner = gs_raw_alloc_struct_immovable(mem->parent, &st_chunk,
+ "alloc_save_space(inner)");
+ if (inner == 0)
+ return 0;
+ }
+ save_mem = *mem;
+ alloc_close_chunk(mem);
+ gs_memory_status((gs_memory_t *) mem, &mem->previous_status);
+ ialloc_reset(mem);
+ mem->cc.cnext = mem->cc.cprev = 0;
+ if (inner != 0) { /* Create an inner chunk to cover only the unallocated part. */
+ alloc_init_chunk(&mem->cc, mem->cc.cbot, mem->cc.ctop,
+ true, mem->pcc);
+ *inner = mem->cc;
+ mem->pcc = inner;
+ mem->cfirst = mem->clast = inner;
+ } else { /* Not enough room to create an inner chunk. */
+ mem->pcc = 0;
+ mem->cfirst = mem->clast = 0;
+ mem->cc.cbot = mem->cc.ctop = 0;
+ }
+ save = gs_alloc_struct((gs_memory_t *) mem, alloc_save_t,
+ &st_alloc_save, "alloc_save_space(save)");
+#ifdef DEBUG
+ if (inner != 0) {
+ if_debug4('u',
+ "[u]save space %u at 0x%lx: cbot=0x%lx ctop=0x%lx\n",
+ mem->space, (ulong) save,
+ (ulong) inner->cbot, (ulong) inner->ctop);
+ } else {
+ if_debug2('u',
+ "[u]save space %u at 0x%lx (no inner)\n",
+ mem->space, (ulong) save);
+ }
+#endif
+ if (save == 0) {
+ gs_free_object(mem->parent, inner, "alloc_save_space(inner)");
+ *mem = save_mem;
+ return 0;
+ }
+ save->state = save_mem;
+ save->dmem = dmem;
+ save->restore_names = (name_memory() == (gs_memory_t *) mem);
+ save->is_current = (dmem->current == mem);
+ mem->saved = save;
+ if_debug2('u', "[u%u]file_save 0x%lx\n",
+ mem->space, (ulong) mem->streams);
+ mem->streams = 0;
+ return save;
+}
+
+/* Record a state change that must be undone for restore, */
+/* and mark it as having been saved. */
+int
+alloc_save_change(gs_dual_memory_t * dmem, const ref * pcont,
+ ref_packed * where, client_name_t cname)
+{
+ gs_ref_memory_t *mem;
+ register alloc_change_t *cp;
+
+ if (dmem->save_level == 0)
+ return 0; /* no saving */
+ mem = (pcont == NULL ? dmem->space_local :
+ dmem->spaces.indexed[r_space(pcont) >> r_space_shift]);
+ cp = gs_alloc_struct((gs_memory_t *) mem, alloc_change_t,
+ &st_alloc_change, "alloc_save_change");
+ if (cp == 0)
+ return -1;
+ cp->next = mem->changes;
+ cp->where = where;
+ if (pcont == NULL)
+ cp->offset = ac_offset_static;
+ else if (r_is_array(pcont) || r_has_type(pcont, t_dictionary))
+ cp->offset = ac_offset_ref;
+ else if (r_is_struct(pcont))
+ cp->offset = (byte *) where - (byte *) pcont->value.pstruct;
+ else {
+ lprintf3("Bad type %u for save! pcont = 0x%lx, where = 0x%lx\n",
+ r_type(pcont), (ulong) pcont, (ulong) where);
+ gs_abort();
+ }
+ if (r_is_packed(where))
+ *(ref_packed *)(&(cp->contents)) = *where;
+ else {
+/* MRS - the following inline assign didn't work...
+ ref_assign_inline(&cp->contents, (ref *) where);*/
+ ref_assign((&(cp->contents)), (ref *) where);
+ r_set_attrs((ref *) where, l_new);
+ }
+ mem->changes = cp;
+#ifdef DEBUG
+ if (gs_debug_c('U')) {
+ dlprintf1("[u]save(%s)", client_name_string(cname));
+ alloc_save_print(cp, false);
+ }
+#endif
+ return 0;
+}
+
+/* Return the current save level */
+int
+alloc_save_level(const gs_dual_memory_t * dmem)
+{
+ return dmem->save_level;
+}
+
+/* Return (the id of) the innermost externally visible save object, */
+/* i.e., the innermost save with a non-zero ID. */
+ulong
+alloc_save_current_id(const gs_dual_memory_t * dmem)
+{
+ const alloc_save_t *save = dmem->space_local->saved;
+
+ while (save != 0 && save->id == 0)
+ save = save->state.saved;
+ return save->id;
+}
+alloc_save_t *
+alloc_save_current(const gs_dual_memory_t * dmem)
+{
+ return alloc_find_save(dmem, alloc_save_current_id(dmem));
+}
+
+/* Test whether a reference would be invalidated by a restore. */
+bool
+alloc_is_since_save(const void *vptr, const alloc_save_t * save)
+{
+#define ptr ((const char *)vptr)
+
+ /* A reference postdates a save iff it is in a chunk allocated */
+ /* since the save (including the carried-over inner chunk). */
+
+ const gs_dual_memory_t *dmem = save->dmem;
+ register const gs_ref_memory_t *mem = dmem->space_local;
+
+ if_debug2('U', "[U]is_since_save 0x%lx, 0x%lx:\n",
+ (ulong) ptr, (ulong) save);
+ if (mem->saved == 0) { /* This is a special case, the final 'restore' from */
+ /* alloc_restore_all. */
+ return true;
+ }
+ /* Check against chunks allocated since the save. */
+ /* (There may have been intermediate saves as well.) */
+ for (;; mem = &mem->saved->state) {
+ const chunk_t *cp;
+
+ if_debug1('U', "[U]checking mem=0x%lx\n", (ulong) mem);
+ for (cp = mem->cfirst; cp != 0; cp = cp->cnext) {
+ if (ptr_is_within_chunk(ptr, cp)) {
+ if_debug3('U', "[U+]in new chunk 0x%lx: 0x%lx, 0x%lx\n",
+ (ulong) cp,
+ (ulong) cp->cbase, (ulong) cp->cend);
+ return true;
+ }
+ if_debug1('U', "[U-]not in 0x%lx\n", (ulong) cp);
+ }
+ if (mem->saved == save) { /* We've checked all the more recent saves, */
+ /* must be OK. */
+ break;
+ }
+ }
+
+ /*
+ * If we're about to do a global restore (save level = 1),
+ * and there is only one context using this global VM
+ * (the normal case, in which global VM is saved by the
+ * outermost save), we also have to check the global save.
+ * Global saves can't be nested, which makes things easy.
+ */
+ if (dmem->save_level == 1 &&
+ (mem = dmem->space_global) != dmem->space_local &&
+ dmem->space_global->num_contexts == 1
+ ) {
+ const chunk_t *cp;
+
+ if_debug1('U', "[U]checking global mem=0x%lx\n", (ulong) mem);
+ for (cp = mem->cfirst; cp != 0; cp = cp->cnext)
+ if (ptr_is_within_chunk(ptr, cp)) {
+ if_debug3('U', "[U+] new chunk 0x%lx: 0x%lx, 0x%lx\n",
+ (ulong) cp, (ulong) cp->cbase, (ulong) cp->cend);
+ return true;
+ }
+ }
+ return false;
+
+#undef ptr
+}
+
+/* Test whether a name would be invalidated by a restore. */
+bool
+alloc_name_is_since_save(const ref * pnref, const alloc_save_t * save)
+{
+ const name *pname;
+
+ if (!save->restore_names)
+ return false;
+ pname = pnref->value.pname;
+ if (pname->foreign_string)
+ return false;
+ return alloc_is_since_save(pname->string_bytes, save);
+}
+bool
+alloc_name_index_is_since_save(uint nidx, const alloc_save_t * save)
+{
+ ref nref;
+
+ nref.value.pname = name_index_ptr(nidx);
+ return alloc_name_is_since_save(&nref, save);
+}
+
+/* Check whether any names have been created since a given save */
+/* that might be released by the restore. */
+bool
+alloc_any_names_since_save(const alloc_save_t * save)
+{
+ return save->restore_names;
+}
+
+/* Get the saved state with a given ID. */
+alloc_save_t *
+alloc_find_save(const gs_dual_memory_t * dmem, ulong sid)
+{
+ alloc_save_t *sprev = dmem->space_local->saved;
+
+ if (sid == 0)
+ return 0; /* invalid id */
+ while (sprev != 0) {
+ if (sprev->id == sid)
+ return sprev;
+ sprev = sprev->state.saved;
+ }
+ return 0;
+}
+
+/* Get the client data from a saved state. */
+void *
+alloc_save_client_data(const alloc_save_t * save)
+{
+ return save->client_data;
+}
+
+/*
+ * Do one step of restoring the state. The client is responsible for
+ * calling alloc_find_save to get the save object, and for ensuring that
+ * there are no surviving pointers for which alloc_is_since_save is true.
+ * Return true if the argument was the innermost save, in which case
+ * this is the last (or only) step.
+ * Note that "one step" may involve multiple internal steps,
+ * if this is the outermost restore (which requires restoring both local
+ * and global VM) or if we created extra save levels to reduce scanning.
+ */
+private void restore_finalize(P1(gs_ref_memory_t *));
+private void restore_space(P1(gs_ref_memory_t *));
+
+bool
+alloc_restore_state_step(alloc_save_t * save)
+{
+ gs_dual_memory_t *dmem = save->dmem;
+ gs_ref_memory_t *mem = dmem->space_local;
+ alloc_save_t *sprev;
+
+ /* Do one (externally visible) step of restoring the state. */
+ do {
+ ulong sid;
+
+ sprev = mem->saved;
+ sid = sprev->id;
+ restore_finalize(mem); /* finalize objects */
+ restore_resources(sprev, mem); /* release other resources */
+ restore_space(mem); /* release memory */
+ if (sid != 0) {
+ dmem->save_level--;
+ break;
+ }
+ }
+ while (sprev != save);
+
+ if (dmem->save_level == 0) { /* This is the outermost save, which might also */
+ /* need to restore global VM. */
+ mem = dmem->space_global;
+ if (mem != dmem->space_local && mem->saved != 0) {
+ restore_finalize(mem);
+ restore_resources(mem->saved, mem);
+ restore_space(mem);
+ }
+ alloc_set_not_in_save(dmem);
+ } else { /* Set the l_new attribute in all slots that are now new. */
+ save_set_new(mem, true);
+ }
+
+ return sprev == save;
+}
+/* Restore the memory of one space, by undoing changes and freeing */
+/* memory allocated since the save. */
+private void
+restore_space(gs_ref_memory_t * mem)
+{
+ alloc_save_t *save = mem->saved;
+ alloc_save_t saved;
+
+ print_save("restore", mem->space, save);
+
+ /* Undo changes since the save. */
+ {
+ register alloc_change_t *cp = mem->changes;
+
+ while (cp) {
+#ifdef DEBUG
+ if (gs_debug_c('U')) {
+ dlputs("[U]restore");
+ alloc_save_print(cp, true);
+ }
+#endif
+ if (r_is_packed(&cp->contents))
+ *cp->where = *(ref_packed *) & cp->contents;
+ else
+ ref_assign_inline((ref *) cp->where, &cp->contents);
+ cp = cp->next;
+ }
+ }
+
+ /* Free memory allocated since the save. */
+ /* Note that this frees all chunks except the inner one */
+ /* belonging to this level. */
+ saved = *save;
+ restore_free(mem);
+
+ /* Restore the allocator state. */
+ {
+ int num_contexts = mem->num_contexts; /* don't restore */
+
+ *mem = saved.state;
+ mem->num_contexts = num_contexts;
+ }
+ alloc_open_chunk(mem);
+
+ /* Make the allocator current if it was current before the save. */
+ if (saved.is_current) {
+ gs_dual_memory_t *dmem = saved.dmem;
+
+ dmem->current = mem;
+ dmem->current_space = mem->space;
+ }
+}
+
+/* Restore to the initial state, releasing all resources. */
+/* The allocator is no longer usable after calling this routine! */
+void
+alloc_restore_all(gs_dual_memory_t * dmem)
+{
+ /* Restore to a state outside any saves. */
+ while (dmem->save_level != 0)
+ discard(alloc_restore_state_step(dmem->space_local->saved));
+
+ /* Finalize memory. */
+ restore_finalize(dmem->space_local);
+ {
+ gs_ref_memory_t *mem = dmem->space_global;
+
+ if (mem != dmem->space_local && mem->num_contexts == 1)
+ restore_finalize(mem);
+ }
+ restore_finalize(dmem->space_system);
+
+ /* Release resources other than memory, using fake */
+ /* save and memory objects. */
+ {
+ alloc_save_t empty_save;
+
+ empty_save.dmem = dmem;
+ empty_save.restore_names = false; /* don't bother to release */
+ restore_resources(&empty_save, NULL);
+ }
+
+ /* Finally, release memory. */
+ restore_free(dmem->space_local);
+ {
+ gs_ref_memory_t *mem = dmem->space_global;
+
+ if (mem != dmem->space_local) {
+ if (!--(mem->num_contexts))
+ restore_free(mem);
+ }
+ }
+ restore_free(dmem->space_system);
+
+}
+
+/*
+ * Finalize objects that will be freed by a restore.
+ * Note that we must temporarily disable the freeing operations
+ * of the allocator while doing this.
+ */
+private void
+restore_finalize(gs_ref_memory_t * mem)
+{
+ chunk_t *cp;
+
+ alloc_close_chunk(mem);
+ gs_enable_free((gs_memory_t *) mem, false);
+ for (cp = mem->clast; cp != 0; cp = cp->cprev) {
+ SCAN_CHUNK_OBJECTS(cp)
+ DO_ALL
+ struct_proc_finalize((*finalize)) =
+ pre->o_type->finalize;
+ if (finalize != 0) {
+ if_debug2('u', "[u]restore finalizing %s 0x%lx\n",
+ struct_type_name_string(pre->o_type),
+ (ulong) (pre + 1));
+ (*finalize) (pre + 1);
+ }
+ END_OBJECTS_SCAN
+ }
+ gs_enable_free((gs_memory_t *) mem, true);
+}
+
+/* Release resources for a restore */
+private void
+restore_resources(alloc_save_t * sprev, gs_ref_memory_t * mem)
+{
+#ifdef DEBUG
+ if (mem) {
+ /* Note restoring of the file list. */
+ if_debug4('u', "[u%u]file_restore 0x%lx => 0x%lx for 0x%lx\n",
+ mem->space, (ulong)mem->streams,
+ (ulong)sprev->state.streams, (ulong) sprev);
+ }
+#endif
+
+ /* Remove entries from font and character caches. */
+ font_restore(sprev);
+
+ /* Adjust the name table. */
+ if (sprev->restore_names)
+ names_restore(the_gs_name_table, sprev);
+}
+
+/* Release memory for a restore. */
+private void
+restore_free(gs_ref_memory_t * mem)
+{
+ /* Free chunks allocated since the save. */
+ gs_free_all((gs_memory_t *) mem);
+}
+
+/* Forget a save, by merging this level with the next outer one. */
+private void file_forget_save(P1(gs_ref_memory_t *));
+private void combine_space(P1(gs_ref_memory_t *));
+private void forget_changes(P1(gs_ref_memory_t *));
+void
+alloc_forget_save(alloc_save_t * save)
+{
+ gs_dual_memory_t *dmem = save->dmem;
+ gs_ref_memory_t *mem = dmem->space_local;
+ alloc_save_t *sprev;
+
+ print_save("forget_save", mem->space, save);
+
+ /* Iteratively combine the current level with the previous one. */
+ do {
+ sprev = mem->saved;
+ if (sprev->id != 0)
+ dmem->save_level--;
+ if (dmem->save_level != 0) {
+ alloc_change_t *chp = mem->changes;
+
+ save_set_new(&sprev->state, true);
+ /* Concatenate the changes chains. */
+ if (chp == 0)
+ mem->changes = sprev->state.changes;
+ else {
+ while (chp->next != 0)
+ chp = chp->next;
+ chp->next = sprev->state.changes;
+ }
+ file_forget_save(mem);
+ combine_space(mem); /* combine memory */
+ } else {
+ forget_changes(mem);
+ save_set_new(mem, false);
+ file_forget_save(mem);
+ combine_space(mem); /* combine memory */
+ /* This is the outermost save, which might also */
+ /* need to combine global VM. */
+ mem = dmem->space_global;
+ if (mem != dmem->space_local && mem->saved != 0) {
+ forget_changes(mem);
+ save_set_new(mem, false);
+ file_forget_save(mem);
+ combine_space(mem);
+ }
+ alloc_set_not_in_save(dmem);
+ break; /* must be outermost */
+ }
+ }
+ while (sprev != save);
+}
+/* Combine the chunks of the next outer level with those of the current one, */
+/* and free the bookkeeping structures. */
+private void
+combine_space(gs_ref_memory_t * mem)
+{
+ alloc_save_t *saved = mem->saved;
+ gs_ref_memory_t *omem = &saved->state;
+ chunk_t *cp;
+ chunk_t *csucc;
+
+ alloc_close_chunk(mem);
+ for (cp = mem->cfirst; cp != 0; cp = csucc) {
+ csucc = cp->cnext; /* save before relinking */
+ if (cp->outer == 0)
+ alloc_link_chunk(cp, omem);
+ else {
+ chunk_t *outer = cp->outer;
+
+ outer->inner_count--;
+ if (mem->pcc == cp)
+ mem->pcc = outer;
+ if (mem->cfreed.cp == cp)
+ mem->cfreed.cp = outer;
+ /* "Free" the header of the inner chunk, */
+ /* and any immediately preceding gap left by */
+ /* the GC having compacted the outer chunk. */
+ {
+ obj_header_t *hp = (obj_header_t *) outer->cbot;
+
+ hp->o_large = 0;
+ hp->o_size = (char *)(cp->chead + 1)
+ - (char *)(hp + 1);
+ hp->o_type = &st_bytes;
+ /* The following call is probably not safe. */
+#if 0 /* **************** */
+ gs_free_object((gs_memory_t *) mem,
+ hp + 1, "combine_space(header)");
+#endif /* **************** */
+ }
+ /* Update the outer chunk's allocation pointers. */
+ outer->cbot = cp->cbot;
+ outer->rcur = cp->rcur;
+ outer->rtop = cp->rtop;
+ outer->ctop = cp->ctop;
+ outer->has_refs |= cp->has_refs;
+ gs_free_object(mem->parent, cp,
+ "combine_space(inner)");
+ }
+ }
+ /* Update relevant parts of allocator state. */
+ mem->cfirst = omem->cfirst;
+ mem->clast = omem->clast;
+ mem->allocated += omem->allocated;
+ mem->gc_allocated += omem->allocated;
+ mem->lost.objects += omem->lost.objects;
+ mem->lost.refs += omem->lost.refs;
+ mem->lost.strings += omem->lost.strings;
+ mem->saved = omem->saved;
+ mem->previous_status = omem->previous_status;
+ { /* Concatenate free lists. */
+ int i;
+
+ for (i = 0; i < num_freelists; i++) {
+ obj_header_t *olist = omem->freelists[i];
+ obj_header_t *list = mem->freelists[i];
+
+ if (olist == 0);
+ else if (list == 0)
+ mem->freelists[i] = olist;
+ else {
+ while (*(obj_header_t **) list != 0)
+ list = *(obj_header_t **) list;
+ *(obj_header_t **) list = olist;
+ }
+ }
+ }
+ gs_free_object((gs_memory_t *) mem, saved, "combine_space(saved)");
+ alloc_open_chunk(mem);
+}
+/* Free the changes chain for a level 0 .forgetsave, */
+/* resetting the l_new flag in the changed refs. */
+private void
+forget_changes(gs_ref_memory_t * mem)
+{
+ register alloc_change_t *chp = mem->changes;
+ alloc_change_t *next;
+
+ for (; chp; chp = next) {
+ ref_packed *prp = chp->where;
+
+ if_debug1('U', "[U]forgetting change 0x%lx\n", (ulong) chp);
+ if (!r_is_packed(prp))
+ r_clear_attrs((ref *) prp, l_new);
+ next = chp->next;
+ gs_free_object((gs_memory_t *) mem, chp, "forget_changes");
+ }
+ mem->changes = 0;
+}
+/* Update the streams list when forgetting a save. */
+private void
+file_forget_save(gs_ref_memory_t * mem)
+{
+ const alloc_save_t *save = mem->saved;
+ stream *streams = mem->streams;
+ stream *saved_streams = save->state.streams;
+
+ if_debug4('u', "[u%d]file_forget_save 0x%lx + 0x%lx for 0x%lx\n",
+ mem->space, (ulong) streams, (ulong) saved_streams,
+ (ulong) save);
+ if (streams == 0)
+ mem->streams = saved_streams;
+ else if (saved_streams != 0) {
+ while (streams->next != 0)
+ streams = streams->next;
+ streams->next = saved_streams;
+ saved_streams->prev = streams;
+ }
+}
+
+/* ------ Internal routines ------ */
+
+/* Set or reset the l_new attribute in every relevant slot. */
+/* This includes every slot on the current change chain, */
+/* and every (ref) slot allocated at this save level. */
+/* Return the number of bytes of data scanned. */
+private long
+save_set_new(gs_ref_memory_t * mem, bool to_new)
+{
+ long scanned = 0;
+
+ /* Handle the change chain. */
+ save_set_new_changes(mem, to_new);
+
+ /* Handle newly allocated ref objects. */
+ SCAN_MEM_CHUNKS(mem, cp) {
+ if (cp->has_refs) {
+ bool has_refs = false;
+
+ SCAN_CHUNK_OBJECTS(cp)
+ DO_ALL
+ if_debug3('U', "[U]set_new scan(0x%lx(%lu), %d)\n",
+ (ulong) pre, size, to_new);
+ if (pre->o_type == &st_refs) { /* These are refs, scan them. */
+ ref_packed *prp = (ref_packed *) (pre + 1);
+ ref_packed *next = (ref_packed *) ((char *)prp + size);
+
+ if_debug2('U', "[U]refs 0x%lx to 0x%lx\n",
+ (ulong) prp, (ulong) next);
+ has_refs = true;
+ scanned += size;
+ /* We know that every block of refs ends with */
+ /* a full-size ref, so we only need the end check */
+ /* when we encounter one of those. */
+ if (to_new)
+ while (1) {
+ if (r_is_packed(prp))
+ prp++;
+ else {
+ ((ref *) prp)->tas.type_attrs |= l_new;
+ prp += packed_per_ref;
+ if (prp >= next)
+ break;
+ }
+ } else
+ while (1) {
+ if (r_is_packed(prp))
+ prp++;
+ else {
+ ((ref *) prp)->tas.type_attrs &= ~l_new;
+ prp += packed_per_ref;
+ if (prp >= next)
+ break;
+ }
+ }
+ } else
+ scanned += sizeof(obj_header_t);
+ END_OBJECTS_SCAN
+ cp->has_refs = has_refs;
+ }
+ }
+ END_CHUNKS_SCAN
+ if_debug2('u', "[u]set_new (%s) scanned %ld\n",
+ (to_new ? "restore" : "save"), scanned);
+ return scanned;
+}
+
+/* Set or reset the l_new attribute on the changes chain. */
+private void
+save_set_new_changes(gs_ref_memory_t * mem, bool to_new)
+{
+ register alloc_change_t *chp = mem->changes;
+ register uint new = (to_new ? l_new : 0);
+
+ for (; chp; chp = chp->next) {
+ ref_packed *prp = chp->where;
+
+ if_debug2('U', "[U]set_new(0x%lx, %d)\n",
+ (ulong) prp, new);
+ if (!r_is_packed(prp)) {
+ ref *const rp = (ref *) prp;
+
+ rp->tas.type_attrs =
+ (rp->tas.type_attrs & ~l_new) + new;
+ }
+ }
+}
diff --git a/pstoraster/isave.h b/pstoraster/isave.h
new file mode 100644
index 000000000..147863ec8
--- /dev/null
+++ b/pstoraster/isave.h
@@ -0,0 +1,133 @@
+/* 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$ */
+/* Requires imemory.h */
+
+#ifndef isave_INCLUDED
+# define isave_INCLUDED
+
+/*
+ * According to the PostScript language definition, save objects are simple,
+ * not composite. Consequently, we cannot use their natural representation,
+ * namely a t_struct pointing to an alloc_save_t, since we aren't willing to
+ * allocate them all in global VM and rely on garbage collection to clean
+ * them up. Instead, we assign each one a unique "save ID", and store this
+ * in the alloc_save_t object. Mapping the number to the object requires
+ * at most searching the local save chain for the current gs_dual_memory_t,
+ * and this approach means we don't have to do anything to invalidate
+ * save objects when we do a restore.
+ */
+#ifndef alloc_save_t_DEFINED /* also in inamedef.h */
+typedef struct alloc_save_s alloc_save_t;
+# define alloc_save_t_DEFINED
+#endif
+
+/* Initialize the save machinery. */
+extern void alloc_save_init(P1(gs_dual_memory_t *));
+
+/* Map a save ID to its save object. Return 0 if the ID is invalid. */
+alloc_save_t *alloc_find_save(P2(const gs_dual_memory_t *, ulong));
+
+/*
+ * Save the state. Return 0 if we can't allocate the save object,
+ * otherwise return the save ID. The second argument is a client data
+ * pointer, assumed to point to an object.
+ */
+ulong alloc_save_state(P2(gs_dual_memory_t *, void *));
+
+/* Get the client pointer passed to alloc_saved_state. */
+void *alloc_save_client_data(P1(const alloc_save_t *));
+
+/* Return the current level of save nesting. */
+int alloc_save_level(P1(const gs_dual_memory_t *));
+
+/* Return (the id of) the innermost externally visible save object. */
+ulong alloc_save_current_id(P1(const gs_dual_memory_t *));
+alloc_save_t *alloc_save_current(P1(const gs_dual_memory_t *));
+
+/* Check whether a pointer refers to an object allocated since a given save. */
+bool alloc_is_since_save(P2(const void *, const alloc_save_t *));
+
+/* Check whether a name was created since a given save. */
+bool alloc_name_is_since_save(P2(const ref *, const alloc_save_t *));
+bool alloc_name_index_is_since_save(P2(uint, const alloc_save_t *));
+
+/*
+ * Check whether any names have been created since a given save
+ * that might be released by the restore.
+ */
+bool alloc_any_names_since_save(P1(const alloc_save_t *));
+
+/*
+ * Do one step of restoring the state. Return true if the argument
+ * was the innermost save, in which case this is the last (or only) step.
+ * Assume the caller obtained the argument by calling alloc_find_save;
+ * if this is the case, the operation cannot fail.
+ */
+bool alloc_restore_state_step(P1(alloc_save_t *));
+
+/*
+ * Forget a save -- like committing a transaction (restore is like
+ * aborting a transaction). Assume the caller obtained the argument
+ * by calling alloc_find_save. Note that forgetting a save does not
+ * require checking pointers for recency.
+ */
+void alloc_forget_save(P1(alloc_save_t *));
+
+/* Release all memory -- like doing a restore "past the bottom". */
+void alloc_restore_all(P1(gs_dual_memory_t *));
+
+/*
+ * If we are in a save, we want to save the old contents if l_new is
+ * not set; if we are not in a save, we never want to save old contents.
+ * We can test this quickly with a single mask that is l_new if we are
+ * in a save, and -1 if we are not, since type_attrs of a valid ref
+ * cannot be 0; this is the test_mask in a gs_dual_memory_t. Similarly,
+ * we want to set the l_new bit in newly allocated objects iff we are in
+ * a save; this is the new_mask in a gs_dual_memory_t.
+ *
+ * We have to pass the pointer to the containing object to alloc_save_change
+ * for two reasons:
+ *
+ * - We need to know which VM the containing object is in, so we can
+ * know on which chain of saved changes to put the new change.
+ *
+ * - We need to know whether the object is an array of refs (which
+ * includes dictionaries) or a struct, so we can properly trace and
+ * relocate the pointer to it from the change record during garbage
+ * collection.
+ */
+int alloc_save_change(P4(gs_dual_memory_t *, const ref * pcont,
+ ref_packed * ptr, client_name_t cname));
+
+/* ------ Internals ------ */
+
+/* Record that we are in a save. */
+void alloc_set_in_save(P1(gs_dual_memory_t *));
+
+/* Record that we are not in a save. */
+void alloc_set_not_in_save(P1(gs_dual_memory_t *));
+
+#endif /* isave_INCLUDED */
diff --git a/pstoraster/iscan.c b/pstoraster/iscan.c
new file mode 100644
index 000000000..867249bd3
--- /dev/null
+++ b/pstoraster/iscan.c
@@ -0,0 +1,1131 @@
+/*
+ Copyright 1993-2002 by Easy Software Products.
+ Copyright 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$ */
+/* Token scanner for Ghostscript interpreter */
+#include "ghost.h"
+#include "memory_.h"
+#include "stream.h"
+#include "errors.h"
+#include "files.h" /* for fptr */
+#include "ialloc.h"
+#include "idict.h" /* for //name lookup */
+#include "dstack.h" /* ditto */
+#include "ilevel.h"
+#include "iname.h"
+#include "ipacked.h"
+#include "iparray.h"
+#include "strimpl.h" /* for string decoding */
+#include "sfilter.h" /* ditto */
+#include "ostack.h" /* for accumulating proc bodies; */
+ /* must precede iscan.h */
+#include "iscan.h" /* defines interface */
+#include "iscannum.h"
+#include "istream.h"
+#include "istruct.h" /* for RELOC_REF_VAR */
+#include "iutil.h"
+#include "ivmspace.h"
+#include "store.h"
+#include "scanchar.h"
+
+/* Array packing flag */
+ref ref_array_packing; /* t_boolean */
+
+/* Binary object format flag. This will never be set non-zero */
+/* unless the binary token feature is enabled. */
+ref ref_binary_object_format; /* t_integer */
+
+#define recognize_btokens()\
+ (ref_binary_object_format.value.intval != 0 && level2_enabled)
+
+/* Procedure for binary tokens. Set at initialization if Level 2 */
+/* features are included; only called if recognize_btokens() is true. */
+/* Returns 0 or scan_BOS on success, <0 on failure. */
+int (*scan_btoken_proc) (P3(stream *, ref *, scanner_state *)) = NULL;
+
+/* Stream template for scanning ASCII85 literals. */
+/* Set at initialization if Level 2 features are included. */
+const stream_template *scan_ascii85_template = NULL;
+
+#ifdef DEBUG
+/* Dummy comment processing procedure for testing. */
+private int
+no_comment_proc(const byte * str, uint len)
+{
+ return 0;
+}
+#endif
+
+/* Procedure for handling DSC comments if desired. */
+/* Set at initialization if a DSC handling module is included. */
+int (*scan_dsc_proc) (P2(const byte *, uint)) = NULL;
+
+/* Procedure for handling all comments if desired. */
+/* Set at initialization if a comment handling module is included. */
+/* If both scan_comment_proc and scan_dsc_proc are set, */
+/* scan_comment_proc is called only for non-DSC comments. */
+int (*scan_comment_proc) (P2(const byte *, uint)) = NULL;
+
+/*
+ * Level 2 includes some changes in the scanner:
+ * - \ is always recognized in strings, regardless of the data source;
+ * - << and >> are legal tokens;
+ * - <~ introduces an ASCII85 encoded string (terminated by ~>);
+ * - Character codes above 127 introduce binary objects.
+ * We explicitly enable or disable these changes here.
+ */
+#define scan_enable_level2 level2_enabled /* from ilevel.h */
+
+/* ------ Dynamic strings ------ */
+
+/* Begin collecting a dynamically allocated string. */
+#define dynamic_init(pda, mem)\
+ ((pda)->is_dynamic = false,\
+ (pda)->limit = (pda)->buf + da_buf_size,\
+ (pda)->next = (pda)->base = (pda)->buf,\
+ (pda)->memory = (mem))
+
+/* Free a dynamic string. */
+private void
+dynamic_free(da_ptr pda)
+{
+ if (pda->is_dynamic)
+ gs_free_string(pda->memory, pda->base, da_size(pda), "scanner");
+}
+
+/* Resize a dynamic string. */
+/* If the allocation fails, return e_VMerror; otherwise, return 0. */
+private int
+dynamic_resize(da_ptr pda, uint new_size)
+{
+ uint old_size = da_size(pda);
+ uint pos = pda->next - pda->base;
+ gs_memory_t *mem = pda->memory;
+ byte *base;
+
+ if (pda->is_dynamic) {
+ base = gs_resize_string(mem, pda->base, old_size,
+ new_size, "scanner");
+ if (base == 0)
+ return_error(e_VMerror);
+ } else { /* switching from static to dynamic */
+ base = gs_alloc_string(mem, new_size, "scanner");
+ if (base == 0)
+ return_error(e_VMerror);
+ memcpy(base, pda->base, min(old_size, new_size));
+ pda->is_dynamic = true;
+ }
+ pda->base = base;
+ pda->next = base + pos;
+ pda->limit = base + new_size;
+ return 0;
+}
+
+/* Grow a dynamic string. */
+/* Return 0 if the allocation failed, the new 'next' ptr if OK. */
+/* Return 0 or an error code, updating pda->next to point to the first */
+/* available byte after growing. */
+private int
+dynamic_grow(da_ptr pda, byte * next, uint max_size)
+{
+ uint old_size = da_size(pda);
+ uint new_size = (old_size < 10 ? 20 :
+ old_size >= (max_size >> 1) ? max_size :
+ old_size << 1);
+ int code;
+
+ pda->next = next;
+ if (old_size == max_size)
+ return_error(e_limitcheck);
+ while ((code = dynamic_resize(pda, new_size)) < 0 &&
+ new_size > old_size
+ ) { /* Try trimming down the requested new size. */
+ new_size -= (new_size - old_size + 1) >> 1;
+ }
+ return code;
+}
+
+/* Ensure that a dynamic string is either on the heap or in the */
+/* private buffer. */
+private void
+dynamic_save(da_ptr pda)
+{
+ if (!pda->is_dynamic && pda->base != pda->buf) {
+ memcpy(pda->buf, pda->base, da_size(pda));
+ pda->next = pda->buf + da_size(pda);
+ pda->base = pda->buf;
+ }
+}
+
+/* Finish collecting a dynamic string. */
+private int
+dynamic_make_string(ref * pref, da_ptr pda, byte * next)
+{
+ uint size = (pda->next = next) - pda->base;
+ int code = dynamic_resize(pda, size);
+
+ if (code < 0)
+ return code;
+ make_tasv_new(pref, t_string,
+ a_all | imemory_space((gs_ref_memory_t *) pda->memory),
+ size, bytes, pda->base);
+ return 0;
+}
+
+/* ------ Main scanner ------ */
+
+/* GC procedures */
+#define ssptr ((scanner_state *)vptr)
+#define ssarray ssptr->s_ss.binary.bin_array
+private
+CLEAR_MARKS_PROC(scanner_clear_marks)
+{
+ r_clear_attrs(&ssarray, l_mark);
+}
+private
+ENUM_PTRS_BEGIN(scanner_enum_ptrs) return 0;
+
+case 0:
+if (ssptr->s_scan_type == scanning_none ||
+ !ssptr->s_da.is_dynamic
+)
+ ENUM_RETURN(0);
+ssptr->s_da.str.data = ssptr->s_da.base;
+ssptr->s_da.str.size = da_size(&ssptr->s_da);
+ENUM_RETURN_STRING_PTR(scanner_state, s_da.str);
+case 1:
+if (ssptr->s_scan_type != scanning_binary)
+ return 0;
+ENUM_RETURN_REF(&ssarray);
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(scanner_reloc_ptrs)
+{
+ if (ssptr->s_scan_type != scanning_none && ssptr->s_da.is_dynamic) {
+ RELOC_STRING_VAR(ssptr->s_da.str);
+ ssptr->s_da.limit = ssptr->s_da.str.data + ssptr->s_da.str.size;
+ ssptr->s_da.next = ssptr->s_da.str.data + (ssptr->s_da.next - ssptr->s_da.base);
+ ssptr->s_da.base = ssptr->s_da.str.data;
+ }
+ if (ssptr->s_scan_type == scanning_binary) {
+ RELOC_REF_VAR(ssarray);
+ r_clear_attrs(&ssarray, l_mark);
+ }
+}
+RELOC_PTRS_END
+#undef ssptr
+/* Structure type */
+public_st_scanner_state();
+
+/* Handle a scan_Refill return from scan_token. */
+/* This may return o_push_estack, 0 (meaning just call scan_token again), */
+/* or an error code. */
+int
+scan_handle_refill(const ref * fop, scanner_state * sstate, bool save,
+ bool push_file, int (*cont) (P1(os_ptr)))
+{
+ stream *s = fptr(fop);
+ uint avail = sbufavailable(s);
+ int status;
+
+ if (s->end_status == EOFC) { /* More data needed, but none available, */
+ /* so this is a syntax error. */
+ return_error(e_syntaxerror);
+ }
+ status = s_process_read_buf(s);
+ if (sbufavailable(s) > avail)
+ return 0;
+ if (status == 0)
+ status = s->end_status;
+ switch (status) {
+ case EOFC:
+ /* We just discovered that we're at EOF. */
+ /* Let the caller find this out. */
+ return 0;
+ case ERRC:
+ return_error(e_ioerror);
+ case INTC:
+ case CALLC:
+ {
+ ref rstate[2];
+ scanner_state *pstate;
+ int nstate = (push_file ? 2 : 1);
+
+ if (save) {
+ pstate =
+ ialloc_struct(scanner_state, &st_scanner_state,
+ "scan_handle_refill");
+ if (pstate == 0)
+ return_error(e_VMerror);
+ *pstate = *sstate;
+ } else
+ pstate = sstate;
+ /* If push_file is true, we want to push the file on the */
+ /* o-stack before the state, for the continuation proc. */
+ /* Since the refs passed to s_handle_read_exception */
+ /* are pushed on the e-stack, we must ensure they are */
+ /* literal, and also pass them in the opposite order! */
+ make_istruct(&rstate[0], 0, pstate);
+ rstate[1] = *fop;
+ r_clear_attrs(&rstate[1], a_executable);
+ return s_handle_read_exception(status, fop,
+ rstate, nstate, cont);
+ }
+ }
+ /* No more data available, but no exception. How can this be? */
+ lprintf("Can't refill scanner input buffer!");
+ return_error(e_Fatal);
+}
+
+/* Handle a comment. The 'saved' argument is needed only for */
+/* tracing printout. */
+private int
+scan_comment(const byte * base, const byte * end, bool saved)
+{
+ uint len = (uint) (end - base);
+
+#ifdef DEBUG
+ const char *sstr = (saved ? ">" : "");
+
+#endif
+ if (len > 1 && base[1] == '%' && scan_dsc_proc != NULL) {
+#ifdef DEBUG
+ if (gs_debug_c('%')) {
+ dlprintf2("[%%%%%s%c]", sstr, (len >= 3 ? '+' : '-'));
+ fwrite(base, 1, len, dstderr);
+ dputs("\n");
+ }
+#endif
+ if (end - base >= 3)
+ return (*scan_dsc_proc) (base, len);
+ } else if (scan_comment_proc != NULL) {
+#ifdef DEBUG
+ if (gs_debug_c('%')) {
+ dlprintf2("[%% %s%c]", sstr, (len >= 2 ? '+' : '-'));
+ fwrite(base, 1, len, dstderr);
+ dputs("\n");
+ }
+#endif
+ if (end - base >= 2)
+ return (*scan_comment_proc) (base, len);
+ }
+ return 0;
+}
+
+/* Read a token from a string. */
+/* Update the string if succesful. */
+int
+scan_string_token(ref * pstr, ref * pref)
+{
+ stream st;
+ stream *s = &st;
+ scanner_state state;
+ int code;
+
+ if (!r_has_attr(pstr, a_read))
+ return_error(e_invalidaccess);
+ sread_string(s, pstr->value.bytes, r_size(pstr));
+ scanner_state_init(&state, true);
+ switch (code = scan_token(s, pref, &state)) {
+ case 0: /* read a token */
+ case scan_BOS:
+ {
+ uint pos = stell(s);
+
+ pstr->value.bytes += pos;
+ r_dec_size(pstr, pos);
+ }
+ break;
+ case scan_Refill: /* error */
+ code = gs_note_error(e_syntaxerror);
+ default: /* error */
+ ;
+ }
+ return code;
+}
+
+/*
+ * Read a token from a stream.
+ * Return 0 if an ordinary token was read,
+ * scan_BOS for a binary object sequence, scan_EOF for end-of-stream,
+ * scan_Refill if more data needed, or a (negative) error code.
+ * If the token required a terminating character (i.e., was a name or
+ * number) and the next character was whitespace, read and discard
+ * that character. Note that the state is relevant for e_VMerror
+ * as well as for scan_Refill.
+ */
+int
+scan_token(stream * s, ref * pref, scanner_state * pstate)
+{
+ ref *myref = pref;
+ int retcode = 0;
+ int c;
+
+ s_declare_inline(s, sptr, endptr);
+#define scan_begin_inline() s_begin_inline(s, sptr, endptr)
+#define scan_getc() sgetc_inline(s, sptr, endptr)
+#define scan_putback() sputback_inline(s, sptr, endptr)
+#define scan_end_inline() s_end_inline(s, sptr, endptr)
+ const byte *newptr;
+ byte *daptr;
+
+#define sreturn(code)\
+ { retcode = gs_note_error(code); goto sret; }
+#define sreturn_no_error(code)\
+ { scan_end_inline(); return(code); }
+#define if_not_spush1()\
+ if ( osp < ostop ) osp++;\
+ else if ( (retcode = ref_stack_push(&o_stack, 1)) >= 0 )\
+ ;\
+ else
+#define spop1()\
+ if ( osp >= osbot ) osp--;\
+ else ref_stack_pop(&o_stack, 1)
+ int max_name_ctype =
+ (recognize_btokens()? ctype_name : ctype_btoken);
+
+#define scan_sign(sign, ptr)\
+ switch ( *ptr ) {\
+ case '-': sign = -1; ptr++; break;\
+ case '+': sign = 1; ptr++; break;\
+ default: sign = 0;\
+ }
+#define ensure2_back(styp,nback)\
+ if ( sptr >= endptr ) { sptr -= nback; scan_type = styp; goto pause; }
+#define ensure2(styp) ensure2_back(styp, 1)
+ byte s1[2];
+ const byte *const decoder = scan_char_decoder;
+ int status;
+ int sign;
+ const bool check_only = pstate->s_check_only;
+ scanner_state sstate;
+
+#define pstack sstate.s_pstack
+#define pdepth sstate.s_pdepth
+#define scan_type sstate.s_scan_type
+#define da sstate.s_da
+#define name_type sstate.s_ss.s_name.s_name_type
+#define try_number sstate.s_ss.s_name.s_try_number
+
+ if (pstate->s_pstack != 0) {
+ if_not_spush1()
+ return retcode;
+ myref = osp;
+ }
+ /* Check whether we are resuming after an interruption. */
+ if (pstate->s_scan_type != scanning_none) {
+ sstate = *pstate;
+ if (!da.is_dynamic && da.base != da.buf) { /* The da contains some self-referencing pointers. */
+ /* Fix them up now. */
+ uint size = da.next - da.base;
+
+ da.base = da.buf;
+ da.next = da.buf + size;
+ da.limit = da.buf + da_buf_size;
+ }
+ daptr = da.next;
+ switch (scan_type) {
+ case scanning_binary:
+ retcode = (*sstate.s_ss.binary.cont) (s, myref, &sstate);
+ scan_begin_inline();
+ if (retcode == scan_Refill)
+ goto pause;
+ goto sret;
+ case scanning_comment:
+ scan_begin_inline();
+ goto cont_comment;
+ case scanning_name:
+ goto cont_name;
+ case scanning_string:
+ goto cont_string;
+ default:
+ return_error(e_Fatal);
+ }
+ }
+ /* Fetch any state variables that are relevant even if */
+ /* scan_type == scanning_none. */
+ pstack = pstate->s_pstack;
+ pdepth = pstate->s_pdepth;
+ sstate.s_check_only = check_only;
+ scan_begin_inline();
+ /*
+ * Loop invariants:
+ * If pstack != 0, myref = osp, and *osp is a valid slot.
+ */
+ top:c = scan_getc();
+ if_debug1('S', (c >= 32 && c <= 126 ? "`%c'" : c >= 0 ? "`\\%03o'" : "`%d'"), c);
+ switch (c) {
+ case ' ':
+ case '\f':
+ case '\t':
+ case char_CR:
+ case char_EOL:
+ case char_NULL:
+ goto top;
+ case '[':
+ case ']':
+ s1[0] = (byte) c;
+ retcode = name_ref(s1, 1, myref, 1); /* can't fail */
+ r_set_attrs(myref, a_executable);
+ break;
+ case '<':
+ if (scan_enable_level2) {
+ ensure2(scanning_none);
+ c = scan_getc();
+ switch (c) {
+ case '<':
+ scan_putback();
+ name_type = 0;
+ try_number = false;
+ goto try_funny_name;
+ case '~':
+ s_A85D_init_inline(&sstate.s_ss.a85d);
+ sstate.s_ss.st.template =
+ scan_ascii85_template;
+ goto str;
+ }
+ scan_putback();
+ }
+ s_AXD_init_inline(&sstate.s_ss.axd);
+ sstate.s_ss.st.template = &s_AXD_template;
+ str:scan_end_inline();
+ dynamic_init(&da, imemory);
+ cont_string:for (;;) {
+ stream_cursor_write w;
+
+ w.ptr = da.next - 1;
+ w.limit = da.limit - 1;
+ status = (*sstate.s_ss.st.template->process)
+ (&sstate.s_ss.st, &s->cursor.r, &w,
+ s->end_status == EOFC);
+ if (!check_only)
+ da.next = w.ptr + 1;
+ switch (status) {
+ case 0:
+ status = s->end_status;
+ if (status < 0) {
+ if (status == EOFC) {
+ if (check_only) {
+ retcode = scan_Refill;
+ scan_type = scanning_string;
+ goto suspend;
+ } else
+ sreturn(e_syntaxerror);
+ }
+ break;
+ }
+ s_process_read_buf(s);
+ continue;
+ case 1:
+ if (!check_only) {
+ retcode = dynamic_grow(&da, da.next, max_string_size);
+ if (retcode == e_VMerror) {
+ scan_type = scanning_string;
+ goto suspend;
+ } else if (retcode < 0)
+ sreturn(retcode);
+ }
+ continue;
+ }
+ break;
+ }
+ scan_begin_inline();
+ switch (status) {
+ default:
+ /*case ERRC: */
+ sreturn(e_syntaxerror);
+ case INTC:
+ case CALLC:
+ scan_type = scanning_string;
+ goto pause;
+ case EOFC:
+ ;
+ }
+ retcode = dynamic_make_string(myref, &da, da.next);
+ if (retcode < 0) { /* VMerror */
+ sputback(s); /* rescan ) */
+ scan_type = scanning_string;
+ goto suspend;
+ }
+ break;
+ case '(':
+ sstate.s_ss.pssd.from_string =
+ pstate->s_from_string && !scan_enable_level2;
+ s_PSSD_init_inline(&sstate.s_ss.pssd);
+ sstate.s_ss.st.template = &s_PSSD_template;
+ goto str;
+ case '{':
+ if (pstack == 0) { /* outermost procedure */
+ if_not_spush1() {
+ scan_putback();
+ scan_type = scanning_none;
+ goto pause_ret;
+ }
+ pdepth = ref_stack_count_inline(&o_stack);
+ }
+ make_int(osp, pstack);
+ pstack = ref_stack_count_inline(&o_stack);
+ if_debug3('S', "[S{]d=%d, s=%d->%d\n",
+ pdepth, (int)osp->value.intval, pstack);
+ goto snext;
+ case '>':
+ if (scan_enable_level2) {
+ ensure2(scanning_none);
+ name_type = 0;
+ try_number = false;
+ goto try_funny_name;
+ }
+ /* falls through */
+ case ')':
+ sreturn(e_syntaxerror);
+ case '}':
+ if (pstack == 0)
+ sreturn(e_syntaxerror);
+ osp--;
+ {
+ uint size = ref_stack_count_inline(&o_stack) - pstack;
+ ref arr;
+
+ if_debug4('S', "[S}]d=%d, s=%d->%ld, c=%d\n",
+ pdepth, pstack,
+ (pstack == pdepth ? 0 :
+ ref_stack_index(&o_stack, size)->value.intval),
+ size + pstack);
+ myref = (pstack == pdepth ? pref : &arr);
+ if (check_only) {
+ make_empty_array(myref, 0);
+ ref_stack_pop(&o_stack, size);
+ } else if (ref_array_packing.value.boolval) {
+ retcode = make_packed_array(myref, &o_stack,
+ size, "scanner(packed)");
+ if (retcode < 0) { /* must be VMerror */
+ osp++;
+ scan_putback();
+ scan_type = scanning_none;
+ goto pause_ret;
+ }
+ r_set_attrs(myref, a_executable);
+ } else {
+ retcode = ialloc_ref_array(myref,
+ a_executable + a_all, size,
+ "scanner(proc)");
+ if (retcode < 0) { /* must be VMerror */
+ osp++;
+ scan_putback();
+ scan_type = scanning_none;
+ goto pause_ret;
+ }
+ retcode = ref_stack_store(&o_stack, myref,
+ size, 0, 1, false, "scanner");
+ if (retcode < 0) {
+ ifree_ref_array(myref, "scanner(proc)");
+ sreturn(retcode);
+ }
+ ref_stack_pop(&o_stack, size);
+ }
+ if (pstack == pdepth) { /* This was the top-level procedure. */
+ spop1();
+ pstack = 0;
+ } else {
+ if (osp < osbot)
+ ref_stack_pop_block(&o_stack);
+ pstack = osp->value.intval;
+ *osp = arr;
+ goto snext;
+ }
+ }
+ break;
+ case '/':
+ ensure2(scanning_none);
+ c = scan_getc();
+ if (c == '/') {
+ name_type = 2;
+ c = scan_getc();
+ } else
+ name_type = 1;
+ try_number = false;
+ switch (decoder[c]) {
+ case ctype_name:
+ default:
+ goto do_name;
+ case ctype_btoken:
+ if (!recognize_btokens())
+ goto do_name;
+ /* otherwise, an empty name */
+ case ctype_exception:
+ case ctype_space:
+ /*
+ * Amazingly enough, the Adobe implementations don't accept
+ * / or // followed by [, ], <<, or >>, so we do the same.
+ * (Older versions of our code had a ctype_other case here
+ * that handled these specially.)
+ */
+ case ctype_other:
+ da.base = da.limit = daptr = 0;
+ da.is_dynamic = false;
+ goto nx;
+ }
+ case '%':
+ { /* Scan as much as possible within the buffer. */
+ const byte *base = sptr;
+ const byte *end;
+
+ while (++sptr < endptr) /* stop 1 char early */
+ switch (*sptr) {
+ case char_CR:
+ end = sptr;
+ if (sptr[1] == char_EOL)
+ sptr++;
+ cend: /* Check for externally processed comments. */
+ retcode = scan_comment(base, end, false);
+ if (retcode < 0)
+ goto sret;
+ goto top;
+ case char_EOL:
+ case '\f':
+ end = sptr;
+ goto cend;
+ }
+ /*
+ * We got to the end of the buffer while inside a comment.
+ * If there is a possibility that we must pass the comment
+ * to an external procedure, move what we have collected
+ * so far into a private buffer now.
+ */
+#define comment_line da.buf
+ --sptr;
+ comment_line[1] = 0;
+ if (scan_comment_proc != NULL ||
+ ((sptr == base || base[1] == '%') &&
+ scan_dsc_proc != NULL)
+ ) { /* Could be an externally processable comment. */
+ uint len = sptr + 1 - base;
+
+ memcpy(comment_line, base, len);
+ daptr = comment_line + len;
+ } else { /* Not a DSC comment. */
+ daptr = comment_line + (max_comment_line + 1);
+ }
+ da.base = comment_line;
+ da.is_dynamic = false;
+ }
+ /* Enter here to continue scanning a comment. */
+ /* daptr must be set. */
+ cont_comment:for (;;) {
+ switch ((c = scan_getc())) {
+ default:
+ if (c < 0)
+ switch (c) {
+ case INTC:
+ case CALLC:
+ da.next = daptr;
+ scan_type = scanning_comment;
+ goto pause;
+ case EOFC:
+ /*
+ * One would think that an EOF in a comment
+ * should be a syntax error, but there are
+ * quite a number of files that end that way.
+ */
+ goto end_comment;
+ default:
+ sreturn(e_syntaxerror);
+ }
+ if (daptr < comment_line + max_comment_line)
+ *daptr++ = c;
+ continue;
+ case char_CR:
+ case char_EOL:
+ case '\f':
+ end_comment:retcode = scan_comment(comment_line, daptr, true);
+ if (retcode < 0)
+ goto sret;
+ goto top;
+ }
+ break;
+ }
+#undef comment_line
+ /*NOTREACHED */
+ case EOFC:
+ if (pstack != 0) {
+ if (check_only)
+ goto pause;
+ sreturn(e_syntaxerror);
+ }
+ retcode = scan_EOF;
+ break;
+ case ERRC:
+ sreturn(e_ioerror);
+
+ /* Check for a Level 2 funny name (<< or >>). */
+ /* c is '<' or '>'. We already did an ensure2. */
+ try_funny_name:
+ {
+ int c1 = scan_getc();
+
+ if (c1 == c) {
+ s1[0] = s1[1] = c;
+ name_ref(s1, 2, myref, 1); /* can't fail */
+ goto have_name;
+ }
+ scan_putback();
+ }
+ sreturn(e_syntaxerror);
+
+ /* Handle separately the names that might be a number. */
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '.':
+ sign = 0;
+ nr: /*
+ * Skip a leading sign, if any, by conditionally passing
+ * sptr + 1 rather than sptr. Also, if the last character
+ * in the buffer is a CR, we must stop the scan 1 character
+ * early, to be sure that we can test for CR+LF within the
+ * buffer, by passing endptr rather than endptr + 1.
+ */
+ retcode = scan_number(sptr + (sign & 1),
+ endptr /*(*endptr == char_CR ? endptr : endptr + 1) */ ,
+ sign, myref, &newptr);
+ if (retcode == 1 && decoder[newptr[-1]] == ctype_space) {
+ sptr = newptr - 1;
+ if (*sptr == char_CR && sptr[1] == char_EOL)
+ sptr++;
+ retcode = 0;
+ break;
+ }
+ name_type = 0;
+ try_number = true;
+ goto do_name;
+ case '+':
+ sign = 1;
+ goto nr;
+ case '-':
+ sign = -1;
+ goto nr;
+
+ /* Check for a binary object */
+#define case4(c) case c: case c+1: case c+2: case c+3
+ case4(128): case4(132): case4(136): case4(140):
+ case4(144): case4(148): case4(152): case4(156):
+#undef case4
+ if (recognize_btokens()) {
+ scan_end_inline();
+ retcode = (*scan_btoken_proc) (s, myref, &sstate);
+ scan_begin_inline();
+ if (retcode == scan_Refill)
+ goto pause;
+ break;
+ }
+ /* Not a binary object, fall through. */
+
+ /* The default is a name. */
+ default:
+ if (c < 0) {
+ dynamic_init(&da, name_memory()); /* da state must be clean */
+ scan_type = scanning_none;
+ goto pause;
+ }
+ /* Populate the switch with enough cases to force */
+ /* simple compilers to use a dispatch rather than tests. */
+ case '!':
+ case '"':
+ case '#':
+ case '$':
+ case '&':
+ case '\'':
+ case '*':
+ case ',':
+ case '=':
+ case ':':
+ case ';':
+ case '?':
+ case '@':
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ case 'G':
+ case 'H':
+ case 'I':
+ case 'J':
+ case 'K':
+ case 'L':
+ case 'M':
+ case 'N':
+ case 'O':
+ case 'P':
+ case 'Q':
+ case 'R':
+ case 'S':
+ case 'T':
+ case 'U':
+ case 'V':
+ case 'W':
+ case 'X':
+ case 'Y':
+ case 'Z':
+ case '\\':
+ case '^':
+ case '_':
+ case '`':
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ case 'g':
+ case 'h':
+ case 'i':
+ case 'j':
+ case 'k':
+ case 'l':
+ case 'm':
+ case 'n':
+ case 'o':
+ case 'p':
+ case 'q':
+ case 'r':
+ case 's':
+ case 't':
+ case 'u':
+ case 'v':
+ case 'w':
+ case 'x':
+ case 'y':
+ case 'z':
+ case '|':
+ case '~':
+ /* Common code for scanning a name. */
+ /* try_number and name_type are already set. */
+ /* We know c has ctype_name (or maybe ctype_btoken) */
+ /* or is a digit. */
+ name_type = 0;
+ try_number = false;
+ do_name:
+ /* Try to scan entirely within the stream buffer. */
+ /* We stop 1 character early, so we don't switch buffers */
+ /* looking ahead if the name is terminated by \r\n. */
+ da.base = (byte *) sptr;
+ da.is_dynamic = false;
+ {
+ const byte *endp1 = endptr - 1;
+
+ do {
+ if (sptr >= endp1) /* stop 1 early! */
+ goto dyn_name;
+ }
+ while (decoder[*++sptr] <= max_name_ctype); /* digit or name */
+ }
+ /* Name ended within the buffer. */
+ daptr = (byte *) sptr;
+ c = *sptr;
+ goto nx;
+ dyn_name: /* Name extended past end of buffer. */
+ scan_end_inline();
+ /* Initialize the dynamic area. */
+ /* We have to do this before the next */
+ /* sgetc, which will overwrite the buffer. */
+ da.limit = (byte *)++ sptr;
+ da.memory = name_memory();
+ retcode = dynamic_grow(&da, da.limit, name_max_string);
+ if (retcode < 0) {
+ dynamic_save(&da);
+ if (retcode != e_VMerror)
+ sreturn(retcode);
+ scan_type = scanning_name;
+ goto pause_ret;
+ }
+ daptr = da.next;
+ /* Enter here to continue scanning a name. */
+ /* daptr must be set. */
+ cont_name:scan_begin_inline();
+ while (decoder[c = scan_getc()] <= max_name_ctype) {
+ if (daptr == da.limit) {
+ retcode = dynamic_grow(&da, daptr,
+ name_max_string);
+ if (retcode < 0) {
+ dynamic_save(&da);
+ if (retcode != e_VMerror)
+ sreturn(retcode);
+ scan_putback();
+ scan_type = scanning_name;
+ goto pause_ret;
+ }
+ daptr = da.next;
+ }
+ *daptr++ = c;
+ }
+ nx:switch (decoder[c]) {
+ case ctype_btoken:
+ case ctype_other:
+ scan_putback();
+ break;
+ case ctype_space:
+ /* Check for \r\n */
+ if (c == char_CR) {
+ if (sptr >= endptr) { /* ensure2 *//* We have to check specially for */
+ /* the case where the very last */
+ /* character of a file is a CR. */
+ if (s->end_status != EOFC) {
+ sptr--;
+ goto pause_name;
+ }
+ } else if (sptr[1] == char_EOL)
+ sptr++;
+ }
+ break;
+ case ctype_exception:
+ switch (c) {
+ case INTC:
+ case CALLC:
+ goto pause_name;
+ case ERRC:
+ sreturn(e_ioerror);
+ case EOFC:
+ break;
+ }
+ }
+ /* Check for a number */
+ if (try_number) {
+ const byte *base = da.base;
+
+ scan_sign(sign, base);
+ retcode = scan_number(base, daptr, sign, myref, &newptr);
+ if (retcode == 1)
+ retcode = 0;
+ else if (retcode != e_syntaxerror) {
+ dynamic_free(&da);
+ if (name_type == 2)
+ sreturn(e_syntaxerror);
+ break; /* might be e_limitcheck */
+ }
+ }
+ if (da.is_dynamic) { /* We've already allocated the string on the heap. */
+ uint size = daptr - da.base;
+
+ retcode = name_ref(da.base, size, myref, -1);
+ if (retcode >= 0) {
+ dynamic_free(&da);
+ } else {
+ retcode = dynamic_resize(&da, size);
+ if (retcode < 0) { /* VMerror */
+ if (c != EOFC)
+ scan_putback();
+ scan_type = scanning_name;
+ goto pause_ret;
+ }
+ retcode = name_ref(da.base, size, myref, 2);
+ }
+ } else {
+ retcode = name_ref(da.base, (uint) (daptr - da.base),
+ myref, 1);
+ }
+ /* Done scanning. Check for preceding /'s. */
+ if (retcode < 0) {
+ if (retcode != e_VMerror)
+ sreturn(retcode);
+ if (!da.is_dynamic) {
+ da.next = daptr;
+ dynamic_save(&da);
+ }
+ if (c != EOFC)
+ scan_putback();
+ scan_type = scanning_name;
+ goto pause_ret;
+ }
+ have_name:switch (name_type) {
+ case 0: /* ordinary executable name */
+ if (r_has_type(myref, t_name)) /* i.e., not a number */
+ r_set_attrs(myref, a_executable);
+ case 1: /* quoted name */
+ break;
+ case 2: /* immediate lookup */
+ {
+ ref *pvalue;
+
+ if (!r_has_type(myref, t_name))
+ sreturn(e_undefined);
+ if ((pvalue = dict_find_name(myref)) == 0)
+ sreturn(e_undefined);
+ if (pstack != 0 &&
+ r_space(pvalue) > ialloc_space(idmemory)
+ )
+ sreturn(e_invalidaccess);
+ ref_assign_new(myref, pvalue);
+ }
+ }
+ }
+ sret:if (retcode < 0) {
+ scan_end_inline();
+ if (pstack != 0)
+ ref_stack_pop(&o_stack,
+ ref_stack_count(&o_stack) - (pdepth - 1));
+ return retcode;
+ }
+ /* If we are at the top level, return the object, */
+ /* otherwise keep going. */
+ if (pstack == 0) {
+ scan_end_inline();
+ return retcode;
+ }
+ snext:if_not_spush1() {
+ scan_end_inline();
+ scan_type = scanning_none;
+ goto save;
+ }
+ myref = osp;
+ goto top;
+
+ /* Pause for an interrupt or callout. */
+ pause_name:
+ /* If we're still scanning within the stream buffer, */
+ /* move the characters to the private buffer (da.buf) now. */
+ da.next = daptr;
+ dynamic_save(&da);
+ scan_type = scanning_name;
+ pause:
+ retcode = scan_Refill;
+ pause_ret:
+ scan_end_inline();
+ suspend:
+ if (pstack != 0)
+ osp--; /* myref */
+ save:
+ sstate.s_from_string = pstate->s_from_string;
+ *pstate = sstate;
+ return retcode;
+}
diff --git a/pstoraster/iscan.h b/pstoraster/iscan.h
new file mode 100644
index 000000000..cb174ad8b
--- /dev/null
+++ b/pstoraster/iscan.h
@@ -0,0 +1,161 @@
+/* Copyright (C) 1992, 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$ */
+/* Requires gsstruct.h, ostack.h, stream.h */
+
+#ifndef iscan_INCLUDED
+# define iscan_INCLUDED
+
+#include "sa85x.h"
+#include "sstring.h"
+
+/*
+ * Define the state of the scanner. Before calling scan_token initially,
+ * the caller must initialize the state by calling scanner_state_init.
+ * Most of the state is only used if scanning is suspended because of
+ * an interrupt or a callout.
+ *
+ * We expose the entire state definition to the caller so that
+ * the state can normally be allocated on the stack.
+ */
+typedef struct scanner_state_s scanner_state;
+
+/*
+ * Define a structure for dynamically growable strings.
+ * If is_dynamic is true, base/next/limit point to a string on the heap;
+ * if is_dynamic is false, base/next/limit point either to the local buffer
+ * or (only while control is inside scan_token) into the source stream buffer.
+ */
+#define max_comment_line 255 /* max size of an externally processable comment */
+#define max_dsc_line max_comment_line /* backward compatibility */
+#define da_buf_size (max_comment_line + 2)
+typedef struct dynamic_area_s {
+ gs_string str; /* for GC */
+ byte *base;
+ byte *next;
+ byte *limit;
+ bool is_dynamic;
+ byte buf[da_buf_size]; /* initial buffer */
+ gs_memory_t *memory;
+} dynamic_area;
+
+#define da_size(pda) ((uint)((pda)->limit - (pda)->base))
+typedef dynamic_area *da_ptr;
+
+/* Define state specific to binary tokens and binary object sequences. */
+typedef struct scan_binary_state_s {
+ int num_format;
+ int (*cont) (P3(stream *, ref *, scanner_state *));
+ ref bin_array;
+ uint index;
+ uint max_array_index; /* largest legal index in objects */
+ uint min_string_index; /* smallest legal index in strings */
+ uint top_size;
+ uint size;
+} scan_binary_state;
+
+/* Define the scanner state. */
+struct scanner_state_s {
+ uint s_pstack; /* stack depth when starting current */
+ /* procedure, after pushing old pstack */
+ uint s_pdepth; /* pstack for very first { encountered, */
+ /* for error recovery */
+ bool s_from_string; /* true if string is source of data */
+ /* (for Level 1 `\' handling) */
+ bool s_check_only; /* true if just checking for syntax errors */
+ /* and complete statements (no value) */
+ enum {
+ scanning_none,
+ scanning_binary,
+ scanning_comment,
+ scanning_name,
+ scanning_string
+ } s_scan_type;
+ dynamic_area s_da;
+ union sss_ { /* scanning sub-state */
+ scan_binary_state binary; /* binary */
+ struct sns_ { /* name */
+ int s_name_type; /* number of /'s preceding a name */
+ bool s_try_number; /* true if should try scanning name */
+ /* as number */
+ } s_name;
+ stream_state st; /* string */
+ stream_A85D_state a85d; /* string */
+ stream_AXD_state axd; /* string */
+ stream_PSSD_state pssd; /* string */
+ } s_ss;
+};
+
+/* The type descriptor is public only for checking. */
+extern_st(st_scanner_state);
+#define public_st_scanner_state() /* in iscan.c */\
+ gs_public_st_complex_only(st_scanner_state, scanner_state, "scanner state",\
+ scanner_clear_marks, scanner_enum_ptrs, scanner_reloc_ptrs, 0)
+#define scanner_state_init_check(pstate, from_string, check_only)\
+ ((pstate)->s_scan_type = scanning_none,\
+ (pstate)->s_pstack = 0,\
+ (pstate)->s_from_string = from_string,\
+ (pstate)->s_check_only = check_only)
+#define scanner_state_init(pstate, from_string)\
+ scanner_state_init_check(pstate, from_string, false)
+
+/*
+ * Read a token from a stream. As usual, 0 is a normal return,
+ * <0 is an error. There are also three special return codes:
+ */
+#define scan_BOS 1 /* binary object sequence */
+#define scan_EOF 2 /* end of stream */
+#define scan_Refill 3 /* get more input data, then call again */
+int scan_token(P3(stream * s, ref * pref, scanner_state * pstate));
+
+/*
+ * Read a token from a string. Return like scan_token, but also
+ * update the string to move past the token (if no error).
+ */
+int scan_string_token(P2(ref * pstr, ref * pref));
+
+/*
+ * Handle a scan_Refill return from scan_token.
+ * This may return o_push_estack, 0 (meaning just call scan_token again),
+ * or an error code.
+ */
+int scan_handle_refill(P5(const ref * fop, scanner_state * pstate, bool save,
+ bool push_file, int (*cont) (P1(os_ptr))));
+
+/*
+ * Define the procedure "hook" for parsing DSC comments. If not NULL,
+ * this procedure is called for every DSC comment seen by the scanner.
+ */
+extern int (*scan_dsc_proc) (P2(const byte *, uint));
+
+/*
+ * Define the procedure "hook" for parsing general comments. If not NULL,
+ * this procedure is called for every comment seen by the scanner.
+ * If both scan_dsc_proc and scan_comment_proc are set,
+ * scan_comment_proc is called only for non-DSC comments.
+ */
+extern int (*scan_comment_proc) (P2(const byte *, uint));
+
+#endif /* iscan_INCLUDED */
diff --git a/pstoraster/iscanbin.c b/pstoraster/iscanbin.c
new file mode 100644
index 000000000..63cdcc157
--- /dev/null
+++ b/pstoraster/iscanbin.c
@@ -0,0 +1,768 @@
+/* Copyright (C) 1989, 1992, 1993, 1994, 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$ */
+/* Ghostscript binary token scanner and writer */
+#include "math_.h"
+#include "memory_.h"
+#include "ghost.h"
+#include "gsutil.h"
+#include "stream.h"
+#include "strimpl.h" /* for sfilter.h */
+#include "sfilter.h" /* for iscan.h */
+#include "errors.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "dstack.h" /* for immediately evaluated names */
+#include "ostack.h" /* must precede iscan.h */
+#include "iname.h"
+#include "iscan.h" /* for scan_Refill */
+#include "iutil.h"
+#include "ivmspace.h"
+#include "store.h"
+#include "btoken.h"
+#include "ibnum.h"
+
+/* Define the binary token types. */
+typedef enum {
+ BT_SEQ = 128, /* binary object sequence: */
+ BT_SEQ_IEEE_MSB = 128, /* IEEE floats, big-endian */
+ BT_SEQ_IEEE_LSB = 129, /* IEEE float, little-endian */
+ BT_SEQ_NATIVE_MSB = 130, /* native floats, big-endian */
+ BT_SEQ_NATIVE_LSB = 131, /* native floats, little-endian */
+ BT_INT32_MSB = 132,
+ BT_INT32_LSB = 133,
+ BT_INT16_MSB = 134,
+ BT_INT16_LSB = 135,
+ BT_INT8 = 136,
+ BT_FIXED = 137,
+ BT_FLOAT_IEEE_MSB = 138,
+ BT_FLOAT_IEEE_LSB = 139,
+ BT_FLOAT_NATIVE = 140,
+ BT_BOOLEAN = 141,
+ BT_STRING_256 = 142,
+ BT_STRING_64K_MSB = 143,
+ BT_STRING_64K_LSB = 144,
+ BT_LITNAME_SYSTEM = 145,
+ BT_EXECNAME_SYSTEM = 146,
+ BT_LITNAME_USER = 147,
+ BT_EXECNAME_USER = 148,
+ BT_NUM_ARRAY = 149
+} bin_token_type_t;
+
+#define MIN_BIN_TOKEN_TYPE 128
+#define MAX_BIN_TOKEN_TYPE 159
+#define NUM_BIN_TOKEN_TYPES (MAX_BIN_TOKEN_TYPE - MIN_BIN_TOKEN_TYPE + 1)
+
+/* Define the number of required initial bytes for binary tokens. */
+private const byte bin_token_bytes[NUM_BIN_TOKEN_TYPES] =
+{
+ 4, 4, 4, 4, 5, 5, 3, 3, 2, 2, 5, 5, 5,
+ 2, 2, 3, 3, 2, 2, 2, 2, 4,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 /* undefined */
+};
+
+/* Define the number formats for those binary tokens that need them. */
+private const byte bin_token_num_formats[NUM_BIN_TOKEN_TYPES] =
+{
+ num_msb + num_float_IEEE, /* BT_SEQ_IEEE_MSB */
+ num_lsb + num_float_IEEE, /* BT_SEQ_IEEE_LSB */
+ num_msb + num_float_native, /* BT_SEQ_NATIVE_MSB */
+ num_lsb + num_float_native, /* BT_SEQ_NATIVE_LSB */
+ num_msb + num_int32, /* BT_INT32_MSB */
+ num_lsb + num_int32, /* BT_INT32_LSB */
+ num_msb + num_int16, /* BT_INT16_MSB */
+ num_lsb + num_int16, /* BT_INT16_LSB */
+ 0, /* BT_INT8, not used */
+ 0, /* BT_FIXED, not used */
+ num_msb + num_float_IEEE, /* BT_FLOAT_IEEE_MSB */
+ num_lsb + num_float_IEEE, /* BT_FLOAT_IEEE_LSB */
+ num_float_native, /* BT_FLOAT_NATIVE */
+ 0, /* BT_BOOLEAN, not used */
+ 0, /* BT_STRING_256, not used */
+ num_msb, /* BT_STRING_64K_MSB */
+ num_lsb /* BT_STRING_64K_LSB */
+ /* rest not used */
+};
+
+/* Binary object sequence element types */
+typedef enum {
+ BS_TYPE_NULL = 0,
+ BS_TYPE_INTEGER = 1,
+ BS_TYPE_REAL = 2,
+ BS_TYPE_NAME = 3,
+ BS_TYPE_BOOLEAN = 4,
+ BS_TYPE_STRING = 5,
+ BS_TYPE_EVAL_NAME = 6,
+ BS_TYPE_ARRAY = 9,
+ BS_TYPE_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_TYPE_DICTIONARY = 15
+} bin_seq_type_t;
+
+#define BS_EXECUTABLE 128
+#define SIZEOF_BIN_SEQ_OBJ ((uint)8)
+
+/* Current binary format (in iscan.c) */
+extern ref ref_binary_object_format;
+
+/* Forward references */
+private int scan_bin_num_array_continue(P3(stream *, ref *, scanner_state *));
+private int scan_bin_string_continue(P3(stream *, ref *, scanner_state *));
+private int scan_bos_continue(P3(stream *, ref *, scanner_state *));
+private byte *scan_bos_resize(P3(scanner_state *, uint, uint));
+private int scan_bos_string_continue(P3(stream *, ref *, scanner_state *));
+
+/* Scan a binary token. Called from the main scanner */
+/* when it encounters an ASCII code 128-159, */
+/* if binary tokens are being recognized (object format != 0). */
+int
+scan_binary_token(stream * s, ref * pref, scanner_state * pstate)
+{
+ scan_binary_state *const pbs = &pstate->s_ss.binary;
+
+ s_declare_inline(s, p, rlimit);
+ int num_format, code;
+ uint arg;
+ uint wanted;
+ uint rcnt;
+
+ s_begin_inline(s, p, rlimit);
+ wanted = bin_token_bytes[*p - MIN_BIN_TOKEN_TYPE] - 1;
+ rcnt = rlimit - p;
+ if (rcnt < wanted) {
+ s_end_inline(s, p - 1, rlimit);
+ pstate->s_scan_type = scanning_none;
+ return scan_Refill;
+ }
+ num_format = bin_token_num_formats[*p - MIN_BIN_TOKEN_TYPE];
+ switch (*p) {
+ case BT_SEQ_IEEE_MSB:
+ case BT_SEQ_IEEE_LSB:
+ case BT_SEQ_NATIVE_MSB:
+ case BT_SEQ_NATIVE_LSB:{
+ uint top_size = p[1];
+ uint hsize, size;
+
+ pbs->num_format = num_format;
+ if (top_size == 0) {
+ /* Extended header (2-byte array size, 4-byte length) */
+ ulong lsize;
+
+ if (rcnt < 7) {
+ s_end_inline(s, p - 1, rlimit);
+ pstate->s_scan_type = scanning_none;
+ return scan_Refill;
+ }
+ top_size = sdecodeushort(p + 2, num_format);
+ lsize = sdecodelong(p + 4, num_format);
+ if ((size = lsize) != lsize)
+ return_error(e_limitcheck);
+ hsize = 8;
+ } else {
+ /* Normal header (1-byte array size, 2-byte length). */
+ /* We already checked rcnt >= 3. */
+ size = sdecodeushort(p + 2, num_format);
+ hsize = 4;
+ }
+ if (size < hsize)
+ return_error(e_syntaxerror);
+ /* Preallocate an array large enough for the worst case, */
+ /* namely, all objects and no strings. */
+ code = ialloc_ref_array(&pbs->bin_array,
+ a_all + a_executable, size / sizeof(ref),
+ "binary object sequence(objects)");
+ if (code < 0)
+ return code;
+ p += hsize - 1;
+ size -= hsize;
+ s_end_inline(s, p, rlimit);
+ pbs->max_array_index = pbs->top_size = top_size;
+ pbs->min_string_index = pbs->size = size;
+ pbs->index = 0;
+ pstate->s_da.is_dynamic = false;
+ pstate->s_da.base = pstate->s_da.next =
+ pstate->s_da.limit = pstate->s_da.buf;
+ code = scan_bos_continue(s, pref, pstate);
+ if (code == scan_Refill || code < 0) {
+ /* Clean up array for GC. */
+ uint index = pbs->index;
+
+ refset_null(pbs->bin_array.value.refs + index,
+ r_size(&pbs->bin_array) - index);
+ pbs->cont = scan_bos_continue;
+ }
+ return code;
+ }
+ case BT_INT8:
+ make_int(pref, (p[1] ^ 128) - 128);
+ s_end_inline(s, p + 1, rlimit);
+ return 0;
+ case BT_FIXED:
+ num_format = p[1];
+ if (!num_is_valid(num_format))
+ return_error(e_syntaxerror);
+ wanted = 1 + encoded_number_bytes(num_format);
+ if (rcnt < wanted) {
+ s_end_inline(s, p - 1, rlimit);
+ pstate->s_scan_type = scanning_none;
+ return scan_Refill;
+ }
+ code = sdecode_number(p + 2, num_format, pref);
+ goto rnum;
+ case BT_INT32_MSB:
+ case BT_INT32_LSB:
+ case BT_INT16_MSB:
+ case BT_INT16_LSB:
+ case BT_FLOAT_IEEE_MSB:
+ case BT_FLOAT_IEEE_LSB:
+ case BT_FLOAT_NATIVE:
+ code = sdecode_number(p + 1, num_format, pref);
+ rnum:
+ switch (code) {
+ case t_integer:
+ case t_real:
+ r_set_type(pref, code);
+ break;
+ case t_null:
+ return_error(e_syntaxerror);
+ default:
+ return code;
+ }
+ s_end_inline(s, p + wanted, rlimit);
+ return 0;
+ case BT_BOOLEAN:
+ arg = p[1];
+ if (arg & ~1)
+ return_error(e_syntaxerror);
+ make_bool(pref, arg);
+ s_end_inline(s, p + 1, rlimit);
+ return 0;
+ case BT_STRING_256:
+ arg = *++p;
+ goto str;
+ case BT_STRING_64K_MSB:
+ case BT_STRING_64K_LSB:
+ arg = sdecodeushort(p + 1, num_format);
+ p += 2;
+ str:
+ {
+ byte *str = ialloc_string(arg, "string token");
+
+ if (str == 0)
+ return_error(e_VMerror);
+ s_end_inline(s, p, rlimit);
+ pstate->s_da.base = pstate->s_da.next = str;
+ pstate->s_da.limit = str + arg;
+ code = scan_bin_string_continue(s, pref, pstate);
+ if (code == scan_Refill || code < 0) {
+ pstate->s_da.is_dynamic = true;
+ make_null(&pbs->bin_array); /* clean up for GC */
+ pbs->cont = scan_bin_string_continue;
+ }
+ return code;
+ }
+ case BT_LITNAME_SYSTEM:
+ code = array_get(system_names_p, p[1], pref);
+ goto lname;
+ case BT_EXECNAME_SYSTEM:
+ code = array_get(system_names_p, p[1], pref);
+ goto xname;
+ case BT_LITNAME_USER:
+ code = array_get(user_names_p, p[1], pref);
+ lname:
+ if (code < 0)
+ return code;
+ if (!r_has_type(pref, t_name))
+ return_error(e_undefined);
+ s_end_inline(s, p + 1, rlimit);
+ return 0;
+ case BT_EXECNAME_USER:
+ code = array_get(user_names_p, p[1], pref);
+ xname:
+ if (code < 0)
+ return code;
+ if (!r_has_type(pref, t_name))
+ return_error(e_undefined);
+ r_set_attrs(pref, a_executable);
+ s_end_inline(s, p + 1, rlimit);
+ return 0;
+ case BT_NUM_ARRAY:
+ num_format = p[1];
+ if (!num_is_valid(num_format))
+ return_error(e_syntaxerror);
+ arg = sdecodeushort(p + 2, num_format);
+ code = ialloc_ref_array(&pbs->bin_array, a_all, arg,
+ "number array token");
+ if (code < 0)
+ return code;
+ pbs->num_format = num_format;
+ pbs->index = 0;
+ p += 3;
+ s_end_inline(s, p, rlimit);
+ code = scan_bin_num_array_continue(s, pref, pstate);
+ if (code == scan_Refill || code < 0) {
+ /* Make sure the array is clean for the GC. */
+ refset_null(pbs->bin_array.value.refs + pbs->index,
+ arg - pbs->index);
+ pbs->cont = scan_bin_num_array_continue;
+ }
+ return code;
+ }
+ return_error(e_syntaxerror);
+}
+
+/* Continue collecting a binary string. */
+private int
+scan_bin_string_continue(stream * s, ref * pref, scanner_state * pstate)
+{
+ byte *q = pstate->s_da.next;
+ uint wanted = pstate->s_da.limit - q;
+ uint rcnt;
+
+ sgets(s, q, wanted, &rcnt);
+ if (rcnt == wanted) {
+ /* Finished collecting the string. */
+ make_string(pref, a_all | icurrent_space,
+ pstate->s_da.limit - pstate->s_da.base,
+ pstate->s_da.base);
+ return 0;
+ }
+ pstate->s_da.next = q + rcnt;
+ pstate->s_scan_type = scanning_binary;
+ return scan_Refill;
+}
+
+/* Continue scanning a binary number array. */
+private int
+scan_bin_num_array_continue(stream * s, ref * pref, scanner_state * pstate)
+{
+ scan_binary_state *const pbs = &pstate->s_ss.binary;
+ uint index = pbs->index;
+ ref *np = pbs->bin_array.value.refs + index;
+ uint wanted = encoded_number_bytes(pbs->num_format);
+
+ for (; index < r_size(&pbs->bin_array); index++, np++) {
+ int code;
+
+ if (sbufavailable(s) < wanted) {
+ pbs->index = index;
+ pstate->s_scan_type = scanning_binary;
+ return scan_Refill;
+ }
+ code = sdecode_number(sbufptr(s), pbs->num_format, np);
+ switch (code) {
+ case t_integer:
+ case t_real:
+ r_set_type(np, code);
+ sbufskip(s, wanted);
+ break;
+ case t_null:
+ return_error(e_syntaxerror);
+ default:
+ return code;
+ }
+ }
+ *pref = pbs->bin_array;
+ return 0;
+}
+
+/*
+ * Continue scanning a binary object sequence. We preallocated space for
+ * the largest possible number of objects, but not for strings, since
+ * the latter would probably be a gross over-estimate. Instead,
+ * we wait until we see the first string or name, and allocate string space
+ * based on the hope that its string index is the smallest one we will see.
+ * If this turns out to be wrong, we may have to reallocate, and adjust
+ * all the pointers.
+ */
+private int
+scan_bos_continue(register stream * s, ref * pref, scanner_state * pstate)
+{
+ scan_binary_state *const pbs = &pstate->s_ss.binary;
+ s_declare_inline(s, p, rlimit);
+ uint max_array_index = pbs->max_array_index;
+ uint min_string_index = pbs->min_string_index;
+ int num_format = pbs->num_format;
+ uint index = pbs->index;
+ uint size = pbs->size;
+ ref *abase = pbs->bin_array.value.refs;
+ int code;
+
+ s_begin_inline(s, p, rlimit);
+ for (; index < max_array_index; p += SIZEOF_BIN_SEQ_OBJ, index++) {
+ ref *op = abase + index;
+ uint osize;
+ long value;
+ uint atype, attrs;
+
+ s_end_inline(s, p, rlimit); /* in case of error */
+ if (rlimit - p < SIZEOF_BIN_SEQ_OBJ) {
+ pbs->index = index;
+ pbs->max_array_index = max_array_index;
+ pbs->min_string_index = min_string_index;
+ pstate->s_scan_type = scanning_binary;
+ return scan_Refill;
+ }
+ attrs = (p[1] & 128 ? a_executable : 0);
+ switch (p[1] & 0x7f) {
+ case BS_TYPE_NULL:
+ make_null(op);
+ break;
+ case BS_TYPE_INTEGER:
+ make_int(op, sdecodelong(p + 5, num_format));
+ break;
+ case BS_TYPE_REAL:{
+ float vreal;
+
+ osize = sdecodeushort(p + 3, num_format);
+ if (osize != 0) { /* fixed-point number */
+ value = sdecodelong(p + 5, num_format);
+ vreal = (float)ldexp((double)value, -osize);
+ } else {
+ vreal = sdecodefloat(p + 5, num_format);
+ }
+ make_real(op, vreal);
+ break;
+ }
+ case BS_TYPE_BOOLEAN:
+ make_bool(op, sdecodelong(p + 5, num_format) != 0);
+ break;
+ case BS_TYPE_STRING:
+ osize = sdecodeushort(p + 3, num_format);
+ attrs |= a_all;
+ str:
+ if (osize == 0) {
+ /* For zero-length strings, the offset */
+ /* doesn't matter, and may be zero. */
+ make_empty_string(op, attrs);
+ break;
+ }
+ value = sdecodelong(p + 5, num_format);
+ if (value < max_array_index * SIZEOF_BIN_SEQ_OBJ ||
+ value + osize > size
+ )
+ return_error(e_syntaxerror);
+ if (value < min_string_index) {
+ /* We have to (re)allocate the strings. */
+ uint str_size = size - value;
+ byte *sbase;
+
+ if (pstate->s_da.is_dynamic)
+ sbase = scan_bos_resize(pstate, str_size,
+ index);
+ else
+ sbase = ialloc_string(str_size,
+ "bos strings");
+ if (sbase == 0)
+ return_error(e_VMerror);
+ pstate->s_da.is_dynamic = true;
+ pstate->s_da.base = pstate->s_da.next = sbase;
+ pstate->s_da.limit = sbase + str_size;
+ min_string_index = value;
+ }
+ make_string(op, attrs | icurrent_space, osize,
+ pstate->s_da.base +
+ (value - min_string_index));
+ break;
+ case BS_TYPE_EVAL_NAME:
+ attrs |= a_readonly; /* mark as executable for later */
+ /* falls through */
+ case BS_TYPE_NAME:
+ osize = sdecodeushort(p + 3, num_format);
+ value = sdecodelong(p + 5, num_format);
+ switch (osize) {
+ case 0:
+ code = array_get(user_names_p, value, op);
+ goto usn;
+ case 0xffff:
+ code = array_get(system_names_p, value, op);
+ usn:
+ if (code < 0)
+ return code;
+ if (!r_has_type(op, t_name))
+ return_error(e_undefined);
+ r_set_attrs(op, attrs);
+ break;
+ default:
+ goto str;
+ }
+ break;
+ case BS_TYPE_ARRAY:
+ osize = sdecodeushort(p + 3, num_format);
+ atype = t_array;
+ arr:
+ value = sdecodelong(p + 5, num_format);
+ if (value + osize > min_string_index ||
+ value & (SIZEOF_BIN_SEQ_OBJ - 1)
+ )
+ return_error(e_syntaxerror);
+ {
+ uint aindex = value / SIZEOF_BIN_SEQ_OBJ;
+
+ max_array_index =
+ max(max_array_index, aindex + osize);
+ make_tasv_new(op, atype,
+ attrs | a_all | icurrent_space,
+ osize, refs, abase + aindex);
+ }
+ break;
+ case BS_TYPE_DICTIONARY: /* EXTENSION */
+ osize = sdecodeushort(p + 3, num_format);
+ if ((osize & 1) != 0 && osize != 1)
+ return_error(e_syntaxerror);
+ atype = t_mixedarray; /* mark as dictionary */
+ goto arr;
+ case BS_TYPE_MARK:
+ make_mark(op);
+ break;
+ default:
+ return_error(e_syntaxerror);
+ }
+ }
+ s_end_inline(s, p, rlimit);
+ /* Shorten the objects to remove the space that turned out */
+ /* to be used for strings. */
+ iresize_ref_array(&pbs->bin_array, max_array_index,
+ "binary object sequence(objects)");
+ code = scan_bos_string_continue(s, pref, pstate);
+ if (code == scan_Refill)
+ pbs->cont = scan_bos_string_continue;
+ return code;
+}
+
+/* Reallocate the strings for a binary object sequence, */
+/* adjusting all the pointers to them from objects. */
+private byte *
+scan_bos_resize(scanner_state * pstate, uint new_size, uint index)
+{
+ scan_binary_state *const pbs = &pstate->s_ss.binary;
+ uint old_size = da_size(&pstate->s_da);
+ byte *old_base = pstate->s_da.base;
+ byte *new_base = iresize_string(old_base, old_size, new_size,
+ "scan_bos_resize");
+ byte *relocated_base = new_base + (new_size - old_size);
+ uint i;
+ ref *aptr = pbs->bin_array.value.refs;
+
+ if (new_base == 0)
+ return 0;
+ /* Since the allocator normally extends strings downward, */
+ /* it's quite possible that new and old addresses are the same. */
+ if (relocated_base != old_base)
+ for (i = index; i != 0; i--, aptr++)
+ if (r_has_type(aptr, t_string) && r_size(aptr) != 0)
+ aptr->value.bytes =
+ aptr->value.bytes - old_base + relocated_base;
+ return new_base;
+}
+
+/* Continue reading the strings for a binary object sequence. */
+private int
+scan_bos_string_continue(register stream * s, ref * pref, scanner_state * pstate)
+{
+ scan_binary_state *const pbs = &pstate->s_ss.binary;
+ ref rstr;
+ ref *op = pbs->bin_array.value.refs;
+ int code = scan_bin_string_continue(s, &rstr, pstate);
+ uint space = ialloc_space(idmemory);
+ bool rescan = false;
+ uint i;
+
+ if (code != 0)
+ return code;
+ /* Finally, fix up names and dictionaries. */
+ for (i = r_size(&pbs->bin_array); i != 0; i--, op++)
+ switch (r_type(op)) {
+ case t_string:
+ if (r_has_attr(op, a_write)) /* a real string */
+ break;
+ /* This is actually a name; look it up now. */
+ {
+ uint attrs =
+ (r_has_attr(op, a_executable) ? a_executable : 0);
+
+ code = name_ref(op->value.bytes, r_size(op), op, 1);
+ if (code < 0)
+ return code;
+ r_set_attrs(op, attrs);
+ }
+ /* falls through */
+ case t_name:
+ if (r_has_attr(op, a_read)) { /* BS_TYPE_EVAL_NAME */
+ ref *defp = dict_find_name(op);
+
+ if (defp == 0)
+ return_error(e_undefined);
+ store_check_space(space, defp);
+ ref_assign(op, defp);
+ }
+ break;
+ case t_mixedarray: /* actually a dictionary */
+ {
+ uint count = r_size(op);
+ ref rdict;
+
+ if (count == 1) {
+ /* Indirect reference. */
+ if (op->value.refs < op)
+ ref_assign(&rdict, op->value.refs);
+ else {
+ rescan = true;
+ continue;
+ }
+ } else {
+ code = dict_create(count >> 1, &rdict);
+ if (code < 0)
+ return code;
+ while (count) {
+ count -= 2;
+ code = dict_put(&rdict,
+ &op->value.refs[count],
+ &op->value.refs[count + 1]);
+ if (code < 0)
+ return code;
+ }
+ }
+ r_set_attrs(&rdict, a_all);
+ r_copy_attrs(&rdict, a_executable, op);
+ ref_assign(op, &rdict);
+ }
+ break;
+ }
+ /* If there were any forward indirect references, */
+ /* fix them up now. */
+ if (rescan)
+ for (op = pbs->bin_array.value.refs, i = r_size(&pbs->bin_array);
+ i != 0; i--, op++
+ )
+ if (r_has_type(op, t_mixedarray)) {
+ const ref *piref = op->value.const_refs;
+ ref rdict;
+
+ if (r_has_type(piref, t_mixedarray)) /* ref to indirect */
+ return_error(e_syntaxerror);
+ ref_assign(&rdict, piref);
+ r_copy_attrs(&rdict, a_executable, op);
+ ref_assign(op, &rdict);
+ }
+ ref_assign(pref, &pbs->bin_array);
+ r_set_size(pref, pbs->top_size);
+ return scan_BOS;
+}
+
+/* ---------------- Writing ---------------- */
+
+int
+encode_binary_token(const ref * obj, long *ref_offset, long *char_offset,
+ byte * str)
+{
+ bin_seq_type_t type;
+ uint size = 0;
+ long value;
+ ref nstr;
+
+ switch (r_type(obj)) {
+ case t_null:
+ type = BS_TYPE_NULL;
+ goto tx;
+ case t_mark:
+ type = BS_TYPE_MARK;
+ goto tx;
+ case t_integer:
+ type = BS_TYPE_INTEGER;
+ value = obj->value.intval;
+ break;
+ case t_real:
+ type = BS_TYPE_REAL;
+ /***** DOESN'T HANDLE NON-IEEE NATIVE *****/
+ if (sizeof(obj->value.realval) == sizeof(int)) {
+ value = *(const int *)&obj->value.realval;
+ } else {
+ /****** CAN'T HANDLE IT ******/
+ return_error(e_rangecheck);
+ }
+ break;
+ case t_boolean:
+ type = BS_TYPE_BOOLEAN;
+ value = obj->value.boolval;
+ break;
+ case t_array:
+ type = BS_TYPE_ARRAY;
+ size = r_size(obj);
+ goto aod;
+ case t_dictionary: /* EXTENSION */
+ type = BS_TYPE_DICTIONARY;
+ size = dict_length(obj) << 1;
+ aod:value = *ref_offset;
+ *ref_offset += size * (ulong) SIZEOF_BIN_SEQ_OBJ;
+ break;
+ case t_string:
+ type = BS_TYPE_STRING;
+nos:
+ size = r_size(obj);
+ value = *char_offset;
+ *char_offset += size;
+ break;
+ case t_name:
+ type = BS_TYPE_NAME;
+ name_string_ref(obj, &nstr);
+ r_copy_attrs(&nstr, a_executable, obj);
+ obj = &nstr;
+ goto nos;
+ default:
+ return_error(e_rangecheck);
+ }
+ {
+ byte s0 = (byte) size, s1 = (byte) (size >> 8);
+ byte v0 = (byte) value, v1 = (byte) (value >> 8), v2 = (byte) (value >> 16),
+ v3 = (byte) (value >> 24);
+ int order = (int)ref_binary_object_format.value.intval - 1;
+
+ if (order & 1) {
+ /* Store little-endian */
+ str[2] = s0, str[3] = s1;
+ str[4] = v0, str[5] = v1, str[6] = v2, str[7] = v3;
+ } else {
+ /* Store big-endian */
+ str[2] = s1, str[3] = s0;
+ str[4] = v3, str[5] = v2, str[6] = v1, str[7] = v0;
+ }
+ }
+tx:
+ if (r_has_attr(obj, a_executable))
+ type += BS_EXECUTABLE;
+ str[0] = (byte) type;
+ return 0;
+}
diff --git a/pstoraster/iscannum.c b/pstoraster/iscannum.c
new file mode 100644
index 000000000..07137418a
--- /dev/null
+++ b/pstoraster/iscannum.c
@@ -0,0 +1,398 @@
+/* Copyright (C) 1994, 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$ */
+/* Number scanner for Ghostscript interpreter */
+#include "math_.h"
+#include "ghost.h"
+#include "errors.h"
+#include "scommon.h"
+#include "iscannum.h" /* defines interface */
+#include "scanchar.h"
+#include "store.h"
+
+/*
+ * Warning: this file has a "spaghetti" control structure. But since this
+ * code accounts for over 10% of the execution time of some PostScript
+ * files, this is one of the few places we feel this is justified.
+ */
+
+/*
+ * Scan a number. If the number consumes the entire string, return 0;
+ * if not, set *psp to the first character beyond the number and return 1.
+ */
+int
+scan_number(const byte * str, const byte * end, int sign,
+ ref * pref, const byte ** psp)
+{
+ const byte *sp = str;
+#define GET_NEXT(cvar, sp, end_action)\
+ if ( sp >= end ) { end_action; } else cvar = *sp++
+ /*
+ * Powers of 10 up to 6 can be represented accurately as
+ * a single-precision float.
+ */
+#define NUM_POWERS_10 6
+ static const float powers_10[NUM_POWERS_10 + 1] =
+ {
+ 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6
+ };
+ static const double neg_powers_10[NUM_POWERS_10 + 1] =
+ {
+ 1e0, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6
+ };
+ int ival;
+ long lval;
+ double dval;
+ int exp10;
+ int code = 0;
+ int c, d;
+ const byte *const decoder = scan_char_decoder;
+#define IS_DIGIT(d, c)\
+ ((d = decoder[c]) < 10)
+
+ GET_NEXT(c, sp, return_error(e_syntaxerror));
+#define WOULD_OVERFLOW(val, d, maxv)\
+ (val >= maxv / 10 && (val > maxv / 10 || d > (int)(maxv % 10)))
+ if (!IS_DIGIT(d, c)) {
+ if (c != '.')
+ return_error(e_syntaxerror);
+ /* Might be a number starting with '.'. */
+ GET_NEXT(c, sp, return_error(e_syntaxerror));
+ if (!IS_DIGIT(d, c))
+ return_error(e_syntaxerror);
+ ival = 0;
+ goto i2r;
+ }
+ /* Accumulate an integer in ival. */
+ /* Do up to 4 digits without a loop, */
+ /* since we know this can't overflow and since */
+ /* most numbers have 4 (integer) digits or fewer. */
+ ival = d;
+ if (end - sp >= 3) { /* just check once */
+ if (!IS_DIGIT(d, (c = *sp))) {
+ sp++;
+ goto ind;
+ }
+ ival = ival * 10 + d;
+ if (!IS_DIGIT(d, (c = sp[1]))) {
+ sp += 2;
+ goto ind;
+ }
+ ival = ival * 10 + d;
+ sp += 3;
+ if (!IS_DIGIT(d, (c = sp[-1])))
+ goto ind;
+ ival = ival * 10 + d;
+ }
+ for (;; ival = ival * 10 + d) {
+ GET_NEXT(c, sp, goto iret);
+ if (!IS_DIGIT(d, c))
+ break;
+ if (WOULD_OVERFLOW(ival, d, max_int))
+ goto i2l;
+ }
+ ind: /* We saw a non-digit while accumulating an integer in ival. */
+ switch (c) {
+ case '.':
+ GET_NEXT(c, sp, c = EOFC);
+ goto i2r;
+ default:
+ *psp = sp;
+ code = 1;
+ break;
+ case 'e':
+ case 'E':
+ if (sign < 0)
+ ival = -ival;
+ dval = ival;
+ exp10 = 0;
+ goto fe;
+ case '#':
+ {
+ const uint radix = (uint)ival;
+ ulong uval = 0, lmax;
+
+ if (sign || radix < min_radix || radix > max_radix)
+ return_error(e_syntaxerror);
+ /* Avoid multiplies for power-of-2 radix. */
+ if (!(radix & (radix - 1))) {
+ int shift;
+
+ switch (radix) {
+ case 2:
+ shift = 1, lmax = max_ulong >> 1;
+ break;
+ case 4:
+ shift = 2, lmax = max_ulong >> 2;
+ break;
+ case 8:
+ shift = 3, lmax = max_ulong >> 3;
+ break;
+ case 16:
+ shift = 4, lmax = max_ulong >> 4;
+ break;
+ case 32:
+ shift = 5, lmax = max_ulong >> 5;
+ break;
+ default: /* can't happen */
+ return_error(e_rangecheck);
+ }
+ for (;; uval = (uval << shift) + d) {
+ GET_NEXT(c, sp, break);
+ d = decoder[c];
+ if (d >= radix) {
+ *psp = sp;
+ code = 1;
+ break;
+ }
+ if (uval > lmax)
+ return_error(e_limitcheck);
+ }
+ } else {
+ int lrem = max_ulong % radix;
+
+ lmax = max_ulong / radix;
+ for (;; uval = uval * radix + d) {
+ GET_NEXT(c, sp, break);
+ d = decoder[c];
+ if (d >= radix) {
+ *psp = sp;
+ code = 1;
+ break;
+ }
+ if (uval >= lmax &&
+ (uval > lmax || d > lrem)
+ )
+ return_error(e_limitcheck);
+ }
+ }
+ make_int_new(pref, uval);
+ return code;
+ }
+ }
+iret:
+ make_int_new(pref, (sign < 0 ? -ival : ival));
+ return code;
+
+ /* Accumulate a long in lval. */
+i2l:
+ for (lval = ival;;) {
+ if (WOULD_OVERFLOW(lval, d, max_long)) {
+ /* Make a special check for entering the smallest */
+ /* (most negative) integer. */
+ if (lval == max_long / 10 &&
+ d == (int)(max_long % 10) + 1 && sign < 0
+ ) {
+ GET_NEXT(c, sp, c = EOFC);
+ dval = -(double)min_long;
+ if (c == 'e' || c == 'E' || c == '.') {
+ exp10 = 0;
+ goto fs;
+ } else if (!IS_DIGIT(d, c)) {
+ lval = min_long;
+ break;
+ }
+ } else
+ dval = lval;
+ goto l2d;
+ }
+ lval = lval * 10 + d;
+ GET_NEXT(c, sp, goto lret);
+ if (!IS_DIGIT(d, c))
+ break;
+ }
+ switch (c) {
+ case '.':
+ GET_NEXT(c, sp, c = EOFC);
+ exp10 = 0;
+ goto l2r;
+ default:
+ *psp = sp;
+ code = 1;
+ break;
+ case 'e':
+ case 'E':
+ exp10 = 0;
+ goto le;
+ case '#':
+ return_error(e_syntaxerror);
+ }
+lret:
+ make_int_new(pref, (sign < 0 ? -lval : lval));
+ return code;
+
+ /* Accumulate a double in dval. */
+l2d:
+ exp10 = 0;
+ for (;;) {
+ dval = dval * 10 + d;
+ GET_NEXT(c, sp, c = EOFC);
+ if (!IS_DIGIT(d, c))
+ break;
+ }
+ switch (c) {
+ case '.':
+ GET_NEXT(c, sp, c = EOFC);
+ exp10 = 0;
+ goto fs;
+ default:
+ *psp = sp;
+ code = 1;
+ /* falls through */
+ case EOFC:
+ if (sign < 0)
+ dval = -dval;
+ goto rret;
+ case 'e':
+ case 'E':
+ exp10 = 0;
+ goto fs;
+ case '#':
+ return_error(e_syntaxerror);
+ }
+
+ /* We saw a '.' while accumulating an integer in ival. */
+i2r:
+ exp10 = 0;
+ while (IS_DIGIT(d, c)) {
+ if (WOULD_OVERFLOW(ival, d, max_int)) {
+ lval = ival;
+ goto l2r;
+ }
+ ival = ival * 10 + d;
+ exp10--;
+ GET_NEXT(c, sp, c = EOFC);
+ }
+ if (sign < 0)
+ ival = -ival;
+ /* Take a shortcut for the common case */
+ if (!(c == 'e' || c == 'E' || exp10 < -NUM_POWERS_10)) { /* Check for trailing garbage */
+ if (c != EOFC)
+ *psp = sp, code = 1;
+ make_real_new(pref, ival * neg_powers_10[-exp10]);
+ return code;
+ }
+ dval = ival;
+ goto fe;
+
+ /* We saw a '.' while accumulating a long in lval. */
+l2r:
+ while (IS_DIGIT(d, c)) {
+ if (WOULD_OVERFLOW(lval, d, max_long)) {
+ dval = lval;
+ goto fd;
+ }
+ lval = lval * 10 + d;
+ exp10--;
+ GET_NEXT(c, sp, c = EOFC);
+ }
+le:
+ if (sign < 0)
+ lval = -lval;
+ dval = lval;
+ goto fe;
+
+ /* Now we are accumulating a double in dval. */
+fd:
+ while (IS_DIGIT(d, c)) {
+ dval = dval * 10 + d;
+ exp10--;
+ GET_NEXT(c, sp, c = EOFC);
+ }
+fs:
+ if (sign < 0)
+ dval = -dval;
+fe:
+ /* Now dval contains the value, negated if necessary. */
+ switch (c) {
+ case 'e':
+ case 'E':
+ { /* Check for a following exponent. */
+ int esign = 0;
+ int iexp;
+
+ GET_NEXT(c, sp, return_error(e_syntaxerror));
+ switch (c) {
+ case '-':
+ esign = 1;
+ case '+':
+ GET_NEXT(c, sp, return_error(e_syntaxerror));
+ }
+ /* Scan the exponent. We limit it arbitrarily to 999. */
+ if (!IS_DIGIT(d, c))
+ return_error(e_syntaxerror);
+ iexp = d;
+ for (;; iexp = iexp * 10 + d) {
+ GET_NEXT(c, sp, break);
+ if (!IS_DIGIT(d, c)) {
+ *psp = sp;
+ code = 1;
+ break;
+ }
+ if (iexp > 99)
+ return_error(e_limitcheck);
+ }
+ if (esign)
+ exp10 -= iexp;
+ else
+ exp10 += iexp;
+ break;
+ }
+ default:
+ *psp = sp;
+ code = 1;
+ case EOFC:
+ ;
+ }
+ /* Compute dval * 10^exp10. */
+ if (exp10 > 0) {
+ while (exp10 > NUM_POWERS_10)
+ dval *= powers_10[NUM_POWERS_10],
+ exp10 -= NUM_POWERS_10;
+ if (exp10 > 0)
+ dval *= powers_10[exp10];
+ } else if (exp10 < 0) {
+ while (exp10 < -NUM_POWERS_10)
+ dval /= powers_10[NUM_POWERS_10],
+ exp10 += NUM_POWERS_10;
+ if (exp10 < 0)
+ dval /= powers_10[-exp10];
+ }
+ /*
+ * Check for an out-of-range result. Currently we don't check for
+ * absurdly large numbers of digits in the accumulation loops,
+ * but we should.
+ */
+ if (dval >= 0) {
+ if (dval > MAX_FLOAT)
+ return_error(e_limitcheck);
+ } else {
+ if (dval < -MAX_FLOAT)
+ return_error(e_limitcheck);
+ }
+rret:
+ make_real_new(pref, dval);
+ return code;
+}
diff --git a/pstoraster/iscannum.h b/pstoraster/iscannum.h
new file mode 100644
index 000000000..e44b7c93c
--- /dev/null
+++ b/pstoraster/iscannum.h
@@ -0,0 +1,36 @@
+/* Copyright (C) 1994, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of GNU Ghostscript.
+
+ GNU Ghostscript is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
+ to anyone for the consequences of using it or for whether it serves any
+ particular purpose or works at all, unless he says so in writing. Refer
+ to the GNU General Public License for full details.
+
+ Everyone is granted permission to copy, modify and redistribute GNU
+ Ghostscript, but only under the conditions described in the GNU General
+ Public License. A copy of this license is supposed to have been given
+ to you along with GNU Ghostscript so you can know your rights and
+ responsibilities. It should be in a file named COPYING. Among other
+ things, the copyright notice and this notice must be preserved on all
+ copies.
+
+ Aladdin Enterprises 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 Ghostscript number scanner */
+
+#ifndef iscannum_INCLUDED
+# define iscannum_INCLUDED
+
+/* Scan a number. If the number consumes the entire string, return 0; */
+/* if not, set *psp to the first character beyond the number and return 1. */
+int scan_number(P5(const byte * sp, const byte * end, int sign, ref * pref,
+ const byte ** psp));
+
+#endif /* iscannum_INCLUDED */
diff --git a/pstoraster/isstate.h b/pstoraster/isstate.h
new file mode 100644
index 000000000..146c71248
--- /dev/null
+++ b/pstoraster/isstate.h
@@ -0,0 +1,46 @@
+/* Copyright (C) 1993, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of GNU Ghostscript.
+
+ GNU Ghostscript is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
+ to anyone for the consequences of using it or for whether it serves any
+ particular purpose or works at all, unless he says so in writing. Refer
+ to the GNU General Public License for full details.
+
+ Everyone is granted permission to copy, modify and redistribute GNU
+ Ghostscript, but only under the conditions described in the GNU General
+ Public License. A copy of this license is supposed to have been given
+ to you along with GNU Ghostscript so you can know your rights and
+ responsibilities. It should be in a file named COPYING. Among other
+ things, the copyright notice and this notice must be preserved on all
+ copies.
+
+ Aladdin Enterprises 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 isave.h */
+
+#ifndef isstate_INCLUDED
+# define isstate_INCLUDED
+
+/* Saved state of allocator and other things as needed. */
+ /*typedef struct alloc_save_s alloc_save_t; *//* in isave.h */
+struct alloc_save_s {
+ gs_ref_memory_t state; /* must be first for subclassing */
+ gs_dual_memory_t *dmem;
+ bool restore_names;
+ bool is_current;
+ ulong id;
+ void *client_data;
+};
+
+#define private_st_alloc_save() /* in isave.c */\
+ gs_private_st_suffix_add1(st_alloc_save, alloc_save_t, "alloc_save",\
+ save_enum_ptrs, save_reloc_ptrs, st_ref_memory, client_data)
+
+#endif /* isstate_INCLUDED */
diff --git a/pstoraster/istack.c b/pstoraster/istack.c
new file mode 100644
index 000000000..2fc191e08
--- /dev/null
+++ b/pstoraster/istack.c
@@ -0,0 +1,588 @@
+/* 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$ */
+/* Ghostscript expandable stack manager */
+#include "memory_.h"
+#include "ghost.h"
+#include "gsstruct.h"
+#include "gsutil.h"
+#include "errors.h"
+#include "ialloc.h"
+#include "istack.h"
+#include "istruct.h" /* for RELOC_REF_VAR */
+#include "iutil.h"
+#include "ivmspace.h" /* for local/global test */
+#include "store.h"
+
+/* Forward references */
+private void init_block(P3(ref_stack *, ref *, uint));
+int ref_stack_push_block(P3(ref_stack *, uint, uint));
+
+/* GC procedures */
+#define sptr ((ref_stack *)vptr)
+private
+CLEAR_MARKS_PROC(ref_stack_clear_marks)
+{
+ r_clear_attrs(&sptr->current, l_mark);
+}
+private
+ENUM_PTRS_BEGIN(ref_stack_enum_ptrs) return 0;
+
+case 0:
+ENUM_RETURN_REF(&sptr->current);
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(ref_stack_reloc_ptrs)
+{
+ /* Note that the relocation must be a multiple of sizeof(ref_packed) */
+ /* * align_packed_per_ref, but it need not be a multiple of */
+ /* sizeof(ref). Therefore, we must do the adjustments using */
+ /* ref_packed pointers rather than ref pointers. */
+ ref_packed *bot = (ref_packed *) sptr->current.value.refs;
+ long reloc;
+
+ RELOC_REF_VAR(sptr->current);
+ r_clear_attrs(&sptr->current, l_mark);
+ reloc = bot - (ref_packed *) sptr->current.value.refs;
+#define RELOC_P(p)\
+ sptr->p = (ref *)((ref_packed *)sptr->p - reloc);
+ RELOC_P(p);
+ RELOC_P(bot);
+ RELOC_P(top);
+#undef RELOC_P
+} RELOC_PTRS_END
+/* Structure type for a ref_stack. */
+public_st_ref_stack();
+
+/* Initialize a stack. */
+void
+ref_stack_init(ref_stack * pstack, ref * psb, uint bot_guard, uint top_guard,
+ ref * pguard, gs_ref_memory_t * mem)
+{
+ uint size = r_size(psb);
+ uint avail = size - (stack_block_refs + bot_guard + top_guard);
+ ref_stack_block *pblock = (ref_stack_block *) psb->value.refs;
+ s_ptr body = (s_ptr) (pblock + 1);
+
+ pstack->bot = body + bot_guard;
+ pstack->p = pstack->bot - 1;
+ pstack->top = pstack->p + avail;
+ pstack->current = *psb;
+ pstack->extension_size = 0;
+ pstack->extension_used = 0;
+
+ make_int(&pstack->max_stack, avail);
+ pstack->requested = 0;
+ pstack->margin = 0;
+ pstack->body_size = avail;
+
+ pstack->bot_guard = bot_guard;
+ pstack->top_guard = top_guard;
+ pstack->block_size = size;
+ pstack->data_size = avail;
+ if (pguard != 0)
+ pstack->guard_value = *pguard;
+ else
+ make_tav(&pstack->guard_value, t__invalid, 0, intval, 0);
+ pstack->underflow_error = -1; /* bogus, caller must set */
+ pstack->overflow_error = -1; /* bogus, caller must set */
+ pstack->allow_expansion = true; /* default, caller may reset */
+ pstack->memory = mem;
+ init_block(pstack, psb, 0);
+ refset_null(pstack->bot, avail);
+ make_empty_array(&pblock->next, 0);
+}
+
+/* Set the maximum number of elements allowed on a stack. */
+int
+ref_stack_set_max_count(ref_stack * pstack, long nmax)
+{
+ uint nmin = ref_stack_count_inline(pstack);
+
+ if (nmax < nmin)
+ nmax = nmin;
+ if (nmax > max_uint / sizeof(ref))
+ nmax = max_uint / sizeof(ref);
+ if (!pstack->allow_expansion) {
+ uint ncur = pstack->body_size;
+
+ if (nmax > ncur)
+ nmax = ncur;
+ }
+ pstack->max_stack.value.intval = nmax;
+ return 0;
+}
+
+/* Set the margin between the limit and the top of the stack. */
+/* Note that this may require allocating a block. */
+int
+ref_stack_set_margin(ref_stack * pstack, uint margin)
+{
+ if (margin <= pstack->margin) {
+ refset_null(pstack->top + 1, pstack->margin - margin);
+ } else {
+ if (margin > pstack->data_size >> 1)
+ return_error(e_rangecheck);
+ if (pstack->top - pstack->p < margin) {
+ uint used = pstack->p + 1 - pstack->bot;
+ uint keep = pstack->data_size - margin;
+ int code = ref_stack_push_block(pstack, keep, used - keep);
+
+ if (code < 0)
+ return code;
+ }
+ }
+ pstack->margin = margin;
+ pstack->body_size = pstack->data_size - margin;
+ pstack->top = pstack->bot + pstack->body_size - 1;
+ return 0;
+}
+
+/* Return the number of elements on a stack. */
+uint
+ref_stack_count(const ref_stack * pstack)
+{
+ return pstack->extension_used + (pstack->p - pstack->bot + 1);
+}
+
+/* Retrieve a given element from the stack, counting from */
+/* 0 as the top element. */
+ref *
+ref_stack_index(const ref_stack * pstack, long idx)
+{
+ ref_stack_block *pblock;
+ uint used = pstack->p + 1 - pstack->bot;
+
+ if (idx < 0)
+ return NULL;
+ if (idx < used) /* common case */
+ return pstack->p - (uint) idx;
+ pblock = (ref_stack_block *) pstack->current.value.refs;
+ do {
+ pblock = (ref_stack_block *) pblock->next.value.refs;
+ if (pblock == 0)
+ return NULL;
+ idx -= used;
+ used = r_size(&pblock->used);
+ } while (idx >= used);
+ return pblock->used.value.refs + (used - 1 - (uint) idx);
+}
+
+/* Count the number of elements down to and including the first mark. */
+/* If no mark is found, return 0. */
+uint
+ref_stack_counttomark(const ref_stack * pstack)
+{
+ uint scanned = 0;
+ ref_stack_enum_t rsenum;
+
+ ref_stack_enum_begin(&rsenum, pstack);
+ do {
+ uint count = rsenum.size;
+ const ref *p = rsenum.ptr + count - 1;
+
+ for (; count; count--, p--)
+ if (r_has_type(p, t_mark))
+ return scanned + (rsenum.size - count + 1);
+ scanned += rsenum.size;
+ } while (ref_stack_enum_next(&rsenum));
+ return 0;
+}
+
+/* Do the store check for storing elements of a stack into an array. */
+/* May return e_invalidaccess. */
+int
+ref_stack_store_check(const ref_stack * pstack, ref * parray, uint count,
+ uint skip)
+{
+ uint space = r_space(parray);
+
+ if (space != avm_local) {
+ uint left = count, pass = skip;
+ ref_stack_enum_t rsenum;
+
+ ref_stack_enum_begin(&rsenum, pstack);
+ do {
+ ref *ptr = rsenum.ptr;
+ uint size = rsenum.size;
+
+ if (size <= pass)
+ pass -= size;
+ else {
+ int code;
+
+ if (pass != 0)
+ size -= pass, pass = 0;
+ ptr += size;
+ if (size > left)
+ size = left;
+ left -= size;
+ code = refs_check_space(ptr - size, size, space);
+ if (code < 0)
+ return code;
+ if (left == 0)
+ break;
+ }
+ } while (ref_stack_enum_next(&rsenum));
+ }
+ return 0;
+}
+
+/* Store the top elements of a stack into an array, */
+/* with or without store/undo checking. */
+/* May return e_rangecheck or e_invalidaccess. */
+int
+ref_stack_store(const ref_stack * pstack, ref * parray, uint count, uint skip,
+ int age, bool check, client_name_t cname)
+{
+ uint left, pass;
+ ref *to;
+ ref_stack_enum_t rsenum;
+
+ if (count > ref_stack_count(pstack) || count > r_size(parray))
+ return_error(e_rangecheck);
+ if (check) {
+ int code = ref_stack_store_check(pstack, parray, count, skip);
+
+ if (code < 0)
+ return code;
+ }
+ to = parray->value.refs + count;
+ left = count, pass = skip;
+ ref_stack_enum_begin(&rsenum, pstack);
+ do {
+ ref *from = rsenum.ptr;
+ uint size = rsenum.size;
+
+ if (size <= pass)
+ pass -= size;
+ else {
+ if (pass != 0)
+ size -= pass, pass = 0;
+ from += size;
+ if (size > left)
+ size = left;
+ left -= size;
+ switch (age) {
+ case -1: /* not an array */
+ while (size--) {
+ from--, to--;
+ ref_assign(to, from);
+ }
+ break;
+ case 0: /* old array */
+ while (size--) {
+ from--, to--;
+ ref_assign_old(parray, to, from, cname);
+ }
+ break;
+ case 1: /* new array */
+ while (size--) {
+ from--, to--;
+ ref_assign_new(to, from);
+ }
+ break;
+ }
+ if (left == 0)
+ break;
+ }
+ } while (ref_stack_enum_next(&rsenum));
+ r_set_size(parray, count);
+ return 0;
+}
+
+/* Pop a given number of elements off a stack. */
+/* The number must not exceed the number of elements in use. */
+void
+ref_stack_pop(ref_stack * pstack, uint count)
+{
+ uint used;
+
+ while ((used = pstack->p + 1 - pstack->bot) < count) {
+ count -= used;
+ pstack->p = pstack->bot - 1;
+ ref_stack_pop_block(pstack);
+ }
+ pstack->p -= count;
+}
+
+/* Pop the top block off a stack. */
+int
+ref_stack_pop_block(ref_stack * pstack)
+{
+ s_ptr bot = pstack->bot;
+ uint count = pstack->p + 1 - bot;
+ ref_stack_block *pcur =
+ (ref_stack_block *) pstack->current.value.refs;
+ ref_stack_block *pnext =
+ (ref_stack_block *) pcur->next.value.refs;
+ uint used;
+ ref *body;
+ ref next;
+
+ if (pnext == 0)
+ return_error(pstack->underflow_error);
+ used = r_size(&pnext->used);
+ body = (ref *) (pnext + 1) + pstack->bot_guard;
+ next = pcur->next;
+ /*
+ * If the contents of the two blocks won't fit in a single block, we
+ * move up the used part of the top block, and copy up as much of
+ * the contents of the next block under it as will fit. If the
+ * contents of both blocks fit in a single block, we copy the used
+ * part of the top block to the top of the next block, and free the
+ * top block.
+ */
+ if (used + count > pstack->body_size) {
+ /*
+ * The contents of the two blocks won't fit into a single block.
+ * On the assumption that we're recovering from a local stack
+ * underflow and need to increase the number of contiguous
+ * elements available, move up the used part of the top block, and
+ * copy up as much of the contents of the next block under it as
+ * will fit.
+ */
+ uint moved = pstack->body_size - count;
+ uint left;
+
+ if (moved == 0)
+ return_error(e_Fatal);
+ memmove(bot + moved, bot, count * sizeof(ref));
+ left = used - moved;
+ memcpy(bot, body + left, moved * sizeof(ref));
+ refset_null(body + left, moved);
+ r_dec_size(&pnext->used, moved);
+ pstack->p = pstack->top;
+ pstack->extension_used -= moved;
+ } else {
+ /*
+ * The contents of the two blocks will fit into a single block.
+ * Copy the used part of the top block to the top of the next
+ * block, and free the top block.
+ */
+ memcpy(body + used, bot, count * sizeof(ref));
+ pstack->bot = bot = body;
+ pstack->top = bot + pstack->body_size - 1;
+ gs_free_ref_array(pstack->memory, &pstack->current,
+ "ref_stack_pop_block");
+ pstack->current = next;
+ pstack->p = bot + (used + count - 1);
+ pstack->extension_size -= pstack->body_size;
+ pstack->extension_used -= used;
+ }
+ return 0;
+}
+
+/* Extend a stack to recover from an overflow condition. */
+/* May return overflow_error or e_VMerror. */
+int
+ref_stack_extend(ref_stack * pstack, uint request)
+{
+ uint keep = (pstack->top - pstack->bot + 1) / 3;
+ uint count = pstack->p - pstack->bot + 1;
+
+ if (request > pstack->data_size)
+ return_error(pstack->overflow_error);
+ if (keep + request > pstack->body_size)
+ keep = pstack->body_size - request;
+ if (keep > count)
+ keep = count; /* required by ref_stack_push_block */
+ return ref_stack_push_block(pstack, keep, request);
+}
+
+/* Push N empty slots onto a stack. These slots are not initialized; */
+/* the caller must fill them immediately. May return overflow_error */
+/* (if max_stack would be exceeded, or the stack has no allocator) */
+/* or e_VMerror. */
+int
+ref_stack_push(ref_stack * pstack, uint count)
+{
+ /* Don't bother to pre-check for overflow: we must be able to */
+ /* back out in the case of a VMerror anyway, and */
+ /* ref_stack_push_block will make the check itself. */
+ uint needed = count;
+ uint added;
+
+ for (; (added = pstack->top - pstack->p) < needed; needed -= added) {
+ int code;
+
+ pstack->p = pstack->top;
+ code = ref_stack_push_block(pstack,
+ (pstack->top - pstack->bot + 1) / 3,
+ added);
+ if (code < 0) {
+ /* Back out. */
+ ref_stack_pop(pstack, count - needed + added);
+ pstack->requested = count;
+ return code;
+ }
+ }
+ pstack->p += needed;
+ return 0;
+}
+
+/* Push a block onto the stack, specifying how many elements of */
+/* the current top block should remain in the top block and also */
+/* how many elements we are trying to add. */
+/* May return overflow_error or e_VMerror. */
+/* Must have keep <= count. */
+int
+ref_stack_push_block(ref_stack * pstack, uint keep, uint add)
+{
+ uint count = pstack->p - pstack->bot + 1;
+ uint move = count - keep;
+ ref_stack_block *pcur = (ref_stack_block *) pstack->current.value.refs;
+ ref next;
+ ref_stack_block *pnext;
+ ref *body;
+ int code;
+
+ if (keep > count)
+ return_error(e_Fatal);
+ /* Check for overflowing the maximum size, */
+ /* or expansion not allowed. */
+ if (pstack->memory == 0 ||
+ pstack->extension_used + (pstack->top - pstack->bot) + add >=
+ pstack->max_stack.value.intval ||
+ !pstack->allow_expansion
+ )
+ return_error(pstack->overflow_error);
+ code = gs_alloc_ref_array(pstack->memory, &next, 0,
+ pstack->block_size, "ref_stack_push_block");
+ if (code < 0)
+ return code;
+ pnext = (ref_stack_block *) next.value.refs;
+ body = (ref *) (pnext + 1);
+ /* Copy the top keep elements into the new block, */
+ /* and make the new block the top block. */
+ init_block(pstack, &next, keep);
+ body += pstack->bot_guard;
+ memcpy(body, pstack->bot + move, keep * sizeof(ref));
+ /* Clear the elements above the top of the new block. */
+ refset_null(body + keep, pstack->data_size - keep);
+ /* Clear the elements above the top of the old block. */
+ refset_null(pstack->bot + move, keep);
+ pnext->next = pstack->current;
+ pcur->used.value.refs = pstack->bot;
+ r_set_size(&pcur->used, move);
+ pstack->current = next;
+ pstack->bot = body;
+ pstack->top = pstack->bot + pstack->body_size - 1;
+ pstack->p = pstack->bot + keep - 1;
+ pstack->extension_size += pstack->body_size;
+ pstack->extension_used += move;
+ return 0;
+}
+
+/* Begin enumerating the blocks of a stack. */
+void
+ref_stack_enum_begin(ref_stack_enum_t *prse, const ref_stack *pstack)
+{
+ prse->block = (ref_stack_block *)pstack->current.value.refs;
+ prse->ptr = pstack->bot;
+ prse->size = pstack->p + 1 - pstack->bot;
+}
+
+bool
+ref_stack_enum_next(ref_stack_enum_t *prse)
+{
+ ref_stack_block *block =
+ prse->block = (ref_stack_block *)prse->block->next.value.refs;
+
+ if (block == 0)
+ return false;
+ prse->ptr = block->used.value.refs;
+ prse->size = r_size(&block->used);
+ return true;
+}
+
+/* Clean up a stack for garbage collection. */
+void
+ref_stack_cleanup(ref_stack * pstack)
+{
+ ref_stack_block *pblock =
+ (ref_stack_block *) pstack->current.value.refs;
+
+ refset_null(pstack->p + 1, pstack->top - pstack->p);
+ pblock->used = pstack->current; /* set attrs */
+ pblock->used.value.refs = pstack->bot;
+ r_set_size(&pblock->used, pstack->p + 1 - pstack->bot);
+}
+
+/*
+ * Free the entire contents of a stack, including the bottom block.
+ * The client must free the ref_stack itself. Note that after calling
+ * ref_stack_release, the stack is no longer usable.
+ */
+void
+ref_stack_release(ref_stack * pstack)
+{
+ ref_stack_clear(pstack);
+ /* Free the original (bottom) block. */
+ gs_free_ref_array(pstack->memory, &pstack->current,
+ "ref_stack_release");
+}
+
+/*
+ * Release a stack and then free the ref_stack object.
+ */
+void
+ref_stack_free(ref_stack * pstack, gs_memory_t * mem, client_name_t cname)
+{
+ ref_stack_release(pstack);
+ gs_free_object(mem, pstack, cname);
+}
+
+/* ------ Internal routines ------ */
+
+/* Initialize the guards and body of a stack block. */
+private void
+init_block(ref_stack * pstack, ref * psb, uint used)
+{
+ ref *brefs = psb->value.refs;
+ uint i;
+ ref *p;
+
+ for (i = pstack->bot_guard, p = brefs + stack_block_refs;
+ i != 0; i--, p++
+ )
+ ref_assign(p, &pstack->guard_value);
+ /* The top guard elements will never be read, */
+ /* but we need to initialize them for the sake of the GC. */
+ /* We can use refset_null for this, because even though it uses */
+ /* make_null_new and stack elements must not be marked new, */
+ /* these slots will never actually be read or written. */
+ if (pstack->top_guard) {
+ ref *top = brefs + r_size(psb);
+ int top_guard = pstack->top_guard;
+
+ refset_null(top - top_guard, top_guard);
+ } {
+ ref_stack_block *const pblock = (ref_stack_block *) brefs;
+
+ pblock->used = *psb;
+ pblock->used.value.refs = brefs + stack_block_refs + pstack->bot_guard;
+ r_set_size(&pblock->used, 0);
+ }
+}
diff --git a/pstoraster/istack.h b/pstoraster/istack.h
new file mode 100644
index 000000000..deacf36d2
--- /dev/null
+++ b/pstoraster/istack.h
@@ -0,0 +1,256 @@
+/* Copyright (C) 1992, 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$ */
+/* Definitions for expandable Ghostscript stacks */
+/* Requires iref.h */
+
+#ifndef istack_INCLUDED
+# define istack_INCLUDED
+
+/* Define an opaque allocator type. */
+#ifndef gs_ref_memory_DEFINED
+# define gs_ref_memory_DEFINED
+typedef struct gs_ref_memory_s gs_ref_memory_t;
+#endif
+
+/*
+ * The 3 principal Ghostscript stacks (operand, execution, and dictionary)
+ * are implemented as a linked list of blocks.
+ *
+ * Since all operators exit cleanly in case of stack under- or overflow,
+ * we handle all issues related to stack blocks in the top-level error
+ * recovery code in interp.c. A few situations require special treatment:
+ * see ostack.h, estack.h, and dstack.h for details.
+ */
+
+typedef ref *s_ptr;
+typedef const ref *const_s_ptr;
+
+/*
+ * Define the structure for a stack block.
+ * In order to simplify allocation, stack blocks are implemented as
+ * t_array objects, with the first few elements used for special purposes.
+ * The actual layout is as follows:
+ * ref_stack_block structure
+ * bottom guard if any (see below)
+ * used elements of block
+ * unused elements of block
+ * top guard if any (see below)
+ * The `next' member of the next higher stack block includes all of this.
+ * The `used' member only includes the used elements of this block.
+ * Notes:
+ * - In the top block, the size of the `used' member may not be correct.
+ * - In all blocks but the top, we fill the unused elements with nulls.
+ */
+typedef struct ref_stack_block_s {
+ ref next; /* t_array, next lower block on stack */
+ ref used; /* t_array, subinterval of this block */
+ /* Actual stack starts here */
+} ref_stack_block;
+
+#define stack_block_refs (sizeof(ref_stack_block) / sizeof(ref))
+
+/*
+ * In order to detect under- and overflow with minimum overhead, we put
+ * guard elements at the top and bottom of each stack block (see dstack.h,
+ * estack.h, and ostack.h for details of the individual stacks). Note that
+ * the 'current' and 'next' arrays include the guard elements.
+ */
+
+/*
+ * The garbage collector requires that the entire contents of every block
+ * be 'clean', i.e., contain legitimate refs; we also need to ensure that
+ * at GC time, pointers in unused areas of a block will not be followed
+ * (since they may be dangling). We ensure this as follows:
+ * - When allocating a new block, we set the entire body to nulls.
+ * This is necessary because the block may be freed before the next GC,
+ * and the GC must be able to scan (parse) refs even if they are free.
+ * - When adding a new block to the top of the stack, we set to nulls
+ * the unused area of the new next-to-top blocks.
+ * - At the beginning of garbage collection, we set to nulls the unused
+ * elements of the top block.
+ */
+
+/*
+ * Define the (statically allocated) state of a stack.
+ * Note that the total size of a stack cannot exceed max_uint,
+ * because it has to be possible to copy a stack to a PostScript array.
+ */
+#ifndef ref_stack_DEFINED
+typedef struct ref_stack_s ref_stack; /* also defined in idebug.h */
+# define ref_stack_DEFINED
+#endif
+struct ref_stack_s {
+ /* Following are updated dynamically. */
+ s_ptr p; /* current top element */
+ /* Following are updated when adding or deleting blocks. */
+ s_ptr bot; /* bottommost valid element */
+ s_ptr top; /* topmost valid element = */
+ /* bot + data_size */
+ ref current; /* t_array for current top block */
+ uint extension_size; /* total sizes of extn. blocks */
+ uint extension_used; /* total used sizes of extn. blocks */
+ /* Following are updated rarely. */
+ ref max_stack; /* t_integer, Max...Stack user param */
+ uint requested; /* amount of last failing */
+ /* push or pop request */
+ uint margin; /* # of slots to leave between limit */
+ /* and top */
+ uint body_size; /* data_size - margin */
+ /* Following are set at initialization. */
+ uint bot_guard; /* # of guard elements below bot */
+ uint top_guard; /* # of guard elements above top */
+ uint block_size; /* size of each block */
+ uint data_size; /* # of data slots in each block */
+ ref guard_value; /* t__invalid or t_operator, */
+ /* bottom guard value */
+ int underflow_error; /* error code for underflow */
+ int overflow_error; /* error code for overflow */
+ bool allow_expansion; /* if false, don't expand */
+ gs_ref_memory_t *memory; /* allocator for blocks */
+};
+#define public_st_ref_stack() /* in istack.c */\
+ gs_public_st_complex_only(st_ref_stack, ref_stack, "ref_stack",\
+ ref_stack_clear_marks, ref_stack_enum_ptrs, ref_stack_reloc_ptrs, 0)
+#define st_ref_stack_num_ptrs 1 /* current */
+
+/* ------ Procedural interface ------ */
+
+/* Initialize a stack. */
+void ref_stack_init(P6(ref_stack *, ref *, uint, uint, ref *,
+ gs_ref_memory_t *));
+
+/* Set the maximum number of elements allowed on a stack. */
+/* Note that the value is a long, not a uint or a ulong. */
+int ref_stack_set_max_count(P2(ref_stack *, long));
+
+/* Set the margin between the limit and the top of the stack. */
+/* Note that this may require allocating a block. */
+int ref_stack_set_margin(P2(ref_stack *, uint));
+
+/* Return the number of elements on a stack. */
+uint ref_stack_count(P1(const ref_stack *));
+
+#define ref_stack_count_inline(pstk)\
+ ((pstk)->p + 1 - (pstk)->bot + (pstk)->extension_used)
+
+/* Return the maximum number of elements allowed on a stack. */
+#define ref_stack_max_count(pstk) (uint)((pstk)->max_stack.value.intval)
+
+/* Return a pointer to a given element from the stack, counting from */
+/* 0 as the top element. If the index is out of range, return 0. */
+/* Note that the index is a long, not a uint or a ulong. */
+ref *ref_stack_index(P2(const ref_stack *, long));
+
+/* Count the number of elements down to and including the first mark. */
+/* If no mark is found, return 0. */
+uint ref_stack_counttomark(P1(const ref_stack *));
+
+/*
+ * Do the store check for storing 'count' elements of a stack, starting
+ * 'skip' elements below the top, into an array. Return 0 or e_invalidaccess.
+ */
+int ref_stack_store_check(P4(const ref_stack * pstack, ref * parray,
+ uint count, uint skip));
+
+/*
+ * Store 'count elements of a stack, starting 'skip' elements below the top,
+ * into an array, with or without store/undo checking.
+ * age=-1 for no check, 0 for old, 1 for new.
+ * May return e_rangecheck or e_invalidaccess.
+ */
+int ref_stack_store(P7(const ref_stack * pstack, ref * parray, uint count,
+ uint skip, int age, bool check, client_name_t cname));
+
+/* Pop the top N elements off a stack. */
+/* The number must not exceed the number of elements in use. */
+void ref_stack_pop(P2(ref_stack *, uint));
+
+#define ref_stack_clear(pstk) ref_stack_pop(pstk, ref_stack_count(pstk))
+#define ref_stack_pop_to(pstk, depth)\
+ ref_stack_pop(pstk, ref_stack_count(pstk) - (depth))
+
+/* Pop the top block off a stack. */
+/* May return underflow_error. */
+int ref_stack_pop_block(P1(ref_stack *));
+
+/* Extend a stack to recover from an overflow condition. */
+/* Uses the requested value to decide what to do. */
+/* May return overflow_error or e_VMerror. */
+int ref_stack_extend(P2(ref_stack *, uint));
+
+/* Push N empty slots onto a stack. These slots are not initialized; */
+/* the caller must immediately fill them. May return overflow_error */
+/* (if max_stack would be exceeded, or the stack has no allocator) */
+/* or e_VMerror. */
+int ref_stack_push(P2(ref_stack *, uint));
+
+/*
+ * Enumerate the blocks of a stack from top to bottom, as follows:
+
+ ref_stack_enum_t rsenum;
+
+ ref_stack_enum_begin(&rsenum, pstack);
+ do {
+ ... process rsenum.size refs starting at rsenum.ptr ...
+ } while (ref_stack_enum_next(&rsenum));
+
+ */
+typedef struct ref_stack_enum_s {
+ ref_stack_block *block;
+ ref *ptr;
+ uint size;
+} ref_stack_enum_t;
+void ref_stack_enum_begin(P2(ref_stack_enum_t *, const ref_stack *));
+bool ref_stack_enum_next(P1(ref_stack_enum_t *));
+
+/* Define a previous enumeration structure, for backward compatibility. */
+#define STACK_LOOP_BEGIN(pstack, ptrv, sizev)\
+{ ref_stack_enum_t enum_;\
+ ref_stack_enum_begin(&enum_, pstack);\
+ do {\
+ ref *ptrv = enum_.ptr;\
+ uint sizev = enum_.size;
+#define STACK_LOOP_END(ptrv, sizev)\
+ } while (ref_stack_enum_next(&enum_));\
+}
+
+/* Clean up a stack for garbage collection. */
+void ref_stack_cleanup(P1(ref_stack *));
+
+/*
+ * Free the entire contents of a stack, including the bottom block.
+ * The client must free the ref_stack itself. Note that after calling
+ * ref_stack_release, the stack is no longer usable.
+ */
+void ref_stack_release(P1(ref_stack *));
+
+/*
+ * Release a stack and then free the ref_stack object.
+ */
+void ref_stack_free(P3(ref_stack * pstack, gs_memory_t * mem,
+ client_name_t cname));
+
+#endif /* istack_INCLUDED */
diff --git a/pstoraster/istream.h b/pstoraster/istream.h
new file mode 100644
index 000000000..f1019f49b
--- /dev/null
+++ b/pstoraster/istream.h
@@ -0,0 +1,43 @@
+/* Copyright (C) 1994, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of GNU Ghostscript.
+
+ GNU Ghostscript is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
+ to anyone for the consequences of using it or for whether it serves any
+ particular purpose or works at all, unless he says so in writing. Refer
+ to the GNU General Public License for full details.
+
+ Everyone is granted permission to copy, modify and redistribute GNU
+ Ghostscript, but only under the conditions described in the GNU General
+ Public License. A copy of this license is supposed to have been given
+ to you along with GNU Ghostscript so you can know your rights and
+ responsibilities. It should be in a file named COPYING. Among other
+ things, the copyright notice and this notice must be preserved on all
+ copies.
+
+ Aladdin Enterprises 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 scommon.h, ostack.h */
+
+#ifndef istream_INCLUDED
+# define istream_INCLUDED
+
+/* Procedures exported by zfproc.c */
+ /* for zfilter.c - procedure stream initialization */
+int sread_proc(P2(ref *, stream **));
+int swrite_proc(P2(ref *, stream **));
+
+ /* for interp.c, zfileio.c, zpaint.c - handle a procedure */
+ /* callback or an interrupt */
+int s_handle_read_exception(P5(int, const ref *, const ref *, int,
+ int (*)(P1(os_ptr))));
+int s_handle_write_exception(P5(int, const ref *, const ref *, int,
+ int (*)(P1(os_ptr))));
+
+#endif /* istream_INCLUDED */
diff --git a/pstoraster/istruct.h b/pstoraster/istruct.h
new file mode 100644
index 000000000..082327028
--- /dev/null
+++ b/pstoraster/istruct.h
@@ -0,0 +1,98 @@
+/* Copyright (C) 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$ */
+/* Interpreter-level extension of gsstruct.h */
+
+#ifndef istruct_INCLUDED
+# define istruct_INCLUDED
+
+#include "gsstruct.h"
+
+/* ================ Refs ================ */
+
+/*
+ * Define the pointer type for refs. Note that if a structure contains refs,
+ * both its clear_marks and its reloc_ptrs procedure must unmark them,
+ * since the GC will never see the refs during the unmarking sweep.
+ */
+extern const gs_ptr_procs_t ptr_ref_procs;
+#define ptr_ref_type (&ptr_ref_procs)
+
+/* The structure type descriptor for (blocks of) refs. */
+/* This is defined in igc.c and exported for isave.c. */
+extern_st(st_refs);
+
+/*
+ * Extend the GC procedure vector to include refs.
+ */
+#define refs_proc_reloc(proc)\
+ void proc(P3(ref_packed *from, ref_packed *to, gc_state_t *gcst))
+typedef struct gc_procs_with_refs_s {
+ gc_procs_common;
+ /* Relocate a pointer to a ref[_packed]. */
+ ptr_proc_reloc((*reloc_ref_ptr), ref_packed);
+ /* Relocate a block of ref[_packed]s. */
+ refs_proc_reloc((*reloc_refs));
+} gc_procs_with_refs_t;
+
+#undef gc_proc
+#define gc_proc(gcst, proc) ((*(const gc_procs_with_refs_t **)(gcst))->proc)
+
+/*
+ * Define enumeration and relocation macros analogous to those for
+ * structures and strings. (We should go back and change the names of
+ * those macros to be consistent which these, which are better, but it's
+ * not worth the trouble.)
+ */
+#define ENUM_RETURN_REF(ptr)\
+ BEGIN *pep = (const void *)(ptr); return ptr_ref_type; END
+#define ENUM_RETURN_REF_MEMBER(typ, memb)\
+ ENUM_RETURN_REF(&((typ *)vptr)->memb)
+#define RELOC_REF_PTR_VAR(ptrvar)\
+ ptrvar = (*gc_proc(gcst, reloc_ref_ptr))((const void *)(ptrvar), gcst)
+#define RELOC_REF_PTR_MEMBER(typ, memb)\
+ RELOC_REF_PTR_VAR(((typ *)vptr)->memb)
+#define RELOC_REFS(from, upto)\
+ (*gc_proc(gcst, reloc_refs))((ref_packed *)(from), (ref_packed *)(upto), gcst)
+#define RELOC_REF_VAR(refvar)\
+ RELOC_REFS(&(refvar), &(refvar) + 1)
+
+/*
+ * Define an object allocated as a struct, but actually containing refs.
+ * Such objects are useful as the client_data of library structures
+ * (currently only gstates and fonts).
+ */
+struct_proc_clear_marks(ref_struct_clear_marks);
+struct_proc_enum_ptrs(ref_struct_enum_ptrs);
+struct_proc_reloc_ptrs(ref_struct_reloc_ptrs);
+#define gs__st_ref_struct(scope_st, stname, stype, sname)\
+ gs__st_complex_only(scope_st, stname, stype, sname, ref_struct_clear_marks,\
+ ref_struct_enum_ptrs, ref_struct_reloc_ptrs, 0)
+#define gs_public_st_ref_struct(stname, stype, sname)\
+ gs__st_ref_struct(public_st, stname, stype, sname)
+#define gs_private_st_ref_struct(stname, stype, sname)\
+ gs__st_ref_struct(private_st, stname, stype, sname)
+
+#endif /* istruct_INCLUDED */
diff --git a/pstoraster/iutil.c b/pstoraster/iutil.c
new file mode 100644
index 000000000..55d1fdaa1
--- /dev/null
+++ b/pstoraster/iutil.c
@@ -0,0 +1,676 @@
+/* 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$ */
+/* Utilities for Ghostscript interpreter */
+#include "math_.h" /* for fabs */
+#include "memory_.h"
+#include "string_.h"
+#include "ghost.h"
+#include "errors.h"
+#include "idict.h"
+#include "imemory.h"
+#include "iname.h"
+#include "ipacked.h" /* for array_get */
+#include "iutil.h" /* for checking prototypes */
+#include "ivmspace.h"
+#include "oper.h"
+#include "store.h"
+#include "gsccode.h" /* for gxfont.h */
+#include "gsmatrix.h"
+#include "gsutil.h"
+#include "gxfont.h"
+
+/* ------ Object utilities ------ */
+
+/* Define the table of ref type properties. */
+const byte ref_type_properties[] =
+{
+ ref_type_properties_data
+};
+
+/* Copy refs from one place to another. */
+int
+refcpy_to_old(ref * aref, uint index, const ref * from,
+ uint size, client_name_t cname)
+{
+ ref *to = aref->value.refs + index;
+ int code = refs_check_space(from, size, r_space(aref));
+
+ if (code < 0)
+ return code;
+ /* We have to worry about aliasing.... */
+ if (to <= from || from + size <= to)
+ while (size--)
+ ref_assign_old(aref, to, from, cname), to++, from++;
+ else
+ for (from += size, to += size; size--;)
+ from--, to--, ref_assign_old(aref, to, from, cname);
+ return 0;
+}
+void
+refcpy_to_new(ref * to, const ref * from, uint size)
+{
+ while (size--)
+ ref_assign_new(to, from), to++, from++;
+}
+
+/* Fill a new object with nulls. */
+void
+refset_null(ref * to, uint size)
+{
+ while (size--)
+ make_null_new(to), to++;
+}
+
+/* Compare two objects for equality. */
+bool
+obj_eq(const ref * pref1, const ref * pref2)
+{
+ ref nref;
+
+ if (r_type(pref1) != r_type(pref2)) {
+ /*
+ * Only a few cases need be considered here:
+ * integer/real (and vice versa), name/string (and vice versa),
+ * and extended operators.
+ */
+ switch (r_type(pref1)) {
+ case t_integer:
+ return (r_has_type(pref2, t_real) &&
+ pref2->value.realval == pref1->value.intval);
+ case t_real:
+ return (r_has_type(pref2, t_integer) &&
+ pref2->value.intval == pref1->value.realval);
+ case t_name:
+ if (!r_has_type(pref2, t_string))
+ return false;
+ name_string_ref(pref1, &nref);
+ pref1 = &nref;
+ break;
+ case t_string:
+ if (!r_has_type(pref2, t_name))
+ return false;
+ name_string_ref(pref2, &nref);
+ pref2 = &nref;
+ break;
+ default:
+ if (r_btype(pref1) != r_btype(pref2))
+ return false;
+ }
+ }
+ /*
+ * Now do a type-dependent comparison. This would be very simple if we
+ * always filled in all the bytes of a ref, but we currently don't.
+ */
+ switch (r_btype(pref1)) {
+ case t_array:
+ return (pref1->value.refs == pref2->value.refs &&
+ r_size(pref1) == r_size(pref2));
+ case t_mixedarray:
+ case t_shortarray:
+ return (pref1->value.packed == pref2->value.packed &&
+ r_size(pref1) == r_size(pref2));
+ case t_boolean:
+ return (pref1->value.boolval == pref2->value.boolval);
+ case t_dictionary:
+ return (pref1->value.pdict == pref2->value.pdict);
+ case t_file:
+ return (pref1->value.pfile == pref2->value.pfile &&
+ r_size(pref1) == r_size(pref2));
+ case t_integer:
+ return (pref1->value.intval == pref2->value.intval);
+ case t_mark:
+ case t_null:
+ return true;
+ case t_name:
+ return (pref1->value.pname == pref2->value.pname);
+ case t_oparray:
+ case t_operator:
+ return (op_index(pref1) == op_index(pref2));
+ case t_real:
+ return (pref1->value.realval == pref2->value.realval);
+ case t_save:
+ return (pref2->value.saveid == pref1->value.saveid);
+ case t_string:
+ return (!bytes_compare(pref1->value.bytes, r_size(pref1),
+ pref2->value.bytes, r_size(pref2)));
+ case t_device:
+ return (pref1->value.pdevice == pref2->value.pdevice);
+ case t_struct:
+ case t_astruct:
+ return (pref1->value.pstruct == pref2->value.pstruct);
+ case t_fontID:
+ { /*
+ * In the Adobe implementations, different scalings of a
+ * font have "equal" FIDs, so we do the same.
+ */
+ const gs_font *pfont1 = r_ptr(pref1, gs_font);
+ const gs_font *pfont2 = r_ptr(pref2, gs_font);
+
+ while (pfont1->base != pfont1)
+ pfont1 = pfont1->base;
+ while (pfont2->base != pfont2)
+ pfont2 = pfont2->base;
+ return (pfont1 == pfont2);
+ }
+ }
+ return false; /* shouldn't happen! */
+}
+
+/* Compare two objects for identity. */
+bool
+obj_ident_eq(const ref * pref1, const ref * pref2)
+{
+ if (r_type(pref1) != r_type(pref2))
+ return false;
+ if (r_has_type(pref1, t_string))
+ return (pref1->value.bytes == pref2->value.bytes &&
+ r_size(pref1) == r_size(pref2));
+ return obj_eq(pref1, pref2);
+}
+
+/*
+ * Create a printable representation of an object, a la cvs (full_print =
+ * false) or == (full_print = true). Return 0 if OK, <0 if the destination
+ * wasn't large enough or the object's contents weren't readable.
+ * If the object was a string or name, store a pointer to its characters
+ * even if it was too large.
+ */
+private void ensure_dot(P1(char *));
+int
+obj_cvp(const ref * op, byte * str, uint len, uint * prlen,
+ const byte ** pchars, bool full_print)
+{
+ if (full_print)
+ switch (r_btype(op)) {
+ case t_boolean:
+ case t_integer:
+ break;
+ case t_real:
+ /*
+ * To get fully accurate output results for IEEE single-
+ * precision floats (24 bits of mantissa), the ANSI
+ * %g default of 6 digits is not enough; 9 are needed.
+ * Unfortunately, using %.9g for floats (as opposed to
+ * doubles) produces unfortunate artifacts such as 0.01 5 mul
+ * printing as 0.049999997. Therefore, we print using %g,
+ * and if the result isn't accurate enough, print again
+ * using %.9g. Unfortunately, a few PostScript programs
+ * 'know' that the printed representation of floats fits
+ * into 6 digits (e.g., with cvs). We resolve this by letting
+ * cvs, cvrs, and = do what the Adobe interpreters appear
+ * to do (use %g), and only produce accurate output for ==,
+ * for which there is no analogue of cvs. What a hack!
+ */
+ if (!full_print)
+ break;
+ {
+ char buf[30]; /* big enough for any float or double */
+ float value = op->value.realval;
+ float scanned;
+ uint plen;
+
+ sprintf(buf, "%g", value);
+ sscanf(buf, "%f", &scanned);
+ if (scanned != value)
+ sprintf(buf, "%.9g", value);
+ ensure_dot(buf);
+ *prlen = plen = strlen(buf);
+ if (plen > len)
+ return_error(e_rangecheck);
+ memcpy(str, buf, plen);
+ return 0;
+ }
+ default:
+ return_error(e_typecheck);
+ }
+ return obj_cvs(op, str, len, prlen, pchars);
+}
+int
+obj_cvs(const ref * op, byte * str, uint len, uint * prlen,
+ const byte ** pchars)
+{
+ char buf[30]; /* big enough for any float or double */
+ const byte *pstr = (const byte *)buf;
+ uint plen;
+ ref nref;
+
+ switch (r_btype(op)) {
+ case t_boolean:
+ pstr = (const byte *)(op->value.boolval ? "true" : "false");
+ break;
+ case t_integer:
+ sprintf(buf, "%ld", op->value.intval);
+ break;
+ case t_name:
+ name_string_ref(op, &nref); /* name string */
+cvname: pstr = nref.value.bytes;
+ plen = r_size(&nref);
+ if (pchars != 0)
+ *pchars = pstr;
+ goto nl;
+ case t_oparray:
+ {
+ uint index = op_index(op);
+ const op_array_table *opt = op_index_op_array_table(index);
+
+ name_index_ref(opt->nx_table[index - opt->base_index], &nref);
+ }
+ name_string_ref(&nref, &nref);
+ goto cvname;
+ case t_operator:
+ {
+ /* Recover the name from the initialization table. */
+ uint index = op_index(op);
+
+ /*
+ * Check the validity of the index. (An out-of-bounds index
+ * is only possible when examining an invalid object using
+ * the debugger.)
+ */
+ if (index > 0 && index < op_def_count) {
+ pstr = (const byte *)(op_def_table[index]->oname + 1);
+ break;
+ }
+ }
+ /* Internal operator, no name. */
+ sprintf(buf, "@0x%lx", (ulong) op->value.opproc);
+ break;
+ case t_real:
+ sprintf(buf, "%g", op->value.realval);
+ ensure_dot(buf);
+ break;
+ case t_string:
+ check_read(*op);
+ pstr = op->value.bytes;
+ plen = r_size(op);
+ if (pchars != 0)
+ *pchars = pstr;
+ goto nl;
+ default:
+ pstr = (const byte *)"--nostringval--";
+ }
+ plen = strlen((const char *)pstr);
+nl: *prlen = plen;
+ if (plen > len)
+ return_error(e_rangecheck);
+ memcpy(str, pstr, plen);
+ return 0;
+}
+/*
+ * Make sure the converted form of a real number has a decimal point. This
+ * is needed for compatibility with Adobe (and other) interpreters.
+ */
+private void
+ensure_dot(char *buf)
+{
+ if (strchr(buf, '.') == NULL) {
+ char *ept = strchr(buf, 'e');
+
+ if (ept == NULL)
+ strcat(buf, ".0");
+ else {
+ /* Insert the .0 before the exponent. What a nuisance! */
+ char buf1[30];
+
+ strcpy(buf1, ept);
+ strcpy(ept, ".0");
+ strcat(buf, buf1);
+ }
+ }
+}
+
+/* Find the index of an operator that doesn't have one stored in it. */
+ushort
+op_find_index(const ref * pref /* t_operator */ )
+{
+ op_proc_p proc = real_opproc(pref);
+ const op_def *const *opp = op_def_table;
+ const op_def *const *opend = opp + op_def_count;
+
+ for (; ++opp < opend;) {
+ if ((*opp)->proc == proc)
+ return opp - op_def_table;
+ }
+ /* Lookup failed! This isn't possible.... */
+ return 0;
+}
+
+/*
+ * Convert an operator index to an operator or oparray ref.
+ * This is only used for debugging and for 'get' from packed arrays,
+ * so it doesn't have to be very fast.
+ */
+void
+op_index_ref(uint index, ref * pref)
+{
+ const op_array_table *opt;
+
+ if (op_index_is_operator(index)) {
+ make_oper(pref, index, op_index_proc(index));
+ return;
+ }
+ opt = op_index_op_array_table(index);
+ make_tasv(pref, t_oparray, opt->attrs, index,
+ const_refs, (opt->table.value.const_refs
+ + index - opt->base_index));
+}
+
+/* Get an element from an array of some kind. */
+/* This is also used to index into Encoding vectors, */
+/* the error name vector, etc. */
+int
+array_get(const ref * aref, long index_long, ref * pref)
+{
+ if ((ulong)index_long >= r_size(aref))
+ return_error(e_rangecheck);
+ switch (r_type(aref)) {
+ case t_array:
+ {
+ const ref *pvalue = aref->value.refs + index_long;
+
+ ref_assign(pref, pvalue);
+ }
+ break;
+ case t_mixedarray:
+ {
+ const ref_packed *packed = aref->value.packed;
+ uint index = (uint)index_long;
+
+ for (; index--;)
+ packed = packed_next(packed);
+ packed_get(packed, pref);
+ }
+ break;
+ case t_shortarray:
+ {
+ const ref_packed *packed = aref->value.packed + index_long;
+
+ packed_get(packed, pref);
+ }
+ break;
+ default:
+ return_error(e_typecheck);
+ }
+ return 0;
+}
+
+/* Get an element from a packed array. */
+/* (This works for ordinary arrays too.) */
+/* Source and destination are allowed to overlap if the source is packed, */
+/* or if they are identical. */
+void
+packed_get(const ref_packed * packed, ref * pref)
+{
+ const ref_packed elt = *packed;
+ uint value = elt & packed_value_mask;
+
+ switch (elt >> r_packed_type_shift) {
+ default: /* (shouldn't happen) */
+ make_null(pref);
+ break;
+ case pt_executable_operator:
+ op_index_ref(value, pref);
+ break;
+ case pt_integer:
+ make_int(pref, (int)value + packed_min_intval);
+ break;
+ case pt_literal_name:
+ name_index_ref(value, pref);
+ break;
+ case pt_executable_name:
+ name_index_ref(value, pref);
+ r_set_attrs(pref, a_executable);
+ break;
+ case pt_full_ref:
+ case pt_full_ref + 1:
+ ref_assign(pref, (const ref *)packed);
+ }
+}
+
+/* Check to make sure an interval contains no object references */
+/* to a space younger than a given one. */
+/* Return 0 or e_invalidaccess. */
+int
+refs_check_space(const ref * bot, uint size, uint space)
+{
+ for (; size--; bot++)
+ store_check_space(space, bot);
+ return 0;
+}
+
+/* ------ String utilities ------ */
+
+/* Convert a C string to a Ghostscript string */
+int
+string_to_ref(const char *cstr, ref * pref, gs_ref_memory_t * mem,
+ client_name_t cname)
+{
+ uint size = strlen(cstr);
+ int code = gs_alloc_string_ref(mem, pref, a_all, size, cname);
+
+ if (code < 0)
+ return code;
+ memcpy(pref->value.bytes, cstr, size);
+ return 0;
+}
+
+/* Convert a Ghostscript string to a C string. */
+/* Return 0 iff the buffer can't be allocated. */
+char *
+ref_to_string(const ref * pref, gs_memory_t * mem, client_name_t cname)
+{
+ uint size = r_size(pref);
+ char *str = (char *)gs_alloc_string(mem, size + 1, cname);
+
+ if (str == 0)
+ return 0;
+ memcpy(str, (const char *)pref->value.bytes, size);
+ str[size] = 0;
+ return str;
+}
+
+/* ------ Operand utilities ------ */
+
+/* Get N numeric operands from the stack or an array. */
+/* Return a bit-mask indicating which ones are integers, */
+/* or a (negative) error indication. */
+/* The 1-bit in the bit-mask refers to the first operand. */
+/* Store float versions of the operands at pval. */
+/* The stack underflow check (check for t__invalid) is harmless */
+/* if the operands come from somewhere other than the stack. */
+int
+num_params(const ref * op, int count, double *pval)
+{
+ int mask = 0;
+
+ pval += count;
+ while (--count >= 0) {
+ mask <<= 1;
+ switch (r_type(op)) {
+ case t_real:
+ *--pval = op->value.realval;
+ break;
+ case t_integer:
+ *--pval = op->value.intval;
+ mask++;
+ break;
+ case t__invalid:
+ return_error(e_stackunderflow);
+ default:
+ return_error(e_typecheck);
+ }
+ op--;
+ }
+ /* If count is very large, mask might overflow. */
+ /* In this case we clearly don't care about the value of mask. */
+ return (mask < 0 ? 0 : mask);
+}
+/* float_params doesn't bother to keep track of the mask. */
+int
+float_params(const ref * op, int count, float *pval)
+{
+ for (pval += count; --count >= 0; --op)
+ switch (r_type(op)) {
+ case t_real:
+ *--pval = op->value.realval;
+ break;
+ case t_integer:
+ *--pval = op->value.intval;
+ break;
+ case t__invalid:
+ return_error(e_stackunderflow);
+ default:
+ return_error(e_typecheck);
+ }
+ return 0;
+}
+
+/* Get a single real parameter. */
+/* The only possible error is e_typecheck. */
+/* If an error is returned, the return value is not updated. */
+int
+real_param(const ref * op, double *pparam)
+{
+ switch (r_type(op)) {
+ case t_integer:
+ *pparam = op->value.intval;
+ break;
+ case t_real:
+ *pparam = op->value.realval;
+ break;
+ default:
+ return_error(e_typecheck);
+ }
+ return 0;
+}
+int
+float_param(const ref * op, float *pparam)
+{
+ double dval;
+ int code = real_param(op, &dval);
+
+ if (code >= 0)
+ *pparam = (float)dval; /* can't overflow */
+ return code;
+}
+
+/* Get an integer parameter in a given range. */
+int
+int_param(const ref * op, int max_value, int *pparam)
+{
+ check_int_leu(*op, max_value);
+ *pparam = (int)op->value.intval;
+ return 0;
+}
+
+/* Make real values on the operand stack. */
+int
+make_reals(ref * op, const double *pval, int count)
+{
+ /* This should return e_limitcheck if any real is too large */
+ /* to fit into a float on the stack. */
+ for (; count--; op++, pval++)
+ make_real(op, *pval);
+ return 0;
+}
+int
+make_floats(ref * op, const float *pval, int count)
+{
+ /* This should return e_undefinedresult for infinities. */
+ for (; count--; op++, pval++)
+ make_real(op, *pval);
+ return 0;
+}
+
+/* Compute the error code when check_proc fails. */
+/* Note that the client, not this procedure, uses return_error. */
+/* The stack underflow check is harmless in the off-stack case. */
+int
+check_proc_failed(const ref * pref)
+{
+ return (r_is_array(pref) ? e_invalidaccess :
+ r_has_type(pref, t__invalid) ? e_stackunderflow :
+ e_typecheck);
+}
+
+/* Compute the error code when a type check on the stack fails. */
+/* Note that the client, not this procedure, uses return_error. */
+int
+check_type_failed(const ref * op)
+{
+ return (r_has_type(op, t__invalid) ? e_stackunderflow : e_typecheck);
+}
+
+/* ------ Matrix utilities ------ */
+
+/* Read a matrix operand. */
+/* Return 0 if OK, error code if not. */
+int
+read_matrix(const ref * op, gs_matrix * pmat)
+{
+ int code;
+ ref values[6];
+ const ref *pvalues;
+
+ if (r_has_type(op, t_array))
+ pvalues = op->value.refs;
+ else {
+ int i;
+
+ for (i = 0; i < 6; ++i) {
+ code = array_get(op, (long)i, &values[i]);
+ if (code < 0)
+ return code;
+ }
+ pvalues = values;
+ }
+ check_read(*op);
+ if (r_size(op) != 6)
+ return_error(e_rangecheck);
+ code = float_params(pvalues + 5, 6, (float *)pmat);
+ return (code < 0 ? code : 0);
+}
+
+/* Write a matrix operand. */
+/* Return 0 if OK, error code if not. */
+int
+write_matrix(ref * op, const gs_matrix * pmat)
+{
+ ref *aptr;
+ const float *pel;
+ int i;
+
+ check_write_type(*op, t_array);
+ if (r_size(op) != 6)
+ return_error(e_rangecheck);
+ aptr = op->value.refs;
+ pel = (const float *)pmat;
+ for (i = 5; i >= 0; i--, aptr++, pel++) {
+ ref_save(op, aptr, "write_matrix");
+ make_real_new(aptr, *pel);
+ }
+ return 0;
+}
diff --git a/pstoraster/iutil.h b/pstoraster/iutil.h
new file mode 100644
index 000000000..ea0489a29
--- /dev/null
+++ b/pstoraster/iutil.h
@@ -0,0 +1,121 @@
+/* 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$ */
+/* Requires imemory.h, ostack.h */
+
+#ifndef iutil_INCLUDED
+# define iutil_INCLUDED
+
+/* ------ Object utilities ------ */
+
+/* Copy refs from one place to another. */
+/* (If we are copying to the stack, we can just use memcpy.) */
+void refcpy_to_new(P3(ref * to, const ref * from, uint size));
+int refcpy_to_old(P5(ref * aref, uint index, const ref * from, uint size,
+ client_name_t cname));
+
+/* Fill an array with nulls. */
+void refset_null(P2(ref * to, uint size));
+
+/* Compare two objects for equality. */
+bool obj_eq(P2(const ref *, const ref *));
+
+/* Compare two objects for identity. */
+/* (This is not a standard PostScript concept.) */
+bool obj_ident_eq(P2(const ref *, const ref *));
+
+/*
+ * Create a printable representation of an object, a la cvs (full_print =
+ * false) or == (full_print = true). Return 0 if OK, <0 if the destination
+ * wasn't large enough or the object's contents weren't readable.
+ * If the object was a string or name, store a pointer to its characters
+ * even if it was too large. Note that if full_print is true, the only
+ * allowed types are boolean, integer, and real.
+ */
+int obj_cvp(P6(const ref * op, byte * str, uint len, uint * prlen,
+ const byte ** pchars, bool full_print));
+/* obj_cvs is equivalent to obj_cvp with full_print = false. */
+int obj_cvs(P5(const ref * op, byte * str, uint len, uint * prlen,
+ const byte ** pchars));
+
+/* Get an element from an array (packed or not). */
+int array_get(P3(const ref *, long, ref *));
+
+/* Get an element from a packed array. */
+/* (This works for ordinary arrays too.) */
+/* Source and destination are allowed to overlap if the source is packed, */
+/* or if they are identical. */
+void packed_get(P2(const ref_packed *, ref *));
+
+/* Check to make sure an interval contains no object references */
+/* to a space younger than a given one. */
+/* Return 0 or e_invalidaccess. */
+int refs_check_space(P3(const ref * refs, uint size, uint space));
+
+/* ------ String utilities ------ */
+
+/* Convert a C string to a string object. */
+int string_to_ref(P4(const char *, ref *, gs_ref_memory_t *, client_name_t));
+
+/* Convert a string object to a C string. */
+/* Return 0 iff the buffer can't be allocated. */
+char *ref_to_string(P3(const ref *, gs_memory_t *, client_name_t));
+
+/* ------ Operand utilities ------ */
+
+/* Get N numeric operands from the stack or an array. */
+int num_params(P3(const ref *, int, double *));
+
+/* float_params can lose accuracy for large integers. */
+int float_params(P3(const ref *, int, float *));
+
+/* Get a single real parameter. */
+/* The only possible error is e_typecheck. */
+int real_param(P2(const ref *, double *));
+
+/* float_param can lose accuracy for large integers. */
+int float_param(P2(const ref *, float *));
+
+/* Get an integer parameter in a given range. */
+int int_param(P3(const ref *, int, int *));
+
+/* Make real values on the stack. */
+/* Return e_limitcheck for infinities or double->float overflow. */
+int make_reals(P3(ref *, const double *, int));
+int make_floats(P3(ref *, const float *, int));
+
+/* Define the gs_matrix type if necessary. */
+#ifndef gs_matrix_DEFINED
+# define gs_matrix_DEFINED
+typedef struct gs_matrix_s gs_matrix;
+#endif
+
+/* Read a matrix operand. */
+int read_matrix(P2(const ref *, gs_matrix *));
+
+/* Write a matrix operand. */
+int write_matrix(P2(ref *, const gs_matrix *));
+
+#endif /* iutil_INCLUDED */
diff --git a/pstoraster/iutil2.c b/pstoraster/iutil2.c
new file mode 100644
index 000000000..c49022510
--- /dev/null
+++ b/pstoraster/iutil2.c
@@ -0,0 +1,154 @@
+/* Copyright (C) 1993, 1994, 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$ */
+/* Level 2 utilities for Ghostscript interpreter */
+#include "memory_.h"
+#include "string_.h"
+#include "ghost.h"
+#include "errors.h"
+#include "opcheck.h"
+#include "gsparam.h"
+#include "gsutil.h" /* bytes_compare prototype */
+#include "idict.h"
+#include "imemory.h" /* for iutil.h */
+#include "iutil.h"
+#include "iutil2.h"
+
+/* ------ Password utilities ------ */
+
+/* Read a password from a parameter list. */
+/* Return 0 if present, 1 if absent, or an error code. */
+int
+param_read_password(gs_param_list * plist, const char *kstr, password * ppass)
+{
+ gs_param_string ps;
+ long ipass;
+ int code;
+
+ ps.data = (const byte *)ppass->data, ps.size = ppass->size,
+ ps.persistent = false;
+ code = param_read_string(plist, kstr, &ps);
+ switch (code) {
+ case 0: /* OK */
+ if (ps.size > MAX_PASSWORD)
+ return_error(e_limitcheck);
+ /* Copy the data back. */
+ memcpy(ppass->data, ps.data, ps.size);
+ ppass->size = ps.size;
+ return 0;
+ case 1: /* key is missing */
+ return 1;
+ }
+ /* We might have gotten a typecheck because */
+ /* the supplied password was an integer. */
+ if (code != e_typecheck)
+ return code;
+ code = param_read_long(plist, kstr, &ipass);
+ if (code != 0) /* error or missing */
+ return code;
+ sprintf((char *)ppass->data, "%ld", ipass);
+ ppass->size = strlen((char *)ppass->data);
+ return 0;
+}
+/* Write a password to a parameter list. */
+int
+param_write_password(gs_param_list * plist, const char *kstr,
+ const password * ppass)
+{
+ gs_param_string ps;
+
+ ps.data = (const byte *)ppass->data, ps.size = ppass->size,
+ ps.persistent = false;
+ if (ps.size > MAX_PASSWORD)
+ return_error(e_limitcheck);
+ return param_write_string(plist, kstr, &ps);
+}
+
+/* Check a password from a parameter list. */
+/* Return 0 if OK, 1 if not OK, or an error code. */
+int
+param_check_password(gs_param_list * plist, const password * ppass)
+{
+ if (ppass->size != 0) {
+ password pass;
+ int code = param_read_password(plist, "Password", &pass);
+
+ if (code)
+ return code;
+ if (pass.size != ppass->size ||
+ bytes_compare(&pass.data[0], pass.size,
+ &ppass->data[0],
+ ppass->size) != 0
+ )
+ return 1;
+ }
+ return 0;
+}
+
+/* Read a password from, or write a password into, a dictionary */
+/* (presumably systemdict). */
+private int
+dict_find_password(ref ** ppvalue, const ref * pdref, const char *kstr)
+{
+ ref *pvalue;
+
+ if (dict_find_string(pdref, kstr, &pvalue) <= 0)
+ return_error(e_undefined);
+ if (!r_has_type(pvalue, t_string) ||
+ r_has_attrs(pvalue, a_read) ||
+ pvalue->value.const_bytes[0] >= r_size(pvalue)
+ )
+ return_error(e_rangecheck);
+ *ppvalue = pvalue;
+ return 0;
+}
+int
+dict_read_password(password * ppass, const ref * pdref, const char *pkey)
+{
+ ref *pvalue;
+ int code = dict_find_password(&pvalue, pdref, pkey);
+
+ if (code < 0)
+ return code;
+ if (pvalue->value.const_bytes[0] > MAX_PASSWORD)
+ return_error(e_rangecheck); /* limitcheck? */
+ memcpy(ppass->data, pvalue->value.const_bytes + 1,
+ (ppass->size = pvalue->value.const_bytes[0]));
+ return 0;
+}
+int
+dict_write_password(const password * ppass, ref * pdref, const char *pkey)
+{
+ ref *pvalue;
+ int code = dict_find_password(&pvalue, pdref, pkey);
+
+ if (code < 0)
+ return code;
+ if (ppass->size >= r_size(pvalue))
+ return_error(e_rangecheck);
+ memcpy(pvalue->value.bytes + 1, ppass->data,
+ (pvalue->value.bytes[0] = ppass->size));
+ return 0;
+}
diff --git a/pstoraster/iutil2.h b/pstoraster/iutil2.h
new file mode 100644
index 000000000..ff76d87f6
--- /dev/null
+++ b/pstoraster/iutil2.h
@@ -0,0 +1,56 @@
+/* Copyright (C) 1993, 1994, 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 procedures in iutil2.c */
+
+#ifndef iutil2_INCLUDED
+# define iutil2_INCLUDED
+
+/* ------ Password utilities ------ */
+
+/* Define the password structure. */
+/* NOTE: MAX_PASSWORD must match the initial password lengths in gs_lev2.ps. */
+#define MAX_PASSWORD 64 /* must be at least 11 */
+typedef struct password_s {
+ uint size;
+ byte data[MAX_PASSWORD];
+} password;
+
+# define NULL_PASSWORD {0, {0}}
+
+/* Transmit a password to or from a parameter list. */
+int param_read_password(P3(gs_param_list *, const char *, password *));
+int param_write_password(P3(gs_param_list *, const char *, const password *));
+
+/* Check a password from a parameter list. */
+/* Return 0 if OK, 1 if not OK, or an error code. */
+int param_check_password(P2(gs_param_list *, const password *));
+
+/* Read a password from, or write a password into, a dictionary */
+/* (presumably systemdict). */
+int dict_read_password(P3(password *, const ref *, const char *));
+int dict_write_password(P3(const password *, ref *, const char *));
+
+#endif /* iutil2_INCLUDED */
diff --git a/pstoraster/ivmspace.h b/pstoraster/ivmspace.h
new file mode 100644
index 000000000..dd51d91e1
--- /dev/null
+++ b/pstoraster/ivmspace.h
@@ -0,0 +1,111 @@
+/* Copyright (C) 1992, 1993, 1994, 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$ */
+/* Local/global space management */
+/* Requires iref.h */
+
+#ifndef ivmspace_INCLUDED
+# define ivmspace_INCLUDED
+
+#include "gsgc.h"
+
+/*
+ * r_space_bits and r_space_shift, which define the bits in a ref
+ * that carry VM space information, are defined in iref.h.
+ * r_space_bits must be at least 2.
+ */
+#define a_space (((1 << r_space_bits) - 1) << r_space_shift)
+/*
+ * The i_vm_xxx values are defined in gsgc.h.
+ */
+typedef enum {
+ avm_foreign = (i_vm_foreign << r_space_shift),
+ avm_system = (i_vm_system << r_space_shift),
+ avm_global = (i_vm_global << r_space_shift),
+ avm_local = (i_vm_local << r_space_shift),
+ avm_max = avm_local
+} avm_space;
+
+#define r_space(rp) (avm_space)(r_type_attrs(rp) & a_space)
+#define r_space_index(rp) ((int)r_space(rp) >> r_space_shift)
+#define r_set_space(rp,space) r_store_attrs(rp, a_space, (uint)space)
+
+/*
+ * According to the PostScript language specification, attempting to store
+ * a reference to a local object into a global object must produce an
+ * invalidaccess error. However, systemdict must be able to refer to
+ * a number of local dictionaries such as userdict and errordict.
+ * Therefore, we implement a special hack in 'def' that allows such stores
+ * if the dictionary being stored into is systemdict (which is normally
+ * only writable during initialization) or a dictionary that appears
+ * in systemdict (such as level2dict), and the current save level is zero
+ * (to guarantee that we can't get dangling pointers).
+ * We could allow this for any global dictionary, except that the garbage
+ * collector must treat any such dictionaries as roots when collecting
+ * local VM without collecting global VM.
+ * We make a similar exception for .makeglobaloperator; this requires
+ * treating the operator table as a GC root as well.
+ *
+ * We extend the local-into-global store check because we have four VM
+ * spaces (local, global, system, and foreign), and we allow PostScript
+ * programs to create objects in any of the first three. If we define
+ * the "generation" of an object as foreign = 0, system = 1, global = 2,
+ * and local = 3, then a store is legal iff the generation of the object
+ * into which a pointer is being stored is greater than or equal to
+ * the generation of the object into which the store is occurring.
+ *
+ * We must check for local-into-global stores in three categories of places:
+ *
+ * - The scanner, when it encounters a //name inside {}.
+ *
+ * - All operators that allocate ref-containing objects and also
+ * store into them:
+ * packedarray gstate makepattern?
+ * makefont scalefont definefont filter
+ *
+ * - All operators that store refs into existing objects
+ * ("operators" marked with * are actually PostScript procedures):
+ * put(array) putinterval(array) astore copy(to array)
+ * def store* put(dict) copy(dict)
+ * dictstack execstack .make(global)operator
+ * currentgstate defineusername
+ */
+
+/* Test whether an object is in local space, */
+/* which implies that we need not check when storing into it. */
+#define r_is_local(rp) (r_space(rp) == avm_local)
+/* Test whether an object is foreign, i.e., outside known space. */
+#define r_is_foreign(rp) (r_space(rp) == avm_foreign)
+/* Check whether a store is allowed. */
+#define store_check_space(destspace,rpnew)\
+ if ( r_space(rpnew) > (destspace) )\
+ return_error(e_invalidaccess)
+#define store_check_dest(rpdest,rpnew)\
+ store_check_space(r_space(rpdest), rpnew)
+/* BACKWARD COMPATIBILITY (not used by any Ghostscript code per se) */
+#define check_store_space(rdest,rnewcont)\
+ store_check_dest(&(rdest),&(rnewcont))
+
+#endif /* ivmspace_INCLUDED */
diff --git a/pstoraster/main.h b/pstoraster/main.h
new file mode 100644
index 000000000..6b8769020
--- /dev/null
+++ b/pstoraster/main.h
@@ -0,0 +1,101 @@
+/* Copyright (C) 1992, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of GNU Ghostscript.
+
+ GNU Ghostscript is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
+ to anyone for the consequences of using it or for whether it serves any
+ particular purpose or works at all, unless he says so in writing. Refer
+ to the GNU General Public License for full details.
+
+ Everyone is granted permission to copy, modify and redistribute GNU
+ Ghostscript, but only under the conditions described in the GNU General
+ Public License. A copy of this license is supposed to have been given
+ to you along with GNU Ghostscript so you can know your rights and
+ responsibilities. It should be in a file named COPYING. Among other
+ things, the copyright notice and this notice must be preserved on all
+ copies.
+
+ Aladdin Enterprises 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$ */
+/* Backward-compatible interface to gsmain.c */
+
+#ifndef main_INCLUDED
+# define main_INCLUDED
+
+#include "imain.h"
+#include "iminst.h"
+
+/*
+ * This file adds to imain.h some backward-compatible procedures and
+ * data elements that assume there is only a single instance of
+ * the interpreter.
+ */
+
+/* ================ Data elements ================ */
+
+/* Clients should never access these directly. */
+
+#define gs_user_errors (gs_main_instance_default()->user_errors)
+#define gs_lib_path (gs_main_instance_default()->lib_path)
+/* gs_lib_paths removed in release 3.65 */
+/* gs_lib_env_path removed in release 3.65 */
+
+/* ================ Exported procedures from gsmain.c ================ */
+
+/* ---------------- Initialization ---------------- */
+
+#define gs_init0(in, out, err, mlp)\
+ gs_main_init0(gs_main_instance_default(), in, out, err, mlp)
+
+#define gs_init1()\
+ gs_main_init1(gs_main_instance_default())
+
+#define gs_init2()\
+ gs_main_init2(gs_main_instance_default())
+
+#define gs_add_lib_path(path)\
+ gs_main_add_lib_path(gs_main_instance_default(), path)
+
+#define gs_set_lib_paths()\
+ gs_main_set_lib_paths(gs_main_instance_default())
+
+#define gs_lib_open(fname, pfile)\
+ gs_main_lib_open(gs_main_instance_default(), fname, pfile)
+
+/* ---------------- Execution ---------------- */
+
+#define gs_run_file(fn, ue, pec, peo)\
+ gs_main_run_file(gs_main_instance_default(), fn, ue, pec, peo)
+
+#define gs_run_string(str, ue, pec, peo)\
+ gs_main_run_string(gs_main_instance_default(), str, ue, pec, peo)
+
+#define gs_run_string_with_length(str, len, ue, pec, peo)\
+ gs_main_run_string_with_length(gs_main_instance_default(),\
+ str, len, ue, pec, peo)
+
+#define gs_run_file_open(fn, pfref)\
+ gs_main_run_file_open(gs_main_instance_default(), fn, pfref)
+
+#define gs_run_string_begin(ue, pec, peo)\
+ gs_main_run_string_begin(gs_main_instance_default(), ue, pec, peo)
+
+#define gs_run_string_continue(str, len, ue, pec, peo)\
+ gs_main_run_string_continue(gs_main_instance_default(),\
+ str, len, ue, pec, peo)
+
+#define gs_run_string_end(ue, pec, peo)\
+ gs_main_run_string_end(gs_main_instance_default(), ue, pec, peo)
+
+/* ---------------- Termination ---------------- */
+
+#define gs_finit(status, code)\
+ gs_main_finit(gs_main_instance_default(), status, code)
+
+#endif /* main_INCLUDED */
diff --git a/pstoraster/malloc_.h b/pstoraster/malloc_.h
new file mode 100644
index 000000000..cbd6f7d34
--- /dev/null
+++ b/pstoraster/malloc_.h
@@ -0,0 +1,59 @@
+/* Copyright (C) 1989, 1992, 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$ */
+/* Generic substitute for Unix malloc.h */
+
+#ifndef malloc__INCLUDED
+# define malloc__INCLUDED
+
+/* We must include std.h before any file that includes sys/types.h. */
+#include "std.h"
+
+#ifdef __TURBOC__
+# include <alloc.h>
+#else
+# if defined(BSD4_2) || defined(apollo) || defined(vax) || defined(sequent) || defined(UTEK)
+# if defined(_POSIX_SOURCE) || (defined(__STDC__) && (!defined(sun) || defined(__svr4__))) /* >>> */
+# include <stdlib.h>
+# else /* Ancient breakage */
+extern char *malloc();
+extern void free();
+
+# endif
+# else
+# if defined(_HPUX_SOURCE) || defined(__CONVEX__) || defined(__convex__) || defined(__OSF__) || defined(__386BSD__) || defined(_POSIX_SOURCE) || defined(__STDC__) || defined(VMS)
+# include <stdlib.h>
+# else
+# include <malloc.h>
+# endif /* !_HPUX_SOURCE, ... */
+# endif /* !BSD4_2, ... */
+#endif /* !__TURBOC__ */
+
+/* (At least some versions of) Linux don't have a working realloc.... */
+/* MRS - in order to make sure memory is initialized, always use gs_realloc() */
+#define malloc__need_realloc
+void *gs_realloc(P3(void *, size_t, size_t));
+
+#endif /* malloc__INCLUDED */
diff --git a/pstoraster/math_.h b/pstoraster/math_.h
new file mode 100644
index 000000000..e04e3d4d2
--- /dev/null
+++ b/pstoraster/math_.h
@@ -0,0 +1,97 @@
+/* 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$ */
+/* Generic substitute for math.h */
+
+#ifndef math__INCLUDED
+# define math__INCLUDED
+
+/* We must include std.h before any file that includes sys/types.h. */
+#include "std.h"
+
+#if defined(VMS) && defined(__GNUC__)
+/* DEC VAX/VMS C comes with a math.h file, but GNU VAX/VMS C does not. */
+# include "vmsmath.h"
+#else
+# include <math.h>
+#endif
+
+/* math.h is different for Turbo and Unix.... */
+#ifndef M_PI
+# ifdef PI
+# define M_PI PI
+# else
+# define M_PI 3.14159265358979324
+# endif
+#endif
+
+/* Factors for converting between degrees and radians */
+#define degrees_to_radians (M_PI / 180.0)
+#define radians_to_degrees (180.0 / M_PI)
+
+/*
+ * Define the maximum value of a single-precision float.
+ * This doesn't seem to be defined in any standard place,
+ * and we need an exact value for it.
+ */
+#undef MAX_FLOAT /* just in case */
+#if defined(vax) || defined(VAX) || defined(__vax) || defined(__VAX)
+/* Maximum exponent is +127, 23 bits of fraction. */
+# define MAX_FLOAT\
+ ((0x800000 - 1.0) * 0x1000000 * 0x1000000 * 0x10000000 * 0x10000000)
+#else
+/* IEEE, maximum exponent is +127, 23 bits of fraction + an implied '1'. */
+# define MAX_FLOAT\
+ ((0x1000000 - 1.0) * 0x1000000 * 0x1000000 * 0x10000000 * 0x10000000)
+#endif
+
+/* Define the hypot procedure on those few systems that don't provide it. */
+#ifdef _IBMR2
+/* The RS/6000 has hypot, but math.h doesn't declare it! */
+extern double hypot(double, double);
+
+#else
+# if !defined(__TURBOC__) && !defined(BSD4_2) && !defined(VMS)
+# define hypot(x,y) sqrt((x)*(x)+(y)*(y))
+# endif
+#endif
+
+#ifdef OSK
+/* OSK has atan2 and ldexp, but math.h doesn't declare them! */
+extern double atan2(), ldexp();
+
+#endif
+
+#ifdef DEBUG
+
+/* Intercept calls on sqrt for debugging. */
+extern double gs_sqrt(P3(double, const char *, int));
+
+#undef sqrt
+#define sqrt(x) gs_sqrt(x, __FILE__, __LINE__)
+
+#endif /* DEBUG */
+
+#endif /* math__INCLUDED */
diff --git a/pstoraster/memory_.h b/pstoraster/memory_.h
new file mode 100644
index 000000000..27e0da922
--- /dev/null
+++ b/pstoraster/memory_.h
@@ -0,0 +1,107 @@
+/* Copyright (C) 1989, 1992, 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$ */
+/* Generic substitute for Unix memory.h */
+
+#ifndef memory__INCLUDED
+# define memory__INCLUDED
+
+/* We must include std.h before any file that includes sys/types.h. */
+#include "std.h"
+
+/******
+ ****** Note: the System V bcmp routine only returns zero or non-zero,
+ ****** unlike memcmp which returns -1, 0, or 1.
+ ******/
+
+#ifdef __TURBOC__
+/* Define inline functions */
+# ifdef __WIN32__
+# define memcmp_inline(b1,b2,len) memcmp(b1,b2,len)
+# else
+# define memcmp_inline(b1,b2,len) __memcmp__(b1,b2,len)
+# endif
+/*
+ * The Turbo C implementation of memset swaps the arguments and calls
+ * the non-standard routine setmem. We may as well do it in advance.
+ */
+# undef memset /* just in case */
+# include <mem.h>
+# ifndef memset /* Borland C++ can inline this */
+# define memset(dest,chr,cnt) setmem(dest,cnt,chr)
+# endif
+#else
+ /* Not Turbo C, no inline functions */
+# define memcmp_inline(b1,b2,len) memcmp(b1,b2,len)
+ /*
+ * Apparently the newer VMS compilers include prototypes
+ * for the mem... routines in <string.h>. Unfortunately,
+ * gcc lies on Sun systems: it defines __STDC__ even if
+ * the header files in /usr/include are broken.
+ * However, Solaris systems, which define __svr4__, do have
+ * correct header files.
+ */
+ /*
+ * The exceptions vastly outnumber the BSD4_2 "rule":
+ * these tests should be the other way around....
+ */
+# if defined(VMS) || defined(_POSIX_SOURCE) || (defined(__STDC__) && (!defined(sun) || defined(__svr4__))) || defined(_HPUX_SOURCE) || defined(__WATCOMC__) || defined(THINK_C) || defined(bsdi) || defined(__FreeBSD) || (defined(_MSC_VER) && _MSC_VER >= 1000)
+# include <string.h>
+# else
+# if defined(BSD4_2) || defined(UTEK)
+extern bcopy(), bcmp(), bzero();
+
+# define memcpy(dest,src,len) bcopy(src,dest,len)
+# define memcmp(b1,b2,len) bcmp(b1,b2,len)
+ /* Define our own versions of missing routines (in gsmisc.c). */
+# define memory__need_memmove
+# define memmove(dest,src,len) gs_memmove(dest,src,len)
+# include <sys/types.h> /* for size_t */
+void *gs_memmove(P3(void *, const void *, size_t));
+
+# define memory__need_memset
+# define memset(dest,ch,len) gs_memset(dest,ch,len)
+void *gs_memset(P3(void *, int, size_t));
+
+# if defined(UTEK)
+# define memory__need_memchr
+# define memchr(ptr,ch,len) gs_memchr(ptr,ch,len)
+const char *gs_memchr(P3(const void *, int, size_t));
+
+# endif /* UTEK */
+# else
+# include <memory.h>
+# if defined(__SVR3) || defined(sun) /* Not sure this is right.... */
+# define memory__need_memmove
+# define memmove(dest,src,len) gs_memmove(dest,src,len)
+# include <sys/types.h> /* for size_t */
+void *gs_memmove(P3(void *, const void *, size_t));
+
+# endif /* __SVR3 or sun */
+# endif /* BSD4_2 or UTEK */
+# endif /* VMS, POSIX, ... */
+#endif /* !__TURBOC__ */
+
+#endif /* memory__INCLUDED */
diff --git a/pstoraster/opcheck.h b/pstoraster/opcheck.h
new file mode 100644
index 000000000..43fdca099
--- /dev/null
+++ b/pstoraster/opcheck.h
@@ -0,0 +1,86 @@
+/* Copyright (C) 1993, 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$ */
+/* Requires ialloc.h (for imemory), iref.h, errors.h */
+
+#ifndef opcheck_INCLUDED
+# define opcheck_INCLUDED
+
+/*
+ * Check the type of an object. Operators almost always use check_type,
+ * which is defined in oper.h; check_type_only is for checking
+ * subsidiary objects obtained from places other than the stack.
+ */
+#define check_type_only(rf,typ)\
+ BEGIN if ( !r_has_type(&rf,typ) ) return_error(e_typecheck); END
+#define check_stype_only(rf,styp)\
+ BEGIN if ( !r_has_stype(&rf,imemory,styp) ) return_error(e_typecheck); END
+/* Check for array */
+#define check_array_else(rf,errstat)\
+ BEGIN if ( !r_has_type(&rf, t_array) ) errstat; END
+#define check_array_only(rf)\
+ check_array_else(rf, return_error(e_typecheck))
+/* Check for procedure. check_proc_failed includes the stack underflow */
+/* check, but it doesn't do any harm in the off-stack case. */
+int check_proc_failed(P1(const ref *));
+
+#define check_proc(rf)\
+ BEGIN if ( !r_is_proc(&rf) ) return_error(check_proc_failed(&rf)); END
+#define check_proc_only(rf) check_proc(rf)
+
+/* Check for read, write, or execute access. */
+#define check_access(rf,acc1)\
+ BEGIN if ( !r_has_attr(&rf,acc1) ) return_error(e_invalidaccess); END
+#define check_read(rf) check_access(rf,a_read)
+#define check_write(rf) check_access(rf,a_write)
+#define check_execute(rf) check_access(rf,a_execute)
+#define check_type_access_only(rf,typ,acc1)\
+ BEGIN\
+ if ( !r_has_type_attrs(&rf,typ,acc1) )\
+ return_error((!r_has_type(&rf,typ) ? e_typecheck : e_invalidaccess));\
+ END
+#define check_read_type_only(rf,typ)\
+ check_type_access_only(rf,typ,a_read)
+#define check_write_type_only(rf,typ)\
+ check_type_access_only(rf,typ,a_write)
+
+/* Check for an integer value within an unsigned bound. */
+#define check_int_leu(orf, u)\
+ BEGIN\
+ check_type(orf, t_integer);\
+ if ( (ulong)(orf).value.intval > (u) ) return_error(e_rangecheck);\
+ END
+#define check_int_leu_only(rf, u)\
+ BEGIN\
+ check_type_only(rf, t_integer);\
+ if ( (ulong)(rf).value.intval > (u) ) return_error(e_rangecheck);\
+ END
+#define check_int_ltu(orf, u)\
+ BEGIN\
+ check_type(orf, t_integer);\
+ if ( (ulong)(orf).value.intval >= (u) ) return_error(e_rangecheck);\
+ END
+
+#endif /* opcheck_INCLUDED */
diff --git a/pstoraster/opdef.h b/pstoraster/opdef.h
new file mode 100644
index 000000000..d593a017f
--- /dev/null
+++ b/pstoraster/opdef.h
@@ -0,0 +1,164 @@
+/* Copyright (C) 1991, 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$ */
+/* Operator definition interface for Ghostscript */
+
+#ifndef opdef_INCLUDED
+# define opdef_INCLUDED
+
+/*
+ * Operator procedures take the pointer to the top of the o-stack
+ * as their argument. They return 0 for success, a negative code
+ * for an error, or a positive code for some uncommon situations (see below).
+ */
+
+/*
+ * Define the structure for initializing the operator table. Each operator
+ * file zxxx.c declares an array of these as follows:
+
+ const op_def * const zxxx_op_defs[] =
+ {
+ {"1name", zname},
+ ...
+ op_def_end(iproc)
+ };
+
+ * where iproc is an initialization procedure for the file, or 0. This
+ * definition always appears at the END of the file, to avoid the need for
+ * forward declarations for all the operator procedures. For backward
+ * compatibility with an older convention, we also allow (deprecated)
+
+ BEGIN_OP_DEFS(my_defs) {
+ {"1name", zname},
+ ...
+ END_OP_DEFS(iproc) }
+
+ * Operators may be stored in dictionaries other than systemdict.
+ * We support this with op_def entries of a special form:
+
+ op_def_begin_dict("dictname"),
+
+ */
+typedef struct {
+ const char *oname;
+ op_proc_p proc;
+} op_def;
+
+#define op_def_begin_dict(dname) {dname, 0}
+#define op_def_begin_filter() op_def_begin_dict("filterdict")
+#define op_def_begin_level2() op_def_begin_dict("level2dict")
+#define op_def_begin_ll3() op_def_begin_dict("ll3dict")
+#define op_def_is_begin_dict(def) ((def)->proc == 0)
+#define op_def_end(iproc) {0, (op_proc_p)iproc}
+
+/*
+ * Define the table of pointers to all operator definition tables.
+ */
+extern const op_def *const op_defs_all[];
+
+/*
+ * Formerly, we needed to define each op_defs table as a procedure that
+ * returns the actual table, because of cross-segment linking restrictions
+ * in the 16-bit Borland C compiler for MS Windows. This is no longer
+ * relevant, but for backward compatibility, we need to retain
+ * BEGIN/END_OP_DEFS with the same syntax. This involves a kludge to create
+ * a dummy procedure to match up with a closing brace, and another kludge to
+ * prevent a "defined but not used" warning.
+ */
+
+#define BEGIN_OP_DEFS(xx_op_defs)\
+const op_def xx_op_defs[] =
+
+#define END_OP_DEFS(iproc)\
+ op_def_end(iproc)\
+};\
+static int op_defs_dummy(void)\
+{ return 1 || op_defs_dummy(); /* generates the least wasted code */
+
+/*
+ * Internal operators whose names begin with %, such as continuation
+ * operators, do not appear in systemdict. Ghostscript assumes
+ * that these operators cannot appear anywhere (in executable form)
+ * except on the e-stack; to maintain this invariant, the execstack
+ * operator converts them to literal form, and cvx refuses to convert
+ * them back. As a result of this invariant, they do not need to
+ * push themselves back on the e-stack when executed, since the only
+ * place they could have come from was the e-stack.
+ */
+#define op_def_is_internal(def) ((def)->oname[1] == '%')
+
+/*
+ * All operators are catalogued in a table; this is necessary because
+ * they must have a short packed representation for the sake of 'bind'.
+ * The `size' of an operator is normally its index in this table;
+ * however, internal operators have a `size' of 0, and their true index
+ * must be found by searching the table for their procedure address.
+ */
+ushort op_find_index(P1(const ref *));
+
+#define op_index(opref)\
+ (r_size(opref) == 0 ? op_find_index(opref) : r_size(opref))
+/*
+ * There are actually two kinds of operators: the real ones (t_operator),
+ * and ones defined by procedures (t_oparray). The catalog for t_operators
+ * is op_def_table, and their index is in the range [1..op_def_count-1].
+ */
+#define op_index_is_operator(index) ((index) < op_def_count)
+extern const op_def **op_def_table;
+extern uint op_def_count;
+
+#define op_num_args(opref) (op_def_table[op_index(opref)]->oname[0] - '0')
+#define op_index_proc(index) (op_def_table[index]->proc)
+/*
+ * There are two catalogs for t_oparrays, one global and one local.
+ * Operator indices for the global table are in the range
+ * [op_def_count..op_def_count+op_array_global.count-1]
+ * Operator indices for the local table are in the range
+ * [op_def_count+r_size(&op_array_global.table)..
+ * op_def_count+r_size(&op_array_global.table)+op_array_local.count-1]
+ */
+typedef struct op_array_table_s {
+ ref table; /* t_array */
+ ushort *nx_table; /* name indices */
+ uint count; /* # of occupied entries */
+ uint base_index; /* operator index of first entry */
+ uint attrs; /* ref attrs of ops in this table */
+ ref *root_p; /* self-pointer for GC root */
+} op_array_table;
+extern op_array_table
+ op_array_table_global, op_array_table_local;
+
+#define op_index_op_array_table(index)\
+ ((index) < op_array_table_local.base_index ?\
+ &op_array_table_global : &op_array_table_local)
+
+/*
+ * Convert an operator index to an operator or oparray ref.
+ * This is only used for debugging and for 'get' from packed arrays,
+ * so it doesn't have to be very fast.
+ */
+void op_index_ref(P2(uint, ref *));
+
+#endif /* opdef_INCLUDED */
diff --git a/pstoraster/oper.h b/pstoraster/oper.h
new file mode 100644
index 000000000..31c02275b
--- /dev/null
+++ b/pstoraster/oper.h
@@ -0,0 +1,108 @@
+/* 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$ */
+/* Definitions for Ghostscript operators */
+
+#ifndef oper_INCLUDED
+# define oper_INCLUDED
+
+#include "errors.h"
+#include "ostack.h"
+#include "opdef.h"
+#include "opextern.h"
+#include "opcheck.h"
+#include "iutil.h"
+
+/*
+ * In order to combine typecheck and stackunderflow error checking
+ * into a single test, we guard the bottom of the o-stack with
+ * additional entries of type t__invalid. However, if a type check fails,
+ * we must make an additional check to determine which error
+ * should be reported. In order not to have to make this check in-line
+ * in every type check in every operator, we define a procedure that takes
+ * an o-stack pointer and returns e_stackunderflow if it points to
+ * a guard entry, e_typecheck otherwise.
+ *
+ * Note that we only need to do this for typecheck, not for any other
+ * kind of error such as invalidaccess, since any operator that can
+ * generate the latter will do a check_type or a check_op first.
+ * (See ostack.h for more information.)
+ *
+ * We define the operand type of check_type_failed as const ref * rather than
+ * const_os_ptr simply because there are a number of routines that might
+ * be used either with a stack operand or with a general operand, and
+ * the check for t__invalid is harmless when applied to off-stack refs.
+ */
+int check_type_failed(P1(const ref *));
+
+/*
+ * Check the type of an object. Operators almost always use check_type,
+ * which includes the stack underflow check described just above;
+ * check_type_only is for checking subsidiary objects obtained from
+ * places other than the stack.
+ */
+#define return_op_typecheck(op)\
+ return_error(check_type_failed(op))
+#define check_type(orf,typ)\
+ if ( !r_has_type(&orf,typ) ) return_op_typecheck(&orf)
+#define check_stype(orf,styp)\
+ if ( !r_has_stype(&orf,imemory,styp) ) return_op_typecheck(&orf)
+#define check_array(orf)\
+ check_array_else(orf, return_op_typecheck(&orf))
+#define check_type_access(orf,typ,acc1)\
+ if ( !r_has_type_attrs(&orf,typ,acc1) )\
+ return_error((!r_has_type(&orf,typ) ? check_type_failed(&orf) :\
+ e_invalidaccess))
+#define check_read_type(orf,typ)\
+ check_type_access(orf,typ,a_read)
+#define check_write_type(orf,typ)\
+ check_type_access(orf,typ,a_write)
+
+/* Macro for as yet unimplemented operators. */
+/* The if ( 1 ) is to prevent the compiler from complaining about */
+/* unreachable code. */
+#define NYI(msg) if ( 1 ) return_error(e_undefined)
+
+/*
+ * If an operator has popped or pushed something on the control stack,
+ * it must return o_pop_estack or o_push_estack respectively,
+ * rather than 0, to indicate success.
+ * It is OK to return o_pop_estack if nothing has been popped,
+ * but it is not OK to return o_push_estack if nothing has been pushed.
+ *
+ * If an operator has suspended the current context and wants the
+ * interpreter to call the scheduler, it must return o_reschedule.
+ * It may also have pushed or popped elements on the control stack.
+ * (This is only used when the Display PostScript option is included.)
+ *
+ * These values must be greater than 1, and far enough apart from zero and
+ * from each other not to tempt a compiler into implementing a 'switch'
+ * on them using indexing rather than testing.
+ */
+#define o_push_estack 5
+#define o_pop_estack 14
+#define o_reschedule 22
+
+#endif /* oper_INCLUDED */
diff --git a/pstoraster/opextern.h b/pstoraster/opextern.h
new file mode 100644
index 000000000..831c95a94
--- /dev/null
+++ b/pstoraster/opextern.h
@@ -0,0 +1,115 @@
+/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of GNU Ghostscript.
+
+ GNU Ghostscript is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
+ to anyone for the consequences of using it or for whether it serves any
+ particular purpose or works at all, unless he says so in writing. Refer
+ to the GNU General Public License for full details.
+
+ Everyone is granted permission to copy, modify and redistribute GNU
+ Ghostscript, but only under the conditions described in the GNU General
+ Public License. A copy of this license is supposed to have been given
+ to you along with GNU Ghostscript so you can know your rights and
+ responsibilities. It should be in a file named COPYING. Among other
+ things, the copyright notice and this notice must be preserved on all
+ copies.
+
+ Aladdin Enterprises 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$ */
+/* Externally accessible operator declarations */
+
+#ifndef opextern_INCLUDED
+# define opextern_INCLUDED
+
+/*
+ * Normally, the procedures that implement PostScript operators (named zX
+ * where X is the name of the operator, e.g., zadd) are private to the
+ * file in which they are defined. There are, however, a surprising
+ * number of these procedures that are used from other files.
+ * This file, opextern.h, declares all z* procedures that are
+ * - referenced from outside their defining file, and
+ * - present in *all* configurations of the interpreter.
+ * For z* procedures referenced from outside their file but not present
+ * in all configurations (e.g., Level 2 operators), the file making the
+ * reference must include a local extern. Not pretty, but c'est la vie.
+ */
+
+/* Operators exported for the special operator encoding in interp.c. */
+int zadd(P1(os_ptr));
+int zdef(P1(os_ptr));
+int zdup(P1(os_ptr));
+int zexch(P1(os_ptr));
+int zif(P1(os_ptr));
+int zifelse(P1(os_ptr));
+int zindex(P1(os_ptr));
+int zpop(P1(os_ptr));
+int zroll(P1(os_ptr));
+int zsub(P1(os_ptr));
+
+/* Operators exported for server loop implementations. */
+int zflush(P1(os_ptr));
+int zflushpage(P1(os_ptr));
+int zsave(P1(os_ptr));
+int zrestore(P1(os_ptr));
+
+/* Operators exported for save/restore. */
+int zgsave(P1(os_ptr));
+int zgrestore(P1(os_ptr));
+
+/* Operators exported for Level 2 pagedevice facilities. */
+int zcopy_gstate(P1(os_ptr));
+int zcurrentgstate(P1(os_ptr));
+int zgrestoreall(P1(os_ptr));
+int zgstate(P1(os_ptr));
+int zreadonly(P1(os_ptr));
+int zsetdevice(P1(os_ptr));
+int zsetgstate(P1(os_ptr));
+
+/* Operators exported for Level 2 "wrappers". */
+int zcopy(P1(os_ptr));
+int zimage(P1(os_ptr));
+int zimagemask(P1(os_ptr));
+int zwhere(P1(os_ptr));
+
+/* Operators exported for specific-VM operators. */
+int zarray(P1(os_ptr));
+int zdict(P1(os_ptr));
+int zpackedarray(P1(os_ptr));
+int zstring(P1(os_ptr));
+
+/* Operators exported for user path decoding. */
+/* Note that only operators defined in all configurations are declared here. */
+int zclosepath(P1(os_ptr));
+int zcurveto(P1(os_ptr));
+int zlineto(P1(os_ptr));
+int zmoveto(P1(os_ptr));
+int zrcurveto(P1(os_ptr));
+int zrlineto(P1(os_ptr));
+int zrmoveto(P1(os_ptr));
+
+/* Operators exported for CIE cache loading. */
+int zcvx(P1(os_ptr));
+int zexec(P1(os_ptr)); /* also for .runexec */
+int zfor(P1(os_ptr));
+
+/* Odds and ends */
+int zbegin(P1(os_ptr));
+int zcleartomark(P1(os_ptr));
+int zend(P1(os_ptr));
+int zclosefile(P1(os_ptr)); /* for runexec_cleanup */
+int zsetfont(P1(os_ptr)); /* for cshow_continue */
+
+/* Operators exported for special customer needs. */
+int zcurrentdevice(P1(os_ptr));
+int ztoken(P1(os_ptr));
+int ztokenexec(P1(os_ptr));
+int zwrite(P1(os_ptr));
+
+#endif /* opextern_INCLUDED */
diff --git a/pstoraster/ostack.h b/pstoraster/ostack.h
new file mode 100644
index 000000000..bf134dc90
--- /dev/null
+++ b/pstoraster/ostack.h
@@ -0,0 +1,94 @@
+/* Copyright (C) 1991, 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$ */
+/* Definitions for Ghostscript operand stack */
+
+#ifndef ostack_INCLUDED
+# define ostack_INCLUDED
+
+#include "iostack.h"
+
+/* Define the operand stack pointers. */
+extern op_stack_t iop_stack;
+
+#define o_stack (iop_stack.stack)
+#define osbot (o_stack.bot)
+#define osp (o_stack.p)
+#define ostop (o_stack.top)
+
+/* Macro to ensure enough room on the operand stack */
+#define check_ostack(n)\
+ if ( ostop - osp < (n) )\
+ { o_stack.requested = (n); return_error(e_stackoverflow); }
+
+/* Operand stack manipulation. */
+
+/* Note that push sets osp to (the new value of) op. */
+#define push(n)\
+ BEGIN\
+ if ( (op += (n)) > ostop )\
+ { o_stack.requested = (n); return_error(e_stackoverflow); }\
+ else osp = op;\
+ END
+
+/*
+ * Note that the pop macro only decrements osp, not op. For this reason,
+ *
+ * >>> pop should only be used just before returning, <<<
+ * >>> or else op must be decremented explicitly. <<<
+ */
+#define pop(n) (osp -= (n))
+
+/*
+ * Note that the interpreter does not check for operand stack underflow
+ * before calling the operator procedure. There are "guard" entries
+ * with invalid types and attributes just below the bottom of the
+ * operand stack: if the operator returns with a typecheck error,
+ * the interpreter checks for underflow at that time.
+ * Operators that don't typecheck their arguments must check for
+ * operand stack underflow explicitly; operators that take a variable
+ * number of arguments must also check for stack underflow in those cases
+ * where they expect more than their minimum number of arguments.
+ * (This is because the interpreter can only recognize that a typecheck
+ * is really a stackunderflow when the stack has fewer than the
+ * operator's declared minimum number of entries.)
+ */
+#define check_op(nargs)\
+ if ( op < osbot + ((nargs) - 1) ) return_error(e_stackunderflow)
+/*
+ * Similarly, in order to simplify some overflow checks, we allocate
+ * a few guard entries just above the top of the o-stack.
+ */
+
+/*
+ * The operand stack is implemented as a linked list of blocks:
+ * operators that can push or pop an unbounded number of values, or that
+ * access the entire o-stack, must take this into account. These are:
+ * (int)copy index roll clear count cleartomark
+ * counttomark aload astore packedarray
+ * .get/.putdeviceparams .gethardwareparams
+ */
+
+#endif /* ostack_INCLUDED */
diff --git a/pstoraster/pipe_.h b/pstoraster/pipe_.h
new file mode 100644
index 000000000..9354d9f81
--- /dev/null
+++ b/pstoraster/pipe_.h
@@ -0,0 +1,42 @@
+/* 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$ */
+/* Declaration of popen and pclose */
+
+#ifndef pipe__INCLUDED
+# define pipe__INCLUDED
+
+#include "stdio_.h"
+
+/*
+ * popen isn't POSIX-standard, so we declare it here.
+ * Because of inconsistent (and sometimes incorrect) header files,
+ * we must omit the argument list. Unfortunately, this sometimes causes
+ * more trouble than it cures.
+ */
+extern FILE *popen( /* P2(const char *, const char *) */ );
+extern int pclose(P1(FILE *));
+
+#endif /* pipe__INCLUDED */
diff --git a/pstoraster/pstoraster.c b/pstoraster/pstoraster.c
new file mode 100644
index 000000000..e36426824
--- /dev/null
+++ b/pstoraster/pstoraster.c
@@ -0,0 +1,253 @@
+/*
+ * "$Id$"
+ *
+ * PostScript RIP filter main entry for the Common UNIX Printing System
+ * (CUPS).
+ *
+ * Copyright 1993-2002 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:
+ *
+ * main() - Main entry for pstoraster.
+ * define_string() - Define a string value...
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#define bool bool_ /* (maybe not needed) */
+#define uchar uchar_
+#define uint uint_
+#define ushort ushort_
+#define ulong ulong_
+
+#include <cups/cups.h>
+#include <cups/string.h>
+#include <stdlib.h>
+
+#ifdef __sgi
+# include <sys/sysmips.h>
+#endif /* __sgi */
+
+#undef bool
+#undef uchar
+#undef uint
+#undef ushort
+#undef ulong
+
+#include "ghost.h"
+#include "imain.h"
+#include "iminst.h"
+#include "istack.h"
+#include "interp.h"
+#include "ostack.h"
+#include "opextern.h"
+#include "gscdefs.h"
+#include "store.h"
+
+
+/*
+ * Globals...
+ */
+
+const char *cupsProfile = NULL;
+
+
+/*
+ * Local functions...
+ */
+
+static void define_string(const char *, const char *);
+
+
+/*
+ * 'main()' - Main entry for pstoraster.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ FILE *stdfiles[3]; /* Copies of stdin, stdout, and stderr */
+ gs_main_instance *minst; /* Interpreter instance */
+ ref vtrue; /* True value */
+ int exit_code; /* Exit code */
+ ref error_object; /* Error object */
+ int num_options; /* Number of job options */
+ cups_option_t *options; /* Job options */
+ char gspath[2048]; /* Path to GS files... */
+ const char *datadir; /* CUPS_DATADIR env variable */
+ const char *fontpath; /* CUPS_FONTPATH env variable */
+
+
+#ifdef __sgi
+ /*
+ * Force unaligned memory access handling on R12K processors...
+ * (this should be done by default...) Ghostscript is not 64-bit
+ * safe...
+ */
+
+ sysmips(MIPS_FIXADE, 1, 0, 0);
+#endif /* __sgi */
+
+ /*
+ * Force the locale to "C" to avoid bugs...
+ */
+
+ putenv("LANG=C");
+
+ /*
+ * Create a PostScript interpreter instance...
+ */
+
+ minst = gs_main_instance_default();
+
+ /*
+ * Grab the old stdin/stdout/stderr...
+ */
+
+ gs_get_real_stdio(stdfiles);
+
+ /*
+ * Make sure status messages are not buffered...
+ */
+
+ setbuf(stdfiles[2], NULL);
+
+ /*
+ * Grab any job options...
+ */
+
+ num_options = cupsParseOptions(argv[5], 0, &options);
+
+ cupsProfile = cupsGetOption("profile", num_options, options);
+
+ /*
+ * Initialize basic interpreter stuff and read from the named file or
+ * from stdin...
+ */
+
+ if (argc > 6)
+ gs_main_init0(minst, fopen(argv[6], "r"), stdfiles[1], stdfiles[2], 8);
+ else
+ gs_main_init0(minst, stdfiles[0], stdfiles[1], stdfiles[2], 8);
+
+ /*
+ * Tell the interpreter where to find its files...
+ */
+
+ if ((datadir = getenv("CUPS_DATADIR")) == NULL)
+ datadir = CUPS_DATADIR;
+ if ((fontpath = getenv("CUPS_FONTPATH")) == NULL)
+ fontpath = CUPS_FONTPATH;
+
+ snprintf(gspath, sizeof(gspath), "%s/pstoraster:%s", datadir, fontpath);
+
+ minst->lib_path.final = gspath;
+ gs_main_set_lib_paths(minst);
+
+ /*
+ * Set interpreter options...
+ */
+
+ make_true(&vtrue);
+ gs_main_init1(minst);
+ initial_enter_name("QUIET", &vtrue);
+ initial_enter_name("NOPAUSE", &vtrue);
+ initial_enter_name("BATCH", &vtrue);
+
+ define_string("OutputFile", "-");
+
+ define_string("FONTPATH", fontpath);
+
+ /*
+ * Start the interpreter...
+ */
+
+ gs_main_init2(minst);
+ gs_main_run_string(minst, ".runstdin", minst->user_errors, &exit_code,
+ &error_object);
+
+ /*
+ * Make sure that the last page was printed...
+ */
+
+ zflush(osp);
+ zflushpage(osp);
+
+ /*
+ * And the exit when we're done...
+ */
+
+ gs_exit(exit_code);
+
+ return (0);
+}
+
+
+/*
+ * 'define_string()' - Define a string value...
+ */
+
+static void
+define_string(const char *name, /* I - Variable to set */
+ const char *s) /* I - Value */
+{
+ int len; /* Length of string */
+ char *copy; /* Copy of string */
+ ref value; /* Value object */
+
+
+ /*
+ * Get the string value and copy it using strdup(). Note that this uses
+ * the malloc() function, but since we are only running gsrip on "real"
+ * operating systems (no Windows/PC build), this is not a problem...
+ */
+
+ if (s == NULL)
+ {
+ len = 0;
+ copy = strdup("");
+ }
+ else
+ {
+ len = strlen(s);
+ copy = strdup(s);
+ };
+
+ /*
+ * Enter the name in systemdict...
+ */
+
+ make_const_string(&value, a_readonly | avm_foreign, len, (const byte *)copy);
+ initial_enter_name(name, &value);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/pstoraster/sa85x.h b/pstoraster/sa85x.h
new file mode 100644
index 000000000..d01513568
--- /dev/null
+++ b/pstoraster/sa85x.h
@@ -0,0 +1,51 @@
+/* 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$ */
+/* Requires scommon.h; strimpl.h if any templates are referenced */
+
+#ifndef sa85x_INCLUDED
+# define sa85x_INCLUDED
+
+/* ASCII85Encode */
+/* (no state) */
+extern const stream_template s_A85E_template;
+
+/* ASCII85Decode */
+typedef struct stream_A85D_state_s {
+ stream_state_common;
+ int odd; /* # of odd digits */
+ ulong word; /* word being accumulated */
+} stream_A85D_state;
+
+#define private_st_A85D_state() /* in sfilter2.c */\
+ gs_private_st_simple(st_A85D_state, stream_A85D_state,\
+ "ASCII85Decode state")
+/* We define the initialization procedure here, so that the scanner */
+/* can avoid a procedure call. */
+#define s_A85D_init_inline(ss)\
+ ((ss)->word = 0, (ss)->odd = 0)
+extern const stream_template s_A85D_template;
+
+#endif /* sa85x_INCLUDED */
diff --git a/pstoraster/sbcp.c b/pstoraster/sbcp.c
new file mode 100644
index 000000000..c7c735027
--- /dev/null
+++ b/pstoraster/sbcp.c
@@ -0,0 +1,259 @@
+/* Copyright (C) 1993, 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$ */
+/* BCP and TBCP filters */
+#include "stdio_.h"
+#include "strimpl.h"
+#include "sfilter.h"
+
+#define CtrlA 0x01
+#define CtrlC 0x03
+#define CtrlD 0x04
+#define CtrlE 0x05
+#define CtrlQ 0x11
+#define CtrlS 0x13
+#define CtrlT 0x14
+#define ESC 0x1b
+#define CtrlBksl 0x1c
+
+/* The following is not used yet. */
+/*private const char *TBCP_end_protocol_string = "\033%-12345X"; */
+
+/* ------ BCPEncode and TBCPEncode ------ */
+
+/* Process a buffer */
+private int
+s_xBCPE_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last, const byte * escaped)
+{
+ const byte *p = pr->ptr;
+ const byte *rlimit = pr->limit;
+ uint rcount = rlimit - p;
+ byte *q = pw->ptr;
+ uint wcount = pw->limit - q;
+ const byte *end = p + min(rcount, wcount);
+
+ while (p < end) {
+ byte ch = *++p;
+
+ if (ch <= 31 && escaped[ch]) {
+ if (p == rlimit) {
+ p--;
+ break;
+ }
+ *++q = CtrlA;
+ ch ^= 0x40;
+ if (--wcount < rcount)
+ end--;
+ }
+ *++q = ch;
+ }
+ pr->ptr = p;
+ pw->ptr = q;
+ return (p == rlimit ? 0 : 1);
+}
+
+/* Actual process procedures */
+private int
+s_BCPE_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last)
+{
+ static const byte escaped[32] =
+ {
+ 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0
+ };
+
+ return s_xBCPE_process(st, pr, pw, last, escaped);
+}
+private int
+s_TBCPE_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last)
+{
+ static const byte escaped[32] =
+ {
+ 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0
+ };
+
+ return s_xBCPE_process(st, pr, pw, last, escaped);
+}
+
+/* Stream templates */
+const stream_template s_BCPE_template =
+{&st_stream_state, NULL, s_BCPE_process, 1, 2
+};
+const stream_template s_TBCPE_template =
+{&st_stream_state, NULL, s_TBCPE_process, 1, 2
+};
+
+/* ------ BCPDecode and TBCPDecode ------ */
+
+private_st_BCPD_state();
+
+/* Initialize the state */
+private int
+s_BCPD_init(stream_state * st)
+{
+ stream_BCPD_state *const ss = (stream_BCPD_state *) st;
+
+ ss->escaped = 0;
+ ss->matched = ss->copy_count = 0;
+ return 0;
+}
+
+/* Process a buffer */
+private int
+s_xBCPD_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last, bool tagged)
+{
+ stream_BCPD_state *const ss = (stream_BCPD_state *) st;
+ const byte *p = pr->ptr;
+ const byte *rlimit = pr->limit;
+ byte *q = pw->ptr;
+ byte *wlimit = pw->limit;
+ int copy_count = ss->copy_count;
+ int status;
+ bool escaped = ss->escaped;
+
+ for (;;) {
+ byte ch;
+
+ if (copy_count) {
+ if (q == wlimit) {
+ status = (p < rlimit ? 1 : 0);
+ break;
+ }
+ *++q = *++(ss->copy_ptr);
+ copy_count--;
+ continue;
+ }
+ if (p == rlimit) {
+ status = 0;
+ break;
+ }
+ ch = *++p;
+ if (ch <= 31)
+ switch (ch) {
+ case CtrlA:
+ if (escaped) {
+ status = ERRC;
+ goto out;
+ }
+ escaped = true;
+ continue;
+ case CtrlC:
+ status = (*ss->signal_interrupt) (st);
+ if (status < 0)
+ goto out;
+ continue;
+ case CtrlD:
+ if (escaped) {
+ status = ERRC;
+ goto out;
+ }
+ status = EOFC;
+ goto out;
+ case CtrlE:
+ continue;
+ case CtrlQ:
+ continue;
+ case CtrlS:
+ continue;
+ case CtrlT:
+ status = (*ss->request_status) (st);
+ if (status < 0)
+ goto out;
+ continue;
+ case CtrlBksl:
+ continue;
+ }
+ if (q == wlimit) {
+ p--;
+ status = 1;
+ break;
+ }
+ if (escaped) {
+ escaped = false;
+ switch (ch) {
+ case '[':
+ if (!tagged) {
+ status = ERRC;
+ goto out;
+ }
+ /* falls through */
+ case 'A':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'Q':
+ case 'S':
+ case 'T':
+ case '\\':
+ ch ^= 0x40;
+ break;
+ case 'M':
+ if (!tagged) {
+ status = ERRC;
+ goto out;
+ }
+ continue;
+ default:
+ status = ERRC;
+ goto out;
+ }
+ }
+ *++q = ch;
+ }
+ out:ss->copy_count = copy_count;
+ ss->escaped = escaped;
+ pr->ptr = p;
+ pw->ptr = q;
+ return status;
+}
+
+/* Actual process procedures */
+private int
+s_BCPD_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last)
+{
+ return s_xBCPD_process(st, pr, pw, last, false);
+}
+private int
+s_TBCPD_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last)
+{
+ return s_xBCPD_process(st, pr, pw, last, true);
+}
+
+/* Stream templates */
+const stream_template s_BCPD_template =
+{&st_BCPD_state, s_BCPD_init, s_BCPD_process, 1, 1,
+ NULL, NULL, s_BCPD_init
+};
+const stream_template s_TBCPD_template =
+{&st_BCPD_state, s_BCPD_init, s_TBCPD_process, 1, 1,
+ NULL, NULL, s_BCPD_init
+};
diff --git a/pstoraster/sbhc.c b/pstoraster/sbhc.c
new file mode 100644
index 000000000..157c5f997
--- /dev/null
+++ b/pstoraster/sbhc.c
@@ -0,0 +1,291 @@
+/* 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$ */
+/* Bounded Huffman code filters */
+#include "memory_.h"
+#include "stdio_.h"
+#include "gdebug.h"
+#include "strimpl.h"
+#include "sbhc.h"
+#include "shcgen.h"
+
+/* ------ BoundedHuffmanEncode ------ */
+
+private_st_BHCE_state();
+
+/* Initialize BoundedHuffmanEncode filter. */
+private int
+s_BHCE_reinit(stream_state * st)
+{
+ stream_BHCE_state *const ss = (stream_BHCE_state *) st;
+
+ ss->encode.count = ss->definition.num_values;
+ s_bhce_init_inline(ss);
+ return 0;
+}
+private int
+s_BHCE_init(register stream_state * st)
+{
+ stream_BHCE_state *const ss = (stream_BHCE_state *) st;
+ hce_code *encode = ss->encode.codes =
+ (hce_code *) gs_alloc_byte_array(st->memory,
+ ss->definition.num_values,
+ sizeof(hce_code), "BHCE encode");
+
+ if (encode == 0)
+ return ERRC;
+/****** WRONG ******/
+ hc_make_encoding(encode, &ss->definition);
+ return s_BHCE_reinit(st);
+}
+
+/* Release the filter. */
+private void
+s_BHCE_release(stream_state * st)
+{
+ stream_BHCE_state *const ss = (stream_BHCE_state *) st;
+
+ gs_free_object(st->memory, ss->encode.codes, "BHCE encode");
+}
+
+/* Process a buffer. */
+private int
+s_BHCE_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last)
+{
+ stream_BHCE_state *const ss = (stream_BHCE_state *) st;
+ const byte *p = pr->ptr;
+ const byte *rlimit = pr->limit;
+ byte *q = pw->ptr;
+ byte *wlimit = pw->limit - (hc_bits_size >> 3);
+ const hce_code *encode = ss->encode.codes;
+ uint num_values = ss->definition.num_values;
+ uint zero_runs = ss->EncodeZeroRuns;
+ uint zero_max = num_values - zero_runs + (ss->EndOfData ? 0 : 1);
+ uint zero_value = (zero_max > 1 ? 0 : 0x100);
+ int zeros = ss->zeros;
+ int status = 0;
+
+ hce_declare_state;
+
+ hce_load_state();
+ while (p < rlimit && q < wlimit) {
+ uint value = *++p;
+ const hce_code *cp;
+
+ if (value >= num_values) {
+ status = ERRC;
+ break;
+ }
+ if (value == zero_value) { /* Accumulate a run of zeros. */
+ ++zeros;
+ if (zeros != zero_max)
+ continue;
+ /* We've scanned the longest run we can encode. */
+ cp = &encode[zeros - 2 + zero_runs];
+ zeros = 0;
+ hc_put_code((stream_hc_state *) ss, q, cp);
+ continue;
+ }
+ /* Check whether we need to put out a zero run. */
+ if (zeros > 0) {
+ --p;
+ cp = (zeros == 1 ? &encode[0] :
+ &encode[zeros - 2 + zero_runs]);
+ zeros = 0;
+ hc_put_code((stream_hc_state *) ss, q, cp);
+ continue;
+ }
+ cp = &encode[value];
+ hc_put_code((stream_hc_state *) ss, q, cp);
+ }
+ if (q >= wlimit)
+ status = 1;
+ wlimit = pw->limit;
+ if (last && status == 0) {
+ if (zeros > 0) { /* Put out a final run of zeros. */
+ const hce_code *cp = (zeros == 1 ? &encode[0] :
+ &encode[zeros - 2 + zero_runs]);
+
+ if (!hce_bits_available(cp->code_length))
+ status = 1;
+ else {
+ hc_put_code((stream_hc_state *) ss, q, cp);
+ zeros = 0;
+ }
+ }
+ if (ss->EndOfData) { /* Put out the EOD code if we have room. */
+ const hce_code *cp = &encode[num_values - 1];
+
+ if (!hce_bits_available(cp->code_length))
+ status = 1;
+ else
+ hc_put_code((stream_hc_state *) ss, q, cp);
+ } else {
+ if (q >= wlimit)
+ status = 1;
+ }
+ if (!status) {
+ q = hc_put_last_bits((stream_hc_state *) ss, q);
+ goto ns;
+ }
+ }
+ hce_store_state();
+ ns:pr->ptr = p;
+ pw->ptr = q;
+ ss->zeros = zeros;
+ return (p == rlimit ? 0 : 1);
+}
+
+/* Stream template */
+const stream_template s_BHCE_template =
+{&st_BHCE_state, s_BHCE_init, s_BHCE_process,
+ 1, hc_bits_size >> 3, s_BHCE_release, NULL, s_BHCE_reinit
+};
+
+/* ------ BoundedHuffmanDecode ------ */
+
+private_st_BHCD_state();
+
+#define hcd_initial_bits 7 /* arbitrary, >= 1 and <= 8 */
+
+/* Initialize BoundedHuffmanDecode filter. */
+private int
+s_BHCD_reinit(stream_state * st)
+{
+ stream_BHCD_state *const ss = (stream_BHCD_state *) st;
+
+ ss->decode.count = ss->definition.num_values;
+ s_bhcd_init_inline(ss);
+ return 0;
+}
+private int
+s_BHCD_init(register stream_state * st)
+{
+ stream_BHCD_state *const ss = (stream_BHCD_state *) st;
+ uint initial_bits = ss->decode.initial_bits =
+ min(hcd_initial_bits, ss->definition.num_counts);
+ uint dsize = hc_sizeof_decoding(&ss->definition, initial_bits);
+ hcd_code *decode = ss->decode.codes =
+ (hcd_code *) gs_alloc_byte_array(st->memory, dsize,
+ sizeof(hcd_code), "BHCD decode");
+
+ if (decode == 0)
+ return ERRC;
+/****** WRONG ******/
+ hc_make_decoding(decode, &ss->definition, initial_bits);
+ return s_BHCD_reinit(st);
+}
+
+/* Release the filter. */
+private void
+s_BHCD_release(stream_state * st)
+{
+ stream_BHCD_state *const ss = (stream_BHCD_state *) st;
+
+ gs_free_object(st->memory, ss->decode.codes, "BHCD decode");
+}
+
+/* Process a buffer. */
+private int
+s_BHCD_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last)
+{
+ stream_BHCD_state *const ss = (stream_BHCD_state *) st;
+
+ bhcd_declare_state;
+ byte *q = pw->ptr;
+ byte *wlimit = pw->limit;
+ const hcd_code *decode = ss->decode.codes;
+ uint initial_bits = ss->decode.initial_bits;
+ uint zero_runs = ss->EncodeZeroRuns;
+ int status = 0;
+ int eod = (ss->EndOfData ? ss->definition.num_values - 1 : -1);
+
+ bhcd_load_state();
+ z:for (; zeros > 0; --zeros) {
+ if (q >= wlimit) {
+ status = 1;
+ goto out;
+ }
+ *++q = 0;
+ }
+ for (;;) {
+ const hcd_code *cp;
+ int clen;
+
+ hcd_ensure_bits(initial_bits, x1);
+ cp = &decode[hcd_peek_var_bits(initial_bits)];
+ w1:if (q >= wlimit) {
+ status = 1;
+ break;
+ }
+ if ((clen = cp->code_length) > initial_bits) {
+ if (!hcd_bits_available(clen)) { /* We don't have enough bits for */
+ /* all possible codes that begin this way, */
+ /* but we might have enough for */
+ /* the next code. */
+/****** NOT IMPLEMENTED YET ******/
+ break;
+ }
+ clen -= initial_bits;
+ hcd_skip_bits(initial_bits);
+ hcd_ensure_bits(clen, out); /* can't exit */
+ cp = &decode[cp->value + hcd_peek_var_bits(clen)];
+ hcd_skip_bits(cp->code_length);
+ } else {
+ hcd_skip_bits(clen);
+ }
+ if (cp->value >= zero_runs) {
+ if (cp->value == eod) {
+ status = EOFC;
+ goto out;
+ }
+ /* This code represents a run of zeros, */
+ /* not a single output value. */
+ zeros = cp->value - zero_runs + 2;
+ goto z;
+ }
+ *++q = cp->value;
+ continue;
+ /* We don't have enough bits for all possible */
+ /* codes, but we might have enough for */
+ /* the next code. */
+ x1:cp = &decode[(bits & ((1 << bits_left) - 1)) <<
+ (initial_bits - bits_left)];
+ if ((clen = cp->code_length) <= bits_left)
+ goto w1;
+ break;
+ }
+ out:bhcd_store_state();
+ pw->ptr = q;
+ return status;
+}
+
+/* Stream template */
+const stream_template s_BHCD_template =
+{&st_BHCD_state, s_BHCD_init, s_BHCD_process, 1, 1, s_BHCD_release,
+ NULL, s_BHCD_reinit
+};
diff --git a/pstoraster/sbhc.h b/pstoraster/sbhc.h
new file mode 100644
index 000000000..e0317cabc
--- /dev/null
+++ b/pstoraster/sbhc.h
@@ -0,0 +1,98 @@
+/* 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 strimpl.h */
+
+#ifndef sbhc_INCLUDED
+# define sbhc_INCLUDED
+
+#include "shc.h"
+
+/*
+ * The BoundedHuffman filters extend the basic Huffman coding model by
+ * providing the ability to encode runs of zeros as a single data item,
+ * and by providing an end-of-data (EOD) marker.
+ */
+#define max_zero_run 100
+
+/* Common state */
+#define stream_BHC_state_common\
+ stream_hc_state_common;\
+ hc_definition definition;\
+ /* The client sets the following before initialization. */\
+ bool EndOfData;\
+ uint EncodeZeroRuns;\
+ /* The following are updated dynamically. */\
+ int zeros /* # of zeros scanned or left to output */
+typedef struct stream_BHC_state_s {
+ stream_BHC_state_common;
+} stream_BHC_state;
+
+/* BoundedHuffmanEncode */
+typedef struct stream_BHCE_state_s {
+ stream_BHC_state_common;
+ hce_table encode;
+} stream_BHCE_state;
+
+#define private_st_BHCE_state() /* in sbhc.c */\
+ gs_private_st_ptrs3(st_BHCE_state, stream_BHCE_state,\
+ "BoundedHuffmanEncode state", bhce_enum_ptrs, bhce_reloc_ptrs,\
+ definition.counts, definition.values, encode.codes)
+extern const stream_template s_BHCE_template;
+
+#define s_bhce_init_inline(ss)\
+ (s_hce_init_inline(ss), (ss)->zeros = 0)
+
+/* BoundedHuffmanDecode */
+typedef struct stream_BHCD_state_s {
+ stream_BHC_state_common;
+ hcd_table decode;
+} stream_BHCD_state;
+
+#define private_st_BHCD_state() /* in sbhc.c */\
+ gs_private_st_ptrs3(st_BHCD_state, stream_BHCD_state,\
+ "BoundedHuffmanDecode state", bhcd_enum_ptrs, bhcd_reloc_ptrs,\
+ definition.counts, definition.values, decode.codes)
+extern const stream_template s_BHCD_template;
+
+#define s_bhcd_init_inline(ss)\
+ (s_hcd_init_inline(ss), (ss)->zeros = 0)
+
+/* Declare variables that hold the decoder state. */
+#define bhcd_declare_state\
+ hcd_declare_state;\
+ int zeros
+
+/* Load the state from the stream. */
+/* Free variables: pr, ss, p, rlimit, bits, bits_left, zeros. */
+#define bhcd_load_state()\
+ hcd_load_state(), zeros = ss->zeros
+
+/* Store the state back in the stream. */
+/* Free variables: pr, ss, p, bits, bits_left, zeros. */
+#define bhcd_store_state()\
+ hcd_store_state(), ss->zeros = zeros
+
+#endif /* sbhc_INCLUDED */
diff --git a/pstoraster/sbtx.h b/pstoraster/sbtx.h
new file mode 100644
index 000000000..e1a3324bf
--- /dev/null
+++ b/pstoraster/sbtx.h
@@ -0,0 +1,45 @@
+/* Copyright (C) 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of GNU Ghostscript.
+
+ GNU Ghostscript is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
+ to anyone for the consequences of using it or for whether it serves any
+ particular purpose or works at all, unless he says so in writing. Refer
+ to the GNU General Public License for full details.
+
+ Everyone is granted permission to copy, modify and redistribute GNU
+ Ghostscript, but only under the conditions described in the GNU General
+ Public License. A copy of this license is supposed to have been given
+ to you along with GNU Ghostscript so you can know your rights and
+ responsibilities. It should be in a file named COPYING. Among other
+ things, the copyright notice and this notice must be preserved on all
+ copies.
+
+ Aladdin Enterprises 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 scommon.h; strimpl.h if any templates are referenced */
+
+#ifndef sbtx_INCLUDED
+# define sbtx_INCLUDED
+
+/* ByteTranslateEncode/Decode */
+typedef struct stream_BT_state_s {
+ stream_state_common;
+ byte table[256];
+} stream_BT_state;
+typedef stream_BT_state stream_BTE_state;
+typedef stream_BT_state stream_BTD_state;
+
+#define private_st_BT_state() /* in sfilter1.c */\
+ gs_private_st_simple(st_BT_state, stream_BT_state,\
+ "ByteTranslateEncode/Decode state")
+extern const stream_template s_BTE_template;
+extern const stream_template s_BTD_template;
+
+#endif /* sbtx_INCLUDED */
diff --git a/pstoraster/sbwbs.c b/pstoraster/sbwbs.c
new file mode 100644
index 000000000..1523ac7b1
--- /dev/null
+++ b/pstoraster/sbwbs.c
@@ -0,0 +1,535 @@
+/* Copyright (C) 1994, 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$ */
+/* Burrows/Wheeler block sorting compression filters */
+#include "stdio_.h"
+#include "memory_.h"
+#include <stdlib.h> /* for qsort */
+#include "gdebug.h"
+#include "strimpl.h"
+#include "sfilter.h"
+#include "sbwbs.h"
+
+/* ------ Common code for streams that buffer a block ------ */
+
+private_st_buffered_state();
+
+/* Initialize */
+private int
+s_buffered_no_block_init(stream_state * st)
+{
+ stream_buffered_state *const ss = (stream_buffered_state *) st;
+
+ ss->buffer = 0;
+ ss->filling = true;
+ ss->bpos = 0;
+ return 0;
+}
+private int
+s_buffered_block_init(stream_state * st)
+{
+ stream_buffered_state *const ss = (stream_buffered_state *) st;
+
+ s_buffered_no_block_init(st);
+ ss->buffer = gs_alloc_bytes(st->memory, ss->BlockSize, "buffer");
+ if (ss->buffer == 0)
+ return ERRC;
+/****** WRONG ******/
+ return 0;
+}
+
+/* Continue filling the buffer if needed. */
+/* Return 0 if the buffer isn't full yet, 1 if it is full or if */
+/* we reached the end of input data. */
+/* In the latter case, also set filling = false. */
+/* Note that this procedure doesn't take pw as an argument. */
+private int
+s_buffered_process(stream_state * st, stream_cursor_read * pr, bool last)
+{
+ stream_buffered_state *const ss = (stream_buffered_state *) st;
+ register const byte *p = pr->ptr;
+ const byte *rlimit = pr->limit;
+ uint count = rlimit - p;
+ uint left = ss->bsize - ss->bpos;
+
+ if (!ss->filling)
+ return 1;
+ if (left < count)
+ count = left;
+ if_debug3('w', "[w]buffering %d bytes to position %d, last = %s\n",
+ count, ss->bpos, (last ? "true" : "false"));
+ memcpy(ss->buffer + ss->bpos, p + 1, count);
+ pr->ptr = p += count;
+ ss->bpos += count;
+ if (ss->bpos == ss->bsize || (p == rlimit && last)) {
+ ss->filling = false;
+ return 1;
+ }
+ return 0;
+}
+
+/* Release */
+private void
+s_buffered_release(stream_state * st)
+{
+ stream_buffered_state *const ss = (stream_buffered_state *) st;
+
+ gs_free_object(st->memory, ss->buffer, "buffer");
+}
+
+/* ------ Common code for Burrows/Wheeler block sorting filters ------ */
+
+private_st_BWBS_state();
+private void s_BWBS_release(P1(stream_state *));
+
+/* Initialize */
+private int
+bwbs_init(stream_state * st, uint osize)
+{
+ stream_BWBS_state *const ss = (stream_BWBS_state *) st;
+ int code;
+
+ ss->bsize = ss->BlockSize;
+ code = s_buffered_block_init(st);
+ if (code != 0)
+ return code;
+ ss->offsets = (void *)gs_alloc_bytes(st->memory, osize,
+ "BWBlockSort offsets");
+ if (ss->offsets == 0) {
+ s_BWBS_release(st);
+ return ERRC;
+/****** WRONG ******/
+ }
+ ss->I = -1; /* haven't read I yet */
+ return 0;
+}
+
+/* Release the filter. */
+private void
+s_BWBS_release(stream_state * st)
+{
+ stream_BWBS_state *const ss = (stream_BWBS_state *) st;
+
+ gs_free_object(st->memory, ss->offsets, "BWBlockSort offsets");
+ s_buffered_release(st);
+}
+
+/* ------ BWBlockSortEncode ------ */
+
+/* Initialize */
+private int
+s_BWBSE_init(stream_state * st)
+{
+ stream_BWBS_state *const ss = (stream_BWBS_state *) st;
+
+ return bwbs_init(st, ss->BlockSize * sizeof(int));
+}
+
+/* Compare two rotated strings for sorting. */
+private stream_BWBS_state *bwbs_compare_ss;
+private int
+bwbs_compare_rotations(const void *p1, const void *p2)
+{
+ const byte *buffer = bwbs_compare_ss->buffer;
+ const byte *s1 = buffer + *(const int *)p1;
+ const byte *s2 = buffer + *(const int *)p2;
+ const byte *start1;
+ const byte *end;
+ int swap;
+
+ if (*s1 != *s2)
+ return (*s1 < *s2 ? -1 : 1);
+ if (s1 < s2)
+ swap = 1;
+ else {
+ const byte *t = s1;
+
+ s1 = s2;
+ s2 = t;
+ swap = -1;
+ }
+ start1 = s1;
+ end = buffer + bwbs_compare_ss->N;
+ for (s1++, s2++; s2 < end; s1++, s2++)
+ if (*s1 != *s2)
+ return (*s1 < *s2 ? -swap : swap);
+ s2 = buffer;
+ for (; s1 < end; s1++, s2++)
+ if (*s1 != *s2)
+ return (*s1 < *s2 ? -swap : swap);
+ s1 = buffer;
+ for (; s1 < start1; s1++, s2++)
+ if (*s1 != *s2)
+ return (*s1 < *s2 ? -swap : swap);
+ return 0;
+}
+/* Sort the strings. */
+private void
+bwbse_sort(const byte * buffer, uint * indices, int N)
+{
+ offsets_full Cs;
+
+#define C Cs.v
+ /* Sort the strings. We start with a radix sort. */
+ uint sum = 0, j, ch;
+
+ memset(C, 0, sizeof(Cs));
+ for (j = 0; j < N; j++)
+ C[buffer[j]]++;
+ for (ch = 0; ch <= 255; ch++) {
+ sum += C[ch];
+ C[ch] = sum - C[ch];
+ }
+ for (j = 0; j < N; j++)
+ indices[C[buffer[j]]++] = j;
+ /* Now C[ch] = the number of strings that start */
+ /* with a character less than or equal to ch. */
+ sum = 0;
+ /* qsort each bucket produced by the radix sort. */
+ for (ch = 0; ch <= 255; sum = C[ch], ch++)
+ qsort(indices + sum, C[ch] - sum,
+ sizeof(*indices),
+ bwbs_compare_rotations);
+#undef C
+}
+
+/* Encode a buffer */
+private int
+s_BWBSE_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last)
+{
+ stream_BWBS_state *const ss = (stream_BWBS_state *) st;
+ register byte *q = pw->ptr;
+ byte *wlimit = pw->limit;
+ uint wcount = wlimit - q;
+ uint *indices = ss->offsets;
+
+ if (ss->filling) {
+ int status, j, N;
+ byte *buffer = ss->buffer;
+ if (wcount < sizeof(int) * 2)
+ return 1;
+
+ /* Continue filling the buffer. */
+ status = s_buffered_process(st, pr, last);
+ if (!status)
+ return 0;
+ ss->N = N = ss->bpos;
+ /* We reverse the string before encoding it, */
+ /* so it will come out of the decoder correctly. */
+ for (j = N / 2 - 1; j >= 0; j--) {
+ byte *p0 = &buffer[j];
+ byte *p1 = &buffer[N - 1 - j];
+ byte b = *p0;
+
+ *p0 = *p1;
+ *p1 = b;
+ }
+ /* Save st in a static, because that's the only way */
+ /* we can pass it to the comparison procedure (ugh). */
+ bwbs_compare_ss = ss;
+ /* Sort the strings. */
+ bwbse_sort(buffer, indices, N);
+ /* Find the unrotated string. */
+ for (j = 0; j < N; j++)
+ if (indices[j] == 0) {
+ ss->I = j;
+ break;
+ }
+ for (j = sizeof(int); --j >= 0;)
+ *++q = (byte) (N >> (j * 8));
+ for (j = sizeof(int); --j >= 0;)
+ *++q = (byte) (ss->I >> (j * 8));
+ ss->bpos = 0;
+ }
+ /* We're reading out of the buffer, writing the permuted string. */
+ while (q < wlimit && ss->bpos < ss->N) {
+ int i = indices[ss->bpos++];
+
+ *++q = ss->buffer[(i == 0 ? ss->N - 1 : i - 1)];
+ }
+ if (ss->bpos == ss->N) {
+ ss->filling = true;
+ ss->bpos = 0;
+ }
+ pw->ptr = q;
+ if (q == wlimit)
+ return 1;
+ return 0;
+}
+
+/* Stream template */
+const stream_template s_BWBSE_template =
+{&st_BWBS_state, s_BWBSE_init, s_BWBSE_process, sizeof(int) * 2, 1, s_BWBS_release
+};
+
+/* ------ BWBlockSortDecode ------ */
+
+#define SHORT_OFFSETS
+
+#ifdef SHORT_OFFSETS
+
+/*
+ * Letting S[0..N-1] be the data block before depermutation, we need
+ * a table P[0..N-1] that maps the index i to O(S[i],i), where O(c,i) is
+ * the number of occurrences of c in S before position i.
+ * We observe that for a fixed c, O(c,i) is monotonic with i,
+ * and falls in the range 0 .. i; consequently, if 0 <= i <= j,
+ * 0 <= O(c,j) - O(c,i) <= j - i. Proceeding from this observation,
+ * rather than allocate an entire int to each entry of P,
+ * we construct three tables as follows:
+ * P2[k,c] = O(c,k*65536) for k = 0 .. (N-1)/65536;
+ * each entry requires an int.
+ * P1[k,c] = O(c,k*4096) - P2[k/16,c] for k = 0 .. (N-1)/4096;
+ * each entry falls in the range 0 .. 15*4096 and hence
+ * requires 16 bits.
+ * P0[i] = O(S[i],i) - P1[i/4096,S[i]] for i = 0 .. N-1;
+ * each entry falls in the range 0 .. 4095 and hence
+ * requires 12 bits.
+ * Since the value we need in the decompression loop is actually
+ * P[i] + C[S[i]], where C[c] is the sum of O(0,N) ... O(c-1,N),
+ * we add C[c] into P2[k,c] for all k.
+ */
+ /*typedef struct { uint v[256]; } offsets_full; *//* in sbwbs.h */
+typedef struct {
+ bits16 v[256];
+} offsets_4k;
+
+#if arch_sizeof_int > 2
+# define ceil_64k(n) (((n) + 0xffff) >> 16)
+#else
+# define ceil_64k(n) 1
+#endif
+#define ceil_4k(n) (((n) + 0xfff) >> 12)
+#define offset_space(bsize)\
+ (ceil_64k(bsize) * sizeof(offsets_full) +\
+ ceil_4k(bsize) * sizeof(offsets_4k) +\
+ ((bsize + 1) >> 1) * 3)
+
+#else /* !SHORT_OFFSETS */
+
+#define offset_space(bsize)\
+ (bsize * sizeof(int))
+
+#endif /* (!)SHORT_OFFSETS */
+
+/* Initialize */
+private int
+s_BWBSD_init(stream_state * st)
+{
+ stream_BWBS_state *const ss = (stream_BWBS_state *) st;
+ uint bsize = ss->BlockSize;
+
+ return bwbs_init(st, offset_space(bsize));
+}
+
+/* Construct the decoding tables. */
+
+#ifdef SHORT_OFFSETS
+
+private void
+bwbsd_construct_offsets(stream_BWBS_state * sst, offsets_full * po64k,
+ offsets_4k * po4k, byte * po1, int N)
+{
+ offsets_full Cs;
+
+#define C Cs.v
+ uint i1;
+ byte *b = sst->buffer;
+ offsets_full *p2 = po64k - 1;
+ offsets_4k *p1 = po4k;
+ byte *p0 = po1;
+
+ memset(C, 0, sizeof(Cs));
+ for (i1 = 0; i1 < ceil_4k(N); i1++, p1++) {
+ int j;
+
+ if (!(i1 & 15))
+ *++p2 = Cs;
+ for (j = 0; j < 256; j++)
+ p1->v[j] = C[j] - p2->v[j];
+ j = (N + 1 - (i1 << 12)) >> 1;
+ if (j > 4096 / 2)
+ j = 4096 / 2;
+ for (; j > 0; j--, b += 2, p0 += 3) {
+ byte b0 = b[0];
+ uint d0 = C[b0]++ - (p1->v[b0] + p2->v[b0]);
+ byte b1 = b[1];
+ uint d1 = C[b1]++ - (p1->v[b1] + p2->v[b1]);
+
+ p0[0] = d0 >> 4;
+ p0[1] = (byte) ((d0 << 4) + (d1 >> 8));
+ p0[2] = (byte) d1;
+ }
+ }
+ /* If the block length is odd, discount the extra byte. */
+ if (N & 1)
+ C[sst->buffer[N]]--;
+ /* Compute the cumulative totals in C. */
+ {
+ int sum = 0, ch;
+
+ for (ch = 0; ch <= 255; ch++) {
+ sum += C[ch];
+ C[ch] = sum - C[ch];
+ }
+ }
+ /* Add the C values back into the 64K table, */
+ /* which saves an addition of C[b] in the decoding loop. */
+ {
+ int i2, ch;
+
+ for (p2 = po64k, i2 = ceil_64k(N); i2 > 0; p2++, i2--)
+ for (ch = 0; ch < 256; ch++)
+ p2->v[ch] += C[ch];
+ }
+#undef C
+}
+
+#else /* !SHORT_OFFSETS */
+
+private void
+bwbsd_construct_offsets(stream_BWBS_state * sst, int *po, int N)
+{
+ offsets_full Cs;
+
+#define C Cs.v
+ uint i;
+ byte *b = sst->buffer;
+ int *p = po;
+
+ memset(C, 0, sizeof(Cs));
+ for (i = 0; i < N; i++, p++, b++)
+ *p = C[*b]++;
+ /* Compute the cumulative totals in C. */
+ {
+ int sum = 0, ch;
+
+ for (ch = 0; ch <= 255; ch++) {
+ sum += C[ch];
+ C[ch] = sum - C[ch];
+ }
+ }
+ /* Add the C values back into the offsets. */
+ for (i = 0, b = sst->buffer, p = po; i < N; i++, b++, p++)
+ *p += C[*b];
+#undef C
+}
+
+#endif /* (!)SHORT_OFFSETS */
+
+/* Decode a buffer */
+private int
+s_BWBSD_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last)
+{
+ stream_BWBS_state *const ss = (stream_BWBS_state *) st;
+ register const byte *p = pr->ptr;
+ const byte *rlimit = pr->limit;
+ uint count = rlimit - p;
+ register byte *q = pw->ptr;
+ byte *wlimit = pw->limit;
+
+#ifdef SHORT_OFFSETS
+ uint BlockSize = ss->BlockSize;
+ offsets_full *po64k = ss->offsets;
+ offsets_4k *po4k = (offsets_4k *) (po64k + ceil_64k(BlockSize));
+ byte *po1 = (byte *) (po4k + ceil_4k(BlockSize));
+
+#else /* !SHORT_OFFSETS */
+ int *po = ss->offsets;
+
+#endif /* (!)SHORT_OFFSETS */
+
+ if (ss->I < 0) { /* Read block parameters */
+ int I, N, j;
+ if (count < sizeof(int) * 2)
+ return 0;
+ for (N = 0, j = 0; j < sizeof(int); j++)
+
+ N = (N << 8) + *++p;
+ for (I = 0, j = 0; j < sizeof(int); j++)
+
+ I = (I << 8) + *++p;
+ ss->N = N;
+ ss->I = I;
+ if_debug2('w', "[w]N=%d I=%d\n", N, I);
+ pr->ptr = p;
+ if (N < 0 || N > ss->BlockSize || I < 0 || I >= N)
+ return ERRC;
+ if (N == 0)
+ return EOFC;
+ count -= sizeof(int) * 2;
+
+ ss->bpos = 0;
+ ss->bsize = N;
+ }
+ if (ss->filling) { /* Continue filling the buffer. */
+ if (!s_buffered_process(st, pr, last))
+ return 0;
+ /* Construct the inverse sort order. */
+#ifdef SHORT_OFFSETS
+ bwbsd_construct_offsets(ss, po64k, po4k, po1, ss->bsize);
+#else /* !SHORT_OFFSETS */
+ bwbsd_construct_offsets(ss, po, ss->bsize);
+#endif /* (!)SHORT_OFFSETS */
+ ss->bpos = 0;
+ ss->i = ss->I;
+ }
+ /* We're reading out of the buffer. */
+ while (q < wlimit && ss->bpos < ss->bsize) {
+ int i = ss->i;
+ byte b = ss->buffer[i];
+
+#ifdef SHORT_OFFSETS
+ uint d;
+ const byte *pd = &po1[(i >> 1) + i];
+
+ *++q = b;
+ if (!(i & 1))
+ d = ((uint) pd[0] << 4) + (pd[1] >> 4);
+ else
+ d = ((pd[0] & 0xf) << 8) + pd[1];
+ ss->i = po64k[i >> 16].v[b] + po4k[i >> 12].v[b] + d;
+#else /* !SHORT_OFFSETS */
+ *++q = b;
+ ss->i = po[i];
+#endif /* (!)SHORT_OFFSETS */
+ ss->bpos++;
+ }
+ if (ss->bpos == ss->bsize) {
+ ss->I = -1;
+ ss->filling = true;
+ }
+ pw->ptr = q;
+ if (q == wlimit)
+ return 1;
+ return 0;
+}
+
+/* Stream template */
+const stream_template s_BWBSD_template =
+{&st_BWBS_state, s_BWBSD_init, s_BWBSD_process, 1, sizeof(int) * 2, s_BWBS_release
+};
diff --git a/pstoraster/sbwbs.h b/pstoraster/sbwbs.h
new file mode 100644
index 000000000..0018673b8
--- /dev/null
+++ b/pstoraster/sbwbs.h
@@ -0,0 +1,78 @@
+/* Copyright (C) 1994, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of GNU Ghostscript.
+
+ GNU Ghostscript is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
+ to anyone for the consequences of using it or for whether it serves any
+ particular purpose or works at all, unless he says so in writing. Refer
+ to the GNU General Public License for full details.
+
+ Everyone is granted permission to copy, modify and redistribute GNU
+ Ghostscript, but only under the conditions described in the GNU General
+ Public License. A copy of this license is supposed to have been given
+ to you along with GNU Ghostscript so you can know your rights and
+ responsibilities. It should be in a file named COPYING. Among other
+ things, the copyright notice and this notice must be preserved on all
+ copies.
+
+ Aladdin Enterprises 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 scommon.h; strimpl.h if any templates are referenced */
+
+#ifndef sbwbs_INCLUDED
+# define sbwbs_INCLUDED
+
+/* Common framework for streams that buffer a block for processing */
+#define stream_buffered_state_common\
+ stream_state_common;\
+ /* The client may set the following before initialization, */\
+ /* or the stream may set it later. */\
+ int BlockSize;\
+ /* The init procedure sets the following, */\
+ /* if BlockSize has been set. */\
+ byte *buffer; /* [BlockSize] */\
+ /* The following are updated dynamically. */\
+ bool filling; /* true if filling buffer, */\
+ /* false if emptying */\
+ int bsize; /* size of current block (<= BlockSize) */\
+ int bpos /* current index within buffer */
+typedef struct stream_buffered_state_s {
+ stream_buffered_state_common;
+} stream_buffered_state;
+
+#define private_st_buffered_state() /* in sbwbs.c */\
+ gs_private_st_ptrs1(st_buffered_state, stream_buffered_state,\
+ "stream_buffered state", sbuf_enum_ptrs, sbuf_reloc_ptrs, buffer)
+
+/* BWBlockSortEncode/Decode */
+typedef struct of_ {
+ uint v[256];
+} offsets_full;
+typedef struct stream_BWBS_state_s {
+ stream_buffered_state_common;
+ /* The init procedure sets the following. */
+ void *offsets; /* permutation indices when writing, */
+ /* multi-level indices when reading */
+ /* The following are updated dynamically. */
+ int N; /* actual length of block */
+ /* The following are only used when decoding. */
+ int I; /* index of unrotated string */
+ int i; /* next index in encoded string */
+} stream_BWBS_state;
+typedef stream_BWBS_state stream_BWBSE_state;
+typedef stream_BWBS_state stream_BWBSD_state;
+
+#define private_st_BWBS_state() /* in sbwbs.c */\
+ gs_private_st_suffix_add1(st_BWBS_state, stream_BWBS_state,\
+ "BWBlockSortEncode/Decode state", bwbs_enum_ptrs, bwbs_reloc_ptrs,\
+ st_buffered_state, offsets)
+extern const stream_template s_BWBSE_template;
+extern const stream_template s_BWBSD_template;
+
+#endif /* sbwbs_INCLUDED */
diff --git a/pstoraster/scanchar.h b/pstoraster/scanchar.h
new file mode 100644
index 000000000..8c5d25d21
--- /dev/null
+++ b/pstoraster/scanchar.h
@@ -0,0 +1,75 @@
+/* Copyright (C) 1990, 1995, 1996 Aladdin Enterprises. All rights reserved.
+
+ This file is part of GNU Ghostscript.
+
+ GNU Ghostscript is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
+ to anyone for the consequences of using it or for whether it serves any
+ particular purpose or works at all, unless he says so in writing. Refer
+ to the GNU General Public License for full details.
+
+ Everyone is granted permission to copy, modify and redistribute GNU
+ Ghostscript, but only under the conditions described in the GNU General
+ Public License. A copy of this license is supposed to have been given
+ to you along with GNU Ghostscript so you can know your rights and
+ responsibilities. It should be in a file named COPYING. Among other
+ things, the copyright notice and this notice must be preserved on all
+ copies.
+
+ Aladdin Enterprises 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 scommon.h */
+
+#ifndef scanchar_INCLUDED
+# define scanchar_INCLUDED
+
+/*
+ * An array for fast scanning of names, numbers, and hex strings.
+ * Indexed by character code (including exceptions), it contains:
+ * 0 - max_radix-1 for valid digits,
+ * ctype_name for other characters valid in names,
+ * ctype_btoken for characters introducing binary tokens
+ * (if the binary token feature is enabled),
+ * ctype_space for whitespace characters,
+ * ctype_exception for exceptions (see scommon.h), and
+ * ctype_other for everything else.
+ * Exceptions are negative values; we bias the table origin accordingly.
+ *
+ * NOTE: This table is defined in iscantab.c and used in a variety of places.
+ * If any of the values below change, you must edit the table.
+ */
+extern const byte scan_char_array[max_stream_exception + 256];
+
+#define scan_char_decoder (&scan_char_array[max_stream_exception])
+#define min_radix 2
+#define max_radix 36
+#define ctype_name 100
+#define ctype_btoken 101
+#define ctype_space 102
+#define ctype_other 103
+#define ctype_exception 104
+/* Special characters with no \xxx representation */
+#define char_NULL 0
+#define char_EOT 004 /* ^D, job delimiter */
+#define char_VT 013 /* ^K, vertical tab */
+#define char_DOS_EOF 032 /* ^Z */
+/*
+ * Most systems define '\n' as 0x0a and '\r' as 0x0d; however, OS-9
+ * has '\n' = '\r' = 0x0d and '\l' = 0x0a. To deal with this,
+ * we introduce abstract characters char_CR and char_EOL such that
+ * any of [char_CR], [char_CR char_EOL], or [char_EOL] is recognized
+ * as an end-of-line sequence.
+ */
+#define char_CR '\r'
+#if '\r' == '\n'
+# define char_EOL 0x0a /* non-OS-9 compilers complain about '\l' */
+#else
+# define char_EOL '\n'
+#endif
+
+#endif /* scanchar_INCLUDED */
diff --git a/pstoraster/scantab.c b/pstoraster/scantab.c
new file mode 100644
index 000000000..f36243603
--- /dev/null
+++ b/pstoraster/scantab.c
@@ -0,0 +1,112 @@
+/* Copyright (C) 1994, 1995, 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$ */
+/* Scanner table for PostScript/PDF tokens */
+#include "stdpre.h"
+#include "scommon.h"
+#include "scanchar.h" /* defines interface */
+
+/* Define the character scanning table (see scanchar.h). */
+const byte scan_char_array[max_stream_exception + 256] =
+{stream_exception_repeat(ctype_exception),
+ /* Control characters 0-31. */
+ ctype_space, /* NULL - standard only in Level 2 */
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_name, ctype_name, ctype_name,
+ ctype_space, /* TAB (\t) */
+ ctype_space, /* LF (\n) */
+ ctype_name,
+ ctype_space, /* FF (\f) */
+ ctype_space, /* CR (\r) */
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_name, ctype_name, ctype_name,
+ /* Printable characters 32-63 */
+ ctype_space, /* space (\s) */
+ ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_other, /* % */
+ ctype_name, ctype_name,
+ ctype_other, /* ( */
+ ctype_other, /* ) */
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_other, /* / */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, /* digits 0-9 */
+ ctype_name, ctype_name,
+ ctype_other, /* < */
+ ctype_name,
+ ctype_other, /* > */
+ ctype_name,
+ /* Printable characters 64-95 */
+ ctype_name,
+ 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,
+ ctype_other, /* [ */
+ ctype_name,
+ ctype_other, /* ] */
+ ctype_name, ctype_name,
+ /* Printable characters 96-126 and DEL */
+ ctype_name,
+ 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,
+ ctype_other, /* { */
+ ctype_name,
+ ctype_other, /* } */
+ ctype_name, ctype_name,
+ /* Characters 128-159, binary tokens */
+ ctype_btoken, ctype_btoken, ctype_btoken, ctype_btoken, ctype_btoken,
+ ctype_btoken, ctype_btoken, ctype_btoken, ctype_btoken, ctype_btoken,
+ ctype_btoken, ctype_btoken, ctype_btoken, ctype_btoken, ctype_btoken,
+ ctype_btoken, ctype_btoken, ctype_btoken, ctype_btoken, ctype_btoken,
+ ctype_btoken, ctype_btoken, ctype_btoken, ctype_btoken, ctype_btoken,
+ ctype_btoken, ctype_btoken, ctype_btoken, ctype_btoken, ctype_btoken,
+ ctype_btoken, ctype_btoken,
+ /* Characters 160-191, not defined */
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_name, ctype_name,
+ /* Characters 192-223, not defined */
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_name, ctype_name,
+ /* Characters 224-255, not defined */
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_name, ctype_name, ctype_name, ctype_name, ctype_name,
+ ctype_name, ctype_name
+};
diff --git a/pstoraster/scf.h b/pstoraster/scf.h
new file mode 100644
index 000000000..f8f08bcc5
--- /dev/null
+++ b/pstoraster/scf.h
@@ -0,0 +1,213 @@
+/* Copyright (C) 1992, 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$ */
+/* Common definitions for CCITTFax encoding and decoding filters */
+
+#ifndef scf_INCLUDED
+# define scf_INCLUDED
+
+#include "shc.h"
+
+/*
+ * The CCITT Group 3 (T.4) and Group 4 (T.6) fax specifications map
+ * run lengths to Huffman codes. White and black have different mappings.
+ * If the run length is 64 or greater, two or more codes are needed:
+ * - One or more 'make-up' codes for 2560 pixels;
+ * - A 'make-up' code that encodes the multiple of 64;
+ * - A 'termination' code for the remainder.
+ * For runs of 63 or less, only the 'termination' code is needed.
+ */
+
+/* ------ Encoding tables ------ */
+
+/*
+ * The maximum possible length of a scan line is determined by the
+ * requirement that 3 runs have to fit into the stream buffer.
+ * A run of length N requires approximately ceil(N / 2560) makeup codes,
+ * hence 1.5 * ceil(N / 2560) bytes. Taking the largest safe stream
+ * buffer size as 32K, we arrive at the following maximum width:
+ */
+#if arch_sizeof_int > 2
+# define cfe_max_width (2560 * 32000 * 2 / 3)
+#else
+# define cfe_max_width (max_int - 40) /* avoid overflows */
+#endif
+/* The +5 in cfe_max_code_bytes is a little conservative. */
+#define cfe_max_code_bytes(width) ((width) / 2560 * 3 / 2 + 5)
+
+typedef hce_code cfe_run;
+
+/* Codes common to 1-D and 2-D encoding. */
+/* The decoding algorithms know that EOL is 0....01. */
+#define run_eol_code_length 12
+#define run_eol_code_value 1
+extern const cfe_run cf_run_eol;
+typedef struct cf_runs_s {
+ cfe_run termination[64];
+ cfe_run make_up[41];
+} cf_runs;
+extern const cf_runs
+ cf_white_runs, cf_black_runs;
+extern const cfe_run cf_uncompressed[6];
+extern const cfe_run cf_uncompressed_exit[10]; /* indexed by 2 x length of */
+
+ /* white run + (1 if next run black, 0 if white) */
+/* 1-D encoding. */
+extern const cfe_run cf1_run_uncompressed;
+
+/* 2-D encoding. */
+extern const cfe_run cf2_run_pass;
+
+#define cf2_run_pass_length 4
+#define cf2_run_pass_value 0x1
+#define cf2_run_vertical_offset 3
+extern const cfe_run cf2_run_vertical[7]; /* indexed by b1 - a1 + offset */
+extern const cfe_run cf2_run_horizontal;
+
+#define cf2_run_horizontal_value 1
+#define cf2_run_horizontal_length 3
+extern const cfe_run cf2_run_uncompressed;
+
+/* 2-D Group 3 encoding. */
+extern const cfe_run cf2_run_eol_1d;
+extern const cfe_run cf2_run_eol_2d;
+
+/* ------ Decoding tables ------ */
+
+typedef hcd_code cfd_node;
+
+#define run_length value
+
+/*
+ * The value in the decoding tables is either a white or black run length,
+ * or a (negative) exceptional value.
+ */
+#define run_error (-1)
+#define run_zeros (-2) /* EOL follows, possibly with more padding first */
+#define run_uncompressed (-3)
+/* 2-D codes */
+#define run2_pass (-4)
+#define run2_horizontal (-5)
+
+#define cfd_white_initial_bits 8
+extern const cfd_node cf_white_decode[];
+
+#define cfd_black_initial_bits 7
+extern const cfd_node cf_black_decode[];
+
+#define cfd_2d_initial_bits 7
+extern const cfd_node cf_2d_decode[];
+
+#define cfd_uncompressed_initial_bits 6 /* must be 6 */
+extern const cfd_node cf_uncompressed_decode[];
+
+/* ------ Run detection macros ------ */
+
+/*
+ * For the run detection macros:
+ * white_byte is 0 or 0xff for BlackIs1 or !BlackIs1 respectively;
+ * data holds p[-1], inverted if !BlackIs1;
+ * count is the number of valid bits remaining in the scan line.
+ */
+
+/* Aliases for bit processing tables. */
+#define cf_byte_run_length byte_bit_run_length_neg
+#define cf_byte_run_length_0 byte_bit_run_length_0
+
+/* Skip over white pixels to find the next black pixel in the input. */
+/* Store the run length in rlen, and update data, p, and count. */
+/* There are many more white pixels in typical input than black pixels, */
+/* and the runs of white pixels tend to be much longer, so we use */
+/* substantially different loops for the two cases. */
+
+#define skip_white_pixels(data, p, count, white_byte, rlen)\
+BEGIN\
+ rlen = cf_byte_run_length[count & 7][data ^ 0xff];\
+ if ( rlen >= 8 ) { /* run extends past byte boundary */\
+ if ( white_byte == 0 ) {\
+ if ( p[0] ) { data = p[0]; p += 1; rlen -= 8; }\
+ else if ( p[1] ) { data = p[1]; p += 2; }\
+ else {\
+ while ( !(p[2] | p[3] | p[4] | p[5]) )\
+ p += 4, rlen += 32;\
+ if ( p[2] ) {\
+ data = p[2]; p += 3; rlen += 8;\
+ } else if ( p[3] ) {\
+ data = p[3]; p += 4; rlen += 16;\
+ } else if ( p[4] ) {\
+ data = p[4]; p += 5; rlen += 24;\
+ } else /* p[5] */ {\
+ data = p[5]; p += 6; rlen += 32;\
+ }\
+ }\
+ } else {\
+ if ( p[0] != 0xff ) { data = (byte)~p[0]; p += 1; rlen -= 8; }\
+ else if ( p[1] != 0xff ) { data = (byte)~p[1]; p += 2; }\
+ else {\
+ while ( (p[2] & p[3] & p[4] & p[5]) == 0xff )\
+ p += 4, rlen += 32;\
+ if ( p[2] != 0xff ) {\
+ data = (byte)~p[2]; p += 3; rlen += 8;\
+ } else if ( p[3] != 0xff ) {\
+ data = (byte)~p[3]; p += 4; rlen += 16;\
+ } else if ( p[4] != 0xff ) {\
+ data = (byte)~p[4]; p += 5; rlen += 24;\
+ } else /* p[5] != 0xff */ {\
+ data = (byte)~p[5]; p += 6; rlen += 32;\
+ }\
+ }\
+ }\
+ rlen += cf_byte_run_length_0[data ^ 0xff];\
+ }\
+ count -= rlen;\
+END
+
+/* Skip over black pixels to find the next white pixel in the input. */
+/* Store the run length in rlen, and update data, p, and count. */
+
+#define skip_black_pixels(data, p, count, white_byte, rlen)\
+BEGIN\
+ rlen = cf_byte_run_length[count & 7][data];\
+ if ( rlen >= 8 ) {\
+ if ( white_byte == 0 )\
+ for ( ; ; p += 4, rlen += 32 ) {\
+ if ( p[0] != 0xff ) { data = p[0]; p += 1; rlen -= 8; break; }\
+ if ( p[1] != 0xff ) { data = p[1]; p += 2; break; }\
+ if ( p[2] != 0xff ) { data = p[2]; p += 3; rlen += 8; break; }\
+ if ( p[3] != 0xff ) { data = p[3]; p += 4; rlen += 16; break; }\
+ }\
+ else\
+ for ( ; ; p += 4, rlen += 32 ) {\
+ if ( p[0] ) { data = (byte)~p[0]; p += 1; rlen -= 8; break; }\
+ if ( p[1] ) { data = (byte)~p[1]; p += 2; break; }\
+ if ( p[2] ) { data = (byte)~p[2]; p += 3; rlen += 8; break; }\
+ if ( p[3] ) { data = (byte)~p[3]; p += 4; rlen += 16; break; }\
+ }\
+ rlen += cf_byte_run_length_0[data];\
+ }\
+ count -= rlen;\
+END
+
+#endif /* scf_INCLUDED */
diff --git a/pstoraster/scfd.c b/pstoraster/scfd.c
new file mode 100644
index 000000000..2d9a34296
--- /dev/null
+++ b/pstoraster/scfd.c
@@ -0,0 +1,809 @@
+/* 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$ */
+/* CCITTFax decoding filter */
+#include "stdio_.h" /* includes std.h */
+#include "memory_.h"
+#include "gdebug.h"
+#include "strimpl.h"
+#include "scf.h"
+#include "scfx.h"
+
+/* ------ CCITTFaxDecode ------ */
+
+private_st_CFD_state();
+
+/* Set default parameter values. */
+private void
+s_CFD_set_defaults(register stream_state * st)
+{
+ stream_CFD_state *const ss = (stream_CFD_state *) st;
+
+ s_CFD_set_defaults_inline(ss);
+}
+
+/* Initialize CCITTFaxDecode filter */
+private int
+s_CFD_init(stream_state * st)
+{
+ stream_CFD_state *const ss = (stream_CFD_state *) st;
+ int raster = ss->raster =
+ round_up((ss->Columns + 7) >> 3, ss->DecodedByteAlign);
+ byte white = (ss->BlackIs1 ? 0 : 0xff);
+
+ s_hcd_init_inline(ss);
+ /* Because skip_white_pixels can look as many as 4 bytes ahead, */
+ /* we need to allow 4 extra bytes at the end of the row buffers. */
+ ss->lbuf = gs_alloc_bytes(st->memory, raster + 4, "CFD lbuf");
+ ss->lprev = 0;
+ if (ss->lbuf == 0)
+ return ERRC;
+/****** WRONG ******/
+ if (ss->K != 0) {
+ ss->lprev = gs_alloc_bytes(st->memory, raster + 4, "CFD lprev");
+ if (ss->lprev == 0)
+ return ERRC;
+/****** WRONG ******/
+ /* Clear the initial reference line for 2-D encoding. */
+ memset(ss->lbuf, white, raster);
+ /* Ensure that the scan of the reference line will stop. */
+ ss->lbuf[raster] = 0xa0;
+ }
+ ss->k_left = min(ss->K, 0);
+ ss->run_color = 0;
+ ss->damaged_rows = 0;
+ ss->skipping_damage = false;
+ ss->cbit = 0;
+ ss->uncomp_run = 0;
+ ss->rows_left = (ss->Rows <= 0 || ss->EndOfBlock ? -1 : ss->Rows + 1);
+ ss->rpos = ss->wpos = raster - 1;
+ ss->eol_count = 0;
+ ss->invert = white;
+ return 0;
+}
+
+/* Release the filter. */
+private void
+s_CFD_release(stream_state * st)
+{
+ stream_CFD_state *const ss = (stream_CFD_state *) st;
+
+ gs_free_object(st->memory, ss->lprev, "CFD lprev(close)");
+ gs_free_object(st->memory, ss->lbuf, "CFD lbuf(close)");
+}
+
+/* Declare the variables that hold the state. */
+#define cfd_declare_state\
+ hcd_declare_state;\
+ register byte *q;\
+ int qbit
+/* Load the state from the stream. */
+#define cfd_load_state()\
+ hcd_load_state(),\
+ q = ss->lbuf + ss->wpos, qbit = ss->cbit
+/* Store the state back in the stream. */
+#define cfd_store_state()\
+ hcd_store_state(),\
+ ss->wpos = q - ss->lbuf, ss->cbit = qbit
+
+/* Macros to get blocks of bits from the input stream. */
+/* Invariants: 0 <= bits_left <= bits_size; */
+/* bits [bits_left-1..0] contain valid data. */
+
+#define avail_bits(n) hcd_bits_available(n)
+#define ensure_bits(n, outl) hcd_ensure_bits(n, outl)
+#define peek_bits(n) hcd_peek_bits(n)
+#define peek_var_bits(n) hcd_peek_var_bits(n)
+#define skip_bits(n) hcd_skip_bits(n)
+
+/* Get a run from the stream. */
+#ifdef DEBUG
+# define IF_DEBUG(expr) expr
+#else
+# define IF_DEBUG(expr) DO_NOTHING
+#endif
+#define get_run(decode, initial_bits, runlen, str, outl)\
+{ const cfd_node *np;\
+ int clen;\
+ ensure_bits(initial_bits, outl);\
+ np = &decode[peek_bits(initial_bits)];\
+ if ( (clen = np->code_length) > initial_bits )\
+ { IF_DEBUG(uint init_bits = peek_bits(initial_bits));\
+ if ( !avail_bits(clen) ) goto outl;\
+ clen -= initial_bits;\
+ skip_bits(initial_bits);\
+ ensure_bits(clen, outl); /* can't goto outl */\
+ np = &decode[np->run_length + peek_var_bits(clen)];\
+ if_debug4('W', "%s xcode=0x%x,%d rlen=%d\n", str,\
+ (init_bits << np->code_length) +\
+ peek_var_bits(np->code_length),\
+ initial_bits + np->code_length,\
+ np->run_length);\
+ skip_bits(np->code_length);\
+ }\
+ else\
+ { if_debug4('W', "%s code=0x%x,%d rlen=%d\n", str,\
+ peek_var_bits(clen), clen, np->run_length);\
+ skip_bits(clen);\
+ }\
+ runlen = np->run_length;\
+}
+
+/* Skip data bits for a white run. */
+/* rlen is either less than 64, or a multiple of 64. */
+#define skip_data(rlen, makeup_label)\
+ if ( (qbit -= rlen) < 0 )\
+ { q -= qbit >> 3, qbit &= 7;\
+ if ( rlen >= 64 ) goto makeup_label;\
+ }
+
+/* Invert data bits for a black run. */
+/* If rlen >= 64, execute makeup_action: this is to handle */
+/* makeup codes efficiently, since these are always a multiple of 64. */
+#define invert_data(rlen, black_byte, makeup_action, d)\
+ if ( rlen > qbit )\
+ { *q++ ^= (1 << qbit) - 1;\
+ rlen -= qbit;\
+ switch ( rlen >> 3 )\
+ {\
+ case 7: /* original rlen possibly >= 64 */\
+ if ( rlen + qbit >= 64 ) goto d;\
+ *q++ = black_byte;\
+ case 6: *q++ = black_byte;\
+ case 5: *q++ = black_byte;\
+ case 4: *q++ = black_byte;\
+ case 3: *q++ = black_byte;\
+ case 2: *q++ = black_byte;\
+ case 1: *q = black_byte;\
+ rlen &= 7;\
+ if ( !rlen ) { qbit = 0; break; }\
+ q++;\
+ case 0: /* know rlen != 0 */\
+ qbit = 8 - rlen;\
+ *q ^= 0xff << qbit;\
+ break;\
+ default: /* original rlen >= 64 */\
+d: memset(q, black_byte, rlen >> 3);\
+ q += rlen >> 3;\
+ rlen &= 7;\
+ if ( !rlen ) qbit = 0, q--;\
+ else qbit = 8 - rlen, *q ^= 0xff << qbit;\
+ makeup_action;\
+ }\
+ }\
+ else\
+ qbit -= rlen,\
+ *q ^= ((1 << rlen) - 1) << qbit
+
+/* Buffer refill for CCITTFaxDecode filter */
+private int cf_decode_eol(P2(stream_CFD_state *, stream_cursor_read *));
+private int cf_decode_1d(P2(stream_CFD_state *, stream_cursor_read *));
+private int cf_decode_2d(P2(stream_CFD_state *, stream_cursor_read *));
+private int cf_decode_uncompressed(P2(stream_CFD_state *, stream_cursor_read *));
+private int
+s_CFD_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last)
+{
+ stream_CFD_state *const ss = (stream_CFD_state *) st;
+ int wstop = ss->raster - 1;
+ int eol_count = ss->eol_count;
+ int k_left = ss->k_left;
+ int rows_left = ss->rows_left;
+ int status = 0;
+
+#ifdef DEBUG
+ const byte *rstart = pr->ptr;
+ const byte *wstart = pw->ptr;
+
+#endif
+
+ top:
+#ifdef DEBUG
+ {
+ hcd_declare_state;
+ hcd_load_state();
+ if_debug8('w', "\
+[w]CFD_process top: eol_count=%d, k_left=%d, rows_left=%d\n\
+ bits=0x%lx, bits_left=%d, read %u, wrote %u%s\n",
+ eol_count, k_left, rows_left,
+ (ulong) bits, bits_left,
+ (uint) (p - rstart), (uint) (pw->ptr - wstart),
+ (ss->skipping_damage ? ", skipping damage" : ""));
+ }
+#endif
+ if (ss->skipping_damage) { /* Skip until we reach an EOL. */
+ hcd_declare_state;
+ int skip;
+
+ status = 0;
+ do {
+ switch ((skip = cf_decode_eol(ss, pr))) {
+ default: /* not EOL */
+ hcd_load_state();
+ skip_bits(-skip);
+ hcd_store_state();
+ continue;
+ case 0: /* need more input */
+ goto out;
+ case 1: /* EOL */
+ { /* Back up over the EOL. */
+ hcd_load_state();
+ bits_left += run_eol_code_length;
+ hcd_store_state();
+ }
+ ss->skipping_damage = false;
+ }
+ }
+ while (ss->skipping_damage);
+ ss->damaged_rows++;
+ }
+ /*
+ * Check for a completed input scan line. This isn't quite as
+ * simple as it seems, because we could have run out of input data
+ * between a makeup code and a 0-length termination code, or in a
+ * 2-D line before a final horizontal code with a 0-length second
+ * run. There's probably a way to think about this situation that
+ * doesn't require a special check, but I haven't found it yet.
+ */
+ if (ss->wpos == wstop && ss->cbit <= (-ss->Columns & 7) &&
+ (k_left == 0 ? !(ss->run_color & ~1) : ss->run_color == 0)
+ ) { /* Check for completed data to be copied to the client. */
+ /* (We could avoid the extra copy step for 1-D, but */
+ /* it's simpler not to, and it doesn't cost much.) */
+ if (ss->rpos < ss->wpos) {
+ stream_cursor_read cr;
+
+ cr.ptr = ss->lbuf + ss->rpos;
+ cr.limit = ss->lbuf + ss->wpos;
+ status = stream_move(&cr, pw);
+ ss->rpos = cr.ptr - ss->lbuf;
+ if (status)
+ goto out;
+ }
+ if (rows_left > 0 && --rows_left == 0) {
+ status = EOFC;
+ goto out;
+ }
+ if (ss->K != 0) {
+ byte *prev_bits = ss->lprev;
+
+ ss->lprev = ss->lbuf;
+ ss->lbuf = prev_bits;
+ if (ss->K > 0)
+ k_left = (k_left == 0 ? ss->K : k_left) - 1;
+ }
+ ss->rpos = ss->wpos = -1;
+ ss->eol_count = eol_count = 0;
+ ss->cbit = 0;
+ ss->invert = (ss->BlackIs1 ? 0 : 0xff);
+ memset(ss->lbuf, ss->invert, wstop + 1);
+ ss->run_color = 0;
+ /*
+ * If EndOfLine is true, we want to include the byte padding
+ * in the string of initial zeros in the EOL. If EndOfLine
+ * is false, we aren't sure what we should do....
+ */
+ if (ss->EncodedByteAlign & !ss->EndOfLine)
+ ss->bits_left &= ~7;
+ }
+ /* If we're between scan lines, scan for EOLs. */
+ if (ss->wpos < 0) {
+ while ((status = cf_decode_eol(ss, pr)) > 0) {
+ if_debug0('w', "[w]EOL\n");
+ /* If we are in a Group 3 mixed regime, */
+ /* check the next bit for 1- vs. 2-D. */
+ if (ss->K > 0) {
+ hcd_declare_state;
+ hcd_load_state();
+ ensure_bits(1, out); /* can't fail */
+ k_left = (peek_bits(1) ? 0 : 1);
+ skip_bits(1);
+ hcd_store_state();
+ }
+ ++eol_count;
+ /*
+ * According to Adobe, the decoder should always check for
+ * the EOD sequence, regardless of EndOfBlock: the Red Book's
+ * documentation of EndOfBlock is wrong.
+ */
+ if (eol_count == (ss->K < 0 ? 2 : 6)) {
+ status = EOFC;
+ goto out;
+ }
+ }
+ if (status == 0) /* input empty while scanning EOLs */
+ goto out;
+ switch (eol_count) {
+ case 0:
+ if (ss->EndOfLine) { /* EOL is required, but none is present. */
+ status = ERRC;
+ goto check;
+ }
+ case 1:
+ break;
+ default:
+ status = ERRC;
+ goto check;
+ }
+ }
+ /* Now decode actual data. */
+ if (k_left < 0) {
+ if_debug0('w', "[w2]new row\n");
+ status = cf_decode_2d(ss, pr);
+ } else if (k_left == 0) {
+ if_debug0('w', "[w1]new row\n");
+ status = cf_decode_1d(ss, pr);
+ } else {
+ if_debug1('w', "[w1]new 2-D row, %d left\n", k_left);
+ status = cf_decode_2d(ss, pr);
+ }
+ if_debug3('w', "[w]CFD status = %d, wpos = %d, cbit = %d\n",
+ status, ss->wpos, ss->cbit);
+ check:switch (status) {
+ case 1: /* output full */
+ goto top;
+ case ERRC:
+ /* Check for special handling of damaged rows. */
+ if (ss->damaged_rows >= ss->DamagedRowsBeforeError ||
+ !(ss->EndOfLine && ss->K >= 0)
+ )
+ break;
+ /* Substitute undamaged data if appropriate. */
+/****** NOT IMPLEMENTED YET ******/
+ {
+ ss->wpos = wstop;
+ ss->cbit = -ss->Columns & 7;
+ ss->run_color = 0;
+ }
+ ss->skipping_damage = true;
+ goto top;
+ default:
+ ss->damaged_rows = 0; /* finished a good row */
+ }
+ out:ss->k_left = k_left;
+ ss->rows_left = rows_left;
+ ss->eol_count = eol_count;
+ return status;
+}
+
+/*
+ * Decode a leading EOL, if any.
+ * If an EOL is present, skip over it and return 1;
+ * if no EOL is present, read no input and return -N, where N is the
+ * number of initial bits that can be skipped in the search for an EOL;
+ * if more input is needed, return 0.
+ * Note that if we detected an EOL, we know that we can back up over it;
+ * if we detected an N-bit non-EOL, we know that at least N bits of data
+ * are available in the buffer.
+ */
+private int
+cf_decode_eol(stream_CFD_state * ss, stream_cursor_read * pr)
+{
+ hcd_declare_state;
+ int zeros;
+ int look_ahead;
+
+ hcd_load_state();
+ for (zeros = 0; zeros < run_eol_code_length - 1; zeros++) {
+ ensure_bits(1, out);
+ if (peek_bits(1))
+ return -(zeros + 1);
+ skip_bits(1);
+ }
+ /* We definitely have an EOL. Skip further zero bits. */
+ look_ahead = (ss->K > 0 ? 2 : 1);
+ for (;;) {
+ ensure_bits(look_ahead, back);
+ if (peek_bits(1))
+ break;
+ skip_bits(1);
+ }
+ skip_bits(1);
+ hcd_store_state();
+ return 1;
+ back: /*
+ * We ran out of data while skipping zeros.
+ * We know we are at a byte boundary, and have just skipped
+ * at least run_eol_code_length - 1 zeros. However,
+ * bits_left may be 1 if look_ahead == 2.
+ */
+ bits &= (1 << bits_left) - 1;
+ bits_left += run_eol_code_length - 1;
+ hcd_store_state();
+ out:return 0;
+}
+
+/* Decode a 1-D scan line. */
+private int
+cf_decode_1d(stream_CFD_state * ss, stream_cursor_read * pr)
+{
+ cfd_declare_state;
+ byte black_byte = (ss->BlackIs1 ? 0xff : 0);
+ int end_bit = -ss->Columns & 7;
+ byte *stop = ss->lbuf - 1 + ss->raster;
+ int run_color = ss->run_color;
+ int status;
+ int bcnt;
+
+ cfd_load_state();
+ if_debug1('w', "[w1]entry run_color = %d\n", ss->run_color);
+ if (ss->run_color > 0)
+ goto db;
+ else
+ goto dw;
+#define q_at_stop() (q >= stop && (qbit <= end_bit || q > stop))
+ top:run_color = 0;
+ if (q_at_stop())
+ goto done;
+ dw: /* Decode a white run. */
+ get_run(cf_white_decode, cfd_white_initial_bits, bcnt, "[w1]white", out0);
+ if (bcnt < 0) { /* exceptional situation */
+ switch (bcnt) {
+ case run_uncompressed: /* Uncompressed data. */
+ cfd_store_state();
+ bcnt = cf_decode_uncompressed(ss, pr);
+ if (bcnt < 0)
+ return bcnt;
+ cfd_load_state();
+ if (bcnt)
+ goto db;
+ else
+ goto dw;
+ /*case run_error: */
+ /*case run_zeros: *//* Premature end-of-line. */
+ default:
+ status = ERRC;
+ goto out;
+ }
+ }
+ skip_data(bcnt, dwx);
+ if (q_at_stop()) {
+ run_color = 0; /* not inside a run */
+ goto done;
+ }
+ run_color = 1;
+ db: /* Decode a black run. */
+ get_run(cf_black_decode, cfd_black_initial_bits, bcnt, "[w1]black", out1);
+ if (bcnt < 0) { /* All exceptional codes are invalid here. */
+/****** WRONG, uncompressed IS ALLOWED ******/
+ status = ERRC;
+ goto out;
+ }
+ /* Invert bits designated by black run. */
+ invert_data(bcnt, black_byte, goto dbx, idb);
+ goto top;
+ dwx: /* If we run out of data after a makeup code, */
+ /* note that we are still processing a white run. */
+ run_color = -1;
+ goto dw;
+ dbx: /* If we run out of data after a makeup code, */
+ /* note that we are still processing a black run. */
+ run_color = 2;
+ goto db;
+ done:if (q > stop || qbit < end_bit)
+ status = ERRC;
+ else
+ status = 1;
+ out:cfd_store_state();
+ ss->run_color = run_color;
+ if_debug1('w', "[w1]exit run_color = %d\n", run_color);
+ return status;
+ out0: /* We already set run_color to 0 or -1. */
+ status = 0;
+ goto out;
+ out1: /* We already set run_color to 1 or 2. */
+ status = 0;
+ goto out;
+}
+
+/* Decode a 2-D scan line. */
+private int
+cf_decode_2d(stream_CFD_state * ss, stream_cursor_read * pr)
+{
+ cfd_declare_state;
+ byte invert_white = (ss->BlackIs1 ? 0 : 0xff);
+ byte black_byte = ~invert_white;
+ byte invert = ss->invert;
+ int end_count = -ss->Columns & 7;
+ uint raster = ss->raster;
+ byte *q0 = ss->lbuf;
+ byte *prev_q01 = ss->lprev + 1;
+ byte *endptr = q0 - 1 + raster;
+ int init_count = raster << 3;
+ register int count;
+ int rlen;
+ int status;
+
+ cfd_load_state();
+ count = ((endptr - q) << 3) + qbit;
+ endptr[1] = 0xa0; /* a byte with some 0s and some 1s, */
+ /* to ensure run scan will stop */
+ if_debug1('W', "[w2]raster=%d\n", raster);
+ switch (ss->run_color) {
+ case -2:
+ ss->run_color = 0;
+ goto hww;
+ case -1:
+ ss->run_color = 0;
+ goto hbw;
+ case 1:
+ ss->run_color = 0;
+ goto hwb;
+ case 2:
+ ss->run_color = 0;
+ goto hbb;
+ /*case 0: */
+ }
+ top:if (count <= end_count) {
+ status = (count < end_count ? ERRC : 1);
+ goto out;
+ }
+ /* If invert == invert_white, white and black have their */
+ /* correct meanings; if invert == ~invert_white, */
+ /* black and white are interchanged. */
+ if_debug1('W', "[w2]%4d:\n", count);
+#ifdef DEBUG
+ /* Check the invariant between q, qbit, and count. */
+ {
+ int pcount = (endptr - q) * 8 + qbit;
+
+ if (pcount != count)
+ dlprintf2("[w2]Error: count=%d pcount=%d\n",
+ count, pcount);
+ }
+#endif
+ /* We could just use get_run here, but we can do better: */
+ ensure_bits(3, out0);
+#define vertical_0 (countof(cf2_run_vertical) / 2)
+ switch (peek_bits(3)) {
+ default /*4..7 */ : /* vertical(0) */
+ skip_bits(1);
+ rlen = vertical_0;
+ break;
+ case 2: /* vertical(+1) */
+ skip_bits(3);
+ rlen = vertical_0 + 1;
+ break;
+ case 3: /* vertical(-1) */
+ skip_bits(3);
+ rlen = vertical_0 - 1;
+ break;
+ case 1: /* horizontal */
+ skip_bits(3);
+ if (invert == invert_white)
+ goto hww;
+ else
+ goto hbb;
+ case 0: /* everything else */
+ get_run(cf_2d_decode, cfd_2d_initial_bits, rlen,
+ "[w2]", out0);
+ /* rlen may be run2_pass, run_uncompressed, or */
+ /* 0..countof(cf2_run_vertical)-1. */
+ if (rlen < 0)
+ switch (rlen) {
+ case run2_pass:
+ break;
+ case run_uncompressed:
+ {
+ int which;
+
+ cfd_store_state();
+ which = cf_decode_uncompressed(ss, pr);
+ if (which < 0) {
+ status = which;
+ goto out;
+ }
+ cfd_load_state();
+/****** ADJUST count ******/
+ invert = (which ? ~invert_white : invert_white);
+ }
+ goto top;
+ default: /* run_error, run_zeros */
+ status = ERRC;
+ goto out;
+ }
+ }
+ /* Interpreting the run requires scanning the */
+ /* previous ('reference') line. */
+ {
+ int prev_count = count;
+ byte prev_data;
+ int dlen;
+ static const byte count_bit[8] =
+ {0x80, 1, 2, 4, 8, 0x10, 0x20, 0x40};
+ byte *prev_q = prev_q01 + (q - q0);
+ int plen;
+
+ if (!(count & 7))
+ prev_q++; /* because of skip macros */
+ prev_data = prev_q[-1] ^ invert;
+ /* Find the b1 transition. */
+ if ((prev_data & count_bit[prev_count & 7]) &&
+ (prev_count < init_count || invert != invert_white)
+ ) { /* Look for changing white first. */
+ if_debug1('W', " data=0x%x", prev_data);
+ skip_black_pixels(prev_data, prev_q,
+ prev_count, invert, plen);
+ if (prev_count < end_count) /* overshot */
+ prev_count = end_count;
+ if_debug1('W', " b1 other=%d", prev_count);
+ }
+ if (prev_count != end_count) {
+ if_debug1('W', " data=0x%x", prev_data);
+ skip_white_pixels(prev_data, prev_q,
+ prev_count, invert, plen);
+ if (prev_count < end_count) /* overshot */
+ prev_count = end_count;
+ if_debug1('W', " b1 same=%d", prev_count);
+ }
+ /* b1 = prev_count; */
+ if (rlen == run2_pass) { /* Pass mode. Find b2. */
+ if (prev_count != end_count) {
+ if_debug1('W', " data=0x%x", prev_data);
+ skip_black_pixels(prev_data, prev_q,
+ prev_count, invert, plen);
+ if (prev_count < end_count) /* overshot */
+ prev_count = end_count;
+ }
+ /* b2 = prev_count; */
+ if_debug2('W', " b2=%d, pass %d\n",
+ prev_count, count - prev_count);
+ } else { /* Vertical coding. */
+ /* Remember that count counts *down*. */
+ prev_count += rlen - vertical_0; /* a1 */
+ if_debug2('W', " vertical %d -> %d\n",
+ rlen - vertical_0, prev_count);
+ }
+ /* Now either invert or skip from count */
+ /* to prev_count, and reset count. */
+ if (invert == invert_white) { /* Skip data bits. */
+ q = endptr - (prev_count >> 3);
+ qbit = prev_count & 7;
+ } else { /* Invert data bits. */
+ dlen = count - prev_count;
+ invert_data(dlen, black_byte, DO_NOTHING, idd);
+ }
+ count = prev_count;
+ if (rlen >= 0) /* vertical mode */
+ invert = ~invert; /* polarity changes */
+ }
+ goto top;
+ out:cfd_store_state();
+ ss->invert = invert;
+ return status;
+ out0:status = 0;
+ goto out;
+ /*
+ * We handle horizontal decoding here, so that we can
+ * branch back into it if we run out of input data.
+ */
+ /* White, then black. */
+ hww:get_run(cf_white_decode, cfd_white_initial_bits, rlen,
+ " white", outww);
+ if ((count -= rlen) < end_count) {
+ status = ERRC;
+ goto out;
+ }
+ skip_data(rlen, hww);
+ /* Handle the second half of a white-black horizontal code. */
+ hwb:get_run(cf_black_decode, cfd_black_initial_bits, rlen,
+ " black", outwb);
+ if ((count -= rlen) < end_count) {
+ status = ERRC;
+ goto out;
+ }
+ invert_data(rlen, black_byte, goto hwb, ihwb);
+ goto top;
+ outww:ss->run_color = -2;
+ goto out0;
+ outwb:ss->run_color = 1;
+ goto out0;
+ /* Black, then white. */
+ hbb:get_run(cf_black_decode, cfd_black_initial_bits, rlen,
+ " black", outbb);
+ if ((count -= rlen) < end_count) {
+ status = ERRC;
+ goto out;
+ }
+ invert_data(rlen, black_byte, goto hbb, ihbb);
+ /* Handle the second half of a black-white horizontal code. */
+ hbw:get_run(cf_white_decode, cfd_white_initial_bits, rlen,
+ " white", outbw);
+ if ((count -= rlen) < end_count) {
+ status = ERRC;
+ goto out;
+ }
+ skip_data(rlen, hbw);
+ goto top;
+ outbb:ss->run_color = 2;
+ goto out0;
+ outbw:ss->run_color = -1;
+ goto out0;
+}
+
+#if 1 /*************** */
+private int
+cf_decode_uncompressed(stream_CFD_state * ss, stream_cursor_read * pr)
+{
+ return ERRC;
+}
+#else /*************** */
+
+/* Decode uncompressed data. */
+/* (Not tested: no sample data available!) */
+/****** DOESN'T CHECK FOR OVERFLOWING SCAN LINE ******/
+private int
+cf_decode_uncompressed(stream * s)
+{
+ cfd_declare_state;
+ const cfd_node *np;
+ int clen, rlen;
+
+ cfd_load_state();
+ while (1) {
+ ensure_bits(cfd_uncompressed_initial_bits, NOOUT);
+ np = &cf_uncompressed_decode[peek_bits(cfd_uncompressed_initial_bits)];
+ clen = np->code_length;
+ rlen = np->run_length;
+ if (clen > cfd_uncompressed_initial_bits) { /* Must be an exit code. */
+ break;
+ }
+ if (rlen == cfd_uncompressed_initial_bits) { /* Longest representable white run */
+ if_debug1('W', "[wu]%d\n", rlen);
+ if ((qbit -= cfd_uncompressed_initial_bits) < 0)
+ qbit += 8, q++;
+ } else {
+ if_debug1('W', "[wu]%d+1\n", rlen);
+ if (qbit -= rlen < 0)
+ qbit += 8, q++;
+ *q ^= 1 << qbit;
+ }
+ skip_bits(clen);
+ }
+ clen -= cfd_uncompressed_initial_bits;
+ skip_bits(cfd_uncompressed_initial_bits);
+ ensure_bits(clen, NOOUT);
+ np = &cf_uncompressed_decode[rlen + peek_var_bits(clen)];
+ rlen = np->run_length;
+ skip_bits(np->code_length);
+ if_debug1('w', "[wu]exit %d\n", rlen);
+ if (rlen >= 0) { /* Valid exit code, rlen = 2 * run length + next polarity */
+ if ((qbit -= rlen >> 1) < 0)
+ qbit += 8, q++;
+ rlen &= 1;
+ }
+ out:
+/******* WRONG ******/
+ cfd_store_state();
+ return rlen;
+}
+
+#endif /*************** */
+
+/* Stream template */
+const stream_template s_CFD_template =
+{&st_CFD_state, s_CFD_init, s_CFD_process, 1, 1, s_CFD_release,
+ s_CFD_set_defaults
+};
diff --git a/pstoraster/scfdtab.c b/pstoraster/scfdtab.c
new file mode 100644
index 000000000..1d6dc99f7
--- /dev/null
+++ b/pstoraster/scfdtab.c
@@ -0,0 +1,942 @@
+/* Copyright (C) 1992, 1993, 1998 Aladdin Enterprises. All rights reserved. */
+
+/* This file was generated automatically. It is governed by the same terms */
+/* as the files scftab.c and scfdgen.c from which it was derived. */
+/* Consult those files for the licensing terms and conditions. */
+
+/*$Id$ */
+/* Tables for CCITTFaxDecode filter. */
+
+#include "std.h"
+#include "scommon.h" /* for scf.h */
+#include "scf.h"
+
+/* White decoding table. */
+const cfd_node cf_white_decode[] =
+{
+ {256, 12},
+ {272, 12},
+ {29, 8},
+ {30, 8},
+ {45, 8},
+ {46, 8},
+ {22, 7},
+ {22, 7},
+ {23, 7},
+ {23, 7},
+ {47, 8},
+ {48, 8},
+ {13, 6},
+ {13, 6},
+ {13, 6},
+ {13, 6},
+ {20, 7},
+ {20, 7},
+ {33, 8},
+ {34, 8},
+ {35, 8},
+ {36, 8},
+ {37, 8},
+ {38, 8},
+ {19, 7},
+ {19, 7},
+ {31, 8},
+ {32, 8},
+ {1, 6},
+ {1, 6},
+ {1, 6},
+ {1, 6},
+ {12, 6},
+ {12, 6},
+ {12, 6},
+ {12, 6},
+ {53, 8},
+ {54, 8},
+ {26, 7},
+ {26, 7},
+ {39, 8},
+ {40, 8},
+ {41, 8},
+ {42, 8},
+ {43, 8},
+ {44, 8},
+ {21, 7},
+ {21, 7},
+ {28, 7},
+ {28, 7},
+ {61, 8},
+ {62, 8},
+ {63, 8},
+ {0, 8},
+ {320, 8},
+ {384, 8},
+ {10, 5},
+ {10, 5},
+ {10, 5},
+ {10, 5},
+ {10, 5},
+ {10, 5},
+ {10, 5},
+ {10, 5},
+ {11, 5},
+ {11, 5},
+ {11, 5},
+ {11, 5},
+ {11, 5},
+ {11, 5},
+ {11, 5},
+ {11, 5},
+ {27, 7},
+ {27, 7},
+ {59, 8},
+ {60, 8},
+ {288, 9},
+ {290, 9},
+ {18, 7},
+ {18, 7},
+ {24, 7},
+ {24, 7},
+ {49, 8},
+ {50, 8},
+ {51, 8},
+ {52, 8},
+ {25, 7},
+ {25, 7},
+ {55, 8},
+ {56, 8},
+ {57, 8},
+ {58, 8},
+ {192, 6},
+ {192, 6},
+ {192, 6},
+ {192, 6},
+ {1664, 6},
+ {1664, 6},
+ {1664, 6},
+ {1664, 6},
+ {448, 8},
+ {512, 8},
+ {292, 9},
+ {640, 8},
+ {576, 8},
+ {294, 9},
+ {296, 9},
+ {298, 9},
+ {300, 9},
+ {302, 9},
+ {256, 7},
+ {256, 7},
+ {2, 4},
+ {2, 4},
+ {2, 4},
+ {2, 4},
+ {2, 4},
+ {2, 4},
+ {2, 4},
+ {2, 4},
+ {2, 4},
+ {2, 4},
+ {2, 4},
+ {2, 4},
+ {2, 4},
+ {2, 4},
+ {2, 4},
+ {2, 4},
+ {3, 4},
+ {3, 4},
+ {3, 4},
+ {3, 4},
+ {3, 4},
+ {3, 4},
+ {3, 4},
+ {3, 4},
+ {3, 4},
+ {3, 4},
+ {3, 4},
+ {3, 4},
+ {3, 4},
+ {3, 4},
+ {3, 4},
+ {3, 4},
+ {128, 5},
+ {128, 5},
+ {128, 5},
+ {128, 5},
+ {128, 5},
+ {128, 5},
+ {128, 5},
+ {128, 5},
+ {8, 5},
+ {8, 5},
+ {8, 5},
+ {8, 5},
+ {8, 5},
+ {8, 5},
+ {8, 5},
+ {8, 5},
+ {9, 5},
+ {9, 5},
+ {9, 5},
+ {9, 5},
+ {9, 5},
+ {9, 5},
+ {9, 5},
+ {9, 5},
+ {16, 6},
+ {16, 6},
+ {16, 6},
+ {16, 6},
+ {17, 6},
+ {17, 6},
+ {17, 6},
+ {17, 6},
+ {4, 4},
+ {4, 4},
+ {4, 4},
+ {4, 4},
+ {4, 4},
+ {4, 4},
+ {4, 4},
+ {4, 4},
+ {4, 4},
+ {4, 4},
+ {4, 4},
+ {4, 4},
+ {4, 4},
+ {4, 4},
+ {4, 4},
+ {4, 4},
+ {5, 4},
+ {5, 4},
+ {5, 4},
+ {5, 4},
+ {5, 4},
+ {5, 4},
+ {5, 4},
+ {5, 4},
+ {5, 4},
+ {5, 4},
+ {5, 4},
+ {5, 4},
+ {5, 4},
+ {5, 4},
+ {5, 4},
+ {5, 4},
+ {14, 6},
+ {14, 6},
+ {14, 6},
+ {14, 6},
+ {15, 6},
+ {15, 6},
+ {15, 6},
+ {15, 6},
+ {64, 5},
+ {64, 5},
+ {64, 5},
+ {64, 5},
+ {64, 5},
+ {64, 5},
+ {64, 5},
+ {64, 5},
+ {6, 4},
+ {6, 4},
+ {6, 4},
+ {6, 4},
+ {6, 4},
+ {6, 4},
+ {6, 4},
+ {6, 4},
+ {6, 4},
+ {6, 4},
+ {6, 4},
+ {6, 4},
+ {6, 4},
+ {6, 4},
+ {6, 4},
+ {6, 4},
+ {7, 4},
+ {7, 4},
+ {7, 4},
+ {7, 4},
+ {7, 4},
+ {7, 4},
+ {7, 4},
+ {7, 4},
+ {7, 4},
+ {7, 4},
+ {7, 4},
+ {7, 4},
+ {7, 4},
+ {7, 4},
+ {7, 4},
+ {7, 4},
+ {-2, 3},
+ {-2, 3},
+ {-1, 0},
+ {-1, 0},
+ {-1, 0},
+ {-1, 0},
+ {-1, 0},
+ {-1, 0},
+ {-1, 0},
+ {-1, 0},
+ {-1, 0},
+ {-1, 0},
+ {-1, 0},
+ {-1, 0},
+ {-1, 0},
+ {-3, 4},
+ {1792, 3},
+ {1792, 3},
+ {1984, 4},
+ {2048, 4},
+ {2112, 4},
+ {2176, 4},
+ {2240, 4},
+ {2304, 4},
+ {1856, 3},
+ {1856, 3},
+ {1920, 3},
+ {1920, 3},
+ {2368, 4},
+ {2432, 4},
+ {2496, 4},
+ {2560, 4},
+ {1472, 1},
+ {1536, 1},
+ {1600, 1},
+ {1728, 1},
+ {704, 1},
+ {768, 1},
+ {832, 1},
+ {896, 1},
+ {960, 1},
+ {1024, 1},
+ {1088, 1},
+ {1152, 1},
+ {1216, 1},
+ {1280, 1},
+ {1344, 1},
+ {1408, 1}
+};
+
+/* Black decoding table. */
+const cfd_node cf_black_decode[] =
+{
+ {128, 12},
+ {160, 13},
+ {224, 12},
+ {256, 12},
+ {10, 7},
+ {11, 7},
+ {288, 12},
+ {12, 7},
+ {9, 6},
+ {9, 6},
+ {8, 6},
+ {8, 6},
+ {7, 5},
+ {7, 5},
+ {7, 5},
+ {7, 5},
+ {6, 4},
+ {6, 4},
+ {6, 4},
+ {6, 4},
+ {6, 4},
+ {6, 4},
+ {6, 4},
+ {6, 4},
+ {5, 4},
+ {5, 4},
+ {5, 4},
+ {5, 4},
+ {5, 4},
+ {5, 4},
+ {5, 4},
+ {5, 4},
+ {1, 3},
+ {1, 3},
+ {1, 3},
+ {1, 3},
+ {1, 3},
+ {1, 3},
+ {1, 3},
+ {1, 3},
+ {1, 3},
+ {1, 3},
+ {1, 3},
+ {1, 3},
+ {1, 3},
+ {1, 3},
+ {1, 3},
+ {1, 3},
+ {4, 3},
+ {4, 3},
+ {4, 3},
+ {4, 3},
+ {4, 3},
+ {4, 3},
+ {4, 3},
+ {4, 3},
+ {4, 3},
+ {4, 3},
+ {4, 3},
+ {4, 3},
+ {4, 3},
+ {4, 3},
+ {4, 3},
+ {4, 3},
+ {3, 2},
+ {3, 2},
+ {3, 2},
+ {3, 2},
+ {3, 2},
+ {3, 2},
+ {3, 2},
+ {3, 2},
+ {3, 2},
+ {3, 2},
+ {3, 2},
+ {3, 2},
+ {3, 2},
+ {3, 2},
+ {3, 2},
+ {3, 2},
+ {3, 2},
+ {3, 2},
+ {3, 2},
+ {3, 2},
+ {3, 2},
+ {3, 2},
+ {3, 2},
+ {3, 2},
+ {3, 2},
+ {3, 2},
+ {3, 2},
+ {3, 2},
+ {3, 2},
+ {3, 2},
+ {3, 2},
+ {3, 2},
+ {2, 2},
+ {2, 2},
+ {2, 2},
+ {2, 2},
+ {2, 2},
+ {2, 2},
+ {2, 2},
+ {2, 2},
+ {2, 2},
+ {2, 2},
+ {2, 2},
+ {2, 2},
+ {2, 2},
+ {2, 2},
+ {2, 2},
+ {2, 2},
+ {2, 2},
+ {2, 2},
+ {2, 2},
+ {2, 2},
+ {2, 2},
+ {2, 2},
+ {2, 2},
+ {2, 2},
+ {2, 2},
+ {2, 2},
+ {2, 2},
+ {2, 2},
+ {2, 2},
+ {2, 2},
+ {2, 2},
+ {2, 2},
+ {-2, 4},
+ {-2, 4},
+ {-1, 0},
+ {-1, 0},
+ {-1, 0},
+ {-1, 0},
+ {-1, 0},
+ {-1, 0},
+ {-1, 0},
+ {-1, 0},
+ {-1, 0},
+ {-1, 0},
+ {-1, 0},
+ {-1, 0},
+ {-1, 0},
+ {-3, 5},
+ {1792, 4},
+ {1792, 4},
+ {1984, 5},
+ {2048, 5},
+ {2112, 5},
+ {2176, 5},
+ {2240, 5},
+ {2304, 5},
+ {1856, 4},
+ {1856, 4},
+ {1920, 4},
+ {1920, 4},
+ {2368, 5},
+ {2432, 5},
+ {2496, 5},
+ {2560, 5},
+ {18, 3},
+ {18, 3},
+ {18, 3},
+ {18, 3},
+ {18, 3},
+ {18, 3},
+ {18, 3},
+ {18, 3},
+ {52, 5},
+ {52, 5},
+ {640, 6},
+ {704, 6},
+ {768, 6},
+ {832, 6},
+ {55, 5},
+ {55, 5},
+ {56, 5},
+ {56, 5},
+ {1280, 6},
+ {1344, 6},
+ {1408, 6},
+ {1472, 6},
+ {59, 5},
+ {59, 5},
+ {60, 5},
+ {60, 5},
+ {1536, 6},
+ {1600, 6},
+ {24, 4},
+ {24, 4},
+ {24, 4},
+ {24, 4},
+ {25, 4},
+ {25, 4},
+ {25, 4},
+ {25, 4},
+ {1664, 6},
+ {1728, 6},
+ {320, 5},
+ {320, 5},
+ {384, 5},
+ {384, 5},
+ {448, 5},
+ {448, 5},
+ {512, 6},
+ {576, 6},
+ {53, 5},
+ {53, 5},
+ {54, 5},
+ {54, 5},
+ {896, 6},
+ {960, 6},
+ {1024, 6},
+ {1088, 6},
+ {1152, 6},
+ {1216, 6},
+ {64, 3},
+ {64, 3},
+ {64, 3},
+ {64, 3},
+ {64, 3},
+ {64, 3},
+ {64, 3},
+ {64, 3},
+ {13, 1},
+ {13, 1},
+ {13, 1},
+ {13, 1},
+ {13, 1},
+ {13, 1},
+ {13, 1},
+ {13, 1},
+ {13, 1},
+ {13, 1},
+ {13, 1},
+ {13, 1},
+ {13, 1},
+ {13, 1},
+ {13, 1},
+ {13, 1},
+ {23, 4},
+ {23, 4},
+ {50, 5},
+ {51, 5},
+ {44, 5},
+ {45, 5},
+ {46, 5},
+ {47, 5},
+ {57, 5},
+ {58, 5},
+ {61, 5},
+ {256, 5},
+ {16, 3},
+ {16, 3},
+ {16, 3},
+ {16, 3},
+ {17, 3},
+ {17, 3},
+ {17, 3},
+ {17, 3},
+ {48, 5},
+ {49, 5},
+ {62, 5},
+ {63, 5},
+ {30, 5},
+ {31, 5},
+ {32, 5},
+ {33, 5},
+ {40, 5},
+ {41, 5},
+ {22, 4},
+ {22, 4},
+ {14, 1},
+ {14, 1},
+ {14, 1},
+ {14, 1},
+ {14, 1},
+ {14, 1},
+ {14, 1},
+ {14, 1},
+ {14, 1},
+ {14, 1},
+ {14, 1},
+ {14, 1},
+ {14, 1},
+ {14, 1},
+ {14, 1},
+ {14, 1},
+ {15, 2},
+ {15, 2},
+ {15, 2},
+ {15, 2},
+ {15, 2},
+ {15, 2},
+ {15, 2},
+ {15, 2},
+ {128, 5},
+ {192, 5},
+ {26, 5},
+ {27, 5},
+ {28, 5},
+ {29, 5},
+ {19, 4},
+ {19, 4},
+ {20, 4},
+ {20, 4},
+ {34, 5},
+ {35, 5},
+ {36, 5},
+ {37, 5},
+ {38, 5},
+ {39, 5},
+ {21, 4},
+ {21, 4},
+ {42, 5},
+ {43, 5},
+ {0, 3},
+ {0, 3},
+ {0, 3},
+ {0, 3}
+};
+
+/* 2-D decoding table. */
+const cfd_node cf_2d_decode[] =
+{
+ {128, 11},
+ {144, 10},
+ {6, 7},
+ {0, 7},
+ {5, 6},
+ {5, 6},
+ {1, 6},
+ {1, 6},
+ {-4, 4},
+ {-4, 4},
+ {-4, 4},
+ {-4, 4},
+ {-4, 4},
+ {-4, 4},
+ {-4, 4},
+ {-4, 4},
+ {-5, 3},
+ {-5, 3},
+ {-5, 3},
+ {-5, 3},
+ {-5, 3},
+ {-5, 3},
+ {-5, 3},
+ {-5, 3},
+ {-5, 3},
+ {-5, 3},
+ {-5, 3},
+ {-5, 3},
+ {-5, 3},
+ {-5, 3},
+ {-5, 3},
+ {-5, 3},
+ {4, 3},
+ {4, 3},
+ {4, 3},
+ {4, 3},
+ {4, 3},
+ {4, 3},
+ {4, 3},
+ {4, 3},
+ {4, 3},
+ {4, 3},
+ {4, 3},
+ {4, 3},
+ {4, 3},
+ {4, 3},
+ {4, 3},
+ {4, 3},
+ {2, 3},
+ {2, 3},
+ {2, 3},
+ {2, 3},
+ {2, 3},
+ {2, 3},
+ {2, 3},
+ {2, 3},
+ {2, 3},
+ {2, 3},
+ {2, 3},
+ {2, 3},
+ {2, 3},
+ {2, 3},
+ {2, 3},
+ {2, 3},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {3, 1},
+ {-2, 4},
+ {-1, 0},
+ {-1, 0},
+ {-1, 0},
+ {-1, 0},
+ {-1, 0},
+ {-1, 0},
+ {-1, 0},
+ {-1, 0},
+ {-1, 0},
+ {-1, 0},
+ {-1, 0},
+ {-1, 0},
+ {-1, 0},
+ {-1, 0},
+ {-1, 0},
+ {-1, 0},
+ {-1, 0},
+ {-1, 0},
+ {-1, 0},
+ {-1, 0},
+ {-1, 0},
+ {-1, 0},
+ {-3, 3}
+};
+
+/* Uncompresssed decoding table. */
+const cfd_node cf_uncompressed_decode[] =
+{
+ {64, 12},
+ {5, 6},
+ {4, 5},
+ {4, 5},
+ {3, 4},
+ {3, 4},
+ {3, 4},
+ {3, 4},
+ {2, 3},
+ {2, 3},
+ {2, 3},
+ {2, 3},
+ {2, 3},
+ {2, 3},
+ {2, 3},
+ {2, 3},
+ {1, 2},
+ {1, 2},
+ {1, 2},
+ {1, 2},
+ {1, 2},
+ {1, 2},
+ {1, 2},
+ {1, 2},
+ {1, 2},
+ {1, 2},
+ {1, 2},
+ {1, 2},
+ {1, 2},
+ {1, 2},
+ {1, 2},
+ {1, 2},
+ {0, 1},
+ {0, 1},
+ {0, 1},
+ {0, 1},
+ {0, 1},
+ {0, 1},
+ {0, 1},
+ {0, 1},
+ {0, 1},
+ {0, 1},
+ {0, 1},
+ {0, 1},
+ {0, 1},
+ {0, 1},
+ {0, 1},
+ {0, 1},
+ {0, 1},
+ {0, 1},
+ {0, 1},
+ {0, 1},
+ {0, 1},
+ {0, 1},
+ {0, 1},
+ {0, 1},
+ {0, 1},
+ {0, 1},
+ {0, 1},
+ {0, 1},
+ {0, 1},
+ {0, 1},
+ {0, 1},
+ {0, 1},
+ {-1, 0},
+ {-1, 0},
+ {8, 6},
+ {9, 6},
+ {6, 5},
+ {6, 5},
+ {7, 5},
+ {7, 5},
+ {4, 4},
+ {4, 4},
+ {4, 4},
+ {4, 4},
+ {5, 4},
+ {5, 4},
+ {5, 4},
+ {5, 4},
+ {2, 3},
+ {2, 3},
+ {2, 3},
+ {2, 3},
+ {2, 3},
+ {2, 3},
+ {2, 3},
+ {2, 3},
+ {3, 3},
+ {3, 3},
+ {3, 3},
+ {3, 3},
+ {3, 3},
+ {3, 3},
+ {3, 3},
+ {3, 3},
+ {0, 2},
+ {0, 2},
+ {0, 2},
+ {0, 2},
+ {0, 2},
+ {0, 2},
+ {0, 2},
+ {0, 2},
+ {0, 2},
+ {0, 2},
+ {0, 2},
+ {0, 2},
+ {0, 2},
+ {0, 2},
+ {0, 2},
+ {0, 2},
+ {1, 2},
+ {1, 2},
+ {1, 2},
+ {1, 2},
+ {1, 2},
+ {1, 2},
+ {1, 2},
+ {1, 2},
+ {1, 2},
+ {1, 2},
+ {1, 2},
+ {1, 2},
+ {1, 2},
+ {1, 2},
+ {1, 2},
+ {1, 2}
+};
+
+/* Dummy executable code to pacify compilers. */
+void
+cfd_dummy(void)
+{
+}
diff --git a/pstoraster/scfe.c b/pstoraster/scfe.c
new file mode 100644
index 000000000..ec416bc66
--- /dev/null
+++ b/pstoraster/scfe.c
@@ -0,0 +1,536 @@
+/* Copyright (C) 1992, 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$ */
+/* CCITTFax encoding filter */
+#include "stdio_.h" /* includes std.h */
+#include "memory_.h"
+#include "gdebug.h"
+#include "strimpl.h"
+#include "scf.h"
+#include "scfx.h"
+
+/* ------ Macros and support routines ------ */
+
+/* Statistics */
+
+#ifdef DEBUG
+
+typedef struct stats_runs_s {
+ ulong termination[64];
+ ulong make_up[41];
+} stats_runs_t;
+private stats_runs_t stats_white_runs, stats_black_runs;
+
+#define COUNT_RUN(tab, i) (tab)[i]++;
+
+private void
+print_run_stats(const stats_runs_t * stats)
+{
+ int i;
+ ulong total;
+
+ for (i = 0, total = 0; i < 41; i++)
+ dprintf1(" %lu", stats->make_up[i]),
+ total += stats->make_up[i];
+ dprintf1(" total=%lu\n\t", total);
+ for (i = 0, total = 0; i < 64; i++)
+ dprintf1(" %lu", stats->termination[i]),
+ total += stats->termination[i];
+ dprintf1(" total=%lu\n", total);
+}
+
+#else /* !DEBUG */
+
+#define COUNT_RUN(cnt, i) DO_NOTHING
+
+#endif /* DEBUG */
+
+/* Put a run onto the output stream. */
+/* Free variables: q, bits, bits_left. */
+
+#define CF_PUT_RUN(ss, lenv, rt, stats)\
+BEGIN\
+ cfe_run rr;\
+\
+ if ( lenv >= 64 ) {\
+ hce_store_state();\
+ q = cf_put_long_run(ss, q, lenv, &rt);\
+ hce_load_state();\
+ lenv &= 63;\
+ }\
+ rr = rt.termination[lenv];\
+ COUNT_RUN(stats.termination, lenv);\
+ hc_put_value(ss, q, rr.code, rr.code_length);\
+END
+
+private byte *
+cf_put_long_run(stream_CFE_state * ss, byte * q, int lenv, const cf_runs * prt)
+{
+ hce_declare_state;
+ cfe_run rr;
+
+#ifdef DEBUG
+ stats_runs_t *pstats =
+ (prt == &cf_white_runs ? &stats_white_runs : &stats_black_runs);
+
+#endif
+
+ hce_load_state();
+ while (lenv >= 2560 + 64) {
+ rr = prt->make_up[40];
+ COUNT_RUN(pstats->make_up, 40);
+ hc_put_value(ss, q, rr.code, rr.code_length);
+ lenv -= 2560;
+ }
+ rr = prt->make_up[lenv >> 6];
+ COUNT_RUN(pstats->make_up, lenv >> 6);
+ hc_put_value(ss, q, rr.code, rr.code_length);
+ hce_store_state();
+ return q;
+}
+
+#define CF_PUT_WHITE_RUN(ss, lenv)\
+ CF_PUT_RUN(ss, lenv, cf_white_runs, stats_white_runs)
+
+#define CF_PUT_BLACK_RUN(ss, lenv)\
+ CF_PUT_RUN(ss, lenv, cf_black_runs, stats_black_runs)
+
+/* ------ CCITTFaxEncode ------ */
+
+private_st_CFE_state();
+
+private void s_CFE_release(P1(stream_state *));
+
+/* Set default parameter values. */
+private void
+s_CFE_set_defaults(register stream_state * st)
+{
+ stream_CFE_state *const ss = (stream_CFE_state *) st;
+
+ s_CFE_set_defaults_inline(ss);
+}
+
+/* Initialize CCITTFaxEncode filter */
+private int
+s_CFE_init(register stream_state * st)
+{
+ stream_CFE_state *const ss = (stream_CFE_state *) st;
+ int columns = ss->Columns;
+
+ /*
+ * The worst case for encoding is alternating white and black pixels.
+ * For 1-D encoding, the worst case is 9 bits per 2 pixels; for 2-D
+ * (horizontal), 12 bits per 2 pixels. To fill out a scan line,
+ * we may add up to 6 12-bit EOL codes.
+ */
+ int code_bytes =
+ ((columns * (ss->K == 0 ? 9 : 12)) >> 4) + 20; /* add slop */
+ int raster = ss->raster =
+ round_up((columns + 7) >> 3, ss->DecodedByteAlign);
+
+ s_hce_init_inline(ss);
+ ss->lbuf = ss->lprev = ss->lcode = 0; /* in case we have to release */
+ if (columns > cfe_max_width)
+ return ERRC;
+/****** WRONG ******/
+ /* Because skip_white_pixels can look as many as 4 bytes ahead, */
+ /* we need to allow 4 extra bytes at the end of the row buffers. */
+ ss->lbuf = gs_alloc_bytes(st->memory, raster + 4, "CFE lbuf");
+ ss->lcode = gs_alloc_bytes(st->memory, code_bytes, "CFE lcode");
+ if (ss->lbuf == 0 || ss->lcode == 0) {
+ s_CFE_release(st);
+ return ERRC;
+/****** WRONG ******/
+ }
+ if (ss->K != 0) {
+ ss->lprev = gs_alloc_bytes(st->memory, raster + 4, "CFE lprev");
+ if (ss->lprev == 0) {
+ s_CFE_release(st);
+ return ERRC;
+/****** WRONG ******/
+ }
+ /* Clear the initial reference line for 2-D encoding. */
+ /* Make sure it is terminated properly. */
+ memset(ss->lprev, (ss->BlackIs1 ? 0 : 0xff), raster);
+ if (columns & 7)
+ ss->lprev[raster - 1] ^= 0x80 >> (columns & 7);
+ else
+ ss->lprev[raster] = ~ss->lprev[0];
+ }
+ ss->read_count = raster;
+ ss->write_count = 0;
+ ss->k_left = (ss->K > 0 ? 1 : ss->K);
+ ss->max_code_bytes = code_bytes;
+ return 0;
+}
+
+/* Release the filter. */
+private void
+s_CFE_release(stream_state * st)
+{
+ stream_CFE_state *const ss = (stream_CFE_state *) st;
+
+ gs_free_object(st->memory, ss->lprev, "CFE lprev(close)");
+ gs_free_object(st->memory, ss->lcode, "CFE lcode(close)");
+ gs_free_object(st->memory, ss->lbuf, "CFE lbuf(close)");
+}
+
+/* Flush the buffer */
+private void cf_encode_1d(P3(stream_CFE_state *, const byte *,
+ stream_cursor_write *));
+private void cf_encode_2d(P4(stream_CFE_state *, const byte *,
+ stream_cursor_write *, const byte *));
+private int
+s_CFE_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last)
+{
+ stream_CFE_state *const ss = (stream_CFE_state *) st;
+ const byte *rlimit = pr->limit;
+ byte *wlimit = pw->limit;
+ int raster = ss->raster;
+ byte end_mask = 1 << (-ss->Columns & 7);
+ int status = 0;
+
+ for (;;) {
+ stream_cursor_write w;
+
+ if_debug2('w', "[w]CFE: read_count = %d, write_count=%d,\n",
+ ss->read_count, ss->write_count);
+ if_debug6('w', " pr = 0x%lx(%d)0x%lx, pw = 0x%lx(%d)0x%lx\n",
+ (ulong) pr->ptr, (int)(rlimit - pr->ptr), (ulong) rlimit,
+ (ulong) pw->ptr, (int)(wlimit - pw->ptr), (ulong) wlimit);
+ if (ss->write_count) {
+ /* Copy more of an encoded line to the caller. */
+ int wcount = wlimit - pw->ptr;
+ int ccount = min(wcount, ss->write_count);
+
+ memcpy(pw->ptr + 1, ss->lcode + ss->code_bytes - ss->write_count,
+ ccount);
+ pw->ptr += ccount;
+ if ((ss->write_count -= ccount) > 0) {
+ status = 1;
+ break;
+ }
+ }
+ if (ss->read_count) {
+ /* Copy more of an unencoded line from the caller. */
+ int rcount = rlimit - pr->ptr;
+ int ccount = min(rcount, ss->read_count);
+
+ if (rcount == 0 && last)
+ break;
+ memcpy(ss->lbuf + raster - ss->read_count,
+ pr->ptr + 1, ccount);
+ pr->ptr += ccount;
+ if ((ss->read_count -= ccount) != 0)
+ break;
+ }
+ /*
+ * We have a full scan line in lbuf. Ensure that it ends with
+ * two polarity changes.
+ */
+ {
+ byte *end = ss->lbuf + raster - 1;
+ byte end_bit = *end & end_mask;
+ byte not_bit = end_bit ^ end_mask;
+
+ *end &= -end_mask;
+ if (end_mask == 1)
+ end[1] = (end_bit ? 0x40 : 0x80);
+ else if (end_mask == 2)
+ *end |= not_bit >> 1, end[1] = end_bit << 7;
+ else
+ *end |= (not_bit >> 1) | (end_bit >> 2);
+ }
+ /*
+ * Write the output directly to the caller's buffer if it's large
+ * enough, otherwise to our own buffer.
+ */
+ if (wlimit - pw->ptr >= ss->max_code_bytes) {
+ w = *pw;
+ } else {
+ w.ptr = ss->lcode - 1;
+ w.limit = w.ptr + ss->max_code_bytes;
+ }
+#ifdef DEBUG
+ if (ss->K > 0) {
+ if_debug1('w', "[w]new row, k_left=%d\n",
+ ss->k_left);
+ } else {
+ if_debug0('w', "[w]new row\n");
+ }
+#endif
+ /*
+ * Write an EOL (actually a "beginning of line") if requested.
+ */
+ if (ss->EndOfLine) {
+ const cfe_run *rp =
+ (ss->K <= 0 ? &cf_run_eol :
+ ss->k_left > 1 ? &cf2_run_eol_2d :
+ &cf2_run_eol_1d);
+ cfe_run run;
+
+ hce_declare_state;
+
+ hce_load_state();
+ if (ss->EncodedByteAlign) {
+ run = *rp;
+ /* Pad the run on the left */
+ /* so it winds up byte-aligned. */
+ run.code_length +=
+ (bits_left - run_eol_code_length) & 7;
+ if (run.code_length > 16) /* <= 23 */
+ bits_left -= run.code_length & 7,
+ run.code_length = 16;
+ rp = &run;
+ }
+ hc_put_code(ss, w.ptr, rp);
+ hce_store_state();
+ } else if (ss->EncodedByteAlign)
+ ss->bits_left &= ~7;
+ /* Encode the line. */
+ if (ss->K == 0)
+ cf_encode_1d(ss, ss->lbuf, &w); /* pure 1-D */
+ else if (ss->K < 0)
+ cf_encode_2d(ss, ss->lbuf, &w, ss->lprev); /* pure 2-D */
+ else if (--(ss->k_left)) /* mixed, use 2-D */
+ cf_encode_2d(ss, ss->lbuf, &w, ss->lprev);
+ else { /* mixed, use 1-D */
+ cf_encode_1d(ss, ss->lbuf, &w);
+ ss->k_left = ss->K;
+ }
+ /*
+ * If we didn't write directly to the client's buffer, schedule
+ * the output data to be written.
+ */
+ if (w.limit == wlimit)
+ pw->ptr = w.ptr;
+ else
+ ss->write_count = ss->code_bytes = w.ptr - (ss->lcode - 1);
+ if (ss->K != 0) {
+ /* In 2-D modes, swap the current and previous scan lines. */
+ byte *temp = ss->lbuf;
+
+ ss->lbuf = ss->lprev;
+ ss->lprev = temp;
+ }
+ /* Note that the input buffer needs refilling. */
+ ss->read_count = raster;
+ }
+ /*
+ * When we exit from the loop, we know that write_count = 0, and
+ * there is no line waiting to be processed in the input buffer.
+ */
+ if (last && status == 0) {
+ const cfe_run *rp =
+ (ss->K > 0 ? &cf2_run_eol_1d : &cf_run_eol);
+ int i = (!ss->EndOfBlock ? 0 : ss->K < 0 ? 2 : 6);
+ uint bits_to_write =
+ hc_bits_size - ss->bits_left + i * rp->code_length;
+ byte *q = pw->ptr;
+
+ hce_declare_state;
+
+ if (wlimit - q < (bits_to_write + 7) >> 3) {
+ status = 1;
+ goto out;
+ }
+ hce_load_state();
+ if (ss->EncodedByteAlign)
+ bits_left &= ~7;
+ while (--i >= 0)
+ hc_put_code(ss, q, rp);
+ /* Force out the last byte or bytes. */
+ pw->ptr = hc_put_last_bits((stream_hc_state *) ss, q);
+ }
+ out:
+ if_debug9('w', "[w]CFE exit %d: read_count = %d, write_count = %d,\n pr = 0x%lx(%d)0x%lx; pw = 0x%lx(%d)0x%lx\n",
+ status, ss->read_count, ss->write_count,
+ (ulong) pr->ptr, (int)(rlimit - pr->ptr), (ulong) rlimit,
+ (ulong) pw->ptr, (int)(wlimit - pw->ptr), (ulong) wlimit);
+#ifdef DEBUG
+ if (pr->ptr > rlimit || pw->ptr > wlimit) {
+ lprintf("Pointer overrun!\n");
+ status = ERRC;
+ }
+ if (gs_debug_c('w') && status == 1) {
+ dlputs("[w]white runs:");
+ print_run_stats(&stats_white_runs);
+ dlputs("[w]black runs:");
+ print_run_stats(&stats_black_runs);
+ }
+#endif
+ return status;
+}
+
+/* Encode a 1-D scan line. */
+private void
+cf_encode_1d(stream_CFE_state * ss, const byte * lbuf, stream_cursor_write * pw)
+{
+ uint count = ss->raster << 3;
+ byte *q = pw->ptr;
+ int end_count = -ss->Columns & 7;
+ int rlen;
+
+ hce_declare_state;
+ const byte *p = lbuf;
+ byte invert = (ss->BlackIs1 ? 0 : 0xff);
+
+ /* Invariant: data = p[-1] ^ invert. */
+ uint data = *p++ ^ invert;
+
+ hce_load_state();
+ while (count != end_count) {
+ /* Parse a white run. */
+ skip_white_pixels(data, p, count, invert, rlen);
+ CF_PUT_WHITE_RUN(ss, rlen);
+ if (count == end_count)
+ break;
+ /* Parse a black run. */
+ skip_black_pixels(data, p, count, invert, rlen);
+ CF_PUT_BLACK_RUN(ss, rlen);
+ }
+ hce_store_state();
+ pw->ptr = q;
+}
+
+/* Encode a 2-D scan line. */
+private void
+cf_encode_2d(stream_CFE_state * ss, const byte * lbuf, stream_cursor_write * pw,
+ const byte * lprev)
+{
+ byte invert_white = (ss->BlackIs1 ? 0 : 0xff);
+ byte invert = invert_white;
+ uint count = ss->raster << 3;
+ int end_count = -ss->Columns & 7;
+ const byte *p = lbuf;
+ byte *q = pw->ptr;
+ uint data = *p++ ^ invert;
+
+ hce_declare_state;
+ /*
+ * In order to handle the nominal 'changing white' at the beginning of
+ * each scan line, we need to suppress the test for an initial black bit
+ * in the reference line when we are at the very beginning of the scan
+ * line. To avoid an extra test, we use two different mask tables.
+ */
+ static const byte initial_count_bit[8] =
+ {
+ 0, 1, 2, 4, 8, 0x10, 0x20, 0x40
+ };
+ static const byte further_count_bit[8] =
+ {
+ 0x80, 1, 2, 4, 8, 0x10, 0x20, 0x40
+ };
+ const byte *count_bit = initial_count_bit;
+
+ hce_load_state();
+ while (count != end_count) {
+ /*
+ * If invert == invert_white, white and black have their
+ * correct meanings; if invert == ~invert_white,
+ * black and white are interchanged.
+ */
+ uint a0 = count;
+ uint a1;
+
+#define b1 (a1 - diff) /* only for printing */
+ int diff;
+ uint prev_count = count;
+ const byte *prev_p = p - lbuf + lprev;
+ byte prev_data = prev_p[-1] ^ invert;
+ int rlen;
+
+ /* Find the a1 and b1 transitions. */
+ skip_white_pixels(data, p, count, invert, rlen);
+ a1 = count;
+ if ((prev_data & count_bit[prev_count & 7])) {
+ /* Look for changing white first. */
+ skip_black_pixels(prev_data, prev_p, prev_count, invert, rlen);
+ }
+ count_bit = further_count_bit; /* no longer at beginning */
+ pass:
+ if (prev_count != end_count)
+ skip_white_pixels(prev_data, prev_p, prev_count, invert, rlen);
+ diff = a1 - prev_count; /* i.e., logical b1 - a1 */
+ /* In all the comparisons below, remember that count */
+ /* runs downward, not upward, so the comparisons are */
+ /* reversed. */
+ if (diff <= -2) {
+ /* Could be a pass mode. Find b2. */
+ if (prev_count != end_count)
+ skip_black_pixels(prev_data, prev_p,
+ prev_count, invert, rlen);
+ if (prev_count > a1) {
+ /* Use pass mode. */
+ if_debug4('W', "[W]pass: count = %d, a1 = %d, b1 = %d, new count = %d\n",
+ a0, a1, b1, prev_count);
+ hc_put_value(ss, q, cf2_run_pass_value, cf2_run_pass_length);
+ a0 = prev_count;
+ goto pass;
+ }
+ }
+ /* Check for vertical coding. */
+ if (diff <= 3 && diff >= -3) {
+ /* Use vertical coding. */
+ const cfe_run *cp = &cf2_run_vertical[diff + 3];
+
+ if_debug5('W', "[W]vertical %d: count = %d, a1 = %d, b1 = %d, new count = %d\n",
+ diff, a0, a1, b1, count);
+ hc_put_code(ss, q, cp);
+ invert = ~invert; /* a1 polarity changes */
+ data ^= 0xff;
+ continue;
+ }
+ /* No luck, use horizontal coding. */
+ if (count != end_count)
+ skip_black_pixels(data, p, count, invert, rlen); /* find a2 */
+ hc_put_value(ss, q, cf2_run_horizontal_value,
+ cf2_run_horizontal_length);
+ a0 -= a1;
+ a1 -= count;
+ if (invert == invert_white) {
+ if_debug3('W', "[W]horizontal: white = %d, black = %d, new count = %d\n",
+ a0, a1, count);
+ CF_PUT_WHITE_RUN(ss, a0);
+ CF_PUT_BLACK_RUN(ss, a1);
+ } else {
+ if_debug3('W', "[W]horizontal: black = %d, white = %d, new count = %d\n",
+ a0, a1, count);
+ CF_PUT_BLACK_RUN(ss, a0);
+ CF_PUT_WHITE_RUN(ss, a1);
+#undef b1
+ }
+ }
+ hce_store_state();
+ pw->ptr = q;
+}
+
+/* Stream template */
+const stream_template s_CFE_template =
+{
+ &st_CFE_state, s_CFE_init, s_CFE_process, 1, 1,
+ s_CFE_release, s_CFE_set_defaults
+};
diff --git a/pstoraster/scfetab.c b/pstoraster/scfetab.c
new file mode 100644
index 000000000..287d02075
--- /dev/null
+++ b/pstoraster/scfetab.c
@@ -0,0 +1,170 @@
+/* Copyright (C) 1992, 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$ */
+/* Tables for CCITTFaxEncode filter */
+#include "std.h"
+#include "scommon.h" /* for scf.h */
+#include "scf.h"
+
+/* We make this a separate file so that it can be used by */
+/* the program that generates the tables for the CCITTFaxDecode filter. */
+
+/* ------ Run encoding tables ------ */
+
+/* Abbreviate hce_entry to make the file smaller. */
+#define RUN(c,len) hce_entry(c,len)
+
+/* Define the end-of-line code. */
+/* Code in scfd.c and scfdgen.c knows that the run value is 1. */
+const cfe_run cf_run_eol =
+RUN(run_eol_code_value, run_eol_code_length);
+
+/* Define the 1-D code that signals uncompressed data. */
+const cfe_run cf1_run_uncompressed =
+RUN(0xf, 12);
+
+/* Define the 2-D run codes. */
+const cfe_run cf2_run_pass =
+RUN(cf2_run_pass_value, cf2_run_pass_length);
+const cfe_run cf2_run_vertical[7] =
+{
+ RUN(0x3, 7),
+ RUN(0x3, 6),
+ RUN(0x3, 3),
+ RUN(0x1, 1),
+ RUN(0x2, 3),
+ RUN(0x2, 6),
+ RUN(0x2, 7)
+};
+const cfe_run cf2_run_horizontal =
+RUN(cf2_run_horizontal_value, cf2_run_horizontal_length);
+const cfe_run cf2_run_uncompressed =
+RUN(0xf, 10);
+
+/* EOL codes for Group 3 2-D. */
+/* Code in scfd.c knows that these are 0...01x. */
+const cfe_run cf2_run_eol_1d =
+RUN((run_eol_code_value << 1) + 1, run_eol_code_length + 1);
+const cfe_run cf2_run_eol_2d =
+RUN((run_eol_code_value << 1) + 0, run_eol_code_length + 1);
+
+/* White run codes. */
+const cf_runs cf_white_runs =
+{
+ { /* Termination codes */
+ RUN(0x35, 8), RUN(0x7, 6), RUN(0x7, 4), RUN(0x8, 4),
+ RUN(0xb, 4), RUN(0xc, 4), RUN(0xe, 4), RUN(0xf, 4),
+ RUN(0x13, 5), RUN(0x14, 5), RUN(0x7, 5), RUN(0x8, 5),
+ RUN(0x8, 6), RUN(0x3, 6), RUN(0x34, 6), RUN(0x35, 6),
+ RUN(0x2a, 6), RUN(0x2b, 6), RUN(0x27, 7), RUN(0xc, 7),
+ RUN(0x8, 7), RUN(0x17, 7), RUN(0x3, 7), RUN(0x4, 7),
+ RUN(0x28, 7), RUN(0x2b, 7), RUN(0x13, 7), RUN(0x24, 7),
+ RUN(0x18, 7), RUN(0x2, 8), RUN(0x3, 8), RUN(0x1a, 8),
+ RUN(0x1b, 8), RUN(0x12, 8), RUN(0x13, 8), RUN(0x14, 8),
+ RUN(0x15, 8), RUN(0x16, 8), RUN(0x17, 8), RUN(0x28, 8),
+ RUN(0x29, 8), RUN(0x2a, 8), RUN(0x2b, 8), RUN(0x2c, 8),
+ RUN(0x2d, 8), RUN(0x4, 8), RUN(0x5, 8), RUN(0xa, 8),
+ RUN(0xb, 8), RUN(0x52, 8), RUN(0x53, 8), RUN(0x54, 8),
+ RUN(0x55, 8), RUN(0x24, 8), RUN(0x25, 8), RUN(0x58, 8),
+ RUN(0x59, 8), RUN(0x5a, 8), RUN(0x5b, 8), RUN(0x4a, 8),
+ RUN(0x4b, 8), RUN(0x32, 8), RUN(0x33, 8), RUN(0x34, 8)
+ },
+ { /* Make-up codes */
+ RUN(0, 0) /* dummy */ , RUN(0x1b, 5), RUN(0x12, 5), RUN(0x17, 6),
+ RUN(0x37, 7), RUN(0x36, 8), RUN(0x37, 8), RUN(0x64, 8),
+ RUN(0x65, 8), RUN(0x68, 8), RUN(0x67, 8), RUN(0xcc, 9),
+ RUN(0xcd, 9), RUN(0xd2, 9), RUN(0xd3, 9), RUN(0xd4, 9),
+ RUN(0xd5, 9), RUN(0xd6, 9), RUN(0xd7, 9), RUN(0xd8, 9),
+ RUN(0xd9, 9), RUN(0xda, 9), RUN(0xdb, 9), RUN(0x98, 9),
+ RUN(0x99, 9), RUN(0x9a, 9), RUN(0x18, 6), RUN(0x9b, 9),
+ RUN(0x8, 11), RUN(0xc, 11), RUN(0xd, 11), RUN(0x12, 12),
+ RUN(0x13, 12), RUN(0x14, 12), RUN(0x15, 12), RUN(0x16, 12),
+ RUN(0x17, 12), RUN(0x1c, 12), RUN(0x1d, 12), RUN(0x1e, 12),
+ RUN(0x1f, 12)
+ }
+};
+
+/* Black run codes. */
+const cf_runs cf_black_runs =
+{
+ { /* Termination codes */
+ RUN(0x37, 10), RUN(0x2, 3), RUN(0x3, 2), RUN(0x2, 2),
+ RUN(0x3, 3), RUN(0x3, 4), RUN(0x2, 4), RUN(0x3, 5),
+ RUN(0x5, 6), RUN(0x4, 6), RUN(0x4, 7), RUN(0x5, 7),
+ RUN(0x7, 7), RUN(0x4, 8), RUN(0x7, 8), RUN(0x18, 9),
+ RUN(0x17, 10), RUN(0x18, 10), RUN(0x8, 10), RUN(0x67, 11),
+ RUN(0x68, 11), RUN(0x6c, 11), RUN(0x37, 11), RUN(0x28, 11),
+ RUN(0x17, 11), RUN(0x18, 11), RUN(0xca, 12), RUN(0xcb, 12),
+ RUN(0xcc, 12), RUN(0xcd, 12), RUN(0x68, 12), RUN(0x69, 12),
+ RUN(0x6a, 12), RUN(0x6b, 12), RUN(0xd2, 12), RUN(0xd3, 12),
+ RUN(0xd4, 12), RUN(0xd5, 12), RUN(0xd6, 12), RUN(0xd7, 12),
+ RUN(0x6c, 12), RUN(0x6d, 12), RUN(0xda, 12), RUN(0xdb, 12),
+ RUN(0x54, 12), RUN(0x55, 12), RUN(0x56, 12), RUN(0x57, 12),
+ RUN(0x64, 12), RUN(0x65, 12), RUN(0x52, 12), RUN(0x53, 12),
+ RUN(0x24, 12), RUN(0x37, 12), RUN(0x38, 12), RUN(0x27, 12),
+ RUN(0x28, 12), RUN(0x58, 12), RUN(0x59, 12), RUN(0x2b, 12),
+ RUN(0x2c, 12), RUN(0x5a, 12), RUN(0x66, 12), RUN(0x67, 12)
+ },
+ { /* Make-up codes. */
+ RUN(0, 0) /* dummy */ , RUN(0xf, 10), RUN(0xc8, 12), RUN(0xc9, 12),
+ RUN(0x5b, 12), RUN(0x33, 12), RUN(0x34, 12), RUN(0x35, 12),
+ RUN(0x6c, 13), RUN(0x6d, 13), RUN(0x4a, 13), RUN(0x4b, 13),
+ RUN(0x4c, 13), RUN(0x4d, 13), RUN(0x72, 13), RUN(0x73, 13),
+ RUN(0x74, 13), RUN(0x75, 13), RUN(0x76, 13), RUN(0x77, 13),
+ RUN(0x52, 13), RUN(0x53, 13), RUN(0x54, 13), RUN(0x55, 13),
+ RUN(0x5a, 13), RUN(0x5b, 13), RUN(0x64, 13), RUN(0x65, 13),
+ RUN(0x8, 11), RUN(0xc, 11), RUN(0xd, 11), RUN(0x12, 12),
+ RUN(0x13, 12), RUN(0x14, 12), RUN(0x15, 12), RUN(0x16, 12),
+ RUN(0x17, 12), RUN(0x1c, 12), RUN(0x1d, 12), RUN(0x1e, 12),
+ RUN(0x1f, 12)
+ }
+};
+
+/* Uncompressed codes. */
+const cfe_run cf_uncompressed[6] =
+{
+ RUN(1, 1),
+ RUN(1, 2),
+ RUN(1, 3),
+ RUN(1, 4),
+ RUN(1, 5),
+ RUN(1, 6)
+};
+
+/* Uncompressed exit codes. */
+const cfe_run cf_uncompressed_exit[10] =
+{
+ RUN(2, 8), RUN(3, 8),
+ RUN(2, 9), RUN(3, 9),
+ RUN(2, 10), RUN(3, 10),
+ RUN(2, 11), RUN(3, 11),
+ RUN(2, 12), RUN(3, 12)
+};
+
+/* Some C compilers insist on having executable code in every file.... */
+void
+cfe_dummy(void)
+{
+}
diff --git a/pstoraster/scfparam.c b/pstoraster/scfparam.c
new file mode 100644
index 000000000..c906ae22e
--- /dev/null
+++ b/pstoraster/scfparam.c
@@ -0,0 +1,99 @@
+/* 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$ */
+/* CCITTFax filter parameter setting and reading */
+#include "std.h"
+#include "gserror.h"
+#include "gserrors.h"
+#include "gstypes.h"
+#include "gsmemory.h"
+#include "gsparam.h"
+#include "scommon.h"
+#include "scf.h" /* for cfe_max_width */
+#include "scfx.h"
+
+/* Define the CCITTFax parameters. */
+private const gs_param_item_t s_CF_param_items[] =
+{
+#define cfp(key, type, memb) { key, type, offset_of(stream_CF_state, memb) }
+ cfp("Uncompressed", gs_param_type_bool, Uncompressed),
+ cfp("K", gs_param_type_int, K),
+ cfp("EndOfLine", gs_param_type_bool, EndOfLine),
+ cfp("EncodedByteAlign", gs_param_type_bool, EncodedByteAlign),
+ cfp("Columns", gs_param_type_int, Columns),
+ cfp("Rows", gs_param_type_int, Rows),
+ cfp("EndOfBlock", gs_param_type_bool, EndOfBlock),
+ cfp("BlackIs1", gs_param_type_bool, BlackIs1),
+ cfp("DamagedRowsBeforeError", gs_param_type_int, DamagedRowsBeforeError),
+ cfp("FirstBitLowOrder", gs_param_type_bool, FirstBitLowOrder),
+ cfp("DecodedByteAlign", gs_param_type_int, DecodedByteAlign),
+#undef cfp
+ gs_param_item_end
+};
+
+/* Define a limit on the Rows parameter, close to max_int. */
+#define cf_max_height 32000
+
+/* Get non-default CCITTFax filter parameters. */
+stream_state_proc_get_params(s_CF_get_params, stream_CF_state); /* check */
+int
+s_CF_get_params(gs_param_list * plist, const stream_CF_state * ss, bool all)
+{
+ stream_CF_state cfs_defaults;
+ const stream_CF_state *defaults;
+
+ if (all)
+ defaults = 0;
+ else {
+ s_CF_set_defaults_inline(&cfs_defaults);
+ defaults = &cfs_defaults;
+ }
+ return gs_param_write_items(plist, ss, defaults, s_CF_param_items);
+}
+
+/* Put CCITTFax filter parameters. */
+stream_state_proc_put_params(s_CF_put_params, stream_CF_state); /* check */
+int
+s_CF_put_params(gs_param_list * plist, stream_CF_state * ss)
+{
+ stream_CF_state state;
+ int code;
+
+ state = *ss;
+ code = gs_param_read_items(plist, (void *)&state, s_CF_param_items);
+ if (code >= 0 &&
+ (state.K < -cf_max_height || state.K > cf_max_height ||
+ state.Columns < 0 || state.Columns > cfe_max_width ||
+ state.Rows < 0 || state.Rows > cf_max_height ||
+ state.DamagedRowsBeforeError < 0 ||
+ state.DamagedRowsBeforeError > cf_max_height ||
+ state.DecodedByteAlign < 1 || state.DecodedByteAlign > 16 ||
+ (state.DecodedByteAlign & (state.DecodedByteAlign - 1)) != 0)
+ )
+ code = gs_note_error(gs_error_rangecheck);
+ if (code >= 0)
+ *ss = state;
+ return code;
+}
diff --git a/pstoraster/scfx.h b/pstoraster/scfx.h
new file mode 100644
index 000000000..96a6b43d4
--- /dev/null
+++ b/pstoraster/scfx.h
@@ -0,0 +1,132 @@
+/* Copyright (C) 1993, 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$ */
+/* CCITTFax filter state definition */
+/* Requires strimpl.h */
+
+#ifndef scfx_DEFINED
+# define scfx_DEFINED
+
+#include "shc.h"
+
+/* Common state */
+#define stream_CF_state_common\
+ stream_hc_state_common;\
+ /* The client sets the following before initialization. */\
+ bool Uncompressed;\
+ int K;\
+ bool EndOfLine;\
+ bool EncodedByteAlign;\
+ int Columns;\
+ int Rows;\
+ bool EndOfBlock;\
+ bool BlackIs1;\
+ int DamagedRowsBeforeError; /* (Decode only) */\
+ /*bool FirstBitLowOrder;*/ /* in stream_hc_state_common */\
+ int DecodedByteAlign;\
+ /* The init procedure sets the following. */\
+ uint raster;\
+ byte *lbuf; /* current scan line buffer */\
+ /* (only if decoding or 2-D encoding) */\
+ byte *lprev; /* previous scan line buffer (only if 2-D) */\
+ /* The following are updated dynamically. */\
+ int k_left /* number of next rows to encode in 2-D */\
+ /* (only if K > 0) */
+typedef struct stream_CF_state_s {
+ stream_CF_state_common;
+} stream_CF_state;
+
+/* Define common default parameter setting. */
+#define s_CF_set_defaults_inline(ss)\
+ ((ss)->Uncompressed = false,\
+ (ss)->K = 0,\
+ (ss)->EndOfLine = false,\
+ (ss)->EncodedByteAlign = false,\
+ (ss)->Columns = 1728,\
+ (ss)->Rows = 0,\
+ (ss)->EndOfBlock = true,\
+ (ss)->BlackIs1 = false,\
+ /* Added by Adobe since the Red Book */\
+ (ss)->DamagedRowsBeforeError = 0, /* always set, for s_CF_get_params */\
+ (ss)->FirstBitLowOrder = false,\
+ /* Added by us */\
+ (ss)->DecodedByteAlign = 1)
+
+/* CCITTFaxEncode */
+typedef struct stream_CFE_state_s {
+ stream_CF_state_common;
+ /* The init procedure sets the following. */
+ int max_code_bytes; /* max # of bytes for an encoded line */
+ byte *lcode; /* buffer for encoded output line */
+ /* The following change dynamically. */
+ int read_count; /* # of bytes to copy into lbuf */
+ int write_count; /* # of bytes to copy out of lcode */
+ int code_bytes; /* # of occupied bytes in lcode */
+} stream_CFE_state;
+
+#define private_st_CFE_state() /* in scfe.c */\
+ gs_private_st_ptrs3(st_CFE_state, stream_CFE_state, "CCITTFaxEncode state",\
+ cfe_enum_ptrs, cfe_reloc_ptrs, lbuf, lprev, lcode)
+#define s_CFE_set_defaults_inline(ss)\
+ s_CF_set_defaults_inline(ss)
+extern const stream_template s_CFE_template;
+
+/* CCITTFaxDecode */
+typedef struct stream_CFD_state_s {
+ stream_CF_state_common;
+ int cbit; /* bits left to fill in current decoded */
+ /* byte at lbuf[wpos] (0..7) */
+ int rows_left; /* number of rows left */
+ int rpos; /* rptr for copying lbuf to client */
+ int wpos; /* rlimit/wptr for filling lbuf or */
+ /* copying to client */
+ int eol_count; /* number of EOLs seen so far */
+ byte invert; /* current value of 'white' */
+ /* for 2-D decoding */
+ int run_color; /* -1 if processing white run, */
+ /* 0 if between runs but white is next, */
+ /* 1 if between runs and black is next, */
+ /* 2 if processing black run */
+ int damaged_rows; /* # of consecutive damaged rows preceding */
+ /* the current row */
+ bool skipping_damage; /* true if skipping a damaged row looking */
+ /* for EOL */
+ /* The following are not used yet. */
+ int uncomp_run; /* non-0 iff we are in an uncompressed */
+ /* run straddling a scan line (-1 if white, */
+ /* 1 if black) */
+ int uncomp_left; /* # of bits left in the run */
+ int uncomp_exit; /* non-0 iff this is an exit run */
+ /* (-1 if next run white, 1 if black) */
+} stream_CFD_state;
+
+#define private_st_CFD_state() /* in scfd.c */\
+ gs_private_st_ptrs2(st_CFD_state, stream_CFD_state, "CCITTFaxDecode state",\
+ cfd_enum_ptrs, cfd_reloc_ptrs, lbuf, lprev)
+#define s_CFD_set_defaults_inline(ss)\
+ s_CF_set_defaults_inline(ss)
+extern const stream_template s_CFD_template;
+
+#endif /* scfx_INCLUDED */
diff --git a/pstoraster/scommon.h b/pstoraster/scommon.h
new file mode 100644
index 000000000..9f02bc04f
--- /dev/null
+++ b/pstoraster/scommon.h
@@ -0,0 +1,173 @@
+/* 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$ */
+/* Definitions common to stream clients and implementors */
+
+#ifndef scommon_DEFINED
+# define scommon_DEFINED
+
+#include "gsmemory.h"
+#include "gstypes.h" /* for gs_string */
+#include "gsstruct.h" /* for extern_st */
+
+/*
+ * There are three major structures involved in the stream package.
+ *
+ * A stream is an "object" that owns a buffer, which it uses to implement
+ * byte-oriented sequential access in a standard way, and a set of
+ * procedures that handle things like buffer refilling. See stream.h
+ * for more information about streams.
+ */
+#ifndef stream_DEFINED
+# define stream_DEFINED
+typedef struct stream_s stream;
+
+#endif
+/*
+ * A stream_state records the state specific to a given variety of stream.
+ * The buffer processing function of a stream maintains this state.
+ */
+typedef struct stream_state_s stream_state;
+
+/*
+ * A stream_template provides the information needed to create a stream.
+ * The client must fill in any needed setup parameters in the appropriate
+ * variety of stream_state, and then call the initialization function
+ * provided by the template. See strimpl.h for more information about
+ * stream_templates.
+ */
+typedef struct stream_template_s stream_template;
+
+/*
+ * The stream package works with bytes, not chars.
+ * This is to ensure unsigned representation on all systems.
+ * A stream currently can only be read or written, not both.
+ * Note also that the read procedure returns an int, not a char or a byte;
+ * we use negative values to indicate exceptional conditions.
+ * (We cast these values to int explicitly, because some compilers
+ * don't do this if the other arm of a conditional is a byte.)
+ */
+/* End of data */
+#define EOFC ((int)(-1))
+/* Error */
+#define ERRC ((int)(-2))
+/* Interrupt */
+#define INTC ((int)(-3))
+/****** INTC IS NOT USED YET ******/
+/* Callout */
+#define CALLC ((int)(-4))
+#define max_stream_exception 4
+/* The following hack is needed for initializing scan_char_array in iscan.c. */
+#define stream_exception_repeat(x) x, x, x, x
+
+/*
+ * Define cursors for reading from or writing into a buffer.
+ * We lay them out this way so that we can alias
+ * the write pointer and the read limit.
+ */
+typedef struct stream_cursor_read_s {
+ const byte *ptr;
+ const byte *limit;
+ byte *_skip;
+} stream_cursor_read;
+typedef struct stream_cursor_write_s {
+ const byte *_skip;
+ byte *ptr;
+ byte *limit;
+} stream_cursor_write;
+typedef union stream_cursor_s {
+ stream_cursor_read r;
+ stream_cursor_write w;
+} stream_cursor;
+
+/*
+ * Define the prototype for the procedures known to both the generic
+ * stream code and the stream implementations.
+ */
+
+/* Initialize the stream state (after the client parameters are set). */
+#define stream_proc_init(proc)\
+ int proc(P1(stream_state *))
+
+/* Process a buffer. See strimpl.h for details. */
+#define stream_proc_process(proc)\
+ int proc(P4(stream_state *, stream_cursor_read *,\
+ stream_cursor_write *, bool))
+
+/* Release the stream state when closing. */
+#define stream_proc_release(proc)\
+ void proc(P1(stream_state *))
+
+/* Initialize the client parameters to default values. */
+#define stream_proc_set_defaults(proc)\
+ void proc(P1(stream_state *))
+
+/* Reinitialize any internal stream state. Note that this does not */
+/* affect buffered data. We declare this as returning an int so that */
+/* it can be the same as the init procedure; however, reinit cannot fail. */
+#define stream_proc_reinit(proc)\
+ int proc(P1(stream_state *))
+
+/* Report an error. Note that this procedure is stored in the state, */
+/* not in the main stream structure. */
+#define stream_proc_report_error(proc)\
+ int proc(P2(stream_state *, const char *))
+stream_proc_report_error(s_no_report_error);
+
+/*
+ * Some types of streams have the ability to read their parameters from
+ * a parameter list, and to write all (or only the non-default)
+ * parameters to a parameter list. Since these are not virtual
+ * procedures for the stream (they operate on stream_state structures
+ * even if no actual stream has been created), we name them differently.
+ */
+#define stream_state_proc_get_params(proc, state_type)\
+ int proc(P3(gs_param_list *plist, const state_type *ss, bool all))
+#define stream_state_proc_put_params(proc, state_type)\
+ int proc(P2(gs_param_list *plist, state_type *ss))
+
+/*
+ * Define a generic stream state. If a processing procedure has no
+ * state of its own, it can use stream_state; otherwise, it must
+ * create a "subclass". There is a hack in stream.h to allow the stream
+ * itself to serve as the "state" of a couple of heavily used stream types.
+ *
+ * In order to simplify the structure descriptors for concrete streams,
+ * we require that the generic stream state not contain any pointers
+ * to garbage-collectable storage.
+ */
+#define stream_state_common\
+ const stream_template *template;\
+ gs_memory_t *memory;\
+ stream_proc_report_error((*report_error))
+struct stream_state_s {
+ stream_state_common;
+};
+
+extern_st(st_stream_state);
+#define public_st_stream_state() /* in stream.c */\
+ gs_public_st_simple(st_stream_state, stream_state, "stream_state")
+
+#endif /* scommon_INCLUDED */
diff --git a/pstoraster/sdcparam.c b/pstoraster/sdcparam.c
new file mode 100644
index 000000000..ab0bb4aec
--- /dev/null
+++ b/pstoraster/sdcparam.c
@@ -0,0 +1,630 @@
+/*
+ Copyright 1993-2002 by Easy Software Products.
+ Copyright 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.
+*/
+
+#include <config.h>
+#ifdef HAVE_LIBJPEG
+/*$Id$ */
+/* DCT filter parameter setting and reading */
+#include "memory_.h"
+#include "jpeglib.h"
+#include "gserror.h"
+#include "gserrors.h"
+#include "gstypes.h"
+#include "gsmemory.h"
+#include "gsparam.h"
+#include "strimpl.h" /* sdct.h requires this */
+#include "sdct.h"
+#include "sdcparam.h"
+#include "sjpeg.h"
+
+/* Define the DCT parameters. */
+#define dctp(key, type, stype, memb) { key, type, offset_of(stype, memb) }
+private const gs_param_item_t s_DCT_param_items[] =
+{
+dctp("ColorTransform", gs_param_type_int, stream_DCT_state, ColorTransform),
+ dctp("QFactor", gs_param_type_float, stream_DCT_state, QFactor),
+ gs_param_item_end
+};
+private const gs_param_item_t jsd_param_items[] =
+{
+ dctp("Picky", gs_param_type_int, jpeg_stream_data, Picky),
+ dctp("Relax", gs_param_type_int, jpeg_stream_data, Relax),
+ gs_param_item_end
+};
+
+#undef dctp
+
+/*
+ * Adobe specifies the values to be supplied in zigzag order.
+ * For IJG versions newer than v6, we need to convert this order
+ * to natural array order. Older IJG versions want zigzag order.
+ */
+#if JPEG_LIB_VERSION >= 61
+ /* natural array position of n'th element of JPEG zigzag order */
+static const byte natural_order[DCTSIZE2] =
+{
+ 0, 1, 8, 16, 9, 2, 3, 10,
+ 17, 24, 32, 25, 18, 11, 4, 5,
+ 12, 19, 26, 33, 40, 48, 41, 34,
+ 27, 20, 13, 6, 7, 14, 21, 28,
+ 35, 42, 49, 56, 57, 50, 43, 36,
+ 29, 22, 15, 23, 30, 37, 44, 51,
+ 58, 59, 52, 45, 38, 31, 39, 46,
+ 53, 60, 61, 54, 47, 55, 62, 63
+};
+
+#define jpeg_order(x) natural_order[x]
+ /* invert natural_order for getting parameters */
+static const byte inverse_natural_order[DCTSIZE2] =
+{
+ 0, 1, 5, 6, 14, 15, 27, 28,
+ 2, 4, 7, 13, 16, 26, 29, 42,
+ 3, 8, 12, 17, 25, 30, 41, 43,
+ 9, 11, 18, 24, 31, 40, 44, 53,
+ 10, 19, 23, 32, 39, 45, 52, 54,
+ 20, 22, 33, 38, 46, 51, 55, 60,
+ 21, 34, 37, 47, 50, 56, 59, 61,
+ 35, 36, 48, 49, 57, 58, 62, 63
+};
+
+#define jpeg_inverse_order(x) inverse_natural_order[x]
+#else
+#define jpeg_order(x) (x)
+#define jpeg_inverse_order(x) (x)
+#endif
+
+/* ================ Get parameters ================ */
+
+private int
+quant_param_string(gs_param_string * pstr, int count, const UINT16 * pvals,
+ floatp QFactor, gs_memory_t * mem)
+{
+ byte *data;
+ int code = 0;
+ int i;
+
+ data = gs_alloc_string(mem, count, "quant_param_string");
+ if (data == 0)
+ return_error(gs_error_VMerror);
+ for (i = 0; i < count; ++i) {
+ floatp val = pvals[jpeg_inverse_order(i)] / QFactor;
+
+ data[i] =
+ (val < 1 ? (code = 1) : val > 255 ? (code = 255) : (byte) val);
+ }
+ pstr->data = data;
+ pstr->size = count;
+ pstr->persistent = true;
+ return code & 1;
+}
+
+private int
+quant_param_array(gs_param_float_array * pfa, int count, const UINT16 * pvals,
+ floatp QFactor, gs_memory_t * mem)
+{
+ float *data;
+ int i;
+
+ data = (float *)gs_alloc_byte_array(mem, count, sizeof(float),
+ "quant_param_array");
+
+ if (data == 0)
+ return_error(gs_error_VMerror);
+ for (i = 0; i < count; ++i)
+ data[i] = pvals[jpeg_inverse_order(i)] / QFactor;
+ pfa->data = data;
+ pfa->size = count;
+ pfa->persistent = true;
+ return 0;
+}
+
+int
+s_DCT_get_quantization_tables(gs_param_list * plist,
+ const stream_DCT_state * pdct, const stream_DCT_state * defaults,
+ bool is_encode)
+{
+ gs_memory_t *mem = pdct->memory;
+ jpeg_component_info d_comp_info[4];
+ int num_in_tables;
+ const jpeg_component_info *comp_info;
+ const jpeg_component_info *default_comp_info;
+ JQUANT_TBL **table_ptrs;
+ JQUANT_TBL **default_table_ptrs;
+ gs_param_array quant_tables;
+ floatp QFactor = pdct->QFactor;
+ int i;
+ int code;
+
+ if (is_encode) {
+ num_in_tables = pdct->data.compress->cinfo.num_components;
+ comp_info = pdct->data.compress->cinfo.comp_info;
+ table_ptrs = pdct->data.compress->cinfo.quant_tbl_ptrs;
+ if (defaults) {
+ default_comp_info = defaults->data.compress->cinfo.comp_info;
+ default_table_ptrs = defaults->data.compress->cinfo.quant_tbl_ptrs;
+ }
+ } else {
+ num_in_tables = quant_tables.size;
+ for (i = 0; i < num_in_tables; ++i)
+ d_comp_info[i].quant_tbl_no = i;
+ comp_info = d_comp_info;
+ table_ptrs = pdct->data.decompress->dinfo.quant_tbl_ptrs;
+ if (defaults) {
+ default_comp_info = d_comp_info;
+ default_table_ptrs =
+ defaults->data.decompress->dinfo.quant_tbl_ptrs;
+ }
+ }
+
+ /* Check whether all tables match defaults. */
+ if (defaults) {
+ bool match = true;
+
+ for (i = 0; i < num_in_tables; ++i) {
+ JQUANT_TBL *tbl = table_ptrs[comp_info[i].quant_tbl_no];
+ JQUANT_TBL *default_tbl =
+ (default_comp_info == 0 || default_table_ptrs == 0 ? 0 :
+ default_table_ptrs[default_comp_info[i].quant_tbl_no]);
+
+ if (tbl == default_tbl)
+ continue;
+ if (tbl == 0 || default_tbl == 0 ||
+ memcmp(tbl->quantval, default_tbl->quantval,
+ DCTSIZE2 * sizeof(UINT16))
+ ) {
+ match = false;
+ break;
+ }
+ }
+ if (match)
+ return 0;
+ }
+ quant_tables.size = num_in_tables;
+ code = param_begin_write_collection(plist, "QuantTables",
+ &quant_tables,
+ gs_param_collection_array);
+ if (code < 0)
+ return code;
+ for (i = 0; i < num_in_tables; ++i) {
+ char key[3];
+ gs_param_string str;
+ gs_param_float_array fa;
+
+ sprintf(key, "%d", i);
+ if (QFactor == 1.0) {
+ code = quant_param_string(&str, DCTSIZE2,
+ table_ptrs[comp_info[i].quant_tbl_no]->quantval,
+ QFactor, mem);
+ switch (code) {
+ case 0:
+ code = param_write_string(quant_tables.list, key, &str);
+ if (code < 0)
+ return code; /* should dealloc */
+ continue;
+ default:
+ return code; /* should dealloc */
+ case 1:
+ break;
+ }
+ /* break const to free the string */
+ gs_free_string(mem, (byte *) str.data, str.size,
+ "quant_param_string");
+ }
+ code = quant_param_array(&fa, DCTSIZE2,
+ table_ptrs[comp_info[i].quant_tbl_no]->quantval,
+ QFactor, mem);
+ if (code < 0)
+ return code; /* should dealloc */
+ code = param_write_float_array(quant_tables.list, key, &fa);
+ if (code < 0)
+ return code; /* should dealloc */
+ }
+ return param_end_write_dict(plist, "QuantTables", &quant_tables);
+}
+
+private int
+pack_huff_table(gs_param_string * pstr, const JHUFF_TBL * table,
+ gs_memory_t * mem)
+{
+ int total;
+ int i;
+ byte *data;
+
+ for (i = 1, total = 0; i <= 16; ++i)
+ total += table->bits[i];
+ data = gs_alloc_string(mem, 16 + total, "pack_huff_table");
+ if (data == 0)
+ return_error(gs_error_VMerror);
+ memcpy(data, table->bits + 1, 16);
+ memcpy(data + 16, table->huffval, total);
+ pstr->data = data;
+ pstr->size = 16 + total;
+ pstr->persistent = true;
+ return 0;
+}
+
+int
+s_DCT_get_huffman_tables(gs_param_list * plist,
+ const stream_DCT_state * pdct, const stream_DCT_state * defaults,
+ bool is_encode)
+{
+ gs_memory_t *mem = pdct->memory;
+ gs_param_string *huff_data;
+ gs_param_string_array hta;
+ int num_in_tables;
+ jpeg_component_info *comp_info;
+ JHUFF_TBL **dc_table_ptrs;
+ JHUFF_TBL **ac_table_ptrs;
+ int i;
+ int code = 0;
+
+ if (is_encode) {
+ dc_table_ptrs = pdct->data.compress->cinfo.dc_huff_tbl_ptrs;
+ ac_table_ptrs = pdct->data.compress->cinfo.ac_huff_tbl_ptrs;
+ num_in_tables = pdct->data.compress->cinfo.input_components * 2;
+ comp_info = pdct->data.compress->cinfo.comp_info;
+ } else {
+ dc_table_ptrs = pdct->data.decompress->dinfo.dc_huff_tbl_ptrs;
+ ac_table_ptrs = pdct->data.decompress->dinfo.ac_huff_tbl_ptrs;
+ for (i = 2; i > 0; --i)
+ if (dc_table_ptrs[i - 1] || ac_table_ptrs[i - 1])
+ break;
+ num_in_tables = i * 2;
+ comp_info = NULL; /* do not set for decompress case */
+ }
+/****** byte_array IS WRONG ******/
+ huff_data = (gs_param_string *)
+ gs_alloc_byte_array(mem, num_in_tables, sizeof(gs_param_string),
+ "get huffman tables");
+ if (huff_data == 0)
+ return_error(gs_error_VMerror);
+ for (i = 0; i < num_in_tables; i += 2) {
+ if ((code = pack_huff_table(huff_data + i, ac_table_ptrs[i >> 1], mem)) < 0 ||
+ (code = pack_huff_table(huff_data + i + 1, dc_table_ptrs[i >> 1], mem))
+ )
+ break;
+ }
+ if (code < 0)
+ return code;
+ hta.data = huff_data;
+ hta.size = num_in_tables;
+ hta.persistent = true;
+ return param_write_string_array(plist, "HuffTables", &hta);
+}
+
+int
+s_DCT_get_params(gs_param_list * plist, const stream_DCT_state * ss,
+ const stream_DCT_state * defaults)
+{
+ int code =
+ gs_param_write_items(plist, ss, defaults, s_DCT_param_items);
+
+ if (code >= 0)
+ code = gs_param_write_items(plist, ss->data.common,
+ (defaults ? defaults->data.common :
+ NULL),
+ jsd_param_items);
+ return code;
+}
+
+/* ================ Put parameters ================ */
+
+stream_state_proc_put_params(s_DCT_put_params, stream_DCT_state); /* check */
+
+/* ---------------- Utilities ---------------- */
+
+/*
+ * Get N byte-size values from an array or a string.
+ * Used for HuffTables, HSamples, VSamples.
+ */
+int
+s_DCT_byte_params(gs_param_list * plist, gs_param_name key, int start,
+ int count, UINT8 * pvals)
+{
+ int i;
+ gs_param_string bytes;
+ gs_param_float_array floats;
+ int code = param_read_string(plist, key, &bytes);
+
+ switch (code) {
+ case 0:
+ if (bytes.size < start + count) {
+ code = gs_note_error(gs_error_rangecheck);
+ break;
+ }
+ for (i = 0; i < count; ++i)
+ pvals[i] = (UINT8) bytes.data[start + i];
+ return 0;
+ default: /* might be a float array */
+ code = param_read_float_array(plist, key, &floats);
+ if (!code) {
+ if (floats.size < start + count) {
+ code = gs_note_error(gs_error_rangecheck);
+ break;
+ }
+ for (i = 0; i < count; ++i) {
+ float v = floats.data[start + i];
+
+ if (v < 0 || v > 255) {
+ code = gs_note_error(gs_error_rangecheck);
+ break;
+ }
+ pvals[i] = (UINT8) (v + 0.5);
+ }
+ }
+ }
+ if (code < 0)
+ param_signal_error(plist, key, code);
+ return code;
+}
+
+/* Get N quantization values from an array or a string. */
+private int
+quant_params(gs_param_list * plist, gs_param_name key, int count,
+ UINT16 * pvals, floatp QFactor)
+{
+ int i;
+ gs_param_string bytes;
+ gs_param_float_array floats;
+ int code = param_read_string(plist, key, &bytes);
+
+ switch (code) {
+ case 0:
+ if (bytes.size != count) {
+ code = gs_note_error(gs_error_rangecheck);
+ break;
+ }
+ for (i = 0; i < count; ++i) {
+ double v = bytes.data[i] * QFactor;
+
+ pvals[jpeg_order(i)] =
+ (UINT16) (v < 1 ? 1 : v > 255 ? 255 : v + 0.5);
+ }
+ return 0;
+ default: /* might be a float array */
+ code = param_read_float_array(plist, key, &floats);
+ if (!code) {
+ if (floats.size != count) {
+ code = gs_note_error(gs_error_rangecheck);
+ break;
+ }
+ for (i = 0; i < count; ++i) {
+ double v = floats.data[i] * QFactor;
+
+ pvals[jpeg_order(i)] =
+ (UINT16) (v < 1 ? 1 : v > 255 ? 255 : v + 0.5);
+ }
+ }
+ }
+ if (code < 0)
+ param_signal_error(plist, key, code);
+ return code;
+#undef jpeg_order
+}
+
+/* ---------------- Main procedures ---------------- */
+
+/* Put common scalars. */
+int
+s_DCT_put_params(gs_param_list * plist, stream_DCT_state * pdct)
+{
+ int code =
+ gs_param_read_items(plist, pdct, s_DCT_param_items);
+
+ if (code < 0)
+ return code;
+ code = gs_param_read_items(plist, pdct->data.common, jsd_param_items);
+ if (code < 0)
+ return code;
+ if (pdct->data.common->Picky < 0 || pdct->data.common->Picky > 1 ||
+ pdct->data.common->Relax < 0 || pdct->data.common->Relax > 1 ||
+ pdct->ColorTransform < -1 || pdct->ColorTransform > 2 ||
+ pdct->QFactor < 0.0 || pdct->QFactor > 1000000.0
+ )
+ return_error(gs_error_rangecheck);
+ return 0;
+}
+
+/* Put quantization tables. */
+int
+s_DCT_put_quantization_tables(gs_param_list * plist, stream_DCT_state * pdct,
+ bool is_encode)
+{
+ int code;
+ int i, j;
+ gs_param_array quant_tables; /* array of strings/arrays */
+ int num_in_tables;
+ int num_out_tables;
+ jpeg_component_info *comp_info;
+ JQUANT_TBL **table_ptrs;
+ JQUANT_TBL *this_table;
+
+ switch ((code = param_begin_read_dict(plist, "QuantTables",
+ &quant_tables, true))
+ ) {
+ case 1:
+ return 0;
+ default:
+ return param_signal_error(plist, "QuantTables", code);
+ case 0:
+ ;
+ }
+ if (is_encode) {
+ num_in_tables = pdct->data.compress->cinfo.num_components;
+ if (quant_tables.size < num_in_tables)
+ return_error(gs_error_rangecheck);
+ comp_info = pdct->data.compress->cinfo.comp_info;
+ table_ptrs = pdct->data.compress->cinfo.quant_tbl_ptrs;
+ } else {
+ num_in_tables = quant_tables.size;
+ comp_info = NULL; /* do not set for decompress case */
+ table_ptrs = pdct->data.decompress->dinfo.quant_tbl_ptrs;
+ }
+ num_out_tables = 0;
+ for (i = 0; i < num_in_tables; ++i) {
+ char istr[5]; /* i converted to string key */
+ UINT16 values[DCTSIZE2];
+
+ sprintf(istr, "%d", i);
+ code = quant_params(quant_tables.list, istr, DCTSIZE2, values,
+ pdct->QFactor);
+ if (code < 0)
+ return code;
+ /* Check for duplicate tables. */
+ for (j = 0; j < num_out_tables; j++) {
+ if (!memcmp(table_ptrs[j]->quantval, values, sizeof(values)))
+ break;
+ }
+ if (comp_info != NULL)
+ comp_info[i].quant_tbl_no = j;
+ if (j < num_out_tables) /* found a duplicate */
+ continue;
+ if (++num_out_tables > NUM_QUANT_TBLS)
+ return_error(gs_error_rangecheck);
+ this_table = table_ptrs[j];
+ if (this_table == NULL) {
+ this_table = gs_jpeg_alloc_quant_table(pdct);
+ if (this_table == NULL)
+ return_error(gs_error_VMerror);
+ table_ptrs[j] = this_table;
+ }
+ memcpy(this_table->quantval, values, sizeof(values));
+ }
+ return 0;
+}
+
+/* Put Huffman tables. */
+private int
+find_huff_values(JHUFF_TBL ** table_ptrs, int num_tables,
+ const UINT8 counts[16], const UINT8 * values, int codes_size)
+{
+ int j;
+
+ for (j = 0; j < num_tables; ++j)
+ if (!memcmp(table_ptrs[j]->bits, counts, sizeof(counts)) &&
+ !memcmp(table_ptrs[j]->huffval, values,
+ codes_size * sizeof(values[0])))
+ break;
+ return j;
+}
+int
+s_DCT_put_huffman_tables(gs_param_list * plist, stream_DCT_state * pdct,
+ bool is_encode)
+{
+ int code;
+ int i, j;
+ gs_param_array huff_tables;
+ int num_in_tables;
+ int ndc, nac;
+ int codes_size;
+ jpeg_component_info *comp_info;
+ JHUFF_TBL **dc_table_ptrs;
+ JHUFF_TBL **ac_table_ptrs;
+ JHUFF_TBL **this_table_ptr;
+ JHUFF_TBL *this_table;
+ int max_tables = 2; /* baseline limit */
+
+ switch ((code = param_begin_read_dict(plist, "HuffTables",
+ &huff_tables, true))
+ ) {
+ case 1:
+ return 0;
+ default:
+ return param_signal_error(plist, "HuffTables", code);
+ case 0:
+ ;
+ }
+ if (is_encode) {
+ num_in_tables = pdct->data.compress->cinfo.input_components * 2;
+ if (huff_tables.size < num_in_tables)
+ return_error(gs_error_rangecheck);
+ comp_info = pdct->data.compress->cinfo.comp_info;
+ dc_table_ptrs = pdct->data.compress->cinfo.dc_huff_tbl_ptrs;
+ ac_table_ptrs = pdct->data.compress->cinfo.ac_huff_tbl_ptrs;
+ if (pdct->data.common->Relax)
+ max_tables = max(pdct->data.compress->cinfo.input_components, 2);
+ } else {
+ num_in_tables = huff_tables.size;
+ comp_info = NULL; /* do not set for decompress case */
+ dc_table_ptrs = pdct->data.decompress->dinfo.dc_huff_tbl_ptrs;
+ ac_table_ptrs = pdct->data.decompress->dinfo.ac_huff_tbl_ptrs;
+ if (pdct->data.common->Relax)
+ max_tables = NUM_HUFF_TBLS;
+ }
+ ndc = nac = 0;
+ for (i = 0; i < num_in_tables; ++i) {
+ char istr[5]; /* i converted to string key */
+ UINT8 counts[16], values[256];
+
+ /* Collect the Huffman parameters. */
+ sprintf(istr, "%d", i);
+ code = s_DCT_byte_params(huff_tables.list, istr, 0, 16, counts);
+ if (code < 0)
+ return code;
+ for (codes_size = 0, j = 0; j < 16; j++)
+ codes_size += counts[j];
+ if (codes_size > 256 /*|| r_size(pa) != codes_size+16 */ )
+ return_error(gs_error_rangecheck);
+ code = s_DCT_byte_params(huff_tables.list, istr, 16, codes_size,
+ values);
+ if (code < 0)
+ return code;
+ if (i & 1) {
+ j = find_huff_values(ac_table_ptrs, nac, counts, values,
+ codes_size);
+ if (comp_info != NULL)
+ comp_info[i >> 1].ac_tbl_no = j;
+ if (j < nac)
+ continue;
+ if (++nac > NUM_HUFF_TBLS)
+ return_error(gs_error_rangecheck);
+ this_table_ptr = ac_table_ptrs + j;
+ } else {
+ j = find_huff_values(dc_table_ptrs, ndc, counts, values,
+ codes_size);
+ if (comp_info != NULL)
+ comp_info[i >> 1].dc_tbl_no = j;
+ if (j < ndc)
+ continue;
+ if (++ndc > NUM_HUFF_TBLS)
+ return_error(gs_error_rangecheck);
+ this_table_ptr = dc_table_ptrs + j;
+ }
+ this_table = *this_table_ptr;
+ if (this_table == NULL) {
+ this_table = gs_jpeg_alloc_huff_table(pdct);
+ if (this_table == NULL)
+ return_error(gs_error_VMerror);
+ *this_table_ptr = this_table;
+ }
+ memcpy(this_table->bits, counts, sizeof(counts));
+ memcpy(this_table->huffval, values, codes_size * sizeof(values[0]));
+ }
+ if (nac > max_tables || ndc > max_tables)
+ return_error(gs_error_rangecheck);
+ return 0;
+}
+#endif /* HAVE_LIBJPEG */
diff --git a/pstoraster/sdcparam.h b/pstoraster/sdcparam.h
new file mode 100644
index 000000000..ae3750310
--- /dev/null
+++ b/pstoraster/sdcparam.h
@@ -0,0 +1,57 @@
+/* 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$ */
+/* DCT filter parameter setting and reading interface */
+
+#ifndef sdcparam_INCLUDED
+# define sdcparam_INCLUDED
+
+/*
+ * All of these procedures are defined in sdcparam.c and are only for
+ * internal use (by sddparam.c and sdeparam.c), so they are not
+ * documented here.
+ */
+
+int s_DCT_get_params(P3(gs_param_list * plist, const stream_DCT_state * ss,
+ const stream_DCT_state * defaults));
+int s_DCT_get_quantization_tables(P4(gs_param_list * plist,
+ const stream_DCT_state * pdct,
+ const stream_DCT_state * defaults,
+ bool is_encode));
+int s_DCT_get_huffman_tables(P4(gs_param_list * plist,
+ const stream_DCT_state * pdct,
+ const stream_DCT_state * defaults,
+ bool is_encode));
+
+int s_DCT_byte_params(P5(gs_param_list * plist, gs_param_name key, int start,
+ int count, UINT8 * pvals));
+int s_DCT_put_params(P2(gs_param_list * plist, stream_DCT_state * pdct));
+int s_DCT_put_quantization_tables(P3(gs_param_list * plist,
+ stream_DCT_state * pdct,
+ bool is_encode));
+int s_DCT_put_huffman_tables(P3(gs_param_list * plist, stream_DCT_state * pdct,
+ bool is_encode));
+
+#endif /* sdcparam_INCLUDED */
diff --git a/pstoraster/sdct.h b/pstoraster/sdct.h
new file mode 100644
index 000000000..cffc646b8
--- /dev/null
+++ b/pstoraster/sdct.h
@@ -0,0 +1,121 @@
+/* Copyright (C) 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$ */
+/* Requires stream.h, strimpl.h, jpeg/jpeglib.h */
+
+#ifndef sdct_INCLUDED
+# define sdct_INCLUDED
+
+#include <setjmp.h> /* for jmp_buf */
+
+/* ------ DCT filters ------ */
+
+/*
+ * Define the stream state.
+ * The jpeg_xxx_data structs are allocated in immovable memory
+ * to simplify use of the IJG library.
+ */
+#define jpeg_stream_data_common\
+ /* We put a copy of the stream template here, because */\
+ /* the minimum buffer sizes depend on the image parameters. */\
+ stream_template template;\
+ struct jpeg_error_mgr err;\
+ jmp_buf exit_jmpbuf;\
+ gs_memory_t *memory; /* heap for library allocations */\
+ /* The following are documented in Adobe TN 5116. */\
+ int Picky; /* 0 or 1 */\
+ int Relax /* 0 or 1 */
+typedef struct jpeg_stream_data_s {
+ jpeg_stream_data_common;
+} jpeg_stream_data;
+
+/* Define initialization for the non-library part of the stream state. */
+#define jpeg_stream_data_common_init(pdata)\
+ ((pdata)->Picky = 0, (pdata)->Relax = 0)
+
+typedef struct jpeg_compress_data_s {
+ jpeg_stream_data_common;
+ /* cinfo must immediately follow the common fields */
+ struct jpeg_compress_struct cinfo;
+ struct jpeg_destination_mgr destination;
+} jpeg_compress_data;
+
+typedef struct jpeg_decompress_data_s {
+ jpeg_stream_data_common;
+ /* dinfo must immediately follow the common fields, */
+ /* so that it has same offset as cinfo. */
+ struct jpeg_decompress_struct dinfo;
+ struct jpeg_source_mgr source;
+ long skip; /* # of bytes remaining to skip in input */
+ bool input_eod; /* true when no more input data available */
+ bool faked_eoi; /* true when fill_input_buffer inserted EOI */
+ byte *scanline_buffer; /* buffer for oversize scanline, or NULL */
+ uint bytes_in_scanline; /* # of bytes remaining to output from same */
+} jpeg_decompress_data;
+
+/* The stream state itself. This is kept in garbage-collectable memory. */
+typedef struct stream_DCT_state_s {
+ stream_state_common;
+ /* The following are set before initialization. */
+ /* Note that most JPEG parameters go straight into */
+ /* the IJG data structures, not into this struct. */
+ gs_const_string Markers; /* NULL if no Markers parameter */
+ float QFactor;
+ int ColorTransform; /* -1 if not specified */
+ bool NoMarker; /* DCTEncode only */
+ gs_memory_t *jpeg_memory; /* heap for library allocations */
+ /* This is a pointer to immovable storage. */
+ union _jd {
+ jpeg_stream_data *common;
+ jpeg_compress_data *compress;
+ jpeg_decompress_data *decompress;
+ } data;
+ /* DCTEncode sets this before initialization;
+ * DCTDecode cannot set it until the JPEG headers are read.
+ */
+ uint scan_line_size;
+ /* The following are updated dynamically. */
+ int phase;
+} stream_DCT_state;
+
+/* The state descriptor is public only to allow us to split up */
+/* the encoding and decoding filters. */
+extern_st(st_DCT_state);
+#define public_st_DCT_state() /* in sdctc.c */\
+ gs_public_st_const_strings1(st_DCT_state, stream_DCT_state,\
+ "DCTEncode/Decode state", dct_enum_ptrs, dct_reloc_ptrs, Markers)
+
+/*
+ * NOTE: the client *must* invoke the set_defaults procedure in the
+ * template before calling the init procedure.
+ */
+extern const stream_template s_DCTD_template;
+extern const stream_template s_DCTE_template;
+
+/* Define an internal procedure for setting stream defaults. */
+/* Clients do not call this. */
+void s_DCT_set_defaults(P1(stream_state * st));
+
+#endif /* sdct_INCLUDED */
diff --git a/pstoraster/sdctc.c b/pstoraster/sdctc.c
new file mode 100644
index 000000000..0a833e59e
--- /dev/null
+++ b/pstoraster/sdctc.c
@@ -0,0 +1,55 @@
+/*
+ Copyright 1993-2002 by Easy Software Products.
+ Copyright 1994, 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.
+*/
+#include <config.h>
+#ifdef HAVE_LIBJPEG
+
+/*$Id$ */
+/* Code common to DCT encoding and decoding streams */
+#include "stdio_.h"
+#include "gsmemory.h"
+#include "gsmalloc.h"
+#include "jpeglib.h"
+#include "strimpl.h"
+#include "sdct.h"
+
+public_st_DCT_state();
+
+/* Set the defaults for the DCT filters. */
+void
+s_DCT_set_defaults(stream_state * st)
+{
+ stream_DCT_state *const ss = (stream_DCT_state *) st;
+
+ ss->jpeg_memory = &gs_memory_default;
+ ss->data.common = 0;
+ /****************
+ ss->data.common->Picky = 0;
+ ss->data.common->Relax = 0;
+ ****************/
+ ss->ColorTransform = -1;
+ ss->QFactor = 1.0;
+}
+#endif /* HAVE_LIBJPEG */
diff --git a/pstoraster/sdctd.c b/pstoraster/sdctd.c
new file mode 100644
index 000000000..4e18fe482
--- /dev/null
+++ b/pstoraster/sdctd.c
@@ -0,0 +1,303 @@
+/*
+ Copyright 1993-2002 by Easy Software Products.
+ Copyright 1994, 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.
+*/
+#include <config.h>
+#ifdef HAVE_LIBJPEG
+
+/*$Id$ */
+/* DCT decoding filter stream */
+#include "memory_.h"
+#include "stdio_.h"
+#include "jpeglib.h"
+#include "jerror.h"
+#include "gdebug.h"
+#include "gsmemory.h" /* for gsmalloc.h */
+#include "gsmalloc.h" /* for gs_memory_default */
+#include "strimpl.h"
+#include "sdct.h"
+#include "sjpeg.h"
+
+/* ------ DCTDecode ------ */
+
+/* JPEG source manager procedures */
+private void
+dctd_init_source(j_decompress_ptr dinfo)
+{
+}
+static const JOCTET fake_eoi[2] =
+{0xFF, JPEG_EOI};
+private boolean
+dctd_fill_input_buffer(j_decompress_ptr dinfo)
+{
+ jpeg_decompress_data *jddp =
+ (jpeg_decompress_data *) ((char *)dinfo -
+ offset_of(jpeg_decompress_data, dinfo));
+
+ if (!jddp->input_eod)
+ return FALSE; /* normal case: suspend processing */
+ /* Reached end of source data without finding EOI */
+ WARNMS(dinfo, JWRN_JPEG_EOF);
+ /* Insert a fake EOI marker */
+ dinfo->src->next_input_byte = fake_eoi;
+ dinfo->src->bytes_in_buffer = 2;
+ jddp->faked_eoi = true; /* so process routine doesn't use next_input_byte */
+ return TRUE;
+}
+private void
+dctd_skip_input_data(j_decompress_ptr dinfo, long num_bytes)
+{
+ struct jpeg_source_mgr *src = dinfo->src;
+ jpeg_decompress_data *jddp =
+ (jpeg_decompress_data *) ((char *)dinfo -
+ offset_of(jpeg_decompress_data, dinfo));
+
+ if (num_bytes > 0) {
+ if (num_bytes > src->bytes_in_buffer) {
+ jddp->skip += num_bytes - src->bytes_in_buffer;
+ src->next_input_byte += src->bytes_in_buffer;
+ src->bytes_in_buffer = 0;
+ return;
+ }
+ src->next_input_byte += num_bytes;
+ src->bytes_in_buffer -= num_bytes;
+ }
+}
+private void
+dctd_term_source(j_decompress_ptr dinfo)
+{
+}
+
+/* Set the defaults for the DCTDecode filter. */
+private void
+s_DCTD_set_defaults(stream_state * st)
+{
+ s_DCT_set_defaults(st);
+}
+
+/* Initialize DCTDecode filter */
+private int
+s_DCTD_init(stream_state * st)
+{
+ stream_DCT_state *const ss = (stream_DCT_state *) st;
+ struct jpeg_source_mgr *src = &ss->data.decompress->source;
+
+ src->init_source = dctd_init_source;
+ src->fill_input_buffer = dctd_fill_input_buffer;
+ src->skip_input_data = dctd_skip_input_data;
+ src->term_source = dctd_term_source;
+ src->resync_to_restart = jpeg_resync_to_restart; /* use default method */
+ ss->data.common->memory = ss->jpeg_memory;
+ ss->data.decompress->dinfo.src = src;
+ ss->data.decompress->skip = 0;
+ ss->data.decompress->input_eod = false;
+ ss->data.decompress->faked_eoi = false;
+ ss->phase = 0;
+ return 0;
+}
+
+/* Process a buffer */
+private int
+s_DCTD_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last)
+{
+ stream_DCT_state *const ss = (stream_DCT_state *) st;
+ jpeg_decompress_data *jddp = ss->data.decompress;
+ struct jpeg_source_mgr *src = jddp->dinfo.src;
+ int code;
+
+ if_debug3('w', "[wdd]process avail=%u, skip=%u, last=%d\n",
+ (uint) (pr->limit - pr->ptr), (uint) jddp->skip, last);
+ if (jddp->skip != 0) {
+ long avail = pr->limit - pr->ptr;
+
+ if (avail < jddp->skip) {
+ jddp->skip -= avail;
+ pr->ptr = pr->limit;
+ if (!last)
+ return 0; /* need more data */
+ jddp->skip = 0; /* don't skip past input EOD */
+ }
+ pr->ptr += jddp->skip;
+ jddp->skip = 0;
+ }
+ src->next_input_byte = pr->ptr + 1;
+ src->bytes_in_buffer = pr->limit - pr->ptr;
+ jddp->input_eod = last;
+ switch (ss->phase) {
+ case 0: /* not initialized yet */
+ /*
+ * Adobe implementations seem to ignore leading garbage bytes,
+ * even though neither the standard nor Adobe's own
+ * documentation mention this.
+ */
+ while (pr->ptr < pr->limit && pr->ptr[1] != 0xff)
+ pr->ptr++;
+ if (pr->ptr == pr->limit)
+ return 0;
+ src->next_input_byte = pr->ptr + 1;
+ src->bytes_in_buffer = pr->limit - pr->ptr;
+ ss->phase = 1;
+ /* falls through */
+ case 1: /* reading header markers */
+ if ((code = gs_jpeg_read_header(ss, TRUE)) < 0)
+ return ERRC;
+ pr->ptr =
+ (jddp->faked_eoi ? pr->limit : src->next_input_byte - 1);
+ switch (code) {
+ case JPEG_SUSPENDED:
+ return 0;
+ /*case JPEG_HEADER_OK: */
+ }
+ /* If we have a ColorTransform parameter, and it's not
+ * overridden by an Adobe marker in the data, set colorspace.
+ */
+ if (ss->ColorTransform >= 0 &&
+ !jddp->dinfo.saw_Adobe_marker) {
+ switch (jddp->dinfo.num_components) {
+ case 3:
+ jddp->dinfo.jpeg_color_space =
+ (ss->ColorTransform ? JCS_YCbCr : JCS_RGB);
+ /* out_color_space will default to JCS_RGB */
+ break;
+ case 4:
+ jddp->dinfo.jpeg_color_space =
+ (ss->ColorTransform ? JCS_YCCK : JCS_CMYK);
+ /* out_color_space will default to JCS_CMYK */
+ break;
+ }
+ }
+ ss->phase = 2;
+ /* falls through */
+ case 2: /* start_decompress */
+ if ((code = gs_jpeg_start_decompress(ss)) < 0)
+ return ERRC;
+ pr->ptr =
+ (jddp->faked_eoi ? pr->limit : src->next_input_byte - 1);
+ if (code == 0)
+ return 0;
+ ss->scan_line_size =
+ jddp->dinfo.output_width * jddp->dinfo.output_components;
+ if_debug4('w', "[wdd]width=%u, components=%d, scan_line_size=%u, min_out_size=%u\n",
+ jddp->dinfo.output_width,
+ jddp->dinfo.output_components,
+ ss->scan_line_size, jddp->template.min_out_size);
+ if (ss->scan_line_size > (uint) jddp->template.min_out_size) {
+ /* Create a spare buffer for oversize scanline */
+ jddp->scanline_buffer =
+ gs_alloc_bytes_immovable(jddp->memory,
+ ss->scan_line_size,
+ "s_DCTD_process(scanline_buffer)");
+ if (jddp->scanline_buffer == NULL)
+ return ERRC;
+ }
+ jddp->bytes_in_scanline = 0;
+ ss->phase = 3;
+ /* falls through */
+ case 3: /* reading data */
+ dumpbuffer:
+ if (jddp->bytes_in_scanline != 0) {
+ uint avail = pw->limit - pw->ptr;
+ uint tomove = min(jddp->bytes_in_scanline,
+ avail);
+
+ if_debug2('w', "[wdd]moving %u/%u\n",
+ tomove, avail);
+ memcpy(pw->ptr + 1, jddp->scanline_buffer +
+ (ss->scan_line_size - jddp->bytes_in_scanline),
+ tomove);
+ pw->ptr += tomove;
+ jddp->bytes_in_scanline -= tomove;
+ if (jddp->bytes_in_scanline != 0)
+ return 1; /* need more room */
+ }
+ while (jddp->dinfo.output_height > jddp->dinfo.output_scanline) {
+ int read;
+ byte *samples;
+
+ if (jddp->scanline_buffer != NULL)
+ samples = jddp->scanline_buffer;
+ else {
+ if ((uint) (pw->limit - pw->ptr) < ss->scan_line_size)
+ return 1; /* need more room */
+ samples = pw->ptr + 1;
+ }
+ read = gs_jpeg_read_scanlines(ss, &samples, 1);
+ if (read < 0)
+ return ERRC;
+ if_debug3('w', "[wdd]read returns %d, used=%u, faked_eoi=%d\n",
+ read,
+ (uint) (src->next_input_byte - 1 - pr->ptr),
+ (int)jddp->faked_eoi);
+ pr->ptr =
+ (jddp->faked_eoi ? pr->limit : src->next_input_byte - 1);
+ if (!read)
+ return 0; /* need more data */
+ if (jddp->scanline_buffer != NULL) {
+ jddp->bytes_in_scanline = ss->scan_line_size;
+ goto dumpbuffer;
+ }
+ pw->ptr += ss->scan_line_size;
+ }
+ ss->phase = 4;
+ /* falls through */
+ case 4: /* end of image; scan for EOI */
+ if ((code = gs_jpeg_finish_decompress(ss)) < 0)
+ return ERRC;
+ pr->ptr =
+ (jddp->faked_eoi ? pr->limit : src->next_input_byte - 1);
+ if (code == 0)
+ return 0;
+ ss->phase = 5;
+ /* falls through */
+ case 5: /* we are DONE */
+ return EOFC;
+ }
+ /* Default case can't happen.... */
+ return ERRC;
+}
+
+/* Release the stream */
+private void
+s_DCTD_release(stream_state * st)
+{
+ stream_DCT_state *const ss = (stream_DCT_state *) st;
+
+ gs_jpeg_destroy(ss);
+ if (ss->data.decompress->scanline_buffer != NULL)
+ gs_free_object(ss->data.common->memory,
+ ss->data.decompress->scanline_buffer,
+ "s_DCTD_release(scanline_buffer)");
+ gs_free_object(ss->data.common->memory, ss->data.decompress,
+ "s_DCTD_release");
+ /* Switch the template pointer back in case we still need it. */
+ st->template = &s_DCTD_template;
+}
+
+/* Stream template */
+const stream_template s_DCTD_template =
+{&st_DCT_state, s_DCTD_init, s_DCTD_process, 2000, 4000, s_DCTD_release,
+ s_DCTD_set_defaults
+};
+#endif /* HAVE_LIBJPEG */
diff --git a/pstoraster/sdcte.c b/pstoraster/sdcte.c
new file mode 100644
index 000000000..dcd1d78cf
--- /dev/null
+++ b/pstoraster/sdcte.c
@@ -0,0 +1,203 @@
+/*
+ Copyright 1993-2002 by Easy Software Products.
+ Copyright 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.
+*/
+#include <config.h>
+#ifdef HAVE_LIBJPEG
+
+/*$Id$ */
+/* DCT encoding filter stream */
+#include "memory_.h"
+#include "stdio_.h"
+#include "jpeglib.h"
+#include "jerror.h"
+#include "gdebug.h"
+#include "gsmemory.h" /* for gsmalloc.h */
+#include "gsmalloc.h" /* for gs_memory_default */
+#include "strimpl.h"
+#include "sdct.h"
+#include "sjpeg.h"
+
+/* ------ DCTEncode ------ */
+
+/* JPEG destination manager procedures */
+private void
+dcte_init_destination(j_compress_ptr cinfo)
+{
+}
+private boolean
+dcte_empty_output_buffer(j_compress_ptr cinfo)
+{
+ return FALSE;
+}
+private void
+dcte_term_destination(j_compress_ptr cinfo)
+{
+}
+
+/* Set the defaults for the DCTEncode filter. */
+private void
+s_DCTE_set_defaults(stream_state * st)
+{
+ stream_DCT_state *const ss = (stream_DCT_state *) st;
+
+ s_DCT_set_defaults(st);
+ ss->QFactor = 1.0;
+ ss->ColorTransform = 0;
+ ss->Markers.data = 0;
+ ss->Markers.size = 0;
+ ss->NoMarker = true;
+}
+
+/* Initialize DCTEncode filter */
+private int
+s_DCTE_init(stream_state * st)
+{
+ stream_DCT_state *const ss = (stream_DCT_state *) st;
+ struct jpeg_destination_mgr *dest = &ss->data.compress->destination;
+
+ dest->init_destination = dcte_init_destination;
+ dest->empty_output_buffer = dcte_empty_output_buffer;
+ dest->term_destination = dcte_term_destination;
+ ss->data.common->memory = ss->jpeg_memory;
+ ss->data.compress->cinfo.dest = dest;
+ ss->phase = 0;
+ return 0;
+}
+
+/* Process a buffer */
+private int
+s_DCTE_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last)
+{
+ stream_DCT_state *const ss = (stream_DCT_state *) st;
+ jpeg_compress_data *jcdp = ss->data.compress;
+ struct jpeg_destination_mgr *dest = jcdp->cinfo.dest;
+
+ dest->next_output_byte = pw->ptr + 1;
+ dest->free_in_buffer = pw->limit - pw->ptr;
+ switch (ss->phase) {
+ case 0: /* not initialized yet */
+ if (gs_jpeg_start_compress(ss, TRUE) < 0)
+ return ERRC;
+ pw->ptr = dest->next_output_byte - 1;
+ ss->phase = 1;
+ /* falls through */
+ case 1: /* initialized, Markers not written */
+ if (pw->limit - pw->ptr < ss->Markers.size)
+ return 1;
+ memcpy(pw->ptr + 1, ss->Markers.data, ss->Markers.size);
+ pw->ptr += ss->Markers.size;
+ ss->phase = 2;
+ /* falls through */
+ case 2: /* still need to write Adobe marker */
+ if (!ss->NoMarker) {
+ static const byte Adobe[] =
+ {
+ 0xFF, JPEG_APP0 + 14, 0, 14, /* parameter length */
+ 'A', 'd', 'o', 'b', 'e',
+ 0, 100, /* Version */
+ 0, 0, /* Flags0 */
+ 0, 0, /* Flags1 */
+ 0 /* ColorTransform */
+ };
+
+#define ADOBE_MARKER_LEN sizeof(Adobe)
+ if (pw->limit - pw->ptr < ADOBE_MARKER_LEN)
+ return 1;
+ memcpy(pw->ptr + 1, Adobe, ADOBE_MARKER_LEN);
+ pw->ptr += ADOBE_MARKER_LEN;
+ *pw->ptr = ss->ColorTransform;
+#undef ADOBE_MARKER_LEN
+ }
+ dest->next_output_byte = pw->ptr + 1;
+ dest->free_in_buffer = pw->limit - pw->ptr;
+ ss->phase = 3;
+ /* falls through */
+ case 3: /* markers written, processing data */
+ while (jcdp->cinfo.image_height > jcdp->cinfo.next_scanline) {
+ int written;
+
+ /*
+ * The data argument for jpeg_write_scanlines is
+ * declared as a JSAMPARRAY. There is no corresponding
+ * const type, so we must remove const from the
+ * argument that we are passing here. (Tom Lane of IJG
+ * judges that providing const analogues of the
+ * interface types wouldn't be worth the trouble.)
+ */
+ /*const */ byte *samples = (byte *) (pr->ptr + 1);
+
+ if ((uint) (pr->limit - pr->ptr) < ss->scan_line_size) {
+ if (last)
+ return ERRC; /* premature EOD */
+ return 0; /* need more data */
+ }
+ written = gs_jpeg_write_scanlines(ss, &samples, 1);
+ if (written < 0)
+ return ERRC;
+ pw->ptr = dest->next_output_byte - 1;
+ if (!written)
+ return 1; /* output full */
+ pr->ptr += ss->scan_line_size;
+ }
+ ss->phase = 4;
+ /* falls through */
+ case 4: /* all data processed, finishing */
+ /* jpeg_finish_compress can't suspend, so make sure
+ * it has plenty of room to write the last few bytes.
+ */
+ if (pw->limit - pw->ptr < 100)
+ return 1;
+ if (gs_jpeg_finish_compress(ss) < 0)
+ return ERRC;
+ pw->ptr = dest->next_output_byte - 1;
+ ss->phase = 5;
+ /* falls through */
+ case 5: /* we are DONE */
+ return EOFC;
+ }
+ /* Default case can't happen.... */
+ return ERRC;
+}
+
+/* Release the stream */
+private void
+s_DCTE_release(stream_state * st)
+{
+ stream_DCT_state *const ss = (stream_DCT_state *) st;
+
+ gs_jpeg_destroy(ss);
+ gs_free_object(ss->data.common->memory, ss->data.compress,
+ "s_DCTE_release");
+ /* Switch the template pointer back in case we still need it. */
+ st->template = &s_DCTE_template;
+}
+
+/* Stream template */
+const stream_template s_DCTE_template =
+{&st_DCT_state, s_DCTE_init, s_DCTE_process, 1000, 4000, s_DCTE_release,
+ s_DCTE_set_defaults
+};
+#endif /* HAVE_LIBJPEG */
diff --git a/pstoraster/sddparam.c b/pstoraster/sddparam.c
new file mode 100644
index 000000000..01c3a9b17
--- /dev/null
+++ b/pstoraster/sddparam.c
@@ -0,0 +1,83 @@
+/*
+ Copyright 1993-2002 by Easy Software Products.
+ Copyright 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.
+*/
+
+#include <config.h>
+#ifdef HAVE_LIBJPEG
+/*$Id$ */
+/* DCTDecode filter parameter setting and reading */
+#include "std.h"
+#include "jpeglib.h"
+#include "gserror.h"
+#include "gserrors.h"
+#include "gstypes.h"
+#include "gsmemory.h"
+#include "gsparam.h"
+#include "strimpl.h" /* sdct.h requires this */
+#include "sdct.h"
+#include "sdcparam.h"
+#include "sjpeg.h"
+
+/* ================ Get parameters ================ */
+
+stream_state_proc_get_params(s_DCTD_get_params, stream_DCT_state); /* check */
+
+int
+s_DCTD_get_params(gs_param_list * plist, const stream_DCT_state * ss, bool all)
+{
+ stream_DCT_state dcts_defaults;
+ const stream_DCT_state *defaults;
+
+ if (all)
+ defaults = 0;
+ else {
+ (*s_DCTE_template.set_defaults) ((stream_state *) & dcts_defaults);
+ defaults = &dcts_defaults;
+ }
+/****** NYI ******/
+ return s_DCT_get_params(plist, ss, defaults);
+}
+
+/* ================ Put parameters ================ */
+
+stream_state_proc_put_params(s_DCTD_put_params, stream_DCT_state); /* check */
+
+int
+s_DCTD_put_params(gs_param_list * plist, stream_DCT_state * pdct)
+{
+ int code;
+
+ if ((code = s_DCT_put_params(plist, pdct)) < 0 ||
+ /*
+ * DCTDecode accepts quantization and huffman tables
+ * in case these tables have been omitted from the datastream.
+ */
+ (code = s_DCT_put_huffman_tables(plist, pdct, false)) < 0 ||
+ (code = s_DCT_put_quantization_tables(plist, pdct, false)) < 0
+ )
+ DO_NOTHING;
+ return code;
+}
+#endif /* HAVE_LIBJPEG */
diff --git a/pstoraster/sdeparam.c b/pstoraster/sdeparam.c
new file mode 100644
index 000000000..cb54faa35
--- /dev/null
+++ b/pstoraster/sdeparam.c
@@ -0,0 +1,328 @@
+/*
+ Copyright 1993-2002 by Easy Software Products.
+ Copyright 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.
+*/
+
+#include <config.h>
+#ifdef HAVE_LIBJPEG
+/*$Id$ */
+/* DCTEncode filter parameter setting and reading */
+#include "memory_.h"
+#include "jpeglib.h"
+#include "gserror.h"
+#include "gserrors.h"
+#include "gstypes.h"
+#include "gsmemory.h"
+#include "gsparam.h"
+#include "strimpl.h" /* sdct.h requires this */
+#include "sdct.h"
+#include "sdcparam.h"
+#include "sjpeg.h"
+
+/* Define a structure for the DCTEncode scalar parameters. */
+typedef struct dcte_scalars_s {
+ int Columns;
+ int Rows;
+ int Colors;
+ gs_param_string Markers;
+ bool NoMarker;
+ int Resync;
+ int Blend;
+} dcte_scalars_t;
+private const dcte_scalars_t dcte_scalars_default =
+{
+ 0, 0, -1,
+ {0, 0}, 0 /*false */ , 0, 0
+};
+private const gs_param_item_t s_DCTE_param_items[] =
+{
+#define dctp(key, type, memb) { key, type, offset_of(dcte_scalars_t, memb) }
+ dctp("Columns", gs_param_type_int, Columns),
+ dctp("Rows", gs_param_type_int, Rows),
+ dctp("Colors", gs_param_type_int, Colors),
+ dctp("Marker", gs_param_type_string, Markers),
+ dctp("NoMarker", gs_param_type_bool, NoMarker),
+ dctp("Resync", gs_param_type_int, Resync),
+ dctp("Blend", gs_param_type_int, Blend),
+#undef dctp
+ gs_param_item_end
+};
+
+/* ================ Get parameters ================ */
+
+stream_state_proc_get_params(s_DCTE_get_params, stream_DCT_state); /* check */
+
+/* Get a set of sampling values. */
+private int
+dcte_get_samples(gs_param_list * plist, gs_param_name key, int num_colors,
+ const jpeg_compress_data * jcdp, gs_memory_t * mem, bool is_vert, bool all)
+{
+ const jpeg_component_info *comp_info = jcdp->cinfo.comp_info;
+ int samples[4];
+ bool write = all;
+ int i;
+
+ for (i = 0; i < num_colors; ++i)
+ write |= (samples[i] = (is_vert ? comp_info[i].v_samp_factor :
+ comp_info[i].h_samp_factor)) != 1;
+ if (write) {
+ int *data = (int *)gs_alloc_byte_array(mem, num_colors, sizeof(int),
+ "dcte_get_samples");
+ gs_param_int_array sa;
+
+ if (data == 0)
+ return_error(gs_error_VMerror);
+ sa.data = data;
+ sa.size = num_colors;
+ sa.persistent = true;
+ memcpy(data, samples, num_colors * sizeof(samples[0]));
+ return param_write_int_array(plist, key, &sa);
+ }
+ return 0;
+}
+
+int
+s_DCTE_get_params(gs_param_list * plist, const stream_DCT_state * ss, bool all)
+{
+ gs_memory_t *mem = ss->memory;
+ stream_DCT_state dcts_defaults;
+ const stream_DCT_state *defaults = 0;
+ dcte_scalars_t params;
+ const jpeg_compress_data *jcdp = ss->data.compress;
+ int code;
+
+ if (!all) {
+ jpeg_compress_data *jcdp_default =
+ (jpeg_compress_data *)
+ gs_alloc_bytes_immovable(mem, sizeof(*jcdp), "s_DCTE_get_params");
+
+ if (jcdp_default == 0)
+ return_error(gs_error_VMerror);
+ defaults = &dcts_defaults;
+ (*s_DCTE_template.set_defaults) ((stream_state *) & dcts_defaults);
+ dcts_defaults.data.compress = jcdp_default;
+ jcdp_default->memory = dcts_defaults.jpeg_memory = mem;
+ if ((code = gs_jpeg_create_compress(&dcts_defaults)) < 0)
+ goto fail; /* correct to do jpeg_destroy here */
+/****** SET DEFAULTS HERE ******/
+ dcts_defaults.data.common->Picky = 0;
+ dcts_defaults.data.common->Relax = 0;
+ }
+ params.Columns = jcdp->cinfo.image_width;
+ params.Rows = jcdp->cinfo.image_height;
+ params.Colors = jcdp->cinfo.input_components;
+ params.Markers.data = ss->Markers.data;
+ params.Markers.size = ss->Markers.size;
+ params.Markers.persistent = false;
+ params.NoMarker = ss->NoMarker;
+ params.Resync = jcdp->cinfo.restart_interval;
+ /* What about Blend?? */
+ if ((code = s_DCT_get_params(plist, ss, defaults)) < 0 ||
+ (code = gs_param_write_items(plist, &params,
+ &dcte_scalars_default,
+ s_DCTE_param_items)) < 0 ||
+ (code = dcte_get_samples(plist, "HSamples", params.Colors,
+ jcdp, mem, false, all)) < 0 ||
+ (code = dcte_get_samples(plist, "VSamples", params.Colors,
+ jcdp, mem, true, all)) < 0 ||
+ (code = s_DCT_get_quantization_tables(plist, ss, defaults, true)) < 0 ||
+ (code = s_DCT_get_huffman_tables(plist, ss, defaults, true)) < 0
+ )
+ DO_NOTHING;
+/****** NYI ******/
+ fail:if (defaults) {
+ gs_jpeg_destroy(&dcts_defaults);
+ gs_free_object(mem, dcts_defaults.data.compress,
+ "s_DCTE_get_params");
+ }
+ return code;
+}
+
+/* ================ Put parameters ================ */
+
+stream_state_proc_put_params(s_DCTE_put_params, stream_DCT_state); /* check */
+
+/* Put a set of sampling values. */
+private int
+dcte_put_samples(gs_param_list * plist, gs_param_name key, int num_colors,
+ jpeg_compress_data * jcdp, bool is_vert)
+{
+ int code;
+ int i;
+ jpeg_component_info *comp_info = jcdp->cinfo.comp_info;
+ UINT8 samples[4];
+
+ /*
+ * Adobe default is all sampling factors = 1,
+ * which is NOT the IJG default, so we must always assign values.
+ */
+ switch ((code = s_DCT_byte_params(plist, key, 0, num_colors,
+ samples))
+ ) {
+ default: /* error */
+ return code;
+ case 0:
+ break;
+ case 1:
+ samples[0] = samples[1] = samples[2] = samples[3] = 1;
+ }
+ for (i = 0; i < num_colors; i++) {
+ if (samples[i] < 1 || samples[i] > 4)
+ return_error(gs_error_rangecheck);
+ if (is_vert)
+ comp_info[i].v_samp_factor = samples[i];
+ else
+ comp_info[i].h_samp_factor = samples[i];
+ }
+ return 0;
+}
+
+/* Main procedure */
+int
+s_DCTE_put_params(gs_param_list * plist, stream_DCT_state * pdct)
+{
+ jpeg_compress_data *jcdp = pdct->data.compress;
+ dcte_scalars_t params;
+ int i;
+ int code;
+
+ params = dcte_scalars_default;
+ /*
+ * Required parameters for DCTEncode.
+ * (DCTDecode gets the equivalent info from the SOF marker.)
+ */
+ code = gs_param_read_items(plist, &params, s_DCTE_param_items);
+ if (code < 0)
+ return code;
+ if (params.Columns <= 0 || params.Columns > 0xffff ||
+ params.Rows <= 0 || params.Rows > 0xffff ||
+ params.Colors <= 0 || params.Colors == 2 || params.Colors > 4 ||
+ params.Resync < 0 || params.Resync > 0xffff ||
+ params.Blend < 0 || params.Blend > 1
+ )
+ return_error(gs_error_rangecheck);
+/****** HACK: SET DEFAULTS HERE ******/
+ jcdp->Picky = 0;
+ jcdp->Relax = 0;
+ if ((code = s_DCT_put_params(plist, pdct)) < 0 ||
+ (code = s_DCT_put_huffman_tables(plist, pdct, false)) < 0
+ )
+ return code;
+ switch ((code = s_DCT_put_quantization_tables(plist, pdct, false))) {
+ case 0:
+ break;
+ default:
+ return code;
+ case 1:
+ /* No QuantTables, but maybe a QFactor to apply to default. */
+ if (pdct->QFactor != 1.0) {
+ code = gs_jpeg_set_linear_quality(pdct,
+ (int)(min(pdct->QFactor, 100.0)
+ * 100.0 + 0.5),
+ TRUE);
+ if (code < 0)
+ return code;
+ }
+ }
+ /* Set up minimal image description & call set_defaults */
+ jcdp->cinfo.image_width = params.Columns;
+ jcdp->cinfo.image_height = params.Rows;
+ jcdp->cinfo.input_components = params.Colors;
+ switch (params.Colors) {
+ case 1:
+ jcdp->cinfo.in_color_space = JCS_GRAYSCALE;
+ break;
+ case 3:
+ jcdp->cinfo.in_color_space = JCS_RGB;
+ break;
+ case 4:
+ jcdp->cinfo.in_color_space = JCS_CMYK;
+ break;
+ default:
+ jcdp->cinfo.in_color_space = JCS_UNKNOWN;
+ }
+ if ((code = gs_jpeg_set_defaults(pdct)) < 0)
+ return code;
+ /* Change IJG colorspace defaults as needed;
+ * set ColorTransform to what will go in the Adobe marker.
+ */
+ switch (params.Colors) {
+ case 3:
+ if (pdct->ColorTransform < 0)
+ pdct->ColorTransform = 1; /* default */
+ if (pdct->ColorTransform == 0) {
+ if ((code = gs_jpeg_set_colorspace(pdct, JCS_RGB)) < 0)
+ return code;
+ } else
+ pdct->ColorTransform = 1; /* flag YCC xform */
+ break;
+ case 4:
+ if (pdct->ColorTransform < 0)
+ pdct->ColorTransform = 0; /* default */
+ if (pdct->ColorTransform != 0) {
+ if ((code = gs_jpeg_set_colorspace(pdct, JCS_YCCK)) < 0)
+ return code;
+ pdct->ColorTransform = 2; /* flag YCCK xform */
+ } else {
+ if ((code = gs_jpeg_set_colorspace(pdct, JCS_CMYK)) < 0)
+ return code;
+ }
+ break;
+ default:
+ pdct->ColorTransform = 0; /* no transform otherwise */
+ break;
+ }
+ /* Optional encoding-only parameters */
+ pdct->Markers.data = params.Markers.data;
+ pdct->Markers.size = params.Markers.size;
+ pdct->NoMarker = params.NoMarker;
+ if ((code = dcte_put_samples(plist, "HSamples", params.Colors,
+ jcdp, false)) < 0 ||
+ (code = dcte_put_samples(plist, "VSamples", params.Colors,
+ jcdp, true)) < 0
+ )
+ return code;
+ jcdp->cinfo.write_JFIF_header = FALSE;
+ jcdp->cinfo.write_Adobe_marker = FALSE; /* must do it myself */
+ jcdp->cinfo.restart_interval = params.Resync;
+ /* What to do with Blend ??? */
+ if (pdct->data.common->Relax == 0) {
+ jpeg_component_info *comp_info = jcdp->cinfo.comp_info;
+ int num_samples;
+
+ for (i = 0, num_samples = 0; i < params.Colors; i++)
+ num_samples += comp_info[i].h_samp_factor *
+ comp_info[i].v_samp_factor;
+ if (num_samples > 10)
+ return_error(gs_error_rangecheck);
+ /*
+ * Note: by default the IJG software does not allow
+ * num_samples to exceed 10, Relax or no. For full
+ * compatibility with Adobe's non-JPEG-compliant
+ * software, set MAX_BLOCKS_IN_MCU to 64 in jpeglib.h.
+ */
+ }
+ return 0;
+}
+#endif /* HAVE_LIBJPEG */
diff --git a/pstoraster/seexec.c b/pstoraster/seexec.c
new file mode 100644
index 000000000..df6fb3e0b
--- /dev/null
+++ b/pstoraster/seexec.c
@@ -0,0 +1,192 @@
+/* Copyright (C) 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$ */
+/* eexec filters */
+#include "stdio_.h" /* includes std.h */
+#include "strimpl.h"
+#include "sfilter.h"
+#include "gscrypt1.h"
+#include "scanchar.h"
+
+/* ------ eexecEncode ------ */
+
+/* Encoding is much simpler than decoding, because we don't */
+/* worry about initial characters or hex vs. binary (the client */
+/* has to take care of these aspects). */
+
+private_st_exE_state();
+
+/* Process a buffer */
+private int
+s_exE_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last)
+{
+ stream_exE_state *const ss = (stream_exE_state *) st;
+ const byte *p = pr->ptr;
+ byte *q = pw->ptr;
+ uint rcount = pr->limit - p;
+ uint wcount = pw->limit - q;
+ uint count;
+ int status;
+
+ if (rcount <= wcount)
+ count = rcount, status = 0;
+ else
+ count = wcount, status = 1;
+ gs_type1_encrypt(q + 1, p + 1, count, (crypt_state *)&ss->cstate);
+ pr->ptr += count;
+ pw->ptr += count;
+ return status;
+}
+
+/* Stream template */
+const stream_template s_exE_template = {
+ &st_exE_state, NULL, s_exE_process, 1, 2
+};
+
+/* ------ eexecDecode ------ */
+
+private_st_exD_state();
+
+/* Set defaults. */
+private void
+s_exD_set_defaults(stream_state * st)
+{
+ stream_exD_state *const ss = (stream_exD_state *) st;
+
+ ss->lenIV = 4;
+}
+
+/* Initialize the state for reading and decrypting. */
+/* Decrypting streams are not positionable. */
+private int
+s_exD_init(stream_state * st)
+{
+ stream_exD_state *const ss = (stream_exD_state *) st;
+
+ ss->odd = -1;
+ ss->binary = -1; /* unknown */
+ ss->record_left = max_long;
+ ss->skip = ss->lenIV;
+ return 0;
+}
+
+/* Process a buffer. */
+private int
+s_exD_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last)
+{
+ stream_exD_state *const ss = (stream_exD_state *) st;
+ const byte *p = pr->ptr;
+ byte *q = pw->ptr;
+ int skip = ss->skip;
+ int rcount = pr->limit - p;
+ int wcount = pw->limit - q;
+ int status = 0;
+ int count = (wcount < rcount ? (status = 1, wcount) : rcount);
+
+ if (ss->binary < 0) {
+ /*
+ * This is the very first time we're filling the buffer.
+ * Determine whether this is ASCII or hex encoding.
+ */
+ const byte *const decoder = scan_char_decoder;
+ int i;
+
+ if (rcount < 8)
+ return 0;
+ /*
+ * Adobe's documentation doesn't actually specify the test
+ * that eexec should use, but we believe the following
+ * gives correct answers even on certain non-conforming
+ * PostScript files encountered in practice:
+ */
+ ss->binary = 0;
+ for (i = 1; i <= 8; i++)
+ if (!(decoder[p[i]] <= 0xf ||
+ decoder[p[i]] == ctype_space)
+ ) {
+ ss->binary = 1;
+ if (ss->pfb_state != 0) {
+ /* Stop at the end of the .PFB binary data. */
+ ss->record_left = ss->pfb_state->record_left;
+ }
+ break;
+ }
+ }
+ if (ss->binary) {
+ if (count > ss->record_left) {
+ count = ss->record_left;
+ status = 0;
+ }
+ /*
+ * We pause at the end of the .PFB binary data,
+ * in an attempt to keep from reading beyond the end of
+ * the encrypted data.
+ */
+ if ((ss->record_left -= count) == 0)
+ ss->record_left = max_long;
+ pr->ptr = p + count;
+ } else {
+ /*
+ * We only ignore leading whitespace, in an attempt to
+ * keep from reading beyond the end of the encrypted data.
+ */
+ status = s_hex_process(pr, pw, &ss->odd,
+ hex_ignore_leading_whitespace);
+ p = q;
+ count = pw->ptr - q;
+ }
+ if (skip >= count && skip != 0) {
+ gs_type1_decrypt(q + 1, p + 1, count,
+ (crypt_state *) & ss->cstate);
+ ss->skip -= count;
+ count = 0;
+ status = 0;
+ } else {
+ gs_type1_decrypt(q + 1, p + 1, skip,
+ (crypt_state *) & ss->cstate);
+ count -= skip;
+ gs_type1_decrypt(q + 1, p + 1 + skip, count,
+ (crypt_state *) & ss->cstate);
+ ss->skip = 0;
+ }
+ pw->ptr = q + count;
+ return status;
+}
+
+/* Stream template */
+/*
+ * The specification of eexec decoding requires that it never read more than
+ * 512 source bytes ahead. The only reliable way to ensure this is to
+ * limit the size of the output buffer to 256. We set it a little smaller
+ * so that it will stay under the limit even after adding min_in_size
+ * for a subsequent filter in a pipeline. Note that we have to specify
+ * a size of at least 128 so that filter_read won't round it up.
+ */
+const stream_template s_exD_template = {
+ &st_exD_state, s_exD_init, s_exD_process, 8, 200,
+ NULL, s_exD_set_defaults
+};
diff --git a/pstoraster/sfilter.h b/pstoraster/sfilter.h
new file mode 100644
index 000000000..3daa96783
--- /dev/null
+++ b/pstoraster/sfilter.h
@@ -0,0 +1,139 @@
+/* Copyright (C) 1993, 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$ */
+/* Definitions for simple Ghostscript streams */
+/* Requires scommon.h; should require strimpl.h only if any templates */
+/* are referenced, but some compilers always require strimpl.h. */
+
+#ifndef sfilter_INCLUDED
+# define sfilter_INCLUDED
+
+#include "gstypes.h" /* for gs_[const_]string */
+
+/*
+ * Define the processing states of the simplest Ghostscript streams.
+ * We use abbreviations for the stream names so as not to exceed the
+ * 31-character limit that some compilers put on identifiers.
+ *
+ * The processing state of a stream has three logical sections:
+ * parameters set by the client before the stream is opened,
+ * values computed from the parameters at initialization time,
+ * and values that change dynamically. Unless otherwise indicated,
+ * all structure members change dynamically.
+ */
+
+/* (T)BCPEncode */
+/* (no state) */
+extern const stream_template s_BCPE_template;
+extern const stream_template s_TBCPE_template;
+
+/* (T)BCPDecode */
+typedef struct stream_BCPD_state_s {
+ stream_state_common;
+ /* The client sets the following before initialization. */
+ int (*signal_interrupt) (P1(stream_state *));
+ int (*request_status) (P1(stream_state *));
+ /* The following are updated dynamically. */
+ bool escaped;
+ int matched; /* TBCP only */
+ int copy_count; /* TBCP only */
+ const byte *copy_ptr; /* TBCP only */
+} stream_BCPD_state;
+
+#define private_st_BCPD_state() /* in sbcp.c */\
+ gs_private_st_simple(st_BCPD_state, stream_BCPD_state, "(T)BCPDecode state")
+extern const stream_template s_BCPD_template;
+extern const stream_template s_TBCPD_template;
+
+/* eexecEncode */
+typedef struct stream_exE_state_s {
+ stream_state_common;
+ /* The following parameters are set by the client. */
+ ushort cstate; /* encryption state */
+} stream_exE_state;
+
+#define private_st_exE_state() /* in sfilter1.c */\
+ gs_private_st_simple(st_exE_state, stream_exE_state, "eexecEncode state")
+extern const stream_template s_exE_template;
+
+/* eexecDecode */
+typedef struct stream_PFBD_state_s stream_PFBD_state;
+typedef struct stream_exD_state_s {
+ stream_state_common;
+ /* The following parameters are set by the client. */
+ ushort cstate; /* encryption state */
+ stream_PFBD_state *pfb_state; /* state of underlying */
+ /* PFBDecode stream, if any */
+ int binary; /* 1=binary, 0=hex, -1=don't know yet */
+ int lenIV; /* # of initial decoded bytes to skip */
+ /* The following change dynamically. */
+ int odd; /* odd digit */
+ long record_left; /* data left in binary record in .PFB file, */
+ /* max_long if not reading a .PFB file */
+ int skip; /* # of decoded bytes to skip */
+} stream_exD_state;
+
+#define private_st_exD_state() /* in seexec.c */\
+ gs_private_st_ptrs1(st_exD_state, stream_exD_state, "eexecDecode state",\
+ exd_enum_ptrs, exd_reloc_ptrs, pfb_state)
+extern const stream_template s_exD_template;
+
+/* NullEncode/Decode */
+/* (no state) */
+extern const stream_template s_NullE_template;
+extern const stream_template s_NullD_template;
+
+/* PFBDecode */
+/* The typedef for the state appears under eexecDecode above. */
+/*typedef */ struct stream_PFBD_state_s {
+ stream_state_common;
+ /* The following parameters are set by the client. */
+ int binary_to_hex;
+ /* The following change dynamically. */
+ int record_type;
+ ulong record_left; /* bytes left in current record */
+} /*stream_PFBD_state */ ;
+
+#define private_st_PFBD_state() /* in sfilter1.c */\
+ gs_private_st_simple(st_PFBD_state, stream_PFBD_state, "PFBDecode state")
+extern const stream_template s_PFBD_template;
+
+/* SubFileDecode */
+typedef struct stream_SFD_state_s {
+ stream_state_common;
+ /* The following parameters are set by the client. */
+ long count; /* # of EODs to scan over */
+ gs_const_string eod;
+ /* The following change dynamically. */
+ uint match; /* # of matched chars not copied to output */
+ uint copy_count; /* # of matched characters left to copy */
+ uint copy_ptr; /* index of next character to copy */
+} stream_SFD_state;
+#define private_st_SFD_state() /* in sfilter1.c */\
+ gs_private_st_const_strings1(st_SFD_state, stream_SFD_state,\
+ "SubFileDecode state", sfd_enum_ptrs, sfd_reloc_ptrs, eod)
+extern const stream_template s_SFD_template;
+
+#endif /* sfilter_INCLUDED */
diff --git a/pstoraster/sfilter1.c b/pstoraster/sfilter1.c
new file mode 100644
index 000000000..0a9181c4e
--- /dev/null
+++ b/pstoraster/sfilter1.c
@@ -0,0 +1,301 @@
+/* Copyright (C) 1993, 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$ */
+/* Filters included in Level 1 systems: NullEncode/Decode, PFBDecode, */
+/* SubFileDecode. */
+#include "stdio_.h" /* includes std.h */
+#include "memory_.h"
+#include "strimpl.h"
+#include "sfilter.h"
+
+/* ------ NullEncode/Decode ------ */
+
+/* Process a buffer */
+private int
+s_Null_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last)
+{
+ return stream_move(pr, pw);
+}
+
+/* Stream template */
+const stream_template s_NullE_template = {
+ &st_stream_state, NULL, s_Null_process, 1, 1
+};
+const stream_template s_NullD_template = {
+ &st_stream_state, NULL, s_Null_process, 1, 1
+};
+
+/* ------ PFBDecode ------ */
+
+private_st_PFBD_state();
+
+/* Initialize the state */
+private int
+s_PFBD_init(stream_state * st)
+{
+ stream_PFBD_state *const ss = (stream_PFBD_state *) st;
+
+ ss->record_type = -1;
+ return 0;
+}
+
+/* Process a buffer */
+private int
+s_PFBD_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last)
+{
+ stream_PFBD_state *const ss = (stream_PFBD_state *) st;
+ register const byte *p = pr->ptr;
+ register byte *q = pw->ptr;
+ int rcount, wcount;
+ int c;
+ int status = 0;
+
+top:
+ rcount = pr->limit - p;
+ wcount = pw->limit - q;
+ switch (ss->record_type) {
+ case -1: /* new record */
+ if (rcount < 2)
+ goto out;
+ if (p[1] != 0x80)
+ goto err;
+ c = p[2];
+ switch (c) {
+ case 1:
+ case 2:
+ break;
+ case 3:
+ status = EOFC;
+ p += 2;
+ goto out;
+ default:
+ p += 2;
+ goto err;
+ }
+ if (rcount < 6)
+ goto out;
+ ss->record_type = c;
+ ss->record_left = p[3] + ((uint) p[4] << 8) +
+ ((ulong) p[5] << 16) +
+ ((ulong) p[6] << 24);
+ p += 6;
+ goto top;
+ case 1: /* text data */
+ /* Translate \r to \n. */
+ {
+ int count = (wcount < rcount ? (status = 1, wcount) : rcount);
+
+ if (count > ss->record_left)
+ count = ss->record_left,
+ status = 0;
+ ss->record_left -= count;
+ for (; count != 0; count--) {
+ c = *++p;
+ *++q = (c == '\r' ? '\n' : c);
+ }
+ }
+ break;
+ case 2: /* binary data */
+ if (ss->binary_to_hex) {
+ /* Translate binary to hex. */
+ int count;
+ const char *const hex_digits = "0123456789abcdef";
+
+ wcount >>= 1; /* 2 chars per input byte */
+ count = (wcount < rcount ? (status = 1, wcount) : rcount);
+ if (count > ss->record_left)
+ count = ss->record_left,
+ status = 0;
+ ss->record_left -= count;
+ for (; count != 0; count--) {
+ c = *++p;
+ q[1] = hex_digits[c >> 4];
+ q[2] = hex_digits[c & 0xf];
+ q += 2;
+ }
+ } else { /* Just read binary data. */
+ int count = (wcount < rcount ? (status = 1, wcount) : rcount);
+
+ if (count > ss->record_left)
+ count = ss->record_left,
+ status = 0;
+ ss->record_left -= count;
+ memcpy(q + 1, p + 1, count);
+ p += count;
+ q += count;
+ }
+ break;
+ }
+ if (ss->record_left == 0) {
+ ss->record_type = -1;
+ goto top;
+ }
+out:
+ pr->ptr = p;
+ pw->ptr = q;
+ return status;
+err:
+ pr->ptr = p;
+ pw->ptr = q;
+ return ERRC;
+}
+
+/* Stream template */
+const stream_template s_PFBD_template = {
+ &st_PFBD_state, s_PFBD_init, s_PFBD_process, 6, 2
+};
+
+/* ------ SubFileDecode ------ */
+
+private_st_SFD_state();
+
+/* Initialize the stream */
+private int
+s_SFD_init(stream_state * st)
+{
+ stream_SFD_state *const ss = (stream_SFD_state *) st;
+
+ ss->match = 0;
+ ss->copy_count = 0;
+ return 0;
+}
+
+/* Refill the buffer */
+private int
+s_SFD_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last)
+{
+ stream_SFD_state *const ss = (stream_SFD_state *) st;
+ register const byte *p = pr->ptr;
+ register byte *q = pw->ptr;
+ const byte *rlimit = pr->limit;
+ byte *wlimit = pw->limit;
+ int status = 0;
+
+ if (ss->eod.size == 0) { /* Just read, with no EOD pattern. */
+ int rcount = rlimit - p;
+ int wcount = wlimit - q;
+ int count = min(rcount, wcount);
+
+ if (ss->count == 0) /* no EOD limit */
+ return stream_move(pr, pw);
+ else if (ss->count > count) { /* not EOD yet */
+ ss->count -= count;
+ return stream_move(pr, pw);
+ } else { /* We're going to reach EOD. */
+ count = ss->count;
+ memcpy(q + 1, p + 1, count);
+ pr->ptr = p + count;
+ pw->ptr = q + count;
+ return EOFC;
+ }
+ } else { /* Read looking for an EOD pattern. */
+ const byte *pattern = ss->eod.data;
+ uint match = ss->match;
+
+cp:
+ /* Check whether we're still copying a partial match. */
+ if (ss->copy_count) {
+ int count = min(wlimit - q, ss->copy_count);
+
+ memcpy(q + 1, ss->eod.data + ss->copy_ptr, count);
+ ss->copy_count -= count;
+ ss->copy_ptr += count;
+ q += count;
+ if (ss->copy_count != 0) { /* hit wlimit */
+ status = 1;
+ goto xit;
+ } else if (ss->count < 0) {
+ status = EOFC;
+ goto xit;
+ }
+ }
+ while (p < rlimit) {
+ int c = *++p;
+
+ if (c == pattern[match]) {
+ if (++match == ss->eod.size) {
+ switch (ss->count) {
+ case 0:
+ status = EOFC;
+ goto xit;
+ case 1:
+ ss->count = -1;
+ break;
+ default:
+ ss->count--;
+ }
+ ss->copy_ptr = 0;
+ ss->copy_count = match;
+ match = 0;
+ goto cp;
+ }
+ continue;
+ }
+ /*
+ * No match here, back up to find the longest one.
+ * This may be quadratic in string_size, but
+ * we don't expect this to be a real problem.
+ */
+ if (match > 0) {
+ int end = match;
+
+ while (match > 0) {
+ match--;
+ if (!memcmp(pattern,
+ pattern + end - match,
+ match)
+ )
+ break;
+ }
+ /*
+ * Copy the unmatched initial portion of
+ * the EOD string to the output.
+ */
+ p--;
+ ss->copy_ptr = 0;
+ ss->copy_count = end - match;
+ goto cp;
+ }
+ if (q == wlimit) {
+ p--;
+ status = 1;
+ break;
+ }
+ *++q = c;
+ }
+xit: pr->ptr = p;
+ pw->ptr = q;
+ ss->match = match;
+ }
+ return status;
+}
+
+/* Stream template */
+const stream_template s_SFD_template = {
+ &st_SFD_state, s_SFD_init, s_SFD_process, 1, 1
+};
diff --git a/pstoraster/sfilter2.c b/pstoraster/sfilter2.c
new file mode 100644
index 000000000..ad9728202
--- /dev/null
+++ b/pstoraster/sfilter2.c
@@ -0,0 +1,339 @@
+/* Copyright (C) 1991, 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$ */
+/* Simple Level 2 filters */
+#include "stdio_.h" /* includes std.h */
+#include "memory_.h"
+#include "strimpl.h"
+#include "sa85x.h"
+#include "sbtx.h"
+#include "scanchar.h"
+
+/* ------ ASCII85Encode ------ */
+
+/* Process a buffer */
+#define LINE_LIMIT 65
+private int
+s_A85E_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last)
+{
+ register const byte *p = pr->ptr;
+ register byte *q = pw->ptr;
+ byte *qn = q + LINE_LIMIT;
+ const byte *rlimit = pr->limit;
+ byte *wlimit = pw->limit;
+ int status = 0;
+ int count;
+
+ for (; (count = rlimit - p) >= 4; p += 4) {
+ ulong word =
+ ((ulong) (((uint) p[1] << 8) + p[2]) << 16) +
+ (((uint) p[3] << 8) + p[4]);
+
+ if (word == 0) {
+ if (wlimit - q < 2) {
+ status = 1;
+ break;
+ }
+ *++q = 'z';
+ } else {
+ ulong v4 = word / 85; /* max 85^4 */
+ ulong v3 = v4 / 85; /* max 85^3 */
+ uint v2 = v3 / 85; /* max 85^2 */
+ uint v1 = v2 / 85; /* max 85 */
+
+put: if (wlimit - q < 6) {
+ status = 1;
+ break;
+ }
+ q[1] = (byte) v1 + '!';
+ q[2] = (byte) (v2 - v1 * 85) + '!';
+ q[3] = (byte) ((uint) v3 - v2 * 85) + '!';
+ q[4] = (byte) ((uint) v4 - (uint) v3 * 85) + '!';
+ q[5] = (byte) ((uint) word - (uint) v4 * 85) + '!';
+ /*
+ * Two consecutive '%' characters at the beginning
+ * of the line will confuse some document managers:
+ * insert (an) EOL(s) if necessary to prevent this.
+ */
+ if (q[1] == '%') {
+ if (q == pw->ptr) {
+ /*
+ * The very first character written is a %.
+ * Add an EOL before it in case the last
+ * character of the previous batch was a %.
+ */
+ *++q = '\n';
+ qn = q + LINE_LIMIT;
+ goto put;
+ }
+ if (q[2] == '%' && *q == '\n') {
+ /*
+ * We may have to insert more than one EOL if
+ * there are more than two %s in a row.
+ */
+ int extra =
+ (q[3] != '%' ? 1 : q[4] != '%' ? 2 :
+ q[5] != '%' ? 3 : 4);
+
+ if (wlimit - q < 6 + extra) {
+ status = 1;
+ break;
+ }
+ switch (extra) {
+ case 4:
+ q[9] = '%', q[8] = '\n';
+ goto e3;
+ case 3:
+ q[8] = q[5];
+ e3:q[7] = '%', q[6] = '\n';
+ goto e2;
+ case 2:
+ q[7] = q[5], q[6] = q[4];
+ e2:q[5] = '%', q[4] = '\n';
+ goto e1;
+ case 1:
+ q[6] = q[5], q[5] = q[4], q[4] = q[3];
+ e1:q[3] = '%', q[2] = '\n';
+ }
+ q += extra;
+ qn = q + (5 + LINE_LIMIT);
+ }
+ }
+ q += 5;
+ }
+ if (q >= qn) {
+ *++q = '\n';
+ qn = q + LINE_LIMIT;
+ }
+ }
+ /* Check for final partial word. */
+ if (last && status == 0 && count < 4) {
+ if (wlimit - q < (count == 0 ? 2 : count + 3))
+ status = 1;
+ else {
+ ulong word = 0;
+ ulong divisor = 85L * 85 * 85 * 85;
+
+ switch (count) {
+ case 3:
+ word += (uint) p[3] << 8;
+ case 2:
+ word += (ulong) p[2] << 16;
+ case 1:
+ word += (ulong) p[1] << 24;
+ p += count;
+ while (count-- >= 0) {
+ ulong v = word / divisor; /* actually only a byte */
+
+ *++q = (byte) v + '!';
+ word -= v * divisor;
+ divisor /= 85;
+ }
+ /*case 0: */
+ }
+ *++q = '~';
+ *++q = '>';
+ }
+ }
+ pr->ptr = p;
+ pw->ptr = q;
+ return status;
+}
+#undef LINE_LIMIT
+
+/* Stream template */
+const stream_template s_A85E_template = {
+ &st_stream_state, NULL, s_A85E_process, 4, 6
+};
+
+/* ------ ASCII85Decode ------ */
+
+private_st_A85D_state();
+
+/* Initialize the state */
+private int
+s_A85D_init(stream_state * st)
+{
+ stream_A85D_state *const ss = (stream_A85D_state *) st;
+
+ return s_A85D_init_inline(ss);
+}
+
+/* Process a buffer */
+private int a85d_finish(P3(int, ulong, stream_cursor_write *));
+private int
+s_A85D_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last)
+{
+ stream_A85D_state *const ss = (stream_A85D_state *) st;
+ register const byte *p = pr->ptr;
+ register byte *q = pw->ptr;
+ const byte *rlimit = pr->limit;
+ byte *wlimit = pw->limit;
+ int ccount = ss->odd;
+ ulong word = ss->word;
+ int status = 0;
+
+ while (p < rlimit) {
+ int ch = *++p;
+ uint ccode = ch - '!';
+
+ if (ccode < 85) { /* catches ch < '!' as well */
+ if (wlimit - q < 4) {
+ p--;
+ status = 1;
+ break;
+ }
+ word = word * 85 + ccode;
+ if (++ccount == 5) {
+ q[1] = (byte) (word >> 24);
+ q[2] = (byte) (word >> 16);
+ q[3] = (byte) ((uint) word >> 8);
+ q[4] = (byte) word;
+ q += 4;
+ word = 0;
+ ccount = 0;
+ }
+ } else if (ch == 'z' && ccount == 0) {
+ if (wlimit - q < 4) {
+ p--;
+ status = 1;
+ break;
+ }
+ q[1] = q[2] = q[3] = q[4] = 0,
+ q += 4;
+ } else if (scan_char_decoder[ch] == ctype_space)
+ DO_NOTHING;
+ else if (ch == '~') {
+ /* Handle odd bytes. */
+ if (p == rlimit) {
+ if (last)
+ status = ERRC;
+ else
+ p--;
+ break;
+ }
+ if ((int)(wlimit - q) < ccount - 1) {
+ status = 1;
+ p--;
+ break;
+ }
+ if (*++p != '>') {
+ status = ERRC;
+ break;
+ }
+ pw->ptr = q;
+ status = a85d_finish(ccount, word, pw);
+ q = pw->ptr;
+ break;
+ } else { /* syntax error or exception */
+ status = ERRC;
+ break;
+ }
+ }
+ pw->ptr = q;
+ if (status == 0 && last) {
+ if ((int)(wlimit - q) < ccount - 1)
+ status = 1;
+ else
+ status = a85d_finish(ccount, word, pw);
+ }
+ pr->ptr = p;
+ ss->odd = ccount;
+ ss->word = word;
+ return status;
+}
+/* Handle the end of input data. */
+private int
+a85d_finish(int ccount, ulong word, stream_cursor_write * pw)
+{
+ /* Assume there is enough room in the output buffer! */
+ byte *q = pw->ptr;
+ int status = EOFC;
+
+ switch (ccount) {
+ case 0:
+ break;
+ case 1: /* syntax error */
+ status = ERRC;
+ break;
+ case 2: /* 1 odd byte */
+ word = word * (85L * 85 * 85) + 0xffffffL;
+ goto o1;
+ case 3: /* 2 odd bytes */
+ word = word * (85L * 85) + 0xffffL;
+ goto o2;
+ case 4: /* 3 odd bytes */
+ word = word * 85 + 0xffL;
+ q[3] = (byte) (word >> 8);
+o2: q[2] = (byte) (word >> 16);
+o1: q[1] = (byte) (word >> 24);
+ q += ccount - 1;
+ pw->ptr = q;
+ }
+ return status;
+}
+
+/* Stream template */
+const stream_template s_A85D_template = {
+ &st_A85D_state, s_A85D_init, s_A85D_process, 2, 4
+};
+
+/* ------ ByteTranslateEncode/Decode ------ */
+
+private_st_BT_state();
+
+/* Process a buffer. Note that the same code serves for both streams. */
+private int
+s_BT_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last)
+{
+ stream_BT_state *const ss = (stream_BT_state *) st;
+ const byte *p = pr->ptr;
+ byte *q = pw->ptr;
+ uint rcount = pr->limit - p;
+ uint wcount = pw->limit - q;
+ uint count;
+ int status;
+
+ if (rcount <= wcount)
+ count = rcount, status = 0;
+ else
+ count = wcount, status = 1;
+ while (count--)
+ *++q = ss->table[*++p];
+ pr->ptr = p;
+ pw->ptr = q;
+ return status;
+}
+
+/* Stream template */
+const stream_template s_BTE_template = {
+ &st_BT_state, NULL, s_BT_process, 1, 1
+};
+const stream_template s_BTD_template = {
+ &st_BT_state, NULL, s_BT_process, 1, 1
+};
diff --git a/pstoraster/sfxstdio.c b/pstoraster/sfxstdio.c
new file mode 100644
index 000000000..455d80c1d
--- /dev/null
+++ b/pstoraster/sfxstdio.c
@@ -0,0 +1,269 @@
+/* Copyright (C) 1993, 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$ */
+/* File stream implementation using stdio */
+#include "stdio_.h" /* includes std.h */
+#include "memory_.h"
+#include "gdebug.h"
+#include "gpcheck.h"
+#include "stream.h"
+#include "strimpl.h"
+
+/* Forward references for file stream procedures */
+private int
+ s_file_available(P2(stream *, long *)),
+ s_file_read_seek(P2(stream *, long)),
+ s_file_read_close(P1(stream *)),
+ s_file_read_process(P4(stream_state *, stream_cursor_read *,
+ stream_cursor_write *, bool));
+private int
+ s_file_write_seek(P2(stream *, long)),
+ s_file_write_flush(P1(stream *)),
+ s_file_write_close(P1(stream *)),
+ s_file_write_process(P4(stream_state *, stream_cursor_read *,
+ stream_cursor_write *, bool));
+private int
+ s_file_switch(P2(stream *, bool));
+
+/* ------ File streams ------ */
+
+/* Initialize a stream for reading an OS file. */
+void
+sread_file(register stream * s, FILE * file, byte * buf, uint len)
+{
+ static const stream_procs p = {
+ s_file_available, s_file_read_seek, s_std_read_reset,
+ s_std_read_flush, s_file_read_close, s_file_read_process,
+ s_file_switch
+ };
+ /*
+ * There is no really portable way to test seekability, but this should
+ * work on most systems. Note that if our probe sets the ferror bit for
+ * the stream, we have to clear it again to avoid trouble later.
+ */
+ int had_error = ferror(file);
+ long curpos = ftell(file);
+ bool seekable = (curpos != -1L && fseek(file, curpos, SEEK_SET) == 0);
+
+ if (!had_error)
+ clearerr(file);
+ s_std_init(s, buf, len, &p,
+ (seekable ? s_mode_read + s_mode_seek : s_mode_read));
+ if_debug1('s', "[s]read file=0x%lx\n", (ulong) file);
+ s->file = file;
+ s->file_modes = s->modes;
+}
+/* Procedures for reading from a file */
+private int
+s_file_available(register stream * s, long *pl)
+{
+ *pl = sbufavailable(s);
+ if (sseekable(s)) {
+ long pos, end;
+
+ pos = ftell(s->file);
+ if (fseek(s->file, 0L, SEEK_END))
+ return ERRC;
+ end = ftell(s->file);
+ if (fseek(s->file, pos, SEEK_SET))
+ return ERRC;
+ *pl += end - pos;
+ if (*pl == 0)
+ *pl = -1; /* EOF */
+ } else {
+ if (*pl == 0 && feof(s->file))
+ *pl = -1; /* EOF */
+ }
+ return 0;
+}
+private int
+s_file_read_seek(register stream * s, long pos)
+{
+ uint end = s->srlimit - s->cbuf + 1;
+ long offset = pos - s->position;
+
+ if (offset >= 0 && offset <= end) { /* Staying within the same buffer */
+ s->srptr = s->cbuf + offset - 1;
+ return 0;
+ }
+ if (fseek(s->file, pos, SEEK_SET) != 0)
+ return ERRC;
+ s->srptr = s->srlimit = s->cbuf - 1;
+ s->end_status = 0;
+ s->position = pos;
+ return 0;
+}
+private int
+s_file_read_close(stream * s)
+{
+ FILE *file = s->file;
+
+ if (file != 0) {
+ s->file = 0;
+ return fclose(file);
+ }
+ return 0;
+}
+
+/* Initialize a stream for writing an OS file. */
+void
+swrite_file(register stream * s, FILE * file, byte * buf, uint len)
+{
+ static const stream_procs p = {
+ s_std_noavailable, s_file_write_seek, s_std_write_reset,
+ s_file_write_flush, s_file_write_close, s_file_write_process,
+ s_file_switch
+ };
+
+ s_std_init(s, buf, len, &p,
+ (file == stdout ? s_mode_write : s_mode_write + s_mode_seek));
+ if_debug1('s', "[s]write file=0x%lx\n", (ulong) file);
+ s->file = file;
+ s->file_modes = s->modes;
+}
+/* Initialize for appending to an OS file. */
+void
+sappend_file(register stream * s, FILE * file, byte * buf, uint len)
+{
+ swrite_file(s, file, buf, len);
+ s->modes = s_mode_write + s_mode_append; /* no seek */
+ s->file_modes = s->modes;
+ fseek(file, 0L, SEEK_END);
+ s->position = ftell(file);
+}
+/* Procedures for writing on a file */
+private int
+s_file_write_seek(stream * s, long pos)
+{
+ /* We must flush the buffer to reposition. */
+ int code = sflush(s);
+
+ if (code < 0)
+ return code;
+ if (fseek(s->file, pos, SEEK_SET) != 0)
+ return ERRC;
+ s->position = pos;
+ return 0;
+}
+private int
+s_file_write_flush(register stream * s)
+{
+ int result = s_process_write_buf(s, false);
+
+ fflush(s->file);
+ return result;
+}
+private int
+s_file_write_close(register stream * s)
+{
+ s_process_write_buf(s, true);
+ return s_file_read_close(s);
+}
+
+/*
+ * Process a buffer for a file reading stream.
+ * This is the first stream in the pipeline, so pr is irrelevant.
+ */
+private int
+s_file_read_process(stream_state * st, stream_cursor_read * ignore_pr,
+ stream_cursor_write * pw, bool last)
+{
+ FILE *file = ((stream *) st)->file;
+ int count = fread(pw->ptr + 1, 1, (uint) (pw->limit - pw->ptr), file);
+
+ if (count < 0)
+ count = 0;
+ pw->ptr += count;
+ process_interrupts();
+ return (ferror(file) ? ERRC : feof(file) ? EOFC : 1);
+}
+
+/*
+ * Process a buffer for a file writing stream.
+ * This is the last stream in the pipeline, so pw is irrelevant.
+ */
+private int
+s_file_write_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * ignore_pw, bool last)
+{
+ uint count = pr->limit - pr->ptr;
+
+ /*
+ * The DEC C library on AXP architectures gives an error on
+ * fwrite if the count is zero!
+ */
+ if (count != 0) {
+ FILE *file = ((stream *) st)->file;
+ int written = fwrite(pr->ptr + 1, 1, count, file);
+
+ if (written < 0)
+ written = 0;
+ pr->ptr += written;
+ process_interrupts();
+ return (ferror(file) ? ERRC : 0);
+ } else {
+ process_interrupts();
+ return 0;
+ }
+}
+
+/* Switch a file stream to reading or writing. */
+private int
+s_file_switch(stream * s, bool writing)
+{
+ uint modes = s->file_modes;
+ FILE *file = s->file;
+ long pos;
+
+ if (writing) {
+ if (!(s->file_modes & s_mode_write))
+ return ERRC;
+ pos = stell(s);
+ if_debug2('s', "[s]switch 0x%lx to write at %ld\n",
+ (ulong) s, pos);
+ fseek(file, pos, SEEK_SET);
+ if (modes & s_mode_append) {
+ sappend_file(s, file, s->cbuf, s->cbsize); /* sets position */
+ } else {
+ swrite_file(s, file, s->cbuf, s->cbsize);
+ s->position = pos;
+ }
+ s->modes = modes;
+ } else {
+ if (!(s->file_modes & s_mode_read))
+ return ERRC;
+ pos = stell(s);
+ if_debug2('s', "[s]switch 0x%lx to read at %ld\n",
+ (ulong) s, pos);
+ if (sflush(s) < 0)
+ return ERRC;
+ fseek(file, 0L, SEEK_CUR); /* pacify C library */
+ sread_file(s, file, s->cbuf, s->cbsize);
+ s->modes |= modes & s_mode_append; /* don't lose append info */
+ s->position = pos;
+ }
+ s->file_modes = modes;
+ return 0;
+}
diff --git a/pstoraster/shc.c b/pstoraster/shc.c
new file mode 100644
index 000000000..6c745b0f6
--- /dev/null
+++ b/pstoraster/shc.c
@@ -0,0 +1,74 @@
+/* Copyright (C) 1992, 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$ */
+/* Support code for shc.h */
+#include "std.h"
+#include "scommon.h"
+#include "shc.h"
+
+/* ------ Encoding ------ */
+
+/* Empty the 1-word buffer onto the output stream. */
+/* q has already been incremented. */
+void
+hc_put_code_proc(bool reverse_bits, byte * q, uint cw)
+{
+#define cb(n) ((byte)(cw >> (n * 8)))
+ if (reverse_bits) {
+#if hc_bits_size > 16
+ q[-3] = byte_reverse_bits[cb(3)];
+ q[-2] = byte_reverse_bits[cb(2)];
+#endif
+ q[-1] = byte_reverse_bits[cb(1)];
+ q[0] = byte_reverse_bits[cb(0)];
+ } else {
+#if hc_bits_size > 16
+ q[-3] = cb(3);
+ q[-2] = cb(2);
+#endif
+ q[-1] = cb(1);
+ q[0] = cb(0);
+ }
+#undef cb
+}
+
+/* Put out any final bytes. */
+/* Note that this does a store_state, but not a load_state. */
+byte *
+hc_put_last_bits_proc(stream_hc_state * ss, byte * q, uint bits, int bits_left)
+{
+ while (bits_left < hc_bits_size) {
+ byte c = (byte) (bits >> (hc_bits_size - 8));
+
+ if (ss->FirstBitLowOrder)
+ c = byte_reverse_bits[c];
+ *++q = c;
+ bits <<= 8;
+ bits_left += 8;
+ }
+ ss->bits = bits;
+ ss->bits_left = bits_left;
+ return q;
+}
diff --git a/pstoraster/shc.h b/pstoraster/shc.h
new file mode 100644
index 000000000..81aa300b8
--- /dev/null
+++ b/pstoraster/shc.h
@@ -0,0 +1,254 @@
+/* Copyright (C) 1992, 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$ */
+/* Common definitions for filters using Huffman coding */
+
+#ifndef shc_INCLUDED
+# define shc_INCLUDED
+
+#include "gsbittab.h"
+#include "scommon.h"
+
+/*
+ * These definitions are valid for code lengths up to 16 bits
+ * and non-negative decoded values up to 15 bits.
+ *
+ * We define 3 different representations of the code: encoding tables,
+ * decoding tables, and a definition table which can be generated easily
+ * from frequency information and which in turn can easily generate
+ * the encoding and decoding tables.
+ *
+ * The definition table has two parts: a list of the number of i-bit
+ * codes for each i >= 1, and the decoded values corresponding to
+ * the code values in increasing lexicographic order (which will also
+ * normally be decreasing code frequency). Calling these two lists
+ * L[1..M] and V[0..N-1] respectively, we have the following invariants:
+ * - 1 <= M <= max_hc_length, N >= 2.
+ * - L[0] = 0.
+ * - for i=1..M, L[i] >= 0.
+ * - sum(i=1..M: L[i]) = N.
+ * - sum(i=1..M: L[i] * 2^-i) = 1.
+ * - V[0..N-1] are a permutation of the integers 0..N-1.
+ */
+#define max_hc_length 16
+typedef struct hc_definition_s {
+ ushort *counts; /* [0..M] */
+ uint num_counts; /* M */
+ ushort *values; /* [0..N-1] */
+ uint num_values; /* N */
+} hc_definition;
+
+/* ------ Common state ------ */
+
+/*
+ * Define the common stream state for Huffman-coded filters.
+ * Invariants when writing:
+ * 0 <= bits_left <= hc_bits_size;
+ * Only the leftmost (hc_bits_size - bits_left) bits of bits
+ * contain valid data.
+ */
+#define stream_hc_state_common\
+ stream_state_common;\
+ /* The client sets the following before initialization. */\
+ bool FirstBitLowOrder;\
+ /* The following are updated dynamically. */\
+ uint bits; /* most recent bits of input or */\
+ /* current bits of output */\
+ int bits_left /* # of valid low bits (input) or */\
+ /* unused low bits (output) in above, */\
+ /* 0 <= bits_left <= 7 */
+typedef struct stream_hc_state_s {
+ stream_hc_state_common;
+} stream_hc_state;
+
+#define hc_bits_size (arch_sizeof_int * 8)
+#define s_hce_init_inline(ss)\
+ ((ss)->bits = 0, (ss)->bits_left = hc_bits_size)
+#define s_hcd_init_inline(ss)\
+ ((ss)->bits = 0, (ss)->bits_left = 0)
+
+/* ------ Encoding tables ------ */
+
+/* Define the structure for the encoding tables. */
+typedef struct hce_code_s {
+ ushort code;
+ ushort code_length;
+} hce_code;
+
+#define hce_entry(c, len) { c, len }
+
+typedef struct hce_table_s {
+ uint count;
+ hce_code *codes;
+} hce_table;
+
+#define hce_bits_available(n)\
+ (ss->bits_left >= (n) || wlimit - q > ((n) - ss->bits_left - 1) >> 3)
+
+/* ------ Encoding utilities ------ */
+
+/*
+ * Put a code on the output. The client is responsible for ensuring
+ * that q does not exceed pw->limit.
+ */
+
+#ifdef DEBUG
+# define hc_print_value(code, clen)\
+ (gs_debug_c('W') ?\
+ (dlprintf2("[W]0x%x,%d\n", code, clen), 0) : 0)
+# define hc_print_value_then(code, clen) hc_print_value(code, clen),
+#else
+# define hc_print_value(code, clen) 0
+# define hc_print_value_then(code, clen) /* */
+#endif
+#define hc_print_code(rp) hc_print_value((rp)->code, (rp)->code_length)
+
+/* Declare variables that hold the encoder state. */
+#define hce_declare_state\
+ register uint bits;\
+ register int bits_left
+
+/* Load the state from the stream. */
+/* Free variables: ss, bits, bits_left. */
+#define hce_load_state()\
+ bits = ss->bits, bits_left = ss->bits_left
+
+/* Store the state back in the stream. */
+/* Free variables: ss, bits, bits_left. */
+#define hce_store_state()\
+ ss->bits = bits, ss->bits_left = bits_left
+
+/* Put a code on the stream. */
+void hc_put_code_proc(P3(bool, byte *, uint));
+
+#define hc_put_value(ss, q, code, clen)\
+ (hc_print_value_then(code, clen)\
+ ((bits_left -= (clen)) >= 0 ?\
+ (bits += (code) << bits_left) :\
+ (hc_put_code_proc((ss)->FirstBitLowOrder,\
+ q += hc_bits_size >> 3,\
+ (bits + ((code) >> -bits_left))),\
+ bits = (code) << (bits_left += hc_bits_size))))
+#define hc_put_code(ss, q, cp)\
+ hc_put_value(ss, q, (cp)->code, (cp)->code_length)
+
+/*
+ * Force out the final bits to the output.
+ * Note that this does a store_state, but not a load_state.
+ */
+byte *hc_put_last_bits_proc(P4(stream_hc_state *, byte *, uint, int));
+
+#define hc_put_last_bits(ss, q)\
+ hc_put_last_bits_proc(ss, q, bits, bits_left)
+
+/* ------ Decoding tables ------ */
+
+/*
+ * Define the structure for the decoding tables.
+ * First-level nodes are either leaves, which have
+ * value = decoded value
+ * code_length <= initial_bits
+ * or non-leaves, which have
+ * value = the index of a sub-table
+ * code_length = initial_bits + the number of additional dispatch bits
+ * Second-level nodes are always leaves, with
+ * code_length = the actual number of bits in the code - initial_bits.
+ */
+
+typedef struct hcd_code_s {
+ short value;
+ ushort code_length;
+} hcd_code;
+
+typedef struct hcd_table_s {
+ uint count;
+ uint initial_bits;
+ hcd_code *codes;
+} hcd_table;
+
+/* Declare variables that hold the decoder state. */
+#define hcd_declare_state\
+ register const byte *p;\
+ const byte *rlimit;\
+ uint bits;\
+ int bits_left
+
+/* Load the state from the stream. */
+/* Free variables: pr, ss, p, rlimit, bits, bits_left. */
+#define hcd_load_state()\
+ p = pr->ptr,\
+ rlimit = pr->limit,\
+ bits = ss->bits,\
+ bits_left = ss->bits_left
+
+/* Store the state back in the stream. */
+/* Put back any complete bytes into the input buffer. */
+/* Free variables: pr, ss, p, bits, bits_left. */
+#define hcd_store_state()\
+ pr->ptr = p -= (bits_left >> 3),\
+ ss->bits = bits >>= (bits_left & ~7),\
+ ss->bits_left = bits_left &= 7
+
+/* Macros to get blocks of bits from the input stream. */
+/* Invariants: 0 <= bits_left <= bits_size; */
+/* bits [bits_left-1..0] contain valid data. */
+
+#define hcd_bits_available(n)\
+ (bits_left >= (n) || rlimit - p > ((n) - bits_left - 1) >> 3)
+/* For hcd_ensure_bits, n must not be greater than 8. */
+#define hcd_ensure_bits(n, outl)\
+ if ( bits_left < n ) hcd_more_bits(outl)
+
+/* Load more bits into the buffer. */
+#define hcd_more_bits_1(outl)\
+ { int c;\
+ if ( p < rlimit ) c = *++p;\
+ else goto outl;\
+ if ( ss->FirstBitLowOrder ) c = byte_reverse_bits[c];\
+ bits = (bits << 8) + c, bits_left += 8;\
+ }
+#if hc_bits_size == 16
+# define hcd_more_bits(outl) hcd_more_bits_1(outl)
+#else /* hc_bits_size >= 32 */
+# define hcd_more_bits(outl)\
+ { if ( rlimit - p < 3 ) hcd_more_bits_1(outl)\
+ else\
+ { if ( ss->FirstBitLowOrder )\
+ bits = (bits << 24) + ((uint)byte_reverse_bits[p[1]] << 16) + ((uint)byte_reverse_bits[p[2]] << 8) + byte_reverse_bits[p[3]];\
+ else\
+ bits = (bits << 24) + ((uint)p[1] << 16) + ((uint)p[2] << 8) + p[3];\
+ bits_left += 24, p += 3;\
+ }\
+ }
+#endif
+
+#define hcd_peek_bits(n) ((bits >> (bits_left - (n))) & ((1 << (n)) - 1))
+
+#define hcd_peek_var_bits(n)\
+ ((bits >> (bits_left - (n))) & byte_right_mask[n])
+
+#define hcd_skip_bits(n) (bits_left -= (n))
+
+#endif /* shc_INCLUDED */
diff --git a/pstoraster/shcgen.c b/pstoraster/shcgen.c
new file mode 100644
index 000000000..cdcd957c1
--- /dev/null
+++ b/pstoraster/shcgen.c
@@ -0,0 +1,491 @@
+/* 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$ */
+/* Generate (bounded) Huffman code definitions from frequencies, */
+/* and tables from definitions. */
+#include "memory_.h"
+#include "stdio_.h"
+#include <stdlib.h> /* for qsort */
+#include "gdebug.h"
+#include "gserror.h"
+#include "gserrors.h"
+#include "gsmemory.h"
+#include "scommon.h"
+#include "shc.h"
+#include "shcgen.h"
+
+/* ------ Frequency -> definition procedure ------ */
+
+/* Define a node for the Huffman code tree. */
+typedef struct count_node_s count_node;
+struct count_node_s {
+ long freq; /* frequency of value */
+ uint value; /* data value being encoded */
+ uint code_length; /* length of Huffman code */
+ count_node *next; /* next node in freq-sorted list */
+ count_node *left; /* left child in tree (smaller code_length) */
+ count_node *right; /* right child in tree (greater code_length) */
+};
+
+#ifdef DEBUG
+# define debug_print_nodes(nodes, n, tag, lengths)\
+ if ( gs_debug_c('W') ) print_nodes_proc(nodes, n, tag, lengths);
+private void
+print_nodes_proc(const count_node * nodes, int n, const char *tag, int lengths)
+{
+ int i;
+
+ dlprintf1("[w]---------------- %s ----------------\n", tag);
+ for (i = 0; i < n; ++i)
+ dlprintf7("[w]node %d: f=%ld v=%d len=%d N=%d L=%d R=%d\n",
+ i, nodes[i].freq, nodes[i].value, nodes[i].code_length,
+ (nodes[i].next == 0 ? -1 : (int)(nodes[i].next - nodes)),
+ (nodes[i].left == 0 ? -1 : (int)(nodes[i].left - nodes)),
+ (nodes[i].right == 0 ? -1 : (int)(nodes[i].right - nodes)));
+ for (i = lengths; i > 0;) {
+ int j = i;
+ int len = nodes[--j].code_length;
+
+ while (j > 0 && nodes[j - 1].code_length == len)
+ --j;
+ dlprintf2("[w]%d codes of length %d\n", i - j, len);
+ i = j;
+ }
+}
+#else
+# define debug_print_nodes(nodes, n, tag, lengths) DO_NOTHING
+#endif
+
+/* Node comparison procedures for sorting. */
+#define pn1 ((const count_node *)p1)
+#define pn2 ((const count_node *)p2)
+/* Sort by decreasing frequency. */
+private int
+compare_freqs(const void *p1, const void *p2)
+{
+ long diff = pn2->freq - pn1->freq;
+
+ return (diff < 0 ? -1 : diff > 0 ? 1 : 0);
+}
+/* Sort by increasing code length, and secondarily by decreasing frequency. */
+private int
+compare_code_lengths(const void *p1, const void *p2)
+{
+ int diff = pn1->code_length - pn2->code_length;
+
+ return (diff < 0 ? -1 : diff > 0 ? 1 : compare_freqs(p1, p2));
+}
+/* Sort by increasing code value. */
+private int
+compare_values(const void *p1, const void *p2)
+{
+ return (pn1->value < pn2->value ? -1 :
+ pn1->value > pn2->value ? 1 : 0);
+}
+#undef pn1
+#undef pn2
+
+/* Adjust code lengths so that none of them exceeds max_length. */
+/* We break this out just to help organize the code; it's only called */
+/* from one place in hc_compute. */
+private void
+hc_limit_code_lengths(count_node * nodes, uint num_values, int max_length)
+{
+ int needed; /* # of max_length codes we need to free up */
+ count_node *longest = nodes + num_values;
+
+ { /* Compute the number of additional max_length codes */
+ /* we need to make available. */
+ int length = longest[-1].code_length;
+ int next_length;
+ int avail = 0;
+
+ while ((next_length = longest[-1].code_length) > max_length) {
+ avail >>= length - next_length;
+ length = next_length;
+ (--longest)->code_length = max_length;
+ ++avail;
+ }
+ needed = (nodes + num_values - longest) -
+ (avail >>= (length - max_length));
+ if_debug2('W', "[w]avail=%d, needed=%d\n",
+ avail, needed);
+ }
+ /* Skip over all max_length codes. */
+ while (longest[-1].code_length == max_length)
+ --longest;
+
+ /*
+ * To make available a code of length N, suppose that the next
+ * shortest used code is of length M.
+ * We take the lowest-frequency code of length M and change it
+ * to M+1; we then have to compensate by reducing the length of
+ * some of the highest-frequency codes of length N, as follows:
+ * M new lengths for codes of length N
+ * --- -----------
+ * N-1 (none)
+ * N-2 N-1
+ * <N-2 M+2, M+2, N-1
+ * In the present situation, N = max_length.
+ */
+ for (; needed > 0; --needed) { /* longest points to the first code of length max_length. */
+ /* Since codes are sorted by increasing code length, */
+ /* longest-1 is the desired code of length M. */
+ int M1 = ++(longest[-1].code_length);
+
+ switch (max_length - M1) {
+ case 0: /* M == N-1 */
+ --longest;
+ break;
+ case 1: /* M == N-2 */
+ longest++->code_length = M1;
+ break;
+ default:
+ longest->code_length = M1 + 1;
+ longest[1].code_length = M1 + 1;
+ longest[2].code_length--;
+ longest += 3;
+ }
+ }
+}
+
+/* Compute an optimal Huffman code from an input data set. */
+/* The client must have set all the elements of *def. */
+int
+hc_compute(hc_definition * def, const long *freqs, gs_memory_t * mem)
+{
+ uint num_values = def->num_values;
+ count_node *nodes =
+ (count_node *) gs_alloc_byte_array(mem, num_values * 2 - 1,
+ sizeof(count_node), "hc_compute");
+ int i;
+ count_node *lowest;
+ count_node *comb;
+
+ if (nodes == 0)
+ return_error(gs_error_VMerror);
+
+ /* Create leaf nodes for the input data. */
+ for (i = 0; i < num_values; ++i)
+ nodes[i].freq = freqs[i], nodes[i].value = i;
+
+ /* Create a list sorted by increasing frequency. */
+ /* Also initialize the tree structure. */
+ qsort(nodes, num_values, sizeof(count_node), compare_freqs);
+ for (i = 0; i < num_values; ++i)
+ nodes[i].next = &nodes[i - 1],
+ nodes[i].code_length = 0,
+ nodes[i].left = nodes[i].right = 0;
+ nodes[0].next = 0;
+ debug_print_nodes(nodes, num_values, "after sort", 0);
+
+ /* Construct the Huffman code tree. */
+ for (lowest = &nodes[num_values - 1], comb = &nodes[num_values];;
+ ++comb
+ ) {
+ count_node *pn1 = lowest;
+ count_node *pn2 = pn1->next;
+ long freq = pn1->freq + pn2->freq;
+
+ /* Create a parent for the two lowest-frequency nodes. */
+ lowest = pn2->next;
+ comb->freq = freq;
+ if (pn1->code_length <= pn2->code_length)
+ comb->left = pn1, comb->right = pn2,
+ comb->code_length = pn2->code_length + 1;
+ else
+ comb->left = pn2, comb->right = pn1,
+ comb->code_length = pn1->code_length + 1;
+ if (lowest == 0) /* no nodes left to combine */
+ break;
+ /* Insert comb in the sorted list. */
+ if (freq < lowest->freq)
+ comb->next = lowest, lowest = comb;
+ else {
+ count_node *here = lowest;
+
+ while (here->next != 0 && freq >= here->next->freq)
+ here = here->next;
+ comb->next = here->next;
+ here->next = comb;
+ }
+ }
+
+ /* comb (i.e., &nodes[num_values * 2 - 2] is the root of the tree. */
+ /* Note that the left and right children of an interior node */
+ /* were constructed before, and therefore have lower indices */
+ /* in the nodes array than, the parent node. Thus we can assign */
+ /* the code lengths (node depths) in a single descending-order */
+ /* sweep. */
+ comb++->code_length = 0;
+ while (comb > nodes + num_values) {
+ --comb;
+ comb->left->code_length = comb->right->code_length =
+ comb->code_length + 1;
+ }
+ debug_print_nodes(nodes, num_values * 2 - 1, "after combine", 0);
+
+ /* Sort the leaves again by code length. */
+ qsort(nodes, num_values, sizeof(count_node), compare_code_lengths);
+ debug_print_nodes(nodes, num_values, "after re-sort", num_values);
+
+ /* Limit the code length to def->num_counts. */
+ hc_limit_code_lengths(nodes, num_values, def->num_counts);
+ debug_print_nodes(nodes, num_values, "after limit", num_values);
+
+ /* Sort within each code length by increasing code value. */
+ /* This doesn't affect data compression, but it makes */
+ /* the code definition itself compress better using our */
+ /* incremental encoding. */
+ for (i = num_values; i > 0;) {
+ int j = i;
+ int len = nodes[--j].code_length;
+
+ while (j > 0 && nodes[j - 1].code_length == len)
+ --j;
+ qsort(&nodes[j], i - j, sizeof(count_node), compare_values);
+ i = j;
+ }
+
+ /* Extract the definition from the nodes. */
+ memset(def->counts, 0, sizeof(*def->counts) * (def->num_counts + 1));
+ for (i = 0; i < num_values; ++i) {
+ def->values[i] = nodes[i].value;
+ def->counts[nodes[i].code_length]++;
+ }
+
+ /* All done, release working storage. */
+ gs_free_object(mem, nodes, "hc_compute");
+ return 0;
+}
+
+/* ------ Byte string <-> definition procedures ------ */
+
+/*
+ * We define a compressed representation for (well-behaved) definitions
+ * as a byte string. A "well-behaved" definition is one where if
+ * code values A and B have the same code length and A < B,
+ * A precedes B in the values table of the definition, and hence
+ * A's encoding lexicographically precedes B's.
+ *
+ * The successive bytes in the compressed string give the code lengths for
+ * runs of decoded values, in the form nnnnllll where nnnn is the number of
+ * consecutive values -1 and llll is the code length -1.
+ */
+
+/* Convert a definition to a byte string. */
+/* The caller must provide the byte string, of length def->num_values. */
+/* Assume (do not check) that the definition is well-behaved. */
+/* Return the actual length of the string. */
+int
+hc_bytes_from_definition(byte * dbytes, const hc_definition * def)
+{
+ int i, j;
+ byte *bp = dbytes;
+ const byte *lp = dbytes;
+ const byte *end = dbytes + def->num_values;
+ const ushort *values = def->values;
+
+ /* Temporarily use the output string as a map from */
+ /* values to code lengths. */
+ for (i = 1; i <= def->num_counts; i++)
+ for (j = 0; j < def->counts[i]; j++)
+ bp[*values++] = i;
+
+ /* Now construct the actual string. */
+ while (lp < end) {
+ const byte *vp;
+ byte len = *lp;
+
+ for (vp = lp + 1; vp < end && vp < lp + 16 && *vp == len;)
+ vp++;
+ *bp++ = ((vp - lp - 1) << 4) + (len - 1);
+ lp = vp;
+ }
+
+ return bp - dbytes;
+}
+
+/* Extract num_counts and num_values from a byte string. */
+void
+hc_sizes_from_bytes(hc_definition * def, const byte * dbytes, int num_bytes)
+{
+ uint num_counts = 0, num_values = 0;
+ int i;
+
+ for (i = 0; i < num_bytes; i++) {
+ int n = (dbytes[i] >> 4) + 1;
+ int l = (dbytes[i] & 15) + 1;
+
+ if (l > num_counts)
+ num_counts = l;
+ num_values += n;
+ }
+ def->num_counts = num_counts;
+ def->num_values = num_values;
+}
+
+/* Convert a byte string back to a definition. */
+/* The caller must initialize *def, including allocating counts and values. */
+void
+hc_definition_from_bytes(hc_definition * def, const byte * dbytes)
+{
+ int v, i;
+ ushort counts[max_hc_length + 1];
+
+ /* Make a first pass to set the counts for each code length. */
+ memset(counts, 0, sizeof(counts[0]) * (def->num_counts + 1));
+ for (i = 0, v = 0; v < def->num_values; i++) {
+ int n = (dbytes[i] >> 4) + 1;
+ int l = (dbytes[i] & 15) + 1;
+
+ counts[l] += n;
+ v += n;
+ }
+
+ /* Now fill in the definition. */
+ memcpy(def->counts, counts, sizeof(counts[0]) * (def->num_counts + 1));
+ for (i = 1, v = 0; i <= def->num_counts; i++) {
+ uint prev = counts[i];
+
+ counts[i] = v;
+ v += prev;
+ }
+ for (i = 0, v = 0; v < def->num_values; i++) {
+ int n = (dbytes[i] >> 4) + 1;
+ int l = (dbytes[i] & 15) + 1;
+ int j;
+
+ for (j = 0; j < n; n++)
+ def->values[counts[l]++] = v++;
+ }
+}
+
+/* ------ Definition -> table procedures ------ */
+
+/* Generate the encoding table from the definition. */
+/* The size of the encode array is def->num_values. */
+void
+hc_make_encoding(hce_code * encode, const hc_definition * def)
+{
+ uint next = 0;
+ const ushort *pvalue = def->values;
+ uint i, k;
+
+ for (i = 1; i <= def->num_counts; i++) {
+ for (k = 0; k < def->counts[i]; k++, pvalue++, next++) {
+ hce_code *pce = encode + *pvalue;
+
+ pce->code = next;
+ pce->code_length = i;
+ }
+ next <<= 1;
+ }
+}
+
+/* We decode in two steps, first indexing into a table with */
+/* a fixed number of bits from the source, and then indexing into */
+/* an auxiliary table if necessary. (See shc.h for details.) */
+
+/* Calculate the size of the decoding table. */
+uint
+hc_sizeof_decoding(const hc_definition * def, int initial_bits)
+{
+ uint size = 1 << initial_bits;
+ uint carry = 0, mask = (uint) ~ 1;
+ uint i;
+
+ for (i = initial_bits + 1; i <= def->num_counts;
+ i++, carry <<= 1, mask <<= 1
+ ) {
+ carry += def->counts[i];
+ size += carry & mask;
+ carry &= ~mask;
+ }
+ return size;
+}
+
+/* Generate the decoding tables. */
+void
+hc_make_decoding(hcd_code * decode, const hc_definition * def,
+ int initial_bits)
+{ /* Make entries for single-dispatch codes. */
+ {
+ hcd_code *pcd = decode;
+ const ushort *pvalue = def->values;
+ uint i, k, d;
+
+ for (i = 0; i <= initial_bits; i++) {
+ for (k = 0; k < def->counts[i]; k++, pvalue++) {
+ for (d = 1 << (initial_bits - i); d > 0;
+ d--, pcd++
+ )
+ pcd->value = *pvalue,
+ pcd->code_length = i;
+ }
+ }
+ }
+ /* Make entries for two-dispatch codes. */
+ /* By working backward, we can do this more easily */
+ /* in a single pass. */
+ {
+ uint dsize = hc_sizeof_decoding(def, initial_bits);
+ hcd_code *pcd = decode + (1 << initial_bits);
+ hcd_code *pcd2 = decode + dsize;
+ const ushort *pvalue = def->values + def->num_values;
+ uint entries_left = 0, slots_left = 0, mult_shift = 0;
+ uint i = def->num_counts + 1, j;
+
+ for (;;) {
+ if (slots_left == 0) {
+ if (entries_left != 0) {
+ slots_left = 1 << (i - initial_bits);
+ mult_shift = 0;
+ continue;
+ }
+ if (--i <= initial_bits)
+ break;
+ entries_left = def->counts[i];
+ continue;
+ }
+ if (entries_left == 0) {
+ entries_left = def->counts[--i];
+ mult_shift++;
+ continue;
+ }
+ --entries_left, --pvalue;
+ for (j = 1 << mult_shift; j > 0; j--) {
+ --pcd2;
+ pcd2->value = *pvalue;
+ pcd2->code_length = i - initial_bits;
+ }
+ if ((slots_left -= 1 << mult_shift) == 0) {
+ --pcd;
+ pcd->value = pcd2 - decode;
+ pcd->code_length = i + mult_shift;
+ }
+ }
+ }
+}
diff --git a/pstoraster/shcgen.h b/pstoraster/shcgen.h
new file mode 100644
index 000000000..247a4cf3d
--- /dev/null
+++ b/pstoraster/shcgen.h
@@ -0,0 +1,60 @@
+/* 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 shc.h */
+
+#ifndef shcgen_INCLUDED
+# define shcgen_INCLUDED
+
+/* Compute an optimal Huffman code from an input data set. */
+/* The client must have set all the elements of *def. */
+/* The definition is guaranteed to be well-behaved. */
+int hc_compute(P3(hc_definition * def, const long *freqs, gs_memory_t * mem));
+
+/* Convert a definition to a byte string. */
+/* The caller must provide the byte string, of length def->num_values. */
+/* Assume (do not check) that the definition is well-behaved. */
+/* Return the actual length of the string. */
+int hc_bytes_from_definition(P2(byte * dbytes, const hc_definition * def));
+
+/* Extract num_counts and num_values from a byte string. */
+void hc_sizes_from_bytes(P3(hc_definition * def, const byte * dbytes, int num_bytes));
+
+/* Convert a byte string back to a definition. */
+/* The caller must initialize *def, including allocating counts and values. */
+void hc_definition_from_bytes(P2(hc_definition * def, const byte * dbytes));
+
+/* Generate the encoding table from the definition. */
+/* The size of the encode array is def->num_values. */
+void hc_make_encoding(P2(hce_code * encode, const hc_definition * def));
+
+/* Calculate the size of the decoding table. */
+uint hc_sizeof_decoding(P2(const hc_definition * def, int initial_bits));
+
+/* Generate the decoding tables. */
+void hc_make_decoding(P3(hcd_code * decode, const hc_definition * def,
+ int initial_bits));
+
+#endif /* shcgen_INCLUDED */
diff --git a/pstoraster/siscale.c b/pstoraster/siscale.c
new file mode 100644
index 000000000..d23b2e936
--- /dev/null
+++ b/pstoraster/siscale.c
@@ -0,0 +1,498 @@
+/* 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$ */
+/* Image scaling filters */
+#include "math_.h"
+#include "memory_.h"
+#include "stdio_.h"
+#include <assert.h>
+#include "strimpl.h"
+#include "siscale.h"
+
+/*
+ * Image scaling code is based on public domain code from
+ * Graphics Gems III (pp. 414-424), Academic Press, 1992.
+ */
+
+/* ---------------- ImageScaleEncode/Decode ---------------- */
+
+public_st_IScale_state(); /* public so clients can allocate */
+
+/* ------ Digital filter definition ------ */
+
+/* Mitchell filter definition */
+#define Mitchell_support 2.0
+#define B (1.0 / 3.0)
+#define C (1.0 / 3.0)
+private double
+Mitchell_filter(double t)
+{
+ double t2 = t * t;
+
+ if (t < 0)
+ t = -t;
+
+ if (t < 1)
+ return
+ ((12 - 9 * B - 6 * C) * (t * t2) +
+ (-18 + 12 * B + 6 * C) * t2 +
+ (6 - 2 * B)) / 6;
+ else if (t < 2)
+ return
+ ((-1 * B - 6 * C) * (t * t2) +
+ (6 * B + 30 * C) * t2 +
+ (-12 * B - 48 * C) * t +
+ (8 * B + 24 * C)) / 6;
+ else
+ return 0;
+}
+
+#define filter_support Mitchell_support
+#define filter_proc Mitchell_filter
+#define fproc(t) filter_proc(t)
+#define fWidthIn filter_support
+
+/*
+ * The environment provides the following definitions:
+ * typedef PixelTmp, PixelTmp2
+ * double fproc(double t)
+ * double fWidthIn
+ * PixelTmp {min,max,unit}PixelTmp
+ */
+#define CLAMP(v, mn, mx)\
+ (v < mn ? mn : v > mx ? mx : v)
+
+/* ------ Auxiliary procedures ------ */
+
+/* Define the minimum scale. */
+#define min_scale ((fWidthIn * 2) / (max_support - 1.01))
+
+/* Calculate the support for a given scale. */
+/* The value is always in the range 1 .. max_support. */
+private int
+contrib_pixels(double scale)
+{
+ return (int)(fWidthIn / (scale >= 1.0 ? 1.0 : max(scale, min_scale))
+ * 2 + 1);
+}
+
+/* Pre-calculate filter contributions for a row or a column. */
+/* Return the highest input pixel index used. */
+private int
+calculate_contrib(
+ /* Return weight list parameters in contrib[0 .. size-1]. */
+ CLIST * contrib,
+ /* Store weights in items[0 .. contrib_pixels(scale)*size-1]. */
+ /* (Less space than this may actually be needed.) */
+ CONTRIB * items,
+ /* The output image is scaled by 'scale' relative to the input. */
+ double scale,
+ /* Start generating weights for input pixel 'input_index'. */
+ int input_index,
+ /* Generate 'size' weight lists. */
+ int size,
+ /* Limit pixel indices to 'limit', for clamping at the edges */
+ /* of the image. */
+ int limit,
+ /* Wrap pixel indices modulo 'modulus'. */
+ int modulus,
+ /* Successive pixel values are 'stride' distance apart -- */
+ /* normally, the number of color components. */
+ int stride,
+ /* The unit of output is 'rescale_factor' times the unit of input. */
+ double rescale_factor
+)
+{
+ double scaled_factor = scale_PixelWeight(rescale_factor);
+ double WidthIn, fscale;
+ bool squeeze;
+ int npixels;
+ int i, j;
+ int last_index = -1;
+
+ if (scale < 1.0) {
+ double clamped_scale = max(scale, min_scale);
+
+ WidthIn = fWidthIn / clamped_scale;
+ fscale = 1.0 / clamped_scale;
+ squeeze = true;
+ } else {
+ WidthIn = fWidthIn;
+ fscale = 1.0;
+ squeeze = false;
+ }
+ npixels = (int)(WidthIn * 2 + 1);
+
+ for (i = 0; i < size; ++i) {
+ double center = (input_index + i) / scale;
+ int left = (int)ceil(center - WidthIn);
+ int right = (int)floor(center + WidthIn);
+
+ /*
+ * In pathological cases, the limit may be much less
+ * than the support. We do need to deal with this.
+ */
+#define clamp_pixel(j)\
+ (j < 0 ? (-j >= limit ? limit - 1 : -j) :\
+ j >= limit ? (j >> 1 >= limit ? 0 : (limit - j) + limit - 1) :\
+ j)
+ int lmin =
+ (left < 0 ? 0 : left);
+ int lmax =
+ (left < 0 ? (-left >= limit ? limit - 1 : -left) : left);
+ int rmin =
+ (right >= limit ?
+ (right >> 1 >= limit ? 0 : (limit - right) + limit - 1) :
+ right);
+ int rmax =
+ (right >= limit ? limit - 1 : right);
+ int first_pixel = min(lmin, rmin);
+ int last_pixel = max(lmax, rmax);
+ CONTRIB *p;
+
+ if (last_pixel > last_index)
+ last_index = last_pixel;
+ contrib[i].first_pixel = (first_pixel % modulus) * stride;
+ contrib[i].n = last_pixel - first_pixel + 1;
+ contrib[i].index = i * npixels;
+ p = items + contrib[i].index;
+ for (j = 0; j < npixels; ++j)
+ p[j].weight = 0;
+ if (squeeze) {
+ for (j = left; j <= right; ++j) {
+ double weight =
+ fproc((center - j) / fscale) / fscale;
+ int n = clamp_pixel(j);
+ int k = n - first_pixel;
+
+ p[k].weight +=
+ (PixelWeight) (weight * scaled_factor);
+ }
+ } else {
+ for (j = left; j <= right; ++j) {
+ double weight = fproc(center - j);
+ int n = clamp_pixel(j);
+ int k = n - first_pixel;
+
+ p[k].weight +=
+ (PixelWeight) (weight * scaled_factor);
+ }
+ }
+ }
+ return last_index;
+}
+
+
+/* Apply filter to zoom horizontally from src to tmp. */
+private void
+zoom_x(PixelTmp * tmp, const void /*PixelIn */ *src, int sizeofPixelIn,
+ int tmp_width, int WidthIn, int Colors, const CLIST * contrib,
+ const CONTRIB * items)
+{
+ int c, i;
+
+ for (c = 0; c < Colors; ++c) {
+ PixelTmp *tp = tmp + c;
+ const CLIST *clp = contrib;
+
+#define zoom_x_loop(PixelIn, PixelIn2)\
+ const PixelIn *raster = (const PixelIn *)src + c;\
+ for ( i = 0; i < tmp_width; tp += Colors, ++clp, ++i )\
+ { AccumTmp weight = 0;\
+ { int j = clp->n;\
+ const PixelIn *pp = raster + clp->first_pixel;\
+ const CONTRIB *cp = items + clp->index;\
+ switch ( Colors )\
+ {\
+ case 1:\
+ for ( ; j > 0; pp += 1, ++cp, --j )\
+ weight += *pp * cp->weight;\
+ break;\
+ case 3:\
+ for ( ; j > 0; pp += 3, ++cp, --j )\
+ weight += *pp * cp->weight;\
+ break;\
+ default:\
+ for ( ; j > 0; pp += Colors, ++cp, --j )\
+ weight += *pp * cp->weight;\
+ }\
+ }\
+ { PixelIn2 pixel = unscale_AccumTmp(weight);\
+ *tp =\
+ (PixelTmp)CLAMP(pixel, minPixelTmp, maxPixelTmp);\
+ }\
+ }
+
+ if (sizeofPixelIn == 1) {
+ zoom_x_loop(byte, int)
+ } else { /* sizeofPixelIn == 2 */
+#if arch_ints_are_short
+ zoom_x_loop(bits16, long)
+#else
+ zoom_x_loop(bits16, int)
+#endif
+ }
+ }
+} /* Apply filter to zoom vertically from tmp to dst. *//* This is simpler because we can treat all columns identically *//* without regard to the number of samples per pixel. */ private void
+zoom_y(void /*PixelOut */ *dst, int sizeofPixelOut, uint MaxValueOut,
+ const PixelTmp * tmp, int WidthOut, int tmp_width,
+ int Colors, const CLIST * contrib, const CONTRIB * items)
+{
+ int kn = WidthOut * Colors;
+ int cn = contrib->n;
+ int first_pixel = contrib->first_pixel;
+ const CONTRIB *cbp = items + contrib->index;
+ int kc;
+ PixelTmp2 max_weight = MaxValueOut;
+
+#define zoom_y_loop(PixelOut)\
+ for ( kc = 0; kc < kn; ++kc )\
+ { AccumTmp weight = 0;\
+ { const PixelTmp *pp = &tmp[kc + first_pixel];\
+ int j = cn;\
+ const CONTRIB *cp = cbp;\
+ for ( ; j > 0; pp += kn, ++cp, --j )\
+ weight += *pp * cp->weight;\
+ }\
+ { PixelTmp2 pixel = unscale_AccumTmp(weight);\
+ ((PixelOut *)dst)[kc] =\
+ (PixelOut)CLAMP(pixel, 0, max_weight);\
+ }\
+ }
+
+ if (sizeofPixelOut == 1) {
+ zoom_y_loop(byte)
+ } else { /* sizeofPixelOut == 2 */
+ zoom_y_loop(bits16)
+ }
+}
+
+/* ------ Stream implementation ------ */
+
+#define tmp_width WidthOut
+#define tmp_height HeightIn
+
+/* Forward references */
+private void s_IScale_release(P1(stream_state * st));
+
+/* Calculate the weights for an output row. */
+private void
+calculate_dst_contrib(stream_IScale_state * ss, int y)
+{
+ uint row_size = ss->WidthOut * ss->Colors;
+ int last_index =
+ calculate_contrib(&ss->dst_next_list, ss->dst_items, ss->yscale,
+ y, 1, ss->HeightIn, max_support, row_size,
+ (double)ss->MaxValueOut / unitPixelTmp);
+ int first_index_mod = ss->dst_next_list.first_pixel / row_size;
+
+ ss->dst_last_index = last_index;
+ last_index %= max_support;
+ if (last_index < first_index_mod) { /* Shuffle the indices to account for wraparound. */
+ CONTRIB shuffle[max_support];
+ int i;
+
+ for (i = 0; i < max_support; ++i)
+ shuffle[i].weight =
+ (i <= last_index ?
+ ss->dst_items[i + max_support - first_index_mod].weight :
+ i >= first_index_mod ?
+ ss->dst_items[i - first_index_mod].weight :
+ 0);
+ memcpy(ss->dst_items, shuffle, max_support * sizeof(CONTRIB));
+ ss->dst_next_list.n = max_support;
+ ss->dst_next_list.first_pixel = 0;
+ }
+}
+
+/* Initialize the filter. */
+private int
+s_IScale_init(stream_state * st)
+{
+ stream_IScale_state *const ss = (stream_IScale_state *) st;
+ gs_memory_t *mem = ss->memory;
+
+ ss->sizeofPixelIn = ss->BitsPerComponentIn / 8;
+ ss->sizeofPixelOut = ss->BitsPerComponentOut / 8;
+ ss->xscale = (double)ss->WidthOut / (double)ss->WidthIn;
+ ss->yscale = (double)ss->HeightOut / (double)ss->HeightIn;
+
+ ss->src_y = 0;
+ ss->src_size = ss->WidthIn * ss->sizeofPixelIn * ss->Colors;
+ ss->src_offset = 0;
+ ss->dst_y = 0;
+ ss->dst_size = ss->WidthOut * ss->sizeofPixelOut * ss->Colors;
+ ss->dst_offset = 0;
+
+ /* create intermediate image to hold horizontal zoom */
+ ss->tmp = (PixelTmp *) gs_alloc_byte_array(mem,
+ min(ss->tmp_height, max_support),
+ ss->tmp_width * ss->Colors * sizeof(PixelTmp),
+ "image_scale tmp");
+ ss->contrib = (CLIST *) gs_alloc_byte_array(mem,
+ max(ss->WidthOut, ss->HeightOut),
+ sizeof(CLIST), "image_scale contrib");
+ ss->items = (CONTRIB *) gs_alloc_byte_array(mem,
+ contrib_pixels(ss->xscale) * ss->WidthOut,
+ sizeof(CONTRIB), "image_scale contrib[*]");
+ /* Allocate buffers for 1 row of source and destination. */
+ ss->dst = gs_alloc_byte_array(mem, ss->WidthOut * ss->Colors,
+ ss->sizeofPixelOut, "image_scale dst");
+ ss->src = gs_alloc_byte_array(mem, ss->WidthIn * ss->Colors,
+ ss->sizeofPixelIn, "image_scale src");
+ if (ss->tmp == 0 || ss->contrib == 0 || ss->items == 0 ||
+ ss->dst == 0 || ss->src == 0
+ ) {
+ s_IScale_release(st);
+ return ERRC;
+/****** WRONG ******/
+ }
+ /* Pre-calculate filter contributions for a row. */
+ calculate_contrib(ss->contrib, ss->items, ss->xscale,
+ 0, ss->WidthOut, ss->WidthIn, ss->WidthIn,
+ ss->Colors, (double)unitPixelTmp / ss->MaxValueIn);
+
+ /* Prepare the weights for the first output row. */
+ calculate_dst_contrib(ss, 0);
+
+ return 0;
+
+}
+
+/* Process a buffer. Note that this handles Encode and Decode identically. */
+private int
+s_IScale_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last)
+{
+ stream_IScale_state *const ss = (stream_IScale_state *) st;
+
+ /* Check whether we need to deliver any output. */
+
+ top:while (ss->src_y > ss->dst_last_index) { /* We have enough horizontally scaled temporary rows */
+ /* to generate a vertically scaled output row. */
+ uint wleft = pw->limit - pw->ptr;
+
+ if (ss->dst_y == ss->HeightOut)
+ return EOFC;
+ if (wleft == 0)
+ return 1;
+ if (ss->dst_offset == 0) {
+ byte *row;
+
+ if (wleft >= ss->dst_size) { /* We can scale the row directly into the output. */
+ row = pw->ptr + 1;
+ pw->ptr += ss->dst_size;
+ } else { /* We'll have to buffer the row. */
+ row = ss->dst;
+ }
+ /* Apply filter to zoom vertically from tmp to dst. */
+ zoom_y(row, ss->sizeofPixelOut, ss->MaxValueOut, ss->tmp,
+ ss->WidthOut, ss->tmp_width, ss->Colors,
+ &ss->dst_next_list, ss->dst_items);
+ /* Idiotic C coercion rules allow T* and void* to be */
+ /* inter-assigned freely, but not compared! */
+ if ((void *)row != ss->dst) /* no buffering */
+ goto adv;
+ } { /* We're delivering a buffered output row. */
+ uint wcount = ss->dst_size - ss->dst_offset;
+ uint ncopy = min(wleft, wcount);
+
+ memcpy(pw->ptr + 1, (byte *) ss->dst + ss->dst_offset, ncopy);
+ pw->ptr += ncopy;
+ ss->dst_offset += ncopy;
+ if (ncopy != wcount)
+ return 1;
+ ss->dst_offset = 0;
+ }
+ /* Advance to the next output row. */
+ adv:++(ss->dst_y);
+ if (ss->dst_y != ss->HeightOut)
+ calculate_dst_contrib(ss, ss->dst_y);
+ }
+
+ /* Read input data and scale horizontally into tmp. */
+
+ {
+ uint rleft = pr->limit - pr->ptr;
+ uint rcount = ss->src_size - ss->src_offset;
+
+ if (rleft == 0)
+ return 0; /* need more input */
+#ifdef DEBUG
+ assert(ss->src_y < ss->HeightIn);
+#endif
+ if (rleft >= rcount) { /* We're going to fill up a row. */
+ const byte *row;
+
+ if (ss->src_offset == 0) { /* We have a complete row. Read the data */
+ /* directly from the input. */
+ row = pr->ptr + 1;
+ } else { /* We're buffering a row in src. */
+ row = ss->src;
+ memcpy((byte *) ss->src + ss->src_offset, pr->ptr + 1,
+ rcount);
+ ss->src_offset = 0;
+ }
+ /* Apply filter to zoom horizontally from src to tmp. */
+ zoom_x(ss->tmp + (ss->src_y % max_support) *
+ ss->tmp_width * ss->Colors, row,
+ ss->sizeofPixelIn, ss->tmp_width, ss->WidthIn,
+ ss->Colors, ss->contrib, ss->items);
+ pr->ptr += rcount;
+ ++(ss->src_y);
+ goto top;
+ } else { /* We don't have a complete row. Copy data to src buffer. */
+ memcpy((byte *) ss->src + ss->src_offset, pr->ptr + 1, rleft);
+ ss->src_offset += rleft;
+ pr->ptr += rleft;
+ return 0;
+ }
+ }
+}
+
+/* Release the filter's storage. */
+private void
+s_IScale_release(stream_state * st)
+{
+ stream_IScale_state *const ss = (stream_IScale_state *) st;
+ gs_memory_t *mem = ss->memory;
+
+ gs_free_object(mem, (void *)ss->src, "image_scale src"); /* no longer const */
+ ss->src = 0;
+ gs_free_object(mem, ss->dst, "image_scale dst");
+ ss->dst = 0;
+ gs_free_object(mem, ss->items, "image_scale contrib[*]");
+ ss->items = 0;
+ gs_free_object(mem, ss->contrib, "image_scale contrib");
+ ss->contrib = 0;
+ gs_free_object(mem, ss->tmp, "image_scale tmp");
+ ss->tmp = 0;
+}
+
+/* Stream template */
+const stream_template s_IScale_template =
+{&st_IScale_state, s_IScale_init, s_IScale_process, 1, 1,
+ s_IScale_release
+};
diff --git a/pstoraster/siscale.h b/pstoraster/siscale.h
new file mode 100644
index 000000000..ca034db12
--- /dev/null
+++ b/pstoraster/siscale.h
@@ -0,0 +1,148 @@
+/* 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$ */
+/* Requires strimpl.h */
+
+#ifndef siscale_INCLUDED
+# define siscale_INCLUDED
+
+#include "gconfigv.h"
+
+/* Define whether to accumulate pixels in fixed or floating point. */
+#if USE_FPU <= 0
+
+ /* Accumulate pixels in fixed point. */
+
+typedef int PixelWeight;
+
+# if arch_ints_are_short
+typedef long AccumTmp;
+
+# else
+typedef int AccumTmp;
+
+# endif
+#define num_weight_bits\
+ ((sizeof(AccumTmp) - maxSizeofPixel) * 8 - (log2_max_support + 1))
+#define scale_PixelWeight(factor) ((int)((factor) * (1 << num_weight_bits)))
+#define unscale_AccumTmp(atemp) arith_rshift(atemp, num_weight_bits)
+
+#else /* USE_FPU > 0 */
+
+ /* Accumulate pixels in floating point. */
+
+typedef float PixelWeight;
+typedef double AccumTmp;
+
+#define scale_PixelWeight(factor) (factor)
+#define unscale_AccumTmp(atemp) ((int)(atemp))
+
+#endif /* USE_FPU */
+
+/* Input values */
+ /*typedef byte PixelIn; *//* see sizeofPixelIn below */
+ /*#define MaxValueIn 255 *//* see MaxValueIn below */
+
+/* Temporary intermediate values */
+typedef byte PixelTmp;
+typedef int PixelTmp2; /* extra width for clamping sum */
+
+#define minPixelTmp 0
+#define maxPixelTmp 255
+#define unitPixelTmp 255
+
+/* Max of all pixel sizes */
+#define maxSizeofPixel 2
+
+/* Output values */
+ /*typedef byte PixelOut; *//* see sizeofPixelOut below */
+ /*#define MaxValueOut 255 *//* see MaxValueOut below */
+
+/*
+ * The 'support' S of the digital filter is the value such that the filter
+ * is guaranteed to be zero for all arguments outside the range [-S..S].
+ * We artificially limit the support so that we can put an upper bound
+ * on the time required to compute an output value and on the amount of
+ * storage required for the X-filtered input data; this also allows us
+ * to use pre-scaled fixed-point values for the weights if we wish.
+ *
+ * 8x8 pixels should be enough for any reasonable application....
+ */
+#define log2_max_support 3
+#define max_support (1 << log2_max_support)
+
+/* Auxiliary structures. */
+
+typedef struct {
+ PixelWeight weight; /* float or scaled fraction */
+} CONTRIB;
+
+typedef struct {
+ int index; /* index of first element in list of */
+ /* contributors */
+ int n; /* number of contributors */
+ /* (not multiplied by stride) */
+ int first_pixel; /* offset of first value in source data */
+} CLIST;
+
+/* ImageScaleEncode / ImageScaleDecode */
+typedef struct stream_IScale_state_s {
+ stream_state_common;
+ /* The client sets the following before initialization. */
+ int Colors; /* any number >= 1 */
+ int BitsPerComponentIn; /* bits per input value, 8 or 16 */
+ uint MaxValueIn; /* max value of input component */
+ int WidthIn, HeightIn;
+ int BitsPerComponentOut; /* bits per output value, 8 or 16 */
+ uint MaxValueOut; /* max value of output component */
+ int WidthOut, HeightOut;
+ /* The init procedure sets the following. */
+ int sizeofPixelIn; /* bytes per input value, 1 or 2 */
+ int sizeofPixelOut; /* bytes per output value, 1 or 2 */
+ double xscale, yscale;
+ void /*PixelIn */ *src;
+ void /*PixelOut */ *dst;
+ PixelTmp *tmp;
+ CLIST *contrib;
+ CONTRIB *items;
+ /* The following are updated dynamically. */
+ int src_y;
+ uint src_offset, src_size;
+ int dst_y;
+ uint dst_offset, dst_size;
+ CLIST dst_next_list; /* for next output value */
+ int dst_last_index; /* highest index used in list */
+ CONTRIB dst_items[max_support]; /* ditto */
+} stream_IScale_state;
+
+extern_st(st_IScale_state); /* so clients can allocate */
+#define public_st_IScale_state() /* in siscale.c */\
+ gs_public_st_ptrs5(st_IScale_state, stream_IScale_state,\
+ "ImageScaleEncode/Decode state",\
+ iscale_state_enum_ptrs, iscale_state_reloc_ptrs,\
+ dst, src, tmp, contrib, items)
+extern const stream_template s_IScale_template;
+
+#endif /* siscale_INCLUDED */
diff --git a/pstoraster/sjpeg.h b/pstoraster/sjpeg.h
new file mode 100644
index 000000000..92fb684dd
--- /dev/null
+++ b/pstoraster/sjpeg.h
@@ -0,0 +1,80 @@
+/* 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 sdct.h, jpeg/jpeglib.h */
+
+#ifndef sjpeg_INCLUDED
+# define sjpeg_INCLUDED
+
+/*
+ * Each routine gs_jpeg_xxx is equivalent to the IJG entry point jpeg_xxx,
+ * except that
+ * (a) it takes a pointer to stream_DCT_state instead of just the IJG
+ * jpeg_(de)compress_data struct;
+ * (b) it catches any error exit from the IJG code and converts it into
+ * an error return value per Ghostscript custom. A negative return
+ * value is an error code, except for gs_jpeg_alloc_xxx which return
+ * NULL (indicating e_VMerror).
+ */
+
+/* Common to encode/decode */
+
+void gs_jpeg_error_setup(P1(stream_DCT_state * st));
+int gs_jpeg_log_error(P1(stream_DCT_state * st));
+JQUANT_TBL *gs_jpeg_alloc_quant_table(P1(stream_DCT_state * st));
+JHUFF_TBL *gs_jpeg_alloc_huff_table(P1(stream_DCT_state * st));
+int gs_jpeg_destroy(P1(stream_DCT_state * st));
+
+/* Encode */
+
+int gs_jpeg_create_compress(P1(stream_DCT_state * st));
+int gs_jpeg_set_defaults(P1(stream_DCT_state * st));
+int gs_jpeg_set_colorspace(P2(stream_DCT_state * st,
+ J_COLOR_SPACE colorspace));
+int gs_jpeg_set_linear_quality(P3(stream_DCT_state * st,
+ int scale_factor,
+ boolean force_baseline));
+int gs_jpeg_set_quality(P3(stream_DCT_state * st,
+ int quality,
+ boolean force_baseline));
+int gs_jpeg_start_compress(P2(stream_DCT_state * st,
+ boolean write_all_tables));
+int gs_jpeg_write_scanlines(P3(stream_DCT_state * st,
+ JSAMPARRAY scanlines,
+ int num_lines));
+int gs_jpeg_finish_compress(P1(stream_DCT_state * st));
+
+/* Decode */
+
+int gs_jpeg_create_decompress(P1(stream_DCT_state * st));
+int gs_jpeg_read_header(P2(stream_DCT_state * st,
+ boolean require_image));
+int gs_jpeg_start_decompress(P1(stream_DCT_state * st));
+int gs_jpeg_read_scanlines(P3(stream_DCT_state * st,
+ JSAMPARRAY scanlines,
+ int max_lines));
+int gs_jpeg_finish_decompress(P1(stream_DCT_state * st));
+
+#endif /* sjpeg_INCLUDED */
diff --git a/pstoraster/sjpegc.c b/pstoraster/sjpegc.c
new file mode 100644
index 000000000..eca7e589c
--- /dev/null
+++ b/pstoraster/sjpegc.c
@@ -0,0 +1,305 @@
+/*
+ Copyright 1993-2002 by Easy Software Products.
+ Copyright 1994, 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.
+*/
+
+#include <config.h>
+#ifdef HAVE_LIBJPEG
+/*$Id$ */
+/* Interface routines for IJG code, common to encode/decode. */
+#include "stdio_.h"
+#include "string_.h"
+#include "jpeglib.h"
+#include "jerror.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "strimpl.h"
+#include "sdct.h"
+#include "sjpeg.h"
+
+/* gs_jpeg_message_table() is kept in a separate file for arcane reasons.
+ * See sjpegerr.c.
+ */
+const char *const *gs_jpeg_message_table(P1(void));
+
+/*
+ * Error handling routines (these replace corresponding IJG routines from
+ * jpeg/jerror.c). These are used for both compression and decompression.
+ * We assume
+ * offset_of(jpeg_compress_data, cinfo)==offset_of(jpeg_decompress_data, dinfo)
+ */
+
+private void
+gs_jpeg_error_exit(j_common_ptr cinfo)
+{
+ jpeg_stream_data *jcomdp =
+ (jpeg_stream_data *) ((char *)cinfo -
+ offset_of(jpeg_compress_data, cinfo));
+
+ longjmp(jcomdp->exit_jmpbuf, 1);
+}
+
+private void
+gs_jpeg_emit_message(j_common_ptr cinfo, int msg_level)
+{
+ if (msg_level < 0) { /* GS policy is to ignore IJG warnings when Picky=0,
+ * treat them as errors when Picky=1.
+ */
+ jpeg_stream_data *jcomdp =
+ (jpeg_stream_data *) ((char *)cinfo -
+ offset_of(jpeg_compress_data, cinfo));
+
+ if (jcomdp->Picky)
+ gs_jpeg_error_exit(cinfo);
+ }
+ /* Trace messages are always ignored. */
+}
+
+/*
+ * This is an exact copy of format_message from jpeg/jerror.c.
+ * We do not use jerror.c in Ghostscript, so we have to duplicate this routine.
+ */
+
+private void
+gs_jpeg_format_message(j_common_ptr cinfo, char *buffer)
+{
+ struct jpeg_error_mgr *err = cinfo->err;
+ int msg_code = err->msg_code;
+ const char *msgtext = NULL;
+ const char *msgptr;
+ char ch;
+ boolean isstring;
+
+ /* Look up message string in proper table */
+ if (msg_code > 0 && msg_code <= err->last_jpeg_message) {
+ msgtext = err->jpeg_message_table[msg_code];
+ } else if (err->addon_message_table != NULL &&
+ msg_code >= err->first_addon_message &&
+ msg_code <= err->last_addon_message) {
+ msgtext = err->addon_message_table[msg_code - err->first_addon_message];
+ }
+ /* Defend against bogus message number */
+ if (msgtext == NULL) {
+ err->msg_parm.i[0] = msg_code;
+ msgtext = err->jpeg_message_table[0];
+ }
+ /* Check for string parameter, as indicated by %s in the message text */
+ isstring = FALSE;
+ msgptr = msgtext;
+ while ((ch = *msgptr++) != '\0') {
+ if (ch == '%') {
+ if (*msgptr == 's')
+ isstring = TRUE;
+ break;
+ }
+ }
+
+ /* Format the message into the passed buffer */
+ if (isstring)
+ sprintf(buffer, msgtext, err->msg_parm.s);
+ else
+ sprintf(buffer, msgtext,
+ err->msg_parm.i[0], err->msg_parm.i[1],
+ err->msg_parm.i[2], err->msg_parm.i[3],
+ err->msg_parm.i[4], err->msg_parm.i[5],
+ err->msg_parm.i[6], err->msg_parm.i[7]);
+}
+
+/* And this is an exact copy of another routine from jpeg/jerror.c. */
+
+private void
+gs_jpeg_reset_error_mgr(j_common_ptr cinfo)
+{
+ cinfo->err->num_warnings = 0;
+ /* trace_level is not reset since it is an application-supplied parameter */
+ cinfo->err->msg_code = 0; /* may be useful as a flag for "no error" */
+}
+
+/*
+ * This routine initializes the error manager fields in the JPEG object.
+ * It is based on jpeg_std_error from jpeg/jerror.c.
+ */
+
+void
+gs_jpeg_error_setup(stream_DCT_state * st)
+{
+ struct jpeg_error_mgr *err = &st->data.common->err;
+
+ err->error_exit = gs_jpeg_error_exit;
+ err->emit_message = gs_jpeg_emit_message;
+ /* We need not set the output_message field since gs_jpeg_emit_message
+ * doesn't call it, and the IJG library never calls output_message directly.
+ * Setting the format_message field isn't strictly necessary either,
+ * since gs_jpeg_log_error calls gs_jpeg_format_message directly.
+ */
+ err->format_message = gs_jpeg_format_message;
+ err->reset_error_mgr = gs_jpeg_reset_error_mgr;
+
+ err->trace_level = 0; /* default = no tracing */
+ err->num_warnings = 0; /* no warnings emitted yet */
+ err->msg_code = 0; /* may be useful as a flag for "no error" */
+
+ /* Initialize message table pointers */
+ err->jpeg_message_table = gs_jpeg_message_table();
+ err->last_jpeg_message = (int)JMSG_LASTMSGCODE - 1;
+
+ err->addon_message_table = NULL;
+ err->first_addon_message = 0; /* for safety */
+ err->last_addon_message = 0;
+
+ st->data.compress->cinfo.err = err; /* works for decompress case too */
+}
+
+/* Stuff the IJG error message into errorinfo after an error exit. */
+
+int
+gs_jpeg_log_error(stream_DCT_state * st)
+{
+ j_common_ptr cinfo = (j_common_ptr) & st->data.compress->cinfo;
+ char buffer[JMSG_LENGTH_MAX];
+
+ /* Format the error message */
+ gs_jpeg_format_message(cinfo, buffer);
+ (*st->report_error) ((stream_state *) st, buffer);
+ return gs_error_ioerror; /* caller will do return_error() */
+}
+
+
+/*
+ * Interface routines. This layer of routines exists solely to limit
+ * side-effects from using setjmp.
+ */
+
+
+JQUANT_TBL *
+gs_jpeg_alloc_quant_table(stream_DCT_state * st)
+{
+ if (setjmp(st->data.common->exit_jmpbuf)) {
+ gs_jpeg_log_error(st);
+ return NULL;
+ }
+ return jpeg_alloc_quant_table((j_common_ptr)
+ & st->data.compress->cinfo);
+}
+
+JHUFF_TBL *
+gs_jpeg_alloc_huff_table(stream_DCT_state * st)
+{
+ if (setjmp(st->data.common->exit_jmpbuf)) {
+ gs_jpeg_log_error(st);
+ return NULL;
+ }
+ return jpeg_alloc_huff_table((j_common_ptr)
+ & st->data.compress->cinfo);
+}
+
+int
+gs_jpeg_destroy(stream_DCT_state * st)
+{
+ if (setjmp(st->data.common->exit_jmpbuf))
+ return_error(gs_jpeg_log_error(st));
+ jpeg_destroy((j_common_ptr) & st->data.compress->cinfo);
+ return 0;
+}
+
+
+/*
+ * These routines replace the low-level memory manager of the IJG library.
+ * They pass malloc/free calls to the Ghostscript memory manager.
+ * Note we do not need these to be declared in any GS header file.
+ */
+
+private gs_memory_t *
+gs_j_common_memory(j_common_ptr cinfo)
+{ /*
+ * We use the offset of cinfo in jpeg_compress data here, but we
+ * could equally well have used jpeg_decompress_data.
+ */
+ const jpeg_stream_data *sd =
+ ((const jpeg_stream_data *)((const byte *)cinfo -
+ offset_of(jpeg_compress_data, cinfo)));
+
+ return sd->memory;
+}
+
+void *
+jpeg_get_small(j_common_ptr cinfo, size_t sizeofobject)
+{
+ gs_memory_t *mem = gs_j_common_memory(cinfo);
+
+ return gs_alloc_bytes_immovable(mem, sizeofobject,
+ "JPEG small internal data allocation");
+}
+
+void
+jpeg_free_small(j_common_ptr cinfo, void *object, size_t sizeofobject)
+{
+ gs_memory_t *mem = gs_j_common_memory(cinfo);
+
+ gs_free_object(mem, object, "Freeing JPEG small internal data");
+}
+
+void FAR *
+jpeg_get_large(j_common_ptr cinfo, size_t sizeofobject)
+{
+ gs_memory_t *mem = gs_j_common_memory(cinfo);
+
+ return gs_alloc_bytes_immovable(mem, sizeofobject,
+ "JPEG large internal data allocation");
+}
+
+void
+jpeg_free_large(j_common_ptr cinfo, void FAR * object, size_t sizeofobject)
+{
+ gs_memory_t *mem = gs_j_common_memory(cinfo);
+
+ gs_free_object(mem, object, "Freeing JPEG large internal data");
+}
+
+long
+jpeg_mem_available(j_common_ptr cinfo, long min_bytes_needed,
+ long max_bytes_needed, long already_allocated)
+{
+ return max_bytes_needed;
+}
+
+void
+jpeg_open_backing_store(j_common_ptr cinfo, void *info,
+ long total_bytes_needed)
+{
+ ERREXIT(cinfo, JERR_NO_BACKING_STORE);
+}
+
+long
+jpeg_mem_init(j_common_ptr cinfo)
+{
+ return 0; /* just set max_memory_to_use to 0 */
+}
+
+void
+jpeg_mem_term(j_common_ptr cinfo)
+{
+ /* no work */
+}
+#endif /* HAVE_LIBJPEG */
diff --git a/pstoraster/sjpegd.c b/pstoraster/sjpegd.c
new file mode 100644
index 000000000..ec7a9c04f
--- /dev/null
+++ b/pstoraster/sjpegd.c
@@ -0,0 +1,100 @@
+/*
+ Copyright 1993-2002 by Easy Software Products.
+ Copyright (C) 1994, 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.
+*/
+
+#include <config.h>
+#ifdef HAVE_LIBJPEG
+/*$Id$ */
+/* Interface routines for IJG decoding code. */
+#include "stdio_.h"
+#include "string_.h"
+#include "jpeglib.h"
+#include "jerror.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "strimpl.h"
+#include "sdct.h"
+#include "sjpeg.h"
+
+/*
+ * Interface routines. This layer of routines exists solely to limit
+ * side-effects from using setjmp.
+ */
+
+int
+gs_jpeg_create_decompress(stream_DCT_state * st)
+{ /* Initialize error handling */
+ gs_jpeg_error_setup(st);
+ /* Establish the setjmp return context for gs_jpeg_error_exit to use. */
+ if (setjmp(st->data.common->exit_jmpbuf))
+ return_error(gs_jpeg_log_error(st));
+
+ jpeg_create_decompress(&st->data.decompress->dinfo);
+ jpeg_stream_data_common_init(st->data.decompress);
+ return 0;
+}
+
+int
+gs_jpeg_read_header(stream_DCT_state * st,
+ boolean require_image)
+{
+ if (setjmp(st->data.common->exit_jmpbuf))
+ return_error(gs_jpeg_log_error(st));
+ return jpeg_read_header(&st->data.decompress->dinfo, require_image);
+}
+
+int
+gs_jpeg_start_decompress(stream_DCT_state * st)
+{
+ if (setjmp(st->data.common->exit_jmpbuf))
+ return_error(gs_jpeg_log_error(st));
+#if JPEG_LIB_VERSION > 55
+ return (int)jpeg_start_decompress(&st->data.decompress->dinfo);
+#else
+ /* in IJG version 5, jpeg_start_decompress had no return value */
+ jpeg_start_decompress(&st->data.decompress->dinfo);
+ return 1;
+#endif
+}
+
+int
+gs_jpeg_read_scanlines(stream_DCT_state * st,
+ JSAMPARRAY scanlines,
+ int max_lines)
+{
+ if (setjmp(st->data.common->exit_jmpbuf))
+ return_error(gs_jpeg_log_error(st));
+ return (int)jpeg_read_scanlines(&st->data.decompress->dinfo,
+ scanlines, (JDIMENSION) max_lines);
+}
+
+int
+gs_jpeg_finish_decompress(stream_DCT_state * st)
+{
+ if (setjmp(st->data.common->exit_jmpbuf))
+ return_error(gs_jpeg_log_error(st));
+ return (int)jpeg_finish_decompress(&st->data.decompress->dinfo);
+}
+#endif /* HAVE_LIBJPEG */
diff --git a/pstoraster/sjpege.c b/pstoraster/sjpege.c
new file mode 100644
index 000000000..0621e12be
--- /dev/null
+++ b/pstoraster/sjpege.c
@@ -0,0 +1,129 @@
+/*
+ Copyright 1993-2002 by Easy Software Products.
+ Copyright 1994, 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.
+*/
+
+#include <config.h>
+#ifdef HAVE_LIBJPEG
+/*$Id$ */
+/* Interface routines for IJG encoding code. */
+#include "stdio_.h"
+#include "string_.h"
+#include "jpeglib.h"
+#include "jerror.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "strimpl.h"
+#include "sdct.h"
+#include "sjpeg.h"
+
+/*
+ * Interface routines. This layer of routines exists solely to limit
+ * side-effects from using setjmp.
+ */
+
+int
+gs_jpeg_create_compress(stream_DCT_state * st)
+{ /* Initialize error handling */
+ gs_jpeg_error_setup(st);
+ /* Establish the setjmp return context for gs_jpeg_error_exit to use. */
+ if (setjmp(st->data.common->exit_jmpbuf))
+ return_error(gs_jpeg_log_error(st));
+
+ jpeg_create_compress(&st->data.compress->cinfo);
+ jpeg_stream_data_common_init(st->data.compress);
+ return 0;
+}
+
+int
+gs_jpeg_set_defaults(stream_DCT_state * st)
+{
+ if (setjmp(st->data.common->exit_jmpbuf))
+ return_error(gs_jpeg_log_error(st));
+ jpeg_set_defaults(&st->data.compress->cinfo);
+ return 0;
+}
+
+int
+gs_jpeg_set_colorspace(stream_DCT_state * st,
+ J_COLOR_SPACE colorspace)
+{
+ if (setjmp(st->data.common->exit_jmpbuf))
+ return_error(gs_jpeg_log_error(st));
+ jpeg_set_colorspace(&st->data.compress->cinfo, colorspace);
+ return 0;
+}
+
+int
+gs_jpeg_set_linear_quality(stream_DCT_state * st,
+ int scale_factor, boolean force_baseline)
+{
+ if (setjmp(st->data.common->exit_jmpbuf))
+ return_error(gs_jpeg_log_error(st));
+ jpeg_set_linear_quality(&st->data.compress->cinfo,
+ scale_factor, force_baseline);
+ return 0;
+}
+
+int
+gs_jpeg_set_quality(stream_DCT_state * st,
+ int quality, boolean force_baseline)
+{
+ if (setjmp(st->data.common->exit_jmpbuf))
+ return_error(gs_jpeg_log_error(st));
+ jpeg_set_quality(&st->data.compress->cinfo,
+ quality, force_baseline);
+ return 0;
+}
+
+int
+gs_jpeg_start_compress(stream_DCT_state * st,
+ boolean write_all_tables)
+{
+ if (setjmp(st->data.common->exit_jmpbuf))
+ return_error(gs_jpeg_log_error(st));
+ jpeg_start_compress(&st->data.compress->cinfo, write_all_tables);
+ return 0;
+}
+
+int
+gs_jpeg_write_scanlines(stream_DCT_state * st,
+ JSAMPARRAY scanlines,
+ int num_lines)
+{
+ if (setjmp(st->data.common->exit_jmpbuf))
+ return_error(gs_jpeg_log_error(st));
+ return (int)jpeg_write_scanlines(&st->data.compress->cinfo,
+ scanlines, (JDIMENSION) num_lines);
+}
+
+int
+gs_jpeg_finish_compress(stream_DCT_state * st)
+{
+ if (setjmp(st->data.common->exit_jmpbuf))
+ return_error(gs_jpeg_log_error(st));
+ jpeg_finish_compress(&st->data.compress->cinfo);
+ return 0;
+}
+#endif /* HAVE_LIBJPEG */
diff --git a/pstoraster/sjpegerr.c b/pstoraster/sjpegerr.c
new file mode 100644
index 000000000..767aeac04
--- /dev/null
+++ b/pstoraster/sjpegerr.c
@@ -0,0 +1,102 @@
+/*
+ Copyright 1993-2002 by Easy Software Products
+ Copyright (C) 1994, 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.
+*/
+
+#include <config.h>
+#ifdef HAVE_LIBJPEG
+/*$Id$ */
+/* IJG error message table for Ghostscript. */
+#include "stdio_.h"
+#include "jpeglib.h"
+
+/*
+ * MRS - these are normally found in jversion.h, however it seems that
+ * many vendors (Red Hat, SGI, etc.) do not distribute it...
+ *
+ * The following definitions come from the 6B distribution...
+ */
+
+#define JVERSION "6b 27-Mar-1998"
+#define JCOPYRIGHT "Copyright (C) 1998, Thomas G. Lane"
+
+/*
+ * This file exists solely to hold the rather large IJG error message string
+ * table (now about 4K, and likely to grow in future releases). The table
+ * is large enough that we don't want it to be in the default data segment
+ * in a 16-bit executable.
+ *
+ * In IJG version 5 and earlier, under Borland C, this is accomplished simply
+ * by compiling this one file in "huge" memory model rather than "large".
+ * The string constants will then go into a private far data segment.
+ * In less brain-damaged architectures, this file is simply compiled normally,
+ * and we pay only the price of one extra function call.
+ *
+ * In IJG version 5a and later, under Borland C, this is accomplished by making
+ * each string be a separate variable that's explicitly declared "far".
+ * (What a crock...)
+ *
+ * This must be a separate file to avoid duplicate-symbol errors, since we
+ * use the IJG message code names as variables rather than as enum constants.
+ */
+
+#if JPEG_LIB_VERSION <= 50 /**************** *************** */
+
+#include "jerror.h" /* get error codes */
+#define JMAKE_MSG_TABLE
+#include "jerror.h" /* create message string table */
+
+#define jpeg_std_message_table jpeg_message_table
+
+#else /* JPEG_LIB_VERSION >= 51 */ /**************** *************** */
+
+/* Create a static const char[] variable for each message string. */
+
+#define JMESSAGE(code,string) static const char code[] = string;
+
+#include "jerror.h"
+
+/* Now build an array of pointers to same. */
+
+#define JMESSAGE(code,string) code ,
+
+static const char *const jpeg_std_message_table[] =
+{
+#include "jerror.h"
+ NULL
+};
+
+#endif /* JPEG_LIB_VERSION */ /**************** *************** */
+
+/*
+ * Return a pointer to the message table.
+ * It is unsafe to do much more than this within the "huge" environment.
+ */
+
+const char *const *
+gs_jpeg_message_table(void)
+{
+ return jpeg_std_message_table;
+}
+#endif /* HAVE_LIBJPEG */
diff --git a/pstoraster/slzwc.c b/pstoraster/slzwc.c
new file mode 100644
index 000000000..a9564a785
--- /dev/null
+++ b/pstoraster/slzwc.c
@@ -0,0 +1,50 @@
+/* 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$ */
+/* Code common to LZW encoding and decoding streams */
+#include "std.h"
+#include "strimpl.h"
+#include "slzwx.h"
+
+/* Define the structure for the GC. */
+public_st_LZW_state();
+
+/* Set defaults */
+void
+s_LZW_set_defaults(stream_state * st)
+{
+ stream_LZW_state *const ss = (stream_LZW_state *) st;
+
+ s_LZW_set_defaults_inline(ss);
+}
+
+/* Release a LZW filter. */
+void
+s_LZW_release(stream_state * st)
+{
+ stream_LZW_state *const ss = (stream_LZW_state *) st;
+
+ gs_free_object(st->memory, ss->table.decode, "LZW(close)");
+}
diff --git a/pstoraster/slzwce.c b/pstoraster/slzwce.c
new file mode 100644
index 000000000..85a774fad
--- /dev/null
+++ b/pstoraster/slzwce.c
@@ -0,0 +1,167 @@
+/* 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$ */
+/* Simple encoder compatible with LZW decoding filter */
+#include "stdio_.h" /* includes std.h */
+#include "gdebug.h"
+#include "strimpl.h"
+#include "slzwx.h"
+
+/* ------ Alternate LZWEncode filter implementation ------ */
+
+/*
+
+ The encoded data stream produced by this implementation of the LZWEncode
+ filter consists of a sequence of 9-bit data elements. These elements are
+ packed into bytes in big-endian order, e.g. the elements
+
+ 100000000 001100001
+
+ occurring at the very beginning of the data stream would be packed into
+ bytes as
+
+ 10000000 00011000 01......
+
+ The first bit of each data element is a control bit. If the control bit is
+ 0, the remaining 8 bits of the data element are a data byte. If the control
+ bit is 1, the remaining 8 bits of the data element define a control
+ function:
+
+ 1 00000000 synchronization mark, see below
+ 1 00000001 end of data
+ 1 xxxxxxxx not used (all other values)
+
+ The synchronization mark occurs at the beginning of the data stream, and at
+ least once every 254 data bytes thereafter.
+
+ This format is derived from basic principles of data encoding (the use of a
+ separate flag bit to distinguish out-of-band control information from data
+ per se, and the use of a periodic synchronization mark to help verify the
+ validity of a data stream); it has no relationship to data compression. It
+ is, however, compatible with LZW decompressors. It produces output that is
+ approximately 9/8 times the size of the input.
+
+ */
+
+/* Define the special codes, relative to 1 << InitialCodeLength. */
+#define CODE_RESET 0
+#define CODE_EOD 1
+#define CODE_0 2 /* first assignable code */
+
+/* Internal routine to put a code into the output buffer. */
+/* Let S = ss->code_size. */
+/* Relevant invariants: 9 <= S <= 15, 0 <= code < 1 << S; */
+/* 1 <= ss->bits_left <= 8; only the rightmost (8 - ss->bits_left) */
+/* bits of ss->bits contain valid data. */
+private byte *
+lzw_put_code(register stream_LZW_state * ss, byte * q, uint code)
+{
+ uint size = ss->code_size;
+ byte cb = (ss->bits << ss->bits_left) +
+ (code >> (size - ss->bits_left));
+
+ if_debug2('W', "[w]writing 0x%x,%d\n", code, ss->code_size);
+ *++q = cb;
+ if ((ss->bits_left += 8 - size) <= 0) {
+ *++q = code >> -ss->bits_left;
+ ss->bits_left += 8;
+ }
+ ss->bits = code;
+ return q;
+}
+
+/* Initialize LZW-compatible encoding filter. */
+int
+s_LZWE_reset(stream_state * st)
+{
+ stream_LZW_state *const ss = (stream_LZW_state *) st;
+
+ ss->code_size = ss->InitialCodeLength + 1;
+ ss->bits_left = 8;
+ /* Force the first code emitted to be a reset. */
+ ss->next_code = (1 << ss->code_size) - 2;
+ return 0;
+}
+private int
+s_LZWE_init(stream_state * st)
+{
+ stream_LZW_state *const ss = (stream_LZW_state *) st;
+
+ ss->InitialCodeLength = 8;
+ ss->table.encode = 0;
+ return s_LZWE_reset(st);
+}
+
+/* Process a buffer */
+private int
+s_LZWE_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last)
+{
+ stream_LZW_state *const ss = (stream_LZW_state *) st;
+ register const byte *p = pr->ptr;
+ const byte *rlimit = pr->limit;
+ register byte *q = pw->ptr;
+ byte *wlimit = pw->limit;
+ int status = 0;
+ int signal = 1 << (ss->code_size - 1);
+ uint limit_code = (1 << ss->code_size) - 2; /* reset 1 early */
+ uint next_code = ss->next_code;
+
+ while (p < rlimit) {
+ if (next_code == limit_code) { /* Emit a reset code. */
+ if (wlimit - q < 2) {
+ status = 1;
+ break;
+ }
+ q = lzw_put_code(ss, q, signal + CODE_RESET);
+ next_code = signal + CODE_0;
+ }
+ if (wlimit - q < 2) {
+ status = 1;
+ break;
+ }
+ q = lzw_put_code(ss, q, *++p);
+ next_code++;
+ }
+ if (last && status == 0) {
+ if (wlimit - q < 2)
+ status = 1;
+ else {
+ q = lzw_put_code(ss, q, signal + CODE_EOD);
+ if (ss->bits_left < 8)
+ *++q = ss->bits << ss->bits_left; /* final byte */
+ }
+ }
+ ss->next_code = next_code;
+ pr->ptr = p;
+ pw->ptr = q;
+ return status;
+}
+
+/* Stream template */
+const stream_template s_LZWE_template = {
+ &st_LZW_state, s_LZWE_init, s_LZWE_process, 1, 2, NULL,
+ s_LZW_set_defaults, s_LZWE_reset
+};
diff --git a/pstoraster/slzwd.c b/pstoraster/slzwd.c
new file mode 100644
index 000000000..8680e8607
--- /dev/null
+++ b/pstoraster/slzwd.c
@@ -0,0 +1,372 @@
+/* Copyright (C) 1993, 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$ */
+/* LZW decoding filter */
+#include "stdio_.h" /* includes std.h */
+#include "gdebug.h"
+#include "strimpl.h"
+#include "slzwx.h"
+
+/* ------ LZWDecode ------ */
+
+/********************************************************/
+/* LZW routines are based on: */
+/* Dr. Dobbs Journal --- Oct. 1989. */
+/* Article on LZW Data Compression by Mark R. Nelson */
+/********************************************************/
+
+/* Define the special codes in terms of code_escape, which is */
+/* 1 << InitialCodeLength. */
+#define code_reset (code_escape + 0)
+#define code_eod (code_escape + 1)
+#define code_0 (code_escape + 2) /* first assignable code */
+
+struct lzw_decode_s {
+ byte datum;
+ byte len; /* length of code */
+ ushort prefix; /* code to be prefixed */
+};
+
+gs_private_st_simple(st_lzw_decode, lzw_decode, "lzw_decode");
+/* We can use a simple type as the element type, */
+/* because there are no pointers to enumerate or relocate. */
+#define st_lzw_decode_element st_lzw_decode
+#define lzw_decode_max 4096 /* must be 4096 */
+
+/* Initialize LZWDecode filter */
+/* We separate out the reset function for some non-stream clients. */
+int
+s_LZWD_reset(stream_state * st)
+{
+ stream_LZW_state *const ss = (stream_LZW_state *) st;
+ register lzw_decode *dc = ss->table.decode;
+ register int i;
+ uint code_escape = 1 << ss->InitialCodeLength;
+
+ ss->bits_left = 0;
+ ss->bytes_left = 0;
+ ss->next_code = code_0;
+ ss->code_size = ss->InitialCodeLength + 1;
+ ss->prev_code = -1;
+ ss->copy_code = -1;
+ dc[code_reset].len = 255;
+ dc[code_eod].len = 255;
+ for (i = 0; i < code_escape; i++, dc++)
+ dc->datum = i, dc->len = 1, dc->prefix = code_eod;
+ return 0;
+}
+private int
+s_LZWD_init(stream_state * st)
+{
+ stream_LZW_state *const ss = (stream_LZW_state *) st;
+ lzw_decode *dc =
+ gs_alloc_struct_array(st->memory, lzw_decode_max + 1,
+ lzw_decode, &st_lzw_decode_element,
+ "LZWDecode(init)");
+
+ if (dc == 0)
+ return ERRC;
+/****** WRONG ******/
+ ss->table.decode = dc;
+ return s_LZWD_reset(st);
+}
+
+/* Process a buffer */
+private int
+s_LZWD_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last)
+{
+ stream_LZW_state *const ss = (stream_LZW_state *) st;
+ register const byte *p = pr->ptr;
+ register byte *q = pw->ptr;
+
+#ifdef DEBUG
+ byte *q0 = q;
+
+#endif
+ const byte *rlimit = pr->limit; /* constant pointer */
+ byte *wlimit = pw->limit; /* constant pointer */
+ int status = 0;
+ int code = ss->copy_code;
+ int prev_code = ss->prev_code;
+ uint prev_len = ss->prev_len;
+ byte bits = ss->bits;
+ int bits_left = ss->bits_left;
+ int bytes_left = ss->bytes_left;
+ int code_size = ss->code_size;
+ int code_mask;
+ int switch_code;
+ int next_code = ss->next_code;
+ lzw_decode *table = ss->table.decode; /* constant pointer */
+ lzw_decode *dc_next = table + next_code; /* invariant */
+ lzw_decode *dc;
+ int code_escape = 1 << ss->InitialCodeLength;
+ int eod = code_eod;
+ bool low_order = ss->FirstBitLowOrder;
+ uint len;
+ int c;
+ byte b;
+ byte *q1;
+
+ if_debug2('w', "[w]process decode: code_size=%d next_code=%d\n",
+ code_size, next_code);
+#define set_code_size()\
+ code_mask = (1 << code_size) - 1,\
+ switch_code = code_mask + 1 - ss->EarlyChange
+ set_code_size();
+ if (!ss->BlockData)
+ bytes_left = rlimit - p + 2; /* never stop for bytes_left */
+ /* If we are in the middle of copying a string, */
+ /* do some more now. */
+ if (code >= 0) {
+ int rlen = ss->copy_left;
+ int wlen = wlimit - q;
+ int n = len = min(rlen, wlen);
+
+ c = code;
+ ss->copy_left = rlen -= len;
+ if_debug3('W', "[W]copying 0x%x, %d byte(s) out of %d left\n",
+ code, len, rlen + len);
+ while (rlen)
+ c = table[c].prefix,
+ rlen--;
+ q1 = q += len;
+ n = len;
+ while (--n >= 0) {
+ *q1-- = (dc = &table[c])->datum;
+ c = dc->prefix;
+ }
+ if (ss->copy_left) { /* more to do */
+ pw->ptr = q;
+ return 1;
+ }
+ ss->copy_code = -1;
+ len = ss->copy_len;
+ /* Retrieve the first byte of the code just copied. */
+ if (c == eod) { /* We just copied the entire code, */
+ /* so the byte we want is immediately available. */
+ b = q1[1];
+ } else { /* We have to scan to the beginning of the code. */
+ for (; c != eod; c = table[c].prefix)
+ b = (byte) c;
+ }
+ goto add;
+ }
+ top:if (code_size > bits_left) {
+ if (bytes_left == 0) {
+ if (p == rlimit)
+ goto out;
+ bytes_left = *++p;
+ if_debug1('W', "[W]block count %d\n", bytes_left);
+ if (bytes_left == 0) {
+ status = EOFC;
+ goto out;
+ }
+ goto top;
+ }
+ if (low_order)
+ code = bits >> (8 - bits_left);
+ else
+ code = (uint) bits << (code_size - bits_left);
+ if (bits_left + 8 < code_size) { /* Need 2 more data bytes */
+ if (bytes_left == 1) {
+ if (rlimit - p < 3)
+ goto out;
+ bytes_left = p[2];
+ if_debug1('W', "[W]block count %d\n",
+ bytes_left);
+ if (bytes_left == 0) {
+ status = EOFC;
+ goto out;
+ }
+ bytes_left++;
+ bits = p[1];
+ p++;
+ } else {
+ if (rlimit - p < 2)
+ goto out;
+ bits = p[1];
+ }
+ if (low_order)
+ code += (uint) bits << bits_left;
+ else
+ code += (uint) bits << (code_size - 8 - bits_left);
+ bits_left += 8;
+ bits = p[2];
+ p += 2;
+ bytes_left -= 2;
+ } else {
+ if (p == rlimit)
+ goto out;
+ bits = *++p;
+ bytes_left--;
+ }
+ if (low_order)
+ code += (uint) bits << bits_left,
+ bits_left += 8 - code_size;
+ else
+ bits_left += 8 - code_size,
+ code += bits >> bits_left;
+ } else {
+ if (low_order)
+ code = bits >> (8 - bits_left),
+ bits_left -= code_size;
+ else
+ bits_left -= code_size,
+ code = bits >> bits_left;
+ }
+ code &= code_mask;
+ if_debug2('W', "[W]reading 0x%x,%d\n", code, code_size);
+ /*
+ * There is an anomalous case where a code S is followed
+ * immediately by another occurrence of the S string.
+ * In this case, the next available code will be defined as
+ * S followed by the first character of S, and will be
+ * emitted immediately after the code S. We have to
+ * recognize this case specially, by noting that the code is
+ * equal to next_code.
+ */
+ if (code >= next_code) {
+ if (code > next_code) {
+#ifdef DEBUG
+ lprintf2("[W]code = %d > next_code = %d\n",
+ code, next_code);
+#endif
+ status = ERRC;
+ goto out;
+ }
+ /* Fabricate the entry for the code. It will be */
+ /* overwritten immediately, of course. */
+ for (c = prev_code; c != eod; c = table[c].prefix)
+ dc_next->datum = c;
+ len = prev_len + 1;
+ dc_next->len = min(len, 255);
+ dc_next->prefix = prev_code;
+ if_debug3('w', "[w]decoding anomalous 0x%x=0x%x+%c\n",
+ next_code, prev_code, dc_next->datum);
+ }
+ /* See if there is enough room for the code. */
+ len = table[code].len;
+ if (len == 255) { /* Check for special code (reset or end). */
+ /* We set their lengths to 255 to avoid doing */
+ /* an extra check in the normal case. */
+ if (code == code_reset) {
+ if_debug1('w', "[w]reset: next_code was %d\n",
+ next_code);
+ next_code = code_0;
+ dc_next = table + code_0;
+ code_size = ss->InitialCodeLength + 1;
+ set_code_size();
+ prev_code = -1;
+ goto top;
+ } else if (code == eod) {
+ status = EOFC;
+ goto out;
+ }
+ /* The code length won't fit in a byte, */
+ /* compute it the hard way. */
+ for (c = code, len = 0; c != eod; len++)
+ c = table[c].prefix;
+ if_debug2('w', "[w]long code %d, length=%d\n", code, len);
+ }
+ if (wlimit - q < len) {
+ ss->copy_code = code;
+ ss->copy_left = ss->copy_len = len;
+ status = 1;
+ goto out;
+ }
+ /* Copy the string to the buffer (back to front). */
+ /* Optimize for short codes, which are the most frequent. */
+ dc = &table[code];
+ switch (len) {
+ default:
+ {
+ byte *q1 = q += len;
+
+ c = code;
+ do {
+ *q1-- = (dc = &table[c])->datum;
+ }
+ while ((c = dc->prefix) != eod);
+ b = q1[1];
+ }
+ break;
+ case 3:
+ q[3] = dc->datum;
+ dc = &table[dc->prefix];
+ case 2:
+ q[2] = dc->datum;
+ dc = &table[dc->prefix];
+ case 1:
+ q[1] = b = dc->datum;
+ q += len;
+ }
+ add: /* Add a new entry to the table */
+ if (prev_code >= 0) { /* Unfortunately, we have to check for next_code == */
+ /* lzw_decode_max every time: just checking at power */
+ /* of 2 boundaries stops us one code too soon. */
+ if (next_code == lzw_decode_max) {
+ status = ERRC;
+ goto out;
+ }
+ dc_next->datum = b; /* added char of string */
+ dc_next->len = min(prev_len, 254) + 1;
+ dc_next->prefix = prev_code;
+ dc_next++;
+ if_debug4('W', "[W]adding 0x%x=0x%x+%c(%d)\n",
+ next_code, prev_code, b, min(len, 255));
+ if (++next_code == switch_code) { /* Crossed a power of 2. */
+ /* We have to make a strange special check for */
+ /* reaching the end of the code space. */
+ if (next_code < lzw_decode_max - 1) {
+ code_size++;
+ set_code_size();
+ if_debug2('w', "[w]crossed power of 2: new code_size=%d, next_code=%d\n",
+ code_size, next_code);
+ }
+ }
+ }
+ prev_code = code;
+ prev_len = len;
+ goto top;
+ out:pr->ptr = p;
+ pw->ptr = q;
+ ss->code_size = code_size;
+ ss->prev_code = prev_code;
+ ss->prev_len = prev_len;
+ ss->bits = bits;
+ ss->bits_left = bits_left;
+ ss->bytes_left = bytes_left;
+ ss->next_code = next_code;
+ if_debug3('w', "[w]decoded %d bytes, prev_code=%d, next_code=%d\n",
+ (int)(q - q0), prev_code, next_code);
+ return status;
+}
+
+/* Stream template */
+const stream_template s_LZWD_template =
+{&st_LZW_state, s_LZWD_init, s_LZWD_process, 3, 1, s_LZW_release,
+ s_LZW_set_defaults, s_LZWD_reset
+};
diff --git a/pstoraster/slzwx.h b/pstoraster/slzwx.h
new file mode 100644
index 000000000..50e0b4258
--- /dev/null
+++ b/pstoraster/slzwx.h
@@ -0,0 +1,80 @@
+/* Copyright (C) 1993, 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 strimpl.h */
+
+#ifndef slzwx_INCLUDED
+# define slzwx_INCLUDED
+
+typedef struct lzw_decode_s lzw_decode;
+typedef struct lzw_encode_table_s lzw_encode_table;
+typedef struct stream_LZW_state_s {
+ stream_state_common;
+ /* The following are set before initialization. */
+ int InitialCodeLength; /* decoding only */
+ /*
+ * Adobe calls FirstBitLowOrder LowBitFirst. Either one will work
+ * in PostScript code.
+ */
+ bool FirstBitLowOrder; /* decoding only */
+ bool BlockData; /* decoding only */
+ int EarlyChange; /* decoding only */
+ /* The following are updated dynamically. */
+ uint bits; /* buffer for input bits */
+ int bits_left; /* # of valid low bits left */
+ int bytes_left; /* # of bytes left in current block */
+ /* (arbitrary large # if not GIF) */
+ union _lzt {
+ lzw_decode *decode;
+ lzw_encode_table *encode;
+ } table;
+ uint next_code; /* next code to be assigned */
+ int code_size; /* current # of bits per code */
+ int prev_code; /* previous code recognized or assigned */
+ uint prev_len; /* length of prev_code */
+ int copy_code; /* code whose string is being */
+ /* copied, -1 if none */
+ uint copy_len; /* length of copy_code */
+ int copy_left; /* amount of string left to copy */
+ bool first; /* true if no output yet */
+} stream_LZW_state;
+
+extern_st(st_LZW_state);
+#define public_st_LZW_state() /* in slzwc.c */\
+ gs_public_st_ptrs1(st_LZW_state, stream_LZW_state,\
+ "LZWDecode state", lzwd_enum_ptrs, lzwd_reloc_ptrs, table.decode)
+#define s_LZW_set_defaults_inline(ss)\
+ ((ss)->InitialCodeLength = 8,\
+ (ss)->FirstBitLowOrder = false,\
+ (ss)->BlockData = false,\
+ (ss)->EarlyChange = 1)
+extern const stream_template s_LZWD_template;
+extern const stream_template s_LZWE_template;
+
+/* Shared procedures */
+void s_LZW_set_defaults(P1(stream_state *));
+void s_LZW_release(P1(stream_state *));
+
+#endif /* slzwx_INCLUDED */
diff --git a/pstoraster/smtf.c b/pstoraster/smtf.c
new file mode 100644
index 000000000..93513041d
--- /dev/null
+++ b/pstoraster/smtf.c
@@ -0,0 +1,184 @@
+/* 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$ */
+/* MoveToFront filters */
+#include "stdio_.h"
+#include "strimpl.h"
+#include "smtf.h"
+
+/* ------ MoveToFrontEncode/Decode ------ */
+
+private_st_MTF_state();
+
+/* Initialize */
+private int
+s_MTF_init(stream_state * st)
+{
+ stream_MTF_state *const ss = (stream_MTF_state *) st;
+ int i;
+
+ for (i = 0; i < 256; i++)
+ ss->prev.b[i] = (byte) i;
+ return 0;
+}
+
+/* Encode a buffer */
+private int
+s_MTFE_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last)
+{
+ stream_MTF_state *const ss = (stream_MTF_state *) st;
+ register const byte *p = pr->ptr;
+ register byte *q = pw->ptr;
+ const byte *rlimit = pr->limit;
+ uint count = rlimit - p;
+ uint wcount = pw->limit - q;
+ int status =
+ (count < wcount ? 0 : (rlimit = p + wcount, 1));
+
+ while (p < rlimit) {
+ byte b = *++p;
+ int i;
+ byte prev = b, repl;
+
+ for (i = 0; (repl = ss->prev.b[i]) != b; i++)
+ ss->prev.b[i] = prev, prev = repl;
+ ss->prev.b[i] = prev;
+ *++q = (byte) i;
+ }
+ pr->ptr = p;
+ pw->ptr = q;
+ return status;
+}
+
+/* Stream template */
+const stream_template s_MTFE_template = {
+ &st_MTF_state, s_MTF_init, s_MTFE_process, 1, 1
+};
+
+/* Decode a buffer */
+private int
+s_MTFD_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last)
+{
+ stream_MTF_state *const ss = (stream_MTF_state *) st;
+ register const byte *p = pr->ptr;
+ register byte *q = pw->ptr;
+ const byte *rlimit = pr->limit;
+ uint count = rlimit - p;
+ uint wcount = pw->limit - q;
+ int status = (count <= wcount ? 0 : (rlimit = p + wcount, 1));
+
+ /* Cache the first few entries in local variables. */
+ byte
+ v0 = ss->prev.b[0], v1 = ss->prev.b[1],
+ v2 = ss->prev.b[2], v3 = ss->prev.b[3];
+
+ while (p < rlimit) {
+ byte first;
+
+ /* Zeros far outnumber all other bytes in the BWBS */
+ /* code; check for them first. */
+ if (*++p == 0) {
+ *++q = v0;
+ continue;
+ }
+ switch (*p) {
+ default:
+ {
+ uint b = *p;
+ byte *bp = &ss->prev.b[b];
+
+ *++q = first = *bp;
+#if arch_sizeof_long == 4
+ ss->prev.b[3] = v3;
+#endif
+ /* Move trailing entries individually. */
+ for (;; bp--, b--) {
+ *bp = bp[-1];
+ if (!(b & (sizeof(long) - 1)))
+ break;
+ }
+ /* Move in long-size chunks. */
+ for (; (b -= sizeof(long)) != 0;) {
+ bp -= sizeof(long);
+
+#if arch_is_big_endian
+ *(ulong *) bp =
+ (*(ulong *) bp >> 8) |
+ ((ulong) bp[-1] << ((sizeof(long) - 1) * 8));
+
+#else
+ *(ulong *) bp = (*(ulong *) bp << 8) | bp[-1];
+#endif
+ }
+ }
+#if arch_sizeof_long > 4 /* better be 8! */
+ goto m7;
+ case 7:
+ *++q = first = ss->prev.b[7];
+m7: ss->prev.b[7] = ss->prev.b[6];
+ goto m6;
+ case 6:
+ *++q = first = ss->prev.b[6];
+m6: ss->prev.b[6] = ss->prev.b[5];
+ goto m5;
+ case 5:
+ *++q = first = ss->prev.b[5];
+m5: ss->prev.b[5] = ss->prev.b[4];
+ goto m4;
+ case 4:
+ *++q = first = ss->prev.b[4];
+m4: ss->prev.b[4] = v3;
+#endif
+ goto m3;
+ case 3:
+ *++q = first = v3;
+m3: v3 = v2, v2 = v1, v1 = v0, v0 = first;
+ break;
+ case 2:
+ *++q = first = v2;
+ v2 = v1, v1 = v0, v0 = first;
+ break;
+ case 1:
+ *++q = first = v1;
+ v1 = v0, v0 = first;
+ break;
+ }
+ }
+ ss->prev.b[0] = v0;
+ ss->prev.b[1] = v1;
+ ss->prev.b[2] = v2;
+ ss->prev.b[3] = v3;
+ pr->ptr = p;
+ pw->ptr = q;
+ return status;
+}
+
+/* Stream template */
+const stream_template s_MTFD_template = {
+ &st_MTF_state, s_MTF_init, s_MTFD_process, 1, 1,
+ NULL, NULL, s_MTF_init
+};
diff --git a/pstoraster/smtf.h b/pstoraster/smtf.h
new file mode 100644
index 000000000..eed6a2db6
--- /dev/null
+++ b/pstoraster/smtf.h
@@ -0,0 +1,49 @@
+/* Copyright (C) 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of GNU Ghostscript.
+
+ GNU Ghostscript is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
+ to anyone for the consequences of using it or for whether it serves any
+ particular purpose or works at all, unless he says so in writing. Refer
+ to the GNU General Public License for full details.
+
+ Everyone is granted permission to copy, modify and redistribute GNU
+ Ghostscript, but only under the conditions described in the GNU General
+ Public License. A copy of this license is supposed to have been given
+ to you along with GNU Ghostscript so you can know your rights and
+ responsibilities. It should be in a file named COPYING. Among other
+ things, the copyright notice and this notice must be preserved on all
+ copies.
+
+ Aladdin Enterprises 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 scommon.h; strimpl.h if any templates are referenced */
+
+#ifndef smtf_INCLUDED
+# define smtf_INCLUDED
+
+/* MoveToFrontEncode/Decode */
+typedef struct stream_MTF_state_s {
+ stream_state_common;
+ /* The following change dynamically. */
+ union _p {
+ ulong l[256 / sizeof(long)];
+ byte b[256];
+ } prev;
+} stream_MTF_state;
+typedef stream_MTF_state stream_MTFE_state;
+typedef stream_MTF_state stream_MTFD_state;
+
+#define private_st_MTF_state() /* in sbwbs.c */\
+ gs_private_st_simple(st_MTF_state, stream_MTF_state,\
+ "MoveToFrontEncode/Decode state")
+extern const stream_template s_MTFE_template;
+extern const stream_template s_MTFD_template;
+
+#endif /* smtf_INCLUDED */
diff --git a/pstoraster/spcxd.c b/pstoraster/spcxd.c
new file mode 100644
index 000000000..4cb2a2f59
--- /dev/null
+++ b/pstoraster/spcxd.c
@@ -0,0 +1,75 @@
+/* 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$ */
+/* PCXDecode filter */
+#include "stdio_.h" /* includes std.h */
+#include "memory_.h"
+#include "strimpl.h"
+#include "spcxx.h"
+
+/* ------ PCXDecode ------ */
+
+/* Refill the buffer */
+private int
+s_PCXD_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last)
+{
+ register const byte *p = pr->ptr;
+ register byte *q = pw->ptr;
+ const byte *rlimit = pr->limit;
+ byte *wlimit = pw->limit;
+ int status = 0;
+
+ while (p < rlimit) {
+ int b = *++p;
+
+ if (b < 0xc0) {
+ if (q >= wlimit) {
+ --p;
+ status = 1;
+ break;
+ }
+ *++q = b;
+ } else if (p >= rlimit) {
+ --p;
+ break;
+ } else if ((b -= 0xc0) > wlimit - q) {
+ --p;
+ status = 1;
+ break;
+ } else {
+ memset(q + 1, *++p, b);
+ q += b;
+ }
+ }
+ pr->ptr = p;
+ pw->ptr = q;
+ return status;
+}
+
+/* Stream template */
+const stream_template s_PCXD_template = {
+ &st_stream_state, NULL, s_PCXD_process, 2, 63
+};
diff --git a/pstoraster/spcxx.h b/pstoraster/spcxx.h
new file mode 100644
index 000000000..cc156cf8e
--- /dev/null
+++ b/pstoraster/spcxx.h
@@ -0,0 +1,35 @@
+/* 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$ */
+/* Requires scommon.h; strimpl.h if any templates are referenced */
+
+#ifndef spcxx_INCLUDED
+# define spcxx_INCLUDED
+
+/* PCXDecode */
+/* (no state) */
+extern const stream_template s_PCXD_template;
+
+#endif /* spcxx_INCLUDED */
diff --git a/pstoraster/spdiff.c b/pstoraster/spdiff.c
new file mode 100644
index 000000000..53290596a
--- /dev/null
+++ b/pstoraster/spdiff.c
@@ -0,0 +1,334 @@
+/* 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$ */
+/* Pixel differencing filters */
+#include "stdio_.h" /* should be std.h, but needs NULL */
+#include "strimpl.h"
+#include "spdiffx.h"
+
+/* ------ PixelDifferenceEncode/Decode ------ */
+
+private_st_PDiff_state();
+
+/* Define values for case dispatch. */
+#define cBits1 0
+#define cBits2 4
+#define cBits4 8
+#define cBits8 12
+#define cEncode -1
+#define cDecode 15
+
+/* Set defaults */
+private void
+s_PDiff_set_defaults(stream_state * st)
+{
+ stream_PDiff_state *const ss = (stream_PDiff_state *) st;
+
+ s_PDiff_set_defaults_inline(ss);
+}
+
+/* Common (re)initialization. */
+private int
+s_PDiff_reinit(stream_state * st)
+{
+ stream_PDiff_state *const ss = (stream_PDiff_state *) st;
+
+ ss->row_left = 0;
+ return 0;
+}
+
+/* Initialize PixelDifferenceEncode filter. */
+private int
+s_PDiffE_init(stream_state * st)
+{
+ stream_PDiff_state *const ss = (stream_PDiff_state *) st;
+ long bits_per_row =
+ ss->Colors * ss->BitsPerComponent * (long)ss->Columns;
+ static const byte cb_values[] =
+ {0, cBits1, cBits2, 0, cBits4, 0, 0, 0, cBits8};
+
+ ss->row_count = (uint) ((bits_per_row + 7) >> 3);
+ ss->end_mask = (1 << (-bits_per_row & 7)) - 1;
+ ss->case_index =
+ cb_values[ss->BitsPerComponent] + ss->Colors + cEncode;
+ return s_PDiff_reinit(st);
+}
+
+/* Initialize PixelDifferenceDecode filter. */
+private int
+s_PDiffD_init(stream_state * st)
+{
+ stream_PDiff_state *const ss = (stream_PDiff_state *) st;
+
+ s_PDiffE_init(st);
+ ss->case_index += cDecode - cEncode;
+ return 0;
+}
+
+/* Process a buffer. Note that this handles both Encode and Decode. */
+private int
+s_PDiff_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last)
+{
+ stream_PDiff_state *const ss = (stream_PDiff_state *) st;
+ register const byte *p = pr->ptr;
+ register byte *q = pw->ptr;
+ int rcount, wcount;
+ register int count;
+ int status = 0;
+ register byte s0 = ss->s0;
+ register byte t;
+ byte save_last;
+ const byte end_mask = ss->end_mask;
+
+ row:if (ss->row_left == 0)
+ ss->row_left = ss->row_count,
+ s0 = ss->s1 = ss->s2 = ss->s3 = 0;
+ rcount = pr->limit - p;
+ wcount = pw->limit - q;
+ if (ss->row_left < rcount)
+ rcount = ss->row_left;
+ count = (wcount < rcount ? (status = 1, wcount) : rcount);
+ ss->row_left -= count;
+ if (ss->row_left == count)
+ save_last = p[count];
+
+ /*
+ * Encoding and decoding are fundamentally different.
+ * Encoding computes E[i] = D[i] - D[i-1];
+ * decoding computes D[i] = E[i] + D[i-1].
+ * Nevertheless, the loop structures are similar enough that
+ * we put the code for both functions in the same place.
+ */
+
+#define loopn(n, body)\
+ while ( count >= n ) p += n, q += n, body, count -= n
+
+ switch (ss->case_index) {
+
+ /* 1 bit per component */
+
+#define eloop1(ee)\
+ loopn(1, (t = *p, *q = ee, s0 = t))
+
+ case cEncode + cBits1 + 1:
+ eloop1(t ^ ((s0 << 7) | (t >> 1)));
+ case cEncode + cBits1 + 2:
+ eloop1(t ^ ((s0 << 6) | (t >> 2)));
+ case cEncode + cBits1 + 3:
+ eloop1(t ^ ((s0 << 5) | (t >> 3)));
+ case cEncode + cBits1 + 4:
+ eloop1(t ^ ((s0 << 4) | (t >> 4)));
+
+#define dloop1(te, de)\
+ loopn(1, (t = te, s0 = *q = de)); break
+
+ case cDecode + cBits1 + 1:
+ dloop1(*p ^ (s0 << 7),
+ (t ^= t >> 1, t ^= t >> 2, t ^ (t >> 4)));
+ case cDecode + cBits1 + 2:
+ dloop1(*p ^ (s0 << 6),
+ (t ^= (t >> 2), t ^ (t >> 4)));
+ case cDecode + cBits1 + 3:
+ dloop1(*p ^ (s0 << 5),
+ t ^ (t >> 3) ^ (t >> 6));
+ case cDecode + cBits1 + 4:
+ dloop1(*p ^ (s0 << 4),
+ t ^ (t >> 4));
+
+ /* 2 bits per component */
+
+#define add4x2(a, b) ( (((a) & (b) & 0x55) << 1) ^ (a) ^ (b) )
+#define sub4x2(a, b) ( ((~(a) & (b) & 0x55) << 1) ^ (a) ^ (b) )
+
+ case cEncode + cBits2 + 1:
+ eloop1((s0 = (s0 << 6) | (t >> 2), sub4x2(t, s0)));
+ case cEncode + cBits2 + 2:
+ eloop1((s0 = (s0 << 4) | (t >> 4), sub4x2(t, s0)));
+ case cEncode + cBits2 + 3:
+ eloop1((s0 = (s0 << 2) | (t >> 6), sub4x2(t, s0)));
+ case cEncode + cBits2 + 4:
+ eloop1(sub4x2(t, s0));
+
+ case cDecode + cBits2 + 1:
+ dloop1(*p + (s0 << 6),
+ (t = add4x2(t >> 2, t),
+ add4x2(t >> 4, t)));
+ case cDecode + cBits2 + 2:
+ dloop1(*p, (t = add4x2(t, s0 << 4),
+ add4x2(t >> 4, t)));
+ case cDecode + cBits2 + 3:
+ dloop1(*p, (t = add4x2(t, s0 << 2),
+ add4x2(t >> 6, t)));
+ case cDecode + cBits2 + 4:
+ dloop1(*p, add4x2(t, s0));
+
+#undef add4x2
+#undef sub4x2
+
+ /* 4 bits per component */
+
+#define add2x4(a, b) ( (((a) + (b)) & 0xf) + ((a) & 0xf0) + ((b) & 0xf0) )
+#define add2x4r4(a) ( (((a) + ((a) >> 4)) & 0xf) + ((a) & 0xf0) )
+#define sub2x4(a, b) ( (((a) - (b)) & 0xf) + ((a) & 0xf0) - ((b) & 0xf0) )
+#define sub2x4r4(a) ( (((a) - ((a) >> 4)) & 0xf) + ((a) & 0xf0) )
+
+ case cEncode + cBits4 + 1:
+ eloop1(((t - (s0 << 4)) & 0xf0) | ((t - (t >> 4)) & 0xf));
+ case cEncode + cBits4 + 2:
+ eloop1(sub2x4(t, s0));
+ case cEncode + cBits4 + 3:
+ {
+ register byte s1 = ss->s1;
+
+ loopn(1, (t = *p,
+ *q =
+ ((t - (s0 << 4)) & 0xf0) | ((t - (s1 >> 4)) & 0xf),
+ s0 = s1, s1 = t));
+ ss->s1 = s1;
+ } break;
+ case cEncode + cBits4 + 4:
+ {
+ register byte s1 = ss->s1;
+
+ loopn(2,
+ (t = p[-1], q[-1] = sub2x4(t, s0), s0 = t,
+ t = *p, *q = sub2x4(t, s1), s1 = t));
+ ss->s1 = s1;
+ } break;
+
+ case cDecode + cBits4 + 1:
+ dloop1(*p + (s0 << 4), add2x4r4(t));
+ case cDecode + cBits4 + 2:
+ dloop1(*p, add2x4(t, s0));
+ case cDecode + cBits4 + 3:
+ {
+ register byte s1 = ss->s1;
+
+ loopn(1, (t = (s0 << 4) + (s1 >> 4),
+ s0 = s1, s1 = *q = add2x4(*p, t)));
+ ss->s1 = s1;
+ } break;
+ case cDecode + cBits4 + 4:
+ {
+ register byte s1 = ss->s1;
+
+ loopn(2,
+ (t = p[-1], s0 = q[-1] = add2x4(s0, t),
+ t = *p, s1 = *q = add2x4(s1, t)));
+ ss->s1 = s1;
+ } break;
+
+#undef add2x4
+#undef add2x4r4
+#undef sub2x4
+#undef sub2x4r4
+
+ /* 8 bits per component */
+
+#define encode8(s, d) (q[d] = p[d] - s, s = p[d])
+#define decode8(s, d) s = q[d] = s + p[d]
+
+ case cEncode + cBits8 + 1:
+ loopn(1, encode8(s0, 0));
+ break;
+ case cDecode + cBits8 + 1:
+ loopn(1, decode8(s0, 0));
+ break;
+ case cEncode + cBits8 + 2:
+ {
+ register byte s1 = ss->s1;
+
+ loopn(2, (encode8(s0, -1), encode8(s1, 0)));
+ ss->s1 = s1;
+ } break;
+ case cDecode + cBits8 + 2:
+ {
+ register byte s1 = ss->s1;
+
+ loopn(2, (decode8(s0, -1), decode8(s1, 0)));
+ ss->s1 = s1;
+ } break;
+ case cEncode + cBits8 + 3:
+ {
+ register byte s1 = ss->s1, s2 = ss->s2;
+
+ loopn(3, (encode8(s0, -2), encode8(s1, -1),
+ encode8(s2, 0)));
+ ss->s1 = s1, ss->s2 = s2;
+ } break;
+ case cDecode + cBits8 + 3:
+ {
+ register byte s1 = ss->s1, s2 = ss->s2;
+
+ loopn(3, (decode8(s0, -2), decode8(s1, -1),
+ decode8(s2, 0)));
+ ss->s1 = s1, ss->s2 = s2;
+ } break;
+ case cEncode + cBits8 + 4:
+ {
+ register byte s1 = ss->s1, s2 = ss->s2, s3 = ss->s3;
+
+ loopn(4, (encode8(s0, -3), encode8(s1, -2),
+ encode8(s2, -1), encode8(s3, 0)));
+ ss->s1 = s1, ss->s2 = s2, ss->s3 = s3;
+ } break;
+ case cDecode + cBits8 + 4:
+ {
+ register byte s1 = ss->s1, s2 = ss->s2, s3 = ss->s3;
+
+ loopn(4, (decode8(s0, -3), decode8(s1, -2),
+ decode8(s2, -1), decode8(s3, 0)));
+ ss->s1 = s1, ss->s2 = s2, ss->s3 = s3;
+ } break;
+
+#undef encode8
+#undef decode8
+
+ }
+#undef loopn
+#undef dloop1
+ ss->row_left += count; /* leftover bytes are possible */
+ if (ss->row_left == 0) {
+ if (end_mask != 0)
+ *q = (*q & ~end_mask) | (save_last & end_mask);
+ if (p < pr->limit && q < pw->limit)
+ goto row;
+ }
+ ss->s0 = s0;
+ pr->ptr = p;
+ pw->ptr = q;
+ return status;
+}
+
+/* Stream templates */
+const stream_template s_PDiffE_template =
+{&st_PDiff_state, s_PDiffE_init, s_PDiff_process, 1, 1, NULL,
+ s_PDiff_set_defaults, s_PDiff_reinit
+};
+const stream_template s_PDiffD_template =
+{&st_PDiff_state, s_PDiffD_init, s_PDiff_process, 1, 1, NULL,
+ s_PDiff_set_defaults, s_PDiff_reinit
+};
diff --git a/pstoraster/spdiffx.h b/pstoraster/spdiffx.h
new file mode 100644
index 000000000..1a4e1da96
--- /dev/null
+++ b/pstoraster/spdiffx.h
@@ -0,0 +1,55 @@
+/* Copyright (C) 1994, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of GNU Ghostscript.
+
+ GNU Ghostscript is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
+ to anyone for the consequences of using it or for whether it serves any
+ particular purpose or works at all, unless he says so in writing. Refer
+ to the GNU General Public License for full details.
+
+ Everyone is granted permission to copy, modify and redistribute GNU
+ Ghostscript, but only under the conditions described in the GNU General
+ Public License. A copy of this license is supposed to have been given
+ to you along with GNU Ghostscript so you can know your rights and
+ responsibilities. It should be in a file named COPYING. Among other
+ things, the copyright notice and this notice must be preserved on all
+ copies.
+
+ Aladdin Enterprises 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 strimpl.h */
+
+#ifndef spdiffx_INCLUDED
+# define spdiffx_INCLUDED
+
+/* PixelDifferenceDecode / PixelDifferenceEncode */
+typedef struct stream_PDiff_state_s {
+ stream_state_common;
+ /* The client sets the following before initialization. */
+ int Colors; /* # of colors, 1..4 */
+ int BitsPerComponent; /* 1, 2, 4, 8 */
+ int Columns;
+ /* The init procedure computes the following. */
+ uint row_count; /* # of bytes per row */
+ byte end_mask; /* mask for left-over bits in last byte */
+ int case_index; /* switch index for case dispatch */
+ /* The following are updated dynamically. */
+ uint row_left; /* # of bytes left in row */
+ byte s0, s1, s2, s3; /* previous sample */
+} stream_PDiff_state;
+
+#define private_st_PDiff_state() /* in spdiff.c */\
+ gs_private_st_simple(st_PDiff_state, stream_PDiff_state,\
+ "PixelDifferenceEncode/Decode state")
+#define s_PDiff_set_defaults_inline(ss)\
+ ((ss)->Colors = 1, (ss)->BitsPerComponent = 8, (ss)->Columns = 1)
+extern const stream_template s_PDiffD_template;
+extern const stream_template s_PDiffE_template;
+
+#endif /* spdiffx_INCLUDED */
diff --git a/pstoraster/spngp.c b/pstoraster/spngp.c
new file mode 100644
index 000000000..cc270a6bb
--- /dev/null
+++ b/pstoraster/spngp.c
@@ -0,0 +1,364 @@
+/* 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$ */
+/* PNG pixel prediction filters */
+#include "memory_.h"
+#include "strimpl.h"
+#include "spngpx.h"
+
+/* ------ PNGPredictorEncode/Decode ------ */
+
+private_st_PNGP_state();
+
+/* Define values for case dispatch. */
+#define cNone 10
+#define cSub 11
+#define cUp 12
+#define cAverage 13
+#define cPaeth 14
+#define cOptimum 15
+#define cEncode -10
+#define cDecode -4
+private const byte pngp_case_needs_prev[] =
+{0, 0, 1, 1, 1, 1};
+
+/* Set defaults */
+private void
+s_PNGP_set_defaults(stream_state * st)
+{
+ stream_PNGP_state *const ss = (stream_PNGP_state *) st;
+
+ s_PNGP_set_defaults_inline(ss);
+}
+
+/* Common (re)initialization. */
+private int
+s_PNGP_reinit(stream_state * st)
+{
+ stream_PNGP_state *const ss = (stream_PNGP_state *) st;
+
+ if (ss->prev_row != 0)
+ memset(ss->prev_row + ss->bpp, 0, ss->row_count);
+ ss->row_left = 0;
+ return 0;
+}
+
+/* Initialize PNGPredictorEncode filter. */
+private int
+s_pngp_init(stream_state * st, bool need_prev)
+{
+ stream_PNGP_state *const ss = (stream_PNGP_state *) st;
+ int bits_per_pixel = ss->Colors * ss->BitsPerComponent;
+ long bits_per_row = (long)bits_per_pixel * ss->Columns;
+ byte *prev_row = 0;
+
+#if arch_sizeof_long > arch_sizeof_int
+ if (bits_per_row > max_uint * 7L)
+ return ERRC;
+/****** WRONG ******/
+#endif
+ ss->row_count = (uint) ((bits_per_row + 7) >> 3);
+ ss->end_mask = (1 << (-bits_per_row & 7)) - 1;
+ ss->bpp = (bits_per_pixel + 7) >> 3;
+ if (need_prev) {
+ prev_row = gs_alloc_bytes(st->memory, ss->bpp + ss->row_count,
+ "PNGPredictor prev row");
+ if (prev_row == 0)
+ return ERRC;
+/****** WRONG ******/
+ memset(prev_row, 0, ss->bpp);
+ }
+ ss->prev_row = prev_row;
+ /* case_index is only preset for encoding */
+ return s_PNGP_reinit(st);
+}
+
+/* Initialize PNGPredictorEncode filter. */
+private int
+s_PNGPE_init(stream_state * st)
+{
+ stream_PNGP_state *const ss = (stream_PNGP_state *) st;
+
+ return s_pngp_init(st, pngp_case_needs_prev[ss->Predictor - cNone]);
+}
+
+/* Initialize PNGPredictorDecode filter. */
+private int
+s_PNGPD_init(stream_state * st)
+{
+ return s_pngp_init(st, true);
+}
+
+/*
+ * Process a partial buffer. We pass in current and previous pointers
+ * to both the current and preceding scan line. Note that dprev is
+ * p - bpp for encoding, q - bpp for decoding; similarly, the 'up' row
+ * is the raw data for encoding, the filtered data for decoding.
+ * Note also that the case_index cannot be cOptimum.
+ */
+private int
+paeth_predictor(int a, int b, int c)
+{
+#undef any_abs /* just in case */
+#define any_abs(u) ((u) < 0 ? -(u) : (u))
+ int px = a + b - c;
+ int pa = any_abs(px - a), pb = any_abs(px - b), pc = any_abs(px - c);
+
+ return (pa <= pb && pa <= pc ? a : pb <= pc ? b : c);
+#undef any_abs
+}
+private void
+s_pngp_process(stream_state * st, stream_cursor_write * pw,
+ const byte * dprev, stream_cursor_read * pr,
+ const byte * upprev, const byte * up, uint count)
+{
+ stream_PNGP_state *const ss = (stream_PNGP_state *) st;
+ byte *q = pw->ptr + 1;
+ const byte *p = pr->ptr + 1;
+
+ pr->ptr += count;
+ pw->ptr += count;
+ ss->row_left -= count;
+ switch (ss->case_index) {
+ case cEncode + cNone:
+ case cDecode + cNone:
+ memcpy(q, p, count);
+ break;
+ case cEncode + cSub:
+ for (; count; ++q, ++dprev, ++p, --count)
+ *q = (byte) (*p - *dprev);
+ break;
+ case cDecode + cSub:
+ for (; count; ++q, ++dprev, ++p, --count)
+ *q = (byte) (*p + *dprev);
+ break;
+ case cEncode + cUp:
+ for (; count; ++q, ++up, ++p, --count)
+ *q = (byte) (*p - *up);
+ break;
+ case cDecode + cUp:
+ for (; count; ++q, ++up, ++p, --count)
+ *q = (byte) (*p + *up);
+ break;
+ case cEncode + cAverage:
+ for (; count; ++q, ++dprev, ++up, ++p, --count)
+ *q = (byte) (*p - arith_rshift_1((int)*dprev + (int)*up));
+ break;
+ case cDecode + cAverage:
+ for (; count; ++q, ++dprev, ++up, ++p, --count)
+ *q = (byte) (*p + arith_rshift_1((int)*dprev + (int)*up));
+ break;
+ case cEncode + cPaeth:
+ for (; count; ++q, ++dprev, ++up, ++upprev, ++p, --count)
+ *q = (byte) (*p - paeth_predictor(*dprev, *up, *upprev));
+ break;
+ case cDecode + cPaeth:
+ for (; count; ++q, ++dprev, ++up, ++upprev, ++p, --count)
+ *q = (byte) (*p + paeth_predictor(*dprev, *up, *upprev));
+ break;
+ }
+}
+
+/* Calculate the number of bytes for the next processing step, */
+/* the min of (input data, output data, remaining row length). */
+private uint
+s_pngp_count(const stream_state * st_const, const stream_cursor_read * pr,
+ const stream_cursor_write * pw)
+{
+ const stream_PNGP_state *const ss_const =
+ (const stream_PNGP_state *)st_const;
+ uint rcount = pr->limit - pr->ptr;
+ uint wcount = pw->limit - pw->ptr;
+ uint row_left = ss_const->row_left;
+
+ if (rcount < row_left)
+ row_left = rcount;
+ if (wcount < row_left)
+ row_left = wcount;
+ return row_left;
+}
+
+/*
+ * Encode a buffer. Let N = ss->row_count, P = N - ss->row_left,
+ * and B = ss->bpp. Consider that bytes [-B .. -1] of every row are zero.
+ * Then:
+ * prev_row[0 .. P - 1] contain bytes -B .. P - B - 1
+ * of the current input row.
+ * ss->prev[0 .. B - 1] contain bytes P - B .. P - 1
+ * of the current input row.
+ * prev_row[P .. N + B - 1] contain bytes P - B .. N - 1
+ * of the previous input row.
+ */
+private int
+optimum_predictor(const stream_state * st, const stream_cursor_read * pr)
+{
+ return cSub;
+}
+private int
+s_PNGPE_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last)
+{
+ stream_PNGP_state *const ss = (stream_PNGP_state *) st;
+ int bpp = ss->bpp;
+ int code = 0;
+
+ while (pr->ptr < pr->limit) {
+ uint count;
+
+ if (ss->row_left == 0) { /* Beginning of row, write algorithm byte. */
+ int predictor;
+
+ if (pw->ptr >= pw->limit) {
+ code = 1;
+ break;
+ }
+ predictor =
+ (ss->Predictor == cOptimum ?
+ optimum_predictor(st, pr) :
+ ss->Predictor);
+ *++(pw->ptr) = (byte) predictor - cNone;
+ ss->case_index = predictor + cEncode;
+ ss->row_left = ss->row_count;
+ memset(ss->prev, 0, bpp);
+ continue;
+ }
+ count = s_pngp_count(st, pr, pw);
+ if (count == 0) { /* We know we have input, so output must be full. */
+ code = 1;
+ break;
+ } {
+ byte *up = ss->prev_row + bpp + ss->row_count - ss->row_left;
+ uint n = min(count, bpp);
+
+ /* Process bytes whose predecessors are in prev. */
+ s_pngp_process(st, pw, ss->prev, pr, up - bpp, up, n);
+ if (ss->prev_row)
+ memcpy(up - bpp, ss->prev, n);
+ if (n < bpp) { /* We didn't have enough data to use up all of prev. */
+ /* Shift more data into prev and exit. */
+ int prev_left = bpp - n;
+
+ memmove(ss->prev, ss->prev + n, prev_left);
+ memcpy(ss->prev + prev_left, pr->ptr - (n - 1), n);
+ break;
+ }
+ /* Process bytes whose predecessors are in the input. */
+ /* We know we have at least bpp input and output bytes, */
+ /* and that n = bpp. */
+ count -= bpp;
+ s_pngp_process(st, pw, pr->ptr - (bpp - 1), pr,
+ up, up + bpp, count);
+ memcpy(ss->prev, pr->ptr - (bpp - 1), bpp);
+ if (ss->prev_row) {
+ memcpy(up, pr->ptr - (bpp + count - 1), count);
+ if (ss->row_left == 0)
+ memcpy(up + count, ss->prev, bpp);
+ }
+ }
+ }
+ return code;
+}
+
+/*
+ * Decode a buffer. Let N = ss->row_count, P = N - ss->row_left,
+ * and B = ss->bpp. Consider that bytes [-B .. -1] of every row are zero.
+ * Then:
+ * prev_row[0 .. P - 1] contain bytes -B .. P - B - 1
+ * of the current output row.
+ * ss->prev[0 .. B - 1] contain bytes P - B .. P - 1
+ * of the current output row.
+ * prev_row[P .. N + B - 1] contain bytes P - B .. N - 1
+ * of the previous output row.
+ */
+private int
+s_PNGPD_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last)
+{
+ stream_PNGP_state *const ss = (stream_PNGP_state *) st;
+ int bpp = ss->bpp;
+ int code = 0;
+
+ while (pr->ptr < pr->limit) {
+ uint count;
+
+ if (ss->row_left == 0) { /* Beginning of row, read algorithm byte. */
+ int predictor = pr->ptr[1];
+
+ if (predictor >= cOptimum - cNone) {
+ code = ERRC;
+ break;
+ }
+ pr->ptr++;
+ ss->case_index = predictor + cNone + cDecode;
+ ss->row_left = ss->row_count;
+ memset(ss->prev, 0, bpp);
+ continue;
+ }
+ count = s_pngp_count(st, pr, pw);
+ if (count == 0) { /* We know we have input, so output must be full. */
+ code = 1;
+ break;
+ } {
+ byte *up = ss->prev_row + bpp + ss->row_count - ss->row_left;
+ uint n = min(count, bpp);
+
+ /* Process bytes whose predecessors are in prev. */
+ s_pngp_process(st, pw, ss->prev, pr, up - bpp, up, n);
+ if (ss->prev_row)
+ memcpy(up - bpp, ss->prev, n);
+ if (n < bpp) { /* We didn't have enough data to use up all of prev. */
+ /* Shift more data into prev and exit. */
+ int prev_left = bpp - n;
+
+ memmove(ss->prev, ss->prev + n, prev_left);
+ memcpy(ss->prev + prev_left, pw->ptr - (n - 1), n);
+ break;
+ }
+ /* Process bytes whose predecessors are in the output. */
+ /* We know we have at least bpp input and output bytes, */
+ /* and that n = bpp. */
+ count -= bpp;
+ s_pngp_process(st, pw, pw->ptr - (bpp - 1), pr,
+ up, up + bpp, count);
+ memcpy(ss->prev, pw->ptr - (bpp - 1), bpp);
+ if (ss->prev_row) {
+ memcpy(up, pw->ptr - (bpp + count - 1), count);
+ if (ss->row_left == 0)
+ memcpy(up + count, ss->prev, bpp);
+ }
+ }
+ }
+ return code;
+}
+
+/* Stream templates */
+const stream_template s_PNGPE_template =
+{&st_PNGP_state, s_PNGPE_init, s_PNGPE_process, 1, 1, 0 /*NULL */ ,
+ s_PNGP_set_defaults, s_PNGP_reinit
+};
+const stream_template s_PNGPD_template =
+{&st_PNGP_state, s_PNGPD_init, s_PNGPD_process, 1, 1, 0 /*NULL */ ,
+ s_PNGP_set_defaults, s_PNGP_reinit
+};
diff --git a/pstoraster/spngpx.h b/pstoraster/spngpx.h
new file mode 100644
index 000000000..303341ad0
--- /dev/null
+++ b/pstoraster/spngpx.h
@@ -0,0 +1,61 @@
+/* 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$ */
+/* Requires strimpl.h */
+
+#ifndef spngpx_INCLUDED
+# define spngpx_INCLUDED
+
+/* PNGPredictorDecode / PNGPredictorEncode */
+typedef struct stream_PNGP_state_s {
+ stream_state_common;
+ /* The client sets the following before initialization. */
+ int Colors; /* # of colors, 1..16 */
+ int BitsPerComponent; /* 1, 2, 4, 8, 16 */
+ uint Columns; /* >0 */
+ int Predictor; /* 10-15, only relevant for Encode */
+ /* The init procedure computes the following. */
+ uint row_count; /* # of bytes per row */
+ byte end_mask; /* mask for left-over bits in last byte */
+ int bpp; /* bytes per pixel */
+ byte *prev_row; /* previous row */
+ int case_index; /* switch index for case dispatch, */
+ /* set dynamically when decoding */
+ /* The following are updated dynamically. */
+ long row_left; /* # of bytes left in row */
+ byte prev[32]; /* previous samples */
+} stream_PNGP_state;
+
+#define private_st_PNGP_state() /* in sPNGP.c */\
+ gs_private_st_ptrs1(st_PNGP_state, stream_PNGP_state,\
+ "PNGPredictorEncode/Decode state", pngp_enum_ptrs, pngp_reloc_ptrs,\
+ prev_row)
+#define s_PNGP_set_defaults_inline(ss)\
+ ((ss)->Colors = 1, (ss)->BitsPerComponent = 8, (ss)->Columns = 1,\
+ (ss)->Predictor = 15)
+extern const stream_template s_PNGPD_template;
+extern const stream_template s_PNGPE_template;
+
+#endif /* spngpx_INCLUDED */
diff --git a/pstoraster/srld.c b/pstoraster/srld.c
new file mode 100644
index 000000000..adacef808
--- /dev/null
+++ b/pstoraster/srld.c
@@ -0,0 +1,133 @@
+/* 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$ */
+/* RunLengthDecode filter */
+#include "stdio_.h" /* includes std.h */
+#include "memory_.h"
+#include "strimpl.h"
+#include "srlx.h"
+
+/* ------ RunLengthDecode ------ */
+
+private_st_RLD_state();
+
+/* Set defaults */
+private void
+s_RLD_set_defaults(stream_state * st)
+{
+ stream_RLD_state *const ss = (stream_RLD_state *) st;
+
+ s_RLD_set_defaults_inline(ss);
+}
+
+/* Initialize */
+private int
+s_RLD_init(stream_state * st)
+{
+ stream_RLD_state *const ss = (stream_RLD_state *) st;
+
+ return s_RLD_init_inline(ss);
+}
+
+/* Refill the buffer */
+private int
+s_RLD_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last)
+{
+ stream_RLD_state *const ss = (stream_RLD_state *) st;
+ register const byte *p = pr->ptr;
+ register byte *q = pw->ptr;
+ const byte *rlimit = pr->limit;
+ byte *wlimit = pw->limit;
+ int left;
+ int status = 0;
+
+top:
+ if ((left = ss->copy_left) > 0) {
+ /*
+ * We suspended because the output buffer was full:;
+ * try again now.
+ */
+ uint avail = wlimit - q;
+ int copy_status = 1;
+
+ if (left > avail)
+ left = avail;
+ if (ss->copy_data >= 0)
+ memset(q + 1, ss->copy_data, left);
+ else {
+ avail = rlimit - p;
+ if (left >= avail) {
+ copy_status = 0;
+ left = avail;
+ }
+ memcpy(q + 1, p + 1, left);
+ p += left;
+ }
+ q += left;
+ if ((ss->copy_left -= left) > 0) {
+ status = copy_status;
+ goto x;
+ }
+ }
+ while (p < rlimit) {
+ int b = *++p;
+
+ if (b < 128) {
+ if (++b > rlimit - p || b > wlimit - q) {
+ ss->copy_left = b;
+ ss->copy_data = -1;
+ goto top;
+ }
+ memcpy(q + 1, p + 1, b);
+ p += b;
+ q += b;
+ } else if (b == 128) { /* end of data */
+ if (ss->EndOfData) {
+ status = EOFC;
+ break;
+ }
+ } else if (p == rlimit) {
+ p--;
+ break;
+ } else if ((b = 257 - b) > wlimit - q) {
+ ss->copy_left = b;
+ ss->copy_data = *++p;
+ goto top;
+ } else {
+ memset(q + 1, *++p, b);
+ q += b;
+ }
+ }
+x: pr->ptr = p;
+ pw->ptr = q;
+ return status;
+}
+
+/* Stream template */
+const stream_template s_RLD_template = {
+ &st_RLD_state, s_RLD_init, s_RLD_process, 1, 1, NULL,
+ s_RLD_set_defaults
+};
diff --git a/pstoraster/srle.c b/pstoraster/srle.c
new file mode 100644
index 000000000..58476e091
--- /dev/null
+++ b/pstoraster/srle.c
@@ -0,0 +1,203 @@
+/* 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$ */
+/* RunLengthEncode filter */
+#include "stdio_.h" /* includes std.h */
+#include "memory_.h"
+#include "strimpl.h"
+#include "srlx.h"
+
+/* ------ RunLengthEncode ------ */
+
+private_st_RLE_state();
+
+/* Set defaults */
+private void
+s_RLE_set_defaults(stream_state * st)
+{
+ stream_RLE_state *const ss = (stream_RLE_state *) st;
+
+ s_RLE_set_defaults_inline(ss);
+}
+
+/* Initialize */
+private int
+s_RLE_init(stream_state * st)
+{
+ stream_RLE_state *const ss = (stream_RLE_state *) st;
+
+ return s_RLE_init_inline(ss);
+}
+
+/* Process a buffer */
+private int
+s_RLE_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last)
+{
+ stream_RLE_state *const ss = (stream_RLE_state *) st;
+ register const byte *p = pr->ptr;
+ register byte *q = pw->ptr;
+ const byte *rlimit = pr->limit;
+ byte *wlimit = pw->limit;
+ int status = 0;
+ ulong rleft = ss->record_left;
+
+ /*
+ * We thought that the Genoa CET demands that the output from this
+ * filter be not just legal, but optimal, so we went to the trouble
+ * of ensuring this. It turned out that this wasn't actually
+ * necessary, but we didn't want to change the code back.
+ *
+ * For optimal output, we can't just break runs at buffer
+ * boundaries: unless we hit a record boundary or the end of the
+ * input, we have to look ahead far enough to know that we aren't
+ * breaking a run prematurely.
+ */
+
+ /* Check for leftover output. */
+copy:
+ if (ss->copy_left) {
+ uint rcount = rlimit - p;
+ uint wcount = wlimit - q;
+ uint count = ss->copy_left;
+
+ if (rcount < count)
+ count = rcount;
+ if (wcount < count)
+ count = wcount;
+ if (rleft < count)
+ count = rleft;
+ memcpy(q + 1, p + 1, count);
+ pr->ptr = p += count;
+ pw->ptr = q += count;
+ if ((ss->record_left = rleft -= count) == 0)
+ ss->record_left = rleft = ss->record_size;
+ if ((ss->copy_left -= count) != 0)
+ return (rcount == 0 ? 0 : 1);
+ }
+ while (p < rlimit) {
+ const byte *beg = p;
+ const byte *p1;
+ uint count = rlimit - p;
+ bool end = last;
+ byte next;
+
+ if (count > rleft)
+ count = rleft, end = true;
+ if (count > 128)
+ count = 128, end = true;
+ p1 = p + count - 1;
+ if (count < 3) {
+ if (!end || count == 0)
+ break; /* can't look ahead far enough */
+ if (count == 1) {
+ if (wlimit - q < 2) {
+ status = 1;
+ break;
+ }
+ *++q = 0;
+ } else { /* count == 2 */
+ if (p[1] == p[2]) {
+ if (wlimit - q < 2) {
+ status = 1;
+ break;
+ }
+ *++q = 255;
+ } else {
+ if (wlimit - q < 3) {
+ status = 1;
+ break;
+ }
+ *++q = 1;
+ *++q = p[1];
+ }
+ }
+ *++q = p1[1];
+ p = p1 + 1;
+ } else if ((next = p[1]) == p[2] && next == p[3]) {
+ if (wlimit - q < 2) {
+ status = 1;
+ break;
+ }
+ /* Recognize leading repeated byte */
+ do {
+ p++;
+ }
+ while (p < p1 && p[2] == next);
+ if (p == p1 && !end) {
+ p = beg; /* need to look ahead further */
+ break;
+ }
+ p++;
+ *++q = (byte) (257 - (p - beg));
+ *++q = next;
+ } else {
+ p1--;
+ while (p < p1 && (p[2] != p[1] || p[3] != p[1]))
+ p++;
+ if (p == p1) {
+ if (!end) {
+ p = beg; /* need to look ahead further */
+ break;
+ }
+ p += 2;
+ }
+ count = p - beg;
+ if (wlimit - q < count + 1) {
+ p = beg;
+ if (q >= wlimit) {
+ status = 1;
+ break;
+ }
+ /* Copy some now and some later. */
+ *++q = count - 1;
+ ss->copy_left = count;
+ goto copy;
+ }
+ *++q = count - 1;
+ memcpy(q + 1, beg + 1, count);
+ q += count;
+ }
+ rleft -= p - beg;
+ if (rleft == 0)
+ rleft = ss->record_size;
+ }
+ if (last && status == 0 && ss->EndOfData) {
+ if (q < wlimit)
+ *++q = 128;
+ else
+ status = 1;
+ }
+ pr->ptr = p;
+ pw->ptr = q;
+ ss->record_left = rleft;
+ return status;
+}
+
+/* Stream template */
+const stream_template s_RLE_template = {
+ &st_RLE_state, s_RLE_init, s_RLE_process, 129, 2, NULL,
+ s_RLE_set_defaults, s_RLE_init
+};
diff --git a/pstoraster/srlx.h b/pstoraster/srlx.h
new file mode 100644
index 000000000..eaf89563a
--- /dev/null
+++ b/pstoraster/srlx.h
@@ -0,0 +1,77 @@
+/* Copyright (C) 1994, 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$ */
+/* Requires scommon.h; strimpl.h if any templates are referenced */
+
+#ifndef srlx_INCLUDED
+# define srlx_INCLUDED
+
+/* Common state */
+#define stream_RL_state_common\
+ stream_state_common;\
+ bool EndOfData /* true if 128 = EOD */
+
+/* RunLengthEncode */
+typedef struct stream_RLE_state_s {
+ stream_RL_state_common;
+ /* The following parameters are set by the client. */
+ ulong record_size;
+ /* The following change dynamically. */
+ ulong record_left; /* bytes left in current record */
+ int copy_left; /* # of bytes waiting to be copied */
+} stream_RLE_state;
+
+#define private_st_RLE_state() /* in srle.c */\
+ gs_private_st_simple(st_RLE_state, stream_RLE_state, "RunLengthEncode state")
+/* We define the initialization procedure here, so that clients */
+/* can avoid a procedure call. */
+#define s_RLE_set_defaults_inline(ss)\
+ ((ss)->EndOfData = true, (ss)->record_size = 0)
+#define s_RLE_init_inline(ss)\
+ ((ss)->record_left =\
+ ((ss)->record_size == 0 ? ((ss)->record_size = max_uint) :\
+ (ss)->record_size),\
+ (ss)->copy_left = 0)
+extern const stream_template s_RLE_template;
+
+/* RunLengthDecode */
+typedef struct stream_RLD_state_s {
+ stream_RL_state_common;
+ /* The following change dynamically. */
+ int copy_left; /* # of output bytes waiting to be produced */
+ int copy_data; /* -1 if copying, repeated byte if repeating */
+} stream_RLD_state;
+
+#define private_st_RLD_state() /* in srld.c */\
+ gs_private_st_simple(st_RLD_state, stream_RLD_state, "RunLengthDecode state")
+/* We define the initialization procedure here, so that clients */
+/* can avoid a procedure call. */
+#define s_RLD_set_defaults_inline(ss)\
+ ((ss)->EndOfData = true)
+#define s_RLD_init_inline(ss)\
+ ((ss)->copy_left = 0)
+extern const stream_template s_RLD_template;
+
+#endif /* srlx_INCLUDED */
diff --git a/pstoraster/sstring.c b/pstoraster/sstring.c
new file mode 100644
index 000000000..f08d5757e
--- /dev/null
+++ b/pstoraster/sstring.c
@@ -0,0 +1,464 @@
+/* Copyright (C) 1993, 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$ */
+/* String and hexstring streams (filters) */
+#include "stdio_.h" /* includes std.h */
+#include "memory_.h"
+#include "string_.h"
+#include "strimpl.h"
+#include "sstring.h"
+#include "scanchar.h"
+
+/* ------ ASCIIHexEncode ------ */
+
+private_st_AXE_state();
+
+/* Initialize the state */
+private int
+s_AXE_init(stream_state * st)
+{
+ stream_AXE_state *const ss = (stream_AXE_state *) st;
+
+ return s_AXE_init_inline(ss);
+}
+
+/* Process a buffer */
+private int
+s_AXE_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last)
+{
+ stream_AXE_state *const ss = (stream_AXE_state *) st;
+ const byte *p = pr->ptr;
+ byte *q = pw->ptr;
+ int rcount = pr->limit - p;
+ int wcount = pw->limit - q;
+ int count;
+ int pos = ss->count;
+ const char *hex_digits = "0123456789abcdef";
+ int status = 0;
+
+ if (last)
+ wcount--; /* leave room for '>' */
+ wcount -= (wcount + 64) / 65; /* leave room for \n */
+ wcount >>= 1; /* 2 chars per input byte */
+ count = (wcount < rcount ? (status = 1, wcount) : rcount);
+ while (--count >= 0) {
+ *++q = hex_digits[*++p >> 4];
+ *++q = hex_digits[*p & 0xf];
+ if (!(++pos & 31) && (count != 0 || !last))
+ *++q = '\n';
+ }
+ if (last && status == 0)
+ *++q = '>';
+ pr->ptr = p;
+ pw->ptr = q;
+ ss->count = pos & 31;
+ return status;
+}
+
+/* Stream template */
+const stream_template s_AXE_template =
+{&st_AXE_state, s_AXE_init, s_AXE_process, 1, 3
+};
+
+/* ------ ASCIIHexDecode ------ */
+
+private_st_AXD_state();
+
+/* Initialize the state */
+private int
+s_AXD_init(stream_state * st)
+{
+ stream_AXD_state *const ss = (stream_AXD_state *) st;
+
+ return s_AXD_init_inline(ss);
+}
+
+/* Process a buffer */
+private int
+s_AXD_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last)
+{
+ stream_AXD_state *const ss = (stream_AXD_state *) st;
+ int code = s_hex_process(pr, pw, &ss->odd, hex_ignore_whitespace);
+
+ switch (code) {
+ case 0:
+ if (ss->odd >= 0 && last) {
+ if (pw->ptr == pw->limit)
+ return 1;
+ *++(pw->ptr) = ss->odd << 4;
+ }
+ /* falls through */
+ case 1:
+ /* We still need to read ahead and check for EOD. */
+ for (; pr->ptr < pr->limit; pr->ptr++)
+ if (scan_char_decoder[pr->ptr[1]] != ctype_space) {
+ if (pr->ptr[1] == '>') {
+ pr->ptr++;
+ goto eod;
+ }
+ return 1;
+ }
+ return 0; /* still need to scan ahead */
+ default:
+ return code;
+ case ERRC:
+ ;
+ }
+ /*
+ * Check for EOD. ERRC implies at least one more character
+ * was read; we must unread it, since the caller might have
+ * invoked the filter with exactly the right count to read all
+ * the available data, and we might be reading past the end.
+ */
+ if (*pr->ptr != '>') { /* EOD */
+ --(pr->ptr);
+ return ERRC;
+ }
+ eod:if (ss->odd >= 0) {
+ if (pw->ptr == pw->limit)
+ return 1;
+ *++(pw->ptr) = ss->odd << 4;
+ }
+ return EOFC;
+}
+
+/* Stream template */
+const stream_template s_AXD_template =
+{&st_AXD_state, s_AXD_init, s_AXD_process, 2, 1
+};
+
+/* ------ PSStringEncode ------ */
+
+/* Process a buffer */
+private int
+s_PSSE_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last)
+{
+ const byte *p = pr->ptr;
+ const byte *rlimit = pr->limit;
+ byte *q = pw->ptr;
+ byte *wlimit = pw->limit;
+ int status = 0;
+
+ /* This doesn't have to be very efficient. */
+ while (p < rlimit) {
+ int c = *++p;
+
+ if (c < 32 || c >= 127) {
+ const char *pesc;
+ const char *const esc = "\n\r\t\b\f";
+
+ if (c < 32 && c != 0 && (pesc = strchr(esc, c)) != 0) {
+ if (wlimit - q < 2) {
+ --p;
+ status = 1;
+ break;
+ }
+ *++q = '\\';
+ *++q = "nrtbf"[pesc - esc];
+ continue;
+ }
+ if (wlimit - q < 4) {
+ --p;
+ status = 1;
+ break;
+ }
+ q[1] = '\\';
+ q[2] = (c >> 6) + '0';
+ q[3] = ((c >> 3) & 7) + '0';
+ q[4] = (c & 7) + '0';
+ q += 4;
+ continue;
+ } else if (c == '(' || c == ')' || c == '\\') {
+ if (wlimit - q < 2) {
+ --p;
+ status = 1;
+ break;
+ }
+ *++q = '\\';
+ } else {
+ if (q == wlimit) {
+ --p;
+ status = 1;
+ break;
+ }
+ }
+ *++q = c;
+ }
+ if (last && status == 0) {
+ if (q == wlimit)
+ status = 1;
+ else
+ *++q = ')';
+ }
+ pr->ptr = p;
+ pw->ptr = q;
+ return status;
+}
+
+/* Stream template */
+const stream_template s_PSSE_template =
+{&st_stream_state, NULL, s_PSSE_process, 1, 4
+};
+
+/* ------ PSStringDecode ------ */
+
+private_st_PSSD_state();
+
+/* Initialize the state */
+private int
+s_PSSD_init(stream_state * st)
+{
+ stream_PSSD_state *const ss = (stream_PSSD_state *) st;
+
+ return s_PSSD_init_inline(ss);
+}
+
+/* Process a buffer */
+private int
+s_PSSD_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last)
+{
+ stream_PSSD_state *const ss = (stream_PSSD_state *) st;
+ const byte *p = pr->ptr;
+ const byte *rlimit = pr->limit;
+ byte *q = pw->ptr;
+ byte *wlimit = pw->limit;
+ int status = 0;
+ int c;
+
+#define check_p(n)\
+ if ( p == rlimit ) { p -= n; goto out; }
+#define check_q(n)\
+ if ( q == wlimit ) { p -= n; status = 1; goto out; }
+ while (p < rlimit) {
+ c = *++p;
+ if (c == '\\' && !ss->from_string) {
+ check_p(1);
+ switch ((c = *++p)) {
+ case 'n':
+ c = '\n';
+ goto put;
+ case 'r':
+ c = '\r';
+ goto put;
+ case 't':
+ c = '\t';
+ goto put;
+ case 'b':
+ c = '\b';
+ goto put;
+ case 'f':
+ c = '\f';
+ goto put;
+ default: /* ignore the \ */
+ put:check_q(2);
+ *++q = c;
+ continue;
+ case char_CR: /* ignore, check for following \n */
+ check_p(2);
+ if (p[1] == char_EOL)
+ p++;
+ continue;
+ case char_EOL: /* ignore */
+ continue;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ {
+ int d;
+
+ check_p(2);
+ d = p[1];
+ c -= '0';
+ if (d >= '0' && d <= '7') {
+ if (p + 1 == rlimit) {
+ p -= 2;
+ goto out;
+ }
+ check_q(2);
+ c = (c << 3) + d - '0';
+ d = p[2];
+ if (d >= '0' && d <= '7') {
+ c = (c << 3) + d - '0';
+ p += 2;
+ } else
+ p++;
+ } else
+ check_q(2);
+ *++q = c;
+ continue;
+ }
+ }
+ } else
+ switch (c) {
+ case '(':
+ check_q(1);
+ ss->depth++;
+ break;
+ case ')':
+ if (ss->depth == 0) {
+ status = EOFC;
+ goto out;
+ }
+ check_q(1);
+ ss->depth--;
+ break;
+ case char_CR: /* convert to \n */
+ check_p(1);
+ check_q(1);
+ if (p[1] == char_EOL)
+ p++;
+ *++q = '\n';
+ continue;
+ case char_EOL:
+ c = '\n';
+ default:
+ check_q(1);
+ break;
+ }
+ *++q = c;
+ }
+#undef check_p
+#undef check_q
+ out:pr->ptr = p;
+ pw->ptr = q;
+ if (last && status == 0 && p != rlimit)
+ status = ERRC;
+ return status;
+}
+
+/* Stream template */
+const stream_template s_PSSD_template =
+{&st_PSSD_state, s_PSSD_init, s_PSSD_process, 4, 1
+};
+
+/* ------ Utilities ------ */
+
+/*
+ * Convert hex data to binary. Return 1 if we filled the string, 0 if
+ * we ran out of input data before filling the string, or ERRC on error.
+ * The caller must set *odd_digit to -1 before the first call;
+ * after each call, if an odd number of hex digits has been read (total),
+ * *odd_digit is the odd digit value, otherwise *odd_digit = -1.
+ * See strimpl.h for the definition of syntax.
+ */
+int
+s_hex_process(stream_cursor_read * pr, stream_cursor_write * pw,
+ int *odd_digit, hex_syntax syntax)
+{
+ const byte *p = pr->ptr;
+ const byte *rlimit = pr->limit;
+ byte *q = pw->ptr;
+ byte *wlimit = pw->limit;
+ byte *q0 = q;
+ byte val1 = (byte) * odd_digit;
+ byte val2;
+ uint rcount;
+ byte *flimit;
+ const byte *const decoder = scan_char_decoder;
+ int code = 0;
+
+ if (q >= wlimit)
+ return 1;
+ if (val1 <= 0xf)
+ goto d2;
+ d1:if ((rcount = (rlimit - p) >> 1) == 0)
+ goto x1;
+ /* Set up a fast end-of-loop check, so we don't have to test */
+ /* both p and q against their respective limits. */
+ flimit = (rcount < wlimit - q ? q + rcount : wlimit);
+ f1:if ((val1 = decoder[p[1]]) <= 0xf &&
+ (val2 = decoder[p[2]]) <= 0xf
+ ) {
+ p += 2;
+ *++q = (val1 << 4) + val2;
+ if (q < flimit)
+ goto f1;
+ if (q >= wlimit)
+ goto px;
+ }
+ x1:if (p >= rlimit)
+ goto end1;
+ if ((val1 = decoder[*++p]) > 0xf) {
+ if (val1 == ctype_space) {
+ switch (syntax) {
+ case hex_ignore_whitespace:
+ goto x1;
+ case hex_ignore_leading_whitespace:
+ if (q == q0 && *odd_digit < 0)
+ goto x1;
+ --p;
+ code = 1;
+ goto end1;
+ case hex_ignore_garbage:
+ goto x1;
+ }
+ } else if (syntax == hex_ignore_garbage)
+ goto x1;
+ code = ERRC;
+ goto end1;
+ }
+ d2:if (p >= rlimit) {
+ *odd_digit = val1;
+ goto ended;
+ }
+ if ((val2 = decoder[*++p]) > 0xf) {
+ if (val2 == ctype_space)
+ switch (syntax) {
+ case hex_ignore_whitespace:
+ goto d2;
+ case hex_ignore_leading_whitespace:
+ if (q == q0)
+ goto d2;
+ --p;
+ *odd_digit = val1;
+ code = 1;
+ goto ended;
+ case hex_ignore_garbage: /* pacify compilers */
+ ;
+ }
+ if (syntax == hex_ignore_garbage)
+ goto d2;
+ *odd_digit = val1;
+ code = ERRC;
+ goto ended;
+ }
+ *++q = (val1 << 4) + val2;
+ if (q < wlimit)
+ goto d1;
+ px:code = 1;
+ end1:*odd_digit = -1;
+ ended:pr->ptr = p;
+ pw->ptr = q;
+ return code;
+}
diff --git a/pstoraster/sstring.h b/pstoraster/sstring.h
new file mode 100644
index 000000000..c0618e367
--- /dev/null
+++ b/pstoraster/sstring.h
@@ -0,0 +1,79 @@
+/* Copyright (C) 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$ */
+/* are referenced, but some compilers always require strimpl.h. */
+
+#ifndef sstring_INCLUDED
+# define sstring_INCLUDED
+
+/* ASCIIHexEncode */
+typedef struct stream_AXE_state_s {
+ stream_state_common;
+ int count; /* # of digits since last EOL */
+} stream_AXE_state;
+
+#define private_st_AXE_state() /* in sstring.c */\
+ gs_private_st_simple(st_AXE_state, stream_AXE_state,\
+ "ASCIIHexEncode state")
+#define s_AXE_init_inline(ss)\
+ ((ss)->count = 0)
+extern const stream_template s_AXE_template;
+
+/* ASCIIHexDecode */
+typedef struct stream_AXD_state_s {
+ stream_state_common;
+ int odd; /* odd digit */
+} stream_AXD_state;
+
+#define private_st_AXD_state() /* in sstring.c */\
+ gs_private_st_simple(st_AXD_state, stream_AXD_state,\
+ "ASCIIHexDecode state")
+#define s_AXD_init_inline(ss)\
+ ((ss)->odd = -1, 0)
+extern const stream_template s_AXD_template;
+
+/* PSStringDecode */
+typedef struct stream_PSSD_state_s {
+ stream_state_common;
+ /* The following are set by the client. */
+ bool from_string; /* true if using Level 1 \ convention */
+ /* The following change dynamically. */
+ int depth;
+} stream_PSSD_state;
+
+#define private_st_PSSD_state() /* in sstring.c */\
+ gs_private_st_simple(st_PSSD_state, stream_PSSD_state,\
+ "PSStringDecode state")
+/* We define the initialization procedure here, so that the scanner */
+/* can avoid a procedure call. */
+#define s_PSSD_init_inline(ss)\
+ ((ss)->depth = 0)
+extern const stream_template s_PSSD_template;
+
+/* PSStringEncode */
+/* (no state) */
+extern const stream_template s_PSSE_template;
+
+#endif /* sstring_INCLUDED */
diff --git a/pstoraster/stat_.h b/pstoraster/stat_.h
new file mode 100644
index 000000000..dbc04eef5
--- /dev/null
+++ b/pstoraster/stat_.h
@@ -0,0 +1,62 @@
+/* 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$ */
+/* Generic substitute for Unix sys/stat.h */
+
+#ifndef stat__INCLUDED
+# define stat__INCLUDED
+
+/* We must include std.h before any file that includes sys/types.h. */
+#include "std.h"
+#include <sys/stat.h>
+
+/*
+ * Many environments, including the MS-DOS compilers, don't define
+ * the st_blocks member of a stat structure.
+ */
+#if defined(__SVR3) || defined(__EMX__) || defined(__DVX__) || defined(OSK) || defined(__MSDOS__) || defined(__QNX__) || defined(VMS) || defined(__WIN32__) || defined(__IBMC__) || defined(__BEOS__) || defined(Plan9)
+# define stat_blocks(psbuf) (((psbuf)->st_size + 1023) >> 10)
+#else
+# define stat_blocks(psbuf) ((psbuf)->st_blocks)
+#endif
+
+/*
+ * Microsoft C uses _stat instead of stat,
+ * for both the function name and the structure name.
+ */
+#ifdef _MSC_VER
+# define stat _stat
+#endif
+
+/*
+ * Some (System V?) systems test for directories in a slightly different way.
+ */
+#if defined(OSK) || !defined(S_ISDIR)
+# define stat_is_dir(stbuf) ((stbuf).st_mode & S_IFDIR)
+#else
+# define stat_is_dir(stbuf) S_ISDIR((stbuf).st_mode)
+#endif
+
+#endif /* stat__INCLUDED */
diff --git a/pstoraster/std.h b/pstoraster/std.h
new file mode 100644
index 000000000..503805252
--- /dev/null
+++ b/pstoraster/std.h
@@ -0,0 +1,261 @@
+/* Copyright (C) 1989, 1992, 1993, 1994, 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$ */
+/* Standard definitions for Aladdin Enterprises code */
+
+#ifndef std_INCLUDED
+# define std_INCLUDED
+
+#include "stdpre.h"
+
+/* Include the architecture definitions. */
+#include "arch.h"
+
+/* Define integer data type sizes in terms of log2s. */
+#define arch_sizeof_short (1 << arch_log2_sizeof_short)
+#define arch_sizeof_int (1 << arch_log2_sizeof_int)
+#define arch_sizeof_long (1 << arch_log2_sizeof_long)
+#define arch_ints_are_short (arch_sizeof_int == arch_sizeof_short)
+
+/* Define whether we are on a large- or small-memory machine. */
+/* Currently, we assume small memory and 16-bit ints are synonymous. */
+#define arch_small_memory (arch_sizeof_int <= 2)
+
+/* Define unsigned 16- and 32-bit types. These are needed in */
+/* a surprising number of places that do bit manipulation. */
+#if arch_sizeof_short == 2 /* no plausible alternative! */
+typedef ushort bits16;
+
+#endif
+#if arch_sizeof_int == 4
+typedef uint bits32;
+
+#else
+# if arch_sizeof_long == 4
+typedef ulong bits32;
+
+# endif
+#endif
+
+/* Minimum and maximum values for the signed types. */
+/* Avoid casts, to make them acceptable to strict ANSI compilers. */
+#define min_short (-1 << (arch_sizeof_short * 8 - 1))
+#define max_short (~min_short)
+#define min_int (-1 << (arch_sizeof_int * 8 - 1))
+#define max_int (~min_int)
+#define min_long (-1L << (arch_sizeof_long * 8 - 1))
+#define max_long (~min_long)
+
+/*
+ * The maximum values for the unsigned types are defined in arch.h,
+ * because so many compilers handle unsigned constants wrong.
+ * In particular, most of the DEC VMS compilers incorrectly sign-extend
+ * short unsigned constants (but not short unsigned variables) when
+ * widening them to longs. We program around this on a case-by-case basis.
+ * Some compilers don't truncate constants when they are cast down.
+ * The UTek compiler does special weird things of its own.
+ * All the rest (including gcc on all platforms) do the right thing.
+ */
+#define max_uchar arch_max_uchar
+#define max_ushort arch_max_ushort
+#define max_uint arch_max_uint
+#define max_ulong arch_max_ulong
+
+/* Minimum and maximum values for pointers. */
+#if arch_ptrs_are_signed
+# define min_ptr min_long
+# define max_ptr max_long
+#else
+# define min_ptr ((ulong)0)
+# define max_ptr max_ulong
+#endif
+
+/* Define a reliable arithmetic right shift. */
+/* Must use arith_rshift_1 for a shift by a literal 1. */
+#define arith_rshift_slow(x,n) ((x) < 0 ? ~(~(x) >> (n)) : (x) >> (n))
+#if arch_arith_rshift == 2
+# define arith_rshift(x,n) ((x) >> (n))
+# define arith_rshift_1(x) ((x) >> 1)
+#else
+#if arch_arith_rshift == 1 /* OK except for n=1 */
+# define arith_rshift(x,n) ((x) >> (n))
+# define arith_rshift_1(x) arith_rshift_slow(x,1)
+#else
+# define arith_rshift(x,n) arith_rshift_slow(x,n)
+# define arith_rshift_1(x) arith_rshift_slow(x,1)
+#endif
+#endif
+
+/*
+ * Standard error printing macros.
+ * Use dprintf for messages that just go to dstderr;
+ * dlprintf for messages to dsterr with optional with file name (and,
+ * if available, line number);
+ * eprintf for error messages to estderr that include the program name;
+ * lprintf for debugging messages that should include line number info.
+ * Since we intercept fprintf to redirect output under MS Windows,
+ * we have to define dputc and dputs in terms of fprintf also.
+ */
+
+/*
+ * We would prefer not to include stdio.h here, but we need it for
+ * the FILE * argument of the printing procedures.
+ */
+#include <stdio.h>
+
+/* dstderr and estderr may be redefined. */
+#define dstderr stderr
+#define estderr stderr
+
+/* Print the program line # for debugging. */
+#if __LINE__ /* compiler provides it */
+void dprintf_file_and_line(P3(FILE *, const char *, int));
+
+# define _dpl dprintf_file_and_line(estderr, __FILE__, __LINE__),
+#else
+void dprintf_file_only(P2(FILE *, const char *));
+
+# define _dpl dprintf_file_only(estderr, __FILE__),
+#endif
+
+#define dputc(chr) dprintf1("%c", chr)
+#define dlputc(chr) dlprintf1("%c", chr)
+#define dputs(str) dprintf1("%s", str)
+#define dlputs(str) dlprintf1("%s", str)
+#define dprintf(str)\
+ fprintf(dstderr, str)
+#define dlprintf(str)\
+ (_dpl dprintf(str))
+#define dprintf1(str,arg1)\
+ fprintf(dstderr, str, arg1)
+#define dlprintf1(str,arg1)\
+ (_dpl dprintf1(str, arg1))
+#define dprintf2(str,arg1,arg2)\
+ fprintf(dstderr, str, arg1, arg2)
+#define dlprintf2(str,arg1,arg2)\
+ (_dpl dprintf2(str, arg1, arg2))
+#define dprintf3(str,arg1,arg2,arg3)\
+ fprintf(dstderr, str, arg1, arg2, arg3)
+#define dlprintf3(str,arg1,arg2,arg3)\
+ (_dpl dprintf3(str, arg1, arg2, arg3))
+#define dprintf4(str,arg1,arg2,arg3,arg4)\
+ fprintf(dstderr, str, arg1, arg2, arg3, arg4)
+#define dlprintf4(str,arg1,arg2,arg3,arg4)\
+ (_dpl dprintf4(str, arg1, arg2, arg3, arg4))
+#define dprintf5(str,arg1,arg2,arg3,arg4,arg5)\
+ fprintf(dstderr, str, arg1, arg2, arg3, arg4, arg5)
+#define dlprintf5(str,arg1,arg2,arg3,arg4,arg5)\
+ (_dpl dprintf5(str, arg1, arg2, arg3, arg4, arg5))
+#define dprintf6(str,arg1,arg2,arg3,arg4,arg5,arg6)\
+ fprintf(dstderr, str, arg1, arg2, arg3, arg4, arg5, arg6)
+#define dlprintf6(str,arg1,arg2,arg3,arg4,arg5,arg6)\
+ (_dpl dprintf6(str, arg1, arg2, arg3, arg4, arg5, arg6))
+#define dprintf7(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7)\
+ fprintf(dstderr, str, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
+#define dlprintf7(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7)\
+ (_dpl dprintf7(str, arg1, arg2, arg3, arg4, arg5, arg6, arg7))
+#define dprintf8(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8)\
+ fprintf(dstderr, str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
+#define dlprintf8(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8)\
+ (_dpl dprintf8(str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8))
+#define dprintf9(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9)\
+ fprintf(dstderr, str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)
+#define dlprintf9(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9)\
+ (_dpl dprintf9(str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9))
+#define dprintf10(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10)\
+ fprintf(dstderr, str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10)
+#define dlprintf10(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10)\
+ (_dpl dprintf10(str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10))
+#define dprintf11(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11)\
+ fprintf(dstderr, str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11)
+#define dlprintf11(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11)\
+ (_dpl dprintf11(str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11))
+#define dprintf12(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12)\
+ fprintf(dstderr, str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12)
+#define dlprintf12(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12)\
+ (_dpl dprintf12(str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12))
+
+void eprintf_program_name(P2(FILE *, const char *));
+const char *gs_program_name(P0());
+
+#define _epn eprintf_program_name(estderr, gs_program_name()),
+
+#define eprintf(str)\
+ (_epn fprintf(estderr, str))
+#define eprintf1(str,arg1)\
+ (_epn fprintf(estderr, str, arg1))
+#define eprintf2(str,arg1,arg2)\
+ (_epn fprintf(estderr, str, arg1, arg2))
+#define eprintf3(str,arg1,arg2,arg3)\
+ (_epn fprintf(estderr, str, arg1, arg2, arg3))
+#define eprintf4(str,arg1,arg2,arg3,arg4)\
+ (_epn fprintf(estderr, str, arg1, arg2, arg3, arg4))
+#define eprintf5(str,arg1,arg2,arg3,arg4,arg5)\
+ (_epn fprintf(estderr, str, arg1, arg2, arg3, arg4, arg5))
+#define eprintf6(str,arg1,arg2,arg3,arg4,arg5,arg6)\
+ (_epn fprintf(estderr, str, arg1, arg2, arg3, arg4, arg5, arg6))
+#define eprintf7(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7)\
+ (_epn fprintf(estderr, str, arg1, arg2, arg3, arg4, arg5, arg6, arg7))
+#define eprintf8(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8)\
+ (_epn fprintf(estderr, str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8))
+#define eprintf9(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9)\
+ (_epn fprintf(estderr, str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9))
+#define eprintf10(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10)\
+ (_epn fprintf(estderr, str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10))
+
+#if __LINE__ /* compiler provides it */
+void lprintf_file_and_line(P3(FILE *, const char *, int));
+
+# define _epl _epn lprintf_file_and_line(estderr, __FILE__, __LINE__),
+#else
+void lprintf_file_only(P2(FILE *, const char *));
+
+# define _epl _epn lprintf_file_only(estderr, __FILE__)
+#endif
+
+#define lprintf(str)\
+ (_epl fprintf(estderr, str))
+#define lprintf1(str,arg1)\
+ (_epl fprintf(estderr, str, arg1))
+#define lprintf2(str,arg1,arg2)\
+ (_epl fprintf(estderr, str, arg1, arg2))
+#define lprintf3(str,arg1,arg2,arg3)\
+ (_epl fprintf(estderr, str, arg1, arg2, arg3))
+#define lprintf4(str,arg1,arg2,arg3,arg4)\
+ (_epl fprintf(estderr, str, arg1, arg2, arg3, arg4))
+#define lprintf5(str,arg1,arg2,arg3,arg4,arg5)\
+ (_epl fprintf(estderr, str, arg1, arg2, arg3, arg4, arg5))
+#define lprintf6(str,arg1,arg2,arg3,arg4,arg5,arg6)\
+ (_epl fprintf(estderr, str, arg1, arg2, arg3, arg4, arg5, arg6))
+#define lprintf7(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7)\
+ (_epl fprintf(estderr, str, arg1, arg2, arg3, arg4, arg5, arg6, arg7))
+#define lprintf8(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8)\
+ (_epl fprintf(estderr, str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8))
+#define lprintf9(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9)\
+ (_epl fprintf(estderr, str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9))
+#define lprintf10(str,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10)\
+ (_epl fprintf(estderr, str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10))
+
+#endif /* std_INCLUDED */
diff --git a/pstoraster/stdio_.h b/pstoraster/stdio_.h
new file mode 100644
index 000000000..7b2088bbb
--- /dev/null
+++ b/pstoraster/stdio_.h
@@ -0,0 +1,74 @@
+/* Copyright (C) 1992, 1993, 1994, 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 stdio.h */
+
+#ifndef stdio__INCLUDED
+# define stdio__INCLUDED
+
+/*
+ * This is here primarily because we must include std.h before
+ * any file that includes sys/types.h.
+ */
+#include "std.h"
+#include <stdio.h>
+
+#ifdef VMS
+/* VMS doesn't have the unlink system call. Use delete instead. */
+# ifdef __DECC
+# include <unixio.h>
+# endif
+# define unlink(fname) delete(fname)
+#else
+/*
+ * Other systems may or may not declare unlink in stdio.h;
+ * if they do, the declaration will be compatible with this one.
+ */
+int unlink(P1(const char *));
+
+#endif
+
+/*
+ * Plan 9 has a system function called sclose, which interferes with the
+ * procedure defined in stream.h. The following makes the system sclose
+ * inaccessible, but avoids the name clash.
+ */
+#ifdef Plan9
+# undef sclose
+# define sclose(s) Sclose(s)
+#endif
+
+/* Patch a couple of things possibly missing from stdio.h. */
+#ifndef SEEK_SET
+# define SEEK_SET 0
+#endif
+#ifndef SEEK_CUR
+# define SEEK_CUR 1
+#endif
+#ifndef SEEK_END
+# define SEEK_END 2
+#endif
+
+#endif /* stdio__INCLUDED */
diff --git a/pstoraster/stdpre.h b/pstoraster/stdpre.h
new file mode 100644
index 000000000..e7bce6d03
--- /dev/null
+++ b/pstoraster/stdpre.h
@@ -0,0 +1,422 @@
+/*
+ Copyright 2001 by Easy Software Products.
+ Copyright 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$ */
+/* Standard definitions for Aladdin Enterprises code not needing arch.h */
+
+#ifndef stdpre_INCLUDED
+# define stdpre_INCLUDED
+
+/*
+ * Here we deal with the vagaries of various C compilers. We assume that:
+ * ANSI-standard Unix compilers define __STDC__.
+ * gcc defines __GNUC__.
+ * Borland Turbo C and Turbo C++ define __MSDOS__ and __TURBOC__.
+ * Borland C++ defines __BORLANDC__, __MSDOS__, and __TURBOC__.
+ * Microsoft C/C++ defines _MSC_VER and _MSDOS.
+ * Watcom C defines __WATCOMC__ and MSDOS.
+ * MetroWerks C defines __MWERKS__.
+ *
+ * We arrange to define __MSDOS__ on all the MS-DOS platforms.
+ */
+#if (defined(MSDOS) || defined(_MSDOS)) && !defined(__MSDOS__)
+# define __MSDOS__
+#endif
+/*
+ * Also, not used much here, but used in other header files, we assume:
+ * Unix System V environments define SYSV.
+ * The SCO ODT compiler defines M_SYSV and M_SYS3.
+ * VMS systems define VMS.
+ * OSF/1 compilers define __osf__ or __OSF__.
+ * (The VMS and OSF/1 C compilers handle prototypes and const,
+ * but do not define __STDC__.)
+ * bsd 4.2 or 4.3 systems define BSD4_2.
+ * POSIX-compliant environments define _POSIX_SOURCE.
+ * Motorola 88K BCS/OCS systems defined m88k.
+ *
+ * We make fairly heroic efforts to confine all uses of these flags to
+ * header files, and never to use them in code.
+ */
+#if defined(__osf__) && !defined(__OSF__)
+# define __OSF__ /* */
+#endif
+#if defined(M_SYSV) && !defined(SYSV)
+# define SYSV /* */
+#endif
+#if defined(M_SYS3) && !defined(__SVR3)
+# define __SVR3 /* */
+#endif
+
+#if defined(__STDC__) || defined(__MSDOS__) || defined(__convex__) || defined(VMS) || defined(__OSF__) || defined(__WIN32__) || defined(__IBMC__) || defined(M_UNIX) || defined(__GNUC__) || defined(__BORLANDC__)
+# if !(defined(M_XENIX) && !defined(__GNUC__)) /* SCO Xenix cc is broken */
+# define __PROTOTYPES__ /* */
+# endif
+#endif
+
+/* Define dummy values for __FILE__ and __LINE__ if the compiler */
+/* doesn't provide these. Note that places that use __FILE__ */
+/* must check explicitly for a null pointer. */
+#ifndef __FILE__
+# define __FILE__ NULL
+#endif
+#ifndef __LINE__
+# define __LINE__ 0
+#endif
+
+/* Disable 'const' and 'volatile' if the compiler can't handle them. */
+#ifndef __PROTOTYPES__
+# undef const
+# define const /* */
+# undef volatile
+# define volatile /* */
+#endif
+
+/* Disable 'inline' if the compiler can't handle it. */
+#ifdef __DECC
+# undef inline
+# define inline __inline
+#else
+# if !(defined(__GNUC__) || defined(__MWERKS__) || defined(inline))
+# define inline /* */
+# endif
+#endif
+
+/*
+ * Some compilers give a warning if a function call that returns a value
+ * is used as a statement; a few compilers give an error for the construct
+ * (void)0, which is contrary to the ANSI standard. Since we don't know of
+ * any compilers that do both, we define a macro here for discarding
+ * the value of an expression statement, which can be defined as either
+ * including or not including the cast. (We don't conditionalize this here,
+ * because no commercial compiler gives the error on (void)0, although
+ * some give warnings.)
+ */
+#define discard(expr) ((void)(expr))
+
+/*
+ * The SVR4.2 C compiler incorrectly considers the result of << and >>
+ * to be unsigned if the left operand is signed and the right operand is
+ * unsigned. We believe this only causes trouble in Ghostscript code when
+ * the right operand is a sizeof(...), which is unsigned for this compiler.
+ * Therefore, we replace the relevant uses of sizeof with size_of:
+ */
+#define size_of(x) ((int)(sizeof(x)))
+
+/*
+ * Disable MS-DOS specialized pointer types on non-MS-DOS systems.
+ * Watcom C defines near, far, and huge as macros, so we must undef them.
+ * far_data is used for static data that must get its own segment.
+ * This is supported in Borland C++, but none of the others.
+ */
+#undef far_data
+#if defined(__TURBOC__) && !defined(__WIN32__)
+# ifdef __BORLANDC__
+# define far_data far
+# else
+# define far_data /* */
+# endif
+#else
+# undef near
+# define near /* */
+# undef far
+# define far /* */
+# define far_data /* */
+# undef huge
+# define huge /* */
+# define _cs /* */
+# define _ds /* */
+/* _es is never safe to use */
+# define _ss /* */
+#endif
+
+/* Get the size of a statically declared array. */
+#define countof(a) (sizeof(a) / sizeof((a)[0]))
+#define count_of(a) (size_of(a) / size_of((a)[0]))
+
+/*
+ * Get the offset of a structure member. Amazingly enough, the simpler
+ * definition works on all compilers except for one broken MIPS compiler
+ * and the IBM RS/6000. Unfortunately, because of these two compilers,
+ * we have to use the more complex definition. Even more unfortunately,
+ * the more complex definition doesn't work on the MetroWerks
+ * CodeWarrior compiler (Macintosh and BeOS).
+ */
+#ifdef __MWERKS__
+#define offset_of(type, memb)\
+ ((int) &((type *) 0)->memb)
+#else
+#define offset_of(type, memb)\
+ ((int) ( (char *)&((type *)0)->memb - (char *)((type *)0) ))
+#endif
+
+/*
+ * Get the alignment of a pointer modulo a given power of 2.
+ * There is no portable way to do this, but the following definition
+ * works on all reasonable systems.
+ */
+#define alignment_mod(ptr, modu)\
+ ((uint)( ((const char *)(ptr) - (const char *)0) & ((modu) - 1) ))
+
+/* Define short names for the unsigned types. */
+typedef unsigned char byte;
+typedef unsigned char uchar;
+typedef unsigned short ushort;
+typedef unsigned int uint;
+typedef unsigned long ulong;
+
+/* Since sys/types.h often defines one or more of these (depending on */
+/* the platform), we have to take steps to prevent name clashes. */
+/*** NOTE: This requires that you include std.h *before* any other ***/
+/*** header file that includes sys/types.h. ***/
+#define bool bool_ /* (maybe not needed) */
+#define uchar uchar_
+#define uint uint_
+#define ushort ushort_
+#define ulong ulong_
+#include <sys/types.h>
+#undef bool
+#undef uchar
+#undef uint
+#undef ushort
+#undef ulong
+
+/*
+ * Define a Boolean type. Even though we would like it to be
+ * unsigned char, it pretty well has to be int, because
+ * that's what all the relational operators and && and || produce.
+ * We can't make it an enumerated type, because ints don't coerce
+ * freely to enums (although the opposite is true).
+ * Unfortunately, at least some C++ compilers have a built-in bool type,
+ * and the MetroWerks C++ compiler insists that bool be equivalent to
+ * unsigned char.
+ */
+#ifndef __cplusplus
+#ifdef __BEOS__
+typedef unsigned char bool;
+
+#else
+typedef int bool;
+
+#endif
+#endif
+/*
+ * MetroWerks CodeWarrior predefines true and false, probably as 1 and 0.
+ * We need to cancel those definitions for our own code.
+ */
+#undef false
+#define false ((bool)0)
+#undef true
+#define true ((bool)1)
+
+/*
+ * Compilers disagree as to whether macros used in macro arguments
+ * should be expanded at the time of the call, or at the time of
+ * final expansion. Even authoritative documents disagree: the ANSI
+ * standard says the former, but Harbison and Steele's book says the latter.
+ * In order to work around this discrepancy, we have to do some very
+ * ugly things in a couple of places. We mention it here because
+ * it might well trip up future developers.
+ */
+
+/*
+ * Define the type to be used for ordering pointers (<, >=, etc.).
+ * The Borland and Microsoft large models only compare the offset part
+ * of segmented pointers. Semantically, the right type to use for the
+ * comparison is char huge *, but we have no idea how expensive comparing
+ * such pointers is, and any type that compares all the bits of the pointer,
+ * gives the right result for pointers in the same segment, and keeps
+ * different segments disjoint will do.
+ */
+#if defined(__TURBOC__) || defined(_MSC_VER)
+typedef unsigned long ptr_ord_t;
+
+#else
+typedef const char *ptr_ord_t;
+
+#endif
+/* Define all the pointer comparison operations. */
+#define _ptr_cmp(p1, rel, p2) ((ptr_ord_t)(p1) rel (ptr_ord_t)(p2))
+#define ptr_le(p1, p2) _ptr_cmp(p1, <=, p2)
+#define ptr_lt(p1, p2) _ptr_cmp(p1, <, p2)
+#define ptr_ge(p1, p2) _ptr_cmp(p1, >=, p2)
+#define ptr_gt(p1, p2) _ptr_cmp(p1, >, p2)
+#define ptr_between(ptr, lo, hi)\
+ (ptr_ge(ptr, lo) && ptr_lt(ptr, hi))
+
+/* Define min and max, but make sure to use the identical definition */
+/* to the one that all the compilers seem to have.... */
+#ifndef min
+# define min(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+#ifndef max
+# define max(a, b) (((a) > (b)) ? (a) : (b))
+#endif
+
+/* Define a standard way to round values to a (constant) modulus. */
+#define round_down(value, modulus)\
+ ( (modulus) & ((modulus) - 1) ? /* not a power of 2 */\
+ (value) - (value) % (modulus) :\
+ (value) & -(modulus) )
+#define round_up(value, modulus)\
+ ( (modulus) & ((modulus) - 1) ? /* not a power of 2 */\
+ ((value) + ((modulus) - 1)) / (modulus) * (modulus) :\
+ ((value) + ((modulus) - 1)) & -(modulus) )
+
+/*
+ * In pre-ANSI C, float parameters get converted to double.
+ * However, if we pass a float to a function that has been declared
+ * with a prototype, and the parameter has been declared as float,
+ * the ANSI standard specifies that the parameter is left as float.
+ * To avoid problems caused by missing prototypes,
+ * we declare almost all float parameters as double.
+ */
+typedef double floatp;
+
+/*
+ * Because of C's strange insistence that ; is a terminator and not a
+ * separator, compound statements {...} are not syntactically equivalent to
+ * single statements. Therefore, we define here a compound-statement
+ * construct that *is* syntactically equivalent to a single statement.
+ * Usage is
+ * BEGIN
+ * ...statements...
+ * END
+ */
+/*** MRS: If you didn't treat C like a macro language, maybe this wouldn't
+ *** be a problem; changed to { and } (which do work) to avoid
+ *** needless compiler warnings...
+ ***/
+#define BEGIN {
+#define END }
+
+/*
+ * Define a handy macro for a statement that does nothing.
+ * We can't just use an empty statement, since this upsets some compilers.
+ */
+/*** MRS: Fix DO_NOTHING to use a void statement. Again, not using
+ *** macros makes life easier...
+ ***/
+#ifndef DO_NOTHING
+# define DO_NOTHING (void)stdout
+#endif
+
+/*
+ * For accountability, debugging, and error messages,
+ * we pass a client identification string to alloc and free,
+ * and possibly other places as well. Define the type for these strings.
+ * The definition used to have a _ds modifier, so we had to coerce
+ * them when passing them to printf at all; this is no longer needed.
+ */
+typedef const char *client_name_t;
+
+#define client_name_string(cname) (cname)
+
+/*
+ * If we are debugging, make all static variables and procedures public
+ * so they get passed through the linker.
+ */
+#define public /* */
+/*
+ * We separate out the definition of private this way so that
+ * we can temporarily #undef it to handle the X Windows headers,
+ * which define a member named private.
+ */
+#ifdef NOPRIVATE
+# define private_ /* */
+#else
+# define private_ static
+#endif
+#define private private_
+
+/*
+ * Macros for argument templates. ANSI C has these, as does Turbo C,
+ * but older pcc-derived (K&R) Unix compilers don't. The syntax is
+ * resulttype func(Pn(arg1, ..., argn));
+ */
+
+#ifdef __PROTOTYPES__
+# define P0() void
+# define P1(t1) t1
+# define P2(t1,t2) t1,t2
+# define P3(t1,t2,t3) t1,t2,t3
+# define P4(t1,t2,t3,t4) t1,t2,t3,t4
+# define P5(t1,t2,t3,t4,t5) t1,t2,t3,t4,t5
+# define P6(t1,t2,t3,t4,t5,t6) t1,t2,t3,t4,t5,t6
+# define P7(t1,t2,t3,t4,t5,t6,t7) t1,t2,t3,t4,t5,t6,t7
+# define P8(t1,t2,t3,t4,t5,t6,t7,t8) t1,t2,t3,t4,t5,t6,t7,t8
+# define P9(t1,t2,t3,t4,t5,t6,t7,t8,t9) t1,t2,t3,t4,t5,t6,t7,t8,t9
+# define P10(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10) t1,t2,t3,t4,t5,t6,t7,t8,t9,t10
+# define P11(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11) t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11
+# define P12(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12) t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12
+# define P13(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13) t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13
+# define P14(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14) t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14
+# define P15(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15) t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15
+# define P16(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16) t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16
+#else
+# define P0() /* */
+# define P1(t1) /* */
+# define P2(t1,t2) /* */
+# define P3(t1,t2,t3) /* */
+# define P4(t1,t2,t3,t4) /* */
+# define P5(t1,t2,t3,t4,t5) /* */
+# define P6(t1,t2,t3,t4,t5,t6) /* */
+# define P7(t1,t2,t3,t4,t5,t6,t7) /* */
+# define P8(t1,t2,t3,t4,t5,t6,t7,t8) /* */
+# define P9(t1,t2,t3,t4,t5,t6,t7,t8,t9) /* */
+# define P10(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10) /* */
+# define P11(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11) /* */
+# define P12(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12) /* */
+# define P13(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13) /* */
+# define P14(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14) /* */
+# define P15(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15) /* */
+# define P16(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16) /* */
+#endif
+
+/* Define success and failure codes for 'exit'. */
+#ifdef VMS
+# define exit_OK 1
+# define exit_FAILED 18
+#else
+# define exit_OK 0
+# define exit_FAILED 1
+#endif
+/*
+ * Define the informational exit status.
+ * We need to distinguish information returns because under MS Windows,
+ * they must return like an error so that the text window stays on the
+ * screen, while on other platforms, they must return successfully.
+ * Note that we define both gs_exit_INFO (before platform-specific
+ * mapping of 0 to exit_OK and 1 to exit_FAILED) and exit_INFO.
+ */
+#if defined(_WINDOWS) || defined(_Windows)
+# define exit_INFO exit_FAILED
+# define gs_exit_INFO 1
+#else
+# define exit_INFO exit_OK
+# define gs_exit_INFO 0
+#endif
+
+#endif /* stdpre_INCLUDED */
diff --git a/pstoraster/store.h b/pstoraster/store.h
new file mode 100644
index 000000000..0488cf974
--- /dev/null
+++ b/pstoraster/store.h
@@ -0,0 +1,250 @@
+/* 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$ */
+/* Assignment-related macros */
+
+#ifndef store_INCLUDED
+# define store_INCLUDED
+
+#include "ialloc.h" /* for imemory masks & checks */
+
+/*
+ * Macros for storing a ref. We use macros for storing into objects,
+ * since the storage manager needs to be able to track stores for
+ * save/restore and also for global/local checking.
+ * We also use macros for other ref assignments, because (as it happens)
+ * Turbo C generates pretty awful code for doing this.
+ *
+ * There are three cases that we need to distinguish:
+ * - Storing to a stack (no special action);
+ * - Storing into a newly created object (set l_new);
+ * - Storing into a slot of an existing object (check l_new in
+ * old value, set in new value).
+ * The macros are called
+ * <make/store><new_type><case>(place_to_store, new_value)
+ * where <case> is nothing for storing to the stack, _new for storing into
+ * a new object, and _old for storing into an existing object.
+ * (The _old macros also take a client name for tracing and debugging.)
+ * <new_type> and new_value are chosen from the following alternatives:
+ * ref_assign POINTER TO arbitrary ref
+ * make_t type (only for null and mark)
+ * make_tv type, value field name, value
+ * (only for scalars, which don't have attributes)
+ * make_tav type, attributes, value field name, value
+ * make_tasv type, attributes, size, value field name, value
+ * There are also specialized make_ macros for specific types:
+ * make_array, make_int, make_real, make_bool, make_false, make_true,
+ * make_mark, make_null, make_oper, make_[const_]string, make_struct.
+ * Not all of the specialized make_ macros have _new and _old variants.
+ *
+ * For _tav and _tasv, we must store the value first, because sometimes
+ * it depends on the contents of the place being stored into.
+ *
+ * Note that for composite objects (dictionary, file, array, string, device,
+ * struct), we must set a_foreign if the contents are allocated statically
+ * (e.g., for constant C strings) or not by the Ghostscript allocator
+ * (e.g., with malloc).
+ */
+
+/*
+ * Define the most efficient ref assignment macro for the platform.
+ */
+/*
+ * Assigning the components individually is fastest on Turbo C,
+ * and on Watcom C when one or both of the addresses are
+ * already known or in a register.
+ */
+#define ref_assign_inline(pto,pfrom)\
+ ((pto)->value = (pfrom)->value,\
+ (pto)->tas = (pfrom)->tas)
+#ifdef __TURBOC__
+ /*
+ * Move the data in two 32-bit chunks, because
+ * otherwise the compiler calls SCOPY@.
+ * The cast to void is to discourage the compiler from
+ * wanting to deliver the value of the expression.
+ */
+# define ref_assign(pto,pfrom)\
+ discard(ref_assign_inline(pto, pfrom))
+#else
+ /*
+ * Trust the compiler and hope for the best.
+ * The MIPS compiler doesn't like the cast to void.
+ */
+# define ref_assign(pto,pfrom)\
+ (*(pto) = *(pfrom))
+#endif
+
+/****** NOTE: the following declarations are duplicated from isave.h. ******/
+
+int alloc_save_change(P4(gs_dual_memory_t *, const ref * pcont,
+ ref_packed * ptr, client_name_t cname));
+int alloc_save_level(P1(const gs_dual_memory_t *));
+
+/****** END duplicated declarations. ******/
+
+#define ialloc_save_change(pcont, ptr, cname)\
+ alloc_save_change(idmemory, pcont, ptr, cname)
+#define ialloc_is_in_save() (idmemory->save_level > 0)
+#define ialloc_test_mask (idmemory->test_mask)
+#define ialloc_new_mask (idmemory->new_mask)
+#define ref_must_save(pto)\
+ ((r_type_attrs(pto) & ialloc_test_mask) == 0)
+#define ref_do_save(pcont, pto, cname)\
+ ialloc_save_change(pcont, (ref_packed *)(pto), cname)
+#define ref_save(pcont, pto, cname)\
+ discard((ref_must_save(pto) ? ref_do_save(pcont, pto, cname) : 0))
+#define ref_mark_new(pto) ((pto)->tas.type_attrs |= ialloc_new_mask)
+#define ref_assign_new(pto,pfrom)\
+ discard((ref_assign(pto,pfrom), ref_mark_new(pto)))
+#define ref_assign_new_inline(pto,pfrom)\
+ discard((ref_assign_inline(pto,pfrom), ref_mark_new(pto)))
+#define ref_assign_old(pcont,pto,pfrom,cname)\
+ (ref_save(pcont,pto,cname), ref_assign_new(pto,pfrom))
+#define ref_assign_old_inline(pcont,pto,pfrom,cname)\
+ (ref_save(pcont,pto,cname), ref_assign_new_inline(pto,pfrom))
+/* ref_mark_old is only needed in very unusual situations, namely, */
+/* when we want to do a ref_save just before a save instead of */
+/* when the actual assignment occurs. */
+#define ref_mark_old(pto) ((pto)->tas.type_attrs &= ~ialloc_new_mask)
+
+/* Define macros for conditionally clearing the parts of a ref */
+/* that aren't being set to anything useful. */
+
+#ifdef DEBUG
+# define and_fill_s(pref)\
+ , (gs_debug['$'] ? r_set_size(pref, 0xfeed) : 0)
+# define and_fill_sv(pref)\
+ , (gs_debug['$'] ? (r_set_size(pref, 0xfeed),\
+ (pref)->value.intval = 0xdeadbeef) : 0)
+#else /* !DEBUG */
+# define and_fill_s(pref) /* */
+# define and_fill_sv(pref) /* */
+#endif
+
+/* make_t must set the attributes to 0 to clear a_local! */
+#define make_t(pref,newtype)\
+ (r_set_type_attrs(pref, newtype, 0) and_fill_sv(pref))
+#define make_t_new(pref,newtype)\
+ (r_set_type_attrs(pref, newtype, ialloc_new_mask) and_fill_sv(pref))
+#define make_t_old(pcont,pref,newtype,cname)\
+ (ref_save(pcont,pref,cname), make_t_new(pref,newtype))
+
+#define make_tav(pref,newtype,newattrs,valfield,newvalue)\
+ ((pref)->value.valfield = (newvalue),\
+ r_set_type_attrs(pref, newtype, newattrs)\
+ and_fill_s(pref))
+#define make_tav_new(pref,t,a,vf,v)\
+ make_tav(pref,t,(a)|ialloc_new_mask,vf,v)
+#define make_tav_old(pcont,pref,t,a,vf,v,cname)\
+ (ref_save(pcont,pref,cname), make_tav_new(pref,t,a,vf,v))
+
+#define make_tv(pref,newtype,valfield,newvalue)\
+ make_tav(pref,newtype,0,valfield,newvalue)
+#define make_tv_new(pref,t,vf,v)\
+ make_tav_new(pref,t,0,vf,v)
+#define make_tv_old(pcont,pref,t,vf,v,cname)\
+ make_tav_old(pcont,pref,t,0,vf,v,cname)
+
+#define make_tasv(pref,newtype,newattrs,newsize,valfield,newvalue)\
+ ((pref)->value.valfield = (newvalue),\
+ r_set_type_attrs(pref, newtype, newattrs),\
+ r_set_size(pref, newsize))
+#define make_tasv_new(pref,t,a,s,vf,v)\
+ make_tasv(pref,t,(a)|ialloc_new_mask,s,vf,v)
+#define make_tasv_old(pcont,pref,t,a,s,vf,v,cname)\
+ (ref_save(pcont,pref,cname), make_tasv_new(pref,t,a,s,vf,v))
+
+/* Type-specific constructor macros for scalar (non-composite) types */
+
+#define make_bool(pref,bval)\
+ make_tv(pref, t_boolean, boolval, bval)
+#define make_false(pref)\
+ make_bool(pref, 0)
+#define make_true(pref)\
+ make_bool(pref, 1)
+
+#define make_int(pref,ival)\
+ make_tv(pref, t_integer, intval, ival)
+#define make_int_new(pref,ival)\
+ make_tv_new(pref, t_integer, intval, ival)
+
+#define make_mark(pref)\
+ make_t(pref, t_mark)
+
+#define make_null(pref)\
+ make_t(pref, t_null)
+#define make_null_new(pref)\
+ make_t_new(pref, t_null)
+#define make_null_old(pcont,pref,cname)\
+ make_t_old(pcont, pref, t_null, cname)
+
+#define make_oper(pref,opidx,proc)\
+ make_tasv(pref, t_operator, a_executable, opidx, opproc, proc)
+#define make_oper_new(pref,opidx,proc)\
+ make_tasv_new(pref, t_operator, a_executable, opidx, opproc, proc)
+
+#define make_real(pref,rval)\
+ make_tv(pref, t_real, realval, rval)
+#define make_real_new(pref,rval)\
+ make_tv_new(pref, t_real, realval, rval)
+
+/* Type-specific constructor macros for composite types */
+
+/* For composite types, the a_space field is relevant; however, */
+/* as noted in ivmspace.h, a value of 0 designates the most static space, */
+/* so for making empty composites, a space value of 0 is appropriate. */
+
+#define make_array(pref,attrs,size,elts)\
+ make_tasv(pref, t_array, attrs, size, refs, elts)
+#define make_array_new(pref,attrs,size,elts)\
+ make_tasv_new(pref, t_array, attrs, size, refs, elts)
+#define make_const_array(pref,attrs,size,elts)\
+ make_tasv(pref, t_array, attrs, size, const_refs, elts)
+#define make_empty_array(pref,attrs)\
+ make_array(pref, attrs, 0, (ref *)NULL)
+#define make_empty_const_array(pref,attrs)\
+ make_const_array(pref, attrs, 0, (const ref *)NULL)
+
+#define make_string(pref,attrs,size,chars)\
+ make_tasv(pref, t_string, attrs, size, bytes, chars)
+#define make_const_string(pref,attrs,size,chars)\
+ make_tasv(pref, t_string, attrs, size, const_bytes, chars)
+#define make_empty_string(pref,attrs)\
+ make_string(pref, attrs, 0, (byte *)NULL)
+#define make_empty_const_string(pref,attrs)\
+ make_const_string(pref, attrs, 0, (const byte *)NULL)
+
+#define make_struct(pref,attrs,ptr)\
+ make_tav(pref, t_struct, attrs, pstruct, (obj_header_t *)(ptr))
+#define make_struct_new(pref,attrs,ptr)\
+ make_tav_new(pref, t_struct, attrs, pstruct, (obj_header_t *)(ptr))
+
+#define make_astruct(pref,attrs,ptr)\
+ make_tav(pref, t_astruct, attrs, pstruct, (obj_header_t *)(ptr))
+#define make_astruct_new(pref,attrs,ptr)\
+ make_tav_new(pref, t_astruct, attrs, pstruct, (obj_header_t *)(ptr))
+
+#endif /* store_INCLUDED */
diff --git a/pstoraster/stream.c b/pstoraster/stream.c
new file mode 100644
index 000000000..abe3b103e
--- /dev/null
+++ b/pstoraster/stream.c
@@ -0,0 +1,911 @@
+/* Copyright (C) 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$ */
+/* Stream package for Ghostscript interpreter */
+#include "stdio_.h" /* includes std.h */
+#include "memory_.h"
+#include "gdebug.h"
+#include "gpcheck.h"
+#include "stream.h"
+#include "strimpl.h"
+
+/* Forward declarations */
+private int sreadbuf(P2(stream *, stream_cursor_write *));
+private int swritebuf(P3(stream *, stream_cursor_read *, bool));
+private void stream_compact(P2(stream *, bool));
+
+/* Structure types for allocating streams. */
+private_st_stream();
+public_st_stream_state(); /* default */
+/* GC procedures */
+#define st ((stream *)vptr)
+private
+ENUM_PTRS_BEGIN(stream_enum_ptrs) return 0;
+
+case 0:
+if (st->foreign)
+ ENUM_RETURN(NULL);
+else if (st->cbuf_string.data != 0)
+ ENUM_RETURN_STRING_PTR(stream, cbuf_string);
+else
+ ENUM_RETURN(st->cbuf);
+ENUM_PTR(1, stream, strm);
+ENUM_PTR(2, stream, prev);
+ENUM_PTR(3, stream, next);
+ENUM_PTR(4, stream, state);
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(stream_reloc_ptrs)
+{
+ byte *cbuf_old = st->cbuf;
+
+ if (cbuf_old != 0 && !st->foreign) {
+ long reloc;
+
+ if (st->cbuf_string.data != 0) {
+ RELOC_STRING_VAR(st->cbuf_string);
+ st->cbuf = st->cbuf_string.data;
+ } else
+ RELOC_VAR(st->cbuf);
+ reloc = cbuf_old - st->cbuf;
+ /* Relocate the other buffer pointers. */
+ st->srptr -= reloc;
+ st->srlimit -= reloc; /* same as swptr */
+ st->swlimit -= reloc;
+ }
+ RELOC_VAR(st->strm);
+ RELOC_VAR(st->prev);
+ RELOC_VAR(st->next);
+ RELOC_VAR(st->state);
+}
+RELOC_PTRS_END
+/* Finalize a stream by closing it. */
+/* We only do this for file streams, because other kinds of streams */
+/* may attempt to free storage when closing. */
+private void
+stream_finalize(void *vptr)
+{
+ if_debug2('u', "[u]%s 0x%lx\n",
+ (!s_is_valid(st) ? "already closed:" :
+ st->is_temp ? "is_temp set:" :
+ st->file == 0 ? "not file:" :
+ "closing file:"), (ulong) st);
+ if (s_is_valid(st) && !st->is_temp && st->file != 0) { /* Prevent any attempt to free the buffer. */
+ st->cbuf = 0;
+ st->cbuf_string.data = 0;
+ sclose(st); /* ignore errors */
+ }
+}
+#undef st
+
+/* Dummy template for streams that don't have a separate state. */
+private const stream_template s_no_template = {
+ &st_stream_state, 0, 0, 1, 1, 0
+};
+
+/* ------ Generic procedures ------ */
+
+/* Allocate a stream and initialize it minimally. */
+stream *
+s_alloc(gs_memory_t * mem, client_name_t cname)
+{
+ stream *s = gs_alloc_struct(mem, stream, &st_stream, cname);
+
+ if_debug2('s', "[s]alloc(%s) = 0x%lx\n",
+ client_name_string(cname), (ulong) s);
+ if (s == 0)
+ return 0;
+ s->memory = mem;
+ s->report_error = s_no_report_error;
+ s->prev = s->next = 0; /* clean for GC */
+ s->close_strm = false; /* default */
+ return s;
+}
+
+/* Allocate a stream state and initialize it minimally. */
+stream_state *
+s_alloc_state(gs_memory_t * mem, gs_memory_type_ptr_t stype,
+ client_name_t cname)
+{
+ stream_state *st = gs_alloc_struct(mem, stream_state, stype, cname);
+
+ if_debug3('s', "[s]alloc_state %s(%s) = 0x%lx\n",
+ client_name_string(cname),
+ client_name_string(stype->sname),
+ (ulong) st);
+ if (st == 0)
+ return 0;
+ st->memory = mem;
+ st->report_error = s_no_report_error;
+ return st;
+}
+
+/* Vacuous stream initialization */
+int
+s_no_init(stream_state * st)
+{
+ return 0;
+}
+
+/* Standard stream initialization */
+void
+s_std_init(register stream * s, byte * ptr, uint len, const stream_procs * pp,
+ int modes)
+{
+ s->template = &s_no_template;
+ s->cbuf = ptr;
+ s->srptr = s->srlimit = s->swptr = ptr - 1;
+ s->swlimit = ptr - 1 + len;
+ s->end_status = 0;
+ s->foreign = 0;
+ s->modes = modes;
+ s->cbuf_string.data = 0;
+ s->position = 0;
+ s->bsize = s->cbsize = len;
+ s->strm = 0; /* not a filter */
+ s->is_temp = 0;
+ s->procs = *pp;
+ s->state = (stream_state *) s; /* hack to avoid separate state */
+ s->file = 0;
+ if_debug4('s', "[s]init 0x%lx, buf=0x%lx, len=%u, modes=%d\n",
+ (ulong) s, (ulong) ptr, len, modes);
+}
+
+/* Implement a stream procedure as a no-op. */
+int
+s_std_null(stream * s)
+{
+ return 0;
+}
+
+/* Discard the contents of the buffer when reading. */
+void
+s_std_read_reset(stream * s)
+{
+ s->srptr = s->srlimit = s->cbuf - 1;
+}
+
+/* Discard the contents of the buffer when writing. */
+void
+s_std_write_reset(stream * s)
+{
+ s->swptr = s->cbuf - 1;
+}
+
+/* Flush data to end-of-file when reading. */
+int
+s_std_read_flush(stream * s)
+{
+ while (1) {
+ s->srptr = s->srlimit = s->cbuf - 1;
+ if (s->end_status)
+ break;
+ s_process_read_buf(s);
+ }
+ return (s->end_status == EOFC ? 0 : s->end_status);
+}
+
+/* Flush buffered data when writing. */
+int
+s_std_write_flush(stream * s)
+{
+ return s_process_write_buf(s, false);
+}
+
+/* Indicate that the number of available input bytes is unknown. */
+int
+s_std_noavailable(stream * s, long *pl)
+{
+ *pl = -1;
+ return 0;
+}
+
+/* Indicate an error when asked to seek. */
+int
+s_std_noseek(stream * s, long pos)
+{
+ return ERRC;
+}
+
+/* Standard stream closing. */
+int
+s_std_close(stream * s)
+{
+ return 0;
+}
+
+/* Standard stream mode switching. */
+int
+s_std_switch_mode(stream * s, bool writing)
+{
+ return ERRC;
+}
+
+/* Standard stream finalization. Disable the stream. */
+void
+s_disable(register stream * s)
+{
+ s->cbuf = 0;
+ s->bsize = 0;
+ s->end_status = EOFC;
+ s->modes = 0;
+ s->cbuf_string.data = 0;
+ /* The pointers in the next two statements should really be */
+ /* initialized to ([const] byte *)0 - 1, but some very picky */
+ /* compilers complain about this. */
+ s->cursor.r.ptr = s->cursor.r.limit = 0;
+ s->cursor.w.limit = 0;
+ s->procs.close = s_std_null;
+ /* Clear pointers for GC */
+ s->strm = 0;
+ s->state = (stream_state *) s;
+ s->template = &s_no_template;
+ /****** SHOULD DO MORE THAN THIS ******/
+ if_debug1('s', "[s]disable 0x%lx\n", (ulong) s);
+}
+
+/* Implement flushing for encoding filters. */
+int
+s_filter_write_flush(register stream * s)
+{
+ int status = s_process_write_buf(s, false);
+
+ if (status != 0)
+ return status;
+ return sflush(s->strm);
+}
+
+/* Close a filter. If this is an encoding filter, flush it first. */
+int
+s_filter_close(register stream * s)
+{
+ if (s_is_writing(s)) {
+ int status = s_process_write_buf(s, true);
+
+ if (status != 0 && status != EOFC)
+ return status;
+ }
+ return s_std_close(s);
+}
+
+/* Disregard a stream error message. */
+int
+s_no_report_error(stream_state * st, const char *str)
+{
+ return 0;
+}
+
+/* Generic procedure structures for filters. */
+
+const stream_procs s_filter_read_procs =
+{
+ s_std_noavailable, s_std_noseek, s_std_read_reset,
+ s_std_read_flush, s_filter_close
+};
+
+const stream_procs s_filter_write_procs =
+{
+ s_std_noavailable, s_std_noseek, s_std_write_reset,
+ s_std_write_flush, s_filter_close
+};
+
+/* ------ Implementation-independent procedures ------ */
+
+/* Store the amount of available data in a(n input) stream. */
+int
+savailable(stream * s, long *pl)
+{
+ return (*(s)->procs.available) (s, pl);
+}
+
+/* Return the current position of a stream. */
+long
+stell(stream * s)
+{ /* The stream might have been closed, but the position */
+ /* is still meaningful in this case. */
+ const byte *ptr = (s_is_writing(s) ? s->swptr : s->srptr);
+
+ return (ptr == 0 ? 0 : ptr + 1 - s->cbuf) + s->position;
+}
+
+/* Set the position of a stream. */
+int
+spseek(stream * s, long pos)
+{
+ if_debug3('s', "[s]seek 0x%lx to %ld, position was %ld\n",
+ (ulong) s, pos, stell(s));
+ return (*(s)->procs.seek) (s, pos);
+}
+
+/* Switch a stream to read or write mode. */
+/* Return 0 or ERRC. */
+int
+sswitch(register stream * s, bool writing)
+{
+ if (s->procs.switch_mode == 0)
+ return ERRC;
+ return (*s->procs.switch_mode) (s, writing);
+}
+
+/* Close a stream, disabling it if successful. */
+/* (The stream may already be closed.) */
+int
+sclose(register stream * s)
+{
+ stream_state *st;
+ int code = (*s->procs.close) (s);
+
+ if (code < 0)
+ return code;
+ st = s->state;
+ if (st != 0) {
+ stream_proc_release((*release)) = st->template->release;
+ if (release != 0)
+ (*release) (st);
+ if (st != (stream_state *) s && st->memory != 0)
+ gs_free_object(st->memory, st, "s_std_close");
+ s->state = (stream_state *) s;
+ }
+ s_disable(s);
+ return code;
+}
+
+/*
+ * Implement sgetc when the buffer may be empty.
+ * If the buffer really is empty, refill it and then read a byte.
+ * Note that filters must read one byte ahead, so that they can close immediately
+ * after the client reads the last data byte if the next thing is an EOD.
+ */
+int
+spgetcc(register stream * s, bool close_on_eof)
+{
+ int status, left;
+ int min_left = sbuf_min_left(s);
+
+ while (status = s->end_status,
+ left = s->srlimit - s->srptr,
+ left <= min_left && status >= 0
+ )
+ s_process_read_buf(s);
+ if (left <= min_left && (left == 0 || (status != EOFC && status != ERRC))) { /* Compact the stream so stell will return the right result. */
+ stream_compact(s, true);
+ if (status == EOFC && close_on_eof) {
+ status = sclose(s);
+ if (status == 0)
+ status = EOFC;
+ s->end_status = status;
+ }
+ return status;
+ }
+ return *++(s->srptr);
+}
+
+/* Implementing sputc when the buffer is full, */
+/* by flushing the buffer and then writing the byte. */
+int
+spputc(register stream * s, byte b)
+{
+ for (;;) {
+ if (s->end_status)
+ return s->end_status;
+ if (!sendwp(s)) {
+ *++(s->swptr) = b;
+ return b;
+ }
+ s_process_write_buf(s, false);
+ }
+}
+
+/* Push back a character onto a (read) stream. */
+/* The character must be the same as the last one read. */
+/* Return 0 on success, ERRC on failure. */
+int
+sungetc(register stream * s, byte c)
+{
+ if (!s_is_reading(s) || s->srptr < s->cbuf || *(s->srptr) != c)
+ return ERRC;
+ s->srptr--;
+ return 0;
+}
+
+/* Get a string from a stream. */
+/* Return 0 if the string was filled, or an exception status. */
+int
+sgets(stream * s, byte * buf, uint nmax, uint * pn)
+{
+ stream_cursor_write cw;
+ int status = 0;
+ int min_left = sbuf_min_left(s);
+
+ cw.ptr = buf - 1;
+ cw.limit = cw.ptr + nmax;
+ while (cw.ptr < cw.limit) {
+ int left;
+
+ if ((left = s->srlimit - s->srptr) > min_left) {
+ s->srlimit -= min_left;
+ stream_move(&s->cursor.r, &cw);
+ s->srlimit += min_left;
+ } else {
+ uint wanted = cw.limit - cw.ptr;
+ int c;
+ stream_state *st;
+
+ if (wanted >= s->bsize >> 2 &&
+ (st = s->state) != 0 &&
+ wanted >= st->template->min_out_size &&
+ s->end_status == 0 &&
+ left == 0
+ ) {
+ byte *wptr = cw.ptr;
+
+ cw.limit -= min_left;
+ status = sreadbuf(s, &cw);
+ cw.limit += min_left;
+ /* We know the stream buffer is empty, */
+ /* so it's safe to update position. */
+ s->position += cw.ptr - wptr;
+ if (status != 1 || cw.ptr == cw.limit)
+ break;
+ }
+ c = spgetc(s);
+ if (c < 0) {
+ status = c;
+ break;
+ }
+ *++(cw.ptr) = c;
+ }
+ }
+ *pn = cw.ptr + 1 - buf;
+ return (status >= 0 ? 0 : status);
+}
+
+/* Write a string on a stream. */
+/* Return 0 if the entire string was written, or an exception status. */
+int
+sputs(register stream * s, const byte * str, uint wlen, uint * pn)
+{
+ uint len = wlen;
+ int status = s->end_status;
+
+ if (status >= 0)
+ while (len > 0) {
+ uint count = s->swlimit - s->swptr;
+
+ if (count > 0) {
+ if (count > len)
+ count = len;
+ memcpy(s->swptr + 1, str, count);
+ s->swptr += count;
+ str += count;
+ len -= count;
+ } else {
+ byte ch = *str++;
+
+ status = sputc(s, ch);
+ if (status < 0)
+ break;
+ len--;
+ }
+ }
+ *pn = wlen - len;
+ return (status >= 0 ? 0 : status);
+}
+
+/* Skip ahead a specified distance in a read stream. */
+/* Return 0 or an exception code. */
+/* Store the number of bytes skipped in *pskipped. */
+int
+spskip(register stream * s, long nskip, long *pskipped)
+{
+ long n = nskip;
+ int min_left;
+
+ if (nskip < 0 || !s_is_reading(s)) {
+ *pskipped = 0;
+ return ERRC;
+ }
+ if (s_can_seek(s)) {
+ long pos = stell(s);
+ int code = sseek(s, pos + n);
+
+ *pskipped = stell(s) - pos;
+ return code;
+ }
+ min_left = sbuf_min_left(s);
+ while (sbufavailable(s) < n + min_left) {
+ int code;
+
+ n -= sbufavailable(s);
+ s->srptr = s->srlimit;
+ if (s->end_status) {
+ *pskipped = nskip - n;
+ return s->end_status;
+ }
+ code = sgetc(s);
+ if (code < 0) {
+ *pskipped = nskip - n;
+ return code;
+ }
+ --n;
+ }
+ /* Note that if min_left > 0, n < 0 is possible; this is harmless. */
+ s->srptr += n;
+ *pskipped = nskip;
+ return 0;
+}
+
+/* ------ Utilities ------ */
+
+/*
+ * Attempt to refill the buffer of a read stream. Only call this if the
+ * end_status is not EOFC, and if the buffer is (nearly) empty.
+ */
+int
+s_process_read_buf(stream * s)
+{
+ int status;
+
+ stream_compact(s, false);
+ status = sreadbuf(s, &s->cursor.w);
+ s->end_status = (status >= 0 ? 0 : status);
+ return 0;
+}
+
+/*
+ * Attempt to empty the buffer of a write stream. Only call this if the
+ * end_status is not EOFC.
+ */
+int
+s_process_write_buf(stream * s, bool last)
+{
+ int status = swritebuf(s, &s->cursor.r, last);
+
+ stream_compact(s, false);
+ if (status >= 0)
+ status = 0;
+ s->end_status = status;
+ return status;
+}
+
+/* Move forward or backward in a pipeline. We temporarily reverse */
+/* the direction of the pointers while doing this. */
+/* (Cf the Deutsch-Schorr-Waite graph marking algorithm.) */
+#define move_back(curr, prev)\
+{ stream *back = prev->strm;\
+ prev->strm = curr; curr = prev; prev = back;\
+}
+#define move_ahead(curr, prev)\
+{ stream *ahead = curr->strm;\
+ curr->strm = prev; prev = curr; curr = ahead;\
+}
+
+/* Read from a pipeline. */
+private int
+sreadbuf(stream * s, stream_cursor_write * pbuf)
+{
+ stream *prev = 0;
+ stream *curr = s;
+ int status;
+
+ for (;;) {
+ stream *strm;
+
+ for (;;) { /* Descend into the recursion. */
+ stream_cursor_read cr;
+ stream_cursor_read *pr;
+ stream_cursor_write *pw;
+ bool eof;
+
+ strm = curr->strm;
+ if (strm == 0) {
+ cr.ptr = 0, cr.limit = 0;
+ pr = &cr;
+ eof = false;
+ } else {
+ pr = &strm->cursor.r;
+ eof = strm->end_status == EOFC;
+ }
+ pw = (prev == 0 ? pbuf : &curr->cursor.w);
+ if_debug4('s', "[s]read process 0x%lx, nr=%u, nw=%u, eof=%d\n",
+ (ulong) curr, (uint) (pr->limit - pr->ptr),
+ (uint) (pw->limit - pw->ptr), eof);
+ status = (*curr->procs.process) (curr->state, pr, pw, eof);
+ if_debug4('s', "[s]after read 0x%lx, nr=%u, nw=%u, status=%d\n",
+ (ulong) curr, (uint) (pr->limit - pr->ptr),
+ (uint) (pw->limit - pw->ptr), status);
+ if (strm == 0 || status != 0)
+ break;
+ status = strm->end_status;
+ if (status < 0)
+ break;
+ move_ahead(curr, prev);
+ stream_compact(curr, false);
+ }
+ /* If curr reached EOD and is a filter stream, close it. */
+ if (strm != 0 && status == EOFC &&
+ curr->cursor.r.ptr >= curr->cursor.r.limit
+ ) {
+ int cstat = sclose(curr);
+
+ if (cstat != 0)
+ status = cstat;
+ }
+#if 0
+ /* If we need to do a callout, unwind all the way now. */
+ if (status == CALLC) {
+ while ((curr->end_status = status), prev != 0) {
+ move_back(curr, prev);
+ }
+ return status;
+ }
+#endif
+ /* Unwind from the recursion. */
+ curr->end_status = (status >= 0 ? 0 : status);
+ if (prev == 0)
+ return status;
+ move_back(curr, prev);
+ }
+}
+
+/* Write to a pipeline. */
+private int
+swritebuf(stream * s, stream_cursor_read * pbuf, bool last)
+{
+ stream *prev = 0;
+ stream *curr = s;
+ int depth = 0; /* depth of nesting in non-temp streams */
+ int status;
+
+ /*
+ * The handling of EOFC is a little tricky. There are two
+ * invariants that keep it straight:
+ * - We only pass last = true to a stream if either it is
+ * the first stream in the pipeline, or it is a temporary stream
+ * below the first stream and the stream immediately above it has
+ * end_status = EOFC.
+ * - We never unwind the recursion past a stream with
+ * end_status < 0.
+ */
+ for (;;) {
+ for (;;) { /* Descend into the recursion. */
+ stream *strm = curr->strm;
+ stream_cursor_write cw;
+ stream_cursor_read *pr;
+ stream_cursor_write *pw;
+
+ /*
+ * We only want to set the last/end flag for
+ * the top-level stream and any temporary streams
+ * immediately below it.
+ */
+ bool end = last &&
+ (prev == 0 ||
+ (depth <= 1 && prev->end_status == EOFC));
+
+ if (strm == 0)
+ cw.ptr = 0, cw.limit = 0, pw = &cw;
+ else
+ pw = &strm->cursor.w;
+ if (prev == 0)
+ pr = pbuf;
+ else
+ pr = &curr->cursor.r;
+ if_debug4('s', "[s]write process 0x%lx, nr=%u, nw=%u, end=%d\n",
+ (ulong) curr, (uint) (pr->limit - pr->ptr),
+ (uint) (pw->limit - pw->ptr), end);
+ status = curr->end_status;
+ if (status < 0)
+ break;
+ status = (*curr->procs.process) (curr->state,
+ pr, pw, end);
+ if_debug5('s', "[s]after write 0x%lx, nr=%u, nw=%u, end=%d, status=%d\n",
+ (ulong) curr, (uint) (pr->limit - pr->ptr),
+ (uint) (pw->limit - pw->ptr), end, status);
+ if (status == 0 && end)
+ status = EOFC;
+ if (status == EOFC || status == ERRC)
+ curr->end_status = status;
+ if (strm == 0 || (status < 0 && status != EOFC))
+ break;
+ if (status == 1)
+ end = false;
+ else { /* Keep going if we are closing */
+ /* a filter with a sub-stream. */
+ /* We know status == 0 or EOFC. */
+ if (!end || !strm->is_temp)
+ break;
+ }
+ status = strm->end_status;
+ if (status < 0)
+ break;
+ move_ahead(curr, prev);
+ stream_compact(curr, false);
+ if (!curr->is_temp)
+ ++depth;
+ }
+ /* Unwind from the recursion. */
+ curr->end_status = (status >= 0 ? 0 : status);
+ if (status < 0 || prev == 0) { /*
+ * All streams above here were called with last = true
+ * and returned 0 or EOFC: finish unwinding and then
+ * return.
+ */
+ while (prev) {
+ move_back(curr, prev);
+ curr->end_status = (status >= 0 ? 0 : status);
+ }
+ return status;
+ }
+ move_back(curr, prev);
+ if (!curr->is_temp)
+ --depth;
+ }
+}
+
+/* Move as much data as possible from one buffer to another. */
+/* Return 0 if the input became empty, 1 if the output became full. */
+int
+stream_move(stream_cursor_read * pr, stream_cursor_write * pw)
+{
+ uint rcount = pr->limit - pr->ptr;
+ uint wcount = pw->limit - pw->ptr;
+ uint count;
+ int status;
+
+ if (rcount <= wcount)
+ count = rcount, status = 0;
+ else
+ count = wcount, status = 1;
+ memmove(pw->ptr + 1, pr->ptr + 1, count);
+ pr->ptr += count;
+ pw->ptr += count;
+ return status;
+}
+
+/* If possible, compact the information in a stream buffer to the bottom. */
+private void
+stream_compact(stream * s, bool always)
+{
+ if (s->cursor.r.ptr >= s->cbuf && (always || s->end_status >= 0)) {
+ uint dist = s->cursor.r.ptr + 1 - s->cbuf;
+
+ memmove(s->cbuf, s->cursor.r.ptr + 1,
+ (uint) (s->cursor.r.limit - s->cursor.r.ptr));
+ s->cursor.r.ptr = s->cbuf - 1;
+ s->cursor.r.limit -= dist; /* same as w.ptr */
+ s->position += dist;
+ }
+}
+
+/* ------ String streams ------ */
+
+/* String stream procedures */
+private int
+ s_string_available(P2(stream *, long *)), s_string_read_seek(P2(stream *, long)),
+ s_string_write_seek(P2(stream *, long)), s_string_read_process(P4(stream_state *, stream_cursor_read *,
+ stream_cursor_write *, bool)),
+ s_string_write_process(P4(stream_state *, stream_cursor_read *,
+ stream_cursor_write *, bool));
+
+/* Initialize a stream for reading a string. */
+void
+sread_string(register stream * s, const byte * ptr, uint len)
+{
+ static const stream_procs p =
+ {s_string_available, s_string_read_seek, s_std_read_reset,
+ s_std_read_flush, s_std_null, s_string_read_process
+ };
+
+ s_std_init(s, (byte *) ptr, len, &p, s_mode_read + s_mode_seek);
+ s->cbuf_string.data = (byte *) ptr;
+ s->cbuf_string.size = len;
+ s->end_status = EOFC;
+ s->srlimit = s->swlimit;
+}
+/* Return the number of available bytes when reading from a string. */
+private int
+s_string_available(stream * s, long *pl)
+{
+ *pl = sbufavailable(s);
+ if (*pl == 0) /* EOF */
+ *pl = -1;
+ return 0;
+}
+
+/* Seek in a string being read. Return 0 if OK, ERRC if not. */
+private int
+s_string_read_seek(register stream * s, long pos)
+{
+ if (pos < 0 || pos > s->bsize)
+ return ERRC;
+ s->srptr = s->cbuf + pos - 1;
+ return 0;
+}
+
+/* Initialize a stream for writing a string. */
+void
+swrite_string(register stream * s, byte * ptr, uint len)
+{
+ static const stream_procs p =
+ {s_std_noavailable, s_string_write_seek, s_std_write_reset,
+ s_std_null, s_std_null, s_string_write_process
+ };
+
+ s_std_init(s, ptr, len, &p, s_mode_write + s_mode_seek);
+ s->cbuf_string.data = ptr;
+ s->cbuf_string.size = len;
+}
+
+/* Seek in a string being written. Return 0 if OK, ERRC if not. */
+private int
+s_string_write_seek(register stream * s, long pos)
+{
+ if (pos < 0 || pos > s->bsize)
+ return ERRC;
+ s->swptr = s->cbuf + pos - 1;
+ return 0;
+}
+
+/* Since we initialize the input buffer of a string read stream */
+/* to contain all of the data in the string, if we are ever asked */
+/* to refill the buffer, we should signal EOF. */
+private int
+s_string_read_process(stream_state * st, stream_cursor_read * ignore_pr,
+ stream_cursor_write * pw, bool last)
+{
+ return EOFC;
+}
+/* Similarly, if we are ever asked to empty the buffer, it means that */
+/* there has been an overrun (unless we are closing the stream). */
+private int
+s_string_write_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * ignore_pw, bool last)
+{
+ return (last ? EOFC : ERRC);
+}
+
+/* ------ Position-tracking stream ------ */
+
+private int
+ s_write_position_process(P4(stream_state *, stream_cursor_read *,
+ stream_cursor_write *, bool));
+
+/* Set up a write stream that just keeps track of the position. */
+void
+swrite_position_only(stream *s)
+{
+ static byte buf[50]; /* size is arbitrary */
+
+ swrite_string(s, buf, sizeof(buf));
+ s->procs.process = s_write_position_process;
+}
+
+private int
+s_write_position_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * ignore_pw, bool last)
+{
+ pr->ptr = pr->limit; /* discard data */
+ return 0;
+}
diff --git a/pstoraster/stream.h b/pstoraster/stream.h
new file mode 100644
index 000000000..a0546e6af
--- /dev/null
+++ b/pstoraster/stream.h
@@ -0,0 +1,334 @@
+/* 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$ */
+/* Definitions for Ghostscript stream package */
+/* Requires stdio.h */
+
+#ifndef stream_INCLUDED
+# define stream_INCLUDED
+
+#include "scommon.h"
+
+/* See scommon.h for documentation on the design of streams. */
+
+/* ------ Stream structure definition ------ */
+
+/*
+ * We expose the stream structure definition to clients so that
+ * they can get reasonable performance out of the basic operations.
+ */
+
+/* Define the "virtual" stream procedures. */
+
+typedef struct {
+
+ /* Store # available for reading. */
+ /* Return 0 if OK, ERRC if error or not implemented. */
+#define stream_proc_available(proc)\
+ int proc(P2(stream *, long *))
+ stream_proc_available((*available));
+
+ /* Set position. */
+ /* Return 0 if OK, ERRC if error or not implemented. */
+#define stream_proc_seek(proc)\
+ int proc(P2(stream *, long))
+ stream_proc_seek((*seek));
+
+ /* Clear buffer and, if relevant, unblock channel. */
+ /* Cannot cause an error. */
+#define stream_proc_reset(proc)\
+ void proc(P1(stream *))
+ stream_proc_reset((*reset));
+
+ /* Flush buffered data to output, or drain input. */
+ /* Return 0 if OK, ERRC if error. */
+#define stream_proc_flush(proc)\
+ int proc(P1(stream *))
+ stream_proc_flush((*flush));
+
+ /* Flush data (if writing) & close stream. */
+ /* Return 0 if OK, ERRC if error. */
+#define stream_proc_close(proc)\
+ int proc(P1(stream *))
+ stream_proc_close((*close));
+
+ /* Process a buffer, updating the cursor pointers. */
+ /* See strimpl.h for details. */
+ stream_proc_process((*process));
+
+ /* Switch the stream to read or write mode. */
+ /* false = read, true = write. */
+ /* If the procedure is 0, switching is not allowed. */
+#define stream_proc_switch_mode(proc)\
+ int proc(P2(stream *, bool))
+ stream_proc_switch_mode((*switch_mode));
+
+} stream_procs;
+
+/* ------ The actual stream structure ------ */
+
+struct stream_s {
+ /*
+ * To allow the stream itself to serve as the "state"
+ * of a couple of heavily used types, we start its
+ * definition with the common stream state.
+ */
+ stream_state_common;
+ stream_cursor cursor; /* cursor for reading/writing data */
+ byte *cbuf; /* base of buffer */
+ uint bsize; /* size of buffer, 0 if closed */
+ uint cbsize; /* size of buffer */
+ /*
+ * end_status indicates what should happen when the client
+ * reaches the end of the buffer:
+ * 0 in the normal case;
+ * EOFC if a read stream has reached EOD or a write
+ * stream has written the EOD marker;
+ * ERRC if an error terminated the last read or write
+ * operation from or to the underlying data source
+ * or sink;
+ * INTC if the last transfer was interrupted (NOT
+ * USED YET);
+ * CALLC if a callout is required.
+ */
+ short end_status; /* status at end of buffer (when */
+ /* reading) or now (when writing) */
+ byte foreign; /* true if buffer is outside heap */
+ byte modes; /* access modes allowed for this */
+ /* stream */
+#define s_mode_read 1
+#define s_mode_write 2
+#define s_mode_seek 4
+#define s_mode_append 8 /* (s_mode_write also set) */
+#define s_is_valid(s) ((s)->modes != 0)
+#define s_is_reading(s) (((s)->modes & s_mode_read) != 0)
+#define s_is_writing(s) (((s)->modes & s_mode_write) != 0)
+#define s_can_seek(s) (((s)->modes & s_mode_seek) != 0)
+ gs_string cbuf_string; /* cbuf/cbsize if cbuf is a string, */
+ /* 0/? if not */
+ long position; /* file position of beginning of */
+ /* buffer */
+ stream_procs procs;
+ stream *strm; /* the underlying stream, non-zero */
+ /* iff this is a filter stream */
+ int is_temp; /* if >0, this is a temporary */
+ /* stream and should be freed */
+ /* when its source/sink is closed; */
+ /* if >1, the buffer is also */
+ /* temporary */
+ int inline_temp; /* temporary for inline access */
+ /* (see spgetc_inline below) */
+ stream_state *state; /* state of process */
+ /*
+ * The following are for the use of the interpreter.
+ * See files.h for more information on read_id and write_id,
+ * zfile.c for more information on prev and next,
+ * zfilter.c for more information on close_strm.
+ */
+ ushort read_id; /* "unique" serial # for detecting */
+ /* references to closed streams */
+ /* and for validating read access */
+ ushort write_id; /* ditto to validate write access */
+ stream *prev, *next; /* keep track of all files */
+ bool close_strm; /* CloseSource/CloseTarget */
+ /*
+ * In order to avoid allocating a separate stream_state for
+ * file streams, which are the most heavily used stream type,
+ * we put their state here.
+ */
+ FILE *file; /* file handle for C library */
+ uint file_modes; /* access modes for the file, */
+ /* may be a superset of modes */
+ int (*save_close)(P1(stream *)); /* save original close proc */
+};
+
+#define private_st_stream() /* in stream.c */\
+ gs_private_st_composite_final(st_stream, stream, "stream",\
+ stream_enum_ptrs, stream_reloc_ptrs, stream_finalize)
+
+/* Initialize the checking IDs of a stream. */
+#define s_init_ids(s) ((s)->read_id = (s)->write_id = 1)
+#define s_init_read_id(s) ((s)->read_id = 1, (s)->write_id = 0)
+#define s_init_write_id(s) ((s)->read_id = 0, (s)->write_id = 1)
+#define s_init_no_id(s) ((s)->read_id = (s)->write_id = 0)
+
+/* ------ Stream functions ------ */
+
+#define srptr cursor.r.ptr
+#define srlimit cursor.r.limit
+#define swptr cursor.w.ptr
+#define swlimit cursor.w.limit
+
+/* Some of these are macros -- beware. */
+/* Note that unlike the C stream library, */
+/* ALL stream procedures take the stream as the first argument. */
+#define sendrp(s) ((s)->srptr >= (s)->srlimit) /* NOT FOR CLIENTS */
+#define sendwp(s) ((s)->swptr >= (s)->swlimit) /* NOT FOR CLIENTS */
+
+/*
+ * Following are valid for all streams.
+ */
+/* flush is NOT a no-op for read streams -- it discards data until EOF. */
+/* close is NOT a no-op for non-file streams -- */
+/* it actively disables them. */
+/* The close routine must do a flush if needed. */
+#define sseekable(s) s_can_seek(s)
+int savailable(P2(stream *, long *));
+
+#define sreset(s) (*(s)->procs.reset)(s)
+#define sflush(s) (*(s)->procs.flush)(s)
+int sclose(P1(stream *));
+int sswitch(P2(stream *, bool));
+
+/*
+ * Following are only valid for read streams.
+ */
+int spgetcc(P2(stream *, bool)); /* bool indicates close-on-EOD */
+
+#define spgetc(s) spgetcc(s, true) /* a procedure equivalent of sgetc */
+/*
+ * Note that sgetc must call spgetc one byte early, because filter must read ahead
+ * to detect EOD.
+ *
+ * In the definition of sgetc, the first alternative should read
+ * (int)(*++((s)->srptr))
+ * but the Borland compiler generates truly atrocious code for this.
+ * The SCO ODT compiler requires the first, pointless cast to int.
+ */
+#define sgetc(s)\
+ ((int)((s)->srlimit - (s)->srptr > 1 ? (++((s)->srptr), (int)*(s)->srptr) : spgetc(s)))
+int sgets(P4(stream *, byte *, uint, uint *));
+int sungetc(P2(stream *, byte)); /* ERRC on error, 0 if OK */
+
+#define sputback(s) ((s)->srptr--) /* can only do this once! */
+#define seofp(s) (sendrp(s) && (s)->end_status == EOFC)
+#define serrorp(s) (sendrp(s) && (s)->end_status == ERRC)
+int spskip(P3(stream *, long, long *));
+
+#define sskip(s,nskip,pskipped) spskip(s, (long)(nskip), pskipped)
+/*
+ * Attempt to refill the buffer of a read stream.
+ * Only call this if the end_status is not EOFC,
+ * and if the buffer is (nearly) empty.
+ */
+int s_process_read_buf(P1(stream *));
+
+/*
+ * Following are only valid for write streams.
+ */
+int spputc(P2(stream *, byte)); /* a procedure equivalent of sputc */
+
+/*
+ * The first alternative should read
+ * ((int)(*++((s)->swptr)=(c)))
+ * but the Borland compiler generates truly atrocious code for this.
+ */
+#define sputc(s,c)\
+ (!sendwp(s) ? (++((s)->swptr), *(s)->swptr=(c), 0) : spputc((s),(c)))
+int sputs(P4(stream *, const byte *, uint, uint *));
+
+/*
+ * Attempt to empty the buffer of a write stream.
+ * Only call this if the end_status is not EOFC.
+ */
+int s_process_write_buf(P2(stream *, bool));
+
+/* Following are only valid for positionable streams. */
+long stell(P1(stream *));
+int spseek(P2(stream *, long));
+
+#define sseek(s,pos) spseek(s, (long)(pos))
+
+/* Following are for high-performance reading clients. */
+/* bufptr points to the next item. */
+#define sbufptr(s) ((s)->srptr + 1)
+#define sbufavailable(s) ((s)->srlimit - (s)->srptr)
+#define sbufskip(s, n) ((s)->srptr += (n), 0)
+/*
+ * Define the minimum amount of data that must be left in an input buffer
+ * after a read operation to handle filter read-ahead. This is 1 byte for
+ * filters (including procedure data sources), 0 for files.
+ */
+#define max_min_left 1
+#define sbuf_min_left(s) (s->strm == 0 && s->end_status != CALLC ? 0 : 1)
+
+/* The following are for very high-performance clients of read streams, */
+/* who unpack the stream state into local variables. */
+/* Note that any non-inline operations must do a s_end_inline before, */
+/* and a s_begin_inline after. */
+#define s_declare_inline(s, cp, ep)\
+ register const byte *cp;\
+ const byte *ep
+#define s_begin_inline(s, cp, ep)\
+ cp = (s)->srptr, ep = (s)->srlimit
+#define s_end_inline(s, cp, ep)\
+ (s)->srptr = cp
+#define sbufavailable_inline(s, cp, ep)\
+ (ep - cp)
+#define sendbufp_inline(s, cp, ep)\
+ (cp >= ep)
+/* The (int) is needed to pacify the SCO ODT compiler. */
+#define sgetc_inline(s, cp, ep)\
+ ((int)(sendbufp_inline(s, cp, ep) ? spgetc_inline(s, cp, ep) : *++cp))
+#define spgetc_inline(s, cp, ep)\
+ (s_end_inline(s, cp, ep), (s)->inline_temp = spgetc(s),\
+ s_begin_inline(s, cp, ep), (s)->inline_temp)
+#define sputback_inline(s, cp, ep)\
+ --cp
+
+/* Allocate a stream or a stream state. */
+stream *s_alloc(P2(gs_memory_t *, client_name_t));
+stream_state *s_alloc_state(P3(gs_memory_t *, gs_memory_type_ptr_t, client_name_t));
+
+/* Create a stream on a string or a file. */
+void sread_string(P3(stream *, const byte *, uint)),
+ swrite_string(P3(stream *, byte *, uint));
+void sread_file(P4(stream *, FILE *, byte *, uint)),
+ swrite_file(P4(stream *, FILE *, byte *, uint)),
+ sappend_file(P4(stream *, FILE *, byte *, uint));
+
+/* Create a stream that tracks the position, */
+/* for calculating how much space to allocate when actually writing. */
+void swrite_position_only(P1(stream *));
+
+/* Standard stream initialization */
+void s_std_init(P5(stream *, byte *, uint, const stream_procs *, int /*mode */ ));
+
+/* Standard stream finalization */
+void s_disable(P1(stream *));
+
+/* Generic stream procedures exported for templates */
+int s_std_null(P1(stream *));
+void s_std_read_reset(P1(stream *)), s_std_write_reset(P1(stream *));
+int s_std_read_flush(P1(stream *)), s_std_write_flush(P1(stream *)), s_std_noavailable(P2(stream *, long *)),
+ s_std_noseek(P2(stream *, long)), s_std_close(P1(stream *)), s_std_switch_mode(P2(stream *, bool));
+
+/* Generic procedures for filters. */
+int s_filter_write_flush(P1(stream *)), s_filter_close(P1(stream *));
+
+/* Generic procedure structures for filters. */
+extern const stream_procs s_filter_read_procs, s_filter_write_procs;
+
+#endif /* stream_INCLUDED */
diff --git a/pstoraster/strimpl.h b/pstoraster/strimpl.h
new file mode 100644
index 000000000..6ba9560ff
--- /dev/null
+++ b/pstoraster/strimpl.h
@@ -0,0 +1,154 @@
+/* Copyright (C) 1993, 1995, 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$ */
+/* Definitions for stream implementors */
+/* Requires stdio.h */
+
+#ifndef strimpl_INCLUDED
+# define strimpl_INCLUDED
+
+#include "scommon.h"
+#include "gstypes.h" /* for gsstruct.h */
+#include "gsstruct.h"
+
+/*
+ * The 'process' procedure does the real work of the stream.
+ * It must process as much input information (from pr->ptr + 1 through
+ * pr->limit) as it can, subject to space available for output
+ * (pw->ptr + 1 through pw->limit), updating pr->ptr and pw->ptr.
+ *
+ * The procedure return value must be one of:
+ * EOFC - an end-of-data pattern was detected in the input,
+ * or no more input can be processed for some other reason (e.g.,
+ * the stream was told only to read a certain amount of data).
+ * ERRC - a syntactic error was detected in the input.
+ * 0 - more input data is needed.
+ * 1 - more output space is needed.
+ * If the procedure returns EOFC, it can assume it will never be called
+ * again for that stream.
+ *
+ * If the procedure is called with last = 1, this is an indication that
+ * no more input will ever be supplied (after the input in the current
+ * buffer defined by *pr); the procedure should produce as much output
+ * as possible, including an end-of-data marker if applicable. In this
+ * case:
+ * - If the procedure returns 1, it may be called again (also with
+ * last = 1).
+ * - If the procedure returns any other value other than 1, the
+ * procedure will never be called again for that stream.
+ * - If the procedure returns 0, this is taken as equivalent to
+ * returning EOFC.
+ * - If the procedure returns EOFC (or 0), the stream's end_status
+ * is set to EOFC, meaning no more writing is allowed.
+ *
+ * Note that these specifications do not distinguish input from output
+ * streams. This is deliberate: The processing procedures should work
+ * regardless of which way they are oriented in a stream pipeline.
+ * (The PostScript language does take a position as whether any given
+ * filter may be used for input or output, but this occurs at a higher level.)
+ *
+ * The value returned by the process procedure of a stream whose data source
+ * or sink is external (i.e., not another stream) is interpreted slightly
+ * differently. For an external data source, a return value of 0 means
+ * "no more input data are available now, but more might become available
+ * later." For an external data sink, a return value of 1 means "there is
+ * no more room for output data now, but there might be room later."
+ *
+ * It appears that the Adobe specifications, read correctly, require that when
+ * the process procedure of a decoding filter has filled up the output
+ * buffer, it must still peek ahead in the input to determine whether or not
+ * the next thing in the input stream is EOD. If the next thing is an EOD (or
+ * end-of-data, indicated by running out of input data with last = true), the
+ * process procedure must return EOFC; if the next thing is definitely not
+ * an EOD, the process procedure must return 1 (output full) (without, of
+ * course, consuming the non-EOD datum); if the procedure cannot determine
+ * whether or not the next thing is an EOD, it must return 0 (need more input).
+ * Decoding filters that don't have EOD (for example, NullDecode) can use
+ * a simpler algorithm: if the output buffer is full, then if there is more
+ * input, return 1, otherwise return 0 (which is taken as EOFC if last
+ * is true). All this may seem a little awkward, but it is needed in order
+ * to have consistent behavior regardless of where buffer boundaries fall --
+ * in particular, if a buffer boundary falls just before an EOD. It is
+ * actually quite easy to implement if the main loop of the process
+ * procedure tests for running out of input rather than for filling the
+ * output: with this structure, exhausting the input always returns 0,
+ * and discovering that the output buffer is full when attempting to store
+ * more output always returns 1.
+ *
+ * Even this algorithm for handling end-of-buffer is not sufficient if an
+ * EOD falls just after a buffer boundary, but the generic stream code
+ * handles this case: the process procedures need only do what was just
+ * described.
+ */
+
+/*
+ * Define a template for creating a stream.
+ *
+ * The meaning of min_in_size and min_out_size is the following:
+ * If the amount of input information is at least min_in_size,
+ * and the available output space is at least min_out_size,
+ * the process procedure guarantees that it will make some progress.
+ * (It may make progress even if this condition is not met, but this is
+ * not guaranteed.)
+ */
+struct stream_template_s {
+
+ /* Define the structure type for the stream state. */
+ gs_memory_type_ptr_t stype;
+
+ /* Define an optional initialization procedure. */
+ stream_proc_init((*init));
+
+ /* Define the processing procedure. */
+ /* (The init procedure can reset other procs if it wants.) */
+ stream_proc_process((*process));
+
+ /* Define the minimum buffer sizes. */
+ uint min_in_size; /* minimum size for process input */
+ uint min_out_size; /* minimum size for process output */
+
+ /* Define an optional releasing procedure. */
+ stream_proc_release((*release));
+
+ /* Define an optional parameter defaulting procedure. */
+ stream_proc_set_defaults((*set_defaults));
+
+ /* Define an optional reinitialization procedure. */
+ stream_proc_reinit((*reinit));
+
+};
+
+/* Utility procedures */
+int stream_move(P2(stream_cursor_read *, stream_cursor_write *)); /* in stream.c */
+
+/* Hex decoding utility procedure */
+typedef enum {
+ hex_ignore_garbage = 0,
+ hex_ignore_whitespace = 1,
+ hex_ignore_leading_whitespace = 2
+} hex_syntax;
+int s_hex_process(P4(stream_cursor_read *, stream_cursor_write *, int *, hex_syntax)); /* in sstring.c */
+
+#endif /* strimpl_INCLUDED */
diff --git a/pstoraster/string_.h b/pstoraster/string_.h
new file mode 100644
index 000000000..7771125a3
--- /dev/null
+++ b/pstoraster/string_.h
@@ -0,0 +1,59 @@
+/* Copyright (C) 1989, 1992, 1993, 1994, 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 string.h */
+
+#ifndef string__INCLUDED
+# define string__INCLUDED
+
+/* We must include std.h before any file that includes sys/types.h. */
+#include "std.h"
+
+#ifdef BSD4_2
+# include <strings.h>
+# define strchr index
+#else
+# ifdef __TURBOC__
+# undef memset /* just in case */
+# include <string.h>
+# ifndef memset /* Borland C++ can inline this */
+# define memset(dest,chr,cnt) setmem(dest,cnt,chr)
+# endif
+# else
+# ifdef memory__need_memmove
+# undef memmove /* This is disgusting, but so is GCC */
+# endif
+# include <string.h>
+# if defined(THINK_C)
+ /* Patch strlen to return a uint rather than a size_t. */
+# define strlen (uint)strlen
+# endif
+# ifdef memory__need_memmove
+# define memmove(dest,src,len) gs_memmove(dest,src,len)
+# endif
+# endif
+#endif
+
+#endif /* string__INCLUDED */
diff --git a/pstoraster/szlibc.c b/pstoraster/szlibc.c
new file mode 100644
index 000000000..576e84e41
--- /dev/null
+++ b/pstoraster/szlibc.c
@@ -0,0 +1,151 @@
+/*
+ Copyright 1993-2002 by Easy Software Products
+ Copyright 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.
+*/
+#include <config.h>
+#ifdef HAVE_LIBZ
+
+/*$Id$ */
+/* Code common to zlib encoding and decoding streams */
+#include "std.h"
+#include "gserror.h"
+#include "gserrors.h"
+#include "gstypes.h"
+#include "gsmemory.h"
+#include "gsmalloc.h"
+#include "gsstruct.h"
+#include "strimpl.h"
+#include "szlibxx.h"
+#include "zconf.h"
+
+private_st_zlib_block();
+private_st_zlib_dynamic_state();
+/*public_st_zlib_state();*/
+
+private const gc_ptr_element_t zlib_state_enum_ptrs[] = {
+ GC_OBJ_ELT(stream_zlib_state, dynamic)
+};
+private const gc_struct_data_t zlib_state_reloc_ptrs = {
+ countof(zlib_state_enum_ptrs), 0, 0, zlib_state_enum_ptrs
+};
+gs_memory_struct_type_t st_zlib_state = {
+ sizeof(stream_zlib_state), "zlibEncode/Decode state", 0, 0,
+ basic_enum_ptrs, basic_reloc_ptrs, 0, &zlib_state_reloc_ptrs
+};
+
+/* Set defaults for stream parameters. */
+void
+s_zlib_set_defaults(stream_state * st)
+{
+ stream_zlib_state *const ss = (stream_zlib_state *)st;
+
+ ss->windowBits = MAX_WBITS;
+ ss->no_wrapper = false;
+ ss->level = Z_DEFAULT_COMPRESSION;
+ ss->method = Z_DEFLATED;
+ /* DEF_MEM_LEVEL should be in zlib.h or zconf.h, but it isn't. */
+ ss->memLevel = min(MAX_MEM_LEVEL, 8);
+ ss->strategy = Z_DEFAULT_STRATEGY;
+}
+
+/* Allocate the dynamic state. */
+int
+s_zlib_alloc_dynamic_state(stream_zlib_state *ss)
+{
+ gs_memory_t *mem = (ss->memory ? ss->memory : &gs_memory_default);
+ zlib_dynamic_state_t *zds =
+ gs_alloc_struct_immovable(mem, zlib_dynamic_state_t,
+ &st_zlib_dynamic_state,
+ "s_zlib_alloc_dynamic_state");
+
+ ss->dynamic = zds;
+ if (zds == 0)
+ return_error(gs_error_VMerror);
+ zds->blocks = 0;
+ zds->memory = mem;
+ zds->zstate.zalloc = (alloc_func)s_zlib_alloc;
+ zds->zstate.zfree = (free_func)s_zlib_free;
+ zds->zstate.opaque = (voidpf)zds;
+ return 0;
+}
+
+/* Free the dynamic state. */
+void
+s_zlib_free_dynamic_state(stream_zlib_state *ss)
+{
+ if (ss->dynamic)
+ gs_free_object(ss->dynamic->memory, ss->dynamic,
+ "s_zlib_free_dynamic_state");
+}
+
+/* Provide zlib-compatible allocation and freeing functions. */
+void *
+s_zlib_alloc(void *zmem, uint items, uint size)
+{
+ zlib_dynamic_state_t *const zds = zmem;
+ gs_memory_t *mem = zds->memory;
+ zlib_block_t *block =
+ gs_alloc_struct(mem, zlib_block_t, &st_zlib_block,
+ "s_zlib_alloc(block)");
+ void *data =
+ gs_alloc_byte_array_immovable(mem, items, size, "s_zlib_alloc(data)");
+
+ if (block == 0 || data == 0) {
+ gs_free_object(mem, data, "s_zlib_alloc(data)");
+ gs_free_object(mem, block, "s_zlib_alloc(block)");
+ return Z_NULL;
+ }
+ block->data = data;
+ block->next = zds->blocks;
+ block->prev = 0;
+ if (zds->blocks)
+ zds->blocks->prev = block;
+ zds->blocks = block;
+ return data;
+}
+void
+s_zlib_free(void *zmem, void *data)
+{
+ zlib_dynamic_state_t *const zds = zmem;
+ gs_memory_t *mem = zds->memory;
+ zlib_block_t *block = zds->blocks;
+
+ gs_free_object(mem, data, "s_zlib_free(data)");
+ for (; ; block = block->next) {
+ if (block == 0) {
+ lprintf1("Freeing unrecorded data 0x%lx!\n", (ulong)data);
+ return;
+ }
+ if (block->data == data)
+ break;
+ }
+ if (block->next)
+ block->next->prev = block->prev;
+ if (block->prev)
+ block->prev->next = block->next;
+ else
+ zds->blocks = block->next;
+ gs_free_object(mem, block, "s_zlib_free(block)");
+}
+#endif
diff --git a/pstoraster/szlibd.c b/pstoraster/szlibd.c
new file mode 100644
index 000000000..7c4fbd19a
--- /dev/null
+++ b/pstoraster/szlibd.c
@@ -0,0 +1,118 @@
+/*
+ Copyright 1993-2002 by Easy Software Products.
+ Copyright 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.
+*/
+#include <config.h>
+#ifdef HAVE_LIBZ
+
+/*$Id$ */
+/* zlib decoding (decompression) filter stream */
+#include "std.h"
+#include "gsmemory.h"
+#include "gsmalloc.h" /* for gs_memory_default */
+#include "strimpl.h"
+#include "szlibxx.h"
+
+/* Initialize the filter. */
+private int
+s_zlibD_init(stream_state * st)
+{
+ stream_zlib_state *const ss = (stream_zlib_state *)st;
+ int code = s_zlib_alloc_dynamic_state(ss);
+
+ if (code < 0)
+ return ERRC; /****** WRONG ******/
+ if (inflateInit2(&ss->dynamic->zstate,
+ (ss->no_wrapper ? -ss->windowBits : ss->windowBits))
+ != Z_OK
+ ) {
+ s_zlib_free_dynamic_state(ss);
+ return ERRC; /****** WRONG ******/
+ }
+ return 0;
+}
+
+/* Reinitialize the filter. */
+private int
+s_zlibD_reset(stream_state * st)
+{
+ stream_zlib_state *const ss = (stream_zlib_state *)st;
+
+ if (inflateReset(&ss->dynamic->zstate) != Z_OK)
+ return ERRC; /****** WRONG ******/
+ return 0;
+}
+
+/* Process a buffer */
+private int
+s_zlibD_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool ignore_last)
+{
+ stream_zlib_state *const ss = (stream_zlib_state *)st;
+ z_stream *zs = &ss->dynamic->zstate;
+ const byte *p = pr->ptr;
+ int status;
+
+ /* Detect no input or full output so that we don't get */
+ /* a Z_BUF_ERROR return. */
+ if (pw->ptr == pw->limit)
+ return 1;
+ if (pr->ptr == pr->limit)
+ return 0;
+ zs->next_in = (Bytef *)p + 1;
+ zs->avail_in = pr->limit - p;
+ zs->next_out = pw->ptr + 1;
+ zs->avail_out = pw->limit - pw->ptr;
+ status = inflate(zs, Z_PARTIAL_FLUSH);
+ pr->ptr = zs->next_in - 1;
+ pw->ptr = zs->next_out - 1;
+ switch (status) {
+ case Z_OK:
+ return (pw->ptr == pw->limit ? 1 : pr->ptr > p ? 0 : 1);
+ case Z_STREAM_END:
+ return EOFC;
+ default:
+ return ERRC;
+ }
+}
+
+/* Release the stream */
+private void
+s_zlibD_release(stream_state * st)
+{
+ stream_zlib_state *const ss = (stream_zlib_state *)st;
+
+ inflateEnd(&ss->dynamic->zstate);
+ s_zlib_free_dynamic_state(ss);
+}
+
+/* Stream template */
+#ifdef _AIX
+const
+#endif /* _AIX */
+stream_template s_zlibD_template = {
+ &st_zlib_state, s_zlibD_init, s_zlibD_process, 1, 1, s_zlibD_release,
+ s_zlib_set_defaults, s_zlibD_reset
+};
+#endif /* HAVE_LIBZ */
diff --git a/pstoraster/szlibe.c b/pstoraster/szlibe.c
new file mode 100644
index 000000000..d3c3b4825
--- /dev/null
+++ b/pstoraster/szlibe.c
@@ -0,0 +1,115 @@
+/*
+ Copyright 1993-2002 by Easy Software Products
+ Copyright 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.
+*/
+#include <config.h>
+#ifdef HAVE_LIBZ
+
+/*$Id$ */
+/* zlib encoding (compression) filter stream */
+#include "std.h"
+#include "gsmemory.h"
+#include "gsmalloc.h" /* for gs_memory_default */
+#include "strimpl.h"
+#include "szlibxx.h"
+
+/* Initialize the filter. */
+private int
+s_zlibE_init(stream_state * st)
+{
+ stream_zlib_state *const ss = (stream_zlib_state *)st;
+ int code = s_zlib_alloc_dynamic_state(ss);
+
+ if (code < 0)
+ return ERRC; /****** WRONG ******/
+ if (deflateInit2(&ss->dynamic->zstate, ss->level, ss->method,
+ (ss->no_wrapper ? -ss->windowBits : ss->windowBits),
+ ss->memLevel, ss->strategy) != Z_OK)
+ return ERRC; /****** WRONG ******/
+ return 0;
+}
+
+/* Reinitialize the filter. */
+private int
+s_zlibE_reset(stream_state * st)
+{
+ stream_zlib_state *const ss = (stream_zlib_state *)st;
+
+ if (deflateReset(&ss->dynamic->zstate) != Z_OK)
+ return ERRC; /****** WRONG ******/
+ return 0;
+}
+
+/* Process a buffer */
+private int
+s_zlibE_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last)
+{
+ stream_zlib_state *const ss = (stream_zlib_state *)st;
+ z_stream *zs = &ss->dynamic->zstate;
+ const byte *p = pr->ptr;
+ int status;
+
+ /* Detect no input or full output so that we don't get */
+ /* a Z_BUF_ERROR return. */
+ if (pw->ptr == pw->limit)
+ return 1;
+ if (p == pr->limit && !last)
+ return 0;
+ zs->next_in = (Bytef *)p + 1;
+ zs->avail_in = pr->limit - p;
+ zs->next_out = pw->ptr + 1;
+ zs->avail_out = pw->limit - pw->ptr;
+ status = deflate(zs, (last ? Z_FINISH : Z_NO_FLUSH));
+ pr->ptr = zs->next_in - 1;
+ pw->ptr = zs->next_out - 1;
+ switch (status) {
+ case Z_OK:
+ return (pw->ptr == pw->limit ? 1 : pr->ptr > p && !last ? 0 : 1);
+ case Z_STREAM_END:
+ return (last && pr->ptr == pr->limit ? 0 : ERRC);
+ default:
+ return ERRC;
+ }
+}
+
+/* Release the stream */
+private void
+s_zlibE_release(stream_state * st)
+{
+ stream_zlib_state *const ss = (stream_zlib_state *)st;
+
+ deflateEnd(&ss->dynamic->zstate);
+ s_zlib_free_dynamic_state(ss);
+}
+
+/* Stream template */
+#ifdef _AIX
+const
+#endif /* _AIX */
+stream_template s_zlibE_template = {
+ &st_zlib_state, s_zlibE_init, s_zlibE_process, 1, 1, s_zlibE_release,
+ s_zlib_set_defaults, s_zlibE_reset
+};
+#endif
diff --git a/pstoraster/szlibx.h b/pstoraster/szlibx.h
new file mode 100644
index 000000000..e629c02f9
--- /dev/null
+++ b/pstoraster/szlibx.h
@@ -0,0 +1,74 @@
+/*
+ Copyright 2001 by Easy Software Products.
+ Copyright 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$ */
+/* zlib filter state definition */
+
+#ifndef szlibx_INCLUDED
+# define szlibx_INCLUDED
+
+/* Define an opaque type for the dynamic part of the state. */
+typedef struct zlib_dynamic_state_s zlib_dynamic_state_t;
+
+/* Define the stream state structure. */
+typedef struct stream_zlib_state_s {
+ stream_state_common;
+ /* Parameters - compression and decompression */
+ int windowBits;
+ bool no_wrapper; /* omit wrapper and checksum */
+ /* Parameters - compression only */
+ int level; /* effort level */
+ int method;
+ int memLevel;
+ int strategy;
+ /* Dynamic state */
+ zlib_dynamic_state_t *dynamic;
+} stream_zlib_state;
+
+/*
+ * The state descriptor is public only to allow us to split up
+ * the encoding and decoding filters.
+ *
+ * MRS - Had to split this up and move to source files to get it to
+ * compile with AIX C 5.0...
+ */
+#if 0
+extern_st(st_zlib_state);
+#define public_st_zlib_state() /* in szlibc.c */\
+ gs_public_st_ptrs1(st_zlib_state, stream_zlib_state,\
+ "zlibEncode/Decode state", zlib_state_enum_ptrs, zlib_state_reloc_ptrs,\
+ dynamic)
+#else
+extern gs_memory_struct_type_t st_zlib_state;
+#endif /* 0 */
+
+extern stream_template s_zlibD_template;
+extern stream_template s_zlibE_template;
+
+/* Shared procedures */
+stream_proc_set_defaults(s_zlib_set_defaults);
+
+#endif /* szlibx_INCLUDED */
diff --git a/pstoraster/szlibxx.h b/pstoraster/szlibxx.h
new file mode 100644
index 000000000..cffffab00
--- /dev/null
+++ b/pstoraster/szlibxx.h
@@ -0,0 +1,73 @@
+/* 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$ */
+/* Implementation definitions for zlib interface */
+/* Must be compiled with -I$(ZSRCDIR) */
+
+#ifndef szlibxx_INCLUDED
+# define szlibxx_INCLUDED
+
+#include "szlibx.h"
+#include "zlib.h"
+
+/*
+ * We don't want to allocate zlib's private data directly from
+ * the C heap, but we must allocate it as immovable; and to avoid
+ * garbage collection issues, we must keep GC-traceable pointers
+ * to every block allocated. Since the stream state itself is movable,
+ * we have to allocate an immovable block for the z_stream state as well.
+ */
+typedef struct zlib_block_s zlib_block_t;
+struct zlib_block_s {
+ void *data;
+ zlib_block_t *next;
+ zlib_block_t *prev;
+};
+#define private_st_zlib_block() /* in szlibc.c */\
+ gs_private_st_ptrs3(st_zlib_block, zlib_block_t, "zlib_block_t",\
+ zlib_block_enum_ptrs, zlib_block_reloc_ptrs, next, prev, data)
+/* The typedef is in szlibx.h */
+/*typedef*/ struct zlib_dynamic_state_s {
+ gs_memory_t *memory;
+ zlib_block_t *blocks;
+ z_stream zstate;
+} /*zlib_dynamic_state_t*/;
+#define private_st_zlib_dynamic_state() /* in szlibc.c */\
+ gs_private_st_ptrs1(st_zlib_dynamic_state, zlib_dynamic_state_t,\
+ "zlib_dynamic_state_t", zlib_dynamic_enum_ptrs, zlib_dynamic_reloc_ptrs,\
+ blocks)
+
+/*
+ * Provide zlib-compatible allocation and freeing functions.
+ * The mem pointer actually points to the dynamic state.
+ */
+void *s_zlib_alloc(P3(void *mem, uint items, uint size));
+void s_zlib_free(P2(void *mem, void *address));
+
+/* Internal procedure to allocate and free the dynamic state. */
+int s_zlib_alloc_dynamic_state(P1(stream_zlib_state *ss));
+void s_zlib_free_dynamic_state(P1(stream_zlib_state *ss));
+
+#endif /* szlibxx_INCLUDED */
diff --git a/pstoraster/time_.h b/pstoraster/time_.h
new file mode 100644
index 000000000..e451315da
--- /dev/null
+++ b/pstoraster/time_.h
@@ -0,0 +1,70 @@
+/*
+ Copyright 1993-2002 by Easy Software Products.
+ Copyright 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$ */
+/* Generic substitute for Unix sys/time.h */
+
+#ifndef time__INCLUDED
+# define time__INCLUDED
+
+/* We must include std.h before any file that includes sys/types.h. */
+#include "std.h"
+
+#include <config.h>
+
+/*
+ * Some System V environments don't include sys/time.h.
+ * The HAVE_SYS_TIME_H switch in gconfig_.h reflects this.
+ */
+#include <sys/time.h>
+#include <time.h>
+
+/*
+ * In SVR4.0 (but not other System V implementations),
+ * gettimeofday doesn't take a timezone argument.
+ */
+#ifdef SVR4_0
+# define gettimeofday_no_timezone 1
+#else
+# define gettimeofday_no_timezone 0
+#endif
+
+/* Some System V environments, and Posix environments, need <sys/times.h>. */
+#ifdef HAVE_SYS_TIMES_H
+# include <sys/times.h>
+# define use_times_for_usertime 1
+ /* Posix 1003.1b-1993 section 4.8.1.5 says that
+ CLK_TCK is obsolescent and that sysconf(_SC_CLK_TCK)
+ should be used instead, but this requires including
+ <unistd.h>, which is too painful to configure. */
+# ifndef CLK_TCK
+# define CLK_TCK 100 /* guess for older hosts */
+# endif
+#else
+# define use_times_for_usertime 0
+#endif
+
+#endif /* time__INCLUDED */
diff --git a/pstoraster/vmsmath.h b/pstoraster/vmsmath.h
new file mode 100644
index 000000000..6e247b5f9
--- /dev/null
+++ b/pstoraster/vmsmath.h
@@ -0,0 +1,49 @@
+/* Copyright (C) 1989 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$ */
+/* Substitute for math.h on VAX/VMS systems */
+
+#ifndef vmsmath_INCLUDED
+# define vmsmath_INCLUDED
+
+/* DEC VAX/VMS C comes with a math.h file but GNU VAX/VMS C does not. */
+/* This file substitutes for math.h when using GNU C. */
+# ifndef __MATH
+# define __MATH
+# if CC$gfloat
+# define HUGE_VAL 8.988465674311578540726371186585e+307
+# else
+# define HUGE_VAL 1.70141183460469229e+38
+# endif
+extern double acos(), asin(), atan(), atan2();
+extern double sin(), tan(), cos();
+extern double cosh(), sinh(), tanh();
+extern double exp(), frexp(), ldexp(), log(), log10(), pow();
+extern double modf(), fmod(), sqrt(), ceil(), floor();
+extern double fabs(), cabs(), hypot();
+
+# endif
+
+#endif /* vmsmath_INCLUDED */
diff --git a/pstoraster/zarith.c b/pstoraster/zarith.c
new file mode 100644
index 000000000..74584ffe2
--- /dev/null
+++ b/pstoraster/zarith.c
@@ -0,0 +1,373 @@
+/* Copyright (C) 1989, 1992, 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$ */
+/* Arithmetic operators */
+#include "math_.h"
+#include "ghost.h"
+#include "oper.h"
+#include "store.h"
+
+/****** NOTE: none of the arithmetic operators ******/
+/****** currently check for floating exceptions ******/
+
+/* Define max and min values for what will fit in value.intval. */
+#define MIN_INTVAL min_long
+#define MAX_INTVAL max_long
+#define MAX_HALF_INTVAL ((1 << (size_of(long) / 2 - 1)) - 1)
+
+/* <num1> <num2> add <sum> */
+/* We make this into a separate procedure because */
+/* the interpreter will almost always call it directly. */
+int
+zop_add(register os_ptr op)
+{
+ switch (r_type(op)) {
+ default:
+ return_op_typecheck(op);
+ case t_real:
+ switch (r_type(op - 1)) {
+ default:
+ return_op_typecheck(op - 1);
+ case t_real:
+ op[-1].value.realval += op->value.realval;
+ break;
+ case t_integer:
+ make_real(op - 1, (double)op[-1].value.intval + op->value.realval);
+ }
+ break;
+ case t_integer:
+ switch (r_type(op - 1)) {
+ default:
+ return_op_typecheck(op - 1);
+ case t_real:
+ op[-1].value.realval += (double)op->value.intval;
+ break;
+ case t_integer: {
+ long int2 = op->value.intval;
+
+ if (((op[-1].value.intval += int2) ^ int2) < 0 &&
+ ((op[-1].value.intval - int2) ^ int2) >= 0
+ ) { /* Overflow, convert to real */
+ make_real(op - 1, (double)(op[-1].value.intval - int2) + int2);
+ }
+ }
+ }
+ }
+ return 0;
+}
+int
+zadd(os_ptr op)
+{
+ int code = zop_add(op);
+
+ if (code == 0) {
+ pop(1);
+ }
+ return code;
+}
+
+/* <num1> <num2> div <real_quotient> */
+private int
+zdiv(register os_ptr op)
+{
+ register os_ptr op1 = op - 1;
+
+ /* We can't use the non_int_cases macro, */
+ /* because we have to check explicitly for op == 0. */
+ switch (r_type(op)) {
+ default:
+ return_op_typecheck(op);
+ case t_real:
+ if (op->value.realval == 0)
+ return_error(e_undefinedresult);
+ switch (r_type(op1)) {
+ default:
+ return_op_typecheck(op1);
+ case t_real:
+ op1->value.realval /= op->value.realval;
+ break;
+ case t_integer:
+ make_real(op1, (double)op1->value.intval / op->value.realval);
+ }
+ break;
+ case t_integer:
+ if (op->value.intval == 0)
+ return_error(e_undefinedresult);
+ switch (r_type(op1)) {
+ default:
+ return_op_typecheck(op1);
+ case t_real:
+ op1->value.realval /= (double)op->value.intval;
+ break;
+ case t_integer:
+ make_real(op1, (double)op1->value.intval / (double)op->value.intval);
+ }
+ }
+ pop(1);
+ return 0;
+}
+
+/* <num1> <num2> mul <product> */
+private int
+zmul(register os_ptr op)
+{
+ switch (r_type(op)) {
+ default:
+ return_op_typecheck(op);
+ case t_real:
+ switch (r_type(op - 1)) {
+ default:
+ return_op_typecheck(op - 1);
+ case t_real:
+ op[-1].value.realval *= op->value.realval;
+ break;
+ case t_integer:
+ make_real(op - 1, (double)op[-1].value.intval * op->value.realval);
+ }
+ break;
+ case t_integer:
+ switch (r_type(op - 1)) {
+ default:
+ return_op_typecheck(op - 1);
+ case t_real:
+ op[-1].value.realval *= (double)op->value.intval;
+ break;
+ case t_integer: {
+ long int1 = op[-1].value.intval;
+ long int2 = op->value.intval;
+ long abs1 = (int1 >= 0 ? int1 : -int1);
+ long abs2 = (int2 >= 0 ? int2 : -int2);
+ float fprod;
+
+ if ((abs1 > MAX_HALF_INTVAL || abs2 > MAX_HALF_INTVAL) &&
+ /* At least one of the operands is very large. */
+ /* Check for integer overflow. */
+ abs1 != 0 &&
+ abs2 > MAX_INTVAL / abs1 &&
+ /* Check for the boundary case */
+ (fprod = (float)int1 * int2,
+ (int1 * int2 != MIN_INTVAL ||
+ fprod != (float)MIN_INTVAL))
+ )
+ make_real(op - 1, fprod);
+ else
+ op[-1].value.intval = int1 * int2;
+ }
+ }
+ }
+ pop(1);
+ return 0;
+}
+
+/* <num1> <num2> sub <difference> */
+/* We make this into a separate procedure because */
+/* the interpreter will almost always call it directly. */
+int
+zop_sub(register os_ptr op)
+{
+ switch (r_type(op)) {
+ default:
+ return_op_typecheck(op);
+ case t_real:
+ switch (r_type(op - 1)) {
+ default:
+ return_op_typecheck(op - 1);
+ case t_real:
+ op[-1].value.realval -= op->value.realval;
+ break;
+ case t_integer:
+ make_real(op - 1, (double)op[-1].value.intval - op->value.realval);
+ }
+ break;
+ case t_integer:
+ switch (r_type(op - 1)) {
+ default:
+ return_op_typecheck(op - 1);
+ case t_real:
+ op[-1].value.realval -= (double)op->value.intval;
+ break;
+ case t_integer: {
+ long int1 = op[-1].value.intval;
+
+ if ((int1 ^ (op[-1].value.intval = int1 - op->value.intval)) < 0 &&
+ (int1 ^ op->value.intval) < 0
+ ) { /* Overflow, convert to real */
+ make_real(op - 1, (float)int1 - op->value.intval);
+ }
+ }
+ }
+ }
+ return 0;
+}
+int
+zsub(os_ptr op)
+{
+ int code = zop_sub(op);
+
+ if (code == 0) {
+ pop(1);
+ }
+ return code;
+}
+
+/* <num1> <num2> idiv <int_quotient> */
+private int
+zidiv(register os_ptr op)
+{
+ check_type(*op, t_integer);
+ check_type(op[-1], t_integer);
+ if (op->value.intval == 0)
+ return_error(e_undefinedresult);
+ if ((op[-1].value.intval /= op->value.intval) ==
+ MIN_INTVAL && op->value.intval == -1
+ ) { /* Anomalous boundary case, fail. */
+ return_error(e_rangecheck);
+ }
+ pop(1);
+ return 0;
+}
+
+/* <int1> <int2> mod <remainder> */
+private int
+zmod(register os_ptr op)
+{
+ check_type(*op, t_integer);
+ check_type(op[-1], t_integer);
+ if (op->value.intval == 0)
+ return_error(e_undefinedresult);
+ op[-1].value.intval %= op->value.intval;
+ pop(1);
+ return 0;
+}
+
+/* <num1> neg <num2> */
+private int
+zneg(register os_ptr op)
+{
+ switch (r_type(op)) {
+ default:
+ return_op_typecheck(op);
+ case t_real:
+ op->value.realval = -op->value.realval;
+ break;
+ case t_integer:
+ if (op->value.intval == MIN_INTVAL)
+ make_real(op, -(float)MIN_INTVAL);
+ else
+ op->value.intval = -op->value.intval;
+ }
+ return 0;
+}
+
+/* <num1> ceiling <num2> */
+private int
+zceiling(register os_ptr op)
+{
+ switch (r_type(op)) {
+ default:
+ return_op_typecheck(op);
+ case t_real:
+ op->value.realval = ceil(op->value.realval);
+ case t_integer:;
+ }
+ return 0;
+}
+
+/* <num1> floor <num2> */
+private int
+zfloor(register os_ptr op)
+{
+ switch (r_type(op)) {
+ default:
+ return_op_typecheck(op);
+ case t_real:
+ op->value.realval = floor(op->value.realval);
+ case t_integer:;
+ }
+ return 0;
+}
+
+/* <num1> round <num2> */
+private int
+zround(register os_ptr op)
+{
+ switch (r_type(op)) {
+ default:
+ return_op_typecheck(op);
+ case t_real:
+ op->value.realval = floor(op->value.realval + 0.5);
+ case t_integer:;
+ }
+ return 0;
+}
+
+/* <num1> truncate <num2> */
+private int
+ztruncate(register os_ptr op)
+{
+ switch (r_type(op)) {
+ default:
+ return_op_typecheck(op);
+ case t_real:
+ op->value.realval =
+ (op->value.realval < 0.0 ?
+ ceil(op->value.realval) :
+ floor(op->value.realval));
+ case t_integer:;
+ }
+ return 0;
+}
+
+/* Non-standard operators */
+
+/* <int1> <int2> .bitadd <sum> */
+private int
+zbitadd(register os_ptr op)
+{
+ check_type(*op, t_integer);
+ check_type(op[-1], t_integer);
+ op[-1].value.intval += op->value.intval;
+ pop(1);
+ return 0;
+}
+
+/* ------ Initialization table ------ */
+
+const op_def zarith_op_defs[] =
+{
+ {"2add", zadd},
+ {"2.bitadd", zbitadd},
+ {"1ceiling", zceiling},
+ {"2div", zdiv},
+ {"2idiv", zidiv},
+ {"1floor", zfloor},
+ {"2mod", zmod},
+ {"2mul", zmul},
+ {"1neg", zneg},
+ {"1round", zround},
+ {"2sub", zsub},
+ {"1truncate", ztruncate},
+ op_def_end(0)
+};
diff --git a/pstoraster/zarray.c b/pstoraster/zarray.c
new file mode 100644
index 000000000..04af4666b
--- /dev/null
+++ b/pstoraster/zarray.c
@@ -0,0 +1,131 @@
+/* Copyright (C) 1989, 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$ */
+/* Array operators */
+#include "memory_.h"
+#include "ghost.h"
+#include "ialloc.h"
+#include "ipacked.h"
+#include "oper.h"
+#include "store.h"
+
+/* The generic operators (copy, get, put, getinterval, putinterval, */
+/* length, and forall) are implemented in zgeneric.c. */
+
+/* <int> array <array> */
+int
+zarray(register os_ptr op)
+{
+ uint size;
+ int code;
+
+ check_int_leu(*op, max_array_size);
+ size = op->value.intval;
+ code = ialloc_ref_array((ref *)op, a_all, size, "array");
+ if (code < 0)
+ return code;
+ refset_null(op->value.refs, size);
+ return 0;
+}
+
+/* <array> aload <obj_0> ... <obj_n-1> <array> */
+private int
+zaload(register os_ptr op)
+{
+ ref aref;
+ uint asize;
+
+ ref_assign(&aref, op);
+ if (!r_is_array(&aref))
+ return_op_typecheck(op);
+ check_read(aref);
+ asize = r_size(&aref);
+ if (asize > ostop - op) { /* Use the slow, general algorithm. */
+ int code = ref_stack_push(&o_stack, asize);
+ uint i;
+ const ref_packed *packed = aref.value.packed;
+
+ if (code < 0)
+ return code;
+ for (i = asize; i > 0; i--, packed = packed_next(packed))
+ packed_get(packed, ref_stack_index(&o_stack, i));
+ *osp = aref;
+ return 0;
+ }
+ if (r_has_type(&aref, t_array))
+ memcpy(op, aref.value.refs, asize * sizeof(ref));
+ else {
+ uint i;
+ const ref_packed *packed = aref.value.packed;
+ os_ptr pdest = op;
+
+ for (i = 0; i < asize; i++, pdest++, packed = packed_next(packed))
+ packed_get(packed, pdest);
+ }
+ push(asize);
+ ref_assign(op, &aref);
+ return 0;
+}
+
+/* <obj_0> ... <obj_n-1> <array> astore <array> */
+private int
+zastore(register os_ptr op)
+{
+ uint size;
+ int code;
+
+ check_write_type(*op, t_array);
+ size = r_size(op);
+ if (size > op - osbot) { /* The store operation might involve other stack segments. */
+ ref arr;
+
+ if (size >= ref_stack_count(&o_stack))
+ return_error(e_stackunderflow);
+ arr = *op;
+ code = ref_stack_store(&o_stack, &arr, size, 1, 0, true,
+ "astore");
+ if (code < 0)
+ return code;
+ ref_stack_pop(&o_stack, size);
+ *ref_stack_index(&o_stack, 0) = arr;
+ } else {
+ code = refcpy_to_old(op, 0, op - size, size, "astore");
+ if (code < 0)
+ return code;
+ op[-(int)size] = *op;
+ pop(size);
+ }
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zarray_op_defs[] =
+{
+ {"1aload", zaload},
+ {"1array", zarray},
+ {"1astore", zastore},
+ op_def_end(0)
+};
diff --git a/pstoraster/zbseq.c b/pstoraster/zbseq.c
new file mode 100644
index 000000000..037a89e3e
--- /dev/null
+++ b/pstoraster/zbseq.c
@@ -0,0 +1,136 @@
+/* Copyright (C) 1990, 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$ */
+/* Level 2 binary object sequence operators */
+#include "memory_.h"
+#include "ghost.h"
+#include "oper.h"
+#include "ialloc.h"
+#include "btoken.h"
+#include "store.h"
+
+/* Current binary format (in iscan.c) */
+extern ref ref_binary_object_format;
+
+/* System and user name arrays. */
+ref binary_token_names; /* array of size 2 */
+private ref *const binary_token_names_p = &binary_token_names;
+
+/* Import the Level 2 scanner extensions. */
+typedef struct scanner_state_s scanner_state;
+extern int scan_binary_token(P3(stream *, ref *, scanner_state *));
+extern int (*scan_btoken_proc) (P3(stream *, ref *, scanner_state *));
+
+/* Initialize the binary token machinery. */
+private void
+zbseq_init(void)
+{
+ /* Initialize fake system and user name tables. */
+ /* PostScript code will install the real system name table. */
+ ialloc_ref_array(&binary_token_names, 0 /*a_noaccess */ , 2,
+ "binary token names");
+ make_empty_array(system_names_p, a_readonly);
+ make_empty_array(user_names_p, a_all);
+ gs_register_ref_root(imemory, NULL, (void **)&binary_token_names_p,
+ "binary token names");
+
+ /* Set up Level 2 scanning constants. */
+ scan_btoken_proc = scan_binary_token;
+}
+
+/* <names> .installsystemnames - */
+private int
+zinstallsystemnames(register os_ptr op)
+{
+ if (r_space(op) != avm_global)
+ return_error(e_invalidaccess);
+ check_read_type(*op, t_shortarray);
+ ref_assign_old(NULL, system_names_p, op, ".installsystemnames");
+ pop(1);
+ return 0;
+}
+
+/* - currentobjectformat <int> */
+private int
+zcurrentobjectformat(register os_ptr op)
+{
+ push(1);
+ *op = ref_binary_object_format;
+ return 0;
+}
+
+/* <int> setobjectformat - */
+private int
+zsetobjectformat(register os_ptr op)
+{
+ check_type(*op, t_integer);
+ if (op->value.intval < 0 || op->value.intval > 4)
+ return_error(e_rangecheck);
+ ref_assign_old(NULL, &ref_binary_object_format, op, "setobjectformat");
+ pop(1);
+ return 0;
+}
+
+/* <ref_offset> <char_offset> <obj> <string8> .bosobject */
+/* <ref_offset'> <char_offset'> <string8> */
+/*
+ * This converts a single object to its binary object sequence
+ * representation, doing the dirty work of printobject and writeobject.
+ * (The main control is in PostScript code, so that we don't have to worry
+ * about interrupts or callouts in the middle of writing the various data
+ * items.) Note that this may or may not modify the 'unused' field.
+ */
+
+private int
+zbosobject(os_ptr op)
+{
+ int code;
+
+ check_type(op[-3], t_integer);
+ check_type(op[-2], t_integer);
+ check_write_type(*op, t_string);
+ if (r_size(op) < 8)
+ return_error(e_rangecheck);
+ code = encode_binary_token(op - 1, &op[-3].value.intval,
+ &op[-2].value.intval, op->value.bytes);
+ if (code < 0)
+ return code;
+ op[-1] = *op;
+ r_set_size(op - 1, 8);
+ pop(1);
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zbseq_l2_op_defs[] =
+{
+ op_def_begin_level2(),
+ {"1.installsystemnames", zinstallsystemnames},
+ {"0currentobjectformat", zcurrentobjectformat},
+ {"1setobjectformat", zsetobjectformat},
+ {"4.bosobject", zbosobject},
+ op_def_end(zbseq_init)
+};
diff --git a/pstoraster/zcfont.c b/pstoraster/zcfont.c
new file mode 100644
index 000000000..061a3a15f
--- /dev/null
+++ b/pstoraster/zcfont.c
@@ -0,0 +1,164 @@
+/* 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$ */
+/* Composite font-related character operators */
+#include "ghost.h"
+#include "oper.h"
+#include "gschar.h"
+#include "gsmatrix.h" /* for gxfont.h */
+#include "gxfixed.h" /* for gxfont.h */
+#include "gxfont.h"
+#include "gxchar.h"
+#include "estack.h"
+#include "ichar.h"
+#include "ifont.h"
+#include "igstate.h"
+#include "store.h"
+
+/* Forward references */
+private int cshow_continue(P1(os_ptr));
+private int cshow_restore_font(P1(os_ptr));
+
+/* <proc> <string> cshow - */
+private int
+zcshow(os_ptr op)
+{
+ os_ptr proc_op = op - 1;
+ os_ptr str_op = op;
+ gs_show_enum *penum;
+ int code;
+
+ /*
+ * Even though this is not documented anywhere by Adobe,
+ * the Adobe interpreters apparently allow the string and
+ * the procedure to be provided in either order!
+ */
+ if (r_is_proc(proc_op))
+ ;
+ else if (r_is_proc(op)) { /* operands reversed */
+ proc_op = op;
+ str_op = op - 1;
+ } else {
+ check_op(2);
+ return_error(e_typecheck);
+ }
+ if ((code = op_show_setup(str_op, &penum)) != 0)
+ return code;
+ if ((code = gs_cshow_n_init(penum, igs, (char *)str_op->value.bytes,
+ r_size(str_op))) < 0
+ ) {
+ ifree_object(penum, "op_show_enum_setup");
+ return code;
+ }
+ op_show_finish_setup(penum, 2, NULL);
+ sslot = *proc_op; /* save kerning proc */
+ return cshow_continue(op - 2);
+}
+private int
+cshow_continue(os_ptr op)
+{
+ gs_show_enum *penum = senum;
+ int code;
+
+ check_estack(4); /* in case we call the procedure */
+ code = gs_show_next(penum);
+ if (code != gs_show_move) {
+ code = op_show_continue_dispatch(op, code);
+ if (code == o_push_estack) /* must be gs_show_render */
+ make_op_estack(esp - 1, cshow_continue);
+ return code;
+ }
+ /* Push the character code and width, and call the procedure. */
+ {
+ ref *pslot = &sslot;
+ gs_point wpt;
+ gs_font *font = gs_show_current_font(penum);
+ gs_font *scaled_font;
+
+ gs_show_current_width(penum, &wpt);
+#if 0
+ /****************
+ * The following code is logically correct (or at least,
+ * probably more correct than the code it replaces),
+ * but because of the issues about creating the scaled
+ * font in the correct VM space that make_font (in zfont.c)
+ * has to deal with, it creates references pointing to
+ * the wrong spaces. Therefore, we've removed it.
+ *****************/
+ {
+ int fdepth = penum->fstack.depth;
+
+ if (fdepth <= 0)
+ scaled_font = font; /* not composite */
+ else {
+ code = gs_makefont(font->dir, font,
+ &penum->fstack.items[fdepth - 1].font->
+ FontMatrix, &scaled_font);
+ if (code < 0)
+ return code;
+ }
+ }
+#else
+ scaled_font = font;
+#endif
+ push(3);
+ make_int(op - 2, gs_show_current_char(penum));
+ make_real(op - 1, wpt.x);
+ make_real(op, wpt.y);
+ push_op_estack(cshow_continue);
+ if (scaled_font != gs_rootfont(igs))
+ push_op_estack(cshow_restore_font);
+ /* cshow does not change rootfont for user procedure */
+ gs_set_currentfont(igs, scaled_font);
+ *++esp = *pslot; /* user procedure */
+ }
+ return o_push_estack;
+}
+private int
+cshow_restore_font(os_ptr op)
+{ /* We have 1 more entry on the e-stack (cshow_continue). */
+ return gs_show_restore_font(esenum(esp - 1));
+}
+
+/* - rootfont <font> */
+private int
+zrootfont(os_ptr op)
+{
+ push(1);
+ *op = *pfont_dict(gs_rootfont(igs));
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zcfont_op_defs[] =
+{
+ {"2cshow", zcshow},
+ {"0rootfont", zrootfont},
+ /* Internal operators */
+ {"0%cshow_continue", cshow_continue},
+ {"0%cshow_restore_font", cshow_restore_font},
+ op_def_end(0)
+};
diff --git a/pstoraster/zchar.c b/pstoraster/zchar.c
new file mode 100644
index 000000000..3911885fb
--- /dev/null
+++ b/pstoraster/zchar.c
@@ -0,0 +1,710 @@
+/* Copyright (C) 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$ */
+/* Character operators */
+#include "ghost.h"
+#include "oper.h"
+#include "gsstruct.h"
+#include "gxarith.h"
+#include "gxfixed.h"
+#include "gxmatrix.h" /* for ifont.h */
+#include "gxchar.h" /* for stringwidth_flag */
+#include "gxdevice.h" /* for gxfont.h */
+#include "gxfont.h"
+#include "gzpath.h"
+#include "gzstate.h"
+#include "dstack.h" /* for stack depth */
+#include "estack.h"
+#include "ialloc.h"
+#include "ichar.h"
+#include "idict.h"
+#include "ifont.h"
+#include "igstate.h"
+#include "ilevel.h"
+#include "iname.h"
+#include "ipacked.h"
+#include "store.h"
+
+/* Forward references */
+private bool map_glyph_to_char(P3(const ref *, const ref *, ref *));
+private int finish_show(P1(os_ptr));
+private int finish_stringwidth(P1(os_ptr));
+private int op_show_cleanup(P1(os_ptr));
+private int op_show_return_width(P3(os_ptr, uint, double *));
+
+/* <string> show - */
+private int
+zshow(register os_ptr op)
+{
+ gs_show_enum *penum;
+ int code = op_show_setup(op, &penum);
+
+ if (code != 0)
+ return code;
+ if ((code = gs_show_n_init(penum, igs, (char *)op->value.bytes, r_size(op))) < 0) {
+ ifree_object(penum, "op_show_enum_setup");
+ return code;
+ }
+ op_show_finish_setup(penum, 1, finish_show);
+ return op_show_continue(op - 1);
+}
+
+/* <ax> <ay> <string> ashow - */
+private int
+zashow(register os_ptr op)
+{
+ gs_show_enum *penum;
+ int code;
+ double axy[2];
+
+ if ((code = num_params(op - 1, 2, axy)) < 0 ||
+ (code = op_show_setup(op, &penum)) != 0
+ )
+ return code;
+ if ((code = gs_ashow_n_init(penum, igs, axy[0], axy[1], (char *)op->value.bytes, r_size(op))) < 0) {
+ ifree_object(penum, "op_show_enum_setup");
+ return code;
+ }
+ op_show_finish_setup(penum, 3, finish_show);
+ return op_show_continue(op - 3);
+}
+
+/* <cx> <cy> <char> <string> widthshow - */
+private int
+zwidthshow(register os_ptr op)
+{
+ gs_show_enum *penum;
+ int code;
+ double cxy[2];
+
+ check_type(op[-1], t_integer);
+ if ((gs_char) (op[-1].value.intval) != op[-1].value.intval)
+ return_error(e_rangecheck);
+ if ((code = num_params(op - 2, 2, cxy)) < 0 ||
+ (code = op_show_setup(op, &penum)) != 0
+ )
+ return code;
+ if ((code = gs_widthshow_n_init(penum, igs, cxy[0], cxy[1],
+ (gs_char) op[-1].value.intval,
+ (char *)op->value.bytes,
+ r_size(op))) < 0) {
+ ifree_object(penum, "op_show_enum_setup");
+ return code;
+ }
+ op_show_finish_setup(penum, 4, finish_show);
+ return op_show_continue(op - 4);
+}
+
+/* <cx> <cy> <char> <ax> <ay> <string> awidthshow - */
+private int
+zawidthshow(register os_ptr op)
+{
+ gs_show_enum *penum;
+ int code;
+ double cxy[2], axy[2];
+
+ check_type(op[-3], t_integer);
+ if ((gs_char) (op[-3].value.intval) != op[-3].value.intval)
+ return_error(e_rangecheck);
+ if ((code = num_params(op - 4, 2, cxy)) < 0 ||
+ (code = num_params(op - 1, 2, axy)) < 0 ||
+ (code = op_show_setup(op, &penum)) != 0
+ )
+ return code;
+ if ((code = gs_awidthshow_n_init(penum, igs, cxy[0], cxy[1],
+ (gs_char) op[-3].value.intval,
+ axy[0], axy[1],
+ (char *)op->value.bytes,
+ r_size(op))) < 0) {
+ ifree_object(penum, "op_show_enum_setup");
+ return code;
+ }
+ op_show_finish_setup(penum, 6, finish_show);
+ return op_show_continue(op - 6);
+}
+
+/* <proc> <string> kshow - */
+private int
+zkshow(register os_ptr op)
+{
+ gs_show_enum *penum;
+ int code;
+
+ check_proc(op[-1]);
+ if ((code = op_show_setup(op, &penum)) != 0)
+ return code;
+ if ((code = gs_kshow_n_init(penum, igs, (char *)op->value.bytes, r_size(op))) < 0) {
+ ifree_object(penum, "op_show_enum_setup");
+ return code;
+ }
+ op_show_finish_setup(penum, 2, finish_show);
+ sslot = op[-1]; /* save kerning proc */
+ return op_show_continue(op - 2);
+}
+
+/* Common finish procedure for all show operations. */
+/* Doesn't have to do anything. */
+private int
+finish_show(os_ptr op)
+{
+ return 0;
+}
+
+/* <string> stringwidth <wx> <wy> */
+private int
+zstringwidth(register os_ptr op)
+{
+ gs_show_enum *penum;
+ int code = op_show_setup(op, &penum);
+
+ if (code != 0)
+ return code;
+ if ((code = gs_stringwidth_n_init(penum, igs, (char *)op->value.bytes, r_size(op))) < 0) {
+ ifree_object(penum, "op_show_enum_setup");
+ return code;
+ }
+ op_show_finish_setup(penum, 1, finish_stringwidth);
+ return op_show_continue(op - 1);
+}
+/* Finishing procedure for stringwidth. */
+/* Pushes the accumulated width. */
+private int
+finish_stringwidth(register os_ptr op)
+{
+ gs_point width;
+
+ gs_show_width(senum, &width);
+ push(2);
+ make_real(op - 1, width.x);
+ make_real(op, width.y);
+ return 0;
+}
+
+/* Common code for charpath and .charboxpath. */
+private int
+zchar_path(register os_ptr op,
+ int (*init)(P5(gs_show_enum *, gs_state *, const char *, uint, bool)))
+{
+ gs_show_enum *penum;
+ int code;
+
+ check_type(*op, t_boolean);
+ code = op_show_setup(op - 1, &penum);
+ if (code != 0)
+ return code;
+ if ((code = (*init)(penum, igs, (char *)op[-1].value.bytes, r_size(op - 1), op->value.boolval)) < 0) {
+ ifree_object(penum, "op_show_enum_setup");
+ return code;
+ }
+ op_show_finish_setup(penum, 2, finish_show);
+ return op_show_continue(op - 2);
+}
+/* <string> <outline_bool> charpath - */
+private int
+zcharpath(register os_ptr op)
+{
+ return zchar_path(op, gs_charpath_n_init);
+}
+/* <string> <box_bool> .charboxpath - */
+private int
+zcharboxpath(register os_ptr op)
+{
+ return zchar_path(op, gs_charboxpath_n_init);
+}
+
+/* <wx> <wy> <llx> <lly> <urx> <ury> setcachedevice - */
+int
+zsetcachedevice(register os_ptr op)
+{
+ double wbox[6];
+ gs_show_enum *penum = op_show_find();
+ int code = num_params(op, 6, wbox);
+
+ if (penum == 0)
+ return_error(e_undefined);
+ if (code < 0)
+ return code;
+ if (gs_show_width_only(penum))
+ return op_show_return_width(op, 6, &wbox[0]);
+ code = gs_setcachedevice_double(penum, igs, wbox);
+ if (code < 0)
+ return code;
+ pop(6);
+ if (code == 1)
+ clear_pagedevice(istate);
+ return 0;
+}
+
+/* <w0x> <w0y> <llx> <lly> <urx> <ury> <w1x> <w1y> <vx> <vy> setcachedevice2 - */
+int
+zsetcachedevice2(os_ptr op)
+{
+ double wbox[10];
+ gs_show_enum *penum = op_show_find();
+ int code = num_params(op, 10, wbox);
+
+ if (penum == 0)
+ return_error(e_undefined);
+ if (code < 0)
+ return code;
+ if (gs_show_width_only(penum))
+ return op_show_return_width(op, 10,
+ (gs_rootfont(igs)->WMode ?
+ &wbox[6] : &wbox[0]));
+ code = gs_setcachedevice2_double(penum, igs, wbox);
+ if (code < 0)
+ return code;
+ pop(10);
+ if (code == 1)
+ clear_pagedevice(istate);
+ return 0;
+}
+
+/* <wx> <wy> setcharwidth - */
+private int
+zsetcharwidth(register os_ptr op)
+{
+ double width[2];
+ gs_show_enum *penum = op_show_find();
+ int code = num_params(op, 2, width);
+
+ if (penum == 0)
+ return_error(e_undefined);
+ if (code < 0)
+ return code;
+ if (gs_show_width_only(penum))
+ return op_show_return_width(op, 2, &width[0]);
+ code = gs_setcharwidth(penum, igs, width[0], width[1]);
+ if (code < 0)
+ return code;
+ pop(2);
+ return 0;
+}
+
+/* <dict> .fontbbox <llx> <lly> <urx> <ury> -true- */
+/* <dict> .fontbbox -false- */
+private int
+zfontbbox(register os_ptr op)
+{
+ double bbox[4];
+ int code;
+
+ check_type(*op, t_dictionary);
+ check_dict_read(*op);
+ code = font_bbox_param(op, bbox);
+ if (code < 0)
+ return code;
+ if (bbox[0] < bbox[2] && bbox[1] < bbox[3]) {
+ push(4);
+ make_reals(op - 4, bbox, 4);
+ make_true(op);
+ } else { /* No bbox, or an empty one. */
+ make_false(op);
+ }
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zchar_op_defs[] =
+{
+ {"3ashow", zashow},
+ {"6awidthshow", zawidthshow},
+ {"2charpath", zcharpath},
+ {"2.charboxpath", zcharboxpath},
+ {"2kshow", zkshow},
+ {"6setcachedevice", zsetcachedevice},
+ {":setcachedevice2", zsetcachedevice2},
+ {"2setcharwidth", zsetcharwidth},
+ {"1show", zshow},
+ {"1stringwidth", zstringwidth},
+ {"4widthshow", zwidthshow},
+ /* Extensions */
+ {"1.fontbbox", zfontbbox},
+ /* Internal operators */
+ {"0%finish_show", finish_show},
+ {"0%finish_stringwidth", finish_stringwidth},
+ {"0%op_show_continue", op_show_continue},
+ op_def_end(0)
+};
+
+/* ------ Subroutines ------ */
+
+/* Most of these are exported for zchar2.c. */
+
+/* Convert a glyph to a ref. */
+private void
+glyph_ref(gs_glyph glyph, ref * gref)
+{
+ if (glyph < gs_min_cid_glyph)
+ name_index_ref(glyph, gref);
+ else
+ make_int(gref, glyph - gs_min_cid_glyph);
+}
+
+/* Prepare to set up for a show operator. */
+/* Don't change any state yet. */
+int
+op_show_setup(os_ptr op, gs_show_enum ** ppenum)
+{
+ check_read_type(*op, t_string);
+ return op_show_enum_setup(op, ppenum);
+}
+int
+op_show_enum_setup(os_ptr op, gs_show_enum ** ppenum)
+{
+ check_estack(snumpush + 2);
+ if ((*ppenum = gs_show_enum_alloc((gs_memory_t *) imemory, igs, "op_show_enum_setup")) == 0)
+ return_error(e_VMerror);
+ return 0;
+}
+
+/* Finish setting up a show operator. This can't fail, since */
+/* op_show_enum_setup did the check_estack. */
+void
+op_show_finish_setup(gs_show_enum * penum, int npop, op_proc_p endproc /* end procedure */ )
+{
+ register es_ptr ep = esp + snumpush;
+
+ esp = ep;
+ make_mark_estack(ep - (snumpush - 1), es_show, op_show_cleanup);
+ if (endproc == NULL)
+ endproc = finish_show;
+ make_null(&esslot(ep));
+ make_int(&essindex(ep), 0);
+ make_int(&esodepth(ep), 0); /* see gs_show_render case in */
+ /* op_show_continue_dispatch */
+ make_int(&esddepth(ep), 0); /* ditto */
+ make_int(&esgslevel(ep), igs->level);
+ make_op_estack(&eseproc(ep), endproc);
+ make_istruct(ep, 0, penum);
+}
+
+/* Continuation operator for character rendering. */
+int
+op_show_continue(os_ptr op)
+{
+ return op_show_continue_dispatch(op, gs_show_next(senum));
+}
+/*
+ * Note that op_show_continue_dispatch sets osp = op explicitly iff the
+ * dispatch succeeds. This is so that the show operators don't pop anything
+ * from the o-stack if they don't succeed. Note also that if it returns an
+ * error, it has freed the enumerator.
+ */
+int
+op_show_continue_dispatch(register os_ptr op, int code)
+{
+ gs_show_enum *penum = senum;
+
+ switch (code) {
+ case 0: { /* all done */
+ os_ptr save_osp = osp;
+
+ osp = op;
+ code = (*real_opproc(&seproc)) (op);
+ op_show_free(code);
+ if (code < 0) {
+ osp = save_osp;
+ return code;
+ }
+ return o_pop_estack;
+ }
+ case gs_show_kern: {
+ ref *pslot = &sslot;
+
+ push(2);
+ make_int(op - 1, gs_kshow_previous_char(penum));
+ make_int(op, gs_kshow_next_char(penum));
+ push_op_estack(op_show_continue); /* continue after kerning */
+ *++esp = *pslot; /* kerning procedure */
+ return o_push_estack;
+ }
+ case gs_show_render: {
+ gs_font *pfont = gs_currentfont(igs);
+ font_data *pfdata = pfont_data(pfont);
+ gs_char chr = gs_show_current_char(penum);
+ gs_glyph glyph = gs_show_current_glyph(penum);
+
+ push(2);
+ op[-1] = pfdata->dict; /* push the font */
+ /*
+ * For Type 1 and Type 4 fonts, prefer BuildChar to
+ * BuildGlyph, so that PostScript procedures appearing in the
+ * CharStrings dictionary will receive the character code
+ * rather than the character name; for Type 3 fonts,
+ * prefer BuildGlyph to BuildChar. For other font types
+ * (such as CID fonts), only BuildGlyph will be present.
+ */
+ if (pfont->FontType == ft_user_defined) { /* Type 3 font, prefer BuildGlyph. */
+ if (level2_enabled &&
+ !r_has_type(&pfdata->BuildGlyph, t_null) &&
+ glyph != gs_no_glyph
+ ) {
+ glyph_ref(glyph, op);
+ esp[2] = pfdata->BuildGlyph;
+ } else if (r_has_type(&pfdata->BuildChar, t_null))
+ goto err;
+ else if (chr == gs_no_char) { /* glyphshow, reverse map the character */
+ /* through the Encoding */
+ ref gref;
+ const ref *pencoding = &pfdata->Encoding;
+
+ glyph_ref(glyph, &gref);
+ if (!map_glyph_to_char(&gref, pencoding,
+ (ref *) op)
+ ) { /* Not found, try .notdef */
+ name_enter_string(".notdef", &gref);
+ if (!map_glyph_to_char(&gref,
+ pencoding,
+ (ref *) op)
+ )
+ goto err;
+ }
+ esp[2] = pfdata->BuildChar;
+ } else {
+ make_int(op, chr);
+ esp[2] = pfdata->BuildChar;
+ }
+ } else {
+ /*
+ * For a Type 1 or Type 4 font, prefer BuildChar: we know
+ * that both BuildChar and BuildGlyph are present. For
+ * other font types, only BuildGlyph is available.
+ */
+ if (chr != gs_no_char && !r_has_type(&pfdata->BuildChar, t_null)) {
+ make_int(op, chr);
+ esp[2] = pfdata->BuildChar;
+ } else {
+ /* We might not have a glyph: substitute 0. **HACK** */
+ if (glyph == gs_no_glyph)
+ make_int(op, 0);
+ else
+ glyph_ref(glyph, op);
+ esp[2] = pfdata->BuildGlyph;
+ }
+ }
+ /* Save the stack depths in case we bail out. */
+ sodepth.value.intval = ref_stack_count(&o_stack) - 2;
+ sddepth.value.intval = ref_stack_count(&d_stack);
+ push_op_estack(op_show_continue);
+ ++esp; /* skip BuildChar or BuildGlyph proc */
+ return o_push_estack;
+ }
+ default: /* error */
+err:
+ if (code >= 0)
+ code = gs_note_error(e_invalidfont);
+ return op_show_free(code);
+ }
+}
+/* Reverse-map a glyph name to a character code for glyphshow. */
+private bool
+map_glyph_to_char(const ref * pgref, const ref * pencoding, ref * pch)
+{
+ uint esize = r_size(pencoding);
+ uint ch;
+ ref eref;
+
+ for (ch = 0; ch < esize; ch++) {
+ array_get(pencoding, (long)ch, &eref);
+ if (obj_eq(pgref, &eref)) {
+ make_int(pch, ch);
+ return true;
+ }
+ }
+ return false;
+}
+
+/* Find the index of the e-stack mark for the current show enumerator. */
+/* Return 0 if we can't find the mark. */
+uint
+op_show_find_index(void)
+{
+ ref_stack_enum_t rsenum;
+ uint count = 0;
+
+ ref_stack_enum_begin(&rsenum, &e_stack);
+ do {
+ es_ptr ep = rsenum.ptr;
+ uint size = rsenum.size;
+
+ for (ep += size - 1; size != 0; size--, ep--, count++)
+ if (r_is_estack_mark(ep) && estack_mark_index(ep) == es_show)
+ return count;
+ } while (ref_stack_enum_next(&rsenum));
+ return 0; /* no mark */
+}
+
+/* Find the current show enumerator on the e-stack. */
+gs_show_enum *
+op_show_find(void)
+{
+ uint index = op_show_find_index();
+
+ if (index == 0)
+ return 0; /* no mark */
+ return r_ptr(ref_stack_index(&e_stack, index - (snumpush - 1)),
+ gs_show_enum);
+}
+
+/* Shortcut the BuildChar or BuildGlyph procedure at the point */
+/* of the setcharwidth or the setcachedevice[2] if we are in */
+/* a stringwidth or cshow, or if we are only collecting the scalable */
+/* width for an xfont character. */
+private int
+op_show_return_width(os_ptr op, uint npop, double *pwidth)
+{
+ uint index = op_show_find_index();
+ es_ptr ep = (es_ptr) ref_stack_index(&e_stack, index - (snumpush - 1));
+ int code = gs_setcharwidth(esenum(ep), igs, pwidth[0], pwidth[1]);
+ uint ocount, dsaved, dcount;
+
+ if (code < 0)
+ return code;
+ /* Restore the operand and dictionary stacks. */
+ ocount = ref_stack_count(&o_stack) - (uint) esodepth(ep).value.intval;
+ if (ocount < npop)
+ return_error(e_stackunderflow);
+ dsaved = (uint) esddepth(ep).value.intval;
+ dcount = ref_stack_count(&d_stack);
+ if (dcount < dsaved)
+ return_error(e_dictstackunderflow);
+ while (dcount > dsaved) {
+ code = zend(op);
+ if (code < 0)
+ return code;
+ dcount--;
+ }
+ ref_stack_pop(&o_stack, ocount);
+ /* We don't want to pop the mark or the continuation */
+ /* procedure (op_show_continue or cshow_continue). */
+ pop_estack(index - snumpush);
+ return o_pop_estack;
+}
+
+/*
+ * Restore state after finishing, or unwinding from an error within, a show
+ * operation. Note that we assume op == osp, and may reset osp.
+ */
+private int
+op_show_restore(bool for_error)
+{
+ register es_ptr ep = esp + snumpush;
+ gs_show_enum *penum = esenum(ep);
+ int saved_level = esgslevel(ep).value.intval;
+ int code = 0;
+
+ if (for_error) {
+ uint saved_count = esodepth(ep).value.intval;
+ uint count = ref_stack_count(&o_stack);
+
+ if (count > saved_count) /* if <, we're in trouble */
+ ref_stack_pop(&o_stack, count - saved_count);
+ }
+ if (SHOW_IS_STRINGWIDTH(penum)) { /* stringwidth does an extra gsave */
+ --saved_level;
+ }
+ /*
+ * We might have been inside a cshow, in which case currentfont
+ * was reset temporarily, as though we were inside a BuildChar/
+ * BuildGlyph procedure. If this is the case, set currentfont
+ * back to its normal state, the root font.
+ */
+ if (penum->fstack.depth >= 0)
+ gs_set_currentfont(igs, penum->fstack.items[0].font);
+ while (igs->level > saved_level && code >= 0) {
+ if (igs->saved == 0 || igs->saved->saved == 0) {
+ /*
+ * Bad news: we got an error inside a save inside a BuildChar or
+ * BuildGlyph. Don't attempt to recover.
+ */
+ code = gs_note_error(e_Fatal);
+ } else
+ code = gs_grestore(igs);
+ }
+ gs_show_enum_release(penum, (gs_memory_t *) imemory);
+ return code;
+}
+/* Clean up after an error. */
+private int
+op_show_cleanup(os_ptr op)
+{
+ return op_show_restore(true);
+}
+/* Clean up after termination of a show operation. */
+int
+op_show_free(int code)
+{
+ int rcode;
+
+ esp -= snumpush;
+ rcode = op_show_restore(code < 0);
+ return (rcode < 0 ? rcode : code);
+}
+
+/* Get a FontBBox parameter from a font dictionary. */
+int
+font_bbox_param(const ref * pfdict, double bbox[4])
+{
+ ref *pbbox;
+
+ /*
+ * Pre-clear the bbox in case it's invalid. The Red Books say that
+ * FontBBox is required, but the Adobe interpreters don't require
+ * it, and a few user-written fonts don't supply it, or supply one
+ * of the wrong size (!); also, PageMaker 5.0 (an Adobe product!)
+ * sometimes emits an absurd bbox for Type 1 fonts converted from
+ * TrueType.
+ */
+ bbox[0] = bbox[1] = bbox[2] = bbox[3] = 0.0;
+ if (dict_find_string(pfdict, "FontBBox", &pbbox) > 0) {
+ if (!r_is_array(pbbox))
+ return_error(e_typecheck);
+ if (r_size(pbbox) == 4) {
+ const ref_packed *pbe = pbbox->value.packed;
+ ref rbe[4];
+ int i;
+ int code;
+ float dx, dy, ratio;
+
+ for (i = 0; i < 4; i++) {
+ packed_get(pbe, rbe + i);
+ pbe = packed_next(pbe);
+ }
+ if ((code = num_params(rbe + 3, 4, bbox)) < 0)
+ return code;
+ /* Require "reasonable" values. Thanks to Ray */
+ /* Johnston for suggesting the following test. */
+ dx = bbox[2] - bbox[0];
+ dy = bbox[3] - bbox[1];
+ if (dx <= 0 || dy <= 0 ||
+ (ratio = dy / dx) < 0.125 || ratio > 8.0
+ )
+ bbox[0] = bbox[1] = bbox[2] = bbox[3] = 0.0;
+ }
+ }
+ return 0;
+}
diff --git a/pstoraster/zchar1.c b/pstoraster/zchar1.c
new file mode 100644
index 000000000..bc34e3308
--- /dev/null
+++ b/pstoraster/zchar1.c
@@ -0,0 +1,763 @@
+/* Copyright (C) 1993, 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$ */
+/* Type 1 character display operator */
+#include "ghost.h"
+#include "oper.h"
+#include "gsstruct.h"
+#include "gxfixed.h"
+#include "gxmatrix.h"
+#include "gxchar.h" /* for gs_type1_init in gstype1.h */
+ /* (should only be gschar.h) */
+#include "gxdevice.h" /* for gxfont.h */
+#include "gxfont.h"
+#include "gxfont1.h"
+#include "gxtype1.h"
+#include "gzstate.h" /* for path for gs_type1_init */
+ /* (should only be gsstate.h) */
+#include "gspaint.h" /* for gs_fill, gs_stroke */
+#include "gspath.h"
+#include "estack.h"
+#include "ialloc.h"
+#include "ichar.h"
+#include "icharout.h"
+#include "idict.h"
+#include "ifont.h"
+#include "igstate.h"
+#include "iname.h"
+#include "store.h"
+
+/* Test whether a font is Type 1 compatible. */
+inline private bool
+font_is_type1_compatible(const gs_font *pfont)
+{
+ return (pfont->FontType == ft_encrypted ||
+ pfont->FontType == ft_disk_based);
+}
+
+/* ---------------- .type1execchar ---------------- */
+
+/*
+ * This is the workhorse for %Type1BuildChar, %Type1BuildGlyph,
+ * CCRun, and CID fonts. Eventually this will appear in the C API;
+ * even now, its normal control path doesn't use any continuations.
+ */
+
+/*
+ * Define the state record for this operator, which must save the metrics
+ * separately as well as the Type 1 interpreter state.
+ */
+typedef struct gs_type1exec_state_s {
+ gs_type1_state cis; /* must be first */
+ double sbw[4];
+ int /*metrics_present */ present;
+ gs_rect char_bbox;
+ /*
+ * The following elements are only used locally to make the stack clean
+ * for OtherSubrs: they don't need to be declared for the garbage
+ * collector.
+ */
+ ref save_args[6];
+ int num_args;
+} gs_type1exec_state;
+
+gs_private_st_suffix_add0(st_gs_type1exec_state, gs_type1exec_state,
+ "gs_type1exec_state", gs_type1exec_state_enum_ptrs,
+ gs_type1exec_state_reloc_ptrs, st_gs_type1_state);
+
+/* Forward references */
+private int bbox_continue(P1(os_ptr));
+private int nobbox_continue(P1(os_ptr));
+private int type1_call_OtherSubr(P3(const gs_type1exec_state *,
+ int (*)(P1(os_ptr)), const ref *));
+private int type1_continue_dispatch(P4(gs_type1exec_state *, const ref *,
+ ref *, int));
+private int op_type1_cleanup(P1(os_ptr));
+private void op_type1_free(P1(os_ptr));
+private void
+ type1_cis_get_metrics(P2(const gs_type1_state * pcis, double psbw[4]));
+private int bbox_getsbw_continue(P1(os_ptr));
+private int type1exec_bbox(P3(os_ptr, gs_type1exec_state *, gs_font *));
+private int bbox_fill(P1(os_ptr));
+private int bbox_stroke(P1(os_ptr));
+private int nobbox_finish(P2(os_ptr, gs_type1exec_state *));
+private int nobbox_fill(P1(os_ptr));
+private int nobbox_stroke(P1(os_ptr));
+
+/* <font> <code|name> <name> <charstring> .type1execchar - */
+private int
+ztype1execchar(register os_ptr op)
+{
+ gs_font *pfont;
+ int code = font_param(op - 3, &pfont);
+ gs_font_base *const pbfont = (gs_font_base *) pfont;
+ gs_font_type1 *const pfont1 = (gs_font_type1 *) pfont;
+ const gs_type1_data *pdata;
+ gs_show_enum *penum = op_show_find();
+ gs_type1exec_state cxs;
+ gs_type1_state *const pcis = &cxs.cis;
+
+ if (code < 0)
+ return code;
+ if (penum == 0 || !font_is_type1_compatible(pfont))
+ return_error(e_undefined);
+ pdata = &pfont1->data;
+ /*
+ * Any reasonable implementation would execute something like
+ * 1 setmiterlimit 0 setlinejoin 0 setlinecap
+ * here, but apparently the Adobe implementations aren't reasonable.
+ *
+ * If this is a stroked font, set the stroke width.
+ */
+ if (pfont->PaintType)
+ gs_setlinewidth(igs, pfont->StrokeWidth);
+ check_estack(3); /* for continuations */
+ /*
+ * Execute the definition of the character.
+ */
+ if (r_is_proc(op))
+ return zchar_exec_char_proc(op);
+ /*
+ * The definition must be a Type 1 CharString.
+ * Note that we do not require read access: this is deliberate.
+ */
+ check_type(*op, t_string);
+ if (r_size(op) <= max(pdata->lenIV, 0))
+ return_error(e_invalidfont);
+ /*
+ * In order to make character oversampling work, we must
+ * set up the cache before calling .type1addpath.
+ * To do this, we must get the bounding box from the FontBBox,
+ * and the width from the CharString or the Metrics.
+ * If the FontBBox isn't valid, we can't do any of this.
+ */
+ code = zchar_get_metrics(pbfont, op - 1, cxs.sbw);
+ if (code < 0)
+ return code;
+ cxs.present = code;
+ /* Establish a current point. */
+ code = gs_moveto(igs, 0.0, 0.0);
+ if (code < 0)
+ return code;
+ code = gs_type1_init(pcis, penum, NULL,
+ gs_show_in_charpath(penum) != cpm_show,
+ pfont1->PaintType, pfont1);
+ if (code < 0)
+ return code;
+ if (pfont1->FontBBox.q.x > pfont1->FontBBox.p.x &&
+ pfont1->FontBBox.q.y > pfont1->FontBBox.p.y
+ ) {
+ /* The FontBBox is valid. */
+ cxs.char_bbox = pfont1->FontBBox;
+ return type1exec_bbox(op, &cxs, pfont);
+ } else {
+ /*
+ * The FontBBox is not valid. In this case,
+ * we create the path first, then do the setcachedevice.
+ * If we are oversampling (in this case, only for anti-
+ * aliasing, not just to improve quality), we have to
+ * create the path twice, since we can't know the
+ * oversampling factor until after setcachedevice.
+ */
+ const ref *opstr = op;
+ ref other_subr;
+
+ if (cxs.present == metricsSideBearingAndWidth) {
+ gs_point sbpt;
+
+ sbpt.x = cxs.sbw[0], sbpt.y = cxs.sbw[1];
+ gs_type1_set_lsb(pcis, &sbpt);
+ }
+ /* Continue interpreting. */
+ icont:
+ code = type1_continue_dispatch(&cxs, opstr, &other_subr, 4);
+ op = osp; /* OtherSubrs might change it */
+ switch (code) {
+ case 0: /* all done */
+ return nobbox_finish(op, &cxs);
+ default: /* code < 0, error */
+ return code;
+ case type1_result_callothersubr: /* unknown OtherSubr */
+ return type1_call_OtherSubr(&cxs, nobbox_continue,
+ &other_subr);
+ case type1_result_sbw: /* [h]sbw, just continue */
+ if (cxs.present != metricsSideBearingAndWidth)
+ type1_cis_get_metrics(pcis, cxs.sbw);
+ opstr = 0;
+ goto icont;
+ }
+ }
+}
+/* Do all the work for the case where we have a bounding box. */
+private int
+type1exec_bbox(os_ptr op, gs_type1exec_state * pcxs, gs_font * pfont)
+{
+ gs_type1_state *const pcis = &pcxs->cis;
+ gs_font_base *const pbfont = (gs_font_base *) pfont;
+
+ /*
+ * We have a valid bounding box. If we don't have Metrics
+ * for this character, start interpreting the CharString;
+ * do the setcachedevice as soon as we know the
+ * (side bearing and) width.
+ */
+ if (pcxs->present == metricsNone) {
+ /* Get the width from the CharString, */
+ /* then set the cache device. */
+ ref cnref;
+ ref other_subr;
+ int code;
+
+ /* Since an OtherSubr callout might change osp, */
+ /* save the character name now. */
+ ref_assign(&cnref, op - 1);
+ code = type1_continue_dispatch(pcxs, op, &other_subr, 4);
+ op = osp; /* OtherSubrs might change it */
+ switch (code) {
+ default: /* code < 0 or done, error */
+ return ((code < 0 ? code :
+ gs_note_error(e_invalidfont)));
+ case type1_result_callothersubr: /* unknown OtherSubr */
+ return type1_call_OtherSubr(pcxs,
+ bbox_getsbw_continue,
+ &other_subr);
+ case type1_result_sbw: /* [h]sbw, done */
+ break;
+ }
+ type1_cis_get_metrics(pcis, pcxs->sbw);
+ return zchar_set_cache(op, pbfont, &cnref,
+ NULL, pcxs->sbw + 2,
+ &pcxs->char_bbox,
+ bbox_fill, bbox_stroke);
+ } else {
+ /* We have the width and bounding box: */
+ /* set up the cache device now. */
+ return zchar_set_cache(op, pbfont, op - 1,
+ (pcxs->present ==
+ metricsSideBearingAndWidth ?
+ pcxs->sbw : NULL),
+ pcxs->sbw + 2,
+ &pcxs->char_bbox,
+ bbox_fill, bbox_stroke);
+ }
+}
+
+
+/* Handle the results of gs_type1_interpret. */
+/* pcref points to a t_string ref. */
+private int
+type1_continue_dispatch(gs_type1exec_state *pcxs, const ref * pcref,
+ ref *pos, int num_args)
+{
+ int value;
+ int code;
+ gs_const_string charstring;
+ gs_const_string *pchars;
+
+ if (pcref == 0) {
+ pchars = 0;
+ } else {
+ charstring.data = pcref->value.const_bytes;
+ charstring.size = r_size(pcref);
+ pchars = &charstring;
+ }
+ /*
+ * Since OtherSubrs may push or pop values on the PostScript operand
+ * stack, remove the arguments of .type1execchar before calling the
+ * Type 1 interpreter, and put them back afterwards unless we're
+ * about to execute an OtherSubr procedure.
+ */
+ pcxs->num_args = num_args;
+ memcpy(pcxs->save_args, osp - (num_args - 1), num_args * sizeof(ref));
+ osp -= num_args;
+ code = gs_type1_interpret(&pcxs->cis, pchars, &value);
+ switch (code) {
+ case type1_result_callothersubr: {
+ /*
+ * The Type 1 interpreter handles all known OtherSubrs,
+ * so this must be an unknown one.
+ */
+ const font_data *pfdata = pfont_data(gs_currentfont(igs));
+
+ code = array_get(&pfdata->u.type1.OtherSubrs, (long)value, pos);
+ if (code >= 0)
+ return type1_result_callothersubr;
+ }
+ }
+ /* Put back the arguments removed above. */
+ memcpy(osp + 1, pcxs->save_args, num_args * sizeof(ref));
+ osp += num_args;
+ return code;
+}
+
+/*
+ * Push a continuation, the arguments removed for the OtherSubr, and
+ * the OtherSubr procedure.
+ */
+private int
+type1_push_OtherSubr(const gs_type1exec_state *pcxs, int (*cont)(P1(os_ptr)),
+ const ref *pos)
+{
+ int i, n = pcxs->num_args;
+
+ push_op_estack(cont);
+ /*
+ * Push the saved arguments (in reverse order, so they will get put
+ * back on the operand stack in the correct order) on the e-stack.
+ */
+ for (i = n; --i >= 0; ) {
+ *++esp = pcxs->save_args[i];
+ r_clear_attrs(esp, a_executable); /* just in case */
+ }
+ ++esp;
+ *esp = *pos;
+ return o_push_estack;
+}
+
+/* Do a callout to an OtherSubr implemented in PostScript. */
+/* The caller must have done a check_estack(4 + num_args). */
+private int
+type1_call_OtherSubr(const gs_type1exec_state * pcxs, int (*cont) (P1(os_ptr)),
+ const ref * pos)
+{
+ /* Move the Type 1 interpreter state to the heap. */
+ gs_type1exec_state *hpcxs =
+ ialloc_struct(gs_type1exec_state, &st_gs_type1exec_state,
+ "type1_call_OtherSubr");
+
+ if (hpcxs == 0)
+ return_error(e_VMerror);
+ *hpcxs = *pcxs;
+ push_mark_estack(es_show, op_type1_cleanup);
+ ++esp;
+ make_istruct(esp, 0, hpcxs);
+ return type1_push_OtherSubr(pcxs, cont, pos);
+}
+
+/* Continue from an OtherSubr callout while getting metrics. */
+private int
+bbox_getsbw_continue(os_ptr op)
+{
+ ref other_subr;
+ gs_type1exec_state *pcxs = r_ptr(esp, gs_type1exec_state);
+ gs_type1_state *const pcis = &pcxs->cis;
+ int code;
+
+ code = type1_continue_dispatch(pcxs, NULL, &other_subr, 4);
+ op = osp; /* in case z1_push/pop_proc was called */
+ switch (code) {
+ default: /* code < 0 or done, error */
+ op_type1_free(op);
+ return ((code < 0 ? code : gs_note_error(e_invalidfont)));
+ case type1_result_callothersubr: /* unknown OtherSubr */
+ return type1_push_OtherSubr(pcxs, bbox_getsbw_continue,
+ &other_subr);
+ case type1_result_sbw: { /* [h]sbw, done */
+ double sbw[4];
+ const gs_font_base *const pbfont =
+ (const gs_font_base *)pcis->pfont;
+ gs_rect bbox;
+
+ /* Get the metrics before freeing the state. */
+ type1_cis_get_metrics(pcis, sbw);
+ bbox = pcxs->char_bbox;
+ op_type1_free(op);
+ return zchar_set_cache(op, pbfont, op, sbw, sbw + 2, &bbox,
+ bbox_fill, bbox_stroke);
+ }
+ }
+}
+
+/* <font> <code|name> <name> <charstring> <sbx> <sby> %bbox_{fill|stroke} - */
+/* <font> <code|name> <name> <charstring> %bbox_{fill|stroke} - */
+private int bbox_finish(P2(os_ptr, int (*)(P1(os_ptr))));
+private int
+bbox_fill(os_ptr op)
+{
+ return bbox_finish(op, nobbox_fill);
+}
+private int
+bbox_stroke(os_ptr op)
+{
+ return bbox_finish(op, nobbox_stroke);
+}
+private int
+bbox_finish(os_ptr op, int (*cont) (P1(os_ptr)))
+{
+ gs_font *pfont;
+ int code;
+ gs_show_enum *penum = op_show_find();
+ gs_type1exec_state cxs; /* stack allocate to avoid sandbars */
+ gs_type1_state *const pcis = &cxs.cis;
+ double sbxy[2];
+ gs_point sbpt;
+ gs_point *psbpt = 0;
+ os_ptr opc = op;
+ const ref *opstr;
+ ref other_subr;
+
+ if (!r_has_type(opc, t_string)) {
+ check_op(3);
+ code = num_params(op, 2, sbxy);
+ if (code < 0)
+ return code;
+ sbpt.x = sbxy[0];
+ sbpt.y = sbxy[1];
+ psbpt = &sbpt;
+ opc -= 2;
+ check_type(*opc, t_string);
+ }
+ code = font_param(opc - 3, &pfont);
+ if (code < 0)
+ return code;
+ if (penum == 0 || !font_is_type1_compatible(pfont))
+ return_error(e_undefined);
+ {
+ gs_font_type1 *const pfont1 = (gs_font_type1 *) pfont;
+ int lenIV = pfont1->data.lenIV;
+
+ if (lenIV > 0 && r_size(opc) <= lenIV)
+ return_error(e_invalidfont);
+ check_estack(5); /* in case we need to do a callout */
+ code = gs_type1_init(pcis, penum, psbpt,
+ gs_show_in_charpath(penum) != cpm_show,
+ pfont1->PaintType, pfont1);
+ if (code < 0)
+ return code;
+ }
+ opstr = opc;
+ icont:
+ code = type1_continue_dispatch(&cxs, opstr, &other_subr, (psbpt ? 6 : 4));
+ op = osp; /* OtherSubrs might have altered it */
+ switch (code) {
+ case 0: /* all done */
+ /* Call the continuation now. */
+ if (psbpt)
+ pop(2);
+ return (*cont)(osp);
+ case type1_result_callothersubr: /* unknown OtherSubr */
+ push_op_estack(cont); /* call later */
+ return type1_call_OtherSubr(&cxs, bbox_continue, &other_subr);
+ case type1_result_sbw: /* [h]sbw, just continue */
+ opstr = 0;
+ goto icont;
+ default: /* code < 0, error */
+ return code;
+ }
+}
+
+/* Continue from an OtherSubr callout while building the path. */
+private int
+type1_callout_dispatch(os_ptr op, int (*cont)(P1(os_ptr)), int num_args)
+{
+ ref other_subr;
+ gs_type1exec_state *pcxs = r_ptr(esp, gs_type1exec_state);
+ int code;
+
+ icont:
+ code = type1_continue_dispatch(pcxs, NULL, &other_subr, num_args);
+ op = osp; /* in case z1_push/pop_proc was called */
+ switch (code) {
+ case 0: /* callout done, cont is on e-stack */
+ return 0;
+ default: /* code < 0 or done, error */
+ op_type1_free(op);
+ return ((code < 0 ? code : gs_note_error(e_invalidfont)));
+ case type1_result_callothersubr: /* unknown OtherSubr */
+ return type1_push_OtherSubr(pcxs, cont, &other_subr);
+ case type1_result_sbw: /* [h]sbw, just continue */
+ goto icont;
+ }
+}
+private int
+bbox_continue(os_ptr op)
+{
+ int npop = (r_has_type(op, t_string) ? 4 : 6);
+ int code = type1_callout_dispatch(op, bbox_continue, npop);
+
+ if (code == 0) {
+ op = osp; /* OtherSubrs might have altered it */
+ npop -= 4; /* nobbox_fill/stroke handles the rest */
+ pop(npop);
+ op -= npop;
+ op_type1_free(op);
+ }
+ return code;
+}
+private int
+nobbox_continue(os_ptr op)
+{
+ int code = type1_callout_dispatch(op, nobbox_continue, 4);
+
+ if (code)
+ return code;
+ {
+ gs_type1exec_state cxs;
+ gs_type1exec_state *pcxs = r_ptr(esp, gs_type1exec_state);
+
+ op = osp; /* OtherSubrs might have altered it */
+ cxs = *pcxs;
+ op_type1_free(op);
+ return nobbox_finish(op, &cxs);
+ }
+}
+
+/* Clean up after a Type 1 callout. */
+private int
+op_type1_cleanup(os_ptr op)
+{
+ ifree_object(r_ptr(esp + 2, void), "op_type1_cleanup");
+ return 0;
+}
+private void
+op_type1_free(os_ptr op)
+{
+ ifree_object(r_ptr(esp, void), "op_type1_free");
+ /*
+ * In order to avoid popping from the e-stack and then pushing onto
+ * it, which would violate an interpreter invariant, we simply
+ * overwrite the two e-stack items being discarded (hpcxs and the
+ * cleanup operator) with empty procedures.
+ */
+ make_empty_const_array(esp - 1, a_readonly + a_executable);
+ make_empty_const_array(esp, a_readonly + a_executable);
+}
+
+/* Finish the no-FontBBox case after constructing the path. */
+/* If we are oversampling for anti-aliasing, we have to go around again. */
+/* <font> <code|name> <name> <charstring> %nobbox_continue - */
+private int
+nobbox_finish(os_ptr op, gs_type1exec_state * pcxs)
+{
+ int code;
+ gs_show_enum *penum = op_show_find();
+ gs_font *pfont;
+
+ if ((code = gs_pathbbox(igs, &pcxs->char_bbox)) < 0 ||
+ (code = font_param(op - 3, &pfont)) < 0
+ )
+ return code;
+ if (penum == 0 || !font_is_type1_compatible(pfont))
+ return_error(e_undefined);
+ {
+ gs_font_base *const pbfont = (gs_font_base *) pfont;
+ gs_font_type1 *const pfont1 = (gs_font_type1 *) pfont;
+
+ if (pcxs->present == metricsNone) {
+ gs_point endpt;
+
+ if ((code = gs_currentpoint(igs, &endpt)) < 0)
+ return code;
+ pcxs->sbw[2] = endpt.x, pcxs->sbw[3] = endpt.y;
+ pcxs->present = metricsSideBearingAndWidth;
+ }
+ /*
+ * We only need to rebuild the path from scratch if we might
+ * oversample for anti-aliasing.
+ */
+ if ((*dev_proc(igs->device, get_alpha_bits))(igs->device, go_text) > 1
+ ) {
+ gs_newpath(igs);
+ gs_moveto(igs, 0.0, 0.0);
+ code = gs_type1_init(&pcxs->cis, penum, NULL,
+ gs_show_in_charpath(penum) != cpm_show,
+ pfont1->PaintType, pfont1);
+ if (code < 0)
+ return code;
+ return type1exec_bbox(op, pcxs, pfont);
+ }
+ return zchar_set_cache(op, pbfont, op, NULL, pcxs->sbw + 2,
+ &pcxs->char_bbox,
+ nobbox_fill, nobbox_stroke);
+ }
+}
+/* Finish by popping the operands and filling or stroking. */
+private int
+nobbox_fill(os_ptr op)
+{
+ pop(4);
+ /*
+ * Properly designed fonts, which have no self-intersecting outlines
+ * and in which outer and inner outlines are drawn in opposite
+ * directions, aren't affected by choice of filling rule; but some
+ * badly designed fonts in the Genoa test suite seem to require
+ * using the even-odd rule to match Adobe interpreters.
+ */
+ return gs_eofill(igs);
+}
+private int
+nobbox_stroke(os_ptr op)
+{
+ pop(4);
+ return gs_stroke(igs);
+}
+
+/* ------ Internal procedures ------ */
+
+/* Get the metrics (l.s.b. and width) from the Type 1 interpreter. */
+private void
+type1_cis_get_metrics(const gs_type1_state * pcis, double psbw[4])
+{
+ psbw[0] = fixed2float(pcis->lsb.x);
+ psbw[1] = fixed2float(pcis->lsb.y);
+ psbw[2] = fixed2float(pcis->width.x);
+ psbw[3] = fixed2float(pcis->width.y);
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zchar1_op_defs[] =
+{
+ {"4.type1execchar", ztype1execchar},
+ /* Internal operators */
+ {"4%nobbox_continue", nobbox_continue},
+ {"4%nobbox_fill", nobbox_fill},
+ {"4%nobbox_stroke", nobbox_stroke},
+ {"4%bbox_getsbw_continue", bbox_getsbw_continue},
+ {"4%bbox_continue", bbox_continue},
+ {"4%bbox_fill", bbox_fill},
+ {"4%bbox_stroke", bbox_stroke},
+ op_def_end(0)
+};
+
+/* ------ Auxiliary procedures for type 1 fonts ------ */
+
+private int
+z1_charstring_data(gs_font_type1 * pfont, const ref * pgref,
+ gs_const_string * pstr)
+{
+ ref *pcstr;
+
+ if (dict_find(&pfont_data(pfont)->CharStrings, pgref, &pcstr) <= 0)
+ return_error(e_undefined);
+ check_type_only(*pcstr, t_string);
+ pstr->data = pcstr->value.const_bytes;
+ pstr->size = r_size(pcstr);
+ return 0;
+
+}
+
+private int
+z1_glyph_data(gs_font_type1 * pfont, gs_glyph glyph, gs_const_string * pstr)
+{
+ ref gref;
+
+ if (glyph < gs_min_cid_glyph)
+ name_index_ref(glyph, &gref);
+ else
+ make_int(&gref, glyph - gs_min_cid_glyph);
+ return z1_charstring_data(pfont, &gref, pstr);
+}
+
+private int
+z1_subr_data(gs_font_type1 * pfont, int index, bool global,
+ gs_const_string * pstr)
+{
+ const font_data *pfdata = pfont_data(pfont);
+ ref subr;
+ int code;
+
+ code = array_get((global ? &pfdata->u.type1.GlobalSubrs :
+ &pfdata->u.type1.Subrs),
+ index, &subr);
+ if (code < 0)
+ return code;
+ check_type_only(subr, t_string);
+ pstr->data = subr.value.const_bytes;
+ pstr->size = r_size(&subr);
+ return 0;
+}
+
+private int
+z1_seac_data(gs_font_type1 * pfont, int index, gs_const_string * pstr)
+{
+ ref enc_entry;
+ int code = array_get(&StandardEncoding, (long)index, &enc_entry);
+
+ if (code < 0)
+ return code;
+ return z1_charstring_data(pfont, &enc_entry, pstr);
+}
+
+private int
+z1_next_glyph(gs_font_type1 * pfont, int *pindex, gs_glyph * pglyph)
+{
+ ref *pcsdict = &pfont_data(pfont)->CharStrings;
+ int index = *pindex - 1;
+ ref elt[2];
+
+ if (index < 0)
+ index = dict_first(pcsdict);
+next:
+ index = dict_next(pcsdict, index, elt);
+ *pindex = index + 1;
+ if (index >= 0) {
+ switch (r_type(elt)) {
+ case t_integer:
+ *pglyph = gs_min_cid_glyph + elt[0].value.intval;
+ break;
+ case t_name:
+ *pglyph = name_index(elt);
+ break;
+ default: /* can't handle it */
+ goto next;
+ }
+ }
+ return 0;
+}
+
+private int
+z1_push(gs_font_type1 * ignore, const fixed * pf, int count)
+{
+ const fixed *p = pf + count - 1;
+ int i;
+
+ check_ostack(count);
+ for (i = 0; i < count; i++, p--) {
+ osp++;
+ make_real(osp, fixed2float(*p));
+ }
+ return 0;
+}
+
+private int
+z1_pop(gs_font_type1 * ignore, fixed * pf)
+{
+ double val;
+ int code = real_param(osp, &val);
+
+ if (code < 0)
+ return code;
+ *pf = float2fixed(val);
+ osp--;
+ return 0;
+}
+
+/* Define the Type 1 procedure vector. */
+const gs_type1_data_procs_t z1_data_procs =
+{
+ z1_glyph_data, z1_subr_data, z1_seac_data, z1_next_glyph,
+ z1_push, z1_pop
+};
diff --git a/pstoraster/zchar2.c b/pstoraster/zchar2.c
new file mode 100644
index 000000000..1bb7e348e
--- /dev/null
+++ b/pstoraster/zchar2.c
@@ -0,0 +1,228 @@
+/* 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$ */
+/* Level 2 character operators */
+#include "ghost.h"
+#include "oper.h"
+#include "gschar.h"
+#include "gsmatrix.h" /* for gxfont.h */
+#include "gsstruct.h" /* for st_stream */
+#include "gxfixed.h" /* for gxfont.h */
+#include "gxfont.h"
+#include "gxchar.h"
+#include "estack.h"
+#include "ialloc.h"
+#include "ichar.h"
+#include "ifont.h"
+#include "igstate.h"
+#include "iname.h"
+#include "store.h"
+#include "stream.h"
+#include "ibnum.h"
+#include "gspath.h" /* gs_rmoveto prototype */
+
+/* Table of continuation procedures. */
+private int xshow_continue(P1(os_ptr));
+private int yshow_continue(P1(os_ptr));
+private int xyshow_continue(P1(os_ptr));
+static const op_proc_p xyshow_continues[4] =
+{
+ 0, xshow_continue, yshow_continue, xyshow_continue
+};
+
+/* Forward references */
+private int moveshow(P2(os_ptr, int));
+private int moveshow_continue(P2(os_ptr, int));
+
+/* <charname> glyphshow - */
+private int
+zglyphshow(os_ptr op)
+{
+ gs_glyph glyph;
+ gs_show_enum *penum;
+ int code;
+
+ switch (gs_currentfont(igs)->FontType) {
+ case ft_CID_encrypted:
+ case ft_CID_user_defined:
+ case ft_CID_TrueType:
+ case ft_CID_bitmap:
+ check_int_leu(*op, gs_max_glyph - gs_min_cid_glyph);
+ glyph = (gs_glyph) op->value.intval + gs_min_cid_glyph;
+ break;
+ default:
+ check_type(*op, t_name);
+ glyph = name_index(op);
+ }
+ if ((code = op_show_enum_setup(op, &penum)) != 0)
+ return code;
+ if ((code = gs_glyphshow_init(penum, igs, glyph)) < 0) {
+ ifree_object(penum, "op_show_glyph");
+ return code;
+ }
+ op_show_finish_setup(penum, 1, NULL);
+ return op_show_continue(op - 1);
+}
+
+/* <string> <numarray|numstring> xshow - */
+private int
+zxshow(os_ptr op)
+{
+ return moveshow(op, 1);
+}
+
+/* <string> <numarray|numstring> yshow - */
+private int
+zyshow(os_ptr op)
+{
+ return moveshow(op, 2);
+}
+
+/* <string> <numarray|numstring> xyshow - */
+private int
+zxyshow(os_ptr op)
+{
+ return moveshow(op, 3);
+}
+
+/* Common code for {x,y,xy}show */
+private int
+moveshow(os_ptr op, int xymask)
+{
+ gs_show_enum *penum;
+ int code = op_show_setup(op - 1, &penum);
+
+ if (code != 0)
+ return code;
+ if ((code = gs_xyshow_n_init(penum, igs, (char *)op[-1].value.bytes, r_size(op - 1)) < 0)) {
+ ifree_object(penum, "op_show_enum_setup");
+ return code;
+ }
+ code = num_array_format(op);
+ if (code < 0) {
+ ifree_object(penum, "op_show_enum_setup");
+ return code;
+ }
+ op_show_finish_setup(penum, 2, NULL);
+ ref_assign(&sslot, op);
+ return moveshow_continue(op - 2, xymask);
+}
+
+/* Continuation procedures */
+
+private int
+xshow_continue(os_ptr op)
+{
+ return moveshow_continue(op, 1);
+}
+
+private int
+yshow_continue(os_ptr op)
+{
+ return moveshow_continue(op, 2);
+}
+
+private int
+xyshow_continue(os_ptr op)
+{
+ return moveshow_continue(op, 3);
+}
+
+/* Get one value from the encoded number string or array. */
+/* Sets pvalue->value.realval. */
+private int
+sget_real(const ref * nsp, int format, uint index, ref * pvalue)
+{
+ int code;
+
+ switch (code = num_array_get(nsp, format, index, pvalue)) {
+ case t_integer:
+ pvalue->value.realval = pvalue->value.intval;
+ case t_real:
+ return t_real;
+ case t_null:
+ code = gs_note_error(e_rangecheck);
+ default:
+ return code;
+ }
+}
+
+private int
+moveshow_continue(os_ptr op, int xymask)
+{
+ const ref *nsp = &sslot;
+ int format = num_array_format(nsp);
+ int code;
+ gs_show_enum *penum = senum;
+ uint index = ssindex.value.intval;
+
+ for (;;) {
+ ref rwx, rwy;
+
+ code = gs_show_next(penum);
+ if (code != gs_show_move) {
+ ssindex.value.intval = index;
+ code = op_show_continue_dispatch(op, code);
+ if (code == o_push_estack) { /* must be gs_show_render */
+ make_op_estack(esp - 1, xyshow_continues[xymask]);
+ }
+ return code;
+ }
+ /* Move according to the next value(s) from the stream. */
+ if (xymask & 1) {
+ code = sget_real(nsp, format, index++, &rwx);
+ if (code < 0)
+ break;
+ } else
+ rwx.value.realval = 0;
+ if (xymask & 2) {
+ code = sget_real(nsp, format, index++, &rwy);
+ if (code < 0)
+ break;
+ } else
+ rwy.value.realval = 0;
+ code = gs_rmoveto(igs, rwx.value.realval, rwy.value.realval);
+ if (code < 0)
+ break;
+ }
+ /* An error occurred. Clean up before returning. */
+ return op_show_free(code);
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zchar2_op_defs[] =
+{
+ op_def_begin_level2(),
+ {"1glyphshow", zglyphshow},
+ {"2xshow", zxshow},
+ {"2xyshow", zxyshow},
+ {"2yshow", zyshow},
+ /* Internal operators */
+ {"0%xshow_continue", xshow_continue},
+ {"0%yshow_continue", yshow_continue},
+ {"0%xyshow_continue", xyshow_continue},
+ op_def_end(0)
+};
diff --git a/pstoraster/zchar32.c b/pstoraster/zchar32.c
new file mode 100644
index 000000000..1a2d532dd
--- /dev/null
+++ b/pstoraster/zchar32.c
@@ -0,0 +1,217 @@
+/* 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$ */
+/* Type 32 font glyph operators */
+#include "ghost.h"
+#include "oper.h"
+#include "gsccode.h" /* for gxfont.h */
+#include "gsmatrix.h"
+#include "gsutil.h"
+#include "gxfixed.h"
+#include "gxchar.h"
+#include "gxfont.h"
+#include "gxfcache.h"
+#include "ifont.h"
+#include "igstate.h"
+#include "store.h"
+
+/* ([wx wy llx lly urx ury] | [w0x w0y llx lly urx ury w1x w1y vx vy]) */
+/* <bitmap> <cid> <type32font> <str22> .makeglyph32 <<same with substr>> */
+private int
+zmakeglyph32(os_ptr op)
+{
+ bool long_form;
+ uint msize;
+ double metrics[10];
+ int wx, llx, lly, urx, ury;
+ int width, height, raster;
+ gs_font *pfont;
+ int code;
+ byte *str;
+
+ check_array(op[-4]);
+ msize = r_size(op - 4);
+ switch (msize) {
+ case 10:
+ long_form = true;
+ break;
+ case 6:
+ long_form = false;
+ break;
+ default:
+ return_error(e_rangecheck);
+ }
+ code = num_params(op[-4].value.refs + msize - 1, msize, metrics);
+ if (code < 0)
+ return code;
+ if (~code & 0x3c) /* check llx .. ury for integers */
+ return_error(e_typecheck);
+ check_read_type(op[-3], t_string);
+ llx = (int)metrics[2];
+ lly = (int)metrics[3];
+ urx = (int)metrics[4];
+ ury = (int)metrics[5];
+ width = urx - llx;
+ height = ury - lly;
+ raster = (width + 7) >> 3;
+ if (width < 0 || height < 0 || r_size(op - 3) != raster * height)
+ return_error(e_rangecheck);
+ check_int_leu(op[-2], 65535);
+ code = font_param(op - 1, &pfont);
+ if (code < 0)
+ return code;
+ if (pfont->FontType != ft_CID_bitmap)
+ return_error(e_invalidfont);
+ check_write_type(*op, t_string);
+ if (r_size(op) < 22)
+ return_error(e_rangecheck);
+ str = op->value.bytes;
+ if (long_form || metrics[0] != (wx = (int)metrics[0]) ||
+ metrics[1] != 0 || height == 0 ||
+ ((wx | width | height | (llx + 128) | (lly + 128)) & ~255) != 0
+ ) {
+ /* Use the long form. */
+ int i, n = (long_form ? 10 : 6);
+
+ str[0] = 0;
+ str[1] = long_form;
+ for (i = 0; i < n; ++i) {
+ int v = (int)metrics[i]; /* no floating point widths yet */
+
+ str[2 + 2 * i] = (byte)(v >> 8);
+ str[2 + 2 * i + 1] = (byte)v;
+ }
+ r_set_size(op, 2 + n * 2);
+ } else {
+ /* Use the short form. */
+ str[0] = (byte)width;
+ str[1] = (byte)height;
+ str[2] = (byte)wx;
+ str[3] = (byte)(llx + 128);
+ str[4] = (byte)(lly + 128);
+ r_set_size(op, 5);
+ }
+ return code;
+}
+
+/* <cid_min> <cid_max> <type32font> .removeglyphs - */
+typedef struct {
+ gs_glyph cid_min, cid_max;
+ gs_font *font;
+} font_cid_range_t;
+private bool
+select_cid_range(cached_char * cc, void *range_ptr)
+{
+ const font_cid_range_t *range = range_ptr;
+
+ return (cc->code >= range->cid_min &&
+ cc->code <= range->cid_max &&
+ cc->pair->font == range->font);
+}
+private int
+zremoveglyphs(os_ptr op)
+{
+ int code;
+ font_cid_range_t range;
+
+ check_int_leu(op[-2], 65535);
+ check_int_leu(op[-1], 65535);
+ code = font_param(op, &range.font);
+ if (code < 0)
+ return code;
+ if (range.font->FontType != ft_CID_bitmap)
+ return_error(e_invalidfont);
+ range.cid_min = gs_min_cid_glyph + op[-2].value.intval;
+ range.cid_max = gs_min_cid_glyph + op[-1].value.intval;
+ gx_purge_selected_cached_chars(range.font->dir, select_cid_range,
+ &range);
+ pop(3);
+ return 0;
+}
+
+/* <str5/14/22> .getmetrics32 <width> <height> <w0x> ... <vy> 5/14 */
+/* <str5/14/22> .getmetrics32 <width> <height> <wx> ... <ury> 22 */
+private int
+zgetmetrics32(os_ptr op)
+{
+ const byte *data;
+ uint size;
+ int i, n = 6;
+ os_ptr wop;
+
+ check_read_type(*op, t_string);
+ data = op->value.const_bytes;
+ size = r_size(op);
+ if (size < 5)
+ return_error(e_rangecheck);
+ if (data[0]) {
+ /* Short form. */
+ int llx = (int)data[3] - 128, lly = (int)data[4] - 128;
+
+ n = 6;
+ size = 5;
+ push(8);
+ make_int(op - 6, data[2]); /* wx */
+ make_int(op - 5, 0); /* wy */
+ make_int(op - 4, llx);
+ make_int(op - 3, lly);
+ make_int(op - 2, llx + data[0]); /* urx */
+ make_int(op - 1, lly + data[1]); /* ury */
+ } else {
+ if (data[1]) {
+ /* Long form, both WModes. */
+ if (size < 22)
+ return_error(e_rangecheck);
+ n = 10;
+ size = 22;
+ } else {
+ /* Long form, WMode = 0 only. */
+ if (size < 14)
+ return_error(e_rangecheck);
+ n = 6;
+ size = 14;
+ }
+ push(2 + n);
+ for (i = 0; i < n; ++i)
+ make_int(op - n + i,
+ ((int)((data[2 * i + 2] << 8) + data[2 * i + 3]) ^ 0x8000)
+ - 0x8000);
+ }
+ wop = op - n;
+ make_int(wop - 2, wop[4].value.intval - wop[2].value.intval);
+ make_int(wop - 1, wop[5].value.intval - wop[3].value.intval);
+ make_int(op, size);
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zchar32_op_defs[] =
+{
+ {"1.getmetrics32", zgetmetrics32},
+ {"4.makeglyph32", zmakeglyph32},
+ {"3.removeglyphs", zremoveglyphs},
+ op_def_end(0)
+};
diff --git a/pstoraster/zchar42.c b/pstoraster/zchar42.c
new file mode 100644
index 000000000..93a78c038
--- /dev/null
+++ b/pstoraster/zchar42.c
@@ -0,0 +1,184 @@
+/* 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$ */
+/* Type 42 character display operator */
+#include "ghost.h"
+#include "oper.h"
+#include "gsmatrix.h"
+#include "gspaint.h" /* for gs_fill, gs_stroke */
+#include "gspath.h"
+#include "gxfixed.h"
+#include "gxchar.h"
+#include "gxfont.h"
+#include "gxfont42.h"
+#include "gxistate.h"
+#include "gxpath.h"
+#include "gzstate.h" /* only for ->path */
+#include "dstack.h" /* only for systemdict */
+#include "estack.h"
+#include "ichar.h"
+#include "icharout.h"
+#include "ifont.h" /* for font_param */
+#include "igstate.h"
+#include "store.h"
+
+/* Imported procedures */
+int gs_type42_append(P7(uint glyph_index, gs_imager_state * pis,
+ gx_path * ppath, const gs_log2_scale_point * pscale,
+ bool charpath_flag, int paint_type,
+ gs_font_type42 * pfont));
+int gs_type42_get_metrics(P3(gs_font_type42 * pfont, uint glyph_index,
+ float psbw[4]));
+
+/* <font> <code|name> <name> <glyph_index> .type42execchar - */
+private int type42_fill(P1(os_ptr));
+private int type42_stroke(P1(os_ptr));
+private int
+ztype42execchar(register os_ptr op)
+{
+ gs_font *pfont;
+ int code = font_param(op - 3, &pfont);
+ gs_font_base *const pbfont = (gs_font_base *) pfont;
+ gs_show_enum *penum = op_show_find();
+ int present;
+ double sbw[4];
+
+ if (code < 0)
+ return code;
+ if (penum == 0 ||
+ (pfont->FontType != ft_TrueType &&
+ pfont->FontType != ft_CID_TrueType)
+ )
+ return_error(e_undefined);
+ /*
+ * Any reasonable implementation would execute something like
+ * 1 setmiterlimit 0 setlinejoin 0 setlinecap
+ * here, but apparently the Adobe implementations aren't reasonable.
+ *
+ * If this is a stroked font, set the stroke width.
+ */
+ if (pfont->PaintType)
+ gs_setlinewidth(igs, pfont->StrokeWidth);
+ check_estack(3); /* for continuations */
+ /*
+ * Execute the definition of the character.
+ */
+ if (r_is_proc(op))
+ return zchar_exec_char_proc(op);
+ /*
+ * The definition must be a Type 42 glyph index.
+ * Note that we do not require read access: this is deliberate.
+ */
+ check_type(*op, t_integer);
+ check_ostack(3); /* for lsb values */
+ present = zchar_get_metrics(pbfont, op - 1, sbw);
+ if (present < 0)
+ return present;
+ /* Establish a current point. */
+ code = gs_moveto(igs, 0.0, 0.0);
+ if (code < 0)
+ return code;
+ /* Get the metrics and set the cache device. */
+ if (present == metricsNone) {
+ float sbw42[4];
+ int i;
+
+ code = gs_type42_get_metrics((gs_font_type42 *) pfont,
+ (uint) op->value.intval, sbw42);
+ if (code < 0)
+ return code;
+ for (i = 0; i < 4; ++i)
+ sbw[i] = sbw42[i];
+ }
+ return zchar_set_cache(op, pbfont, op - 1,
+ (present == metricsSideBearingAndWidth ?
+ sbw : NULL),
+ sbw + 2, &pbfont->FontBBox,
+ type42_fill, type42_stroke);
+}
+
+/* Continue after a CDevProc callout. */
+private int type42_finish(P2(os_ptr op, int (*cont) (P1(gs_state *))));
+private int
+type42_fill(os_ptr op)
+{
+ return type42_finish(op, gs_fill);
+}
+private int
+type42_stroke(os_ptr op)
+{
+ return type42_finish(op, gs_stroke);
+}
+/* <font> <code|name> <name> <glyph_index> <sbx> <sby> %type42_{fill|stroke} - */
+/* <font> <code|name> <name> <glyph_index> %type42_{fill|stroke} - */
+private int
+type42_finish(os_ptr op, int (*cont) (P1(gs_state *)))
+{
+ gs_font *pfont;
+ int code;
+ gs_show_enum *penum = op_show_find();
+ double sbxy[2];
+ gs_point sbpt;
+ gs_point *psbpt = 0;
+ os_ptr opc = op;
+
+ if (!r_has_type(op - 3, t_dictionary)) {
+ check_op(6);
+ code = num_params(op, 2, sbxy);
+ if (code < 0)
+ return code;
+ sbpt.x = sbxy[0];
+ sbpt.y = sbxy[1];
+ psbpt = &sbpt;
+ opc -= 2;
+ }
+ check_type(*opc, t_integer);
+ code = font_param(opc - 3, &pfont);
+ if (code < 0)
+ return code;
+ if (penum == 0 || (pfont->FontType != ft_TrueType &&
+ pfont->FontType != ft_CID_TrueType)
+ )
+ return_error(e_undefined);
+ code = gs_type42_append((uint) opc->value.intval,
+ (gs_imager_state *) penum->pgs,
+ penum->pgs->path,
+ &penum->log2_current_scale,
+ gs_show_in_charpath(penum) != cpm_show,
+ pfont->PaintType,
+ (gs_font_type42 *) pfont);
+ if (code < 0)
+ return code;
+ pop((psbpt == 0 ? 4 : 6));
+ return (*cont)(penum->pgs);
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zchar42_op_defs[] =
+{
+ {"4.type42execchar", ztype42execchar},
+ op_def_end(0)
+};
diff --git a/pstoraster/zcharout.c b/pstoraster/zcharout.c
new file mode 100644
index 000000000..08d9c2997
--- /dev/null
+++ b/pstoraster/zcharout.c
@@ -0,0 +1,241 @@
+/* Copyright (C) 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$ */
+/* Common code for outline (Type 1 / 4 / 42) fonts */
+#include "ghost.h"
+#include "oper.h"
+#include "gschar.h"
+#include "gxdevice.h" /* for gxfont.h */
+#include "gxfont.h"
+#include "dstack.h" /* only for systemdict */
+#include "estack.h"
+#include "ichar.h"
+#include "icharout.h"
+#include "idict.h"
+#include "ifont.h"
+#include "igstate.h"
+#include "store.h"
+
+/* Imported operators */
+int zsetcachedevice(P1(os_ptr)); /* zchar.c */
+int zsetcachedevice2(P1(os_ptr)); /* zchar.c */
+
+/*
+ * Execute an outline defined by a PostScript procedure.
+ * The top elements of the stack are:
+ * <font> <code|name> <name> <outline_id>
+ */
+int
+zchar_exec_char_proc(os_ptr op)
+{ /*
+ * The definition is a PostScript procedure. Execute
+ * <code|name> proc
+ * within a systemdict begin/end and a font begin/end.
+ */
+ es_ptr ep;
+
+ check_estack(5);
+ ep = esp += 5;
+ make_op_estack(ep - 4, zend);
+ make_op_estack(ep - 3, zend);
+ ref_assign(ep - 2, op);
+ make_op_estack(ep - 1, zbegin);
+ make_op_estack(ep, zbegin);
+ ref_assign(op - 1, systemdict);
+ {
+ ref rfont;
+
+ ref_assign(&rfont, op - 3);
+ ref_assign(op - 3, op - 2);
+ ref_assign(op - 2, &rfont);
+ }
+ pop(1);
+ return o_push_estack;
+}
+
+/*
+ * Get the metrics for a character from the Metrics dictionary of a base
+ * font. If present, store the l.s.b. in psbw[0,1] and the width in
+ * psbw[2,3].
+ */
+int /*metrics_present*/
+zchar_get_metrics(const gs_font_base * pbfont, const ref * pcnref,
+ double psbw[4])
+{
+ const ref *pfdict = &pfont_data(pbfont)->dict;
+ ref *pmdict;
+
+ if (dict_find_string(pfdict, "Metrics", &pmdict) > 0) {
+ ref *pmvalue;
+
+ check_type_only(*pmdict, t_dictionary);
+ check_dict_read(*pmdict);
+ if (dict_find(pmdict, pcnref, &pmvalue) > 0) {
+ if (num_params(pmvalue, 1, psbw + 2) >= 0) { /* <wx> only */
+ psbw[3] = 0;
+ return metricsWidthOnly;
+ } else {
+ int code;
+
+ check_read_type_only(*pmvalue, t_array);
+ switch (r_size(pmvalue)) {
+ case 2: /* [<sbx> <wx>] */
+ code = num_params(pmvalue->value.refs + 1,
+ 2, psbw);
+ psbw[2] = psbw[1];
+ psbw[1] = psbw[3] = 0;
+ break;
+ case 4: /* [<sbx> <sby> <wx> <wy>] */
+ code = num_params(pmvalue->value.refs + 3,
+ 4, psbw);
+ break;
+ default:
+ return_error(e_rangecheck);
+ }
+ if (code < 0)
+ return code;
+ return metricsSideBearingAndWidth;
+ }
+ }
+ }
+ return metricsNone;
+}
+
+/*
+ * Consult Metrics2 and CDevProc, and call setcachedevice[2]. Return
+ * o_push_estack if we had to call a CDevProc, or if we are skipping the
+ * rendering process (only getting the metrics).
+ */
+int
+zchar_set_cache(os_ptr op, const gs_font_base * pbfont, const ref * pcnref,
+ const double psb[2], const double pwidth[2], const gs_rect * pbbox,
+ int (*cont_fill)(P1(os_ptr)), int (*cont_stroke)(P1(os_ptr)))
+{
+ const ref *pfdict = &pfont_data(pbfont)->dict;
+ ref *pmdict;
+ ref *pcdevproc;
+ int have_cdevproc;
+ ref rpop;
+ bool metrics2 = false;
+ int (*cont) (P1(os_ptr));
+ double w2[10];
+ gs_show_enum *penum = op_show_find();
+
+ w2[0] = pwidth[0], w2[1] = pwidth[1];
+
+ /* Adjust the bounding box for stroking if needed. */
+
+ w2[2] = pbbox->p.x, w2[3] = pbbox->p.y;
+ w2[4] = pbbox->q.x, w2[5] = pbbox->q.y;
+ if (pbfont->PaintType == 0)
+ cont = cont_fill;
+ else {
+ double expand = max(1.415, gs_currentmiterlimit(igs)) *
+ gs_currentlinewidth(igs) / 2;
+
+ w2[2] -= expand, w2[3] -= expand;
+ w2[4] += expand, w2[5] += expand;
+ cont = cont_stroke;
+ }
+
+ /* Check for Metrics2. */
+
+ if (dict_find_string(pfdict, "Metrics2", &pmdict) > 0) {
+ ref *pmvalue;
+
+ check_type_only(*pmdict, t_dictionary);
+ check_dict_read(*pmdict);
+ if (dict_find(pmdict, pcnref, &pmvalue) > 0) {
+ check_read_type_only(*pmvalue, t_array);
+ if (r_size(pmvalue) == 4) {
+ int code = num_params(pmvalue->value.refs + 3,
+ 4, w2 + 6);
+
+ if (code < 0)
+ return code;
+ metrics2 = true;
+ }
+ }
+ }
+ /* Check for CDevProc or "short-circuiting". */
+
+ have_cdevproc = dict_find_string(pfdict, "CDevProc", &pcdevproc) > 0;
+ if (have_cdevproc || gs_show_width_only(penum)) {
+ int i;
+ int (*zsetc) (P1(os_ptr));
+ int nparams;
+
+ if (have_cdevproc) {
+ check_proc_only(*pcdevproc);
+ zsetc = zsetcachedevice2;
+ if (!metrics2) {
+ w2[6] = w2[0], w2[7] = w2[1];
+ w2[8] = w2[9] = 0;
+ }
+ nparams = 10;
+ } else {
+ make_oper(&rpop, 0, zpop);
+ pcdevproc = &rpop;
+ if (metrics2)
+ zsetc = zsetcachedevice2, nparams = 10;
+ else
+ zsetc = zsetcachedevice, nparams = 6;
+ }
+ check_estack(3);
+ /* Push the l.s.b. for .type1addpath if necessary. */
+ if (psb != 0) {
+ push(nparams + 3);
+ make_real(op - (nparams + 2), psb[0]);
+ make_real(op - (nparams + 1), psb[1]);
+ } else {
+ push(nparams + 1);
+ }
+ for (i = 0; i < nparams; ++i)
+ make_real(op - nparams + i, w2[i]);
+ ref_assign(op, pcnref);
+ push_op_estack(cont);
+ push_op_estack(zsetc);
+ ++esp;
+ ref_assign(esp, pcdevproc);
+ return o_push_estack;
+ } {
+ int code =
+ (metrics2 ? gs_setcachedevice2_double(penum, igs, w2) :
+ gs_setcachedevice_double(penum, igs, w2));
+
+ if (code < 0)
+ return code;
+ }
+
+ /* No metrics modification, do the stroke or fill now. */
+
+ /* Push the l.s.b. for .type1addpath if necessary. */
+ if (psb != 0) {
+ push(2);
+ make_real(op - 1, psb[0]);
+ make_real(op, psb[1]);
+ }
+ return cont(op);
+}
diff --git a/pstoraster/zcid.c b/pstoraster/zcid.c
new file mode 100644
index 000000000..1211d249e
--- /dev/null
+++ b/pstoraster/zcid.c
@@ -0,0 +1,102 @@
+/* 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$ */
+/* CID-keyed font operators */
+#include "ghost.h"
+#include "oper.h"
+#include "gsmatrix.h"
+#include "gsccode.h"
+#include "gxfont.h"
+#include "bfont.h"
+#include "iname.h"
+#include "store.h"
+
+/* Imported from zfont42.c */
+int build_gs_TrueType_font(P5(os_ptr op, font_type ftype,
+ const char *bcstr, const char *bgstr,
+ build_font_options_t options));
+
+/* <string|name> <font_dict> .buildfont9/10 <string|name> <font> */
+/* Build a type 9 or 10 (CID-keyed) font. */
+/* Right now, we treat these like type 3 (with a BuildGlyph procedure). */
+private int
+build_gs_cid_font(os_ptr op, font_type ftype, const build_proc_refs * pbuild)
+{
+ int code;
+ gs_font_base *pfont;
+
+ check_type(*op, t_dictionary);
+ code = build_gs_simple_font(op, &pfont, ftype, &st_gs_font_base,
+ pbuild,
+ bf_Encoding_optional |
+ bf_FontBBox_required |
+ bf_UniqueID_ignored);
+ if (code < 0)
+ return code;
+ return define_gs_font((gs_font *) pfont);
+}
+private int
+zbuildfont9(os_ptr op)
+{
+ build_proc_refs build;
+ int code = build_proc_name_refs(&build, NULL, "%Type9BuildGlyph");
+
+ if (code < 0)
+ return code;
+ return build_gs_cid_font(op, ft_CID_encrypted, &build);
+}
+private int
+zbuildfont10(os_ptr op)
+{
+ build_proc_refs build;
+ int code = build_gs_font_procs(op, &build);
+
+ if (code < 0)
+ return code;
+ make_null(&build.BuildChar); /* only BuildGlyph */
+ return build_gs_cid_font(op, ft_CID_user_defined, &build);
+}
+
+/* <string|name> <font_dict> .buildfont11 <string|name> <font> */
+private int
+zbuildfont11(os_ptr op)
+{
+ return build_gs_TrueType_font(op, ft_CID_TrueType, (const char *)0,
+ "%Type11BuildGlyph",
+ bf_Encoding_optional |
+ bf_FontBBox_required |
+ bf_UniqueID_ignored |
+ bf_CharStrings_optional);
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zcid_op_defs[] =
+{
+ {"2.buildfont9", zbuildfont9},
+ {"2.buildfont10", zbuildfont10},
+ {"2.buildfont11", zbuildfont11},
+ op_def_end(0)
+};
diff --git a/pstoraster/zcie.c b/pstoraster/zcie.c
new file mode 100644
index 000000000..f5024e17c
--- /dev/null
+++ b/pstoraster/zcie.c
@@ -0,0 +1,731 @@
+/* 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$ */
+/* CIE color operators */
+#include "math_.h"
+#include "memory_.h"
+#include "ghost.h"
+#include "oper.h"
+#include "gsstruct.h"
+#include "gxcspace.h" /* gscolor2.h requires gscspace.h */
+#include "gscolor2.h"
+#include "gscie.h"
+#include "estack.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "idparam.h"
+#include "igstate.h"
+#include "icie.h"
+#include "isave.h"
+#include "ivmspace.h"
+#include "store.h" /* for make_null */
+
+/* CIE color dictionaries are so complex that */
+/* we handle the CIE case of setcolorspace separately here. */
+
+/* Empty procedures */
+static const ref empty_procs[4] =
+{
+ empty_ref_data(t_array, a_readonly | a_executable),
+ empty_ref_data(t_array, a_readonly | a_executable),
+ empty_ref_data(t_array, a_readonly | a_executable),
+ empty_ref_data(t_array, a_readonly | a_executable)
+};
+
+/* Redefined CIE color space installers that load the cache. */
+extern cs_proc_install_cspace(gx_install_CIEDEFG);
+extern cs_proc_install_cspace(gx_install_CIEDEF);
+extern cs_proc_install_cspace(gx_install_CIEABC);
+extern cs_proc_install_cspace(gx_install_CIEA);
+private cs_proc_install_cspace(cs_install_zCIEDEFG);
+private cs_proc_install_cspace(cs_install_zCIEDEF);
+private cs_proc_install_cspace(cs_install_zCIEABC);
+private cs_proc_install_cspace(cs_install_zCIEA);
+
+/* ------ Parameter extraction utilities ------ */
+
+/* Get a range array parameter from a dictionary. */
+/* We know that count <= 4. */
+int
+dict_ranges_param(const ref * pdref, const char *kstr, int count,
+ gs_range * prange)
+{
+ int code = dict_float_array_param(pdref, kstr, count * 2,
+ (float *)prange, NULL);
+
+ if (code < 0)
+ return code;
+ else if (code == 0)
+ memcpy(prange, Range4_default.ranges, count * sizeof(gs_range));
+ else if (code != count * 2)
+ return_error(e_rangecheck);
+ return 0;
+}
+
+/* Get an array of procedures from a dictionary. */
+/* We know count <= countof(empty_procs). */
+int
+dict_proc_array_param(const ref * pdict, const char *kstr,
+ uint count, ref * pparray)
+{
+ ref *pvalue;
+
+ if (dict_find_string(pdict, kstr, &pvalue) > 0) {
+ uint i;
+
+ check_array_only(*pvalue);
+ if (r_size(pvalue) != count)
+ return_error(e_rangecheck);
+ for (i = 0; i < count; i++) {
+ ref proc;
+
+ array_get(pvalue, (long)i, &proc);
+ check_proc_only(proc);
+ }
+ *pparray = *pvalue;
+ } else
+ make_const_array(pparray, a_readonly | avm_foreign,
+ count, &empty_procs[0]);
+ return 0;
+}
+
+/* Get WhitePoint and BlackPoint values. */
+int
+cie_points_param(const ref * pdref, gs_cie_wb * pwb)
+{
+ int code;
+
+ if ((code = dict_float_array_param(pdref, "WhitePoint", 3, (float *)&pwb->WhitePoint, NULL)) != 3 ||
+ (code = dict_float_array_param(pdref, "BlackPoint", 3, (float *)&pwb->BlackPoint, (const float *)&BlackPoint_default)) != 3
+ )
+ return (code < 0 ? code : gs_note_error(e_rangecheck));
+ if (pwb->WhitePoint.u <= 0 ||
+ pwb->WhitePoint.v != 1 ||
+ pwb->WhitePoint.w <= 0 ||
+ pwb->BlackPoint.u < 0 ||
+ pwb->BlackPoint.v < 0 ||
+ pwb->BlackPoint.w < 0
+ )
+ return_error(e_rangecheck);
+ return 0;
+}
+
+/* Process a 3- or 4-dimensional lookup table from a dictionary. */
+/* The caller has set pclt->n and pclt->m. */
+/* ptref is known to be a readable array of size at least n+1. */
+private int cie_3d_table_param(P4(const ref * ptable, uint count, uint nbytes,
+ gs_const_string * strings));
+int
+cie_table_param(const ref * ptref, gx_color_lookup_table * pclt,
+ gs_memory_t * mem)
+{
+ int n = pclt->n, m = pclt->m;
+ const ref *pta = ptref->value.const_refs;
+ int i;
+ uint nbytes;
+ int code;
+ gs_const_string *table;
+
+ for (i = 0; i < n; ++i) {
+ check_type_only(pta[i], t_integer);
+ if (pta[i].value.intval <= 1 || pta[i].value.intval > max_ushort)
+ return_error(e_rangecheck);
+ pclt->dims[i] = (int)pta[i].value.intval;
+ }
+ nbytes = m * pclt->dims[n - 2] * pclt->dims[n - 1];
+ if (n == 3) {
+ /* gs_alloc_byte_array is ****** WRONG ****** */
+ table =
+ (gs_const_string *) gs_alloc_byte_array(mem, pclt->dims[0],
+ sizeof(gs_const_string),
+ "cie_table_param");
+ if (table == 0)
+ return_error(e_VMerror);
+ code = cie_3d_table_param(pta + 3, pclt->dims[0], nbytes, table);
+ } else { /* n == 4 */
+ int d0 = pclt->dims[0], d1 = pclt->dims[1];
+ uint ntables = d0 * d1;
+ const ref *psuba;
+
+ check_read_type(pta[4], t_array);
+ if (r_size(pta + 4) != d0)
+ return_error(e_rangecheck);
+ /* gs_alloc_byte_array is ****** WRONG ****** */
+ table =
+ (gs_const_string *) gs_alloc_byte_array(mem, ntables,
+ sizeof(gs_const_string),
+ "cie_table_param");
+ if (table == 0)
+ return_error(e_VMerror);
+ psuba = pta[4].value.const_refs;
+ for (i = 0; i < d0; ++i) {
+ code = cie_3d_table_param(psuba + i, d1, nbytes, table + d1 * i);
+ if (code < 0)
+ break;
+ }
+ }
+ if (code < 0) {
+ gs_free_object(mem, table, "cie_table_param");
+ return code;
+ }
+ pclt->table = table;
+ return 0;
+}
+private int
+cie_3d_table_param(const ref * ptable, uint count, uint nbytes,
+ gs_const_string * strings)
+{
+ const ref *rstrings;
+ uint i;
+
+ check_read_type(*ptable, t_array);
+ if (r_size(ptable) != count)
+ return_error(e_rangecheck);
+ rstrings = ptable->value.const_refs;
+ for (i = 0; i < count; ++i) {
+ const ref *const prt2 = rstrings + i;
+
+ check_read_type(*prt2, t_string);
+ if (r_size(prt2) != nbytes)
+ return_error(e_rangecheck);
+ strings[i].data = prt2->value.const_bytes;
+ strings[i].size = nbytes;
+ }
+ return 0;
+}
+
+/* ------ CIE setcolorspace ------ */
+
+/* Common code for the CIEBased* cases of setcolorspace. */
+private int
+cie_lmnp_param(const ref * pdref, gs_cie_common * pcie, ref_cie_procs * pcprocs)
+{
+ int code;
+
+ if ((code = dict_range3_param(pdref, "RangeLMN", &pcie->RangeLMN)) < 0 ||
+ (code = dict_proc3_param(pdref, "DecodeLMN", &pcprocs->DecodeLMN)) < 0 ||
+ (code = dict_matrix3_param(pdref, "MatrixLMN", &pcie->MatrixLMN)) != matrix3_ok ||
+ (code = cie_points_param(pdref, &pcie->points)) < 0
+ )
+ return (code < 0 ? code : gs_note_error(e_rangecheck));
+ pcie->DecodeLMN = DecodeLMN_default;
+ return 0;
+}
+
+/* Common code for the CIEBasedABC/DEF[G] cases of setcolorspace. */
+private int
+cie_abc_param(const ref * pdref, gs_cie_abc * pcie, ref_cie_procs * pcprocs)
+{
+ int code;
+
+ if ((code = dict_range3_param(pdref, "RangeABC", &pcie->RangeABC)) < 0 ||
+ (code = dict_proc3_param(pdref, "DecodeABC", &pcprocs->Decode.ABC)) < 0 ||
+ (code = dict_matrix3_param(pdref, "MatrixABC", &pcie->MatrixABC)) != matrix3_ok ||
+ (code = cie_lmnp_param(pdref, &pcie->common, pcprocs)) < 0
+ )
+ return (code < 0 ? code : gs_note_error(e_rangecheck));
+ pcie->DecodeABC = DecodeABC_default;
+ return 0;
+}
+
+/* Finish setting a CIE space. */
+private int
+set_cie_finish(os_ptr op, gs_color_space * pcs, const ref_cie_procs * pcprocs)
+{
+ ref_colorspace cspace_old;
+ uint edepth = ref_stack_count(&e_stack);
+ int code;
+
+ /* The color space installation procedure may refer to */
+ /* istate->colorspace.procs. */
+ cspace_old = istate->colorspace;
+ istate->colorspace.procs.cie = *pcprocs;
+ code = gs_setcolorspace(igs, pcs);
+ /* Delete the extra reference to the parameter tables. */
+ gs_cspace_release(pcs);
+ /* Free the top-level object, which was copied by gs_setcolorspace. */
+ gs_free_object(gs_state_memory(igs), pcs, "set_cie_finish");
+ if (code < 0) {
+ istate->colorspace = cspace_old;
+ ref_stack_pop_to(&e_stack, edepth);
+ return code;
+ }
+ pop(1);
+ return (ref_stack_count(&e_stack) == edepth ? 0 : o_push_estack); /* installation will load the caches */
+}
+
+/* <dict> .setciedefgspace - */
+private int
+zsetciedefgspace(register os_ptr op)
+{
+ gs_memory_t *mem = gs_state_memory(igs);
+ gs_color_space *pcs;
+ ref_color_procs procs;
+ gs_cie_defg *pcie;
+ int code;
+ ref *ptref;
+
+ check_type(*op, t_dictionary);
+ check_dict_read(*op);
+ if ((code = dict_find_string(op, "Table", &ptref)) <= 0)
+ return (code < 0 ? code : gs_note_error(e_rangecheck));
+ check_read_type(*ptref, t_array);
+ if (r_size(ptref) != 5)
+ return_error(e_rangecheck);
+ procs = istate->colorspace.procs;
+ code = gs_cspace_build_CIEDEFG(&pcs, NULL, mem);
+ if (code < 0)
+ return code;
+ pcie = pcs->params.defg;
+ pcie->common.install_cspace = cs_install_zCIEDEFG;
+ pcie->Table.n = 4;
+ pcie->Table.m = 3;
+ if ((code = dict_ranges_param(op, "RangeDEFG", 4, pcie->RangeDEFG.ranges)) < 0 ||
+ (code = dict_proc_array_param(op, "DecodeDEFG", 4, &procs.cie.PreDecode.DEFG)) < 0 ||
+ (code = dict_ranges_param(op, "RangeHIJK", 4, pcie->RangeHIJK.ranges)) < 0 ||
+ (code = cie_table_param(ptref, &pcie->Table, mem)) < 0 ||
+ (code = cie_abc_param(op, (gs_cie_abc *) pcie, &procs.cie)) < 0
+ ) {
+ gs_cspace_release(pcs);
+ gs_free_object(mem, pcs, "setcolorspace(CIEBasedDEFG)");
+ return code;
+ }
+ return set_cie_finish(op, pcs, &procs.cie);
+}
+
+/* <dict> .setciedefspace - */
+private int
+zsetciedefspace(register os_ptr op)
+{
+ gs_memory_t *mem = gs_state_memory(igs);
+ gs_color_space *pcs;
+ ref_color_procs procs;
+ gs_cie_def *pcie;
+ int code;
+ ref *ptref;
+
+ check_type(*op, t_dictionary);
+ check_dict_read(*op);
+ if ((code = dict_find_string(op, "Table", &ptref)) <= 0)
+ return (code < 0 ? code : gs_note_error(e_rangecheck));
+ check_read_type(*ptref, t_array);
+ if (r_size(ptref) != 4)
+ return_error(e_rangecheck);
+ procs = istate->colorspace.procs;
+ code = gs_cspace_build_CIEDEF(&pcs, NULL, mem);
+ if (code < 0)
+ return code;
+ pcie = pcs->params.def;
+ pcie->common.install_cspace = cs_install_zCIEDEF;
+ pcie->Table.n = 3;
+ pcie->Table.m = 3;
+ if ((code = dict_range3_param(op, "RangeDEF", &pcie->RangeDEF)) < 0 ||
+ (code = dict_proc3_param(op, "DecodeDEF", &procs.cie.PreDecode.DEF)) < 0 ||
+ (code = dict_range3_param(op, "RangeHIJ", &pcie->RangeHIJ)) < 0 ||
+ (code = cie_table_param(ptref, &pcie->Table, mem)) < 0 ||
+ (code = cie_abc_param(op, (gs_cie_abc *) pcie, &procs.cie)) < 0
+ ) {
+ gs_cspace_release(pcs);
+ gs_free_object(mem, pcs, "setcolorspace(CIEBasedDEF)");
+ return code;
+ }
+ return set_cie_finish(op, pcs, &procs.cie);
+}
+
+/* <dict> .setcieabcspace - */
+private int
+zsetcieabcspace(register os_ptr op)
+{
+ gs_memory_t *mem = gs_state_memory(igs);
+ gs_color_space *pcs;
+ ref_color_procs procs;
+ gs_cie_abc *pcie;
+ int code;
+
+ check_type(*op, t_dictionary);
+ check_dict_read(*op);
+ procs = istate->colorspace.procs;
+ code = gs_cspace_build_CIEABC(&pcs, NULL, mem);
+ if (code < 0)
+ return code;
+ pcie = pcs->params.abc;
+ pcie->common.install_cspace = cs_install_zCIEABC;
+ code = cie_abc_param(op, pcie, &procs.cie);
+ if (code < 0) {
+ gs_cspace_release(pcs);
+ gs_free_object(mem, pcs, "setcolorspace(CIEBasedABC)");
+ return code;
+ }
+ return set_cie_finish(op, pcs, &procs.cie);
+}
+
+/* <dict> .setcieaspace - */
+private int
+zsetcieaspace(register os_ptr op)
+{
+ gs_memory_t *mem = gs_state_memory(igs);
+ gs_color_space *pcs;
+ ref_color_procs procs;
+ gs_cie_a *pcie;
+ int code;
+
+ check_type(*op, t_dictionary);
+ check_dict_read(*op);
+ procs = istate->colorspace.procs;
+ if ((code = dict_proc_param(op, "DecodeA", &procs.cie.Decode.A, true)) < 0)
+ return code;
+ code = gs_cspace_build_CIEA(&pcs, NULL, mem);
+ if (code < 0)
+ return code;
+ pcie = pcs->params.a;
+ pcie->common.install_cspace = cs_install_zCIEA;
+ if ((code = dict_float_array_param(op, "RangeA", 2, (float *)&pcie->RangeA, (const float *)&RangeA_default)) != 2 ||
+ (code = dict_float_array_param(op, "MatrixA", 3, (float *)&pcie->MatrixA, (const float *)&MatrixA_default)) != 3 ||
+ (code = cie_lmnp_param(op, &pcie->common, &procs.cie)) < 0
+ ) {
+ gs_cspace_release(pcs);
+ gs_free_object(mem, pcs, "setcolorspace(CIEBasedA)");
+ return code;
+ }
+ pcie->DecodeA = DecodeA_default;
+ return set_cie_finish(op, pcs, &procs.cie);
+}
+
+/* ------ Install a CIE-based color space. ------ */
+
+/* Forward references */
+private int cache_common(P4(gs_cie_common *, const ref_cie_procs *,
+ void *, gs_ref_memory_t *));
+private int cache_abc_common(P4(gs_cie_abc *, const ref_cie_procs *,
+ void *, gs_ref_memory_t *));
+
+private int cie_defg_finish(P1(os_ptr));
+private int
+cs_install_zCIEDEFG(gs_color_space * pcs, gs_state * pgs)
+{
+ es_ptr ep = esp;
+ gs_cie_defg *pcie = pcs->params.defg;
+ gs_ref_memory_t *imem = (gs_ref_memory_t *) gs_state_memory(pgs);
+ const int_gstate *pigs = gs_int_gstate(pgs);
+ const ref_cie_procs *pcprocs = &pigs->colorspace.procs.cie;
+ int code = gx_install_CIEDEFG(pcs, pgs); /* base routine */
+
+ if (code < 0 ||
+ (code = cie_cache_joint(&pigs->colorrendering.procs, pgs)) < 0 || /* do this last */
+ (code = cie_cache_push_finish(cie_defg_finish, imem, pcie)) < 0 ||
+ (code = cie_prepare_cache4(&pcie->RangeDEFG,
+ pcprocs->PreDecode.DEFG.value.const_refs,
+ &pcie->caches_defg.DecodeDEFG[0],
+ pcie, imem, "Decode.DEFG")) < 0 ||
+ (code = cache_abc_common((gs_cie_abc *)pcie, pcprocs, pcie, imem)) < 0
+ ) {
+ esp = ep;
+ return code;
+ }
+ return o_push_estack;
+}
+private int
+cie_defg_finish(os_ptr op)
+{
+ gs_cie_defg_complete(r_ptr(op, gs_cie_defg));
+ pop(1);
+ return 0;
+}
+
+private int cie_def_finish(P1(os_ptr));
+private int
+cs_install_zCIEDEF(gs_color_space * pcs, gs_state * pgs)
+{
+ es_ptr ep = esp;
+ gs_cie_def *pcie = pcs->params.def;
+ gs_ref_memory_t *imem = (gs_ref_memory_t *) gs_state_memory(pgs);
+ const int_gstate *pigs = gs_int_gstate(pgs);
+ const ref_cie_procs *pcprocs = &pigs->colorspace.procs.cie;
+ int code = gx_install_CIEDEF(pcs, pgs); /* base routine */
+
+ if (code < 0 ||
+ (code = cie_cache_joint(&pigs->colorrendering.procs, pgs)) < 0 || /* do this last */
+ (code = cie_cache_push_finish(cie_def_finish, imem, pcie)) < 0 ||
+ (code = cie_prepare_cache3(&pcie->RangeDEF,
+ pcprocs->PreDecode.DEF.value.const_refs,
+ &pcie->caches_def.DecodeDEF[0],
+ pcie, imem, "Decode.DEF")) < 0 ||
+ (code = cache_abc_common((gs_cie_abc *)pcie, pcprocs, pcie, imem)) < 0
+ ) {
+ esp = ep;
+ return code;
+ }
+ return o_push_estack;
+}
+private int
+cie_def_finish(os_ptr op)
+{
+ gs_cie_def_complete(r_ptr(op, gs_cie_def));
+ pop(1);
+ return 0;
+}
+
+private int cie_abc_finish(P1(os_ptr));
+private int
+cs_install_zCIEABC(gs_color_space * pcs, gs_state * pgs)
+{
+ es_ptr ep = esp;
+ gs_cie_abc *pcie = pcs->params.abc;
+ gs_ref_memory_t *imem = (gs_ref_memory_t *) gs_state_memory(pgs);
+ const int_gstate *pigs = gs_int_gstate(pgs);
+ const ref_cie_procs *pcprocs = &pigs->colorspace.procs.cie;
+ int code = gx_install_CIEABC(pcs, pgs); /* base routine */
+
+ if (code < 0 ||
+ (code = cie_cache_joint(&pigs->colorrendering.procs, pgs)) < 0 || /* do this last */
+ (code = cie_cache_push_finish(cie_abc_finish, imem, pcie)) < 0 ||
+ (code = cache_abc_common(pcie, pcprocs, pcie, imem)) < 0
+ ) {
+ esp = ep;
+ return code;
+ }
+ return o_push_estack;
+}
+private int
+cie_abc_finish(os_ptr op)
+{
+ gs_cie_abc_complete(r_ptr(op, gs_cie_abc));
+ pop(1);
+ return 0;
+}
+
+private int cie_a_finish(P1(os_ptr));
+private int
+cs_install_zCIEA(gs_color_space * pcs, gs_state * pgs)
+{
+ es_ptr ep = esp;
+ gs_cie_a *pcie = pcs->params.a;
+ gs_ref_memory_t *imem = (gs_ref_memory_t *) gs_state_memory(pgs);
+ const int_gstate *pigs = gs_int_gstate(pgs);
+ const ref_cie_procs *pcprocs = &pigs->colorspace.procs.cie;
+ int code = gx_install_CIEA(pcs, pgs); /* base routine */
+
+ if (code < 0 ||
+ (code = cie_cache_joint(&pigs->colorrendering.procs, pgs)) < 0 || /* do this last */
+ (code = cie_cache_push_finish(cie_a_finish, imem, pcie)) < 0 ||
+ (code = cie_prepare_cache(&pcie->RangeA, &pcprocs->Decode.A, &pcie->caches.DecodeA.floats, pcie, imem, "Decode.A")) < 0 ||
+ (code = cache_common(&pcie->common, pcprocs, pcie, imem)) < 0
+ ) {
+ esp = ep;
+ return code;
+ }
+ return o_push_estack;
+}
+private int
+cie_a_finish(os_ptr op)
+{
+ gs_cie_a_complete(r_ptr(op, gs_cie_a));
+ pop(1);
+ return 0;
+}
+
+/* Common cache code */
+
+private int
+cache_abc_common(gs_cie_abc * pcie, const ref_cie_procs * pcprocs,
+ void *container, gs_ref_memory_t * imem)
+{
+ int code =
+ cie_prepare_cache3(&pcie->RangeABC,
+ pcprocs->Decode.ABC.value.const_refs,
+ &pcie->caches.DecodeABC[0], pcie, imem,
+ "Decode.ABC");
+
+ return (code < 0 ? code :
+ cache_common(&pcie->common, pcprocs, pcie, imem));
+}
+
+private int
+cache_common(gs_cie_common * pcie, const ref_cie_procs * pcprocs,
+ void *container, gs_ref_memory_t * imem)
+{
+ return cie_prepare_cache3(&pcie->RangeLMN,
+ pcprocs->DecodeLMN.value.const_refs,
+ &pcie->caches.DecodeLMN[0], container, imem,
+ "Decode.LMN");
+}
+
+/* ------ Internal routines ------ */
+
+/* Prepare to cache the values for one or more procedures. */
+private int cie_cache_finish1(P1(os_ptr));
+private int cie_cache_finish(P1(os_ptr));
+int
+cie_prepare_cache(const gs_range * domain, const ref * proc,
+ cie_cache_floats * pcache, void *container,
+ gs_ref_memory_t * imem, client_name_t cname)
+{
+ int space = imemory_space(imem);
+ gs_for_loop_params flp;
+ es_ptr ep;
+
+ gs_cie_cache_init(&pcache->params, &flp, domain, cname);
+ pcache->params.is_identity = r_size(proc) == 0;
+ /*
+ * If a matrix was singular, it is possible that flp.step = 0.
+ * In this case, flp.limit = flp.init as well.
+ * Execute the procedure once, and replicate the result.
+ */
+ if (flp.step == 0) {
+ check_estack(5);
+ ep = esp;
+ make_real(ep + 5, flp.init);
+ ep[4] = *proc;
+ make_op_estack(ep + 3, cie_cache_finish1);
+ esp += 5;
+ } else {
+ check_estack(9);
+ ep = esp;
+ make_real(ep + 9, flp.init);
+ make_real(ep + 8, flp.step);
+ make_real(ep + 7, flp.limit);
+ ep[6] = *proc;
+ r_clear_attrs(ep + 6, a_executable);
+ make_op_estack(ep + 5, zcvx);
+ make_op_estack(ep + 4, zfor);
+ make_op_estack(ep + 3, cie_cache_finish);
+ esp += 9;
+ }
+ /*
+ * The caches are embedded in the middle of other
+ * structures, so we represent the pointer to the cache
+ * as a pointer to the container plus an offset.
+ */
+ make_int(ep + 2, (char *)pcache - (char *)container);
+ make_struct(ep + 1, space, container);
+ return o_push_estack;
+}
+/* Note that pc3 may be 0, indicating that there are only 3 caches to load. */
+int
+cie_prepare_caches_4(const gs_range * domains, const ref * procs,
+ cie_cache_floats * pc0, cie_cache_floats * pc1,
+ cie_cache_floats * pc2, cie_cache_floats * pc3,
+ void *container,
+ gs_ref_memory_t * imem, client_name_t cname)
+{
+ cie_cache_floats *pcn[4];
+ int i, n, code = 0;
+
+ pcn[0] = pc0, pcn[1] = pc1, pcn[2] = pc2;
+ if (pc3 == 0)
+ n = 3;
+ else
+ pcn[3] = pc3, n = 4;
+ for (i = 0; i < n && code >= 0; ++i)
+ code = cie_prepare_cache(domains + i, procs + i, pcn[i],
+ container, imem, cname);
+ return code;
+}
+
+/* Store the result of caching one procedure. */
+private int
+cie_cache_finish_store(os_ptr op, bool replicate)
+{
+ cie_cache_floats *pcache;
+ int code;
+
+ check_esp(2);
+ /* See above for the container + offset representation of */
+ /* the pointer to the cache. */
+ pcache = (cie_cache_floats *) (r_ptr(esp - 1, char) + esp->value.intval);
+
+ if_debug3('c', "[c]cache 0x%lx base=%g, factor=%g:\n",
+ (ulong) pcache, pcache->params.base, pcache->params.factor);
+ if (replicate ||
+ (code = float_params(op, gx_cie_cache_size, &pcache->values[0])) < 0
+ ) {
+ /* We might have underflowed the current stack block. */
+ /* Handle the parameters one-by-one. */
+ uint i;
+
+ for (i = 0; i < gx_cie_cache_size; i++) {
+ code = float_param(ref_stack_index(&o_stack,
+ (replicate ? 0 : gx_cie_cache_size - 1 - i)),
+ &pcache->values[i]);
+ if (code < 0)
+ return code;
+ }
+ }
+#ifdef DEBUG
+ if (gs_debug_c('c')) {
+ int i;
+
+ for (i = 0; i < gx_cie_cache_size; i += 4)
+ dlprintf5("[c] cache[%3d]=%g, %g, %g, %g\n", i,
+ pcache->values[i], pcache->values[i + 1],
+ pcache->values[i + 2], pcache->values[i + 3]);
+ }
+#endif
+ ref_stack_pop(&o_stack, (replicate ? 1 : gx_cie_cache_size));
+ esp -= 2; /* pop pointer to cache */
+ return o_pop_estack;
+}
+private int
+cie_cache_finish(os_ptr op)
+{
+ return cie_cache_finish_store(op, false);
+}
+private int
+cie_cache_finish1(os_ptr op)
+{
+ return cie_cache_finish_store(op, true);
+}
+
+/* Push a finishing procedure on the e-stack. */
+/* ptr will be the top element of the o-stack. */
+int
+cie_cache_push_finish(int (*finish_proc) (P1(os_ptr)), gs_ref_memory_t * imem,
+ void *data)
+{
+ check_estack(2);
+ push_op_estack(finish_proc);
+ ++esp;
+ make_struct(esp, imemory_space(imem), data);
+ return o_push_estack;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zcie_l2_op_defs[] =
+{
+ op_def_begin_level2(),
+ {"1.setcieaspace", zsetcieaspace},
+ {"1.setcieabcspace", zsetcieabcspace},
+ {"1.setciedefspace", zsetciedefspace},
+ {"1.setciedefgspace", zsetciedefgspace},
+ /* Internal operators */
+ {"1%cie_defg_finish", cie_defg_finish},
+ {"1%cie_def_finish", cie_def_finish},
+ {"1%cie_abc_finish", cie_abc_finish},
+ {"1%cie_a_finish", cie_a_finish},
+ {"0%cie_cache_finish", cie_cache_finish},
+ {"1%cie_cache_finish1", cie_cache_finish1},
+ op_def_end(0)
+};
diff --git a/pstoraster/zcolor.c b/pstoraster/zcolor.c
new file mode 100644
index 000000000..27e12d1ad
--- /dev/null
+++ b/pstoraster/zcolor.c
@@ -0,0 +1,241 @@
+/* Copyright (C) 1989, 1992, 1993, 1994, 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$ */
+/* Color operators */
+#include "ghost.h"
+#include "oper.h"
+#include "estack.h"
+#include "ialloc.h"
+#include "igstate.h"
+#include "iutil.h"
+#include "store.h"
+#include "gxfixed.h"
+#include "gxmatrix.h"
+#include "gzstate.h"
+#include "gxdevice.h"
+#include "gxcmap.h"
+#include "icolor.h"
+
+/* Import the 'for' operator */
+extern int
+ zfor_fraction(P1(os_ptr));
+
+/* Imported from gsht.c */
+void gx_set_effective_transfer(P1(gs_state *));
+
+/* Define the number of stack slots needed for zcolor_remap_one. */
+const int zcolor_remap_one_ostack = 4;
+const int zcolor_remap_one_estack = 3;
+
+/* - currentgray <gray> */
+private int
+zcurrentgray(register os_ptr op)
+{
+ push(1);
+ make_real(op, gs_currentgray(igs));
+ return 0;
+}
+
+/* - currentrgbcolor <red> <green> <blue> */
+private int
+zcurrentrgbcolor(register os_ptr op)
+{
+ float par[3];
+
+ gs_currentrgbcolor(igs, par);
+ push(3);
+ make_floats(op - 2, par, 3);
+ return 0;
+}
+
+/* - currenttransfer <proc> */
+private int
+zcurrenttransfer(register os_ptr op)
+{
+ push(1);
+ *op = istate->transfer_procs.colored.gray;
+ return 0;
+}
+
+/* - processcolors <int> - */
+/* Note: this is an undocumented operator that is not supported */
+/* in Level 2. */
+private int
+zprocesscolors(register os_ptr op)
+{
+ push(1);
+ make_int(op, gs_currentdevice(igs)->color_info.num_components);
+ return 0;
+}
+
+/* <gray> setgray - */
+private int
+zsetgray(register os_ptr op)
+{
+ double gray;
+ int code;
+
+ if (real_param(op, &gray) < 0)
+ return_op_typecheck(op);
+ if ((code = gs_setgray(igs, gray)) < 0)
+ return code;
+ make_null(&istate->colorspace.array);
+ pop(1);
+ return 0;
+}
+
+/* <red> <green> <blue> setrgbcolor - */
+private int
+zsetrgbcolor(register os_ptr op)
+{
+ double par[3];
+ int code;
+
+ if ((code = num_params(op, 3, par)) < 0 ||
+ (code = gs_setrgbcolor(igs, par[0], par[1], par[2])) < 0
+ )
+ return code;
+ make_null(&istate->colorspace.array);
+ pop(3);
+ return 0;
+}
+
+/* <proc> settransfer - */
+private int
+zsettransfer(register os_ptr op)
+{
+ int code;
+
+ check_proc(*op);
+ check_ostack(zcolor_remap_one_ostack - 1);
+ check_estack(1 + zcolor_remap_one_estack);
+ istate->transfer_procs.colored.red =
+ istate->transfer_procs.colored.green =
+ istate->transfer_procs.colored.blue =
+ istate->transfer_procs.colored.gray = *op;
+ code = gs_settransfer_remap(igs, gs_mapped_transfer, false);
+ if (code < 0)
+ return code;
+ push_op_estack(zcolor_reset_transfer);
+ pop(1);
+ op--;
+ return zcolor_remap_one(&istate->transfer_procs.colored.gray, op,
+ igs->set_transfer.colored.gray, igs,
+ zcolor_remap_one_finish);
+}
+
+/* ------ Internal routines ------ */
+
+/* Prepare to remap one color component */
+/* (also used for black generation and undercolor removal). */
+/* Use the 'for' operator to gather the values. */
+/* The caller must have done the necessary check_ostack and check_estack. */
+int
+zcolor_remap_one(const ref * pproc, register os_ptr op, gx_transfer_map * pmap,
+ const gs_state * pgs, int (*finish_proc)(P1(os_ptr)))
+{
+ osp = op += 4;
+ make_int(op - 3, 0);
+ make_int(op - 2, 1);
+ make_int(op - 1, transfer_map_size - 1);
+ *op = *pproc;
+ ++esp;
+ make_struct(esp, imemory_space((gs_ref_memory_t *) pgs->memory),
+ pmap);
+ push_op_estack(finish_proc);
+ push_op_estack(zfor_fraction);
+ return o_push_estack;
+}
+
+/* Store the result of remapping a component. */
+private int
+zcolor_remap_one_store(os_ptr op, floatp min_value)
+{
+ int i;
+ gx_transfer_map *pmap = r_ptr(esp, gx_transfer_map);
+
+ if (ref_stack_count(&o_stack) < transfer_map_size)
+ return_error(e_stackunderflow);
+ for (i = 0; i < transfer_map_size; i++) {
+ double v;
+ int code =
+ real_param(ref_stack_index(&o_stack, transfer_map_size - 1 - i),
+ &v);
+
+ if (code < 0)
+ return code;
+ pmap->values[i] =
+ (v < min_value ? float2frac(min_value) :
+ v >= 1.0 ? frac_1 :
+ float2frac(v));
+ }
+ ref_stack_pop(&o_stack, transfer_map_size);
+ esp--; /* pop pointer to transfer map */
+ return o_pop_estack;
+}
+int
+zcolor_remap_one_finish(os_ptr op)
+{
+ return zcolor_remap_one_store(op, 0.0);
+}
+int
+zcolor_remap_one_signed_finish(os_ptr op)
+{
+ return zcolor_remap_one_store(op, -1.0);
+}
+
+/* Finally, reset the effective transfer functions and */
+/* invalidate the current color. */
+int
+zcolor_reset_transfer(os_ptr op)
+{
+ gx_set_effective_transfer(igs);
+ return zcolor_remap_color(op);
+}
+int
+zcolor_remap_color(os_ptr op)
+{
+ gx_unset_dev_color(igs);
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zcolor_op_defs[] =
+{
+ {"0currentgray", zcurrentgray},
+ {"0currentrgbcolor", zcurrentrgbcolor},
+ {"0currenttransfer", zcurrenttransfer},
+ {"0processcolors", zprocesscolors},
+ {"1setgray", zsetgray},
+ {"3setrgbcolor", zsetrgbcolor},
+ {"1settransfer", zsettransfer},
+ /* Internal operators */
+ {"1%zcolor_remap_one_finish", zcolor_remap_one_finish},
+ {"1%zcolor_remap_one_signed_finish", zcolor_remap_one_signed_finish},
+ {"0%zcolor_reset_transfer", zcolor_reset_transfer},
+ {"0%zcolor_remap_color", zcolor_remap_color},
+ op_def_end(0)
+};
diff --git a/pstoraster/zcolor1.c b/pstoraster/zcolor1.c
new file mode 100644
index 000000000..7f6daf786
--- /dev/null
+++ b/pstoraster/zcolor1.c
@@ -0,0 +1,247 @@
+/* Copyright (C) 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$ */
+/* Level 1 extended color operators */
+#include "ghost.h"
+#include "oper.h"
+#include "estack.h"
+#include "ialloc.h"
+#include "igstate.h"
+#include "iutil.h"
+#include "store.h"
+#include "gxfixed.h"
+#include "gxmatrix.h"
+#include "gzstate.h"
+#include "gxdevice.h"
+#include "gxcmap.h"
+#include "gscolor1.h"
+#include "gxcspace.h"
+#include "icolor.h"
+#include "iimage.h"
+
+/* - currentblackgeneration <proc> */
+private int
+zcurrentblackgeneration(register os_ptr op)
+{
+ push(1);
+ *op = istate->black_generation;
+ return 0;
+}
+
+/* - currentcmykcolor <cyan> <magenta> <yellow> <black> */
+private int
+zcurrentcmykcolor(register os_ptr op)
+{
+ float par[4];
+
+ gs_currentcmykcolor(igs, par);
+ push(4);
+ make_floats(op - 3, par, 4);
+ return 0;
+}
+
+/* - currentcolortransfer <redproc> <greenproc> <blueproc> <grayproc> */
+private int
+zcurrentcolortransfer(register os_ptr op)
+{
+ push(4);
+ op[-3] = istate->transfer_procs.colored.red;
+ op[-2] = istate->transfer_procs.colored.green;
+ op[-1] = istate->transfer_procs.colored.blue;
+ *op = istate->transfer_procs.colored.gray;
+ return 0;
+}
+
+/* - currentundercolorremoval <proc> */
+private int
+zcurrentundercolorremoval(register os_ptr op)
+{
+ push(1);
+ *op = istate->undercolor_removal;
+ return 0;
+}
+
+/* <proc> setblackgeneration - */
+private int
+zsetblackgeneration(register os_ptr op)
+{
+ int code;
+
+ check_proc(*op);
+ check_ostack(zcolor_remap_one_ostack - 1);
+ check_estack(1 + zcolor_remap_one_estack);
+ code = gs_setblackgeneration_remap(igs, gs_mapped_transfer, false);
+ if (code < 0)
+ return code;
+ istate->black_generation = *op;
+ pop(1);
+ op--;
+ push_op_estack(zcolor_remap_color);
+ return zcolor_remap_one(&istate->black_generation, op,
+ igs->black_generation, igs,
+ zcolor_remap_one_finish);
+}
+
+/* <cyan> <magenta> <yellow> <black> setcmykcolor - */
+private int
+zsetcmykcolor(register os_ptr op)
+{
+ double par[4];
+ int code;
+
+ if ((code = num_params(op, 4, par)) < 0 ||
+ (code = gs_setcmykcolor(igs, par[0], par[1], par[2], par[3])) < 0
+ )
+ return code;
+ make_null(&istate->colorspace.array);
+ pop(4);
+ return 0;
+}
+
+/* <redproc> <greenproc> <blueproc> <grayproc> setcolortransfer - */
+private int
+zsetcolortransfer(register os_ptr op)
+{
+ int code;
+
+ check_proc(op[-3]);
+ check_proc(op[-2]);
+ check_proc(op[-1]);
+ check_proc(*op);
+ check_ostack(zcolor_remap_one_ostack * 4 - 4);
+ check_estack(1 + zcolor_remap_one_estack * 4);
+ istate->transfer_procs.colored.red = op[-3];
+ istate->transfer_procs.colored.green = op[-2];
+ istate->transfer_procs.colored.blue = op[-1];
+ istate->transfer_procs.colored.gray = *op;
+ if ((code = gs_setcolortransfer_remap(igs,
+ gs_mapped_transfer, gs_mapped_transfer,
+ gs_mapped_transfer, gs_mapped_transfer,
+ false)) < 0
+ )
+ return code;
+ /* Use osp rather than op here, because zcolor_remap_one pushes. */
+ pop(4);
+ op -= 4;
+ push_op_estack(zcolor_reset_transfer);
+ if ((code = zcolor_remap_one(&istate->transfer_procs.colored.red,
+ osp, igs->set_transfer.colored.red, igs,
+ zcolor_remap_one_finish)) < 0 ||
+ (code = zcolor_remap_one(&istate->transfer_procs.colored.green,
+ osp, igs->set_transfer.colored.green, igs,
+ zcolor_remap_one_finish)) < 0 ||
+ (code = zcolor_remap_one(&istate->transfer_procs.colored.blue,
+ osp, igs->set_transfer.colored.blue, igs,
+ zcolor_remap_one_finish)) < 0
+ )
+ return code;
+ return zcolor_remap_one(&istate->transfer_procs.colored.gray,
+ osp, igs->set_transfer.colored.gray, igs,
+ zcolor_remap_one_finish);
+}
+
+/* <proc> setundercolorremoval - */
+private int
+zsetundercolorremoval(register os_ptr op)
+{
+ int code;
+
+ check_proc(*op);
+ check_ostack(zcolor_remap_one_ostack - 1);
+ check_estack(1 + zcolor_remap_one_estack);
+ code = gs_setundercolorremoval_remap(igs, gs_mapped_transfer, false);
+ if (code < 0)
+ return code;
+ istate->undercolor_removal = *op;
+ pop(1);
+ op--;
+ push_op_estack(zcolor_remap_color);
+ return zcolor_remap_one(&istate->undercolor_removal, op,
+ igs->undercolor_removal, igs,
+ zcolor_remap_one_signed_finish);
+}
+
+/* <width> <height> <bits/comp> <matrix> */
+/* <datasrc_0> ... <datasrc_ncomp-1> true <ncomp> colorimage - */
+/* <datasrc> false <ncomp> colorimage - */
+int zimage_multiple(P2(os_ptr op, bool has_alpha));
+private int
+zcolorimage(register os_ptr op)
+{
+ return zimage_multiple(op, false);
+}
+/* We export zimage_multiple for alphaimage. */
+int
+zimage_multiple(os_ptr op, bool has_alpha)
+{
+ int spp; /* samples per pixel */
+ int npop = 7;
+ os_ptr procp = op - 2;
+ const gs_color_space *pcs;
+ bool multi = false;
+
+ check_int_leu(*op, 4); /* ncolors */
+ check_type(op[-1], t_boolean); /* multiproc */
+ switch ((spp = (int)(op->value.intval))) {
+ case 1:
+ pcs = gs_cspace_DeviceGray((const gs_imager_state *)igs);
+ break;
+ case 3:
+ pcs = gs_cspace_DeviceRGB((const gs_imager_state *)igs);
+ goto color;
+ case 4:
+ pcs = gs_cspace_DeviceCMYK((const gs_imager_state *)igs);
+color:
+ if (op[-1].value.boolval) { /* planar format */
+ if (has_alpha)
+ ++spp;
+ npop += spp - 1;
+ procp -= spp - 1;
+ multi = true;
+ }
+ break;
+ default:
+ return_error(e_rangecheck);
+ }
+ return zimage_opaque_setup(procp, multi,
+ (has_alpha ? gs_image_alpha_last : gs_image_alpha_none),
+ pcs, npop);
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zcolor1_op_defs[] =
+{
+ {"0currentblackgeneration", zcurrentblackgeneration},
+ {"0currentcmykcolor", zcurrentcmykcolor},
+ {"0currentcolortransfer", zcurrentcolortransfer},
+ {"0currentundercolorremoval", zcurrentundercolorremoval},
+ {"1setblackgeneration", zsetblackgeneration},
+ {"4setcmykcolor", zsetcmykcolor},
+ {"4setcolortransfer", zsetcolortransfer},
+ {"1setundercolorremoval", zsetundercolorremoval},
+ {"7colorimage", zcolorimage},
+ op_def_end(0)
+};
diff --git a/pstoraster/zcolor2.c b/pstoraster/zcolor2.c
new file mode 100644
index 000000000..a3085a9eb
--- /dev/null
+++ b/pstoraster/zcolor2.c
@@ -0,0 +1,191 @@
+/* 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$ */
+/* Level 2 color operators */
+#include "ghost.h"
+#include "oper.h"
+#include "gscolor.h"
+#include "gsmatrix.h"
+#include "gsstruct.h"
+#include "gxcspace.h"
+#include "gxfixed.h" /* for gxcolor2.h */
+#include "gxcolor2.h"
+#include "gxdcolor.h" /* for gxpcolor.h */
+#include "gxdevice.h"
+#include "gxdevmem.h" /* for gxpcolor.h */
+#include "gxpcolor.h"
+#include "estack.h"
+#include "ialloc.h"
+#include "istruct.h"
+#include "idict.h"
+#include "idparam.h"
+#include "igstate.h"
+#include "store.h"
+
+/* Declare a local alias for st_pattern_instance. */
+/* We do this so we can have configurations with */
+/* the base Level 2 color machinery but without patterns. */
+gs_memory_type_ptr_t zcolor2_st_pattern_instance_p = 0;
+
+/* Forward references */
+private int store_color_params(P3(os_ptr, const gs_paint_color *,
+ const gs_color_space *));
+private int load_color_params(P3(os_ptr, gs_paint_color *,
+ const gs_color_space *));
+
+/* - currentcolor <param1> ... <paramN> */
+private int
+zcurrentcolor(register os_ptr op)
+{
+ const gs_client_color *pc = gs_currentcolor(igs);
+ const gs_color_space *pcs = gs_currentcolorspace(igs);
+ int n;
+
+ check_ostack(5); /* Worst case: CMYK + pattern */
+ if (pcs->type->index == gs_color_space_index_Pattern) {
+ n = 1;
+ if (pc->pattern != 0 && pc->pattern->template.PaintType == 2) /* uncolored */
+ n += store_color_params(op, &pc->paint,
+ (const gs_color_space *)&pcs->params.pattern.base_space);
+ op[n] = istate->pattern;
+ } else
+ n = store_color_params(op, &pc->paint, pcs);
+ push(n);
+ return 0;
+}
+
+/* - .currentcolorspace <array|int> */
+private int
+zcurrentcolorspace(register os_ptr op)
+{
+ push(1);
+ if (r_has_type(&istate->colorspace.array, t_null)) {
+ /*
+ * Return the color space index. This is only possible
+ * for the parameterless color spaces.
+ */
+ make_int(op, (int)(gs_currentcolorspace(igs)->type->index));
+ } else
+ *op = istate->colorspace.array;
+ return 0;
+}
+
+/* <param1> ... <paramN> setcolor - */
+private int
+zsetcolor(register os_ptr op)
+{
+ gs_client_color c;
+ const gs_color_space *pcs = gs_currentcolorspace(igs);
+ int n, code;
+ gs_pattern_instance *pinst = 0;
+
+ if (pcs->type->index == gs_color_space_index_Pattern) {
+ /* Make sure *op is a real Pattern. */
+ ref *pImpl;
+
+ check_type(*op, t_dictionary);
+ check_dict_read(*op);
+ if (dict_find_string(op, "Implementation", &pImpl) <= 0 ||
+ !r_has_stype(pImpl, imemory, *zcolor2_st_pattern_instance_p)
+ )
+ return_error(e_rangecheck);
+ pinst = r_ptr(pImpl, gs_pattern_instance);
+ c.pattern = pinst;
+ if (pinst->template.PaintType == 2) { /* uncolored */
+ if (!pcs->params.pattern.has_base_space)
+ return_error(e_rangecheck);
+ n = load_color_params(op - 1, &c.paint,
+ (const gs_color_space *)&pcs->params.pattern.base_space);
+ if (n < 0)
+ return n;
+ n++;
+ } else
+ n = 1;
+ } else {
+ n = load_color_params(op, &c.paint, pcs);
+ c.pattern = 0; /* for GC */
+ }
+ if (n < 0)
+ return n;
+ code = gs_setcolor(igs, &c);
+ if (code < 0)
+ return code;
+ if (pinst != 0)
+ istate->pattern = *op;
+ pop(n);
+ return code;
+}
+
+/* <array> .setcolorspace - */
+private int
+zsetcolorspace(register os_ptr op)
+{
+ check_type(*op, t_array);
+ istate->colorspace.array = *op;
+ pop(1);
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zcolor2_l2_op_defs[] =
+{
+ op_def_begin_level2(),
+ {"0currentcolor", zcurrentcolor},
+ {"0.currentcolorspace", zcurrentcolorspace},
+ {"1setcolor", zsetcolor},
+ {"1.setcolorspace", zsetcolorspace},
+ op_def_end(0)
+};
+
+/* ------ Internal procedures ------ */
+
+/* Store non-pattern color values on the operand stack. */
+/* Return the number of values stored. */
+private int
+store_color_params(os_ptr op, const gs_paint_color * pc,
+ const gs_color_space * pcs)
+{
+ int n = cs_num_components(pcs);
+
+ if (pcs->type->index == gs_color_space_index_Indexed)
+ make_int(op + 1, (int)pc->values[0]);
+ else
+ make_floats(op + 1, pc->values, n);
+ return n;
+}
+
+/* Load non-pattern color values from the operand stack. */
+/* Return the number of values stored. */
+private int
+load_color_params(os_ptr op, gs_paint_color * pc, const gs_color_space * pcs)
+{
+ int n = cs_num_components(pcs);
+ int code = float_params(op, n, pc->values);
+
+ if (code < 0)
+ return code;
+ return n;
+}
diff --git a/pstoraster/zcontrol.c b/pstoraster/zcontrol.c
new file mode 100644
index 000000000..f08d0ede5
--- /dev/null
+++ b/pstoraster/zcontrol.c
@@ -0,0 +1,897 @@
+/*
+ Copyright 1993-2002 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$ */
+/* Control operators */
+#include "string_.h"
+#include "ghost.h"
+#include "stream.h"
+#include "oper.h"
+#include "estack.h"
+#include "files.h"
+#include "ipacked.h"
+#include "iutil.h"
+#include "store.h"
+
+/* Make an invalid file object. */
+extern void make_invalid_file(P1(ref *)); /* in zfile.c */
+
+/* Forward references */
+private int no_cleanup(P1(os_ptr));
+private uint count_exec_stack(P1(bool));
+private uint count_to_stopped(P1(long));
+private int unmatched_exit(P2(os_ptr, op_proc_p));
+
+/* See the comment in opdef.h for an invariant which allows */
+/* more efficient implementation of for, loop, and repeat. */
+
+/* <[test0 body0 ...]> .cond - */
+private int cond_continue(P1(os_ptr));
+private int
+zcond(register os_ptr op)
+{
+ es_ptr ep = esp;
+
+ /* Push the array on the e-stack and call the continuation. */
+ if (!r_is_array(op))
+ return_op_typecheck(op);
+ check_execute(*op);
+ if ((r_size(op) & 1) != 0)
+ return_error(e_rangecheck);
+ if (r_size(op) == 0)
+ return zpop(op);
+ check_estack(3);
+ esp = ep += 3;
+ ref_assign(ep - 2, op); /* the cond body */
+ make_op_estack(ep - 1, cond_continue);
+ array_get(op, 0L, ep);
+ esfile_check_cache();
+ pop(1);
+ return o_push_estack;
+}
+private int
+cond_continue(register os_ptr op)
+{
+ es_ptr ep = esp;
+ int code;
+
+ /* The top element of the e-stack is the remaining tail of */
+ /* the cond body. The top element of the o-stack should be */
+ /* the (boolean) result of the test that is the first element */
+ /* of the tail. */
+ check_type(*op, t_boolean);
+ if (op->value.boolval) { /* true */
+ array_get(ep, 1L, ep);
+ esfile_check_cache();
+ code = o_pop_estack;
+ } else if (r_size(ep) > 2) { /* false */
+ const ref_packed *elts = ep->value.packed;
+
+ check_estack(2);
+ r_dec_size(ep, 2);
+ elts = packed_next(elts);
+ elts = packed_next(elts);
+ ep->value.packed = elts;
+ array_get(ep, 0L, ep + 2);
+ make_op_estack(ep + 1, cond_continue);
+ esp = ep + 2;
+ esfile_check_cache();
+ code = o_push_estack;
+ } else { /* fall off end of cond */
+ esp = ep - 1;
+ code = o_pop_estack;
+ }
+ pop(1); /* get rid of the boolean */
+ return code;
+}
+
+/* <obj> exec - */
+int
+zexec(register os_ptr op)
+{
+ check_op(1);
+ if (!r_has_attr(op, a_executable))
+ return 0; /* literal object just gets pushed back */
+ check_estack(1);
+ ++esp;
+ ref_assign(esp, op);
+ esfile_check_cache();
+ pop(1);
+ return o_push_estack;
+}
+
+/* <obj1> ... <objn> <n> .execn - */
+int
+zexecn(register os_ptr op)
+{
+ uint n, i;
+ es_ptr esp_orig;
+
+ check_int_leu(*op, max_uint - 1);
+ n = (uint) op->value.intval;
+ check_op(n + 1);
+ check_estack(n);
+ esp_orig = esp;
+ for (i = 0; i < n; ++i) {
+ const ref *rp = ref_stack_index(&o_stack, (long)(i + 1));
+
+ /* Make sure this object is legal to execute. */
+ if (ref_type_uses_access(r_type(rp))) {
+ if (!r_has_attr(rp, a_execute) &&
+ r_has_attr(rp, a_executable)
+ ) {
+ esp = esp_orig;
+ return_error(e_invalidaccess);
+ }
+ }
+ /* Executable nulls have a special meaning on the e-stack, */
+ /* so since they are no-ops, don't push them. */
+ if (!r_has_type_attrs(rp, t_null, a_executable)) {
+ ++esp;
+ ref_assign(esp, rp);
+ }
+ }
+ esfile_check_cache();
+ pop(n + 1);
+ return o_push_estack;
+}
+
+/* <obj> superexec - */
+/* THIS IS NOT REALLY IMPLEMENTED YET. */
+private int
+zsuperexec(os_ptr op)
+{
+ return zexec(op);
+}
+
+/* <bool> <proc> if - */
+int
+zif(register os_ptr op)
+{
+ check_type(op[-1], t_boolean);
+ check_proc(*op);
+ if (op[-1].value.boolval) {
+ check_estack(1);
+ ++esp;
+ ref_assign(esp, op);
+ esfile_check_cache();
+ }
+ pop(2);
+ return o_push_estack;
+}
+
+/* <bool> <proc_true> <proc_false> ifelse - */
+int
+zifelse(register os_ptr op)
+{
+ check_type(op[-2], t_boolean);
+ check_proc(op[-1]);
+ check_proc(*op);
+ check_estack(1);
+ ++esp;
+ if (op[-2].value.boolval) {
+ ref_assign(esp, op - 1);
+ } else {
+ ref_assign(esp, op);
+ }
+ esfile_check_cache();
+ pop(3);
+ return o_push_estack;
+}
+
+/* <init> <step> <limit> <proc> for - */
+private int
+ for_pos_int_continue(P1(os_ptr)), for_neg_int_continue(P1(os_ptr)),
+ for_real_continue(P1(os_ptr));
+int
+zfor(register os_ptr op)
+{
+ register es_ptr ep;
+
+ check_estack(7);
+ ep = esp + 6;
+ check_proc(*op);
+ /* Push a mark, the control variable, the initial value, */
+ /* the increment, the limit, and the procedure, */
+ /* and invoke the continuation operator. */
+ if (r_has_type(op - 3, t_integer) &&
+ r_has_type(op - 2, t_integer)
+ ) {
+ make_int(ep - 4, op[-3].value.intval);
+ make_int(ep - 3, op[-2].value.intval);
+ switch (r_type(op - 1)) {
+ case t_integer:
+ make_int(ep - 2, op[-1].value.intval);
+ break;
+ case t_real:
+ make_int(ep - 2, (long)op[-1].value.realval);
+ break;
+ default:
+ return_op_typecheck(op - 1);
+ }
+ if (ep[-3].value.intval >= 0)
+ make_op_estack(ep, for_pos_int_continue);
+ else
+ make_op_estack(ep, for_neg_int_continue);
+ } else {
+ float params[3];
+ int code;
+
+ if ((code = float_params(op - 1, 3, params)) < 0)
+ return code;
+ make_real(ep - 4, params[0]);
+ make_real(ep - 3, params[1]);
+ make_real(ep - 2, params[2]);
+ make_op_estack(ep, for_real_continue);
+ }
+ make_mark_estack(ep - 5, es_for, no_cleanup);
+ ref_assign(ep - 1, op);
+ esp = ep;
+ pop(4);
+ return o_push_estack;
+}
+/* Continuation operators for for, separate for positive integer, */
+/* negative integer, and real. */
+/* Execution stack contains mark, control variable, increment, */
+/* limit, and procedure (procedure is topmost.) */
+/* Continuation operator for positive integers. */
+private int
+for_pos_int_continue(register os_ptr op)
+{
+ register es_ptr ep = esp;
+ long var = ep[-3].value.intval;
+
+ if (var > ep[-1].value.intval) {
+ esp -= 5; /* pop everything */
+ return o_pop_estack;
+ }
+ push(1);
+ make_int(op, var);
+ ep[-3].value.intval = var + ep[-2].value.intval;
+ ref_assign_inline(ep + 2, ep); /* saved proc */
+ esp = ep + 2;
+ return o_push_estack;
+}
+/* Continuation operator for negative integers. */
+private int
+for_neg_int_continue(register os_ptr op)
+{
+ register es_ptr ep = esp;
+ long var = ep[-3].value.intval;
+
+ if (var < ep[-1].value.intval) {
+ esp -= 5; /* pop everything */
+ return o_pop_estack;
+ }
+ push(1);
+ make_int(op, var);
+ ep[-3].value.intval = var + ep[-2].value.intval;
+ ref_assign(ep + 2, ep); /* saved proc */
+ esp = ep + 2;
+ return o_push_estack;
+}
+/* Continuation operator for reals. */
+private int
+for_real_continue(register os_ptr op)
+{
+ es_ptr ep = esp;
+ float var = ep[-3].value.realval;
+ float incr = ep[-2].value.realval;
+
+ if (incr >= 0 ? (var > ep[-1].value.realval) :
+ (var < ep[-1].value.realval)
+ ) {
+ esp -= 5; /* pop everything */
+ return o_pop_estack;
+ }
+ push(1);
+ ref_assign(op, ep - 3);
+ ep[-3].value.realval = var + incr;
+ esp = ep + 2;
+ ref_assign(ep + 2, ep); /* saved proc */
+ return o_push_estack;
+}
+
+/* Here we provide an internal variant of 'for' that enumerates the */
+/* values 0, 1/N, 2/N, ..., 1 precisely. The arguments must be */
+/* the integers 0, 1, and N. We need this for */
+/* loading caches such as the transfer function cache. */
+private int for_fraction_continue(P1(os_ptr));
+int
+zfor_fraction(register os_ptr op)
+{
+ int code = zfor(op);
+
+ if (code < 0)
+ return code; /* shouldn't ever happen! */
+ make_op_estack(esp, for_fraction_continue);
+ return code;
+}
+/* Continuation procedure */
+private int
+for_fraction_continue(register os_ptr op)
+{
+ register es_ptr ep = esp;
+ int code = for_pos_int_continue(op);
+
+ if (code != o_push_estack)
+ return code;
+ /* We must use osp instead of op here, because */
+ /* for_pos_int_continue pushes a value on the o-stack. */
+ make_real(osp, (float)osp->value.intval / ep[-1].value.intval);
+ return code;
+}
+
+/* <int> <proc> repeat - */
+private int repeat_continue(P1(os_ptr));
+private int
+zrepeat(register os_ptr op)
+{
+ check_type(op[-1], t_integer);
+ check_proc(*op);
+ if (op[-1].value.intval < 0)
+ return_error(e_rangecheck);
+ check_estack(5);
+ /* Push a mark, the count, and the procedure, and invoke */
+ /* the continuation operator. */
+ push_mark_estack(es_for, no_cleanup);
+ *++esp = op[-1];
+ *++esp = *op;
+ make_op_estack(esp + 1, repeat_continue);
+ pop(2);
+ return repeat_continue(op - 2);
+}
+/* Continuation operator for repeat */
+private int
+repeat_continue(register os_ptr op)
+{
+ es_ptr ep = esp; /* saved proc */
+
+ if (--(ep[-1].value.intval) >= 0) { /* continue */
+ esp += 2;
+ ref_assign(esp, ep);
+ return o_push_estack;
+ } else { /* done */
+ esp -= 3; /* pop mark, count, proc */
+ return o_pop_estack;
+ }
+}
+
+/* <proc> loop */
+private int loop_continue(P1(os_ptr));
+private int
+zloop(register os_ptr op)
+{
+ check_proc(*op);
+ check_estack(4);
+ /* Push a mark and the procedure, and invoke */
+ /* the continuation operator. */
+ push_mark_estack(es_for, no_cleanup);
+ *++esp = *op;
+ make_op_estack(esp + 1, loop_continue);
+ pop(1);
+ return loop_continue(op - 1);
+}
+/* Continuation operator for loop */
+private int
+loop_continue(register os_ptr op)
+{
+ register es_ptr ep = esp; /* saved proc */
+
+ ref_assign(ep + 2, ep);
+ esp = ep + 2;
+ return o_push_estack;
+}
+
+/* - exit - */
+private int
+zexit(register os_ptr op)
+{
+ ref_stack_enum_t rsenum;
+ uint scanned = 0;
+
+ ref_stack_enum_begin(&rsenum, &e_stack);
+ do {
+ uint used = rsenum.size;
+ es_ptr ep = rsenum.ptr + used - 1;
+ uint count = used;
+
+ for (; count; count--, ep--)
+ if (r_is_estack_mark(ep))
+ switch (estack_mark_index(ep)) {
+ case es_for:
+ pop_estack(scanned + (used - count + 1));
+ return o_pop_estack;
+ case es_stopped:
+ return_error(e_invalidexit); /* not a loop */
+ }
+ scanned += used;
+ } while (ref_stack_enum_next(&rsenum));
+ /* No mark, quit. (per Adobe documentation) */
+ push(2);
+ return unmatched_exit(op, zexit);
+}
+
+/*
+ * .stopped pushes the following on the e-stack:
+ * - A mark with type = es_stopped and procedure = no_cleanup.
+ * - The result to be pushed on a normal return.
+ * - The signal mask for .stop.
+ * - The procedure %stopped_push, to handle the normal return case.
+ */
+
+/* In the normal (no-error) case, pop the mask from the e-stack, */
+/* and move the result to the o-stack. */
+private int
+stopped_push(register os_ptr op)
+{
+ push(1);
+ *op = esp[-1];
+ esp -= 3;
+ return o_pop_estack;
+}
+
+/* - stop - */
+/* Equivalent to true 1 .stop. */
+/* This is implemented in C because if were a pseudo-operator, */
+/* the stacks would get restored in case of an error. */
+private int
+zstop(register os_ptr op)
+{
+ uint count = count_to_stopped(1L);
+
+ if (count) {
+ /*
+ * If there are any t_oparrays on the e-stack, they will pop
+ * any new items from the o-stack. Wait to push the 'true'
+ * until we have run all the unwind procedures.
+ */
+ check_ostack(2);
+ pop_estack(count);
+ op = osp;
+ push(1);
+ make_true(op);
+ return o_pop_estack;
+ }
+ /* No mark, quit. (per Adobe documentation) */
+ push(2);
+ return unmatched_exit(op, zstop);
+}
+
+/* <result> <mask> .stop - */
+private int
+zzstop(register os_ptr op)
+{
+ uint count;
+
+ check_type(*op, t_integer);
+ count = count_to_stopped(op->value.intval);
+ if (count) {
+ /*
+ * If there are any t_oparrays on the e-stack, they will pop
+ * any new items from the o-stack. Wait to push the result
+ * until we have run all the unwind procedures.
+ */
+ ref save_result;
+
+ check_op(2);
+ save_result = op[-1];
+ pop(2);
+ pop_estack(count);
+ op = osp;
+ push(1);
+ *op = save_result;
+ return o_pop_estack;
+ }
+ /* No mark, quit. (per Adobe documentation) */
+ return unmatched_exit(op, zzstop);
+}
+
+/* <obj> stopped <stopped> */
+/* Equivalent to false 1 .stopped. */
+/* This is implemented in C because if were a pseudo-operator, */
+/* the stacks would get restored in case of an error. */
+private int
+zstopped(register os_ptr op)
+{
+ check_op(1);
+ /* Mark the execution stack, and push the default result */
+ /* in case control returns normally. */
+ check_estack(5);
+ push_mark_estack(es_stopped, no_cleanup);
+ ++esp;
+ make_false(esp); /* save the result */
+ ++esp;
+ make_int(esp, 1); /* save the signal mask */
+ push_op_estack(stopped_push);
+ *++esp = *op; /* execute the operand */
+ esfile_check_cache();
+ pop(1);
+ return o_push_estack;
+}
+
+/* <obj> <result> <mask> .stopped <result> */
+private int
+zzstopped(register os_ptr op)
+{
+ check_type(*op, t_integer);
+ check_op(3);
+ /* Mark the execution stack, and push the default result */
+ /* in case control returns normally. */
+ check_estack(5);
+ push_mark_estack(es_stopped, no_cleanup);
+ *++esp = op[-1]; /* save the result */
+ *++esp = *op; /* save the signal mask */
+ push_op_estack(stopped_push);
+ *++esp = op[-2]; /* execute the operand */
+ esfile_check_cache();
+ pop(3);
+ return o_push_estack;
+}
+
+/* <mask> .instopped false */
+/* <mask> .instopped <result> true */
+private int
+zinstopped(register os_ptr op)
+{
+ uint count;
+
+ check_type(*op, t_integer);
+ count = count_to_stopped(op->value.intval);
+ if (count) {
+ push(1);
+ op[-1] = *ref_stack_index(&e_stack, count - 2); /* default result */
+ make_true(op);
+ } else
+ make_false(op);
+ return 0;
+}
+
+/* <include_marks> .countexecstack <int> */
+/* - countexecstack <int> */
+/* countexecstack is an operator solely for the sake of the Genoa tests. */
+private int
+zcountexecstack(register os_ptr op)
+{
+ push(1);
+ make_int(op, count_exec_stack(false));
+ return 0;
+}
+private int
+zcountexecstack1(register os_ptr op)
+{
+ check_type(*op, t_boolean);
+ make_int(op, count_exec_stack(op->value.boolval));
+ return 0;
+}
+
+/* <array> <include_marks> .execstack <subarray> */
+/* <array> execstack <subarray> */
+/* execstack is an operator solely for the sake of the Genoa tests. */
+private int execstack_continue(P1(os_ptr));
+private int execstack2_continue(P1(os_ptr));
+private int
+push_execstack(os_ptr op1, bool include_marks, int (*cont)(P1(os_ptr)))
+{
+ uint size;
+ /*
+ * We can't do this directly, because the interpreter
+ * might have cached some state. To force the interpreter
+ * to update the stored state, we push a continuation on
+ * the exec stack; the continuation is executed immediately,
+ * and does the actual transfer.
+ */
+ uint depth;
+
+ check_write_type(*op1, t_array);
+ size = r_size(op1);
+ depth = count_exec_stack(include_marks);
+ if (depth > size)
+ return_error(e_rangecheck);
+ {
+ int code = ref_stack_store_check(&e_stack, op1, size, 0);
+
+ if (code < 0)
+ return code;
+ }
+ check_estack(1);
+ r_set_size(op1, depth);
+ push_op_estack(cont);
+ return o_push_estack;
+}
+private int
+zexecstack(register os_ptr op)
+{
+ return push_execstack(op, false, execstack_continue);
+}
+private int
+zexecstack2(register os_ptr op)
+{
+ check_type(*op, t_boolean);
+ return push_execstack(op - 1, op->value.boolval, execstack2_continue);
+}
+/* Continuation operator to do the actual transfer. */
+/* r_size(op1) was set just above. */
+private int
+do_execstack(os_ptr op, bool include_marks, os_ptr op1)
+{
+ ref *arefs = op1->value.refs;
+ uint asize = r_size(op1);
+ uint i;
+ ref *rq;
+
+ /*
+ * Copy elements from the stack to the array,
+ * optionally skipping executable nulls.
+ * Clear the executable bit in any internal operators, and
+ * convert t_structs and t_astructs (which can only appear
+ * in connection with stack marks, which means that they will
+ * probably be freed when unwinding) to something harmless.
+ */
+ for (i = 0, rq = arefs + asize; rq != arefs; ++i) {
+ const ref *rp = ref_stack_index(&e_stack, (long)i);
+
+ if (r_has_type_attrs(rp, t_null, a_executable) && !include_marks)
+ continue;
+ --rq;
+ ref_assign_old(op1, rq, rp, "execstack");
+ switch (r_type(rq)) {
+ case t_operator: {
+ uint opidx = op_index(rq);
+
+ if (opidx == 0 || op_def_is_internal(op_def_table[opidx]))
+ r_clear_attrs(rq, a_executable);
+ break;
+ }
+ case t_struct:
+ case t_astruct: {
+ const char *tname =
+ gs_struct_type_name_string(
+ gs_object_type(imemory, rq->value.pstruct));
+
+ make_const_string(rq, a_readonly | avm_foreign,
+ strlen(tname), (const byte *)tname);
+ break;
+ }
+ default:
+ ;
+ }
+ }
+ pop(op - op1);
+ return 0;
+}
+private int
+execstack_continue(os_ptr op)
+{
+ return do_execstack(op, false, op);
+}
+private int
+execstack2_continue(os_ptr op)
+{
+ return do_execstack(op, op->value.boolval, op - 1);
+}
+
+/* - .needinput - */
+private int
+zneedinput(register os_ptr op)
+{
+ return e_NeedInput; /* interpreter will exit to caller */
+}
+
+/* <obj> <int> .quit - */
+private int
+zquit(register os_ptr op)
+{
+ check_op(2);
+ check_type(*op, t_integer);
+ return_error(e_Quit); /* Interpreter will do the exit */
+}
+
+/* - currentfile <file> */
+private ref *zget_current_file(P0());
+private int
+zcurrentfile(register os_ptr op)
+{
+ ref *fp;
+
+ push(1);
+ /* Check the cache first */
+ if (esfile != 0) {
+#ifdef DEBUG
+ /* Check that esfile is valid. */
+ ref *efp = zget_current_file();
+
+ if (esfile != efp) {
+ lprintf2("currentfile: esfile=0x%lx, efp=0x%lx\n",
+ (ulong) esfile, (ulong) efp);
+ ref_assign(op, efp);
+ } else
+#endif
+ ref_assign(op, esfile);
+ } else if ((fp = zget_current_file()) == 0) { /* Return an invalid file object. */
+ /* This doesn't make a lot of sense to me, */
+ /* but it's what the PostScript manual specifies. */
+ make_invalid_file(op);
+ } else {
+ ref_assign(op, fp);
+ esfile_set_cache(fp);
+ }
+ /* Make the returned value literal. */
+ r_clear_attrs(op, a_executable);
+ return 0;
+}
+/* Get the current file from which the interpreter is reading. */
+private ref *
+zget_current_file(void)
+{
+ ref_stack_enum_t rsenum;
+
+ ref_stack_enum_begin(&rsenum, &e_stack);
+ do {
+ uint count = rsenum.size;
+ es_ptr ep = rsenum.ptr + count - 1;
+
+ for (; count; count--, ep--)
+ if (r_has_type_attrs(ep, t_file, a_executable))
+ return ep;
+ } while (ref_stack_enum_next(&rsenum));
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zcontrol_op_defs[] =
+{
+ {"1.cond", zcond},
+ {"0countexecstack", zcountexecstack},
+ {"1.countexecstack", zcountexecstack1},
+ {"0currentfile", zcurrentfile},
+ {"1exec", zexec},
+ {"1.execn", zexecn},
+ {"1execstack", zexecstack},
+ {"2.execstack", zexecstack2},
+ {"0exit", zexit},
+ {"2if", zif},
+ {"3ifelse", zifelse},
+ {"0.instopped", zinstopped},
+ {"0.needinput", zneedinput},
+ {"4for", zfor},
+ {"1loop", zloop},
+ {"2.quit", zquit},
+ {"2repeat", zrepeat},
+ {"0stop", zstop},
+ {"1.stop", zzstop},
+ {"1stopped", zstopped},
+ {"2.stopped", zzstopped},
+ /* Internal operators */
+ {"1%cond_continue", cond_continue},
+ {"1%execstack_continue", execstack_continue},
+ {"2%execstack2_continue", execstack2_continue},
+ {"0%for_pos_int_continue", for_pos_int_continue},
+ {"0%for_neg_int_continue", for_neg_int_continue},
+ {"0%for_real_continue", for_real_continue},
+ {"4%for_fraction", zfor_fraction},
+ {"0%for_fraction_continue", for_fraction_continue},
+ {"0%loop_continue", loop_continue},
+ {"0%repeat_continue", repeat_continue},
+ {"0%stopped_push", stopped_push},
+ {"1superexec", zsuperexec},
+ op_def_end(0)
+};
+
+/* ------ Internal routines ------ */
+
+/* Vacuous cleanup routine */
+private int
+no_cleanup(os_ptr op)
+{
+ return 0;
+}
+
+/*
+ * Count the number of elements on the exec stack, with or without
+ * the normally invisible elements (*op is a Boolean that indicates this).
+ */
+private uint
+count_exec_stack(bool include_marks)
+{
+ uint count = ref_stack_count(&e_stack);
+
+ if (!include_marks) {
+ uint i;
+
+ for (i = count; i--;)
+ if (r_has_type_attrs(ref_stack_index(&e_stack, (long)i),
+ t_null, a_executable))
+ --count;
+ }
+ return count;
+}
+
+/*
+ * Count the number of elements down to and including the first 'stopped'
+ * mark on the e-stack with a given mask. Return 0 if there is no 'stopped'
+ * mark.
+ */
+private uint
+count_to_stopped(long mask)
+{
+ ref_stack_enum_t rsenum;
+ uint scanned = 0;
+
+ ref_stack_enum_begin(&rsenum, &e_stack);
+ do {
+ uint used = rsenum.size;
+ es_ptr ep = rsenum.ptr + used - 1;
+ uint count = used;
+
+ for (; count; count--, ep--)
+ if (r_is_estack_mark(ep) &&
+ estack_mark_index(ep) == es_stopped &&
+ (ep[2].value.intval & mask) != 0
+ )
+ return scanned + (used - count + 1);
+ scanned += used;
+ } while (ref_stack_enum_next(&rsenum));
+ return 0;
+}
+
+/*
+ * Pop the e-stack, executing cleanup procedures as needed.
+ * We could make this more efficient using ref_stack_enum_*,
+ * but it isn't used enough to make this worthwhile.
+ */
+void
+pop_estack(uint count)
+{
+ uint idx = 0;
+ uint popped = 0;
+
+ esfile_clear_cache();
+ for (; idx < count; idx++) {
+ ref *ep = ref_stack_index(&e_stack, idx - popped);
+
+ if (r_is_estack_mark(ep)) {
+ ref_stack_pop(&e_stack, idx + 1 - popped);
+ popped = idx + 1;
+ (*real_opproc(ep)) (osp);
+ }
+ }
+ ref_stack_pop(&e_stack, count - popped);
+}
+
+/*
+ * Execute a quit in the case of an exit or stop with no appropriate
+ * enclosing control scope (loop or stopped). The caller has already
+ * ensured two free slots on the top of the o-stack.
+ */
+private int
+unmatched_exit(os_ptr op, op_proc_p opproc)
+{
+ make_oper(op - 1, 0, opproc);
+ make_int(op, e_invalidexit);
+ return_error(e_Quit);
+}
diff --git a/pstoraster/zcrd.c b/pstoraster/zcrd.c
new file mode 100644
index 000000000..aad458be9
--- /dev/null
+++ b/pstoraster/zcrd.c
@@ -0,0 +1,438 @@
+/* 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$ */
+/* CIE color rendering operators */
+#include "math_.h"
+#include "ghost.h"
+#include "oper.h"
+#include "gsstruct.h"
+#include "gscspace.h"
+#include "gscolor2.h"
+#include "gscrd.h"
+#include "estack.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "idparam.h"
+#include "igstate.h"
+#include "icie.h"
+#include "ivmspace.h"
+#include "store.h" /* for make_null */
+
+/*#define TEST*/
+
+/* Forward references */
+private int zcrd1_proc_params(P2(os_ptr op, ref_cie_render_procs * pcprocs));
+private int zcrd1_params(P4(os_ptr op, gs_cie_render * pcrd,
+ ref_cie_render_procs * pcprocs, gs_memory_t * mem));
+private int cache_colorrendering1(P3(gs_cie_render * pcrd,
+ const ref_cie_render_procs * pcprocs,
+ gs_ref_memory_t * imem));
+
+/* - currentcolorrendering <dict> */
+private int
+zcurrentcolorrendering(os_ptr op)
+{
+ push(1);
+ *op = istate->colorrendering.dict;
+ return 0;
+}
+
+/* <dict> <crd> .setcolorrendering1 - */
+private int
+zsetcolorrendering1(os_ptr op)
+{
+ es_ptr ep = esp;
+ ref_cie_render_procs procs;
+ int code;
+
+ check_type(op[-1], t_dictionary);
+ check_stype(*op, st_cie_render1);
+ code = zcrd1_proc_params(op - 1, &procs);
+ if (code < 0)
+ return code;
+ code = gs_setcolorrendering(igs, r_ptr(op, gs_cie_render));
+ if (code < 0)
+ return code;
+ if (gs_cie_cs_common(igs) != 0 &&
+ (code = cie_cache_joint(&procs, igs)) < 0
+ )
+ return code;
+ istate->colorrendering.dict = op[-1];
+ istate->colorrendering.procs = procs;
+ pop(2);
+ return (esp == ep ? 0 : o_push_estack);
+}
+
+/* <dict> .buildcolorrendering1 <crd> */
+private int
+zbuildcolorrendering1(os_ptr op)
+{
+ gs_memory_t *mem = gs_state_memory(igs);
+ int code;
+ es_ptr ep = esp;
+ gs_cie_render *pcrd;
+ ref_cie_render_procs procs;
+
+ check_read_type(*op, t_dictionary);
+ check_dict_read(*op);
+ code = gs_cie_render1_build(&pcrd, mem, ".setcolorrendering1");
+ if (code < 0)
+ return code;
+ code = zcrd1_params(op, pcrd, &procs, mem);
+ if (code < 0 ||
+ (code = cache_colorrendering1(pcrd, &procs, (gs_ref_memory_t *) mem)) < 0
+ ) {
+ rc_free_struct(pcrd, ".setcolorrendering1");
+ esp = ep;
+ return code;
+ }
+ /****** FIX refct ******/
+ /*rc_decrement(pcrd, ".setcolorrendering1"); *//* build sets rc = 1 */
+ istate->colorrendering.dict = *op;
+ make_istruct_new(op, a_readonly, pcrd);
+ return (esp == ep ? 0 : o_push_estack);
+}
+/* Get ColorRenderingType 1 procedures from the PostScript dictionary. */
+private int
+zcrd1_proc_params(os_ptr op, ref_cie_render_procs * pcprocs)
+{
+ int code;
+ ref *pRT;
+
+ if ((code = dict_proc3_param(op, "EncodeLMN", &pcprocs->EncodeLMN)) < 0 ||
+ (code = dict_proc3_param(op, "EncodeABC", &pcprocs->EncodeABC)) < 0 ||
+ (code = dict_proc3_param(op, "TransformPQR", &pcprocs->TransformPQR)) < 0
+ )
+ return (code < 0 ? code : gs_note_error(e_rangecheck));
+ if (dict_find_string(op, "RenderTable", &pRT) > 0) {
+ const ref *prte;
+ int size;
+ int i;
+
+ check_read_type(*pRT, t_array);
+ size = r_size(pRT);
+ if (size < 5)
+ return_error(e_rangecheck);
+ prte = pRT->value.const_refs;
+ for (i = 5; i < size; i++)
+ check_proc_only(prte[i]);
+ make_const_array(&pcprocs->RenderTableT, a_readonly | r_space(pRT),
+ size - 5, prte + 5);
+ } else
+ make_null(&pcprocs->RenderTableT);
+ return 0;
+}
+/* Get ColorRenderingType 1 parameters from the PostScript dictionary. */
+private int
+zcrd1_params(os_ptr op, gs_cie_render * pcrd,
+ ref_cie_render_procs * pcprocs, gs_memory_t * mem)
+{
+ int code;
+ int ignore;
+ gx_color_lookup_table *const prtl = &pcrd->RenderTable.lookup;
+ ref *pRT;
+
+ if ((code = dict_int_param(op, "ColorRenderingType", 1, 1, 0, &ignore)) < 0 ||
+ (code = zcrd1_proc_params(op, pcprocs)) < 0 ||
+ (code = dict_matrix3_param(op, "MatrixLMN", &pcrd->MatrixLMN)) != matrix3_ok ||
+ (code = dict_range3_param(op, "RangeLMN", &pcrd->RangeLMN)) < 0 ||
+ (code = dict_matrix3_param(op, "MatrixABC", &pcrd->MatrixABC)) != matrix3_ok ||
+ (code = dict_range3_param(op, "RangeABC", &pcrd->RangeABC)) < 0 ||
+ (code = cie_points_param(op, &pcrd->points)) < 0 ||
+ (code = dict_matrix3_param(op, "MatrixPQR", &pcrd->MatrixPQR)) != matrix3_ok ||
+ (code = dict_range3_param(op, "RangePQR", &pcrd->RangePQR)) < 0
+ )
+ return (code < 0 ? code : gs_note_error(e_rangecheck));
+ if (dict_find_string(op, "RenderTable", &pRT) > 0) {
+ const ref *prte = pRT->value.const_refs;
+
+ /* Finish unpacking and checking the RenderTable parameter. */
+ check_type_only(prte[4], t_integer);
+ if (!(prte[4].value.intval == 3 || prte[4].value.intval == 4))
+ return_error(e_rangecheck);
+ prtl->n = 3;
+ prtl->m = prte[4].value.intval;
+ if (r_size(pRT) != prtl->m + 5)
+ return_error(e_rangecheck);
+ code = cie_table_param(pRT, prtl, mem);
+ if (code < 0)
+ return code;
+ } else {
+ prtl->table = 0;
+ }
+ pcrd->EncodeLMN = Encode_default;
+ pcrd->EncodeABC = Encode_default;
+ pcrd->TransformPQR = TransformPQR_default;
+ pcrd->RenderTable.T = RenderTableT_default;
+ return 0;
+}
+
+/* Cache the results of the color rendering procedures. */
+private int cie_cache_render_finish(P1(os_ptr));
+private int
+cache_colorrendering1(gs_cie_render * pcrd,
+ const ref_cie_render_procs * pcrprocs,
+ gs_ref_memory_t * imem)
+{
+ es_ptr ep = esp;
+ int code = gs_cie_render_init(pcrd); /* sets Domain values */
+ int i;
+
+ if (code < 0 ||
+ (code = cie_cache_push_finish(cie_cache_render_finish, imem, pcrd)) < 0 ||
+ (code = cie_prepare_cache3(&pcrd->DomainLMN, pcrprocs->EncodeLMN.value.const_refs, &pcrd->caches.EncodeLMN[0], pcrd, imem, "Encode.LMN")) < 0 ||
+ (code = cie_prepare_cache3(&pcrd->DomainABC, pcrprocs->EncodeABC.value.const_refs, &pcrd->caches.EncodeABC[0], pcrd, imem, "Encode.ABC")) < 0
+ ) {
+ esp = ep;
+ return code;
+ }
+ if (pcrd->RenderTable.lookup.table != 0) {
+ bool is_identity = true;
+
+ for (i = 0; i < pcrd->RenderTable.lookup.m; i++)
+ if (r_size(pcrprocs->RenderTableT.value.const_refs + i) != 0) {
+ is_identity = false;
+ break;
+ }
+ pcrd->caches.RenderTableT_is_identity = is_identity;
+ if (!is_identity)
+ for (i = 0; i < pcrd->RenderTable.lookup.m; i++)
+ if ((code =
+ cie_prepare_cache(Range4_default.ranges,
+ pcrprocs->RenderTableT.value.const_refs + i,
+ &pcrd->caches.RenderTableT[i].floats,
+ pcrd, imem, "RenderTable.T")) < 0
+ ) {
+ esp = ep;
+ return code;
+ }
+ }
+ return o_push_estack;
+}
+
+/* Finish up after loading the rendering caches. */
+private int
+cie_cache_render_finish(os_ptr op)
+{
+ gs_cie_render *pcrd = r_ptr(op, gs_cie_render);
+ int code;
+
+ if (pcrd->RenderTable.lookup.table != 0 &&
+ !pcrd->caches.RenderTableT_is_identity
+ ) {
+ /* Convert the RenderTableT cache from floats to fracs. */
+ int j;
+
+ for (j = 0; j < pcrd->RenderTable.lookup.m; j++)
+ gs_cie_cache_to_fracs(&pcrd->caches.RenderTableT[j]);
+ }
+ pcrd->status = CIE_RENDER_STATUS_SAMPLED;
+ code = gs_cie_render_complete(pcrd);
+ if (code < 0)
+ return code;
+ /* Note that the cache holds the only record of the values. */
+ pcrd->EncodeLMN = EncodeLMN_from_cache;
+ pcrd->EncodeABC = EncodeABC_from_cache;
+ pop(1);
+ return 0;
+}
+
+/* ------ Internal procedures ------ */
+
+/* Load the joint caches. */
+private int
+ cie_exec_tpqr(P1(os_ptr)), cie_post_exec_tpqr(P1(os_ptr)), cie_tpqr_finish(P1(os_ptr));
+int
+cie_cache_joint(const ref_cie_render_procs * pcrprocs, gs_state * pgs)
+{
+ const gs_cie_render *pcrd = gs_currentcolorrendering(pgs);
+ /*
+ * The former installation procedures have allocated
+ * the joint caches and filled in points_sd.
+ */
+ gx_cie_joint_caches *pjc = gx_currentciecaches(pgs);
+ gs_ref_memory_t *imem = (gs_ref_memory_t *) gs_state_memory(pgs);
+ ref pqr_procs;
+ uint space;
+ int code;
+ int i;
+
+ if (pcrd == 0) /* cache is not set up yet */
+ return 0;
+ if (pjc == 0)
+ return_error(e_VMerror);
+ code = ialloc_ref_array(&pqr_procs, a_readonly, 3 * (1 + 4 + 4 * 6),
+ "cie_cache_common");
+ if (code < 0)
+ return code;
+ /* When we're done, deallocate the procs and complete the caches. */
+ check_estack(3);
+ cie_cache_push_finish(cie_tpqr_finish, imem, pgs);
+ *++esp = pqr_procs;
+ space = r_space(&pqr_procs);
+ for (i = 0; i < 3; i++) {
+ ref *p = pqr_procs.value.refs + 3 + (4 + 4 * 6) * i;
+ const float *ppt = (float *)&pjc->points_sd;
+ int j;
+
+ make_array(pqr_procs.value.refs + i, a_readonly | a_executable | space,
+ 4, p);
+ make_array(p, a_readonly | space, 4 * 6, p + 4);
+ p[1] = pcrprocs->TransformPQR.value.refs[i];
+ make_oper(p + 2, 0, cie_exec_tpqr);
+ make_oper(p + 3, 0, cie_post_exec_tpqr);
+ for (j = 0, p += 4; j < 4 * 6; j++, p++, ppt++)
+ make_real(p, *ppt);
+ }
+ return cie_prepare_cache3(&pcrd->RangePQR,
+ pqr_procs.value.const_refs,
+ &pjc->TransformPQR[0],
+ pjc, imem, "Transform.PQR");
+}
+
+/* Private operator to shuffle arguments for the TransformPQR procedure: */
+/* v [ws wd bs bd] proc -> -mark- ws wd bs bd v proc + exec */
+private int
+cie_exec_tpqr(os_ptr op)
+{
+ const ref *ppt = op[-1].value.const_refs;
+ uint space = r_space(op - 1);
+ int i;
+
+ check_op(3);
+ push(4);
+ *op = op[-4]; /* proc */
+ op[-1] = op[-6]; /* v */
+ for (i = 0; i < 4; i++)
+ make_const_array(op - 5 + i, a_readonly | space,
+ 6, ppt + i * 6);
+ make_mark(op - 6);
+ return zexec(op);
+}
+
+/* Remove extraneous values from the stack after executing */
+/* the TransformPQR procedure. -mark- ... v -> v */
+private int
+cie_post_exec_tpqr(os_ptr op)
+{
+ uint count = ref_stack_counttomark(&o_stack);
+ ref vref;
+
+ if (count < 2)
+ return_error(e_unmatchedmark);
+ vref = *op;
+ ref_stack_pop(&o_stack, count - 1);
+ *osp = vref;
+ return 0;
+}
+
+/* Free the procs array and complete the joint caches. */
+private int
+cie_tpqr_finish(os_ptr op)
+{
+ gs_state *pgs = r_ptr(op, gs_state);
+ int code;
+
+ ifree_ref_array(op - 1, "cie_tpqr_finish");
+ code = gs_cie_cs_complete(pgs, false);
+ pop(2);
+ return code;
+}
+
+/* ------ Operators for testing ------ */
+
+#ifdef TEST
+
+#include "gscrdp.h"
+#include "iparam.h"
+
+/* - .currentcrd <dict> */
+private int
+zcurrentcrd(os_ptr op)
+{
+ stack_param_list list;
+ int code;
+
+ stack_param_list_write(&list, &o_stack, NULL);
+ code = param_write_cie_render1((gs_param_list *) & list, "CRD",
+ gs_currentcolorrendering(igs), imemory);
+ if (code < 0)
+ return code;
+ ref_assign(osp - 1, osp);
+ pop(1);
+ return 0;
+}
+
+/* <dict> .setcrd - */
+private int
+zsetcrd(os_ptr op)
+{
+ gs_memory_t *mem = gs_state_memory(igs);
+ dict_param_list list;
+ gs_cie_render *pcrd = 0;
+ int code;
+
+ check_type(*op, t_dictionary);
+ code = dict_param_list_read(&list, op, NULL, false);
+ if (code < 0)
+ return code;
+ code = gs_cie_render1_build(&pcrd, mem, ".setcrd");
+ if (code >= 0 &&
+ (code = param_get_cie_render1(pcrd, (gs_param_list *) & list,
+ gs_currentdevice(igs))) >= 0
+ ) {
+ code = gs_setcolorrendering(igs, pcrd);
+ }
+ if (pcrd)
+ rc_decrement(pcrd, ".setcrd"); /* build sets rc = 1 */
+ iparam_list_release(&list);
+ if (code < 0)
+ return code;
+ pop(1);
+ return 0;
+}
+
+#endif
+
+/* ------ Initialization procedure ------ */
+
+const op_def zcrd_l2_op_defs[] =
+{
+ op_def_begin_level2(),
+ {"0currentcolorrendering", zcurrentcolorrendering},
+ {"2.setcolorrendering1", zsetcolorrendering1},
+ {"1.buildcolorrendering1", zbuildcolorrendering1},
+ /* Internal "operators" */
+ {"1%cie_render_finish", cie_cache_render_finish},
+ {"3%cie_exec_tpqr", cie_exec_tpqr},
+ {"2%cie_post_exec_tpqr", cie_post_exec_tpqr},
+ {"1%cie_tpqr_finish", cie_tpqr_finish},
+ /* Testing */
+#ifdef TEST
+ {"0.currentcrd", zcurrentcrd},
+ {"1.setcrd", zsetcrd},
+#endif
+ op_def_end(0)
+};
diff --git a/pstoraster/zcsdevn.c b/pstoraster/zcsdevn.c
new file mode 100644
index 000000000..4a4ffad3d
--- /dev/null
+++ b/pstoraster/zcsdevn.c
@@ -0,0 +1,119 @@
+/* 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$ */
+/* DeviceN color space support */
+#include "ghost.h"
+#include "oper.h"
+#include "gxcspace.h" /* must precede gscolor2.h */
+#include "gscolor2.h"
+#include "igstate.h"
+#include "ialloc.h"
+#include "iname.h"
+
+/* Imported from gscdevn.c */
+extern const gs_color_space_type gs_color_space_type_DeviceN;
+
+/* <array> .setdevicepixelspace - */
+/* The current color space is the alternate space for the DeviceN space. */
+private int
+zsetdevicenspace(register os_ptr op)
+{
+ const ref *pcsa;
+ gs_separation_name *names;
+ uint num_components;
+ gs_color_space cs;
+ ref_colorspace cspace_old;
+ int code;
+
+ check_read_type(*op, t_array);
+ if (r_size(op) != 4)
+ return_error(e_rangecheck);
+ pcsa = op->value.const_refs + 1;
+ if (!r_is_array(pcsa))
+ return_error(e_typecheck);
+ num_components = r_size(pcsa);
+ if (num_components == 0)
+ return_error(e_rangecheck);
+ check_proc(pcsa[2]);
+ cs = *gs_currentcolorspace(igs);
+ if (!cs.type->can_be_alt_space)
+ return_error(e_rangecheck);
+ names = (gs_separation_name *)
+ ialloc_byte_array(num_components, sizeof(gs_separation_name),
+ ".setdevicenspace");
+ if (names == 0)
+ return_error(e_VMerror);
+ {
+ uint i;
+ ref sname;
+
+ for (i = 0; i < num_components; ++i) {
+ array_get(pcsa, (long)i, &sname);
+ switch (r_type(&sname)) {
+ case t_string:
+ code = name_from_string(&sname, &sname);
+ if (code < 0) {
+ ifree_object(names, ".setdevicenspace");
+ return code;
+ }
+ /* falls through */
+ case t_name:
+ names[i] = name_index(&sname);
+ break;
+ default:
+ ifree_object(names, ".setdevicenspace");
+ return_error(e_typecheck);
+ }
+ }
+ }
+ cs.params.device_n.alt_space = *(gs_base_color_space *) & cs;
+ cspace_old = istate->colorspace;
+ istate->colorspace.procs.special.device_n.layer_names = pcsa[0];
+ istate->colorspace.procs.special.device_n.tint_transform = pcsa[2];
+ cs.type = &gs_color_space_type_DeviceN;
+ cs.params.device_n.names = names;
+ cs.params.device_n.num_components = num_components;
+ cs.params.device_n.tint_transform = 0;
+/****** ? ******/
+ cs.params.device_n.tint_transform_data = 0;
+/****** ? ******/
+ code = gs_setcolorspace(igs, &cs);
+ if (code < 0) {
+ istate->colorspace = cspace_old;
+ ifree_object(names, ".setdevicenspace");
+ return code;
+ }
+ pop(1);
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zcsdevn_op_defs[] =
+{
+ op_def_begin_ll3(),
+ {"1.setdevicenspace", zsetdevicenspace},
+ op_def_end(0)
+};
diff --git a/pstoraster/zcsindex.c b/pstoraster/zcsindex.c
new file mode 100644
index 000000000..afaa03cd0
--- /dev/null
+++ b/pstoraster/zcsindex.c
@@ -0,0 +1,239 @@
+/* Copyright (C) 1993, 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$ */
+/* Indexed color space support */
+#include "memory_.h"
+#include "ghost.h"
+#include "oper.h"
+#include "gsstruct.h"
+#include "gscolor.h"
+#include "gsmatrix.h" /* for gxcolor2.h */
+#include "gxcspace.h"
+#include "gxfixed.h" /* ditto */
+#include "gxcolor2.h"
+#include "estack.h"
+#include "ialloc.h"
+#include "icsmap.h"
+#include "igstate.h"
+#include "ivmspace.h"
+#include "store.h"
+
+/* Imported from gscolor2.c */
+extern const gs_color_space_type gs_color_space_type_Indexed;
+
+/* Forward references. */
+private int indexed_map1(P1(os_ptr));
+
+/* Free the map when freeing the gs_indexed_map structure. */
+private void
+rc_free_indexed_map(gs_memory_t * mem, void *data, client_name_t cname)
+{ /*
+ * A bug in the SGI Irix 4.05 compiler requires the following:
+ */
+ char *cdata = (char *)data;
+
+ gs_free_object(mem, ((gs_indexed_map *)cdata)->values, cname);
+ gs_free_object(mem, cdata, cname);
+}
+
+/* Indexed lookup procedure that just consults the cache. */
+private int
+lookup_indexed(const gs_indexed_params * params, int index, float *values)
+{
+ int m = cs_num_components((const gs_color_space *)&params->base_space);
+ const float *pv = &params->lookup.map->values[index * m];
+
+ switch (m) {
+ default:
+ return_error(e_rangecheck);
+ case 4:
+ values[3] = pv[3];
+ case 3:
+ values[2] = pv[2];
+ values[1] = pv[1];
+ case 1:
+ values[0] = pv[0];
+ }
+ return 0;
+}
+
+/* <array> .setindexedspace - */
+/* The current color space is the base space for the indexed space. */
+private int
+zsetindexedspace(register os_ptr op)
+{
+ ref *pproc = &istate->colorspace.procs.special.index_proc;
+ const ref *pcsa;
+ gs_color_space cs;
+ gs_direct_color_space cs_base;
+ ref_colorspace cspace_old;
+ uint edepth = ref_stack_count(&e_stack);
+ int num_entries;
+ int code;
+
+ check_read_type(*op, t_array);
+ if (r_size(op) != 4)
+ return_error(e_rangecheck);
+ pcsa = op->value.const_refs + 1;
+ check_type_only(pcsa[1], t_integer);
+ if (pcsa[1].value.intval < 0 || pcsa[1].value.intval > 4095)
+ return_error(e_rangecheck);
+ num_entries = (int)pcsa[1].value.intval + 1;
+ cs = *gs_currentcolorspace(igs);
+ if (!cs.type->can_be_base_space)
+ return_error(e_rangecheck);
+ cspace_old = istate->colorspace;
+ /*
+ * We can't count on C compilers to recognize the aliasing
+ * that would be involved in a direct assignment.
+ * Formerly, we used the following code:
+ cs_base = *(gs_direct_color_space *)&cs;
+ cs.params.indexed.base_space = cs_base;
+ * But the Watcom C 10.0 compiler is too smart: it turns this into
+ * a direct assignment (and compiles incorrect code for it),
+ * defeating our purpose. Instead, we have to do it by brute force:
+ */
+ memcpy(&cs_base, &cs, sizeof(cs_base));
+ cs.params.indexed.base_space = cs_base;
+ if (r_has_type(&pcsa[2], t_string)) {
+ int num_values = num_entries * cs_num_components(&cs);
+
+ check_read(pcsa[2]);
+ if (r_size(&pcsa[2]) != num_values)
+ return_error(e_rangecheck);
+ cs.params.indexed.lookup.table.data =
+ pcsa[2].value.const_bytes;
+ cs.params.indexed.use_proc = 0;
+ make_null(pproc);
+ code = 0;
+ } else {
+ gs_indexed_map *map;
+
+ check_proc(pcsa[2]);
+ code = zcs_begin_map(&map, &pcsa[2], num_entries,
+ (const gs_base_color_space *)&cs,
+ indexed_map1);
+ if (code < 0)
+ return code;
+ cs.params.indexed.use_proc = 1;
+ *pproc = pcsa[2];
+ map->proc.lookup_index = lookup_indexed;
+ cs.params.indexed.lookup.map = map;
+ }
+ cs.params.indexed.hival = num_entries - 1;
+ cs.type = &gs_color_space_type_Indexed;
+ code = gs_setcolorspace(igs, &cs);
+ if (code < 0) {
+ istate->colorspace = cspace_old;
+ ref_stack_pop_to(&e_stack, edepth);
+ return code;
+ }
+ pop(1);
+ return (ref_stack_count(&e_stack) == edepth ? 0 : o_push_estack); /* installation will load the caches */
+}
+
+/* Continuation procedure for saving mapped Indexed color values. */
+private int
+indexed_map1(os_ptr op)
+{
+ es_ptr ep = esp;
+ int i = (int)ep[csme_index].value.intval;
+
+ if (i >= 0) { /* i.e., not first time */
+ int m = (int)ep[csme_num_components].value.intval;
+ int code = float_params(op, m, &r_ptr(&ep[csme_map], gs_indexed_map)->values[i * m]);
+
+ if (code < 0)
+ return code;
+ pop(m);
+ op -= m;
+ if (i == (int)ep[csme_hival].value.intval) { /* All done. */
+ esp -= num_csme;
+ return o_pop_estack;
+ }
+ }
+ push(1);
+ ep[csme_index].value.intval = ++i;
+ make_int(op, i);
+ make_op_estack(ep + 1, indexed_map1);
+ ep[2] = ep[csme_proc]; /* lookup proc */
+ esp = ep + 2;
+ return o_push_estack;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zcsindex_l2_op_defs[] =
+{
+ op_def_begin_level2(),
+ {"1.setindexedspace", zsetindexedspace},
+ /* Internal operators */
+ {"1%indexed_map1", indexed_map1},
+ op_def_end(0)
+};
+
+/* ------ Internal routines ------ */
+
+/* Allocate, and prepare to load, the index or tint map. */
+int
+zcs_begin_map(gs_indexed_map ** pmap, const ref * pproc, int num_entries,
+ const gs_base_color_space * base_space, int (*map1) (P1(os_ptr)))
+{
+ gs_memory_t *mem = gs_state_memory(igs);
+ int num_components =
+ cs_num_components((const gs_color_space *)base_space);
+ int num_values = num_entries * num_components;
+ gs_indexed_map *map;
+ es_ptr ep;
+ float *values;
+
+ rc_alloc_struct_0(map, gs_indexed_map, &st_indexed_map,
+ mem, return_error(e_VMerror),
+ "setcolorspace(mapped)");
+ values =
+ (float *)gs_alloc_byte_array(mem, num_values, sizeof(float),
+ "setcolorspace(mapped)");
+
+ if (values == 0) {
+ gs_free_object(mem, map, "setcolorspace(mapped)");
+ return_error(e_VMerror);
+ }
+ map->rc.free = rc_free_indexed_map;
+ map->num_values = num_values;
+ map->values = values;
+ *pmap = map;
+ /* Map the entire set of color indices. Since the */
+ /* o-stack may not be able to hold 4*4096 values, we have */
+ /* to load them into the cache as they are generated. */
+ check_estack(num_csme + 1); /* 1 extra for map1 proc */
+ ep = esp += num_csme;
+ make_int(ep + csme_num_components, num_components);
+ make_struct(ep + csme_map, imemory_space((gs_ref_memory_t *) mem), map);
+ ep[csme_proc] = *pproc;
+ make_int(ep + csme_hival, num_entries - 1);
+ make_int(ep + csme_index, -1);
+ push_op_estack(map1);
+ return o_push_estack;
+}
diff --git a/pstoraster/zcspixel.c b/pstoraster/zcspixel.c
new file mode 100644
index 000000000..7b427bb6e
--- /dev/null
+++ b/pstoraster/zcspixel.c
@@ -0,0 +1,73 @@
+/* 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$ */
+/* DevicePixel color space support */
+#include "ghost.h"
+#include "oper.h"
+#include "igstate.h"
+#include "gscspace.h"
+#include "gsmatrix.h" /* for gscolor2.h */
+#include "gscolor2.h"
+#include "gscpixel.h"
+
+/* <array> .setdevicepixelspace - */
+private int
+zsetdevicepixelspace(register os_ptr op)
+{
+ ref depth;
+ gs_color_space cs;
+ int code;
+
+ check_read_type(*op, t_array);
+ if (r_size(op) != 2)
+ return_error(e_rangecheck);
+ array_get(op, 1L, &depth);
+ check_type_only(depth, t_integer);
+ switch (depth.value.intval) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ case 16:
+ case 24:
+ case 32:
+ break;
+ default:
+ return_error(e_rangecheck);
+ }
+ gs_cs_init_DevicePixel(&cs, (int)depth.value.intval);
+ code = gs_setcolorspace(igs, &cs);
+ if (code >= 0)
+ pop(1);
+ return code;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zcspixel_op_defs[] =
+{
+ {"1.setdevicepixelspace", zsetdevicepixelspace},
+ op_def_end(0)
+};
diff --git a/pstoraster/zcssepr.c b/pstoraster/zcssepr.c
new file mode 100644
index 000000000..87f6e349b
--- /dev/null
+++ b/pstoraster/zcssepr.c
@@ -0,0 +1,186 @@
+/* Copyright (C) 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$ */
+/* Separation color space support */
+#include "ghost.h"
+#include "oper.h"
+#include "gsstruct.h"
+#include "gscolor.h"
+#include "gsmatrix.h" /* for gxcolor2.h */
+#include "gscsepr.h"
+#include "gxcspace.h"
+#include "gxfixed.h" /* ditto */
+#include "gxcolor2.h"
+#include "estack.h"
+#include "ialloc.h"
+#include "icsmap.h"
+#include "igstate.h"
+#include "ivmspace.h"
+#include "store.h"
+
+/* Imported from gscsepr.c */
+extern const gs_color_space_type gs_color_space_type_Separation;
+
+/* Forward references */
+private int separation_map1(P1(os_ptr));
+
+/* Define the separation cache size. This makes many useful tint values */
+/* map to integer cache indices. */
+#define SEPARATION_CACHE_SIZE 360
+
+/* Tint transform procedure that just consults the cache. */
+private int
+lookup_tint(const gs_separation_params * params, floatp tint, float *values)
+{
+ int m = cs_num_components((const gs_color_space *)&params->alt_space);
+ const gs_indexed_map *map = params->map;
+ int value_index =
+ (tint < 0 ? 0 : tint > 1 ? map->num_values - m :
+ (int)(tint * SEPARATION_CACHE_SIZE + 0.5) * m);
+ const float *pv = &map->values[value_index];
+
+ switch (m) {
+ default:
+ return_error(e_rangecheck);
+ case 4:
+ values[3] = pv[3];
+ case 3:
+ values[2] = pv[2];
+ values[1] = pv[1];
+ case 1:
+ values[0] = pv[0];
+ }
+ return 0;
+}
+
+/* <array> .setseparationspace - */
+/* The current color space is the alternate space for the separation space. */
+private int
+zsetseparationspace(register os_ptr op)
+{
+ const ref *pcsa;
+ gs_color_space cs;
+ ref_colorspace cspace_old;
+ uint edepth = ref_stack_count(&e_stack);
+ gs_indexed_map *map;
+ int code;
+
+ check_read_type(*op, t_array);
+ if (r_size(op) != 4)
+ return_error(e_rangecheck);
+ pcsa = op->value.const_refs + 1;
+ switch (r_type(pcsa)) {
+ default:
+ return_error(e_typecheck);
+ case t_string:
+ case t_name:
+ ;
+ }
+ check_proc(pcsa[2]);
+ cs = *gs_currentcolorspace(igs);
+ if (!cs.type->can_be_alt_space)
+ return_error(e_rangecheck);
+ code = zcs_begin_map(&map, &pcsa[2], SEPARATION_CACHE_SIZE + 1,
+ (const gs_base_color_space *)&cs,
+ separation_map1);
+ if (code < 0)
+ return code;
+ map->proc.tint_transform = lookup_tint;
+ cs.params.separation.alt_space = *(gs_base_color_space *) & cs;
+ cs.params.separation.map = map;
+ cspace_old = istate->colorspace;
+ istate->colorspace.procs.special.separation.layer_name = pcsa[0];
+ istate->colorspace.procs.special.separation.tint_transform = pcsa[2];
+ cs.type = &gs_color_space_type_Separation;
+ code = gs_setcolorspace(igs, &cs);
+ if (code < 0) {
+ istate->colorspace = cspace_old;
+ ref_stack_pop_to(&e_stack, edepth);
+ return code;
+ }
+ pop(1);
+ return (ref_stack_count(&e_stack) == edepth ? 0 : o_push_estack); /* installation will load the caches */
+}
+
+/* Continuation procedure for saving transformed tint values. */
+private int
+separation_map1(os_ptr op)
+{
+ es_ptr ep = esp;
+ int i = (int)ep[csme_index].value.intval;
+
+ if (i >= 0) { /* i.e., not first time */
+ int m = (int)ep[csme_num_components].value.intval;
+ int code = float_params(op, m, &r_ptr(&ep[csme_map], gs_indexed_map)->values[i * m]);
+
+ if (code < 0)
+ return code;
+ pop(m);
+ op -= m;
+ if (i == (int)ep[csme_hival].value.intval) { /* All done. */
+ esp -= num_csme;
+ return o_pop_estack;
+ }
+ }
+ push(1);
+ ep[csme_index].value.intval = ++i;
+ make_real(op, i / (float)SEPARATION_CACHE_SIZE);
+ make_op_estack(ep + 1, separation_map1);
+ ep[2] = ep[csme_proc]; /* tint_transform */
+ esp = ep + 2;
+ return o_push_estack;
+}
+
+/* - currentoverprint <bool> */
+private int
+zcurrentoverprint(register os_ptr op)
+{
+ push(1);
+ make_bool(op, gs_currentoverprint(igs));
+ return 0;
+}
+
+/* <bool> setoverprint - */
+private int
+zsetoverprint(register os_ptr op)
+{
+ check_type(*op, t_boolean);
+ gs_setoverprint(igs, op->value.boolval);
+ pop(1);
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zcssepr_l2_op_defs[] =
+{
+ op_def_begin_level2(),
+ {"0currentoverprint", zcurrentoverprint},
+ {"1setoverprint", zsetoverprint},
+ {"1.setseparationspace", zsetseparationspace},
+ /* Internal operators */
+ {"1%separation_map1", separation_map1},
+ op_def_end(0)
+};
diff --git a/pstoraster/zdevcal.c b/pstoraster/zdevcal.c
new file mode 100644
index 000000000..7b96e1fc9
--- /dev/null
+++ b/pstoraster/zdevcal.c
@@ -0,0 +1,79 @@
+/* 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$ */
+/* %Calendar% IODevice */
+#include "time_.h"
+#include "ghost.h"
+#include "gxiodev.h"
+#include "istack.h"
+#include "iparam.h"
+
+/* ------ %Calendar% ------ */
+
+private iodev_proc_get_params(calendar_get_params);
+const gx_io_device gs_iodev_calendar = {
+ "%Calendar%", "Special",
+ { iodev_no_init, iodev_no_open_device, iodev_no_open_file,
+ iodev_no_fopen, iodev_no_fclose,
+ iodev_no_delete_file, iodev_no_rename_file, iodev_no_file_status,
+ iodev_no_enumerate_files, NULL, NULL,
+ calendar_get_params, iodev_no_put_params
+ }
+};
+
+/* Get the date and time. */
+private int
+calendar_get_params(gx_io_device * iodev, gs_param_list * plist)
+{
+ int code;
+ time_t t;
+ struct tm *pltime;
+ struct tm ltime;
+ static const gs_param_item_t items[] = {
+ {"Year", gs_param_type_int, offset_of(struct tm, tm_year)},
+ {"Month", gs_param_type_int, offset_of(struct tm, tm_mon)},
+ {"Day", gs_param_type_int, offset_of(struct tm, tm_mday)},
+ {"Weekday", gs_param_type_int, offset_of(struct tm, tm_wday)},
+ {"Hour", gs_param_type_int, offset_of(struct tm, tm_hour)},
+ {"Minute", gs_param_type_int, offset_of(struct tm, tm_min)},
+ {"Second", gs_param_type_int, offset_of(struct tm, tm_sec)},
+ gs_param_item_end
+ };
+ bool running;
+
+ if (time(&t) == -1 || (pltime = localtime(&t)) == 0) {
+ ltime.tm_sec = ltime.tm_min = ltime.tm_hour =
+ ltime.tm_mday = ltime.tm_mon = ltime.tm_year = 0;
+ running = false;
+ } else {
+ ltime = *pltime;
+ ltime.tm_year += 1900;
+ ltime.tm_mon++; /* 1-origin */
+ running = true;
+ }
+ if ((code = gs_param_write_items(plist, &ltime, NULL, items)) < 0)
+ return code;
+ return param_write_bool(plist, "Running", &running);
+}
diff --git a/pstoraster/zdevice.c b/pstoraster/zdevice.c
new file mode 100644
index 000000000..1ec580f7d
--- /dev/null
+++ b/pstoraster/zdevice.c
@@ -0,0 +1,445 @@
+/* Copyright (C) 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$ */
+/* Device-related operators */
+#include "string_.h"
+#include "ghost.h"
+#include "oper.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "igstate.h"
+#include "iname.h"
+#include "interp.h"
+#include "iparam.h"
+#include "ivmspace.h"
+#include "gsmatrix.h"
+#include "gsstate.h"
+#include "gxdevice.h"
+#include "gxgetbit.h"
+#include "store.h"
+
+/* <device> copydevice <newdevice> */
+private int
+zcopydevice(register os_ptr op)
+{
+ gx_device *new_dev;
+ int code;
+
+ check_read_type(*op, t_device);
+ code = gs_copydevice(&new_dev, op->value.pdevice, imemory);
+ if (code < 0)
+ return code;
+ new_dev->memory = imemory;
+ make_tav(op, t_device, icurrent_space | a_all, pdevice, new_dev);
+ return 0;
+}
+
+/* - currentdevice <device> */
+int
+zcurrentdevice(register os_ptr op)
+{
+ gx_device *dev = gs_currentdevice(igs);
+ gs_ref_memory_t *mem = (gs_ref_memory_t *) dev->memory;
+
+ push(1);
+ make_tav(op, t_device,
+ (mem == 0 ? avm_foreign : imemory_space(mem)) | a_all,
+ pdevice, dev);
+ return 0;
+}
+
+/* <device> .devicename <string> */
+int
+zdevicename(register os_ptr op)
+{
+ const char *dname;
+
+ check_read_type(*op, t_device);
+ dname = op->value.pdevice->dname;
+ make_const_string(op, avm_foreign | a_readonly, strlen(dname),
+ (const byte *)dname);
+ return 0;
+}
+
+/* - .doneshowpage - */
+private int
+zdoneshowpage(register os_ptr op)
+{
+ gx_device *dev = gs_currentdevice(igs);
+ gx_device *tdev = (*dev_proc(dev, get_page_device)) (dev);
+
+ if (tdev != 0)
+ tdev->ShowpageCount++;
+ return 0;
+}
+
+/* - flushpage - */
+int
+zflushpage(register os_ptr op)
+{
+ return gs_flushpage(igs);
+}
+
+/* <device> <x> <y> <width> <max_height> <alpha?> <std_depth> <string> */
+/* .getbitsrect <height> <substring> */
+private int
+zgetbitsrect(register os_ptr op)
+{ /*
+ * alpha? is 0 for no alpha, -1 for alpha first, 1 for alpha last.
+ * std_depth is null for native pixels, depth/component for
+ * standard color space.
+ */
+ gx_device *dev;
+ gs_int_rect rect;
+ gs_get_bits_params_t params;
+ int w, h;
+ gs_get_bits_options_t options =
+ GB_ALIGN_ANY | GB_RETURN_COPY | GB_OFFSET_0 | GB_RASTER_STANDARD |
+ GB_PACKING_CHUNKY;
+ int std_depth;
+ uint raster;
+ int num_rows;
+ int code;
+
+ check_read_type(op[-7], t_device);
+ dev = op[-7].value.pdevice;
+ check_int_leu(op[-6], dev->width);
+ rect.p.x = op[-6].value.intval;
+ check_int_leu(op[-5], dev->height);
+ rect.p.y = op[-5].value.intval;
+ check_int_leu(op[-4], dev->width);
+ w = op[-4].value.intval;
+ check_int_leu(op[-3], dev->height);
+ h = op[-3].value.intval;
+ check_type(op[-2], t_integer);
+ switch (op[-2].value.intval) {
+ case -1:
+ options |= GB_ALPHA_FIRST;
+ break;
+ case 0:
+ options |= GB_ALPHA_NONE;
+ break;
+ case 1:
+ options |= GB_ALPHA_LAST;
+ break;
+ default:
+ return_error(e_rangecheck);
+ }
+ if (r_has_type(op - 1, t_null))
+ options |= GB_COLORS_NATIVE;
+ else {
+ static const gs_get_bits_options_t depths[17] = {
+ 0, GB_DEPTH_1, GB_DEPTH_2, 0, GB_DEPTH_4, 0, 0, 0, GB_DEPTH_8,
+ 0, 0, 0, GB_DEPTH_12, 0, 0, 0, GB_DEPTH_16
+ };
+ gs_get_bits_options_t depth_option;
+
+ check_int_leu(op[-1], 16);
+ std_depth = (int)op[-1].value.intval;
+ depth_option = depths[std_depth];
+ if (depth_option == 0)
+ return_error(e_rangecheck);
+ options |= depth_option | gb_colors_for_device(dev);
+ }
+ check_write_type(*op, t_string);
+ {
+ int depth =
+ (options & GB_COLORS_NATIVE ? dev->color_info.depth :
+ (dev->color_info.num_components +
+ (options & GB_ALPHA_NONE ? 0 : 1)) * std_depth);
+
+ raster = (w * depth + 7) >> 3;
+ }
+ num_rows = r_size(op) / raster;
+ h = min(h, num_rows);
+ if (h == 0)
+ return_error(e_rangecheck);
+ rect.q.x = rect.p.x + w;
+ rect.q.y = rect.p.y + h;
+ params.options = options;
+ params.data[0] = op->value.bytes;
+ code = (*dev_proc(dev, get_bits_rectangle))(dev, &rect, &params, NULL);
+ if (code < 0)
+ return code;
+ make_int(op - 7, h);
+ op[-6] = *op;
+ r_set_size(op - 6, h * raster);
+ pop(6);
+ return 0;
+}
+
+/* <int> .getdevice <device> */
+private int
+zgetdevice(register os_ptr op)
+{
+ const gx_device *dev;
+
+ check_type(*op, t_integer);
+ if (op->value.intval != (int)(op->value.intval))
+ return_error(e_rangecheck); /* won't fit in an int */
+ dev = gs_getdevice((int)(op->value.intval));
+ if (dev == 0) /* index out of range */
+ return_error(e_rangecheck);
+ /* Device prototypes are read-only; */
+ /* the cast is logically unnecessary. */
+ make_tav(op, t_device, avm_foreign | a_readonly, pdevice,
+ (gx_device *) dev);
+ return 0;
+}
+
+/* Common functionality of zgethardwareparms & zgetdeviceparams */
+private int
+zget_device_params(os_ptr op, bool is_hardware)
+{
+ ref rkeys;
+ gx_device *dev;
+ stack_param_list list;
+ int code;
+ ref *pmark;
+
+ check_read_type(op[-1], t_device);
+ rkeys = *op;
+ dev = op[-1].value.pdevice;
+ pop(1);
+ stack_param_list_write(&list, &o_stack, &rkeys);
+ code = gs_get_device_or_hardware_params(dev, (gs_param_list *) & list,
+ is_hardware);
+ if (code < 0) {
+ /* We have to put back the top argument. */
+ if (list.count > 0)
+ ref_stack_pop(&o_stack, list.count * 2 - 1);
+ else
+ ref_stack_push(&o_stack, 1);
+ *osp = rkeys;
+ return code;
+ }
+ pmark = ref_stack_index(&o_stack, list.count * 2);
+ make_mark(pmark);
+ return 0;
+}
+/* <device> <key_dict|null> .getdeviceparams <mark> <name> <value> ... */
+private int
+zgetdeviceparams(os_ptr op)
+{
+ return zget_device_params(op, false);
+}
+/* <device> <key_dict|null> .gethardwareparams <mark> <name> <value> ... */
+private int
+zgethardwareparams(os_ptr op)
+{
+ return zget_device_params(op, true);
+}
+
+/* <matrix> <width> <height> <palette> <word?> makewordimagedevice <device> */
+private int
+zmakewordimagedevice(register os_ptr op)
+{
+ os_ptr op1 = op - 1;
+ gs_matrix imat;
+ gx_device *new_dev;
+ const byte *colors;
+ int colors_size;
+ int code;
+
+ check_int_leu(op[-3], max_uint >> 1); /* width */
+ check_int_leu(op[-2], max_uint >> 1); /* height */
+ check_type(*op, t_boolean);
+ if (r_has_type(op1, t_null)) { /* true color */
+ colors = 0;
+ colors_size = -24; /* 24-bit true color */
+ } else if (r_has_type(op1, t_integer)) {
+ switch (op1->value.intval) {
+ case 16:
+ case 24:
+ case 32:
+ break;
+ default:
+ return_error(e_rangecheck);
+ }
+ colors = 0;
+ colors_size = -op1->value.intval;
+ } else {
+ check_type(*op1, t_string); /* palette */
+ if (r_size(op1) > 3 * 256)
+ return_error(e_rangecheck);
+ colors = op1->value.bytes;
+ colors_size = r_size(op1);
+ }
+ if ((code = read_matrix(op - 4, &imat)) < 0)
+ return code;
+ /* Everything OK, create device */
+ code = gs_makewordimagedevice(&new_dev, &imat,
+ (int)op[-3].value.intval,
+ (int)op[-2].value.intval,
+ colors, colors_size,
+ op->value.boolval, true, imemory);
+ if (code == 0) {
+ new_dev->memory = imemory;
+ make_tav(op - 4, t_device, imemory_space(iimemory) | a_all,
+ pdevice, new_dev);
+ pop(4);
+ }
+ return code;
+}
+
+/* - nulldevice - */
+/* Note that nulldevice clears the current pagedevice. */
+private int
+znulldevice(register os_ptr op)
+{
+ gs_nulldevice(igs);
+ clear_pagedevice(istate);
+ return 0;
+}
+
+/* <num_copies> <flush_bool> .outputpage - */
+private int
+zoutputpage(register os_ptr op)
+{
+ int code;
+
+ check_type(op[-1], t_integer);
+ check_type(*op, t_boolean);
+ code = gs_output_page(igs, (int)op[-1].value.intval,
+ op->value.boolval);
+ if (code < 0)
+ return code;
+ pop(2);
+ return 0;
+}
+
+/* <device> <policy_dict|null> <require_all> <mark> <name> <value> ... */
+/* .putdeviceparams */
+/* (on success) <device> <eraseflag> */
+/* (on failure) <device> <policy_dict|null> <require_all> <mark> */
+/* <name1> <error1> ... */
+/* For a key that simply was not recognized, if require_all is true, */
+/* the result will be an /undefined error; if require_all is false, */
+/* the key will be ignored. */
+/* Note that .putdeviceparams clears the current pagedevice. */
+private int
+zputdeviceparams(os_ptr op)
+{
+ uint count = ref_stack_counttomark(&o_stack);
+ ref *prequire_all;
+ ref *ppolicy;
+ ref *pdev;
+ gx_device *dev;
+ stack_param_list list;
+ int code;
+ int old_width, old_height;
+ int i, dest;
+
+ if (count == 0)
+ return_error(e_unmatchedmark);
+ prequire_all = ref_stack_index(&o_stack, count);
+ ppolicy = ref_stack_index(&o_stack, count + 1);
+ pdev = ref_stack_index(&o_stack, count + 2);
+ if (pdev == 0)
+ return_error(e_stackunderflow);
+ check_type_only(*prequire_all, t_boolean);
+ check_write_type_only(*pdev, t_device);
+ dev = pdev->value.pdevice;
+ code = stack_param_list_read(&list, &o_stack, 0, ppolicy,
+ prequire_all->value.boolval);
+ if (code < 0)
+ return code;
+ old_width = dev->width;
+ old_height = dev->height;
+ code = gs_putdeviceparams(dev, (gs_param_list *) & list);
+ /* Check for names that were undefined or caused errors. */
+ for (dest = count - 2, i = 0; i < count >> 1; i++)
+ if (list.results[i] < 0) {
+ *ref_stack_index(&o_stack, dest) =
+ *ref_stack_index(&o_stack, count - (i << 1) - 2);
+ gs_errorname(list.results[i],
+ ref_stack_index(&o_stack, dest - 1));
+ dest -= 2;
+ }
+ iparam_list_release(&list);
+ if (code < 0) { /* There were errors reported. */
+ ref_stack_pop(&o_stack, dest + 1);
+ return 0;
+ }
+ if (code > 0 || (code == 0 && (dev->width != old_width || dev->height != old_height))) {
+ /*
+ * The device was open and is now closed, or its dimensions have
+ * changed. If it was the current device, call setdevice to
+ * reinstall it and erase the page.
+ */
+ /****** DOESN'T FIND ALL THE GSTATES THAT REFERENCE THE DEVICE. ******/
+ if (gs_currentdevice(igs) == dev) {
+ bool was_open = dev->is_open;
+
+ code = gs_setdevice_no_erase(igs, dev);
+ /* If the device wasn't closed, setdevice won't erase the page. */
+ if (was_open && code >= 0)
+ code = 1;
+ }
+ }
+ if (code < 0)
+ return code;
+ ref_stack_pop(&o_stack, count + 1);
+ make_bool(osp, code);
+ clear_pagedevice(istate);
+ return 0;
+}
+
+/* <device> .setdevice <eraseflag> */
+/* Note that .setdevice clears the current pagedevice. */
+int
+zsetdevice(register os_ptr op)
+{
+ int code;
+
+ check_write_type(*op, t_device);
+ code = gs_setdevice_no_erase(igs, op->value.pdevice);
+ if (code < 0)
+ return code;
+ make_bool(op, code != 0); /* erase page if 1 */
+ clear_pagedevice(istate);
+ return code;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zdevice_op_defs[] =
+{
+ {"1copydevice", zcopydevice},
+ {"0currentdevice", zcurrentdevice},
+ {"1.devicename", zdevicename},
+ {"0.doneshowpage", zdoneshowpage},
+ {"0flushpage", zflushpage},
+ {"7.getbitsrect", zgetbitsrect},
+ {"1.getdevice", zgetdevice},
+ {"2.getdeviceparams", zgetdeviceparams},
+ {"2.gethardwareparams", zgethardwareparams},
+ {"5makewordimagedevice", zmakewordimagedevice},
+ {"0nulldevice", znulldevice},
+ {"2.outputpage", zoutputpage},
+ {"3.putdeviceparams", zputdeviceparams},
+ {"1.setdevice", zsetdevice},
+ op_def_end(0)
+};
diff --git a/pstoraster/zdevice2.c b/pstoraster/zdevice2.c
new file mode 100644
index 000000000..098541372
--- /dev/null
+++ b/pstoraster/zdevice2.c
@@ -0,0 +1,373 @@
+/* Copyright (C) 1993, 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$ */
+/* Level 2 device operators */
+#include "math_.h"
+#include "memory_.h"
+#include "ghost.h"
+#include "oper.h"
+#include "dstack.h" /* for dict_find_name */
+#include "estack.h"
+#include "idict.h"
+#include "idparam.h"
+#include "igstate.h"
+#include "iname.h"
+#include "store.h"
+#include "gxdevice.h"
+#include "gsstate.h"
+
+/* Forward references */
+private int z2copy_gstate(P1(os_ptr));
+private int push_callout(P1(const char *));
+
+/* Extend the `copy' operator to deal with gstates. */
+/* This is done with a hack -- we know that gstates are the only */
+/* t_astruct subtype that implements copy. */
+private int
+z2copy(register os_ptr op)
+{
+ int code = zcopy(op);
+
+ if (code >= 0)
+ return code;
+ if (!r_has_type(op, t_astruct))
+ return code;
+ return z2copy_gstate(op);
+}
+
+/* - .currentshowpagecount <count> true */
+/* - .currentshowpagecount false */
+private int
+zcurrentshowpagecount(register os_ptr op)
+{
+ gx_device *dev = gs_currentdevice(igs);
+
+ if ((*dev_proc(dev, get_page_device))(dev) == 0) {
+ push(1);
+ make_false(op);
+ } else {
+ push(2);
+ make_int(op - 1, dev->ShowpageCount);
+ make_true(op);
+ }
+ return 0;
+}
+
+/* - .currentpagedevice <dict> <bool> */
+private int
+zcurrentpagedevice(register os_ptr op)
+{
+ gx_device *dev = gs_currentdevice(igs);
+
+ push(2);
+ if ((*dev_proc(dev, get_page_device))(dev) != 0) {
+ op[-1] = istate->pagedevice;
+ make_true(op);
+ } else {
+ make_null(op - 1);
+ make_false(op);
+ }
+ return 0;
+}
+
+/* <local_dict|null> .setpagedevice - */
+private int
+zsetpagedevice(register os_ptr op)
+{
+ int code;
+
+/******
+ if ( igs->in_cachedevice )
+ return_error(e_undefined);
+ ******/
+ if (r_has_type(op, t_dictionary)) {
+ check_dict_read(*op);
+#if 0 /****************/
+ /*
+ * In order to avoid invalidaccess errors on setpagedevice,
+ * the dictionary must be allocated in local VM.
+ */
+ if (!(r_is_local(op)))
+ return_error(e_invalidaccess);
+#endif /****************/
+ /* Make the dictionary read-only. */
+ code = zreadonly(op);
+ if (code < 0)
+ return code;
+ } else {
+ check_type(*op, t_null);
+ }
+ istate->pagedevice = *op;
+ pop(1);
+ return 0;
+}
+
+/* Default Install/BeginPage/EndPage procedures */
+/* that just call the procedure in the device. */
+
+/* - .callinstall - */
+private int
+zcallinstall(os_ptr op)
+{
+ gx_device *dev = gs_currentdevice(igs);
+
+ if ((dev = (*dev_proc(dev, get_page_device))(dev)) != 0) {
+ int code = (*dev->page_procs.install) (dev, igs);
+
+ if (code < 0)
+ return code;
+ }
+ return 0;
+}
+
+/* <showpage_count> .callbeginpage - */
+private int
+zcallbeginpage(os_ptr op)
+{
+ gx_device *dev = gs_currentdevice(igs);
+
+ check_type(*op, t_integer);
+ if ((dev = (*dev_proc(dev, get_page_device))(dev)) != 0) {
+ int code = (*dev->page_procs.begin_page)(dev, igs);
+
+ if (code < 0)
+ return code;
+ }
+ pop(1);
+ return 0;
+}
+
+/* <showpage_count> <reason_int> .callendpage <flush_bool> */
+private int
+zcallendpage(os_ptr op)
+{
+ gx_device *dev = gs_currentdevice(igs);
+ int code;
+
+ check_type(op[-1], t_integer);
+ check_type(*op, t_integer);
+ if ((dev = (*dev_proc(dev, get_page_device))(dev)) != 0) {
+ code = (*dev->page_procs.end_page)(dev, (int)op->value.intval, igs);
+ if (code < 0)
+ return code;
+ if (code > 1)
+ return_error(e_rangecheck);
+ } else {
+ code = (op->value.intval == 2 ? 0 : 1);
+ }
+ make_bool(op - 1, code);
+ pop(1);
+ return 0;
+}
+
+/* ------ Wrappers for operators that save the graphics state. ------ */
+
+/* When saving the state with the current device a page device, */
+/* we need to make sure that the page device dictionary exists */
+/* so that grestore can use it to reset the device parameters. */
+/* This may have significant performance consequences, but we don't see */
+/* any way around it. */
+
+/* Check whether we need to call out to create the page device dictionary. */
+private bool
+save_page_device(gs_state *pgs)
+{
+ return
+ (r_has_type(&gs_int_gstate(pgs)->pagedevice, t_null) &&
+ (*dev_proc(gs_currentdevice(pgs), get_page_device))(gs_currentdevice(pgs)) != 0);
+}
+
+/* - gsave - */
+private int
+z2gsave(os_ptr op)
+{
+ if (!save_page_device(igs))
+ return gs_gsave(igs);
+ return push_callout("%gsavepagedevice");
+}
+
+/* - save - */
+private int
+z2save(os_ptr op)
+{
+ if (!save_page_device(igs))
+ return zsave(op);
+ return push_callout("%savepagedevice");
+}
+
+/* - gstate <gstate> */
+private int
+z2gstate(os_ptr op)
+{
+ if (!save_page_device(igs))
+ return zgstate(op);
+ return push_callout("%gstatepagedevice");
+}
+
+/* <gstate1> <gstate2> copy <gstate2> */
+private int
+z2copy_gstate(os_ptr op)
+{
+ if (!save_page_device(igs))
+ return zcopy_gstate(op);
+ return push_callout("%copygstatepagedevice");
+}
+
+/* <gstate> currentgstate <gstate> */
+private int
+z2currentgstate(os_ptr op)
+{
+ if (!save_page_device(igs))
+ return zcurrentgstate(op);
+ return push_callout("%currentgstatepagedevice");
+}
+
+/* ------ Wrappers for operators that reset the graphics state. ------ */
+
+/* Check whether we need to call out to restore the page device. */
+private bool
+restore_page_device(const gs_state * pgs_old, const gs_state * pgs_new)
+{
+ gx_device *dev_old = gs_currentdevice(pgs_old);
+ gx_device *dev_new;
+ gx_device *dev_t1;
+ gx_device *dev_t2;
+
+ if ((dev_t1 = (*dev_proc(dev_old, get_page_device)) (dev_old)) == 0)
+ return false;
+ dev_new = gs_currentdevice(pgs_new);
+ if (dev_old != dev_new) {
+ if ((dev_t2 = (*dev_proc(dev_new, get_page_device)) (dev_new)) == 0)
+ return false;
+ if (dev_t1 != dev_t2)
+ return true;
+ }
+ /* The current implementation of setpagedevice just sets new */
+ /* parameters in the same device object, so we have to check */
+ /* whether the page device dictionaries are the same. */
+ {
+ const ref *ppd1 = &gs_int_gstate(pgs_old)->pagedevice;
+ const ref *ppd2 = &gs_int_gstate(pgs_new)->pagedevice;
+
+ return (r_type(ppd1) != r_type(ppd2) ||
+ (r_has_type(ppd1, t_dictionary) &&
+ ppd1->value.pdict != ppd2->value.pdict));
+ }
+}
+
+/* - grestore - */
+private int
+z2grestore(os_ptr op)
+{
+ if (!restore_page_device(igs, gs_state_saved(igs)))
+ return gs_grestore(igs);
+ return push_callout("%grestorepagedevice");
+}
+
+/* - grestoreall - */
+private int
+z2grestoreall(os_ptr op)
+{
+ for (;;) {
+ if (!restore_page_device(igs, gs_state_saved(igs))) {
+ bool done = !gs_state_saved(gs_state_saved(igs));
+
+ gs_grestore(igs);
+ if (done)
+ break;
+ } else
+ return push_callout("%grestoreallpagedevice");
+ }
+ return 0;
+}
+
+/* <save> restore - */
+private int
+z2restore(os_ptr op)
+{
+ for (;;) {
+ if (!restore_page_device(igs, gs_state_saved(igs))) {
+ zgrestore(op);
+ if (!gs_state_saved(gs_state_saved(igs)))
+ break;
+ } else
+ return push_callout("%restorepagedevice");
+ }
+ return zrestore(op);
+}
+
+/* <gstate> setgstate - */
+private int
+z2setgstate(os_ptr op)
+{
+ check_stype(*op, st_igstate_obj);
+ if (!restore_page_device(igs, igstate_ptr(op)))
+ return zsetgstate(op);
+ return push_callout("%setgstatepagedevice");
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zdevice2_l2_op_defs[] =
+{
+ op_def_begin_level2(),
+ {"0.currentshowpagecount", zcurrentshowpagecount},
+ {"0.currentpagedevice", zcurrentpagedevice},
+ {"1.setpagedevice", zsetpagedevice},
+ /* Note that the following replace prior definitions */
+ /* in the indicated files: */
+ {"1copy", z2copy}, /* zdps1.c */
+ {"0gsave", z2gsave}, /* zgstate.c */
+ {"0save", z2save}, /* zvmem.c */
+ {"0gstate", z2gstate}, /* zdps1.c */
+ {"1currentgstate", z2currentgstate}, /* zdps1.c */
+ {"0grestore", z2grestore}, /* zgstate.c */
+ {"0grestoreall", z2grestoreall}, /* zgstate.c */
+ {"1restore", z2restore}, /* zvmem.c */
+ {"1setgstate", z2setgstate}, /* zdps1.c */
+ /* Default Install/BeginPage/EndPage procedures */
+ /* that just call the procedure in the device. */
+ {"0.callinstall", zcallinstall},
+ {"1.callbeginpage", zcallbeginpage},
+ {"2.callendpage", zcallendpage},
+ op_def_end(0)
+};
+
+/* ------ Internal routines ------ */
+
+/* Call out to a PostScript procedure. */
+private int
+push_callout(const char *callout_name)
+{
+ int code;
+
+ check_estack(1);
+ code = name_enter_string(callout_name, esp + 1);
+ if (code < 0)
+ return code;
+ ++esp;
+ r_set_attrs(esp, a_executable);
+ return o_push_estack;
+}
diff --git a/pstoraster/zdict.c b/pstoraster/zdict.c
new file mode 100644
index 000000000..fe7685a6e
--- /dev/null
+++ b/pstoraster/zdict.c
@@ -0,0 +1,515 @@
+/* Copyright (C) 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$ */
+/* Dictionary operators */
+#include "ghost.h"
+#include "oper.h"
+#include "idict.h"
+#include "dstack.h"
+#include "ilevel.h" /* for [count]dictstack */
+#include "iname.h" /* for dict_find_name */
+#include "ipacked.h" /* for inline dict lookup */
+#include "ivmspace.h"
+#include "store.h"
+
+/* <int> dict <dict> */
+int
+zdict(register os_ptr op)
+{
+ check_type(*op, t_integer);
+#if arch_sizeof_int < arch_sizeof_long
+ check_int_leu(*op, max_uint);
+#else
+ if (op->value.intval < 0)
+ return_error(e_rangecheck);
+#endif
+ return dict_create((uint) op->value.intval, op);
+}
+
+/* <dict> maxlength <int> */
+private int
+zmaxlength(register os_ptr op)
+{
+ check_type(*op, t_dictionary);
+ check_dict_read(*op);
+ make_int(op, dict_maxlength(op));
+ return 0;
+}
+
+/* <dict> begin - */
+int
+zbegin(register os_ptr op)
+{
+ check_type(*op, t_dictionary);
+ check_dict_read(*op);
+ if (dsp == dstop)
+ return_error(e_dictstackoverflow);
+ ++dsp;
+ ref_assign(dsp, op);
+ dict_set_top();
+ pop(1);
+ return 0;
+}
+
+/* - end - */
+int
+zend(register os_ptr op)
+{
+ if (ref_stack_count_inline(&d_stack) == min_dstack_size) {
+ /* We would underflow the d-stack. */
+ return_error(e_dictstackunderflow);
+ }
+ while (dsp == dsbot) {
+ /* We would underflow the current block. */
+ ref_stack_pop_block(&d_stack);
+ }
+ dsp--;
+ dict_set_top();
+ return 0;
+}
+
+/* <key> <value> def - */
+/*
+ * We make this into a separate procedure because
+ * the interpreter will almost always call it directly.
+ */
+int
+zop_def(register os_ptr op)
+{
+ register os_ptr op1 = op - 1;
+ ref *pvslot;
+
+ /* The following combines a check_op(2) with a type check. */
+ switch (r_type(op1)) {
+ case t_name: {
+ /* We can use the fast single-probe lookup here. */
+ uint nidx = name_index(op1);
+ uint htemp;
+
+ if_dict_find_name_by_index_top(nidx, htemp, pvslot) {
+ if (dtop_can_store(op))
+ goto ra;
+ }
+ break; /* handle all slower cases */
+ }
+ case t_null:
+ return_error(e_typecheck);
+ case t__invalid:
+ return_error(e_stackunderflow);
+ }
+ /*
+ * Combine the check for a writable top dictionary with
+ * the global/local store check. See dstack.h for details.
+ */
+ if (!dtop_can_store(op)) {
+ check_dict_write(*dsp);
+ /*
+ * If the dictionary is writable, the problem must be
+ * an invalid store.
+ */
+ return_error(e_invalidaccess);
+ }
+ /*
+ * Save a level of procedure call in the common (redefinition)
+ * case. With the current interfaces, we pay a double lookup
+ * in the uncommon case.
+ */
+ if (dict_find(dsp, op1, &pvslot) <= 0)
+ return dict_put(dsp, op1, op);
+ra:
+ ref_assign_old_inline(&dsp->value.pdict->values, pvslot, op,
+ "dict_put(value)");
+ return 0;
+}
+int
+zdef(os_ptr op)
+{
+ int code = zop_def(op);
+
+ if (code >= 0) {
+ pop(2);
+ }
+ return code;
+}
+
+/* <key> load <value> */
+private int
+zload(register os_ptr op)
+{
+ ref *pvalue;
+
+ switch (r_type(op)) {
+ case t_name:
+ /* Use the fast lookup. */
+ if ((pvalue = dict_find_name(op)) == 0)
+ return_error(e_undefined);
+ ref_assign(op, pvalue);
+ return 0;
+ case t_null:
+ return_error(e_typecheck);
+ case t__invalid:
+ return_error(e_stackunderflow);
+ default: {
+ /* Use an explicit loop. */
+ uint size = ref_stack_count(&d_stack);
+ uint i;
+
+ for (i = 0; i < size; i++) {
+ ref *dp = ref_stack_index(&d_stack, i);
+
+ check_dict_read(*dp);
+ if (dict_find(dp, op, &pvalue) > 0) {
+ ref_assign(op, pvalue);
+ return 0;
+ }
+ }
+ return_error(e_undefined);
+ }
+ }
+}
+
+/* get - implemented in zgeneric.c */
+
+/* put - implemented in zgeneric.c */
+
+/* <dict> <key> .undef - */
+/* <dict> <key> undef - */
+private int
+zundef(register os_ptr op)
+{
+ check_type(op[-1], t_dictionary);
+ check_dict_write(op[-1]);
+ dict_undef(op - 1, op); /* ignore undefined error */
+ pop(2);
+ return 0;
+}
+
+/* <dict> <key> known <bool> */
+private int
+zknown(register os_ptr op)
+{
+ register os_ptr op1 = op - 1;
+ ref *pvalue;
+
+ check_type(*op1, t_dictionary);
+ check_dict_read(*op1);
+ make_bool(op1, (dict_find(op1, op, &pvalue) > 0 ? 1 : 0));
+ pop(1);
+ return 0;
+}
+
+/* <key> where <dict> true */
+/* <key> where false */
+int
+zwhere(register os_ptr op)
+{
+ ref_stack_enum_t rsenum;
+
+ check_op(1);
+ ref_stack_enum_begin(&rsenum, &d_stack);
+ do {
+ const ref *const bot = rsenum.ptr;
+ const ref *pdref = bot + rsenum.size;
+ ref *pvalue;
+
+ while (pdref-- > bot) {
+ check_dict_read(*pdref);
+ if (dict_find(pdref, op, &pvalue) > 0) {
+ push(1);
+ ref_assign(op - 1, pdref);
+ make_true(op);
+ return 0;
+ }
+ }
+ } while (ref_stack_enum_next(&rsenum));
+ make_false(op);
+ return 0;
+}
+
+/* copy for dictionaries -- called from zcopy in zgeneric.c. */
+/* Only the type of *op has been checked. */
+int
+zcopy_dict(register os_ptr op)
+{
+ os_ptr op1 = op - 1;
+ int code;
+
+ check_type(*op1, t_dictionary);
+ check_dict_read(*op1);
+ check_dict_write(*op);
+ if (!dict_auto_expand &&
+ (dict_length(op) != 0 || dict_maxlength(op) < dict_length(op1))
+ )
+ return_error(e_rangecheck);
+ code = dict_copy(op1, op);
+ if (code < 0)
+ return code;
+ /*
+ * In Level 1 systems, we must copy the access attributes too.
+ * The only possible effect this can have is to make the
+ * copy read-only if the original dictionary is read-only.
+ */
+ if (!level2_enabled)
+ r_copy_attrs(dict_access_ref(op), a_write, dict_access_ref(op1));
+ ref_assign(op1, op);
+ pop(1);
+ return 0;
+}
+
+/* - currentdict <dict> */
+private int
+zcurrentdict(register os_ptr op)
+{
+ push(1);
+ ref_assign(op, dsp);
+ return 0;
+}
+
+/* - countdictstack <int> */
+private int
+zcountdictstack(register os_ptr op)
+{
+ uint count = ref_stack_count(&d_stack);
+
+ push(1);
+ if (!level2_enabled)
+ count--; /* see dstack.h */
+ make_int(op, count);
+ return 0;
+}
+
+/* <array> dictstack <subarray> */
+private int
+zdictstack(register os_ptr op)
+{
+ uint count = ref_stack_count(&d_stack);
+
+ check_write_type(*op, t_array);
+ if (!level2_enabled)
+ count--; /* see dstack.h */
+ return ref_stack_store(&d_stack, op, count, 0, 0, true, "dictstack");
+}
+
+/* - cleardictstack - */
+private int
+zcleardictstack(os_ptr op)
+{
+ while (zend(op) >= 0);
+ return 0;
+}
+
+/* ------ Extensions ------ */
+
+/* <dict1> <dict2> .dictcopynew <dict2> */
+private int
+zdictcopynew(register os_ptr op)
+{
+ os_ptr op1 = op - 1;
+ int code;
+
+ check_type(*op1, t_dictionary);
+ check_dict_read(*op1);
+ check_type(*op, t_dictionary);
+ check_dict_write(*op);
+ /* This is only recognized in Level 2 mode. */
+ if (!dict_auto_expand)
+ return_error(e_undefined);
+ code = dict_copy_new(op1, op);
+ if (code < 0)
+ return code;
+ ref_assign(op1, op);
+ pop(1);
+ return 0;
+}
+
+/* -mark- <key0> <value0> <key1> <value1> ... .dicttomark <dict> */
+/* This is the Level 2 >> operator. */
+private int
+zdicttomark(register os_ptr op)
+{
+ uint count2 = ref_stack_counttomark(&o_stack);
+ ref rdict;
+ int code;
+ uint idx;
+
+ if (count2 == 0)
+ return_error(e_unmatchedmark);
+ count2--;
+ if ((count2 & 1) != 0)
+ return_error(e_rangecheck);
+ code = dict_create(count2 >> 1, &rdict);
+ if (code < 0)
+ return code;
+ /* << /a 1 /a 2 >> => << /a 1 >>, i.e., */
+ /* we must enter the keys in top-to-bottom order. */
+ for (idx = 0; idx < count2; idx += 2) {
+ code = dict_put(&rdict,
+ ref_stack_index(&o_stack, idx + 1),
+ ref_stack_index(&o_stack, idx));
+ if (code < 0) { /* There's no way to free the dictionary -- too bad. */
+ return code;
+ }
+ }
+ ref_stack_pop(&o_stack, count2);
+ ref_assign(osp, &rdict);
+ return code;
+}
+
+/* <dict> <key> <value> .forceput - */
+/*
+ * This forces a "put" even if the dictionary is not writable, and (if the
+ * dictionary is systemdict or the save level is 0) even if the value is in
+ * local VM. It is meant to be used only for replacing the value of
+ * FontDirectory in systemdict when switching between local and global VM,
+ * and a few similar applications. After initialization, this operator
+ * should no longer be accessible by name.
+ */
+private int
+zforceput(register os_ptr op)
+{
+ os_ptr odp = op - 2;
+ int code;
+
+ check_type(*odp, t_dictionary);
+ if (odp->value.pdict == systemdict->value.pdict ||
+ !ialloc_is_in_save()
+ ) {
+ uint space = r_space(odp);
+
+ r_set_space(odp, avm_local);
+ code = dict_put(odp, op - 1, op);
+ r_set_space(odp, space);
+ } else
+ code = dict_put(odp, op - 1, op);
+ if (code < 0)
+ return code;
+ pop(3);
+ return 0;
+}
+
+/* <dict> <key> .forceundef - */
+/*
+ * This forces an "undef" even if the dictionary is not writable.
+ * Like .forceput, it is meant to be used only in a few special situations,
+ * and should not be accessible by name after initialization.
+ */
+private int
+zforceundef(register os_ptr op)
+{
+ check_type(op[-1], t_dictionary);
+ /* Don't check_dict_write */
+ dict_undef(op - 1, op); /* ignore undefined error */
+ pop(2);
+ return 0;
+}
+
+/* <dict> <key> .knownget <value> true */
+/* <dict> <key> .knownget false */
+private int
+zknownget(register os_ptr op)
+{
+ register os_ptr op1 = op - 1;
+ ref *pvalue;
+
+ check_type(*op1, t_dictionary);
+ check_dict_read(*op1);
+ if (dict_find(op1, op, &pvalue) <= 0) {
+ make_false(op1);
+ pop(1);
+ } else {
+ ref_assign(op1, pvalue);
+ make_true(op);
+ }
+ return 0;
+}
+
+/* <dict> <key> .knownundef <bool> */
+private int
+zknownundef(register os_ptr op)
+{
+ os_ptr op1 = op - 1;
+ int code;
+
+ check_type(*op1, t_dictionary);
+ check_dict_write(*op1);
+ code = dict_undef(op1, op);
+ make_bool(op1, code == 0);
+ pop(1);
+ return 0;
+}
+
+/* <dict> <int> .setmaxlength - */
+private int
+zsetmaxlength(register os_ptr op)
+{
+ os_ptr op1 = op - 1;
+ uint new_size;
+ int code;
+
+ check_type(*op1, t_dictionary);
+ check_dict_write(*op1);
+ check_type(*op, t_integer);
+#if arch_sizeof_int < arch_sizeof_long
+ check_int_leu(*op, max_uint);
+#else
+ if (op->value.intval < 0)
+ return_error(e_rangecheck);
+#endif
+ new_size = (uint) op->value.intval;
+ if (dict_length(op - 1) > new_size)
+ return_error(e_dictfull);
+ code = dict_resize(op - 1, new_size);
+ if (code >= 0)
+ pop(2);
+ return code;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zdict_op_defs[] =
+{
+ {"0cleardictstack", zcleardictstack},
+ {"1begin", zbegin},
+ {"0countdictstack", zcountdictstack},
+ {"0currentdict", zcurrentdict},
+ {"2def", zdef},
+ {"1dict", zdict},
+ {"0dictstack", zdictstack},
+ {"0end", zend},
+ {"2known", zknown},
+ {"1load", zload},
+ {"1maxlength", zmaxlength},
+ {"2.undef", zundef}, /* we need this even in Level 1 */
+ {"1where", zwhere},
+ /* Extensions */
+ {"2.dictcopynew", zdictcopynew},
+ {"1.dicttomark", zdicttomark},
+ {"3.forceput", zforceput},
+ {"2.forceundef", zforceundef},
+ {"2.knownget", zknownget},
+ {"1.knownundef", zknownundef},
+ {"2.setmaxlength", zsetmaxlength},
+ op_def_end(0)
+};
diff --git a/pstoraster/zdps1.c b/pstoraster/zdps1.c
new file mode 100644
index 000000000..c3e891589
--- /dev/null
+++ b/pstoraster/zdps1.c
@@ -0,0 +1,459 @@
+/* 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$ */
+/* Level 2 / Display PostScript graphics extensions */
+#include "ghost.h"
+#include "oper.h"
+#include "gsmatrix.h"
+#include "gspath.h"
+#include "gspath2.h"
+#include "gsstate.h"
+#include "ialloc.h"
+#include "igstate.h"
+#include "ivmspace.h"
+#include "store.h"
+#include "stream.h"
+#include "ibnum.h"
+
+/* Forward references */
+private int gstate_unshare(P1(os_ptr));
+
+/* Structure descriptors */
+public_st_igstate_obj();
+
+/* Extend the `copy' operator to deal with gstates. */
+/* This is done with a hack -- we know that gstates are the only */
+/* t_astruct subtype that implements copy. */
+private int
+z1copy(register os_ptr op)
+{
+ int code = zcopy(op);
+
+ if (code >= 0)
+ return code;
+ if (!r_has_type(op, t_astruct))
+ return code;
+ return zcopy_gstate(op);
+}
+
+/* ------ Graphics state ------ */
+
+/* <bool> setstrokeadjust - */
+private int
+zsetstrokeadjust(register os_ptr op)
+{
+ check_type(*op, t_boolean);
+ gs_setstrokeadjust(igs, op->value.boolval);
+ pop(1);
+ return 0;
+}
+
+/* - currentstrokeadjust <bool> */
+private int
+zcurrentstrokeadjust(register os_ptr op)
+{
+ push(1);
+ make_bool(op, gs_currentstrokeadjust(igs));
+ return 0;
+}
+
+/* ------ Graphics state objects ------ */
+
+/* Check to make sure that all the elements of a graphics state */
+/* can be stored in the given allocation space. */
+/****** DOESN'T CHECK THE NON-REFS. ****** */
+private int
+gstate_check_space(int_gstate * isp, uint space)
+{
+#define gsref_check(p) store_check_space(space, p)
+ int_gstate_map_refs(isp, gsref_check);
+#undef gsref_check
+ return 0;
+}
+
+/* - gstate <gstate> */
+int
+zgstate(register os_ptr op)
+{
+ int code = gstate_check_space(istate, icurrent_space);
+ igstate_obj *pigo;
+ gs_state *pnew;
+ int_gstate *isp;
+
+ if (code < 0)
+ return code;
+ pigo = ialloc_struct(igstate_obj, &st_igstate_obj, "gstate");
+ if (pigo == 0)
+ return_error(e_VMerror);
+ pnew = gs_state_copy(igs, imemory);
+ if (pnew == 0) {
+ ifree_object(pigo, "gstate");
+ return_error(e_VMerror);
+ }
+ isp = gs_int_gstate(pnew);
+ int_gstate_map_refs(isp, ref_mark_new);
+ push(1);
+ /*
+ * Since igstate_obj isn't a ref, but only contains a ref, save won't
+ * clear its l_new bit automatically, and restore won't set it
+ * automatically; we have to make sure this ref is on the changes chain.
+ */
+ make_iastruct(op, a_all, pigo);
+ make_null(&pigo->gstate);
+ ref_save(op, &pigo->gstate, "gstate");
+ make_istruct_new(&pigo->gstate, 0, pnew);
+ return 0;
+}
+
+/* copy for gstates */
+int
+zcopy_gstate(register os_ptr op)
+{
+ os_ptr op1 = op - 1;
+ gs_state *pgs;
+ gs_state *pgs1;
+ int_gstate *pistate;
+ gs_memory_t *mem;
+ int code;
+
+ check_stype(*op, st_igstate_obj);
+ check_stype(*op1, st_igstate_obj);
+ check_write(*op);
+ code = gstate_unshare(op);
+ if (code < 0)
+ return code;
+ pgs = igstate_ptr(op);
+ pgs1 = igstate_ptr(op1);
+ pistate = gs_int_gstate(pgs);
+ code = gstate_check_space(gs_int_gstate(pgs1), r_space(op));
+ if (code < 0)
+ return code;
+#define gsref_save(p) ref_save(op, p, "copygstate")
+ int_gstate_map_refs(pistate, gsref_save);
+#undef gsref_save
+ mem = gs_state_swap_memory(pgs, imemory);
+ code = gs_copygstate(pgs, pgs1);
+ gs_state_swap_memory(pgs, mem);
+ if (code < 0)
+ return code;
+ int_gstate_map_refs(pistate, ref_mark_new);
+ *op1 = *op;
+ pop(1);
+ return 0;
+}
+
+/* <gstate> currentgstate <gstate> */
+int
+zcurrentgstate(register os_ptr op)
+{
+ gs_state *pgs;
+ int_gstate *pistate;
+ int code;
+ gs_memory_t *mem;
+
+ check_stype(*op, st_igstate_obj);
+ check_write(*op);
+ code = gstate_unshare(op);
+ if (code < 0)
+ return code;
+ pgs = igstate_ptr(op);
+ pistate = gs_int_gstate(pgs);
+ code = gstate_check_space(istate, r_space(op));
+ if (code < 0)
+ return code;
+#define gsref_save(p) ref_save(op, p, "currentgstate")
+ int_gstate_map_refs(pistate, gsref_save);
+#undef gsref_save
+ mem = gs_state_swap_memory(pgs, imemory);
+ code = gs_currentgstate(pgs, igs);
+ gs_state_swap_memory(pgs, mem);
+ if (code < 0)
+ return code;
+ int_gstate_map_refs(pistate, ref_mark_new);
+ return 0;
+}
+
+/* <gstate> setgstate - */
+int
+zsetgstate(register os_ptr op)
+{
+ int code;
+
+ check_stype(*op, st_igstate_obj);
+ check_read(*op);
+ code = gs_setgstate(igs, igstate_ptr(op));
+ if (code < 0)
+ return code;
+ pop(1);
+ return 0;
+}
+
+/* ------ Rectangles ------- */
+
+/*
+ * We preallocate a short list for rectangles, because
+ * the rectangle operators usually will involve very few rectangles.
+ */
+#define MAX_LOCAL_RECTS 5
+typedef struct local_rects_s {
+ gs_rect *pr;
+ uint count;
+ gs_rect rl[MAX_LOCAL_RECTS];
+} local_rects_t;
+
+/* Forward references */
+private int rect_get(P2(local_rects_t *, os_ptr));
+private void rect_release(P1(local_rects_t *));
+
+/* <x> <y> <width> <height> .rectappend - */
+/* <numarray|numstring> .rectappend - */
+private int
+zrectappend(os_ptr op)
+{
+ local_rects_t lr;
+ int npop = rect_get(&lr, op);
+ int code;
+
+ if (npop < 0)
+ return npop;
+ code = gs_rectappend(igs, lr.pr, lr.count);
+ rect_release(&lr);
+ if (code < 0)
+ return code;
+ pop(npop);
+ return 0;
+}
+
+/* <x> <y> <width> <height> rectclip - */
+/* <numarray|numstring> rectclip - */
+private int
+zrectclip(os_ptr op)
+{
+ local_rects_t lr;
+ int npop = rect_get(&lr, op);
+ int code;
+
+ if (npop < 0)
+ return npop;
+ code = gs_rectclip(igs, lr.pr, lr.count);
+ rect_release(&lr);
+ if (code < 0)
+ return code;
+ pop(npop);
+ return 0;
+}
+
+/* <x> <y> <width> <height> rectfill - */
+/* <numarray|numstring> rectfill - */
+private int
+zrectfill(os_ptr op)
+{
+ local_rects_t lr;
+ int npop = rect_get(&lr, op);
+ int code;
+
+ if (npop < 0)
+ return npop;
+ code = gs_rectfill(igs, lr.pr, lr.count);
+ rect_release(&lr);
+ if (code < 0)
+ return code;
+ pop(npop);
+ return 0;
+}
+
+/* <x> <y> <width> <height> rectstroke - */
+/* <numarray|numstring> rectstroke - */
+private int
+zrectstroke(os_ptr op)
+{
+ gs_matrix mat;
+ local_rects_t lr;
+ int npop, code;
+
+ if (read_matrix(op, &mat) >= 0) {
+ /* Concatenate the matrix to the CTM just before stroking the path. */
+ npop = rect_get(&lr, op - 1);
+ if (npop < 0)
+ return npop;
+ code = gs_rectstroke(igs, lr.pr, lr.count, &mat);
+ npop++;
+ } else {
+ /* No matrix. */
+ npop = rect_get(&lr, op);
+ if (npop < 0)
+ return npop;
+ code = gs_rectstroke(igs, lr.pr, lr.count, (gs_matrix *) 0);
+ }
+ rect_release(&lr);
+ if (code < 0)
+ return code;
+ pop(npop);
+ return 0;
+}
+
+/* --- Internal routines --- */
+
+/* Get rectangles from the stack. */
+/* Return the number of elements to pop (>0) if OK, <0 if error. */
+private int
+rect_get(local_rects_t * plr, os_ptr op)
+{
+ int format, code;
+ uint n, count;
+ gs_rect *pr;
+ double rv[4];
+
+ switch (r_type(op)) {
+ case t_array:
+ case t_mixedarray:
+ case t_shortarray:
+ case t_string:
+ code = num_array_format(op);
+ if (code < 0)
+ return code;
+ format = code;
+ count = num_array_size(op, format);
+ if (count % 4)
+ return_error(e_rangecheck);
+ count /= 4;
+ break;
+ default: /* better be 4 numbers */
+ code = num_params(op, 4, rv);
+ if (code < 0)
+ return code;
+ plr->pr = plr->rl;
+ plr->count = 1;
+ plr->rl[0].q.x = (plr->rl[0].p.x = rv[0]) + rv[2];
+ plr->rl[0].q.y = (plr->rl[0].p.y = rv[1]) + rv[3];
+ return 4;
+ }
+ plr->count = count;
+ if (count <= MAX_LOCAL_RECTS)
+ pr = plr->rl;
+ else {
+ pr = (gs_rect *) ialloc_byte_array(count, sizeof(gs_rect),
+ "rect_get");
+ if (pr == 0)
+ return_error(e_VMerror);
+ }
+ plr->pr = pr;
+ for (n = 0; n < count; n++, pr++) {
+ ref rnum;
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ code = num_array_get((const ref *)op, format,
+ (n << 2) + i, &rnum);
+ switch (code) {
+ case t_integer:
+ rv[i] = rnum.value.intval;
+ break;
+ case t_real:
+ rv[i] = rnum.value.realval;
+ break;
+ default: /* code < 0 */
+ return code;
+ }
+ }
+ pr->q.x = (pr->p.x = rv[0]) + rv[2];
+ pr->q.y = (pr->p.y = rv[1]) + rv[3];
+ }
+ return 1;
+}
+
+/* Release the rectangle list if needed. */
+private void
+rect_release(local_rects_t * plr)
+{
+ if (plr->pr != plr->rl)
+ ifree_object(plr->pr, "rect_release");
+}
+
+/* ------ Graphics state ------ */
+
+/* <llx> <lly> <urx> <ury> setbbox - */
+int
+zsetbbox(register os_ptr op)
+{
+ double box[4];
+
+ int code = num_params(op, 4, box);
+
+ if (code < 0)
+ return code;
+ if ((code = gs_setbbox(igs, box[0], box[1], box[2], box[3])) < 0)
+ return code;
+ pop(4);
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zdps1_l2_op_defs[] =
+{
+ op_def_begin_level2(),
+ /* Graphics state */
+ {"0currentstrokeadjust", zcurrentstrokeadjust},
+ {"1setstrokeadjust", zsetstrokeadjust},
+ /* Graphics state objects */
+ {"1copy", z1copy},
+ {"1currentgstate", zcurrentgstate},
+ {"0gstate", zgstate},
+ {"1setgstate", zsetgstate},
+ /* Rectangles */
+ {"1.rectappend", zrectappend},
+ {"1rectclip", zrectclip},
+ {"1rectfill", zrectfill},
+ {"1rectstroke", zrectstroke},
+ /* Graphics state components */
+ {"4setbbox", zsetbbox},
+ op_def_end(0)
+};
+
+/* ------ Internal routines ------ */
+
+/* Ensure that a gstate is not shared with an outer save level. */
+/* *op is of type t_astruct(igstate_obj). */
+private int
+gstate_unshare(os_ptr op)
+{
+ ref *pgsref = &r_ptr(op, igstate_obj)->gstate;
+ gs_state *pgs = r_ptr(pgsref, gs_state);
+ gs_state *pnew;
+ int_gstate *isp;
+
+ if (!ref_must_save(pgsref))
+ return 0;
+ /* Copy the gstate. */
+ pnew = gs_gstate(pgs);
+ if (pnew == 0)
+ return_error(e_VMerror);
+ isp = gs_int_gstate(pnew);
+ int_gstate_map_refs(isp, ref_mark_new);
+ ref_do_save(op, pgsref, "gstate_unshare");
+ make_istruct_new(pgsref, 0, pnew);
+ return 0;
+}
diff --git a/pstoraster/zfbcp.c b/pstoraster/zfbcp.c
new file mode 100644
index 000000000..61f9384c7
--- /dev/null
+++ b/pstoraster/zfbcp.c
@@ -0,0 +1,99 @@
+/* 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$ */
+/* (T)BCP filter creation */
+#include "memory_.h"
+#include "ghost.h"
+#include "oper.h"
+#include "gsstruct.h"
+#include "ialloc.h"
+#include "stream.h"
+#include "strimpl.h"
+#include "sfilter.h"
+#include "ifilter.h"
+
+/* Define null handlers for the BCP out-of-band signals. */
+private int
+no_bcp_signal_interrupt(stream_state * st)
+{
+ return 0;
+}
+private int
+no_bcp_request_status(stream_state * st)
+{
+ return 0;
+}
+
+/* <source> BCPEncode/filter <file> */
+/* <source> <dict> BCPEncode/filter <file> */
+private int
+zBCPE(os_ptr op)
+{
+ return filter_write_simple(op, &s_BCPE_template);
+}
+
+/* <target> BCPDecode/filter <file> */
+/* <target> <dict> BCPDecode/filter <file> */
+private int
+zBCPD(os_ptr op)
+{
+ stream_BCPD_state state;
+
+ state.signal_interrupt = no_bcp_signal_interrupt;
+ state.request_status = no_bcp_request_status;
+ return filter_read(op, 0, &s_BCPD_template, (stream_state *) & state, 0);
+}
+
+/* <source> TBCPEncode/filter <file> */
+/* <source> <dict> TBCPEncode/filter <file> */
+private int
+zTBCPE(os_ptr op)
+{
+ return filter_write_simple(op, &s_TBCPE_template);
+}
+
+/* <target> TBCPDecode/filter <file> */
+/* <target> <dict> TBCPDecode/filter <file> */
+private int
+zTBCPD(os_ptr op)
+{
+ stream_BCPD_state state;
+
+ state.signal_interrupt = no_bcp_signal_interrupt;
+ state.request_status = no_bcp_request_status;
+ return filter_read(op, 0, &s_TBCPD_template, (stream_state *)&state, 0);
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zfbcp_op_defs[] =
+{
+ op_def_begin_filter(),
+ {"1BCPEncode", zBCPE},
+ {"1BCPDecode", zBCPD},
+ {"1TBCPEncode", zTBCPE},
+ {"1TBCPDecode", zTBCPD},
+ op_def_end(0)
+};
diff --git a/pstoraster/zfcmap.c b/pstoraster/zfcmap.c
new file mode 100644
index 000000000..479881e22
--- /dev/null
+++ b/pstoraster/zfcmap.c
@@ -0,0 +1,355 @@
+/* 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$ */
+/* CMap creation operator */
+#include "ghost.h"
+#include "oper.h"
+#include "gsmatrix.h" /* for gxfont.h */
+#include "gsstruct.h"
+#include "gsutil.h" /* for bytes_compare */
+#include "gxfcmap.h"
+#include "gxfont.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "idparam.h"
+#include "ifont.h" /* for zfont_mark_glyph_name */
+#include "iname.h"
+#include "store.h"
+
+/* ---------------- Internal procedures ---------------- */
+
+/* Free a code map tree in case of memory overflow. */
+private void
+free_code_map(gx_code_map * pcmap, gs_memory_t * mem)
+{
+ if (pcmap->type == cmap_subtree) {
+ int i;
+
+ for (i = pcmap->byte_data.count1; i >= 0; --i)
+ free_code_map(&pcmap->data.subtree[i], mem);
+ gs_free_object(mem, pcmap->data.subtree, "free_code_map");
+ }
+}
+
+/* Convert a code map to internal form. */
+private int
+acquire_code_map(gx_code_map * pcmap, const ref * pref, int depth,
+ gs_cmap * root, gs_memory_t * mem)
+{
+ pcmap->add_offset = 0;
+ pcmap->cmap = root;
+ pcmap->byte_data.font_index = 0;
+ switch (r_type(pref)) {
+ case t_null:
+ pcmap->type = cmap_glyph;
+ pcmap->data.glyph = gs_no_glyph;
+ return 0;
+ case t_name:
+ pcmap->type = cmap_glyph;
+ pcmap->data.glyph = name_index(pref);
+ return 0;
+ case t_integer:
+ if (pref->value.intval < 0 ||
+ pref->value.intval > gs_max_glyph - gs_min_cid_glyph
+ )
+ break;
+ pcmap->type = cmap_glyph;
+ pcmap->data.glyph = pref->value.intval + gs_min_cid_glyph;
+ return 0;
+ case t_string:
+ if (r_size(pref) < 1 || r_size(pref) > 4)
+ break;
+ pcmap->type = cmap_char_code;
+ pcmap->num_bytes1 = r_size(pref) - 1;
+ {
+ int i;
+ gs_char chr = 0;
+
+ for (i = 0; i < r_size(pref); ++i)
+ chr = (chr << 8) + pref->value.const_bytes[i];
+ pcmap->data.ccode = chr;
+ }
+ return 0;
+ default:
+ if (!r_is_array(pref) || r_size(pref) < 1 || r_size(pref) > 256)
+ break;
+ if (depth >= 4)
+ return_error(e_limitcheck);
+ {
+ uint size = r_size(pref);
+ uint count = 0;
+ ref_type rtype;
+ long prev_value;
+ long diff;
+ uint run_length;
+ ref rsub;
+ gx_code_map *subtree;
+ uint i, j;
+
+ /* Do a first pass to count non-null entries and find runs. */
+
+ for (rtype = t_null, i = 0; i < size; ++i) {
+ ref_type prev_type = rtype;
+
+ array_get(pref, (long)i, &rsub);
+ rtype = r_type(&rsub);
+ switch (rtype) {
+ case t_null:
+ continue;
+ case t_integer:
+ if (prev_type == t_integer) {
+ if (run_length == 1) {
+ diff = rsub.value.intval - prev_value;
+ if (!(diff & ~1L)) {
+ prev_value = rsub.value.intval;
+ run_length = 2;
+ continue;
+ }
+ } else if (rsub.value.intval - prev_value == diff) {
+ prev_value = rsub.value.intval;
+ ++run_length;
+ continue;
+ }
+ }
+ prev_value = rsub.value.intval;
+ run_length = 1;
+ /* falls through */
+ default:
+ ++count;
+ }
+ }
+
+ if (count == 0) /* all nulls */
+ count = 1;
+ subtree =
+ gs_alloc_struct_array(mem, count, gx_code_map,
+ &st_code_map_element,
+ "acquire_code_map");
+ if (subtree == 0)
+ return_error(e_VMerror);
+ pcmap->type = cmap_subtree;
+ pcmap->data.subtree = subtree;
+ /* Initialize a single undefined entry, in case count = 0 */
+ /* or we have to bail out with j = 0. */
+ subtree->first = subtree->last = 255;
+ subtree->type = cmap_glyph;
+ subtree->byte_data.font_index = 0;
+ subtree->data.glyph = gs_no_glyph;
+
+ /* Do the second pass to construct the tree. */
+
+ for (rtype = t_null, i = j = 0; i < size; ++i) {
+ ref_type prev_type = rtype;
+ gx_code_map *submap = &subtree[j];
+ int code;
+
+ array_get(pref, (long)i, &rsub);
+ rtype = r_type(&rsub);
+ switch (rtype) {
+ case t_null:
+ continue;
+ case t_integer:
+ if (prev_type == t_integer) {
+ if (submap[-1].first == submap[-1].last) {
+ diff = rsub.value.intval - prev_value;
+ if (!(diff & ~1L)) {
+ prev_value = rsub.value.intval;
+ submap[-1].add_offset = (uint)diff;
+ submap[-1].last++;
+ continue;
+ }
+ } else if (rsub.value.intval - prev_value == diff) {
+ prev_value = rsub.value.intval;
+ submap[-1].last++;
+ continue;
+ }
+ }
+ prev_value = rsub.value.intval;
+ /* falls through */
+ default:
+ code = acquire_code_map(submap, &rsub, depth + 1,
+ root, mem);
+ if (code < 0) { /* Release allocated elements. */
+ pcmap->byte_data.count1 = (j ? j - 1 : 0);
+ free_code_map(pcmap, mem);
+ return code;
+ }
+ submap->first = submap->last = (byte)i;
+ ++j;
+ }
+ }
+ pcmap->byte_data.count1 = count - 1;
+ }
+ return 0;
+ }
+ return_error(e_rangecheck);
+}
+
+/* Acquire CIDSystemInfo. If missing, set Registry and Ordering to */
+/* empty strings and Supplement to 0, and return 1. */
+/* Note that this currently does not handle the array format. */
+private int
+acquire_cid_system_info(gs_cid_system_info * pcidsi, const ref * op)
+{
+ ref *prcidsi;
+ ref *pregistry;
+ ref *pordering;
+
+ if (dict_find_string(op, "CIDSystemInfo", &prcidsi) <= 0) {
+ pcidsi->Registry.data = 0, pcidsi->Registry.size = 0;
+ pcidsi->Ordering.data = 0, pcidsi->Ordering.size = 0;
+ pcidsi->Supplement = 0;
+ return 1;
+ }
+ if (!r_has_type(prcidsi, t_dictionary))
+ return_error(e_typecheck);
+ if (dict_find_string(prcidsi, "Registry", &pregistry) <= 0 ||
+ dict_find_string(prcidsi, "Ordering", &pordering) <= 0
+ )
+ return_error(e_rangecheck);
+ check_read_type_only(*pregistry, t_string);
+ check_read_type_only(*pordering, t_string);
+ pcidsi->Registry.data = pregistry->value.const_bytes;
+ pcidsi->Registry.size = r_size(pregistry);
+ pcidsi->Ordering.data = pordering->value.const_bytes;
+ pcidsi->Ordering.size = r_size(pordering);
+ return dict_int_param(prcidsi, "Supplement", 0, max_int, -1,
+ &pcidsi->Supplement);
+}
+
+/* Check compatibility of CIDSystemInfo. */
+private bool
+bytes_eq(const gs_const_string *pcs1, const gs_const_string *pcs2)
+{
+ return !bytes_compare(pcs1->data, pcs1->size,
+ pcs2->data, pcs2->size);
+}
+private bool
+cid_system_info_compatible(const gs_cid_system_info * psi1,
+ const gs_cid_system_info * psi2)
+{
+ return bytes_eq(&psi1->Registry, &psi2->Registry) &&
+ bytes_eq(&psi1->Ordering, &psi2->Ordering);
+}
+
+/* ---------------- (Semi-)public procedures ---------------- */
+
+/* Get the CodeMap from a Type 0 font, and check the CIDSystemInfo of */
+/* its subsidiary fonts. */
+int
+ztype0_get_cmap(const gs_cmap ** ppcmap, const ref * pfdepvector, const ref * op)
+{
+ ref *prcmap;
+ ref *pcodemap;
+ const gs_cmap *pcmap;
+ int code;
+ ref rfdep;
+ gs_cid_system_info cidsi;
+
+ if (dict_find_string(op, "CMap", &prcmap) <= 0 ||
+ !r_has_type(prcmap, t_dictionary) ||
+ dict_find_string(prcmap, "CodeMap", &pcodemap) <= 0 ||
+ !r_has_stype(pcodemap, imemory, st_cmap)
+ )
+ return_error(e_invalidfont);
+ pcmap = r_ptr(pcodemap, gs_cmap);
+ /* Currently we only handle 1-element fonts. */
+ if (r_size(pfdepvector) != 1)
+ return_error(e_rangecheck);
+ array_get(pfdepvector, 0L, &rfdep);
+ code = acquire_cid_system_info(&cidsi, &rfdep);
+ if (code < 0)
+ return code;
+ if (code == 0 &&
+ !cid_system_info_compatible(&cidsi, &pcmap->CIDSystemInfo)
+ )
+ return_error(e_rangecheck);
+ *ppcmap = pcmap;
+ return 0;
+}
+
+/* ---------------- Operators ---------------- */
+
+/* <CMap> .buildcmap <CMap> */
+/*
+ * Create the internal form of a CMap. The initial CMap must be read-write
+ * and have an entry with key = CodeMap and value = null; the result is
+ * read-only and has a real CodeMap.
+ */
+private int
+zbuildcmap(os_ptr op)
+{
+ int code;
+ ref *pcodemaps;
+ ref *pcodemap;
+ gs_cmap *pcmap;
+ ref rdef, rnotdef, rcmap;
+
+ check_type(*op, t_dictionary);
+ check_dict_write(*op);
+ pcmap = ialloc_struct(gs_cmap, &st_cmap, "zbuildcmap(cmap)");
+ if (pcmap == 0) {
+ code = gs_note_error(e_VMerror);
+ goto fail;
+ }
+ if ((code = dict_uid_param(op, &pcmap->uid, 0, imemory)) < 0 ||
+ (code = dict_int_param(op, "WMode", 0, 1, 0, &pcmap->WMode)) < 0
+ )
+ goto fail;
+ if (dict_find_string(op, ".CodeMaps", &pcodemaps) <= 0 ||
+ !r_has_type(pcodemaps, t_array) ||
+ r_size(pcodemaps) != 2 ||
+ dict_find_string(op, "CodeMap", &pcodemap) <= 0 ||
+ !r_has_type(pcodemap, t_null)
+ ) {
+ code = gs_note_error(e_rangecheck);
+ goto fail;
+ }
+ if ((code = acquire_cid_system_info(&pcmap->CIDSystemInfo, op)) < 0 ||
+ (array_get(pcodemaps, 0L, &rdef),
+ (code = acquire_code_map(&pcmap->def, &rdef, 0, pcmap, imemory)) < 0) ||
+ (array_get(pcodemaps, 1L, &rnotdef),
+ (code = acquire_code_map(&pcmap->notdef, &rnotdef, 0, pcmap, imemory)) < 0)
+ )
+ goto fail;
+ pcmap->mark_glyph = zfont_mark_glyph_name;
+ pcmap->mark_glyph_data = 0;
+ make_istruct_new(&rcmap, a_readonly, pcmap);
+ code = dict_put_string(op, "CodeMap", &rcmap);
+ if (code < 0)
+ goto fail;
+ return zreadonly(op);
+fail:
+ ifree_object(pcmap, "zbuildcmap(cmap)");
+ return code;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zfcmap_op_defs[] =
+{
+ {"1.buildcmap", zbuildcmap},
+ op_def_end(0)
+};
diff --git a/pstoraster/zfdctd.c b/pstoraster/zfdctd.c
new file mode 100644
index 000000000..aaefd68c9
--- /dev/null
+++ b/pstoraster/zfdctd.c
@@ -0,0 +1,110 @@
+/*
+ Copyright 1993-2002 by Easy Software Products.
+ Copyright 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.
+*/
+#include <config.h>
+#ifdef HAVE_LIBJPEG
+
+/*$Id$ */
+/* DCTDecode filter creation */
+#include "memory_.h"
+#include "stdio_.h" /* for jpeglib.h */
+#include "jpeglib.h"
+#include "ghost.h"
+#include "oper.h"
+#include "gsmalloc.h" /* for gs_memory_default */
+#include "strimpl.h"
+#include "sdct.h"
+#include "sjpeg.h"
+#include "ialloc.h"
+#include "ifilter.h"
+#include "iparam.h"
+
+/* Import the parameter processing procedure from sddparam.c */
+stream_state_proc_put_params(s_DCTD_put_params, stream_DCT_state);
+
+/* <source> <dict> DCTDecode/filter <file> */
+/* <source> DCTDecode/filter <file> */
+private int
+zDCTD(os_ptr op)
+{
+ gs_memory_t *mem = &gs_memory_default;
+ stream_DCT_state state;
+ dict_param_list list;
+ jpeg_decompress_data *jddp;
+ int code;
+ int npop;
+ const ref *dop;
+ uint dspace;
+
+ /* First allocate space for IJG parameters. */
+ jddp = (jpeg_decompress_data *)
+ gs_alloc_bytes_immovable(mem, sizeof(*jddp), "zDCTD");
+ if (jddp == 0)
+ return_error(e_VMerror);
+ if (s_DCTD_template.set_defaults)
+ (*s_DCTD_template.set_defaults) ((stream_state *) & state);
+ state.data.decompress = jddp;
+ jddp->memory = state.jpeg_memory = mem; /* set now for allocation */
+ jddp->scanline_buffer = NULL; /* set this early for safe error exit */
+ state.report_error = filter_report_error; /* in case create fails */
+ if ((code = gs_jpeg_create_decompress(&state)) < 0)
+ goto fail; /* correct to do jpeg_destroy here */
+ /* Read parameters from dictionary */
+ if (r_has_type(op, t_dictionary))
+ npop = 1, dop = op, dspace = r_space(op);
+ else
+ npop = 0, dop = 0, dspace = 0;
+ if ((code = dict_param_list_read(&list, dop, NULL, false)) < 0)
+ goto fail;
+ if ((code = s_DCTD_put_params((gs_param_list *) & list, &state)) < 0)
+ goto rel;
+ /* Create the filter. */
+ jddp->template = s_DCTD_template;
+ code = filter_read(op, npop, &jddp->template,
+ (stream_state *) & state, dspace);
+ if (code >= 0) /* Success! */
+ return code;
+ /*
+ * We assume that if filter_read fails, the stream has not been
+ * registered for closing, so s_DCTD_release will never be called.
+ * Therefore we free the allocated memory before failing.
+ */
+rel:
+ iparam_list_release(&list);
+fail:
+ gs_jpeg_destroy(&state);
+ gs_free_object(mem, jddp, "zDCTD fail");
+ return code;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zfdctd_op_defs[] =
+{
+ op_def_begin_filter(),
+ {"2DCTDecode", zDCTD},
+ op_def_end(0)
+};
+#endif /* HAVE_LIBJPEG */
diff --git a/pstoraster/zfdcte.c b/pstoraster/zfdcte.c
new file mode 100644
index 000000000..a3084c0b0
--- /dev/null
+++ b/pstoraster/zfdcte.c
@@ -0,0 +1,157 @@
+/*
+ Copyright 1993-2002 by Easy Software Products.
+ Copyright 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.
+*/
+
+#include <config.h>
+#ifdef HAVE_LIBJPEG
+
+/*$Id$ */
+/* DCTEncode filter creation */
+#include "memory_.h"
+#include "stdio_.h" /* for jpeglib.h */
+#include "jpeglib.h"
+#include "ghost.h"
+#include "oper.h"
+#include "gsmalloc.h" /* for gs_memory_default */
+#include "ialloc.h"
+#include "idict.h"
+#include "idparam.h"
+#include "strimpl.h"
+#include "sdct.h"
+#include "sjpeg.h"
+#include "ifilter.h"
+#include "iparam.h"
+
+/*#define TEST*/
+
+/* Import the parameter processing procedure from sdeparam.c */
+stream_state_proc_put_params(s_DCTE_put_params, stream_DCT_state);
+#ifdef TEST
+stream_state_proc_get_params(s_DCTE_get_params, stream_DCT_state);
+#endif
+
+/* <target> <dict> DCTEncode/filter <file> */
+private int
+zDCTE(os_ptr op)
+{
+ gs_memory_t *mem = &gs_memory_default;
+ stream_DCT_state state;
+ dict_param_list list;
+ jpeg_compress_data *jcdp;
+ int code;
+ int npop;
+ const ref *dop;
+ uint dspace;
+
+ /* First allocate space for IJG parameters. */
+ jcdp = (jpeg_compress_data *)
+ gs_alloc_bytes_immovable(mem, sizeof(*jcdp), "zDCTE");
+ if (jcdp == 0)
+ return_error(e_VMerror);
+ if (s_DCTE_template.set_defaults)
+ (*s_DCTE_template.set_defaults) ((stream_state *) & state);
+ state.data.compress = jcdp;
+ jcdp->memory = state.jpeg_memory = mem; /* set now for allocation */
+ state.report_error = filter_report_error; /* in case create fails */
+ if ((code = gs_jpeg_create_compress(&state)) < 0)
+ goto fail; /* correct to do jpeg_destroy here */
+ /* Read parameters from dictionary */
+ if (r_has_type(op, t_dictionary))
+ npop = 1, dop = op, dspace = r_space(op);
+ else
+ npop = 0, dop = 0, dspace = 0;
+ if ((code = dict_param_list_read(&list, dop, NULL, false)) < 0)
+ goto fail;
+ if ((code = s_DCTE_put_params((gs_param_list *) & list, &state)) < 0)
+ goto rel;
+ /* Create the filter. */
+ jcdp->template = s_DCTE_template;
+ /* Make sure we get at least a full scan line of input. */
+ state.scan_line_size = jcdp->cinfo.input_components *
+ jcdp->cinfo.image_width;
+ jcdp->template.min_in_size =
+ max(s_DCTE_template.min_in_size, state.scan_line_size);
+ /* Make sure we can write the user markers in a single go. */
+ jcdp->template.min_out_size =
+ max(s_DCTE_template.min_out_size, state.Markers.size);
+ code = filter_write(op, npop, &jcdp->template,
+ (stream_state *) & state, dspace);
+ if (code >= 0) /* Success! */
+ return code;
+ /* We assume that if filter_write fails, the stream has not been
+ * registered for closing, so s_DCTE_release will never be called.
+ * Therefore we free the allocated memory before failing.
+ */
+rel:
+ iparam_list_release(&list);
+fail:
+ gs_jpeg_destroy(&state);
+ gs_free_object(mem, jcdp, "zDCTE fail");
+ return code;
+}
+
+#ifdef TEST
+#include "stream.h"
+#include "files.h"
+/* <dict> <filter> <bool> .dcteparams <dict> */
+private int
+zdcteparams(os_ptr op)
+{
+ stream *s;
+ dict_param_list list;
+ int code;
+
+ check_type(*op, t_boolean);
+ check_write_file(s, op - 1);
+ check_type(op[-2], t_dictionary);
+ /* The DCT filters copy the template.... */
+ if (s->state->template->process != s_DCTE_template.process)
+ return_error(e_rangecheck);
+ code = dict_param_list_write(&list, op - 2, NULL);
+ if (code < 0)
+ return code;
+ code = s_DCTE_get_params((gs_param_list *) & list,
+ (stream_DCT_state *) s->state,
+ op->value.boolval);
+ iparam_list_release(&list);
+ if (code >= 0)
+ pop(2);
+ return code;
+}
+#endif
+
+/* ------ Initialization procedure ------ */
+
+const op_def zfdcte_op_defs[] =
+{
+#ifdef TEST
+ {"3.dcteparams", zdcteparams},
+#endif
+ op_def_begin_filter(),
+ {"2DCTEncode", zDCTE},
+ op_def_end(0)
+};
+
+#endif /* HAVE_LIBJPEG */
diff --git a/pstoraster/zfdecode.c b/pstoraster/zfdecode.c
new file mode 100644
index 000000000..5baed631c
--- /dev/null
+++ b/pstoraster/zfdecode.c
@@ -0,0 +1,363 @@
+/* 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$ */
+/* Additional decoding filter creation */
+#include "memory_.h"
+#include "ghost.h"
+#include "oper.h"
+#include "gsparam.h"
+#include "gsstruct.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "idparam.h"
+#include "ilevel.h" /* for LL3 test */
+#include "iparam.h"
+#include "store.h"
+#include "stream.h" /* for setting is_temp */
+#include "strimpl.h"
+#include "sfilter.h"
+#include "sa85x.h"
+#include "scfx.h"
+#include "scf.h"
+#include "slzwx.h"
+#include "spdiffx.h"
+#include "spngpx.h"
+#include "ifilter.h"
+
+/* Import the Level 2 scanner extensions. */
+extern const stream_template *scan_ascii85_template;
+
+/* Initialize the Level 2 scanner for ASCII85 strings. */
+private void
+zfdecode_init(void)
+{
+ scan_ascii85_template = &s_A85D_template;
+}
+
+/* ------ ASCII85 filters ------ */
+
+/* We include both encoding and decoding filters here, */
+/* because it would be a nuisance to separate them. */
+
+/* <target> ASCII85Encode/filter <file> */
+/* <target> <dict> ASCII85Encode/filter <file> */
+private int
+zA85E(os_ptr op)
+{
+ return filter_write_simple(op, &s_A85E_template);
+}
+
+/* <source> ASCII85Decode/filter <file> */
+/* <source> <dict> ASCII85Decode/filter <file> */
+private int
+zA85D(os_ptr op)
+{
+ return filter_read_simple(op, &s_A85D_template);
+}
+
+/* ------ CCITTFaxDecode filter ------ */
+
+/* Common setup for encoding and decoding filters. */
+extern stream_state_proc_put_params(s_CF_put_params, stream_CF_state);
+int
+zcf_setup(os_ptr op, stream_CF_state * pcfs)
+{
+ dict_param_list list;
+ int code = dict_param_list_read(&list, op, NULL, false);
+
+ if (code < 0)
+ return code;
+ s_CF_set_defaults_inline(pcfs);
+ code = s_CF_put_params((gs_param_list *) & list, pcfs);
+ iparam_list_release(&list);
+ return code;
+}
+
+/* <source> <dict> CCITTFaxDecode/filter <file> */
+/* <source> CCITTFaxDecode/filter <file> */
+private int
+zCFD(os_ptr op)
+{
+ os_ptr dop;
+ stream_CFD_state cfs;
+ int code;
+
+ if (r_has_type(op, t_dictionary)) {
+ check_dict_read(*op);
+ dop = op;
+ } else
+ dop = 0;
+ code = zcf_setup(dop, (stream_CF_state *) & cfs);
+ if (code < 0)
+ return code;
+ return filter_read(op, 0, &s_CFD_template, (stream_state *) & cfs, 0);
+}
+
+/* ------ Common setup for possibly pixel-oriented decoding filters ------ */
+
+/* Forward declarations */
+int zpd_setup(P2(os_ptr op, stream_PDiff_state * ppds));
+int zpp_setup(P2(os_ptr op, stream_PNGP_state * ppps));
+
+int
+filter_read_predictor(os_ptr op, int npop, const stream_template * template,
+ stream_state * st)
+{
+ int predictor, code;
+ stream_PDiff_state pds;
+ stream_PNGP_state pps;
+
+ if (r_has_type(op, t_dictionary)) {
+ if ((code = dict_int_param(op, "Predictor", 0, 15, 1, &predictor)) < 0)
+ return code;
+ switch (predictor) {
+ case 0: /* identity */
+ predictor = 1;
+ case 1: /* identity */
+ break;
+ case 2: /* componentwise horizontal differencing */
+ code = zpd_setup(op, &pds);
+ break;
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ /* PNG prediction */
+ code = zpp_setup(op, &pps);
+ break;
+ default:
+ return_error(e_rangecheck);
+ }
+ if (code < 0)
+ return code;
+ } else
+ predictor = 1;
+ if (predictor == 1)
+ return filter_read(op, npop, template, st, 0);
+ {
+ /* We need to cascade filters. */
+ ref rsource, rdict, rfd;
+ int code;
+
+ /* Save the operands, just in case. */
+ ref_assign(&rsource, op - 1);
+ ref_assign(&rdict, op);
+ code = filter_read(op, 1, template, st, 0);
+ if (code < 0)
+ return code;
+ /* filter_read changed osp.... */
+ op = osp;
+ ref_assign(&rfd, op);
+ code =
+ (predictor == 2 ?
+ filter_read(op, 0, &s_PDiffD_template, (stream_state *) & pds, 0) :
+ filter_read(op, 0, &s_PNGPD_template, (stream_state *) & pps, 0));
+ if (code < 0) {
+ /* Restore the operands. Don't bother trying to clean up */
+ /* the first stream. */
+ osp = ++op;
+ ref_assign(op - 1, &rsource);
+ ref_assign(op, &rdict);
+ return code;
+ }
+ filter_mark_temp(&rfd, 2); /* Mark the decompression stream as temporary. */
+ return code;
+ }
+}
+
+/* ------ Generalized LZW/GIF decoding filter ------ */
+
+/* Common setup for encoding and decoding filters. */
+int
+zlz_setup(os_ptr op, stream_LZW_state * plzs)
+{
+ int code;
+ const ref *dop;
+
+ if (r_has_type(op, t_dictionary)) {
+ check_dict_read(*op);
+ dop = op;
+ } else
+ dop = 0;
+ if ( (code = dict_int_param(dop, "EarlyChange", 0, 1, 1,
+ &plzs->EarlyChange)) < 0 ||
+ /*
+ * The following are not PostScript standard, although
+ * LanguageLevel 3 provides the first two under different
+ * names.
+ */
+ (code = dict_int_param(dop, "InitialCodeLength", 2, 11, 8,
+ &plzs->InitialCodeLength)) < 0 ||
+ (code = dict_bool_param(dop, "FirstBitLowOrder", false,
+ &plzs->FirstBitLowOrder)) < 0 ||
+ (code = dict_bool_param(dop, "BlockData", false,
+ &plzs->BlockData)) < 0
+ )
+ return code;
+ return 0;
+}
+
+/* <source> LZWDecode/filter <file> */
+/* <source> <dict> LZWDecode/filter <file> */
+private int
+zLZWD(os_ptr op)
+{
+ stream_LZW_state lzs;
+ int code = zlz_setup(op, &lzs);
+
+ if (code < 0)
+ return code;
+ if (LL3_ENABLED && r_has_type(op, t_dictionary)) {
+ int unit_size;
+
+ if ((code = dict_bool_param(op, "LowBitFirst", lzs.FirstBitLowOrder,
+ &lzs.FirstBitLowOrder)) < 0 ||
+ (code = dict_int_param(op, "UnitSize", 3, 8, 8,
+ &unit_size)) < 0
+ )
+ return code;
+ if (code == 0 /* UnitSize specified */ )
+ lzs.InitialCodeLength = unit_size + 1;
+ }
+ return filter_read_predictor(op, 0, &s_LZWD_template,
+ (stream_state *) & lzs);
+}
+
+/* ------ Color differencing filters ------ */
+
+/* We include both encoding and decoding filters here, */
+/* because it would be a nuisance to separate them. */
+
+/* Common setup for encoding and decoding filters. */
+int
+zpd_setup(os_ptr op, stream_PDiff_state * ppds)
+{
+ int code, bpc;
+
+ check_type(*op, t_dictionary);
+ check_dict_read(*op);
+ if ((code = dict_int_param(op, "Colors", 1, 4, 1,
+ &ppds->Colors)) < 0 ||
+ (code = dict_int_param(op, "BitsPerComponent", 1, 8, 8,
+ &bpc)) < 0 ||
+ (bpc & (bpc - 1)) != 0 ||
+ (code = dict_int_param(op, "Columns", 1, max_int, 1,
+ &ppds->Columns)) < 0
+ )
+ return (code < 0 ? code : gs_note_error(e_rangecheck));
+ ppds->BitsPerComponent = bpc;
+ return 0;
+}
+
+/* <target> <dict> PixelDifferenceEncode/filter <file> */
+private int
+zPDiffE(os_ptr op)
+{
+ stream_PDiff_state pds;
+ int code = zpd_setup(op, &pds);
+
+ if (code < 0)
+ return code;
+ return filter_write(op, 0, &s_PDiffE_template, (stream_state *) & pds, 0);
+}
+
+/* <source> <dict> PixelDifferenceDecode/filter <file> */
+private int
+zPDiffD(os_ptr op)
+{
+ stream_PDiff_state pds;
+ int code = zpd_setup(op, &pds);
+
+ if (code < 0)
+ return code;
+ return filter_read(op, 0, &s_PDiffD_template, (stream_state *) & pds, 0);
+}
+
+/* ------ PNG pixel predictor filters ------ */
+
+/* Common setup for encoding and decoding filters. */
+int
+zpp_setup(os_ptr op, stream_PNGP_state * ppps)
+{
+ int code, bpc;
+
+ check_type(*op, t_dictionary);
+ check_dict_read(*op);
+ if ((code = dict_int_param(op, "Colors", 1, 16, 1,
+ &ppps->Colors)) < 0 ||
+ (code = dict_int_param(op, "BitsPerComponent", 1, 16, 8,
+ &bpc)) < 0 ||
+ (bpc & (bpc - 1)) != 0 ||
+ (code = dict_uint_param(op, "Columns", 1, max_uint, 1,
+ &ppps->Columns)) < 0 ||
+ (code = dict_int_param(op, "Predictor", 10, 15, 15,
+ &ppps->Predictor)) < 0
+ )
+ return (code < 0 ? code : gs_note_error(e_rangecheck));
+ ppps->BitsPerComponent = bpc;
+ return 0;
+}
+
+/* <target> <dict> PNGPredictorEncode/filter <file> */
+private int
+zPNGPE(os_ptr op)
+{
+ stream_PNGP_state pps;
+ int code = zpp_setup(op, &pps);
+
+ if (code < 0)
+ return code;
+ return filter_write(op, 0, &s_PNGPE_template, (stream_state *) & pps, 0);
+}
+
+/* <source> <dict> PNGPredictorDecode/filter <file> */
+private int
+zPNGPD(os_ptr op)
+{
+ stream_PNGP_state pps;
+ int code = zpp_setup(op, &pps);
+
+ if (code < 0)
+ return code;
+ return filter_read(op, 0, &s_PNGPD_template, (stream_state *) & pps, 0);
+}
+
+/* ---------------- Initialization procedure ---------------- */
+
+const op_def zfdecode_op_defs[] =
+{
+ op_def_begin_filter(),
+ {"1ASCII85Encode", zA85E},
+ {"1ASCII85Decode", zA85D},
+ {"2CCITTFaxDecode", zCFD},
+ {"1LZWDecode", zLZWD},
+ {"2PixelDifferenceDecode", zPDiffD},
+ {"2PixelDifferenceEncode", zPDiffE},
+ {"2PNGPredictorDecode", zPNGPD},
+ {"2PNGPredictorEncode", zPNGPE},
+ op_def_end(zfdecode_init)
+};
diff --git a/pstoraster/zfile.c b/pstoraster/zfile.c
new file mode 100644
index 000000000..640d59a00
--- /dev/null
+++ b/pstoraster/zfile.c
@@ -0,0 +1,915 @@
+/* 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$ */
+/* Non-I/O file operators */
+#include "memory_.h"
+#include "string_.h"
+#include "ghost.h"
+#include "gscdefs.h" /* for gx_io_device_table */
+#include "gp.h"
+#include "gsstruct.h" /* for registering root */
+#include "gxalloc.h" /* for streams */
+#include "oper.h"
+#include "estack.h" /* for filenameforall, .execfile */
+#include "ialloc.h"
+#include "ilevel.h" /* %names only work in Level 2 */
+#include "interp.h" /* gs_errorinfo_put_string prototype */
+#include "isave.h" /* for restore */
+#include "iutil.h"
+#include "stream.h"
+#include "strimpl.h"
+#include "sfilter.h"
+#include "gxiodev.h" /* must come after stream.h */
+ /* and before files.h */
+#include "files.h" /* ditto */
+#include "fname.h" /* ditto */
+#include "main.h" /* for gs_lib_paths */
+#include "store.h"
+
+/* Import the file_open routine for %os%, which is the default. */
+extern iodev_proc_open_file(iodev_os_open_file);
+
+/* Import the IODevice table. */
+extern_gx_io_device_table();
+
+/* Forward references: file opening. */
+int file_open(P6(const byte *, uint, const char *, uint, ref *, stream **));
+
+/* Forward references: other. */
+private int execfile_finish(P1(os_ptr));
+private int execfile_cleanup(P1(os_ptr));
+
+/*
+ * Since there can be many file objects referring to the same file/stream,
+ * we can't simply free a stream when we close it. On the other hand,
+ * we don't want freed streams to clutter up memory needlessly.
+ * Our solution is to retain the freed streams, and reuse them.
+ * To prevent an old file object from being able to access a reused stream,
+ * we keep a serial number in each stream, and check it against a serial
+ * number stored in the file object (as the "size"); when we close a file,
+ * we increment its serial number. If the serial number ever overflows,
+ * we leave it at zero, and do not reuse the stream.
+ * (This will never happen.)
+ *
+ * Storage management for this scheme is a little tricky. We maintain an
+ * invariant that says that a stream opened at a given save level always
+ * uses a stream structure allocated at that level. By doing this, we don't
+ * need to keep track separately of streams open at a level vs. streams
+ * allocated at a level. To make this interact properly with save and
+ * restore, we maintain a list of all streams allocated at this level, both
+ * open and closed. We store this list in the allocator: this is a hack,
+ * but it simplifies bookkeeping (in particular, it guarantees the list is
+ * restored properly by a restore).
+ *
+ * We want to close streams freed by restore and by garbage collection. We
+ * use the finalization procedure for this. For restore, we don't have to
+ * do anything special to make this happen. For garbage collection, we do
+ * something more drastic: we simply clear the list of known streams (at all
+ * save levels). Any streams open at the time of garbage collection will no
+ * longer participate in the list of known streams, but this does no harm;
+ * it simply means that they won't get reused, and can only be reclaimed by
+ * a future garbage collection or restore.
+ */
+
+/*
+ * Define the default stream buffer sizes. For file streams,
+ * this is arbitrary, since the C library or operating system
+ * does its own buffering in addition.
+ * However, the buffer size for eexec decoding is NOT arbitrary:
+ * it must be at most 512.
+ */
+#define DEFAULT_BUFFER_SIZE 512
+const uint file_default_buffer_size = DEFAULT_BUFFER_SIZE;
+
+/* An invalid file object */
+stream *invalid_file_entry; /* exported for zfileio.c */
+
+/* Initialize the file table */
+private void
+zfile_init(void)
+{
+ /* Create and initialize an invalid (closed) stream. */
+ /* Initialize the stream for the sake of the GC, */
+ /* and so it can act as an empty input stream. */
+
+ stream *s = s_alloc(imemory_system, "zfile_init");
+
+ sread_string(s, NULL, 0);
+ s->next = s->prev = 0;
+ s_init_no_id(s);
+ invalid_file_entry = s;
+ gs_register_struct_root(imemory, NULL, (void **)&invalid_file_entry,
+ "invalid_file_entry");
+}
+
+/* Make an invalid file object. */
+void
+make_invalid_file(ref * fp)
+{
+ make_file(fp, avm_system, ~0, invalid_file_entry);
+}
+
+/* <name_string> <access_string> file <file> */
+int
+zfile(register os_ptr op)
+{
+ char file_access[3];
+ parsed_file_name pname;
+ const byte *astr;
+ int code;
+ stream *s;
+
+ check_read_type(*op, t_string);
+ astr = op->value.const_bytes;
+ switch (r_size(op)) {
+ case 2:
+ if (astr[1] != '+')
+ return_error(e_invalidfileaccess);
+ file_access[1] = '+';
+ file_access[2] = 0;
+ break;
+ case 1:
+ file_access[1] = 0;
+ break;
+ default:
+ return_error(e_invalidfileaccess);
+ }
+ switch (astr[0]) {
+ case 'r':
+ case 'w':
+ case 'a':
+ break;
+ default:
+ return_error(e_invalidfileaccess);
+ }
+ file_access[0] = astr[0];
+ code = parse_file_name(op - 1, &pname);
+ if (code < 0)
+ return code;
+ if (pname.iodev == NULL)
+ pname.iodev = iodev_default;
+ if (pname.fname == NULL) /* just a device */
+ code = (*pname.iodev->procs.open_device)(pname.iodev,
+ file_access, &s, imemory);
+ else { /* file */
+ iodev_proc_open_file((*open_file)) =
+ pname.iodev->procs.open_file;
+ if (open_file == 0)
+ open_file = iodev_os_open_file;
+ code = (*open_file)(pname.iodev, pname.fname, pname.len,
+ file_access, &s, imemory);
+ }
+ if (code < 0)
+ return code;
+ make_stream_file(op - 1, s, file_access);
+ pop(1);
+ return code;
+}
+
+/* ------ Level 2 extensions ------ */
+
+/* <string> deletefile - */
+private int
+zdeletefile(register os_ptr op)
+{
+ parsed_file_name pname;
+ int code = parse_real_file_name(op, &pname, "deletefile");
+
+ if (code < 0)
+ return code;
+ code = (*pname.iodev->procs.delete_file)(pname.iodev, pname.fname);
+ free_file_name(&pname, "deletefile");
+ if (code < 0)
+ return code;
+ pop(1);
+ return 0;
+}
+
+/* <template> <proc> <scratch> filenameforall - */
+/****** NOT CONVERTED FOR IODEVICES YET ******/
+private int file_continue(P1(os_ptr));
+private int file_cleanup(P1(os_ptr));
+private int
+zfilenameforall(register os_ptr op)
+{
+ file_enum *pfen;
+ int code;
+
+ check_write_type(*op, t_string);
+ check_proc(op[-1]);
+ check_read_type(op[-2], t_string);
+ /* Push a mark, the pattern, the scratch string, the enumerator, */
+ /* and the procedure, and invoke the continuation. */
+ check_estack(7);
+ pfen = gp_enumerate_files_init((char *)op[-2].value.bytes, r_size(op - 2), imemory);
+ if (pfen == 0)
+ return_error(e_VMerror);
+ push_mark_estack(es_for, file_cleanup);
+ *++esp = op[-2];
+ *++esp = *op;
+ ++esp;
+ make_istruct(esp, 0, pfen);
+ *++esp = op[-1];
+ pop(3);
+ op -= 3;
+ code = file_continue(op);
+ return (code == o_pop_estack ? o_push_estack : code);
+}
+/* Continuation operator for enumerating files */
+private int
+file_continue(register os_ptr op)
+{
+ es_ptr pscratch = esp - 2;
+ file_enum *pfen = r_ptr(esp - 1, file_enum);
+ uint len = r_size(pscratch);
+ uint code =
+ gp_enumerate_files_next(pfen, (char *)pscratch->value.bytes, len);
+
+ if (code == ~(uint) 0) { /* all done */
+ esp -= 4; /* pop proc, pfen, scratch, mark */
+ return o_pop_estack;
+ } else if (code > len) /* overran string */
+ return_error(e_rangecheck);
+ else {
+ push(1);
+ ref_assign(op, pscratch);
+ r_set_size(op, code);
+ push_op_estack(file_continue); /* come again */
+ *++esp = pscratch[2]; /* proc */
+ return o_push_estack;
+ }
+}
+/* Cleanup procedure for enumerating files */
+private int
+file_cleanup(os_ptr op)
+{
+ gp_enumerate_files_close(r_ptr(esp + 4, file_enum));
+ return 0;
+}
+
+/* <string1> <string2> renamefile - */
+private int
+zrenamefile(register os_ptr op)
+{
+ parsed_file_name pname1, pname2;
+ int code = parse_real_file_name(op - 1, &pname1, "renamefile(from)");
+
+ if (code < 0)
+ return code;
+ pname2.fname = 0;
+ code = parse_real_file_name(op, &pname2, "renamefile(to)");
+ if (code < 0 || pname1.iodev != pname2.iodev ||
+ (code = (*pname1.iodev->procs.rename_file)(pname1.iodev,
+ pname1.fname, pname2.fname)) < 0
+ ) {
+ if (code >= 0)
+ code = gs_note_error(e_invalidfileaccess);
+ }
+ free_file_name(&pname2, "renamefile(to)");
+ free_file_name(&pname1, "renamefile(from)");
+ if (code < 0)
+ return code;
+ pop(2);
+ return 0;
+}
+
+/* <file> status <open_bool> */
+/* <string> status <pages> <bytes> <ref_time> <creation_time> true */
+/* <string> status false */
+private int
+zstatus(register os_ptr op)
+{
+ switch (r_type(op)) {
+ case t_file:
+ {
+ stream *s;
+
+ make_bool(op, (file_is_valid(s, op) ? 1 : 0));
+ }
+ return 0;
+ case t_string:
+ {
+ parsed_file_name pname;
+ struct stat fstat;
+ int code = parse_file_name(op, &pname);
+
+ if (code < 0)
+ return code;
+ code = terminate_file_name(&pname, "status");
+ if (code < 0)
+ return code;
+ code = (*pname.iodev->procs.file_status)(pname.iodev,
+ pname.fname, &fstat);
+ switch (code) {
+ case 0:
+ check_ostack(4);
+ /*
+ * Check to make sure that the file size fits into
+ * a PostScript integer. (On some systems, long is
+ * 32 bits, but file sizes are 64 bits.)
+ */
+ push(4);
+ make_int(op - 4, stat_blocks(&fstat));
+ make_int(op - 3, fstat.st_size);
+ /*
+ * We can't check the value simply by using ==,
+ * because signed/unsigned == does the wrong thing.
+ * Instead, since integer assignment only keeps the
+ * bottom bits, we convert the values to double
+ * and then test for equality. This handles all
+ * cases of signed/unsigned or width mismatch.
+ */
+ if ((double)op[-4].value.intval !=
+ (double)stat_blocks(&fstat) ||
+ (double)op[-3].value.intval !=
+ (double)fstat.st_size
+ )
+ return_error(e_limitcheck);
+ make_int(op - 2, fstat.st_mtime);
+ make_int(op - 1, fstat.st_ctime);
+ make_bool(op, 1);
+ break;
+ case e_undefinedfilename:
+ make_bool(op, 0);
+ code = 0;
+ }
+ free_file_name(&pname, "status");
+ return code;
+ }
+ default:
+ return_op_typecheck(op);
+ }
+}
+
+/* ------ Non-standard extensions ------ */
+
+/* <executable_file> .execfile - */
+private int
+zexecfile(register os_ptr op)
+{
+ check_type_access(*op, t_file, a_executable | a_read | a_execute);
+ check_estack(4); /* cleanup, file, finish, file */
+ push_mark_estack(es_other, execfile_cleanup);
+ *++esp = *op;
+ push_op_estack(execfile_finish);
+ return zexec(op);
+}
+/* Finish normally. */
+private int
+execfile_finish(os_ptr op)
+{
+ check_ostack(1);
+ esp -= 2;
+ execfile_cleanup(op);
+ return o_pop_estack;
+}
+/* Clean up by closing the file. */
+private int
+execfile_cleanup(os_ptr op)
+{
+ check_ostack(1);
+ *++osp = esp[2];
+ return zclosefile(osp);
+}
+
+/* <dir> <name> .filenamedirseparator <string> */
+int
+zfilenamedirseparator(os_ptr op)
+{
+ const char *sepr;
+
+ check_read_type(*op, t_string);
+ check_read_type(op[-1], t_string);
+ sepr =
+ gp_file_name_concat_string((const char *)op[-1].value.const_bytes,
+ r_size(op - 1),
+ (const char *)op->value.const_bytes,
+ r_size(op));
+ make_const_string(op - 1, avm_foreign | a_readonly,
+ strlen(sepr), (const byte *)sepr);
+ pop(1);
+ return 0;
+}
+
+/* - .filenamelistseparator <string> */
+int
+zfilenamelistseparator(os_ptr op)
+{
+ push(1);
+ make_const_string(op, avm_foreign | a_readonly, 1,
+ (const byte *)&gp_file_name_list_separator);
+ return 0;
+}
+
+/* <name> .filenamesplit <dir> <base> <extension> */
+int
+zfilenamesplit(os_ptr op)
+{
+ check_read_type(*op, t_string);
+/****** NOT IMPLEMENTED YET ******/
+ return_error(e_undefined);
+}
+
+/* <string> findlibfile <found_string> <file> true */
+/* <string> findlibfile <string> false */
+int
+zfindlibfile(register os_ptr op)
+{
+ int code;
+
+#define MAX_CNAME 200
+ byte cname[MAX_CNAME];
+ uint clen;
+ parsed_file_name pname;
+ stream *s;
+
+ check_ostack(2);
+ code = parse_file_name(op, &pname);
+ if (code < 0)
+ return code;
+ if (pname.iodev == NULL)
+ pname.iodev = iodev_default;
+ if (pname.iodev != iodev_default) { /* Non-OS devices don't have search paths (yet). */
+ code =
+ (pname.fname == NULL ?
+ (*pname.iodev->procs.open_device)(pname.iodev, "r",
+ &s, imemory) :
+ (*pname.iodev->procs.open_file)(pname.iodev,
+ pname.fname, pname.len, "r",
+ &s, imemory));
+ if (code < 0) {
+ push(1);
+ make_false(op);
+ return 0;
+ }
+ make_stream_file(op + 1, s, "r");
+ } else {
+ byte *cstr;
+
+ code = lib_file_open(pname.fname, pname.len, cname, MAX_CNAME,
+ &clen, op + 1);
+ if (code == e_VMerror)
+ return code;
+ if (code < 0) {
+ push(1);
+ make_false(op);
+ return 0;
+ }
+ cstr = ialloc_string(clen, "findlibfile");
+ if (cstr == 0)
+ return_error(e_VMerror);
+ memcpy(cstr, cname, clen);
+ make_string(op, a_all | icurrent_space, clen, cstr);
+ }
+ push(2);
+ make_true(op);
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zfile_op_defs[] =
+{
+ {"1deletefile", zdeletefile},
+ {"1.execfile", zexecfile},
+ {"2file", zfile},
+ {"3filenameforall", zfilenameforall},
+ {"2.filenamedirseparator", zfilenamedirseparator},
+ {"0.filenamelistseparator", zfilenamelistseparator},
+ {"1.filenamesplit", zfilenamesplit},
+ {"1findlibfile", zfindlibfile},
+ {"2renamefile", zrenamefile},
+ {"1status", zstatus},
+ /* Internal operators */
+ {"0%file_continue", file_continue},
+ {"0%execfile_finish", execfile_finish},
+ op_def_end(zfile_init)
+};
+
+/* ------ Stream opening ------ */
+
+/* Make a t_file reference to a stream. */
+void
+make_stream_file(ref * pfile, stream * s, const char *access)
+{
+ uint attrs =
+ (access[1] == '+' ? a_write + a_read + a_execute : 0) |
+ imemory_space((gs_ref_memory_t *) s->memory);
+
+ if (access[0] == 'r') {
+ make_file(pfile, attrs | (a_read | a_execute), s->read_id, s);
+ s->write_id = 0;
+ } else {
+ make_file(pfile, attrs | a_write, s->write_id, s);
+ s->read_id = 0;
+ }
+}
+
+/* Open an OS-level file (like fopen), using the search paths if necessary. */
+/* Note that it does not automatically look in the current */
+/* directory first (or at all): this is like Unix, and unlike MS-DOS. */
+private int
+lib_file_fopen(gx_io_device * iodev, const char *bname,
+ const char *ignore_access, FILE ** pfile,
+ char *rfname, uint rnamelen)
+{
+ char fmode[3]; /* r, [b], null */
+ int len = strlen(bname);
+ const gs_file_path *pfpath = &gs_lib_path;
+ uint pi;
+
+ strcpy(fmode, "r");
+ strcat(fmode, gp_fmode_binary_suffix);
+ if (gp_file_name_is_absolute(bname, len))
+ return (*iodev->procs.fopen)(iodev, bname, fmode, pfile,
+ rfname, rnamelen);
+ /* Go through the list of search paths */
+ for (pi = 0; pi < r_size(&pfpath->list); ++pi) {
+ const ref *prdir = pfpath->list.value.refs + pi;
+ const char *pstr = (const char *)prdir->value.const_bytes;
+ uint plen = r_size(prdir);
+ const char *cstr =
+ gp_file_name_concat_string(pstr, plen, bname, len);
+ int up, i;
+ int code;
+
+ /* Concatenate the prefix, combiner, and file name. */
+ /* Do this carefully in case rfname is the same */
+ /* as fname. (We don't worry about the case */
+ /* where rfname only overlaps fname.) */
+ up = plen + strlen(cstr);
+ if (up + len + 1 > rnamelen)
+ return_error(e_limitcheck);
+ for (i = len + 1; --i >= 0;)
+ rfname[i + up] = bname[i];
+ memcpy(rfname, pstr, plen);
+ memcpy(rfname + plen, cstr, strlen(cstr));
+ code = (*iodev->procs.fopen)(iodev, rfname, fmode,
+ pfile, rfname, rnamelen);
+ if (code >= 0)
+ return code;
+ /* strcpy isn't guaranteed to work for overlapping */
+ /* source and destination, so: */
+ if (rfname == bname)
+ for (i = 0; (rfname[i] = rfname[i + up]) != 0; i++);
+ }
+ return_error(e_undefinedfilename);
+}
+/* The startup code calls this to open @-files. */
+FILE *
+lib_fopen(const char *bname)
+{
+ FILE *file = NULL;
+ /* We need a buffer to hold the expanded file name. */
+ char buffer[gp_file_name_sizeof];
+ /* We can't count on the IODevice table to have been initialized yet. */
+ /* Allocate a copy of the default IODevice. */
+ gx_io_device iodev_default_copy;
+ int code;
+
+ iodev_default_copy = *gx_io_device_table[0];
+ code = lib_file_fopen(&iodev_default_copy, bname, "r", &file,
+ buffer, gp_file_name_sizeof);
+ return (code < 0 ? NULL : file);
+}
+
+/* Open a file stream on an OS file and create a file object, */
+/* using the search paths. */
+/* The startup code calls this to open the initialization file gs_init.ps. */
+int
+lib_file_open(const char *fname, uint len, byte * cname, uint max_clen,
+ uint * pclen, ref * pfile)
+{
+ stream *s;
+ int code = file_open_stream(fname, len, "r",
+ file_default_buffer_size, &s, lib_file_fopen);
+ char *bname;
+ uint blen;
+
+ if (code < 0)
+ return code;
+ /* Get the name from the stream buffer. */
+ bname = (char *)s->cbuf;
+ blen = strlen(bname);
+ if (blen > max_clen) {
+ sclose(s);
+ return_error(e_limitcheck);
+ }
+ memcpy(cname, bname, blen);
+ *pclen = blen;
+ make_stream_file(pfile, s, "r");
+ return 0;
+}
+
+/* Open a file stream that reads a string. */
+/* (This is currently used only by the ccinit feature.) */
+/* The string must be allocated in non-garbage-collectable (foreign) space. */
+int
+file_read_string(const byte * str, uint len, ref * pfile)
+{
+ stream *s = file_alloc_stream(imemory, "file_read_string");
+ int space;
+
+ if (s == 0)
+ return_error(e_VMerror);
+ space = icurrent_space;
+ sread_string(s, str, len);
+ s->foreign = 1;
+ s->write_id = 0;
+ make_file(pfile, a_readonly | space, s->read_id, s);
+ s->save_close = s->procs.close;
+ s->procs.close = file_close_disable;
+ return 0;
+}
+
+/* Open a file stream, optionally on an OS file. */
+/* Return 0 if successful, error code if not. */
+/* On a successful return, the C file name is in the stream buffer. */
+/* If fname==0, set up the file entry, stream, and buffer, */
+/* but don't open an OS file or initialize the stream. */
+int
+file_open_stream(const char *fname, uint len, const char *file_access,
+ uint buffer_size, stream ** ps, iodev_proc_fopen_t fopen_proc)
+{
+ byte *buffer;
+ register stream *s;
+
+ if (buffer_size == 0)
+ buffer_size = file_default_buffer_size;
+ if (len >= buffer_size) /* we copy the file name into the buffer */
+ return_error(e_limitcheck);
+ /* Allocate the stream first, since it persists */
+ /* even after the file has been closed. */
+ s = file_alloc_stream(imemory, "file_open_stream");
+ if (s == 0)
+ return_error(e_VMerror);
+ /* Allocate the buffer. */
+ buffer = ialloc_bytes(buffer_size, "file_open(buffer)");
+ if (buffer == 0)
+ return_error(e_VMerror);
+ if (fname != 0) {
+ /* Copy the name (so we can terminate it with a zero byte.) */
+ char *file_name = (char *)buffer;
+ char fmode[4]; /* r/w/a, [+], [b], null */
+ FILE *file;
+ int code;
+
+ memcpy(file_name, fname, len);
+ file_name[len] = 0; /* terminate string */
+ /* Open the file, always in binary mode. */
+ strcpy(fmode, file_access);
+ strcat(fmode, gp_fmode_binary_suffix);
+ /****** iodev_default IS QUESTIONABLE ******/
+ code = (*fopen_proc)(iodev_default, file_name, fmode, &file,
+ (char *)buffer, buffer_size);
+ if (code < 0) {
+ ifree_object(buffer, "file_open(buffer)");
+ return code;
+ }
+ /* Set up the stream. */
+ switch (fmode[0]) {
+ case 'a':
+ sappend_file(s, file, buffer, buffer_size);
+ break;
+ case 'r':
+ sread_file(s, file, buffer, buffer_size);
+ break;
+ case 'w':
+ swrite_file(s, file, buffer, buffer_size);
+ }
+ if (fmode[1] == '+')
+ s->file_modes |= s_mode_read | s_mode_write;
+ s->save_close = s->procs.close;
+ s->procs.close = file_close_file;
+ } else { /* save the buffer and size */
+ s->cbuf = buffer;
+ s->bsize = s->cbsize = buffer_size;
+ }
+ *ps = s;
+ return 0;
+}
+
+/* Report an error by storing it in $error.errorinfo. */
+int
+filter_report_error(stream_state * st, const char *str)
+{
+ if_debug1('s', "[s]stream error: %s\n", str);
+ return gs_errorinfo_put_string(str);
+}
+
+/* Open a file stream for a filter. */
+int
+filter_open(const char *file_access, uint buffer_size, ref * pfile,
+ const stream_procs * procs, const stream_template * template,
+ const stream_state * st)
+{
+ stream *s;
+ uint ssize = gs_struct_type_size(template->stype);
+ stream_state *sst = 0;
+ int code;
+
+ if (template->stype != &st_stream_state) {
+ sst = s_alloc_state(imemory, template->stype,
+ "filter_open(stream_state)");
+ if (sst == 0)
+ return_error(e_VMerror);
+ }
+ code = file_open_stream((char *)0, 0, file_access,
+ buffer_size, &s, (iodev_proc_fopen_t) 0);
+ if (code < 0) {
+ ifree_object(sst, "filter_open(stream_state)");
+ return code;
+ }
+ s_std_init(s, s->cbuf, s->bsize, procs,
+ (*file_access == 'r' ? s_mode_read : s_mode_write));
+ s->procs.process = template->process;
+ s->save_close = s->procs.close;
+ s->procs.close = file_close_file;
+ if (sst == 0) {
+ /* This stream doesn't have any state of its own. */
+ /* Hack: use the stream itself as the state. */
+ sst = (stream_state *) s;
+ } else if (st != 0) /* might not have client parameters */
+ memcpy(sst, st, ssize);
+ s->state = sst;
+ sst->template = template;
+ sst->memory = imemory;
+ sst->report_error = filter_report_error;
+ if (template->init != 0) {
+ code = (*template->init)(sst);
+ if (code < 0) {
+ ifree_object(sst, "filter_open(stream_state)");
+ ifree_object(s->cbuf, "filter_open(buffer)");
+ return code;
+ }
+ }
+ make_stream_file(pfile, s, file_access);
+ return 0;
+}
+
+/* Allocate and return a file stream. */
+/* Return 0 if the allocation failed. */
+/* The stream is initialized to an invalid state, so the caller need not */
+/* worry about cleaning up if a later step in opening the stream fails. */
+stream *
+file_alloc_stream(gs_memory_t * mem, client_name_t cname)
+{
+ stream *s;
+ gs_ref_memory_t *imem = 0;
+
+ /*
+ * HACK: Figure out whether this is a gs_ref_memory_t we know
+ * about. Avoiding this hack would require rippling a change
+ * from gs_memory_t to gs_ref_memory_t into the open_file and
+ * open_device procedures of gx_io_device, which in turn would
+ * impact other things we don't want to change.
+ */
+ {
+ int i;
+
+ for (i = 0; i < countof(gs_imemory.spaces.indexed); ++i)
+ if (mem == (gs_memory_t *) gs_imemory.spaces.indexed[i]) {
+ imem = (gs_ref_memory_t *) mem;
+ break;
+ }
+ }
+
+ if (imem) {
+ /* Look first for a free stream allocated at this level. */
+ s = imem->streams;
+ while (s != 0) {
+ if (!s_is_valid(s) && s->read_id != 0 /* i.e. !overflowed */ ) {
+ s->is_temp = 0; /* not a temp stream */
+ return s;
+ }
+ s = s->next;
+ }
+ }
+ s = s_alloc(mem, cname);
+ if (s == 0)
+ return 0;
+ s_init_ids(s);
+ s->is_temp = 0; /* not a temp stream */
+ /*
+ * Disable the stream now (in case we can't open the file,
+ * or a filter init procedure fails) so that `restore' won't
+ * crash when it tries to close open files.
+ */
+ s_disable(s);
+ if (imem) {
+ /* Add s to the list of files. */
+ if (imem->streams != 0)
+ imem->streams->prev = s;
+ s->next = imem->streams;
+ imem->streams = s;
+ } else {
+ s->next = 0;
+ }
+ s->prev = 0;
+ return s;
+}
+
+/* ------ Stream closing ------ */
+
+/*
+ * Finish closing a file stream. This used to check whether it was
+ * currentfile, but we don't have to do this any longer. This replaces the
+ * close procedure for the std* streams, which cannot actually be closed.
+ *
+ * This is exported for ziodev.c. */
+int
+file_close_finish(stream * s)
+{
+ return 0;
+}
+
+/*
+ * Close a file stream, but don't deallocate the buffer. This replaces the
+ * close procedure for %lineedit and %statementedit. (This is WRONG: these
+ * streams should allocate a new buffer each time they are opened, but that
+ * would overstress the allocator right now.) This is exported for ziodev.c.
+ * This also replaces the close procedure for the string-reading stream
+ * created for gs_run_string.
+ */
+int
+file_close_disable(stream * s)
+{
+ int code = (*s->save_close)(s);
+
+ if (code)
+ return code;
+ /* Increment the IDs to prevent further access. */
+ s->read_id = s->write_id = (s->read_id | s->write_id) + 1;
+ return file_close_finish(s);
+}
+
+/* Close a file stream. This replaces the close procedure in the stream */
+/* for normal (OS) files and for filters. */
+int
+file_close_file(stream * s)
+{
+ stream *stemp = s->strm;
+ gs_memory_t *mem;
+ int code = file_close_disable(s);
+
+ if (code)
+ return code;
+ /*
+ * Check for temporary streams created for filters.
+ * There may be more than one in the case of a procedure-based filter,
+ * or if we created an intermediate stream to ensure
+ * a large enough buffer. Note that these streams may have been
+ * allocated by file_alloc_stream, so we mustn't free them.
+ */
+ while (stemp != 0 && stemp->is_temp != 0) {
+ stream *snext = stemp->strm;
+
+ mem = stemp->memory;
+ if (stemp->is_temp > 1)
+ gs_free_object(mem, stemp->cbuf,
+ "file_close(temp stream buffer)");
+ s_disable(stemp);
+ stemp = snext;
+ }
+ mem = s->memory;
+ gs_free_object(mem, s->cbuf, "file_close(buffer)");
+ if (s->close_strm && stemp != 0)
+ return sclose(stemp);
+ return 0;
+}
+
+/* Close a file object. */
+/* This is exported only for gsmain.c. */
+int
+file_close(ref * pfile)
+{
+ stream *s;
+
+ if (file_is_valid(s, pfile)) { /* closing a closed file is a no-op */
+ if (sclose(s))
+ return_error(e_ioerror);
+ }
+ return 0;
+}
diff --git a/pstoraster/zfileio.c b/pstoraster/zfileio.c
new file mode 100644
index 000000000..ba95faa7a
--- /dev/null
+++ b/pstoraster/zfileio.c
@@ -0,0 +1,842 @@
+/* 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$ */
+/* File I/O operators */
+#include "ghost.h"
+#include "gp.h"
+#include "oper.h"
+#include "stream.h"
+#include "files.h"
+#include "store.h"
+#include "strimpl.h" /* for ifilter.h */
+#include "ifilter.h" /* for procedure streams */
+#include "gsmatrix.h" /* for gxdevice.h */
+#include "gxdevice.h"
+#include "gxdevmem.h"
+
+/* Forward references */
+private int write_string(P2(ref *, stream *));
+private int handle_read_status(P4(int, const ref *, const uint *,
+ int (*)(P1(os_ptr))));
+private int handle_write_status(P4(int, const ref *, const uint *,
+ int (*)(P1(os_ptr))));
+
+/* ------ Operators ------ */
+
+/* <file> closefile - */
+int
+zclosefile(register os_ptr op)
+{
+ stream *s;
+
+ check_type(*op, t_file);
+ if (file_is_valid(s, op)) { /* closing a closed file is a no-op */
+ int status = sclose(s);
+
+ if (status != 0) {
+ if (s_is_writing(s))
+ return handle_write_status(status, op, NULL, zclosefile);
+ else
+ return handle_read_status(status, op, NULL, zclosefile);
+ }
+ }
+ pop(1);
+ return 0;
+}
+
+/* <file> read <int> -true- */
+/* <file> read -false- */
+private int
+zread(register os_ptr op)
+{
+ stream *s;
+ int ch;
+
+ check_read_file(s, op);
+ ch = sgetc(s);
+ if (ch >= 0) {
+ push(1);
+ make_int(op - 1, ch);
+ make_bool(op, 1);
+ } else if (ch == EOFC)
+ make_bool(op, 0);
+ else
+ return handle_read_status(ch, op, NULL, zread);
+ return 0;
+}
+
+/* <file> <int> write - */
+int
+zwrite(register os_ptr op)
+{
+ stream *s;
+ byte ch;
+ int status;
+
+ check_write_file(s, op - 1);
+ check_type(*op, t_integer);
+ ch = (byte) op->value.intval;
+ status = sputc(s, (byte) ch);
+ if (status >= 0) {
+ pop(2);
+ return 0;
+ }
+ return handle_write_status(status, op - 1, NULL, zwrite);
+}
+
+/* <file> <string> readhexstring <substring> <filled_bool> */
+private int zreadhexstring_continue(P1(os_ptr));
+
+/* We keep track of the odd digit in the next byte of the string */
+/* beyond the bytes already used. (This is just for convenience; */
+/* we could do the same thing by passing 2 state parameters to the */
+/* continuation procedure instead of 1.) */
+private int
+zreadhexstring_at(register os_ptr op, uint start)
+{
+ stream *s;
+ uint len, nread;
+ byte *str;
+ int odd;
+ stream_cursor_write cw;
+ int status;
+
+ check_read_file(s, op - 1);
+ /*check_write_type(*op, t_string); *//* done by caller */
+ str = op->value.bytes;
+ len = r_size(op);
+ if (start < len) {
+ odd = str[start];
+ if (odd > 0xf)
+ odd = -1;
+ } else
+ odd = -1;
+ cw.ptr = str + start - 1;
+ cw.limit = str + len - 1;
+ for (;;) {
+ status = s_hex_process(&s->cursor.r, &cw, &odd,
+ hex_ignore_garbage);
+ if (status == 1) { /* filled the string */
+ ref_assign_inline(op - 1, op);
+ make_true(op);
+ return 0;
+ } else if (status != 0) /* error or EOF */
+ break;
+ /* Didn't fill, keep going. */
+ status = spgetc(s);
+ if (status < 0)
+ break;
+ sputback(s);
+ }
+ nread = cw.ptr + 1 - str;
+ if (status != EOFC) { /* Error */
+ if (nread < len)
+ str[nread] = (odd < 0 ? 0x10 : odd);
+ return handle_read_status(status, op - 1, &nread,
+ zreadhexstring_continue);
+ }
+ /* Reached end-of-file before filling the string. */
+ /* Return an appropriate substring. */
+ ref_assign_inline(op - 1, op);
+ r_set_size(op - 1, nread);
+ make_false(op);
+ return 0;
+}
+private int
+zreadhexstring(os_ptr op)
+{
+ check_write_type(*op, t_string);
+ if (r_size(op) > 0)
+ *op->value.bytes = 0x10;
+ return zreadhexstring_at(op, 0);
+}
+/* Continue a readhexstring operation after a callout. */
+/* *op is the index within the string. */
+private int
+zreadhexstring_continue(register os_ptr op)
+{
+ int code;
+
+ check_type(*op, t_integer);
+ if (op->value.intval < 0 || op->value.intval > r_size(op - 1))
+ return_error(e_rangecheck);
+ check_write_type(op[-1], t_string);
+ code = zreadhexstring_at(op - 1, (uint) op->value.intval);
+ if (code >= 0)
+ pop(1);
+ return code;
+}
+
+/* <file> <string> writehexstring - */
+private int zwritehexstring_continue(P1(os_ptr));
+private int
+zwritehexstring_at(register os_ptr op, uint odd)
+{
+ register stream *s;
+ register byte ch;
+ register const byte *p;
+ register const char *const hex_digits = "0123456789abcdef";
+ register uint len;
+ int status;
+
+#define MAX_HEX 128
+ byte buf[MAX_HEX];
+
+ check_write_file(s, op - 1);
+ check_read_type(*op, t_string);
+ p = op->value.bytes;
+ len = r_size(op);
+ while (len) {
+ uint len1 = min(len, MAX_HEX / 2);
+ register byte *q = buf;
+ uint count = len1;
+ ref rbuf;
+
+ do {
+ ch = *p++;
+ *q++ = hex_digits[ch >> 4];
+ *q++ = hex_digits[ch & 0xf];
+ }
+ while (--count);
+ r_set_size(&rbuf, (len1 << 1) - odd);
+ rbuf.value.bytes = buf + odd;
+ status = write_string(&rbuf, s);
+ switch (status) {
+ default:
+ return_error(e_ioerror);
+ case 0:
+ len -= len1;
+ odd = 0;
+ continue;
+ case INTC:
+ case CALLC:
+ count = rbuf.value.bytes - buf;
+ op->value.bytes += count >> 1;
+ r_set_size(op, len - (count >> 1));
+ count &= 1;
+ return handle_write_status(status, op - 1, &count,
+ zwritehexstring_continue);
+ }
+ }
+ pop(2);
+ return 0;
+#undef MAX_HEX
+}
+private int
+zwritehexstring(os_ptr op)
+{
+ return zwritehexstring_at(op, 0);
+}
+/* Continue a writehexstring operation after a callout. */
+/* *op is the odd/even hex digit flag for the first byte. */
+private int
+zwritehexstring_continue(register os_ptr op)
+{
+ int code;
+
+ check_type(*op, t_integer);
+ if ((op->value.intval & ~1) != 0)
+ return_error(e_rangecheck);
+ code = zwritehexstring_at(op - 1, (uint) op->value.intval);
+ if (code >= 0)
+ pop(1);
+ return code;
+}
+
+/* <file> <string> readstring <substring> <filled_bool> */
+private int zreadstring_continue(P1(os_ptr));
+private int
+zreadstring_at(register os_ptr op, uint start)
+{
+ stream *s;
+ uint len, rlen;
+ int status;
+
+ check_read_file(s, op - 1);
+ check_write_type(*op, t_string);
+ len = r_size(op);
+ status = sgets(s, op->value.bytes + start, len - start, &rlen);
+ rlen += start;
+ switch (status) {
+ case EOFC:
+ case 0:
+ break;
+ default:
+ return handle_read_status(status, op - 1, &rlen,
+ zreadstring_continue);
+ }
+ /*
+ * The most recent Adobe specification says that readstring
+ * must signal a rangecheck if the string length is zero.
+ * I can't imagine the motivation for this, but we emulate it.
+ * It's safe to check it here, rather than earlier, because if
+ * len is zero, sgets will return 0 immediately with rlen = 0.
+ */
+ if (len == 0)
+ return_error(e_rangecheck);
+ r_set_size(op, rlen);
+ op[-1] = *op;
+ make_bool(op, (rlen == len ? 1 : 0));
+ return 0;
+}
+private int
+zreadstring(os_ptr op)
+{
+ return zreadstring_at(op, 0);
+}
+/* Continue a readstring operation after a callout. */
+/* *op is the index within the string. */
+private int
+zreadstring_continue(register os_ptr op)
+{
+ int code;
+
+ check_type(*op, t_integer);
+ if (op->value.intval < 0 || op->value.intval > r_size(op - 1))
+ return_error(e_rangecheck);
+ code = zreadstring_at(op - 1, (uint) op->value.intval);
+ if (code >= 0)
+ pop(1);
+ return code;
+}
+
+/* <file> <string> writestring - */
+private int
+zwritestring(register os_ptr op)
+{
+ stream *s;
+ int status;
+
+ check_write_file(s, op - 1);
+ check_read_type(*op, t_string);
+ status = write_string(op, s);
+ if (status >= 0) {
+ pop(2);
+ return 0;
+ }
+ return handle_write_status(status, op - 1, NULL, zwritestring);
+}
+
+/* <file> <string> readline <substring> <bool> */
+private int zreadline(P1(os_ptr));
+private int zreadline_continue(P1(os_ptr));
+
+/*
+ * We could handle readline the same way as readstring,
+ * except for the anomalous situation where we get interrupted
+ * between the CR and the LF of an end-of-line marker.
+ * We hack around this in the following way: if we get interrupted
+ * before we've read any characters, we just restart the readline;
+ * if we get interrupted at any other time, we use readline_continue;
+ * we use start=0 (which we have just ruled out as a possible start value
+ * for readline_continue) to indicate interruption after the CR.
+ */
+private int
+zreadline_at(register os_ptr op, uint count, bool in_eol)
+{
+ stream *s;
+ byte *ptr;
+ uint len;
+ int status;
+
+ check_read_file(s, op - 1);
+ check_write_type(*op, t_string);
+ ptr = op->value.bytes;
+ len = r_size(op);
+ status = zreadline_from(s, ptr, len, &count, &in_eol);
+ switch (status) {
+ case 0:
+ case EOFC:
+ break;
+ case 1:
+ return_error(e_rangecheck);
+ default:
+ if (count == 0 && !in_eol)
+ return handle_read_status(status, op - 1, NULL,
+ zreadline);
+ else {
+ if (in_eol) {
+ r_set_size(op, count);
+ count = 0;
+ }
+ return handle_read_status(status, op - 1, &count,
+ zreadline_continue);
+ }
+ }
+ r_set_size(op, count);
+ op[-1] = *op;
+ make_bool(op, status == 0);
+ return 0;
+}
+private int
+zreadline(register os_ptr op)
+{
+ return zreadline_at(op, 0, false);
+}
+/* Continue a readline operation after a callout. */
+/* *op is the index within the string, or 0 for an interrupt after a CR. */
+private int
+zreadline_continue(register os_ptr op)
+{
+ uint size = r_size(op - 1);
+ uint start;
+ int code;
+
+ check_type(*op, t_integer);
+ if (op->value.intval < 0 || op->value.intval > size)
+ return_error(e_rangecheck);
+ start = (uint) op->value.intval;
+ code = (start == 0 ? zreadline_at(op - 1, size, true) :
+ zreadline_at(op - 1, start, false));
+ if (code >= 0)
+ pop(1);
+ return code;
+}
+
+/* Internal readline routine. */
+/* Returns a stream status value, or 1 if we overflowed the string. */
+/* This is exported for %lineedit. */
+int
+zreadline_from(stream * s, byte * ptr, uint size, uint * pcount, bool * pin_eol)
+{
+ uint count = *pcount;
+
+ /* Most systems define \n as 0xa and \r as 0xd; however, */
+ /* OS-9 has \n == \r == 0xd and \l == 0xa. The following */
+ /* code works properly regardless of environment. */
+#if '\n' == '\r'
+# define LF 0xa
+#else
+# define LF '\n'
+#endif
+
+top:
+ if (*pin_eol) {
+ /*
+ * We're in the middle of checking for a two-character
+ * end-of-line sequence. If we get an EOF here, stop, but
+ * don't signal EOF now; wait till the next read.
+ */
+ int ch = spgetcc(s, false);
+
+ if (ch == EOFC) {
+ *pin_eol = false;
+ return 0;
+ } else if (ch < 0)
+ return ch;
+ else if (ch != LF)
+ sputback(s);
+ *pin_eol = false;
+ return 0;
+ }
+ for (;;) {
+ int ch = sgetc(s);
+
+ if (ch < 0) { /* EOF or exception */
+ *pcount = count;
+ return ch;
+ }
+ switch (ch) {
+ case '\r':
+ {
+#if '\n' == '\r' /* OS-9 or similar */
+ stream *ins;
+ int code = zget_stdin(&ins);
+
+ if (code < 0 || s != ins)
+#endif
+ {
+ *pcount = count;
+ *pin_eol = true;
+ goto top;
+ }
+ }
+ /* falls through */
+ case LF:
+#undef LF
+ *pcount = count;
+ return 0;
+ }
+ if (count >= size) { /* filled the string */
+ sputback(s);
+ *pcount = count;
+ return 1;
+ }
+ ptr[count++] = ch;
+ }
+ /*return 0; *//* not reached */
+}
+
+/* <file> bytesavailable <int> */
+private int
+zbytesavailable(register os_ptr op)
+{
+ stream *s;
+ long avail;
+
+ check_read_file(s, op);
+ switch (savailable(s, &avail)) {
+ default:
+ return_error(e_ioerror);
+ case EOFC:
+ avail = -1;
+ case 0:
+ ;
+ }
+ make_int(op, avail);
+ return 0;
+}
+
+/* - flush - */
+int
+zflush(register os_ptr op)
+{
+ stream *s;
+ int code = zget_stderr(&s);
+
+ if (code < 0)
+ return code;
+ sflush(s);
+ return 0;
+}
+
+/* <file> flushfile - */
+private int
+zflushfile(register os_ptr op)
+{
+ stream *s;
+ int status;
+
+ check_file(s, op);
+ status = sflush(s);
+ if (status == 0) {
+ pop(1);
+ return 0;
+ }
+ return
+ (s_is_writing(s) ?
+ handle_write_status(status, op, NULL, zflushfile) :
+ handle_read_status(status, op, NULL, zflushfile));
+}
+
+/* <file> resetfile - */
+private int
+zresetfile(register os_ptr op)
+{
+ stream *s;
+
+ /* According to Adobe, resetfile is a no-op on closed files. */
+ check_type(*op, t_file);
+ if (file_is_valid(s, op))
+ sreset(s);
+ pop(1);
+ return 0;
+}
+
+/* <string> print - */
+private int
+zprint(register os_ptr op)
+{
+ stream *s;
+ int status;
+ ref rstdout;
+ int code;
+
+ check_read_type(*op, t_string);
+ code = zget_stderr(&s);
+ if (code < 0)
+ return code;
+ status = write_string(op, s);
+ if (status >= 0) {
+ pop(1);
+ return 0;
+ }
+ /* Convert print to writestring on the fly. */
+ make_stream_file(&rstdout, s, "w");
+ code = handle_write_status(status, &rstdout, NULL, zwritestring);
+ if (code != o_push_estack)
+ return code;
+ push(1);
+ *op = op[-1];
+ op[-1] = rstdout;
+ return code;
+}
+
+/* <bool> echo - */
+private int
+zecho(register os_ptr op)
+{
+ check_type(*op, t_boolean);
+ /****** NOT IMPLEMENTED YET ******/
+ pop(1);
+ return 0;
+}
+
+/* ------ Level 2 extensions ------ */
+
+/* <file> fileposition <int> */
+private int
+zfileposition(register os_ptr op)
+{
+ stream *s;
+
+ check_file(s, op);
+ make_int(op, stell(s));
+ return 0;
+}
+
+/* <file> <int> setfileposition - */
+private int
+zsetfileposition(register os_ptr op)
+{
+ stream *s;
+
+ check_file(s, op - 1);
+ check_type(*op, t_integer);
+ if (sseek(s, op->value.intval) < 0)
+ return_error(e_ioerror);
+ pop(2);
+ return 0;
+}
+
+/* ------ Non-standard extensions ------ */
+
+/* <file> <int> unread - */
+private int
+zunread(register os_ptr op)
+{
+ stream *s;
+ ulong ch;
+
+ check_read_file(s, op - 1);
+ check_type(*op, t_integer);
+ ch = op->value.intval;
+ if (ch > 0xff)
+ return_error(e_rangecheck);
+ if (sungetc(s, (byte) ch) < 0)
+ return_error(e_ioerror);
+ pop(2);
+ return 0;
+}
+
+/* <file> <object> <==flag> .writecvp - */
+private int zwritecvp_continue(P1(os_ptr));
+private int
+zwritecvp_at(register os_ptr op, uint start)
+{
+ stream *s;
+#define MAX_CVS 128
+ byte str[MAX_CVS];
+ ref rstr;
+ const byte *pchars = str;
+ uint len;
+ int code, status;
+
+ check_write_file(s, op - 2);
+ check_type(*op, t_boolean);
+ code = obj_cvp(op - 1, str, MAX_CVS, &len, &pchars, op->value.boolval);
+ if (code < 0) {
+ if (pchars == str)
+ return code;
+ }
+ if (start > len)
+ return_error(e_rangecheck);
+ r_set_size(&rstr, len - start);
+ rstr.value.const_bytes = pchars + start;
+ status = write_string(&rstr, s);
+ switch (status) {
+ default:
+ return_error(e_ioerror);
+ case 0:
+ break;
+ case INTC:
+ case CALLC:
+ len -= r_size(&rstr);
+ return handle_write_status(status, op - 2, &len,
+ zwritecvp_continue);
+ }
+ pop(3);
+ return 0;
+#undef MAX_CVS
+}
+private int
+zwritecvp(os_ptr op)
+{
+ return zwritecvp_at(op, 0);
+}
+/* Continue a .writecvp after a callout. */
+/* *op is the index within the string. */
+private int
+zwritecvp_continue(os_ptr op)
+{
+ int code;
+
+ check_type(*op, t_integer);
+ if (op->value.intval != (uint) op->value.intval)
+ return_error(e_rangecheck);
+ code = zwritecvp_at(op - 1, (uint) op->value.intval);
+ if (code >= 0)
+ pop(1);
+ return code;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zfileio_op_defs[] =
+{
+ {"1bytesavailable", zbytesavailable},
+ {"1closefile", zclosefile},
+ /* currentfile is in zcontrol.c */
+ {"1echo", zecho},
+ {"1fileposition", zfileposition},
+ {"0flush", zflush},
+ {"1flushfile", zflushfile},
+ {"1print", zprint},
+ {"1read", zread},
+ {"2readhexstring", zreadhexstring},
+ {"2readline", zreadline},
+ {"2readstring", zreadstring},
+ {"1resetfile", zresetfile},
+ {"2setfileposition", zsetfileposition},
+ {"2unread", zunread},
+ {"2write", zwrite},
+ {"3.writecvp", zwritecvp},
+ {"2writehexstring", zwritehexstring},
+ {"2writestring", zwritestring},
+ /* Internal operators */
+ {"3%zreadhexstring_continue", zreadhexstring_continue},
+ {"3%zwritehexstring_continue", zwritehexstring_continue},
+ {"3%zreadstring_continue", zreadstring_continue},
+ {"3%zreadline_continue", zreadline_continue},
+ {"4%zwritecvp_continue", zwritecvp_continue},
+ op_def_end(0)
+};
+
+/* ------ Non-operator routines ------ */
+
+/* Switch a file open for read/write access but currently in write mode */
+/* to read mode. */
+int
+file_switch_to_read(const ref * op)
+{
+ stream *s = fptr(op);
+
+ if (s->write_id != r_size(op) || s->file == 0) /* not valid */
+ return_error(e_invalidaccess);
+ if (sswitch(s, false) < 0)
+ return_error(e_ioerror);
+ s->read_id = s->write_id; /* enable reading */
+ s->write_id = 0; /* disable writing */
+ return 0;
+}
+
+/* Switch a file open for read/write access but currently in read mode */
+/* to write mode. */
+int
+file_switch_to_write(const ref * op)
+{
+ stream *s = fptr(op);
+
+ if (s->read_id != r_size(op) || s->file == 0) /* not valid */
+ return_error(e_invalidaccess);
+ if (sswitch(s, true) < 0)
+ return_error(e_ioerror);
+ s->write_id = s->read_id; /* enable writing */
+ s->read_id = 0; /* disable reading */
+ return 0;
+}
+
+/* ------ Internal routines ------ */
+
+/* Write a string on a file. The file and string have been validated. */
+/* If the status is INTC or CALLC, updates the string on the o-stack. */
+private int
+write_string(ref * op, stream * s)
+{
+ const byte *data = op->value.const_bytes;
+ uint len = r_size(op);
+ uint wlen;
+ int status = sputs(s, data, len, &wlen);
+
+ switch (status) {
+ case INTC:
+ case CALLC:
+ op->value.const_bytes = data + wlen;
+ r_set_size(op, len - wlen);
+ /* falls through */
+ default: /* 0, EOFC, ERRC */
+ return status;
+ }
+}
+
+/* Handle an exceptional status return from a read stream. */
+/* fop points to the ref for the stream. */
+/* ch may be any stream exceptional value. */
+/* Return 0, 1 (EOF), o_push_estack, or an error. */
+private int
+handle_read_status(int ch, const ref * fop, const uint * pindex,
+ int (*cont) (P1(os_ptr)))
+{
+ switch (ch) {
+ default: /* error */
+ return_error(e_ioerror);
+ case EOFC:
+ return 1;
+ case INTC:
+ case CALLC:
+ if (pindex) {
+ ref index;
+
+ make_int(&index, *pindex);
+ return s_handle_read_exception(ch, fop, &index, 1, cont);
+ } else
+ return s_handle_read_exception(ch, fop, NULL, 0, cont);
+ }
+}
+
+/* Handle an exceptional status return from a write stream. */
+/* fop points to the ref for the stream. */
+/* ch may be any stream exceptional value. */
+/* Return 0, 1 (EOF), o_push_estack, or an error. */
+private int
+handle_write_status(int ch, const ref * fop, const uint * pindex,
+ int (*cont) (P1(os_ptr)))
+{
+ switch (ch) {
+ default: /* error */
+ return_error(e_ioerror);
+ case EOFC:
+ return 1;
+ case INTC:
+ case CALLC:
+ if (pindex) {
+ ref index;
+
+ make_int(&index, *pindex);
+ return s_handle_write_exception(ch, fop, &index, 1, cont);
+ } else
+ return s_handle_write_exception(ch, fop, NULL, 0, cont);
+ }
+}
diff --git a/pstoraster/zfilter.c b/pstoraster/zfilter.c
new file mode 100644
index 000000000..2ab5a5c43
--- /dev/null
+++ b/pstoraster/zfilter.c
@@ -0,0 +1,418 @@
+/* Copyright (C) 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$ */
+/* Filter creation */
+#include "memory_.h"
+#include "ghost.h"
+#include "oper.h"
+#include "gsstruct.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "idparam.h"
+#include "ilevel.h" /* SubFileDecode is different in LL3 */
+#include "stream.h"
+#include "strimpl.h"
+#include "sfilter.h"
+#include "srlx.h"
+#include "sstring.h"
+#include "ifilter.h"
+#include "files.h" /* for filter_open, file_d'_buffer_size */
+
+/* <source> ASCIIHexEncode/filter <file> */
+/* <source> <dict> ASCIIHexEncode/filter <file> */
+private int
+zAXE(os_ptr op)
+{
+ return filter_write_simple(op, &s_AXE_template);
+}
+
+/* <target> ASCIIHexDecode/filter <file> */
+/* <target> <dict> ASCIIHexDecode/filter <file> */
+private int
+zAXD(os_ptr op)
+{
+ return filter_read_simple(op, &s_AXD_template);
+}
+
+/* <target> NullEncode/filter <file> */
+/* <target> <dict_ignored> NullEncode/filter <file> */
+private int
+zNullE(os_ptr op)
+{
+ return filter_write_simple(op, &s_NullE_template);
+}
+
+/* <source> <bool> PFBDecode/filter <file> */
+/* <source> <dict> <bool> PFBDecode/filter <file> */
+private int
+zPFBD(os_ptr op)
+{
+ stream_PFBD_state state;
+ os_ptr sop = op;
+
+ check_type(*sop, t_boolean);
+ state.binary_to_hex = sop->value.boolval;
+ return filter_read(op, 1, &s_PFBD_template, (stream_state *) & state, 0);
+}
+
+/* <target> PSStringEncode/filter <file> */
+/* <target> <dict> PSStringEncode/filter <file> */
+private int
+zPSSE(os_ptr op)
+{
+ return filter_write_simple(op, &s_PSSE_template);
+}
+
+/* ------ RunLength filters ------ */
+
+/* Common setup for RLE and RLD filters. */
+private int
+rl_setup(os_ptr dop, bool * eod)
+{
+ if (r_has_type(dop, t_dictionary)) {
+ int code;
+
+ check_dict_read(*dop);
+ if ((code = dict_bool_param(dop, "EndOfData", true, eod)) < 0)
+ return code;
+ return 1;
+ } else {
+ *eod = true;
+ return 0;
+ }
+}
+
+/* <target> <record_size> RunLengthEncode/filter <file> */
+/* <target> <dict> <record_size> RunLengthEncode/filter <file> */
+private int
+zRLE(register os_ptr op)
+{
+ stream_RLE_state state;
+ int code;
+
+ check_op(2);
+ code = rl_setup(op - 1, &state.EndOfData);
+ if (code < 0)
+ return code;
+ check_int_leu(*op, max_uint);
+ state.record_size = op->value.intval;
+ return filter_write(op, 1, &s_RLE_template, (stream_state *) & state, 0);
+}
+
+/* <source> RunLengthDecode/filter <file> */
+/* <source> <dict> RunLengthDecode/filter <file> */
+private int
+zRLD(os_ptr op)
+{
+ stream_RLD_state state;
+ int code = rl_setup(op, &state.EndOfData);
+
+ if (code < 0)
+ return code;
+ return filter_read(op, 0, &s_RLD_template, (stream_state *) & state, 0);
+}
+
+/* <source> <EODcount> <EODstring> SubFileDecode/filter <file> */
+/* <source> <dict> <EODcount> <EODstring> SubFileDecode/filter <file> */
+/* <source> <dict> SubFileDecode/filter <file> *//* (LL3 only) */
+private int
+zSFD(os_ptr op)
+{
+ stream_SFD_state state;
+ ref *sop = op;
+ int npop;
+
+ if (LL3_ENABLED && r_has_type(op, t_dictionary)) {
+ int count;
+ int code;
+
+ check_dict_read(*op);
+ if ((code = dict_int_param(op, "EODCount", 0, max_int, -1, &count)) < 0)
+ return code;
+ if (dict_find_string(op, "EODString", &sop) <= 0)
+ return_error(e_rangecheck);
+ state.count = count;
+ npop = 0;
+ } else {
+ check_type(sop[-1], t_integer);
+ if (sop[-1].value.intval < 0)
+ return_error(e_rangecheck);
+ state.count = sop[-1].value.intval;
+ npop = 2;
+ }
+ check_read_type(*sop, t_string);
+ state.eod.data = sop->value.const_bytes;
+ state.eod.size = r_size(sop);
+ return filter_read(op, npop, &s_SFD_template, (stream_state *) & state,
+ r_space(sop));
+}
+
+/* ------ Utilities ------ */
+
+/* Forward references */
+private int filter_ensure_buf(P3(stream **, uint, bool));
+
+/* Set up an input filter. */
+int
+filter_read(os_ptr op, int npop, const stream_template * template,
+ stream_state * st, uint space)
+{
+ uint min_size = template->min_out_size + max_min_left;
+ uint save_space = ialloc_space(idmemory);
+ os_ptr sop = op - npop;
+ stream *s;
+ stream *sstrm;
+ bool close = false;
+ int code;
+
+ /* Skip over an optional dictionary parameter. */
+ if (r_has_type(sop, t_dictionary)) {
+ check_dict_read(*sop);
+ if ((code = dict_bool_param(sop, "CloseSource", false, &close)) < 0)
+ return code;
+ --sop;
+ }
+ /*
+ * Check to make sure that the underlying data
+ * can function as a source for reading.
+ */
+ switch (r_type(sop)) {
+ case t_string:
+ check_read(*sop);
+ ialloc_set_space(idmemory, max(space, r_space(sop)));
+ sstrm = file_alloc_stream(imemory, "filter_read(string stream)");
+ if (sstrm == 0) {
+ code = gs_note_error(e_VMerror);
+ goto out;
+ }
+ sread_string(sstrm, sop->value.bytes, r_size(sop));
+ sstrm->is_temp = 1;
+ break;
+ case t_file:
+ check_read_known_file(sstrm, sop, return);
+ ialloc_set_space(idmemory, max(space, r_space(sop)));
+ goto ens;
+ default:
+ check_proc(*sop);
+ ialloc_set_space(idmemory, max(space, r_space(sop)));
+ code = sread_proc(sop, &sstrm);
+ if (code < 0)
+ goto out;
+ sstrm->is_temp = 2;
+ ens:
+ code = filter_ensure_buf(&sstrm,
+ template->min_in_size +
+ sstrm->state->template->min_out_size,
+ false);
+ if (code < 0)
+ goto out;
+ break;
+ }
+ if (min_size < 128)
+ min_size = file_default_buffer_size;
+ code = filter_open("r", min_size, (ref *) sop,
+ &s_filter_read_procs, template, st);
+ if (code < 0)
+ goto out;
+ s = fptr(sop);
+ s->strm = sstrm;
+ s->close_strm = close;
+ pop(op - sop);
+out:
+ ialloc_set_space(idmemory, save_space);
+ return code;
+}
+int
+filter_read_simple(os_ptr op, const stream_template * template)
+{
+ return filter_read(op, 0, template, NULL, 0);
+}
+
+/* Set up an output filter. */
+int
+filter_write(os_ptr op, int npop, const stream_template * template,
+ stream_state * st, uint space)
+{
+ uint min_size = template->min_in_size + max_min_left;
+ uint save_space = ialloc_space(idmemory);
+ register os_ptr sop = op - npop;
+ stream *s;
+ stream *sstrm;
+ bool close = false;
+ int code;
+
+ /* Skip over an optional dictionary parameter. */
+ if (r_has_type(sop, t_dictionary)) {
+ check_dict_read(*sop);
+ if ((code = dict_bool_param(sop, "CloseTarget", false, &close)) < 0)
+ return code;
+ --sop;
+ }
+ /*
+ * Check to make sure that the underlying data
+ * can function as a sink for writing.
+ */
+ switch (r_type(sop)) {
+ case t_string:
+ check_write(*sop);
+ ialloc_set_space(idmemory, max(space, r_space(sop)));
+ sstrm = file_alloc_stream(imemory, "filter_write(string)");
+ if (sstrm == 0) {
+ code = gs_note_error(e_VMerror);
+ goto out;
+ }
+ swrite_string(sstrm, sop->value.bytes, r_size(sop));
+ sstrm->is_temp = 1;
+ break;
+ case t_file:
+ check_write_known_file(sstrm, sop, return);
+ ialloc_set_space(idmemory, max(space, r_space(sop)));
+ goto ens;
+ default:
+ check_proc(*sop);
+ ialloc_set_space(idmemory, max(space, r_space(sop)));
+ code = swrite_proc(sop, &sstrm);
+ if (code < 0)
+ goto out;
+ sstrm->is_temp = 2;
+ ens:
+ code = filter_ensure_buf(&sstrm,
+ template->min_out_size +
+ sstrm->state->template->min_in_size,
+ true);
+ if (code < 0)
+ goto out;
+ break;
+ }
+ if (min_size < 128)
+ min_size = file_default_buffer_size;
+ code = filter_open("w", min_size, (ref *) sop,
+ &s_filter_write_procs, template, st);
+ if (code < 0)
+ goto out;
+ s = fptr(sop);
+ s->strm = sstrm;
+ s->close_strm = close;
+ pop(op - sop);
+out:
+ ialloc_set_space(idmemory, save_space);
+ return code;
+}
+int
+filter_write_simple(os_ptr op, const stream_template * template)
+{
+ return filter_write(op, 0, template, NULL, 0);
+}
+
+/* Define a byte-at-a-time NullDecode filter for intermediate buffers. */
+/* (The standard NullDecode filter can read ahead too far.) */
+private int
+s_Null1D_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * pw, bool last)
+{
+ if (pr->ptr >= pr->limit)
+ return 0;
+ if (pw->ptr >= pw->limit)
+ return 1;
+ *++(pw->ptr) = *++(pr->ptr);
+ return 1;
+}
+private const stream_template s_Null1D_template =
+{
+ &st_stream_state, NULL, s_Null1D_process, 1, 1
+};
+
+/* Ensure a minimum buffer size for a filter. */
+/* This may require creating an intermediate stream. */
+private int
+filter_ensure_buf(stream ** ps, uint min_buf_size, bool writing)
+{
+ stream *s = *ps;
+ uint min_size = min_buf_size + max_min_left;
+ stream *bs;
+ ref bsop;
+ int code;
+
+ if (s->modes == 0 /* stream is closed */ || s->bsize >= min_size)
+ return 0;
+ /* Otherwise, allocate an intermediate stream. */
+ if (s->cbuf == 0) {
+ /* This is a newly created procedure stream. */
+ /* Just allocate a buffer for it. */
+ uint len = max(min_size, 128);
+ byte *buf = ialloc_bytes(len, "filter_ensure_buf");
+
+ if (buf == 0)
+ return_error(e_VMerror);
+ s->cbuf = buf;
+ s->srptr = s->srlimit = s->swptr = buf - 1;
+ s->swlimit = buf - 1 + len;
+ s->bsize = s->cbsize = len;
+ return 0;
+ } else {
+ /* Allocate an intermediate stream. */
+ if (writing)
+ code = filter_open("w", min_size, &bsop, &s_filter_write_procs,
+ &s_NullE_template, NULL);
+ else
+ code = filter_open("r", min_size, &bsop, &s_filter_read_procs,
+ &s_Null1D_template, NULL);
+ if (code < 0)
+ return code;
+ bs = fptr(&bsop);
+ bs->strm = s;
+ bs->is_temp = 2;
+ *ps = bs;
+ return code;
+ }
+}
+
+/* Mark a (filter) stream as temporary. */
+/* We define this here to avoid importing stream.h into zf*.c. */
+void
+filter_mark_temp(const ref * fop, int is_temp)
+{
+ fptr(fop)->is_temp = is_temp;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zfilter_op_defs[] =
+{
+ /* We enter PSStringEncode and SubFileDecode (only) */
+ /* as separate operators. */
+ {"1.psstringencode", zPSSE},
+ {"2.subfiledecode", zSFD},
+ op_def_begin_filter(),
+ {"1ASCIIHexEncode", zAXE},
+ {"1ASCIIHexDecode", zAXD},
+ {"1NullEncode", zNullE},
+ {"2PFBDecode", zPFBD},
+ {"1PSStringEncode", zPSSE},
+ {"2RunLengthEncode", zRLE},
+ {"1RunLengthDecode", zRLD},
+ {"3SubFileDecode", zSFD},
+ op_def_end(0)
+};
diff --git a/pstoraster/zfilter2.c b/pstoraster/zfilter2.c
new file mode 100644
index 000000000..fc58762e7
--- /dev/null
+++ b/pstoraster/zfilter2.c
@@ -0,0 +1,165 @@
+/* Copyright (C) 1991, 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$ */
+/* Additional filter creation */
+#include "memory_.h"
+#include "ghost.h"
+#include "oper.h"
+#include "gsstruct.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "idparam.h"
+#include "store.h"
+#include "strimpl.h"
+#include "sfilter.h"
+#include "scfx.h"
+#include "slzwx.h"
+#include "spdiffx.h"
+#include "spngpx.h"
+#include "ifilter.h"
+
+/* Import setup code from zfdecode.c */
+int zcf_setup(P2(os_ptr op, stream_CF_state * pcfs));
+int zlz_setup(P2(os_ptr op, stream_LZW_state * plzs));
+int zpd_setup(P2(os_ptr op, stream_PDiff_state * ppds));
+int zpp_setup(P2(os_ptr op, stream_PNGP_state * ppps));
+
+/* ------ CCITTFaxEncode filter ------ */
+
+/* <target> <dict> CCITTFaxEncode/filter <file> */
+private int
+zCFE(os_ptr op)
+{
+ stream_CFE_state cfs;
+ int code;
+
+ check_type(*op, t_dictionary);
+ check_dict_read(*op);
+ code = zcf_setup(op, (stream_CF_state *)&cfs);
+ if (code < 0)
+ return code;
+ return filter_write(op, 0, &s_CFE_template, (stream_state *)&cfs, 0);
+}
+
+/* ------ Common setup for possibly pixel-oriented encoding filters ------ */
+
+int
+filter_write_predictor(os_ptr op, int npop, const stream_template * template,
+ stream_state * st)
+{
+ int predictor, code;
+ stream_PDiff_state pds;
+ stream_PNGP_state pps;
+
+ if (r_has_type(op, t_dictionary)) {
+ if ((code = dict_int_param(op, "Predictor", 0, 15, 1, &predictor)) < 0)
+ return code;
+ switch (predictor) {
+ case 0: /* identity */
+ predictor = 1;
+ case 1: /* identity */
+ break;
+ case 2: /* componentwise horizontal differencing */
+ code = zpd_setup(op, &pds);
+ break;
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ /* PNG prediction */
+ code = zpp_setup(op, &pps);
+ break;
+ default:
+ return_error(e_rangecheck);
+ }
+ if (code < 0)
+ return code;
+ } else
+ predictor = 1;
+ if (predictor == 1)
+ return filter_write(op, npop, template, st, 0);
+ {
+ /* We need to cascade filters. */
+ ref rtarget, rdict, rfd;
+ int code;
+
+ /* Save the operands, just in case. */
+ ref_assign(&rtarget, op - 1);
+ ref_assign(&rdict, op);
+ code = filter_write(op, 1, template, st, 0);
+ if (code < 0)
+ return code;
+ /* filter_write changed osp.... */
+ op = osp;
+ ref_assign(&rfd, op);
+ code =
+ (predictor == 2 ?
+ filter_write(op, 0, &s_PDiffE_template, (stream_state *)&pds, 0) :
+ filter_write(op, 0, &s_PNGPE_template, (stream_state *)&pps, 0));
+ if (code < 0) {
+ /* Restore the operands. Don't bother trying to clean up */
+ /* the first stream. */
+ osp = ++op;
+ ref_assign(op - 1, &rtarget);
+ ref_assign(op, &rdict);
+ return code;
+ }
+ filter_mark_temp(&rfd, 2); /* Mark the compression stream as temporary. */
+ return code;
+ }
+}
+
+/* ------ LZW encoding filter ------ */
+
+/* <target> LZWEncode/filter <file> */
+/* <target> <dict> LZWEncode/filter <file> */
+/*
+ * Note: the default implementation of this filter, in slzwce.c,
+ * does not use any algorithms that could reasonably be claimed
+ * to be subject to Unisys' Welch Patent.
+ */
+private int
+zLZWE(os_ptr op)
+{
+ stream_LZW_state lzs;
+ int code = zlz_setup(op, &lzs);
+
+ if (code < 0)
+ return code;
+ return filter_write_predictor(op, 0, &s_LZWE_template,
+ (stream_state *) & lzs);
+}
+
+/* ================ Initialization procedure ================ */
+
+const op_def zfilter2_op_defs[] =
+{
+ op_def_begin_filter(),
+ {"2CCITTFaxEncode", zCFE},
+ {"1LZWEncode", zLZWE},
+ op_def_end(0)
+};
diff --git a/pstoraster/zfilterx.c b/pstoraster/zfilterx.c
new file mode 100644
index 000000000..6c3897236
--- /dev/null
+++ b/pstoraster/zfilterx.c
@@ -0,0 +1,336 @@
+/* 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$ */
+/* Extended (non-standard) filter creation */
+#include "memory_.h"
+#include "ghost.h"
+#include "oper.h"
+#include "gsstruct.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "idparam.h"
+#include "store.h"
+#include "strimpl.h"
+#include "sfilter.h"
+#include "sbwbs.h"
+#include "sbhc.h"
+#include "sbtx.h"
+#include "shcgen.h"
+#include "smtf.h"
+#include "spcxx.h"
+#include "ifilter.h"
+
+/* ------ Bounded Huffman code filters ------ */
+
+/* Common setup for encoding and decoding filters */
+private int
+bhc_setup(os_ptr op, stream_BHC_state * pbhcs)
+{
+ int code;
+ int num_counts;
+ int data[max_hc_length + 1 + 256 + max_zero_run + 1];
+ uint dsize;
+ int i;
+ uint num_values, accum;
+ ushort *counts;
+ ushort *values;
+
+ check_type(*op, t_dictionary);
+ check_dict_read(*op);
+ if ((code = dict_bool_param(op, "FirstBitLowOrder", false,
+ &pbhcs->FirstBitLowOrder)) < 0 ||
+ (code = dict_int_param(op, "MaxCodeLength", 1, max_hc_length,
+ max_hc_length, &num_counts)) < 0 ||
+ (code = dict_bool_param(op, "EndOfData", true,
+ &pbhcs->EndOfData)) < 0 ||
+ (code = dict_uint_param(op, "EncodeZeroRuns", 2, 256,
+ 256, &pbhcs->EncodeZeroRuns)) < 0 ||
+ /* Note: the code returned from the following call */
+ /* is actually the number of elements in the array. */
+ (code = dict_int_array_param(op, "Tables", countof(data),
+ data)) <= 0
+ )
+ return (code < 0 ? code : gs_note_error(e_rangecheck));
+ dsize = code;
+ if (dsize <= num_counts + 2)
+ return_error(e_rangecheck);
+ for (i = 0, num_values = 0, accum = 0; i <= num_counts;
+ i++, accum <<= 1
+ ) {
+ int count = data[i];
+
+ if (count < 0)
+ return_error(e_rangecheck);
+ num_values += count;
+ accum += count;
+ }
+ if (dsize != num_counts + 1 + num_values ||
+ accum != 1 << (num_counts + 1) ||
+ pbhcs->EncodeZeroRuns >
+ (pbhcs->EndOfData ? num_values - 1 : num_values)
+ )
+ return_error(e_rangecheck);
+ for (; i < num_counts + 1 + num_values; i++) {
+ int value = data[i];
+
+ if (value < 0 || value >= num_values)
+ return_error(e_rangecheck);
+ }
+ pbhcs->definition.counts = counts =
+ (ushort *) ialloc_byte_array(num_counts + 1, sizeof(ushort),
+ "bhc_setup(counts)");
+ pbhcs->definition.values = values =
+ (ushort *) ialloc_byte_array(num_values, sizeof(ushort),
+ "bhc_setup(values)");
+ if (counts == 0 || values == 0) {
+ ifree_object(values, "bhc_setup(values)");
+ ifree_object(counts, "bhc_setup(counts)");
+ return_error(e_VMerror);
+ }
+ for (i = 0; i <= num_counts; i++)
+ counts[i] = data[i];
+ pbhcs->definition.counts = counts;
+ pbhcs->definition.num_counts = num_counts;
+ for (i = 0; i < num_values; i++)
+ values[i] = data[i + num_counts + 1];
+ pbhcs->definition.values = values;
+ pbhcs->definition.num_values = num_values;
+ return 0;
+}
+
+/* <target> <dict> BoundedHuffmanEncode/filter <file> */
+private int
+zBHCE(os_ptr op)
+{
+ stream_BHCE_state bhcs;
+ int code = bhc_setup(op, (stream_BHC_state *)&bhcs);
+
+ if (code < 0)
+ return code;
+ return filter_write(op, 0, &s_BHCE_template, (stream_state *)&bhcs, 0);
+}
+
+/* <source> <dict> BoundedHuffmanDecode/filter <file> */
+private int
+zBHCD(os_ptr op)
+{
+ stream_BHCD_state bhcs;
+ int code = bhc_setup(op, (stream_BHC_state *)&bhcs);
+
+ if (code < 0)
+ return code;
+ return filter_read(op, 0, &s_BHCD_template, (stream_state *)&bhcs, 0);
+}
+
+/* <array> <max_length> .computecodes <array> */
+/* The first max_length+1 elements of the array will be filled in with */
+/* the code counts; the remaining elements will be replaced with */
+/* the code values. This is the form needed for the Tables element of */
+/* the dictionary parameter for the BoundedHuffman filters. */
+private int
+zcomputecodes(os_ptr op)
+{
+ os_ptr op1 = op - 1;
+ uint asize;
+ hc_definition def;
+ ushort *data;
+ long *freqs;
+ int code = 0;
+
+ check_type(*op, t_integer);
+ check_write_type(*op1, t_array);
+ asize = r_size(op1);
+ if (op->value.intval < 1 || op->value.intval > max_hc_length)
+ return_error(e_rangecheck);
+ def.num_counts = op->value.intval;
+ if (asize < def.num_counts + 2)
+ return_error(e_rangecheck);
+ def.num_values = asize - (def.num_counts + 1);
+ data = (ushort *) gs_alloc_byte_array(imemory, asize, sizeof(ushort),
+ "zcomputecodes");
+ freqs = (long *)gs_alloc_byte_array(imemory, def.num_values,
+ sizeof(long),
+ "zcomputecodes(freqs)");
+
+ if (data == 0 || freqs == 0)
+ code = gs_note_error(e_VMerror);
+ else {
+ uint i;
+
+ def.counts = data;
+ def.values = data + (def.num_counts + 1);
+ for (i = 0; i < def.num_values; i++) {
+ const ref *pf = op1->value.const_refs + i + def.num_counts + 1;
+
+ if (!r_has_type(pf, t_integer)) {
+ code = gs_note_error(e_typecheck);
+ break;
+ }
+ freqs[i] = pf->value.intval;
+ }
+ if (!code) {
+ code = hc_compute(&def, freqs, imemory);
+ if (code >= 0) {
+ /* Copy back results. */
+ for (i = 0; i < asize; i++)
+ make_int(op1->value.refs + i, data[i]);
+ }
+ }
+ }
+ gs_free_object(imemory, freqs, "zcomputecodes(freqs)");
+ gs_free_object(imemory, data, "zcomputecodes");
+ if (code < 0)
+ return code;
+ pop(1);
+ return code;
+}
+
+/* ------ Burrows/Wheeler block sorting filters ------ */
+
+/* Common setup for encoding and decoding filters */
+private int
+bwbs_setup(os_ptr op, stream_BWBS_state * pbwbss)
+{
+ int code =
+ dict_int_param(op, "BlockSize", 1, max_int / sizeof(int) - 10, 16384,
+ &pbwbss->BlockSize);
+
+ if (code < 0)
+ return code;
+ return 0;
+}
+
+/* <target> <dict> BWBlockSortEncode/filter <file> */
+private int
+zBWBSE(os_ptr op)
+{
+ stream_BWBSE_state bwbss;
+ int code;
+
+ check_type(*op, t_dictionary);
+ check_dict_read(*op);
+ code = bwbs_setup(op, (stream_BWBS_state *)&bwbss);
+ if (code < 0)
+ return code;
+ return filter_write(op, 0, &s_BWBSE_template, (stream_state *)&bwbss, 0);
+}
+
+/* <source> <dict> BWBlockSortDecode/filter <file> */
+private int
+zBWBSD(os_ptr op)
+{
+ stream_BWBSD_state bwbss;
+ int code = bwbs_setup(op, (stream_BWBS_state *)&bwbss);
+
+ if (code < 0)
+ return code;
+ return filter_read(op, 0, &s_BWBSD_template, (stream_state *)&bwbss, 0);
+}
+
+/* ------ Byte translation filters ------ */
+
+/* Common setup */
+private int
+bt_setup(os_ptr op, stream_BT_state * pbts)
+{
+ check_read_type(*op, t_string);
+ if (r_size(op) != 256)
+ return_error(e_rangecheck);
+ memcpy(pbts->table, op->value.const_bytes, 256);
+ return 0;
+}
+
+/* <target> <table> ByteTranslateEncode/filter <file> */
+/* <target> <table> <dict> ByteTranslateEncode/filter <file> */
+private int
+zBTE(os_ptr op)
+{
+ stream_BT_state bts;
+ int code = bt_setup(op, &bts);
+
+ if (code < 0)
+ return code;
+ return filter_write(op, 0, &s_BTE_template, (stream_state *)&bts, 0);
+}
+
+/* <target> <table> ByteTranslateDecode/filter <file> */
+/* <target> <table> <dict> ByteTranslateDecode/filter <file> */
+private int
+zBTD(os_ptr op)
+{
+ stream_BT_state bts;
+ int code = bt_setup(op, &bts);
+
+ if (code < 0)
+ return code;
+ return filter_read(op, 0, &s_BTD_template, (stream_state *)&bts, 0);
+}
+
+/* ------ Move-to-front filters ------ */
+
+/* <target> MoveToFrontEncode/filter <file> */
+/* <target> <dict> MoveToFrontEncode/filter <file> */
+private int
+zMTFE(os_ptr op)
+{
+ return filter_write_simple(op, &s_MTFE_template);
+}
+
+/* <source> MoveToFrontDecode/filter <file> */
+/* <source> <dict> MoveToFrontDecode/filter <file> */
+private int
+zMTFD(os_ptr op)
+{
+ return filter_read_simple(op, &s_MTFD_template);
+}
+
+/* ------ PCX decoding filter ------ */
+
+/* <source> PCXDecode/filter <file> */
+/* <source> <dict> PCXDecode/filter <file> */
+private int
+zPCXD(os_ptr op)
+{
+ return filter_read_simple(op, &s_PCXD_template);
+}
+
+/* ================ Initialization procedure ================ */
+
+const op_def zfilterx_op_defs[] =
+{
+ {"2.computecodes", zcomputecodes}, /* not a filter */
+ op_def_begin_filter(),
+ /* Non-standard filters */
+ {"2BoundedHuffmanEncode", zBHCE},
+ {"2BoundedHuffmanDecode", zBHCD},
+ {"2BWBlockSortEncode", zBWBSE},
+ {"2BWBlockSortDecode", zBWBSD},
+ {"2ByteTranslateEncode", zBTE},
+ {"2ByteTranslateDecode", zBTD},
+ {"1MoveToFrontEncode", zMTFE},
+ {"1MoveToFrontDecode", zMTFD},
+ {"1PCXDecode", zPCXD},
+ op_def_end(0)
+};
diff --git a/pstoraster/zfname.c b/pstoraster/zfname.c
new file mode 100644
index 000000000..66bfd385e
--- /dev/null
+++ b/pstoraster/zfname.c
@@ -0,0 +1,116 @@
+/* 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$ */
+/* File name utilities */
+#include "memory_.h"
+#include "ghost.h"
+#include "oper.h"
+#include "ialloc.h"
+#include "stream.h"
+#include "gxiodev.h" /* must come after stream.h */
+#include "fname.h"
+
+/* Parse a file name into device and individual name. */
+/* The device may be NULL, or the name may be NULL, but not both. */
+/* According to the Adobe documentation, %device and %device% */
+/* are equivalent; both return name==NULL. */
+int
+parse_file_name(const ref * op, parsed_file_name * pfn)
+{
+ const byte *pname;
+ uint len, dlen;
+ const byte *pdelim;
+ gx_io_device *iodev;
+
+ check_read_type(*op, t_string);
+ len = r_size(op);
+ pname = op->value.const_bytes;
+ if (len == 0)
+ return_error(e_undefinedfilename);
+ if (pname[0] != '%') { /* no device */
+ pfn->iodev = NULL;
+ pfn->fname = (const char *)pname;
+ pfn->len = len;
+ return 0;
+ }
+ pdelim = (const byte *)memchr(pname + 1, '%', len - 1);
+ if (pdelim == NULL) /* %device */
+ dlen = len;
+ else if (pdelim[1] == 0) { /* %device% */
+ pdelim = NULL;
+ dlen = len;
+ } else {
+ dlen = pdelim - pname;
+ pdelim++, len--;
+ }
+ iodev = gs_findiodevice(pname, dlen);
+ if (iodev == 0)
+ return_error(e_undefinedfilename);
+ pfn->iodev = iodev;
+ pfn->fname = (const char *)pdelim;
+ pfn->len = len - dlen;
+ return 0;
+}
+
+/* Parse a real (non-device) file name and convert to a C string. */
+int
+parse_real_file_name(const ref * op, parsed_file_name * pfn, client_name_t cname)
+{
+ int code = parse_file_name(op, pfn);
+
+ if (code < 0)
+ return code;
+ if (pfn->len == 0)
+ return_error(e_invalidfileaccess); /* device only */
+ return terminate_file_name(pfn, cname);
+}
+
+/* Convert a file name to a C string by adding a null terminator. */
+int
+terminate_file_name(parsed_file_name * pfn, client_name_t cname)
+{
+ uint len = pfn->len;
+ ref fnref;
+ const char *fname;
+
+ if (pfn->iodev == NULL) /* no device */
+ pfn->iodev = iodev_default;
+ fnref.value.const_bytes = (const byte *)pfn->fname;
+ r_set_size(&fnref, len);
+ fname = ref_to_string(&fnref, imemory, cname);
+ if (fname == 0)
+ return_error(e_VMerror);
+ pfn->fname = fname;
+ pfn->len = len + 1; /* null terminator */
+ return 0;
+}
+
+/* Free a file name that was copied to a C string. */
+void
+free_file_name(parsed_file_name * pfn, client_name_t cname)
+{
+ if (pfn->fname != 0)
+ ifree_string((byte *) pfn->fname, pfn->len, cname);
+}
diff --git a/pstoraster/zfont.c b/pstoraster/zfont.c
new file mode 100644
index 000000000..919d017f6
--- /dev/null
+++ b/pstoraster/zfont.c
@@ -0,0 +1,471 @@
+/* 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$ */
+/* Generic font operators */
+#include "ghost.h"
+#include "oper.h"
+#include "gsstruct.h" /* for registering root */
+#include "gzstate.h" /* must precede gxdevice */
+#include "gxdevice.h" /* must precede gxfont */
+#include "gschar.h"
+#include "gxfont.h"
+#include "gxfcache.h"
+#include "bfont.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "igstate.h"
+#include "iname.h" /* for name_mark_index */
+#include "isave.h"
+#include "store.h"
+#include "ivmspace.h"
+
+/* Forward references */
+private int make_font(P2(os_ptr, const gs_matrix *));
+private void make_uint_array(P3(os_ptr, const uint *, int));
+
+/* The (global) font directory */
+gs_font_dir *ifont_dir = 0; /* needed for buildfont */
+
+/* Mark a glyph as a PostScript name (if it isn't a CID). */
+bool
+zfont_mark_glyph_name(gs_glyph glyph, void *ignore_data)
+{
+ return (glyph >= gs_min_cid_glyph || glyph == gs_no_glyph ? false :
+ name_mark_index((uint) glyph));
+}
+
+/* Initialize the font operators */
+private void
+zfont_init(void)
+{
+ ifont_dir = gs_font_dir_alloc2(imemory, &gs_memory_default);
+ ifont_dir->ccache.mark_glyph = zfont_mark_glyph_name;
+ gs_register_struct_root(imemory, NULL, (void **)&ifont_dir,
+ "ifont_dir");
+}
+
+/* <font> <scale> scalefont <new_font> */
+private int
+zscalefont(register os_ptr op)
+{
+ int code;
+ double scale;
+ gs_matrix mat;
+
+ if ((code = real_param(op, &scale)) < 0)
+ return code;
+ if ((code = gs_make_scaling(scale, scale, &mat)) < 0)
+ return code;
+ return make_font(op, &mat);
+}
+
+/* <font> <matrix> makefont <new_font> */
+private int
+zmakefont(register os_ptr op)
+{
+ int code;
+ gs_matrix mat;
+
+ if ((code = read_matrix(op, &mat)) < 0)
+ return code;
+ return make_font(op, &mat);
+}
+
+/* <font> setfont - */
+int
+zsetfont(register os_ptr op)
+{
+ gs_font *pfont;
+ int code = font_param(op, &pfont);
+
+ if (code < 0 || (code = gs_setfont(igs, pfont)) < 0)
+ return code;
+ pop(1);
+ return code;
+}
+
+/* - currentfont <font> */
+private int
+zcurrentfont(register os_ptr op)
+{
+ push(1);
+ *op = *pfont_dict(gs_currentfont(igs));
+ return 0;
+}
+
+/* - cachestatus <mark> <bsize> <bmax> <msize> <mmax> <csize> <cmax> <blimit> */
+private int
+zcachestatus(register os_ptr op)
+{
+ uint status[7];
+
+ gs_cachestatus(ifont_dir, status);
+ push(7);
+ make_uint_array(op - 6, status, 7);
+ return 0;
+}
+
+/* <blimit> setcachelimit - */
+private int
+zsetcachelimit(register os_ptr op)
+{
+ check_int_leu(*op, max_uint);
+ gs_setcachelimit(ifont_dir, (uint) op->value.intval);
+ pop(1);
+ return 0;
+}
+
+/* <mark> <size> <lower> <upper> setcacheparams - */
+private int
+zsetcacheparams(register os_ptr op)
+{
+ uint params[3];
+ int i, code;
+ os_ptr opp = op;
+
+ for (i = 0; i < 3 && !r_has_type(opp, t_mark); i++, opp--) {
+ check_int_leu(*opp, max_uint);
+ params[i] = opp->value.intval;
+ }
+ switch (i) {
+ case 3:
+ if ((code = gs_setcachesize(ifont_dir, params[2])) < 0)
+ return code;
+ case 2:
+ if ((code = gs_setcachelower(ifont_dir, params[1])) < 0)
+ return code;
+ case 1:
+ if ((code = gs_setcacheupper(ifont_dir, params[0])) < 0)
+ return code;
+ case 0:;
+ }
+ return zcleartomark(op);
+}
+
+/* - currentcacheparams <mark> <size> <lower> <upper> */
+private int
+zcurrentcacheparams(register os_ptr op)
+{
+ uint params[3];
+
+ params[0] = gs_currentcachesize(ifont_dir);
+ params[1] = gs_currentcachelower(ifont_dir);
+ params[2] = gs_currentcacheupper(ifont_dir);
+ push(4);
+ make_mark(op - 3);
+ make_uint_array(op - 2, params, 3);
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zfont_op_defs[] =
+{
+ {"0currentfont", zcurrentfont},
+ {"2makefont", zmakefont},
+ {"2scalefont", zscalefont},
+ {"1setfont", zsetfont},
+ {"0cachestatus", zcachestatus},
+ {"1setcachelimit", zsetcachelimit},
+ {"1setcacheparams", zsetcacheparams},
+ {"0currentcacheparams", zcurrentcacheparams},
+ op_def_end(zfont_init)
+};
+
+/* ------ Subroutines ------ */
+
+/* Validate a font parameter. */
+int
+font_param(const ref * pfdict, gs_font ** ppfont)
+{ /*
+ * Check that pfdict is a read-only dictionary, that it has a FID
+ * entry whose value is a fontID, and that the fontID points to a
+ * gs_font structure whose associated PostScript dictionary is
+ * pfdict.
+ */
+ ref *pid;
+ gs_font *pfont;
+ const font_data *pdata;
+
+ check_type(*pfdict, t_dictionary);
+ if (dict_find_string(pfdict, "FID", &pid) <= 0 ||
+ !r_has_type(pid, t_fontID)
+ )
+ return_error(e_invalidfont);
+ pfont = r_ptr(pid, gs_font);
+ pdata = pfont->client_data;
+ if (!obj_eq(&pdata->dict, pfdict))
+ return_error(e_invalidfont);
+ *ppfont = pfont;
+ if (pfont == 0)
+ return_error(e_invalidfont); /* unregistered font */
+ return 0;
+}
+
+/* Add the FID entry to a font dictionary. */
+int
+add_FID(ref * fp /* t_dictionary */ , gs_font * pfont)
+{
+ ref fid;
+
+ make_tav_new(&fid, t_fontID, a_readonly | icurrent_space,
+ pstruct, (void *)pfont);
+ return dict_put_string(fp, "FID", &fid);
+}
+
+/* Make a transformed font (common code for makefont/scalefont). */
+private int
+make_font(os_ptr op, const gs_matrix * pmat)
+{
+ os_ptr fp = op - 1;
+ gs_font *oldfont, *newfont;
+ int code;
+ ref *pencoding = 0;
+
+ code = font_param(fp, &oldfont);
+ if (code < 0)
+ return code;
+ {
+ uint space = ialloc_space(idmemory);
+
+ ialloc_set_space(idmemory, r_space(fp));
+ if (dict_find_string(fp, "Encoding", &pencoding) > 0 &&
+ !r_is_array(pencoding)
+ )
+ code = gs_note_error(e_invalidfont);
+ else {
+ /*
+ * Temporarily substitute the new dictionary
+ * for the old one, in case the Encoding changed.
+ */
+ ref olddict;
+
+ olddict = *pfont_dict(oldfont);
+ *pfont_dict(oldfont) = *fp;
+ code = gs_makefont(ifont_dir, oldfont, pmat, &newfont);
+ *pfont_dict(oldfont) = olddict;
+ }
+ ialloc_set_space(idmemory, space);
+ }
+ if (code < 0)
+ return code;
+ /*
+ * We have to allow for the possibility that the font's Encoding
+ * is different from that of the base font. Note that the
+ * font_data of the new font was simply copied from the old one.
+ */
+ if (pencoding != 0 &&
+ !obj_eq(pencoding, &pfont_data(newfont)->Encoding)
+ ) {
+ if (newfont->FontType == ft_composite)
+ return_error(e_rangecheck);
+ /* We should really do validity checking here.... */
+ ref_assign(&pfont_data(newfont)->Encoding, pencoding);
+ lookup_gs_simple_font_encoding((gs_font_base *) newfont);
+ }
+ *fp = *pfont_dict(newfont);
+ pop(1);
+ return 0;
+}
+/* Create the transformed font dictionary. */
+/* This is the make_font completion procedure for all non-composite fonts */
+/* created at the interpreter level (see build_gs_simple_font in zfont2.c.) */
+int
+zbase_make_font(gs_font_dir * pdir, const gs_font * oldfont,
+ const gs_matrix * pmat, gs_font ** ppfont)
+{
+ /*
+ * We must call gs_base_make_font so that the XUID gets copied
+ * if necessary.
+ */
+ int code = gs_base_make_font(pdir, oldfont, pmat, ppfont);
+
+ if (code < 0)
+ return code;
+ return zdefault_make_font(pdir, oldfont, pmat, ppfont);
+}
+int
+zdefault_make_font(gs_font_dir * pdir, const gs_font * oldfont,
+ const gs_matrix * pmat, gs_font ** ppfont)
+{
+ gs_font *newfont = *ppfont;
+ ref *fp = pfont_dict(oldfont);
+ font_data *pdata;
+ ref newdict, newmat, scalemat;
+ uint dlen = dict_maxlength(fp);
+ uint mlen = dict_length(fp) + 3; /* FontID, OrigFont, ScaleMatrix */
+ int code;
+
+ if (dlen < mlen)
+ dlen = mlen;
+ if ((pdata = ialloc_struct(font_data, &st_font_data,
+ "make_font(font_data)")) == 0
+ )
+ return_error(e_VMerror);
+ if ((code = dict_create(dlen, &newdict)) < 0 ||
+ (code = dict_copy(fp, &newdict)) < 0 ||
+ (code = ialloc_ref_array(&newmat, a_all, 12, "make_font(matrices)")) < 0
+ )
+ return code;
+ refset_null(newmat.value.refs, 12);
+ ref_assign(&scalemat, &newmat);
+ r_set_size(&scalemat, 6);
+ scalemat.value.refs += 6;
+ /*
+ * Create the scaling matrix. We could do this several different
+ * ways: by "dividing" the new FontMatrix by the base FontMatrix, by
+ * multiplying the current scaling matrix by a ScaleMatrix kept in
+ * the gs_font, or by multiplying the current scaling matrix by the
+ * ScaleMatrix from the font dictionary. We opt for the last of
+ * these.
+ */
+ {
+ gs_matrix scale, prev_scale;
+ ref *ppsm;
+
+ if (!(dict_find_string(fp, "ScaleMatrix", &ppsm) > 0 &&
+ read_matrix(ppsm, &prev_scale) >= 0 &&
+ gs_matrix_multiply(pmat, &prev_scale, &scale) >= 0)
+ )
+ scale = *pmat;
+ write_matrix(&scalemat, &scale);
+ }
+ r_clear_attrs(&scalemat, a_write);
+ r_set_size(&newmat, 6);
+ write_matrix(&newmat, &newfont->FontMatrix);
+ r_clear_attrs(&newmat, a_write);
+ if ((code = dict_put_string(&newdict, "FontMatrix", &newmat)) < 0 ||
+ (code = dict_put_string(&newdict, "OrigFont", pfont_dict(oldfont->base))) < 0 ||
+ (code = dict_put_string(&newdict, "ScaleMatrix", &scalemat)) < 0 ||
+ (code = add_FID(&newdict, newfont)) < 0
+ )
+ return code;
+ newfont->client_data = pdata;
+ *pdata = *pfont_data(oldfont);
+ pdata->dict = newdict;
+ r_clear_attrs(dict_access_ref(&newdict), a_write);
+ return 0;
+}
+
+/* Convert an array of (unsigned) integers to stack form. */
+private void
+make_uint_array(register os_ptr op, const uint * intp, int count)
+{
+ int i;
+
+ for (i = 0; i < count; i++, op++, intp++)
+ make_int(op, *intp);
+}
+
+/* Remove scaled font and character cache entries that would be */
+/* invalidated by a restore. */
+private bool
+purge_if_name_removed(cached_char * cc, void *vsave)
+{
+ return alloc_name_index_is_since_save(cc->code, vsave);
+}
+void
+font_restore(const alloc_save_t * save)
+{
+ gs_font_dir *pdir = ifont_dir;
+
+ if (pdir == 0) /* not initialized yet */
+ return;
+
+ /* Purge original (unscaled) fonts. */
+
+ {
+ gs_font *pfont;
+
+otop:
+ for (pfont = pdir->orig_fonts; pfont != 0;
+ pfont = pfont->next
+ ) {
+ if (alloc_is_since_save((char *)pfont, save)) {
+ gs_purge_font(pfont);
+ goto otop;
+ }
+ }
+ }
+
+ /* Purge cached scaled fonts. */
+
+ {
+ gs_font *pfont;
+
+top:
+ for (pfont = pdir->scaled_fonts; pfont != 0;
+ pfont = pfont->next
+ ) {
+ if (alloc_is_since_save((char *)pfont, save)) {
+ gs_purge_font(pfont);
+ goto top;
+ }
+ }
+ }
+
+ /* Purge xfonts and uncached scaled fonts. */
+
+ {
+ cached_fm_pair *pair;
+ uint n;
+
+ for (pair = pdir->fmcache.mdata, n = pdir->fmcache.mmax;
+ n > 0; pair++, n--
+ )
+ if (!fm_pair_is_free(pair)) {
+ if ((uid_is_XUID(&pair->UID) &&
+ alloc_is_since_save((char *)pair->UID.xvalues,
+ save))
+ ) {
+ gs_purge_fm_pair(pdir, pair, 0);
+ continue;
+ }
+ if (pair->font != 0 &&
+ alloc_is_since_save((char *)pair->font, save)
+ ) {
+ if (!uid_is_valid(&pair->UID)) {
+ gs_purge_fm_pair(pdir, pair, 0);
+ continue;
+ }
+ /* Don't discard pairs with a surviving UID. */
+ pair->font = 0;
+ }
+ if (pair->xfont != 0 &&
+ alloc_is_since_save((char *)pair->xfont, save)
+ )
+ gs_purge_fm_pair(pdir, pair, 1);
+ }
+ }
+
+ /* Purge characters with names about to be removed. */
+ /* We only need to do this if any new names have been created */
+ /* since the save. */
+
+ if (alloc_any_names_since_save(save))
+ gx_purge_selected_cached_chars(pdir, purge_if_name_removed,
+ (void *)save);
+
+}
diff --git a/pstoraster/zfont0.c b/pstoraster/zfont0.c
new file mode 100644
index 000000000..a331047ce
--- /dev/null
+++ b/pstoraster/zfont0.c
@@ -0,0 +1,346 @@
+/* Copyright (C) 1991, 1992, 1993, 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$ */
+/* Composite font creation operator */
+#include "ghost.h"
+#include "oper.h"
+#include "gsstruct.h"
+/*
+ * The following lines used to say:
+ * #include "gsmatrix.h"
+ * #include "gxdevice.h" /. for gxfont.h ./
+ * Tony Li says the longer list is necessary to keep the GNU compiler
+ * happy, but this is pretty hard to understand....
+ */
+#include "gxfixed.h"
+#include "gxmatrix.h"
+#include "gzstate.h" /* must precede gxdevice */
+#include "gxdevice.h" /* must precede gxfont */
+#include "gschar.h"
+#include "gxfcmap.h"
+#include "gxfont.h"
+#include "gxfont0.h"
+#include "bfont.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "idparam.h"
+#include "igstate.h"
+#include "iname.h"
+#include "store.h"
+
+/* Composite font procedures */
+extern font_proc_init_fstack(gs_type0_init_fstack);
+extern font_proc_define_font(gs_type0_define_font);
+extern font_proc_make_font(gs_type0_make_font);
+extern font_proc_next_glyph(gs_type0_next_glyph);
+
+/* Imported from zfcmap.c */
+int ztype0_get_cmap(P3(const gs_cmap ** ppcmap, const ref * pfdepvector,
+ const ref * op));
+
+/* Forward references */
+private font_proc_define_font(ztype0_define_font);
+private font_proc_make_font(ztype0_make_font);
+private int ensure_char_entry(P4(os_ptr, const char *, byte *, int));
+
+/* <string|name> <font_dict> .buildfont0 <string|name> <font> */
+/* Build a type 0 (composite) font. */
+private int
+zbuildfont0(os_ptr op)
+{
+ gs_type0_data data;
+ ref fdepvector;
+ ref *pprefenc;
+ gs_font_type0 *pfont;
+ font_data *pdata;
+ ref save_FID;
+ int i;
+ int code = 0;
+
+ check_type(*op, t_dictionary);
+ {
+ ref *pfmaptype;
+ ref *pfdepvector;
+
+ if (dict_find_string(op, "FMapType", &pfmaptype) <= 0 ||
+ !r_has_type(pfmaptype, t_integer) ||
+ pfmaptype->value.intval < (int)fmap_type_min ||
+ pfmaptype->value.intval > (int)fmap_type_max ||
+ dict_find_string(op, "FDepVector", &pfdepvector) <= 0 ||
+ !r_is_array(pfdepvector)
+ )
+ return_error(e_invalidfont);
+ data.FMapType = (fmap_type) pfmaptype->value.intval;
+ /*
+ * Adding elements below could cause the font dictionary to be
+ * resized, which would invalidate pfdepvector.
+ */
+ fdepvector = *pfdepvector;
+ }
+ /* Check that every element of the FDepVector is a font. */
+ data.fdep_size = r_size(&fdepvector);
+ for (i = 0; i < data.fdep_size; i++) {
+ ref fdep;
+ gs_font *psub;
+
+ array_get(&fdepvector, i, &fdep);
+ if ((code = font_param(&fdep, &psub)) < 0)
+ return code;
+ /*
+ * Check the inheritance rules. Allowed configurations
+ * (paths from root font) are defined by the regular
+ * expression:
+ * (shift | double_escape escape* | escape*)
+ * non_modal* non_composite
+ */
+ if (psub->FontType == ft_composite) {
+ const gs_font_type0 *const psub0 = (const gs_font_type0 *)psub;
+ fmap_type fmt = psub0->data.FMapType;
+
+ if (fmt == fmap_double_escape ||
+ fmt == fmap_shift ||
+ (fmt == fmap_escape &&
+ !(data.FMapType == fmap_escape ||
+ data.FMapType == fmap_double_escape))
+ )
+ return_error(e_invalidfont);
+ }
+ }
+ switch (data.FMapType) {
+ case fmap_escape:
+ case fmap_double_escape: /* need EscChar */
+ code = ensure_char_entry(op, "EscChar", &data.EscChar, 255);
+ break;
+ case fmap_shift: /* need ShiftIn & ShiftOut */
+ code = ensure_char_entry(op, "ShiftIn", &data.ShiftIn, 15);
+ if (code >= 0)
+ code = ensure_char_entry(op, "ShiftOut", &data.ShiftOut, 14);
+ break;
+ case fmap_SubsVector: /* need SubsVector */
+ {
+ ref *psubsvector;
+ uint svsize;
+
+ if (dict_find_string(op, "SubsVector", &psubsvector) <= 0 ||
+ !r_has_type(psubsvector, t_string) ||
+ (svsize = r_size(psubsvector)) == 0 ||
+ (data.subs_width = (int)*psubsvector->value.bytes + 1) > 4 ||
+ (svsize - 1) % data.subs_width != 0
+ )
+ return_error(e_invalidfont);
+ data.subs_size = (svsize - 1) / data.subs_width;
+ data.SubsVector.data = psubsvector->value.bytes + 1;
+ data.SubsVector.size = svsize - 1;
+ } break;
+ case fmap_CMap: /* need CMap */
+ code = ztype0_get_cmap(&data.CMap, (const ref *)&fdepvector,
+ (const ref *)op);
+ break;
+ default:
+ ;
+ }
+ if (code < 0)
+ return code;
+ /*
+ * Save the old FID in case we have to back out.
+ * build_gs_font will return an error if there is a FID entry
+ * but it doesn't reference a valid font.
+ */
+ {
+ ref *pfid;
+
+ if (dict_find_string(op, "FID", &pfid) <= 0)
+ make_null(&save_FID);
+ else
+ save_FID = *pfid;
+ }
+ {
+ build_proc_refs build;
+
+ code = build_proc_name_refs(&build,
+ "%Type0BuildChar", "%Type0BuildGlyph");
+ if (code < 0)
+ return code;
+ code = build_gs_font(op, (gs_font **) & pfont,
+ ft_composite, &st_gs_font_type0, &build,
+ bf_options_none);
+ }
+ if (code != 0)
+ return code;
+ /* Fill in the rest of the basic font data. */
+ pfont->procs.init_fstack = gs_type0_init_fstack;
+ pfont->procs.next_char = 0; /* superseded by next_glyph */
+ pfont->procs.define_font = ztype0_define_font;
+ pfont->procs.make_font = ztype0_make_font;
+ pfont->procs.next_glyph = gs_type0_next_glyph;
+ if (dict_find_string(op, "PrefEnc", &pprefenc) <= 0) {
+ ref nul;
+
+ make_null_new(&nul);
+ if ((code = dict_put_string(op, "PrefEnc", &nul)) < 0)
+ goto fail;
+ }
+ /* Fill in the font data */
+ pdata = pfont_data(pfont);
+ data.encoding_size = r_size(&pdata->Encoding);
+ data.Encoding =
+ (uint *) ialloc_byte_array(data.encoding_size, sizeof(uint),
+ "buildfont0(Encoding)");
+ if (data.Encoding == 0) {
+ code = gs_note_error(e_VMerror);
+ goto fail;
+ }
+ /* Fill in the encoding vector, checking to make sure that */
+ /* each element is an integer between 0 and fdep_size-1. */
+ for (i = 0; i < data.encoding_size; i++) {
+ ref enc;
+
+ array_get(&pdata->Encoding, i, &enc);
+ if (!r_has_type(&enc, t_integer)) {
+ code = gs_note_error(e_typecheck);
+ goto fail;
+ }
+ if ((ulong) enc.value.intval >= data.fdep_size) {
+ code = gs_note_error(e_rangecheck);
+ goto fail;
+ }
+ data.Encoding[i] = (uint) enc.value.intval;
+ }
+ data.FDepVector =
+ ialloc_struct_array(data.fdep_size, gs_font *,
+ &st_gs_font_ptr_element,
+ "buildfont0(FDepVector)");
+ if (data.FDepVector == 0) {
+ code = gs_note_error(e_VMerror);
+ goto fail;
+ }
+ for (i = 0; i < data.fdep_size; i++) {
+ ref fdep;
+ ref *pfid;
+
+ array_get(&fdepvector, i, &fdep);
+ /* The lookup can't fail, because of the pre-check above. */
+ dict_find_string(&fdep, "FID", &pfid);
+ data.FDepVector[i] = r_ptr(pfid, gs_font);
+ }
+ pfont->data = data;
+ code = define_gs_font((gs_font *) pfont);
+ if (code >= 0)
+ return code;
+fail:
+ /* Undo the insertion of the FID entry in the dictionary. */
+ if (r_has_type(&save_FID, t_null)) {
+ ref rnfid;
+
+ name_enter_string("FID", &rnfid);
+ dict_undef(op, &rnfid);
+ } else
+ dict_put_string(op, "FID", &save_FID);
+ gs_free_object(pfont->memory, pfont, "buildfont0(font)");
+ return code;
+}
+/* If a newly defined or scaled composite font had to scale */
+/* any composite sub-fonts, adjust the parent font's FDepVector. */
+/* This is called only if gs_type0_define/make_font */
+/* actually changed the FDepVector. */
+private int
+ztype0_adjust_FDepVector(gs_font_type0 * pfont)
+{
+ gs_font **pdep = pfont->data.FDepVector;
+ ref newdep;
+ uint fdep_size = pfont->data.fdep_size;
+ ref *prdep;
+ uint i;
+ int code = ialloc_ref_array(&newdep, a_readonly, fdep_size,
+ "ztype0_adjust_matrix");
+
+ if (code < 0)
+ return code;
+ for (prdep = newdep.value.refs, i = 0; i < fdep_size; i++, prdep++) {
+ const ref *pdict = pfont_dict(pdep[i]);
+
+ ref_assign_new(prdep, pdict);
+ }
+ return dict_put_string(pfont_dict(pfont), "FDepVector", &newdep);
+}
+private int
+ztype0_define_font(gs_font_dir * pdir, gs_font * pfont)
+{
+ gs_font_type0 *const pfont0 = (gs_font_type0 *)pfont;
+ gs_font **pdep = pfont0->data.FDepVector;
+ int code = gs_type0_define_font(pdir, pfont);
+
+ if (code < 0 || pfont0->data.FDepVector == pdep)
+ return code;
+ return ztype0_adjust_FDepVector(pfont0);
+}
+private int
+ztype0_make_font(gs_font_dir * pdir, const gs_font * pfont,
+ const gs_matrix * pmat, gs_font ** ppfont)
+{
+ gs_font_type0 **const ppfont0 = (gs_font_type0 **)ppfont;
+ gs_font **pdep = (*ppfont0)->data.FDepVector;
+ int code;
+
+ code = zdefault_make_font(pdir, pfont, pmat, ppfont);
+ if (code < 0)
+ return code;
+ code = gs_type0_make_font(pdir, pfont, pmat, ppfont);
+ if (code < 0)
+ return code;
+ if ((*ppfont0)->data.FDepVector == pdep)
+ return 0;
+ return ztype0_adjust_FDepVector(*ppfont0);
+}
+
+/* ------ Internal routines ------ */
+
+/* Find or add a character entry in a font dictionary. */
+private int
+ensure_char_entry(os_ptr op, const char *kstr,
+ byte * pvalue, int default_value)
+{
+ ref *pentry;
+
+ if (dict_find_string(op, kstr, &pentry) <= 0) {
+ ref ent;
+
+ make_int(&ent, default_value);
+ *pvalue = (byte) default_value;
+ return dict_put_string(op, kstr, &ent);
+ } else {
+ check_int_leu_only(*pentry, 255);
+ *pvalue = (byte) pentry->value.intval;
+ return 0;
+ }
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zfont0_op_defs[] =
+{
+ {"2.buildfont0", zbuildfont0},
+ op_def_end(0)
+};
diff --git a/pstoraster/zfont1.c b/pstoraster/zfont1.c
new file mode 100644
index 000000000..525167bc1
--- /dev/null
+++ b/pstoraster/zfont1.c
@@ -0,0 +1,291 @@
+/* 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$ */
+/* Type 1 and Type 4 font creation operator */
+#include "ghost.h"
+#include "oper.h"
+#include "gxfixed.h"
+#include "gsmatrix.h"
+#include "gxdevice.h"
+#include "gschar.h"
+#include "gxfont.h"
+#include "gxfont1.h"
+#include "bfont.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "idparam.h"
+#include "store.h"
+
+/*#define TEST*/
+
+/* Type 1 auxiliary procedures (defined in zchar1.c) */
+extern const gs_type1_data_procs_t z1_data_procs;
+
+/* Default value of lenIV */
+#define DEFAULT_LENIV_1 4
+#define DEFAULT_LENIV_2 (-1)
+
+/* Private utilities */
+private uint
+subr_bias(const ref * psubrs)
+{
+ uint size = r_size(psubrs);
+
+ return (size < 1240 ? 107 : size < 33900 ? 1131 : 32768);
+}
+private void
+find_zone_height(float *pmax_height, int count, const float *values)
+{
+ int i;
+ float zone_height;
+
+ for (i = 0; i < count; i += 2)
+ if ((zone_height = values[i + 1] - values[i]) > *pmax_height)
+ *pmax_height = zone_height;
+}
+
+/* Build a Type 1 or Type 4 font. */
+private int
+buildfont1or4(os_ptr op, build_proc_refs * pbuild, font_type ftype,
+ build_font_options_t options)
+{
+ gs_type1_data data1;
+ ref no_subrs;
+ ref *pothersubrs = &no_subrs;
+ ref *psubrs = &no_subrs;
+ ref *pglobalsubrs = &no_subrs;
+ ref *pprivate;
+ gs_font_type1 *pfont;
+ font_data *pdata;
+ int code;
+
+ check_type(*op, t_dictionary);
+ if (dict_find_string(op, "Private", &pprivate) <= 0 ||
+ !r_has_type(pprivate, t_dictionary)
+ )
+ return_error(e_invalidfont);
+ make_empty_array(&no_subrs, 0);
+ if (dict_find_string(pprivate, "OtherSubrs", &pothersubrs) > 0) {
+ if (!r_is_array(pothersubrs))
+ return_error(e_typecheck);
+ }
+ if (dict_find_string(pprivate, "Subrs", &psubrs) > 0) {
+ if (!r_is_array(psubrs))
+ return_error(e_typecheck);
+ }
+ if ((code = dict_int_param(op, "CharstringType", 1, 2, 1,
+ &data1.CharstringType)) < 0
+ )
+ return code;
+ /* Get information specific to Type 2 charstrings. */
+ if (data1.CharstringType == 2) {
+ float dwx, nwx;
+
+ data1.subroutineNumberBias = subr_bias(psubrs);
+ if (dict_find_string(pprivate, "GlobalSubrs", &pglobalsubrs) > 0) {
+ if (!r_is_array(pglobalsubrs))
+ return_error(e_typecheck);
+ }
+ data1.gsubrNumberBias = subr_bias(pglobalsubrs);
+ if ((code = dict_uint_param(pprivate, "gsubrNumberBias",
+ 0, max_uint, data1.gsubrNumberBias,
+ &data1.gsubrNumberBias)) < 0 ||
+ (code = dict_float_param(pprivate, "defaultWidthX", 0.0,
+ &dwx)) < 0 ||
+ (code = dict_float_param(pprivate, "nominalWidthX", 0.0,
+ &nwx)) < 0
+ )
+ return code;
+ data1.defaultWidthX = float2fixed(dwx);
+ data1.nominalWidthX = float2fixed(nwx);
+ {
+ ref *pirs;
+
+ if (dict_find_string(pprivate, "initialRandomSeed", &pirs) <= 0)
+ data1.initialRandomSeed = 0;
+ else if (!r_has_type(pirs, t_integer))
+ return_error(e_typecheck);
+ else
+ data1.initialRandomSeed = pirs->value.intval;
+ }
+ data1.lenIV = DEFAULT_LENIV_2;
+ } else {
+ data1.subroutineNumberBias = 0;
+ data1.gsubrNumberBias = 0;
+ data1.lenIV = DEFAULT_LENIV_1;
+ }
+ /* Get the rest of the information from the Private dictionary. */
+ if ((code = dict_int_param(pprivate, "lenIV", -1, 255, data1.lenIV,
+ &data1.lenIV)) < 0 ||
+ (code = dict_uint_param(pprivate, "subroutineNumberBias",
+ 0, max_uint, data1.subroutineNumberBias,
+ &data1.subroutineNumberBias)) < 0 ||
+ (code = dict_int_param(pprivate, "BlueFuzz", 0, 1999, 1,
+ &data1.BlueFuzz)) < 0 ||
+ (code = dict_float_param(pprivate, "BlueScale", 0.039625,
+ &data1.BlueScale)) < 0 ||
+ (code = dict_float_param(pprivate, "BlueShift", 7.0,
+ &data1.BlueShift)) < 0 ||
+ (code = data1.BlueValues.count =
+ dict_float_array_param(pprivate, "BlueValues", max_BlueValues * 2,
+ &data1.BlueValues.values[0], NULL)) < 0 ||
+ (code = dict_float_param(pprivate, "ExpansionFactor", 0.06,
+ &data1.ExpansionFactor)) < 0 ||
+ (code = data1.FamilyBlues.count =
+ dict_float_array_param(pprivate, "FamilyBlues", max_FamilyBlues * 2,
+ &data1.FamilyBlues.values[0], NULL)) < 0 ||
+ (code = data1.FamilyOtherBlues.count =
+ dict_float_array_param(pprivate,
+ "FamilyOtherBlues", max_FamilyOtherBlues * 2,
+ &data1.FamilyOtherBlues.values[0], NULL)) < 0 ||
+ (code = dict_bool_param(pprivate, "ForceBold", false,
+ &data1.ForceBold)) < 0 ||
+ (code = dict_int_param(pprivate, "LanguageGroup", 0, 1, 0,
+ &data1.LanguageGroup)) < 0 ||
+ (code = data1.OtherBlues.count =
+ dict_float_array_param(pprivate, "OtherBlues", max_OtherBlues * 2,
+ &data1.OtherBlues.values[0], NULL)) < 0 ||
+ (code = dict_bool_param(pprivate, "RndStemUp", true,
+ &data1.RndStemUp)) < 0 ||
+ (code = data1.StdHW.count =
+ dict_float_array_param(pprivate, "StdHW", 1,
+ &data1.StdHW.values[0], NULL)) < 0 ||
+ (code = data1.StdVW.count =
+ dict_float_array_param(pprivate, "StdVW", 1,
+ &data1.StdVW.values[0], NULL)) < 0 ||
+ (code = data1.StemSnapH.count =
+ dict_float_array_param(pprivate, "StemSnapH", max_StemSnap,
+ &data1.StemSnapH.values[0], NULL)) < 0 ||
+ (code = data1.StemSnapV.count =
+ dict_float_array_param(pprivate, "StemSnapV", max_StemSnap,
+ &data1.StemSnapV.values[0], NULL)) < 0 ||
+ /* The WeightVector is in the font dictionary, not Private. */
+ (code = data1.WeightVector.count =
+ dict_float_array_param(op, "WeightVector", max_WeightVector,
+ data1.WeightVector.values, NULL)) < 0
+ )
+ return code;
+ /*
+ * According to section 5.6 of the "Adobe Type 1 Font Format",
+ * there is a requirement that BlueScale times the maximum
+ * alignment zone height must be less than 1. Some fonts
+ * produced by Fontographer have ridiculously large BlueScale
+ * values, so we force BlueScale back into range here.
+ */
+ {
+ float max_zone_height = 1.0;
+
+#define SCAN_ZONE(z)\
+ find_zone_height(&max_zone_height, data1.z.count, data1.z.values);
+
+ SCAN_ZONE(BlueValues);
+ SCAN_ZONE(OtherBlues);
+ SCAN_ZONE(FamilyBlues);
+ SCAN_ZONE(FamilyOtherBlues);
+
+#undef SCAN_ZONE
+
+ if (data1.BlueScale * max_zone_height > 1.0)
+ data1.BlueScale = 1.0 / max_zone_height;
+ }
+ /* Do the work common to primitive font types. */
+ code = build_gs_primitive_font(op, (gs_font_base **) & pfont, ftype,
+ &st_gs_font_type1, pbuild, options);
+ if (code != 0)
+ return code;
+ /* This is a new font, fill it in. */
+ pdata = pfont_data(pfont);
+ pfont->data = data1;
+ ref_assign(&pdata->u.type1.OtherSubrs, pothersubrs);
+ ref_assign(&pdata->u.type1.Subrs, psubrs);
+ ref_assign(&pdata->u.type1.GlobalSubrs, pglobalsubrs);
+ pfont->data.procs = &z1_data_procs;
+ pfont->data.proc_data = (char *)pdata;
+ return define_gs_font((gs_font *)pfont);
+}
+
+/* <string|name> <font_dict> .buildfont1 <string|name> <font> */
+/* Build a type 1 (Adobe encrypted) font. */
+private int
+zbuildfont1(os_ptr op)
+{
+ build_proc_refs build;
+ int code = build_proc_name_refs(&build,
+ "%Type1BuildChar", "%Type1BuildGlyph");
+
+ if (code < 0)
+ return code;
+ return buildfont1or4(op, &build, ft_encrypted, bf_notdef_required);
+}
+
+/* <string|name> <font_dict> .buildfont4 <string|name> <font> */
+/* Build a type 4 (disk-based Adobe encrypted) font. */
+private int
+zbuildfont4(os_ptr op)
+{
+ build_proc_refs build;
+ int code = build_gs_font_procs(op, &build);
+
+ if (code < 0)
+ return code;
+ return buildfont1or4(op, &build, ft_disk_based, bf_options_none);
+}
+
+#ifdef TEST
+
+#include "igstate.h"
+#include "stream.h"
+#include "files.h"
+
+/* <file> .printfont1 - */
+private int
+zprintfont1(os_ptr op)
+{
+ const gs_font *pfont = gs_currentfont(igs);
+ stream *s;
+ int code;
+
+ if (pfont->FontType != ft_encrypted)
+ return_error(e_rangecheck);
+ check_write_file(s, op);
+ code = psdf_embed_type1_font(s, (gs_font_type1 *) pfont);
+ if (code >= 0)
+ pop(1);
+ return code;
+}
+
+#endif
+
+/* ------ Initialization procedure ------ */
+
+const op_def zfont1_op_defs[] =
+{
+ {"2.buildfont1", zbuildfont1},
+ {"2.buildfont4", zbuildfont4},
+#ifdef TEST
+ {"2.printfont1", zprintfont1},
+#endif
+ op_def_end(0)
+};
diff --git a/pstoraster/zfont2.c b/pstoraster/zfont2.c
new file mode 100644
index 000000000..0ef13e82b
--- /dev/null
+++ b/pstoraster/zfont2.c
@@ -0,0 +1,553 @@
+/* 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$ */
+/* Font creation utilities */
+#include "memory_.h"
+#include "string_.h"
+#include "ghost.h"
+#include "oper.h"
+#include "gxfixed.h"
+#include "gsmatrix.h"
+#include "gxdevice.h"
+#include "gschar.h"
+#include "gxfont.h"
+#include "bfont.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "idparam.h"
+#include "ilevel.h"
+#include "iname.h"
+#include "interp.h" /* for initial_enter_name */
+#include "ipacked.h"
+#include "istruct.h"
+#include "store.h"
+
+/* Registered encodings. See ifont.h for documentation. */
+ref registered_Encodings;
+private ref *const registered_Encodings_p = &registered_Encodings;
+
+/* Structure descriptor */
+public_st_font_data();
+
+/* Initialize the font building operators */
+private void
+zfont2_init(void)
+{ /* Initialize the registered Encodings. */
+ int i;
+
+ ialloc_ref_array(&registered_Encodings, a_all,
+ registered_Encodings_countof,
+ "registered_Encodings");
+ for (i = 0; i < registered_Encodings_countof; i++)
+ make_empty_array(&registered_Encoding(i), 0);
+ initial_enter_name("registeredencodings", &registered_Encodings);
+ gs_register_ref_root(imemory, NULL, (void **)&registered_Encodings_p,
+ "registered_Encodings");
+}
+
+/* <string|name> <font_dict> .buildfont3 <string|name> <font> */
+/* Build a type 3 (user-defined) font. */
+private int
+zbuildfont3(os_ptr op)
+{
+ int code;
+ build_proc_refs build;
+ gs_font_base *pfont;
+
+ check_type(*op, t_dictionary);
+ code = build_gs_font_procs(op, &build);
+ if (code < 0)
+ return code;
+ code = build_gs_simple_font(op, &pfont, ft_user_defined,
+ &st_gs_font_base, &build, bf_options_none);
+ if (code < 0)
+ return code;
+ return define_gs_font((gs_font *) pfont);
+}
+
+/* Encode a character. */
+private gs_glyph
+zfont_encode_char(gs_show_enum * penum, gs_font * pfont, gs_char * pchr)
+{
+ const ref *pencoding = &pfont_data(pfont)->Encoding;
+ ulong index = *pchr; /* work around VAX widening bug */
+ ref cname;
+ int code = array_get(pencoding, (long)index, &cname);
+
+ if (code < 0 || !r_has_type(&cname, t_name))
+ return gs_no_glyph;
+ return (gs_glyph) name_index(&cname);
+}
+
+/* Encode a character in a known encoding. */
+private gs_glyph
+zfont_known_encode(gs_char chr, int encoding_index)
+{
+ ulong index = chr; /* work around VAX widening bug */
+ ref cname;
+ int code;
+
+ if (encoding_index < 0)
+ return gs_no_glyph;
+ code = array_get(&registered_Encoding(encoding_index),
+ (long)index, &cname);
+ if (code < 0 || !r_has_type(&cname, t_name))
+ return gs_no_glyph;
+ return (gs_glyph) name_index(&cname);
+}
+
+/* Get the name of a glyph. */
+/* The following typedef is needed to work around a bug in */
+/* some AIX C compilers. */
+typedef const char *const_chars;
+private const_chars
+zfont_glyph_name(gs_glyph index, uint * plen)
+{
+ ref nref, sref;
+
+ if (index >= gs_min_cid_glyph) { /* Fabricate a numeric name. */
+ char cid_name[sizeof(gs_glyph) * 3 + 1];
+ int code;
+
+ sprintf(cid_name, "%lu", (ulong) index);
+ code = name_ref((const byte *)cid_name, strlen(cid_name),
+ &nref, 1);
+ if (code < 0)
+ return 0; /* What can we possibly do here? */
+ } else
+ name_index_ref(index, &nref);
+ name_string_ref(&nref, &sref);
+ *plen = r_size(&sref);
+ return (const char *)sref.value.const_bytes;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zfont2_op_defs[] =
+{
+ {"2.buildfont3", zbuildfont3},
+ op_def_end(zfont2_init)
+};
+
+/* ------ Subroutines ------ */
+
+/* Convert strings to executable names for build_proc_refs. */
+int
+build_proc_name_refs(build_proc_refs * pbuild,
+ const char *bcstr, const char *bgstr)
+{
+ int code;
+
+ if (!bcstr)
+ make_null(&pbuild->BuildChar);
+ else {
+ if ((code = name_ref((const byte *)bcstr, strlen(bcstr), &pbuild->BuildChar, 0)) < 0)
+ return code;
+ r_set_attrs(&pbuild->BuildChar, a_executable);
+ }
+ if (!bgstr)
+ make_null(&pbuild->BuildGlyph);
+ else {
+ if ((code = name_ref((const byte *)bgstr, strlen(bgstr), &pbuild->BuildGlyph, 0)) < 0)
+ return code;
+ r_set_attrs(&pbuild->BuildGlyph, a_executable);
+ }
+ return 0;
+}
+
+/* Get the BuildChar and/or BuildGlyph routines from a (base) font. */
+int
+build_gs_font_procs(os_ptr op, build_proc_refs * pbuild)
+{
+ int ccode, gcode;
+ ref *pBuildChar;
+ ref *pBuildGlyph;
+
+ check_type(*op, t_dictionary);
+ ccode = dict_find_string(op, "BuildChar", &pBuildChar);
+ gcode = dict_find_string(op, "BuildGlyph", &pBuildGlyph);
+ if (ccode <= 0) {
+ if (gcode <= 0)
+ return_error(e_invalidfont);
+ make_null(&pbuild->BuildChar);
+ } else {
+ check_proc(*pBuildChar);
+ pbuild->BuildChar = *pBuildChar;
+ }
+ if (gcode <= 0)
+ make_null(&pbuild->BuildGlyph);
+ else {
+ check_proc(*pBuildGlyph);
+ pbuild->BuildGlyph = *pBuildGlyph;
+ }
+ return 0;
+}
+
+/* Do the common work for building a primitive font -- one whose execution */
+/* algorithm is implemented in C (Type 1, Type 4, or Type 42). */
+/* The caller guarantees that *op is a dictionary. */
+int
+build_gs_primitive_font(os_ptr op, gs_font_base ** ppfont, font_type ftype,
+ gs_memory_type_ptr_t pstype,
+ const build_proc_refs * pbuild,
+ build_font_options_t options)
+{
+ int painttype;
+ float strokewidth;
+ ref *pcharstrings = 0;
+ gs_font_base *pfont;
+ font_data *pdata;
+ int code;
+
+ code = dict_int_param(op, "PaintType", 0, 3, 0, &painttype);
+ if (code < 0)
+ return code;
+ code = dict_float_param(op, "StrokeWidth", 0.0, &strokewidth);
+ if (code < 0)
+ return code;
+ if (dict_find_string(op, "CharStrings", &pcharstrings) <= 0) {
+ if (!(options & bf_CharStrings_optional))
+ return_error(e_invalidfont);
+ } else {
+ ref *ignore;
+
+ if (!r_has_type(pcharstrings, t_dictionary))
+ return_error(e_invalidfont);
+ if ((options & bf_notdef_required) != 0 &&
+ dict_find_string(pcharstrings, ".notdef", &ignore) <= 0
+ )
+ return_error(e_invalidfont);
+ }
+ code = build_gs_simple_font(op, &pfont, ftype, pstype, pbuild, options);
+ if (code != 0)
+ return code;
+ pfont->PaintType = painttype;
+ pfont->StrokeWidth = strokewidth;
+ pdata = pfont_data(pfont);
+ if (pcharstrings)
+ ref_assign(&pdata->CharStrings, pcharstrings);
+ else
+ make_null(&pdata->CharStrings);
+ /* Check that the UniqueIDs match. This is part of the */
+ /* Adobe protection scheme, but we may as well emulate it. */
+ if (uid_is_valid(&pfont->UID) &&
+ !dict_check_uid_param(op, &pfont->UID)
+ )
+ uid_set_invalid(&pfont->UID);
+ *ppfont = pfont;
+ return 0;
+}
+
+/* Do the common work for building a font of any non-composite FontType. */
+/* The caller guarantees that *op is a dictionary. */
+int
+build_gs_simple_font(os_ptr op, gs_font_base ** ppfont, font_type ftype,
+ gs_memory_type_ptr_t pstype,
+ const build_proc_refs * pbuild,
+ build_font_options_t options)
+{
+ double bbox[4];
+ gs_uid uid;
+ int code;
+ gs_font_base *pfont;
+
+ code = font_bbox_param(op, bbox);
+ if (code < 0)
+ return code;
+ if ((options & bf_FontBBox_required) &&
+ bbox[0] == 0 && bbox[1] == 0 && bbox[2] == 0 && bbox[3] == 0
+ )
+ return_error(e_invalidfont);
+ code = dict_uid_param(op, &uid, 0, imemory);
+ if (code < 0)
+ return code;
+ if ((options & bf_UniqueID_ignored) && uid_is_UniqueID(&uid))
+ uid_set_invalid(&uid);
+ code = build_gs_font(op, (gs_font **) ppfont, ftype, pstype, pbuild,
+ options);
+ if (code != 0) /* invalid or scaled font */
+ return code;
+ pfont = *ppfont;
+ pfont->procs.init_fstack = gs_default_init_fstack;
+ pfont->procs.next_char = gs_default_next_char;
+ pfont->procs.define_font = gs_no_define_font;
+ pfont->procs.make_font = zbase_make_font;
+ pfont->FontBBox.p.x = bbox[0];
+ pfont->FontBBox.p.y = bbox[1];
+ pfont->FontBBox.q.x = bbox[2];
+ pfont->FontBBox.q.y = bbox[3];
+ pfont->UID = uid;
+ lookup_gs_simple_font_encoding(pfont);
+ return 0;
+}
+
+/* Compare the encoding of a simple font with the registered encodings. */
+void
+lookup_gs_simple_font_encoding(gs_font_base * pfont)
+{
+ const ref *pfe = &pfont_data(pfont)->Encoding;
+ int index;
+
+ for (index = registered_Encodings_countof; --index >= 0;)
+ if (obj_eq(pfe, &registered_Encoding(index)))
+ break;
+ pfont->encoding_index = index;
+ if (index < 0) { /* Look for an encoding that's "close". */
+ int near_index = -1;
+ uint esize = r_size(pfe);
+ uint best = esize / 3; /* must match at least this many */
+
+ for (index = registered_Encodings_countof; --index >= 0;) {
+ const ref *pre = &registered_Encoding(index);
+ bool r_packed = r_has_type(pre, t_shortarray);
+ bool f_packed = !r_has_type(pfe, t_array);
+ uint match = esize;
+ int i;
+ ref fchar, rchar;
+ const ref *pfchar = &fchar;
+
+ if (r_size(pre) != esize)
+ continue;
+ for (i = esize; --i >= 0;) {
+ uint rnidx;
+
+ if (r_packed)
+ rnidx = packed_name_index(pre->value.packed + i);
+ else {
+ array_get(pre, (long)i, &rchar);
+ rnidx = name_index(&rchar);
+ }
+ if (f_packed)
+ array_get(pfe, (long)i, &fchar);
+ else
+ pfchar = pfe->value.const_refs + i;
+ if (!r_has_type(pfchar, t_name) ||
+ name_index(pfchar) != rnidx
+ )
+ if (--match <= best)
+ break;
+ }
+ if (match > best)
+ best = match,
+ near_index = index;
+ }
+ index = near_index;
+ }
+ pfont->nearest_encoding_index = index;
+}
+
+/* Do the common work for building a font of any FontType. */
+/* The caller guarantees that *op is a dictionary. */
+/* op[-1] must be the key under which the font is being registered */
+/* in FontDirectory, normally a name or string. */
+/* Return 0 for a new font, 1 for a font made by makefont or scalefont, */
+/* or a negative error code. */
+private void get_font_name(P2(ref *, const ref *));
+private void copy_font_name(P2(gs_font_name *, const ref *));
+int
+build_gs_font(os_ptr op, gs_font ** ppfont, font_type ftype,
+ gs_memory_type_ptr_t pstype, const build_proc_refs * pbuild,
+ build_font_options_t options)
+{
+ ref kname, fname; /* t_string */
+ ref *pftype;
+ ref *pfontname;
+ ref *pmatrix;
+ gs_matrix mat;
+ ref *pencoding = 0;
+ bool bitmapwidths;
+ int exactsize, inbetweensize, transformedchar;
+ int wmode;
+ int code;
+ gs_font *pfont;
+ ref *pfid;
+ ref *aop = dict_access_ref(op);
+
+ get_font_name(&kname, op - 1);
+ if (dict_find_string(op, "FontType", &pftype) <= 0 ||
+ !r_has_type(pftype, t_integer) ||
+ pftype->value.intval != (int)ftype ||
+ dict_find_string(op, "FontMatrix", &pmatrix) <= 0 ||
+ read_matrix(pmatrix, &mat) < 0
+ )
+ return_error(e_invalidfont);
+ if (dict_find_string(op, "Encoding", &pencoding) <= 0) {
+ if (!(options & bf_Encoding_optional))
+ return_error(e_invalidfont);
+ } else {
+ if (!r_is_array(pencoding))
+ return_error(e_invalidfont);
+ }
+ if (dict_find_string(op, "FontName", &pfontname) > 0)
+ get_font_name(&fname, pfontname);
+ else
+ make_empty_string(&fname, a_readonly);
+ if ((code = dict_int_param(op, "WMode", 0, 1, 0, &wmode)) < 0 ||
+ (code = dict_bool_param(op, "BitmapWidths", false, &bitmapwidths)) < 0 ||
+ (code = dict_int_param(op, "ExactSize", 0, 2, fbit_use_bitmaps, &exactsize)) < 0 ||
+ (code = dict_int_param(op, "InBetweenSize", 0, 2, fbit_use_outlines, &inbetweensize)) < 0 ||
+ (code = dict_int_param(op, "TransformedChar", 0, 2, fbit_use_outlines, &transformedchar)) < 0
+ )
+ return code;
+ code = dict_find_string(op, "FID", &pfid);
+ if (code > 0) {
+ if (!r_has_type(pfid, t_fontID))
+ return_error(e_invalidfont);
+ /*
+ * If this font has a FID entry already, it might be
+ * a scaled font made by makefont or scalefont;
+ * in a Level 2 environment, it might be an existing font
+ * being registered under a second name, or a re-encoded
+ * font (which is questionable PostScript, but dvips
+ * is known to do this).
+ */
+ pfont = r_ptr(pfid, gs_font);
+ if (pfont->base == pfont) { /* original font */
+ if (!level2_enabled)
+ return_error(e_invalidfont);
+ if (obj_eq(pfont_dict(pfont), op)) {
+ *ppfont = pfont;
+ return 1;
+ }
+ /*
+ * This is a re-encoded font, or some other
+ * questionable situation in which the FID
+ * was preserved. Pretend the FID wasn't there.
+ */
+ } else { /* This was made by makefont or scalefont. */
+ /* Just insert the new name. */
+ code = 1;
+ goto set_name;
+ }
+ }
+ /* This is a new font. */
+ if (!r_has_attr(aop, a_write))
+ return_error(e_invalidaccess);
+ {
+ font_data *pdata;
+ ref encoding;
+ /*
+ * Make sure that we allocate the font data
+ * in the same VM as the font dictionary.
+ */
+ uint space = ialloc_space(idmemory);
+
+ /*
+ * Since add_FID may resize the dictionary and cause
+ * pencoding to become invalid, save the Encoding.
+ */
+ if (pencoding)
+ encoding = *pencoding;
+ ialloc_set_space(idmemory, r_space(op));
+ pfont = ialloc_struct(gs_font, pstype,
+ "buildfont(font)");
+ pdata = ialloc_struct(font_data, &st_font_data,
+ "buildfont(data)");
+ if (pfont == 0 || pdata == 0)
+ code = gs_note_error(e_VMerror);
+ else
+ code = add_FID(op, pfont);
+ if (code < 0) {
+ ifree_object(pdata, "buildfont(data)");
+ ifree_object(pfont, "buildfont(font)");
+ ialloc_set_space(idmemory, space);
+ return code;
+ }
+ refset_null((ref *) pdata, sizeof(font_data) / sizeof(ref));
+ ref_assign_new(&pdata->dict, op);
+ ref_assign_new(&pdata->BuildChar, &pbuild->BuildChar);
+ ref_assign_new(&pdata->BuildGlyph, &pbuild->BuildGlyph);
+ if (pencoding)
+ ref_assign_new(&pdata->Encoding, &encoding);
+ /* Clear the chain pointers so as not to confuse the memory */
+ /* manager if we bail out after returning from here. */
+ pfont->next = pfont->prev = 0;
+ pfont->memory = imemory;
+ pfont->dir = 0;
+ pfont->base = pfont;
+ pfont->client_data = pdata;
+ pfont->FontType = ftype;
+ pfont->FontMatrix = mat;
+ pfont->BitmapWidths = bitmapwidths;
+ pfont->ExactSize = (fbit_type) exactsize;
+ pfont->InBetweenSize = (fbit_type) inbetweensize;
+ pfont->TransformedChar = (fbit_type) transformedchar;
+ pfont->WMode = wmode;
+ pfont->PaintType = 0;
+ pfont->StrokeWidth = 0.0;
+ pfont->procs.build_char = gs_no_build_char;
+ pfont->procs.encode_char = zfont_encode_char;
+ pfont->procs.callbacks.glyph_name = zfont_glyph_name;
+ pfont->procs.callbacks.known_encode = zfont_known_encode;
+ ialloc_set_space(idmemory, space);
+ }
+ code = 0;
+set_name:
+ copy_font_name(&pfont->key_name, &kname);
+ copy_font_name(&pfont->font_name, &fname);
+ *ppfont = pfont;
+ return code;
+}
+
+/* Get the string corresponding to a font name. */
+/* If the font name isn't a name or a string, return an empty string. */
+private void
+get_font_name(ref * pfname, const ref * op)
+{
+ switch (r_type(op)) {
+ case t_string:
+ *pfname = *op;
+ break;
+ case t_name:
+ name_string_ref(op, pfname);
+ break;
+ default:
+ /* This is weird, but legal.... */
+ make_empty_string(pfname, a_readonly);
+ }
+}
+
+/* Copy a font name into the gs_font structure. */
+private void
+copy_font_name(gs_font_name * pfstr, const ref * pfname)
+{
+ uint size = r_size(pfname);
+
+ if (size > gs_font_name_max)
+ size = gs_font_name_max;
+ memcpy(&pfstr->chars[0], pfname->value.const_bytes, size);
+ /* Following is only for debugging printout. */
+ pfstr->chars[size] = 0;
+ pfstr->size = size;
+}
+
+/* Finish building a font, by calling gs_definefont if needed. */
+int
+define_gs_font(gs_font * pfont)
+{
+ return (pfont->base == pfont && pfont->dir == 0 ? /* i.e., unregistered original font */
+ gs_definefont(ifont_dir, pfont) :
+ 0);
+}
diff --git a/pstoraster/zfont32.c b/pstoraster/zfont32.c
new file mode 100644
index 000000000..7fba978aa
--- /dev/null
+++ b/pstoraster/zfont32.c
@@ -0,0 +1,79 @@
+/* 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$ */
+/* Type 32 font operators */
+#include "ghost.h"
+#include "oper.h"
+#include "gsccode.h" /* for gxfont.h */
+#include "gsmatrix.h"
+#include "gsutil.h"
+#include "gxfixed.h" /* for gxchar.h */
+#include "gxchar.h"
+#include "gxfont.h"
+#include "bfont.h"
+#include "store.h"
+
+/* The encode_char procedure of a Type 32 font should never be called. */
+private gs_glyph
+zfont_no_encode_char(gs_show_enum * penum, gs_font * pfont, gs_char * pchr)
+{
+ return gs_no_glyph;
+}
+
+/* <string|name> <font_dict> .buildfont32 <string|name> <font> */
+/* Build a type 32 (bitmap) font. */
+private int
+zbuildfont32(os_ptr op)
+{
+ int code;
+ build_proc_refs build;
+ gs_font_base *pfont;
+
+ check_type(*op, t_dictionary);
+ code = build_proc_name_refs(&build, NULL, "%Type32BuildGlyph");
+ if (code < 0)
+ return code;
+ code = build_gs_simple_font(op, &pfont, ft_CID_bitmap, &st_gs_font_base,
+ &build, bf_Encoding_optional);
+ if (code < 0)
+ return code;
+ /* Always transform cached bitmaps. */
+ pfont->BitmapWidths = true;
+ pfont->ExactSize = fbit_transform_bitmaps;
+ pfont->InBetweenSize = fbit_transform_bitmaps;
+ pfont->TransformedChar = fbit_transform_bitmaps;
+ /* The encode_char procedure of a Type 32 font */
+ /* should never be called. */
+ pfont->procs.encode_char = zfont_no_encode_char;
+ return define_gs_font((gs_font *) pfont);
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zfont32_op_defs[] =
+{
+ {"2.buildfont32", zbuildfont32},
+ op_def_end(0)
+};
diff --git a/pstoraster/zfont42.c b/pstoraster/zfont42.c
new file mode 100644
index 000000000..59278a265
--- /dev/null
+++ b/pstoraster/zfont42.c
@@ -0,0 +1,189 @@
+/* Copyright (C) 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$ */
+/* Type 42 font creation operator */
+#include "memory_.h"
+#include "ghost.h"
+#include "oper.h"
+#include "gsccode.h"
+#include "gsmatrix.h"
+#include "gxfont.h"
+#include "gxfont42.h"
+#include "bfont.h"
+#include "idict.h"
+#include "idparam.h"
+#include "store.h"
+
+/* Forward references */
+private int z42_string_proc(P4(gs_font_type42 *, ulong, uint, const byte **));
+private int z42_gdir_get_outline(P3(gs_font_type42 *, uint, gs_const_string *));
+
+/* <string|name> <font_dict> .buildfont11/42 <string|name> <font> */
+/* Build a type 11 (TrueType CID-keyed) or 42 (TrueType) font. */
+int
+build_gs_TrueType_font(os_ptr op, font_type ftype, const char *bcstr,
+ const char *bgstr, build_font_options_t options)
+{
+ build_proc_refs build;
+ ref sfnts, sfnts0, GlyphDirectory;
+ gs_font_type42 *pfont;
+ font_data *pdata;
+ int code;
+
+ code = build_proc_name_refs(&build, bcstr, bgstr);
+ if (code < 0)
+ return code;
+ check_type(*op, t_dictionary);
+ {
+ ref *psfnts;
+ ref *pGlyphDirectory;
+
+ if (dict_find_string(op, "sfnts", &psfnts) <= 0)
+ return_error(e_invalidfont);
+ if ((code = array_get(psfnts, 0L, &sfnts0)) < 0)
+ return code;
+ if (!r_has_type(&sfnts0, t_string))
+ return_error(e_typecheck);
+ if (dict_find_string(op, "GlyphDirectory", &pGlyphDirectory) <= 0)
+ make_null(&GlyphDirectory);
+ else if (!r_has_type(pGlyphDirectory, t_dictionary))
+ return_error(e_typecheck);
+ else
+ GlyphDirectory = *pGlyphDirectory;
+ /*
+ * Since build_gs_primitive_font may resize the dictionary and cause
+ * pointers to become invalid, save sfnts.
+ */
+ sfnts = *psfnts;
+ }
+ code = build_gs_primitive_font(op, (gs_font_base **) & pfont, ftype,
+ &st_gs_font_type42, &build, options);
+ if (code != 0)
+ return code;
+ pdata = pfont_data(pfont);
+ ref_assign(&pdata->u.type42.sfnts, &sfnts);
+ ref_assign(&pdata->u.type42.GlyphDirectory, &GlyphDirectory);
+ pfont->data.string_proc = z42_string_proc;
+ pfont->data.proc_data = (char *)pdata;
+ code = gs_type42_font_init(pfont);
+ if (code < 0)
+ return code;
+ /*
+ * Some versions of the Adobe PostScript Windows driver have a bug
+ * that causes them to output the FontBBox for Type 42 fonts in the
+ * 2048- or 4096-unit character space rather than a 1-unit space.
+ * Work around this here.
+ */
+ if (pfont->FontBBox.q.x - pfont->FontBBox.p.x > 100 ||
+ pfont->FontBBox.q.y - pfont->FontBBox.p.y > 100
+ ) {
+ float upem = pfont->data.unitsPerEm;
+
+ pfont->FontBBox.p.x /= upem;
+ pfont->FontBBox.p.y /= upem;
+ pfont->FontBBox.q.x /= upem;
+ pfont->FontBBox.q.y /= upem;
+ }
+ /*
+ * Apparently Adobe versions 2015 and later use an alternate
+ * method of accessing character outlines: instead of loca and glyf,
+ * they use a dictionary called GlyphDirectory. In this case,
+ * we use an alternate get_outline procedure.
+ */
+ if (!r_has_type(&GlyphDirectory, t_null))
+ pfont->data.get_outline = z42_gdir_get_outline;
+ return define_gs_font((gs_font *) pfont);
+}
+private int
+zbuildfont42(os_ptr op)
+{
+ return build_gs_TrueType_font(op, ft_TrueType, "%Type42BuildChar",
+ "%Type42BuildGlyph", bf_options_none);
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zfont42_op_defs[] =
+{
+ {"2.buildfont42", zbuildfont42},
+ op_def_end(0)
+};
+
+/* Get an outline from GlyphDirectory instead of loca / glyf. */
+private int
+z42_gdir_get_outline(gs_font_type42 * pfont, uint glyph_index,
+ gs_const_string * pgstr)
+{
+ const font_data *pfdata = pfont_data(pfont);
+ const ref *pgdir = &pfdata->u.type42.GlyphDirectory;
+ ref iglyph;
+ ref *pgdef;
+
+ make_int(&iglyph, glyph_index);
+ if (dict_find(pgdir, &iglyph, &pgdef) <= 0) {
+ pgstr->data = 0;
+ pgstr->size = 0;
+ } else if (!r_has_type(pgdef, t_string)) {
+ return_error(e_typecheck);
+ } else {
+ pgstr->data = pgdef->value.const_bytes;
+ pgstr->size = r_size(pgdef);
+ }
+ return 0;
+}
+
+/* Procedure for accessing the sfnts array. */
+private int
+z42_string_proc(gs_font_type42 * pfont, ulong offset, uint length,
+ const byte ** pdata)
+{
+ const font_data *pfdata = pfont_data(pfont);
+ ulong left = offset;
+ uint index = 0;
+
+ for (;; ++index) {
+ ref rstr;
+ int code = array_get(&pfdata->u.type42.sfnts, index, &rstr);
+ uint size;
+
+ if (code < 0)
+ return code;
+ if (!r_has_type(&rstr, t_string))
+ return_error(e_typecheck);
+ /*
+ * NOTE: According to the Adobe documentation, each sfnts
+ * string should have even length. If the length is odd,
+ * the additional byte is padding and should be ignored.
+ */
+ size = r_size(&rstr) & ~1;
+ if (left < size) {
+ if (left + length > size)
+ return_error(e_rangecheck);
+ *pdata = rstr.value.const_bytes + left;
+ return 0;
+ }
+ left -= size;
+ }
+}
diff --git a/pstoraster/zfproc.c b/pstoraster/zfproc.c
new file mode 100644
index 000000000..46d40ca26
--- /dev/null
+++ b/pstoraster/zfproc.c
@@ -0,0 +1,363 @@
+/* Copyright (C) 1994, 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$ */
+/* Procedure-based filter stream support */
+#include "memory_.h"
+#include "ghost.h"
+#include "oper.h" /* for ifilter.h */
+#include "estack.h"
+#include "gsstruct.h"
+#include "ialloc.h"
+#include "istruct.h" /* for RELOC_REF_VAR */
+#include "stream.h"
+#include "strimpl.h"
+#include "ifilter.h"
+#include "files.h"
+#include "store.h"
+
+/* ---------------- Generic ---------------- */
+
+/* GC procedures */
+#define pptr ((stream_proc_state *)vptr)
+private
+CLEAR_MARKS_PROC(sproc_clear_marks)
+{
+ r_clear_attrs(&pptr->proc, l_mark);
+ r_clear_attrs(&pptr->data, l_mark);
+}
+private
+ENUM_PTRS_BEGIN(sproc_enum_ptrs) return 0;
+
+case 0:
+ENUM_RETURN_REF(&pptr->proc);
+case 1:
+ENUM_RETURN_REF(&pptr->data);
+ENUM_PTRS_END
+private RELOC_PTRS_BEGIN(sproc_reloc_ptrs);
+RELOC_REF_VAR(pptr->proc);
+r_clear_attrs(&pptr->proc, l_mark);
+RELOC_REF_VAR(pptr->data);
+r_clear_attrs(&pptr->data, l_mark);
+RELOC_PTRS_END
+#undef pptr
+
+/* Structure type for procedure-based streams. */
+private_st_stream_proc_state();
+
+/* Allocate and open a procedure-based filter. */
+/* The caller must have checked that *sop is a procedure. */
+private int
+s_proc_init(ref * sop, stream ** psstrm, uint mode,
+ const stream_template * temp, const stream_procs * procs)
+{
+ stream *sstrm = file_alloc_stream(imemory, "s_proc_init(stream)");
+ stream_proc_state *state =
+ (stream_proc_state *) s_alloc_state(imemory, &st_sproc_state,
+ "s_proc_init(state)");
+
+ if (sstrm == 0 || state == 0) {
+ ifree_object(state, "s_proc_init(state)");
+ /*ifree_object(sstrm, "s_proc_init(stream)"); *//* just leave it on the file list */
+ return_error(e_VMerror);
+ }
+ s_std_init(sstrm, NULL, 0, procs, mode);
+ sstrm->procs.process = temp->process;
+ state->template = temp;
+ state->memory = imemory;
+ state->eof = 0;
+ state->proc = *sop;
+ make_empty_string(&state->data, a_all);
+ state->index = 0;
+ sstrm->state = (stream_state *) state;
+ *psstrm = sstrm;
+ return 0;
+}
+
+/* Handle an interrupt during a stream operation. */
+/* This is logically unrelated to procedure streams, */
+/* but it is also associated with the interpreter stream machinery. */
+private int
+s_handle_intc(const ref * pstate, int nstate, int (*cont) (P1(os_ptr)))
+{
+ int npush = nstate + 2;
+
+ check_estack(npush);
+ if (nstate)
+ memcpy(esp + 2, pstate, nstate * sizeof(ref));
+#if 0 /* **************** */
+ {
+ int code = gs_interpret_error(e_interrupt, (ref *) (esp + npush));
+
+ if (code < 0)
+ return code;
+ }
+#else /* **************** */
+ npush--;
+#endif /* **************** */
+ make_op_estack(esp + 1, cont);
+ esp += npush;
+ return o_push_estack;
+}
+
+
+/* ---------------- Read streams ---------------- */
+
+/* Forward references */
+private stream_proc_process(s_proc_read_process);
+private int s_proc_read_continue(P1(os_ptr));
+
+/* Stream templates */
+private const stream_template s_proc_read_template = {
+ &st_sproc_state, NULL, s_proc_read_process, 1, 1, NULL
+};
+private const stream_procs s_proc_read_procs = {
+ s_std_noavailable, s_std_noseek, s_std_read_reset,
+ s_std_read_flush, s_std_null, NULL
+};
+
+/* Allocate and open a procedure-based read stream. */
+/* The caller must have checked that *sop is a procedure. */
+int
+sread_proc(ref * sop, stream ** psstrm)
+{
+ int code =
+ s_proc_init(sop, psstrm, s_mode_read, &s_proc_read_template,
+ &s_proc_read_procs);
+
+ if (code < 0)
+ return code;
+ (*psstrm)->end_status = CALLC;
+ return code;
+}
+
+/* Handle an input request. */
+private int
+s_proc_read_process(stream_state * st, stream_cursor_read * ignore_pr,
+ stream_cursor_write * pw, bool last)
+{
+ /* Move data from the string returned by the procedure */
+ /* into the stream buffer, or ask for a callback. */
+ stream_proc_state *const ss = (stream_proc_state *) st;
+ uint count = r_size(&ss->data) - ss->index;
+
+ if (count > 0) {
+ uint wcount = pw->limit - pw->ptr;
+
+ if (wcount < count)
+ count = wcount;
+ memcpy(pw->ptr + 1, ss->data.value.bytes + ss->index, count);
+ pw->ptr += count;
+ ss->index += count;
+ return 1;
+ }
+ return (ss->eof ? EOFC : CALLC);
+}
+
+/* Handle an exception (INTC or CALLC) from a read stream */
+/* whose buffer is empty. */
+int
+s_handle_read_exception(int status, const ref * fop, const ref * pstate,
+ int nstate, int (*cont) (P1(os_ptr)))
+{
+ int npush = nstate + 4;
+ stream *ps;
+
+ switch (status) {
+ case INTC:
+ return s_handle_intc(pstate, nstate, cont);
+ case CALLC:
+ break;
+ default:
+ return_error(e_ioerror);
+ }
+ /* Find the stream whose buffer needs refilling. */
+ for (ps = fptr(fop); ps->strm != 0;)
+ ps = ps->strm;
+ check_estack(npush);
+ if (nstate)
+ memcpy(esp + 2, pstate, nstate * sizeof(ref));
+ make_op_estack(esp + 1, cont);
+ esp += npush;
+ make_op_estack(esp - 2, s_proc_read_continue);
+ esp[-1] = *fop;
+ r_clear_attrs(esp - 1, a_executable);
+ *esp = ((stream_proc_state *) ps->state)->proc;
+ return o_push_estack;
+}
+/* Continue a read operation after returning from a procedure callout. */
+/* osp[0] contains the file (pushed on the e-stack by handle_read_status); */
+/* osp[-1] contains the new data string (pushed by the procedure). */
+/* The top of the e-stack contains the real continuation. */
+private int
+s_proc_read_continue(os_ptr op)
+{
+ os_ptr opbuf = op - 1;
+ stream *ps;
+ stream_proc_state *ss;
+
+ check_file(ps, op);
+ check_read_type(*opbuf, t_string);
+ while ((ps->end_status = 0, ps->strm) != 0)
+ ps = ps->strm;
+ ss = (stream_proc_state *) ps->state;
+ ss->data = *opbuf;
+ ss->index = 0;
+ if (r_size(opbuf) == 0)
+ ss->eof = true;
+ pop(2);
+ return 0;
+}
+
+/* ---------------- Write streams ---------------- */
+
+/* Forward references */
+private stream_proc_process(s_proc_write_process);
+private int s_proc_write_continue(P1(os_ptr));
+
+/* Stream templates */
+private const stream_template s_proc_write_template = {
+ &st_sproc_state, NULL, s_proc_write_process, 1, 1, NULL
+};
+private const stream_procs s_proc_write_procs = {
+ s_std_noavailable, s_std_noseek, s_std_write_reset,
+ s_std_write_flush, s_std_null, NULL
+};
+
+/* Allocate and open a procedure-based write stream. */
+/* The caller must have checked that *sop is a procedure. */
+int
+swrite_proc(ref * sop, stream ** psstrm)
+{
+ return s_proc_init(sop, psstrm, s_mode_write, &s_proc_write_template,
+ &s_proc_write_procs);
+}
+
+/* Handle an output request. */
+private int
+s_proc_write_process(stream_state * st, stream_cursor_read * pr,
+ stream_cursor_write * ignore_pw, bool last)
+{
+ /* Move data from the stream buffer to the string */
+ /* returned by the procedure, or ask for a callback. */
+ stream_proc_state *const ss = (stream_proc_state *) st;
+ uint rcount = pr->limit - pr->ptr;
+
+ if (rcount > 0) {
+ uint wcount = r_size(&ss->data) - ss->index;
+ uint count = min(rcount, wcount);
+
+ memcpy(ss->data.value.bytes + ss->index, pr->ptr + 1, count);
+ pr->ptr += count;
+ ss->index += count;
+ if (rcount > wcount)
+ return CALLC;
+ else if (last) {
+ ss->eof = true;
+ return CALLC;
+ } else
+ return 0;
+ }
+ return ((ss->eof = last) ? EOFC : 0);
+}
+
+/* Handle an exception (INTC or CALLC) from a write stream */
+/* whose buffer is full. */
+int
+s_handle_write_exception(int status, const ref * fop, const ref * pstate,
+ int nstate, int (*cont) (P1(os_ptr)))
+{
+ stream *ps;
+ stream_proc_state *psst;
+
+ switch (status) {
+ case INTC:
+ return s_handle_intc(pstate, nstate, cont);
+ case CALLC:
+ break;
+ default:
+ return_error(e_ioerror);
+ }
+ /* Find the stream whose buffer needs emptying. */
+ for (ps = fptr(fop); ps->strm != 0;)
+ ps = ps->strm;
+ psst = (stream_proc_state *) ps->state;
+ if (psst->eof) {
+ /* This is the final call from closing the stream. */
+ /* Don't run the continuation. */
+ check_estack(5);
+ esp += 5;
+ make_op_estack(esp - 4, zpop); /* pop the file */
+ make_op_estack(esp - 3, zpop); /* pop the string returned */
+ /* by the procedure */
+ make_false(esp - 1);
+ } else {
+ int npush = nstate + 6;
+
+ check_estack(npush);
+ if (nstate)
+ memcpy(esp + 2, pstate, nstate * sizeof(ref));
+ make_op_estack(esp + 1, cont);
+ esp += npush;
+ make_op_estack(esp - 4, s_proc_write_continue);
+ esp[-3] = *fop;
+ r_clear_attrs(esp - 3, a_executable);
+ make_true(esp - 1);
+ }
+ esp[-2] = psst->proc;
+ *esp = psst->data;
+ r_set_size(esp, psst->index);
+ return o_push_estack;
+}
+/* Continue a write operation after returning from a procedure callout. */
+/* osp[0] contains the file (pushed on the e-stack by handle_write_status); */
+/* osp[-1] contains the new buffer string (pushed by the procedure). */
+/* The top of the e-stack contains the real continuation. */
+private int
+s_proc_write_continue(os_ptr op)
+{
+ os_ptr opbuf = op - 1;
+ stream *ps;
+ stream_proc_state *ss;
+
+ check_file(ps, op);
+ check_write_type(*opbuf, t_string);
+ while ((ps->end_status = 0, ps->strm) != 0)
+ ps = ps->strm;
+ ss = (stream_proc_state *) ps->state;
+ ss->data = *opbuf;
+ ss->index = 0;
+ pop(2);
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zfproc_op_defs[] =
+{
+ /* Internal operators */
+ {"2%s_proc_read_continue", s_proc_read_continue},
+ {"2%s_proc_write_continue", s_proc_write_continue},
+ op_def_end(0)
+};
diff --git a/pstoraster/zfreuse.c b/pstoraster/zfreuse.c
new file mode 100644
index 000000000..0d2488bef
--- /dev/null
+++ b/pstoraster/zfreuse.c
@@ -0,0 +1,206 @@
+/* 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$ */
+/* ReusableStreamDecode filter support */
+#include "memory_.h"
+#include "ghost.h"
+#include "oper.h"
+#include "stream.h"
+#include "strimpl.h"
+#include "sfilter.h" /* for SubFileDecode */
+#include "files.h"
+#include "idict.h"
+#include "idparam.h"
+#include "iname.h"
+#include "store.h"
+
+/*
+ * The actual work of constructing the filter is done in PostScript code.
+ * The operators in this file are internal ones that handle the dirty work.
+ */
+
+/* <dict|null> .rsdparams <filters> <decodeparms|null> */
+/* filters is always an array, and decodeparms is always either an array */
+/* of the same length as filters, or null. */
+private int
+zrsdparams(os_ptr op)
+{
+ ref *pFilter;
+ ref *pDecodeParms;
+ int Intent;
+ bool AsyncRead;
+ ref empty_array, filter1_array, parms1_array;
+ uint i;
+ int code;
+
+ make_empty_array(&empty_array, a_readonly);
+ if (dict_find_string(op, "Filter", &pFilter) > 0) {
+ if (!r_is_array(pFilter)) {
+ if (!r_has_type(pFilter, t_name))
+ return_error(e_typecheck);
+ make_array(&filter1_array, a_readonly, 1, pFilter);
+ pFilter = &filter1_array;
+ }
+ } else
+ pFilter = &empty_array;
+ /* If Filter is undefined, ignore DecodeParms. */
+ if (pFilter != &empty_array &&
+ dict_find_string(op, "DecodeParms", &pDecodeParms) > 0
+ ) {
+ if (pFilter == &filter1_array) {
+ make_array(&parms1_array, a_readonly, 1, pDecodeParms);
+ pDecodeParms = &parms1_array;
+ } else if (!r_is_array(pDecodeParms))
+ return_error(e_typecheck);
+ else if (r_size(pFilter) != r_size(pDecodeParms))
+ return_error(e_rangecheck);
+ } else
+ pDecodeParms = 0;
+ for (i = 0; i < r_size(pFilter); ++i) {
+ ref f, fname, dp;
+
+ array_get(pFilter, (long)i, &f);
+ if (!r_has_type(&f, t_name))
+ return_error(e_typecheck);
+ name_string_ref(&f, &fname);
+ if (r_size(&fname) < 6 ||
+ !memcmp(fname.value.bytes + r_size(&fname) - 6, "Decode", 6)
+ )
+ return_error(e_rangecheck);
+ if (pDecodeParms) {
+ array_get(pDecodeParms, (long)i, &dp);
+ if (!(r_has_type(&dp, t_dictionary) || r_has_type(&dp, t_null)))
+ return_error(e_typecheck);
+ }
+ }
+ if ((code = dict_int_param(op, "Intent", 0, 3, 0, &Intent)) < 0 ||
+ (code = dict_bool_param(op, "AsyncRead", false, &AsyncRead)) < 0
+ )
+ return code;
+ push(1);
+ op[-1] = *pFilter;
+ if (pDecodeParms)
+ *op = *pDecodeParms;
+ else
+ make_null(op);
+ return 0;
+}
+
+/* <file|string> <length|null> <CloseSource> .reusablestream <filter> */
+/*
+ * The file|string operand must be a "reusable source", either:
+ * - A string;
+ * - A readable, positionable file stream;
+ * - A SubFileDecode filter with an empty EODString and a reusable
+ * source;
+ * - A reusable stream.
+ */
+private int make_rss(P6(os_ptr op, const byte * data, uint size, long offset,
+ long length, bool close_source));
+private int
+zreusablestream(os_ptr op)
+{
+ os_ptr source_op = op - 2;
+ os_ptr length_op = op - 1;
+ long length;
+ bool close_source;
+ int code;
+
+ if (r_has_type(length_op, t_integer)) {
+ length = length_op->value.intval;
+ if (length < 0)
+ return_error(e_rangecheck);
+ } else
+ length = -1;
+ check_type(*op, t_boolean);
+ close_source = op->value.boolval;
+ if (r_has_type(source_op, t_string)) {
+ check_read(*source_op);
+ code = make_rss(source_op, source_op->value.const_bytes,
+ r_size(source_op), 0L, length, close_source);
+ } else {
+ long offset = 0;
+ stream *source;
+
+ check_read_file(source, source_op);
+rs:
+ if (source->cbuf_string.data != 0) {
+ /* The data source is a string. */
+ long avail;
+
+ offset += stell(source);
+ savailable(source, &avail);
+ if (avail < 0)
+ avail = 0;
+ if (avail > length)
+ avail = length;
+ code = make_rss(source_op, source->cbuf_string.data,
+ source->cbuf_string.size, offset, avail,
+ close_source);
+ } else if (source->file != 0) {
+ /* The data source is a file. */
+/****** NYI ******/
+ } else if (source->state->template == &s_SFD_template) {
+ /* The data source is a SubFileDecode filter. */
+ const stream_SFD_state *const sfd_state =
+ (const stream_SFD_state *)source->state;
+
+ if (sfd_state->eod.size != 0)
+ return_error(e_rangecheck);
+ if (sfd_state->count != 0) {
+ long left = sfd_state->count + sbufavailable(source);
+
+ if (left < length)
+ length = left;
+ }
+ source = source->strm;
+ goto rs;
+ }
+/****** REUSABLE CASE IS NYI ******/
+ else
+ return_error(e_rangecheck);
+ }
+ if (code >= 0)
+ pop(2);
+ return code;
+}
+
+/* Make a reusable string stream. */
+private int
+make_rss(os_ptr op, const byte * data, uint size, long offset,
+ long length, bool close_source)
+{
+/****** NYI ******/
+ return_error(e_rangecheck);
+}
+
+/* ---------------- Initialization procedure ---------------- */
+
+const op_def zfreuse_op_defs[] =
+{
+ {"2.rsdparams", zrsdparams},
+ {"2.reusablestream", zreusablestream},
+ op_def_end(0)
+};
diff --git a/pstoraster/zfunc.c b/pstoraster/zfunc.c
new file mode 100644
index 000000000..38b0c4a8f
--- /dev/null
+++ b/pstoraster/zfunc.c
@@ -0,0 +1,237 @@
+/*
+ Copyright 2001 by Easy Software Products.
+ Copyright 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 PostScript language interface to Functions */
+#include "memory_.h"
+#include "ghost.h"
+#include "oper.h"
+#include "gsfunc.h"
+#include "gsstruct.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "idparam.h"
+#include "ifunc.h"
+#include "store.h"
+
+/* Define the maximum depth of nesting of subsidiary functions. */
+#define MAX_SUB_FUNCTION_DEPTH 3
+
+/* Define the table of build procedures. */
+build_function_proc((*build_function_procs[5])) = {
+ build_function_undefined, build_function_undefined, build_function_undefined,
+ build_function_undefined, build_function_undefined
+};
+
+int
+build_function_undefined(const_os_ptr op, const gs_function_params_t * mnDR,
+ int depth, gs_function_t ** ppfn)
+{
+ return_error(e_rangecheck);
+}
+
+/* GC descriptors */
+gs_private_st_ptr(st_function_ptr, gs_function_t *, "gs_function_t *",
+ function_ptr_enum_ptrs, function_ptr_reloc_ptrs);
+gs_private_st_element(st_function_ptr_element, gs_function_t *,
+ "gs_function_t *[]", function_ptr_element_enum_ptrs,
+ function_ptr_element_reloc_ptrs, st_function_ptr);
+
+/* ------ Operators ------ */
+
+private int zexecfunction(P1(os_ptr op));
+
+/* <dict> .buildfunction <function_struct> */
+private int
+zbuildfunction(os_ptr op)
+{
+ gs_function_t *pfn;
+ ref cref; /* closure */
+ int code;
+
+ code = ialloc_ref_array(&cref, a_executable | a_execute, 2,
+ ".buildfunction");
+ if (code < 0)
+ return code;
+ code = fn_build_function(op, &pfn);
+ if (code < 0) {
+ ifree_ref_array(&cref, ".buildfunction");
+ return code;
+ }
+ make_istruct_new(cref.value.refs, a_executable | a_execute, pfn);
+ make_oper_new(cref.value.refs + 1, 0, zexecfunction);
+ ref_assign(op, &cref);
+ return 0;
+}
+
+/* <in1> ... <function_struct> %execfunction <out1> ... */
+private int
+zexecfunction(os_ptr op)
+{ /*
+ * Since this operator's name begins with %, the name is not defined
+ * in systemdict. The only place this operator can ever appear is
+ * in the execute-only closure created by .buildfunction.
+ * Therefore, in principle it is unnecessary to check the argument.
+ * However, we do a little checking anyway just on general
+ * principles. Note that since the argument may be an instance of
+ * any subclass of gs_function_t, we currently have no way to check
+ * its type.
+ */
+ if (!r_is_struct(op) ||
+ r_has_masked_attrs(op, a_executable | a_execute, a_all)
+ )
+ return_error(e_typecheck);
+ {
+ gs_function_t *pfn = (gs_function_t *) op->value.pstruct;
+ int m = pfn->params.m, n = pfn->params.n;
+ int diff = n - (m + 1);
+
+ if (diff > 0)
+ check_ostack(diff);
+ {
+ float *in = (float *)ialloc_byte_array(m, sizeof(float),
+ "%execfunction(in)");
+ float *out = (float *)ialloc_byte_array(n, sizeof(float),
+ "%execfunction(out)");
+ int code;
+
+ if (in == 0 || out == 0)
+ code = gs_note_error(e_VMerror);
+ else if ((code = float_params(op - 1, m, in)) < 0 ||
+ (code = gs_function_evaluate(pfn, in, out)) < 0
+ )
+ DO_NOTHING;
+ else {
+ if (diff > 0)
+ push(diff) /* can't fail */ /* MRS: No trailing ; */
+ else if (diff < 0) {
+ pop(-diff);
+ op = osp;
+ }
+ code = make_floats(op + 1 - n, out, n);
+ }
+ ifree_object(out, "%execfunction(out)");
+ ifree_object(in, "%execfunction(in)");
+ return code;
+ }
+ }
+}
+
+/* ------ Procedures ------ */
+
+/* Build a function structure from a PostScript dictionary. */
+int
+fn_build_sub_function(const ref * op, gs_function_t ** ppfn, int depth)
+{
+ int code, type;
+ gs_function_params_t params;
+
+ if (depth > MAX_SUB_FUNCTION_DEPTH)
+ return_error(e_limitcheck);
+ check_type(*op, t_dictionary);
+ code = dict_int_param(op, "FunctionType", 0,
+ countof(build_function_procs) - 1, -1, &type);
+ if (code < 0)
+ return code;
+ /* Collect parameters common to all function types. */
+ params.Domain = 0;
+ params.Range = 0;
+ code = fn_build_float_array(op, "Domain", true, true, &params.Domain);
+ if (code < 0)
+ goto fail;
+ params.m = code >> 1;
+ code = fn_build_float_array(op, "Range", false, true, &params.Range);
+ if (code < 0)
+ goto fail;
+ params.n = code >> 1;
+ /* Finish building the function. */
+ /* If this fails, it will free all the parameters. */
+ return (*build_function_procs[type]) (op, &params, depth + 1, ppfn);
+fail:
+ ifree_object((void *)params.Range, "Range"); /* break const */
+ ifree_object((void *)params.Domain, "Domain"); /* break const */
+ return code;
+}
+
+/* Allocate an array of function objects. */
+int
+ialloc_function_array(uint count, gs_function_t *** pFunctions)
+{
+ gs_function_t **ptr;
+
+ if (count == 0)
+ return_error(e_rangecheck);
+ ptr = ialloc_struct_array(count, gs_function_t *,
+ &st_function_ptr_element, "Functions");
+ if (ptr == 0)
+ return_error(e_VMerror);
+ memset(ptr, 0, sizeof(*ptr) * count);
+ *pFunctions = ptr;
+ return 0;
+}
+
+/*
+ * Collect a heap-allocated array of floats. If the key is missing, set
+ * *pparray = 0 and return 0; otherwise set *pparray and return the number
+ * of elements. Note that 0-length arrays are acceptable, so if the value
+ * returned is 0, the caller must check whether *pparray == 0.
+ */
+int
+fn_build_float_array(const ref * op, const char *kstr, bool required,
+ bool even, const float **pparray)
+{
+ ref *par;
+ int code;
+
+ *pparray = 0;
+ if (dict_find_string(op, kstr, &par) <= 0)
+ return (required ? gs_note_error(e_rangecheck) : 0);
+ if (!r_is_array(par))
+ return_error(e_typecheck);
+ {
+ uint size = r_size(par);
+ float *ptr = (float *)ialloc_byte_array(size, sizeof(float), kstr);
+
+ if (ptr == 0)
+ return_error(e_VMerror);
+ code = dict_float_array_param(op, kstr, size, ptr, NULL);
+ if (code < 0 || (even && (code & 1) != 0)) {
+ ifree_object(ptr, kstr);
+ return(code < 0 ? code : gs_note_error(e_rangecheck));
+ }
+ *pparray = ptr;
+ }
+ return code;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zfunc_op_defs[] =
+{
+ {"1.buildfunction", zbuildfunction},
+ {"1%execfunction", zexecfunction},
+ op_def_end(0)
+};
diff --git a/pstoraster/zfunc0.c b/pstoraster/zfunc0.c
new file mode 100644
index 000000000..56956da51
--- /dev/null
+++ b/pstoraster/zfunc0.c
@@ -0,0 +1,113 @@
+/* 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$ */
+/* PostScript language interface to FunctionType 0 (Sampled) Functions */
+#include "memory_.h"
+#include "ghost.h"
+#include "oper.h"
+#include "gsdsrc.h"
+#include "gsfunc.h"
+#include "gsfunc0.h"
+#include "stream.h" /* for files.h */
+#include "files.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "idparam.h"
+#include "ifunc.h"
+
+/* Initialization */
+private build_function_proc(build_function_0);
+int
+zfunc0_init(gs_memory_t * mem)
+{
+ build_function_procs[0] = build_function_0;
+ return 0;
+}
+
+const op_def zfunc0_op_defs[] =
+{
+ op_def_end(zfunc0_init)
+};
+
+/* Finish building a FunctionType 0 (Sampled) function. */
+private int
+build_function_0(const_os_ptr op, const gs_function_params_t * mnDR, int depth,
+ gs_function_t ** ppfn)
+{
+ gs_function_Sd_params_t params;
+ ref *pDataSource;
+ int code;
+
+ *(gs_function_params_t *) & params = *mnDR;
+ params.Encode = 0;
+ params.Decode = 0;
+ params.Size = 0;
+ if ((code = dict_find_string(op, "DataSource", &pDataSource)) <= 0)
+ return (code < 0 ? code : gs_note_error(e_rangecheck));
+ switch (r_type(pDataSource)) {
+ case t_string:
+ data_source_init_string2(&params.DataSource,
+ pDataSource->value.const_bytes,
+ r_size(pDataSource));
+ break;
+ case t_file: {
+ stream *s;
+
+ check_read_known_file_else(s, pDataSource, return_error,
+ return_error(e_invalidfileaccess));
+ if (!(s->modes & s_mode_seek))
+ return_error(e_ioerror);
+ data_source_init_stream(&params.DataSource, s);
+ break;
+ }
+ default:
+ return_error(e_rangecheck);
+ }
+ if ((code = dict_int_param(op, "Order", 1, 3, 1, &params.Order)) < 0 ||
+ (code = dict_int_param(op, "BitsPerSample", 1, 32, 0,
+ &params.BitsPerSample)) < 0 ||
+ ((code = fn_build_float_array(op, "Encode", false, true, &params.Encode)) != 2 * params.m && (code != 0 || params.Encode != 0)) ||
+ ((code = fn_build_float_array(op, "Decode", false, true, &params.Decode)) != 2 * params.n && (code != 0 || params.Decode != 0))
+ ) {
+ goto fail;
+ } {
+ int *ptr = (int *)ialloc_byte_array(params.m, sizeof(int), "Size");
+
+ if (ptr == 0) {
+ code = gs_note_error(e_VMerror);
+ goto fail;
+ }
+ params.Size = ptr;
+ code = dict_int_array_param(op, "Size", params.m, ptr);
+ if (code != params.m)
+ goto fail;
+ }
+ code = gs_function_Sd_init(ppfn, &params, imemory);
+ if (code >= 0)
+ return 0;
+fail:
+ gs_function_Sd_free_params(&params, imemory);
+ return (code < 0 ? code : gs_note_error(e_rangecheck));
+}
diff --git a/pstoraster/zfunc3.c b/pstoraster/zfunc3.c
new file mode 100644
index 000000000..20f5d1840
--- /dev/null
+++ b/pstoraster/zfunc3.c
@@ -0,0 +1,136 @@
+/* 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 language interface to LL3 Functions */
+#include "memory_.h"
+#include "ghost.h"
+#include "oper.h"
+#include "gsfunc3.h"
+#include "gsstruct.h"
+#include "stream.h" /* for files.h */
+#include "files.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "idparam.h"
+#include "ifunc.h"
+#include "store.h"
+
+/* Initialization */
+private build_function_proc(build_function_2);
+private build_function_proc(build_function_3);
+int
+zfunc3_init(gs_memory_t * mem)
+{
+ build_function_procs[2] = build_function_2;
+ build_function_procs[3] = build_function_3;
+ return 0;
+}
+
+const op_def zfunc3_op_defs[] =
+{
+ op_def_end(zfunc3_init)
+};
+
+/* Define the available Function types. */
+
+/* Finish building a FunctionType 2 (ExponentialInterpolation) function. */
+private int
+build_function_2(const_os_ptr op, const gs_function_params_t * mnDR, int depth,
+ gs_function_t ** ppfn)
+{
+ gs_function_ElIn_params_t params;
+ int code, n0, n1;
+
+ *(gs_function_params_t *)&params = *mnDR;
+ params.C0 = 0;
+ params.C1 = 0;
+ if ((code = dict_float_param(op, "N", 0.0, &params.N)) != 0 ||
+ (code = n0 = fn_build_float_array(op, "C0", false, false, &params.C0)) < 0 ||
+ (code = n1 = fn_build_float_array(op, "C1", false, false, &params.C1)) < 0
+ )
+ goto fail;
+ if (params.C0 == 0)
+ n0 = 1; /* C0 defaulted */
+ if (params.C1 == 0)
+ n1 = 1; /* C1 defaulted */
+ if (params.Range == 0)
+ params.n = n0; /* either one will do */
+ if (n0 != n1 || n0 != params.n)
+ goto fail;
+ code = gs_function_ElIn_init(ppfn, &params, imemory);
+ if (code >= 0)
+ return 0;
+fail:
+ gs_function_ElIn_free_params(&params, imemory);
+ return (code < 0 ? code : gs_note_error(e_rangecheck));
+}
+
+/* Finish building a FunctionType 3 (1-Input Stitching) function. */
+private int
+build_function_3(const_os_ptr op, const gs_function_params_t * mnDR, int depth,
+ gs_function_t ** ppfn)
+{
+ gs_function_1ItSg_params_t params;
+ int code;
+
+ *(gs_function_params_t *) & params = *mnDR;
+ params.Functions = 0;
+ params.Bounds = 0;
+ params.Encode = 0;
+ {
+ ref *pFunctions;
+ gs_function_t **ptr;
+ int i;
+
+ if ((code = dict_find_string(op, "Functions", &pFunctions)) <= 0)
+ return (code < 0 ? code : gs_note_error(e_rangecheck));
+ check_array_only(*pFunctions);
+ params.k = r_size(pFunctions);
+ code = ialloc_function_array(params.k, &ptr);
+ if (code < 0)
+ return code;
+ params.Functions = (const gs_function_t * const *)ptr;
+ for (i = 0; i < params.k; ++i) {
+ ref subfn;
+
+ array_get(pFunctions, (long)i, &subfn);
+ code = fn_build_sub_function(&subfn, &ptr[i], depth);
+ if (code < 0)
+ goto fail;
+ }
+ }
+ if ((code = fn_build_float_array(op, "Bounds", true, false, &params.Bounds)) != params.k - 1 ||
+ (code = fn_build_float_array(op, "Encode", true, true, &params.Encode)) != 2 * params.k
+ )
+ goto fail;
+ if (params.Range == 0)
+ params.n = params.Functions[0]->params.n;
+ code = gs_function_1ItSg_init(ppfn, &params, imemory);
+ if (code >= 0)
+ return 0;
+fail:
+ gs_function_1ItSg_free_params(&params, imemory);
+ return (code < 0 ? code : gs_note_error(e_rangecheck));
+}
diff --git a/pstoraster/zfzlib.c b/pstoraster/zfzlib.c
new file mode 100644
index 000000000..e52cdff35
--- /dev/null
+++ b/pstoraster/zfzlib.c
@@ -0,0 +1,105 @@
+/*
+ Copyright 1993-2002 by Easy Software Products
+ Copyright 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.
+*/
+
+#include <config.h>
+#ifdef HAVE_LIBZ
+/*$Id$ */
+/* zlib and Flate filter creation */
+#include "ghost.h"
+#include "oper.h"
+#include "idict.h"
+#include "strimpl.h"
+#include "spdiffx.h"
+#include "spngpx.h"
+#include "szlibx.h"
+#include "ifilter.h"
+
+/* Import the Predictor machinery from zfdecode.c and zfilter2.c. */
+int filter_read_predictor(P4(os_ptr op, int npop,
+ const stream_template * template,
+ stream_state * st));
+int filter_write_predictor(P4(os_ptr op, int npop,
+ const stream_template * template,
+ stream_state * st));
+
+/* <source> zlibEncode/filter <file> */
+/* <source> <dict> zlibEncode/filter <file> */
+private int
+zzlibE(os_ptr op)
+{
+ stream_zlib_state zls;
+
+ (*s_zlibE_template.set_defaults)((stream_state *)&zls);
+ return filter_write(op, 0, &s_zlibE_template, (stream_state *)&zls, 0);
+}
+
+/* <target> zlibDecode/filter <file> */
+/* <target> <dict> zlibDecode/filter <file> */
+private int
+zzlibD(os_ptr op)
+{
+ stream_zlib_state zls;
+
+ (*s_zlibD_template.set_defaults)((stream_state *)&zls);
+ return filter_read(op, 0, &s_zlibD_template, (stream_state *)&zls, 0);
+}
+
+/* <source> FlateEncode/filter <file> */
+/* <source> <dict> FlateEncode/filter <file> */
+private int
+zFlateE(os_ptr op)
+{
+ stream_zlib_state zls;
+
+ (*s_zlibE_template.set_defaults)((stream_state *)&zls);
+ return filter_write_predictor(op, 0, &s_zlibE_template,
+ (stream_state *)&zls);
+}
+
+/* <target> FlateDecode/filter <file> */
+/* <target> <dict> FlateDecode/filter <file> */
+private int
+zFlateD(os_ptr op)
+{
+ stream_zlib_state zls;
+
+ (*s_zlibD_template.set_defaults)((stream_state *)&zls);
+ return filter_read_predictor(op, 0, &s_zlibD_template,
+ (stream_state *)&zls);
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zfzlib_op_defs[] =
+{
+ op_def_begin_filter(),
+ {"1zlibEncode", zzlibE},
+ {"1zlibDecode", zzlibD},
+ {"1FlateEncode", zFlateE},
+ {"1FlateDecode", zFlateD},
+ op_def_end(0)
+};
+#endif /* HAVE_LIBZ */
diff --git a/pstoraster/zgeneric.c b/pstoraster/zgeneric.c
new file mode 100644
index 000000000..c56c7f220
--- /dev/null
+++ b/pstoraster/zgeneric.c
@@ -0,0 +1,528 @@
+/* Copyright (C) 1989, 1992, 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$ */
+/* Array/string/dictionary generic operators for PostScript */
+#include "memory_.h"
+#include "ghost.h"
+#include "oper.h"
+#include "estack.h" /* for forall */
+#include "idict.h"
+#include "iname.h"
+#include "ipacked.h"
+#include "ivmspace.h"
+#include "store.h"
+
+/* This file implements copy, get, put, getinterval, putinterval, */
+/* length, and forall, which apply generically to */
+/* arrays, strings, and dictionaries. (Copy also has a special */
+/* meaning for copying the top N elements of the stack.) */
+
+/* See the comment in opdef.h for an invariant which allows */
+/* more efficient implementation of forall. */
+
+/* Imported operators */
+extern int zcopy_dict(P1(os_ptr));
+
+/* Forward references */
+private int zcopy_integer(P1(os_ptr));
+private int zcopy_interval(P1(os_ptr));
+private int copy_interval(P4(os_ptr, uint, os_ptr, client_name_t));
+
+/* <various1> <various2> copy <various> */
+/* <obj1> ... <objn> <int> copy <obj1> ... <objn> <obj1> ... <objn> */
+/* Note that this implements copy for arrays and strings, */
+/* but not for dictionaries (see zcopy_dict in zdict.c). */
+int
+zcopy(register os_ptr op)
+{
+ int type = r_type(op);
+
+ if (type == t_integer)
+ return zcopy_integer(op);
+ check_op(2);
+ switch (type) {
+ case t_array:
+ case t_string:
+ return zcopy_interval(op);
+ case t_dictionary:
+ return zcopy_dict(op);
+ default:
+ return_op_typecheck(op);
+ }
+}
+
+/* <obj1> ... <objn> <int> copy <obj1> ... <objn> <obj1> ... <objn> */
+private int
+zcopy_integer(register os_ptr op)
+{
+ os_ptr op1 = op - 1;
+ int count, i;
+ int code;
+
+ if ((ulong) op->value.intval > op - osbot) {
+ /* There might be enough elements in other blocks. */
+ check_int_ltu(*op, ref_stack_count(&o_stack));
+ count = op->value.intval;
+ } else if (op1 + (count = op->value.intval) <= ostop) {
+ /* Fast case. */
+ memcpy((char *)op, (char *)(op - count), count * sizeof(ref));
+ push(count - 1);
+ return 0;
+ }
+ /* Do it the slow, general way. */
+ code = ref_stack_push(&o_stack, count - 1);
+ if (code < 0)
+ return code;
+ for (i = 0; i < count; i++)
+ *ref_stack_index(&o_stack, i) =
+ *ref_stack_index(&o_stack, i + count);
+ return 0;
+}
+
+/* <array1> <array2> copy <subarray2> */
+/* <string1> <string2> copy <substring2> */
+private int
+zcopy_interval(register os_ptr op)
+{
+ os_ptr op1 = op - 1;
+ int code = copy_interval(op, 0, op1, "copy");
+
+ if (code < 0)
+ return code;
+ r_set_size(op, r_size(op1));
+ *op1 = *op;
+ pop(1);
+ return 0;
+}
+
+/* <array|dict|name|packedarray|string> length <int> */
+private int
+zlength(register os_ptr op)
+{
+ switch (r_type(op)) {
+ case t_array:
+ case t_string:
+ case t_mixedarray:
+ case t_shortarray:
+ check_read(*op);
+ make_int(op, r_size(op));
+ return 0;
+ case t_dictionary:
+ check_dict_read(*op);
+ make_int(op, dict_length(op));
+ return 0;
+ case t_name: {
+ ref str;
+
+ name_string_ref(op, &str);
+ make_int(op, r_size(&str));
+ return 0;
+ }
+ default:
+ return_op_typecheck(op);
+ }
+}
+
+/* <array|packedarray|string> <index> get <obj> */
+/* <dict> <key> get <obj> */
+private int
+zget(register os_ptr op)
+{
+ os_ptr op1 = op - 1;
+ ref *pvalue;
+
+ switch (r_type(op1)) {
+ case t_dictionary:
+ check_dict_read(*op1);
+ if (dict_find(op1, op, &pvalue) <= 0)
+ return_error(e_undefined);
+ op[-1] = *pvalue;
+ break;
+ case t_string:
+ check_read(*op1);
+ check_int_ltu(*op, r_size(op1));
+ make_int(op1, op1->value.bytes[(uint) op->value.intval]);
+ break;
+ default: {
+ int code;
+
+ check_type(*op, t_integer);
+ check_read(*op1);
+ code = array_get(op1, op->value.intval, op1);
+ if (code < 0) { /* Might be a stackunderflow reported as typecheck. */
+ if (code == e_typecheck)
+ return_op_typecheck(op1);
+ else
+ return code;
+ }
+ }
+ }
+ pop(1);
+ return 0;
+}
+
+/* <array> <index> <obj> put - */
+/* <dict> <key> <value> put - */
+/* <string> <index> <int> put - */
+private int
+zput(register os_ptr op)
+{
+ os_ptr op1 = op - 1;
+ os_ptr op2 = op1 - 1;
+
+ switch (r_type(op2)) {
+ case t_dictionary:
+ check_dict_write(*op2);
+ {
+ int code = dict_put(op2, op1, op);
+
+ if (code < 0)
+ return code; /* error */
+ }
+ break;
+ case t_array:
+ check_write(*op2);
+ check_int_ltu(*op1, r_size(op2));
+ store_check_dest(op2, op);
+ {
+ ref *eltp = op2->value.refs + (uint) op1->value.intval;
+
+ ref_assign_old(op2, eltp, op, "put");
+ }
+ break;
+ case t_mixedarray: /* packed arrays are read-only */
+ case t_shortarray:
+ return_error(e_invalidaccess);
+ case t_string:
+ check_write(*op2);
+ check_int_ltu(*op1, r_size(op2));
+ check_int_leu(*op, 0xff);
+ op2->value.bytes[(uint) op1->value.intval] = (byte) op->value.intval;
+ break;
+ default:
+ return_op_typecheck(op2);
+ }
+ pop(3);
+ return 0;
+}
+
+/* <seq:array|packedarray|string> <index> <count> getinterval <subseq> */
+private int
+zgetinterval(register os_ptr op)
+{
+ os_ptr op1 = op - 1;
+ os_ptr op2 = op1 - 1;
+ uint index;
+ uint count;
+
+ switch (r_type(op2)) {
+ default:
+ return_op_typecheck(op2);
+ case t_array:
+ case t_string:
+ case t_mixedarray:
+ case t_shortarray:;
+ }
+ check_read(*op2);
+ check_int_leu(*op1, r_size(op2));
+ index = op1->value.intval;
+ check_int_leu(*op, r_size(op2) - index);
+ count = op->value.intval;
+ switch (r_type(op2)) {
+ case t_array:
+ op2->value.refs += index;
+ break;
+ case t_string:
+ op2->value.bytes += index;
+ break;
+ case t_mixedarray: {
+ const ref_packed *packed = op2->value.packed;
+
+ for (; index--;)
+ packed = packed_next(packed);
+ op2->value.packed = packed;
+ break;
+ }
+ case t_shortarray:
+ op2->value.packed += index;
+ break;
+ }
+ r_set_size(op2, count);
+ pop(2);
+ return 0;
+}
+
+/* <array1> <index> <array2|packedarray2> putinterval - */
+/* <string1> <index> <string2> putinterval - */
+private int
+zputinterval(register os_ptr op)
+{
+ os_ptr opindex = op - 1;
+ os_ptr opto = opindex - 1;
+ int code;
+
+ switch (r_type(opto)) {
+ default:
+ return_op_typecheck(opto);
+ case t_mixedarray:
+ case t_shortarray:
+ return_error(e_invalidaccess);
+ case t_array:
+ case t_string:
+ ;
+ }
+ check_write(*opto);
+ check_int_leu(*opindex, r_size(opto));
+ code = copy_interval(opto, (uint) (opindex->value.intval), op, "putinterval");
+ if (code >= 0)
+ pop(3);
+ return code;
+}
+
+/* <array|packedarray|string> <<element> proc> forall - */
+/* <dict> <<key> <value> proc> forall - */
+private int
+ array_continue(P1(os_ptr)),
+ dict_continue(P1(os_ptr)),
+ string_continue(P1(os_ptr)),
+ packedarray_continue(P1(os_ptr));
+private int forall_cleanup(P1(os_ptr));
+private int
+zforall(register os_ptr op)
+{
+ os_ptr obj = op - 1;
+ es_ptr ep = esp;
+ es_ptr cproc = ep + 4;
+
+ check_estack(6);
+ switch (r_type(obj)) {
+ default:
+ return_op_typecheck(obj);
+ case t_array:
+ check_read(*obj);
+ make_op_estack(cproc, array_continue);
+ break;
+ case t_dictionary:
+ check_dict_read(*obj);
+ make_int(cproc, dict_first(obj));
+ ++cproc;
+ make_op_estack(cproc, dict_continue);
+ break;
+ case t_string:
+ check_read(*obj);
+ make_op_estack(cproc, string_continue);
+ break;
+ case t_mixedarray:
+ case t_shortarray:
+ check_read(*obj);
+ make_op_estack(cproc, packedarray_continue);
+ break;
+ }
+ check_proc(*op);
+ /*
+ * Push:
+ * - a mark;
+ * - the composite object;
+ * - the procedure;
+ * - the iteration index (only for dictionaries, done above);
+ * and invoke the continuation operator.
+ */
+ make_mark_estack(ep + 1, es_for, forall_cleanup);
+ ep[2] = *obj;
+ ep[3] = *op;
+ esp = cproc - 1;
+ pop(2);
+ op -= 2;
+ return (*real_opproc(cproc))(op);
+}
+/* Continuation operator for arrays */
+private int
+array_continue(register os_ptr op)
+{
+ es_ptr obj = esp - 1;
+
+ if (r_size(obj)) { /* continue */
+ push(1);
+ r_dec_size(obj, 1);
+ *op = *obj->value.refs;
+ obj->value.refs++;
+ esp += 2;
+ *esp = obj[1];
+ return o_push_estack;
+ } else { /* done */
+ esp -= 3; /* pop mark, object, proc */
+ return o_pop_estack;
+ }
+}
+/* Continuation operator for dictionaries */
+private int
+dict_continue(register os_ptr op)
+{
+ es_ptr obj = esp - 2;
+ int index = (int)esp->value.intval;
+
+ push(2); /* make room for key and value */
+ if ((index = dict_next(obj, index, op - 1)) >= 0) { /* continue */
+ esp->value.intval = index;
+ esp += 2;
+ *esp = obj[1];
+ return o_push_estack;
+ } else { /* done */
+ pop(2); /* undo push */
+ esp -= 4; /* pop mark, object, proc, index */
+ return o_pop_estack;
+ }
+}
+/* Continuation operator for strings */
+private int
+string_continue(register os_ptr op)
+{
+ es_ptr obj = esp - 1;
+
+ if (r_size(obj)) { /* continue */
+ r_dec_size(obj, 1);
+ push(1);
+ make_int(op, *obj->value.bytes);
+ obj->value.bytes++;
+ esp += 2;
+ *esp = obj[1];
+ return o_push_estack;
+ } else { /* done */
+ esp -= 3; /* pop mark, object, proc */
+ return o_pop_estack;
+ }
+}
+/* Continuation operator for packed arrays */
+private int
+packedarray_continue(register os_ptr op)
+{
+ es_ptr obj = esp - 1;
+
+ if (r_size(obj)) { /* continue */
+ const ref_packed *packed = obj->value.packed;
+
+ r_dec_size(obj, 1);
+ push(1);
+ packed_get(packed, op);
+ obj->value.packed = packed_next(packed);
+ esp += 2;
+ *esp = obj[1];
+ return o_push_estack;
+ } else { /* done */
+ esp -= 3; /* pop mark, object, proc */
+ return o_pop_estack;
+ }
+}
+/* Vacuous cleanup procedure */
+private int
+forall_cleanup(os_ptr op)
+{
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zgeneric_op_defs[] =
+{
+ {"1copy", zcopy},
+ {"2forall", zforall},
+ {"2get", zget},
+ {"3getinterval", zgetinterval},
+ {"1length", zlength},
+ {"3put", zput},
+ {"3putinterval", zputinterval},
+ /* Internal operators */
+ {"0%array_continue", array_continue},
+ {"0%dict_continue", dict_continue},
+ {"0%packedarray_continue", packedarray_continue},
+ {"0%string_continue", string_continue},
+ op_def_end(0)
+};
+
+/* ------ Shared routines ------ */
+
+/* Copy an interval from one operand to another. */
+/* This is used by both putinterval and string/array copy. */
+/* The destination is known to be an array or string, */
+/* and the starting index is known to be less than or equal to */
+/* its length; nothing else has been checked. */
+private int
+copy_interval(os_ptr prto, uint index, os_ptr prfrom, client_name_t cname)
+{
+ int fromtype = r_type(prfrom);
+ uint fromsize = r_size(prfrom);
+
+ if (!(fromtype == r_type(prto) ||
+ ((fromtype == t_shortarray || fromtype == t_mixedarray) &&
+ r_type(prto) == t_array))
+ )
+ return_op_typecheck(prfrom);
+ check_read(*prfrom);
+ check_write(*prto);
+ if (fromsize > r_size(prto) - index)
+ return_error(e_rangecheck);
+ switch (fromtype) {
+ case t_array:
+ { /* We have to worry about aliasing, */
+ /* but refcpy_to_old takes care of it for us. */
+ return refcpy_to_old(prto, index, prfrom->value.refs,
+ fromsize, cname);
+ }
+ case t_string:
+ { /* We have to worry about aliasing. */
+ const byte *from = prfrom->value.bytes;
+ byte *to = prto->value.bytes + index;
+ uint i;
+
+ if (from + fromsize <= to || to + fromsize <= from)
+ memcpy(to, from, fromsize);
+ else if (to < from)
+ for (i = fromsize; i != 0; i--, from++, to++)
+ *to = *from;
+ else
+ for (i = fromsize, from += i, to += i; i != 0; i--)
+ *--to = *--from;
+ }
+ break;
+ case t_mixedarray:
+ case t_shortarray:
+ { /* We don't have to worry about aliasing, because */
+ /* packed arrays are read-only and hence the destination */
+ /* can't be a packed array. */
+ int i;
+ const ref_packed *packed = prfrom->value.packed;
+ ref *pdest = prto->value.refs + index;
+ ref elt;
+
+ for (i = 0; i < fromsize; i++, pdest++) {
+ packed_get(packed, &elt);
+ ref_assign_old(prto, pdest, &elt, cname);
+ packed = packed_next(packed);
+ }
+ }
+ break;
+ }
+ return 0;
+}
diff --git a/pstoraster/zgstate.c b/pstoraster/zgstate.c
new file mode 100644
index 000000000..b9fabe1a4
--- /dev/null
+++ b/pstoraster/zgstate.c
@@ -0,0 +1,450 @@
+/* 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$ */
+/* Graphics state operators */
+#include "math_.h"
+#include "ghost.h"
+#include "oper.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "istruct.h"
+#include "igstate.h"
+#include "gsmatrix.h"
+#include "store.h"
+
+/* Forward references */
+private int num_param(P2(const_os_ptr, int (*)(P2(gs_state *, floatp))));
+
+/* Structure descriptors */
+private_st_int_gstate();
+
+/* ------ Operations on the entire graphics state ------ */
+
+/* The current graphics state */
+gs_state *igs;
+
+/* "Client" procedures */
+private void *gs_istate_alloc(P1(gs_memory_t * mem));
+private int gs_istate_copy(P2(void *to, const void *from));
+private void gs_istate_free(P2(void *old, gs_memory_t * mem));
+private const gs_state_client_procs istate_procs =
+{
+ gs_istate_alloc,
+ gs_istate_copy,
+ gs_istate_free
+};
+
+/* Initialize the graphics stack. */
+void
+igs_init(void)
+{
+ gs_register_struct_root(imemory, NULL, (void **)&igs, "igs");
+ igs = int_gstate_alloc(iimemory);
+}
+gs_state *
+int_gstate_alloc(gs_ref_memory_t * mem)
+{
+ int_gstate *iigs;
+ ref proc0;
+ gs_state *pgs = gs_state_alloc((gs_memory_t *) mem);
+
+ iigs = gs_alloc_struct((gs_memory_t *) mem, int_gstate, &st_int_gstate,
+ "int_gstate_alloc(int_gstate)");
+ int_gstate_map_refs(iigs, make_null);
+ make_empty_array(&iigs->dash_pattern, a_all);
+ gs_alloc_ref_array(mem, &proc0, a_readonly + a_executable, 2,
+ "int_gstate_alloc(proc0)");
+ make_oper(proc0.value.refs, 0, zpop);
+ make_real(proc0.value.refs + 1, 0.0);
+ iigs->black_generation = proc0;
+ iigs->undercolor_removal = proc0;
+ clear_pagedevice(iigs);
+ gs_state_set_client(pgs, iigs, &istate_procs);
+ /* PostScript code wants limit clamping enabled. */
+ gs_setlimitclamp(pgs, true);
+ /*
+ * gsave and grestore only work properly
+ * if there are always at least 2 entries on the stack.
+ * We count on the PostScript initialization code to do a gsave.
+ */
+ return pgs;
+}
+
+/* - gsave - */
+int
+zgsave(register os_ptr op)
+{
+ return gs_gsave(igs);
+}
+
+/* - grestore - */
+int
+zgrestore(register os_ptr op)
+{
+ return gs_grestore(igs);
+}
+
+/* - grestoreall - */
+int
+zgrestoreall(register os_ptr op)
+{
+ return gs_grestoreall(igs);
+}
+
+/* - initgraphics - */
+private int
+zinitgraphics(register os_ptr op)
+{
+ /* gs_initgraphics does a setgray; we must clear the interpreter's */
+ /* cached copy of the color space object. */
+ int code = gs_initgraphics(igs);
+
+ if (code >= 0)
+ make_null(&istate->colorspace.array);
+ return code;
+}
+
+/* ------ Operations on graphics state elements ------ */
+
+/* <num> setlinewidth - */
+private int
+zsetlinewidth(register os_ptr op)
+{ /*
+ * The Red Book doesn't say anything about this, but Adobe
+ * interpreters return (or perhaps store) the absolute value
+ * of the width.
+ */
+ double width;
+ int code = real_param(op, &width);
+
+ if (code < 0)
+ return_op_typecheck(op);
+ code = gs_setlinewidth(igs, fabs(width));
+ if (code >= 0)
+ pop(1);
+ return code;
+}
+
+/* - currentlinewidth <num> */
+private int
+zcurrentlinewidth(register os_ptr op)
+{
+ push(1);
+ make_real(op, gs_currentlinewidth(igs));
+ return 0;
+}
+
+/* <cap_int> .setlinecap - */
+private int
+zsetlinecap(register os_ptr op)
+{
+ int param;
+ int code = int_param(op, max_int, &param);
+
+ if (code < 0 || (code = gs_setlinecap(igs, (gs_line_cap) param)) < 0)
+ return code;
+ pop(1);
+ return 0;
+}
+
+/* - currentlinecap <cap_int> */
+private int
+zcurrentlinecap(register os_ptr op)
+{
+ push(1);
+ make_int(op, (int)gs_currentlinecap(igs));
+ return 0;
+}
+
+/* <join_int> .setlinejoin - */
+private int
+zsetlinejoin(register os_ptr op)
+{
+ int param;
+ int code = int_param(op, max_int, &param);
+
+ if (code < 0 || (code = gs_setlinejoin(igs, (gs_line_join) param)) < 0)
+ return code;
+ pop(1);
+ return 0;
+}
+
+/* - currentlinejoin <join_int> */
+private int
+zcurrentlinejoin(register os_ptr op)
+{
+ push(1);
+ make_int(op, (int)gs_currentlinejoin(igs));
+ return 0;
+}
+
+/* <num> setmiterlimit - */
+private int
+zsetmiterlimit(register os_ptr op)
+{
+ return num_param(op, gs_setmiterlimit);
+}
+
+/* - currentmiterlimit <num> */
+private int
+zcurrentmiterlimit(register os_ptr op)
+{
+ push(1);
+ make_real(op, gs_currentmiterlimit(igs));
+ return 0;
+}
+
+/* <array> <offset> setdash - */
+private int
+zsetdash(register os_ptr op)
+{
+ os_ptr op1 = op - 1;
+ double offset;
+ int code = real_param(op, &offset);
+ uint i, n;
+ gs_memory_t *mem = imemory;
+ float *pattern;
+
+ if (code < 0)
+ return_op_typecheck(op);
+ if (!r_is_array(op1))
+ return_op_typecheck(op1);
+ /* Adobe interpreters apparently don't check the array for */
+ /* read access, so we won't either. */
+ /*check_read(*op1); */
+ /* Unpack the dash pattern and check it */
+ n = r_size(op1);
+ pattern =
+ (float *)gs_alloc_byte_array(mem, n, sizeof(float), "setdash");
+
+ if (pattern == 0)
+ return_error(e_VMerror);
+ for (i = 0, code = 0; i < n && code >= 0; ++i) {
+ ref element;
+
+ array_get(op1, (long)i, &element);
+ code = float_param(&element, &pattern[i]);
+ }
+ if (code >= 0)
+ code = gs_setdash(igs, pattern, n, offset);
+ gs_free_object(mem, pattern, "setdash"); /* gs_setdash copies this */
+ if (code < 0)
+ return code;
+ ref_assign(&istate->dash_pattern, op1);
+ pop(2);
+ return code;
+}
+
+/* - currentdash <array> <offset> */
+private int
+zcurrentdash(register os_ptr op)
+{
+ push(2);
+ ref_assign(op - 1, &istate->dash_pattern);
+ make_real(op, gs_currentdash_offset(igs));
+ return 0;
+}
+
+/* <num> setflat - */
+private int
+zsetflat(register os_ptr op)
+{
+ return num_param(op, gs_setflat);
+}
+
+/* - currentflat <num> */
+private int
+zcurrentflat(register os_ptr op)
+{
+ push(1);
+ make_real(op, gs_currentflat(igs));
+ return 0;
+}
+
+/* ------ Extensions ------ */
+
+/* <bool> .setaccuratecurves - */
+private int
+zsetaccuratecurves(register os_ptr op)
+{
+ check_type(*op, t_boolean);
+ gs_setaccuratecurves(igs, op->value.boolval);
+ pop(1);
+ return 0;
+}
+
+/* - .currentaccuratecurves <bool> */
+private int
+zcurrentaccuratecurves(register os_ptr op)
+{
+ push(1);
+ make_bool(op, gs_currentaccuratecurves(igs));
+ return 0;
+}
+
+/* <adjust.x> <adjust.y> .setfilladjust2 - */
+private int
+zsetfilladjust2(register os_ptr op)
+{
+ double adjust[2];
+ int code = num_params(op, 2, adjust);
+
+ if (code < 0)
+ return code;
+ code = gs_setfilladjust(igs, adjust[0], adjust[1]);
+ if (code < 0)
+ return code;
+ pop(2);
+ return 0;
+}
+
+/* - .currentfilladjust2 <adjust.x> <adjust.y> */
+private int
+zcurrentfilladjust2(register os_ptr op)
+{
+ gs_point adjust;
+
+ push(2);
+ gs_currentfilladjust(igs, &adjust);
+ make_real(op - 1, adjust.x);
+ make_real(op, adjust.y);
+ return 0;
+}
+
+/* <bool> .setdashadapt - */
+private int
+zsetdashadapt(register os_ptr op)
+{
+ check_type(*op, t_boolean);
+ gs_setdashadapt(igs, op->value.boolval);
+ pop(1);
+ return 0;
+}
+
+/* - .currentdashadapt <bool> */
+private int
+zcurrentdashadapt(register os_ptr op)
+{
+ push(1);
+ make_bool(op, gs_currentdashadapt(igs));
+ return 0;
+}
+
+/* <num> <bool> .setdotlength - */
+private int
+zsetdotlength(register os_ptr op)
+{
+ double length;
+ int code = real_param(op - 1, &length);
+
+ if (code < 0)
+ return code;
+ check_type(*op, t_boolean);
+ code = gs_setdotlength(igs, length, op->value.boolval);
+ if (code < 0)
+ return code;
+ pop(2);
+ return 0;
+}
+
+/* - .currentdotlength <num> <bool> */
+private int
+zcurrentdotlength(register os_ptr op)
+{
+ push(2);
+ make_real(op - 1, gs_currentdotlength(igs));
+ make_bool(op, gs_currentdotlength_absolute(igs));
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zgstate_op_defs[] =
+{
+ {"0.currentaccuratecurves", zcurrentaccuratecurves},
+ {"0currentdash", zcurrentdash},
+ {"0.currentdashadapt", zcurrentdashadapt},
+ {"0.currentdotlength", zcurrentdotlength},
+ {"0.currentfilladjust2", zcurrentfilladjust2},
+ {"0currentflat", zcurrentflat},
+ {"0currentlinecap", zcurrentlinecap},
+ {"0currentlinejoin", zcurrentlinejoin},
+ {"0currentlinewidth", zcurrentlinewidth},
+ {"0currentmiterlimit", zcurrentmiterlimit},
+ {"0grestore", zgrestore},
+ {"0grestoreall", zgrestoreall},
+ {"0gsave", zgsave},
+ {"0initgraphics", zinitgraphics},
+ {"1.setaccuratecurves", zsetaccuratecurves},
+ {"2setdash", zsetdash},
+ {"1.setdashadapt", zsetdashadapt},
+ {"2.setdotlength", zsetdotlength},
+ {"2.setfilladjust2", zsetfilladjust2},
+ {"1setflat", zsetflat},
+ {"1.setlinecap", zsetlinecap},
+ {"1.setlinejoin", zsetlinejoin},
+ {"1setlinewidth", zsetlinewidth},
+ {"1setmiterlimit", zsetmiterlimit},
+ op_def_end(0)
+};
+
+/* ------ Internal routines ------ */
+
+/* Allocate the interpreter's part of a graphics state. */
+private void *
+gs_istate_alloc(gs_memory_t * mem)
+{
+ return gs_alloc_struct(mem, int_gstate, &st_int_gstate, "int_gsave");
+}
+
+/* Copy the interpreter's part of a graphics state. */
+private int
+gs_istate_copy(void *to, const void *from)
+{
+ *(int_gstate *) to = *(const int_gstate *)from;
+ return 0;
+}
+
+/* Free the interpreter's part of a graphics state. */
+private void
+gs_istate_free(void *old, gs_memory_t * mem)
+{
+ gs_free_object(mem, old, "int_grestore");
+}
+
+/* Get a numeric parameter */
+private int
+num_param(const_os_ptr op, int (*pproc)(P2(gs_state *, floatp)))
+{
+ double param;
+ int code = real_param(op, &param);
+
+ if (code < 0)
+ return_op_typecheck(op);
+ code = (*pproc)(igs, param);
+ if (!code)
+ pop(1);
+ return code;
+}
diff --git a/pstoraster/zhsb.c b/pstoraster/zhsb.c
new file mode 100644
index 000000000..cbc5586a4
--- /dev/null
+++ b/pstoraster/zhsb.c
@@ -0,0 +1,68 @@
+/* Copyright (C) 1994, 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$ */
+/* HSB color operators */
+#include "ghost.h"
+#include "oper.h"
+#include "igstate.h"
+#include "store.h"
+#include "gshsb.h"
+
+/* - currenthsbcolor <hue> <saturation> <brightness> */
+private int
+zcurrenthsbcolor(register os_ptr op)
+{
+ float par[3];
+
+ gs_currenthsbcolor(igs, par);
+ push(3);
+ make_floats(op - 2, par, 3);
+ return 0;
+}
+
+/* <hue> <saturation> <brightness> sethsbcolor - */
+private int
+zsethsbcolor(register os_ptr op)
+{
+ double par[3];
+ int code;
+
+ if ((code = num_params(op, 3, par)) < 0 ||
+ (code = gs_sethsbcolor(igs, par[0], par[1], par[2])) < 0
+ )
+ return code;
+ make_null(&istate->colorspace.array);
+ pop(3);
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zhsb_op_defs[] =
+{
+ {"0currenthsbcolor", zcurrenthsbcolor},
+ {"3sethsbcolor", zsethsbcolor},
+ op_def_end(0)
+};
diff --git a/pstoraster/zht.c b/pstoraster/zht.c
new file mode 100644
index 000000000..006d015fc
--- /dev/null
+++ b/pstoraster/zht.c
@@ -0,0 +1,265 @@
+/* Copyright (C) 1989, 1991, 1993, 1994, 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$ */
+/* Halftone definition operators */
+#include "ghost.h"
+#include "memory_.h"
+#include "oper.h"
+#include "estack.h"
+#include "gsstruct.h" /* must precede igstate.h, */
+ /* because of #ifdef in gsht.h */
+#include "ialloc.h"
+#include "igstate.h"
+#include "gsmatrix.h"
+#include "gxdevice.h" /* for gzht.h */
+#include "gzht.h"
+#include "gsstate.h"
+#include "iht.h" /* prototypes */
+#include "store.h"
+
+/* Forward references */
+private int screen_sample(P1(os_ptr));
+private int set_screen_continue(P1(os_ptr));
+private int screen_cleanup(P1(os_ptr));
+
+/* - .currenthalftone <dict> 0 */
+/* - .currenthalftone <frequency> <angle> <proc> 1 */
+/* - .currenthalftone <red_freq> ... <gray_proc> 2 */
+private int
+zcurrenthalftone(register os_ptr op)
+{
+ gs_halftone ht;
+
+ gs_currenthalftone(igs, &ht);
+ switch (ht.type) {
+ case ht_type_screen:
+ push(4);
+ make_real(op - 3, ht.params.screen.frequency);
+ make_real(op - 2, ht.params.screen.angle);
+ op[-1] = istate->screen_procs.colored.gray;
+ make_int(op, 1);
+ break;
+ case ht_type_colorscreen:
+ push(13);
+ {
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ os_ptr opc = op - 12 + i * 3;
+ gs_screen_halftone *pht =
+ &ht.params.colorscreen.screens.indexed[i];
+
+ make_real(opc, pht->frequency);
+ make_real(opc + 1, pht->angle);
+ opc[2] = istate->screen_procs.indexed[i];
+ }
+ }
+ make_int(op, 2);
+ break;
+ default: /* Screen was set by sethalftone. */
+ push(2);
+ op[-1] = istate->halftone;
+ make_int(op, 0);
+ break;
+ }
+ return 0;
+}
+
+/* - .currentscreenlevels <int> */
+private int
+zcurrentscreenlevels(register os_ptr op)
+{
+ push(1);
+ make_int(op, gs_currentscreenlevels(igs));
+ return 0;
+}
+
+/* The setscreen operator is complex because it has to sample */
+/* each pixel in the pattern cell, calling a procedure, and then */
+/* sort the result into a whitening order. */
+
+/* Layout of stuff pushed on estack: */
+/* Control mark, */
+/* [other stuff for other screen-setting operators], */
+/* finishing procedure (or 0), */
+/* spot procedure, */
+/* enumeration structure (as bytes). */
+#define snumpush 4
+#define sproc esp[-1]
+#define senum r_ptr(esp, gs_screen_enum)
+
+/* Forward references */
+int zscreen_enum_init(P7(os_ptr, const gx_ht_order *, gs_screen_halftone *,
+ ref *, int, int (*)(P1(os_ptr)), gs_memory_t *));
+private int setscreen_finish(P1(os_ptr));
+
+/* <frequency> <angle> <proc> setscreen - */
+private int
+zsetscreen(register os_ptr op)
+{
+ gs_screen_halftone screen;
+ gx_ht_order order;
+ int code = zscreen_params(op, &screen);
+ gs_memory_t *mem;
+
+ if (code < 0)
+ return code;
+ mem = (gs_memory_t *)idmemory->spaces.indexed[r_space_index(op)];
+ /*
+ * Allocate the halftone in the same VM space as the procedure.
+ * This keeps the space relationships consistent.
+ */
+ code = gs_screen_order_init_memory(&order, igs, &screen,
+ gs_currentaccuratescreens(), mem);
+ if (code < 0)
+ return code;
+ return zscreen_enum_init(op, &order, &screen, op, 3,
+ setscreen_finish, mem);
+}
+/* We break out the body of this operator so it can be shared with */
+/* the code for Type 1 halftones in sethalftone. */
+int
+zscreen_enum_init(os_ptr op, const gx_ht_order * porder,
+ gs_screen_halftone * psp, ref * pproc, int npop,
+ int (*finish_proc)(P1(os_ptr)), gs_memory_t * mem)
+{
+ gs_screen_enum *penum;
+ int code;
+
+ check_estack(snumpush + 1);
+ penum = gs_screen_enum_alloc(imemory, "setscreen");
+ if (penum == 0)
+ return_error(e_VMerror);
+ make_istruct(esp + snumpush, 0, penum); /* do early for screen_cleanup in case of error */
+ code = gs_screen_enum_init_memory(penum, porder, igs, psp, mem);
+ if (code < 0) {
+ screen_cleanup(op);
+ return code;
+ }
+ /* Push everything on the estack */
+ make_mark_estack(esp + 1, es_other, screen_cleanup);
+ esp += snumpush;
+ make_op_estack(esp - 2, finish_proc);
+ sproc = *pproc;
+ push_op_estack(screen_sample);
+ pop(npop);
+ return o_push_estack;
+}
+/* Set up the next sample */
+private int
+screen_sample(register os_ptr op)
+{
+ gs_screen_enum *penum = senum;
+ gs_point pt;
+ int code = gs_screen_currentpoint(penum, &pt);
+ ref proc;
+
+ switch (code) {
+ default:
+ return code;
+ case 1:
+ /* All done */
+ if (real_opproc(esp - 2) != 0)
+ code = (*real_opproc(esp - 2)) (op);
+ esp -= snumpush;
+ screen_cleanup(op);
+ return (code < 0 ? code : o_pop_estack);
+ case 0:
+ ;
+ }
+ push(2);
+ make_real(op - 1, pt.x);
+ make_real(op, pt.y);
+ proc = sproc;
+ push_op_estack(set_screen_continue);
+ *++esp = proc;
+ return o_push_estack;
+}
+/* Continuation procedure for processing sampled pixels. */
+private int
+set_screen_continue(register os_ptr op)
+{
+ double value;
+ int code = real_param(op, &value);
+
+ if (code < 0)
+ return code;
+ code = gs_screen_next(senum, value);
+ if (code < 0)
+ return code;
+ pop(1);
+ op--;
+ return screen_sample(op);
+}
+/* Finish setscreen. */
+private int
+setscreen_finish(os_ptr op)
+{
+ gs_screen_install(senum);
+ istate->screen_procs.colored.red = sproc;
+ istate->screen_procs.colored.green = sproc;
+ istate->screen_procs.colored.blue = sproc;
+ istate->screen_procs.colored.gray = sproc;
+ make_null(&istate->halftone);
+ return 0;
+}
+/* Clean up after screen enumeration */
+private int
+screen_cleanup(os_ptr op)
+{
+ ifree_object(esp[snumpush].value.pstruct, "screen_cleanup");
+ return 0;
+}
+
+/* ------ Utility procedures ------ */
+
+/* Get parameters for a single screen. */
+int
+zscreen_params(os_ptr op, gs_screen_halftone * phs)
+{
+ double fa[2];
+ int code = num_params(op - 1, 2, fa);
+
+ if (code < 0)
+ return code;
+ check_proc(*op);
+ phs->frequency = fa[0];
+ phs->angle = fa[1];
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zht_op_defs[] =
+{
+ {"0.currenthalftone", zcurrenthalftone},
+ {"0.currentscreenlevels", zcurrentscreenlevels},
+ {"3setscreen", zsetscreen},
+ /* Internal operators */
+ {"0%screen_sample", screen_sample},
+ {"1%set_screen_continue", set_screen_continue},
+ {"0%setscreen_finish", setscreen_finish},
+ op_def_end(0)
+};
diff --git a/pstoraster/zht1.c b/pstoraster/zht1.c
new file mode 100644
index 000000000..72322093d
--- /dev/null
+++ b/pstoraster/zht1.c
@@ -0,0 +1,156 @@
+/* Copyright (C) 1994, 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$ */
+/* setcolorscreen operator */
+#include "ghost.h"
+#include "memory_.h"
+#include "oper.h"
+#include "estack.h"
+#include "gsstruct.h" /* must precede igstate.h, */
+ /* because of #ifdef in gsht.h */
+#include "ialloc.h"
+#include "igstate.h"
+#include "gsmatrix.h"
+#include "gxdevice.h" /* for gzht.h */
+#include "gzht.h"
+#include "gsstate.h"
+#include "iht.h"
+#include "store.h"
+
+/* Dummy spot function */
+float
+spot_dummy(floatp x, floatp y)
+{
+ return (x + y) / 2;
+}
+
+/* <red_freq> ... <gray_proc> setcolorscreen - */
+private int setcolorscreen_finish(P1(os_ptr));
+private int setcolorscreen_cleanup(P1(os_ptr));
+private int
+zsetcolorscreen(register os_ptr op)
+{
+ gs_colorscreen_halftone cscreen;
+ ref sprocs[4];
+ gs_halftone *pht;
+ gx_device_halftone *pdht;
+ int i;
+ int code = 0;
+ int space = 0;
+ gs_memory_t *mem;
+
+ for (i = 0; i < 4; i++) {
+ os_ptr op1 = op - 9 + i * 3;
+ int code = zscreen_params(op1, &cscreen.screens.indexed[i]);
+
+ if (code < 0)
+ return code;
+ cscreen.screens.indexed[i].spot_function = spot_dummy;
+ sprocs[i] = *op1;
+ space = max(space, r_space_index(op1));
+ }
+ mem = (gs_memory_t *)idmemory->spaces.indexed[space];
+ check_estack(8); /* for sampling screens */
+ rc_alloc_struct_0(pht, gs_halftone, &st_halftone,
+ mem, pht = 0, "setcolorscreen(halftone)");
+ rc_alloc_struct_0(pdht, gx_device_halftone, &st_device_halftone,
+ mem, pdht = 0, "setcolorscreen(device halftone)");
+ if (pht == 0 || pdht == 0)
+ code = gs_note_error(e_VMerror);
+ else {
+ pht->type = ht_type_colorscreen;
+ pht->params.colorscreen = cscreen;
+ code = gs_sethalftone_prepare(igs, pht, pdht);
+ }
+ if (code >= 0) { /* Schedule the sampling of the screens. */
+ es_ptr esp0 = esp; /* for backing out */
+
+ esp += 8;
+ make_mark_estack(esp - 7, es_other, setcolorscreen_cleanup);
+ memcpy(esp - 6, sprocs, sizeof(ref) * 4); /* procs */
+ make_istruct(esp - 2, 0, pht);
+ make_istruct(esp - 1, 0, pdht);
+ make_op_estack(esp, setcolorscreen_finish);
+ for (i = 0; i < 4; i++) {
+ /* Shuffle the indices to correspond to */
+ /* the component order. */
+ code = zscreen_enum_init(op,
+ &pdht->components[(i + 1) & 3].corder,
+ &pht->params.colorscreen.screens.indexed[i],
+ &sprocs[i], 0, 0, mem);
+ if (code < 0) {
+ esp = esp0;
+ break;
+ }
+ }
+ }
+ if (code < 0) {
+ gs_free_object(mem, pdht, "setcolorscreen(device halftone)");
+ gs_free_object(mem, pht, "setcolorscreen(halftone)");
+ return code;
+ }
+ pop(12);
+ return o_push_estack;
+}
+/* Install the color screen after sampling. */
+private int
+setcolorscreen_finish(os_ptr op)
+{
+ gx_device_halftone *pdht = r_ptr(esp, gx_device_halftone);
+ int code;
+
+ pdht->order = pdht->components[0].corder;
+ code = gx_ht_install(igs, r_ptr(esp - 1, gs_halftone), pdht);
+ if (code < 0)
+ return code;
+ memcpy(istate->screen_procs.indexed, esp - 5, sizeof(ref) * 4);
+ make_null(&istate->halftone);
+ esp -= 7;
+ setcolorscreen_cleanup(op);
+ return o_pop_estack;
+}
+/* Clean up after installing the color screen. */
+private int
+setcolorscreen_cleanup(os_ptr op)
+{
+ gs_halftone *pht = r_ptr(esp + 6, gs_halftone);
+ gx_device_halftone *pdht = r_ptr(esp + 7, gx_device_halftone);
+
+ gs_free_object(pdht->rc.memory, pdht,
+ "setcolorscreen_cleanup(device halftone)");
+ gs_free_object(pht->rc.memory, pht,
+ "setcolorscreen_cleanup(halftone)");
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zht1_op_defs[] =
+{
+ {"<setcolorscreen", zsetcolorscreen},
+ /* Internal operators */
+ {"0%setcolorscreen_finish", setcolorscreen_finish},
+ op_def_end(0)
+};
diff --git a/pstoraster/zht2.c b/pstoraster/zht2.c
new file mode 100644
index 000000000..9eeee0ed2
--- /dev/null
+++ b/pstoraster/zht2.c
@@ -0,0 +1,357 @@
+/* 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$ */
+/* Level 2 sethalftone operator */
+#include "ghost.h"
+#include "oper.h"
+#include "gsstruct.h"
+#include "gxdevice.h" /* for gzht.h */
+#include "gzht.h"
+#include "estack.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "idparam.h"
+#include "igstate.h"
+#include "icolor.h"
+#include "iht.h"
+#include "store.h"
+
+/* Forward references */
+private int dict_spot_params(P4(const ref *, gs_spot_halftone *,
+ ref *, ref *));
+private int dict_spot_results(P2(ref *, const gs_spot_halftone *));
+private int dict_threshold_params(P3(const ref *,
+ gs_threshold_halftone *, ref *));
+
+/* <dict> <dict5> .sethalftone5 - */
+float spot_dummy(P2(floatp, floatp)); /* in zht1.c */
+int spot_sample_finish(P1(os_ptr)); /* in zht.c */
+private int sethalftone_finish(P1(os_ptr));
+private int sethalftone_cleanup(P1(os_ptr));
+private int
+zsethalftone5(register os_ptr op)
+{
+ uint count;
+ gs_halftone_component *phtc;
+ gs_halftone_component *pc;
+ int code = 0;
+ int i, j;
+ gs_halftone *pht;
+ gx_device_halftone *pdht;
+ static const char *const color_names[] = {
+ gs_ht_separation_name_strings
+ };
+ ref sprocs[countof(color_names)];
+ ref tprocs[countof(color_names)];
+ gs_memory_t *mem;
+ int npop = 2;
+
+ check_type(*op, t_dictionary);
+ check_dict_read(*op);
+ check_type(op[-1], t_dictionary);
+ check_dict_read(op[-1]);
+ count = 0;
+ for (i = 0; i < countof(color_names); i++) {
+ ref *pvalue;
+
+ if (dict_find_string(op, color_names[i], &pvalue) > 0)
+ count++;
+ else if (i == gs_ht_separation_Default)
+ return_error(e_typecheck);
+ }
+ mem = (gs_memory_t *) idmemory->spaces.indexed[r_space_index(op - 1)];
+ check_estack(5); /* for sampling Type 1 screens */
+ refset_null(sprocs, countof(sprocs));
+ refset_null(tprocs, countof(tprocs));
+ rc_alloc_struct_0(pht, gs_halftone, &st_halftone,
+ imemory, pht = 0, ".sethalftone5");
+ phtc = gs_alloc_struct_array(mem, count, gs_halftone_component,
+ &st_ht_component_element,
+ ".sethalftone5");
+ rc_alloc_struct_0(pdht, gx_device_halftone, &st_device_halftone,
+ imemory, pdht = 0, ".sethalftone5");
+ if (pht == 0 || phtc == 0 || pdht == 0)
+ code = gs_note_error(e_VMerror);
+ else
+ for (i = 0, j = 0, pc = phtc; i < countof(color_names); i++) {
+ int type;
+ ref *pvalue;
+
+ if (dict_find_string(op, color_names[i], &pvalue) > 0) {
+ check_type_only(*pvalue, t_dictionary);
+ check_dict_read(*pvalue);
+ if (dict_int_param(pvalue, "HalftoneType", 1, 5, 0,
+ &type) < 0
+ ) {
+ code = gs_note_error(e_typecheck);
+ break;
+ }
+ switch (type) {
+ default:
+ code = gs_note_error(e_rangecheck);
+ break;
+ case 1:
+ code = dict_spot_params(pvalue,
+ &pc->params.spot, sprocs + j,
+ tprocs + j);
+ pc->params.spot.screen.spot_function =
+ spot_dummy;
+ pc->type = ht_type_spot;
+ break;
+ case 3:
+ code = dict_threshold_params(pvalue,
+ &pc->params.threshold, tprocs + j);
+ pc->type = ht_type_threshold;
+ break;
+ }
+ if (code < 0)
+ break;
+ pc->cname = (gs_ht_separation_name) i;
+ pc++, j++;
+ }
+ }
+ if (code >= 0) {
+ /*
+ * We think that Type 2 and Type 4 halftones, like
+ * screens set by setcolorscreen, adapt automatically to
+ * the device color space, so we need to mark them
+ * with a different internal halftone type.
+ */
+ int type = 0;
+
+ dict_int_param(op - 1, "HalftoneType", 1, 5, 0, &type);
+ pht->type =
+ (type == 2 || type == 4 ? ht_type_multiple_colorscreen :
+ ht_type_multiple);
+ pht->params.multiple.components = phtc;
+ pht->params.multiple.num_comp = count;
+ code = gs_sethalftone_prepare(igs, pht, pdht);
+ }
+ if (code >= 0)
+ for (j = 0, pc = phtc; j < count; j++, pc++) {
+ if (pc->type == ht_type_spot) {
+ ref *pvalue;
+
+ dict_find_string(op, color_names[pc->cname], &pvalue);
+ code = dict_spot_results(pvalue, &pc->params.spot);
+ if (code < 0)
+ break;
+ }
+ }
+ if (code >= 0) {
+ /*
+ * Schedule the sampling of any Type 1 screens,
+ * and any (Type 1 or Type 3) TransferFunctions.
+ * Save the stack depths in case we have to back out.
+ */
+ uint edepth = ref_stack_count(&e_stack);
+ uint odepth = ref_stack_count(&o_stack);
+ ref odict, odict5;
+
+ odict = op[-1];
+ odict5 = *op;
+ pop(2);
+ op = osp;
+ esp += 5;
+ make_mark_estack(esp - 4, es_other, sethalftone_cleanup);
+ esp[-3] = odict;
+ make_istruct(esp - 2, 0, pht);
+ make_istruct(esp - 1, 0, pdht);
+ make_op_estack(esp, sethalftone_finish);
+ for (j = 0; j < count; j++) {
+ gx_ht_order *porder =
+ (pdht->components == 0 ? &pdht->order :
+ &pdht->components[j].corder);
+
+ switch (phtc[j].type) {
+ case ht_type_spot:
+ code = zscreen_enum_init(op, porder,
+ &phtc[j].params.spot.screen,
+ &sprocs[j], 0, 0, mem);
+ if (code < 0)
+ break;
+ /* falls through */
+ case ht_type_threshold:
+ if (!r_has_type(tprocs + j, t__invalid)) {
+ /* Schedule TransferFunction sampling. */
+ /****** check_xstack IS WRONG ******/
+ check_ostack(zcolor_remap_one_ostack);
+ check_estack(zcolor_remap_one_estack);
+ code = zcolor_remap_one(tprocs + j,
+ op, porder->transfer, igs,
+ zcolor_remap_one_finish);
+ op = osp;
+ }
+ break;
+ default: /* not possible here, but to keep */
+ /* the compilers happy.... */
+ ;
+ }
+ if (code < 0) { /* Restore the stack. */
+ ref_stack_pop_to(&o_stack, odepth);
+ ref_stack_pop_to(&e_stack, edepth);
+ op = osp;
+ op[-1] = odict;
+ *op = odict5;
+ break;
+ }
+ npop = 0;
+ }
+ }
+ if (code < 0) {
+ gs_free_object(mem, pdht, ".sethalftone5");
+ gs_free_object(mem, phtc, ".sethalftone5");
+ gs_free_object(mem, pht, ".sethalftone5");
+ return code;
+ }
+ pop(npop);
+ return o_push_estack;
+}
+/* Install the halftone after sampling. */
+private int
+sethalftone_finish(os_ptr op)
+{
+ gx_device_halftone *pdht = r_ptr(esp, gx_device_halftone);
+ int code;
+
+ if (pdht->components)
+ pdht->order = pdht->components[0].corder;
+ code = gx_ht_install(igs, r_ptr(esp - 1, gs_halftone), pdht);
+ if (code < 0)
+ return code;
+ istate->halftone = esp[-2];
+ esp -= 4;
+ sethalftone_cleanup(op);
+ return o_pop_estack;
+}
+/* Clean up after installing the halftone. */
+private int
+sethalftone_cleanup(os_ptr op)
+{
+ gx_device_halftone *pdht = r_ptr(&esp[4], gx_device_halftone);
+ gs_halftone *pht = r_ptr(&esp[3], gs_halftone);
+
+ gs_free_object(pdht->rc.memory, pdht,
+ "sethalftone_cleanup(device halftone)");
+ gs_free_object(pht->rc.memory, pht,
+ "sethalftone_cleanup(halftone)");
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zht2_l2_op_defs[] =
+{
+ op_def_begin_level2(),
+ {"2.sethalftone5", zsethalftone5},
+ /* Internal operators */
+ {"0%sethalftone_finish", sethalftone_finish},
+ op_def_end(0)
+};
+
+/* ------ Internal routines ------ */
+
+/* Extract frequency, angle, spot function, and accurate screens flag */
+/* from a dictionary. */
+private int
+dict_spot_params(const ref * pdict, gs_spot_halftone * psp,
+ ref * psproc, ref * ptproc)
+{
+ int code;
+
+ check_dict_read(*pdict);
+ if ((code = dict_float_param(pdict, "Frequency", 0.0,
+ &psp->screen.frequency)) != 0 ||
+ (code = dict_float_param(pdict, "Angle", 0.0,
+ &psp->screen.angle)) != 0 ||
+ (code = dict_proc_param(pdict, "SpotFunction", psproc, false)) != 0 ||
+ (code = dict_bool_param(pdict, "AccurateScreens",
+ gs_currentaccuratescreens(),
+ &psp->accurate_screens)) < 0 ||
+ (code = dict_proc_param(pdict, "TransferFunction", ptproc, false)) < 0
+ )
+ return (code < 0 ? code : e_undefined);
+ psp->transfer = (code > 0 ? (gs_mapping_proc) 0 : gs_mapped_transfer);
+ psp->transfer_closure.proc = 0;
+ psp->transfer_closure.data = 0;
+ return 0;
+}
+
+/* Set actual frequency and angle in a dictionary. */
+private int
+dict_real_result(ref * pdict, const char *kstr, floatp val)
+{
+ int code = 0;
+ ref *ignore;
+
+ if (dict_find_string(pdict, kstr, &ignore) > 0) {
+ ref rval;
+
+ check_dict_write(*pdict);
+ make_real(&rval, val);
+ code = dict_put_string(pdict, kstr, &rval);
+ }
+ return code;
+}
+private int
+dict_spot_results(ref * pdict, const gs_spot_halftone * psp)
+{
+ int code;
+
+ code = dict_real_result(pdict, "ActualFrequency",
+ psp->screen.actual_frequency);
+ if (code < 0)
+ return code;
+ return dict_real_result(pdict, "ActualAngle",
+ psp->screen.actual_angle);
+}
+
+/* Extract width, height, and thresholds from a dictionary. */
+private int
+dict_threshold_params(const ref * pdict, gs_threshold_halftone * ptp,
+ ref * ptproc)
+{
+ int code;
+ ref *tstring;
+
+ check_dict_read(*pdict);
+ if ((code = dict_int_param(pdict, "Width", 1, 0x7fff, -1,
+ &ptp->width)) < 0 ||
+ (code = dict_int_param(pdict, "Height", 1, 0x7fff, -1,
+ &ptp->height)) < 0 ||
+ (code = dict_find_string(pdict, "Thresholds", &tstring)) <= 0 ||
+ (code = dict_proc_param(pdict, "TransferFunction", ptproc, false)) < 0
+ )
+ return (code < 0 ? code : e_undefined);
+ check_read_type_only(*tstring, t_string);
+ if (r_size(tstring) != (long)ptp->width * ptp->height)
+ return_error(e_rangecheck);
+ ptp->thresholds.data = tstring->value.const_bytes;
+ ptp->thresholds.size = r_size(tstring);
+ ptp->transfer = (code > 0 ? (gs_mapping_proc) 0 : gs_mapped_transfer);
+ ptp->transfer_closure.proc = 0;
+ ptp->transfer_closure.data = 0;
+ return 0;
+}
diff --git a/pstoraster/zimage.c b/pstoraster/zimage.c
new file mode 100644
index 000000000..4a1fe20bf
--- /dev/null
+++ b/pstoraster/zimage.c
@@ -0,0 +1,490 @@
+/* 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$ */
+/* Image operators */
+#include "ghost.h"
+#include "oper.h"
+#include "estack.h" /* for image[mask] */
+#include "gsstruct.h"
+#include "ialloc.h"
+#include "igstate.h"
+#include "ilevel.h"
+#include "store.h"
+#include "gscspace.h"
+#include "gsmatrix.h"
+#include "gsimage.h"
+#include "gxiparam.h"
+#include "stream.h"
+#include "ifilter.h" /* for stream exception handling */
+#include "iimage.h"
+
+/* Forward references */
+private int image_setup(P4(gs_image_t * pim, os_ptr op,
+ const gs_color_space * pcs, int npop));
+private int image_proc_continue(P1(os_ptr));
+private int image_file_continue(P1(os_ptr));
+private int image_file_buffered_continue(P1(os_ptr));
+private int image_string_process(P3(os_ptr, gs_image_enum *, int));
+private int image_cleanup(P1(os_ptr));
+
+/* <width> <height> <bits/sample> <matrix> <datasrc> image - */
+int
+zimage(register os_ptr op)
+{
+ return zimage_opaque_setup(op, false, gs_image_alpha_none,
+ gs_cspace_DeviceGray((const gs_imager_state *)igs), 5);
+}
+
+/* <width> <height> <paint_1s> <matrix> <datasrc> imagemask - */
+int
+zimagemask(register os_ptr op)
+{
+ gs_image_t image;
+
+ check_type(op[-2], t_boolean);
+ gs_image_t_init_mask(&image, op[-2].value.boolval);
+ return image_setup(&image, op, NULL, 5);
+}
+
+/* Common setup for [color|alpha]image. */
+/* Fills in format, BitsPerComponent, Alpha. */
+int
+zimage_opaque_setup(os_ptr op, bool multi, gs_image_alpha_t alpha,
+ const gs_color_space * pcs, int npop)
+{
+ gs_image_t image;
+
+ check_int_leu(op[-2], (level2_enabled ? 12 : 8)); /* bits/sample */
+ gs_image_t_init(&image, pcs);
+ image.BitsPerComponent = (int)op[-2].value.intval;
+ image.Alpha = alpha;
+ image.format =
+ (multi ? gs_image_format_component_planar : gs_image_format_chunky);
+ return image_setup(&image, op, pcs, npop);
+}
+
+/* Common setup for [color|alpha]image and imagemask. */
+/* Fills in Width, Height, ImageMatrix, ColorSpace. */
+private int
+image_setup(gs_image_t * pim, os_ptr op, const gs_color_space * pcs, int npop)
+{
+ int code;
+
+ check_type(op[-4], t_integer); /* width */
+ check_type(op[-3], t_integer); /* height */
+ if (op[-4].value.intval < 0 || op[-3].value.intval < 0)
+ return_error(e_rangecheck);
+ if ((code = read_matrix(op - 1, &pim->ImageMatrix)) < 0)
+ return code;
+ pim->ColorSpace = pcs;
+ pim->Width = (int)op[-4].value.intval;
+ pim->Height = (int)op[-3].value.intval;
+ return zimage_setup((gs_pixel_image_t *) pim, op,
+ pim->ImageMask | pim->CombineWithColor, npop);
+}
+
+/* Common setup for all Level 1 and 2 images, and ImageType 4 images. */
+int
+zimage_setup(const gs_pixel_image_t * pim, const ref * sources,
+ bool uses_color, int npop)
+{
+ gx_image_enum_common_t *pie;
+ int code =
+ gs_image_begin_typed((const gs_image_common_t *)pim, igs,
+ uses_color, &pie);
+
+ if (code < 0)
+ return code;
+ return zimage_data_setup((const gs_pixel_image_t *)pim, pie,
+ sources, npop);
+}
+
+/* Common setup for all Level 1 and 2 images, and ImageType 3 and 4 images. */
+int
+zimage_data_setup(const gs_pixel_image_t * pim, gx_image_enum_common_t * pie,
+ const ref * sources, int npop)
+{
+ int num_sources = pie->num_planes;
+
+#define NUM_PUSH(nsource) ((nsource) * 2 + 4) /* see below */
+ int inumpush = NUM_PUSH(num_sources);
+ int code;
+ gs_image_enum *penum;
+ int px;
+ const ref *pp;
+ bool must_buffer = false;
+
+ /*
+ * We push the following on the estack.
+ * Control mark,
+ * num_sources times (plane N-1 first, plane 0 last):
+ * row buffers (only if must_buffer, otherwise null),
+ * data sources,
+ * current plane index,
+ * current byte in row (only if must_buffer, otherwise 0),
+ * enumeration structure.
+ */
+ check_estack(inumpush + 2); /* stuff above, + continuation + proc */
+ /*
+ * Note that the data sources may be procedures, strings, or (Level
+ * 2 only) files. (The Level 1 reference manual says that Level 1
+ * requires procedures, but Adobe Level 1 interpreters also accept
+ * strings.) The sources must all be of the same type.
+ *
+ * If the sources are files, and two or more are the same file,
+ * we must buffer data for each row; otherwise, we can deliver the
+ * data directly out of the stream buffers. This is OK even if
+ * some of the sources are filters on the same file, since they
+ * have separate buffers.
+ */
+ for (px = 0, pp = sources; px < num_sources; px++, pp++) {
+ switch (r_type(pp)) {
+ case t_file:
+ if (!level2_enabled)
+ return_error(e_typecheck);
+ /* Check for aliasing. */
+ {
+ int pi;
+
+ for (pi = 0; pi < px; ++pi)
+ if (sources[pi].value.pfile == pp->value.pfile)
+ must_buffer = true;
+ }
+ /* falls through */
+ case t_string:
+ if (r_type(pp) != r_type(sources))
+ return_error(e_typecheck);
+ check_read(*pp);
+ break;
+ default:
+ if (!r_is_proc(sources))
+ return_error(e_typecheck);
+ check_proc(*pp);
+ }
+ }
+ if ((penum = gs_image_enum_alloc(imemory, "image_setup")) == 0)
+ return_error(e_VMerror);
+ code = gs_image_common_init(penum, pie, (const gs_data_image_t *)pim,
+ imemory, gs_currentdevice(igs));
+ if (code != 0) { /* error, or empty image */
+ ifree_object(penum, "image_setup");
+ if (code >= 0) /* empty image */
+ pop(npop);
+ return code;
+ }
+ push_mark_estack(es_other, image_cleanup);
+ ++esp;
+ for (px = 0, pp = sources + num_sources - 1;
+ px < num_sources; esp += 2, ++px, --pp
+ ) {
+ make_null(esp); /* buffer */
+ esp[1] = *pp;
+ }
+ esp += 2;
+ make_int(esp - 2, 0); /* current plane */
+ make_int(esp - 1, 0); /* current byte in row */
+ make_istruct(esp, 0, penum);
+ switch (r_type(sources)) {
+ case t_file:
+ if (must_buffer) { /* Allocate a buffer for each row. */
+ for (px = 0; px < num_sources; ++px) {
+ uint size = gs_image_bytes_per_plane_row(penum, px);
+ byte *sbody = ialloc_string(size, "image_setup");
+
+ if (sbody == 0) {
+ esp -= inumpush;
+ image_cleanup(osp);
+ return_error(e_VMerror);
+ }
+ make_string(esp - 4 - px * 2,
+ icurrent_space, size, sbody);
+ }
+ push_op_estack(image_file_buffered_continue);
+ } else {
+ push_op_estack(image_file_continue);
+ }
+ break;
+ case t_string:
+ pop(npop);
+ return image_string_process(osp, penum, num_sources);
+ default: /* procedure */
+ push_op_estack(image_proc_continue);
+ *++esp = sources[0];
+ break;
+ }
+ pop(npop);
+ return o_push_estack;
+}
+/* Pop all the control information off the e-stack. */
+private es_ptr
+zimage_pop_estack(es_ptr tep)
+{
+ es_ptr ep = tep - 3;
+
+ while (!r_is_estack_mark(ep))
+ ep -= 2;
+ return ep - 1;
+}
+/* Continuation for procedure data source. */
+private int
+image_proc_continue(register os_ptr op)
+{
+ gs_image_enum *penum = r_ptr(esp, gs_image_enum);
+ uint size, used;
+ int code;
+ int px;
+ const ref *pp;
+
+ if (!r_has_type_attrs(op, t_string, a_read)) {
+ check_op(1);
+ /* Procedure didn't return a (readable) string. Quit. */
+ esp = zimage_pop_estack(esp);
+ image_cleanup(op);
+ return_error(!r_has_type(op, t_string) ? e_typecheck : e_invalidaccess);
+ }
+ size = r_size(op);
+ if (size == 0)
+ code = 1;
+ else
+ code = gs_image_next(penum, op->value.bytes, size, &used);
+ if (code) { /* Stop now. */
+ esp = zimage_pop_estack(esp);
+ pop(1);
+ op = osp;
+ image_cleanup(op);
+ return (code < 0 ? code : o_pop_estack);
+ }
+ pop(1);
+ px = (int)(esp[-2].value.intval) + 1;
+ pp = esp - 3 - px * 2;
+ if (r_is_estack_mark(pp))
+ px = 0, pp = esp - 3;
+ esp[-2].value.intval = px;
+ push_op_estack(image_proc_continue);
+ *++esp = *pp;
+ return o_push_estack;
+}
+/* Continue processing data from an image with file data sources */
+/* and no file buffering. */
+private int
+image_file_continue(os_ptr op)
+{
+ gs_image_enum *penum = r_ptr(esp, gs_image_enum);
+ const ref *pproc = esp - 3;
+
+ for (;;) {
+ uint size = max_uint;
+ int code;
+ int pn, px;
+ const ref *pp;
+
+ /*
+ * Do a first pass through the files to ensure that they all
+ * have data available in their buffers, and compute the min
+ * of the available amounts.
+ */
+
+ for (pn = 0, pp = pproc; !r_is_estack_mark(pp);
+ ++pn, pp -= 2
+ ) {
+ stream *s = pp->value.pfile;
+ int min_left = sbuf_min_left(s);
+ uint avail;
+
+ while ((avail = sbufavailable(s)) <= min_left) {
+ int next = sgetc(s);
+
+ if (next >= 0) {
+ sputback(s);
+ if (s->end_status == EOFC || s->end_status == ERRC)
+ min_left = 0;
+ continue;
+ }
+ switch (next) {
+ case EOFC:
+ break; /* with avail = 0 */
+ case INTC:
+ case CALLC:
+ return
+ s_handle_read_exception(next, pp,
+ NULL, 0, image_file_continue);
+ default:
+ /* case ERRC: */
+ return_error(e_ioerror);
+ }
+ break; /* for EOFC */
+ }
+ /* Note that in the EOF case, we can get here with */
+ /* avail < min_left. */
+ if (avail >= min_left) {
+ avail -= min_left;
+ if (avail < size)
+ size = avail;
+ } else
+ size = 0;
+ }
+
+ /* Now pass the min of the available buffered data to */
+ /* the image processor. */
+
+ if (size == 0)
+ code = 1;
+ else {
+ int pi;
+ uint used; /* only set for the last plane */
+
+ for (px = 0, pp = pproc, code = 0; px < pn && !code;
+ ++px, pp -= 2
+ )
+ code = gs_image_next(penum, sbufptr(pp->value.pfile),
+ size, &used);
+ /* Now that used has been set, update the streams. */
+ for (pi = 0, pp = pproc; pi < px; ++pi, pp -= 2)
+ sbufskip(pp->value.pfile, used);
+ }
+ if (code) {
+ esp = zimage_pop_estack(esp);
+ image_cleanup(op);
+ return (code < 0 ? code : o_pop_estack);
+ }
+ }
+}
+/* Continue processing data from an image with file data sources */
+/* and file buffering. This is similar to the procedure case. */
+private int
+image_file_buffered_continue(os_ptr op)
+{
+ gs_image_enum *penum = r_ptr(esp, gs_image_enum);
+ const ref *pproc = esp - 3;
+ int px = esp[-2].value.intval;
+ int dpos = esp[-1].value.intval;
+ int code = 0;
+
+ while (!code) {
+ const ref *pp;
+
+ /****** 0 IS BOGUS ******/
+ uint size = gs_image_bytes_per_plane_row(penum, 0);
+ uint avail = size;
+ uint used;
+ int pi;
+
+ /* Accumulate data until we have a full set of planes. */
+ while (!r_is_estack_mark(pp = pproc - px * 2)) {
+ const ref *pb = pp - 1;
+ uint used;
+ int status = sgets(pp->value.pfile, pb->value.bytes,
+ size - dpos, &used);
+
+ if ((dpos += used) == size)
+ dpos = 0, ++px;
+ else
+ switch (status) {
+ case EOFC:
+ if (dpos < avail)
+ avail = dpos;
+ dpos = 0, ++px;
+ break;
+ case INTC:
+ case CALLC:
+ /* Call out to read from a procedure-based stream. */
+ esp[-2].value.intval = px;
+ esp[-1].value.intval = dpos;
+ return s_handle_read_exception(status, pp,
+ NULL, 0, image_file_buffered_continue);
+ default:
+ /*case ERRC: */
+ return_error(e_ioerror);
+ }
+ }
+ /* Pass the data to the image processor. */
+ if (avail == 0) {
+ code = 1;
+ break;
+ }
+ for (pi = 0, pp = pproc; pi < px && !code; ++pi, pp -= 2)
+ code = gs_image_next(penum, pp->value.bytes, avail, &used);
+ /* Reinitialize for the next row. */
+ px = dpos = 0;
+ }
+ esp = zimage_pop_estack(esp);
+ image_cleanup(op);
+ return (code < 0 ? code : o_pop_estack);
+}
+/* Process data from an image with string data sources. */
+/* This never requires callbacks, so it's simpler. */
+private int
+image_string_process(os_ptr op, gs_image_enum * penum, int num_sources)
+{
+ int px = 0;
+
+ for (;;) {
+ const ref *psrc = esp - 3 - px * 2;
+ uint size = r_size(psrc);
+ uint used;
+ int code;
+
+ if (size == 0)
+ code = 1;
+ else
+ code = gs_image_next(penum, psrc->value.bytes, size, &used);
+ if (code) { /* Stop now. */
+ esp -= NUM_PUSH(num_sources);
+ image_cleanup(op);
+ return (code < 0 ? code : o_pop_estack);
+ }
+ if (++px == num_sources)
+ px = 0;
+ }
+}
+/* Clean up after enumerating an image */
+private int
+image_cleanup(os_ptr op)
+{
+ gs_image_enum *penum;
+ const ref *pb;
+
+ /* Free any row buffers, in LIFO order as usual. */
+ for (pb = esp + 2; !r_has_type(pb, t_integer); pb += 2)
+ if (r_has_type(pb, t_string))
+ gs_free_string(imemory, pb->value.bytes, r_size(pb),
+ "image_cleanup");
+ penum = r_ptr(pb + 2, gs_image_enum);
+ gs_image_cleanup(penum);
+ ifree_object(penum, "image_cleanup");
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zimage_op_defs[] =
+{
+ {"5image", zimage},
+ {"5imagemask", zimagemask},
+ /* Internal operators */
+ {"1%image_proc_continue", image_proc_continue},
+ {"0%image_file_continue", image_file_continue},
+ op_def_end(0)
+};
diff --git a/pstoraster/zimage2.c b/pstoraster/zimage2.c
new file mode 100644
index 000000000..ca30f01cf
--- /dev/null
+++ b/pstoraster/zimage2.c
@@ -0,0 +1,158 @@
+/* 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$ */
+/* image operator extensions for Level 2 PostScript */
+#include "math_.h"
+#include "memory_.h"
+#include "ghost.h"
+#include "oper.h"
+#include "gscolor.h"
+#include "gscspace.h"
+#include "gscolor2.h"
+#include "gsmatrix.h"
+#include "gsimage.h"
+#include "gxfixed.h"
+#include "idict.h"
+#include "idparam.h"
+#include "iimage.h"
+#include "iimage2.h"
+#include "ilevel.h"
+#include "igstate.h" /* for igs */
+
+/* Extract and check the parameters for a gs_data_image_t. */
+int
+data_image_params(const ref * op, gs_data_image_t * pim, image_params * pip,
+ bool require_DataSource, int num_components, int max_bits_per_component)
+{
+ int code;
+ int decode_size;
+ ref *pds;
+
+ check_type(*op, t_dictionary);
+ check_dict_read(*op);
+ if ((code = dict_int_param(op, "Width", 0, max_int_in_fixed / 2,
+ -1, &pim->Width)) < 0 ||
+ (code = dict_int_param(op, "Height", 0, max_int_in_fixed / 2,
+ -1, &pim->Height)) < 0 ||
+ (code = dict_matrix_param(op, "ImageMatrix",
+ &pim->ImageMatrix)) < 0 ||
+ (code = dict_bool_param(op, "MultipleDataSources", false,
+ &pip->MultipleDataSources)) < 0 ||
+ (code = dict_int_param(op, "BitsPerComponent", 1,
+ max_bits_per_component, -1,
+ &pim->BitsPerComponent)) < 0 ||
+ (code = decode_size = dict_float_array_param(op, "Decode",
+ num_components * 2,
+ &pim->Decode[0], NULL)) < 0 ||
+ (code = dict_bool_param(op, "Interpolate", false,
+ &pim->Interpolate)) < 0
+ )
+ return code;
+ if (decode_size != num_components * 2)
+ return_error(e_rangecheck);
+ pip->pDecode = &pim->Decode[0];
+ /* Extract and check the data sources. */
+ if ((code = dict_find_string(op, "DataSource", &pds)) <= 0) {
+ if (require_DataSource)
+ return (code < 0 ? code : gs_note_error(e_rangecheck));
+ return 1; /* no data source */
+ }
+ if (pip->MultipleDataSources) {
+ check_type_only(*pds, t_array);
+ if (r_size(pds) != num_components)
+ return_error(e_rangecheck);
+ memcpy(&pip->DataSource[0], pds->value.refs,
+ sizeof(ref) * num_components);
+ } else
+ pip->DataSource[0] = *pds;
+ return 0;
+}
+
+/* Extract and check the parameters for a gs_pixel_image_t. */
+int
+pixel_image_params(const ref * op, gs_pixel_image_t * pim, image_params * pip,
+ int max_bits_per_component)
+{
+ int num_components =
+ gs_color_space_num_components(gs_currentcolorspace(igs));
+ int code;
+
+ if (num_components < 1)
+ return_error(e_rangecheck); /* Pattern space not allowed */
+ pim->ColorSpace = gs_currentcolorspace(igs);
+ code = data_image_params(op, (gs_data_image_t *) pim, pip, true,
+ num_components, max_bits_per_component);
+ if (code < 0)
+ return code;
+ pim->format =
+ (pip->MultipleDataSources ? gs_image_format_component_planar :
+ gs_image_format_chunky);
+ return dict_bool_param(op, "CombineWithColor", false,
+ &pim->CombineWithColor);
+}
+
+/* <dict> .image1 - */
+private int
+zimage1(register os_ptr op)
+{
+ gs_image_t image;
+ image_params ip;
+ int code;
+
+ gs_image_t_init(&image, gs_currentcolorspace(igs));
+ code = pixel_image_params(op, (gs_pixel_image_t *) & image, &ip, 12);
+ if (code < 0)
+ return code;
+ return zimage_setup((gs_pixel_image_t *) & image, &ip.DataSource[0],
+ image.CombineWithColor, 1);
+}
+
+/* <dict> .imagemask1 - */
+private int
+zimagemask1(register os_ptr op)
+{
+ gs_image_t image;
+ image_params ip;
+ int code;
+
+ gs_image_t_init_mask(&image, false);
+ code = data_image_params(op, (gs_data_image_t *) & image, &ip, true, 1, 1);
+ if (code < 0)
+ return code;
+ if (ip.MultipleDataSources)
+ return_error(e_rangecheck);
+ return zimage_setup((gs_pixel_image_t *) & image, &ip.DataSource[0],
+ true, 1);
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zimage2_l2_op_defs[] =
+{
+ op_def_begin_level2(),
+ {"1.image1", zimage1},
+ {"1.imagemask1", zimagemask1},
+ op_def_end(0)
+};
diff --git a/pstoraster/zimage3.c b/pstoraster/zimage3.c
new file mode 100644
index 000000000..41cb29170
--- /dev/null
+++ b/pstoraster/zimage3.c
@@ -0,0 +1,139 @@
+/* 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$ */
+/* LanguageLevel 3 ImageTypes (3 & 4 - masked images) */
+#include "memory_.h"
+#include "ghost.h"
+#include "oper.h"
+#include "gscspace.h" /* for gscolor2.h */
+#include "gscolor2.h"
+#include "gsiparm3.h"
+#include "gsiparm4.h"
+#include "gxiparam.h" /* for image enumerator */
+#include "idict.h"
+#include "idparam.h"
+#include "igstate.h"
+#include "iimage.h"
+#include "iimage2.h"
+
+/* <dict> .image3 - */
+private int
+zimage3(register os_ptr op)
+{
+ gs_image3_t image;
+ int interleave_type;
+ ref *pDataDict;
+ ref *pMaskDict;
+ image_params ip_data, ip_mask;
+ int ignored;
+ int code, mcode;
+
+ check_type(*op, t_dictionary);
+ check_dict_read(*op);
+ if ((code = dict_int_param(op, "InterleaveType", 1, 3, -1,
+ &interleave_type)) < 0
+ )
+ return code;
+ gs_image3_t_init(&image, NULL, interleave_type);
+ if (dict_find_string(op, "DataDict", &pDataDict) <= 0 ||
+ dict_find_string(op, "MaskDict", &pMaskDict) <= 0
+ )
+ return_error(e_rangecheck);
+ if ((code = pixel_image_params(pDataDict, (gs_pixel_image_t *)&image,
+ &ip_data, 12)) < 0 ||
+ (mcode = code = data_image_params(pMaskDict, &image.MaskDict, &ip_mask, false, 1, 12)) < 0 ||
+ (code = dict_int_param(pDataDict, "ImageType", 1, 1, 0, &ignored)) < 0 ||
+ (code = dict_int_param(pMaskDict, "ImageType", 1, 1, 0, &ignored)) < 0
+ )
+ return code;
+ /*
+ * MaskDict must have a DataSource iff InterleaveType == 3.
+ */
+ if ((ip_data.MultipleDataSources && interleave_type != 3) ||
+ ip_mask.MultipleDataSources ||
+ mcode != (image.InterleaveType != 3)
+ )
+ return_error(e_rangecheck);
+ if (!mcode) {
+ /* Insert the mask DataSource before the data DataSources. */
+ memmove(&ip_data.DataSource[1], &ip_data.DataSource[0],
+ (countof(ip_data.DataSource) - 1) *
+ sizeof(ip_data.DataSource[0]));
+ ip_data.DataSource[0] = ip_mask.DataSource[0];
+ }
+ return zimage_setup((gs_pixel_image_t *)&image,
+ &ip_data.DataSource[0],
+ image.CombineWithColor, 1);
+}
+
+/* <dict> .image4 - */
+private int
+zimage4(register os_ptr op)
+{
+ gs_image4_t image;
+ image_params ip;
+ int num_components =
+ gs_color_space_num_components(gs_currentcolorspace(igs));
+ int colors[countof(image.MaskColor)];
+ int code;
+ int i;
+
+ gs_image4_t_init(&image, NULL);
+ code = pixel_image_params(op, (gs_pixel_image_t *)&image, &ip, 12);
+ if (code < 0)
+ return code;
+ code = dict_int_array_param(op, "MaskColor", num_components * 2,
+ colors);
+ /* Clamp the color values to the unsigned range. */
+ if (code == num_components) {
+ image.MaskColor_is_range = false;
+ for (i = 0; i < code; ++i)
+ image.MaskColor[i] = (colors[i] < 0 ? ~(uint)0 : colors[i]);
+ }
+ else if (code == num_components * 2) {
+ image.MaskColor_is_range = true;
+ for (i = 0; i < code; i += 2) {
+ if (colors[i+1] < 0) /* no match possible */
+ image.MaskColor[i] = 1, image.MaskColor[i+1] = 0;
+ else {
+ image.MaskColor[i+1] = colors[i+1];
+ image.MaskColor[i] = max(colors[i], 0);
+ }
+ }
+ } else
+ return_error(code < 0 ? code : gs_note_error(e_rangecheck));
+ return zimage_setup((gs_pixel_image_t *)&image, &ip.DataSource[0],
+ image.CombineWithColor, 1);
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zimage3_op_defs[] =
+{
+ op_def_begin_ll3(),
+ {"1.image3", zimage3},
+ {"1.image4", zimage4},
+ op_def_end(0)
+};
diff --git a/pstoraster/ziodev.c b/pstoraster/ziodev.c
new file mode 100644
index 000000000..b506d44e1
--- /dev/null
+++ b/pstoraster/ziodev.c
@@ -0,0 +1,475 @@
+/* Copyright (C) 1993, 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$ */
+/* Standard IODevice implementation */
+#include "memory_.h"
+#include "stdio_.h"
+#include "string_.h"
+#include "ghost.h"
+#include "gp.h"
+#include "gpcheck.h"
+#include "gsstruct.h" /* for registering root */
+#include "oper.h"
+#include "stream.h"
+#include "ialloc.h"
+#include "iscan.h"
+#include "ivmspace.h"
+#include "gxiodev.h" /* must come after stream.h */
+ /* and before files.h */
+#include "files.h"
+#include "scanchar.h" /* for char_EOL */
+#include "store.h"
+
+/* Complete the definition of the %os% device. */
+/* The open_file routine is exported for pipes and for %null. */
+int
+iodev_os_open_file(gx_io_device * iodev, const char *fname, uint len,
+ const char *file_access, stream ** ps, gs_memory_t * mem)
+{
+ return file_open_stream(fname, len, file_access,
+ file_default_buffer_size, ps,
+ iodev->procs.fopen);
+}
+
+/* Define the special devices. */
+#define iodev_special(dname, init, open) {\
+ dname, "Special",\
+ { init, open, iodev_no_open_file, iodev_no_fopen, iodev_no_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\
+ }\
+}
+
+/* Export the stdio refs for switching contexts. */
+ref ref_stdio[3];
+
+#define STDIN_BUF_SIZE 128
+/*#define ref_stdin ref_stdio[0] *//* in files.h */
+bool gs_stdin_is_interactive; /* exported for command line only */
+private iodev_proc_init(stdin_init);
+private iodev_proc_open_device(stdin_open);
+const gx_io_device gs_iodev_stdin =
+ iodev_special("%stdin%", stdin_init, stdin_open);
+
+#define STDOUT_BUF_SIZE 128
+/*#define ref_stdout ref_stdio[1] *//* in files.h */
+private iodev_proc_init(stdout_init);
+private iodev_proc_open_device(stdout_open);
+const gx_io_device gs_iodev_stdout =
+ iodev_special("%stdout%", stdout_init, stdout_open);
+
+#define STDERR_BUF_SIZE 128
+/*#define ref_stderr ref_stdio[2] *//* in files.h */
+private iodev_proc_init(stderr_init);
+private iodev_proc_open_device(stderr_open);
+const gx_io_device gs_iodev_stderr =
+ iodev_special("%stderr%", stderr_init, stderr_open);
+
+#define LINEEDIT_BUF_SIZE 20 /* initial size, not fixed size */
+private iodev_proc_open_device(lineedit_open);
+const gx_io_device gs_iodev_lineedit =
+ iodev_special("%lineedit%", iodev_no_init, lineedit_open);
+
+#define STATEMENTEDIT_BUF_SIZE 50 /* initial size, not fixed size */
+private iodev_proc_open_device(statementedit_open);
+const gx_io_device gs_iodev_statementedit =
+ iodev_special("%statementedit%", iodev_no_init, statementedit_open);
+
+/* ------ Operators ------ */
+
+/* <int> .getiodevice <string> */
+private int
+zgetiodevice(register os_ptr op)
+{
+ gx_io_device *iodev;
+ const byte *dname;
+
+ check_type(*op, t_integer);
+ if (op->value.intval != (int)op->value.intval)
+ return_error(e_rangecheck);
+ iodev = gs_getiodevice((int)(op->value.intval));
+ if (iodev == 0) /* index out of range */
+ return_error(e_rangecheck);
+ dname = (const byte *)iodev->dname;
+ make_const_string(op, a_readonly | avm_foreign,
+ strlen((const char *)dname), dname);
+ return 0;
+}
+
+/* ------- %stdin, %stdout, and %stderr ------ */
+
+/*
+ * According to Adobe, it is legal to close the %std... files and then
+ * re-open them later. However, the re-opened file object is not 'eq' to
+ * the original file object (in our implementation, it has a different
+ * read_id or write_id).
+ */
+
+private int
+ s_stdin_read_process(P4(stream_state *, stream_cursor_read *,
+ stream_cursor_write *, bool));
+
+private int
+stdin_init(gx_io_device * iodev, gs_memory_t * mem)
+{
+ static void *const pstdin = &ref_stdin;
+
+ make_file(&ref_stdin, a_readonly | avm_system, 1, invalid_file_entry);
+ gs_stdin_is_interactive = true;
+ gs_register_ref_root(mem, NULL, (void **)&pstdin, "ref_stdin");
+ return 0;
+}
+
+/* Read from stdin into the buffer. */
+/* If interactive, only read one character. */
+private int
+s_stdin_read_process(stream_state * st, stream_cursor_read * ignore_pr,
+ stream_cursor_write * pw, bool last)
+{
+ FILE *file = ((stream *) st)->file; /* hack for file streams */
+ int wcount = (int)(pw->limit - pw->ptr);
+ int count;
+
+ if (wcount > 0) {
+ if (gs_stdin_is_interactive)
+ wcount = 1;
+ count = fread(pw->ptr + 1, 1, wcount, file);
+ if (count < 0)
+ count = 0;
+ pw->ptr += count;
+ } else
+ count = 0; /* return 1 if no error/EOF */
+ process_interrupts();
+ return (ferror(file) ? ERRC : feof(file) ? EOFC : count == wcount ? 1 : 0);
+}
+
+int
+iodev_stdin_open(gx_io_device * iodev, const char *access, stream ** ps,
+ gs_memory_t * mem)
+{
+ stream *s;
+
+ if (!streq1(access, 'r'))
+ return_error(e_invalidfileaccess);
+ if (file_is_invalid(s, &ref_stdin)) {
+ /****** stdin SHOULD NOT LINE-BUFFER ******/
+ gs_memory_t *mem = imemory_system;
+ byte *buf;
+
+ s = file_alloc_stream(mem, "stdin_open(stream)");
+ /* We want stdin to read only one character at a time, */
+ /* but it must have a substantial buffer, in case it is used */
+ /* by a stream that requires more than one input byte */
+ /* to make progress. */
+ buf = gs_alloc_bytes(mem, STDIN_BUF_SIZE,
+ "stdin_open(buffer)");
+ if (s == 0 || buf == 0)
+ return_error(e_VMerror);
+ sread_file(s, gs_stdin, buf, STDIN_BUF_SIZE);
+ s->procs.process = s_stdin_read_process;
+ s->save_close = s_std_null;
+ s->procs.close = file_close_file;
+ make_file(&ref_stdin, a_readonly | avm_system,
+ s->read_id, s);
+ *ps = s;
+ return 1;
+ }
+ *ps = s;
+ return 0;
+}
+private int
+stdin_open(gx_io_device * iodev, const char *access, stream ** ps,
+ gs_memory_t * mem)
+{
+ int code = iodev_stdin_open(iodev, access, ps, mem);
+
+ return min(code, 0);
+}
+/* This is the public routine for getting the stdin stream. */
+int
+zget_stdin(stream ** ps)
+{
+ stream *s;
+ gx_io_device *iodev;
+
+ if (file_is_valid(s, &ref_stdin)) {
+ *ps = s;
+ return 0;
+ }
+ iodev = gs_findiodevice((const byte *)"%stdin", 6);
+ return (*iodev->procs.open_device)(iodev, "r", ps, imemory_system);
+}
+
+private int
+stdout_init(gx_io_device * iodev, gs_memory_t * mem)
+{
+ static void *const pstdout = &ref_stdout;
+
+ make_file(&ref_stdout, a_all | avm_system, 1, invalid_file_entry);
+ gs_register_ref_root(mem, NULL, (void **)&pstdout, "ref_stdout");
+ return 0;
+}
+
+int
+iodev_stdout_open(gx_io_device * iodev, const char *access, stream ** ps,
+ gs_memory_t * mem)
+{
+ stream *s;
+
+ if (!streq1(access, 'w'))
+ return_error(e_invalidfileaccess);
+ if (file_is_invalid(s, &ref_stdout)) {
+ gs_memory_t *mem = imemory_system;
+ byte *buf;
+
+ s = file_alloc_stream(mem, "stdout_open(stream)");
+ buf = gs_alloc_bytes(mem, STDOUT_BUF_SIZE,
+ "stdout_open(buffer)");
+ if (s == 0 || buf == 0)
+ return_error(e_VMerror);
+ swrite_file(s, gs_stdout, buf, STDOUT_BUF_SIZE);
+ s->save_close = s->procs.flush;
+ s->procs.close = file_close_file;
+ make_file(&ref_stdout, a_write | avm_system, s->write_id, s);
+ *ps = s;
+ return 1;
+ }
+ *ps = s;
+ return 0;
+}
+private int
+stdout_open(gx_io_device * iodev, const char *access, stream ** ps,
+ gs_memory_t * mem)
+{
+ int code = iodev_stdout_open(iodev, access, ps, mem);
+
+ return min(code, 0);
+}
+/* This is the public routine for getting the stdout stream. */
+int
+zget_stdout(stream ** ps)
+{
+ stream *s;
+ gx_io_device *iodev;
+
+ if (file_is_valid(s, &ref_stdout)) {
+ *ps = s;
+ return 0;
+ }
+ iodev = gs_findiodevice((const byte *)"%stdout", 7);
+ return (*iodev->procs.open_device)(iodev, "w", ps, imemory_system);
+}
+
+private int
+stderr_init(gx_io_device * iodev, gs_memory_t * mem)
+{
+ static void *const pstderr = &ref_stderr;
+
+ make_file(&ref_stderr, a_all | avm_system, 1, invalid_file_entry);
+ gs_register_ref_root(mem, NULL, (void **)&pstderr, "ref_stderr");
+ return 0;
+}
+
+int
+iodev_stderr_open(gx_io_device * iodev, const char *access, stream ** ps,
+ gs_memory_t * mem)
+{
+ stream *s;
+
+ if (!streq1(access, 'w'))
+ return_error(e_invalidfileaccess);
+ if (file_is_invalid(s, &ref_stderr)) {
+ gs_memory_t *mem = imemory_system;
+ byte *buf;
+
+ s = file_alloc_stream(mem, "stderr_open(stream)");
+ buf = gs_alloc_bytes(mem, STDERR_BUF_SIZE,
+ "stderr_open(buffer)");
+ if (s == 0 || buf == 0)
+ return_error(e_VMerror);
+ swrite_file(s, gs_stderr, buf, STDERR_BUF_SIZE);
+ s->save_close = s->procs.flush;
+ s->procs.close = file_close_file;
+ make_file(&ref_stderr, a_write | avm_system, s->write_id, s);
+ *ps = s;
+ return 1;
+ }
+ *ps = s;
+ return 0;
+}
+private int
+stderr_open(gx_io_device * iodev, const char *access, stream ** ps,
+ gs_memory_t * mem)
+{
+ int code = iodev_stderr_open(iodev, access, ps, mem);
+
+ return min(code, 0);
+}
+/* This is the public routine for getting the stderr stream. */
+int
+zget_stderr(stream ** ps)
+{
+ stream *s;
+ gx_io_device *iodev;
+
+ if (file_is_valid(s, &ref_stderr)) {
+ *ps = s;
+ return 0;
+ }
+ iodev = gs_findiodevice((const byte *)"%stderr", 7);
+ return (*iodev->procs.open_device)(iodev, "w", ps, imemory_system);
+}
+
+/* ------ %lineedit and %statementedit ------ */
+
+private int
+line_collect(gx_io_device * iodev, const char *access, stream ** ps,
+ gs_memory_t * mem, uint initial_buf_size, bool statement)
+{
+ uint count = 0;
+ bool in_eol = false;
+ int code;
+ gx_io_device *indev = gs_findiodevice((const byte *)"%stdin", 6);
+ stream *s;
+ stream *ins;
+ byte *buf;
+ uint buf_size = initial_buf_size;
+
+ if (strcmp(access, "r"))
+ return_error(e_invalidfileaccess);
+ s = file_alloc_stream(mem, "line_collect(stream)");
+ if (s == 0)
+ return_error(e_VMerror);
+ code = (indev->procs.open_device)(indev, access, &ins, mem);
+ if (code < 0)
+ return code;
+ buf = gs_alloc_string(mem, buf_size, "line_collect(buffer)");
+ if (buf == 0)
+ return_error(e_VMerror);
+ rd: /* We have to stop 1 character short of the buffer size, */
+ /* because %statementedit must append an EOL. */
+ code = zreadline_from(ins, buf, buf_size - 1, &count, &in_eol);
+ switch (code) {
+ case EOFC:
+ code = gs_note_error(e_undefinedfilename);
+ /* falls through */
+ case 0:
+ break;
+ default:
+ code = gs_note_error(e_ioerror);
+ break;
+ case 1: /* filled buffer */
+ {
+ uint nsize;
+ byte *nbuf;
+
+#if arch_ints_are_short
+ if (nsize == max_uint) {
+ code = gs_note_error(e_limitcheck);
+ break;
+ } else if (nsize >= max_uint / 2)
+ nsize = max_uint;
+ else
+#endif
+ nsize = buf_size * 2;
+ nbuf = gs_resize_string(mem, buf, buf_size, nsize,
+ "line_collect(grow buffer)");
+ if (nbuf == 0) {
+ code = gs_note_error(e_VMerror);
+ break;
+ }
+ buf = nbuf;
+ buf_size = nsize;
+ goto rd;
+ }
+ }
+ if (code != 0) {
+ gs_free_string(mem, buf, buf_size, "line_collect(buffer)");
+ return code;
+ }
+ if (statement) {
+ /* If we don't have a complete token, keep going. */
+ stream st;
+ stream *ts = &st;
+ scanner_state state;
+ ref ignore_value;
+ uint depth = ref_stack_count(&o_stack);
+ int code;
+
+ /* Add a terminating EOL. */
+ buf[count++] = char_EOL;
+ sread_string(ts, buf, count);
+sc:
+ scanner_state_init_check(&state, false, true);
+ code = scan_token(ts, &ignore_value, &state);
+ ref_stack_pop_to(&o_stack, depth);
+ switch (code) {
+ case 0: /* read a token */
+ case scan_BOS:
+ goto sc; /* keep going until we run out of data */
+ case scan_Refill:
+ goto rd;
+ case scan_EOF:
+ break;
+ default: /* error */
+ gs_free_string(mem, buf, buf_size, "line_collect(buffer)");
+ return code;
+ }
+ }
+ buf = gs_resize_string(mem, buf, buf_size, count,
+ "line_collect(resize buffer)");
+ if (buf == 0)
+ return_error(e_VMerror);
+ sread_string(s, buf, count);
+ s->save_close = s->procs.close;
+ s->procs.close = file_close_disable;
+ *ps = s;
+ return 0;
+}
+
+private int
+lineedit_open(gx_io_device * iodev, const char *access, stream ** ps,
+ gs_memory_t * mem)
+{
+ return line_collect(iodev, access, ps, mem,
+ LINEEDIT_BUF_SIZE, false);
+}
+
+private int
+statementedit_open(gx_io_device * iodev, const char *access, stream ** ps,
+ gs_memory_t * mem)
+{
+ return line_collect(iodev, access, ps, mem,
+ STATEMENTEDIT_BUF_SIZE, true);
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def ziodev_op_defs[] =
+{
+ {"1.getiodevice", zgetiodevice},
+ op_def_end(0)
+};
diff --git a/pstoraster/ziodev2.c b/pstoraster/ziodev2.c
new file mode 100644
index 000000000..d7fb6fe7e
--- /dev/null
+++ b/pstoraster/ziodev2.c
@@ -0,0 +1,148 @@
+/* Copyright (C) 1993, 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$ */
+/* (Level 2) IODevice operators */
+#include "string_.h"
+#include "ghost.h"
+#include "gp.h"
+#include "oper.h"
+#include "stream.h"
+#include "gxiodev.h"
+#include "dstack.h" /* for systemdict */
+#include "files.h" /* for file_open_stream */
+#include "iparam.h"
+#include "iutil2.h"
+#include "store.h"
+
+/* ------ %null% ------ */
+
+/* This represents the null output file. */
+private iodev_proc_open_device(null_open);
+const gx_io_device gs_iodev_null = {
+ "%null%", "FileSystem",
+ {
+ iodev_no_init, null_open, iodev_no_open_file,
+ iodev_os_fopen, iodev_os_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
+ }
+};
+
+private int
+null_open(gx_io_device * iodev, const char *access, stream ** ps,
+ gs_memory_t * mem)
+{
+ if (!streq1(access, 'w'))
+ return_error(e_invalidfileaccess);
+ return file_open_stream(gp_null_file_name,
+ strlen(gp_null_file_name),
+ access, 256 /* arbitrary */ , ps,
+ iodev->procs.fopen);
+}
+
+/* ------ %ram% ------ */
+
+/* This is an IODevice with no interesting parameters for the moment. */
+const gx_io_device gs_iodev_ram = {
+ "%ram%", "Special",
+ {
+ iodev_no_init, iodev_no_open_device, iodev_no_open_file,
+ iodev_no_fopen, iodev_no_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
+ }
+};
+
+/* ------ Operators ------ */
+
+/* <iodevice> .getdevparams <mark> <name> <value> ... */
+private int
+zgetdevparams(os_ptr op)
+{
+ gx_io_device *iodev;
+ stack_param_list list;
+ gs_param_list *const plist = (gs_param_list *) & list;
+ int code;
+ ref *pmark;
+
+ check_read_type(*op, t_string);
+ iodev = gs_findiodevice(op->value.bytes, r_size(op));
+ if (iodev == 0)
+ return_error(e_undefinedfilename);
+ stack_param_list_write(&list, &o_stack, NULL);
+ if ((code = gs_getdevparams(iodev, plist)) < 0) {
+ ref_stack_pop(&o_stack, list.count * 2);
+ return code;
+ }
+ pmark = ref_stack_index(&o_stack, list.count * 2);
+ make_mark(pmark);
+ return 0;
+}
+
+/* <mark> <name> <value> ... <iodevice> .putdevparams */
+private int
+zputdevparams(os_ptr op)
+{
+ gx_io_device *iodev;
+ stack_param_list list;
+ gs_param_list *const plist = (gs_param_list *) & list;
+ int code;
+ password system_params_password;
+
+ check_read_type(*op, t_string);
+ iodev = gs_findiodevice(op->value.bytes, r_size(op));
+ if (iodev == 0)
+ return_error(e_undefinedfilename);
+ code = stack_param_list_read(&list, &o_stack, 1, NULL, false);
+ if (code < 0)
+ return code;
+ code = dict_read_password(&system_params_password, systemdict,
+ "SystemParamsPassword");
+ if (code < 0)
+ return code;
+ code = param_check_password(plist, &system_params_password);
+ if (code != 0) {
+ iparam_list_release(&list);
+ return_error(code < 0 ? code : e_invalidaccess);
+ }
+ code = gs_putdevparams(iodev, plist);
+ iparam_list_release(&list);
+ if (code < 0)
+ return code;
+ ref_stack_pop(&o_stack, list.count * 2 + 2);
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def ziodev2_l2_op_defs[] =
+{
+ op_def_begin_level2(),
+ {"1.getdevparams", zgetdevparams},
+ {"2.putdevparams", zputdevparams},
+ op_def_end(0)
+};
diff --git a/pstoraster/zmath.c b/pstoraster/zmath.c
new file mode 100644
index 000000000..56165e051
--- /dev/null
+++ b/pstoraster/zmath.c
@@ -0,0 +1,277 @@
+/* Copyright (C) 1989, 1992, 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$ */
+/* Mathematical operators */
+#include "math_.h"
+#include "ghost.h"
+#include "gxfarith.h"
+#include "oper.h"
+#include "store.h"
+
+/*
+ * Define the current state of random number generator. We have to
+ * implement this ourselves because the Unix rand doesn't provide anything
+ * equivalent to rrand. Note that the value always lies in the range
+ * [0..0x7ffffffe], even if longs are longer than 32 bits.
+ *
+ * The state must be public so that context switching can save and
+ * restore it. (Even though the Red Book doesn't mention this,
+ * we verified with Adobe that this is the case.)
+ */
+long zrand_state;
+
+/* Initialize the random number generator. */
+void
+zrand_state_init(long *pstate)
+{
+ *pstate = 1;
+}
+
+/****** NOTE: none of these operators currently ******/
+/****** check for floating over- or underflow. ******/
+
+/* <num> sqrt <real> */
+private int
+zsqrt(register os_ptr op)
+{
+ double num;
+ int code = real_param(op, &num);
+
+ if (code < 0)
+ return code;
+ if (num < 0.0)
+ return_error(e_rangecheck);
+ make_real(op, sqrt(num));
+ return 0;
+}
+
+/* <num> arccos <real> */
+private int
+zarccos(register os_ptr op)
+{
+ double num, result;
+ int code = real_param(op, &num);
+
+ if (code < 0)
+ return code;
+ result = acos(num) * radians_to_degrees;
+ make_real(op, result);
+ return 0;
+}
+
+/* <num> arcsin <real> */
+private int
+zarcsin(register os_ptr op)
+{
+ double num, result;
+ int code = real_param(op, &num);
+
+ if (code < 0)
+ return code;
+ result = asin(num) * radians_to_degrees;
+ make_real(op, result);
+ return 0;
+}
+
+/* <num> <denom> atan <real> */
+private int
+zatan(register os_ptr op)
+{
+ double args[2];
+ double result;
+ int code = num_params(op, 2, args);
+
+ if (code < 0)
+ return code;
+ if (args[0] == 0) { /* on X-axis, special case */
+ if (args[1] == 0)
+ return_error(e_undefinedresult);
+ result = (args[1] < 0 ? 180 : 0);
+ } else {
+ result = atan2(args[0], args[1]) * radians_to_degrees;
+ if (result < 0)
+ result += 360;
+ }
+ make_real(op - 1, result);
+ pop(1);
+ return 0;
+}
+
+/* <num> cos <real> */
+private int
+zcos(register os_ptr op)
+{
+ double angle;
+ int code = real_param(op, &angle);
+
+ if (code < 0)
+ return code;
+ make_real(op, gs_cos_degrees(angle));
+ return 0;
+}
+
+/* <num> sin <real> */
+private int
+zsin(register os_ptr op)
+{
+ double angle;
+ int code = real_param(op, &angle);
+
+ if (code < 0)
+ return code;
+ make_real(op, gs_sin_degrees(angle));
+ return 0;
+}
+
+/* <base> <exponent> exp <real> */
+private int
+zexp(register os_ptr op)
+{
+ double args[2];
+ double result;
+ double ipart;
+ int code = num_params(op, 2, args);
+
+ if (code < 0)
+ return code;
+ if (args[0] == 0.0 && args[1] == 0.0)
+ return_error(e_undefinedresult);
+ if (args[0] < 0.0 && modf(args[1], &ipart) != 0.0)
+ return_error(e_undefinedresult);
+ result = pow(args[0], args[1]);
+ make_real(op - 1, result);
+ pop(1);
+ return 0;
+}
+
+/* <posnum> ln <real> */
+private int
+zln(register os_ptr op)
+{
+ double num;
+ int code = real_param(op, &num);
+
+ if (code < 0)
+ return code;
+ if (num <= 0.0)
+ return_error(e_rangecheck);
+ make_real(op, log(num));
+ return 0;
+}
+
+/* <posnum> log <real> */
+private int
+zlog(register os_ptr op)
+{
+ double num;
+ int code = real_param(op, &num);
+
+ if (code < 0)
+ return code;
+ if (num <= 0.0)
+ return_error(e_rangecheck);
+ make_real(op, log10(num));
+ return 0;
+}
+
+/* - rand <int> */
+private int
+zrand(register os_ptr op)
+{ /*
+ * We use an algorithm from CACM 31 no. 10, pp. 1192-1201,
+ * October 1988. According to a posting by Ed Taft on
+ * comp.lang.postscript, Level 2 (Adobe) PostScript interpreters
+ * use this algorithm too:
+ * x[n+1] = (16807 * x[n]) mod (2^31 - 1)
+ */
+#define A 16807
+#define M 0x7fffffff
+#define Q 127773 /* M / A */
+#define R 2836 /* M % A */
+ zrand_state = A * (zrand_state % Q) - R * (zrand_state / Q);
+ /* Note that zrand_state cannot be 0 here. */
+ if (zrand_state <= 0)
+ zrand_state += M;
+#undef A
+#undef M
+#undef Q
+#undef R
+ push(1);
+ make_int(op, zrand_state);
+ return 0;
+}
+
+/* <int> srand - */
+private int
+zsrand(register os_ptr op)
+{
+ long state;
+
+ check_type(*op, t_integer);
+ state = op->value.intval;
+#if arch_sizeof_long > 4
+ /* Trim the state back to 32 bits. */
+ state = (int)state;
+#endif
+ /*
+ * The following somewhat bizarre adjustments are according to
+ * public information from Adobe describing their implementation.
+ */
+ if (state < 1)
+ state = -(state % 0x7ffffffe) + 1;
+ else if (state > 0x7ffffffe)
+ state = 0x7ffffffe;
+ zrand_state = state;
+ pop(1);
+ return 0;
+}
+
+/* - rrand <int> */
+private int
+zrrand(register os_ptr op)
+{
+ push(1);
+ make_int(op, zrand_state);
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zmath_op_defs[] =
+{
+ {"1arccos", zarccos}, /* extension */
+ {"1arcsin", zarcsin}, /* extension */
+ {"2atan", zatan},
+ {"1cos", zcos},
+ {"2exp", zexp},
+ {"1ln", zln},
+ {"1log", zlog},
+ {"0rand", zrand},
+ {"0rrand", zrrand},
+ {"1sin", zsin},
+ {"1sqrt", zsqrt},
+ {"1srand", zsrand},
+ op_def_end(0)
+};
diff --git a/pstoraster/zmatrix.c b/pstoraster/zmatrix.c
new file mode 100644
index 000000000..abf6e6515
--- /dev/null
+++ b/pstoraster/zmatrix.c
@@ -0,0 +1,358 @@
+/* Copyright (C) 1989, 1995, 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$ */
+/* Matrix operators */
+#include "ghost.h"
+#include "oper.h"
+#include "igstate.h"
+#include "gsmatrix.h"
+#include "gscoord.h"
+#include "store.h"
+
+/* Forward references */
+private int common_transform(P3(os_ptr,
+ int (*)(P4(gs_state *, floatp, floatp, gs_point *)),
+ int (*)(P4(floatp, floatp, const gs_matrix *, gs_point *))));
+
+/* - initmatrix - */
+private int
+zinitmatrix(os_ptr op)
+{
+ return gs_initmatrix(igs);
+}
+
+/* <matrix> defaultmatrix <matrix> */
+private int
+zdefaultmatrix(register os_ptr op)
+{
+ gs_matrix mat;
+
+ gs_defaultmatrix(igs, &mat);
+ return write_matrix(op, &mat);
+}
+
+/* - .currentmatrix <xx> <xy> <yx> <yy> <tx> <ty> */
+private int
+zcurrentmatrix(register os_ptr op)
+{
+ gs_matrix mat;
+ int code = gs_currentmatrix(igs, &mat);
+
+ if (code < 0)
+ return code;
+ push(6);
+ code = make_floats(op - 5, &mat.xx, 6);
+ if (code < 0)
+ pop(6);
+ return code;
+}
+
+/* <xx> <xy> <yx> <yy> <tx> <ty> .setmatrix - */
+private int
+zsetmatrix(register os_ptr op)
+{
+ gs_matrix mat;
+ int code = float_params(op, 6, &mat.xx);
+
+ if (code < 0)
+ return code;
+ if ((code = gs_setmatrix(igs, &mat)) < 0)
+ return code;
+ pop(6);
+ return 0;
+}
+
+/* <matrix|null> .setdefaultmatrix - */
+private int
+zsetdefaultmatrix(register os_ptr op)
+{
+ int code;
+
+ if (r_has_type(op, t_null))
+ code = gs_setdefaultmatrix(igs, NULL);
+ else {
+ gs_matrix mat;
+
+ code = read_matrix(op, &mat);
+ if (code < 0)
+ return code;
+ code = gs_setdefaultmatrix(igs, &mat);
+ }
+ if (code < 0)
+ return code;
+ pop(1);
+ return 0;
+}
+
+/* <tx> <ty> translate - */
+/* <tx> <ty> <matrix> translate <matrix> */
+private int
+ztranslate(register os_ptr op)
+{
+ int code;
+ double trans[2];
+
+ if ((code = num_params(op, 2, trans)) >= 0) {
+ code = gs_translate(igs, trans[0], trans[1]);
+ if (code < 0)
+ return code;
+ } else { /* matrix operand */
+ gs_matrix mat;
+
+ /* The num_params failure might be a stack underflow. */
+ check_op(2);
+ if ((code = num_params(op - 1, 2, trans)) < 0 ||
+ (code = gs_make_translation(trans[0], trans[1], &mat)) < 0 ||
+ (code = write_matrix(op, &mat)) < 0
+ ) { /* Might be a stack underflow. */
+ check_op(3);
+ return code;
+ }
+ op[-2] = *op;
+ }
+ pop(2);
+ return code;
+}
+
+/* <sx> <sy> scale - */
+/* <sx> <sy> <matrix> scale <matrix> */
+private int
+zscale(register os_ptr op)
+{
+ int code;
+ double scale[2];
+
+ if ((code = num_params(op, 2, scale)) >= 0) {
+ code = gs_scale(igs, scale[0], scale[1]);
+ if (code < 0)
+ return code;
+ } else { /* matrix operand */
+ gs_matrix mat;
+
+ /* The num_params failure might be a stack underflow. */
+ check_op(2);
+ if ((code = num_params(op - 1, 2, scale)) < 0 ||
+ (code = gs_make_scaling(scale[0], scale[1], &mat)) < 0 ||
+ (code = write_matrix(op, &mat)) < 0
+ ) { /* Might be a stack underflow. */
+ check_op(3);
+ return code;
+ }
+ op[-2] = *op;
+ }
+ pop(2);
+ return code;
+}
+
+/* <angle> rotate - */
+/* <angle> <matrix> rotate <matrix> */
+private int
+zrotate(register os_ptr op)
+{
+ int code;
+ double ang;
+
+ if ((code = real_param(op, &ang)) >= 0) {
+ code = gs_rotate(igs, ang);
+ if (code < 0)
+ return code;
+ } else { /* matrix operand */
+ gs_matrix mat;
+
+ /* The num_params failure might be a stack underflow. */
+ check_op(1);
+ if ((code = num_params(op - 1, 1, &ang)) < 0 ||
+ (code = gs_make_rotation(ang, &mat)) < 0 ||
+ (code = write_matrix(op, &mat)) < 0
+ ) { /* Might be a stack underflow. */
+ check_op(2);
+ return code;
+ }
+ op[-1] = *op;
+ }
+ pop(1);
+ return code;
+}
+
+/* <matrix> concat - */
+private int
+zconcat(register os_ptr op)
+{
+ gs_matrix mat;
+ int code = read_matrix(op, &mat);
+
+ if (code < 0)
+ return code;
+ code = gs_concat(igs, &mat);
+ if (code < 0)
+ return code;
+ pop(1);
+ return 0;
+}
+
+/* <matrix1> <matrix2> <matrix> concatmatrix <matrix> */
+private int
+zconcatmatrix(register os_ptr op)
+{
+ gs_matrix m1, m2, mp;
+ int code;
+
+ if ((code = read_matrix(op - 2, &m1)) < 0 ||
+ (code = read_matrix(op - 1, &m2)) < 0 ||
+ (code = gs_matrix_multiply(&m1, &m2, &mp)) < 0 ||
+ (code = write_matrix(op, &mp)) < 0
+ )
+ return code;
+ op[-2] = *op;
+ pop(2);
+ return code;
+}
+
+/* <x> <y> transform <xt> <yt> */
+/* <x> <y> <matrix> transform <xt> <yt> */
+private int
+ztransform(register os_ptr op)
+{
+ return common_transform(op, gs_transform, gs_point_transform);
+}
+
+/* <dx> <dy> dtransform <dxt> <dyt> */
+/* <dx> <dy> <matrix> dtransform <dxt> <dyt> */
+private int
+zdtransform(register os_ptr op)
+{
+ return common_transform(op, gs_dtransform, gs_distance_transform);
+}
+
+/* <xt> <yt> itransform <x> <y> */
+/* <xt> <yt> <matrix> itransform <x> <y> */
+private int
+zitransform(register os_ptr op)
+{
+ return common_transform(op, gs_itransform, gs_point_transform_inverse);
+}
+
+/* <dxt> <dyt> idtransform <dx> <dy> */
+/* <dxt> <dyt> <matrix> idtransform <dx> <dy> */
+private int
+zidtransform(register os_ptr op)
+{
+ return common_transform(op, gs_idtransform, gs_distance_transform_inverse);
+}
+
+/* Common logic for [i][d]transform */
+private int
+common_transform(register os_ptr op,
+ int (*ptproc)(P4(gs_state *, floatp, floatp, gs_point *)),
+ int (*matproc)(P4(floatp, floatp, const gs_matrix *, gs_point *)))
+{
+ double opxy[2];
+ gs_point pt;
+ int code;
+
+ /* Optimize for the non-matrix case */
+ switch (r_type(op)) {
+ case t_real:
+ opxy[1] = op->value.realval;
+ break;
+ case t_integer:
+ opxy[1] = op->value.intval;
+ break;
+ case t_array: /* might be a matrix */
+ case t_shortarray:
+ case t_mixedarray: {
+ gs_matrix mat;
+ gs_matrix *pmat = &mat;
+
+ if ((code = read_matrix(op, pmat)) < 0 ||
+ (code = num_params(op - 1, 2, opxy)) < 0 ||
+ (code = (*matproc) (opxy[0], opxy[1], pmat, &pt)) < 0
+ ) { /* Might be a stack underflow. */
+ check_op(3);
+ return code;
+ }
+ op--;
+ pop(1);
+ goto out;
+ }
+ default:
+ return_op_typecheck(op);
+ }
+ switch (r_type(op - 1)) {
+ case t_real:
+ opxy[0] = (op - 1)->value.realval;
+ break;
+ case t_integer:
+ opxy[0] = (op - 1)->value.intval;
+ break;
+ default:
+ return_op_typecheck(op - 1);
+ }
+ if ((code = (*ptproc) (igs, opxy[0], opxy[1], &pt)) < 0)
+ return code;
+out:
+ make_real(op - 1, pt.x);
+ make_real(op, pt.y);
+ return 0;
+}
+
+/* <matrix> <inv_matrix> invertmatrix <inv_matrix> */
+private int
+zinvertmatrix(register os_ptr op)
+{
+ gs_matrix m;
+ int code;
+
+ if ((code = read_matrix(op - 1, &m)) < 0 ||
+ (code = gs_matrix_invert(&m, &m)) < 0 ||
+ (code = write_matrix(op, &m)) < 0
+ )
+ return code;
+ op[-1] = *op;
+ pop(1);
+ return code;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zmatrix_op_defs[] =
+{
+ {"1concat", zconcat},
+ {"2dtransform", zdtransform},
+ {"3concatmatrix", zconcatmatrix},
+ {"0.currentmatrix", zcurrentmatrix},
+ {"1defaultmatrix", zdefaultmatrix},
+ {"2idtransform", zidtransform},
+ {"0initmatrix", zinitmatrix},
+ {"2invertmatrix", zinvertmatrix},
+ {"2itransform", zitransform},
+ {"1rotate", zrotate},
+ {"2scale", zscale},
+ {"6.setmatrix", zsetmatrix},
+ {"1.setdefaultmatrix", zsetdefaultmatrix},
+ {"2transform", ztransform},
+ {"2translate", ztranslate},
+ op_def_end(0)
+};
diff --git a/pstoraster/zmedia2.c b/pstoraster/zmedia2.c
new file mode 100644
index 000000000..12a36c4e9
--- /dev/null
+++ b/pstoraster/zmedia2.c
@@ -0,0 +1,472 @@
+/*
+ Copyright 2000 by Easy Software Products.
+ Copyright 1993, 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$ */
+/* Media matching for setpagedevice */
+#include "math_.h"
+#include "memory_.h"
+#include "ghost.h"
+#include "gsmatrix.h"
+#include "oper.h"
+#include "idict.h"
+#include "idparam.h"
+#include "iname.h"
+#include "store.h"
+
+/* <pagedict> <attrdict> <policydict> <keys> .matchmedia <key> true */
+/* <pagedict> <attrdict> <policydict> <keys> .matchmedia false */
+/* <pagedict> null <policydict> <keys> .matchmedia null true */
+private int zmatch_page_size(P8(const ref * pvreq, const ref * pvmed,
+ int policy, int orient, bool roll,
+ float *best_mismatch, gs_matrix * pmat,
+ gs_point * pmsize));
+typedef struct match_record_s {
+ ref best_key, match_key;
+ uint priority, no_match_priority;
+} match_record_t;
+private void
+reset_match(match_record_t *match)
+{
+ make_null(&match->best_key);
+ make_null(&match->match_key);
+ match->priority = match->no_match_priority;
+}
+private int
+zmatchmedia(register os_ptr op)
+{
+ os_ptr preq = op - 3;
+ os_ptr pattr = op - 2;
+ os_ptr ppol = op - 1;
+ os_ptr pkeys = op; /* *const */
+ int policy_default;
+ float best_mismatch = (float)max_long; /* adhoc */
+ float mbest = best_mismatch;
+ match_record_t match;
+ ref no_priority;
+ ref *ppriority;
+ int mepos, orient;
+ bool roll;
+ int code;
+ int ai;
+ struct mkd_ {
+ ref key, dict;
+ } aelt;
+ if (r_has_type(pattr, t_null)) {
+ check_op(4);
+ make_null(op - 3);
+ make_true(op - 2);
+ pop(2);
+ return 0;
+ }
+ check_type(*preq, t_dictionary);
+ check_dict_read(*preq);
+ check_type(*pattr, t_dictionary);
+ check_dict_read(*pattr);
+ check_type(*ppol, t_dictionary);
+ check_dict_read(*ppol);
+ check_array(*pkeys);
+ check_read(*pkeys);
+#if 0 /* MRS - this code breaks the MediaPosition option */
+ switch (code = dict_int_null_param(preq, "MediaPosition", 0, 0x7fff,
+ 0, &mepos)) {
+ default:
+ return code;
+ case 2:
+ case 1:
+ mepos = -1;
+ case 0:;
+ }
+ switch (code = dict_int_null_param(preq, "Orientation", 0, 3,
+ 0, &orient)) {
+ default:
+ return code;
+ case 2:
+ case 1:
+ orient = -1;
+ case 0:;
+ }
+ code = dict_bool_param(preq, "RollFedMedia", false, &roll);
+ if (code < 0)
+ return code;
+#endif /* 0 */
+ code = dict_int_param(ppol, "PolicyNotFound", 0, 7, 0,
+ &policy_default);
+ if (code < 0)
+ return code;
+ if (dict_find_string(pattr, "Priority", &ppriority) > 0) {
+ check_array_only(*ppriority);
+ check_read(*ppriority);
+ } else {
+ make_empty_array(&no_priority, a_readonly);
+ ppriority = &no_priority;
+ }
+ match.no_match_priority = r_size(ppriority);
+ reset_match(&match);
+ for (ai = dict_first(pattr);
+ (ai = dict_next(pattr, ai, (ref * /*[2]*/)&aelt)) >= 0;
+ ) {
+ if (r_has_type(&aelt.dict, t_dictionary) &&
+ r_has_attr(dict_access_ref(&aelt.dict), a_read) &&
+ r_has_type(&aelt.key, t_integer) &&
+ (mepos < 0 || aelt.key.value.intval == mepos)
+ ) {
+ bool match_all;
+ uint ki, pi;
+
+ code = dict_bool_param(&aelt.dict, "MatchAll", false,
+ &match_all);
+ if (code < 0)
+ return code;
+ for (ki = 0; ki < r_size(pkeys); ki++) {
+ ref key;
+ ref kstr;
+ ref *prvalue;
+ ref *pmvalue;
+ ref *ppvalue;
+ int policy;
+
+ array_get(pkeys, ki, &key);
+ if (dict_find(&aelt.dict, &key, &pmvalue) <= 0)
+ continue;
+ if (dict_find(preq, &key, &prvalue) <= 0 ||
+ r_has_type(prvalue, t_null)
+ ) {
+ if (match_all)
+ goto no;
+ else
+ continue;
+ }
+ /* Look for the Policies entry for this key. */
+ if (dict_find(ppol, &key, &ppvalue) > 0) {
+ check_type_only(*ppvalue, t_integer);
+ policy = ppvalue->value.intval;
+ } else
+ policy = policy_default;
+ /*
+ * Match a requested attribute value with the attribute value in the
+ * description of a medium. For all attributes except PageSize,
+ * matching means equality. PageSize is special; see match_page_size
+ * below.
+ */
+ if (r_has_type(&key, t_name) &&
+ (name_string_ref(&key, &kstr),
+ r_size(&kstr) == 8 &&
+ !memcmp(kstr.value.bytes, "PageSize", 8))
+ ) {
+ gs_matrix ignore_mat;
+ gs_point ignore_msize;
+
+ if (zmatch_page_size(prvalue, pmvalue,
+ policy, orient, roll,
+ &best_mismatch,
+ &ignore_mat,
+ &ignore_msize)
+ <= 0)
+ goto no;
+ } else if (!obj_eq(prvalue, pmvalue))
+ goto no;
+ }
+ /* We have a match. If it is a better match */
+ /* than the current best one, it supersedes it */
+ /* regardless of priority. */
+ if (best_mismatch < mbest) {
+ mbest = best_mismatch;
+ reset_match(&match);
+ }
+ /* In case of a tie, see if the new match has */
+ /* priority. */
+ for (pi = match.priority; pi > 0;) {
+ ref pri;
+
+ pi--;
+ array_get(ppriority, pi, &pri);
+ if (obj_eq(&aelt.key, &pri)) { /* Yes, higher priority. */
+ match.best_key = aelt.key;
+ match.priority = pi;
+ break;
+ }
+ }
+ /* Save the match in case no match has priority. */
+ match.match_key = aelt.key;
+no:;
+ }
+ }
+ if (r_has_type(&match.match_key, t_null)) {
+ make_false(op - 3);
+ pop(3);
+ } else {
+ if (r_has_type(&match.best_key, t_null))
+ op[-3] = match.match_key;
+ else
+ op[-3] = match.best_key;
+ make_true(op - 2);
+ pop(2);
+ }
+ return 0;
+}
+
+/* [<req_x> <req_y>] [<med_x0> <med_y0> (<med_x1> <med_y1> | )]
+ * <policy> <orient|null> <roll> <matrix|null> .matchpagesize
+ * <matrix|null> <med_x> <med_y> true -or- false
+ */
+private int
+zmatchpagesize(register os_ptr op)
+{
+ gs_matrix mat;
+ float ignore_mismatch = (float)max_long;
+ gs_point media_size;
+ int orient;
+ bool roll;
+ int code;
+
+ check_type(op[-3], t_integer);
+ if (r_has_type(op - 2, t_null))
+ orient = -1;
+ else {
+ check_int_leu(op[-2], 3);
+ orient = (int)op[-2].value.intval;
+ }
+ check_type(op[-1], t_boolean);
+ roll = op[-1].value.boolval;
+ code = zmatch_page_size(op - 5, op - 4, (int)op[-3].value.intval,
+ orient, roll,
+ &ignore_mismatch, &mat, &media_size);
+ switch (code) {
+ default:
+ return code;
+ case 0:
+ make_false(op - 5);
+ pop(5);
+ break;
+ case 1:
+ code = write_matrix(op, &mat);
+ if (code < 0 && !r_has_type(op, t_null))
+ return code;
+ op[-5] = *op;
+ make_real(op - 4, media_size.x);
+ make_real(op - 3, media_size.y);
+ make_true(op - 2);
+ pop(2);
+ break;
+ }
+ return 0;
+}
+/* Match the PageSize. See below for details. */
+private bool match_page_size(P8(const gs_point * request,
+ const gs_rect * medium,
+ int policy, int orient, bool roll,
+ float *best_mismatch, gs_matrix * pmat,
+ gs_point * pmsize));
+private int
+zmatch_page_size(const ref * pvreq, const ref * pvmed,
+ int policy, int orient, bool roll,
+ float *best_mismatch, gs_matrix * pmat, gs_point * pmsize)
+{
+ uint nm;
+
+ check_array(*pvreq);
+ check_array(*pvmed);
+ if (!(r_size(pvreq) == 2 && ((nm = r_size(pvmed)) == 2 || nm == 4)))
+ return_error(e_rangecheck);
+ {
+ ref rv[6];
+ uint i;
+ double v[6];
+ int code;
+
+ array_get(pvreq, 0, &rv[0]);
+ array_get(pvreq, 1, &rv[1]);
+ for (i = 0; i < 4; ++i)
+ array_get(pvmed, i % nm, &rv[i + 2]);
+ if ((code = num_params(rv + 5, 6, v)) < 0)
+ return code;
+ {
+ gs_point request;
+ gs_rect medium;
+
+ request.x = v[0], request.y = v[1];
+ medium.p.x = v[2], medium.p.y = v[3],
+ medium.q.x = v[4], medium.q.y = v[5];
+ return match_page_size(&request, &medium, policy, orient,
+ roll, best_mismatch, pmat, pmsize);
+ }
+ }
+}
+/*
+ * Match a requested PageSize with the PageSize of a medium. The medium
+ * may specify either a single value [mx my] or a range
+ * [mxmin mymin mxmax mymax]; matching means equality or inclusion
+ * to within a tolerance of 5, possibly swapping the requested X and Y.
+ * Take the Policies value into account, keeping track of the discrepancy
+ * if needed. When a match is found, also return the matrix to be
+ * concatenated after setting up the default matrix, and the actual
+ * media size.
+ *
+ * NOTE: The algorithm here doesn't work properly for variable-size media
+ * when the match isn't exact. We'll fix it if we ever need to.
+ */
+private void make_adjustment_matrix(P5(const gs_point * request,
+ const gs_rect * medium,
+ gs_matrix * pmat,
+ bool scale, int rotate));
+private bool
+match_page_size(const gs_point * request, const gs_rect * medium, int policy,
+ int orient, bool roll, float *best_mismatch, gs_matrix * pmat,
+ gs_point * pmsize)
+{
+ double rx = request->x, ry = request->y;
+
+ if (policy == 7) {
+ /* (Adobe) hack: just impose requested values */
+ *best_mismatch = 0;
+ gs_make_identity(pmat);
+ *pmsize = *request;
+ return true;
+ }
+ if (rx - medium->p.x >= -5 && rx - medium->q.x <= 5 &&
+ ry - medium->p.y >= -5 && ry - medium->q.y <= 5 &&
+ (orient < 0 || !(orient & 1))
+ ) {
+ *best_mismatch = 0;
+ make_adjustment_matrix(request, medium, pmat, false,
+ (orient >= 0 ? orient : 0));
+ } else if (rx - medium->p.y >= -5 && rx - medium->q.y <= 5 &&
+ ry - medium->p.x >= -5 && ry - medium->q.x <= 5 &&
+ (orient < 0 || (orient & 1))
+ ) {
+ *best_mismatch = 0;
+ make_adjustment_matrix(request, medium, pmat, false,
+ (orient >= 0 ? orient :
+ rx < ry ? -1 : 1));
+ } else {
+ int rotate =
+ (orient >= 0 ? orient :
+ rx < ry ?
+ (medium->q.x > medium->q.y ? -1 : 0) :
+ (medium->q.x < medium->q.y ? 1 : 0));
+ bool larger =
+ (rotate ? medium->q.y >= rx && medium->q.x >= ry :
+ medium->q.x >= rx && medium->q.y >= ry);
+ bool adjust = false;
+ float mismatch = medium->q.x * medium->q.y - rx * ry;
+
+ switch (policy) {
+ default: /* exact match only */
+ return false;
+ case 3: /* nearest match, adjust */
+ adjust = true;
+ case 5: /* nearest match, don't adjust */
+ if (fabs(mismatch) >= fabs(*best_mismatch))
+ return false;
+ break;
+ case 4: /* next larger match, adjust */
+ adjust = true;
+ case 6: /* next larger match, don't adjust */
+ if (!larger || mismatch >= *best_mismatch)
+ return false;
+ break;
+ }
+ if (adjust)
+ make_adjustment_matrix(request, medium, pmat, !larger, rotate);
+ else {
+ gs_rect req_rect;
+
+ req_rect.p = *request;
+ req_rect.q = *request;
+ make_adjustment_matrix(request, &req_rect, pmat, false, rotate);
+ }
+ *best_mismatch = mismatch;
+ }
+ if (pmat->xx == 0) { /* Swap request X and Y. */
+ double temp = rx;
+
+ rx = ry, ry = temp;
+ }
+#define ADJUST_INTO(req, mmin, mmax)\
+ (req < mmin ? mmin : req > mmax ? mmax : req)
+ pmsize->x = ADJUST_INTO(rx, medium->p.x, medium->q.x);
+ pmsize->y = ADJUST_INTO(ry, medium->p.y, medium->q.y);
+#undef ADJUST_INTO
+ return true;
+}
+/*
+ * Compute the adjustment matrix for scaling and/or rotating the page
+ * to match the medium. If the medium is completely flexible in a given
+ * dimension (e.g., roll media in one dimension, or displays in both),
+ * we must adjust its size in that dimension to match the request.
+ * We recognize this by an unreasonably small medium->p.{x,y}.
+ */
+#define MIN_MEDIA_SIZE 9
+private void
+make_adjustment_matrix(const gs_point * request, const gs_rect * medium,
+ gs_matrix * pmat, bool scale, int rotate)
+{
+ double rx = request->x, ry = request->y;
+ double mx = medium->q.x, my = medium->q.y;
+
+ /* Rotate the request if necessary. */
+ if (rotate & 1) {
+ double temp = rx;
+
+ rx = ry, ry = temp;
+ }
+ /* Adjust the medium size if flexible. */
+ if (medium->p.x < MIN_MEDIA_SIZE && mx > rx)
+ mx = rx;
+ if (medium->p.y < MIN_MEDIA_SIZE && my > ry)
+ my = ry;
+
+ /* Translate to align the centers. */
+ gs_make_translation(mx / 2, my / 2, pmat);
+
+ /* Rotate if needed. */
+ if (rotate)
+ gs_matrix_rotate(pmat, 90.0 * rotate, pmat);
+
+ /* Scale if needed. */
+ if (scale) {
+ double xfactor = mx / rx;
+ double yfactor = my / ry;
+ double factor = min(xfactor, yfactor);
+
+ if (factor < 1)
+ gs_matrix_scale(pmat, factor, factor, pmat);
+ }
+ /* Now translate the origin back, */
+ /* using the original, unswapped request. */
+ gs_matrix_translate(pmat, -request->x / 2, -request->y / 2, pmat);
+}
+#undef MIN_MEDIA_SIZE
+
+/* ------ Initialization procedure ------ */
+
+const op_def zmedia2_l2_op_defs[] =
+{
+ op_def_begin_level2(),
+ {"4.matchmedia", zmatchmedia},
+ {"6.matchpagesize", zmatchpagesize},
+ op_def_end(0)
+};
diff --git a/pstoraster/zmisc.c b/pstoraster/zmisc.c
new file mode 100644
index 000000000..2cc93d00f
--- /dev/null
+++ b/pstoraster/zmisc.c
@@ -0,0 +1,345 @@
+/* Copyright (C) 1989, 1995, 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$ */
+/* Miscellaneous operators */
+#include "errno_.h"
+#include "memory_.h"
+#include "string_.h"
+#include "ghost.h"
+#include "gscdefs.h" /* for gs_serialnumber */
+#include "gp.h"
+#include "oper.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "dstack.h" /* for name lookup in bind */
+#include "iname.h"
+#include "ipacked.h"
+#include "ivmspace.h"
+#include "store.h"
+
+/* <proc> bind <proc> */
+private int
+zbind(os_ptr op)
+{
+ uint depth = 1;
+ ref defn;
+ register os_ptr bsp;
+
+ switch (r_type(op)) {
+ case t_array:
+ case t_mixedarray:
+ case t_shortarray:
+ defn = *op;
+ break;
+ case t_oparray:
+ defn = *op->value.const_refs;
+ break;
+ default:
+ return_op_typecheck(op);
+ }
+ push(1);
+ *op = defn;
+ bsp = op;
+ /*
+ * We must not make the top-level procedure read-only,
+ * but we must bind it even if it is read-only already.
+ *
+ * Here are the invariants for the following loop:
+ * `depth' elements have been pushed on the ostack;
+ * For i < depth, p = ref_stack_index(&o_stack, i):
+ * *p is an array (or packedarray) ref. */
+#define r_is_ex_oper(rp)\
+ ((r_btype(rp) == t_operator || r_type(rp) == t_oparray) &&\
+ r_has_attr(rp, a_executable))
+ while (depth) {
+ while (r_size(bsp)) {
+ ref *tp = bsp->value.refs;
+
+ r_dec_size(bsp, 1);
+ if (r_is_packed(tp)) {
+ /* Check for a packed executable name */
+ ushort elt = *PACKED(tp);
+
+ if (r_packed_is_exec_name(&elt)) {
+ ref nref;
+ ref *pvalue;
+
+ name_index_ref(packed_name_index(&elt),
+ &nref);
+ if ((pvalue = dict_find_name(&nref)) != 0 &&
+ r_is_ex_oper(pvalue)
+ )
+ /* Note: can't undo this by restore! */
+ *PACKED(tp) =
+ pt_tag(pt_executable_operator) +
+ op_index(pvalue);
+ }
+ bsp->value.refs = (ref *) ((ref_packed *) tp + 1);
+ } else
+ switch (bsp->value.refs++, r_type(tp)) {
+ case t_name: /* bind the name if an operator */
+ if (r_has_attr(tp, a_executable)) {
+ ref *pvalue;
+
+ if ((pvalue = dict_find_name(tp)) != 0 &&
+ r_is_ex_oper(pvalue)
+ )
+ ref_assign_old(bsp, tp, pvalue, "bind");
+ }
+ break;
+ case t_array: /* push into array if writable */
+ if (!r_has_attr(tp, a_write))
+ break;
+ case t_mixedarray:
+ case t_shortarray:
+ if (r_has_attr(tp, a_executable)) {
+ /* Make reference read-only */
+ r_clear_attrs(tp, a_write);
+ if (bsp >= ostop) {
+ /* Push a new stack block. */
+ ref temp;
+ int code;
+
+ temp = *tp;
+ osp = bsp;
+ code = ref_stack_push(&o_stack, 1);
+ if (code < 0) {
+ ref_stack_pop(&o_stack, depth);
+ return_error(code);
+ }
+ bsp = osp;
+ *bsp = temp;
+ } else
+ *++bsp = *tp;
+ depth++;
+ }
+ }
+ }
+ bsp--;
+ depth--;
+ if (bsp < osbot) { /* Pop back to the previous stack block. */
+ osp = bsp;
+ ref_stack_pop_block(&o_stack);
+ bsp = osp;
+ }
+ }
+ osp = bsp;
+ return 0;
+}
+
+/* - serialnumber <int> */
+private int
+zserialnumber(register os_ptr op)
+{
+ push(1);
+ make_int(op, gs_serialnumber);
+ return 0;
+}
+
+/* - realtime <int> */
+private int
+zrealtime(register os_ptr op)
+{
+ long secs_ns[2];
+
+ gp_get_realtime(secs_ns);
+ push(1);
+ make_int(op, secs_ns[0] * 1000 + secs_ns[1] / 1000000);
+ return 0;
+}
+
+/* - usertime <int> */
+private int
+zusertime(register os_ptr op)
+{
+ long secs_ns[2];
+
+ gp_get_usertime(secs_ns);
+ push(1);
+ make_int(op, secs_ns[0] * 1000 + secs_ns[1] / 1000000);
+ return 0;
+}
+
+/* ---------------- Non-standard operators ---------------- */
+
+/* <string> getenv <value_string> true */
+/* <string> getenv false */
+private int
+zgetenv(register os_ptr op)
+{
+ char *str;
+ byte *value;
+ int code;
+ int len = 0;
+
+ check_read_type(*op, t_string);
+ str = ref_to_string(op, imemory, "getenv key");
+ if (str == 0)
+ return_error(e_VMerror);
+ if (gp_getenv(str, (char *)0, &len) > 0) { /* key missing */
+ ifree_string((byte *) str, r_size(op) + 1, "getenv key");
+ make_false(op);
+ return 0;
+ }
+ value = ialloc_string(len, "getenv value");
+ if (value == 0) {
+ ifree_string((byte *) str, r_size(op) + 1, "getenv key");
+ return_error(e_VMerror);
+ }
+ code = gp_getenv(str, (char *)value, &len); /* can't fail */
+ ifree_string((byte *) str, r_size(op) + 1, "getenv key");
+ /* Delete the stupid C string terminator. */
+ value = iresize_string(value, len, len - 1,
+ "getenv value"); /* can't fail */
+ push(1);
+ make_string(op - 1, a_all | icurrent_space, len - 1, value);
+ make_true(op);
+ return 0;
+}
+
+/* <name> <proc> .makeoperator <oper> */
+private int
+zmakeoperator(register os_ptr op)
+{
+ op_array_table *opt;
+ uint count;
+ ref *tab;
+
+ check_type(op[-1], t_name);
+ check_proc(*op);
+ switch (r_space(op)) {
+ case avm_global:
+ opt = &op_array_table_global;
+ break;
+ case avm_local:
+ opt = &op_array_table_local;
+ break;
+ default:
+ return_error(e_invalidaccess);
+ }
+ count = opt->count;
+ tab = opt->table.value.refs;
+ /*
+ * restore doesn't reset op_array_table.count, but it does
+ * remove entries from op_array_table.table. Since we fill
+ * the table in order, we can detect that a restore has occurred
+ * by checking whether what should be the most recent entry
+ * is occupied. If not, we scan backwards over the vacated entries
+ * to find the true end of the table.
+ */
+ while (count > 0 && r_has_type(&tab[count - 1], t_null))
+ --count;
+ if (count == r_size(&opt->table))
+ return_error(e_limitcheck);
+ ref_assign_old(&opt->table, &tab[count], op, "makeoperator");
+ opt->nx_table[count] = name_index(op - 1);
+ op_index_ref(opt->base_index + count, op - 1);
+ opt->count = count + 1;
+ pop(1);
+ return 0;
+}
+
+/* - .oserrno <int> */
+private int
+zoserrno(register os_ptr op)
+{
+ push(1);
+ make_int(op, errno);
+ return 0;
+}
+
+/* <int> .setoserrno - */
+private int
+zsetoserrno(register os_ptr op)
+{
+ check_type(*op, t_integer);
+ errno = op->value.intval;
+ pop(1);
+ return 0;
+}
+
+/* <int> .oserrorstring <string> true */
+/* <int> .oserrorstring false */
+private int
+zoserrorstring(register os_ptr op)
+{
+ const char *str;
+ int code;
+ uint len;
+ byte ch;
+
+ check_type(*op, t_integer);
+ str = gp_strerror((int)op->value.intval);
+ if (str == 0 || (len = strlen(str)) == 0) {
+ make_false(op);
+ return 0;
+ }
+ check_ostack(1);
+ code = string_to_ref(str, op, iimemory, ".oserrorstring");
+ if (code < 0)
+ return code;
+ /* Strip trailing end-of-line characters. */
+ while ((len = r_size(op)) != 0 &&
+ ((ch = op->value.bytes[--len]) == '\r' || ch == '\n')
+ )
+ r_dec_size(op, 1);
+ push(1);
+ make_true(op);
+ return 0;
+}
+
+/* <string> <bool> .setdebug - */
+private int
+zsetdebug(register os_ptr op)
+{
+ check_read_type(op[-1], t_string);
+ check_type(*op, t_boolean);
+ {
+ int i;
+
+ for (i = 0; i < r_size(op - 1); i++)
+ gs_debug[op[-1].value.bytes[i] & 127] =
+ op->value.boolval;
+ }
+ pop(2);
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zmisc_op_defs[] =
+{
+ {"1bind", zbind},
+ {"1getenv", zgetenv},
+ {"2.makeoperator", zmakeoperator},
+ {"0.oserrno", zoserrno},
+ {"1.oserrorstring", zoserrorstring},
+ {"0realtime", zrealtime},
+ {"1serialnumber", zserialnumber},
+ {"2.setdebug", zsetdebug},
+ {"1.setoserrno", zsetoserrno},
+ {"0usertime", zusertime},
+ op_def_end(0)
+};
diff --git a/pstoraster/zmisc1.c b/pstoraster/zmisc1.c
new file mode 100644
index 000000000..aff17b5ff
--- /dev/null
+++ b/pstoraster/zmisc1.c
@@ -0,0 +1,157 @@
+/* Copyright (C) 1994, 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$ */
+/* Miscellaneous Type 1 font operators */
+#include "memory_.h"
+#include "ghost.h"
+#include "oper.h"
+#include "gscrypt1.h"
+#include "stream.h" /* for getting state of PFBD stream */
+#include "strimpl.h"
+#include "sfilter.h"
+#include "idict.h"
+#include "idparam.h"
+#include "ifilter.h"
+
+/* <state> <from_string> <to_string> .type1encrypt <new_state> <substring> */
+/* <state> <from_string> <to_string> .type1decrypt <new_state> <substring> */
+private int type1crypt(P2(os_ptr,
+ int (*)(P4(byte *, const byte *, uint, ushort *))));
+private int
+ztype1encrypt(os_ptr op)
+{
+ return type1crypt(op, gs_type1_encrypt);
+}
+private int
+ztype1decrypt(os_ptr op)
+{
+ return type1crypt(op, gs_type1_decrypt);
+}
+private int
+type1crypt(register os_ptr op,
+ int (*proc)(P4(byte *, const byte *, uint, ushort *)))
+{
+ crypt_state state;
+ uint ssize;
+
+ check_type(op[-2], t_integer);
+ state = op[-2].value.intval;
+ if (op[-2].value.intval != state)
+ return_error(e_rangecheck); /* state value was truncated */
+ check_read_type(op[-1], t_string);
+ check_write_type(*op, t_string);
+ ssize = r_size(op - 1);
+ if (r_size(op) < ssize)
+ return_error(e_rangecheck);
+ discard((*proc)(op->value.bytes, op[-1].value.const_bytes, ssize,
+ &state)); /* can't fail */
+ op[-2].value.intval = state;
+ op[-1] = *op;
+ r_set_size(op - 1, ssize);
+ pop(1);
+ return 0;
+}
+
+/* Get the seed parameter for eexecEncode/Decode. */
+/* Return npop if OK. */
+private int
+eexec_param(os_ptr op, ushort * pcstate)
+{
+ int npop = 1;
+
+ if (r_has_type(op, t_dictionary))
+ ++npop, --op;
+ check_type(*op, t_integer);
+ *pcstate = op->value.intval;
+ if (op->value.intval != *pcstate)
+ return_error(e_rangecheck); /* state value was truncated */
+ return npop;
+}
+
+/* <target> <seed> eexecEncode/filter <file> */
+/* <target> <seed> <dict_ignored> eexecEncode/filter <file> */
+private int
+zexE(register os_ptr op)
+{
+ stream_exE_state state;
+ int code = eexec_param(op, &state.cstate);
+
+ if (code < 0)
+ return code;
+ return filter_write(op, code, &s_exE_template, (stream_state *)&state, 0);
+}
+
+/* <source> <seed> eexecDecode/filter <file> */
+/* <source> <dict> eexecDecode/filter <file> */
+private int
+zexD(register os_ptr op)
+{
+ stream_exD_state state;
+ int code;
+
+ (*s_exD_template.set_defaults)((stream_state *)&state);
+ if (r_has_type(op, t_dictionary)) {
+ uint cstate;
+
+ check_dict_read(*op);
+ if ((code = dict_uint_param(op, "seed", 0, 0xffff, 0x10000,
+ &cstate)) < 0 ||
+ (code = dict_int_param(op, "lenIV", 0, max_int, 4,
+ &state.lenIV)) < 0
+ )
+ return code;
+ state.cstate = cstate;
+ code = 1;
+ } else {
+ code = eexec_param(op, &state.cstate);
+ }
+ if (code < 0)
+ return code;
+ /*
+ * If we're reading a .PFB file, let the filter know about it,
+ * so it can read recklessly to the end of the binary section.
+ */
+ state.pfb_state = 0;
+ if (r_has_type(op - 1, t_file)) {
+ stream *s = (op - 1)->value.pfile;
+
+ if (s->state != 0 && s->state->template == &s_PFBD_template)
+ state.pfb_state = (stream_PFBD_state *) s->state;
+ }
+ state.binary = -1;
+ return filter_read(op, code, &s_exD_template, (stream_state *)&state, 0);
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zmisc1_op_defs[] =
+{
+ {"3.type1encrypt", ztype1encrypt},
+ {"3.type1decrypt", ztype1decrypt},
+ op_def_begin_filter(),
+ {"2eexecEncode", zexE},
+ {"2eexecDecode", zexD},
+ op_def_end(0)
+};
diff --git a/pstoraster/zmisc2.c b/pstoraster/zmisc2.c
new file mode 100644
index 000000000..63b367100
--- /dev/null
+++ b/pstoraster/zmisc2.c
@@ -0,0 +1,322 @@
+/* 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$ */
+/* Miscellaneous Level 2 operators */
+#include "memory_.h"
+#include "string_.h"
+#include "ghost.h"
+#include "oper.h"
+#include "estack.h"
+#include "idict.h"
+#include "idparam.h"
+#include "iparam.h"
+#include "dstack.h"
+#include "ilevel.h"
+#include "iname.h"
+#include "iutil2.h"
+#include "ivmspace.h"
+#include "store.h"
+
+/* Forward references */
+private int set_language_level(P1(int));
+
+/* ------ Language level operators ------ */
+
+/* - .languagelevel <int> */
+private int
+zlanguagelevel(register os_ptr op)
+{
+ push(1);
+ ref_assign(op, &ref_language_level);
+ return 0;
+}
+
+/* <int> .setlanguagelevel - */
+private int
+zsetlanguagelevel(register os_ptr op)
+{
+ int code = 0;
+
+ check_type(*op, t_integer);
+ if (op->value.intval != ref_language_level.value.intval) {
+ code = set_language_level((int)op->value.intval);
+ if (code < 0)
+ return code;
+ }
+ pop(1);
+ ref_assign_old(NULL, &ref_language_level, op, "setlanguagelevel");
+ return code;
+}
+
+/* ------ The 'where' hack ------ */
+
+private int
+z2where(register os_ptr op)
+{ /*
+ * Aldus Freehand versions 2.x check for the presence of the
+ * setcolor operator, and if it is missing, substitute a procedure.
+ * Unfortunately, the procedure takes different parameters from
+ * the operator. As a result, files produced by this application
+ * cause an error if the setcolor operator is actually defined
+ * and 'bind' is ever used. Aldus fixed this bug in Freehand 3.0,
+ * but there are a lot of files created by the older versions
+ * still floating around. Therefore, at Adobe's suggestion,
+ * we implement the following dreadful hack in the 'where' operator:
+ * If the key is /setcolor, and
+ * there is a dictionary named FreeHandDict, and
+ * currentdict is that dictionary,
+ * then "where" consults only that dictionary and not any other
+ * dictionaries on the dictionary stack.
+ */
+ ref rkns, rfh;
+ const ref *pdref = dsp;
+ ref *pvalue;
+
+ if (!r_has_type(op, t_name) ||
+ (name_string_ref(op, &rkns), r_size(&rkns)) != 8 ||
+ memcmp(rkns.value.bytes, "setcolor", 8) != 0 ||
+ name_ref((const byte *)"FreeHandDict", 12, &rfh, -1) < 0 ||
+ (pvalue = dict_find_name(&rfh)) == 0 ||
+ !obj_eq(pvalue, pdref)
+ )
+ return zwhere(op);
+ check_dict_read(*pdref);
+ if (dict_find(pdref, op, &pvalue) > 0) {
+ ref_assign(op, pdref);
+ push(1);
+ make_true(op);
+ } else
+ make_false(op);
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+/* The level setting ops are recognized even in Level 1 mode. */
+const op_def zmisc2_op_defs[] =
+{
+ {"0.languagelevel", zlanguagelevel},
+ {"1.setlanguagelevel", zsetlanguagelevel},
+ /* The rest of the operators are defined only in Level 2. */
+ op_def_begin_level2(),
+ /* Note that this overrides the definition in zdict.c. */
+ {"1where", z2where},
+ op_def_end(0)
+};
+
+/* ------ Internal procedures ------ */
+
+/*
+ * Adjust the interpreter for a change in language level.
+ * This is used for the .setlanguagelevel operator,
+ * and (perhaps someday) after a restore.
+ */
+private int swap_level_dict(P1(const char *dict_name));
+private int swap_entry(P3(ref elt[2], ref * pdict, ref * pdict2));
+private int
+set_language_level(int new_level)
+{
+ int old_level = ref_language_level.value.intval;
+ ref *pgdict = /* globaldict, if present */
+ ref_stack_index(&d_stack, ref_stack_count(&d_stack) - 2);
+ ref *level2dict;
+ int code = 0;
+
+ if (new_level < 1 ||
+ new_level >
+ (dict_find_string(systemdict, "ll3dict", &level2dict) > 0 ? 3 : 2)
+ )
+ return_error(e_rangecheck);
+ if (dict_find_string(systemdict, "level2dict", &level2dict) <= 0)
+ return_error(e_undefined);
+ /*
+ * As noted in dstack.h, we allocate the extra d-stack entry for
+ * globaldict even in Level 1 mode; in Level 1 mode, this entry
+ * holds an extra copy of systemdict, and [count]dictstack omit the
+ * very bottommost entry.
+ */
+ while (new_level != old_level) {
+ switch (old_level) {
+ case 1: { /* 1 => 2 or 3 */
+ /* Put globaldict in the dictionary stack. */
+ ref *pdict;
+
+ /*
+ * This might be called so early in initialization that
+ * globaldict hasn't been defined yet. If so, just skip
+ * this step.
+ */
+ code = dict_find_string(level2dict, "globaldict", &pdict);
+ if (code > 0) {
+ if (!r_has_type(pdict, t_dictionary))
+ return_error(e_typecheck);
+ *pgdict = *pdict;
+ }
+ /* Set other flags for Level 2 operation. */
+ dict_auto_expand = true;
+ }
+ code = swap_level_dict("level2dict");
+ if (code < 0)
+ return code;
+ ++old_level;
+ continue;
+ case 3: /* 3 => 1 or 2 */
+ code = swap_level_dict("ll3dict");
+ if (code < 0)
+ return code;
+ --old_level;
+ continue;
+ default: /* 2 => 1 or 3 */
+ break;
+ }
+ switch (new_level) {
+ case 1: { /* 2 => 1 */
+ /*
+ * Clear the cached definition pointers of all names defined
+ * in globaldict. This will slow down future lookups, but
+ * we don't care.
+ */
+ int index = dict_first(pgdict);
+ ref elt[2];
+
+ while ((index = dict_next(pgdict, index, &elt[0])) >= 0)
+ if (r_has_type(&elt[0], t_name))
+ name_invalidate_value_cache(&elt[0]);
+ /* Overwrite globaldict in the dictionary stack. */
+ *pgdict = *systemdict;
+ /* Set other flags for Level 1 operation. */
+ dict_auto_expand = false;
+ }
+ code = swap_level_dict("level2dict");
+ break;
+ case 3: /* 2 => 3 */
+ code = swap_level_dict("ll3dict");
+ break;
+ default: /* not possible */
+ return_error(e_Fatal);
+ }
+ break;
+ }
+ dict_set_top(); /* reload dict stack cache */
+ return code;
+}
+
+/*
+ * Swap the contents of a level dictionary (level2dict or ll3dict) and
+ * systemdict. If a value in the level dictionary is itself a dictionary,
+ * and it contains a key/value pair referring to itself, swap its contents
+ * with the contents of the same dictionary in systemdict. (This is a hack
+ * to swap the contents of statusdict.)
+ */
+private int
+swap_level_dict(const char *dict_name)
+{
+ ref *leveldict;
+ int index;
+ ref elt[2]; /* key, value */
+ ref *subdict;
+
+ if (dict_find_string(systemdict, dict_name, &leveldict) <= 0)
+ return_error(e_undefined);
+ index = dict_first(leveldict);
+ while ((index = dict_next(leveldict, index, &elt[0])) >= 0)
+ if (r_has_type(&elt[1], t_dictionary) &&
+ dict_find(&elt[1], &elt[0], &subdict) > 0 &&
+ obj_eq(&elt[1], subdict)
+ ) {
+ /* elt[1] is the 2nd-level sub-dictionary */
+ int isub = dict_first(&elt[1]);
+ ref subelt[2];
+ int found = dict_find(systemdict, &elt[0], &subdict);
+
+ if (found <= 0)
+ continue;
+ while ((isub = dict_next(&elt[1], isub, &subelt[0])) >= 0)
+ if (!obj_eq(&subelt[0], &elt[0])) {
+ /* don't swap dict itself */
+ int code = swap_entry(subelt, subdict, &elt[1]);
+
+ if (code < 0)
+ return code;
+ }
+ } else {
+ int code = swap_entry(elt, systemdict, leveldict);
+
+ if (code < 0)
+ return code;
+ }
+ return 0;
+}
+
+/*
+ * Swap an entry from a higher level dictionary into a base dictionary.
+ * elt[0] is the key, elt[1] is the current value in the Level 2 dictionary
+ * (*pdict2).
+ */
+private int
+swap_entry(ref elt[2], ref * pdict, ref * pdict2)
+{
+ ref *pvalue;
+ ref old_value; /* current value in *pdict */
+ int found = dict_find(pdict, &elt[0], &pvalue);
+
+ switch (found) {
+ default: /* <0, error */
+ return found;
+ case 0: /* missing */
+ make_null(&old_value);
+ break;
+ case 1: /* present */
+ old_value = *pvalue;
+ }
+ /*
+ * Temporarily flag the dictionaries as local, so that we don't
+ * get invalidaccess errors. (We know that they are both
+ * referenced from systemdict, so they are allowed to reference
+ * local objects even if they are global.)
+ */
+ {
+ uint space2 = r_space(pdict2);
+ int code;
+
+ r_set_space(pdict2, avm_local);
+ dict_put(pdict2, &elt[0], &old_value);
+ if (r_has_type(&elt[1], t_null)) {
+ code = dict_undef(pdict, &elt[0]);
+ if (code == e_undefined &&
+ r_has_type(&old_value, t_null)
+ )
+ code = 0;
+ } else {
+ uint space = r_space(pdict);
+
+ r_set_space(pdict, avm_local);
+ code = dict_put(pdict, &elt[0], &elt[1]);
+ r_set_space(pdict, space);
+ }
+ r_set_space(pdict2, space2);
+ return code;
+ }
+}
diff --git a/pstoraster/zmisc3.c b/pstoraster/zmisc3.c
new file mode 100644
index 000000000..0c27f3cf7
--- /dev/null
+++ b/pstoraster/zmisc3.c
@@ -0,0 +1,129 @@
+/* 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$ */
+/* Miscellaneous LanguageLevel 3 operators */
+#include "ghost.h"
+#include "gsclipsr.h"
+#include "oper.h"
+#include "igstate.h"
+#include "store.h"
+
+/* - clipsave - */
+private int
+zclipsave(os_ptr op)
+{
+ return gs_clipsave(igs);
+}
+
+/* - cliprestore - */
+private int
+zcliprestore(os_ptr op)
+{
+ return gs_cliprestore(igs);
+}
+
+/* <proc1> <proc2> .eqproc <bool> */
+/*
+ * Test whether two procedures are equal to depth 10.
+ * This is the equality test used by idiom recognition in 'bind'.
+ */
+#define MAX_DEPTH 10 /* depth is per Adobe specification */
+typedef struct ref2_s {
+ ref proc1, proc2;
+} ref2_t;
+private int
+zeqproc(register os_ptr op)
+{
+ ref2_t stack[MAX_DEPTH + 1];
+ ref2_t *top = stack;
+
+ make_array(&stack[0].proc1, 0, 1, op - 1);
+ make_array(&stack[0].proc2, 0, 1, op);
+ for (;;) {
+ long i;
+
+ if (r_size(&top->proc1) == 0) {
+ /* Finished these arrays, go up to next level. */
+ if (top == stack) {
+ /* We're done matching: it succeeded. */
+ make_true(op - 1);
+ pop(1);
+ return 0;
+ }
+ --top;
+ continue;
+ }
+ /* Look at the next elements of the arrays. */
+ i = r_size(&top->proc1) - 1;
+ array_get(&top->proc1, i, &top[1].proc1);
+ array_get(&top->proc2, i, &top[1].proc2);
+ r_dec_size(&top->proc1, 1);
+ ++top;
+ /*
+ * Amazingly enough, the objects' executable attributes are not
+ * required to match. This means { x load } will match { /x load },
+ * even though this is clearly wrong.
+ */
+#if 0
+ if (r_has_attr(&top->proc1, a_executable) !=
+ r_has_attr(&top->proc2, a_executable)
+ )
+ break;
+#endif
+ if (obj_eq(&top->proc1, &top->proc2)) {
+ /* Names don't match strings. */
+ if (r_type(&top->proc1) != r_type(&top->proc2) &&
+ (r_type(&top->proc1) == t_name ||
+ r_type(&top->proc2) == t_name)
+ )
+ break;
+ --top; /* no recursion */
+ continue;
+ }
+ if (r_is_array(&top->proc1) && r_is_array(&top->proc2) &&
+ r_size(&top->proc1) == r_size(&top->proc2) &&
+ top < stack + (MAX_DEPTH - 1)
+ ) {
+ /* Descend into the arrays. */
+ continue;
+ }
+ break;
+ }
+ /* An exit from the loop indicates that matching failed. */
+ make_false(op - 1);
+ pop(1);
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zmisc3_op_defs[] =
+{
+ op_def_begin_ll3(),
+ {"0cliprestore", zcliprestore},
+ {"0clipsave", zclipsave},
+ {"2.eqproc", zeqproc},
+ op_def_end(0)
+};
diff --git a/pstoraster/zpacked.c b/pstoraster/zpacked.c
new file mode 100644
index 000000000..7f3947068
--- /dev/null
+++ b/pstoraster/zpacked.c
@@ -0,0 +1,258 @@
+/* Copyright (C) 1990, 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$ */
+/* Packed array operators */
+#include "ghost.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "iname.h"
+#include "istack.h" /* for iparray.h */
+#include "ipacked.h"
+#include "iparray.h"
+#include "ivmspace.h"
+#include "oper.h"
+#include "store.h"
+
+/* Import the array packing flag */
+extern ref ref_array_packing;
+
+/* - currentpacking <bool> */
+private int
+zcurrentpacking(register os_ptr op)
+{
+ push(1);
+ ref_assign(op, &ref_array_packing);
+ return 0;
+}
+
+/* <obj_0> ... <obj_n-1> <n> packedarray <packedarray> */
+int
+zpackedarray(register os_ptr op)
+{
+ int code;
+ ref parr;
+
+ check_type(*op, t_integer);
+ if (op->value.intval < 0 ||
+ (op->value.intval > op - osbot &&
+ op->value.intval >= ref_stack_count(&o_stack))
+ )
+ return_error(e_rangecheck);
+ osp--;
+ code = make_packed_array(&parr, &o_stack, (uint) op->value.intval,
+ "packedarray");
+ osp++;
+ if (code >= 0)
+ *osp = parr;
+ return code;
+}
+
+/* <bool> setpacking - */
+private int
+zsetpacking(register os_ptr op)
+{
+ check_type(*op, t_boolean);
+ ref_assign_old(NULL, &ref_array_packing, op, "setpacking");
+ pop(1);
+ return 0;
+}
+
+/* ------ Non-operator routines ------ */
+
+/* Make a packed array. See the comment in packed.h about */
+/* ensuring that refs in mixed arrays are properly aligned. */
+int
+make_packed_array(ref * parr, ref_stack * pstack, uint size,
+ client_name_t cname)
+{
+ uint i;
+ const ref *pref;
+ uint idest = 0, ishort = 0;
+ ref_packed *pbody;
+ ref_packed *pdest;
+ ref_packed *pshort; /* points to start of */
+ /* last run of short elements */
+ uint space = ialloc_space(idmemory);
+ int skip = 0, pad;
+ ref rtemp;
+ int code;
+
+ /* Do a first pass to calculate the size of the array, */
+ /* and to detect local-into-global stores. */
+
+ for (i = size; i != 0; i--) {
+ pref = ref_stack_index(pstack, i - 1);
+ switch (r_btype(pref)) { /* not r_type, opers are special */
+ case t_name:
+ if (name_index(pref) >= packed_name_max_index)
+ break; /* can't pack */
+ idest++;
+ continue;
+ case t_integer:
+ if (pref->value.intval < packed_min_intval ||
+ pref->value.intval > packed_max_intval
+ )
+ break;
+ idest++;
+ continue;
+ case t_oparray:
+ /* Check for local-into-global store. */
+ store_check_space(space, pref);
+ /* falls through */
+ case t_operator:
+ {
+ uint oidx;
+
+ if (!r_has_attr(pref, a_executable))
+ break;
+ oidx = op_index(pref);
+ if (oidx == 0 || oidx > packed_int_mask)
+ break;
+ }
+ idest++;
+ continue;
+ default:
+ /* Check for local-into-global store. */
+ store_check_space(space, pref);
+ }
+ /* Can't pack this element, use a full ref. */
+ /* We may have to unpack up to align_packed_per_ref - 1 */
+ /* preceding short elements. */
+ /* If we are at the beginning of the array, however, */
+ /* we can just move the elements up. */
+ {
+ int i = (idest - ishort) & (align_packed_per_ref - 1);
+
+ if (ishort == 0) /* first time */
+ idest += skip = -i & (align_packed_per_ref - 1);
+ else
+ idest += (packed_per_ref - 1) * i;
+ }
+ ishort = idest += packed_per_ref;
+ }
+ pad = -idest & (packed_per_ref - 1); /* padding at end */
+
+ /* Now we can allocate the array. */
+
+ code = ialloc_ref_array(&rtemp, 0, (idest + pad) / packed_per_ref,
+ cname);
+ if (code < 0)
+ return code;
+ pbody = (ref_packed *) rtemp.value.refs;
+
+ /* Make sure any initial skipped elements contain legal packed */
+ /* refs, so that the garbage collector can scan storage. */
+
+ pshort = pbody;
+ for (; skip; skip--)
+ *pbody++ = pt_tag(pt_integer);
+ pdest = pbody;
+
+ for (i = size; i != 0; i--) {
+ pref = ref_stack_index(pstack, i - 1);
+ switch (r_btype(pref)) { /* not r_type, opers are special */
+ case t_name:
+ {
+ uint nidx = name_index(pref);
+
+ if (nidx >= packed_name_max_index)
+ break; /* can't pack */
+ *pdest++ = nidx +
+ (r_has_attr(pref, a_executable) ?
+ pt_tag(pt_executable_name) :
+ pt_tag(pt_literal_name));
+ }
+ continue;
+ case t_integer:
+ if (pref->value.intval < packed_min_intval ||
+ pref->value.intval > packed_max_intval
+ )
+ break;
+ *pdest++ = pt_tag(pt_integer) +
+ ((short)pref->value.intval - packed_min_intval);
+ continue;
+ case t_oparray:
+ case t_operator:
+ {
+ uint oidx;
+
+ if (!r_has_attr(pref, a_executable))
+ break;
+ oidx = op_index(pref);
+ if (oidx == 0 || oidx > packed_int_mask)
+ break;
+ *pdest++ = pt_tag(pt_executable_operator) + oidx;
+ }
+ continue;
+ }
+ /* Can't pack this element, use a full ref. */
+ /* We may have to unpack up to align_packed_per_ref - 1 */
+ /* preceding short elements. */
+ /* Note that if we are at the beginning of the array, */
+ /* 'skip' already ensures that we don't need to do this. */
+ {
+ int i = (pdest - pshort) & (align_packed_per_ref - 1);
+ const ref_packed *psrc = pdest;
+ ref *pmove =
+ (ref *) (pdest += (packed_per_ref - 1) * i);
+
+ ref_assign_new(pmove, pref);
+ while (--i >= 0) {
+ --psrc;
+ --pmove;
+ packed_get(psrc, pmove);
+ }
+ }
+ pshort = pdest += packed_per_ref;
+ }
+
+ {
+ int atype =
+ (pdest == pbody + size ? t_shortarray : t_mixedarray);
+
+ /* Pad with legal packed refs so that the garbage collector */
+ /* can scan storage. */
+
+ for (; pad; pad--)
+ *pdest++ = pt_tag(pt_integer);
+
+ /* Finally, make the array. */
+
+ ref_stack_pop(pstack, size);
+ make_tasv_new(parr, atype, a_readonly | space, size,
+ packed, pbody + skip);
+ }
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zpacked_op_defs[] =
+{
+ {"0currentpacking", zcurrentpacking},
+ {"1packedarray", zpackedarray},
+ {"1setpacking", zsetpacking},
+ op_def_end(0)
+};
diff --git a/pstoraster/zpaint.c b/pstoraster/zpaint.c
new file mode 100644
index 000000000..895b40852
--- /dev/null
+++ b/pstoraster/zpaint.c
@@ -0,0 +1,92 @@
+/* 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$ */
+/* Painting operators */
+#include "ghost.h"
+#include "oper.h"
+#include "gspaint.h"
+#include "igstate.h"
+
+/* - fill - */
+private int
+zfill(register os_ptr op)
+{
+ return gs_fill(igs);
+}
+
+/* - eofill - */
+private int
+zeofill(register os_ptr op)
+{
+ return gs_eofill(igs);
+}
+
+/* - stroke - */
+private int
+zstroke(register os_ptr op)
+{
+ return gs_stroke(igs);
+}
+
+/* ------ Non-standard operators ------ */
+
+/* - .fillpage - */
+private int
+zfillpage(register os_ptr op)
+{
+ return gs_fillpage(igs);
+}
+
+/* <width> <height> <data> .imagepath - */
+private int
+zimagepath(register os_ptr op)
+{
+ int code;
+
+ check_type(op[-2], t_integer);
+ check_type(op[-1], t_integer);
+ check_read_type(*op, t_string);
+ if (r_size(op) < ((op[-2].value.intval + 7) >> 3) * op[-1].value.intval)
+ return_error(e_rangecheck);
+ code = gs_imagepath(igs,
+ (int)op[-2].value.intval, (int)op[-1].value.intval,
+ op->value.const_bytes);
+ if (code >= 0)
+ pop(3);
+ return code;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zpaint_op_defs[] =
+{
+ {"0eofill", zeofill},
+ {"0fill", zfill},
+ {"0stroke", zstroke},
+ /* Non-standard operators */
+ {"0.fillpage", zfillpage},
+ {"3.imagepath", zimagepath},
+ op_def_end(0)
+};
diff --git a/pstoraster/zpath.c b/pstoraster/zpath.c
new file mode 100644
index 000000000..7b1d77a7e
--- /dev/null
+++ b/pstoraster/zpath.c
@@ -0,0 +1,205 @@
+/* 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$ */
+/* Basic path operators */
+#include "math_.h"
+#include "ghost.h"
+#include "oper.h"
+#include "igstate.h"
+#include "gsmatrix.h"
+#include "gspath.h"
+#include "store.h"
+
+/* Forward references */
+private int common_to(P2(os_ptr,
+ int (*)(P3(gs_state *, floatp, floatp))));
+private int common_curve(P2(os_ptr,
+ int (*)(P7(gs_state *, floatp, floatp, floatp, floatp, floatp, floatp))));
+
+/* - newpath - */
+private int
+znewpath(register os_ptr op)
+{
+ return gs_newpath(igs);
+}
+
+/* - currentpoint <x> <y> */
+private int
+zcurrentpoint(register os_ptr op)
+{
+ gs_point pt;
+ int code = gs_currentpoint(igs, &pt);
+
+ if (code < 0)
+ return code;
+ push(2);
+ make_real(op - 1, pt.x);
+ make_real(op, pt.y);
+ return 0;
+}
+
+/* <x> <y> moveto - */
+int
+zmoveto(os_ptr op)
+{
+ return common_to(op, gs_moveto);
+}
+
+/* <dx> <dy> rmoveto - */
+int
+zrmoveto(os_ptr op)
+{
+ return common_to(op, gs_rmoveto);
+}
+
+/* <x> <y> lineto - */
+int
+zlineto(os_ptr op)
+{
+ return common_to(op, gs_lineto);
+}
+
+/* <dx> <dy> rlineto - */
+int
+zrlineto(os_ptr op)
+{
+ return common_to(op, gs_rlineto);
+}
+
+/* Common code for [r](move/line)to */
+private int
+common_to(os_ptr op, int (*add_proc)(P3(gs_state *, floatp, floatp)))
+{
+ double opxy[2];
+ int code;
+
+ if ((code = num_params(op, 2, opxy)) < 0 ||
+ (code = (*add_proc)(igs, opxy[0], opxy[1])) < 0
+ )
+ return code;
+ pop(2);
+ return 0;
+}
+
+/* <x1> <y1> <x2> <y2> <x3> <y3> curveto - */
+int
+zcurveto(register os_ptr op)
+{
+ return common_curve(op, gs_curveto);
+}
+
+/* <dx1> <dy1> <dx2> <dy2> <dx3> <dy3> rcurveto - */
+int
+zrcurveto(register os_ptr op)
+{
+ return common_curve(op, gs_rcurveto);
+}
+
+/* Common code for [r]curveto */
+private int
+common_curve(os_ptr op,
+ int (*add_proc)(P7(gs_state *, floatp, floatp, floatp, floatp, floatp, floatp)))
+{
+ double opxy[6];
+ int code;
+
+ if ((code = num_params(op, 6, opxy)) < 0)
+ return code;
+ code = (*add_proc)(igs, opxy[0], opxy[1], opxy[2], opxy[3], opxy[4], opxy[5]);
+ if (code >= 0)
+ pop(6);
+ return code;
+}
+
+/* - closepath - */
+int
+zclosepath(register os_ptr op)
+{
+ return gs_closepath(igs);
+}
+
+/* - initclip - */
+private int
+zinitclip(register os_ptr op)
+{
+ return gs_initclip(igs);
+}
+
+/* - clip - */
+private int
+zclip(register os_ptr op)
+{
+ return gs_clip(igs);
+}
+
+/* - eoclip - */
+private int
+zeoclip(register os_ptr op)
+{
+ return gs_eoclip(igs);
+}
+
+/* <bool> .setclipoutside - */
+private int
+zsetclipoutside(register os_ptr op)
+{
+ int code;
+
+ check_type(*op, t_boolean);
+ code = gs_setclipoutside(igs, op->value.boolval);
+ if (code >= 0)
+ pop(1);
+ return code;
+}
+
+/* - .currentclipoutside <bool> */
+private int
+zcurrentclipoutside(register os_ptr op)
+{
+ push(1);
+ make_bool(op, gs_currentclipoutside(igs));
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zpath_op_defs[] =
+{
+ {"0clip", zclip},
+ {"0closepath", zclosepath},
+ {"0.currentclipoutside", zcurrentclipoutside},
+ {"0currentpoint", zcurrentpoint},
+ {"6curveto", zcurveto},
+ {"0eoclip", zeoclip},
+ {"0initclip", zinitclip},
+ {"2lineto", zlineto},
+ {"2moveto", zmoveto},
+ {"0newpath", znewpath},
+ {"6rcurveto", zrcurveto},
+ {"2rlineto", zrlineto},
+ {"2rmoveto", zrmoveto},
+ {"1.setclipoutside", zsetclipoutside},
+ op_def_end(0)
+};
diff --git a/pstoraster/zpath1.c b/pstoraster/zpath1.c
new file mode 100644
index 000000000..39dd7d6b2
--- /dev/null
+++ b/pstoraster/zpath1.c
@@ -0,0 +1,279 @@
+/* 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$ */
+/* PostScript Level 1 additional path operators */
+#include "memory_.h"
+#include "ghost.h"
+#include "oper.h"
+#include "estack.h" /* for pathforall */
+#include "ialloc.h"
+#include "igstate.h"
+#include "gsstruct.h"
+#include "gspath.h"
+#include "store.h"
+
+/* Forward references */
+private int common_arc(P2(os_ptr,
+ int (*)(P6(gs_state *, floatp, floatp, floatp, floatp, floatp))));
+private int common_arct(P2(os_ptr, float *));
+
+/* <x> <y> <r> <ang1> <ang2> arc - */
+int
+zarc(os_ptr op)
+{
+ return common_arc(op, gs_arc);
+}
+
+/* <x> <y> <r> <ang1> <ang2> arcn - */
+int
+zarcn(os_ptr op)
+{
+ return common_arc(op, gs_arcn);
+}
+
+/* Common code for arc[n] */
+private int
+common_arc(os_ptr op,
+ int (*aproc)(P6(gs_state *, floatp, floatp, floatp, floatp, floatp)))
+{
+ double xyra[5]; /* x, y, r, ang1, ang2 */
+ int code = num_params(op, 5, xyra);
+
+ if (code < 0)
+ return code;
+ code = (*aproc)(igs, xyra[0], xyra[1], xyra[2], xyra[3], xyra[4]);
+ if (code >= 0)
+ pop(5);
+ return code;
+}
+
+/* <x1> <y1> <x2> <y2> <r> arct - */
+int
+zarct(register os_ptr op)
+{
+ int code = common_arct(op, (float *)0);
+
+ if (code < 0)
+ return code;
+ pop(5);
+ return 0;
+}
+
+/* <x1> <y1> <x2> <y2> <r> arcto <xt1> <yt1> <xt2> <yt2> */
+private int
+zarcto(register os_ptr op)
+{
+ float tanxy[4]; /* xt1, yt1, xt2, yt2 */
+ int code = common_arct(op, tanxy);
+
+ if (code < 0)
+ return code;
+ make_real(op - 4, tanxy[0]);
+ make_real(op - 3, tanxy[1]);
+ make_real(op - 2, tanxy[2]);
+ make_real(op - 1, tanxy[3]);
+ pop(1);
+ return 0;
+}
+
+/* Common code for arct[o] */
+private int
+common_arct(os_ptr op, float *tanxy)
+{
+ double args[5]; /* x1, y1, x2, y2, r */
+ int code = num_params(op, 5, args);
+
+ if (code < 0)
+ return code;
+ return gs_arcto(igs, args[0], args[1], args[2], args[3], args[4], tanxy);
+}
+
+/* - .dashpath - */
+private int
+zdashpath(register os_ptr op)
+{
+ return gs_dashpath(igs);
+}
+
+/* - flattenpath - */
+private int
+zflattenpath(register os_ptr op)
+{
+ return gs_flattenpath(igs);
+}
+
+/* - reversepath - */
+private int
+zreversepath(register os_ptr op)
+{
+ return gs_reversepath(igs);
+}
+
+/* - strokepath - */
+private int
+zstrokepath(register os_ptr op)
+{
+ return gs_strokepath(igs);
+}
+
+/* - clippath - */
+private int
+zclippath(register os_ptr op)
+{
+ return gs_clippath(igs);
+}
+
+/* <bool> .pathbbox <llx> <lly> <urx> <ury> */
+private int
+zpathbbox(register os_ptr op)
+{
+ gs_rect box;
+ int code;
+
+ check_type(*op, t_boolean);
+ code = gs_upathbbox(igs, &box, op->value.boolval);
+ if (code < 0)
+ return code;
+ push(3);
+ make_real(op - 3, box.p.x);
+ make_real(op - 2, box.p.y);
+ make_real(op - 1, box.q.x);
+ make_real(op, box.q.y);
+ return 0;
+}
+
+/* <moveproc> <lineproc> <curveproc> <closeproc> pathforall - */
+private int path_continue(P1(os_ptr));
+private int path_cleanup(P1(os_ptr));
+private int
+zpathforall(register os_ptr op)
+{
+ gs_path_enum *penum;
+ int code;
+
+ check_proc(op[-3]);
+ check_proc(op[-2]);
+ check_proc(op[-1]);
+ check_proc(*op);
+ check_estack(8);
+ if ((penum = gs_path_enum_alloc(imemory, "pathforall")) == 0)
+ return_error(e_VMerror);
+ code = gs_path_enum_init(penum, igs);
+ if (code < 0) {
+ ifree_object(penum, "path_cleanup");
+ return code;
+ }
+ /* Push a mark, the four procedures, and the path enumerator. */
+ push_mark_estack(es_for, path_cleanup); /* iterator */
+ memcpy(esp + 1, op - 3, 4 * sizeof(ref)); /* 4 procs */
+ esp += 5;
+ make_istruct(esp, 0, penum);
+ push_op_estack(path_continue);
+ pop(4);
+ op -= 4;
+ return o_push_estack;
+}
+/* Continuation procedure for pathforall */
+private void pf_push(P3(gs_point *, int, os_ptr));
+private int
+path_continue(register os_ptr op)
+{
+ gs_path_enum *penum = r_ptr(esp, gs_path_enum);
+ gs_point ppts[3];
+ int code;
+
+ /* Make sure we have room on the o-stack for the worst case */
+ /* before we enumerate the next path element. */
+ check_ostack(6); /* 3 points for curveto */
+ code = gs_path_enum_next(penum, ppts);
+ switch (code) {
+ case 0: /* all done */
+ esp -= 6;
+ path_cleanup(op);
+ return o_pop_estack;
+ default: /* error */
+ return code;
+ case gs_pe_moveto:
+ esp[2] = esp[-4]; /* moveto proc */
+ pf_push(ppts, 1, op);
+ break;
+ case gs_pe_lineto:
+ esp[2] = esp[-3]; /* lineto proc */
+ pf_push(ppts, 1, op);
+ break;
+ case gs_pe_curveto:
+ esp[2] = esp[-2]; /* curveto proc */
+ pf_push(ppts, 3, op);
+ break;
+ case gs_pe_closepath:
+ esp[2] = esp[-1]; /* closepath proc */
+ break;
+ }
+ push_op_estack(path_continue);
+ ++esp; /* include pushed procedure */
+ return o_push_estack;
+}
+/* Internal procedure to push one or more points */
+private void
+pf_push(gs_point * ppts, int n, os_ptr op)
+{
+ while (n--) {
+ op += 2;
+ make_real(op - 1, ppts->x);
+ make_real(op, ppts->y);
+ ppts++;
+ }
+ osp = op;
+}
+/* Clean up after a pathforall */
+private int
+path_cleanup(os_ptr op)
+{
+ gs_path_enum *penum = r_ptr(esp + 6, gs_path_enum);
+
+ gs_path_enum_cleanup(penum);
+ ifree_object(penum, "path_cleanup");
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zpath1_op_defs[] =
+{
+ {"5arc", zarc},
+ {"5arcn", zarcn},
+ {"5arct", zarct},
+ {"5arcto", zarcto},
+ {"0clippath", zclippath},
+ {"0.dashpath", zdashpath},
+ {"0flattenpath", zflattenpath},
+ {"4pathforall", zpathforall},
+ {"0reversepath", zreversepath},
+ {"0strokepath", zstrokepath},
+ {"0.pathbbox", zpathbbox},
+ /* Internal operators */
+ {"0%path_continue", path_continue},
+ op_def_end(0)
+};
diff --git a/pstoraster/zpcolor.c b/pstoraster/zpcolor.c
new file mode 100644
index 000000000..445487d02
--- /dev/null
+++ b/pstoraster/zpcolor.c
@@ -0,0 +1,264 @@
+/* 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$ */
+/* Pattern color */
+#include "ghost.h"
+#include "oper.h"
+#include "gscolor.h"
+#include "gsmatrix.h"
+#include "gsstruct.h"
+#include "gxcspace.h"
+#include "gxfixed.h" /* for gxcolor2.h */
+#include "gxcolor2.h"
+#include "gxdcolor.h" /* for gxpcolor.h */
+#include "gxdevice.h"
+#include "gxdevmem.h" /* for gxpcolor.h */
+#include "gxpcolor.h"
+#include "estack.h"
+#include "ialloc.h"
+#include "istruct.h"
+#include "idict.h"
+#include "idparam.h"
+#include "igstate.h"
+#include "store.h"
+
+/* Imported from gspcolor.c */
+extern const gs_color_space_type gs_color_space_type_Pattern;
+
+/* Imported from zcolor2.c */
+extern gs_memory_type_ptr_t zcolor2_st_pattern_instance_p;
+
+/* Forward references */
+private int zPaintProc(P2(const gs_client_color *, gs_state *));
+private int pattern_paint_prepare(P1(os_ptr));
+private int pattern_paint_finish(P1(os_ptr));
+
+/*
+ * Define the structure for remembering the pattern dictionary.
+ * This is the "client data" in the template.
+ * See zgstate.c (int_gstate) or zfont2.c (font_data) for information
+ * as to why we define this as a structure rather than a ref array.
+ */
+typedef struct int_pattern_s {
+ ref dict;
+} int_pattern;
+
+gs_private_st_ref_struct(st_int_pattern, int_pattern, "int_pattern");
+
+/* Initialize the Pattern cache and the Pattern instance type. */
+private void
+zpcolor_init(void)
+{
+ gstate_set_pattern_cache(igs,
+ gx_pattern_alloc_cache(imemory_system,
+ gx_pat_cache_default_tiles(),
+ gx_pat_cache_default_bits()));
+ zcolor2_st_pattern_instance_p = &st_pattern_instance;
+}
+
+/* <pattern> <matrix> .buildpattern1 <pattern> <instance> */
+private int
+zbuildpattern1(os_ptr op)
+{
+ os_ptr op1 = op - 1;
+ int code;
+ gs_matrix mat;
+ float BBox[4];
+ gs_client_pattern template;
+ int_pattern *pdata;
+ gs_client_color cc_instance;
+ ref *pPaintProc;
+
+ check_type(*op1, t_dictionary);
+ check_dict_read(*op1);
+ gs_pattern1_init(&template);
+ if ((code = read_matrix(op, &mat)) < 0 ||
+ (code = dict_uid_param(op1, &template.uid, 1, imemory)) != 1 ||
+ (code = dict_int_param(op1, "PaintType", 1, 2, 0, &template.PaintType)) < 0 ||
+ (code = dict_int_param(op1, "TilingType", 1, 3, 0, &template.TilingType)) < 0 ||
+ (code = dict_float_array_param(op1, "BBox", 4, BBox, NULL)) != 4 ||
+ (code = dict_float_param(op1, "XStep", 0.0, &template.XStep)) != 0 ||
+ (code = dict_float_param(op1, "YStep", 0.0, &template.YStep)) != 0 ||
+ (code = dict_find_string(op1, "PaintProc", &pPaintProc)) <= 0
+ )
+ return_error((code < 0 ? code : e_rangecheck));
+ check_proc(*pPaintProc);
+ template.BBox.p.x = BBox[0];
+ template.BBox.p.y = BBox[1];
+ template.BBox.q.x = BBox[2];
+ template.BBox.q.y = BBox[3];
+ template.PaintProc = zPaintProc;
+ pdata = ialloc_struct(int_pattern, &st_int_pattern, "int_pattern");
+ if (pdata == 0)
+ return_error(e_VMerror);
+ template.client_data = pdata;
+ pdata->dict = *op1;
+ code = gs_makepattern(&cc_instance, &template, &mat, igs, imemory);
+ if (code < 0) {
+ ifree_object(pdata, "int_pattern");
+ return code;
+ }
+ make_istruct(op, a_readonly, cc_instance.pattern);
+ return code;
+}
+
+/* <array> .setpatternspace - */
+/* In the case of uncolored patterns, the current color space is */
+/* the base space for the pattern space. */
+private int
+zsetpatternspace(register os_ptr op)
+{
+ gs_color_space cs;
+ uint edepth = ref_stack_count(&e_stack);
+ int code;
+
+ check_read_type(*op, t_array);
+ switch (r_size(op)) {
+ case 1: /* no base space */
+ cs.params.pattern.has_base_space = false;
+ break;
+ default:
+ return_error(e_rangecheck);
+ case 2:
+ cs = *gs_currentcolorspace(igs);
+ if (cs_num_components(&cs) < 0) /* i.e., Pattern space */
+ return_error(e_rangecheck);
+ /* We can't count on C compilers to recognize the aliasing */
+ /* that would be involved in a direct assignment, so.... */
+ {
+ gs_paint_color_space cs_paint;
+
+ cs_paint = *(gs_paint_color_space *) & cs;
+ cs.params.pattern.base_space = cs_paint;
+ }
+ cs.params.pattern.has_base_space = true;
+ }
+ cs.type = &gs_color_space_type_Pattern;
+ code = gs_setcolorspace(igs, &cs);
+ if (code < 0) {
+ ref_stack_pop_to(&e_stack, edepth);
+ return code;
+ }
+ pop(1);
+ return (ref_stack_count(&e_stack) == edepth ? 0 : o_push_estack); /* installation will load the caches */
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zpcolor_l2_op_defs[] =
+{
+ op_def_begin_level2(),
+ {"2.buildpattern1", zbuildpattern1},
+ {"1.setpatternspace", zsetpatternspace},
+ /* Internal operators */
+ {"0%pattern_paint_prepare", pattern_paint_prepare},
+ {"0%pattern_paint_finish", pattern_paint_finish},
+ op_def_end(zpcolor_init)
+};
+
+/* ------ Internal procedures ------ */
+
+/* Set up the pattern pointer in a client color for setcolor */
+/* with a Pattern space. */
+/****** ? WHAT WAS THIS FOR ? ******/
+
+/* Render the pattern by calling the PaintProc. */
+private int pattern_paint_cleanup(P1(os_ptr));
+private int
+zPaintProc(const gs_client_color * pcc, gs_state * pgs)
+{
+ /* Just schedule a call on the real PaintProc. */
+ check_estack(2);
+ esp++;
+ push_op_estack(pattern_paint_prepare);
+ return e_InsertProc;
+}
+/* Prepare to run the PaintProc. */
+private int
+pattern_paint_prepare(os_ptr op)
+{
+ gs_state *pgs = igs;
+ gs_pattern_instance *pinst = gs_currentcolor(pgs)->pattern;
+ ref *pdict = &((int_pattern *) pinst->template.client_data)->dict;
+ gx_device_pattern_accum *pdev;
+ int code;
+ ref *ppp;
+
+ check_estack(5);
+ pdev = gx_pattern_accum_alloc(imemory, "pattern_paint_prepare");
+ if (pdev == 0)
+ return_error(e_VMerror);
+ pdev->instance = pinst;
+ pdev->bitmap_memory = gstate_pattern_cache(pgs)->memory;
+ code = (*dev_proc(pdev, open_device)) ((gx_device *) pdev);
+ if (code < 0) {
+ ifree_object(pdev, "pattern_paint_prepare");
+ return code;
+ }
+ code = gs_gsave(pgs);
+ if (code < 0)
+ return code;
+ code = gs_setgstate(pgs, pinst->saved);
+ if (code < 0) {
+ gs_grestore(pgs);
+ return code;
+ }
+ gx_set_device_only(pgs, (gx_device *) pdev);
+ push_mark_estack(es_other, pattern_paint_cleanup);
+ ++esp;
+ make_istruct(esp, 0, pdev);
+ push_op_estack(pattern_paint_finish);
+ dict_find_string(pdict, "PaintProc", &ppp); /* can't fail */
+ *++esp = *ppp;
+ *++esp = *pdict; /* (push on ostack) */
+ return o_push_estack;
+}
+/* Save the rendered pattern. */
+private int
+pattern_paint_finish(os_ptr op)
+{
+ gx_device_pattern_accum *pdev = r_ptr(esp, gx_device_pattern_accum);
+ gx_color_tile *ctile;
+ int code = gx_pattern_cache_add_entry((gs_imager_state *)igs,
+ pdev, &ctile);
+
+ if (code < 0)
+ return code;
+ esp -= 2;
+ pattern_paint_cleanup(op);
+ return o_pop_estack;
+}
+/* Clean up after rendering a pattern. Note that iff the rendering */
+/* succeeded, closing the accumulator won't free the bits. */
+private int
+pattern_paint_cleanup(os_ptr op)
+{
+ gx_device_pattern_accum *const pdev =
+ r_ptr(esp + 2, gx_device_pattern_accum);
+
+ /* grestore will free the device, so close it first. */
+ (*dev_proc(pdev, close_device)) ((gx_device *) pdev);
+ return gs_grestore(igs);
+}
diff --git a/pstoraster/zrelbit.c b/pstoraster/zrelbit.c
new file mode 100644
index 000000000..08e07f3d0
--- /dev/null
+++ b/pstoraster/zrelbit.c
@@ -0,0 +1,342 @@
+/* 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$ */
+/* Relational, boolean, and bit operators */
+#include "ghost.h"
+#include "oper.h"
+#include "gsutil.h"
+#include "idict.h"
+#include "store.h"
+
+/* ------ Standard operators ------ */
+
+/* Define the type test for eq and its relatives. */
+#define EQ_CHECK_READ(opp, dflt)\
+ switch ( r_type(opp) ) {\
+ case t_string:\
+ check_read(*(opp));\
+ break;\
+ default:\
+ dflt;\
+ }
+
+/* Forward references */
+private int obj_le(P2(os_ptr, os_ptr));
+
+/* <obj1> <obj2> eq <bool> */
+private int
+zeq(register os_ptr op)
+{
+ EQ_CHECK_READ(op - 1, check_op(2));
+ EQ_CHECK_READ(op, DO_NOTHING);
+ make_bool(op - 1, (obj_eq(op - 1, op) ? 1 : 0));
+ pop(1);
+ return 0;
+}
+
+/* <obj1> <obj2> ne <bool> */
+private int
+zne(register os_ptr op)
+{ /* We'll just be lazy and use eq. */
+ int code = zeq(op);
+
+ if (!code)
+ op[-1].value.boolval ^= 1;
+ return code;
+}
+
+/* <num1> <num2> ge <bool> */
+/* <str1> <str2> ge <bool> */
+private int
+zge(register os_ptr op)
+{
+ int code = obj_le(op, op - 1);
+
+ if (code < 0)
+ return code;
+ make_bool(op - 1, code);
+ pop(1);
+ return 0;
+}
+
+/* <num1> <num2> gt <bool> */
+/* <str1> <str2> gt <bool> */
+private int
+zgt(register os_ptr op)
+{
+ int code = obj_le(op - 1, op);
+
+ if (code < 0)
+ return code;
+ make_bool(op - 1, code ^ 1);
+ pop(1);
+ return 0;
+}
+
+/* <num1> <num2> le <bool> */
+/* <str1> <str2> le <bool> */
+private int
+zle(register os_ptr op)
+{
+ int code = obj_le(op - 1, op);
+
+ if (code < 0)
+ return code;
+ make_bool(op - 1, code);
+ pop(1);
+ return 0;
+}
+
+/* <num1> <num2> lt <bool> */
+/* <str1> <str2> lt <bool> */
+private int
+zlt(register os_ptr op)
+{
+ int code = obj_le(op, op - 1);
+
+ if (code < 0)
+ return code;
+ make_bool(op - 1, code ^ 1);
+ pop(1);
+ return 0;
+}
+
+/* <num1> <num2> .max <num> */
+/* <str1> <str2> .max <str> */
+private int
+zmax(register os_ptr op)
+{
+ int code = obj_le(op - 1, op);
+
+ if (code < 0)
+ return code;
+ if (code) {
+ ref_assign(op - 1, op);
+ }
+ pop(1);
+ return 0;
+}
+
+/* <num1> <num2> .min <num> */
+/* <str1> <str2> .min <str> */
+private int
+zmin(register os_ptr op)
+{
+ int code = obj_le(op - 1, op);
+
+ if (code < 0)
+ return code;
+ if (!code) {
+ ref_assign(op - 1, op);
+ }
+ pop(1);
+ return 0;
+}
+
+/* <bool1> <bool2> and <bool> */
+/* <int1> <int2> and <int> */
+private int
+zand(register os_ptr op)
+{
+ switch (r_type(op)) {
+ case t_boolean:
+ check_type(op[-1], t_boolean);
+ op[-1].value.boolval &= op->value.boolval;
+ break;
+ case t_integer:
+ check_type(op[-1], t_integer);
+ op[-1].value.intval &= op->value.intval;
+ break;
+ default:
+ return_op_typecheck(op);
+ }
+ pop(1);
+ return 0;
+}
+
+/* <bool> not <bool> */
+/* <int> not <int> */
+private int
+znot(register os_ptr op)
+{
+ switch (r_type(op)) {
+ case t_boolean:
+ op->value.boolval = !op->value.boolval;
+ break;
+ case t_integer:
+ op->value.intval = ~op->value.intval;
+ break;
+ default:
+ return_op_typecheck(op);
+ }
+ return 0;
+}
+
+/* <bool1> <bool2> or <bool> */
+/* <int1> <int2> or <int> */
+private int
+zor(register os_ptr op)
+{
+ switch (r_type(op)) {
+ case t_boolean:
+ check_type(op[-1], t_boolean);
+ op[-1].value.boolval |= op->value.boolval;
+ break;
+ case t_integer:
+ check_type(op[-1], t_integer);
+ op[-1].value.intval |= op->value.intval;
+ break;
+ default:
+ return_op_typecheck(op);
+ }
+ pop(1);
+ return 0;
+}
+
+/* <bool1> <bool2> xor <bool> */
+/* <int1> <int2> xor <int> */
+private int
+zxor(register os_ptr op)
+{
+ switch (r_type(op)) {
+ case t_boolean:
+ check_type(op[-1], t_boolean);
+ op[-1].value.boolval ^= op->value.boolval;
+ break;
+ case t_integer:
+ check_type(op[-1], t_integer);
+ op[-1].value.intval ^= op->value.intval;
+ break;
+ default:
+ return_op_typecheck(op);
+ }
+ pop(1);
+ return 0;
+}
+
+/* <int> <shift> bitshift <int> */
+private int
+zbitshift(register os_ptr op)
+{
+ int shift;
+
+ check_type(*op, t_integer);
+ check_type(op[-1], t_integer);
+#define MAX_SHIFT (arch_sizeof_long * 8 - 1)
+ if (op->value.intval < -MAX_SHIFT || op->value.intval > MAX_SHIFT)
+ op[-1].value.intval = 0;
+#undef MAX_SHIFT
+ else if ((shift = op->value.intval) < 0)
+ op[-1].value.intval = ((ulong)(op[-1].value.intval)) >> -shift;
+ else
+ op[-1].value.intval <<= shift;
+ pop(1);
+ return 0;
+}
+
+/* ------ Extensions ------ */
+
+/* <obj1> <obj2> .identeq <bool> */
+private int
+zidenteq(register os_ptr op)
+{
+ EQ_CHECK_READ(op - 1, check_op(2));
+ EQ_CHECK_READ(op, DO_NOTHING);
+ make_bool(op - 1, (obj_ident_eq(op - 1, op) ? 1 : 0));
+ pop(1);
+ return 0;
+
+}
+
+/* <obj1> <obj2> .identne <bool> */
+private int
+zidentne(register os_ptr op)
+{ /* We'll just be lazy and use .identeq. */
+ int code = zidenteq(op);
+
+ if (!code)
+ op[-1].value.boolval ^= 1;
+ return code;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zrelbit_op_defs[] =
+{
+ {"2and", zand},
+ {"2bitshift", zbitshift},
+ {"2eq", zeq},
+ {"2ge", zge},
+ {"2gt", zgt},
+ {"2le", zle},
+ {"2lt", zlt},
+ {"2.max", zmax},
+ {"2.min", zmin},
+ {"2ne", zne},
+ {"1not", znot},
+ {"2or", zor},
+ {"2xor", zxor},
+ /* Extensions */
+ {"2.identeq", zidenteq},
+ {"2.identne", zidentne},
+ op_def_end(0)
+};
+
+/* ------ Internal routines ------ */
+
+/* Compare two operands (both numeric, or both strings). */
+/* Return 1 if op[-1] <= op[0], 0 if op[-1] > op[0], */
+/* or a (negative) error code. */
+private int
+obj_le(register os_ptr op1, register os_ptr op)
+{
+ switch (r_type(op1)) {
+ case t_integer:
+ switch (r_type(op)) {
+ case t_integer:
+ return (op1->value.intval <= op->value.intval);
+ case t_real:
+ return ((double)op1->value.intval <= op->value.realval);
+ default:
+ return_op_typecheck(op);
+ }
+ case t_real:
+ switch (r_type(op)) {
+ case t_real:
+ return (op1->value.realval <= op->value.realval);
+ case t_integer:
+ return (op1->value.realval <= (double)op->value.intval);
+ default:
+ return_op_typecheck(op);
+ }
+ case t_string:
+ check_read(*op1);
+ check_read_type(*op, t_string);
+ return (bytes_compare(op1->value.bytes, r_size(op1),
+ op->value.bytes, r_size(op)) <= 0);
+ default:
+ return_op_typecheck(op1);
+ }
+}
diff --git a/pstoraster/zshade.c b/pstoraster/zshade.c
new file mode 100644
index 000000000..2486976b8
--- /dev/null
+++ b/pstoraster/zshade.c
@@ -0,0 +1,599 @@
+/* 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 language interface to shading */
+#include "memory_.h"
+#include "ghost.h"
+#include "oper.h"
+#include "gscolor3.h"
+#include "gscspace.h"
+#include "gscolor2.h" /* requires gscspace.h */
+#include "gsfunc3.h"
+#include "gsstruct.h" /* must precede gsshade.h */
+#include "gsshade.h"
+#include "gsuid.h"
+#include "stream.h" /* for files.h */
+#include "files.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "idparam.h"
+#include "ifunc.h"
+#include "igstate.h"
+#include "store.h"
+
+/* Forward references */
+private int shading_param(P2(const_os_ptr op, const gs_shading_t ** ppsh));
+
+/* ---------------- Standard operators ---------------- */
+
+/* - currentsmoothness <smoothness> */
+private int
+zcurrentsmoothness(register os_ptr op)
+{
+ push(1);
+ make_real(op, gs_currentsmoothness(igs));
+ return 0;
+}
+
+/* <smoothness> setsmoothness - */
+private int
+zsetsmoothness(register os_ptr op)
+{
+ double smoothness;
+ int code;
+
+ if (real_param(op, &smoothness) < 0)
+ return_op_typecheck(op);
+ if ((code = gs_setsmoothness(igs, smoothness)) < 0)
+ return code;
+ pop(1);
+ return 0;
+}
+
+/* <shading> .shfill - */
+private int
+zshfill(register os_ptr op)
+{
+ const gs_shading_t *psh;
+ int code = shading_param(op, &psh);
+
+ if (code < 0 || (code = gs_shfill(igs, psh)) < 0)
+ return code;
+ pop(1);
+ return 0;
+}
+
+/* ------ Non-standard operators ------ */
+
+/* <pattern> <matrix> <shading> .buildshadingpattern <pattern> <instance> */
+private int
+zbuildshadingpattern(os_ptr op)
+{
+ os_ptr op2 = op - 2;
+ const gs_shading_t *psh;
+ gs_matrix mat;
+ struct {
+ gs_uid uid;
+ } template; /****** WRONG ******/
+ int code;
+
+ check_type(*op2, t_dictionary);
+ check_dict_read(*op2);
+
+ if ((code = shading_param(op, &psh)) < 0 ||
+ (code = read_matrix(op - 1, &mat)) < 0 ||
+ (code = dict_uid_param(op2, &template.uid, 1, imemory)) != 1
+ )
+ return_error((code < 0 ? code : e_rangecheck));
+ /****** NYI ******/
+ return_error(e_undefined);
+}
+
+/* ------ Internal procedures ------ */
+
+/* Get a shading parameter. */
+private int
+shading_param(const_os_ptr op, const gs_shading_t ** ppsh)
+{ /*
+ * Since shadings form a subclass hierarchy, we currently have
+ * no way to check whether a structure is actually a shading.
+ */
+ if (!r_is_struct(op) ||
+ r_has_masked_attrs(op, a_executable | a_execute, a_all)
+ )
+ return_error(e_typecheck);
+ *ppsh = (gs_shading_t *) op->value.pstruct;
+ return 0;
+}
+
+/* ---------------- Shading dictionaries ---------------- */
+
+/* ------ Common code ------ */
+
+extern_st(st_color_space);
+
+typedef int (*build_shading_proc_t)(P3(const ref *op,
+ const gs_shading_params_t *params,
+ gs_shading_t **ppsh));
+
+/* Operators */
+
+/* Common framework for building shadings. */
+private int
+build_shading(ref * op, build_shading_proc_t proc)
+{
+ int code;
+ float box[4];
+ gs_shading_params_t params;
+ gs_shading_t *psh;
+ ref *pvalue;
+
+ check_type(*op, t_dictionary);
+ params.ColorSpace = 0;
+ params.Background = 0;
+ /* Collect parameters common to all shading types. */
+ {
+ const gs_color_space *pcs_orig = gs_currentcolorspace(igs);
+ int num_comp = gs_color_space_num_components(pcs_orig);
+ gs_color_space *pcs;
+
+ if (num_comp < 0) /* Pattern color space */
+ return_error(e_rangecheck);
+ pcs = ialloc_struct(gs_color_space, &st_color_space,
+ "build_shading");
+ if (pcs == 0)
+ return_error(e_VMerror);
+ gs_cspace_init_from(pcs, pcs_orig);
+ params.ColorSpace = pcs;
+ if (dict_find_string(op, "Background", &pvalue) > 0) {
+ gs_client_color *pcc =
+ ialloc_struct(gs_client_color, &st_client_color,
+ "build_shading");
+
+ if (pcc == 0) {
+ code = gs_note_error(e_VMerror);
+ goto fail;
+ }
+ pcc->pattern = 0;
+ params.Background = pcc;
+ code = dict_float_array_param(op, "Background",
+ countof(pcc->paint.values),
+ pcc->paint.values, NULL);
+ if (code != gs_color_space_num_components(pcs))
+ goto fail;
+ }
+ }
+ if (dict_find_string(op, "BBox", &pvalue) <= 0)
+ params.have_BBox = false;
+ else if ((code = dict_float_array_param(op, "BBox", 4, box, NULL)) == 4) {
+ params.BBox.p.x = box[0];
+ params.BBox.p.y = box[1];
+ params.BBox.q.x = box[2];
+ params.BBox.q.y = box[3];
+ params.have_BBox = true;
+ } else
+ goto fail;
+ code = dict_bool_param(op, "AntiAlias", false, &params.AntiAlias);
+ if (code < 0)
+ goto fail;
+ /* Finish building the shading. */
+ code = (*proc) (op, &params, &psh);
+ if (code < 0)
+ goto fail;
+ make_istruct_new(op, 0, psh);
+ return code;
+fail:
+ ifree_object(params.Background, "Background");
+ if (params.ColorSpace) {
+ gs_cspace_release(params.ColorSpace);
+ ifree_object(params.ColorSpace, "ColorSpace");
+ }
+ return (code < 0 ? code : gs_note_error(e_rangecheck));
+}
+
+/* Collect a Function value. */
+private int
+build_shading_function(const ref * op, gs_function_t ** ppfn, int num_inputs)
+{
+ ref *pFunction;
+
+ *ppfn = 0;
+ if (dict_find_string(op, "Function", &pFunction) <= 0)
+ return 0;
+ if (r_is_array(pFunction)) {
+ uint size = r_size(pFunction);
+ gs_function_t **Functions;
+ uint i;
+ gs_function_AdOt_params_t params;
+ int code;
+
+ check_read(*pFunction);
+ if (size == 0)
+ return_error(e_rangecheck);
+ code = ialloc_function_array(size, &Functions);
+ if (code < 0)
+ return code;
+ for (i = 0; i < size; ++i) {
+ ref rsubfn;
+
+ array_get(op, (long)i, &rsubfn);
+ code = fn_build_function(&rsubfn, &Functions[i]);
+ if (code < 0)
+ break;
+ }
+ params.m = 1;
+ params.Domain = 0;
+ params.n = size;
+ params.Range = 0;
+ params.Functions = (const gs_function_t * const *)Functions;
+ if (code >= 0)
+ code = gs_function_AdOt_init(ppfn, &params, imemory);
+ if (code < 0)
+ gs_function_AdOt_free_params(&params, imemory);
+ return code;
+ } else
+ return fn_build_function(pFunction, ppfn);
+}
+
+/* ------ Build shadings ------ */
+
+/* Build a ShadingType 1 (Function-based) shading. */
+private int
+build_shading_1(const ref * op, const gs_shading_params_t * pcommon,
+ gs_shading_t ** ppsh)
+{
+ gs_shading_Fb_params_t params;
+ int code;
+ static const float default_Domain[4] = {0, 1, 0, 1};
+
+ *(gs_shading_params_t *)&params = *pcommon;
+ gs_make_identity(&params.Matrix);
+ params.Function = 0;
+ if ((code = dict_float_array_param(op, "Domain", 4, params.Domain,
+ default_Domain)) != 4 ||
+ (code = dict_matrix_param(op, "Matrix", &params.Matrix)) < 0 ||
+ (code = build_shading_function(op, &params.Function, 2)) < 0 ||
+ (code = gs_shading_Fb_init(ppsh, &params, imemory)) < 0
+ ) {
+ ifree_object(params.Function, "Function");
+ return (code < 0 ? code : gs_note_error(e_rangecheck));
+ }
+ return 0;
+}
+/* <dict> .buildshading1 <shading_struct> */
+private int
+zbuildshading1(os_ptr op)
+{
+ return build_shading(op, build_shading_1);
+}
+
+/* Collect parameters for an Axial or Radial shading. */
+private int
+build_directional_shading(const ref * op, float *Coords, int num_Coords,
+ float Domain[2], gs_function_t ** pFunction, bool Extend[2])
+{
+ int code =
+ dict_float_array_param(op, "Coords", num_Coords, Coords, NULL);
+ static const float default_Domain[2] = {0, 1};
+ ref *pExtend;
+
+ *pFunction = 0;
+ if (code != num_Coords ||
+ (code = dict_float_array_param(op, "Domain", 2, Domain,
+ default_Domain)) != 2 ||
+ (code = build_shading_function(op, pFunction, 1)) < 0
+ )
+ return (code < 0 ? code : gs_note_error(e_rangecheck));
+ if (dict_find_string(op, "Extend", &pExtend) <= 0)
+ Extend[0] = Extend[1] = false;
+ else {
+ ref E0, E1;
+
+ if (!r_is_array(pExtend))
+ return_error(e_typecheck);
+ else if (r_size(pExtend) != 2)
+ return_error(e_rangecheck);
+ else if ((array_get(pExtend, 0L, &E0), !r_has_type(&E0, t_boolean)) ||
+ (array_get(pExtend, 1L, &E1), !r_has_type(&E1, t_boolean))
+ )
+ return_error(e_typecheck);
+ Extend[0] = E0.value.boolval, Extend[1] = E1.value.boolval;
+ }
+ return 0;
+}
+
+/* Build a ShadingType 2 (Axial) shading. */
+private int
+build_shading_2(const ref * op, const gs_shading_params_t * pcommon,
+ gs_shading_t ** ppsh)
+{
+ gs_shading_A_params_t params;
+ int code;
+
+ *(gs_shading_params_t *)&params = *pcommon;
+ if ((code = build_directional_shading(op, params.Coords, 4,
+ params.Domain, &params.Function,
+ params.Extend)) < 0 ||
+ (code = gs_shading_A_init(ppsh, &params, imemory)) < 0
+ ) {
+ ifree_object(params.Function, "Function");
+ }
+ return code;
+}
+/* <dict> .buildshading2 <shading_struct> */
+private int
+zbuildshading2(os_ptr op)
+{
+ return build_shading(op, build_shading_2);
+}
+
+/* Build a ShadingType 3 (Radial) shading. */
+private int
+build_shading_3(const ref * op, const gs_shading_params_t * pcommon,
+ gs_shading_t ** ppsh)
+{
+ gs_shading_R_params_t params;
+ int code;
+
+ *(gs_shading_params_t *)&params = *pcommon;
+ if ((code = build_directional_shading(op, params.Coords, 6,
+ params.Domain, &params.Function,
+ params.Extend)) < 0 ||
+ (code = gs_shading_R_init(ppsh, &params, imemory)) < 0
+ ) {
+ ifree_object(params.Function, "Function");
+ }
+ return code;
+}
+/* <dict> .buildshading3 <shading_struct> */
+private int
+zbuildshading3(os_ptr op)
+{
+ return build_shading(op, build_shading_3);
+}
+
+/* Collect parameters for a mesh shading. */
+private int
+build_mesh_shading(const ref * op, gs_shading_mesh_params_t * params,
+ float **pDecode, gs_function_t ** pFunction)
+{
+ int code;
+ ref *pDataSource;
+
+ *pDecode = 0;
+ *pFunction = 0;
+ if (dict_find_string(op, "DataSource", &pDataSource) <= 0)
+ return_error(e_rangecheck);
+ if (r_is_array(pDataSource)) {
+ uint size = r_size(pDataSource);
+ float *data =
+ (float *)ialloc_byte_array(size, sizeof(float),
+ "build_mesh_shading");
+ int code;
+
+ if (data == 0)
+ return_error(e_VMerror);
+ code = float_params(pDataSource->value.refs + size - 1, size, data);
+ if (code < 0) {
+ ifree_object(data, "build_mesh_shading");
+ return code;
+ }
+ data_source_init_floats(&params->DataSource, data, size);
+ } else
+ switch (r_type(pDataSource)) {
+ case t_file: {
+ stream *s;
+
+ check_read_file(s, pDataSource);
+ data_source_init_stream(&params->DataSource, s);
+ break;
+ }
+ case t_string:
+ check_read(*pDataSource);
+ data_source_init_string2(&params->DataSource,
+ pDataSource->value.bytes,
+ r_size(pDataSource));
+ break;
+ default:
+ return_error(e_typecheck);
+ }
+ if (data_source_is_array(params->DataSource)) {
+ params->BitsPerCoordinate = 0;
+ params->BitsPerComponent = 0;
+ } else {
+ int num_decode =
+ 4 + gs_color_space_num_components(params->ColorSpace) * 2;
+
+/****** FREE FLOAT ARRAY DATA ON ERROR ******/
+ if ((code = dict_int_param(op, "BitsPerCoordinate", 1, 32, 0,
+ &params->BitsPerCoordinate)) < 0 ||
+ (code = dict_int_param(op, "BitsPerComponent", 1, 16, 0,
+ &params->BitsPerComponent)) < 0
+ )
+ return code;
+ *pDecode = (float *)ialloc_byte_array(num_decode, sizeof(float),
+ "build_mesh_shading");
+
+ if (*pDecode == 0)
+ return_error(e_VMerror);
+ code = dict_float_array_param(op, "Decode", num_decode, *pDecode,
+ NULL);
+ if (code != num_decode) {
+ ifree_object(*pDecode, "build_mesh_shading");
+ *pDecode = 0;
+ return (code < 0 ? code : gs_note_error(e_rangecheck));
+ }
+ }
+ code = build_shading_function(op, pFunction, 1);
+ if (code < 0) {
+ ifree_object(*pDecode, "build_mesh_shading");
+ *pDecode = 0;
+ }
+ return code;
+}
+
+/* Collect the BitsPerFlag parameter, if relevant. */
+private int
+flag_bits_param(const ref * op, const gs_shading_mesh_params_t * params,
+ int *pBitsPerFlag)
+{
+ if (data_source_is_array(params->DataSource)) {
+ *pBitsPerFlag = 0;
+ return 0;
+ } else {
+ return dict_int_param(op, "BitsPerFlag", 2, 8, 0, pBitsPerFlag);
+ }
+}
+
+/* Build a ShadingType 4 (Free-form Gouraud triangle mesh) shading. */
+private int
+build_shading_4(const ref * op, const gs_shading_params_t * pcommon,
+ gs_shading_t ** ppsh)
+{
+ gs_shading_FfGt_params_t params;
+ int code;
+
+ *(gs_shading_params_t *)&params = *pcommon;
+ if ((code =
+ build_mesh_shading(op, (gs_shading_mesh_params_t *)&params,
+ &params.Decode, &params.Function)) < 0 ||
+ (code = flag_bits_param(op, (gs_shading_mesh_params_t *)&params,
+ &params.BitsPerFlag)) < 0 ||
+ (code = gs_shading_FfGt_init(ppsh, &params, imemory)) < 0
+ ) {
+ ifree_object(params.Function, "Function");
+ ifree_object(params.Decode, "Decode");
+ }
+ return code;
+}
+/* <dict> .buildshading4 <shading_struct> */
+private int
+zbuildshading4(os_ptr op)
+{
+ return build_shading(op, build_shading_4);
+}
+
+/* Build a ShadingType 5 (Lattice-form Gouraud triangle mesh) shading. */
+private int
+build_shading_5(const ref * op, const gs_shading_params_t * pcommon,
+ gs_shading_t ** ppsh)
+{
+ gs_shading_LfGt_params_t params;
+ int code;
+
+ *(gs_shading_params_t *)&params = *pcommon;
+ if ((code =
+ build_mesh_shading(op, (gs_shading_mesh_params_t *)&params,
+ &params.Decode, &params.Function)) < 0 ||
+ (code = dict_int_param(op, "VerticesPerRow", 2, max_int, 0,
+ &params.VerticesPerRow)) < 0 ||
+ (code = gs_shading_LfGt_init(ppsh, &params, imemory)) < 0
+ ) {
+ ifree_object(params.Function, "Function");
+ ifree_object(params.Decode, "Decode");
+ }
+ return code;
+}
+/* <dict> .buildshading5 <shading_struct> */
+private int
+zbuildshading5(os_ptr op)
+{
+ return build_shading(op, build_shading_5);
+}
+
+/* Build a ShadingType 6 (Coons patch mesh) shading. */
+private int
+build_shading_6(const ref * op, const gs_shading_params_t * pcommon,
+ gs_shading_t ** ppsh)
+{
+ gs_shading_Cp_params_t params;
+ int code;
+
+ *(gs_shading_params_t *)&params = *pcommon;
+ if ((code =
+ build_mesh_shading(op, (gs_shading_mesh_params_t *)&params,
+ &params.Decode, &params.Function)) < 0 ||
+ (code = flag_bits_param(op, (gs_shading_mesh_params_t *)&params,
+ &params.BitsPerFlag)) < 0 ||
+ (code = gs_shading_Cp_init(ppsh, &params, imemory)) < 0
+ ) {
+ ifree_object(params.Function, "Function");
+ ifree_object(params.Decode, "Decode");
+ }
+ return code;
+}
+/* <dict> .buildshading6 <shading_struct> */
+private int
+zbuildshading6(os_ptr op)
+{
+ return build_shading(op, build_shading_6);
+}
+
+/* Build a ShadingType 7 (Tensor product patch mesh) shading. */
+private int
+build_shading_7(const ref * op, const gs_shading_params_t * pcommon,
+ gs_shading_t ** ppsh)
+{
+ gs_shading_Tpp_params_t params;
+ int code;
+
+ *(gs_shading_params_t *)&params = *pcommon;
+ if ((code =
+ build_mesh_shading(op, (gs_shading_mesh_params_t *)&params,
+ &params.Decode, &params.Function)) < 0 ||
+ (code = flag_bits_param(op, (gs_shading_mesh_params_t *)&params,
+ &params.BitsPerFlag)) < 0 ||
+ (code = gs_shading_Tpp_init(ppsh, &params, imemory)) < 0
+ ) {
+ ifree_object(params.Function, "Function");
+ ifree_object(params.Decode, "Decode");
+ }
+ return code;
+}
+/* <dict> .buildshading7 <shading_struct> */
+private int
+zbuildshading7(os_ptr op)
+{
+ return build_shading(op, build_shading_7);
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zshade_op_defs[] =
+{
+ op_def_begin_ll3(),
+ {"0currentsmoothness", zcurrentsmoothness},
+ {"1setsmoothness", zsetsmoothness},
+ {"1.shfill", zshfill},
+ {"1.buildshading1", zbuildshading1},
+ {"1.buildshading2", zbuildshading2},
+ {"1.buildshading3", zbuildshading3},
+ {"1.buildshading4", zbuildshading4},
+ {"1.buildshading5", zbuildshading5},
+ {"1.buildshading6", zbuildshading6},
+ {"1.buildshading7", zbuildshading7},
+ {"3.buildshadingpattern", zbuildshadingpattern},
+ op_def_end(0)
+};
diff --git a/pstoraster/zstack.c b/pstoraster/zstack.c
new file mode 100644
index 000000000..5057b1d64
--- /dev/null
+++ b/pstoraster/zstack.c
@@ -0,0 +1,295 @@
+/* Copyright (C) 1989, 1991, 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$ */
+/* Operand stack operators */
+#include "memory_.h"
+#include "ghost.h"
+#include "ialloc.h"
+#include "istack.h"
+#include "oper.h"
+#include "store.h"
+
+/* <obj> pop - */
+int
+zpop(register os_ptr op)
+{
+ check_op(1);
+ pop(1);
+ return 0;
+}
+
+/* <obj1> <obj2> exch <obj2> <obj1> */
+int
+zexch(register os_ptr op)
+{
+ ref next;
+
+ check_op(2);
+ ref_assign_inline(&next, op - 1);
+ ref_assign_inline(op - 1, op);
+ ref_assign_inline(op, &next);
+ return 0;
+}
+
+/* <obj> dup <obj> <obj> */
+int
+zdup(register os_ptr op)
+{
+ check_op(1);
+ push(1);
+ ref_assign_inline(op, op - 1);
+ return 0;
+}
+
+/* <obj_n> ... <obj_0> <n> index <obj_n> ... <obj_0> <obj_n> */
+int
+zindex(register os_ptr op)
+{
+ register os_ptr opn;
+
+ check_type(*op, t_integer);
+ if ((ulong)op->value.intval >= op - osbot) {
+ /* Might be in an older stack block. */
+ ref *elt;
+
+ if (op->value.intval < 0)
+ return_error(e_rangecheck);
+ elt = ref_stack_index(&o_stack, op->value.intval + 1);
+ if (elt == 0)
+ return_error(e_rangecheck);
+ ref_assign(op, elt);
+ return 0;
+ }
+ opn = op + ~(int)op->value.intval;
+ ref_assign_inline(op, opn);
+ return 0;
+}
+
+/* <obj_n-1> ... <obj_0> <n> <i> roll */
+/* <obj_(i-1)_mod_ n> ... <obj_0> <obj_n-1> ... <obj_i_mod_n> */
+int
+zroll(register os_ptr op)
+{
+ os_ptr op1 = op - 1;
+ int count, mod;
+ register os_ptr from, to;
+ register int n;
+
+ check_type(*op1, t_integer);
+ check_type(*op, t_integer);
+ if ((ulong) op1->value.intval > op1 - osbot) {
+ /*
+ * The data might span multiple stack blocks.
+ * There are efficient ways to handle this situation,
+ * but they're more complicated than seems worth implementing;
+ * for now, do something very simple and inefficient.
+ */
+ int left, i;
+
+ if (op1->value.intval < 0 ||
+ op1->value.intval + 2 > ref_stack_count(&o_stack)
+ )
+ return_error(e_rangecheck);
+ count = op1->value.intval;
+ if (count <= 1) {
+ pop(2);
+ return 0;
+ }
+ mod = op->value.intval;
+ if (mod >= count)
+ mod %= count;
+ else if (mod < 0) {
+ mod %= count;
+ if (mod < 0)
+ mod += count; /* can't assume % means mod! */
+ }
+ /* Use the chain rotation algorithm mentioned below. */
+ for (i = 0, left = count; left; i++) {
+ ref *elt = ref_stack_index(&o_stack, i + 2);
+ ref save;
+ int j, k;
+ ref *next;
+
+ save = *elt;
+ for (j = i, left--;; j = k, elt = next, left--) {
+ k = (j + mod) % count;
+ if (k == i)
+ break;
+ next = ref_stack_index(&o_stack, k + 2);
+ ref_assign(elt, next);
+ }
+ *elt = save;
+ }
+ pop(2);
+ return 0;
+ }
+ count = op1->value.intval;
+ if (count <= 1) {
+ pop(2);
+ return 0;
+ }
+ mod = op->value.intval;
+ /*
+ * The elegant approach, requiring no extra space, would be to
+ * rotate the elements in chains separated by mod elements.
+ * Instead, we simply check to make sure there is enough space
+ * above op to do the roll in two block moves.
+ * Unfortunately, we can't count on memcpy doing the right thing
+ * in *either* direction.
+ */
+ switch (mod) {
+ case 1: /* common special case */
+ pop(2);
+ op -= 2;
+ {
+ ref top;
+
+ ref_assign_inline(&top, op);
+ for (from = op, n = count; --n; from--)
+ ref_assign_inline(from, from - 1);
+ ref_assign_inline(from, &top);
+ }
+ return 0;
+ case -1: /* common special case */
+ pop(2);
+ op -= 2;
+ {
+ ref bot;
+
+ to = op - count + 1;
+ ref_assign_inline(&bot, to);
+ for (n = count; --n; to++)
+ ref_assign(to, to + 1);
+ ref_assign_inline(to, &bot);
+ }
+ return 0;
+ }
+ if (mod < 0) {
+ mod += count;
+ if (mod < 0) {
+ mod %= count;
+ if (mod < 0)
+ mod += count; /* can't assume % means mod! */
+ }
+ } else if (mod >= count)
+ mod %= count;
+ if (mod <= count >> 1) {
+ /* Move everything up, then top elements down. */
+ if (mod >= ostop - op) {
+ o_stack.requested = mod;
+ return_error(e_stackoverflow);
+ }
+ pop(2);
+ op -= 2;
+ for (to = op + mod, from = op, n = count; n--; to--, from--)
+ ref_assign(to, from);
+ memcpy((char *)(from + 1), (char *)(op + 1), mod * sizeof(ref));
+ } else {
+ /* Move bottom elements up, then everything down. */
+ mod = count - mod;
+ if (mod >= ostop - op) {
+ o_stack.requested = mod;
+ return_error(e_stackoverflow);
+ }
+ pop(2);
+ op -= 2;
+ to = op - count + 1;
+ memcpy((char *)(op + 1), (char *)to, mod * sizeof(ref));
+ for (from = to + mod, n = count; n--; to++, from++)
+ ref_assign(to, from);
+ }
+ return 0;
+}
+
+/* |- ... clear |- */
+/* The function name is changed, because the IRIS library has */
+/* a function called zclear. */
+private int
+zclear_stack(os_ptr op)
+{
+ ref_stack_clear(&o_stack);
+ return 0;
+}
+
+/* |- <obj_n-1> ... <obj_0> count <obj_n-1> ... <obj_0> <n> */
+private int
+zcount(register os_ptr op)
+{
+ push(1);
+ make_int(op, ref_stack_count(&o_stack) - 1);
+ return 0;
+}
+
+/* - mark <mark> */
+private int
+zmark(register os_ptr op)
+{
+ push(1);
+ make_mark(op);
+ return 0;
+}
+
+/* <mark> ... cleartomark */
+int
+zcleartomark(register os_ptr op)
+{
+ uint count = ref_stack_counttomark(&o_stack);
+
+ if (count == 0)
+ return_error(e_unmatchedmark);
+ ref_stack_pop(&o_stack, count);
+ return 0;
+}
+
+/* <mark> <obj_n-1> ... <obj_0> counttomark */
+/* <mark> <obj_n-1> ... <obj_0> <n> */
+private int
+zcounttomark(os_ptr op)
+{
+ uint count = ref_stack_counttomark(&o_stack);
+
+ if (count == 0)
+ return_error(e_unmatchedmark);
+ push(1);
+ make_int(op, count - 1);
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zstack_op_defs[] =
+{
+ {"0clear", zclear_stack},
+ {"0cleartomark", zcleartomark},
+ {"0count", zcount},
+ {"0counttomark", zcounttomark},
+ {"1dup", zdup},
+ {"2exch", zexch},
+ {"2index", zindex},
+ {"0mark", zmark},
+ {"1pop", zpop},
+ {"2roll", zroll},
+ op_def_end(0)
+};
diff --git a/pstoraster/zstring.c b/pstoraster/zstring.c
new file mode 100644
index 000000000..d009465a8
--- /dev/null
+++ b/pstoraster/zstring.c
@@ -0,0 +1,172 @@
+/* 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$ */
+/* String operators */
+#include "memory_.h"
+#include "ghost.h"
+#include "gsutil.h"
+#include "ialloc.h"
+#include "iname.h"
+#include "ivmspace.h"
+#include "oper.h"
+#include "store.h"
+
+/* The generic operators (copy, get, put, getinterval, putinterval, */
+/* length, and forall) are implemented in zgeneric.c. */
+
+/* <int> string <string> */
+int
+zstring(register os_ptr op)
+{
+ byte *sbody;
+ uint size;
+
+ check_int_leu(*op, max_string_size);
+ size = op->value.intval;
+ sbody = ialloc_string(size, "string");
+ if (sbody == 0)
+ return_error(e_VMerror);
+ make_string(op, a_all | icurrent_space, size, sbody);
+ memset(sbody, 0, size);
+ return 0;
+}
+
+/* <name> .namestring <string> */
+private int
+znamestring(register os_ptr op)
+{
+ check_type(*op, t_name);
+ name_string_ref(op, op);
+ return 0;
+}
+
+/* <string> <pattern> anchorsearch <post> <match> -true- */
+/* <string> <pattern> anchorsearch <string> -false- */
+private int
+zanchorsearch(register os_ptr op)
+{
+ os_ptr op1 = op - 1;
+ uint size = r_size(op);
+
+ check_read_type(*op1, t_string);
+ check_read_type(*op, t_string);
+ if (size <= r_size(op1) && !memcmp(op1->value.bytes, op->value.bytes, size)) {
+ os_ptr op0 = op;
+
+ push(1);
+ *op0 = *op1;
+ r_set_size(op0, size);
+ op1->value.bytes += size;
+ r_dec_size(op1, size);
+ make_true(op);
+ } else
+ make_false(op);
+ return 0;
+}
+
+/* <string> <pattern> search <post> <match> <pre> -true- */
+/* <string> <pattern> search <string> -false- */
+private int
+zsearch(register os_ptr op)
+{
+ os_ptr op1 = op - 1;
+ uint size = r_size(op);
+ uint count;
+ byte *pat;
+ byte *ptr;
+ byte ch;
+
+ check_read_type(*op1, t_string);
+ check_read_type(*op, t_string);
+ if (size > r_size(op1)) { /* can't match */
+ make_false(op);
+ return 0;
+ }
+ count = r_size(op1) - size;
+ ptr = op1->value.bytes;
+ if (size == 0)
+ goto found;
+ pat = op->value.bytes;
+ ch = pat[0];
+ do {
+ if (*ptr == ch && (size == 1 || !memcmp(ptr, pat, size)))
+ goto found;
+ ptr++;
+ }
+ while (count--);
+ /* No match */
+ make_false(op);
+ return 0;
+found:
+ op->tas.type_attrs = op1->tas.type_attrs;
+ op->value.bytes = ptr;
+ r_set_size(op, size);
+ push(2);
+ op[-1] = *op1;
+ r_set_size(op - 1, ptr - op[-1].value.bytes);
+ op1->value.bytes = ptr + size;
+ r_set_size(op1, count);
+ make_true(op);
+ return 0;
+}
+
+/* <obj> <pattern> .stringmatch <bool> */
+private int
+zstringmatch(register os_ptr op)
+{
+ os_ptr op1 = op - 1;
+ bool result;
+
+ check_read_type(*op, t_string);
+ switch (r_type(op1)) {
+ case t_string:
+ check_read(*op1);
+ goto cmp;
+ case t_name:
+ name_string_ref(op1, op1); /* can't fail */
+cmp:
+ result = string_match(op1->value.const_bytes, r_size(op1),
+ op->value.const_bytes, r_size(op),
+ NULL);
+ break;
+ default:
+ result = (r_size(op) == 1 && *op->value.bytes == '*');
+ }
+ make_bool(op1, result);
+ pop(1);
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zstring_op_defs[] =
+{
+ {"2anchorsearch", zanchorsearch},
+ {"1.namestring", znamestring},
+ {"2search", zsearch},
+ {"1string", zstring},
+ {"2.stringmatch", zstringmatch},
+ op_def_end(0)
+};
diff --git a/pstoraster/zsysvm.c b/pstoraster/zsysvm.c
new file mode 100644
index 000000000..f55d14f12
--- /dev/null
+++ b/pstoraster/zsysvm.c
@@ -0,0 +1,164 @@
+/* Copyright (C) 1994, 1995 Aladdin Enterprises. All rights reserved.
+
+ This file is part of GNU Ghostscript.
+
+ GNU Ghostscript is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
+ to anyone for the consequences of using it or for whether it serves any
+ particular purpose or works at all, unless he says so in writing. Refer
+ to the GNU General Public License for full details.
+
+ Everyone is granted permission to copy, modify and redistribute GNU
+ Ghostscript, but only under the conditions described in the GNU General
+ Public License. A copy of this license is supposed to have been given
+ to you along with GNU Ghostscript so you can know your rights and
+ responsibilities. It should be in a file named COPYING. Among other
+ things, the copyright notice and this notice must be preserved on all
+ copies.
+
+ Aladdin Enterprises 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$ */
+/* System VM and VM-specific operators */
+#include "ghost.h"
+#include "oper.h"
+#include "ialloc.h"
+#include "ivmspace.h"
+#include "store.h" /* for make_bool */
+
+/*
+ * These operators allow creation of objects in a specific VM --
+ * local, global, or system. System VM, which is not a standard PostScript
+ * facility, is not subject to save and restore; objects in system VM
+ * may only refer to simple objects or to other (composite) objects
+ * in system VM.
+ */
+
+/* Execute an operator with a specific VM selected as current VM. */
+private int
+specific_vm_op(os_ptr op, int (*opproc)(P1(os_ptr)), uint space)
+{
+ uint save_space = icurrent_space;
+ int code;
+
+ ialloc_set_space(idmemory, space);
+ code = (*opproc)(op);
+ ialloc_set_space(idmemory, save_space);
+ return code;
+}
+
+/* <int> .globalvmarray <array> */
+private int
+zglobalvmarray(os_ptr op)
+{
+ return specific_vm_op(op, zarray, avm_global);
+}
+
+/* <int> .globalvmdict <dict> */
+private int
+zglobalvmdict(os_ptr op)
+{
+ return specific_vm_op(op, zdict, avm_global);
+}
+
+/* <obj_0> ... <obj_n-1> <n> .globalvmpackedarray <packedarray> */
+private int
+zglobalvmpackedarray(os_ptr op)
+{
+ return specific_vm_op(op, zpackedarray, avm_global);
+}
+
+/* <int> .globalvmstring <string> */
+private int
+zglobalvmstring(os_ptr op)
+{
+ return specific_vm_op(op, zstring, avm_global);
+}
+
+/* <int> .localvmarray <array> */
+private int
+zlocalvmarray(os_ptr op)
+{
+ return specific_vm_op(op, zarray, avm_local);
+}
+
+/* <int> .localvmdict <dict> */
+private int
+zlocalvmdict(os_ptr op)
+{
+ return specific_vm_op(op, zdict, avm_local);
+}
+
+/* <obj_0> ... <obj_n-1> <n> .localvmpackedarray <packedarray> */
+private int
+zlocalvmpackedarray(os_ptr op)
+{
+ return specific_vm_op(op, zpackedarray, avm_local);
+}
+
+/* <int> .localvmstring <string> */
+private int
+zlocalvmstring(os_ptr op)
+{
+ return specific_vm_op(op, zstring, avm_local);
+}
+
+/* <int> .systemvmarray <array> */
+private int
+zsystemvmarray(os_ptr op)
+{
+ return specific_vm_op(op, zarray, avm_system);
+}
+
+/* <int> .systemvmdict <dict> */
+private int
+zsystemvmdict(os_ptr op)
+{
+ return specific_vm_op(op, zdict, avm_system);
+}
+
+/* <obj_0> ... <obj_n-1> <n> .systemvmpackedarray <packedarray> */
+private int
+zsystemvmpackedarray(os_ptr op)
+{
+ return specific_vm_op(op, zpackedarray, avm_system);
+}
+
+/* <int> .systemvmstring <string> */
+private int
+zsystemvmstring(os_ptr op)
+{
+ return specific_vm_op(op, zstring, avm_system);
+}
+
+/* <any> .systemvmcheck <bool> */
+private int
+zsystemvmcheck(register os_ptr op)
+{
+ make_bool(op, (r_space(op) == avm_system ? true : false));
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zsysvm_op_defs[] =
+{
+ {"1.globalvmarray", zglobalvmarray},
+ {"1.globalvmdict", zglobalvmdict},
+ {"1.globalvmpackedarray", zglobalvmpackedarray},
+ {"1.globalvmstring", zglobalvmstring},
+ {"1.localvmarray", zlocalvmarray},
+ {"1.localvmdict", zlocalvmdict},
+ {"1.localvmpackedarray", zlocalvmpackedarray},
+ {"1.localvmstring", zlocalvmstring},
+ {"1.systemvmarray", zsystemvmarray},
+ {"1.systemvmcheck", zsystemvmcheck},
+ {"1.systemvmdict", zsystemvmdict},
+ {"1.systemvmpackedarray", zsystemvmpackedarray},
+ {"1.systemvmstring", zsystemvmstring},
+ op_def_end(0)
+};
diff --git a/pstoraster/ztoken.c b/pstoraster/ztoken.c
new file mode 100644
index 000000000..fe01e18ef
--- /dev/null
+++ b/pstoraster/ztoken.c
@@ -0,0 +1,241 @@
+/* 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$ */
+/* Token reading operators */
+#include "ghost.h"
+#include "oper.h"
+#include "estack.h"
+#include "gsstruct.h" /* for iscan.h */
+#include "stream.h"
+#include "files.h"
+#include "store.h"
+#include "strimpl.h" /* for sfilter.h */
+#include "sfilter.h" /* for iscan.h */
+#include "iscan.h"
+
+/* <file> token <obj> -true- */
+/* <string> token <post> <obj> -true- */
+/* <string|file> token -false- */
+private int ztoken_continue(P1(os_ptr));
+private int token_continue(P4(os_ptr, stream *, scanner_state *, bool));
+int
+ztoken(register os_ptr op)
+{
+ switch (r_type(op)) {
+ default:
+ return_op_typecheck(op);
+ case t_file: {
+ stream *s;
+ scanner_state state;
+
+ check_read_file(s, op);
+ check_ostack(1);
+ scanner_state_init(&state, false);
+ return token_continue(op, s, &state, true);
+ }
+ case t_string: {
+ ref token;
+ int code = scan_string_token(op, &token);
+
+ switch (code) {
+ case scan_EOF: /* no tokens */
+ make_false(op);
+ return 0;
+ default:
+ if (code < 0)
+ return code;
+ }
+ push(2);
+ op[-1] = token;
+ make_true(op);
+ return 0;
+ }
+ }
+}
+/* Continue reading a token after an interrupt or callout. */
+/* *op is the scanner state; op[-1] is the file. */
+private int
+ztoken_continue(os_ptr op)
+{
+ stream *s;
+ scanner_state *pstate;
+
+ check_read_file(s, op - 1);
+ check_stype(*op, st_scanner_state);
+ pstate = r_ptr(op, scanner_state);
+ pop(1);
+ return token_continue(osp, s, pstate, false);
+}
+/* Common code for token reading. */
+private int
+token_continue(os_ptr op, stream * s, scanner_state * pstate, bool save)
+{
+ int code;
+ ref token;
+
+ /* Note that scan_token may change osp! */
+ /* Also, we must temporarily remove the file from the o-stack */
+ /* when calling scan_token, in case we are scanning a procedure. */
+ ref fref;
+
+ ref_assign(&fref, op);
+again:
+ pop(1);
+ code = scan_token(s, &token, pstate);
+ op = osp;
+ switch (code) {
+ default: /* error */
+ push(1);
+ ref_assign(op, &fref);
+ break;
+ case scan_BOS:
+ code = 0;
+ case 0: /* read a token */
+ push(2);
+ ref_assign(op - 1, &token);
+ make_true(op);
+ break;
+ case scan_EOF: /* no tokens */
+ push(1);
+ make_false(op);
+ code = 0;
+ break;
+ case scan_Refill: /* need more data */
+ push(1);
+ ref_assign(op, &fref);
+ code = scan_handle_refill(op, pstate, save, false,
+ ztoken_continue);
+ switch (code) {
+ case 0: /* state is not copied to the heap */
+ goto again;
+ case o_push_estack:
+ return code;
+ }
+ break; /* error */
+ }
+ if (code <= 0 && !save) { /* Deallocate the scanner state record. */
+ ifree_object(pstate, "token_continue");
+ }
+ return code;
+}
+
+/* <file> .tokenexec - */
+/* Read a token and do what the interpreter would do with it. */
+/* This is different from token + exec because literal procedures */
+/* are not executed (although binary object sequences ARE executed). */
+int ztokenexec_continue(P1(os_ptr)); /* export for interpreter */
+private int tokenexec_continue(P4(os_ptr, stream *, scanner_state *, bool));
+int
+ztokenexec(register os_ptr op)
+{
+ stream *s;
+ scanner_state state;
+
+ check_read_file(s, op);
+ check_estack(1);
+ scanner_state_init(&state, false);
+ return tokenexec_continue(op, s, &state, true);
+}
+/* Continue reading a token for execution after an interrupt or callout. */
+/* *op is the scanner state; op[-1] is the file. */
+/* We export this because this is how the interpreter handles a */
+/* scan_Refill for an executable file. */
+int
+ztokenexec_continue(os_ptr op)
+{
+ stream *s;
+ scanner_state *pstate;
+
+ check_read_file(s, op - 1);
+ check_stype(*op, st_scanner_state);
+ pstate = r_ptr(op, scanner_state);
+ pop(1);
+ return tokenexec_continue(osp, s, pstate, false);
+}
+/* Common code for token reading + execution. */
+private int
+tokenexec_continue(os_ptr op, stream * s, scanner_state * pstate, bool save)
+{
+ int code;
+
+ /* Note that scan_token may change osp! */
+ /* Also, we must temporarily remove the file from the o-stack */
+ /* when calling scan_token, in case we are scanning a procedure. */
+ ref fref;
+
+ ref_assign(&fref, op);
+ pop(1);
+again:
+ code = scan_token(s, (ref *) (esp + 1), pstate);
+ op = osp;
+ switch (code) {
+ case 0:
+ if (r_is_proc(esp + 1)) { /* Treat procedure as a literal. */
+ push(1);
+ ref_assign(op, esp + 1);
+ code = 0;
+ break;
+ }
+ /* falls through */
+ case scan_BOS:
+ ++esp;
+ code = o_push_estack;
+ break;
+ case scan_EOF: /* no tokens */
+ code = 0;
+ break;
+ case scan_Refill: /* need more data */
+ code = scan_handle_refill(&fref, pstate, save, true,
+ ztokenexec_continue);
+ switch (code) {
+ case 0: /* state is not copied to the heap */
+ goto again;
+ case o_push_estack:
+ return code;
+ }
+ /* falls through */
+ default: /* error */
+ break;
+ }
+ if (code < 0) { /* Push the operand back on the stack. */
+ push(1);
+ ref_assign(op, &fref);
+ }
+ if (!save) { /* Deallocate the scanner state record. */
+ ifree_object(pstate, "token_continue");
+ }
+ return code;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def ztoken_op_defs[] =
+{
+ {"1token", ztoken},
+ {"1.tokenexec", ztokenexec},
+ /* Internal operators */
+ {"2%ztokenexec_continue", ztokenexec_continue},
+ op_def_end(0)
+};
diff --git a/pstoraster/ztrap.c b/pstoraster/ztrap.c
new file mode 100644
index 000000000..8cb77447e
--- /dev/null
+++ b/pstoraster/ztrap.c
@@ -0,0 +1,72 @@
+/* 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$ */
+/* Operators for setting trapping parameters and zones */
+#include "ghost.h"
+#include "oper.h"
+#include "ialloc.h"
+#include "iparam.h"
+#include "gstrap.h"
+
+/* Define the current trap parameters. */
+/****** THIS IS BOGUS ******/
+gs_trap_params_t i_trap_params;
+
+/* <dict> .settrapparams - */
+private int
+zsettrapparams(os_ptr op)
+{
+ dict_param_list list;
+ int code;
+
+ check_type(*op, t_dictionary);
+ code = dict_param_list_read(&list, op, NULL, false);
+ if (code < 0)
+ return code;
+ code = gs_settrapparams(&i_trap_params, (gs_param_list *) & list);
+ iparam_list_release(&list);
+ if (code < 0)
+ return code;
+ pop(1);
+ return 0;
+}
+
+/* - settrapzone - */
+private int
+zsettrapzone(os_ptr op)
+{
+/****** NYI ******/
+ return_error(e_undefined);
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def ztrap_op_defs[] =
+{
+ op_def_begin_ll3(),
+ {"1.settrapparams", zsettrapparams},
+ {"0settrapzone", zsettrapzone},
+ op_def_end(0)
+};
diff --git a/pstoraster/ztype.c b/pstoraster/ztype.c
new file mode 100644
index 000000000..716daee0f
--- /dev/null
+++ b/pstoraster/ztype.c
@@ -0,0 +1,510 @@
+/* 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$ */
+/* Type, attribute, and conversion operators */
+#include "math_.h"
+#include "memory_.h"
+#include "string_.h"
+#include "gsexit.h"
+#include "ghost.h"
+#include "oper.h"
+#include "imemory.h" /* for register_ref_root */
+#include "idict.h"
+#include "iname.h"
+#include "stream.h" /* for iscan.h */
+#include "strimpl.h" /* for sfilter.h for picky compilers */
+#include "sfilter.h" /* ditto */
+#include "iscan.h"
+#include "iutil.h"
+#include "dstack.h" /* for dict_set_top */
+#include "store.h"
+
+/* Forward references */
+private int access_check(P3(os_ptr, int, bool));
+private int convert_to_string(P2(os_ptr, os_ptr));
+
+/*
+ * Max and min integer values expressed as reals.
+ * Note that these are biased by 1 to allow for truncation.
+ * They should be #defines rather than static consts, but
+ * several of the SCO Unix compilers apparently can't handle this.
+ * On the other hand, the DEC compiler can't handle casts in
+ * constant expressions, so we can't use min_long and max_long.
+ * What a nuisance!
+ */
+#define ALT_MIN_LONG (-1L << (arch_sizeof_long * 8 - 1))
+#define ALT_MAX_LONG (~(ALT_MIN_LONG))
+private const double min_int_real = (ALT_MIN_LONG * 1.0 - 1);
+private const double max_int_real = (ALT_MAX_LONG * 1.0 + 1);
+
+#define REAL_CAN_BE_INT(v)\
+ ((v) > min_int_real && (v) < max_int_real)
+
+/* Get the pointer to the access flags for a ref. */
+#define ACCESS_REF(opp)\
+ (r_has_type(opp, t_dictionary) ? dict_access_ref(opp) : opp)
+
+/* Initialize the table of type names. */
+private void
+ztype_init(void)
+{
+ static const char *const tnames[] = { type_name_strings };
+ ref type_names;
+ int i;
+
+ ialloc_ref_array(&type_names, a_readonly, t_next_index,
+ "type names");
+ for (i = 0; i < t_next_index; i++) {
+ if (i >= countof(tnames) || tnames[i] == 0)
+ make_null(&type_names.value.refs[i]);
+ else {
+ name_enter_string(tnames[i], &type_names.value.refs[i]);
+ r_set_attrs(&type_names.value.refs[i], a_executable);
+ }
+ }
+ if (dict_put_string(systemdict, "typenames", &type_names) < 0) {
+ lprintf("Entering typenames in systemdict failed.\n");
+ gs_exit(1);
+ }
+}
+
+/* <obj> <typenames> .type <name> */
+private int
+ztype(register os_ptr op)
+{
+ ref tnref;
+ int code = array_get(op, (long)r_btype(op - 1), &tnref);
+
+ if (code < 0)
+ return code;
+ if (!r_has_type(&tnref, t_name)) {
+ /* Must be either a stack underflow or a t_[a]struct. */
+ check_op(2);
+ { /* Get the type name from the structure. */
+ const char *sname =
+ gs_struct_type_name_string(gs_object_type(imemory,
+ op[-1].value.pstruct));
+ int code = name_ref((const byte *)sname, strlen(sname),
+ (ref *) (op - 1), 0);
+
+ if (code < 0)
+ return code;
+ }
+ r_set_attrs(op - 1, a_executable);
+ } else {
+ ref_assign(op - 1, &tnref);
+ }
+ pop(1);
+ return 0;
+}
+
+/* <obj> cvlit <obj> */
+private int
+zcvlit(register os_ptr op)
+{
+ ref *aop;
+
+ check_op(1);
+ aop = ACCESS_REF(op);
+ r_clear_attrs(aop, a_executable);
+ return 0;
+}
+
+/* <obj> cvx <obj> */
+int
+zcvx(register os_ptr op)
+{
+ ref *aop;
+ uint opidx;
+
+ check_op(1);
+ /*
+ * If the object is an internal operator, we can't allow it to
+ * exist in executable form anywhere outside the e-stack.
+ */
+ if (r_has_type(op, t_operator) &&
+ ((opidx = op_index(op)) == 0 ||
+ op_def_is_internal(op_def_table[opidx]))
+ )
+ return_error(e_rangecheck);
+ aop = ACCESS_REF(op);
+ r_set_attrs(aop, a_executable);
+ return 0;
+}
+
+/* <obj> xcheck <bool> */
+private int
+zxcheck(register os_ptr op)
+{
+ check_op(1);
+ make_bool(op, (r_has_attr(ACCESS_REF(op), a_executable) ? 1 : 0));
+ return 0;
+}
+
+/* <obj:array|packedarray|file|string> executeonly <obj> */
+private int
+zexecuteonly(register os_ptr op)
+{
+ check_op(1);
+ if (r_has_type(op, t_dictionary))
+ return_error(e_typecheck);
+ return access_check(op, a_execute, true);
+}
+
+/* <obj:array|packedarray|dict|file|string> noaccess <obj> */
+private int
+znoaccess(register os_ptr op)
+{
+ check_op(1);
+ if (r_has_type(op, t_dictionary)) {
+ /*
+ * Setting noaccess on a read-only dictionary is an attempt to
+ * change its value, which is forbidden (this is a subtle
+ * point confirmed with Adobe). Also, don't allow removing
+ * read access to permanent dictionaries.
+ */
+ if (dict_is_permanent_on_dstack(op) ||
+ !r_has_attr(dict_access_ref(op), a_write)
+ )
+ return_error(e_invalidaccess);
+ }
+ return access_check(op, 0, true);
+}
+
+/* <obj:array|packedarray|dict|file|string> readonly <obj> */
+int
+zreadonly(register os_ptr op)
+{
+ return access_check(op, a_readonly, true);
+}
+
+/* <array|packedarray|dict|file|string> rcheck <bool> */
+private int
+zrcheck(register os_ptr op)
+{
+ int code = access_check(op, a_read, false);
+
+ if (code >= 0)
+ make_bool(op, code), code = 0;
+ return code;
+}
+
+/* <array|packedarray|dict|file|string> wcheck <bool> */
+private int
+zwcheck(register os_ptr op)
+{
+ int code = access_check(op, a_write, false);
+
+ if (code >= 0)
+ make_bool(op, code), code = 0;
+ return code;
+}
+
+/* <num> cvi <int> */
+/* <string> cvi <int> */
+private int
+zcvi(register os_ptr op)
+{
+ float fval;
+
+ switch (r_type(op)) {
+ case t_integer:
+ return 0;
+ case t_real:
+ fval = op->value.realval;
+ break;
+ default:
+ return_op_typecheck(op);
+ case t_string:
+ {
+ ref str, token;
+ int code;
+
+ ref_assign(&str, op);
+ code = scan_string_token(&str, &token);
+ switch (code) {
+ case scan_EOF: /* no tokens */
+ case scan_BOS: /* not allowed */
+ code = gs_note_error(e_syntaxerror);
+ default:
+ if (code < 0)
+ return code;
+ }
+ switch (r_type(&token)) {
+ case t_integer:
+ *op = token;
+ return 0;
+ case t_real:
+ fval = token.value.realval;
+ break;
+ default:
+ return_error(e_typecheck);
+ }
+ }
+ }
+ if (!REAL_CAN_BE_INT(fval))
+ return_error(e_rangecheck);
+ make_int(op, (long)fval); /* truncates towards 0 */
+ return 0;
+}
+
+/* <string> cvn <name> */
+private int
+zcvn(register os_ptr op)
+{
+ check_read_type(*op, t_string);
+ return name_from_string(op, op);
+}
+
+/* <num> cvr <real> */
+/* <string> cvr <real> */
+private int
+zcvr(register os_ptr op)
+{
+ switch (r_type(op)) {
+ case t_integer:
+ make_real(op, op->value.intval);
+ case t_real:
+ return 0;
+ default:
+ return_op_typecheck(op);
+ case t_string:
+ {
+ ref str, token;
+ int code;
+
+ ref_assign(&str, op);
+ code = scan_string_token(&str, &token);
+ switch (code) {
+ case scan_EOF: /* no tokens */
+ case scan_BOS: /* not allowed */
+ code = gs_note_error(e_syntaxerror);
+ default:
+ if (code < 0)
+ return code;
+ }
+ switch (r_type(&token)) {
+ case t_integer:
+ make_real(op, token.value.intval);
+ return 0;
+ case t_real:
+ *op = token;
+ return 0;
+ default:
+ return_error(e_typecheck);
+ }
+ }
+ }
+}
+
+/* <num> <radix_int> <string> cvrs <substring> */
+private int
+zcvrs(register os_ptr op)
+{
+ int radix;
+
+ check_type(op[-1], t_integer);
+ if (op[-1].value.intval < 2 || op[-1].value.intval > 36)
+ return_error(e_rangecheck);
+ radix = op[-1].value.intval;
+ check_write_type(*op, t_string);
+ if (radix == 10) {
+ switch (r_type(op - 2)) {
+ case t_integer:
+ case t_real:
+ {
+ int code = convert_to_string(op - 2, op);
+
+ if (code < 0)
+ return code;
+ pop(2);
+ return 0;
+ }
+ default:
+ return_op_typecheck(op - 2);
+ }
+ } else {
+ ulong ival;
+ byte digits[sizeof(ulong) * 8];
+ byte *endp = &digits[countof(digits)];
+ byte *dp = endp;
+
+ switch (r_type(op - 2)) {
+ case t_integer:
+ ival = (ulong) op[-2].value.intval;
+ break;
+ case t_real:
+ {
+ float fval = op[-2].value.realval;
+
+ if (!REAL_CAN_BE_INT(fval))
+ return_error(e_rangecheck);
+ ival = (ulong) (long)fval;
+ } break;
+ default:
+ return_op_typecheck(op - 2);
+ }
+ do {
+ int dit = ival % radix;
+
+ *--dp = dit + (dit < 10 ? '0' : ('A' - 10));
+ ival /= radix;
+ }
+ while (ival);
+ if (endp - dp > r_size(op))
+ return_error(e_rangecheck);
+ memcpy(op->value.bytes, dp, (uint) (endp - dp));
+ r_set_size(op, endp - dp);
+ }
+ op[-2] = *op;
+ pop(2);
+ return 0;
+}
+
+/* <any> <string> cvs <substring> */
+private int
+zcvs(register os_ptr op)
+{
+ int code;
+
+ check_op(2);
+ check_write_type(*op, t_string);
+ code = convert_to_string(op - 1, op);
+ if (code >= 0)
+ pop(1);
+ return code;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def ztype_op_defs[] =
+{
+ {"1cvi", zcvi},
+ {"1cvlit", zcvlit},
+ {"1cvn", zcvn},
+ {"1cvr", zcvr},
+ {"3cvrs", zcvrs},
+ {"2cvs", zcvs},
+ {"1cvx", zcvx},
+ {"1executeonly", zexecuteonly},
+ {"1noaccess", znoaccess},
+ {"1rcheck", zrcheck},
+ {"1readonly", zreadonly},
+ {"2.type", ztype},
+ {"1wcheck", zwcheck},
+ {"1xcheck", zxcheck},
+ op_def_end(ztype_init)
+};
+
+/* ------ Internal routines ------ */
+
+/* Test or modify the access of an object. */
+/* If modify = true, restrict to the selected access and return 0; */
+/* if modify = false, do not change the access, and return 1 */
+/* if the object had the access. */
+/* Return an error code if the object is not of appropriate type, */
+/* or if the object did not have the access already when modify=1. */
+private int
+access_check(os_ptr op,
+ int access, /* mask for attrs */
+ bool modify) /* if true, reduce access */
+{
+ ref *aop;
+
+ switch (r_type(op)) {
+ case t_dictionary:
+ aop = dict_access_ref(op);
+ if (modify) {
+ if (!r_has_attrs(aop, access))
+ return_error(e_invalidaccess);
+ ref_save(op, aop, "access_check(modify)");
+ r_clear_attrs(aop, a_all);
+ r_set_attrs(aop, access);
+ dict_set_top();
+ return 0;
+ }
+ break;
+ case t_array:
+ case t_file:
+ case t_string:
+ case t_mixedarray:
+ case t_shortarray:
+ case t_astruct:
+ case t_device:;
+ if (modify) {
+ if (!r_has_attrs(op, access))
+ return_error(e_invalidaccess);
+ r_clear_attrs(op, a_all);
+ r_set_attrs(op, access);
+ return 0;
+ }
+ aop = op;
+ break;
+ default:
+ return_op_typecheck(op);
+ }
+ return (r_has_attrs(aop, access) ? 1 : 0);
+}
+
+/* Do all the work of cvs. The destination has been checked, but not */
+/* the source. This is a separate procedure so that */
+/* cvrs can use it when the radix is 10. */
+private int
+convert_to_string(os_ptr op1, os_ptr op)
+{
+ uint len;
+ const byte *pstr = 0;
+ int code = obj_cvs(op1, op->value.bytes, r_size(op), &len, &pstr);
+
+ if (code < 0) {
+ /*
+ * Some common downloaded error handlers assume that
+ * operator names don't exceed a certain fixed size.
+ * To work around this bit of bad design, we implement
+ * a special hack here: if we got a rangecheck, and
+ * the object is an operator whose name begins with
+ * %, ., or @, we just truncate the name.
+ */
+ if (code == e_rangecheck)
+ switch (r_btype(op1)) {
+ case t_oparray:
+ case t_operator:
+ if (pstr != 0)
+ switch (*pstr) {
+ case '%':
+ case '.':
+ case '@':
+ len = r_size(op);
+ memcpy(op->value.bytes, pstr, len);
+ goto ok;
+ }
+ }
+ return code;
+ }
+ok:
+ *op1 = *op;
+ r_set_size(op1, len);
+ return 0;
+}
diff --git a/pstoraster/zupath.c b/pstoraster/zupath.c
new file mode 100644
index 000000000..e05fe6dd3
--- /dev/null
+++ b/pstoraster/zupath.c
@@ -0,0 +1,673 @@
+/* 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$ */
+/* Operators related to user paths */
+#include "ghost.h"
+#include "oper.h"
+#include "idict.h"
+#include "dstack.h"
+#include "igstate.h"
+#include "iname.h"
+#include "iutil.h"
+#include "store.h"
+#include "stream.h"
+#include "ibnum.h"
+#include "gsmatrix.h"
+#include "gsstate.h"
+#include "gscoord.h"
+#include "gspaint.h"
+#include "gxfixed.h"
+#include "gxdevice.h"
+#include "gspath.h"
+#include "gzpath.h" /* for saving path */
+#include "gzstate.h" /* for accessing path */
+
+/* Imported data */
+extern const gx_device gs_hit_device;
+extern const int gs_hit_detected;
+
+/* Forward references */
+private int upath_append(P2(os_ptr, os_ptr));
+private int upath_stroke(P2(os_ptr, gs_matrix *));
+
+/* ---------------- Insideness testing ---------------- */
+
+/* Forward references */
+private int in_test(P2(os_ptr, int (*)(P1(gs_state *))));
+private int in_path(P3(os_ptr, os_ptr, gx_device *));
+private int in_path_result(P3(os_ptr, int, int));
+private int in_utest(P2(os_ptr, int (*)(P1(gs_state *))));
+private int in_upath(P2(os_ptr, gx_device *));
+private int in_upath_result(P3(os_ptr, int, int));
+
+/* <x> <y> ineofill <bool> */
+/* <userpath> ineofill <bool> */
+private int
+zineofill(os_ptr op)
+{
+ return in_test(op, gs_eofill);
+}
+
+/* <x> <y> infill <bool> */
+/* <userpath> infill <bool> */
+private int
+zinfill(os_ptr op)
+{
+ return in_test(op, gs_fill);
+}
+
+/* <x> <y> instroke <bool> */
+/* <userpath> instroke <bool> */
+private int
+zinstroke(os_ptr op)
+{
+ return in_test(op, gs_stroke);
+}
+
+/* <x> <y> <userpath> inueofill <bool> */
+/* <userpath1> <userpath2> inueofill <bool> */
+private int
+zinueofill(os_ptr op)
+{
+ return in_utest(op, gs_eofill);
+}
+
+/* <x> <y> <userpath> inufill <bool> */
+/* <userpath1> <userpath2> inufill <bool> */
+private int
+zinufill(os_ptr op)
+{
+ return in_utest(op, gs_fill);
+}
+
+/* <x> <y> <userpath> inustroke <bool> */
+/* <x> <y> <userpath> <matrix> inustroke <bool> */
+/* <userpath1> <userpath2> inustroke <bool> */
+/* <userpath1> <userpath2> <matrix> inustroke <bool> */
+private int
+zinustroke(os_ptr op)
+{ /* This is different because of the optional matrix operand. */
+ int code = gs_gsave(igs);
+ int spop, npop;
+ gs_matrix mat;
+ gx_device hdev;
+
+ if (code < 0)
+ return code;
+ if ((spop = upath_stroke(op, &mat)) < 0) {
+ gs_grestore(igs);
+ return spop;
+ }
+ if ((npop = in_path(op - spop, op, &hdev)) < 0) {
+ gs_grestore(igs);
+ return npop;
+ }
+ if (npop > 1) /* matrix was supplied */
+ code = gs_concat(igs, &mat);
+ if (code >= 0)
+ code = gs_stroke(igs);
+ return in_upath_result(op, npop + spop, code);
+}
+
+/* ------ Internal routines ------ */
+
+/* Do the work of the non-user-path insideness operators. */
+private int
+in_test(os_ptr op, int (*paintproc)(P1(gs_state *)))
+{
+ gx_device hdev;
+ int npop = in_path(op, op, &hdev);
+ int code;
+
+ if (npop < 0)
+ return npop;
+ code = (*paintproc)(igs);
+ return in_path_result(op, npop, code);
+}
+
+/* Set up a clipping path and device for insideness testing. */
+private int
+in_path(os_ptr oppath, os_ptr op, gx_device * phdev)
+{
+ int code = gs_gsave(igs);
+ int npop;
+ double uxy[2];
+
+ if (code < 0)
+ return code;
+ code = num_params(oppath, 2, uxy);
+ if (code >= 0) { /* Aperture is a single pixel. */
+ gs_point dxy;
+ gs_fixed_rect fr;
+
+ gs_transform(igs, uxy[0], uxy[1], &dxy);
+ fr.p.x = fixed_floor(float2fixed(dxy.x));
+ fr.p.y = fixed_floor(float2fixed(dxy.y));
+ fr.q.x = fr.p.x + fixed_1;
+ fr.q.y = fr.p.y + fixed_1;
+ code = gx_clip_to_rectangle(igs, &fr);
+ npop = 2;
+ } else { /* Aperture is a user path. */
+ /* We have to set the clipping path without disturbing */
+ /* the current path. */
+ gx_path *ipath = igs->path;
+ gx_path save;
+
+ gx_path_init_local(&save, imemory);
+ gx_path_assign_preserve(&save, ipath);
+ gs_newpath(igs);
+ code = upath_append(oppath, op);
+ if (code >= 0)
+ code = gx_clip_to_path(igs);
+ gx_path_assign_free(igs->path, &save);
+ npop = 1;
+ }
+ if (code < 0) {
+ gs_grestore(igs);
+ return code;
+ }
+ /* Install the hit detection device. */
+ gx_set_device_color_1(igs);
+ gx_device_init((gx_device *) phdev, (const gx_device *)&gs_hit_device,
+ NULL, true);
+ phdev->width = phdev->height = max_int;
+ gx_device_fill_in_procs(phdev);
+ gx_set_device_only(igs, phdev);
+ return npop;
+}
+
+/* Finish an insideness test. */
+private int
+in_path_result(os_ptr op, int npop, int code)
+{
+ bool result;
+
+ gs_grestore(igs); /* matches gsave in in_path */
+ if (code == gs_hit_detected)
+ result = true;
+ else if (code == 0) /* completed painting without a hit */
+ result = false;
+ else /* error */
+ return code;
+ npop--;
+ pop(npop);
+ op -= npop;
+ make_bool(op, result);
+ return 0;
+
+}
+
+/* Do the work of the user-path insideness operators. */
+private int
+in_utest(os_ptr op, int (*paintproc)(P1(gs_state *)))
+{
+ gx_device hdev;
+ int npop = in_upath(op, &hdev);
+ int code;
+
+ if (npop < 0)
+ return npop;
+ code = (*paintproc)(igs);
+ return in_upath_result(op, npop, code);
+}
+
+/* Set up a clipping path and device for insideness testing */
+/* with a user path. */
+private int
+in_upath(os_ptr op, gx_device * phdev)
+{
+ int code = gs_gsave(igs);
+ int npop;
+
+ if (code < 0)
+ return code;
+ if ((code = upath_append(op, op)) < 0 ||
+ (npop = in_path(op - 1, op, phdev)) < 0
+ ) {
+ gs_grestore(igs);
+ return code;
+ }
+ return npop + 1;
+}
+
+/* Finish an insideness test with a user path. */
+private int
+in_upath_result(os_ptr op, int npop, int code)
+{
+ gs_grestore(igs); /* matches gsave in in_upath */
+ return in_path_result(op, npop, code);
+}
+
+/* ---------------- User paths ---------------- */
+
+/* User path operator codes */
+typedef enum {
+ upath_op_setbbox = 0,
+ upath_op_moveto = 1,
+ upath_op_rmoveto = 2,
+ upath_op_lineto = 3,
+ upath_op_rlineto = 4,
+ upath_op_curveto = 5,
+ upath_op_rcurveto = 6,
+ upath_op_arc = 7,
+ upath_op_arcn = 8,
+ upath_op_arct = 9,
+ upath_op_closepath = 10,
+ upath_op_ucache = 11
+} upath_op;
+
+#define UPATH_MAX_OP 11
+#define UPATH_REPEAT 32
+static const byte up_nargs[UPATH_MAX_OP + 1] = {
+ 4, 2, 2, 2, 2, 6, 6, 5, 5, 5, 0, 0
+};
+
+/* Declare operator procedures not declared in opextern.h. */
+int zsetbbox(P1(os_ptr));
+int zarc(P1(os_ptr));
+int zarcn(P1(os_ptr));
+int zarct(P1(os_ptr));
+private int zucache(P1(os_ptr));
+
+#undef zp
+static const op_proc_p up_ops[UPATH_MAX_OP + 1] = {
+ zsetbbox, zmoveto, zrmoveto, zlineto, zrlineto,
+ zcurveto, zrcurveto, zarc, zarcn, zarct,
+ zclosepath, zucache
+};
+
+/* - ucache - */
+private int
+zucache(os_ptr op)
+{ /* A no-op for now. */
+ return 0;
+}
+
+/* <userpath> uappend - */
+private int
+zuappend(register os_ptr op)
+{
+ int code = gs_gsave(igs);
+
+ if (code < 0)
+ return code;
+ if ((code = upath_append(op, op)) >= 0)
+ code = gs_upmergepath(igs);
+ gs_grestore(igs);
+ if (code < 0)
+ return code;
+ pop(1);
+ return 0;
+}
+
+/* <userpath> ueofill - */
+private int
+zueofill(register os_ptr op)
+{
+ int code = gs_gsave(igs);
+
+ if (code < 0)
+ return code;
+ if ((code = upath_append(op, op)) >= 0)
+ code = gs_eofill(igs);
+ gs_grestore(igs);
+ if (code < 0)
+ return code;
+ pop(1);
+ return 0;
+}
+
+/* <userpath> ufill - */
+private int
+zufill(register os_ptr op)
+{
+ int code = gs_gsave(igs);
+
+ if (code < 0)
+ return code;
+ if ((code = upath_append(op, op)) >= 0)
+ code = gs_fill(igs);
+ gs_grestore(igs);
+ if (code < 0)
+ return code;
+ pop(1);
+ return 0;
+}
+
+/* <userpath> ustroke - */
+/* <userpath> <matrix> ustroke - */
+private int
+zustroke(register os_ptr op)
+{
+ int code = gs_gsave(igs);
+ int npop;
+
+ if (code < 0)
+ return code;
+ if ((code = npop = upath_stroke(op, NULL)) >= 0)
+ code = gs_stroke(igs);
+ gs_grestore(igs);
+ if (code < 0)
+ return code;
+ pop(npop);
+ return 0;
+}
+
+/* <userpath> ustrokepath - */
+/* <userpath> <matrix> ustrokepath - */
+private int
+zustrokepath(register os_ptr op)
+{
+ gx_path save;
+ int code, npop;
+
+ /* Save and reset the path. */
+ gx_path_init_local(&save, imemory);
+ gx_path_assign_preserve(&save, igs->path);
+ if ((code = npop = upath_stroke(op, NULL)) < 0 ||
+ (code = gs_strokepath(igs)) < 0
+ ) {
+ gx_path_assign_free(igs->path, &save);
+ return code;
+ }
+ gx_path_free(&save, "ustrokepath");
+ pop(npop);
+ return 0;
+}
+
+/* <with_ucache> upath <userpath> */
+/* We do all the work in a procedure that is also used to construct */
+/* the UnpaintedPath user path for ImageType 2 images. */
+int make_upath(P4(ref * rupath, gs_state * pgs, gx_path * ppath,
+ bool with_ucache));
+private int
+zupath(register os_ptr op)
+{
+ check_type(*op, t_boolean);
+ return make_upath(op, igs, igs->path, op->value.boolval);
+}
+int
+make_upath(ref * rupath, gs_state * pgs, gx_path * ppath, bool with_ucache)
+{
+ int size = (with_ucache ? 6 : 5);
+ gs_path_enum penum;
+ int op;
+ ref *next;
+ int code;
+
+ /* Compute the size of the user path array. */
+ {
+ gs_fixed_point pts[3];
+
+ gx_path_enum_init(&penum, ppath);
+ while ((op = gx_path_enum_next(&penum, pts)) != 0) {
+ switch (op) {
+ case gs_pe_moveto:
+ case gs_pe_lineto:
+ size += 3;
+ continue;
+ case gs_pe_curveto:
+ size += 7;
+ continue;
+ case gs_pe_closepath:
+ size += 1;
+ continue;
+ default:
+ return_error(e_unregistered);
+ }
+ }
+ }
+ code = ialloc_ref_array(rupath, a_all | a_executable, size,
+ "make_upath");
+ if (code < 0)
+ return code;
+ /* Construct the path. */
+ next = rupath->value.refs;
+ if (with_ucache) {
+ if ((code = name_enter_string("ucache", next)) < 0)
+ return code;
+ r_set_attrs(next, a_executable | l_new);
+ ++next;
+ } {
+ gs_rect bbox;
+
+ gs_upathbbox(pgs, &bbox, true);
+ make_real_new(next, bbox.p.x);
+ make_real_new(next + 1, bbox.p.y);
+ make_real_new(next + 2, bbox.q.x);
+ make_real_new(next + 3, bbox.q.y);
+ next += 4;
+ if ((code = name_enter_string("setbbox", next)) < 0)
+ return code;
+ r_set_attrs(next, a_executable | l_new);
+ ++next;
+ }
+ {
+ gs_point pts[3];
+
+ /* Patch the path in the gstate to set up the enumerator. */
+ gx_path *save_path = pgs->path;
+
+ pgs->path = ppath;
+ gs_path_enum_copy_init(&penum, pgs, false);
+ pgs->path = save_path;
+ while ((op = gs_path_enum_next(&penum, pts)) != 0) {
+ const char *opstr;
+
+ switch (op) {
+ case gs_pe_moveto:
+ opstr = "moveto";
+ goto ml;
+ case gs_pe_lineto:
+ opstr = "lineto";
+ ml:make_real_new(next, pts[0].x);
+ make_real_new(next + 1, pts[0].y);
+ next += 2;
+ break;
+ case gs_pe_curveto:
+ opstr = "curveto";
+ make_real_new(next, pts[0].x);
+ make_real_new(next + 1, pts[0].y);
+ make_real_new(next + 2, pts[1].x);
+ make_real_new(next + 3, pts[1].y);
+ make_real_new(next + 4, pts[2].x);
+ make_real_new(next + 5, pts[2].y);
+ next += 6;
+ break;
+ case gs_pe_closepath:
+ opstr = "closepath";
+ break;
+ default:
+ return_error(e_unregistered);
+ }
+ if ((code = name_enter_string(opstr, next)) < 0)
+ return code;
+ r_set_attrs(next, a_executable);
+ ++next;
+ }
+ }
+ return 0;
+}
+
+/* ------ Internal routines ------ */
+
+/* Append a user path to the current path. */
+private int
+upath_append(os_ptr oppath, os_ptr op)
+{
+ check_read(*oppath);
+ gs_newpath(igs);
+/****** ROUND tx AND ty ******/
+ if (r_has_type(oppath, t_array) && r_size(oppath) == 2 &&
+ r_has_type(oppath->value.refs + 1, t_string)
+ ) { /* 1st element is operators, 2nd is operands */
+ const ref *operands = oppath->value.refs;
+ int code, format;
+ int repcount = 1;
+ const byte *opp;
+ uint ocount, i = 0;
+
+ code = num_array_format(operands);
+ if (code < 0)
+ return code;
+ format = code;
+ opp = oppath->value.refs[1].value.bytes;
+ ocount = r_size(&oppath->value.refs[1]);
+ while (ocount--) {
+ byte opx = *opp++;
+
+ if (opx > UPATH_REPEAT)
+ repcount = opx - UPATH_REPEAT;
+ else if (opx > UPATH_MAX_OP)
+ return_error(e_rangecheck);
+ else { /* operator */
+ do {
+ byte opargs = up_nargs[opx];
+
+ while (opargs--) {
+ push(1);
+ code = num_array_get(operands, format, i++, op);
+ switch (code) {
+ case t_integer:
+ r_set_type_attrs(op, t_integer, 0);
+ break;
+ case t_real:
+ r_set_type_attrs(op, t_real, 0);
+ break;
+ default:
+ return_error(e_typecheck);
+ }
+ }
+ code = (*up_ops[opx])(op);
+ if (code < 0)
+ return code;
+ op = osp; /* resync */
+ }
+ while (--repcount);
+ repcount = 1;
+ }
+ }
+ } else if (r_is_array(oppath)) { /* Ordinary executable array. */
+ const ref *arp = oppath;
+ uint ocount = r_size(oppath);
+ long index = 0;
+ int argcount = 0;
+ int (*oproc)(P1(os_ptr));
+ int opx, code;
+
+ for (; index < ocount; index++) {
+ ref rup;
+ ref *defp;
+
+ array_get(arp, index, &rup);
+ switch (r_type(&rup)) {
+ case t_integer:
+ case t_real:
+ argcount++;
+ push(1);
+ *op = rup;
+ break;
+ case t_name:
+ if (!r_has_attr(&rup, a_executable))
+ return_error(e_typecheck);
+ if (dict_find(systemdict, &rup, &defp) <= 0)
+ return_error(e_undefined);
+ if (r_btype(defp) != t_operator)
+ return_error(e_typecheck);
+ goto xop;
+ case t_operator:
+ defp = &rup;
+ xop:if (!r_has_attr(defp, a_executable))
+ return_error(e_typecheck);
+ oproc = real_opproc(defp);
+ for (opx = 0; opx <= UPATH_MAX_OP; opx++)
+ if (oproc == up_ops[opx])
+ break;
+ if (opx > UPATH_MAX_OP || argcount != up_nargs[opx])
+ return_error(e_typecheck);
+ code = (*oproc)(op);
+ if (code < 0)
+ return code;
+ op = osp; /* resync ostack pointer */
+ argcount = 0;
+ break;
+ default:
+ return_error(e_typecheck);
+ }
+ }
+ if (argcount)
+ return_error(e_typecheck); /* leftover args */
+ } else
+ return_error(e_typecheck);
+ return 0;
+}
+
+/* Append a user path to the current path, and then apply or return */
+/* a transformation if one is supplied. */
+private int
+upath_stroke(os_ptr op, gs_matrix *pmat)
+{
+ int code, npop;
+ gs_matrix mat;
+
+ if ((code = read_matrix(op, &mat)) >= 0) {
+ if ((code = upath_append(op - 1, op)) >= 0) {
+ if (pmat)
+ *pmat = mat;
+ else
+ code = gs_concat(igs, &mat);
+ }
+ npop = 2;
+ } else {
+ if ((code = upath_append(op, op)) >= 0)
+ if (pmat)
+ gs_make_identity(pmat);
+ npop = 1;
+ }
+ return (code < 0 ? code : npop);
+}
+
+/* ---------------- Initialization procedure ---------------- */
+
+const op_def zupath_l2_op_defs[] =
+{
+ op_def_begin_level2(),
+ /* Insideness testing */
+ {"1ineofill", zineofill},
+ {"1infill", zinfill},
+ {"1instroke", zinstroke},
+ {"2inueofill", zinueofill},
+ {"2inufill", zinufill},
+ {"2inustroke", zinustroke},
+ /* User paths */
+ {"1uappend", zuappend},
+ {"0ucache", zucache},
+ {"1ueofill", zueofill},
+ {"1ufill", zufill},
+ {"1upath", zupath},
+ {"1ustroke", zustroke},
+ {"1ustrokepath", zustrokepath},
+ op_def_end(0)
+};
diff --git a/pstoraster/zusparam.c b/pstoraster/zusparam.c
new file mode 100644
index 000000000..5cdbd13ca
--- /dev/null
+++ b/pstoraster/zusparam.c
@@ -0,0 +1,655 @@
+/* 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$ */
+/* User and system parameter operators */
+#include "memory_.h"
+#include "string_.h"
+#include "ghost.h"
+#include "oper.h"
+#include "gscdefs.h"
+#include "gsstruct.h" /* for gxht.h */
+#include "gsfont.h" /* for user params */
+#include "gxht.h" /* for user params */
+#include "gsutil.h"
+#include "estack.h"
+#include "ialloc.h" /* for imemory for status */
+#include "icontext.h" /* for set_user_params prototype */
+#include "idict.h"
+#include "idparam.h"
+#include "iparam.h"
+#include "dstack.h"
+#include "iname.h"
+#include "iutil2.h"
+#include "store.h"
+
+/* The (global) font directory */
+extern gs_font_dir *ifont_dir; /* in zfont.c */
+
+/* Import the GC parameters from zvmem2.c. */
+extern int set_vm_reclaim(P1(long));
+extern int set_vm_threshold(P1(long));
+
+/* Define an individual user or system parameter. */
+/* Eventually this will be made public. */
+#define param_def_common\
+ const char *pname
+typedef struct param_def_s {
+ param_def_common;
+} param_def_t;
+typedef struct long_param_def_s {
+ param_def_common;
+ long min_value, max_value;
+ long (*current)(P0());
+ int (*set)(P1(long));
+} long_param_def_t;
+
+#if arch_sizeof_long > arch_sizeof_int
+# define MAX_UINT_PARAM max_uint
+#else
+# define MAX_UINT_PARAM max_long
+#endif
+typedef struct bool_param_def_s {
+ param_def_common;
+ bool (*current)(P0());
+ int (*set)(P1(bool));
+} bool_param_def_t;
+typedef struct string_param_def_s {
+ param_def_common;
+ void (*current)(P1(gs_param_string *));
+ int (*set)(P1(gs_param_string *));
+} string_param_def_t;
+
+/* Define a parameter set (user or system). */
+typedef struct param_set_s {
+ const long_param_def_t *long_defs;
+ uint long_count;
+ const bool_param_def_t *bool_defs;
+ uint bool_count;
+ const string_param_def_t *string_defs;
+ uint string_count;
+} param_set;
+
+/* Forward references */
+private int setparams(P2(gs_param_list *, const param_set *));
+private int currentparams(P2(os_ptr, const param_set *));
+private int currentparam1(P2(os_ptr, const param_set *));
+
+/* ------ Passwords ------ */
+
+/* <string|int> .checkpassword <0|1|2> */
+private int
+zcheckpassword(register os_ptr op)
+{
+ ref params[2];
+ array_param_list list;
+ gs_param_list *const plist = (gs_param_list *)&list;
+ int result = 0;
+ int code = name_ref((const byte *)"Password", 8, &params[0], 0);
+ password pass;
+
+ if (code < 0)
+ return code;
+ params[1] = *op;
+ array_param_list_read(&list, params, 2, NULL, false);
+ if (dict_read_password(&pass, systemdict, "StartJobPassword") >= 0 &&
+ param_check_password(plist, &pass) == 0
+ )
+ result = 1;
+ if (dict_read_password(&pass, systemdict, "SystemParamsPassword") >= 0 &&
+ param_check_password(plist, &pass) == 0
+ )
+ result = 2;
+ iparam_list_release(&list);
+ make_int(op, result);
+ return 0;
+}
+
+/* ------ System parameters ------ */
+
+/* Integer values */
+private long
+current_BuildTime(void)
+{
+ return gs_buildtime;
+}
+private long
+current_MaxFontCache(void)
+{
+ return gs_currentcachesize(ifont_dir);
+}
+private int
+set_MaxFontCache(long val)
+{
+ return gs_setcachesize(ifont_dir,
+ (uint)(val < 0 ? 0 : val > max_uint ? max_uint :
+ val));
+}
+private long
+current_CurFontCache(void)
+{
+ uint cstat[7];
+
+ gs_cachestatus(ifont_dir, cstat);
+ return cstat[0];
+}
+private long
+current_MaxGlobalVM(void)
+{
+ gs_memory_gc_status_t stat;
+
+ gs_memory_gc_status(iimemory_global, &stat);
+ return stat.max_vm;
+}
+private int
+set_MaxGlobalVM(long val)
+{
+ gs_memory_gc_status_t stat;
+
+ gs_memory_gc_status(iimemory_global, &stat);
+ stat.max_vm = max(val, 0);
+ gs_memory_set_gc_status(iimemory_global, &stat);
+ return 0;
+}
+private long
+current_Revision(void)
+{
+ return gs_revision;
+}
+private const long_param_def_t system_long_params[] =
+{
+ {"BuildTime", min_long, max_long, current_BuildTime, NULL},
+{"MaxFontCache", 0, MAX_UINT_PARAM, current_MaxFontCache, set_MaxFontCache},
+ {"CurFontCache", 0, MAX_UINT_PARAM, current_CurFontCache, NULL},
+ {"Revision", min_long, max_long, current_Revision, NULL},
+ /* Extensions */
+ {"MaxGlobalVM", 0, max_long, current_MaxGlobalVM, set_MaxGlobalVM}
+};
+
+/* Boolean values */
+private bool
+current_ByteOrder(void)
+{
+ return !arch_is_big_endian;
+}
+private const bool_param_def_t system_bool_params[] =
+{
+ {"ByteOrder", current_ByteOrder, NULL}
+};
+
+/* String values */
+private void
+current_RealFormat(gs_param_string * pval)
+{
+#if arch_floats_are_IEEE
+ static const char *const rfs = "IEEE";
+
+#else
+ static const char *const rfs = "not IEEE";
+
+#endif
+
+ pval->data = (const byte *)rfs;
+ pval->size = strlen(rfs);
+ pval->persistent = true;
+}
+private const string_param_def_t system_string_params[] =
+{
+ {"RealFormat", current_RealFormat, NULL}
+};
+
+/* The system parameter set */
+private const param_set system_param_set =
+{
+ system_long_params, countof(system_long_params),
+ system_bool_params, countof(system_bool_params),
+ system_string_params, countof(system_string_params)
+};
+
+/* <dict> .setsystemparams - */
+private int
+zsetsystemparams(register os_ptr op)
+{
+ int code;
+ dict_param_list list;
+ gs_param_list *const plist = (gs_param_list *)&list;
+ password pass;
+
+ check_type(*op, t_dictionary);
+ code = dict_param_list_read(&list, op, NULL, false);
+ if (code < 0)
+ return code;
+ code = dict_read_password(&pass, systemdict, "SystemParamsPassword");
+ if (code < 0)
+ return code;
+ code = param_check_password(plist, &pass);
+ if (code != 0) {
+ if (code > 0)
+ code = gs_note_error(e_invalidaccess);
+ goto out;
+ }
+ code = param_read_password(plist, "StartJobPassword", &pass);
+ switch (code) {
+ default: /* invalid */
+ goto out;
+ case 1: /* missing */
+ break;
+ case 0:
+ code = dict_write_password(&pass, systemdict,
+ "StartJobPassword");
+ if (code < 0)
+ goto out;
+ }
+ code = param_read_password(plist, "SystemParamsPassword", &pass);
+ switch (code) {
+ default: /* invalid */
+ goto out;
+ case 1: /* missing */
+ break;
+ case 0:
+ code = dict_write_password(&pass, systemdict,
+ "SystemParamsPassword");
+ if (code < 0)
+ goto out;
+ }
+ code = setparams(plist, &system_param_set);
+ out:
+ iparam_list_release(&list);
+ if (code < 0)
+ return code;
+ pop(1);
+ return 0;
+}
+
+/* - .currentsystemparams <name1> <value1> ... */
+private int
+zcurrentsystemparams(os_ptr op)
+{
+ return currentparams(op, &system_param_set);
+}
+
+/* <name> .getsystemparam <value> */
+private int
+zgetsystemparam(os_ptr op)
+{
+ return currentparam1(op, &system_param_set);
+}
+
+/* ------ User parameters ------ */
+
+/* Integer values */
+private long
+current_JobTimeout(void)
+{
+ return 0;
+}
+private int
+set_JobTimeout(long val)
+{
+ return 0;
+}
+private long
+current_MaxFontItem(void)
+{
+ return gs_currentcacheupper(ifont_dir);
+}
+private int
+set_MaxFontItem(long val)
+{
+ return gs_setcacheupper(ifont_dir, val);
+}
+private long
+current_MinFontCompress(void)
+{
+ return gs_currentcachelower(ifont_dir);
+}
+private int
+set_MinFontCompress(long val)
+{
+ return gs_setcachelower(ifont_dir, val);
+}
+private long
+current_MaxOpStack(void)
+{
+ return ref_stack_max_count(&o_stack);
+}
+private int
+set_MaxOpStack(long val)
+{
+ return ref_stack_set_max_count(&o_stack, val);
+}
+private long
+current_MaxDictStack(void)
+{
+ return ref_stack_max_count(&d_stack);
+}
+private int
+set_MaxDictStack(long val)
+{
+ return ref_stack_set_max_count(&d_stack, val);
+}
+private long
+current_MaxExecStack(void)
+{
+ return ref_stack_max_count(&e_stack);
+}
+private int
+set_MaxExecStack(long val)
+{
+ return ref_stack_set_max_count(&e_stack, val);
+}
+private long
+current_MaxLocalVM(void)
+{
+ gs_memory_gc_status_t stat;
+
+ gs_memory_gc_status(iimemory_local, &stat);
+ return stat.max_vm;
+}
+private int
+set_MaxLocalVM(long val)
+{
+ gs_memory_gc_status_t stat;
+
+ gs_memory_gc_status(iimemory_local, &stat);
+ stat.max_vm = max(val, 0);
+ gs_memory_set_gc_status(iimemory_local, &stat);
+ return 0;
+}
+private long
+current_VMReclaim(void)
+{
+ gs_memory_gc_status_t gstat, lstat;
+
+ gs_memory_gc_status(iimemory_global, &gstat);
+ gs_memory_gc_status(iimemory_local, &lstat);
+ return (!gstat.enabled ? -2 : !lstat.enabled ? -1 : 0);
+}
+private long
+current_VMThreshold(void)
+{
+ gs_memory_gc_status_t stat;
+
+ gs_memory_gc_status(iimemory_local, &stat);
+ return stat.vm_threshold;
+}
+private long
+current_WaitTimeout(void)
+{
+ return 0;
+}
+private int
+set_WaitTimeout(long val)
+{
+ return 0;
+}
+private long
+current_MinScreenLevels(void)
+{
+ return gs_currentminscreenlevels();
+}
+private int
+set_MinScreenLevels(long val)
+{
+ gs_setminscreenlevels((uint) val);
+ return 0;
+}
+private const long_param_def_t user_long_params[] =
+{
+ {"JobTimeout", 0, MAX_UINT_PARAM,
+ current_JobTimeout, set_JobTimeout},
+ {"MaxFontItem", 0, MAX_UINT_PARAM,
+ current_MaxFontItem, set_MaxFontItem},
+ {"MinFontCompress", 0, MAX_UINT_PARAM,
+ current_MinFontCompress, set_MinFontCompress},
+ {"MaxOpStack", 0, MAX_UINT_PARAM,
+ current_MaxOpStack, set_MaxOpStack},
+ {"MaxDictStack", 0, MAX_UINT_PARAM,
+ current_MaxDictStack, set_MaxDictStack},
+ {"MaxExecStack", 0, MAX_UINT_PARAM,
+ current_MaxExecStack, set_MaxExecStack},
+ {"MaxLocalVM", 0, max_long,
+ current_MaxLocalVM, set_MaxLocalVM},
+ {"VMReclaim", -2, 0,
+ current_VMReclaim, set_vm_reclaim},
+ {"VMThreshold", -1, max_long,
+ current_VMThreshold, set_vm_threshold},
+ {"WaitTimeout", 0, MAX_UINT_PARAM,
+ current_WaitTimeout, set_WaitTimeout},
+ /* Extensions */
+ {"MinScreenLevels", 0, MAX_UINT_PARAM,
+ current_MinScreenLevels, set_MinScreenLevels}
+};
+
+/* Boolean values */
+private bool
+current_AccurateScreens(void)
+{
+ return gs_currentaccuratescreens();
+}
+private int
+set_AccurateScreens(bool val)
+{
+ gs_setaccuratescreens(val);
+ return 0;
+}
+private const bool_param_def_t user_bool_params[] =
+{
+ {"AccurateScreens", current_AccurateScreens, set_AccurateScreens}
+};
+
+/* The user parameter set */
+private const param_set user_param_set =
+{
+ user_long_params, countof(user_long_params),
+ user_bool_params, countof(user_bool_params),
+ 0, 0
+};
+
+/* <dict> .setuserparams - */
+/* We break this out for use when switching contexts. */
+int
+set_user_params(const ref * op)
+{
+ dict_param_list list;
+ int code;
+
+ check_type(*op, t_dictionary);
+ code = dict_param_list_read(&list, op, NULL, false);
+ if (code < 0)
+ return code;
+ code = setparams((gs_param_list *)&list, &user_param_set);
+ iparam_list_release(&list);
+ return code;
+}
+private int
+zsetuserparams(register os_ptr op)
+{
+ int code = set_user_params(op);
+
+ if (code >= 0)
+ pop(1);
+ return code;
+}
+
+/* - .currentuserparams <name1> <value1> ... */
+private int
+zcurrentuserparams(os_ptr op)
+{
+ return currentparams(op, &user_param_set);
+}
+
+/* <name> .getuserparam <value> */
+private int
+zgetuserparam(os_ptr op)
+{
+ return currentparam1(op, &user_param_set);
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zusparam_op_defs[] =
+{
+ /* User and system parameters are accessible even in Level 1 */
+ /* (if this is a Level 2 system). */
+ {"0.currentsystemparams", zcurrentsystemparams},
+ {"0.currentuserparams", zcurrentuserparams},
+ {"1.getsystemparam", zgetsystemparam},
+ {"1.getuserparam", zgetuserparam},
+ {"1.setsystemparams", zsetsystemparams},
+ {"1.setuserparams", zsetuserparams},
+ /* The rest of the operators are defined only in Level 2. */
+ op_def_begin_level2(),
+ {"1.checkpassword", zcheckpassword},
+ op_def_end(0)
+};
+
+/* ------ Internal procedures ------ */
+
+/* Set the values of a parameter set from a parameter list. */
+/* We don't attempt to back out if anything fails. */
+private int
+setparams(gs_param_list * plist, const param_set * pset)
+{
+ int i, code;
+
+ for (i = 0; i < pset->long_count; i++) {
+ const long_param_def_t *pdef = &pset->long_defs[i];
+ long val;
+
+ if (pdef->set == NULL)
+ continue;
+ code = param_read_long(plist, pdef->pname, &val);
+ switch (code) {
+ default: /* invalid */
+ return code;
+ case 1: /* missing */
+ break;
+ case 0:
+ if (val < pdef->min_value || val > pdef->max_value)
+ return_error(e_rangecheck);
+ code = (*pdef->set)(val);
+ if (code < 0)
+ return code;
+ }
+ }
+ for (i = 0; i < pset->bool_count; i++) {
+ const bool_param_def_t *pdef = &pset->bool_defs[i];
+ bool val;
+
+ if (pdef->set == NULL)
+ continue;
+ code = param_read_bool(plist, pdef->pname, &val);
+ if (code == 0)
+ code = (*pdef->set)(val);
+ if (code < 0)
+ return code;
+ }
+/****** WE SHOULD DO STRINGS AND STRING ARRAYS, BUT WE DON'T YET ******/
+ return 0;
+}
+
+/* Get the current values of a parameter set to the stack. */
+private bool
+pname_matches(const char *pname, const ref * psref)
+{
+ return
+ (psref == 0 ||
+ !bytes_compare((const byte *)pname, strlen(pname),
+ psref->value.const_bytes, r_size(psref)));
+}
+private int
+current_param_list(os_ptr op, const param_set * pset,
+ const ref * psref /*t_string */ )
+{
+ stack_param_list list;
+ gs_param_list *const plist = (gs_param_list *)&list;
+ int i;
+
+ stack_param_list_write(&list, &o_stack, NULL);
+ for (i = 0; i < pset->long_count; i++) {
+ const char *pname = pset->long_defs[i].pname;
+
+ if (pname_matches(pname, psref)) {
+ long val = (*pset->long_defs[i].current)();
+ int code = param_write_long(plist, pname, &val);
+
+ if (code < 0)
+ return code;
+ }
+ }
+ for (i = 0; i < pset->bool_count; i++) {
+ const char *pname = pset->bool_defs[i].pname;
+
+ if (pname_matches(pname, psref)) {
+ bool val = (*pset->bool_defs[i].current)();
+ int code = param_write_bool(plist, pname, &val);
+
+ if (code < 0)
+ return code;
+ }
+ }
+ for (i = 0; i < pset->string_count; i++) {
+ const char *pname = pset->string_defs[i].pname;
+
+ if (pname_matches(pname, psref)) {
+ gs_param_string val;
+ int code;
+
+ (*pset->string_defs[i].current)(&val);
+ code = param_write_string(plist, pname, &val);
+ if (code < 0)
+ return code;
+ }
+ }
+ return 0;
+}
+
+/* Get the current values of a parameter set to the stack. */
+private int
+currentparams(os_ptr op, const param_set * pset)
+{
+ return current_param_list(op, pset, NULL);
+}
+
+/* Get the value of a single parameter to the stack, or signal an error. */
+private int
+currentparam1(os_ptr op, const param_set * pset)
+{
+ ref sref;
+ int code;
+
+ check_type(*op, t_name);
+ check_ostack(2);
+ name_string_ref((const ref *)op, &sref);
+ code = current_param_list(op, pset, &sref);
+ if (code < 0)
+ return code;
+ if (osp == op)
+ return_error(e_undefined);
+ /* We know osp == op + 2. */
+ ref_assign(op, op + 2);
+ pop(2);
+ return code;
+}
diff --git a/pstoraster/zvmem.c b/pstoraster/zvmem.c
new file mode 100644
index 000000000..109816969
--- /dev/null
+++ b/pstoraster/zvmem.c
@@ -0,0 +1,404 @@
+/* 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$ */
+/* "Virtual memory" operators */
+#include "ghost.h"
+#include "gsstruct.h"
+#include "oper.h"
+#include "estack.h" /* for checking in restore */
+#include "ialloc.h"
+#include "idict.h" /* ditto */
+#include "igstate.h"
+#include "isave.h"
+#include "dstack.h"
+#include "stream.h" /* for files.h */
+#include "files.h" /* for e-stack processing */
+#include "store.h"
+#include "gsmalloc.h" /* for gs_memory_default */
+#include "gsmatrix.h" /* for gsstate.h */
+#include "gsstate.h"
+
+/* Define whether we validate memory before/after save/restore. */
+/* Note that we only actually do this if DEBUG is set and -Z? is selected. */
+private bool I_VALIDATE_BEFORE_SAVE = true;
+private bool I_VALIDATE_AFTER_SAVE = true;
+private bool I_VALIDATE_BEFORE_RESTORE = true;
+private bool I_VALIDATE_AFTER_RESTORE = true;
+
+/* Make an invalid file object. */
+extern void make_invalid_file(P1(ref *)); /* in zfile.c */
+
+/* 'Save' structure */
+typedef struct vm_save_s vm_save_t;
+struct vm_save_s {
+ gs_state *gsave; /* old graphics state */
+};
+
+gs_private_st_ptrs1(st_vm_save, vm_save_t, "savetype",
+ vm_save_enum_ptrs, vm_save_reloc_ptrs, gsave);
+
+/* Clean up the stacks and validate storage. */
+private void
+ivalidate_clean_spaces(void)
+{
+ if (gs_debug_c('?')) {
+ ref_stack_cleanup(&d_stack);
+ ref_stack_cleanup(&e_stack);
+ ref_stack_cleanup(&o_stack);
+ ivalidate_spaces();
+ }
+}
+
+/* - save <save> */
+int
+zsave(register os_ptr op)
+{
+ uint space = icurrent_space;
+ vm_save_t *vmsave;
+ ulong sid;
+ int code;
+ gs_state *prev;
+
+ if (I_VALIDATE_BEFORE_SAVE)
+ ivalidate_clean_spaces();
+ ialloc_set_space(idmemory, avm_local);
+ vmsave = ialloc_struct(vm_save_t, &st_vm_save, "zsave");
+ ialloc_set_space(idmemory, space);
+ if (vmsave == 0)
+ return_error(e_VMerror);
+ sid = alloc_save_state(idmemory, vmsave);
+ if (sid == 0) {
+ ifree_object(vmsave, "zsave");
+ return_error(e_VMerror);
+ }
+ if_debug2('u', "[u]vmsave 0x%lx, id = %lu\n",
+ (ulong) vmsave, (ulong) sid);
+ code = gs_gsave_for_save(igs, &prev);
+ if (code < 0)
+ return code;
+ code = gs_gsave(igs);
+ if (code < 0)
+ return code;
+ vmsave->gsave = prev;
+ push(1);
+ make_tav(op, t_save, 0, saveid, sid);
+ if (I_VALIDATE_AFTER_SAVE)
+ ivalidate_clean_spaces();
+ return 0;
+}
+
+/* <save> restore - */
+private int restore_check_operand(P2(os_ptr, alloc_save_t **));
+private int restore_check_stack(P3(const ref_stack *, const alloc_save_t *, bool));
+private void restore_fix_stack(P3(ref_stack *, const alloc_save_t *, bool));
+int
+zrestore(register os_ptr op)
+{
+ alloc_save_t *asave;
+ bool last;
+ vm_save_t *vmsave;
+ int code = restore_check_operand(op, &asave);
+
+ if (code < 0)
+ return code;
+ if_debug2('u', "[u]vmrestore 0x%lx, id = %lu\n",
+ (ulong) alloc_save_client_data(asave),
+ (ulong) op->value.saveid);
+ if (I_VALIDATE_BEFORE_RESTORE)
+ ivalidate_clean_spaces();
+ /* Check the contents of the stacks. */
+ osp--;
+ {
+ int code;
+
+ if ((code = restore_check_stack(&o_stack, asave, false)) < 0 ||
+ (code = restore_check_stack(&e_stack, asave, true)) < 0 ||
+ (code = restore_check_stack(&d_stack, asave, false)) < 0
+ ) {
+ osp++;
+ return code;
+ }
+ }
+ /* Reset l_new in all stack entries if the new save level is zero. */
+ /* Also do some special fixing on the e-stack. */
+ restore_fix_stack(&o_stack, asave, false);
+ restore_fix_stack(&e_stack, asave, true);
+ restore_fix_stack(&d_stack, asave, false);
+ /* Iteratively restore the state of memory, */
+ /* also doing a grestoreall at each step. */
+ do {
+ vmsave = alloc_save_client_data(alloc_save_current(idmemory));
+ /* Restore the graphics state. */
+ gs_grestoreall_for_restore(igs, vmsave->gsave);
+ /*
+ * If alloc_save_space decided to do a second save, the vmsave
+ * object was allocated one save level less deep than the
+ * current level, so ifree_object won't actually free it;
+ * however, it points to a gsave object that definitely
+ * *has* been freed. In order not to trip up the garbage
+ * collector, we clear the gsave pointer now.
+ */
+ vmsave->gsave = 0;
+ /* Now it's safe to restore the state of memory. */
+ last = alloc_restore_state_step(asave);
+ }
+ while (!last);
+ {
+ uint space = icurrent_space;
+
+ ialloc_set_space(idmemory, avm_local);
+ ifree_object(vmsave, "zrestore");
+ ialloc_set_space(idmemory, space);
+ }
+ dict_set_top(); /* reload dict stack cache */
+ if (I_VALIDATE_AFTER_RESTORE)
+ ivalidate_clean_spaces();
+ return 0;
+}
+/* Check the operand of a restore. */
+private int
+restore_check_operand(os_ptr op, alloc_save_t ** pasave)
+{
+ vm_save_t *vmsave;
+ ulong sid;
+ alloc_save_t *asave;
+
+ check_type(*op, t_save);
+ vmsave = r_ptr(op, vm_save_t);
+ if (vmsave == 0) /* invalidated save */
+ return_error(e_invalidrestore);
+ sid = op->value.saveid;
+ asave = alloc_find_save(idmemory, sid);
+ if (asave == 0)
+ return_error(e_invalidrestore);
+ *pasave = asave;
+ return 0;
+}
+/* Check a stack to make sure all its elements are older than a save. */
+private int
+restore_check_stack(const ref_stack * pstack, const alloc_save_t * asave,
+ bool is_estack)
+{
+ ref_stack_enum_t rsenum;
+
+ ref_stack_enum_begin(&rsenum, pstack);
+ do {
+ const ref *stkp = rsenum.ptr;
+ uint size = rsenum.size;
+
+ for (; size; stkp++, size--) {
+ const void *ptr;
+
+ switch (r_type(stkp)) {
+ case t_array:
+ ptr = stkp->value.refs;
+ break;
+ case t_dictionary:
+ ptr = stkp->value.pdict;
+ break;
+ case t_file:
+ /* Don't check executable or closed literal */
+ /* files on the e-stack. */
+ {
+ stream *s;
+
+ if (is_estack &&
+ (r_has_attr(stkp, a_executable) ||
+ file_is_invalid(s, stkp))
+ )
+ continue;
+ }
+ ptr = stkp->value.pfile;
+ break;
+ case t_name:
+ /* Names are special because of how they are allocated. */
+ if (alloc_name_is_since_save(stkp, asave))
+ return_error(e_invalidrestore);
+ continue;
+ case t_string:
+ /* Don't check empty executable strings */
+ /* on the e-stack. */
+ if (r_size(stkp) == 0 &&
+ r_has_attr(stkp, a_executable) && is_estack
+ )
+ continue;
+ ptr = stkp->value.bytes;
+ break;
+ case t_mixedarray:
+ case t_shortarray:
+ ptr = stkp->value.packed;
+ break;
+ case t_device:
+ ptr = stkp->value.pdevice;
+ break;
+ case t_fontID:
+ case t_struct:
+ case t_astruct:
+ ptr = stkp->value.pstruct;
+ break;
+ default:
+ continue;
+ }
+ if (alloc_is_since_save(ptr, asave))
+ return_error(e_invalidrestore);
+ }
+ } while (ref_stack_enum_next(&rsenum));
+ return 0; /* OK */
+}
+/*
+ * If the new save level is zero, fix up the contents of a stack
+ * by clearing the l_new bit in all the entries (since we can't tolerate
+ * values with l_new set if the save level is zero).
+ * Also, in any case, fix up the e-stack by replacing empty executable
+ * strings and closed executable files that are newer than the save
+ * with canonical ones that aren't.
+ *
+ * Note that this procedure is only called if restore_check_stack succeeded.
+ */
+private void
+restore_fix_stack(ref_stack * pstack, const alloc_save_t * asave,
+ bool is_estack)
+{
+ ref_stack_enum_t rsenum;
+
+ ref_stack_enum_begin(&rsenum, pstack);
+ do {
+ ref *stkp = rsenum.ptr;
+ uint size = rsenum.size;
+
+ for (; size; stkp++, size--) {
+ r_clear_attrs(stkp, l_new); /* always do it, no harm */
+ if (is_estack) {
+ ref ofile;
+
+ ref_assign(&ofile, stkp);
+ switch (r_type(stkp)) {
+ case t_string:
+ if (r_size(stkp) == 0 &&
+ alloc_is_since_save(stkp->value.bytes,
+ asave)
+ ) {
+ make_empty_const_string(stkp,
+ avm_foreign);
+ break;
+ }
+ continue;
+ case t_file:
+ if (alloc_is_since_save(stkp->value.pfile,
+ asave)
+ ) {
+ make_invalid_file(stkp);
+ break;
+ }
+ continue;
+ default:
+ continue;
+ }
+ r_copy_attrs(stkp, a_all | a_executable,
+ &ofile);
+ }
+ }
+ } while (ref_stack_enum_next(&rsenum));
+}
+
+/* - vmstatus <save_level> <vm_used> <vm_maximum> */
+private int
+zvmstatus(register os_ptr op)
+{
+ gs_memory_status_t mstat, dstat;
+
+ gs_memory_status(imemory, &mstat);
+ if (imemory == imemory_global) {
+ gs_memory_status_t sstat;
+
+ gs_memory_status(imemory_system, &sstat);
+ mstat.allocated += sstat.allocated;
+ mstat.used += sstat.used;
+ }
+ gs_memory_status(&gs_memory_default, &dstat);
+ push(3);
+ make_int(op - 2, alloc_save_level(idmemory));
+ make_int(op - 1, mstat.used);
+ make_int(op, mstat.allocated + dstat.allocated - dstat.used);
+ return 0;
+}
+
+/* ------ Non-standard extensions ------ */
+
+/* <save> .forgetsave - */
+private int
+zforgetsave(register os_ptr op)
+{
+ alloc_save_t *asave;
+ vm_save_t *vmsave;
+ int code = restore_check_operand(op, &asave);
+
+ if (code < 0)
+ return 0;
+ vmsave = alloc_save_client_data(asave);
+ /* Reset l_new in all stack entries if the new save level is zero. */
+ restore_fix_stack(&o_stack, asave, false);
+ restore_fix_stack(&e_stack, asave, false);
+ restore_fix_stack(&d_stack, asave, false);
+ /*
+ * Forget the gsaves, by deleting the bottom gstate on
+ * the current stack and the top one on the saved stack and then
+ * concatenating the stacks together.
+ */
+ {
+ gs_state *pgs = igs;
+ gs_state *last;
+
+ while (gs_state_saved(last = gs_state_saved(pgs)) != 0)
+ pgs = last;
+ gs_state_swap_saved(last, vmsave->gsave);
+ gs_grestore(last);
+ gs_grestore(last);
+ }
+ /* Forget the save in the memory manager. */
+ alloc_forget_save(asave);
+ {
+ uint space = icurrent_space;
+
+ ialloc_set_space(idmemory, avm_local);
+ /* See above for why we clear the gsave pointer here. */
+ vmsave->gsave = 0;
+ ifree_object(vmsave, "zrestore");
+ ialloc_set_space(idmemory, space);
+ }
+ pop(1);
+ return 0;
+}
+
+/* ------ Initialization procedure ------ */
+
+const op_def zvmem_op_defs[] =
+{
+ {"1.forgetsave", zforgetsave},
+ {"1restore", zrestore},
+ {"0save", zsave},
+ {"0vmstatus", zvmstatus},
+ op_def_end(0)
+};
diff --git a/pstoraster/zvmem2.c b/pstoraster/zvmem2.c
new file mode 100644
index 000000000..84f960783
--- /dev/null
+++ b/pstoraster/zvmem2.c
@@ -0,0 +1,153 @@
+/* Copyright (C) 1992, 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$ */
+/* Level 2 "Virtual memory" operators */
+#include "ghost.h"
+#include "oper.h"
+#include "estack.h"
+#include "ialloc.h" /* for ivmspace.h */
+#include "ivmspace.h"
+#include "store.h"
+
+/* Garbage collector control parameters. */
+#define DEFAULT_VM_THRESHOLD_SMALL 20000
+#define DEFAULT_VM_THRESHOLD_LARGE 250000
+#define MIN_VM_THRESHOLD 1
+#define MAX_VM_THRESHOLD max_long
+
+/* ------ Local/global VM control ------ */
+
+/* <bool> .setglobal - */
+private int
+zsetglobal(register os_ptr op)
+{
+ check_type(*op, t_boolean);
+ ialloc_set_space(idmemory,
+ (op->value.boolval ? avm_global : avm_local));
+ pop(1);
+ return 0;
+}
+
+/* <bool> .currentglobal - */
+private int
+zcurrentglobal(register os_ptr op)
+{
+ push(1);
+ make_bool(op, ialloc_space(idmemory) != avm_local);
+ return 0;
+}
+
+/* <any> gcheck/scheck <bool> */
+private int
+zgcheck(register os_ptr op)
+{
+ check_op(1);
+ make_bool(op, (r_is_local(op) ? false : true));
+ return 0;
+}
+
+/* ------ Garbage collector control ------ */
+
+/* These routines are exported for setuserparams. */
+
+/*
+ * <int> setvmthreshold -
+ *
+ * This is implemented as a PostScript procedure that calls setuserparams.
+ */
+int
+set_vm_threshold(long val)
+{
+ gs_memory_gc_status_t stat;
+
+ if (val < -1)
+ return_error(e_rangecheck);
+ else if (val == -1)
+ val = (gs_debug_c('.') ? DEFAULT_VM_THRESHOLD_SMALL :
+ DEFAULT_VM_THRESHOLD_LARGE);
+ else if (val < MIN_VM_THRESHOLD)
+ val = MIN_VM_THRESHOLD;
+ else if (val > MAX_VM_THRESHOLD)
+ val = MAX_VM_THRESHOLD;
+ gs_memory_gc_status(idmemory->space_global, &stat);
+ stat.vm_threshold = val;
+ gs_memory_set_gc_status(idmemory->space_global, &stat);
+ gs_memory_gc_status(idmemory->space_local, &stat);
+ stat.vm_threshold = val;
+ gs_memory_set_gc_status(idmemory->space_local, &stat);
+ return 0;
+}
+
+/*
+ * <int> .vmreclaim -
+ *
+ * This implements only immediate garbage collection: enabling and
+ * disabling GC is implemented by calling setuserparams.
+ */
+int
+set_vm_reclaim(long val)
+{
+ if (val >= -2 && val <= 0) {
+ gs_memory_gc_status_t stat;
+
+ gs_memory_gc_status(idmemory->space_system, &stat);
+ stat.enabled = val >= -1;
+ gs_memory_set_gc_status(idmemory->space_system, &stat);
+ gs_memory_gc_status(idmemory->space_global, &stat);
+ stat.enabled = val >= -1;
+ gs_memory_set_gc_status(idmemory->space_global, &stat);
+ gs_memory_gc_status(idmemory->space_local, &stat);
+ stat.enabled = val == 0;
+ gs_memory_set_gc_status(idmemory->space_local, &stat);
+ return 0;
+ } else
+ return_error(e_rangecheck);
+}
+private int
+zvmreclaim(register os_ptr op)
+{
+ check_type(*op, t_integer);
+ if (op->value.intval == 1 || op->value.intval == 2) {
+ /* Force the interpreter to store its state and exit. */
+ /* The interpreter's caller will do the actual GC. */
+ return_error(e_VMreclaim);
+ }
+ return_error(e_rangecheck);
+}
+
+/* ------ Initialization procedure ------ */
+
+/* The VM operators are defined even if the initial language level is 1, */
+/* because we need them during initialization. */
+const op_def zvmem2_op_defs[] =
+{
+ {"0.currentglobal", zcurrentglobal},
+ {"1.gcheck", zgcheck},
+ {"1.setglobal", zsetglobal},
+ /* The rest of the operators are defined only in Level 2. */
+ op_def_begin_level2(),
+ {"1.vmreclaim", zvmreclaim},
+ op_def_end(0)
+};
diff --git a/scheduler/.cvsignore b/scheduler/.cvsignore
new file mode 100644
index 000000000..bec82db23
--- /dev/null
+++ b/scheduler/.cvsignore
@@ -0,0 +1,3 @@
+cupsd
+cups-polld
+cups-lpd
diff --git a/scheduler/Makefile b/scheduler/Makefile
new file mode 100644
index 000000000..333073d72
--- /dev/null
+++ b/scheduler/Makefile
@@ -0,0 +1,145 @@
+#
+# "$Id$"
+#
+# Scheduler Makefile for the Common UNIX Printing System (CUPS).
+#
+# Copyright 1997-2002 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
+
+CUPSDOBJS = auth.o banners.o cert.o classes.o client.o conf.o devices.o \
+ dirsvc.o main.o ipp.o listen.o job.o log.o ppds.o printers.o \
+ quotas.o server.o
+MIMEOBJS = filter.o mime.o type.o
+OBJS = $(CUPSDOBJS) $(MIMEOBJS) cups-lpd.o cups-polld.o testmime.o \
+ testspeed.o
+
+
+#
+# Make everything...
+#
+
+all: cupsd cups-lpd cups-polld libmime.a
+
+
+#
+# Clean all object files...
+#
+
+clean:
+ $(RM) $(OBJS) cupsd cups-lpd cups-polld libmime.a testmime testspeed
+
+
+#
+# Install the scheduler...
+#
+
+install:
+ $(INSTALL_DIR) $(SBINDIR)
+ $(INSTALL_BIN) cupsd $(SBINDIR)
+ $(INSTALL_DIR) $(SERVERBIN)/daemon
+ $(INSTALL_BIN) cups-lpd $(SERVERBIN)/daemon
+ $(INSTALL_BIN) cups-polld $(SERVERBIN)/daemon
+ $(INSTALL_DIR) -m 711 -o $(CUPS_USER) -g $(CUPS_GROUP) $(SERVERROOT)/certs
+ $(INSTALL_DIR) $(SERVERROOT)/interfaces
+ $(INSTALL_DIR) $(SERVERROOT)/ppd
+ $(INSTALL_DIR) $(LOGDIR)
+ $(INSTALL_DIR) -m 700 -o $(CUPS_USER) -g $(CUPS_GROUP) $(REQUESTS)
+ $(INSTALL_DIR) -m 1700 -o $(CUPS_USER) -g $(CUPS_GROUP) $(REQUESTS)/tmp
+
+
+#
+# Make the scheduler executable, "cupsd".
+#
+
+cupsd: $(CUPSDOBJS) libmime.a ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o cupsd $(CUPSDOBJS) libmime.a \
+ $(LIBZ) $(SSLLIBS) $(LIBSLP) $(PAMLIBS) $(LIBS) $(LIBMALLOC)
+
+$(CUPSDOBJS): auth.h banners.h cert.h classes.h client.h conf.h \
+ cupsd.h dirsvc.h job.h mime.h printers.h \
+ ../cups/cups.h ../cups/http.h ../cups/ipp.h \
+ ../cups/language.h ../cups/string.h
+
+
+#
+# Make the line printer daemon, "cups-lpd".
+#
+
+cups-lpd: cups-lpd.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o cups-lpd cups-lpd.o $(LIBS)
+
+cups-lpd.o: ../cups/cups.h ../cups/http.h ../cups/ipp.h \
+ ../cups/language.h ../cups/string.h
+
+
+#
+# Make the polling daemon, "cups-polld".
+#
+
+cups-polld: cups-polld.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o cups-polld cups-polld.o $(LIBS)
+
+cups-polld.o: ../cups/cups.h ../cups/http.h ../cups/ipp.h \
+ ../cups/language.h ../cups/string.h
+
+
+#
+# libmime.a
+#
+
+libmime.a: $(MIMEOBJS)
+ echo Archiving $@...
+ $(RM) $@
+ $(AR) $(ARFLAGS) $@ $(MIMEOBJS)
+ $(RANLIB) $@
+
+$(MIMEOBJS): mime.h
+
+
+#
+# testmime
+#
+
+testmime: testmime.o libmime.a
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ testmime.o libmime.a ../cups/libcups.a
+
+testmime.o: mime.h
+
+#
+# Make the test program, "testspeed".
+#
+
+testspeed: testspeed.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o testspeed testspeed.o $(LIBS)
+
+testspeed.o: ../cups/cups.h ../cups/http.h ../cups/ipp.h ../cups/language.h
+
+$(OBJS): ../config.h ../Makedefs
+
+
+#
+# End of "$Id$".
+#
diff --git a/scheduler/auth.c b/scheduler/auth.c
new file mode 100644
index 000000000..4fb555bba
--- /dev/null
+++ b/scheduler/auth.c
@@ -0,0 +1,1498 @@
+/*
+ * "$Id$"
+ *
+ * Authorization routines for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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:
+ *
+ * AddLocation() - Add a location for authorization.
+ * AddName() - Add a name to a location...
+ * AllowHost() - Add a host name that is allowed to access the
+ * location.
+ * AllowIP() - Add an IP address or network that is allowed to
+ * access the location.
+ * CheckAuth() - Check authorization masks.
+ * CopyLocation() - Make a copy of a location...
+ * DeleteAllLocations() - Free all memory used for location authorization.
+ * DenyHost() - Add a host name that is not allowed to access the
+ * location.
+ * DenyIP() - Add an IP address or network that is not allowed
+ * to access the location.
+ * FindBest() - Find the location entry that best matches the
+ * resource.
+ * FindLocation() - Find the named location.
+ * IsAuthorized() - Check to see if the user is authorized...
+ * add_allow() - Add an allow mask to the location.
+ * add_deny() - Add a deny mask to the location.
+ * cups_crypt() - Encrypt the password using the DES or MD5
+ * algorithms, as needed.
+ * get_md5_passwd() - Get an MD5 password.
+ * pam_func() - PAM conversation function.
+ * to64() - Base64-encode an integer value...
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cupsd.h"
+#include <pwd.h>
+#include <grp.h>
+#include <cups/md5.h>
+#ifdef HAVE_SHADOW_H
+# include <shadow.h>
+#endif /* HAVE_SHADOW_H */
+#ifdef HAVE_CRYPT_H
+# include <crypt.h>
+#endif /* HAVE_CRYPT_H */
+#if HAVE_LIBPAM
+# include <security/pam_appl.h>
+#endif /* HAVE_LIBPAM */
+#ifdef HAVE_USERSEC_H
+# include <usersec.h>
+#endif /* HAVE_USERSEC_H */
+
+
+/*
+ * Local functions...
+ */
+
+static authmask_t *add_allow(location_t *loc);
+static authmask_t *add_deny(location_t *loc);
+#if !HAVE_LIBPAM
+static char *cups_crypt(const char *pw, const char *salt);
+#endif /* !HAVE_LIBPAM */
+static char *get_md5_passwd(const char *username, const char *group,
+ char passwd[33]);
+#if HAVE_LIBPAM
+static int pam_func(int, const struct pam_message **,
+ struct pam_response **, void *);
+#else
+static void to64(char *s, unsigned long v, int n);
+#endif /* HAVE_LIBPAM */
+
+
+/*
+ * Local globals...
+ */
+
+#ifdef __hpux
+static client_t *auth_client; /* Current client being authenticated */
+#endif /* __hpux */
+
+
+/*
+ * 'AddLocation()' - Add a location for authorization.
+ */
+
+location_t * /* O - Pointer to new location record */
+AddLocation(const char *location) /* I - Location path */
+{
+ location_t *temp; /* New location */
+
+
+ /*
+ * Try to allocate memory for the new location.
+ */
+
+ if (NumLocations == 0)
+ temp = malloc(sizeof(location_t));
+ else
+ temp = realloc(Locations, sizeof(location_t) * (NumLocations + 1));
+
+ if (temp == NULL)
+ return (NULL);
+
+ Locations = temp;
+ temp += NumLocations;
+ NumLocations ++;
+
+ /*
+ * Initialize the record and copy the name over...
+ */
+
+ memset(temp, 0, sizeof(location_t));
+ strncpy(temp->location, location, sizeof(temp->location) - 1);
+ temp->length = strlen(temp->location);
+
+ LogMessage(L_DEBUG, "AddLocation: added location \'%s\'", location);
+
+ /*
+ * Return the new record...
+ */
+
+ return (temp);
+}
+
+
+/*
+ * 'AddName()' - Add a name to a location...
+ */
+
+void
+AddName(location_t *loc, /* I - Location to add to */
+ char *name) /* I - Name to add */
+{
+ char **temp; /* Pointer to names array */
+
+
+ if (loc->num_names == 0)
+ temp = malloc(sizeof(char *));
+ else
+ temp = realloc(loc->names, (loc->num_names + 1) * sizeof(char *));
+
+ if (temp == NULL)
+ {
+ LogMessage(L_ERROR, "Unable to add name to location %s: %s", loc->location,
+ strerror(errno));
+ return;
+ }
+
+ loc->names = temp;
+
+ if ((temp[loc->num_names] = strdup(name)) == NULL)
+ {
+ LogMessage(L_ERROR, "Unable to duplicate name for location %s: %s",
+ loc->location, strerror(errno));
+ return;
+ }
+
+ loc->num_names ++;
+}
+
+
+/*
+ * 'AllowHost()' - Add a host name that is allowed to access the location.
+ */
+
+void
+AllowHost(location_t *loc, /* I - Location to add to */
+ char *name) /* I - Name of host or domain to add */
+{
+ authmask_t *temp; /* New host/domain mask */
+
+
+ if ((temp = add_allow(loc)) == NULL)
+ return;
+
+ temp->type = AUTH_NAME;
+ temp->mask.name.name = strdup(name);
+ temp->mask.name.length = strlen(name);
+
+ LogMessage(L_DEBUG, "AllowHost: %s allow %s", loc->location, name);
+}
+
+
+/*
+ * 'AllowIP()' - Add an IP address or network that is allowed to access the
+ * location.
+ */
+
+void
+AllowIP(location_t *loc, /* I - Location to add to */
+ unsigned address, /* I - IP address to add */
+ unsigned netmask) /* I - Netmask of address */
+{
+ authmask_t *temp; /* New host/domain mask */
+
+
+ if ((temp = add_allow(loc)) == NULL)
+ return;
+
+ temp->type = AUTH_IP;
+ temp->mask.ip.address = address;
+ temp->mask.ip.netmask = netmask;
+
+ LogMessage(L_DEBUG, "AllowIP: %s allow %08x/%08x", loc->location,
+ address, netmask);
+}
+
+
+/*
+ * 'CheckAuth()' - Check authorization masks.
+ */
+
+int /* O - 1 if mask matches, 0 otherwise */
+CheckAuth(unsigned ip, /* I - Client address */
+ char *name, /* I - Client hostname */
+ int name_len, /* I - Length of hostname */
+ int num_masks, /* I - Number of masks */
+ authmask_t *masks) /* I - Masks */
+{
+ while (num_masks > 0)
+ {
+ switch (masks->type)
+ {
+ case AUTH_NAME :
+ /*
+ * Check for exact name match...
+ */
+
+ if (strcasecmp(name, masks->mask.name.name) == 0)
+ return (1);
+
+ /*
+ * Check for domain match...
+ */
+
+ if (name_len >= masks->mask.name.length &&
+ masks->mask.name.name[0] == '.' &&
+ strcasecmp(name + name_len - masks->mask.name.length,
+ masks->mask.name.name) == 0)
+ return (1);
+ break;
+
+ case AUTH_IP :
+ /*
+ * Check for IP/network address match...
+ */
+
+ if ((ip & masks->mask.ip.netmask) == masks->mask.ip.address)
+ return (1);
+ break;
+ }
+
+ masks ++;
+ num_masks --;
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'CopyLocation()' - Make a copy of a location...
+ */
+
+location_t * /* O - New location */
+CopyLocation(location_t **loc) /* IO - Original location */
+{
+ int i; /* Looping var */
+ int locindex; /* Index into Locations array */
+ location_t *temp; /* New location */
+
+
+ /*
+ * Add the new location, updating the original location
+ * pointer as needed...
+ */
+
+ locindex = *loc - Locations;
+
+ if ((temp = AddLocation((*loc)->location)) == NULL)
+ return (NULL);
+
+ *loc = Locations + locindex;
+
+ /*
+ * Copy the information from the original location to the new one.
+ */
+
+ temp->limit = (*loc)->limit;
+ temp->order_type = (*loc)->order_type;
+ temp->type = (*loc)->type;
+ temp->level = (*loc)->level;
+ temp->satisfy = (*loc)->satisfy;
+ temp->encryption = (*loc)->encryption;
+
+ if ((temp->num_names = (*loc)->num_names) > 0)
+ {
+ /*
+ * Copy the names array...
+ */
+
+ if ((temp->names = calloc(temp->num_names, sizeof(char *))) == NULL)
+ {
+ LogMessage(L_ERROR, "CopyLocation: Unable to allocate memory for %d names: %s",
+ temp->num_names, strerror(errno));
+ NumLocations --;
+ return (NULL);
+ }
+
+ for (i = 0; i < temp->num_names; i ++)
+ if ((temp->names[i] = strdup((*loc)->names[i])) == NULL)
+ {
+ LogMessage(L_ERROR, "CopyLocation: Unable to copy name \"%s\": %s",
+ (*loc)->names[i], strerror(errno));
+
+ NumLocations --;
+ return (NULL);
+ }
+ }
+
+ if ((temp->num_allow = (*loc)->num_allow) > 0)
+ {
+ /*
+ * Copy allow rules...
+ */
+
+ if ((temp->allow = calloc(temp->num_allow, sizeof(authmask_t))) == NULL)
+ {
+ LogMessage(L_ERROR, "CopyLocation: Unable to allocate memory for %d allow rules: %s",
+ temp->num_allow, strerror(errno));
+ NumLocations --;
+ return (NULL);
+ }
+
+ for (i = 0; i < temp->num_allow; i ++)
+ switch (temp->allow[i].type = (*loc)->allow[i].type)
+ {
+ case AUTH_NAME :
+ temp->allow[i].mask.name.length = (*loc)->allow[i].mask.name.length;
+ temp->allow[i].mask.name.name = strdup((*loc)->allow[i].mask.name.name);
+
+ if (temp->allow[i].mask.name.name == NULL)
+ {
+ LogMessage(L_ERROR, "CopyLocation: Unable to copy allow name \"%s\": %s",
+ (*loc)->allow[i].mask.name.name, strerror(errno));
+ NumLocations --;
+ return (NULL);
+ }
+ break;
+ case AUTH_IP :
+ memcpy(&(temp->allow[i].mask.ip), &((*loc)->allow[i].mask.ip),
+ sizeof(ipmask_t));
+ break;
+ }
+ }
+
+ if ((temp->num_deny = (*loc)->num_deny) > 0)
+ {
+ /*
+ * Copy deny rules...
+ */
+
+ if ((temp->deny = calloc(temp->num_deny, sizeof(authmask_t))) == NULL)
+ {
+ LogMessage(L_ERROR, "CopyLocation: Unable to allocate memory for %d deny rules: %s",
+ temp->num_deny, strerror(errno));
+ NumLocations --;
+ return (NULL);
+ }
+
+ for (i = 0; i < temp->num_deny; i ++)
+ switch (temp->deny[i].type = (*loc)->deny[i].type)
+ {
+ case AUTH_NAME :
+ temp->deny[i].mask.name.length = (*loc)->deny[i].mask.name.length;
+ temp->deny[i].mask.name.name = strdup((*loc)->deny[i].mask.name.name);
+
+ if (temp->deny[i].mask.name.name == NULL)
+ {
+ LogMessage(L_ERROR, "CopyLocation: Unable to copy deny name \"%s\": %s",
+ (*loc)->deny[i].mask.name.name, strerror(errno));
+ NumLocations --;
+ return (NULL);
+ }
+ break;
+ case AUTH_IP :
+ memcpy(&(temp->deny[i].mask.ip), &((*loc)->deny[i].mask.ip),
+ sizeof(ipmask_t));
+ break;
+ }
+ }
+
+ return (temp);
+}
+
+
+/*
+ * 'DeleteAllLocations()' - Free all memory used for location authorization.
+ */
+
+void
+DeleteAllLocations(void)
+{
+ int i, j; /* Looping vars */
+ location_t *loc; /* Current location */
+ authmask_t *mask; /* Current mask */
+
+
+ /*
+ * Free all of the allow/deny records first...
+ */
+
+ for (i = NumLocations, loc = Locations; i > 0; i --, loc ++)
+ {
+ for (j = loc->num_names - 1; j >= 0; j --)
+ free(loc->names[j]);
+
+ if (loc->num_names > 0)
+ free(loc->names);
+
+ for (j = loc->num_allow, mask = loc->allow; j > 0; j --, mask ++)
+ if (mask->type == AUTH_NAME)
+ free(mask->mask.name.name);
+
+ if (loc->num_allow > 0)
+ free(loc->allow);
+
+ for (j = loc->num_deny, mask = loc->deny; j > 0; j --, mask ++)
+ if (mask->type == AUTH_NAME)
+ free(mask->mask.name.name);
+
+ if (loc->num_deny > 0)
+ free(loc->deny);
+ }
+
+ /*
+ * Then free the location array...
+ */
+
+ if (NumLocations > 0)
+ free(Locations);
+
+ Locations = NULL;
+ NumLocations = 0;
+}
+
+
+/*
+ * 'DenyHost()' - Add a host name that is not allowed to access the location.
+ */
+
+void
+DenyHost(location_t *loc, /* I - Location to add to */
+ char *name) /* I - Name of host or domain to add */
+{
+ authmask_t *temp; /* New host/domain mask */
+
+
+ if ((temp = add_deny(loc)) == NULL)
+ return;
+
+ temp->type = AUTH_NAME;
+ temp->mask.name.name = strdup(name);
+ temp->mask.name.length = strlen(name);
+
+ LogMessage(L_DEBUG, "DenyHost: %s deny %s", loc->location, name);
+}
+
+
+/*
+ * 'DenyIP()' - Add an IP address or network that is not allowed to access
+ * the location.
+ */
+
+void
+DenyIP(location_t *loc, /* I - Location to add to */
+ unsigned address, /* I - IP address to add */
+ unsigned netmask) /* I - Netmask of address */
+{
+ authmask_t *temp; /* New host/domain mask */
+
+
+ if ((temp = add_deny(loc)) == NULL)
+ return;
+
+ temp->type = AUTH_IP;
+ temp->mask.ip.address = address;
+ temp->mask.ip.netmask = netmask;
+
+ LogMessage(L_DEBUG, "DenyIP: %s deny %08x/%08x\n", loc->location,
+ address, netmask);
+}
+
+
+/*
+ * 'FindBest()' - Find the location entry that best matches the resource.
+ */
+
+location_t * /* O - Location that matches */
+FindBest(const char *path, /* I - Resource path */
+ http_state_t state) /* I - HTTP state/request */
+{
+ int i; /* Looping var */
+ char uri[HTTP_MAX_URI],
+ /* URI in request... */
+ *uriptr; /* Pointer into URI */
+ location_t *loc, /* Current location */
+ *best; /* Best match for location so far */
+ int bestlen; /* Length of best match */
+ int limit; /* Limit field */
+ static int limits[] = /* Map http_status_t to AUTH_LIMIT_xyz */
+ {
+ AUTH_LIMIT_ALL,
+ AUTH_LIMIT_OPTIONS,
+ AUTH_LIMIT_GET,
+ AUTH_LIMIT_GET,
+ AUTH_LIMIT_HEAD,
+ AUTH_LIMIT_POST,
+ AUTH_LIMIT_POST,
+ AUTH_LIMIT_POST,
+ AUTH_LIMIT_PUT,
+ AUTH_LIMIT_PUT,
+ AUTH_LIMIT_DELETE,
+ AUTH_LIMIT_TRACE,
+ AUTH_LIMIT_ALL,
+ AUTH_LIMIT_ALL
+ };
+
+
+ /*
+ * First copy the connection URI to a local string so we have drop
+ * any .ppd extension from the pathname in /printers or /classes
+ * URIs...
+ */
+
+ strncpy(uri, path, sizeof(uri) - 1);
+ uri[sizeof(uri) - 1] = '\0';
+
+ if (strncmp(uri, "/printers/", 10) == 0 ||
+ strncmp(uri, "/classes/", 9) == 0)
+ {
+ /*
+ * Check if the URI has .ppd on the end...
+ */
+
+ uriptr = uri + strlen(uri) - 4; /* len > 4 if we get here... */
+
+ if (strcmp(uriptr, ".ppd") == 0)
+ *uriptr = '\0';
+ }
+
+ LogMessage(L_DEBUG2, "FindBest: uri = \"%s\"...", uri);
+
+ /*
+ * Loop through the list of locations to find a match...
+ */
+
+ limit = limits[state];
+ best = NULL;
+ bestlen = 0;
+
+ for (i = NumLocations, loc = Locations; i > 0; i --, loc ++)
+ {
+ LogMessage(L_DEBUG2, "FindBest: Location %s Limit %x",
+ loc->location, loc->limit);
+
+ if (loc->length > bestlen &&
+ strncmp(uri, loc->location, loc->length) == 0 &&
+ loc->location[0] == '/' &&
+ (limit & loc->limit) != 0)
+ {
+ best = loc;
+ bestlen = loc->length;
+ }
+ }
+
+ /*
+ * Return the match, if any...
+ */
+
+ LogMessage(L_DEBUG2, "FindBest: best = \"%s\"",
+ best ? best->location : "NONE");
+
+ return (best);
+}
+
+
+/*
+ * 'FindLocation()' - Find the named location.
+ */
+
+location_t * /* O - Location that matches */
+FindLocation(const char *location) /* I - Connection */
+{
+ int i; /* Looping var */
+
+
+ /*
+ * Loop through the list of locations to find a match...
+ */
+
+ for (i = 0; i < NumLocations; i ++)
+ if (strcasecmp(Locations[i].location, location) == 0)
+ return (Locations + i);
+
+ return (NULL);
+}
+
+
+/*
+ * 'IsAuthorized()' - Check to see if the user is authorized...
+ */
+
+http_status_t /* O - HTTP_OK if authorized or error code */
+IsAuthorized(client_t *con) /* I - Connection */
+{
+ int i, j, /* Looping vars */
+ auth; /* Authorization status */
+ unsigned address; /* Authorization address */
+ location_t *best; /* Best match for location so far */
+ int hostlen; /* Length of hostname */
+ struct passwd *pw; /* User password data */
+ struct group *grp; /* Group data */
+ char nonce[HTTP_MAX_VALUE],
+ /* Nonce value from client */
+ md5[33], /* MD5 password */
+ basicmd5[33]; /* MD5 of Basic password */
+#if HAVE_LIBPAM
+ pam_handle_t *pamh; /* PAM authentication handle */
+ int pamerr; /* PAM error code */
+ struct pam_conv pamdata; /* PAM conversation data */
+#elif defined(HAVE_USERSEC_H)
+ char *authmsg; /* Authentication message */
+ char *loginmsg; /* Login message */
+ int reenter; /* ??? */
+#else
+ char *pass; /* Encrypted password */
+# ifdef HAVE_SHADOW_H
+ struct spwd *spw; /* Shadow password data */
+# endif /* HAVE_SHADOW_H */
+#endif /* HAVE_LIBPAM */
+ static const char *states[] = /* HTTP client states... */
+ {
+ "WAITING",
+ "OPTIONS",
+ "GET",
+ "GET",
+ "HEAD",
+ "POST",
+ "POST",
+ "POST",
+ "PUT",
+ "PUT",
+ "DELETE",
+ "TRACE",
+ "CLOSE",
+ "STATUS"
+ };
+
+
+ LogMessage(L_DEBUG2, "IsAuthorized: con->uri = \"%s\"", con->uri);
+
+ /*
+ * Find a matching location; if there is no match then access is
+ * not authorized...
+ */
+
+ if ((best = FindBest(con->uri, con->http.state)) == NULL)
+ return (HTTP_FORBIDDEN);
+
+ /*
+ * Check host/ip-based accesses...
+ */
+
+ address = ntohl(con->http.hostaddr.sin_addr.s_addr);
+ hostlen = strlen(con->http.hostname);
+
+ if (address == 0x7f000001 || strcasecmp(con->http.hostname, "localhost") == 0)
+ {
+ /*
+ * Access from localhost (127.0.0.1) is always allowed...
+ */
+
+ auth = AUTH_ALLOW;
+ }
+ else if (best->num_allow == 0 && best->num_deny == 0)
+ {
+ /*
+ * No allow/deny lines - allow access...
+ */
+
+ auth = AUTH_ALLOW;
+ }
+ else
+ {
+ /*
+ * Do authorization checks on the domain/address...
+ */
+
+ switch (best->order_type)
+ {
+ default :
+ auth = AUTH_DENY; /* anti-compiler-warning-code */
+ break;
+
+ case AUTH_ALLOW : /* Order Deny,Allow */
+ auth = AUTH_ALLOW;
+
+ if (CheckAuth(address, con->http.hostname, hostlen,
+ best->num_deny, best->deny))
+ auth = AUTH_DENY;
+
+ if (CheckAuth(address, con->http.hostname, hostlen,
+ best->num_allow, best->allow))
+ auth = AUTH_ALLOW;
+ break;
+
+ case AUTH_DENY : /* Order Allow,Deny */
+ auth = AUTH_DENY;
+
+ if (CheckAuth(address, con->http.hostname, hostlen,
+ best->num_allow, best->allow))
+ auth = AUTH_ALLOW;
+
+ if (CheckAuth(address, con->http.hostname, hostlen,
+ best->num_deny, best->deny))
+ auth = AUTH_DENY;
+ break;
+ }
+ }
+
+ LogMessage(L_DEBUG2, "IsAuthorized: auth = %d, satisfy=%d...",
+ auth, best->satisfy);
+
+ if (auth == AUTH_DENY && best->satisfy == AUTH_SATISFY_ALL)
+ return (HTTP_FORBIDDEN);
+
+#ifdef HAVE_LIBSSL
+ /*
+ * See if encryption is required...
+ */
+
+ if (best->encryption >= HTTP_ENCRYPT_REQUIRED && !con->http.tls)
+ {
+ LogMessage(L_DEBUG2, "IsAuthorized: Need upgrade to TLS...");
+ return (HTTP_UPGRADE_REQUIRED);
+ }
+#endif /* HAVE_LIBSSL */
+
+ /*
+ * Now see what access level is required...
+ */
+
+ if (best->level == AUTH_ANON) /* Anonymous access - allow it */
+ return (HTTP_OK);
+
+ LogMessage(L_DEBUG2, "IsAuthorized: username = \"%s\" password = %d chars",
+ con->username, strlen(con->password));
+ DEBUG_printf(("IsAuthorized: username = \"%s\", password = \"%s\"\n",
+ con->username, con->password));
+
+ if (con->username[0] == '\0')
+ {
+ if (best->satisfy == AUTH_SATISFY_ALL || auth == AUTH_DENY)
+ return (HTTP_UNAUTHORIZED); /* Non-anonymous needs user/pass */
+ else
+ return (HTTP_OK); /* unless overridden with Satisfy */
+ }
+
+ /*
+ * Check the user's password...
+ */
+
+ LogMessage(L_DEBUG2, "IsAuthorized: Checking \"%s\", address = %08x, hostname = \"%s\"",
+ con->username, address, con->http.hostname);
+
+ pw = NULL;
+
+ if ((address != 0x7f000001 &&
+ strcasecmp(con->http.hostname, "localhost") != 0) ||
+ strncmp(con->http.fields[HTTP_FIELD_AUTHORIZATION], "Local", 5) != 0)
+ {
+ /*
+ * Not doing local certificate-based authentication; check the password...
+ */
+
+ if (!con->password[0])
+ return (HTTP_UNAUTHORIZED);
+
+ /*
+ * See what kind of authentication we are doing...
+ */
+
+ switch (best->type)
+ {
+ case AUTH_BASIC :
+ /*
+ * Get the user info...
+ */
+
+ pw = getpwnam(con->username); /* Get the current password */
+ endpwent(); /* Close the password file */
+
+ if (pw == NULL) /* No such user... */
+ {
+ LogMessage(L_WARN, "IsAuthorized: Unknown username \"%s\"; access denied.",
+ con->username);
+ return (HTTP_UNAUTHORIZED);
+ }
+
+#if HAVE_LIBPAM
+ /*
+ * Only use PAM to do authentication. This allows MD5 passwords, among
+ * other things...
+ */
+
+ pamdata.conv = pam_func;
+ pamdata.appdata_ptr = con;
+
+# ifdef __hpux
+ /*
+ * Workaround for HP-UX bug in pam_unix; see pam_conv() below for
+ * more info...
+ */
+
+ auth_client = con;
+# endif /* __hpux */
+
+ DEBUG_printf(("IsAuthorized: Setting appdata_ptr = %p\n", con));
+
+ pamerr = pam_start("cups", con->username, &pamdata, &pamh);
+ if (pamerr != PAM_SUCCESS)
+ {
+ LogMessage(L_ERROR, "IsAuthorized: pam_start() returned %d (%s)!\n",
+ pamerr, pam_strerror(pamh, pamerr));
+ pam_end(pamh, 0);
+ return (HTTP_UNAUTHORIZED);
+ }
+
+ pamerr = pam_authenticate(pamh, PAM_SILENT);
+ if (pamerr != PAM_SUCCESS)
+ {
+ LogMessage(L_ERROR, "IsAuthorized: pam_authenticate() returned %d (%s)!\n",
+ pamerr, pam_strerror(pamh, pamerr));
+ pam_end(pamh, 0);
+ return (HTTP_UNAUTHORIZED);
+ }
+
+ pamerr = pam_acct_mgmt(pamh, PAM_SILENT);
+ if (pamerr != PAM_SUCCESS)
+ {
+ LogMessage(L_ERROR, "IsAuthorized: pam_acct_mgmt() returned %d (%s)!\n",
+ pamerr, pam_strerror(pamh, pamerr));
+ pam_end(pamh, 0);
+ return (HTTP_UNAUTHORIZED);
+ }
+
+ pam_end(pamh, PAM_SUCCESS);
+#elif defined(HAVE_USERSEC_H)
+ /*
+ * Use AIX authentication interface...
+ */
+
+ LogMessage(L_DEBUG, "IsAuthorized: AIX authenticate of username \"%s\"",
+ con->username);
+
+ reenter = 1;
+ if (authenticate(con->username, con->password, &reenter, &authmsg) != 0)
+ {
+ LogMessage(L_DEBUG, "IsAuthorized: Unable to authenticate username \"%s\": %s",
+ con->username, strerror(errno));
+ return (HTTP_UNAUTHORIZED);
+ }
+#else
+# ifdef HAVE_SHADOW_H
+ spw = getspnam(con->username);
+ endspent();
+
+ if (spw == NULL && strcmp(pw->pw_passwd, "x") == 0)
+ { /* Don't allow blank passwords! */
+ LogMessage(L_WARN, "IsAuthorized: Username \"%s\" has no shadow password; access denied.",
+ con->username);
+ return (HTTP_UNAUTHORIZED); /* No such user or bad shadow file */
+ }
+
+# ifdef DEBUG
+ if (spw != NULL)
+ printf("spw->sp_pwdp = \"%s\"\n", spw->sp_pwdp);
+ else
+ puts("spw = NULL");
+# endif /* DEBUG */
+
+ if (spw != NULL && spw->sp_pwdp[0] == '\0' && pw->pw_passwd[0] == '\0')
+# else
+ if (pw->pw_passwd[0] == '\0')
+# endif /* HAVE_SHADOW_H */
+ { /* Don't allow blank passwords! */
+ LogMessage(L_WARN, "IsAuthorized: Username \"%s\" has no password; access denied.",
+ con->username);
+ return (HTTP_UNAUTHORIZED);
+ }
+
+ /*
+ * OK, the password isn't blank, so compare with what came from the client...
+ */
+
+ pass = cups_crypt(con->password, pw->pw_passwd);
+
+ LogMessage(L_DEBUG2, "IsAuthorized: pw_passwd = %s, crypt = %s",
+ pw->pw_passwd, pass);
+
+ if (pass == NULL || strcmp(pw->pw_passwd, pass) != 0)
+ {
+# ifdef HAVE_SHADOW_H
+ if (spw != NULL)
+ {
+ pass = cups_crypt(con->password, spw->sp_pwdp);
+
+ LogMessage(L_DEBUG2, "IsAuthorized: sp_pwdp = %s, crypt = %s",
+ spw->sp_pwdp, pass);
+
+ if (pass == NULL || strcmp(spw->sp_pwdp, pass) != 0)
+ return (HTTP_UNAUTHORIZED);
+ }
+ else
+# endif /* HAVE_SHADOW_H */
+ return (HTTP_UNAUTHORIZED);
+ }
+#endif /* HAVE_LIBPAM */
+ break;
+
+ case AUTH_DIGEST :
+ /*
+ * Do Digest authentication...
+ */
+
+ if (!httpGetSubField(&(con->http), HTTP_FIELD_AUTHORIZATION, "nonce",
+ nonce))
+ {
+ LogMessage(L_ERROR, "IsAuthorized: No nonce value for Digest authentication!");
+ return (HTTP_UNAUTHORIZED);
+ }
+
+ if (strcmp(con->http.hostname, nonce) != 0)
+ {
+ LogMessage(L_ERROR, "IsAuthorized: Nonce value error!");
+ LogMessage(L_ERROR, "IsAuthorized: Expected \"%s\",",
+ con->http.hostname);
+ LogMessage(L_ERROR, "IsAuthorized: Got \"%s\"!", nonce);
+ return (HTTP_UNAUTHORIZED);
+ }
+
+ LogMessage(L_DEBUG2, "IsAuthorized: nonce = \"%s\"", nonce);
+
+ if (best->num_names && best->level == AUTH_GROUP)
+ {
+ for (i = 0; i < best->num_names; i ++)
+ if (get_md5_passwd(con->username, best->names[i], md5))
+ break;
+
+ if (i >= best->num_names)
+ md5[0] = '\0';
+ }
+ else if (!get_md5_passwd(con->username, NULL, md5))
+ md5[0] = '\0';
+
+
+ if (!md5[0])
+ {
+ LogMessage(L_ERROR, "IsAuthorized: No matching user:group for \"%s\" in passwd.md5!",
+ con->username);
+ return (HTTP_UNAUTHORIZED);
+ }
+
+ httpMD5Final(nonce, states[con->http.state], con->uri, md5);
+
+ if (strcmp(md5, con->password) != 0)
+ {
+ LogMessage(L_ERROR, "IsAuthorized: MD5s \"%s\" and \"%s\" don't match!",
+ md5, con->password);
+ return (HTTP_UNAUTHORIZED);
+ }
+ break;
+
+ case AUTH_BASICDIGEST :
+ /*
+ * Do Basic authentication with the Digest password file...
+ */
+
+ if (best->num_names && best->level == AUTH_GROUP)
+ {
+ for (i = 0; i < best->num_names; i ++)
+ if (get_md5_passwd(con->username, best->names[i], md5))
+ break;
+
+ if (i >= best->num_names)
+ md5[0] = '\0';
+ }
+ else if (!get_md5_passwd(con->username, NULL, md5))
+ md5[0] = '\0';
+
+ if (!md5[0])
+ {
+ LogMessage(L_ERROR, "IsAuthorized: No matching user:group for \"%s\" in passwd.md5!",
+ con->username);
+ return (HTTP_UNAUTHORIZED);
+ }
+
+ httpMD5(con->username, "CUPS", con->password, basicmd5);
+
+ if (strcmp(md5, basicmd5) != 0)
+ {
+ LogMessage(L_ERROR, "IsAuthorized: MD5s \"%s\" and \"%s\" don't match!",
+ md5, basicmd5);
+ return (HTTP_UNAUTHORIZED);
+ }
+ break;
+ }
+ }
+ else
+ {
+ /*
+ * Get password entry for certificate-based auth...
+ */
+
+ pw = getpwnam(con->username); /* Get the current password */
+ endpwent(); /* Close the password file */
+ }
+
+ /*
+ * OK, the password is good. See if we need normal user access, or group
+ * access... (root always matches)
+ */
+
+ if (strcmp(con->username, "root") == 0)
+ return (HTTP_OK);
+
+ if (best->level == AUTH_USER)
+ {
+ /*
+ * If there are no names associated with this location, then
+ * any valid user is OK...
+ */
+
+ LogMessage(L_DEBUG2, "IsAuthorized: Checking user membership...");
+
+ if (best->num_names == 0)
+ return (HTTP_OK);
+
+ /*
+ * Otherwise check the user list and return OK if this user is
+ * allowed...
+ */
+
+ for (i = 0; i < best->num_names; i ++)
+ if (strcmp(con->username, best->names[i]) == 0)
+ return (HTTP_OK);
+
+ return (HTTP_UNAUTHORIZED);
+ }
+
+ if (best->type == AUTH_BASIC)
+ {
+ /*
+ * Check to see if this user is in any of the named groups...
+ */
+
+ LogMessage(L_DEBUG2, "IsAuthorized: Checking group membership...");
+
+ for (i = 0; i < best->num_names; i ++)
+ {
+ grp = getgrnam(best->names[i]);
+ endgrent();
+
+ if (grp == NULL) /* No group by that name??? */
+ {
+ LogMessage(L_WARN, "IsAuthorized: group name \"%s\" does not exist!",
+ best->names[i]);
+ return (HTTP_FORBIDDEN);
+ }
+
+ for (j = 0; grp->gr_mem[j] != NULL; j ++)
+ if (strcmp(con->username, grp->gr_mem[j]) == 0)
+ return (HTTP_OK);
+
+ /*
+ * Check to see if the default group ID matches for the user...
+ */
+
+ if (grp->gr_gid == pw->pw_gid)
+ return (HTTP_OK);
+ }
+
+ /*
+ * The user isn't part of the specified group, so deny access...
+ */
+
+ LogMessage(L_DEBUG2, "IsAuthorized: user not in group!");
+
+ return (HTTP_UNAUTHORIZED);
+ }
+
+ /*
+ * All checks passed...
+ */
+
+ return (HTTP_OK);
+}
+
+
+/*
+ * 'add_allow()' - Add an allow mask to the location.
+ */
+
+static authmask_t * /* O - New mask record */
+add_allow(location_t *loc) /* I - Location to add to */
+{
+ authmask_t *temp; /* New mask record */
+
+
+ /*
+ * Range-check...
+ */
+
+ if (loc == NULL)
+ return (NULL);
+
+ /*
+ * Try to allocate memory for the record...
+ */
+
+ if (loc->num_allow == 0)
+ temp = malloc(sizeof(authmask_t));
+ else
+ temp = realloc(loc->allow, sizeof(authmask_t) * (loc->num_allow + 1));
+
+ if (temp == NULL)
+ return (NULL);
+
+ loc->allow = temp;
+ temp += loc->num_allow;
+ loc->num_allow ++;
+
+ /*
+ * Clear the mask record and return...
+ */
+
+ memset(temp, 0, sizeof(authmask_t));
+ return (temp);
+}
+
+
+/*
+ * 'add_deny()' - Add a deny mask to the location.
+ */
+
+static authmask_t * /* O - New mask record */
+add_deny(location_t *loc) /* I - Location to add to */
+{
+ authmask_t *temp; /* New mask record */
+
+
+ /*
+ * Range-check...
+ */
+
+ if (loc == NULL)
+ return (NULL);
+
+ /*
+ * Try to allocate memory for the record...
+ */
+
+ if (loc->num_deny == 0)
+ temp = malloc(sizeof(authmask_t));
+ else
+ temp = realloc(loc->deny, sizeof(authmask_t) * (loc->num_deny + 1));
+
+ if (temp == NULL)
+ return (NULL);
+
+ loc->deny = temp;
+ temp += loc->num_deny;
+ loc->num_deny ++;
+
+ /*
+ * Clear the mask record and return...
+ */
+
+ memset(temp, 0, sizeof(authmask_t));
+ return (temp);
+}
+
+
+#if !HAVE_LIBPAM
+/*
+ * 'cups_crypt()' - Encrypt the password using the DES or MD5 algorithms,
+ * as needed.
+ */
+
+static char * /* O - Encrypted password */
+cups_crypt(const char *pw, /* I - Password string */
+ const char *salt) /* I - Salt (key) string */
+{
+ if (strncmp(salt, "$1$", 3) == 0)
+ {
+ /*
+ * Use MD5 passwords without the benefit of PAM; this is for
+ * Slackware Linux, and the algorithm was taken from the
+ * old shadow-19990827/lib/md5crypt.c source code... :(
+ */
+
+ int i; /* Looping var */
+ unsigned long n; /* Output number */
+ int pwlen; /* Length of password string */
+ const char *salt_end; /* End of "salt" data for MD5 */
+ char *ptr; /* Pointer into result string */
+ md5_state_t state; /* Primary MD5 state info */
+ md5_state_t state2; /* Secondary MD5 state info */
+ md5_byte_t digest[16]; /* MD5 digest result */
+ static char result[120]; /* Final password string */
+
+
+ /*
+ * Get the salt data between dollar signs, e.g. $1$saltdata$md5.
+ * Get a maximum of 8 characters of salt data after $1$...
+ */
+
+ for (salt_end = salt + 3; *salt_end && (salt_end - salt) < 11; salt_end ++)
+ if (*salt_end == '$')
+ break;
+
+ /*
+ * Compute the MD5 sum we need...
+ */
+
+ pwlen = strlen(pw);
+
+ md5_init(&state);
+ md5_append(&state, pw, pwlen);
+ md5_append(&state, salt, salt_end - salt);
+
+ md5_init(&state2);
+ md5_append(&state2, pw, pwlen);
+ md5_append(&state2, salt + 3, salt_end - salt - 3);
+ md5_append(&state2, pw, pwlen);
+ md5_finish(&state2, digest);
+
+ for (i = pwlen; i > 0; i -= 16)
+ md5_append(&state, digest, i > 16 ? 16 : i);
+
+ for (i = pwlen; i > 0; i >>= 1)
+ md5_append(&state, (i & 1) ? "" : pw, 1);
+
+ md5_finish(&state, digest);
+
+ for (i = 0; i < 1000; i ++)
+ {
+ md5_init(&state);
+
+ if (i & 1)
+ md5_append(&state, pw, pwlen);
+ else
+ md5_append(&state, digest, 16);
+
+ if (i % 3)
+ md5_append(&state, salt + 3, salt_end - salt - 3);
+
+ if (i % 7)
+ md5_append(&state, pw, pwlen);
+
+ if (i & 1)
+ md5_append(&state, digest, 16);
+ else
+ md5_append(&state, pw, pwlen);
+
+ md5_finish(&state, digest);
+ }
+
+ /*
+ * Copy the final sum to the result string and return...
+ */
+
+ memcpy(result, salt, salt_end - salt);
+ ptr = result + (salt_end - salt);
+ *ptr++ = '$';
+
+ for (i = 0; i < 5; i ++, ptr += 4)
+ {
+ n = (((digest[i] << 8) | digest[i + 6]) << 8);
+
+ if (i < 4)
+ n |= digest[i + 12];
+ else
+ n |= digest[5];
+
+ to64(ptr, n, 4);
+ }
+
+ to64(ptr, digest[11], 2);
+ ptr += 2;
+ *ptr = '\0';
+
+ return (result);
+ }
+ else
+ {
+ /*
+ * Use the standard crypt() function...
+ */
+
+ return (crypt(pw, salt));
+ }
+}
+#endif /* !HAVE_LIBPAM */
+
+
+/*
+ * 'get_md5_passwd()' - Get an MD5 password.
+ */
+
+static char * /* O - MD5 password string */
+get_md5_passwd(const char *username, /* I - Username */
+ const char *group, /* I - Group */
+ char passwd[33]) /* O - MD5 password string */
+{
+ FILE *fp; /* passwd.md5 file */
+ char filename[1024], /* passwd.md5 filename */
+ line[256], /* Line from file */
+ tempuser[33], /* User from file */
+ tempgroup[33]; /* Group from file */
+
+
+ snprintf(filename, sizeof(filename), "%s/passwd.md5", ServerRoot);
+ if ((fp = fopen(filename, "r")) == NULL)
+ return (NULL);
+
+ while (fgets(line, sizeof(line), fp) != NULL)
+ {
+ if (sscanf(line, "%32[^:]:%32[^:]:%32s", tempuser, tempgroup, passwd) != 3)
+ continue;
+
+ if (strcmp(username, tempuser) == 0 &&
+ (group == NULL || strcmp(group, tempgroup) == 0))
+ {
+ /*
+ * Found the password entry!
+ */
+
+ fclose(fp);
+ return (passwd);
+ }
+ }
+
+ /*
+ * Didn't find a password entry - return NULL!
+ */
+
+ fclose(fp);
+ return (NULL);
+}
+
+
+#if HAVE_LIBPAM
+/*
+ * 'pam_func()' - PAM conversation function.
+ */
+
+static int /* O - Success or failure */
+pam_func(int num_msg, /* I - Number of messages */
+ const struct pam_message **msg, /* I - Messages */
+ struct pam_response **resp, /* O - Responses */
+ void *appdata_ptr) /* I - Pointer to connection */
+{
+ int i; /* Looping var */
+ struct pam_response *replies; /* Replies */
+ client_t *client; /* Pointer client connection */
+
+
+ /*
+ * Allocate memory for the responses...
+ */
+
+ if ((replies = malloc(sizeof(struct pam_response) * num_msg)) == NULL)
+ return (PAM_CONV_ERR);
+
+ /*
+ * Answer all of the messages...
+ */
+
+ DEBUG_printf(("pam_func: appdata_ptr = %p\n", appdata_ptr));
+
+#ifdef __hpux
+ /*
+ * Apparently some versions of HP-UX 11 have a broken pam_unix security
+ * module. This is a workaround...
+ */
+
+ client = auth_client;
+ (void)appdata_ptr;
+#else
+ client = (client_t *)appdata_ptr;
+#endif /* __hpux */
+
+ for (i = 0; i < num_msg; i ++)
+ {
+ DEBUG_printf(("pam_func: Message = \"%s\"\n", msg[i]->msg));
+
+ switch (msg[i]->msg_style)
+ {
+ case PAM_PROMPT_ECHO_ON:
+ DEBUG_printf(("pam_func: PAM_PROMPT_ECHO_ON, returning \"%s\"...\n",
+ client->username));
+ replies[i].resp_retcode = PAM_SUCCESS;
+ replies[i].resp = strdup(client->username);
+ break;
+
+ case PAM_PROMPT_ECHO_OFF:
+ DEBUG_printf(("pam_func: PAM_PROMPT_ECHO_OFF, returning \"%s\"...\n",
+ client->password));
+ replies[i].resp_retcode = PAM_SUCCESS;
+ replies[i].resp = strdup(client->password);
+ break;
+
+ case PAM_TEXT_INFO:
+ DEBUG_puts("pam_func: PAM_TEXT_INFO...");
+ replies[i].resp_retcode = PAM_SUCCESS;
+ replies[i].resp = NULL;
+ break;
+
+ case PAM_ERROR_MSG:
+ DEBUG_puts("pam_func: PAM_ERROR_MSG...");
+ replies[i].resp_retcode = PAM_SUCCESS;
+ replies[i].resp = NULL;
+ break;
+
+ default:
+ DEBUG_printf(("pam_func: Unknown PAM message %d...\n",
+ msg[i]->msg_style));
+ free(replies);
+ return (PAM_CONV_ERR);
+ }
+ }
+
+ /*
+ * Return the responses back to PAM...
+ */
+
+ *resp = replies;
+
+ return (PAM_SUCCESS);
+}
+#else
+
+
+/*
+ * 'to64()' - Base64-encode an integer value...
+ */
+
+static void
+to64(char *s, /* O - Output string */
+ unsigned long v, /* I - Value to encode */
+ int n) /* I - Number of digits */
+{
+ const char *itoa64 = "./0123456789"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz";
+
+
+ for (; n > 0; n --, v >>= 6)
+ *s++ = itoa64[v & 0x3f];
+}
+#endif /* HAVE_LIBPAM */
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/auth.h b/scheduler/auth.h
new file mode 100644
index 000000000..d792bdcaf
--- /dev/null
+++ b/scheduler/auth.h
@@ -0,0 +1,136 @@
+/*
+ * "$Id$"
+ *
+ * Authorization definitions for the Common UNIX Printing System (CUPS)
+ * scheduler.
+ *
+ * Copyright 1997-2002 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
+ */
+
+/*
+ * HTTP authorization types and levels...
+ */
+
+#define AUTH_NONE 0 /* No authentication */
+#define AUTH_BASIC 1 /* Basic authentication */
+#define AUTH_DIGEST 2 /* Digest authentication */
+#define AUTH_BASICDIGEST 3 /* Basic authentication w/passwd.md5 */
+
+#define AUTH_ANON 0 /* Anonymous access */
+#define AUTH_USER 1 /* Must have a valid username/password */
+#define AUTH_GROUP 2 /* Must also be in a named group */
+
+#define AUTH_ALLOW 0 /* Allow access */
+#define AUTH_DENY 1 /* Deny access */
+
+#define AUTH_NAME 0 /* Authorize host by name */
+#define AUTH_IP 1 /* Authorize host by IP */
+
+#define AUTH_SATISFY_ALL 0 /* Satisfy both address and auth */
+#define AUTH_SATISFY_ANY 1 /* Satisfy either address or auth */
+
+#define AUTH_LIMIT_DELETE 1 /* Limit DELETE requests */
+#define AUTH_LIMIT_GET 2 /* Limit GET requests */
+#define AUTH_LIMIT_HEAD 4 /* Limit HEAD requests */
+#define AUTH_LIMIT_OPTIONS 8 /* Limit OPTIONS requests */
+#define AUTH_LIMIT_POST 16 /* Limit POST requests */
+#define AUTH_LIMIT_PUT 32 /* Limit PUT requests */
+#define AUTH_LIMIT_TRACE 64 /* Limit TRACE requests */
+#define AUTH_LIMIT_ALL 127 /* Limit all requests */
+
+
+/*
+ * HTTP access control structures...
+ */
+
+typedef struct
+{
+ unsigned address, /* IP address */
+ netmask; /* IP netmask */
+} ipmask_t;
+
+typedef struct
+{
+ int length; /* Length of name */
+ char *name; /* Name string */
+} namemask_t;
+
+typedef struct
+{
+ int type; /* Mask type */
+ union
+ {
+ namemask_t name; /* Host/Domain name */
+ ipmask_t ip; /* IP address/network */
+ } mask; /* Mask data */
+} authmask_t;
+
+typedef struct
+{
+ char location[HTTP_MAX_URI]; /* Location of resource */
+ int limit, /* Limit for these types of requests */
+ length, /* Length of location string */
+ order_type, /* Allow or Deny */
+ type, /* Type of authentication */
+ level, /* Access level required */
+ satisfy; /* Satisfy any or all limits? */
+ int num_names; /* Number of names */
+ char **names; /* User or group names */
+ int num_allow; /* Number of Allow lines */
+ authmask_t *allow; /* Allow lines */
+ int num_deny; /* Number of Deny lines */
+ authmask_t *deny; /* Deny lines */
+ http_encryption_t encryption; /* To encrypt or not to encrypt... */
+} location_t;
+
+
+/*
+ * Globals...
+ */
+
+VAR int NumLocations VALUE(0);
+ /* Number of authorization locations */
+VAR location_t *Locations VALUE(NULL);
+ /* Authorization locations */
+
+
+/*
+ * Prototypes...
+ */
+
+extern location_t *AddLocation(const char *location);
+extern void AddName(location_t *loc, char *name);
+extern void AllowHost(location_t *loc, char *name);
+extern void AllowIP(location_t *loc, unsigned address,
+ unsigned netmask);
+extern int CheckAuth(unsigned ip, char *name, int namelen,
+ int num_masks, authmask_t *masks);
+extern location_t *CopyLocation(location_t **loc);
+extern void DeleteAllLocations(void);
+extern void DenyHost(location_t *loc, char *name);
+extern void DenyIP(location_t *loc, unsigned address,
+ unsigned netmask);
+extern location_t *FindBest(const char *path, http_state_t state);
+extern location_t *FindLocation(const char *location);
+extern http_status_t IsAuthorized(client_t *con);
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/banners.c b/scheduler/banners.c
new file mode 100644
index 000000000..ff9632c14
--- /dev/null
+++ b/scheduler/banners.c
@@ -0,0 +1,216 @@
+/*
+ * "$Id$"
+ *
+ * Banner routines for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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:
+ *
+ * AddBanner() - Add a banner to the array.
+ * FindBanner() - Find a named banner.
+ * LoadBanners() - Load all available banner files...
+ * compare() - Compare two banners.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cupsd.h"
+
+
+/*
+ * Local functions...
+ */
+
+static int compare(const banner_t *b0, const banner_t *b1);
+
+
+/*
+ * 'AddBanner()' - Add a banner to the array.
+ */
+
+void
+AddBanner(const char *name, /* I - Name of banner */
+ const char *filename) /* I - Filename for banner */
+{
+ mime_type_t *filetype; /* Filetype */
+ banner_t *temp; /* New banner data */
+
+
+ /*
+ * See what the filetype is...
+ */
+
+ if ((filetype = mimeFileType(MimeDatabase, filename)) == NULL)
+ {
+ LogMessage(L_WARN, "AddBanner: Banner \"%s\" is of an unknown file type - skipping!",
+ name);
+ return;
+ }
+
+ /*
+ * Allocate memory...
+ */
+
+ if (NumBanners == 0)
+ temp = malloc(sizeof(banner_t));
+ else
+ temp = realloc(Banners, sizeof(banner_t) * (NumBanners + 1));
+
+ if (temp == NULL)
+ {
+ LogMessage(L_ERROR, "AddBanner: Ran out of memory adding a banner!");
+ return;
+ }
+
+ /*
+ * Copy the new banner data over...
+ */
+
+ Banners = temp;
+ temp += NumBanners;
+ NumBanners ++;
+
+ memset(temp, 0, sizeof(banner_t));
+ strncpy(temp->name, name, sizeof(temp->name) - 1);
+ temp->filetype = filetype;
+}
+
+
+/*
+ * 'FindBanner()' - Find a named banner.
+ */
+
+banner_t * /* O - Pointer to banner or NULL */
+FindBanner(const char *name) /* I - Name of banner */
+{
+ banner_t key; /* Search key */
+
+
+ strncpy(key.name, name, sizeof(key.name) - 1);
+ key.name[sizeof(key.name) - 1] = '\0';
+
+ return ((banner_t *)bsearch(&key, Banners, NumBanners, sizeof(banner_t),
+ (int (*)(const void *, const void *))compare));
+}
+
+
+/*
+ * 'LoadBanners()' - Load all available banner files...
+ */
+
+void
+LoadBanners(const char *d) /* I - Directory to search */
+{
+ DIR *dir; /* Directory pointer */
+ DIRENT *dent; /* Directory entry */
+ char filename[1024], /* Name of banner */
+ *ext; /* Pointer to extension */
+ struct stat fileinfo; /* File information */
+
+
+ /*
+ * Free old banner info...
+ */
+
+ if (NumBanners)
+ {
+ free(Banners);
+ NumBanners = 0;
+ }
+
+ /*
+ * Try opening the banner directory...
+ */
+
+ if ((dir = opendir(d)) == NULL)
+ {
+ LogMessage(L_ERROR, "LoadBanners: Unable to open banner directory \"%s\": %s",
+ d, strerror(errno));
+ return;
+ }
+
+ /*
+ * Read entries, skipping directories and backup files.
+ */
+
+ while ((dent = readdir(dir)) != NULL)
+ {
+ /*
+ * Check the file to make sure it isn't a directory or a backup
+ * file of some sort...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/%s", d, dent->d_name);
+
+ if (stat(filename, &fileinfo))
+ {
+ LogMessage(L_WARN, "LoadBanners: Unable to state \"%s\" banner: %s",
+ dent->d_name, strerror(errno));
+ continue;
+ }
+
+ if (S_ISDIR(fileinfo.st_mode))
+ continue;
+
+ if (dent->d_name[0] == '~')
+ continue;
+
+ if ((ext = strrchr(dent->d_name, '.')) != NULL)
+ if (strcmp(ext, ".bck") == 0 ||
+ strcmp(ext, ".bak") == 0 ||
+ strcmp(ext, ".sav") == 0)
+ continue;
+
+ /*
+ * Must be a valid file; add it!
+ */
+
+ AddBanner(dent->d_name, filename);
+ }
+
+ /*
+ * Close the directory and sort as needed...
+ */
+
+ closedir(dir);
+
+ if (NumBanners > 1)
+ qsort(Banners, NumBanners, sizeof(banner_t),
+ (int (*)(const void *, const void *))compare);
+}
+
+
+/*
+ * 'compare()' - Compare two banners.
+ */
+
+static int /* O - -1 if name0 < name1, etc. */
+compare(const banner_t *b0, /* I - First banner */
+ const banner_t *b1) /* I - Second banner */
+{
+ return (strcasecmp(b0->name, b1->name));
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/banners.h b/scheduler/banners.h
new file mode 100644
index 000000000..ababc82c5
--- /dev/null
+++ b/scheduler/banners.h
@@ -0,0 +1,57 @@
+/*
+ * "$Id$"
+ *
+ * Banner definitions for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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
+ */
+
+/*
+ * Banner information structure...
+ */
+
+typedef struct
+{
+ char name[256]; /* Name of banner */
+ mime_type_t *filetype; /* Filetype for banner */
+} banner_t;
+
+
+/*
+ * Globals...
+ */
+
+VAR int NumBanners VALUE(0);
+ /* Number of banner files available */
+VAR banner_t *Banners VALUE(NULL);
+ /* Available banner files */
+
+
+/*
+ * Prototypes...
+ */
+
+extern void AddBanner(const char *name, const char *filename);
+extern banner_t *FindBanner(const char *name);
+extern void LoadBanners(const char *d);
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/cert.c b/scheduler/cert.c
new file mode 100644
index 000000000..76fc2c7fd
--- /dev/null
+++ b/scheduler/cert.c
@@ -0,0 +1,275 @@
+/*
+ * "$Id$"
+ *
+ * Authentication certificate routines for the Common UNIX
+ * Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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:
+ *
+ * AddCert() - Add a certificate.
+ * DeleteCert() - Delete a single certificate.
+ * DeleteAllCerts() - Delete all certificates...
+ * FindCert() - Find a certificate.
+ * InitCerts() - Initialize the certificate "system" and root
+ * certificate.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cupsd.h"
+#include <grp.h>
+
+
+/*
+ * 'AddCert()' - Add a certificate.
+ */
+
+void
+AddCert(int pid, /* I - Process ID */
+ const char *username) /* I - Username */
+{
+ int i; /* Looping var */
+ cert_t *cert; /* Current certificate */
+ FILE *fp; /* Certificate file */
+ char filename[1024]; /* Certificate filename */
+ struct group *grp; /* System group */
+ static const char *hex = "0123456789ABCDEF";
+ /* Hex constants... */
+
+
+ /*
+ * Allocate memory for the certificate...
+ */
+
+ if ((cert = calloc(sizeof(cert_t), 1)) == NULL)
+ return;
+
+ /*
+ * Fill in the certificate information...
+ */
+
+ cert->pid = pid;
+ strncpy(cert->username, username, sizeof(cert->username) - 1);
+
+ for (i = 0; i < 32; i ++)
+ cert->certificate[i] = hex[random() & 15];
+
+ /*
+ * Save the certificate to a file readable only by the User and Group
+ * (or root and SystemGroup for PID == 0)...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/certs/%d", ServerRoot, pid);
+
+ if ((fp = fopen(filename, "w")) == NULL)
+ {
+ free(cert);
+ return;
+ }
+
+ if (pid == 0)
+ {
+ /*
+ * Root certificate...
+ */
+
+ fchmod(fileno(fp), 0440);
+
+ if ((grp = getgrnam(SystemGroups[0])) == NULL)
+ fchown(fileno(fp), getuid(), 0);
+ else
+ fchown(fileno(fp), getuid(), grp->gr_gid);
+
+ endgrent();
+
+ RootCertTime = time(NULL);
+ }
+ else
+ {
+ /*
+ * CGI certificate...
+ */
+
+ fchmod(fileno(fp), 0400);
+ fchown(fileno(fp), User, Group);
+ }
+
+ fputs(cert->certificate, fp);
+ fclose(fp);
+
+ /*
+ * Insert the certificate at the front of the list...
+ */
+
+ cert->next = Certs;
+ Certs = cert;
+}
+
+
+/*
+ * 'DeleteCert()' - Delete a single certificate.
+ */
+
+void
+DeleteCert(int pid) /* I - Process ID */
+{
+ cert_t *cert, /* Current certificate */
+ *prev; /* Previous certificate */
+ char filename[1024]; /* Certificate file */
+
+
+ for (prev = NULL, cert = Certs; cert != NULL; prev = cert, cert = cert->next)
+ if (cert->pid == pid)
+ {
+ /*
+ * Remove this certificate from the list...
+ */
+
+ if (prev == NULL)
+ Certs = cert->next;
+ else
+ prev->next = cert->next;
+
+ free(cert);
+
+ /*
+ * Delete the file and return...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/certs/%d", ServerRoot, pid);
+ unlink(filename);
+ return;
+ }
+}
+
+
+/*
+ * 'DeleteAllCerts()' - Delete all certificates...
+ */
+
+void
+DeleteAllCerts(void)
+{
+ cert_t *cert, /* Current certificate */
+ *next; /* Next certificate */
+ char filename[1024]; /* Certificate file */
+
+
+ /*
+ * Loop through each certificate, deleting them...
+ */
+
+ for (cert = Certs; cert != NULL; cert = next)
+ {
+ /*
+ * Delete the file...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/certs/%d", ServerRoot, cert->pid);
+ unlink(filename);
+
+ /*
+ * Free memory...
+ */
+
+ next = cert->next;
+ free(cert);
+ }
+
+ Certs = NULL;
+}
+
+
+/*
+ * 'FindCert()' - Find a certificate.
+ */
+
+const char * /* O - Matching username or NULL */
+FindCert(const char *certificate) /* I - Certificate */
+{
+ cert_t *cert; /* Current certificate */
+
+
+ for (cert = Certs; cert != NULL; cert = cert->next)
+ if (strcasecmp(certificate, cert->certificate) == 0)
+ return (cert->username);
+
+ return (NULL);
+}
+
+
+/*
+ * 'InitCerts()' - Initialize the certificate "system" and root certificate.
+ */
+
+void
+InitCerts(void)
+{
+ FILE *fp; /* /dev/random file */
+ unsigned seed; /* Seed for random number generator */
+ struct timeval tod; /* Time of day */
+
+
+ /*
+ * Initialize the random number generator using the random device or
+ * the current time, as available...
+ */
+
+ if ((fp = fopen("/dev/urandom", "rb")) == NULL)
+ {
+ /*
+ * Get the time in usecs and use it as the initial seed...
+ */
+
+ gettimeofday(&tod, NULL);
+
+ seed = (unsigned)(tod.tv_sec + tod.tv_usec);
+ }
+ else
+ {
+ /*
+ * Read 4 random characters from the random device and use
+ * them as the seed...
+ */
+
+ seed = getc(fp);
+ seed = (seed << 8) | getc(fp);
+ seed = (seed << 8) | getc(fp);
+ seed = (seed << 8) | getc(fp);
+
+ fclose(fp);
+ }
+
+ srandom(seed);
+
+ /*
+ * Create a root certificate and return...
+ */
+
+ AddCert(0, "root");
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/cert.h b/scheduler/cert.h
new file mode 100644
index 000000000..d078d53cc
--- /dev/null
+++ b/scheduler/cert.h
@@ -0,0 +1,60 @@
+/*
+ * "$Id$"
+ *
+ * Authentication certificate definitions for the Common UNIX
+ * Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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
+ */
+
+/*
+ * Certificate structure...
+ */
+
+typedef struct cert_str
+{
+ struct cert_str *next; /* Next certificate in list */
+ int pid; /* Process ID (0 for root certificate) */
+ char certificate[33];/* 32 hex characters, or 128 bits */
+ char username[33]; /* Authenticated username */
+} cert_t;
+
+
+/*
+ * Globals...
+ */
+
+VAR cert_t *Certs; /* List of certificates */
+VAR time_t RootCertTime; /* Root certificate update time */
+
+
+/*
+ * Prototypes...
+ */
+
+extern void AddCert(int pid, const char *username);
+extern void DeleteCert(int pid);
+extern void DeleteAllCerts(void);
+extern const char *FindCert(const char *certificate);
+extern void InitCerts(void);
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/classes.c b/scheduler/classes.c
new file mode 100644
index 000000000..bbb37d394
--- /dev/null
+++ b/scheduler/classes.c
@@ -0,0 +1,695 @@
+/*
+ * "$Id$"
+ *
+ * Printer class routines for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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:
+ *
+ * AddClass() - Add a class to the system.
+ * AddPrinterToClass() - Add a printer to a class...
+ * DeletePrinterFromClass() - Delete a printer from a class.
+ * DeletePrinterFromClasses() - Delete a printer from all classes.
+ * DeleteAllClasses() - Remove all classes from the system.
+ * FindAvailablePrinter() - Find an available printer in a class.
+ * FindClass() - Find the named class.
+ * LoadAllClasses() - Load classes from the classes.conf file.
+ * SaveAllClasses() - Save classes to the classes.conf file.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cupsd.h"
+
+
+/*
+ * 'AddClass()' - Add a class to the system.
+ */
+
+printer_t * /* O - New class */
+AddClass(const char *name) /* I - Name of class */
+{
+ printer_t *c; /* New class */
+
+
+ /*
+ * Add the printer and set the type to "class"...
+ */
+
+ if ((c = AddPrinter(name)) != NULL)
+ {
+ /*
+ * Change from a printer to a class...
+ */
+
+ c->type = CUPS_PRINTER_CLASS;
+ snprintf(c->uri, sizeof(c->uri), "ipp://%s:%d/classes/%s", ServerName,
+ ntohs(Listeners[0].address.sin_port), name);
+
+ /*
+ * Set the printer attributes to make this a class.
+ */
+
+ SetPrinterAttrs(c);
+ }
+
+ return (c);
+}
+
+
+/*
+ * 'AddPrinterToClass()' - Add a printer to a class...
+ */
+
+void
+AddPrinterToClass(printer_t *c, /* I - Class to add to */
+ printer_t *p) /* I - Printer to add */
+{
+ int i; /* Looping var */
+ printer_t **temp; /* Pointer to printer array */
+
+
+ /*
+ * See if this printer is already a member of the class...
+ */
+
+ for (i = 0; i < c->num_printers; i ++)
+ if (c->printers[i] == p)
+ return;
+
+ /*
+ * Allocate memory as needed...
+ */
+
+ if (c->num_printers == 0)
+ temp = malloc(sizeof(printer_t *));
+ else
+ temp = realloc(c->printers, sizeof(printer_t *) * (c->num_printers + 1));
+
+ if (temp == NULL)
+ {
+ LogMessage(L_ERROR, "Unable to add printer %s to class %s!",
+ p->name, c->name);
+ return;
+ }
+
+ /*
+ * Add the printer to the end of the array and update the number of printers.
+ */
+
+ c->printers = temp;
+ temp += c->num_printers;
+ c->num_printers ++;
+
+ *temp = p;
+
+ /*
+ * Update the IPP attributes...
+ */
+
+ SetPrinterAttrs(c);
+}
+
+
+/*
+ * 'DeletePrinterFromClass()' - Delete a printer from a class.
+ */
+
+void
+DeletePrinterFromClass(printer_t *c, /* I - Class to delete from */
+ printer_t *p) /* I - Printer to delete */
+{
+ int i; /* Looping var */
+ cups_ptype_t type; /* Class type */
+
+
+ /*
+ * See if the printer is in the class...
+ */
+
+ for (i = 0; i < c->num_printers; i ++)
+ if (p == c->printers[i])
+ break;
+
+ /*
+ * If it is, remove it from the list...
+ */
+
+ if (i < c->num_printers)
+ {
+ /*
+ * Yes, remove the printer...
+ */
+
+ c->num_printers --;
+ if (i < c->num_printers)
+ memcpy(c->printers + i, c->printers + i + 1,
+ (c->num_printers - i) * sizeof(printer_t *));
+ }
+
+ /*
+ * Recompute the printer type mask as needed...
+ */
+
+ if (c->num_printers > 0)
+ {
+ type = c->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT);
+ c->type = ~CUPS_PRINTER_REMOTE;
+
+ for (i = 0; i < c->num_printers; i ++)
+ c->type &= c->printers[i]->type;
+
+ c->type |= type;
+
+ /*
+ * Update the IPP attributes...
+ */
+
+ SetPrinterAttrs(c);
+ }
+}
+
+
+/*
+ * 'DeletePrinterFromClasses()' - Delete a printer from all classes.
+ */
+
+void
+DeletePrinterFromClasses(printer_t *p) /* I - Printer to delete */
+{
+ printer_t *c, /* Pointer to current class */
+ *next; /* Pointer to next class */
+
+
+ /*
+ * Loop through the printer/class list and remove the printer
+ * from each class listed...
+ */
+
+ for (c = Printers; c != NULL; c = next)
+ {
+ next = c->next;
+
+ if (c->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))
+ DeletePrinterFromClass(c, p);
+ }
+
+ /*
+ * Then clean out any empty classes...
+ */
+
+ for (c = Printers; c != NULL; c = next)
+ {
+ next = c->next;
+
+ if ((c->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT)) &&
+ c->num_printers == 0)
+ DeletePrinter(c);
+ }
+}
+
+
+/*
+ * 'DeleteAllClasses()' - Remove all classes from the system.
+ */
+
+void
+DeleteAllClasses(void)
+{
+ printer_t *c, /* Pointer to current printer/class */
+ *next; /* Pointer to next printer in list */
+
+
+ for (c = Printers; c != NULL; c = next)
+ {
+ next = c->next;
+
+ if (c->type & CUPS_PRINTER_CLASS)
+ DeletePrinter(c);
+ }
+}
+
+
+/*
+ * 'FindAvailablePrinter()' - Find an available printer in a class.
+ */
+
+printer_t * /* O - Available printer or NULL */
+FindAvailablePrinter(const char *name) /* I - Class to check */
+{
+ int i; /* Looping var */
+ printer_t *c; /* Printer class */
+
+
+ /*
+ * Find the class...
+ */
+
+ if ((c = FindClass(name)) == NULL)
+ {
+ LogMessage(L_ERROR, "Unable to find class \"%s\"!", name);
+ return (NULL);
+ }
+
+ /*
+ * Loop through the printers in the class and return the first idle
+ * printer... We keep track of the last printer that we used so that
+ * a "round robin" type of scheduling is realized (otherwise the first
+ * server might be saturated with print jobs...)
+ *
+ * Thanks to Joel Fredrikson for helping us get this right!
+ */
+
+ for (i = c->last_printer + 1; ; i ++)
+ {
+ if (i >= c->num_printers)
+ i = 0;
+
+ if (c->printers[i]->state == IPP_PRINTER_IDLE ||
+ ((c->printers[i]->type & CUPS_PRINTER_REMOTE) && !c->printers[i]->job))
+ {
+ c->last_printer = i;
+ return (c->printers[i]);
+ }
+
+ if (i == c->last_printer)
+ break;
+ }
+
+ return (NULL);
+}
+
+
+/*
+ * 'FindClass()' - Find the named class.
+ */
+
+printer_t * /* O - Matching class or NULL */
+FindClass(const char *name) /* I - Name of class */
+{
+ printer_t *c; /* Current class/printer */
+
+
+ for (c = Printers; c != NULL; c = c->next)
+ switch (strcasecmp(name, c->name))
+ {
+ case 0 : /* name == c->name */
+ if (c->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))
+ return (c);
+ case 1 : /* name > c->name */
+ break;
+ case -1 : /* name < c->name */
+ return (NULL);
+ }
+
+ return (NULL);
+}
+
+
+/*
+ * 'LoadAllClasses()' - Load classes from the classes.conf file.
+ */
+
+void
+LoadAllClasses(void)
+{
+ FILE *fp; /* classes.conf file */
+ int linenum; /* Current line number */
+ int len; /* Length of line */
+ char line[1024], /* Line from file */
+ name[256], /* Parameter name */
+ *nameptr, /* Pointer into name */
+ *value, /* Pointer to value */
+ *valueptr; /* Pointer into value */
+ printer_t *p, /* Current printer class */
+ *temp; /* Temporary pointer to printer */
+
+
+ /*
+ * Open the classes.conf file...
+ */
+
+ snprintf(line, sizeof(line), "%s/classes.conf", ServerRoot);
+ if ((fp = fopen(line, "r")) == NULL)
+ return;
+
+ /*
+ * Read class configurations until we hit EOF...
+ */
+
+ linenum = 0;
+ p = NULL;
+
+ while (fgets(line, sizeof(line), fp) != NULL)
+ {
+ linenum ++;
+
+ /*
+ * Skip comment lines...
+ */
+
+ if (line[0] == '#')
+ continue;
+
+ /*
+ * Strip trailing whitespace, if any...
+ */
+
+ len = strlen(line);
+
+ while (len > 0 && isspace(line[len - 1]))
+ {
+ len --;
+ line[len] = '\0';
+ }
+
+ /*
+ * Extract the name from the beginning of the line...
+ */
+
+ for (value = line; isspace(*value); value ++);
+
+ for (nameptr = name; *value != '\0' && !isspace(*value) &&
+ nameptr < (name + sizeof(name) - 1);)
+ *nameptr++ = *value++;
+ *nameptr = '\0';
+
+ while (isspace(*value))
+ value ++;
+
+ if (name[0] == '\0')
+ continue;
+
+ /*
+ * Decode the directive...
+ */
+
+ if (strcmp(name, "<Class") == 0 ||
+ strcmp(name, "<DefaultClass") == 0)
+ {
+ /*
+ * <Class name> or <DefaultClass name>
+ */
+
+ if (line[len - 1] == '>' && p == NULL)
+ {
+ line[len - 1] = '\0';
+
+ p = AddClass(value);
+ p->accepting = 1;
+ p->state = IPP_PRINTER_IDLE;
+
+ if (strcmp(name, "<DefaultClass") == 0)
+ DefaultPrinter = p;
+ }
+ else
+ {
+ LogMessage(L_ERROR, "Syntax error on line %d of classes.conf.",
+ linenum);
+ return;
+ }
+ }
+ else if (strcmp(name, "</Class>") == 0)
+ {
+ if (p != NULL)
+ {
+ SetPrinterAttrs(p);
+ p = NULL;
+ }
+ else
+ {
+ LogMessage(L_ERROR, "Syntax error on line %d of classes.conf.",
+ linenum);
+ return;
+ }
+ }
+ else if (p == NULL)
+ {
+ LogMessage(L_ERROR, "Syntax error on line %d of classes.conf.",
+ linenum);
+ return;
+ }
+
+ else if (strcmp(name, "Info") == 0)
+ strncpy(p->info, value, sizeof(p->info) - 1);
+ else if (strcmp(name, "Location") == 0)
+ strncpy(p->location, value, sizeof(p->location) - 1);
+ else if (strcmp(name, "Printer") == 0)
+ {
+ if ((temp = FindPrinter(value)) == NULL)
+ {
+ LogMessage(L_WARN, "Unknown printer %s on line %d of classes.conf.",
+ value, linenum);
+
+ /*
+ * Add the missing remote printer...
+ */
+
+ temp = AddPrinter(value);
+ strcpy(temp->make_model, "Remote Printer on unknown");
+
+ temp->state = IPP_PRINTER_STOPPED;
+ temp->type |= CUPS_PRINTER_REMOTE;
+ temp->browse_time = 2147483647;
+
+ strcpy(temp->location, "Location Unknown");
+ strcpy(temp->info, "No Information Available");
+ temp->hostname[0] = '\0';
+
+ SetPrinterAttrs(temp);
+ }
+
+ if (temp)
+ AddPrinterToClass(p, temp);
+ }
+ else if (strcmp(name, "State") == 0)
+ {
+ /*
+ * Set the initial queue state...
+ */
+
+ if (strcasecmp(value, "idle") == 0)
+ p->state = IPP_PRINTER_IDLE;
+ else if (strcasecmp(value, "stopped") == 0)
+ p->state = IPP_PRINTER_STOPPED;
+ }
+ else if (strcmp(name, "StateMessage") == 0)
+ {
+ /*
+ * Set the initial queue state message...
+ */
+
+ while (isspace(*value))
+ value ++;
+
+ strncpy(p->state_message, value, sizeof(p->state_message) - 1);
+ }
+ else if (strcmp(name, "Accepting") == 0)
+ {
+ /*
+ * Set the initial accepting state...
+ */
+
+ if (strcasecmp(value, "yes") == 0)
+ p->accepting = 1;
+ else
+ p->accepting = 0;
+ }
+ else if (strcmp(name, "JobSheets") == 0)
+ {
+ /*
+ * Set the initial job sheets...
+ */
+
+ for (valueptr = value; *valueptr && !isspace(*valueptr); valueptr ++);
+
+ if (*valueptr)
+ *valueptr++ = '\0';
+
+ strncpy(p->job_sheets[0], value, sizeof(p->job_sheets[0]) - 1);
+
+ while (isspace(*valueptr))
+ valueptr ++;
+
+ if (*valueptr)
+ {
+ for (value = valueptr; *valueptr && !isspace(*valueptr); valueptr ++);
+
+ if (*valueptr)
+ *valueptr++ = '\0';
+
+ strncpy(p->job_sheets[1], value, sizeof(p->job_sheets[1]) - 1);
+ }
+ }
+ else if (strcmp(name, "AllowUser") == 0)
+ {
+ p->deny_users = 0;
+ AddPrinterUser(p, value);
+ }
+ else if (strcmp(name, "DenyUser") == 0)
+ {
+ p->deny_users = 1;
+ AddPrinterUser(p, value);
+ }
+ else if (strcmp(name, "QuotaPeriod") == 0)
+ p->quota_period = atoi(value);
+ else if (strcmp(name, "PageLimit") == 0)
+ p->page_limit = atoi(value);
+ else if (strcmp(name, "KLimit") == 0)
+ p->k_limit = atoi(value);
+ else
+ {
+ /*
+ * Something else we don't understand...
+ */
+
+ LogMessage(L_ERROR, "Unknown configuration directive %s on line %d of classes.conf.",
+ name, linenum);
+ }
+ }
+
+ fclose(fp);
+}
+
+
+/*
+ * 'SaveAllClasses()' - Save classes to the classes.conf file.
+ */
+
+void
+SaveAllClasses(void)
+{
+ FILE *fp; /* classes.conf file */
+ char temp[1024]; /* Temporary string */
+ char backup[1024]; /* classes.conf.O file */
+ printer_t *pclass; /* Current printer class */
+ int i; /* Looping var */
+ time_t curtime; /* Current time */
+ struct tm *curdate; /* Current date */
+
+
+ /*
+ * Create the classes.conf file...
+ */
+
+ snprintf(temp, sizeof(temp), "%s/classes.conf", ServerRoot);
+ snprintf(backup, sizeof(backup), "%s/classes.conf.O", ServerRoot);
+
+ if (rename(temp, backup))
+ LogMessage(L_ERROR, "Unable to backup classes.conf - %s", strerror(errno));
+
+ if ((fp = fopen(temp, "w")) == NULL)
+ {
+ LogMessage(L_ERROR, "Unable to save classes.conf - %s", strerror(errno));
+
+ if (rename(backup, temp))
+ LogMessage(L_ERROR, "Unable to restore classes.conf - %s", strerror(errno));
+ return;
+ }
+ else
+ LogMessage(L_INFO, "Saving classes.conf...");
+
+ /*
+ * Restrict access to the file...
+ */
+
+ fchown(fileno(fp), User, Group);
+ fchmod(fileno(fp), 0600);
+
+ /*
+ * Write a small header to the file...
+ */
+
+ curtime = time(NULL);
+ curdate = gmtime(&curtime);
+ strftime(temp, sizeof(temp) - 1, CUPS_STRFTIME_FORMAT, curdate);
+
+ fputs("# Class configuration file for " CUPS_SVERSION "\n", fp);
+ fprintf(fp, "# Written by cupsd on %s\n", temp);
+
+ /*
+ * Write each local class known to the system...
+ */
+
+ for (pclass = Printers; pclass != NULL; pclass = pclass->next)
+ {
+ /*
+ * Skip remote destinations and regular printers...
+ */
+
+ if ((pclass->type & CUPS_PRINTER_REMOTE) ||
+ (pclass->type & CUPS_PRINTER_IMPLICIT) ||
+ !(pclass->type & CUPS_PRINTER_CLASS))
+ continue;
+
+ /*
+ * Write printers as needed...
+ */
+
+ if (pclass == DefaultPrinter)
+ fprintf(fp, "<DefaultClass %s>\n", pclass->name);
+ else
+ fprintf(fp, "<Class %s>\n", pclass->name);
+
+ if (pclass->info[0])
+ fprintf(fp, "Info %s\n", pclass->info);
+
+ if (pclass->location[0])
+ fprintf(fp, "Location %s\n", pclass->location);
+
+ if (pclass->state == IPP_PRINTER_STOPPED)
+ {
+ fputs("State Stopped\n", fp);
+ fprintf(fp, "StateMessage %s\n", pclass->state_message);
+ }
+ else
+ fputs("State Idle\n", fp);
+
+ if (pclass->accepting)
+ fputs("Accepting Yes\n", fp);
+ else
+ fputs("Accepting No\n", fp);
+
+ fprintf(fp, "JobSheets %s %s\n", pclass->job_sheets[0],
+ pclass->job_sheets[1]);
+
+ for (i = 0; i < pclass->num_printers; i ++)
+ fprintf(fp, "Printer %s\n", pclass->printers[i]->name);
+
+ fprintf(fp, "QuotaPeriod %d\n", pclass->quota_period);
+ fprintf(fp, "PageLimit %d\n", pclass->page_limit);
+ fprintf(fp, "KLimit %d\n", pclass->k_limit);
+
+ for (i = 0; i < pclass->num_users; i ++)
+ fprintf(fp, "%sUser %s\n", pclass->deny_users ? "Deny" : "Allow",
+ pclass->users[i]);
+
+ fputs("</Class>\n", fp);
+ }
+
+ fclose(fp);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/classes.h b/scheduler/classes.h
new file mode 100644
index 000000000..385314d28
--- /dev/null
+++ b/scheduler/classes.h
@@ -0,0 +1,43 @@
+/*
+ * "$Id$"
+ *
+ * Printer class definitions for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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
+ */
+
+
+/*
+ * Prototypes...
+ */
+
+extern printer_t *AddClass(const char *name);
+extern void AddPrinterToClass(printer_t *c, printer_t *p);
+extern void DeletePrinterFromClass(printer_t *c, printer_t *p);
+extern void DeletePrinterFromClasses(printer_t *p);
+extern void DeleteAllClasses(void);
+extern printer_t *FindAvailablePrinter(const char *name);
+extern printer_t *FindClass(const char *name);
+extern void LoadAllClasses(void);
+extern void SaveAllClasses(void);
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/client.c b/scheduler/client.c
new file mode 100644
index 000000000..de47ad078
--- /dev/null
+++ b/scheduler/client.c
@@ -0,0 +1,2497 @@
+/*
+ * "$Id$"
+ *
+ * Client routines for the Common UNIX Printing System (CUPS) scheduler.
+ *
+ * Copyright 1997-2002 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:
+ *
+ * AcceptClient() - Accept a new client.
+ * CloseAllClients() - Close all remote clients immediately.
+ * CloseClient() - Close a remote client.
+ * EncryptClient() - Enable encryption for the client...
+ * ReadClient() - Read data from a client.
+ * SendCommand() - Send output from a command via HTTP.
+ * SendError() - Send an error message via HTTP.
+ * SendFile() - Send a file via HTTP.
+ * SendHeader() - Send an HTTP request.
+ * WriteClient() - Write data to a client as needed.
+ * check_if_modified() - Decode an "If-Modified-Since" line.
+ * decode_auth() - Decode an authorization string.
+ * get_file() - Get a filename and state info.
+ * install_conf_file() - Install a configuration file.
+ * pipe_command() - Pipe the output of a command to the remote client.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cupsd.h"
+
+#include <grp.h>
+
+#ifdef HAVE_LIBSSL
+# include <openssl/err.h>
+# include <openssl/ssl.h>
+# include <openssl/rand.h>
+#endif /* HAVE_LIBSSL */
+
+
+/*
+ * Local functions...
+ */
+
+static int check_if_modified(client_t *con,
+ struct stat *filestats);
+static void decode_auth(client_t *con);
+static char *get_file(client_t *con, struct stat *filestats);
+static http_status_t install_conf_file(client_t *con);
+static int pipe_command(client_t *con, int infile, int *outfile,
+ char *command, char *options);
+
+
+/*
+ * 'AcceptClient()' - Accept a new client.
+ */
+
+void
+AcceptClient(listener_t *lis) /* I - Listener socket */
+{
+ int i; /* Looping var */
+ int val; /* Parameter value */
+ client_t *con; /* New client pointer */
+ unsigned address;/* Address of client */
+ struct hostent *host; /* Host entry for address */
+
+
+ LogMessage(L_DEBUG2, "AcceptClient(%08x) %d NumClients = %d",
+ lis, lis->fd, NumClients);
+
+ /*
+ * Make sure we don't have a full set of clients already...
+ */
+
+ if (NumClients == MaxClients)
+ return;
+
+ /*
+ * Get a pointer to the next available client...
+ */
+
+ con = Clients + NumClients;
+
+ memset(con, 0, sizeof(client_t));
+ con->http.activity = time(NULL);
+
+ /*
+ * Accept the client and get the remote address...
+ */
+
+ val = sizeof(struct sockaddr_in);
+
+ if ((con->http.fd = accept(lis->fd, (struct sockaddr *)&(con->http.hostaddr),
+ &val)) < 0)
+ {
+ LogMessage(L_ERROR, "Unable to accept client connection - %s.",
+ strerror(errno));
+ return;
+ }
+
+ con->http.hostaddr.sin_port = lis->address.sin_port;
+
+ /*
+ * Get the hostname or format the IP address as needed...
+ */
+
+ address = ntohl(con->http.hostaddr.sin_addr.s_addr);
+
+ if (HostNameLookups)
+#ifndef __sgi
+ host = gethostbyaddr((char *)&(con->http.hostaddr.sin_addr),
+ sizeof(struct in_addr), AF_INET);
+#else
+ host = gethostbyaddr(&(con->http.hostaddr.sin_addr),
+ sizeof(struct in_addr), AF_INET);
+#endif /* !__sgi */
+ else
+ host = NULL;
+
+ if (con->http.hostaddr.sin_addr.s_addr == ServerAddr.sin_addr.s_addr)
+ {
+ /*
+ * Map accesses from the same host to the server name.
+ */
+
+ strncpy(con->http.hostname, ServerName, sizeof(con->http.hostname) - 1);
+ }
+ else if (host == NULL)
+ {
+ sprintf(con->http.hostname, "%d.%d.%d.%d", (address >> 24) & 255,
+ (address >> 16) & 255, (address >> 8) & 255, address & 255);
+
+ if (HostNameLookups == 2)
+ {
+ /*
+ * Can't have an unresolved IP address with double-lookups enabled...
+ */
+
+#ifdef WIN32
+ closesocket(con->http.fd);
+#else
+ close(con->http.fd);
+#endif /* WIN32 */
+
+ LogMessage(L_WARN, "Name lookup failed - connection from %s closed!",
+ con->http.hostname);
+ return;
+ }
+ }
+ else
+ strncpy(con->http.hostname, host->h_name, sizeof(con->http.hostname) - 1);
+
+ if (HostNameLookups == 2)
+ {
+ /*
+ * Do double lookups as needed...
+ */
+
+ if ((host = httpGetHostByName(con->http.hostname)) != NULL)
+ {
+ /*
+ * See if the hostname maps to the IP address...
+ */
+
+ if (host->h_length != 4 || host->h_addrtype != AF_INET)
+ {
+ /*
+ * Not an IPv4 address...
+ */
+
+ host = NULL;
+ }
+ else
+ {
+ /*
+ * Compare all of the addresses against this one...
+ */
+
+ for (i = 0; host->h_addr_list[i]; i ++)
+ if (memcmp(&(con->http.hostaddr.sin_addr), host->h_addr_list[i], 4) == 0)
+ break;
+
+ if (!host->h_addr_list[i])
+ host = NULL;
+ }
+ }
+
+ if (host == NULL)
+ {
+ /*
+ * Can't have a hostname that doesn't resolve to the same IP address
+ * with double-lookups enabled...
+ */
+
+#ifdef WIN32
+ closesocket(con->http.fd);
+#else
+ close(con->http.fd);
+#endif /* WIN32 */
+
+ LogMessage(L_WARN, "IP lookup failed - connection from %s closed!",
+ con->http.hostname);
+ return;
+ }
+ }
+
+ LogMessage(L_DEBUG, "AcceptClient() %d from %s:%d.", con->http.fd,
+ con->http.hostname, ntohs(con->http.hostaddr.sin_port));
+
+ /*
+ * Using TCP_NODELAY improves responsiveness, especially on systems
+ * with a slow loopback interface... Since we write large buffers
+ * when sending print files and requests, there shouldn't be any
+ * performance penalty for this...
+ */
+
+ val = 1;
+ setsockopt(con->http.fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
+
+ /*
+ * Add the socket to the select() input mask.
+ */
+
+ fcntl(con->http.fd, F_SETFD, fcntl(con->http.fd, F_GETFD) | FD_CLOEXEC);
+
+ LogMessage(L_DEBUG2, "AcceptClient: Adding fd %d to InputSet...",
+ con->http.fd);
+ FD_SET(con->http.fd, &InputSet);
+
+ NumClients ++;
+
+ /*
+ * Temporarily suspend accept()'s until we lose a client...
+ */
+
+ if (NumClients == MaxClients)
+ PauseListening();
+
+#ifdef HAVE_LIBSSL
+ /*
+ * See if we are connecting on a secure port...
+ */
+
+ if (lis->encryption == HTTP_ENCRYPT_ALWAYS)
+ {
+ /*
+ * https connection; go secure...
+ */
+
+ EncryptClient(con);
+ }
+#endif /* HAVE_LIBSSL */
+}
+
+
+/*
+ * 'CloseAllClients()' - Close all remote clients immediately.
+ */
+
+void
+CloseAllClients(void)
+{
+ while (NumClients > 0)
+ CloseClient(Clients);
+}
+
+
+/*
+ * 'CloseClient()' - Close a remote client.
+ */
+
+void
+CloseClient(client_t *con) /* I - Client to close */
+{
+ int status; /* Exit status of pipe command */
+#ifdef HAVE_LIBSSL
+ SSL_CTX *context; /* Context for encryption */
+ SSL *conn; /* Connection for encryption */
+#endif /* HAVE_LIBSSL */
+
+
+ LogMessage(L_DEBUG, "CloseClient() %d", con->http.fd);
+
+#ifdef HAVE_LIBSSL
+ /*
+ * Shutdown encryption as needed...
+ */
+
+ if (con->http.tls)
+ {
+ conn = (SSL *)(con->http.tls);
+ context = SSL_get_SSL_CTX(conn);
+
+ SSL_shutdown(conn);
+ SSL_CTX_free(context);
+ SSL_free(conn);
+
+ con->http.tls = NULL;
+ }
+#endif /* HAVE_LIBSSL */
+
+ /*
+ * Close the socket and clear the file from the input set for select()...
+ */
+
+ if (con->http.fd > 0)
+ {
+ LogMessage(L_DEBUG2, "CloseClient: Removing fd %d from InputSet and OutputSet...",
+ con->http.fd);
+ close(con->http.fd);
+ FD_CLR(con->http.fd, &InputSet);
+ FD_CLR(con->http.fd, &OutputSet);
+ con->http.fd = 0;
+ }
+
+ if (con->pipe_pid != 0)
+ {
+ LogMessage(L_DEBUG2, "CloseClient: Removing fd %d from InputSet...",
+ con->file);
+ FD_CLR(con->file, &InputSet);
+ }
+
+ if (con->file)
+ {
+ /*
+ * Close the open data file...
+ */
+
+ if (con->pipe_pid)
+ {
+ kill(con->pipe_pid, SIGKILL);
+ waitpid(con->pipe_pid, &status, WNOHANG);
+ }
+
+ LogMessage(L_DEBUG2, "CloseClient: %d Closing data file %d.",
+ con->http.fd, con->file);
+ LogMessage(L_DEBUG2, "CloseClient: %d Removing fd %d from InputSet.",
+ con->http.fd, con->file);
+
+ FD_CLR(con->file, &InputSet);
+ close(con->file);
+ con->file = 0;
+ }
+
+ if (con->request)
+ {
+ ippDelete(con->request);
+ con->request = NULL;
+ }
+
+ if (con->response)
+ {
+ ippDelete(con->response);
+ con->response = NULL;
+ }
+
+ if (con->language)
+ {
+ cupsLangFree(con->language);
+ con->language = NULL;
+ }
+
+ /*
+ * Re-enable new client connections if we are going back under the
+ * limit...
+ */
+
+ if (NumClients == MaxClients)
+ ResumeListening();
+
+ /*
+ * Compact the list of clients as necessary...
+ */
+
+ NumClients --;
+
+ if (con < (Clients + NumClients))
+ memcpy(con, con + 1, (Clients + NumClients - con) * sizeof(client_t));
+}
+
+
+/*
+ * 'EncryptClient()' - Enable encryption for the client...
+ */
+
+int /* O - 1 on success, 0 on error */
+EncryptClient(client_t *con) /* I - Client to encrypt */
+{
+#ifdef HAVE_LIBSSL
+ SSL_CTX *context; /* Context for encryption */
+ SSL *conn; /* Connection for encryption */
+ unsigned long error; /* Error code */
+
+
+ /*
+ * Create the SSL context and accept the connection...
+ */
+
+ context = SSL_CTX_new(SSLv23_method());
+ conn = SSL_new(context);
+
+ SSL_use_PrivateKey_file(conn, ServerKey, SSL_FILETYPE_PEM);
+ SSL_use_certificate_file(conn, ServerCertificate, SSL_FILETYPE_PEM);
+
+ SSL_set_fd(conn, con->http.fd);
+ if (SSL_accept(conn) != 1)
+ {
+ while ((error = ERR_get_error()) != 0)
+ LogMessage(L_ERROR, "EncryptClient: %s", ERR_error_string(error, NULL));
+
+ SSL_CTX_free(context);
+ SSL_free(conn);
+ return (0);
+ }
+
+ LogMessage(L_DEBUG, "EncryptClient() %d Connection now encrypted.",
+ con->http.fd);
+
+ con->http.tls = conn;
+ return (1);
+#else
+ return (0);
+#endif /* HAVE_LIBSSL */
+}
+
+
+/*
+ * 'ReadClient()' - Read data from a client.
+ */
+
+int /* O - 1 on success, 0 on error */
+ReadClient(client_t *con) /* I - Client to read from */
+{
+ char line[32768], /* Line from client... */
+ operation[64], /* Operation code from socket */
+ version[64]; /* HTTP version number string */
+ int major, minor; /* HTTP version numbers */
+ http_status_t status; /* Transfer status */
+ ipp_state_t ipp_state; /* State of IPP transfer */
+ int bytes; /* Number of bytes to POST */
+ char *filename; /* Name of file for GET/HEAD */
+ struct stat filestats; /* File information */
+ mime_type_t *type; /* MIME type of file */
+ printer_t *p; /* Printer */
+ location_t *best; /* Best match for authentication */
+ static unsigned request_id = 0;/* Request ID for temp files */
+
+
+ status = HTTP_CONTINUE;
+
+ switch (con->http.state)
+ {
+ case HTTP_WAITING :
+ /*
+ * See if we've received a request line...
+ */
+
+ if (httpGets(line, sizeof(line) - 1, HTTP(con)) == NULL)
+ {
+ CloseClient(con);
+ return (0);
+ }
+
+ /*
+ * Ignore blank request lines...
+ */
+
+ if (line[0] == '\0')
+ break;
+
+ /*
+ * Clear other state variables...
+ */
+
+ httpClearFields(HTTP(con));
+
+ con->http.activity = time(NULL);
+ con->http.version = HTTP_1_0;
+ con->http.keep_alive = HTTP_KEEPALIVE_OFF;
+ con->http.data_encoding = HTTP_ENCODE_LENGTH;
+ con->http.data_remaining = 0;
+ con->operation = HTTP_WAITING;
+ con->bytes = 0;
+ con->file = 0;
+ con->pipe_pid = 0;
+ con->command[0] = '\0';
+ con->username[0] = '\0';
+ con->password[0] = '\0';
+ con->uri[0] = '\0';
+
+ if (con->language != NULL)
+ {
+ cupsLangFree(con->language);
+ con->language = NULL;
+ }
+
+ /*
+ * Grab the request line...
+ */
+
+ switch (sscanf(line, "%63s%1023s%63s", operation, con->uri, version))
+ {
+ case 1 :
+ SendError(con, HTTP_BAD_REQUEST);
+ CloseClient(con);
+ return (0);
+ case 2 :
+ con->http.version = HTTP_0_9;
+ break;
+ case 3 :
+ if (sscanf(version, "HTTP/%d.%d", &major, &minor) != 2)
+ {
+ SendError(con, HTTP_BAD_REQUEST);
+ CloseClient(con);
+ return (0);
+ }
+
+ if (major < 2)
+ {
+ con->http.version = (http_version_t)(major * 100 + minor);
+ if (con->http.version == HTTP_1_1 && KeepAlive)
+ con->http.keep_alive = HTTP_KEEPALIVE_ON;
+ else
+ con->http.keep_alive = HTTP_KEEPALIVE_OFF;
+ }
+ else
+ {
+ SendError(con, HTTP_NOT_SUPPORTED);
+ CloseClient(con);
+ return (0);
+ }
+ break;
+ }
+
+ /*
+ * Process the request...
+ */
+
+ if (strcmp(operation, "GET") == 0)
+ con->http.state = HTTP_GET;
+ else if (strcmp(operation, "PUT") == 0)
+ con->http.state = HTTP_PUT;
+ else if (strcmp(operation, "POST") == 0)
+ con->http.state = HTTP_POST;
+ else if (strcmp(operation, "DELETE") == 0)
+ con->http.state = HTTP_DELETE;
+ else if (strcmp(operation, "TRACE") == 0)
+ con->http.state = HTTP_TRACE;
+ else if (strcmp(operation, "OPTIONS") == 0)
+ con->http.state = HTTP_OPTIONS;
+ else if (strcmp(operation, "HEAD") == 0)
+ con->http.state = HTTP_HEAD;
+ else
+ {
+ SendError(con, HTTP_BAD_REQUEST);
+ CloseClient(con);
+ return (0);
+ }
+
+ con->start = time(NULL);
+ con->operation = con->http.state;
+
+ LogMessage(L_DEBUG, "ReadClient() %d %s %s HTTP/%d.%d", con->http.fd,
+ operation, con->uri,
+ con->http.version / 100, con->http.version % 100);
+
+ con->http.status = HTTP_OK;
+
+ case HTTP_OPTIONS :
+ case HTTP_DELETE :
+ case HTTP_GET :
+ case HTTP_HEAD :
+ case HTTP_POST :
+ case HTTP_PUT :
+ case HTTP_TRACE :
+ /*
+ * Parse incoming parameters until the status changes...
+ */
+
+ status = httpUpdate(HTTP(con));
+
+ if (status != HTTP_OK && status != HTTP_CONTINUE)
+ {
+ SendError(con, HTTP_BAD_REQUEST);
+ CloseClient(con);
+ return (0);
+ }
+ break;
+
+ default :
+ break; /* Anti-compiler-warning-code */
+ }
+
+ /*
+ * Handle new transfers...
+ */
+
+ if (status == HTTP_OK)
+ {
+ con->language = cupsLangGet(con->http.fields[HTTP_FIELD_ACCEPT_LANGUAGE]);
+
+ decode_auth(con);
+
+ if (strncmp(con->http.fields[HTTP_FIELD_CONNECTION], "Keep-Alive", 10) == 0 &&
+ KeepAlive)
+ con->http.keep_alive = HTTP_KEEPALIVE_ON;
+
+ if (con->http.fields[HTTP_FIELD_HOST][0] == '\0' &&
+ con->http.version >= HTTP_1_1)
+ {
+ /*
+ * HTTP/1.1 and higher require the "Host:" field...
+ */
+
+ if (!SendError(con, HTTP_BAD_REQUEST))
+ {
+ CloseClient(con);
+ return (0);
+ }
+ }
+ else if (con->operation == HTTP_OPTIONS)
+ {
+ /*
+ * Do OPTIONS command...
+ */
+
+ if ((best = FindBest(con->uri, con->http.state)) != NULL &&
+ best->type != AUTH_NONE)
+ {
+ if (!SendHeader(con, HTTP_UNAUTHORIZED, NULL))
+ {
+ CloseClient(con);
+ return (0);
+ }
+ }
+
+ if (strcasecmp(con->http.fields[HTTP_FIELD_CONNECTION], "Upgrade") == 0 &&
+ con->http.tls == NULL)
+ {
+#ifdef HAVE_LIBSSL
+ /*
+ * Do encryption stuff...
+ */
+
+ if (!SendHeader(con, HTTP_SWITCHING_PROTOCOLS, NULL))
+ {
+ CloseClient(con);
+ return (0);
+ }
+
+ httpPrintf(HTTP(con), "Connection: Upgrade\r\n");
+ httpPrintf(HTTP(con), "Upgrade: TLS/1.0,HTTP/1.1\r\n");
+ httpPrintf(HTTP(con), "Content-Length: 0\r\n");
+ httpPrintf(HTTP(con), "\r\n");
+
+ EncryptClient(con);
+#else
+ if (!SendError(con, HTTP_NOT_IMPLEMENTED))
+ {
+ CloseClient(con);
+ return (0);
+ }
+#endif /* HAVE_LIBSSL */
+ }
+
+ if (!SendHeader(con, HTTP_OK, NULL))
+ {
+ CloseClient(con);
+ return (0);
+ }
+
+ httpPrintf(HTTP(con), "Allow: GET, HEAD, OPTIONS, POST, PUT\r\n");
+ httpPrintf(HTTP(con), "Content-Length: 0\r\n");
+ httpPrintf(HTTP(con), "\r\n");
+ }
+ else if (strstr(con->uri, "..") != NULL)
+ {
+ /*
+ * Protect against malicious users!
+ */
+
+ if (!SendError(con, HTTP_FORBIDDEN))
+ {
+ CloseClient(con);
+ return (0);
+ }
+ }
+ else if (con->uri[0] != '/')
+ {
+ /*
+ * Don't allow proxying (yet)...
+ */
+
+ if (!SendError(con, HTTP_METHOD_NOT_ALLOWED))
+ {
+ CloseClient(con);
+ return (0);
+ }
+ }
+ else
+ {
+ if (strcasecmp(con->http.fields[HTTP_FIELD_CONNECTION], "Upgrade") == 0 &&
+ con->http.tls == NULL)
+ {
+#ifdef HAVE_LIBSSL
+ /*
+ * Do encryption stuff...
+ */
+
+ if (!SendHeader(con, HTTP_SWITCHING_PROTOCOLS, NULL))
+ {
+ CloseClient(con);
+ return (0);
+ }
+
+ httpPrintf(HTTP(con), "Connection: Upgrade\r\n");
+ httpPrintf(HTTP(con), "Upgrade: TLS/1.0,HTTP/1.1\r\n");
+ httpPrintf(HTTP(con), "Content-Length: 0\r\n");
+ httpPrintf(HTTP(con), "\r\n");
+
+ EncryptClient(con);
+#else
+ if (!SendError(con, HTTP_NOT_IMPLEMENTED))
+ {
+ CloseClient(con);
+ return (0);
+ }
+#endif /* HAVE_LIBSSL */
+ }
+
+ if ((status = IsAuthorized(con)) != HTTP_OK)
+ {
+ SendError(con, status);
+ CloseClient(con);
+ return (0);
+ }
+
+ switch (con->http.state)
+ {
+ case HTTP_GET_SEND :
+ if (strncmp(con->uri, "/printers/", 10) == 0 &&
+ strcmp(con->uri + strlen(con->uri) - 4, ".ppd") == 0)
+ {
+ /*
+ * Send PPD file - get the real printer name since printer
+ * names are not case sensitive but filenames can be...
+ */
+
+ con->uri[strlen(con->uri) - 4] = '\0'; /* Drop ".ppd" */
+
+ if ((p = FindPrinter(con->uri + 10)) != NULL)
+ snprintf(con->uri, sizeof(con->uri), "/ppd/%s.ppd", p->name);
+ else
+ {
+ if (!SendError(con, HTTP_NOT_FOUND))
+ {
+ CloseClient(con);
+ return (0);
+ }
+
+ break;
+ }
+ }
+
+ if ((strncmp(con->uri, "/admin", 6) == 0 &&
+ strncmp(con->uri, "/admin/conf/", 12) != 0) ||
+ strncmp(con->uri, "/printers", 9) == 0 ||
+ strncmp(con->uri, "/classes", 8) == 0 ||
+ strncmp(con->uri, "/jobs", 5) == 0)
+ {
+ /*
+ * Send CGI output...
+ */
+
+ if (strncmp(con->uri, "/admin", 6) == 0)
+ {
+ snprintf(con->command, sizeof(con->command),
+ "%s/cgi-bin/admin.cgi", ServerBin);
+ con->options = con->uri + 6;
+ }
+ else if (strncmp(con->uri, "/printers", 9) == 0)
+ {
+ snprintf(con->command, sizeof(con->command),
+ "%s/cgi-bin/printers.cgi", ServerBin);
+ con->options = con->uri + 9;
+ }
+ else if (strncmp(con->uri, "/classes", 8) == 0)
+ {
+ snprintf(con->command, sizeof(con->command),
+ "%s/cgi-bin/classes.cgi", ServerBin);
+ con->options = con->uri + 8;
+ }
+ else
+ {
+ snprintf(con->command, sizeof(con->command),
+ "%s/cgi-bin/jobs.cgi", ServerBin);
+ con->options = con->uri + 5;
+ }
+
+ if (con->options[0] == '/')
+ con->options ++;
+
+ if (!SendCommand(con, con->command, con->options))
+ {
+ if (!SendError(con, HTTP_NOT_FOUND))
+ {
+ CloseClient(con);
+ return (0);
+ }
+ }
+ else
+ LogRequest(con, HTTP_OK);
+
+ if (con->http.version <= HTTP_1_0)
+ con->http.keep_alive = HTTP_KEEPALIVE_OFF;
+ }
+ else if (strncmp(con->uri, "/admin/conf/", 12) == 0 &&
+ (strchr(con->uri + 12, '/') != NULL ||
+ strlen(con->uri) == 12))
+ {
+ /*
+ * GET can only be done to configuration files under
+ * /admin/conf...
+ */
+
+ if (!SendError(con, HTTP_FORBIDDEN))
+ {
+ CloseClient(con);
+ return (0);
+ }
+
+ break;
+ }
+ else
+ {
+ /*
+ * Serve a file...
+ */
+
+ if ((filename = get_file(con, &filestats)) == NULL)
+ {
+ if (!SendError(con, HTTP_NOT_FOUND))
+ {
+ CloseClient(con);
+ return (0);
+ }
+ }
+ else if (!check_if_modified(con, &filestats))
+ {
+ if (!SendError(con, HTTP_NOT_MODIFIED))
+ {
+ CloseClient(con);
+ return (0);
+ }
+ }
+ else
+ {
+ type = mimeFileType(MimeDatabase, filename);
+ if (type == NULL)
+ strcpy(line, "text/plain");
+ else
+ snprintf(line, sizeof(line), "%s/%s", type->super, type->type);
+
+ if (!SendFile(con, HTTP_OK, filename, line, &filestats))
+ {
+ CloseClient(con);
+ return (0);
+ }
+ }
+ }
+ break;
+
+ case HTTP_POST_RECV :
+ /*
+ * See if the POST request includes a Content-Length field, and if
+ * so check the length against any limits that are set...
+ */
+
+ LogMessage(L_DEBUG2, "POST %s", con->uri);
+ LogMessage(L_DEBUG2, "CONTENT_TYPE = %s", con->http.fields[HTTP_FIELD_CONTENT_TYPE]);
+
+ if (con->http.fields[HTTP_FIELD_CONTENT_LENGTH][0] &&
+ atoi(con->http.fields[HTTP_FIELD_CONTENT_LENGTH]) > MaxRequestSize &&
+ MaxRequestSize > 0)
+ {
+ /*
+ * Request too large...
+ */
+
+ if (!SendError(con, HTTP_REQUEST_TOO_LARGE))
+ {
+ CloseClient(con);
+ return (0);
+ }
+
+ break;
+ }
+
+ /*
+ * See what kind of POST request this is; for IPP requests the
+ * content-type field will be "application/ipp"...
+ */
+
+ if (strcmp(con->http.fields[HTTP_FIELD_CONTENT_TYPE], "application/ipp") == 0)
+ con->request = ippNew();
+ else if ((strncmp(con->uri, "/admin", 6) == 0 &&
+ strncmp(con->uri, "/admin/conf/", 12) != 0) ||
+ strncmp(con->uri, "/printers", 9) == 0 ||
+ strncmp(con->uri, "/classes", 8) == 0 ||
+ strncmp(con->uri, "/jobs", 5) == 0)
+ {
+ /*
+ * CGI request...
+ */
+
+ if (strncmp(con->uri, "/admin", 6) == 0)
+ {
+ snprintf(con->command, sizeof(con->command),
+ "%s/cgi-bin/admin.cgi", ServerBin);
+ con->options = con->uri + 6;
+ }
+ else if (strncmp(con->uri, "/printers", 9) == 0)
+ {
+ snprintf(con->command, sizeof(con->command),
+ "%s/cgi-bin/printers.cgi", ServerBin);
+ con->options = con->uri + 9;
+ }
+ else if (strncmp(con->uri, "/classes", 8) == 0)
+ {
+ snprintf(con->command, sizeof(con->command),
+ "%s/cgi-bin/classes.cgi", ServerBin);
+ con->options = con->uri + 8;
+ }
+ else
+ {
+ snprintf(con->command, sizeof(con->command),
+ "%s/cgi-bin/jobs.cgi", ServerBin);
+ con->options = con->uri + 5;
+ }
+
+ if (con->options[0] == '/')
+ con->options ++;
+
+ LogMessage(L_DEBUG2, "ReadClient() %d command=\"%s\", options = \"%s\"",
+ con->http.fd, con->command, con->options);
+
+ if (con->http.version <= HTTP_1_0)
+ con->http.keep_alive = HTTP_KEEPALIVE_OFF;
+ }
+ else if (!SendError(con, HTTP_UNAUTHORIZED))
+ {
+ CloseClient(con);
+ return (0);
+ }
+ break;
+
+ case HTTP_PUT_RECV :
+ /*
+ * Validate the resource name...
+ */
+
+ if (strncmp(con->uri, "/admin/conf/", 12) != 0 ||
+ strchr(con->uri + 12, '/') != NULL ||
+ strlen(con->uri) == 12)
+ {
+ /*
+ * PUT can only be done to configuration files under
+ * /admin/conf...
+ */
+
+ if (!SendError(con, HTTP_FORBIDDEN))
+ {
+ CloseClient(con);
+ return (0);
+ }
+
+ break;
+ }
+
+ /*
+ * See if the PUT request includes a Content-Length field, and if
+ * so check the length against any limits that are set...
+ */
+
+ LogMessage(L_DEBUG2, "PUT %s", con->uri);
+ LogMessage(L_DEBUG2, "CONTENT_TYPE = %s", con->http.fields[HTTP_FIELD_CONTENT_TYPE]);
+
+ if (con->http.fields[HTTP_FIELD_CONTENT_LENGTH][0] &&
+ atoi(con->http.fields[HTTP_FIELD_CONTENT_LENGTH]) > MaxRequestSize &&
+ MaxRequestSize > 0)
+ {
+ /*
+ * Request too large...
+ */
+
+ if (!SendError(con, HTTP_REQUEST_TOO_LARGE))
+ {
+ CloseClient(con);
+ return (0);
+ }
+
+ break;
+ }
+
+ /*
+ * Open a temporary file to hold the request...
+ */
+
+ snprintf(con->filename, sizeof(con->filename), "%s/%08x",
+ RequestRoot, request_id ++);
+ con->file = open(con->filename, O_WRONLY | O_CREAT | O_TRUNC, 0640);
+ fchmod(con->file, 0640);
+ fchown(con->file, User, Group);
+
+ LogMessage(L_DEBUG2, "ReadClient() %d REQUEST %s=%d", con->http.fd,
+ con->filename, con->file);
+
+ if (con->file < 0)
+ {
+ if (!SendError(con, HTTP_REQUEST_TOO_LARGE))
+ {
+ CloseClient(con);
+ return (0);
+ }
+ }
+ break;
+
+ case HTTP_DELETE :
+ case HTTP_TRACE :
+ SendError(con, HTTP_NOT_IMPLEMENTED);
+ CloseClient(con);
+ return (0);
+
+ case HTTP_HEAD :
+ if (strncmp(con->uri, "/printers/", 10) == 0 &&
+ strcmp(con->uri + strlen(con->uri) - 4, ".ppd") == 0)
+ {
+ /*
+ * Send PPD file - get the real printer name since printer
+ * names are not case sensitive but filenames can be...
+ */
+
+ con->uri[strlen(con->uri) - 4] = '\0'; /* Drop ".ppd" */
+
+ if ((p = FindPrinter(con->uri + 10)) != NULL)
+ snprintf(con->uri, sizeof(con->uri), "/ppd/%s.ppd", p->name);
+ else
+ {
+ if (!SendError(con, HTTP_NOT_FOUND))
+ {
+ CloseClient(con);
+ return (0);
+ }
+
+ break;
+ }
+ }
+
+ if ((strncmp(con->uri, "/admin/", 7) == 0 &&
+ strncmp(con->uri, "/admin/conf/", 12) != 0) ||
+ strncmp(con->uri, "/printers/", 10) == 0 ||
+ strncmp(con->uri, "/classes/", 9) == 0 ||
+ strncmp(con->uri, "/jobs/", 6) == 0)
+ {
+ /*
+ * CGI output...
+ */
+
+ if (!SendHeader(con, HTTP_OK, "text/html"))
+ {
+ CloseClient(con);
+ return (0);
+ }
+
+ if (httpPrintf(HTTP(con), "\r\n") < 0)
+ {
+ CloseClient(con);
+ return (0);
+ }
+
+ LogRequest(con, HTTP_OK);
+ }
+ else if (strncmp(con->uri, "/admin/conf/", 12) == 0 &&
+ (strchr(con->uri + 12, '/') != NULL ||
+ strlen(con->uri) == 12))
+ {
+ /*
+ * HEAD can only be done to configuration files under
+ * /admin/conf...
+ */
+
+ if (!SendError(con, HTTP_FORBIDDEN))
+ {
+ CloseClient(con);
+ return (0);
+ }
+
+ break;
+ }
+ else if ((filename = get_file(con, &filestats)) == NULL)
+ {
+ if (!SendHeader(con, HTTP_NOT_FOUND, "text/html"))
+ {
+ CloseClient(con);
+ return (0);
+ }
+
+ LogRequest(con, HTTP_NOT_FOUND);
+ }
+ else if (!check_if_modified(con, &filestats))
+ {
+ if (!SendError(con, HTTP_NOT_MODIFIED))
+ {
+ CloseClient(con);
+ return (0);
+ }
+
+ LogRequest(con, HTTP_NOT_MODIFIED);
+ }
+ else
+ {
+ /*
+ * Serve a file...
+ */
+
+ type = mimeFileType(MimeDatabase, filename);
+ if (type == NULL)
+ strcpy(line, "text/plain");
+ else
+ snprintf(line, sizeof(line), "%s/%s", type->super, type->type);
+
+ if (!SendHeader(con, HTTP_OK, line))
+ {
+ CloseClient(con);
+ return (0);
+ }
+
+ if (httpPrintf(HTTP(con), "Last-Modified: %s\r\n",
+ httpGetDateString(filestats.st_mtime)) < 0)
+ {
+ CloseClient(con);
+ return (0);
+ }
+
+ if (httpPrintf(HTTP(con), "Content-Length: %lu\r\n",
+ (unsigned long)filestats.st_size) < 0)
+ {
+ CloseClient(con);
+ return (0);
+ }
+
+ LogRequest(con, HTTP_OK);
+ }
+
+ if (httpPrintf(HTTP(con), "\r\n") < 0)
+ {
+ CloseClient(con);
+ return (0);
+ }
+
+ con->http.state = HTTP_WAITING;
+ break;
+
+ default :
+ break; /* Anti-compiler-warning-code */
+ }
+ }
+ }
+
+ /*
+ * Handle any incoming data...
+ */
+
+ switch (con->http.state)
+ {
+ case HTTP_PUT_RECV :
+ LogMessage(L_DEBUG2, "ReadClient() %d con->data_encoding = %s, con->data_remaining = %d, con->file = %d",
+ con->http.fd,
+ con->http.data_encoding == HTTP_ENCODE_CHUNKED ? "chunked" : "length",
+ con->http.data_remaining, con->file);
+
+ if ((bytes = httpRead(HTTP(con), line, sizeof(line))) < 0)
+ {
+ CloseClient(con);
+ return (0);
+ }
+ else if (bytes > 0)
+ {
+ con->bytes += bytes;
+
+ LogMessage(L_DEBUG2, "ReadClient() %d writing %d bytes to %d",
+ con->http.fd, bytes, con->file);
+
+ if (write(con->file, line, bytes) < bytes)
+ {
+ LogMessage(L_ERROR, "ReadClient: Unable to write %d bytes to %s: %s",
+ bytes, con->filename, strerror(errno));
+
+ close(con->file);
+ con->file = 0;
+ unlink(con->filename);
+ con->filename[0] = '\0';
+
+ if (!SendError(con, HTTP_REQUEST_TOO_LARGE))
+ {
+ CloseClient(con);
+ return (0);
+ }
+ }
+ }
+
+ if (con->http.state == HTTP_WAITING)
+ {
+ /*
+ * End of file, see how big it is...
+ */
+
+ fstat(con->file, &filestats);
+
+ LogMessage(L_DEBUG2, "ReadClient() %d Closing data file %d, size = %d.",
+ con->http.fd, con->file, filestats.st_size);
+
+ close(con->file);
+ con->file = 0;
+
+ if (filestats.st_size > MaxRequestSize &&
+ MaxRequestSize > 0)
+ {
+ /*
+ * Request is too big; remove it and send an error...
+ */
+
+ LogMessage(L_DEBUG2, "ReadClient() %d Removing temp file %s",
+ con->http.fd, con->filename);
+ unlink(con->filename);
+ con->filename[0] = '\0';
+
+ if (!SendError(con, HTTP_REQUEST_TOO_LARGE))
+ {
+ CloseClient(con);
+ return (0);
+ }
+ }
+
+ /*
+ * Install the configuration file...
+ */
+
+ status = install_conf_file(con);
+
+ /*
+ * Return the status to the client...
+ */
+
+ if (!SendError(con, status))
+ {
+ CloseClient(con);
+ return (0);
+ }
+ }
+ break;
+
+ case HTTP_POST_RECV :
+ LogMessage(L_DEBUG2, "ReadClient() %d con->data_encoding = %s, con->data_remaining = %d, con->file = %d",
+ con->http.fd,
+ con->http.data_encoding == HTTP_ENCODE_CHUNKED ? "chunked" : "length",
+ con->http.data_remaining, con->file);
+
+ if (con->request != NULL)
+ {
+ /*
+ * Grab any request data from the connection...
+ */
+
+ if ((ipp_state = ippRead(&(con->http), con->request)) == IPP_ERROR)
+ {
+ LogMessage(L_ERROR, "ReadClient() %d IPP Read Error!",
+ con->http.fd);
+ CloseClient(con);
+ return (0);
+ }
+ else if (ipp_state != IPP_DATA)
+ break;
+ else
+ con->bytes += ippLength(con->request);
+ }
+
+ if (con->file == 0 && con->http.state != HTTP_POST_SEND)
+ {
+ /*
+ * Create a file as needed for the request data...
+ */
+
+ snprintf(con->filename, sizeof(con->filename), "%s/%08x",
+ RequestRoot, request_id ++);
+ con->file = open(con->filename, O_WRONLY | O_CREAT | O_TRUNC, 0640);
+ fchmod(con->file, 0640);
+ fchown(con->file, User, Group);
+
+ LogMessage(L_DEBUG2, "ReadClient() %d REQUEST %s=%d", con->http.fd,
+ con->filename, con->file);
+
+ if (con->file < 0)
+ {
+ if (!SendError(con, HTTP_REQUEST_TOO_LARGE))
+ {
+ CloseClient(con);
+ return (0);
+ }
+ }
+ }
+
+ if (con->http.state != HTTP_POST_SEND)
+ {
+ if ((bytes = httpRead(HTTP(con), line, sizeof(line))) < 0)
+ {
+ CloseClient(con);
+ return (0);
+ }
+ else if (bytes > 0)
+ {
+ con->bytes += bytes;
+
+ LogMessage(L_DEBUG2, "ReadClient() %d writing %d bytes to %d",
+ con->http.fd, bytes, con->file);
+
+ if (write(con->file, line, bytes) < bytes)
+ {
+ LogMessage(L_ERROR, "ReadClient: Unable to write %d bytes to %s: %s",
+ bytes, con->filename, strerror(errno));
+
+ close(con->file);
+ con->file = 0;
+ unlink(con->filename);
+ con->filename[0] = '\0';
+
+ if (!SendError(con, HTTP_REQUEST_TOO_LARGE))
+ {
+ CloseClient(con);
+ return (0);
+ }
+ }
+ }
+ else if (con->http.state != HTTP_POST_SEND)
+ {
+ CloseClient(con);
+ return (0);
+ }
+ }
+
+ if (con->http.state == HTTP_POST_SEND)
+ {
+ if (con->file)
+ {
+ fstat(con->file, &filestats);
+
+ LogMessage(L_DEBUG2, "ReadClient() %d Closing data file %d, size = %d.",
+ con->http.fd, con->file, filestats.st_size);
+
+ close(con->file);
+ con->file = 0;
+
+ if (filestats.st_size > MaxRequestSize &&
+ MaxRequestSize > 0)
+ {
+ /*
+ * Request is too big; remove it and send an error...
+ */
+
+ LogMessage(L_DEBUG2, "ReadClient() %d Removing temp file %s",
+ con->http.fd, con->filename);
+ unlink(con->filename);
+ con->filename[0] = '\0';
+
+ if (con->request)
+ {
+ /*
+ * Delete any IPP request data...
+ */
+
+ ippDelete(con->request);
+ con->request = NULL;
+ }
+
+ if (!SendError(con, HTTP_REQUEST_TOO_LARGE))
+ {
+ CloseClient(con);
+ return (0);
+ }
+ }
+
+ if (con->command[0])
+ {
+ if (!SendCommand(con, con->command, con->options))
+ {
+ if (!SendError(con, HTTP_NOT_FOUND))
+ {
+ CloseClient(con);
+ return (0);
+ }
+ }
+ else
+ LogRequest(con, HTTP_OK);
+ }
+ }
+
+ if (con->request)
+ ProcessIPPRequest(con);
+ }
+ break;
+
+ default :
+ break; /* Anti-compiler-warning-code */
+ }
+
+ if (!con->http.keep_alive && con->http.state == HTTP_WAITING)
+ {
+ CloseClient(con);
+ return (0);
+ }
+ else
+ return (1);
+}
+
+
+/*
+ * 'SendCommand()' - Send output from a command via HTTP.
+ */
+
+int
+SendCommand(client_t *con,
+ char *command,
+ char *options)
+{
+ int fd;
+
+
+ if (con->filename[0])
+ fd = open(con->filename, O_RDONLY);
+ else
+ fd = open("/dev/null", O_RDONLY);
+
+ con->pipe_pid = pipe_command(con, fd, &(con->file), command, options);
+
+ close(fd);
+
+ LogMessage(L_INFO, "Started \"%s\" (pid=%d)", command, con->pipe_pid);
+
+ LogMessage(L_DEBUG, "SendCommand() %d file=%d", con->http.fd, con->file);
+
+ if (con->pipe_pid == 0)
+ return (0);
+
+ fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
+
+ LogMessage(L_DEBUG2, "SendCommand: Adding fd %d to InputSet...", con->file);
+ LogMessage(L_DEBUG2, "SendCommand: Adding fd %d to OutputSet...",
+ con->http.fd);
+
+ FD_SET(con->file, &InputSet);
+ FD_SET(con->http.fd, &OutputSet);
+
+ if (!SendHeader(con, HTTP_OK, NULL))
+ return (0);
+
+ if (con->http.version == HTTP_1_1)
+ {
+ con->http.data_encoding = HTTP_ENCODE_CHUNKED;
+
+ if (httpPrintf(HTTP(con), "Transfer-Encoding: chunked\r\n") < 0)
+ return (0);
+ }
+
+ con->got_fields = 0;
+ con->field_col = 0;
+
+ return (1);
+}
+
+
+/*
+ * 'SendError()' - Send an error message via HTTP.
+ */
+
+int /* O - 1 if successful, 0 otherwise */
+SendError(client_t *con, /* I - Connection */
+ http_status_t code) /* I - Error code */
+{
+ char message[1024]; /* Message for user */
+
+
+ /*
+ * Put the request in the access_log file...
+ */
+
+ if (con->operation > HTTP_WAITING)
+ LogRequest(con, code);
+
+ LogMessage(L_DEBUG, "SendError() %d code=%d", con->http.fd, code);
+
+ /*
+ * To work around bugs in some proxies, don't use Keep-Alive for some
+ * error messages...
+ */
+
+ if (code >= HTTP_BAD_REQUEST)
+ con->http.keep_alive = HTTP_KEEPALIVE_OFF;
+
+ /*
+ * Send an error message back to the client. If the error code is a
+ * 400 or 500 series, make sure the message contains some text, too!
+ */
+
+ if (!SendHeader(con, code, NULL))
+ return (0);
+
+#ifdef HAVE_LIBSSL
+ if (code == HTTP_UPGRADE_REQUIRED)
+ if (httpPrintf(HTTP(con), "Connection: Upgrade\r\n") < 0)
+ return (0);
+
+ if (httpPrintf(HTTP(con), "Upgrade: TLS/1.0,HTTP/1.1\r\n") < 0)
+ return (0);
+#endif /* HAVE_LIBSSL */
+
+ if (con->http.version >= HTTP_1_1 && !con->http.keep_alive)
+ {
+ if (httpPrintf(HTTP(con), "Connection: close\r\n") < 0)
+ return (0);
+ }
+
+ if (code >= HTTP_BAD_REQUEST)
+ {
+ /*
+ * Send a human-readable error message.
+ */
+
+ snprintf(message, sizeof(message),
+ "<HTML><HEAD><TITLE>%d %s</TITLE></HEAD>"
+ "<BODY><H1>%s</H1>%s</BODY></HTML>\n",
+ code, httpStatus(code), httpStatus(code),
+ con->language ? con->language->messages[code] :
+ httpStatus(code));
+
+ if (httpPrintf(HTTP(con), "Content-Type: text/html\r\n") < 0)
+ return (0);
+ if (httpPrintf(HTTP(con), "Content-Length: %d\r\n", strlen(message)) < 0)
+ return (0);
+ if (httpPrintf(HTTP(con), "\r\n") < 0)
+ return (0);
+ if (httpPrintf(HTTP(con), "%s", message) < 0)
+ return (0);
+ }
+ else if (httpPrintf(HTTP(con), "\r\n") < 0)
+ return (0);
+
+ con->http.state = HTTP_WAITING;
+
+ return (1);
+}
+
+
+/*
+ * 'SendFile()' - Send a file via HTTP.
+ */
+
+int
+SendFile(client_t *con,
+ http_status_t code,
+ char *filename,
+ char *type,
+ struct stat *filestats)
+{
+ con->file = open(filename, O_RDONLY);
+
+ LogMessage(L_DEBUG, "SendFile() %d file=%d", con->http.fd, con->file);
+
+ if (con->file < 0)
+ return (0);
+
+ fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
+
+ con->pipe_pid = 0;
+
+ if (!SendHeader(con, code, type))
+ return (0);
+
+ if (httpPrintf(HTTP(con), "Last-Modified: %s\r\n", httpGetDateString(filestats->st_mtime)) < 0)
+ return (0);
+ if (httpPrintf(HTTP(con), "Content-Length: %lu\r\n",
+ (unsigned long)filestats->st_size) < 0)
+ return (0);
+ if (httpPrintf(HTTP(con), "\r\n") < 0)
+ return (0);
+
+ LogMessage(L_DEBUG2, "SendFile: Adding fd %d to OutputSet...", con->http.fd);
+
+ FD_SET(con->http.fd, &OutputSet);
+
+ return (1);
+}
+
+
+/*
+ * 'SendHeader()' - Send an HTTP request.
+ */
+
+int /* O - 1 on success, 0 on failure */
+SendHeader(client_t *con, /* I - Client to send to */
+ http_status_t code, /* I - HTTP status code */
+ char *type) /* I - MIME type of document */
+{
+ location_t *loc; /* Authentication location */
+
+
+ if (httpPrintf(HTTP(con), "HTTP/%d.%d %d %s\r\n", con->http.version / 100,
+ con->http.version % 100, code, httpStatus(code)) < 0)
+ return (0);
+ if (httpPrintf(HTTP(con), "Date: %s\r\n", httpGetDateString(time(NULL))) < 0)
+ return (0);
+ if (httpPrintf(HTTP(con), "Server: CUPS/1.1\r\n") < 0)
+ return (0);
+ if (con->http.keep_alive && con->http.version >= HTTP_1_0)
+ {
+ if (httpPrintf(HTTP(con), "Connection: Keep-Alive\r\n") < 0)
+ return (0);
+ if (httpPrintf(HTTP(con), "Keep-Alive: timeout=%d\r\n", KeepAliveTimeout) < 0)
+ return (0);
+ }
+ if (code == HTTP_METHOD_NOT_ALLOWED)
+ if (httpPrintf(HTTP(con), "Allow: GET, HEAD, OPTIONS, POST\r\n") < 0)
+ return (0);
+
+ if (code == HTTP_UNAUTHORIZED)
+ {
+ /*
+ * This already succeeded in IsAuthorized...
+ */
+
+ loc = FindBest(con->uri, con->http.state);
+
+ if (loc->type != AUTH_DIGEST)
+ {
+ if (httpPrintf(HTTP(con), "WWW-Authenticate: Basic realm=\"CUPS\"\r\n") < 0)
+ return (0);
+ }
+ else
+ {
+ if (httpPrintf(HTTP(con), "WWW-Authenticate: Digest realm=\"CUPS\" "
+ "nonce=\"%s\"\r\n", con->http.hostname) < 0)
+ return (0);
+ }
+ }
+ if (con->language != NULL)
+ {
+ if (httpPrintf(HTTP(con), "Content-Language: %s\r\n",
+ con->language->language) < 0)
+ return (0);
+
+ if (type != NULL)
+ if (httpPrintf(HTTP(con), "Content-Type: %s; charset=%s\r\n", type,
+ cupsLangEncoding(con->language)) < 0)
+ return (0);
+ }
+ else if (type != NULL)
+ if (httpPrintf(HTTP(con), "Content-Type: %s\r\n", type) < 0)
+ return (0);
+
+ return (1);
+}
+
+
+/*
+ * 'WriteClient()' - Write data to a client as needed.
+ */
+
+int /* O - 1 if success, 0 if fail */
+WriteClient(client_t *con) /* I - Client connection */
+{
+ int bytes; /* Number of bytes written */
+ char buf[HTTP_MAX_BUFFER + 1];/* Data buffer */
+ char *bufptr; /* Pointer into buffer */
+ ipp_state_t ipp_state; /* IPP state value */
+
+
+ if (con->http.state != HTTP_GET_SEND &&
+ con->http.state != HTTP_POST_SEND)
+ return (1);
+
+ if (con->response != NULL)
+ {
+ ipp_state = ippWrite(&(con->http), con->response);
+ bytes = ipp_state != IPP_ERROR && ipp_state != IPP_DATA;
+ }
+ else if ((bytes = read(con->file, buf, HTTP_MAX_BUFFER)) > 0)
+ {
+ if (con->pipe_pid && !con->got_fields)
+ {
+ /*
+ * Inspect the data for Content-Type and other fields.
+ */
+
+ buf[bytes] = '\0';
+
+ for (bufptr = buf; !con->got_fields && *bufptr; bufptr ++)
+ if (*bufptr == '\n')
+ {
+ /*
+ * Send line to client...
+ */
+
+ if (bufptr > buf && bufptr[-1] == '\r')
+ bufptr[-1] = '\0';
+ *bufptr++ = '\0';
+
+ httpPrintf(HTTP(con), "%s\r\n", buf);
+ LogMessage(L_DEBUG2, "WriteClient() %d %s", con->http.fd, buf);
+
+ /*
+ * Update buffer...
+ */
+
+ bytes -= (bufptr - buf);
+ memcpy(buf, bufptr, bytes + 1);
+ bufptr = buf - 1;
+
+ /*
+ * See if the line was empty...
+ */
+
+ if (con->field_col == 0)
+ con->got_fields = 1;
+ else
+ con->field_col = 0;
+ }
+ else if (*bufptr != '\r')
+ con->field_col ++;
+
+ if (bytes > 0 && !con->got_fields)
+ {
+ /*
+ * Remaining text needs to go out...
+ */
+
+ httpPrintf(HTTP(con), "%s", buf);
+
+ con->http.activity = time(NULL);
+ return (1);
+ }
+ else if (bytes == 0)
+ {
+ con->http.activity = time(NULL);
+ return (1);
+ }
+ }
+
+ if (httpWrite(HTTP(con), buf, bytes) < 0)
+ {
+ CloseClient(con);
+ return (0);
+ }
+
+ con->bytes += bytes;
+ }
+
+ if (bytes <= 0)
+ {
+ LogRequest(con, HTTP_OK);
+
+ if (con->http.data_encoding == HTTP_ENCODE_CHUNKED)
+ {
+ if (httpPrintf(HTTP(con), "0\r\n\r\n") < 0)
+ {
+ CloseClient(con);
+ return (0);
+ }
+ }
+
+ con->http.state = HTTP_WAITING;
+
+ LogMessage(L_DEBUG2, "WriteClient: Removing fd %d from OutputSet...",
+ con->http.fd);
+
+ FD_CLR(con->http.fd, &OutputSet);
+
+ if (con->file)
+ {
+ LogMessage(L_DEBUG2, "WriteClient: Removing fd %d from InputSet...",
+ con->file);
+ FD_CLR(con->file, &InputSet);
+
+ if (con->pipe_pid)
+ kill(con->pipe_pid, SIGTERM);
+
+ LogMessage(L_DEBUG2, "WriteClient: %d Closing data file %d.",
+ con->http.fd, con->file);
+
+ close(con->file);
+ con->file = 0;
+ con->pipe_pid = 0;
+ }
+
+ if (con->filename[0])
+ {
+ LogMessage(L_DEBUG2, "WriteClient: %d Removing temp file %s",
+ con->http.fd, con->filename);
+ unlink(con->filename);
+ con->filename[0] = '\0';
+ }
+
+ if (con->request != NULL)
+ {
+ ippDelete(con->request);
+ con->request = NULL;
+ }
+
+ if (con->response != NULL)
+ {
+ ippDelete(con->response);
+ con->response = NULL;
+ }
+
+ if (!con->http.keep_alive)
+ {
+ CloseClient(con);
+ return (0);
+ }
+ }
+
+ if (bytes >= 1024)
+ LogMessage(L_DEBUG2, "WriteClient() %d %d bytes", con->http.fd, bytes);
+
+ con->http.activity = time(NULL);
+
+ return (1);
+}
+
+
+/*
+ * 'check_if_modified()' - Decode an "If-Modified-Since" line.
+ */
+
+static int /* O - 1 if modified since */
+check_if_modified(client_t *con, /* I - Client connection */
+ struct stat *filestats) /* I - File information */
+{
+ char *ptr; /* Pointer into field */
+ time_t date; /* Time/date value */
+ int size; /* Size/length value */
+
+
+ size = 0;
+ date = 0;
+ ptr = con->http.fields[HTTP_FIELD_IF_MODIFIED_SINCE];
+
+ if (*ptr == '\0')
+ return (1);
+
+ LogMessage(L_DEBUG2, "check_if_modified() %d If-Modified-Since=\"%s\"",
+ con->http.fd, ptr);
+
+ while (*ptr != '\0')
+ {
+ while (isspace(*ptr) || *ptr == ';')
+ ptr ++;
+
+ if (strncasecmp(ptr, "length=", 7) == 0)
+ {
+ ptr += 7;
+ size = atoi(ptr);
+
+ while (isdigit(*ptr))
+ ptr ++;
+ }
+ else if (isalpha(*ptr))
+ {
+ date = httpGetDateTime(ptr);
+ while (*ptr != '\0' && *ptr != ';')
+ ptr ++;
+ }
+ }
+
+ LogMessage(L_DEBUG2, "check_if_modified() %d sizes=%d,%d dates=%d,%d",
+ con->http.fd, size, filestats->st_size, date, filestats->st_mtime);
+
+ return ((size != filestats->st_size && size != 0) ||
+ (date < filestats->st_mtime && date != 0) ||
+ (size == 0 && date == 0));
+}
+
+
+/*
+ * 'decode_auth()' - Decode an authorization string.
+ */
+
+static void
+decode_auth(client_t *con) /* I - Client to decode to */
+{
+ char *s, /* Authorization string */
+ value[1024]; /* Value string */
+ const char *username; /* Certificate username */
+
+
+ /*
+ * Decode the string...
+ */
+
+ s = con->http.fields[HTTP_FIELD_AUTHORIZATION];
+
+ LogMessage(L_DEBUG2, "decode_auth(%08x): Authorization string = \"%s\"",
+ con, s);
+
+ if (strncmp(s, "Basic", 5) == 0)
+ {
+ s += 5;
+ while (isspace(*s))
+ s ++;
+
+ httpDecode64(value, s);
+
+ /*
+ * Pull the username and password out...
+ */
+
+ if ((s = strchr(value, ':')) == NULL)
+ {
+ LogMessage(L_DEBUG, "decode_auth() %d no colon in auth string \"%s\"",
+ con->http.fd, value);
+ return;
+ }
+
+ *s++ = '\0';
+
+ strncpy(con->username, value, sizeof(con->username) - 1);
+ con->username[sizeof(con->username) - 1] = '\0';
+
+ strncpy(con->password, s, sizeof(con->password) - 1);
+ con->password[sizeof(con->password) - 1] = '\0';
+ }
+ else if (strncmp(s, "Local", 5) == 0)
+ {
+ s += 5;
+ while (isspace(*s))
+ s ++;
+
+ if ((username = FindCert(s)) != NULL)
+ {
+ strncpy(con->username, username, sizeof(con->username) - 1);
+ con->username[sizeof(con->username) - 1] = '\0';
+ }
+ }
+ else if (strncmp(s, "Digest", 5) == 0)
+ {
+ /*
+ * Get the username and password from the Digest attributes...
+ */
+
+ if (httpGetSubField(&(con->http), HTTP_FIELD_AUTHORIZATION, "username",
+ value))
+ {
+ strncpy(con->username, value, sizeof(con->username) - 1);
+ con->username[sizeof(con->username) - 1] = '\0';
+ }
+
+ if (httpGetSubField(&(con->http), HTTP_FIELD_AUTHORIZATION, "response",
+ value))
+ {
+ strncpy(con->password, value, sizeof(con->password) - 1);
+ con->password[sizeof(con->password) - 1] = '\0';
+ }
+ }
+
+ LogMessage(L_DEBUG2, "decode_auth() %d username=\"%s\"",
+ con->http.fd, con->username);
+}
+
+
+/*
+ * 'get_file()' - Get a filename and state info.
+ */
+
+static char * /* O - Real filename */
+get_file(client_t *con, /* I - Client connection */
+ struct stat *filestats)/* O - File information */
+{
+ int status; /* Status of filesystem calls */
+ char *params; /* Pointer to parameters in URI */
+ static char filename[1024]; /* Filename buffer */
+
+
+ /*
+ * Need to add DocumentRoot global...
+ */
+
+ if (strncmp(con->uri, "/ppd/", 5) == 0)
+ snprintf(filename, sizeof(filename), "%s%s", ServerRoot, con->uri);
+ else if (strncmp(con->uri, "/admin/conf/", 12) == 0)
+ snprintf(filename, sizeof(filename), "%s%s", ServerRoot, con->uri + 11);
+ else if (con->language != NULL)
+ snprintf(filename, sizeof(filename), "%s/%s%s", DocumentRoot, con->language->language,
+ con->uri);
+ else
+ snprintf(filename, sizeof(filename), "%s%s", DocumentRoot, con->uri);
+
+ if ((params = strchr(filename, '?')) != NULL)
+ *params = '\0';
+
+ /*
+ * Grab the status for this language; if there isn't a language-specific file
+ * then fallback to the default one...
+ */
+
+ if ((status = stat(filename, filestats)) != 0 && con->language != NULL)
+ {
+ /*
+ * Drop the language prefix and try the current directory...
+ */
+
+ if (strncmp(con->uri, "/ppd/", 5) != 0 &&
+ strncmp(con->uri, "/admin/conf/", 12) != 0)
+ {
+ snprintf(filename, sizeof(filename), "%s%s", DocumentRoot, con->uri);
+
+ status = stat(filename, filestats);
+ }
+ }
+
+ /*
+ * If we're found a directory, get the index.html file instead...
+ */
+
+ if (!status && S_ISDIR(filestats->st_mode))
+ {
+ if (filename[strlen(filename) - 1] == '/')
+ strncat(filename, "index.html", sizeof(filename));
+ else
+ strncat(filename, "/index.html", sizeof(filename));
+
+ filename[sizeof(filename) - 1] = '\0';
+
+ status = stat(filename, filestats);
+ }
+
+ LogMessage(L_DEBUG2, "get_file() %d filename=%s size=%d",
+ con->http.fd, filename, status ? -1 : filestats->st_size);
+
+ if (status)
+ return (NULL);
+ else
+ return (filename);
+}
+
+
+/*
+ * 'install_conf_file()' - Install a configuration file.
+ */
+
+static http_status_t /* O - Status */
+install_conf_file(client_t *con) /* I - Connection */
+{
+ FILE *in, /* Input file */
+ *out; /* Output file */
+ char buffer[1024]; /* Copy buffer */
+ int bytes; /* Number of bytes */
+ char conffile[1024], /* Configuration filename */
+ newfile[1024], /* New config filename */
+ oldfile[1024]; /* Old config filename */
+ struct stat confinfo; /* Config file info */
+
+
+ /*
+ * First construct the filenames...
+ */
+
+ snprintf(conffile, sizeof(conffile), "%s%s", ServerRoot, con->uri + 11);
+ snprintf(newfile, sizeof(newfile), "%s%s.N", ServerRoot, con->uri + 11);
+ snprintf(oldfile, sizeof(oldfile), "%s%s.O", ServerRoot, con->uri + 11);
+
+ LogMessage(L_INFO, "Installing config file \"%s\"...", conffile);
+
+ /*
+ * Get the owner, group, and permissions of the configuration file.
+ * If it doesn't exist, assign it to the User and Group in the
+ * cupsd.conf file with mode 0640 permissions.
+ */
+
+ if (stat(conffile, &confinfo))
+ {
+ confinfo.st_uid = User;
+ confinfo.st_gid = Group;
+ confinfo.st_mode = 0640;
+ }
+
+ /*
+ * Open the request file and new config file...
+ */
+
+ if ((in = fopen(con->filename, "rb")) == NULL)
+ {
+ LogMessage(L_ERROR, "Unable to open request file \"%s\" - %s",
+ con->filename, strerror(errno));
+ return (HTTP_SERVER_ERROR);
+ }
+
+ if ((out = fopen(newfile, "wb")) == NULL)
+ {
+ fclose(in);
+ LogMessage(L_ERROR, "Unable to open config file \"%s\" - %s",
+ newfile, strerror(errno));
+ return (HTTP_SERVER_ERROR);
+ }
+
+ fchmod(fileno(out), confinfo.st_mode);
+ fchown(fileno(out), confinfo.st_uid, confinfo.st_gid);
+
+ /*
+ * Copy from the request to the new config file...
+ */
+
+ while ((bytes = fread(buffer, 1, sizeof(buffer), in)) > 0)
+ if (fwrite(buffer, 1, bytes, out) < bytes)
+ {
+ LogMessage(L_ERROR, "Unable to copy to config file \"%s\" - %s",
+ newfile, strerror(errno));
+
+ fclose(in);
+ fclose(out);
+ unlink(newfile);
+
+ return (HTTP_SERVER_ERROR);
+ }
+
+ /*
+ * Close the files...
+ */
+
+ fclose(in);
+ if (fclose(out))
+ {
+ LogMessage(L_ERROR, "Error file closing config file \"%s\" - %s",
+ newfile, strerror(errno));
+
+ unlink(newfile);
+
+ return (HTTP_SERVER_ERROR);
+ }
+
+ /*
+ * Remove the request file...
+ */
+
+ unlink(con->filename);
+ con->filename[0] = '\0';
+
+ /*
+ * Unlink the old backup, rename the current config file to the backup
+ * filename, and rename the new config file to the config file name...
+ */
+
+ if (unlink(oldfile))
+ if (errno != ENOENT)
+ {
+ LogMessage(L_ERROR, "Unable to remove backup config file \"%s\" - %s",
+ oldfile, strerror(errno));
+
+ unlink(newfile);
+
+ return (HTTP_SERVER_ERROR);
+ }
+
+ if (rename(conffile, oldfile))
+ if (errno != ENOENT)
+ {
+ LogMessage(L_ERROR, "Unable to rename old config file \"%s\" - %s",
+ conffile, strerror(errno));
+
+ unlink(newfile);
+
+ return (HTTP_SERVER_ERROR);
+ }
+
+ if (rename(newfile, conffile))
+ {
+ LogMessage(L_ERROR, "Unable to rename new config file \"%s\" - %s",
+ newfile, strerror(errno));
+
+ rename(oldfile, conffile);
+ unlink(newfile);
+
+ return (HTTP_SERVER_ERROR);
+ }
+
+ /*
+ * If the cupsd.conf file was updated, set the NeedReload flag...
+ */
+
+ if (strcmp(con->uri, "/admin/conf/cupsd.conf") == 0)
+ NeedReload = TRUE;
+
+ /*
+ * Return that the file was created successfully...
+ */
+
+ return (HTTP_CREATED);
+}
+
+
+/*
+ * 'pipe_command()' - Pipe the output of a command to the remote client.
+ */
+
+static int /* O - Process ID */
+pipe_command(client_t *con, /* I - Client connection */
+ int infile, /* I - Standard input for command */
+ int *outfile, /* O - Standard output for command */
+ char *command, /* I - Command to run */
+ char *options) /* I - Options for command */
+{
+ int pid; /* Process ID */
+ char *commptr; /* Command string pointer */
+ int fd; /* Looping var */
+ int fds[2]; /* Pipe FDs */
+ int argc; /* Number of arguments */
+ int envc; /* Number of environment variables */
+ char argbuf[10240], /* Argument buffer */
+ *argv[100], /* Argument strings */
+ *envp[100]; /* Environment variables */
+ char lang[1024], /* LANG env variable */
+ content_length[1024], /* CONTENT_LENGTH env variable */
+ content_type[1024], /* CONTENT_TYPE env variable */
+ ipp_port[1024], /* Default listen port */
+ server_port[1024], /* Default server port */
+ server_name[1024], /* Default listen hostname */
+ remote_host[1024], /* REMOTE_HOST env variable */
+ remote_user[1024], /* REMOTE_USER env variable */
+ tmpdir[1024], /* TMPDIR environment variable */
+ ldpath[1024], /* LD_LIBRARY_PATH environment variable */
+ datadir[1024], /* CUPS_DATADIR environment variable */
+ root[1024], /* CUPS_SERVERROOT environment variable */
+ query_string[10240]; /* QUERY_STRING env variable */
+
+
+ /*
+ * Copy the command string...
+ */
+
+ strncpy(argbuf, options, sizeof(argbuf) - 1);
+ argbuf[sizeof(argbuf) - 1] = '\0';
+
+ /*
+ * Parse the string; arguments can be separated by + and are terminated
+ * by ?...
+ */
+
+ argv[0] = argbuf;
+
+ for (commptr = argbuf, argc = 1; *commptr != '\0' && argc < 99; commptr ++)
+ if (*commptr == ' ' || *commptr == '+')
+ {
+ *commptr++ = '\0';
+
+ while (*commptr == ' ')
+ commptr ++;
+
+ if (*commptr != '\0')
+ {
+ argv[argc] = commptr;
+ argc ++;
+ }
+
+ commptr --;
+ }
+ else if (*commptr == '%')
+ {
+ if (commptr[1] >= '0' && commptr[1] <= '9')
+ *commptr = (commptr[1] - '0') << 4;
+ else
+ *commptr = (tolower(commptr[1]) - 'a' + 10) << 4;
+
+ if (commptr[2] >= '0' && commptr[2] <= '9')
+ *commptr |= commptr[2] - '0';
+ else
+ *commptr |= tolower(commptr[2]) - 'a' + 10;
+
+ strcpy(commptr + 1, commptr + 3);
+ }
+ else if (*commptr == '?')
+ break;
+
+ argv[argc] = NULL;
+
+ if (argv[0][0] == '\0')
+ argv[0] = strrchr(command, '/') + 1;
+
+ /*
+ * Setup the environment variables as needed...
+ */
+
+ snprintf(lang, sizeof(lang), "LANG=%s",
+ con->language ? con->language->language : "C");
+ sprintf(ipp_port, "IPP_PORT=%d", ntohs(con->http.hostaddr.sin_port));
+ sprintf(server_port, "SERVER_PORT=%d", ntohs(con->http.hostaddr.sin_port));
+ snprintf(server_name, sizeof(server_name), "SERVER_NAME=%s", ServerName);
+ snprintf(remote_host, sizeof(remote_host), "REMOTE_HOST=%s", con->http.hostname);
+ snprintf(remote_user, sizeof(remote_user), "REMOTE_USER=%s", con->username);
+ snprintf(tmpdir, sizeof(tmpdir), "TMPDIR=%s", TempDir);
+ snprintf(datadir, sizeof(datadir), "CUPS_DATADIR=%s", DataDir);
+ snprintf(root, sizeof(root), "CUPS_SERVERROOT=%s", ServerRoot);
+
+ if (getenv("LD_LIBRARY_PATH") != NULL)
+ snprintf(ldpath, sizeof(ldpath), "LD_LIBRARY_PATH=%s", getenv("LD_LIBRARY_PATH"));
+ else
+ ldpath[0] = '\0';
+
+ envp[0] = "PATH=/bin:/usr/bin";
+ envp[1] = "SERVER_SOFTWARE=CUPS/1.1";
+ envp[2] = "GATEWAY_INTERFACE=CGI/1.1";
+ envp[3] = "SERVER_PROTOCOL=HTTP/1.1";
+ envp[4] = ipp_port;
+ envp[5] = server_name;
+ envp[6] = server_port;
+ envp[7] = remote_host;
+ envp[8] = remote_user;
+ envp[9] = lang;
+ envp[10] = TZ;
+ envp[11] = tmpdir;
+ envp[12] = datadir;
+ envp[13] = root;
+
+ envc = 14;
+
+ if (ldpath[0])
+ envp[envc ++] = ldpath;
+
+ if (con->operation == HTTP_GET)
+ {
+ envp[envc ++] = "REQUEST_METHOD=GET";
+
+ if (*commptr)
+ {
+ /*
+ * Add GET form variables after ?...
+ */
+
+ *commptr++ = '\0';
+
+ snprintf(query_string, sizeof(query_string), "QUERY_STRING=%s", commptr);
+ envp[envc ++] = query_string;
+ }
+ }
+ else
+ {
+ sprintf(content_length, "CONTENT_LENGTH=%d", con->bytes);
+ snprintf(content_type, sizeof(content_type), "CONTENT_TYPE=%s",
+ con->http.fields[HTTP_FIELD_CONTENT_TYPE]);
+
+ envp[envc ++] = "REQUEST_METHOD=POST";
+ envp[envc ++] = content_length;
+ envp[envc ++] = content_type;
+ }
+
+ /*
+ * Tell the CGI if we are using encryption...
+ */
+
+ if (con->http.encryption >= HTTP_ENCRYPT_REQUIRED)
+ envp[envc ++] = "HTTPS=ON";
+
+ envp[envc] = NULL;
+
+ /*
+ * Create a pipe for the output...
+ */
+
+ if (pipe(fds))
+ {
+ LogMessage(L_ERROR, "Unable to create pipes for CGI %s - %s",
+ argv[0], strerror(errno));
+ return (0);
+ }
+
+ /*
+ * Then execute the command...
+ */
+
+ if ((pid = fork()) == 0)
+ {
+ /*
+ * Child comes here... Close stdin if necessary and dup the pipe to stdout.
+ */
+
+ if (getuid() == 0)
+ {
+ /*
+ * Running as root, so change to a non-priviledged user...
+ */
+
+ if (setgid(Group))
+ exit(errno);
+
+ if (setuid(User))
+ exit(errno);
+ }
+
+ /*
+ * Reset group membership to just the main one we belong to.
+ */
+
+ setgroups(0, NULL);
+
+ /*
+ * Update stdin/stdout...
+ */
+
+ if (infile)
+ {
+ close(0);
+ if (dup(infile) < 0)
+ exit(errno);
+ }
+
+ close(1);
+ if (dup(fds[1]) < 0)
+ exit(errno);
+
+ /*
+ * Close extra file descriptors...
+ */
+
+ for (fd = 3; fd < MaxFDs; fd ++)
+ close(fd);
+
+ /*
+ * Change umask to restrict permissions on created files...
+ */
+
+ umask(077);
+
+ /*
+ * Execute the pipe program; if an error occurs, exit with status 1...
+ */
+
+ execve(command, argv, envp);
+ exit(errno);
+ return (0);
+ }
+ else if (pid < 0)
+ {
+ /*
+ * Error - can't fork!
+ */
+
+ LogMessage(L_ERROR, "Unable to fork for CGI %s - %s", argv[0],
+ strerror(errno));
+
+ close(fds[0]);
+ close(fds[1]);
+ return (0);
+ }
+ else
+ {
+ /*
+ * Fork successful - return the PID...
+ */
+
+ AddCert(pid, con->username);
+
+ LogMessage(L_DEBUG, "CGI %s started - PID = %d", command, pid);
+
+ *outfile = fds[0];
+ close(fds[1]);
+
+ return (pid);
+ }
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/client.h b/scheduler/client.h
new file mode 100644
index 000000000..2517605f8
--- /dev/null
+++ b/scheduler/client.h
@@ -0,0 +1,104 @@
+/*
+ * "$Id$"
+ *
+ * Client definitions for the Common UNIX Printing System (CUPS) scheduler.
+ *
+ * Copyright 1997-2002 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
+ */
+
+/*
+ * HTTP client structure...
+ */
+
+typedef struct
+{
+ http_t http; /* HTTP client connection */
+ ipp_t *request, /* IPP request information */
+ *response; /* IPP response information */
+ time_t start; /* Request start time */
+ http_state_t operation; /* Request operation */
+ int bytes; /* Bytes transferred for this request */
+ char username[33], /* Username from Authorization: line */
+ password[33], /* Password from Authorization: line */
+ uri[HTTP_MAX_URI], /* Localized URL/URI for GET/PUT */
+ filename[HTTP_MAX_URI], /* Filename of output file */
+ command[HTTP_MAX_URI], /* Command to run */
+ *options; /* Options for command */
+ int file; /* Input/output file */
+ int pipe_pid; /* Pipe process ID (or 0 if not a pipe) */
+ int got_fields, /* Non-zero if all fields seen */
+ field_col; /* Column within line */
+ cups_lang_t *language; /* Language to use */
+} client_t;
+
+#define HTTP(con) &((con)->http)
+
+
+/*
+ * HTTP listener structure...
+ */
+
+typedef struct
+{
+ int fd; /* File descriptor for this server */
+ struct sockaddr_in address; /* Bind address of socket */
+ http_encryption_t encryption; /* To encrypt or not to encrypt... */
+} listener_t;
+
+
+/*
+ * Globals...
+ */
+
+VAR int ListenBackLog VALUE(SOMAXCONN);
+VAR int NumListeners VALUE(0);
+ /* Number of listening sockets */
+VAR listener_t Listeners[MAX_LISTENERS];
+ /* Listening sockets */
+VAR int NumClients VALUE(0);
+ /* Number of HTTP clients */
+VAR client_t *Clients VALUE(NULL);
+ /* HTTP clients */
+VAR struct sockaddr_in ServerAddr; /* Server IP address */
+
+
+/*
+ * Prototypes...
+ */
+
+extern void AcceptClient(listener_t *lis);
+extern void CloseAllClients(void);
+extern void CloseClient(client_t *con);
+extern int EncryptClient(client_t *con);
+extern void PauseListening(void);
+extern void ProcessIPPRequest(client_t *con);
+extern int ReadClient(client_t *con);
+extern void ResumeListening(void);
+extern int SendCommand(client_t *con, char *command, char *options);
+extern int SendError(client_t *con, http_status_t code);
+extern int SendFile(client_t *con, http_status_t code, char *filename,
+ char *type, struct stat *filestats);
+extern int SendHeader(client_t *con, http_status_t code, char *type);
+extern void StartListening(void);
+extern void StopListening(void);
+extern int WriteClient(client_t *con);
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/conf.c b/scheduler/conf.c
new file mode 100644
index 000000000..c4a5480ef
--- /dev/null
+++ b/scheduler/conf.c
@@ -0,0 +1,1868 @@
+/*
+ * "$Id$"
+ *
+ * Configuration routines for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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:
+ *
+ * ReadConfiguration() - Read the cupsd.conf file.
+ * read_configuration() - Read a configuration file.
+ * read_location() - Read a <Location path> definition.
+ * get_address() - Get an address + port number from a line.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cupsd.h"
+#include <stdarg.h>
+#include <pwd.h>
+#include <grp.h>
+#include <sys/resource.h>
+
+#ifdef HAVE_VSYSLOG
+# include <syslog.h>
+#endif /* HAVE_VSYSLOG */
+
+
+/*
+ * Possibly missing network definitions...
+ */
+
+#ifndef INADDR_NONE
+# define INADDR_NONE 0xffffffff
+#endif /* !INADDR_NONE */
+
+
+/*
+ * Configuration variable structure...
+ */
+
+typedef struct
+{
+ char *name; /* Name of variable */
+ void *ptr; /* Pointer to variable */
+ int type, /* Type (int, string, address) */
+ size; /* Size of string */
+} var_t;
+
+#define VAR_INTEGER 0
+#define VAR_STRING 1
+#define VAR_BOOLEAN 2
+
+
+/*
+ * Local globals...
+ */
+
+static var_t variables[] =
+{
+ { "AccessLog", AccessLog, VAR_STRING, sizeof(AccessLog) },
+ { "AutoPurgeJobs", &JobAutoPurge, VAR_BOOLEAN, 0 },
+ { "BrowseInterval", &BrowseInterval, VAR_INTEGER, 0 },
+ { "BrowsePort", &BrowsePort, VAR_INTEGER, 0 },
+ { "BrowseShortNames", &BrowseShortNames, VAR_BOOLEAN, 0 },
+ { "BrowseTimeout", &BrowseTimeout, VAR_INTEGER, 0 },
+ { "Browsing", &Browsing, VAR_BOOLEAN, 0 },
+ { "Classification", Classification, VAR_STRING, sizeof(Classification) },
+ { "ClassifyOverride", &ClassifyOverride, VAR_BOOLEAN, 0 },
+ { "DataDir", DataDir, VAR_STRING, sizeof(DataDir) },
+ { "DefaultCharset", DefaultCharset, VAR_STRING, sizeof(DefaultCharset) },
+ { "DefaultLanguage", DefaultLanguage, VAR_STRING, sizeof(DefaultLanguage) },
+ { "DocumentRoot", DocumentRoot, VAR_STRING, sizeof(DocumentRoot) },
+ { "ErrorLog", ErrorLog, VAR_STRING, sizeof(ErrorLog) },
+ { "FilterLimit", &FilterLimit, VAR_INTEGER, 0 },
+ { "FontPath", FontPath, VAR_STRING, sizeof(FontPath) },
+ { "HideImplicitMembers", &HideImplicitMembers, VAR_BOOLEAN, 0 },
+ { "ImplicitClasses", &ImplicitClasses, VAR_BOOLEAN, 0 },
+ { "ImplicitAnyClasses", &ImplicitAnyClasses, VAR_BOOLEAN, 0 },
+ { "KeepAliveTimeout", &KeepAliveTimeout, VAR_INTEGER, 0 },
+ { "KeepAlive", &KeepAlive, VAR_BOOLEAN, 0 },
+ { "LimitRequestBody", &MaxRequestSize, VAR_INTEGER, 0 },
+ { "ListenBackLog", &ListenBackLog, VAR_INTEGER, 0 },
+ { "MaxClients", &MaxClients, VAR_INTEGER, 0 },
+ { "MaxJobs", &MaxJobs, VAR_INTEGER, 0 },
+ { "MaxJobsPerPrinter",&MaxJobsPerPrinter, VAR_INTEGER, 0 },
+ { "MaxJobsPerUser", &MaxJobsPerUser, VAR_INTEGER, 0 },
+ { "MaxLogSize", &MaxLogSize, VAR_INTEGER, 0 },
+ { "MaxRequestSize", &MaxRequestSize, VAR_INTEGER, 0 },
+ { "PageLog", PageLog, VAR_STRING, sizeof(PageLog) },
+ { "PreserveJobFiles", &JobFiles, VAR_BOOLEAN, 0 },
+ { "PreserveJobHistory", &JobHistory, VAR_BOOLEAN, 0 },
+ { "Printcap", Printcap, VAR_STRING, sizeof(Printcap) },
+ { "PrintcapGUI", PrintcapGUI, VAR_STRING, sizeof(PrintcapGUI) },
+ { "RemoteRoot", RemoteRoot, VAR_STRING, sizeof(RemoteRoot) },
+ { "RequestRoot", RequestRoot, VAR_STRING, sizeof(RequestRoot) },
+ { "RIPCache", RIPCache, VAR_STRING, sizeof(RIPCache) },
+ { "RunAsUser", &RunAsUser, VAR_BOOLEAN, 0 },
+ { "ServerAdmin", ServerAdmin, VAR_STRING, sizeof(ServerAdmin) },
+ { "ServerBin", ServerBin, VAR_STRING, sizeof(ServerBin) },
+#ifdef HAVE_LIBSSL
+ { "ServerCertificate",ServerCertificate, VAR_STRING, sizeof(ServerCertificate) },
+ { "ServerKey", ServerKey, VAR_STRING, sizeof(ServerKey) },
+#endif /* HAVE_LIBSSL */
+ { "ServerName", ServerName, VAR_STRING, sizeof(ServerName) },
+ { "ServerRoot", ServerRoot, VAR_STRING, sizeof(ServerRoot) },
+ { "TempDir", TempDir, VAR_STRING, sizeof(TempDir) },
+ { "Timeout", &Timeout, VAR_INTEGER, 0 }
+};
+#define NUM_VARS (sizeof(variables) / sizeof(variables[0]))
+
+
+/*
+ * Local functions...
+ */
+
+static int read_configuration(FILE *fp);
+static int read_location(FILE *fp, char *name, int linenum);
+static int get_address(char *value, unsigned defaddress, int defport,
+ struct sockaddr_in *address);
+
+
+/*
+ * 'ReadConfiguration()' - Read the cupsd.conf file.
+ */
+
+int /* O - 1 if file read successfully, 0 otherwise */
+ReadConfiguration(void)
+{
+ int i; /* Looping var */
+ FILE *fp; /* Configuration file */
+ int status; /* Return status */
+ char directory[1024],/* Configuration directory */
+ *slash; /* Directory separator */
+ char type[MIME_MAX_SUPER + MIME_MAX_TYPE];
+ /* MIME type name */
+ struct rlimit limit; /* Runtime limit */
+ char *language; /* Language string */
+ struct passwd *user; /* Default user */
+ struct group *group; /* Default group */
+
+
+ /*
+ * Shutdown the server...
+ */
+
+ StopServer();
+
+ /*
+ * Free all memory...
+ */
+
+ DeleteAllClasses();
+ DeleteAllLocations();
+ DeleteAllPrinters();
+
+ DefaultPrinter = NULL;
+
+ if (Devices)
+ {
+ ippDelete(Devices);
+ Devices = NULL;
+ }
+
+ if (PPDs)
+ {
+ ippDelete(PPDs);
+ PPDs = NULL;
+ }
+
+ if (MimeDatabase != NULL)
+ mimeDelete(MimeDatabase);
+
+ if (NumMimeTypes)
+ {
+ for (i = 0; i < NumMimeTypes; i ++)
+ free((void *)MimeTypes[i]);
+
+ free(MimeTypes);
+ }
+
+ for (i = 0; i < NumRelays; i ++)
+ if (Relays[i].from.type == AUTH_NAME)
+ free(Relays[i].from.mask.name.name);
+
+ NumRelays = 0;
+
+ /*
+ * Reset the current configuration to the defaults...
+ */
+
+ NeedReload = FALSE;
+
+ /*
+ * String options...
+ */
+
+ gethostname(ServerName, sizeof(ServerName));
+ snprintf(ServerAdmin, sizeof(ServerAdmin), "root@%s", ServerName);
+ strcpy(ServerBin, CUPS_SERVERBIN);
+ strcpy(RequestRoot, CUPS_REQUESTS);
+ strcpy(DocumentRoot, CUPS_DOCROOT);
+ strcpy(DataDir, CUPS_DATADIR);
+ strcpy(AccessLog, CUPS_LOGDIR "/access_log");
+ strcpy(ErrorLog, CUPS_LOGDIR "/error_log");
+ strcpy(PageLog, CUPS_LOGDIR "/page_log");
+ strcpy(Printcap, "/etc/printcap");
+ strcpy(PrintcapGUI, "/usr/bin/glpoptions");
+ strcpy(FontPath, CUPS_FONTPATH);
+ strcpy(RemoteRoot, "remroot");
+
+ strcpy(ServerRoot, ConfigurationFile);
+ if ((slash = strrchr(ServerRoot, '/')) != NULL)
+ *slash = '\0';
+
+ Classification[0] = '\0';
+ ClassifyOverride = 0;
+
+#ifdef HAVE_LIBSSL
+ strcpy(ServerCertificate, "ssl/server.crt");
+ strcpy(ServerKey, "ssl/server.key");
+#endif /* HAVE_LIBSSL */
+
+ if ((language = DEFAULT_LANGUAGE) == NULL)
+ language = "en";
+ else if (strcmp(language, "C") == 0 || strcmp(language, "POSIX") == 0)
+ language = "en";
+
+ strncpy(DefaultLanguage, language, sizeof(DefaultLanguage) - 1);
+ DefaultLanguage[sizeof(DefaultLanguage) - 1] = '\0';
+
+ strcpy(DefaultCharset, DEFAULT_CHARSET);
+
+ strcpy(RIPCache, "8m");
+
+ if (getenv("TMPDIR") == NULL)
+ strcpy(TempDir, CUPS_REQUESTS "/tmp");
+ else
+ {
+ strncpy(TempDir, getenv("TMPDIR"), sizeof(TempDir) - 1);
+ TempDir[sizeof(TempDir) - 1] = '\0';
+ }
+
+ /*
+ * Find the default system group: "sys", "system", or "root"...
+ */
+
+ group = getgrnam(CUPS_DEFAULT_GROUP);
+ endgrent();
+
+ NumSystemGroups = 0;
+
+ if (group != NULL)
+ {
+ strcpy(SystemGroups[0], CUPS_DEFAULT_GROUP);
+ Group = group->gr_gid;
+ }
+ else
+ {
+ group = getgrgid(0);
+ endgrent();
+
+ if (group != NULL)
+ {
+ strcpy(SystemGroups[0], group->gr_name);
+ Group = 0;
+ }
+ else
+ {
+ strcpy(SystemGroups[0], "unknown");
+ Group = 0;
+ }
+ }
+
+ /*
+ * Find the default user...
+ */
+
+ if ((user = getpwnam(CUPS_DEFAULT_USER)) == NULL)
+ User = 1; /* Force to a non-priviledged account */
+ else
+ User = user->pw_uid;
+
+ endpwent();
+
+ /*
+ * Numeric options...
+ */
+
+ FilterLevel = 0;
+ FilterLimit = 0;
+ HostNameLookups = FALSE;
+ ImplicitClasses = TRUE;
+ ImplicitAnyClasses = FALSE;
+ HideImplicitMembers = TRUE;
+ KeepAlive = TRUE;
+ KeepAliveTimeout = DEFAULT_KEEPALIVE;
+ ListenBackLog = SOMAXCONN;
+ LogLevel = L_ERROR;
+ MaxClients = 100;
+ MaxLogSize = 1024 * 1024;
+ MaxRequestSize = 0;
+ RunAsUser = FALSE;
+ Timeout = DEFAULT_TIMEOUT;
+
+ BrowseInterval = DEFAULT_INTERVAL;
+ BrowsePort = ippPort();
+ BrowseProtocols = BROWSE_CUPS;
+ BrowseShortNames = TRUE;
+ BrowseTimeout = DEFAULT_TIMEOUT;
+ Browsing = TRUE;
+ NumBrowsers = 0;
+ NumPolled = 0;
+
+ NumListeners = 0;
+
+ JobHistory = DEFAULT_HISTORY;
+ JobFiles = DEFAULT_FILES;
+ JobAutoPurge = 0;
+ MaxJobs = 500;
+ MaxJobsPerUser = 0;
+ MaxJobsPerPrinter = 0;
+
+ /*
+ * Read the configuration file...
+ */
+
+ if ((fp = fopen(ConfigurationFile, "r")) == NULL)
+ return (0);
+
+ status = read_configuration(fp);
+
+ fclose(fp);
+
+ if (!status)
+ return (0);
+
+ /*
+ * Use the default system group if none was supplied in cupsd.conf...
+ */
+
+ if (NumSystemGroups == 0)
+ NumSystemGroups ++;
+
+ /*
+ * Get the access control list for browsing...
+ */
+
+ BrowseACL = FindLocation("CUPS_INTERNAL_BROWSE_ACL");
+
+ /*
+ * Open the system log for cupsd if necessary...
+ */
+
+#ifdef HAVE_VSYSLOG
+ if (strcmp(AccessLog, "syslog") == 0 ||
+ strcmp(ErrorLog, "syslog") == 0 ||
+ strcmp(PageLog, "syslog") == 0)
+ openlog("cupsd", LOG_PID | LOG_NOWAIT | LOG_NDELAY, LOG_LPR);
+#endif /* HAVE_VSYSLOG */
+
+ /*
+ * Log the configuration file that was used...
+ */
+
+ LogMessage(L_DEBUG, "ReadConfiguration() ConfigurationFile=\"%s\"",
+ ConfigurationFile);
+
+ /*
+ * Update all relative filenames to include the full path from ServerRoot...
+ */
+
+ if (DocumentRoot[0] != '/')
+ {
+ snprintf(directory, sizeof(directory), "%s/%s", ServerRoot, DocumentRoot);
+ strncpy(DocumentRoot, directory, sizeof(DocumentRoot) - 1);
+ DocumentRoot[sizeof(DocumentRoot) - 1] = '\0';
+ }
+
+ if (RequestRoot[0] != '/')
+ {
+ snprintf(directory, sizeof(directory), "%s/%s", ServerRoot, RequestRoot);
+ strncpy(RequestRoot, directory, sizeof(RequestRoot) - 1);
+ RequestRoot[sizeof(RequestRoot) - 1] = '\0';
+ }
+
+ if (ServerBin[0] != '/')
+ {
+ snprintf(directory, sizeof(directory), "%s/%s", ServerRoot, ServerBin);
+ strncpy(ServerBin, directory, sizeof(ServerBin) - 1);
+ ServerBin[sizeof(ServerBin) - 1] = '\0';
+ }
+
+#ifdef HAVE_LIBSSL
+ if (ServerCertificate[0] != '/')
+ {
+ snprintf(directory, sizeof(directory), "%s/%s", ServerRoot, ServerCertificate);
+ strncpy(ServerCertificate, directory, sizeof(ServerCertificate) - 1);
+ ServerCertificate[sizeof(ServerCertificate) - 1] = '\0';
+ }
+
+ chown(ServerCertificate, User, Group);
+ chmod(ServerCertificate, 0600);
+
+ if (ServerKey[0] != '/')
+ {
+ snprintf(directory, sizeof(directory), "%s/%s", ServerRoot, ServerKey);
+ strncpy(ServerKey, directory, sizeof(ServerKey) - 1);
+ ServerKey[sizeof(ServerKey) - 1] = '\0';
+ }
+
+ chown(ServerKey, User, Group);
+ chmod(ServerKey, 0600);
+#endif /* HAVE_LIBSSL */
+
+ /*
+ * Make sure that ServerRoot and the config files are owned and
+ * writable by the user and group in the cupsd.conf file...
+ */
+
+ chown(ServerRoot, User, Group);
+ chmod(ServerRoot, 0755);
+
+ snprintf(directory, sizeof(directory), "%s/certs", ServerRoot);
+ chown(directory, User, Group);
+ chmod(directory, 0711);
+
+ snprintf(directory, sizeof(directory), "%s/ppd", ServerRoot);
+ chown(directory, User, Group);
+ chmod(directory, 0755);
+
+ snprintf(directory, sizeof(directory), "%s/ssl", ServerRoot);
+ chown(directory, User, Group);
+ chmod(directory, 0700);
+
+ snprintf(directory, sizeof(directory), "%s/cupsd.conf", ServerRoot);
+ chown(directory, User, Group);
+ chmod(directory, 0600);
+
+ snprintf(directory, sizeof(directory), "%s/classes.conf", ServerRoot);
+ chown(directory, User, Group);
+ chmod(directory, 0600);
+
+ snprintf(directory, sizeof(directory), "%s/printers.conf", ServerRoot);
+ chown(directory, User, Group);
+ chmod(directory, 0600);
+
+ snprintf(directory, sizeof(directory), "%s/passwd.md5", ServerRoot);
+ chown(directory, User, Group);
+ chmod(directory, 0600);
+
+ /*
+ * Make sure the request and temporary directories have the right
+ * permissions...
+ */
+
+ chown(RequestRoot, User, Group);
+ chmod(RequestRoot, 0700);
+
+ if (strncmp(TempDir, RequestRoot, strlen(RequestRoot)) == 0)
+ {
+ /*
+ * Only update ownership and permissions if the CUPS temp directory
+ * is under the spool directory...
+ */
+
+ chown(TempDir, User, Group);
+ chmod(TempDir, 01700);
+ }
+
+ /*
+ * Check the MaxClients setting, and then allocate memory for it...
+ */
+
+ getrlimit(RLIMIT_NOFILE, &limit);
+
+ if (MaxClients > (limit.rlim_max / 3) || MaxClients <= 0)
+ MaxClients = limit.rlim_max / 3;
+
+ if ((Clients = calloc(sizeof(client_t), MaxClients)) == NULL)
+ {
+ LogMessage(L_ERROR, "ReadConfiguration: Unable to allocate memory for %d clients: %s",
+ MaxClients, strerror(errno));
+ exit(1);
+ }
+ else
+ LogMessage(L_INFO, "Configured for up to %d clients.", MaxClients);
+
+ if (strcasecmp(Classification, "none") == 0)
+ Classification[0] = '\0';
+
+ if (Classification[0])
+ LogMessage(L_INFO, "Security set to \"%s\"", Classification);
+
+ /*
+ * Read the MIME type and conversion database...
+ */
+
+ MimeDatabase = mimeNew();
+ mimeMerge(MimeDatabase, ServerRoot);
+
+ /*
+ * Create a list of MIME types for the document-format-supported
+ * attribute...
+ */
+
+ NumMimeTypes = MimeDatabase->num_types;
+ if (!mimeType(MimeDatabase, "application", "octet-stream"))
+ NumMimeTypes ++;
+
+ MimeTypes = calloc(NumMimeTypes, sizeof(const char *));
+
+ for (i = 0; i < MimeDatabase->num_types; i ++)
+ {
+ snprintf(type, sizeof(type), "%s/%s", MimeDatabase->types[i]->super,
+ MimeDatabase->types[i]->type);
+
+ MimeTypes[i] = strdup(type);
+ }
+
+ if (i < NumMimeTypes)
+ MimeTypes[i] = strdup("application/octet-stream");
+
+ /*
+ * Load banners...
+ */
+
+ snprintf(directory, sizeof(directory), "%s/banners", DataDir);
+ LoadBanners(directory);
+
+ /*
+ * Load printers and classes...
+ */
+
+ LoadAllPrinters();
+ LoadAllClasses();
+
+ /*
+ * Load devices and PPDs...
+ */
+
+ snprintf(directory, sizeof(directory), "%s/model", DataDir);
+ LoadPPDs(directory);
+
+ snprintf(directory, sizeof(directory), "%s/backend", ServerBin);
+ LoadDevices(directory);
+
+ /*
+ * Startup the server...
+ */
+
+ StartServer();
+
+ /*
+ * Check for queued jobs...
+ */
+
+ CheckJobs();
+
+ return (1);
+}
+
+
+/*
+ * 'read_configuration()' - Read a configuration file.
+ */
+
+static int /* O - 1 on success, 0 on failure */
+read_configuration(FILE *fp) /* I - File to read from */
+{
+ int i; /* Looping var */
+ int linenum; /* Current line number */
+ int len; /* Length of line */
+ char line[HTTP_MAX_BUFFER], /* Line from file */
+ name[256], /* Parameter name */
+ *nameptr, /* Pointer into name */
+ *value; /* Pointer to value */
+ int valuelen; /* Length of value */
+ var_t *var; /* Current variable */
+ unsigned address, /* Address value */
+ netmask; /* Netmask value */
+ int ip[4], /* IP address components */
+ ipcount, /* Number of components provided */
+ mask[4]; /* IP netmask components */
+ dirsvc_relay_t *relay; /* Relay data */
+ dirsvc_poll_t *poll; /* Polling data */
+ struct sockaddr_in polladdr; /* Polling address */
+ location_t *location; /* Browse location */
+ FILE *incfile; /* Include file */
+ char incname[1024]; /* Include filename */
+ static unsigned netmasks[4] = /* Standard netmasks... */
+ {
+ 0xff000000,
+ 0xffff0000,
+ 0xffffff00,
+ 0xffffffff
+ };
+
+
+ /*
+ * Loop through each line in the file...
+ */
+
+ linenum = 0;
+
+ while (fgets(line, sizeof(line), fp) != NULL)
+ {
+ linenum ++;
+
+ /*
+ * Skip comment lines...
+ */
+
+ if (line[0] == '#')
+ continue;
+
+ /*
+ * Strip trailing whitespace, if any...
+ */
+
+ len = strlen(line);
+
+ while (len > 0 && isspace(line[len - 1]))
+ {
+ len --;
+ line[len] = '\0';
+ }
+
+ /*
+ * Extract the name from the beginning of the line...
+ */
+
+ for (value = line; isspace(*value); value ++);
+
+ for (nameptr = name; *value != '\0' && !isspace(*value) &&
+ nameptr < (name + sizeof(name) - 1);)
+ *nameptr++ = *value++;
+ *nameptr = '\0';
+
+ while (isspace(*value))
+ value ++;
+
+ if (name[0] == '\0')
+ continue;
+
+ /*
+ * Decode the directive...
+ */
+
+ if (strcasecmp(name, "Include") == 0)
+ {
+ /*
+ * Include filename
+ */
+
+ if (value[0] == '/')
+ {
+ strncpy(incname, value, sizeof(incname) - 1);
+ incname[sizeof(incname) - 1] = '\0';
+ }
+ else
+ snprintf(incname, sizeof(incname), "%s/%s", ServerRoot, value);
+
+ if ((incfile = fopen(incname, "rb")) == NULL)
+ LogMessage(L_ERROR, "Unable to include config file \"%s\" - %s",
+ incname, strerror(errno));
+ else
+ {
+ read_configuration(incfile);
+ fclose(incfile);
+ }
+ }
+ else if (strcasecmp(name, "<Location") == 0)
+ {
+ /*
+ * <Location path>
+ */
+
+ if (line[len - 1] == '>')
+ {
+ line[len - 1] = '\0';
+
+ linenum = read_location(fp, value, linenum);
+ if (linenum == 0)
+ return (0);
+ }
+ else
+ {
+ LogMessage(L_ERROR, "ReadConfiguration() Syntax error on line %d.",
+ linenum);
+ return (0);
+ }
+ }
+ else if (strcasecmp(name, "Port") == 0 ||
+ strcasecmp(name, "Listen") == 0)
+ {
+ /*
+ * Add a listening address to the list...
+ */
+
+ if (NumListeners < MAX_LISTENERS)
+ {
+ if (get_address(value, INADDR_ANY, IPP_PORT,
+ &(Listeners[NumListeners].address)))
+ {
+ LogMessage(L_INFO, "Listening to %x:%d",
+ ntohl(Listeners[NumListeners].address.sin_addr.s_addr),
+ ntohs(Listeners[NumListeners].address.sin_port));
+ NumListeners ++;
+ }
+ else
+ LogMessage(L_ERROR, "Bad %s address %s at line %d.", name,
+ value, linenum);
+ }
+ else
+ LogMessage(L_WARN, "Too many %s directives at line %d.", name,
+ linenum);
+ }
+#ifdef HAVE_LIBSSL
+ else if (strcasecmp(name, "SSLPort") == 0 ||
+ strcasecmp(name, "SSLListen") == 0)
+ {
+ /*
+ * Add a listening address to the list...
+ */
+
+ if (NumListeners < MAX_LISTENERS)
+ {
+ if (get_address(value, INADDR_ANY, IPP_PORT,
+ &(Listeners[NumListeners].address)))
+ {
+ LogMessage(L_INFO, "Listening to %x:%d (SSL)",
+ ntohl(Listeners[NumListeners].address.sin_addr.s_addr),
+ ntohs(Listeners[NumListeners].address.sin_port));
+ Listeners[NumListeners].encryption = HTTP_ENCRYPT_ALWAYS;
+ NumListeners ++;
+ }
+ else
+ LogMessage(L_ERROR, "Bad %s address %s at line %d.", name,
+ value, linenum);
+ }
+ else
+ LogMessage(L_WARN, "Too many %s directives at line %d.", name,
+ linenum);
+ }
+#endif /* HAVE_LIBSSL */
+ else if (strcasecmp(name, "BrowseAddress") == 0)
+ {
+ /*
+ * Add a browse address to the list...
+ */
+
+ if (NumBrowsers < MAX_BROWSERS)
+ {
+ if (get_address(value, INADDR_NONE, BrowsePort, Browsers + NumBrowsers))
+ {
+ LogMessage(L_INFO, "Sending browsing info to %x:%d",
+ ntohl(Browsers[NumBrowsers].sin_addr.s_addr),
+ ntohs(Browsers[NumBrowsers].sin_port));
+ NumBrowsers ++;
+ }
+ else
+ LogMessage(L_ERROR, "Bad BrowseAddress %s at line %d.", value,
+ linenum);
+ }
+ else
+ LogMessage(L_WARN, "Too many BrowseAddress directives at line %d.",
+ linenum);
+ }
+ else if (strcasecmp(name, "BrowseOrder") == 0)
+ {
+ /*
+ * "BrowseOrder Deny,Allow" or "BrowseOrder Allow,Deny"...
+ */
+
+ if ((location = FindLocation("CUPS_INTERNAL_BROWSE_ACL")) == NULL)
+ location = AddLocation("CUPS_INTERNAL_BROWSE_ACL");
+
+ if (location == NULL)
+ LogMessage(L_ERROR, "Unable to initialize browse access control list!");
+ else if (strncasecmp(value, "deny", 4) == 0)
+ location->order_type = AUTH_ALLOW;
+ else if (strncasecmp(value, "allow", 5) == 0)
+ location->order_type = AUTH_DENY;
+ else
+ LogMessage(L_ERROR, "Unknown BrowseOrder value %s on line %d.",
+ value, linenum);
+ }
+ else if (strcasecmp(name, "BrowseProtocols") == 0)
+ {
+ /*
+ * "BrowseProtocol name [... name]"
+ */
+
+ BrowseProtocols = 0;
+
+ for (; *value;)
+ {
+ for (valuelen = 0; value[valuelen]; valuelen ++)
+ if (isspace(value[valuelen]) || value[valuelen] == ',')
+ break;
+
+ if (value[valuelen])
+ {
+ value[valuelen] = '\0';
+ valuelen ++;
+ }
+
+ if (strcasecmp(value, "cups") == 0)
+ BrowseProtocols |= BROWSE_CUPS;
+ else if (strcasecmp(value, "slp") == 0)
+ BrowseProtocols |= BROWSE_SLP;
+ else if (strcasecmp(value, "ldap") == 0)
+ BrowseProtocols |= BROWSE_LDAP;
+ else if (strcasecmp(value, "all") == 0)
+ BrowseProtocols |= BROWSE_ALL;
+ else
+ {
+ LogMessage(L_ERROR, "Unknown browse protocol \"%s\" on line %d.",
+ value, linenum);
+ break;
+ }
+
+ for (value += valuelen; *value; value ++)
+ if (!isspace(*value) || *value != ',')
+ break;
+ }
+ }
+ else if (strcasecmp(name, "BrowseAllow") == 0 ||
+ strcasecmp(name, "BrowseDeny") == 0)
+ {
+ /*
+ * BrowseAllow [From] host/ip...
+ * BrowseDeny [From] host/ip...
+ */
+
+ if ((location = FindLocation("CUPS_INTERNAL_BROWSE_ACL")) == NULL)
+ location = AddLocation("CUPS_INTERNAL_BROWSE_ACL");
+
+ if (location == NULL)
+ LogMessage(L_ERROR, "Unable to initialize browse access control list!");
+ else
+ {
+ if (strncasecmp(value, "from ", 5) == 0)
+ {
+ /*
+ * Strip leading "from"...
+ */
+
+ value += 5;
+
+ while (isspace(*value))
+ value ++;
+ }
+
+ /*
+ * Figure out what form the allow/deny address takes:
+ *
+ * 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
+ */
+
+ if (strcasecmp(value, "all") == 0)
+ {
+ /*
+ * All hosts...
+ */
+
+ if (strcasecmp(name, "BrowseAllow") == 0)
+ AllowIP(location, 0, 0);
+ else
+ DenyIP(location, 0, 0);
+ }
+ else if (strcasecmp(value, "none") == 0)
+ {
+ /*
+ * No hosts...
+ */
+
+ if (strcasecmp(name, "BrowseAllow") == 0)
+ AllowIP(location, ~0, 0);
+ else
+ DenyIP(location, ~0, 0);
+ }
+ else if (value[0] == '*' || value[0] == '.' || !isdigit(value[0]))
+ {
+ /*
+ * Host or domain name...
+ */
+
+ if (value[0] == '*')
+ value ++;
+
+ if (strcasecmp(name, "BrowseAllow") == 0)
+ AllowHost(location, value);
+ else
+ DenyHost(location, value);
+ }
+ else
+ {
+ /*
+ * One of many IP address forms...
+ */
+
+ memset(ip, 0, sizeof(ip));
+ ipcount = sscanf(value, "%d.%d.%d.%d", ip + 0, ip + 1, ip + 2, ip + 3);
+ address = (((((ip[0] << 8) | ip[1]) << 8) | ip[2]) << 8) | ip[3];
+
+ if ((value = strchr(value, '/')) != NULL)
+ {
+ value ++;
+ memset(mask, 0, sizeof(mask));
+ switch (sscanf(value, "%d.%d.%d.%d", mask + 0, mask + 1,
+ mask + 2, mask + 3))
+ {
+ case 1 :
+ netmask = (0xffffffff << (32 - mask[0])) & 0xffffffff;
+ break;
+ case 4 :
+ netmask = (((((mask[0] << 8) | mask[1]) << 8) |
+ mask[2]) << 8) | mask[3];
+ break;
+ default :
+ LogMessage(L_ERROR, "Bad netmask value %s on line %d.",
+ value, linenum);
+ netmask = 0xffffffff;
+ break;
+ }
+ }
+ else
+ netmask = netmasks[ipcount - 1];
+
+ if (strcasecmp(name, "BrowseAllow") == 0)
+ AllowIP(location, address, netmask);
+ else
+ DenyIP(location, address, netmask);
+ }
+ }
+ }
+ else if (strcasecmp(name, "BrowseRelay") == 0)
+ {
+ /*
+ * BrowseRelay [from] source [to] destination
+ */
+
+ if (NumRelays >= MAX_BROWSERS)
+ {
+ LogMessage(L_WARN, "Too many BrowseRelay directives at line %d.",
+ linenum);
+ continue;
+ }
+
+ relay = Relays + NumRelays;
+
+ memset(relay, 0, sizeof(dirsvc_relay_t));
+
+ if (strncasecmp(value, "from ", 5) == 0)
+ {
+ /*
+ * Strip leading "from"...
+ */
+
+ value += 5;
+
+ while (isspace(*value))
+ value ++;
+ }
+
+ /*
+ * Figure out what form the from address takes:
+ *
+ * *.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
+ */
+
+ if (value[0] == '*' || value[0] == '.' || !isdigit(value[0]))
+ {
+ /*
+ * Host or domain name...
+ */
+
+ if (value[0] == '*')
+ value ++;
+
+ relay->from.type = AUTH_NAME;
+ relay->from.mask.name.name = strdup(value);
+ relay->from.mask.name.length = strlen(value);
+ }
+ else
+ {
+ /*
+ * One of many IP address forms...
+ */
+
+ memset(ip, 0, sizeof(ip));
+ ipcount = sscanf(value, "%d.%d.%d.%d", ip + 0, ip + 1, ip + 2, ip + 3);
+ address = (((((ip[0] << 8) | ip[1]) << 8) | ip[2]) << 8) | ip[3];
+
+ for (; *value; value ++)
+ if (*value == '/' || isspace(*value))
+ break;
+
+ if (*value == '/')
+ {
+ value ++;
+ memset(mask, 0, sizeof(mask));
+ switch (sscanf(value, "%d.%d.%d.%d", mask + 0, mask + 1,
+ mask + 2, mask + 3))
+ {
+ case 1 :
+ netmask = (0xffffffff << (32 - mask[0])) & 0xffffffff;
+ break;
+ case 4 :
+ netmask = (((((mask[0] << 8) | mask[1]) << 8) |
+ mask[2]) << 8) | mask[3];
+ break;
+ default :
+ LogMessage(L_ERROR, "Bad netmask value %s on line %d.",
+ value, linenum);
+ netmask = 0xffffffff;
+ break;
+ }
+ }
+ else
+ netmask = netmasks[ipcount - 1];
+
+ relay->from.type = AUTH_IP;
+ relay->from.mask.ip.address = address;
+ relay->from.mask.ip.netmask = netmask;
+ }
+
+ /*
+ * Skip value and trailing whitespace...
+ */
+
+ for (; *value; value ++)
+ if (isspace(*value))
+ break;
+
+ while (isspace(*value))
+ value ++;
+
+ if (strncasecmp(value, "to ", 3) == 0)
+ {
+ /*
+ * Strip leading "to"...
+ */
+
+ value += 3;
+
+ while (isspace(*value))
+ value ++;
+ }
+
+ /*
+ * Get "to" address and port...
+ */
+
+ if (get_address(value, INADDR_BROADCAST, BrowsePort, &(relay->to)))
+ {
+ if (relay->from.type == AUTH_NAME)
+ LogMessage(L_INFO, "Relaying from %s to %x:%d",
+ ntohl(relay->to.sin_addr.s_addr),
+ ntohs(relay->to.sin_port));
+ else
+ LogMessage(L_INFO, "Relaying from %x/%x to %x:%d",
+ relay->from.mask.ip.address, relay->from.mask.ip.netmask,
+ ntohl(relay->to.sin_addr.s_addr),
+ ntohs(relay->to.sin_port));
+
+ NumRelays ++;
+ }
+ else
+ {
+ if (relay->from.type == AUTH_NAME)
+ free(relay->from.mask.name.name);
+
+ LogMessage(L_ERROR, "Bad relay address %s at line %d.", value, linenum);
+ }
+ }
+ else if (strcasecmp(name, "BrowsePoll") == 0)
+ {
+ /*
+ * BrowsePoll address[:port]
+ */
+
+ if (NumPolled >= MAX_BROWSERS)
+ {
+ LogMessage(L_WARN, "Too many BrowsePoll directives at line %d.",
+ linenum);
+ continue;
+ }
+
+ /*
+ * Get poll address and port...
+ */
+
+ if (get_address(value, INADDR_NONE, ippPort(), &polladdr))
+ {
+ LogMessage(L_INFO, "Polling %x:%d", ntohl(polladdr.sin_addr.s_addr),
+ ntohs(polladdr.sin_port));
+
+ poll = Polled + NumPolled;
+ NumPolled ++;
+ memset(poll, 0, sizeof(dirsvc_poll_t));
+
+ address = ntohl(polladdr.sin_addr.s_addr);
+
+ sprintf(poll->hostname, "%d.%d.%d.%d", address >> 24,
+ (address >> 16) & 255, (address >> 8) & 255, address & 255);
+ poll->port = ntohs(polladdr.sin_port);
+ }
+ else
+ LogMessage(L_ERROR, "Bad poll address %s at line %d.", value, linenum);
+ }
+ else if (strcasecmp(name, "User") == 0)
+ {
+ /*
+ * User ID to run as...
+ */
+
+ if (isdigit(value[0]))
+ User = atoi(value);
+ else
+ {
+ struct passwd *p; /* Password information */
+
+ endpwent();
+ p = getpwnam(value);
+
+ if (p != NULL)
+ User = p->pw_uid;
+ else
+ LogMessage(L_WARN, "ReadConfiguration() Unknown username \"%s\"",
+ value);
+ }
+ }
+ else if (strcasecmp(name, "Group") == 0)
+ {
+ /*
+ * Group ID to run as...
+ */
+
+ if (isdigit(value[0]))
+ Group = atoi(value);
+ else
+ {
+ struct group *g; /* Group information */
+
+ endgrent();
+ g = getgrnam(value);
+
+ if (g != NULL)
+ Group = g->gr_gid;
+ else
+ LogMessage(L_WARN, "ReadConfiguration() Unknown groupname \"%s\"",
+ value);
+ }
+ }
+ else if (strcasecmp(name, "SystemGroup") == 0)
+ {
+ /*
+ * System (admin) group(s)...
+ */
+
+ char *valueptr; /* Pointer into value */
+
+
+ for (i = 0; i < MAX_SYSTEM_GROUPS; i ++)
+ {
+ for (valueptr = value; *valueptr; valueptr ++)
+ if (isspace(*valueptr) || *valueptr == ',')
+ break;
+
+ if (*valueptr)
+ *valueptr++ = '\0';
+
+ strncpy(SystemGroups[i], value, sizeof(SystemGroups[0]));
+ SystemGroups[i][sizeof(SystemGroups[0]) - 1] = '\0';
+
+ while (*value == ',' || isspace(*value))
+ value ++;
+ }
+
+ if (i)
+ NumSystemGroups = i;
+ }
+ else if (strcasecmp(name, "HostNameLookups") == 0)
+ {
+ /*
+ * Do hostname lookups?
+ */
+
+ if (strcasecmp(value, "off") == 0)
+ HostNameLookups = 0;
+ else if (strcasecmp(value, "on") == 0)
+ HostNameLookups = 1;
+ else if (strcasecmp(value, "double") == 0)
+ HostNameLookups = 2;
+ else
+ LogMessage(L_WARN, "ReadConfiguration() Unknown HostNameLookups %s on line %d.",
+ value, linenum);
+ }
+ else if (strcasecmp(name, "LogLevel") == 0)
+ {
+ /*
+ * Amount of logging to do...
+ */
+
+ if (strcasecmp(value, "debug2") == 0)
+ LogLevel = L_DEBUG2;
+ else if (strcasecmp(value, "debug") == 0)
+ LogLevel = L_DEBUG;
+ else if (strcasecmp(value, "info") == 0)
+ LogLevel = L_INFO;
+ else if (strcasecmp(value, "notice") == 0)
+ LogLevel = L_NOTICE;
+ else if (strcasecmp(value, "warn") == 0)
+ LogLevel = L_WARN;
+ else if (strcasecmp(value, "error") == 0)
+ LogLevel = L_ERROR;
+ else if (strcasecmp(value, "crit") == 0)
+ LogLevel = L_CRIT;
+ else if (strcasecmp(value, "alert") == 0)
+ LogLevel = L_ALERT;
+ else if (strcasecmp(value, "emerg") == 0)
+ LogLevel = L_EMERG;
+ else if (strcasecmp(value, "none") == 0)
+ LogLevel = L_NONE;
+ else
+ LogMessage(L_WARN, "Unknown LogLevel %s on line %d.", value, linenum);
+ }
+ else if (strcasecmp(name, "PrintcapFormat") == 0)
+ {
+ /*
+ * Format of printcap file?
+ */
+
+ if (strcasecmp(value, "bsd") == 0)
+ PrintcapFormat = PRINTCAP_BSD;
+ else if (strcasecmp(value, "solaris") == 0)
+ PrintcapFormat = PRINTCAP_SOLARIS;
+ else
+ LogMessage(L_WARN, "ReadConfiguration() Unknown PrintcapFormat %s on line %d.",
+ value, linenum);
+ }
+ else
+ {
+ /*
+ * Find a simple variable in the list...
+ */
+
+ for (i = NUM_VARS, var = variables; i > 0; i --, var ++)
+ if (strcasecmp(name, var->name) == 0)
+ break;
+
+ if (i == 0)
+ {
+ /*
+ * Unknown directive! Output an error message and continue...
+ */
+
+ LogMessage(L_ERROR, "Unknown directive %s on line %d.", name,
+ linenum);
+ continue;
+ }
+
+ switch (var->type)
+ {
+ case VAR_INTEGER :
+ {
+ float n; /* Number */
+ char units[255]; /* Units */
+
+
+ switch (sscanf(value, "%f%254s", &n, units))
+ {
+ case 0 :
+ n = 0.0;
+ case 1 :
+ break;
+ case 2 :
+ if (tolower(units[0]) == 'g')
+ n *= 1024.0 * 1024.0 * 1024.0;
+ else if (tolower(units[0]) == 'm')
+ n *= 1024.0 * 1024.0;
+ else if (tolower(units[0]) == 'k')
+ n *= 1024.0;
+ else if (tolower(units[0]) == 't')
+ n *= 262144.0;
+ break;
+ }
+
+ *((int *)var->ptr) = (int)n;
+ }
+ break;
+
+ case VAR_BOOLEAN :
+ if (strcasecmp(value, "true") == 0 ||
+ strcasecmp(value, "on") == 0 ||
+ strcasecmp(value, "enabled") == 0 ||
+ strcasecmp(value, "yes") == 0 ||
+ atoi(value) != 0)
+ *((int *)var->ptr) = TRUE;
+ else if (strcasecmp(value, "false") == 0 ||
+ strcasecmp(value, "off") == 0 ||
+ strcasecmp(value, "disabled") == 0 ||
+ strcasecmp(value, "no") == 0 ||
+ strcasecmp(value, "0") == 0)
+ *((int *)var->ptr) = FALSE;
+ else
+ LogMessage(L_ERROR, "Unknown boolean value %s on line %d.",
+ value, linenum);
+ break;
+
+ case VAR_STRING :
+ strncpy((char *)var->ptr, value, var->size - 1);
+ value[var->size - 1] = '\0';
+ break;
+ }
+ }
+ }
+
+ return (1);
+}
+
+
+/*
+ * 'read_location()' - Read a <Location path> definition.
+ */
+
+static int /* O - New line number or 0 on error */
+read_location(FILE *fp, /* I - Configuration file */
+ char *location, /* I - Location name/path */
+ int linenum) /* I - Current line number */
+{
+ int i; /* Looping var */
+ location_t *loc, /* New location */
+ *parent; /* Parent location */
+ int len; /* Length of line */
+ char line[HTTP_MAX_BUFFER], /* Line buffer */
+ name[256], /* Configuration directive */
+ *nameptr, /* Pointer into name */
+ *value, /* Value for directive */
+ *valptr; /* Pointer into value */
+ unsigned address, /* Address value */
+ netmask; /* Netmask value */
+ int ip[4], /* IP address components */
+ ipcount, /* Number of components provided */
+ mask[4]; /* IP netmask components */
+ static unsigned netmasks[4] = /* Standard netmasks... */
+ {
+ 0xff000000,
+ 0xffff0000,
+ 0xffffff00,
+ 0xffffffff
+ };
+
+
+ if ((parent = AddLocation(location)) == NULL)
+ return (0);
+
+ parent->limit = AUTH_LIMIT_ALL;
+ loc = parent;
+
+ while (fgets(line, sizeof(line), fp) != NULL)
+ {
+ linenum ++;
+
+ /*
+ * Skip comment lines...
+ */
+
+ if (line[0] == '#')
+ continue;
+
+ /*
+ * Strip trailing whitespace, if any...
+ */
+
+ len = strlen(line);
+
+ while (len > 0 && isspace(line[len - 1]))
+ {
+ len --;
+ line[len] = '\0';
+ }
+
+ /*
+ * Extract the name from the beginning of the line...
+ */
+
+ for (value = line; isspace(*value); value ++);
+
+ for (nameptr = name; *value != '\0' && !isspace(*value) &&
+ nameptr < (name + sizeof(name) - 1);)
+ *nameptr++ = *value++;
+ *nameptr = '\0';
+
+ while (isspace(*value))
+ value ++;
+
+ if (name[0] == '\0')
+ continue;
+
+ /*
+ * Decode the directive...
+ */
+
+ if (strcasecmp(name, "</Location>") == 0)
+ return (linenum);
+ else if (strcasecmp(name, "<Limit") == 0 ||
+ strcasecmp(name, "<LimitExcept") == 0)
+ {
+ if ((loc = CopyLocation(&parent)) == NULL)
+ return (0);
+
+ loc->limit = 0;
+ while (*value)
+ {
+ for (valptr = value;
+ !isspace(*valptr) && *valptr != '>' && *valptr;
+ valptr ++);
+
+ if (*valptr)
+ *valptr++ = '\0';
+
+ if (strcmp(value, "ALL") == 0)
+ loc->limit = AUTH_LIMIT_ALL;
+ else if (strcmp(value, "GET") == 0)
+ loc->limit |= AUTH_LIMIT_GET;
+ else if (strcmp(value, "HEAD") == 0)
+ loc->limit |= AUTH_LIMIT_HEAD;
+ else if (strcmp(value, "OPTIONS") == 0)
+ loc->limit |= AUTH_LIMIT_OPTIONS;
+ else if (strcmp(value, "POST") == 0)
+ loc->limit |= AUTH_LIMIT_POST;
+ else if (strcmp(value, "PUT") == 0)
+ loc->limit |= AUTH_LIMIT_PUT;
+ else if (strcmp(value, "TRACE") == 0)
+ loc->limit |= AUTH_LIMIT_TRACE;
+ else
+ LogMessage(L_WARN, "Unknown request type %s on line %d!", value,
+ linenum);
+
+ for (value = valptr; isspace(*value) || *value == '>'; value ++);
+ }
+
+ if (strcasecmp(name, "<LimitExcept") == 0)
+ loc->limit = AUTH_LIMIT_ALL ^ loc->limit;
+
+ parent->limit &= ~loc->limit;
+ }
+ else if (strcasecmp(name, "</Limit>") == 0)
+ loc = parent;
+ else if (strcasecmp(name, "Encryption") == 0)
+ {
+ /*
+ * "Encryption xxx" - set required encryption level...
+ */
+
+ if (strcasecmp(value, "never") == 0)
+ loc->encryption = HTTP_ENCRYPT_NEVER;
+ else if (strcasecmp(value, "always") == 0)
+ {
+ LogMessage(L_ERROR, "Encryption value \"%s\" on line %d is invalid in this context. "
+ "Using \"required\" instead.", value, linenum);
+
+ loc->encryption = HTTP_ENCRYPT_REQUIRED;
+ }
+ else if (strcasecmp(value, "required") == 0)
+ loc->encryption = HTTP_ENCRYPT_REQUIRED;
+ else if (strcasecmp(value, "ifrequested") == 0)
+ loc->encryption = HTTP_ENCRYPT_IF_REQUESTED;
+ else
+ LogMessage(L_ERROR, "Unknown Encryption value %s on line %d.",
+ value, linenum);
+ }
+ else if (strcasecmp(name, "Order") == 0)
+ {
+ /*
+ * "Order Deny,Allow" or "Order Allow,Deny"...
+ */
+
+ if (strncasecmp(value, "deny", 4) == 0)
+ loc->order_type = AUTH_ALLOW;
+ else if (strncasecmp(value, "allow", 5) == 0)
+ loc->order_type = AUTH_DENY;
+ else
+ LogMessage(L_ERROR, "Unknown Order value %s on line %d.",
+ value, linenum);
+ }
+ else if (strcasecmp(name, "Allow") == 0 ||
+ strcasecmp(name, "Deny") == 0)
+ {
+ /*
+ * Allow [From] host/ip...
+ * Deny [From] host/ip...
+ */
+
+ if (strncasecmp(value, "from", 4) == 0)
+ {
+ /*
+ * Strip leading "from"...
+ */
+
+ value += 4;
+
+ while (isspace(*value))
+ value ++;
+ }
+
+ /*
+ * Figure out what form the allow/deny address takes:
+ *
+ * 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
+ */
+
+ if (strcasecmp(value, "all") == 0)
+ {
+ /*
+ * All hosts...
+ */
+
+ if (strcasecmp(name, "Allow") == 0)
+ AllowIP(loc, 0, 0);
+ else
+ DenyIP(loc, 0, 0);
+ }
+ else if (strcasecmp(value, "none") == 0)
+ {
+ /*
+ * No hosts...
+ */
+
+ if (strcasecmp(name, "Allow") == 0)
+ AllowIP(loc, ~0, 0);
+ else
+ DenyIP(loc, ~0, 0);
+ }
+ else if (value[0] == '*' || value[0] == '.' || !isdigit(value[0]))
+ {
+ /*
+ * Host or domain name...
+ */
+
+ if (value[0] == '*')
+ value ++;
+
+ if (strcasecmp(name, "Allow") == 0)
+ AllowHost(loc, value);
+ else
+ DenyHost(loc, value);
+ }
+ else
+ {
+ /*
+ * One of many IP address forms...
+ */
+
+ memset(ip, 0, sizeof(ip));
+ ipcount = sscanf(value, "%d.%d.%d.%d", ip + 0, ip + 1, ip + 2, ip + 3);
+ address = (((((ip[0] << 8) | ip[1]) << 8) | ip[2]) << 8) | ip[3];
+
+ if ((value = strchr(value, '/')) != NULL)
+ {
+ value ++;
+ memset(mask, 0, sizeof(mask));
+ switch (sscanf(value, "%d.%d.%d.%d", mask + 0, mask + 1,
+ mask + 2, mask + 3))
+ {
+ case 1 :
+ netmask = (0xffffffff << (32 - mask[0])) & 0xffffffff;
+ break;
+ case 4 :
+ netmask = (((((mask[0] << 8) | mask[1]) << 8) |
+ mask[2]) << 8) | mask[3];
+ break;
+ default :
+ LogMessage(L_ERROR, "Bad netmask value %s on line %d.",
+ value, linenum);
+ netmask = 0xffffffff;
+ break;
+ }
+ }
+ else
+ netmask = netmasks[ipcount - 1];
+
+ if (strcasecmp(name, "Allow") == 0)
+ AllowIP(loc, address, netmask);
+ else
+ DenyIP(loc, address, netmask);
+ }
+ }
+ else if (strcasecmp(name, "AuthType") == 0)
+ {
+ /*
+ * AuthType {none,basic,digest}
+ */
+
+ if (strcasecmp(value, "none") == 0)
+ {
+ loc->type = AUTH_NONE;
+ loc->level = AUTH_ANON;
+ }
+ else if (strcasecmp(value, "basic") == 0)
+ {
+ loc->type = AUTH_BASIC;
+
+ if (loc->level == AUTH_ANON)
+ loc->level = AUTH_USER;
+ }
+ else if (strcasecmp(value, "digest") == 0)
+ {
+ loc->type = AUTH_DIGEST;
+
+ if (loc->level == AUTH_ANON)
+ loc->level = AUTH_USER;
+ }
+ else if (strcasecmp(value, "basicdigest") == 0)
+ {
+ loc->type = AUTH_BASICDIGEST;
+
+ if (loc->level == AUTH_ANON)
+ loc->level = AUTH_USER;
+ }
+ else
+ LogMessage(L_WARN, "Unknown authorization type %s on line %d.",
+ value, linenum);
+ }
+ else if (strcasecmp(name, "AuthClass") == 0)
+ {
+ /*
+ * AuthClass anonymous, user, system, group
+ */
+
+ if (strcasecmp(value, "anonymous") == 0)
+ {
+ loc->type = AUTH_NONE;
+ loc->level = AUTH_ANON;
+ }
+ else if (strcasecmp(value, "user") == 0)
+ loc->level = AUTH_USER;
+ else if (strcasecmp(value, "group") == 0)
+ loc->level = AUTH_GROUP;
+ else if (strcasecmp(value, "system") == 0)
+ {
+ loc->level = AUTH_GROUP;
+
+ /*
+ * Use the default system group if none is defined so far...
+ */
+
+ if (NumSystemGroups == 0)
+ NumSystemGroups = 1;
+
+ for (i = 0; i < NumSystemGroups; i ++)
+ AddName(loc, SystemGroups[i]);
+ }
+ else
+ LogMessage(L_WARN, "Unknown authorization class %s on line %d.",
+ value, linenum);
+ }
+ else if (strcasecmp(name, "AuthGroupName") == 0)
+ AddName(loc, value);
+ else if (strcasecmp(name, "Require") == 0)
+ {
+ /*
+ * Apache synonym for AuthClass and AuthGroupName...
+ *
+ * Get initial word:
+ *
+ * Require valid-user
+ * Require group names
+ * Require user names
+ */
+
+ for (valptr = value;
+ !isspace(*valptr) && *valptr != '>' && *valptr;
+ valptr ++);
+
+ if (*valptr)
+ *valptr++ = '\0';
+
+ if (strcasecmp(value, "valid-user") == 0 ||
+ strcasecmp(value, "user") == 0)
+ loc->type = AUTH_USER;
+ else if (strcasecmp(value, "group") == 0)
+ loc->type = AUTH_GROUP;
+ else
+ {
+ LogMessage(L_WARN, "Unknown Require type %s on line %d.",
+ value, linenum);
+ continue;
+ }
+
+ /*
+ * Get the list of names from the line...
+ */
+
+ for (value = valptr; *value;)
+ {
+ for (valptr = value; !isspace(*valptr) && *valptr; valptr ++);
+
+ if (*valptr)
+ *valptr++ = '\0';
+
+ AddName(loc, value);
+
+ for (value = valptr; isspace(*value); value ++);
+ }
+ }
+ else if (strcasecmp(name, "Satisfy") == 0)
+ {
+ if (strcasecmp(value, "all") == 0)
+ loc->satisfy = AUTH_SATISFY_ALL;
+ else if (strcasecmp(value, "any") == 0)
+ loc->satisfy = AUTH_SATISFY_ANY;
+ else
+ LogMessage(L_WARN, "Unknown Satisfy value %s on line %d.", value,
+ linenum);
+ }
+ else
+ LogMessage(L_ERROR, "Unknown Location directive %s on line %d.",
+ name, linenum);
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'get_address()' - Get an address + port number from a line.
+ */
+
+static int /* O - 1 if address good, 0 if bad */
+get_address(char *value, /* I - Value string */
+ unsigned defaddress, /* I - Default address */
+ int defport, /* I - Default port */
+ struct sockaddr_in *address) /* O - Socket address */
+{
+ char hostname[256], /* Hostname or IP */
+ portname[256]; /* Port number or name */
+ struct hostent *host; /* Host address */
+ struct servent *port; /* Port number */
+
+
+ /*
+ * Initialize the socket address to the defaults...
+ */
+
+ memset(address, 0, sizeof(struct sockaddr_in));
+ address->sin_family = AF_INET;
+ address->sin_addr.s_addr = htonl(defaddress);
+ address->sin_port = htons(defport);
+
+ /*
+ * Try to grab a hostname and port number...
+ */
+
+ switch (sscanf(value, "%255[^:]:%255s", hostname, portname))
+ {
+ case 1 :
+ if (strchr(hostname, '.') == NULL && defaddress == INADDR_ANY)
+ {
+ /*
+ * Hostname is a port number...
+ */
+
+ strncpy(portname, hostname, sizeof(portname) - 1);
+ portname[sizeof(portname) - 1] = '\0';
+ hostname[0] = '\0';
+ }
+ else
+ portname[0] = '\0';
+ break;
+ case 2 :
+ break;
+ default :
+ LogMessage(L_ERROR, "Unable to decode address \"%s\"!", value);
+ return (0);
+ }
+
+ /*
+ * Decode the hostname and port number as needed...
+ */
+
+ if (hostname[0] && strcmp(hostname, "*") != 0)
+ {
+ if ((host = httpGetHostByName(hostname)) == NULL)
+ {
+ LogMessage(L_ERROR, "httpGetHostByName(\"%s\") failed - %s!", hostname,
+ strerror(errno));
+ return (0);
+ }
+
+ memcpy(&(address->sin_addr), host->h_addr, host->h_length);
+ address->sin_port = htons(defport);
+ }
+
+ if (portname[0] != '\0')
+ {
+ if (isdigit(portname[0]))
+ address->sin_port = htons(atoi(portname));
+ else
+ {
+ if ((port = getservbyname(portname, NULL)) == NULL)
+ {
+ LogMessage(L_ERROR, "getservbyname(\"%s\") failed - %s!", portname,
+ strerror(errno));
+ return (0);
+ }
+ else
+ address->sin_port = htons(port->s_port);
+ }
+ }
+
+ return (1);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/conf.h b/scheduler/conf.h
new file mode 100644
index 000000000..a790b1c2f
--- /dev/null
+++ b/scheduler/conf.h
@@ -0,0 +1,169 @@
+/*
+ * "$Id$"
+ *
+ * Configuration file definitions for the Common UNIX Printing System (CUPS)
+ * scheduler.
+ *
+ * Copyright 1997-2002 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
+ */
+
+/*
+ * Log levels...
+ */
+
+#define L_PAGE -1 /* Used internally for page logging */
+#define L_NONE 0
+#define L_EMERG 1 /* Emergency issues */
+#define L_ALERT 2 /* Something bad happened that needs attention */
+#define L_CRIT 3 /* Critical error but server continues */
+#define L_ERROR 4 /* Error condition */
+#define L_WARN 5 /* Warning */
+#define L_NOTICE 6 /* Normal condition that needs logging */
+#define L_INFO 7 /* General information */
+#define L_DEBUG 8 /* General debugging */
+#define L_DEBUG2 9 /* Detailed debugging */
+
+
+/*
+ * Printcap formats...
+ */
+
+#define PRINTCAP_BSD 0 /* Berkeley LPD format */
+#define PRINTCAP_SOLARIS 1 /* Solaris lpsched format */
+
+
+/*
+ * Globals...
+ */
+
+VAR char ConfigurationFile[256] VALUE(CUPS_SERVERROOT "/cupsd.conf"),
+ /* Configuration file to use */
+ ServerName[256] VALUE(""),
+ /* FQDN for server */
+ ServerAdmin[256] VALUE(""),
+ /* Administrator's email */
+ ServerRoot[1024] VALUE(CUPS_SERVERROOT),
+ /* Root directory for scheduler */
+ ServerBin[1024] VALUE(CUPS_SERVERBIN),
+ /* Root directory for binaries */
+ RequestRoot[1024] VALUE(CUPS_REQUESTS),
+ /* Directory for request files */
+ DocumentRoot[1024] VALUE(CUPS_DOCROOT);
+ /* Root directory for documents */
+VAR int NumSystemGroups VALUE(0);
+ /* Number of system group names */
+VAR char SystemGroups[MAX_SYSTEM_GROUPS][32],
+ /* System group names */
+ AccessLog[1024] VALUE(CUPS_LOGDIR "/access_log"),
+ /* Access log filename */
+ ErrorLog[1024] VALUE(CUPS_LOGDIR "/error_log"),
+ /* Error log filename */
+ PageLog[1024] VALUE(CUPS_LOGDIR "/page_log"),
+ /* Page log filename */
+ DataDir[1024] VALUE(CUPS_DATADIR),
+ /* Data file directory */
+ DefaultLanguage[32] VALUE("C"),
+ /* Default language encoding */
+ DefaultCharset[32] VALUE(DEFAULT_CHARSET),
+ /* Default charset */
+ RIPCache[32] VALUE("8m"),
+ /* Amount of memory for RIPs */
+ TempDir[1024] VALUE(CUPS_REQUESTS "/tmp"),
+ /* Temporary directory */
+ Printcap[1024] VALUE(""),
+ /* Printcap file */
+ PrintcapGUI[1024] VALUE("/usr/bin/glpoptions"),
+ /* GUI program to use for IRIX */
+ FontPath[1024] VALUE(CUPS_FONTPATH),
+ /* Font search path */
+ RemoteRoot[32] VALUE("remroot"),
+ /* Remote root user */
+ Classification[IPP_MAX_NAME] VALUE("");
+ /* Classification of system */
+VAR int ClassifyOverride VALUE(0),
+ /* Allow overrides? */
+ User VALUE(1),
+ /* User ID for server */
+ Group VALUE(0),
+ /* Group ID for server */
+ LogLevel VALUE(L_ERROR),
+ /* Log level */
+ MaxClients VALUE(0),
+ /* Maximum number of clients */
+ MaxLogSize VALUE(1024 * 1024),
+ /* Maximum size of log files */
+ MaxRequestSize VALUE(0),
+ /* Maximum size of IPP requests */
+ HostNameLookups VALUE(FALSE),
+ /* Do we do reverse lookups? */
+ Timeout VALUE(DEFAULT_TIMEOUT),
+ /* Timeout during requests */
+ KeepAlive VALUE(TRUE),
+ /* Support the Keep-Alive option? */
+ KeepAliveTimeout VALUE(DEFAULT_KEEPALIVE),
+ /* Timeout between requests */
+ ImplicitClasses VALUE(TRUE),
+ /* Are classes implicitly created? */
+ ImplicitAnyClasses VALUE(FALSE),
+ /* Create AnyPrinter classes? */
+ HideImplicitMembers VALUE(TRUE),
+ /* Hide implicit class members? */
+ FilterLimit VALUE(0),
+ /* Max filter cost at any time */
+ FilterLevel VALUE(0),
+ /* Current filter level */
+ RunAsUser VALUE(FALSE),
+ /* Run as unpriviledged user? */
+ PrintcapFormat VALUE(PRINTCAP_BSD);
+ /* Format of printcap file? */
+VAR FILE *AccessFile VALUE(NULL),
+ /* Access log file */
+ *ErrorFile VALUE(NULL),
+ /* Error log file */
+ *PageFile VALUE(NULL);
+ /* Page log file */
+VAR mime_t *MimeDatabase VALUE(NULL);
+ /* MIME type database */
+VAR int NumMimeTypes VALUE(0);
+ /* Number of MIME types */
+VAR const char **MimeTypes VALUE(NULL);
+ /* Array of MIME types */
+
+#ifdef HAVE_LIBSSL
+VAR char ServerCertificate[1024] VALUE("ssl/server.crt"),
+ /* Server certificate file */
+ ServerKey[1024] VALUE("ssl/server.key");
+ /* Server key file */
+#endif /* HAVE_LIBSSL */
+
+
+/*
+ * Prototypes...
+ */
+
+extern char *GetDateTime(time_t t);
+extern int ReadConfiguration(void);
+extern int LogRequest(client_t *con, http_status_t code);
+extern int LogMessage(int level, const char *message, ...);
+extern int LogPage(job_t *job, const char *page);
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/cups-lpd.c b/scheduler/cups-lpd.c
new file mode 100644
index 000000000..e46f6fa21
--- /dev/null
+++ b/scheduler/cups-lpd.c
@@ -0,0 +1,1287 @@
+/*
+ * "$Id$"
+ *
+ * Line Printer Daemon interface for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Easy Software Products and are protected by Federal
+ * copyright law. Distribution and use rights are outlined in the file
+ * "LICENSE.txt" which should have been included with this file. If this
+ * file is missing or damaged please contact Easy Software Products
+ * at:
+ *
+ * Attn: CUPS Licensing Information
+ * Easy Software Products
+ * 44141 Airport View Drive, Suite 204
+ * Hollywood, Maryland 20636-3111 USA
+ *
+ * Voice: (301) 373-9603
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * Contents:
+ *
+ * main() - Process an incoming LPD request...
+ * print_file() - Print a file to a printer or class.
+ * recv_print_job() - Receive a print job from the client.
+ * remove_jobs() - Cancel one or more jobs.
+ * send_short_state() - Send the short queue state.
+ * smart_gets() - Get a line of text, removing the trailing CR
+ * and/or LF.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups.h>
+#include <cups/string.h>
+#include <cups/language.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <syslog.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+
+/*
+ * LPD "mini-daemon" for CUPS. This program must be used in conjunction
+ * with inetd or another similar program that monitors ports and starts
+ * daemons for each client connection. A typical configuration is:
+ *
+ * printer stream tcp nowait lp /usr/lib/cups/daemon/cups-lpd cups-lpd
+ *
+ * This daemon implements most of RFC 1179 (the unofficial LPD specification)
+ * except for:
+ *
+ * - This daemon does not check to make sure that the source port is
+ * between 721 and 731, since it isn't necessary for proper
+ * functioning and port-based security is no security at all!
+ *
+ * - The "Print any waiting jobs" command is a no-op.
+ *
+ * The LPD-to-IPP mapping is as defined in RFC 2569. The report formats
+ * currently match the Solaris LPD mini-daemon.
+ */
+
+/*
+ * Prototypes...
+ */
+
+int print_file(const char *name, const char *file,
+ const char *title, const char *docname,
+ const char *user, int num_options,
+ cups_option_t *options);
+int recv_print_job(const char *dest, int num_defaults, cups_option_t *defaults);
+int remove_jobs(const char *dest, const char *agent, const char *list);
+int send_state(const char *dest, const char *list, int longstatus);
+char *smart_gets(char *s, int len, FILE *fp);
+
+
+/*
+ * 'main()' - Process an incoming LPD request...
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i; /* Looping var */
+ int num_defaults; /* Number of default options */
+ cups_option_t *defaults; /* Default options */
+ char line[256], /* Command string */
+ command, /* Command code */
+ *dest, /* Pointer to destination */
+ *list, /* Pointer to list */
+ *agent, /* Pointer to user */
+ status; /* Status for client */
+ int hostlen; /* Size of client address */
+ unsigned hostip; /* (32-bit) IP address */
+ struct sockaddr_in hostaddr; /* Address of client */
+ struct hostent *hostname; /* Name of client */
+
+
+ /*
+ * Don't buffer the output...
+ */
+
+ setbuf(stdout, NULL);
+
+ /*
+ * Log things using the "cups-lpd" name...
+ */
+
+ openlog("cups-lpd", LOG_PID, LOG_LPR);
+
+ /*
+ * Get the address of the client...
+ */
+
+ hostlen = sizeof(hostaddr);
+
+ if (getpeername(0, (struct sockaddr *)&hostaddr, &hostlen))
+ syslog(LOG_WARNING, "Unable to get client address - %s", strerror(errno));
+ else
+ {
+ hostip = ntohl(hostaddr.sin_addr.s_addr);
+ hostname = gethostbyaddr((void *)&(hostaddr.sin_addr), hostlen, AF_INET);
+
+ syslog(LOG_INFO, "Connection from %s (%d.%d.%d.%d)",
+ hostname ? hostname->h_name : "unknown",
+ (hostip >> 24) & 255, (hostip >> 16) & 255,
+ (hostip >> 8) & 255, hostip & 255);
+ }
+
+ /*
+ * Scan the command-line for options...
+ */
+
+ num_defaults = 0;
+ defaults = NULL;
+
+ for (i = 1; i < argc; i ++)
+ if (argv[i][0] == '-')
+ {
+ switch (argv[i][1])
+ {
+ case 'o' : /* Option */
+ if (argv[i][2])
+ num_defaults = cupsParseOptions(argv[i] + 2, num_defaults,
+ &defaults);
+ else
+ {
+ i ++;
+ if (i < argc)
+ num_defaults = cupsParseOptions(argv[i], num_defaults, &defaults);
+ else
+ syslog(LOG_WARNING, "Expected option string after -o option!");
+ }
+ break;
+ default :
+ syslog(LOG_WARNING, "Unknown option \"%c\" ignored!", argv[i][1]);
+ break;
+ }
+ }
+ else
+ syslog(LOG_WARNING, "Unknown command-line option \"%s\" ignored!", argv[i]);
+
+ /*
+ * RFC1179 specifies that only 1 daemon command can be received for
+ * every connection.
+ */
+
+ if (smart_gets(line, sizeof(line), stdin) == NULL)
+ {
+ /*
+ * Unable to get command from client! Send an error status and return.
+ */
+
+ syslog(LOG_ERR, "Unable to get command line from client!");
+ putchar(1);
+ return (1);
+ }
+
+ /*
+ * The first byte is the command byte. After that will be the queue name,
+ * resource list, and/or user name.
+ */
+
+ command = line[0];
+ dest = line + 1;
+
+ for (list = dest + 1; *list && !isspace(*list); list ++);
+
+ while (isspace(*list))
+ *list++ = '\0';
+
+ /*
+ * Do the command...
+ */
+
+ switch (command)
+ {
+ default : /* Unknown command */
+ syslog(LOG_ERR, "Unknown LPD command 0x%02X!", command);
+ syslog(LOG_ERR, "Command line = %s", line + 1);
+ putchar(1);
+
+ status = 1;
+ break;
+
+ case 0x01 : /* Print any waiting jobs */
+ syslog(LOG_INFO, "Print waiting jobs (no-op)");
+ putchar(0);
+
+ status = 0;
+ break;
+
+ case 0x02 : /* Receive a printer job */
+ syslog(LOG_INFO, "Receive print job for %s", dest);
+ /* recv_print_job() sends initial status byte */
+
+ status = recv_print_job(dest, num_defaults, defaults);
+ break;
+
+ case 0x03 : /* Send queue state (short) */
+ syslog(LOG_INFO, "Send queue state (short) for %s %s", dest, list);
+ /* send_state() sends initial status byte */
+
+ status = send_state(dest, list, 0);
+ break;
+
+ case 0x04 : /* Send queue state (long) */
+ syslog(LOG_INFO, "Send queue state (long) for %s %s", dest, list);
+ /* send_state() sends initial status byte */
+
+ status = send_state(dest, list, 1);
+ break;
+
+ case 0x05 : /* Remove jobs */
+ /*
+ * Grab the agent and skip to the list of users and/or jobs.
+ */
+
+ agent = list;
+
+ for (; *list && !isspace(*list); list ++);
+ while (isspace(*list))
+ *list++ = '\0';
+
+ syslog(LOG_INFO, "Remove jobs %s on %s by %s", list, dest, agent);
+
+ status = remove_jobs(dest, agent, list);
+
+ putchar(status);
+ break;
+ }
+
+ syslog(LOG_INFO, "Closing connection");
+ closelog();
+
+ return (status);
+}
+
+
+/*
+ * 'print_file()' - Print a file to a printer or class.
+ */
+
+int /* O - Job ID */
+print_file(const char *name, /* I - Printer or class name */
+ const char *file, /* I - File to print */
+ const char *title, /* I - Title of job */
+ const char *docname, /* I - Name of job file */
+ const char *user, /* I - Owner of job */
+ int num_options, /* I - Number of options */
+ cups_option_t *options) /* I - Options */
+{
+ http_t *http; /* Connection to server */
+ ipp_t *request; /* IPP request */
+ ipp_t *response; /* IPP response */
+ ipp_attribute_t *attr; /* IPP job-id attribute */
+ char uri[HTTP_MAX_URI]; /* Printer URI */
+ cups_lang_t *language; /* Language to use */
+ int jobid; /* New job ID */
+
+
+ /*
+ * Setup a connection and request data...
+ */
+
+ if ((http = httpConnectEncrypt(cupsServer(), ippPort(),
+ cupsEncryption())) == NULL)
+ {
+ syslog(LOG_ERR, "Unable to connect to server: %s", strerror(errno));
+ return (0);
+ }
+
+ language = cupsLangDefault();
+
+ /*
+ * Build a standard CUPS URI for the printer and fill the standard IPP
+ * attributes...
+ */
+
+ if ((request = ippNew()) == NULL)
+ {
+ syslog(LOG_ERR, "Unable to create request: %s", strerror(errno));
+ return (0);
+ }
+
+ request->request.op.operation_id = IPP_PRINT_JOB;
+ request->request.op.request_id = 1;
+
+ snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", name);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, cupsLangEncoding(language));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL,
+ language != NULL ? language->language : "C");
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, uri);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, user);
+
+ if (title)
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL, title);
+ if (docname)
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "document-name", NULL, docname);
+
+ /*
+ * Then add all options on the command-line...
+ */
+
+ cupsEncodeOptions(request, num_options, options);
+
+ /*
+ * Do the request...
+ */
+
+ snprintf(uri, sizeof(uri), "/printers/%s", name);
+
+ response = cupsDoFileRequest(http, request, uri, file);
+
+ if (response == NULL)
+ jobid = 0;
+ else if (response->request.status.status_code > IPP_OK_CONFLICT)
+ jobid = 0;
+ else if ((attr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER)) == NULL)
+ jobid = 0;
+ else
+ jobid = attr->values[0].integer;
+
+ if (jobid)
+ syslog(LOG_INFO, "Print file - job ID = %d", jobid);
+ else if (response)
+ syslog(LOG_ERR, "Unable to print file - %s",
+ ippErrorString(response->request.status.status_code));
+ else
+ syslog(LOG_ERR, "Unable to print file - %s",
+ ippErrorString(cupsLastError()));
+
+ if (response != NULL)
+ ippDelete(response);
+
+ httpClose(http);
+ cupsLangFree(language);
+
+ return (jobid);
+}
+
+
+/*
+ * 'recv_print_job()' - Receive a print job from the client.
+ */
+
+int /* O - Command status */
+recv_print_job(const char *dest, /* I - Destination */
+ int num_defaults,/* I - Number of default options */
+ cups_option_t *defaults) /* I - Default options */
+{
+ int i; /* Looping var */
+ int status; /* Command status */
+ int fd; /* Temporary file */
+ FILE *fp; /* File pointer */
+ char filename[1024]; /* Temporary filename */
+ int bytes; /* Bytes received */
+ char line[256], /* Line from file/stdin */
+ command, /* Command from line */
+ *count, /* Number of bytes */
+ *name; /* Name of file */
+ int num_data; /* Number of data files */
+ char control[1024], /* Control filename */
+ data[32][256], /* Data files */
+ temp[32][1024]; /* Temporary files */
+ char user[1024], /* User name */
+ title[1024], /* Job title */
+ docname[1024], /* Document name */
+ queue[256], /* Printer/class queue */
+ *instance; /* Printer/class instance */
+ int num_dests; /* Number of destinations */
+ cups_dest_t *dests, /* Destinations */
+ *destptr; /* Current destination */
+ int num_options; /* Number of options */
+ cups_option_t *options; /* Options */
+ int banner; /* Print banner? */
+
+
+ status = 0;
+ num_data = 0;
+ fd = -1;
+
+ control[0] = '\0';
+
+ strncpy(queue, dest, sizeof(queue) - 1);
+ queue[sizeof(queue) - 1] = '\0';
+
+ if ((instance = strrchr(queue, '/')) != NULL)
+ *instance++ = '\0';
+
+ num_dests = cupsGetDests(&dests);
+ if ((destptr = cupsGetDest(queue, instance, num_dests, dests)) == NULL)
+ {
+ if (instance)
+ syslog(LOG_ERR, "Unknown destination %s/%s!", queue, instance);
+ else
+ syslog(LOG_ERR, "Unknown destination %s!", queue);
+
+ cupsFreeDests(num_dests, dests);
+
+ putchar(1);
+
+ return (1);
+ }
+ else
+ putchar(0);
+
+ while (smart_gets(line, sizeof(line), stdin) != NULL)
+ {
+ if (strlen(line) < 2)
+ {
+ status = 1;
+ break;
+ }
+
+ command = line[0];
+ count = line + 1;
+
+ for (name = count + 1; *name && !isspace(*name); name ++);
+ while (isspace(*name))
+ *name++ = '\0';
+
+ switch (command)
+ {
+ default :
+ case 0x01 : /* Abort */
+ status = 1;
+ break;
+ case 0x02 : /* Receive control file */
+ if (strlen(name) < 2)
+ {
+ syslog(LOG_ERR, "Bad control file name \"%s\"", name);
+ putchar(1);
+ status = 1;
+ break;
+ }
+
+ if (control[0])
+ {
+ /*
+ * Append to the existing control file - the LPD spec is
+ * not entirely clear, but at least the OS/2 LPD code sends
+ * multiple control files per connection...
+ */
+
+ if ((fd = open(control, O_WRONLY)) < 0)
+ {
+ syslog(LOG_ERR, "Unable to append to temporary control file - %s",
+ strerror(errno));
+ putchar(1);
+ status = 1;
+ break;
+ }
+
+ lseek(fd, 0, SEEK_END);
+ }
+ else
+ {
+ if ((fd = cupsTempFd(control, sizeof(control))) < 0)
+ {
+ syslog(LOG_ERR, "Unable to open temporary control file - %s",
+ strerror(errno));
+ putchar(1);
+ status = 1;
+ break;
+ }
+
+ strcpy(filename, control);
+ }
+ break;
+ case 0x03 : /* Receive data file */
+ if (strlen(name) < 2)
+ {
+ syslog(LOG_ERR, "Bad data file name \"%s\"", name);
+ putchar(1);
+ status = 1;
+ break;
+ }
+
+ if (num_data >= (sizeof(data) / sizeof(data[0])))
+ {
+ /*
+ * Too many data files...
+ */
+
+ syslog(LOG_ERR, "Too many data files (%d)", num_data);
+ putchar(1);
+ status = 1;
+ break;
+ }
+
+ strncpy(data[num_data], name, sizeof(data[0]) - 1);
+ data[num_data][sizeof(data[0]) - 1] = '\0';
+
+ if ((fd = cupsTempFd(temp[num_data], sizeof(temp[0]))) < 0)
+ {
+ syslog(LOG_ERR, "Unable to open temporary data file - %s",
+ strerror(errno));
+ putchar(1);
+ status = 1;
+ break;
+ }
+
+ strcpy(filename, temp[num_data]);
+
+ num_data ++;
+ break;
+ }
+
+ putchar(status);
+
+ if (status)
+ break;
+
+ /*
+ * Copy the data or control file from the client...
+ */
+
+ for (i = atoi(count); i > 0; i -= bytes)
+ {
+ if (i > sizeof(line))
+ bytes = sizeof(line);
+ else
+ bytes = i;
+
+ if ((bytes = fread(line, 1, bytes, stdin)) > 0)
+ bytes = write(fd, line, bytes);
+
+ if (bytes < 1)
+ {
+ syslog(LOG_ERR, "Error while reading file - %s",
+ strerror(errno));
+ status = 1;
+ break;
+ }
+ }
+
+ /*
+ * Read trailing nul...
+ */
+
+ if (!status)
+ {
+ if (fread(line, 1, 1, stdin) < 1)
+ {
+ status = 1;
+ syslog(LOG_ERR, "Error while reading trailing nul - %s",
+ strerror(errno));
+ }
+ else if (line[0])
+ {
+ status = 1;
+ syslog(LOG_ERR, "Trailing character after file is not nul (%02X)!",
+ line[0]);
+ }
+ }
+
+ /*
+ * Close the file and send an acknowledgement...
+ */
+
+ close(fd);
+
+ putchar(status);
+
+ if (status)
+ break;
+ }
+
+ if (!status)
+ {
+ /*
+ * Process the control file and print stuff...
+ */
+
+ if ((fp = fopen(control, "rb")) == NULL)
+ status = 1;
+ else
+ {
+ /*
+ * Grab the job information first...
+ */
+
+ title[0] = '\0';
+ user[0] = '\0';
+ docname[0] = '\0';
+ banner = 0;
+
+ while (smart_gets(line, sizeof(line), fp) != NULL)
+ {
+ /*
+ * Process control lines...
+ */
+
+ switch (line[0])
+ {
+ case 'J' : /* Job name */
+ strncpy(title, line + 1, sizeof(title) - 1);
+ title[sizeof(title) - 1] = '\0';
+ break;
+ case 'N' : /* Document name */
+ strncpy(docname, line + 1, sizeof(docname) - 1);
+ docname[sizeof(docname) - 1] = '\0';
+ break;
+ case 'P' : /* User identification */
+ strncpy(user, line + 1, sizeof(user) - 1);
+ user[sizeof(user) - 1] = '\0';
+ break;
+ case 'L' : /* Print banner page */
+ banner = 1;
+ break;
+ }
+
+ if (status)
+ break;
+ }
+
+ /*
+ * Then print the jobs...
+ */
+
+ rewind(fp);
+
+ while (smart_gets(line, sizeof(line), fp) != NULL)
+ {
+ /*
+ * Process control lines...
+ */
+
+ switch (line[0])
+ {
+ case 'c' : /* Plot CIF file */
+ case 'd' : /* Print DVI file */
+ case 'f' : /* Print formatted file */
+ case 'g' : /* Plot file */
+ case 'l' : /* Print file leaving control characters (raw) */
+ case 'n' : /* Print ditroff output file */
+ case 'o' : /* Print PostScript output file */
+ case 'p' : /* Print file with 'pr' format (prettyprint) */
+ case 'r' : /* File to print with FORTRAN carriage control */
+ case 't' : /* Print troff output file */
+ case 'v' : /* Print raster file */
+ /*
+ * Check that we have a username...
+ */
+
+ if (!user[0])
+ {
+ syslog(LOG_WARNING, "No username specified by client! "
+ "Using \"anonymous\"...");
+ strcpy(user, "anonymous");
+ }
+
+ /*
+ * Copy the default options...
+ */
+
+ num_options = 0;
+ options = NULL;
+
+ for (i = 0; i < num_defaults; i ++)
+ num_options = cupsAddOption(defaults[i].name,
+ defaults[i].value,
+ num_options, &options);
+ for (i = 0; i < destptr->num_options; i ++)
+ num_options = cupsAddOption(destptr->options[i].name,
+ destptr->options[i].value,
+ num_options, &options);
+
+ /*
+ * Add additional options as needed...
+ */
+
+ if (!banner)
+ num_options = cupsAddOption("job-sheets", "none",
+ num_options, &options);
+
+ if (line[0] == 'l')
+ num_options = cupsAddOption("raw", "", num_options, &options);
+
+ if (line[0] == 'p')
+ num_options = cupsAddOption("prettyprint", "", num_options,
+ &options);
+
+ /*
+ * Figure out which file we are printing...
+ */
+
+ for (i = 0; i < num_data; i ++)
+ if (strcmp(data[i], line + 1) == 0)
+ break;
+
+ if (i >= num_data)
+ {
+ status = 1;
+ break;
+ }
+
+ /*
+ * Send the print request...
+ */
+
+ if (print_file(queue, temp[i], title, docname, user, num_options,
+ options) == 0)
+ status = 1;
+ else
+ status = 0;
+
+ cupsFreeOptions(num_options, options);
+ break;
+ }
+
+ if (status)
+ break;
+ }
+
+ fclose(fp);
+ }
+ }
+
+ /*
+ * Clean up all temporary files and return...
+ */
+
+ unlink(control);
+
+ for (i = 0; i < num_data; i ++)
+ unlink(temp[i]);
+
+ cupsFreeDests(num_dests, dests);
+
+ return (status);
+}
+
+
+/*
+ * 'remove_jobs()' - Cancel one or more jobs.
+ */
+
+int /* O - Command status */
+remove_jobs(const char *dest, /* I - Destination */
+ const char *agent, /* I - User agent */
+ const char *list) /* I - List of jobs or users */
+{
+ int id; /* Job ID */
+ http_t *http; /* HTTP server connection */
+ ipp_t *request, /* IPP Request */
+ *response; /* IPP Response */
+ cups_lang_t *language; /* Default language */
+ char uri[HTTP_MAX_URI]; /* Job URI */
+
+
+ (void)dest; /* Suppress compiler warnings... */
+
+ /*
+ * Try connecting to the local server...
+ */
+
+ if ((http = httpConnectEncrypt(cupsServer(), ippPort(),
+ cupsEncryption())) == NULL)
+ {
+ syslog(LOG_ERR, "Unable to connect to server: %s", strerror(errno));
+ return (1);
+ }
+
+ language = cupsLangDefault();
+
+ /*
+ * Loop for each job...
+ */
+
+ while ((id = atoi(list)) > 0)
+ {
+ /*
+ * Skip job ID in list...
+ */
+
+ while (isdigit(*list))
+ list ++;
+ while (isspace(*list))
+ list ++;
+
+ /*
+ * Build an IPP_CANCEL_JOB request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * job-uri
+ * requesting-user-name
+ */
+
+ request = ippNew();
+
+ request->request.op.operation_id = IPP_CANCEL_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);
+
+ sprintf(uri, "ipp://localhost/jobs/%d", 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, agent);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/jobs")) != NULL)
+ {
+ if (response->request.status.status_code > IPP_OK_CONFLICT)
+ {
+ syslog(LOG_WARNING, "Cancel of job ID %d failed: %s\n", id,
+ ippErrorString(response->request.status.status_code));
+ ippDelete(response);
+ cupsLangFree(language);
+ httpClose(http);
+ return (1);
+ }
+ else
+ syslog(LOG_INFO, "Job ID %d cancelled", id);
+
+ ippDelete(response);
+ }
+ else
+ {
+ syslog(LOG_WARNING, "Cancel of job ID %d failed: %s\n", id,
+ ippErrorString(cupsLastError()));
+ cupsLangFree(language);
+ httpClose(http);
+ return (1);
+ }
+ }
+
+ cupsLangFree(language);
+ httpClose(http);
+
+ return (0);
+}
+
+
+/*
+ * 'send_state()' - Send the queue state.
+ */
+
+int /* O - Command status */
+send_state(const char *dest, /* I - Destination */
+ const char *list, /* I - Job or user */
+ int longstatus) /* I - List of jobs or users */
+{
+ int id; /* Job ID from list */
+ http_t *http; /* HTTP server connection */
+ 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 */
+ 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 */
+ jobcount, /* Number of jobs */
+ jobcopies, /* Number of copies */
+ rank; /* Rank of job */
+ char rankstr[255]; /* Rank string */
+ char namestr[1024]; /* Job name string */
+ char uri[HTTP_MAX_URI]; /* Printer URI */
+ char queue[256], /* Printer/class queue */
+ *instance; /* Printer/class instance */
+ static const char *ranks[10] = /* Ranking strings */
+ {
+ "th",
+ "st",
+ "nd",
+ "rd",
+ "th",
+ "th",
+ "th",
+ "th",
+ "th",
+ "th"
+ };
+ static const char *requested[] = /* Requested attributes */
+ {
+ "job-id",
+ "job-k-octets",
+ "job-state",
+ "job-printer-uri",
+ "job-originating-user-name",
+ "job-name",
+ "copies"
+ };
+
+
+ /*
+ * Remove instance from destination, if any...
+ */
+
+ strncpy(queue, dest, sizeof(queue) - 1);
+ queue[sizeof(queue) - 1] = '\0';
+
+ if ((instance = strrchr(queue, '/')) != NULL)
+ *instance++ = '\0';
+
+ /*
+ * Try connecting to the local server...
+ */
+
+ if ((http = httpConnectEncrypt(cupsServer(), ippPort(),
+ cupsEncryption())) == NULL)
+ {
+ syslog(LOG_ERR, "Unable to connect to server: %s", strerror(errno));
+ putchar(1);
+ return (1);
+ }
+
+ /*
+ * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following
+ * 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);
+
+ snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", queue);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, uri);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes", NULL, "printer-state");
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/")) != NULL)
+ {
+ if (response->request.status.status_code > IPP_OK_CONFLICT)
+ {
+ syslog(LOG_WARNING, "Unable to get printer list: %s\n",
+ ippErrorString(response->request.status.status_code));
+ ippDelete(response);
+ putchar(1);
+ return (1);
+ }
+ else
+ putchar(0);
+
+ if ((attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != NULL)
+ state = (ipp_pstate_t)attr->values[0].integer;
+ 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
+ {
+ syslog(LOG_WARNING, "Unable to get printer list: %s\n",
+ ippErrorString(cupsLastError()));
+ putchar(1);
+ return (1);
+ }
+
+ /*
+ * 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
+ */
+
+ id = atoi(list);
+
+ request = ippNew();
+
+ request->request.op.operation_id = id ? IPP_GET_JOB_ATTRIBUTES : IPP_GET_JOBS;
+ request->request.op.request_id = 1;
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, cupsLangEncoding(language));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", queue);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, uri);
+
+ if (id)
+ ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", id);
+ else
+ {
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requesting-user-name", NULL, list);
+ ippAddBoolean(request, IPP_TAG_OPERATION, "my-jobs", 1);
+ }
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes", sizeof(requested) / sizeof(requested[0]),
+ NULL, requested);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ jobcount = 0;
+
+ if ((response = cupsDoRequest(http, request, "/")) != NULL)
+ {
+ if (response->request.status.status_code > IPP_OK_CONFLICT)
+ {
+ printf("get-jobs failed: %s\n",
+ ippErrorString(response->request.status.status_code));
+ ippDelete(response);
+ return (1);
+ }
+
+ 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->name == NULL))
+ attr = attr->next;
+
+ if (attr == NULL)
+ break;
+
+ /*
+ * Pull the needed attributes from this job...
+ */
+
+ jobid = 0;
+ jobsize = 0;
+ 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;
+
+ 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;
+ }
+
+ if (!longstatus && jobcount == 0)
+ puts("Rank Owner Job File(s) Total Size");
+
+ jobcount ++;
+
+ /*
+ * Display the job...
+ */
+
+ if (jobstate == IPP_JOB_PROCESSING)
+ strcpy(rankstr, "active");
+ else
+ {
+ snprintf(rankstr, sizeof(rankstr), "%d%s", rank, ranks[rank % 10]);
+ rank ++;
+ }
+
+ if (longstatus)
+ {
+ puts("");
+
+ if (jobcopies > 1)
+ snprintf(namestr, sizeof(namestr), "%d copies of %s", jobcopies,
+ jobname);
+ else
+ {
+ strncpy(namestr, jobname, sizeof(namestr) - 1);
+ namestr[sizeof(namestr) - 1] = '\0';
+ }
+
+ printf("%s: %-34.34s[job %d localhost]\n", jobuser, rankstr, jobid);
+ printf(" %-40.40s%d bytes\n", namestr, jobsize);
+ }
+ else
+ printf("%-7s %-8.8s%-8d%-32.32s%d bytes\n", rankstr, jobuser,
+ jobid, jobname, jobsize);
+
+ if (attr == NULL)
+ break;
+ }
+
+ ippDelete(response);
+ }
+ else
+ {
+ printf("get-jobs failed: %s\n", ippErrorString(cupsLastError()));
+ return (1);
+ }
+
+ if (jobcount == 0)
+ puts("no entries");
+
+ cupsLangFree(language);
+ httpClose(http);
+
+ return (0);
+}
+
+
+/*
+ * 'smart_gets()' - Get a line of text, removing the trailing CR and/or LF.
+ */
+
+char * /* O - Line read or NULL */
+smart_gets(char *s, /* I - Pointer to line buffer */
+ int len, /* I - Size of line buffer */
+ FILE *fp) /* I - File to read from */
+{
+ char *ptr, /* Pointer into line */
+ *end; /* End of line */
+ int ch; /* Character from file */
+
+
+ /*
+ * Read the line; unlike fgets(), we read the entire line but dump
+ * characters that go past the end of the buffer. Also, we accept
+ * CR, LF, or CR LF for the line endings to be "safe", although
+ * RFC 1179 specifically says "just use LF".
+ */
+
+ ptr = s;
+ end = s + len - 1;
+
+ while ((ch = getc(fp)) != EOF)
+ {
+ if (ch == '\n')
+ break;
+ else if (ch == '\r')
+ {
+ /*
+ * See if a LF follows...
+ */
+
+ ch = getc(fp);
+
+ if (ch != '\n')
+ ungetc(ch, fp);
+
+ break;
+ }
+ else if (ptr < end)
+ *ptr++ = ch;
+ }
+
+ *ptr = '\0';
+
+ if (ch == EOF && ptr == s)
+ return (NULL);
+ else
+ return (s);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/cups-polld.c b/scheduler/cups-polld.c
new file mode 100644
index 000000000..c7e53e8b4
--- /dev/null
+++ b/scheduler/cups-polld.c
@@ -0,0 +1,327 @@
+/*
+ * "$Id$"
+ *
+ * Polling daemon for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Easy Software Products and are protected by Federal
+ * copyright law. Distribution and use rights are outlined in the file
+ * "LICENSE.txt" which should have been included with this file. If this
+ * file is missing or damaged please contact Easy Software Products
+ * at:
+ *
+ * Attn: CUPS Licensing Information
+ * Easy Software Products
+ * 44141 Airport View Drive, Suite 204
+ * Hollywood, Maryland 20636-3111 USA
+ *
+ * Voice: (301) 373-9603
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * Contents:
+ *
+ * main() - Open socks and poll until we are killed...
+ * poll_server() - Poll the server for the given set of printers or classes.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups.h>
+#include <stdlib.h>
+#include <cups/language.h>
+#include <cups/string.h>
+
+
+/*
+ * Local functions...
+ */
+
+int poll_server(http_t *http, cups_lang_t *language, ipp_op_t op,
+ int sock, int port);
+
+
+/*
+ * 'main()' - Open socks and poll until we are killed...
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ http_t *http; /* HTTP connection */
+ cups_lang_t *language; /* Language info */
+ int interval; /* Polling interval */
+ int sock; /* Browser sock */
+ int port; /* Browser port */
+ int val; /* Socket option value */
+
+
+ /*
+ * Don't buffer errors...
+ */
+
+ setbuf(stderr, NULL);
+
+ /*
+ * The command-line must contain the following:
+ *
+ * cups-polld server server-port interval port
+ */
+
+ if (argc != 5)
+ {
+ fputs("Usage: cups-polld server server-port interval port\n", stderr);
+ return (1);
+ }
+
+ interval = atoi(argv[3]);
+ port = atoi(argv[4]);
+
+ /*
+ * Open a connection to the server...
+ */
+
+ if ((http = httpConnectEncrypt(argv[1], atoi(argv[2]),
+ cupsEncryption())) == NULL)
+ {
+ perror("cups-polld");
+ return (1);
+ }
+
+ /*
+ * Open a broadcast sock...
+ */
+
+ if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ {
+ perror("cups-polld");
+ httpClose(http);
+ return (1);
+ }
+
+ /*
+ * Set the "broadcast" flag...
+ */
+
+ val = 1;
+ if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)))
+ {
+ perror("cups-polld");
+
+ close(sock);
+ httpClose(http);
+ return (1);
+ }
+
+ /*
+ * Loop forever, asking for available printers and classes...
+ */
+
+ language = cupsLangDefault();
+
+ for (;;)
+ {
+ if (!poll_server(http, language, CUPS_GET_PRINTERS, sock, port))
+ poll_server(http, language, CUPS_GET_CLASSES, sock, port);
+
+ sleep(interval);
+ }
+}
+
+
+/*
+ * 'poll_server()' - Poll the server for the given set of printers or classes.
+ */
+
+int /* O - 0 for success, -1 on error */
+poll_server(http_t *http, /* I - HTTP connection */
+ cups_lang_t *language, /* I - Language */
+ ipp_op_t op, /* I - Operation code */
+ int sock, /* I - Broadcast sock */
+ int port) /* I - Broadcast port */
+{
+ ipp_t *request, /* Request data */
+ *response; /* Response data */
+ ipp_attribute_t *attr; /* Current attribute */
+ const char *uri, /* printer-uri */
+ *info, /* printer-info */
+ *location, /* printer-location */
+ *make_model; /* printer-make-and-model */
+ cups_ptype_t type; /* printer-type */
+ ipp_pstate_t state; /* printer-state */
+ struct sockaddr_in addr; /* Broadcast address */
+ char packet[1540]; /* Data packet */
+ static const char *attrs[] = /* Requested attributes */
+ {
+ "printer-info",
+ "printer-location",
+ "printer-make-and-model",
+ "printer-state",
+ "printer-type",
+ "printer-uri-supported"
+ };
+
+
+ /*
+ * Broadcast to 127.0.0.1 (localhost)
+ */
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_addr.s_addr = htonl(0x7f000001);
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+
+ /*
+ * Build a CUPS_GET_PRINTERS or CUPS_GET_CLASSES request, which requires
+ * only the attributes-charset and attributes-natural-language attributes.
+ */
+
+ 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);
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes", sizeof(attrs) / sizeof(attrs[0]),
+ NULL, attrs);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/")) != NULL)
+ {
+ if (response->request.status.status_code > IPP_OK_CONFLICT)
+ {
+ fprintf(stderr, "cups-polld: get-%s failed: %s\n",
+ op == CUPS_GET_PRINTERS ? "printers" : "classes",
+ ippErrorString(response->request.status.status_code));
+ ippDelete(response);
+ return (-1);
+ }
+
+ /*
+ * Loop through the printers or classes returned in the list...
+ */
+
+ for (attr = response->attrs; attr != NULL; attr = attr->next)
+ {
+ /*
+ * Skip leading attributes until we hit a printer...
+ */
+
+ while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
+ attr = attr->next;
+
+ if (attr == NULL)
+ break;
+
+ /*
+ * Pull the needed attributes from this printer...
+ */
+
+ uri = NULL;
+ info = "";
+ location = "";
+ make_model = "";
+ type = CUPS_PRINTER_REMOTE;
+ state = IPP_PRINTER_IDLE;
+
+ while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
+ {
+ if (strcmp(attr->name, "printer-uri-supported") == 0 &&
+ attr->value_tag == IPP_TAG_URI)
+ uri = attr->values[0].string.text;
+
+ if (strcmp(attr->name, "printer-info") == 0 &&
+ attr->value_tag == IPP_TAG_TEXT)
+ info = attr->values[0].string.text;
+
+ if (strcmp(attr->name, "printer-location") == 0 &&
+ attr->value_tag == IPP_TAG_TEXT)
+ location = attr->values[0].string.text;
+
+ if (strcmp(attr->name, "printer-make-and-model") == 0 &&
+ attr->value_tag == IPP_TAG_TEXT)
+ make_model = attr->values[0].string.text;
+
+ if (strcmp(attr->name, "printer-state") == 0 &&
+ attr->value_tag == IPP_TAG_ENUM)
+ state = (ipp_pstate_t)attr->values[0].integer;
+
+ if (strcmp(attr->name, "printer-type") == 0 &&
+ attr->value_tag == IPP_TAG_ENUM)
+ type = (cups_ptype_t)attr->values[0].integer;
+
+ attr = attr->next;
+ }
+
+ /*
+ * See if we have everything needed...
+ */
+
+ if (uri == NULL)
+ {
+ if (attr == NULL)
+ break;
+ else
+ continue;
+ }
+
+ /*
+ * See if this is a local printer or class...
+ */
+
+ if (!(type & CUPS_PRINTER_REMOTE))
+ {
+ /*
+ * Send the printer information...
+ */
+
+ snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\"\n",
+ type | CUPS_PRINTER_REMOTE, state, uri,
+ location, info, make_model);
+ puts(packet);
+
+ if (sendto(sock, packet, strlen(packet), 0,
+ (struct sockaddr *)&addr, sizeof(addr)) <= 0)
+ {
+ perror("cups-polld");
+ return (-1);
+ }
+ }
+
+ if (attr == NULL)
+ break;
+ }
+
+ ippDelete(response);
+ }
+ else
+ {
+ fprintf(stderr, "cups-polld: get-%s failed: %s\n",
+ op == CUPS_GET_PRINTERS ? "printers" : "classes",
+ ippErrorString(cupsLastError()));
+ return (-1);
+ }
+
+ return (0);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/cups.pam b/scheduler/cups.pam
new file mode 100644
index 000000000..f38e70184
--- /dev/null
+++ b/scheduler/cups.pam
@@ -0,0 +1,2 @@
+auth required /lib/security/pam_pwdb.so nullok shadow
+account required /lib/security/pam_pwdb.so
diff --git a/scheduler/cupsd.dsp b/scheduler/cupsd.dsp
new file mode 100644
index 000000000..60b2cb927
--- /dev/null
+++ b/scheduler/cupsd.dsp
@@ -0,0 +1,173 @@
+# Microsoft Developer Studio Project File - Name="cupsd" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=cupsd - 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 "cupsd.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 "cupsd.mak" CFG="cupsd - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "cupsd - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "cupsd - Win32 Debug" (based on "Win32 (x86) Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "cupsd - 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 "_WINDOWS" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# 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 /nologo /subsystem:windows /machine:I386
+# ADD 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 /nologo /subsystem:windows /machine:I386
+
+!ELSEIF "$(CFG)" == "cupsd - 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 "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "../visualc" /I ".." /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# 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 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# ADD 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 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "cupsd - Win32 Release"
+# Name "cupsd - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\auth.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\classes.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\client.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\conf.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\dirsvc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ipp.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\job.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\listen.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\log.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\main.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\printers.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\auth.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\classes.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\client.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\conf.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\cupsd.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\dirsvc.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\job.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\printers.h
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/scheduler/cupsd.h b/scheduler/cupsd.h
new file mode 100644
index 000000000..3f5fa4cfe
--- /dev/null
+++ b/scheduler/cupsd.h
@@ -0,0 +1,176 @@
+/*
+ * "$Id$"
+ *
+ * Main header file for the Common UNIX Printing System (CUPS) scheduler.
+ *
+ * Copyright 1997-2002 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
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <limits.h>
+#include <errno.h>
+#include <time.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#ifdef WIN32
+# include <direct.h>
+#else
+# include <unistd.h>
+#endif /* WIN32 */
+
+#include <cups/cups.h>
+#include <cups/string.h>
+#include "mime.h"
+#include <cups/http.h>
+#include <cups/ipp.h>
+#include <cups/language.h>
+#include <cups/debug.h>
+
+
+/*
+ * Common constants.
+ */
+
+#ifndef FALSE
+# define FALSE 0
+# define TRUE (!FALSE)
+#endif /* !FALSE */
+
+
+/*
+ * Implementation limits...
+ */
+
+#define MAX_BROWSERS 10 /* Maximum number of browse addresses */
+#define MAX_LISTENERS 10 /* Maximum number of listener sockets */
+#define MAX_USERPASS 33 /* Maximum size of username/password */
+#define MAX_FILTERS 20 /* Maximum number of filters */
+#define MAX_SYSTEM_GROUPS 32 /* Maximum number of system groups */
+
+
+/*
+ * Defaults...
+ */
+
+#define DEFAULT_HISTORY 1 /* Preserve job history? */
+#define DEFAULT_FILES 0 /* Preserve job files? */
+#define DEFAULT_TIMEOUT 300 /* Timeout during requests/updates */
+#define DEFAULT_KEEPALIVE 60 /* Timeout between requests */
+#define DEFAULT_INTERVAL 30 /* Interval between browse updates */
+#define DEFAULT_LANGUAGE setlocale(LC_ALL,"")
+ /* Default language encoding */
+#define DEFAULT_CHARSET "utf-8" /* Default charset */
+
+
+/*
+ * Global variable macros...
+ */
+
+#ifdef _MAIN_C_
+# define VAR
+# define VALUE(x) =x
+#else
+# define VAR extern
+# define VALUE(x)
+#endif /* _MAIN_C */
+
+
+/*
+ * Other stuff for the scheduler...
+ */
+
+#include "cert.h"
+#include "client.h"
+#include "auth.h"
+#include "printers.h"
+#include "classes.h"
+#include "job.h"
+#include "conf.h"
+#include "banners.h"
+#include "dirsvc.h"
+
+
+/*
+ * Directory handling functions...
+ */
+
+#if HAVE_DIRENT_H
+# include <dirent.h>
+typedef struct dirent DIRENT;
+# define NAMLEN(dirent) strlen((dirent)->d_name)
+#else
+# if HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# if HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# if HAVE_NDIR_H
+# include <ndir.h>
+# endif
+typedef struct direct DIRENT;
+# define NAMLEN(dirent) (dirent)->d_namlen
+#endif
+
+
+/*
+ * Globals...
+ */
+
+VAR int MaxFDs; /* Maximum number of files */
+VAR fd_set InputSet, /* Input files for select() */
+ OutputSet; /* Output files for select() */
+
+VAR int NeedReload VALUE(TRUE);
+ /* Need to load configuration? */
+VAR char TZ[1024] VALUE("TZ=GMT");
+ /* Timezone configuration */
+
+VAR ipp_t *Devices VALUE(NULL),
+ /* Available devices */
+ *PPDs VALUE(NULL);
+ /* Available PPDs */
+
+
+/*
+ * Prototypes...
+ */
+
+extern void CatchChildSignals(void);
+extern void IgnoreChildSignals(void);
+extern void LoadDevices(const char *d);
+extern void LoadPPDs(const char *d);
+extern void StartServer(void);
+extern void StopServer(void);
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/devices.c b/scheduler/devices.c
new file mode 100644
index 000000000..d9cac05e7
--- /dev/null
+++ b/scheduler/devices.c
@@ -0,0 +1,482 @@
+/*
+ * "$Id$"
+ *
+ * Device scanning routines for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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:
+ *
+ * LoadDevices() - Load all available devices.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cupsd.h"
+
+
+/*
+ * Device information structure...
+ */
+
+typedef struct
+{
+ char device_class[128], /* Device class */
+ device_make_and_model[128], /* Make and model, if known */
+ device_info[128], /* Device info/description */
+ device_uri[1024]; /* Device URI */
+} dev_info_t;
+
+
+/*
+ * Local globals...
+ */
+
+static int num_devs, /* Number of devices */
+ alloc_devs; /* Number of allocated entries */
+static dev_info_t *devs; /* Device info */
+
+
+/*
+ * Local functions...
+ */
+
+static int compare_devs(const dev_info_t *p0, const dev_info_t *p1);
+static void sigalrm_handler(int sig);
+
+
+/*
+ * 'LoadDevices()' - Load all available devices.
+ */
+
+void
+LoadDevices(const char *d) /* I - Directory to scan */
+{
+ int i; /* Looping var */
+ int count; /* Number of devices from backend */
+ int compat; /* Compatibility device? */
+ FILE *fp; /* Pipe to device backend */
+ DIR *dir; /* Directory pointer */
+ DIRENT *dent; /* Directory entry */
+ char filename[1024], /* Name of backend */
+ line[2048], /* Line from backend */
+ dclass[64], /* Device class */
+ uri[1024], /* Device URI */
+ info[128], /* Device info */
+ make_model[256];/* Make and model */
+ dev_info_t *dev; /* Current device */
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ struct sigaction action; /* Actions for POSIX signals */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+
+
+ /*
+ * Initialize the device list.
+ */
+
+ Devices = ippNew();
+
+ /*
+ * Try opening the backend directory...
+ */
+
+ if ((dir = opendir(d)) == NULL)
+ {
+ LogMessage(L_ERROR, "LoadDevices: Unable to open backend directory \"%s\": %s",
+ d, strerror(errno));
+ return;
+ }
+
+ /*
+ * Setup the devices array...
+ */
+
+ alloc_devs = 0;
+ num_devs = 0;
+ devs = (dev_info_t *)0;
+
+ /*
+ * Ignore child signals...
+ */
+
+ IgnoreChildSignals();
+
+ /*
+ * Loop through all of the device backends...
+ */
+
+ while ((dent = readdir(dir)) != NULL)
+ {
+ /*
+ * Skip "." and ".."...
+ */
+
+ if (dent->d_name[0] == '.')
+ continue;
+
+ /*
+ * Run the backend with no arguments and collect the output...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/%s", d, dent->d_name);
+ if ((fp = popen(filename, "r")) != NULL)
+ {
+ /*
+ * Set an alarm for the first read from the backend; this avoids
+ * problems when a backend is hung getting device information.
+ */
+
+#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
+ sigset(SIGALRM, sigalrm_handler);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+
+ sigemptyset(&action.sa_mask);
+ sigaddset(&action.sa_mask, SIGALRM);
+ action.sa_handler = sigalrm_handler;
+ sigaction(SIGALRM, &action, NULL);
+#else
+ signal(SIGALRM, sigalrm_handler);
+#endif /* HAVE_SIGSET */
+
+ alarm(30);
+ count = 0;
+ compat = strcmp(dent->d_name, "smb") == 0;
+
+ while (fgets(line, sizeof(line), fp) != NULL)
+ {
+ /*
+ * Reset the alarm clock...
+ */
+
+ alarm(30);
+
+ /*
+ * Each line is of the form:
+ *
+ * class URI "make model" "name"
+ */
+
+ if (strncasecmp(line, "Usage", 5) == 0)
+ compat = 1;
+ else if (sscanf(line, "%63s%1023s%*[ \t]\"%127[^\"]\"%*[ \t]\"%255[^\"]",
+ dclass, uri, make_model, info) != 4)
+ {
+ /*
+ * Bad format; strip trailing newline and write an error message.
+ */
+
+ if (line[strlen(line) - 1] == '\n')
+ line[strlen(line) - 1] = '\0';
+
+ LogMessage(L_ERROR, "LoadDevices: Bad line from \"%s\": %s",
+ dent->d_name, line);
+ compat = 1;
+ break;
+ }
+ else
+ {
+ /*
+ * Add the device to the array of available devices...
+ */
+
+ if (num_devs >= alloc_devs)
+ {
+ /*
+ * Allocate (more) memory for the devices...
+ */
+
+ if (alloc_devs == 0)
+ dev = malloc(sizeof(dev_info_t) * 16);
+ else
+ dev = realloc(devs, sizeof(dev_info_t) * (alloc_devs + 16));
+
+ if (dev == NULL)
+ {
+ LogMessage(L_ERROR, "LoadDevices: Ran out of memory for %d devices!",
+ alloc_devs + 16);
+ closedir(dir);
+ return;
+ }
+
+ devs = dev;
+ alloc_devs += 16;
+ }
+
+ dev = devs + num_devs;
+ num_devs ++;
+
+ memset(dev, 0, sizeof(dev_info_t));
+ strncpy(dev->device_class, dclass, sizeof(dev->device_class) - 1);
+ strncpy(dev->device_info, info, sizeof(dev->device_info) - 1);
+ strncpy(dev->device_make_and_model, make_model,
+ sizeof(dev->device_make_and_model) - 1);
+ strncpy(dev->device_uri, uri, sizeof(dev->device_uri) - 1);
+
+ LogMessage(L_DEBUG, "LoadDevices: Added device \"%s\"...", uri);
+ count ++;
+ }
+ }
+
+ /*
+ * Turn the alarm clock off and close the pipe to the command...
+ */
+
+ alarm(0);
+
+ pclose(fp);
+
+ /*
+ * Hack for backends that don't support the CUPS 1.1 calling convention:
+ * add a network device with the method == backend name.
+ */
+
+ if (count == 0 && compat)
+ {
+ if (num_devs >= alloc_devs)
+ {
+ /*
+ * Allocate (more) memory for the devices...
+ */
+
+ if (alloc_devs == 0)
+ dev = malloc(sizeof(dev_info_t) * 16);
+ else
+ dev = realloc(devs, sizeof(dev_info_t) * (alloc_devs + 16));
+
+ if (dev == NULL)
+ {
+ LogMessage(L_ERROR, "LoadDevices: Ran out of memory for %d devices!",
+ alloc_devs + 16);
+ closedir(dir);
+ return;
+ }
+
+ devs = dev;
+ alloc_devs += 16;
+ }
+
+ dev = devs + num_devs;
+ num_devs ++;
+
+ memset(dev, 0, sizeof(dev_info_t));
+ strcpy(dev->device_class, "network");
+ snprintf(dev->device_info, sizeof(dev->device_info),
+ "Unknown Network Device (%s)", dent->d_name);
+ strcpy(dev->device_make_and_model, "Unknown");
+ strncpy(dev->device_uri, dent->d_name, sizeof(dev->device_uri) - 1);
+
+ LogMessage(L_DEBUG, "LoadDevices: Compatibility device \"%s\"...",
+ dent->d_name);
+ }
+ }
+ else
+ LogMessage(L_WARN, "LoadDevices: Unable to execute \"%s\" backend: %s",
+ dent->d_name, strerror(errno));
+ }
+
+ closedir(dir);
+
+ /*
+ * Catch child signals...
+ */
+
+ CatchChildSignals();
+
+ /*
+ * Sort the available devices...
+ */
+
+ if (num_devs > 1)
+ qsort(devs, num_devs, sizeof(dev_info_t),
+ (int (*)(const void *, const void *))compare_devs);
+
+ /*
+ * Create the list of devices...
+ */
+
+ for (i = num_devs, dev = devs; i > 0; i --, dev ++)
+ {
+ /*
+ * Add strings to attributes...
+ */
+
+ if (i < num_devs)
+ ippAddSeparator(Devices);
+
+ ippAddString(Devices, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "device-class", NULL, dev->device_class);
+ ippAddString(Devices, IPP_TAG_PRINTER, IPP_TAG_TEXT,
+ "device-info", NULL, dev->device_info);
+ ippAddString(Devices, IPP_TAG_PRINTER, IPP_TAG_TEXT,
+ "device-make-and-model", NULL, dev->device_make_and_model);
+ ippAddString(Devices, IPP_TAG_PRINTER, IPP_TAG_URI,
+ "device-uri", NULL, dev->device_uri);
+ }
+
+ /*
+ * Free the devices array...
+ */
+
+ if (alloc_devs)
+ free(devs);
+}
+
+
+/*
+ * 'compare_devs()' - Compare PPD file make and model names for sorting.
+ */
+
+static int /* O - Result of comparison */
+compare_devs(const dev_info_t *d0, /* I - First PPD file */
+ const dev_info_t *d1) /* I - Second PPD file */
+{
+ const char *s, /* First name */
+ *t; /* Second name */
+ int diff, /* Difference between digits */
+ digits; /* Number of digits */
+
+
+ /*
+ * First compare names...
+ */
+
+ s = d0->device_info;
+ t = d1->device_info;
+
+ /*
+ * Loop through both nicknames, 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;
+ s ++;
+ t ++;
+
+ 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 if (diff)
+ 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 if ((diff = strcasecmp(d0->device_class, d1->device_class)) != 0)
+ return (diff);
+ else
+ return (strcasecmp(d0->device_uri, d1->device_uri));
+}
+
+
+/*
+ * 'sigalrm_handler()' - Handle alarm signals for backends that get hung
+ * trying to list the available devices...
+ */
+
+static void
+sigalrm_handler(int sig) /* I - Signal number */
+{
+ (void)sig; /* remove compiler warnings... */
+
+ LogMessage(L_WARN, "LoadDevices: Backend did not respond within 30 seconds!");
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/dirsvc.c b/scheduler/dirsvc.c
new file mode 100644
index 000000000..53b413b7c
--- /dev/null
+++ b/scheduler/dirsvc.c
@@ -0,0 +1,1729 @@
+/*
+ * "$Id$"
+ *
+ * Directory services routines for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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:
+ *
+ * ProcessBrowseData() - Process new browse data.
+ * SendBrowseList() - Send new browsing information as necessary.
+ * SendCUPSBrowse() - Send new browsing information using the CUPS protocol.
+ * StartBrowsing() - Start sending and receiving broadcast information.
+ * StartPolling() - Start polling servers as needed.
+ * StopBrowsing() - Stop sending and receiving broadcast information.
+ * StopPolling() - Stop polling servers as needed.
+ * UpdateCUPSBrowse() - Update the browse lists using the CUPS protocol.
+ * UpdatePolling() - Read status messages from the poll daemons.
+ * RegReportCallback() - Empty SLPRegReport.
+ * SendSLPBrowse() - Register the specified printer with SLP.
+ * SLPDeregPrinter() - SLPDereg() the specified printer
+ * GetSlpAttrVal() - Get an attribute from an SLP registration.
+ * AttrCallback() - SLP attribute callback
+ * SrvUrlCallback() - SLP service url callback
+ * UpdateSLPBrowse() - Get browsing information via SLP.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cupsd.h"
+#include <grp.h>
+
+
+/*
+ * 'ProcessBrowseData()' - Process new browse data.
+ */
+
+void
+ProcessBrowseData(const char *uri, /* I - URI of printer/class */
+ cups_ptype_t type, /* I - Printer type */
+ ipp_pstate_t state, /* I - Printer state */
+ const char *location,/* I - Printer location */
+ const char *info, /* I - Printer information */
+ const char *make_model) /* I - Printer make and model */
+{
+ int i; /* Looping var */
+ int update; /* Update printer attributes? */
+ char method[HTTP_MAX_URI], /* Method portion of URI */
+ username[HTTP_MAX_URI], /* Username portion of URI */
+ host[HTTP_MAX_URI], /* Host portion of URI */
+ resource[HTTP_MAX_URI]; /* Resource portion of URI */
+ int port; /* Port portion of URI */
+ char name[IPP_MAX_NAME], /* Name of printer */
+ *hptr, /* Pointer into hostname */
+ *sptr; /* Pointer into ServerName */
+ char local_make_model[IPP_MAX_NAME];
+ /* Local make and model */
+ printer_t *p, /* Printer information */
+ *pclass, /* Printer class */
+ *first, /* First printer in class */
+ *next; /* Next printer in list */
+ int offset, /* Offset of name */
+ len; /* Length of name */
+
+
+ /*
+ * Pull the URI apart to see if this is a local or remote printer...
+ */
+
+ httpSeparate(uri, method, username, host, &port, resource);
+
+ /*
+ * OK, this isn't a local printer; see if we already have it listed in
+ * the Printers list, and add it if not...
+ */
+
+ update = 0;
+ hptr = strchr(host, '.');
+ sptr = strchr(ServerName, '.');
+
+ if (sptr != NULL && hptr != NULL)
+ {
+ /*
+ * Strip the common domain name components...
+ */
+
+ while (hptr != NULL)
+ {
+ if (strcasecmp(hptr, sptr) == 0)
+ {
+ *hptr = '\0';
+ break;
+ }
+ else
+ hptr = strchr(hptr + 1, '.');
+ }
+ }
+
+ if (type & CUPS_PRINTER_CLASS)
+ {
+ /*
+ * Remote destination is a class...
+ */
+
+ if (strncmp(resource, "/classes/", 9) == 0)
+ snprintf(name, sizeof(name), "%s@%s", resource + 9, host);
+ else
+ return;
+
+ if ((p = FindClass(name)) == NULL && BrowseShortNames)
+ {
+ if ((p = FindClass(resource + 9)) != NULL)
+ {
+ if (strcasecmp(p->hostname, host) != 0 && p->hostname[0])
+ {
+ /*
+ * Nope, this isn't the same host; if the hostname isn't the local host,
+ * add it to the other class and then find a class using the full host
+ * name...
+ */
+
+ if (p->type & CUPS_PRINTER_REMOTE)
+ {
+ /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */
+ strncat(p->name, "@", sizeof(p->name) - 1);
+ strncat(p->name, p->hostname, sizeof(p->name) - 1);
+ SetPrinterAttrs(p);
+ SortPrinters();
+ }
+
+ p = NULL;
+ }
+ else if (!p->hostname[0])
+ {
+ /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */
+ strncpy(p->hostname, host, sizeof(p->hostname) - 1);
+ strncpy(p->uri, uri, sizeof(p->uri) - 1);
+ strncpy(p->device_uri, uri, sizeof(p->device_uri) - 1);
+ update = 1;
+ }
+ }
+ else
+ {
+ strncpy(name, resource + 9, sizeof(name) - 1);
+ name[sizeof(name) - 1] = '\0';
+ }
+ }
+ else if (p != NULL && !p->hostname[0])
+ {
+ /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */
+ strncpy(p->hostname, host, sizeof(p->hostname) - 1);
+ strncpy(p->uri, uri, sizeof(p->uri) - 1);
+ strncpy(p->device_uri, uri, sizeof(p->device_uri) - 1);
+ update = 1;
+ }
+
+ if (p == NULL)
+ {
+ /*
+ * Class doesn't exist; add it...
+ */
+
+ p = AddClass(name);
+
+ LogMessage(L_INFO, "Added remote class \"%s\"...", name);
+
+ /*
+ * Force the URI to point to the real server...
+ */
+
+ p->type = type;
+ /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */
+ strncpy(p->uri, uri, sizeof(p->uri) - 1);
+ strncpy(p->device_uri, uri, sizeof(p->device_uri) - 1);
+ strncpy(p->hostname, host, sizeof(p->hostname) - 1);
+
+ update = 1;
+ }
+ }
+ else
+ {
+ /*
+ * Remote destination is a printer...
+ */
+
+ if (strncmp(resource, "/printers/", 10) == 0)
+ snprintf(name, sizeof(name), "%s@%s", resource + 10, host);
+ else
+ return;
+
+ if ((p = FindPrinter(name)) == NULL && BrowseShortNames)
+ {
+ if ((p = FindPrinter(resource + 10)) != NULL)
+ {
+ if (strcasecmp(p->hostname, host) != 0 && p->hostname[0])
+ {
+ /*
+ * Nope, this isn't the same host; if the hostname isn't the local host,
+ * add it to the other printer and then find a printer using the full host
+ * name...
+ */
+
+ if (p->type & CUPS_PRINTER_REMOTE)
+ {
+ /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */
+ strncat(p->name, "@", sizeof(p->name) - 1);
+ strncat(p->name, p->hostname, sizeof(p->name) - 1);
+ SetPrinterAttrs(p);
+ SortPrinters();
+ }
+
+ p = NULL;
+ }
+ else if (!p->hostname[0])
+ {
+ /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */
+ strncpy(p->hostname, host, sizeof(p->hostname) - 1);
+ strncpy(p->uri, uri, sizeof(p->uri) - 1);
+ strncpy(p->device_uri, uri, sizeof(p->device_uri) - 1);
+ update = 1;
+ }
+ }
+ else
+ {
+ strncpy(name, resource + 10, sizeof(name) - 1);
+ name[sizeof(name) - 1] = '\0';
+ }
+ }
+ else if (p != NULL && !p->hostname[0])
+ {
+ /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */
+ strncpy(p->hostname, host, sizeof(p->hostname) - 1);
+ strncpy(p->uri, uri, sizeof(p->uri) - 1);
+ strncpy(p->device_uri, uri, sizeof(p->device_uri) - 1);
+ update = 1;
+ }
+
+ if (p == NULL)
+ {
+ /*
+ * Printer doesn't exist; add it...
+ */
+
+ p = AddPrinter(name);
+
+ LogMessage(L_INFO, "Added remote printer \"%s\"...", name);
+
+ /*
+ * Force the URI to point to the real server...
+ */
+
+ p->type = type;
+ /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */
+ strncpy(p->hostname, host, sizeof(p->hostname) - 1);
+ strncpy(p->uri, uri, sizeof(p->uri) - 1);
+ strncpy(p->device_uri, uri, sizeof(p->device_uri) - 1);
+
+ update = 1;
+ }
+ }
+
+ /*
+ * Update the state...
+ */
+
+ p->state = state;
+ p->accepting = state != IPP_PRINTER_STOPPED;
+ p->browse_time = time(NULL);
+
+ if (p->type != type)
+ {
+ p->type = type;
+ update = 1;
+ }
+
+ if (strcmp(p->location, location))
+ {
+ /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */
+ strncpy(p->location, location, sizeof(p->location) - 1);
+ update = 1;
+ }
+
+ if (strcmp(p->info, info))
+ {
+ /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */
+ strncpy(p->info, info, sizeof(p->info) - 1);
+ update = 1;
+ }
+
+ if (!make_model[0])
+ {
+ if (type & CUPS_PRINTER_CLASS)
+ snprintf(local_make_model, sizeof(local_make_model),
+ "Remote Class on %s", host);
+ else
+ snprintf(local_make_model, sizeof(local_make_model),
+ "Remote Printer on %s", host);
+ }
+ else
+ snprintf(local_make_model, sizeof(local_make_model),
+ "%s on %s", make_model, host);
+
+ if (strcmp(p->make_model, local_make_model))
+ {
+ /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */
+ strncpy(p->make_model, local_make_model, sizeof(p->make_model) - 1);
+ update = 1;
+ }
+
+ if (update)
+ SetPrinterAttrs(p);
+
+ /*
+ * See if we have a default printer... If not, make the first printer the
+ * default.
+ */
+
+ if (DefaultPrinter == NULL && Printers != NULL)
+ DefaultPrinter = Printers;
+
+ /*
+ * Do auto-classing if needed...
+ */
+
+ if (ImplicitClasses)
+ {
+ /*
+ * Loop through all available printers and create classes as needed...
+ */
+
+ for (p = Printers, len = 0, offset = 0, first = NULL;
+ p != NULL;
+ p = next)
+ {
+ /*
+ * Get next printer in list...
+ */
+
+ next = p->next;
+
+ /*
+ * Skip classes...
+ */
+
+ if (p->type & (CUPS_PRINTER_IMPLICIT | CUPS_PRINTER_CLASS))
+ {
+ len = 0;
+ continue;
+ }
+
+ /*
+ * If len == 0, get the length of this printer name up to the "@"
+ * sign (if any).
+ */
+
+ if (len > 0 &&
+ strncasecmp(p->name, name + offset, len) == 0 &&
+ (p->name[len] == '\0' || p->name[len] == '@'))
+ {
+ /*
+ * We have more than one printer with the same name; see if
+ * we have a class, and if this printer is a member...
+ */
+
+ if ((pclass = FindPrinter(name)) == NULL)
+ {
+ /*
+ * Need to add the class...
+ */
+
+ pclass = AddPrinter(name);
+ pclass->type |= CUPS_PRINTER_IMPLICIT;
+ pclass->accepting = 1;
+ pclass->state = IPP_PRINTER_IDLE;
+
+ SetPrinterAttrs(pclass);
+
+ LogMessage(L_INFO, "Added implicit class \"%s\"...", name);
+ }
+
+ if (first != NULL)
+ {
+ for (i = 0; i < pclass->num_printers; i ++)
+ if (pclass->printers[i] == first)
+ break;
+
+ if (i >= pclass->num_printers)
+ AddPrinterToClass(pclass, first);
+
+ first = NULL;
+ }
+
+ for (i = 0; i < pclass->num_printers; i ++)
+ if (pclass->printers[i] == p)
+ break;
+
+ if (i >= pclass->num_printers)
+ AddPrinterToClass(pclass, p);
+ }
+ else
+ {
+ /*
+ * First time around; just get name length and mark it as first
+ * in the list...
+ */
+
+ if ((hptr = strchr(p->name, '@')) != NULL)
+ len = hptr - p->name;
+ else
+ len = strlen(p->name);
+
+ strncpy(name, p->name, len);
+ name[len] = '\0';
+ offset = 0;
+
+ if ((pclass = FindPrinter(name)) != NULL &&
+ !(pclass->type & CUPS_PRINTER_IMPLICIT))
+ {
+ /*
+ * Can't use same name as a local printer; add "Any" to the
+ * front of the name, unless we have explicitly disabled
+ * the "ImplicitAnyClasses"...
+ */
+
+ if (ImplicitAnyClasses)
+ {
+ /*
+ * Add "Any" to the class name...
+ */
+
+ strcpy(name, "Any");
+ strncpy(name + 3, p->name, len);
+ name[len + 3] = '\0';
+ offset = 3;
+ }
+ else
+ {
+ /*
+ * Don't create an implicit class if we have a local printer
+ * with the same name...
+ */
+
+ len = 0;
+ continue;
+ }
+ }
+
+ first = p;
+ }
+ }
+ }
+}
+
+
+/*
+ * 'SendBrowseList()' - Send new browsing information as necessary.
+ */
+
+void
+SendBrowseList(void)
+{
+ printer_t *p, /* Current printer */
+ *np; /* Next printer */
+ time_t ut, /* Minimum update time */
+ to; /* Timeout time */
+
+
+ if (!Browsing || !(BrowseProtocols & BROWSE_CUPS))
+ return;
+
+ /*
+ * Compute the update and timeout times...
+ */
+
+ ut = time(NULL) - BrowseInterval;
+ to = time(NULL) - BrowseTimeout;
+
+ /*
+ * Loop through all of the printers and send local updates as needed...
+ */
+
+ for (p = Printers; p != NULL; p = np)
+ {
+ np = p->next;
+
+ if (p->type & CUPS_PRINTER_REMOTE)
+ {
+ /*
+ * See if this printer needs to be timed out...
+ */
+
+ if (p->browse_time < to)
+ {
+ LogMessage(L_INFO, "Remote destination \"%s\" has timed out; deleting it...",
+ p->name);
+ DeletePrinter(p);
+ }
+ }
+ else if (p->browse_time < ut && BrowseInterval > 0 &&
+ !(p->type & CUPS_PRINTER_IMPLICIT))
+ {
+ /*
+ * Need to send an update...
+ */
+
+ p->browse_time = time(NULL);
+
+ if (BrowseProtocols & BROWSE_CUPS)
+ SendCUPSBrowse(p);
+
+#ifdef HAVE_LIBSLP
+ if (BrowseProtocols & BROWSE_SLP)
+ SendSLPBrowse(p);
+#endif /* HAVE_LIBSLP */
+ }
+ }
+}
+
+
+/*
+ * 'SendCUPSBrowse()' - Send new browsing information using the CUPS protocol.
+ */
+
+void
+SendCUPSBrowse(printer_t *p) /* I - Printer to send */
+{
+ int i; /* Looping var */
+ int bytes; /* Length of packet */
+ char packet[1453];
+ /* Browse data packet */
+
+
+ snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\"\n",
+ p->type | CUPS_PRINTER_REMOTE, p->state, p->uri,
+ p->location, p->info, p->make_model);
+
+ bytes = strlen(packet);
+ LogMessage(L_DEBUG2, "SendBrowseList: (%d bytes) %s", bytes, packet);
+
+ /*
+ * Send a packet to each browse address...
+ */
+
+ for (i = 0; i < NumBrowsers; i ++)
+ if (sendto(BrowseSocket, packet, bytes, 0,
+ (struct sockaddr *)Browsers + i, sizeof(Browsers[0])) <= 0)
+ {
+ LogMessage(L_ERROR, "SendBrowseList: sendto failed for browser %d - %s.",
+ i + 1, strerror(errno));
+ LogMessage(L_ERROR, "Browsing turned off.");
+
+ StopBrowsing();
+ Browsing = 0;
+ return;
+ }
+}
+
+
+/*
+ * 'StartBrowsing()' - Start sending and receiving broadcast information.
+ */
+
+void
+StartBrowsing(void)
+{
+ int val; /* Socket option value */
+ struct sockaddr_in addr; /* Broadcast address */
+
+
+ if (!Browsing)
+ return;
+
+ if (BrowseProtocols & BROWSE_CUPS)
+ {
+ /*
+ * Create the broadcast socket...
+ */
+
+ if ((BrowseSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ {
+ LogMessage(L_ERROR, "StartBrowsing: Unable to create broadcast socket - %s.",
+ strerror(errno));
+ Browsing = 0;
+ return;
+ }
+
+ /*
+ * Set the "broadcast" flag...
+ */
+
+ val = 1;
+ if (setsockopt(BrowseSocket, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)))
+ {
+ LogMessage(L_ERROR, "StartBrowsing: Unable to set broadcast mode - %s.",
+ strerror(errno));
+
+#ifdef WIN32
+ closesocket(BrowseSocket);
+#else
+ close(BrowseSocket);
+#endif /* WIN32 */
+
+ BrowseSocket = -1;
+ Browsing = 0;
+ return;
+ }
+
+ /*
+ * Bind the socket to browse port...
+ */
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(BrowsePort);
+
+ if (bind(BrowseSocket, (struct sockaddr *)&addr, sizeof(addr)))
+ {
+ LogMessage(L_ERROR, "StartBrowsing: Unable to bind broadcast socket - %s.",
+ strerror(errno));
+
+#ifdef WIN32
+ closesocket(BrowseSocket);
+#else
+ close(BrowseSocket);
+#endif /* WIN32 */
+
+ BrowseSocket = -1;
+ Browsing = 0;
+ return;
+ }
+
+ /*
+ * Finally, add the socket to the input selection set...
+ */
+
+ LogMessage(L_DEBUG2, "StartBrowsing: Adding fd %d to InputSet...",
+ BrowseSocket);
+
+ FD_SET(BrowseSocket, &InputSet);
+ }
+
+#ifdef HAVE_LIBSLP
+ if (BrowseProtocols & BROWSE_SLP)
+ {
+ /*
+ * Open SLP handle...
+ */
+
+ if (SLPOpen("en", SLP_FALSE, &BrowseSLPHandle) != SLP_OK)
+ {
+ LogMessage(L_ERROR, "Unable to open an SLP handle; disabling SLP browsing!");
+ BrowseProtocols &= ~BROWSE_SLP;
+ }
+
+ BrowseSLPRefresh = 0;
+ }
+#endif /* HAVE_LIBSLP */
+}
+
+
+/*
+ * 'StartPolling()' - Start polling servers as needed.
+ */
+
+void
+StartPolling(void)
+{
+ int i; /* Looping var */
+ dirsvc_poll_t *poll; /* Current polling server */
+ int pid; /* New process ID */
+ char sport[10]; /* Server port */
+ char bport[10]; /* Browser port */
+ char interval[10]; /* Poll interval */
+ int statusfds[2]; /* Status pipe */
+ int fd; /* Current file descriptor */
+
+
+ /*
+ * Don't do anything if we aren't polling...
+ */
+
+ if (NumPolled == 0)
+ {
+ PollPipe = -1;
+ return;
+ }
+
+ /*
+ * Setup string arguments for port and interval options.
+ */
+
+ sprintf(bport, "%d", BrowsePort);
+
+ if (BrowseInterval)
+ sprintf(interval, "%d", BrowseInterval);
+ else
+ strcpy(interval, "30");
+
+ /*
+ * Create a pipe that receives the status messages from each
+ * polling daemon...
+ */
+
+ if (pipe(statusfds))
+ {
+ LogMessage(L_ERROR, "Unable to create polling status pipes - %s.",
+ strerror(errno));
+ PollPipe = -1;
+ return;
+ }
+
+ PollPipe = statusfds[0];
+
+ /*
+ * Run each polling daemon, redirecting stderr to the polling pipe...
+ */
+
+ for (i = 0, poll = Polled; i < NumPolled; i ++, poll ++)
+ {
+ sprintf(sport, "%d", poll->port);
+
+ if ((pid = fork()) == 0)
+ {
+ /*
+ * Child...
+ */
+
+ if (getuid() == 0)
+ {
+ /*
+ * Running as root, so change to non-priviledged user...
+ */
+
+ if (setgid(Group))
+ exit(errno);
+
+ if (setuid(User))
+ exit(errno);
+ }
+
+ /*
+ * Reset group membership to just the main one we belong to.
+ */
+
+ setgroups(0, NULL);
+
+ /*
+ * Redirect stdin and stdout to /dev/null, and stderr to the
+ * status pipe. Close all other files.
+ */
+
+ close(0);
+ open("/dev/null", O_RDONLY);
+
+ close(1);
+ open("/dev/null", O_WRONLY);
+
+ close(2);
+ dup(statusfds[1]);
+
+ for (fd = 3; fd < MaxFDs; fd ++)
+ close(fd);
+
+ /*
+ * Execute the polling daemon...
+ */
+
+ execl(CUPS_SERVERBIN "/daemon/cups-polld", "cups-polld", poll->hostname,
+ sport, interval, bport, NULL);
+ exit(errno);
+ }
+ else if (pid < 0)
+ {
+ LogMessage(L_ERROR, "StartPolling: Unable to fork polling daemon - %s",
+ strerror(errno));
+ poll->pid = 0;
+ break;
+ }
+ else
+ {
+ poll->pid = pid;
+ LogMessage(L_DEBUG, "StartPolling: Started polling daemon for %s:%d, pid = %d",
+ poll->hostname, poll->port, pid);
+ }
+ }
+
+ close(statusfds[1]);
+
+ /*
+ * Finally, add the pipe to the input selection set...
+ */
+
+ LogMessage(L_DEBUG2, "StartPolling: Adding fd %d to InputSet...",
+ PollPipe);
+
+ FD_SET(PollPipe, &InputSet);
+}
+
+
+/*
+ * 'StopBrowsing()' - Stop sending and receiving broadcast information.
+ */
+
+void
+StopBrowsing(void)
+{
+ if (!Browsing)
+ return;
+
+ if (BrowseProtocols & BROWSE_CUPS)
+ {
+ /*
+ * Close the socket and remove it from the input selection set.
+ */
+
+ if (BrowseSocket >= 0)
+ {
+#ifdef WIN32
+ closesocket(BrowseSocket);
+#else
+ close(BrowseSocket);
+#endif /* WIN32 */
+
+ LogMessage(L_DEBUG2, "StopBrowsing: Removing fd %d from InputSet...",
+ BrowseSocket);
+
+ FD_CLR(BrowseSocket, &InputSet);
+ BrowseSocket = 0;
+ }
+ }
+
+#ifdef HAVE_LIBSLP
+ if (BrowseProtocols & BROWSE_SLP)
+ {
+ /*
+ * Close SLP handle...
+ */
+
+ SLPClose(BrowseSLPHandle);
+ }
+#endif /* HAVE_LIBSLP */
+}
+
+
+/*
+ * 'StopPolling()' - Stop polling servers as needed.
+ */
+
+void
+StopPolling(void)
+{
+ int i; /* Looping var */
+ dirsvc_poll_t *poll; /* Current polling server */
+
+
+ if (PollPipe)
+ {
+ close(PollPipe);
+
+ LogMessage(L_DEBUG2, "StopPolling: removing fd %d from InputSet.",
+ PollPipe);
+ FD_CLR(PollPipe, &InputSet);
+
+ PollPipe = -1;
+ }
+
+ for (i = 0, poll = Polled; i < NumPolled; i ++, poll ++)
+ if (poll->pid)
+ kill(poll->pid, SIGTERM);
+}
+
+
+/*
+ * 'UpdateCUPSBrowse()' - Update the browse lists using the CUPS protocol.
+ */
+
+void
+UpdateCUPSBrowse(void)
+{
+ int i; /* Looping var */
+ int auth; /* Authorization status */
+ int len; /* Length of name string */
+ int bytes; /* Number of bytes left */
+ char packet[1540], /* Broadcast packet */
+ *pptr; /* Pointer into packet */
+ struct sockaddr_in srcaddr; /* Source address */
+ char srcname[1024]; /* Source hostname */
+ unsigned address; /* Source address (host order) */
+ struct hostent *srchost; /* Host entry for source address */
+ cups_ptype_t type; /* Printer type */
+ ipp_pstate_t state; /* Printer state */
+ char uri[HTTP_MAX_URI], /* Printer URI */
+ method[HTTP_MAX_URI], /* Method portion of URI */
+ username[HTTP_MAX_URI], /* Username portion of URI */
+ host[HTTP_MAX_URI], /* Host portion of URI */
+ resource[HTTP_MAX_URI], /* Resource portion of URI */
+ info[IPP_MAX_NAME], /* Information string */
+ location[IPP_MAX_NAME], /* Location string */
+ make_model[IPP_MAX_NAME];/* Make and model string */
+ int port; /* Port portion of URI */
+
+
+ /*
+ * Read a packet from the browse socket...
+ */
+
+ len = sizeof(srcaddr);
+ if ((bytes = recvfrom(BrowseSocket, packet, sizeof(packet), 0,
+ (struct sockaddr *)&srcaddr, &len)) <= 0)
+ {
+ /*
+ * "Connection refused" is returned under Linux if the destination port
+ * or address is unreachable from a previous sendto(); check for the
+ * error here and ignore it for now...
+ */
+
+ if (errno != ECONNREFUSED)
+ {
+ LogMessage(L_ERROR, "Browse recv failed - %s.", strerror(errno));
+ LogMessage(L_ERROR, "Browsing turned off.");
+
+ StopBrowsing();
+ Browsing = 0;
+ }
+
+ return;
+ }
+
+ packet[bytes] = '\0';
+
+ /*
+ * Figure out where it came from...
+ */
+
+ address = ntohl(srcaddr.sin_addr.s_addr);
+
+ if (HostNameLookups)
+#ifndef __sgi
+ srchost = gethostbyaddr((char *)&(srcaddr.sin_addr), sizeof(struct in_addr),
+ AF_INET);
+#else
+ srchost = gethostbyaddr(&(srcaddr.sin_addr), sizeof(struct in_addr),
+ AF_INET);
+#endif /* !__sgi */
+ else
+ srchost = NULL;
+
+ if (srchost == NULL)
+ sprintf(srcname, "%d.%d.%d.%d", address >> 24, (address >> 16) & 255,
+ (address >> 8) & 255, address & 255);
+ else
+ {
+ strncpy(srcname, srchost->h_name, sizeof(srcname) - 1);
+ srcname[sizeof(srcname) - 1] = '\0';
+ }
+
+ len = strlen(srcname);
+
+ /*
+ * Do ACL stuff...
+ */
+
+ if (BrowseACL && (BrowseACL->num_allow || BrowseACL->num_deny))
+ {
+ if (address == 0x7f000001 || strcasecmp(srcname, "localhost") == 0)
+ {
+ /*
+ * Access from localhost (127.0.0.1) is always allowed...
+ */
+
+ auth = AUTH_ALLOW;
+ }
+ else
+ {
+ /*
+ * Do authorization checks on the domain/address...
+ */
+
+ switch (BrowseACL->order_type)
+ {
+ default :
+ auth = AUTH_DENY; /* anti-compiler-warning-code */
+ break;
+
+ case AUTH_ALLOW : /* Order Deny,Allow */
+ auth = AUTH_ALLOW;
+
+ if (CheckAuth(address, srcname, len,
+ BrowseACL->num_deny, BrowseACL->deny))
+ auth = AUTH_DENY;
+
+ if (CheckAuth(address, srcname, len,
+ BrowseACL->num_allow, BrowseACL->allow))
+ auth = AUTH_ALLOW;
+ break;
+
+ case AUTH_DENY : /* Order Allow,Deny */
+ auth = AUTH_DENY;
+
+ if (CheckAuth(address, srcname, len,
+ BrowseACL->num_allow, BrowseACL->allow))
+ auth = AUTH_ALLOW;
+
+ if (CheckAuth(address, srcname, len,
+ BrowseACL->num_deny, BrowseACL->deny))
+ auth = AUTH_DENY;
+ break;
+ }
+ }
+ }
+ else
+ auth = AUTH_ALLOW;
+
+ if (auth == AUTH_DENY)
+ {
+ LogMessage(L_DEBUG, "UpdateBrowseList: Refused %d bytes from %s", bytes,
+ srcname);
+ return;
+ }
+
+ LogMessage(L_DEBUG2, "UpdateBrowseList: (%d bytes from %s) %s", bytes, srcname,
+ packet);
+
+ /*
+ * Parse packet...
+ */
+
+ if (sscanf(packet, "%x%x%1023s", (unsigned *)&type, (unsigned *)&state,
+ uri) < 3)
+ {
+ LogMessage(L_WARN, "UpdateBrowseList: Garbled browse packet - %s",
+ packet);
+ return;
+ }
+
+ strcpy(location, "Location Unknown");
+ strcpy(info, "No Information Available");
+ make_model[0] = '\0';
+
+ if ((pptr = strchr(packet, '\"')) != NULL)
+ {
+ /*
+ * Have extended information; can't use sscanf for it because not all
+ * sscanf's allow empty strings with %[^\"]...
+ */
+
+ for (i = 0, pptr ++;
+ i < (sizeof(location) - 1) && *pptr && *pptr != '\"';
+ i ++, pptr ++)
+ location[i] = *pptr;
+
+ if (i)
+ location[i] = '\0';
+
+ if (*pptr == '\"')
+ pptr ++;
+
+ while (*pptr && isspace(*pptr))
+ pptr ++;
+
+ if (*pptr == '\"')
+ {
+ for (i = 0, pptr ++;
+ i < (sizeof(info) - 1) && *pptr && *pptr != '\"';
+ i ++, pptr ++)
+ info[i] = *pptr;
+
+ if (i)
+ info[i] = '\0';
+
+ if (*pptr == '\"')
+ pptr ++;
+
+ while (*pptr && isspace(*pptr))
+ pptr ++;
+
+ if (*pptr == '\"')
+ {
+ for (i = 0, pptr ++;
+ i < (sizeof(make_model) - 1) && *pptr && *pptr != '\"';
+ i ++, pptr ++)
+ make_model[i] = *pptr;
+
+ if (i)
+ make_model[i] = '\0';
+ }
+ }
+ }
+
+ DEBUG_puts(packet);
+ DEBUG_printf(("type=%x, state=%x, uri=\"%s\"\n"
+ "location=\"%s\", info=\"%s\", make_model=\"%s\"\n",
+ type, state, uri, location, info, make_model));
+
+ /*
+ * Pull the URI apart to see if this is a local or remote printer...
+ */
+
+ httpSeparate(uri, method, username, host, &port, resource);
+
+ DEBUG_printf(("host=\"%s\", ServerName=\"%s\"\n", host, ServerName));
+
+ if (strcasecmp(host, ServerName) == 0)
+ return;
+
+ /*
+ * Do relaying...
+ */
+
+ for (i = 0; i < NumRelays; i ++)
+ if (CheckAuth(address, srcname, len, 1, &(Relays[i].from)))
+ if (sendto(BrowseSocket, packet, bytes, 0,
+ (struct sockaddr *)&(Relays[i].to),
+ sizeof(struct sockaddr_in)) <= 0)
+ {
+ LogMessage(L_ERROR, "UpdateBrowseList: sendto failed for relay %d - %s.",
+ i + 1, strerror(errno));
+ return;
+ }
+
+ /*
+ * Process the browse data...
+ */
+
+ ProcessBrowseData(uri, type, state, location, info, make_model);
+}
+
+
+/*
+ * 'UpdatePolling()' - Read status messages from the poll daemons.
+ */
+
+void
+UpdatePolling(void)
+{
+ int bytes; /* Number of bytes read */
+ char *lineptr; /* Pointer to end of line in buffer */
+ static int bufused = 0; /* Number of bytes used in buffer */
+ static char buffer[1024]; /* Status buffer */
+
+
+ if ((bytes = read(PollPipe, buffer + bufused,
+ sizeof(buffer) - bufused - 1)) > 0)
+ {
+ bufused += bytes;
+ buffer[bufused] = '\0';
+ lineptr = strchr(buffer, '\n');
+ }
+ else if (bytes < 0 && errno == EINTR)
+ return;
+ else
+ {
+ lineptr = buffer + bufused;
+ lineptr[1] = 0;
+ }
+
+ if (bytes == 0 && bufused == 0)
+ lineptr = NULL;
+
+ while (lineptr != NULL)
+ {
+ /*
+ * Terminate each line and process it...
+ */
+
+ *lineptr++ = '\0';
+
+ LogMessage(L_ERROR, "%s", buffer);
+
+ /*
+ * Copy over the buffer data we've used up...
+ */
+
+ strcpy(buffer, lineptr);
+ bufused -= lineptr - buffer;
+
+ if (bufused < 0)
+ bufused = 0;
+
+ lineptr = strchr(buffer, '\n');
+ }
+
+ if (bytes <= 0)
+ {
+ /*
+ * All polling processes have died; stop polling...
+ */
+
+ LogMessage(L_ERROR, "UpdatePolling: all polling processes have exited!");
+ StopPolling();
+ }
+}
+
+
+/***********************************************************************
+ **** SLP Support Code *************************************************
+ ***********************************************************************/
+
+#ifdef HAVE_LIBSLP
+/*
+ * SLP service name for CUPS...
+ */
+
+# define SLP_CUPS_SRVTYPE "service:printer"
+# define SLP_CUPS_SRVLEN 15
+
+
+/*
+ * Printer service URL structure
+ */
+
+typedef struct _slpsrvurl
+{
+ struct _slpsrvurl *next;
+ char url[HTTP_MAX_URI];
+} slpsrvurl_t;
+
+
+/*
+ * 'RegReportCallback()' - Empty SLPRegReport.
+ */
+
+void
+RegReportCallback(SLPHandle hslp,
+ SLPError errcode,
+ void *cookie)
+{
+ (void)hslp;
+ (void)errcode;
+ (void)cookie;
+
+ return;
+}
+
+
+/*
+ * 'SendSLPBrowse()' - Register the specified printer with SLP.
+ */
+
+void
+SendSLPBrowse(printer_t *p) /* I - Printer to register */
+{
+ char srvurl[HTTP_MAX_URI], /* Printer service URI */
+ attrs[8192], /* Printer attributes */
+ finishings[1024], /* Finishings to support */
+ make_model[IPP_MAX_NAME * 2],
+ /* Make and model, quoted */
+ location[IPP_MAX_NAME * 2],
+ /* Location, quoted */
+ info[IPP_MAX_NAME * 2],
+ /* Info, quoted */
+ *src, /* Pointer to original string */
+ *dst; /* Pointer to destination string */
+ ipp_attribute_t *authentication; /* uri-authentication-supported value */
+ SLPError error; /* SLP error, if any */
+
+
+ LogMessage(L_DEBUG, "SendSLPBrowse(%p = \"%s\")", p, p->name);
+
+ /*
+ * Make the SLP service URL that conforms to the IANA
+ * 'printer:' template.
+ */
+
+ snprintf(srvurl, sizeof(srvurl), SLP_CUPS_SRVTYPE ":%s", p->uri);
+
+ LogMessage(L_DEBUG2, "Service URL = \"%s\"", srvurl);
+
+ /*
+ * Figure out the finishings string...
+ */
+
+ if (p->type & CUPS_PRINTER_STAPLE)
+ strcpy(finishings, "staple");
+ else
+ finishings[0] = '\0';
+
+ if (p->type & CUPS_PRINTER_BIND)
+ {
+ if (finishings[0])
+ strncat(finishings, ",bind", sizeof(finishings) - 1);
+ else
+ strcpy(finishings, "bind");
+ }
+
+ if (p->type & CUPS_PRINTER_PUNCH)
+ {
+ if (finishings[0])
+ strncat(finishings, ",punch", sizeof(finishings) - 1);
+ else
+ strcpy(finishings, "punch");
+ }
+
+ if (p->type & CUPS_PRINTER_COVER)
+ {
+ if (finishings[0])
+ strncat(finishings, ",cover", sizeof(finishings) - 1);
+ else
+ strcpy(finishings, "cover");
+ }
+
+ if (p->type & CUPS_PRINTER_SORT)
+ {
+ if (finishings[0])
+ strncat(finishings, ",sort", sizeof(finishings) - 1);
+ else
+ strcpy(finishings, "sort");
+ }
+
+ if (!finishings[0])
+ strcpy(finishings, "none");
+
+ finishings[sizeof(finishings) - 1] = '\0';
+
+ /*
+ * Quote any commas in the make and model, location, and info strings
+ * (local strings are twice the size of the ones in the printer_t
+ * structure, so no buffer overflow is possible...)
+ */
+
+ for (src = p->make_model, dst = make_model; *src;)
+ {
+ if (*src == ',' || *src == '\\' || *src == ')')
+ *dst++ = '\\';
+
+ *dst++ = *src++;
+ }
+
+ *dst = '\0';
+
+ if (!make_model[0])
+ strcpy(make_model, "Unknown");
+
+ for (src = p->location, dst = location; *src;)
+ {
+ if (*src == ',' || *src == '\\' || *src == ')')
+ *dst++ = '\\';
+
+ *dst++ = *src++;
+ }
+
+ *dst = '\0';
+
+ if (!location[0])
+ strcpy(location, "Unknown");
+
+ for (src = p->info, dst = info; *src;)
+ {
+ if (*src == ',' || *src == '\\' || *src == ')')
+ *dst++ = '\\';
+
+ *dst++ = *src++;
+ }
+
+ *dst = '\0';
+
+ if (!info[0])
+ strcpy(info, "Unknown");
+
+ /*
+ * Get the authentication value...
+ */
+
+ authentication = ippFindAttribute(p->attrs, "uri-authentication-supported",
+ IPP_TAG_KEYWORD);
+
+ /*
+ * Make the SLP attribute string list that conforms to
+ * the IANA 'printer:' template.
+ */
+
+ snprintf(attrs, sizeof(attrs),
+ "(printer-uri-supported=%s),"
+ "(uri-authentication-supported=%s>),"
+#ifdef HAVE_LIBSSL
+ "(uri-security-supported=tls>),"
+#else
+ "(uri-security-supported=none>),"
+#endif /* HAVE_LIBSSL */
+ "(printer-name=%s),"
+ "(printer-location=%s),"
+ "(printer-info=%s),"
+ "(printer-more-info=%s),"
+ "(printer-make-and-model=%s),"
+ "(charset-supported=utf-8),"
+ "(natural-language-configured=%s),"
+ "(natural-language-supported=de,en,es,fr,it),"
+ "(color-supported=%s),"
+ "(finishings-supported=%s),"
+ "(sides-supported=one-sided%s),"
+ "(multiple-document-jobs-supported=true)"
+ "(ipp-versions-supported=1.0,1.1)",
+ p->uri, authentication->values[0].string.text, p->name, location,
+ info, p->uri, make_model, DefaultLanguage,
+ p->type & CUPS_PRINTER_COLOR ? "true" : "false",
+ finishings,
+ p->type & CUPS_PRINTER_DUPLEX ?
+ ",two-sided-long-edge,two-sided-short-edge" : "");
+
+ LogMessage(L_DEBUG2, "Attributes = \"%s\"", attrs);
+
+ /*
+ * Register the printer with the SLP server...
+ */
+
+ error = SLPReg(BrowseSLPHandle, srvurl, BrowseTimeout,
+ SLP_CUPS_SRVTYPE, attrs, SLP_TRUE, RegReportCallback, 0);
+
+ if (error != SLP_OK)
+ LogMessage(L_ERROR, "SLPReg of \"%s\" failed with status %d!", p->name,
+ error);
+}
+
+
+/*
+ * 'SLPDeregPrinter()' - SLPDereg() the specified printer
+ */
+
+void
+SLPDeregPrinter(printer_t *p)
+{
+ char srvurl[HTTP_MAX_URI]; /* Printer service URI */
+
+
+ if((p->type & CUPS_PRINTER_REMOTE) == 0)
+ {
+ /*
+ * Make the SLP service URL that conforms to the IANA
+ * 'printer:' template.
+ */
+
+ snprintf(srvurl, sizeof(srvurl), SLP_CUPS_SRVTYPE ":%s", p->uri);
+
+ /*
+ * Deregister the printer...
+ */
+
+ SLPDereg(BrowseSLPHandle, srvurl, RegReportCallback, 0);
+ }
+}
+
+
+/*
+ * 'GetSlpAttrVal()' - Get an attribute from an SLP registration.
+ */
+
+int /* O - 0 on success */
+GetSlpAttrVal(const char *attrlist, /* I - Attribute list string */
+ const char *tag, /* I - Name of attribute */
+ char *valbuf, /* O - Value */
+ int valbuflen) /* I - Max length of value */
+{
+ char *ptr1, /* Pointer into string */
+ *ptr2; /* ... */
+
+
+ valbuf[0] = '\0';
+
+ if ((ptr1 = strstr(attrlist, tag)) != NULL)
+ {
+ ptr1 += strlen(tag);
+
+ if ((ptr2 = strchr(ptr1,')')) != NULL)
+ {
+ if (valbuflen > (ptr2 - ptr1))
+ {
+ /*
+ * Copy the value...
+ */
+
+ strncpy(valbuf, ptr1, ptr2 - ptr1);
+ valbuf[ptr2 - ptr1] = '\0';
+
+ /*
+ * Dequote the value...
+ */
+
+ for (ptr1 = valbuf; *ptr1; ptr1 ++)
+ if (*ptr1 == '\\' && ptr1[1])
+ strcpy(ptr1, ptr1 + 1);
+
+ return (0);
+ }
+ }
+ }
+
+ return (-1);
+}
+
+
+/*
+ * 'AttrCallback()' - SLP attribute callback
+ */
+
+SLPBoolean
+AttrCallback(SLPHandle hslp,
+ const char *attrlist,
+ SLPError errcode,
+ void *cookie)
+{
+ char tmp[IPP_MAX_NAME];
+ printer_t *p = (printer_t*)cookie;
+
+
+ /*
+ * Let the compiler know we won't be using these...
+ */
+
+ (void)hslp;
+
+ /*
+ * Bail if there was an error
+ */
+
+ if (errcode != SLP_OK)
+ return (SLP_TRUE);
+
+ /*
+ * Parse the attrlist to obtain things needed to build CUPS browse packet
+ */
+
+ memset(p, 0, sizeof(printer_t));
+
+ p->type = CUPS_PRINTER_REMOTE;
+
+ if (GetSlpAttrVal(attrlist, "(printer-location=", p->location,
+ sizeof(p->location)))
+ return (SLP_FALSE);
+ if (GetSlpAttrVal(attrlist, "(printer-make-and-model=", p->make_model,
+ sizeof(p->make_model)))
+ return (SLP_FALSE);
+
+ if (GetSlpAttrVal(attrlist, "(color-supported=", tmp, sizeof(tmp)))
+ return (SLP_FALSE);
+ if (strcasecmp(tmp, "true") == 0)
+ p->type |= CUPS_PRINTER_COLOR;
+
+ if (GetSlpAttrVal(attrlist, "(finishings-supported=", tmp, sizeof(tmp)))
+ return (SLP_FALSE);
+ if (strstr(tmp, "staple"))
+ p->type |= CUPS_PRINTER_STAPLE;
+ if (strstr(tmp, "bind"))
+ p->type |= CUPS_PRINTER_BIND;
+ if (strstr(tmp, "punch"))
+ p->type |= CUPS_PRINTER_PUNCH;
+
+ if (GetSlpAttrVal(attrlist, "(sides-supported=", tmp, sizeof(tmp)))
+ return (SLP_FALSE);
+ if (strstr(tmp,"two-sided"))
+ p->type |= CUPS_PRINTER_DUPLEX;
+
+ return (SLP_TRUE);
+}
+
+
+/*
+ * 'SrvUrlCallback()' - SLP service url callback
+ */
+
+SLPBoolean /* O - TRUE = OK, FALSE = error */
+SrvUrlCallback(SLPHandle hslp, /* I - SLP handle */
+ const char *srvurl, /* I - URL of service */
+ unsigned short lifetime, /* I - Life of service */
+ SLPError errcode, /* I - Existing error code */
+ void *cookie) /* I - Pointer to service list */
+{
+ slpsrvurl_t *s, /* New service entry */
+ **head; /* Pointer to head of entry */
+
+
+ /*
+ * Let the compiler know we won't be using these vars...
+ */
+
+ (void)hslp;
+ (void)lifetime;
+
+ /*
+ * Bail if there was an error
+ */
+
+ if (errcode != SLP_OK)
+ return (SLP_TRUE);
+
+ /*
+ * Grab the head of the list...
+ */
+
+ head = (slpsrvurl_t**)cookie;
+
+ /*
+ * Allocate a *temporary* slpsrvurl_t to hold this entry.
+ */
+
+ if ((s = (slpsrvurl_t *)calloc(1, sizeof(slpsrvurl_t))) == NULL)
+ return (SLP_FALSE);
+
+ /*
+ * Copy the SLP service URL...
+ */
+
+ strncpy(s->url, srvurl, sizeof(s->url));
+
+ /*
+ * Link the SLP service URL into the head of the list
+ */
+
+ if (*head)
+ s->next = *head;
+
+ *head = s;
+
+ return (SLP_TRUE);
+}
+
+
+/*
+ * 'UpdateSLPBrowse()' - Get browsing information via SLP.
+ */
+
+void
+UpdateSLPBrowse(void)
+{
+ slpsrvurl_t *s, /* Temporary list of service URLs */
+ *next; /* Next service in list */
+ printer_t p; /* Printer information */
+ const char *uri; /* Pointer to printer URI */
+ char method[HTTP_MAX_URI], /* Method portion of URI */
+ username[HTTP_MAX_URI], /* Username portion of URI */
+ host[HTTP_MAX_URI], /* Host portion of URI */
+ resource[HTTP_MAX_URI]; /* Resource portion of URI */
+ int port; /* Port portion of URI */
+
+
+ LogMessage(L_DEBUG, "UpdateSLPBrowse() Start...");
+
+ /*
+ * Reset the refresh time...
+ */
+
+ BrowseSLPRefresh = time(NULL) + BrowseTimeout - BrowseInterval;
+
+ /*
+ * Poll for remote printers using SLP...
+ */
+
+ s = NULL;
+
+ SLPFindSrvs(BrowseSLPHandle, SLP_CUPS_SRVTYPE, "", "",
+ SrvUrlCallback, &s);
+
+ /*
+ * Loop through the list of available printers...
+ */
+
+ for (; s; s = next)
+ {
+ /*
+ * Load a printer_t structure with the SLP service attributes...
+ */
+
+ SLPFindAttrs(BrowseSLPHandle, s->url, "", "", AttrCallback, &p);
+
+ /*
+ * Process this printer entry...
+ */
+
+ uri = s->url + SLP_CUPS_SRVLEN + 1;
+
+ if (strncmp(uri, "http://", 7) == 0 ||
+ strncmp(uri, "ipp://", 6) == 0)
+ {
+ /*
+ * Pull the URI apart to see if this is a local or remote printer...
+ */
+
+ httpSeparate(uri, method, username, host, &port, resource);
+
+ if (strcasecmp(host, ServerName) == 0)
+ continue;
+
+ /*
+ * OK, at least an IPP printer, see if it is a CUPS printer or
+ * class...
+ */
+
+ if (strstr(uri, "/printers/") != NULL)
+ ProcessBrowseData(uri, p.type, IPP_PRINTER_IDLE, p.location,
+ p.info, p.make_model);
+ else if (strstr(uri, "/classes/") != NULL)
+ ProcessBrowseData(uri, p.type | CUPS_PRINTER_CLASS, IPP_PRINTER_IDLE,
+ p.location, p.info, p.make_model);
+ }
+
+ /*
+ * Save the "next" pointer and free this listing...
+ */
+
+ next = s->next;
+ free(s);
+ }
+
+ LogMessage(L_DEBUG, "UpdateSLPBrowse() End...");
+}
+#endif /* HAVE_LIBSLP */
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/dirsvc.h b/scheduler/dirsvc.h
new file mode 100644
index 000000000..c8714b198
--- /dev/null
+++ b/scheduler/dirsvc.h
@@ -0,0 +1,132 @@
+/*
+ * "$Id$"
+ *
+ * Directory services definitions for the Common UNIX Printing System
+ * (CUPS) scheduler.
+ *
+ * Copyright 1997-2002 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 necessary headers...
+ */
+
+#ifdef HAVE_LIBSLP
+# include <slp.h>
+#endif /* HAVE_LIBSLP */
+
+
+/*
+ * Browse protocols...
+ */
+
+#define BROWSE_CUPS 1 /* CUPS */
+#define BROWSE_SLP 2 /* SLPv2 */
+#define BROWSE_LDAP 4 /* LDAP (not supported yet) */
+#define BROWSE_ALL 7 /* All protocols */
+
+
+/*
+ * Relay structure...
+ */
+
+typedef struct
+{
+ authmask_t from; /* Source address/name mask */
+ struct sockaddr_in to; /* Destination address */
+} dirsvc_relay_t;
+
+
+/*
+ * Polling structure...
+ */
+
+typedef struct
+{
+ char hostname[16]; /* Hostname (actually, IP address) */
+ int port; /* Port number */
+ int pid; /* Current poll server PID */
+} dirsvc_poll_t;
+
+
+/*
+ * Globals...
+ */
+
+VAR int Browsing VALUE(TRUE),
+ /* Whether or not browsing is enabled */
+ BrowseProtocols VALUE(BROWSE_ALL),
+ /* Protocols to support */
+ BrowseShortNames VALUE(TRUE),
+ /* Short names for remote printers? */
+ BrowseSocket VALUE(-1),
+ /* Socket for browsing */
+ BrowsePort VALUE(IPP_PORT),
+ /* Port number for broadcasts */
+ BrowseInterval VALUE(DEFAULT_INTERVAL),
+ /* Broadcast interval in seconds */
+ BrowseTimeout VALUE(DEFAULT_TIMEOUT),
+ /* Time out for printers in seconds */
+ NumBrowsers VALUE(0);
+ /* Number of broadcast addresses */
+VAR struct sockaddr_in Browsers[MAX_BROWSERS];
+ /* Broadcast addresses */
+VAR location_t *BrowseACL VALUE(NULL);
+ /* Browser access control list */
+VAR int NumRelays VALUE(0);
+ /* Number of broadcast relays */
+VAR dirsvc_relay_t Relays[MAX_BROWSERS];
+ /* Broadcast relays */
+VAR int NumPolled VALUE(0);
+ /* Number of polled servers */
+VAR dirsvc_poll_t Polled[MAX_BROWSERS];
+ /* Polled servers */
+VAR int PollPipe VALUE(0);
+ /* Status pipe for pollers */
+
+#ifdef HAVE_LIBSLP
+VAR SLPHandle BrowseSLPHandle VALUE(NULL);
+ /* SLP API handle */
+VAR time_t BrowseSLPRefresh VALUE(0);
+ /* Next SLP refresh time */
+#endif /* HAVE_LIBSLP */
+
+
+/*
+ * Prototypes...
+ */
+
+extern void ProcessBrowseData(const char *uri, cups_ptype_t type,
+ ipp_pstate_t state, const char *location,
+ const char *info, const char *make_model);
+extern void SendBrowseList(void);
+extern void SendCUPSBrowse(printer_t *p);
+extern void SendSLPBrowse(printer_t *p);
+extern void StartBrowsing(void);
+extern void StartPolling(void);
+extern void StopBrowsing(void);
+extern void StopPolling(void);
+extern void UpdateCUPSBrowse(void);
+extern void UpdatePolling(void);
+extern void UpdateSLPBrowse(void);
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/filter.c b/scheduler/filter.c
new file mode 100644
index 000000000..3efee0fbd
--- /dev/null
+++ b/scheduler/filter.c
@@ -0,0 +1,301 @@
+/*
+ * "$Id$"
+ *
+ * File type conversion routines for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Easy Software Products and are protected by Federal
+ * copyright law. Distribution and use rights are outlined in the file
+ * "LICENSE.txt" which should have been included with this file. If this
+ * file is missing or damaged please contact Easy Software Products
+ * at:
+ *
+ * Attn: CUPS Licensing Information
+ * Easy Software Products
+ * 44141 Airport View Drive, Suite 204
+ * Hollywood, Maryland 20636-3111 USA
+ *
+ * Voice: (301) 373-9603
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * Contents:
+ *
+ * mimeAddFilter() - Add a filter to the current MIME database.
+ * mimeFilter() - Find the fastest way to convert from one type to another.
+ * compare() - Compare two filter types...
+ * lookup() - Lookup a filter...
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include <cups/string.h>
+#include "mime.h"
+
+
+/*
+ * Local functions...
+ */
+
+static int compare(mime_filter_t *, mime_filter_t *);
+static mime_filter_t *lookup(mime_t *, mime_type_t *, mime_type_t *);
+
+
+/*
+ * 'mimeAddFilter()' - Add a filter to the current MIME database.
+ */
+
+mime_filter_t * /* O - New filter */
+mimeAddFilter(mime_t *mime, /* I - MIME database */
+ mime_type_t *src, /* I - Source type */
+ mime_type_t *dst, /* I - Destination type */
+ int cost, /* I - Relative time/resource cost */
+ const char *filter) /* I - Filter program to run */
+{
+ mime_filter_t *temp; /* New filter */
+
+
+ /*
+ * Range-check the input...
+ */
+
+ if (mime == NULL || src == NULL || dst == NULL || filter == NULL)
+ return (NULL);
+
+ if (strlen(filter) > (MIME_MAX_FILTER - 1))
+ return (NULL);
+
+ /*
+ * See if we already have an existing filter for the given source and
+ * destination...
+ */
+
+ if ((temp = lookup(mime, src, dst)) != NULL)
+ {
+ /*
+ * Yup, does the existing filter have a higher cost? If so, copy the
+ * filter and cost to the existing filter entry and return it...
+ */
+
+ if (temp->cost > cost)
+ {
+ temp->cost = cost;
+ strncpy(temp->filter, filter, sizeof(temp->filter) - 1);
+ temp->filter[sizeof(temp->filter) - 1] = '\0';
+ }
+ }
+ else
+ {
+ /*
+ * Nope, add a new one...
+ */
+
+ if (mime->num_filters == 0)
+ temp = malloc(sizeof(mime_filter_t));
+ else
+ temp = realloc(mime->filters, sizeof(mime_filter_t) * (mime->num_filters + 1));
+
+ if (temp == NULL)
+ return (NULL);
+
+ mime->filters = temp;
+ temp += mime->num_filters;
+ mime->num_filters ++;
+
+ /*
+ * Copy the information over and sort if necessary...
+ */
+
+ temp->src = src;
+ temp->dst = dst;
+ temp->cost = cost;
+ strncpy(temp->filter, filter, sizeof(temp->filter) - 1);
+ temp->filter[sizeof(temp->filter) - 1] = '\0';
+
+ if (mime->num_filters > 1)
+ qsort(mime->filters, mime->num_filters, sizeof(mime_filter_t),
+ (int (*)(const void *, const void *))compare);
+ }
+
+ /*
+ * Return the new/updated filter...
+ */
+
+ return (temp);
+}
+
+
+/*
+ * 'mimeFilter()' - Find the fastest way to convert from one type to another.
+ */
+
+mime_filter_t * /* O - Array of filters to run */
+mimeFilter(mime_t *mime, /* I - MIME database */
+ mime_type_t *src, /* I - Source file type */
+ mime_type_t *dst, /* I - Destination file type */
+ int *num_filters) /* O - Number of filters to run */
+{
+ int i, j, /* Looping vars */
+ num_temp, /* Number of temporary filters */
+ num_mintemp, /* Number of filters in the minimum */
+ cost, /* Current cost */
+ mincost; /* Current minimum */
+ mime_filter_t *temp, /* Temporary filter */
+ *mintemp, /* Current minimum */
+ *mincurrent, /* Current filter for minimum */
+ *current, /* Current filter */
+ *filters; /* Filters to use */
+
+
+ /*
+ * Range-check the input...
+ */
+
+ if (mime == NULL || src == NULL || dst == NULL || num_filters == NULL)
+ return (NULL);
+
+ *num_filters = 0;
+
+ /*
+ * See if there is a filter that can convert the files directly...
+ */
+
+ if ((temp = lookup(mime, src, dst)) != NULL)
+ {
+ /*
+ * Got a direct filter!
+ */
+
+ if ((filters = (mime_filter_t *)malloc(sizeof(mime_filter_t))) == NULL)
+ return (NULL);
+
+ memcpy(filters, temp, sizeof(mime_filter_t));
+ *num_filters = 1;
+ return (filters);
+ }
+
+ /*
+ * OK, now look for filters from the source type to any other type...
+ */
+
+ mincost = 9999999;
+ mintemp = NULL;
+ num_mintemp = 0;
+ mincurrent = NULL;
+
+ for (i = mime->num_filters, current = mime->filters; i > 0; i --, current ++)
+ if (current->src == src)
+ {
+ /*
+ * See if we have any filters that can convert from the destination type
+ * of this filter to the final type...
+ */
+
+ if ((temp = mimeFilter(mime, current->dst, dst, &num_temp)) == NULL)
+ continue;
+
+ /*
+ * Found a match; see if this one is less costly than the last (if
+ * any...)
+ */
+
+ for (j = 0, cost = 0; j < num_temp; j ++)
+ cost += temp->cost;
+
+ if (cost < mincost)
+ {
+ if (mintemp != NULL)
+ free(mintemp);
+
+ mincost = cost;
+ mintemp = temp;
+ num_mintemp = num_temp;
+ mincurrent = current;
+ }
+ else
+ free(temp);
+ }
+
+ if (mintemp != NULL)
+ {
+ /*
+ * Hey, we got a match! Add the current filter to the beginning of the
+ * filter list...
+ */
+
+ filters = (mime_filter_t *)realloc(mintemp, sizeof(mime_filter_t) *
+ (num_mintemp + 1));
+
+ if (filters == NULL)
+ {
+ *num_filters = 0;
+ return (NULL);
+ }
+
+ memmove(filters + 1, filters, num_mintemp * sizeof(mime_filter_t));
+ memcpy(filters, mincurrent, sizeof(mime_filter_t));
+
+ *num_filters = num_mintemp + 1;
+
+ return (filters);
+ }
+
+ return (NULL);
+}
+
+
+/*
+ * 'compare()' - Compare two filter types...
+ */
+
+static int /* O - Comparison result */
+compare(mime_filter_t *f0, /* I - First filter */
+ mime_filter_t *f1) /* I - Second filter */
+{
+ int i; /* Result of comparison */
+
+
+ if ((i = strcmp(f0->src->super, f1->src->super)) == 0)
+ if ((i = strcmp(f0->src->type, f1->src->type)) == 0)
+ if ((i = strcmp(f0->dst->super, f1->dst->super)) == 0)
+ i = strcmp(f0->dst->type, f1->dst->type);
+
+ return (i);
+}
+
+
+/*
+ * 'lookup()' - Lookup a filter...
+ */
+
+static mime_filter_t * /* O - Filter for src->dst */
+lookup(mime_t *mime, /* I - MIME database */
+ mime_type_t *src, /* I - Source type */
+ mime_type_t *dst) /* I - Destination type */
+{
+ mime_filter_t key; /* Key record for filter search */
+
+
+ if (mime->num_filters == 0)
+ return (NULL);
+
+ key.src = src;
+ key.dst = dst;
+
+ return ((mime_filter_t *)bsearch(&key, mime->filters, mime->num_filters,
+ sizeof(mime_filter_t),
+ (int (*)(const void *, const void *))compare));
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/ipp.c b/scheduler/ipp.c
new file mode 100644
index 000000000..4bf934293
--- /dev/null
+++ b/scheduler/ipp.c
@@ -0,0 +1,5643 @@
+/*
+ * "$Id$"
+ *
+ * IPP routines for the Common UNIX Printing System (CUPS) scheduler.
+ *
+ * Copyright 1997-2002 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:
+ *
+ * ProcessIPPRequest() - Process an incoming IPP request...
+ * accept_jobs() - Accept print jobs to a printer.
+ * add_class() - Add a class to the system.
+ * add_file() - Add a file to a job.
+ * add_job_state_reasons() - Add the "job-state-reasons" attribute based
+ * upon the job and printer state...
+ * add_printer() - Add a printer to the system.
+ * add_printer_state_reasons() - Add the "printer-state-reasons" attribute
+ * based upon the printer state...
+ * add_queued_job_count() - Add the "queued-job-count" attribute for
+ * cancel_all_jobs() - Cancel all print jobs.
+ * cancel_job() - Cancel a print job.
+ * check_quotas() - Check quotas for a printer and user.
+ * copy_attribute() - Copy a single attribute.
+ * copy_attrs() - Copy attributes from one request to another.
+ * create_job() - Print a file to a printer or class.
+ * copy_banner() - Copy a banner file to the requests directory
+ * for the specified job.
+ * copy_file() - Copy a PPD file or interface script...
+ * delete_printer() - Remove a printer or class from the system.
+ * get_default() - Get the default destination.
+ * get_devices() - Get the list of available devices on the
+ * local system.
+ * get_jobs() - Get a list of jobs for the specified printer.
+ * get_job_attrs() - Get job attributes.
+ * get_ppds() - Get the list of PPD files on the local
+ * system.
+ * get_printer_attrs() - Get printer attributes.
+ * get_printers() - Get a list of printers.
+ * hold_job() - Hold a print job.
+ * move_job() - Move a job to a new destination.
+ * print_job() - Print a file to a printer or class.
+ * reject_jobs() - Reject print jobs to a printer.
+ * release_job() - Release a held print job.
+ * restart_job() - Restart an old print job.
+ * send_document() - Send a file to a printer or class.
+ * send_ipp_error() - Send an error status back to the IPP client.
+ * set_default() - Set the default destination...
+ * set_job_attrs() - Set job attributes.
+ * start_printer() - Start a printer.
+ * stop_printer() - Stop a printer.
+ * validate_job() - Validate printer options and destination.
+ * validate_user() - Validate the user for the request.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cupsd.h"
+#include <pwd.h>
+#include <grp.h>
+#ifdef HAVE_LIBZ
+# include <zlib.h>
+#endif /* HAVE_LIBZ */
+
+
+/*
+ * Local functions...
+ */
+
+static void accept_jobs(client_t *con, ipp_attribute_t *uri);
+static void add_class(client_t *con, ipp_attribute_t *uri);
+static int add_file(client_t *con, job_t *job, mime_type_t *filetype);
+static void add_job_state_reasons(client_t *con, job_t *job);
+static void add_printer(client_t *con, ipp_attribute_t *uri);
+static void add_printer_state_reasons(client_t *con, printer_t *p);
+static void add_queued_job_count(client_t *con, printer_t *p);
+static void cancel_all_jobs(client_t *con, ipp_attribute_t *uri);
+static void cancel_job(client_t *con, ipp_attribute_t *uri);
+static int check_quotas(client_t *con, printer_t *p);
+static void copy_attribute(ipp_t *to, ipp_attribute_t *attr,
+ int quickcopy);
+static void copy_attrs(ipp_t *to, ipp_t *from, ipp_attribute_t *req,
+ ipp_tag_t group);
+static int copy_banner(client_t *con, job_t *job, const char *name);
+static int copy_file(const char *from, const char *to);
+static void create_job(client_t *con, ipp_attribute_t *uri);
+static void delete_printer(client_t *con, ipp_attribute_t *uri);
+static void get_default(client_t *con);
+static void get_devices(client_t *con);
+static void get_jobs(client_t *con, ipp_attribute_t *uri);
+static void get_job_attrs(client_t *con, ipp_attribute_t *uri);
+static void get_ppds(client_t *con);
+static void get_printers(client_t *con, int type);
+static void get_printer_attrs(client_t *con, ipp_attribute_t *uri);
+static void hold_job(client_t *con, ipp_attribute_t *uri);
+static void move_job(client_t *con, ipp_attribute_t *uri);
+static void print_job(client_t *con, ipp_attribute_t *uri);
+static void reject_jobs(client_t *con, ipp_attribute_t *uri);
+static void release_job(client_t *con, ipp_attribute_t *uri);
+static void restart_job(client_t *con, ipp_attribute_t *uri);
+static void send_document(client_t *con, ipp_attribute_t *uri);
+static void send_ipp_error(client_t *con, ipp_status_t status);
+static void set_default(client_t *con, ipp_attribute_t *uri);
+static void set_job_attrs(client_t *con, ipp_attribute_t *uri);
+static void start_printer(client_t *con, ipp_attribute_t *uri);
+static void stop_printer(client_t *con, ipp_attribute_t *uri);
+static void validate_job(client_t *con, ipp_attribute_t *uri);
+static int validate_user(client_t *con, const char *owner, char *username,
+ int userlen);
+
+
+/*
+ * 'ProcessIPPRequest()' - Process an incoming IPP request...
+ */
+
+void
+ProcessIPPRequest(client_t *con) /* I - Client connection */
+{
+ ipp_tag_t group; /* Current group tag */
+ ipp_attribute_t *attr; /* Current attribute */
+ ipp_attribute_t *charset; /* Character set attribute */
+ ipp_attribute_t *language; /* Language attribute */
+ ipp_attribute_t *uri; /* Printer URI attribute */
+ ipp_attribute_t *username; /* requesting-user-name attr */
+
+
+ LogMessage(L_DEBUG2, "ProcessIPPRequest(%p[%d]): operation_id = %04x",
+ con, con->http.fd, con->request->request.op.operation_id);
+
+ /*
+ * First build an empty response message for this request...
+ */
+
+ con->response = ippNew();
+
+ con->response->request.status.version[0] = con->request->request.op.version[0];
+ con->response->request.status.version[1] = con->request->request.op.version[1];
+ con->response->request.status.request_id = con->request->request.op.request_id;
+
+ /*
+ * Then validate the request header and required attributes...
+ */
+
+ if (con->request->request.any.version[0] != 1)
+ {
+ /*
+ * Return an error, since we only support IPP 1.x.
+ */
+
+ LogMessage(L_ERROR, "ProcessIPPRequest: bad request version (%d.%d)!",
+ con->request->request.any.version[0],
+ con->request->request.any.version[1]);
+
+ send_ipp_error(con, IPP_VERSION_NOT_SUPPORTED);
+ }
+ else if (con->request->attrs == NULL)
+ {
+ LogMessage(L_ERROR, "ProcessIPPRequest: no attributes in request!");
+ send_ipp_error(con, IPP_BAD_REQUEST);
+ }
+ else
+ {
+ /*
+ * Make sure that the attributes are provided in the correct order and
+ * don't repeat groups...
+ */
+
+ for (attr = con->request->attrs, group = attr->group_tag;
+ attr != NULL;
+ attr = attr->next)
+ if (attr->group_tag < group)
+ {
+ /*
+ * Out of order; return an error...
+ */
+
+ LogMessage(L_ERROR, "ProcessIPPRequest: attribute groups are out of order!");
+ send_ipp_error(con, IPP_BAD_REQUEST);
+ break;
+ }
+ else
+ group = attr->group_tag;
+
+ if (attr == NULL)
+ {
+ /*
+ * Then make sure that the first three attributes are:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri/job-uri
+ */
+
+ attr = con->request->attrs;
+ if (attr != NULL && strcmp(attr->name, "attributes-charset") == 0 &&
+ attr->value_tag == IPP_TAG_CHARSET)
+ charset = attr;
+ else
+ charset = NULL;
+
+ if (attr)
+ attr = attr->next;
+ if (attr != NULL && strcmp(attr->name, "attributes-natural-language") == 0 &&
+ attr->value_tag == IPP_TAG_LANGUAGE)
+ language = attr;
+ else
+ language = NULL;
+
+ if ((attr = ippFindAttribute(con->request, "printer-uri", IPP_TAG_URI)) != NULL)
+ uri = attr;
+ else if ((attr = ippFindAttribute(con->request, "job-uri", IPP_TAG_URI)) != NULL)
+ uri = attr;
+ else
+ uri = NULL;
+
+ if (charset)
+ ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, charset->values[0].string.text);
+ else
+ ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, DefaultCharset);
+
+ if (language)
+ ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL,
+ language->values[0].string.text);
+ else
+ ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, DefaultLanguage);
+
+ if (charset == NULL || language == NULL ||
+ (uri == NULL &&
+ con->request->request.op.operation_id != CUPS_GET_DEFAULT &&
+ con->request->request.op.operation_id != CUPS_GET_PRINTERS &&
+ con->request->request.op.operation_id != CUPS_GET_CLASSES &&
+ con->request->request.op.operation_id != CUPS_GET_DEVICES &&
+ con->request->request.op.operation_id != CUPS_GET_PPDS))
+ {
+ /*
+ * Return an error, since attributes-charset,
+ * attributes-natural-language, and printer-uri/job-uri are required
+ * for all operations.
+ */
+
+ if (charset == NULL)
+ LogMessage(L_ERROR, "ProcessIPPRequest: missing attributes-charset attribute!");
+
+ if (language == NULL)
+ LogMessage(L_ERROR, "ProcessIPPRequest: missing attributes-natural-language attribute!");
+
+ if (uri == NULL)
+ LogMessage(L_ERROR, "ProcessIPPRequest: missing printer-uri or job-uri attribute!");
+
+ LogMessage(L_DEBUG, "Request attributes follow...");
+
+ for (attr = con->request->attrs; attr != NULL; attr = attr->next)
+ LogMessage(L_DEBUG, "attr \"%s\": group_tag = %x, value_tag = %x",
+ attr->name ? attr->name : "(null)", attr->group_tag,
+ attr->value_tag);
+
+ LogMessage(L_DEBUG, "End of attributes...");
+
+ send_ipp_error(con, IPP_BAD_REQUEST);
+ }
+ else
+ {
+ /*
+ * OK, all the checks pass so far; make sure requesting-user-name is
+ * not "root" from a remote host...
+ */
+
+ if ((username = ippFindAttribute(con->request, "requesting-user-name", IPP_TAG_NAME)) != NULL)
+ {
+ /*
+ * Check for root user...
+ */
+
+ if (strcmp(username->values[0].string.text, "root") == 0 &&
+ ntohl(con->http.hostaddr.sin_addr.s_addr) != 0x7f000001 &&
+ strcmp(con->username, "root") != 0)
+ {
+ /*
+ * Remote unauthenticated user masquerading as local root...
+ */
+
+ free(username->values[0].string.text);
+ username->values[0].string.text = strdup(RemoteRoot);
+ }
+ }
+
+ /*
+ * Then try processing the operation...
+ */
+
+ switch (con->request->request.op.operation_id)
+ {
+ case IPP_PRINT_JOB :
+ print_job(con, uri);
+ break;
+
+ case IPP_VALIDATE_JOB :
+ validate_job(con, uri);
+ break;
+
+ case IPP_CREATE_JOB :
+ create_job(con, uri);
+ break;
+
+ case IPP_SEND_DOCUMENT :
+ send_document(con, uri);
+ break;
+
+ case IPP_CANCEL_JOB :
+ cancel_job(con, uri);
+ break;
+
+ case IPP_GET_JOB_ATTRIBUTES :
+ get_job_attrs(con, uri);
+ break;
+
+ case IPP_GET_JOBS :
+ get_jobs(con, uri);
+ break;
+
+ case IPP_GET_PRINTER_ATTRIBUTES :
+ get_printer_attrs(con, uri);
+ break;
+
+ case IPP_HOLD_JOB :
+ hold_job(con, uri);
+ break;
+
+ case IPP_RELEASE_JOB :
+ release_job(con, uri);
+ break;
+
+ case IPP_RESTART_JOB :
+ restart_job(con, uri);
+ break;
+
+ case IPP_PAUSE_PRINTER :
+ stop_printer(con, uri);
+ break;
+
+ case IPP_RESUME_PRINTER :
+ start_printer(con, uri);
+ break;
+
+ case IPP_PURGE_JOBS :
+ cancel_all_jobs(con, uri);
+ break;
+
+ case IPP_SET_JOB_ATTRIBUTES :
+ set_job_attrs(con, uri);
+ break;
+
+ case CUPS_GET_DEFAULT :
+ get_default(con);
+ break;
+
+ case CUPS_GET_PRINTERS :
+ get_printers(con, 0);
+ break;
+
+ case CUPS_GET_CLASSES :
+ get_printers(con, CUPS_PRINTER_CLASS);
+ break;
+
+ case CUPS_ADD_PRINTER :
+ add_printer(con, uri);
+ break;
+
+ case CUPS_DELETE_PRINTER :
+ delete_printer(con, uri);
+ break;
+
+ case CUPS_ADD_CLASS :
+ add_class(con, uri);
+ break;
+
+ case CUPS_DELETE_CLASS :
+ delete_printer(con, uri);
+ break;
+
+ case CUPS_ACCEPT_JOBS :
+ case IPP_ENABLE_PRINTER :
+ accept_jobs(con, uri);
+ break;
+
+ case CUPS_REJECT_JOBS :
+ case IPP_DISABLE_PRINTER :
+ reject_jobs(con, uri);
+ break;
+
+ case CUPS_SET_DEFAULT :
+ set_default(con, uri);
+ break;
+
+ case CUPS_GET_DEVICES :
+ get_devices(con);
+ break;
+
+ case CUPS_GET_PPDS :
+ get_ppds(con);
+ break;
+
+ case CUPS_MOVE_JOB :
+ move_job(con, uri);
+ break;
+
+ default :
+ send_ipp_error(con, IPP_OPERATION_NOT_SUPPORTED);
+ }
+ }
+ }
+ }
+
+ SendHeader(con, HTTP_OK, "application/ipp");
+
+ con->http.data_encoding = HTTP_ENCODE_LENGTH;
+ con->http.data_remaining = ippLength(con->response);
+
+ httpPrintf(HTTP(con), "Content-Length: %d\r\n\r\n",
+ con->http.data_remaining);
+
+ FD_SET(con->http.fd, &OutputSet);
+}
+
+
+/*
+ * 'accept_jobs()' - Accept print jobs to a printer.
+ */
+
+static void
+accept_jobs(client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Printer or class URI */
+{
+ cups_ptype_t dtype; /* Destination type (printer or class) */
+ char method[HTTP_MAX_URI],
+ /* Method portion of URI */
+ username[HTTP_MAX_URI],
+ /* Username portion of URI */
+ host[HTTP_MAX_URI],
+ /* Host portion of URI */
+ resource[HTTP_MAX_URI];
+ /* Resource portion of URI */
+ int port; /* Port portion of URI */
+ const char *name; /* Printer name */
+ printer_t *printer; /* Printer data */
+
+
+ LogMessage(L_DEBUG2, "accept_jobs(%p[%d], %s)\n", con, con->http.fd,
+ uri->values[0].string.text);
+
+ /*
+ * Was this operation called from the correct URI?
+ */
+
+ if (strncmp(con->uri, "/admin/", 7) != 0)
+ {
+ LogMessage(L_ERROR, "accept_jobs: admin request on bad resource \'%s\'!",
+ con->uri);
+ send_ipp_error(con, IPP_NOT_AUTHORIZED);
+ return;
+ }
+
+ /*
+ * Is the destination valid?
+ */
+
+ httpSeparate(uri->values[0].string.text, method, username, host, &port, resource);
+
+ if ((name = ValidateDest(host, resource, &dtype)) == NULL)
+ {
+ /*
+ * Bad URI...
+ */
+
+ LogMessage(L_ERROR, "accept_jobs: resource name \'%s\' no good!", resource);
+ send_ipp_error(con, IPP_NOT_FOUND);
+ return;
+ }
+
+ /*
+ * Accept jobs sent to the printer...
+ */
+
+ if (dtype == CUPS_PRINTER_CLASS)
+ printer = FindClass(name);
+ else
+ printer = FindPrinter(name);
+
+ printer->accepting = 1;
+ printer->state_message[0] = '\0';
+
+ if (dtype == CUPS_PRINTER_CLASS)
+ SaveAllClasses();
+ else
+ SaveAllPrinters();
+
+ LogMessage(L_INFO, "Printer \'%s\' now accepting jobs (\'%s\').", name,
+ con->username);
+
+ /*
+ * Everything was ok, so return OK status...
+ */
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'add_class()' - Add a class to the system.
+ */
+
+static void
+add_class(client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - URI of class */
+{
+ int i; /* Looping var */
+ char method[HTTP_MAX_URI],
+ /* Method portion of URI */
+ username[HTTP_MAX_URI],
+ /* Username portion of URI */
+ host[HTTP_MAX_URI],
+ /* Host portion of URI */
+ resource[HTTP_MAX_URI];
+ /* Resource portion of URI */
+ int port; /* Port portion of URI */
+ printer_t *pclass; /* Class */
+ cups_ptype_t dtype; /* Destination type */
+ const char *dest; /* Printer or class name */
+ ipp_attribute_t *attr; /* Printer attribute */
+ int modify; /* Non-zero if we just modified */
+
+
+ LogMessage(L_DEBUG2, "add_class(%p[%d], %s)\n", con, con->http.fd,
+ uri->values[0].string.text);
+
+ /*
+ * Was this operation called from the correct URI?
+ */
+
+ if (strncmp(con->uri, "/admin/", 7) != 0)
+ {
+ LogMessage(L_ERROR, "add_class: admin request on bad resource \'%s\'!",
+ con->uri);
+ send_ipp_error(con, IPP_NOT_AUTHORIZED);
+ return;
+ }
+
+ /*
+ * Do we have a valid URI?
+ */
+
+ httpSeparate(uri->values[0].string.text, method, username, host, &port, resource);
+
+ if (strncmp(resource, "/classes/", 9) != 0 || strlen(resource) == 9)
+ {
+ /*
+ * No, return an error...
+ */
+
+ send_ipp_error(con, IPP_BAD_REQUEST);
+ return;
+ }
+
+ /*
+ * See if the class already exists; if not, create a new class...
+ */
+
+ if ((pclass = FindClass(resource + 9)) == NULL)
+ {
+ /*
+ * Class doesn't exist; see if we have a printer of the same name...
+ */
+
+ if ((pclass = FindPrinter(resource + 9)) != NULL &&
+ !(pclass->type & CUPS_PRINTER_REMOTE))
+ {
+ /*
+ * Yes, return an error...
+ */
+
+ send_ipp_error(con, IPP_NOT_POSSIBLE);
+ return;
+ }
+
+ /*
+ * No, add the pclass...
+ */
+
+ pclass = AddClass(resource + 9);
+ modify = 0;
+ }
+ else if (pclass->type & CUPS_PRINTER_IMPLICIT)
+ {
+ /*
+ * Rename the implicit class to "AnyClass" or remove it...
+ */
+
+ if (ImplicitAnyClasses)
+ {
+ snprintf(pclass->name, sizeof(pclass->name), "Any%s", resource + 9);
+ SortPrinters();
+ }
+ else
+ DeletePrinter(pclass);
+
+ /*
+ * Add the class as a new local class...
+ */
+
+ pclass = AddClass(resource + 9);
+ modify = 0;
+ }
+ else if (pclass->type & CUPS_PRINTER_REMOTE)
+ {
+ /*
+ * Rename the remote class to "Class"...
+ */
+
+ DeletePrinterFilters(pclass);
+ snprintf(pclass->name, sizeof(pclass->name), "%s@%s", resource + 9,
+ pclass->hostname);
+ SetPrinterAttrs(pclass);
+ SortPrinters();
+
+ /*
+ * Add the class as a new local class...
+ */
+
+ pclass = AddClass(resource + 9);
+ modify = 0;
+ }
+ else
+ modify = 1;
+
+ /*
+ * Look for attributes and copy them over as needed...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "printer-location", IPP_TAG_TEXT)) != NULL)
+ {
+ strncpy(pclass->location, attr->values[0].string.text, sizeof(pclass->location) - 1);
+ pclass->location[sizeof(pclass->location) - 1] = '\0';
+ }
+
+ if ((attr = ippFindAttribute(con->request, "printer-info", IPP_TAG_TEXT)) != NULL)
+ {
+ strncpy(pclass->info, attr->values[0].string.text, sizeof(pclass->info) - 1);
+ pclass->info[sizeof(pclass->info) - 1] = '\0';
+ }
+
+ if ((attr = ippFindAttribute(con->request, "printer-is-accepting-jobs", IPP_TAG_BOOLEAN)) != NULL)
+ {
+ LogMessage(L_INFO, "Setting %s printer-is-accepting-jobs to %d (was %d.)",
+ pclass->name, attr->values[0].boolean, pclass->accepting);
+
+ pclass->accepting = attr->values[0].boolean;
+ }
+ if ((attr = ippFindAttribute(con->request, "printer-state", IPP_TAG_ENUM)) != NULL)
+ {
+ LogMessage(L_INFO, "Setting %s printer-state to %d (was %d.)", pclass->name,
+ attr->values[0].integer, pclass->state);
+
+ if (pclass->state == IPP_PRINTER_STOPPED &&
+ attr->values[0].integer != IPP_PRINTER_STOPPED)
+ pclass->state = IPP_PRINTER_IDLE;
+ else if (pclass->state != IPP_PRINTER_STOPPED &&
+ attr->values[0].integer == IPP_PRINTER_STOPPED)
+ {
+ if (pclass->state == IPP_PRINTER_PROCESSING)
+ StopJob(((job_t *)pclass->job)->id, 0);
+
+ pclass->state = IPP_PRINTER_STOPPED;
+ }
+
+ pclass->browse_time = 0;
+ }
+ if ((attr = ippFindAttribute(con->request, "printer-state-message", IPP_TAG_TEXT)) != NULL)
+ {
+ strncpy(pclass->state_message, attr->values[0].string.text,
+ sizeof(pclass->state_message) - 1);
+ pclass->state_message[sizeof(pclass->state_message) - 1] = '\0';
+ }
+ if ((attr = ippFindAttribute(con->request, "job-sheets-default", IPP_TAG_ZERO)) != NULL &&
+ !Classification[0])
+ {
+ strncpy(pclass->job_sheets[0], attr->values[0].string.text,
+ sizeof(pclass->job_sheets[0]) - 1);
+ if (attr->num_values > 1)
+ strncpy(pclass->job_sheets[1], attr->values[1].string.text,
+ sizeof(pclass->job_sheets[1]) - 1);
+ else
+ strcpy(pclass->job_sheets[1], "none");
+ }
+ if ((attr = ippFindAttribute(con->request, "requesting-user-name-allowed",
+ IPP_TAG_ZERO)) != NULL)
+ {
+ FreePrinterUsers(pclass);
+
+ pclass->deny_users = 0;
+ if (attr->value_tag == IPP_TAG_NAME &&
+ (attr->num_values > 1 ||
+ strcmp(attr->values[0].string.text, "all") != 0))
+ for (i = 0; i < attr->num_values; i ++)
+ AddPrinterUser(pclass, attr->values[i].string.text);
+ }
+ else if ((attr = ippFindAttribute(con->request, "requesting-user-name-denied",
+ IPP_TAG_ZERO)) != NULL)
+ {
+ FreePrinterUsers(pclass);
+
+ pclass->deny_users = 1;
+ if (attr->value_tag == IPP_TAG_NAME &&
+ (attr->num_values > 1 ||
+ strcmp(attr->values[0].string.text, "none") != 0))
+ for (i = 0; i < attr->num_values; i ++)
+ AddPrinterUser(pclass, attr->values[i].string.text);
+ }
+ if ((attr = ippFindAttribute(con->request, "job-quota-period",
+ IPP_TAG_INTEGER)) != NULL)
+ {
+ FreeQuotas(pclass);
+ pclass->quota_period = attr->values[0].integer;
+ }
+ if ((attr = ippFindAttribute(con->request, "job-k-limit",
+ IPP_TAG_INTEGER)) != NULL)
+ {
+ FreeQuotas(pclass);
+ pclass->k_limit = attr->values[0].integer;
+ }
+ if ((attr = ippFindAttribute(con->request, "job-page-limit",
+ IPP_TAG_INTEGER)) != NULL)
+ {
+ FreeQuotas(pclass);
+ pclass->page_limit = attr->values[0].integer;
+ }
+
+ if ((attr = ippFindAttribute(con->request, "member-uris", IPP_TAG_URI)) != NULL)
+ {
+ /*
+ * Clear the printer array as needed...
+ */
+
+ if (pclass->num_printers > 0)
+ {
+ free(pclass->printers);
+ pclass->num_printers = 0;
+ }
+
+ /*
+ * Add each printer or class that is listed...
+ */
+
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ /*
+ * Search for the printer or class URI...
+ */
+
+ httpSeparate(attr->values[i].string.text, method, username, host,
+ &port, resource);
+
+ if ((dest = ValidateDest(host, resource, &dtype)) == NULL)
+ {
+ /*
+ * Bad URI...
+ */
+
+ LogMessage(L_ERROR, "add_class: resource name \'%s\' no good!", resource);
+ send_ipp_error(con, IPP_NOT_FOUND);
+ return;
+ }
+
+ /*
+ * Add it to the class...
+ */
+
+ if (dtype == CUPS_PRINTER_CLASS)
+ {
+ AddPrinterToClass(pclass, FindClass(dest));
+
+ LogMessage(L_DEBUG, "add_class: Added class \"%s\" to class \"%s\"...",
+ dest, pclass->name);
+ }
+ else
+ {
+ AddPrinterToClass(pclass, FindPrinter(dest));
+
+ LogMessage(L_DEBUG, "add_class: Added printer \"%s\" to class \"%s\"...",
+ dest, pclass->name);
+ }
+ }
+ }
+
+ /*
+ * Update the printer class attributes and return...
+ */
+
+ SetPrinterAttrs(pclass);
+ SaveAllClasses();
+ CheckJobs();
+
+ if (modify)
+ LogMessage(L_INFO, "Class \'%s\' modified by \'%s\'.", pclass->name,
+ con->username);
+ else
+ LogMessage(L_INFO, "New class \'%s\' added by \'%s\'.", pclass->name,
+ con->username);
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'add_file()' - Add a file to a job.
+ */
+
+static int /* O - 0 on success, -1 on error */
+add_file(client_t *con, /* I - Connection to client */
+ job_t *job, /* I - Job to add to */
+ mime_type_t *filetype) /* I - Type of file */
+{
+ mime_type_t **filetypes; /* New filetypes array... */
+
+
+ LogMessage(L_DEBUG2, "add_file(%p[%d], %d, %s/%s)\n", con, con->http.fd,
+ job->id, filetype->super, filetype->type);
+
+ /*
+ * Add the file to the job...
+ */
+
+ if (job->num_files == 0)
+ filetypes = (mime_type_t **)malloc(sizeof(mime_type_t *));
+ else
+ filetypes = (mime_type_t **)realloc(job->filetypes,
+ (job->num_files + 1) *
+ sizeof(mime_type_t));
+
+ if (filetypes == NULL)
+ {
+ CancelJob(job->id, 1);
+ LogMessage(L_ERROR, "add_file: unable to allocate memory for file types!");
+ send_ipp_error(con, IPP_INTERNAL_ERROR);
+ return (-1);
+ }
+
+ job->filetypes = filetypes;
+ job->filetypes[job->num_files] = filetype;
+
+ job->num_files ++;
+
+ return (0);
+}
+
+
+/*
+ * 'add_job_state_reasons()' - Add the "job-state-reasons" attribute based
+ * upon the job and printer state...
+ */
+
+static void
+add_job_state_reasons(client_t *con, /* I - Client connection */
+ job_t *job) /* I - Job info */
+{
+ printer_t *dest; /* Destination printer */
+
+
+ LogMessage(L_DEBUG2, "add_job_state_reasons(%p[%d], %d)\n", con, con->http.fd,
+ job->id);
+
+ switch (job->state->values[0].integer)
+ {
+ case IPP_JOB_PENDING :
+ if (job->dtype & CUPS_PRINTER_CLASS)
+ dest = FindClass(job->dest);
+ else
+ dest = FindPrinter(job->dest);
+
+ if (dest != NULL && dest->state == IPP_PRINTER_STOPPED)
+ ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD,
+ "job-state-reasons", NULL, "printer-stopped");
+ else
+ ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD,
+ "job-state-reasons", NULL, "none");
+ break;
+
+ case IPP_JOB_HELD :
+ if (ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_KEYWORD) != NULL ||
+ ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME) != NULL)
+ ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD,
+ "job-state-reasons", NULL, "job-hold-until-specified");
+ else
+ ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD,
+ "job-state-reasons", NULL, "job-incoming");
+ break;
+
+ case IPP_JOB_PROCESSING :
+ ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD,
+ "job-state-reasons", NULL, "job-printing");
+ break;
+
+ case IPP_JOB_STOPPED :
+ ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD,
+ "job-state-reasons", NULL, "job-stopped");
+ break;
+
+ case IPP_JOB_CANCELLED :
+ ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD,
+ "job-state-reasons", NULL, "job-canceled-by-user");
+ break;
+
+ case IPP_JOB_ABORTED :
+ ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD,
+ "job-state-reasons", NULL, "aborted-by-system");
+ break;
+
+ case IPP_JOB_COMPLETED :
+ ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD,
+ "job-state-reasons", NULL, "job-completed-successfully");
+ break;
+ }
+}
+
+
+/*
+ * 'add_printer()' - Add a printer to the system.
+ */
+
+static void
+add_printer(client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - URI of printer */
+{
+ int i; /* Looping var */
+ char method[HTTP_MAX_URI],
+ /* Method portion of URI */
+ username[HTTP_MAX_URI],
+ /* Username portion of URI */
+ host[HTTP_MAX_URI],
+ /* Host portion of URI */
+ resource[HTTP_MAX_URI];
+ /* Resource portion of URI */
+ int port; /* Port portion of URI */
+ printer_t *printer; /* Printer/class */
+ ipp_attribute_t *attr; /* Printer attribute */
+#ifdef HAVE_LIBZ
+ gzFile fp; /* Script/PPD file */
+#else
+ FILE *fp; /* Script/PPD file */
+#endif /* HAVE_LIBZ */
+ char line[1024]; /* Line from file... */
+ char srcfile[1024], /* Source Script/PPD file */
+ dstfile[1024]; /* Destination Script/PPD file */
+ int modify; /* Non-zero if we are modifying */
+
+
+ LogMessage(L_DEBUG2, "add_printer(%p[%d], %s)\n", con, con->http.fd,
+ uri->values[0].string.text);
+
+ /*
+ * Was this operation called from the correct URI?
+ */
+
+ if (strncmp(con->uri, "/admin/", 7) != 0)
+ {
+ LogMessage(L_ERROR, "add_printer: admin request on bad resource \'%s\'!",
+ con->uri);
+ send_ipp_error(con, IPP_NOT_AUTHORIZED);
+ return;
+ }
+
+ /*
+ * Do we have a valid URI?
+ */
+
+ httpSeparate(uri->values[0].string.text, method, username, host, &port, resource);
+
+ if (strncmp(resource, "/printers/", 10) != 0 || strlen(resource) == 10)
+ {
+ /*
+ * No, return an error...
+ */
+
+ send_ipp_error(con, IPP_BAD_REQUEST);
+ return;
+ }
+
+ /*
+ * See if the printer already exists; if not, create a new printer...
+ */
+
+ if ((printer = FindPrinter(resource + 10)) == NULL)
+ {
+ /*
+ * Printer doesn't exist; see if we have a class of the same name...
+ */
+
+ if ((printer = FindClass(resource + 10)) != NULL &&
+ !(printer->type & CUPS_PRINTER_REMOTE))
+ {
+ /*
+ * Yes, return an error...
+ */
+
+ send_ipp_error(con, IPP_NOT_POSSIBLE);
+ return;
+ }
+
+ /*
+ * No, add the printer...
+ */
+
+ printer = AddPrinter(resource + 10);
+ modify = 0;
+ }
+ else if (printer->type & CUPS_PRINTER_IMPLICIT)
+ {
+ /*
+ * Rename the implicit printer to "AnyPrinter" or delete it...
+ */
+
+ if (ImplicitAnyClasses)
+ {
+ snprintf(printer->name, sizeof(printer->name), "Any%s", resource + 10);
+ SortPrinters();
+ }
+ else
+ DeletePrinter(printer);
+
+ /*
+ * Add the printer as a new local printer...
+ */
+
+ printer = AddPrinter(resource + 10);
+ modify = 0;
+ }
+ else if (printer->type & CUPS_PRINTER_REMOTE)
+ {
+ /*
+ * Rename the remote printer to "Printer@server"...
+ */
+
+ DeletePrinterFilters(printer);
+ snprintf(printer->name, sizeof(printer->name), "%s@%s", resource + 10,
+ printer->hostname);
+ SetPrinterAttrs(printer);
+ SortPrinters();
+
+ /*
+ * Add the printer as a new local printer...
+ */
+
+ printer = AddPrinter(resource + 10);
+ modify = 0;
+ }
+ else
+ modify = 1;
+
+ /*
+ * Look for attributes and copy them over as needed...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "printer-location", IPP_TAG_TEXT)) != NULL)
+ {
+ strncpy(printer->location, attr->values[0].string.text, sizeof(printer->location) - 1);
+ printer->location[sizeof(printer->location) - 1] = '\0';
+ }
+
+ if ((attr = ippFindAttribute(con->request, "printer-info", IPP_TAG_TEXT)) != NULL)
+ {
+ strncpy(printer->info, attr->values[0].string.text, sizeof(printer->info) - 1);
+ printer->info[sizeof(printer->info) - 1] = '\0';
+ }
+
+ if ((attr = ippFindAttribute(con->request, "device-uri", IPP_TAG_URI)) != NULL)
+ {
+ ipp_attribute_t *device; /* Current device */
+ int methodlen; /* Length of method string */
+
+
+ /*
+ * Do we have a valid device URI?
+ */
+
+ httpSeparate(attr->values[0].string.text, method, username, host,
+ &port, resource);
+ methodlen = strlen(method);
+
+ if (strcmp(method, "file") != 0)
+ {
+ /*
+ * See if the backend is listed as a device...
+ */
+
+ for (device = ippFindAttribute(Devices, "device-uri", IPP_TAG_URI);
+ device != NULL;
+ device = ippFindNextAttribute(Devices, "device-uri", IPP_TAG_URI))
+ if (strncmp(method, device->values[0].string.text, methodlen) == 0 &&
+ (device->values[0].string.text[methodlen] == ':' ||
+ device->values[0].string.text[methodlen] == '\0'))
+ break;
+
+ if (device == NULL)
+ {
+ /*
+ * Could not find device in list!
+ */
+
+ LogMessage(L_ERROR, "add_printer: bad device-uri attribute \'%s\'!",
+ attr->values[0].string.text);
+ send_ipp_error(con, IPP_NOT_POSSIBLE);
+ return;
+ }
+ }
+
+ LogMessage(L_INFO, "Setting %s device-uri to \"%s\" (was \"%s\".)",
+ printer->name, attr->values[0].string.text, printer->device_uri);
+
+ strncpy(printer->device_uri, attr->values[0].string.text,
+ sizeof(printer->device_uri) - 1);
+ printer->device_uri[sizeof(printer->device_uri) - 1] = '\0';
+ }
+
+ if ((attr = ippFindAttribute(con->request, "printer-is-accepting-jobs", IPP_TAG_BOOLEAN)) != NULL)
+ {
+ LogMessage(L_INFO, "Setting %s printer-is-accepting-jobs to %d (was %d.)",
+ printer->name, attr->values[0].boolean, printer->accepting);
+
+ printer->accepting = attr->values[0].boolean;
+ }
+ if ((attr = ippFindAttribute(con->request, "printer-state", IPP_TAG_ENUM)) != NULL)
+ {
+ LogMessage(L_INFO, "Setting %s printer-state to %d (was %d.)", printer->name,
+ attr->values[0].integer, printer->state);
+
+ if (printer->state == IPP_PRINTER_STOPPED &&
+ attr->values[0].integer != IPP_PRINTER_STOPPED)
+ printer->state = IPP_PRINTER_IDLE;
+ else if (printer->state != IPP_PRINTER_STOPPED &&
+ attr->values[0].integer == IPP_PRINTER_STOPPED)
+ {
+ if (printer->state == IPP_PRINTER_PROCESSING)
+ StopJob(((job_t *)printer->job)->id, 0);
+
+ printer->state = IPP_PRINTER_STOPPED;
+ }
+
+ printer->browse_time = 0;
+ }
+ if ((attr = ippFindAttribute(con->request, "printer-state-message", IPP_TAG_TEXT)) != NULL)
+ {
+ strncpy(printer->state_message, attr->values[0].string.text,
+ sizeof(printer->state_message) - 1);
+ printer->state_message[sizeof(printer->state_message) - 1] = '\0';
+ }
+ if ((attr = ippFindAttribute(con->request, "job-sheets-default", IPP_TAG_ZERO)) != NULL &&
+ !Classification[0])
+ {
+ strncpy(printer->job_sheets[0], attr->values[0].string.text,
+ sizeof(printer->job_sheets[0]) - 1);
+ if (attr->num_values > 1)
+ strncpy(printer->job_sheets[1], attr->values[1].string.text,
+ sizeof(printer->job_sheets[1]) - 1);
+ else
+ strcpy(printer->job_sheets[1], "none");
+ }
+ if ((attr = ippFindAttribute(con->request, "requesting-user-name-allowed",
+ IPP_TAG_ZERO)) != NULL)
+ {
+ FreePrinterUsers(printer);
+
+ printer->deny_users = 0;
+ if (attr->value_tag == IPP_TAG_NAME &&
+ (attr->num_values > 1 ||
+ strcmp(attr->values[0].string.text, "all") != 0))
+ for (i = 0; i < attr->num_values; i ++)
+ AddPrinterUser(printer, attr->values[i].string.text);
+ }
+ else if ((attr = ippFindAttribute(con->request, "requesting-user-name-denied",
+ IPP_TAG_ZERO)) != NULL)
+ {
+ FreePrinterUsers(printer);
+
+ printer->deny_users = 1;
+ if (attr->value_tag == IPP_TAG_NAME &&
+ (attr->num_values > 1 ||
+ strcmp(attr->values[0].string.text, "none") != 0))
+ for (i = 0; i < attr->num_values; i ++)
+ AddPrinterUser(printer, attr->values[i].string.text);
+ }
+ if ((attr = ippFindAttribute(con->request, "job-quota-period",
+ IPP_TAG_INTEGER)) != NULL)
+ {
+ FreeQuotas(printer);
+ printer->quota_period = attr->values[0].integer;
+ }
+ if ((attr = ippFindAttribute(con->request, "job-k-limit",
+ IPP_TAG_INTEGER)) != NULL)
+ {
+ FreeQuotas(printer);
+ printer->k_limit = attr->values[0].integer;
+ }
+ if ((attr = ippFindAttribute(con->request, "job-page-limit",
+ IPP_TAG_INTEGER)) != NULL)
+ {
+ FreeQuotas(printer);
+ printer->page_limit = attr->values[0].integer;
+ }
+
+ /*
+ * See if we have all required attributes...
+ */
+
+ if (printer->device_uri[0] == '\0')
+ strcpy(printer->device_uri, "file:/dev/null");
+
+ /*
+ * See if we have an interface script or PPD file attached to the request...
+ */
+
+ if (con->filename[0])
+ {
+ strncpy(srcfile, con->filename, sizeof(srcfile) - 1);
+ srcfile[sizeof(srcfile) - 1] = '\0';
+ }
+ else if ((attr = ippFindAttribute(con->request, "ppd-name", IPP_TAG_NAME)) != NULL)
+ {
+ if (strcmp(attr->values[0].string.text, "raw") == 0)
+ strcpy(srcfile, "raw");
+ else
+ snprintf(srcfile, sizeof(srcfile), "%s/model/%s", DataDir,
+ attr->values[0].string.text);
+ }
+ else
+ srcfile[0] = '\0';
+
+ LogMessage(L_DEBUG, "add_printer: srcfile = \"%s\"", srcfile);
+
+ if (strcmp(srcfile, "raw") == 0)
+ {
+ /*
+ * Raw driver, remove any existing PPD or interface script files.
+ */
+
+ snprintf(dstfile, sizeof(dstfile), "%s/interfaces/%s", ServerRoot,
+ printer->name);
+ unlink(dstfile);
+
+ snprintf(dstfile, sizeof(dstfile), "%s/ppd/%s.ppd", ServerRoot,
+ printer->name);
+ unlink(dstfile);
+ }
+#ifdef HAVE_LIBZ
+ else if (srcfile[0] && (fp = gzopen(srcfile, "rb")) != NULL)
+#else
+ else if (srcfile[0] && (fp = fopen(srcfile, "rb")) != NULL)
+#endif /* HAVE_LIBZ */
+ {
+ /*
+ * Yes; get the first line from it...
+ */
+
+ line[0] = '\0';
+#ifdef HAVE_LIBZ
+ gzgets(fp, line, sizeof(line));
+ gzclose(fp);
+#else
+ fgets(line, sizeof(line), fp);
+ fclose(fp);
+#endif /* HAVE_LIBZ */
+
+ /*
+ * Then see what kind of file it is...
+ */
+
+ snprintf(dstfile, sizeof(dstfile), "%s/interfaces/%s", ServerRoot,
+ printer->name);
+
+ if (strncmp(line, "*PPD-Adobe", 10) == 0)
+ {
+ /*
+ * The new file is a PPD file, so remove any old interface script
+ * that might be lying around...
+ */
+
+ unlink(dstfile);
+ }
+ else
+ {
+ /*
+ * This must be an interface script, so move the file over to the
+ * interfaces directory and make it executable...
+ */
+
+ if (copy_file(srcfile, dstfile))
+ {
+ LogMessage(L_ERROR, "add_printer: Unable to copy interface script from %s to %s - %s!",
+ srcfile, dstfile, strerror(errno));
+ send_ipp_error(con, IPP_INTERNAL_ERROR);
+ return;
+ }
+ else
+ {
+ LogMessage(L_DEBUG, "add_printer: Copied interface script successfully!");
+ chmod(dstfile, 0755);
+ }
+ }
+
+ snprintf(dstfile, sizeof(dstfile), "%s/ppd/%s.ppd", ServerRoot,
+ printer->name);
+
+ if (strncmp(line, "*PPD-Adobe", 10) == 0)
+ {
+ /*
+ * The new file is a PPD file, so move the file over to the
+ * ppd directory and make it readable by all...
+ */
+
+ if (copy_file(srcfile, dstfile))
+ {
+ LogMessage(L_ERROR, "add_printer: Unable to copy PPD file from %s to %s - %s!",
+ srcfile, dstfile, strerror(errno));
+ send_ipp_error(con, IPP_INTERNAL_ERROR);
+ return;
+ }
+ else
+ {
+ LogMessage(L_DEBUG, "add_printer: Copied PPD file successfully!");
+ chmod(dstfile, 0644);
+ }
+ }
+ else
+ {
+ /*
+ * This must be an interface script, so remove any old PPD file that
+ * may be lying around...
+ */
+
+ unlink(dstfile);
+ }
+ }
+
+ /*
+ * Make this printer the default if there is none...
+ */
+
+ if (DefaultPrinter == NULL)
+ DefaultPrinter = printer;
+
+ /*
+ * Update the printer attributes and return...
+ */
+
+ SetPrinterAttrs(printer);
+ SaveAllPrinters();
+
+ if (printer->job != NULL)
+ {
+ /*
+ * Stop the current job and then restart it below...
+ */
+
+ StopJob(((job_t *)printer->job)->id, 0);
+ }
+
+ CheckJobs();
+
+ if (modify)
+ LogMessage(L_INFO, "Printer \'%s\' modified by \'%s\'.", printer->name,
+ con->username);
+ else
+ LogMessage(L_INFO, "New printer \'%s\' added by \'%s\'.", printer->name,
+ con->username);
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'add_printer_state_reasons()' - Add the "printer-state-reasons" attribute
+ * based upon the printer state...
+ */
+
+static void
+add_printer_state_reasons(client_t *con, /* I - Client connection */
+ printer_t *p) /* I - Printer info */
+{
+ LogMessage(L_DEBUG2, "add_printer_state_reasons(%p[%d], %p[%s])\n",
+ con, con->http.fd, p, p->name);
+
+ switch (p->state)
+ {
+ case IPP_PRINTER_STOPPED :
+ ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "printer-state-reasons", NULL, "paused");
+ break;
+
+ default :
+ ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "printer-state-reasons", NULL, "none");
+ break;
+ }
+}
+
+
+/*
+ * 'add_queued_job_count()' - Add the "queued-job-count" attribute for
+ * the specified printer or class.
+ */
+
+static void
+add_queued_job_count(client_t *con, /* I - Client connection */
+ printer_t *p) /* I - Printer or class */
+{
+ int count; /* Number of jobs on destination */
+
+
+ LogMessage(L_DEBUG2, "add_queued_job_count(%p[%d], %p[%s])\n",
+ con, con->http.fd, p, p->name);
+
+ count = GetPrinterJobCount(p->name);
+
+ ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "queued-job-count", count);
+}
+
+
+/*
+ * 'cancel_all_jobs()' - Cancel all print jobs.
+ */
+
+static void
+cancel_all_jobs(client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Job or Printer URI */
+{
+ const char *dest; /* Destination */
+ cups_ptype_t dtype; /* Destination type */
+ char method[HTTP_MAX_URI],
+ /* Method portion of URI */
+ username[HTTP_MAX_URI],
+ /* Username portion of URI */
+ host[HTTP_MAX_URI],
+ /* Host portion of URI */
+ resource[HTTP_MAX_URI];
+ /* Resource portion of URI */
+ int port; /* Port portion of URI */
+ printer_t *printer; /* Current printer */
+
+
+ LogMessage(L_DEBUG2, "cancel_all_jobs(%p[%d], %s)\n", con, con->http.fd,
+ uri->values[0].string.text);
+
+ /*
+ * Was this operation called from the correct URI?
+ */
+
+ if (strncmp(con->uri, "/admin/", 7) != 0)
+ {
+ LogMessage(L_ERROR, "cancel_all_jobs: admin request on bad resource \'%s\'!",
+ con->uri);
+ send_ipp_error(con, IPP_NOT_AUTHORIZED);
+ return;
+ }
+
+ /*
+ * See if we have a printer URI...
+ */
+
+ if (strcmp(uri->name, "printer-uri") != 0)
+ {
+ LogMessage(L_ERROR, "cancel_all_jobs: bad %s attribute \'%s\'!",
+ uri->name, uri->values[0].string.text);
+ send_ipp_error(con, IPP_BAD_REQUEST);
+ return;
+ }
+
+ /*
+ * And if the destination is valid...
+ */
+
+ httpSeparate(uri->values[0].string.text, method, username, host, &port,
+ resource);
+
+ if ((dest = ValidateDest(host, resource, &dtype)) == NULL)
+ {
+ /*
+ * Bad URI?
+ */
+
+ if (strcmp(resource, "/printers/") != 0)
+ {
+ LogMessage(L_ERROR, "cancel_all_jobs: resource name \'%s\' no good!", resource);
+ send_ipp_error(con, IPP_NOT_FOUND);
+ return;
+ }
+
+ /*
+ * Cancel all jobs on all printers...
+ */
+
+ for (printer = Printers; printer; printer = printer->next)
+ {
+ CancelJobs(printer->name);
+ LogMessage(L_INFO, "All jobs on \'%s\' were cancelled by \'%s\'.",
+ printer->name, con->username);
+ }
+ }
+ else
+ {
+ /*
+ * Cancel all of the jobs on the named printer...
+ */
+
+ CancelJobs(dest);
+ LogMessage(L_INFO, "All jobs on \'%s\' were cancelled by \'%s\'.", dest,
+ con->username);
+ }
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'cancel_job()' - Cancel a print job.
+ */
+
+static void
+cancel_job(client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Job or Printer URI */
+{
+ ipp_attribute_t *attr; /* Current attribute */
+ int jobid; /* Job ID */
+ char method[HTTP_MAX_URI],
+ /* Method portion of URI */
+ username[HTTP_MAX_URI],
+ /* Username portion of URI */
+ host[HTTP_MAX_URI],
+ /* Host portion of URI */
+ resource[HTTP_MAX_URI];
+ /* Resource portion of URI */
+ int port; /* Port portion of URI */
+ job_t *job; /* Job information */
+ const char *dest; /* Destination */
+ cups_ptype_t dtype; /* Destination type (printer or class) */
+ printer_t *printer; /* Printer data */
+
+
+ LogMessage(L_DEBUG2, "cancel_job(%p[%d], %s)\n", con, con->http.fd,
+ uri->values[0].string.text);
+
+ /*
+ * Verify that the POST operation was done to a valid URI.
+ */
+
+ if (strncmp(con->uri, "/classes/", 9) != 0 &&
+ strncmp(con->uri, "/jobs/", 5) != 0 &&
+ strncmp(con->uri, "/printers/", 10) != 0)
+ {
+ LogMessage(L_ERROR, "cancel_job: cancel request on bad resource \'%s\'!",
+ con->uri);
+ send_ipp_error(con, IPP_NOT_AUTHORIZED);
+ return;
+ }
+
+ /*
+ * See if we have a job URI or a printer URI...
+ */
+
+ if (strcmp(uri->name, "printer-uri") == 0)
+ {
+ /*
+ * Got a printer URI; see if we also have a job-id attribute...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "job-id", IPP_TAG_INTEGER)) == NULL)
+ {
+ LogMessage(L_ERROR, "cancel_job: got a printer-uri attribute but no job-id!");
+ send_ipp_error(con, IPP_BAD_REQUEST);
+ return;
+ }
+
+ if ((jobid = attr->values[0].integer) == 0)
+ {
+ /*
+ * Find the current job on the specified printer...
+ */
+
+ httpSeparate(uri->values[0].string.text, method, username, host, &port, resource);
+
+ if ((dest = ValidateDest(host, resource, &dtype)) == NULL)
+ {
+ /*
+ * Bad URI...
+ */
+
+ LogMessage(L_ERROR, "cancel_job: resource name \'%s\' no good!", resource);
+ send_ipp_error(con, IPP_NOT_FOUND);
+ return;
+ }
+
+ if (dtype & CUPS_PRINTER_CLASS)
+ printer = FindClass(dest);
+ else
+ printer = FindPrinter(dest);
+
+ /*
+ * See if the printer is currently printing a job...
+ */
+
+ if (printer->job)
+ jobid = ((job_t *)printer->job)->id;
+ else
+ {
+ /*
+ * No, see if there are any pending jobs...
+ */
+
+ for (job = Jobs; job != NULL; job = job->next)
+ if (job->state->values[0].integer <= IPP_JOB_PROCESSING &&
+ strcasecmp(job->dest, dest) == 0)
+ break;
+
+ if (job != NULL)
+ jobid = job->id;
+ else
+ {
+ LogMessage(L_ERROR, "cancel_job: No active jobs on %s!", dest);
+ send_ipp_error(con, IPP_NOT_POSSIBLE);
+ return;
+ }
+ }
+ }
+ }
+ else
+ {
+ /*
+ * Got a job URI; parse it to get the job ID...
+ */
+
+ httpSeparate(uri->values[0].string.text, method, username, host, &port, resource);
+
+ if (strncmp(resource, "/jobs/", 6) != 0)
+ {
+ /*
+ * Not a valid URI!
+ */
+
+ LogMessage(L_ERROR, "cancel_job: bad job-uri attribute \'%s\'!",
+ uri->values[0].string.text);
+ send_ipp_error(con, IPP_BAD_REQUEST);
+ return;
+ }
+
+ jobid = atoi(resource + 6);
+ }
+
+ /*
+ * See if the job exists...
+ */
+
+ if ((job = FindJob(jobid)) == NULL)
+ {
+ /*
+ * Nope - return a "not found" error...
+ */
+
+ LogMessage(L_ERROR, "cancel_job: job #%d doesn't exist!", jobid);
+ send_ipp_error(con, IPP_NOT_FOUND);
+ return;
+ }
+
+ /*
+ * See if the job is owned by the requesting user...
+ */
+
+ if (!validate_user(con, job->username, username, sizeof(username)))
+ {
+ LogMessage(L_ERROR, "cancel_job: \"%s\" not authorized to delete job id %d owned by \"%s\"!",
+ username, jobid, job->username);
+ send_ipp_error(con, IPP_FORBIDDEN);
+ return;
+ }
+
+ /*
+ * See if the job is already completed, cancelled, or aborted; if so,
+ * we can't cancel...
+ */
+
+ if (job->state->values[0].integer >= IPP_JOB_CANCELLED)
+ {
+ LogMessage(L_ERROR, "cancel_job: job id %d is %s - can't cancel!",
+ jobid,
+ job->state->values[0].integer == IPP_JOB_CANCELLED ? "cancelled" :
+ job->state->values[0].integer == IPP_JOB_ABORTED ? "aborted" :
+ "completed");
+ send_ipp_error(con, IPP_NOT_POSSIBLE);
+ return;
+ }
+
+ /*
+ * Cancel the job and return...
+ */
+
+ CancelJob(jobid, 0);
+ CheckJobs();
+
+ LogMessage(L_INFO, "Job %d was cancelled by \'%s\'.", jobid, username);
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'check_quotas()' - Check quotas for a printer and user.
+ */
+
+static int /* O - 1 if OK, 0 if not */
+check_quotas(client_t *con, /* I - Client connection */
+ printer_t *p) /* I - Printer or class */
+{
+ int i; /* Looping var */
+ ipp_attribute_t *attr; /* Current attribute */
+ char username[33]; /* Username */
+ quota_t *q; /* Quota data */
+
+
+ LogMessage(L_DEBUG2, "check_quotas(%p[%d], %p[%s])\n",
+ con, con->http.fd, p, p->name);
+
+ /*
+ * Check input...
+ */
+
+ if (con == NULL || p == NULL)
+ return (0);
+
+ /*
+ * Figure out who is printing...
+ */
+
+ attr = ippFindAttribute(con->request, "requesting-user-name", IPP_TAG_NAME);
+
+ if (con->username[0])
+ {
+ strncpy(username, con->username, sizeof(username) - 1);
+ username[sizeof(username) - 1] = '\0';
+ }
+ else if (attr != NULL)
+ {
+ LogMessage(L_DEBUG, "check_quotas: requesting-user-name = \'%s\'",
+ attr->values[0].string.text);
+
+ strncpy(username, attr->values[0].string.text, sizeof(username) - 1);
+ username[sizeof(username) - 1] = '\0';
+ }
+ else
+ strcpy(username, "anonymous");
+
+ /*
+ * Check global active job limits for printers and users...
+ */
+
+ if (MaxJobsPerPrinter)
+ {
+ /*
+ * Check if there are too many pending jobs on this printer...
+ */
+
+ if (GetPrinterJobCount(p->name) >= MaxJobsPerPrinter)
+ {
+ LogMessage(L_INFO, "Too many jobs for printer \"%s\"...", p->name);
+ return (0);
+ }
+ }
+
+ if (MaxJobsPerUser)
+ {
+ /*
+ * Check if there are too many pending jobs for this user...
+ */
+
+ if (GetUserJobCount(username) >= MaxJobsPerUser)
+ {
+ LogMessage(L_INFO, "Too many jobs for user \"%s\"...", username);
+ return (0);
+ }
+ }
+
+ /*
+ * Check against users...
+ */
+
+ if (p->num_users == 0 && p->k_limit == 0 && p->page_limit == 0)
+ return (1);
+
+ if (p->num_users)
+ {
+ for (i = 0; i < p->num_users; i ++)
+ if (strcasecmp(username, p->users[i]) == 0)
+ break;
+
+ if ((i < p->num_users) == p->deny_users)
+ {
+ LogMessage(L_INFO, "Denying user \"%s\" access to printer \"%s\"...",
+ username, p->name);
+ return (0);
+ }
+ }
+
+ /*
+ * Check quotas...
+ */
+
+ if (p->k_limit || p->page_limit)
+ {
+ if ((q = UpdateQuota(p, username, 0, 0)) == NULL)
+ {
+ LogMessage(L_ERROR, "Unable to allocate quota data for user \"%s\"!",
+ username);
+ return (0);
+ }
+
+ if ((q->k_count >= p->k_limit && p->k_limit) ||
+ (q->page_count >= p->page_limit && p->page_limit))
+ {
+ LogMessage(L_INFO, "User \"%s\" is over the quota limit...",
+ username);
+ return (0);
+ }
+ }
+
+ /*
+ * If we have gotten this far, we're done!
+ */
+
+ return (1);
+}
+
+
+/*
+ * 'copy_attribute()' - Copy a single attribute.
+ */
+
+static void
+copy_attribute(ipp_t *to, /* O - Destination request/response */
+ ipp_attribute_t *attr, /* I - Attribute to copy */
+ int quickcopy)/* I - Do a quick copy? */
+{
+ int i; /* Looping var */
+ ipp_attribute_t *toattr; /* Destination attribute */
+
+
+ LogMessage(L_DEBUG2, "copy_attribute(%p, %p[%s,%x,%x])\n", to, attr,
+ attr->name ? attr->name : "(null)", attr->group_tag,
+ attr->value_tag);
+
+ switch (attr->value_tag & ~IPP_TAG_COPY)
+ {
+ case IPP_TAG_ZERO :
+ ippAddSeparator(to);
+ break;
+
+ case IPP_TAG_INTEGER :
+ case IPP_TAG_ENUM :
+ toattr = ippAddIntegers(to, attr->group_tag, attr->value_tag,
+ attr->name, attr->num_values, NULL);
+
+ for (i = 0; i < attr->num_values; i ++)
+ toattr->values[i].integer = attr->values[i].integer;
+ break;
+
+ case IPP_TAG_BOOLEAN :
+ toattr = ippAddBooleans(to, attr->group_tag, attr->name,
+ attr->num_values, NULL);
+
+ for (i = 0; i < attr->num_values; i ++)
+ toattr->values[i].boolean = attr->values[i].boolean;
+ break;
+
+ case IPP_TAG_STRING :
+ case IPP_TAG_TEXT :
+ case IPP_TAG_NAME :
+ case IPP_TAG_KEYWORD :
+ case IPP_TAG_URI :
+ case IPP_TAG_URISCHEME :
+ case IPP_TAG_CHARSET :
+ case IPP_TAG_LANGUAGE :
+ case IPP_TAG_MIMETYPE :
+ toattr = ippAddStrings(to, attr->group_tag,
+ (ipp_tag_t)(attr->value_tag | quickcopy),
+ attr->name, attr->num_values, NULL, NULL);
+
+ if (quickcopy)
+ {
+ for (i = 0; i < attr->num_values; i ++)
+ toattr->values[i].string.text = attr->values[i].string.text;
+ }
+ else
+ {
+ for (i = 0; i < attr->num_values; i ++)
+ toattr->values[i].string.text = strdup(attr->values[i].string.text);
+ }
+ break;
+
+ case IPP_TAG_DATE :
+ toattr = ippAddDate(to, attr->group_tag, attr->name,
+ attr->values[0].date);
+ break;
+
+ case IPP_TAG_RESOLUTION :
+ toattr = ippAddResolutions(to, attr->group_tag, attr->name,
+ attr->num_values, IPP_RES_PER_INCH,
+ NULL, NULL);
+
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ toattr->values[i].resolution.xres = attr->values[i].resolution.xres;
+ toattr->values[i].resolution.yres = attr->values[i].resolution.yres;
+ toattr->values[i].resolution.units = attr->values[i].resolution.units;
+ }
+ break;
+
+ case IPP_TAG_RANGE :
+ toattr = ippAddRanges(to, attr->group_tag, attr->name,
+ attr->num_values, NULL, NULL);
+
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ toattr->values[i].range.lower = attr->values[i].range.lower;
+ toattr->values[i].range.upper = attr->values[i].range.upper;
+ }
+ break;
+
+ case IPP_TAG_TEXTLANG :
+ case IPP_TAG_NAMELANG :
+ toattr = ippAddStrings(to, attr->group_tag,
+ (ipp_tag_t)(attr->value_tag | quickcopy),
+ attr->name, attr->num_values, NULL, NULL);
+
+ if (quickcopy)
+ {
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ toattr->values[i].string.charset = attr->values[i].string.charset;
+ toattr->values[i].string.text = attr->values[i].string.text;
+ }
+ }
+ else
+ {
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (!i)
+ toattr->values[i].string.charset =
+ strdup(attr->values[i].string.charset);
+ else
+ toattr->values[i].string.charset =
+ toattr->values[0].string.charset;
+
+ toattr->values[i].string.text = strdup(attr->values[i].string.text);
+ }
+ }
+ break;
+
+ default :
+ toattr = ippAddIntegers(to, attr->group_tag, attr->value_tag,
+ attr->name, attr->num_values, NULL);
+
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ toattr->values[i].unknown.length = attr->values[i].unknown.length;
+
+ if (toattr->values[i].unknown.length > 0)
+ {
+ if ((toattr->values[i].unknown.data = malloc(toattr->values[i].unknown.length)) == NULL)
+ toattr->values[i].unknown.length = 0;
+ else
+ memcpy(toattr->values[i].unknown.data,
+ attr->values[i].unknown.data,
+ toattr->values[i].unknown.length);
+ }
+ }
+ break; /* anti-compiler-warning-code */
+ }
+}
+
+
+/*
+ * 'copy_attrs()' - Copy attributes from one request to another.
+ */
+
+static void
+copy_attrs(ipp_t *to, /* I - Destination request */
+ ipp_t *from, /* I - Source request */
+ ipp_attribute_t *req, /* I - Requested attributes */
+ ipp_tag_t group) /* I - Group to copy */
+{
+ int i; /* Looping var */
+ ipp_attribute_t *fromattr; /* Source attribute */
+
+
+ LogMessage(L_DEBUG2, "copy_attrs(%p, %p, %p, %x)\n", to, from, req, group);
+
+ if (to == NULL || from == NULL)
+ return;
+
+ if (req != NULL && strcmp(req->values[0].string.text, "all") == 0)
+ req = NULL; /* "all" means no filter... */
+
+ for (fromattr = from->attrs; fromattr != NULL; fromattr = fromattr->next)
+ {
+ /*
+ * Filter attributes as needed...
+ */
+
+ if (group != IPP_TAG_ZERO && fromattr->group_tag != group &&
+ fromattr->group_tag != IPP_TAG_ZERO)
+ continue;
+
+ if (req != NULL && fromattr->name != NULL)
+ {
+ for (i = 0; i < req->num_values; i ++)
+ if (strcmp(fromattr->name, req->values[i].string.text) == 0)
+ break;
+
+ if (i == req->num_values)
+ continue;
+ }
+
+ copy_attribute(to, fromattr, IPP_TAG_COPY);
+ }
+}
+
+
+/*
+ * 'create_job()' - Print a file to a printer or class.
+ */
+
+static void
+create_job(client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Printer URI */
+{
+ ipp_attribute_t *attr; /* Current attribute */
+ const char *dest; /* Destination */
+ cups_ptype_t dtype; /* Destination type (printer or class) */
+ int priority; /* Job priority */
+ char *title; /* Job name/title */
+ job_t *job; /* Current job */
+ char job_uri[HTTP_MAX_URI],
+ /* Job URI */
+ printer_uri[HTTP_MAX_URI],
+ /* Printer URI */
+ method[HTTP_MAX_URI],
+ /* Method portion of URI */
+ username[HTTP_MAX_URI],
+ /* Username portion of URI */
+ host[HTTP_MAX_URI],
+ /* Host portion of URI */
+ resource[HTTP_MAX_URI];
+ /* Resource portion of URI */
+ int port; /* Port portion of URI */
+ printer_t *printer; /* Printer data */
+ int kbytes; /* Size of print file */
+
+
+ LogMessage(L_DEBUG2, "create_job(%p[%d], %s)\n", con, con->http.fd,
+ uri->values[0].string.text);
+
+ /*
+ * Verify that the POST operation was done to a valid URI.
+ */
+
+ if (strncmp(con->uri, "/classes/", 9) != 0 &&
+ strncmp(con->uri, "/printers/", 10) != 0)
+ {
+ LogMessage(L_ERROR, "create_job: cancel request on bad resource \'%s\'!",
+ con->uri);
+ send_ipp_error(con, IPP_NOT_AUTHORIZED);
+ return;
+ }
+
+ /*
+ * Is the destination valid?
+ */
+
+ httpSeparate(uri->values[0].string.text, method, username, host, &port, resource);
+
+ if ((dest = ValidateDest(host, resource, &dtype)) == NULL)
+ {
+ /*
+ * Bad URI...
+ */
+
+ LogMessage(L_ERROR, "create_job: resource name \'%s\' no good!", resource);
+ send_ipp_error(con, IPP_NOT_FOUND);
+ return;
+ }
+
+ /*
+ * See if the printer is accepting jobs...
+ */
+
+ if (dtype == CUPS_PRINTER_CLASS)
+ {
+ printer = FindClass(dest);
+ snprintf(printer_uri, sizeof(printer_uri), "http://%s:%d/classes/%s",
+ ServerName, ntohs(con->http.hostaddr.sin_port), dest);
+ }
+ else
+ {
+ printer = FindPrinter(dest);
+
+ snprintf(printer_uri, sizeof(printer_uri), "http://%s:%d/printers/%s",
+ ServerName, ntohs(con->http.hostaddr.sin_port), dest);
+ }
+
+ if (!printer->accepting)
+ {
+ LogMessage(L_INFO, "create_job: destination \'%s\' is not accepting jobs.",
+ dest);
+ send_ipp_error(con, IPP_NOT_ACCEPTING);
+ return;
+ }
+
+ /*
+ * Make sure we aren't over our limit...
+ */
+
+ if (NumJobs >= MaxJobs && MaxJobs)
+ CleanJobs();
+
+ if (NumJobs >= MaxJobs && MaxJobs)
+ {
+ LogMessage(L_INFO, "create_job: too many jobs.");
+ send_ipp_error(con, IPP_NOT_POSSIBLE);
+ return;
+ }
+
+ if (!check_quotas(con, printer))
+ {
+ send_ipp_error(con, IPP_NOT_POSSIBLE);
+ return;
+ }
+
+ /*
+ * Create the job and set things up...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "job-priority", IPP_TAG_INTEGER)) != NULL)
+ priority = attr->values[0].integer;
+ else
+ ippAddInteger(con->request, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-priority",
+ priority = 50);
+
+ if ((attr = ippFindAttribute(con->request, "job-name", IPP_TAG_NAME)) != NULL)
+ title = attr->values[0].string.text;
+ else
+ ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_NAME, "job-name", NULL,
+ title = "Untitled");
+
+ if ((job = AddJob(priority, printer->name)) == NULL)
+ {
+ LogMessage(L_ERROR, "create_job: unable to add job for destination \'%s\'!",
+ dest);
+ send_ipp_error(con, IPP_INTERNAL_ERROR);
+ return;
+ }
+
+ job->dtype = dtype;
+ job->attrs = con->request;
+ con->request = NULL;
+
+ strncpy(job->title, title, sizeof(job->title) - 1);
+
+ attr = ippFindAttribute(job->attrs, "requesting-user-name", IPP_TAG_NAME);
+
+ if (con->username[0])
+ {
+ strncpy(job->username, con->username, sizeof(job->username) - 1);
+ job->username[sizeof(job->username) - 1] = '\0';
+ }
+ else if (attr != NULL)
+ {
+ LogMessage(L_DEBUG, "create_job: requesting-user-name = \'%s\'",
+ attr->values[0].string.text);
+
+ strncpy(job->username, attr->values[0].string.text,
+ sizeof(job->username) - 1);
+ job->username[sizeof(job->username) - 1] = '\0';
+ }
+ else
+ strcpy(job->username, "anonymous");
+
+ if (attr == NULL)
+ ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, "job-originating-user-name",
+ NULL, job->username);
+ else
+ {
+ attr->group_tag = IPP_TAG_JOB;
+ free(attr->name);
+ attr->name = strdup("job-originating-user-name");
+ }
+
+ ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME,
+ "job-originating-host-name", NULL, con->http.hostname);
+ ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "time-at-creation",
+ time(NULL));
+ attr = ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER,
+ "time-at-processing", 0);
+ attr->value_tag = IPP_TAG_NOVALUE;
+ attr = ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER,
+ "time-at-completed", 0);
+ attr->value_tag = IPP_TAG_NOVALUE;
+
+ /*
+ * Add remaining job attributes...
+ */
+
+ ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", job->id);
+ job->state = ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_ENUM,
+ "job-state", IPP_JOB_STOPPED);
+ job->sheets = ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER,
+ "job-media-sheets-completed", 0);
+ ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-printer-uri", NULL,
+ printer_uri);
+ ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, "job-name", NULL,
+ title);
+
+ if ((attr = ippFindAttribute(job->attrs, "job-k-octets", IPP_TAG_INTEGER)) != NULL)
+ attr->values[0].integer = 0;
+ else
+ attr = ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER,
+ "job-k-octets", 0);
+
+ if ((attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_KEYWORD)) == NULL)
+ attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);
+ if (attr == NULL)
+ attr = ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_KEYWORD,
+ "job-hold-until", NULL, "no-hold");
+ if (attr != NULL && strcmp(attr->values[0].string.text, "no-hold") != 0 &&
+ !(printer->type & CUPS_PRINTER_REMOTE))
+ {
+ /*
+ * Hold job until specified time...
+ */
+
+ SetJobHoldUntil(job->id, attr->values[0].string.text);
+ }
+ else
+ job->hold_until = time(NULL) + 60;
+
+ job->state->values[0].integer = IPP_JOB_HELD;
+
+ if (!(printer->type & CUPS_PRINTER_REMOTE) || Classification[0])
+ {
+ /*
+ * Add job sheets options...
+ */
+
+ if ((attr = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_ZERO)) == NULL)
+ {
+ LogMessage(L_DEBUG, "Adding default job-sheets values \"%s,%s\"...",
+ printer->job_sheets[0], printer->job_sheets[1]);
+
+ attr = ippAddStrings(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, "job-sheets",
+ 2, NULL, NULL);
+ attr->values[0].string.text = strdup(printer->job_sheets[0]);
+ attr->values[1].string.text = strdup(printer->job_sheets[1]);
+ }
+
+ job->job_sheets = attr;
+
+ /*
+ * Enforce classification level if set...
+ */
+
+ if (Classification[0])
+ {
+ if (ClassifyOverride)
+ {
+ if (strcmp(attr->values[0].string.text, "none") == 0 &&
+ (attr->num_values == 1 ||
+ strcmp(attr->values[1].string.text, "none") == 0))
+ {
+ /*
+ * Force the leading banner to have the classification on it...
+ */
+
+ free(attr->values[0].string.text);
+ attr->values[0].string.text = strdup(Classification);
+ }
+ else if (attr->num_values == 2 &&
+ strcmp(attr->values[0].string.text, attr->values[1].string.text) != 0 &&
+ strcmp(attr->values[0].string.text, "none") != 0 &&
+ strcmp(attr->values[1].string.text, "none") != 0)
+ {
+ /*
+ * Can't put two different security markings on the same document!
+ */
+
+ free(attr->values[1].string.text);
+ attr->values[1].string.text = strdup(attr->values[0].string.text);
+ }
+ }
+ else if (strcmp(attr->values[0].string.text, Classification) != 0 &&
+ (attr->num_values == 1 ||
+ strcmp(attr->values[1].string.text, Classification) != 0))
+ {
+ /*
+ * Force the leading banner to have the classification on it...
+ */
+
+ free(attr->values[0].string.text);
+ attr->values[0].string.text = strdup(Classification);
+ }
+ }
+
+ /*
+ * See if we need to add the starting sheet...
+ */
+
+ if (!(printer->type & CUPS_PRINTER_REMOTE))
+ {
+ kbytes = copy_banner(con, job, attr->values[0].string.text);
+
+ UpdateQuota(printer, job->username, 0, kbytes);
+ }
+ }
+ else if ((attr = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_ZERO)) != NULL)
+ job->sheets = attr;
+
+ /*
+ * Save and log the job...
+ */
+
+ SaveJob(job->id);
+
+ LogMessage(L_INFO, "Job %d created on \'%s\' by \'%s\'.", job->id,
+ job->dest, job->username);
+
+ /*
+ * Fill in the response info...
+ */
+
+ snprintf(job_uri, sizeof(job_uri), "http://%s:%d/jobs/%d", ServerName,
+ ntohs(con->http.hostaddr.sin_port), job->id);
+ ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI, "job-uri", NULL, job_uri);
+
+ ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", job->id);
+
+ ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_ENUM, "job-state",
+ job->state->values[0].integer);
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'copy_banner()' - Copy a banner file to the requests directory for the
+ * specified job.
+ */
+
+static int /* O - Size of banner file in kbytes */
+copy_banner(client_t *con, /* I - Client connection */
+ job_t *job, /* I - Job information */
+ const char *name) /* I - Name of banner */
+{
+ int i; /* Looping var */
+ int kbytes; /* Size of banner file in kbytes */
+ char filename[1024]; /* Job filename */
+ banner_t *banner; /* Pointer to banner */
+ FILE *in; /* Input file */
+ FILE *out; /* Output file */
+ int ch; /* Character from file */
+ char attrname[255], /* Name of attribute */
+ *s; /* Pointer into name */
+ ipp_attribute_t *attr; /* Attribute */
+
+
+ LogMessage(L_DEBUG2, "copy_banner(%p[%d], %p[%d], %s)",
+ con, con->http.fd, job, job->id, name ? name : "(null)");
+
+ /*
+ * Find the banner; return if not found or "none"...
+ */
+
+ if (name == NULL ||
+ strcmp(name, "none") == 0 ||
+ (banner = FindBanner(name)) == NULL)
+ return (0);
+
+ /*
+ * Open the banner and job files...
+ */
+
+ if (add_file(con, job, banner->filetype))
+ return (0);
+
+ snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot, job->id,
+ job->num_files);
+ if ((out = fopen(filename, "w")) == NULL)
+ {
+ LogMessage(L_ERROR, "copy_banner: Unable to create banner job file %s - %s",
+ filename, strerror(errno));
+ job->num_files --;
+ return (0);
+ }
+
+ fchmod(fileno(out), 0640);
+ fchown(fileno(out), User, Group);
+
+ if (con->language)
+ {
+ /*
+ * Try the localized banner file under the subdirectory...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/banners/%s/%s", DataDir,
+ con->language->language, name);
+
+ if (access(filename, 0) && con->language->language[2])
+ {
+ /*
+ * Wasn't able to find "ll_CC" locale file; try the non-national
+ * localization banner directory.
+ */
+
+ attrname[0] = con->language->language[0];
+ attrname[1] = con->language->language[1];
+ attrname[2] = '\0';
+
+ snprintf(filename, sizeof(filename), "%s/banners/%s/%s", DataDir,
+ attrname, name);
+ }
+
+ if (access(filename, 0))
+ {
+ /*
+ * Use the non-localized banner file.
+ */
+
+ snprintf(filename, sizeof(filename), "%s/banners/%s", DataDir, name);
+ }
+ }
+ else
+ {
+ /*
+ * Use the non-localized banner file.
+ */
+
+ snprintf(filename, sizeof(filename), "%s/banners/%s", DataDir, name);
+ }
+
+ if ((in = fopen(filename, "r")) == NULL)
+ {
+ fclose(out);
+ unlink(filename);
+ LogMessage(L_ERROR, "copy_banner: Unable to open banner template file %s - %s",
+ filename, strerror(errno));
+ job->num_files --;
+ return (0);
+ }
+
+ /*
+ * Parse the file to the end...
+ */
+
+ while ((ch = getc(in)) != EOF)
+ if (ch == '{')
+ {
+ /*
+ * Get an attribute name...
+ */
+
+ for (s = attrname; (ch = getc(in)) != EOF;)
+ if (!isalpha(ch) && ch != '-' && ch != '?')
+ break;
+ else if (s < (attrname + sizeof(attrname) - 1))
+ *s++ = ch;
+ else
+ break;
+
+ *s = '\0';
+
+ if (ch != '}')
+ {
+ /*
+ * Ignore { followed by stuff that is not an attribute name...
+ */
+
+ putc('{', out);
+ fputs(attrname, out);
+ putc(ch, out);
+ continue;
+ }
+
+ /*
+ * See if it is defined...
+ */
+
+ if (attrname[0] == '?')
+ s = attrname + 1;
+ else
+ s = attrname;
+
+ if (strcmp(s, "printer-name") == 0)
+ {
+ fputs(job->dest, out);
+ continue;
+ }
+ else if ((attr = ippFindAttribute(job->attrs, s, IPP_TAG_ZERO)) == NULL)
+ {
+ /*
+ * See if we have a leading question mark...
+ */
+
+ if (attrname[0] != '?')
+ {
+ /*
+ * Nope, write to file as-is; probably a PostScript procedure...
+ */
+
+ putc('{', out);
+ fputs(attrname, out);
+ putc('}', out);
+ }
+
+ continue;
+ }
+
+ /*
+ * Output value(s)...
+ */
+
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (i)
+ putc(',', out);
+
+ switch (attr->value_tag)
+ {
+ case IPP_TAG_INTEGER :
+ case IPP_TAG_ENUM :
+ if (strncmp(attrname, "time-at-", 8) == 0)
+ fputs(GetDateTime(attr->values[i].integer), out);
+ else
+ fprintf(out, "%d", attr->values[i].integer);
+ break;
+
+ case IPP_TAG_BOOLEAN :
+ fprintf(out, "%d", attr->values[i].boolean);
+ break;
+
+ case IPP_TAG_NOVALUE :
+ fputs("novalue", out);
+ break;
+
+ case IPP_TAG_RANGE :
+ fprintf(out, "%d-%d", attr->values[i].range.lower,
+ attr->values[i].range.upper);
+ break;
+
+ case IPP_TAG_RESOLUTION :
+ fprintf(out, "%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 :
+ case IPP_TAG_STRING :
+ case IPP_TAG_TEXT :
+ case IPP_TAG_NAME :
+ case IPP_TAG_KEYWORD :
+ case IPP_TAG_CHARSET :
+ case IPP_TAG_LANGUAGE :
+ if (strcasecmp(banner->filetype->type, "postscript") == 0)
+ {
+ /*
+ * Need to quote strings for PS banners...
+ */
+
+ const char *p;
+
+ for (p = attr->values[i].string.text; *p; p ++)
+ {
+ if (*p == '(' || *p == ')' || *p == '\\')
+ {
+ putc('\\', out);
+ putc(*p, out);
+ }
+ else if (*p < 32 || *p > 126)
+ fprintf(out, "\\%03o", *p);
+ else
+ putc(*p, out);
+ }
+ }
+ else
+ fputs(attr->values[i].string.text, out);
+ break;
+
+ default :
+ break; /* anti-compiler-warning-code */
+ }
+ }
+ }
+ else if (ch == '\\') /* Quoted char */
+ putc(getc(in), out);
+ else
+ putc(ch, out);
+
+ fclose(in);
+
+ kbytes = (ftell(out) + 1023) / 1024;
+
+ if ((attr = ippFindAttribute(job->attrs, "job-k-octets", IPP_TAG_INTEGER)) != NULL)
+ attr->values[0].integer += kbytes;
+
+ fclose(out);
+
+ return (kbytes);
+}
+
+
+/*
+ * 'copy_file()' - Copy a PPD file or interface script...
+ */
+
+static int /* O - 0 = success, -1 = error */
+copy_file(const char *from, /* I - Source file */
+ const char *to) /* I - Destination file */
+{
+#ifdef HAVE_LIBZ
+ gzFile src; /* Source file */
+#else
+ int src; /* Source file */
+#endif /* HAVE_LIBZ */
+ int dst, /* Destination file */
+ bytes; /* Bytes to read/write */
+ char buffer[8192]; /* Copy buffer */
+
+
+ LogMessage(L_DEBUG2, "copy_file(\"%s\", \"%s\")\n", from, to);
+
+#ifdef HAVE_LIBZ
+ if ((src = gzopen(from, "rb")) == NULL)
+ return (-1);
+#else
+ if ((src = open(from, O_RDONLY)) < 0)
+ return (-1);
+#endif /* HAVE_LIBZ */
+
+ if ((dst = open(to, O_WRONLY | O_CREAT | O_TRUNC, 0644)) < 0)
+ {
+#ifdef HAVE_LIBZ
+ gzclose(src);
+#else
+ close(src);
+#endif /* HAVE_LIBZ */
+ return (-1);
+ }
+
+#ifdef HAVE_LIBZ
+ while ((bytes = gzread(src, buffer, sizeof(buffer))) > 0)
+#else
+ while ((bytes = read(src, buffer, sizeof(buffer))) > 0)
+#endif /* HAVE_LIBZ */
+ if (write(dst, buffer, bytes) < bytes)
+ {
+#ifdef HAVE_LIBZ
+ gzclose(src);
+#else
+ close(src);
+#endif /* HAVE_LIBZ */
+ close(dst);
+ return (-1);
+ }
+
+#ifdef HAVE_LIBZ
+ gzclose(src);
+#else
+ close(src);
+#endif /* HAVE_LIBZ */
+ close(dst);
+
+ return (0);
+}
+
+
+/*
+ * 'delete_printer()' - Remove a printer or class from the system.
+ */
+
+static void
+delete_printer(client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - URI of printer or class */
+{
+ const char *dest; /* Destination */
+ cups_ptype_t dtype; /* Destination type (printer or class) */
+ char method[HTTP_MAX_URI],
+ /* Method portion of URI */
+ username[HTTP_MAX_URI],
+ /* Username portion of URI */
+ host[HTTP_MAX_URI],
+ /* Host portion of URI */
+ resource[HTTP_MAX_URI];
+ /* Resource portion of URI */
+ int port; /* Port portion of URI */
+ printer_t *printer; /* Printer/class */
+ char filename[1024]; /* Script/PPD filename */
+
+
+ LogMessage(L_DEBUG2, "delete_printer(%p[%d], %s)\n", con, con->http.fd,
+ uri->values[0].string.text);
+
+ /*
+ * Was this operation called from the correct URI?
+ */
+
+ if (strncmp(con->uri, "/admin/", 7) != 0)
+ {
+ LogMessage(L_ERROR, "delete_printer: admin request on bad resource \'%s\'!",
+ con->uri);
+ send_ipp_error(con, IPP_NOT_AUTHORIZED);
+ return;
+ }
+
+ /*
+ * Do we have a valid URI?
+ */
+
+ httpSeparate(uri->values[0].string.text, method, username, host, &port, resource);
+
+ if ((dest = ValidateDest(host, resource, &dtype)) == NULL)
+ {
+ /*
+ * Bad URI...
+ */
+
+ LogMessage(L_ERROR, "delete_printer: resource name \'%s\' no good!", resource);
+ send_ipp_error(con, IPP_NOT_FOUND);
+ return;
+ }
+
+ /*
+ * Find the printer or class and delete it...
+ */
+
+ if (dtype == CUPS_PRINTER_CLASS)
+ printer = FindClass(dest);
+ else
+ printer = FindPrinter(dest);
+
+ /*
+ * Remove old jobs...
+ */
+
+ CancelJobs(dest);
+
+ /*
+ * Remove any old PPD or script files...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/interfaces/%s", ServerRoot, dest);
+ unlink(filename);
+
+ snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd", ServerRoot, dest);
+ unlink(filename);
+
+ if (dtype == CUPS_PRINTER_CLASS)
+ {
+ LogMessage(L_INFO, "Class \'%s\' deleted by \'%s\'.", dest,
+ con->username);
+
+ DeletePrinter(printer);
+ SaveAllClasses();
+ }
+ else
+ {
+ LogMessage(L_INFO, "Printer \'%s\' deleted by \'%s\'.", dest,
+ con->username);
+
+ DeletePrinter(printer);
+ SaveAllPrinters();
+ }
+
+ /*
+ * Return with no errors...
+ */
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'get_default()' - Get the default destination.
+ */
+
+static void
+get_default(client_t *con) /* I - Client connection */
+{
+ LogMessage(L_DEBUG2, "get_default(%p[%d])\n", con, con->http.fd);
+
+ if (DefaultPrinter != NULL)
+ {
+ copy_attrs(con->response, DefaultPrinter->attrs,
+ ippFindAttribute(con->request, "requested-attributes",
+ IPP_TAG_KEYWORD), IPP_TAG_ZERO);
+
+ con->response->request.status.status_code = IPP_OK;
+ }
+ else
+ con->response->request.status.status_code = IPP_NOT_FOUND;
+}
+
+
+/*
+ * 'get_devices()' - Get the list of available devices on the local system.
+ */
+
+static void
+get_devices(client_t *con) /* I - Client connection */
+{
+ LogMessage(L_DEBUG2, "get_devices(%p[%d])\n", con, con->http.fd);
+
+ /*
+ * Copy the device attributes to the response using the requested-attributes
+ * attribute that may be provided by the client.
+ */
+
+ copy_attrs(con->response, Devices,
+ ippFindAttribute(con->request, "requested-attributes",
+ IPP_TAG_KEYWORD), IPP_TAG_ZERO);
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'get_jobs()' - Get a list of jobs for the specified printer.
+ */
+
+static void
+get_jobs(client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Printer URI */
+{
+ ipp_attribute_t *attr, /* Current attribute */
+ *requested; /* Requested attributes */
+ const char *dest; /* Destination */
+ cups_ptype_t dtype; /* Destination type (printer or class) */
+ cups_ptype_t dmask; /* Destination type mask */
+ char method[HTTP_MAX_URI],
+ /* Method portion of URI */
+ username[HTTP_MAX_URI],
+ /* Username portion of URI */
+ host[HTTP_MAX_URI],
+ /* Host portion of URI */
+ resource[HTTP_MAX_URI];
+ /* Resource portion of URI */
+ int port; /* Port portion of URI */
+ int completed; /* Completed jobs? */
+ int limit; /* Maximum number of jobs to return */
+ int count; /* Number of jobs that match */
+ job_t *job; /* Current job pointer */
+ char job_uri[HTTP_MAX_URI];
+ /* Job URI... */
+
+
+ LogMessage(L_DEBUG2, "get_jobs(%p[%d], %s)\n", con, con->http.fd,
+ uri->values[0].string.text);
+
+ /*
+ * Is the destination valid?
+ */
+
+ httpSeparate(uri->values[0].string.text, method, username, host, &port, resource);
+
+ if (strcmp(resource, "/") == 0 ||
+ (strncmp(resource, "/jobs", 5) == 0 && strlen(resource) <= 6))
+ {
+ dest = NULL;
+ dtype = (cups_ptype_t)0;
+ dmask = (cups_ptype_t)0;
+ }
+ else if (strncmp(resource, "/printers", 9) == 0 && strlen(resource) <= 10)
+ {
+ dest = NULL;
+ dtype = (cups_ptype_t)0;
+ dmask = CUPS_PRINTER_CLASS;
+ }
+ else if (strncmp(resource, "/classes", 8) == 0 && strlen(resource) <= 9)
+ {
+ dest = NULL;
+ dtype = CUPS_PRINTER_CLASS;
+ dmask = CUPS_PRINTER_CLASS;
+ }
+ else if ((dest = ValidateDest(host, resource, &dtype)) == NULL)
+ {
+ /*
+ * Bad URI...
+ */
+
+ LogMessage(L_ERROR, "get_jobs: resource name \'%s\' no good!", resource);
+ send_ipp_error(con, IPP_NOT_FOUND);
+ return;
+ }
+ else
+ dmask = CUPS_PRINTER_CLASS;
+
+ /*
+ * See if the "which-jobs" attribute have been specified; if so, return
+ * right away if they specify "completed" - we don't keep old job records...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "which-jobs", IPP_TAG_KEYWORD)) != NULL &&
+ strcmp(attr->values[0].string.text, "completed") == 0)
+ completed = 1;
+ else
+ completed = 0;
+
+ /*
+ * See if they want to limit the number of jobs reported...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "limit", IPP_TAG_INTEGER)) != NULL)
+ limit = attr->values[0].integer;
+ else
+ limit = 1000000;
+
+ /*
+ * See if we only want to see jobs for a specific user...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "my-jobs", IPP_TAG_BOOLEAN)) != NULL &&
+ attr->values[0].boolean)
+ {
+ if (con->username[0])
+ {
+ strncpy(username, con->username, sizeof(username) - 1);
+ username[sizeof(username) - 1] = '\0';
+ }
+ else if ((attr = ippFindAttribute(con->request, "requesting-user-name", IPP_TAG_NAME)) != NULL)
+ {
+ strncpy(username, attr->values[0].string.text, sizeof(username) - 1);
+ username[sizeof(username) - 1] = '\0';
+ }
+ else
+ strcpy(username, "anonymous");
+ }
+ else
+ username[0] = '\0';
+
+ requested = ippFindAttribute(con->request, "requested-attributes",
+ IPP_TAG_KEYWORD);
+
+ /*
+ * OK, build a list of jobs for this printer...
+ */
+
+ for (count = 0, job = Jobs; count < limit && job != NULL; job = job->next)
+ {
+ /*
+ * Filter out jobs that don't match...
+ */
+
+ LogMessage(L_DEBUG2, "get_jobs: job->id = %d", job->id);
+
+ if ((dest != NULL && strcmp(job->dest, dest) != 0) &&
+ (job->printer == NULL || dest == NULL ||
+ strcmp(job->printer->name, dest) != 0))
+ continue;
+ if ((job->dtype & dmask) != dtype &&
+ (job->printer == NULL || (job->printer->type & dmask) != dtype))
+ continue;
+ if (username[0] != '\0' && strcmp(username, job->username) != 0)
+ continue;
+
+ if (completed && job->state->values[0].integer <= IPP_JOB_STOPPED)
+ continue;
+ if (!completed && job->state->values[0].integer > IPP_JOB_STOPPED)
+ continue;
+
+ count ++;
+
+ LogMessage(L_DEBUG2, "get_jobs: count = %d", count);
+
+ /*
+ * Send the requested attributes for each job...
+ */
+
+ snprintf(job_uri, sizeof(job_uri), "http://%s:%d/jobs/%d", ServerName,
+ ntohs(con->http.hostaddr.sin_port), job->id);
+
+ ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI,
+ "job-more-info", NULL, job_uri);
+
+ ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI,
+ "job-uri", NULL, job_uri);
+
+ ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER,
+ "job-printer-up-time", time(NULL));
+
+ /*
+ * Copy the job attributes to the response using the requested-attributes
+ * attribute that may be provided by the client.
+ */
+
+ copy_attrs(con->response, job->attrs, requested, IPP_TAG_JOB);
+
+ add_job_state_reasons(con, job);
+
+ ippAddSeparator(con->response);
+ }
+
+ if (requested != NULL)
+ con->response->request.status.status_code = IPP_OK_SUBST;
+ else
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'get_job_attrs()' - Get job attributes.
+ */
+
+static void
+get_job_attrs(client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Job URI */
+{
+ ipp_attribute_t *attr, /* Current attribute */
+ *requested; /* Requested attributes */
+ int jobid; /* Job ID */
+ job_t *job; /* Current job */
+ char method[HTTP_MAX_URI],
+ /* Method portion of URI */
+ username[HTTP_MAX_URI],
+ /* Username portion of URI */
+ host[HTTP_MAX_URI],
+ /* Host portion of URI */
+ resource[HTTP_MAX_URI];
+ /* Resource portion of URI */
+ int port; /* Port portion of URI */
+ char job_uri[HTTP_MAX_URI];
+ /* Job URI... */
+
+
+ LogMessage(L_DEBUG2, "get_job_attrs(%p[%d], %s)\n", con, con->http.fd,
+ uri->values[0].string.text);
+
+ /*
+ * See if we have a job URI or a printer URI...
+ */
+
+ if (strcmp(uri->name, "printer-uri") == 0)
+ {
+ /*
+ * Got a printer URI; see if we also have a job-id attribute...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "job-id", IPP_TAG_INTEGER)) == NULL)
+ {
+ LogMessage(L_ERROR, "get_job_attrs: got a printer-uri attribute but no job-id!");
+ send_ipp_error(con, IPP_BAD_REQUEST);
+ return;
+ }
+
+ jobid = attr->values[0].integer;
+ }
+ else
+ {
+ /*
+ * Got a job URI; parse it to get the job ID...
+ */
+
+ httpSeparate(uri->values[0].string.text, method, username, host, &port, resource);
+
+ if (strncmp(resource, "/jobs/", 6) != 0)
+ {
+ /*
+ * Not a valid URI!
+ */
+
+ LogMessage(L_ERROR, "get_job_attrs: bad job-uri attribute \'%s\'!\n",
+ uri->values[0].string.text);
+ send_ipp_error(con, IPP_BAD_REQUEST);
+ return;
+ }
+
+ jobid = atoi(resource + 6);
+ }
+
+ /*
+ * See if the job exists...
+ */
+
+ if ((job = FindJob(jobid)) == NULL)
+ {
+ /*
+ * Nope - return a "not found" error...
+ */
+
+ LogMessage(L_ERROR, "get_job_attrs: job #%d doesn't exist!", jobid);
+ send_ipp_error(con, IPP_NOT_FOUND);
+ return;
+ }
+
+ /*
+ * Put out the standard attributes...
+ */
+
+ snprintf(job_uri, sizeof(job_uri), "http://%s:%d/jobs/%d",
+ ServerName, ntohs(con->http.hostaddr.sin_port),
+ job->id);
+
+ ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", job->id);
+
+ ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI,
+ "job-more-info", NULL, job_uri);
+
+ ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI,
+ "job-uri", NULL, job_uri);
+
+ ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER,
+ "job-printer-up-time", time(NULL));
+
+ /*
+ * Copy the job attributes to the response using the requested-attributes
+ * attribute that may be provided by the client.
+ */
+
+ requested = ippFindAttribute(con->request, "requested-attributes",
+ IPP_TAG_KEYWORD);
+
+ copy_attrs(con->response, job->attrs, requested, IPP_TAG_JOB);
+
+ add_job_state_reasons(con, job);
+
+ if (requested != NULL)
+ con->response->request.status.status_code = IPP_OK_SUBST;
+ else
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'get_ppds()' - Get the list of PPD files on the local system.
+ */
+
+static void
+get_ppds(client_t *con) /* I - Client connection */
+{
+ LogMessage(L_DEBUG2, "get_ppds(%p[%d])\n", con, con->http.fd);
+
+ /*
+ * Copy the PPD attributes to the response using the requested-attributes
+ * attribute that may be provided by the client.
+ */
+
+ copy_attrs(con->response, PPDs,
+ ippFindAttribute(con->request, "requested-attributes",
+ IPP_TAG_KEYWORD), IPP_TAG_ZERO);
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'get_printer_attrs()' - Get printer attributes.
+ */
+
+static void
+get_printer_attrs(client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Printer URI */
+{
+ const char *dest; /* Destination */
+ cups_ptype_t dtype; /* Destination type (printer or class) */
+ char method[HTTP_MAX_URI],
+ /* Method portion of URI */
+ username[HTTP_MAX_URI],
+ /* Username portion of URI */
+ host[HTTP_MAX_URI],
+ /* Host portion of URI */
+ resource[HTTP_MAX_URI];
+ /* Resource portion of URI */
+ int port; /* Port portion of URI */
+ printer_t *printer; /* Printer/class */
+ time_t curtime; /* Current time */
+
+
+ LogMessage(L_DEBUG2, "get_printer_attrs(%p[%d], %s)\n", con, con->http.fd,
+ uri->values[0].string.text);
+
+ /*
+ * Is the destination valid?
+ */
+
+ httpSeparate(uri->values[0].string.text, method, username, host, &port, resource);
+
+ if ((dest = ValidateDest(host, resource, &dtype)) == NULL)
+ {
+ /*
+ * Bad URI...
+ */
+
+ LogMessage(L_ERROR, "get_printer_attrs: resource name \'%s\' no good!", resource);
+ send_ipp_error(con, IPP_NOT_FOUND);
+ return;
+ }
+
+ if (dtype == CUPS_PRINTER_CLASS)
+ printer = FindClass(dest);
+ else
+ printer = FindPrinter(dest);
+
+ curtime = time(NULL);
+
+ /*
+ * Copy the printer attributes to the response using requested-attributes
+ * and document-format attributes that may be provided by the client.
+ */
+
+ ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state",
+ printer->state);
+
+ add_printer_state_reasons(con, printer);
+
+ if (printer->state_message[0])
+ ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_TEXT,
+ "printer-state-message", NULL, printer->state_message);
+
+ ippAddBoolean(con->response, IPP_TAG_PRINTER, "printer-is-accepting-jobs",
+ printer->accepting);
+
+ ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "printer-up-time", curtime);
+ ippAddDate(con->response, IPP_TAG_PRINTER, "printer-current-time",
+ ippTimeToDate(curtime));
+
+ add_queued_job_count(con, printer);
+
+ copy_attrs(con->response, printer->attrs,
+ ippFindAttribute(con->request, "requested-attributes",
+ IPP_TAG_KEYWORD), IPP_TAG_ZERO);
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'get_printers()' - Get a list of printers or classes.
+ */
+
+static void
+get_printers(client_t *con, /* I - Client connection */
+ int type) /* I - 0 or CUPS_PRINTER_CLASS */
+{
+ ipp_attribute_t *attr, /* Current attribute */
+ *requested; /* Requested attributes */
+ int limit; /* Maximum number of printers to return */
+ int count; /* Number of printers that match */
+ printer_t *printer; /* Current printer pointer */
+ time_t curtime; /* Current time */
+ int printer_type, /* printer-type attribute */
+ printer_mask; /* printer-type-mask attribute */
+ char *location; /* Location string */
+ char name[IPP_MAX_NAME],
+ /* Printer name */
+ *nameptr; /* Pointer into name */
+ printer_t *iclass; /* Implicit class */
+
+
+ LogMessage(L_DEBUG2, "get_printers(%p[%d], %x)\n", con, con->http.fd, type);
+
+ /*
+ * See if they want to limit the number of printers reported...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "limit", IPP_TAG_INTEGER)) != NULL)
+ limit = attr->values[0].integer;
+ else
+ limit = 10000000;
+
+ /*
+ * Support filtering...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "printer-type", IPP_TAG_ENUM)) != NULL)
+ printer_type = attr->values[0].integer;
+ else
+ printer_type = 0;
+
+ if ((attr = ippFindAttribute(con->request, "printer-type-mask", IPP_TAG_ENUM)) != NULL)
+ printer_mask = attr->values[0].integer;
+ else
+ printer_mask = 0;
+
+ if ((attr = ippFindAttribute(con->request, "location", IPP_TAG_TEXT)) != NULL)
+ location = attr->values[0].string.text;
+ else
+ location = NULL;
+
+ requested = ippFindAttribute(con->request, "requested-attributes",
+ IPP_TAG_KEYWORD);
+
+ /*
+ * OK, build a list of printers for this printer...
+ */
+
+ curtime = time(NULL);
+
+ for (count = 0, printer = Printers;
+ count < limit && printer != NULL;
+ printer = printer->next)
+ if ((printer->type & CUPS_PRINTER_CLASS) == type &&
+ (printer->type & printer_mask) == printer_type &&
+ (location == NULL || strcasecmp(printer->location, location) == 0))
+ {
+ /*
+ * If HideImplicitMembers is enabled, see if this printer or class
+ * is a member of an implicit class...
+ */
+
+ if (ImplicitClasses && HideImplicitMembers &&
+ (printer->type & CUPS_PRINTER_REMOTE))
+ {
+ /*
+ * Make a copy of the printer name...
+ *
+ * Note: name and printer->name are both IPP_MAX_NAME characters
+ * in size, so strcpy() is safe...
+ */
+
+ strcpy(name, printer->name);
+
+ if ((nameptr = strchr(name, '@')) != NULL)
+ {
+ /*
+ * Strip trailing @server...
+ */
+
+ *nameptr = '\0';
+
+ /*
+ * Find the core printer, if any...
+ */
+
+ if ((iclass = FindPrinter(name)) != NULL &&
+ (iclass->type & CUPS_PRINTER_IMPLICIT))
+ continue;
+ }
+ }
+
+ /*
+ * Add the group separator as needed...
+ */
+
+ if (count > 0)
+ ippAddSeparator(con->response);
+
+ count ++;
+
+ /*
+ * Send the following attributes for each printer:
+ *
+ * printer-state
+ * printer-state-message
+ * printer-is-accepting-jobs
+ * + all printer attributes
+ */
+
+ ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ENUM,
+ "printer-state", printer->state);
+
+ add_printer_state_reasons(con, printer);
+
+ if (printer->state_message[0])
+ ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_TEXT,
+ "printer-state-message", NULL, printer->state_message);
+
+ ippAddBoolean(con->response, IPP_TAG_PRINTER, "printer-is-accepting-jobs",
+ printer->accepting);
+
+ ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "printer-up-time", curtime);
+ ippAddDate(con->response, IPP_TAG_PRINTER, "printer-current-time",
+ ippTimeToDate(curtime));
+
+ add_queued_job_count(con, printer);
+
+ copy_attrs(con->response, printer->attrs, requested, IPP_TAG_ZERO);
+ }
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'hold_job()' - Hold a print job.
+ */
+
+static void
+hold_job(client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Job or Printer URI */
+{
+ ipp_attribute_t *attr, /* Current job-hold-until */
+ *newattr; /* New job-hold-until */
+ int jobid; /* Job ID */
+ char method[HTTP_MAX_URI],
+ /* Method portion of URI */
+ username[HTTP_MAX_URI],
+ /* Username portion of URI */
+ host[HTTP_MAX_URI],
+ /* Host portion of URI */
+ resource[HTTP_MAX_URI];
+ /* Resource portion of URI */
+ int port; /* Port portion of URI */
+ job_t *job; /* Job information */
+
+
+ LogMessage(L_DEBUG2, "hold_job(%p[%d], %s)\n", con, con->http.fd,
+ uri->values[0].string.text);
+
+ /*
+ * Verify that the POST operation was done to a valid URI.
+ */
+
+ if (strncmp(con->uri, "/classes/", 9) != 0 &&
+ strncmp(con->uri, "/jobs/", 5) != 0 &&
+ strncmp(con->uri, "/printers/", 10) != 0)
+ {
+ LogMessage(L_ERROR, "hold_job: hold request on bad resource \'%s\'!",
+ con->uri);
+ send_ipp_error(con, IPP_NOT_AUTHORIZED);
+ return;
+ }
+
+ /*
+ * See if we have a job URI or a printer URI...
+ */
+
+ if (strcmp(uri->name, "printer-uri") == 0)
+ {
+ /*
+ * Got a printer URI; see if we also have a job-id attribute...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "job-id", IPP_TAG_INTEGER)) == NULL)
+ {
+ LogMessage(L_ERROR, "hold_job: got a printer-uri attribute but no job-id!");
+ send_ipp_error(con, IPP_BAD_REQUEST);
+ return;
+ }
+
+ jobid = attr->values[0].integer;
+ }
+ else
+ {
+ /*
+ * Got a job URI; parse it to get the job ID...
+ */
+
+ httpSeparate(uri->values[0].string.text, method, username, host, &port, resource);
+
+ if (strncmp(resource, "/jobs/", 6) != 0)
+ {
+ /*
+ * Not a valid URI!
+ */
+
+ LogMessage(L_ERROR, "hold_job: bad job-uri attribute \'%s\'!",
+ uri->values[0].string.text);
+ send_ipp_error(con, IPP_BAD_REQUEST);
+ return;
+ }
+
+ jobid = atoi(resource + 6);
+ }
+
+ /*
+ * See if the job exists...
+ */
+
+ if ((job = FindJob(jobid)) == NULL)
+ {
+ /*
+ * Nope - return a "not found" error...
+ */
+
+ LogMessage(L_ERROR, "hold_job: job #%d doesn't exist!", jobid);
+ send_ipp_error(con, IPP_NOT_FOUND);
+ return;
+ }
+
+ /*
+ * See if the job is owned by the requesting user...
+ */
+
+ if (!validate_user(con, job->username, username, sizeof(username)))
+ {
+ LogMessage(L_ERROR, "hold_job: \"%s\" not authorized to hold job id %d owned by \"%s\"!",
+ username, jobid, job->username);
+ send_ipp_error(con, IPP_FORBIDDEN);
+ return;
+ }
+
+ /*
+ * Hold the job and return...
+ */
+
+ HoldJob(jobid);
+
+ if ((newattr = ippFindAttribute(con->request, "job-hold-until", IPP_TAG_KEYWORD)) == NULL)
+ newattr = ippFindAttribute(con->request, "job-hold-until", IPP_TAG_NAME);
+
+ if ((attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_KEYWORD)) == NULL)
+ attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);
+
+ if (attr != NULL)
+ {
+ /*
+ * Free the old hold value and copy the new one over...
+ */
+
+ free(attr->values[0].string.text);
+
+ if (newattr != NULL)
+ {
+ attr->value_tag = newattr->value_tag;
+ attr->values[0].string.text = strdup(newattr->values[0].string.text);
+ }
+ else
+ {
+ attr->value_tag = IPP_TAG_KEYWORD;
+ attr->values[0].string.text = strdup("indefinite");
+ }
+
+ /*
+ * Hold job until specified time...
+ */
+
+ SetJobHoldUntil(job->id, attr->values[0].string.text);
+ }
+
+ LogMessage(L_INFO, "Job %d was held by \'%s\'.", jobid, username);
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'move_job()' - Move a job to a new destination.
+ */
+
+static void
+move_job(client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Job URI */
+{
+ ipp_attribute_t *attr; /* Current attribute */
+ int jobid; /* Job ID */
+ job_t *job; /* Current job */
+ const char *dest; /* Destination */
+ cups_ptype_t dtype; /* Destination type (printer or class) */
+ char method[HTTP_MAX_URI],
+ /* Method portion of URI */
+ username[HTTP_MAX_URI],
+ /* Username portion of URI */
+ host[HTTP_MAX_URI],
+ /* Host portion of URI */
+ resource[HTTP_MAX_URI];
+ /* Resource portion of URI */
+ int port; /* Port portion of URI */
+
+
+ LogMessage(L_DEBUG2, "move_job(%p[%d], %s)\n", con, con->http.fd,
+ uri->values[0].string.text);
+
+ /*
+ * See if we have a job URI or a printer URI...
+ */
+
+ if (strcmp(uri->name, "printer-uri") == 0)
+ {
+ /*
+ * Got a printer URI; see if we also have a job-id attribute...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "job-id", IPP_TAG_INTEGER)) == NULL)
+ {
+ LogMessage(L_ERROR, "move_job: got a printer-uri attribute but no job-id!");
+ send_ipp_error(con, IPP_BAD_REQUEST);
+ return;
+ }
+
+ jobid = attr->values[0].integer;
+ }
+ else
+ {
+ /*
+ * Got a job URI; parse it to get the job ID...
+ */
+
+ httpSeparate(uri->values[0].string.text, method, username, host, &port, resource);
+
+ if (strncmp(resource, "/jobs/", 6) != 0)
+ {
+ /*
+ * Not a valid URI!
+ */
+
+ LogMessage(L_ERROR, "move_job: bad job-uri attribute \'%s\'!\n",
+ uri->values[0].string.text);
+ send_ipp_error(con, IPP_BAD_REQUEST);
+ return;
+ }
+
+ jobid = atoi(resource + 6);
+ }
+
+ /*
+ * See if the job exists...
+ */
+
+ if ((job = FindJob(jobid)) == NULL)
+ {
+ /*
+ * Nope - return a "not found" error...
+ */
+
+ LogMessage(L_ERROR, "move_job: job #%d doesn't exist!", jobid);
+ send_ipp_error(con, IPP_NOT_FOUND);
+ return;
+ }
+
+ /*
+ * See if the job has been completed...
+ */
+
+ if (job->state->values[0].integer > IPP_JOB_STOPPED)
+ {
+ /*
+ * Return a "not-possible" error...
+ */
+
+ LogMessage(L_ERROR, "move_job: job #%d is finished and cannot be altered!", jobid);
+ send_ipp_error(con, IPP_NOT_POSSIBLE);
+ return;
+ }
+
+ /*
+ * See if the job is owned by the requesting user...
+ */
+
+ if (!validate_user(con, job->username, username, sizeof(username)))
+ {
+ LogMessage(L_ERROR, "move_job: \"%s\" not authorized to move job id %d owned by \"%s\"!",
+ username, jobid, job->username);
+ send_ipp_error(con, IPP_FORBIDDEN);
+ return;
+ }
+
+ if ((attr = ippFindAttribute(con->request, "job-printer-uri", IPP_TAG_URI)) == NULL)
+ {
+ /*
+ * Need job-printer-uri...
+ */
+
+ LogMessage(L_ERROR, "move_job: job-printer-uri attribute missing!");
+ send_ipp_error(con, IPP_BAD_REQUEST);
+ return;
+ }
+
+ /*
+ * Move the job to a different printer or class...
+ */
+
+ httpSeparate(attr->values[0].string.text, method, username, host, &port,
+ resource);
+ if ((dest = ValidateDest(host, resource, &dtype)) == NULL)
+ {
+ /*
+ * Bad URI...
+ */
+
+ LogMessage(L_ERROR, "move_job: resource name \'%s\' no good!", resource);
+ send_ipp_error(con, IPP_NOT_FOUND);
+ return;
+ }
+
+ MoveJob(jobid, dest);
+
+ /*
+ * Start jobs if possible...
+ */
+
+ CheckJobs();
+
+ /*
+ * Return with "everything is OK" status...
+ */
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'print_job()' - Print a file to a printer or class.
+ */
+
+static void
+print_job(client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Printer URI */
+{
+ ipp_attribute_t *attr; /* Current attribute */
+ ipp_attribute_t *format; /* Document-format attribute */
+ const char *dest; /* Destination */
+ cups_ptype_t dtype; /* Destination type (printer or class) */
+ int priority; /* Job priority */
+ char *title; /* Job name/title */
+ job_t *job; /* Current job */
+ char job_uri[HTTP_MAX_URI],
+ /* Job URI */
+ printer_uri[HTTP_MAX_URI],
+ /* Printer URI */
+ method[HTTP_MAX_URI],
+ /* Method portion of URI */
+ username[HTTP_MAX_URI],
+ /* Username portion of URI */
+ host[HTTP_MAX_URI],
+ /* Host portion of URI */
+ resource[HTTP_MAX_URI],
+ /* Resource portion of URI */
+ filename[1024]; /* Job filename */
+ int port; /* Port portion of URI */
+ mime_type_t *filetype; /* Type of file */
+ char super[MIME_MAX_SUPER],
+ /* Supertype of file */
+ type[MIME_MAX_TYPE],
+ /* Subtype of file */
+ mimetype[MIME_MAX_SUPER + MIME_MAX_TYPE + 2];
+ /* Textual name of mime type */
+ printer_t *printer; /* Printer data */
+ struct stat fileinfo; /* File information */
+ int kbytes; /* Size of file */
+
+
+ LogMessage(L_DEBUG2, "print_job(%p[%d], %s)\n", con, con->http.fd,
+ uri->values[0].string.text);
+
+ /*
+ * Verify that the POST operation was done to a valid URI.
+ */
+
+ if (strncmp(con->uri, "/classes/", 9) != 0 &&
+ strncmp(con->uri, "/printers/", 10) != 0)
+ {
+ LogMessage(L_ERROR, "print_job: cancel request on bad resource \'%s\'!",
+ con->uri);
+ send_ipp_error(con, IPP_NOT_AUTHORIZED);
+ return;
+ }
+
+ /*
+ * OK, see if the client is sending the document compressed - CUPS
+ * doesn't support compression yet...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "compression", IPP_TAG_KEYWORD)) != NULL &&
+ strcmp(attr->values[0].string.text, "none") == 0)
+ {
+ LogMessage(L_ERROR, "print_job: Unsupported compression attribute %s!",
+ attr->values[0].string.text);
+ send_ipp_error(con, IPP_ATTRIBUTES);
+ ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_KEYWORD,
+ "compression", NULL, attr->values[0].string.text);
+ return;
+ }
+
+ /*
+ * Do we have a file to print?
+ */
+
+ if (con->filename[0] == '\0')
+ {
+ LogMessage(L_ERROR, "print_job: No file!?!");
+ send_ipp_error(con, IPP_BAD_REQUEST);
+ return;
+ }
+
+ /*
+ * Is it a format we support?
+ */
+
+ if ((format = ippFindAttribute(con->request, "document-format", IPP_TAG_MIMETYPE)) != NULL)
+ {
+ /*
+ * Grab format from client...
+ */
+
+ if (sscanf(format->values[0].string.text, "%15[^/]/%31[^;]", super, type) != 2)
+ {
+ LogMessage(L_ERROR, "print_job: could not scan type \'%s\'!",
+ format->values[0].string.text);
+ send_ipp_error(con, IPP_BAD_REQUEST);
+ return;
+ }
+ }
+ else
+ {
+ /*
+ * No document format attribute? Auto-type it!
+ */
+
+ strcpy(super, "application");
+ strcpy(type, "octet-stream");
+ }
+
+ if (strcmp(super, "application") == 0 &&
+ strcmp(type, "octet-stream") == 0)
+ {
+ /*
+ * Auto-type the file...
+ */
+
+ LogMessage(L_DEBUG, "print_job: auto-typing file...");
+
+ filetype = mimeFileType(MimeDatabase, con->filename);
+
+ if (filetype != NULL)
+ {
+ /*
+ * Replace the document-format attribute value with the auto-typed one.
+ */
+
+ snprintf(mimetype, sizeof(mimetype), "%s/%s", filetype->super,
+ filetype->type);
+
+ if (format != NULL)
+ {
+ free(format->values[0].string.text);
+ format->values[0].string.text = strdup(mimetype);
+ }
+ else
+ ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_MIMETYPE,
+ "document-format", NULL, mimetype);
+ }
+ else
+ filetype = mimeType(MimeDatabase, super, type);
+ }
+ else
+ filetype = mimeType(MimeDatabase, super, type);
+
+ if (filetype == NULL)
+ {
+ LogMessage(L_ERROR, "print_job: Unsupported format \'%s/%s\'!",
+ super, type);
+ send_ipp_error(con, IPP_DOCUMENT_FORMAT);
+
+ if (format)
+ ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_MIMETYPE,
+ "document-format", NULL, format->values[0].string.text);
+
+ return;
+ }
+
+ LogMessage(L_DEBUG, "print_job: request file type is %s/%s.",
+ filetype->super, filetype->type);
+
+ /*
+ * Is the destination valid?
+ */
+
+ httpSeparate(uri->values[0].string.text, method, username, host, &port, resource);
+
+ if ((dest = ValidateDest(host, resource, &dtype)) == NULL)
+ {
+ /*
+ * Bad URI...
+ */
+
+ LogMessage(L_ERROR, "print_job: resource name \'%s\' no good!", resource);
+ send_ipp_error(con, IPP_NOT_FOUND);
+ return;
+ }
+
+ /*
+ * See if the printer is accepting jobs...
+ */
+
+ if (dtype == CUPS_PRINTER_CLASS)
+ {
+ printer = FindClass(dest);
+ snprintf(printer_uri, sizeof(printer_uri), "http://%s:%d/classes/%s",
+ ServerName, ntohs(con->http.hostaddr.sin_port), dest);
+ }
+ else
+ {
+ printer = FindPrinter(dest);
+
+ snprintf(printer_uri, sizeof(printer_uri), "http://%s:%d/printers/%s",
+ ServerName, ntohs(con->http.hostaddr.sin_port), dest);
+ }
+
+ if (!printer->accepting)
+ {
+ LogMessage(L_INFO, "print_job: destination \'%s\' is not accepting jobs.",
+ dest);
+ send_ipp_error(con, IPP_NOT_ACCEPTING);
+ return;
+ }
+
+ /*
+ * Make sure we aren't over our limit...
+ */
+
+ if (NumJobs >= MaxJobs && MaxJobs)
+ CleanJobs();
+
+ if (NumJobs >= MaxJobs && MaxJobs)
+ {
+ LogMessage(L_INFO, "print_job: too many jobs.");
+ send_ipp_error(con, IPP_NOT_POSSIBLE);
+ return;
+ }
+
+ if (!check_quotas(con, printer))
+ {
+ send_ipp_error(con, IPP_NOT_POSSIBLE);
+ return;
+ }
+
+ /*
+ * Create the job and set things up...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "job-priority", IPP_TAG_INTEGER)) != NULL)
+ priority = attr->values[0].integer;
+ else
+ ippAddInteger(con->request, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-priority",
+ priority = 50);
+
+ if ((attr = ippFindAttribute(con->request, "job-name", IPP_TAG_NAME)) != NULL)
+ title = attr->values[0].string.text;
+ else
+ ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_NAME, "job-name", NULL,
+ title = "Untitled");
+
+ if ((job = AddJob(priority, printer->name)) == NULL)
+ {
+ LogMessage(L_ERROR, "print_job: unable to add job for destination \'%s\'!",
+ dest);
+ send_ipp_error(con, IPP_INTERNAL_ERROR);
+ return;
+ }
+
+ job->dtype = dtype;
+ job->attrs = con->request;
+ con->request = NULL;
+
+ /*
+ * Copy the rest of the job info...
+ */
+
+ strncpy(job->title, title, sizeof(job->title) - 1);
+
+ attr = ippFindAttribute(job->attrs, "requesting-user-name", IPP_TAG_NAME);
+
+ if (con->username[0])
+ {
+ strncpy(job->username, con->username, sizeof(job->username) - 1);
+ job->username[sizeof(job->username) - 1] = '\0';
+ }
+ if (attr != NULL)
+ {
+ LogMessage(L_DEBUG, "print_job: requesting-user-name = \'%s\'",
+ attr->values[0].string.text);
+
+ strncpy(job->username, attr->values[0].string.text, sizeof(job->username) - 1);
+ job->username[sizeof(job->username) - 1] = '\0';
+ }
+ else
+ strcpy(job->username, "anonymous");
+
+ if (attr == NULL)
+ ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, "job-originating-user-name",
+ NULL, job->username);
+ else
+ {
+ attr->group_tag = IPP_TAG_JOB;
+ free(attr->name);
+ attr->name = strdup("job-originating-user-name");
+ }
+
+ /*
+ * Add remaining job attributes...
+ */
+
+ ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME,
+ "job-originating-host-name", NULL, con->http.hostname);
+ ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", job->id);
+ job->state = ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_ENUM,
+ "job-state", IPP_JOB_PENDING);
+ job->sheets = ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER,
+ "job-media-sheets-completed", 0);
+ ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-printer-uri", NULL,
+ printer_uri);
+ ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, "job-name", NULL,
+ title);
+
+ if ((attr = ippFindAttribute(job->attrs, "job-k-octets", IPP_TAG_INTEGER)) == NULL)
+ attr = ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER,
+ "job-k-octets", 0);
+
+ if (stat(con->filename, &fileinfo))
+ kbytes = 0;
+ else
+ kbytes = (fileinfo.st_size + 1023) / 1024;
+
+ UpdateQuota(printer, job->username, 0, kbytes);
+ attr->values[0].integer += kbytes;
+
+ ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "time-at-creation",
+ time(NULL));
+ attr = ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER,
+ "time-at-processing", 0);
+ attr->value_tag = IPP_TAG_NOVALUE;
+ attr = ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER,
+ "time-at-completed", 0);
+ attr->value_tag = IPP_TAG_NOVALUE;
+
+ if ((attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_KEYWORD)) == NULL)
+ attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);
+ if (attr == NULL)
+ attr = ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_KEYWORD,
+ "job-hold-until", NULL, "no-hold");
+
+ if (attr != NULL && strcmp(attr->values[0].string.text, "no-hold") != 0 &&
+ !(printer->type & CUPS_PRINTER_REMOTE))
+ {
+ /*
+ * Hold job until specified time...
+ */
+
+ job->state->values[0].integer = IPP_JOB_HELD;
+ SetJobHoldUntil(job->id, attr->values[0].string.text);
+ }
+
+ if (!(printer->type & CUPS_PRINTER_REMOTE) || Classification[0])
+ {
+ /*
+ * Add job sheets options...
+ */
+
+ if ((attr = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_ZERO)) == NULL)
+ {
+ LogMessage(L_DEBUG, "Adding default job-sheets values \"%s,%s\"...",
+ printer->job_sheets[0], printer->job_sheets[1]);
+
+ attr = ippAddStrings(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, "job-sheets",
+ 2, NULL, NULL);
+ attr->values[0].string.text = strdup(printer->job_sheets[0]);
+ attr->values[1].string.text = strdup(printer->job_sheets[1]);
+ }
+
+ job->job_sheets = attr;
+
+ /*
+ * Enforce classification level if set...
+ */
+
+ if (Classification[0])
+ {
+ if (ClassifyOverride)
+ {
+ if (strcmp(attr->values[0].string.text, "none") == 0 &&
+ (attr->num_values == 1 ||
+ strcmp(attr->values[1].string.text, "none") == 0))
+ {
+ /*
+ * Force the leading banner to have the classification on it...
+ */
+
+ free(attr->values[0].string.text);
+ attr->values[0].string.text = strdup(Classification);
+ }
+ else if (attr->num_values == 2 &&
+ strcmp(attr->values[0].string.text, attr->values[1].string.text) != 0 &&
+ strcmp(attr->values[0].string.text, "none") != 0 &&
+ strcmp(attr->values[1].string.text, "none") != 0)
+ {
+ /*
+ * Can't put two different security markings on the same document!
+ */
+
+ free(attr->values[1].string.text);
+ attr->values[1].string.text = strdup(attr->values[0].string.text);
+ }
+ }
+ else if (strcmp(attr->values[0].string.text, Classification) != 0 &&
+ (attr->num_values == 1 ||
+ strcmp(attr->values[1].string.text, Classification) != 0))
+ {
+ /*
+ * Force the leading banner to have the classification on it...
+ */
+
+ free(attr->values[0].string.text);
+ attr->values[0].string.text = strdup(Classification);
+ }
+ }
+
+ /*
+ * Add the starting sheet...
+ */
+
+ if (!(printer->type & CUPS_PRINTER_REMOTE))
+ {
+ kbytes = copy_banner(con, job, attr->values[0].string.text);
+
+ UpdateQuota(printer, job->username, 0, kbytes);
+ }
+ }
+ else if ((attr = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_ZERO)) != NULL)
+ job->sheets = attr;
+
+ /*
+ * Add the job file...
+ */
+
+ if (add_file(con, job, filetype))
+ return;
+
+ snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot, job->id,
+ job->num_files);
+ rename(con->filename, filename);
+ con->filename[0] = '\0';
+
+ /*
+ * See if we need to add the ending sheet...
+ */
+
+ if (!(printer->type & CUPS_PRINTER_REMOTE) && attr->num_values > 1)
+ {
+ /*
+ * Yes...
+ */
+
+ kbytes = copy_banner(con, job, attr->values[1].string.text);
+ UpdateQuota(printer, job->username, 0, kbytes);
+ }
+
+ /*
+ * Log and save the job...
+ */
+
+ LogMessage(L_INFO, "Job %d queued on \'%s\' by \'%s\'.", job->id,
+ job->dest, job->username);
+ LogMessage(L_DEBUG, "Job %d hold_until = %d", job->id, job->hold_until);
+
+ SaveJob(job->id);
+
+ /*
+ * Start the job if possible...
+ */
+
+ CheckJobs();
+
+ /*
+ * Fill in the response info...
+ */
+
+ snprintf(job_uri, sizeof(job_uri), "http://%s:%d/jobs/%d", ServerName,
+ ntohs(con->http.hostaddr.sin_port), job->id);
+ ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI, "job-uri", NULL, job_uri);
+
+ ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", job->id);
+
+ ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_ENUM, "job-state",
+ job->state->values[0].integer);
+ add_job_state_reasons(con, job);
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'reject_jobs()' - Reject print jobs to a printer.
+ */
+
+static void
+reject_jobs(client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Printer or class URI */
+{
+ cups_ptype_t dtype; /* Destination type (printer or class) */
+ char method[HTTP_MAX_URI],
+ /* Method portion of URI */
+ username[HTTP_MAX_URI],
+ /* Username portion of URI */
+ host[HTTP_MAX_URI],
+ /* Host portion of URI */
+ resource[HTTP_MAX_URI];
+ /* Resource portion of URI */
+ int port; /* Port portion of URI */
+ const char *name; /* Printer name */
+ printer_t *printer; /* Printer data */
+ ipp_attribute_t *attr; /* printer-state-message text */
+
+
+ LogMessage(L_DEBUG2, "reject_jobs(%p[%d], %s)\n", con, con->http.fd,
+ uri->values[0].string.text);
+
+ /*
+ * Was this operation called from the correct URI?
+ */
+
+ if (strncmp(con->uri, "/admin/", 7) != 0)
+ {
+ LogMessage(L_ERROR, "reject_jobs: admin request on bad resource \'%s\'!",
+ con->uri);
+ send_ipp_error(con, IPP_NOT_AUTHORIZED);
+ return;
+ }
+
+ /*
+ * Is the destination valid?
+ */
+
+ httpSeparate(uri->values[0].string.text, method, username, host, &port, resource);
+
+ if ((name = ValidateDest(host, resource, &dtype)) == NULL)
+ {
+ /*
+ * Bad URI...
+ */
+
+ LogMessage(L_ERROR, "reject_jobs: resource name \'%s\' no good!", resource);
+ send_ipp_error(con, IPP_NOT_FOUND);
+ return;
+ }
+
+ /*
+ * Reject jobs sent to the printer...
+ */
+
+ if (dtype == CUPS_PRINTER_CLASS)
+ printer = FindClass(name);
+ else
+ printer = FindPrinter(name);
+
+ printer->accepting = 0;
+
+ if ((attr = ippFindAttribute(con->request, "printer-state-message",
+ IPP_TAG_TEXT)) == NULL)
+ strcpy(printer->state_message, "Rejecting Jobs");
+ else
+ {
+ strncpy(printer->state_message, attr->values[0].string.text,
+ sizeof(printer->state_message) - 1);
+ printer->state_message[sizeof(printer->state_message) - 1] = '\0';
+ }
+
+ if (dtype == CUPS_PRINTER_CLASS)
+ SaveAllClasses();
+ else
+ SaveAllPrinters();
+
+ if (dtype == CUPS_PRINTER_CLASS)
+ LogMessage(L_INFO, "Class \'%s\' rejecting jobs (\'%s\').", name,
+ con->username);
+ else
+ LogMessage(L_INFO, "Printer \'%s\' rejecting jobs (\'%s\').", name,
+ con->username);
+
+ /*
+ * Everything was ok, so return OK status...
+ */
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'release_job()' - Release a held print job.
+ */
+
+static void
+release_job(client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Job or Printer URI */
+{
+ ipp_attribute_t *attr; /* Current attribute */
+ int jobid; /* Job ID */
+ char method[HTTP_MAX_URI],
+ /* Method portion of URI */
+ username[HTTP_MAX_URI],
+ /* Username portion of URI */
+ host[HTTP_MAX_URI],
+ /* Host portion of URI */
+ resource[HTTP_MAX_URI];
+ /* Resource portion of URI */
+ int port; /* Port portion of URI */
+ job_t *job; /* Job information */
+
+
+ LogMessage(L_DEBUG2, "release_job(%p[%d], %s)\n", con, con->http.fd,
+ uri->values[0].string.text);
+
+ /*
+ * Verify that the POST operation was done to a valid URI.
+ */
+
+ if (strncmp(con->uri, "/classes/", 9) != 0 &&
+ strncmp(con->uri, "/jobs/", 5) != 0 &&
+ strncmp(con->uri, "/printers/", 10) != 0)
+ {
+ LogMessage(L_ERROR, "release_job: release request on bad resource \'%s\'!",
+ con->uri);
+ send_ipp_error(con, IPP_NOT_AUTHORIZED);
+ return;
+ }
+
+ /*
+ * See if we have a job URI or a printer URI...
+ */
+
+ if (strcmp(uri->name, "printer-uri") == 0)
+ {
+ /*
+ * Got a printer URI; see if we also have a job-id attribute...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "job-id", IPP_TAG_INTEGER)) == NULL)
+ {
+ LogMessage(L_ERROR, "release_job: got a printer-uri attribute but no job-id!");
+ send_ipp_error(con, IPP_BAD_REQUEST);
+ return;
+ }
+
+ jobid = attr->values[0].integer;
+ }
+ else
+ {
+ /*
+ * Got a job URI; parse it to get the job ID...
+ */
+
+ httpSeparate(uri->values[0].string.text, method, username, host, &port, resource);
+
+ if (strncmp(resource, "/jobs/", 6) != 0)
+ {
+ /*
+ * Not a valid URI!
+ */
+
+ LogMessage(L_ERROR, "release_job: bad job-uri attribute \'%s\'!",
+ uri->values[0].string.text);
+ send_ipp_error(con, IPP_BAD_REQUEST);
+ return;
+ }
+
+ jobid = atoi(resource + 6);
+ }
+
+ /*
+ * See if the job exists...
+ */
+
+ if ((job = FindJob(jobid)) == NULL)
+ {
+ /*
+ * Nope - return a "not found" error...
+ */
+
+ LogMessage(L_ERROR, "release_job: job #%d doesn't exist!", jobid);
+ send_ipp_error(con, IPP_NOT_FOUND);
+ return;
+ }
+
+ /*
+ * See if job is "held"...
+ */
+
+ if (job->state->values[0].integer != IPP_JOB_HELD)
+ {
+ /*
+ * Nope - return a "not possible" error...
+ */
+
+ LogMessage(L_ERROR, "release_job: job #%d is not held!", jobid);
+ send_ipp_error(con, IPP_NOT_POSSIBLE);
+ return;
+ }
+
+ /*
+ * See if the job is owned by the requesting user...
+ */
+
+ if (!validate_user(con, job->username, username, sizeof(username)))
+ {
+ LogMessage(L_ERROR, "release_job: \"%s\" not authorized to release job id %d owned by \"%s\"!",
+ username, jobid, job->username);
+ send_ipp_error(con, IPP_FORBIDDEN);
+ return;
+ }
+
+ /*
+ * Reset the job-hold-until value to "no-hold"...
+ */
+
+ if ((attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_KEYWORD)) == NULL)
+ attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);
+
+ if (attr != NULL)
+ {
+ free(attr->values[0].string.text);
+ attr->value_tag = IPP_TAG_KEYWORD;
+ attr->values[0].string.text = strdup("no-hold");
+ }
+
+ /*
+ * Release the job and return...
+ */
+
+ ReleaseJob(jobid);
+
+ LogMessage(L_INFO, "Job %d was released by \'%s\'.", jobid, username);
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'restart_job()' - Restart an old print job.
+ */
+
+static void
+restart_job(client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Job or Printer URI */
+{
+ ipp_attribute_t *attr; /* Current attribute */
+ int jobid; /* Job ID */
+ char method[HTTP_MAX_URI],
+ /* Method portion of URI */
+ username[HTTP_MAX_URI],
+ /* Username portion of URI */
+ host[HTTP_MAX_URI],
+ /* Host portion of URI */
+ resource[HTTP_MAX_URI];
+ /* Resource portion of URI */
+ int port; /* Port portion of URI */
+ job_t *job; /* Job information */
+
+
+ LogMessage(L_DEBUG2, "restart_job(%p[%d], %s)\n", con, con->http.fd,
+ uri->values[0].string.text);
+
+ /*
+ * Verify that the POST operation was done to a valid URI.
+ */
+
+ if (strncmp(con->uri, "/classes/", 9) != 0 &&
+ strncmp(con->uri, "/jobs/", 5) != 0 &&
+ strncmp(con->uri, "/printers/", 10) != 0)
+ {
+ LogMessage(L_ERROR, "restart_job: restart request on bad resource \'%s\'!",
+ con->uri);
+ send_ipp_error(con, IPP_NOT_AUTHORIZED);
+ return;
+ }
+
+ /*
+ * See if we have a job URI or a printer URI...
+ */
+
+ if (strcmp(uri->name, "printer-uri") == 0)
+ {
+ /*
+ * Got a printer URI; see if we also have a job-id attribute...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "job-id", IPP_TAG_INTEGER)) == NULL)
+ {
+ LogMessage(L_ERROR, "restart_job: got a printer-uri attribute but no job-id!");
+ send_ipp_error(con, IPP_BAD_REQUEST);
+ return;
+ }
+
+ jobid = attr->values[0].integer;
+ }
+ else
+ {
+ /*
+ * Got a job URI; parse it to get the job ID...
+ */
+
+ httpSeparate(uri->values[0].string.text, method, username, host, &port, resource);
+
+ if (strncmp(resource, "/jobs/", 6) != 0)
+ {
+ /*
+ * Not a valid URI!
+ */
+
+ LogMessage(L_ERROR, "restart_job: bad job-uri attribute \'%s\'!",
+ uri->values[0].string.text);
+ send_ipp_error(con, IPP_BAD_REQUEST);
+ return;
+ }
+
+ jobid = atoi(resource + 6);
+ }
+
+ /*
+ * See if the job exists...
+ */
+
+ if ((job = FindJob(jobid)) == NULL)
+ {
+ /*
+ * Nope - return a "not found" error...
+ */
+
+ LogMessage(L_ERROR, "restart_job: job #%d doesn't exist!", jobid);
+ send_ipp_error(con, IPP_NOT_FOUND);
+ return;
+ }
+
+ /*
+ * See if job is in any of the "completed" states...
+ */
+
+ if (job->state->values[0].integer <= IPP_JOB_PROCESSING)
+ {
+ /*
+ * Nope - return a "not possible" error...
+ */
+
+ LogMessage(L_ERROR, "restart_job: job #%d is not complete!", jobid);
+ send_ipp_error(con, IPP_NOT_POSSIBLE);
+ return;
+ }
+
+ /*
+ * See if we have retained the job files...
+ */
+
+ if (!JobFiles && job->state->values[0].integer > IPP_JOB_STOPPED)
+ {
+ /*
+ * Nope - return a "not possible" error...
+ */
+
+ LogMessage(L_ERROR, "restart_job: job #%d cannot be restarted - no files!", jobid);
+ send_ipp_error(con, IPP_NOT_POSSIBLE);
+ return;
+ }
+
+ /*
+ * See if the job is owned by the requesting user...
+ */
+
+ if (!validate_user(con, job->username, username, sizeof(username)))
+ {
+ LogMessage(L_ERROR, "restart_job: \"%s\" not authorized to restart job id %d owned by \"%s\"!",
+ username, jobid, job->username);
+ send_ipp_error(con, IPP_FORBIDDEN);
+ return;
+ }
+
+ /*
+ * Restart the job and return...
+ */
+
+ RestartJob(jobid);
+
+ LogMessage(L_INFO, "Job %d was restarted by \'%s\'.", jobid, username);
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'send_document()' - Send a file to a printer or class.
+ */
+
+static void
+send_document(client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Printer URI */
+{
+ ipp_attribute_t *attr; /* Current attribute */
+ ipp_attribute_t *format; /* Document-format attribute */
+ int jobid; /* Job ID number */
+ job_t *job; /* Current job */
+ char job_uri[HTTP_MAX_URI],
+ /* Job URI */
+ method[HTTP_MAX_URI],
+ /* Method portion of URI */
+ username[HTTP_MAX_URI],
+ /* Username portion of URI */
+ host[HTTP_MAX_URI],
+ /* Host portion of URI */
+ resource[HTTP_MAX_URI];
+ /* Resource portion of URI */
+ int port; /* Port portion of URI */
+ mime_type_t *filetype; /* Type of file */
+ char super[MIME_MAX_SUPER],
+ /* Supertype of file */
+ type[MIME_MAX_TYPE],
+ /* Subtype of file */
+ mimetype[MIME_MAX_SUPER + MIME_MAX_TYPE + 2];
+ /* Textual name of mime type */
+ char filename[1024]; /* Job filename */
+ printer_t *printer; /* Current printer */
+ struct stat fileinfo; /* File information */
+ int kbytes; /* Size of file */
+
+
+ LogMessage(L_DEBUG2, "send_document(%p[%d], %s)\n", con, con->http.fd,
+ uri->values[0].string.text);
+
+ /*
+ * Verify that the POST operation was done to a valid URI.
+ */
+
+ if (strncmp(con->uri, "/classes/", 9) != 0 &&
+ strncmp(con->uri, "/jobs/", 6) != 0 &&
+ strncmp(con->uri, "/printers/", 10) != 0)
+ {
+ LogMessage(L_ERROR, "send_document: print request on bad resource \'%s\'!",
+ con->uri);
+ send_ipp_error(con, IPP_NOT_AUTHORIZED);
+ return;
+ }
+
+ /*
+ * See if we have a job URI or a printer URI...
+ */
+
+ if (strcmp(uri->name, "printer-uri") == 0)
+ {
+ /*
+ * Got a printer URI; see if we also have a job-id attribute...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "job-id", IPP_TAG_INTEGER)) == NULL)
+ {
+ LogMessage(L_ERROR, "send_document: got a printer-uri attribute but no job-id!");
+ send_ipp_error(con, IPP_BAD_REQUEST);
+ return;
+ }
+
+ jobid = attr->values[0].integer;
+ }
+ else
+ {
+ /*
+ * Got a job URI; parse it to get the job ID...
+ */
+
+ httpSeparate(uri->values[0].string.text, method, username, host, &port, resource);
+
+ if (strncmp(resource, "/jobs/", 6) != 0)
+ {
+ /*
+ * Not a valid URI!
+ */
+
+ LogMessage(L_ERROR, "send_document: bad job-uri attribute \'%s\'!",
+ uri->values[0].string.text);
+ send_ipp_error(con, IPP_BAD_REQUEST);
+ return;
+ }
+
+ jobid = atoi(resource + 6);
+ }
+
+ /*
+ * See if the job exists...
+ */
+
+ if ((job = FindJob(jobid)) == NULL)
+ {
+ /*
+ * Nope - return a "not found" error...
+ */
+
+ LogMessage(L_ERROR, "send_document: job #%d doesn't exist!", jobid);
+ send_ipp_error(con, IPP_NOT_FOUND);
+ return;
+ }
+
+ /*
+ * See if the job is owned by the requesting user...
+ */
+
+ if (!validate_user(con, job->username, username, sizeof(username)))
+ {
+ LogMessage(L_ERROR, "send_document: \"%s\" not authorized to send document for job id %d owned by \"%s\"!",
+ username, jobid, job->username);
+ send_ipp_error(con, IPP_FORBIDDEN);
+ return;
+ }
+
+ /*
+ * OK, see if the client is sending the document compressed - CUPS
+ * doesn't support compression yet...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "compression", IPP_TAG_KEYWORD)) != NULL &&
+ strcmp(attr->values[0].string.text, "none") == 0)
+ {
+ LogMessage(L_ERROR, "send_document: Unsupported compression attribute %s!",
+ attr->values[0].string.text);
+ send_ipp_error(con, IPP_ATTRIBUTES);
+ ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_KEYWORD,
+ "compression", NULL, attr->values[0].string.text);
+ return;
+ }
+
+ /*
+ * Do we have a file to print?
+ */
+
+ if (con->filename[0] == '\0')
+ {
+ LogMessage(L_ERROR, "send_document: No file!?!");
+ send_ipp_error(con, IPP_BAD_REQUEST);
+ return;
+ }
+
+ /*
+ * Is it a format we support?
+ */
+
+ if ((format = ippFindAttribute(con->request, "document-format", IPP_TAG_MIMETYPE)) != NULL)
+ {
+ /*
+ * Grab format from client...
+ */
+
+ if (sscanf(format->values[0].string.text, "%15[^/]/%31[^;]", super, type) != 2)
+ {
+ LogMessage(L_ERROR, "send_document: could not scan type \'%s\'!",
+ format->values[0].string.text);
+ send_ipp_error(con, IPP_BAD_REQUEST);
+ return;
+ }
+ }
+ else
+ {
+ /*
+ * No document format attribute? Auto-type it!
+ */
+
+ strcpy(super, "application");
+ strcpy(type, "octet-stream");
+ }
+
+ if (strcmp(super, "application") == 0 &&
+ strcmp(type, "octet-stream") == 0)
+ {
+ /*
+ * Auto-type the file...
+ */
+
+ LogMessage(L_DEBUG, "send_document: auto-typing file...");
+
+ filetype = mimeFileType(MimeDatabase, con->filename);
+
+ if (filetype != NULL)
+ {
+ /*
+ * Replace the document-format attribute value with the auto-typed one.
+ */
+
+ snprintf(mimetype, sizeof(mimetype), "%s/%s", filetype->super,
+ filetype->type);
+
+ if (format != NULL)
+ {
+ free(format->values[0].string.text);
+ format->values[0].string.text = strdup(mimetype);
+ }
+ else
+ ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_MIMETYPE,
+ "document-format", NULL, mimetype);
+ }
+ else
+ filetype = mimeType(MimeDatabase, super, type);
+ }
+ else
+ filetype = mimeType(MimeDatabase, super, type);
+
+ if (filetype == NULL)
+ {
+ LogMessage(L_ERROR, "send_document: Unsupported format \'%s/%s\'!",
+ super, type);
+ send_ipp_error(con, IPP_DOCUMENT_FORMAT);
+
+ if (format)
+ ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_MIMETYPE,
+ "document-format", NULL, format->values[0].string.text);
+
+ return;
+ }
+
+ LogMessage(L_DEBUG, "send_document: request file type is %s/%s.",
+ filetype->super, filetype->type);
+
+ /*
+ * Add the file to the job...
+ */
+
+ if (add_file(con, job, filetype))
+ return;
+
+ if (job->dtype & CUPS_PRINTER_CLASS)
+ printer = FindClass(job->dest);
+ else
+ printer = FindPrinter(job->dest);
+
+ if (stat(con->filename, &fileinfo))
+ kbytes = 0;
+ else
+ kbytes = (fileinfo.st_size + 1023) / 1024;
+
+ UpdateQuota(printer, job->username, 0, kbytes);
+
+ if ((attr = ippFindAttribute(job->attrs, "job-k-octets", IPP_TAG_INTEGER)) != NULL)
+ attr->values[0].integer += kbytes;
+
+ snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot, job->id,
+ job->num_files);
+ rename(con->filename, filename);
+
+ con->filename[0] = '\0';
+
+ LogMessage(L_INFO, "File of type %s/%s queued in job #%d by \'%s\'.",
+ filetype->super, filetype->type, job->id, job->username);
+
+ /*
+ * Start the job if this is the last document...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "last-document", IPP_TAG_BOOLEAN)) != NULL &&
+ attr->values[0].boolean)
+ {
+ /*
+ * See if we need to add the ending sheet...
+ */
+
+ if (printer != NULL && !(printer->type & CUPS_PRINTER_REMOTE) &&
+ (attr = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_ZERO)) != NULL &&
+ attr->num_values > 1)
+ {
+ /*
+ * Yes...
+ */
+
+ kbytes = copy_banner(con, job, attr->values[1].string.text);
+ UpdateQuota(printer, job->username, 0, kbytes);
+ }
+
+ if (job->state->values[0].integer == IPP_JOB_STOPPED)
+ job->state->values[0].integer = IPP_JOB_PENDING;
+ else if (job->state->values[0].integer == IPP_JOB_HELD)
+ {
+ if ((attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_KEYWORD)) == NULL)
+ attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);
+
+ if (attr == NULL || strcmp(attr->values[0].string.text, "no-hold") == 0)
+ job->state->values[0].integer = IPP_JOB_PENDING;
+ }
+
+ SaveJob(job->id);
+ CheckJobs();
+ }
+ else
+ {
+ if ((attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_KEYWORD)) == NULL)
+ attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);
+
+ if (attr == NULL || strcmp(attr->values[0].string.text, "no-hold") == 0)
+ {
+ job->state->values[0].integer = IPP_JOB_HELD;
+ job->hold_until = time(NULL) + 60;
+ SaveJob(job->id);
+ }
+ }
+
+ /*
+ * Fill in the response info...
+ */
+
+ snprintf(job_uri, sizeof(job_uri), "http://%s:%d/jobs/%d", ServerName,
+ ntohs(con->http.hostaddr.sin_port), job->id);
+ ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI, "job-uri", NULL,
+ job_uri);
+
+ ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", job->id);
+
+ ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_ENUM, "job-state",
+ job->state->values[0].integer);
+ add_job_state_reasons(con, job);
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'send_ipp_error()' - Send an error status back to the IPP client.
+ */
+
+static void
+send_ipp_error(client_t *con, /* I - Client connection */
+ ipp_status_t status) /* I - IPP status code */
+{
+ LogMessage(L_DEBUG2, "send_ipp_error(%p[%d], %x)\n", con, con->http.fd,
+ status);
+
+ LogMessage(L_DEBUG, "Sending error: %s", ippErrorString(status));
+
+ con->response->request.status.status_code = status;
+
+ if (ippFindAttribute(con->response, "attributes-charset", IPP_TAG_ZERO) == NULL)
+ ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, DefaultCharset);
+
+ if (ippFindAttribute(con->response, "attributes-natural-language",
+ IPP_TAG_ZERO) == NULL)
+ ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, DefaultLanguage);
+}
+
+
+/*
+ * 'set_default()' - Set the default destination...
+ */
+
+static void
+set_default(client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Printer URI */
+{
+ cups_ptype_t dtype; /* Destination type (printer or class) */
+ char method[HTTP_MAX_URI],
+ /* Method portion of URI */
+ username[HTTP_MAX_URI],
+ /* Username portion of URI */
+ host[HTTP_MAX_URI],
+ /* Host portion of URI */
+ resource[HTTP_MAX_URI];
+ /* Resource portion of URI */
+ int port; /* Port portion of URI */
+ const char *name; /* Printer name */
+
+
+ LogMessage(L_DEBUG2, "set_default(%p[%d], %s)\n", con, con->http.fd,
+ uri->values[0].string.text);
+
+ /*
+ * Was this operation called from the correct URI?
+ */
+
+ if (strncmp(con->uri, "/admin/", 7) != 0)
+ {
+ LogMessage(L_ERROR, "set_default: admin request on bad resource \'%s\'!",
+ con->uri);
+ send_ipp_error(con, IPP_NOT_AUTHORIZED);
+ return;
+ }
+
+ /*
+ * Is the destination valid?
+ */
+
+ httpSeparate(uri->values[0].string.text, method, username, host, &port, resource);
+
+ if ((name = ValidateDest(host, resource, &dtype)) == NULL)
+ {
+ /*
+ * Bad URI...
+ */
+
+ LogMessage(L_ERROR, "set_default: resource name \'%s\' no good!", resource);
+ send_ipp_error(con, IPP_NOT_FOUND);
+ return;
+ }
+
+ /*
+ * Set it as the default...
+ */
+
+ if (dtype == CUPS_PRINTER_CLASS)
+ DefaultPrinter = FindClass(name);
+ else
+ DefaultPrinter = FindPrinter(name);
+
+ SaveAllPrinters();
+ SaveAllClasses();
+
+ LogMessage(L_INFO, "Default destination set to \'%s\' by \'%s\'.", name,
+ con->username);
+
+ /*
+ * Everything was ok, so return OK status...
+ */
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'set_job_attrs()' - Set job attributes.
+ */
+
+static void
+set_job_attrs(client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Job URI */
+{
+ ipp_attribute_t *attr, /* Current attribute */
+ *attr2, /* Job attribute */
+ *prev2; /* Previous job attribute */
+ int jobid; /* Job ID */
+ job_t *job; /* Current job */
+ char method[HTTP_MAX_URI],
+ /* Method portion of URI */
+ username[HTTP_MAX_URI],
+ /* Username portion of URI */
+ host[HTTP_MAX_URI],
+ /* Host portion of URI */
+ resource[HTTP_MAX_URI];
+ /* Resource portion of URI */
+ int port; /* Port portion of URI */
+
+
+ LogMessage(L_DEBUG2, "set_job_attrs(%p[%d], %s)\n", con, con->http.fd,
+ uri->values[0].string.text);
+
+ /*
+ * See if we have a job URI or a printer URI...
+ */
+
+ if (strcmp(uri->name, "printer-uri") == 0)
+ {
+ /*
+ * Got a printer URI; see if we also have a job-id attribute...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "job-id", IPP_TAG_INTEGER)) == NULL)
+ {
+ LogMessage(L_ERROR, "set_job_attrs: got a printer-uri attribute but no job-id!");
+ send_ipp_error(con, IPP_BAD_REQUEST);
+ return;
+ }
+
+ jobid = attr->values[0].integer;
+ }
+ else
+ {
+ /*
+ * Got a job URI; parse it to get the job ID...
+ */
+
+ httpSeparate(uri->values[0].string.text, method, username, host, &port, resource);
+
+ if (strncmp(resource, "/jobs/", 6) != 0)
+ {
+ /*
+ * Not a valid URI!
+ */
+
+ LogMessage(L_ERROR, "set_job_attrs: bad job-uri attribute \'%s\'!\n",
+ uri->values[0].string.text);
+ send_ipp_error(con, IPP_BAD_REQUEST);
+ return;
+ }
+
+ jobid = atoi(resource + 6);
+ }
+
+ /*
+ * See if the job exists...
+ */
+
+ if ((job = FindJob(jobid)) == NULL)
+ {
+ /*
+ * Nope - return a "not found" error...
+ */
+
+ LogMessage(L_ERROR, "set_job_attrs: job #%d doesn't exist!", jobid);
+ send_ipp_error(con, IPP_NOT_FOUND);
+ return;
+ }
+
+ /*
+ * See if the job has been completed...
+ */
+
+ if (job->state->values[0].integer > IPP_JOB_STOPPED)
+ {
+ /*
+ * Return a "not-possible" error...
+ */
+
+ LogMessage(L_ERROR, "set_job_attrs: job #%d is finished and cannot be altered!", jobid);
+ send_ipp_error(con, IPP_NOT_POSSIBLE);
+ return;
+ }
+
+ /*
+ * See if the job is owned by the requesting user...
+ */
+
+ if (!validate_user(con, job->username, username, sizeof(username)))
+ {
+ LogMessage(L_ERROR, "set_job_attrs: \"%s\" not authorized to alter job id %d owned by \"%s\"!",
+ username, jobid, job->username);
+ send_ipp_error(con, IPP_FORBIDDEN);
+ return;
+ }
+
+ /*
+ * See what the user wants to change.
+ */
+
+ for (attr = con->request->attrs; attr != NULL; attr = attr->next)
+ {
+ if (attr->group_tag != IPP_TAG_JOB || !attr->name)
+ continue;
+
+ if (strcmp(attr->name, "job-originating-host-name") == 0 ||
+ strcmp(attr->name, "job-originating-user-name") == 0 ||
+ strcmp(attr->name, "job-media-sheets-completed") == 0 ||
+ strcmp(attr->name, "job-k-octets") == 0 ||
+ strcmp(attr->name, "job-id") == 0 ||
+ strcmp(attr->name, "job-sheets") == 0 ||
+ strncmp(attr->name, "time-at-", 8) == 0)
+ continue; /* Read-only attrs */
+
+ if (strcmp(attr->name, "job-priority") == 0 &&
+ attr->value_tag == IPP_TAG_INTEGER &&
+ job->state->values[0].integer != IPP_JOB_PROCESSING)
+ {
+ /*
+ * Change the job priority
+ */
+
+ SetJobPriority(jobid, attr->values[0].integer);
+ }
+ else if ((attr2 = ippFindAttribute(job->attrs, attr->name, IPP_TAG_ZERO)) != NULL)
+ {
+ /*
+ * Some other value; first free the old value...
+ */
+
+ for (prev2 = job->attrs->attrs; prev2 != NULL; prev2 = prev2->next)
+ if (prev2->next == attr2)
+ break;
+
+ if (prev2)
+ prev2->next = attr2->next;
+ else
+ job->attrs->attrs = attr2->next;
+
+ _ipp_free_attr(attr2);
+
+ /*
+ * Then copy the attribute...
+ */
+
+ copy_attribute(job->attrs, attr, 0);
+
+ /*
+ * See if the job-name or job-hold-until is being changed.
+ */
+
+ if (strcmp(attr->name, "job-name") == 0)
+ strncpy(job->title, attr->values[0].string.text, sizeof(job->title) - 1);
+ else if (strcmp(attr->name, "job-hold-until") == 0)
+ {
+ SetJobHoldUntil(job->id, attr->values[0].string.text);
+
+ if (strcmp(attr->values[0].string.text, "no-hold") == 0)
+ ReleaseJob(job->id);
+ else
+ HoldJob(job->id);
+ }
+ }
+ else if (attr->value_tag == IPP_TAG_DELETEATTR)
+ {
+ /*
+ * Delete the attribute...
+ */
+
+ for (attr2 = job->attrs->attrs, prev2 = NULL;
+ attr2 != NULL;
+ prev2 = attr2, attr2 = attr2->next)
+ if (attr2->name && strcmp(attr2->name, attr->name) == 0)
+ break;
+
+ if (attr2)
+ {
+ if (prev2)
+ prev2->next = attr2->next;
+ else
+ job->attrs->attrs = attr2->next;
+
+ _ipp_free_attr(attr2);
+ }
+ }
+ else
+ {
+ /*
+ * Add new option by copying it...
+ */
+
+ copy_attribute(job->attrs, attr, 0);
+ }
+ }
+
+ /*
+ * Save the job...
+ */
+
+ SaveJob(job->id);
+
+ /*
+ * Start jobs if possible...
+ */
+
+ CheckJobs();
+
+ /*
+ * Return with "everything is OK" status...
+ */
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'start_printer()' - Start a printer.
+ */
+
+static void
+start_printer(client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Printer URI */
+{
+ cups_ptype_t dtype; /* Destination type (printer or class) */
+ char method[HTTP_MAX_URI],
+ /* Method portion of URI */
+ username[HTTP_MAX_URI],
+ /* Username portion of URI */
+ host[HTTP_MAX_URI],
+ /* Host portion of URI */
+ resource[HTTP_MAX_URI];
+ /* Resource portion of URI */
+ int port; /* Port portion of URI */
+ const char *name; /* Printer name */
+ printer_t *printer; /* Printer data */
+
+
+ LogMessage(L_DEBUG2, "start_printer(%p[%d], %s)\n", con, con->http.fd,
+ uri->values[0].string.text);
+
+ /*
+ * Was this operation called from the correct URI?
+ */
+
+ if (strncmp(con->uri, "/admin/", 7) != 0)
+ {
+ LogMessage(L_ERROR, "start_printer: admin request on bad resource \'%s\'!",
+ con->uri);
+ send_ipp_error(con, IPP_NOT_AUTHORIZED);
+ return;
+ }
+
+ /*
+ * Is the destination valid?
+ */
+
+ httpSeparate(uri->values[0].string.text, method, username, host, &port, resource);
+
+ if ((name = ValidateDest(host, resource, &dtype)) == NULL)
+ {
+ /*
+ * Bad URI...
+ */
+
+ LogMessage(L_ERROR, "start_printer: resource name \'%s\' no good!", resource);
+ send_ipp_error(con, IPP_NOT_FOUND);
+ return;
+ }
+
+ /*
+ * Start the printer...
+ */
+
+ if (dtype == CUPS_PRINTER_CLASS)
+ printer = FindClass(name);
+ else
+ printer = FindPrinter(name);
+
+ StartPrinter(printer);
+
+ printer->state_message[0] = '\0';
+
+ if (dtype == CUPS_PRINTER_CLASS)
+ SaveAllClasses();
+ else
+ SaveAllPrinters();
+
+ if (dtype == CUPS_PRINTER_CLASS)
+ LogMessage(L_INFO, "Class \'%s\' started by \'%s\'.", name,
+ con->username);
+ else
+ LogMessage(L_INFO, "Printer \'%s\' started by \'%s\'.", name,
+ con->username);
+
+ CheckJobs();
+
+ /*
+ * Everything was ok, so return OK status...
+ */
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'stop_printer()' - Stop a printer.
+ */
+
+static void
+stop_printer(client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Printer URI */
+{
+ cups_ptype_t dtype; /* Destination type (printer or class) */
+ char method[HTTP_MAX_URI],
+ /* Method portion of URI */
+ username[HTTP_MAX_URI],
+ /* Username portion of URI */
+ host[HTTP_MAX_URI],
+ /* Host portion of URI */
+ resource[HTTP_MAX_URI];
+ /* Resource portion of URI */
+ int port; /* Port portion of URI */
+ const char *name; /* Printer name */
+ printer_t *printer; /* Printer data */
+ ipp_attribute_t *attr; /* printer-state-message attribute */
+
+
+ LogMessage(L_DEBUG2, "stop_printer(%p[%d], %s)\n", con, con->http.fd,
+ uri->values[0].string.text);
+
+ /*
+ * Was this operation called from the correct URI?
+ */
+
+ if (strncmp(con->uri, "/admin/", 7) != 0)
+ {
+ LogMessage(L_ERROR, "stop_printer: admin request on bad resource \'%s\'!",
+ con->uri);
+ send_ipp_error(con, IPP_NOT_AUTHORIZED);
+ return;
+ }
+
+ /*
+ * Is the destination valid?
+ */
+
+ httpSeparate(uri->values[0].string.text, method, username, host, &port, resource);
+
+ if ((name = ValidateDest(host, resource, &dtype)) == NULL)
+ {
+ /*
+ * Bad URI...
+ */
+
+ LogMessage(L_ERROR, "stop_printer: resource name \'%s\' no good!", resource);
+ send_ipp_error(con, IPP_NOT_FOUND);
+ return;
+ }
+
+ /*
+ * Stop the printer...
+ */
+
+ if (dtype == CUPS_PRINTER_CLASS)
+ printer = FindClass(name);
+ else
+ printer = FindPrinter(name);
+
+ StopPrinter(printer);
+
+ if ((attr = ippFindAttribute(con->request, "printer-state-message",
+ IPP_TAG_TEXT)) == NULL)
+ strcpy(printer->state_message, "Paused");
+ else
+ {
+ strncpy(printer->state_message, attr->values[0].string.text,
+ sizeof(printer->state_message) - 1);
+ printer->state_message[sizeof(printer->state_message) - 1] = '\0';
+ }
+
+ if (dtype == CUPS_PRINTER_CLASS)
+ SaveAllClasses();
+ else
+ SaveAllPrinters();
+
+ if (dtype == CUPS_PRINTER_CLASS)
+ LogMessage(L_INFO, "Class \'%s\' stopped by \'%s\'.", name,
+ con->username);
+ else
+ LogMessage(L_INFO, "Printer \'%s\' stopped by \'%s\'.", name,
+ con->username);
+
+ /*
+ * Everything was ok, so return OK status...
+ */
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'validate_job()' - Validate printer options and destination.
+ */
+
+static void
+validate_job(client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Printer URI */
+{
+ ipp_attribute_t *attr; /* Current attribute */
+ ipp_attribute_t *format; /* Document-format attribute */
+ cups_ptype_t dtype; /* Destination type (printer or class) */
+ char method[HTTP_MAX_URI],
+ /* Method portion of URI */
+ username[HTTP_MAX_URI],
+ /* Username portion of URI */
+ host[HTTP_MAX_URI],
+ /* Host portion of URI */
+ resource[HTTP_MAX_URI];
+ /* Resource portion of URI */
+ int port; /* Port portion of URI */
+ char super[MIME_MAX_SUPER],
+ /* Supertype of file */
+ type[MIME_MAX_TYPE];
+ /* Subtype of file */
+
+
+ LogMessage(L_DEBUG2, "validate_job(%p[%d], %s)\n", con, con->http.fd,
+ uri->values[0].string.text);
+
+ /*
+ * Verify that the POST operation was done to a valid URI.
+ */
+
+ if (strncmp(con->uri, "/classes/", 9) != 0 &&
+ strncmp(con->uri, "/printers/", 10) != 0)
+ {
+ LogMessage(L_ERROR, "validate_job: request on bad resource \'%s\'!",
+ con->uri);
+ send_ipp_error(con, IPP_NOT_AUTHORIZED);
+ return;
+ }
+
+ /*
+ * OK, see if the client is sending the document compressed - CUPS
+ * doesn't support compression yet...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "compression", IPP_TAG_KEYWORD)) != NULL &&
+ strcmp(attr->values[0].string.text, "none") == 0)
+ {
+ LogMessage(L_ERROR, "validate_job: Unsupported compression attribute %s!",
+ attr->values[0].string.text);
+ send_ipp_error(con, IPP_ATTRIBUTES);
+ ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_KEYWORD,
+ "compression", NULL, attr->values[0].string.text);
+ return;
+ }
+
+ /*
+ * Is it a format we support?
+ */
+
+ if ((format = ippFindAttribute(con->request, "document-format", IPP_TAG_MIMETYPE)) != NULL)
+ {
+ if (sscanf(format->values[0].string.text, "%15[^/]/%31[^;]", super, type) != 2)
+ {
+ LogMessage(L_ERROR, "validate_job: could not scan type \'%s\'!\n",
+ format->values[0].string.text);
+ send_ipp_error(con, IPP_BAD_REQUEST);
+ return;
+ }
+
+ if ((strcmp(super, "application") != 0 ||
+ strcmp(type, "octet-stream") != 0) &&
+ mimeType(MimeDatabase, super, type) == NULL)
+ {
+ LogMessage(L_ERROR, "validate_job: Unsupported format \'%s\'!\n",
+ format->values[0].string.text);
+ send_ipp_error(con, IPP_DOCUMENT_FORMAT);
+ ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_MIMETYPE,
+ "document-format", NULL, format->values[0].string.text);
+ return;
+ }
+ }
+
+ /*
+ * Is the destination valid?
+ */
+
+ httpSeparate(uri->values[0].string.text, method, username, host, &port, resource);
+
+ if (ValidateDest(host, resource, &dtype) == NULL)
+ {
+ /*
+ * Bad URI...
+ */
+
+ LogMessage(L_ERROR, "validate_job: resource name \'%s\' no good!", resource);
+ send_ipp_error(con, IPP_NOT_FOUND);
+ return;
+ }
+
+ /*
+ * Everything was ok, so return OK status...
+ */
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'validate_user()' - Validate the user for the request.
+ */
+
+static int /* O - 1 if permitted, 0 otherwise */
+validate_user(client_t *con, /* I - Client connection */
+ const char *owner, /* I - Owner of job/resource */
+ char *username, /* O - Authenticated username */
+ int userlen) /* I - Length of username */
+{
+ int i, j; /* Looping vars */
+ ipp_attribute_t *attr; /* requesting-user-name attribute */
+ struct passwd *user; /* User info */
+ struct group *group; /* System group info */
+
+
+ LogMessage(L_DEBUG2, "validate_user(%p[%d], \"%s\", %p, %d)\n",
+ con, con->http.fd, owner, username, userlen);
+
+ /*
+ * Validate input...
+ */
+
+ if (con == NULL || owner == NULL || username == NULL || userlen <= 0)
+ return (0);
+
+ /*
+ * Get the best authenticated username that is available.
+ */
+
+ if (con->username[0])
+ strncpy(username, con->username, userlen - 1);
+ else if ((attr = ippFindAttribute(con->request, "requesting-user-name", IPP_TAG_NAME)) != NULL)
+ strncpy(username, attr->values[0].string.text, userlen - 1);
+ else
+ strncpy(username, "anonymous", userlen - 1);
+
+ username[userlen - 1] = '\0';
+
+ /*
+ * Check the username against the owner...
+ */
+
+ if (strcasecmp(username, owner) != 0 && strcasecmp(username, "root") != 0)
+ {
+ /*
+ * Not the owner or root; check to see if the user is a member of the
+ * system group...
+ */
+
+ user = getpwnam(username);
+ endpwent();
+
+ for (i = 0, j = 0, group = NULL; i < NumSystemGroups; i ++)
+ {
+ group = getgrnam(SystemGroups[i]);
+ endgrent();
+
+ if (group != NULL)
+ {
+ for (j = 0; group->gr_mem[j]; j ++)
+ if (strcasecmp(username, group->gr_mem[j]) == 0)
+ break;
+
+ if (group->gr_mem[j])
+ break;
+ }
+ else
+ j = 0;
+ }
+
+ if (user == NULL || group == NULL ||
+ (group->gr_mem[j] == NULL && group->gr_gid != user->pw_gid))
+ {
+ /*
+ * Username not found, group not found, or user is not part of the
+ * system group...
+ */
+
+ return (0);
+ }
+ }
+
+ return (1);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/job.c b/scheduler/job.c
new file mode 100644
index 000000000..f1bbbb463
--- /dev/null
+++ b/scheduler/job.c
@@ -0,0 +1,2997 @@
+/*
+ * "$Id$"
+ *
+ * Job management routines for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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:
+ *
+ * AddJob() - Add a new job to the job queue...
+ * CancelJob() - Cancel the specified print job.
+ * CancelJobs() - Cancel all jobs on the given printer or class.
+ * CheckJobs() - Check the pending jobs and start any if the
+ * destination is available.
+ * CleanJobs() - Clean out old jobs.
+ * FindJob() - Find the specified job.
+ * GetPrinterJobCount() - Get the number of pending, processing,
+ * or held jobs in a printer or class.
+ * GetUserJobCount() - Get the number of pending, processing,
+ * or held jobs for a user.
+ * HoldJob() - Hold the specified job.
+ * LoadAllJobs() - Load all jobs from disk.
+ * LoadJob() - Load a job from disk.
+ * MoveJob() - Move the specified job to a different
+ * destination.
+ * ReleaseJob() - Release the specified job.
+ * RestartJob() - Restart the specified job.
+ * SaveJob() - Save a job to disk.
+ * SetJobHoldUntil() - Set the hold time for a job...
+ * SetJobPriority() - Set the priority of a job, moving it up/down
+ * in the list as needed.
+ * StartJob() - Start a print job.
+ * StopAllJobs() - Stop all print jobs.
+ * StopJob() - Stop a print job.
+ * UpdateJob() - Read a status update from a job's filters.
+ * ipp_read_file() - Read an IPP request from a file.
+ * ipp_write_file() - Write an IPP request to a file.
+ * start_process() - Start a background process.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cupsd.h"
+#include <grp.h>
+
+
+/*
+ * Local functions...
+ */
+
+static ipp_state_t ipp_read_file(const char *filename, ipp_t *ipp);
+static ipp_state_t ipp_write_file(const char *filename, ipp_t *ipp);
+static void set_time(job_t *job, const char *name);
+static int start_process(const char *command, char *argv[],
+ char *envp[], int in, int out, int err,
+ int root);
+
+
+/*
+ * 'AddJob()' - Add a new job to the job queue...
+ */
+
+job_t * /* O - New job record */
+AddJob(int priority, /* I - Job priority */
+ const char *dest) /* I - Job destination */
+{
+ job_t *job, /* New job record */
+ *current, /* Current job in queue */
+ *prev; /* Previous job in queue */
+
+
+ job = calloc(sizeof(job_t), 1);
+
+ job->id = NextJobId ++;
+ job->priority = priority;
+ strncpy(job->dest, dest, sizeof(job->dest) - 1);
+
+ NumJobs ++;
+
+ for (current = Jobs, prev = NULL;
+ current != NULL;
+ prev = current, current = current->next)
+ if (job->priority > current->priority)
+ break;
+
+ job->next = current;
+ if (prev != NULL)
+ prev->next = job;
+ else
+ Jobs = job;
+
+ return (job);
+}
+
+
+/*
+ * 'CancelJob()' - Cancel the specified print job.
+ */
+
+void
+CancelJob(int id, /* I - Job to cancel */
+ int purge) /* I - Purge jobs? */
+{
+ int i; /* Looping var */
+ job_t *current, /* Current job */
+ *prev; /* Previous job in list */
+ char filename[1024]; /* Job filename */
+
+
+ LogMessage(L_DEBUG, "CancelJob: id = %d", id);
+
+ for (current = Jobs, prev = NULL; current != NULL; prev = current, current = current->next)
+ if (current->id == id)
+ {
+ /*
+ * Stop any processes that are working on the current...
+ */
+
+ DEBUG_puts("CancelJob: found job in list.");
+
+ if (current->state->values[0].integer == IPP_JOB_PROCESSING)
+ StopJob(current->id, 0);
+
+ current->state->values[0].integer = IPP_JOB_CANCELLED;
+
+ set_time(current, "time-at-completed");
+
+ /*
+ * Remove the print file for good if we aren't preserving jobs or
+ * files...
+ */
+
+ current->current_file = 0;
+
+ if (!JobHistory || !JobFiles || purge)
+ for (i = 1; i <= current->num_files; i ++)
+ {
+ snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot,
+ current->id, i);
+ unlink(filename);
+ }
+
+ if (JobHistory && !purge)
+ {
+ /*
+ * Save job state info...
+ */
+
+ SaveJob(current->id);
+ }
+ else
+ {
+ /*
+ * Remove the job info file...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/c%05d", RequestRoot,
+ current->id);
+ unlink(filename);
+
+ /*
+ * Update pointers if we aren't preserving jobs...
+ */
+
+ if (prev == NULL)
+ Jobs = current->next;
+ else
+ prev->next = current->next;
+
+ /*
+ * Free all memory used...
+ */
+
+ if (current->attrs != NULL)
+ ippDelete(current->attrs);
+
+ free(current->filetypes);
+
+ free(current);
+
+ NumJobs --;
+ }
+
+ return;
+ }
+}
+
+
+/*
+ * 'CancelJobs()' - Cancel all jobs on the given printer or class.
+ */
+
+void
+CancelJobs(const char *dest) /* I - Destination to cancel */
+{
+ job_t *current; /* Current job */
+
+
+ for (current = Jobs; current != NULL;)
+ if (strcmp(current->dest, dest) == 0)
+ {
+ /*
+ * Cancel all jobs matching this destination...
+ */
+
+ CancelJob(current->id, 1);
+
+ current = Jobs;
+ }
+ else
+ current = current->next;
+
+ CheckJobs();
+}
+
+
+/*
+ * 'CheckJobs()' - Check the pending jobs and start any if the destination
+ * is available.
+ */
+
+void
+CheckJobs(void)
+{
+ job_t *current, /* Current job in queue */
+ *next; /* Next job in queue */
+ printer_t *printer, /* Printer destination */
+ *pclass; /* Printer class destination */
+
+
+ DEBUG_puts("CheckJobs()");
+
+ for (current = Jobs; current != NULL; current = next)
+ {
+ /*
+ * Save next pointer in case the job is cancelled en-route.
+ */
+
+ next = current->next;
+
+ /*
+ * Start held jobs if they are ready...
+ */
+
+ if (current->state->values[0].integer == IPP_JOB_HELD &&
+ current->hold_until &&
+ current->hold_until < time(NULL))
+ current->state->values[0].integer = IPP_JOB_PENDING;
+
+ /*
+ * Start pending jobs if the destination is available...
+ */
+
+ if (current->state->values[0].integer == IPP_JOB_PENDING)
+ {
+ if ((pclass = FindClass(current->dest)) != NULL)
+ {
+ /*
+ * If the class is remote, just pass it to the remote server...
+ */
+
+ if (pclass->type & CUPS_PRINTER_REMOTE)
+ printer = pclass;
+ else if (pclass->state != IPP_PRINTER_STOPPED)
+ printer = FindAvailablePrinter(current->dest);
+ else
+ printer = NULL;
+ }
+ else
+ printer = FindPrinter(current->dest);
+
+ if (printer != NULL && (printer->type & CUPS_PRINTER_IMPLICIT))
+ {
+ /*
+ * Handle implicit classes...
+ */
+
+ pclass = printer;
+
+ if (pclass->state != IPP_PRINTER_STOPPED)
+ printer = FindAvailablePrinter(current->dest);
+ else
+ printer = NULL;
+ }
+
+ if (printer == NULL && pclass == NULL)
+ {
+ /*
+ * Whoa, the printer and/or class for this destination went away;
+ * cancel the job...
+ */
+
+ LogMessage(L_WARN, "Printer/class %s has gone away; cancelling job %d!",
+ current->dest, current->id);
+ CancelJob(current->id, 1);
+ }
+ else if (printer != NULL)
+ {
+ /*
+ * See if the printer is available or remote and not printing a job;
+ * if so, start the job...
+ */
+
+ if (printer->state == IPP_PRINTER_IDLE || /* Printer is idle */
+ ((printer->type & CUPS_PRINTER_REMOTE) && /* Printer is remote */
+ !printer->job)) /* and not printing a job */
+ StartJob(current->id, printer);
+ }
+ }
+ }
+}
+
+
+/*
+ * 'CleanJobs()' - Clean out old jobs.
+ */
+
+void
+CleanJobs(void)
+{
+ job_t *job, /* Current job */
+ *next; /* Next job */
+
+
+ if (MaxJobs == 0)
+ return;
+
+ for (job = Jobs; job && NumJobs >= MaxJobs; job = next)
+ {
+ next = job->next;
+
+ if (job->state->values[0].integer >= IPP_JOB_CANCELLED)
+ CancelJob(job->id, 1);
+ }
+}
+
+
+/*
+ * 'FindJob()' - Find the specified job.
+ */
+
+job_t * /* O - Job data */
+FindJob(int id) /* I - Job ID */
+{
+ job_t *current; /* Current job */
+
+
+ for (current = Jobs; current != NULL; current = current->next)
+ if (current->id == id)
+ break;
+
+ return (current);
+}
+
+
+/*
+ * 'GetPrinterJobCount()' - Get the number of pending, processing,
+ * or held jobs in a printer or class.
+ */
+
+int /* O - Job count */
+GetPrinterJobCount(const char *dest) /* I - Printer or class name */
+{
+ int count; /* Job count */
+ job_t *job; /* Current job */
+
+
+ for (job = Jobs, count = 0; job != NULL; job = job->next)
+ if (job->state->values[0].integer <= IPP_JOB_PROCESSING &&
+ strcasecmp(job->dest, dest) == 0)
+ count ++;
+
+ return (count);
+}
+
+
+/*
+ * 'GetUserJobCount()' - Get the number of pending, processing,
+ * or held jobs for a user.
+ */
+
+int /* O - Job count */
+GetUserJobCount(const char *username) /* I - Username */
+{
+ int count; /* Job count */
+ job_t *job; /* Current job */
+
+
+ for (job = Jobs, count = 0; job != NULL; job = job->next)
+ if (job->state->values[0].integer <= IPP_JOB_PROCESSING &&
+ strcmp(job->username, username) == 0)
+ count ++;
+
+ return (count);
+}
+
+
+/*
+ * 'HoldJob()' - Hold the specified job.
+ */
+
+void
+HoldJob(int id) /* I - Job ID */
+{
+ job_t *job; /* Job data */
+
+
+ LogMessage(L_DEBUG, "HoldJob: id = %d", id);
+
+ if ((job = FindJob(id)) == NULL)
+ return;
+
+ if (job->state->values[0].integer == IPP_JOB_PROCESSING)
+ StopJob(id, 0);
+
+ DEBUG_puts("HoldJob: setting state to held...");
+
+ job->state->values[0].integer = IPP_JOB_HELD;
+
+ SaveJob(id);
+
+ CheckJobs();
+}
+
+
+/*
+ * 'LoadAllJobs()' - Load all jobs from disk.
+ */
+
+void
+LoadAllJobs(void)
+{
+ DIR *dir; /* Directory */
+ DIRENT *dent; /* Directory entry */
+ char filename[1024]; /* Full filename of job file */
+ job_t *job, /* New job */
+ *current, /* Current job */
+ *prev; /* Previous job */
+ int jobid, /* Current job ID */
+ fileid; /* Current file ID */
+ ipp_attribute_t *attr; /* Job attribute */
+ char method[HTTP_MAX_URI],
+ /* Method portion of URI */
+ username[HTTP_MAX_URI],
+ /* Username portion of URI */
+ host[HTTP_MAX_URI],
+ /* Host portion of URI */
+ resource[HTTP_MAX_URI];
+ /* Resource portion of URI */
+ int port; /* Port portion of URI */
+ printer_t *p; /* Printer or class */
+ const char *dest; /* Destination */
+ mime_type_t **filetypes; /* New filetypes array */
+
+
+ /*
+ * First open the requests directory...
+ */
+
+ if ((dir = opendir(RequestRoot)) == NULL)
+ return;
+
+ /*
+ * Read all the c##### files...
+ */
+
+ while ((dent = readdir(dir)) != NULL)
+ if (NAMLEN(dent) == 6 && dent->d_name[0] == 'c')
+ {
+ /*
+ * Allocate memory for the job...
+ */
+
+ if ((job = calloc(sizeof(job_t), 1)) == NULL)
+ {
+ LogMessage(L_ERROR, "LoadAllJobs: Ran out of memory for jobs!");
+ closedir(dir);
+ return;
+ }
+
+ if ((job->attrs = ippNew()) == NULL)
+ {
+ free(job);
+ LogMessage(L_ERROR, "LoadAllJobs: Ran out of memory for job attributes!");
+ closedir(dir);
+ return;
+ }
+
+ /*
+ * Assign the job ID...
+ */
+
+ job->id = atoi(dent->d_name + 1);
+
+ if (job->id >= NextJobId)
+ NextJobId = job->id + 1;
+
+ /*
+ * Load the job control file...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/%s", RequestRoot, dent->d_name);
+ if (ipp_read_file(filename, job->attrs) != IPP_DATA)
+ {
+ LogMessage(L_ERROR, "LoadAllJobs: Unable to read job control file \"%s\"!",
+ filename);
+ ippDelete(job->attrs);
+ free(job);
+ unlink(filename);
+ continue;
+ }
+
+ if ((attr = ippFindAttribute(job->attrs, "job-printer-uri", IPP_TAG_URI)) == NULL)
+ {
+ LogMessage(L_ERROR, "LoadAllJobs: No job-printer-uri attribute in control file \"%s\"!",
+ filename);
+ ippDelete(job->attrs);
+ free(job);
+ unlink(filename);
+ continue;
+ }
+
+ httpSeparate(attr->values[0].string.text, method, username, host,
+ &port, resource);
+
+ if ((dest = ValidateDest(host, resource, &(job->dtype))) == NULL)
+ {
+ /*
+ * Job queued on remote printer or class, so add it...
+ */
+
+ if (strncmp(resource, "/classes/", 9) == 0)
+ {
+ p = AddClass(resource + 9);
+ strcpy(p->make_model, "Remote Class on unknown");
+ }
+ else
+ {
+ p = AddPrinter(resource + 10);
+ strcpy(p->make_model, "Remote Printer on unknown");
+ }
+
+ p->state = IPP_PRINTER_STOPPED;
+ p->type |= CUPS_PRINTER_REMOTE;
+ p->browse_time = 2147483647;
+
+ strcpy(p->location, "Location Unknown");
+ strcpy(p->info, "No Information Available");
+ p->hostname[0] = '\0';
+
+ SetPrinterAttrs(p);
+ dest = p->name;
+ }
+
+ if (dest == NULL)
+ {
+ LogMessage(L_ERROR, "LoadAllJobs: Unable to queue job for destination \"%s\"!",
+ attr->values[0].string.text);
+ ippDelete(job->attrs);
+ free(job);
+ unlink(filename);
+ continue;
+ }
+
+ strncpy(job->dest, dest, sizeof(job->dest) - 1);
+
+ job->sheets = ippFindAttribute(job->attrs, "job-media-sheets-completed",
+ IPP_TAG_INTEGER);
+ job->state = ippFindAttribute(job->attrs, "job-state", IPP_TAG_ENUM);
+ job->job_sheets = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_NAME);
+
+ attr = ippFindAttribute(job->attrs, "job-priority", IPP_TAG_INTEGER);
+ job->priority = attr->values[0].integer;
+
+ attr = ippFindAttribute(job->attrs, "job-name", IPP_TAG_NAME);
+ strncpy(job->title, attr->values[0].string.text,
+ sizeof(job->title) - 1);
+
+ attr = ippFindAttribute(job->attrs, "job-originating-user-name", IPP_TAG_NAME);
+ strncpy(job->username, attr->values[0].string.text,
+ sizeof(job->username) - 1);
+
+ if (job->state->values[0].integer == IPP_JOB_HELD)
+ {
+ if ((attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_KEYWORD)) == NULL)
+ attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);
+
+ if (attr == NULL)
+ job->state->values[0].integer = IPP_JOB_PENDING;
+ else
+ SetJobHoldUntil(job->id, attr->values[0].string.text);
+ }
+ else if (job->state->values[0].integer == IPP_JOB_PROCESSING)
+ job->state->values[0].integer = IPP_JOB_PENDING;
+
+ /*
+ * Insert the job into the array, sorting by job priority and ID...
+ */
+
+ for (current = Jobs, prev = NULL;
+ current != NULL;
+ prev = current, current = current->next)
+ if (job->priority > current->priority)
+ break;
+ else if (job->priority == current->priority && job->id < current->id)
+ break;
+
+ job->next = current;
+ if (prev != NULL)
+ prev->next = job;
+ else
+ Jobs = job;
+
+ NumJobs ++;
+ }
+
+ /*
+ * Read all the d##### files...
+ */
+
+ rewinddir(dir);
+
+ while ((dent = readdir(dir)) != NULL)
+ if (NAMLEN(dent) > 7 && dent->d_name[0] == 'd')
+ {
+ /*
+ * Find the job...
+ */
+
+ jobid = atoi(dent->d_name + 1);
+ fileid = atoi(dent->d_name + 7);
+
+ snprintf(filename, sizeof(filename), "%s/%s", RequestRoot, dent->d_name);
+
+ if ((job = FindJob(jobid)) == NULL)
+ {
+ LogMessage(L_ERROR, "LoadAllJobs: Orphaned print file \"%s\"!",
+ filename);
+ unlink(filename);
+ continue;
+ }
+
+ if (fileid > job->num_files)
+ {
+ if (job->num_files == 0)
+ filetypes = (mime_type_t **)calloc(sizeof(mime_type_t *), fileid);
+ else
+ filetypes = (mime_type_t **)realloc(job->filetypes,
+ sizeof(mime_type_t *) * fileid);
+
+ if (filetypes == NULL)
+ {
+ LogMessage(L_ERROR, "LoadAllJobs: Ran out of memory for job file types!");
+ continue;
+ }
+
+ job->filetypes = filetypes;
+ job->num_files = fileid;
+ }
+
+ job->filetypes[fileid - 1] = mimeFileType(MimeDatabase, filename);
+
+ if (job->filetypes[fileid - 1] == NULL)
+ job->filetypes[fileid - 1] = mimeType(MimeDatabase, "application",
+ "vnd.cups-raw");
+ }
+
+ closedir(dir);
+
+ /*
+ * Clean out old jobs as needed...
+ */
+
+ CleanJobs();
+
+ /*
+ * Check to see if we need to start any jobs...
+ */
+
+ CheckJobs();
+}
+
+
+/*
+ * 'MoveJob()' - Move the specified job to a different destination.
+ */
+
+void
+MoveJob(int id, /* I - Job ID */
+ const char *dest) /* I - Destination */
+{
+ job_t *current;/* Current job */
+ ipp_attribute_t *attr; /* job-printer-uri attribute */
+ printer_t *p; /* Destination printer or class */
+
+
+ if ((p = FindPrinter(dest)) == NULL)
+ p = FindClass(dest);
+
+ if (p == NULL)
+ return;
+
+ for (current = Jobs; current != NULL; current = current->next)
+ if (current->id == id)
+ {
+ if (current->state->values[0].integer >= IPP_JOB_PROCESSING)
+ break;
+
+ strncpy(current->dest, dest, sizeof(current->dest) - 1);
+ current->dtype = p->type & CUPS_PRINTER_CLASS;
+
+ if ((attr = ippFindAttribute(current->attrs, "job-printer-uri", IPP_TAG_URI)) != NULL)
+ {
+ free(attr->values[0].string.text);
+ attr->values[0].string.text = strdup(p->uri);
+ }
+
+ SaveJob(current->id);
+
+ return;
+ }
+}
+
+
+/*
+ * 'ReleaseJob()' - Release the specified job.
+ */
+
+void
+ReleaseJob(int id) /* I - Job ID */
+{
+ job_t *job; /* Job data */
+
+
+ LogMessage(L_DEBUG, "ReleaseJob: id = %d", id);
+
+ if ((job = FindJob(id)) == NULL)
+ return;
+
+ if (job->state->values[0].integer == IPP_JOB_HELD)
+ {
+ DEBUG_puts("ReleaseJob: setting state to pending...");
+
+ job->state->values[0].integer = IPP_JOB_PENDING;
+ SaveJob(id);
+ CheckJobs();
+ }
+}
+
+
+/*
+ * 'RestartJob()' - Restart the specified job.
+ */
+
+void
+RestartJob(int id) /* I - Job ID */
+{
+ job_t *job; /* Job data */
+
+
+ if ((job = FindJob(id)) == NULL)
+ return;
+
+ if (job->state->values[0].integer == IPP_JOB_STOPPED || JobFiles)
+ {
+ job->state->values[0].integer = IPP_JOB_PENDING;
+ SaveJob(id);
+ CheckJobs();
+ }
+}
+
+
+/*
+ * 'SaveJob()' - Save a job to disk.
+ */
+
+void
+SaveJob(int id) /* I - Job ID */
+{
+ job_t *job; /* Pointer to job */
+ char filename[1024]; /* Job control filename */
+
+
+ if ((job = FindJob(id)) == NULL)
+ return;
+
+ snprintf(filename, sizeof(filename), "%s/c%05d", RequestRoot, id);
+ ipp_write_file(filename, job->attrs);
+}
+
+
+/*
+ * 'SetJobHoldUntil()' - Set the hold time for a job...
+ */
+
+void
+SetJobHoldUntil(int id, /* I - Job ID */
+ const char *when) /* I - When to resume */
+{
+ job_t *job; /* Pointer to job */
+ time_t curtime; /* Current time */
+ struct tm *curdate; /* Current date */
+ int hour; /* Hold hour */
+ int minute; /* Hold minute */
+ int second; /* Hold second */
+
+
+ LogMessage(L_DEBUG, "SetJobHoldUntil(%d, \"%s\")", id, when);
+
+ if ((job = FindJob(id)) == NULL)
+ return;
+
+ second = 0;
+
+ if (strcmp(when, "indefinite") == 0)
+ {
+ /*
+ * Hold indefinitely...
+ */
+
+ job->hold_until = 0;
+ }
+ else if (strcmp(when, "day-time") == 0)
+ {
+ /*
+ * Hold to 6am the next morning unless local time is < 6pm.
+ */
+
+ curtime = time(NULL);
+ curdate = localtime(&curtime);
+
+ if (curdate->tm_hour < 18)
+ job->hold_until = curtime;
+ else
+ job->hold_until = curtime +
+ ((29 - curdate->tm_hour) * 60 + 59 -
+ curdate->tm_min) * 60 + 60 - curdate->tm_sec;
+ }
+ else if (strcmp(when, "evening") == 0 || strcmp(when, "night") == 0)
+ {
+ /*
+ * Hold to 6pm unless local time is > 6pm or < 6am.
+ */
+
+ curtime = time(NULL);
+ curdate = localtime(&curtime);
+
+ if (curdate->tm_hour < 6 || curdate->tm_hour >= 18)
+ job->hold_until = curtime;
+ else
+ job->hold_until = curtime +
+ ((17 - curdate->tm_hour) * 60 + 59 -
+ curdate->tm_min) * 60 + 60 - curdate->tm_sec;
+ }
+ else if (strcmp(when, "second-shift") == 0)
+ {
+ /*
+ * Hold to 4pm unless local time is > 4pm.
+ */
+
+ curtime = time(NULL);
+ curdate = localtime(&curtime);
+
+ if (curdate->tm_hour >= 16)
+ job->hold_until = curtime;
+ else
+ job->hold_until = curtime +
+ ((15 - curdate->tm_hour) * 60 + 59 -
+ curdate->tm_min) * 60 + 60 - curdate->tm_sec;
+ }
+ else if (strcmp(when, "third-shift") == 0)
+ {
+ /*
+ * Hold to 12am unless local time is < 8am.
+ */
+
+ curtime = time(NULL);
+ curdate = localtime(&curtime);
+
+ if (curdate->tm_hour < 8)
+ job->hold_until = curtime;
+ else
+ job->hold_until = curtime +
+ ((23 - curdate->tm_hour) * 60 + 59 -
+ curdate->tm_min) * 60 + 60 - curdate->tm_sec;
+ }
+ else if (strcmp(when, "weekend") == 0)
+ {
+ /*
+ * Hold to weekend unless we are in the weekend.
+ */
+
+ curtime = time(NULL);
+ curdate = localtime(&curtime);
+
+ if (curdate->tm_wday == 0 || curdate->tm_wday == 6)
+ job->hold_until = curtime;
+ else
+ job->hold_until = curtime +
+ (((5 - curdate->tm_wday) * 24 +
+ (17 - curdate->tm_hour)) * 60 + 59 -
+ curdate->tm_min) * 60 + 60 - curdate->tm_sec;
+ }
+ else if (sscanf(when, "%d:%d:%d", &hour, &minute, &second) >= 2)
+ {
+ /*
+ * Hold to specified GMT time (HH:MM or HH:MM:SS)...
+ */
+
+ curtime = time(NULL);
+ curdate = gmtime(&curtime);
+
+ job->hold_until = curtime +
+ ((hour - curdate->tm_hour) * 60 + minute -
+ curdate->tm_min) * 60 + second - curdate->tm_sec;
+
+ /*
+ * Hold until next day as needed...
+ */
+
+ if (job->hold_until < curtime)
+ job->hold_until += 24 * 60 * 60 * 60;
+ }
+
+ LogMessage(L_DEBUG, "SetJobHoldUntil: hold_until = %d", job->hold_until);
+}
+
+
+/*
+ * 'SetJobPriority()' - Set the priority of a job, moving it up/down in the
+ * list as needed.
+ */
+
+void
+SetJobPriority(int id, /* I - Job ID */
+ int priority) /* I - New priority (0 to 100) */
+{
+ job_t *job, /* Job to change */
+ *current, /* Current job */
+ *prev; /* Previous job */
+ ipp_attribute_t *attr; /* Job attribute */
+
+
+ /*
+ * Find the job...
+ */
+
+ for (current = Jobs, prev = NULL;
+ current != NULL;
+ prev = current, current = current->next)
+ if (current->id == id)
+ break;
+
+ if (current == NULL)
+ return;
+
+ /*
+ * Set the new priority...
+ */
+
+ job = current;
+ job->priority = priority;
+
+ if ((attr = ippFindAttribute(job->attrs, "job-priority", IPP_TAG_INTEGER)) != NULL)
+ attr->values[0].integer = priority;
+ else
+ ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-priority",
+ priority);
+
+ SaveJob(job->id);
+
+ /*
+ * See if we need to do any sorting...
+ */
+
+ if ((prev == NULL || job->priority < prev->priority) &&
+ (job->next == NULL || job->next->priority < job->priority))
+ return;
+
+ /*
+ * Remove the job from the list, and then insert it where it belongs...
+ */
+
+ if (prev == NULL)
+ Jobs = job->next;
+ else
+ prev->next = job->next;
+
+ for (current = Jobs, prev = NULL;
+ current != NULL;
+ prev = current, current = current->next)
+ if (job->priority > current->priority)
+ break;
+
+ job->next = current;
+ if (prev != NULL)
+ prev->next = job;
+ else
+ Jobs = job;
+}
+
+
+/*
+ * 'StartJob()' - Start a print job.
+ */
+
+void
+StartJob(int id, /* I - Job ID */
+ printer_t *printer) /* I - Printer to print job */
+{
+ job_t *current; /* Current job */
+ int i; /* Looping var */
+ int slot; /* Pipe slot */
+ int num_filters; /* Number of filters for job */
+ mime_filter_t *filters; /* Filters for job */
+ char method[255], /* Method for output */
+ *optptr; /* Pointer to options */
+ ipp_attribute_t *attr; /* Current attribute */
+ int pid; /* Process ID of new filter process */
+ int banner_page; /* 1 if banner page, 0 otherwise */
+ int statusfds[2], /* Pipes used between the filters and scheduler */
+ filterfds[2][2];/* Pipes used between the filters */
+ char *argv[8], /* Filter command-line arguments */
+ filename[1024], /* Job filename */
+ command[1024], /* Full path to filter/backend command */
+ jobid[255], /* Job ID string */
+ title[IPP_MAX_NAME],
+ /* Job title string */
+ copies[255], /* # copies string */
+ options[16384], /* Full list of options */
+ *envp[20], /* Environment variables */
+ path[1024], /* PATH environment variable */
+ language[255], /* LANG environment variable */
+ charset[255], /* CHARSET environment variable */
+ classification[1024], /* CLASSIFICATION environment variable */
+ content_type[255],/* CONTENT_TYPE environment variable */
+ device_uri[1024],/* DEVICE_URI environment variable */
+ ppd[1024], /* PPD environment variable */
+ printer_name[255],/* PRINTER environment variable */
+ root[1024], /* CUPS_SERVERROOT environment variable */
+ cache[255], /* RIP_MAX_CACHE environment variable */
+ tmpdir[1024], /* TMPDIR environment variable */
+ ldpath[1024], /* LD_LIBRARY_PATH environment variable */
+ datadir[1024], /* CUPS_DATADIR environment variable */
+ fontpath[1050]; /* CUPS_FONTPATH environment variable */
+
+
+ LogMessage(L_DEBUG, "StartJob(%d, %08x)", id, printer);
+
+ for (current = Jobs; current != NULL; current = current->next)
+ if (current->id == id)
+ break;
+
+ if (current == NULL)
+ return;
+
+ LogMessage(L_DEBUG, "StartJob() id = %d, file = %d/%d", id,
+ current->current_file, current->num_files);
+
+ if (current->num_files == 0)
+ {
+ LogMessage(L_ERROR, "Job ID %d has no files! Cancelling it!", id);
+ CancelJob(id, 0);
+ return;
+ }
+
+ /*
+ * Figure out what filters are required to convert from
+ * the source to the destination type...
+ */
+
+ num_filters = 0;
+ current->cost = 0;
+
+ if (printer->type & CUPS_PRINTER_REMOTE)
+ {
+ /*
+ * Remote jobs go directly to the remote job...
+ */
+
+ filters = NULL;
+ }
+ else
+ {
+ /*
+ * Local jobs get filtered...
+ */
+
+ filters = mimeFilter(MimeDatabase, current->filetypes[current->current_file],
+ printer->filetype, &num_filters);
+
+ if (num_filters == 0)
+ {
+ LogMessage(L_ERROR, "Unable to convert file %d to printable format for job %d!",
+ current->current_file, current->id);
+ current->current_file ++;
+
+ if (current->current_file == current->num_files)
+ CancelJob(current->id, 0);
+
+ return;
+ }
+
+ /*
+ * Remove NULL ("-") filters...
+ */
+
+ for (i = 0; i < num_filters;)
+ if (strcmp(filters[i].filter, "-") == 0)
+ {
+ num_filters --;
+ if (i < num_filters)
+ memcpy(filters + i, filters + i + 1,
+ (num_filters - i) * sizeof(mime_filter_t));
+ }
+ else
+ i ++;
+
+ if (num_filters == 0)
+ {
+ free(filters);
+ filters = NULL;
+ }
+ else
+ {
+ /*
+ * Compute filter cost...
+ */
+
+ for (i = 0; i < num_filters; i ++)
+ current->cost += filters[i].cost;
+ }
+ }
+
+ /*
+ * See if the filter cost is too high...
+ */
+
+ if ((FilterLevel + current->cost) > FilterLimit && FilterLevel > 0 &&
+ FilterLimit > 0)
+ {
+ /*
+ * Don't print this job quite yet...
+ */
+
+ if (filters != NULL)
+ free(filters);
+
+ LogMessage(L_INFO, "Holding job %d because filter limit has been reached.",
+ id);
+ LogMessage(L_DEBUG, "StartJob: id = %d, file = %d, "
+ "cost = %d, level = %d, limit = %d",
+ id, current->current_file, current->cost, FilterLevel,
+ FilterLimit);
+ return;
+ }
+
+ FilterLevel += current->cost;
+
+ /*
+ * Update the printer and job state to "processing"...
+ */
+
+ current->state->values[0].integer = IPP_JOB_PROCESSING;
+ current->status = 0;
+ current->printer = printer;
+ printer->job = current;
+ SetPrinterState(printer, IPP_PRINTER_PROCESSING);
+
+ if (current->current_file == 0)
+ set_time(current, "time-at-processing");
+
+ /*
+ * Determine if we are printing a banner page or not...
+ */
+
+ if (current->job_sheets == NULL)
+ {
+ LogMessage(L_DEBUG, "No job-sheets attribute.");
+ if ((current->job_sheets =
+ ippFindAttribute(current->attrs, "job-sheets", IPP_TAG_ZERO)) != NULL)
+ LogMessage(L_DEBUG, "... but someone added one without setting job_sheets!");
+ }
+ else if (current->job_sheets->num_values == 1)
+ LogMessage(L_DEBUG, "job-sheets=%s",
+ current->job_sheets->values[0].string.text);
+ else
+ LogMessage(L_DEBUG, "job-sheets=%s,%s",
+ current->job_sheets->values[0].string.text,
+ current->job_sheets->values[1].string.text);
+
+ if (printer->type & CUPS_PRINTER_REMOTE)
+ banner_page = 0;
+ else if (current->job_sheets == NULL)
+ banner_page = 0;
+ else if (strcasecmp(current->job_sheets->values[0].string.text, "none") != 0 &&
+ current->current_file == 0)
+ banner_page = 1;
+ else if (current->job_sheets->num_values > 1 &&
+ strcasecmp(current->job_sheets->values[1].string.text, "none") != 0 &&
+ current->current_file == (current->num_files - 1))
+ banner_page = 1;
+ else
+ banner_page = 0;
+
+ LogMessage(L_DEBUG, "banner_page = %d", banner_page);
+
+ /*
+ * Building the options string is harder than it needs to be, but
+ * for the moment we need to pass strings for command-line args and
+ * not IPP attribute pointers... :)
+ */
+
+ optptr = options;
+ *optptr = '\0';
+
+ snprintf(title, sizeof(title), "%s-%d", printer->name, current->id);
+ strcpy(copies, "1");
+
+ for (attr = current->attrs->attrs; attr != NULL; attr = attr->next)
+ {
+ if (strcmp(attr->name, "copies") == 0 &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ {
+ /*
+ * Don't use the # copies attribute if we are printing the job sheets...
+ */
+
+ if (!banner_page)
+ sprintf(copies, "%d", attr->values[0].integer);
+ }
+ else if (strcmp(attr->name, "job-name") == 0 &&
+ (attr->value_tag == IPP_TAG_NAME ||
+ attr->value_tag == IPP_TAG_NAMELANG))
+ {
+ strncpy(title, attr->values[0].string.text, sizeof(title) - 1);
+ title[sizeof(title) - 1] = '\0';
+ }
+ else if (attr->group_tag == IPP_TAG_JOB)
+ {
+ /*
+ * Filter out other unwanted attributes...
+ */
+
+ if (attr->value_tag == IPP_TAG_MIMETYPE ||
+ attr->value_tag == IPP_TAG_NAMELANG ||
+ attr->value_tag == IPP_TAG_TEXTLANG ||
+ attr->value_tag == IPP_TAG_URI ||
+ attr->value_tag == IPP_TAG_URISCHEME)
+ continue;
+
+ if (strncmp(attr->name, "time-", 5) == 0)
+ continue;
+
+ if (strncmp(attr->name, "job-", 4) == 0 &&
+ !(printer->type & CUPS_PRINTER_REMOTE))
+ continue;
+
+ if (strncmp(attr->name, "job-", 4) == 0 &&
+ strcmp(attr->name, "job-billing") != 0 &&
+ strcmp(attr->name, "job-sheets") != 0 &&
+ strcmp(attr->name, "job-hold-until") != 0 &&
+ strcmp(attr->name, "job-priority") != 0)
+ continue;
+
+ if (strcmp(attr->name, "page-label") == 0 &&
+ banner_page)
+ continue;
+
+ /*
+ * Otherwise add them to the list...
+ */
+
+ if (optptr > options)
+ strncat(optptr, " ", sizeof(options) - (optptr - options) - 1);
+
+ if (attr->value_tag != IPP_TAG_BOOLEAN)
+ {
+ strncat(optptr, attr->name, sizeof(options) - (optptr - options) - 1);
+ strncat(optptr, "=", sizeof(options) - (optptr - options) - 1);
+ }
+
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (i)
+ strncat(optptr, ",", sizeof(options) - (optptr - options) - 1);
+
+ optptr += strlen(optptr);
+
+ switch (attr->value_tag)
+ {
+ case IPP_TAG_INTEGER :
+ case IPP_TAG_ENUM :
+ snprintf(optptr, sizeof(options) - (optptr - options) - 1,
+ "%d", attr->values[i].integer);
+ break;
+
+ case IPP_TAG_BOOLEAN :
+ if (!attr->values[i].boolean)
+ strncat(optptr, "no", sizeof(options) - (optptr - options) - 1);
+
+ case IPP_TAG_NOVALUE :
+ strncat(optptr, attr->name,
+ sizeof(options) - (optptr - options) - 1);
+ break;
+
+ case IPP_TAG_RANGE :
+ snprintf(optptr, sizeof(options) - (optptr - options) - 1,
+ "%d-%d", attr->values[i].range.lower,
+ attr->values[i].range.upper);
+ break;
+
+ case IPP_TAG_RESOLUTION :
+ snprintf(optptr, sizeof(options) - (optptr - options) - 1,
+ "%dx%d%s", attr->values[i].resolution.xres,
+ attr->values[i].resolution.yres,
+ attr->values[i].resolution.units == IPP_RES_PER_INCH ?
+ "dpi" : "dpc");
+ break;
+
+ case IPP_TAG_STRING :
+ case IPP_TAG_TEXT :
+ case IPP_TAG_NAME :
+ case IPP_TAG_KEYWORD :
+ case IPP_TAG_CHARSET :
+ case IPP_TAG_LANGUAGE :
+ if (strchr(attr->values[i].string.text, ' ') != NULL ||
+ strchr(attr->values[i].string.text, '\t') != NULL ||
+ strchr(attr->values[i].string.text, '\n') != NULL)
+ {
+ strncat(optptr, "\'", sizeof(options) - (optptr - options) - 1);
+ strncat(optptr, attr->values[i].string.text,
+ sizeof(options) - (optptr - options) - 1);
+ strncat(optptr, "\'", sizeof(options) - (optptr - options) - 1);
+ }
+ else
+ strncat(optptr, attr->values[i].string.text,
+ sizeof(options) - (optptr - options) - 1);
+ break;
+
+ default :
+ break; /* anti-compiler-warning-code */
+ }
+ }
+
+ optptr += strlen(optptr);
+ }
+ }
+
+ /*
+ * Build the command-line arguments for the filters. Each filter
+ * has 6 or 7 arguments:
+ *
+ * argv[0] = printer
+ * argv[1] = job ID
+ * argv[2] = username
+ * argv[3] = title
+ * argv[4] = # copies
+ * argv[5] = options
+ * argv[6] = filename (optional; normally stdin)
+ *
+ * This allows legacy printer drivers that use the old System V
+ * printing interface to be used by CUPS.
+ */
+
+ sprintf(jobid, "%d", current->id);
+ snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot,
+ current->id, current->current_file + 1);
+
+ argv[0] = printer->name;
+ argv[1] = jobid;
+ argv[2] = current->username;
+ argv[3] = title;
+ argv[4] = copies;
+ argv[5] = options;
+ argv[6] = filename;
+ argv[7] = NULL;
+
+ LogMessage(L_DEBUG, "StartJob: argv = \"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"",
+ argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]);
+
+ /*
+ * Create environment variable strings for the filters...
+ */
+
+ attr = ippFindAttribute(current->attrs, "attributes-natural-language",
+ IPP_TAG_LANGUAGE);
+ snprintf(language, sizeof(language), "LANG=%s", attr->values[0].string.text);
+
+ attr = ippFindAttribute(current->attrs, "document-format",
+ IPP_TAG_MIMETYPE);
+ if (attr != NULL &&
+ (optptr = strstr(attr->values[0].string.text, "charset=")) != NULL)
+ snprintf(charset, sizeof(charset), "CHARSET=%s", optptr + 8);
+ else
+ {
+ attr = ippFindAttribute(current->attrs, "attributes-charset",
+ IPP_TAG_CHARSET);
+ snprintf(charset, sizeof(charset), "CHARSET=%s",
+ attr->values[0].string.text);
+ }
+
+ snprintf(path, sizeof(path), "PATH=%s/filter:/bin:/usr/bin", ServerBin);
+ snprintf(content_type, sizeof(content_type), "CONTENT_TYPE=%s/%s",
+ current->filetypes[current->current_file]->super,
+ current->filetypes[current->current_file]->type);
+ snprintf(device_uri, sizeof(device_uri), "DEVICE_URI=%s", printer->device_uri);
+ snprintf(ppd, sizeof(ppd), "PPD=%s/ppd/%s.ppd", ServerRoot, printer->name);
+ snprintf(printer_name, sizeof(printer_name), "PRINTER=%s", printer->name);
+ snprintf(cache, sizeof(cache), "RIP_MAX_CACHE=%s", RIPCache);
+ snprintf(root, sizeof(root), "CUPS_SERVERROOT=%s", ServerRoot);
+ snprintf(tmpdir, sizeof(tmpdir), "TMPDIR=%s", TempDir);
+ snprintf(datadir, sizeof(datadir), "CUPS_DATADIR=%s", DataDir);
+ snprintf(fontpath, sizeof(fontpath), "CUPS_FONTPATH=%s", FontPath);
+ if (Classification[0] && !banner_page)
+ {
+ if ((attr = ippFindAttribute(current->attrs, "job-sheets",
+ IPP_TAG_NAME)) == NULL)
+ snprintf(classification, sizeof(classification), "CLASSIFICATION=%s",
+ Classification);
+ else if (attr->num_values > 1 &&
+ strcmp(attr->values[1].string.text, "none") != 0)
+ snprintf(classification, sizeof(classification), "CLASSIFICATION=%s",
+ attr->values[1].string.text);
+ else
+ snprintf(classification, sizeof(classification), "CLASSIFICATION=%s",
+ attr->values[0].string.text);
+ }
+ else
+ classification[0] = '\0';
+ if (getenv("LD_LIBRARY_PATH") != NULL)
+ snprintf(ldpath, sizeof(ldpath), "LD_LIBRARY_PATH=%s", getenv("LD_LIBRARY_PATH"));
+ else
+ ldpath[0] = '\0';
+
+ envp[0] = path;
+ envp[1] = "SOFTWARE=CUPS/1.1";
+ envp[2] = "USER=root";
+ envp[3] = charset;
+ envp[4] = language;
+ envp[5] = TZ;
+ envp[6] = ppd;
+ envp[7] = root;
+ envp[8] = cache;
+ envp[9] = tmpdir;
+ envp[10] = content_type;
+ envp[11] = device_uri;
+ envp[12] = printer_name;
+ envp[13] = datadir;
+ envp[14] = fontpath;
+ envp[15] = ldpath;
+ envp[16] = classification;
+ envp[17] = NULL;
+
+ LogMessage(L_DEBUG, "StartJob: envp = \"%s\",\"%s\",\"%s\",\"%s\","
+ "\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\","
+ "\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"",
+ envp[0], envp[1], envp[2], envp[3], envp[4],
+ envp[5], envp[6], envp[7], envp[8], envp[9],
+ envp[10], envp[11], envp[12], envp[13], envp[14],
+ envp[15], envp[16]);
+
+ current->current_file ++;
+
+ /*
+ * Make sure we have a buffer to read status info into...
+ */
+
+ if (current->buffer == NULL)
+ {
+ LogMessage(L_DEBUG2, "UpdateJob: Allocating status buffer...");
+
+ if ((current->buffer = malloc(JOB_BUFFER_SIZE)) == NULL)
+ {
+ LogMessage(L_EMERG, "Unable to allocate memory for job status buffer - %s",
+ strerror(errno));
+ CancelJob(current->id, 0);
+ return;
+ }
+
+ current->bufused = 0;
+ }
+
+ /*
+ * Now create processes for all of the filters...
+ */
+
+ if (pipe(statusfds))
+ {
+ LogMessage(L_ERROR, "Unable to create job status pipes - %s.",
+ strerror(errno));
+ snprintf(printer->state_message, sizeof(printer->state_message),
+ "Unable to create status pipes - %s.", strerror(errno));
+ return;
+ }
+
+ LogMessage(L_DEBUG, "StartJob: statusfds = %d, %d",
+ statusfds[0], statusfds[1]);
+
+ current->pipe = statusfds[0];
+ current->status = 0;
+ memset(current->procs, 0, sizeof(current->procs));
+
+ filterfds[1][0] = open("/dev/null", O_RDONLY);
+ filterfds[1][1] = -1;
+
+ LogMessage(L_DEBUG, "StartJob: filterfds[%d] = %d, %d", 1, filterfds[1][0],
+ filterfds[1][1]);
+
+ for (i = 0, slot = 0; i < num_filters; i ++)
+ {
+ if (filters[i].filter[0] != '/')
+ snprintf(command, sizeof(command), "%s/filter/%s", ServerBin,
+ filters[i].filter);
+ else
+ {
+ strncpy(command, filters[i].filter, sizeof(command) - 1);
+ command[sizeof(command) - 1] = '\0';
+ }
+
+ if (i < (num_filters - 1) ||
+ strncmp(printer->device_uri, "file:", 5) != 0)
+ pipe(filterfds[slot]);
+ else
+ {
+ filterfds[slot][0] = -1;
+ if (strncmp(printer->device_uri, "file:/dev/", 10) == 0)
+ filterfds[slot][1] = open(printer->device_uri + 5,
+ O_WRONLY | O_EXCL);
+ else
+ filterfds[slot][1] = open(printer->device_uri + 5,
+ O_WRONLY | O_CREAT | O_TRUNC, 0600);
+ }
+
+ LogMessage(L_DEBUG, "StartJob: filter = \"%s\"", command);
+ LogMessage(L_DEBUG, "StartJob: filterfds[%d] = %d, %d",
+ slot, filterfds[slot][0], filterfds[slot][1]);
+
+ pid = start_process(command, argv, envp, filterfds[!slot][0],
+ filterfds[slot][1], statusfds[1], 0);
+
+ close(filterfds[!slot][0]);
+ close(filterfds[!slot][1]);
+
+ if (pid == 0)
+ {
+ LogMessage(L_ERROR, "Unable to start filter \"%s\" - %s.",
+ filters[i].filter, strerror(errno));
+ snprintf(printer->state_message, sizeof(printer->state_message),
+ "Unable to start filter \"%s\" - %s.",
+ filters[i].filter, strerror(errno));
+ return;
+ }
+
+ current->procs[i] = pid;
+
+ LogMessage(L_INFO, "Started filter %s (PID %d) for job %d.",
+ command, pid, current->id);
+
+ argv[6] = NULL;
+ slot = !slot;
+ }
+
+ if (filters != NULL)
+ free(filters);
+
+ /*
+ * Finally, pipe the final output into a backend process if needed...
+ */
+
+ if (strncmp(printer->device_uri, "file:", 5) != 0)
+ {
+ sscanf(printer->device_uri, "%254[^:]", method);
+ snprintf(command, sizeof(command), "%s/backend/%s", ServerBin, method);
+
+ argv[0] = printer->device_uri;
+
+ filterfds[slot][0] = -1;
+ filterfds[slot][1] = open("/dev/null", O_WRONLY);
+
+ LogMessage(L_DEBUG, "StartJob: backend = \"%s\"", command);
+ LogMessage(L_DEBUG, "StartJob: filterfds[%d] = %d, %d",
+ slot, filterfds[slot][0], filterfds[slot][1]);
+
+ pid = start_process(command, argv, envp, filterfds[!slot][0],
+ filterfds[slot][1], statusfds[1], 1);
+
+ close(filterfds[!slot][0]);
+ close(filterfds[!slot][1]);
+
+ if (pid == 0)
+ {
+ LogMessage(L_ERROR, "Unable to start backend \"%s\" - %s.",
+ method, strerror(errno));
+ snprintf(printer->state_message, sizeof(printer->state_message),
+ "Unable to start backend \"%s\" - %s.", method, strerror(errno));
+ return;
+ }
+ else
+ {
+ current->procs[i] = pid;
+
+ LogMessage(L_INFO, "Started backend %s (PID %d) for job %d.", command, pid,
+ current->id);
+ }
+ }
+ else
+ {
+ filterfds[slot][0] = -1;
+ filterfds[slot][1] = -1;
+
+ close(filterfds[!slot][0]);
+ close(filterfds[!slot][1]);
+ }
+
+ close(filterfds[slot][0]);
+ close(filterfds[slot][1]);
+
+ close(statusfds[1]);
+
+ LogMessage(L_DEBUG2, "StartJob: Adding fd %d to InputSet...", current->pipe);
+
+ FD_SET(current->pipe, &InputSet);
+}
+
+
+/*
+ * 'StopAllJobs()' - Stop all print jobs.
+ */
+
+void
+StopAllJobs(void)
+{
+ job_t *current; /* Current job */
+
+
+ DEBUG_puts("StopAllJobs()");
+
+ for (current = Jobs; current != NULL; current = current->next)
+ if (current->state->values[0].integer == IPP_JOB_PROCESSING)
+ {
+ StopJob(current->id, 1);
+ current->state->values[0].integer = IPP_JOB_PENDING;
+ }
+}
+
+
+/*
+ * 'StopJob()' - Stop a print job.
+ */
+
+void
+StopJob(int id, /* I - Job ID */
+ int force) /* I - 1 = Force all filters to stop */
+{
+ int i; /* Looping var */
+ job_t *current; /* Current job */
+
+
+ LogMessage(L_DEBUG, "StopJob: id = %d, force = %d", id, force);
+
+ for (current = Jobs; current != NULL; current = current->next)
+ if (current->id == id)
+ {
+ DEBUG_puts("StopJob: found job in list.");
+
+ if (current->state->values[0].integer == IPP_JOB_PROCESSING)
+ {
+ DEBUG_puts("StopJob: job state is \'processing\'.");
+
+ FilterLevel -= current->cost;
+
+ if (current->status < 0)
+ SetPrinterState(current->printer, IPP_PRINTER_STOPPED);
+ else if (current->printer->state != IPP_PRINTER_STOPPED)
+ SetPrinterState(current->printer, IPP_PRINTER_IDLE);
+
+ LogMessage(L_DEBUG, "StopJob: printer state is %d", current->printer->state);
+
+ current->state->values[0].integer = IPP_JOB_STOPPED;
+ current->printer->job = NULL;
+ current->printer = NULL;
+
+ current->current_file --;
+
+ for (i = 0; current->procs[i]; i ++)
+ if (current->procs[i] > 0)
+ {
+ kill(current->procs[i], force ? SIGKILL : SIGTERM);
+ current->procs[i] = 0;
+ }
+
+ if (current->pipe)
+ {
+ /*
+ * Close the pipe and clear the input bit.
+ */
+
+ LogMessage(L_DEBUG2, "StopJob: Removing fd %d from InputSet...",
+ current->pipe);
+
+ close(current->pipe);
+ FD_CLR(current->pipe, &InputSet);
+ current->pipe = 0;
+ }
+
+ if (current->buffer)
+ {
+ /*
+ * Free the status buffer...
+ */
+
+ LogMessage(L_DEBUG2, "StopJob: Freeing status buffer...");
+
+ free(current->buffer);
+ current->buffer = NULL;
+ current->bufused = 0;
+ }
+ }
+ return;
+ }
+}
+
+
+/*
+ * 'UpdateJob()' - Read a status update from a job's filters.
+ */
+
+void
+UpdateJob(job_t *job) /* I - Job to check */
+{
+ int bytes; /* Number of bytes read */
+ int copies; /* Number of copies printed */
+ char *lineptr, /* Pointer to end of line in buffer */
+ *message; /* Pointer to message text */
+ int loglevel; /* Log level for message */
+
+
+ if ((bytes = read(job->pipe, job->buffer + job->bufused,
+ JOB_BUFFER_SIZE - job->bufused - 1)) > 0)
+ {
+ job->bufused += bytes;
+ job->buffer[job->bufused] = '\0';
+ lineptr = strchr(job->buffer, '\n');
+ }
+ else if (bytes < 0 && errno == EINTR)
+ return;
+ else
+ {
+ lineptr = job->buffer + job->bufused;
+ lineptr[1] = 0;
+ }
+
+ if (job->bufused == 0 && bytes == 0)
+ lineptr = NULL;
+
+ while (lineptr != NULL)
+ {
+ /*
+ * Terminate each line and process it...
+ */
+
+ *lineptr++ = '\0';
+
+ /*
+ * Figure out the logging level...
+ */
+
+ if (strncmp(job->buffer, "EMERG:", 6) == 0)
+ {
+ loglevel = L_EMERG;
+ message = job->buffer + 6;
+ }
+ else if (strncmp(job->buffer, "ALERT:", 6) == 0)
+ {
+ loglevel = L_ALERT;
+ message = job->buffer + 6;
+ }
+ else if (strncmp(job->buffer, "CRIT:", 5) == 0)
+ {
+ loglevel = L_CRIT;
+ message = job->buffer + 5;
+ }
+ else if (strncmp(job->buffer, "ERROR:", 6) == 0)
+ {
+ loglevel = L_ERROR;
+ message = job->buffer + 6;
+ }
+ else if (strncmp(job->buffer, "WARNING:", 8) == 0)
+ {
+ loglevel = L_WARN;
+ message = job->buffer + 8;
+ }
+ else if (strncmp(job->buffer, "NOTICE:", 6) == 0)
+ {
+ loglevel = L_NOTICE;
+ message = job->buffer + 6;
+ }
+ else if (strncmp(job->buffer, "INFO:", 5) == 0)
+ {
+ loglevel = L_INFO;
+ message = job->buffer + 5;
+ }
+ else if (strncmp(job->buffer, "DEBUG:", 6) == 0)
+ {
+ loglevel = L_DEBUG;
+ message = job->buffer + 6;
+ }
+ else if (strncmp(job->buffer, "DEBUG2:", 7) == 0)
+ {
+ loglevel = L_DEBUG2;
+ message = job->buffer + 7;
+ }
+ else if (strncmp(job->buffer, "PAGE:", 5) == 0)
+ {
+ loglevel = L_PAGE;
+ message = job->buffer + 5;
+ }
+ else
+ {
+ loglevel = L_DEBUG;
+ message = job->buffer;
+ }
+
+ /*
+ * Skip leading whitespace in the message...
+ */
+
+ while (isspace(*message))
+ message ++;
+
+ /*
+ * Send it to the log file and printer state message as needed...
+ */
+
+ if (loglevel == L_PAGE)
+ {
+ /*
+ * Page message; send the message to the page_log file and update the
+ * job sheet count...
+ */
+
+ if (job->sheets != NULL)
+ {
+ if (!sscanf(message, "%*d%d", &copies))
+ {
+ job->sheets->values[0].integer ++;
+
+ if (job->printer->page_limit)
+ UpdateQuota(job->printer, job->username, 1, 0);
+ }
+ else
+ {
+ job->sheets->values[0].integer += copies;
+
+ if (job->printer->page_limit)
+ UpdateQuota(job->printer, job->username, copies, 0);
+ }
+ }
+
+ LogPage(job, message);
+ }
+ else
+ {
+ /*
+ * Other status message; send it to the error_log file...
+ */
+
+ if (loglevel != L_INFO)
+ LogMessage(loglevel, "%s", message);
+
+ if ((loglevel == L_INFO && !job->status) ||
+ loglevel < L_INFO)
+ strncpy(job->printer->state_message, message,
+ sizeof(job->printer->state_message) - 1);
+ }
+
+ /*
+ * Copy over the buffer data we've used up...
+ */
+
+ strcpy(job->buffer, lineptr);
+ job->bufused -= lineptr - job->buffer;
+
+ if (job->bufused < 0)
+ job->bufused = 0;
+
+ lineptr = strchr(job->buffer, '\n');
+ }
+
+ if (bytes <= 0)
+ {
+ LogMessage(L_DEBUG, "UpdateJob: job %d, file %d is complete.",
+ job->id, job->current_file - 1);
+
+ if (job->pipe)
+ {
+ /*
+ * Close the pipe and clear the input bit.
+ */
+
+ LogMessage(L_DEBUG2, "UpdateJob: Removing fd %d from InputSet...",
+ job->pipe);
+
+ close(job->pipe);
+ FD_CLR(job->pipe, &InputSet);
+ job->pipe = 0;
+ }
+
+ if (job->status < 0)
+ {
+ /*
+ * Backend had errors; stop it...
+ */
+
+ StopJob(job->id, 0);
+ job->state->values[0].integer = IPP_JOB_PENDING;
+ SaveJob(job->id);
+ }
+ else if (job->status > 0)
+ {
+ /*
+ * Filter had errors; cancel it...
+ */
+
+ if (job->current_file < job->num_files)
+ StartJob(job->id, job->printer);
+ else
+ {
+ CancelJob(job->id, 0);
+
+ if (JobHistory)
+ {
+ job->state->values[0].integer = IPP_JOB_ABORTED;
+ SaveJob(job->id);
+ }
+
+ CheckJobs();
+ }
+ }
+ else
+ {
+ /*
+ * Job printed successfully; cancel it...
+ */
+
+ if (job->current_file < job->num_files)
+ {
+ FilterLevel -= job->cost;
+ StartJob(job->id, job->printer);
+ }
+ else
+ {
+ CancelJob(job->id, 0);
+
+ if (JobHistory)
+ {
+ job->state->values[0].integer = IPP_JOB_COMPLETED;
+ SaveJob(job->id);
+ }
+
+ CheckJobs();
+ }
+ }
+ }
+}
+
+
+/*
+ * 'ipp_read_file()' - Read an IPP request from a file.
+ */
+
+static ipp_state_t /* O - State */
+ipp_read_file(const char *filename, /* I - File to read from */
+ ipp_t *ipp) /* I - Request to read into */
+{
+ int fd; /* File descriptor for file */
+ int n; /* Length of data */
+ unsigned char buffer[8192], /* Data buffer */
+ *bufptr; /* Pointer into buffer */
+ ipp_attribute_t *attr; /* Current attribute */
+ ipp_tag_t tag; /* Current tag */
+
+
+ /*
+ * Open the file if possible...
+ */
+
+ if (filename == NULL || ipp == NULL)
+ return (IPP_ERROR);
+
+ if ((fd = open(filename, O_RDONLY)) == -1)
+ return (IPP_ERROR);
+
+ /*
+ * Read the IPP request...
+ */
+
+ ipp->state = IPP_IDLE;
+
+ switch (ipp->state)
+ {
+ default :
+ break; /* anti-compiler-warning-code */
+
+ case IPP_IDLE :
+ ipp->state ++; /* Avoid common problem... */
+
+ case IPP_HEADER :
+ /*
+ * Get the request header...
+ */
+
+ if ((n = read(fd, buffer, 8)) < 8)
+ {
+ DEBUG_printf(("ipp_read_file: Unable to read header (%d bytes read)!\n", n));
+ close(fd);
+ return (n == 0 ? IPP_IDLE : IPP_ERROR);
+ }
+
+ /*
+ * Verify the major version number...
+ */
+
+ if (buffer[0] != 1)
+ {
+ DEBUG_printf(("ipp_read_file: version number (%d.%d) is bad.\n", buffer[0],
+ buffer[1]));
+ close(fd);
+ return (IPP_ERROR);
+ }
+
+ /*
+ * Then copy the request header over...
+ */
+
+ ipp->request.any.version[0] = buffer[0];
+ ipp->request.any.version[1] = buffer[1];
+ ipp->request.any.op_status = (buffer[2] << 8) | buffer[3];
+ ipp->request.any.request_id = (((((buffer[4] << 8) | buffer[5]) << 8) |
+ buffer[6]) << 8) | buffer[7];
+
+ ipp->state = IPP_ATTRIBUTE;
+ ipp->current = NULL;
+ ipp->curtag = IPP_TAG_ZERO;
+
+ case IPP_ATTRIBUTE :
+ while (read(fd, buffer, 1) > 0)
+ {
+ /*
+ * Read this attribute...
+ */
+
+ tag = (ipp_tag_t)buffer[0];
+
+ if (tag == IPP_TAG_END)
+ {
+ /*
+ * No more attributes left...
+ */
+
+ DEBUG_puts("ipp_read_file: IPP_TAG_END!");
+
+ ipp->state = IPP_DATA;
+ break;
+ }
+ else if (tag < IPP_TAG_UNSUPPORTED_VALUE)
+ {
+ /*
+ * Group tag... Set the current group and continue...
+ */
+
+ if (ipp->curtag == tag)
+ ippAddSeparator(ipp);
+
+ ipp->curtag = tag;
+ ipp->current = NULL;
+ DEBUG_printf(("ipp_read_file: group tag = %x\n", tag));
+ continue;
+ }
+
+ DEBUG_printf(("ipp_read_file: value tag = %x\n", tag));
+
+ /*
+ * Get the name...
+ */
+
+ if (read(fd, buffer, 2) < 2)
+ {
+ DEBUG_puts("ipp_read_file: unable to read name length!");
+ close(fd);
+ return (IPP_ERROR);
+ }
+
+ n = (buffer[0] << 8) | buffer[1];
+
+ DEBUG_printf(("ipp_read_file: name length = %d\n", n));
+
+ if (n == 0)
+ {
+ /*
+ * More values for current attribute...
+ */
+
+ if (ipp->current == NULL)
+ {
+ close(fd);
+ return (IPP_ERROR);
+ }
+
+ attr = ipp->current;
+
+ /*
+ * Finally, reallocate the attribute array as needed...
+ */
+
+ if ((attr->num_values % IPP_MAX_VALUES) == 0)
+ {
+ ipp_attribute_t *temp, /* Pointer to new buffer */
+ *ptr; /* Pointer in attribute list */
+
+
+ /*
+ * Reallocate memory...
+ */
+
+ if ((temp = realloc(attr, sizeof(ipp_attribute_t) +
+ (attr->num_values + IPP_MAX_VALUES - 1) *
+ sizeof(ipp_value_t))) == NULL)
+ {
+ close(fd);
+ return (IPP_ERROR);
+ }
+
+ /*
+ * Reset pointers in the list...
+ */
+
+ for (ptr = ipp->attrs; ptr && ptr->next != attr; ptr = ptr->next);
+
+ if (ptr)
+ ptr->next = temp;
+ else
+ ipp->attrs = temp;
+
+ attr = ipp->current = ipp->last = temp;
+ }
+ }
+ else
+ {
+ /*
+ * New attribute; read the name and add it...
+ */
+
+ if (read(fd, buffer, n) < n)
+ {
+ DEBUG_puts("ipp_read_file: unable to read name!");
+ close(fd);
+ return (IPP_ERROR);
+ }
+
+ buffer[n] = '\0';
+ DEBUG_printf(("ipp_read_file: name = \'%s\'\n", buffer));
+
+ attr = ipp->current = _ipp_add_attr(ipp, IPP_MAX_VALUES);
+
+ attr->group_tag = ipp->curtag;
+ attr->value_tag = tag;
+ attr->name = strdup((char *)buffer);
+ attr->num_values = 0;
+ }
+
+ if (read(fd, buffer, 2) < 2)
+ {
+ DEBUG_puts("ipp_read_file: unable to read value length!");
+ close(fd);
+ return (IPP_ERROR);
+ }
+
+ n = (buffer[0] << 8) | buffer[1];
+ DEBUG_printf(("ipp_read_file: value length = %d\n", n));
+
+ switch (tag)
+ {
+ case IPP_TAG_INTEGER :
+ case IPP_TAG_ENUM :
+ if (read(fd, buffer, 4) < 4)
+ {
+ close(fd);
+ return (IPP_ERROR);
+ }
+
+ n = (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
+ buffer[3];
+
+ attr->values[attr->num_values].integer = n;
+ break;
+ case IPP_TAG_BOOLEAN :
+ if (read(fd, buffer, 1) < 1)
+ {
+ close(fd);
+ return (IPP_ERROR);
+ }
+
+ attr->values[attr->num_values].boolean = buffer[0];
+ break;
+ case IPP_TAG_TEXT :
+ case IPP_TAG_NAME :
+ case IPP_TAG_KEYWORD :
+ case IPP_TAG_STRING :
+ case IPP_TAG_URI :
+ case IPP_TAG_URISCHEME :
+ case IPP_TAG_CHARSET :
+ case IPP_TAG_LANGUAGE :
+ case IPP_TAG_MIMETYPE :
+ if (read(fd, buffer, n) < n)
+ {
+ close(fd);
+ return (IPP_ERROR);
+ }
+
+ buffer[n] = '\0';
+ DEBUG_printf(("ipp_read_file: value = \'%s\'\n", buffer));
+
+ attr->values[attr->num_values].string.text = strdup((char *)buffer);
+ break;
+ case IPP_TAG_DATE :
+ if (read(fd, buffer, 11) < 11)
+ {
+ close(fd);
+ return (IPP_ERROR);
+ }
+
+ memcpy(attr->values[attr->num_values].date, buffer, 11);
+ break;
+ case IPP_TAG_RESOLUTION :
+ if (read(fd, buffer, 9) < 9)
+ {
+ close(fd);
+ return (IPP_ERROR);
+ }
+
+ attr->values[attr->num_values].resolution.xres =
+ (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
+ buffer[3];
+ attr->values[attr->num_values].resolution.yres =
+ (((((buffer[4] << 8) | buffer[5]) << 8) | buffer[6]) << 8) |
+ buffer[7];
+ attr->values[attr->num_values].resolution.units =
+ (ipp_res_t)buffer[8];
+ break;
+ case IPP_TAG_RANGE :
+ if (read(fd, buffer, 8) < 8)
+ {
+ close(fd);
+ return (IPP_ERROR);
+ }
+
+ attr->values[attr->num_values].range.lower =
+ (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
+ buffer[3];
+ attr->values[attr->num_values].range.upper =
+ (((((buffer[4] << 8) | buffer[5]) << 8) | buffer[6]) << 8) |
+ buffer[7];
+ break;
+ case IPP_TAG_TEXTLANG :
+ case IPP_TAG_NAMELANG :
+ if (read(fd, buffer, n) < n)
+ return (IPP_ERROR);
+
+ bufptr = buffer;
+
+ /*
+ * text-with-language and name-with-language are composite
+ * values:
+ *
+ * charset-length
+ * charset
+ * text-length
+ * text
+ */
+
+ n = (bufptr[0] << 8) | bufptr[1];
+
+ attr->values[attr->num_values].string.charset = calloc(n + 1, 1);
+
+ memcpy(attr->values[attr->num_values].string.charset,
+ bufptr + 2, n);
+
+ bufptr += 2 + n;
+ n = (bufptr[0] << 8) | bufptr[1];
+
+ attr->values[attr->num_values].string.text = calloc(n + 1, 1);
+
+ memcpy(attr->values[attr->num_values].string.text,
+ bufptr + 2, n);
+
+ break;
+
+ default : /* Other unsupported values */
+ attr->values[attr->num_values].unknown.length = n;
+ if (n > 0)
+ {
+ attr->values[attr->num_values].unknown.data = malloc(n);
+ if (read(fd, attr->values[attr->num_values].unknown.data, n) < n)
+ return (IPP_ERROR);
+ }
+ else
+ attr->values[attr->num_values].unknown.data = NULL;
+ break;
+ }
+
+ attr->num_values ++;
+ }
+ break;
+
+ case IPP_DATA :
+ break;
+ }
+
+ /*
+ * Close the file and return...
+ */
+
+ close(fd);
+
+ return (ipp->state);
+}
+
+
+/*
+ * 'ipp_write_file()' - Write an IPP request to a file.
+ */
+
+static ipp_state_t /* O - State */
+ipp_write_file(const char *filename, /* I - File to write to */
+ ipp_t *ipp) /* I - Request to write */
+{
+ int fd; /* File descriptor */
+ int i; /* Looping var */
+ int n; /* Length of data */
+ unsigned char buffer[8192], /* Data buffer */
+ *bufptr; /* Pointer into buffer */
+ ipp_attribute_t *attr; /* Current attribute */
+
+
+ /*
+ * Open the file if possible...
+ */
+
+ if (filename == NULL || ipp == NULL)
+ return (IPP_ERROR);
+
+ if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) == -1)
+ return (IPP_ERROR);
+
+ fchmod(fd, 0600);
+ fchown(fd, User, Group);
+
+ /*
+ * Write the IPP request...
+ */
+
+ ipp->state = IPP_IDLE;
+
+ switch (ipp->state)
+ {
+ default :
+ break; /* anti-compiler-warning-code */
+
+ case IPP_IDLE :
+ ipp->state ++; /* Avoid common problem... */
+
+ case IPP_HEADER :
+ /*
+ * Send the request header...
+ */
+
+ bufptr = buffer;
+
+ *bufptr++ = ipp->request.any.version[0];
+ *bufptr++ = ipp->request.any.version[1];
+ *bufptr++ = ipp->request.any.op_status >> 8;
+ *bufptr++ = ipp->request.any.op_status;
+ *bufptr++ = ipp->request.any.request_id >> 24;
+ *bufptr++ = ipp->request.any.request_id >> 16;
+ *bufptr++ = ipp->request.any.request_id >> 8;
+ *bufptr++ = ipp->request.any.request_id;
+
+ if (write(fd, (char *)buffer, bufptr - buffer) < 0)
+ {
+ DEBUG_puts("ipp_write_file: Could not write IPP header...");
+ close(fd);
+ return (IPP_ERROR);
+ }
+
+ ipp->state = IPP_ATTRIBUTE;
+ ipp->current = ipp->attrs;
+ ipp->curtag = IPP_TAG_ZERO;
+
+ case IPP_ATTRIBUTE :
+ while (ipp->current != NULL)
+ {
+ /*
+ * Write this attribute...
+ */
+
+ bufptr = buffer;
+ attr = ipp->current;
+
+ ipp->current = ipp->current->next;
+
+ if (ipp->curtag != attr->group_tag)
+ {
+ /*
+ * Send a group operation tag...
+ */
+
+ ipp->curtag = attr->group_tag;
+
+ if (attr->group_tag == IPP_TAG_ZERO)
+ continue;
+
+ DEBUG_printf(("ipp_write_file: wrote group tag = %x\n", attr->group_tag));
+ *bufptr++ = attr->group_tag;
+ }
+
+ if ((n = strlen(attr->name)) > (sizeof(buffer) - 3))
+ return (IPP_ERROR);
+
+ DEBUG_printf(("ipp_write_file: writing value tag = %x\n", attr->value_tag));
+ DEBUG_printf(("ipp_write_file: writing name = %d, \'%s\'\n", n, attr->name));
+
+ *bufptr++ = attr->value_tag;
+ *bufptr++ = n >> 8;
+ *bufptr++ = n;
+ memcpy(bufptr, attr->name, n);
+ bufptr += n;
+
+ switch (attr->value_tag)
+ {
+ case IPP_TAG_INTEGER :
+ case IPP_TAG_ENUM :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if ((sizeof(buffer) - (bufptr - buffer)) < 9)
+ {
+ if (write(fd, (char *)buffer, bufptr - buffer) < 0)
+ {
+ DEBUG_puts("ippWrite: Could not write IPP attribute...");
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
+ if (i)
+ {
+ /*
+ * Arrays and sets are done by sending additional
+ * values with a zero-length name...
+ */
+
+ *bufptr++ = attr->value_tag;
+ *bufptr++ = 0;
+ *bufptr++ = 0;
+ }
+
+ *bufptr++ = 0;
+ *bufptr++ = 4;
+ *bufptr++ = attr->values[i].integer >> 24;
+ *bufptr++ = attr->values[i].integer >> 16;
+ *bufptr++ = attr->values[i].integer >> 8;
+ *bufptr++ = attr->values[i].integer;
+ }
+ break;
+
+ case IPP_TAG_BOOLEAN :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if ((sizeof(buffer) - (bufptr - buffer)) < 6)
+ {
+ if (write(fd, (char *)buffer, bufptr - buffer) < 0)
+ {
+ DEBUG_puts("ippWrite: Could not write IPP attribute...");
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
+ if (i)
+ {
+ /*
+ * Arrays and sets are done by sending additional
+ * values with a zero-length name...
+ */
+
+ *bufptr++ = attr->value_tag;
+ *bufptr++ = 0;
+ *bufptr++ = 0;
+ }
+
+ *bufptr++ = 0;
+ *bufptr++ = 1;
+ *bufptr++ = attr->values[i].boolean;
+ }
+ break;
+
+ case IPP_TAG_TEXT :
+ case IPP_TAG_NAME :
+ case IPP_TAG_KEYWORD :
+ case IPP_TAG_STRING :
+ case IPP_TAG_URI :
+ case IPP_TAG_URISCHEME :
+ case IPP_TAG_CHARSET :
+ case IPP_TAG_LANGUAGE :
+ case IPP_TAG_MIMETYPE :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (i)
+ {
+ /*
+ * Arrays and sets are done by sending additional
+ * values with a zero-length name...
+ */
+
+ DEBUG_printf(("ipp_write_file: writing value tag = %x\n",
+ attr->value_tag));
+ DEBUG_printf(("ipp_write_file: writing name = 0, \'\'\n"));
+
+ if ((sizeof(buffer) - (bufptr - buffer)) < 3)
+ {
+ if (write(fd, (char *)buffer, bufptr - buffer) < 0)
+ {
+ DEBUG_puts("ippWrite: Could not write IPP attribute...");
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
+ *bufptr++ = attr->value_tag;
+ *bufptr++ = 0;
+ *bufptr++ = 0;
+ }
+
+ n = strlen(attr->values[i].string.text);
+
+ if (n > sizeof(buffer))
+ return (IPP_ERROR);
+
+ DEBUG_printf(("ipp_write_file: writing string = %d, \'%s\'\n", n,
+ attr->values[i].string.text));
+
+ if ((sizeof(buffer) - (bufptr - buffer)) < (n + 2))
+ {
+ if (write(fd, (char *)buffer, bufptr - buffer) < 0)
+ {
+ DEBUG_puts("ipp_write_file: Could not write IPP attribute...");
+ close(fd);
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
+ *bufptr++ = n >> 8;
+ *bufptr++ = n;
+ memcpy(bufptr, attr->values[i].string.text, n);
+ bufptr += n;
+ }
+ break;
+
+ case IPP_TAG_DATE :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if ((sizeof(buffer) - (bufptr - buffer)) < 16)
+ {
+ if (write(fd, (char *)buffer, bufptr - buffer) < 0)
+ {
+ DEBUG_puts("ippWrite: Could not write IPP attribute...");
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
+ if (i)
+ {
+ /*
+ * Arrays and sets are done by sending additional
+ * values with a zero-length name...
+ */
+
+ *bufptr++ = attr->value_tag;
+ *bufptr++ = 0;
+ *bufptr++ = 0;
+ }
+
+ *bufptr++ = 0;
+ *bufptr++ = 11;
+ memcpy(bufptr, attr->values[i].date, 11);
+ bufptr += 11;
+ }
+ break;
+
+ case IPP_TAG_RESOLUTION :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if ((sizeof(buffer) - (bufptr - buffer)) < 14)
+ {
+ if (write(fd, (char *)buffer, bufptr - buffer) < 0)
+ {
+ DEBUG_puts("ippWrite: Could not write IPP attribute...");
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
+ if (i)
+ {
+ /*
+ * Arrays and sets are done by sending additional
+ * values with a zero-length name...
+ */
+
+ *bufptr++ = attr->value_tag;
+ *bufptr++ = 0;
+ *bufptr++ = 0;
+ }
+
+ *bufptr++ = 0;
+ *bufptr++ = 9;
+ *bufptr++ = attr->values[i].resolution.xres >> 24;
+ *bufptr++ = attr->values[i].resolution.xres >> 16;
+ *bufptr++ = attr->values[i].resolution.xres >> 8;
+ *bufptr++ = attr->values[i].resolution.xres;
+ *bufptr++ = attr->values[i].resolution.yres >> 24;
+ *bufptr++ = attr->values[i].resolution.yres >> 16;
+ *bufptr++ = attr->values[i].resolution.yres >> 8;
+ *bufptr++ = attr->values[i].resolution.yres;
+ *bufptr++ = attr->values[i].resolution.units;
+ }
+ break;
+
+ case IPP_TAG_RANGE :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if ((sizeof(buffer) - (bufptr - buffer)) < 13)
+ {
+ if (write(fd, (char *)buffer, bufptr - buffer) < 0)
+ {
+ DEBUG_puts("ippWrite: Could not write IPP attribute...");
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
+ if (i)
+ {
+ /*
+ * Arrays and sets are done by sending additional
+ * values with a zero-length name...
+ */
+
+ *bufptr++ = attr->value_tag;
+ *bufptr++ = 0;
+ *bufptr++ = 0;
+ }
+
+ *bufptr++ = 0;
+ *bufptr++ = 8;
+ *bufptr++ = attr->values[i].range.lower >> 24;
+ *bufptr++ = attr->values[i].range.lower >> 16;
+ *bufptr++ = attr->values[i].range.lower >> 8;
+ *bufptr++ = attr->values[i].range.lower;
+ *bufptr++ = attr->values[i].range.upper >> 24;
+ *bufptr++ = attr->values[i].range.upper >> 16;
+ *bufptr++ = attr->values[i].range.upper >> 8;
+ *bufptr++ = attr->values[i].range.upper;
+ }
+ break;
+
+ case IPP_TAG_TEXTLANG :
+ case IPP_TAG_NAMELANG :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (i)
+ {
+ /*
+ * Arrays and sets are done by sending additional
+ * values with a zero-length name...
+ */
+
+ if ((sizeof(buffer) - (bufptr - buffer)) < 3)
+ {
+ if (write(fd, (char *)buffer, bufptr - buffer) < 0)
+ {
+ DEBUG_puts("ippWrite: Could not write IPP attribute...");
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
+ *bufptr++ = attr->value_tag;
+ *bufptr++ = 0;
+ *bufptr++ = 0;
+ }
+
+ n = strlen(attr->values[i].string.charset) +
+ strlen(attr->values[i].string.text) +
+ 4;
+
+ if (n > sizeof(buffer))
+ return (IPP_ERROR);
+
+ if ((sizeof(buffer) - (bufptr - buffer)) < (n + 2))
+ {
+ if (write(fd, (char *)buffer, bufptr - buffer) < 0)
+ {
+ DEBUG_puts("ipp_write_file: Could not write IPP attribute...");
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
+ /* Length of entire value */
+ *bufptr++ = n >> 8;
+ *bufptr++ = n;
+
+ /* Length of charset */
+ n = strlen(attr->values[i].string.charset);
+ *bufptr++ = n >> 8;
+ *bufptr++ = n;
+
+ /* Charset */
+ memcpy(bufptr, attr->values[i].string.charset, n);
+ bufptr += n;
+
+ /* Length of text */
+ n = strlen(attr->values[i].string.text);
+ *bufptr++ = n >> 8;
+ *bufptr++ = n;
+
+ /* Text */
+ memcpy(bufptr, attr->values[i].string.text, n);
+ bufptr += n;
+ }
+ break;
+
+ default :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (i)
+ {
+ /*
+ * Arrays and sets are done by sending additional
+ * values with a zero-length name...
+ */
+
+ if ((sizeof(buffer) - (bufptr - buffer)) < 3)
+ {
+ if (write(fd, (char *)buffer, bufptr - buffer) < 0)
+ {
+ DEBUG_puts("ippWrite: Could not write IPP attribute...");
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
+ *bufptr++ = attr->value_tag;
+ *bufptr++ = 0;
+ *bufptr++ = 0;
+ }
+
+ n = attr->values[i].unknown.length;
+
+ if (n > sizeof(buffer))
+ return (IPP_ERROR);
+
+ if ((sizeof(buffer) - (bufptr - buffer)) < (n + 2))
+ {
+ if (write(fd, (char *)buffer, bufptr - buffer) < 0)
+ {
+ DEBUG_puts("ipp_write_file: Could not write IPP attribute...");
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
+ /* Length of unknown value */
+ *bufptr++ = n >> 8;
+ *bufptr++ = n;
+
+ /* Value */
+ if (n > 0)
+ {
+ memcpy(bufptr, attr->values[i].unknown.data, n);
+ bufptr += n;
+ }
+ }
+ break;
+ }
+
+ /*
+ * Write the data out...
+ */
+
+ if (write(fd, (char *)buffer, bufptr - buffer) < 0)
+ {
+ DEBUG_puts("ipp_write_file: Could not write IPP attribute...");
+ close(fd);
+ return (IPP_ERROR);
+ }
+
+ DEBUG_printf(("ipp_write_file: wrote %d bytes\n", bufptr - buffer));
+ }
+
+ if (ipp->current == NULL)
+ {
+ /*
+ * Done with all of the attributes; add the end-of-attributes tag...
+ */
+
+ buffer[0] = IPP_TAG_END;
+ if (write(fd, (char *)buffer, 1) < 0)
+ {
+ DEBUG_puts("ipp_write_file: Could not write IPP end-tag...");
+ close(fd);
+ return (IPP_ERROR);
+ }
+
+ ipp->state = IPP_DATA;
+ }
+ break;
+
+ case IPP_DATA :
+ break;
+ }
+
+ /*
+ * Close the file and return...
+ */
+
+ close(fd);
+
+ return (ipp->state);
+}
+
+
+/*
+ * 'set_time()' - Set one of the "time-at-xyz" attributes...
+ */
+
+static void
+set_time(job_t *job, /* I - Job to update */
+ const char *name) /* I - Name of attribute */
+{
+ ipp_attribute_t *attr; /* Time attribute */
+
+
+ if ((attr = ippFindAttribute(job->attrs, name, IPP_TAG_ZERO)) != NULL)
+ {
+ attr->value_tag = IPP_TAG_INTEGER;
+ attr->values[0].integer = time(NULL);
+ }
+}
+
+
+/*
+ * 'start_process()' - Start a background process.
+ */
+
+static int /* O - Process ID or 0 */
+start_process(const char *command, /* I - Full path to command */
+ char *argv[], /* I - Command-line arguments */
+ char *envp[], /* I - Environment */
+ int infd, /* I - Standard input file descriptor */
+ int outfd, /* I - Standard output file descriptor */
+ int errfd, /* I - Standard error file descriptor */
+ int root) /* I - Run as root? */
+{
+ int fd; /* Looping var */
+ int pid; /* Process ID */
+
+
+ LogMessage(L_DEBUG, "start_process(\"%s\", %08x, %08x, %d, %d, %d)",
+ command, argv, envp, infd, outfd, errfd);
+
+ if ((pid = fork()) == 0)
+ {
+ /*
+ * Child process goes here...
+ *
+ * Update stdin/stdout/stderr as needed...
+ */
+
+ close(0);
+ dup(infd);
+ close(1);
+ dup(outfd);
+ if (errfd > 2)
+ {
+ close(2);
+ dup(errfd);
+ }
+
+ /*
+ * Close extra file descriptors...
+ */
+
+ for (fd = 3; fd < MaxFDs; fd ++)
+ close(fd);
+
+ /*
+ * Change user to something "safe"...
+ */
+
+ if (!root && getuid() == 0)
+ {
+ /*
+ * Running as root, so change to non-priviledged user...
+ */
+
+ if (setgid(Group))
+ exit(errno);
+
+ if (setuid(User))
+ exit(errno);
+ }
+
+ /*
+ * Reset group membership to just the main one we belong to.
+ */
+
+ setgroups(0, NULL);
+
+ /*
+ * Change umask to restrict permissions on created files...
+ */
+
+ umask(077);
+
+ /*
+ * Execute the command; if for some reason this doesn't work,
+ * return the error code...
+ */
+
+ execve(command, argv, envp);
+
+ perror(command);
+
+ exit(errno);
+ }
+ else if (pid < 0)
+ {
+ /*
+ * Error - couldn't fork a new process!
+ */
+
+ LogMessage(L_ERROR, "Unable to fork %s - %s.", command, strerror(errno));
+
+ return (0);
+ }
+
+ return (pid);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/job.h b/scheduler/job.h
new file mode 100644
index 000000000..bb0bf01dd
--- /dev/null
+++ b/scheduler/job.h
@@ -0,0 +1,107 @@
+/*
+ * "$Id$"
+ *
+ * Print job definitions for the Common UNIX Printing System (CUPS) scheduler.
+ *
+ * Copyright 1997-2002 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
+ */
+
+/*
+ * Constants...
+ */
+
+#define JOB_BUFFER_SIZE 1024 /* Bytes for job status buffer */
+
+
+/*
+ * Job request structure...
+ */
+
+typedef struct job_str
+{
+ struct job_str *next; /* Next job in queue */
+ int id, /* Job ID */
+ priority; /* Job priority */
+ ipp_attribute_t *state; /* Job state */
+ ipp_attribute_t *sheets; /* job-media-sheets-completed */
+ time_t hold_until; /* Hold expiration date/time */
+ char username[33]; /* Printing user */
+ char dest[IPP_MAX_NAME]; /* Destination printer or class */
+ cups_ptype_t dtype; /* Destination type (class/remote bits) */
+ char title[IPP_MAX_NAME]; /* Job name/title */
+ ipp_attribute_t *job_sheets; /* Job sheets (NULL if none) */
+ int num_files; /* Number of files in job */
+ int current_file; /* Current file in job */
+ mime_type_t **filetypes; /* File types */
+ ipp_t *attrs; /* Job attributes */
+ int pipe; /* Status pipe for this job */
+ int cost; /* Filtering cost */
+ int procs[MAX_FILTERS + 2]; /* Process IDs, 0 terminated */
+ int status; /* Status code from filters */
+ printer_t *printer; /* Printer this job is assigned to */
+ char *buffer; /* Status buffer */
+ int bufused; /* Amount of buffer in use */
+} job_t;
+
+
+/*
+ * Globals...
+ */
+
+VAR int JobHistory VALUE(1); /* Preserve job history? */
+VAR int JobFiles VALUE(0); /* Preserve job files? */
+VAR int MaxJobs VALUE(0), /* Max number of jobs */
+ MaxJobsPerUser VALUE(0), /* Max jobs per user */
+ MaxJobsPerPrinter VALUE(0); /* Max jobs per printer */
+VAR int JobAutoPurge VALUE(0); /* Automatically purge jobs */
+VAR int NumJobs VALUE(0); /* Number of jobs in queue */
+VAR job_t *Jobs VALUE(NULL); /* List of current jobs */
+VAR int NextJobId VALUE(1); /* Next job ID to use */
+
+
+/*
+ * Prototypes...
+ */
+
+extern job_t *AddJob(int priority, const char *dest);
+extern void CancelJob(int id, int purge);
+extern void CancelJobs(const char *dest);
+extern void CheckJobs(void);
+extern void CleanJobs(void);
+extern void DeleteJob(int id);
+extern job_t *FindJob(int id);
+extern int GetPrinterJobCount(const char *dest);
+extern int GetUserJobCount(const char *username);
+extern void HoldJob(int id);
+extern void LoadAllJobs(void);
+extern void MoveJob(int id, const char *dest);
+extern void ReleaseJob(int id);
+extern void RestartJob(int id);
+extern void SaveJob(int id);
+extern void SetJobHoldUntil(int id, const char *when);
+extern void SetJobPriority(int id, int priority);
+extern void StartJob(int id, printer_t *printer);
+extern void StopAllJobs(void);
+extern void StopJob(int id, int force);
+extern void UpdateJob(job_t *job);
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/listen.c b/scheduler/listen.c
new file mode 100644
index 000000000..a9787c244
--- /dev/null
+++ b/scheduler/listen.c
@@ -0,0 +1,222 @@
+/*
+ * "$Id$"
+ *
+ * Server listening routines for the Common UNIX Printing System (CUPS)
+ * scheduler.
+ *
+ * Copyright 1997-2002 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:
+ *
+ * PauseListening() - Clear input polling on all listening sockets...
+ * ResumeListening() - Set input polling on all listening sockets...
+ * StartListening() - Create all listening sockets...
+ * StopListening() - Close all listening sockets...
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cupsd.h"
+
+
+/*
+ * 'PauseListening()' - Clear input polling on all listening sockets...
+ */
+
+void
+PauseListening(void)
+{
+ int i; /* Looping var */
+ listener_t *lis; /* Current listening socket */
+
+
+ if (!FD_ISSET(Listeners[0].fd, &InputSet))
+ return;
+
+ if (NumClients == MaxClients)
+ LogMessage(L_WARN, "Max clients reached, holding new connections...");
+
+ LogMessage(L_DEBUG, "PauseListening: clearing input bits...");
+
+ for (i = NumListeners, lis = Listeners; i > 0; i --, lis ++)
+ {
+ LogMessage(L_DEBUG2, "PauseListening: Removing fd %d from InputSet...",
+ lis->fd);
+
+ FD_CLR(lis->fd, &InputSet);
+ }
+}
+
+
+/*
+ * 'ResumeListening()' - Set input polling on all listening sockets...
+ */
+
+void
+ResumeListening(void)
+{
+ int i; /* Looping var */
+ listener_t *lis; /* Current listening socket */
+
+
+ if (FD_ISSET(Listeners[0].fd, &InputSet))
+ return;
+
+ if (NumClients >= (MaxClients - 1))
+ LogMessage(L_WARN, "Resuming new connection processing...");
+
+ LogMessage(L_DEBUG, "ResumeListening: setting input bits...");
+
+ for (i = NumListeners, lis = Listeners; i > 0; i --, lis ++)
+ {
+ LogMessage(L_DEBUG2, "ResumeListening: Adding fd %d to InputSet...",
+ lis->fd);
+
+ FD_SET(lis->fd, &InputSet);
+ }
+}
+
+
+/*
+ * 'StartListening()' - Create all listening sockets...
+ */
+
+void
+StartListening(void)
+{
+ int i, /* Looping var */
+ val; /* Parameter value */
+ listener_t *lis; /* Current listening socket */
+ struct hostent *host; /* Host entry for server address */
+
+
+ LogMessage(L_DEBUG, "StartListening: NumListeners=%d", NumListeners);
+
+ /*
+ * Get the server's IP address...
+ */
+
+ memset(&ServerAddr, 0, sizeof(ServerAddr));
+
+ if ((host = httpGetHostByName(ServerName)) != NULL)
+ {
+ /*
+ * Found the server's address!
+ */
+
+ memcpy((char *)&(ServerAddr.sin_addr), host->h_addr, host->h_length);
+ ServerAddr.sin_family = host->h_addrtype;
+ }
+ else
+ {
+ /*
+ * Didn't find it! Use an address of 0...
+ */
+
+ LogMessage(L_ERROR, "StartListening: Unable to find IP address for server name \"%s\"!\n",
+ ServerName);
+
+ ServerAddr.sin_family = AF_INET;
+ }
+
+ /*
+ * Setup socket listeners...
+ */
+
+ for (i = NumListeners, lis = Listeners; i > 0; i --, lis ++)
+ {
+ LogMessage(L_DEBUG, "StartListening: address=%08x port=%d",
+ ntohl(lis->address.sin_addr.s_addr),
+ ntohs(lis->address.sin_port));
+
+ if ((lis->fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
+ {
+ LogMessage(L_ERROR, "StartListening: Unable to open listen socket - %s.",
+ strerror(errno));
+ exit(errno);
+ }
+
+ fcntl(lis->fd, F_SETFD, fcntl(lis->fd, F_GETFD) | FD_CLOEXEC);
+
+ /*
+ * Set things up to reuse the local address for this port.
+ */
+
+ val = 1;
+#ifdef __sun
+ setsockopt(lis->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
+#else
+ setsockopt(lis->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
+#endif /* __sun */
+
+ /*
+ * Bind to the port we found...
+ */
+
+ if (bind(lis->fd, (struct sockaddr *)&(lis->address), sizeof(lis->address)) < 0)
+ {
+ LogMessage(L_ERROR, "StartListening: Unable to bind socket - %s.", strerror(errno));
+ exit(errno);
+ }
+
+ /*
+ * Listen for new clients.
+ */
+
+ if (listen(lis->fd, ListenBackLog) < 0)
+ {
+ LogMessage(L_ERROR, "StartListening: Unable to listen for clients - %s.",
+ strerror(errno));
+ exit(errno);
+ }
+ }
+
+ ResumeListening();
+}
+
+
+/*
+ * 'StopListening()' - Close all listening sockets...
+ */
+
+void
+StopListening(void)
+{
+ int i; /* Looping var */
+ listener_t *lis; /* Current listening socket */
+
+
+ LogMessage(L_DEBUG, "StopListening: closing all listen sockets.");
+
+ PauseListening();
+
+ for (i = NumListeners, lis = Listeners; i > 0; i --, lis ++)
+#ifdef WIN32
+ closesocket(lis->fd);
+#else
+ close(lis->fd);
+#endif /* WIN32 */
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/log.c b/scheduler/log.c
new file mode 100644
index 000000000..c76dd9fb4
--- /dev/null
+++ b/scheduler/log.c
@@ -0,0 +1,440 @@
+/*
+ * "$Id$"
+ *
+ * Log file routines for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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:
+ *
+ * GetDateTime() - Returns a pointer to a date/time string.
+ * LogMessage() - Log a message to the error log file.
+ * LogPage() - Log a page to the page log file.
+ * LogRequest() - Log an HTTP request in Common Log Format.
+ * check_log_file() - Open/rotate a log file if it needs it.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cupsd.h"
+#include <stdarg.h>
+
+#ifdef HAVE_VSYSLOG
+# include <syslog.h>
+#endif /* HAVE_VSYSLOG */
+
+
+/*
+ * Local functions...
+ */
+
+static int check_log_file(FILE **, const char *);
+
+
+/*
+ * 'GetDateTime()' - Returns a pointer to a date/time string.
+ */
+
+char * /* O - Date/time string */
+GetDateTime(time_t t) /* I - Time value */
+{
+ struct tm *date; /* Date/time value */
+ static char s[1024]; /* Date/time string */
+ static const char *months[12] =/* Months */
+ {
+ "Jan",
+ "Feb",
+ "Mar",
+ "Apr",
+ "May",
+ "Jun",
+ "Jul",
+ "Aug",
+ "Sep",
+ "Oct",
+ "Nov",
+ "Dec"
+ };
+
+
+ /*
+ * Get the date and time from the UNIX time value, and then format it
+ * into a string. Note that we *can't* use the strftime() function since
+ * it is localized and will seriously confuse automatic programs if the
+ * month names are in the wrong language!
+ *
+ * Also, we use the "timezone" variable that contains the current timezone
+ * offset from GMT in seconds so that we are reporting local time in the
+ * log files. If you want GMT, set the TZ environment variable accordingly
+ * before starting the scheduler.
+ *
+ * (*BSD and Darwin store the timezone offset in the tm structure)
+ */
+
+ date = localtime(&t);
+
+ snprintf(s, sizeof(s), "[%02d/%s/%04d:%02d:%02d:%02d %+03ld%02ld]",
+ date->tm_mday, months[date->tm_mon], 1900 + date->tm_year,
+ date->tm_hour, date->tm_min, date->tm_sec,
+#ifdef HAVE_TM_GMTOFF
+ date->tm_gmtoff / 3600, (date->tm_gmtoff / 60) % 60);
+#else
+ timezone / 3600, (timezone / 60) % 60);
+#endif /* HAVE_TM_GMTOFF */
+
+ return (s);
+}
+
+
+/*
+ * 'LogMessage()' - Log a message to the error log file.
+ */
+
+int /* O - 1 on success, 0 on error */
+LogMessage(int level, /* I - Log level */
+ const char *message, /* I - printf-style message string */
+ ...) /* I - Additional args as needed */
+{
+ int len; /* Length of message */
+ char line[1024]; /* Line for output file */
+ va_list ap; /* Argument pointer */
+ static char levels[] = /* Log levels... */
+ {
+ ' ',
+ 'X',
+ 'A',
+ 'C',
+ 'E',
+ 'W',
+ 'N',
+ 'I',
+ 'D',
+ 'd'
+ };
+#ifdef HAVE_VSYSLOG
+ static int syslevels[] = /* SYSLOG levels... */
+ {
+ 0,
+ LOG_EMERG,
+ LOG_ALERT,
+ LOG_CRIT,
+ LOG_ERR,
+ LOG_WARNING,
+ LOG_NOTICE,
+ LOG_INFO,
+ LOG_DEBUG,
+ LOG_DEBUG
+ };
+#endif /* HAVE_VSYSLOG */
+
+
+ /*
+ * See if we want to log this message...
+ */
+
+ if (level > LogLevel)
+ return (1);
+
+#ifdef HAVE_VSYSLOG
+ /*
+ * See if we are logging errors via syslog...
+ */
+
+ if (strcmp(ErrorLog, "syslog") == 0)
+ {
+ va_start(ap, message);
+ vsyslog(syslevels[level], message, ap);
+ va_end(ap);
+
+ return (1);
+ }
+#endif /* HAVE_VSYSLOG */
+
+ /*
+ * Not using syslog; check the log file...
+ */
+
+ if (!check_log_file(&ErrorFile, ErrorLog))
+ return (0);
+
+ /*
+ * Print the log level and date/time...
+ */
+
+ fprintf(ErrorFile, "%c %s ", levels[level], GetDateTime(time(NULL)));
+
+ /*
+ * Then the log message...
+ */
+
+ va_start(ap, message);
+ len = vsnprintf(line, sizeof(line), message, ap);
+ va_end(ap);
+
+ /*
+ * Then a newline...
+ */
+
+ fputs(line, ErrorFile);
+ if (len > 0 && line[len - 1] != '\n')
+ putc('\n', ErrorFile);
+
+ fflush(ErrorFile);
+
+ return (1);
+}
+
+
+/*
+ * 'LogPage()' - Log a page to the page log file.
+ */
+
+int /* O - 1 on success, 0 on error */
+LogPage(job_t *job, /* I - Job being printed */
+ const char *page) /* I - Page being printed */
+{
+ ipp_attribute_t *billing; /* job-billing attribute */
+
+
+
+ billing = ippFindAttribute(job->attrs, "job-billing", IPP_TAG_ZERO);
+
+#ifdef HAVE_VSYSLOG
+ /*
+ * See if we are logging pages via syslog...
+ */
+
+ if (strcmp(PageLog, "syslog") == 0)
+ {
+ syslog(LOG_INFO, "PAGE %s %s %d %s %s", job->printer->name, job->username,
+ job->id, page, billing ? billing->values[0].string.text : "");
+
+ return (1);
+ }
+#endif /* HAVE_VSYSLOG */
+
+ /*
+ * Not using syslog; check the log file...
+ */
+
+ if (!check_log_file(&PageFile, PageLog))
+ return (0);
+
+ /*
+ * Print a page log entry of the form:
+ *
+ * printer job-id user [DD/MON/YYYY:HH:MM:SS +TTTT] page num-copies billing
+ */
+
+ fprintf(PageFile, "%s %s %d %s %s %s\n", job->printer->name, job->username,
+ job->id, GetDateTime(time(NULL)), page,
+ billing ? billing->values[0].string.text : "");
+ fflush(PageFile);
+
+ return (1);
+}
+
+
+/*
+ * 'LogRequest()' - Log an HTTP request in Common Log Format.
+ */
+
+int /* O - 1 on success, 0 on error */
+LogRequest(client_t *con, /* I - Request to log */
+ http_status_t code) /* I - Response code */
+{
+ static const char *states[] = /* HTTP client states... */
+ {
+ "WAITING",
+ "OPTIONS",
+ "GET",
+ "GET",
+ "HEAD",
+ "POST",
+ "POST",
+ "POST",
+ "PUT",
+ "PUT",
+ "DELETE",
+ "TRACE",
+ "CLOSE",
+ "STATUS"
+ };
+
+
+#ifdef HAVE_VSYSLOG
+ /*
+ * See if we are logging accesses via syslog...
+ */
+
+ if (strcmp(AccessLog, "syslog") == 0)
+ {
+ syslog(LOG_INFO, "REQUEST %s - %s \"%s %s HTTP/%d.%d\" %d %d\n",
+ con->http.hostname, con->username[0] != '\0' ? con->username : "-",
+ states[con->operation], con->uri,
+ con->http.version / 100, con->http.version % 100,
+ code, con->bytes);
+
+ return (1);
+ }
+#endif /* HAVE_VSYSLOG */
+
+ /*
+ * Not using syslog; check the log file...
+ */
+
+ if (!check_log_file(&AccessFile, AccessLog))
+ return (0);
+
+ /*
+ * Write a log of the request in "common log format"...
+ */
+
+ fprintf(AccessFile, "%s - %s %s \"%s %s HTTP/%d.%d\" %d %d\n",
+ con->http.hostname, con->username[0] != '\0' ? con->username : "-",
+ GetDateTime(con->start), states[con->operation], con->uri,
+ con->http.version / 100, con->http.version % 100,
+ code, con->bytes);
+ fflush(AccessFile);
+
+ return (1);
+}
+
+
+/*
+ * 'check_log_file()' - Open/rotate a log file if it needs it.
+ */
+
+static int /* O - 1 if log file open */
+check_log_file(FILE **log, /* IO - Log file */
+ const char *logname) /* I - Log filename */
+{
+ char backname[1024], /* Backup log filename */
+ filename[1024], /* Formatted log filename */
+ *ptr; /* Pointer into filename */
+
+
+ /*
+ * See if we have a log file to check...
+ */
+
+ if (log == NULL || logname == NULL || !logname[0])
+ return (1);
+
+ /*
+ * Format the filename as needed...
+ */
+
+ if (*log == NULL ||
+ (ftell(*log) > MaxLogSize && MaxLogSize > 0))
+ {
+ /*
+ * Handle format strings...
+ */
+
+ filename[sizeof(filename) - 1] = '\0';
+
+ if (logname[0] != '/')
+ {
+ strncpy(filename, ServerRoot, sizeof(filename) - 1);
+ strncat(filename, "/", sizeof(filename) - 1);
+ }
+ else
+ filename[0] = '\0';
+
+ for (ptr = filename + strlen(filename);
+ *logname && ptr < (filename + sizeof(filename) - 1);
+ logname ++)
+ if (*logname == '%')
+ {
+ /*
+ * Format spec...
+ */
+
+ logname ++;
+ if (*logname == 's')
+ {
+ /*
+ * Insert the server name...
+ */
+
+ strncpy(ptr, ServerName, sizeof(filename) - (ptr - filename) - 1);
+ ptr += strlen(ptr);
+ }
+ else
+ {
+ /*
+ * Otherwise just insert the character...
+ */
+
+ *ptr++ = *logname;
+ }
+ }
+ else
+ *ptr++ = *logname;
+
+ *ptr = '\0';
+ }
+
+ /*
+ * See if the log file is open...
+ */
+
+ if (*log == NULL)
+ {
+ /*
+ * Nope, open the log file...
+ */
+
+ if ((*log = fopen(filename, "a")) == NULL)
+ return (0);
+ }
+
+ /*
+ * Do we need to rotate the log?
+ */
+
+ if (ftell(*log) > MaxLogSize && MaxLogSize > 0)
+ {
+ /*
+ * Rotate log file...
+ */
+
+ fclose(*log);
+
+ strcpy(backname, filename);
+ strncat(backname, ".O", sizeof(backname) - 1);
+ backname[sizeof(backname) - 1] = '\0';
+
+ unlink(backname);
+ rename(filename, backname);
+
+ if ((*log = fopen(filename, "a")) == NULL)
+ return (0);
+ }
+
+ return (1);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/main.c b/scheduler/main.c
new file mode 100644
index 000000000..01befbd06
--- /dev/null
+++ b/scheduler/main.c
@@ -0,0 +1,802 @@
+/*
+ * "$Id$"
+ *
+ * Scheduler main loop for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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() - Main entry for the CUPS scheduler.
+ * CatchChildSignals() - Catch SIGCHLD signals...
+ * IgnoreChildSignals() - Ignore SIGCHLD signals...
+ * sigchld_handler() - Handle 'child' signals from old processes.
+ * sighup_handler() - Handle 'hangup' signals to reconfigure the scheduler.
+ * sigterm_handler() - Handle 'terminate' signals that stop the scheduler.
+ * usage() - Show scheduler usage.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#define _MAIN_C_
+#include "cupsd.h"
+#include <sys/resource.h>
+#include <syslog.h>
+
+#if defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO)
+# include <malloc.h>
+#endif /* HAVE_MALLOC_H && HAVE_MALLINFO */
+
+#ifndef FD_SETSIZE
+# define FD_SETSIZE 1024
+#endif /* !FD_SETSIZE */
+
+
+/*
+ * Local functions...
+ */
+
+static void sigchld_handler(int sig);
+static void sighup_handler(int sig);
+static void sigterm_handler(int sig);
+static void usage(void);
+
+
+/*
+ * 'main()' - Main entry for the CUPS scheduler.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i; /* Looping var */
+ char *opt; /* Option character */
+ int fg; /* Run in the foreground */
+ fd_set input, /* Input set for select() */
+ output; /* Output set for select() */
+ client_t *con; /* Current client */
+ job_t *job, /* Current job */
+ *next; /* Next job */
+ listener_t *lis; /* Current listener */
+ time_t activity; /* Activity timer */
+ time_t senddoc_time; /* Send-Document time */
+#ifdef HAVE_MALLINFO
+ time_t mallinfo_time; /* Malloc information time */
+#endif /* HAVE_MALLINFO */
+ struct timeval timeout; /* select() timeout */
+ struct rlimit limit; /* Runtime limit */
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ struct sigaction action; /* Actions for POSIX signals */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+#ifdef __sgi
+ FILE *fp; /* Fake lpsched lock file */
+#endif /* __sgi */
+
+
+ /*
+ * Check for command-line arguments...
+ */
+
+ fg = 0;
+
+ for (i = 1; i < argc; i ++)
+ if (argv[i][0] == '-')
+ for (opt = argv[i] + 1; *opt != '\0'; opt ++)
+ switch (*opt)
+ {
+ case 'c' : /* Configuration file */
+ i ++;
+ if (i >= argc)
+ usage();
+
+ if (argv[i][0] == '/')
+ {
+ /*
+ * Absolute directory...
+ */
+
+ strncpy(ConfigurationFile, argv[i], sizeof(ConfigurationFile) - 1);
+ ConfigurationFile[sizeof(ConfigurationFile) - 1] = '\0';
+ }
+ else
+ {
+ /*
+ * Relative directory...
+ */
+
+ getcwd(ConfigurationFile, sizeof(ConfigurationFile));
+ strncat(ConfigurationFile, "/", sizeof(ConfigurationFile) - 1);
+ strncat(ConfigurationFile, argv[i], sizeof(ConfigurationFile) - 1);
+ ConfigurationFile[sizeof(ConfigurationFile) - 1] = '\0';
+ }
+ break;
+
+ case 'f' : /* Run in foreground... */
+ fg = 1;
+ break;
+
+ default : /* Unknown option */
+ fprintf(stderr, "cupsd: Unknown option \'%c\' - aborting!\n", *opt);
+ usage();
+ break;
+ }
+ else
+ {
+ fprintf(stderr, "cupsd: Unknown argument \'%s\' - aborting!\n", argv[i]);
+ usage();
+ }
+
+ /*
+ * If the user hasn't specified "-f", run in the background...
+ */
+
+ if (!fg)
+ {
+ if (fork() > 0)
+ return (0);
+
+ /*
+ * Make sure we aren't tying up any filesystems...
+ */
+
+ chdir("/");
+
+#ifndef DEBUG
+ /*
+ * Disable core dumps...
+ */
+
+ getrlimit(RLIMIT_CORE, &limit);
+ limit.rlim_cur = 0;
+ setrlimit(RLIMIT_CORE, &limit);
+
+ /*
+ * Disconnect from the controlling terminal...
+ */
+
+ close(0);
+ close(1);
+ close(2);
+
+ setsid();
+#endif /* DEBUG */
+ }
+
+ /*
+ * Set the timezone info...
+ */
+
+ if (getenv("TZ") != NULL)
+ snprintf(TZ, sizeof(TZ), "TZ=%s", getenv("TZ"));
+
+ tzset();
+
+ /*
+ * Set the maximum number of files...
+ */
+
+ getrlimit(RLIMIT_NOFILE, &limit);
+ if (limit.rlim_max > FD_SETSIZE) /* Can't exceed size of FD set! */
+ MaxFDs = FD_SETSIZE;
+ else
+ MaxFDs = limit.rlim_max;
+
+ limit.rlim_cur = MaxFDs;
+ setrlimit(RLIMIT_NOFILE, &limit);
+
+ /*
+ * Catch hangup and child signals and ignore broken pipes...
+ */
+
+#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
+ if (RunAsUser)
+ sigset(SIGHUP, sigterm_handler);
+ else
+ sigset(SIGHUP, sighup_handler);
+ sigset(SIGPIPE, SIG_IGN);
+ sigset(SIGTERM, sigterm_handler);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+
+ sigemptyset(&action.sa_mask);
+ sigaddset(&action.sa_mask, SIGHUP);
+
+ if (RunAsUser)
+ action.sa_handler = sigterm_handler;
+ else
+ action.sa_handler = sighup_handler;
+
+ sigaction(SIGHUP, &action, NULL);
+
+ sigemptyset(&action.sa_mask);
+ action.sa_handler = SIG_IGN;
+ sigaction(SIGPIPE, &action, NULL);
+
+ sigemptyset(&action.sa_mask);
+ sigaddset(&action.sa_mask, SIGTERM);
+ action.sa_handler = sigterm_handler;
+ sigaction(SIGTERM, &action, NULL);
+#else
+ if (RunAsUser)
+ signal(SIGHUP, sigterm_handler);
+ else
+ signal(SIGHUP, sighup_handler);
+
+ signal(SIGPIPE, SIG_IGN);
+ signal(SIGTERM, sigterm_handler);
+#endif /* HAVE_SIGSET */
+
+ /*
+ * Read configuration...
+ */
+
+ if (!ReadConfiguration())
+ {
+ syslog(LOG_LPR, "Unable to read configuration file \'%s\' - exiting!",
+ ConfigurationFile);
+ return (1);
+ }
+
+#ifdef __sgi
+ /*
+ * Try to create a fake lpsched lock file if one is not already there.
+ * Some Adobe applications need it under IRIX in order to enable
+ * printing...
+ */
+
+ if ((fp = fopen("/var/spool/lp/SCHEDLOCK", "a")) == NULL)
+ {
+ syslog(LOG_LPR, "Unable to create fake lpsched lock file "
+ "\"/var/spool/lp/SCHEDLOCK\"\' - %s!",
+ strerror(errno));
+ }
+ else
+ {
+ fclose(fp);
+
+ chmod("/var/spool/lp/SCHEDLOCK", 0644);
+ chown("/var/spool/lp/SCHEDLOCK", User, Group);
+ }
+#endif /* __sgi */
+
+ /*
+ * Initialize authentication certificates...
+ */
+
+ InitCerts();
+
+ /*
+ * Load all the jobs...
+ */
+
+ LoadAllJobs();
+
+ /*
+ * Loop forever...
+ */
+
+ senddoc_time = time(NULL);
+
+#ifdef HAVE_MALLINFO
+ mallinfo_time = 0;
+#endif /* HAVE_MALLINFO */
+
+ for (;;)
+ {
+ /*
+ * Check if we need to load the server configuration file...
+ */
+
+ if (NeedReload)
+ {
+ if (NumClients > 0)
+ {
+ for (i = NumClients, con = Clients; i > 0; i --, con ++)
+ if (con->http.state == HTTP_WAITING)
+ {
+ CloseClient(con);
+ con --;
+ }
+ else
+ con->http.keep_alive = HTTP_KEEPALIVE_OFF;
+
+ PauseListening();
+ }
+ else if (!ReadConfiguration())
+ {
+ syslog(LOG_LPR, "Unable to read configuration file \'%s\' - exiting!",
+ ConfigurationFile);
+ break;
+ }
+ }
+
+ /*
+ * Check for available input or ready output. If select() returns
+ * 0 or -1, something bad happened and we should exit immediately.
+ *
+ * Note that we at least have one listening socket open at all
+ * times.
+ */
+
+ input = InputSet;
+ output = OutputSet;
+
+ timeout.tv_sec = 1;
+ timeout.tv_usec = 0;
+
+ for (i = NumClients, con = Clients; i > 0; i --, con ++)
+ if (con->http.used > 0)
+ {
+ timeout.tv_sec = 0;
+ break;
+ }
+
+ if ((i = select(MaxFDs, &input, &output, NULL, &timeout)) < 0)
+ {
+ char s[16384], /* String buffer */
+ *sptr; /* Pointer into buffer */
+ int slen; /* Length of string buffer */
+
+
+ /*
+ * Got an error from select!
+ */
+
+ if (errno == EINTR) /* Just interrupted by a signal */
+ continue;
+
+ /*
+ * Log all sorts of debug info to help track down the problem.
+ */
+
+ LogMessage(L_EMERG, "select() failed - %s!", strerror(errno));
+
+ strcpy(s, "InputSet =");
+ slen = 9;
+ sptr = s + 9;
+
+ for (i = 0; i < MaxFDs; i ++)
+ if (FD_ISSET(i, &InputSet))
+ snprintf(sptr, sizeof(s) - slen, " %d", i);
+
+ LogMessage(L_EMERG, s);
+
+ strcpy(s, "OutputSet =");
+ slen = 10;
+ sptr = s + 10;
+
+ for (i = 0; i < MaxFDs; i ++)
+ if (FD_ISSET(i, &OutputSet))
+ snprintf(sptr, sizeof(s) - slen, " %d", i);
+
+ LogMessage(L_EMERG, s);
+
+ for (i = 0, con = Clients; i < NumClients; i ++, con ++)
+ LogMessage(L_EMERG, "Clients[%d] = %d, file = %d, state = %d",
+ i, con->http.fd, con->file, con->http.state);
+
+ for (i = 0, lis = Listeners; i < NumListeners; i ++, lis ++)
+ LogMessage(L_EMERG, "Listeners[%d] = %d", i, lis->fd);
+
+ LogMessage(L_EMERG, "BrowseSocket = %d", BrowseSocket);
+
+ for (job = Jobs; job != NULL; job = job->next)
+ LogMessage(L_EMERG, "Jobs[%d] = %d", job->id, job->pipe);
+
+ break;
+ }
+
+ for (i = NumListeners, lis = Listeners; i > 0; i --, lis ++)
+ if (FD_ISSET(lis->fd, &input))
+ AcceptClient(lis);
+
+ for (i = NumClients, con = Clients; i > 0; i --, con ++)
+ {
+ /*
+ * Process the input buffer...
+ */
+
+ if (FD_ISSET(con->http.fd, &input) || con->http.used)
+ if (!ReadClient(con))
+ {
+ con --;
+ continue;
+ }
+
+ /*
+ * Write data as needed...
+ */
+
+ if (FD_ISSET(con->http.fd, &output) &&
+ (!con->pipe_pid || FD_ISSET(con->file, &input)))
+ if (!WriteClient(con))
+ {
+ con --;
+ continue;
+ }
+
+ /*
+ * Check the activity and close old clients...
+ */
+
+ activity = time(NULL) - Timeout;
+ if (con->http.activity < activity && !con->pipe_pid)
+ {
+ CloseClient(con);
+ con --;
+ continue;
+ }
+ }
+
+ /*
+ * Check for status info from job filters...
+ */
+
+ for (job = Jobs; job != NULL; job = next)
+ {
+ next = job->next;
+
+ if (job->pipe && FD_ISSET(job->pipe, &input))
+ {
+ /*
+ * Clear the input bit to avoid updating the next job
+ * using the same status pipe file descriptor...
+ */
+
+ FD_CLR(job->pipe, &input);
+
+ /*
+ * Read any status messages from the filters...
+ */
+
+ UpdateJob(job);
+ }
+ }
+
+ /*
+ * Update the browse list as needed...
+ */
+
+ if (Browsing)
+ {
+ if (FD_ISSET(BrowseSocket, &input))
+ UpdateCUPSBrowse();
+
+ if (PollPipe >= 0 && FD_ISSET(PollPipe, &input))
+ UpdatePolling();
+
+#ifdef HAVE_LIBSLP
+ if ((BrowseProtocols & BROWSE_SLP) && BrowseSLPRefresh <= time(NULL))
+ UpdateSLPBrowse();
+#endif /* HAVE_LIBSLP */
+
+ SendBrowseList();
+ }
+
+ /*
+ * Update any pending multi-file documents...
+ */
+
+ if ((time(NULL) - senddoc_time) >= 10)
+ {
+ CheckJobs();
+ senddoc_time = time(NULL);
+ }
+
+#ifdef HAVE_MALLINFO
+ /*
+ * Log memory usage every minute...
+ */
+
+ if ((time(NULL) - mallinfo_time) >= 60 && LogLevel >= L_DEBUG)
+ {
+ struct mallinfo mem; /* Malloc information */
+
+
+ mem = mallinfo();
+ LogMessage(L_DEBUG, "mallinfo: arena = %d, used = %d, free = %d\n",
+ mem.arena, mem.usmblks + mem.uordblks,
+ mem.fsmblks + mem.fordblks);
+ mallinfo_time = time(NULL);
+ }
+#endif /* HAVE_MALLINFO */
+
+ /*
+ * Update the root certificate once every 5 minutes...
+ */
+
+ if ((time(NULL) - RootCertTime) >= 300)
+ {
+ /*
+ * Update the root certificate...
+ */
+
+ DeleteCert(0);
+ AddCert(0, "root");
+ }
+ }
+
+ /*
+ * If we get here something very bad happened and we need to exit
+ * immediately.
+ */
+
+ DeleteAllCerts();
+ CloseAllClients();
+ StopListening();
+
+ return (1);
+}
+
+
+/*
+ * 'CatchChildSignals()' - Catch SIGCHLD signals...
+ */
+
+void
+CatchChildSignals(void)
+{
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ struct sigaction action; /* Actions for POSIX signals */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+
+
+#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
+ sigset(SIGCHLD, sigchld_handler);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+
+ sigemptyset(&action.sa_mask);
+ sigaddset(&action.sa_mask, SIGCHLD);
+ action.sa_handler = sigchld_handler;
+ sigaction(SIGCHLD, &action, NULL);
+#else
+ signal(SIGCLD, sigchld_handler); /* No, SIGCLD isn't a typo... */
+#endif /* HAVE_SIGSET */
+}
+
+
+/*
+ * 'IgnoreChildSignals()' - Ignore SIGCHLD signals...
+ */
+
+void
+IgnoreChildSignals(void)
+{
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ struct sigaction action; /* Actions for POSIX signals */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+
+#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
+ sigset(SIGCHLD, SIG_IGN);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+
+ sigemptyset(&action.sa_mask);
+ sigaddset(&action.sa_mask, SIGCHLD);
+ action.sa_handler = SIG_IGN;
+ sigaction(SIGCHLD, &action, NULL);
+#else
+ signal(SIGCLD, SIG_IGN); /* No, SIGCLD isn't a typo... */
+#endif /* HAVE_SIGSET */
+}
+
+
+/*
+ * 'sigchld_handler()' - Handle 'child' signals from old processes.
+ */
+
+static void
+sigchld_handler(int sig) /* I - Signal number */
+{
+ int status; /* Exit status of child */
+ int pid; /* Process ID of child */
+ job_t *job; /* Current job */
+ int i; /* Looping var */
+
+
+ (void)sig;
+
+#ifdef HAVE_WAITPID
+ while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
+#elif defined(HAVE_WAIT3)
+ while ((pid = wait3(&status, WNOHANG, NULL)) > 0)
+#else
+ if ((pid = wait(&status)) > 0)
+#endif /* HAVE_WAITPID */
+ {
+ DEBUG_printf(("sigcld_handler: pid = %d, status = %d\n", pid, status));
+
+ /*
+ * Delete certificates for CGI processes...
+ */
+
+ if (pid)
+ DeleteCert(pid);
+
+ /*
+ * Ignore SIGTERM errors - that comes when a job is cancelled...
+ */
+
+ if (status == SIGTERM)
+ status = 0;
+
+ if (status)
+ {
+ if (status < 256)
+ LogMessage(L_ERROR, "PID %d crashed on signal %d!", pid, status);
+ else
+ LogMessage(L_ERROR, "PID %d stopped with status %d!", pid,
+ status / 256);
+ }
+
+ for (job = Jobs; job != NULL; job = job->next)
+ if (job->state->values[0].integer == IPP_JOB_PROCESSING)
+ {
+ for (i = 0; job->procs[i]; i ++)
+ if (job->procs[i] == pid)
+ break;
+
+ if (job->procs[i])
+ {
+ /*
+ * OK, this process has gone away; what's left?
+ */
+
+ job->procs[i] = -pid;
+
+ if (status && job->status >= 0)
+ {
+ /*
+ * An error occurred; save the exit status so we know to stop
+ * the printer or cancel the job when all of the filters finish...
+ *
+ * A negative status indicates that the backend failed and the
+ * printer needs to be stopped.
+ */
+
+ if (!job->procs[i + 1])
+ job->status = -status; /* Backend failed */
+ else
+ job->status = status; /* Filter failed */
+ }
+ break;
+ }
+ }
+ }
+
+#ifdef HAVE_SIGSET
+ sigset(SIGCHLD, sigchld_handler);
+#elif !defined(HAVE_SIGACTION)
+ signal(SIGCLD, sigchld_handler);
+#endif /* HAVE_SIGSET */
+}
+
+
+/*
+ * 'sighup_handler()' - Handle 'hangup' signals to reconfigure the scheduler.
+ */
+
+static void
+sighup_handler(int sig) /* I - Signal number */
+{
+ (void)sig;
+
+ NeedReload = TRUE;
+
+#ifdef HAVE_SIGSET
+ sigset(SIGHUP, sighup_handler);
+#elif !defined(HAVE_SIGACTION)
+ signal(SIGHUP, sighup_handler);
+#endif /* HAVE_SIGSET */
+}
+
+
+/*
+ * 'sigterm_handler()' - Handle 'terminate' signals that stop the scheduler.
+ */
+
+static void
+sigterm_handler(int sig)
+{
+#ifdef __sgi
+ struct stat statbuf; /* Needed for checking lpsched FIFO */
+#endif /* __sgi */
+
+
+ (void)sig; /* remove compiler warnings... */
+
+ /*
+ * Log an error...
+ */
+
+ LogMessage(L_ERROR, "Scheduler shutting down due to SIGTERM.");
+
+ /*
+ * Close all network clients and stop all jobs...
+ */
+
+ CloseAllClients();
+ StopListening();
+ StopPolling();
+ StopBrowsing();
+
+ if (Clients != NULL)
+ free(Clients);
+
+ StopAllJobs();
+
+ if (AccessFile != NULL)
+ fclose(AccessFile);
+
+ if (ErrorFile != NULL)
+ fclose(ErrorFile);
+
+ if (PageFile != NULL)
+ fclose(PageFile);
+
+ DeleteAllLocations();
+
+ DeleteAllClasses();
+
+ if (Devices)
+ ippDelete(Devices);
+
+ if (PPDs)
+ ippDelete(PPDs);
+
+ DeleteAllPrinters();
+
+ if (MimeDatabase != NULL)
+ mimeDelete(MimeDatabase);
+
+#ifdef __sgi
+ /*
+ * Remove the fake IRIX lpsched lock file, but only if the existing
+ * file is not a FIFO which indicates that the real IRIX lpsched is
+ * running...
+ */
+
+ if (!stat("/var/spool/lp/FIFO", &statbuf))
+ if (!S_ISFIFO(statbuf.st_mode))
+ unlink("/var/spool/lp/SCHEDLOCK");
+#endif /* __sgi */
+
+ exit(1);
+}
+
+
+/*
+ * 'usage()' - Show scheduler usage.
+ */
+
+static void
+usage(void)
+{
+ fputs("Usage: cupsd [-c config-file] [-f]\n", stderr);
+ exit(1);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/mime.c b/scheduler/mime.c
new file mode 100644
index 000000000..96ed3ee5e
--- /dev/null
+++ b/scheduler/mime.c
@@ -0,0 +1,579 @@
+/*
+ * "$Id$"
+ *
+ * MIME database file routines for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Easy Software Products and are protected by Federal
+ * copyright law. Distribution and use rights are outlined in the file
+ * "LICENSE.txt" which should have been included with this file. If this
+ * file is missing or damaged please contact Easy Software Products
+ * at:
+ *
+ * Attn: CUPS Licensing Information
+ * Easy Software Products
+ * 44141 Airport View Drive, Suite 204
+ * Hollywood, Maryland 20636-3111 USA
+ *
+ * Voice: (301) 373-9603
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * Contents:
+ *
+ * mimeDelete() - Delete (free) a MIME database.
+ * mimeMerge() - Merge a MIME database from disk with the current one.
+ * mimeNew() - Create a new, empty MIME database.
+ * load_types() - Load a xyz.types file...
+ * delete_rules() - Free all memory for the given rule tree.
+ * load_convs() - Load a xyz.convs file...
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include <cups/string.h>
+#include "mime.h"
+
+#ifdef WIN32
+# include <windows.h>
+#elif HAVE_DIRENT_H
+# include <dirent.h>
+typedef struct dirent DIRENT;
+# define NAMLEN(dirent) strlen((dirent)->d_name)
+#else
+# if HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# if HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# if HAVE_NDIR_H
+# include <ndir.h>
+# endif
+typedef struct direct DIRENT;
+# define NAMLEN(dirent) (dirent)->d_namlen
+#endif
+
+
+/*
+ * Local functions...
+ */
+
+static void load_types(mime_t *mime, char *filename);
+static void load_convs(mime_t *mime, char *filename);
+static void delete_rules(mime_magic_t *rules);
+
+
+/*
+ * 'mimeDelete()' - Delete (free) a MIME database.
+ */
+
+void
+mimeDelete(mime_t *mime) /* I - MIME database */
+{
+ int i; /* Looping var */
+
+
+ if (mime == NULL)
+ return;
+
+ /*
+ * Loop through the file types and delete any rules...
+ */
+
+ for (i = 0; i < mime->num_types; i ++)
+ {
+ delete_rules(mime->types[i]->rules);
+ free(mime->types[i]);
+ }
+
+ /*
+ * Free the types and filters arrays, and then the MIME database structure.
+ */
+
+ free(mime->types);
+ free(mime->filters);
+ free(mime);
+}
+
+
+/*
+ * 'mimeMerge()' - Merge a MIME database from disk with the current one.
+ */
+
+mime_t * /* O - Updated MIME database */
+mimeMerge(mime_t *mime, /* I - MIME database to add to */
+ const char *pathname) /* I - Directory to load */
+{
+#ifdef WIN32
+ HANDLE dir; /* Directory handle */
+ WIN32_FIND_DATA dent; /* Directory entry */
+ char filename[1024], /* Full filename of types/converts file */
+ *pathsep; /* Last character in path */
+
+
+ /*
+ * First open the directory specified by pathname... Return NULL if nothing
+ * was read or if the pathname is NULL...
+ */
+
+ if (pathname == NULL)
+ return (NULL);
+
+ strncpy(filename, pathname, sizeof(filename) - 1);
+ filename[sizeof(filename) - 1] = '\0';
+
+ pathsep = filename + strlen(filename);
+ if ((pathsep - filename + 9) > sizeof(filename))
+ return (NULL);
+
+ if (pathsep == filename ||
+ (pathsep[-1] != '/' && pathsep[-1] != '\\'))
+ {
+ strcpy(pathsep, "/");
+ pathsep ++;
+ }
+
+ strcpy(pathsep, "*.types");
+
+ if ((dir = FindFirstFile(filename, &dent)) == 0)
+ return (NULL);
+
+ /*
+ * If "mime" is NULL, make a new, blank database...
+ */
+
+ if (mime == NULL)
+ if ((mime = mimeNew()) == NULL)
+ return (NULL);
+
+ /*
+ * Read all the .types files...
+ */
+
+ do
+ {
+ /*
+ * Load a mime.types file...
+ */
+
+ if ((pathsep - filename + strlen(dent.cFileName)) >= sizeof(filename))
+ continue;
+
+ strcpy(pathsep, dent.cFileName);
+ load_types(mime, filename);
+ }
+ while (FindNextFile(dir, &dent));
+
+ FindClose(dir);
+
+ /*
+ * Read all the .convs files...
+ */
+
+ strcpy(pathsep, "*.convs");
+
+ if ((dir = FindFirstFile(filename, &dent)) == 0)
+ return (mime);
+
+ do
+ {
+ /*
+ * Load a mime.convs file...
+ */
+
+ if ((pathsep - filename + strlen(dent.cFileName)) >= sizeof(filename))
+ continue;
+
+ strcpy(pathsep, dent.cFileName);
+ load_convs(mime, filename);
+ }
+ while (FindNextFile(dir, &dent));
+
+ FindClose(dir);
+
+ return (mime);
+#else
+ DIR *dir; /* Directory */
+ DIRENT *dent; /* Directory entry */
+ char filename[1024]; /* Full filename of types/converts file */
+
+
+ /*
+ * First open the directory specified by pathname... Return NULL if nothing
+ * was read or if the pathname is NULL...
+ */
+
+ if (pathname == NULL)
+ return (NULL);
+
+ if ((dir = opendir(pathname)) == NULL)
+ return (NULL);
+
+ /*
+ * If "mime" is NULL, make a new, blank database...
+ */
+
+ if (mime == NULL)
+ if ((mime = mimeNew()) == NULL)
+ return (NULL);
+
+ /*
+ * Read all the .types files...
+ */
+
+ while ((dent = readdir(dir)) != NULL)
+ {
+ if (NAMLEN(dent) > 6 &&
+ strcmp(dent->d_name + NAMLEN(dent) - 6, ".types") == 0)
+ {
+ /*
+ * Load a mime.types file...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/%s", pathname, dent->d_name);
+ load_types(mime, filename);
+ }
+ }
+
+ rewinddir(dir);
+
+ /*
+ * Read all the .convs files...
+ */
+
+ while ((dent = readdir(dir)) != NULL)
+ {
+ if (NAMLEN(dent) > 6 &&
+ strcmp(dent->d_name + NAMLEN(dent) - 6, ".convs") == 0)
+ {
+ /*
+ * Load a mime.convs file...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/%s", pathname, dent->d_name);
+ load_convs(mime, filename);
+ }
+ }
+
+ closedir(dir);
+
+ return (mime);
+#endif /* WIN32 */
+}
+
+
+/*
+ * 'mimeNew()' - Create a new, empty MIME database.
+ */
+
+mime_t * /* O - MIME database */
+mimeNew(void)
+{
+ return ((mime_t *)calloc(1, sizeof(mime_t)));
+}
+
+
+/*
+ * 'load_types()' - Load a xyz.types file...
+ */
+
+static void
+load_types(mime_t *mime, /* I - MIME database */
+ char *filename) /* I - Types file to load */
+{
+ FILE *fp; /* Types file */
+ int linelen; /* Length of line */
+ char line[65536], /* Input line from file */
+ *lineptr, /* Current position in line */
+ super[MIME_MAX_SUPER], /* Super-type name */
+ type[MIME_MAX_TYPE], /* Type name */
+ *temp; /* Temporary pointer */
+ mime_type_t *typeptr; /* New MIME type */
+
+
+ /*
+ * First try to open the file...
+ */
+
+ if ((fp = fopen(filename, "r")) == NULL)
+ return;
+
+ /*
+ * Then read each line from the file, skipping any comments in the file...
+ */
+
+ while (fgets(line, sizeof(line), fp) != NULL)
+ {
+ linelen = strlen(line);
+
+ /*
+ * While the last character in the line is a backslash, continue on to the
+ * next line (and the next, etc.)
+ */
+
+ if (line[linelen - 1] == '\n')
+ {
+ line[linelen - 1] = '\0';
+ linelen --;
+ }
+
+ while (line[linelen - 1] == '\\')
+ {
+ linelen --;
+
+ if (fgets(line + linelen, sizeof(line) - linelen, fp) == NULL)
+ line[linelen] = '\0';
+ else
+ {
+ linelen += strlen(line + linelen);
+ if (line[linelen - 1] == '\n')
+ {
+ line[linelen - 1] = '\0';
+ linelen --;
+ }
+ }
+ }
+
+ /*
+ * Skip blank lines and lines starting with a #...
+ */
+
+ if (line[0] == '\n' || line[0] == '#')
+ continue;
+
+ /*
+ * Extract the super-type and type names from the beginning of the line.
+ */
+
+ lineptr = line;
+ temp = super;
+
+ while (*lineptr != '/' && *lineptr != '\n' && *lineptr != '\0' &&
+ (temp - super + 1) < MIME_MAX_SUPER)
+ *temp++ = tolower(*lineptr++);
+
+ *temp = '\0';
+
+ if (*lineptr != '/')
+ continue;
+
+ lineptr ++;
+ temp = type;
+
+ while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\n' &&
+ *lineptr != '\0' && (temp - type + 1) < MIME_MAX_TYPE)
+ *temp++ = tolower(*lineptr++);
+
+ *temp = '\0';
+
+ /*
+ * Add the type and rules to the MIME database...
+ */
+
+ typeptr = mimeAddType(mime, super, type);
+ mimeAddTypeRule(typeptr, lineptr);
+ }
+
+ fclose(fp);
+}
+
+
+/*
+ * 'load_convs()' - Load a xyz.convs file...
+ */
+
+static void
+load_convs(mime_t *mime, /* I - MIME database */
+ char *filename) /* I - Convs file to load */
+{
+ int i; /* Looping var */
+ FILE *fp; /* Convs file */
+ char line[1024], /* Input line from file */
+ *lineptr, /* Current position in line */
+ super[MIME_MAX_SUPER], /* Super-type name */
+ type[MIME_MAX_TYPE], /* Type name */
+ *temp, /* Temporary pointer */
+ *filter; /* Filter program */
+ mime_type_t **temptype, /* MIME type looping var */
+ *dsttype; /* Destination MIME type */
+ int cost; /* Cost of filter */
+
+
+ /*
+ * First try to open the file...
+ */
+
+ if ((fp = fopen(filename, "r")) == NULL)
+ return;
+
+ /*
+ * Then read each line from the file, skipping any comments in the file...
+ */
+
+ while (fgets(line, sizeof(line), fp) != NULL)
+ {
+ /*
+ * Skip blank lines and lines starting with a #...
+ */
+
+ if (line[0] == '\n' || line[0] == '#')
+ continue;
+
+ /*
+ * Strip trailing whitespace...
+ */
+
+ for (lineptr = line + strlen(line) - 1;
+ lineptr >= line && isspace(*lineptr);
+ lineptr --)
+ *lineptr = '\0';
+
+ /*
+ * Extract the destination super-type and type names from the middle of
+ * the line.
+ */
+
+ lineptr = line;
+ while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\0')
+ lineptr ++;
+
+ while (*lineptr == ' ' || *lineptr == '\t')
+ lineptr ++;
+
+ temp = super;
+
+ while (*lineptr != '/' && *lineptr != '\n' && *lineptr != '\0' &&
+ (temp - super + 1) < MIME_MAX_SUPER)
+ *temp++ = tolower(*lineptr++);
+
+ *temp = '\0';
+
+ if (*lineptr != '/')
+ continue;
+
+ lineptr ++;
+ temp = type;
+
+ while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\n' &&
+ *lineptr != '\0' && (temp - type + 1) < MIME_MAX_TYPE)
+ *temp++ = tolower(*lineptr++);
+
+ *temp = '\0';
+
+ if (*lineptr == '\0' || *lineptr == '\n')
+ continue;
+
+ if ((dsttype = mimeType(mime, super, type)) == NULL)
+ continue;
+
+ /*
+ * Then get the cost and filter program...
+ */
+
+ while (*lineptr == ' ' || *lineptr == '\t')
+ lineptr ++;
+
+ if (*lineptr < '0' || *lineptr > '9')
+ continue;
+
+ cost = atoi(lineptr);
+
+ while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\0')
+ lineptr ++;
+ while (*lineptr == ' ' || *lineptr == '\t')
+ lineptr ++;
+
+ if (*lineptr == '\0' || *lineptr == '\n')
+ continue;
+
+ filter = lineptr;
+
+ /*
+ * Finally, get the source super-type and type names from the beginning of
+ * the line. We do it here so we can support wildcards...
+ */
+
+ lineptr = line;
+ temp = super;
+
+ while (*lineptr != '/' && *lineptr != '\n' && *lineptr != '\0' &&
+ (temp - super + 1) < MIME_MAX_SUPER)
+ *temp++ = tolower(*lineptr++);
+
+ *temp = '\0';
+
+ if (*lineptr != '/')
+ continue;
+
+ lineptr ++;
+ temp = type;
+
+ while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\n' &&
+ *lineptr != '\0' && (temp - type + 1) < MIME_MAX_TYPE)
+ *temp++ = tolower(*lineptr++);
+
+ *temp = '\0';
+
+ if (strcmp(super, "*") == 0 && strcmp(type, "*") == 0)
+ {
+ /*
+ * Force * / * to be "application/octet-stream"...
+ */
+
+ strcpy(super, "application");
+ strcpy(type, "octet-stream");
+ }
+
+ /*
+ * Add the filter to the MIME database, supporting wildcards as needed...
+ */
+
+ for (temptype = mime->types, i = 0; i < mime->num_types; i ++, temptype ++)
+ if ((super[0] == '*' || strcmp((*temptype)->super, super) == 0) &&
+ (type[0] == '*' || strcmp((*temptype)->type, type) == 0))
+ mimeAddFilter(mime, *temptype, dsttype, cost, filter);
+ }
+
+ fclose(fp);
+}
+
+
+/*
+ * 'delete_rules()' - Free all memory for the given rule tree.
+ */
+
+static void
+delete_rules(mime_magic_t *rules) /* I - Rules to free */
+{
+ mime_magic_t *next; /* Next rule to free */
+
+
+ /*
+ * Free the rules list, descending recursively to free any child rules.
+ */
+
+ while (rules != NULL)
+ {
+ next = rules->next;
+
+ if (rules->child != NULL)
+ delete_rules(rules->child);
+
+ free(rules);
+ rules = next;
+ }
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/mime.h b/scheduler/mime.h
new file mode 100644
index 000000000..6d9e8f870
--- /dev/null
+++ b/scheduler/mime.h
@@ -0,0 +1,139 @@
+/*
+ * "$Id$"
+ *
+ * MIME type/conversion database definitions for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Easy Software Products and are protected by Federal
+ * copyright law. Distribution and use rights are outlined in the file
+ * "LICENSE.txt" which should have been included with this file. If this
+ * file is missing or damaged please contact Easy Software Products
+ * at:
+ *
+ * Attn: CUPS Licensing Information
+ * Easy Software Products
+ * 44141 Airport View Drive, Suite 204
+ * Hollywood, Maryland 20636-3111 USA
+ *
+ * Voice: (301) 373-9603
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ */
+
+#ifndef _MIME_H_
+# define _MIME_H_
+
+/*
+ * C++ magic...
+ */
+
+# ifdef _cplusplus
+extern "C" {
+# endif /* _cplusplus */
+
+
+/*
+ * Constants...
+ */
+
+# define MIME_MAX_SUPER 16 /* Maximum size of supertype name */
+# define MIME_MAX_TYPE 32 /* Maximum size of type name */
+# define MIME_MAX_FILTER 256 /* Maximum size of filter pathname */
+# define MIME_MAX_BUFFER 8192 /* Maximum size of file buffer */
+
+
+/*
+ * Types/structures...
+ */
+
+typedef enum
+{
+ MIME_MAGIC_NOP, /* No operation */
+ MIME_MAGIC_AND, /* Logical AND of all children */
+ MIME_MAGIC_OR, /* Logical OR of all children */
+ MIME_MAGIC_MATCH, /* Filename match */
+ MIME_MAGIC_ASCII, /* ASCII characters in range */
+ MIME_MAGIC_PRINTABLE, /* Printable characters (32-255) in range */
+ MIME_MAGIC_STRING, /* String matches */
+ MIME_MAGIC_CHAR, /* Character/byte matches */
+ MIME_MAGIC_SHORT, /* Short/16-bit word matches */
+ MIME_MAGIC_INT, /* Integer/32-bit word matches */
+ MIME_MAGIC_LOCALE, /* Current locale matches string */
+ MIME_MAGIC_CONTAINS /* File contains a string */
+} mime_op_t;
+
+typedef struct mime_magic_str /**** MIME Magic Data ****/
+{
+ struct mime_magic_str *prev, /* Previous rule */
+ *next, /* Next rule */
+ *parent, /* Parent rules */
+ *child; /* Child rules */
+ short op, /* Operation code (see above) */
+ invert; /* Invert the result */
+ int offset, /* Offset in file */
+ region, /* Region length */
+ length; /* Length of data */
+ union
+ {
+ char matchv[64]; /* Match value */
+ char localev[64]; /* Locale value */
+ char stringv[64]; /* String value */
+ char charv; /* Byte value */
+ short shortv; /* Short value */
+ int intv; /* Integer value */
+ } value;
+} mime_magic_t;
+
+typedef struct /**** MIME Type Data ****/
+{
+ char super[MIME_MAX_SUPER], /* Super-type name ("image", "application", etc.) */
+ type[MIME_MAX_TYPE]; /* Type name ("png", "postscript", etc.) */
+ mime_magic_t *rules; /* Rules used to detect this type */
+} mime_type_t;
+
+typedef struct /**** MIME Conversion Filter Data ****/
+{
+ mime_type_t *src, /* Source type */
+ *dst; /* Destination type */
+ int cost; /* Relative cost */
+ char filter[MIME_MAX_FILTER];/* Filter program to use */
+} mime_filter_t;
+
+typedef struct /**** MIME Database ****/
+{
+ int num_types; /* Number of file types */
+ mime_type_t **types; /* File types */
+ int num_filters; /* Number of type conversion filters */
+ mime_filter_t *filters; /* Type conversion filters */
+} mime_t;
+
+
+/*
+ * Functions...
+ */
+
+extern void mimeDelete(mime_t *mime);
+#define mimeLoad(pathname) mimeMerge((mime_t *)0, (pathname));
+extern mime_t *mimeMerge(mime_t *mime, const char *pathname);
+extern mime_t *mimeNew(void);
+
+extern mime_type_t *mimeAddType(mime_t *mime, const char *super, const char *type);
+extern int mimeAddTypeRule(mime_type_t *mt, const char *rule);
+extern mime_type_t *mimeFileType(mime_t *mime, const char *pathname);
+extern mime_type_t *mimeType(mime_t *mime, const char *super, const char *type);
+
+extern mime_filter_t *mimeAddFilter(mime_t *mime, mime_type_t *src, mime_type_t *dst,
+ int cost, const char *filter);
+extern mime_filter_t *mimeFilter(mime_t *mime, mime_type_t *src, mime_type_t *dst,
+ int *num_filters);
+
+# ifdef _cplusplus
+}
+# endif /* _cplusplus */
+#endif /* !_MIME_H_ */
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/ppds.c b/scheduler/ppds.c
new file mode 100644
index 000000000..9ee566918
--- /dev/null
+++ b/scheduler/ppds.c
@@ -0,0 +1,897 @@
+/*
+ * "$Id$"
+ *
+ * PPD scanning routines for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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:
+ *
+ * LoadPPDs() - Load PPD files from the specified directory...
+ * buf_read() - Read a buffer of data into memory...
+ * check_ppds() - Check to see if we need to regenerate the PPD file
+ * list...
+ * compare_names() - Compare PPD filenames for sorting.
+ * compare_ppds() - Compare PPD file make and model names for sorting.
+ * load_ppds() - Load PPD files recursively.
+ * ppd_gets() - Read a line from a PPD file.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cupsd.h"
+#include <ctype.h>
+
+#ifdef HAVE_LIBZ
+# include <zlib.h>
+#else
+# define gzFile FILE *
+# define gzclose fclose
+# define gzread(f,b,l) fread((b), 1, (l), (f))
+# define gzopen fopen
+#endif /* HAVE_LIBZ */
+
+
+/*
+ * PPD information structures...
+ */
+
+typedef struct
+{
+ char ppd_make[128], /* Manufacturer */
+ ppd_make_and_model[248]; /* Make and model */
+ int ppd_size, /* Size in bytes */
+ ppd_mtime; /* Modification time */
+ char ppd_name[256], /* PPD filename */
+ ppd_natural_language[16]; /* Natural language */
+} ppd_rec_t;
+
+typedef struct
+{
+ int found; /* 1 if PPD is found */
+ ppd_rec_t record; /* ppds.dat record */
+} ppd_info_t;
+
+
+/*
+ * Buffered file structure...
+ */
+
+typedef struct
+{
+ gzFile fp; /* Pointer to file */
+ char *ptr, /* Pointer in buffer */
+ *end, /* End of buffer */
+ buf[1024]; /* Buffer */
+} buf_t;
+
+
+/*
+ * Local globals...
+ */
+
+static int num_ppds, /* Number of PPD files */
+ alloc_ppds; /* Number of allocated entries */
+static ppd_info_t *ppds; /* PPD file info */
+static int changed_ppd; /* Did we change the PPD database? */
+
+
+/*
+ * Local functions...
+ */
+
+static int buf_read(buf_t *fp);
+static int compare_names(const ppd_info_t *p0, const ppd_info_t *p1);
+static int compare_ppds(const ppd_info_t *p0, const ppd_info_t *p1);
+static void load_ppds(const char *d, const char *p);
+static char *ppd_gets(buf_t *fp, char *buf, int buflen);
+
+
+/*
+ * 'LoadPPDs()' - Load PPD files from the specified directory...
+ */
+
+void
+LoadPPDs(const char *d) /* I - Directory to scan... */
+{
+ int i; /* Looping var */
+ ppd_info_t *ppd; /* Current PPD file */
+ FILE *fp; /* ppds.dat file */
+ struct stat fileinfo; /* ppds.dat information */
+ char filename[1024]; /* ppds.dat filename */
+
+
+ /*
+ * See if we a PPD database file...
+ */
+
+ num_ppds = 0;
+ alloc_ppds = 0;
+ ppds = (ppd_info_t *)0;
+ changed_ppd = 0;
+
+ snprintf(filename, sizeof(filename), "%s/ppds.dat", ServerRoot);
+ if (!stat(filename, &fileinfo) &&
+ (num_ppds = fileinfo.st_size / sizeof(ppd_rec_t)) > 0)
+ {
+ /*
+ * We have a ppds.dat file, so read it!
+ */
+
+ alloc_ppds = num_ppds;
+
+ if ((ppds = malloc(sizeof(ppd_info_t) * num_ppds)) == NULL)
+ {
+ LogMessage(L_ERROR, "LoadPPDs: Unable to allocate memory for %d PPD files!",
+ num_ppds);
+ num_ppds = 0;
+ alloc_ppds = 0;
+ }
+ else if ((fp = fopen(filename, "rb")) != NULL)
+ {
+ for (i = num_ppds, ppd = ppds; i > 0; i --, ppd ++)
+ {
+ fread(&(ppd->record), 1, sizeof(ppd_rec_t), fp);
+ ppd->found = 0;
+ }
+
+ fclose(fp);
+
+ LogMessage(L_INFO, "LoadPPDs: Read \"%s\", %d PPDs...", filename,
+ num_ppds);
+
+ /*
+ * Sort the PPDs by name...
+ */
+
+ if (num_ppds > 1)
+ qsort(ppds, num_ppds, sizeof(ppd_info_t),
+ (int (*)(const void *, const void *))compare_names);
+ }
+ else
+ {
+ LogMessage(L_ERROR, "LoadPPDs: Unable to read \"%s\" - %s", filename,
+ strerror(errno));
+ num_ppds = 0;
+ }
+ }
+
+ /*
+ * Load all PPDs in the specified directory and below...
+ */
+
+ load_ppds(d, "");
+
+ /*
+ * Cull PPD files that are no longer present...
+ */
+
+ for (i = num_ppds, ppd = ppds; i > 0; i --, ppd ++)
+ if (!ppd->found)
+ {
+ /*
+ * Remove this PPD file from the list...
+ */
+
+ if (i > 1)
+ memcpy(ppd, ppd + 1, (i - 1) * sizeof(ppd_info_t));
+
+ num_ppds --;
+ ppd --;
+ }
+
+ /*
+ * Sort the PPDs by make and model...
+ */
+
+ if (num_ppds > 1)
+ qsort(ppds, num_ppds, sizeof(ppd_info_t),
+ (int (*)(const void *, const void *))compare_ppds);
+
+ /*
+ * Write the new ppds.dat file...
+ */
+
+ if (changed_ppd)
+ {
+ if ((fp = fopen(filename, "wb")) != NULL)
+ {
+ for (i = num_ppds, ppd = ppds; i > 0; i --, ppd ++)
+ fwrite(&(ppd->record), 1, sizeof(ppd_rec_t), fp);
+
+ fclose(fp);
+
+ LogMessage(L_INFO, "LoadPPDs: Wrote \"%s\", %d PPDs...", filename,
+ num_ppds);
+ }
+ else
+ LogMessage(L_ERROR, "LoadPPDs: Unable to write \"%s\" - %s", filename,
+ strerror(errno));
+ }
+ else
+ LogMessage(L_INFO, "LoadPPDs: No new or changed PPDs...");
+
+ /*
+ * Create the list of PPDs...
+ */
+
+ PPDs = ippNew();
+
+ /*
+ * First the raw driver...
+ */
+
+ ippAddString(PPDs, IPP_TAG_PRINTER, IPP_TAG_NAME,
+ "ppd-name", NULL, "raw");
+ ippAddString(PPDs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
+ "ppd-make", NULL, "Raw");
+ ippAddString(PPDs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
+ "ppd-make-and-model", NULL, "Raw Queue");
+ ippAddString(PPDs, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE,
+ "ppd-natural-language", NULL, "en");
+
+ /*
+ * Then the PPD files...
+ */
+
+ for (i = num_ppds, ppd = ppds; i > 0; i --, ppd ++)
+ {
+ ippAddSeparator(PPDs);
+
+ ippAddString(PPDs, IPP_TAG_PRINTER, IPP_TAG_NAME,
+ "ppd-name", NULL, ppd->record.ppd_name);
+ ippAddString(PPDs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
+ "ppd-make", NULL, ppd->record.ppd_make);
+ ippAddString(PPDs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
+ "ppd-make-and-model", NULL, ppd->record.ppd_make_and_model);
+ ippAddString(PPDs, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE,
+ "ppd-natural-language", NULL, ppd->record.ppd_natural_language);
+ }
+
+ /*
+ * Free the memory used...
+ */
+
+ if (alloc_ppds)
+ {
+ free(ppds);
+ alloc_ppds = 0;
+ }
+}
+
+
+/*
+ * 'buf_read()' - Read a buffer of data into memory...
+ */
+
+static int /* O - Number of bytes read */
+buf_read(buf_t *fp) /* I - File to read from */
+{
+ int count; /* Number of bytes read */
+
+
+ if ((count = gzread(fp->fp, fp->buf, sizeof(fp->buf))) > 0)
+ {
+ fp->ptr = fp->buf;
+ fp->end = fp->buf + count;
+ }
+ else
+ {
+ fp->ptr = NULL;
+ fp->end = NULL;
+ }
+
+ return (count);
+}
+
+
+/*
+ * 'compare_names()' - Compare PPD filenames for sorting.
+ */
+
+static int /* O - Result of comparison */
+compare_names(const ppd_info_t *p0, /* I - First PPD file */
+ const ppd_info_t *p1) /* I - Second PPD file */
+{
+ return (strcasecmp(p0->record.ppd_name, p1->record.ppd_name));
+}
+
+
+/*
+ * 'compare_ppds()' - Compare PPD file make and model names for sorting.
+ */
+
+static int /* O - Result of comparison */
+compare_ppds(const ppd_info_t *p0, /* I - First PPD file */
+ const ppd_info_t *p1) /* I - Second PPD file */
+{
+ const char *s, /* First name */
+ *t; /* Second name */
+ int diff, /* Difference between digits */
+ digits; /* Number of digits */
+
+
+ /*
+ * First compare manufacturers...
+ */
+
+ if ((diff = strcasecmp(p0->record.ppd_make, p1->record.ppd_make)) != 0)
+ return (diff);
+
+ /*
+ * Then compare names...
+ */
+
+ s = p0->record.ppd_make_and_model;
+ t = p1->record.ppd_make_and_model;
+
+ /*
+ * Loop through both nicknames, 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;
+ s ++;
+ t ++;
+
+ 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 if (diff)
+ 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 (strcasecmp(p0->record.ppd_natural_language,
+ p1->record.ppd_natural_language));
+}
+
+
+/*
+ * 'load_ppds()' - Load PPD files recursively.
+ */
+
+static void
+load_ppds(const char *d, /* I - Actual directory */
+ const char *p) /* I - Virtual path in name */
+{
+ int i; /* Looping var */
+ buf_t fp; /* Pointer to file */
+ DIR *dir; /* Directory pointer */
+ DIRENT *dent; /* Directory entry */
+ struct stat fileinfo; /* File information */
+ char filename[1024], /* Name of PPD or directory */
+ line[256], /* Line from backend */
+ *ptr, /* Pointer into name */
+ name[128], /* Name of PPD file */
+ language[64], /* PPD language version */
+ country[64], /* Country code */
+ manufacturer[256], /* Manufacturer */
+ make_model[256], /* Make and Model */
+ model_name[256], /* ModelName */
+ nick_name[256]; /* NickName */
+ ppd_info_t *ppd, /* New PPD file */
+ key; /* Search key */
+ int new_ppd; /* Is this a new PPD? */
+ struct /* LanguageVersion translation table */
+ {
+ const char *version, /* LanguageVersion string */
+ *language; /* Language code */
+ } languages[] =
+ {
+ { "chinese", "cn" },
+ { "english", "en" },
+ { "french", "fr" },
+ { "german", "de" },
+ { "danish", "da" },
+ { "finnish", "fi" },
+ { "italian", "it" },
+ { "dutch", "du" },
+ { "japanese", "jp" },
+ { "norwegian", "no" },
+ { "polish", "pl" },
+ { "portugese", "pt" },
+ { "russian", "ru" },
+ { "swedish", "sv" },
+ { "turkish", "tr" }
+ };
+
+
+ if ((dir = opendir(d)) == NULL)
+ {
+ LogMessage(L_ERROR, "LoadPPDs: Unable to open PPD directory \"%s\": %s",
+ d, strerror(errno));
+ return;
+ }
+
+ while ((dent = readdir(dir)) != NULL)
+ {
+ /*
+ * Skip "." and ".."...
+ */
+
+ if (dent->d_name[0] == '.')
+ continue;
+
+ /*
+ * See if this is a file...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/%s", d, dent->d_name);
+
+ if (p[0])
+ snprintf(name, sizeof(name), "%s/%s", p, dent->d_name);
+ else
+ {
+ strncpy(name, dent->d_name, sizeof(name) - 1);
+ name[sizeof(name) - 1] = '\0';
+ }
+
+ if (stat(filename, &fileinfo))
+ continue;
+
+ if (S_ISDIR(fileinfo.st_mode))
+ {
+ /*
+ * Do subdirectory...
+ */
+
+ load_ppds(filename, name);
+ continue;
+ }
+
+ /*
+ * See if this file has been scanned before...
+ */
+
+ if (num_ppds > 0)
+ {
+ strcpy(key.record.ppd_name, name);
+
+ ppd = bsearch(&key, ppds, num_ppds, sizeof(ppd_info_t),
+ (int (*)(const void *, const void *))compare_names);
+
+ if (ppd &&
+ ppd->record.ppd_size == fileinfo.st_size &&
+ ppd->record.ppd_mtime == fileinfo.st_mtime)
+ {
+ ppd->found = 1;
+ continue;
+ }
+ }
+ else
+ ppd = NULL;
+
+ /*
+ * No, file is new/changed, so re-scan it...
+ */
+
+ if ((fp.fp = gzopen(filename, "rb")) == NULL)
+ continue;
+
+ fp.ptr = fp.end = NULL;
+
+ /*
+ * Now see if this is a PPD file...
+ */
+
+ line[0] = '\0';
+ ppd_gets(&fp, line, sizeof(line));
+
+ if (strncmp(line, "*PPD-Adobe:", 11) != 0)
+ {
+ /*
+ * Nope, close the file and continue...
+ */
+
+ gzclose(fp.fp);
+
+ continue;
+ }
+
+ /*
+ * Now read until we get the NickName field...
+ */
+
+ model_name[0] = '\0';
+ nick_name[0] = '\0';
+ manufacturer[0] = '\0';
+ strcpy(language, "en");
+
+ while (ppd_gets(&fp, line, sizeof(line)) != NULL)
+ {
+ if (strncmp(line, "*Manufacturer:", 14) == 0)
+ sscanf(line, "%*[^\"]\"%255[^\"]", manufacturer);
+ else if (strncmp(line, "*ModelName:", 11) == 0)
+ sscanf(line, "%*[^\"]\"%127[^\"]", model_name);
+ else if (strncmp(line, "*LanguageVersion:", 17) == 0)
+ sscanf(line, "%*[^:]:%63s", language);
+ else if (strncmp(line, "*NickName:", 10) == 0)
+ sscanf(line, "%*[^\"]\"%255[^\"]", nick_name);
+ else if (strncmp(line, "*OpenUI", 7) == 0)
+ {
+ /*
+ * Stop early if we have a NickName or ModelName attributes
+ * before the first OpenUI...
+ */
+
+ if (model_name[0] || nick_name[0])
+ break;
+ }
+
+ /*
+ * Stop early if we have both the Manufacturer and NickName
+ * attributes...
+ */
+
+ if (manufacturer[0] && nick_name[0])
+ break;
+ }
+
+ /*
+ * Close the file...
+ */
+
+ gzclose(fp.fp);
+
+ /*
+ * See if we got all of the required info...
+ */
+
+ if (nick_name[0])
+ strcpy(make_model, nick_name);
+ else
+ strcpy(make_model, model_name);
+
+ while (isspace(make_model[0]))
+ strcpy(make_model, make_model + 1);
+
+ if (!make_model[0])
+ continue; /* Nope... */
+
+ /*
+ * See if we got a manufacturer...
+ */
+
+ while (isspace(manufacturer[0]))
+ strcpy(manufacturer, manufacturer + 1);
+
+ if (!manufacturer[0] || strcmp(manufacturer, "ESP") == 0)
+ {
+ /*
+ * Nope, copy the first part of the make and model then...
+ */
+
+ strncpy(manufacturer, make_model, sizeof(manufacturer) - 1);
+
+ /*
+ * Truncate at the first space, dash, or slash, or make the
+ * manufacturer "Other"...
+ */
+
+ for (ptr = manufacturer; *ptr; ptr ++)
+ if (*ptr == ' ' || *ptr == '-' || *ptr == '/')
+ break;
+
+ if (*ptr && ptr > manufacturer)
+ *ptr = '\0';
+ else if (strncasecmp(manufacturer, "agfa", 4) == 0)
+ strcpy(manufacturer, "AGFA");
+ else if (strncasecmp(manufacturer, "herk", 4) == 0 ||
+ strncasecmp(manufacturer, "linotype", 8) == 0)
+ strcpy(manufacturer, "LHAG");
+ else
+ strcpy(manufacturer, "Other");
+
+ /*
+ * Hack for various vendors...
+ */
+
+ if (strcasecmp(manufacturer, "XPrint") == 0)
+ strcpy(manufacturer, "Xerox");
+ else if (strcasecmp(manufacturer, "Eastman") == 0)
+ strcpy(manufacturer, "Kodak");
+ else if (strcasecmp(manufacturer, "laserwriter") == 0)
+ strcpy(manufacturer, "Apple");
+ else if (strcasecmp(manufacturer, "colorpoint") == 0)
+ strcpy(manufacturer, "Seiko");
+ else if (strcasecmp(manufacturer, "fiery") == 0)
+ strcpy(manufacturer, "EFI");
+ else if (strcasecmp(manufacturer, "ps") == 0 ||
+ strcasecmp(manufacturer, "colorpass") == 0)
+ strcpy(manufacturer, "Canon");
+ else if (strncasecmp(manufacturer, "primera", 7) == 0)
+ strcpy(manufacturer, "Fargo");
+ else if (strcasecmp(manufacturer, "designjet") == 0)
+ strcpy(manufacturer, "HP");
+ }
+ else if (strncasecmp(manufacturer, "LHAG", 4) == 0 ||
+ strncasecmp(manufacturer, "linotype", 8) == 0)
+ strcpy(manufacturer, "LHAG");
+
+ /*
+ * Fix the language as needed...
+ */
+
+ if ((ptr = strchr(language, '-')) != NULL)
+ *ptr++ = '\0';
+ else if ((ptr = strchr(language, '_')) != NULL)
+ *ptr++ = '\0';
+
+ if (ptr)
+ {
+ /*
+ * Setup the country suffix...
+ */
+
+ country[0] = '_';
+ strcpy(country + 1, ptr);
+ }
+ else
+ {
+ /*
+ * No country suffix...
+ */
+
+ country[0] = '\0';
+ }
+
+ for (i = 0; i < (int)(sizeof(languages) / sizeof(languages[0])); i ++)
+ if (strcasecmp(languages[i].version, language) == 0)
+ break;
+
+ if (i < (int)(sizeof(languages) / sizeof(languages[0])))
+ {
+ /*
+ * Found a known language...
+ */
+
+ snprintf(language, sizeof(language), "%s%s", languages[i].language,
+ country);
+ }
+ else
+ {
+ /*
+ * Unknown language; use "xx"...
+ */
+
+ strcpy(language, "xx");
+ }
+
+ /*
+ * Add the PPD file...
+ */
+
+ new_ppd = !ppd;
+
+ if (new_ppd)
+ {
+ /*
+ * Allocate memory for the new PPD file...
+ */
+
+ LogMessage(L_DEBUG, "LoadPPDs: Adding ppd \"%s\"...", name);
+
+ if (num_ppds >= alloc_ppds)
+ {
+ /*
+ * Allocate (more) memory for the PPD files...
+ */
+
+ if (alloc_ppds == 0)
+ ppd = malloc(sizeof(ppd_info_t) * 32);
+ else
+ ppd = realloc(ppds, sizeof(ppd_info_t) * (alloc_ppds + 32));
+
+ if (ppd == NULL)
+ {
+ LogMessage(L_ERROR, "load_ppds: Ran out of memory for %d PPD files!",
+ alloc_ppds + 32);
+ closedir(dir);
+ return;
+ }
+
+ ppds = ppd;
+ alloc_ppds += 32;
+ }
+
+ ppd = ppds + num_ppds;
+ num_ppds ++;
+ }
+ else
+ LogMessage(L_DEBUG, "LoadPPDs: Updating ppd \"%s\"...", name);
+
+ /*
+ * Zero the PPD record and copy the info over...
+ */
+
+ memset(ppd, 0, sizeof(ppd_info_t));
+
+ ppd->found = 1;
+ ppd->record.ppd_mtime = fileinfo.st_mtime;
+ ppd->record.ppd_size = fileinfo.st_size;
+
+ strncpy(ppd->record.ppd_name, name,
+ sizeof(ppd->record.ppd_name) - 1);
+ strncpy(ppd->record.ppd_make, manufacturer,
+ sizeof(ppd->record.ppd_make) - 1);
+ strncpy(ppd->record.ppd_make_and_model, make_model,
+ sizeof(ppd->record.ppd_make_and_model) - 1);
+ strncpy(ppd->record.ppd_natural_language, language,
+ sizeof(ppd->record.ppd_natural_language) - 1);
+
+ changed_ppd = 1;
+
+ /*
+ * Re-sort the PPD array...
+ */
+
+ if (num_ppds > 1 && new_ppd)
+ qsort(ppds, num_ppds, sizeof(ppd_info_t),
+ (int (*)(const void *, const void *))compare_names);
+ }
+
+ closedir(dir);
+}
+
+
+/*
+ * 'ppd_gets()' - Read a line from a PPD file.
+ */
+
+static char * /* O - Line from file or NULL on EOF */
+ppd_gets(buf_t *fp, /* I - File to read from */
+ char *buf, /* I - Line buffer */
+ int buflen) /* I - Length of buffer */
+{
+ int ch; /* Character from file */
+ char *ptr, /* Current position in line buffer */
+ *end; /* End of line buffer */
+
+ /*
+ * Range check everything...
+ */
+
+ if (fp == NULL || buf == NULL || buflen < 2)
+ return (NULL);
+
+ /*
+ * Now loop until we have a valid line...
+ */
+
+ ptr = buf;
+ end = buf + buflen - 1;
+
+ for (;;)
+ {
+ if (fp->ptr >= fp->end)
+ if (buf_read(fp) <= 0)
+ break;
+
+ ch = *(fp->ptr)++;
+
+ if (ch == '\r' || ch == '\n')
+ {
+ /*
+ * Line feed or carriage return...
+ */
+
+ if (ptr == buf) /* Skip blank lines */
+ continue;
+
+ break;
+ }
+ else if (ptr < end)
+ *ptr++ = ch;
+ }
+
+ if (ptr > buf)
+ {
+ *ptr = '\0';
+
+ return (buf);
+ }
+ else
+ return (NULL);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/printers.c b/scheduler/printers.c
new file mode 100644
index 000000000..2a54328ed
--- /dev/null
+++ b/scheduler/printers.c
@@ -0,0 +1,2054 @@
+/*
+ * "$Id$"
+ *
+ * Printer routines for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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:
+ *
+ * AddPrinter() - Add a printer to the system.
+ * AddPrinterFilter() - Add a MIME filter for a printer.
+ * AddPrinterUser() - Add a user to the ACL.
+ * DeleteAllPrinters() - Delete all printers from the system.
+ * DeletePrinter() - Delete a printer from the system.
+ * DeletePrinterFilters() - Delete all MIME filters for a printer.
+ * FindPrinter() - Find a printer in the list.
+ * FreePrinterUsers() - Free allow/deny users.
+ * LoadAllPrinters() - Load printers from the printers.conf file.
+ * SaveAllPrinters() - Save all printer definitions to the printers.conf
+ * SetPrinterAttrs() - Set printer attributes based upon the PPD file.
+ * SetPrinterState() - Update the current state of a printer.
+ * SortPrinters() - Sort the printer list when a printer name is
+ * changed.
+ * StopPrinter() - Stop a printer from printing any jobs...
+ * ValidateDest() - Validate a printer/class destination.
+ * write_irix_config() - Update the config files used by the IRIX
+ * desktop tools.
+ * write_irix_state() - Update the status files used by IRIX printing
+ * desktop tools.
+ * write_printcap() - Write a pseudo-printcap file for older
+ * applications that need it...
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cupsd.h"
+
+
+/*
+ * Local functions...
+ */
+
+static void write_printcap(void);
+#ifdef __sgi
+static void write_irix_config(printer_t *p);
+static void write_irix_state(printer_t *p);
+#endif /* __sgi */
+
+
+/*
+ * 'AddPrinter()' - Add a printer to the system.
+ */
+
+printer_t * /* O - New printer */
+AddPrinter(const char *name) /* I - Name of printer */
+{
+ printer_t *p, /* New printer */
+ *current, /* Current printer in list */
+ *prev; /* Previous printer in list */
+
+
+ DEBUG_printf(("AddPrinter(\"%s\")\n", name));
+
+ /*
+ * Range check input...
+ */
+
+ if (name == NULL)
+ return (NULL);
+
+ /*
+ * Create a new printer entity...
+ */
+
+ if ((p = calloc(1, sizeof(printer_t))) == NULL)
+ return (NULL);
+
+ strncpy(p->name, name, sizeof(p->name) - 1);
+ strncpy(p->hostname, ServerName, sizeof(p->hostname) - 1);
+ snprintf(p->uri, sizeof(p->uri), "ipp://%s:%d/printers/%s", ServerName,
+ ntohs(Listeners[0].address.sin_port), name);
+
+ p->state = IPP_PRINTER_STOPPED;
+ p->accepting = 0;
+ p->filetype = mimeAddType(MimeDatabase, "printer", name);
+
+ strcpy(p->job_sheets[0], "none");
+ strcpy(p->job_sheets[1], "none");
+
+ /*
+ * Setup required filters and IPP attributes...
+ */
+
+ SetPrinterAttrs(p);
+
+ /*
+ * Insert the printer in the printer list alphabetically...
+ */
+
+ for (prev = NULL, current = Printers;
+ current != NULL;
+ prev = current, current = current->next)
+ if (strcasecmp(p->name, current->name) < 0)
+ break;
+
+ /*
+ * Insert this printer before the current one...
+ */
+
+ if (prev == NULL)
+ Printers = p;
+ else
+ prev->next = p;
+
+ p->next = current;
+
+ /*
+ * Write a new /etc/printcap or /var/spool/lp/pstatus file.
+ */
+
+ write_printcap();
+
+ return (p);
+}
+
+
+/*
+ * 'AddPrinterFilter()' - Add a MIME filter for a printer.
+ */
+
+void
+AddPrinterFilter(printer_t *p, /* I - Printer to add to */
+ const char *filter) /* I - Filter to add */
+{
+ int i; /* Looping var */
+ char super[MIME_MAX_SUPER], /* Super-type for filter */
+ type[MIME_MAX_TYPE], /* Type for filter */
+ program[1024]; /* Program/filter name */
+ int cost; /* Cost of filter */
+ mime_type_t **temptype; /* MIME type looping var */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (p == NULL || filter == NULL)
+ return;
+
+ /*
+ * Parse the filter string; it should be in the following format:
+ *
+ * super/type cost program
+ */
+
+ if (sscanf(filter, "%15[^/]/%31s%d%1023s", super, type, &cost, program) != 4)
+ {
+ LogMessage(L_ERROR, "AddPrinterFilter: Invalid filter string \"%s\"!",
+ filter);
+ return;
+ }
+
+ /*
+ * Add the filter to the MIME database, supporting wildcards as needed...
+ */
+
+ for (temptype = MimeDatabase->types, i = MimeDatabase->num_types;
+ i > 0;
+ i --, temptype ++)
+ if (((super[0] == '*' && strcmp((*temptype)->super, "printer") != 0) ||
+ strcmp((*temptype)->super, super) == 0) &&
+ (type[0] == '*' || strcmp((*temptype)->type, type) == 0))
+ {
+ LogMessage(L_DEBUG2, "Adding filter %s/%s %s/%s %d %s",
+ (*temptype)->super, (*temptype)->type,
+ p->filetype->super, p->filetype->type,
+ cost, program);
+ mimeAddFilter(MimeDatabase, *temptype, p->filetype, cost, program);
+ }
+}
+
+
+/*
+ * 'AddPrinterUser()' - Add a user to the ACL.
+ */
+
+void
+AddPrinterUser(printer_t *p, /* I - Printer */
+ const char *username) /* I - User */
+{
+ const char **temp; /* Temporary array pointer */
+
+
+ if (!p || !username)
+ return;
+
+ if (p->num_users == 0)
+ temp = malloc(sizeof(char **));
+ else
+ temp = realloc(p->users, sizeof(char **) * (p->num_users + 1));
+
+ if (!temp)
+ return;
+
+ p->users = temp;
+ temp += p->num_users;
+
+ if ((*temp = strdup(username)) != NULL)
+ p->num_users ++;
+}
+
+
+/*
+ * 'DeleteAllPrinters()' - Delete all printers from the system.
+ */
+
+void
+DeleteAllPrinters(void)
+{
+ printer_t *p, /* Pointer to current printer/class */
+ *next; /* Pointer to next printer in list */
+
+
+ for (p = Printers; p != NULL; p = next)
+ {
+ next = p->next;
+
+ if (!(p->type & CUPS_PRINTER_CLASS))
+ DeletePrinter(p);
+ }
+}
+
+
+/*
+ * 'DeletePrinter()' - Delete a printer from the system.
+ */
+
+void
+DeletePrinter(printer_t *p) /* I - Printer to delete */
+{
+ printer_t *current, /* Current printer in list */
+ *prev; /* Previous printer in list */
+#ifdef __sgi
+ char filename[1024]; /* Interface script filename */
+#endif /* __sgi */
+
+
+ DEBUG_printf(("DeletePrinter(%08x): p->name = \"%s\"...\n", p, p->name));
+
+ /*
+ * Range check input...
+ */
+
+ if (p == NULL)
+ return;
+
+ /*
+ * Remove the printer from the list...
+ */
+
+ for (prev = NULL, current = Printers;
+ current != NULL;
+ prev = current, current = current->next)
+ if (p == current)
+ break;
+
+ if (current == NULL)
+ {
+ LogMessage(L_ERROR, "Tried to delete a non-existent printer %s!\n",
+ p->name);
+ return;
+ }
+
+ if (prev == NULL)
+ Printers = p->next;
+ else
+ prev->next = p->next;
+
+ /*
+ * Stop printing on this printer...
+ */
+
+ StopPrinter(p);
+
+ /*
+ * Remove the dummy interface/icon/option files under IRIX...
+ */
+
+#ifdef __sgi
+ snprintf(filename, sizeof(filename), "/var/spool/lp/interface/%s", p->name);
+ unlink(filename);
+
+ snprintf(filename, sizeof(filename), "/var/spool/lp/gui_interface/ELF/%s.gui",
+ p->name);
+ unlink(filename);
+
+ snprintf(filename, sizeof(filename), "/var/spool/lp/activeicons/%s", p->name);
+ unlink(filename);
+
+ snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.config", p->name);
+ unlink(filename);
+
+ snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.status", p->name);
+ unlink(filename);
+
+ snprintf(filename, sizeof(filename), "/var/spool/lp/member/%s", p->name);
+ unlink(filename);
+#endif /* __sgi */
+
+ /*
+ * If p is the default printer, assign the next one...
+ */
+
+ if (p == DefaultPrinter)
+ {
+ DefaultPrinter = Printers;
+
+#ifdef __sgi
+ /*
+ * Update the IRIX printer state for the new default printer; if
+ * no printers remain, then the default printer file will be
+ * removed...
+ */
+
+ write_irix_state(DefaultPrinter);
+#endif /* __sgi */
+ }
+
+ /*
+ * Remove this printer from any classes...
+ */
+
+ if (!(p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT)))
+ DeletePrinterFromClasses(p);
+
+ /*
+ * Free all memory used by the printer...
+ */
+
+ if (p->printers != NULL)
+ free(p->printers);
+
+ ippDelete(p->attrs);
+
+ DeletePrinterFilters(p);
+
+ FreePrinterUsers(p);
+ FreeQuotas(p);
+
+ free(p);
+
+ /*
+ * Write a new /etc/printcap file...
+ */
+
+ write_printcap();
+}
+
+
+/*
+ * 'DeletePrinterFilters()' - Delete all MIME filters for a printer.
+ */
+
+void
+DeletePrinterFilters(printer_t *p) /* I - Printer to remove from */
+{
+ int i; /* Looping var */
+ mime_filter_t *filter; /* MIME filter looping var */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (p == NULL)
+ return;
+
+ /*
+ * Remove all filters from the MIME database that have a destination
+ * type == printer...
+ */
+
+ for (filter = MimeDatabase->filters, i = MimeDatabase->num_filters;
+ i > 0;
+ i --, filter ++)
+ if (filter->dst == p->filetype)
+ {
+ /*
+ * Delete the current filter...
+ */
+
+ MimeDatabase->num_filters --;
+
+ if (i > 1)
+ memcpy(filter, filter + 1, sizeof(mime_filter_t) * (i - 1));
+
+ filter --;
+ }
+}
+
+
+/*
+ * 'FindPrinter()' - Find a printer in the list.
+ */
+
+printer_t * /* O - Printer in list */
+FindPrinter(const char *name) /* I - Name of printer to find */
+{
+ printer_t *p; /* Current printer */
+
+
+ for (p = Printers; p != NULL; p = p->next)
+ switch (strcasecmp(name, p->name))
+ {
+ case 0 : /* name == p->name */
+ if (!(p->type & CUPS_PRINTER_CLASS))
+ return (p);
+ case 1 : /* name > p->name */
+ break;
+ case -1 : /* name < p->name */
+ return (NULL);
+ }
+
+ return (NULL);
+}
+
+
+/*
+ * 'FreePrinterUsers()' - Free allow/deny users.
+ */
+
+void
+FreePrinterUsers(printer_t *p) /* I - Printer */
+{
+ int i; /* Looping var */
+
+
+ if (!p || !p->num_users)
+ return;
+
+ for (i = 0; i < p->num_users; i ++)
+ free((void *)p->users[i]);
+
+ free(p->users);
+
+ p->num_users = 0;
+ p->users = NULL;
+}
+
+
+/*
+ * 'LoadAllPrinters()' - Load printers from the printers.conf file.
+ */
+
+void
+LoadAllPrinters(void)
+{
+ FILE *fp; /* printers.conf file */
+ int linenum; /* Current line number */
+ int len; /* Length of line */
+ char line[1024], /* Line from file */
+ name[256], /* Parameter name */
+ *nameptr, /* Pointer into name */
+ *value, /* Pointer to value */
+ *valueptr; /* Pointer into value */
+ printer_t *p; /* Current printer */
+
+
+ /*
+ * Open the printers.conf file...
+ */
+
+ snprintf(line, sizeof(line), "%s/printers.conf", ServerRoot);
+ if ((fp = fopen(line, "r")) == NULL)
+ return;
+
+ /*
+ * Read printer configurations until we hit EOF...
+ */
+
+ linenum = 0;
+ p = NULL;
+
+ while (fgets(line, sizeof(line), fp) != NULL)
+ {
+ linenum ++;
+
+ /*
+ * Skip comment lines...
+ */
+
+ if (line[0] == '#')
+ continue;
+
+ /*
+ * Strip trailing whitespace, if any...
+ */
+
+ len = strlen(line);
+
+ while (len > 0 && isspace(line[len - 1]))
+ {
+ len --;
+ line[len] = '\0';
+ }
+
+ /*
+ * Extract the name from the beginning of the line...
+ */
+
+ for (value = line; isspace(*value); value ++);
+
+ for (nameptr = name; *value != '\0' && !isspace(*value) &&
+ nameptr < (name + sizeof(name) - 1);)
+ *nameptr++ = *value++;
+ *nameptr = '\0';
+
+ while (isspace(*value))
+ value ++;
+
+ if (name[0] == '\0')
+ continue;
+
+ /*
+ * Decode the directive...
+ */
+
+ if (strcmp(name, "<Printer") == 0 ||
+ strcmp(name, "<DefaultPrinter") == 0)
+ {
+ /*
+ * <Printer name> or <DefaultPrinter name>
+ */
+
+ if (line[len - 1] == '>' && p == NULL)
+ {
+ /*
+ * Add the printer and a base file type...
+ */
+
+ line[len - 1] = '\0';
+
+ p = AddPrinter(value);
+ p->accepting = 1;
+ p->state = IPP_PRINTER_IDLE;
+
+ /*
+ * Set the default printer as needed...
+ */
+
+ if (strcmp(name, "<DefaultPrinter") == 0)
+ DefaultPrinter = p;
+ }
+ else
+ {
+ LogMessage(L_ERROR, "Syntax error on line %d of printers.conf.",
+ linenum);
+ return;
+ }
+ }
+ else if (strcmp(name, "</Printer>") == 0)
+ {
+ if (p != NULL)
+ {
+ SetPrinterAttrs(p);
+ p = NULL;
+ }
+ else
+ {
+ LogMessage(L_ERROR, "Syntax error on line %d of printers.conf.",
+ linenum);
+ return;
+ }
+ }
+ else if (p == NULL)
+ {
+ LogMessage(L_ERROR, "Syntax error on line %d of printers.conf.",
+ linenum);
+ return;
+ }
+ else if (strcmp(name, "Info") == 0)
+ strncpy(p->info, value, sizeof(p->info) - 1);
+ else if (strcmp(name, "Location") == 0)
+ strncpy(p->location, value, sizeof(p->location) - 1);
+ else if (strcmp(name, "DeviceURI") == 0)
+ strncpy(p->device_uri, value, sizeof(p->device_uri) - 1);
+ else if (strcmp(name, "State") == 0)
+ {
+ /*
+ * Set the initial queue state...
+ */
+
+ if (strcasecmp(value, "idle") == 0)
+ p->state = IPP_PRINTER_IDLE;
+ else if (strcasecmp(value, "stopped") == 0)
+ p->state = IPP_PRINTER_STOPPED;
+ }
+ else if (strcmp(name, "StateMessage") == 0)
+ {
+ /*
+ * Set the initial queue state message...
+ */
+
+ while (isspace(*value))
+ value ++;
+
+ strncpy(p->state_message, value, sizeof(p->state_message) - 1);
+ }
+ else if (strcmp(name, "Accepting") == 0)
+ {
+ /*
+ * Set the initial accepting state...
+ */
+
+ if (strcasecmp(value, "yes") == 0)
+ p->accepting = 1;
+ else
+ p->accepting = 0;
+ }
+ else if (strcmp(name, "JobSheets") == 0)
+ {
+ /*
+ * Set the initial job sheets...
+ */
+
+ for (valueptr = value; *valueptr && !isspace(*valueptr); valueptr ++);
+
+ if (*valueptr)
+ *valueptr++ = '\0';
+
+ strncpy(p->job_sheets[0], value, sizeof(p->job_sheets[0]) - 1);
+
+ while (isspace(*valueptr))
+ valueptr ++;
+
+ if (*valueptr)
+ {
+ for (value = valueptr; *valueptr && !isspace(*valueptr); valueptr ++);
+
+ if (*valueptr)
+ *valueptr++ = '\0';
+
+ strncpy(p->job_sheets[1], value, sizeof(p->job_sheets[1]) - 1);
+ }
+ }
+ else if (strcmp(name, "AllowUser") == 0)
+ {
+ p->deny_users = 0;
+ AddPrinterUser(p, value);
+ }
+ else if (strcmp(name, "DenyUser") == 0)
+ {
+ p->deny_users = 1;
+ AddPrinterUser(p, value);
+ }
+ else if (strcmp(name, "QuotaPeriod") == 0)
+ p->quota_period = atoi(value);
+ else if (strcmp(name, "PageLimit") == 0)
+ p->page_limit = atoi(value);
+ else if (strcmp(name, "KLimit") == 0)
+ p->k_limit = atoi(value);
+ else
+ {
+ /*
+ * Something else we don't understand...
+ */
+
+ LogMessage(L_ERROR, "Unknown configuration directive %s on line %d of printers.conf.",
+ name, linenum);
+ }
+ }
+
+ fclose(fp);
+}
+
+
+/*
+ * 'SaveAllPrinters()' - Save all printer definitions to the printers.conf
+ * file.
+ */
+
+void
+SaveAllPrinters(void)
+{
+ int i; /* Looping var */
+ FILE *fp; /* printers.conf file */
+ char temp[1024]; /* Temporary string */
+ char backup[1024]; /* printers.conf.O file */
+ printer_t *printer; /* Current printer class */
+ time_t curtime; /* Current time */
+ struct tm *curdate; /* Current date */
+
+
+ /*
+ * Create the printers.conf file...
+ */
+
+ snprintf(temp, sizeof(temp), "%s/printers.conf", ServerRoot);
+ snprintf(backup, sizeof(backup), "%s/printers.conf.O", ServerRoot);
+
+ if (rename(temp, backup))
+ LogMessage(L_ERROR, "Unable to backup printers.conf - %s", strerror(errno));
+
+ if ((fp = fopen(temp, "w")) == NULL)
+ {
+ LogMessage(L_ERROR, "Unable to save printers.conf - %s", strerror(errno));
+
+ if (rename(backup, temp))
+ LogMessage(L_ERROR, "Unable to restore printers.conf - %s", strerror(errno));
+ return;
+ }
+ else
+ LogMessage(L_INFO, "Saving printers.conf...");
+
+ /*
+ * Restrict access to the file...
+ */
+
+ fchown(fileno(fp), User, Group);
+ fchmod(fileno(fp), 0600);
+
+ /*
+ * Write a small header to the file...
+ */
+
+ curtime = time(NULL);
+ curdate = gmtime(&curtime);
+ strftime(temp, sizeof(temp) - 1, CUPS_STRFTIME_FORMAT, curdate);
+
+ fputs("# Printer configuration file for " CUPS_SVERSION "\n", fp);
+ fprintf(fp, "# Written by cupsd on %s\n", temp);
+
+ /*
+ * Write each local printer known to the system...
+ */
+
+ for (printer = Printers; printer != NULL; printer = printer->next)
+ {
+ /*
+ * Skip remote destinations and printer classes...
+ */
+
+ if ((printer->type & CUPS_PRINTER_REMOTE) ||
+ (printer->type & CUPS_PRINTER_CLASS) ||
+ (printer->type & CUPS_PRINTER_IMPLICIT))
+ continue;
+
+ /*
+ * Write printers as needed...
+ */
+
+ if (printer == DefaultPrinter)
+ fprintf(fp, "<DefaultPrinter %s>\n", printer->name);
+ else
+ fprintf(fp, "<Printer %s>\n", printer->name);
+
+ if (printer->info[0])
+ fprintf(fp, "Info %s\n", printer->info);
+
+ if (printer->location[0])
+ fprintf(fp, "Location %s\n", printer->location);
+
+ if (printer->device_uri[0])
+ fprintf(fp, "DeviceURI %s\n", printer->device_uri);
+
+ if (printer->state == IPP_PRINTER_STOPPED)
+ {
+ fputs("State Stopped\n", fp);
+ fprintf(fp, "StateMessage %s\n", printer->state_message);
+ }
+ else
+ fputs("State Idle\n", fp);
+
+ if (printer->accepting)
+ fputs("Accepting Yes\n", fp);
+ else
+ fputs("Accepting No\n", fp);
+
+ fprintf(fp, "JobSheets %s %s\n", printer->job_sheets[0],
+ printer->job_sheets[1]);
+
+ fprintf(fp, "QuotaPeriod %d\n", printer->quota_period);
+ fprintf(fp, "PageLimit %d\n", printer->page_limit);
+ fprintf(fp, "KLimit %d\n", printer->k_limit);
+
+ for (i = 0; i < printer->num_users; i ++)
+ fprintf(fp, "%sUser %s\n", printer->deny_users ? "Deny" : "Allow",
+ printer->users[i]);
+
+ fputs("</Printer>\n", fp);
+
+#ifdef __sgi
+ /*
+ * Make IRIX desktop & printer status happy
+ */
+
+ write_irix_state(printer);
+#endif /* __sgi */
+ }
+
+ fclose(fp);
+}
+
+
+/*
+ * 'SetPrinterAttrs()' - Set printer attributes based upon the PPD file.
+ */
+
+void
+SetPrinterAttrs(printer_t *p) /* I - Printer to setup */
+{
+ char uri[HTTP_MAX_URI]; /* URI for printer */
+ char method[HTTP_MAX_URI], /* Method portion of URI */
+ username[HTTP_MAX_URI], /* Username portion of URI */
+ host[HTTP_MAX_URI], /* Host portion of URI */
+ resource[HTTP_MAX_URI]; /* Resource portion of URI */
+ int port; /* Port portion of URI */
+ int i; /* Looping var */
+ char filename[1024]; /* Name of PPD file */
+ int num_media; /* Number of media options */
+ location_t *auth; /* Pointer to authentication element */
+ const char *auth_supported; /* Authentication supported */
+ cups_ptype_t printer_type; /* Printer type data */
+ ppd_file_t *ppd; /* PPD file data */
+ ppd_option_t *input_slot, /* InputSlot options */
+ *media_type, /* MediaType options */
+ *page_size, /* PageSize options */
+ *output_bin; /* OutputBin options */
+ ipp_attribute_t *attr; /* Attribute data */
+ ipp_value_t *val; /* Attribute value */
+ int nups[3] = /* number-up-supported values */
+ { 1, 2, 4 };
+ ipp_orient_t orients[4] = /* orientation-requested-supported values */
+ {
+ IPP_PORTRAIT,
+ IPP_LANDSCAPE,
+ IPP_REVERSE_LANDSCAPE,
+ IPP_REVERSE_PORTRAIT
+ };
+ const char *sides[3] = /* sides-supported values */
+ {
+ "one",
+ "two-long-edge",
+ "two-short-edge"
+ };
+ const char *versions[] = /* ipp-versions-supported values */
+ {
+ "1.0",
+ "1.1"
+ };
+ ipp_op_t ops[] = /* operations-supported values */
+ {
+ IPP_PRINT_JOB,
+ IPP_VALIDATE_JOB,
+ IPP_CREATE_JOB,
+ IPP_SEND_DOCUMENT,
+ IPP_CANCEL_JOB,
+ IPP_GET_JOB_ATTRIBUTES,
+ IPP_GET_JOBS,
+ IPP_GET_PRINTER_ATTRIBUTES,
+ IPP_HOLD_JOB,
+ IPP_RELEASE_JOB,
+ IPP_PAUSE_PRINTER,
+ IPP_RESUME_PRINTER,
+ IPP_PURGE_JOBS,
+ IPP_SET_JOB_ATTRIBUTES,
+ IPP_ENABLE_PRINTER,
+ IPP_DISABLE_PRINTER,
+ 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_GET_DEVICES,
+ CUPS_GET_PPDS,
+ IPP_RESTART_JOB
+ };
+ const char *charsets[] = /* charset-supported values */
+ {
+ "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",
+ "iso-8859-10",
+ "iso-8859-13",
+ "iso-8859-14",
+ "iso-8859-15",
+ "utf-8",
+ "windows-874",
+ "windows-1250",
+ "windows-1251",
+ "windows-1252",
+ "windows-1253",
+ "windows-1254",
+ "windows-1255",
+ "windows-1256",
+ "windows-1257",
+ "windows-1258",
+ "koi8-r",
+ "koi8-u",
+ };
+ int num_finishings;
+ ipp_finish_t finishings[5];
+ const char *multiple_document_handling[] =
+ {
+ "separate-documents-uncollated-copies",
+ "separate-documents-collated-copies"
+ };
+
+
+ DEBUG_printf(("SetPrinterAttrs: entering name = %s, type = %x\n", p->name,
+ p->type));
+
+ /*
+ * Clear out old filters and add a filter from application/vnd.cups-raw to
+ * printer/name to handle "raw" printing by users.
+ */
+
+ DeletePrinterFilters(p);
+ AddPrinterFilter(p, "application/vnd.cups-raw 0 -");
+
+ /*
+ * Figure out the authentication that is required for the printer.
+ */
+
+ auth_supported = "requesting-user-name";
+ if (!(p->type & CUPS_PRINTER_REMOTE))
+ {
+ if (p->type & CUPS_PRINTER_CLASS)
+ snprintf(resource, sizeof(resource), "/classes/%s", p->name);
+ else
+ snprintf(resource, sizeof(resource), "/printers/%s", p->name);
+
+ if ((auth = FindBest(resource, HTTP_POST)) != NULL)
+ {
+ if (auth->type == AUTH_BASIC || auth->type == AUTH_BASICDIGEST)
+ auth_supported = "basic";
+ else if (auth->type == AUTH_DIGEST)
+ auth_supported = "digest";
+ }
+ }
+
+ /*
+ * Create the required IPP attributes for a printer...
+ */
+
+ if (p->attrs)
+ ippDelete(p->attrs);
+
+ p->attrs = ippNew();
+
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-uri-supported",
+ NULL, p->uri);
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "uri-authentication-supported", NULL, auth_supported);
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "uri-security-supported", NULL, "none");
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, "printer-name", NULL,
+ p->name);
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location",
+ NULL, p->location);
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info",
+ NULL, p->info);
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-more-info",
+ NULL, p->uri);
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "pdl-override-supported", NULL, "not-attempted");
+ ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "ipp-versions-supported", sizeof(versions) / sizeof(versions[0]),
+ NULL, versions);
+ ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "operations-supported",
+ sizeof(ops) / sizeof(ops[0]) + JobFiles - 1, (int *)ops);
+ ippAddBoolean(p->attrs, IPP_TAG_PRINTER, "multiple-document-jobs-supported", 1);
+ ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "multiple-operation-time-out", 60);
+ ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "multiple-document-handling-supported",
+ sizeof(multiple_document_handling) /
+ sizeof(multiple_document_handling[0]), NULL,
+ multiple_document_handling);
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_CHARSET, "charset-configured",
+ NULL, DefaultCharset);
+ ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_CHARSET, "charset-supported",
+ sizeof(charsets) / sizeof(charsets[0]), NULL, charsets);
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE,
+ "natural-language-configured", NULL, DefaultLanguage);
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE,
+ "generated-natural-language-supported", NULL, DefaultLanguage);
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE,
+ "document-format-default", NULL, "application/octet-stream");
+ ippAddStrings(p->attrs, IPP_TAG_PRINTER,
+ (ipp_tag_t)(IPP_TAG_MIMETYPE | IPP_TAG_COPY),
+ "document-format-supported", NumMimeTypes, NULL, MimeTypes);
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "compression-supported", NULL, "none");
+ ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "job-priority-supported", 100);
+ ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "job-priority-default", 50);
+ ippAddRange(p->attrs, IPP_TAG_PRINTER, "copies-supported", 1, 65535);
+ ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "copies-default", 1);
+ ippAddBoolean(p->attrs, IPP_TAG_PRINTER, "page-ranges-supported", 1);
+ ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "number-up-supported", 3, nups);
+ ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "number-up-default", 1);
+ ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
+ "orientation-requested-supported", 4, (int *)orients);
+ ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
+ "orientation-requested-default", IPP_PORTRAIT);
+
+ if (p->num_users)
+ {
+ if (p->deny_users)
+ ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
+ "requesting-user-name-denied", p->num_users, NULL,
+ p->users);
+ else
+ ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
+ "requesting-user-name-allowed", p->num_users, NULL,
+ p->users);
+ }
+
+ ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "job-quota-period", p->quota_period);
+ ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "job-k-limit", p->k_limit);
+ ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "job-page-limit", p->page_limit);
+
+ if (NumBanners > 0)
+ {
+ /*
+ * Setup the job-sheets-supported and job-sheets-default attributes...
+ */
+
+ if (Classification[0] && !ClassifyOverride)
+ attr = ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
+ "job-sheets-supported", NULL, Classification);
+ else
+ attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
+ "job-sheets-supported", NumBanners + 1, NULL, NULL);
+
+ if (attr == NULL)
+ LogMessage(L_EMERG, "SetPrinterAttrs: Unable to allocate memory for "
+ "job-sheets-supported attribute: %s!",
+ strerror(errno));
+ else if (!Classification[0] || ClassifyOverride)
+ {
+ attr->values[0].string.text = strdup("none");
+
+ for (i = 0; i < NumBanners; i ++)
+ attr->values[i + 1].string.text = strdup(Banners[i].name);
+ }
+
+ if (!(p->type & CUPS_PRINTER_REMOTE))
+ {
+ attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
+ "job-sheets-default", 2, NULL, NULL);
+
+ if (attr != NULL)
+ {
+ attr->values[0].string.text = strdup(Classification[0] ?
+ Classification : p->job_sheets[0]);
+ attr->values[1].string.text = strdup(Classification[0] ?
+ Classification : p->job_sheets[1]);
+ }
+ }
+ }
+
+ printer_type = p->type;
+
+ if (p->type & CUPS_PRINTER_REMOTE)
+ {
+ /*
+ * Tell the client this is a remote printer of some type...
+ */
+
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
+ "printer-make-and-model", NULL, p->make_model);
+ }
+ else
+ {
+ /*
+ * Assign additional attributes depending on whether this is a printer
+ * or class...
+ */
+
+ p->type &= ~CUPS_PRINTER_OPTIONS;
+
+ if (p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))
+ {
+ /*
+ * Add class-specific attributes...
+ */
+
+ if ((p->type & CUPS_PRINTER_IMPLICIT) && p->num_printers > 0)
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
+ "printer-make-and-model", NULL, p->printers[0]->make_model);
+ else
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
+ "printer-make-and-model", NULL, "Local Printer Class");
+
+ if (p->num_printers > 0)
+ {
+ /*
+ * Add a list of member URIs and names...
+ */
+
+ attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
+ "member-uris", p->num_printers, NULL, NULL);
+ p->type |= CUPS_PRINTER_OPTIONS;
+
+ for (i = 0; i < p->num_printers; i ++)
+ {
+ if (attr != NULL)
+ attr->values[i].string.text = strdup(p->printers[i]->uri);
+
+ p->type &= ~CUPS_PRINTER_OPTIONS | p->printers[i]->type;
+ }
+
+ attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
+ "member-names", p->num_printers, NULL, NULL);
+
+ if (attr != NULL)
+ {
+ for (i = 0; i < p->num_printers; i ++)
+ attr->values[i].string.text = strdup(p->printers[i]->name);
+ }
+ }
+ }
+ else
+ {
+ /*
+ * Add printer-specific attributes... Start by sanitizing the device
+ * URI so it doesn't have a username or password in it...
+ */
+
+ if (strstr(p->device_uri, "://") != NULL)
+ {
+ /*
+ * http://..., ipp://..., etc.
+ */
+
+ httpSeparate(p->device_uri, method, username, host, &port, resource);
+ if (port)
+ snprintf(uri, sizeof(uri), "%s://%s:%d%s", method, host, port,
+ resource);
+ else
+ snprintf(uri, sizeof(uri), "%s://%s%s", method, host, resource);
+ }
+ else
+ {
+ /*
+ * file:..., serial:..., etc.
+ */
+
+ strcpy(uri, p->device_uri);
+ }
+
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL,
+ uri);
+
+ /*
+ * Assign additional attributes from the PPD file (if any)...
+ */
+
+ p->type |= CUPS_PRINTER_BW;
+ finishings[0] = IPP_FINISHINGS_NONE;
+ num_finishings = 1;
+
+ snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd", ServerRoot,
+ p->name);
+
+ if ((ppd = ppdOpenFile(filename)) != NULL)
+ {
+ /*
+ * Add make/model and other various attributes...
+ */
+
+ if (ppd->color_device)
+ p->type |= CUPS_PRINTER_COLOR;
+ if (ppd->variable_sizes)
+ p->type |= CUPS_PRINTER_VARIABLE;
+ if (!ppd->manual_copies)
+ p->type |= CUPS_PRINTER_COPIES;
+
+ ippAddBoolean(p->attrs, IPP_TAG_PRINTER, "color-supported",
+ ppd->color_device);
+ if (ppd->throughput)
+ ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "pages-per-minute", ppd->throughput);
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
+ "printer-make-and-model", NULL, ppd->nickname);
+
+ if (ppd->nickname)
+ strncpy(p->make_model, ppd->nickname, sizeof(p->make_model) - 1);
+ else if (ppd->modelname)
+ strncpy(p->make_model, ppd->modelname, sizeof(p->make_model) - 1);
+ else
+ strcpy(p->make_model, "Bad PPD File");
+
+ /*
+ * Add media options from the PPD file...
+ */
+
+ if ((input_slot = ppdFindOption(ppd, "InputSlot")) != NULL)
+ num_media = input_slot->num_choices;
+ else
+ num_media = 0;
+
+ if ((media_type = ppdFindOption(ppd, "MediaType")) != NULL)
+ num_media += media_type->num_choices;
+
+ if ((page_size = ppdFindOption(ppd, "PageSize")) != NULL)
+ num_media += page_size->num_choices;
+
+ attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "media-supported", num_media, NULL, NULL);
+ if (attr != NULL)
+ {
+ val = attr->values;
+
+ if (input_slot != NULL)
+ for (i = 0; i < input_slot->num_choices; i ++, val ++)
+ val->string.text = strdup(input_slot->choices[i].choice);
+
+ if (media_type != NULL)
+ for (i = 0; i < media_type->num_choices; i ++, val ++)
+ val->string.text = strdup(media_type->choices[i].choice);
+
+ if (page_size != NULL)
+ {
+ for (i = 0; i < page_size->num_choices; i ++, val ++)
+ val->string.text = strdup(page_size->choices[i].choice);
+
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-default",
+ NULL, page_size->defchoice);
+ }
+ else if (input_slot != NULL)
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-default",
+ NULL, input_slot->defchoice);
+ else if (media_type != NULL)
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-default",
+ NULL, media_type->defchoice);
+ else
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-default",
+ NULL, "none");
+ }
+
+ /*
+ * Output bin...
+ */
+
+ if ((output_bin = ppdFindOption(ppd, "OutputBin")) != NULL)
+ {
+ attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "output-bin-supported", output_bin->num_choices,
+ NULL, NULL);
+
+ if (attr != NULL)
+ {
+ for (i = 0, val = attr->values;
+ i < output_bin->num_choices;
+ i ++, val ++)
+ val->string.text = strdup(output_bin->choices[i].choice);
+ }
+ }
+
+ /*
+ * Duplexing, etc...
+ */
+
+ if (ppdFindOption(ppd, "Duplex") != NULL)
+ {
+ p->type |= CUPS_PRINTER_DUPLEX;
+
+ ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "sides-supported",
+ 3, NULL, sides);
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "sides-default",
+ NULL, "one");
+ }
+
+ if (ppdFindOption(ppd, "Collate") != NULL)
+ p->type |= CUPS_PRINTER_COLLATE;
+
+ if (ppdFindOption(ppd, "StapleLocation") != NULL)
+ {
+ p->type |= CUPS_PRINTER_STAPLE;
+ finishings[num_finishings++] = IPP_FINISHINGS_STAPLE;
+ }
+
+ if (ppdFindOption(ppd, "BindEdge") != NULL)
+ {
+ p->type |= CUPS_PRINTER_BIND;
+ finishings[num_finishings++] = IPP_FINISHINGS_BIND;
+ }
+
+ for (i = 0; i < ppd->num_sizes; i ++)
+ if (ppd->sizes[i].length > 1728)
+ p->type |= CUPS_PRINTER_LARGE;
+ else if (ppd->sizes[i].length > 1008)
+ p->type |= CUPS_PRINTER_MEDIUM;
+ else
+ p->type |= CUPS_PRINTER_SMALL;
+
+ /*
+ * Add any filters in the PPD file...
+ */
+
+ DEBUG_printf(("ppd->num_filters = %d\n", ppd->num_filters));
+ for (i = 0; i < ppd->num_filters; i ++)
+ {
+ DEBUG_printf(("ppd->filters[%d] = \"%s\"\n", i, ppd->filters[i]));
+ AddPrinterFilter(p, ppd->filters[i]);
+ }
+
+ if (ppd->num_filters == 0)
+ AddPrinterFilter(p, "application/vnd.cups-postscript 0 -");
+
+ ppdClose(ppd);
+
+ printer_type = p->type;
+ }
+ else if (access(filename, 0) == 0)
+ {
+ LogMessage(L_ERROR, "PPD file for %s cannot be loaded!", p->name);
+
+ AddPrinterFilter(p, "application/vnd.cups-postscript 0 -");
+ }
+ else
+ {
+ /*
+ * If we have an interface script, add a filter entry for it...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/interfaces/%s", ServerRoot,
+ p->name);
+ if (access(filename, X_OK) == 0)
+ {
+ /*
+ * Yes, we have a System V style interface script; use it!
+ */
+
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
+ "printer-make-and-model", NULL, "Local System V Printer");
+
+ snprintf(filename, sizeof(filename), "*/* 0 %s/interfaces/%s",
+ ServerRoot, p->name);
+ AddPrinterFilter(p, filename);
+ }
+ else if (strncmp(p->device_uri, "ipp://", 6) == 0 &&
+ (strstr(p->device_uri, "/printers/") != NULL ||
+ strstr(p->device_uri, "/classes/") != NULL))
+ {
+ /*
+ * Tell the client this is really a hard-wired remote printer.
+ */
+
+ printer_type |= CUPS_PRINTER_REMOTE;
+
+ /*
+ * Reset the printer-uri-supported attribute to point at the
+ * remote printer...
+ */
+
+ attr = ippFindAttribute(p->attrs, "printer-uri-supported", IPP_TAG_URI);
+ free(attr->values[0].string.text);
+ attr->values[0].string.text = strdup(p->device_uri);
+
+ /*
+ * Then set the make-and-model accordingly...
+ */
+
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
+ "printer-make-and-model", NULL, "Remote Printer");
+
+ /*
+ * Print all files directly...
+ */
+
+ AddPrinterFilter(p, "*/* 0 -");
+ }
+ else
+ {
+ /*
+ * Otherwise we have neither - treat this as a "dumb" printer
+ * with no PPD file...
+ */
+
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
+ "printer-make-and-model", NULL, "Local Raw Printer");
+
+ AddPrinterFilter(p, "*/* 0 -");
+ }
+ }
+
+ ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
+ "finishings-supported", num_finishings, (int *)finishings);
+ ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
+ "finishings-default", IPP_FINISHINGS_NONE);
+ }
+ }
+
+ /*
+ * Add the CUPS-specific printer-type attribute...
+ */
+
+ ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-type",
+ printer_type);
+
+ DEBUG_printf(("SetPrinterAttrs: leaving name = %s, type = %x\n", p->name,
+ p->type));
+
+#ifdef __sgi
+ /*
+ * Write the IRIX printer config and status files...
+ */
+
+ write_irix_config(p);
+ write_irix_state(p);
+#endif /* __sgi */
+}
+
+
+/*
+ * 'SetPrinterState()' - Update the current state of a printer.
+ */
+
+void
+SetPrinterState(printer_t *p, /* I - Printer to change */
+ ipp_pstate_t s) /* I - New state */
+{
+ ipp_pstate_t old_state; /* Old printer state */
+
+
+ /*
+ * Can't set status of remote printers...
+ */
+
+ if (p->type & CUPS_PRINTER_REMOTE)
+ return;
+
+ /*
+ * Set the new state...
+ */
+
+ old_state = p->state;
+ p->state = s;
+ p->state_time = time(NULL);
+
+ if (old_state != s)
+ {
+ p->browse_time = 0;
+
+#ifdef __sgi
+ write_irix_state(p);
+#endif /* __sgi */
+ }
+
+ /*
+ * Save the printer configuration if a printer goes from idle or processing
+ * to stopped (or visa-versa)...
+ */
+
+ if ((old_state == IPP_PRINTER_STOPPED) != (s == IPP_PRINTER_STOPPED))
+ SaveAllPrinters();
+
+ /*
+ * Check to see if any pending jobs can now be printed...
+ */
+
+ CheckJobs();
+}
+
+
+/*
+ * 'SortPrinters()' - Sort the printer list when a printer name is changed.
+ */
+
+void
+SortPrinters(void)
+{
+ printer_t *current, /* Current printer */
+ *prev, /* Previous printer */
+ *next; /* Next printer */
+ int did_swap; /* Non-zero if we did a swap */
+
+
+ do
+ {
+ for (did_swap = 0, current = Printers, prev = NULL; current != NULL;)
+ if (current->next == NULL)
+ break;
+ else if (strcasecmp(current->name, current->next->name) > 0)
+ {
+ DEBUG_printf(("Swapping %s and %s...\n", current->name,
+ current->next->name));
+
+ /*
+ * Need to swap these two printers...
+ */
+
+ did_swap = 1;
+
+ if (prev == NULL)
+ Printers = current->next;
+ else
+ prev->next = current->next;
+
+ /*
+ * Yes, we can all get a headache from the next bunch of pointer
+ * swapping...
+ */
+
+ next = current->next;
+ current->next = next->next;
+ next->next = current;
+ prev = next;
+ }
+ else
+ {
+ prev = current;
+ current = current->next;
+ }
+ }
+ while (did_swap);
+}
+
+
+/*
+ * 'StopPrinter()' - Stop a printer from printing any jobs...
+ */
+
+void
+StopPrinter(printer_t *p) /* I - Printer to stop */
+{
+ job_t *job; /* Active print job */
+
+
+ /*
+ * See if we have a job printing on this printer...
+ */
+
+ if (p->job)
+ {
+ /*
+ * Get pointer to job...
+ */
+
+ job = (job_t *)p->job;
+
+ /*
+ * Stop it...
+ */
+
+ StopJob(job->id, 0);
+
+ /*
+ * Reset the state to pending...
+ */
+
+ job->state->values[0].integer = IPP_JOB_PENDING;
+
+ SaveJob(job->id);
+ }
+
+ p->state = IPP_PRINTER_STOPPED;
+}
+
+
+/*
+ * 'ValidateDest()' - Validate a printer/class destination.
+ */
+
+const char * /* O - Printer or class name */
+ValidateDest(const char *hostname, /* I - Host name */
+ const char *resource, /* I - Resource name */
+ cups_ptype_t *dtype) /* O - Type (printer or class) */
+{
+ printer_t *p; /* Current printer */
+ char localname[1024], /* Localized hostname */
+ *lptr, /* Pointer into localized hostname */
+ *sptr; /* Pointer into server name */
+
+
+ DEBUG_printf(("ValidateDest(\"%s\", \"%s\", %p)\n", hostname, resource, dtype));
+
+ /*
+ * See if the resource is a class or printer...
+ */
+
+ if (strncmp(resource, "/classes/", 9) == 0)
+ {
+ /*
+ * Class...
+ */
+
+ resource += 9;
+ }
+ else if (strncmp(resource, "/printers/", 10) == 0)
+ {
+ /*
+ * Printer...
+ */
+
+ resource += 10;
+ }
+ else
+ {
+ /*
+ * Bad resource name...
+ */
+
+ return (NULL);
+ }
+
+ /*
+ * See if the printer or class name exists...
+ */
+
+ if ((p = FindPrinter(resource)) == NULL)
+ p = FindClass(resource);
+
+ if (p == NULL && strchr(resource, '@') == NULL)
+ return (NULL);
+ else if (p != NULL)
+ {
+ *dtype = p->type & CUPS_PRINTER_CLASS;
+ return (p->name);
+ }
+
+ /*
+ * Change localhost to the server name...
+ */
+
+ if (strcasecmp(hostname, "localhost") == 0)
+ hostname = ServerName;
+
+ strncpy(localname, hostname, sizeof(localname) - 1);
+ localname[sizeof(localname) - 1] = '\0';
+
+ if (strcasecmp(hostname, ServerName) != 0)
+ {
+ /*
+ * Localize the hostname...
+ */
+
+ lptr = strchr(localname, '.');
+ sptr = strchr(ServerName, '.');
+
+ if (sptr != NULL && lptr != NULL)
+ {
+ /*
+ * Strip the common domain name components...
+ */
+
+ while (lptr != NULL)
+ {
+ if (strcasecmp(lptr, sptr) == 0)
+ {
+ *lptr = '\0';
+ break;
+ }
+ else
+ lptr = strchr(lptr + 1, '.');
+ }
+ }
+ }
+
+ DEBUG_printf(("localized hostname is \"%s\"...\n", localname));
+
+ /*
+ * Find a matching printer or class...
+ */
+
+ for (p = Printers; p != NULL; p = p->next)
+ if (strcasecmp(p->hostname, localname) == 0 &&
+ strcasecmp(p->name, resource) == 0)
+ {
+ *dtype = p->type & CUPS_PRINTER_CLASS;
+ return (p->name);
+ }
+
+ return (NULL);
+}
+
+
+/*
+ * 'write_printcap()' - Write a pseudo-printcap file for older applications
+ * that need it...
+ */
+
+static void
+write_printcap(void)
+{
+ FILE *fp; /* printcap file */
+ printer_t *p; /* Current printer */
+
+
+ /*
+ * See if we have a printcap file; if not, don't bother writing it.
+ */
+
+ if (!Printcap[0])
+ return;
+
+ /*
+ * Open the printcap file...
+ */
+
+ if ((fp = fopen(Printcap, "w")) == NULL)
+ return;
+
+ /*
+ * Write a new printcap with the current list of printers.
+ */
+
+ switch (PrintcapFormat)
+ {
+ case PRINTCAP_BSD:
+ /*
+ * Each printer is put in the file as:
+ *
+ * Printer1:
+ * Printer2:
+ * Printer3:
+ * ...
+ * PrinterN:
+ */
+
+ for (p = Printers; p != NULL; p = p->next)
+ fprintf(fp, "%s:\n", p->name);
+ break;
+
+ case PRINTCAP_SOLARIS:
+ /*
+ * Each printer is put in the file as:
+ *
+ * _all:all=Printer1,Printer2,Printer3,...,PrinterN
+ * _default:use=DefaultPrinter
+ * Printer1:
+ * Printer2:
+ * Printer3:
+ * ...
+ * PrinterN:
+ */
+
+ fputs("_all:all=", fp);
+ for (p = Printers; p != NULL; p = p->next)
+ fprintf(fp, "%s%c", p->name, p->next ? ',' : '\n');
+
+ if (DefaultPrinter)
+ fprintf(fp, "_default:use=%s\n", DefaultPrinter->name);
+
+ for (p = Printers; p != NULL; p = p->next)
+ fprintf(fp, "%s:\n", p->name);
+ break;
+ }
+
+ /*
+ * Close the file...
+ */
+
+ fclose(fp);
+}
+
+
+#ifdef __sgi
+/*
+ * 'write_irix_config()' - Update the config files used by the IRIX
+ * desktop tools.
+ */
+
+static void
+write_irix_config(printer_t *p) /* I - Printer to update */
+{
+ char filename[1024]; /* Interface script filename */
+ FILE *fp; /* Interface script file */
+ ipp_attribute_t *attr; /* Attribute value */
+
+
+ /*
+ * Add dummy interface and GUI scripts to fool SGI's "challenged" printing
+ * tools. First the interface script that tells the tools what kind of
+ * printer we have...
+ */
+
+ snprintf(filename, sizeof(filename), "/var/spool/lp/interface/%s", p->name);
+
+ if (p->type & CUPS_PRINTER_CLASS)
+ unlink(filename);
+ else if ((fp = fopen(filename, "w")) != NULL)
+ {
+ fputs("#!/bin/sh\n", fp);
+
+ if ((attr = ippFindAttribute(p->attrs, "printer-make-and-model",
+ IPP_TAG_TEXT)) != NULL)
+ fprintf(fp, "NAME=\"%s\"\n", attr->values[0].string.text);
+ else if (p->type & CUPS_PRINTER_CLASS)
+ fputs("NAME=\"Printer Class\"\n", fp);
+ else
+ fputs("NAME=\"Remote Destination\"\n", fp);
+
+ if (p->type & CUPS_PRINTER_COLOR)
+ fputs("TYPE=ColorPostScript\n", fp);
+ else
+ fputs("TYPE=MonoPostScript\n", fp);
+
+ fprintf(fp, "HOSTNAME=%s\n", ServerName);
+ fprintf(fp, "HOSTPRINTER=%s\n", p->name);
+
+ fclose(fp);
+
+ chmod(filename, 0755);
+ chown(filename, User, Group);
+ }
+
+ /*
+ * Then the member file that tells which device file the queue is connected
+ * to... Networked printers use "/dev/null" in this file, so that's what
+ * we use (the actual device URI can confuse some apps...)
+ */
+
+ snprintf(filename, sizeof(filename), "/var/spool/lp/member/%s", p->name);
+
+ if (p->type & CUPS_PRINTER_CLASS)
+ unlink(filename);
+ else if ((fp = fopen(filename, "w")) != NULL)
+ {
+ fputs("/dev/null\n", fp);
+
+ fclose(fp);
+
+ chmod(filename, 0644);
+ chown(filename, User, Group);
+ }
+
+ /*
+ * The gui_interface file is a script or program that launches a GUI
+ * option panel for the printer, using options specified on the
+ * command-line in the third argument. The option panel must send
+ * any printing options to stdout on a single line when the user
+ * accepts them, or nothing if the user cancels the dialog.
+ *
+ * The default options panel program is /usr/bin/glpoptions, from
+ * the ESP Print Pro software. You can select another using the
+ * PrintcapGUI option.
+ */
+
+ snprintf(filename, sizeof(filename), "/var/spool/lp/gui_interface/ELF/%s.gui", p->name);
+
+ if (p->type & CUPS_PRINTER_CLASS)
+ unlink(filename);
+ else if ((fp = fopen(filename, "w")) != NULL)
+ {
+ fputs("#!/bin/sh\n", fp);
+ fprintf(fp, "%s -d %s -o \"$3\"\n", PrintcapGUI, p->name);
+
+ fclose(fp);
+
+ chmod(filename, 0755);
+ chown(filename, User, Group);
+ }
+
+ /*
+ * The POD config file is needed by the printstatus command to show
+ * the printer location and device.
+ */
+
+ snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.config", p->name);
+
+ if (p->type & CUPS_PRINTER_CLASS)
+ unlink(filename);
+ else if ((fp = fopen(filename, "w")) != NULL)
+ {
+ fprintf(fp, "Printer Class | %s\n",
+ (p->type & CUPS_PRINTER_COLOR) ? "ColorPostScript" : "MonoPostScript");
+ fprintf(fp, "Printer Model | %s\n", p->make_model);
+ fprintf(fp, "Location Code | %s\n", p->location);
+ fprintf(fp, "Physical Location | %s\n", p->info);
+ fprintf(fp, "Port Path | %s\n", p->device_uri);
+ fprintf(fp, "Config Path | /var/spool/lp/pod/%s.config\n", p->name);
+ fprintf(fp, "Active Status Path | /var/spool/lp/pod/%s.status\n", p->name);
+ fputs("Status Update Wait | 10 seconds\n", fp);
+
+ fclose(fp);
+
+ chmod(filename, 0664);
+ chown(filename, User, Group);
+ }
+}
+
+
+/*
+ * 'write_irix_state()' - Update the status files used by IRIX printing
+ * desktop tools.
+ */
+
+static void
+write_irix_state(printer_t *p) /* I - Printer to update */
+{
+ char filename[1024]; /* Interface script filename */
+ FILE *fp; /* Interface script file */
+ int tag; /* Status tag value */
+
+
+ if (p)
+ {
+ /*
+ * The POD status file is needed for the printstatus window to
+ * provide the current status of the printer.
+ */
+
+ snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.status", p->name);
+
+ if (p->type & CUPS_PRINTER_CLASS)
+ unlink(filename);
+ else if ((fp = fopen(filename, "w")) != NULL)
+ {
+ fprintf(fp, "Operational Status | %s\n",
+ (p->state == IPP_PRINTER_IDLE) ? "Idle" :
+ (p->state == IPP_PRINTER_PROCESSING) ? "Busy" :
+ "Faulted");
+ fprintf(fp, "Information | 01 00 00 | %s\n", CUPS_SVERSION);
+ fprintf(fp, "Information | 02 00 00 | Device URI: %s\n", p->device_uri);
+ fprintf(fp, "Information | 03 00 00 | %s jobs\n",
+ p->accepting ? "Accepting" : "Not accepting");
+ fprintf(fp, "Information | 04 00 00 | %s\n", p->state_message);
+
+ fclose(fp);
+
+ chmod(filename, 0664);
+ chown(filename, User, Group);
+ }
+
+ /*
+ * The activeicons file is needed to provide desktop icons for printers:
+ *
+ * [ quoted from /usr/lib/print/tagit ]
+ *
+ * --- Type of printer tags (base values)
+ *
+ * Dumb=66048 # 0x10200
+ * DumbColor=66080 # 0x10220
+ * Raster=66112 # 0x10240
+ * ColorRaster=66144 # 0x10260
+ * Plotter=66176 # 0x10280
+ * PostScript=66208 # 0x102A0
+ * ColorPostScript=66240 # 0x102C0
+ * MonoPostScript=66272 # 0x102E0
+ *
+ * --- Printer state modifiers for local printers
+ *
+ * Idle=0 # 0x0
+ * Busy=1 # 0x1
+ * Faulted=2 # 0x2
+ * Unknown=3 # 0x3 (Faulted due to unknown reason)
+ *
+ * --- Printer state modifiers for network printers
+ *
+ * NetIdle=8 # 0x8
+ * NetBusy=9 # 0x9
+ * NetFaulted=10 # 0xA
+ * NetUnknown=11 # 0xB (Faulted due to unknown reason)
+ */
+
+ snprintf(filename, sizeof(filename), "/var/spool/lp/activeicons/%s", p->name);
+
+ if (p->type & CUPS_PRINTER_CLASS)
+ unlink(filename);
+ else if ((fp = fopen(filename, "w")) != NULL)
+ {
+ if (p->type & CUPS_PRINTER_COLOR)
+ tag = 66240;
+ else
+ tag = 66272;
+
+ if (p->type & CUPS_PRINTER_REMOTE)
+ tag |= 8;
+
+ if (p->state == IPP_PRINTER_PROCESSING)
+ tag |= 1;
+
+ else if (p->state == IPP_PRINTER_STOPPED)
+ tag |= 2;
+
+ fputs("#!/bin/sh\n", fp);
+ fprintf(fp, "#Tag %d\n", tag);
+
+ fclose(fp);
+
+ chmod(filename, 0755);
+ chown(filename, User, Group);
+ }
+ }
+
+ /*
+ * The default file is needed by the printers window to show
+ * the default printer.
+ */
+
+ snprintf(filename, sizeof(filename), "/var/spool/lp/default");
+
+ if (DefaultPrinter != NULL)
+ {
+ if ((fp = fopen(filename, "w")) != NULL)
+ {
+ fprintf(fp, "%s\n", DefaultPrinter->name);
+
+ fclose(fp);
+
+ chmod(filename, 0644);
+ chown(filename, User, Group);
+ }
+ }
+ else
+ unlink(filename);
+}
+#endif /* __sgi */
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/printers.h b/scheduler/printers.h
new file mode 100644
index 000000000..addfb2b17
--- /dev/null
+++ b/scheduler/printers.h
@@ -0,0 +1,117 @@
+/*
+ * "$Id$"
+ *
+ * Printer definitions for the Common UNIX Printing System (CUPS) scheduler.
+ *
+ * Copyright 1997-2002 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
+ */
+
+/*
+ * Quota data...
+ */
+
+typedef struct
+{
+ char username[33]; /* User data */
+ time_t next_update; /* Next update time */
+ int page_count, /* Count of pages */
+ k_count; /* Count of kilobytes */
+} quota_t;
+
+
+/*
+ * Printer/class information structure...
+ */
+
+typedef struct printer_str
+{
+ struct printer_str *next; /* Next printer in list */
+ char uri[HTTP_MAX_URI], /* Printer URI */
+ hostname[HTTP_MAX_HOST],/* Host printer resides on */
+ name[IPP_MAX_NAME], /* Printer name */
+ location[IPP_MAX_NAME], /* Location code */
+ make_model[IPP_MAX_NAME],/* Make and model */
+ info[IPP_MAX_NAME]; /* Description */
+ int accepting; /* Accepting jobs? */
+ ipp_pstate_t state; /* Printer state */
+ char state_message[1024]; /* Printer state message */
+ time_t state_time; /* Time at this state */
+ char job_sheets[2][IPP_MAX_NAME];
+ /* Banners/job sheets */
+ cups_ptype_t type; /* Printer type (color, small, etc.) */
+ time_t browse_time; /* Last time update was sent/received */
+ char device_uri[HTTP_MAX_URI],/* Device URI */
+ backend[1024]; /* Backend to use */
+ mime_type_t *filetype; /* Pseudo-filetype for printer */
+ void *job; /* Current job in queue */
+ ipp_t *attrs; /* Attributes supported by this printer */
+ int num_printers, /* Number of printers in class */
+ last_printer; /* Last printer job was sent to */
+ struct printer_str **printers; /* Printers in class */
+ int quota_period, /* Period for quotas */
+ page_limit, /* Maximum number of pages */
+ k_limit, /* Maximum number of kilobytes */
+ num_quotas; /* Number of quota records */
+ quota_t *quotas; /* Quota records */
+ int deny_users, /* 1 = deny, 0 = allow */
+ num_users; /* Number of allowed/denied users */
+ const char **users; /* Allowed/denied users */
+} printer_t;
+
+
+/*
+ * Globals...
+ */
+
+VAR printer_t *Printers VALUE(NULL); /* Printer list */
+VAR printer_t *DefaultPrinter VALUE(NULL);
+ /* Default printer */
+
+/*
+ * Prototypes...
+ */
+
+extern printer_t *AddPrinter(const char *name);
+extern void AddPrinterFilter(printer_t *p, const char *filter);
+extern void AddPrinterUser(printer_t *p, const char *username);
+extern quota_t *AddQuota(printer_t *p, const char *username);
+extern void DeleteAllPrinters(void);
+extern void DeletePrinter(printer_t *p);
+extern void DeletePrinterFilters(printer_t *p);
+extern printer_t *FindPrinter(const char *name);
+extern quota_t *FindQuota(printer_t *p, const char *username);
+extern void FreePrinterUsers(printer_t *p);
+extern void FreeQuotas(printer_t *p);
+extern void LoadAllPrinters(void);
+extern void SaveAllPrinters(void);
+extern void SetPrinterAttrs(printer_t *p);
+extern void SetPrinterState(printer_t *p, ipp_pstate_t s);
+extern void SortPrinters(void);
+#define StartPrinter(p) SetPrinterState((p), IPP_PRINTER_IDLE)
+extern void StopPrinter(printer_t *p);
+extern quota_t *UpdateQuota(printer_t *p, const char *username,
+ int pages, int k);
+extern const char *ValidateDest(const char *hostname,
+ const char *resource,
+ cups_ptype_t *dtype);
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/quotas.c b/scheduler/quotas.c
new file mode 100644
index 000000000..b24bc2da9
--- /dev/null
+++ b/scheduler/quotas.c
@@ -0,0 +1,236 @@
+/*
+ * "$Id$"
+ *
+ * Quota routines for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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:
+ *
+ * AddQuota() - Add a quota record for this printer and user.
+ * FindQuota() - Find a quota record.
+ * FreeQuotas() - Free quotas for a printer.
+ * UpdateQuota() - Update quota data for the specified printer and user.
+ * compare() - Compare two quota records...
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cupsd.h"
+
+
+/*
+ * Local functions...
+ */
+
+static int compare(const quota_t *q1, const quota_t *q2);
+
+
+/*
+ * 'AddQuota()' - Add a quota record for this printer and user.
+ */
+
+quota_t * /* O - Quota data */
+AddQuota(printer_t *p, /* I - Printer */
+ const char *username) /* I - User */
+{
+ quota_t *q; /* New quota data */
+
+
+ if (!p || !username)
+ return (NULL);
+
+ if (p->num_quotas == 0)
+ q = malloc(sizeof(quota_t));
+ else
+ q = realloc(p->quotas, sizeof(quota_t) * (p->num_quotas + 1));
+
+ if (!q)
+ return (NULL);
+
+ p->quotas = q;
+ q += p->num_quotas;
+ p->num_quotas ++;
+
+ memset(q, 0, sizeof(quota_t));
+ strncpy(q->username, username, sizeof(q->username) - 1);
+
+ if (p->num_quotas > 1)
+ qsort(p->quotas, p->num_quotas, sizeof(quota_t),
+ (int (*)(const void *, const void *))compare);
+
+ return (FindQuota(p, username));
+}
+
+
+/*
+ * 'FindQuota()' - Find a quota record.
+ */
+
+quota_t * /* O - Quota data */
+FindQuota(printer_t *p, /* I - Printer */
+ const char *username) /* I - User */
+{
+ quota_t *q, /* Quota data pointer */
+ match; /* Search data */
+
+
+ if (!p || !username)
+ return (NULL);
+
+ if (p->num_quotas == 0)
+ q = NULL;
+ else
+ {
+ strncpy(match.username, username, sizeof(match.username) - 1);
+ match.username[sizeof(match.username) - 1] = '\0';
+
+ q = bsearch(&match, p->quotas, p->num_quotas, sizeof(quota_t),
+ (int(*)(const void *, const void *))compare);
+ }
+
+ if (q)
+ return (q);
+ else
+ return (AddQuota(p, username));
+}
+
+
+/*
+ * 'FreeQuotas()' - Free quotas for a printer.
+ */
+
+void
+FreeQuotas(printer_t *p) /* I - Printer */
+{
+ if (!p)
+ return;
+
+ if (p->num_quotas)
+ free(p->quotas);
+
+ p->num_quotas = 0;
+ p->quotas = NULL;
+}
+
+
+/*
+ * 'UpdateQuota()' - Update quota data for the specified printer and user.
+ */
+
+quota_t * /* O - Quota data */
+UpdateQuota(printer_t *p, /* I - Printer */
+ const char *username, /* I - User */
+ int pages, /* I - Number of pages */
+ int k) /* I - Number of kilobytes */
+{
+ quota_t *q; /* Quota data */
+ job_t *job, /* Current job */
+ *next; /* Next job */
+ time_t curtime; /* Current time */
+ ipp_attribute_t *attr; /* Job attribute */
+
+
+ if (!p || !username)
+ return (NULL);
+
+ if (!p->k_limit && !p->page_limit)
+ return (NULL);
+
+ if ((q = FindQuota(p, username)) == NULL)
+ return (NULL);
+
+ curtime = time(NULL);
+
+ if (curtime < q->next_update)
+ {
+ q->page_count += pages;
+ q->k_count += k;
+
+ return (q);
+ }
+
+ if (p->quota_period)
+ curtime -= p->quota_period;
+ else
+ curtime = 0;
+
+ q->next_update = 0;
+ q->page_count = 0;
+ q->k_count = 0;
+
+ for (job = Jobs; job; job = next)
+ {
+ next = job->next;
+
+ if (strcasecmp(job->dest, p->name) != 0 ||
+ strcasecmp(job->username, q->username) != 0)
+ continue;
+
+ if ((attr = ippFindAttribute(job->attrs, "time-at-completion",
+ IPP_TAG_INTEGER)) == NULL)
+ if ((attr = ippFindAttribute(job->attrs, "time-at-processing",
+ IPP_TAG_INTEGER)) == NULL)
+ attr = ippFindAttribute(job->attrs, "time-at-creation",
+ IPP_TAG_INTEGER);
+
+ if (attr == NULL)
+ break;
+
+ if (attr->values[0].integer < curtime)
+ {
+ if (JobAutoPurge)
+ CancelJob(job->id, 1);
+
+ continue;
+ }
+
+ if (q->next_update == 0)
+ q->next_update = attr->values[0].integer + p->quota_period;
+
+ if ((attr = ippFindAttribute(job->attrs, "job-media-sheets-completed",
+ IPP_TAG_INTEGER)) != NULL)
+ q->page_count += attr->values[0].integer;
+
+ if ((attr = ippFindAttribute(job->attrs, "job-k-octets",
+ IPP_TAG_INTEGER)) != NULL)
+ q->k_count += attr->values[0].integer;
+ }
+
+ return (q);
+}
+
+
+/*
+ * 'compare()' - Compare two quota records...
+ */
+
+static int /* O - Result of comparison */
+compare(const quota_t *q1, /* I - First quota record */
+ const quota_t *q2) /* I - Second quota record */
+{
+ return (strcasecmp(q1->username, q2->username));
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/server.c b/scheduler/server.c
new file mode 100644
index 000000000..524e807b7
--- /dev/null
+++ b/scheduler/server.c
@@ -0,0 +1,162 @@
+/*
+ * "$Id$"
+ *
+ * Server start/stop routines for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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:
+ *
+ * StartServer() - Start the server.
+ * StopServer() - Stop the server.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cupsd.h"
+
+#include <grp.h>
+
+#ifdef HAVE_LIBSSL
+# include <openssl/ssl.h>
+# include <openssl/rand.h>
+#endif /* HAVE_LIBSSL */
+
+
+/*
+ * 'StartServer()' - Start the server.
+ */
+
+void
+StartServer(void)
+{
+#ifdef HAVE_LIBSSL
+ int i; /* Looping var */
+ struct timeval curtime; /* Current time in microseconds */
+ unsigned char data[1024]; /* Seed data */
+#endif /* HAVE_LIBSSL */
+
+
+#ifdef HAVE_LIBSSL
+ /*
+ * Initialize the encryption libraries...
+ */
+
+ SSL_library_init();
+ SSL_load_error_strings();
+
+ /*
+ * Using the current time is a dubious random seed, but on some systems
+ * it is the best we can do (on others, this seed isn't even used...)
+ */
+
+ gettimeofday(&curtime, NULL);
+ srand(curtime.tv_sec + curtime.tv_usec);
+
+ for (i = 0; i < sizeof(data); i ++)
+ data[i] = rand(); /* Yes, this is a poor source of random data... */
+
+ RAND_seed(&data, sizeof(data));
+#endif /* HAVE_LIBSSL */
+
+ /*
+ * Startup all the networking stuff...
+ */
+
+ StartListening();
+ StartBrowsing();
+ StartPolling();
+
+ /*
+ * If the administrator has configured the server to run as an unpriviledged
+ * user, change to that user now...
+ */
+
+ if (RunAsUser)
+ {
+ setgid(Group);
+ setgroups(0, NULL);
+ setuid(User);
+ }
+}
+
+
+/*
+ * 'StopServer()' - Stop the server.
+ */
+
+void
+StopServer(void)
+{
+ /*
+ * Close all network clients and stop all jobs...
+ */
+
+ CloseAllClients();
+ StopListening();
+ StopPolling();
+ StopBrowsing();
+
+ if (Clients != NULL)
+ {
+ free(Clients);
+ Clients = NULL;
+ }
+
+ StopAllJobs();
+
+ /*
+ * Close all log files...
+ */
+
+ if (AccessFile != NULL)
+ {
+ fclose(AccessFile);
+
+ AccessFile = NULL;
+ }
+
+ if (ErrorFile != NULL)
+ {
+ fclose(ErrorFile);
+
+ ErrorFile = NULL;
+ }
+
+ if (PageFile != NULL)
+ {
+ fclose(PageFile);
+
+ PageFile = NULL;
+ }
+
+ /*
+ * Clear the input and output sets...
+ */
+
+ FD_ZERO(&InputSet);
+ FD_ZERO(&OutputSet);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/testmime.c b/scheduler/testmime.c
new file mode 100644
index 000000000..81c07c798
--- /dev/null
+++ b/scheduler/testmime.c
@@ -0,0 +1,228 @@
+/*
+ * "$Id$"
+ *
+ * MIME test program for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Easy Software Products and are protected by Federal
+ * copyright law. Distribution and use rights are outlined in the file
+ * "LICENSE.txt" which should have been included with this file. If this
+ * file is missing or damaged please contact Easy Software Products
+ * at:
+ *
+ * Attn: CUPS Licensing Information
+ * Easy Software Products
+ * 44141 Airport View Drive, Suite 204
+ * Hollywood, Maryland 20636-3111 USA
+ *
+ * Voice: (301) 373-9603
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * Contents:
+ *
+ * main() - Main entry for the test program.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "mime.h"
+
+
+/*
+ * Local functions...
+ */
+
+static void print_rules(mime_magic_t *rules);
+
+
+/*
+ * 'main()' - Main entry for the test program.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line args */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i; /* Looping var */
+ char super[MIME_MAX_SUPER], /* Super-type name */
+ type[MIME_MAX_TYPE]; /* Type name */
+ mime_t *mime; /* MIME database */
+ mime_type_t *src, /* Source type */
+ *dst, /* Destination type */
+ **types; /* File type array pointer */
+ mime_filter_t *filters; /* Filters for the file */
+ int num_filters; /* Number of filters for the file */
+
+
+ mime = mimeLoad("../conf");
+
+ puts("MIME database types:");
+ for (i = 0, types = mime->types; i < mime->num_types; i ++, types ++)
+ {
+ printf("\t%s/%s:\n", (*types)->super, (*types)->type);
+ print_rules((*types)->rules);
+ puts("");
+ }
+
+ puts("");
+
+ puts("MIME database filters:");
+ for (i = 0, filters = mime->filters; i < mime->num_filters; i ++, filters ++)
+ printf("\t%s/%s to %s/%s: %s (%d)\n",
+ filters->src->super, filters->src->type,
+ filters->dst->super, filters->dst->type,
+ filters->filter, filters->cost);
+
+ puts("");
+
+ switch (argc)
+ {
+ default :
+ fputs("Usage: testmime source-file [destination-type]\n", stderr);
+ mimeDelete(mime);
+ return (1);
+
+ case 2 :
+ src = mimeFileType(mime, argv[1]);
+
+ if (src != NULL)
+ {
+ printf("%s: %s/%s\n", argv[1], src->super, src->type);
+ mimeDelete(mime);
+ return (0);
+ }
+ else
+ {
+ printf("%s: unknown\n", argv[1]);
+ mimeDelete(mime);
+ return (1);
+ }
+
+ case 3 :
+ src = mimeFileType(mime, argv[1]);
+
+ sscanf(argv[2], "%15[^/]/%31s", super, type);
+ dst = mimeType(mime, super, type);
+
+ filters = mimeFilter(mime, src, dst, &num_filters);
+
+ if (filters == NULL)
+ {
+ printf("No filters to convert from %s to %s.\n", argv[1], argv[2]);
+ mimeDelete(mime);
+ return (1);
+ }
+ else
+ {
+ for (i = 0; i < num_filters; i ++)
+ if (i < (num_filters - 1))
+ printf("%s | ", filters[i].filter);
+ else
+ puts(filters[i].filter);
+
+ mimeDelete(mime);
+ return (0);
+ }
+ }
+}
+
+
+/*
+ * 'print_rules()' - Print the rules for a file type...
+ */
+
+static void
+print_rules(mime_magic_t *rules) /* I - Rules to print */
+{
+ int i; /* Looping var */
+ static char indent[255] = "\t"; /* Indentation for rules */
+
+
+ if (rules == NULL)
+ return;
+
+ while (rules != NULL)
+ {
+ printf("%s[%p] ", indent, rules);
+
+ if (rules->invert)
+ printf("NOT ");
+
+ switch (rules->op)
+ {
+ case MIME_MAGIC_MATCH :
+ printf("match(%s)", rules->value.matchv);
+ break;
+ case MIME_MAGIC_LOCALE :
+ printf("locale(%s)", rules->value.localev);
+ break;
+ case MIME_MAGIC_ASCII :
+ printf("ascii(%d,%d)", rules->offset, rules->length);
+ break;
+ case MIME_MAGIC_PRINTABLE :
+ printf("printable(%d,%d)", rules->offset, rules->length);
+ break;
+ case MIME_MAGIC_STRING :
+ printf("string(%d,", rules->offset);
+ for (i = 0; i < rules->length; i ++)
+ if (rules->value.stringv[i] < ' ' ||
+ rules->value.stringv[i] > 126)
+ printf("<%02X>", rules->value.stringv[i]);
+ else
+ putchar(rules->value.stringv[i]);
+ putchar(')');
+ break;
+ case MIME_MAGIC_CHAR :
+ printf("char(%d,%d)", rules->offset, rules->value.charv);
+ break;
+ case MIME_MAGIC_SHORT :
+ printf("short(%d,%d)", rules->offset, rules->value.shortv);
+ break;
+ case MIME_MAGIC_INT :
+ printf("int(%d,%d)", rules->offset, rules->value.intv);
+ break;
+ case MIME_MAGIC_CONTAINS :
+ printf("contains(%d,%d,", rules->offset, rules->region);
+ for (i = 0; i < rules->length; i ++)
+ if (rules->value.stringv[i] < ' ' ||
+ rules->value.stringv[i] > 126)
+ printf("<%02X>", rules->value.stringv[i]);
+ else
+ putchar(rules->value.stringv[i]);
+ putchar(')');
+ break;
+ default :
+ break;
+ }
+
+ if (rules->child != NULL)
+ {
+ if (rules->op == MIME_MAGIC_OR)
+ puts("OR (");
+ else
+ puts("AND (");
+
+ strcat(indent, "\t");
+ print_rules(rules->child);
+ indent[strlen(indent) - 1] = '\0';
+ printf("%s)\n", indent);
+ }
+ else
+ putchar('\n');
+
+ rules = rules->next;
+ }
+}
+
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/testspeed.c b/scheduler/testspeed.c
new file mode 100644
index 000000000..671f18148
--- /dev/null
+++ b/scheduler/testspeed.c
@@ -0,0 +1,126 @@
+/*
+ * "$Id$"
+ *
+ * Scheduler speed test for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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 <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <sys/time.h>
+#include <cups/cups.h>
+#include <cups/language.h>
+#include <cups/debug.h>
+
+
+/*
+ * 'main()' - Send multiple IPP requests and report on the average response
+ * time.
+ */
+
+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 */
+ ipp_t *request, /* IPP Request */
+ *response; /* IPP Response */
+ cups_lang_t *language; /* Default language */
+ struct timeval start, /* Start time */
+ end; /* End time */
+ double elapsed; /* Elapsed time */
+
+
+ if (argc > 1)
+ http = httpConnect(argv[1], ippPort());
+ else
+ http = httpConnect("localhost", ippPort());
+
+ if (http == NULL)
+ {
+ perror("testspeed: unable to connect to server");
+ return (1);
+ }
+
+ language = cupsLangDefault();
+
+ /*
+ * Do requests 100 times...
+ */
+
+ printf("Testing: ");
+
+ for (elapsed = 0.0, i = 0; i < 100; i ++)
+ {
+ putchar('>');
+ fflush(stdout);
+
+ /*
+ * Build a CUPS_GET_PRINTERS request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ */
+
+ request = ippNew();
+
+ request->request.op.operation_id = CUPS_GET_PRINTERS;
+ request->request.op.request_id = 1;
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, cupsLangEncoding(language));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ gettimeofday(&start, NULL);
+ response = cupsDoRequest(http, request, "/printers/");
+ gettimeofday(&end, NULL);
+
+ putchar('<');
+
+ if (response != NULL)
+ ippDelete(response);
+
+ elapsed += (end.tv_sec - start.tv_sec) +
+ 0.000001 * (end.tv_usec - start.tv_usec);
+ }
+
+ puts("");
+ printf("Total elapsed time for %d requests was %.1fs (%.3fs/r)\n",
+ i, elapsed, elapsed / i);
+
+ return (0);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/type.c b/scheduler/type.c
new file mode 100644
index 000000000..1c93112a6
--- /dev/null
+++ b/scheduler/type.c
@@ -0,0 +1,1090 @@
+/*
+ * "$Id$"
+ *
+ * MIME typing routines for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Easy Software Products and are protected by Federal
+ * copyright law. Distribution and use rights are outlined in the file
+ * "LICENSE.txt" which should have been included with this file. If this
+ * file is missing or damaged please contact Easy Software Products
+ * at:
+ *
+ * Attn: CUPS Licensing Information
+ * Easy Software Products
+ * 44141 Airport View Drive, Suite 204
+ * Hollywood, Maryland 20636-3111 USA
+ *
+ * Voice: (301) 373-9603
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * Contents:
+ *
+ * mimeAddType() - Add a MIME type to a database.
+ * mimeAddRule() - Add a detection rule for a file type.
+ * mimeFileType() - Determine the type of a file.
+ * mimeType() - Lookup a file type.
+ * compare() - Compare two MIME super/type names.
+ * checkrules() - Check each rule in a list.
+ * patmatch() - Pattern matching...
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <locale.h>
+
+#include <cups/string.h>
+#include "mime.h"
+#include <cups/debug.h>
+
+
+/*
+ * Local functions...
+ */
+
+static int compare(mime_type_t **, mime_type_t **);
+static int checkrules(const char *, FILE *, mime_magic_t *);
+static int patmatch(const char *, const char *);
+
+
+/*
+ * 'mimeAddType()' - Add a MIME type to a database.
+ */
+
+mime_type_t * /* O - New (or existing) MIME type */
+mimeAddType(mime_t *mime, /* I - MIME database */
+ const char *super, /* I - Super-type name */
+ const char *type) /* I - Type name */
+{
+ mime_type_t *temp, /* New MIME type */
+ **types; /* New MIME types array */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (mime == NULL || super == NULL || type == NULL)
+ return (NULL);
+
+ if (strlen(super) > (MIME_MAX_SUPER - 1) ||
+ strlen(type) > (MIME_MAX_TYPE - 1))
+ return (NULL);
+
+ /*
+ * See if the type already exists; if so, return the existing type...
+ */
+
+ if ((temp = mimeType(mime, super, type)) != NULL)
+ return (temp);
+
+ /*
+ * The type doesn't exist; add it...
+ */
+
+ if ((temp = calloc(1, sizeof(mime_type_t))) == NULL)
+ return (NULL);
+
+ if (mime->num_types == 0)
+ types = (mime_type_t **)malloc(sizeof(mime_type_t *));
+ else
+ types = (mime_type_t **)realloc(mime->types, sizeof(mime_type_t *) * (mime->num_types + 1));
+
+ if (types == NULL)
+ {
+ free(temp);
+ return (NULL);
+ }
+
+ mime->types = types;
+ types += mime->num_types;
+ mime->num_types ++;
+
+ *types = temp;
+ strncpy(temp->super, super, sizeof(temp->super) - 1);
+ strncpy(temp->type, type, sizeof(temp->type) - 1);
+
+ if (mime->num_types > 1)
+ qsort(mime->types, mime->num_types, sizeof(mime_type_t *),
+ (int (*)(const void *, const void *))compare);
+
+ return (temp);
+}
+
+
+/*
+ * 'mimeAddRule()' - Add a detection rule for a file type.
+ */
+
+int /* O - 0 on success, -1 on failure */
+mimeAddTypeRule(mime_type_t *mt, /* I - Type to add to */
+ const char *rule) /* I - Rule to add */
+{
+ int num_values, /* Number of values seen */
+ op, /* Operation code */
+ logic, /* Logic for next rule */
+ invert; /* Invert following rule? */
+ char name[255], /* Name in rule string */
+ value[3][255], /* Value in rule string */
+ *ptr, /* Position in name or value */
+ quote; /* Quote character */
+ int length[3]; /* Length of each parameter */
+ mime_magic_t *temp, /* New rule */
+ *current; /* Current rule */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (mt == NULL || rule == NULL)
+ return (-1);
+
+ /*
+ * Find the last rule in the top-level of the rules tree.
+ */
+
+ for (current = mt->rules; current != NULL; current = current->next)
+ if (current->next == NULL)
+ break;
+
+ /*
+ * Parse the rules string. Most rules are either a file extension or a
+ * comparison function:
+ *
+ * extension
+ * function(parameters)
+ */
+
+ logic = MIME_MAGIC_NOP;
+ invert = 0;
+
+ DEBUG_printf(("%s/%s: %s\n", mt->super, mt->type, rule));
+
+ while (*rule != '\0')
+ {
+ while (isspace(*rule))
+ rule ++;
+
+ if (*rule == '(')
+ {
+ DEBUG_puts("new parenthesis group");
+ logic = MIME_MAGIC_NOP;
+ rule ++;
+ }
+ else if (*rule == ')')
+ {
+ DEBUG_puts("close paren...");
+ if (current == NULL || current->parent == NULL)
+ return (-1);
+
+ current = current->parent;
+
+ if (current->parent == NULL)
+ logic = MIME_MAGIC_OR;
+ else
+ logic = current->parent->op;
+
+ rule ++;
+ }
+ else if (*rule == '+' && current != NULL)
+ {
+ if (logic != MIME_MAGIC_AND &&
+ current != NULL && current->prev != NULL && current->prev->prev != NULL)
+ {
+ /*
+ * OK, we have more than 1 rule in the current tree level... Make a
+ * new group tree and move the previous rule to it...
+ */
+
+ if ((temp = calloc(1, sizeof(mime_magic_t))) == NULL)
+ return (-1);
+
+ temp->op = MIME_MAGIC_AND;
+ temp->child = current;
+ temp->parent = current->parent;
+ current->prev->next = temp;
+ temp->prev = current->prev;
+
+ current->prev = NULL;
+ current->parent = temp;
+
+ DEBUG_printf(("creating new AND group %p...\n", temp));
+ }
+ else
+ {
+ DEBUG_printf(("setting group %p op to AND...\n", current->parent));
+ current->parent->op = MIME_MAGIC_AND;
+ }
+
+ logic = MIME_MAGIC_AND;
+ rule ++;
+ }
+ else if (*rule == ',')
+ {
+ if (logic != MIME_MAGIC_OR && current != NULL)
+ {
+ /*
+ * OK, we have two possibilities; either this is the top-level rule or
+ * we have a bunch of AND rules at this level.
+ */
+
+ if (current->parent == NULL)
+ {
+ /*
+ * This is the top-level rule; we have to move *all* of the AND rules
+ * down a level, as AND has precedence over OR.
+ */
+
+ if ((temp = calloc(1, sizeof(mime_magic_t))) == NULL)
+ return (-1);
+
+ DEBUG_printf(("creating new AND group %p inside OR group\n", temp));
+
+ while (current->prev != NULL)
+ {
+ current->parent = temp;
+ current = current->prev;
+ }
+
+ current->parent = temp;
+ temp->op = MIME_MAGIC_AND;
+ temp->child = current;
+
+ mt->rules = current = temp;
+ }
+ else
+ {
+ /*
+ * This isn't the top rule, so go up one level...
+ */
+
+ DEBUG_puts("going up one level");
+ current = current->parent;
+ }
+ }
+
+ logic = MIME_MAGIC_OR;
+ rule ++;
+ }
+ else if (*rule == '!')
+ {
+ DEBUG_puts("NOT");
+ invert = 1;
+ rule ++;
+ }
+ else if (isalnum(*rule))
+ {
+ /*
+ * Read an extension name or a function...
+ */
+
+ for (ptr = name; isalnum(*rule) && (ptr - name) < (sizeof(name) - 1);)
+ *ptr++ = *rule++;
+
+ *ptr = '\0';
+ num_values = 0;
+
+ if (*rule == '(')
+ {
+ /*
+ * Read function parameters...
+ */
+
+ rule ++;
+ for (num_values = 0;
+ num_values < (sizeof(value) / sizeof(value[0]));
+ num_values ++)
+ {
+ ptr = value[num_values];
+
+ while ((ptr - value[num_values]) < (sizeof(value[0]) - 1) &&
+ *rule != '\0' && *rule != ',' && *rule != ')')
+ {
+ if (isspace(*rule))
+ {
+ /*
+ * Ignore whitespace...
+ */
+
+ rule ++;
+ continue;
+ }
+ else if (*rule == '\"' || *rule == '\'')
+ {
+ /*
+ * Copy quoted strings literally...
+ */
+
+ quote = *rule++;
+
+ while (*rule != '\0' && *rule != quote &&
+ (ptr - value[num_values]) < (sizeof(value[0]) - 1))
+ *ptr++ = *rule++;
+
+ if (*rule == quote)
+ rule ++;
+ else
+ return (-1);
+ }
+ else if (*rule == '<')
+ {
+ rule ++;
+
+ while (*rule != '>' && *rule != '\0' &&
+ (ptr - value[num_values]) < (sizeof(value[0]) - 1))
+ {
+ if (isxdigit(rule[0]) && isxdigit(rule[1]))
+ {
+ if (isdigit(*rule))
+ *ptr = (*rule++ - '0') << 4;
+ else
+ *ptr = (tolower(*rule++) - 'a' + 10) << 4;
+
+ if (isdigit(*rule))
+ *ptr++ |= *rule++ - '0';
+ else
+ *ptr++ |= tolower(*rule++) - 'a' + 10;
+ }
+ else
+ return (-1);
+ }
+
+ if (*rule == '>')
+ rule ++;
+ else
+ return (-1);
+ }
+ else
+ *ptr++ = *rule++;
+ }
+
+ *ptr = '\0';
+ length[num_values] = ptr - value[num_values];
+
+ if (*rule != ',')
+ break;
+
+ rule ++;
+ }
+
+ if (*rule != ')')
+ return (-1);
+
+ rule ++;
+
+ /*
+ * Figure out the function...
+ */
+
+ if (strcmp(name, "match") == 0)
+ op = MIME_MAGIC_MATCH;
+ else if (strcmp(name, "ascii") == 0)
+ op = MIME_MAGIC_ASCII;
+ else if (strcmp(name, "printable") == 0)
+ op = MIME_MAGIC_PRINTABLE;
+ else if (strcmp(name, "string") == 0)
+ op = MIME_MAGIC_STRING;
+ else if (strcmp(name, "char") == 0)
+ op = MIME_MAGIC_CHAR;
+ else if (strcmp(name, "short") == 0)
+ op = MIME_MAGIC_SHORT;
+ else if (strcmp(name, "int") == 0)
+ op = MIME_MAGIC_INT;
+ else if (strcmp(name, "locale") == 0)
+ op = MIME_MAGIC_LOCALE;
+ else if (strcmp(name, "contains") == 0)
+ op = MIME_MAGIC_CONTAINS;
+ else
+ return (-1);
+ }
+ else
+ {
+ /*
+ * This is just a filename match on the extension...
+ */
+
+ snprintf(value[0], sizeof(value[0]), "*.%s", name);
+ length[0] = strlen(value[0]);
+ num_values = 1;
+ op = MIME_MAGIC_MATCH;
+ }
+
+ /*
+ * Add a rule for this operation.
+ */
+
+ if ((temp = calloc(1, sizeof(mime_magic_t))) == NULL)
+ return (-1);
+
+ temp->invert = invert;
+ if (current != NULL)
+ {
+ temp->parent = current->parent;
+ current->next = temp;
+ }
+ else
+ mt->rules = temp;
+
+ temp->prev = current;
+
+ if (logic == MIME_MAGIC_NOP)
+ {
+ /*
+ * Add parenthetical grouping...
+ */
+
+ DEBUG_printf(("making new OR group %p for parenthesis...\n", temp));
+
+ temp->op = MIME_MAGIC_OR;
+
+ if ((temp->child = calloc(1, sizeof(mime_magic_t))) == NULL)
+ return (-1);
+
+ temp->child->parent = temp;
+
+ temp = temp->child;
+ logic = MIME_MAGIC_OR;
+ }
+
+ DEBUG_printf(("adding %p: %s, op = %d, logic = %d, invert = %d\n",
+ temp, name, op, logic, invert));
+
+ /*
+ * Fill in data for the rule...
+ */
+
+ current = temp;
+ temp->op = op;
+ invert = 0;
+
+ switch (op)
+ {
+ case MIME_MAGIC_MATCH :
+ if (length[0] > (sizeof(temp->value.matchv) - 1))
+ return (-1);
+ strcpy(temp->value.matchv, value[0]);
+ break;
+ case MIME_MAGIC_ASCII :
+ case MIME_MAGIC_PRINTABLE :
+ temp->offset = strtol(value[0], NULL, 0);
+ temp->length = strtol(value[1], NULL, 0);
+ if (temp->length > MIME_MAX_BUFFER)
+ temp->length = MIME_MAX_BUFFER;
+ break;
+ case MIME_MAGIC_STRING :
+ temp->offset = strtol(value[0], NULL, 0);
+ if (length[1] > sizeof(temp->value.stringv))
+ return (-1);
+ temp->length = length[1];
+ memcpy(temp->value.stringv, value[1], length[1]);
+ break;
+ case MIME_MAGIC_CHAR :
+ temp->offset = strtol(value[0], NULL, 0);
+ if (length[1] == 1)
+ temp->value.charv = value[1][0];
+ else
+ temp->value.charv = strtol(value[1], NULL, 0);
+ break;
+ case MIME_MAGIC_SHORT :
+ temp->offset = strtol(value[0], NULL, 0);
+ temp->value.shortv = strtol(value[1], NULL, 0);
+ break;
+ case MIME_MAGIC_INT :
+ temp->offset = strtol(value[0], NULL, 0);
+ temp->value.intv = strtol(value[1], NULL, 0);
+ break;
+ case MIME_MAGIC_LOCALE :
+ if (length[0] > (sizeof(temp->value.localev) - 1))
+ return (-1);
+
+ strcpy(temp->value.localev, value[0]);
+ break;
+ case MIME_MAGIC_CONTAINS :
+ temp->offset = strtol(value[0], NULL, 0);
+ temp->region = strtol(value[1], NULL, 0);
+ if (length[2] > sizeof(temp->value.stringv))
+ return (-1);
+ temp->length = length[2];
+ memcpy(temp->value.stringv, value[2], length[2]);
+ break;
+ }
+ }
+ else
+ break;
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'mimeFileType()' - Determine the type of a file.
+ */
+
+mime_type_t * /* O - Type of file */
+mimeFileType(mime_t *mime, /* I - MIME database */
+ const char *pathname) /* I - Name of file to check */
+{
+ int i; /* Looping var */
+ FILE *fp; /* File pointer */
+ mime_type_t **types; /* File types */
+ const char *filename; /* Base filename of file */
+
+
+ /*
+ * Range check input parameters...
+ */
+
+ if (mime == NULL || pathname == NULL)
+ return (NULL);
+
+ /*
+ * Try to open the file...
+ */
+
+ if ((fp = fopen(pathname, "r")) == NULL)
+ return (NULL);
+
+ /*
+ * Figure out the filename (without directory portion)...
+ */
+
+ if ((filename = strrchr(pathname, '/')) != NULL)
+ filename ++;
+ else
+ filename = pathname;
+
+ /*
+ * Then check it against all known types...
+ */
+
+ for (i = mime->num_types, types = mime->types; i > 0; i --, types ++)
+ if (checkrules(filename, fp, (*types)->rules))
+ break;
+
+ /*
+ * Finally, close the file and return a match (if any)...
+ */
+
+ fclose(fp);
+
+ if (i > 0)
+ return (*types);
+ else
+ return (NULL);
+}
+
+
+/*
+ * 'mimeType()' - Lookup a file type.
+ */
+
+mime_type_t * /* O - Matching file type definition */
+mimeType(mime_t *mime, /* I - MIME database */
+ const char *super, /* I - Super-type name */
+ const char *type) /* I - Type name */
+{
+ mime_type_t key, /* MIME type search key*/
+ *keyptr, /* Key pointer... */
+ **match; /* Matching pointer */
+
+ /*
+ * Range check input...
+ */
+
+ if (mime == NULL || super == NULL || type == NULL)
+ return (NULL);
+
+ if (strlen(super) > (MIME_MAX_SUPER - 1) ||
+ strlen(type) > (MIME_MAX_TYPE - 1))
+ return (NULL);
+
+ if (mime->num_types == 0)
+ return (NULL);
+
+ /*
+ * Lookup the type in the array...
+ */
+
+ strncpy(key.super, super, sizeof(key.super) - 1);
+ key.super[sizeof(key.super) - 1] = '\0';
+ strncpy(key.type, type, sizeof(key.type) - 1);
+ key.type[sizeof(key.type) - 1] = '\0';
+
+ keyptr = &key;
+
+ match = (mime_type_t **)bsearch(&keyptr, mime->types, mime->num_types,
+ sizeof(mime_type_t *),
+ (int (*)(const void *, const void *))compare);
+
+ if (match == NULL)
+ return (NULL);
+ else
+ return (*match);
+}
+
+
+/*
+ * 'compare()' - Compare two MIME super/type names.
+ */
+
+static int /* O - Result of comparison */
+compare(mime_type_t **t0, /* I - First type */
+ mime_type_t **t1) /* I - Second type */
+{
+ int i; /* Result of comparison */
+
+
+ if ((i = strcasecmp((*t0)->super, (*t1)->super)) == 0)
+ i = strcasecmp((*t0)->type, (*t1)->type);
+
+ return (i);
+}
+
+
+/*
+ * 'checkrules()' - Check each rule in a list.
+ */
+
+static int /* O - 1 if match, 0 if no match */
+checkrules(const char *filename, /* I - Filename */
+ FILE *fp, /* I - File to check */
+ mime_magic_t *rules) /* I - Rules to check */
+{
+ int n; /* Looping var */
+ int region; /* Region to look at */
+ int logic, /* Logic to apply */
+ result, /* Result of test */
+ intv; /* Integer value */
+ short shortv; /* Short value */
+ unsigned char buffer[MIME_MAX_BUFFER],/* Input buffer */
+ *bufptr; /* Current buffer position */
+ int bufoffset, /* Offset in file for buffer */
+ buflength; /* Length of data in buffer */
+
+
+ if (rules == NULL)
+ return (0);
+
+ if (rules->parent == NULL)
+ logic = MIME_MAGIC_OR;
+ else
+ logic = rules->parent->op;
+
+ bufoffset = -1;
+ buflength = 0;
+ result = 0;
+
+ while (rules != NULL)
+ {
+ /*
+ * Compute the result of this rule...
+ */
+
+ switch (rules->op)
+ {
+ case MIME_MAGIC_MATCH :
+ result = patmatch(filename, rules->value.matchv);
+ break;
+
+ case MIME_MAGIC_ASCII :
+ /*
+ * Load the buffer if necessary...
+ */
+
+ if (bufoffset < 0 || rules->offset < bufoffset ||
+ (rules->offset + rules->length) > (bufoffset + buflength))
+ {
+ /*
+ * Reload file buffer...
+ */
+
+ fseek(fp, rules->offset, SEEK_SET);
+ buflength = fread(buffer, 1, sizeof(buffer), fp);
+ bufoffset = rules->offset;
+ }
+
+ /*
+ * Test for ASCII printable characters plus standard control chars.
+ */
+
+ if ((rules->offset + rules->length) > (bufoffset + buflength))
+ n = bufoffset + buflength - rules->offset;
+ else
+ n = rules->length;
+
+ bufptr = buffer + rules->offset - bufoffset;
+ while (n > 0)
+ if ((*bufptr >= 32 && *bufptr <= 126) ||
+ (*bufptr >= 8 && *bufptr <= 13) ||
+ *bufptr == 26 || *bufptr == 27)
+ {
+ n --;
+ bufptr ++;
+ }
+ else
+ break;
+
+ result = (n == 0);
+ break;
+
+ case MIME_MAGIC_PRINTABLE :
+ /*
+ * Load the buffer if necessary...
+ */
+
+ if (bufoffset < 0 || rules->offset < bufoffset ||
+ (rules->offset + rules->length) > (bufoffset + buflength))
+ {
+ /*
+ * Reload file buffer...
+ */
+
+ fseek(fp, rules->offset, SEEK_SET);
+ buflength = fread(buffer, 1, sizeof(buffer), fp);
+ bufoffset = rules->offset;
+ }
+
+ /*
+ * Test for 8-bit printable characters plus standard control chars.
+ */
+
+ if ((rules->offset + rules->length) > (bufoffset + buflength))
+ n = bufoffset + buflength - rules->offset;
+ else
+ n = rules->length;
+
+ bufptr = buffer + rules->offset - bufoffset;
+
+ while (n > 0)
+ if (*bufptr >= 128 ||
+ (*bufptr >= 32 && *bufptr <= 126) ||
+ (*bufptr >= 8 && *bufptr <= 13) ||
+ *bufptr == 26 || *bufptr == 27)
+ {
+ n --;
+ bufptr ++;
+ }
+ else
+ break;
+
+ result = (n == 0);
+ break;
+
+ case MIME_MAGIC_STRING :
+ /*
+ * Load the buffer if necessary...
+ */
+
+ if (bufoffset < 0 || rules->offset < bufoffset ||
+ (rules->offset + rules->length) > (bufoffset + buflength))
+ {
+ /*
+ * Reload file buffer...
+ */
+
+ fseek(fp, rules->offset, SEEK_SET);
+ buflength = fread(buffer, 1, sizeof(buffer), fp);
+ bufoffset = rules->offset;
+ }
+
+ /*
+ * Compare the buffer against the string. If the file is too
+ * short then don't compare - it can't match...
+ */
+
+ if ((rules->offset + rules->length) > (bufoffset + buflength))
+ result = 0;
+ else
+ result = (memcmp(buffer + rules->offset - bufoffset,
+ rules->value.stringv, rules->length) == 0);
+ break;
+
+ case MIME_MAGIC_CHAR :
+ /*
+ * Load the buffer if necessary...
+ */
+
+ if (bufoffset < 0 || rules->offset < bufoffset)
+ {
+ /*
+ * Reload file buffer...
+ */
+
+ fseek(fp, rules->offset, SEEK_SET);
+ buflength = fread(buffer, 1, sizeof(buffer), fp);
+ bufoffset = rules->offset;
+ }
+
+ /*
+ * Compare the character values; if the file is too short, it
+ * can't match...
+ */
+
+ if (buflength < 1)
+ result = 0;
+ else
+ result = (buffer[rules->offset - bufoffset] == rules->value.charv);
+ break;
+
+ case MIME_MAGIC_SHORT :
+ /*
+ * Load the buffer if necessary...
+ */
+
+ if (bufoffset < 0 || rules->offset < bufoffset ||
+ (rules->offset + 2) > (bufoffset + buflength))
+ {
+ /*
+ * Reload file buffer...
+ */
+
+ fseek(fp, rules->offset, SEEK_SET);
+ buflength = fread(buffer, 1, sizeof(buffer), fp);
+ bufoffset = rules->offset;
+ }
+
+ /*
+ * Compare the short values; if the file is too short, it
+ * can't match...
+ */
+
+ if (buflength < 2)
+ result = 0;
+ else
+ {
+ bufptr = buffer + rules->offset - bufoffset;
+ shortv = (bufptr[0] << 8) | bufptr[1];
+ result = (shortv == rules->value.shortv);
+ }
+ break;
+
+ case MIME_MAGIC_INT :
+ /*
+ * Load the buffer if necessary...
+ */
+
+ if (bufoffset < 0 || rules->offset < bufoffset ||
+ (rules->offset + 4) > (bufoffset + buflength))
+ {
+ /*
+ * Reload file buffer...
+ */
+
+ fseek(fp, rules->offset, SEEK_SET);
+ buflength = fread(buffer, 1, sizeof(buffer), fp);
+ bufoffset = rules->offset;
+ }
+
+ /*
+ * Compare the int values; if the file is too short, it
+ * can't match...
+ */
+
+ if (buflength < 4)
+ result = 0;
+ else
+ {
+ bufptr = buffer + rules->offset - bufoffset;
+ intv = (((((bufptr[0] << 8) | bufptr[1]) << 8) | bufptr[2]) << 8) |
+ bufptr[3];;
+ result = (intv == rules->value.intv);
+ }
+ break;
+
+ case MIME_MAGIC_LOCALE :
+ result = (strcmp(rules->value.localev, setlocale(LC_MESSAGES, NULL)) == 0);
+ break;
+
+ case MIME_MAGIC_CONTAINS :
+ /*
+ * Load the buffer if necessary...
+ */
+
+ if (bufoffset < 0 || rules->offset < bufoffset ||
+ (rules->offset + rules->region) > (bufoffset + buflength))
+ {
+ /*
+ * Reload file buffer...
+ */
+
+ fseek(fp, rules->offset, SEEK_SET);
+ buflength = fread(buffer, 1, sizeof(buffer), fp);
+ bufoffset = rules->offset;
+ }
+
+ /*
+ * Compare the buffer against the string. If the file is too
+ * short then don't compare - it can't match...
+ */
+
+ if ((rules->offset + rules->length) > (bufoffset + buflength))
+ result = 0;
+ else
+ {
+ if (buflength > rules->region)
+ region = rules->region - rules->length;
+ else
+ region = buflength - rules->length;
+
+ for (n = 0; n < region; n ++)
+ if ((result = (memcmp(buffer + rules->offset - bufoffset + n,
+ rules->value.stringv, rules->length) == 0)) != 0)
+ break;
+ }
+ break;
+
+ default :
+ if (rules->child != NULL)
+ result = checkrules(filename, fp, rules->child);
+ else
+ result = 0;
+ break;
+ }
+
+ /*
+ * If the logic is inverted, invert the result...
+ */
+
+ if (rules->invert)
+ result = !result;
+
+ /*
+ * OK, now if the current logic is OR and this result is true, the this
+ * rule set is true. If the current logic is AND and this result is false,
+ * the the rule set is false...
+ */
+
+ DEBUG_printf(("result of test %p is %d\n", rules, result));
+
+ if ((result && logic == MIME_MAGIC_OR) ||
+ (!result && logic == MIME_MAGIC_AND))
+ return (result);
+
+ /*
+ * Otherwise the jury is still out on this one, so move to the next rule.
+ */
+
+ rules = rules->next;
+ }
+
+ return (result);
+}
+
+
+/*
+ * 'patmatch()' - Pattern matching...
+ */
+
+static int /* O - 1 if match, 0 if no match */
+patmatch(const char *s, /* I - String to match against */
+ const char *pat) /* I - Pattern to match against */
+{
+ /*
+ * Range check the input...
+ */
+
+ if (s == NULL || pat == NULL)
+ return (0);
+
+ /*
+ * Loop through the pattern and match strings, and stop if we come to a
+ * point where the strings don't match or we find a complete match.
+ */
+
+ while (*s != '\0' && *pat != '\0')
+ {
+ if (*pat == '*')
+ {
+ /*
+ * Wildcard - 0 or more characters...
+ */
+
+ pat ++;
+ if (*pat == '\0')
+ return (1); /* Last pattern char is *, so everything matches now... */
+
+ /*
+ * Test all remaining combinations until we get to the end of the string.
+ */
+
+ while (*s != '\0')
+ {
+ if (patmatch(s, pat))
+ return (1);
+
+ s ++;
+ }
+ }
+ else if (*pat == '?')
+ {
+ /*
+ * Wildcard - 1 character...
+ */
+
+ pat ++;
+ s ++;
+ continue;
+ }
+ else if (*pat == '[')
+ {
+ /*
+ * Match a character from the input set [chars]...
+ */
+
+ pat ++;
+ while (*pat != ']' && *pat != '\0')
+ if (*s == *pat)
+ break;
+ else
+ pat ++;
+
+ if (*pat == ']' || *pat == '\0')
+ return (0);
+
+ while (*pat != ']' && *pat != '\0')
+ pat ++;
+
+ if (*pat == ']')
+ pat ++;
+
+ continue;
+ }
+ else if (*pat == '\\')
+ {
+ /*
+ * Handle quoted characters...
+ */
+
+ pat ++;
+ }
+
+ /*
+ * Stop if the pattern and string don't match...
+ */
+
+ if (*pat++ != *s++)
+ return (0);
+ }
+
+ /*
+ * Done parsing the pattern and string; return 1 if the last character matches
+ * and 0 otherwise...
+ */
+
+ return (*s == *pat);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/standards/draft-ietf-ipp-collection-04.txt b/standards/draft-ietf-ipp-collection-04.txt
new file mode 100644
index 000000000..1a5905eab
--- /dev/null
+++ b/standards/draft-ietf-ipp-collection-04.txt
@@ -0,0 +1,2262 @@
+
+
+
+
+
+
+INTERNET-DRAFT Roger deBry
+<draft-ietf-ipp-collection-04.txt> Utah Valley State College
+ T. Hastings
+ Xerox Corporation
+ R. Herriot
+ Xerox Corporation
+ K. Ocke
+ Xerox Corporation
+ P. Zehler
+ Xerox Corporation
+ January 24, 2001
+
+
+ Internet Printing Protocol (IPP):
+ The 'collection' attribute syntax
+ Copyright (C) The Internet Society (2001). All Rights Reserved.
+
+
+
+Status of this Memo:
+ This document is an Internet-Draft and is in full conformance with
+ all provisions of Section 10 of [RFC2026]. Internet-Drafts are
+ working documents of the Internet Engineering Task Force (IETF), its
+ areas, and its working groups. Note that other groups may also
+ distribute working documents as Internet-Drafts.
+
+ Internet-Drafts are draft documents valid for a maximum of six months
+ and may be updated, replaced, or obsoleted by other documents at any
+ time. It is inappropriate to use Internet-Drafts as reference
+ material or to cite them other than as "work in progress".
+
+ The list of current Internet-Drafts can be accessed at
+ http://www.ietf.org/ietf/1id-abstracts.txt
+
+ The list of Internet-Draft Shadow Directories can be accessed as
+ http://www.ietf.org/shadow.html.
+
+Abstract
+ This document specifies an OPTIONAL attribute syntax called
+ 'collection' for use with the Internet Printing Protocol/1.0
+ (IPP) [RFC2565, RFC2566], IPP/1.1 [RFC2911, RFC2910], and
+ subsequent versions. A 'collection' is a container holding one or
+ more named values, which are called "member" attributes. A
+ collection allows data to be grouped like a PostScript dictionary
+ or a Java Map. This document also specifies the conformance
+ requirements for a definition document that defines a collection
+ attribute. Finally, this document gives some illustrative
+ example collection attribute definitions that are not intended as
+ actual attribute specifications.
+
+
+deBry, et al. Expires: July 24, 2001 [page 1]
+
+
+INTERNET-DRAFT IPP: The 'collection' attribute syntax Jan 24, 2001
+
+
+ The full set of IPP documents includes:
+
+ Design Goals for an Internet Printing Protocol [RFC2567]
+ Rationale for the Structure and Model and Protocol for the Internet
+ Printing Protocol [RFC2568]
+ Internet Printing Protocol/1.1: Model and Semantics [RFC2911]
+ Internet Printing Protocol/1.1: Encoding and Transport [RFC2910]
+ Internet Printing Protocol/1.1: Implementer's Guide [IPP-IIG]
+ Mapping between LPD and IPP Protocols [RFC2569]
+
+ The "Design Goals for an Internet Printing Protocol" document takes a
+ broad look at distributed printing functionality, and it enumerates
+ real-life scenarios that help to clarify the features that need to be
+ included in a printing protocol for the Internet. It identifies
+ requirements for three types of users: end users, operators, and
+ administrators. It calls out a subset of end user requirements that
+ are satisfied in IPP/1.0. A few OPTIONAL operator operations have
+ been added to IPP/1.1.
+
+ The "Rationale for the Structure and Model and Protocol for the
+ Internet Printing Protocol" document describes IPP from a high level
+ view, defines a roadmap for the various documents that form the suite
+ of IPP specification documents, and gives background and rationale
+ for the IETF working group's major decisions.
+
+ The "Internet Printing Protocol/1.1: Encoding and Transport" document
+ is a formal mapping of the abstract operations and attributes defined
+ in the model document onto HTTP/1.1 [RFC2616]. It defines the
+ encoding rules for a new Internet MIME media type called
+ "application/ipp". This document also defines the rules for
+ transporting over HTTP a message body whose Content-Type is
+ "application/ipp". This document defines a new scheme named 'ipp'
+ for identifying IPP printers and jobs.
+
+ The "Internet Printing Protocol/1.1: Implementer's Guide" document
+ gives insight and advice to implementers of IPP clients and IPP
+ objects. It is intended to help them understand IPP/1.1 and some of
+ the considerations that may assist them in the design of their client
+ and/or IPP object implementations. For example, a typical order of
+ processing requests is given, including error checking. Motivation
+ for some of the specification decisions is also included.
+
+ The "Mapping between LPD and IPP Protocols" document gives some
+ advice to implementers of gateways between IPP and LPD (Line Printer
+ Daemon) implementations.
+
+
+
+
+
+
+
+deBry, et al. Expires: July 24, 2001 [page 2]
+
+
+INTERNET-DRAFT IPP: The 'collection' attribute syntax Jan 24, 2001
+
+
+Table of Contents
+
+
+
+ 1 Introduction....................................................5
+ 1.1 Problem Statement ............................................5
+ 1.2 Solution .....................................................5
+
+ 2 Terminology.....................................................6
+ 2.1 Conformance Terminology ......................................6
+ 2.2 Other terminology ............................................7
+
+ 3 Definition of a Collection Attribute............................7
+ 3.1 Information to Include .......................................7
+ 3.2 Nested Collections ..........................................11
+
+ 4 Collection Attributes as Attributes in Operations..............11
+ 4.1 General Rules ...............................................11
+ 4.2 Unsupported Values ..........................................11
+
+ 5 Example definition of a collection attribute...................12
+ 5.1 media-col (collection) ......................................12
+ 5.1.1media-color (type3 keyword | name(MAX) ......................13
+ 5.1.2media-size (collection) .....................................13
+ 5.2 media-col-default (collection) ..............................14
+ 5.3 media-col-ready (1setOf collection) .........................14
+ 5.4 media-col-supported (1setOf type2 keyword) ..................14
+
+ 6 A Second Example Definition Of A Collection Attribute..........15
+
+ 7 Encoding.......................................................15
+ 7.1 Additional tags defined for representing a collection attribute
+ value16
+ 7.2 Example encoding: "media-col" (collection) ..................17
+
+ 8 Legacy issues..................................................23
+
+ 9 IANA Considerations............................................23
+ 9.1 Attribute Syntax Registration ...............................23
+
+ 10 Internationalization Considerations............................23
+
+ 11 Security Considerations........................................24
+
+ 12 References.....................................................24
+
+ 13 Author's Addresses.............................................25
+
+ 14 Appendix A: Encoding Example of a Simple Collection............26
+
+
+
+deBry, et al. Expires: July 24, 2001 [page 3]
+
+
+INTERNET-DRAFT IPP: The 'collection' attribute syntax Jan 24, 2001
+
+
+ 15 Appendix B: Encoding Example of 1setOf Collection..............29
+
+ 16 Appendix C: Encoding Example of Collection containing 1setOf XXX
+ attribute.........................................................34
+
+ 17 Appendix D: Full Copyright Statement...........................38
+
+
+Table of Tables
+
+ Table 1 - "media-col" member attributes...........................13
+ Table 2 - "media-size" collection member attributes...............13
+ Table 3 - Tags defined for encoding the 'collection' attribute syntax
+ ..............................................................16
+ Table 4 - Overview Encoding of "media-col" collection.............18
+ Table 5 - Example Encoding of "media-col" collection..............18
+ Table 6 - Overview Encoding of simple collection..................26
+ Table 7 - Example Encoding of simple collection...................26
+ Table 8 - Overview Encoding of 1setOf collection..................29
+ Table 9 - Example Encoding of 1setOf collection...................30
+ Table 10 - Overview Encoding of collection with 1setOf value......34
+ Table 11 - Example Encoding of collection with 1setOf value.......35
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+deBry, et al. Expires: July 24, 2001 [page 4]
+
+
+INTERNET-DRAFT IPP: The 'collection' attribute syntax Jan 24, 2001
+
+
+
+
+
+
+1 Introduction
+
+
+1.1 Problem Statement
+
+ The IPP Model and Semantics [RFC2911] supports most of the common
+ data structures that are available in programming languages. It lacks
+ a mechanism for grouping several attributes of different types. The
+ Java language uses the Map to solve this problem and PostScript has a
+ dictionary. The new mechanism for grouping attributes together
+ (called 'collection' mechanism) must allow for optional members and
+ subsequent addition of new members.
+
+ The 'collection' mechanism must be encoded in a manner consistent
+ with existing 1.0 and 1.1 parsing rules (see [RFC2910]). Current 1.0
+ and 1.1 parsers that don't support the 'collection' mechanism must
+ not confuse collections or parts of collection they receive with
+ other attributes.
+
+
+1.2 Solution
+
+ The new mechanism is a new IPP attribute syntax called a
+ 'collection'. As such, each collection value is a value of an
+ attribute whose attribute syntax type is defined to be a
+ 'collection'. Such an attribute is called a collection attribute.
+ The name of the collection attribute serves to identify the
+ collection value in an operation request or response, as with any
+ attribute value.
+
+ The 'collection' attribute syntax is a container holding one or more
+ named values (i.e., attributes), which are called member attributes.
+ Each collection attribute definition document lists the mandatory and
+ optional member attributes of each collection value. A collection
+ value is similar to an IPP attribute group in a request or a
+ response, such as the operation attributes group. They both consist
+ of a set of attributes.
+
+ As with any attribute syntax, the document that defines a collection
+ attribute specifies whether the attribute is single-value
+ (collection) or multi-valued (1setOf collection). If the attribute is
+ multi-valued (1setOf collection) each collection value MUST be a
+ separate instance of a single definition of a collection, i.e. it
+ MUST have the same member attributes except for OPTIONAL member
+ attributes. If we view each collection definition as a separate
+ syntax type, this rule continues the IPP/1.1 notion that each
+
+
+deBry, et al. Expires: July 24, 2001 [page 5]
+
+
+INTERNET-DRAFT IPP: The 'collection' attribute syntax Jan 24, 2001
+
+
+ attribute has a single type or pattern (e.g. "keyword | name" is a
+ pattern). Without this rule, the supported values would be more
+ difficult to describe and the mechanism defined in item 4 of section
+ 3.1 would not be sufficient.
+
+ The name of each member attribute MUST be unique for a collection
+ attribute, but MAY be the same as the name of a member attribute in
+ another collection attribute and/or MAY be the same as the name of an
+ attribute that is not a member of a collection. The rules for naming
+ member attributes are given in section 3.1.
+
+ Each member attribute can have any attribute syntax type, including
+ 'collection', and can be either single-valued or multi-valued. The
+ length of a collection value is not limited. However, the length of
+ each member attribute MUST NOT exceed the limit of its attribute
+ syntax.
+
+ The member attributes in a collection MAY be in any order in a
+ request or response. When a client sends a collection attribute to
+ the Printer, the order that the Printer stores the member attributes
+ of the collection value and the order returned in a response MAY be
+ different from the order sent by the client.
+
+ A collection value MUST NOT contains two or more member attributes
+ with the same attribute name. Such a collection is mal-formed.
+ Clients MUST NOT submit such malformed requests and Printers MUST NOT
+ return such malformed responses. If such a malformed request is
+ submitted to a Printer, the Printer MUST (depending on
+ implementation) either (1) reject the request with the 'client-error-
+ bad-request' status code (see section 13.1.4.1), or (2) accept the
+ request and use only one of each duplicate member attribute.
+
+
+
+2 Terminology
+
+ This section defines terminology used throughout this document.
+
+
+2.1 Conformance Terminology
+
+ Capitalized terms, such as MUST, MUST NOT, REQUIRED, SHOULD, SHOULD
+ NOT, MAY, NEED NOT, and OPTIONAL, have special meaning relating to
+ conformance. These terms are defined in [RFC2911] section 12.1 on
+ conformance terminology, most of which is taken from RFC 2119
+ [RFC2119].
+
+ The following specialization of these terms apply to this document:
+
+
+
+
+deBry, et al. Expires: July 24, 2001 [page 6]
+
+
+INTERNET-DRAFT IPP: The 'collection' attribute syntax Jan 24, 2001
+
+
+ REQUIRED: if an implementation supports the extensions described in
+ this document, it MUST support a REQUIRED feature.
+
+ OPTIONAL: if an implementation supports the extensions described in
+ this document, it MAY support an OPTIONAL feature.
+
+
+2.2 Other terminology
+
+ This document uses terms such as Job object (or Job), IPP Printer
+ object (or Printer), "operation", "request", response", "attributes",
+ "keywords", and "support". These terms have special meaning and are
+ defined in the model terminology [RFC2911] section 12.2. The
+ following additional terms are introduced in this document:
+
+ collection: an attribute syntax in which each attribute value is a
+ set of attributes, called member attributes.
+
+ member attribute: an attribute that is defined to be used as one
+ of the attributes in a collection.
+
+ collection attribute: an attribute whose definition specifies the
+ 'collection' attribute syntax and each of the member attributes
+ that MAY occur in a collection attribute value.
+
+
+
+3 Definition of a Collection Attribute
+
+ This section describes the requirements for any collection attribute
+ definition.
+
+
+3.1 Information to Include
+
+ When a specification document defines an "xxx" collection attribute,
+ i.e., an attribute whose attribute syntax type is 'collection' or
+ '1setOf collection'; the definition document MUST include the
+ following aspects of the attribute semantics. Suppose the "xxx"
+ collection attribute contains N member attributes named "aaa1",
+ "aaa2", _, "aaaN" ("aaaI" represents any one of these N member
+ attributes).
+
+ 1. The name of the collection attribute MUST be specified (e.g.
+ "xxx"). The selection of the name "xxx" MUST follow the same rules
+ for uniqueness as for attributes of any other syntax type (as
+ defined by IPP/1.1) unless "xxx" is a member attribute of another
+ collection. Then the selection of the name "xxx" MUST follow the
+ rules for uniqueness defined in item 5a) of this list.
+
+
+
+deBry, et al. Expires: July 24, 2001 [page 7]
+
+
+INTERNET-DRAFT IPP: The 'collection' attribute syntax Jan 24, 2001
+
+
+ 2. The collection attribute syntax MUST be of type 'collection' or
+ '1setOf collection'.
+
+ 3. The context of the collection attribute MUST be specified, i.e.,
+ whether the attribute is an operation attribute, a Job Template
+ attribute, a Job Description attribute, a Printer Description
+ attribute, a member attribute of a particular collection attribute,
+ etc.
+
+ 4. An "xxx-supported" attribute MUST be specified and it has one of
+ the following two forms:
+
+ a)"xxx-supported" is a "1setOf collection" which enumerates all of
+ the supported collection values of "xxx". If a collection of
+ this form contains a nested collection, it MUST be of the same
+ form.
+
+ For example, "media-size-supported" might have the values {{x-
+ dimension:210, y-dimension:297},{x-dimension:297, y-
+ dimension:420}} to show that it supports two values of "media
+ size": A4 (210x297) and A3 (297x420). It does not support other
+ combinations of "x-dimension" and "y-dimension" member
+ attributes, such as 210x420 or 297x297 and it does not supported
+ non-enumerated values, such as 420x595.
+
+ b)"xxx-supported" is a "1setOf type2 keyword" which enumerates
+ the names of all of the member attributes of "xxx": "aaa1",
+ "aaa2", _, "aaaN". If a collection of this form contains a
+ nested collection, it MAY be of either form. See item 5f) below
+ for details on supported values of member attributes.
+
+ For example, "media-col-supported" might have the keyword
+ values: "media-size" and "media-color".
+
+ 5. The member attributes MUST be defined. For each member attribute
+ the definition document MUST provide the following information:
+
+
+ a)The member attribute's name (e.g., "aaa") MUST be unique within
+ the collection being defined and MUST either
+
+
+ i) reuse the attribute name of another attribute (that is unique
+ across the entire IPP attribute name space) and have the same
+ syntax and semantics as the reused attribute (if the condition
+ of item 4b) above is met). For example, a member attribute
+ definition could reuse the IPP/1.1 "media" attribute.
+
+
+
+
+
+deBry, et al. Expires: July 24, 2001 [page 8]
+
+
+INTERNET-DRAFT IPP: The 'collection' attribute syntax Jan 24, 2001
+
+
+ ii) potentially occur elsewhere in the entire IPP attribute
+ name space. (if the condition of item 4a) above is met). For
+ example, a member attribute could be "x-dimension" which could
+ potentially occur in another collection or as an attribute
+ outside of a collection.
+
+
+ iii) be unique across the entire IPP attribute name space (if
+ the condition of item 4b) above is met). For example, a member
+ attribute could be "media-color" which must unique be across
+ the entire IPP attribute name space.
+
+
+ b)Whether the member attribute is REQUIRED or OPTIONAL for the
+ Printer to support
+
+
+ c)Whether the member attribute is REQUIRED or OPTIONAL for the
+ client to supply in a request
+
+
+ d)The member attribute's syntax type, which can be any attribute
+ syntax, including '1setOf X', 'collection', and '1setOf
+ collection'. If this attribute name reuses the name of another
+ attribute (case of item a1 above), it MUST have the same
+ attribute syntax, including cardinality (whether or not 1setOf).
+
+
+ e)The semantics of the "aaa" member attribute. The semantic
+ definition MUST include a description of any constraint or
+ boundary conditions the member attribute places on the
+ associated attribute, especially if the attribute reuses the
+ name of another attribute (case of item a1 above)
+
+ f)The supported values for the each "aaaI" member attribute (of
+ the member attributes "aaa1", "aaa2", _, "aaaN") is specified
+ by one of two mechanisms.
+
+ i) If "xxx-supported" is a "1setOf collection" (see item 4a)
+ above), the value for each "aaaI" is specified in each
+ collection value of "xxx-supported" in the context of other
+ member attributes. That is, "xxx-supported" enumerates all
+ supported values of "xxx".
+
+
+ ii) If the value of "xxx-supported" is a "1setOf type2
+ keyword" (see item 4b) above), the supported values of "aaaI"
+ are the values specified by either i) the "aaaI-supported"
+ attribute or ii) the definition of the member attribute "aaaI"
+ within the document defining the "xxx" attribute. The values
+
+
+deBry, et al. Expires: July 24, 2001 [page 9]
+
+
+INTERNET-DRAFT IPP: The 'collection' attribute syntax Jan 24, 2001
+
+
+ of each member attribute "aaaI" are specified independently of
+ other member attributes though a Printer is not required to
+ support all combinations of supported values.
+
+ For example, "media-col-supported" might have the keyword
+ values: "media-size" and "media-color". Using the first method
+ for defining supported values (an "aaaI-supported" attribute),
+ the collection values of "media-col" are combinations of
+ values of "media-size-supported" and "media-color-
+ supported".If "media-size-supported" has the values of
+ '210x297' and '297x420' and "media-color-supported" has the
+ values of 'white' and 'pink', the Printer might support only
+ the combinations 'white-210x297', 'pink-210x297'and 'white-
+ 297x420', and not 'pink-297x420'.
+
+ If a collection contains a member "aaaI" whose syntax type is
+ "text", the supported values would probably be defined by the
+ definition of "xxx" rather than by the attribute "aaaI-
+ supported".
+
+ g)the default value of each "aaaI" member attribute if it is
+ OPTIONAL for a client to supply the "aaa" member attribute in a
+ request. The default value is specified by in the attribute's
+ definition within a document and MUST be one of the following:
+
+ i) a fixed default
+
+ ii) a mechanism by which the Printer determines default
+
+ iii) an indefinite default that is left to the implementation.
+
+ iv) an attribute that the Printer uses to determine the default
+
+ 6. The default value of "xxx" if a client does not supply it. The
+ default value is specified by in the attribute's definition within
+ a document and MUST be one of the following:
+
+
+ a)a fixed default
+
+
+ b)a mechanism by which the Printer determines default
+
+
+ c)an indefinite default that is left to the implementation
+
+ d)a Printer attribute "xxx-default" which is a collection with the
+ same member attributes as "xxx". Though optional member
+ attributes may be absent in which case the Printer uses the
+ defaulting rules of item 5g) above.
+
+
+deBry, et al. Expires: July 24, 2001 [page 10]
+
+
+INTERNET-DRAFT IPP: The 'collection' attribute syntax Jan 24, 2001
+
+
+ 7. The "xxx-ready (1setOf collection)" attribute if human intervention
+ is required to make many of the supported values available. For
+ example, "media-col" is an attribute which has a "ready" attribute.
+ Most attributes do not have a "ready" attribute.
+
+
+3.2 Nested Collections
+
+ A member attribute may have a syntax type of 'collection' or '1setOf
+ collection', in which case it is called a nested collection
+ attribute. The rules for a nested collection attribute are the same
+ as for a collection attribute as specified in section 3.1.
+
+
+
+4 Collection Attributes as Attributes in Operations
+
+
+4.1 General Rules
+
+ A collection value is like any other IPP/1.1 value, except that it is
+ structured. The rules for attributes with collection values are the
+ same as for attributes of any other syntax type (see IPP/1.1), be
+ they in any group of a request of a response.
+
+
+4.2 Unsupported Values
+
+ The rules for returning an unsupported collection attribute are an
+ extension to the current rules:
+
+ 1. If the entire collection attribute is unsupported, then the
+ Printer returns just the collection attribute name with the
+ 'unsupported' out-of-band value (see the beginning of [RFC2911]
+ section 4.1) in the Unsupported Attributes Group.
+
+ 2. If a collection contains unrecognized, unsupported member
+ attributes and/or conflicting values, the attribute returned in
+ the Unsupported Group is a collection containing the
+ unrecognized, unsupported member attributes, and/or conflicting
+ values. The unrecognized member attributes have an out-of-band
+ value of 'unsupported' (see the beginning of [RFC2911] section
+ 4.1). The unsupported member attributes and conflicting values
+ have their unsupported or conflicting values.
+
+
+
+
+
+
+
+
+deBry, et al. Expires: July 24, 2001 [page 11]
+
+
+INTERNET-DRAFT IPP: The 'collection' attribute syntax Jan 24, 2001
+
+
+5 Example definition of a collection attribute
+
+ In some printing environments, it is desirable to allow the client to
+ select the media by its properties, e.g., weight, color, size, etc.,
+ instead of by name. In IPP/1.1 (see [RFC2911]), the "media (type3
+ keyword | name) Job Template attribute allows selection by name. It
+ is tempting to extend the "media" attribute syntax to include
+ "collection", but then existing clients could not understand default
+ or supported media values that use the collection value. To preserve
+ interoperability, a new attribute MUST BE added, e.g., "media-col
+ (collection)". The following subsections contain a sample definition
+ of a simplified "media-col" attribute. The definition follows the
+ rules in section 3.
+
+ All of the example attribute definitions in this document are
+ illustrative examples, rather than actual definitions. These
+ examples are intended to illustrate how to define collection
+ attributes. Other documents MUST define collection attributes for
+ use in actual interchange. Such definitions may be very similar to
+ the examples in this document, since we attempted to pick useful
+ examples.
+
+ Note: we picked the name "media-col" because the name "media" is
+ already in use. Ordinarily the collection attribute would have a name
+ like any other attribute and would not end in "col".
+
+ The member attributes of "media-col" attribute ("media-color (type 3
+ keyword)" and "media-size (collection)") both follow the naming rules
+ of item 4a3 of section 3, i.e. the names are unique across the entire
+ IPP attribute name space. The member attributes of the "media-size
+ (collection)" member attribute ("x-dimension (integer(0,MAX))" and
+ "y-dimension (integer(0,MAX))") both follow the naming rules of item
+ 4a2 of section 3, i.e. they potentially occur elsewhere in the IPP
+ attribute name space.
+
+
+5.1 media-col (collection)
+
+ The "media-col" (collection) attribute augments the IPP/1.1 [RFC2911]
+ "media" attribute. This collection attribute enables a client end
+ user to submit a list of media characteristics to the Printer. When
+ the client specifies media using the "media-col" collection
+ attribute, the Printer object MUST match the requested media exactly.
+ The 'collection' consists of the following member attributes:
+
+
+
+
+
+
+
+
+deBry, et al. Expires: July 24, 2001 [page 12]
+
+
+INTERNET-DRAFT IPP: The 'collection' attribute syntax Jan 24, 2001
+
+
+ Table 1 - "media-col" member attributes
+
+
+
+ Attribute name attribute syntax reque Printer
+ st Support
+
+
+ media-color type3 keyword | name (MAX) MAY MUST
+
+ media-size collection MUST MUST
+
+
+ The definitions for the member attributes is given in the following
+ sub-sections:
+
+
+ 5.1.1 media-color (type3 keyword | name(MAX)
+
+ This member attribute identifies the color of the media. Valid
+ values are 'red', 'white' and 'blue'
+
+ The "media-color-supported" (1setOf (type3 keyword | name(MAX)))
+ Printer attribute identifies the values of this "media-color"
+ member attribute that the Printer supports, i.e., the colors
+ supported.
+
+ If the client omits this member attribute, the Printer determines
+ the value in an implementation dependent manner.
+
+
+ 5.1.2 media-size (collection)
+
+ This member attribute identifies the size of the media. The
+ 'collection' consists of the member attributes shown in Table 2:
+
+
+ Table 2 - "media-size" collection member attributes
+
+
+
+ Attribute attribute syntax request Printer
+ name Support
+
+
+ x-dimension integer (0:MAX) MUST MUST
+
+ y-dimension integer (0:MAX) MUST MUST
+
+
+
+
+deBry, et al. Expires: July 24, 2001 [page 13]
+
+
+INTERNET-DRAFT IPP: The 'collection' attribute syntax Jan 24, 2001
+
+
+ The definitions for the member attributes is given in the
+ following sub-sections:
+
+
+ 5.1.2.1 x-dimension (integer(0:MAX))
+ This attribute identifies the width of the media in inch units
+ along the X axis.
+
+
+ 5.1.2.2 y-dimension (integer(0:MAX))
+ This attribute identifies the height of the media in inch
+ units along the Y axis.
+
+ The "media-size-supported" (1setOf collection) Printer
+ attribute identifies the values of this "media-size" member
+ attribute that the Printer supports, i.e., the size
+ combinations supported. The names of the member attributes
+ are the same as the member attributes of the "media-size"
+ collection attribute, namely "x-dimension", and "y-dimension",
+ since they have the same attribute syntax and the same
+ semantics.
+
+
+5.2 media-col-default (collection)
+
+ The "media-col-default" Printer attribute specifies the media that
+ the Printer uses, if any, if the client omits the "media-col" and
+ "media". Job Template attribute in the Job Creation operation (and
+ the PDL doesn't include a media specification). The member
+ attributes are defined in Table 1. A Printer MUST support the same
+ member attributes for this default collection attribute as it
+ supports for the corresponding "media-col" Job Template attribute.
+
+
+5.3 media-col-ready (1setOf collection)
+
+ The "media-col-ready" Printer attribute identifies the media that are
+ available for use without human intervention, i.e., the media that
+ are ready to be used without human intervention. The collection
+ value MUST have all of the member attributes that are supported in
+ Table 1.
+
+
+5.4 media-col-supported (1setOf type2 keyword)
+
+ The "media-col-supported" Printer attribute identifies the keyword
+ names of the member attributes supported in the "media-col"
+ collection Job Template attribute, i.e., the keyword names of the
+ member attributes in Table 1 that the Printer supports.
+
+
+
+deBry, et al. Expires: July 24, 2001 [page 14]
+
+
+INTERNET-DRAFT IPP: The 'collection' attribute syntax Jan 24, 2001
+
+
+6 A Second Example Definition Of A Collection Attribute
+
+ All of the example attribute definitions in this document are
+ illustrative examples, rather than actual definitions. These
+ examples are intended to illustrate how to define collection
+ attributes. Other documents MUST define collection attributes for
+ use in actual interchange. Such definitions may be very similar to
+ the examples in this document, since we attempted to pick useful
+ examples.
+
+ In some printing environments, it is desirable to allow the client to
+ select the media for the job start sheet. The reason for not adding
+ the 'collection' attribute syntax to the existing "job-sheets" Job
+ Template attribute is the same as for "media". Instead, a new Job
+ Template attribute is introduced, e.g. "job-sheet-col (collection)".
+
+ The member attributes of "job-sheet-col" attribute ("job-sheets
+ (type 3 keyword)" and "media (type3 keyword | name)") both follow
+ the naming rules of item 4a1 of section 3, i.e they reuse existing
+ IPP attributes. According to the rules, their supported values come
+ from the existing IPP attributes: "job-sheets-supported" and "media-
+ supported". However, their default values do not come from "job-
+ sheets-default" and "media-default", respectively. Rather the
+ definition of "job-sheet-col" says that "job-sheets (type 3 keyword)"
+ is required and if "media (type3 keyword | name)" is absent, the
+ Printer uses the same media as the rest of the job uses.
+
+ If "job-sheet-col" attribute were defined to contain the member
+ attribute "job-sheet-media (type3 keyword | name)" instead of "media
+ (type3 keyword | name)", then the definition would also have to
+ specify a "job-sheet-media-supported (1setOf (type3 keyword |
+ name))" whose values would be independent of "media-supported
+ (1setOf (type3 keyword | name))" and would be set separately by a
+ System Administrator.
+
+ The actual text for the definition of the attribute is left as an
+ exercise for the reader.
+
+
+
+7 Encoding
+
+ This section defines the additional encoding tags used according to
+ [RFC2910] and gives an example of their use. The encoding tags
+ define in this document MUST be used by all collection attributes
+ defined in other documents. However, the example of their use is
+ illustrative only.
+
+
+
+
+
+deBry, et al. Expires: July 24, 2001 [page 15]
+
+
+INTERNET-DRAFT IPP: The 'collection' attribute syntax Jan 24, 2001
+
+
+7.1 Additional tags defined for representing a collection attribute
+ value
+
+ The 'collection' attribute syntax uses the tags defined in Table 3.
+
+
+ Table 3 - Tags defined for encoding the 'collection' attribute syntax
+
+
+
+ Tag name Tag Meaning
+ value
+
+
+ begCollection 0x34 Begin the collection attribute value.
+
+ endCollection 0x37 End the collection attribute value.
+
+ memberAttrName 0x4A The value is the name of the
+ collection member attribute
+
+
+ When encoding a collection attribute "xxx" that contains an attribute
+ "aaa" and is not inside another collection, the encoding follows
+ these rules:
+
+ 1. The beginning of the collection is indicated with a value tag
+ that MUST be syntax type 'begCollection' (0x34) with a name
+ length and Name field that represent the name of the collection
+ attribute ("xxx") as with any attribute, followed by a value. The
+ Printer MAY ignore the value and its length of MAY be 0. In the
+ future, however, this field MAY contain useful information, such
+ as the collection name (cf. the name of a C struct).
+
+ 2. Each member attribute is encoded as a sequence of two or more
+ values that appear to be part of a single multi-valued attribute,
+ i.e. 1setOf. The first value after the 'begCollection' value has
+ the attribute syntax 'memberAttrName' (0x4A) and its value holds
+ the name of the first member attribute (e.g. "aaa"). The second
+ value holds the first member's attribute value, which can be of
+ any attribute syntax, except 'memberAttrName' or 'endCollection'.
+ If the first member's attribute value is multi-valued, the third
+ value holds the second value of the first member's value.
+ Otherwise, the third value holds the name of second member
+ attribute (e.g. "bbb") and its attribute syntax is
+ 'memberAttrName'. In this case, the fourth member's value is the
+ value of "bbb".
+
+ Note that the technique of encoding a 'collection' as a '1setOf'
+ makes it easy for a Printer that doesn't support a particular
+
+
+deBry, et al. Expires: July 24, 2001 [page 16]
+
+
+INTERNET-DRAFT IPP: The 'collection' attribute syntax Jan 24, 2001
+
+
+ collection attribute (or the collection attribute syntax at all)
+ to simply skip over the entire collection value.
+
+ 3. The end of the collection is indicated with a value tag that MUST
+ be syntax type 'endCollection' (e.g. 0x37) and MAY have a zero
+ name length and a zero value length. In the future, this field
+ MAY contain useful information,such as the collection name that
+ matches the one in the 'begCollection' .
+
+ 4. It is valid to have a member attribute that is, itself, a
+ collection attribute, i.e., collections can be nested within
+ collections. This is represented by the occurrence of a member
+ attribute that is of attribute syntax type 'begCollection'. Such
+ a collection is terminated by a matching 'endCollection'. The
+ name of such a member attribute is in the immediately preceding
+ value whose syntax type is 'memberAttrName'.
+
+ 5. It is valid for a collection attribute to be multi-valued, i.e.,
+ have more than one collection value. If the next attribute
+ immediately following the 'endCollection' has a zero name length
+ and a tag of 'begCollection', then the collection attribute is a
+ multi-valued collection, as with any attribute. This statement
+ applies to collections within collections and collections that
+ are not in collections.
+
+
+7.2 Example encoding: "media-col" (collection)
+
+ The collection specified in section 5 is used for the encoding
+ example shown in Table 5. The example also shows nested collections,
+ since the "media-size" member attribute is a 'collection. The
+ encoding example represents a blue 4x6-index cards and takes 216
+ octets. The Appendices contains more complex examples.
+
+ Additional examples have been included in the appendices.
+
+ The overall structure of the two collection values can be pictorially
+ represented as:
+
+ "media-col" =
+ { "media-color" = 'blue';
+ "media-size" =
+ { "x-dimension" = 6;
+ "y-dimension" = 4
+ }
+ },
+
+ The full encoding is in table 4. A simplified view of the encoding
+ looks like this:
+
+
+
+deBry, et al. Expires: July 24, 2001 [page 17]
+
+
+INTERNET-DRAFT IPP: The 'collection' attribute syntax Jan 24, 2001
+
+
+ Table 4 - Overview Encoding of "media-col" collection
+
+
+
+ Tag Value Name Value
+
+
+ begCollection media-col ""
+
+ memberAttrName "" media-color
+
+ keyword "" blue
+
+ memberAttrName "" media-size
+
+ begCollection "" ""
+
+ memberAttrName "" x-dimension
+
+ integer "" 6
+
+ memberAttrName "" y-dimension
+
+ integer "" 4
+
+ endCollection "" ""
+
+ endCollection "" ""
+
+
+
+
+
+
+ Table 5 - Example Encoding of "media-col" collection
+
+
+
+ Octets Symbolic Value Protocol comments
+ field
+
+
+ 0x34 begCollection value-tag beginning of the "media-
+ col" collection attribute
+
+ 0x0009 name- length of (collection)
+ length attribute name
+
+
+
+
+
+deBry, et al. Expires: July 24, 2001 [page 18]
+
+
+INTERNET-DRAFT IPP: The 'collection' attribute syntax Jan 24, 2001
+
+
+
+
+ Octets Symbolic Value Protocol comments
+ field
+
+
+ media-col media-col name name of (collection)
+ attribute
+
+ 0x0000 value- defined to be 0 for this
+ length type
+
+ no value (since value-
+ length was 0)
+
+ 0x4A memberAttrName value-tag starts a new member
+ attribute: "media-color"
+
+ 0x0000 name- defined to be 0 for this
+ length type, so part of 1setOf
+
+ no name (since name-length
+ was 0)
+
+ 0x000B value- length of "media-color"
+ length keyword
+
+ media-color media-color value value is name of 1st
+ member attribute
+
+
+ 0x44 keyword type value-tag keyword type
+
+ 0x0000 name- 0 indicates 1setOf
+ length
+
+ no name (since name-length
+ was 0)
+
+ 0x0004 value-
+ length
+
+ blue blue value value of 1st member
+ attribute
+
+
+ 0x4A memberAttrName value-tag starts a new member
+ attribute: "media-size"
+
+
+
+
+deBry, et al. Expires: July 24, 2001 [page 19]
+
+
+INTERNET-DRAFT IPP: The 'collection' attribute syntax Jan 24, 2001
+
+
+
+
+ Octets Symbolic Value Protocol comments
+ field
+
+
+ 0x0000 name- defined to be 0 for this
+ length type, so part of 1setOf
+
+ no name (since name-length
+ was 0)
+
+ 0x000A value- length of "media-size"
+ length keyword
+
+ media-size media-size value Name of 2nd member
+ attribute
+
+
+ 0x34 begCollection value-tag Beginning of the "media-
+ size" collection attribute
+ which is a sub-collection
+
+ 0x0000 name- 0 indicates 1setOf
+ length
+
+ no name (since name-length
+ was 0)
+
+ 0x0000 value- collection attribute names
+ length have no value
+
+ no value (since value-
+ length was 0)
+
+ 0x4A memberAttrName value-tag starts a new member
+ attribute: "x-dimension"
+
+ 0x0000 name- defined to be 0 for this
+ length type, so part of 1setOf
+
+ no name (since name-length
+ was 0)
+
+ 0x000B value- length of "x-dimension"
+ length keyword
+
+
+
+
+
+
+deBry, et al. Expires: July 24, 2001 [page 20]
+
+
+INTERNET-DRAFT IPP: The 'collection' attribute syntax Jan 24, 2001
+
+
+
+
+ Octets Symbolic Value Protocol comments
+ field
+
+
+ x-dimension x-dimension value name of 1st sub-
+ collection member
+ attribute
+
+
+ 0x21 integer type value-tag attribute type
+
+ 0x0000 name- 0 indicates 1setOf
+ length
+
+ no name (since name-length
+ was 0)
+
+ 0x0004 value- length of an integer = 4
+ length
+
+ 0x0006 value value of 1st sub-
+ collection member
+ attribute
+
+
+ 0x4A memberAttrName value-tag starts a new member
+ attribute: "y-dimension"
+
+ 0x0000 name- defined to be 0 for this
+ length type, so part of 1setOf
+
+ no name (since name-length
+ was 0)
+
+ 0x000B value- length of the "y-
+ length dimension" keyword
+
+ y-dimension y-dimension value name of 2nd sub-
+ collection member
+ attribute
+
+
+ 0x21 integer type value-tag attribute type
+
+ 0x0000 name- 0 indicates 1setOf
+ length
+
+
+
+
+deBry, et al. Expires: July 24, 2001 [page 21]
+
+
+INTERNET-DRAFT IPP: The 'collection' attribute syntax Jan 24, 2001
+
+
+
+
+ Octets Symbolic Value Protocol comments
+ field
+
+
+ no name (since name-length
+ was 0)
+
+ 0x0004 value- length of an integer = 4
+ length
+
+ 0x0004 value value of 2nd sub-
+ collection member
+ attribute
+
+
+ 0x37 endCollection value-tag end of the sub-collection
+
+ 0x0000 name- defined to be 0 for this
+ length type, so part of 1setOf
+
+ no name (since name-length
+ was 0)
+
+ 0x0000 value- defined to be 0 for this
+ length type
+
+ no value (since value-
+ length was 0)
+
+ 0x37 endCollection value-tag end of the 1st collection
+ value in 1setOf
+
+ 0x0000 name- defined to be 0 for this
+ length type, so part of 1setOf
+
+ no name (since name-length
+ was 0)
+
+ 0x0000 value- defined to be 0 for this
+ length type
+
+ no value (since value-
+ length was 0)
+
+
+
+
+
+
+
+deBry, et al. Expires: July 24, 2001 [page 22]
+
+
+INTERNET-DRAFT IPP: The 'collection' attribute syntax Jan 24, 2001
+
+
+8 Legacy issues
+
+ IPP 1.x Printers and Clients will gracefully ignore collections and
+ its member attributes if it does not understand the collection. The
+ begCollection and endCollection elements each look like an attribute
+ with an attribute syntax that the recipient doesn't support and so
+ should ignore the entire attribute. The individual member attributes
+ and their values will look like a 1setOf values of the collection
+ attribute, so that the Printer simply ignores the entire attribute
+ and all of its values. Returning unsupported attributes is also
+ simple, since only the name of the collection attribute is returned
+ with the 'unsupported' out-of-band value (see section 4.2).
+
+
+
+9 IANA Considerations
+
+ This section contains the exact information for IANA to add to the
+ IPP Registries according to the procedures defined in "IPP/1.1 Model
+ and Semantics" document [RFC2911] section 6.
+
+ Note to RFC Editors: Replace RFC NNNN below with the RFC number for
+ this document, so that it accurately reflects the content of the
+ information for the IANA Registry.
+
+
+9.1 Attribute Syntax Registration
+
+ The attribute syntax defined in this document will be published by
+ IANA according to the procedures in RFC 2911 [RFC2911] section 6.3
+ with the following path:
+
+ ftp.isi.edu/iana/assignments/ipp/attribute-syntaxes/
+
+ The registry entry will contain the following information:
+
+ Reference:
+ RFC NNNN [this document]
+
+ Attribute Syntaxes: Ref. Section:
+ collection RFC NNNN 3
+
+
+
+
+10 Internationalization Considerations
+
+ This attribute syntax by itself has no impact on
+ internationalization. However, the member attributes that are
+ subsequently defined for use in a collection may have
+
+
+deBry, et al. Expires: July 24, 2001 [page 23]
+
+
+INTERNET-DRAFT IPP: The 'collection' attribute syntax Jan 24, 2001
+
+
+ internationalization considerations, as may any attribute, according
+ to [RFC2911].
+
+
+
+11 Security Considerations
+
+ This attribute syntax causes no more security concerns than any other
+ attribute syntax. It is only the attributes that are subsequently
+ defined to use this or any other attribute syntax that may have
+ security concerns, depending on the semantics of the attribute,
+ according to [RFC2911].
+
+
+
+12 References
+
+ [ipp-ntfy]
+ Isaacson, S., Martin, J., deBry, R., Hastings, T., Shepherd, M.,
+ Bergman, R. " Internet Printing Protocol/1.0 & 1.1: IPP Event
+ Notification Specification" draft-ietf-ipp-not-spec-02.txt, work in
+ progress, February 2, 2000.
+
+ [RFC2565]
+ Herriot, R., Butler, S., Moore, P., Tuner, R., "Internet Printing
+ Protocol/1.0: Encoding and Transport", RFC 2565, April 1999.
+
+ [RFC2566]
+ R. deBry, T. Hastings, R. Herriot, S. Isaacson, P. Powell,
+ "Internet Printing Protocol/1.0: Model and Semantics", RFC 2566,
+ April 1999.
+
+ [RFC2567]
+ Wright, D., "Design Goals for an Internet Printing Protocol", RFC
+ 2567, April 1999.
+
+ [RFC2568]
+ Zilles, S., "Rationale for the Structure and Model and Protocol for
+ the Internet Printing Protocol", RFC 2568, April 1999.
+
+ [RFC2569]
+ Herriot, R., Hastings, T., Jacobs, N., Martin, J., "Mapping between
+ LPD and IPP Protocols", RFC 2569, April 1999.
+
+ [RFC2616]
+ R. Fielding, J. Gettys, J. Mogul, H. Frystyk, L. Masinter, P.
+ Leach, T. Berners-Lee, "Hypertext Transfer Protocol - HTTP/1.1",
+ RFC 2616, June 1999.
+
+
+
+
+deBry, et al. Expires: July 24, 2001 [page 24]
+
+
+INTERNET-DRAFT IPP: The 'collection' attribute syntax Jan 24, 2001
+
+
+ [RFC2910]
+ Herriot, R., Butler, S., Moore, P., Turner, R., "Internet Printing
+ Protocol/1.1: Encoding and Transport", draft-ietf-ipp-protocol-v11-
+ 05.txt, March 1, 2000.
+
+ [RFC2911]
+ Isaacson, S., deBry, R., Hastings, T., Herriot, R., Powell, P.,
+ "Internet Printing Protocol/1.1: Model and Semantics", RFC 2911,
+ September 2000.
+
+
+
+13 Author's Addresses
+
+ Roger deBry
+ Utah Valley State College
+ Orem, UT 84058
+ Phone: (801) 222-8000
+ EMail: debryro@uvsc.edu
+
+ Tom Hastings
+ Xerox Corporation
+ 737 Hawaii St. ESAE 231
+ El Segundo, CA 90245
+ Phone: 310-333-6413
+ Fax: 310-333-5514
+ e-mail: hastings@cp10.es.xerox.com
+
+ Robert Herriot
+ Xerox Corp.
+ 3400 Hill View Ave, Building 1
+ Palo Alto, CA 94304
+ Phone: 650-813-7696
+ Fax: 650-813-6860
+ e-mail: robert.herriot@pahv.xerox.com
+
+ Kirk Ocke
+ Xerox Corp.
+ 800 Phillips Rd
+ M/S 139-05A
+ Webster, NY 14580
+ Phone: (716) 442-4832
+ EMail: kirk.ocke@usa.xerox.com
+
+ Peter Zehler
+ Xerox Corp.
+ 800 Phillips Rd
+ M/S 139-05A
+ Webster, NY 14580
+ Phone: (716) 265-8755
+
+
+deBry, et al. Expires: July 24, 2001 [page 25]
+
+
+INTERNET-DRAFT IPP: The 'collection' attribute syntax Jan 24, 2001
+
+
+ EMail: peter.zehler@usa.xerox.com
+
+
+14 Appendix A: Encoding Example of a Simple Collection
+
+ The overall structure of the collection value can be pictorially
+ represented as:
+
+ " media-size " =
+ { "x-dimension" = 6;
+ "y-dimension" = 4
+ }
+
+ A simplified view of the encoding would look like this:
+
+
+ Table 6 - Overview Encoding of simple collection
+
+
+
+ Tag Value Name Value
+
+
+ begCollection media-size ""
+
+ memberAttrName "" x-dimension
+
+ integer "" 6
+
+ memberAttrName "" y-dimension
+
+ integer "" 4
+
+ endCollection "" ""
+
+
+ Note: "" represents a name or value whose length is 0.
+
+
+ Table 7 - Example Encoding of simple collection
+
+
+
+ Octets Symbolic Value Protocol comments
+ field
+
+
+ 0x34 begCollection value-tag beginning of the "media-
+ size" collection attribute
+
+
+
+deBry, et al. Expires: July 24, 2001 [page 26]
+
+
+INTERNET-DRAFT IPP: The 'collection' attribute syntax Jan 24, 2001
+
+
+
+
+ Octets Symbolic Value Protocol comments
+ field
+
+
+ 0x000A name- length of (collection)
+ length attribute name
+
+ media-size media-size name name of (collection)
+ attribute
+
+ 0x0000 value- defined to be 0 for this
+ length type
+
+ no value (since value-
+ length was 0)
+
+ 0x4A memberAttrName value-tag starts member attribute:
+ "x-dimension"
+
+ 0x0000 name- defined to be 0 for this
+ length type, so part of 1setOf
+
+ no name (since name-length
+ was 0)
+
+ 0x000B value- length of "x-dimension"
+ length keyword
+
+ x-dimension x-dimension value name of 1st collection
+ member attribute
+
+
+ 0x21 integer type value-tag attribute type
+
+ 0x0000 name- 0 indicates 1setOf
+ length
+
+ no name (since name-length
+ was 0)
+
+ 0x0004 value- length of an integer = 4
+ length
+
+ 0x0006 value value of 1st collection
+ member attribute
+
+
+
+
+
+deBry, et al. Expires: July 24, 2001 [page 27]
+
+
+INTERNET-DRAFT IPP: The 'collection' attribute syntax Jan 24, 2001
+
+
+
+
+ Octets Symbolic Value Protocol comments
+ field
+
+
+ 0x4A memberAttrName value-tag starts a new member
+ attribute: "y-dimension"
+
+ 0x0000 name- defined to be 0 for this
+ length type, so part of 1setOf
+
+ no name (since name-length
+ was 0)
+
+ 0x000B value- length of the "y-
+ length dimension" keyword
+
+ y-dimension y-dimension value name of 2nd collection
+ member attribute
+
+
+ 0x21 integer type value-tag attribute type
+
+ 0x0000 name- 0 indicates 1setOf for
+ length media-size
+
+ no name (since name-length
+ was 0)
+
+ 0x0004 value- length of an integer = 4
+ length
+
+ 0x0004 value value of 2nd collection
+ member attribute
+
+
+ 0x37 endCollection value-tag end of the collection
+
+ 0x0000 name- defined to be 0 for this
+ length type, so part of 1setOf
+
+ no name (since name-length
+ was 0)
+
+ 0x0000 value- defined to be 0 for this
+ length type
+
+
+
+
+
+deBry, et al. Expires: July 24, 2001 [page 28]
+
+
+INTERNET-DRAFT IPP: The 'collection' attribute syntax Jan 24, 2001
+
+
+
+
+ Octets Symbolic Value Protocol comments
+ field
+
+
+ no value (since value-
+ length was 0)
+
+
+
+
+
+15 Appendix B: Encoding Example of 1setOf Collection
+
+ The overall structure of the collection value can be pictorially
+ represented as:
+
+ "media-size-supported" =
+ { "x-dimension" = 6;
+ "y-dimension" = 4
+ },
+ { "x-dimension" = 3;
+ "y-dimension" = 5
+ };
+
+ A simplified view of the encoding would look like this:
+
+
+ Table 8 - Overview Encoding of 1setOf collection
+
+
+
+ Tag Value Name Value
+
+
+ begCollection media-size- ""
+ supported
+
+ memberAttrName "" x-dimension
+
+ integer "" 6
+
+ memberAttrName "" y-dimension
+
+ integer "" 4
+
+ endCollection "" ""
+
+
+
+
+deBry, et al. Expires: July 24, 2001 [page 29]
+
+
+INTERNET-DRAFT IPP: The 'collection' attribute syntax Jan 24, 2001
+
+
+
+ begCollection "" ""
+
+ memberAttrName "" x-dimension
+
+ integer "" 3
+
+ memberAttrName "" y-dimension
+
+ integer "" 5
+
+ endCollection "" ""
+
+
+
+
+ Table 9 - Example Encoding of 1setOf collection
+
+
+
+ Octets Symbolic Value Protocol comments
+ field
+
+
+ 0x34 begCollection value-tag beginning of the "media-
+ size-supported (1setOf
+ collection" attribute
+
+ 0x00014 name- length of (collection)
+ length attribute name
+
+ media-size- media-size- name name of (collection)
+ supported supported attribute
+
+ 0x0000 value- defined to be 0 for this
+ length type
+
+ no value (since value-
+ length was 0)
+
+ 0x4A memberAttrName value-tag starts member attribute:
+ "x-dimension"
+
+ 0x0000 name- defined to be 0 for this
+ length type, so part of 1setOf
+
+ no name (since name-length
+ was 0)
+
+
+
+
+deBry, et al. Expires: July 24, 2001 [page 30]
+
+
+INTERNET-DRAFT IPP: The 'collection' attribute syntax Jan 24, 2001
+
+
+
+
+ Octets Symbolic Value Protocol comments
+ field
+
+
+ 0x000B value- length of "x-dimension"
+ length keyword
+
+ x-dimension x-dimension value name of 1st collection
+ member attribute
+
+
+ 0x21 integer type value-tag attribute type
+
+ 0x0000 name- 0 indicates 1setOf
+ length
+
+ no name (since name-length
+ was 0)
+
+ 0x0004 value- length of an integer = 4
+ length
+
+ 0x0006 value value of 1st collection
+ member attribute
+
+ 0x4A memberAttrName value-tag starts member attribute:
+ "y-dimension"
+
+ 0x0000 name- defined to be 0 for this
+ length type, so part of 1setOf
+
+ no name (since name-length
+ was 0)
+
+ 0x000B value- length of the "y-
+ length dimension" keyword
+
+ y-dimension y-dimension value name of 2nd collection
+ member attribute
+
+ 0x21 integer type value-tag attribute type
+
+ 0x0000 name- 0 indicates 1setOf
+ length
+
+ no name (since name-length
+ was 0)
+
+
+
+deBry, et al. Expires: July 24, 2001 [page 31]
+
+
+INTERNET-DRAFT IPP: The 'collection' attribute syntax Jan 24, 2001
+
+
+
+
+ Octets Symbolic Value Protocol comments
+ field
+
+
+ 0x0004 value- length of an integer = 4
+ length
+
+ 0x0004 value value of 2nd collection
+ member attribute
+
+ 0x37 endCollection value-tag end of the collection
+
+ 0x0000 name- defined to be 0 for this
+ length type, so part of 1setOf
+
+ no name (since name-length
+ was 0)
+
+ 0x0000 value- defined to be 0 for this
+ length type
+
+ no value (since value-
+ length was 0)
+
+ 0x34 begCollection value-tag beginning of the 2nd
+ member of the 1SetOf
+ "sizes-avail " collection
+ attribute
+
+ 0x0000 name- Zero length name indicates
+ length this is member of previous
+ attribute
+
+ name no name (since name-length
+ was 0)
+
+ 0x0000 value- defined to be 0 for this
+ length type
+
+ no value (since value-
+ length was 0)
+
+ 0x4A memberAttrName value-tag starts member attribute:
+ "x-dimension"
+
+ 0x0000 name- defined to be 0 for this
+ length type, so part of 1setOf
+
+
+
+deBry, et al. Expires: July 24, 2001 [page 32]
+
+
+INTERNET-DRAFT IPP: The 'collection' attribute syntax Jan 24, 2001
+
+
+
+
+ Octets Symbolic Value Protocol comments
+ field
+
+
+ no name (since name-length
+ was 0)
+
+ 0x000B value- length of "x-dimension"
+ length keyword
+
+ x-dimension x-dimension value name of 1st collection
+ member attribute
+
+ 0x21 integer type value-tag attribute type
+
+ 0x0000 name- 0 indicates 1setOf
+ length
+
+ no name (since name-length
+ was 0)
+
+ 0x0004 value- length of an integer = 4
+ length
+
+ 0x0003 value value of 1st collection
+ member attribute
+
+ 0x4A memberAttrName value-tag starts member attribute:
+ "y-dimension"
+
+ 0x0000 name- defined to be 0 for this
+ length type, so part of 1setOf
+
+ no name (since name-length
+ was 0)
+
+ 0x000B value- length of the "y-
+ length dimension" keyword
+
+ y-dimension y-dimension value name of 2nd collection
+ member attribute
+
+ 0x21 integer type value-tag attribute type
+
+ 0x0000 name- 0 indicates 1setOf
+ length
+
+
+
+
+deBry, et al. Expires: July 24, 2001 [page 33]
+
+
+INTERNET-DRAFT IPP: The 'collection' attribute syntax Jan 24, 2001
+
+
+
+
+ Octets Symbolic Value Protocol comments
+ field
+
+
+ no name (since name-length
+ was 0)
+
+ 0x0004 value- length of an integer = 4
+ length
+
+ 0x0005 value value of 2nd collection
+ member attribute
+
+ 0x37 endCollection value-tag end of the 1setOf
+ collection value
+
+ 0x0000 name- defined to be 0 for this
+ length type, so part of 1setOf
+
+ no name (since name-length
+ was 0)
+
+ 0x0000 value- defined to be 0 for this
+ length type
+
+ no value (since value-
+ length was 0)
+
+
+
+
+
+16 Appendix C: Encoding Example of Collection containing 1setOf XXX
+ attribute
+
+ The overall structure of the collection value can be pictorially
+ represented as:
+
+ "wagons" =
+ { "colors" = red, blue;
+ "sizes" = 4, 6, 8
+ }
+
+ A simplified view of the encoding would look like this:
+
+ Table 10 - Overview Encoding of collection with 1setOf value
+
+
+
+
+deBry, et al. Expires: July 24, 2001 [page 34]
+
+
+INTERNET-DRAFT IPP: The 'collection' attribute syntax Jan 24, 2001
+
+
+
+
+ Tag Value Name Value
+
+
+ begCollection wagons ""
+
+ memberAttrName "" colors
+
+ keyword "" red
+
+ keyword "" blue
+
+ memberAttrName "" sizes
+
+ integer "" 4
+
+ integer "" 6
+
+ integer "" 8
+
+ endCollection "" ""
+
+
+
+
+ Table 11 - Example Encoding of collection with 1setOf value
+
+
+
+ Octets Symbolic Value Protocol comments
+ field
+
+
+ 0x34 begCollection value-tag beginning of the "wagons"
+ collection attribute
+
+ 0x0005 name- length of (collection)
+ length attribute name
+
+ wagons wagons name name of (collection)
+ attribute
+
+ 0x0000 value- defined to be 0 for this
+ length type
+
+ no value (since value-
+ length was 0)
+
+
+
+
+deBry, et al. Expires: July 24, 2001 [page 35]
+
+
+INTERNET-DRAFT IPP: The 'collection' attribute syntax Jan 24, 2001
+
+
+
+
+ Octets Symbolic Value Protocol comments
+ field
+
+
+ 0x4A memberAttrName value-tag starts a new member
+ attribute: "colors"
+
+ 0x0000 name- defined to be 0 for this
+ length type, so part of 1setOf
+
+ no name (since name-length
+ was 0)
+
+ 0x0006 value- length of "colors" keyword
+ length
+
+ colors colosr value value is name of 1st
+ member attribute
+
+ 0x44 keyword type value-tag keyword type
+
+ 0x0000 name- 0 indicates 1setOf wagons
+ length
+
+ no name (since name-length
+ was 0)
+
+ 0x0004 value-
+ length
+
+ blue blue value value of 1st member
+ attribute
+
+ 0x44 keyword type value-tag keyword type
+
+ 0x0000 name- 0 indicates 1setOf wagons
+ length
+
+ no name (since name-length
+ was 0)
+
+ 0x0003 value-
+ length
+
+ red red value value of 1st member
+ attribute
+
+
+
+
+deBry, et al. Expires: July 24, 2001 [page 36]
+
+
+INTERNET-DRAFT IPP: The 'collection' attribute syntax Jan 24, 2001
+
+
+
+
+ Octets Symbolic Value Protocol comments
+ field
+
+
+ 0x4A memberAttrName value-tag starts a new member
+ attribute: "sizes"
+
+ 0x0000 name- defined to be 0 for this
+ length type, so part of 1setOf
+
+ no name (since name-length
+ was 0)
+
+ 0x0005 value- length of "length-avail"
+ length keyword
+
+ sizes sizes value Name of 2nd member
+ attribute
+
+ 0x21 integer type value-tag attribute type
+
+ 0x0000 name- 0 indicates 1setOf wagons
+ length
+
+ no name (since name-length
+ was 0)
+
+ 0x0004 value- length of an integer = 4
+ length
+
+ 0x0004 value 1st value for 1SetOf
+ integer attribute
+
+ 0x21 integer type value-tag attribute type
+
+ 0x0000 name- 0 indicates 1setOf
+ length
+
+ no name (since name-length
+ was 0)
+
+ 0x0004 value- length of an integer = 4
+ length
+
+ 0x0006 value 2nd value for 1SetOf
+ integer attribute
+
+
+
+
+deBry, et al. Expires: July 24, 2001 [page 37]
+
+
+INTERNET-DRAFT IPP: The 'collection' attribute syntax Jan 24, 2001
+
+
+
+
+ Octets Symbolic Value Protocol comments
+ field
+
+
+ 0x21 integer type value-tag attribute type
+
+ 0x0000 name- 0 indicates 1setOf
+ length
+
+ no name (since name-length
+ was 0)
+
+ 0x0004 value- length of an integer = 4
+ length
+
+ 0x0008 value 3rd value for 1SetOf
+ integer attribute
+
+ 0x37 endCollection value-tag end of the collection
+
+ 0x0000 name- defined to be 0 for this
+ length type, so part of 1setOf
+
+ no name (since name-length
+ was 0)
+
+ 0x0000 value- defined to be 0 for this
+ length type
+
+ no value (since value-
+ length was 0)
+
+
+
+
+
+17 Appendix D: Full Copyright Statement
+
+ Copyright (C) The Internet Society (1998,1999,2000,2001). All Rights
+ Reserved
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+
+
+deBry, et al. Expires: July 24, 2001 [page 38]
+
+
+INTERNET-DRAFT IPP: The 'collection' attribute syntax Jan 24, 2001
+
+
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+deBry, et al. Expires: July 24, 2001 [page 39]
diff --git a/standards/draft-ietf-ipp-finishings-fold-trim-bale-00.txt b/standards/draft-ietf-ipp-finishings-fold-trim-bale-00.txt
new file mode 100644
index 000000000..dd4ac3403
--- /dev/null
+++ b/standards/draft-ietf-ipp-finishings-fold-trim-bale-00.txt
@@ -0,0 +1,585 @@
+INTERNET-DRAFT
+<draft-ietf-ipp-finishings-fold-trim-bale-00.txt>
+ T. Hastings
+ Xerox Corporation
+ D. Fullman
+ Xerox Corporation
+ October 20, 1999
+
+
+Internet Printing Protocol/1.1: "finishings" 'fold', 'trim', and 'bale'
+ attribute values extension
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+
+
+
+Status of this Memo
+
+
+This document is an Internet-Draft and is in full conformance with all
+provisions of Section 10 of [RFC2026]. Internet-Drafts are working
+documents of the Internet Engineering Task Force (IETF), its areas, and
+its working groups. Note that other groups may also distribute working
+documents as Internet-Drafts.
+
+
+Internet-Drafts are draft documents valid for a maximum of six months
+and may be updated, replaced, or obsoleted by other documents at any
+time. It is inappropriate to use Internet-Drafts as reference material
+or to cite them other than as "work in progress".
+
+
+The list of current Internet-Drafts can be accessed at
+http://www.ietf.org/ietf/1id-abstracts.txt
+
+
+The list of Internet-Draft Shadow Directories can be accessed as
+http://www.ietf.org/shadow.html.
+
+
+Abstract
+
+
+This document specifies the additional enum values 'fold', 'trim', and
+'bale' for the IPP/1.1 "finishings" Job Template attribute for use with
+the Internet Printing Protocol/1.1 (IPP) [ipp-mod, ipp-pro]. This
+attribute permits the client to specify additional finishing options,
+including values that include a specification of a coordinate system for
+the placement of finishings operation with respect to the corners and
+edges of portrait and landscape documents.
+
+
+
+
+
+
+
+
+
+T. Hastings, D. Fullman [page 1]
+ Expires April 20, 2000
+
+
+
+INTERNET-DRAFT IPP/1.0: "finishings" extension October 20, 1999
+
+
+The full set of IPP documents includes:
+
+ Design Goals for an Internet Printing Protocol [RFC2567]
+ Rationale for the Structure and Model and Protocol for the Internet
+ Printing Protocol [RFC2568]
+ Internet Printing Protocol/1.1: Model and Semantics [ipp-mod]
+ Internet Printing Protocol/1.1: Encoding and Transport [ipp-pro]
+ Internet Printing Protocol/1.1: Implementer's Guide [ipp-iig]
+ Mapping between LPD and IPP Protocols [RFC2569]
+
+
+The "Design Goals for an Internet Printing Protocol" document takes a
+broad look at distributed printing functionality, and it enumerates
+real-life scenarios that help to clarify the features that need to be
+included in a printing protocol for the Internet. It identifies
+requirements for three types of users: end users, operators, and
+administrators. It calls out a subset of end user requirements that are
+satisfied in IPP/1.0. A few OPTIONAL operator operations have been
+added to IPP/1.1.
+
+
+The "Rationale for the Structure and Model and Protocol for the Internet
+Printing Protocol" document describes IPP from a high level view,
+defines a roadmap for the various documents that form the suite of IPP
+specification documents, and gives background and rationale for the IETF
+working group's major decisions.
+
+
+The "Internet Printing Protocol/1.1: Encoding and Transport" document is
+a formal mapping of the abstract operations and attributes defined in
+the model document onto HTTP/1.1 [RFC2616]. It defines the encoding
+rules for a new Internet MIME media type called "application/ipp". This
+document also defines the rules for transporting over HTTP a message
+body whose Content-Type is "application/ipp". This document defines a
+new scheme named 'ipp' for identifying IPP printers and jobs.
+
+
+The "Internet Printing Protocol/1.1: Implementer's Guide" document gives
+insight and advice to implementers of IPP clients and IPP objects. It
+is intended to help them understand IPP/1.1 and some of the
+considerations that may assist them in the design of their client and/or
+IPP object implementations. For example, a typical order of processing
+requests is given, including error checking. Motivation for some of the
+specification decisions is also included.
+
+
+The "Mapping between LPD and IPP Protocols" document gives some advice
+to implementers of gateways between IPP and LPD (Line Printer Daemon)
+implementations.
+
+
+
+
+
+
+
+
+
+T. Hastings, D. Fullman [page 2]
+ Expires April 20, 2000
+
+
+
+INTERNET-DRAFT IPP/1.0: "finishings" extension October 20, 1999
+
+
+
+
+ TABLE OF CONTENTS
+
+1 Additional values for the "finishings" Job Template attribute......4
+
+ 1.1 Problem.........................................................4
+
+ 1.2 Suggested solution..............................................4
+
+ 1.3 Proposed Text...................................................5
+
+ 1.3.1Coordinate system for enum values............................6
+
+2 IANA Considerations................................................7
+
+3 Security Considerations............................................7
+
+4 References.........................................................7
+
+5 Author's Addresses.................................................8
+
+6 Full Copyright Statement...........................................9
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+T. Hastings, D. Fullman [page 3]
+ Expires April 20, 2000
+
+
+
+INTERNET-DRAFT IPP/1.0: "finishings" extension October 20, 1999
+
+
+
+
+1 Additional values for the "finishings" Job Template attribute
+
+
+1.1 Problem
+
+
+Need additional enum values for finishing to specify which of four
+corners to put a single staple, which of four edges to put two staples,
+and generic values for the following: fold, trim, bale, saddle stitch
+and edge stitch.
+
+1.2 Suggested solution
+
+
+This solution has been proposed at two previous meetings with comments
+returned and incorporated. The suggestion is to add additional enum
+values to the "finishings" Job Template attributes (also applies to
+"finishings-default" and "finishings-supported" attributes).
+
+Coordination with the Finisher MIB has been done. There appears to be
+no direct way to use the same enum values, since the Finisher MIB
+divides up finishing into separate enum values by type. So all the
+stapling is done as a separate enum. Also all the punching is done as a
+separate enum.
+
+The coordinate system scheme has been selected to agree with the
+Finisher MIB which in turn follows the ISO DPA approach of using a
+coordinate system as if the document were portrait. The approach for
+coordinate system being relative to the intended reading direction
+depends on the device being able to understand the orientation embedded
+in the PDL, which is too problematic for many PDLs. The approach for
+the coordinate system of being relative to the media feed direction is
+to dependent on the way the device is currently set up, i.e., pulling
+short edge first vs. long edge first, and can vary between different
+output-bins in the same device.
+
+Additional (new) keyword symbolic names of these enum values are:
+ fold
+ trim
+ bale
+
+
+Although not a part of this specification, more specific values for
+saddle-stitch and fold could be considered once adequate definitions
+have been developed. Some examples are:
+
+ saddle-stitch-single-long
+ saddle-stitch-single-short
+ saddle-stitch-dual-long
+ saddle-stitch-dual-short
+ fold-in-half-long
+ fold-in-half-short
+ fold-in-thirds-long
+ fold-in-thirds-short
+
+T. Hastings, D. Fullman [page 4]
+ Expires April 20, 2000
+
+
+
+INTERNET-DRAFT IPP/1.0: "finishings" extension October 20, 1999
+
+
+ fold-z-long
+ fold-z-short
+
+
+1.3 Proposed Text
+
+
+Add the following paragraphs indicated with revision marks to the
+description of the "finishings" Job Template attribute, section 4.2.6,
+so that the entire section would be:
+
+4.2.6 finishings (1setOf type2 enum)
+
+This attribute identifies the finishing operations that the Printer uses
+for each copy of each printed document in the Job. For Jobs with
+multiple documents, the "multiple-document-handling" attribute
+determines what constitutes a "copy" for purposes of finishing.
+
+
+Standard enum values are:
+
+ Value Symbolic Name and Description
+
+ '3' 'none': Perform no finishing
+ '4' 'staple': Bind the document(s) with one or more staples. The
+ exact number and placement of the staples is site-
+ defined.
+ '5' 'punch': This value indicates that holes are required in the
+ finished document. The exact number and placement of the
+ holes is site-defined The punch specification MAY be
+ satisfied (in a site- and implementation-specific manner)
+ either by drilling/punching, or by substituting pre-
+ drilled media.
+ '6' 'cover': This value is specified when it is desired to select
+ a non-printed (or pre-printed) cover for the document.
+ This does not supplant the specification of a printed
+ cover (on cover stock medium) by the document itself.
+ '7' 'bind': This value indicates that a binding is to be applied
+ to the document; the type and placement of the binding is
+ site-defined.
+ '8' 'saddle-stitch': Bind the document(s) with one or more
+ staples (wire stitches) along the middle fold. The exact
+ number and placement of the staples and the middle fold
+ is implementation and/or site-defined.
+ '9' 'edge-stitch': Bind the document(s) with one or more staples
+ (wire stitches) along one edge. The exact number and
+ placement of the staples is implementation and/or site-
+ defined.
+ '10' 'fold': Fold the document(s) with one or more folds. The
+ exact number and orientations of the folds is
+ implementation and/or site-defined.
+ '11' 'trim': Trim the document(s) on one or more edges. The exact
+ number of edges and the amount to be trimmed is
+ implementation and/or site-defined.
+
+
+
+T. Hastings, D. Fullman [page 5]
+ Expires April 20, 2000
+
+
+
+INTERNET-DRAFT IPP/1.0: "finishings" extension October 20, 1999
+
+
+ '12' 'bale': Bale the document(s). The type of baling is
+ implementation and/or site-defined.
+ '13'-'19' reserved for future generic finishing enum values.
+
+The following values are more specific stapling and stitching values;
+they indicate a corner or an edge as if the document were a portrait
+document (see section 1.3.1):
+
+ '20' 'staple-top-left': Bind the document(s) with one or more
+ staples in the top left corner.
+ '21' 'staple-bottom-left': Bind the document(s) with one or more
+ staples in the bottom left corner.
+ '22' 'staple-top-right': Bind the document(s) with one or more
+ staples in the top right corner.
+ '23' 'staple-bottom-right': Bind the document(s) with one or more
+ staples in the bottom right corner.
+ '24' 'edge-stitch-left': Bind the document(s) with one or more
+ staples (wire stitches) along the left edge. The exact
+ number and placement of the staples is implementation
+ and/or site-defined.
+ '25' 'edge-stitch-top': Bind the document(s) with one or more
+ staples (wire stitches) along the top edge. The exact
+ number and placement of the staples is implementation
+ and/or site-defined.
+ '26' 'edge-stitch-right': Bind the document(s) with one or more
+ staples (wire stitches) along the right edge. The exact
+ number and placement of the staples is implementation
+ and/or site-defined.
+ '27' 'edge-stitch-bottom': Bind the document(s) with one or more
+ staples (wire stitches) along the bottom edge. The exact
+ number and placement of the staples is implementation
+ and/or site-defined.
+ '28' 'staple-dual-left': Bind the document(s) with two staples
+ (wire stitches) along the left edge.
+ '29' 'staple-dual-top': Bind the document(s) with two staples
+ (wire stitches) along the top edge.
+ '30' 'staple-dual-right': Bind the document(s) with two staples
+ (wire stitches) along the right edge.
+ '31' 'staple-dual-bottom': Bind the document(s) with two staples
+ (wire stitches) along the bottom edge.
+ '32'-'79' reserved for future specific stapling, stitching and
+ folding enum values.
+
+1.1.11.3.1Coordinate system for enum values
+
+The values, for which the symbolic name contains "top", "bottom", "left"
+and "right", are specified with respect to the document as if the
+document were a portrait document. If the document is actually a
+landscape or a reverse-landscape document, the client supplies the
+appropriate transformed value. This applies to values such as 'staple-
+xxx' and 'edge-stitch-xxx'. For example, to position a staple in the
+upper left hand corner of a landscape document when held for reading,
+the client supplies the 'staple-bottom-left' value (since landscape is
+defined as a +90 degree rotation from portrait, i.e., anti-clockwise).
+On the other hand, to position a staple in the upper left hand corner of
+
+T. Hastings, D. Fullman [page 6]
+ Expires April 20, 2000
+
+
+
+INTERNET-DRAFT IPP/1.0: "finishings" extension October 20, 1999
+
+
+a reverse-landscape document when held for reading, the client supplies
+the 'staple-top-right' value (since reverse-landscape is defined as a -
+90 degree rotation from portrait, i.e., clockwise).
+
+
+The angle (vertical, horizontal, angled) of each staple with respect to
+the document depends on the implementation which may in turn depend on
+the value of the attribute.
+
+
+Note: The effect of this attribute on jobs with multiple documents is
+controlled by the "multiple-document-handling" job attribute (section
+4.2.4) and the relationship of this attribute and the other attributes
+that control document processing is described in section 16.3.
+
+
+If the client supplies a value of 'none' along with any other
+combination of values, it is the same as if only that other combination
+of values had been supplied (that is the 'none' value has no effect).
+
+
+2 IANA Considerations
+
+
+These "finishings" type2 enum attribute values will be published by IANA
+according to the procedures in RFC 2566 [rfc2566] section 6.1 with the
+following URL:
+
+ ftp.isi.edu/iana/assignments/ipp/attribute-values/finishings/fold-
+ trim-bale.txt
+
+
+3 Internationalization Considerations
+
+
+Normally a client will provide localization of the enum values of this
+attribute to the language of the user.
+
+
+4 Security Considerations
+
+
+This extension poses no additional security threats or burdens than
+those in IPP/1.0 [RFC2566, RFC2565] and IPP/1.1 [ipp-mod, ipp-pro].
+However, implementations MAY support different access control to various
+finishing features, depending on the identity of the job submitting
+user.
+
+
+5 References
+
+
+[ipp-iig]
+ Hastings, T., Manros, C., "Internet Printing Protocol/1.1: <draft-
+ ietf-ipp-implementers-guide-v11-00.txt>, work in progress,
+ September 27, 1999.
+
+
+
+
+T. Hastings, D. Fullman [page 7]
+ Expires April 20, 2000
+
+
+
+INTERNET-DRAFT IPP/1.0: "finishings" extension October 20, 1999
+
+
+[ipp-mod]
+ R. deBry, T. Hastings, R. Herriot, S. Isaacson, P. Powell,
+ "Internet Printing Protocol/1.1: Model and Semantics", <draft-ietf-
+ ipp-model-v11-03.txt>, work in progress, June 1999.
+
+
+[ipp-pro]
+ Herriot, R., Butler, S., Moore, P., Tuner, R., "Internet Printing
+ Protocol/1.1: Encoding and Transport", <draft-ietf-ipp-protocol-
+ v11-03.txt>, work in progress, June 1999.
+
+
+[RFC2565]
+ Herriot, R., Butler, S., Moore, P., Tuner, R., "Internet Printing
+ Protocol/1.0: Encoding and Transport", RFC 2565, April 1999.
+
+
+[RFC2566]
+ R. deBry, T. Hastings, R. Herriot, S. Isaacson, P. Powell,
+ "Internet Printing Protocol/1.0: Model and Semantics", RFC 2566,
+ April 1999.
+
+
+[RFC2567]
+ Wright, D., "Design Goals for an Internet Printing Protocol", RFC
+ 2567, April 1999.
+
+
+[RFC2568]
+ Zilles, S., "Rationale for the Structure and Model and Protocol for
+ the Internet Printing Protocol", RFC 2568, April 1999.
+
+
+[RFC2569]
+ Herriot, R., Hastings, T., Jacobs, N., Martin, J., "Mapping between
+ LPD and IPP Protocols", RFC 2569, April 1999.
+
+
+[RFC2639]
+ Hastings, T., Manros, C., "Internet Printing Protocol/1.0:
+ Implementer's Guide", RFC 2639, July 1999.
+
+
+6 Author's Addresses
+
+ Tom Hastings
+ Xerox Corporation
+ 737 Hawaii St. ESAE 231
+ El Segundo, CA 90245
+
+ Phone: 310-333-6413
+ Fax: 310-333-5514
+ e-mail: hastings@cp10.es.xerox.com
+
+ Don Fullman
+ Xerox Corporation
+ 737 Hawaii St. ESAE 231
+
+
+T. Hastings, D. Fullman [page 8]
+ Expires April 20, 2000
+
+
+
+INTERNET-DRAFT IPP/1.0: "finishings" extension October 20, 1999
+
+
+ El Segundo, CA 90245
+
+ Phone: 310-333-8342
+ Fax: 310-333-5514
+ e-mail: dfullman@cp10.es.xerox.com
+
+7 Full Copyright Statement
+
+
+Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it or
+assist in its implementation may be prepared, copied, published and
+distributed, in whole or in part, without restriction of any kind,
+provided that the above copyright notice and this paragraph are included
+on all such copies and derivative works. However, this document itself
+may not be modified in any way, such as by removing the copyright notice
+or references to the Internet Society or other Internet organizations,
+except as needed for the purpose of developing Internet standards in
+which case the procedures for copyrights defined in the Internet
+Standards process must be followed, or as required to translate it into
+languages other than English.
+
+
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+
+
+This document and the information contained herein is provided on an "AS
+IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK
+FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT
+LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT
+INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR
+FITNESS FOR A PARTICULAR PURPOSE.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+T. Hastings, D. Fullman [page 9]
+ Expires April 20, 2000
diff --git a/standards/draft-ietf-ipp-implementers-guide-v11-02.txt b/standards/draft-ietf-ipp-implementers-guide-v11-02.txt
new file mode 100644
index 000000000..5cf1db457
--- /dev/null
+++ b/standards/draft-ietf-ipp-implementers-guide-v11-02.txt
@@ -0,0 +1,5046 @@
+
+
+
+
+
+
+INTERNET-DRAFT
+draft-ietf-ipp-implementers-guide-v11-02.txt
+[Obsoletes RFC 2639] T. Hastings
+ Xerox Corporation
+ C. Manros
+ Xerox Corporation
+ C. Kugler
+ IBM Printing Systems Co
+ H. Holst
+ i-data Printing Systems
+ P. Zehler
+ Xerox Corporation
+ January 25, 2001
+
+ Internet Printing Protocol/1.1: Implementer's Guide
+
+ Copyright (C) The Internet Society (2001). All Rights Reserved.
+
+Status of this Memo
+
+ This document is an Internet-Draft and is in full conformance with
+ all provisions of Section 10 of [RFC2026]. Internet-Drafts are
+ working documents of the Internet Engineering Task Force (IETF), its
+ areas, and its working groups. Note that other groups may also
+ distribute working documents as Internet-Drafts.
+
+ Internet-Drafts are draft documents valid for a maximum of six months
+ and may be updated, replaced, or obsoleted by other documents at any
+ time. It is inappropriate to use Internet-Drafts as reference
+ material or to cite them other than as "work in progress".
+
+ The list of current Internet-Drafts can be accessed at
+ http://www.ietf.org/ietf/1id-abstracts.txt
+
+ The list of Internet-Draft Shadow Directories can be accessed as
+ http://www.ietf.org/shadow.html.
+
+Abstract
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 1]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ This document is one of a set of documents, which together describe
+ all aspects of a new Internet Printing Protocol (IPP). IPP is an
+ application level protocol that can be used for distributed printing
+ using Internet tools and technologies. This document contains
+ information that supplements the IPP Model and Semantics [RFC2911]
+ and the IPP Transport and Encoding [RFC2910] documents. It is
+ intended to help implementers understand IPP/1.1, as well as IPP/1.0,
+ and some of the considerations that may assist them in the design of
+ their client and/or IPP object implementations. For example, a
+ typical order of processing requests is given, including error
+ checking. Motivation for some of the specification decisions is also
+ included.
+
+ This document obsoletes RFC 2639 which was the Implementer's Guide
+ for IPP/1.0.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 2]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ The full set of IPP documents includes:
+ Design Goals for an Internet Printing Protocol [RFC2567]
+ Rationale for the Structure and Model and Protocol for the Internet
+ Printing Protocol [RFC2568]
+ Internet Printing Protocol/1.1: Model and Semantics [RFC2911]
+ Internet Printing Protocol/1.1: Encoding and Transport [RFC2910]
+ Mapping between LPD and IPP Protocols [RFC2569]
+ The document, "Design Goals for an Internet Printing Protocol", takes
+ a broad look at distributed printing functionality, and it enumerates
+ real-life scenarios that help to clarify the features that need to be
+ included in a printing protocol for the Internet. It identifies
+ requirements for three types of users: end users, operators, and
+ administrators. The design goal document calls out a subset of end
+ user requirements that are satisfied in IPP/1.1. Operator and
+ administrator requirements are out of scope for version 1.1.
+
+ The document, "Rationale for the Structure and Model and Protocol for
+ the Internet Printing Protocol", describes IPP from a high level
+ view, defines a roadmap for the various documents that form the suite
+ of IPP specifications, and gives background and rationale for the
+ IETF working group's major decisions.
+
+ The document, "Internet Printing Protocol/1.1: Model and Semantics",
+ describes a simplified model with abstract objects, their attributes,
+ and their operations. The model introduces a Printer and a Job. The
+ Job supports multiple documents per Job. The model document also
+ addresses how security, internationalization, and directory issues
+ are addressed.
+
+ The document, "Internet Printing Protocol/1.1: Encoding and
+ Transport", is a formal mapping of the abstract operations and
+ attributes defined in the model document onto HTTP/1.1. It also
+ defines the encoding rules for a new Internet media type called
+ "application/ipp".
+
+ The document, "Mapping between LPD and IPP Protocols", gives some
+ advice to implementers of gateways between IPP and LPD (Line Printer
+ Daemon) implementations.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 3]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+TABLE OF CONTENTS
+
+ 1 Introduction....................................................7
+ 1.1 Conformance language.........................................7
+ 1.2 Other terminology............................................8
+ 1.3 Issues Raised from Interoperability Testing Events...........8
+
+ 2 IPP Objects.....................................................8
+
+ 3 IPP Operations.................................................10
+ 3.1 Common Semantics............................................10
+ 3.1.1 Summary of Operation Attributes............................10
+ 3.1.2 Suggested Operation Processing Steps for IPP Objects.......16
+ 3.1.2.1 Suggested Operation Processing Steps for all Operations ..17
+ 3.1.2.1.1 Validate version number...............................18
+ 3.1.2.1.2 Validate operation identifier.........................19
+ 3.1.2.1.3 Validate the request identifier.......................19
+ 3.1.2.1.4 Validate attribute group and attribute presence and order
+ 19
+ 3.1.2.1.4.1 Validate the presence and order of attribute groups .19
+ 3.1.2.1.4.2 Ignore unknown attribute groups in the expected
+ position 20
+ 3.1.2.1.4.3 Validate the presence of a single occurrence of
+ required Operation attributes.....................................21
+ 3.1.2.1.5 Validate the values of the REQUIRED Operation attributes
+ 28
+ 3.1.2.1.6 Validate the values of the OPTIONAL Operation attributes
+ 32
+ 3.1.2.2 Suggested Additional Processing Steps for Operations that
+ Create/Validate Jobs and Add Documents............................35
+ 3.1.2.2.1 Default "ipp-attribute-fidelity" if not supplied......35
+ 3.1.2.2.2 Check that the Printer object is accepting jobs.......36
+ 3.1.2.2.3 Validate the values of the Job Template attributes....36
+ 3.1.2.3 Algorithm for job validation .............................37
+ 3.1.2.3.1 Check for conflicting Job Template attributes values..43
+ 3.1.2.3.2 Decide whether to REJECT the request..................43
+ 3.1.2.3.3 For the Validate-Job operation, RETURN one of the success
+ status codes......................................................45
+ 3.1.2.3.4 Create the Job object with attributes to support......45
+ 3.1.2.3.5 Return one of the success status codes................47
+ 3.1.2.3.6 Accept appended Document Content......................48
+ 3.1.2.3.7 Scheduling and Starting to Process the Job............48
+ 3.1.2.3.8 Completing the Job....................................48
+ 3.1.2.3.9 Destroying the Job after completion...................48
+ 3.1.2.3.10 Interaction with "ipp-attribute-fidelity".............49
+ 3.1.2.3.11 Character set code conversion support.................49
+ 3.1.2.3.12 What charset to return when an unsupported charset is
+ requested (Issue 1.19)?...........................................50
+ 3.1.2.3.13 Natural Language Override (NLO).......................51
+ 3.1.3 Status codes returned by operation.........................53
+
+
+Hastings, et al. Expires July 25, 2001 [page 4]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ 3.1.3.1 Printer Operations .......................................53
+ 3.1.3.1.1 Print-Job.............................................53
+ 3.1.3.1.2 Print-URI.............................................55
+ 3.1.3.1.3 Validate-Job..........................................56
+ 3.1.3.1.4 Create-Job............................................56
+ 3.1.3.1.5 Get-Printer-Attributes................................56
+ 3.1.3.1.6 Get-Jobs..............................................57
+ 3.1.3.1.7 Pause-Printer.........................................58
+ 3.1.3.1.8 Resume-Printer........................................59
+ 3.1.3.1.8.1 What about Printers unable to change state due to an
+ error condition?..................................................59
+ 3.1.3.1.8.2 How is "printer-state" handled on Resume-Printer? ...59
+ 3.1.3.1.9 Purge-Printer.........................................60
+ 3.1.3.2 Job Operations ...........................................60
+ 3.1.3.2.1 Send-Document.........................................60
+ 3.1.3.2.2 Send-URI..............................................61
+ 3.1.3.2.3 Cancel-Job............................................62
+ 3.1.3.2.4 Get-Job-Attributes....................................62
+ 3.1.3.2.5 Hold-Job..............................................63
+ 3.1.3.2.6 Release-Job...........................................64
+ 3.1.3.2.7 Restart-Job...........................................64
+ 3.1.3.2.7.1 Can documents be added to a restarted job? ..........65
+ 3.1.4 Returning unsupported attributes in Get-Xxxx responses (Issue
+ 1.18) 65
+ 3.1.5 Sending empty attribute groups.............................65
+ 3.2 Printer Operations..........................................66
+ 3.2.1 Print-Job operation........................................66
+ 3.2.1.1 Flow controlling the data portion of a Print-Job request
+ (Issue 1.22)......................................................66
+ 3.2.1.2 Returning job-state in Print-Job response (Issue 1.30) ...66
+ 3.2.2 Get-Printer-Attributes operation...........................67
+ 3.2.3 Get-Jobs operation.........................................67
+ 3.2.3.1 Get-Jobs, my-jobs='true', and 'requesting-user-name' (Issue
+ 1.39)? 67
+ 3.2.3.2 Why is there a "limit" attribute in the Get-Jobs operation?
+ 68
+ 3.2.4 Create-Job operation.......................................68
+ 3.3 Job Operations..............................................69
+ 3.3.1 Validate-Job...............................................69
+ 3.3.2 Restart-Job................................................69
+
+ 4 Object Attributes..............................................70
+ 4.1 Attribute Syntax's..........................................70
+ 4.1.1 The 'none' value for empty sets (Issue 1.37)...............70
+ 4.1.2 Multi-valued attributes (Issue 1.31).......................70
+ 4.1.3 Case Sensitivity in URIs (issue 1.6).......................70
+ 4.1.4 Maximum length for xxxWithLanguage and xxxWithoutLanguage..71
+ 4.2 Job Template Attributes.....................................72
+ 4.2.1 multiple-document-handling(type2 keyword)..................72
+ 4.2.1.1 Support of multiple document jobs ........................72
+
+
+Hastings, et al. Expires July 25, 2001 [page 5]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ 4.3 Job Description Attributes..................................72
+ 4.3.1 Getting the date and time of day...........................72
+ 4.4 Printer Description Attributes..............................73
+ 4.4.1 queued-job-count (integer(0:MAX))..........................73
+ 4.4.1.1 Why is "queued-job-count" RECOMMENDED (Issue 1.14)? ......73
+ 4.4.1.2 Is "queued-job-count" a good measure of how busy a printer
+ is (Issue 1.15)?..................................................73
+ 4.4.2 printer-current-time (dateTime)............................73
+ 4.4.3 Printer-uri................................................74
+ 4.5 Empty Jobs..................................................74
+
+ 5 Directory Considerations.......................................75
+ 5.1 General Directory Schema Considerations.....................75
+ 5.2 IPP Printer with a DNS name.................................75
+
+ 6 Security Considerations........................................75
+ 6.1 Querying jobs with IPP that were submitted using other job
+ submission protocols (Issue 1.32).................................75
+
+ 7 Encoding and Transport.........................................76
+ 7.1 General Headers.............................................78
+ 7.2 Request Headers............................................79
+ 7.3 Response Headers............................................81
+ 7.4 Entity Headers.............................................81
+ 7.5 Optional support for HTTP/1.0...............................82
+ 7.6 HTTP/1.1 Chunking...........................................83
+ 7.6.1 Disabling IPP Server Response Chunking.....................83
+ 7.6.2 Warning About the Support of Chunked Requests..............83
+
+ 8 References.....................................................84
+
+ 9 Authors' Address...............................................85
+
+ 10 Full Copyright Statement.......................................86
+
+TABLES
+
+ Table 1 - Summary of Printer operation attributes that sender MUST
+ supply ........................................................11
+ Table 2 - Summary of Printer operation attributes that sender MAY
+ supply ........................................................12
+ Table 3 - Summary of Job operation attributes that sender MUST supply
+ ..............................................................13
+ Table 4 - Summary of Job operation attributes that sender MAY supply
+ ..............................................................14
+ Table 5 - Printer operation response attributes...................15
+ Table 6 - Examples of validating IPP version......................18
+ Table 7 - Rules for validating single values X against Z..........38
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 6]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+
+
+
+
+1 Introduction
+
+ The IPP Implementer's Guide (IIG) (this document) contains
+ information that supplements the IPP Model and Semantics [RFC2911]
+ and the IPP Transport and Encoding [RFC2910] documents. As such this
+ information is not part of the formal specifications. Instead
+ information is presented to help implementers understand the
+ specification, including some of the motivation for decisions taken
+ by the committee in developing the specification. Some of the
+ implementation considerations are intended to help implementers
+ design their client and/or IPP object implementations. If there are
+ any contradictions between this document and [RFC2911] or [RFC2910],
+ those documents take precedence over this document.
+
+ Platform-specific implementation considerations will be included in
+ this guide as they become known.
+
+ In order to help the reader of the IIG and the IPP Model and
+ Semantics document, the sections in this document parallel the
+ corresponding sections in the Model document and are numbered the
+ same for ease of cross reference. The sections that correspond to
+ the IPP Transport and Encoding are correspondingly offset.
+
+
+1.1 Conformance language
+
+ Usually, this document does not contain the terminology MUST, MUST
+ NOT, MAY, NEED NOT, SHOULD, SHOULD NOT, REQUIRED, and OPTIONAL.
+ However, when those terms do appear in this document, their intent is
+ to repeat what the [RFC2911] and [RFC2910] documents require and
+ allow, rather than specifying additional conformance requirements.
+ These terms are defined in section 12 on conformance terminology in
+ [RFC2911], most of which is taken from RFC 2119 [RFC2119].
+
+ Implementers should read section 12 (APPENDIX A) in [RFC2911] in
+ order to understand these capitalized words. The words MUST, MUST
+ NOT, and REQUIRED indicate what implementations are required to
+ support in a client or IPP object in order to be conformant to
+ [RFC2911] and [RFC2910]. MAY, NEED NOT, and OPTIONAL indicate was is
+ merely allowed as an implementer option. The verbs SHOULD and SHOULD
+ NOT indicate suggested behavior, but which is not required or
+ disallowed, respectively, in order to conform to the specification.
+
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 7]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+1.2 Other terminology
+
+ This document uses other terms, such as "attributes", "operation",
+ and "Printer" as defined in [RFC2911] section 12. In addition, the
+ term "sender" refers to the client that sends a request or an IPP
+ object that returns a response. The term "receiver" refers to the
+ IPP object that receives a request and to a client that receives a
+ response.
+
+
+1.3 Issues Raised from Interoperability Testing Events
+
+ The IPP WG has conducted three open Interoperability Testing Events.
+ The first one was held in September 1998, the second one was held in
+ March 1999, and the third one was held in October 2000. See the
+ summary reports in:
+
+ ftp://ftp.pwg.org/pub/pwg/ipp/new_TES/
+
+ The issues raised from the first Interoperability Testing Event are
+ numbered 1.n in this document and have been incorporated into
+ "IPP/1.0 Model and Semantics" [RFC2566] and the "IPP/1.0 Encoding and
+ Transport" [RFC2565] documents. However, some of the discussion is
+ left here in the Implementer's Guide to help understanding.
+
+ The issues raised from the second Interoperability Testing Event are
+ numbered 2.n in this document have been incorporated into "IPP/1.1
+ Model and Semantics" [RFC2911] and the "IPP/1.1 Encoding and
+ Transport" [RFC2910] documents. However, some of the discussion is
+ left here in the Implementer's Guide to help understanding.
+
+ The issues raised from the third Interoperability Testing Event are
+ numbered 3.n in this document and are described in:
+
+ ftp://ftp.pwg.org/pub/pwg/ipp/Issues/Issues-raised-at-Bake-Off3.pdf
+ ftp://ftp.pwg.org/pub/pwg/ipp/Issues/Issues-raised-at-Bake-Off3.doc
+ ftp://ftp.pwg.org/pub/pwg/ipp/Issues/Issues-raised-at-Bake-Off3.txt
+
+
+2 IPP Objects
+
+ The term "client" in IPP is intended to mean any client that issues
+ IPP operation requests and accepts IPP operation responses, whether
+ it be a desktop or a server. In other words, the term "client" does
+ not just mean end-user clients, such as those associated with
+ desktops.
+
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 8]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ The term "IPP Printer" in IPP is intended to mean an object that
+ accepts IPP operation requests and returns IPP operation responses,
+ whether implemented in a server or a device. An IPP Printer object
+ MAY, if implemented in a server, turn around and forward received
+ jobs (and other requests) to other devices and print
+ servers/services, either using IPP or some other protocol.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 9]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+3 IPP Operations
+
+ This section corresponds to Section 3 "IPP Operations" in the
+ IPP/1.1 Model and Semantics document [RFC2911].
+
+
+3.1 Common Semantics
+
+ This section discusses semantics common to all operations.
+
+
+3.1.1 Summary of Operation Attributes
+
+ Legend for the following table:
+
+ R indicates a REQUIRED operation that MUST be supported by the IPP
+ object (Printer or Job). For attributes, R indicates that the
+ attribute MUST be supported by the IPP object supports the
+ associated operation.
+
+ O indicates an OPTIONAL operation or attribute that MAY be
+ supported by the IPP object (Printer or Job).
+
+ + indicates that this is not an IPP/1.0 feature, but is only a part
+ of IPP/1.1 and future versions of IPP.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 10]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ Table 1 - Summary of Printer operation attributes that sender MUST
+ supply
+
+ Printer Operations
+ Requests Response
+ s
+
+ Operation Print- Pri Crea Get- Get Pause- All
+ Attributes Job, te- Printer- - Printer Operatio
+ Validate URI Job Attribut Job , ns
+ -Job (R) (O) (O) es (R) s Resume-
+ (R) Printer
+ ,
+ Purge-
+ nt- Printer
+ (O+)
+
+ Operation parameters--REQUIRED to be supplied by the sender:
+ operation-id R R R R R R
+ status-code R
+ request-id R R R R R R R
+ version- R R R R R R R
+ number
+ Operation attributes--REQUIRED to be supplied by the sender:
+ attributes- R R R R R R R
+ charset
+ attributes- R R R R R R R
+ natural-
+ language
+ document-uri R
+ job-id*
+ job-uri*
+ last-
+ document
+ printer-uri R R R R R R
+ Operation attributes--RECOMMENDED to be supplied by the sender:
+ job-name R R R
+ requesting- R R R R R R
+ user-name
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 11]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ Table 2 - Summary of Printer operation attributes that sender MAY
+ supply
+
+ Printer Operations
+ Requests Respo
+ nses
+
+ Operation Print- Prin Crea Get- Get Pause- All
+ Attributes Job, t- te- Printer - Printer Opera
+ Valida URI Job - Job , tions
+ te-Job (O) (O) Attribu s Resume-
+ (R) tes (R) (R) Printer
+ ,
+ Purge-
+ Printer
+ (O+)
+
+ Operation attributes--OPTIONAL to be supplied by the sender:
+ status-message O
+ detailed-status- O
+ message
+ document-access- O**
+ error
+ compression O O
+ document-format R R R
+ document-name O O
+ document-natural- O O
+ language
+ ipp-attribute- R R R
+ fidelity
+ job-impressions O O O
+ job-k-octets O O O
+ job-media-sheets O O O
+ limit R
+ message
+ my-jobs R
+ requested- R R
+ attributes
+ which-jobs R
+ * "job-id" is REQUIRED only if used together with "printer-uri"
+ to identify the target job; otherwise, "job-uri" is REQUIRED.
+ ** "document-access-error" applies to the Print-URI response
+ only.
+
+
+
+
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 12]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+
+
+ Table 3 - Summary of Job operation attributes that sender MUST supply
+
+ Job Operations
+ Requests Respons
+ es
+
+ Operation Send- Send Cance Get- All
+ Attributes Docume -URI l-Job Job- Job, Operatio
+ nt (O) (R) Attrib Release ns
+ (O) utes -Job,
+ (R) Restart
+ -Job
+ (O+)
+
+ Operation parameters--REQUIRED to be supplied by the sender:
+ operation-id R R R R R
+ status-code R
+ request-id R R R R R R
+ version-number R R R R R R
+ Operation attributes--REQUIRED to be supplied by the sender:
+ attributes-charset R R R R R R
+ attributes-natural- R R R R R R
+ language
+ document-uri R
+ job-id* R R R R R
+ job-uri* R R R R R
+ last-document R R
+ printer-uri R R R R R
+ Operation attributes--RECOMMENDED to be supplied by the sender:
+ job-name
+ requesting-user- R R R R R
+ name
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 13]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+
+ Table 4 - Summary of Job operation attributes that sender MAY supply
+
+ Job Operations
+ Requests Respo
+ nses
+
+ Operation Send- Sen Cance Hold- Relea All
+ Attributes Documen d- l-Job Get- Job, se- Opera
+ t URI (R) Attrib Restar Job tions
+ (O) (O) utes t-Job (O+)
+ (R) (O+)
+
+ Operation attributes--OPTIONAL to be supplied by the sender:
+ status-message O
+ detailed-status- O
+ message
+ document-access- O**
+ error
+ compression O O
+ document-format R R
+ document-name O O
+ document-natural- O O
+ language
+ ipp-attribute-
+ fidelity
+ job-impressions
+ job-k-octets
+ job-media-sheets
+ limit
+ message O O O
+ job-hold-until R
+ my-jobs
+ requested- R
+ attributes
+ which-jobs
+ * "job-id" is REQUIRED only if used together with "printer-uri" to
+ identify the target job; otherwise, "job-uri" is REQUIRED.
+ ** "document-access-error" applies to the Send-URI operation only.
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 14]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+
+
+ Table 5 - Printer operation response attributes
+
+ Printer Operations
+ Response
+
+ Operation Print- Validat Prin Create Get- Get- Pause-
+ Attributes Job e-Job t- -Job Printe Jobs Printer
+ (R),Send (R) URI (O) r- (R) ,
+ - (O), Attrib Resume-
+ Document Send utes Printer
+ (O) -URI (R) ,
+ (O) Purge-
+ Printer
+ (O+)
+
+ job-uri R R R
+ job-id R R R
+ job-state R R R
+ job-state- R+ R+ R+
+ reasons
+ number-of- O O O
+ intervening-
+ jobs
+ document- O
+ access-error+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 15]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+
+
+
+3.1.2 Suggested Operation Processing Steps for IPP Objects
+
+ This section suggests the steps and error checks that an IPP object
+ MAY perform when processing requests and returning responses. An IPP
+ object MAY perform some or all of the error checks. However, some
+ implementations MAY choose to be more forgiving than the error checks
+ shown here, in order to be able to accept requests from non-
+ conforming clients. Not performing all of these error checks is a
+ so-called "forgiving" implementation. On the other hand, clients
+ that successfully submit requests to IPP objects that do perform all
+ the error checks will be more likely to be able to interoperate with
+ other IPP object implementations. Thus an implementer of an IPP
+ object needs to decide whether to be a "forgiving" or a "strict"
+ implementation. Therefore, the error status codes returned may
+ differ between implementations. Consequentially, client SHOULD NOT
+ expect exactly the error code processing described in this section.
+
+ When an IPP object receives a request, the IPP object either accepts
+ or rejects the request. In order to determine whether or not to
+ accept or reject the request, the IPP object SHOULD execute the
+ following steps. The order of the steps may be rearranged and/or
+ combined, including making one or multiple passes over the request.
+
+ A client MUST supply requests that would pass all of the error checks
+ indicated here in order to be a conforming client. Therefore, a
+ client SHOULD supply requests that are conforming, in order to avoid
+ being rejected by some IPP object implementations and/or risking
+ different semantics by different implementations of forgiving
+ implementations. For example, a forgiving implementation that
+ accepts multiple occurrences of the same attribute, rather than
+ rejecting the request might use the first occurrences, while another
+ might use the last occurrence. Thus such a non-conforming client
+ would get different results from the two forgiving implementations.
+
+ In the following, processing continues step by step until a "RETURNS
+ the xxx status code ..." statement is encountered. Error returns are
+ indicated by the verb: "REJECTS". Since clients have difficulty
+ getting the status code before sending all of the document data in a
+ Print-Job request, clients SHOULD use the Validate-Job operation
+ before sending large documents to be printed, in order to validate
+ whether the IPP Printer will accept the job or not.
+
+ It is assumed that security authentication and authorization has
+ already taken place at a lower layer.
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 16]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+3.1.2.1 Suggested Operation Processing Steps for all Operations
+
+ This section is intended to apply to all operations. The next
+ section contains the additional steps for the Print-Job, Validate-
+ Job, Print-URI, Create-Job, Send-Document, and Send-URI operations
+ that create jobs, adds documents, and validates jobs.
+
+ IIG Sect # Flow IPP error status codes
+ ---------- ---- ----------------------
+ |
+ v err
+ 3.1.2.1.1 <Validate version> --> server-error-version-not-
+ supported
+ ok|
+ v err
+ 3.1.2.1.2 <Validate operation> --> server-error-operation-not-
+ supported
+ ok|
+ v err
+ 3.1.2.1.4.1- <Validate presence> --> client-error-bad-request
+ 3.1.2.1.4.2 <of attributes>
+ ok|
+ v err
+ 3.1.2.1.4.3 <Validate presence> --> client-error-bad-request
+ <of operation attr>
+ ok|
+ v err
+ 3.1.2.1.5 <Valied values of> --> client-error-bad-request
+ <operation attrs> client-error-request-value-
+ too-long
+ <(length, tag, range,>
+ <multi-value)>
+ ok|
+ v err
+ 3.1.2.1.5 <Validate values> --> client-error-bad-request
+ <with supported values> client-error-charset-not-
+ supported
+ ok| client-error-attributes-or-
+ values-
+ | not-supported
+ v err
+ 3.1.2.1.6 <Validate optionally> --> client-error-bad-request
+ <operation attr> client-error-natural-language-
+ not-supported
+ | client-error-request-value-
+ too-long
+ | client-error-attributes-or-
+ values-not-supported
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 17]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+3.1.2.1.1 Validate version number
+
+ Every request and every response contains the "version-number"
+ attribute. The value of this attribute is the major and minor
+ version number of the syntax and semantics that the client and IPP
+ object is using, respectively. The "version-number" attribute
+ remains in a fixed position across all future versions so that all
+ clients and IPP object that support future versions can determine
+ which version is being used. The IPP object checks to see if the
+ major version number supplied in the request is supported. If not,
+ the Printer object REJECTS the request and RETURNS the 'server-error-
+ version-not-supported' status code in the response. The IPP object
+ returns in the "version-number" response attribute the major and
+ minor version for the error response. Thus the client can learn at
+ least one major and minor version that the IPP object supports. The
+ IPP object is encouraged to return the closest version number to the
+ one supplied by the client.
+
+ The checking of the minor version number is implementation dependent,
+ however if the client supplied minor version is explicitly supported,
+ the IPP object MUST respond using that identical minor version
+ number. If the major version number matches, but the minor version
+ number does not, the Printer SHOULD accept and attempt to process
+ the request, or MAY reject the request and return the 'server-error-
+ version-not-supported' status code. In all cases, the Printer MUST
+ return the nearest version number that it supports. For example,
+ suppose that an IPP/1.2 Printer supports versions '1.1' and '1.2'.
+ The following responses are conforming:
+
+ Table 6 - Examples of validating IPP version
+
+
+
+ Client supplies Printer Accept Request? Printer returns
+
+
+ 1.0 yes (SHOULD) 1.1
+
+ 1.0 no (SHOULD NOT) 1.1
+
+ 1.1 yes (MUST) 1.1
+
+ 1.2 yes (MUST) 1.2
+
+ 1.3 yes (SHOULD) 1.2
+
+ 1.3 no (SHOULD NOT) 1.2
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 18]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ It is advantageous for Printers to support both IPP/1.1 and IPP/1.0,
+ so that they can interoperate with either client implementations.
+ Some implementations may allow an Administrator to explicitly disable
+ support for one or the other by setting the "ipp-versions-supported"
+ Printer description attribute.
+
+ Likewise, it is advantageous for clients to support both versions to
+ allow interoperability with new and legacy Printers.
+
+
+3.1.2.1.2 Validate operation identifier
+
+ The Printer object checks to see if the "operation-id" attribute
+ supplied by the client is supported as indicated in the Printer
+ object's "operations-supported" attribute. If not, the Printer
+ REJECTS the request and returns the 'server-error-operation-not-
+ supported' status code in the response.
+
+
+3.1.2.1.3 Validate the request identifier
+
+ The Printer object SHOULD NOT check to see if the "request-id"
+ attribute supplied by the client is in range: between 1 and 2**31 - 1
+ (inclusive), but copies all 32 bits.
+
+ Note: The "version-number", "operation-id", and the "request-id"
+ parameters are in fixed octet positions in the IPP/1.1 encoding. The
+ "version-number" parameter will be the same fixed octet position in
+ all versions of the protocol. These fields are validated before
+ proceeding with the rest of the validation.
+
+
+3.1.2.1.4 Validate attribute group and attribute presence and order
+
+ The order of the following validation steps depends on
+ implementation.
+
+
+3.1.2.1.4.1 Validate the presence and order of attribute groups
+ Client requests and IPP object responses contain attribute groups
+ that Section 3 requires to be present and in a specified order. An
+ IPP object verifies that the attribute groups are present and in the
+ correct order in requests supplied by clients (attribute groups
+ without an * in the following tables).
+
+
+
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 19]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ If an IPP object receives a request with (1) required attribute
+ groups missing, or (2) the attributes groups are out of order, or (3)
+ the groups are repeated, the IPP object REJECTS the request and
+ RETURNS the 'client-error-bad-request' status code. For example, it
+ is an error for the Job Template Attributes group to occur before the
+ Operation Attributes group, for the Operation Attributes group to be
+ omitted, or for an attribute group to occur more than once, except in
+ the Get-Jobs response.
+
+ Since this kind of attribute group error is most likely to be an
+ error detected by a client developer rather than by a customer, the
+ IPP object NEED NOT return an indication of which attribute group was
+ in error in either the Unsupported Attributes group or the Status
+ Message. Also, the IPP object NEED NOT find all attribute group
+ errors before returning this error.
+
+
+3.1.2.1.4.2 Ignore unknown attribute groups in the expected position
+ Future attribute groups may be added to the specification at the end
+ of requests just before the Document Content and at the end of
+ response, except for the Get-Jobs response, where it maybe there or
+ before the first job attributes returned. If an IPP object receives
+ an unknown attribute group in these positions, it ignores the entire
+ group, rather than returning an error, since that group may be a new
+ group in a later minor version of the protocol that can be ignored.
+ (If the new attribute group cannot be ignored without confusing the
+ client, the major version number would have been increased in the
+ protocol document and in the request). If the unknown group occurs
+ in a different position, the IPP object REJECTS the request and
+ RETURNS the 'client-error-bad-request' status code.
+
+ Clients also ignore unknown attribute groups returned in a response.
+
+ Note: By validating that requests are in the proper form, IPP
+ objects force clients to use the proper form which, in turn,
+ increases the chances that customers will be able to use such clients
+ from multiple vendors with IPP objects from other vendors.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 20]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+3.1.2.1.4.3 Validate the presence of a single occurrence of required
+ Operation attributes
+ Client requests and IPP object responses contain Operation attributes
+ that [RFC2911] Section 3 requires to be present. Attributes within a
+ group may be in any order, except for the ordering of target,
+ charset, and natural languages attributes. These attributes MUST be
+ first, and MUST be supplied in the following order: charset, natural
+ language, and then target. An IPP object verifies that the attributes
+ that Section 4 requires to be supplied by the client have been
+ supplied in the request (attributes without an * in the following
+ tables). An asterisk (*) indicates groups and Operation attributes
+ that the client may omit in a request or an IPP object may omit in a
+ response.
+
+ If an IPP object receives a request with required attributes missing
+ or repeated from a group or in the wrong position, the behavior of
+ the IPP object is IMPLEMENTATION DEPENDENT. Some of the possible
+ implementations are:
+
+ REJECTS the request and RETURNS the 'client-error-bad-request'
+ status code
+
+ accepts the request and uses the first occurrence of the
+ attribute no matter where it is
+
+ accepts the request and uses the last occurrence of the
+ attribute no matter where it is
+
+ accept the request and assume some default value for the
+ missing attribute
+
+ Therefore, client MUST send conforming requests, if they want to
+ receive the same behavior from all IPP object implementations. For
+ example, it is an error for the "attributes-charset" or "attributes-
+ natural-language" attribute to be omitted in any operation request,
+ or for an Operation attribute to be supplied in a Job Template group
+ or a Job Template attribute to be supplied in an Operation Attribute
+ group in a create request. It is also an error to supply the
+ "attributes-charset" attribute twice.
+
+ Since these kinds of attribute errors are most likely to be detected
+ by a client developer rather than by a customer, the IPP object NEED
+ NOT return an indication of which attribute was in error in either
+ the Unsupported Attributes group or the Status Message. Also, the
+ IPP object NEED NOT find all attribute errors before returning this
+ error.
+
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 21]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ The following tables list all the attributes for all the operations
+ by attribute group in each request and each response. The order of
+ the groups is the order that the client supplies the groups as
+ specified in [RFC2911] Section 3. The order of the attributes within
+ a group is arbitrary, except as noted for some of the special
+ operation attributes (charset, natural language, and target). The
+ tables below use the following notation:
+
+ R indicates a REQUIRED attribute or operation that an IPP object
+ MUST support
+ O indicates an OPTIONAL attribute or operation that an IPP
+ object NEED NOT support
+ * indicates that a client MAY omit the attribute in a request
+ and that an IPP object MAY omit the attribute in a
+ response. The absence of an * means that a client MUST
+ supply the attribute in a request and an IPP object
+ MUST supply the attribute in a response.
+ + indicates that this is not a IPP/1.0 operation, but is only a
+ part of IPP/1.1 and future versions of IPP.
+
+ Operation Requests
+
+ The tables below show the attributes in their proper attribute groups
+ for operation requests:
+
+ Note: All operation requests contain "version-number", "operation-
+ id", and "request-id" parameters.
+
+
+
+ Print-Job Request (R):
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ printer-uri (R)
+ requesting-user-name (R*)
+ job-name (R*)
+ ipp-attribute-fidelity (R*)
+ document-name (R*)
+ document-format (R*)
+ document-natural-language (O*)
+ compression (O*)
+ job-k-octets (O*)
+ job-impressions (O*)
+ job-media-sheets (O*)
+ Group 2: Job Template Attributes (R*)
+ <Job Template attributes> (O*)
+ (see [RFC2911] Section 4.2)
+ Group 3: Document Content (R)
+ <document content>
+
+
+Hastings, et al. Expires July 25, 2001 [page 22]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+
+ Validate-Job Request (R):
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ printer-uri (R)
+ requesting-user-name (R*)
+ job-name (R*)
+ ipp-attribute-fidelity (R*)
+ document-name (R*)
+ document-format (R*)
+ document-natural-language (O*)
+ compression (O*)
+ job-k-octets (O*)
+ job-impressions (O*)
+ job-media-sheets (O*)
+ Group 2: Job Template Attributes (R*)
+ <Job Template attributes> (O*)
+ (see [RFC2911] Section 4.2)
+
+ Print-URI Request (O):
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ printer-uri (R)
+ document-uri (R)
+ requesting-user-name (R*)
+ job-name (R*)
+ ipp-attribute-fidelity (R*)
+ document-name (R*)
+ document-format (R*)
+ document-natural-language (O*)
+ compression (O*)
+ job-k-octets (O*)
+ job-impressions (O*)
+ job-media-sheets (O*)
+ Group 2: Job Template Attributes (R*)
+ <Job Template attributes> (O*) (see
+ (see [RFC2911] Section 4.2)
+
+ Create-Job Request (O):
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ printer-uri (R)
+ requesting-user-name (R*)
+ job-name (R*)
+ ipp-attribute-fidelity (R*)
+ job-k-octets (O*)
+ job-impressions (O*)
+
+
+Hastings, et al. Expires July 25, 2001 [page 23]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ job-media-sheets (O*)
+ Group 2: Job Template Attributes (R*)
+ <Job Template attributes> (O*) (see
+ (see [RFC2911] Section 4.2)
+
+ Get-Printer-Attributes Request (R):
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ printer-uri (R)
+ requesting-user-name (R*)
+ requested-attributes (R*)
+ document-format (R*)
+
+ Get-Jobs Request (R):
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ printer-uri (R)
+ requesting-user-name (R*)
+ limit (R*)
+ requested-attributes (R*)
+ which-jobs (R*)
+ my-jobs (R*)
+
+ Send-Document Request (O):
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ (printer-uri & job-id) | job-uri (R)
+ last-document (R)
+ requesting-user-name (R*)
+ document-name (R*)
+ document-format (R*)
+ document-natural-language (O*)
+ compression (O*)
+ Group 2: Document Content (R*)
+ <document content>
+
+ Send-URI Request (O):
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ (printer-uri & job-id) | job-uri (R)
+ last-document (R)
+ document-uri (R)
+ requesting-user-name (R*)
+ document-name (R*)
+ document-format (R*)
+ document-natural-language (O*)
+
+
+Hastings, et al. Expires July 25, 2001 [page 24]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ compression (O*)
+
+ Cancel-Job Request (R):
+ Release-Job Request (O+):
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ (printer-uri & job-id) | job-uri (R)
+ requesting-user-name (R*)
+ message (O*)
+
+ Get-Job-Attributes Request (R):
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ (printer-uri & job-id) | job-uri (R)
+ requesting-user-name (R*)
+ requested-attributes (R*)
+
+ Pause-Printer Request (O+):
+ Resume-Printer Request (O+):
+ Purge-Printer Request (O+):
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ printer-uri (R)
+ requesting-user-name (R*)
+
+ Hold-Job Request (O+):
+ Restart-Job Request (O+):
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ (printer-uri & job-id) | job-uri (R)
+ requesting-user-name (R*)
+ job-hold-until (R*)
+ message (O*)
+
+ Operation Responses
+
+ The tables below show the response attributes in their proper
+ attribute groups for responses.
+
+ Note: All operation responses contain "version-number", "status-
+ code", and "request-id" parameters.
+
+
+ Print-Job Response (R):
+ Create-Job Response (O):
+ Send-Document Response (O):
+
+
+Hastings, et al. Expires July 25, 2001 [page 25]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ status-message (O*)
+ detailed-status-message (O*)
+ Group 2: Unsupported Attributes (R*) (see Note 3)
+ <unsupported attributes> (R*)
+ Group 3: Job Object Attributes(R*) (see Note 2)
+ job-uri (R)
+ job-id (R)
+ job-state (R)
+ job-state-reasons (O* | R+)
+ job-state-message (O*)
+ number-of-intervening-jobs (O*)
+
+ Validate-Job Response (R):
+ Cancel-Job Response (R):
+ Hold-Job Response (O+):
+ Release-Job Response (O+):
+ Restart-Job Response (O+):
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ status-message (O*)
+ detailed-status-message (O*)
+ Group 2: Unsupported Attributes (R*) (see Note 3)
+ <unsupported attributes> (R*)
+
+ Print-URI Response (O):
+ Send-URI Response (O):
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ status-message (O*)
+ detailed-status-message (O*)
+ document-access-error (O*)
+ Group 2: Unsupported Attributes (R*) (see Note 3)
+ <unsupported attributes> (R*)
+ Group 3: Job Object Attributes(R*) (see Note 2)
+ job-uri (R)
+ job-id (R)
+ job-state (R)
+ job-state-reasons (O* | R+)
+ job-state-message (O*)
+ number-of-intervening-jobs (O*)
+
+ Get-Printer-Attributes Response (R):
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+
+
+Hastings, et al. Expires July 25, 2001 [page 26]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ status-message (O*)
+ detailed-status-message (O*)
+ Group 2: Unsupported Attributes (R*) (see Note 4)
+ <unsupported attributes> (R*)
+ Group 3: Printer Object Attributes(R*) (see Note 2)
+ <requested attributes> (R*)
+
+ Get-Jobs Response (R):
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ status-message (O*)
+ detailed-status-message (O*)
+ Group 2: Unsupported Attributes (R*) (see Note 4)
+ <unsupported attributes> (R*)
+ Group 3: Job Object Attributes(R*) (see Note 2, 5)
+ <requested attributes> (R*)
+
+ Get-Job-Attributes Response (R):
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ status-message (O*)
+ detailed-status-message (O*)
+ Group 2: Unsupported Attributes (R*) (see Note 4)
+ <unsupported attributes> (R*)
+ Group 3: Job Object Attributes(R*) (see Note 2)
+ <requested attributes> (R*)
+
+ Pause-Printer Response (O+):
+ Resume-Printer Response (O+):
+ Purge-Printer Response (O+):
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ status-message (O*)
+ detailed-status-message (O*)
+ Group 2: Unsupported Attributes (R*) (see Note 4)
+ <unsupported attributes> (R*)
+
+ Note 2 - the Job Object Attributes and Printer Object Attributes are
+ returned only if the IPP object returns one of the success status
+ codes.
+
+ Note 3 - the Unsupported Attributes Group is present only if the
+ client included some Operation and/or Job Template attributes or
+ values that the Printer doesn't support whether a success or an error
+ return.
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 27]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ Note 4 - the Unsupported Attributes Group is present only if the
+ client included some Operation attributes that the Printer doesn't
+ support whether a success or an error return.
+
+ Note 5: for the Get-Jobs operation the response contains a separate
+ Job Object Attributes group 3 to N containing requested-attributes
+ for each job object in the response.
+
+
+3.1.2.1.5 Validate the values of the REQUIRED Operation attributes
+
+ An IPP object validates the values supplied by the client of the
+ REQUIRED Operation attribute that the IPP object MUST support. The
+ next section specifies the validation of the values of the OPTIONAL
+ Operation attributes that IPP objects MAY support.
+
+ The IPP object performs the following syntactic validation checks of
+ each Operation attribute value:
+
+ a) that the length of each Operation attribute value is
+ correct for the attribute syntax tag supplied by the client
+ according to [RFC2911] Section 4.1,
+
+ b) that the attribute syntax tag is correct for that Operation
+ attribute according to [RFC2911] Section 3,
+
+ c) that the value is in the range specified for that Operation
+ attribute according to [RFC2911] Section 3,
+
+ d) that multiple values are supplied by the client only for
+ operation attributes that are multi-valued, i.e., that are 1setOf
+ X according to [RFC2911] Section 3.
+
+
+
+ If any of these checks fail, the IPP object REJECTS the request and
+ RETURNS the 'client-error-bad-request' or the 'client-error-request-
+ value-too-long' status code. Since such an error is most likely to
+ be an error detected by a client developer, rather than by an end-
+ user, the IPP object NEED NOT return an indication of which attribute
+ had the error in either the Unsupported Attributes Group or the
+ Status Message. The description for each of these syntactic checks
+ is explicitly expressed in the first IF statement in the following
+ table.
+
+
+
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 28]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ In addition, the IPP object checks each Operation attribute value
+ against some Printer object attribute or some hard-coded value if
+ there is no "xxx-supported" Printer object attribute defined. If its
+ value is not among those supported or is not in the range supported,
+ then the IPP object REJECTS the request and RETURNS the error status
+ code indicated in the table by the second IF statement. If the value
+ of the Printer object's "xxx-supported" attribute is 'no-value'
+ (because the system administrator hasn't configured a value), the
+ check always fails.
+
+ -----------------------------------------------
+
+ attributes-charset (charset)
+
+ IF NOT a single non-empty 'charset' value, REJECT/RETURN
+ 'client-error-bad-request'.
+ IF the value length is greater than 63 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+ IF NOT in the Printer object's "charset-supported" attribute,
+ REJECT/RETURN "client-error-charset-not-supported".
+
+ attributes-natural-language(naturalLanguage)
+
+ IF NOT a single non-empty 'naturalLanguage' value, REJECT/RETURN
+ 'client-error-bad-request'.
+ IF the value length is greater than 63 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+ ACCEPT the request even if not a member of the set in the
+ Printer object's "generated-natural-language-supported"
+ attribute. If the supplied value is not a member of the
+ Printer object's "generated-natural-language-supported"
+ attribute, use the Printer object's "natural-language-
+ configured" value.
+
+ requesting-user-name
+
+ IF NOT a single 'name' value, REJECT/RETURN 'client-error-bad-
+ request'.
+ IF the value length is greater than 255 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+ IF the IPP object can obtain a better-authenticated name, use it
+ instead.
+
+ job-name(name)
+
+ IF NOT a single 'name' value, REJECT/RETURN 'client-error-bad-
+ request'.
+ IF the value length is greater than 255 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 29]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ IF NOT supplied by the client, the Printer object creates a name
+ from the document-name or document-uri.
+
+ document-name (name)
+
+ IF NOT a single 'name' value, REJECT/RETURN 'client-error-bad-
+ request'.
+ IF the value length is greater than 255 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+
+ ipp-attribute-fidelity (boolean)
+
+ IF NEITHER a single 'true' NOR a single 'false' 'boolean' value,
+ REJECT/RETURN 'client-error-bad-request'.
+ IF the value length is NOT equal to 1 octet, REJECT/RETURN
+ 'client-error-request-value-too-long'
+ IF NOT supplied by the client, the IPP object assumes the value
+ 'false'.
+
+ document-format (mimeMediaType)
+
+ IF NOT a single non-empty 'mimeMediaType' value, REJECT/RETURN
+ 'client-error-bad-request'.
+ IF the value length is greater than 255 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+ IF NOT in the Printer object's "document-format-supported"
+ attribute, REJECT/RETURN 'client-error-document-format-not-
+ supported'
+ IF NOT supplied by the client, the IPP object assumes the value
+ of the Printer object's "document-format-default"
+ attribute.
+
+ document-uri (uri)
+
+ IF NOT a single non-empty 'uri' value, REJECT/RETURN 'client-
+ error-bad-request'.
+ IF the value length is greater than 1023 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+ IF the URI syntax is not valid, REJECT/RETURN 'client-error-bad-
+ request'.
+ If the client-supplied URI scheme is not supported, i.e. the
+ value is not in the Printer object's referenced-uri-scheme-
+ supported" attribute, the Printer object MUST reject the
+ request and return the 'client-error-uri-scheme-not-
+ supported' status code. The Printer object MAY check to see
+ if the document exists and is accessible. If the document
+ is not found or is not accessible, REJECT/RETURN 'client-
+ error-not found'.
+ last-document (boolean)
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 30]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ IF NEITHER a single 'true' NOR a single 'false' 'boolean' value,
+ REJECT/RETURN 'client-error-bad-request'.
+ IF the value length is NOT equal to 1 octet, REJECT/RETURN
+ 'client-error-request-value-too-long'
+
+ job-id (integer(1:MAX))
+
+ IF NOT an single 'integer' value equal to 4 octets AND in the
+ range 1 to MAX, REJECT/RETURN 'client-error-bad-request'.
+ IF NOT a job-id of an existing Job object, REJECT/RETURN
+ 'client-error-not-found' or 'client-error-gone' status
+ code, if keep track of recently deleted jobs.
+
+ requested-attributes (1setOf keyword)
+
+ IF NOT one or more 'keyword' values, REJECT/RETURN 'client-
+ error-bad-request'.
+ IF the value length is greater than 255 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+ Ignore unsupported values, which are the keyword names of
+ unsupported attributes. Don't bother to copy such
+ requested (unsupported) attributes to the Unsupported
+ Attribute response group since the response will not return
+ them.
+
+ which-jobs (type2 keyword)
+
+ IF NOT a single 'keyword' value, REJECT/RETURN 'client-error-
+ bad-request'.
+ IF the value length is greater than 255 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+ IF NEITHER 'completed' NOR 'not-completed', copy the attribute
+ and the unsupported value to the Unsupported Attributes
+ response group and REJECT/RETURN 'client-error-attributes-
+ or-values-not-supported'.
+ Note: a Printer still supports the 'completed' value even if it
+ keeps no completed/canceled/aborted jobs: by returning no
+ jobs when so queried.
+ IF NOT supplied by the client, the IPP object assumes the 'not-
+ completed' value.
+
+ my-jobs (boolean)
+
+ IF NEITHER a single 'true' NOR a single 'false' 'boolean' value,
+ REJECT/RETURN 'client-error-bad-request'.
+ IF the value length is NOT equal to 1 octet, REJECT/RETURN
+ 'client-error-request-value-too-long'
+ IF NOT supplied by the client, the IPP object assumes the
+ 'false' value.
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 31]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ limit (integer(1:MAX))
+
+ IF NOT a single 'integer' value equal to 4 octets AND in the
+ range 1 to MAX, REJECT/RETURN 'client-error-bad-request'.
+ IF NOT supplied by the client, the IPP object returns all jobs,
+ no matter how many.
+
+ -----------------------------------------------
+
+
+
+3.1.2.1.6 Validate the values of the OPTIONAL Operation attributes
+
+ OPTIONAL Operation attributes are those that an IPP object MAY
+ support. An IPP object validates the values of the OPTIONAL
+ attributes supplied by the client. The IPP object performs the same
+ syntactic validation checks for each OPTIONAL attribute value as in
+ Section 3.1.2.1.5. As in Section 3.1.2.1.5, if any fail, the IPP
+ object REJECTS the request and RETURNS the 'client-error-bad-request'
+ or the 'client-error-request-value-too-long' status code.
+
+ In addition, the IPP object checks each Operation attribute value
+ against some Printer attribute or some hard-coded value if there is
+ no "xxx-supported" Printer attribute defined. If its value is not
+ among those supported or is not in the range supported, then the IPP
+ object REJECTS the request and RETURNS the error status code
+ indicated in the table. If the value of the Printer object's "xxx-
+ supported" attribute is 'no-value' (because the system administrator
+ hasn't configured a value), the check always fails.
+
+ If the IPP object doesn't recognize/support an attribute, the IPP
+ object treats the attribute as an unknown or unsupported attribute
+ (see the last row in the table below).
+
+ -----------------------------------------------
+
+ document-natural-language (naturalLanguage)
+
+ IF NOT a single non-empty 'naturalLanguage' value, REJECT/RETURN
+ 'client-error-bad-request'.
+ IF the value length is greater than 63 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+ IF NOT a value that the Printer object supports in document
+ formats, (no corresponding "xxx-supported" Printer attribute),
+ REJECT/RETURN 'client-error-natural-language-not-supported'.
+
+ compression (type3 keyword)
+
+ IF NOT a single 'keyword' value, REJECT/RETURN 'client-error-bad-
+ request'.
+
+
+Hastings, et al. Expires July 25, 2001 [page 32]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ IF the value length is greater than 255 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+ IF NOT in the Printer object's "compression-supported" attribute,
+ copy the attribute and the unsupported value to the
+ Unsupported Attributes response group and REJECT/RETURN
+ 'client-error-attributes-or-values-not-supported'.
+ Note to IPP/1.0 implementers: Support for the "compression"
+ attribute was optional in IPP/1.0 and was changed to REQUIRED
+ in IPP/1.1. However, an IPP/1.0 object SHOULD at least check
+ for the "compression" attribute being present and reject the
+ create request, if they don't support "compression". Not
+ checking is a bug, since the data will be unintelligible.
+
+ job-k-octets (integer(0:MAX))
+
+ IF NOT a single 'integer' value equal to 4 octets,
+ REJECT/RETURN 'client-error-bad-request'.
+ IF NOT in the range of the Printer object's "job-k-octets-
+ supported" attribute, copy the attribute and the unsupported
+ value to the Unsupported Attributes response group and
+ REJECT/RETURN 'client-error-attributes-or-values-not-
+ supported'.
+
+ job-impressions (integer(0:MAX))
+
+ IF NOT a single 'integer' value equal to 4 octets,
+ REJECT/RETURN 'client-error-bad-request'.
+ IF NOT in the range of the Printer object's "job-impressions-
+ supported" attribute, copy the attribute and the unsupported
+ value to the Unsupported Attributes response group and
+ REJECT/RETURN 'client-error-attributes-or-values-not-
+ supported'.
+
+ job-media-sheets (integer(0:MAX))
+
+ IF NOT a single 'integer' value equal to 4 octets,
+ REJECT/RETURN 'client-error-bad-request'.
+ IF NOT in the range of the Printer object's "job-media-sheets-
+ supported" attribute, copy the attribute and the unsupported
+ value to the Unsupported Attributes response group and
+ REJECT/RETURN 'client-error-attributes-or-values-not-
+ supported'.
+
+ message (text(127))
+
+ IF NOT a single 'text' value, REJECT/RETURN 'client-error-bad-
+ request'.
+ IF the value length is greater than 127 octets,
+ REJECT/RETURN 'client-error-request-value-too-long'.
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 33]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ unknown or unsupported attribute
+
+ IF the attribute syntax supplied by the client is supported but the
+ length is not legal for that attribute syntax, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+ ELSE copy the attribute and value to the Unsupported Attributes
+ response group and change the attribute value to the "out-of-
+ band" 'unsupported' value, but otherwise ignore the attribute.
+
+ Note: Future Operation attributes may be added to the protocol
+ specification that may occur anywhere in the specified group. When
+ the operation is otherwise successful, the IPP object returns the
+ 'successful-ok-ignored-or-substituted-attributes' status code.
+ Ignoring unsupported Operation attributes in all operations is
+ analogous to the handling of unsupported Job Template attributes in
+ the create and Validate-Job operations when the client supplies the
+ "ipp-attribute-fidelity" Operation attribute with the 'false' value.
+ This last rule is so that we can add OPTIONAL Operation attributes to
+ future versions of IPP so that older clients can inter-work with new
+ IPP objects and newer clients can inter-work with older IPP objects.
+ (If the new attribute cannot be ignored without performing
+ unexpectedly, the major version number would have been increased in
+ the protocol document and in the request). This rule for Operation
+ attributes is independent of the value of the "ipp-attribute-
+ fidelity" attribute. For example, if an IPP object doesn't support
+ the OPTIONAL "job-k-octets" attribute', the IPP object treats "job-k-
+ octets" as an unknown attribute and only checks the length for the
+ 'integer' attribute syntax supplied by the client. If it is not four
+ octets, the IPP object REJECTS the request and RETURNS the 'client-
+ error-bad-request' status code, else the IPP object copies the
+ attribute to the Unsupported Attribute response group, setting the
+ value to the "out-of-band" 'unsupported' value, but otherwise ignores
+ the attribute.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 34]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+3.1.2.2 Suggested Additional Processing Steps for Operations that
+ Create/Validate Jobs and Add Documents
+
+ This section in combination with the previous section recommends the
+ processing steps for the Print-Job, Validate-Job, Print-URI, Create-
+ Job, Send-Document, and Send-URI operations that IPP objects SHOULD
+ use. These are the operations that create jobs, validate a Print-Job
+ request, and add documents to a job.
+
+ IIG Sect # Flow IPP error status codes
+ ---------- ---- ----------------------
+ |
+ v No
+ 3.1.2.2.1 <ipp-attribute-fidelity> ------------------+
+ <supplied?> |
+ Yes| |
+ | ipp-attribute-fidelity = no |
+ |<------------------------------+
+ v No
+ 3.1.2.2.2 <Printer is> --> server-error-not-accepting-jobs
+ <accepting jobs?>
+ Yes|
+ v err
+ 3.1.2.3 <Validate values of> --> client-error-bad-request
+ <Job template attributes> client-error-request-value-too-
+ long
+ <(length, tag, range,>
+ <multi-value)>
+ ok|
+ v err
+ 3.1.2.3 <Validate values with> --> client-error-bad-request
+ <supported values> client-error-attributes-or-
+ | values-not-supported
+ v err
+ 3.1.2.3.1 <Any conflicting> --> client-error-conflicting-
+ attributes
+ <Job Template attr values> client-error-attributes-or-
+ values-not-supported
+ v
+
+3.1.2.2.1 Default "ipp-attribute-fidelity" if not supplied
+
+ The Printer object checks to see if the client supplied an "ipp-
+ attribute-fidelity" Operation attribute. If the attribute is not
+ supplied by the client, the IPP object assumes that the value is
+ 'false'.
+
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 35]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+3.1.2.2.2 Check that the Printer object is accepting jobs
+
+ If the value of the Printer objects "printer-is-accepting-jobs" is
+ 'false', the Printer object REJECTS the request and RETURNS the
+ 'server-error-not-accepting-jobs' status code.
+
+
+3.1.2.2.3 Validate the values of the Job Template attributes
+
+ An IPP object validates the values of all Job Template attribute
+ supplied by the client. The IPP object performs the analogous
+ syntactic validation checks of each Job Template attribute value that
+ it performs for Operation attributes (see Section 3.1.2.1.5.):
+
+ a) that the length of each value is correct for the attribute
+ syntax tag supplied by the client according to [RFC2911] Section
+ 4.1.
+
+ b) that the attribute syntax tag is correct for that attribute
+ according to [RFC2911] Sections 4.2 to 4.4.
+
+ c) that multiple values are supplied only for multi-valued
+ attributes, i.e., that are 1setOf X according to [RFC2911]
+ Sections 4.2 to 4.4.
+
+ As in Section 3.1.2.1.5, if any of these syntactic checks fail, the
+ IPP object REJECTS the request and RETURNS the 'client-error-bad-
+ request' or 'client-error-request-value-too-long' status code as
+ appropriate, independent of the value of the "ipp-attribute-
+ fidelity". Since such an error is most likely to be an error
+ detected by a client developer, rather than by an end-user, the IPP
+ object NEED NOT return an indication of which attribute had the error
+ in either the Unsupported Attributes Group or the Status Message.
+ The description for each of these syntactic checks is explicitly
+ expressed in the first IF statement in the following table.
+
+ Each Job Template attribute MUST occur no more than once. If an IPP
+ Printer receives a create request with multiple occurrences of a Job
+ Template attribute, it MAY:
+
+ 1. reject the operation and return the 'client-error-bad-request'
+ error status code
+
+ 2. accept the operation and use the first occurrence of the
+ attribute
+
+ 3. accept the operation and use the last occurrence of the
+ attribute
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 36]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ depending on implementation. Therefore, clients MUST NOT supply
+ multiple occurrences of the same Job Template attribute in the Job
+ Attributes group in the request.
+
+
+3.1.2.3 Algorithm for job validation
+
+ The process of validating a Job-Template attribute "xxx" against a
+ Printer attribute "xxx-supported" can use the following validation
+ algorithm (see section 3.2.1.2 in [RFC2911]).
+
+ To validate the value U of Job-Template attribute "xxx" against the
+ value V of Printer "xxx-supported", perform the following
+ algorithm:
+
+ 1.If U is multi-valued, validate each value X of U by performing
+ the algorithm in Table 7 with each value X. Each validation is
+ separate from the standpoint of returning unsupported values.
+ Example: If U is "finishings" that the client supplies with
+ 'staple', 'bind' values, then X takes on the successive values:
+ 'staple', then 'bind'
+
+ 2.If V is multi-valued, validate X against each Z of V by
+ performing the algorithm in Table 7 with each value Z. If a
+ value Z validates, the validation for the attribute value X
+ succeeds. If it fails, the algorithm is applied to the next
+ value Z of V. If there are no more values Z of V, validation
+ fails. Example" If V is "sides-supported" with values: 'one-
+ sided', 'two-sided-long', and 'two-sided-short', then Z takes on
+ the successive values: 'one-sided', 'two-sided-long', and 'two-
+ sided-short'. If the client supplies "sides" with 'two-sided-
+ long', the first comparison fails ('one-sided' is not equal to
+ 'two-sided-long'), the second comparison succeeds ('two-sided-
+ long' is equal to 'two-sided-long"), and the third comparison
+ ('two-sided-short' with 'two-sided-long') is not even performed.
+
+ 3.If both U and V are single-valued, let X be U and Z be V and use
+ the validation rules in Table 7.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 37]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ Table 7 - Rules for validating single values X against Z
+
+
+
+ Attribute syntax attribute syntax validated if:
+ of X of Z
+
+
+ integer rangeOfInteger X is within the range of Z
+
+ uri uriScheme the uri scheme in X is equal to
+ Z
+
+ any boolean the value of Z is TRUE
+
+ any any X and Z are of the same type
+ and are equal.
+
+
+
+ If the value of the Printer object's "xxx-supported" attribute is
+ 'no-value' (because the system administrator hasn't configured a
+ value), the check always fails. If the check fails, the IPP object
+ copies the attribute to the Unsupported Attributes response group
+ with its unsupported value. If the attribute contains more than one
+ value, each value is checked and each unsupported value is separately
+ copied, while supported values are not copied. If an IPP object
+ doesn't recognize/support a Job Template attribute, i.e., there is no
+ corresponding Printer object "xxx-supported" attribute, the IPP
+ object treats the attribute as an unknown or unsupported attribute
+ (see the last row in the table below).
+
+ If some Job Template attributes are supported for some document
+ formats and not for others or the values are different for different
+ document formats, the IPP object SHOULD take that into account in
+ this validation using the value of the "document-format" supplied by
+ the client (or defaulted to the value of the Printer's "document-
+ format-default" attribute, if not supplied by the client). For
+ example, if "number-up" is supported for the 'text/plain' document
+ format, but not for the 'application/postscript' document format, the
+ check SHOULD (though it NEED NOT) depend on the value of the
+ "document-format" operation attribute. See "document-format" in
+ [RFC2911] section 3.2.1.1 and 3.2.5.1.
+
+ Note: whether the request is accepted or rejected is determined by
+ the value of the "ipp-attribute-fidelity" attribute in a subsequent
+ step, so that all Job Template attribute supplied are examined and
+ all unsupported attributes and/or values are copied to the
+ Unsupported Attributes response group.
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 38]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ -----------------------------------------------
+
+ job-priority (integer(1:100))
+
+ IF NOT a single 'integer' value with a length equal to 4 octets,
+ REJECT/RETURN 'client-error-bad-request'.
+ IF NOT supplied by the client, use the value of the Printer
+ object's "job-priority-default" attribute at job submission
+ time.
+ IF NOT in the range 1 to 100, inclusive, copy the attribute and the
+ unsupported value to the Unsupported Attributes response
+ group.
+ Map the value to the nearest supported value in the range 1:100 as
+ specified by the number of discrete values indicated by the
+ value of the Printer's "job-priority-supported" attribute.
+ See the formula in [RFC2911] Section 4.2.1.
+
+ job-hold-until (type3 keyword | name)
+
+ IF NOT a single 'keyword' or 'name' value, REJECT/RETURN 'client-
+ error-bad-request'.
+ IF the value length is greater than 255 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+ IF NOT supplied by the client, use the value of the Printer
+ object's "job-hold-until" attribute at job submission time.
+ IF NOT in the Printer object's "job-hold-until-supported"
+ attribute, copy the attribute and the unsupported value to the
+ Unsupported Attributes response group.
+
+ job-sheets (type3 keyword | name)
+
+ IF NOT a single 'keyword' or 'name' value, REJECT/RETURN 'client-
+ error-bad-request'.
+ IF the value length is greater than 255 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+ IF NOT in the Printer object's "job-sheets-supported" attribute,
+ copy the attribute and the unsupported value to the
+ Unsupported Attributes response group.
+
+ multiple-document-handling (type2 keyword)
+
+ IF NOT a single 'keyword' value, REJECT/RETURN 'client-error-bad-
+ request'.
+ IF the value length is greater than 255 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+ IF NOT in the Printer object's "multiple-document-handling-
+ supported" attribute, copy the attribute and the unsupported
+ value to the Unsupported Attributes response group.
+
+ copies (integer(1:MAX))
+
+
+Hastings, et al. Expires July 25, 2001 [page 39]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ IF NOT a single 'integer' value with a length equal to 4 octets,
+ REJECT/RETURN 'client-error-bad-request'.
+ IF NOT in range of the Printer object's "copies-supported"
+ attribute
+ copy the attribute and the unsupported value to the Unsupported
+ Attributes response group.
+
+ finishings (1setOf type2 enum)
+
+ IF NOT an 'enum' value(s) each with a length equal to 4 octets,
+ REJECT/RETURN 'client-error-bad-request'.
+ IF NOT in the Printer object's "finishings-supported" attribute,
+ copy the attribute and the unsupported value(s), but not any
+ supported values, to the Unsupported Attributes response
+ group.
+
+ page-ranges (1setOf rangeOfInteger(1:MAX))
+
+ IF NOT a 'rangeOfInteger' value(s) each with a length equal to 8
+ octets, REJECT/RETURN 'client-error-bad-request'.
+ IF first value is greater than second value in any range, the
+ ranges are not in ascending order, or ranges overlap,
+ REJECT/RETURN 'client-error-bad-request'.
+ IF the value of the Printer object's "page-ranges-supported"
+ attribute is 'false', copy the attribute to the Unsupported
+ Attributes response group and set the value to the "out-of-
+ band" 'unsupported' value.
+
+ sides (type2 keyword)
+
+ IF NOT a single 'keyword' value, REJECT/RETURN 'client-error-bad-
+ request'.
+ IF the value length is greater than 255 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+ IF NOT in the Printer object's "sides-supported" attribute, copy
+ the attribute and the unsupported value to the Unsupported
+ Attributes response group.
+
+ number-up (integer(1:MAX))
+
+ IF NOT a single 'integer' value with a length equal to 4 octets,
+ REJECT/RETURN 'client-error-bad-request'.
+ IF NOT a value or in the range of one of the values of the Printer
+ object's "number-up-supported" attribute, copy the attribute
+ and value to the Unsupported Attribute response group.
+
+ orientation-requested (type2 enum)
+
+ IF NOT a single 'enum' value with a length equal to 4 octets,
+ REJECT/RETURN 'client-error-bad-request'.
+
+
+Hastings, et al. Expires July 25, 2001 [page 40]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ IF NOT in the Printer object's "orientation-requested-supported"
+ attribute, copy the attribute and the unsupported value to the
+ Unsupported Attributes response group.
+
+ media (type3 keyword | name)
+
+ IF NOT a single 'keyword' or 'name' value, REJECT/RETURN 'client-
+ error-bad-request'.
+ IF the value length is greater than 255 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+ IF NOT in the Printer object's "media-supported" attribute, copy
+ the attribute and the unsupported value to the Unsupported
+ Attributes response group.
+
+ printer-resolution (resolution)
+
+ IF NOT a single 'resolution' value with a length equal to 9 octets,
+ REJECT/RETURN 'client-error-bad-request'.
+ IF NOT in the Printer object's "printer-resolution-supported"
+ attribute, copy the attribute and the unsupported value to the
+ Unsupported Attributes response group.
+
+ print-quality (type2 enum)
+
+ IF NOT a single 'enum' value with a length equal to 4 octets,
+ REJECT/RETURN 'client-error-bad-request'.
+ IF NOT in the Printer object's "print-quality-supported" attribute,
+ copy the attribute and the unsupported value to the
+ Unsupported Attributes response group.
+
+ unknown or unsupported attribute (i.e., there is no corresponding
+ Printer object "xxx-supported" attribute)
+
+ IF the attribute syntax supplied by the client is supported but the
+ length is not legal for that attribute syntax,
+ REJECT/RETURN 'client-error-bad-request' if the length of the
+ attribute syntax is fixed or 'client-error-request-value-too-
+ long' if the length of the attribute syntax is variable.
+ ELSE copy the attribute and value to the Unsupported Attributes
+ response group and change the attribute value to the "out-of-
+ band" 'unsupported' value. Any remaining Job Template
+ Attributes are either unknown or unsupported Job Template
+ attributes and are validated algorithmically according to
+ their attribute syntax for proper length (see below).
+ -----------------------------------------------
+
+
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 41]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ If the attribute syntax is supported AND the length check fails, the
+ IPP object REJECTS the request and RETURNS the 'client-error-bad-
+ request' if the length of the attribute syntax is fixed or the
+ 'client-error-request-value-too-long' status code if the length of
+ the attribute syntax is variable. Otherwise, the IPP object copies
+ the unsupported Job Template attribute to the Unsupported Attributes
+ response group and changes the attribute value to the "out-of-band"
+ 'unsupported' value. The following table shows the length checks for
+ all attribute syntaxes. In the following table: "<=" means less
+ than or equal, "=" means equal to:
+
+ Name Octet length check for read-write attributes
+ ----------- --------------------------------------------
+ 'textWithLanguage <= 1023 AND 'naturalLanguage' <= 63
+ 'textWithoutLanguage' <= 1023
+ 'nameWithLanguage' <= 255 AND 'naturalLanguage' <= 63
+ 'nameWithoutLanguage' <= 255
+ 'keyword' <= 255
+ 'enum' = 4
+ 'uri' <= 1023
+ 'uriScheme' <= 63
+ 'charset' <= 63
+ 'naturalLanguage' <= 63
+ 'mimeMediaType' <= 255
+ 'octetString' <= 1023
+ 'boolean' = 1
+ 'integer' = 4
+ 'rangeOfInteger' = 8
+ 'dateTime' = 11
+ 'resolution' = 9
+ '1setOf X'
+
+ Note: It's possible for a Printer to receive a zero length keyword
+ in a request. Since this is a keyword, its value needs to be
+ compared with the supported values. Assuming that the printer
+ doesn't have any values in its corresponding "xxx-supported"
+ attribute that are keywords of zero length, the comparison will fail.
+ Then the request will be accepted or rejected depending on the value
+ of "ipp-attributes-fidelity" being 'false' or 'true', respectively.
+ No special handling is required for
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 42]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+3.1.2.3.1 Check for conflicting Job Template attributes values
+
+ Once all the Operation and Job Template attributes have been checked
+ individually, the Printer object SHOULD check for any conflicting
+ values among all the supported values supplied by the client. For
+ example, a Printer object might be able to staple and to print on
+ transparencies, however due to physical stapling constraints, the
+ Printer object might not be able to staple transparencies. The IPP
+ object copies the supported attributes and their conflicting
+ attribute values to the Unsupported Attributes response group. The
+ Printer object only copies over those attributes that the Printer
+ object either ignores or substitutes in order to resolve the
+ conflict, and it returns the original values which were supplied by
+ the client. For example suppose the client supplies "finishings"
+ equals 'staple' and "media" equals 'transparency', but the Printer
+ object does not support stapling transparencies. If the Printer
+ chooses to ignore the stapling request in order to resolve the
+ conflict, the Printer objects returns "finishings" equal to 'staple'
+ in the Unsupported Attributes response group. If any attributes are
+ multi-valued, only the conflicting values of the attributes are
+ copied.
+
+ Note: The decisions made to resolve the conflict (if there is a
+ choice) is implementation dependent.
+
+
+3.1.2.3.2 Decide whether to REJECT the request
+
+ If there were any unsupported Job Template attributes or
+ unsupported/conflicting Job Template attribute values and the client
+ supplied the "ipp-attribute-fidelity" attribute with the 'true'
+ value, the Printer object REJECTS the request and return the status
+ code:
+
+ 1. 'client-error-conflicting-attributes' status code, if there were
+ any conflicts between attributes supplied by the client.
+ 2. 'client-error-attributes-or-values-not-supported' status code,
+ otherwise.
+
+ Note: Unsupported Operation attributes or values that are returned
+ do not affect the status returned in this step. If the unsupported
+ Operation attribute was a serious error, the above already rejected
+ the request in a previous step. If control gets to this step with
+ unsupported Operation attributes being returned, they are not serious
+ errors.
+
+
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 43]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ In general, the final results of Job processing are unknown at Job
+ submission time. The client has to rely on notifications or polling
+ to find out what happens at Job processing time. However, there are
+ cases in which some Printers can determine at Job submission time
+ that Job processing is going to fail. As an optimization, we'd like
+ to have the Printer reject the Job in these cases.
+
+ There are three types of "processing" errors that might be detectable
+ at Job submission time:
+
+ 1. 'client-error-document-format-not-supported' : For the Print-
+ Job, Send-Document, Print-URI, and Send-URI operations, if all these
+ conditions are true:
+
+ - the Printer supports auto-sensing,
+ - the request "document-format" operation attribute is
+ 'application/octet-stream',
+ - the Printer receives document data before responding,
+ - the Printer auto-senses the document format before responding,
+ - the sensed document format is not supported by the Printer
+ then the Printer should respond with 'client-error-document-format-
+ not-supported' status.
+
+ 2. 'client-error-compression-error': For the Print-Job, Send-
+ Document, Print-URI, and Send-URI operations, if all these
+ conditions are true:
+
+ - the client supplies a supported value for the "compression"
+ operation attribute in the request
+ - the Printer receives document data before responding,
+ - the Printer attempts to decompress the document data before
+ responding,
+ - the document data cannot be decompressed using the algorithm
+ specified by the "compression" operation attribute
+ then the Printer should respond with 'client-error-compression-error'
+ status.
+
+ 3. 'client-error-document-access-error': For the Print-URI, and
+ Send-URI operations, if the Printer attempts and fails to pull the
+ referenced document data before responding, it should respond with
+ 'client-error-document-access-error' status.
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 44]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ Some Printers are not able to detect these errors until Job
+ processing time. In that case, the errors are recorded in the
+ corresponding job-state and job-state reason attributes. (There is
+ no standard way for a client to determine whether a Printer can
+ detect these errors at Job submission time.) For example, if auto-
+ sensing happens AFTER the job is accepted (as opposed to auto-sensing
+ at submit time before returning the response), the implementation
+ aborts the job, puts the job in the 'aborted' state and sets the
+ 'unsupported-document-format' value in the job's "job-state-reasons".
+
+ A client should always provide a valid "document-format" operation
+ attribute whenever practical. In the absence of other information, a
+ client itself may sniff the document data to determine document
+ format.
+
+ Auto sensing at Job submission time may be more difficult for the
+ Printer when combined with compression. For auto-sensed Jobs, a
+ client may be better off deferring compression to the transfer
+ protocol layer, e.g.; by using the HTTP Content-Encoding header.
+
+
+3.1.2.3.3 For the Validate-Job operation, RETURN one of the success
+ status codes
+
+ If the requested operation is the Validate-Job operation, the Printer
+ object returns:
+
+ 1. the "successful-ok" status code, if there are no unsupported or
+ conflicting Job Template attributes or values.
+ 2. the "successful-ok-conflicting-attributes, if there are any
+ conflicting Job Template attribute or values.
+ 3. the "successful-ok-ignored-or-substituted-attributes, if there
+ are only unsupported Job Template attributes or values.
+
+
+ Note: Unsupported Operation attributes or values that are returned
+ do not affect the status returned in this step. If the unsupported
+ Operation attribute was a serious error, the above already rejected
+ the request in a previous step. If control gets to this step with
+ unsupported Operation attributes being returned, they are not serious
+ errors.
+
+
+3.1.2.3.4 Create the Job object with attributes to support
+
+ If "ipp-attribute-fidelity" is set to 'false' (or it was not supplied
+ by the client), the Printer object:
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 45]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ 1. creates a Job object, assigns a unique value to the job's "job-
+ uri" and "job-id" attributes, and initializes all of the job's
+ other supported Job Description attributes.
+ 2. removes all unsupported attributes from the Job object.
+ 3. for each unsupported value, removes either the unsupported value
+ or substitutes the unsupported attribute value with some
+ supported value. If an attribute has no values after removing
+ unsupported values from it, the attribute is removed from the
+ Job object (so that the normal default behavior at job
+ processing time will take place for that attribute).
+ 4. for each conflicting value, removes either the conflicting value
+ or substitutes the conflicting attribute value with some other
+ supported value. If an attribute has no values after removing
+ conflicting values from it, the attribute is removed from the
+ Job object (so that the normal default behavior at job
+ processing time will take place for that attribute).
+
+ If there were no attributes or values flagged as unsupported, or the
+ value of 'ipp-attribute-fidelity" was 'false', the Printer object is
+ able to accept the create request and create a new Job object. If
+ the "ipp-attribute-fidelity" attribute is set to 'true', the Job
+ Template attributes that populate the new Job object are necessarily
+ all the Job Template attributes supplied in the create request. If
+ the "ipp-attribute-fidelity" attribute is set to 'false', the Job
+ Template attributes that populate the new Job object are all the
+ client supplied Job Template attributes that are supported or that
+ have value substitution. Thus, some of the requested Job Template
+ attributes will not appear in the Job object because the Printer
+ object did not support those attributes. The attributes that
+ populate the Job object are persistently stored with the Job object
+ for that Job. A Get-Job-Attributes operation on that Job object will
+ return only those attributes that are persistently stored with the
+ Job object.
+
+ Note: All Job Template attributes that are persistently stored with
+ the Job object are intended to be "override values"; that is, they
+ that take precedence over whatever other embedded instructions might
+ be in the document data itself. However, it is not possible for all
+ Printer objects to realize the semantics of "override". End users
+ may query the Printer's "pdl-override-supported" attribute to
+ determine if the Printer either attempts or does not attempt to
+ override document data instructions with IPP attributes.
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 46]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ There are some cases, where a Printer supports a Job Template
+ attribute and has an associated default value set for that attribute.
+ In the case where a client does not supply the corresponding
+ attribute, the Printer does not use its default values to populate
+ Job attributes when creating the new Job object; only Job Template
+ attributes actually in the create request are used to populate the
+ Job object. The Printer's default values are only used later at Job
+ processing time if no other IPP attribute or instruction embedded in
+ the document data is present.
+
+ Note: If the default values associated with Job Template attributes
+ that the client did not supply were to be used to populate the Job
+ object, then these values would become "override values" rather than
+ defaults. If the Printer supports the 'attempted' value of the "pdl-
+ override-supported" attribute, then these override values could
+ replace values specified within the document data. This is not the
+ intent of the default value mechanism. A default value for an
+ attribute is used only if the create request did not specify that
+ attribute (or it was ignored when allowed by "ipp-attribute-fidelity"
+ being 'false') and no value was provided within the content of the
+ document data.
+
+ If the client does not supply a value for some Job Template
+ attribute, and the Printer does not support that attribute, as far as
+ IPP is concerned, the result of processing that Job (with respect to
+ the missing attribute) is undefined.
+
+
+3.1.2.3.5 Return one of the success status codes
+
+ Once the Job object has been created, the Printer object accepts the
+ request and returns to the client:
+
+ 1. the 'successful-ok' status code, if there are no unsupported or
+ conflicting Job Template attributes or values.
+ 2. the 'successful-ok-conflicting-attributes' status code, if there
+ are any conflicting Job Template attribute or values.
+ 3. the 'successful-ok-ignored-or-substituted-attributes' status
+ code, if there are only unsupported Job Template attributes or
+ values.
+
+ Note: Unsupported Operation attributes or values that are returned
+ do not affect the status returned in this step. If the unsupported
+ Operation attribute was a serious error, the above already rejected
+ the request in a previous step. If control gets to this step with
+ unsupported Operation attributes being returned, they are not serious
+ errors.
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 47]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ The Printer object also returns Job status attributes that indicate
+ the initial state of the Job ('pending', 'pending-held',
+ 'processing', etc.), etc. See Print-Job Response, [RFC2911] section
+ 3.2.1.2.
+
+
+3.1.2.3.6 Accept appended Document Content
+
+ The Printer object accepts the appended Document Content data and
+ either starts it printing, or spools it for later processing.
+
+
+3.1.2.3.7 Scheduling and Starting to Process the Job
+
+ The Printer object uses its own configuration and implementation
+ specific algorithms for scheduling the Job in the correct processing
+ order. Once the Printer object begins processing the Job, the
+ Printer changes the Job's state to 'processing'. If the Printer
+ object supports PDL override (the "pdl-override-supported" attribute
+ set to 'attempted'), the implementation does its best to see that IPP
+ attributes take precedence over embedded instructions in the document
+ data.
+
+
+3.1.2.3.8 Completing the Job
+
+ The Printer object continues to process the Job until it can move the
+ Job into the 'completed' state. If an Cancel-Job operation is
+ received, the implementation eventually moves the Job into the
+ 'canceled' state. If the system encounters errors during processing
+ that do not allow it to progress the Job into a completed state, the
+ implementation halts all processing, cleans up any resources, and
+ moves the Job into the 'aborted' state.
+
+
+3.1.2.3.9 Destroying the Job after completion
+
+ Once the Job moves to the 'completed', 'aborted', or 'canceled'
+ state, it is an implementation decision as to when to destroy the Job
+ object and release all associated resources. Once the Job has been
+ destroyed, the Printer would return either the "client-error-not-
+ found" or "client-error-gone" status codes for operations directed at
+ that Job.
+
+ Note: the Printer object SHOULD NOT re-use a "job-uri" or "job-id"
+ value for a sufficiently long time after a job has been destroyed, so
+ that stale references kept by clients are less likely to access the
+ wrong (newer) job.
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 48]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+3.1.2.3.10 Interaction with "ipp-attribute-fidelity"
+
+ Some Printer object implementations may support "ipp-attribute-
+ fidelity" set to 'true' and "pdl-override-supported" set to
+ 'attempted' and yet still not be able to realize exactly what the
+ client specifies in the create request. This is due to legacy
+ decisions and assumptions that have been made about the role of job
+ instructions embedded within the document data and external job
+ instructions that accompany the document data and how to handle
+ conflicts between such instructions. The inability to be 100%
+ precise about how a given implementation will behave is also
+ compounded by the fact that the two special attributes, "ipp-
+ attribute-fidelity" and "pdl-"override-supported", apply to the whole
+ job rather than specific values for each attribute. For example, some
+ implementations may be able to override almost all Job Template
+ attributes except for "number-up". Character Sets, natural languages,
+ and internationalization
+
+ This section discusses character set support, natural language
+ support and internationalization.
+
+
+3.1.2.3.11 Character set code conversion support
+
+ IPP clients and IPP objects are REQUIRED to support UTF-8. They MAY
+ support additional charsets. It is RECOMMENDED that an IPP object
+ also support US-ASCII, since many clients support US-ASCII, and
+ indicate that UTF-8 and US-ASCII are supported by populating the
+ Printer's "charset-supported" with 'utf-8' and 'us-ascii' values. An
+ IPP object is required to code covert with as little loss as possible
+ between the charsets that it supports, as indicated in the Printer's
+ "charsets-supported" attribute.
+
+ How should the server handle the situation where the "attributes-
+ charset" of the response itself is "us-ascii", but one or more
+ attributes in that response is in the "utf-8" format?
+
+ Example: Consider a case where a client sends a Print-Job request
+ with "utf-8" as the value of "attributes-charset" and with the "job-
+ name" attribute supplied. Later another client submits a Get-Job-
+ Attribute or Get-Jobs request. This second request contains the
+ "attributes-charset" with value "us-ascii" and "requested-attributes"
+ attribute with exactly one value "job-name".
+
+
+
+
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 49]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ According to the RFC2911 document (section 3.1.4.2), the value of the
+ "attributes-charset" for the response of the second request must be
+ "us-ascii" since that is the charset specified in the request. The
+ "job-name" value, however, is in "utf-8" format. Should the request
+ be rejected even though both "utf-8" and "us-ascii" charsets are
+ supported by the server? or should the "job-name" value be converted
+ to "us-ascii" and return "successful-ok-conflicting-attributes"
+ (0x0002) as the status code?
+
+ Answer: An IPP object that supports both utf-8 (REQUIRED) and us-
+ ascii, the second paragraph of section 3.1.4.2 applies so that the
+ IPP object MUST accept the request, perform code set conversion
+ between these two charsets with "the highest fidelity possible" and
+ return 'successful-ok', rather than a warning 'successful-ok-
+ conflicting-attributes, or an error. The printer will do the best it
+ can to convert between each of the character sets that it supports--
+ even if that means providing a string of question marks because none
+ of the characters are representable in US ASCII. If it can't perform
+ such conversion, it MUST NOT advertise us-ascii as a value of its
+ "attributes-charset-supported" and MUST reject any request that
+ requests 'us-ascii'.
+
+ One IPP object implementation strategy is to convert all request text
+ and name values to a Unicode internal representation. This is 16-bit
+ and virtually universal. Then convert to the specified operation
+ attributes-charset on output.
+
+ Also it would be smarter for a client to ask for 'utf-8', rather than
+ 'us-ascii' and throw away characters that it doesn't understand,
+ rather than depending on the code conversion of the IPP object.
+
+
+3.1.2.3.12 What charset to return when an unsupported charset is
+ requested (Issue 1.19)?
+
+ Section 3.1.4.1 Request Operation attributes was clarified in
+ November 1998 as follows:
+
+ All clients and IPP objects MUST support the 'utf-8' charset
+ [RFC2044] and MAY support additional charsets provided that they are
+ registered with IANA [IANA-CS]. If the Printer object does not
+ support the client supplied charset value, the Printer object MUST
+ reject the request, set the "attributes-charset" to 'utf-8' in the
+ response, and return the 'client-error-charset-not-supported' status
+ code and any 'text' or 'name' attributes using the 'utf-8' charset.
+
+ Since the client and IPP object MUST support UTF-8, returning any
+ text or name attributes in UTF-8 when the client requests a charset
+ that is not supported should allow the client to display the text or
+ name.
+
+
+Hastings, et al. Expires July 25, 2001 [page 50]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ Since such an error is a client error, rather than a user error, the
+ client should check the status code first so that it can avoid
+ displaying any other returned 'text' and 'name' attributes that are
+ not in the charset requested.
+
+ Furthermore, [RFC2911] section 14.1.4.14 client-error-charset-not-
+ supported (0x040D) was clarified in November 1998 as follows:
+
+ For any operation, if the IPP Printer does not support the charset
+ supplied by the client in the "attributes-charset" operation
+ attribute, the Printer MUST reject the operation and return this
+ status and any 'text' or 'name' attributes using the 'utf-8' charset
+ (see Section 3.1.4.1).
+
+
+3.1.2.3.13 Natural Language Override (NLO)
+
+ The 'text' and 'name' attributes each have two forms. One has an
+ implicit natural language, and the other has an explicit natural
+ language. The 'textWithoutLanguage' and 'textWithLanguage' are the
+ two 'text' forms. The 'nameWithoutLanguage" and 'nameWithLanguage
+ are the two 'name' forms. If a receiver (IPP object or IPP client)
+ supports an attribute with attribute syntax 'text', it MUST support
+ both forms in a request and a response. A sender (IPP client or IPP
+ object) MAY send either form for any such attribute. When a sender
+ sends a WithoutLanguage form, the implicit natural language is
+ specified in the "attributes-natural-language" operation attribute,
+ which all senders MUST include in every request and response.
+
+ When a sender sends a WithLanguage form, it MAY be different from the
+ implicit natural language supplied by the sender or it MAY be the
+ same. The receiver MUST treat either form equivalently.
+
+ There is an implementation decision for senders, whether to always
+ send the WithLanguage forms or use the WithoutLanguage form when the
+ attribute's natural language is the same as the request or response.
+ The former approach makes the sender implementation simpler. The
+ latter approach is more efficient on the wire and allows inter-
+ working with non-conforming receivers that fail to support the
+ WithLanguage forms. As each approach have advantages, the choice is
+ completely up to the implementer of the sender.
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 51]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ Furthermore, when a client receives a 'text' or 'name' job attribute
+ that it had previously supplied, that client MUST NOT expect to see
+ the attribute in the same form, i.e., in the same WithoutLanguage or
+ WithLanguage form as the client supplied when it created the job.
+ The IPP object is free to transform the attribute from the
+ WithLanguage form to the WithoutLanguage form and vice versa, as long
+ as the natural language is preserved. However, in order to meet this
+ latter requirement, it is usually simpler for the IPP object
+ implementation to store the natural language explicitly with the
+ attribute value, i.e., to store using an internal representation that
+ resembles the WithLanguage form.
+
+ The IPP Printer MUST copy the natural language of a job, i.e., the
+ value of the "attributes-natural-language" operation attribute
+ supplied by the client in the create operation, to the Job object as
+ a Job Description attribute, so that a client is able to query it.
+ In returning a Get-Job-Attributes response, the IPP object MAY return
+ one of three natural language values in the response's "attributes-
+ natural-language" operation attribute: (1) that requested by the
+ requester, (2) the natural language of the job, or (3) the configured
+ natural language of the IPP Printer, if the requested language is not
+ supported by the IPP Printer.
+
+ This "attributes-natural-language" Job Description attribute is
+ useful for an IPP object implementation that prints start sheets in
+ the language of the user who submitted the job. This same Job
+ Description attribute is useful to a multi-lingual operator who has
+ to communicate with different job submitters in different natural
+ languages. This same Job Description attribute is expected to be
+ used in the future to generate notification messages in the natural
+ language of the job submitter.
+
+ Early drafts of [RFC2911] contained a job-level natural language
+ override (NLO) for the Get-Jobs response. A job-level (NLO) is an
+ (unrequested) Job Attribute which then specified the implicit natural
+ language for any other WithoutLanguage job attributes returned in the
+ response for that job. Interoperability testing of early
+ implementations showed that no one was implementing the job-level NLO
+ in Get-Job responses. So the job-level NLO was eliminated from the
+ Get-Jobs response. This simplification makes all requests and
+ responses consistent in that the implicit natural language for any
+ WithoutLanguage 'text' or 'name' form is always supplied in the
+ request's or response's "attributes-natural-language" operation
+ attribute.
+
+
+
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 52]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+3.1.3 Status codes returned by operation
+
+ This section corresponds to [RFC2911] section 3.1.6 "Operation
+ Response Status Codes and Status Messages". This section lists all
+ status codes once in the first operation (Print-Job). Then it lists
+ the status codes that are different or specialized for subsequent
+ operations under each operation.
+
+
+3.1.3.1 Printer Operations
+
+
+3.1.3.1.1 Print-Job
+
+ The Printer object MUST return one of the following "status-code"
+ values for the indicated reason. Whether all of the document data
+ has been accepted or not before returning the success or error
+ response depends on implementation. See Section 13 in [RFC2911] for
+ a more complete description of each status code.
+
+ For the following success status codes, the Job object has been
+ created and the "job-id", and "job-uri" assigned and returned in the
+ response:
+
+ successful-ok: no request attributes were substituted or ignored.
+ successful-ok-ignored-or-substituted-attributes: some supplied (1)
+ attributes were ignored or (2) unsupported attribute syntaxes or
+ values were substituted with supported values or were ignored.
+ Unsupported attributes, attribute syntax's, or values MUST be
+ returned in the Unsupported Attributes group of the response.
+ successful-ok-conflicting-attributes: some supplied attribute
+ values conflicted with the values of other supplied attributes
+ and were either substituted or ignored. Attributes or values
+ which conflict with other attributes and have been substituted
+ or ignored MUST be returned in the Unsupported Attributes group
+ of the response as supplied by the client.
+
+ [RFC2911] section 3.1.6 Operation Status Codes and Messages states:
+
+ If the Printer object supports the "status-message" operation
+ attribute, it SHOULD use the REQUIRED 'utf-8' charset to return a
+ status message for the following error status codes (see section 13
+ in [RFC2911]): 'client-error-bad-request', 'client-error-charset-
+ not-supported', 'server-error-internal-error', 'server-error-
+ operation-not-supported', and 'server-error-version-not-supported'.
+ In this case, it MUST set the value of the "attributes-charset"
+ operation attribute to 'utf-8' in the error response.
+
+ For the following error status codes, no job is created and no
+ "job-id" or "job-uri" is returned:
+
+
+Hastings, et al. Expires July 25, 2001 [page 53]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ client-error-bad-request: The request syntax does not conform
+ to the specification.
+ client-error-forbidden: The request is being refused for
+ authorization or authentication reasons. The implementation
+ security policy is to not reveal whether the failure is one of
+ authentication or authorization.
+ client-error-not-authenticated: Either the request requires
+ authentication information to be supplied or the
+ authentication information is not sufficient for
+ authorization.
+ client-error-not-authorized: The requester is not authorized to
+ perform the request on the target object.
+ client-error-not-possible: The request cannot be carried out
+ because of the state of the system. See also 'server-error-
+ not-accepting-jobs' status code, which MUST take precedence if
+ the Printer object's "printer-accepting-jobs" attribute is
+ 'false'.
+ client-error-timeout: not applicable.
+ client-error-not-found: the target object does not exist.
+ client-error-gone: the target object no longer exists and no
+ forwarding address is known.
+ client-error-request-entity-too-large: the size of the request
+ and/or print data exceeds the capacity of the IPP Printer to
+ process it.
+ client-error-request-value-too-long: the size of request
+ variable length attribute values, such as 'text' and 'name'
+ attribute syntax's, exceed the maximum length specified in
+ [RFC2911] for the attribute and MUST be returned in the
+ Unsupported Attributes Group.
+ client-error-document-format-not-supported: the document format
+ supplied is not supported. The "document-format" attribute
+ with the unsupported value MUST be returned in the Unsupported
+ Attributes Group. This error SHOULD take precedence over any
+ other 'xxx-not-supported' error, except 'client-error-charset-
+ not-supported'.
+ client-error-attributes-or-values-not-supported: one or more
+ supplied attributes, attribute syntax's, or values are not
+ supported and the client supplied the "ipp-attributes-
+ fidelity" operation attribute with a 'true' value. They MUST
+ be returned in the Unsupported Attributes Group as explained
+ below.
+ client-error-uri-scheme-not-supported: not applicable.
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 54]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ client-error-charset-not-supported: the charset supplied in the
+ "attributes-charset" operation attribute is not supported.
+ The Printer's "configured-charset" MUST be returned in the
+ response as the value of the "attributes-charset" operation
+ attribute and used for any 'text' and 'name' attributes
+ returned in the error response. This error SHOULD take
+ precedence over any other error, unless the request syntax is
+ so bad that the client's supplied "attributes-charset" cannot
+ be determined.
+ client-error-conflicting-attributes: one or more supplied
+ attribute values conflicted with each other and the client
+ supplied the "ipp-attributes-fidelity" operation attribute
+ with a 'true' value. They MUST be returned in the Unsupported
+ Attributes Group as explained below.
+ server-error-internal-error: an unexpected condition prevents
+ the request from being fulfilled.
+ server-error-operation-not-supported: not applicable (since
+ Print-Job is REQUIRED).
+ server-error-service-unavailable: the service is temporarily
+ overloaded.
+ server-error-version-not-supported: the version in the request
+ is not supported. The "closest" version number supported MUST
+ be returned in the response.
+ server-error-device-error: a device error occurred while
+ receiving or spooling the request or document data or the IPP
+ Printer object can only accept one job at a time.
+ server-error-temporary-error: a temporary error such as a
+ buffer full write error, a memory overflow, or a disk full
+ condition occurred while receiving the request and/or the
+ document data.
+ server-error-not-accepting-jobs: the Printer object's "printer-
+ is-not-accepting-jobs" attribute is 'false'.
+ server-error-busy: the Printer is too busy processing jobs to
+ accept another job at this time.
+ server-error-job-canceled: the job has been canceled by an
+ operator or the system while the client was transmitting the
+ document data.
+
+3.1.3.1.2 Print-URI
+
+ All of the Print-Job status codes described in Section 3.1.3.1.1
+ Print-Job Response are applicable to Print-URI with the following
+ specializations and differences. See Section 14 for a more complete
+ description of each status code.
+
+ client-error-uri-scheme-not-supported: the URI scheme supplied in
+ the "document-uri" operation attribute is not supported and is
+ returned in the Unsupported Attributes group.
+ server-error-operation-not-supported: the Print-URI operation is
+ not supported.
+
+
+Hastings, et al. Expires July 25, 2001 [page 55]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+
+
+3.1.3.1.3 Validate-Job
+
+ All of the Print-Job status codes described in Section 3.1.3.1.1
+ Print-Job Response are applicable to Validate-Job. See Section 13 in
+ [RFC2911] for a more complete description of each status code.
+
+
+3.1.3.1.4 Create-Job
+
+ All of the Print-Job status codes described in Section 3.1.3.1.1
+ Print-Job Response are applicable to Create-Job with the following
+ specializations and differences. See Section 13 in [RFC2911] for a
+ more complete description of each status code.
+
+ server-error-operation-not-supported: the Create-Job operation is
+ not supported.
+ client-error-multiple-document-jobs-not-supported: while the
+ Create-Job and Send-Document operations are supported, this
+ implementation doesn't support more than one document with data.
+
+3.1.3.1.5 Get-Printer-Attributes
+
+ All of the Print-Job status codes described in Section 3.1.3.1.1
+ Print-Job Response are applicable to the Get-Printer-Attributes
+ operation with the following specialization's and differences. See
+ Section 13 in [RFC2911] for a more complete description of each
+ status code.
+
+ For the following success status codes, the requested attributes are
+ returned in Group 3 in the response:
+
+ successful-ok: no operation attributes or values were substituted
+ or ignored (same as Print-Job) and no requested attributes were
+ unsupported.
+ successful-ok-ignored-or-substituted-attributes: The "requested-
+ attributes" operation attribute MAY, but NEED NOT, be returned
+ with the unsupported values.
+ successful-ok-conflicting-attributes: same as Print-Job.
+
+ For the error status codes, Group 3 is returned containing no
+ attributes or is not returned at all:
+
+ client-error-not-possible: Same as Print-Job, in addition the
+ Printer object is not accepting any requests.
+ client-error-request-entity-too-large: same as Print-job, except
+ that no print data is involved.
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 56]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ client-error-attributes-or-values-not-supported: not applicable,
+ since unsupported operation attributes and/or values MUST be
+ ignored and an appropriate success code returned (see above).
+ client-error-conflicting-attributes: same as Print-Job, except
+ that "ipp-attribute-fidelity" is not involved.
+ server-error-operation-not-supported: not applicable (since Get-
+ Printer-Attributes is REQUIRED).
+ server-error-device-error: same as Print-Job, except that no
+ document data is involved.
+ server-error-temporary-error: same as Print-Job, except that no
+ document data is involved.
+ server-error-not-accepting-jobs: not applicable.
+ server-error-busy: same as Print-Job, except the IPP object is too
+ busy to accept even query requests.
+ server-error-job-canceled: not applicable.
+
+3.1.3.1.6 Get-Jobs
+
+ All of the Print-Job status codes described in Section 3.1.3.1.1
+ Print-Job Response are applicable to the Get-Jobs operation with the
+ following specialization's and differences. See Section 13 in
+ [RFC2911] for a more complete description of each status code.
+
+ For the following success status codes, the requested attributes are
+ returned in Group 3 in the response:
+
+ successful-ok: same as Get-Printer-Attributes (see section
+ 3.1.3.1.5).
+ successful-ok-ignored-or-substituted-attributes: same as Get-
+ Printer-Attributes (see section 3.1.3.1.5).
+ successful-ok-conflicting-attributes: same as Get-Printer-
+ Attributes (see section 3.1.3.1.5).
+
+ For any error status codes, Group 3 is returned containing no
+ attributes or is not returned at all. The following brief error
+ status code descriptions contain unique information for use with Get-
+ Jobs operation. See section 14 for the other error status codes that
+ apply uniformly to all operations:
+
+ client-error-not-possible: Same as Print-Job, in addition the
+ Printer object is not accepting any requests.
+ client-error-request-entity-too-large: same as Print-job,
+ except that no print data is involved.
+ client-error-document-format-not-supported: not applicable.
+ client-error-attributes-or-values-not-supported: not
+ applicable, since unsupported operation attributes and/or
+ values MUST be ignored and an appropriate success code
+ returned (see above).
+ client-error-conflicting-attributes: same as Print-Job, except
+ that "ipp-attribute-fidelity" is not involved.
+
+
+Hastings, et al. Expires July 25, 2001 [page 57]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ server-error-operation-not-supported: not applicable (since
+ Get-Jobs is REQUIRED).
+ server-error-device-error: same as Print-Job, except that no
+ document data is involved.
+ server-error-temporary-error: same as Print-Job, except that no
+ document data is involved.
+ server-error-not-accepting-jobs: not applicable.
+ server-error-job-canceled: not applicable.
+
+3.1.3.1.7 Pause-Printer
+
+ All of the Print-Job status codes described in Section 3.1.3.1.1
+ Print-Job Response are applicable to Pause-Printer with the following
+ specializations and differences. See Section 13 in [RFC2911] for a
+ more complete description of each status code.
+
+ For the following success status codes, the Printer object is being
+ stopped from scheduling jobs on all its devices.
+
+ successful-ok: no request attributes were substituted or
+ ignored (same as Print-Job).
+ successful-ok-ignored-or-substituted-attributes: same as
+ Print-Job.
+ successful-ok-conflicting-attributes: same as Print-Job.
+
+ For any of the error status codes, the Printer object has not been
+ stopped from scheduling jobs on all its devices.
+
+ client-error-not-possible: not applicable.
+ client-error-not-found: the target Printer object does not
+ exist.
+ client-error-gone: the target Printer object no longer exists
+ and no forwarding address is known.
+ client-error-request-entity-too-large: same as Print-Job,
+ except no document data is involved.
+ client-error-document-format-not-supported: not applicable.
+ client-error-conflicting-attributes: same as Print-Job, except
+ that the Printer's "printer-is-accepting-jobs" attribute is
+ not involved.
+ server-error-operation-not-supported: the Pause-Printer
+ operation is not supported.
+ server-error-device-error: not applicable.
+ server-error-temporary-error: same as Print-Job, except no
+ document data is involved.
+ server-error-not-accepting-jobs: not applicable.
+ server-error-job-canceled: not applicable.
+
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 58]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+3.1.3.1.8 Resume-Printer
+
+ All of the Print-Job status code descriptions in Section 3.1.3.1.1
+ Print-Job Response with the specialization's described for Pause-
+ Printer are applicable to Resume-Printer. See Section 13 in
+ [RFC2911] for a more complete description of each status code.
+
+ For the following success status codes, the Printer object resumes
+ scheduling jobs on all its devices.
+
+ successful-ok: no request attributes were substituted or
+ ignored (same as Print-Job).
+ successful-ok-ignored-or-substituted-attributes: same as
+ Print-Job.
+ successful-ok-conflicting-attributes: same as Print-Job.
+
+ For any of the error status codes, the Printer object does not resume
+ scheduling jobs.
+
+ server-error-operation-not-supported: the Resume-Printer
+ operation is not supported.
+
+
+3.1.3.1.8.1 What about Printers unable to change state due to an error
+ condition?
+ If, in case, the IPP printer is unable to change its state due to
+ some problem with the actual printer device (say, it is shut down or
+ there is a media-jam as indicated in [RFC2911]), what should be the
+ result of the "Resume-Printer" operation? Should it still change the
+ 'printer-state-reasons' and return success or should it fail ?
+
+ The Resume-Printer operation must clear the 'paused' or 'moving-to-
+ paused' 'printer-state-message'. The operation must return a
+ 'successful-ok' status code.
+
+
+3.1.3.1.8.2 How is "printer-state" handled on Resume-Printer?
+
+
+ If the Resume-Printer operation succeeds, what should be the value of
+ "printer-state" and who should take care of the "printer-state"
+ attribute value later on ?
+
+ The Resume-Printer operation may change the "printer-state-reasons"
+ value.
+
+ The "printer-state" will change to one of three states:
+
+ 1. 'idle' - no additional jobs and no error conditions present
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 59]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ 2. 'processing' - job available and no error conditions present
+
+ 3. current state (i.e. no change) an error condition is present
+ (e.g. media jam)
+
+ In the third case the "printer-state-reason" will be cleared by
+ automata when it detects the error condition no longer exists. The
+ "printer-state" will move to 'idle' or 'processing' when conditions
+ permit. (i.e. no more error conditions)
+
+
+3.1.3.1.9 Purge-Printer
+
+ All of the Print-Job status code descriptions in Section 3.1.3.1.1
+ Print-Job Response with the specialization's described for Pause-
+ Printer are applicable to Purge-Printer. See Section 13 in [RFC2911]
+ for a more complete description of each status code.
+
+ For the following success status codes, the Printer object purges all
+ it's jobs.
+
+ successful-ok: no request attributes were substituted or
+ ignored (same as Print-Job).
+ successful-ok-ignored-or-substituted-attributes: same as
+ Print-Job.
+ successful-ok-conflicting-attributes: same as Print-Job.
+
+ For any of the error status codes, the Printer object does not purge
+ any jobs.
+
+ server-error-operation-not-supported: the Purge-Printer
+ operation is not supported.
+
+3.1.3.2 Job Operations
+
+
+3.1.3.2.1 Send-Document
+
+ All of the Print-Job status codes described in Section 3.1.3.1.1
+ Print-Job Response are applicable to the Get-Printer-Attributes
+ operation with the following specialization's and differences. See
+ Section 13 in [RFC2911] for a more complete description of each
+ status code.
+
+ For the following success status codes, the document has been added
+ to the specified Job object and the job's "number-of-documents"
+ attribute has been incremented:
+
+ successful-ok: no request attributes were substituted or
+ ignored (same as Print-Job).
+
+
+Hastings, et al. Expires July 25, 2001 [page 60]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ successful-ok-ignored-or-substituted-attributes: same as Print-
+ Job.
+ successful-ok-conflicting-attributes: same as Print-Job.
+
+ For the error status codes, no document has been added to the Job
+ object and the job's "number-of-documents" attribute has not been
+ incremented:
+
+ client-error-not-possible: Same as Print-Job, except that the
+ Printer's "printer-is-accepting-jobs" attribute is not
+ involved, so that the client is able to finish submitting a
+ job that was created with a Create-Job operation after this
+ attribute has been set to 'true'. Another condition is that
+ the state of the job precludes Send-Document, i.e., the job
+ has already been closed out by the client. However, if the
+ IPP Printer closed out the job due to timeout, the 'client-
+ error-timeout' error status SHOULD be returned instead.
+ client-error-timeout: This request was sent after the Printer
+ closed the job, because it has not received a Send-Document or
+ Send-URI operation within the Printer's "multiple-operation-
+ time-out" period .
+ client-error-request-entity-too-large: same as Print-Job.
+ client-error-conflicting-attributes: same as Print-Job, except
+ that "ipp-attributes-fidelity" operation attribute is not
+ involved..
+ server-error-operation-not-supported: the Send-Document request
+ is not supported.
+ server-error-not-accepting-jobs: not applicable.
+ server-error-job-canceled: the job has been canceled by an
+ operator or the system while the client was transmitting the
+ data.
+
+3.1.3.2.2 Send-URI
+
+ All of the Print-Job status code descriptions in Section 3.1.3.1.1
+ Print-Job Response with the specialization's described for Send-
+ Document are applicable to Send-URI. See Section 13 in [RFC2911] for
+ a more complete description of each status code.
+
+ client-error-uri-scheme-not-supported: the URI scheme supplied
+ in the "document-uri" operation attribute is not supported and
+ the "document-uri" attribute MUST be returned in the
+ Unsupported Attributes group.
+ server-error-operation-not-supported: the Send-URI operation is
+ not supported.
+
+
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 61]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+3.1.3.2.3 Cancel-Job
+
+ All of the Print-Job status codes described in Section 3.1.3.1.1
+ Print-Job Response are applicable to Cancel-Job with the following
+ specializations and differences. See Section 13 in [RFC2911] for a
+ more complete description of each status code.
+
+ For the following success status codes, the Job object is being
+ canceled or has been canceled:
+
+ successful-ok: no request attributes were substituted or
+ ignored (same as Print-Job).
+ successful-ok-ignored-or-substituted-attributes: same as
+ Print-Job.
+ successful-ok-conflicting-attributes: same as Print-Job.
+
+ For any of the error status codes, the Job object has not been
+ canceled or was previously canceled.
+
+ client-error-not-possible: The request cannot be carried out
+ because of the state of the Job object ('completed',
+ 'canceled', or 'aborted') or the state of the system.
+ client-error-not-found: the target Printer and/or Job object
+ does not exist.
+ client-error-gone: the target Printer and/or Job object no
+ longer exists and no forwarding address is known.
+ client-error-request-entity-too-large: same as Print-Job,
+ except no document data is involved.
+ client-error-document-format-not-supported: not applicable.
+ client-error-attributes-or-values-not-supported: not
+ applicable, since unsupported operation attributes and values
+ MUST be ignored.
+ client-error-conflicting-attributes: same as Print-Job, except
+ that the Printer's "printer-is-accepting-jobs" attribute is
+ not involved.
+ server-error-operation-not-supported: not applicable (Cancel-
+ Job is REQUIRED).
+ server-error-device-error: same as Print-Job, except no
+ document data is involved.
+ server-error-temporary-error: same as Print-Job, except no
+ document data is involved.
+ server-error-not-accepting-jobs: not applicable..
+ server-error-job-canceled: not applicable.
+
+3.1.3.2.4 Get-Job-Attributes
+
+ All of the Print-Job status codes described in Section 3.1.3.1.1
+ Print-Job Response are applicable to Get-Job-Attributes with the
+ following specializations and differences. See Section 13 in
+ [RFC2911] for a more complete description of each status code.
+
+
+Hastings, et al. Expires July 25, 2001 [page 62]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ For the following success status codes, the requested attributes are
+ returned in Group 3 in the response:
+
+ successful-ok: same as Get-Printer-Attributes (see section
+ 3.1.3.1.5).
+ successful-ok-ignored-or-substituted-attributes: same as Get-
+ Printer-Attributes (see section 3.1.3.1.5).
+ successful-ok-conflicting-attributes: same as Get-Printer-
+ Attributes (see section 3.1.3.1.5).
+
+ For the error status codes, Group 3 is returned containing no
+ attributes or is not returned at all.
+
+ client-error-not-possible: Same as Print-Job, in addition the
+ Printer object is not accepting any requests.
+ client-error-document-format-not-supported: not applicable.
+ client-error-attributes-or-values-not-supported: not
+ applicable.
+ client-error-uri-scheme-not-supported: not applicable.
+ client-error-attributes-or-values-not-supported: not
+ applicable, since unsupported operation attributes and/or
+ values MUST be ignored and an appropriate success code
+ returned (see above).
+ client-error-conflicting-attributes: not applicable
+ server-error-operation-not-supported: not applicable (since
+ Get-Job-Attributes is REQUIRED).
+ server-error-device-error: same as Print-Job, except no
+ document data is involved.
+ server-error-temporary-error: sane as Print-Job, except no
+ document data is involved..
+ server-error-not-accepting-jobs: not applicable.
+ server-error-job-canceled: not applicable.
+
+3.1.3.2.5 Hold-Job
+
+ All of the Print-Job status codes described in Section 3.1.3.1.1
+ Print-Job Response are applicable to Hold-Job with the following
+ specializations and differences. See Section 13 in [RFC2911] for a
+ more complete description of each status code.
+
+ For the following success status codes, the Job object is being held
+ or has been held:
+
+ successful-ok: no request attributes were substituted or
+ ignored (same as Print-Job).
+ successful-ok-ignored-or-substituted-attributes: same as
+ Print-Job.
+ successful-ok-conflicting-attributes: same as Print-Job.
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 63]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ For any of the error status codes, the Job object has not been held
+ or was previously held.
+
+ client-error-not-possible: The request cannot be carried out
+ because of the state of the Job object ('completed',
+ 'canceled', or 'aborted') or the state of the system.
+ client-error-not-found: the target Printer and/or Job object
+ does not exist.
+ client-error-gone: the target Printer and/or Job object no
+ longer exists and no forwarding address is known.
+ client-error-request-entity-too-large: same as Print-Job,
+ except no document data is involved.
+ client-error-document-format-not-supported: not applicable.
+ client-error-conflicting-attributes: same as Print-Job, except
+ that the Printer's "printer-is-accepting-jobs" attribute is
+ not involved.
+ server-error-operation-not-supported: the Hold-Job operation is
+ not supported.
+ server-error-device-error: not applicable.
+ server-error-temporary-error: same as Print-Job, except no
+ document data is involved.
+ server-error-not-accepting-jobs: not applicable.
+ server-error-job-canceled: not applicable.
+
+3.1.3.2.6 Release-Job
+
+ All of the Print-Job status code descriptions in Section 3.1.3.1.1
+ Print-Job Response with the specialization's described for Hold-Job
+ are applicable to Release-Job. See Section 13 in [RFC2911] for a
+ more complete description of each status code.
+
+ server-error-operation-not-supported: the Release-Job operation
+ is not supported.
+
+3.1.3.2.7 Restart-Job
+
+ All of the Print-Job status code descriptions in Section 3.1.3.1.1
+ Print-Job Response with the specialization's described for Hold-Job
+ are applicable to Restart-Job. See Section 13 in [RFC2911] for a
+ more complete description of each status code.
+
+ server-error-operation-not-supported: the Restart-Job operation
+ is not supported.
+
+
+
+
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 64]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+3.1.3.2.7.1 Can documents be added to a restarted job?
+ Assume I give a Create-Job request along with a set of 5 documents .
+ All the documents get printed and the job state is moved to completed
+ . I issue a Restart-Job request on the job. Now the issue is that, if
+ I try to add new documents to the restarted job, will the IPP Server
+ permit me to do so or return "client-error-not-possible " and again
+ print those 5 jobs?
+
+ A job can not move to the 'completed' state until all the documents
+ have been processed. The 'last-document' flag indicates when the
+ last document for a job is being sent from the client. This is the
+ semantic equivalent of closing a job. No documents may be added once
+ a job is closed. Section 3.3.7 of the IPP/1.1 model states "The job
+ is moved to the 'pending' job state and restarts the beginning on the
+ same IPP Printer object with the same attribute values." 'number-of-
+ documents' is a job attribute.
+
+
+3.1.4 Returning unsupported attributes in Get-Xxxx responses (Issue
+ 1.18)
+
+ In the Get-Printer-Attributes, Get-Jobs, or Get-Job-Attributes
+ responses, the client cannot depend on getting unsupported attributes
+ returned in the Unsupported Attributes group that the client
+ requested, but are not supported by the IPP object. However, such
+ unsupported requested attributes will not be returned in the Job
+ Attributes or Printer Attributes group (since they are unsupported).
+ Furthermore, the IPP object is REQUIRED to return the 'successful-ok-
+ ignored-or-substituted-attributes' status code, so that the client
+ knows that not all that was requested has been returned.
+
+
+3.1.5 Sending empty attribute groups
+
+ The [RFC2911] and [RFC2910] specifications RECOMMEND that a sender
+ not send an empty attribute group in a request or a response.
+ However, they REQUIRE a receiver to accept an empty attribute group
+ as equivalent to the omission of that group. So a client SHOULD omit
+ the Job Template Attributes group entirely in a create operation that
+ is not supplying any Job Template attributes. Similarly, an IPP
+ object SHOULD omit an empty Unsupported Attributes group if there are
+ no unsupported attributes to be returned in a response.
+
+ The [RFC2910] specification REQUIRES a receiver to be able to receive
+ either an empty attribute group or an omitted attribute group and
+ treat them equivalently. The term "receiver" means an IPP object for
+ a request and a client for a response. The term "sender' means a
+ client for a request and an IPP object for a response.
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 65]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ There is an exception to the rule for Get-Jobs when there are no
+ attributes to be returned. [RFC2910] contains the following
+ paragraph:
+
+ The syntax allows an xxx-attributes-tag to be present when the xxx-
+ attribute-sequence that follows is empty. The syntax is defined this
+ way to allow for the response of Get-Jobs where no attributes are
+ returned for some job-objects. Although it is RECOMMENDED that the
+ sender not send an xxx-attributes-tag if there are no attributes
+ (except in the Get-Jobs response just mentioned), the receiver MUST
+ be able to decode such syntax.
+
+
+3.2 Printer Operations
+
+
+3.2.1 Print-Job operation
+
+
+3.2.1.1 Flow controlling the data portion of a Print-Job request
+ (Issue 1.22)
+
+ A paused printer, or one that is stopped due to paper out or jam or
+ spool space full or buffer space full, may flow control the data of a
+ Print-Job operation (at the TCP/IP layer), so that the client is not
+ able to send all the document data. Consequently, the Printer will
+ not return a response until the condition is changed.
+
+ The Printer should not return a Print-Job response with an error code
+ in any of these conditions, since either the printer will be resumed
+ and/or the condition will be freed either by human intervention or as
+ jobs print.
+
+ In writing test scripts to test IPP Printers, the script must also be
+ written not to expect a response, if the printer has been paused,
+ until the printer is resumed, in order to work with all possible
+ implementations.
+
+
+3.2.1.2 Returning job-state in Print-Job response (Issue 1.30)
+
+ An IPP client submits a small job via Print-Job. By the time the IPP
+ printer/print server is putting together a response to the operation,
+ the job has finished printing and been removed as an object from the
+ print system. What should the job-state be in the response?
+
+ The Model suggests that the Printer return a response before it even
+ accepts the document content. The Job Object Attributes are returned
+ only if the IPP object returns one of the success status codes. Then
+ the job-state would always be "pending" or "pending-held".
+
+
+Hastings, et al. Expires July 25, 2001 [page 66]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ This issue comes up for the implementation of an IPP Printer object
+ as a server that forwards jobs to devices that do not provide job
+ status back to the server. If the server is reasonably certain that
+ the job completed successfully, then it should return the job-state
+ as 'completed'. Also the server can keep the job in its "job
+ history" long after the job is no longer in the device. Then a user
+ could query the server and see that the job was in the 'completed'
+ state and completed as specified by the jobs "time-at-completed"
+ time, which would be the same as the server submitted the job to the
+ device.
+
+ An alternative is for the server to respond to the client before or
+ while sending the job to the device, instead of waiting until the
+ server has finished sending the job to the device. In this case, the
+ server can return the job's state as 'pending' with the 'job-
+ outgoing' value in the job's "job-state-reasons" attribute.
+
+ If the server doesn't know for sure whether the job completed
+ successfully (or at all), it could return the (out-of-band) 'unknown'
+ value.
+
+ On the other hand, if the server is able to query the device and/or
+ setup some sort of event notification that the device initiates when
+ the job makes state transitions, then the server can return the
+ current job state in the Print-Job response and in subsequent queries
+ because the server knows what the job state is in the device (or can
+ query the device).
+
+ All of these alternatives depend on implementation of the server and
+ the device.
+
+
+3.2.2 Get-Printer-Attributes operation
+
+ If a Printer supports the "printer-make-and-model" attribute and
+ returns the .INF file model name of the printer in that attribute,
+ the Microsoft client will automatically install the correct driver
+ (if available).
+
+ Clients which poll periodically for printer status or queued-job-
+ count should use the "requested-attributes" operation attribute to
+ limit the scope of the query in order to save Printer and network
+ resources.
+
+
+3.2.3 Get-Jobs operation
+
+
+3.2.3.1 Get-Jobs, my-jobs='true', and 'requesting-user-name' (Issue
+ 1.39)?
+
+
+Hastings, et al. Expires July 25, 2001 [page 67]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ In [RFC2911] section 3.2.6.1 'Get-Jobs Request', if the attribute
+ 'my-jobs' is present and set to TRUE, MUST the 'requesting-user-name'
+ attribute be there too, and if it's not present what should the IPP
+ printer do?
+
+ [RFC2911] Section 8.3 describes the various cases of "requesting-
+ user-name" being present or not for any operation. If the client
+ does not supply a value for "requesting-user-name", the printer MUST
+ assume that the client is supplying some anonymous name, such as
+ "anonymous".
+
+
+3.2.3.2 Why is there a "limit" attribute in the Get-Jobs operation?
+
+ When using the Get-Jobs operation a client implementer might choose
+ to limit the number of jobs that the client shows on the first
+ screenful. For example, if its UI can only display 50 jobs, it can
+ defend itself against a printer that would otherwise return 500 jobs,
+ perhaps taking a long time on a slow dial-up line. The client can
+ then go and ask for a larger number of jobs in the background, while
+ showing the user the first 50 jobs. Since the job history is returned
+ in reverse order, namely the most recently completed jobs are
+ returned first, the user is most likely interested in the first jobs
+ that are returned. Limiting the number of jobs may be especially
+ useful for a client that is requesting 'completed' jobs from a
+ printer that keeps a long job history. Clients that don't mind
+ sometimes getting very large responses, can omit the "limit"
+ attribute in their Get-Jobs requests.
+
+
+3.2.4 Create-Job operation
+
+ A Printer may respond to a Create-Job operation with "job-state"
+ 'pending' or 'pending-held' and " job-state-reason" 'job-data-
+ insufficient' to indicate that operation has been accepted by the
+ Printer, but the Printer is expecting additional document data before
+ it can move the job into the 'processing' state. Alternatively, it
+ may respond with "job-state" 'processing' and "job-state-reason"
+ 'job-incoming' to indicate that the Create-Job operation has been
+ accepted by the Printer, but the Printer is expecting additional
+ Send-Document and/or Send-URI operations and/or is
+ accessing/accepting document data. The second alternative is for
+ non-spooling Printers that don't implement the 'pending' state.
+
+ Should the server wait for the "last-document" operation attribute
+ set to 'true' before starting to "process" the job?
+
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 68]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ It depends on implementation. Some servers spool the entire job,
+ including all document data, before starting to process, so such an
+ implementation would wait for the "last-document" before starting to
+ process the job. If the time-out occurs without the "last-document",
+ then the server takes one of the indicated actions in section 3.3.1
+ in the [RFC2911] document. Other servers will start to process
+ document data as soon as they have some. These are the so-called
+ "non-spooling" printers. Currently, there isn't a way for a client to
+ determine whether the Printer will spool all the data or will start
+ to process (and print) as soon as it has some data.
+
+
+3.3 Job Operations
+
+
+3.3.1 Validate-Job
+
+ The Validate-Job operation has been designed so that its
+ implementation may be a part of the Print-Job operation. Therefore,
+ requiring Validate-Job is not a burden on implementers. Also it is
+ useful for client's to be able to count on its presence in all
+ conformance implementations, so that the client can determine before
+ sending a long document, whether the job will be accepted by the IPP
+ Printer or not.
+
+
+3.3.2 Restart-Job
+
+ The Restart-Job operation allows the reprocessing of a completed job.
+ Some jobs store the document data on the printer. Jobs created using
+ the Print-Job operation are an example. It is required that the
+ printer retains the job data after the job has moved to a 'completed
+ state' in order for the Restart-Job operation to succeed.
+
+ Some jobs contain only a reference to the job data. A job created
+ using the Print-URI is an example of such a job. When the Restart-
+ Job operation is issued the job is reprocessed. The job data MUST be
+ retrieved again to print the job.
+
+ It is possible that a job fails while attempting to access the print
+ data. When such a job is the target of a Restart-Job the Printer
+ SHALL attempt to retrieve the job data again.
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 69]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+4 Object Attributes
+
+
+4.1 Attribute Syntax's
+
+
+4.1.1 The 'none' value for empty sets (Issue 1.37)
+
+ [RFC2911] states that the 'none' value should be used as the value of
+ a 1setOf when the set is empty. In most cases, sets that are
+ potentially empty contain keywords so the keyword 'none' is used, but
+ for the 3 finishings attributes, the values are enums and thus the
+ empty set is represented by the enum 3. Currently there are no other
+ attributes with 1setOf values, which can be empty and can contain
+ values that are not keywords. This exception requires special code
+ and is a potential place for bugs. It would have been better if we
+ had chosen an out-of-band value, either "no-value" or some new value,
+ such as 'none'. Since we didn't, implementations have to deal with
+ the different representations of 'none', depending on the attribute
+ syntax.
+
+
+4.1.2 Multi-valued attributes (Issue 1.31)
+
+ What is the attribute syntax for a multi-valued attribute? Since
+ some attributes support values in more than one data type, such as
+ "media", "job-hold-until", and "job-sheets", IPP semantics associate
+ the attribute syntax with each value, not with the attribute as a
+ whole. The protocol associates the attribute syntax tag with each
+ value. Don't be fooled, just because the attribute syntax tag comes
+ before the attribute keyword. All attribute values after the first
+ have a zero length attribute keyword as the indication of a
+ subsequent value of the same attribute.
+
+
+4.1.3 Case Sensitivity in URIs (issue 1.6)
+
+ IPP client and server implementations must be aware of the diverse
+ uppercase/lowercase nature of URIs. RFC 2396 defines URL schemes and
+ Host names as case insensitive but reminds us that the rest of the
+ URL may well demonstrate case sensitivity. When creating URL's for
+ fields where the choice is completely arbitrary, it is probably best
+ to select lower case. However, this cannot be guaranteed and
+ implementations MUST NOT rely on any fields being case-sensitive or
+ case-insensitive in the URL beyond the URL scheme and host name
+ fields.
+
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 70]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ The reason that the IPP specification does not make any restrictions
+ on URIs, is so that implementations of IPP may use off-the-shelf
+ components that conform to the standards that define URIs, such as
+ RFC 2396 and the HTTP/1.1 specifications [RFC2616]. See these
+ specifications for rules of matching, comparison, and case-
+ sensitivity.
+
+ It is also recommended that System Administrators and implementations
+ avoid creating URLs for different printers that differ only in their
+ case. For example, don't have Printer1 and printer1 as two different
+ IPP Printers.
+
+ Example of equivalent URI's
+
+ http://abc.com:80/~smith/home.html
+
+ http://ABC.com/%7Esmith/home.html
+
+ http:/ABC.com:/%7esmith/home.html
+
+ Example of equivalent URI's using the IPP scheme
+
+ ipp://abc.com:631/~smith/home.html
+
+ ipp://ABC.com/%7Esmith/home.html
+
+ http:/ABC.com:631/%7esmith/home.html
+
+ The HTTP/1.1 specification [RFC2616] contains more details on
+ comparing URLs.
+
+
+4.1.4 Maximum length for xxxWithLanguage and xxxWithoutLanguage
+
+ The 'textWithLanguage' and 'nameWithLanguage' are compound syntaxes
+ that have two components. The first component is the 'language'
+ component that can contain up to 63 octets. The second component is
+ the 'text' or 'name' component. The maximum length of these are 1023
+ octets and 255 octets respectively. The definition of attributes
+ with either syntax may further restrict the length. (e.g. printer-
+ name (name(127)))
+
+ The length of the 'language' component has no effect on the allowable
+ length of 'text' in 'textWithLanguage' or the length of 'name' in
+ 'nameWithLanguage'
+
+
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 71]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+4.2 Job Template Attributes
+
+
+4.2.1 multiple-document-handling(type2 keyword)
+
+
+4.2.1.1 Support of multiple document jobs
+
+ IPP/1.0 is silent on which of the four effects an implementation
+ would perform if it supports Create-Job, but does not support
+ "multiple-document-handling" or multiple documents per job. IPP/1.1
+ was changed so that a Printer could support Create-Job without having
+ to support multiple document jobs. The "multiple-document-jobs-
+ supported" (boolean) Printer description attribute was added to
+ IPP/1.1 along with the 'server-error-multiple-document-jobs-not-
+ supported' status code for a Printer to indicate whether or not it
+ supports multiple document jobs, when it supports the Create-Job
+ operation. Also IPP/1.1 was clarified that the Printer MUST support
+ the "multiple-document-handling" (type2 keyword) Job Template
+ attribute with at least one value if the Printer supports multiple
+ documents per job.
+
+
+4.3 Job Description Attributes
+
+
+4.3.1 Getting the date and time of day
+
+ The "date-time-at-creation", "date-time-at-processing", and "date-
+ time-at-completed" attributes are returned as dateTime syntax.
+ These attributes are OPTIONAL for a Printer to support. However,
+ there are various ways for a Printer to get the date and time of day.
+ Some suggestions:
+
+ 1. A Printer can get time from an NTP timeserver if there's one
+ reachable on the network . See RFC 1305. Also DHCP option 32 in
+ RFC 2132 returns the IP address of the NTP server.
+
+ 2. Get the date and time at startup from a human operator
+
+ 3. Have an operator set the date and time using a web
+ administrative interface
+
+ 4. Get the date and time from incoming HTTP requests, though the
+ problems of spoofing need to be considered. Perhaps comparing
+ several HTTP requests could reduce the chances of spoofing.
+
+ 5. Internal date time clock battery driven.
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 72]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ 6. Query "http://tycho.usno.navy.mil/cgi-bin/timer.pl"
+
+
+
+4.4 Printer Description Attributes
+
+
+4.4.1 queued-job-count (integer(0:MAX))
+
+
+4.4.1.1 Why is "queued-job-count" RECOMMENDED (Issue 1.14)?
+
+ The reason that "queued-job-count" is RECOMMENDED, is that some
+ clients look at that attribute alone when summarizing the status of a
+ list of printers, instead of doing a Get-Jobs to determine the number
+ of jobs in the queue. Implementations that fail to support the
+ "queued-job-count" will cause that client to display 0 jobs when
+ there are actually queued jobs.
+
+ We would have made it a REQUIRED Printer attribute, but some
+ implementations had already been completed before the issue was
+ raised, so making it a SHOULD was a compromise.
+
+
+4.4.1.2 Is "queued-job-count" a good measure of how busy a printer is
+ (Issue 1.15)?
+
+ The "queued-job-count" is not a good measure of how busy the printer
+ is when there are held jobs. A future registration could be to add a
+ "held-job-count" (or an "active-job-count") Printer Description
+ attribute if experience shows that such an attribute (combination) is
+ needed to quickly indicate how busy a printer really is.
+
+
+4.4.2 printer-current-time (dateTime)
+
+ A Printer implementation MAY support this attribute by obtaining the
+ date and time by any number of implementation-dependent means at
+ startup or subsequently. Examples include:
+
+ 1. an internal date time clock,
+
+ 2. from the operator at startup using the console,
+
+ 3. from an operator using an administrative web page,
+
+ 4. from HTTP headers supplied in client requests,
+
+ 5. use HTTP to query "http://tycho.usno.navy.mil/cgi-bin/timer.pl"
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 73]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ 6. from the network, using NTP [RFC1305] or DHCP option 32
+ [RFC2132] that returns the IP address of the NTP server.
+
+ If an implementation supports this attribute by obtaining the current
+ time from the network (at startup or later), but the time is not
+ available, then the implementation MUST return the value of this
+ attribute using the out-of-band 'no-value' meaning not configured.
+ See the beginning of section 4.1.
+
+ Since the new "date-and-time-at-xxx" Job Description attributes refer
+ to the "printer-current-time", they will be covered also.
+
+
+4.4.3 Printer-uri
+
+ Must the operational attribute for printer-uri match one of the
+ values in "printer-uri-supported"?
+
+ A forgiving printer implementation would not reject the operation.
+ But the implementation has its rights to reject a printer or job
+ operation if the operational attribute printer-uri is not a value of
+ the printer-uri-supported. The printer might not be improperly
+ configured. The request obviously reached the printer. The printer
+ could treat the printer-uri as the logical equivalent of a value in
+ the printer-uri-supported. It would be implementation dependent for
+ which value, and associated security policy, would apply. This does
+ also apply to a job object specified with a printer-uri and job-id,
+ or with a job-uri. See section 4.1.3 for how to compare URI's.
+
+
+4.5 Empty Jobs
+
+ The IPP object model does not prohibit a job that contains no
+ documents. Such a job may be created in a number of ways including a
+ 'create-job' followed by an 'add-document' that contains no data and
+ has the 'last-document' flag set.
+
+ An empty job is processed just as any other job. The operation that
+ "closes" an empty job is not rejected because the job is empty. If
+ no other conditions exist, other than the job is empty, the response
+ to the operation will indicate success. After the job is scheduled
+ and processed, the job state SHALL be 'completed'.
+
+ There will be some variation in the value(s) of the "job-state-
+ reasons" attribute. It is required that if no conditions, other than
+ the job being empty, exist the "job-state-reasons" SHALL include the
+ 'completed-successfully'. If other conditions existed, the
+ 'completed-with-warnings' or 'completed-with-errors' values may be
+ used.
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 74]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+5 Directory Considerations
+
+
+5.1 General Directory Schema Considerations
+
+ The [RFC2911] document lists RECOMMENDED and OPTIONAL Printer object
+ attributes for directory schemas. See [RFC2911] APPENDIX E: Generic
+ Directory Schema.
+
+ The SLP printer template is defined in the "Definition of the Printer
+ Abstract Service Type v2.0" document [svrloc-printer]. The LDAP
+ printer template is defined in the "Internet Printing Protocol (IPP):
+ LDAP Schema for Printer Services" document [ldap-printer]. Both
+ documents systematically add "printer-" to any attribute that doesn't
+ already start with "printer-" in order to keep the printer directory
+ attributes distinct from other directory attributes. Also, instead
+ of using "printer-uri-supported", "uri-authentication-supported", and
+ "uri-security-supported", they use a "printer-xri-supported"
+ attribute with special syntax to contain all of the same information
+ in a single attribute.
+
+
+5.2 IPP Printer with a DNS name
+
+ If the IPP printer has a DNS name should there be at least two values
+ for the printer-uri-supported attribute. One URL with the fully
+ qualified DNS name the other with the IP address in the URL?
+
+ The printer may contain one or the other or both. It's up to the
+ administrator to configure this attribute.
+
+
+6 Security Considerations
+
+ This section corresponds to the RFC2911 Section 8 "Security
+ Considerations.
+
+
+6.1 Querying jobs with IPP that were submitted using other job
+ submission protocols (Issue 1.32)
+
+ The following clarification was added to [RFC2911] section 8.5:
+
+ 8.5 Queries on jobs submitted using non-IPP protocols
+
+
+
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 75]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ If the device that an IPP Printer is representing is able to accept
+ jobs using other job submission protocols in addition to IPP, it is
+ RECOMMEND that such an implementation at least allow such "foreign"
+ jobs to be queried using Get-Jobs returning "job-id" and "job-uri"
+ as 'unknown'. Such an implementation NEED NOT support all of the
+ same IPP job attributes as for IPP jobs. The IPP object returns
+ the 'unknown' out-of-band value for any requested attribute of a
+ foreign job that is supported for IPP jobs, but not for foreign
+ jobs.
+
+ It is further RECOMMENDED, that the IPP Printer generate "job-id"
+ and "job-uri" values for such "foreign jobs", if possible, so that
+ they may be targets of other IPP operations, such as Get-Job-
+ Attributes and Cancel-Job. Such an implementation also needs to
+ deal with the problem of authentication of such foreign jobs. One
+ approach would be to treat all such foreign jobs as belonging to
+ users other than the user of the IPP client. Another approach
+ would be for the foreign job to belong to 'anonymous'. Only if the
+ IPP client has been authenticated as an operator or administrator
+ of the IPP Printer object, could the foreign jobs be queried by an
+ IPP request. Alternatively, if the security policy were to allow
+ users to query other users' jobs, then the foreign jobs would also
+ be visible to an end-user IPP client using Get-Jobs and Get-Job-
+ Attributes.
+
+ Thus IPP MAY be implemented as a "universal" protocol that provides
+ access to jobs submitted with any job submission protocol. As IPP
+ becomes widely implemented, providing a more universal access makes
+ sense.
+
+
+7 Encoding and Transport
+
+ This section discusses various aspects of IPP/1.1 Encoding and
+ Transport [RFC2910].
+
+ A server is not required to send a response until after it has
+ received the client's entire request. Hence, a client must not
+ expect a response until after it has sent the entire request.
+ However, we recommend that the server return a response as soon as
+ possible if an error is detected while the client is still sending
+ the data, rather than waiting until all of the data is received.
+ Therefore, we also recommend that a client listen for an error
+ response that an IPP server MAY send before it receives all the data.
+ In this case a client, if chunking the data, can send a premature
+ zero-length chunk to end the request before sending all the data (and
+ so the client can keep the connection open for other requests, rather
+ than closing it). If the request is blocked for some reason, a client
+ MAY determine the reason by opening another connection to query the
+ server using Get-Printer-Attributes.
+
+
+Hastings, et al. Expires July 25, 2001 [page 76]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ IPP, by design, uses TCP's built-in flow control mechanisms [RFC 793]
+ to throttle clients when Printers are busy. Therefore, it is
+ perfectly normal for an IPP client transmitting a Job to be blocked
+ for a really long time. Accordingly, socket timeouts must be
+ avoided. Some socket implementations have a timeout option, which
+ specifies how long a write operation on a socket can be blocked
+ before it times out and the blocking ends. A client should set this
+ option for infinite timeout when transmitting Job submissions.
+
+ Some IPP client applications might be able to perform other useful
+ work while a Job transmission is blocked. For example, the client
+ may have other jobs that it could transmit to other Printers
+ simultaneously. A client may have a GUI, which must remain
+ responsive to the user while the Job transmission is blocked. These
+ clients should be designed to spawn a thread to handle the Job
+ transmission at its own pace, leaving the main application free to do
+ other work. Alternatively, single-threaded applications could use
+ non-blocking I/O.
+
+ Some Printer conditions, such as jam or lack of paper, could cause a
+ client to be blocked indefinitely. Clients may open additional
+ connections to the Printer to Get-Printer-Attributes, determine the
+ state of the device, alert a user if the printer is stopped, and let
+ a user decide whether to abort the job transmission or not.
+
+ In the following sections, there are tables of all HTTP headers,
+ which describe their use in an IPP client or server. The following
+ is an explanation of each column in these tables.
+
+ - the "header" column contains the name of a header
+ - the "request/client" column indicates whether a client sends the
+ header.
+ - the "request/ server" column indicates whether a server supports
+ the header when received.
+ - the "response/ server" column indicates whether a server sends
+ the header.
+ - the "response /client" column indicates whether a client
+ supports the header when received.
+ - the "values and conditions" column specifies the allowed header
+ values and the conditions for the header to be present in a
+ request/response.
+
+ The table for "request headers" does not have columns for responses,
+ and the table for "response headers" does not have columns for
+ requests.
+
+ The following is an explanation of the values in the "request/client"
+ and "response/ server" columns.
+
+ - must: the client or server MUST send the header,
+
+
+Hastings, et al. Expires July 25, 2001 [page 77]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ - must-if: the client or server MUST send the header when the
+ condition described in the "values and conditions" column is
+ met,
+ - may: the client or server MAY send the header
+ - not: the client or server SHOULD NOT send the header. It is not
+ relevant to an IPP implementation.
+
+
+ The following is an explanation of the values in the
+ "response/client" and "request/ server" columns.
+
+ - must: the client or server MUST support the header,
+ - may: the client or server MAY support the header
+ - not: the client or server SHOULD NOT support the header. It is
+ not relevant to an IPP implementation.
+
+7.1 General Headers
+
+ The following is a table for the general headers.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 78]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+
+
+ General- Request Response Values and Conditions
+ Header
+
+
+
+ Client Server Server Client
+
+
+ Cache- must not must not "no-cache" only
+ Control
+
+ Connection must- must must- must "close" only. Both
+ if if client and server SHOULD
+ keep a connection for
+ the duration of a
+ sequence of operations.
+ The client and server
+ MUST include this header
+ for the last operation
+ in such a sequence.
+
+ Date may may must may per RFC 1123 [RFC1123]
+ from RFC 2616 [RFC2616]
+
+ Pragma must not must not "no-cache" only
+
+ Transfer- must- must must- must "chunked" only . Header
+ Encoding if if MUST be present if
+ Content-Length is
+ absent.
+
+ Upgrade not not not not
+
+ Via not not not not
+
+
+7.2 Request Headers
+
+The following is a table for the request headers.
+
+
+ Request- Client Server Request Values and Conditions
+ Header
+
+
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 79]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+
+ Request- Client Server Request Values and Conditions
+ Header
+
+ Accept may must "application/ipp" only. This
+ value is the default if the client
+ omits it
+
+ Accept- not not Charset information is within the
+ Charset application/ipp entity
+
+ Accept- may must empty and per RFC 2616 [RFC2616]
+ Encoding and IANA registry for content-
+ codings
+
+ Accept- not not language information is within the
+ Language application/ipp entity
+
+ Authorization must- must per RFC 2616. A client MUST send
+ if this header when it receives a 401
+ "Unauthorized" response and does
+ not receive a "Proxy-
+ Authenticate" header.
+
+ From not not per RFC 2616. Because RFC
+ recommends sending this header
+ only with the user's approval, it
+ is not very useful
+
+ Host must must per RFC 2616
+
+ If-Match not not
+
+ If-Modified- not not
+ Since
+
+ If-None-Match not not
+
+ If-Range not not
+
+ If- not not
+ Unmodified-
+ Since
+
+ Max-Forwards not not
+
+ Proxy- must- not per RFC 2616. A client MUST send
+ Authorization if this header when it receives a 401
+ "Unauthorized" response and a
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 80]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+
+ Request- Client Server Request Values and Conditions
+ Header
+
+ "Proxy-Authenticate" header.
+
+ Range not not
+
+ Referrer not not
+
+ User-Agent not not
+
+
+7.3 Response Headers
+
+ The following is a table for the request headers.
+
+
+
+ Response- Server Client Response Values and Conditions
+ Header
+
+
+ Accept-Ranges not not
+
+ Age not not
+
+ Location must- may per RFC 2616. When URI needs
+ if redirection.
+
+ Proxy- not must per RFC 2616
+ Authenticate
+
+ Public may may per RFC 2616
+
+ Retry-After may may per RFC 2616
+
+ Server not not
+
+ Vary not not
+
+ Warning may may per RFC 2616
+
+ WWW- must- must per RFC 2616. When a server needs
+ Authenticate if to authenticate a client.
+
+
+7.4 Entity Headers
+
+The following is a table for the entity headers.
+
+
+Hastings, et al. Expires July 25, 2001 [page 81]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+
+ Entity-Header Request Response Values and
+ Conditions
+
+ Client Server Server Client
+
+ Allow not not not not
+
+ Content-Base not not not not
+
+ Content- may must must must per RFC 2616 and
+ Encoding IANA registry for
+ content codings.
+
+ Content- not not not not Application/ipp
+ Language handles language
+
+ Content- must- must must- must the length of the
+ Length if if message-body per
+ RFC 2616. Header
+ MUST be present if
+ Transfer-Encoding
+ is absent..
+
+ Content- not not not not
+ Location
+
+ Content-MD5 may may may may per RFC 2616
+
+ Content-Range not not not not
+
+ Content-Type must must must must "application/ipp"
+ only
+
+ ETag not not not not
+
+ Expires not not not not
+
+ Last-Modified not not not not
+
+
+7.5 Optional support for HTTP/1.0
+
+ IPP implementations consist of an HTTP layer and an IPP layer. In
+ the following discussion, the term "client" refers to the HTTP client
+ layer and the term "server" refers to the HTTP server layer. The
+ Encoding and Transport document [RFC2910] requires that HTTP 1.1 MUST
+ be supported by all clients and all servers. However, a client
+ and/or a server implementation may choose to also support HTTP 1.0.
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 82]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ This option means that a server may choose to communicate with a
+ (non-conforming) client that only supports HTTP 1.0. In such cases
+ the server should not use any HTTP 1.1 specific parameters or
+ features and should respond using HTTP version number 1.0.
+
+ This option also means that a client may choose to communicate with a
+ (non-conforming) server that only supports HTTP 1.0. In such cases,
+ if the server responds with an HTTP 'unsupported version number' to
+ an HTTP 1.1 request, the client should retry using HTTP version
+ number 1.0.
+
+
+7.6 HTTP/1.1 Chunking
+
+
+7.6.1 Disabling IPP Server Response Chunking
+
+ Clients MUST anticipate that the HTTP/1.1 server may chunk responses
+ and MUST accept them in responses. However, a (non-conforming) HTTP
+ client that is unable to accept chunked responses may attempt to
+ request an HTTP 1.1 server not to use chunking in its response to an
+ operation by using the following HTTP header:
+
+ TE: identity
+
+ This mechanism should not be used by a server to disable a client
+ from chunking a request, since chunking of document data is an
+ important feature for clients to send long documents.
+
+
+7.6.2 Warning About the Support of Chunked Requests
+
+ This section describes some problems with the use of chunked requests
+ and HTTP/1.1 servers.
+
+ The HTTP/1.1 standard [RFC2616] requires that conforming servers
+ support chunked requests for any method. However, in spite of this
+ requirement, some HTTP/1.1 implementations support chunked responses
+ in the GET method, but do not support chunked POST method requests.
+ Some HTTP/1.1 implementations that support CGI scripts [CGI] and/or
+ servlets [Servlet] require that the client supply a Content-Length.
+ These implementations might reject a chunked POST method and return a
+ 411 status code (Length Required), might attempt to buffer the
+ request and run out of room returning a 413 status code (Request
+ Entity Too Large), or might successfully accept the chunked request.
+
+
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 83]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ Because of this lack of conformance of HTTP servers to the HTTP/1.1
+ standard, the IPP standard [RFC2910] REQUIRES that a conforming IPP
+ Printer object implementation support chunked requests and that
+ conforming clients accept chunked responses. Therefore, IPP object
+ implementers are warned to seek HTTP server implementations that
+ support chunked POST requests in order to conform to the IPP standard
+ and/or use implementation techniques that support chunked POST
+ requests.
+
+
+8 References
+
+ [CGI]
+ CGI/1.1 (http://www.ietf.org/internet-drafts/draft-coar-cgi-v11-
+ 00.txt).
+
+ [ldap-printer]
+ Fleming, P., Jones, K., Lewis, H., McDonald, I., "Internet Printing
+ Protocol (IPP): LDAP Schema for Printer Services", <draft-ietf-ipp-
+ ldap-printer-schema-01.txt>, work in progress, April 27, 2000.
+
+ [RFC793]
+ J. Postel, "Transmission Control Protocol", RFC 793.
+
+ [RFC1123]
+ Braden, S., "Requirements for Internet Hosts - Application and
+ Support", RFC 1123, October, 1989.
+
+ [RFC2026]
+ S. Bradner, "The Internet Standards Process -- Revision 3", RFC
+ 2026, October 1996.
+
+ [RFC2119]
+ S. Bradner, "Key words for use in RFCs to Indicate Requirement
+ Levels", RFC 2119 , March 1997.
+
+ [RFC2396]
+ Berners-Lee, T., Fielding, R., Masinter, L., "Uniform Resource
+ Identifiers (URI): Generic Syntax", RFC 2396, August 1998.
+
+ [RFC2565]
+ R. deBry, T. Hastings, R. Herriot, S. Isaacson, P. Powell,
+ "Internet Printing Protocol/1.0: Model and Semantics", RFC 2566,
+ April 1999.
+
+ [RFC2566]
+ Herriot, R., Butler, S., Moore, P., Turner, R., "Internet Printing
+ Protocol/1.0: Encoding and Transport", RFC 2565, April 1999.
+
+ [RFC2567]
+
+
+Hastings, et al. Expires July 25, 2001 [page 84]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ Wright, D., "Design Goals for an Internet Printing Protocol",
+ draft-ietf-ipp-req-03.txt, November, 1998.
+
+ [RFC2568
+ Zilles, S., "Rationale for the Structure and Model and Protocol for
+ the Internet Printing Protocol", RFC 2568, April 1999.
+
+ [RFC2569]
+ Herriot, R., Hastings, T., Jacobs, N., Martin, J., "Mapping between
+ LPD and IPP Protocols", RFC 2569, April 1999.
+
+ [RFC2616]
+ R. Fielding, J. Gettys, J. Mogul, H. Frystyk, L. Masinter, P.
+ Leach, T. Berners-Lee, "Hypertext Transfer Protocol - HTTP/1.1",
+ RFC 2616, June 1999.
+
+ [RFC2910]
+ Herriot, R., Butler, S., Moore, P., Turner, R., "Internet Printing
+ Protocol/1.0: Encoding and Transport", RFC 2910, September, 2000.
+
+ [RFC2911]
+ R. deBry, T. Hastings, R. Herriot, S. Isaacson, P. Powell,
+ "Internet Printing Protocol/1.0: Model and Semantics", RFC 2911,
+ September, 2000.
+
+ [Servlet]
+ Servlet Specification Version 2.1
+ (http://java.sun.com/products/servlet/2.1/index.html).
+
+
+ [svrloc-printer]
+ St. Pierre, P., Isaacson, S., McDonald, I., "Definition of the
+ Printer Abstract Service Type v2.0", <draft-ietf-svrloc-printer-
+ scheme-06.txt>, work in progress, March 8, 2000.
+
+ [SSL]
+ Netscape, The SSL Protocol, Version 3, (Text version 3.02),
+ November 1996.
+
+
+9 Authors' Address
+
+
+ Thomas N. Hastings
+ Xerox Corporation
+ 701 Aviation Blvd.
+ El Segundo, CA 90245
+ hastings@cp10.es.xerox.com
+
+ Carl-Uno Manros
+
+
+Hastings, et al. Expires July 25, 2001 [page 85]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ Xerox Corporation
+ 701 Aviation Blvd.
+ El Segundo, CA 90245
+ manros@cp10.es.xerox.com
+
+ Carl Kugler
+ Mail Stop 003G
+ IBM Printing Systems Co
+ 6300 Diagonal Hwy
+ Boulder CO 80301
+ Kugler@us.ibm.com
+
+ Henrik Holst
+ i-data Printing Systems
+ Vadstrupvej 35-43
+ 2880 Bagsvaerd, Denmark
+ hh@I-data.com
+
+
+ Peter Zehler
+ Xerox Corporation
+ 800 Philips Road
+ Webster, NY 14580
+ peter.zehler@usa.xerox.com
+
+10 Full Copyright Statement
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 86]
+
+
+INTERNET-DRAFT IPP/1.1: Implementer's Guide January 25, 2001
+
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+ Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Expires July 25, 2001 [page 87]
diff --git a/standards/draft-ietf-ipp-indp-method-04.txt b/standards/draft-ietf-ipp-indp-method-04.txt
new file mode 100644
index 000000000..b87973fb2
--- /dev/null
+++ b/standards/draft-ietf-ipp-indp-method-04.txt
@@ -0,0 +1,1768 @@
+
+
+
+
+
+
+INTERNET-DRAFT Hugo Parra
+<draft-ietf-ipp-indp-method-04.txt> Novell, Inc.
+[Target Category: standards track] Tom Hastings
+ Xerox Corp.
+ February 28, 2001
+
+ Internet Printing Protocol (IPP):
+ The 'indp' Delivery Method for Event Notifications and Protocol/1.0
+
+ Copyright (C) The Internet Society (2001). All Rights Reserved.
+
+Status of this Memo
+
+ This document is an Internet-Draft and is in full conformance with
+ all provisions of Section 10 of [RFC2026]. Internet-Drafts are
+ working documents of the Internet Engineering Task Force (IETF), its
+ areas, and its working groups. Note that other groups may also
+ distribute working documents as Internet-Drafts.
+
+ Internet-Drafts are draft documents valid for a maximum of six months
+ and may be updated, replaced, or obsoleted by other documents at any
+ time. It is inappropriate to use Internet-Drafts as reference
+ material or to cite them other than as "work in progress".
+
+ The list of current Internet-Drafts can be accessed at
+ http://www.ietf.org/ietf/1id-abstracts.txt
+
+ The list of Internet-Draft Shadow Directories can be accessed as
+ http://www.ietf.org/shadow.html.
+
+Abstract
+
+ The IPP notification extension document [ipp-ntfy] defines operations
+ that a client can perform in order to create Subscription Objects in
+ a Printer and carry out other operations on them. The Subscription
+ Object specifies that when one of the specified Events occurs, the
+ Printer sends an asynchronous Event Notification to the specified
+ Notification Recipient via the specified Delivery Method (i.e.,
+ protocol).
+
+ The notification extension document [ipp-ntfy] specifies that each
+ Delivery Method is defined in another document. This document is one
+ such document, and it specifies the 'indp' Delivery Method and
+ Protocol. This Delivery Method is a simple protocol consisting of a
+ single operation: the Send-Notifications operation which uses the
+ same encoding and transport as IPP. This document defines version
+ '1.0' of the protocol.
+
+ For this Delivery Method, when an Event occurs, the Printer
+ immediately sends (pushes) an Event Notification via the Send-
+
+ Parra, Hastings Expires: August 28, 2001 [page 1]
+
+
+INTERNET-DRAFT IPP: The 'indp' Method and Protocol February 28, 2001
+
+
+ Notifications operation to the Notification Recipient specified in
+ the Subscription Object. The Event Notification content consists of
+ Machine Consumable attributes and a Human Consumable "notify-text"
+ attribute. The Notification Recipient returns a response to the
+ Printer.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Parra, Hastings Expires: August 28, 2001 [page 2]
+
+
+INTERNET-DRAFT IPP: The 'indp' Method and Protocol February 28, 2001
+
+
+ The full set of IPP documents includes:
+
+ Design Goals for an Internet Printing Protocol [RFC2567]
+ Rationale for the Structure and Model and Protocol for the
+ Internet Printing Protocol [RFC2568]
+ Internet Printing Protocol/1.1: Model and Semantics [RFC2911]
+ Internet Printing Protocol/1.1: Encoding and Transport [RFC2910]
+ Internet Printing Protocol/1.1: Implementer's Guide [ipp-iig]
+ Mapping between LPD and IPP Protocols [RFC2569]
+ Internet Printing Protocol (IPP): IPP Event Notification
+ Specification [ipp-ntfy]
+
+ The "Design Goals for an Internet Printing Protocol" document takes a
+ broad look at distributed printing functionality, and it enumerates
+ real-life scenarios that help to clarify the features that need to be
+ included in a printing protocol for the Internet. It identifies
+ requirements for three types of users: end users, operators, and
+ administrators. It calls out a subset of end user requirements that
+ are satisfied in IPP/1.0. A few OPTIONAL operator operations have
+ been added to IPP/1.1.
+
+ The "Rationale for the Structure and Model and Protocol for the
+ Internet Printing Protocol" document describes IPP from a high level
+ view, defines a roadmap for the various documents that form the suite
+ of IPP specification documents, and gives background and rationale
+ for the IETF working group's major decisions.
+
+ The "Internet Printing Protocol/1.1: Model and Semantics" document
+ describes a simplified model with abstract objects, their attributes,
+ and their operations that are independent of encoding and transport.
+ It introduces a Printer and a Job object. The Job object optionally
+ supports multiple documents per Job. It also addresses security,
+ internationalization, and directory issues.
+
+ The "Internet Printing Protocol/1.1: Encoding and Transport" document
+ is a formal mapping of the abstract operations and attributes defined
+ in the model document onto HTTP/1.1 [RFC2616]. It defines the
+ encoding rules for a new Internet MIME media type called
+ "application/ipp". This document also defines the rules for
+ transporting a message body over HTTP whose Content-Type is
+ "application/ipp". This document defines a new scheme named 'ipp'
+ for identifying IPP printers and jobs.
+
+ The "Internet Printing Protocol/1.1: Implementer's Guide" document
+ gives insight and advice to implementers of IPP clients and IPP
+ objects. It is intended to help them understand IPP/1.1 and some of
+ the considerations that may assist them in the design of their client
+ and/or IPP object implementations. For example, a typical order of
+ processing requests is given, including error checking. Motivation
+ for some of the specification decisions is also included.
+
+Parra, Hastings Expires: August 28, 2001 [page 3]
+
+
+INTERNET-DRAFT IPP: The 'indp' Method and Protocol February 28, 2001
+
+
+ The "Mapping between LPD and IPP Protocols" document gives some
+ advice to implementers of gateways between IPP and LPD (Line Printer
+ Daemon) implementations.
+
+ The "Internet Printing Protocol (IPP): IPP Event Notification
+ Specification" document defines the semantics for Subscription
+ Creation Operations and the requirements for other Delivery Method
+ documents to define a Delivery Method to carry an Event Notifications
+ to a Notification Recipient.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Parra, Hastings Expires: August 28, 2001 [page 4]
+
+
+INTERNET-DRAFT IPP: The 'indp' Method and Protocol February 28, 2001
+
+
+
+
+Table of Contents
+
+
+ 1 Introduction....................................................7
+
+ 2 Terminology.....................................................7
+
+ 3 Model and Operation.............................................8
+
+ 4 General Information.............................................9
+
+ 5 Subscription object attributes.................................12
+ 5.1 Subscription Template Attribute Conformance.................12
+ 5.2 Additional Information about Subscription Template Attributes12
+ 5.2.1 notify-recipient-uri (uri)................................12
+ 5.3 Subscription Description Attribute Conformance..............12
+
+ 6 Printer Description Attributes.................................12
+ 6.1 Printer Description Attribute Conformance...................13
+ 6.2 New Values for Existing Printer Description Attributes......13
+ 6.2.1 notify-schemes-supported (1setOf uriScheme)...............13
+ 6.2.2 operations-supported (1setOf type2 enum)..................13
+
+ 7 Attributes Only in Event Notifications.........................13
+
+ 8 Operations for Notification....................................14
+ 8.1 Send-Notifications operation................................14
+ 8.1.1 Send-Notifications Request................................14
+ 8.1.2 Send-Notifications Response...............................18
+
+ 9 Status Codes...................................................19
+ 9.1 Additional Status Codes.....................................19
+ 9.1.1 successful-ok-ignored-notifications (0x0004)..............20
+ 9.1.2 client-error-ignored-all-notifications (0x0416)...........20
+ 9.2 Status Codes returned in Event Notification Attributes Groups20
+ 9.2.1 client-error-not-found (0x0406)...........................20
+ 9.2.2 successful-ok-but-cancel-subscription (0x0006)............20
+
+ 10 Encoding and Transport.........................................21
+ 10.1 Encoding of the Operation Layer.............................21
+ 10.2 Encoding of Transport Layer.................................21
+
+ 11 Conformance Requirements.......................................21
+ 11.1 Conformance Requirements for Printers.......................21
+ 11.2 Conformance Requirements for INDP Notification Recipients...22
+
+ 12 INDP URL Scheme................................................23
+ 12.1 INDP URL Scheme Applicability and Intended Usage............23
+
+Parra, Hastings Expires: August 28, 2001 [page 5]
+
+
+INTERNET-DRAFT IPP: The 'indp' Method and Protocol February 28, 2001
+
+
+ 12.2 INDP URL Scheme Associated INDP Port........................23
+ 12.3 INDP URL Scheme Associated MIME Type........................23
+ 12.4 INDP URL Scheme Character Encoding..........................23
+ 12.5 INDP URL Scheme Syntax in ABNF..............................23
+ 12.5.1 INDP URL Examples.........................................24
+ 12.5.2 INDP URL Comparisons......................................25
+
+ 13 IANA Considerations............................................26
+ 13.1 Operation Registrations.....................................26
+ 13.2 Additional values of existing attributes....................26
+ 13.2.1 Additional values for the "notify-schemes-supported" Printer
+ attribute..............................................26
+ 13.2.2 Additional values for the "operations-supported" Printer
+ attribute..............................................27
+ 13.3 Status code Registrations...................................27
+
+ 14 Internationalization Considerations............................27
+
+ 15 Security Considerations........................................28
+ 15.1 Security Conformance........................................28
+
+ 16 References.....................................................28
+
+ 17 Author's Addresses.............................................30
+
+ 18 Full Copyright Statement.......................................30
+
+
+Tables
+
+ Table 1 - Information about the Delivery Method...................10
+ Table 2 - Operation-id assignments................................13
+ Table 3 - Attributes in Event Notification Content................16
+ Table 4 - Additional Attributes in Event Notification Content for Job
+ Events ........................................................17
+ Table 5 - Combinations of Events and Subscribed Events for "job-
+ impressions-completed" ........................................17
+ Table 6 - Additional Attributes in Event Notification Content for
+ Printer Events ................................................18
+ Table 7 - The "event-notification-attributes-tag" value...........21
+
+
+
+
+
+
+
+
+
+
+
+Parra, Hastings Expires: August 28, 2001 [page 6]
+
+
+INTERNET-DRAFT IPP: The 'indp' Method and Protocol February 28, 2001
+
+
+
+
+
+1 Introduction
+
+ The notification extension document [ipp-ntfy] defines operations
+ that a client can perform in order to create Subscription Objects in
+ a Printer and carry out other operations on them. A Subscription
+ Object represents a Subscription abstraction. The Subscription Object
+ specifies that when one of the specified Events occurs, the Printer
+ sends an asynchronous Event Notification to the specified
+ Notification Recipient via the specified Delivery Method (i.e.,
+ protocol).
+
+ The notification extension document [ipp-ntfy] specifies that each
+ Delivery Method is defined in another document. This document is one
+ such document, and it specifies the 'indp' Delivery Method. This
+ Delivery Method is a simple protocol consisting of a single
+ operation: the Send-Notifications operation which uses the same
+ encoding and transport as IPP. This document defines version '1.0'
+ of the protocol.
+
+ For the 'indp' Delivery Method, an IPP Printer sends (pushes) a Send-
+ Notifications operation request containing one or more Event
+ Notifications to the Notification Recipient specified in the
+ Subscription Object. The Event Notification content consists of
+ Machine Consumable attributes and a Human Consumable "notify-text"
+ attribute.
+
+ The Notification Recipient receives the Event Notification as a Send-
+ Notifications operation, in the same way as an IPP Printer receives
+ IPP operations. The Notification Recipient returns a response to the
+ Printer.
+
+
+2 Terminology
+
+ This section defines the following terms that are used throughout
+ this document:
+
+ Terms such as attributes, keywords, and support. These terms have
+ special meaning and are defined in the model terminology
+ [RFC2911] section 12.2.
+
+ Capitalized terms, such as MUST, MUST NOT, REQUIRED, SHOULD,
+ SHOULD NOT, MAY, NEED NOT, and OPTIONAL, have special
+ meaning relating to conformance as specified in RFC 2119
+ [RFC2119] and [RFC2911] section 12.1. These terms refer to
+ conformance to this document, if this document is
+ implemented.
+
+Parra, Hastings Expires: August 28, 2001 [page 7]
+
+
+INTERNET-DRAFT IPP: The 'indp' Method and Protocol February 28, 2001
+
+
+ Capitalized terms, such as Notification Recipient, Event
+ Notification, Printer, etc., that are defined in [ipp-ntfy]
+ with the same meanings and are not reproduced here.
+
+ Event Notification Attributes Group - The attributes group in a
+ request that contains Event Notification Attributes in a
+ request or response.
+
+
+3 Model and Operation
+
+ See [ipp-ntfy] for the description of the Event Notification Model
+ and Operation. This Delivery Method takes advantage of combining
+ several Event Notifications into a single Compound Event Notification
+ that is delivery by a single Send-Notification operation to a single
+ Notification Recipient.
+
+ When creating each Subscription object, the client supplies the
+ "notify-recipient" (uri) Subscription Template attribute. The
+ "notify-recipient" attribute specifies both a single Notification
+ Recipient that is to receive the Notifications when subsequent events
+ occur and the method for notification delivery that the IPP Printer
+ is to use. For the Notification Delivery Method defined in this
+ document, the notification method is 'indp' and the rest of the URI
+ is the address of the Notification Recipient to which the IPP Printer
+ will send the Send-Notifications operation.
+
+ The 'indp' Notification Delivery Method defined in this document uses
+ a client/server protocol paradigm. The "client" in this relationship
+ is the Printer described in [ipp-ntfy] while the "server" is the
+ Notification Recipient. The Printer invokes the Send-Notifications
+ operation to communicate IPP Event Notification contents to the
+ Notification Recipient. The Notification Recipient only conveys
+ information to the Printer in the form of responses to the operations
+ initiated by the Printer.
+
+ Printers that implement the 'indp' Notification Delivery Method will
+ need to include an HTTP client stack while Notification Recipients
+ that implement this Delivery Method will need to support an HTTP
+ server stack. See section 10.2 for more details.
+
+ If the client wants the Printer to send Event Notifications via the
+ 'indp' Delivery Method, the client MUST choose a value for "notify-
+ recipient-uri" attribute which conforms to the rules of section
+ 5.2.1.
+
+ When an Event occurs, the Printer MUST immediately:
+
+ 1.Find all pertinent Subscription Objects P according to the rules of
+ section 9 of [ipp-ntfy], AND
+
+Parra, Hastings Expires: August 28, 2001 [page 8]
+
+
+INTERNET-DRAFT IPP: The 'indp' Method and Protocol February 28, 2001
+
+
+ 2.Find the subset M of these Subscription Objects P whose "notify-
+ recipient-uri" attribute has a scheme value of 'indp', AND
+
+ 3.For each Subscription Object in M, the Printer MUST
+
+ a)generate a Send-Notifications request as specified in section
+ 8.1.1 AND
+
+ b)send the Send-Notifications request to the Notification
+ Recipient specified by the address part of the "notify-
+ recipient-uri" attribute value (see section 5.2.1).
+
+ If several events occur sufficiently close to one another for the
+ same or different Subscription objects, but with the same
+ Notification Recipient, the Printer MAY combine them into a single
+ Send-Notifications request using a separate Event Notification
+ Attributes group for each event (see section 8.1.1).
+
+
+4 General Information
+
+ If a Printer supports this Delivery Method, Table 1 lists its
+ characteristics.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Parra, Hastings Expires: August 28, 2001 [page 9]
+
+
+INTERNET-DRAFT IPP: The 'indp' Method and Protocol February 28, 2001
+
+
+ Table 1 - Information about the Delivery Method
+
+
+ Document Method conformance 'indp' realization
+ requirement
+
+
+ 1. What is the URL scheme name indp
+ for the Delivery Method?
+
+ 2. Is the Delivery Method is RECOMMENDED
+ REQUIRED, RECOMMENDED, or
+ OPTIONAL for an IPP Printer to
+ support?
+
+ 3. What transport and delivery A Printer MUST support a
+ protocol does the Printer use complete HTTP/1.1 stack
+ to deliver the Event [RFC2616]
+ Notification content, i.e.,
+ what is the entire network
+ stack?
+
+ 4. Can several Event A Printer implementation MAY
+ Notifications be combined into combine several Event
+ a Compound Event Notification? Notifications into a single
+ Event Notifications request as
+ separate Event Notification
+ Attributes Groups, see section
+ 8.1.1
+
+ 5. Is the Delivery Method This Delivery Method is a push.
+ initiated by the Notification
+ Recipient (pull), or by the
+ Printer (push)?
+
+ 6. Is the Event Notification Machine Consumable with the
+ content Machine Consumable or "notify-text" attribute being
+ Human Consumable? Human Consumable
+
+ 7. What section in this document The representation and encoding
+ answers the following is the same as IPP. See
+ question? For a Machine section 8.1.1
+ Consumable Event Notification,
+ what is the representation and
+ encoding of values defined in
+ section 9.1 of [ipp-ntfy] and
+ the conformance requirements
+ thereof? For a Human
+ Consumable Event Notification,
+
+
+Parra, Hastings Expires: August 28, 2001 [page 10]
+
+
+INTERNET-DRAFT IPP: The 'indp' Method and Protocol February 28, 2001
+
+
+
+ Document Method conformance 'indp' realization
+ requirement
+
+
+ what is the representation and
+ encoding of pieces of
+ information defined in section
+ 9.2 of [ipp-ntfy] and the
+ conformance requirements
+ thereof?
+
+ 8. What are the latency and
+ reliability of the transport itselfs(see [RFC2911]).IPP/1.1
+ and delivery protocol?
+
+ 9. What are the security aspects 15
+ of the transport and delivery
+ protocol, e.g., how it is See section
+ handled in firewalls?
+
+ 10. What are the content length They are the same as for
+ restrictions? IPP/1.0 and IPP/1.1 itself (see
+ [RFC2911]).
+
+ 11. What are the additional values A new Event Notifications
+ or pieces of information that attribute group (see section
+ a Printer sends in an Event 10.1) and additional status
+ Notification and the codes for use in the response
+ conformance requirements (see section 9)
+ thereof?
+
+ 12. What are the additional None
+ Subscription Template and/or
+ Subscription Description
+ attributes and the conformance
+ requirements thereof?
+
+ 13. What are the additional None
+ Printer Description attributes
+ and the conformance
+ requirements thereof?
+
+
+ The remaining sections of this document parallel the sections of
+ [ipp-ntfy].
+
+
+
+
+
+Parra, Hastings Expires: August 28, 2001 [page 11]
+
+
+INTERNET-DRAFT IPP: The 'indp' Method and Protocol February 28, 2001
+
+
+5 Subscription object attributes
+
+ This section defines the Subscription object conformance requirements
+ for Printers.
+
+
+5.1 Subscription Template Attribute Conformance
+
+ The 'indp' Delivery Method has the same conformance requirements for
+ Subscription Template attributes as defined in [ipp-ntfy]. The
+ 'indp' Delivery Method does not define any addition Subscription
+ Template attributes.
+
+
+5.2 Additional Information about Subscription Template Attributes
+
+ This section defines additional information about Subscription
+ Template attributes defined in [ipp-ntfy].
+
+
+5.2.1 notify-recipient-uri (uri)
+
+ This section describes the syntax of the value of this attribute for
+ the 'indp' Delivery Method. The syntax for values of this attribute
+ for other Delivery Method is defined in other Delivery Method
+ Documents.
+
+ In order to support the 'indp' Delivery Method and Protocol, the
+ Printer MUST support the following syntax:
+
+ The 'indp://' URI scheme. The remainder of the URI indicates
+ the host name or host address (and optional path) of the
+ Notification Recipient that is to receive the Send-
+ Notification operation.
+
+
+5.3 Subscription Description Attribute Conformance
+
+ The 'indp' Delivery Method has the same conformance requirements for
+ Subscription Description attributes as defined in [ipp-ntfy]. The
+ 'indp' Delivery Method does not define any addition Subscription
+ Description attributes.
+
+
+6 Printer Description Attributes
+
+ This section defines the Printer Description Attributes conformance
+ requirements for Printers.
+
+
+
+Parra, Hastings Expires: August 28, 2001 [page 12]
+
+
+INTERNET-DRAFT IPP: The 'indp' Method and Protocol February 28, 2001
+
+
+6.1 Printer Description Attribute Conformance
+
+ The 'indp' Delivery Method has the same conformance requirements for
+ Printer Description attributes as defined in [ipp-ntfy]. The 'indp'
+ Delivery Method does not define any addition Printer Description
+ attributes.
+
+
+6.2 New Values for Existing Printer Description Attributes
+
+ This section defines additional values for existing Printer
+ Description attributes.
+
+
+6.2.1 notify-schemes-supported (1setOf uriScheme)
+
+ The following "notify-schemes-supported" value is added in order to
+ support the new Delivery Method defined in this document:
+
+ 'indp' - The IPP Notification Delivery Method defined in this
+ document.
+
+6.2.2 operations-supported (1setOf type2 enum)
+
+ Table 2 lists the "operation-id" value added in order to support the
+ new operation defined in this document. The operation-id is assigned
+ in the same name space as other operations that a Printer supports.
+ However, a Printer MUST NOT include this value in its "operations-
+ supported" attribute unless it can accept the Send-Notifications
+ request.
+
+ Table 2 - Operation-id assignments
+
+
+ Value Operation Name
+
+
+ 0x001D Send-Notifications
+
+
+
+
+7 Attributes Only in Event Notifications
+
+ No additional attributes are defined only for use in Event
+ Notifications besides those defined in [ipp-ntfy].
+
+
+
+
+
+Parra, Hastings Expires: August 28, 2001 [page 13]
+
+
+INTERNET-DRAFT IPP: The 'indp' Method and Protocol February 28, 2001
+
+
+8 Operations for Notification
+
+ This section defines the operation for Event Notification using the
+ 'indp' Delivery Method.
+
+ There is only one operation defined: Send-Notifications. Section
+ 6.2.2 assigns of the "operation-id" for the Send-Notifications
+ operation and the following section defined the operation.
+
+
+8.1 Send-Notifications operation
+
+ This REQUIRED operation allows a Printer to send one or more Event
+ Notifications to a Notification Recipient using HTTP.
+
+ The Printer composes the information defined for an IPP Notification
+ [ipp-ntfy] and sends it using the Sent-Notifications operation to the
+ Notification Recipient supplied in the Subscription object.
+
+ The Send-Notifications operations uses the operations model defined
+ by IPP [RFC2566]. This includes, the use of a URI as the identifier
+ for the target of each operation, the inclusion of a version number,
+ operation-id, and request-id in each request, and the definition of
+ attribute groups. The Send-Notifications operation uses the Operation
+ Attributes group, but currently has no need for the Unsupported
+ Attributes, Printer Object Attributes, and Job-Object Attributes
+ groups. However, it uses a new attribute group, the Event
+ Notification Attributes group.
+
+ The Notification Recipient MUST accept the request in any state.
+ There is no state defined for the Notification Recipient for this
+ Delivery Method.
+
+ Access Rights: Notification Recipient MAY enforce access rights. If
+ the Printer receives a rejection with these status codes: 'client-
+ error-forbidden', 'client-error-not-authenticated', or 'client-error-
+ not-authorized' status code , the Printer SHOULD cancel the
+ subscription.
+
+
+8.1.1 Send-Notifications Request
+
+ Every operation request MUST contains the following parameters (see
+ [RFC2911] section 3.1.1):
+
+ - a "version-number" '1.0' - the version of the 'indp'
+ protocol is '1.0'.
+ - an "operation-id" - the value defined in Table 2
+ - a "request-id" - the request id (see [RFC2911] section 3.1.2).
+
+
+Parra, Hastings Expires: August 28, 2001 [page 14]
+
+
+INTERNET-DRAFT IPP: The 'indp' Method and Protocol February 28, 2001
+
+
+ The following groups of attributes MUST be part of the Send-
+ Notifications Request:
+
+
+ Group 1: Operation Attributes
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as defined in [RFC2911] section 3.1.4.1.
+
+ The Printer MUST use the values of "notify-charset" and
+ "notify-natural-language", respectively, from one Subscription
+ Object associated with the Event Notifications in this request.
+
+ Normally, there is only one matched Subscription Object, or the
+ value of the "notify-charset" and "notify-natural-language"
+ attributes is the same in all Subscription Objects. If not, the
+ Printer MUST pick one Subscription Object from which to obtain
+ the value of these attributes. The algorithm for picking the
+ Subscription Object is implementation dependent. The choice of
+ natural language is not critical because 'text' and 'name'
+ values can override the "attributes-natural-language" Operation
+ attribute. The Printer's choice of charset is critical because
+ a bad choice may leave it unable to send some 'text' and 'name'
+ values accurately.
+
+ Target:
+ A copy of the Subscription object's "notify-recipient-uri"
+ (uri) attribute which is the target of this operation as
+ described in [RFC2911] section 3.1.5, i.e., the URI of the
+ 'indp' Notification Recipient (see section 5.2.1).
+
+ Group 2 to N: Event Notification Attributes
+
+ In each group 2 to N, each attribute is encoded using the IPP
+ rules for encoding attributes [RFC2910] and may be encoded in
+ any order. Note: the Get-Jobs response in [RFC2911] acts as a
+ model for encoding multiple groups of attributes.
+
+ Each Event Notification Group MUST contain all of attributes
+ specified in [ipp-ntfy] section 9.1 ("Content of Machine
+ Consumable Event Notifications") with exceptions denoted by
+ asterisks in the tables below.
+
+ The tables below are copies of the tables in [ipp-ntfy] section
+ 9.1 ("Content of Machine Consumable Event Notifications")
+ except that each cell in the "Sends" column is a "MUST".
+
+ For an Event Notification for all Events, the Printer sends the
+ following attributes.
+
+
+Parra, Hastings Expires: August 28, 2001 [page 15]
+
+
+INTERNET-DRAFT IPP: The 'indp' Method and Protocol February 28, 2001
+
+
+ Table 3 - Attributes in Event Notification Content
+
+
+ Source Value Sends Source Object
+
+
+ notify-subscription-id (integer(1:MAX)) MUST Subscription
+
+ notify-printer-uri (uri) MUST Subscription
+
+ notify-subscribed-event (type2 keyword) MUST Event
+ Notification
+
+ printer-up-time (integer(MIN:MAX)) MUST Printer
+
+ printer-current-time (dateTime) * MUST Printer
+
+ notify-sequence-number (integer (0:MAX)) MUST Subscription
+
+ notify-charset (charset) MUST Subscription
+
+ notify-natural-language (naturalLanguage) MUST Subscription
+
+ notify-user-data (octetString(63)) ** MUST Subscription
+
+ notify-text (text (MAX)) MUST Event
+ Notification
+
+ attributes from the "notify-attributes" MUST *** Printer
+ attribute, if any ***
+
+ attributes from the "notify-attributes" MUST *** Job
+ attribute, if any ***
+
+ attributes from the "notify-attributes" MUST *** Subscription
+ attribute, if any ***
+
+
+ * The Printer MUST send "printer-current-time" if and only if
+ it supports the "printer-current-time" attribute on the Printer
+ object.
+
+ ** If the associated Subscription Object does not contain a
+ "notify-user-data" attribute, the Printer MUST send an octet-
+ string of length 0.
+
+ *** If the "notify-attributes" attribute is present on the
+ Subscription Object, the Printer MUST send all attributes
+ specified by the "notify-attributes" attribute. Note: if the
+ Printer doesn't support the "notify-attributes" attribute, it
+
+Parra, Hastings Expires: August 28, 2001 [page 16]
+
+
+INTERNET-DRAFT IPP: The 'indp' Method and Protocol February 28, 2001
+
+
+ is not present on the associated Subscription Object and the
+ Printer does not send any client-requested attributes.
+
+ For Event Notifications for Job Events, the Printer sends the
+ following additional attributes shown in Table 4.
+
+ Table 4 - Additional Attributes in Event Notification Content for
+ Job Events
+
+
+ Source Value Sends Source Object
+
+
+ job-id (integer(1:MAX)) MUST Job
+
+ job-state (type1 enum) MUST Job
+
+ job-state-reasons (1setOf type2 keyword) MUST Job
+
+ job-impressions-completed MUST Job
+ (integer(0:MAX)) *
+
+
+ * The Printer MUST send the "job-impressions-completed"
+ attribute in an Event Notification only for the combinations of
+ Events and Subscribed Events shown in Table 5.
+
+
+
+ Table 5 - Combinations of Events and Subscribed Events for "job-
+ impressions-completed"
+
+
+ Job Event Subscribed Job Event
+
+
+ 'job-progress' 'job-progress'
+
+ 'job-completed' 'job-completed'
+
+ 'job-completed' 'job-state-changed'
+
+
+ For Event Notification for Printer Events, the Printer sends
+ the following additional attributes shown in Table 6.
+
+
+
+
+
+
+Parra, Hastings Expires: August 28, 2001 [page 17]
+
+
+INTERNET-DRAFT IPP: The 'indp' Method and Protocol February 28, 2001
+
+
+ Table 6 - Additional Attributes in Event Notification Content for
+ Printer Events
+
+
+ Source Value Sends Source Object
+
+
+ printer-state (type1 enum) MUST Printer
+
+ printer-state-reasons (1setOf type2 keyword) MUST Printer
+
+ printer-is-accepting-jobs (boolean) MUST Printer
+
+
+
+8.1.2 Send-Notifications Response
+
+ The Notification Recipient MUST return (to the client which is the
+ Printer) the following sets of attributes as part of a Send-
+ Notifications response:
+
+ Every operation response contains the following REQUIRED parameters
+ (see [RFC2911] section 3.1.1}:
+
+ - a "version-number"
+ - a "status-code"
+ - the "request-id" that was supplied in the corresponding request
+
+ Group 1: Operation Attributes
+
+ Status Message:
+ As defined in [RFC2911].
+
+ The Notification Recipient can return any status codes defined
+ in [RFC2911] and section 9.1 that applies to all of the Event
+ Notification Attribute groups. The following is a description
+ of the important status codes:
+
+ 'successful-ok': the Notification Recipient received all of
+ the Event Notification Attribute Groups and was expecting
+ each of them.
+
+ 'successful-ok-ignored-notifications': the Notification
+ Recipient was able to consume some, but not all of the
+ Event Notification Attributes Groups sent. The Event
+ Notification Attributes Groups with a "notify-status-
+ code" attribute are the ones that were ignored or are to
+ be canceled.
+
+
+
+Parra, Hastings Expires: August 28, 2001 [page 18]
+
+
+INTERNET-DRAFT IPP: The 'indp' Method and Protocol February 28, 2001
+
+
+ 'client-error-ignored-all-notifications': the Notification
+ Recipient was unable to consume any of the Event
+ Notification Attributes Groups sent. The Event
+ Notification Attributes Groups with a "notify-status-
+ code" attribute are the ones that were ignored or are to
+ be canceled.
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as defined in [RFC2911] section 3.1.4.1.
+
+ Group 2 to N: Notification Attributes
+
+ These groups MUST be returned if and only if the "status-code"
+ parameter returned in Group 1 is anything but the 'successful-ok'
+ status code.
+
+ "notify-status-code" (type2 enum)
+ Indicates whether the Notification Recipient was able to
+ consume the n-th Notification Report as follows:
+
+ 'successful-ok' - this Event Notification Attribute Group
+ was consumed
+ 'client-error-not-found' - this Event Notification
+ Attribute Group was not able to be consumed. The Printer
+ MUST cancel the Subscription and MUST NOT attempt to send
+ any further Event Notifications from the associated
+ Subscription object.
+ 'successful-ok-but-cancel-subscription' - the Event
+ Notification Attribute Group was consumed, but the
+ Notification Recipient wishes to cancel the Subscription
+ object. The Printer MUST cancel the Subscription and
+ MUST NOT attempt to send any further Event Notifications
+ from the associated Subscription object.
+
+9 Status Codes
+
+ This section lists status codes whose meaning have been extended
+ and/or defined for returning in Event Notification Attribute Groups
+ as the value of the "notify-status-code" operation attribute. The
+ code values are allocated in the same space as the status codes in
+ [RFC2911].
+
+
+9.1 Additional Status Codes
+
+ The following status codes are defined as extensions for Notification
+ and are returned as the value of the "status-code" parameter in the
+ Operation Attributes Group of a response (see [RFC2911] section
+ 3.1.6.1). Operations in this document can also return the status
+
+Parra, Hastings Expires: August 28, 2001 [page 19]
+
+
+INTERNET-DRAFT IPP: The 'indp' Method and Protocol February 28, 2001
+
+
+ codes defined in section 13 of [RFC2911]. The 'successful-ok' status
+ code is an example of such a status code.
+
+
+9.1.1 successful-ok-ignored-notifications (0x0004)
+
+ The Notification Recipient was able to consume some, but not all, of
+ the Event Notifications Attributes Groups sent by the Printer in the
+ Send-Notifications request. See section 8.1.2 for further details.
+
+
+9.1.2 client-error-ignored-all-notifications (0x0416)
+
+ The Notification Recipient was unable to consume any of the Event
+ Notification Attributes Groups sent by the Printer. The Event
+ Notification Attributes Groups with a "notify-status-code" attribute
+ are the ones that were ignored or are to be canceled.
+
+
+9.2 Status Codes returned in Event Notification Attributes Groups
+
+ This section contains values of the "notify-status-code" attribute
+ that the Notification Recipient returns in a Event Notification
+ Attributes Group in a response when the corresponding Event
+ Notification Attributes Group in the request:
+
+ 1.was not consumed OR
+
+ 2.was consumed, but the Notification Recipient wants to cancel the
+ corresponding Subscription object
+
+ The following sections are ordered in decreasing order of importance
+ of the status-codes.
+
+
+9.2.1 client-error-not-found (0x0406)
+
+ This status code is defined in [RFC2911]. This document extends its
+ meaning and allows it to be returned in an Event Notification
+ Attributes Group of a response.
+
+ The Notification Recipient was unable to consume this Event
+ Notification Attributes Group because it was not expected. See
+ section 8.1.2 for further details.
+
+
+9.2.2 successful-ok-but-cancel-subscription (0x0006)
+
+ The Notification Recipient was able to consume this Event
+ Notification Attributes Group that the Printer sent, but wants the
+
+Parra, Hastings Expires: August 28, 2001 [page 20]
+
+
+INTERNET-DRAFT IPP: The 'indp' Method and Protocol February 28, 2001
+
+
+ corresponding Subscription object to be canceled none-the-less. See
+ section 8.1.2 for further details.
+
+
+10 Encoding and Transport
+
+ This section defines the encoding and transport used by the 'indp'
+ Delivery Method.
+
+
+10.1 Encoding of the Operation Layer
+
+ The 'indp' Delivery Method uses the IPP operation layer encoding
+ described in [RFC2910] and the Event Notification Attributes Group
+ tag allocated by [ipp-ntfy] as shown in Table 7:
+
+ Table 7 - The "event-notification-attributes-tag" value
+
+
+ Tag Value (Hex) Meaning
+
+
+ 0x07 "event-notification-attributes-tag"
+
+
+
+10.2 Encoding of Transport Layer
+
+ The 'indp' Notification Delivery Method uses the IPP transport layer
+ encoding described in [RFC2910].
+
+ It is REQUIRED that an 'indp' Notification Recipient implementation
+ support HTTP over the IANA assigned Well Known Port assigned to the
+ 'indp' Delivery Method as its default port by IANA (see section 13),
+ though a Notification Recipient implementation MAY support HTTP over
+ some other port as well.
+
+
+11 Conformance Requirements
+
+ This section defines conformance requirements for Printers and
+ Notification Recipients.
+
+
+11.1 Conformance Requirements for Printers
+
+ The 'indp' Delivery Method is RECOMMENDED for a Printer to support.
+
+ IPP Printers that conform to this specification:
+
+
+Parra, Hastings Expires: August 28, 2001 [page 21]
+
+
+INTERNET-DRAFT IPP: The 'indp' Method and Protocol February 28, 2001
+
+
+ 1.MUST meet the conformance requirements defined in [ipp-ntfy].
+
+ 2.MUST support the conformance requirements for Subscription object
+ attributes defined in section 5, including the syntax for the
+ "notify-recipient-uri" Subscription Object attribute defined in
+ section 5.2.1.
+
+ 3.MUST support the conformance requirements for Printer Description
+ object attributes defined in section 6.
+
+ 4.MUST support the 'indp' protocol by sending Event Notifications
+ using the Send-Notifications operation defined in section 8.1.
+
+ 5.MUST send INDP URLs (e.g., in the "notify-recipient-uri" attribute
+ in 'Send-Notifications') that conform to the ABNF specified in
+ section 12.5 of this document;
+
+ 6.MUST send INDP operations via the port specified in the INDP URL
+ (if present) or otherwise via IANA assigned well-known port [TBD];
+
+ 7.MUST convert INDP URLs to their corresponding HTTP URL forms by
+ the same rules used to convert IPP URLs to their corresponding
+ HTTP URL forms (see section 5 'IPP URL Scheme' in [RFC2910]).
+
+
+11.2 Conformance Requirements for INDP Notification Recipients
+
+ INDP Notification Recipients that conform to this specification:
+
+ 1.MUST accept Send-Notifications requests and return Send-
+ Notifications responses as defined in sections 8 and 9.
+
+ 2.SHOULD reject received INDP URLs in "application/ipp" request
+ bodies (e.g., in the "notify-recipient-uri" attribute in 'Send-
+ Notifications') that do not conform to the ABNF for INDP URLs
+ specified in section 12.5 of this document;
+
+ 3.MUST listen for INDP operations on IANA-assigned well-known port
+ [TBD], unless explicitly configured by system administrators or
+ site policies;
+
+ 4.SHOULD NOT listen for INDP operations on any other port, unless
+ explicitly configured by system administrators or site policies.
+
+
+
+
+
+
+
+
+Parra, Hastings Expires: August 28, 2001 [page 22]
+
+
+INTERNET-DRAFT IPP: The 'indp' Method and Protocol February 28, 2001
+
+
+12 INDP URL Scheme
+
+
+12.1 INDP URL Scheme Applicability and Intended Usage
+
+ This section is intended for use in registering the "indp" URL scheme
+ with IANA and fully conforms to the requirements in [RFC2717]. This
+ document defines the "indp" URL (Uniform Resource Locator) scheme for
+ specifying the location of an INDP Notification Recipient object
+ which implements IPP Notification Delivery Protocol (INDP) specified
+ in this document.
+
+ The intended usage of the "indp" URL scheme is COMMON.
+
+
+12.2 INDP URL Scheme Associated INDP Port
+
+ All INDP URLs which do NOT explicitly specify a port MUST be used
+ over IANA-assigned well-known port [TBD] for the INDP protocol.
+
+ See: IANA Port Numbers Registry [IANA-PORTREG].
+
+
+12.3 INDP URL Scheme Associated MIME Type
+
+ All INDP protocol operations (requests and responses) MUST be
+ conveyed in an "application/ipp" MIME media type as registered in
+ [IANA-MIMEREG]. INDP URLs MUST refer to INDP Notification Recipient
+ objects which support this "application/ipp" MIME media type.
+
+ See: IANA MIME Media Types Registry [IANA-MIMEREG].
+
+
+12.4 INDP URL Scheme Character Encoding
+
+ The INDP URL scheme defined in this document is based on the ABNF for
+ the HTTP URL scheme defined in HTTP/1.1 [RFC2616], which is derived
+ from the URI Generic Syntax [RFC2396] and further updated by
+ [RFC2732] and [RFC2373] (for IPv6 addresses in URLs). The INDP URL
+ scheme is case-insensitive in the host name or host address part;
+ however the path part is case-sensitive, as in [RFC2396]. Code
+ points outside [US-ASCII] MUST be hex escaped by the mechanism
+ specified in [RFC2396].
+
+
+12.5 INDP URL Scheme Syntax in ABNF
+
+ This section is intended for use in registering the "indp" URL scheme
+ with IANA and fully conforms to the requirements in [RFC2717]. This
+ document defines the "indp" URL (Uniform Resource Locator) scheme for
+
+Parra, Hastings Expires: August 28, 2001 [page 23]
+
+
+INTERNET-DRAFT IPP: The 'indp' Method and Protocol February 28, 2001
+
+
+ specifying the location of an INDP Notification Recipient object
+ which implements IPP Notification Delivery Protocol (INDP) specified
+ in this document.
+
+ The intended usage of the "indp" URL scheme is COMMON.
+
+ The IPP protocol places a limit of 1023 octets (NOT characters) on
+ the length of a URI (see section 4.1.5 'uri' in [RFC2911]). An INDP
+ Notification Recipient MUST return 'client-error-request-value-too-
+ long' (see section 13.1.4.10 in [RFC2911]) when a URI received in a
+ request is too long.
+
+ Note: INDP Notification Recipients ought to be cautious about
+ depending on URI lengths above 255 bytes, because some older client
+ or proxy implementations might not properly support these lengths.
+
+ INDP URLs MUST be represented in absolute form. Absolute URLs always
+ begin with a scheme name followed by a colon. For definitive
+ information on URL syntax and semantics, see "Uniform Resource
+ Identifiers (URI): Generic Syntax and Semantics" [RFC2396]. This
+ specification adopts the definitions of "port", "host", "abs_path",
+ and "query" from [RFC2396], as updated by [RFC2732] and [RFC2373]
+ (for IPv6 addresses in URLs).
+
+ The INDP URL scheme syntax in ABNF is as follows:
+
+ indp_URL = "indp:" "//" host [ ":" port ] [ abs_path [ "?" query ]]
+
+ If the port is empty or not given, IANA-assigned well-known port
+ [TBD] is assumed. The semantics are that the identified resource
+ (see section 5.1.2 of [RFC2616]) is located at the INDP Notification
+ Recipient listening for HTTP connections on that port of that host,
+ and the Request-URI for the identified resource is 'abs_path'.
+
+ Note: The use of IP addresses in URLs SHOULD be avoided whenever
+ possible (see [RFC1900]).
+
+ If the 'abs_path' is not present in the URL, it MUST be given as "/"
+ when used as a Request-URI for a resource (see section 5.1.2 of
+ [RFC2616]). If a proxy receives a host name which is not a fully
+ qualified domain name, it MAY add its domain to the host name it
+ received. If a proxy receives a fully qualified domain name, the
+ proxy MUST NOT change the host name.
+
+
+12.5.1 INDP URL Examples
+
+ The following are examples of valid INDP URLs for Notification
+ Recipient objects (using DNS host names):
+
+
+Parra, Hastings Expires: August 28, 2001 [page 24]
+
+
+INTERNET-DRAFT IPP: The 'indp' Method and Protocol February 28, 2001
+
+
+ indp://abc.com
+ indp://abc.com/listener
+
+ Note: The use of IP addresses in URLs SHOULD be avoided whenever
+ possible (see [RFC1900]).
+
+ The following literal IPv4 addresses:
+
+ 192.9.5.5 ; IPv4 address in IPv4 style
+ 186.7.8.9 ; IPv4 address in IPv4 style
+
+ are represented in the following example INDP URLs:
+
+ indp://192.9.5.5/listener
+ indp://186.7.8.9/listeners/tom
+
+ The following literal IPv6 addresses (conformant to [RFC2373]):
+
+ ::192.9.5.5 ; IPv4 address in IPv6 style
+ ::FFFF:129.144.52.38 ; IPv4 address in IPv6 style
+ 2010:836B:4179::836B:4179 ; IPv6 address per RFC 2373
+
+ are represented in the following example INDP URLs:
+
+ indp://[::192.9.5.5]/listener
+ indp://[::FFFF:129.144.52.38]/listener
+ indp://[2010:836B:4179::836B:4179]/listeners/tom
+
+
+12.5.2 INDP URL Comparisons
+
+ When comparing two INDP URLs to decide if they match or not, an INDP
+ Client SHOULD use a case-sensitive octet-by-octet comparison of the
+ entire URLs, with these exceptions:
+
+ . A port that is empty or not given is equivalent to the well-
+ known port for that INDP URL (port [TBD]);
+
+ . Comparisons of host names MUST be case-insensitive;
+
+ . Comparisons of scheme names MUST be case-insensitive;
+
+ . An empty 'abs_path' is equivalent to an 'abs_path' of "/".
+
+ Characters other than those in the "reserved" and "unsafe" sets (see
+ [RFC2396] and [RFC2732]) are equivalent to their ""%" HEX HEX"
+ encoding.
+
+ For example, the following three URIs are equivalent:
+
+
+Parra, Hastings Expires: August 28, 2001 [page 25]
+
+
+INTERNET-DRAFT IPP: The 'indp' Method and Protocol February 28, 2001
+
+
+ indp://abc.com/~smith/listener
+ indp://ABC.com/%7Esmith/listener
+ indp://ABC.com:/%7esmith/listener
+
+
+13 IANA Considerations
+
+ IANA is requested to register the indp URL scheme as defined in
+ section 12.
+
+ IANA is requested to assign a default system port (less than 1024)
+ for use with the indp URL as defined in section 12.
+
+ The rest of this section contains the exact information for IANA to
+ add to the IPP Registries according to the procedures defined in RFC
+ 2911 [RFC2911] section 6.
+
+ Note to RFC Editors: Replace RFC NNNN below with the RFC number
+ for this document, so that it accurately reflects the content of
+ the information for the IANA Registry.
+
+
+13.1 Operation Registrations
+
+ The operations defined in this document will be published by IANA
+ according to the procedures in RFC 2911 [RFC2911] section 6.4 with
+ the following path:
+
+ ftp.isi.edu/iana/assignments/ipp/operations/
+
+ The registry entry will contain the following information:
+
+ Operations: Ref. Section:
+ Send-Notifications operation RFC NNNN 8.1
+
+
+13.2 Additional values of existing attributes
+
+
+13.2.1 Additional values for the "notify-schemes-supported" Printer
+ attribute
+
+ The "notify-schemes-supported" uriScheme attribute value defined in
+ this document will be published by IANA according to the procedures
+ in RFC 2911 [RFC2911] section 6.1 with the following path:
+
+ ftp.isi.edu/iana/assignments/ipp/attribute-values/notify-schemes-
+ supported/
+
+ The registry entry will contain the following information:
+
+Parra, Hastings Expires: August 28, 2001 [page 26]
+
+
+INTERNET-DRAFT IPP: The 'indp' Method and Protocol February 28, 2001
+
+
+ Ref. Section:
+ indp RFC NNNN 6.2.1
+
+
+13.2.2 Additional values for the "operations-supported" Printer
+ attribute
+
+ The "operations-supported" type2 enum attribute value defined in this
+ document will be published by IANA according to the procedures in RFC
+ 2911 [RFC2911] section 6.1 with the following path:
+
+ ftp.isi.edu/iana/assignments/ipp/attribute-values/operations-
+ supported/
+
+ The registry entry will contain the following information:
+
+ Value Ref. Section:
+ Send-Notifications 0x001D RFC NNNN 6.2.1
+
+
+13.3 Status code Registrations
+
+ The status codes defined in this document will be published by IANA
+ according to the procedures in RFC 2911 [RFC2911] section 6.6 with
+ the following path:
+
+ ftp.isi.edu/iana/assignments/ipp/status-codes/
+
+ The registry entry will contain the following information:
+
+ Status codes: Ref. Section:
+ successful-ok-ignored-notifications (0x0004) RFC NNNN 9.1.1
+ client-error-ignored-all-notifications (0x0416) RFC NNNN 9.1.2
+
+
+
+14 Internationalization Considerations
+
+ When the client requests Human Consumable form by supplying the
+ "notify-text-format" operation attribute (see [ipp-ntfy]), the IPP
+ Printer (or any Notification Service that the IPP Printer might be
+ configured to use) supplies and localizes the text value of the
+ "human-readable-report" attribute in the Notification according to
+ the charset and natural language requested in the notification
+ subscription.
+
+
+
+
+
+
+Parra, Hastings Expires: August 28, 2001 [page 27]
+
+
+INTERNET-DRAFT IPP: The 'indp' Method and Protocol February 28, 2001
+
+
+15 Security Considerations
+
+ The IPP Model and Semantics document [RFC2911] discusses high level
+ security requirements (Client Authentication, Server Authentication
+ and Operation Privacy). Client Authentication is the mechanism by
+ which the client proves its identity to the server in a secure
+ manner. Server Authentication is the mechanism by which the server
+ proves its identity to the client in a secure manner. Operation
+ Privacy is defined as a mechanism for protecting operations from
+ eavesdropping.
+
+ The Notification Recipient can cancel unwanted Subscriptions created
+ by other parties without having to be the owner of the subscription
+ by returning the 'successful-ok-but-cancel-subscription' status code
+ in the Send-Notifications response returned to the Printer.
+
+15.1 Security Conformance
+
+ Printers (client) MAY support Digest Authentication [RFC2617]. If
+ Digest Authentication is supported, then MD5 and MD5-sess MUST be
+ supported, but the Message Integrity feature NEED NOT be supported.
+
+ Notification Recipient (server) MAY support Digest Authentication
+ [RFC2617]. If Digest Authentication is supported, then MD5 and MD5-
+ sess MUST be supported, but the Message Integrity feature NEED NOT be
+ supported.
+
+ Notification Recipients MAY support TLS for client authentication,
+ server authentication and operation privacy. If a Notification
+ Recipient supports TLS, it MUST support the
+ TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA cipher suite as mandated by RFC
+ 2246 [RFC2246]. All other cipher suites are OPTIONAL. Notification
+ recipients MAY support Basic Authentication (described in HTTP/1.1
+ [RFC2616]) for client authentication if the channel is secure. TLS
+ with the above mandated cipher suite can provide such a secure
+ channel.
+
+
+16 References
+
+
+ [ipp-iig]
+ Hastings, T., Manros, C., Kugler, K, Holst H., Zehler, P.,
+ "Internet Printing Protocol/1.1: draft-ietf-ipp-implementers-
+ guide-v11-02.txt, work in progress, January 25, 2001
+
+
+
+
+
+
+Parra, Hastings Expires: August 28, 2001 [page 28]
+
+
+INTERNET-DRAFT IPP: The 'indp' Method and Protocol February 28, 2001
+
+
+ [ipp-ntfy]
+ Isaacson, S., Martin, J., deBry, R., Hastings, T., Shepherd, M.,
+ Bergman, R., "Internet Printing Protocol/1.1: IPP Event
+ Notification Specification", <draft-ietf-ipp-not-spec-06.txt>,
+ January 24, 2001.
+
+ [IANA-MIMEREG]
+ IANA MIME Media Types Registry. ftp://ftp.isi.edu/in-
+
+ notes/iana/assignments/media-types/
+
+
+ [IANA-PORTREG]
+ IANA Port Numbers Registry. ftp://ftp.isi.edu/in-
+
+ notes/iana/assignments/port-numbers
+
+
+ [RFC1900]
+ B. Carpenter, Y. Rekhter. Renumbering Needs Work, RFC 1900,
+ February 1996.
+
+ [RFC2026]
+ S. Bradner, "The Internet Standards Process -- Revision 3", RFC
+ 2026, October 1996.
+
+ [RFC2373]
+ R. Hinden, S. Deering. IP Version 6 Addressing Architecture, RFC
+ 2373, July 1998.
+
+ [RFC2396]
+ Berners-Lee, T. et al. Uniform Resource Identifiers (URI): Generic
+ Syntax, RFC 2396, August 1998
+
+ [RFC2616]
+ R. Fielding, J. Gettys, J. Mogul, H. Frystyk, L. Masinter, P.
+ Leach, T. Berners-Lee, "Hypertext Transfer Protocol - HTTP/1.1",
+ RFC 2616, June 1999.
+
+ [RFC2617]
+ J. Franks, P. Hallam-Baker, J. Hostetler, S. Lawrence, P. Leach, A.
+ Luotonen, L. Stewart, "HTTP Authentication: Basic and Digest Access
+ Authentication", RFC 2617, June 1999.
+
+ [RFC2717]
+ R. Petke and I. King, "Registration Procedures for URL Scheme
+ Names", RFC 2717, November 1999.
+
+
+
+
+Parra, Hastings Expires: August 28, 2001 [page 29]
+
+
+INTERNET-DRAFT IPP: The 'indp' Method and Protocol February 28, 2001
+
+
+ [RFC2732]
+ R. Hinden, B. Carpenter, L. Masinter. Format for Literal IPv6
+ Addresses in URL's, RFC 2732, December 1999.
+
+ [RFC2910]
+ Herriot, R., Butler, S., Moore, P., Tuner, R., "Internet Printing
+ Protocol/1.1: Encoding and Transport", RFC 2910, September 2001.
+
+ [RFC2911]
+ R. deBry, T. Hastings, R. Herriot, S. Isaacson, P. Powell,
+ "Internet Printing Protocol/1.1: Model and Semantics", RFC 2911,
+ September 2001.
+
+
+17 Author's Addresses
+
+ Hugo Parra
+ Novell, Inc.
+ 1800 South Novell Place
+
+ Provo, UT 84606
+
+ Phone: 801-861-3307
+ Fax: 801-861-2517
+ e-mail: hparra@novell.com
+
+ Tom Hastings
+ Xerox Corporation
+ 737 Hawaii St. ESAE 231
+ El Segundo, CA 90245
+
+ Phone: 310-333-6413
+ Fax: 310-333-5514
+ e-mail: hastings@cp10.es.xerox.com
+
+
+18 Full Copyright Statement
+
+ Copyright (C) The Internet Society (2001). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+
+Parra, Hastings Expires: August 28, 2001 [page 30]
+
+
+INTERNET-DRAFT IPP: The 'indp' Method and Protocol February 28, 2001
+
+
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Parra, Hastings Expires: August 28, 2001 [page 31]
diff --git a/standards/draft-ietf-ipp-install-02.txt b/standards/draft-ietf-ipp-install-02.txt
new file mode 100644
index 000000000..6319c431e
--- /dev/null
+++ b/standards/draft-ietf-ipp-install-02.txt
@@ -0,0 +1,1426 @@
+
+
+
+
+
+
+INTERNET-DRAFT
+<draft-ietf-ipp-install-02.txt>
+[Target category: standards track] Hugo Parra
+ Novell, Inc.
+ Ted Tronson
+ Novell, Inc.
+ Tom Hastings
+ Xerox Corp.
+ February 28, 2001
+ Internet Printing Protocol (IPP):
+ Printer Installation Extension
+
+ Copyright (C) The Internet Society (2001). All Rights Reserved.
+
+Status of this Memo
+
+ This document is an Internet-Draft and is in full conformance with
+ all provisions of Section 10 of [RFC2026]. Internet-Drafts are
+ working documents of the Internet Engineering Task Force (IETF), its
+ areas, and its working groups. Note that other groups may also
+ distribute working documents as Internet-Drafts.
+
+ Internet-Drafts are draft documents valid for a maximum of six months
+ and may be updated, replaced, or obsoleted by other documents at any
+ time. It is inappropriate to use Internet-Drafts as reference
+ material or to cite them other than as "work in progress".
+
+ The list of current Internet-Drafts can be accessed at
+ http://www.ietf.org/ietf/1id-abstracts.txt
+
+ The list of Internet-Draft Shadow Directories can be accessed as
+ http://www.ietf.org/shadow.html.
+
+Abstract
+
+ Various client platforms require that some setting up take place at
+ the workstation before the client can properly submit jobs to a
+ specific printer. This setup process is sometimes referred to as
+ printer installation. Most clients need some information about the
+ printer being installed as well as support files to complete the
+ printer installation. The nature of the support files varies
+ depending on the specific client platform, from simple configuration
+ files to highly sophisticated printer drivers. This document refers
+ to these support files as "Client Print Support Files".
+ Traditionally, the selection and installation of the correct Client
+ Print Support Files has been error prone. The selection and
+ installation process can be simplified and even automated if the
+ workstation can learn some key information about the printer and
+ which sets of Client Print Support Files are available. Such key
+ information includes: operating system type, CPU type, document-
+
+Parra, Tronson, Hastings Expires August 28, 2001 [page 1]
+
+
+INTERNET-DRAFT IPP: Printer Installation Extension February 28, 2001
+
+
+ format (PDL), natural language, compression mechanism, file type,
+ client file name, policy for automatic loading, file size, file
+ version, file date and time, file information description, and
+ digital signature. This document describes the IPP extensions that
+ enable workstations to obtain the information needed to perform a
+ proper printer driver installation using IPP, including security for
+ downloading executable code and data.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Parra, Tronson, Hastings Expires August 28, 2001 [page 2]
+
+
+INTERNET-DRAFT IPP: Printer Installation Extension February 28, 2001
+
+
+ The full set of IPP documents includes:
+
+ Design Goals for an Internet Printing Protocol [RFC2567]
+ Rationale for the Structure and Model and Protocol for the
+ Internet Printing Protocol [RFC2568]
+ Internet Printing Protocol/1.1: Model and Semantics [RFC2911]
+ Internet Printing Protocol/1.1: Encoding and Transport [RFC2910]
+ Internet Printing Protocol/1.1: Implementer's Guide [ipp-iig]
+ Mapping between LPD and IPP Protocols [RFC2569]
+
+ The "Design Goals for an Internet Printing Protocol" document takes a
+ broad look at distributed printing functionality, and it enumerates
+ real-life scenarios that help to clarify the features that need to be
+ included in a printing protocol for the Internet. It identifies
+ requirements for three types of users: end users, operators, and
+ administrators. It calls out a subset of end user requirements that
+ are satisfied in IPP/1.0. A few OPTIONAL operator operations have
+ been added to IPP/1.1.
+
+ The "Rationale for the Structure and Model and Protocol for the
+ Internet Printing Protocol" document describes IPP from a high level
+ view, defines a roadmap for the various documents that form the suite
+ of IPP specification documents, and gives background and rationale
+ for the IETF working group's major decisions.
+
+ The "Internet Printing Protocol/1.1: Encoding and Transport" document
+ is a formal mapping of the abstract operations and attributes defined
+ in the model document onto HTTP/1.1 [RFC2616]. It defines the
+ encoding rules for a new Internet MIME media type called
+ "application/ipp". This document also defines the rules for
+ transporting a message body over HTTP whose Content-Type is
+ "application/ipp". This document defines a new scheme named 'ipp'
+ for identifying IPP printers and jobs.
+
+ The "Internet Printing Protocol/1.1: Implementer's Guide" document
+ gives insight and advice to implementers of IPP clients and IPP
+ objects. It is intended to help them understand IPP/1.1 and some of
+ the considerations that may assist them in the design of their client
+ and/or IPP object implementations. For example, a typical order of
+ processing requests is given, including error checking. Motivation
+ for some of the specification decisions is also included.
+
+ The "Mapping between LPD and IPP Protocols" document gives some
+ advice to implementers of gateways between IPP and LPD (Line Printer
+ Daemon) implementations.
+
+
+
+
+
+
+Parra, Tronson, Hastings Expires August 28, 2001 [page 3]
+
+
+INTERNET-DRAFT IPP: Printer Installation Extension February 28, 2001
+
+
+
+Table of Contents
+
+ 1 Introduction....................................................6
+
+
+ 2 Terminology.....................................................6
+
+
+ 3 Model Extensions................................................7
+
+ 3.1 client-print-support-files-supported (1setOf octetString(MAX))
+
+ ..........................................................7
+ 3.1.1 Use of Keyword Values in fields.............................12
+
+ 3.1.2 Use of the Special Keyword Value: 'unknown'.................12
+
+ 3.1.3 Examples of "client-print-support-files-supported" attribute
+
+ values.................................................12
+
+ 3.2 Get-Printer-Attributes Operation Extension..................13
+
+ 3.2.1 Get-Printer-Attributes Request..............................13
+
+ 3.2.1.1 client-print-support-files-filter (octetString(MAX))
+
+ operation attribute..................................13
+
+ 3.2.1.1.1 Filter matching rules.................................15
+
+ 3.2.2 Get-Printer-Attributes Response.............................16
+
+ 3.3 Get-Client-Print-Support-Files..............................17
+
+ 3.3.1 Get-Client-Print-Support-Files Request......................17
+
+ 3.3.2 Get-Client-Print-Support-Files Response.....................18
+
+
+ 4 Conformance....................................................19
+
+
+ 5 Encoding of the Operation Layer................................20
+
+
+ 6 Encoding of Transport Layer....................................20
+
+
+
+Parra, Tronson, Hastings Expires August 28, 2001 [page 4]
+
+
+INTERNET-DRAFT IPP: Printer Installation Extension February 28, 2001
+
+
+ 7 IANA Considerations............................................20
+
+ 7.1 Attribute Registrations.....................................21
+
+ 7.2 Operation Registrations.....................................22
+
+
+ 8 Internationalization Considerations............................22
+
+
+ 9 Security Considerations........................................22
+
+
+ 10 References.....................................................23
+
+
+ 11 Author's Addresses.............................................24
+
+
+ 12 Full Copyright Statement.......................................25
+
+
+
+Tables
+
+ Table 1 - "client-print-support-files-supported" attribute fields..9
+
+ Table 2 - "client-print-support-files-filter" attribute fields....14
+
+ Table 3 - REQUIRED "client-print-support-files-filter" fields.....14
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Parra, Tronson, Hastings Expires August 28, 2001 [page 5]
+
+
+INTERNET-DRAFT IPP: Printer Installation Extension February 28, 2001
+
+
+1 Introduction
+
+ A common configuration for printing from a workstation requires that
+ some Client Print Support Files (e.g., PPD, printer driver files)
+ specific to the target printer be installed on that workstation.
+ Selection and configuration of the appropriate Client Print Support
+ Files can be simplified and even automated if the workstation can
+ obtain some key information about the printer and which sets of
+ Client Print Support Files are available. Such key information
+ includes: operating system type, CPU type, document-format (PDL),
+ natural language, compression mechanism, file type, client file name,
+ policy for automatic loading, file size, file version, file date and
+ time, file information description, and digital signature. With a
+ few extensions, IPP provides a simple and reliable vehicle for
+ printers to convey this information to interested workstations. The
+ IPP extensions described in this document enable a flexible solution
+ for installing Client Print Support Files on workstations running
+ different operating systems and for printers of all makes and models.
+ It allows Client Print Support Files to be downloaded from
+ repositories of different sorts. A possible repository for the files
+ is the printer itself. The extensions necessary for getting Client
+ Print Support Files from the printer are included in this document,
+ including security for downloading executable code and data.
+
+
+2 Terminology
+
+ Client Print Support Files - a set of files, such as a printer
+ driver, font metric file, printer configuration file (PPD, GPD, etc.)
+ that support a client printing to a particular Printer. A Printer
+ MAY have multiple sets of Client Print Support Files that work for
+ different operating systems, document formats, natural languages,
+ CPUs, etc.
+
+ This document uses terms such as "attributes", "keywords", and
+ "support". These terms have special meaning and are defined in the
+ model terminology [RFC2911] section 12.2. This document also uses
+ the terms "IPP Printer", "Printer" and "Printer object"
+ interchangeably as in [RFC2911] to mean the software entity that
+ accepts IPP operation requests and returns IPP operation responses
+ (see [RFC2911] section 2).
+
+ Capitalized terms, such as MUST, MUST NOT, REQUIRED, SHOULD, SHOULD
+ NOT, MAY, NEED NOT, and OPTIONAL, have special meaning relating to
+ conformance. These terms are defined in [RFC2911] section 12.1 on
+ conformance terminology, most of which is taken from RFC 2119
+ [RFC2119].
+
+ This section defines the following additional terms that are used
+ throughout this document:
+
+Parra, Tronson, Hastings Expires August 28, 2001 [page 6]
+
+
+INTERNET-DRAFT IPP: Printer Installation Extension February 28, 2001
+
+
+ REQUIRED: if an implementation supports the extensions described
+ in this document, it MUST support a REQUIRED feature.
+ OPTIONAL: if an implementation supports the extensions described
+ in this document, it MAY support an OPTIONAL feature.
+
+3 Model Extensions
+
+ To assist workstations in the printer installation process, an IPP
+ printer needs to provide the workstation with information about the
+ Client Print Support Files, such as the their name and location/s.
+ This information needs to match the workstation's specific
+ environment, such as its operating system, preferred natural
+ language, and preferred document format.
+
+ The following extensions to the IPP model enable assisted or
+ automated printer installation. This section describes each
+ extension in detail.
+
+
+ - A new REQUIRED Printer Description attribute: "client-print-
+ support-files-supported" (1setOf octetString(MAX)).
+ - A new REQUIRED Get-Printer-Attributes operation attribute:
+ "client-print-support-files-filter" (octetString(MAX)).
+ - A new RECOMMENDED printer operation: Get-Client-Print-Support-
+ Files.
+
+
+3.1 client-print-support-files-supported (1setOf octetString(MAX))
+
+ An IPP Printer uses the REQUIRED Printer Description attribute
+ "client-print-support-files-supported" to represent relevant
+ information about all of the Client Print Support Files it supports.
+ Each value is a composite UTF-8 string with well-defined fields (see
+ Table 1). Each value string MUST be formatted as follows:
+
+ "uri=val1< field-name2=val21,_,val2p< _ < field-namen=valn1,_,valnq<"
+
+ The first field MUST be the "uri" field. The remaining fields MAY be
+ in any order.
+
+ The string MUST NOT include any control characters (hex 00 to 1F),
+ even the so-called white space control characters (TAB, CR, and LF)
+ anywhere. Only zero or more UTF-8 SPACE characters (hex 20) can be
+ included and they can be included only IMMEDIATELY AFTER the
+ delimiter character: "<", but NOT anywhere else, including after "="
+ and ",". However, if the UTF-8 SPACE character is needed in a
+ client-file-name value, then each occurrence is included directly,
+ without escaping (see example). On the other hand, if the UTF-8
+ SPACE character is needed in a URL value, then each occurrence is
+ escaped as: "%20" (URI conventions - see [RFC2396]).
+
+Parra, Tronson, Hastings Expires August 28, 2001 [page 7]
+
+
+INTERNET-DRAFT IPP: Printer Installation Extension February 28, 2001
+
+
+ Table 1 lists the REQUIRED fields that a Printer MUST support and the
+ OPTIONAL fields that a Printer MAY support in the "client-print-
+ support-files-supported" (1setOf octetString(MAX)) Printer
+ Description attribute. A Printer implementation MAY support
+ additional fields using the same syntax. Values are defined to be
+ either CASE-SENSITIVE or ALL-LOWER-CASE according to the definitions
+ for the attribute syntaxes from [RFC2911] (set off by single quotes
+ in the table). The CASE-SENSITIVE values MAY have upper and lower
+ case letters as for the corresponding attribute syntaxes in
+ [RFC2911]. The LOWER-CASE values MUST have all lower case alphabetic
+ letters. Additional characters, such as digits, hyphen-minus (-),
+ period (.), and slash (/) are according to the corresponding
+ attribute syntaxes in [RFC2911].
+
+ Clients SHOULD ignore fields they don't recognize in a given value.
+ This allows for future extensions to the format of the string without
+ breaking compatibility with earlier clients.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Parra, Tronson, Hastings Expires August 28, 2001 [page 8]
+
+
+INTERNET-DRAFT IPP: Printer Installation Extension February 28, 2001
+
+
+ Table 1 - "client-print-support-files-supported" attribute fields
+
+
+ Field Field value
+ name
+
+
+ "uri" One REQUIRED CASE-SENSITIVE 'uri' string identifying the
+ uri where to obtain the support files for each OS
+ platform, document format, and natural language the
+ printer supports. This MUST be the first field in each
+ value. Examples of uri schemes that MAY be found here
+ are 'ftp', 'http', and 'ipp'. The 'ftp' and 'http'
+ schemed URIs identify the archive file that contains all
+ the necessary client support files.
+
+ The 'ipp' schemed URIs identify the archive file that
+ clients MAY obtain from the Printer using the Get-
+ Client-Print-Support-Files operation (see section 3.3).
+ The URI MUST be a valid URI to the same Printer object,
+ i.e., one of the values of the Printer's "printer-uri-
+ supported" attribute. The 'ipp' URI is used to
+ distinguish between multiple Client Print Support Files
+ in an implementation dependent manner using the URL
+ query syntax (e.g., "?drv-id=xxx") [RFC2396]. The
+ query part MUST NOT exceed 127 octets, not counting the
+ "?" character that begins the query part. A Printer
+ SHOULD support the 'ipp' scheme.
+
+ "os-type" One or more REQUIRED comma-separated LOWER-CASE
+ 'keyword' strings identifying the operating system types
+ supported by this set of Client Print Support Files.
+ Valid values are the operating system names defined in
+ the IANA document [os-names] and the special keyword
+ value: 'unknown'. Although the IANA registry requires
+ that the names be all upper-case, the values MUST be all
+ lower case in this field (plus hyphen-minus (-), period
+ (.), and slash (/)). Examples: 'linux', 'linux-2.2',
+ 'os/2', 'sun-os-4.0', 'unix', 'unix-bsd', 'win32',
+ 'windows-95', 'windows-98', 'windows-ce', 'windows-nt',
+ 'windows-nt-4', 'windows-nt-5', 'unknown'.
+
+ "cpu- One or more REQUIRED comma-separated LOWER-CASE
+ type" 'keyword' strings identifying the CPU types supported by
+ this set of Client Print Support Files. The values
+ indicate the CPU family independent of the CPU
+ manufacturer. Valid keyword values are: 'x86-16',
+ 'x86-32', 'x86-64', 'dec-vax', 'alpha', 'power-pc', 'm-
+ 68000, 'sparc', 'itantium', 'mips', 'arm' and will be
+
+
+Parra, Tronson, Hastings Expires August 28, 2001 [page 9]
+
+
+INTERNET-DRAFT IPP: Printer Installation Extension February 28, 2001
+
+
+
+ Field Field value
+ name
+
+
+ used as the initial value for the "cpu-type" IANA
+ registry. In addition, the special keyword value:
+ 'unknown' is valid.
+
+ "document One or more REQUIRED comma-separated CASE-SENSITIVE
+ -format" 'mimeMediaType' strings identifying the document formats
+ supported by this set of Client Print Support Files.
+ Valid values are the string representation of the IPP
+ mimeMediaType attribute syntax (see [RFC2911] section
+ 4.1.9), for example 'application/postscript'. In
+ addition, the special keyword value: 'unknown' is valid.
+
+ "natural- One or more REQUIRED comma-separated LOWER-CASE
+ language" 'naturalLanguage' strings identifying the natural
+ language used by this set of Client Print Support Files.
+ Valid values are the string representation of the IPP
+ 'naturalLanguage' attribute syntax (see [RFC2911]
+ section 4.1.8), for example 'en' and 'en-us'. In
+ addition, the special keyword value: 'unknown' is valid.
+
+ "compress One REQUIRED LOWER-CASE 'keyword' string identifying the
+ ion" mechanism used to compress this set of Client Print
+ Support Files. All files needed for the installation of
+ a printer driver MUST be compressed into a single file.
+ Valid keyword values are the keywords defined by
+ [RFC2911] or registered with IANA for use in the IPP
+ "compression" and "compression-supported" attributes.
+ See [RFC2911] section 4.4.32), for example 'gzip'. The
+ 'none' value limits the uncompressed Client Print
+ Support File to a single file. The values for the
+ "compression" field that a Printer supports NEED NOT be
+ the same values that the Printer is configured to
+ support in Job Creation operations as indicated in the
+ Printer's "compressions-supported" attribute.
+
+ "file- One or more REQUIRED comma-separated LOWER-CASE
+ type" 'keyword' strings identifying the type of the Client
+ Print Support Files. Valid keyword values are:
+ 'printer-driver', 'ppd', 'updf', 'gpd'.
+
+ "client- One REQUIRED CASE-SENSITIVE string identifying the name
+ file- by which the Client Print Support Files will be
+ name" installed on the workstation. For Client Print Support
+ Files of type 'printer-driver', this is also the name
+
+
+Parra, Tronson, Hastings Expires August 28, 2001 [page 10]
+
+
+INTERNET-DRAFT IPP: Printer Installation Extension February 28, 2001
+
+
+
+ Field Field value
+ name
+
+
+ that identifies this printer driver in an .inf file.
+
+ "policy" One OPTIONAL LOWER-CASE 'keyword' string indicating the
+ policy for automatic loading. Valid keyword values are:
+ 'manufacturer-recommended', 'administrator-recommended',
+ 'manufacturer-experimental, 'administrator-
+ experimental'. The experimental values are for beta
+ test.
+
+ "file- One OPTIONAL file size in octets represented as ASCII
+ size" decimal digits.
+
+ "file- One OPTIONAL LOWER-CASE version number. Recommended to
+ version" be of the form "Major.minor[.revision]" where "Major" is
+ the major version number, "minor" is the minor version
+ number and "revision" is an optional revision number.
+
+ "file- One OPTIONAL File CASE-SENSITIVE creation date and time
+ date- according to ISO 8601 where all fields are fixed length
+ time" with leading zeroes (see [RFC2518] Appendix 2).
+ Examples: 2000-01-01T23:09:05Z and 2000-01-01T02:59:59-
+ 04.00
+
+ "file- One OPTIONAL CASE-SENSITIVE human readable 'text' string
+ info" describing this set of Client Print Support Files. The
+ natural language for this value MUST be the natural
+ language indicated by the Printer's "natural-language-
+ configured" attribute. To avoid exceeding the maximum
+ limit imposed on IPP attributes and to increase
+ interoperability with other systems, the length of this
+ field value MUST not exceed 127 characters.
+
+ "digital- One REQUIRED LOWER-CASE 'keyword' string identifying the
+ signature mechanism used to ensure the integrity and authenticity
+ " of this set of Client Print Support Files. Valid values
+ are: 'smime', 'pgp', 'dss', and 'xmldsig' which are
+ defined in [RFC2634], [RFC1991], [dss], and [xmldsig],
+ respectively. In addition, the special keyword value:
+ 'none' is valid.
+
+
+ Each value MUST refer to one and only one set of Client Print Support
+ Files, even if the files are downloadable from various repositories
+ (i.e., even if they are associated with multiple URIs).
+
+
+Parra, Tronson, Hastings Expires August 28, 2001 [page 11]
+
+
+INTERNET-DRAFT IPP: Printer Installation Extension February 28, 2001
+
+
+3.1.1 Use of Keyword Values in fields
+
+ A number of the fields in Table 1 use keyword strings as values. The
+ syntax of these keywords is the same as in [RFC2911], including the
+ use of private keywords. See [RFC2911] sections 4.1.3 and 6.1.
+ Printer implementers are strongly RECOMMENDED to submit additional
+ keyword values for registration with IANA according to the procedures
+ for registering attributes. See section 7 and [RFC2911] section 6.1.
+
+
+3.1.2 Use of the Special Keyword Value: 'unknown'
+
+ A number of REQUIRED 'keyword' value fields have a special keyword
+ value: 'unknown' defined. This value is intended for use when the
+ actual value is not known, such as by an administrator automatic
+ software configuring the IPP Printer object. However, it is strongly
+ RECOMMENDED that other more meaningful values be used, instead of the
+ 'unknown' value whenever possible.
+
+
+3.1.3 Examples of "client-print-support-files-supported" attribute
+ values
+
+ The following illustrates what two valid values of the "client-print-
+ support-files-supported" (1setOf octetString(MAX)) Printer
+ Description attribute might look like:
+
+ uri=ipp://mycompany.com/myprinter?drv-id=ModelY.gz<
+ os-type=windows-95< cpu-type=x86-32<
+ document-format=application/postscript<
+ natural-language=en< compression=gzip<
+ file-type=printer-driver<
+ client-file-name=CompanyX-ModelY-driver.gz<
+ policy=manufacturer-recommended<
+
+ uri=ftp://mycompany.com/root/drivers/win95/CompanyX/ModelY.gz<
+ os-type=windows-95< cpu-type=x86-32<
+ document-format=application/postscript,application/vnd.hp-PCL<
+ natural-language=en,fr< compression=gzip<
+ file-type=printer-driver<
+ client-file-name=Company T Model Z driver.gz<
+ policy=manufacturer-recommended<
+
+ The above examples have been broken onto separate lines for
+ readability in this document. However, there MUST NOT be any line
+ breaks in the actual values.
+
+
+
+
+
+Parra, Tronson, Hastings Expires August 28, 2001 [page 12]
+
+
+INTERNET-DRAFT IPP: Printer Installation Extension February 28, 2001
+
+
+ The "client-print-support-files-supported" Printer Description
+ attribute MAY be preset at manufacturing time or through
+ administrative means outside the scope of this document.
+
+
+3.2 Get-Printer-Attributes Operation Extension
+
+ The "client-print-support-files-supported" Printer Description
+ attribute defined in section 3.1 contains information, such as
+ operating system, natural language, and document format, about all of
+ the sets of Client Print Support Files. This section defines an
+ extension to the Get-Printer-Attributes operation that allows a
+ workstation to filter out all but the Client Print Support Files of
+ interest.
+
+
+3.2.1 Get-Printer-Attributes Request
+
+ A Printer MAY contain information about multiple sets of Client Print
+ Support Files to match the different operating systems, natural
+ languages and document formats it supports. A workstation MAY query
+ this information by including the 'client-print-support-files-
+ supported' keyword as a value of the "requested-attributes" operation
+ attribute of the Get-Printer-Attributes operation.
+
+
+3.2.1.1 client-print-support-files-filter (octetString(MAX)) operation
+ attribute
+
+ The client can request a subset of the values of the "client-print-
+ support-files-supported" Printer attribute by supplying the "client-
+ print-support-files-filter" (octetString(MAX)) operation attribute in
+ the request as a filter. The filter value indicates in which Client
+ Print Support Files the client is interested. The client MAY supply
+ this attribute. The Printer MUST support this attribute.
+
+ The filter value of the "client-print-support-files-filter" attribute
+ is a composite string with the same format as that of "client-print-
+ support-files-supported" (see Table 1 - "client-print-support-files-
+ supported" attribute fields in section 3.1) with the following
+ exceptions:
+
+
+
+
+
+
+
+
+
+
+Parra, Tronson, Hastings Expires August 28, 2001 [page 13]
+
+
+INTERNET-DRAFT IPP: Printer Installation Extension February 28, 2001
+
+
+ Table 2 - "client-print-support-files-filter" attribute fields
+
+
+ Field Field Value in the "client-print-support-files-filter"
+ Name attribute
+
+
+ uri- One or more comma-separated LOWER-CASE 'uriScheme'
+ scheme string values identifying the uri scheme to be
+ filtered on. Valid values are the string
+ representation of the IPP 'uriScheme' attribute syntax
+ (see [RFC2911] section 4.1.6). Example URI schemes
+ are: 'ftp', 'http', and 'ipp'. The Printer SHOULD
+ support the 'ipp' scheme. If supplied by the client,
+ this field NEED NOT be first. If this field is
+ omitted by the client, the Printer returns all
+ schemes.
+
+ xxx One or more comma-separated values for any of the
+ fields defined in Table 1, with the single exception
+ of the "uri" field which a client MUST NOT supply and
+ a Printer MUST NOT support.
+ The Printer MUST support any filter field having more
+ than one value separated by a COMMA (,), including the
+ fields that Table 1 indicates MUST BE single valued.
+
+
+ Printer implementations MUST support the "client-print-support-files-
+ filter" operation attribute in a Get-Printer-Attributes request with
+ the member fields listed Table 3. Printers MAY support any
+ additional filter fields listed in Table 2.
+
+ Client implementations MAY supply any filter fields listed in Table 2
+ in the "client-print-support-files-filter" operation attribute of a
+ Get-Printer-Attributes request.
+
+ Table 3 - REQUIRED "client-print-support-files-filter" fields
+
+
+ uri-scheme
+
+ os-type
+
+ cpu-type
+
+ document-format
+
+ natural-language
+
+
+
+Parra, Tronson, Hastings Expires August 28, 2001 [page 14]
+
+
+INTERNET-DRAFT IPP: Printer Installation Extension February 28, 2001
+
+
+3.2.1.1.1 Filter matching rules
+
+ The Printer returns only the values of the "client-print-support-
+ files-supported" Printer Description attribute that match the filter
+ in the "client-print-support-files-filter" operation attribute. The
+ following filter matching rules are defined:
+
+ 1. A match occurs if at least one value of each field supplied by
+ the client in the filter matches a Client Print Support File
+ value. Printers MUST ignore a filter field supplied by a client
+ that the Printer does not support and return a match if all
+ supported fields do match, no matter what value the client
+ supplied for that unsupported field. Similarly, Printers MUST
+ ignore a filter field supplied by a client that the Printer does
+ support, but which the field has not been populated for a Client
+ Print Support Files and return a match if all supported and
+ populated fields do match, no matter what value the client
+ supplied for that unpopulated field.
+
+ 2. A match for a CASE-INSENSITIVE field occurs independent of the
+ case of the letters supplied by the client and those stored by
+ the Printer, while a match for a LOWER-CASE field is a strict
+ character for character match.
+
+ 3. A match for a 'keyword' Printer field that is populated with the
+ 'unknown' special keyword value occurs for any value supplied by
+ the client for that field.
+
+ 4. If the "client-print-support-files-filter" operation attribute
+ filter is not supplied by the client, the printer SHOULD behave
+ as if the attribute had been provided with all fields left empty
+ (i.e., return an unfiltered list).
+
+ The following are two examples of a "client-print-support-files-
+ filter" filter value:
+
+ os-type=windows-95< cpu-type=x86-32<
+ document-format=application-postscript< natural-language=en,de<
+
+ uri-scheme=ipp< os-type=windows-95< cpu-type=x86-32<
+ document-format=application-postscript< natural-language=en,de<
+
+ See section 3.2.2 for example matching responses.
+
+ It is RECOMMENDED that workstations first use the Get-Printer-
+ Attributes operation in combination with "client-print-support-files-
+ filter" operation attribute filter to get a list of the potential
+ Client Print Support Files that meet the workstation's requirements.
+ The workstation can then choose from the returned list which Client
+ Print Support Files to use and where to get them. If one of the URIs
+
+Parra, Tronson, Hastings Expires August 28, 2001 [page 15]
+
+
+INTERNET-DRAFT IPP: Printer Installation Extension February 28, 2001
+
+
+ returned is an IPP uri, the workstation can retrieve the Client Print
+ Support Files from an IPP printer via the Get-Client-Print-Support-
+ Files operation (see section 3.3).
+
+
+3.2.2 Get-Printer-Attributes Response
+
+
+ A Printer MUST return the "client-print-support-files-supported"
+ (1setOf octetString(MAX)) attribute in the Printer Object Attributes
+ group (group 3) when requested by a client. Each returned attribute
+ value MUST satisfy the criteria specified by the client in the
+ request.
+
+
+ For example, if the request contains the following "client-print-
+ support-files-filter" filter:
+
+ os-type=windows-95< cpu-type=x86-32<
+ document-format=application-postscript<
+ natural-language=en,de<
+
+ A conforming response is the following two octet String values:
+
+ uri=ipp://mycompany.com/myprinter?drv-id=ModelY.gz<
+ os-type=windows-95< cpu-type=x86-32<
+ document-format=application/postscript<
+ natural-language=en< compression=gzip<
+ file-type=printer-driver<
+ client-file-name=CompanyX-ModelY-driver.gz<
+ policy=manufacturer-recommended<
+ digital-signature=smime<
+
+ uri=ftp://mycompany.com/root/drivers/win95/CompanyX/ModelY.gz<
+ os-type=windows-95< cpu-type=x86-32<
+ document-format=application/postscript,application/vnd.hp-PCL<
+ natural-language=en,fr< compression=gzip<
+ file-type=printer-driver<
+ client-file-name=CompanyX-ModelY-driver.gz<
+ policy=manufacturer-recommended<
+ digital-signature=smime<
+
+
+ These examples have been broken onto separate lines for readability
+ in this document. However, there MUST NOT be any line breaks in the
+ actual values.
+
+
+
+
+
+Parra, Tronson, Hastings Expires August 28, 2001 [page 16]
+
+
+INTERNET-DRAFT IPP: Printer Installation Extension February 28, 2001
+
+
+ As another example, if the above request had also contained the "uri-
+ scheme" field in the following "client-print-support-files-filter"
+ filter:
+
+ uri-scheme=ipp< os-type=windows-95< cpu-type=x86-32<
+ document-format=application-postscript<
+ natural-language=en,de<
+
+ Then only the first value would have been returned as a single
+ octetString value:
+
+ uri=ipp://mycompany.com/myprinter?drv-id=ModelY.gz<
+ os-type=windows-95< cpu-type=x86-32<
+ document-format=application/postscript<
+ natural-language=en< compression=gzip<
+ file-type=printer-driver<
+ client-file-name=CompanyX-ModelY-driver.gz<
+ policy=manufacturer-recommended<
+ digital-signature=smime<
+
+3.3 Get-Client-Print-Support-Files
+
+ This RECOMMENDED operation allows a client to download Client Print
+ Support Files from an IPP Printer.
+
+
+3.3.1 Get-Client-Print-Support-Files Request
+
+
+ The following sets of attributes are part of the Get-Client-Print-
+ Support-Files request:
+
+
+ Group 1: Operation Attributes
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in [RFC2911], section 3.1.4.1.
+
+ Target:
+ The "printer-uri" (uri) operation attribute which is the target
+ for this operation as described in [RFC2911], section 3.1.5.
+ The client MUST use the URI value as the target of this
+ operation that the Printer returns in the "uri" field (see Table
+ 1) in the Get-Printer-Attributes response. Furthermore, the
+ client MUST use the appropriate authorization and security
+ regime for this URI as indicated by the Printer's "printer-uri-
+ supported", "uri-authentication-supported" and "uri-security-
+ supported" attributes (see [RFC2911] sections 4.4.1, 4.4.2, and
+ 4.4.3). Only if the URI returned in the "uri" field matches the
+
+Parra, Tronson, Hastings Expires August 28, 2001 [page 17]
+
+
+INTERNET-DRAFT IPP: Printer Installation Extension February 28, 2001
+
+
+ URI that the client used for the Get-Printer-Attributes request
+ MAY the client use the same HTTP connection. The 'ipp' URL
+ matching rules are defined in [ipp-url] and do not include the
+ query part.
+
+ Requesting User Name:
+ The "requesting-user-name" (name(MAX)) attribute SHOULD be
+ supplied by the client as described in [RFC2911], section 8.3.
+
+ "client-print-support-files-query" (text(127)):
+ The client MUST supply this attribute specifying the query part
+ [RFC2396] of the ipp uri for the desired Client Print Support
+ Files not including the "?" character that starts the query
+ part, i.e., the value of the "uri" field following the "?"
+ character returned by the Get-Printer-Attributes in one of the
+ values of the "client-print-support-files-supported" (1setOf
+ octetString(MAX)) Printer attribute (see Table 1) that had an
+ 'ipp' scheme.
+
+
+3.3.2 Get-Client-Print-Support-Files Response
+
+
+ The Printer object returns the following sets of attributes as part
+ of the Get-Client-Print-Support-Files Response:
+
+
+ Group 1: Operation Attributes
+
+ Status Message:
+ In addition to the REQUIRED status code returned in every
+ response, the response OPTIONALLY includes a "status-message"
+ (text(255)) operation attribute as described in [RFC2911],
+ sections 13 and 3.1.6.
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in [RFC2911], section 3.1.4.2.
+
+ Group 2: Unsupported Attributes
+ See [RFC2911], section 3.1.7 for details on returning Unsupported
+ Attributes.
+
+
+ Group 3: Printer Object Attributes
+ "client-print-support-files-supported" (octetString(MAX)).
+ This attribute identifies the properties of the returned Client
+ Print Support Files. The Printer object MUST return this
+ attribute if the response includes Group 4 (i.e., if a set of
+ Client Print Support Files identified by the supplied "client-
+
+Parra, Tronson, Hastings Expires August 28, 2001 [page 18]
+
+
+INTERNET-DRAFT IPP: Printer Installation Extension February 28, 2001
+
+
+ print-support-files-query" operation attribute was found). The
+ Printer MUST return all configured fields for the selected
+ Client Print Support Files in the format shown in section 3.1.
+
+
+ Group 4: Client Print Support Files
+ The printer MUST supply the Client Print Support Files that match
+ the client's criteria following the "end-of-attributes" tag. All
+ necessary files MUST be compressed into a single transferred file.
+
+
+4 Conformance
+
+ A Printer conforming to this specification:
+
+ 1.MUST support the "client-print-support-files-supported" Printer
+ Description attribute as defined in section 3.1, including all
+ of the REQUIRED fields defined in Table 1 and MAY support the
+ OPTIONAL fields defined in Table 1.
+
+ 2.MUST support the "client-print-support-files-filter" operation
+ attribute in the Get-Printer-Attributes request as defined in
+ section 3.2, including all of the fields listed in Table 3 and
+ ignoring any fields not recognized.
+
+ 3.MUST support at least one of the following URI schemes that
+ identify the support files: 'ftp', 'http', or 'ipp', of which
+ the 'ipp' scheme is the RECOMMENDED one.
+
+ 4.SHOULD support the Get-Client-Print-Support-Files operation as
+ described in section 3.3. If this operation is supported, then
+ one of the supported schemes MUST be 'ipp'.
+
+ 5.SHOULD support TLS as described in section 9.
+
+ 6.SHOULD support the downloading of Client Print Support Files
+ that have been digitally signed as described in section 9.
+
+ A client conforming to this specification:
+
+ 1.MUST ignore any fields returned by the Printer in the "client-
+ print-support-files-supported" Printer Description attribute
+ that the client does not recognize or support.
+
+ 2.SHOULD be able to retrieve Client Print Support Files by either
+ FTP Get or HTTP Get operations.
+
+ 3.MUST be able to retrieve Client Print Support Files using the
+ Get-Client-Print-Support-Files operation, i.e., support the
+ 'ipp' scheme.
+
+Parra, Tronson, Hastings Expires August 28, 2001 [page 19]
+
+
+INTERNET-DRAFT IPP: Printer Installation Extension February 28, 2001
+
+
+ 4.MUST supply the proper URI value for the "printer-uri" operation
+ attribute as specified in section 3.3.1 under Target:.
+
+ 5.MUST validate that files that are supposed to be digitally
+ signed are done with the indicated mechanism as described in
+ section 9.
+
+ 6.SHOULD support TLS as described in section 9.
+
+
+5 Encoding of the Operation Layer
+
+ This extension uses the operation layer encoding described in
+ [RFC2910].
+
+
+6 Encoding of Transport Layer
+
+ This specification uses the transport layer encoding described in
+ [RFC2910] with the following extensions.
+
+ New Error codes:
+
+ 0x0417 client-error-client-print-support-file-not-found
+
+ New Operation code
+
+ 0x0021 Get-Client-Print-Support-Files
+
+
+7 IANA Considerations
+
+ The IANA-registered operating system names that IANA has registered
+ [os-names] are required by this spec for use in the "os-type" field
+ (see Table 1).
+
+ Table 1 of this document defines possible 'keyword' values for the
+ "cpu-type" field. However, the existing IANA machine registration
+ [cpu-names] is inadequate for two reasons: a) it is really a machine
+ model number, not a CPU type, and b) it doesn't express whether a
+ CPU is 16-bit, 32-bit, or 64-bit which needs to be indicated in the
+ keyword value. Therefore, the "os-type" field will be a new
+ registration with initial values assigned.
+
+ The rest of this section contains the exact information for IANA to
+ add to the IPP Registries according to the procedures defined in RFC
+ 2911 [RFC2911] section 6.
+
+
+
+
+Parra, Tronson, Hastings Expires August 28, 2001 [page 20]
+
+
+INTERNET-DRAFT IPP: Printer Installation Extension February 28, 2001
+
+
+ Note to RFC Editors: Replace RFC NNNN below with the RFC number
+ for this document, so that it accurately reflects the content of
+ the information for the IANA Registry.
+
+
+7.1 Attribute Registrations
+
+ The attributes and fields defined in this document will be published
+ by IANA according to the procedures in RFC 2911 [RFC2911] section 6.2
+ with the following path:
+
+ ftp.isi.edu/iana/assignments/ipp/attributes/
+
+ The registry entry will contain the following information:
+
+ Printer Description Attributes: Ref: Section:
+ client-print-support-files-supported (1setOf octetString(MAX))
+ RFC NNNN 3.1
+
+ For purposes of IANA attribute registration, the following fields of
+ the "client-print-support-files-supported" and the "client-print-
+ support-files-filter" attributes are registered following the
+ procedures for IPP attribute registration:
+ Ref: Section:
+ uri (uri) RFC NNNN 3.1
+ os-type (type2 keyword) RFC NNNN 3.1
+ cpu-type (type2 keyword) RFC NNNN 3.1
+ document-format (mimeMediaType) RFC NNNN 3.1
+ natural-language (naturalLanguage) RFC NNNN 3.1
+ compression (type2 keyword) RFC NNNN 3.1
+ file-type (type2 keyword) RFC NNNN 3.1
+ client-file-name (name(MAX)) RFC NNNN 3.1
+ policy (type2 keyword) RFC NNNN 3.1
+ file-size (integer(0:MAX)) RFC NNNN 3.1
+ file-version (name(MAX)) RFC NNNN 3.1
+ file-date-time (text(25)) RFC NNNN 3.1
+ file-info (text(127)) RFC NNNN 3.1
+ digital-signature (type2 keyword) RFC NNNN 3.1
+
+ uri-scheme (uriScheme) RFC NNNN 3.2
+
+ Operation Attributes: Ref: Section:
+ client-print-support-files-filter (octetString(MAX))RFC NNNN 3.2
+
+
+
+
+
+
+
+
+Parra, Tronson, Hastings Expires August 28, 2001 [page 21]
+
+
+INTERNET-DRAFT IPP: Printer Installation Extension February 28, 2001
+
+
+7.2 Operation Registrations
+
+ The operations defined in this document will be published by IANA
+ according to the procedures in RFC 2911 [RFC2911] section 6.4 with
+ the following path:
+
+ ftp.isi.edu/iana/assignments/ipp/operations/
+
+ The registry entry will contain the following information:
+
+ Operations: Ref. Section:
+ Get-Client-Print-Support-Files RFC NNNN 3.3
+
+
+8 Internationalization Considerations
+
+ All text representations introduced by this specification adhere to
+ the internationalization-friendly representation supported by IPP.
+ This work is also accommodates the use of Client Print Support Files
+ of different languages.
+
+
+9 Security Considerations
+
+ The IPP Model and Semantics document [RFC2911] discusses high-level
+ security requirements (Client Authentication, Server Authentication
+ and Operation Privacy). Client Authentication is the mechanism by
+ which the client proves its identity to the server in a secure
+ manner. Server Authentication is the mechanism by which the server
+ proves its identity to the client in a secure manner. Operation
+ Privacy is defined as a mechanism for protecting operations from
+ eavesdropping.
+
+ Only operators of a printer SHOULD be allowed to set the "client-
+ print-support-files-supported" attribute and only users of the
+ printer SHOULD be allowed to query that information.
+
+ The IPP extension described in this document introduces the potential
+ for a security threat previously not encountered by IPP. As Client
+ Print Support Files might exist in the form of executable objects (as
+ is the case with printer drivers, for example), additional provisions
+ are needed to prevent the distribution of malicious code through this
+ mechanism. Digital signatures provide the message level security
+ commonly used to help consumers of network resources verify the
+ authenticity and integrity of those resources. Specifically, digital
+ signatures help defend against security threats such as message
+ insertion, message deletion, and message modification, and their
+ combined use into man-in-the-middle attacks.
+
+
+
+Parra, Tronson, Hastings Expires August 28, 2001 [page 22]
+
+
+INTERNET-DRAFT IPP: Printer Installation Extension February 28, 2001
+
+
+ This document identifies some commonly used signing mechanisms (SMIME
+ [RFC2634], PGP [RFC1991], DSS [dss], and XML Digital Signatures
+ [xmldsig]), though any others MAY be used. Of course, it is assumed
+ that once end-users know the identity of the provider of Client Print
+ Support Files, they can make the correct determination as to whether
+ it is safe to use those files.
+
+ Printers that support the Get-Client-Print-Support-Files operation
+ SHOULD support the downloading of Client Print Support Files that
+ have been digitally signed. Clients that invoke the Get-Client-
+ Print-Support-Files operation MUST make sure that Client Print
+ Support Files that are supposed to be signed (i.e., whose client-
+ print-support-files-supported attribute value includes the "digital-
+ signature" field) are indeed signed via the specified mechanism when
+ downloaded from the printer.
+
+ Furthermore, printers that support the Get-Client-Print-Support-Files
+ operation SHOULD implement TLS to provide application level channel
+ security and enable users to reliably authenticate the source of the
+ Client Print Support Files.
+
+
+10 References
+
+
+ [cpu-names]
+ IANA Registry of CPU Names at ftp://ftp.isi.edu/in-
+ notes/iana/assignments/XXX.
+
+ [dss]
+ U.S. Department of Commerce, "Digital Signature Standard (DDS)",
+ Federal Information Processing Standards Publication 186-1 (FIPS
+ PUB 186-1), December 15, 1998.
+
+ [ipp-url]
+ Herriot, R., McDonald, I., "Internet Printing Protocol (IPP): IPP
+ URL Scheme." <draft-ietf-ipp-url-scheme-02.txt>, February 14,
+ 2001.
+
+ [os-names]
+ IANA Registry of Operating System Names at ftp://ftp.isi.edu/in-
+ notes/iana/assignments/operating-system-names.
+
+ [RFC1991]
+ D. Atkins, W. Stallings, P. Zimmermann, "PGP Message Exchange
+ Formats", RFC 1991, August, 1996.
+
+ [RFC2026]
+ S. Bradner, "The Internet Standards Process -- Revision 3", RFC
+ 2026, October 1996.
+
+Parra, Tronson, Hastings Expires August 28, 2001 [page 23]
+
+
+INTERNET-DRAFT IPP: Printer Installation Extension February 28, 2001
+
+
+ [RFC2396]
+ Berners-Lee, T., Fielding, R., Masinter, L., "Uniform Resource
+ Identifiers (URI): Generic Syntax", RFC 2396, August 1998.
+
+ [RFC2518]
+ Goland, Y., et al, "HTTP Extensions for Distributed Authoring --
+ WEBDAV", RFC 2518, February 1999.
+
+ [RFC2616]
+ R. Fielding, J. Gettys, J. Mogul, H. Frystyk, L. Masinter, P.
+ Leach, T. Berners-Lee, "Hypertext Transfer Protocol - HTTP/1.1",
+ RFC 2616, June 1999.
+
+ [RFC2634]
+ P. Hoffman, "Enhanced Security Services for S/MIME", RFC 2634, June
+ 1999.
+
+ [RFC2910]
+ Herriot, R., Butler, S., Moore, P., Tuner, R., "Internet Printing
+ Protocol/1.1: Encoding and Transport", RFC 2910, September 2000.
+
+ [RFC2911]
+ R. deBry, T. Hastings, R. Herriot, S. Isaacson, P. Powell,
+ "Internet Printing Protocol/1.0: Model and Semantics", RFC 2911,
+ September 2000.
+
+ [xmldsig]
+ D. Eastlake, J. Reagle, D. Solo "XML-Signature Syntax and
+ Processing", <draft-ietf-xmldsig-core-11.txt>, October 31, 2000.
+
+
+11 Author's Addresses
+
+ Hugo Parra
+ Novell, Inc.
+ 1800 South Novell Place
+ Provo, UT 84606
+
+ Phone: 801-861-3307
+ Fax: 801-861-4025
+ e-mail: hparra@novell.com
+
+ Ted Tronson
+ Novell, Inc.
+ 1800 South Novell Place
+ Provo, UT 84606
+
+ Phone: 801-861-3338
+ Fax: 801-861-4025
+ e-mail: ttronson@novell.com
+
+Parra, Tronson, Hastings Expires August 28, 2001 [page 24]
+
+
+INTERNET-DRAFT IPP: Printer Installation Extension February 28, 2001
+
+
+
+ Thomas N. Hastings
+ Xerox Corp.
+ 737 Hawaii St. ESAE 231
+ El Segundo, CA 90245
+
+ Phone: 310-333-6413
+ Fax: 310-333-5514
+ e-mail: hastings@cp10.es.xerox.com
+
+
+
+12 Full Copyright Statement
+
+ Copyright (C) The Internet Society (2001). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+Parra, Tronson, Hastings Expires August 28, 2001 [page 25]
diff --git a/standards/draft-ietf-ipp-job-printer-set-ops-03.txt b/standards/draft-ietf-ipp-job-printer-set-ops-03.txt
new file mode 100644
index 000000000..4d628f637
--- /dev/null
+++ b/standards/draft-ietf-ipp-job-printer-set-ops-03.txt
@@ -0,0 +1,3828 @@
+
+
+
+
+
+
+INTERNET-DRAFT T. Hastings
+<draft-ietf-ipp-job-printer-set-ops-03.txt> R. Herriot
+Category: standards track Xerox Corporation
+ Carl Kugler
+ H. Lewis
+ IBM Corporation
+ January 22, 2001
+
+ Internet Printing Protocol (IPP):
+ Job and Printer Set Operations
+
+ Copyright (C) The Internet Society (2001). All Rights Reserved.
+
+
+Status of this Memo
+
+
+ This document is an Internet-Draft and is in full conformance with
+ all provisions of Section 10 of [RFC2026]. Internet-Drafts are
+ working documents of the Internet Engineering Task Force (IETF), its
+ areas, and its working groups. Note that other groups may also
+ distribute working documents as Internet-Drafts.
+
+
+ Internet-Drafts are draft documents valid for a maximum of six months
+ and may be updated, replaced, or obsoleted by other documents at any
+ time. It is inappropriate to use Internet-Drafts as reference
+ material or to cite them other than as "work in progress".
+
+
+ The list of current Internet-Drafts can be accessed at
+ http://www.ietf.org/ietf/1id-abstracts.txt
+ The list of Internet-Draft Shadow Directories can be accessed as
+ http://www.ietf.org/shadow.html.
+
+
+Abstract
+
+
+ This document specifies 3 additional OPTIONAL operations for use with
+ the Internet Printing Protocol/1.0 (IPP) [RFC2565, RFC2566], IPP/1.1
+ [RFC2911, RFC2910], and future versions. The end user, operator, and
+ administrator Set-Job-Attributes and Set-Printer-Attributes
+ operations are used to modify IPP Job objects and Printer objects,
+ respectively. The third administrator Get-Printer-Supported-Values
+ operation returns values that the IPP Printer will accept for setting
+ its "xxx-supported" attributes.
+
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 1]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+ Three out-of-band values are defined for use with these operations:
+ 'delete-attribute', 'admin-define', and 'not-settable', along with a
+ 'client-error-attributes-not-settable' status code.
+
+
+ Two operation attributes: "printer-message-from-operator" (text) and
+ "job-message-from-operator" (text) are defined to set the
+ corresponding IPP/1.1 Printer and Job Description attributes with the
+ same names.
+
+ Nine Printer Description attributes are defined:
+ printer-settable-attributes-supported (1setOf type2 keyword)
+ job-settable-attributes-supported (1setOf type2 keyword)
+ document-format-varying-attributes (1setOf type2 keyword)
+ printer-message-time (integer(MIN:MAX))
+ printer-message-date-time (dateTime)
+ printer-xri-supported (1setOf collection)
+ xri-uri-scheme-supported (1setOf uriScheme)
+ xri-authentication-supported (1setOf type2 keyword)
+ xri-security-supported (1setOf type2 keyword)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 2]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+ The full set of IPP documents includes:
+
+ Design Goals for an Internet Printing Protocol [RFC2567]
+ Rationale for the Structure and Model and Protocol for the Internet
+ Printing Protocol [RFC2568]
+ Internet Printing Protocol/1.1: Model and Semantics [RFC2911]
+ Internet Printing Protocol/1.1: Encoding and Transport [RFC2910]
+ Internet Printing Protocol/1.1: Implementer's Guide [IPP-IIG]
+ Mapping between LPD and IPP Protocols [RFC2569]
+
+
+ The "Design Goals for an Internet Printing Protocol" document takes a
+ broad look at distributed printing functionality, and it enumerates
+ real-life scenarios that help to clarify the features that need to be
+ included in a printing protocol for the Internet. It identifies
+ requirements for three types of users: end users, operators, and
+ administrators. It calls out a subset of end user requirements that
+ are satisfied in IPP/1.0. A few OPTIONAL operator operations have
+ been added to IPP/1.1.
+
+
+ The "Rationale for the Structure and Model and Protocol for the
+ Internet Printing Protocol" document describes IPP from a high level
+ view, defines a roadmap for the various documents that form the suite
+ of IPP specification documents, and gives background and rationale
+ for the IETF working group's major decisions.
+
+
+ The "Internet Printing Protocol/1.1: Encoding and Transport" document
+ is a formal mapping of the abstract operations and attributes defined
+ in the model document onto HTTP/1.1 [RFC2616]. It defines the
+ encoding rules for a new Internet MIME media type called
+ "application/ipp". This document also defines the rules for
+ transporting over HTTP a message body whose Content-Type is
+ "application/ipp". This document defines a new scheme named 'ipp'
+ for identifying IPP printers and jobs.
+
+
+ The "Internet Printing Protocol/1.1: Implementer's Guide" document
+ gives insight and advice to implementers of IPP clients and IPP
+ objects. It is intended to help them understand IPP/1.1 and some of
+ the considerations that may assist them in the design of their client
+ and/or IPP object implementations. For example, a typical order of
+ processing requests is given, including error checking. Motivation
+ for some of the specification decisions is also included.
+
+
+ The "Mapping between LPD and IPP Protocols" document gives some
+ advice to implementers of gateways between IPP and LPD (Line Printer
+ Daemon) implementations.
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 3]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 4]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+Table of Contents
+
+
+ 1 Introduction....................................................8
+
+ 2 Terminology.....................................................8
+ 2.1 Conformance Terminology......................................9
+ 2.2 Other terminology............................................9
+
+ 3 Requirements and Use Cases......................................9
+
+ 4 Definition of the Set operations...............................10
+ 4.1 Set-Printer-Attributes Operation............................11
+ 4.1.1 Settable and READ-ONLY Printer Description attributes.....13
+ 4.1.2 Set-Printer-Attributes Request............................15
+ 4.1.3 Set-Printer-Attributes Response...........................16
+ 4.2 Set-Job-Attributes Operation................................18
+ 4.2.1 Settable and READ-ONLY Job Description attributes.........21
+ 4.2.2 Set-Job-Attributes Request................................21
+ 4.2.3 Set-Job-Attributes Response...............................22
+ 4.3 Get-Printer-Supported-Values Operation......................24
+ 4.3.1 Definition of the usage of the 'admin-define' out-of-band
+ attribute value...................................................25
+
+ 5 New Operation attributes.......................................27
+ 5.1 printer-message-from-operator (text(127))...................27
+ 5.2 job-message-from-operator (text(127)).......................28
+
+ 6 New Printer Description Attributes.............................29
+ 6.1 printer-settable-attributes-supported (1setOf type2 keyword)29
+ 6.2 job-settable-attributes-supported (1setOf type2 keyword)....30
+ 6.3 document-format-varying-attributes (1setOf type2 keyword)...30
+ 6.4 printer-message-time (integer(MIN:MAX)).....................31
+ 6.5 printer-message-date-time (dateTime)........................31
+ 6.6 printer-xri-supported (1setOf collection)...................32
+ 6.7 xri-uri-scheme-supported (1setOf uriScheme).................34
+ 6.8 xri-authentication-supported (1setOf type2 keyword).........35
+ 6.9 xri-security-supported (1setOf type2 keyword)...............35
+
+ 7 Additional status codes........................................35
+ 7.1 'client-error-attributes-not-settable' (0x0413).............35
+
+ 8 Additional out-of-band values..................................36
+ 8.1 'not-settable' out-of-band value............................36
+ 8.1.1 Encoding of the 'not-settable' out-of-band attribute value37
+ 8.2 'delete-attribute' out-of-band value........................37
+ 8.2.1 Encoding of the 'delete-attribute' out-of-band value......37
+ 8.3 'admin-define' out-of-band attribute value..................38
+ 8.3.1 Encoding of the 'admin-define' out-of-band attribute value39
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 5]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+ 9 Conformance Requirements.......................................39
+
+ 10 IANA Considerations............................................41
+ 10.1 Operation Registrations.....................................41
+ 10.2 Attribute Registrations.....................................41
+ 10.3 Status code Registrations...................................42
+ 10.4 Out-of-band Attribute Value Registrations...................42
+
+ 11 Internationalization Considerations............................43
+
+ 12 Security Considerations........................................43
+
+ 13 Author's Addresses.............................................44
+
+ 14 References.....................................................45
+
+ 15 Appendix A: Allowed Values for Set-Printer-Attributes and Set-Job-
+ Attributes requests...............................................46
+
+ 16 Appendix B: Attributes returned from Get-Printer-Supported-Values
+ 60
+
+ 17 Appendix C: Full Copyright Statement...........................65
+
+
+ Table of Tables
+
+ Table 1 - Operation-Id assignments................................11
+ Table 2 - Job State Transition Table for the Set-Job-Attributes
+ operation .....................................................20
+ Table 3 - Member attributes of "printer-xri-supported" (1setOf
+ collection) ...................................................33
+ Table 4 - Validation rules for 'Any of "xxx-supported" '..........47
+ Table 5 - Validation rules for 'From Get-Printer-Supported-Values'48
+ Table 6 - Values allowed for Job Template Attributes in the Set-Job-
+ Attributes Operation ..........................................50
+ Table 7 - Values allowed for Job Description Attributes in the Set-
+ Job-Attributes Operation ......................................52
+ Table 8 - Values allowed for Printer Job Template Attributes in the
+ Set-Printer-Attributes Operation ..............................54
+ Table 9 - Values allowed for Printer Description Attributes in the
+ Set-Printer-Attributes Operation ..............................57
+ Table 10 - Printer Job Template Attributes returned from Get-Printer-
+ Supported-Values ..............................................61
+ Table 11 - Printer Job Template Attributes returned from Get-Printer-
+ Supported-Values ..............................................61
+ Table 12 - Printer Description Attributes returned from Get-Printer-
+ Supported-Values ..............................................62
+ Table 13 - Printer Job Template Attributes returned from Get-Printer-
+ Supported-Values ..............................................62
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 6]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+ Table 14 - Printer Job Template Attributes returned from Get-Printer-
+ Supported-Values ..............................................63
+ Table 15 - Printer Description Attributes returned from Get-Printer-
+ Supported-Values ..............................................64
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 7]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+1 Introduction
+
+
+ The Internet Printing Protocol (IPP) is an application level protocol
+ that can be used for distributed printing using Internet tools and
+ technologies. IPP version 1.1 [RFC2911, RFC2910] focuses on end user
+ functionality with a few administrative operations included. This
+ document defines additional OPTIONAL end user, operator, and
+ administrator Set-Job-Attributes and Set-Printer-Attributes
+ operations used to modify IPP Job objects and Printer objects,
+ respectively. It also defines a third administrator Get-Printer-
+ Supported-Values operation that returns values that the IPP Printer
+ will accept for setting its "xxx-supported" attributes. The Get-
+ Printer-Supported-Values operation MUST be supported, if the
+ implementation supports setting any "xxx-supported" Printer
+ attributes using the Set-Printer-Attributes operation.
+
+
+ Three out-of-band values are defined for use with these three
+ operations: 'delete-attribute' for deleting Job attributes with the
+ Set-Job-Attributes request, 'not-settable' for use in either the Set-
+ Job-Attributes or Set-Printer-Attributes responses, and 'admin-
+ define' for use in the Get-Printer-Supported-Values response.
+
+
+ Two operation attributes: "printer-message-from-operator" (text) and
+ "job-message-from-operator" (text) are defined to set the
+ corresponding IPP/1.1 Printer and Job Description attributes with the
+ same names. These operation attributes may be used with any
+ operation that affect the Printer or Job object for which an
+ operation might want to indicate a message. For the Set-Job-
+ Attributes and Set-Printer-Attributes operations, the client MUST
+ explicitly set them, rather than using these operation attributes.
+
+
+ A Printer implementation can make the value of some attributes
+ dependent on the document-format, e.g. "resolution-supported".
+
+
+ This document is an extension to IPP/1.0 [RFC2565, RFC2566] and
+ IPP/1.1 [RFC2911, RFC2910], and future versions.
+
+
+
+2 Terminology
+
+ This section defines terminology used throughout this document.
+
+
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 8]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+2.1 Conformance Terminology
+
+
+ Capitalized terms, such as MUST, MUST NOT, REQUIRED, SHOULD, SHOULD
+ NOT, MAY, NEED NOT, and OPTIONAL, have special meaning relating to
+ conformance. These terms are defined in [RFC2911] section 12.1 on
+ conformance terminology, most of which is taken from RFC 2119
+ [RFC2119].
+
+
+ The following specialization of these terms apply to this document:
+
+ REQUIRED: if an implementation supports the extensions described in
+ this document, it MUST support a REQUIRED feature.
+ OPTIONAL: if an implementation supports the extensions described in
+ this document, it MAY support an OPTIONAL feature.
+
+2.2 Other terminology
+
+
+ This document uses terms such as Job object (or Job), IPP Printer
+ object (or Printer), "operation", "request", response", "attributes",
+ "keywords", and "support". These terms have special meaning and are
+ defined in the model terminology [RFC2911] section 12.2. The
+ following additional terms are introduced in this document:
+
+ READ-ONLY: used in an attribute definition document to indicate that
+ the attribute MUST NOT be settable using an IPP protocol Set
+ operation. In other words, the attribute is not settable by
+ definition.
+ not-settable: an implementation does not support setting an
+ attribute (whether or not the attribute's definition is READ-ONLY).
+
+
+3 Requirements and Use Cases
+
+
+ The following requirements and usage are intended to be met by the
+ specification in this document.
+
+
+ 1. The end-user and the operator need a way to modify a Job that is in
+ the 'pending' or 'pending-held' state.
+
+
+ Usage: The end-user discovers that he/she forgot to include a
+ print instruction, such as "finishings" = 'staple' after submitting
+ a job. Rather than canceling the job and resubmitting it to the
+ same IPP Printer, the end-user is able to modify the job on the IPP
+ Printer.
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 9]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+ The operator needs to modify a job because it is requesting a
+ particular kind of media for which there is no more, but the policy
+ is to print the job on a comparable medium.
+
+
+ 2. The system administrator needs a way to re-configure or change the
+ policy of the IPP Printer remotely.
+
+
+ Usage: The system administrator is adding additional named media
+ to the supported media list (setting 'name' values to the "media-
+ supported" Printer attribute).
+
+
+ The system administrator is reducing the capability of the IPP
+ Printer by removing one of the operations from the supported
+ operations list, such as Cancel-Job, because the policy is to run
+ the IPP Printer like a public facsimile machine. After having
+ removed Cancel-Job from the list of supported operations, an
+ administrative client needs to be able to display to an
+ administrator that the implementation is capable of being
+ reconfigured to support Cancel-Job once again.
+
+
+ The system administrator is remotely configuring the IPP Printer
+ after installing it, and so is replacing the Printer Description
+ attributes that have the out-of-band 'no-value' value (see
+ [RFC2911] section 4.1) with the proper values.
+
+
+ The operator is changing the media loaded in the input tray and so
+ is replacing the "media-ready" Job Template Printer attribute value
+ with the proper values
+
+
+
+4 Definition of the Set operations
+
+
+ The Set-Printer-Attributes operation (as are all Printer operations)
+ are directed at Printer objects. A client MUST always supply the
+ "printer-uri" operation attribute in order to identify the correct
+ target of the operation. These descriptions assume all of the common
+ semantics of IPP/1.1 Model and Semantics document [RFC2911] section
+ 3.1.
+
+
+ The Set-Job-Attributes operation (as are all Job operations) are
+ directed at Job objects. A client MUST always supply some means of
+ identifying the Job object in order to identify the correct target of
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 10]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+ the operation. That job identification MAY either be a single Job
+ URI or a combination of a Printer URI with a Job ID as defined in
+ [RFC2911]. The IPP object implementation MUST support both forms of
+ identification for every job. If possible, a client SHOULD use the
+ Printer URI with a Job ID rather than a Job URI, since the 32-bit
+ "job-id" is more readily translated to and from other print protocols
+ that MAY be serving as gateways into or out of the IPP
+ implementation.
+
+
+ The Set Printer operations are summarized in Table 1:
+
+ Table 1 - Operation-Id assignments
+
+
+
+ Operation Name Operation Brief description
+ -Id
+
+
+ Set-Printer- 0x0013 Sets attribute values of the target
+ Attributes Printer object
+
+ Set-Job-Attributes 0x0014 Sets attribute values of the target
+ Job object
+
+ Get-Printer- 0x0015 Gets values that are valid for
+ Supported-Values setting "xxx-supported" attributes
+ using the Set-Printer-Attributes
+ operation
+
+
+4.1 Set-Printer-Attributes Operation
+
+
+ This OPTIONAL operation allows a client to set the values of the
+ attributes of a Printer object. In the request, the client supplies
+ the set of Printer keyword attribute names and values that are to be
+ set. In the response, the Printer object returns success or rejects
+ the entire request with indications of which attribute or attributes
+ could not be set.
+
+
+ The Printer object validates the client-supplied attributes in the
+ Set-Printer-Attributes request. For an attribute to validate it MUST
+ meet all of the following rules:
+
+
+ 1. The number of attributes supplied by the client MUST NOT exceed the
+ maximum number that the Printer supports in a Set-Printer-
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 11]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+ Attributes request. A Printer MUST accept at least one attribute,
+ but SHOULD accept a reasonable number in a single Set-Printer-
+ Attributes request.
+
+
+ Note: There is no way for the client to determine the maximum
+ number of attributes that the Printer supports in a Set-Printer-
+ Attributes request, except to try a reasonable number.
+
+
+ 2. The Printer MUST support the attribute.
+
+
+ 3. The attribute MUST NOT be READ-ONLY, i.e., the definition of the
+ attribute MUST NOT indicate that the attribute is READ-ONLY (see
+ Appendix A for an indication of which IPP/1.1 attributes are READ-
+ ONLY).
+
+
+ 4. The attribute MUST be settable in this implementation.
+
+
+ 5. The Printer MUST support the value according to the rules defined
+ in Appendix A, i.e., each value of each supplied "xxx" attribute
+ MUST be validated against a value of a corresponding "xxx-
+ supported" Printer attribute. One of those rules permits an
+ administrator to set arbitrary 'name' values to those "xxx-
+ supported" Printer attributes that include the 'name' attribute
+ syntax if the implementation supports the 'admin-define' out-of-
+ band value for that "xxx-supported" attribute (see section 15 and
+ 8.3).
+
+
+ 6. The attribute's values MUST NOT conflict with the values of other
+ Printer attributes, including ones being set in this same
+ operation.
+
+
+ If any of the supplied attributes does not validate, the Printer
+ object MUST reject the entire operation; the Printer object MUST NOT
+ partially set some of the supplied attributes. In other words, after
+ the operation, all the supplied attributes MUST be set or none of
+ them MUST be set, thus making the Set-Printer-Attributes an atomic
+ operation.
+
+
+ The Printer MUST accept this operation when its READ-ONLY "printer-
+ state" attribute (see RFC2911] section 4.4.11) is 'idle' or
+ 'stopped', and SHOULD accept it when the value is 'processing'. The
+ Printer MUST accept this operation for any of the values of the
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 12]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+ Printer object's READ-ONLY "printer-state-reasons" and "printer-is-
+ accepting-jobs" attributes, unless explicitly defined otherwise in
+ the definition of these attributes' values.
+
+
+ This operation MUST NOT change the value of attributes not specified
+ in the operation unless the definition of the attribute explicitly
+ specifies such side-effects. For example, this document explicitly
+ specifies that when this operation sets "printer-message-from-
+ operator", the Printer also MUST set the READ-ONLY "printer-message-
+ time" and READ-ONLY "printer-message-date-time" attributes to the
+ time of the operation as a side effect . In particular, if this
+ operation changes an "xxx-default" attribute, the new value MUST be
+ in the "xxx-supported" attribute or the request MUST contain a new
+ value for "xxx-supported" which contains the new value for the "xxx-
+ default". Otherwise, the Printer MUST reject the operation. In
+ general, Printer attribute definitions that are settable will not
+ define side-effects on other attributes that are settable, only side
+ effects on READ-ONLY attributes, if any.
+
+
+4.1.1 Settable and READ-ONLY Printer Description attributes
+
+
+ If the Printer supports the Set-Printer-Attributes operation, then it
+ SHOULD support setting of:
+
+
+ all Job Template Default ("xxx-default") attributes
+
+ all Job Template Supported ("xxx-supported") attributes
+
+ all Job Template Ready ("xxx-ready") attributes
+
+ that the implementation supports (see [RFC2911] section 4.2 and
+ extensions).
+
+
+ Some Printer Description attributes (see [RFC2911] section 4.4) MUST
+ NOT be settable, i.e., they are defined to be READ-ONLY. An
+ attribute marked as "READ-ONLY" in the Printer Description attribute
+ table in Appendix A is such an attribute. The Printer attributes
+ that are not marked as "READ-ONLY" MAY be settable using the Set-
+ Printer-Attributes operation, depending on implementation.
+
+
+ Note: From now on, all extensions that define new object attributes
+ will indicate whether or not the attributes are READ-ONLY, by
+ including the "READ-ONLY" adjective in their descriptions and/or
+ explicitly stating whether they MAY be settable.
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 13]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+ The current values of each "xxx-supported" Printer attribute MUST
+ reflect the current policy for support of the corresponding "xxx"
+ attribute. If an "xxx-supported" Printer attribute is settable in an
+ implementation, then its value(s) MUST affect the behavior of the
+ implementation. If an "xxx-supported" Printer attribute is defined
+ to be READ-ONLY or is not-settable in an implementation, then its
+ values MUST NOT be settable using the Set-Printer-Attributes
+ operation. Consider the following example:
+
+
+ For example, if the "operations-supported" Printer Description
+ attribute (see [RFC2911] section 4.4.15) is settable in a
+ particular implementation, then changing its value with a Set-
+ Printer-Attributes operation MUST affect the operations that the
+ implementation accepts or rejects. Such an implementation will
+ need to be able to reject values for operations that it contains no
+ code support for (see section 4.3). If the "operations-supported"
+ Printer Description attribute is not settable in a particular
+ implementation, then that implementation MUST reject an attempt to
+ set it with a Set-Printer-Attributes operation, return the 'client-
+ error-attributes-not-settable' status code (see section 7.1), and
+ return the "operations-supported" attribute with the out-of-band
+ 'not-settable' value in the Unsupported Attributes Group.
+
+
+ As another example, consider an implementation in which the "media-
+ default" and "media-supported" are settable. If a client supplies
+ a Set-Printer-Attributes request that contains the "media-default"
+ attribute with a value that is not a member of the Printer's
+ "media-supported" attribute, the Printer MUST reject the request
+ and return the "client-error-conflicting-attributes" status code
+ with the "media-default" and "media-supported" attributes and their
+ values (see [RFC2911] section 3.1.7).
+
+
+ As a third example, if a client supplies a Set-Printer-Attributes
+ request that contains both the "media-default" and the "media-
+ supported" attributes, but includes a value in the "media-default"
+ that is not a member of the supplied "media-supported" attribute,
+ the Printer MUST reject the request and return the "client-error-
+ conflicting-attributes" status code with the "media-default" and
+ "media-supported" attributes and their values (see [RFC2911]
+ section 3.1.7).
+
+
+ Access Rights: The authenticated user (see [RFC2911] section 8.3)
+ performing this operation must be an operator or administrator of the
+ Printer object (see [RFC2911] Sections 1 and 8.5). Most Printer
+ attributes will require administrator access rights to set, such as
+ "xxx-supported", while some will require operator access rights only,
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 14]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+ such as "media-ready" and "printer-message-from-operator". Which
+ attributes require which access rights depends on implementation and
+ MAY depend on site policy.
+
+
+4.1.2 Set-Printer-Attributes Request
+
+
+ The following sets of attributes are part of the Set-Printer-
+ Attributes Request:
+
+
+ Group 1: Operation Attributes
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in [RFC2911] section 3.1.4.1.
+
+ Target:
+ The "printer-uri" (uri) operation attribute which is the target
+ for this operation as described in [RFC2911] section 3.1.5.
+
+ Requesting User Name:
+ The "requesting-user-name" (name(MAX)) attribute SHOULD be
+ supplied by the client as described in [RFC2911] section 8.3.
+
+ "document-format" (mimeMediaType):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object MUST support this attribute. This attribute is useful
+ for a client to select the document-format to which the
+ attribute modification should be applied. A Printer
+ implementation MAY allow some attributes to have different
+ values for each document format that it supports. See [RFC2911]
+ section 3.2.5.1 "Get-Printer-Attributes Request".
+
+ If the client includes this attribute, the Printer MUST change
+ the supplied attributes for the document format specified by
+ this attribute. If a supplied attribute is a member of the
+ "document-format-varying-attributes" (i.e., the attribute
+ varies by document format, see section 6.3), the Printer MUST
+ change the supplied attribute for the document format specified
+ by this attribute, but not for other document formats. If a
+ supplied attribute isn't a member of the "document-format-
+ varying-attributes" (i.e. it doesn't vary by document format),
+ the Printer MUST change the supplied attribute for all document
+ formats.
+
+ If the client omits this attribute, the Printer MUST change the
+ supplied attributes for all document formats whether or not
+ they vary by document-format.
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 15]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+
+ If the client supplies a value for the "document-format"
+ Operation attribute that is either 'application/octet-stream'
+ or not supported by the Printer, i.e., is not among the values
+ of the Printer object's "document-format-supported" attribute,
+ the Printer object MUST reject the operation and return the
+ 'client-error-document-format-not-supported' status code.
+ Note: the document-format 'application/octet-stream' is the
+ union of several document-formats (see [RFC2911] section
+ 3.2.5.1, Get-Printer-Attributes) and is not a true document-
+ format.
+
+
+ Group 2: Printer Attributes
+
+ The client MUST supply a set of Printer attributes with one or
+ more values (including explicitly allowed out-of-band values)
+ as defined in [RFC2911] section 4.2 Job Template Attributes
+ ("xxx-default", "xxx-supported", and "xxx-ready" attributes),
+ section 4.4 Printer Description Attributes, and any attribute
+ extensions supported by the Printer. The value(s) of each
+ Printer attribute supplied in Group 2 replaces the value(s) of
+ the corresponding Printer attribute on the target Printer
+ object. For attributes that can have multiple values (1setOf),
+ all values supplied by the client replace all values of the
+ corresponding Printer object attribute. If a Printer object
+ attribute had not been configured yet and so had the 'no-value'
+ out-of-band value (see [RFC2911] section 4.1), the supplied
+ value(s) replace the 'no-value' value.
+
+
+4.1.3 Set-Printer-Attributes Response
+
+
+ The Printer object returns the following sets of attributes as part
+ of the Get-Printer-Attributes Response:
+
+
+ Group 1: Operation Attributes
+
+ Status Message:
+ In addition to the REQUIRED status code returned in every
+ response, the response OPTIONALLY includes a "status-message"
+ (text(255)) and/or a "detailed-status-message" (text(MAX))
+ operation attribute as described in [RFC2911] sections 13 and
+ 3.1.6.
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in [RFC2911] section 3.1.4.2.
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 16]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+
+
+ Group 2: Unsupported Attributes
+
+ See [RFC2911] section 3.1.7 for details on returning
+ Unsupported Attributes.
+
+ If some of the attributes in the operation fail to validate,
+ the Printer MUST reject the operation, MUST NOT change any
+ Printer attributes, and MUST return the indicated status code
+ below. In this group, the Printer MUST also return all
+ attributes that fail to validate. The following are the
+ reasons that an attribute fails to validate and the value
+ returned for the attribute, along with the indicated status
+ code and order of detection:
+
+ 1.The number of attributes supplied by the client exceeds the
+ maximum number that the Printer supports in a Set-Printer-
+ Attributes request: return the 'client-error-request-
+ entity-too-large' (see [RFC2911] section 13.1.4.9).
+
+
+ 2.The Printer doesn't support the attribute: return the
+ attribute with the "out-of-band" value 'unsupported' (see
+ [RFC2911] section 3.1.7 and [RFC2910]) and the 'client-
+ error-attributes-or-values-not-supported (see [RFC2911]
+ section 13.1.4.12).
+
+
+ 3.The attribute is either READ-ONLY (in its definition) or is
+ not-settable in this implementation: return the attribute
+ with the "out-of-band" value 'not-settable' (see section
+ 8.1) and the 'client-error-attributes-not-settable' status
+ code (see section 7.1).
+
+
+ 4.The Printer doesn't support the value: if the attribute in
+ the operation has a single value return it. If the
+ attribute in the operation is multi-valued, return only
+ those values in a 1setOf that are not supported. Return the
+ 'client-error-attributes-or-values-not-supported' status
+ code (see [RFC2911] section 13.1.4.12).
+
+
+ 5.The values of some of the supplied attributes conflict with
+ one another and/or other Printer attribute values not being
+ set: if the conflicting attribute in the operation has a
+ single value return the attribute and the value. If the
+ attribute in the operation is multi-valued, return only the
+ attribute and those values in a 1setOf that are conflicting
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 17]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+ with other attributes. Return the 'client-error-
+ conflicting-attributes' status code (see [RFC2911] section
+ 13.1.4.15).
+
+
+4.2 Set-Job-Attributes Operation
+
+
+ This OPTIONAL operation allows a client to set the values of the
+ attributes of a Job object. In the request, the client supplies the
+ set of Job keyword attribute names and values that are to be set. In
+ the response, the IPP object returns success or rejects the entire
+ request with indications of which attribute or attributes could not
+ be set.
+
+
+ This operation is almost identical to the Set-Printer-Attributes
+ operation and follows the same rules for validation (see section
+ 4.1). The only differences are that the Set-Job-Attributes operation
+ is directed at a Job object rather than a Printer object, there is no
+ "document-format" operation attribute used when setting a Job object,
+ the operation can add an attribute to the (Job) object, the 'delete-
+ attributes' out-of-band value is permitted to remove an attribute,
+ and the validation is the same as the Job Creation operations (Print-
+ Job, Print-URI, and Create-Job), i.e., depends on the "xxx-supported"
+ Printer Description attributes (see [RFC2911] section 3.1). Using
+ the Set-Printer-Attributes operation, the administrator can set
+ arbitrary 'name' values to those "xxx-supported" Printer attributes
+ that include the 'name' attribute syntax if the implementation
+ supports the 'admin-define' out-of-band value for that "xxx-
+ supported" attribute (see section 15 and 8.3). However, the Set-Job-
+ Attributes cannot be used to add unsupported names to the Job object.
+
+
+ If a client supplies a job attribute in a Set-Job-Attributes request
+ that the Printer supports, and the job was originally submitted
+ without supplying that attribute, the Printer adds the attribute to
+ the Job object.
+
+
+ If the client supplies a job attribute with the "out-of-band" value
+ 'delete-attribute' (see section 8.2), then the Printer MUST remove
+ the attribute and all of its values from the Job object, if present.
+ The semantic effect of the client supplying the 'delete-attribute'
+ value in a Set-Job-Attributes operation MUST be the same as if the
+ attribute had not been supplied with the Job object in the Job
+ Creation operation, i.e., the Printer applies its default attribute
+ or behavior with lower precedence that the PDL (see the beginning of
+ [RFC2911] section 4.2 and [RFC2911] 3.2.1.1). Any subsequent query
+ of the Job object using Get-Job-Attributes or Get-Jobs MUST NOT
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 18]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+ return any attribute that has been deleted using the 'delete-
+ attribute' out-of-band value. However, a client can re-establish
+ such a deleted Job attribute with any supported value(s) using a
+ subsequent Set-Job-Attributes operation.
+
+
+ If the client supplies an attribute in a Set-Job-Attributes request
+ with the 'delete-attribute' value and that attribute is not present
+ on the Job object, the Printer ignores that supplied attribute in the
+ request, does not return the attribute in the Unsupported Attributes
+ group, and returns the 'successful-ok' status code, if there are no
+ other problems with the request.
+
+
+ The validation of the Set-Job-Attributes request is performed by the
+ Printer as if the job had been submitted originally with the new
+ attribute values (and the deleted attributes removed) and with "ipp-
+ attribute-fidelity" set to 'true', i.e., all modified attributes Job
+ attributes and values MUST be supported in combination with the Job
+ attributes not modified. If such a Job Creation operation would have
+ been accepted, then the Set-Job-Attributes MUST be accepted. If such
+ a Job Creation operation would have been rejected, then the Set-Job-
+ Attributes MUST be rejected and the Job MUST be unchanged. In
+ addition, if any of the supplied attributes are not supported, are
+ not settable, or the values are not supported, the Printer object
+ MUST reject the entire operation; the Printer object MUST NOT
+ partially set some of the supplied attributes. In other words, after
+ the operation, all the supplied attributes MUST be set or none of
+ them MUST be set, thus making the Set-Job-Attributes an atomic
+ operation.
+
+
+ The IPP object MUST accept or reject this operations when the Job's
+ READ-ONLY "job-state" attribute has the values shown in Table 2. The
+ job's current state MUST affect whether the IPP object accepts or
+ rejects the request. For example, in the case where the operation
+ creates a request for unavailable resources, the Job transitions to a
+ new state. Table 2 shows the allowed behaviors in each job state and
+ the transitions.
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 19]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+ Table 2 - Job State Transition Table for the Set-Job-Attributes
+ operation
+
+
+
+ Current "job- New "job- IPP object's response status code
+ state" state" and action:
+
+
+ 'pending' 'pending' 'successful-ok'
+
+ 'pending' 'pending-held' 'successful-ok' - needed resources
+ are not ready
+
+ 'pending-held' 'pending-held' 'successful-ok'
+
+ 'pending-held' 'pending' 'successful-ok' - needed resources
+ are ready
+
+ 'processing' 'processing' 'successful-ok' or 'client-error-
+ not-possible' depending on
+ implementation, including the
+ attributes being set, whether the
+ job has started marking media,
+ etc.
+
+ 'processing- 'processing- 'successful-ok' or 'client-error-
+ stopped' stopped' not-possible' depending on
+ implementation, including the
+ attributes being set, whether the
+ job has started marking media,
+ etc.
+
+ 'completed' 'completed' 'client-error-not-possible'
+
+ 'canceled' 'canceled' 'client-error-not-possible'
+
+ 'aborted' 'aborted' 'client-error-not-possible'
+
+
+
+
+
+ This operation MUST NOT change the value of attributes not specified
+ in the operation unless the definition of the attribute explicitly
+ specifies such side-effects. In general, Job attribute definitions
+ that are settable will not define side-effects on other attributes
+ that are settable, only side effects on READ-ONLY attributes, if any.
+
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 20]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+4.2.1 Settable and READ-ONLY Job Description attributes
+
+
+ If the Printer supports the "job-message-from-operator" Job
+ Description attribute (see [RFC2911] section 4.3.16) and the client
+ explicitly supplies a new value for the "job-message-from-operator"
+ in the Set-Job-Attributes request, then the Printer MUST set the
+ "job-message-from-operator" Job attribute to this new value.
+
+
+ If the Printer supports the Set-Job-Attributes operation, then it
+ SHOULD support setting of:
+
+
+ all Job Template job ("xxx") attributes
+
+ that the implementation supports (see [RFC2911] section 4.2 and
+ extensions).
+
+
+ Some Job Description attributes (see [RFC2911] section 4.3) MUST NOT
+ be settable, i.e., they are defined to be READ-ONLY. An attribute
+ marked as "READ-ONLY" in the Job Description attribute table in
+ Appendix A is such an attribute. The Job attributes not marked as
+ "READ-ONLY" MAY be settable using the Set-Job-Attributes operation,
+ depending on implementation.
+
+
+ Note: From now on, all extensions that define new object attributes
+ will indicate whether or not the attributes are READ-ONLY, by
+ including the "READ-ONLY" adjective in their descriptions and/or
+ explicitly stating whether they MAY be settable.
+
+
+ Access Rights: The authenticated user (see [RFC2911] section 8.3)
+ performing this operation must either be the job owner (as determined
+ in the Job Creation operation) or an operator or administrator of the
+ Printer object (see [RFC2911] Sections 1 and 8.5).
+
+
+4.2.2 Set-Job-Attributes Request
+
+
+ The following sets of attributes are part of the Set-Job-Attributes
+ Request:
+
+
+ Group 1: Operation Attributes
+
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 21]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in [RFC2911] section 3.1.4.1.
+
+ Target:
+ Either (1) the "printer-uri" (uri) plus "job-id"
+ (integer(1:MAX)) or (2) the "job-uri" (uri) operation
+ attribute(s) which define the target for this operation as
+ described in [RFC2911] section 3.1.5.
+
+ Requesting User Name:
+ The "requesting-user-name" (name(MAX)) attribute SHOULD be
+ supplied by the client as described in [RFC2911] section 8.3.
+
+
+ Group 2: Job Attributes
+
+ The client MUST supply a set of Job attributes with one or more
+ values (including explicitly allowed out-of-band values) as
+ defined in [RFC2911] section 4.2 Job Template Attributes ("xxx"
+ attributes), section 4.3 Job Description Attributes, and any
+ attribute extensions supported by the Printer. The value(s) of
+ each Job attribute supplied in Group 2 replaces the value(s) of
+ the corresponding Job attribute on the target Job object. For
+ attributes that can have multiple values (1setOf), all values
+ supplied by the client replace all values of the corresponding
+ Job object attribute.
+
+ If the client supplies an "xxx" attribute with the 'delete-
+ attribute' out-of-band value (see section 8.2), the Printer
+ MUST remove the "xxx" attribute from the Job object, if
+ present.
+
+
+4.2.3 Set-Job-Attributes Response
+
+
+ The IPP object returns the following sets of attributes as part of
+ the Set-Job-Attributes Response:
+
+
+ Group 1: Operation Attributes
+
+ Status Message:
+ In addition to the REQUIRED status code returned in every
+ response, the response OPTIONALLY includes a "status-message"
+ (text(255)) and/or a "detailed-status-message" (text(MAX))
+ operation attribute as described in [RFC2911] sections 13 and
+ 3.1.6.
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 22]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in [RFC2911] section 3.1.4.2.
+
+
+ Group 2: Unsupported Attributes
+
+ See [RFC2911] section 3.1.7 for details on returning
+ Unsupported Attributes.
+
+ If some of the attributes in the operation fail to validate,
+ the Printer MUST reject the operation, MUST NOT change any Job
+ attributes, and MUST return the indicated status code below.
+ In this group, the Printer MUST also return all attributes that
+ fail to validate. The following are the reasons that an
+ attribute fails to validate and the value returned for the
+ attribute, along with the indicated status code and order of
+ detection:
+
+ 1.The number of attributes supplied by the client exceeds the
+ maximum number that the Printer supports in a Set-Printer-
+ Attributes request: return the 'client-error-request-
+ entity-too-large' (see [RFC2911] section 13.1.4.9).
+
+
+ 2.The Printer doesn't support the attribute: return the
+ attribute with the 'unsupported' out-of-band attribute value
+ (see [RFC2911] section 3.1.7 and [RFC2910]) and the 'client-
+ error-attributes-or-values-not-supported (see [RFC2911]
+ section 13.1.4.12).
+
+
+ 3.The attribute is READ-ONLY (in its definition) or is not-
+ settable in this implementation: return the attribute with
+ the 'not-settable' out-of-band attribute value (see section
+ 8.1) and the 'client-error-attributes-not-settable' status
+ code (see section 7.1).
+
+
+ 4.The Printer doesn't support the value: if the attribute in
+ the operation has a single value return it. If the
+ attribute in the operation is multi-valued, return only
+ those values in a 1setOf that are not supported. Return the
+ 'client-error-attributes-or-values-not-supported' status
+ code (see [RFC2911] section 13.1.4.12).
+
+
+ 5.The values of some of the supplied attributes conflict with
+ one another and/or other Job attribute values not being set:
+ if the conflicting attribute in the operation has a single
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 23]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+ value return the attribute and the value. If the attribute
+ in the operation is multi-valued, return only the attribute
+ and those values in a 1setOf that are conflicting with other
+ attributes. Return the 'client-error-conflicting-
+ attributes' status code (see [RFC2911] section 13.1.4.15).
+
+
+4.3 Get-Printer-Supported-Values Operation
+
+
+ This OPTIONAL operation allows a client to request the values that
+ the Printer allows in the Set-Printer-Attributes operation for "xxx-
+ supported" attributes. If the Printer supports the Set-Printer-
+ Attributes operation AND some of its "xxx-supported" Printer
+ attributes are settable, then the Printer MUST also support this
+ operation.
+
+
+ The Printer MUST return in the Get-Printer-Supported-Values response
+ those, and only those, "xxx-supported" Printer attributes that it
+ supports setting with the Set-Printer-Attributes operation.
+ Furthermore, if a client requests the value of an attribute that is
+ not settable or is not supported (as in the Get-Printer-Attributes
+ response), the Unsupported Attributes Group of the response NEED NOT
+ contain the "requested-attributes" operation attribute with any such
+ requested (attribute keyword) values.
+
+
+ This operation has identical request/response attributes to the Get-
+ Printer-Attributes operation in IPP/1.1 [RFC2911]. The operation
+ also behaves identically to the Get-Printer-Attributes operation in
+ IPP/1.1 [RFC2911] with the following exceptions:
+
+
+ 1.The Get-Printer-Supported-Values operation supports only "xxx-
+ supported" attributes.
+
+
+ 2.The Get-Printer-Attributes operation returns the few "xxx-
+ supported" attributes that are defined to be single valued, such
+ as "page-ranges-supported" (boolean) or "pdl-override-supported"
+ (type2 keyword), as single values, while Get-Printer-Supported-
+ Values returns the possible values that can be set as a 1setOf of
+ the same attribute syntax type (See Appendix B: Attributes
+ returned from Get-Printer-Supported-Values).
+
+
+ 3.The Get-Printer-Attributes operation returns the current values of
+ requested attributes while the Get-Printer-Supported-Values
+ operation returns the values that are inherently supported by the
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 24]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+ implementation code, i.e., the values that an administrative
+ client can set in a Set-Printer-Attributes request.
+
+
+ 4.The Get-Printer-Attributes operation returns the current values of
+ requested "xxx-supported" attributes that the Printer is
+ configured to accept in Job Creation operations, including
+ additional values defined by the administrator, while the Get-
+ Printer-Supported-Values operation returns only the values of
+ "xxx-supported" attributes that are inherently supported by the
+ implementation and does not return any additional values defined
+ by the administrator where the implementation supports the 'admin-
+ define' out-of-band value.
+
+
+ 5.The Get-Printer-Attributes never returns the 'admin-define' out-
+ of-band attribute value, while the Get-Printer-Supported-
+ Attributes operation does, if the implementation allows the
+ administrator to define name values by setting that "xxx-
+ supported" attribute with any 'name' value(s).
+
+
+ 6.The Get-Printer-Attributes operation only requires end-user access
+ rights, while the Get-Printer-Supported-Values requires
+ administrator access rights.
+
+
+ Access Rights: The authenticated user (see [RFC2911] section 8.3)
+ performing this operation must be an administrator of the Printer
+ object (see [RFC2911] Sections 1 and 8.5).
+
+
+4.3.1 Definition of the usage of the 'admin-define' out-of-band
+ attribute value
+
+
+ If the Set-Printer-Attributes operation allows the System
+ Administrator to define arbitrary 'name' values for an "xxx-
+ supported" attribute, then the Get-Printer-Supported-Values operation
+ MUST return the 'admin-define' out-of-band attribute value (see
+ section 8.3) as one of the values of the "xxx-supported" attribute.
+ In other words, the 'admin-define' out-of-band attribute value
+ indicates that the Printer implementation supports clients setting
+ arbitrary 'name' attribute syntax values for that "xxx-supported"
+ attribute using the Set-Printer-Attributes operation as long as the
+ attribute is defined with the 'name' attribute syntax.
+
+
+ For example, if the Get-Printer-Supported-Values operation returns
+ several keywords as the value of the "media-supported" attribute,
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 25]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+ then the Set-Printer-Attributes operation MUST accept any of these
+ keywords as values for the "media-supported" attribute. If the Get-
+ Printer-Supported-Values operation returns an 'admin-define' out-of-
+ band attribute value as one of the values of the "media-supported"
+ attribute, then the Set-Printer-Attributes operation MUST accept any
+ value whose attribute syntax is 'name' as a value for the "media-
+ supported" attribute (provided that the user is properly
+ authenticated to use the Set-Printer-Attributes operation, e.g., has
+ administrative access rights).
+
+
+ The Get-Printer-Supported-Values MAY return the 'admin-define' out-
+ of-band attribute value for any IPP/1.1 or extension Job Template
+ attribute if the implementation supports allowing the System
+ Administrator to add values to the "xxx-supported" attribute using
+ the Set-Printer-Attributes operation. In this case, the Printer MUST
+ accept any 'name' value of the correct attribute syntax in a Set-
+ Printer-Attributes operation that is setting that attribute. For
+ "xxx-supported" attributes that are defined with a choice of
+ attribute syntaxes, such as 'keyword | name', it is the 'name'
+ attribute syntax that the System Administrator can use to add new
+ values, not the 'keyword' attribute syntax. For IPP/1.1 this
+ requirement includes the following Job Template attributes:
+
+ media-supported
+ job-hold-until-supported
+ job-sheets-supported
+
+ Implementations that support additional Job Template attributes that
+ include the 'name' attribute syntax, MAY use the 'admin-define' out-
+ of-band value with them.
+
+
+ If the 'admin-define' out-of-band attribute value is not one of the
+ values of an "xxx-supported" attribute returned in a Get-Printer-
+ Supported-Values response, then the Printer MUST NOT allow the Set-
+ Printer-Attributes operation for that attribute to contain a value
+ that is not one of the explicit 'keyword' or 'name' values returned
+ in a Get-Printer-Supported-Values response.
+
+
+ See Appendix B: Attributes returned from Get-Printer-Supported-Values
+ for a full list of values returned by this operation.
+
+
+
+
+
+
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 26]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+5 New Operation attributes
+
+
+ This section defines new operation attributes for use with the
+ IPP/1.1 operations indicated. As new operations are defined they
+ will also indicate explicitly whether these operation attributes are
+ defined for use with them.
+
+
+5.1 printer-message-from-operator (text(127))
+
+
+ The Printer SHOULD support this Operation attribute in following
+ operations if it supports the corresponding "printer-message-from-
+ operator" Printer Description attribute.
+
+
+ Pause-Printer
+ Resume-Printer
+ Purge-Jobs
+
+
+ The client OPTIONALLY supplies this attribute in the above
+ operations. The value of this attribute is a message from the
+ operator about the Printer object on which the operator is performing
+ the operation. If this operation attribute is supported, the Printer
+ copies the value to its "printer-message-from-operator" Printer
+ Description attribute (see [RFC2911] section 4.4.25) even if this
+ Operation attribute is a zero-length text value or consists solely of
+ white space.
+
+
+ If the Printer supports this operation attribute, it MUST support
+ both a zero-length text value and the 'no-value' out-of-band value
+ (see [RFC2911] section 4.1) to indicate that the operator has sent no
+ message. In this case, the Printer sets the value of the "printer-
+ message-from-operator" to the zero-length value or 'no-value' out-of-
+ band value, respectively. If the client queries the "printer-
+ message-from-operator" Printer attribute, the Printer returns the
+ attribute with the zero-length value or the 'no-value' value,
+ respectively.
+
+
+ In addition, the Printer automatically copies:
+
+
+ 1.the value of its "printer-up-time" attribute (see [RFC2911]
+ section 4.4.29) to its "printer-message-time" attribute,
+
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 27]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+ 2.the value of its printer-current-time" (dateTime) attribute (see
+ [RFC2911] section 4.4.30) to its "printer-message-date-time"
+ attribute, if supported.
+
+
+ If the client omits this operation attribute, the Printer does not
+ change the value of its "printer-message-from-operator", "printer-
+ message-time" and "printer-message-date-time" Printer Description
+ attributes.
+
+
+ The "printer-message-from-operator" operation attribute MUST NOT be
+ supported as an operation attribute for the Set-Printer-Attributes
+ operation. If the operator wants to set the Printer's "printer-
+ message-from-operator" Printer Description attribute when issuing the
+ Set-Printer-Attributes operation, the client supplies the "printer-
+ message-from-operator" explicitly with its new value as one of the
+ Printer Description attributes in Group 2 in the request. The
+ Printer also updates its "printer-message-time" and "printer-message-
+ date-time" Printer Description attributes. If the client does not
+ explicitly supply the "printer-message-from-operator" with its new
+ value in the Set-Printer-Attributes request, the Printer leaves the
+ value of the Printer's "printer-message-from-operator" Printer
+ Description attribute unchanged.
+
+
+5.2 job-message-from-operator (text(127))
+
+
+ The Printer SHOULD support this Operation attribute in following
+ operations if it supports the corresponding "job-message-from-
+ operator" Job Description attribute.
+
+
+ Cancel-Job
+ Hold-Job
+ Release-Job
+ Restart-Job
+
+
+ The client OPTIONALLY supplies this attribute in the above
+ operations. The value of this attribute is a message from the
+ operator about the Job object on which the operator has just
+ performed an operation. If supported, the Printer copies the value
+ to the Job's "job-message-from-operator" Job Description attribute
+ (see [RFC2911] section 4.3.16) (even if this Operation attribute is a
+ zero-length text value or consists solely of white space).
+
+
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 28]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+ If the Printer supports this operation attribute, it MUST support
+ both a zero-length text value and the 'no-value' out-of-band value
+ (see [RFC2911] section 4.1) to indicate that the operator has sent no
+ message. In this case, the Printer sets the value of the "job-
+ message-from-operator" to the zero-length value or 'no-value' out-of-
+ band value, respectively. If the client queries the "job-message-
+ from-operator" Job attribute, the IPP object returns the attribute
+ with the zero-length value or the 'no-value' value, respectively.
+
+
+ If the client omits this attribute, the Printer does not change the
+ value of its "job-message-from-operator" Job Description attribute.
+
+
+ Note: There are no corresponding 'job-message-time" and "job-
+ message-date-time" Job Description attributes, since the usual
+ lifetime of a job is limited.
+
+
+ The "job-message-from-operator" operation attribute MUST NOT be
+ supported as an operation attribute for the Set-Job-Attributes
+ operation. If the operator wants to set the Job's "job-message-from-
+ operator" Job Description attribute when issuing the Set-Job-
+ Attributes operation, the client MUST supply the "job-message-from-
+ operator" with its new value as one of the Job Description attributes
+ in Group 2 in the request. Otherwise, the Printer leaves the value
+ of the Job's "job-message-from-operator" Job Description attribute
+ unchanged by not explicitly setting the attribute. If the client
+ does not explicitly supply the "job-message-from-operator" with its
+ new value in the Set-Job-Attributes request, the Printer leaves the
+ value of the Job's "job-message-from-operator" Job Description
+ attribute unchanged.
+
+
+
+6 New Printer Description Attributes
+
+
+ The following new Printer Description attributes are needed to
+ support the new operations defined in this document.
+
+
+6.1 printer-settable-attributes-supported (1setOf type2 keyword)
+
+
+ This REQUIRED READ-ONLY Printer attribute identifies the Printer
+ object attributes that are settable in this implementation, i.e.,
+ that are settable using the Set-Printer-Attributes operations (see
+ section 4.1). This attribute MUST be supported if the Set-Printer-
+ Attributes operations is supported. The Printer MUST reject attempts
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 29]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+ to set any Printer attributes that are not one of the values of this
+ attribute, returning the 'client-error-attributes-not-settable'
+ status code (see section 7.1). The value of this attribute MAY
+ depend on the value of the "document-format" operation attribute
+ supplied in the Get-Printer-Attributes operation (see [RFC2911]
+ section 3.2.5.1).
+
+
+ Standard keyword values are:
+
+ 'none': There are no settable Printer attributes.
+ 'xxx': Where 'xxx' is any of the keyword attribute names allowed
+ by section 4.1.1
+
+6.2 job-settable-attributes-supported (1setOf type2 keyword)
+
+
+ This REQUIRED READ-ONLY Printer attribute identifies the Job object
+ attributes that are settable in this implementation, i.e., that are
+ settable using the Set-Job-Attributes operation (see section 4.2).
+ This attribute MUST be supported if the Set-Job-Attributes operations
+ is supported. The Printer MUST reject attempts to set any Job
+ attributes that are not one of the values of this attribute,
+ returning the 'client-error-attributes-not-settable' status code (see
+ section 7.1).
+
+
+ Standard keyword values are:
+
+ 'none': There are no settable Job attributes.
+ 'xxx': Where 'xxx' is any of the keyword attribute names allowed
+ by section 4.2.1.
+
+6.3 document-format-varying-attributes (1setOf type2 keyword)
+
+
+ This OPTIONAL READ-ONLY Printer Description attribute contains a set
+ of attribute name keywords. This attribute SHOULD be supported by a
+ Printer object, if the Printer object has Printer attributes whose
+ value vary depending on document format (see [RFC2911] Get-Printer-
+ Attributes operation). This attribute specifies which attribute
+ values can vary by document-format. If an attribute's name "xxx" is
+ a member of this attribute and the value of attribute "xxx" is
+ changed with the Set-Printer-Attributes operation that included the
+ "document-format" operation attribute, then the Printer MUST change
+ the value for the specified document format and no other document
+ formats (see section 4.1.2). If an attribute's name "xxx" is not a
+ member of this attribute and the value of attribute "xxx" is changed
+ with the Set-Printer-Attributes operation, then the attribute is
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 30]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+ changed for all document formats (whether or not the client supplied
+ the "document-format" operation attribute).
+
+
+6.4 printer-message-time (integer(MIN:MAX))
+
+
+ This OPTIONAL READ-ONLY Printer Description attribute contains the
+ time that the Printer's "printer-message-from-operator" was changed
+ by the operator using any operation where the client supplied the
+ "printer-message-from-operator" operation attribute (see section 5.1)
+ or was explicitly set using the Set-Printer-Attributes operation (see
+ section 4.1). This attribute allows the users to know when the
+ "printer-message-from-operator" attribute was last set.
+
+
+ The Printer sets the value of this attribute by copying the value of
+ the Printer's "printer-up-time" attribute (see [RFC2911] section
+ 4.3.14). If the Printer resets its "printer-up-time" attribute to 1
+ on power-up, then it MUST change the value of the "printer-message-
+ time" to 0 or a negative number as specified in [RFC2911] section
+ 4.3.14.
+
+
+ Note: This attribute helps users better understand the context for
+ the "printer-message-from-operator" message.
+
+
+6.5 printer-message-date-time (dateTime)
+
+
+ This OPTIONAL READ-ONLY Printer Description attribute contains the
+ date and time that the Printer's "printer-message-from-operator" was
+ changed by the operator using any operation where the client supplied
+ the "printer-message-from-operator" operation attribute (see section
+ 5.1) or was explicitly set using the Set-Printer-Attributes operation
+ (see section 4.1). This attribute allows the users to know when the
+ "printer-message-from-operator" attribute was last set.
+
+
+ This attribute MUST be supported if the Printer supports both the
+ "printer-message-time" and the "printer-current-time" (dateTime)
+ attributes (see [RFC2911] section 4.4.30).
+
+
+ Note: This attribute helps users better understand the context for
+ the "printer-message-from-operator" message.
+
+
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 31]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+6.6 printer-xri-supported (1setOf collection)
+
+
+ This OPTIONAL Printer Description attribute is a multi-valued
+ attribute where each value has the 'collection' attribute syntax (see
+ [ipp-coll]) containing member attributes with the same semantics as
+ the following IPP/1.1 READ-ONLY Printer Description attributes,
+ except for cardinality:
+
+ printer-uri-supported (1setOf uri) - see [RFC2911] section
+ 4.4.1
+ uri-authentication-supported (1setOf type2 keyword) - see
+ [RFC2911] section 4.4.2
+ uri-security-supported (1setOf type2 keyword) - see [RFC2911]
+ section 4.4.3
+
+ When setting the "printer-xri-supported" attribute with a Set-
+ Printer-Attributes request, the Printer MUST also set these three
+ IPP/1.1 READ-ONLY Printer Description attributes as a defined side
+ effect. Thus, this collection attribute provides the means to set
+ these three IPP/1.1 READ-ONLY attributes atomically so that they are
+ never left in a partially inconsistent state.
+
+
+ An IPP Printer MUST NOT provide any other way using IPP to set these
+ three IPP/1.1 READ-ONLY Printer Description attributes, since they
+ are READ-ONLY and MUST have consistent values at all times. Note:
+ The "xri-printer-supported" (1setOf collection) attribute can be put
+ into a directory schema that requires a single text string value,
+ such as SLP or LDPA, by using suitable delimiting characters to
+ separate member attributes of the collection and/or terminating
+ collection values. See [svrloc-printer] and [ldap-printer].
+
+
+ The member attributes of the "printer-xri-supported" (1setOf
+ collection) are given in Table 3.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 32]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+ Table 3 - Member attributes of "printer-xri-supported" (1setOf
+ collection)
+
+
+
+ Member attribute client Printer
+ MUST MUST
+ supply support
+
+
+ xri-uri (uri) yes yes
+
+ xri-authentication (1setOf type2 keyword) yes yes
+
+ xri-security (1setOf type2 keyword) yes yes
+
+
+ Each collection value MUST contain a single unique value for the
+ "xri-uri" member attribute. However, the other two member attributes
+ are multi-valued, so that a single URI can support more than one
+ authentication scheme and/or more than one security scheme. Other
+ than the uniqueness and the cardinality requirements, the semantics
+ of these three member attributes is given in [RFC2911] sections
+ 4.4.1, 4.4.2, and 4.4.3, respectively.
+
+
+ A client can query the current values using the Get-Printer-
+ Attributes operation by supplying either:
+
+
+ 1.the three IPP/1.1 attribute names: "printer-uri-supported", "uri-
+ authentication-supported", "uri-security-supported" and getting
+ back the parallel values OR
+
+
+ 2.the single attribute name: "printer-xri-supported" and getting
+ back the 1setOf collection which contains the same information
+ semantically, but in a different form.
+
+
+ A client can query what member attribute values can be set by
+ supplying the three attribute names: "xri-uri-scheme-supported",
+ "xri-authentication-supported", and "xri-security-supported" in a
+ Get-Printer-Supported-Values request and getting back the uriScheme
+ and type2 keyword values that can be set. Since the "printer-xri-
+ supported", "uri-authentication-supported", and "uri-security-
+ supported" attributes are READ-ONLY, they are not queriable with the
+ Get-Printer-Supported-Values operation (see section 4.3). See Table
+ 15.
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 33]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+ When performing a Set-Printer-Attributes operation, if there are
+ multiple values for the "xri-authentication" and/or "xri-security"
+ member attributes, the Printer MUST set the corresponding three READ-
+ ONLY attributes with all possible combinations of values. For
+ example, setting the "printer-xri-supported" with the following two
+ collection values where the first URI has both 'basic' and 'digest'
+ authentication:
+
+
+ "printer-xri-supported =
+ { "xri-uri" = ipp://abc.com/p1
+ "xri-authentication" = basic, digest
+ "xri-security" = tls
+ },
+ { "xri-uri" = http://abc.com/pq
+ "xri-authentication" = none
+ "xri-security" = none
+ }
+
+
+ would cause the Printer to set the three corresponding IPP/1.1 READ-
+ ONLY attributes, each with three parallel values as follows:
+
+
+ "printer-uri-supported" = { ipp://abc.com/p1, ipp://abc.com/p1,
+ http://abc.com/pq }
+ "uri-authentication-supported" = { basic, digest, none }
+ "uri-security-supported" = { tls, tls, none }
+
+
+ Because there were two authentication values for the ipp://abc.com/p1
+ URL, that URL value is repeated. Had the ipp URL had 2
+ authentication values and 3 security values, then there would have
+ been 7 (2*3 + 1) parallel values for each of the three attributes, 6
+ with the same ipp URI and 1 with the http URI.
+
+
+6.7 xri-uri-scheme-supported (1setOf uriScheme)
+
+
+ This OPTIONAL READ-ONLY Printer Description attribute identifies the
+ URI schemes that the implementation supports for use in the "printer-
+ uri-supported" (1setOf uri) Printer Description attribute (see
+ [RFC2911] section 4.4.1) and the "xri-uri" member attribute of the
+ "xri-printer-supported" (1setOf collection) Printer Description
+ attribute (see section 6.6).
+
+
+
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 34]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+ A Printer MUST support this attribute if it supports setting the
+ "printer-xri-supported" (1setOf collection) with the Set-Printer-
+ Attributes operation.
+
+
+6.8 xri-authentication-supported (1setOf type2 keyword)
+
+
+ This OPTIONAL READ-ONLY Printer Description attribute identifies the
+ Client Authentication mechanisms that the implementation supports for
+ use in the "uri-authentication-supported" (1setOf type2 keyword)
+ Printer Description attribute (see [RFC2911] section 4.4.2) and the
+ "xri-authentication" member attribute of the "xri-printer-supported"
+ (1setOf collection) Printer Description attribute (see section 6.6).
+
+
+ A Printer MUST support this attribute if it supports setting the
+ "printer-xri-supported" (1setOf collection) with the Set-Printer-
+ Attributes operation.
+
+
+6.9 xri-security-supported (1setOf type2 keyword)
+
+
+ This OPTIONAL READ-ONLY Printer Description attribute identifies the
+ URI schemes that the implementation supports for use in the "uri-
+ security-supported" (1setOf type2 keyword) Printer Description
+ attribute (see [RFC2911] section 4.4.3) and the "xri-security" member
+ attribute of the "xri-printer-supported" (1setOf collection) Printer
+ Description attribute (see section 6.6).
+
+
+ A Printer MUST support this attribute if it supports setting the
+ "printer-xri-supported" (1setOf collection) with the Set-Printer-
+ Attributes operation.
+
+
+
+7 Additional status codes
+
+ This section defines new status codes used by the operations defined
+ in this document.
+
+7.1 'client-error-attributes-not-settable' (0x0413)
+
+
+ The Set-Printer-Attributes or Set-Job-Attributes operation failed
+ because one or more of the specified attributes cannot be set either
+ because the attribute is defined to be READ-ONLY or the attribute is
+ not settable in this implementation (see sections 4.1.3 and 4.2.3),
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 35]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+ the Printer MUST return this error code and the attribute keyword
+ name(s) and the 'not-settable' out-of-band value (see section 8.1) in
+ the Unsupported Attributes Group(see [RFC2911] section 3.1.7) for all
+ of the attributes that could not be set. When the Printer returns
+ this status, it MUST NOT change any of the attributes supplied in the
+ operation.
+
+
+
+8 Additional out-of-band values
+
+
+ This section defines additional out-of-band values. As with all out-
+ of-band values, a client or a Printer MUST NOT use an out-of-band
+ value unless the definition of the attribute in an operation request
+ and/or response explicitly allows such usage. See the beginning of
+ [RFC2911] section 4.1.
+
+
+8.1 'not-settable' out-of-band value
+
+
+ The 'not-settable' out-of-band attribute value is returned by the IPP
+ Printer in the Unsupported Attributes group of a response to indicate
+ that the attribute supplied by the client in the request is READ-ONLY
+ by definition or is not settable in this implementation.
+
+
+ The 'not-settable' out-of-band attribute value is defined for use
+ with the Set-Job-Attributes and Set-Printer-Attributes response only.
+ If a future additional "set" operation allows the 'not-settable' out-
+ of-band value, its definition document MUST indicate such use
+ explicitly, including with which attributes.
+
+
+ An IPP object MUST support the 'not-settable' out-of-band value in a
+ Set-Job-Attributes or Set-Printer-Attributes request if it supports
+ those operations. A client MUST NOT supply the 'not-settable' out-
+ of-band value in any request. An IPP object MUST NOT support the
+ 'not-settable' out-of-band value in other operations, unless the
+ operations' definition document explicitly defines such usage. If a
+ Printer receives this out-of-band value in any operation request, the
+ Printer MUST either (1) reject the entire request and return the
+ 'client-error-bad-request' status code or (2) ignore the attribute
+ and return it with the 'unsupported' out-of-band value.
+
+
+ See sections 4.1.3 and 4.2.3 in this document for an example
+ definition of the usage of the 'not-settable' out-of-band value in
+ the Set-Printer-Attributes and Set-Job-Attributes responses.
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 36]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+8.1.1 Encoding of the 'not-settable' out-of-band attribute value
+
+
+ The encoding of the 'not-settable' out-of-band value is 0x15 (see
+ [RFC2910]). The value-length MUST be 0 and the value empty.
+
+
+8.2 'delete-attribute' out-of-band value
+
+
+ The 'delete-attribute' out-of-band attribute value is supplied by the
+ client in a request to indicate that the Printer is to remove the
+ supplied attribute and all of its values from the target object, if
+ present.
+
+
+ The 'delete-attribute' out-of-band attribute value is defined for use
+ with the Set-Job-Attributes request only. If a future additional
+ "set" operation allows the 'delete-attribute' out-of-band value, its
+ definition document MUST indicate such use explicitly, including with
+ which attributes.
+
+
+ An IPP Printer MUST support the 'delete-attribute' out-of-band value
+ if it supports the Set-Job-Attributes operation. A client MUST NOT
+ supply and an IPP object MUST NOT support the 'delete-attribute' out-
+ of-band value in other operations, unless the operations' definition
+ document explicitly defines such usage. For example, the 'delete-
+ attribute' out-of-band value MUST NOT be used in the Set-Printer-
+ Attributes operation, where the absence of an attribute from an IPP
+ object indicates that the attribute is not supported. If a Printer
+ receives this out-of-band value in other operation requests, the
+ Printer MUST either (1) reject the entire request and return the
+ 'client-error-bad-request' status code or (2) ignore the attribute
+ and return it with the 'unsupported' out-of-band value.
+
+
+ See section 4.2 in this document for the definition of the usage of
+ the 'delete-attribute' out-of-band value in the Set-Job-Attributes
+ request.
+
+
+8.2.1 Encoding of the 'delete-attribute' out-of-band value
+
+
+ The encoding of the 'delete-attribute' out-of-band value is 0x16 (see
+ [RFC2910]). The value-length MUST be 0 and the value empty.
+
+
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 37]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+8.3 'admin-define' out-of-band attribute value
+
+
+ Section 4.3 defines the Get-Printer-Supported-Values response to
+ contain the values of an "xxx-supported" attribute that are supported
+ by the implementation before any additional value are defined by the
+ administrator. The 'admin-define' out-of-band attribute value is
+ returned as an additional value of an "xxx-supported" attribute in a
+ Get-Printer-Supported-Values response to indicate that the
+ implementation supports allowing an administrator to define
+ additional arbitrary 'name' values for that "xxx-supported"
+ attribute.
+
+
+ For example, if the "media-supported" (1setOf (type3 keyword | name))
+ attribute contains this value, then the Printer MUST permit an
+ administrator to add new media names to the Printer's "media-
+ supported" attribute. In order for an administrator to add new
+ values to a Printer's "xxx-supported" attribute, the client supplies
+ the existing and new values in a Set-Printer-Attributes request for
+ that attribute. The client MUST supply any such administratively
+ defined values in the Set-Printer-Attributes request using the 'name'
+ attribute syntax.
+
+
+ The 'admin-define' out-of-band attribute value is defined for use
+ with the Get-Printer-Supported-Values response only. A Printer MUST
+ NOT return the 'admin-define' out-of-band value in a Get-Printer-
+ Attributes response, since such a response indicates what an end-user
+ client can supply in a Job Creation operation. If a future
+ additional "get" operation allows the 'admin-define' out-of-band
+ value, its definition document MUST indicate such use explicitly,
+ including with which attributes.
+
+
+ An IPP Printer MUST support the 'admin-define' out-of-band value, if
+ it supports a client setting arbitrary 'name' values of an "xxx-
+ supported" Printer attribute using the Set-Printer-Attributes
+ operation. A client MUST NOT supply the 'admin-define' out-of-band
+ value in any request. An IPP object MUST NOT support the 'admin-
+ define' out-of-band value in other operations, unless the operations'
+ definition document explicitly defines such usage. If a Printer
+ receives this out-of-band value in any operation request, the Printer
+ MUST either (1) reject the entire request and return the 'client-
+ error-bad-request' status code or (2) ignore the attribute and return
+ it with the 'unsupported' out-of-band value.
+
+
+ This document defines that the 'admin-define' out-of-band value MUST
+ be used only with "xxx-supported" attributes that are defined to
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 38]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+ include the 'name' attribute syntax. This out-of-band value is not
+ intended to be used with "xxx-supported" attributes of other
+ attribute syntaxes, such as 'uri', even though the administrator
+ defines arbitrary values for such attributes. If other documents
+ extend the use of the 'admin-define' out-of-band value to other
+ attribute syntaxes, such a document MUST define such use explicitly,
+ including with which attributes.
+
+
+ See section 4.3 in this document for an example definition of the
+ usage of the 'admin-define' out-of-band attribute value in any "xxx-
+ supported" attribute returned in a Get-Printer-Supported-Values
+ response that is defined to include the 'name' attribute syntax.
+
+
+8.3.1 Encoding of the 'admin-define' out-of-band attribute value
+
+
+ The encoding of the 'admin-define' out-of-band attribute value is
+ 0x17 (see [RFC2910]). The value-length MUST be 0 and the value
+ empty.
+
+
+
+9 Conformance Requirements
+
+
+ This section specifies the conformance requirements for clients and
+ IPP objects.
+
+
+ Both the Set-Job-Attributes and the Set-Printer-Attributes operations
+ defined in the document are OPTIONAL for an IPP object to support.
+ Either one MAY be supported without the other or both MAY be
+ supported. However, if the Set-Printer-Attributes operation is
+ supported, then the Get-Printer-Supported-Values operation MUST be
+ supported if any "xxx-supported" attributes are settable. Otherwise,
+ the Get-Printer-Supported-Values operation is OPTIONAL for an IPP
+ Printer to support.
+
+
+ If the Set-Printer-Attributes operation is supported, then the
+ Printer MUST support the following additional items:
+
+
+ 1.the Get-Printer-Supported-Values operation (see section 5), if
+ any "xxx-supported" attributes are settable.
+
+
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 39]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+ 2.the "printer-settable-attributes-supported" Printer Description
+ attribute (see section 6.1)
+
+
+ 3.the 'not-settable' out-of-band value in responses (see section
+ 8.1)
+
+
+ 4.the 'client-error-not-settable' status code (see section 7.1)
+
+
+ 5.If "printer-message-from-operator" Printer Description attribute
+ is supported (see [RFC2911] section 4.4.25), then it MUST be
+ settable.
+
+
+ 6.the Get-Printer-Supported-Values operation (see section 4.3), if
+ any "xxx-supported" attributes are settable.
+
+
+ 7.If a client can set a value with the 'name' attribute syntax for
+ one or more "xxx-supported" attributes, then the 'admin-define'
+ out-of-band attribute value (see section 8.3) MUST be supported
+ in the Get-Printer-Supported-Values response for each such
+ settable attribute (see section 4.3)
+
+
+ If the Set-Job-Attributes operation is supported, then the Printer
+ MUST support the following additional items:
+
+
+ 1.the "job-settable-attributes-supported " Printer Description
+ attribute (see section 6.2)
+
+
+ 2.the 'not-settable' out-of-band value in responses (see section
+ 8.1)
+
+
+ 3.the 'delete-attribute' out-of-band value in requests (see
+ section 8.2)
+
+
+ 4.the 'client-error-not-settable' status code (see section 7.1)
+
+
+ 5.If the "job-message-from-operator" Printer Description attribute
+ is supported (see [RFC2911] 4.3.16), then it MUST be settable.
+
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 40]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+ It is OPTIONAL for the Printer object to support the "printer-
+ message-time" (integer) and "printer-message-date-time" (dateTime)
+ Printer Description attributes. If both the "printer-message-time"
+ (integer) and the "printer-current-time" (dateTime) (see [RFC2911]
+ section 4.4.30) attributes are supported, then the "printer-message-
+ date-time" (dateTime) Printer Description attribute MUST be
+ supported.
+
+
+ As with all out-of-band values, a client or a Printer MUST NOT use an
+ out-of-band value unless the definition document for the attribute in
+ an operation request and/or response explicitly allows such usage.
+
+
+
+10 IANA Considerations
+
+ This section contains the exact information for IANA to add to the
+ IPP Registries according to the procedures defined in RFC 2911
+ [RFC2911] section 6.
+
+ Note to RFC Editors: Replace RFC NNNN below with the RFC number for
+ this document, so that it accurately reflects the content of the
+ information for the IANA Registry.
+
+10.1 Operation Registrations
+
+ The operations defined in this document will be published by IANA
+ according to the procedures in RFC 2911 [RFC2911] section 6.4 with
+ the following path:
+
+ ftp.isi.edu/iana/assignments/ipp/operations/
+
+ The registry entry will contain the following information:
+
+ Operations: Ref. Section:
+ Set-Printer-Attributes RFC NNNN 4.1
+ Set-Job-Attributes RFC NNNN 4.2
+ Get-Printer-Supported-Values RFC NNNN 4.3
+
+
+10.2 Attribute Registrations
+
+ The attributes defined in this document will be published by IANA
+ according to the procedures in RFC 2911 [RFC2911] section 6.2 with
+ the following path:
+
+ ftp.isi.edu/iana/assignments/ipp/attributes/
+
+ The registry entry will contain the following information:
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 41]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+
+ Operation attributes: Ref. Section:
+ printer-message-from-operator (text(127)) RFC NNNN 5.1
+ job-message-from-operator (text(127)) RFC NNNN 5.2
+
+ Printer Description attributes: Ref. Section:
+ printer-settable-attributes-supported (1setOf type2 keyword)
+ RFC NNNN 6.1
+ job-settable-attributes-supported (1setOf type2 keyword)
+ RFC NNNN 6.2
+ document-format-varying-attributes (1setOf type2 keyword)
+ RFC NNNN 6.3
+ printer-message-time (integer(MIN:MAX)) RFC NNNN 6.4
+ printer-message-date-time (dateTime) RFC NNNN 6.5
+ printer-xri-supported (1setOf collection) RFC NNNN 6.6
+ xri-uri-scheme-supported (1setOf uriScheme) RFC NNNN 6.7
+ xri-authentication-supported (1setOf type2 keyword) 6.8
+ xri-security-supported (1setOf type2 keyword) RFC NNNN 6.9
+
+
+10.3 Status code Registrations
+
+ The status codes defined in this document will be published by IANA
+ according to the procedures in RFC 2911 [RFC2911] section 6.6 with
+ the following path:
+
+ ftp.isi.edu/iana/assignments/ipp/status-codes/
+
+ The registry entry will contain the following information:
+
+ Status codes: Ref. Section:
+ 'client-error-attributes-not-settable' (0x0413) RFC NNNN 7.1
+
+
+10.4 Out-of-band Attribute Value Registrations
+
+ The out-of-band attribute values defined in this document will be
+ published by IANA according to the procedures in RFC 2911 [RFC2911]
+ section 6.7 with the following path:
+
+ ftp.isi.edu/iana/assignments/ipp/out-of-band-attribute-value-tags/
+
+ The registry entry will contain the following information:
+
+ Out-of-band Attribute Values: Ref. Section:
+ 'not-settable' out-of-band value RFC NNNN 8.1
+ 'delete-attribute' out-of-band value RFC NNNN 8.2
+ 'admin-define' out-of-band attribute value RFC NNNN 8.3
+
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 42]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+11 Internationalization Considerations
+
+ This document has the same localization considerations as the
+ [RFC2911].
+
+
+12 Security Considerations
+
+
+ The IPP Model and Semantics document [RFC2911 section 8] discusses
+ high level security requirements (Client Authentication, Server
+ Authentication and Operation Privacy). Client Authentication is the
+ mechanism by which the client proves its identity to the server in a
+ secure manner. Server Authentication is the mechanism by which the
+ server proves its identity to the client in a secure manner.
+ Operation Privacy is defined as a mechanism for protecting operations
+ from eavesdropping.
+
+
+ In addition, the introduction of the Set-Printer-Attributes and Set-
+ Job-Attributes operations creates another security threat, since the
+ client is able to modify the Printer and Job attributes stored in the
+ Printer. Such modifications could lead to denial of service.
+
+
+ A malicious user could alter the policy established by the system
+ administrator and stored in the Printer attributes. Such alteration
+ could either grant access to more resources or deny access to
+ resources that the system administrator has established. For
+ example, the malicious user could remove all of the document-format
+ values from the "document-format-supported" Printer attribute so that
+ the Printer would refuse to accept all jobs.
+
+
+ The general remedy for such malicious user actions against Printer
+ attributes is to have strong Client Authentication coupled with
+ Printer access control to limit the users who have System
+ Administrator or Operator privileges.
+
+
+ A malicious user could modify the Job Template attributes of another
+ user's Job, such as the "copies" attribute. For example, setting the
+ number of copies to a large number.
+
+
+ The general remedy for such malicious user actions against another
+ user's job is to have strong Client Authentication coupled with
+ Printer access control to limit the users who have System
+ Administrator or Operator privileges who can modify any job and, in
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 43]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+ addition, store the Client Authentication with each Job so that only
+ the job owner End User can modify his/her own job.
+
+
+
+13 Author's Addresses
+
+ Carl Kugler
+ IBM
+ P.O. Box 1900
+ Boulder, CO 80301-9191
+
+ Phone: (303) 924-5060
+ FAX:
+ e-mail: kugler@us.ibm.com
+
+ Tom Hastings
+ Xerox Corporation
+ 737 Hawaii St. ESAE 231
+ El Segundo, CA 90245
+
+ Phone: 310-333-6413
+ Fax: 310-333-5514
+ e-mail: hastings@cp10.es.xerox.com
+
+ Robert Herriot
+ Xerox Corp.
+ 3400 Hill View Ave, Building 1
+ Palo Alto, CA 94304
+
+ Phone: 650-813-7696
+ Fax: 650-813-6860
+ e-mail: robert.herriot@pahv.xerox.com
+
+ Harry Lewis
+ IBM
+ P.O. Box 1900
+ Boulder, CO 80301-9191
+
+ Phone: (303) 924-5337
+ FAX:
+ e-mail: harryl@us.ibm.com
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 44]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+14 References
+
+ [ipp-coll]
+ deBry, R., , Hastings, T., Herriot, R., "Internet Printing Protocol
+ (IPP): The Collection Attribute Syntax", <draft-ietf-ipp-
+ collection-02.doc>, work in progress, March 9, 2000.
+
+ [ipp-set2]
+ Kugler, C, Hastings, T., Lewis, H., "Internet Printing
+ Protocol/1.1: Job and Printer Administrative Operations", <draft-
+ ietf-ipp-ops-set2-01.txt>, December 8, 1999.
+
+ [ldap-printer]
+ Fleming, P., Jones, K., Lewis, H., McDonald, I., "Internet Printing
+ Protocol (IPP): LDAP Schema for Printer Services", <draft-ietf-ipp-
+ ldap-printer-schema-00.txt>, work in progress, March 8, 2000.
+
+ [RFC2565]
+ Herriot, R., Butler, S., Moore, P., Tuner, R., "Internet Printing
+ Protocol/1.0: Encoding and Transport", RFC 2565, April 1999.
+
+ [RFC2566]
+ R. deBry, T. Hastings, R. Herriot, S. Isaacson, P. Powell,
+ "Internet Printing Protocol/1.0: Model and Semantics", RFC 2566,
+ April 1999.
+
+ [RFC2910]
+ Herriot, R., Butler, S., Moore, P., Turner, R., "Internet Printing
+ Protocol/1.1: Encoding and Transport", RFC 2910, September 2000.
+
+ [RFC2911]
+ R. deBry, T. Hastings, R. Herriot, S. Isaacson, P. Powell,
+ "Internet Printing Protocol/1.0: Model and Semantics", RFC 2911,
+ September 2000.
+
+ [svrloc-printer]
+ St. Pierre, P., Isaacson, S., McDonald, I., "Definition of the
+ Printer Abstract Service Type v2.0", <draft-ietf-svrloc-printer-
+ scheme-06.txt>, work in progress, March 8, 2000.
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 45]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+15 Appendix A: Allowed Values for Set-Printer-Attributes and Set-Job-
+ Attributes requests
+
+
+ This appendix is a normative part of this document and contains a
+ table of all IPP/1.1 attributes. Each row contains:
+
+ . an attribute and
+
+ . the values allowed in the Set-Printer-Attributes or Set-Job-
+ Attributes request for the attribute. The entry in each cell is
+ the name (first few words) of each item below 1, 2, 3, 4a-g, and
+ 5.
+
+ The allowed values include the following cases:
+
+ 1.READ-ONLY: the Set-Printer-Attributes or Set-Job-Attributes
+ operation MUST NOT change this attribute and MUST reject the
+ entire operation (see section 7.1).
+
+ 2.Any of "xxx-supported": the Set-Printer-Attributes or Set-Job-
+ Attributes operation accepts values that are allowed according to
+ the IPP/1.1 rules for validating the value(s) of an "xxx" Printer
+ or Job attribute against the value(s) of the corresponding "xxx-
+ supported" Printer attribute. Table 4 summarizes those validation
+ rules depending on each attribute syntax and value of an "xxx"
+ attribute supplied in the request and that of the corresponding
+ "xxx-supported" Printer attribute. The "xxx-supported" attribute
+ syntax type and value(s) are obtained from a Get-Printer-
+ Supported-Values response (see the tables in this Appendix).
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 46]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+ Table 4 - Validation rules for 'Any of "xxx-supported" '
+
+
+
+ Type of "xxx" Type of "xxx- Validates if:
+ value to be supported" value
+ set
+
+
+ integer rangeOfInteger each value is in one of the
+ "xxx-supported" ranges
+
+ uri uriScheme each uri scheme matches one
+ of the "xxx-supported"
+ schemes
+
+ any boolean if the boolean "xxx-
+ supported" is 'true'
+
+ any same type each value matches an "xxx-
+ supported" value of the same
+ type
+
+
+
+ For additional non-normative explanatory information see section
+ 3.1.2.3 of the "Internet Printing Protocol/1.1: Implementer's
+ Guide" [ipp-iig]).
+
+ 3. From Get-Printer-Supported-Values: the Set-Printer-Attributes
+ operation accepts values that are allowed according to the IPP/1.1
+ rules for validating the value(s) of an "xxx" Printer attribute
+ against the value(s) of the corresponding "xxx-supported" Printer
+ attribute. Table 5 summarizes those validation rules depending on
+ each attribute syntax and value of an "xxx" attribute supplied in
+ the request and that of the corresponding "xxx-supported" Printer
+ attribute. The "xxx-supported" attribute syntax type and attribute
+ value(s) are obtained from a Get-Printer-Supported-Values response
+ (see Appendix B: Attributes returned from Get-Printer-Supported-
+ Values below).
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 47]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+ Table 5 - Validation rules for 'From Get-Printer-Supported-Values'
+
+
+
+ Type of Type of "xxx- Validates if:
+ "xxx" supported" value
+ value to
+ be set
+
+
+ integer rangeOfInteger each 'integer' value is in one of
+ the "xxx-supported" ranges
+
+ uri uriScheme the uri scheme of each value
+ matches one of the "xxx-supported"
+ schemes
+
+ any boolean if the boolean "xxx-supported" is
+ 'true'
+
+ name 'admin-define' any 'name' value matches
+ out-of-band
+ value
+
+ any same type each value matches an "xxx-
+ supported" value of the same type
+
+
+
+ For additional non-normative explanatory information see section
+ 3.1.2.3 of the "Internet Printing Protocol/1.1: Implementer's
+ Guide" [ipp-iig]).
+
+ 4. Any value of the proper attribute syntax: the Set-Printer-
+ Attributes or Set-Job-Attributes operation accepts any value of the
+ specified attribute syntax. The attribute syntaxes supported are
+ enumerated below.
+
+ a.Any text(127)
+ b.Any name(127)
+ c.Any uri
+ d.Any boolean
+ e.Any positive integer
+ f.Any dateTime
+ g.1setOf any uri
+
+ 5. Combination of 'Any of "xxx-supported"' or 'Any name'.
+
+
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 48]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+ If a Printer implementation doesn't want to allow setting values
+ indicated in this Appendix as "any xxx", it can make the value be
+ not-settable.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 49]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+ Table 6 - Values allowed for Job Template Attributes in the Set-Job-
+ Attributes Operation
+
+
+
+ Job Template Attributes Values allowed for
+ Set
+
+
+
+
+ job-priority (integer(1:100)) Any of "xxx-
+ supported"
+
+ job-hold-until (type3 keyword | name (MAX)) Any of "xxx-
+ supported"
+
+ job-sheets (type3 keyword | name(MAX)) Any of "xxx-
+ supported"
+
+ multiple-document-handling (type2 keyword) Any of "xxx-
+ supported"
+
+ copies (integer(1:MAX)) Any of "xxx-
+ supported"
+
+ finishings (1setOf type2 enum) Any of "xxx-
+ supported"
+
+ page-ranges (1setOf rangeOfInteger (1:MAX)) Any of "xxx-
+ supported"
+
+ sides (type2 keyword) Any of "xxx-
+ supported"
+
+ number-up (integer(1:MAX)) Any of "xxx-
+ supported"
+
+ orientation-requested (type2 enum) Any of "xxx-
+ supported"
+
+ media (type3 keyword | name(MAX)) Any of "xxx-
+ supported"
+
+ printer-resolution (resolution) Any of "xxx-
+ supported"
+
+ print-quality (type2 enum) Any of "xxx-
+ supported"
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 50]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 51]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+ Table 7 - Values allowed for Job Description Attributes in the Set-
+ Job-Attributes Operation
+
+
+
+ Job Description Attributes Values allowed for
+ Set
+
+
+
+
+ job-uri (uri) READ-ONLY
+
+ job-id (integer(1:MAX)) READ-ONLY
+
+ job-printer-uri (uri) READ-ONLY
+
+ job-more-info (uri) READ-ONLY
+
+ job-name (name(MAX)) Any name(MAX)
+
+ job-originating-user-name (name(MAX)) READ-ONLY
+
+ job-state (type1 enum) READ-ONLY
+
+ job-state-reasons (1setOf type2 keyword) READ-ONLY
+
+ job-state-message (text(MAX)) READ-ONLY
+
+ job-detailed-status-messages (1setOf READ-ONLY
+ text(MAX))
+
+ job-document-access-errors (1setOf READ-ONLY
+ text(MAX))
+
+ number-of-documents (integer(0:MAX)) READ-ONLY
+
+ output-device-assigned (name(127)) READ-ONLY
+
+ time-at-creation (integer(MIN:MAX)) READ-ONLY
+
+ time-at-processing (integer(MIN:MAX)) READ-ONLY
+
+ time-at-completed (integer(MIN:MAX)) READ-ONLY
+
+ job-printer-up-time (integer(1:MAX)) READ-ONLY
+
+ date-time-at-creation (dateTime) READ-ONLY
+
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 52]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+
+
+ Job Description Attributes Values allowed for
+ Set
+
+
+
+
+ date-time-at-processing (dateTime) READ-ONLY
+
+ date-time-at-completed (dateTime) READ-ONLY
+
+ number-of-intervening-jobs (integer(0:MAX)) READ-ONLY
+
+ job-message-from-operator (text(127)) Any text(127)
+
+ job-k-octets (integer(0:MAX)) READ-ONLY
+
+ job-impressions (integer(0:MAX)) READ-ONLY
+
+ job-media-sheets (integer(0:MAX)) READ-ONLY
+
+ job-k-octets-processed (integer(0:MAX)) READ-ONLY
+
+ job-impressions-completed (integer(0:MAX)) READ-ONLY
+
+ job-media-sheets-completed (integer(0:MAX)) READ-ONLY
+
+ attributes-charset (charset) READ-ONLY
+
+ attributes-natural-language READ-ONLY
+ (naturalLanguage)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 53]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+ Table 8 - Values allowed for Printer Job Template Attributes in the
+ Set-Printer-Attributes Operation
+
+
+
+ Printer Job Template Attributes Values allowed
+ for Set
+
+
+ job-priority-default (integer(1:100)) Any of "xxx-
+ supported"
+
+ job-hold-until-default (type3 keyword | name Any of "xxx-
+ (MAX)) supported"
+
+ job-sheets-default (type3 keyword | name(MAX)) Any of "xxx-
+ supported"
+
+ multiple-document-handling-default (type2 Any of "xxx-
+ keyword) supported"
+
+ copies-default (integer(1:MAX)) Any of "xxx-
+ supported"
+
+ finishings-default (1setOf type2 enum) Any of "xxx-
+ supported"
+
+ sides-default (type2 keyword) Any of "xxx-
+ supported"
+
+ number-up-default (integer(1:MAX)) Any of "xxx-
+ supported"
+
+ orientation-requested-default (type2 enum) Any of "xxx-
+ supported"
+
+ media-default (type3 keyword | name(MAX)) Any of "xxx-
+ supported"
+
+ printer-resolution-default (resolution) Any of "xxx-
+ supported"
+
+ print-quality-default (type2 enum) Any of "xxx-
+ supported"
+
+ job-priority-supported (integer(1:100)) From Get-
+ Printer-
+ Supported-Values
+
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 54]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+
+
+ Printer Job Template Attributes Values allowed
+ for Set
+
+
+ job-hold-until-supported (1setOf(type3 keyword From Get-
+ | name (MAX))) Printer-
+ Supported-Values
+
+ job-sheets-supported (1setOf(type3 keyword | From Get-
+ name(MAX))) Printer-
+ Supported-Values
+
+ multiple-document-handling-supported (1setOf From Get-
+ type2 keyword) Printer-
+ Supported-Values
+
+ copies-supported (rangeOfInteger(1:MAX)) From Get-
+ Printer-
+ Supported-Values
+
+ finishings-supported (1setOf type2 enum) From Get-
+ Printer-
+ Supported-Values
+
+ page-ranges-supported (boolean) From Get-
+ Printer-
+ Supported-Values
+
+ sides-supported (1setOf type2 keyword) From Get-
+ Printer-
+ Supported-Values
+
+ number-up-supported (1setOf (integer(1:MAX) | From Get-
+ rangeOfInteger(1:MAX))) Printer-
+ Supported-Values
+
+ orientation-requested-supported (1setOf type2 From Get-
+ enum) Printer-
+ Supported-Values
+
+ media-supported (1setOf (type3 keyword | From Get-
+ name(MAX))) Printer-
+ Supported-Values
+
+ printer-resolution-supported (1setOf From Get-
+ resolution) Printer-
+ Supported-Values
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 55]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+
+
+ Printer Job Template Attributes Values allowed
+ for Set
+
+
+ print-quality-supported (1setOf type2 enum) From Get-
+ Printer-
+ Supported-Values
+
+ media-ready (type3 keyword | name(MAX)) From Get-
+ Printer-
+ Supported-Values
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 56]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+ Table 9 - Values allowed for Printer Description Attributes in the
+ Set-Printer-Attributes Operation
+
+
+
+ Printer Description Attributes Values allowed for
+ Set
+
+
+ printer-uri-supported (1setOf uri) READ-ONLY
+
+ uri-authentication-supported (1setOf type2 READ-ONLY
+ keyword)
+
+ uri-security-supported (1setOf type2 READ-ONLY
+ keyword)
+
+ printer-xri-supported (1setOf collection)
+ member attributes:
+
+ xri-uri (uri) any uriScheme of
+ "xri-uri-scheme-
+ supported" from
+ Get-Printer-
+ Attributes
+
+ xri-authentication (1setOf type2 keyword) any keyword of
+ "xri-
+ authentication-
+ supported" from
+ Get-Printer-
+ Attributes
+
+ xri-security (1setOf type2 keyword) any keyword of
+ "xri-security-
+ supported" from
+ Get-Printer-
+ Attributes
+
+ xri-uri-scheme-supported (1setOf uriScheme) READ-ONLY
+
+ xri-authentication-supported (1setOf type2 READ-ONLY
+ keyword)
+
+ xri-security-supported (1setOf type2 READ-ONLY
+ keyword)
+
+ printer-name (name(127)) Any name(127)
+
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 57]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+
+
+ Printer Description Attributes Values allowed for
+ Set
+
+
+ printer-location (text(127)) Any text(127)
+
+ printer-info (text(127)) Any text(127)
+
+ printer-more-info (uri) Any uri
+
+ printer-driver-installer (uri) Any uri
+
+ printer-make-and-model (text(127)) Any text(127)
+
+ printer-more-info-manufacturer (uri) Any uri
+
+ printer-state (type1 enum) READ-ONLY
+
+ printer-state-reasons (1setOf type2 READ-ONLY
+ keyword)
+
+ printer-state-message (text(MAX)) READ-ONLY
+
+ ipp-versions-supported (1setOf type2 From Get-Printer-
+ keyword) Supported-Values
+
+ operations-supported (1setOf type2 enum) From Get-Printer-
+ Supported-Values
+
+ multiple-document-jobs-supported (boolean) From Get-Printer-
+ Supported-Values
+
+ charset-configured (charset) Any of "xxx-
+ supported", use
+ "charset-supported"
+
+ charset-supported (1setOf charset) From Get-Printer-
+ Supported-Values
+
+ natural-language-configured Any of "xxx-
+ (naturalLanguage) supported", use
+ "generated-natural-
+ language-supported"
+
+ generated-natural-language-supported From Get-Printer-
+ (1setOf naturalLanguage) Supported-Values
+
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 58]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+
+
+ Printer Description Attributes Values allowed for
+ Set
+
+
+ document-format-default (mimeMediaType) Any of "xxx-
+ supported"
+
+ document-format-supported (1setOf From Get-Printer-
+ mimeMediaType) Supported-Values
+
+ printer-is-accepting-jobs (boolean) READ-ONLY
+
+ queued-job-count (integer(0:MAX)) READ-ONLY
+
+ printer-message-from-operator (text(127)) Any text(127)
+
+ color-supported (boolean) From Get-Printer-
+ Supported-Values
+
+ reference-uri-schemes-supported (1setOf From Get-Printer-
+ uriScheme) Supported-Values
+
+ pdl-override-supported (type2 keyword) From Get-Printer-
+ Supported-Values
+
+ printer-up-time (integer(1:MAX)) READ-ONLY
+
+ printer-current-time (dateTime) Any dateTime **
+
+ multiple-operation-time-out any positive
+ (integer(1:MAX)) integer
+
+ compression-supported (1setOf type3 From Get-Printer-
+ keyword) Supported-Values
+
+ job-k-octets-supported From Get-Printer-
+ (rangeOfInteger(0:MAX)) Supported-Values
+
+ job-impressions-supported From Get-Printer-
+ (rangeOfInteger(0:MAX)) Supported-Values
+
+ job-media-sheets-supported From Get-Printer-
+ (rangeOfInteger(0:MAX)) Supported-Values
+
+ pages-per-minute (integer(0:MAX)) READ-ONLY
+
+ pages-per-minute-color (integer(0:MAX)) READ-ONLY
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 59]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+
+
+ Printer Description Attributes Values allowed for
+ Set
+
+
+ printer-settable-attributes-supported From Get-Printer-
+ (1setOf type2 keyword) Supported-Values
+
+ job-settable-attributes-supported (1setOf From Get-Printer-
+ type2 keyword) Supported-Values
+
+ document-format-varying-attributes (1setOf READ-ONLY
+ type2 keyword)
+
+ printer-message-time (integer(MIN:MAX)) READ-ONLY
+
+ printer-message-date-time(dateTime) READ-ONLY
+
+
+ ** - The "printer-current-time" (dateTime) attribute is settable in
+ order to allow an administrator to correct an incorrect dateTime or
+ time zone.
+
+
+16 Appendix B: Attributes returned from Get-Printer-Supported-Values
+
+
+ This Appendix is a normative part of this document and lists all the
+ attributes that are possible for an implementation to return in a
+ Get-Printer-Supported-Values response, i.e., all the "xxx-supported"
+ attributes that can be supplied in a Set-Printer-Attributes request.
+ READ-ONLY attributes MUST NOT be returned in a Get-Printer-Supported-
+ Values response and are indicated in the tables as "READ-ONLY - MUST
+ NOT be returned."
+
+
+ For the following attributes, the value allowed by the Set-Printer-
+ Attributes operation MUST be a single integer value in the range
+ specified by the value returned by the Get-Printer-Supported-Values
+ operation.
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 60]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+ Table 10 - Printer Job Template Attributes returned from Get-Printer-
+ Supported-Values
+
+
+
+ Printer Job Template Attributes Values Returned
+
+
+ job-priority-supported (integer(1:100)) rangeOfInteger(1:100)
+
+
+
+ For the following attributes, the value allowed by the Set-Printer-
+ Attributes operation MUST be a single rangeOfInteger value whose
+ bounds do not exceed those of the range specified by the value
+ returned by the Get-Printer-Supported-Values operation.
+
+ Table 11 - Printer Job Template Attributes returned from Get-Printer-
+ Supported-Values
+
+
+
+ Printer Job Template Attributes Values Returned
+
+
+ copies-supported (rangeOfInteger(1:MAX)) rangeOfInteger(1:MAX)
+
+
+
+
+
+ The following table has the same criteria as the last, but is for
+ Printer Description attributes.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 61]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+ Table 12 - Printer Description Attributes returned from Get-Printer-
+ Supported-Values
+
+
+
+ Printer Description Attributes Values allowed for Set
+
+
+ job-k-octets-supported rangeOfInteger(0:MAX)
+ (rangeOfInteger(0:MAX))
+
+ job-impressions-supported rangeOfInteger(0:MAX)
+ (rangeOfInteger(0:MAX))
+
+ job-media-sheets-supported rangeOfInteger(0:MAX)
+ (rangeOfInteger(0:MAX))
+
+
+
+ For the following attributes, the value allowed by the Set-Printer-
+ Attributes operation MUST be one or more integers and rangeOfInteger
+ values, such that the integer values described by these integers and
+ rangeOfInteger is the same as or a subset of the integers described
+ by the integers and rangeOf Integer of value returned by the Get-
+ Printer-Supported-Values operation.
+
+ Table 13 - Printer Job Template Attributes returned from Get-Printer-
+ Supported-Values
+
+
+
+ Printer Job Template Attributes Values Returned
+
+
+ number-up-supported (1setOf (integer(1:MAX) 1setOf
+ | rangeOfInteger(1:MAX))) (integer(1:MAX) |
+ rangeOfInteger(1:MA
+ X))
+
+
+
+ For the following attributes, the value allowed by the Set-Printer-
+ Attributes operation MUST be one or more values, where each such
+ value matches a value returned by the Get-Printer-Supported-Values
+ operation. A keyword, enum, boolean, charset, naturalLanguage,
+ uriScheme, mimeMediaType or resolution value matches if it is equal.
+ For Job Template attributes with the attribute syntax 'type3 keyword
+ | name', any 'name' attribute syntax value matches the 'admin-define'
+ out-of-band value, if the implementation allows the administrator to
+ set any name values for the attribute.
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 62]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+ Table 14 - Printer Job Template Attributes returned from Get-Printer-
+ Supported-Values
+
+
+
+ Printer Job Template Attributes Values Returned
+
+
+ job-hold-until-supported (1setOf(type3 1setOf (type3
+ keyword | name (MAX))) keyword | 'admin-
+ define')
+
+ job-sheets-supported (1setOf(type3 keyword 1setOf (type3
+ | name(MAX))) keyword | 'admin-
+ define')
+
+ multiple-document-handling-supported 1setOf type2
+ (1setOf type2 keyword) keyword
+
+ finishings-supported (1setOf type2 enum) 1setOf type2 enum
+
+ page-ranges-supported (boolean) 1setOf boolean **
+
+ sides-supported (1setOf type2 keyword) 1setOf type2
+ keyword
+
+ orientation-requested-supported (1setOf 1setOf type2 enum
+ type2 enum)
+
+ media-supported (1setOf (type3 keyword | 1setOf (type3
+ name(MAX))) keyword | 'admin-
+ define')
+
+ printer-resolution-supported (1setOf 1setOf resolution
+ resolution)
+
+ print-quality-supported (1setOf type2 enum) 1setOf type2 enum
+
+
+ ** Note: the Get-Printer-Supported-Values returns a '1setOf boolean'
+ so that all possible values are indicated, while Get-Printer-
+ Attributes returns only a single 'boolean' value.
+
+
+ The following table has the same criteria as the last, but is for
+ Printer Description attributes.
+
+
+
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 63]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+ Table 15 - Printer Description Attributes returned from Get-Printer-
+ Supported-Values
+
+
+
+ Printer Description Attributes Values allowed for
+ Set
+
+
+ printer-uri-supported (1setOf uri) READ-ONLY - MUST
+ NOT be returned
+
+ uri-authentication-supported (1setOf type2 READ-ONLY - MUST
+ keyword) NOT be returned
+
+ uri-security-supported (1setOf type2 READ-ONLY - MUST
+ keyword) NOT be returned
+
+ xri-printer-supported (1setOf collection) MUST NOT be
+ returned; see next
+ three attributes
+ returned with Get-
+ Printer-Attributes:
+
+ xri-uri-scheme-supported (1setOf uriScheme) READ-ONLY - MUST
+ NOT be returned
+
+ xri-authentication-supported (1setOf type2 READ-ONLY - MUST
+ keyword) NOT be returned
+
+ xri-security-supported (1setOf type2 READ-ONLY - MUST
+ keyword) NOT be returned
+
+ ipp-versions-supported (1setOf type2 1setOf type2
+ keyword) keyword
+
+ operations-supported (1setOf type2 enum) 1setOf type2
+ keyword
+
+ multiple-document-jobs-supported (boolean) 1setOf boolean **
+
+ charset-supported (1setOf charset) 1setOf charset
+
+ generated-natural-language-supported 1setOf
+ (1setOf naturalLanguage) naturalLanguage
+
+ document-format-supported (1setOf 1setOf
+ mimeMediaType) mimeMediaType
+
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 64]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+
+
+ Printer Description Attributes Values allowed for
+ Set
+
+
+ color-supported (boolean) 1setOf boolean **
+
+ reference-uri-schemes-supported (1setOf 1setOf uriScheme
+ uriScheme)
+
+ pdl-override-supported (type2 keyword) 1setOf type2
+ keyword **
+
+ compression-supported (1setOf type3 1setOf type3
+ keyword) keyword
+
+ printer-settable-attributes-supported 1setOf type2
+ (1setOf type2 keyword) keyword
+
+ job-settable-attributes-supported (1setOf 1setOf type2
+ type2 keyword) keyword
+
+
+ ** Note: the Get-Printer-Supported-Values returns a '1setOf X' so
+ that all possible values are indicated, while Get-Printer-Attributes
+ returns only a single 'X' value.
+
+
+
+
+17 Appendix C: Full Copyright Statement
+
+
+ Copyright (C) The Internet Society (1998,1999,2000,2001). All Rights
+ Reserved
+
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 65]
+
+
+INTERNET-DRAFT IPP: Job and Printer Set Operations January 22, 2001
+
+
+ followed, or as required to translate it into languages other than
+ English.
+
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Expires: July 22, 2001 [Page 66]
diff --git a/standards/draft-ietf-ipp-job-prog-02.txt b/standards/draft-ietf-ipp-job-prog-02.txt
new file mode 100644
index 000000000..68ac0f577
--- /dev/null
+++ b/standards/draft-ietf-ipp-job-prog-02.txt
@@ -0,0 +1,986 @@
+
+
+
+
+
+
+INTERNET-DRAFT
+<draft-ietf-ipp-job-prog-02.txt> T. Hastings
+Category: standards track Xerox Corporation
+ H. Lewis
+ IBM Printing Company
+ R. Bergman
+ Hitachi Koki Imaging Solutions
+ January 23, 2001
+
+ Internet Printing Protocol (IPP):
+ Job Progress Attributes
+ Copyright (C) The Internet Society (2001). All Rights Reserved.
+
+Status of this Memo:
+ This document is an Internet-Draft and is in full conformance with
+ all provisions of Section 10 of [RFC2026]. Internet-Drafts are
+ working documents of the Internet Engineering Task Force (IETF), its
+ areas, and its working groups. Note that other groups may also
+ distribute working documents as Internet-Drafts.
+
+ Internet-Drafts are draft documents valid for a maximum of six months
+ and may be updated, replaced, or obsoleted by other documents at any
+ time. It is inappropriate to use Internet-Drafts as reference
+ material or to cite them other than as "work in progress".
+
+ The list of current Internet-Drafts can be accessed at
+ http://www.ietf.org/ietf/1id-abstracts.txt
+
+ The list of Internet-Draft Shadow Directories can be accessed as
+ http://www.ietf.org/shadow.html.
+
+Abstract
+ This document defines four new Job Description attributes for
+ monitoring job progress to be registered as extensions to IPP/1.0
+ [RFC2566] and IPP/1.1 [RFC2911]. These attributes are drawn from the
+ PWG Job Monitoring MIB [rfc2707]. The new Job Description attributes
+ are:
+
+ "job-collation-type" (type2 enum)
+ "sheet-completed-copy-number" (integer(0:MAX))
+ "sheet-completed-document-number" (integer(0:MAX))
+ "impressions-completed-current-copy" (integer(0:MAX))
+
+ This document also defines a new "sheet-collate" Job Template
+ attribute to control sheet collation and to help with the
+ interpretation of the job progress attributes. These new attributes
+ may also be used by themselves in combination with the IPP/1.1 "job-
+ impressions-completed" attribute as useful job progress monitoring
+ attributes and/or may be passed in an IPP Notification (see [ipp-
+ ntfy]).
+
+Hastings, Lewis, Bergman Expires July 23, 2001 [page 1]
+
+
+INTERNET-DRAFT IPP: Job Progress Attributes January 23, 2001
+
+
+ The full set of IPP documents includes:
+
+ Design Goals for an Internet Printing Protocol [RFC2567]
+ Rationale for the Structure and Model and Protocol for the Internet
+ Printing Protocol [RFC2568]
+ Internet Printing Protocol/1.1: Model and Semantics [RFC2911]
+ Internet Printing Protocol/1.1: Encoding and Transport [RFC2910]
+ Internet Printing Protocol/1.1: Implementer's Guide [ipp-iig]
+ Mapping between LPD and IPP Protocols [RFC2569]
+ Internet Printing Protocol/1.0 & 1.1: Event Notification
+ Specification [ipp-ntfy]
+ The "Design Goals for an Internet Printing Protocol" document takes a
+ broad look at distributed printing functionality, and it enumerates
+ real-life scenarios that help to clarify the features that need to be
+ included in a printing protocol for the Internet. It identifies
+ requirements for three types of users: end users, operators, and
+ administrators. It calls out a subset of end user requirements that
+ are satisfied in IPP/1.0. A few OPTIONAL operator operations have
+ been added to IPP/1.1.
+
+ The "Rationale for the Structure and Model and Protocol for the
+ Internet Printing Protocol" document describes IPP from a high level
+ view, defines a roadmap for the various documents that form the suite
+ of IPP specification documents, and gives background and rationale
+ for the IETF working group's major decisions.
+
+ The "Internet Printing Protocol/1.1: Model and Semantics" document
+ describes a simplified model with abstract objects, their attributes,
+ and their operations that are independent of encoding and transport.
+ It introduces a Printer and a Job object. The Job object optionally
+ supports multiple documents per Job. It also addresses security,
+ internationalization, and directory issues.
+
+ The "Internet Printing Protocol/1.1: Encoding and Transport" document
+ is a formal mapping of the abstract operations and attributes defined
+ in the model document onto HTTP/1.1 [RFC2616]. It defines the
+ encoding rules for a new Internet MIME media type called
+ "application/ipp". This document also defines the rules for
+ transporting over HTTP a message body whose Content-Type is
+ "application/ipp". This document defines a new scheme named 'ipp'
+ for identifying IPP printers and jobs.
+
+ The "Internet Printing Protocol/1.1: Implementer's Guide" document
+ gives insight and advice to implementers of IPP clients and IPP
+ objects. It is intended to help them understand IPP/1.1 and some of
+ the considerations that may assist them in the design of their client
+ and/or IPP object implementations. For example, a typical order of
+ processing requests is given, including error checking. Motivation
+ for some of the specification decisions is also included.
+
+
+
+Hastings, Lewis, Bergman Expires July 23, 2001 [page 2]
+
+
+INTERNET-DRAFT IPP: Job Progress Attributes January 23, 2001
+
+
+ The "Mapping between LPD and IPP Protocols" document gives some
+ advice to implementers of gateways between IPP and LPD (Line Printer
+ Daemon) implementations.
+
+ The "Event Notification Specification" document defines OPTIONAL
+ operations that allow a client to subscribe to printing related
+ events. Subscriptions include "Per-Job subscriptions" and "Per-
+ Printer subscriptions". Subscriptions are modeled as Subscription
+ objects. Four other operations are defined for subscription objects:
+ get attributes, get subscriptions, renew a subscription, and cancel a
+ subscription.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, Lewis, Bergman Expires July 23, 2001 [page 3]
+
+
+INTERNET-DRAFT IPP: Job Progress Attributes January 23, 2001
+
+
+
+TABLE OF CONTENTS
+
+ 1 New Job Template attribute......................................5
+ 1.1 sheet-collate (type2 keyword) ................................5
+
+ 2 IPP Job Description attributes for monitoring Job Progress......8
+ 2.1 job-collation-type (type2 enum) .............................11
+ 2.2 sheet-completed-copy-number (integer(0:MAX)) ................12
+ 2.3 sheet-completed-document-number (integer(0:MAX)) ............13
+ 2.4 impressions-completed-current-copy (integer(0:MAX)) .........13
+
+ 3 Conformance Requirements.......................................13
+
+ 4 IANA Considerations............................................13
+ 4.1 Attribute Registrations .....................................14
+
+ 5 Internationalization Considerations............................14
+
+ 6 Security Considerations........................................14
+
+ 7 References.....................................................15
+
+ 8 Author's Addresses.............................................16
+
+ 9 Full Copyright Statement.......................................16
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, Lewis, Bergman Expires July 23, 2001 [page 4]
+
+
+INTERNET-DRAFT IPP: Job Progress Attributes January 23, 2001
+
+
+
+
+
+
+1 New Job Template attribute
+
+
+1.1 sheet-collate (type2 keyword)
+
+ +===================+======================+=====================+
+ | Job Attribute |Printer: Default Value| Printer: Supported |
+ | | Attribute | Values Attribute |
+ +===================+======================+=====================+
+ | sheet-collate | sheet-collate-default| sheet-collate- |
+ | (type2 keyword) | (type2 keyword) | supported (1setOf |
+ | | | type2 keyword) |
+ +-------------------+----------------------+---------------------+
+ This attribute specifies whether or not the media sheets of each copy
+ of each printed document in a job are to be in sequence, when
+ multiple copies of the document are specified by the 'copies'
+ attribute.
+
+ Standard keyword values are:
+
+ 'uncollated': each print-stream sheet is printed a number of times
+ in succession equal to the value of the 'copies' attribute,
+ followed by the next print-stream sheet.
+
+ 'collated': each copy of each document is printed with the print-
+ stream sheets in sequence, followed by the next document copy.
+
+ For example, suppose a document produces two media sheets as output,
+ and "copies" is equal to '6', For the 'uncollated' case, six copies
+ of the first media sheet are printed followed by six copies of the
+ second media sheet. For the 'collated' case, one copy of each of the
+ six sheets are printed followed by another copy of each of the six
+ media sheets.
+
+ Whether the effect of sheet collation is achieved by placing copies
+ of a document in multiple output bins or in the same output bin with
+ implementation defined document separation is implementation
+ dependent. Also whether it is achieved by making multiple passes
+ over the job or by using an output sorter is implementation
+ dependent.
+
+ Note: IPP/1.0 [RFC2566] and IPP/1.1 [RFC2911] is silent on whether
+ or not sheets within documents are collated. The "sheet-collate-
+ supported" Printer attribute permits a Printer object to indicate
+ whether or not it collates sheets with each document and whether it
+ allows the client to control sheet collation. An implementation is
+
+
+Hastings, Lewis, Bergman Expires July 23, 2001 [page 5]
+
+
+INTERNET-DRAFT IPP: Job Progress Attributes January 23, 2001
+
+
+ able to indicate that it supports uncollated sheets, collated sheets,
+ or both, using the 'uncollated', 'collated', or both 'uncollated' and
+ 'collated' values, respectively.
+
+ This attribute is affected by "multiple-document-handling." The
+ "multiple-document-handling" attribute describes the collation of
+ documents, and the "sheet-collate" attribute describes the semantics
+ of collating individual pages within a document. To better explain
+ the interaction between these two attributes the term "set" is
+ introduced. A "set" is a logical boundary between the delivered
+ media sheets of a printed job. For-example, in the case of a ten
+ page single document with collated pages and a request for 50 copies,
+ each of the 50 printed copies of the document constitutes a "set."
+ In the above example if the pages were uncollated, then 50 copies of
+ each of the individual pages within the document would represent each
+ "set".
+
+ The following table describes the interaction of "sheet-collate" with
+ multiple document handling.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, Lewis, Bergman Expires July 23, 2001 [page 6]
+
+
+INTERNET-DRAFT IPP: Job Progress Attributes January 23, 2001
+
+
+
+
+ "sheet- "multiple- Semantics
+ collate" document-
+ handling"
+
+
+ 'collated' 'single- Each copy of the concatenated
+ document' documents, with their pages in
+ sequence, represents a "set."
+
+ 'collated' 'single- Each copy of the concatenated
+ document-new- documents, with their pages in
+ sheet' sequence, represents a "set."
+
+ 'collated' 'separate- Each copy of each separate
+ documents- document, with its pages in
+ collated- sequence, represents a "set."
+ copies'
+
+ 'collated' 'separate- Each copy of each separate
+ documents- document, with its pages in
+ uncollated- sequence, represents a "set."
+ copies
+
+ 'uncollated' 'single- Each media sheet of the document
+ document' is printed a number of times equal
+ to the "copies" attribute; which
+ constitutes a "set."
+
+ 'uncollated' 'single- Each media sheet of the
+ document-new- concatenated documents is printed
+ sheet' a number of times equal to the
+ "copies" attribute; which
+ constitutes a "set."
+
+ 'uncollated' 'separate- This is a degenerate case, and the
+ documents- printer object MUST reject the job
+ collated- and return the status, "client-
+ copies' error-conflicting-attributes."
+
+ 'uncollated' 'separate- This is a degenerate case, and the
+ documents- printer object MUST reject the job
+ uncollated- and return the status "client-
+ copies error-conflicting-attributes."
+
+
+
+ From the above table it is obvious that the implicit value of the
+ "sheet-collate" attribute in a printer that does not support the
+
+
+Hastings, Lewis, Bergman Expires July 23, 2001 [page 7]
+
+
+INTERNET-DRAFT IPP: Job Progress Attributes January 23, 2001
+
+
+ "sheet-collate" attribute, is 'collated.' The semantics of
+ "multiple-document-handling" are otherwise nonsensical in the case
+ of separate documents.
+
+
+
+2 IPP Job Description attributes for monitoring Job Progress
+
+ The following IPP Job Description attributes are proposed to be added
+ to IPP through the type2 registration procedures. They are useful
+ for monitoring the progress of a job. They are also used at
+ attributes in the notification content in a notification report [ipp-
+ ntfy].
+
+ There are a number of Job Description attributes for monitoring the
+ progress of a job. These objects and attributes count the number of
+ K octets, impressions, sheets, and pages requested or completed. For
+ impressions and sheets, "completed" means stacked, unless the
+ implementation is unable to detect when each sheet is stacked, in
+ which case stacked is approximated when processing of each sheet
+ completes. There are objects and attributes for the overall job and
+ for the current copy of the document currently being stacked. For
+ the latter, the rate at which the various objects and attributes
+ count depends on the sheet and document collation of the job.
+
+ Consider the following four Job Description attributes that are used
+ to monitor the progress of a job's impressions:
+
+ 1."job-impressions-completed" - counts the total number of
+ impressions stacked for the job (see [RFC2911] section 4.3.18.2)
+
+ 2."impressions-completed-current-copy" - counts the number of
+ impressions stacked for the current document copy
+
+ 3."sheet-completed-copy-number" - identifies the number of the
+ copy for the current document being stacked where the first copy
+ is 1.
+
+ 4."sheet-completed-document-number" - identifies the current
+ document within the job that is being stacked where the first
+ document in a job is 1. NOTE: this attribute SHOULD NOT be
+ implemented for implementations that only support one document
+ per job.
+
+ For each of the three types of job collation, a job with three copies
+ of two documents (1, 2), where each document consists of 3
+ impressions, the four variables have the following values as each
+ sheet is stacked for one-sided printing:
+
+
+
+
+Hastings, Lewis, Bergman Expires July 23, 2001 [page 8]
+
+
+INTERNET-DRAFT IPP: Job Progress Attributes January 23, 2001
+
+
+
+"job-collation-type" = 'uncollated-sheets(3)'
+
+
+"job- "impressions- "sheet- "sheet-
+impressions- completed- completed- completed-
+completed" current-copy" copy-number" document-
+ number"
+
+ 0 0 0 0
+ 1 1 1 1
+ 2 1 2 1
+ 3 1 3 1
+ 4 2 1 1
+ 5 2 2 1
+ 6 2 3 1
+ 7 3 1 1
+ 8 3 2 1
+ 9 3 3 1
+ 10 1 1 2
+ 11 1 2 2
+ 12 1 3 2
+ 13 2 1 2
+ 14 2 2 2
+ 15 2 3 2
+ 16 3 1 2
+ 17 3 2 2
+ 18 3 3 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, Lewis, Bergman Expires July 23, 2001 [page 9]
+
+
+INTERNET-DRAFT IPP: Job Progress Attributes January 23, 2001
+
+
+
+"job-collation-type" = 'collated-documents(4)'
+
+
+ "job- "impressions- "sheet- "sheet-
+ impressions- completed- completed- completed-
+ completed" current-copy" copy- document-
+ number" number"
+
+
+ 0 0 0 0
+ 1 1 1 1
+ 2 2 1 1
+ 3 3 1 1
+ 4 1 1 2
+ 5 2 1 2
+ 6 3 1 2
+ 7 1 2 1
+ 8 2 2 1
+ 9 3 2 1
+ 10 1 2 2
+ 11 2 2 2
+ 12 3 2 2
+ 13 1 3 1
+ 14 2 3 1
+ 15 3 3 1
+ 16 1 3 2
+ 17 2 3 2
+ 18 3 3 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, Lewis, Bergman Expires July 23, 2001 [page 10]
+
+
+INTERNET-DRAFT IPP: Job Progress Attributes January 23, 2001
+
+
+
+"job-collation-type" = 'uncollated-documents(5)'
+
+ "job- "impressions- "sheet- "sheet-
+ impressions- completed- completed- completed-
+ completed" current-copy" copy- document-
+ number" number"
+
+
+ 0 0 0 0
+ 1 1 1 1
+ 2 2 1 1
+ 3 3 1 1
+ 4 1 2 1
+ 5 2 2 1
+ 6 3 2 1
+ 7 1 3 1
+ 8 2 3 1
+ 9 3 3 1
+ 10 1 1 2
+ 11 2 1 2
+ 12 3 1 2
+ 13 1 2 2
+ 14 2 2 2
+ 15 3 2 2
+ 16 1 3 2
+ 17 2 3 2
+ 18 3 3 2
+
+
+
+2.1 job-collation-type (type2 enum)
+
+ Job Collation includes sheet collation and document collation. Sheet
+ collation is defined to be the ordering of sheets within a document
+ copy. Document collation is defined to be ordering of document
+ copies within a multi-document job. The value of the "job-collation-
+ type" is affected by the value of the "sheet-collate" Job Template
+ attribute (see section 1.1), if supplied and supported.
+
+ The Standard enum values are:
+
+ '1' 'other': not one of the defined values
+
+ '2' 'unknown': the collation type is unknown
+
+ '3' 'uncollated-sheets': No collation of the sheets within each
+ document copy, i.e., each sheet of a document that is
+ to produce multiple copies is replicated before the
+ next sheet in the document is processed and stacked.
+
+
+Hastings, Lewis, Bergman Expires July 23, 2001 [page 11]
+
+
+INTERNET-DRAFT IPP: Job Progress Attributes January 23, 2001
+
+
+ If the device has an output bin collator, the
+ 'uncollated-sheets(3)' value may actually produce
+ collated sheets as far as the user is concerned (in
+ the output bins). However, when the job collation is
+ the 'uncollated-sheets(3)' value, job progress is
+ indistinguishable to a monitoring application between
+ a device that has an output bin collator and one that
+ does not.
+
+ '4' 'collated-documents': Collation of the sheets within each
+ document copy is performed within the printing device
+ by making multiple passes over either the source or
+ an intermediate representation of the document. In
+ addition, when there are multiple documents per job,
+ the i'th copy of each document is stacked before the
+ j'th copy of each document, i.e., the documents are
+ collated within each job copy. For example, if a job
+ is submitted with documents, A and B, the job is made
+ available to the end user as: A, B, A, B, .... The
+ 'collated-documents(4)' value corresponds to the IPP
+ [RFC2911] 'separate-documents-collated-copies'
+ keyword value of the "multiple-document-handling"
+ attribute.
+
+ If the job's "copies" attribute is '1' (or not
+ supplied), then the "job-collation-type" attribute is
+ defined to be '4'.
+
+
+ '5' 'uncollated-documents': Collation of the sheets within each
+ document copy is performed within the printing device
+ by making multiple passes over either the source or
+ an intermediate representation of the document. In
+ addition, when there are multiple documents per job,
+ all copies of the first document in the job are
+ stacked before the any copied of the next document in
+ the job, i.e., the documents are uncollated within
+ the job. For example, if a job is submitted with
+ documents, A and B, the job is mad available to the
+ end user as: A, A, ..., B, B, .... The 'uncollated-
+ documents(5)' value corresponds to the IPP [RFC2911]
+ 'separate-documents-uncollated-copies' keyword value
+ of the "multiple-document-handling" attribute.
+
+2.2 sheet-completed-copy-number (integer(0:MAX))
+
+ The number of the copy being stacked for the current document. This
+ number starts at 0, is set to 1 when the first sheet of the first
+ copy for each document is being stacked and is equal to n where n is
+ the nth sheet stacked in the current document copy. If the value is
+
+
+Hastings, Lewis, Bergman Expires July 23, 2001 [page 12]
+
+
+INTERNET-DRAFT IPP: Job Progress Attributes January 23, 2001
+
+
+ unknown, the Printer MUST return the 'unknown' out-of-band value (see
+ [RFC2911] section 4.1), rather than the -2 value used in some MIBs
+ [rfc2707].
+
+
+2.3 sheet-completed-document-number (integer(0:MAX))
+
+ The ordinal number of the document in the job that is currently being
+ stacked. This number starts at 0, increments to 1 when the first
+ sheet of the first document in the job is being stacked, and is equal
+ to n where n is the nth document in the job, starting with 1. If the
+ value is unknown, the Printer MUST return the 'unknown' out-of-band
+ value (see [RFC2911] section 4.1), rather than the -2 value used in
+ some MIBs [rfc2707].
+
+ Implementations that only support one document jobs SHOULD NOT
+ implement this attribute.
+
+
+2.4 impressions-completed-current-copy (integer(0:MAX))
+
+ The number of impressions completed by the device for the current
+ copy of the current document so far. For printing, the impressions
+ completed includes interpreting, marking, and stacking the output.
+ For other types of job services, the number of impressions completed
+ includes the number of impressions processed. If the value is
+ unknown, the Printer MUST return the 'unknown' out-of-band value (see
+ [RFC2911] section 4.1), rather than the -2 value used in some MIBs
+ [rfc2707].
+
+ This value SHALL be reset to 0 for each document in the job and for
+ each document copy.
+
+
+
+3 Conformance Requirements
+
+ This section summarizes the Conformance Requirements detailed in the
+ definitions in this document. In general each of the attributes
+ defined in this document are OPTIONAL for a Printer to support, so
+ that Printer implementers MAY implement any combination of
+ attributes.
+
+
+
+4 IANA Considerations
+
+ This section contains the exact information for IANA to add to the
+ IPP Registries according to the procedures defined in RFC 2911
+ [RFC2911] section 6.
+
+
+Hastings, Lewis, Bergman Expires July 23, 2001 [page 13]
+
+
+INTERNET-DRAFT IPP: Job Progress Attributes January 23, 2001
+
+
+ Note to RFC Editors: Replace RFC NNNN below with the RFC number for
+ this document, so that it accurately reflects the content of the
+ information for the IANA Registry.
+
+
+4.1 Attribute Registrations
+
+ The attributes defined in this document will be published by IANA
+ according to the procedures in RFC 2911 [RFC2911] section 6.2 with
+ the following path:
+
+ ftp.isi.edu/iana/assignments/ipp/attributes/
+
+ The registry entry will contain the following information:
+
+ Job Template attributes: Ref. Section:
+ sheet-collate (type2 keyword) RFC NNNN 1.1
+
+ Job Description attributes: Ref. Section:
+ job-collation-type (type2 enum) RFC NNNN 2.1
+ sheet-completed-copy-number (integer(0:MAX)) RFC NNNN 2.2
+ sheet-completed-document-number (integer(0:MAX))RFC NNNN 2.3
+ impressions-completed-current-copy (integer(0:MAX))
+ RFC NNNN 2.4
+
+
+
+
+5 Internationalization Considerations
+
+ The IPP extensions defined in this document require the same
+ internationalization considerations as any of the Job Template and
+ Job Descriptions attributes defined in IPP/1.1 [RFC2911].
+
+
+
+6 Security Considerations
+
+ The IPP extensions defined in this document require the same security
+ considerations as any of the Job Template attributes and Job
+ Descriptions attributes defined in IPP/1.1 [RFC2911].
+
+
+
+
+
+
+
+
+
+
+
+Hastings, Lewis, Bergman Expires July 23, 2001 [page 14]
+
+
+INTERNET-DRAFT IPP: Job Progress Attributes January 23, 2001
+
+
+7 References
+
+ [ipp-iig]
+
+ Hastings, T., Manros, C., "Internet Printing Protocol/1.1: draft-
+ ietf-ipp-implementers-guide-v11-01.txt, work in progress, May 9,
+ 2000.
+
+ [ipp-ntfy]
+
+ Isaacson, S., Martin, J., deBry, R., Hastings, T., Shepherd, M.,
+ Bergman, R., " IPP Event Notification Specification", <draft-ietf-
+ ipp-not-spec-04.txt>, work in progress, August 30, 2000.
+
+ [RFC2565]
+
+ Herriot, R., Butler, S., Moore, P., Tuner, R., "Internet Printing
+ Protocol/1.0: Encoding and Transport", RFC 2565, April 1999.
+
+ [RFC2566]
+
+ deBry, R., , Hastings, T., Herriot, R., Isaacson, S., Powell, P.,
+ "Internet Printing Protocol/1.0: Model and Semantics", RFC 2566,
+ April 1999.
+
+ [RFC2567]
+
+ Wright, D., "Design Goals for an Internet Printing Protocol", RFC
+ 2567, April 1999.
+
+ [RFC2568]
+
+ Zilles, S., "Rationale for the Structure and Model and Protocol for
+ the Internet Printing Protocol", RFC 2568, April 1999.
+
+ [RFC2569]
+
+ Herriot, R., Hastings, T., Jacobs, N., Martin, J., "Mapping between
+ LPD and IPP Protocols", RFC 2569, April 1999.
+
+ [RFC2707]
+
+ Bergman, R., Hastings, T., Isaacson, S., Lewis, H. "PWG Job
+ Monitoring MIB - V1", RFC 2707, November, 1999.
+
+ [RFC2910]
+
+ Herriot, R., Butler, S., Moore, P., Tuner, R., "Internet Printing
+ Protocol/1.1: Encoding and Transport", RFC 2910, September, 2000.
+
+
+
+Hastings, Lewis, Bergman Expires July 23, 2001 [page 15]
+
+
+INTERNET-DRAFT IPP: Job Progress Attributes January 23, 2001
+
+
+ [RFC2911]
+
+ deBry, R., , Hastings, T., Herriot, R., Isaacson, S., Powell, P.,
+ "Internet Printing Protocol/1.1: Model and Semantics", RFC 2911,
+ September, 2000.
+
+
+
+8 Author's Addresses
+
+
+ Tom Hastings
+ Xerox Corporation
+ 737 Hawaii St. ESAE 231
+ El Segundo, CA 90245
+ Phone: 310-333-6413
+ Fax: 310-333-5514
+ e-mail: hastings@cp10.es.xerox.com
+
+
+
+ Harry Lewis
+ IBM
+ P.O. Box 1900
+ Boulder, CO 80301-9191
+
+ Phone: (303) 924-5337
+ FAX:
+ e-mail: harryl@us.ibm.com
+
+
+ Ron Bergman (Editor)
+ Hitachi Koki Imaging Solutions
+ 1757 Tapo Canyon Road
+ Simi Valley, CA 93063-3394
+
+ Phone: 805-578-4421
+ Fax: 805-578-4001
+ Email: rbergma@hitachi-hkis.com
+
+
+
+9 Full Copyright Statement
+
+ Copyright (C) The Internet Society (2001). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+
+
+Hastings, Lewis, Bergman Expires July 23, 2001 [page 16]
+
+
+INTERNET-DRAFT IPP: Job Progress Attributes January 23, 2001
+
+
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, Lewis, Bergman Expires July 23, 2001 [page 17]
diff --git a/standards/draft-ietf-ipp-ldap-printer-schema-04.txt b/standards/draft-ietf-ipp-ldap-printer-schema-04.txt
new file mode 100644
index 000000000..583fa1675
--- /dev/null
+++ b/standards/draft-ietf-ipp-ldap-printer-schema-04.txt
@@ -0,0 +1,1456 @@
+
+
+Internet Printing Protocol Working Group Pat Fleming
+INTERNET DRAFT IBM
+Expires 20 June 2001 Ken Jones
+ eStarCom
+[Target Category: Standards Track] Harry Lewis
+ IBM
+ Ira McDonald
+ High North Inc
+ 20 December 2000
+
+ Internet Printing Protocol (IPP):
+ LDAP Schema for Printer Services
+ <draft-ietf-ipp-ldap-printer-schema-04.txt>
+
+ Copyright (C) The Internet Society (2000). All Rights Reserved.
+
+Status of This Memo
+
+ This document is an Internet-Draft and is in full conformance with
+ all provisions of Section 10 of RFC 2026. Internet-Drafts are
+ working documents of the Internet Engineering Task Force (IETF), its
+ areas, and its working groups. Note that other groups may also
+ distribute working documents as Internet-Drafts.
+
+ Internet-Drafts are draft documents valid for a maximum of six months
+ and may be updated, replaced, or obsoleted by other documents at any
+ time. It is inappropriate to use Internet-Drafts as reference
+ material or to cite them other than as "work in progress."
+
+ To view the list of Internet-Draft Shadow Directories, see
+ http://www.ietf.org/shadow.html.
+
+Abstract
+
+ This document is a product of the Internet Printing Protocol Working
+ Group, chartered by the IETF. Comments should be sent to the
+ ipp@pwg.org mailing list and the principal editor
+ flemingp@us.ibm.com.
+
+ This document defines a common printer schema for use with directory
+ services that support the Lightweight Directory Access Protocol
+ (LDAP) [RFC 2251]. Using this common printer schema enables client
+ applications to use LDAP to search for printers using application or
+ user specified search criteria. Searches are defined based on the
+ entry's type and attributes independent of the LDAP directory being
+ used.
+
+ This document describes the LDAP schema, object classes and
+ attributes, for printers and printer services. This document uses
+ the printer attributes defined in Appendix E of [RFC 2911], the
+ 'printer:' service template defined in [SLPPRT], and the mapping
+ between SLP service advertisements and LDAP descriptions of services
+
+Fleming, Jones, Lewis, McDonald Expires 20 June 2001 [Page 1]
+
+Internet Draft LDAP Schema for Printer Services 20 December 2000
+
+ defined in [RFC 2926] to define an LDAP printer schema.
+
+ The goal of this document is to define a consistent schema to be used
+ by printers and print servers. The LDAP printer schema described in
+ this document MAY be used in part or whole.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Fleming, Jones, Lewis, McDonald Expires 20 June 2001 [Page 2]
+
+Internet Draft LDAP Schema for Printer Services 20 December 2000
+
+ Table of Contents
+
+1. Introduction ............................................... 5
+2. Terminology ................................................ 5
+3. Definition of Object Classes ............................... 6
+ 3.1. slpServicePrinter ...................................... 7
+ 3.2. printerAbstract ........................................ 7
+ 3.3. printerService ......................................... 8
+ 3.4. printerServiceAuxClass ................................. 8
+ 3.5. printerIPP ............................................. 9
+ 3.6. printerLPR ............................................. 9
+4. Definition of Attribute Types .............................. 10
+ 4.1. printer-uri ............................................ 11
+ 4.2. printer-xri-supported .................................. 11
+ 4.3. printer-name ........................................... 12
+ 4.4. printer-natural-language-configured .................... 13
+ 4.5. printer-location ....................................... 13
+ 4.6. printer-info ........................................... 13
+ 4.7. printer-more-info ...................................... 14
+ 4.8. printer-make-and-model ................................. 14
+ 4.9. printer-ipp-versions-supported ......................... 14
+ 4.10. printer-multiple-document-jobs-supported .............. 15
+ 4.11. printer-charset-configured ............................ 15
+ 4.12. printer-charset-supported ............................. 15
+ 4.13. printer-generated-natural-language-supported .......... 16
+ 4.14. printer-document-format-supported ..................... 16
+ 4.15. printer-color-supported ............................... 16
+ 4.16. printer-compression-supported ......................... 16
+ 4.17. printer-pages-per-minute .............................. 17
+ 4.18. printer-pages-per-minute-color ........................ 17
+ 4.19. printer-finishings-supported .......................... 17
+ 4.20. printer-number-up-supported ........................... 18
+ 4.21. printer-sides-supported ............................... 18
+ 4.22. printer-media-supported ............................... 18
+ 4.23. printer-media-local-supported ......................... 18
+ 4.24. printer-resolution-supported .......................... 19
+ 4.25. printer-print-quality-supported ....................... 19
+ 4.26. printer-job-priority-supported ........................ 19
+ 4.27. printer-copies-supported .............................. 20
+ 4.28. printer-job-k-octets-supported ........................ 20
+ 4.29. printer-current-operator .............................. 20
+ 4.30. printer-service-person ................................ 20
+ 4.31. printer-delivery-orientation-supported ................ 21
+ 4.32. printer-stacking-order-supported ...................... 21
+ 4.33. printer-output-features-supported ..................... 21
+ 4.34. printer-aliases ....................................... 22
+5. Definition of Syntaxes ..................................... 23
+6. IANA Considerations ........................................ 23
+7. Internationalization Considerations ........................ 23
+8. Security Considerations .................................... 23
+9. References ................................................. 23
+
+Fleming, Jones, Lewis, McDonald Expires 20 June 2001 [Page 3]
+
+Internet Draft LDAP Schema for Printer Services 20 December 2000
+
+10. Acknowledgments ........................................... 24
+11. Authors' Addresses ........................................ 25
+12. Full Copyright Statement .................................. 26
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Fleming, Jones, Lewis, McDonald Expires 20 June 2001 [Page 4]
+
+Internet Draft LDAP Schema for Printer Services 20 December 2000
+
+
+
+1. Introduction
+
+ The use of directory services based on the Lightweight Directory
+ Access Protocol [RFC 2251] is becoming increasingly popular for
+ distributed services. To ensure interoperability between vendor
+ implementations it is crucial to standardize the schemas which
+ describe these services.
+
+ Under the auspices of the IETF IPP Working Group the IPP protocol is
+ being developed to bring a standards based printing solution to the
+ Internet.
+
+ Section 16 of [RFC 2911] describes a list of attributes which should
+ be included in a general directory schema describing IPP print
+ services. The syntax for each of these attributes is described in
+ detail in [RFC 2911] and [SLPPRT]. This document will take these
+ attributes and map them to LDAP attributes and object classes.
+
+ This document defines several object classes to provide LDAP
+ applications with multiple options in defining printer information
+ using LDAP schema. Classes are provided for defining directory
+ entries with common printer information and for extending existing
+ directory entries with SLP, IPP, and LPR specific information.
+
+
+
+
+2. Terminology
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+ document are to be interpreted as described in [RFC 2119].
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Fleming, Jones, Lewis, McDonald Expires 20 June 2001 [Page 5]
+
+Internet Draft LDAP Schema for Printer Services 20 December 2000
+
+
+
+3. Definition of Object Classes
+
+ We define the following LDAP object classes for use with both generic
+ printer related information and services specific to SLP, IPP, and
+ LPR.
+
+ slpServicePrinter - auxiliary class for SLP registered printers
+ printerAbstract - abstract class for all printer classes
+ printerService - structural class for printers
+ printerServiceAuxClass - auxiliary class for printers
+ printerIPP - auxiliary class for IPP printers
+ printerLPR - auxiliary class for LPR printers
+
+ The following are some examples of how applications MAY choose to use
+ these classes when creating directory entries:
+
+ 1) Use printerService for directory entries containing common printer
+ information.
+
+ 2) Use both printerService and slpServicePrinter for directory
+ entries containing common printer information for SLP registered
+ printers.
+
+ 3) Use printerService, printerLPR and printerIPP for directory
+ entries containing common printer information for printers that
+ support both LPR and IPP.
+
+ 4) Use printerServiceAuxClass and object classes not defined by this
+ document for directory entries containing common printer information.
+ In this example, printerServiceAuxClass is used for extending other
+ structural classes defining printer information with common printer
+ information defined in this document.
+
+ Note that specifying the abstract object class printerAbstract is
+ OPTIONAL when using printerService or printerServiceAuxClass to
+ create directory entries per [RFC 2251].
+
+ Refer to section 4 for definition of attribute types referenced by
+ these object classes. We use names instead of OIDs in MUST and MAY
+ for clarity. Some attribute names described in [RFC 2911] have been
+ prefixed with 'printer-' as recommended in [SLPPRT] and [RFC 2926].
+
+ For the object classes defined in this section, schema developers MAY
+ add to the list of MAY OIDs, but MUST NOT modify the list of MUST
+ OIDs and MUST NOT remove OIDs from the list of MAY OIDs. Schema
+ developers MAY derive additional classes from the abstract and
+ structural classes defined in this section. Note, an object class
+ definition SHOULD NOT be changed without having a new name and OID
+ assigned to it.
+
+Fleming, Jones, Lewis, McDonald Expires 20 June 2001 [Page 6]
+
+Internet Draft LDAP Schema for Printer Services 20 December 2000
+
+
+
+
+3.1. slpServicePrinter
+
+ This auxiliary class defines Service Location Protocol (SLP) specific
+ information. It MUST be used with a structural class such as
+ printerService. It MAY be used to create new or extend existing
+ directory entries with SLP 'service:printer' abstract service type
+ information as defined in [SLPPRT]. This object class is derived
+ from 'slpService', the parent class for all SLP services, defined in
+ [RFC 2926].
+
+ ( 1.3.18.0.2.6.254
+ NAME 'slpServicePrinter'
+ DESC 'Service Location Protocol (SLP) information.'
+ AUXILIARY
+ SUP slpService
+ )
+
+
+3.2. printerAbstract
+
+ This abstract class defines printer information. It is a base class
+ for deriving other printer related classes, such as, but not limited
+ to, classes defined in this document. It defines a common set of
+ printer attributes that are not specific to any one type of service,
+ protocol or operating system.
+
+ ( 1.3.18.0.2.6.258
+ NAME 'printerAbstract'
+ DESC 'Printer related information.'
+ ABSTRACT
+ SUP top
+ MAY ( printer-name $
+ printer-natural-language-configured $
+ printer-location $ printer-info $ printer-more-info $
+ printer-make-and-model $
+ printer-multiple-document-jobs-supported $
+ printer-charset-configured $ printer-charset-supported $
+ printer-generated-natural-language-supported $
+ printer-document-format-supported $ printer-color-supported $
+ printer-compression-supported $ printer-pages-per-minute $
+ printer-pages-per-minute-color $
+ printer-finishings-supported $ printer-number-up-supported $
+ printer-sides-supported $ printer-media-supported $
+ printer-media-local-supported $
+ printer-resolution-supported $
+ printer-print-quality-supported $
+ printer-job-priority-supported $ printer-copies-supported $
+ printer-job-k-octets-supported $ printer-current-operator $
+
+Fleming, Jones, Lewis, McDonald Expires 20 June 2001 [Page 7]
+
+Internet Draft LDAP Schema for Printer Services 20 December 2000
+
+ printer-service-person $
+ printer-delivery-orientation-supported $
+ printer-stacking-order-supported $
+ printer-output-features-supported )
+ )
+
+
+3.3. printerService
+
+ This structural class defines printer information. It is derived
+ from class printerAbstract and thus inherits common printer
+ attributes. This class can be used with or without auxiliary classes
+ to define printer information. Auxiliary classes can be used to
+ extend the common printer information with protocol, service or
+ operating system specific information. Note that when extending
+ other structural classes with auxiliary classes, printerService MUST
+ NOT be used.
+
+ LDAP applications SHOULD use printer-uri as the naming attribute.
+ That is, when using printerService, printer-uri SHOULD be used as the
+ attribute type of the directory entry's relative distinguished name
+ (RDN). printer-uri uniquely identifies each of the printer services
+ for a given printer. Note that if the printer service changes
+ domains, printer-uri must be updated with the new domain name.
+
+ ( 1.3.18.0.2.6.255
+ NAME 'printerService'
+ DESC 'Printer information.'
+ STRUCTURAL
+ SUP printerAbstract
+ MAY ( printer-uri $ printer-xri-supported )
+ )
+
+
+3.4. printerServiceAuxClass
+
+ This auxiliary class defines printer information. It is derived from
+ class printerAbstract and thus inherits common printer attributes.
+ This class MUST be used with a structural class.
+
+ LDAP applications SHOULD use printer-uri as the naming attribute.
+ That is, when using printerServiceAuxClass, printer-uri SHOULD be
+ used as the attribute type of the directory entry's relative
+ distinguished name (RDN). printer-uri uniquely identifies each of
+ the printer services for a given printer. Note that if the printer
+ service changes domains, printer-uri must be updated with the new
+ domain name.
+
+ ( 1.3.18.0.2.6.257
+ NAME 'printerServiceAuxClass'
+ DESC 'Printer information.'
+
+Fleming, Jones, Lewis, McDonald Expires 20 June 2001 [Page 8]
+
+Internet Draft LDAP Schema for Printer Services 20 December 2000
+
+ AUXILIARY
+ SUP printerAbstract
+ MAY ( printer-uri $ printer-xri-supported )
+ )
+
+
+3.5. printerIPP
+
+ This auxiliary class defines Internet Printing Protocol (IPP)
+ information. It MUST be used with a structural class such as
+ printerService. It is used to extend structural classes with IPP
+ specific printer information.
+
+ ( 1.3.18.0.2.6.256
+ NAME 'printerIPP'
+ DESC 'Internet Printing Protocol (IPP) information.'
+ AUXILIARY
+ SUP top
+ MAY ( printer-ipp-versions-supported $
+ printer-multiple-document-jobs-supported )
+ )
+
+
+3.6. printerLPR
+
+ This auxiliary class defines LPR information. It MUST be used with a
+ structural class such as printerService. It is used to identify
+ directory entries that support LPR.
+
+ ( 1.3.18.0.2.6.253
+ NAME 'printerLPR'
+ DESC 'LPR information.'
+ AUXILIARY
+ SUP top
+ MUST ( printer-name )
+ MAY ( printer-aliases)
+ )
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Fleming, Jones, Lewis, McDonald Expires 20 June 2001 [Page 9]
+
+Internet Draft LDAP Schema for Printer Services 20 December 2000
+
+
+
+4. Definition of Attribute Types
+
+ The following attribute types are referenced by the object classes
+ defined in section 3.
+
+ The following table is a summary of the attribute names referenced by
+ this document and their corresponding names from [RFC 2911]. Some
+ attribute names described in [RFC 2911] have been prefixed with
+ 'printer-' as recommended in [RFC 2926], to address the flat
+ namespace for LDAP identifiers.
+
+ LDAP & SLP Printer Schema IPP Model [RFC 2911]
+ ------------------------------ -------------------------------------
+ printer-uri
+ printer-xri-supported
+ [IPP printer-uri-supported]
+ [IPP uri-authentication-supported]
+ [IPP uri-security-supported]
+ printer-name printer-name
+ printer-natural-language-configured
+ natural-language-configured
+ printer-location printer-location
+ printer-info printer-info
+ printer-more-info printer-more-info
+ printer-make-and-model printer-make-and-model
+ printer-ipp-versions-supported ipp-versions-supported
+ printer-multiple-document-jobs-supported
+ multiple-document-jobs-supported
+ printer-charset-configured charset-configured
+ printer-charset-supported charset-supported
+ printer-generated-natural-language-supported
+ generated-natural-language-supported
+ printer-document-format-supported
+ document-format-supported
+ printer-color-supported color-supported
+ printer-compression-supported compression-supported
+ printer-pages-per-minute pages-per-minute
+ printer-pages-per-minute-color pages-per-minute-color
+ printer-finishings-supported finishings-supported
+ printer-number-up-supported number-up-supported
+ printer-sides-supported sides-supported
+ printer-media-supported media-supported
+ printer-media-local-supported [site names from IPP media-supported]
+ printer-resolution-supported printer-resolution-supported
+ printer-print-quality-supported print-quality-supported
+ printer-job-priority-supported job-priority-supported
+ printer-copies-supported copies-supported
+ printer-job-k-octets-supported job-k-octets-supported
+ printer-current-operator
+
+Fleming, Jones, Lewis, McDonald Expires 20 June 2001 [Page 10]
+
+Internet Draft LDAP Schema for Printer Services 20 December 2000
+
+ printer-service-person
+ printer-delivery-orientation-supported
+ printer-stacking-order-supported
+ printer-output-features-supported
+ printer-aliases
+
+ In the following definitions, we use matching rule names instead of
+ OIDs for clarity. Note that if the printer information is not known,
+ the attribute value is not set (for optional attributes). In the
+ following definitions, referenced matching rules are defined in
+ section 8 of [RFC 2252].
+
+ The following definitions reference syntax OIDs as defined in [RFC
+ 2252], which are summarized below:
+ Syntax OID Syntax Description
+ ----------------------------- ------------------
+ 1.3.6.1.4.1.1466.115.121.1.7 Boolean
+ 1.3.6.1.4.1.1466.115.121.1.15 Directory String (UTF-8 [RFC 2279])
+ 1.3.6.1.4.1.1466.115.121.1.27 Integer
+
+
+
+4.1. printer-uri
+
+ Note, that for SLP registered printers, the LDAP printer-uri
+ attribute should set to the value of the registered URL of the
+ printer.
+
+ ( 1.3.18.0.2.4.1140
+ NAME 'printer-uri'
+ DESC 'The URI supported by this printer.'
+ EQUALITY caseIgnoreMatch
+ ORDERING caseIgnoreOrderingMatch
+ SUBSTR caseIgnoreSubstringMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+ SINGLE-VALUE
+ )
+
+
+4.2. printer-xri-supported
+
+ A list of XRI (extended resource identifiers) supported by this
+ printer. Each value of this list consists of a URI (uniform resource
+ identifier) followed by optional authentication and security
+ metaparameters. The keywords for URI and their metaparameters are:
+ 'uri' == IPP 'printer-uri-supported' value
+ 'auth' == IPP 'uri-authentication-supported' value
+ 'sec' == IPP 'uri-security-supported' value
+ Legal values of the 'auth' metaparameter include
+ 'none' (no authentication for this URI)
+ 'requesting-user-name' (from operation request)
+
+Fleming, Jones, Lewis, McDonald Expires 20 June 2001 [Page 11]
+
+Internet Draft LDAP Schema for Printer Services 20 December 2000
+
+ 'basic' (HTTP/1.1 Basic [RFC 2617])
+ 'digest' (HTTP/1.1 Basic, [RFC 2617])
+ 'certificate' (from certificate)
+ per IPP Model [3] (extensions MAY also be used). A missing 'auth'
+ metaparameter SHALL mean 'none'. Legal values of the 'sec'
+ metaparameter include
+ 'none' (no security for this URI)
+ 'ssl3' (Netscape SSL3)
+ 'tls' (IETF TLS/1.0, [RFC 2246])
+ per IPP Model [3] (extensions MAY also be used). A missing 'sec'
+ metaparameter SHALL mean 'none'. Each metaparameter of a list member
+ is delimited by '<'. For example:
+ 'uri=ipp://foo.com< auth=digest< sec=tls<'
+ 'uri=lpr://bar.com< auth=none< sec=none<'
+ Registrations MAY consolidate values for metaparameters, as in the
+ following example:
+ 'uri=ipp://foo.com< auth=basic,digest< sec=tls,ssl3<'
+
+ ( 1.3.18.0.2.4.1107
+ NAME 'printer-xri-supported'
+ DESC 'The unordered list of XRI (extended resource identifiers)
+ supported by this printer. Each member of the list consists of
+ a URI (uniform resource identifier) followed by optional
+ authentication and security metaparameters.'
+ EQUALITY caseIgnoreMatch
+ ORDERING caseIgnoreOrderingMatch
+ SUBSTR caseIgnoreSubstringMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+ )
+
+
+4.3. printer-name
+
+ The site-specific administrative name of this printer. This value of
+ this attribute SHOULD be in the language specified in
+ 'printer-natural-language-configured' (although the printer's name
+ may be in any language). This name MAY be the last part of the
+ printer's URI or it MAY be completely unrelated. This name MAY
+ contain characters that are not allowed in a conventional URI (which
+ conforms to [RFC 2396]).
+
+ ( 1.3.18.0.2.4.1135
+ NAME 'printer-name'
+ DESC 'The site-specific administrative name of this printer, more
+ end-user friendly than a URI.'
+ EQUALITY caseIgnoreMatch
+ ORDERING caseIgnoreOrderingMatch
+ SUBSTR caseIgnoreSubstringMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127}
+ SINGLE-VALUE
+ )
+
+Fleming, Jones, Lewis, McDonald Expires 20 June 2001 [Page 12]
+
+Internet Draft LDAP Schema for Printer Services 20 December 2000
+
+
+
+4.4. printer-natural-language-configured
+
+ ( 1.3.18.0.2.4.1119
+ NAME 'printer-natural-language-configured'
+ DESC 'The configured language in which error and status messages will
+ be generated (by default) by this printer. Also, a possible
+ language for printer string attributes set by operator, system
+ administrator, or manufacturer. Also, the (declared) language
+ of the "printer-name", "printer-location", "printer-info", and
+ "printer-make-and-model" attributes of this printer. For
+ example: "en-us" (US English) or "fr-fr" (French in France)
+ Legal values of language tags conform to [RFC 1766] "Tags for
+ the Identification of Languages".'
+ EQUALITY caseIgnoreMatch
+ ORDERING caseIgnoreOrderingMatch
+ SUBSTR caseIgnoreSubstringMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127}
+ SINGLE-VALUE
+ )
+
+
+4.5. printer-location
+
+ ( 1.3.18.0.2.4.1136
+ NAME 'printer-location'
+ DESC 'Identifies the location of the printer. This could include
+ things like: "in Room 123A", "second floor of building XYZ".'
+ EQUALITY caseIgnoreMatch
+ ORDERING caseIgnoreOrderingMatch
+ SUBSTR caseIgnoreSubstringMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127}
+ SINGLE-VALUE
+ )
+
+
+4.6. printer-info
+
+ ( 1.3.18.0.2.4.1139
+ NAME 'printer-info'
+ DESC 'Identifies the descriptive information about this printer.
+ This could include things like: "This printer can be used for
+ printing color transparencies for HR presentations", or "Out
+ of courtesy for others, please print only small (1-5 page) jobs
+ at this printer", or even "This printer is going away on July
+ 1, 1997, please find a new printer".'
+ EQUALITY caseIgnoreMatch
+ ORDERING caseIgnoreOrderingMatch
+ SUBSTR caseIgnoreSubstringMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127}
+
+Fleming, Jones, Lewis, McDonald Expires 20 June 2001 [Page 13]
+
+Internet Draft LDAP Schema for Printer Services 20 December 2000
+
+ SINGLE-VALUE
+ )
+
+
+4.7. printer-more-info
+
+ ( 1.3.18.0.2.4.1134
+ NAME 'printer-more-info'
+ DESC 'A URI used to obtain more information about this specific
+ printer. For example, this could be an HTTP type URI
+ referencing an HTML page accessible to a Web Browser. The
+ information obtained from this URI is intended for end user
+ consumption.'
+ EQUALITY caseIgnoreMatch
+ ORDERING caseIgnoreOrderingMatch
+ SUBSTR caseIgnoreSubstringMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+ SINGLE-VALUE
+ )
+
+
+4.8. printer-make-and-model
+
+ ( 1.3.18.0.2.4.1138
+ NAME 'printer-make-and-model'
+ DESC 'Identifies the make and model of the device. The device
+ manufacturer may initially populate this attribute.'
+ EQUALITY caseIgnoreMatch
+ ORDERING caseIgnoreOrderingMatch
+ SUBSTR caseIgnoreSubstringMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127}
+ SINGLE-VALUE
+ )
+
+
+4.9. printer-ipp-versions-supported
+
+ ( 1.3.18.0.2.4.1133
+ NAME 'printer-ipp-versions-supported'
+ DESC 'Identifies the IPP protocol version(s) that this printer
+ supports, including major and minor versions, i.e., the version
+ numbers for which this Printer implementation meets the
+ conformance requirements.'
+ EQUALITY caseIgnoreMatch
+ ORDERING caseIgnoreOrderingMatch
+ SUBSTR caseIgnoreSubstringMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127}
+ )
+
+
+
+
+Fleming, Jones, Lewis, McDonald Expires 20 June 2001 [Page 14]
+
+Internet Draft LDAP Schema for Printer Services 20 December 2000
+
+
+
+4.10. printer-multiple-document-jobs-supported
+
+ ( 1.3.18.0.2.4.1132
+ NAME 'printer-multiple-document-jobs-supported'
+ DESC 'Indicates whether or not the printer supports more than one
+ document per job, i.e., more than one Send-Document or
+ Send-Data operation with document data.'
+ EQUALITY booleanMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
+ SINGLE-VALUE
+ )
+
+
+4.11. printer-charset-configured
+
+ ( 1.3.18.0.2.4.1109
+ NAME 'printer-charset-configured'
+ DESC 'The configured charset in which error and status messages will
+ be generated (by default) by this printer. Also, a possible
+ charset for printer string attributes set by operator, system
+ administrator, or manufacturer. For example: "utf-8" (ISO
+ 10646/Unicode) or "iso-8859-1" (Latin1). Legal values are
+ defined by the IANA Registry of Coded Character Sets and the
+ "(preferred MIME name)" SHALL be used as the tag. For
+ coherence with IPP Model, charset tags in this attribute SHALL
+ be lowercase normalized. This attribute SHOULD be static (time
+ of registration) and SHOULD NOT be dynamically refreshed
+ (subsequently).'
+ EQUALITY caseIgnoreMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{63}
+ SINGLE-VALUE
+ )
+
+
+4.12. printer-charset-supported
+
+ ( 1.3.18.0.2.4.1131
+ NAME 'printer-charset-supported'
+ DESC 'Identifies the set of charsets supported for attribute type
+ values of type Directory String for this directory entry. For
+ example: "utf-8" (ISO 10646/Unicode) or "iso-8859-1" (Latin1).
+ Legal values are defined by the IANA Registry of Coded
+ Character Sets and the preferred MIME name.'
+ EQUALITY caseIgnoreMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{63}
+ )
+
+
+
+
+Fleming, Jones, Lewis, McDonald Expires 20 June 2001 [Page 15]
+
+Internet Draft LDAP Schema for Printer Services 20 December 2000
+
+
+
+4.13. printer-generated-natural-language-supported
+
+ ( 1.3.18.0.2.4.1137
+ NAME 'printer-generated-natural-language-supported'
+ DESC 'Identifies the natural language(s) supported for this directory
+ entry. For example: "en-us" (US English) or "fr-fr" (French in
+ France). Legal values conform to [RFC 1766], Tags for the
+ Identification of Languages.'
+ EQUALITY caseIgnoreMatch
+ ORDERING caseIgnoreOrderingMatch
+ SUBSTR caseIgnoreSubstringMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{63}
+ )
+
+
+4.14. printer-document-format-supported
+
+ ( 1.3.18.0.2.4.1130
+ NAME 'printer-document-format-supported'
+ DESC 'The possible document formats in which data may be interpreted
+ and printed by this printer. Legal values are MIME types come
+ from the IANA Registry of Internet Media Types.'
+ EQUALITY caseIgnoreMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127}
+ )
+
+
+4.15. printer-color-supported
+
+ ( 1.3.18.0.2.4.1129
+ NAME 'printer-color-supported'
+ DESC 'Indicates whether this printer is capable of any type of color
+ printing at all, including highlight color.'
+ EQUALITY booleanMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
+ SINGLE-VALUE
+ )
+
+
+4.16. printer-compression-supported
+
+ ( 1.3.18.0.2.4.1128
+ NAME 'printer-compression-supported'
+ DESC 'Compression algorithms supported by this printer. For example:
+ "deflate, gzip". Legal values include; "none", "deflate"
+ (public domain ZIP), "gzip" (GNU ZIP), "compress" (UNIX).'
+ EQUALITY caseIgnoreMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255}
+ )
+
+Fleming, Jones, Lewis, McDonald Expires 20 June 2001 [Page 16]
+
+Internet Draft LDAP Schema for Printer Services 20 December 2000
+
+
+
+4.17. printer-pages-per-minute
+
+ ( 1.3.18.0.2.4.1127
+ NAME 'printer-pages-per-minute'
+ DESC 'The nominal number of pages per minute which may be output by
+ this printer (e.g., a simplex or black-and-white printer).
+ This attribute is informative, NOT a service guarantee.
+ Typically, it is the value used in marketing literature to
+ describe this printer.'
+ EQUALITY integerMatch
+ ORDERING integerOrderingMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+ SINGLE-VALUE
+ )
+
+
+4.18. printer-pages-per-minute-color
+
+ ( 1.3.18.0.2.4.1126
+ NAME 'printer-pages-per-minute-color'
+ DESC 'The nominal number of color pages per minute which may be
+ output by this printer (e.g., a simplex or color printer).
+ This attribute is informative, NOT a service guarantee.
+ Typically, it is the value used in marketing literature to
+ describe this printer.'
+ EQUALITY integerMatch
+ ORDERING integerOrderingMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+ SINGLE-VALUE
+ )
+
+
+4.19. printer-finishings-supported
+
+ ( 1.3.18.0.2.4.1125
+ NAME 'printer-finishings-supported'
+ DESC 'The possible finishing operations supported by this printer.
+ Legal values include; "none", "staple", "punch", "cover",
+ "bind", "saddle-stitch", "edge-stitch", "staple-top-left",
+ "staple-bottom-left", "staple-top-right",
+ "staple-bottom-right", "edge-stitch-left", "edge-stitch-top",
+ "edge-stitch-right", "edge-stitch-bottom", "staple-dual-left",
+ "staple-dual-top", "staple-dual-right", "staple-dual-bottom".'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255}
+ )
+
+
+
+Fleming, Jones, Lewis, McDonald Expires 20 June 2001 [Page 17]
+
+Internet Draft LDAP Schema for Printer Services 20 December 2000
+
+
+
+4.20. printer-number-up-supported
+
+ ( 1.3.18.0.2.4.1124
+ NAME 'printer-number-up-supported'
+ DESC 'The possible numbers of print-stream pages to impose upon a
+ single side of an instance of a selected medium. Legal values
+ include; 1, 2, and 4. Implementations may support other
+ values.'
+ EQUALITY integerMatch
+ ORDERING integerOrderingMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+ )
+
+
+4.21. printer-sides-supported
+
+ ( 1.3.18.0.2.4.1123
+ NAME 'printer-sides-supported'
+ DESC 'The number of impression sides (one or two) and the two-sided
+ impression rotations supported by this printer. Legal values
+ include; "one-sided", "two-sided-long-edge",
+ "two-sided-short-edge".'
+ EQUALITY caseIgnoreMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127}
+ )
+
+
+4.22. printer-media-supported
+
+ ( 1.3.18.0.2.4.1122
+ NAME 'printer-media-supported'
+ DESC 'The standard names/types/sizes (and optional color suffixes) of
+ the media supported by this printer. For example: "iso-a4",
+ "envelope", or "na-letter-white". Legal values conform to ISO
+ 10175, Document Printing Application (DPA), and any IANA
+ registered extensions.'
+ EQUALITY caseIgnoreMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255}
+ )
+
+
+4.23. printer-media-local-supported
+
+ ( 1.3.18.0.2.4.1117
+ NAME 'printer-media-local-supported'
+ DESC 'Site-specific names of media supported by this printer, in the
+ language in "printer-natural-language-configured".
+ For example: "purchasing-form" (site-specific name) as opposed
+ to (in "printer-media-supported"): "na-letter" (standard
+
+Fleming, Jones, Lewis, McDonald Expires 20 June 2001 [Page 18]
+
+Internet Draft LDAP Schema for Printer Services 20 December 2000
+
+ keyword from ISO 10175).'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255}
+ )
+
+
+4.24. printer-resolution-supported
+
+ ( 1.3.18.0.2.4.1121
+ NAME 'printer-resolution-supported'
+ DESC 'List of resolutions supported for printing documents by this
+ printer. Each resolution value is a string with 3 fields:
+ 1) Cross feed direction resolution (positive integer), 2) Feed
+ direction resolution (positive integer), 3) Resolution unit.
+ Legal values are "dpi" (dots per inch) and "dpcm" (dots per
+ centimeter). Each resolution field is delimited by ">". For
+ example: "300> 300> dpi>".'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255}
+ )
+
+
+4.25. printer-print-quality-supported
+
+ ( 1.3.18.0.2.4.1120
+ NAME 'printer-print-quality-supported'
+ DESC 'List of print qualities supported for printing documents on
+ this printer. For example: "draft, normal". Legal values
+ include; "unknown", "draft", "normal", "high".'
+ EQUALITY caseIgnoreMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127}
+ )
+
+
+4.26. printer-job-priority-supported
+
+ ( 1.3.18.0.2.4.1110
+ NAME 'printer-job-priority-supported'
+ DESC 'Indicates the number of job priority levels supported. An IPP
+ conformant printer which supports job priority must always
+ support a full range of priorities from "1" to "100" (to ensure
+ consistent behavior), therefore this attribute describes the
+ "granularity". Legal values of this attribute are from "1" to
+ "100".'
+ EQUALITY integerMatch
+ ORDERING integerOrderingMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+ SINGLE-VALUE
+ )
+
+Fleming, Jones, Lewis, McDonald Expires 20 June 2001 [Page 19]
+
+Internet Draft LDAP Schema for Printer Services 20 December 2000
+
+
+
+4.27. printer-copies-supported
+
+ ( 1.3.18.0.2.4.1118
+ NAME 'printer-copies-supported'
+ DESC 'The maximum number of copies of a document that may be printed
+ as a single job. A value of "0" indicates no maximum limit. A
+ value of "-1" indicates unknown.'
+ EQUALITY integerMatch
+ ORDERING integerOrderingMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+ SINGLE-VALUE
+ )
+
+
+4.28. printer-job-k-octets-supported
+
+ ( 1.3.18.0.2.4.1111
+ NAME 'printer-job-k-octets-supported'
+ DESC 'The maximum size in kilobytes (1,024 octets actually) incoming
+ print job that this printer will accept. A value of "0"
+ indicates no maximum limit. A value of "-1" indicates
+ unknown.'
+ EQUALITY integerMatch
+ ORDERING integerOrderingMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+ SINGLE-VALUE
+ )
+
+
+4.29. printer-current-operator
+
+ ( 1.3.18.0.2.4.1112
+ NAME 'printer-current-operator'
+ DESC 'The name of the current human operator responsible for
+ operating this printer. It is suggested that this string
+ include information that would enable other humans to reach the
+ operator, such as a phone number.'
+ EQUALITY caseIgnoreMatch
+ ORDERING caseIgnoreOrderingMatch
+ SUBSTR caseIgnoreSubstringMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127}
+ SINGLE-VALUE
+ )
+
+
+4.30. printer-service-person
+
+ ( 1.3.18.0.2.4.1113
+ NAME 'printer-service-person'
+
+Fleming, Jones, Lewis, McDonald Expires 20 June 2001 [Page 20]
+
+Internet Draft LDAP Schema for Printer Services 20 December 2000
+
+ DESC 'The name of the current human service person responsible for
+ servicing this printer. It is suggested that this string
+ include information that would enable other humans to reach the
+ service person, such as a phone number.'
+ EQUALITY caseIgnoreMatch
+ ORDERING caseIgnoreOrderingMatch
+ SUBSTR caseIgnoreSubstringMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127}
+ SINGLE-VALUE
+ )
+
+
+4.31. printer-delivery-orientation-supported
+
+ ( 1.3.18.0.2.4.1114
+ NAME 'printer-delivery-orientation-supported'
+ DESC 'The possible delivery orientations of pages as they are printed
+ and ejected from this printer. Legal values include;
+ "unknown", "face-up", and "face-down".'
+ EQUALITY caseIgnoreMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127}
+ )
+
+
+4.32. printer-stacking-order-supported
+
+ ( 1.3.18.0.2.4.1115
+ NAME 'printer-stacking-order-supported'
+ DESC 'The possible stacking order of pages as they are printed and
+ ejected from this printer. Legal values include; "unknown",
+ "first-to-last", "last-to-first".'
+ EQUALITY caseIgnoreMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127}
+ )
+
+
+4.33. printer-output-features-supported
+
+ ( 1.3.18.0.2.4.1116
+ NAME 'printer-output-features-supported'
+ DESC 'The possible output features supported by this printer. Legal
+ values include; "unknown", "bursting", "decollating",
+ "page-collating", "offset-stacking".'
+ EQUALITY caseIgnoreMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127}
+ )
+
+
+
+
+
+
+Fleming, Jones, Lewis, McDonald Expires 20 June 2001 [Page 21]
+
+Internet Draft LDAP Schema for Printer Services 20 December 2000
+
+
+
+4.34. printer-aliases
+
+ ( 1.3.18.0.2.4.1108
+ NAME 'printer-aliases'
+ DESC 'Site-specific administrative names of this printer in addition
+ the printer name specified for printer-name.'
+ EQUALITY caseIgnoreMatch
+ ORDERING caseIgnoreOrderingMatch
+ SUBSTR caseIgnoreSubstringMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127}
+ )
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Fleming, Jones, Lewis, McDonald Expires 20 June 2001 [Page 22]
+
+Internet Draft LDAP Schema for Printer Services 20 December 2000
+
+
+
+5. Definition of Syntaxes
+
+ No new syntaxes are defined by this document.
+
+
+6. IANA Considerations
+
+ There are no IANA registration considerations defined by this
+ document.
+
+
+7. Internationalization Considerations
+
+ All text string attribute values in objects of the printerService
+ class MUST be encoded in UTF-8 [RFC 2279] characters, as required by
+ the syntax 'Directory String' [RFC 2252]. Also, a language tag for
+ all of the text string attributes in objects of the printerService
+ class SHOULD be supplied in 'printer-natural-language-configured'.
+ Therefore, all objects of the printerService class conform to "IETF
+ Policy on Character Sets and Languages" [RFC 2277].
+
+
+
+8. Security Considerations
+
+ As with any LDAP schema, it is important to protect specific entries
+ and attributes with the appropriate access control. It is
+ particularly important that only administrators can modify entries
+ defined in this schema. For additional considerations of deploying
+ printers in an IPP environment the reader is referred to section 8 of
+ [RFC 2911].
+
+ By advertising the security methods for each supported printer URL
+ the printer may expose information useful to attackers. Suitable
+ security methods SHOULD be used to authenticate any service
+ advertisements.
+
+ Obtaining a reference to an object and storing it in the directory
+ may make a handle to the object available to a wider audience. This
+ may have security implications.
+
+
+
+9. References
+
+ [SLPPRT] St. Pierre, Isaacson, McDonald. Definition Printer Abstract
+ Service Type v2.0, <draft-ietf-svrloc-printer-schema-06.txt>, March
+ 2000 (appoved and archived in the IANA SLP Template Registry:
+
+
+Fleming, Jones, Lewis, McDonald Expires 20 June 2001 [Page 23]
+
+Internet Draft LDAP Schema for Printer Services 20 December 2000
+
+ ftp://isi.edu/in-notes/iana/assignments/svrloc-templates/
+ in the file 'printer.2.0.en')
+
+ [RFC 1179] McLaughlin. Line Printer Daemon Protocol, RFC 1179,
+ August 1990.
+
+ [RFC 1766] Alvestrand. Tags for the Identification of Languages, RFC
+ 1766, March 1995.
+
+ [RFC 2119] Bradner. Key words for use in RFCs to Indicate
+ Requirement Levels, RFC 2119, March 1997.
+
+ [RFC 2246] Dierks, Allen. TLS Protocol Version 1.0, RFC 2246,
+ January 1999.
+
+ [RFC 2251] Wahl, Howes, Kille. Lightweight Directory Access Protocol
+ (v3), RFC 2251, December 1997.
+
+ [RFC 2252] Wahl, Coulbeck, Howes, Kille. Lightweight Directory
+ Access Protocol (v3): Attribute Syntax Definitions, RFC 2252,
+ December 1997.
+
+ [RFC 2277] Alvestrand. IETF Policy on Character Sets and Languages,
+ RFC 2277, January 1998.
+
+ [RFC 2279] Yergeau. UTF-8, a Transformation Format of ISO 10646, RFC
+ 2279, January 1998.
+
+ [RFC 2307] Howard. An Approach for Using LDAP as a Network
+ Information Service, RFC 2307, March 1998.
+
+ [RFC 2396] Berners-Lee, Fielding, Masinter. URI Generic Syntax, RFC
+ 2396, August 1998.
+
+ [RFC 2911] deBry, Hastings, Herriot, Isaacson, Powell. Internet
+ Printing Protocol/1.1: Model and Semantics, RFC 2911, September 2000.
+
+ [RFC 2926] Kempf, Moats, St. Pierre. Conversion of LDAP Schemas to
+ and from SLP Templates, RFC 2926, September 2000.
+
+
+
+10. Acknowledgments
+
+ This document is a submission to the IPP Working group.
+
+ Thanks to Kimberly Reger (IBM), Robert Moore (IBM) and Lee Rafalow
+ (IBM) for their review comments and help in preparing this document.
+
+
+
+
+Fleming, Jones, Lewis, McDonald Expires 20 June 2001 [Page 24]
+
+Internet Draft LDAP Schema for Printer Services 20 December 2000
+
+
+
+11. Authors' Addresses
+
+ Principal Editor:
+ Pat Fleming
+ IBM
+ Highway 52 N.
+ Rochester, MN 55901
+ USA
+ Phone: +1 507-253-7583
+ EMail: flemingp@us.ibm.com
+
+ Ken Jones
+ eStarCom
+ 400 S McCaslin Blvd Suite 211
+ Louisville, CO 80027
+ USA
+ Phone: +1 720-890-7507
+ EMail: kenjones@estarcom.com
+
+ Harry Lewis
+ IBM
+ 6300 Diagonal Hwy
+ Boulder, CO 80301
+ USA
+ Phone: +1 303-924-5337
+ EMail: harryl@us.ibm.com
+
+ Ira McDonald
+ High North Inc
+ 221 Ridge Ave
+ Grand Marais, MI 49839
+ USA
+ Phone: +1 906-494-2434
+ Email: imcdonald@sharplabs.com
+ Email: imcdonald@crt.xerox.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Fleming, Jones, Lewis, McDonald Expires 20 June 2001 [Page 25]
+
+Internet Draft LDAP Schema for Printer Services 20 December 2000
+
+
+
+12. Full Copyright Statement
+
+ Copyright (C) The Internet Society (2000). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE."
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Fleming, Jones, Lewis, McDonald Expires 20 June 2001 [Page 26]
diff --git a/standards/draft-ietf-ipp-not-05.txt b/standards/draft-ietf-ipp-not-05.txt
new file mode 100644
index 000000000..c06658f1a
--- /dev/null
+++ b/standards/draft-ietf-ipp-not-05.txt
@@ -0,0 +1,928 @@
+
+
+
+
+
+
+INTERNET DRAFT Roger K deBry
+<draft-ietf-ipp-not-05.txt> Utah Valley State College
+[Target Category: Informational] Harry Lewis
+ IBM Corporation
+ Tom Hastings (editor)
+ Xerox Corporation
+ January 23, 2001
+
+ Internet Printing Protocol (IPP): Requirements for IPP Notifications
+ Copyright (C) The Internet Society (2001). All Rights Reserved.
+
+
+STATUS OF THIS MEMO
+
+ This document is an Internet-Draft and is in full conformance with
+ all provisions of Section 10 of [RFC2026]. Internet-Drafts are
+ working documents of the Internet Engineering Task Force (IETF), its
+ areas, and its working groups. Note that other groups may also
+ distribute working documents as Internet-Drafts.
+
+ Internet-Drafts are draft documents valid for a maximum of six months
+ and may be updated, replaced, or obsoleted by other documents at any
+ time. It is inappropriate to use Internet-Drafts as reference
+ material or to cite them other than as ''work in progress.''
+
+ The list of current Internet-Drafts can be accessed at
+ http://www.ietf.org/ietf/1id-abstracts.txt
+
+ The list of Internet-Draft Shadow Directories can be accessed as
+ http://www.ietf.org/shadow.html.
+
+ABSTRACT
+
+ This document is one of a set of documents which together describe
+ all aspects of a new Internet Printing Protocol (IPP). IPP is an
+ application level protocol that can be used for distributed printing
+ on the Internet. There are multiple parts to IPP, but the primary
+ architectural components are the Model, the Protocol and an interface
+ to Directory Services. This document provides a statement of the
+ requirements for notifications as part of an IPP Service.
+
+
+
+
+
+
+
+
+
+
+
+deBry, Lewis, Hastings Expires July 23, 2001 [Page 1]
+
+
+INTERNET DRAFT IPP/1.1: Notification Requirements January 23, 2001
+
+
+ The full set of IPP documents include:
+
+ Design Goals for an Internet Printing Protocol [RFC2567]
+ Rationale for the Structure and Model and Protocol for the Internet
+ Printing Protocol [RFC2568]
+ Internet Printing Protocol/1.0: Model and Semantics [RFC2566]
+ Internet Printing Protocol/1.0: Encoding and Transport [RFC2565]
+ Internet Printing Protocol/1.0: Implementer's Guide [RFC 2639]
+ Mapping between LPD and IPP Protocols [RFC2569]
+
+ The 'Design Goals for an Internet Printing Protocol' document takes a
+ broad look at distributed printing functionality, and it enumerates
+ real-life scenarios that help to clarify the features that need to be
+ included in a printing protocol for the Internet. It identifies
+ requirements for three types of users: end users, operators, and
+ administrators. It calls out a subset of end user requirements that
+ are satisfied in IPP/1.0. Operator and administrator requirements
+ are out of scope for version 1.0.
+
+ The 'Rationale for the Structure and Model and Protocol for the
+ Internet Printing Protocol' document describes IPP from a high level
+ view, defines a roadmap for the various documents that form the suite
+ of IPP specifications, and gives background and rationale for the
+ IETF working group's major decisions.
+
+ The 'Internet Printing Protocol/1.0: Encoding and Transport' document
+ is a formal mapping of the abstract operations and attributes defined
+ in the model document onto HTTP/1.1. It defines the encoding rules
+ for a new Internet media type called 'application/ipp'.
+
+ The 'Internet Printing Protocol/1.0: Implementer's Guide' document
+ gives insight and advice to implementers of IPP clients and IPP
+ objects. It is intended to help them understand IPP/1.0 and some of
+ the considerations that may assist them in the design of their client
+ and/or IPP object implementations. For example, a typical order of
+ processing requests is given, including error checking. Motivation
+ for some of the specification decisions is also included.
+
+ The 'Mapping between LPD and IPP Protocols' document gives some
+ advice to implementers of gateways between IPP and LPD (Line Printer
+ Daemon) implementations.
+
+ Table of Contents
+
+
+ 1 Scope ...........................................................4
+
+ 2 Terminology .....................................................4
+
+ 3 Scenarios .......................................................8
+
+
+deBry, Lewis, Hastings Expires July 23, 2001 [Page 2]
+
+
+INTERNET DRAFT IPP/1.1: Notification Requirements January 23, 2001
+
+
+ 4 Requirements ...................................................11
+
+ 5 Security considerations for IPP Notifications requirements .....13
+
+ 6 Internationalization Considerations ............................14
+
+ 7 IANA Considerations ............................................14
+
+ 8 References .....................................................14
+
+ 9 Author's Address ...............................................15
+
+ 10 Appendix A: Full Copyright Statement...........................16
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+deBry, Lewis, Hastings Expires July 23, 2001 [Page 3]
+
+
+INTERNET DRAFT IPP/1.1: Notification Requirements January 23, 2001
+
+
+1 Scope
+
+ The scope of this requirements document covers functionality used by
+ the following kinds of IPP Users: End Users, Print Administrators and
+ Operators.
+
+2 Terminology
+
+ It is necessary to define a set of terms in order to be able to
+ clearly express the requirements for notification services in an IPP
+ System.
+
+2.1 Job Submitting End User
+
+ A human end user who submits a print job to an IPP Printer. This
+ person may or may not be within the same security domain as the
+ Printer. This person may or may not be geographically near the
+ printer.
+
+2.2 Administrator
+
+ A human user who established policy for and configures the print
+ system.
+
+2.3 Operator
+
+ A human user who carries out the policy established by the
+ Administrator and controls the day to day running of the print
+ system.
+
+2.4 Job Submitting Application
+
+ An application (for example, a batch application), acting on behalf
+ of a Job Submitting End User, which submits a print job to an IPP
+ Printer. The application may or may not be within the same security
+ domain as the Printer. This application may or may not be
+ geographically near the printer.
+
+2.5 Security Domain
+
+ For the purposes of this discussion, the set of network components
+ which can communicate without going through a proxy or firewall. A
+ security domain may be geographically very large, for example -
+ anyplace within IBM.COM.
+
+2.6 IPP Client
+
+ The software component that sends IPP requests to an IPP Printer
+ object and accepts IPP responses from an IPP Printer.
+
+
+
+deBry, Lewis, Hastings Expires July 23, 2001 [Page 4]
+
+
+INTERNET DRAFT IPP/1.1: Notification Requirements January 23, 2001
+
+
+2.7 Job Recipient
+
+ A human who is the ultimate consumer of the print job. In many cases
+ this will be the same person as the Job Submitting End User, but this
+ need not always be the case. For example, if I use IPP to print a
+ document on a printer in a business partner's office, I am the Job
+ Submitting End User, while the person I intend the document for in my
+ business partner's office is the Job Recipient. Since one of the
+ goals of IPP is to be able to print near the Job Recipient of the
+ printed output, we would normally expect that person to be in the
+ same security domain as, and geographically near, the Printer.
+ However, this may not always be the case. For example, I submit a
+ print job across the Internet to a Kinko's print shop. I am both the
+ Submitting end User and the Job Recipient, but I am neither near nor
+ in the same security domain as the Printer.
+
+2.8 Job Recipient Proxy
+
+ A person acting on behalf of the Job Recipient. In particular, the
+ Job Recipient Proxy physically picks up the printed document from the
+ Printer, if the Job Recipient cannot perform that function. The Proxy
+ is by definition geographically near and in the same security domain
+ as the printer. For example, I submit a print job from home to be
+ printed on a printer at work. I'd like my secretary to pick up the
+ print job and put it on my desk. In this case, I am acting as both
+ Job Submitting End User and Job Recipient. My secretary is acting as
+ a Job Recipient Proxy.
+
+2.9 Notification Subscriber
+
+ A client that requests the IPP Printer to send Event Notifications to
+ one or more Notification Recipients. A Notification Subscriber may
+ be a Job Submitting End User or an End User, an Operator, or an
+ Administrator that is not submitting a job.
+
+2.10 Notification Source
+
+ The entity that sends Event Notifications.
+
+2.11 Notification Recipient
+
+ The entity that receives IPP Notifications about Job and/or Printer
+ events. A Notification Recipient may be a: Job Submitting End User,
+ Job Submitting Application, Job Recipient, Job Recipient Proxy,
+ Operator, or Administrator, etc., and their representatives or log
+ file or usage statistics gathering application or other active or
+ passive entities.
+
+2.12 Notification Recipient Agent
+
+
+
+deBry, Lewis, Hastings Expires July 23, 2001 [Page 5]
+
+
+INTERNET DRAFT IPP/1.1: Notification Requirements January 23, 2001
+
+
+ A program which receives Event Notifications on behalf of the
+ Notification Recipient. The agent may take some action on behalf of
+ the recipient, forward the notification to the recipient via some
+ alternative means (for example, page the recipient), or queue the
+ notification for later retrieval by the recipient.
+
+2.13 Event
+
+ A Event is some occurrence (either expected or unexpected) within the
+ printing system of a change of state, condition, or configuration of
+ a Job or Printer object.
+
+2.14 Event Notification
+
+ When an event occurs, an Event Notification is generated that fully
+ describes the event (what the event was, where it occurred, when it
+ occurred, etc.). Event Notifications are delivered to all the
+ Notification Recipients that are subscribed to that Event, if any.
+ The Event Notification is delivered to the address of the
+ Notification Recipient using the notification delivery method defined
+ in the subscription. However, an Event Notification is sent ONLY if
+ there is a corresponding subscription.
+
+2.15 Notification Subscription
+
+ A Notification Subscription is a request by a Notification Subscriber
+ to the IPP Printer to send Event Notifications to specified
+ Notification Recipient(s) when the event occur.
+
+2.16 Notification Attributes
+
+ IPP Objects (for example, a print job) from which notification are
+ being sent may have attributes associated with them. A user may want
+ to have one or more of these associated attributes returned along
+ with a particular notification. In general, these may include any
+ attribute associated with the object emitting the notification.
+ Examples include:
+
+ number-of-intervening jobs
+ job-k-octets
+ job-k-octets processed
+ job impressions
+ job-impressions-interpreted
+ job-impressions-completed
+ impressionsCompletedCurrentCopy (job MIB)
+ sheetCompletedCopyNumber (job MIB)
+ sheetsCompletedDocumentNumber (job MIB)
+ Copies-requested
+ Copy-type
+ Output-destination
+
+
+deBry, Lewis, Hastings Expires July 23, 2001 [Page 6]
+
+
+INTERNET DRAFT IPP/1.1: Notification Requirements January 23, 2001
+
+
+ Job-state-reasons
+ Job ID
+ Printer URI
+ Subscription ID (for job independent subscription)
+
+2.17 Notification Delivery Method (or Delivery Method for short)
+
+ Event Notifications are delivered using a method, such as email,
+ TCP/IP, etc.
+
+2.18 Immediate Notification
+
+ Notifications sent to the Notification Recipient or the Notification
+ Recipient's agent in such a way that the notification arrives
+ immediately , within the limits of common addressing, routing,
+ network congestion and quality of service.
+
+2.19 Store and Forward Notification
+
+ Notifications which are not necessarily delivered to Notification
+ Recipients immediately, but are queued for delivery by some
+ intermediate network application, for later retrieval. Email is an
+ example of a store and forward notification delivery method.
+
+2.20 Reliable Delivery of Notifications
+
+ Notifications which are delivered by a reliable delivery of packets
+ or character stream, with acknowledgment and retry, such that
+ delivery of the notification is guaranteed within some determinate
+ time limits. For example, if the Notification Recipient has logged
+ off and gone home for the day, an immediate notification cannot be
+ guaranteed to be delivered, even when sent over a reliable transport,
+ because there is nothing there to catch it. Guaranteed delivery
+ requires both store and forward notification and a reliable
+ transport.
+
+2.21 Notification over Unreliable Transport
+
+ Notifications are delivered via the fundamental transport address and
+ routing framework, but no acknowledgment or retry is required.
+ Process to process communications, if involved, are unconstrained.
+
+
+2.22 Human Consumable Notification
+
+ Notifications which are intended to be consumed by human end users
+ only. Email would be an example of a Human consumable notification,
+ though it could also contain Machine Consumable Notification.
+
+2.23 Machine Consumable Notification
+
+
+deBry, Lewis, Hastings Expires July 23, 2001 [Page 7]
+
+
+INTERNET DRAFT IPP/1.1: Notification Requirements January 23, 2001
+
+
+
+ Notifications which are intended for consumption by a program only,
+ such as an IPP Client. Machine Consumable notifications may not
+ contain human readable information. Do we need both human and
+ machine? Machine readable is intended for application to application
+ only. The Notification Recipient could process the machine readable
+ Event Notification into human readable format.
+
+2.24 Mixed Notification
+
+ A mixed notification contains both Human Consumable and Machine
+ Consumable information.
+
+3 Scenarios
+
+ 1.I am sitting in my office and submit a print job to the printer
+ down the hall. I am in the same security domain as the printer and
+ of course, geographically near. I want to know immediately when
+ my print job will be completed (or if there is a problem) because
+ the document I am working on is urgent. I submit the print job
+ with the following attributes:
+
+ . Notification Recipient - me
+ . Notification Events - all
+ . Notification Attributes - job-state-reason
+ . Notification Type - immediate
+
+ 2.I am working from home and submit a print job to the same printer
+ as in the previous example. However, since I am not at work, I
+ cannot physically get the print file or do anything with it. It
+ can wait until I get to work this afternoon. However, I'd like my
+ secretary to pick up the output and put it on my desk so it
+ doesn't get lost or miss-filed. I'd also like a store and forward
+ notification sent to my email so that when I get to work I can
+ tell if there was a problem with the print job. I submit a print
+ job with the following attributes:
+
+ . Notification Recipient - my secretary
+ . Notification Events - print complete
+ . Notification Type - immediate
+
+ . Notification Recipient - me
+ . Notification Events - print complete
+ . Notification Attributes - impressions completed
+ . Notification Type - store and forward
+
+ 3.I am sitting in my office and submit a print job to a client at an
+ engineering firm we work with on a daily basis. The engineering
+ firm is in Belgium. I would like my client to know when the print
+ job is complete, so that she can pick it up from the printer in
+
+
+deBry, Lewis, Hastings Expires July 23, 2001 [Page 8]
+
+
+INTERNET DRAFT IPP/1.1: Notification Requirements January 23, 2001
+
+
+ her building. It is important that she review it right away and
+ get her comments back to me. I submit the print job with the
+ following attributes:
+
+
+ . Notification Recipient - client at engineering firm
+ . Notification Events - print complete
+ . Notification Type - immediate
+ . Notification Language - French
+
+ 4.I am in a hotel room and send a print job to a Kinko's store in
+ the town I am working in, in order to get a printed report for the
+ meeting I am attending in the morning. Since I'm going out to
+ dinner after I get this job submitted, an immediate notification
+ won't do me much good. However, I'd like to check in the morning
+ before I drive to the Kinko's store to see if the file has been
+ printed. An email notification is sufficient for this purpose. I
+ submit the print job with the following attributes:
+
+ . Notification Recipient - me
+ . Notification Events - print complete
+ . Notification Type - store and forward
+
+ 5.I am printing a large, complex print file. I want to have some
+ immediate feedback on the progress of the print job as it prints.
+ I submit the print job with the following attributes:
+
+ . Notification Recipient - me
+ . Notification Type - immediate
+ . Notification Events - all state transitions
+ . Notification Attributes - impression completed
+
+ 6.I am an operator and my duties is to keep the printer running. I
+ subscribe independently from a job submission so that my
+ subscription outlasts any particular job. I subscribe with the
+ following attributes:
+
+ . Notification Recipient - me
+ . Notification Type - immediate
+ . Notification Events - all Printer state transitions
+ . Notification Attributes - Printer state, printer state reasons,
+ device powering up, device powering down.
+
+ 7.I am a usage statistics gathering application. I subscribe
+ independently from a job submission so that my subscription
+ outlasts any particular job. My subscription may persists across
+ power cycles. I subscribe with the following attributes:
+
+ . Notification Recipient - me
+ . Notification Type - immediate
+
+
+deBry, Lewis, Hastings Expires July 23, 2001 [Page 9]
+
+
+INTERNET DRAFT IPP/1.1: Notification Requirements January 23, 2001
+
+
+ . Notification Events - job completion
+ . Notification Attributes - impression completed, sheets
+ completed, time submitted, time started, time completed, job
+ owner, job size in octets, etc.
+
+ 8.I am a client application program that displays a list of jobs
+ currently queued for printing on a printer. I display the "job-
+ name", "job-state", "job-state-reasons", "page-count", and
+ "intervening-jobs" either for the user's jobs or for all jobs.
+ The window displaying the job list remains open for an independent
+ amount of time, and it is desired that it represent the current
+ state of the queue. It is desired that the application only need
+ to perform a slow poll in order to recover from any missed
+ notifications. So the event delivery mechanism provides the means
+ to update the screen on all needed changes, including querying for
+ some attributes that may not be delivered in the Notification.
+
+ 9.I am a client application program that displays a list of
+ printers. For each Printer I display the current state and
+ configuration. The window displaying the printer list remains
+ open for an independent amount of time, and it is desired that it
+ represent the current state of each printer. It is desired that
+ the application only need to perform a slow poll in order to
+ recover from any missed notifications. So the event delivery
+ mechanism provides the means to update the screen on all needed
+ changes, including querying for some attributes that may not be
+ delivered in the Notification.
+
+ 10. I am an IPP Server that controls one or more devices and
+ implements an IPP Printer object to represent each device. I want
+ to support IPP Notification for each of the IPP Printer objects
+ that I implement. Many of these devices do not support
+ notification (or IPP). So I need to support the IPP Notification
+ semantics specified for each IPP Printer object myself on behalf
+ of each of the devices that each of the IPP Printer objects
+ represent. When I accept IPP job creation requests, I convert the
+ request to what the device will accept. In some cases, I must
+ poll the devices in order to be informed of their job and device
+ state and state changes in order to be able to send IPP
+ Notifications to subscribed Notification Recipients.
+
+ 11. I am an IPP Server that controls one or more devices and
+ implements an IPP Printer object to represent each device. I want
+ to support IPP Notification for each of the IPP Printer objects
+ that I implement. These devices all support IPP, including IPP
+ Notification. I would like the design choice for supporting IPP
+ Notification for these IPP Printer objects that I implement either
+ (1) by forwarding the notification to the IPP Printers that I
+ alone control and have them send the notifications to the intended
+ Notification Recipients without my involvement or (2) replace the
+
+
+deBry, Lewis, Hastings Expires July 23, 2001 [Page 10]
+
+
+INTERNET DRAFT IPP/1.1: Notification Requirements January 23, 2001
+
+
+ notification submitted with the Job to indicate me as the
+ Notification Recipient and I will in turn forward Notifications to
+ the Notification Recipients requested by my clients. Most of the
+ rest of the contents of the IPP Job that I send to the IPP
+ Printers that I control will be the same as the IPP Job that I
+ receive from my IPP clients.
+
+ 12. I am an IPP Server that controls one or more devices and
+ implements an IPP Printer object to represent each device. I want
+ to support IPP Notification for each of the IPP Printer objects
+ that I implement. These devices all support IPP, including IPP
+ Notification. Because these IPP Printers MAY also be being
+ controlled by other servers (using IPP or other protocols), I only
+ want job events for the jobs that I send, but do want Printer
+ events all the time, so that I can show proper Printer state to my
+ clients. So I subscribe to these IPP Printers for Printer events
+ with a long standing subscription with myself to as the
+ Notification Recipient. When I get a Job Creation request, I
+ decide to which IPP Printer to send the job. When I do so, I also
+ add a job subscription for Job events with me as the Notification
+ Recipient to the job's job subscriptions supplied by my clients
+ (this usage is called "piggy-backing"). These IPP Printers
+ automatically remove their job subscriptions when the job
+ completes as for all job subscriptions so that I no longer get Job
+ events when my jobs are completed.
+
+4 Requirements
+
+ The following requirements are intended to be met by the IPP
+ Notification specification (not the implementation). The resulting
+ IPP Notification Specification document:
+
+ 1.must indicate which of these requirements are REQUIRED and which
+ are OPTIONAL for a conforming implementation to support. See
+ [RFC2911] section 12.1 for the definition of these important
+ conformance terms.
+
+ 2.must be designed to that an IPP Printer can transparently support
+ the IPP Notification semantics using third party notification
+ services that exist today or that may be standardized in the
+ future.
+
+ 3.must define means for a Job Submitting End User to specify zero or
+ more Notification Recipients when submitting a print job. A
+ Submitter will not be able to prevent out of band subscriptions
+ from authorized persons, such as Operators.
+
+ 4.must define means when specifying a Notification Recipient, for a
+ Notification Subscriber to be able to specify one or more
+ notification events for that Notification Recipient, subject to
+
+
+deBry, Lewis, Hastings Expires July 23, 2001 [Page 11]
+
+
+INTERNET DRAFT IPP/1.1: Notification Requirements January 23, 2001
+
+
+ administrative and security policy restrictions. Any of the
+ following constitute Job or Printer Events that a Job Submitting
+ End User can specify notifications be sent for:
+ . Any standard Printer MIB alert (i.e. device alerts) (critical
+ and warning?) (state change notifications)?
+ . Job Received (transition from Unknown to Pending)
+ . Job Started (Transition from Pending to Processing)
+ . Page Complete (Page is stacked)
+ . Collated Copy Complete (last sheet of collated copy is
+ stacked)
+ . Job Complete (transition from Processing or Processing-
+ stopped to Completed)
+ . Job aborted (transition from Pending, Pending-held,
+ Processing, or Processing-stopped to Aborted)
+ . Job canceled (transition from Pending, Pending-held,
+ Processing, or Processing-held to Canceled)
+ . Other job state changes like 'paused', purged?
+ . Device problems for which the job is destined
+ . Job (interpreter) issues
+
+
+ 5.must define how an End User or Operator subscribes for:
+ . Any set of Job Events for a specific job.
+ . Any set of Printer Events while a specific job is not
+ complete.
+
+ 6.must define how an End User or Operator subscribes for the
+ following without having to submit a Job:
+ . Any set of Printer Events for a defined period.
+ . Any set of Job Events for all jobs with no control over which
+ jobs.
+
+ 7.must define how the Notification Subscriber is able to specify
+ either immediate or store and forward notification independently
+ for each Notification Recipient. The means may be explicit, or
+ implied by the method of delivery chosen by the Job Submitting End
+ User.
+
+ 8.must define common delivery methods, e.g. email, must be defined.
+
+ 9.must define how an IPP Printer validates its ability to deliver an
+ Event using the specified delivery scheme. If it does not support
+ the specified scheme, or the specified scheme is invalid for some
+ reason, then the IPP Printer accepts and performs the request
+ anyway and responds indicating the unsupported attribute values.
+ There is no requirement for the IPP Printer receiving the print
+ request to validate the identity of an Notification Recipient, nor
+ the ability of the system to deliver an event to that recipient as
+ requested (for example, if the Notification Recipient is not at
+ work today).
+
+
+deBry, Lewis, Hastings Expires July 23, 2001 [Page 12]
+
+
+INTERNET DRAFT IPP/1.1: Notification Requirements January 23, 2001
+
+
+
+ 10. must define a class of IPP event notification delivery methods
+ which can flow through corporate firewalls. However, an IPP
+ printer need not test to guarantee delivery of the notification
+ through a firewall before accepting a print job.
+ 11. may define means for delivering a notification to the
+ submitting client when the delivery of an event notification to a
+ specified Notification Recipient fails. Fall back means of
+ subscribers determining if notifications have failed, i.e.
+ polling, may be provided.
+
+ 12. must define a mechanism for localizing Human Consumable
+ notifications by the Notification Source.
+
+ 13. may define a way to specify whether or not event delivery
+ requires acknowledgement back to the Notification Source.
+
+ 14. There must be a mechanism defined so that job independent
+ subscriptions do not become stale and do not require human
+ intervention to remove stale subscriptions. However, stale must
+ not be the inability to deliver an Event Notification , since
+ temporary Notification delivery problems must be tolerated.
+
+ 15. A mechanism must be defined so that an Event Subscriber is
+ able to add an Event Subscription to a Job after the Job has been
+ submitted.
+
+ 16. A mechanism must be defined so that a client is able to cancel
+ an Event Subscription on a job or printer after the job has been
+ submitted.
+
+ 17. A mechanism must be defined so that a client can obtain the
+ set of current Subscriptions.
+
+5 Security considerations for IPP Notifications requirements
+
+ By far the biggest security concern is the abuse of notification:
+ sending unwanted notifications to third parties (i.e., spam). The
+ problem is made worse by notification addresses that may be
+ redistributed to multiple parties (e.g. mailing lists). There exist
+ scenarios where third party notification is required (see Scenario #2
+ and #3). The fully secure solution would require active agreement of
+ all recipients before sending out anything. However, requirement #9
+ ("There is no requirement for IPP Printer receiving the print request
+ to validate the identity of an event recipient") argues against this.
+ Certain systems may decide to disallow third party notifications (a
+ traditional fax model).
+
+ Clients submitting notification requests to the IPP Printer has the
+ same security issues as submitting an IPP/1.1 print job request. The
+
+
+deBry, Lewis, Hastings Expires July 23, 2001 [Page 13]
+
+
+INTERNET DRAFT IPP/1.1: Notification Requirements January 23, 2001
+
+
+ same mechanisms used by IPP/1.1 can therefore be used by the client
+ notification submission. Operations that require authentication can
+ use the HTTP authentication. Operations that require privacy can use
+ the HTTP/TLS privacy.
+
+ The notification access control model should be similar to the IPP
+ access control model. Creating a notification subscription is
+ associated with a user. Only the creator or an operator can cancel
+ the subscription. The system may limit the listing of items to only
+ those items owned by the user. Some subscriptions (e.g. those that
+ have a lifetime longer than a job) can be done only by privileged
+ users (operators and/or administrators), if that is the authorization
+ policy.
+
+ The standard security concerns (delivery to the right user, privacy
+ of content, tamper proof content) apply to the notification delivery.
+ IPP should use the security mechanism of the delivery method used.
+ Some delivery mechanisms are more secure than others. Therefore,
+ sensitive notifications should use the delivery method that has the
+ strongest security.
+
+6 Internationalization Considerations
+
+ The Human Consumable notification must be localized to the natural
+ language and charset that Notification Subscriber specifies within
+ the choice of natural languages and charsets that the IPP Printer
+ supports.
+
+ The Machine Consumable notification data uses the 'application/ipp'
+ MIME media type. It contains some attributes whose text values are
+ required to be in the natural language and charset that the
+ Notification Subscriber specifies within the choice of natural
+ languages and charsets that the IPP Printer supports. See [RFC2566].
+
+7 IANA Considerations
+
+ There will be some notification delivery methods registered with IANA
+ for use in URLs. These will be defined in other documents.
+
+8 References
+
+ [RFC2565]
+ Herriot, R., Butler, S., Moore, P., Tuner, R., "Internet Printing
+ Protocol/1.0: Encoding and Transport", RFC 2565, April 1999.
+
+ [RFC2566]
+ R. deBry, T. Hastings, R. Herriot, S. Isaacson, P. Powell,
+ "Internet Printing Protocol/1.0: Model and Semantics", RFC 2566,
+ April 1999.
+
+
+
+deBry, Lewis, Hastings Expires July 23, 2001 [Page 14]
+
+
+INTERNET DRAFT IPP/1.1: Notification Requirements January 23, 2001
+
+
+ [RFC2567]
+ Wright, D., "Design Goals for an Internet Printing Protocol",
+ draft-ietf-ipp-req-03.txt, November, 1998.
+
+ [RFC2568]
+ Zilles, S., "Rationale for the Structure and Model and Protocol for
+ the Internet Printing Protocol", draft-ietf-ipp-rat-04.txt,
+ November, 1998.
+
+ [RFC2569]
+ Herriot, R., Hastings, T., Jacobs, N., Martin, J., "Mapping between
+ LPD and IPP Protocols", draft-ietf-ipp-lpd-ipp-map-05.txt, November
+ 1998.
+
+ [RFC2639]
+ T. Hastings, C. Manros. "Internet Printing Protocol/1.0:
+ Implementer's Guide", RFC 2639, July 1999.
+
+ [RFC2911]
+ deBry, R., , Hastings, T., Herriot, R., Isaacson, S., Powell, P.,
+ "Internet Printing Protocol/1.1: Model and Semantics", RFC 2911,
+ September 2000.
+
+9 Author's Address
+
+ Harry Lewis
+ HUC/003G
+ IBM Corporation
+ P.O. Box 1900
+ Boulder, CO 80301-9191
+
+ Phone: (303) 924-5337
+ Fax: (303) 924-9889
+ e-mail: harryl@us.ibm.com
+
+ Roger deBry
+ Utah Valley State College
+ Orem, UT 84058
+
+ Phone: (801) 222-8000
+ e-mail: debryro@uvsc.edu
+
+ Tom Hastings (editor)
+ Xerox Corporation
+ 737 Hawaii St. ESAE 231
+ El Segundo, CA 90245
+
+ Phone: 310-333-6413
+ Fax: 310-333-5514
+ e-mail: hastings@cp10.es.xerox.com
+
+
+deBry, Lewis, Hastings Expires July 23, 2001 [Page 15]
+
+
+INTERNET DRAFT IPP/1.1: Notification Requirements January 23, 2001
+
+
+
+ IPP Mailing List: ipp@pwg.org
+ IPP Mailing List Subscription: ipp-request@pwg.org
+ IPP Web Page: http://www.pwg.org/ipp/
+
+10 Appendix A: Full Copyright Statement
+
+ Copyright (C) The Internet Society (1998,1999,2000,2001). All Rights
+ Reserved
+
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+deBry, Lewis, Hastings Expires July 23, 2001 [Page 16]
diff --git a/standards/draft-ietf-ipp-not-over-snmp-04.txt b/standards/draft-ietf-ipp-not-over-snmp-04.txt
new file mode 100644
index 000000000..f7aa32af3
--- /dev/null
+++ b/standards/draft-ietf-ipp-not-over-snmp-04.txt
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
+<HTML><HEAD>
+<TITLE>404 Not Found</TITLE>
+</HEAD><BODY>
+<H1>Not Found</H1>
+The requested URL /internet-drafts/draft-ietf-ipp-not-over-snmp-04.txt was not found on this server.<P>
+<HR>
+<ADDRESS>Apache/1.3.11 Server at www2.ietf.org Port 80</ADDRESS>
+</BODY></HTML>
diff --git a/standards/draft-ietf-ipp-not-spec-06.txt b/standards/draft-ietf-ipp-not-spec-06.txt
new file mode 100644
index 000000000..fef25561f
--- /dev/null
+++ b/standards/draft-ietf-ipp-not-spec-06.txt
@@ -0,0 +1,4988 @@
+
+
+
+
+
+
+INTERNET-DRAFT R. Herriot (editor)
+<draft-ietf-ipp-not-spec-06.txt> Xerox Corporation
+[Target Category: standards track] T. Hastings
+ Xerox Corporation
+ R. deBry
+ Utah Valley State College
+ S. Isaacson
+ Novell, Inc.
+ J. Martin
+ Underscore
+ M. Shepherd
+ Xerox Corporation
+ R. Bergman
+ Hitachi Koki Imaging Solutions
+ January 24, 2000
+ Internet Printing Protocol (IPP):
+ IPP Event Notification Specification
+ Copyright (C) The Internet Society (2001). All Rights Reserved.
+
+Status of this Memo
+
+ This document is an Internet-Draft and is in full conformance with
+ all provisions of Section 10 of [RFC2026]. Internet-Drafts are
+ working documents of the Internet Engineering Task Force (IETF), its
+ areas, and its working groups. Note that other groups may also
+ distribute working documents as Internet-Drafts.
+
+ Internet-Drafts are draft documents valid for a maximum of six months
+ and may be updated, replaced, or obsoleted by other documents at any
+ time. It is inappropriate to use Internet-Drafts as reference
+ material or to cite them other than as "work in progress".
+
+ The list of current Internet-Drafts can be accessed at
+ http://www.ietf.org/ietf/1id-abstracts.txt
+
+ The list of Internet-Draft Shadow Directories can be accessed as
+ http://www.ietf.org/shadow.html.
+
+Abstract
+
+ This document describes an extension to the IPP/1.0, IPP/1.1, and
+ future versions. This extension allows a client to subscribe to
+ printing related Events. Subscriptions are modeled as Subscription
+ Objects. The Subscription Object specifies that when one of the
+ specified Event occurs, the Printer sends an asynchronous Event
+ Notification to the specified Notification Recipient via the
+ specified Delivery Method (i.e., protocol). A client associates
+ Subscription Objects with a particular Job by performing the Create-
+ Job-Subscriptions operation or by submitting a Job with subscription
+ information. A client associates Subscription Objects with the
+
+Herriot, et al. Expires July 24, 2001 [page 1]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ Printer by performing a Create-Printer-Subscriptions operation. Four
+ other operations are defined for Subscription Objects: Get-
+ Subscriptions-Attributes, Get-Subscriptions, Renew-Subscription, and
+ Cancel-Subscription.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 2]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+
+
+ The basic set of IPP documents includes:
+
+ Design Goals for an Internet Printing Protocol [RFC2567]
+ Rationale for the Structure and Model and Protocol for the Internet
+ Printing Protocol [RFC2568]
+ Internet Printing Protocol/1.1: Model and Semantics [RFC2911]
+ Internet Printing Protocol/1.1: Encoding and Transport [RFC2910]
+ Internet Printing Protocol/1.1: Implementer's Guide [IPP-IIG]
+ Mapping between LPD and IPP Protocols [RFC2569]
+
+ The "Design Goals for an Internet Printing Protocol" document takes a
+ broad look at distributed printing functionality, and it enumerates
+ real-life scenarios that help to clarify the features that need to be
+ included in a printing protocol for the Internet. It identifies
+ requirements for three types of users: end users, Operators, and
+ Administrators. It calls out a subset of end user requirements that
+ are satisfied in IPP/1.0. Operator and Administrator requirements
+ are out of scope for version 1.0. A few OPTIONAL Operator operations
+ have been added to IPP/1.1.
+
+ The "Rationale for the Structure and Model and Protocol for the
+ Internet Printing Protocol" document describes IPP from a high level
+ view, defines a roadmap for the various documents that form the suite
+ of IPP specifications, and gives background and rationale for the
+ IETF working group's major decisions.
+
+ The "Internet Printing Protocol/1.1: Model and Semantics", describes
+ a simplified model with abstract objects, their attributes, and their
+ operations that are independent of encoding and transport. It
+ introduces a Printer object and a Job object. The Job object
+ optionally supports multiple documents per Job. It also addresses
+ security, internationalization, and directory issues.
+
+ The "Internet Printing Protocol/1.1: Encoding and Transport" document
+ is a formal mapping of the abstract operations and attributes defined
+ in the model document onto HTTP/1.1. It defines the encoding rules
+ for a new Internet MIME media type called "application/ipp". This
+ document also defines the rules for transporting over HTTP a message
+ body whose Content-Type is "application/ipp". This document defines
+ a new scheme named 'ipp' for identifying IPP printers and jobs.
+ Finally, this document defines interoperability rules for supporting
+ IPP/1.0 clients.
+
+ The "Internet Printing Protocol/1.1: Implementer's Guide" document
+ gives insight and advice to implementers of IPP clients and IPP
+ objects. It is intended to help them understand IPP/1.0 and some of
+ the considerations that may assist them in the design of their client
+ and/or IPP object implementations. For example, a typical order of
+
+
+Herriot, et al. Expires July 24, 2001 [page 3]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ processing requests is given, including error checking. Motivation
+ for some of the specification decisions is also included.
+
+ The "Mapping between LPD and IPP Protocols" document gives some
+ advice to implementers of gateways between IPP and LPD (Line Printer
+ Daemon) implementations.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 4]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+Table of Contents
+
+
+ 1 Introduction....................................................9
+ 1.1 Notification Overview........................................9
+
+ 2 Models for Notification........................................12
+ 2.1 Model for Notification (Simple Case)........................12
+ 2.2 Model for Notification with Cascading Printers..............12
+ 2.3 Distributed Model for Notification..........................12
+ 2.4 Extended Notification Recipient.............................13
+
+ 3 Terminology....................................................13
+ 3.1 Conformance Terminology.....................................13
+ 3.2 Other Terminology...........................................14
+
+ 4 Object Relationships...........................................16
+ 4.1 Printer and Per-Printer Subscription Objects................16
+ 4.2 Printer, Job and Per-Job Subscription Objects...............16
+
+ 5 Subscription Object............................................17
+ 5.1 Rules for Support of Subscription Template Attributes.......17
+ 5.2 Rules for Processing Subscription Template Attributes.......18
+ 5.3 Subscription Template Attributes............................22
+ 5.3.1 notify-recipient-uri (uri)..................................23
+ 5.3.2 notify-events (1setOf type2 keyword)........................24
+ 5.3.2.1 Standard Values for Subscribed Events ...................24
+ 5.3.2.1.1 No Events.............................................25
+ 5.3.2.1.2 Subscribed Printer Events.............................25
+ 5.3.2.1.3 Subscribed Job Events.................................26
+ 5.3.2.2 Rules for Matching of Subscribed Events .................28
+ 5.3.2.2.1 Rules for Matching of Printer Events..................28
+ 5.3.2.2.2 Rules for Matching of Job Events......................28
+ 5.3.2.2.3 Special Cases for Matching Rules......................29
+ 5.3.3 notify-attributes (1setOf type2 keyword)....................30
+ 5.3.4 notify-user-data (octetString(63))..........................31
+ 5.3.5 notify-charset (charset)....................................31
+ 5.3.6 notify-natural-language (naturalLanguage)...................32
+ 5.3.7 notify-lease-duration (integer(0:67108863)).................32
+ 5.3.8 notify-time-interval (integer(0:MAX)).......................33
+ 5.4 Subscription Description Attributes.........................35
+ 5.4.1 notify-subscription-id (integer (1:MAX))...................35
+ 5.4.2 notify-sequence-number (integer (0:MAX))....................36
+ 5.4.3 notify-lease-expiration-time (integer(0:MAX))...............36
+ 5.4.4 notify-printer-up-time (integer(1:MAX)).....................37
+ 5.4.5 notify-printer-uri (uri)....................................37
+ 5.4.6 notify-job-id (integer(1:MAX))..............................38
+ 5.4.7 notify-subscriber-user-name (name(MAX)).....................38
+
+ 6 Printer Description Attributes Related to Notification.........38
+
+
+Herriot, et al. Expires July 24, 2001 [page 5]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ 6.1 printer-state-change-time (integer(1:MAX))..................39
+ 6.2 printer-state-change-date-time (dateTime)...................39
+
+ 7 New Values for Existing Printer Description Attributes.........40
+ 7.1 operations-supported (1setOf type2 enum)....................40
+
+ 8 Attributes Only in Event Notifications.........................40
+ 8.1 notify-subscribed-event (type2 keyword).....................40
+ 8.2 notify-text (text(MAX)).....................................41
+
+ 9 Event Notification Content.....................................41
+ 9.1 Content of Machine Consumable Event Notifications...........43
+ 9.1.1 Event Notification Content Common to All Events.............44
+ 9.1.2 Additional Event Notification Content for Job Events........45
+ 9.1.3 Additional Event Notification Content for Printer Events....46
+ 9.2 Content of Human Consumable Event Notification..............46
+ 9.2.1 Event Notification Content Common to All Events.............47
+ 9.2.2 Additional Event Notification Content for Job Events........49
+ 9.2.3 Additional Event Notification Content for Printer Events....50
+
+ 10 Delivery Methods...............................................51
+
+ 11 Operations for Notification....................................53
+ 11.1 Subscription Creation Operations............................53
+ 11.1.1 Create-Job-Subscriptions Operation .......................54
+ 11.1.1.1 Create-Job-Subscriptions Request ........................54
+ 11.1.1.2 Create-Job-Subscriptions Response .......................55
+ 11.1.2 Create-Printer-Subscriptions operation ...................56
+ 11.1.2.1 Create-Printer-Subscriptions Request ....................57
+ 11.1.2.2 Create-Printer-Subscriptions Response ...................57
+ 11.1.3 Job Creation Operation - Extensions for Notification .....57
+ 11.1.3.1 Job Creation Request ....................................58
+ 11.1.3.2 Job Creation Response ...................................58
+ 11.2 Other Operations............................................59
+ 11.2.1 Validate-Job Operation - Extensions for Notification .....59
+ 11.2.2 Get-Printer-Attributes - Extensions for Notification .....60
+ 11.2.3 Get-Subscription-Attributes operation ....................60
+ 11.2.3.1 Get-Subscription-Attributes Request .....................61
+ 11.2.3.2 Get-Subscription-Attributes Response ....................62
+ 11.2.4 Get-Subscriptions operation ..............................63
+ 11.2.4.1 Get-Subscriptions Request ...............................63
+ 11.2.4.2 Get-Subscriptions Response ..............................64
+ 11.2.5 Renew-Subscription operation .............................65
+ 11.2.5.1 Renew-Subscription Request ..............................66
+ 11.2.5.2 Renew-Subscription Response .............................66
+ 11.2.6 Cancel-Subscription operation ............................67
+ 11.2.6.1 Cancel-Subscription Request .............................68
+ 11.2.6.2 Cancel-Subscription Response ............................69
+
+ 12 Conformance Requirements.......................................69
+
+
+Herriot, et al. Expires July 24, 2001 [page 6]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ 13 IANA Considerations............................................70
+ 13.1 Attribute Registrations.....................................70
+ 13.2 Keyword Attribute Value Registrations.......................71
+ 13.3 Operation Registrations.....................................71
+ 13.4 Status code Registrations...................................72
+ 13.5 Attribute Group tag Registrations...........................72
+ 13.6 Format for Event Notification Delivery Method Registration
+ proposals.........................................................73
+ 13.7 Format and Requirements for IPP Delivery Method Registration
+ Proposals.........................................................73
+
+ 14 Internationalization Considerations............................73
+
+ 15 Security Considerations........................................74
+
+ 16 Status Codes...................................................74
+ 16.1 successful-ok-ignored-subscriptions (0x0003)................75
+ 16.2 client-error-ignored-all-subscriptions (0x0414).............75
+
+ 17 Status Codes in Subscription Attributes Groups.................75
+ 17.1 client-error-uri-scheme-not-supported (0x040C)..............75
+ 17.2 client-error-too-many-subscriptions (0x0415)................76
+ 17.3 successful-ok-too-many-events (0x0005)......................76
+ 17.4 successful-ok-ignored-or-substituted-attributes (0x0001)....76
+
+ 18 Encodings of Additional Attribute Tags.........................76
+
+ 19 References.....................................................76
+
+ 20 Author's Addresses.............................................78
+
+ A. Appendix - Model for Notification with Cascading Printers......79
+
+ B. Appendix - Distributed Model for Notification..................80
+
+ C. Appendix - Extended Notification Recipient.....................81
+
+ D. Appendix - Details about Conformance Terminology...............82
+
+ E. Appendix - Object Model for Notification.......................83
+ E.1 Appendix - Object relationships.............................84
+ E.2 Printer Object and Per-Printer Subscription Objects.........85
+ E.3 Job Object and Per-Job Subscription Objects.................85
+
+ F. Appendix - Per-Job versus Per-Printer Subscription Objects.....85
+
+ G. Appendix: Full Copyright Statement.............................86
+
+Tables
+ Table 1 - Subscription Template Attributes........................23
+
+
+Herriot, et al. Expires July 24, 2001 [page 7]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ Table 2 - Subscription Description Attributes.....................35
+ Table 3 - Printer Description Attributes Associated with Notification
+ ..............................................................39
+ Table 4 - Operation-id assignments................................40
+ Table 5 - Attributes in Event Notification Content................44
+ Table 6 - Additional Event Notification Content for Job Events....45
+ Table 7 - Combinations of Events and Subscribed Events for "job-
+ impressions-completed" ........................................46
+ Table 8 - Additional Event Notification Content for Printer Events46
+ Table 9 - Printer Name in Event Notification Content..............48
+ Table 10 - Event Name in Event Notification Content...............48
+ Table 11 - Event Time in Event Notification Content...............49
+ Table 12 - Job Name in Event Notification Content.................49
+ Table 13 - Job State in Event Notification Content................50
+ Table 14 - Printer State in Event Notification Content............51
+ Table 15 - Information about the Delivery Method..................52
+ Table 16 - Conformance Requirements for Operations................70
+Figures
+ Figure 1 - Model for Notification.................................12
+ Figure 2 - Model for Notification with Cascading Printers.........80
+ Figure 3 - Opaque Use of a Notification Service Transparent to the
+ Client ........................................................81
+ Figure 4 - Use of an Extended Notification Recipient transparent to
+ the Printer ...................................................82
+ Figure 5 - Object Model for Notification..........................84
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 8]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+1 Introduction
+
+ This IPP notification specification is an extension to IPP/1.0
+ [RFC2568, RFC2569] and IPP/1.1 [RFC2911, RFC2910]. This document in
+ combination with the following documents is intended to meet the
+ notification requirements described in [ipp-not-req]:
+
+ Internet Printing Protocol (IPP): "Job Progress Attributes"
+ [ipp-prog]
+ One or more Delivery Method Documents registered with IANA (see
+ section 13).
+
+ Note: this document does not define any Delivery Methods, but it does
+ define the rules for conformance for Delivery Method Documents.
+
+ Refer to the Table of Contents for the layout of this document.
+
+1.1 Notification Overview
+
+ This document defines operations that a client can perform in order
+ to create Subscription Objects in a Printer and carry out other
+ operations on them. A Subscription Object represents a Subscription
+ abstraction. The Subscription Object specifies that when one of the
+ specified Events occurs, the Printer sends an asynchronous Event
+ Notification to the specified Notification Recipient via the
+ specified Delivery Method (i.e., protocol).
+
+ When a client (called a Subscribing Client) performs an operation
+ that creates a Subscription Object, the operation contains one or
+ more Subscription Template Attributes Groups. Each such group holds
+ information used by the Printer to initialize a newly created
+ Subscription Object. The Printer creates one Subscription Object for
+ each Subscription Template Attributes Group in the operation. This
+ group is like the Job Template Attributes group defined in [RFC2911].
+ The following is an example of the information included in a
+ Subscription Template Attributes Group (see section 5 for details on
+ the Subscription Object attributes):
+
+ 1.The names of Subscribed Events that are of interest to the
+ Notification Recipient.
+ 2.The address (URL) of one Notification Recipient.
+ 3.The Delivery Method (i.e., the protocol) which the Printer uses
+ to send the Event Notification.
+ 4.Some opaque data that the Printer sends to the Notification
+ Recipient in the Event Notification. The Notification Recipient
+ might use this opaque data as a forwarding address for the Event
+ Notification.
+ 5.The charset to use in text fields within an Event Notification
+ 6.The natural language to use in the text fields of the Event
+ Notification
+
+
+Herriot, et al. Expires July 24, 2001 [page 9]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ 7.The requested lease time in seconds for the Subscription Object
+ An operation that creates a Subscription Object is called a
+ Subscription Creation Operation. These operations include the
+ following operations (see section 11.1 for further details):
+
+ . Job Creation operation: When a client performs such an operation
+ (Print-Job, Print-URI, and Create-Job), a client can include
+ zero or more Subscription Template Attributes Groups in the
+ request. The Printer creates one Subscription Object for each
+ Subscription Template Attributes Group in the request, and the
+ Printer associates each such Subscription Object with the newly
+ created Job. This document extends these operations' definitions
+ in [RFC2911] by adding Subscription Template Attributes Groups
+ in the request and Subscription Attributes Groups in the
+ response.
+
+ . Create-Job-Subscriptions operation: A client can include one or
+ more Subscription Template Attributes Groups in the request.
+ The Printer creates one Subscription Object for each
+ Subscription Template Attributes Group and associates each with
+ the job that is the target of this operation.
+
+ . Create-Printer-Subscriptions operation: A client can include one
+ or more Subscription Template Attributes Groups in the request.
+ The Printer creates one Subscription Object for each
+ Subscription Template Attributes Group and associates each with
+ the Printer that is the target of this operation.
+
+ For each of the above operations:
+
+ . the Printer associates a Subscription Object with the Printer or
+ a specific Job. When a Subscription Object is associated with a
+ Job Object, it is called a Per-Job Subscription Object. When a
+ Subscription Object is associated with a Printer Object, it is
+ called a Per-Printer Subscription Object.
+
+ . the response contains one Subscription Attributes Group for each
+ Subscription Template Attributes Group in the request and in the
+ same order. When the Printer successfully creates a Subscription
+ Object, its corresponding Subscription Attributes Group contains
+ the "notify-subscription-id" attribute. This attribute uniquely
+ identifies the Subscription Object and is analogous to a "job-
+ id" for a Job object. Some operations described below use the
+ "notify-subscription-id" to identify the target Subscription
+ Object.
+
+ This document defines the following additional operations (see
+ section 11.2 for further details):
+
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 10]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ . Validate-Job operation: When a client performs this operation, a
+ client can include zero or more Subscription Template Attributes
+ Groups in the request. The Printer determines if it could
+ create one Subscription Object for each Subscription Template
+ Attributes Group in the request. This document extends this
+ operation's definition in [RFC2911] by adding Subscription
+ Template Attributes Groups in the request and Subscription
+ Attributes Groups in the response.
+
+ . Get-Subscription-Attributes operation: This operation allows a
+ client to obtain the specified attributes of a target
+ Subscription Object.
+
+ . Get-Subscriptions operation: This operation allows a client to
+ obtain the specified attributes of all Subscription Objects
+ associated with the Printer or a specified Job.
+
+ . Renew-Subscription operation: This operation renews the lease on
+ the target Per-Printer Subscription Object before it expires. A
+ newly created Per-Printer Subscription Object receives an
+ initial lease. It is the duty of the client to use this
+ operation frequently enough to preserve a Per-Printer
+ Subscription Object. The Printer deletes a Per-Printer
+ Subscription Object when its lease expires. A Per-Job
+ Subscription Object last exactly as long as its associated Job
+ Object and thus doesn't have a lease.
+
+ . Cancel-Subscription operation: This operation cancels the lease
+ on the specified Per-Printer Subscription Object and thereby
+ deletes the Subscription Object.
+
+ When an Event occurs, the Printer finds all Subscription Objects
+ listening for the Event (see section 9 for details on finding such
+ Subscription Objects). For each such Subscription Object, the
+ Printer:
+
+ a)generates an Event Notification with information specified in
+ section 9, AND
+
+ b)either:
+
+ i) delivers the Event Notification using the Delivery Method
+ and target address identified in the Subscription Object's
+ "notify-recipient-uri" attribute if the Delivery Method is a
+ "push", OR
+
+ ii) saves Event Notification for a time period defined by the
+ Delivery Method if the Delivery Method is a "pull", i.e., the
+ Notification Recipient is expected to fetch the Event
+ Notifications.
+
+
+Herriot, et al. Expires July 24, 2001 [page 11]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+2 Models for Notification
+
+2.1 Model for Notification (Simple Case)
+
+ As part of a Subscription Creation Operation, an IPP Printer (i.e.,
+ located in an output device or a server) creates one or more
+ Subscription Objects. In a Subscription Creation Operation, the
+ client specifies the Notification Recipient to which the Printer is
+ to deliver Event Notifications. A Notification Recipient can be the
+ Subscribing Client or a third party.
+
+ Figure 1 shows the Notification model for a simple Client-Printer
+ relationship.
+
+
+ embedded printer:
+ output device or server
+ PDA, desktop, or server +---------------+
+ +--------+ | ########### |
+ | client |-----Subscription ---------># Printer # |
+ +--------+ Creation Operation | # Object # |
+ +------------+ | #####|##### |
+ |Notification| +-------|-------+
+ |Recipient |<----IPP Event Notifications----+
+ +------------+ (Job and/or Printer Events)
+
+ Figure 1 - Model for Notification
+
+2.2 Model for Notification with Cascading Printers
+
+ With this model, there is an intervening Print server between the
+ human user and the Printer in the output device. If the Printer in
+ the output device generates an Event, the system can be configured to
+ send Event Notification either
+
+ . directly to the Notification Recipient specified by the
+ Subscribing Client or
+
+ . via the Print Server to the Notification Recipient specified by
+ the Subscribing Client.
+
+ See Appendix A for more details.
+
+2.3 Distributed Model for Notification
+
+ The preceding sections (2.1 and 2.2) assume that the Notification
+ software resides in the same device or Server box as the rest of the
+ Printer software. In many implementations, the assumption is correct.
+ However, the Notification model also permits a distributed
+ implementation.
+
+
+Herriot, et al. Expires July 24, 2001 [page 12]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ For example, the software that supports both Subscription Creation
+ Operations and sending of Event Notifications could be on hardware
+ that is separate from the output device. To make this work, there
+ must be a symbiotic relationship between the output device software
+ and the remote Notification software. Without the remote Notification
+ software, the output device software is not a complete Printer.
+
+ The term "Printer" in this document includes the software on the
+ output device or server box as well as Notification software that is
+ local to or remote from the output device.
+
+ Appendix B describes this example in detail.
+
+2.4 Extended Notification Recipient
+
+ The model allows for an extended Notification Recipient that is
+ itself a Notification service that forwards each Event Notification
+ to another recipient. The client contacts this Notification Recipient
+ to arrange for forwarding by means outside the scope of this
+ document. The Printer need not be aware that the Notification
+ Recipient forwards Event Notifications.
+
+ Appendix C describes this example in detail.
+
+
+3 Terminology
+
+ This section defines terminology used throughout this document. Other
+ terminology is defined in [RFC2911].
+
+3.1 Conformance Terminology
+
+ Capitalized terms, such as MUST, MUST NOT, REQUIRED, SHOULD, SHOULD
+ NOT, MAY, NEED NOT, and OPTIONAL, have special meaning relating to
+ conformance to this specification. These terms are defined in
+ [RFC2911 section 13.1 on conformance terminology, most of which is
+ taken from RFC 2119 [RFC2119]. See Appendix D for complete details.
+
+ Note: a feature that is OPTIONAL in this document becomes REQUIRED if
+ the Printer implements a Delivery Method that REQUIRES the feature
+
+ READ-ONLY - an adjective used in an attribute definition to indicate
+ that an IPP Printer MUST NOT allow the attribute's value to be
+ modified with the Set-Job-Attributes or Set-Printer-Attributes
+ operations (see [ipp-set]). Note: there is no Set-Subscription
+ operation so this term is not used for Subscription object
+ attributes.
+
+
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 13]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+3.2 Other Terminology
+
+ Administrator - A human user who establishes policy for and
+ configures the print system.
+
+ Operator - A human user who carries out the policy established by the
+ Administrator and controls the day to day running of the print
+ system.
+
+ IPP Client (or client) - The software component (PDA, desktop, or
+ server) that performs an IPP operation directed at an IPP Printer
+ (located in a server or output device).
+
+ Job Creation operation - One of the operations that creates a Job
+ object: Print-Job, Print-URI and Create-Job. The Validate-Job
+ operation is not a Job Creation operation because no Job object is
+ created. Therefore, when a statement also applies to the
+ Validate-Job operation, it is mentioned explicitly.
+
+ Event - some occurrence (either expected or unexpected) within the
+ printing system of a change of state, condition, or configuration
+ of a Job or Printer object. An Event occurs only at one instant in
+ time and does not span the time the physical Event takes place.
+ For example, jam-occurred and jam-cleared are two distinct,
+ instantaneous Events, even though the jam may last for a while.
+
+ Job Event - an Event caused by some change in a particular job on the
+ Printer, e.g., job-completed.
+
+ Printer Event - an Event caused by some change in the Printer that is
+ not specific to a job, e.g., printer-state-changed.
+
+ Subscribed Event - an Event that the Subscribing Client expresses
+ interest in by making it a value of the "notify-events" attribute
+ on a Subscription Object.
+
+ Subscribed Job Event - a Subscribed Event that is a Job Event.
+
+ Subscribed Printer Event - a Subscribed Event that is a Printer
+ Event.
+
+ Event Notification - the information about an Event that the Printer
+ sends when an Event occurs.
+
+ Notification Recipient - the entity to which the Printer sends an
+ Event Notification.
+
+ Delivery Method - the mechanism by which the Printer delivers the
+ Event Notification, e.g., via email or via SNMP.
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 14]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ Delivery Method Document - a document, separate from this document,
+ that defines a Delivery Method.
+
+ Compound Event Notification - two or more Event Notifications that a
+ Printer sends together as a single entity. The Delivery Method
+ Document specifies whether the Delivery Method supports Compound
+ Event Notifications.
+
+ Subscription Object - An object containing a set of attributes that
+ indicate: the Notification Recipient, the Delivery Method, the
+ Subscribed Events that cause the Printer to send an Event
+ Notification, and the information to send in an Event
+ Notification.
+
+ Per-Job Subscription Object - A Subscription Object that is
+ associated with a single Job. The Create-Job-Subscriptions
+ operation and Job Creation operations create such an object.
+
+ Per-Printer Subscription Object - A Subscription Object that is
+ associated with the Printer as a whole. The Create-Printer-
+ Subscriptions operation creates such an object.
+
+ Subscribing Client - The client that creates the Subscription Object.
+
+ Subscription Creation Operation - An operation that creates a
+ Subscription Object: Job Creation operations, Create-Job-
+ Subscriptions operation, and Create-Printer-Subscriptions
+ operation. In the context of a Job Creation operation, a
+ Subscription Creation Operation is the part of the Job Creation
+ operation that creates a Subscription object.
+
+ Subscription Creation Request - The request portion of a
+ Subscription Creation Operation.
+
+ Subscription Template Attributes - Subscription Object attributes
+ that a client can supply in a Subscription Creation Operation and
+ associated Printer Object attributes that specify supported and
+ default values for the Subscription Object attributes.
+
+ Subscription Description Attributes - Subscription Object attributes
+ that a Printer supplies during a Subscription Creation Operation.
+
+ Subscription Template Attributes Group - The attributes group in a
+ request that contains Subscription Object attributes that are
+ Subscription Template Attributes.
+
+ Subscription Attributes Group - The attributes group in a response
+ that contains Subscription Object attributes.
+
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 15]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ Human Consumable Event Notification - localized text for human
+ consumption only. There is no standardized format and thus
+ programs should not try to parse this text.
+
+ Machine Consumable Event Notification - bytes for program
+ consumption. The bytes are formatted according to the Delivery
+ Method document.
+
+ Printer - the software that supports an output device or print server
+ (see IPP/1.1 [RFC2911] which uses the terms Printer and Printer
+ object interchangeably). This document extends the IPP/1.1 Printer
+ definition to include the software that implements Subscription
+ Creation Operations and the sending of Event Notifications, even
+ if the software for such a Printer would be distributed across a
+ network (see section 2.3).
+
+ Notification - when not in the phrases 'Event Notification' and
+ 'Notification Recipient' - the concepts of this specification,
+ i.e., Events, Subscription Objects, and Event Notifications.
+
+
+4 Object Relationships
+
+ This section defines the object relationships between the Printer,
+ Job, and Subscription Objects. It does not define the
+ implementation. For an illustration of these relationships, see
+ Appendix E.
+
+4.1 Printer and Per-Printer Subscription Objects
+
+ 1.A Printer object can be associated with zero or more Per-Printer
+ Subscription Objects.
+
+ 2.Each Per-Printer Subscription Object is associated with exactly
+ one Printer object.
+
+4.2 Printer, Job and Per-Job Subscription Objects
+
+ 1.A Printer object is associated with zero or more Job objects.
+
+ 2.Each Job object is associated with exactly one Printer object.
+
+ 3.A Job object is associated with zero or more Per-Job Subscription
+ Objects.
+
+ 4.Each Per-Job Subscription Object is associated with exactly one
+ Job object.
+
+
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 16]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+5 Subscription Object
+
+ A Subscribing Client creates a Subscription Object with a
+ Subscription Creation Operation in order to indicate its interest in
+ certain Events. See section 11 for a description of these operations.
+ When an Event occurs, the Subscription Object specifies to the
+ Printer where to send Event Notifications, how to send them and what
+ to put in them. See section 9 for details on the contents of an Event
+ Notification.
+
+ Using the IPP Job Template attributes as a model (see [RFC2911]
+ section 4.2), the attributes of a Subscription Object are divided
+ into two categories: Subscription Template Attributes and
+ Subscription Description Attributes.
+
+ Subscription Template attributes are, in turn, like the Job Template
+ attributes, divided into
+
+ 1.Subscription Object attributes that a client can supply in a
+ Subscription Creation Request and
+
+ 2.their associated Printer Object attributes that specify
+ supported and default values for the Subscription Object
+ attributes
+
+ The remainder of this section specifies general rules for
+ Subscription Template Attributes and describes each attribute in a
+ Subscription Object.
+
+5.1 Rules for Support of Subscription Template Attributes
+
+ Subscription Template Attributes are fundamental to the Notification
+ model described in this specification. The client supplies these
+ attributes in Subscription Creation Operations and the Printer uses
+ these attributes to populate a newly created Subscription Object.
+
+ Subscription Objects attributes that are Subscription Template
+ Attributes conform to the following rules:
+
+ 1.Each attribute's name starts with the prefix string "notify-"
+ and this document calls such attributes "notify-xxx".
+
+ 2.For each "notify-xxx" Subscription Object attribute defined in
+ column 1 of Table 1 in section 5.3, Table 1 specifies
+ corresponding Printer attributes: "notify-xxx-default", "notify-
+ xxx-supported", "yyy-supported" and "notify-max-xxx-supported"
+ defined in column 2 of Table 1. Note "xxx" stands for the same
+ string in each case and "yyy" stands for some other string.
+
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 17]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ 3.If a Printer supports "notify-xxx" in column 1 of Table 1, then
+ the Printer MUST support all associated attributes specified in
+ column 2 of Table 1. For example, Table 1 shows that if the
+ Printer supports "notify-events", it MUST support "notify-
+ events-default", "notify-events-supported" and "notify-max-
+ events-supported".
+
+ 4.If a Printer does not support "notify-xxx" in column 1 of Table
+ 1, then the Printer MUST NOT support any associated "notify-yyy"
+ attributes specified in column 2 of Table 1. For example, Table
+ 1 shows that if the Printer doesn't support "notify-events", it
+ MUST NOT support "notify-events-default", "notify-events-
+ supported" and "notify-max-events-supported". Note this rule
+ does not apply to attributes whose names do not start with the
+ string "notify-" and are thus defined in another object and used
+ by other attributes.
+
+ 5.Most "notify-xxx" attributes have a corresponding "yyy-
+ supported" attribute that specifies the supported values for
+ "notify-xxx". Column 2 of Table 1 specifies the name of each
+ "yyy-supported" attribute. The naming rules of IPP/1.1 (see
+ [RFC2911]) are used when "yyy-supported" is "notify-xxx-
+ supported".
+
+ 6.Some "notify-xxx" attributes have a corresponding "notify-xxx-
+ default" attribute that specifies the value for "notify-xxx" if
+ the client does not supply it. Column 2 of Table 1 specifies the
+ name of each "notify-xxx-default" attribute. The naming rules of
+ IPP/1.1 (see [RFC2911]) are used.
+
+ If a client wishes to present an end user with a list of supported
+ values from which to choose, the client SHOULD query the Printer for
+ its supported value attributes. The client SHOULD also query the
+ default value attributes. If the client then limits selectable
+ values to only those values that are supported, the client can
+ guarantee that the values supplied by the client in the create
+ request all fall within the set of supported values at the Printer.
+ When querying the Printer, the client MAY enumerate each attribute by
+ name in the Get-Printer-Attributes Request, or the client MAY just
+ supply the 'subscription-template' group name in order to get the
+ complete set of supported attributes (both supported and default
+ attributes).
+
+5.2 Rules for Processing Subscription Template Attributes
+
+ This section defines a detailed set of rules that a Printer follows
+ when it processes Subscription Template Attributes in a Subscription
+ Creation Request. These rules for are similar to the rules for
+ processing Operation attributes in [RFC2911]. That is, the Printer
+ may or may not support an attribute and a client may or may not
+
+
+Herriot, et al. Expires July 24, 2001 [page 18]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ supply the attribute. Some combinations of these cases are OK. Others
+ return warnings or errors, and perhaps a list of unsupported
+ attributes.
+
+ A Printer MUST implement the following behavior for processing
+ Subscription Template Attributes in a Subscription Creation Request:
+
+ 1.If a client supplies a "notify-xxx" attribute from column 1 of
+ Table 1 and the Printer supports it and its value, the Printer
+ MUST populate the attribute on the created Subscription Object.
+
+ 2.If a client supplies a "notify-xxx" attribute from column 1 of
+ Table 1 and the Printer doesn't support it or its value, the
+ Printer MUST NOT populate the attribute on the created
+ Subscription Object with it. The Printer MUST do one of the
+ following:
+
+ a) If the value of the "notify-xxx" attribute is unsupported, the
+ Printer MUST return the attribute with its value in the
+ Subscription Attributes Group of the response.
+
+ b) If "notify-xxx" is an unsupported attribute, the Printer MUST
+ return the attribute in the Subscription Attributes Group of the
+ response with the 'unsupported' out-of-band value.
+
+ Note: The rules of this step are the same as for Unsupported
+ Attributes [RFC2911] section 3.1.7. except that the unsupported
+ attributes are returned in the Subscription Attributes Group
+ rather than the Unsupported Attributes Group because Subscription
+ Creation Operations can create more than one Subscription Object).
+
+ 3.If a client is REQUIRED to supply a "notify-xxx" attribute from
+ column 1 of Table 1 and the Printer doesn't support the supplied
+ value, the Printer MUST NOT create a Subscription Object. The
+ rules for Unsupported Attributes in step #2 still apply.
+
+ 4.If a client does not supply a "notify-xxx" attribute from column 1
+ of Table 1 and the attribute is REQUIRED for the client to supply,
+ the Printer MUST reject the Subscription Creation Operation
+ (including Job Creation operations) without creating a
+ Subscription Object, and MUST return in the response:
+
+ c) the status code 'client-error-bad-request' AND
+
+ d) no Subscription Attribute Groups.
+
+ 5.If a client does not supply a "notify-xxx" attribute from column 1
+ of Table 1 that is OPTIONAL for the client to supply, and column 2
+ of Table 1 either:
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 19]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ a) specifies a "notify-xxx-default" attribute, the Printer MUST
+ behave as if the client had supplied the "notify-xxx-default"
+ attribute (see step #1) and populate the Subscription object
+ with the value of the "notify-xxx-default" attribute as part of
+ the Subscription Creation operation (unlike Job Template
+ attributes where the Printer does not populate the Job object
+ with defaults - see [RFC2911]) OR
+
+ b) does not specify a "notify-xxx-default" attribute, the Printer
+ MUST populate the "notify-xxx" attribute on the Subscription
+ Object according to the definition of the "notify-xxx" attribute
+ in a section 5.3. For some attributes, the "notify-xxx" is
+ populated with the value of some other attribute, and for
+ others, the "notify-xxx" is NOT populated on the Subscription
+ object at all.
+
+ 6.A Printer MUST create a Subscription Object for each Subscription
+ Template Attributes group in a request unless the Printer:
+
+ a) encounters some attributes in a Subscription Template Attributes
+ Group that require the Printer not to create the Subscription
+ Object OR
+
+ b) would create a Per-Job Subscription Object when it doesn't have
+ space for another Per-Job Subscription Object OR
+
+ c) would create a Per-Printer Subscription Object when it doesn't
+ have space for another Per-Printer Subscription Object.
+
+ 7.A response MUST contain one Subscription Attributes Group for each
+ Subscription Template Attributes Group in the request (and in the
+ same order) whether the Printer creates a Subscription Object from
+ the Subscription Template Attributes Group or not. However, the
+ attributes in each Subscription Attributes Group can be in any
+ order.
+
+ 8.The Printer MUST populate each Subscription Attributes Group of
+ the response such that each contains:
+
+ a) the "notify-subscription-id" attribute (see section 0), if and
+ only if the Printer creates a Subscription Object.
+
+ b) the "notify-lease-duration" attribute (see section 5.3.7), if
+ and only if the Printer creates a Per-Printer Subscription
+ Object. The value of this attribute is the value of the
+ Subscription Object's "notify-lease-duration" attribute. This
+ value MAY be different from the client-supplied value (see
+ section 5.3.7). If a client supplies this attribute in the
+ creation of a Per-Job Subscription Object, it MUST appear in
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 20]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ this group with the out-of-band value 'unsupported' to indicate
+ that the Printer doesn't support it in this context.
+
+ c) all of the unsupported Subscription Template Attributes from
+ step #2. Note, they are not returned in the Unsupported
+ Attributes Group in order to separate the unsupported attributes
+ for each Subscription Object.
+
+ d) the "notify-status-code" attribute if the Printer does not
+ create the Subscription Object or if there are unsupported
+ attributes from step #2. The possible values of the "notify-
+ status-code" attribute are shown below (see section 17 for more
+ details). The Printer returns the first value in the list below
+ that describes the status.
+
+ 'client-error-uri-scheme-not-supported': the Subscription
+ Object was not created because the scheme of the "notify-
+ recipient-uri" attribute is not supported. See section 17.1
+ for more details about this status code. See step #3 in
+ this section for the case that causes this error, and the
+ resulting step #6a) that causes the Printer not to create
+ the Subscription Object.
+
+ 'client-error-too-many-subscriptions': the Subscription
+ Object was not created because the Printer has no space for
+ additional Subscription Objects. The client SHOULD try
+ again later. See section 17.2 for more details about this
+ status code. See steps #6b) and #6c) in this section for
+ the cases that causes this error.
+
+ 'successful-ok-too-many-events': the Subscription Object
+ was created without the "notify-events" values included in
+ this Subscription Attributes Group because the "notify-
+ events" attribute contains too many values. See section
+ 17.3 for more details about this status code. See step #2
+ in this section and section 5.3.2 for the cases that cause
+ this status code.
+
+ 'successful-ok-ignored-or-substituted-attributes' : the
+ Subscription Object was created but some supplied
+ Subscription Template Attributes are unsupported. These
+ unsupported attributes are also in the Subscription
+ Attributes Group. See section 17.4 for more details about
+ this status code. See step #2 in this section for the cases
+ that cause this status code.
+
+ 9.The Printer MUST validate all Subscription Template Attributes and
+ MUST return all unsupported attributes and values in the
+ corresponding Subscription Attributes Group of the response (see
+ step #2) unless it determines that it could not create additional
+
+
+Herriot, et al. Expires July 24, 2001 [page 21]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ Subscription Objects because of condition #6b) or condition #6c).
+ Then, the Printer NEED NOT validate these additional Subscription
+ Template Attributes and the client MUST NOT expect to find
+ unsupported attributes from step #2 in such additional
+ Subscription Attribute Groups.
+
+5.3 Subscription Template Attributes
+
+ This section contains the Subscription Template Attributes defined
+ for the Subscription and Printer objects.
+
+ Table 1 below shows the Subscription Template Attributes and has two
+ columns:
+
+ . Attribute in Subscription Object: the name and attribute syntax
+ of each Subscription Object Attribute that is a Subscription
+ Template Attribute
+
+ . Default and Supported Printer Attributes: the default attribute
+ and supported Printer attributes that are associated with the
+ attribute in column 1.
+
+ A Printer MUST support all attributes in Table 1 below except for
+ "notify-attributes" (and "notify-attributes-supported"). A client
+ MUST supply "notify-recipient-uri" and MAY omit any of the rest of
+ the attributes in column 1 of Table 1 in a Subscription Creation
+ Request.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 22]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ Table 1 - Subscription Template Attributes
+
+
+
+ Attribute in Subscription Default and Supported Printer
+ Object Attributes
+
+
+ notify-recipient-uri (uri) notify-schemes-supported (1setOf
+ uriScheme)
+
+ notify-events (1setOf type2 notify-events-default (1setOf type2
+ keyword) keyword)
+ notify-events-supported (1setOf type2
+ keyword)
+ notify-max-events-supported
+ (integer(2:MAX))
+
+ notify-attributes (1setOf notify-attributes-supported (1setOf
+ type2 keyword) type2 keyword)
+
+ notify-user-data
+ (octetString(63))
+
+ notify-charset (charset) charset-supported (1setOf charset)
+
+ notify-natural-languages generated-natural-language-supported
+ (naturalLanguage) (1setOf naturalLanguage)
+
+ notify-lease-duration notify-lease-duration-default
+ (integer(0:MAX)) (integer(0:67108863))
+ notify-lease-duration-supported
+ (1setOf (integer(0: 67108863) |
+ rangeOfInteger(0:67108863)))
+
+ notify-time-interval
+ (integer(0:MAX))
+
+
+
+5.3.1 notify-recipient-uri (uri)
+
+ This attribute's value is a URL, which is a special case of a URI.
+ Its value consists of a scheme and an address. The address specifies
+ the Notification Recipient and the scheme specifies the Delivery
+ Method for each Event Notification associated with this Subscription
+ Object.
+
+ A Printer MUST support this attribute.
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 23]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ A client MUST supply this attribute in Subscription Creation
+ Operation. Thus there is no need for a default attribute.
+
+ The "notify-schemes-supported (1setOf uriScheme)" attribute MUST
+ specify the schemes supported for this attribute. Note: According to
+ [RFC1738] the ":" terminates the scheme and so is not part of the
+ scheme. Therefore, values of this attribute do not include the ":".
+
+ If the client supplies an unsupported scheme in the value of this
+ attribute, then the Printer MUST not create the Subscription Object
+ and MUST return the "notify-status-code" attribute with the 'client-
+ error-uri-scheme-not-supported' value in the Subscription Attributes
+ Group in the response.
+
+ The Printer MUST treat the address part of this attribute as opaque.
+
+5.3.2 notify-events (1setOf type2 keyword)
+
+ This attribute contains a set of Subscribed Events. When an Event
+ occurs and it "matches" a value of this attribute, the Printer sends
+ an Event Notification using information in the Subscription Object.
+ The details of "matching" are described subsection 5.3.2.2.
+
+ A Printer MUST support this attribute.
+
+ A client MAY supply this attribute in a Subscription Creation
+ Operation. If the client does not supply this attribute in
+ Subscription Creation Operation, the Printer MUST populate this
+ attribute on the Subscription Object with its "notify-events-default"
+ attribute value.
+
+ Each value of this attribute on a Subscription Object MUST be one of
+ the values of the "notify-events-supported (1setOf type2 keyword)"
+ attribute.
+
+ The number of values of this attribute MUST NOT exceed the value of
+ the "notify-max-events-supported" attribute. A Printer MUST support
+ at least 2 values per Subscription Object. If the number of values
+ supplied by a client in a Subscription Creation Operation exceeds the
+ value of this attribute, the Printer MUST treat extra values as
+ unsupported values and MUST use the value of 'successful-ok-too-many-
+ events' for the "notify-status-code" attribute in the Subscription
+ Attributes Group of the response.
+
+5.3.2.1 Standard Values for Subscribed Events
+
+ Each value of this attribute is a keyword and it specifies a
+ Subscribed Event that represents certain changes. Some keywords
+ represent a subset of changes of another keyword, e.g., 'job-
+ completed' is an Event value which is a sub-value of 'job-state-
+
+
+Herriot, et al. Expires July 24, 2001 [page 24]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ change'. See section 5.3.2.2 for the case where this attribute
+ contains both a value and a sub-value.
+
+ The values in this section are divided into three categories: No
+ Events, Job Events and Printer Events.
+
+ A Printer MUST support the Events indicated as "REQUIRED" and MAY
+ support the Events indicated as "OPTIONAL".
+
+5.3.2.1.1 No Events
+
+ The standard and only keyword value for No Events is:
+
+ 'none': REQUIRED - no Event Notifications for any Events. As the
+ sole value of "notify-events-supported", this value means that the
+ Printer does not support the sending of Event Notifications. As
+ the sole value of "notify-events-default", this value means that a
+ client MUST specify the "notify-events" attribute in order for a
+ Subscription Creation Operation to succeed. If the Printer
+ receives this value as the sole value of a Subscription Creation
+ Operation, it does not create a Subscription Object. If a Printer
+ receives this value with other values of a Subscription Creation
+ Operation, the Printer MUST treat this value as an unsupported
+ value.
+
+5.3.2.1.2 Subscribed Printer Events
+
+ The standard keyword values for Subscribed Printer Events are:
+
+ 'printer-state-changed': REQUIRED - the Printer changed state from
+ any state to any other state. Specifically, the value of the
+ Printer's "printer-state", "printer-state-reasons" or "printer-is-
+ accepting-jobs" attributes changed.
+
+ This Subscribed Event value has the following sub-values:
+ 'printer-restarted' and 'printer-shutdown'. A client can listen
+ for any of these sub-values if it doesn't want to listen to all
+ printer-state changes:
+
+ 'printer-restarted': OPTIONAL - when the printer is powered
+ up .
+
+ 'printer-shutdown': OPTIONAL - when the device is being
+ powered down .
+
+ 'printer-stopped: REQUIRED - when the printer stops printing,
+ i.e. the value of the "printer-state" Printer attribute
+ becomes 'stopped'.
+
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 25]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ 'printer-config-changed': OPTIONAL - when the configuration of a
+ Printer has changed, i.e., the value of the "printer-message-from-
+ operator" or any "configuration" Printer attribute has changed. A
+ "configuration" Printer attribute is an attribute which can change
+ value because of some human interaction either direct or indirect,
+ and which is not covered by one of the other Events in this
+ section. Examples of "configuration" Printer attributes are any of
+ the Job Template attributes, such as "xxx-supported", "xxx-ready"
+ and "xxx-default". Often, such a change is the result of a client
+ performing a Set-Printer-Attributes operation (see [ipp-set]) on
+ the Printer. The client has to perform a Get-Printer-Attributes to
+ find out the new values of these changed attributes. This Event
+ is useful for GUI clients and drivers to update the available
+ printer capabilities to the user.
+
+ This Event value has the following sub-values: 'printer-media-
+ changed' and 'printer-finishings-changed'. A client can listen for
+ any of these sub-values if it doesn't want to listen to all
+ printer-configuration changes:
+
+ 'printer-media-changed': OPTIONAL - when the media loaded on
+ a printer has been changed, i.e., the "media-ready"
+ attribute has changed. This Event includes two cases: an
+ input tray that goes empty and an input tray that receives
+ additional media of the same type or of a different type.
+ The client must check the "media-ready" Printer attribute
+ (see [RFC2911] section 4.2.11) separately to find out what
+ changed.
+
+ 'printer-finishings-changed': OPTIONAL - when the finisher on
+ a printer has been changed, i.e., the "finishings-ready"
+ attribute has changed. This Event includes two cases: a
+ finisher that goes empty and a finisher that is refilled
+ (even if it is not full). The client must check the
+ "finishings-ready" Printer attribute separately to find out
+ what changed.
+
+ 'printer-queue-order-changed': OPTIONAL - the order of jobs in the
+ Printer's queue has changed, so that an application that is
+ monitoring the queue can perform a Get-Jobs operation to determine
+ the new order. This Event does not include when a job enters the
+ queue (the 'job-created' Event covers that) and does not include
+ when a job leaves the queue (the 'job-completed' Event covers
+ that).
+
+5.3.2.1.3 Subscribed Job Events
+
+ The standard keyword values for Subscribed Job Events are:
+
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 26]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ 'job-state-changed': REQUIRED - the job has changed from any state
+ to any other state. Specifically, the Printer sends this Event
+ whenever the value of the "job-state" attribute or "job-state-
+ reasons" attribute changes. When a Job is removed from the Job
+ History (see [RFC2911] 4.3.7.1), no Event is generated.
+
+ This Event value has the following sub-values: 'job-created',
+ 'job-completed' and 'job-stopped'. A client can listen for any of
+ these sub-values if it doesn't want to listen to all 'job-state
+ changes'.
+
+ 'job-created': REQUIRED - the Printer has accepted a Job
+ Creation operation and the job's "time-at-creation"
+ attribute value is set (see [RFC2911] section 4.3.14.1).
+ The Printer puts the job in the 'pending', 'pending-held'
+ or 'processing' states..
+
+ 'job-completed': REQUIRED - the job has reached one of the
+ completed states, i.e., the value of the job's "job-state"
+ attribute has changed to: 'completed', 'aborted', or
+ 'canceled'. The Job's "time-at-completed" and "date-time-
+ at-completed" (if supported) attributes are set (see
+ [RFC2911] section 4.3.14).. The Printer also sends this
+ Event when a Job is removed with the Purge-Job operation.
+ In this case, the Event Notification MUST report the 'job-
+ state' as 'canceled'.
+
+ 'job-stopped: OPTIONAL - when the job stops printing, i.e.
+ the value of the "job-state" Job attribute becomes
+ 'processing-stopped'.
+
+ 'job-config-changed': OPTIONAL - when the configuration of a job has
+ changed, i.e., the value of the "job-message-from-operator" or any
+ of the "configuration" Job attributes have changed. A
+ "configuration" Job attribute is an attribute that can change
+ value because of some human interaction either direct or indirect.
+ Examples of "configuration" Job attributes are any of the job
+ template attributes and the "job-name" attribute. Often, such a
+ change is the result of the user or the Operator performing a Set-
+ Job-Attributes operation (see [ipp-set]) on the Job object. The
+ client performs a Get-Job-Attributes to find out the new values of
+ the changed attributes. This Event is useful for GUI clients and
+ drivers to update the job information to the user.
+
+ 'job-progress': OPTIONAL - when the Printer has completed Printing a
+ sheet. See the separate [ipp-prog] specification for additional
+ attributes that a Printer MAY send in an Event Notification caused
+ by this Event. The "notify-time-interval" attribute affects this
+ Event by causing the Printer NOT to send an Event Notification
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 27]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ every time a 'job-progress' Events occurs. See section 5.3.8 for
+ full details.
+
+5.3.2.2 Rules for Matching of Subscribed Events
+
+ When an Event occurs, the Printer MUST find each Subscription object
+ whose "notify-events" attribute "matches" the Event. The rules for
+ "matching" of Subscribed Events are described separately for Printer
+ Events and for Job Events. This section also describes some special
+ cases.
+
+5.3.2.2.1 Rules for Matching of Printer Events
+
+ Suppose that the Printer causes Printer Event E to occur. For each
+ Per-Job or Per-Printer Subscription S in the Printer, if E equals a
+ value of this attribute in S or E is a sub-value of a value of this
+ attribute in S, the Printer MUST generate an Event Notification.
+
+ Consider the example. There are three Subscription Objects each with
+ the Subscribed Printer Event 'printer-state-changed'. Subscription
+ Object A is a Per-Printer Subscription Object. Subscription Object B
+ is a Per-Job Subscription Object for Job 1, and Subscription Object C
+ is a Per-Job Subscription Object for Job 2. When the Printer enters
+ the 'stopped' state, the Printer sends an Event Notification to the
+ Notification Recipients of Subscription Objects A, B, and C because
+ this is a Printer Event. Note if Job 1 has already completed, the
+ Printer would not send an Event Notification for its Subscription
+ Object.
+
+5.3.2.2.2 Rules for Matching of Job Events
+
+ Suppose that Job J causes Job Event E to occur.
+
+ 1.For each Per-Printer Subscription S in the Printer, if E equals
+ a value of this attribute in S or E is a sub-value of a value of
+ this attribute in S, the Printer MUST generate an Event
+ Notification.
+
+ 2.For each Per-Job Subscription S associated with Job J, if E
+ equals a value of this attribute in S or E is a sub-value of a
+ value of this attribute in S, the Printer MUST generate an Event
+ Notification.
+
+ 3.For each Per-Job Subscription S that is NOT associated Job J, if
+ E equals a value of this attribute in S or E is a sub-value of a
+ value of this attribute in, the Printer MUST NOT generate an
+ Event Notification from S.
+
+ Consider the example: There are three Subscription Objects listening
+ for the Job Event 'job-completed'. Subscription Object A is a Per-
+
+
+Herriot, et al. Expires July 24, 2001 [page 28]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ Printer Subscription Object. Subscription Object B is a Per-Job
+ Subscription Object for Job 1, and Subscription Object C is a Per-Job
+ Subscription Object for Job 2. In addition, Per-Printer Subscription
+ Object D is listening for the Job Event 'job-state-changed'. When Job
+ 1 completes, the Printer sends an Event Notification to the
+ Notification Recipient of Subscription Object A (because it is Per-
+ Printer) and Subscription Object B because it is a Per-Job
+ Subscription Object associated with the Job generating the Event.
+ The Printer also sends an Event Notification to the Notification
+ Recipient of Subscription Object D because 'job-completed' is a sub-
+ value of 'job-state-changed' - the value that Subscription Object D
+ is listening for. The Printer does not send an Event Notification to
+ the Notification Recipients of Subscription Object C because it is a
+ Per-Job Subscription Object associated with some Job other than the
+ Job generating the Event.
+
+5.3.2.2.3 Special Cases for Matching Rules
+
+ This section contains rule for special cases.
+
+ If an Event matches Subscribed Events in two different Subscription
+ Objects and the Printer would send two identical Event Notifications
+ (except for the "notify-subscription-id" attribute) to the same
+ Notification Recipient using the same Delivery Method, the Printer
+ MUST send both Event Notifications. That is, the Printer MUST NOT try
+ to consolidate seemingly identical Event Notifications that occur in
+ separate Subscription objects. Incidentally, the Printer MUST NOT
+ reject Subscription Creation Operations that would create this
+ scenario.
+
+ If an Event matches two values of this "notify-events" attribute in a
+ single Subscription object (e.g., a value and its sub-value), a
+ Printer MAY send one Event Notification for each matched value in the
+ Subscription Object or it MAY send only one Event Notification per
+ Subscription Object. The rules in sections 5.3.2.2.1 and 5.3.2.2.2
+ are purposefully ambiguous about the number of Event Notification
+ sent when Event E matches two or more values in a Subscription
+ Object.
+
+ Consider the example: There are two Per-Printer Subscription Objects
+ when a Job completes. Subscription Object A has the Subscribed Job
+ Event 'job-state-changed'. Subscription Object B has the Subscribed
+ Job Events 'job-state-changed' and 'job-completed'. The Printer sends
+ an Event Notification to the Notification Recipient of Subscription
+ Object A with the value of 'job-state-changed' for the "notify-
+ subscribing-event" attribute. The Printer sends either one or two
+ Event Notifications to the Notification Recipient of Subscription
+ Object B, depending on implementation. If it sends two Event
+ Notifications, one has the value of 'job-state-changed' for the
+ "notify-subscribing-event" attribute, and the other has the value of
+
+
+Herriot, et al. Expires July 24, 2001 [page 29]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ 'job-completed' for the "notify-subscribing-event" attribute. If it
+ sends one Event Notification, it has the value of either 'job-state-
+ changed' or 'job-completed' for the "notify-subscribing-event"
+ attribute, depending on implementation. The algorithm for choosing
+ such a value is implementation dependent.
+
+5.3.3 notify-attributes (1setOf type2 keyword)
+
+ This attribute contains a set of attribute names. When a Printer
+ sends a Machine Consumable Event Notification, it includes a fixed
+ set of attributes (see section 9.1). If this attribute is present and
+ the Event Notification is Machine Consumable, the Printer also
+ includes the attributes specified by this attribute.
+
+ A Printer MAY support this attribute.
+
+ A client MAY supply this attribute in a Subscription Creation
+ Operation. If the client does not supply this attribute in
+ Subscription Creation Operation or the Printer does not support this
+ attribute, the Subscription Object MUST NOT contain the "notify-
+ attributes" attribute. There is no "notify-attributes-default"
+ attribute.
+
+ Each keyword value of this attribute on a Subscription Object MUST be
+ a value of the "notify-attributes-supported (1setOf type2 keyword)"
+ attribute. The "notify-attributes-supported" MAY contain any Printer
+ attribute, Job attribute or Subscription Object attribute that the
+ Printer supports in an Event Notification. It MUST NOT contain any
+ of the attributes in Section 9.1 that a Printer automatically puts in
+ an Event Notification; it would be redundant. If a client supplies an
+ attribute in Section 9.1, the Printer MUST treat it as an unsupported
+ attribute value of the "notify-attributes" attribute.
+
+ The following rules apply to each keyword value N of the "notify-
+ attributes" attribute: If the value N names:
+
+ a)a Subscription attribute, the Printer MUST use the attribute N in
+ the Subscription Object that is being used to generate the Event
+ Notification.
+
+ b)a Job attribute and the Printer is generating an Event
+ Notification from a Per-Job Subscription Object S, the Printer
+ MUST use the attribute N in the Job object associated with S.
+
+ c)a Job attribute and the Printer is generating an Event
+ Notification from a Per-Printer Subscription Object and the Event
+ is:
+
+ . a Job Event, the Printer MUST use the attribute N in the Job
+ object that caused the Event.
+
+
+Herriot, et al. Expires July 24, 2001 [page 30]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ . a Printer Event, the Printer MUST use the attribute N in the
+ active Job.
+
+ If a Printer supports this attribute and a Subscription Object
+ contains this attribute and the Delivery Method generates a Machine
+ Consumable Event Notification, the Printer MUST include in each Event
+ Notification:
+
+ a)the attributes specified in section 9.1 and
+
+ b)each attribute named by this attribute.
+
+ The Printer MUST NOT use this attribute to generate a Human
+ Consumable Event Notification.
+
+5.3.4 notify-user-data (octetString(63))
+
+ This attribute contains opaque data that some Delivery Methods
+ include in each Machine Consumable Event Notification. The opaque
+ data might contain, for example:
+
+ . the identity of the Subscriber
+
+ . a path or index to some Subscriber information
+
+ . a key that identifies to the Notification Recipient the ultimate
+ recipient of the Event Notification
+
+ . the id for a Notification Recipient that had previously
+ registered with an Instant Messaging Service
+
+ A Printer MUST support this attribute.
+
+ A client MAY supply this attribute in a Subscription Creation
+ Operation. If the client does not supply this attribute in
+ Subscription Creation Operation, the Subscription Object MUST NOT
+ contain the "notify-user-data" attribute. There is no "notify-user-
+ data-default" attribute.
+
+ There is no "user-data-supported" attribute. Rather, any octetString
+ whose length does not exceed 63 octets is a supported value. If the
+ length exceeds 63 octets, the Printer MUST treat it as an unsupported
+ value.
+
+5.3.5 notify-charset (charset)
+
+ This attribute specifies the charset to be used in the Event
+ Notification content sent to the Notification Recipient, whether the
+ Event Notification content is Machine Consumable or Human Consumable.
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 31]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ A Printer MUST support this attribute.
+
+ A client MAY supply this attribute in a Subscription Creation
+ Operation. If the client does not supply this attribute in
+ Subscription Creation Operation or supplies an unsupported value, the
+ Printer MUST populate this attribute in the Subscription Object with
+ the value of the "attributes-charset" operation attribute, which is a
+ REQUIRED attribute in all IPP requests (see [RFC2911]). If the value
+ of the "attributes-charset" attribute is unsupported, the Printer
+ MUST populate this attribute in the Subscription Object with the
+ value of the Printer's "charset-configured" attribute. There is no
+ "notify-charset-default" attribute.
+
+ The value of this attribute on a Subscription Object MUST be a value
+ of the "charset-supported (1setOf charset)" attribute.
+
+5.3.6 notify-natural-language (naturalLanguage)
+
+ This attribute specifies the natural language to be used in any human
+ consumable text in the Event Notification content sent to the
+ Notification Recipient, whether the Event Notification content is
+ Machine Consumable or Human Consumable.
+
+ A Printer MUST support this attribute.
+
+ A client MAY supply this attribute in a Subscription Creation
+ Operation. If the client does not supply this attribute in
+ Subscription Creation Operation or supplies an unsupported value, the
+ Printer MUST populate this attribute in the Subscription Object with
+ the value of the "attributes-natural-language" operation attribute,
+ which is a REQUIRED attribute in all IPP requests (see [RFC2911]). If
+ the value of the "attributes-natural-language" attribute is
+ unsupported, the Printer MUST populate this attribute in the
+ Subscription Object with the value of the Printer's "natural-
+ language-configured" attribute. There is no "notify-natural-language-
+ default" attribute.
+
+ The value of this attribute on a Subscription Object MUST be a value
+ of the "generated-natural-language-supported (1setOf type2
+ naturalLanguage)" attribute.
+
+5.3.7 notify-lease-duration (integer(0:67108863))
+
+ This attribute specifies the duration of the lease (in seconds)
+ associated with the Per-Printer Subscription Object at the time the
+ Subscription Object was created or the lease was renewed. The
+ duration of the lease is infinite if the value is 0, i.e., the lease
+ never expires.
+
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 32]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ This attribute is not present on a Per-Job Subscription Object
+ because the Subscription Object lasts exactly as long as the
+ associated Job object. See section 5.4.3 on "notify-lease-expiration-
+ time (integer(0:MAX))" for more details.
+
+ A Printer MUST support this attribute.
+
+ For a Subscription Object Creation operation of a Per-Job
+ Subscription Object, the client MUST NOT supply this attribute. If
+ the client does supply this attribute, the Printer MUST treat it as
+ an unsupported attribute.
+
+ For a Subscription Creation Operation of a Per-Printer Subscription
+ Object or a Renew-Subscription operation, a client MAY supply this
+ attribute. If the client does not supply this attribute, the Printer
+ MUST populate this attribute with its "notify-lease-duration-default"
+ (0:67108863) attribute value. If the client supplies this attribute
+ with an unsupported value, the Printer MUST populate this attribute
+ with a supported value, and this value SHOULD be as close as possible
+ to the value requested by the client. Note: this rule implies that a
+ Printer doesn't assign the value of 0 (infinite) unless the client
+ requests it.
+
+ After the Printer has populated this attribute with a supported
+ value, the value represents the "granted duration" of the lease in
+ seconds and the Printer sets the value of the Subscription Object's
+ "notify-lease-expiration-time" attribute as specified in section
+ 5.4.3.
+
+ The value of this attribute on a Subscription Object MUST be a value
+ of the "notify-lease-duration-supported" (1setOf (integer(0:67108863)
+ | rangeOfInteger(0:67108863))) attribute.
+
+ A Printer MAY require authentication in order to return the value of
+ 0 (the lease never expires) as one of the values of "notify-lease-
+ duration-supported", and to allow 0 as a value of the "notify-lease-
+ duration" attribute.
+
+ Note: The maximum value 67,108,863 is 2 raised to the 26 power minus
+ 1 and is about 2 years in seconds. The value is considerably less
+ than MAX so that there is virtually no chance of an overflow when it
+ is added to "printer-up-time" to produce "notify-lease-expiration-
+ time".
+
+5.3.8 notify-time-interval (integer(0:MAX))
+
+ The 'job-progress' Event occurs each time that a Printer completes a
+ sheet. Some Notification Recipients do not want to receive an Event
+ Notification every time this Event occurs. This attribute allows a
+ Subscribing Client to request how often it wants to receive Event
+
+
+Herriot, et al. Expires July 24, 2001 [page 33]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ Notifications for 'job-progress' Events. The value of this attribute
+ MAY be any nonnegative integer (0,MAX) indicating the minimum number
+ of seconds between 'job-progress' Event Notifications.
+
+ The Printer MUST support this attribute if and only if the Printer
+ supports the 'job-progress' Event.
+
+ A client MAY supply this attribute in a Subscription Creation
+ Operation. If the client does not supply this attribute, the Printer
+ MUST not populate this attribute on the Subscription Object. There is
+ no "notify-time-interval-default" attribute.
+
+ There is no "notify-time-interval-supported" attribute.
+
+ If the 'job-progress' Event occurs and a Subscription Object contains
+ the 'job-progress' Event as a value of the 'notify-events' attribute,
+ there are two cases to consider:
+
+ 1.This attribute is not present on the Subscription Object or has
+ the value of 0. The Printer MUST generate and send an Event
+ Notification (as is the case with other Events).
+
+ 2.This attribute is present with a nonzero value of N:
+
+ a)If the Printer has not sent an Event Notification for the 'job-
+ progress' Event for the associated Subscription Object within
+ the past N seconds, the Printer MUST send an Event Notification
+ for the Event that just occurred. Note when the Printer
+ completes the first page of a Job, this rule implies that the
+ Printer sends an Event Notification for a Per-Job Subscription
+ Objects.
+
+ b)Otherwise, the Printer MUST NOT generate or send an Event
+ Notification for the associated Subscription Object. The Printer
+ MUST NOT increase the value of the "notify-sequence-number"
+ Subscription Object attribute (i.e., the sequence of values of
+ the "notify-sequence-number" attribute counts the Event
+ Notifications that the Printer sent and not the Events that do
+ not cause an Event Notification to be sent).
+
+ It is RECOMMENDED that a Subscribing Client use this attribute when
+ it subscribes to the 'job-progress' Event, and that the value be
+ sufficiently large to limit the frequency with which the Printer
+ sends Event Notifications requests.
+
+ This attribute MUST NOT effect any Events other than 'job-progress'.
+
+
+
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 34]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+5.4 Subscription Description Attributes
+
+ Subscription Description Attributes are those attributes that a
+ Printer adds to a Subscription Object at the time of its creation.
+
+ A Printer MUST support all attributes in this Table 2.
+
+ A client MUST NOT supply the attributes in Table 2 in a Subscription
+ Template Attributes Group of a Subscription Creation Operation. If
+ the client supplies them, the Printer MUST NOT set them and MUST
+ treat them as unsupported attributes. There are no corresponding
+ default or supported attributes.
+
+
+ Table 2 - Subscription Description Attributes
+
+
+
+ Subscription Object attributes:
+
+
+ notify-subscription-id (integer(1:MAX))
+
+ notify-sequence-number (integer(0:MAX))
+
+ notify-lease-expiration-time (integer(0:MAX))
+
+ notify-printer-up-time (integer(1:MAX))
+
+ notify-printer-uri (uri)
+
+ notify-job-id (integer(1:MAX))
+
+ notify-subscriber-user-name (name(MAX))
+
+
+
+5.4.1 notify-subscription-id (integer (1:MAX))
+
+ This attribute identifies a Subscription Object instance with a
+ number that is unique within the context of the Printer. The Printer
+ generates this value at the time it creates the Subscription Object.
+
+ A Printer MUST support this attribute.
+
+ The Printer SHOULD NOT assign the value of this attribute
+ sequentially as it creates Subscription Objects. Sequential
+ assignment makes it easy for rogue clients to guess the value of this
+ attribute on other Subscription Objects.
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 35]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ The Printer SHOULD avoid re-using recent values of this attribute
+ during continuous operation of the Printer as well as across power
+ cycles. Then a Subscribing Client is unlikely to find that a stale
+ reference accesses a new Subscription Object.
+
+ The 0 value is not permitted in order to allow for compatibility with
+ "job-id" and with SNMP index values, which also cannot be 0.
+
+5.4.2 notify-sequence-number (integer (0:MAX))
+
+ The value of this attribute indicates the number of times that the
+ Printer has generated and attempted to send an Event Notification.
+ When an Event Notification contains this attribute, the Notification
+ Recipient can determine whether it missed some Event Notifications
+ (i.e., numbers skipped) or received duplicates (i.e., same number
+ twice).
+
+ A Printer MUST support this attribute.
+
+ When the Printer creates a Subscription Object, it MUST set the value
+ of this attribute to 0. This value indicates that the Printer has not
+ sent any Event Notifications for this Subscription Object.
+
+ Each time the Printer sends a newly generated Event Notification, it
+ MUST increase the value of this attribute by 1. For some Delivery
+ Methods, the Printer MUST include this attribute in each Event
+ Notification, and the value MUST be the value after it is increased
+ by 1. That is, the value of this attribute in the first Event
+ Notification after Subscription object creation MUST be 1, the second
+ MUST be 2, etc. If a Delivery Method is defined such that the
+ Notification Recipient returns a response, the Printer can re-try
+ sending an Event Notification a certain number of times with the same
+ sequence number when the Notification Recipient fails to return a
+ response.
+
+ If a Subscription Object lasts long enough to reach the value of MAX,
+ its next value MUST be 0, i.e., it wraps.
+
+5.4.3 notify-lease-expiration-time (integer(0:MAX))
+
+ This attribute specifies the time in the future when the lease on the
+ Per-Printer Subscription Object will expire, i.e. the "printer-up-
+ time" value at which the lease will expire. If the value is 0, the
+ lease never expires.
+
+ A Printer MUST support this attribute.
+
+ When the Printer creates a Per-Job Subscription Object, this
+ attribute MUST NOT be present - the Subscription Object lasts exactly
+ as long as the associated Job object.
+
+
+Herriot, et al. Expires July 24, 2001 [page 36]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ When the Printer creates a Per-Printer Subscription Object, it
+ populates this attribute with a value that is the sum of the values
+ of the Printer's "printer-up-time" attribute and the Subscription
+ Object's "notify-lease-duration" attribute with the following
+ exception. If the value of the Subscription Object's "notify-lease-
+ duration" attribute is 0 (i.e., no expiration time), then the value
+ of this attribute MUST be set to 0 (i.e., no expiration time).
+
+ When the Printer powers up, it MUST set the value of this attribute
+ in each persistent Subscription Object using the algorithm in the
+ previous paragraph.
+
+ When the "printer-up-time" equals the value of this attribute, the
+ Printer MUST delete the Subscription Object. A client can extend a
+ lease of a Per-Printer Subscription Object with the Renew-
+ Subscription operation (see section 11.2.5).
+
+ Note: In order to compute the number of seconds remaining in a lease
+ for a Per-Printer Subscription Object, a client can subtract the
+ Subscription's "notify-printer-up-time" attribute (see section 5.4.4)
+ from the Subscription's "notify-lease-expiration-time" attribute.
+
+5.4.4 notify-printer-up-time (integer(1:MAX))
+
+ This attribute is an alias for the Printer's "printer-up-time"
+ attribute " (see [RFC2911] section 4.4.29).
+
+ A Printer MUST support this attribute.
+
+ When the Printer creates a Per-Job Subscription Object, this
+ attribute MUST NOT be present. When the Printer creates a Per-Printer
+ Subscription Object, this attribute MUST be present.
+
+ Note: this attribute exists in a Per-Printer Subscription Object so
+ that a client using the Get-Subscription-Attributes or Get-
+ Subscription operations can convert the Per-Printer Subscription's
+ "notify-lease-expiration-time" attribute to wall clock time with one
+ request. If the value of the "notify-lease-expiration-time" attribute
+ is not 0 (i.e., no expiration time), then the difference between the
+ "notify-lease-expiration-time" attribute and the "notify-printer-up-
+ time" is the remaining number of seconds on the lease from the
+ current time.
+
+5.4.5 notify-printer-uri (uri)
+
+ This attribute identifies the Printer object that created this
+ Subscription Object.
+
+ A Printer MUST support this attribute.
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 37]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ During a Subscription Creation Operation, the Printer MUST populate
+ this attribute with the value of the "printer-uri" operation
+ attribute in the request. From the Printer URI, the client can, for
+ example, determine what security scheme was used.
+
+5.4.6 notify-job-id (integer(1:MAX))
+
+ This attribute specifies whether the containing Subscription Object
+ is a Per-Job or Per-Printer Subscription Object, and for Per-Job
+ Subscription Objects, it specifies the associated Job.
+
+ A Printer MUST support this attribute.
+
+ If this attribute is not present, the Subscription Object MUST be a
+ Per-Printer Subscription. If this attribute is present, the
+ Subscription Object MUST be a Per-Job Subscription Object and this
+ attribute MUST identify the Job with which the Subscription Object is
+ associated.
+
+ Note: This attribute could be useful to a Notification Recipient that
+ receives an Event Notification generated from a Per-Job Subscription
+ Object and caused by a Printer Event. The Event Notification gives
+ access to the Printer and the Subscription Object. The Event
+ Notification gives access to the associated Job only via this
+ attribute.
+
+5.4.7 notify-subscriber-user-name (name(MAX))
+
+ This attribute contains the name of the user who performed the
+ Subscription Creation Operation.
+
+ A Printer MUST support this attribute.
+
+ The Printer sets this attribute to the most authenticated printable
+ name that it can obtain from the authentication service over which
+ the Subscription Creation Operation was received. The Printer uses
+ the same mechanism for determining the value of this attribute as it
+ does for a Job's "job-originating-user-name" (see [RFC2911] section
+ 4.3.6).
+
+ Note: To help with authentication, a Subscription Object may have
+ additional private attributes about the user, e.g., a credential of a
+ principal. Such private attributes are implementation-dependent and
+ not defined in this document.
+
+
+6 Printer Description Attributes Related to Notification
+
+ This section defines the Printer Description attributes that are
+ related to Notification. Table 3 lists the Printer Description
+
+
+Herriot, et al. Expires July 24, 2001 [page 38]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ attributes, indicates the Printer support required for conformance,
+ and whether or not the attribute is READ-ONLY (see section 3.1):
+
+
+ Table 3 - Printer Description Attributes Associated with Notification
+
+
+
+ Printer object attributes: REQUIRED READ-ONLY
+
+
+ printer-state-change-time (integer(1:MAX)) No Yes
+
+ printer-state-change-date-time (dateTime) No Yes
+
+
+
+6.1 printer-state-change-time (integer(1:MAX))
+
+ This attribute records the most recent time at which the 'printer-
+ state-changed' Printer Event occurred whether or not any Subscription
+ objects were listening for this event. This attribute helps a client
+ or operator to determine how long the Printer has been in its current
+ state.
+
+ A Printer MAY support this attribute and if so, the attribute MUST be
+ READ-ONLY.
+
+ On power-up, the Printer MUST set the value of this attribute to be
+ the value of its "printer-up-time" attribute, so that it always has a
+ value. Whenever the 'printer-state-changed' Printer Event occurs, the
+ Printer MUST set this attribute to the value of the Printer's
+ "printer-up-time" attribute.
+
+6.2 printer-state-change-date-time (dateTime)
+
+ This attribute records the most recent time at which the 'printer-
+ state-changed' Printer Event occurred whether or not there were any
+ Subscription Objects listening for this event. This attribute helps
+ a client or operator to determine how long the Printer has been in
+ its current state.
+
+ A Printer MAY support this attribute and if so, the attribute MUST be
+ READ-ONLY.
+
+ On power-up, the Printer MUST set the value of this attribute to be
+ the value of its "printer-current-time" attribute, so that it always
+ has a value (see [RFC2911] section 4.4.30 on "printer-current-time").
+ Whenever the 'printer-state-changed' Printer Event occurs, the
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 39]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ Printer MUST set this attribute to the value of the Printer's
+ "printer-current-time" attribute.
+
+
+7 New Values for Existing Printer Description Attributes
+
+ This section contains those attributes for which additional values
+ are added.
+
+7.1 operations-supported (1setOf type2 enum)
+
+ The following "operation-id" values are added in order to support the
+ new operations defined in this document:
+
+
+ Table 4 - Operation-id assignments
+
+
+
+ Value Operation Name
+
+
+ 0x0016 Create-Printer-Subscriptions
+
+ 0x0017 Create-Job-Subscriptions
+
+ 0x0018 Get-Subscription-Attributes
+
+ 0x0019 Get-Subscriptions
+
+ 0x001A Renew-Subscription
+
+ 0x001B Cancel-Subscription
+
+
+8 Attributes Only in Event Notifications
+
+ This section contains those attributes that exist only in Event
+ Notifications and do not exist in any objects.
+
+8.1 notify-subscribed-event (type2 keyword)
+
+ This attribute indicates the Subscribed Event that caused the Printer
+ to send this Event Notification. This attribute exists only in Event
+ Notifications.
+
+ This attribute MUST contain one of the values of the "notify-events"
+ attribute in the Subscription Object, i.e., one of the Subscribed
+ Event values. Its value is the Subscribed Event that "matches" the
+ Event that caused the Printer to send this Event Notification. This
+
+
+Herriot, et al. Expires July 24, 2001 [page 40]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ Subscribed Event value may be identical to the Event or the Event may
+ be a sub-value of the Subscribed Event. For example, the 'job-
+ completed' Event (which is a sub-event of the 'job-state-changed'
+ event) would cause the Printer to send an Event Notification for
+ either the 'job-completed' or 'job-state-changed' Subscribed Events
+ and to send the 'job-completed' or 'job-state-changed' value for this
+ attribute, respectively,. See section 5.3.2.2 for the "matching"
+ rules of Subscribed Events and for additional examples.
+
+ The Delivery Method Document specifies whether the Printer includes
+ the value of this attribute in an Event Notification.
+
+8.2 notify-text (text(MAX))
+
+ This attribute contains a Human Consumable text message (see section
+ 0). This message describes the Event and is encoded as plain text,
+ i.e., 'text/plain' with the charset specified by Subscription
+ Object's "notify-charset" attribute.
+
+ The Delivery Method Document specifies whether the Printer includes
+ this attribute in an Event Notification.
+
+
+9 Event Notification Content
+
+ This section defines the Event Notification content that the Printer
+ sends when an Event occurs.
+
+ When an Event occurs, the Printer MUST find each Subscription object
+ whose "notify-events" attribute "matches" the Event. See section
+ 5.3.2.2 for details on "matching". For each matched Subscription
+ Object, the Printer MUST create an Event Notification with the
+ content and format that the Delivery Method Document specifies. The
+ content contains the value of attributes specified by the Delivery
+ Method Document. The Printer obtains the values immediately after the
+ Event occurs. For example, if the "printer-state" attribute changes
+ from 'idle' to 'processing', the Event 'printer-state-changed' occurs
+ and the Printer puts various attributes into the Event Notification,
+ including "printer-up-time" and "printer-state" with the values that
+ they have immediately after the Event occurs, i.e., the value of
+ "printer-state" is 'processing'.
+
+ If two different Events occur simultaneously, or nearly so (e.g.,
+ "printer-up-time" has the same value for both), the Printer MUST
+ create a separate Event Notification for each Event, even if the
+ associated Subscription Object is the same for both Events. However,
+ the Printer MAY combine these distinct Event Notifications into a
+ single Compound Event Notification if the Delivery Method supports
+ Compound Event Notifications For example, suppose that two nearly-
+ simultaneously Events represent two successive 'printer-state-
+
+
+Herriot, et al. Expires July 24, 2001 [page 41]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ changed' Events, one from 'idle' to 'processing' and another from
+ 'processing' to 'stopped'. These two Events have the same name but
+ are different instances of the Event. Then the Printer MUST create a
+ separate Event Notification for each Event and SHOULD accurately
+ report the "printer-state" of the first Event as 'processing' and the
+ second Event as 'stopped'.
+
+ If a Subscription Object contains more than one Subscribed Event, and
+ several Events occur in quick succession each matching a different
+ Subscribed Event in the Subscription Object, the Printer MUST NOT
+ generate a single Event Notification from several of these Events,
+ but MAY combine distinct Event Notifications into a single Compound
+ Event Notification if the Delivery Method supports Compound Event
+ Notifications.
+
+ After the Printer has created the Event Notification, the Printer
+ delivers it via either a:
+
+ Push Delivery Method: The Printer sends the Event Notification
+ shortly after an Event occurs. For some Push Delivery Methods,
+ the Notification Recipient MUST send a response; for others it
+ MUST NOT send a response.
+
+ Pull Delivery Method: The Printer saves Event Notifications for
+ some event-lease time and expects the Notification Recipient to
+ request Event Notifications. The Printer returns the Event
+ Notifications in a response to such a request.
+
+ If an error that meets the following conditions occurs, the Printer
+ MUST cancel the Subscription Object.
+
+ a)the error occurs during the sending of an Event Notification
+ generated from Subscription Object S AND
+
+ b)the error would continue to occur every time the Printer sends an
+ Event Notification generated from Subscription Object S in the
+ future.
+
+ From example, if the address of the "notify-recipient-uri" of
+ Subscription Object A references a non-existent target and the
+ Printer determines that this fact, it MUST delete Subscription Object
+ A.
+
+ The next two sections describe the values that a Printer sends in the
+ content of Machine Consumable and Human Consumable Event
+ Notifications, respectively.
+
+ The tables in the sub-sections of this section contain the following
+ columns:
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 42]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ a)Source Value: the name of the attribute that supplies the value
+ for the Event Notification. Asterisks in this field refer to a
+ note below the table.
+
+ b)Sends: if the Printer supports the value (column 1) on the
+ Source Object (column 3) the Delivery Method MUST specify:
+
+ MUST: that the Printer MUST send the value.
+
+ SHOULD: either that the Printer MUST send the value or that
+ the value is incompatible with the Delivery Method.
+
+ MAY: that the Printer MUST, SHOULD, MAY, MUST NOT, SHOULD NOT,
+ or NEED NOT send the value. The Delivery Method specifies the
+ level of conformance for the Printer.
+
+ c)Source Object: the object from which the source value comes. If
+ the object is "Event Notification", the Printer fabricates the
+ value when it sends the Event Notification. See section 8.
+
+9.1 Content of Machine Consumable Event Notifications
+
+ This section defines the attributes that a Delivery Method MUST
+ mention in a Delivery Method Document when specifying the Machine
+ Consumable Event Notification's contents.
+
+ This document does not define the order of attributes in Event
+ Notifications. However, Delivery Method Documents MAY define the
+ order of some or all of the attributes.
+
+ A Delivery Method Document MUST specify additional attributes (if
+ any) that a Printer implementation sends in a Machine Consumable
+ Event Notification.
+
+ Notification Recipients MUST be able to accept Event Notifications
+ containing attributes they do not recognize. What a Notification
+ Recipient does with an unrecognized attribute is implementation-
+ dependent. Notification Recipients MAY attempt to display
+ unrecognized attributes anyway or MAY ignore them.
+
+ The next three sections define the attributes in Event Notification
+ Contents that are:
+
+ 1.for all Events
+
+ 2.for Job Events only
+
+ 3.for Printer Events only
+
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 43]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+9.1.1 Event Notification Content Common to All Events
+
+ This section lists the attributes that a Delivery Method Document
+ MUST specify for all Events.
+
+ Table 5 lists potential values in each Event Notification.
+
+
+ Table 5 - Attributes in Event Notification Content
+
+
+
+ Source Value Sends Source Object
+
+
+ notify-subscription-id (integer(1:MAX)) MUST Subscription
+
+ notify-printer-uri (uri) MUST Subscription
+
+ notify-subscribed-event (type2 keyword) MUST Event
+ Notification
+
+ printer-up-time (integer(MIN:MAX)) MUST Printer
+
+ printer-current-time (dateTime) * MUST Printer
+
+ notify-sequence-number (integer (0:MAX)) SHOULD Subscription
+
+ notify-charset (charset) SHOULD Subscription
+
+ notify-natural-language (naturalLanguage) SHOULD Subscription
+
+ notify-user-data (octetString(63)) ** SHOULD Subscription
+
+ notify-text (text) SHOULD Event
+ Notification
+
+ attributes from the "notify-attributes" MAY Printer
+ attribute ***
+
+ attributes from the "notify-attributes" MAY Job
+ attribute ***
+
+ attributes from the "notify-attributes" MAY Subscription
+ attribute ***
+
+
+ *A Printer MUST send this value only if and only if it supports the
+ Printer's "printer-current-time" attribute.
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 44]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ ** If the Subscription Object does not contain a "notify-user-data"
+ attribute and the Delivery Method document REQUIRES the Printer to
+ send the "notify-user-data" source value in the Event Notification,
+ the Printer MUST send an octet-string of length 0.
+
+ *** The last three rows represent additional attributes that a client
+ MAY request via the "notify-attributes" attribute. A Printer MAY
+ support the "notify-attributes" attribute. The Delivery Method MUST
+ say that the Printer MUST, SHOULD, MAY, MUST NOT, SHOULD NOT, or NEED
+ NOT support the "notify-attributes" attribute and specific values of
+ this attribute. The Delivery Method MAY say that support for the
+ "notify-attributes" is conditioned on support of the attribute by the
+ Printer or it MAY say that Printer MUST support the "notify-
+ attributes" attribute if the Printer supports the Delivery Method.
+
+9.1.2 Additional Event Notification Content for Job Events
+
+ This section lists the additional attributes that a Delivery Method
+ Document MUST specify for Job Events. See Table 6.
+
+
+ Table 6 - Additional Event Notification Content for Job Events
+
+
+
+ Source Value Sends Source Object
+
+
+ job-id (integer(1:MAX)) MUST Job
+
+ job-state (type1 enum) MUST Job
+
+ job-state-reasons (1setOf type2 keyword) MUST Job
+
+ job-impressions-completed (integer(0:MAX)) * MUST Job
+
+
+ * The Printer MUST send the "job-impressions-completed" attribute in
+ an Event Notification only for the combinations of Events and
+ Subscribed Events shown in Table 7.
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 45]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ Table 7 - Combinations of Events and Subscribed Events for "job-
+ impressions-completed"
+
+
+
+ Job Event Subscribed Job Event
+
+
+ 'job-progress' 'job-progress'
+
+ 'job-completed' 'job-completed'
+
+ 'job-completed' 'job-state-changed'
+
+
+
+9.1.3 Additional Event Notification Content for Printer Events
+
+ This section lists the additional attributes that a Delivery Method
+ Document MUST specify for Printer Events. See Table 8.
+
+
+ Table 8 - Additional Event Notification Content for Printer Events
+
+
+
+ Source Value Sends Source Object
+
+
+ printer-state (type1 enum) MUST Printer
+
+ printer-state-reasons (1setOf type2 keyword) MUST Printer
+
+ printer-is-accepting-jobs (boolean) MUST Printer
+
+
+9.2 Content of Human Consumable Event Notification
+
+ This section defines the information that a Delivery Method MUST
+ mention in a Delivery Method Document when specifying the Human
+ Consumable Event Notifications contents or the value of the "notify-
+ text" attribute.
+
+ Such a Delivery Method MUST specify the following information and a
+ Printer SHOULD send it:
+
+ a)the Printer name (see Table 9)
+ b)the time of the Event (see Table 11)
+ c)for Printer Events only:
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 46]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ i) the Event (see Table 10) and/or Printer state information
+ (see Table 14)
+ d)for Job Events only:
+ i) the job identity (see Table 12)
+ ii) the Event (see Table 10) and/or Job state information (see
+ Table 13)
+
+ The subsections of this section specify the attributes that a Printer
+ MUST use to obtain this information.
+
+ A Delivery Method Document MUST specify additional information (if
+ any) that a Printer implementation sends in a Human Consumable Event
+ Notification or in the "notify-text" attribute.
+
+ A client MUST NOT request additional attributes via the "notify-
+ attributes" attribute because this attribute works only for Machine
+ Consumable Event Notifications.
+
+ Notification Recipients MUST NOT expect to be able to parse the Human
+ Consumable Event Notification contents or the value of the "notify-
+ text" attribute.
+
+ The next three sections define the attributes in Event Notification
+ Contents that are:
+
+ a) for all Events
+ b) for Job Events only
+ c) for Printer Events only
+
+9.2.1 Event Notification Content Common to All Events
+
+ This section lists the source of the information that a Delivery
+ Method MUST specify for all Events.
+
+ There is a separate table for each piece of information. Each row in
+ the table represents a source value for the information and the
+ values are listed in order of preference, with the first one being
+ the preferred one. An implementation SHOULD use the source value from
+ the earliest row in each table. It MAY use the source value from
+ another row instead, or it MAY combine the source values from several
+ rows. An implementation is free to determine the best way to present
+ this information.
+
+ In all tables of this section, all rows contain a "MAY" in order to
+ state that the Delivery Method specifies the conformance.
+
+ Table 9 lists the source of the information for the Printer Name. The
+ "printer-name" is more user-friendly unless the Notification
+ Recipient is in a place where the Printer name is not meaningful. For
+ example, an implementation could have the intelligence to send the
+
+
+Herriot, et al. Expires July 24, 2001 [page 47]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ value of the "printer-name" attribute to a Notification Recipient
+ that can access the Printer via value of the "printer-name" attribute
+ and otherwise send the value of the "notify-printer-uri" attribute.
+
+
+ Table 9 - Printer Name in Event Notification Content
+
+
+
+ Source Value Sends Source Object
+
+
+ printer-name (name(127)) MAY Printer
+
+ notify-printer-uri (uri) MAY Subscription
+
+
+
+
+ Table 10 lists the source of the information for the Event name. A
+ Printer MAY combine this information with state information described
+ for Jobs in Table 13 or for Printers in Table 14.
+
+
+ Table 10 - Event Name in Event Notification Content
+
+
+
+ Source Value Sends Source Object
+
+
+ notify-subscribed-event (type2 keyword) MAY Subscription
+
+
+
+ Table 11 lists the source of the information for the time that the
+ Event occurred. A Printer can send this value only if it supports the
+ Printer's "printer-current-time" attribute. If a Printer does not
+ support the "printer-current-time" attribute, it MUST NOT send the
+ "printer-up-time" value instead, since it is not an allowed option
+ for human consumable information.
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 48]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ Table 11 - Event Time in Event Notification Content
+
+
+
+ Source Value Sends Source Object
+
+
+ printer-current-time (dateTime) MAY Printer
+
+
+
+9.2.2 Additional Event Notification Content for Job Events
+
+ This section lists the source of the additional information that a
+ Delivery Method MUST specify for Job Events.
+
+ Table 12 lists the source of the information for the job name. The
+ "job-name" is likely more meaningful to a user than "job-id".
+
+
+ Table 12 - Job Name in Event Notification Content
+
+
+
+ Source Value Sends Source Object
+
+
+ job-name (name(MAX)) MAY Job
+
+ job-id (integer(1:MAX)) MAY Job
+
+
+
+ Table 13 lists the source of the information for the job state. If a
+ Printer supports the "job-state-message" and "job-detailed-state-
+ message" attributes, it SHOULD use those attributes for the job state
+ information, otherwise, it should fabricate such information from the
+ "job-state" and "job-state-reasons". For some Events, a Printer MAY
+ combine this information with Event information.
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 49]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ Table 13 - Job State in Event Notification Content
+
+
+
+ Source Value Sends Source
+ Object
+
+
+ job-state-message (text(MAX)) MAY Job
+
+ job-detailed-status-messages (1setOf text(MAX)) MAY Job
+
+ job-state (type1 enum) MAY Job
+
+ job-state-reasons (1setOf type2 keyword) MAY Job
+
+
+9.2.3 Additional Event Notification Content for Printer Events
+
+ This section lists the source of the additional information that a
+ Delivery Method MUST specify for Printer Events.
+
+ Table 14 lists the source of the information for the printer state.
+ If a Printer supports the "printer-state-message", it SHOULD use that
+ attribute for the job state information, otherwise it SHOULD
+ fabricate such information from the "printer-state" and "printer-
+ state-reasons". For some Events, a Printer MAY combine this
+ information with Event information.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 50]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ Table 14 - Printer State in Event Notification Content
+
+
+
+ Source Value Sends Source
+ Object
+
+
+ printer-state-message (text(MAX)) MAY Printer
+
+ printer-state (type1 enum) MAY Printer
+
+ printer-state-reasons (1setOf type2 keyword) MAY Printer
+
+ printer-is-accepting-jobs (boolean) MAY Printer
+
+
+10 Delivery Methods
+
+ A Delivery Method is the mechanism, i.e., protocol, by which the
+ Printer delivers an Event Notification to a Notification Recipient.
+ There are several potential Delivery Methods for Event Notifications,
+ standardized, as well as proprietary. This document does not define
+ any of these delivery mechanisms. Each Delivery Method MUST be
+ defined in a Delivery Method Document that is separate from this
+ document. New Delivery Methods will be created as needed using an
+ extension to the registration procedures defined in [RFC2911]. Such
+ documents are registered with IANA (see section 13).
+
+ The following sorts of Delivery Methods are expected:
+
+ - The Notification Recipient polls for Event Notifications at
+ intervals directed by the Printer
+
+ - The Printer sends Event Notifications to the Notification
+ Recipient using http as the transport.
+
+ - The Printer sends an email message.
+
+ This section specifies how to define a Delivery Method Document and
+ what to put in such a document.
+
+ A Delivery Method Document MUST contain an exact copy of the
+ following paragraph, caption and table. In addition, column 2 of the
+ table in the Delivery Method Document MUST contain answers to
+ questions in column 1 for the Delivery Method. Also, the Delivery
+ Method document MUST contain a reference to this document and call
+ that reference [ipp-ntfy] because the table contains an [ipp-ntfy]
+ reference.
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 51]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ If a Printer supports this Delivery Method, the following are its
+ characteristics.
+
+
+ Table 15 - Information about the Delivery Method
+
+
+
+ Document Method Conformance Delivery Method Realization
+ Requirement
+
+
+ 1.What is the URL scheme name for the
+ Delivery Method?
+
+ 2.Is the Delivery Method REQUIRED,
+ RECOMMENDED, or OPTIONAL for an IPP
+ Printer to support?
+
+ 3.What transport and delivery
+ protocols does the Printer use to
+ deliver the Event Notification
+ Content, i.e., what is the entire
+ network stack?
+
+ 4.Can several Event Notifications be
+ combined into a Compound Event
+ Notification?
+
+ 5.Is the Delivery Method initiated by
+ the Notification Recipient (pull),
+ or by the Printer (push)?
+
+ 6.Is the Event Notification content
+ Machine Consumable or Human
+ Consumable?
+
+ 7.What section in this document
+ answers the following question? For
+ a Machine Consumable Event
+ Notification, what is the
+ representation and encoding of
+ values defined in section 9.1 of
+ [ipp-ntfy] and the conformance
+ requirements thereof? For a Human
+ Consumable Event Notification, what
+ is the representation and encoding
+ of pieces of information defined in
+ section 0 of [ipp-ntfy] and the
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 52]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+
+ conformance requirements thereof?
+
+ 8.What are the latency and
+ reliability of the transport and
+ delivery protocol?
+
+ 9.What are the security aspects of
+ the transport and delivery
+ protocol, e.g., how it is handled
+ in firewalls?
+
+ 10. What are the content length
+ restrictions?
+
+ 11. What are the additional values
+ or pieces of information that a
+ Printer sends in an Event
+ Notification content and the
+ conformance requirements thereof?
+
+ 12. What are the additional
+ Subscription Template and/or
+ Subscription Description attributes
+ and the conformance requirements
+ thereof?
+
+ 13. What are the additional Printer
+ Description attributes and the
+ conformance requirements thereof?
+
+
+
+11 Operations for Notification
+
+ This section defines all of the operations for Notification. Section
+ 7.1 assigns the "operation-id" for each operation. The following two
+ sub-sections define Subscription Creation Operations, and other
+ operations.
+
+11.1 Subscription Creation Operations
+
+ This section defines the Subscription Creation Operations. The first
+ section on Create-Job-Subscriptions gives most of the information.
+ The other Subscription Creation Operations refer to the section on
+ Create-Job-Subscriptions, even though the Create-Job-Subscriptions
+ operation is the only OPTIONAL operation in this document (see
+ section 12).
+
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 53]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ A Printer MUST support Create-Printer-Subscriptions and the
+ Subscription Template Attributes Group in Job Creation operations. It
+ MAY support Create-Job-Subscriptions operations.
+
+11.1.1 Create-Job-Subscriptions Operation
+
+ The operation creates one or more Per-Job Subscription Objects. The
+ client supplies one or more Subscription Template Attributes Groups
+ each containing one or more of Subscription Template Attributes
+ (defined in section 5.3).
+
+ Except for errors, the Printer MUST create exactly one Per-Job
+ Subscription Object from each Subscription Template Attributes Group
+ in the request, even if the newly created Subscription Object would
+ have identical behavior to some existing Subscription Object. The
+ Printer MUST associate each newly created Per-Job Subscription Object
+ with the target Job, which is specified by the "notify-job-id"
+ operation attribute.
+
+ The Printer MUST accept the request in any of the target job's 'not-
+ completed' states, i.e., 'pending', 'pending-held', 'processing', or
+ 'processing-stopped'. The Printer MUST NOT change the job's "job-
+ state" attribute because of this operation. If the target job is in
+ any of the 'completed' states, i.e., 'completed', 'canceled', or
+ 'aborted, then the Printer MUST reject the request and return the
+ 'client-error-not-possible' status code; the response MUST NOT
+ contain any Subscription Attribute Groups.
+
+ Access Rights: To create Per-Job Subscription Objects, the
+ authenticated user (see [RFC2911] section 8.3) performing this
+ operation MUST either be the job owner or have Operator or
+ Administrator access rights for this Printer (see [RFC2911] sections
+ 1 and 8.5). Otherwise the Printer MUST reject the operation and
+ return: the 'client-error-forbidden', 'client-error-not-
+ authenticated', or 'client-error-not-authorized' status code as
+ appropriate.
+
+11.1.1.1 Create-Job-Subscriptions Request
+
+ The following groups of attributes are part of the Create-Job-
+ Subscriptions Request:
+
+ Group 1: Operation Attributes
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in [RFC2911] section 3.1.4.1.
+
+
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 54]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ Target:
+ The "printer-uri" attribute which defines the target for this
+ operation as described in [RFC2911] section 3.1.5.
+
+ Requesting User Name:
+ The "requesting-user-name" attribute SHOULD be supplied by the
+ client as described in [RFC2911] section 8.3.
+
+ notify-job-id (integer(1:MAX)):
+ The client MUST supply this attribute and it MUST specify the
+ Job object to associate the Per-Job Subscription with. The
+ value of "notify-job-id" MUST be the value of the "job-id" of
+ the associated Job object. If the client does not supply this
+ attribute, the Printer MUST reject this request with a 'client-
+ error-bad-request' status code.
+
+ Group 2-N: Subscription Template Attributes
+
+ For each occurrence of this group:
+
+ The client MUST supply one or more Subscription Template
+ Attributes in any order. See section 5.3 for a description of
+ each such attribute. See section 5.2 for details on processing
+ these attributes.
+
+11.1.1.2 Create-Job-Subscriptions Response
+
+ The Printer MUST return to the client the following sets of
+ attributes as part of a Create-Job-Subscriptions response:
+
+ Group 1: Operation Attributes
+
+ Status Message:
+ In addition to the REQUIRED status code returned in every
+ response, the response OPTIONALLY includes a "status-message"
+ (text(255)) and/or a "detailed-status-message" (text(MAX))
+ operation attribute as described in [RFC2911] sections 13 and
+ 31.6.
+
+ In this group, the Printer can return any status codes defined
+ in [RFC2911] and section 16. The following is a description of
+ the important status codes:
+
+ successful-ok: the Printer created all Subscription Objects
+ requested.
+ successful-ok-ignored-subscriptions: the Printer created some
+ Subscription Objects requested but some failed. The
+ Subscription Attributes Groups with a "notify-status-code"
+ attribute are the ones that failed.
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 55]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ client-error-ignored-all-subscriptions: the Printer created no
+ Subscription Objects requested and all failed. The
+ Subscription Attributes Groups with a "notify-status-code"
+ attribute are the ones that failed
+ client-error-not-possible: For this operation and other Per-Job
+ Subscription operations, this error can occur because the
+ specified Job has already completed.
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in [RFC2911] section 3.1.4.2.
+
+ Group 2: Unsupported Attributes
+
+ See [RFC2911] section 3.1.7 for details on returning
+ Unsupported Attributes. This group does not contain any
+ unsupported Subscription Template Attributes; they are returned
+ in the Subscription Attributes Group (see below).
+
+ Group 3-N: Subscription Attributes
+
+ These groups MUST be returned unless the Printer is unable to
+ interpret the entire request, e.g., the "status-code" parameter
+ returned in Group 1 has the value: 'client-error-bad-request'.
+
+ "notify-status-code" (type2 enum):
+ Indicates the status of this subscription (see section 17 for
+ the status code definitions). Section 5.2 defines when this
+ attribute MUST be present in this group.
+
+ See section 5.2 for details on the contents of each occurrence
+ of this group.
+
+11.1.2 Create-Printer-Subscriptions operation
+
+ The operation is identical to Create-Job-Subscriptions with
+ exceptions noted in this section.
+
+ The operation creates Per-Printer Subscription Objects instead of
+ Per-Job Subscription Objects, and associates each newly created Per-
+ Printer Subscription Object with the Printer specified by the
+ operation target rather than with a specific Job.
+
+ The Printer MUST accept the request in any of its states, i.e.,
+ 'idle', 'processing', or 'stopped'. The Printer MUST NOT change its
+ "printer-state" attribute because of this operation.
+
+ Access Rights: To create Per-Printer Subscription Objects, the
+ authenticated user (see [RFC2911] section 8.3) performing this
+ operation MUST have Operator or Administrator access rights for this
+
+
+Herriot, et al. Expires July 24, 2001 [page 56]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ Printer (see [RFC2911] sections 1 and 8.5). Otherwise, the Printer
+ MUST reject the operation and return: the 'client-error-forbidden',
+ 'client-error-not-authenticated', or 'client-error-not-authorized'
+ status code as appropriate.
+
+11.1.2.1 Create-Printer-Subscriptions Request
+
+ The groups are identical to the Create-Job-Subscriptions (see section
+ 11.1.1.1) except that the Operation Attributes group MUST NOT contain
+ the "notify-job-id" attribute. If the client does supply the
+ "notify-job-id" attribute, then the Printer MUST treat it as any
+ other unsupported Operation attribute and MUST return it in the
+ Unsupported Attributes group.
+
+11.1.2.2 Create-Printer-Subscriptions Response
+
+ The groups are identical to the Create-Job-Subscriptions (see section
+ 11.1.1.2).
+
+
+11.1.3 Job Creation Operation - Extensions for Notification
+
+ This document extends the Job Creation operations to create
+ Subscription Objects as a part of the operation.
+
+ The operation is identical to Create-Job-Subscriptions with
+ exceptions noted in this section.
+
+ Unlike the Create-Job-Subscriptions operation, this operation
+ associates the newly created Subscription Objects with the Job object
+ created by this operation. The operation succeeds if and only if the
+ Job creation succeeds. If the Printer does not create some or all of
+ the requested Subscription Objects, the Printer MUST return a
+ 'successful-ok-ignored-subscriptions' status-code instead of a
+ 'successful-ok' status-code, but the Printer MUST NOT reject the
+ operation because of a failure to create Subscription Objects.
+
+ If the operation includes a Job Template group, the client MUST
+ supply it after the Operation Attributes group and before the first
+ Subscription Template Attributes Group.
+
+ If a Printer does not support this Notification specification, then
+ it MUST treat the Subscription Attributes Group like an unknown group
+ and ignore it (see [RFC2911] section 5.2.2). Because the Printer
+ ignores the Subscription Attributes Group, it doesn't return them in
+ the response either, thus indicating to the client that the Printer
+ doesn't support Notification.
+
+ Access Rights: To create Per-Job Subscription Objects, the
+ authenticated user (see [RFC2911] section 8.3) performing this
+
+
+Herriot, et al. Expires July 24, 2001 [page 57]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ operation MUST either have permission to create Jobs on the Printer.
+ Otherwise the Printer MUST reject the operation and return: the
+ 'client-error-forbidden', 'client-error-not-authenticated', or
+ 'client-error-not-authorized' status code as appropriate.
+
+11.1.3.1 Job Creation Request
+
+ The groups for this operation are sufficiently different from the
+ Create-Job-Subscriptions operation that they are all presented here.
+ The following groups of attributes are supplied as part of a Job
+ Creation Request:
+
+ Group 1: Operation Attributes
+
+ Same as defined in [RFC2911] for Print-Job, Print-URI, and
+ Create-Job requests.
+ Group 2: Job Template Attributes
+
+ The client OPTIONALLY supplies a set of Job Template attributes
+ as defined in [RFC2911] section 4.2.
+ Group 3 to N: Subscription Template Attributes
+
+ The same as Group 2-N in Create-Job-Subscriptions. See section
+ 11.1.1.1.
+ Group N+1: Document Content (Print-Job only)
+
+ The client MUST supply the document data to be processed.
+
+11.1.3.2 Job Creation Response
+
+ The Printer MUST return to the client the following sets of
+ attributes as part of a Print-Job, Print-URI, and Create-Job
+ Response:
+
+ Group 1: Operation Attributes
+
+
+ Status Message:
+
+ As defined in [RFC2911] for Print-Job, Print-URI, and Create-
+ Job requests.
+
+ In this group, the Printer can return any status codes defined
+ in [RFC2911] and section 16. The following is a description of
+ the important status codes:
+
+ successful-ok: the Printer created the Job and all Subscription
+ Objects requested.
+ successful-ok-ignored-subscriptions: the Printer created the Job
+ and not all of the Subscription Objects requested. This
+
+
+Herriot, et al. Expires July 24, 2001 [page 58]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ status-code hides 'successful-ok-xxx' status-codes that could
+ reveal problems in Job creation. The Printer MUST not return
+ the 'client-error-ignored-all-subscriptions' status code for
+ Job Creation operations because the Printer returns an error
+ status-code only when it fails to create a Job.
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in [RFC2911] section 3.1.4.2.
+
+ Group 2: Unsupported Attributes
+
+ See [RFC2911] section 3.1.7 for details on returning
+ Unsupported Attributes. This group does not contain any
+ unsupported Subscription Template Attributes; they are returned
+ in the Subscription Attributes Group (see below).
+
+ Group 3: Job Object Attributes
+
+ As defined in [RFC2911] for Print-Job, Print-URI, and Create-
+ Job requests.
+
+ Group 4 to N: Subscription Attributes
+
+ These groups MUST be returned if and only if the client
+ supplied Subscription Template Attributes and the operation was
+ accepted.
+
+ See section 5.2 for details on the contents of each occurrence
+ of this group.
+
+11.2 Other Operations
+
+ This section defines other operations on Subscription objects.
+
+11.2.1 Validate-Job Operation - Extensions for Notification
+
+ A client can test whether one or more Subscription Objects could be
+ created using the Validate-Job operation. The client supplies one or
+ more Subscription Template Attributes Groups (defined in section
+ 5.3), just as in a Job Creation request.
+
+ A Printer MUST support this extension to this operation.
+
+ The Printer MUST accept requests that are identical to the Job
+ Creation request defined in section 11.1.3.1, except that the request
+ MUST not contain document data.
+
+ The Printer MUST return the same groups and attributes as the Print-
+ Job operation (section 11.1.3.1) with the following exceptions. The
+
+
+Herriot, et al. Expires July 24, 2001 [page 59]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ Printer MUST NOT return a Job Object Attributes Group because no Job
+ is created. The Printer MUST NOT return the "notify-subscription-id"
+ attribute in any Subscription Attribute Group because no Subscription
+ Object is created.
+
+ If the Printer would succeed in creating a Subscription Object, the
+ corresponding Subscription Attributes Group either has no 'status-
+ code' attribute or a 'status-code' attribute with a value of
+ 'successful-ok-too-many-events' or 'successful-ok-ignored-or-
+ substituted-attributes' (see sections 5.2 and 17). The status-codes
+ have the same meaning as in Job Creation except the results state
+ what "would happen".
+
+ The Printer MUST validate Subscription Template Attributes Groups in
+ the same manner as the Job Creation operations.
+
+11.2.2 Get-Printer-Attributes - Extensions for Notification
+
+ This operation is extended so that it returns Printer attributes
+ defined in this document.
+
+ A Printer MUST support this extension to this operation.
+
+ In addition to the requirements of [RFC2911] section 3.2.5, a Printer
+ MUST support the following additional values for the "requested-
+ attributes" Operation attribute in this operation and return such
+ attributes in the Printer Object Attributes group of its response.
+
+ 1.Subscription Template Attributes: Each supported attribute in
+ column 2 of Table 1.
+
+ 2.New Printer Description Attributes: Each supported attribute in
+ section 6.
+
+ 3.New Group Name: The 'subscription-template' group name, which
+ names all supported Subscription Template Attribute in column 2
+ of Table 1. This group name is also used in the Get-
+ Subscription-Attributes and Get-Subscriptions operation with an
+ analogous meaning.
+
+ 4.Extended Group Name: The 'all' group name, which names all
+ Printer attributes according to [RFC2911] section 3.2.5. In
+ this extension 'all' names all attributes specified in [RFC2911]
+ plus those named in items 1 and 2 of this list.
+
+11.2.3 Get-Subscription-Attributes operation
+
+ This operation allows a client to request the values of the
+ attributes of a Subscription Object.
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 60]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ A Printer MUST support this operation.
+
+ This operation is almost identical to the Get-Job-Attributes
+ operation (see [RFC2911] section 3.3.4). The only differences are
+ that the operation is directed at a Subscription Object rather than a
+ Job object, and the returned attribute group contains Subscription
+ Object attributes rather than Job object attributes.
+
+11.2.3.1 Get-Subscription-Attributes Request
+
+ The following groups of attributes are part of the Get-Subscription-
+ Attributes request:
+
+ Group 1: Operation Attributes
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section [RFC2911] 3.1.4.1.
+
+ Target:
+ The "printer-uri" attribute which defines the target for this
+ operation as described in [RFC2911] section 3.1.5.
+
+ "notify-subscription-id" (integer (1:MAX)):
+ The client MUST supply this attribute. The Printer MUST
+ support this attribute. This attribute specifies the
+ Subscription Object from which the client is requesting
+ attributes. If the client omits this attribute, the Printer
+ MUST reject this request with the 'client-error-bad-request'
+ status code.
+
+ Requesting User Name:
+ The "requesting-user-name" attribute SHOULD be supplied by the
+ client as described in [RFC2911] section 8.3.
+
+ "requested-attributes" (1setOf keyword):
+ The client OPTIONALLY supplies this attribute. The Printer
+ MUST support this attribute. This attribute specifies the
+ attributes of the specified Subscription Object that the
+ Printer MUST return in the response. Each value of this
+ attribute is either an attribute name (defined in sections 5.3
+ and 5.4) or an attribute group name. The attribute group names
+ are:
+
+ - 'subscription-template': all attributes that are both defined
+ in section 5.3 and present on the specified Subscription
+ Object (column 1 of Table 1).
+ - 'subscription-description': all attributes that are both
+ defined in section 5.4 and present on the specified
+ Subscription Object (Table 2).
+
+
+Herriot, et al. Expires July 24, 2001 [page 61]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ - 'all': all attributes that are present on the specified
+ Subscription Object.
+ A Printer MUST support all these group names.
+
+ If the client omits this attribute, the Printer MUST respond as
+ if this attribute had been supplied with a value of 'all'.
+
+11.2.3.2 Get-Subscription-Attributes Response
+
+ The Printer returns the following sets of attributes as part of the
+ Get-Subscription-Attributes Response:
+
+ Group 1: Operation Attributes
+
+ Status Message:
+ Same as [RFC2911].
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in [RFC2911] section 3.1.4.2. The
+ "attributes-natural-language" MAY be the natural language of
+ the Subscription Object, rather than the one requested.
+
+ Group 2: Unsupported Attributes
+
+ See [RFC2911] section 3.1.7 for details on returning
+ Unsupported Attributes.
+
+ The response NEED NOT contain the "requested-attributes"
+ operation attribute with any supplied values (attribute
+ keywords) that were requested by the client but are not
+ supported by the Printer. If the Printer does return
+ unsupported attributes referenced in the "requested-attributes"
+ operation attribute and that attribute included group names,
+ such as 'all', the unsupported attributes MUST NOT include
+ attributes described in the standard but not supported by the
+ implementation.
+
+ Group 3: Subscription Attributes
+
+ This group contains a set of attributes with their current
+ values. Each attribute in this group:
+
+ a)MUST be specified by the "requested-attributes" attribute
+ in the request, AND
+
+ b)MUST be present on the specified Subscription Object AND
+
+ c)MUST NOT be restricted by the security policy in force.
+ For example, a Printer MAY prohibit a client who is not the
+
+
+Herriot, et al. Expires July 24, 2001 [page 62]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ creator of a Subscription Object from seeing some or all of
+ its attributes. See [RFC2911] section 8.
+
+ The Printer can return the attributes of the Subscription
+ Object in any order. The client MUST accept the attributes in
+ any order.
+
+11.2.4 Get-Subscriptions operation
+
+ This operation allows a client to retrieve the values of attributes
+ of all Subscription Objects belonging to a Job or Printer.
+
+ A Printer MUST supported this operation.
+
+ This operation is similar to the Get-Subscription-Attributes
+ operation, except that this Get-Subscriptions operation returns
+ attributes from possibly more than one object.
+
+ This operation is similar to the Get-Jobs operation (see [RFC2911]
+ section 3.2.6), except that the operation returns Subscription
+ Objects rather than Job objects.
+
+11.2.4.1 Get-Subscriptions Request
+
+ The following groups of attributes are part of the Get-Subscriptions
+ request:
+
+ Group 1: Operation Attributes
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in [RFC2911] section 3.1.4.1.
+
+ Target:
+ The "printer-uri" attribute which defines the target for this
+ operation as described in [RFC2911] section 3.1.5.
+
+ Requesting User Name:
+ The "requesting-user-name" attribute SHOULD be supplied by the
+ client as described in [RFC2911] section 8.3.
+
+ "notify-job-id" (integer(1:MAX)):
+ If the client specifies this attribute, the Printer returns the
+ specified attributes of all Per-Job Subscription Objects
+ associated with the Job whose "job-id" attribute value equals
+ the value of this attribute. If the client does not specify
+ this attribute, the Printer returns the specified attributes of
+ all Per-Printer Subscription Objects. Note: there is no way to
+ get all Per-Job Subscriptions.
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 63]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ "limit" (integer(1:MAX)):
+ The client OPTIONALLY supplies this attribute. The Printer
+ MUST support this attribute. It is an integer value that
+ determines the maximum number of Subscription Objects that a
+ client will receive from the Printer even if the "my-
+ subscriptions" attribute constrains which Subscription Objects
+ are returned. The limit is a "stateless limit" in that if the
+ value supplied by the client is 'N', then only the first 'N'
+ Subscription Objects are returned in the Get-Subscriptions
+ Response. There is no mechanism to allow for the next 'M'
+ Subscription Objects after the first 'N' Subscription Objects.
+ If the client does not supply this attribute, the Printer
+ responds with all applicable Subscription Objects.
+
+ "requested-attributes" (1setOf type2 keyword):
+ The client OPTIONALLY supplies this attribute. The Printer
+ MUST support this attribute. This attribute specifies the
+ attributes of the specified Subscription Objects that the
+ Printer MUST return in the response. Each value of this
+ attribute is either an attribute name (defined in sections 5.3
+ and 5.4) or an attribute group name (defined in section
+ 11.2.3.1). If the client omits this attribute, the Printer MUST
+ respond as if the client had supplied this attribute with the
+ one value: 'notify-subscription-id'.
+
+ "my-subscriptions" (boolean):
+ The client OPTIONALLY supplies this attribute. The Printer
+ MUST support this attribute. If the value is 'false', the
+ Printer MUST consider the Subscription Objects from all users
+ as candidates. If the value is 'true', the Printer MUST return
+ the Subscription Objects created by the requesting user of this
+ request. If the client does not supply this attribute, the
+ Printer MUST respond as if the client had supplied the
+ attribute with a value of 'false'. The means for
+ authenticating the requesting user and matching the
+ Subscription Objects is similar to that for Jobs which is
+ described in [RFC2911] section 8.
+
+11.2.4.2 Get-Subscriptions Response
+
+ The Printer returns the following sets of attributes as part of the
+ Get-Subscriptions Response:
+
+ Group 1: Operation Attributes
+
+ Status Message:
+ Same as [RFC2911].
+
+
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 64]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in [RFC2911] section 3.1.4.2.
+
+ Group 2: Unsupported Attributes
+
+ Same as for Get-Subscription-Attributes.
+
+ Groups 3 to N: Subscription Attributes
+
+ The Printer responds with one Subscription Attributes Group for
+ each requested Subscription Object (see the "notify-job-id"
+ attribute in the Operation Attributes Group of this operation).
+
+ The Printer returns Subscription Objects in any order.
+
+ If the "limit" attribute is present in the Operation Attributes
+ group of the request, the number of Subscription Attributes
+ Groups in the response MUST NOT exceed the value of the "limit"
+ attribute.
+
+ It there are no Subscription Objects associated with the
+ specified Job or Printer, the Printer MUST return zero
+ Subscription Attributes Groups and it MUST NOT treat this case
+ as an error, i.e., the status-code MUST be 'successful-ok'
+ unless something else causes the status code to have some other
+ value.
+
+ See the Group 3 response (Subscription Attributes Group) of the
+ Get-Subscription-Attributes operation (section 11.2.3.2) for
+ the attributes that a Printer returns in this group.
+
+11.2.5 Renew-Subscription operation
+
+ This operation allows a client to request the Printer to extend the
+ lease on a Per-Printer Subscription Object.
+
+ The Printer MUST support this operation.
+
+ The Printer MUST accept this request for a Per-Printer Subscription
+ Object in any of the target Printer's states, i.e., 'idle',
+ 'processing', or 'stopped', but MUST NOT change the Printer's
+ "printer-state" attribute.
+
+ The Printer MUST reject this request for a Per-Job Subscription
+ Object because it has no lease (see section 5.4.3). The status code
+ returned MUST be 'client-error-not-possible'.
+
+ Access Rights: The authenticated user (see [RFC2911] section 8.3)
+ performing this operation MUST either be the owner of the Per-Printer
+
+
+Herriot, et al. Expires July 24, 2001 [page 65]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ Subscription Object or have Operator or Administrator access rights
+ for the Printer (see [RFC2911] sections 1 and 8.5). Otherwise, the
+ Printer MUST reject the operation and return: the 'client-error-
+ forbidden', 'client-error-not-authenticated', or 'client-error-not-
+ authorized' status code as appropriate.
+
+11.2.5.1 Renew-Subscription Request
+
+ The following groups of attributes are part of the Renew-Subscription
+ Request:
+
+ Group 1: Operation Attributes
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in [RFC2911] section 3.1.4.1.
+
+ Target:
+ The "printer-uri" attribute which defines the target for this
+ operation as described in [RFC2911] section 3.1.5.
+
+ "notify-subscription-id" (integer (1:MAX)):
+ The client MUST supply this attribute. The Printer MUST
+ support this attribute. This attribute specifies the Per-
+ Printer Subscription Object whose lease the Printer MUST renew.
+ If the client omits this attribute, the Printer MUST reject
+ this request with the 'client-error-bad-request' status code.
+
+ Requesting User Name:
+ The "requesting-user-name" (name(MAX)) attribute SHOULD be
+ supplied by the client as described in [RFC2911] section 8.3.
+
+ Group 2: Subscription Template Attributes
+
+
+ "notify-lease-duration" (integer(0:MAX)):
+ The client MAY supply this attribute. It indicates the number
+ of seconds to renew the lease for the specified Subscription
+ Object. A value of 0 requests an infinite lease (which MAY
+ require Operator access rights). If the client omits this
+ attribute, the Printer MUST use the value of the Printer's
+ "notify-lease-duration-default" attribute. See section 5.3.7
+ for more details.
+
+11.2.5.2 Renew-Subscription Response
+
+ The Printer returns the following sets of attributes as part of the
+ Renew-Subscription Response:
+
+ Group 1: Operation Attributes
+
+
+Herriot, et al. Expires July 24, 2001 [page 66]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ Status Message:
+ Same as [RFC2911].
+
+ The following are some of the status codes returned:
+
+ successful-ok: The operation successfully renewed the lease on the
+ Subscription Object for the requested duration..
+ successful-ok-ignored-or-substituted-attributes: The operation
+ successfully renewed the lease on the Subscription Object for
+ some duration other than the amount requested.
+ client-error-not-possible: The operation failed because the
+ "notify-subscription-id" Operation attribute identified a Per-
+ Job Subscription Object.
+ client-error-not-found: The operation failed because the "notify-
+ subscription-id" Operation attribute identified a non-existent
+ Subscription Object.
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in [RFC2911] section 3.1.4.2. The
+ "attributes-natural-language" MAY be the natural language of
+ the Subscription Object, rather than the one requested.
+
+ Group 2: Unsupported Attributes
+
+ See [RFC2911] section 3.1.7 for details on returning
+ Unsupported Attributes.
+
+ Group 3: Subscription Attributes
+
+ The Printer MUST return the following Subscription Attribute:
+
+ "notify-lease-duration" (integer(0:MAX)):
+ The value of this attribute MUST be the number of seconds that
+ the Printer has granted for the lease of the Subscription
+ Object (see section 5.3.7 for details, such as the value of
+ this attribute when the Printer doesn't support the requested
+ value).
+
+
+
+11.2.6 Cancel-Subscription operation
+
+ This operation allows a client to delete a Subscription Object and
+ stop the Printer from sending more Event Notifications. Once
+ performed, there is no way to reference the Subscription Object.
+
+ A Printer MUST supported this operation.
+
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 67]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ The Printer MUST accept this request in any of the target Printer's
+ states, i.e., 'idle', 'processing', or 'stopped', but MUST NOT change
+ the Printer's "printer-state" attribute.
+
+ If the specified Subscription Object is a Per-Job Subscription
+ Object, the Printer MUST accept this request in any of the target
+ Job's states, but MUST NOT change the Job's "job-state" attribute or
+ affect the Job.
+
+ Access Rights: The authenticated user (see [RFC2911] section 8.3)
+ performing this operation MUST either be the owner of the
+ Subscription Object or have Operator or Administrator access rights
+ for the Printer (see [RFC2911] sections 1 and 8.5). Otherwise, the
+ Printer MUST reject the operation and return: the 'client-error-
+ forbidden', 'client-error-not-authenticated', or 'client-error-not-
+ authorized' status code as appropriate.
+
+ Note: There is no way to change any attributes on a Subscription
+ Object, except the "notify-lease-duration" attribute (using the
+ Renew-Subscription operation). In order to change other attributes,
+ a client performs a Subscription Creation Operation and Cancel-
+ Subscription operation on the old Subscription Object. If the client
+ wants to avoid missing Event Notifications, it performs the
+ Subscription Creation Operation first. If this order would create too
+ many Subscription Objects on the Printer, the client reverses the
+ order.
+
+11.2.6.1 Cancel-Subscription Request
+
+ The following groups of attributes are part of the Cancel-
+ Subscription Request:
+
+ Group 1: Operation Attributes
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in [RFC2911] section 3.1.4.1.
+
+ Target:
+ The "printer-uri" attribute which defines the target for this
+ operation as described in [RFC2911] section 3.1.5.
+
+ "notify-subscription-id" (integer (1:MAX)):
+ The client MUST supply this attribute. The Printer MUST
+ support this attribute. This attribute specifies the
+ Subscription Object that the Printer MUST cancel. If the client
+ omits this attribute, the Printer MUST reject this request with
+ the 'client-error-bad-request' status code.
+
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 68]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ Requesting User Name:
+ The "requesting-user-name" attribute SHOULD be supplied by the
+ client as described in [RFC2911] section 8.3.
+
+11.2.6.2 Cancel-Subscription Response
+
+ The Printer returns the following sets of attributes as part of the
+ Cancel-Subscription Response:
+
+ Group 1: Operation Attributes
+
+ Status Message:
+ Same as [RFC2911].
+
+ The following are some of the status codes returned:
+
+ successful-ok: The operation successfully canceled (deleted) the
+ Subscription Object..
+ client-error-not-found: The operation failed because the "notify-
+ subscription-id" Operation attribute identified a non-existent
+ Subscription Object.
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in [RFC2911] section 3.1.4.2. The
+ "attributes-natural-language" MAY be the natural language of
+ the Subscription Object, rather than the one requested.
+
+ Group 2: Unsupported Attributes
+
+ See [RFC2911] section 3.1.7 for details on returning
+ Unsupported Attributes.
+
+
+12 Conformance Requirements
+
+ It is OPTIONAL to implement this Event Notification specification.
+
+ If this Event Notification specification is implemented, Printers
+ MUST:
+
+ 1.meet the Conformance Requirements detailed in section 5 of
+ [RFC2911].
+
+ 2.support the Subscription Template Attributes Group in requests
+ and the Subscription Attributes Group in responses.
+
+ 3.support all of the following attributes:
+
+ a. REQUIRED Subscription Object attributes in section 5.
+
+
+Herriot, et al. Expires July 24, 2001 [page 69]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ b. REQUIRED Printer Description object attributes in section 6.
+ c. REQUIRED attributes in Event Notification content in section
+ 8.
+
+ 4.send Event Notifications that conform to the requirements of the
+ Delivery Method Document for each supported Delivery Method (the
+ conformance requirements for Delivery Method Documents is
+ specified in section 10).
+
+ 5.support all operations as described in Table 16:
+
+
+ Table 16 - Conformance Requirements for Operations
+
+
+
+ Operation Conformance
+ requirements
+
+
+ Create-Printer-Subscriptions (section 11.1.2) REQUIRED
+
+ Create-Job-Subscriptions (section 11.1.1) OPTIONAL
+
+ Get-Subscription-Attributes (section 11.2.2) REQUIRED
+
+ Get-Subscriptions (section 11.2.4) REQUIRED
+
+ Renew-Subscription (section 11.2.5) REQUIRED
+
+ Cancel-Subscription (section 11.2.6) REQUIRED
+
+
+
+13 IANA Considerations
+
+ This section contains the exact information for IANA to add to the
+ IPP Registries according to the procedures defined in RFC 2911
+ [RFC2911] section 6.
+
+ Note to RFC Editors: Replace RFC NNNN below with the RFC number
+ for this document, so that it accurately reflects the content of
+ the information for the IANA Registry.
+
+13.1 Attribute Registrations
+
+ The attributes defined in this document will be published by IANA
+ according to the procedures in RFC 2911 [RFC2911] section 6.2 with
+ the following path:
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 70]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ ftp.isi.edu/iana/assignments/ipp/attributes/
+
+ The registry entry will contain the following information:
+
+ Subscription Template attributes: Ref. Section:
+ notify-recipient-uri (uri) RFC NNNN 5.3.1
+ notify-events (1setOf type2 keyword) RFC NNNN 5.3.2
+ notify-attributes (1setOf type2 keyword) RFC NNNN 5.3.3
+ notify-user-data (octetString(63)) RFC NNNN 5.3.4
+ notify-charset (charset) RFC NNNN 5.3.5
+ notify-natural-language (naturalLanguage) RFC NNNN 5.3.6
+ notify-lease-duration (integer(0:67108863)) RFC NNNN 5.3.7
+ notify-time-interval (integer(0:MAX)) RFC NNNN 5.3.8
+
+ Subscription Description Attributes:
+ notify-subscription-id (integer (1:MAX))) RFC NNNN 5.4.1
+ notify-sequence-number (integer (0:MAX))) RFC NNNN 5.4.2
+ notify-lease-expiration-time (integer(0:MAX))) RFC NNNN 5.4.3
+ notify-printer-up-time (integer(1:MAX))) RFC NNNN 5.4.4
+ notify-printer-uri (uri)) RFC NNNN 5.4.5
+ notify-job-id (integer(1:MAX))) RFC NNNN 5.4.6
+ notify-subscriber-user-name (name(MAX))) RFC NNNN 5.4.7
+
+ Printer Description Attributes:
+ printer-state-change-time (integer(1:MAX))) RFC NNNN 6.1
+ printer-state-change-date-time (dateTime)) RFC NNNN 6.2
+
+ Attributes Only in Event Notifications
+ notify-subscribed-event (type2 keyword) RFC NNNN 8.1
+ notify-text (text(MAX)) RFC NNNN 8.2
+
+13.2 Keyword Attribute Value Registrations
+
+ The keyword attribute values defined in this document will be
+ published by IANA according to the procedures in RFC 2911 [RFC2911]
+ section 6.1 with the following path:
+
+ ftp.isi.edu/iana/assignments/ipp/attribute-values/
+
+ The registry entry will contain the following information:
+
+ Keyword Attribute Values: Ref. Section:
+ New Values for Existing Printer Description Attributes
+ operations-supported (1setOf type2 enum) RFC NNNN 7.1
+
+13.3 Operation Registrations
+
+ The operations defined in this document will be published by IANA
+ according to the procedures in RFC 2911 [RFC2911] section 6.4 with
+ the following path:
+
+
+Herriot, et al. Expires July 24, 2001 [page 71]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ ftp.isi.edu/iana/assignments/ipp/operations/
+
+ The registry entry will contain the following information:
+
+ Operations: Ref. Section:
+ Create-Job-Subscriptions Operation RFC NNNN 11.1.1
+ Create-Printer-Subscriptions operation RFC NNNN 11.1.2
+ Job Creation Operations - Extensions RFC NNNN 11.1.3
+ Validate-Job Operation - Extensions RFC NNNN 11.2.1
+ Get-Printer-Attributes - Extensions RFC NNNN 11.2.2
+ Get-Subscription-Attributes operation RFC NNNN 11.2.3
+ Get-Subscriptions operation RFC NNNN 11.2.4
+ Renew-Subscription operation RFC NNNN 11.2.5
+ Cancel-Subscription operation RFC NNNN 11.2.6
+
+13.4 Status code Registrations
+
+ The status codes defined in this document will be published by IANA
+ according to the procedures in RFC 2911 [RFC2911] section 6.6 with
+ the following path:
+
+ ftp.isi.edu/iana/assignments/ipp/status-codes/
+
+ The registry entry will contain the following information:
+
+ Status codes: Ref. Section:
+ successful-ok-ignored-subscriptions (0x0003) RFC NNNN 16.1
+ client-error-ignored-all-subscriptions (0x0414) RFC NNNN 16.2
+
+ Status Codes in Subscription Attributes Groups:
+ client-error-uri-scheme-not-supported (0x040C) RFC NNNN 17.1
+ client-error-too-many-subscriptions (0x0415) RFC NNNN 17.2
+ successful-ok-too-many-events (0x0005) RFC NNNN 17.3
+ successful-ok-ignored-or-substituted-attributes (0x0001)
+ RFC NNNN 17.4
+
+13.5 Attribute Group tag Registrations
+
+ The attribute group tags defined in this document will be published
+ by IANA according to the procedures in RFC 2911 [RFC2911] section 6.5
+ with the following path:
+
+ ftp.isi.edu/iana/assignments/ipp/attribute-group-tags/
+
+ The registry entry will contain the following information:
+
+ Attribute Group Tags: Ref. Section:
+ subscription-attributes-tag RFC NNNN 18
+ event-notification-attributes-tag RFC NNNN 18
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 72]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+13.6 Format for Event Notification Delivery Method Registration
+ proposals
+
+ This section describes the procedures for registering Event
+ Notification Delivery Method proposals with IANA to be used with this
+ document. Such Delivery Method proposals that require a new URL
+ scheme MUST be IETF standards track documents according to RFC 2717
+ [RFC2717].
+
+13.7 Format and Requirements for IPP Delivery Method Registration
+ Proposals
+
+ This section defines the format and requirements for an IPP Event
+ Notification Delivery Method Registration Proposal. A Delivery
+ Method Registration Proposal:
+
+ 1.MUST contain the following information:
+
+ Type of registration: IPP Event Notification Delivery Method
+ Name of this delivery method:
+ Proposed URL scheme name of this delivery method:
+ Name of proposer:
+ Address of proposer:
+ Email address of proposer:
+ Is this delivery method REQUIRED or OPTIONAL for conformance to
+ the IPP Event Notification Specification document:
+ Is this delivery method defining Machine Consumable and/or Human
+ Consumable content:
+
+ 2.MUST meet the conformance requirements for Delivery Method
+ Documents specified in section 10.
+
+
+14 Internationalization Considerations
+
+ This IPP Notification specification continues support for the
+ internationalization of [RFC2911] of attributes containing text
+ strings and names. Allowing a Subscribing Client to specify a
+ different natural language and charset for each Subscription Object
+ increases the internationalization support.
+
+ The Printer MUST be able to localize the content of Human Consumable
+ Event Notifications and to localize the value of "notify-text"
+ attribute in Machine Consumable Event Notifications that it sends to
+ Notification Recipients. For localization, the Printer MUST use the
+ value of the "notify-charset" attribute and the "notify-natural-
+ language" attribute in the Subscription Object supplied by the
+ Subscribing Client.
+
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 73]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+15 Security Considerations
+
+ By far the biggest security concern is the abuse of notification:
+ sending unwanted Event Notifications to third parties (i.e., spam).
+ The problem is made worse by notification addresses that may be
+ redistributed to multiple parties (e.g., mailing lists). There exist
+ scenarios where third party notification is required (see Scenario #2
+ and #3 in [ipp-not-req]). The fully secure solution would require
+ active agreement of all recipients before sending out anything.
+ However, requirement #9 in [ipp-req] ("There is no requirement for
+ IPP Printer receiving the print request to validate the identity of
+ an Event recipient") argues against this. Certain systems may decide
+ to disallow third party Event Notifications (a traditional fax
+ model).
+
+ Clients submitting Notification requests to the IPP Printer has the
+ same security issues as submitting an IPP/1.1 print job request. The
+ same mechanisms used by IPP/1.1 can therefore be used by the client
+ Notification submission. Operations that require authentication can
+ use the HTTP authentication. Operations that require privacy can use
+ the HTTP/TLS privacy.
+
+ The Notification access control model should be similar to the IPP
+ access control model for Jobs. Creating a Per-Printer Subscription
+ Object is associated with a user. Only the creator or an Operator
+ can cancel the Subscription Object. The system may limit the listing
+ of items to only those items owned by the user. Some Subscription
+ Objects (e.g., those that have a lifetime longer than a job) can be
+ done only by privileged users (users having Operator and/or
+ Administrator access rights), if that is the authorization policy.
+
+ The standard security concerns (delivery to the right user, privacy
+ of content, tamper proof content) apply to the Delivery Method. IPP
+ should use the security mechanism of the Delivery Method used. Some
+ delivery mechanisms are more secure than others. Therefore,
+ sensitive Event Notifications should use the Delivery Method that has
+ the strongest security.
+
+
+16 Status Codes
+
+ The following status codes are defined as extensions for Notification
+ and are returned as the value of the "status-code" parameter in the
+ Operation Attributes Group of a response (see [RFC2911] section
+ 3.1.6.1). Operations in this document can also return the status
+ codes defined in section 13 of [RFC2911]. The 'successful-ok' status
+ code is an example of such a status code.
+
+
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 74]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+16.1 successful-ok-ignored-subscriptions (0x0003)
+
+ The Subscription Creation Operation was unable to create all
+ requested Subscription Objects.
+
+ For a Create-Job-Subscriptions or Create-Printer-Subscriptions
+ operation, this status code means that the Printer created one or
+ more Subscription Objects, but not all requested Subscription
+ Objects.
+
+ For a Job Creation operation, this status code means that the Printer
+ created the Job along with zero or more Subscription Objects. The
+ Printer returns this status code even if other job attributes are
+ unsupported or in conflict. That is, if an IPP Printer finds a
+ warning that would allow it to return 'successful-ok-ignored-
+ subscriptions' and either 'successful-ok-ignored-or-substituted-
+ attributes' and/or 'successful-ok-conflicting-attributes', it MUST
+ return 'successful-ok-ignored-subscriptions'.
+
+16.2 client-error-ignored-all-subscriptions (0x0414)
+
+ This status code is the same as 'successful-ok-ignored-subscriptions'
+ except that only the Create-Job-Subscriptions and Create-Printer-
+ Subscriptions operation return it. They return this status code only
+ when the Printer creates zero Subscription Objects.
+
+
+17 Status Codes in Subscription Attributes Groups
+
+ This section contains values of the "notify-status-code" (type2 enum)
+ attribute that the Printer returns in a Subscription Attributes Group
+ in a response when the corresponding Subscription Object:
+
+ 1.is not created or
+
+ 2.is created and some of the client-supplied attributes are not
+ supported.
+
+ The following sections are ordered in decreasing order of importance
+ of the status-codes.
+
+17.1 client-error-uri-scheme-not-supported (0x040C)
+
+ This status code is defined in [RFC2911]. This document extends its
+ meaning and allows it to be in a Subscription Attributes Group of a
+ response.
+
+ The scheme of the client-supplied URI in a "notify-recipient-uri"
+ Subscription Template Attribute in a Subscription Creation Operation
+ is not supported. See section 0.
+
+
+Herriot, et al. Expires July 24, 2001 [page 75]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+17.2 client-error-too-many-subscriptions (0x0415)
+
+ The number of Subscription Objects supported by the Printer would be
+ exceeded if this Subscription Object were created (see section 5.2).
+
+17.3 successful-ok-too-many-events (0x0005)
+
+ The client supplied more Events in the "notify-events" operation
+ attribute of a Subscription Creation Operation than the Printer
+ supports, as indicated in its "notify-max-events-supported" Printer
+ attribute (see section 5.3.2).
+
+17.4 successful-ok-ignored-or-substituted-attributes (0x0001)
+
+ This status code is defined in [RFC2911]. This document extends its
+ meaning to include unsupported Subscription Template Attributes and
+ it can appear in a Subscription Attributes Group.
+
+
+18 Encodings of Additional Attribute Tags
+
+ This section assigns values to two attributes tags as extensions to
+ the encoding defined in [RFC2910]).
+
+ The "subscription-attributes-tag" delimits Subscription Template
+ Attributes Groups in requests and Subscription Attributes Groups in
+ responses.
+
+ The "event-notification-attributes-tag" delimits Event Notifications
+ in Delivery Methods that use an IPP-like encoding.
+
+ The following table specifies the values for the delimiter tags:
+
+
+
+ Tag Value (Hex) Meaning
+
+
+ 0x06 "subscription-attributes-tag"
+
+ 0x07 "event-notification-attributes-tag"
+
+
+19 References
+
+ [IANA-CON]
+ Narte, T. and Alvestrand, H.T.: Guidelines for Writing an IANA
+ Considerations Section in RFCs, Work in Progress, draft-iesg-iana-
+ considerations-04.txt, May 21, 1998.
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 76]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ [ipp-not-req]
+ deBry, R., Lewis, H., Hastings, T., "Internet Printing
+ Protocol/1.1: Requirements for IPP Notifications", <draft-ietf-ipp-
+ not-05.txt>, work in progress, January 23, 2001.
+
+ [ipp-prog]
+ Hastings, T., Bergman, R., Lewis, H., "IPP: Job Progress
+ Attributes", <draft-ietf-ipp-job-prog-03.txt> work in
+ progress, January 23, 2001.
+
+ [ipp-set]
+ Kugler, C., Hastings, T., Herriot, R., Lewis, H, "Internet Printing
+ Protocol (IPP): Job and Printer Set Operations", <draft-ietf-ipp-
+ job-printer-set-ops-03.txt>, work in progress, January 22, 2001.
+
+ [RFC2026]
+ S. Bradner, "The Internet Standards Process -- Revision 3", RFC
+ 2026, October 1996.
+
+ [RFC2119]
+ S. Bradner, "Key words for use in RFCs to Indicate Requirement
+ Levels", RFC 2119 , March 1997
+
+ [RFC2566]
+ deBry, R., , Hastings, T., Herriot, R., Isaacson, S., Powell, P.,
+ "Internet Printing Protocol/1.0: Model and Semantics", RFC 2566,
+ April 1999.
+
+ [RFC2567]
+ Wright, D., "Design Goals for an Internet Printing Protocol", RFC
+ 2567, April 1999.
+
+ [RFC2568]
+ Zilles, S., "Rationale for the Structure and Model and Protocol for
+ the Internet Printing Protocol", RFC 2568, April 1999.
+
+ [RFC2569]
+ Herriot, R., Hastings, T., Jacobs, N., Martin, J., "Mapping between
+ LPD and IPP Protocols", RFC 2569, April 1999.
+
+ [RFC2717]
+ R. Petke and I. King, "Registration Procedures for URL Scheme
+ Names", RFC 2717, November 1999.
+
+ [RFC2910]
+ Herriot, R., Butler, S., Moore, P., Turner, R., "Internet Printing
+ Protocol/1.1: Encoding and Transport", RFC 2910, September 2000.
+
+
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 77]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ [RFC2911]
+ deBry, R., , Hastings, T., Herriot, R., Isaacson, S., Powell, P.,
+ "Internet Printing Protocol/1.1: Model and Semantics", RFC 2911,
+ September 2000.
+
+
+20 Author's Addresses
+
+ Robert Herriot
+ Xerox Corporation
+ 3400 Hillview Ave., Bldg #1
+ Palo Alto, CA 94304
+
+ Phone: 650-813-7696
+ Fax: 650-813-6860
+ Email: robert.herriot@pahv.xerox.com
+
+ Tom Hastings
+ Xerox Corporation
+ 737 Hawaii St. ESAE 231
+ El Segundo, CA 90245
+
+ Phone: 310-333-6413
+ Fax: 310-333-5514
+ e-mail: hastings@cp10.es.xerox.com
+
+
+ Scott A. Isaacson
+ Novell, Inc.
+ 122 E 1700 S
+ Provo, UT 84606
+
+ Phone: 801-861-7366
+ Fax: 801-861-2517
+ e-mail: sisaacson@novell.com
+
+
+ Roger deBry
+ Utah Valley State College
+ Orem, UT 84058
+
+ Phone: (801) 222-8000
+ EMail: debryro@uvsc.edu
+
+ Jay Martin
+ Underscore Inc.
+ 9 Jacqueline St.
+ Hudson, NH 03051-5308
+ 603-889-7000
+ fax: 775-414-0245
+
+
+Herriot, et al. Expires July 24, 2001 [page 78]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ e-mail: jkm@underscore.com
+
+
+ Michael Shepherd
+ Xerox Corporation
+ 800 Phillips Road MS 128-51E
+ Webster, NY 14450
+
+ Phone: 716-422-2338
+ Fax: 716-265-8871
+ e-mail: mshepherd@crt.xerox.com
+
+
+ Ron Bergman
+ Hitachi Koki Imaging Solutions
+ 1757 Tapo Canyon Road
+ Simi Valley, CA 93063-3394
+
+ Phone: 805-578-4421
+ Fax: 805-578-4001
+ Email: rbergma@hitachi-hkis.com
+
+A. Appendix - Model for Notification with Cascading Printers
+
+ With this model (see Figure 2), there is an intervening Print server
+ between the human user and the output-device. So the system
+ effectively has two Printers. There are two cases to consider.
+
+ 1.When the Printer 1 (in the server) generates Events, the system
+ behaves like the client and Printer in Figure 1. In this case,
+ Printer 1 sends Event Notifications that are shown as Event
+ Notifications (A) of Figure 2,.
+
+ 2.When the Printer 2 (in the output-device) generates Events, there
+ are two possible system configurations:
+
+ a)Printer 1 forwards the client-supplied Subscription Creation
+ Operations to the downstream Printer 2 and lets Printer 2 send
+ the Event Notifications directly to the Notification Recipients
+ supplied by the Client (Event Notifications(C) in the diagram).
+
+ b)Printer 1 performs the client-supplied Subscription Creation
+ Operations and also forwards the Subscription Creation
+ Operations to Printer 2 with the Notification Recipient changed
+ to be the Printer 1. When an Event occurs in Printer 2, Printer
+ 2 sends the Event Notification (B) to Notification Recipient of
+ Printer 1, which relays the received Event Notification (B) to
+ the client-supplied Notification Recipient (as Event
+ Notifications(A) in the diagram). Note, when a client performs a
+ Subscription Creation Operation, Printer 1 need not forward the
+
+
+Herriot, et al. Expires July 24, 2001 [page 79]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ Subscription Creation Operation to Printer 2 if it would create
+ a duplicate Subscription Object on Printer 2.
+
+ Note: when Printer 1 is forwarding Subscription Creation Operations
+ to Printer 2, it may request Printer 2 to create additional
+ Subscription Objects (called "piggy-backing"). Piggy-backing is
+ useful when:
+
+ . Device A is configured to accept (IPP or non-IPP) requests from
+ other servers.
+
+ . Server S wants to receive Job Events that the client didn't
+ request and Server S wants these Events for jobs it submits and
+ not for other jobs.
+
+ server S device A
+ +------------+ +------------+
+ | | | |
+ +--------+ Subscription | ###########| | ###########|
+ | client |--Creation ----># Printer #| Subscription | # Printer #|
+ +--------+ Operation | # Object 1#|---Creation------|># Object 2#|
+ | ###|#######| Operation | ####|#|####|
+ +----|---^---+ +-----|-|----+
+ +--------+ Event | | | |
+ |Notific-|<-Notifications(A)-+ +-- Event Notifications(B)--+ |
+ |ation Re|<-------------Event Notifications(C)-----------------+
+ |cipient |
+ +--------+
+
+ Figure 2 - Model for Notification with Cascading Printers
+
+
+B. Appendix - Distributed Model for Notification
+
+ A Printer implementation could use some other remote notification
+ service to provide some or most of the service. For example, the
+ remote notification service could send Event Notifications using
+ Delivery Methods that are not directly supported by the output device
+ or server. Or, the remote notification service could store
+ Subscription Objects (passed to it from the output device in response
+ to Subscription Creation requests), accept Events, format the Event
+ Notification in the natural language of the Notification Recipient,
+ and send the Event Notifications to the Notification Recipient(s).
+
+ Figure 3 shows this partitioning. The interface between the output
+ device (or server) and the remote notification service is outside the
+ scope of this document and is intended to be transparent to the
+ client and this document. The combination of the output device (or
+ server) and the notification service together constitute an IPP
+ Printer conforming to this Notification document.
+
+
+Herriot, et al. Expires July 24, 2001 [page 80]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+
+
+ ***********************
+ *
+ * Printer (including
+ * the distributed
+ * Notification Service)
+ *
+ * output device or server
+ * +---------------+
+ PDA, desktop, or server * + ########### +
+ +--------+ * | # partial # |
+ | client |---IPP Subscription--------># Printer # |
+ +--------+ Creation operation * | # Object # |
+ * | #####|##### |
+ * +-------|-------+
+ * | Subscriptions
+ * | OR Event
+ +------------+ * | Notifications
+ |Notification| IPP-defined * +------v--------+
+ |Recipient |<--Event Notifications---| Notification |
+ +------------+ * | Service |
+ * +---------------+
+ *
+ *************************
+ *** = Implementation configuration opaque boundary
+
+
+ Figure 3 - Opaque Use of a Notification Service Transparent to the
+ Client
+
+
+C. Appendix - Extended Notification Recipient
+
+ The model allows for an extended Notification Recipient that is
+ itself a notification service that forwards each Event Notification
+ to another recipient (called the Ultimate Notification Recipient in
+ this section). The Delivery Method to the Ultimate Recipient is
+ probably different from the Delivery Method used by the Printer to
+ the extended Notification Recipient.
+
+ This extended Notification Recipient is transparent to the Printer
+ but not to the client.
+
+ When a client performs a Subscription Creation Operation, it
+ specifies the extended Notification Recipient as it would any
+ Notification Recipient. In addition, the client specifies the
+ Ultimate Notification Recipient in the Subscription Creation
+ Operation in a manner specified by the extended Notification
+ Recipient. Typically, it is either some bytes in the value of
+
+
+Herriot, et al. Expires July 24, 2001 [page 81]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ "notify-user-data" or some additional parameter in the value of
+ "notify-recipient-uri". The client also subscribes directly with the
+ extended Notification Recipient (by means outside this document),
+ since it is a notification service in its own right.
+
+ The IPP Printer treats the extended Notification Recipient like any
+ other Notification Recipient and the IPP Printer is not aware of the
+ forwarding. The Delivery Method that the extended Notification
+ Recipient uses for delivering the Event Notification to the Ultimate
+ Notification Recipient is beyond the scope of this document and is
+ transparent to the IPP Printer.
+
+ Examples of this extended Notification Recipient are paging,
+ immediate messaging services, general notification services, and NOS
+ vendors' infrastructure. Figure 4 shows this approach.
+
+
+ PDA, desktop, or server server or output device
+ +---------------+
+ +--------+ | ########### |
+ | client |---Subscription Creation -----------># Printer # |
+ +--------+ Operation | # Object # |
+ | #####|##### |
+ +------------+ +------------+ IPP-defined +-------|-------+
+ |Ultimate | any |Notification|<--Event Notifications----+
+ |Notification|<----|Recipient |
+ |Recipient | +------------+
+ +------------+ (Notification Service)
+
+ Figure 4 - Use of an Extended Notification Recipient transparent to
+ the Printer
+
+
+D. Appendix - Details about Conformance Terminology
+
+ The following paragraph provide more details about conformance
+ terminology.
+
+ REQUIRED - an adjective used to indicate that a conforming IPP
+ Printer implementation MUST support the indicated operation,
+ object, attribute, attribute value, status code, or out-of-band
+ value in requests and responses. See [RFC2911] "Appendix A -
+ Terminology for a definition of "support". Since support of this
+ entire Notification specification is OPTIONAL for conformance to
+ IPP/1.0 or IPP/1.1, the use of the term REQUIRED in this document
+ means "REQUIRED if this OPTIONAL Notification specification is
+ implemented".
+
+ RECOMMENDED - an adjective used to indicate that a conforming IPP
+ Printer implementation is recommended to support the indicated
+
+
+Herriot, et al. Expires July 24, 2001 [page 82]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ operation, object, attribute, attribute value, status code, or
+ out-of-band value in requests and responses. Since support of
+ this entire Notification specification is OPTIONAL for conformance
+ to IPP/1.0 or IPP/1.1, the use of the term RECOMMENDED in this
+ document means "RECOMMENDED if this OPTIONAL Notification
+ specification is implemented".
+
+ OPTIONAL - an adjective used to indicate that a conforming IPP
+ Printer implementation MAY, but is NOT REQUIRED to, support the
+ indicated operation, object, attribute, attribute value, status
+ code, or out-of-band value in requests and responses.
+
+
+E. Appendix - Object Model for Notification
+
+ This section describes the Notification object model that adds a
+ Subscription Object which together with the Job and Printer object
+ provide the complete Notification semantics.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 83]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ The object relationships can be seen pictorially as:
+
+
+ Subscription Objects (Per-Printer Subscriptions) Printer object
+ +----+ +------------+
+ | s1 |<--------------------------------------------->| |
+ +----++ | |
+ | s2 |<-------------------------------------------->| p1 |
+ +----++ | |
+ | s3 |<------------------------------------------->| |
+ +----+ +------------+
+ Job objects
+ +---------+
+ | |
+ +----+ | j1 |
+ | s4 |<------->| |
+ +----+ | |
+ | | s4 is a Per-Job Subscription Object
+ ++--------++
+ | |
+ +----+ | j2 |
+ | s5 |<------>| |
+ +----++ | |
+ | s6 |<----->| | s5 and s6 are Per-Job Subscription
+ +----+ ++--------++ Objects
+ | |
+ | j3 |
+ | |
+ | | <----> indicates association
+ +---------+
+
+ Figure 5 - Object Model for Notification
+
+ s1, s2, and s3 are Per-Printer Subscription Objects and can
+ identify Printer and/or Job Events.
+ s4, s5, and s6 are Per-Job Subscription Objects and can identify
+ Printer and/or Job Events.
+
+E.1 Appendix - Object relationships
+
+ This sub-section defines the object relationships between the
+ Printer, Job, and Subscription Objects by example. Whether Per-
+ Printer Subscription Objects are actually contained in a Printer
+ object or are just bi-directionally associated with them in some way
+ is IMPLEMENTATION DEPENDENT and is transparent to the client.
+ Similarly, whether Per-Job Subscription Objects are actually
+ contained in a Job object or are just bi-directionally associated
+ with them in some way is IMPLEMENTATION DEPENDENT and is transparent
+ to the client. The object relationships are defined as follows:
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 84]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+E.2 Printer Object and Per-Printer Subscription Objects
+
+ 1.The Printer object contains (is associated with) zero or more
+ Per-Printer Subscription Objects (p1 contains s1-s3 Per-Printer
+ Subscription Objects).
+
+ 2.Each Per-Printer Subscription Object (s1, s2, and s3) is
+ contained in (or is associated with) exactly one Printer object
+ (p1).
+
+
+E.3 Job Object and Per-Job Subscription Objects
+
+ 1.A Job object (j1, j2, j3) is associated with zero or more Per-
+ Job Subscription Objects (s4-s6). Job j1 is associated with
+ Per-Job Subscription Object s4, Job j2 is associated with Per-
+ Job Subscription Objects s5 and s6, and Job j3 is not associated
+ with any Per-Job Subscription Object.
+
+ 2.Each Per-Job Subscription Object is associated with exactly one
+ Job object.
+
+
+F. Appendix - Per-Job versus Per-Printer Subscription Objects
+
+ Per-Job and Per-Printer Subscription Objects are quite similar.
+ Either type of Subscription Object can subscribe to Job Events,
+ Printer Events, or both. Both types of Subscription Objects can be
+ queried using the Get-Subscriptions and Get-Subscription-Attributes
+ operations and canceled using the Cancel-Subscription operation.
+ Both types of Subscription Objects create Subscription Objects which
+ have the same Subscription Object attributes defined. However, there
+ are some semantic differences between Per-Job Subscription Objects
+ and Per-Printer Subscription Objects. A Per-Job Subscription Object
+ is established by the client when submitting a job and after creating
+ the job using the Create-Job-Subscriptions operation by specifying
+ the "job-id" of the Job with the "notify-job-id" attribute. A Per-
+ Printer Subscription Object is established between a client and a
+ Printer using the Create-Printer-Subscriptions operation. Some
+ specific differences are:
+
+ 1.A client usually creates one or more Per-Job Subscription
+ Objects as part of the Job Creation operations (Create-Job,
+ Print-Job, and Print-URI), rather than using the OPTIONAL
+ Create-Job-Subscriptions operation, especially since Printer
+ implementations NEED NOT support the Create-Job-Subscriptions
+ operation, since it is OPTIONAL.
+
+ 2.For Per-Job Subscription Objects, the Subscription Object is
+ only valid while the job is "not-complete" (see sections 5.4.3)
+
+
+Herriot, et al. Expires July 24, 2001 [page 85]
+
+
+INTERNET-DRAFT IPP: Event Notification January 24, 2001
+
+
+ while for the Per-Printer Subscription Objects, the Subscription
+ Object is valid until the time (in seconds) that the Printer
+ returned in the "notify-lease-expiration-time" operation
+ attribute.
+
+ 3.Job Events in a Per-Job Subscription Object apply only to "one
+ job" (the Job created by the Job Creation operation or
+ references by the Create-Job-Subscriptions operation) while Job
+ Events in a Per-Printer Subscription Object apply to ALL jobs
+ contained in the IPP Printer.
+
+
+G. Appendix: Full Copyright Statement
+
+ Copyright (C) The Internet Society (1998,1999,2000,2001). All Rights
+ Reserved
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Expires July 24, 2001 [page 86]
diff --git a/standards/draft-ietf-ipp-notify-get-02.txt b/standards/draft-ietf-ipp-notify-get-02.txt
new file mode 100644
index 000000000..143da3217
--- /dev/null
+++ b/standards/draft-ietf-ipp-notify-get-02.txt
@@ -0,0 +1,1711 @@
+
+
+
+
+
+
+INTERNET-DRAFT Robert Herriot (editor)
+<draft-ietf-ipp-notify-get-02.txt> Xerox Corp.
+[Target category: standards track] Carl Kugler
+ IBM, Corp.
+ Harry Lewis
+ IBM, Corp.
+ February 28, 2001
+ Internet Printing Protocol (IPP):
+ The 'ippget' Delivery Method for Event Notifications
+
+ Copyright (C) The Internet Society (2001). All Rights Reserved.
+
+Status of this Memo:
+
+ This document is an Internet-Draft and is in full conformance with
+ all provisions of Section 10 of [rfc2026]. Internet-Drafts are
+ working documents of the Internet Engineering Task Force (IETF), its
+ areas, and its working groups. Note that other groups may also
+ distribute working documents as Internet-Drafts.
+
+ Internet-Drafts are draft documents valid for a maximum of six months
+ and may be updated, replaced, or obsoleted by other documents at any
+ time. It is inappropriate to use Internet-Drafts as reference
+ material or to cite them other than as "work in progress".
+
+ The list of current Internet-Drafts can be accessed at
+ http://www.ietf.org/ietf/1id-abstracts.txt
+
+ The list of Internet-Draft Shadow Directories can be accessed as
+ http://www.ietf.org/shadow.html.
+
+Abstract
+
+ The notification extension document [ipp-ntfy] defines operations
+ that a client can perform in order to create Subscription Objects in
+ a Printer and carry out other operations on them. A Subscription
+ Object represents a Subscription abstraction. The Subscription Object
+ specifies that when one of the specified Events occurs, the Printer
+ sends an asynchronous Event Notification to the specified
+ Notification Recipient via the specified Delivery Method (i.e.,
+ protocol).
+
+ The notification extension document [ipp-ntfy] specifies that each
+ Delivery Method is defined in another document. This document is one
+ such document, and it specifies the 'ippget' delivery method.
+
+ The 'ippget' Delivery Method is a 'pull and push' Delivery Method.
+ That is, the Printer saves Event Notification for a period of time
+ and expects the Notification Recipient to fetch the Event
+ Notifications (the pull part). The Printer continues to send Event
+
+Herriot, et al. Expires: August 28, 2001 [page 1]
+
+
+INTERNET-DRAFT IPP: The 'ippget' Delivery Method February 28, 2001
+
+
+ Notifications to the Notification Recipient as Events occur (the push
+ part) if the client has selected the option to wait for additional
+ Event Notifications.
+
+ When a Printer supports this Delivery Method, it holds each Event
+ Notification for an amount of time, called the Event Notification
+ Lease Time.
+
+ When a Notification Recipient wants to receive Event Notifications,
+ it performs an IPP operation called 'Get-Notifications', which this
+ document defines. This operation causes the Printer to return all
+ Event Notifications held for the Notification Recipient. If the
+ Notification Recipient has selected the option to wait for additional
+ Event Notifications, the Printer continues sending Event
+ Notifications to the Notification Recipient as additional Events
+ occur.
+
+
+
+ The basic set of IPP documents includes:
+
+ Design Goals for an Internet Printing Protocol [RFC2567]
+ Rationale for the Structure and Model and Protocol for the Internet
+ Printing Protocol [RFC2568]
+ Internet Printing Protocol/1.1: Model and Semantics [RFC2911]
+ Internet Printing Protocol/1.1: Encoding and Transport [RFC2910]
+ Internet Printing Protocol/1.1: Implementer's Guide [ipp-iig]
+ Mapping between LPD and IPP Protocols [RFC2569]
+ Internet Printing Protocol/1.0 & 1.1: IPP Event Notification
+ Specification [ipp-ntfy]
+
+ The "Design Goals for an Internet Printing Protocol" document takes a
+ broad look at distributed printing functionality, and it enumerates
+ real-life scenarios that help to clarify the features that need to be
+ included in a printing protocol for the Internet. It identifies
+ requirements for three types of users: end users, operators, and
+ administrators. It calls out a subset of end user requirements that
+ are satisfied in IPP/1.0. A few OPTIONAL operator operations have
+ been added to IPP/1.1.
+
+ The "Rationale for the Structure and Model and Protocol for the
+ Internet Printing Protocol" document describes IPP from a high level
+ view, defines a roadmap for the various documents that form the suite
+ of IPP specification documents, and gives background and rationale
+ for the IETF working group's major decisions.
+
+ The "Internet Printing Protocol/1.1: Model and Semantics" document
+ describes a simplified model with abstract objects, their attributes,
+ and their operations that are independent of encoding and transport.
+ It introduces a Printer and a Job object. The Job object optionally
+
+Herriot, et al. Expires: August 28, 2001 [page 2]
+
+
+INTERNET-DRAFT IPP: The 'ippget' Delivery Method February 28, 2001
+
+
+ supports multiple documents per Job. It also addresses security,
+ internationalization, and directory issues.
+
+ The "Internet Printing Protocol/1.1: Encoding and Transport" document
+ is a formal mapping of the abstract operations and attributes defined
+ in the model document onto HTTP/1.1 [RFC2616]. It defines the
+ encoding rules for a new Internet MIME media type called
+ "application/ipp". This document also defines the rules for
+ transporting over HTTP a message body whose Content-Type is
+ "application/ipp". This document defines a new scheme named 'ippget'
+ for identifying IPP printers and jobs.
+
+ The "Internet Printing Protocol/1.1: Implementer's Guide" document
+ gives insight and advice to implementers of IPP clients and IPP
+ objects. It is intended to help them understand IPP/1.1 and some of
+ the considerations that may assist them in the design of their client
+ and/or IPP object implementations. For example, a typical order of
+ processing requests is given, including error checking. Motivation
+ for some of the specification decisions is also included.
+
+ The "Mapping between LPD and IPP Protocols" document gives some
+ advice to implementers of gateways between IPP and LPD (Line Printer
+ Daemon) implementations.
+
+ The "Event Notification Specification" document describes an
+ extension to the IPP/1.0, IPP/1.1, and future versions. This
+ extension allows a client to subscribe to printing related Events.
+ Subscriptions are modeled as Subscription Objects. The Subscription
+ Object specifies that when one of the specified Event occurs, the
+ Printer sends an asynchronous Event Notification to the specified
+ Notification Recipient via the specified Delivery Method (i.e.,
+ protocol). A client associates Subscription Objects with a
+ particular Job by performing the Create-Job-Subscriptions operation
+ or by submitting a Job with subscription information. A client
+ associates Subscription Objects with the Printer by performing a
+ Create-Printer-Subscriptions operation. Four other operations are
+ defined for Subscription Objects: Get-Subscriptions-Attributes, Get-
+ Subscriptions, Renew-Subscription, and Cancel-Subscription.
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Expires: August 28, 2001 [page 3]
+
+
+INTERNET-DRAFT IPP: The 'ippget' Delivery Method February 28, 2001
+
+
+
+Table of Contents
+
+
+ 1 Introduction....................................................6
+
+ 2 Terminology.....................................................6
+
+ 3 Model and Operation.............................................7
+
+ 4 General Information.............................................8
+
+ 5 Get-Notifications operation....................................10
+ 5.1 Get-Notifications Request...................................12
+ 5.2 Get-Notifications Response..................................13
+
+ 6 Subscription Template Attributes...............................18
+ 6.1 Subscription Template Attribute Conformance.................18
+ 6.2 Additional Information about Subscription Template Attributes18
+ 6.2.1 notify-recipient-uri (uri)................................18
+ 6.3 Subscription Description Attribute Conformance..............19
+
+ 7 Additional Printer Description Attributes......................19
+ 7.1 Printer Description Attribute Conformance...................19
+ 7.2 New Values for Existing Printer Description Attributes......19
+ 7.2.1 notify-schemes-supported (1setOf uriScheme)...............19
+ 7.2.2 operations-supported (1setOf type2 enum)..................19
+ 7.3 begin-to-expire-time-interval (integer(0:MAX))..............20
+
+ 8 New Status Codes...............................................20
+ 8.1 redirection-other-site (0x300)..............................21
+
+ 9 The IPPGET URL Scheme..........................................21
+ 9.1 The IPPGET URL Scheme Applicability and Intended Usage......21
+ 9.2 The IPPGET URL Scheme Associated Port.......................21
+ 9.3 The IPPGET URL Scheme Associated MIME Type..................21
+ 9.4 The IPPGET URL Scheme Character Encoding....................22
+ 9.5 The IPPGET URL Scheme Syntax in ABNF........................22
+ 9.5.1 IPPGET URL Examples.......................................23
+ 9.5.2 IPPGET URL Comparisons....................................23
+
+ 10 Encoding.......................................................24
+
+ 11 Conformance Requirements.......................................24
+ 11.1 Conformance for IPP Printers................................24
+ 11.2 Conformance for IPP Clients.................................25
+
+ 12 IANA Considerations............................................25
+ 12.1 Operation Registrations.....................................26
+ 12.2 Additional values of existing attributes....................26
+
+Herriot, et al. Expires: August 28, 2001 [page 4]
+
+
+INTERNET-DRAFT IPP: The 'ippget' Delivery Method February 28, 2001
+
+
+ 12.2.1 Additional values for the "notify-schemes-supported" Printer
+ attribute..............................................26
+ 12.2.2 Additional values for the "operations-supported" Printer
+ attribute..............................................26
+ 12.3 Attribute Registrations.....................................27
+ 12.4 Status code Registrations...................................27
+
+ 13 Internationalization Considerations............................27
+
+ 14 Security Considerations........................................27
+
+ 15 References.....................................................28
+
+ 16 Authors' Addresses.............................................29
+
+ 17 Full Copyright Statement.......................................30
+
+
+Table of Tables
+
+ Table 1 - Information about the Delivery Method....................9
+
+ Table 2 - Attributes in Event Notification Content................16
+
+ Table 3 - Additional Attributes in Event Notification Content for Job
+
+ Events ........................................................17
+
+ Table 4 - Combinations of Events and Subscribed Events for "job-
+
+ impressions-completed" ........................................17
+
+ Table 5 - Additional Attributes in Event Notification Content for
+
+ Printer Events ................................................18
+
+ Table 6 - Operation-id assignments................................20
+
+ Table 7 - The "event-notification-attributes-tag" value...........24
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Expires: August 28, 2001 [page 5]
+
+
+INTERNET-DRAFT IPP: The 'ippget' Delivery Method February 28, 2001
+
+
+1 Introduction
+
+ The notification extension document [ipp-ntfy] defines operations
+ that a client can perform in order to create Subscription Objects in
+ a Printer and carry out other operations on them. A Subscription
+ Object represents a Subscription abstraction. The Subscription Object
+ specifies that when one of the specified Events occurs, the Printer
+ sends an asynchronous Event Notification to the specified
+ Notification Recipient via the specified Delivery Method (i.e.,
+ protocol).
+
+ The notification extension document [ipp-ntfy] specifies that each
+ Delivery Method is defined in another document. This document is one
+ such document, and it specifies the 'ippget' delivery method.
+
+ The 'ippget' Delivery Method is a 'pull and push' Delivery Method.
+ That is, the Printer saves Event Notification for a period of time
+ and expects the Notification Recipient to fetch the Event
+ Notifications (the pull part). The Printer continues to send Event
+ Notifications to the Notification Recipient as Events occur (the push
+ part) if the client has selected the option to wait for additional
+ Event Notifications.
+
+ When a Printer supports this Delivery Method, it holds each Event
+ Notification for an amount of time, called the Event Notification
+ Lease Time.
+
+ When a Notification Recipient wants to receive Event Notifications,
+ it performs an IPP operation called 'Get-Notifications', which this
+ document defines. This operation causes the Printer to return all
+ Event Notifications held for the Notification Recipient. If the
+ Notification Recipient has selected the option to wait for additional
+ Event Notifications, the Printer the Printer continues to send Event
+ Notifications to the Notification Recipient as Events occur.
+
+
+2 Terminology
+
+ This section defines the following terms that are used throughout
+ this document:
+
+ Capitalized terms, such as MUST, MUST NOT, REQUIRED, SHOULD, SHOULD
+ NOT, MAY, NEED NOT, and OPTIONAL, have special meaning relating to
+ conformance to this specification. These terms are defined in
+ [RFC2911 section 13.1 on conformance terminology, most of which is
+ taken from RFC 2119 [RFC2119].
+
+ Event Notification Lease: The lease that is associated with an Event
+ Notification. When the lease expires, the Printer discards the
+ associated Event Notification.
+
+Herriot, et al. Expires: August 28, 2001 [page 6]
+
+
+INTERNET-DRAFT IPP: The 'ippget' Delivery Method February 28, 2001
+
+
+ Event Notification Lease Time: The expiration time assigned to a
+ lease that is associated with an Event Notification.
+
+ Event Notification Attributes Group: The attributes group in a
+ response that contains attributes that are part of an Event
+ Notification.
+
+ For other capitalized terms that appear in this document, see [ipp-
+ ntfy].
+
+
+3 Model and Operation
+
+ In a Subscription Creation Operation, when the value of the "notify-
+ recipient-uri" attribute has the scheme 'ippget', the client is
+ requesting that the Printer use the 'ippget' Delivery Method for the
+ Event Notifications associated with the new Subscription Object. The
+ client SHOULD choose a value for the address part of the "notify-
+ recipient-uri" attribute that uniquely identifies the Notification
+ Recipient.
+
+ When an Event occurs, the Printer MUST generate an Event Notification
+ and MUST assign it the Event Notification Lease Time. The Printer
+ MUST hold an Event Notification for its assigned Event Notification
+ Lease Time. The Printer MUST assign the same Event Notification
+ Lease Time to each Event Notification.
+
+ When a Notification Recipient wants to receive Event Notifications,
+ it performs the Get-Notifications operation, which causes the Printer
+ to return all un-expired Event Notifications held for the
+ Notification Recipient. If the Notification Recipient has selected
+ the option to wait for additional Event Notifications, the response
+ to the Get-Notifications request continues indefinitely as the
+ Printer continues to send Event Notifications in the response as
+ Events occur. For the Get-Notification operation, the Printer sends
+ only those Event Notifications that are generated from Subscription
+ Objects whose "notify-recipient-uri" attribute value equals the value
+ of the "notify-recipient-uri" Operation Attribute in the Get-
+ Notifications operation.
+
+ If a Notification Recipient performs the Get-Notifications operation
+ twice in quick succession, it will receive nearly the same Event
+ Notification both times because most of the Event Notifications are
+ those that the Printer saves for a few seconds after the Event
+ occurs. There are two possible differences. Some old Event
+ Notifications may not be present in the second response because their
+ Event Notification Leases have expired. Some new Event Notifications
+ may be present in the second response but not the first response.
+
+
+
+Herriot, et al. Expires: August 28, 2001 [page 7]
+
+
+INTERNET-DRAFT IPP: The 'ippget' Delivery Method February 28, 2001
+
+
+ When the Notification Recipient requests Event Notifications for per-
+ Job Subscription Objects, the Notification Recipient typically
+ performs the Get-Notifications operation within a second of
+ performing the Subscription Creation operation. Because the Printer
+ is likely to save Event Notifications for several seconds, the
+ Notification Recipient is unlikely to miss any Event Notifications
+ that occur between the Subscription Creation and the Get-
+ Notifications operation.
+
+
+4 General Information
+
+ If a Printer supports this Delivery Method, the following are its
+ characteristics.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Expires: August 28, 2001 [page 8]
+
+
+INTERNET-DRAFT IPP: The 'ippget' Delivery Method February 28, 2001
+
+
+ Table 1 - Information about the Delivery Method
+
+
+ Document Method Conformance Delivery Method Realization
+ Requirement
+
+
+ 1. What is the URL scheme name ippget
+ for the Delivery Method?
+
+ 2. Is the Delivery Method RECOMMENDED
+ REQUIRED, RECOMMENDED or
+ OPTIONAL for an IPP Printer
+ to support?
+
+ 3. What transport and delivery
+ protocols does the Printer
+ use to deliver the Event
+ Notification Content, i.e.,
+ what is the entire network IPP with one new operation.
+ stack?
+
+ 4. Can several Event Yes.
+ Notifications be combined
+ into a Compound Event
+ Notification?
+
+ 5. Is the Delivery Method This Delivery Method is a pull
+ initiated by the Notification and a push.
+ Recipient (pull), or by the
+ Printer (push)?
+
+ 6. Is the Event Notification Machine Consumable
+ content Machine Consumable or
+ Human Consumable?
+
+ 7. What section in this document Section 5
+ answers the following
+ question? For a Machine
+ Consumable Event
+ Notification, what is the
+ representation and encoding
+ of values defined in section
+ 9.1 of [ipp-ntfy] and the
+ conformance requirements
+ thereof? For a Human
+ Consumable Event
+ Notification, what is the
+ representation and encoding
+
+
+Herriot, et al. Expires: August 28, 2001 [page 9]
+
+
+INTERNET-DRAFT IPP: The 'ippget' Delivery Method February 28, 2001
+
+
+
+ of pieces of information
+ defined in section 9.2 of
+ [ipp-ntfy] and the
+ conformance requirements
+ thereof?
+
+ 8. What are the latency and Same as IPP and the underlying
+ reliability of the transport HTTP transport
+ and delivery protocol?
+
+ 9. What are the security aspects Same as IPP and the underlying
+ of the transport and delivery HTTP transport
+ protocol, e.g., how it is
+ handled in firewalls?
+
+ 10. What are the content length None
+ restrictions?
+
+ 11. What are the additional None
+ values or pieces of
+ information that a Printer
+ sends in an Event
+ Notification content and the
+ conformance requirements
+ thereof?
+
+ 12. What are the additional None
+ Subscription Template and/or
+ Subscription Description
+ attributes and the
+ conformance requirements
+ thereof?
+
+ 13. What are the additional None
+ Printer Description
+ attributes and the
+ conformance requirements
+ thereof?
+
+
+
+
+5 Get-Notifications operation
+
+ This operation causes the Printer to return all Event Notifications
+ held for the Notification Recipient.
+
+ A Printer MUST support this operation.
+
+
+Herriot, et al. Expires: August 28, 2001 [page 10]
+
+
+INTERNET-DRAFT IPP: The 'ippget' Delivery Method February 28, 2001
+
+
+ When a Printer performs this operation, it MUST return all and only
+ those Event Notifications:
+
+ 1. Whose associated Subscription Object's "notify-recipient-uri"
+ attribute equals the "notify-recipient-uri" Operation attribute
+ AND
+
+ 2. Whose associated Subscription Object's "notify-recipient-uri"
+ attribute has a scheme value of 'ippget' AND
+
+ 3. Whose Event Notification Lease Time has not yet expired AND
+
+ 4. Where the Notification Recipient is the owner of or has read-
+ access rights to the associated Subscription Object.
+
+ The Printer MUST respond to this operation immediately with whatever
+ Event Notifications it currently holds. If the Notification Recipient
+ has selected the option to wait for additional Event Notifications,
+ the Printer MUST continue to send Event Notifications as they occur
+ until all of the associated Subscription Objects are cancelled. A
+ Subscription Object is cancelled either via the Cancel-Subscription
+ operation or by the Printer (e.g. the Subscription Object is
+ cancelled when the associated Job completes).
+
+ Note, the Printer terminates the operation in the same way that it
+ normally terminates IPP operations. For example, if the Printer is
+ sending chunked data, it can send a 0 length chunk to denote the end
+ of the operation or it can close the connection. If the Notification
+ Recipient wishes to terminate the Get-Notifications operation, it can
+ close the connection.
+
+ The Printer MUST accept the request in any state (see [RFC2911]
+ "printer-state" and "printer-state-reasons" attributes) and MUST
+ remain in the same state with the same "printer-state-reasons"
+ values.
+
+ Access Rights: If the policy of the Printer is to allow all users to
+ access all Event Notifications, then the Printer MUST accept this
+ operation from any user. Otherwise, the authenticated user (see
+ [RFC2911] section 8.3) performing this operation MUST either be the
+ owner of each Subscription Object identified by the "notify-
+ recipient-uri" Operation attribute (as determined during a
+ Subscription Creation Operation) or an operator or administrator of
+ the Printer (see [RFC2911] Sections 1 and 8.5). Otherwise, the IPP
+ object MUST reject the operation and return: 'client-error-
+ forbidden', 'client-error-not-authenticated', or 'client-error-not-
+ authorized' status code as appropriate.
+
+
+
+
+Herriot, et al. Expires: August 28, 2001 [page 11]
+
+
+INTERNET-DRAFT IPP: The 'ippget' Delivery Method February 28, 2001
+
+
+5.1 Get-Notifications Request
+
+ The following groups of attributes are part of the Get-Notifications
+ Request:
+
+ Group 1: Operation Attributes
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in [RFC2911] section 3.1.4.1.
+
+ Target:
+ The "printer-uri" (uri) operation attribute which is the target
+ for this operation as described in [RFC2911] section 3.1.5.
+
+ Requesting User Name:
+ The "requesting-user-name" (name(MAX)) attribute SHOULD be
+ supplied by the client as described in [RFC2911] section 8.3.
+
+ "notify-recipient-uri" (url):
+ The client MUST supply this attribute. The Printer object MUST
+ support this attribute. The Printer matches the value of this
+ attribute (byte for byte with no case conversion) against the
+ value of the "notify-recipient-uri" in each Subscription Object
+ in the Printer. If there are no matches, the IPP Printer MUST
+ return the 'client-error-not-found' status code. For each
+ matched Subscription Object, the IPP Printer MUST return all
+ unexpired Event Notifications associated with it. The Printer
+ MUST send additional Event Notifications as Events occur if and
+ only if the value of the "notify-no-wait" attribute is 'false'
+ or not supplied by the client (see the next attribute below).
+
+ Note: this attribute allows a subscribing client to pick URLs
+ that are unique, e.g. the client's own URL or a friend's URL,
+ which in both cases is likely the URL of the person's host. An
+ application could make a URL unique for each application.
+
+ "notify-no-wait" (boolean):
+ The client MAY supply this attribute. The Printer object MUST
+ support this attribute. If the value of this attribute is
+ 'false', the Printer MUST send all un-expired Event
+ Notifications (as defined in the previous attribute) and it
+ MUST continue to send responses for as long as the Subscription
+ Objects associated with the specified "notify-recipient-uri"
+ continue to exist. If the value of this attribute is 'true',
+ the Printer MUST send all un-expired Event Notifications (as
+ defined in the previous attribute) and the Printer MUST
+ conclude the operation without waiting for any additional
+ Events to occur. If the client doesn't supply this attribute,
+
+
+Herriot, et al. Expires: August 28, 2001 [page 12]
+
+
+INTERNET-DRAFT IPP: The 'ippget' Delivery Method February 28, 2001
+
+
+ the Printer MUST behave as if the client had supplied this
+ attribute with the value of 'false'.
+
+5.2 Get-Notifications Response
+
+ The following groups of attributes are part of the Get-Notifications
+ Response:
+
+ Group 1: Operation Attributes
+
+ Status Message:
+ In addition to the REQUIRED status code returned in every
+ response, the response OPTIONALLY includes a "status-message"
+ (text(255)) and/or a "detailed-status-message" (text(MAX))
+ operation attribute as described in [RFC2911] sections 13 and
+ 3.1.6.
+
+ The Printer can return any status codes defined in [RFC2911].
+ If the status code is not 'successful-', the Printer MUST NOT
+ return any Event Notification Attribute groups. The following
+ is a description of the important status codes:
+
+ successful-ok: the response contains all Event Notification
+ associated with the specified "notify-recipient-uri". If
+ the specified Subscription Objects have no associated
+ Event Notification, the response MUST contain zero Event
+ Notifications.
+ client-error-not-found: The Printer has no Subscription
+ Object's whose "notify-recipient-uri" attribute equals
+ the "notify-recipient-uri" Operation attribute.
+ server-error-busy: The Printer is too busy to accept this
+ operation. If the "suggested-ask-again-time-interval"
+ operation attribute is present in the Operation
+ Attributes of the response, then the Notification
+ Recipient SHOULD wait for the number of seconds specified
+ by the "suggested-ask-again-time-interval" attribute
+ before performing this operation again. If the
+ "suggested-ask-again-time-interval" Operation Attribute
+ is not present, the Notification Recipient should use the
+ normal network back-off algorithms for determining when
+ to perform this operation again.
+ redirection-other-site: The Printer does not handle this
+ operation and requests the Notification Recipient to
+ perform the operation with the uri specified by the
+ "notify-ippget-redirect" Operation Attribute in the
+ response.
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in [RFC2911] section 3.1.4.2.
+
+Herriot, et al. Expires: August 28, 2001 [page 13]
+
+
+INTERNET-DRAFT IPP: The 'ippget' Delivery Method February 28, 2001
+
+
+
+ The Printer MUST use the values of "notify-charset" and
+ "notify-natural-language", respectively, from one Subscription
+ Object associated with the Event Notifications in this
+ response.
+
+ Normally, there is only one matched Subscription Object, or the
+ value of the "notify-charset" and "notify-natural-language"
+ attributes is the same in all Subscription Objects. If not, the
+ Printer MUST pick one Subscription Object from which to obtain
+ the value of these attributes. The algorithm for picking the
+ Subscription Object is implementation dependent. The choice of
+ natural language is not critical because 'text' and 'name'
+ values can override the "attributes-natural-language" Operation
+ attribute. The Printer's choice of charset is critical because
+ a bad choice may leave it unable to send some 'text' and 'name'
+ values accurately.
+
+ "printer-up-time" (integer(0:MAX)):
+ The value of this attribute is the Printer's "printer-up-time"
+ attribute at the time the Printer sends this response. Because
+ each Event Notification also contains the value of this
+ attribute when the event occurred, the value of this attribute
+ lets a Notification Recipient know when each Event Notification
+ occurred relative to the time of this response.
+
+ "suggested-ask-again-time-interval" (integer(0:MAX)):
+ The value of this attribute is the number of seconds that the
+ Notification Recipient SHOULD wait before trying this operation
+ again when
+ a) the Printer returns the 'server-error-busy' status code
+ OR
+ b) the Printer returns the 'successful-ok' status code and
+ the client supplied the "notify-no-wait" attribute with a
+ value of 'true'.
+ This value is intended to help the client be a good network
+ citizen.
+
+ "notify-ippget-redirect" (uri):
+ The value of this attribute is uri that the Notification
+ Recipient MUST use for the Get-Notifications operation. This
+ attribute is present in the Operation Attributes if and only if
+ the status code has the value 'redirection-other-site'.
+
+ Group 2: Unsupported Attributes
+
+ See [RFC2911] section 3.1.7 for details on returning
+ Unsupported Attributes.
+
+
+
+Herriot, et al. Expires: August 28, 2001 [page 14]
+
+
+INTERNET-DRAFT IPP: The 'ippget' Delivery Method February 28, 2001
+
+
+ If the "subscription-ids" attribute contained subscription-ids
+ that do not exist, the Printer returns them in this group as
+ value of the "subscription-ids" attribute.
+
+ Group 3 through N: Event Notification Attributes
+
+ The Printer responds with one Event Notification Attributes
+ Group per matched Event Notification. The initial matched Event
+ Notifications are all un-expired Event Notification associated
+ with the matched Subscription Objects. If the Notification
+ Recipient has selected the option to wait for additional Event
+ Notifications, the Printer the subsequent Event Notifications
+ in the response are Event Notifications associated with the
+ matched Subscription Objects as the corresponding Event occurs.
+
+ From the Notification Recipient's view, the response appears as
+ an initial burst of data, which includes the Operation
+ Attributes Group and one Event Notification Attributes Groups
+ per Event Notification that the Printer is holding. After the
+ initial burst of data, if the Notification Recipient has
+ selected the option to wait for additional Event Notifications,
+ the Notification Recipient receives occasional Event
+ Notification Attribute Groups. Proxy servers may delay some
+ Event Notifications or cause time-outs to occur. The client
+ MUST be prepared to perform the Get-Notifications operation
+ again when time-outs occur.
+
+ Each Event Notification Group MUST start with an 'event-
+ notification-attributes-tag' (see the section "Encodings of
+ Additional Attribute Tags" in [ipp-ntfy]).
+
+ Each attribute is encoded using the IPP rules for encoding
+ attributes [RFC2910] and may be encoded in any order. Note:
+ the Get-Jobs response in [RFC2911] acts as a model for encoding
+ multiple groups of attributes.
+
+ Each Event Notification Group MUST contain all of attributes
+ specified in section 9.1 ("Content of Machine Consumable Event
+ Notifications") of [ipp-ntfy] with exceptions denoted by
+ asterisks in the tables below.
+
+ The tables below are copies of the tables in section 9.1
+ ("Content of Machine Consumable Event Notifications") of [ipp-
+ ntfy] except that each cell in the "Sends" column is a "MUST".
+
+ For an Event Notification for all Events, the Printer includes
+ the attributes shown in Table 2.
+
+
+
+
+Herriot, et al. Expires: August 28, 2001 [page 15]
+
+
+INTERNET-DRAFT IPP: The 'ippget' Delivery Method February 28, 2001
+
+
+ Table 2 - Attributes in Event Notification Content
+
+
+ Source Value Sends Source Object
+
+
+ notify-subscription-id (integer(1:MAX)) MUST Subscription
+
+ notify-printer-uri (uri) MUST Subscription
+
+ notify-subscribed-event (type2 keyword) MUST Event
+ Notification
+
+ printer-up-time (integer(MIN:MAX)) MUST Printer
+
+ printer-current-time (dateTime) * MUST * Printer
+
+ notify-sequence-number (integer (0:MAX)) MUST Subscription
+
+ notify-charset (charset) MUST Subscription
+
+ notify-natural-language (naturalLanguage) MUST Subscription
+
+ notify-user-data (octetString(63)) ** MUST Subscription
+
+ notify-text (text) MUST Event
+ Notification
+
+ attributes from the "notify-attributes" MUST Printer
+ attribute ***
+
+ attributes from the "notify-attributes" MUST Job
+ attribute ***
+
+ attributes from the "notify-attributes" MUST Subscription
+ attribute ***
+
+
+ * The Printer MUST send the "printer-current-time" attribute if
+ and only if it supports the "printer-current-time" attribute on
+ the Printer object.
+
+ ** If the associated Subscription Object does not contain a
+ "notify-user-data" attribute, the Printer MUST send an octet-
+ string of length 0.
+
+ *** If the "notify-attributes" attribute is present on the
+ Subscription Object, the Printer MUST send all attributes
+ specified by the "notify-attributes" attribute. Note: if the
+
+
+Herriot, et al. Expires: August 28, 2001 [page 16]
+
+
+INTERNET-DRAFT IPP: The 'ippget' Delivery Method February 28, 2001
+
+
+ Printer doesn't support the "notify-attributes" attribute, it
+ is not present on the associated Subscription Object.
+
+ For Event Notifications for Job Events, the Printer includes
+ the additional attributes shown in Table 3.
+
+ Table 3 - Additional Attributes in Event Notification Content for
+ Job Events
+
+
+ Source Value Sends Source
+ Object
+
+
+ job-id (integer(1:MAX)) MUST Job
+
+ job-state (type1 enum) MUST Job
+
+ job-state-reasons (1setOf type2 keyword) MUST Job
+
+ job-impressions-completed (integer(0:MAX)) * MUST Job
+
+
+ * The Printer MUST send the "job-impressions-completed"
+ attribute in an Event Notification only for the combinations of
+ Events and Subscribed Events shown in Table 4.
+
+
+ Table 4 - Combinations of Events and Subscribed Events for "job-
+ impressions-completed"
+
+
+ Job Event Subscribed Job Event
+
+
+ 'job-progress' 'job-progress'
+
+ 'job-completed' 'job-completed'
+
+ 'job-completed' 'job-state-changed'
+
+
+
+ For Event Notification for Printer Events, the Printer includes
+ the additional attributes shown in Table 5.
+
+
+
+
+
+
+Herriot, et al. Expires: August 28, 2001 [page 17]
+
+
+INTERNET-DRAFT IPP: The 'ippget' Delivery Method February 28, 2001
+
+
+ Table 5 - Additional Attributes in Event Notification Content for
+ Printer Events
+
+
+ Source Value Sends Source
+ Object
+
+
+ printer-state (type1 enum) MUST Printer
+
+ printer-state-reasons (1setOf type2 keyword) MUST Printer
+
+ printer-is-accepting-jobs (boolean) MUST Printer
+
+
+6 Subscription Template Attributes
+
+ This section defines the Subscription object conformance requirements
+ for Printers.
+
+
+6.1 Subscription Template Attribute Conformance
+
+ The 'ippget' Delivery Method has the same conformance requirements
+ for Subscription Template attributes as defined in [ipp-ntfy]. The
+ 'ippget' Delivery Method does not define any addition Subscription
+ Template attributes.
+
+
+6.2 Additional Information about Subscription Template Attributes
+
+ This section defines additional information about Subscription
+ Template attributes defined in [ipp-ntfy].
+
+
+6.2.1 notify-recipient-uri (uri)
+
+ This section describes the syntax of the value of this attribute for
+ the 'ippget' Delivery Method. The syntax for values of this
+ attribute for other Delivery Method is defined in other Delivery
+ Method Documents.
+
+ In order to support the 'ippget' Delivery Method and Protocol, the
+ Printer MUST support the following syntax:
+
+ The 'ippget://' URI scheme. The remainder of the URI indicates
+ something unique about the Notification Recipient, such as its host
+ name or host address (and optional path) that the Printer uses to
+ match the "notify-recipient-uri" Operation attribute supplied in
+ the Get-Notifications request.
+
+Herriot, et al. Expires: August 28, 2001 [page 18]
+
+
+INTERNET-DRAFT IPP: The 'ippget' Delivery Method February 28, 2001
+
+
+6.3 Subscription Description Attribute Conformance
+
+ The 'ippget' Delivery Method has the same conformance requirements
+ for Subscription Description attributes as defined in [ipp-ntfy].
+ The 'ippget' Delivery Method does not define any addition
+ Subscription Description attributes.
+
+
+7 Additional Printer Description Attributes
+
+ This section defines the Printer Description Attributes conformance
+ requirements for Printers.
+
+
+7.1 Printer Description Attribute Conformance
+
+ The 'ippget' Delivery Method has the same conformance requirements
+ for Printer Description attributes as defined in [ipp-ntfy]. The
+ 'ippget' Delivery Method does not define any addition Printer
+ Description attributes.
+
+
+7.2 New Values for Existing Printer Description Attributes
+
+ This section defines additional values for existing Printer
+ Description attributes.
+
+
+7.2.1 notify-schemes-supported (1setOf uriScheme)
+
+ The following value for the "notify-schemes-supported" attribute is
+ added in order to support the new Delivery Method defined in this
+ document:
+
+ 'ippget' - The IPP Notification Delivery Method defined in this
+ document.
+
+7.2.2 operations-supported (1setOf type2 enum)
+
+ Table 6 lists the "operation-id" value defined in order to support
+ the new Get-Notifications operation defined in this document.
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Expires: August 28, 2001 [page 19]
+
+
+INTERNET-DRAFT IPP: The 'ippget' Delivery Method February 28, 2001
+
+
+ Table 6 - Operation-id assignments
+
+
+ Value Operation Name
+
+
+ 0x001C Get-Notifications
+
+
+
+
+7.3 begin-to-expire-time-interval (integer(0:MAX))
+
+ This Printer Description attribute specifies the number of seconds
+ that a Printer keeps an Event Notification that is associated with
+ the 'ippget' Delivery Method.
+
+ The Printer MUST support this attribute if it supports the 'ippget'
+ Delivery Method.
+
+ The value of this attribute is the minimum number of seconds that
+ MUST elapse between the time the Printer creates an Event
+ Notification object for the 'ippget' Delivery Method and the time the
+ Printer discards the same Event Notification.
+
+ For example, assume the following:
+
+ 1.a client performs a Job Creation operation that creates a
+ Subscription Object associated with this Delivery Method, AND
+
+ 2.an Event associated with the new Job occurs immediately after
+ the Subscription Object is created, AND
+
+ 3.the same client or some other client performs a Get-
+ Notifications operation N seconds after the Job Creation
+ operation.
+
+ Then, if N is less than the value of this attribute, the client
+ performing the Get-Notifications operations can expect not miss any
+ Event-Notifications, barring some unforeseen lack of memory space in
+ the Printer.
+
+
+8 New Status Codes
+
+ The following status codes are defined as extensions for this
+ Delivery Method and are returned as the status code of the Get-
+ Notifications operation.
+
+
+
+Herriot, et al. Expires: August 28, 2001 [page 20]
+
+
+INTERNET-DRAFT IPP: The 'ippget' Delivery Method February 28, 2001
+
+
+8.1 redirection-other-site (0x300)
+
+ This status code means that the Printer doesn't perform that Get-
+ Notifications operation and that the "notify-ippget-redirect"
+ Operation Attribute in the response contains the uri that the
+ Notification Recipient MUST use for performing the Get-Notifications
+ operation.
+
+
+9 The IPPGET URL Scheme
+
+ This section defines the 'ippget' URL and the conformance
+ requirements for using it.
+
+
+9.1 The IPPGET URL Scheme Applicability and Intended Usage
+
+ This section is intended for use in registering the 'ippget' URL
+ scheme with IANA and fully conforms to the requirements in [RFC2717].
+ This document defines the 'ippget'" URL (Uniform Resource Locator)
+ scheme for specifying a unique identifier for an IPP Client which
+ implements the IPP Get-Notifications operation specified in this
+ document (see section 5).
+
+ The intended usage of the 'ippget' URL scheme is COMMON.
+
+
+9.2 The IPPGET URL Scheme Associated Port
+
+ None.
+
+ An 'ippget' URL behaves as a unique identifier for IPP Clients and is
+ NOT used to initiate any over-the-wire protocol associations.
+
+ See: IANA Port Numbers Registry [IANA-PORTREG].
+
+
+9.3 The IPPGET URL Scheme Associated MIME Type
+
+ All IPP Get-Notifications operations (requests and responses) MUST be
+ conveyed in an 'application/ipp' MIME media type as registered in
+ [IANA-MIMEREG]. An 'ippget' URL MUST uniquely identify an IPP Client
+ that support this 'application/ipp' MIME media type.
+
+ See: IANA MIME Media Types Registry [IANA-MIMEREG].
+
+
+
+
+
+
+Herriot, et al. Expires: August 28, 2001 [page 21]
+
+
+INTERNET-DRAFT IPP: The 'ippget' Delivery Method February 28, 2001
+
+
+9.4 The IPPGET URL Scheme Character Encoding
+
+ The 'ippget' URL scheme defined in this document is based on the ABNF
+ for the URI Generic Syntax [RFC2396] and further updated by [RFC2732]
+ and [RFC2373] (for IPv6 addresses in URLs). The 'ippget' URL scheme
+ is case-insensitive in the host name or host address part; however,
+ the path part is case-sensitive, as in [RFC2396]. Code points
+ outside [US-ASCII] MUST be hex escaped by the mechanism specified in
+ [RFC2396].
+
+
+9.5 The IPPGET URL Scheme Syntax in ABNF
+
+ This document is intended for use in registering the 'ippget' URL
+ scheme with IANA and fully conforms to the requirements in [RFC2717].
+ This document defines the 'ippget' URL (Uniform Resource Locator)
+ scheme for specifying a unique identifier for an IPP Client which
+ implements IPP 'Get-Notifications' operation specified in this
+ document.
+
+ The intended usage of the 'ippget' URL scheme is COMMON.
+
+ The IPP protocol places a limit of 1023 octets (NOT characters) on
+ the length of a URI (see section 4.1.5 'uri' in [RFC2911]). An IPP
+ Printer MUST return the 'client-error-request-value-too-long' status
+ code (see section 13.1.4.10 in [RFC2911]) when a URI received in a
+ request is too long.
+
+ Note: IPP Clients and IPP Printers ought to be cautious about
+ depending on URI lengths above 255 bytes, because some older client
+ or proxy implementations might not properly support these lengths.
+
+ An 'ippget' URL MUST be represented in absolute form. Absolute URLs
+ always begin with a scheme name followed by a colon. For definitive
+ information on URL syntax and semantics, see "Uniform Resource
+ Identifiers (URI): Generic Syntax and Semantics" [RFC2396]. This
+ specification adopts the definitions of "authority", "abs_path",
+ "query", "reg_name", "server", "userinfo", and "hostport" from
+ [RFC2396], as updated by [RFC2732] and [RFC2373] (for IPv6 addresses
+ in URLs).
+
+ The 'ippget' URL scheme syntax in ABNF is as follows:
+
+ ippget_URL = "ippget:" "//" authority [ abs_path [ "?" query ]]
+ authority = server | reg_name
+ reg_name = 1*( unreserved | escaped | "$" | "," |
+ ";" | ":" | "@" | "&" | "=" | "+" )
+ server = [ [ userinfo "@" ] hostport ]
+ userinfo = *( unreserved | escaped |
+ ";" | ":" | "&" | "=" | "+" | "$" | "," )
+
+Herriot, et al. Expires: August 28, 2001 [page 22]
+
+
+INTERNET-DRAFT IPP: The 'ippget' Delivery Method February 28, 2001
+
+
+ hostport = host [ ":" port ]
+ abs_path = "/" path_segments
+
+ If the port is empty or not given, then no port is assumed. The
+ semantics are that the 'ippget' URL is a unique identifier for an IPP
+ Client that will retrieve IPP event notifications via the IPP Get-
+ Notifications operation.
+
+ Note: The use of IP addresses in URLs SHOULD be avoided whenever
+ possible (see [RFC1900]).
+
+
+9.5.1 IPPGET URL Examples
+
+ The following are examples of valid 'ippget' URLs for IPP Clients
+ (using DNS host names):
+
+ ippget://abc.com
+ ippget://abc.com/listener
+ ippget://bob@abc.com/listener/1232
+
+ Note: The use of IP addresses in URLs SHOULD be avoided whenever
+ possible (see [RFC1900]).
+
+ The choice of 'userinfo@hostport' versus the simpler 'hostport'
+ production in an 'ippget' URL may be influenced by the intended
+ usage.
+
+ If a given IPP Client creates an IPP Subscription object for event
+ notifications intended for retrieval by the same IPP Client, then the
+ simple 'hostport' production may be most appropriate.
+
+ On the other hand, if a given IPP Client creates an IPP Subscription
+ object for event notifications intended for retrieval by a different
+ IPP Client, then the 'userinfo@hostport' production (using, for
+ example, the right-hand side of a 'mailto:' URL, see [RFC2368]) may
+ be most appropriate.
+
+
+9.5.2 IPPGET URL Comparisons
+
+ When comparing two 'ippget' URLs to decide if they match or not, an
+ IPP Client or IPP Printer SHOULD use a case-sensitive octet-by-octet
+ comparison of the entire URLs, with these exceptions:
+
+ - Comparisons of host names MUST be case-insensitive;
+
+ - Comparisons of scheme names MUST be case-insensitive;
+
+ - An empty 'abs_path' is equivalent to an 'abs_path' of "/".
+
+Herriot, et al. Expires: August 28, 2001 [page 23]
+
+
+INTERNET-DRAFT IPP: The 'ippget' Delivery Method February 28, 2001
+
+
+ Characters other than those in the "reserved" and "unsafe" sets (see
+ [RFC2396] and [RFC2732]) are equivalent to their ""%" HEX HEX"
+ encoding.
+
+ For example, the following three URIs are equivalent:
+
+ ippget://abc.com/~smith/listener
+
+ ippget://ABC.com/%7Esmith/listener
+
+ ippget://ABC.com:/%7esmith/listener
+
+
+10 Encoding
+
+ This notification delivery method uses the IPP transport and encoding
+ [RFC2910] for the Get-Notifications operation with one extension
+ allocated in [ipp-ntfy]:
+
+
+ Table 7 - The "event-notification-attributes-tag" value
+
+
+ Tag Value (Hex) Meaning
+
+
+ 0x07 "event-notification-attributes-tag"
+
+
+
+11 Conformance Requirements
+
+
+11.1 Conformance for IPP Printers
+
+ IPP Printers that conform to this specification:
+
+ 1. MUST meet the conformance requirements defined in [ipp-ntfy];
+
+ 2. MUST support the Get-Notifications operation defined in section
+ 5;
+
+ 3. MUST support the Subscription object attributes as defined in
+ section 6;
+
+ 4. MUST support the additional values for IPP/1.1 Printer
+ Description attributes defined in section 7.2;
+
+ 5. MUST support the "begin-to-expire-time-interval" Printer
+ Description attribute defined in section 7.3;
+
+Herriot, et al. Expires: August 28, 2001 [page 24]
+
+
+INTERNET-DRAFT IPP: The 'ippget' Delivery Method February 28, 2001
+
+
+ 6. MUST support the "redirection-other-site" status code defined
+ 8.1;
+
+ 7. SHOULD reject received 'ippget' URLs in 'application/ipp'
+ request bodies (e.g., in the "notify-recipient-uri" attribute in
+ a Get-Notifications request) that do not conform to the ABNF for
+ 'ippget' URLs specified in section 9.5 of this document;
+
+ 8. MUST listen for the IPP Get-Notifications operation requests on
+ IANA-assigned well-known port 631, unless explicitly configured
+ by system administrators or site policies;
+
+ 9. SHOULD NOT listen for IPP Get-Notifications operation requests
+ on any other port, unless explicitly configured by system
+ administrators or site policies.
+
+
+11.2 Conformance for IPP Clients
+
+ IPP Clients that conform to this specification:
+
+ 1.MUST create unambiguously unique 'ippget' URLs in all cases;
+
+ 2.MUST send 'ippget' URLs (e.g., in the "notify-recipient-uri"
+ attribute in a Get-Notifications request) that conform to the
+ ABNF specified in section 9.5 of this document;
+
+ 3.MUST send IPP Get-Notifications operation requests via the port
+ specified in the associated 'ipp' URL (if present) or otherwise
+ via IANA assigned well-known port 631;
+
+ 4.MUST convert the associated 'ipp' URLs to their corresponding
+ 'http' URL forms according to the rules in section 5 "IPP URL
+ Scheme" in [RFC2910].
+
+ Note: The use of ambiguous 'ippget' URLs is NOT an optional feature
+ for IPP Clients; it is a non-conformant implementation error.
+
+
+12 IANA Considerations
+
+ IANA is requested to register the 'ippget' URL scheme as defined in
+ section 9 according to the procedures of [RFC2717].
+
+ The rest of this section contains the exact information for
+ additional IPP entities for IANA to add to the IPP Registries
+ according to the procedures defined in RFC 2911 [RFC2911] section 6.
+
+
+
+
+Herriot, et al. Expires: August 28, 2001 [page 25]
+
+
+INTERNET-DRAFT IPP: The 'ippget' Delivery Method February 28, 2001
+
+
+ Note to RFC Editors: Replace RFC NNNN below with the RFC number
+ for this document, so that it accurately reflects the content of
+ the information for the IANA Registry.
+
+
+12.1 Operation Registrations
+
+ The operations defined in this document will be published by IANA
+ according to the procedures in RFC 2911 [RFC2911] section 6.4 with
+ the following path:
+
+ ftp.isi.edu/iana/assignments/ipp/operations/
+
+ The registry entry will contain the following information:
+
+ Operations: Ref. Section:
+ Get-Notifications operation RFC NNNN 5
+
+
+12.2 Additional values of existing attributes
+
+
+12.2.1 Additional values for the "notify-schemes-supported" Printer
+ attribute
+
+ The "notify-schemes-supported" 'uriScheme' attribute value defined in
+ this document will be published by IANA according to the procedures
+ in RFC 2911 [RFC2911] section 6.1 with the following path:
+
+ ftp.isi.edu/iana/assignments/ipp/attribute-values/notify-schemes-
+ supported/
+
+ The registry entry will contain the following information:
+
+ Ref. Section:
+ ippget RFC NNNN 7.2.1
+
+
+12.2.2 Additional values for the "operations-supported" Printer
+ attribute
+
+ The "operations-supported" type2 enum attribute value defined in this
+ document will be published by IANA according to the procedures in RFC
+ 2911 [RFC2911] section 6.1 with the following path:
+
+ ftp.isi.edu/iana/assignments/ipp/attribute-values/operations-
+ supported/
+
+ The registry entry will contain the following information:
+
+
+Herriot, et al. Expires: August 28, 2001 [page 26]
+
+
+INTERNET-DRAFT IPP: The 'ippget' Delivery Method February 28, 2001
+
+
+ Value Ref. Section:
+ Get-Notifications 0x001C RFC NNNN 7.2.2
+
+
+12.3 Attribute Registrations
+
+ The attributes defined in this document will be published by IANA
+ according to the procedures in RFC 2911 [RFC2911] section 6.2 with
+ the following path:
+
+ ftp.isi.edu/iana/assignments/ipp/attributes/
+
+ The registry entry will contain the following information:
+
+ Printer Description attributes: Ref. Section:
+ begin-to-expire-time-interval (integer(0:MAX)) RFC NNNN 7.3
+
+12.4 Status code Registrations
+
+ The status codes defined in this document will be published by IANA
+ according to the procedures in RFC 2911 [RFC2911] section 6.6 with
+ the following path:
+
+ ftp.isi.edu/iana/assignments/ipp/status-codes/
+
+ The registry entry will contain the following information:
+
+ Status codes: Ref. Section:
+ redirection-other-site (0x300) RFC NNNN 8.1
+
+
+13 Internationalization Considerations
+
+ The IPP Printer MUST localize the "notify-text" attribute as
+ specified in section 14 of [ipp-ntfy].
+
+ In addition, when the client receives the Get-Notifications response,
+ it is expected to localize the attributes that have the 'keyword'
+ attribute syntax according to the charset and natural language
+ requested in the Get-Notifications request.
+
+
+14 Security Considerations
+
+ The IPP Model and Semantics document [RFC2911] discusses high-level
+ security requirements (Client Authentication, Server Authentication
+ and Operation Privacy). Client Authentication is the mechanism by
+ which the client proves its identity to the server in a secure
+ manner. Server Authentication is the mechanism by which the server
+ proves its identity to the client in a secure manner. Operation
+
+Herriot, et al. Expires: August 28, 2001 [page 27]
+
+
+INTERNET-DRAFT IPP: The 'ippget' Delivery Method February 28, 2001
+
+
+ Privacy is defined as a mechanism for protecting operations from
+ eavesdropping.
+
+ Unlike other Event Notification delivery methods in which the IPP
+ Printer initiates the Event Notification, with the method defined in
+ this document, the Notification Recipient is the client who s the
+ Get-Notifications operation. Therefore, there is no chance of "spam"
+ notifications with this method. Furthermore, such a client can close
+ down the HTTP channel at any time, and so can avoid future unwanted
+ Event Notifications at any time.
+
+
+15 References
+
+ [ipp-iig]
+ Hastings, T., Manros, C., Kugler, K, Holst H., Zehler, P.,
+ "Internet Printing Protocol/1.1: draft-ietf-ipp-implementers-
+ guide-v11-02.txt, work in progress, January 25, 2001
+
+ [ipp-ntfy]
+ R. Herriot, Hastings, T., Isaacson, S., Martin, J., deBry, R.,
+ Shepherd, M., Bergman, R., "Internet Printing Protocol/1.1: IPP
+ Event Notification Specification", <draft-ietf-ipp-not-spec-
+ 06.txt>, February 24, 2001.
+
+ [RFC1900]
+ B. Carpenter, Y. Rekhter. Renumbering Needs Work, RFC 1900,
+ February 1996.
+
+ [RFC2026]
+ S. Bradner, "The Internet Standards Process -- Revision 3", RFC
+ 2026, October 1996.
+
+ [RFC2119]
+ S. Bradner, "Key words for use in RFCs to Indicate Requirement
+ Levels", RFC 2119 , March 1997
+
+ [RFC2368]
+ P. Hoffman, L. Masinter, J. Zawinski. The "mailto" URL Scheme, RFC
+ 2368, July 1998.
+
+ [RFC2373]
+ R. Hinden, S. Deering. IP Version 6 Addressing Architecture, RFC
+ 2373, July 1998.
+
+ [RFC2396]
+ Berners-Lee, T. et al. Uniform Resource Identifiers (URI): Generic
+ Syntax, RFC 2396, August 1998
+
+
+
+Herriot, et al. Expires: August 28, 2001 [page 28]
+
+
+INTERNET-DRAFT IPP: The 'ippget' Delivery Method February 28, 2001
+
+
+ [RFC2567]
+ Wright, D., "Design Goals for an Internet Printing Protocol", RFC
+ 2567, April 1999.
+
+ [RFC2568]
+ Zilles, S., "Rationale for the Structure and Model and Protocol for
+ the Internet Printing Protocol", RFC 2568, April 1999.
+
+ [RFC2569]
+ Herriot, R., Hastings, T., Jacobs, N., Martin, J., "Mapping between
+ LPD and IPP Protocols", RFC 2569, April 1999.
+
+ [RFC2616]
+ R. Fielding, J. Gettys, J. Mogul, H. Frystyk, L. Masinter, P.
+ Leach, T. Berners-Lee, "Hypertext Transfer Protocol - HTTP/1.1",
+ RFC 2616, June 1999.
+
+ [RFC2717]
+ R. Petke and I. King, "Registration Procedures for URL Scheme
+ Names", RFC 2717, November 1999.
+
+ [RFC2732]
+ R. Hinden, B. Carpenter, L. Masinter. Format for Literal IPv6
+ Addresses in URL's, RFC 2732, December 1999.
+
+ [RFC2910]
+ Herriot, R., Butler, S., Moore, P., Tuner, R., "Internet Printing
+ Protocol/1.1: Encoding and Transport", RFC 2910, September 2000.
+
+ [RFC2911]
+ R. deBry, T. Hastings, R. Herriot, S. Isaacson, P. Powell,
+ "Internet Printing Protocol/1.1: Model and Semantics", RFC 2911,
+ September 2000.
+
+
+16 Authors' Addresses
+
+
+ Robert Herriot
+ Xerox Corp.
+ 3400 Hill View Ave, Building 1
+ Palo Alto, CA 94304
+
+ Phone: 650-813-7696
+ Fax: 650-813-6860
+ e-mail: robert.herriot@pahv.xerox.com
+
+
+ Carl Kugler
+ IBM
+
+Herriot, et al. Expires: August 28, 2001 [page 29]
+
+
+INTERNET-DRAFT IPP: The 'ippget' Delivery Method February 28, 2001
+
+
+ P.O. Box 1900
+ Boulder, CO 80301-9191
+
+ Phone:
+ Fax:
+ e-mail: kugler@us.ibm.com
+
+ Harry Lewis
+ IBM
+ P.O. Box 1900
+ Boulder, CO 80301-9191
+
+ Phone: 303-924-5337
+ FAX:
+ e-mail: harryl@us.ibm.com
+
+
+17 Full Copyright Statement
+
+ Copyright (C) The Internet Society (2001). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+Herriot, et al. Expires: August 28, 2001 [page 30]
diff --git a/standards/draft-ietf-ipp-notify-mailto-03.txt b/standards/draft-ietf-ipp-notify-mailto-03.txt
new file mode 100644
index 000000000..4be0dd94e
--- /dev/null
+++ b/standards/draft-ietf-ipp-notify-mailto-03.txt
@@ -0,0 +1,1740 @@
+
+
+
+
+
+
+INTERNET-DRAFT
+<draft-ietf-ipp-notify-mailto-03.txt> Robert Herriot
+Category: standards track Xerox Corp.
+ Henrik Holst
+ i-data international a/s
+ Tom Hastings
+ Xerox Corp.
+ Carl-Uno Manros
+ Xerox Corp.
+ August 30, 2000
+
+ Internet Printing Protocol (IPP):
+ The 'mailto' Delivery Method for Event Notifications
+
+ Copyright (C) The Internet Society (2000). All Rights Reserved.
+
+Status of this Memo
+
+This document is an Internet-Draft and is in full conformance with all
+provisions of Section 10 of [RFC2026]. Internet-Drafts are working
+documents of the Internet Engineering Task Force (IETF), its areas, and
+its working groups. Note that other groups may also distribute working
+documents as Internet-Drafts.
+
+Internet-Drafts are draft documents valid for a maximum of six months
+and may be updated, replaced, or obsoleted by other documents at any
+time. It is inappropriate to use Internet-Drafts as reference material
+or to cite them other than as "work in progress".
+
+The list of current Internet-Drafts can be accessed at
+http://www.ietf.org/ietf/1id-abstracts.txt
+
+The list of Internet-Draft Shadow Directories can be accessed as
+http://www.ietf.org/shadow.html.
+
+
+Abstract
+
+
+The notification extension document [ipp-ntfy] defines operations that a
+client can perform in order to create Subscription Objects in a Printer
+and carry out other operations on them. The Subscription Object
+specifies that when one of the specified Events occurs, the Printer
+sends an asynchronous Event Notification to the specified Notification
+Recipient via the specified Delivery Method (i.e., protocol).
+
+
+The notification extension document [ipp-ntfy] specifies that each
+Delivery Method is defined in another document. This document is one
+such document, and it specifies the 'mailto' delivery method.
+
+Herriot, et al. Expires: March 1, 2001 [page 1]
+
+
+PWG-DRAFT IPP: The 'mailto:' Delivery Method August 30, 2000
+
+
+For this Delivery Method, when an Event occurs, the Printer immediately
+sends an Event Notification via an email message to the Notification
+Recipient specified in the Subscription Object. The message body of the
+email consists of Human Consumable text that is not intended to be
+parsed by a machine.
+
+
+The Notification Recipient receives the Event Notification in the same
+way as it receives any other email message.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Expires: March 1, 2001 [page 2]
+
+
+PWG-DRAFT IPP: The 'mailto:' Delivery Method August 30, 2000
+
+
+The basic set of IPP documents includes:
+
+ Design Goals for an Internet Printing Protocol [RFC2567]
+ Rationale for the Structure and Model and Protocol for the Internet
+ Printing Protocol [RFC2568]
+ Internet Printing Protocol/1.1: Model and Semantics [ipp-mod]
+ Internet Printing Protocol/1.1: Encoding and Transport [ipp-pro]
+ Internet Printing Protocol/1.1: Implementer's Guide [ipp-iig]
+ Mapping between LPD and IPP Protocols [RFC2569]
+ Internet Printing Protocol (IPP): IPP Event Notification
+ Specification [ipp-ntfy]
+
+The "Design Goals for an Internet Printing Protocol" document takes a
+broad look at distributed printing functionality, and it enumerates
+real-life scenarios that help to clarify the features that need to be
+included in a printing protocol for the Internet. It identifies
+requirements for three types of users: end users, operators, and
+administrators. It calls out a subset of end user requirements that are
+satisfied in IPP/1.0. A few OPTIONAL operator operations have been
+added to IPP/1.1.
+
+The "Rationale for the Structure and Model and Protocol for the Internet
+Printing Protocol" document describes IPP from a high level view,
+defines a roadmap for the various documents that form the suite of IPP
+specification documents, and gives background and rationale for the IETF
+working group's major decisions.
+
+The "Internet Printing Protocol/1.1: Model and Semantics" document
+describes a simplified model with abstract objects, their attributes,
+and their operations that are independent of encoding and transport. It
+introduces a Printer and a Job object. The Job object optionally
+supports multiple documents per Job. It also addresses security,
+internationalization, and directory issues.
+
+The "Internet Printing Protocol/1.1: Encoding and Transport" document is
+a formal mapping of the abstract operations and attributes defined in
+the model document onto HTTP/1.1 [RFC2616]. It defines the encoding
+rules for a new Internet MIME media type called "application/ipp". This
+document also defines the rules for transporting over HTTP a message
+body whose Content-Type is "application/ipp". This document also
+defines a new scheme named 'ipp' for identifying IPP printers and jobs.
+
+The "Internet Printing Protocol/1.1: Implementer's Guide" document gives
+insight and advice to implementers of IPP clients and IPP objects. It
+is intended to help them understand IPP/1.1 and some of the
+considerations that may assist them in the design of their client and/or
+IPP object implementations. For example, a typical order of processing
+requests is given, including error checking. Motivation for some of the
+specification decisions is also included.
+
+
+
+Herriot, et al. Expires: March 1, 2001 [page 3]
+
+
+PWG-DRAFT IPP: The 'mailto:' Delivery Method August 30, 2000
+
+
+The "Mapping between LPD and IPP Protocols" document gives some advice
+to implementers of gateways between IPP and LPD (Line Printer Daemon)
+implementations.
+
+
+The "Event Notification Specification" document describes an extension
+to the IPP/1.0, IPP/1.1, and future versions. This extension allows a
+client to subscribe to printing related Events. The Subscription Object
+specifies that when one of the specified Event occurs, the Printer sends
+an asynchronous Event Notification to the specified Notification
+Recipient via the specified Delivery Method (i.e., protocol). A client
+associates Subscription Objects with a particular Job by performing the
+Create-Job-Subscriptions operation or by submitting a Job with
+subscription information. A client associates Subscription Objects with
+the Printer by performing a Create-Printer-Subscriptions operation.
+Four other operations are defined for Subscription Objects: Get-
+Subscriptions-Attributes, Get-Subscriptions, Renew-Subscription, and
+Cancel-Subscription.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Expires: March 1, 2001 [page 4]
+
+
+PWG-DRAFT IPP: The 'mailto:' Delivery Method August 30, 2000
+
+
+ Table of Contents
+
+1 Introduction ......................................................7
+
+2 Terminology .......................................................7
+
+3 Model and Operation ...............................................7
+
+4 General Information ...............................................9
+
+5 Subscription Template Attributes .................................11
+ 5.1 Additional Subscription Template Attributes ...................11
+ 5.1.1 notify-mailto-text-only (boolean)..........................11
+ 5.2 Additional Information about Subscription Template Attributes .12
+ 5.2.1 notify-recipient-uri (uri).................................12
+ 5.2.2 notify-user-data (octetString(63)).........................12
+
+6 Event Notification Content .......................................13
+ 6.1 Headers .......................................................13
+ 6.1.1 'Date' header..............................................13
+ 6.1.2 'From' header..............................................14
+ 6.1.3 'Subject' header...........................................14
+ 6.1.4 'Sender' header............................................15
+ 6.1.5 'Reply-to' header..........................................15
+ 6.1.6 'To' header................................................15
+ 6.1.7 'Content-type' header......................................16
+ 6.2 Message Body ..................................................16
+ 6.3 Plain Text Content ............................................17
+ 6.3.1 Event Notification Content Common to All Events............18
+ 6.3.2 Additional Event Notification Content for Job Events.......20
+ 6.3.3 Additional Event Notification Content for Printer Events...21
+ 6.4 Examples ......................................................21
+ 6.4.1 Job Event Example..........................................22
+ 6.4.2 Printer Event Example......................................23
+ 6.4.3 Printer Event Example (localized to Danish)...............24
+
+7 Conformance Requirements .........................................25
+
+8 IANA Considerations ..............................................26
+
+9 Internationalization Considerations ..............................26
+
+10 Security Considerations ..........................................26
+
+11 References .......................................................27
+
+12 Author's Addresses ...............................................28
+
+13 Full Copyright Statement .........................................29
+
+
+
+Herriot, et al. Expires: March 1, 2001 [page 5]
+
+
+PWG-DRAFT IPP: The 'mailto:' Delivery Method August 30, 2000
+
+
+ Table of Tables
+
+Table 1 - Information about the Delivery Method.......................9
+
+
+Table 2 - Additional Subscription Template Attributes................11
+
+
+Table 3 - Printer Name in Event Notification Content.................19
+
+
+Table 4 - Event Name in Event Notification Content...................19
+
+
+Table 5 - Job Name in Event Notification Content.....................20
+
+
+Table 6 - Job State in Event Notification Content....................20
+
+
+Table 7 - Printer State in Event Notification Content................21
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Expires: March 1, 2001 [page 6]
+
+
+PWG-DRAFT IPP: The 'mailto:' Delivery Method August 30, 2000
+
+
+1 Introduction
+
+The notification extension document [ipp-ntfy] defines operations that a
+client can perform in order to create Subscription Objects in a Printer
+and carry out other operations on them. A Subscription Object represents
+a Subscription abstraction. The Subscription Object specifies that when
+one of the specified Events occurs, the Printer sends an asynchronous
+Event Notification to the specified Notification Recipient via the
+specified Delivery Method (i.e., protocol).
+
+
+The notification extension document [ipp-ntfy] specifies that each
+Delivery Method is defined in another document. This document is one
+such document, and it specifies the 'mailto' delivery method.
+
+
+For this Delivery Method, when an Event occurs, the Printer immediately
+sends an Event Notification via an email message to the Notification
+Recipient specified in the Subscription Object. The message body of the
+email consists of Human Consumable text that is not intended to be
+parsed by a machine. The 'mailto' Delivery Method is a 'push' Delivery
+Method as defined in [ipp-ntfy].
+
+
+The Notification Recipient receives the Event Notification in the same
+way as it receives any other email message.
+
+
+2 Terminology
+
+This section defines the following terms that are used throughout this
+document:
+
+
+Capitalized terms, such as MUST, MUST NOT, REQUIRED, SHOULD, SHOULD NOT,
+MAY, NEED NOT, and OPTIONAL, have special meaning relating to
+conformance to this specification. These terms are defined in [ipp-mod
+section 13.1 on conformance terminology, most of which is taken from RFC
+2119 [RFC2119].
+
+
+For capitalized terms that appear in this document, see [ipp-ntfy].
+
+
+3 Model and Operation
+
+In a Subscription Creation Operation, when the value of the "notify-
+recipient-uri" attribute contains the scheme "mailto", the client is
+requesting that the Printer use the 'mailto' Delivery Method for Event
+Notifications generated from the new Subscription Object.
+
+
+Herriot, et al. Expires: March 1, 2001 [page 7]
+
+
+PWG-DRAFT IPP: The 'mailto:' Delivery Method August 30, 2000
+
+
+For this Delivery Method, the "notify-recipient-uri" attribute value
+MUST consist of a "mailto" scheme followed by a colon, and then followed
+by an address part (e.g. 'mailto:smith@abc.com'). See section 5.2.1 for
+the syntax of the "notify-recipient-uri" attribute value for this
+Delivery Method.
+
+
+A Printer MUST support SMTP [RFC821], and it MAY support other email
+protocols. A Printer MAY use additional services, such as SMTP delivery
+status notification [RFC1891] or S/MIME encryption [RFC2633].
+
+
+If the client wants the Printer to send Event Notifications via the
+'mailto' Delivery Method, the client MUST choose a value for "notify-
+recipient-uri" attribute which conforms to the rules of section 5.2.1.
+To avoid denial-of-service attacks, a client SHOULD NOT use distribution
+lists as the Notification Recipient.
+
+
+When an Event occurs, the Printer MUST immediately:
+
+
+ 1. Find all pertinent Subscription Objects P according to the rules of
+ section 9 of [ipp-ntfy], AND
+
+
+ 2. Find the subset M of these Subscription Objects P whose "notify-
+ recipient-uri" attribute has a scheme value of 'mailto', AND
+
+
+ 3. For each Subscription Object in M, the Printer MUST
+
+
+ a)generate an email message as specified in section 5.2.2 AND
+
+
+ b)send the email message to the Notification Recipient specified
+ by the address part of the "notify-recipient-uri" attribute
+ value (see section 5.2.1).
+
+
+If the Printer supports only SMTP, it MUST send the email message via
+SMTP. If the Printer supports additional email protocols, it MUST
+determine the protocol from the address part of the "notify-recipient-
+uri" attribute value and then send the email message via the appropriate
+email protocol.
+
+
+When a Subscribing Client is subscribing to the 'job-progress' event
+(which is a frequently occurring event), it SHOULD supply the "notify-
+
+
+Herriot, et al. Expires: March 1, 2001 [page 8]
+
+
+PWG-DRAFT IPP: The 'mailto:' Delivery Method August 30, 2000
+
+
+time-interval" attribute (see [ipp-ntfy]) in the Subscription Creation
+request with a suitable value to limit the time between 'job-progress'
+Event Notifications sent by the Printer.
+
+
+4 General Information
+If a Printer supports this Delivery Method, the following are its
+characteristics.
+
+
+ Table 1 - Information about the Delivery Method
+
+
+
+ Document Method Conformance Delivery Method Realization
+ Requirement
+
+
+ 1.What is the URL scheme name mailto
+ for the Delivery Method?
+
+ 2.Is the Delivery Method
+ REQUIRED, RECOMMENDED, or
+ OPTIONAL for an IPP Printer to RECOMMENDED
+ support?
+
+ 3.What transport and delivery A Printer MUST support SMTP. It MAY
+ protocols does the Printer use support other email protocols.
+ to deliver the Event
+ Notification Content, i.e.,
+ what is the entire network
+ stack?
+
+ 4.Can several Event A Printer implementation MAY
+ Notifications be combined into combine several Event Notifications
+ a Compound Event Notification? into a single email message.
+
+ 5.Is the Delivery Method This Delivery Method is a push.
+ initiated by the Notification
+ Recipient (pull), or by the
+ Printer (push)?
+
+ 6.Is the Event Notification Human Consumable
+ content Machine Consumable or
+ Human Consumable?
+
+ 7.What section in this document Section 6
+ answers the following
+ question? For a Machine
+
+
+
+Herriot, et al. Expires: March 1, 2001 [page 9]
+
+
+PWG-DRAFT IPP: The 'mailto:' Delivery Method August 30, 2000
+
+
+
+ Consumable Event Notification,
+ what is the representation and
+ encoding of values defined in
+ section 9.1 of [ipp-ntfy] and
+ the conformance requirements
+ thereof? For a Human
+ Consumable Event Notification,
+ what is the representation and
+ encoding of pieces of
+ information defined in section
+ 9.2 of [ipp-ntfy] and the
+ conformance requirements
+ thereof?
+
+ 8.What are the latency and Same as the underlying SMTP (or
+ reliability of the transport other optional) email transport
+ and delivery protocol?
+
+ 9.What are the security aspects Same as the underlying SMTP (or
+ of the transport and delivery other optional) email transport
+ protocol, e.g., how it is
+ handled in firewalls?
+
+ 10. What are the content length None
+ restrictions?
+
+ 11. What are the additional None
+ values or pieces of
+ information that a Printer
+ sends in an Event Notification
+ content and the conformance
+ requirements thereof?
+
+ 12. What are the additional See section 5.1.1 on "notify-
+ Subscription Template and/or mailto-text-only"
+ Subscription Description
+ attributes and the conformance
+ requirements thereof?
+
+ 13. What are the additional None
+ Printer Description attributes
+ and the conformance
+ requirements thereof?
+
+
+
+
+
+
+
+
+Herriot, et al. Expires: March 1, 2001 [page 10]
+
+
+PWG-DRAFT IPP: The 'mailto:' Delivery Method August 30, 2000
+
+
+5 Subscription Template Attributes
+
+5.1 Additional Subscription Template Attributes
+
+
+This Delivery Method introduces one additional Subscription Template
+Attribute (See Table 2).
+
+
+ Table 2 - Additional Subscription Template Attributes
+
+
+
+Attribute in Subscription Default and Supported Printer
+Object Attributes
+
+
+notify-mailto-text-only N/A
+(boolean)
+
+
+5.1.1notify-mailto-text-only (boolean)
+
+
+When the Printer generates an Event Notification from a Subscription
+Object, this attribute specifies whether the Printer generates the Event
+Notification with only plain text (i.e. 'text/plain') or with Content-
+Types that the Printer chooses.
+
+
+The Printer MUST support this attribute if it supports the 'mailto'
+Delivery Method.
+
+
+A client MAY supply this attribute. If a client does not supply this
+attribute, the Printer MUST populate this attribute with the value of
+'false' on the Subscription Object. There is no "notify-mailto-text-
+only-default" attribute.
+
+
+If the value of this attribute is 'true' in a Subscription Object, the
+message body of each Event Notification that the Printer generates from
+the Subscription Object MUST contain plain text only (i.e. 'text/plain'
+with the charset specified by the "notify-charset' Subscription Object
+attribute).
+
+
+If the value of this attribute is 'false' in a Subscription Object, the
+Content-Type of the message body of each Event Notification that the
+Printer generates from the Subscription Object MUST be either
+
+
+Herriot, et al. Expires: March 1, 2001 [page 11]
+
+
+PWG-DRAFT IPP: The 'mailto:' Delivery Method August 30, 2000
+
+
+'text/plain' or 'multipart', depending on implementation. If the
+Content-Type is 'multipart', one message body of the 'multipart' MUST be
+the same as the 'text/plain' message body when this attribute has the
+value of 'true'. Each of the other message bodies of the 'multipart' MAY
+be any Content-Type (e.g. 'text/html', 'image/gif', 'audio/basic',
+etc.).
+
+
+A Printer MUST support both values ('true' and 'false') of this
+attribute. There is no "notify-mailto-text-only-supported" attribute.
+
+
+5.2 Additional Information about Subscription Template Attributes
+
+
+This section describes additional values for attributes defined in [ipp-
+ntfy].
+
+
+5.2.1notify-recipient-uri (uri)
+
+This section describes the syntax of the value of this attribute for the
+'mailto' Delivery Method. The syntax for values of this attribute for
+other Delivery Method is defined in other Delivery Method Documents.
+
+
+In order to support the 'mailto' Delivery Method, the Printer MUST
+support the following syntax for the 'mailto' Delivery Method when the
+Printer uses SMTP. The line below use RFC 822 syntax rules and terms.
+
+
+ "mailto:" mailbox
+
+Note: the above syntax allows 1 occurrence of 'mailbox'. The occurrence
+of 'mailbox' represents an email address of a Notification Recipient.
+
+For SMTP, the phrase 'address part' of the "notify-recipient-uri"
+attribute value refers to the 'mailbox' part of the value.
+
+The Printer MAY support other syntax for the 'address part' if it
+supports email protocols in addition to SMTP.
+
+
+5.2.2notify-user-data (octetString(63))
+
+This attributes has a special use for the 'mailto' Delivery Method. It
+specifies the email address of the Subscribing Client. It is primarily
+useful when the Notification Recipient is some person other than the
+Subscribing Client. Then the Notification Recipient has a way to reply
+to the Subscribing Client.
+
+
+Herriot, et al. Expires: March 1, 2001 [page 12]
+
+
+PWG-DRAFT IPP: The 'mailto:' Delivery Method August 30, 2000
+
+
+If a client specifies this Delivery Method in a Subscription Creation
+Operation, and the specified Notification Recipient is not associated
+with the same person as the client, the client SHOULD supply its email
+address as the value of the "notify-user-data" attribute. If the client
+does not supply this attribute, the Printer MUST NOT populate the
+Subscription Object with this attribute.
+
+
+6 Event Notification Content
+
+This section describes the content of an Event Notification sent via the
+'mailto' Delivery Method using the SMTP protocol. This document does
+not describe the content for other email protocols, but an
+implementation should use this section as a model.
+
+
+When a Printer sends an email message via SMTP, the content MUST conform
+to RFC 822. The following sections define the content that a Printer
+MUST send. A Printer MAY send additional content as long as the
+resulting content conforms to RFC 822.
+
+
+Each subsection below specifies the syntax that pertains to the
+subsection. The syntax rules and syntactic terms (e.g. 'date-time') in
+each subsection come from RFC 822, except for the section on "Content-
+Type" which comes from RFC 1521.
+
+
+The Event Notification content has two parts, the headers and the
+message body. The headers precede the message body and are separated by
+a blank line (see [RFC 822]).
+
+
+6.1 Headers
+
+
+When a Printer sends an Event Notification via SMTP, it MUST include the
+following headers. RFC 822 RECOMMENDS that the headers be in the order
+that they appear below.
+
+
+6.1.1'Date' header
+
+Syntax: "Date" ":" date-time
+
+This header contains the date and time that the Event occurred.
+
+The Printer MUST include a "Date" header if and only if it supports the
+"printer-current-time" Printer attribute.
+
+
+
+Herriot, et al. Expires: March 1, 2001 [page 13]
+
+
+PWG-DRAFT IPP: The 'mailto:' Delivery Method August 30, 2000
+
+
+6.1.2 'From' header
+
+Syntax: "From" ":" mailbox
+
+ where
+
+ mailbox = addr-spec / phrase route-addr
+
+This header causes a typical email reader to show the email as coming
+from the Printer that is sending the Event Notification.
+
+The Printer MUST include a "From" header whose syntax is specified
+above.
+
+The Printer MUST use the second alternative of the syntax for 'mailbox'
+defined above (i.e. 'phrase route-addr'). The 'phrase' is the
+Printer's display name and it MUST be the value of the "printer-name"
+Printer attribute. The 'route-addr' MUST contain an email address
+(inside angle brackets) belonging to either an administrator or the
+output-device. This email address NEED NOT be capable of receiving mail.
+There is no Printer attribute to hold this email address, so that it
+cannot be configured using the IPP protocol without an implementation-
+defined attribute extension.
+
+
+6.1.3'Subject' header
+
+Syntax: "Subject" ":" *text
+
+This header specifies the subject of the message and contains a short
+summary of the Event Notification.
+
+The Printer MUST include a "Subject" header whose syntax is specified
+above.
+
+
+The Printer MUST localize the '*text' using the values of the "notify-
+charset" and "notify-natural-language" Subscription Object attributes.
+
+For Printer Events, the '*text' SHOULD start with the localized word
+"printer:", followed by the Printer name, and then followed by the
+localized Event name, e.g., in English: "printer: 'tiger' stopped" or in
+Danish: 'Printeren 'tiger' er standset'.
+
+For Job Events, the '*text' SHOULD start with the localized phrase
+"print job:", followed by the Job name, and then followed by the
+localized Event name, e.g., in English: "print job: 'financials'
+completed".
+
+
+
+
+Herriot, et al. Expires: March 1, 2001 [page 14]
+
+
+PWG-DRAFT IPP: The 'mailto:' Delivery Method August 30, 2000
+
+
+The wording is implementation dependent. A Notification Recipient MUST
+NOT expect to be able to parse this text. But an email filter might look
+for "printer" or "print job".
+
+
+6.1.4 'Sender' header
+
+Syntax: "Sender" ":" mailbox
+
+This header causes a typical email reader to show the email as coming on
+behalf of the person associated with the Subscribing Client.
+
+
+If the Subscription Object contains the "notify-user-data" attribute,
+and if its value satisfies the RFC 822 syntax rules for 'mailbox', the
+Printer MUST include a "Sender" header whose syntax is specified above.
+Otherwise, the Printer MUST NOT include a "Sender" header.
+
+For the "Sender" header, the 'mailbox' MUST be the value of the "notify-
+user-data" Subscription Object attribute. See section 5.2.2 for details
+about the "notify-user-data" attribute.
+
+
+6.1.5 'Reply-to' header
+
+Syntax: "Reply-to" ":" mailbox
+
+If the Notification Recipient replies to Event Notification email, this
+header causes a typical email reader to send email to the person acting
+as the Subscribing Client. The rules are identical to the "Sender"
+header.
+
+
+If the Subscription Object contains the "notify-user-data" attribute,
+and if its value satisfies the RFC 822 syntax rules for "mailbox", the
+Printer MUST include a "Reply-to" header whose syntax is specified
+above. Otherwise, the Printer MUST NOT include a "Reply-to" header.
+
+For the "Reply-to" header, the "mailbox" MUST be the value of the
+"notify-user-data" Subscription Object attribute. See section 5.2.2 for
+details about the "notify-user-data" attribute.
+
+
+6.1.6 'To' header
+
+
+Syntax: "To" ":" 1#mailbox
+
+See [RFC 1521] for the syntax.
+
+
+
+Herriot, et al. Expires: March 1, 2001 [page 15]
+
+
+PWG-DRAFT IPP: The 'mailto:' Delivery Method August 30, 2000
+
+
+This header specifies the Notification Recipient(s).
+
+The Printer MUST include a "To" header whose syntax is specified above.
+
+The '1#mailbox' MUST be the '1#mailbox' part of the value of the
+"notify-recipient-uri" Subscription attribute, i.e. the part after the
+"mailto:".
+
+
+6.1.7 'Content-type' header
+
+
+Syntax: "Content-Type" ":" type "/" subtype *(";"parameter)
+
+ See [RFC 1521] for the syntactic terms (e.g. 'type').
+
+This header specifies the format of the message body.
+
+The Printer MUST include the "Content-Type" header.
+
+The "notify-mailto-text-only" attribute determines the 'type' and
+'subtype' values. The possible values are "text/plain" and "multipart"
+values.
+
+
+6.2 Message Body
+
+
+The message body MUST contain Human Consumable content as plain text. It
+MAY also contain other types of implementation dependent content.
+
+
+For plain text, the Content-Type of Human Consumable content MUST be
+'text/plain'. For implementation dependent content, the Content-Type of
+Human Consumable content MUST be 'multipart'. The Content-Type of one
+body part MUST be 'text/plain' and the Content-Types of the other body
+parts are implementation dependent. See section 6.3 for a description of
+plain text content.
+
+
+The following table shows the Content-Type of the message body for the
+"notify-mailto-text-only" attribute:
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Expires: March 1, 2001 [page 16]
+
+
+PWG-DRAFT IPP: The 'mailto:' Delivery Method August 30, 2000
+
+
+
+
+ "notify- Content-Type Message Body
+ mailto-text- of Message
+ only" Body
+ attribute
+
+
+ false 'text/plain' Human Consumable
+
+ true 'text/plain' Human Consumable plain
+ or* text
+
+ 'multipart' Human Consumable where
+ one body part is plain
+ text
+
+
+
+ * The Content-Type depends on the implementation. A Printer MAY send
+ 'text/plain' only or it MAY send several body parts of various
+ Content-Types within a message body whose Content-Type is
+ 'multipart'.
+
+
+6.3 Plain Text Content
+
+
+When a Printer sends a plain text message, it MUST localize the text
+using the values of the "notify-charset" and "notify-natural-language"
+Subscription Object attributes.
+
+
+Section 9.2 in [ipp-ntfy] specifies the information that a Delivery
+Method MUST specify and a Printer SHOULD send.
+
+
+A Printer SHOULD send the following localized information in the message
+body. The specific wording of this information and its layout are
+implementation dependent.
+
+ a)the Printer name (see Table 3)
+ b)omitted (see below).
+ c)for Printer Events only:
+ i) the Event (see Table 4) and/or Printer state information
+ (see Table 7)
+ d)for Job Events only:
+ i) the job identity (see Table 5)
+ ii) the Event (see Table 4) and/or Job state information (see
+ Table 6)
+
+
+Herriot, et al. Expires: March 1, 2001 [page 17]
+
+
+PWG-DRAFT IPP: The 'mailto:' Delivery Method August 30, 2000
+
+
+Item b) in the above list is omitted because the Printer sends the time
+of the Event as an email header (see section 6.1.1 on the 'Date'
+header).
+
+
+The subsections of this section specify the attributes that a Printer
+MUST use to obtain this information.
+
+
+The Printer MAY send additional information, depending on
+implementation.
+
+
+Notification Recipients MUST NOT expect to be able to parse the message.
+
+
+The next three sections define the attributes in Event Notification
+Contents that are:
+
+
+ a)for all Events
+
+
+ b)for Job Events only
+
+
+ c)for Printer Events only
+
+
+6.3.1Event Notification Content Common to All Events
+
+
+The Printer MUST send the following information.
+
+
+There is a separate table for each piece of information. Each row in the
+table represents a source value for the information and the values are
+listed in order of preference, with the first one being the preferred
+one. An implementation SHOULD use the source value from the earliest row
+in each table. It MAY use the source value from another row instead, or
+it MAY combine the source values from several rows. An implementation is
+free to determine the best way to present this information.
+
+
+The tables in this section and following sections contain the following
+columns for each piece of information:
+
+
+ a)Source of Value: the name of the attribute that supplies the
+ value for the Event Notification
+
+
+Herriot, et al. Expires: March 1, 2001 [page 18]
+
+
+PWG-DRAFT IPP: The 'mailto:' Delivery Method August 30, 2000
+
+
+ b)Sends:
+
+ MAY: this is the only value used in the tables. It means that
+ the Printer OPTIONALLY sends this value. However, the Printer
+ SHOULD use at least one value from each table.
+
+
+ c)Source Object: the object from which the source value comes.
+
+
+Table 3 lists the source of the information for the Printer Name. The
+"printer-name" is more user-friendly unless the Notification Recipient
+is in a place where the Printer name is not meaningful. For example, an
+implementation could have the intelligence to send the value of the
+"printer-name" attribute to a Notification Recipient that can access the
+Printer via value of the "printer-name" attribute and otherwise send the
+value of the "notify-printer-uri" attribute.
+
+
+ Table 3 - Printer Name in Event Notification Content
+
+
+
+Source Value Sends Source Object
+
+
+printer-name (name(127)) MAY Printer
+
+notify-printer-uri (uri) MAY Subscription
+
+
+
+
+
+Table 4 lists the source of the information for the Event name. A
+Printer MAY combine this information with state information described
+for Jobs in Table 6 or for Printers in Table 7.
+
+
+ Table 4 - Event Name in Event Notification Content
+
+
+
+Source Value Sends Source Object
+
+
+notify-subscribed-event (type2 keyword) MAY Subscription
+
+
+
+
+
+Herriot, et al. Expires: March 1, 2001 [page 19]
+
+
+PWG-DRAFT IPP: The 'mailto:' Delivery Method August 30, 2000
+
+
+6.3.2Additional Event Notification Content for Job Events
+
+
+This section lists the source of the additional information that a
+Printer MUST send for Job Events.
+
+
+Table 5 lists the source of the information for the job name. The "job-
+name" is likely more meaningful to a user than "job-id".
+
+
+ Table 5 - Job Name in Event Notification Content
+
+
+
+Source Value Sends Source Object
+
+
+job-name (name(MAX)) MAY Job
+
+job-id (integer(1:MAX)) MAY Job
+
+
+
+
+
+Table 6 lists the source of the information for the job-state. If a
+Printer supports the "job-state-message" and "job-detailed-state-
+message" attributes, it SHOULD use those attributes for the job state
+information, otherwise, it should fabricate such information from the
+"job-state" and "job-state-reasons". For some Events, a Printer MAY
+combine this information with Event information.
+
+
+ Table 6 - Job State in Event Notification Content
+
+
+
+Source Value Sends Source
+ Object
+
+
+job-state-message (text(MAX)) MAY Job
+
+job-detailed-status-messages (1setOf MAY Job
+text(MAX))
+
+job-state (type1 enum) MAY Job
+
+
+
+
+Herriot, et al. Expires: March 1, 2001 [page 20]
+
+
+PWG-DRAFT IPP: The 'mailto:' Delivery Method August 30, 2000
+
+
+
+
+Source Value Sends Source
+ Object
+
+
+job-state-reasons (1setOf type2 keyword) MAY Job
+
+
+6.3.3Additional Event Notification Content for Printer Events
+
+
+This section lists the source of the additional information that a
+Printer MUST send for Printer Events.
+
+
+Table 7 lists the source of the information for the printer-state. If a
+Printer supports the "printer-state-message", it SHOULD use that
+attribute for the job state information, otherwise it SHOULD fabricate
+such information from the "printer-state" and "printer-state-reasons".
+For some Events, a Printer MAY combine this information with Event
+information.
+
+
+ Table 7 - Printer State in Event Notification Content
+
+
+
+Source Value Sends Source Object
+
+
+printer-state-message (text(MAX)) MAY Printer
+
+printer-state (type1 enum) MAY Printer
+
+printer-state-reasons (1setOf type2 MAY Printer
+keyword)
+
+printer-is-accepting-jobs (boolean) MAY Printer
+
+
+6.4 Examples
+
+
+This section contains three examples. One is a Job Event and the other
+two are Printer Events, the latter in Danish.
+
+
+A Printer implementation NEED NOT generate Event Notification content
+that is identical or even similar to these examples. In fact it would be
+
+
+Herriot, et al. Expires: March 1, 2001 [page 21]
+
+
+PWG-DRAFT IPP: The 'mailto:' Delivery Method August 30, 2000
+
+
+unfortunate if every implementation copied these example as is. These
+examples merely show some possibilities and are not necessarily the best
+way to convey information about an Event.
+
+
+6.4.1Job Event Example
+
+
+This section contains an example of an Event Notification of a Job
+Event.
+
+
+A Subscribing Client Mike Jones (who works for xyz Corp.) performs a
+Subscription Creation Operation as part of the Print-Job operation on
+Printer "ipp://tiger@abc.com". Mike Jones specifies that the "job-name"
+is "financials". Mike is printing the Job for Bill Smith at abc Corp.
+The Subscription Object then has the following attributes:
+
+
+
+ Attribute Name Attribute Value
+
+
+ notify-recipient-uri mailto:bsmith@abc.com
+
+ notify-events job-completed
+
+ notify-user-data mjones@xyz.com
+
+ notify-mailto-text-only true
+
+ notify-charset us-ascii
+
+ notify-natural-language en-us
+
+ notify-subscription-id 35692
+
+ notify-sequence-number 0
+
+ notify-printer-up-time 34593
+
+ notify-printer-uri ipp://tiger@abc.com
+
+ notify-job-id 345
+
+ notify-subscriber-user- mjones
+ name
+
+
+
+
+
+Herriot, et al. Expires: March 1, 2001 [page 22]
+
+
+PWG-DRAFT IPP: The 'mailto:' Delivery Method August 30, 2000
+
+
+When the Job completes, the Printer generates and sends the following
+email message:
+
+ Date: 17 Jul 00 1632 PDT
+ From: tiger <printAdmin@abc.com>
+ Subject: print job: 'financials' completed
+ Sender: mjones@xyz.com
+ Reply-to: mjones@xyz.com
+ To: bsmith@abc.com
+ Content-type: text/plain
+
+ printer: tiger
+ job: financials
+ job-state: completed
+
+The reader should note that the phrases are not identical to IPP
+keywords. They have been localized to English.
+
+
+6.4.2Printer Event Example
+
+
+This section contains an example of an Event Notification of a Printer
+Event.
+
+
+A Subscribing Client Peter Williams, a Printer admin, performs a Create-
+Printer-Subscriptions operation on Printer "ipp://tiger@abc.com". The
+Subscription Object then has the following attributes:
+
+
+
+ Attribute Name Attribute Value
+
+
+ notify-recipient-uri mailto:pwilliams@abc.com
+
+ notify-events printer-state-changed
+
+ notify-mailto-text-only true
+
+ notify-charset us-ascii
+
+ notify-natural-language en-us
+
+ notify-subscription-id 4623
+
+ notify-sequence-number 0
+
+
+
+
+Herriot, et al. Expires: March 1, 2001 [page 23]
+
+
+PWG-DRAFT IPP: The 'mailto:' Delivery Method August 30, 2000
+
+
+
+
+ Attribute Name Attribute Value
+
+
+ notify-printer-uptime 23002
+
+ notify-printer-uri ipp://tiger@abc.com
+
+ notify-lease-expiration- 0
+ time
+
+ notify-subscriber-user- pwilliams
+ name
+
+
+When the Printer jams, the Printer generates and sends the following
+email message:
+
+ Date: 29 Aug 00 0832 PDT
+ From: tiger <printAdmin@abc.com>
+ Subject: printer: 'tiger' has stopped
+ To: pwilliams@abc.com
+ Content-type: text/plain
+
+ Printer tiger has stopped with a paper jam.
+
+
+The reader should note that the phrases are not identical to IPP
+keywords. They have been localized to English.
+
+
+6.4.3Printer Event Example (localized to Danish)
+
+
+This section contains an example of an Event Notification of a Printer
+Event localized to Danish.
+
+
+A Subscribing Client Per Jensen, a Printer admin, performs a a Create-
+Printer-Subscriptions operation on Printer "ipp://tiger@def.dk". The
+Subscription Object then has the following attributes:
+
+
+
+ Attribute Name Attribute Value
+
+
+ notify-recipient-uri mailto:pjensen@def.dk
+
+
+
+Herriot, et al. Expires: March 1, 2001 [page 24]
+
+
+PWG-DRAFT IPP: The 'mailto:' Delivery Method August 30, 2000
+
+
+
+
+ Attribute Name Attribute Value
+
+
+ notify-events printer-state-changed
+
+ notify-mailto-text-only true
+
+ notify-charset utf-8
+
+ notify-natural-language da
+
+ notify-subscription-id 50225
+
+ notify-sequence-number 0
+
+ notify-printer-uptime 53217
+
+ notify-printer-uri ipp://tiger@def.dk
+
+ notify-lease-expiration- 0
+ time
+
+ notify-subscriber-user- pjensen
+ name
+
+
+When the Printer jams, the Printer generates and sends the following
+email message:
+
+ Date: 29 Jan 00 0832 CET
+ From: tiger <admin@def.dk>
+ Subject: Printeren 'tiger' er standset
+ To: pjensen@def.dk
+ Content-type: text/plain;charset=utf-8
+
+ Printerens navn er 'tiger'.
+ Printeren er standset.
+ Aarsagen er papir stop.
+
+7 Conformance Requirements
+
+The 'mailto' Delivery Method is RECOMMENDED for a Printer to support.
+
+
+If the Printer supports the 'mailto' Delivery Method, the Printer MUST:
+
+
+1.meet the conformance requirements defined in [ipp-ntfy].
+
+
+Herriot, et al. Expires: March 1, 2001 [page 25]
+
+
+PWG-DRAFT IPP: The 'mailto:' Delivery Method August 30, 2000
+
+
+2.support the "notify-mailto-text-only " Subscription Object attribute
+ defined in section 5.1.1.
+
+
+3.support the syntax for the "notify-recipient-uri" Subscription Object
+ attribute defined in section 5.2.1
+
+
+4.support the use for the "notify-user-data" Subscription Object
+ attribute defined in section 5.2.2
+
+
+5.support SMTP for sending Event Notifications.
+
+
+6.support the 'text/plain' Content-Type for the message body.
+
+
+7.support sending Event Notification via email with the content
+ specified in section 5.2.
+
+
+8 IANA Considerations
+
+Because the 'mailto' URL scheme is already defined in a standards track
+document [RFC 2368] and registered with IANA, this document does not
+require anything further of IANA.
+
+
+9 Internationalization Considerations
+
+This Delivery Method presents no internationalization considerations
+beyond those covered in the [ipp-ntfy] document, and sections 6.1.3 and
+6.2 of this document.
+
+
+The Notification Recipient is expected to present the email as received
+because the Printer does all necessary localization to the Event
+Notification contents.
+
+
+10 Security Considerations
+
+The biggest security concern is that a Subscribing Client will cause
+unsolicited Event Notifications to be sent to third parties, potentially
+creating denial-of-service problems (i.e., spam). The problem is even
+worse if the third parties are distribution lists.
+
+
+
+
+
+Herriot, et al. Expires: March 1, 2001 [page 26]
+
+
+PWG-DRAFT IPP: The 'mailto:' Delivery Method August 30, 2000
+
+
+There exist scenarios where third party notification is required (see
+Scenario #2 and #3 in [ipp-not-req]). The fully secure solution would
+require active agreement of all persons before they can become
+Notification Recipients. However, requirement #9 in [ipp-req] ("There
+is no requirement for IPP Printer receiving the print request to
+validate the identity of an event recipient") argues against this. To
+minimize the risk, a Printer could disallow third party Notification
+Recipients (a traditional facsimile model).
+
+
+The Delivery Method recommends that the Subscribing Client supply his or
+her email address as the value of the "notify-user-data" attribute in
+the Subscription Creation Operation when the Notification Recipient is a
+third party. To reduce the chance of spamming or identify the spammer, a
+Printer could disallow third party Notification Recipients if the
+Subscribing Client doesn't supply the "notify-user-data" attribute with
+a valid email address.
+
+
+Some firewall administrators prevent mail attachments from being
+accepted into their organizations because of the problem of the
+attachments containing computer viruses. The 'mailto' Delivery Method
+allows the Subscribing Client to request that the Content-Type of a
+message body be 'text/plain'.
+
+
+11 References
+ [ipp-iig]
+ Hastings, T., Manros, C., Kugler, K, Holst H., Zehler, P.,
+ "Internet Printing Protocol/1.1: draft-ietf-ipp-implementers-
+ guide-v11-01.txt, work in progress, May 9, 2000
+
+[ipp-mod]
+ R. deBry, T. Hastings, R. Herriot, S. Isaacson, P. Powell, "Internet
+Printing Protocol/1.0: Model and Semantics", <draft-ietf-ipp-model-v11-
+07.txt>, May 22, 2000.[ipp-ntfy]
+ Herriot, R., Hastings, T., Isaacson, S., Martin, J., deBry, R.,
+ Shepherd, M., Bergman, R., "Internet Printing Protocol/1.1: IPP
+ Event Notification Specification", <draft-ietf-ipp-not-spec-
+ 04.txt>, August 30, 2000.
+
+[ipp-pro]
+ Herriot, R., Butler, S., Moore, P., Tuner, R., "Internet Printing
+ Protocol/1.1: Encoding and Transport", draft-ietf-ipp-protocol-v11-
+ 06.txt, May 20, 2000.
+
+[RFC821]
+ Jonathan B. Postel, "Simple Mail Transfer Protocol", RFC 821,
+ August, 1982.
+
+
+
+Herriot, et al. Expires: March 1, 2001 [page 27]
+
+
+PWG-DRAFT IPP: The 'mailto:' Delivery Method August 30, 2000
+
+
+[RFC822]
+ David H. Crocker, "Standard For The Format Of ARPA Internet Text
+ Messages", RFC 822, August 13, 1982.
+
+[RFC1341]
+ N. Borenstein, N. Freed, "MIME (Multipurpose Internet Mail
+ Extensions): Mechanisms for Specifying and Describing the Format of
+ Internet Message Bodies", RFC 1341, June, 1992.
+
+
+[RFC1521]
+
+ N. Borenstein, N. Freed, "MIME (Multipurpose Internet Mail
+ Extensions) Part One: Mechanisms for Specifying and Describing the
+ Format of Internet Message Bodies", RFC 1521, September 1993.
+
+[RFC1891]
+ K. Moore, "SMTP Service Extension for Delivery Status
+ Notifications", RFC 1891, January 1996
+
+[RFC2026]
+ S. Bradner, "The Internet Standards Process -- Revision 3", RFC
+ 2026, October 1996.
+
+[RFC2046]
+ R. Fielding, J. Gettys, J. Mogul, H. Frystyk, L. Masinter, P.
+ Leach, T. Berners-Lee, "Hypertext Transfer Protocol - HTTP/1.1",
+ RFC 2616, June 1999.
+
+[RFC2368]
+ P. Hoffman, L. Masinter, J. Zawinski, "The mailto URL scheme", RFC
+ 2616, July 1998.
+
+ [RFC2616]
+ R. Fielding, J. Gettys, J. Mogul, H. Frystyk, L. Masinter, P.
+ Leach, T. Berners-Lee, "Hypertext Transfer Protocol - HTTP/1.1",
+ RFC 2616, June 1999.
+
+ [RFC2633]
+ B. Ramsdell, "S/MIME Version 3 Message Specification", RFC 2633,
+ June 1999.
+
+
+12 Author's Addresses
+
+ Robert Herriot
+ Xerox Corporation
+ 3400 Hillview Ave., Bldg #1
+ Palo Alto, CA 94304
+
+
+
+Herriot, et al. Expires: March 1, 2001 [page 28]
+
+
+PWG-DRAFT IPP: The 'mailto:' Delivery Method August 30, 2000
+
+
+ Phone: 650-813-7696
+ Fax: 650-813-6860
+ Email: robert.herriot@pahv.xerox.com
+
+ Henrik Holst
+ i-data international a/s
+ Vadstrupvej 35-43
+ 2880 Bagsvaerd, Denmark
+
+ Phone: +45 4436-6000
+ Fax: +45 4436-6111
+ e-mail: hh@i-data.com
+
+ Tom Hastings
+ Xerox Corporation
+ 737 Hawaii St. ESAE 231
+ El Segundo, CA 90245
+
+ Phone: 310-333-6413
+ Fax: 310-333-5514
+ e-mail: hastings@cp10.es.xerox.com
+
+
+ Carl-Uno Manros
+ Xerox Corporation
+ 737 Hawaii St. ESAE 231
+ El Segundo, CA 90245
+
+ Phone: 310-333-8273
+ Fax: 310-333-5514
+ e-mail: manros@cp10.es.xerox.com
+
+
+13 Full Copyright Statement
+Copyright (C) The Internet Society (2000). All Rights Reserved.
+
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it or
+assist in its implementation may be prepared, copied, published and
+distributed, in whole or in part, without restriction of any kind,
+provided that the above copyright notice and this paragraph are included
+on all such copies and derivative works. However, this document itself
+may not be modified in any way, such as by removing the copyright notice
+or references to the Internet Society or other Internet organizations,
+except as needed for the purpose of developing Internet standards in
+which case the procedures for copyrights defined in the Internet
+Standards process must be followed, or as required to translate it into
+languages other than English.
+
+
+
+
+Herriot, et al. Expires: March 1, 2001 [page 29]
+
+
+PWG-DRAFT IPP: The 'mailto:' Delivery Method August 30, 2000
+
+
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+
+This document and the information contained herein is provided on an "AS
+IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK
+FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT
+LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT
+INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR
+FITNESS FOR A PARTICULAR PURPOSE.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Expires: March 1, 2001 [page 30]
diff --git a/standards/draft-ietf-ipp-notify-poll-02.txt b/standards/draft-ietf-ipp-notify-poll-02.txt
new file mode 100644
index 000000000..b71529e91
--- /dev/null
+++ b/standards/draft-ietf-ipp-notify-poll-02.txt
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
+<HTML><HEAD>
+<TITLE>404 Not Found</TITLE>
+</HEAD><BODY>
+<H1>Not Found</H1>
+The requested URL /internet-drafts/draft-ietf-ipp-notify-poll-02.txt was not found on this server.<P>
+<HR>
+<ADDRESS>Apache/1.3.11 Server at www2.ietf.org Port 80</ADDRESS>
+</BODY></HTML>
diff --git a/standards/draft-ietf-ipp-ops-admin-req-00.txt b/standards/draft-ietf-ipp-ops-admin-req-00.txt
new file mode 100644
index 000000000..c5a6ccfe4
--- /dev/null
+++ b/standards/draft-ietf-ipp-ops-admin-req-00.txt
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
+<HTML><HEAD>
+<TITLE>404 Not Found</TITLE>
+</HEAD><BODY>
+<H1>Not Found</H1>
+The requested URL /internet-drafts/draft-ietf-ipp-ops-admin-req-00.txt was not found on this server.<P>
+<HR>
+<ADDRESS>Apache/1.3.11 Server at www2.ietf.org Port 80</ADDRESS>
+</BODY></HTML>
diff --git a/standards/draft-ietf-ipp-ops-set2-02.txt b/standards/draft-ietf-ipp-ops-set2-02.txt
new file mode 100644
index 000000000..ad575525b
--- /dev/null
+++ b/standards/draft-ietf-ipp-ops-set2-02.txt
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
+<HTML><HEAD>
+<TITLE>404 Not Found</TITLE>
+</HEAD><BODY>
+<H1>Not Found</H1>
+The requested URL /internet-drafts/draft-ietf-ipp-ops-set2-02.txt was not found on this server.<P>
+<HR>
+<ADDRESS>Apache/1.3.11 Server at www2.ietf.org Port 80</ADDRESS>
+</BODY></HTML>
diff --git a/standards/draft-ietf-ipp-url-scheme-02.txt b/standards/draft-ietf-ipp-url-scheme-02.txt
new file mode 100644
index 000000000..2b5378c1f
--- /dev/null
+++ b/standards/draft-ietf-ipp-url-scheme-02.txt
@@ -0,0 +1,899 @@
+
+
+Internet Printing Protocol Working Group Bob Herriot
+INTERNET DRAFT Xerox Corporation
+Expires 13 August 2001 Ira McDonald
+ High North Inc
+[Target Category: Standards Track] 13 February 2001
+
+ Internet Printing Protocol (IPP):
+ IPP URL Scheme
+ <draft-ietf-ipp-url-scheme-02.txt>
+
+ Copyright (C) The Internet Society (2001). All Rights Reserved.
+
+
+Status of this Memo
+
+ This document is an Internet-Draft and is in full conformance with
+ all provisions of Section 10 of RFC2026. Internet-Drafts are working
+ documents of the Internet Engineering Task Force (IETF), its areas,
+ and its working groups. Note that other groups may also distribute
+ working documents as Internet-Drafts.
+
+ Internet-Drafts are draft documents valid for a maximum of six months
+ and may be updated, replaced, or obsoleted by other documents at any
+ time. It is inappropriate to use Internet-Drafts as reference
+ material or to cite them other than as "work in progress."
+
+ The list of current Internet-Drafts can be accessed at
+ http://www.ietf.org/ietf/1id-abstracts.txt
+
+ The list of Internet-Draft Shadow Directories can be accessed at
+ http://www.ietf.org/shadow.html.
+
+
+Abstract
+
+ This document is a product of the Internet Printing Protocol Working
+ Group of the Internet Engineering Task Force (IETF). Comments should
+ be submitted to the ipp@pwg.org mailing list.
+
+ This document is intended for use in registering the "ipp" URL scheme
+ with IANA and fully conforms to the requirements in [RFC-2717]. This
+ document defines the "ipp" URL (Uniform Resource Locator) scheme for
+ specifying the location of an IPP Printer, IPP Job, or other IPP
+ object (defined in some future version of IPP) which implements the
+ IPP/1.1 Model [RFC-2911] and the IPP/1.1 Protocol encoding over HTTP
+ [RFC-2910] or any later version of IPP. The intended usage of the
+ "ipp" URL scheme is COMMON.
+
+ The IPP URL scheme defined in this document is based on the ABNF for
+ the HTTP URL scheme defined in HTTP/1.1 [RFC-2616], which is derived
+ from the URI Generic Syntax [RFC-2396] and further updated by
+ [RFC-2732] and [RFC-2373] (for IPv6 addresses in URLs). An IPP URL
+ is transformed into an HTTP URL according to the rules specified in
+ section 5 of the IPP/1.1 Protocol [RFC-2910].
+
+
+Herriot, McDonald Expires 13 August 2001 [Page 1]
+
+Internet Draft IPP URL Scheme 13 February 2001
+
+
+ Table of Contents
+
+1. Introduction ............................................... 3
+2. Terminology ................................................ 4
+ 2.1. Conformance Terminology ................................ 4
+ 2.2. Model Terminology ...................................... 4
+3. IPP Model for Printers and Jobs ............................ 4
+4. IPP URL Scheme ............................................. 6
+ 4.1. IPP URL Scheme Applicability and Intended Usage ........ 6
+ 4.2. IPP URL Scheme Associated IPP Port ..................... 6
+ 4.3. IPP URL Scheme Associated MIME Type .................... 6
+ 4.4. IPP URL Scheme Character Encoding ...................... 6
+ 4.5. IPP URL Scheme Syntax in ABNF .......................... 7
+ 4.5.1. IPP URL Examples ................................... 8
+ 4.5.2. IPP URL Comparisons ................................ 9
+5. Conformance Requirements ................................... 10
+ 5.1. Conformance Requirements for IPP Clients ............... 10
+ 5.2. Conformance Requirements for IPP Printers .............. 10
+6. IANA Considerations ........................................ 11
+7. Internationalization Considerations ........................ 11
+8. Security Considerations .................................... 11
+9. References ................................................. 12
+10. Acknowledgments ........................................... 13
+11. Authors' Addresses ........................................ 14
+12. Appendix X - Change History ............................... 14
+13. Full Copyright Statement .................................. 15
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, McDonald Expires 13 August 2001 [Page 2]
+
+Internet Draft IPP URL Scheme 13 February 2001
+
+
+
+1. Introduction
+
+ See section 1 'Introduction' in [RFC-2911] for a full description of
+ the IPP document set and overview information about IPP.
+
+ The open issues in this document each begin 'ISSUE_n:'.
+
+ This document is a product of the Internet Printing Protocol Working
+ Group of the Internet Engineering Task Force (IETF). Comments should
+ be submitted to the ipp@pwg.org mailing list.
+
+ This document is intended for use in registering the "ipp" URL scheme
+ with IANA and fully conforms to the requirements in [RFC-2717]. This
+ document defines the "ipp" URL (Uniform Resource Locator) scheme for
+ specifying the location of an IPP Printer, IPP Job, or other IPP
+ object (defined in some future version of IPP) which implements the
+ IPP/1.1 Model [RFC-2911] and the IPP/1.1 Protocol encoding over HTTP
+ [RFC-2910] or any later version of IPP. The intended usage of the
+ "ipp" URL scheme is COMMON.
+
+ This document defines:
+ - IPP URL scheme applicability and intended usage;
+ - IPP URL scheme associated port (i.e., well-known port 631);
+ - IPP URL scheme associated MIME type (i.e., "application/ipp");
+ - IPP URL scheme syntax in ABNF [RFC-2234];
+ - IPP URL scheme character encoding;
+ - IPP URL scheme IANA, internationalization, and security
+ considerations.
+
+ This document is laid out as follows:
+ - Section 2 is the terminology used throughout the document.
+
+ - Section 3 provides references to the IPP Printer and IPP Job object
+ model.
+
+ - Section 4 specifies IPP URL scheme.
+
+ - Section 5 specifies the conformance requirements for IPP Clients
+ and IPP Printers that claim conformance to this document.
+
+ - Section 6, 7, and 8 specify IANA, internationalization, and
+ security considerations.
+
+ - Sections 9, 10, 11, 12, and 13 list references, acknowledgements,
+ authors' addresses, change history, and full IETF copyright
+ statement.
+
+
+
+
+Herriot, McDonald Expires 13 August 2001 [Page 3]
+
+Internet Draft IPP URL Scheme 13 February 2001
+
+
+
+2. Terminology
+
+ This specification document uses the terminology defined in this
+ section.
+
+
+ 2.1. Conformance Terminology
+
+ The uppercase terms "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL
+ NOT" "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in
+ this document are to be interpreted as described in [RFC-2119].
+ These terms are used to specify conformance requirements for all
+ implementations of this specification.
+
+
+ 2.2. Model Terminology
+
+ See section 12.2 'Model Terminology' in [RFC-2911].
+
+
+
+3. IPP Model for Printers and Jobs
+
+ See section 2 'IPP Objects', section 2.1 'Printer Object', and
+ section 2.2 'Job Object' in [RFC-2911] for a full description of the
+ IPP object model and terminology.
+
+ In this document, "IPP Client" means the software (on some hardware
+ platform) that submits, monitors, and/or manages print jobs via
+ IPP/1.1 [RFC-2910] [RFC-2911], or any later version of IPP to a
+ spooler, gateway, or actual printing device.
+
+ In this document, "IPP Printer object" means the software (on some
+ hardware platform) that receives print jobs and/or printer/job
+ operations via IPP/1.1 [RFC-2910] [RFC-2911], or any later version of
+ IPP from an "IPP Client".
+
+ In this document, "IPP Printer" is a synonym for "IPP Printer
+ object".
+
+ In this document, "IPP Job object" means the set of attributes and
+ documents for one print job on an "IPP Printer".
+
+ In this document, "IPP Job" is a synonym for "IPP Job object".
+
+ In this document, "IPP URL" means a URL with the "ipp" scheme.
+
+ Note: In this document, "IPP URL" is a synonym for "ipp_URL" (in
+ section 4 'IPP URL Scheme' of this document) and "ipp-URL" (in
+
+Herriot, McDonald Expires 13 August 2001 [Page 4]
+
+Internet Draft IPP URL Scheme 13 February 2001
+
+ section 5 'IPP URL Scheme' of [RFC-2910]).
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, McDonald Expires 13 August 2001 [Page 5]
+
+Internet Draft IPP URL Scheme 13 February 2001
+
+
+
+4. IPP URL Scheme
+
+
+
+ 4.1. IPP URL Scheme Applicability and Intended Usage
+
+ This document is intended for use in registering the "ipp" URL scheme
+ with IANA and fully conforms to the requirements in [RFC-2717]. This
+ document defines the "ipp" URL (Uniform Resource Locator) scheme for
+ specifying the location of an IPP Printer, IPP Job, or other IPP
+ object (defined in some future version of IPP) which implements the
+ IPP/1.1 Model [RFC-2911] and the IPP/1.1 Protocol encoding over HTTP
+ [RFC-2910] or any later version of IPP. The intended usage of the
+ "ipp" URL scheme is COMMON.
+
+
+
+ 4.2. IPP URL Scheme Associated IPP Port
+
+ All IPP URLs which do NOT explicitly specify a port MUST be used over
+ IANA-assigned well-known port 631 for the IPP protocol described in
+ [RFC-2910].
+
+ See: IANA Port Numbers Registry [IANA-PORTREG]. registration with
+ IANA.
+
+
+
+ 4.3. IPP URL Scheme Associated MIME Type
+
+ All IPP protocol operations (requests and responses) MUST be conveyed
+ in an "application/ipp" MIME media type as registered in
+ [IANA-MIMEREG]. IPP URLs MUST refer to IPP Printers which support
+ this "application/ipp" MIME media type.
+
+ See: IANA MIME Media Types Registry [IANA-MIMEREG].
+
+
+
+ 4.4. IPP URL Scheme Character Encoding
+
+ The IPP URL scheme defined in this document is based on the ABNF for
+ the HTTP URL scheme defined in HTTP/1.1 [RFC-2616], which is derived
+ from the URI Generic Syntax [RFC-2396] and further updated by
+ [RFC-2732] and [RFC-2373] (for IPv6 addresses in URLs). The IPP URL
+ scheme is case-insensitive in the host name or host address part;
+ however the path part is case-sensitive, as in [RFC-2396].
+ Codepoints outside [US-ASCII] MUST be hex escaped by the mechanism
+ specified in [RFC-2396].
+
+Herriot, McDonald Expires 13 August 2001 [Page 6]
+
+Internet Draft IPP URL Scheme 13 February 2001
+
+
+
+
+ 4.5. IPP URL Scheme Syntax in ABNF
+
+ Note: In this document, "IPP URL" is a synonym for "ipp_URL" (in
+ section 4 'IPP URL Scheme' of this document) and "ipp-URL" (in
+ section 5 'IPP URL Scheme' of [RFC-2910]).
+
+ This document is intended for use in registering the "ipp" URL scheme
+ with IANA and fully conforms to the requirements in [RFC-2717]. This
+ document defines the "ipp" URL (Uniform Resource Locator) scheme for
+ specifying the location of an IPP Printer, IPP Job, or other IPP
+ object (defined in some future version of IPP) which implements the
+ IPP/1.1 Model [RFC-2911] and the IPP/1.1 Protocol encoding over HTTP
+ [RFC-2910] or any later version of IPP. The intended usage of the
+ "ipp" URL scheme is COMMON.
+
+ The IPP protocol places a limit of 1023 octets (NOT characters) on
+ the length of a URI (see section 4.1.5 'uri' in [RFC-2911]). An IPP
+ Printer MUST return 'client-error-request-value-too-long' (see
+ section 13.1.4.10 in [RFC-2911]) when a URI received in a request
+ (e.g., in the "printer-uri" attribute) is too long.
+
+ Note: IPP Printers ought to be cautious about depending on URI
+ lengths above 255 bytes, because some older client or proxy
+ implementations might not properly support these lengths.
+
+ IPP URLs MUST be represented in absolute form. Absolute URLs always
+ begin with a scheme name followed by a colon. For definitive
+ information on URL syntax and semantics, see "Uniform Resource
+ Identifiers (URI): Generic Syntax and Semantics" [RFC-2396]. This
+ specification adopts the definitions of "URI-reference",
+ "absoluteURI", "relativeURI", "port", "host","abs_path", "rel_path",
+ and "authority" from [RFC-2396], as updated by [RFC-2732] and
+ [RFC-2373] (for IPv6 addresses in URLs).
+
+ The IPP URL scheme syntax in ABNF is as follows:
+
+ ipp_URL = "ipp:" "//" host [ ":" port ] [ abs_path [ "?" query ]]
+
+ If the port is empty or not given, port 631 is assumed. The
+ semantics are that the identified resource (see section 5.1.2 of
+ [RFC-2616]) is located at the IPP Printer or IPP Job listening for
+ HTTP connections on that port of that host, and the Request-URI for
+ the identified resource is 'abs_path'.
+
+ Note: The use of IP addresses in URLs SHOULD be avoided whenever
+ possible (see [RFC-1900]).
+
+ If the 'abs_path' is not present in the URL, it MUST be given as "/"
+
+Herriot, McDonald Expires 13 August 2001 [Page 7]
+
+Internet Draft IPP URL Scheme 13 February 2001
+
+ when used as a Request-URI for a resource (see section 5.1.2 of
+ [RFC-2616]). If a proxy receives a host name which is not a fully
+ qualified domain name, it MAY add its domain to the host name it
+ received. If a proxy receives a fully qualified domain name, the
+ proxy MUST NOT change the host name.
+
+
+
+ 4.5.1. IPP URL Examples
+
+ The following are examples of valid IPP URLs for IPP Printers:
+
+ ipp://abc.com
+ ipp://abc.com/printer
+ ipp://abc.com/tiger
+ ipp://abc.com/printers/tiger
+ ipp://abc.com/printers/fox
+ ipp://abc.com/printers/tiger/bob
+ ipp://abc.com/printers/tiger/ira
+ ipp://printer.abc.com
+ ipp://printers.abc.com/tiger
+ ipp://printers.abc.com/tiger/bob
+ ipp://printers.abc.com/tiger/ira
+
+ Each of the above URLs are legitimate URLs for IPP Printers and each
+ references a logically different IPP Printer, even though some of the
+ IPP Printers may share the same hardware. The last part of the path
+ 'bob' or 'ira' may represent two different hardware devices where
+ 'tiger' represents some grouping of IPP Printers (e.g., a
+ load-balancing spooler) or the two names may represent separate human
+ recipients ('bob' and 'ira') on the same hardware device (e.g., a
+ printer supporting two job queues). In either case both 'bob' and
+ 'ira' behave as different IPP Printers.
+
+ The following are examples of IPP URLs with (optional) ports and
+ paths:
+
+ ipp://abc.com
+ ipp://abc.com/~smith/printer
+ ipp://abc.com:631/~smith/printer
+
+ The first and second IPP URLs above MUST be resolved to port 631
+ (IANA assigned well-known port for IPP). The second and third IPP
+ URLs above are equivalent (see section 4.5.2 below).
+
+ Note: The use of IP addresses in URLs SHOULD be avoided whenever
+ possible (see [RFC-1900]).
+
+ The following literal IPv4 addresses:
+
+
+
+Herriot, McDonald Expires 13 August 2001 [Page 8]
+
+Internet Draft IPP URL Scheme 13 February 2001
+
+ 192.9.5.5 ; IPv4 address in IPv4 style
+ 186.7.8.9 ; IPv4 address in IPv4 style
+
+ are represented in the following example IPP URLs:
+
+ ipp://192.9.5.5/prt1
+ ipp://186.7.8.9/printers/tiger/bob
+
+ The following literal IPv6 addresses (conformant to [RFC-2373]):
+
+ ::192.9.5.5 ; IPv4 address in IPv6 style
+ ::FFFF:129.144.52.38 ; IPv4 address in IPv6 style
+ 2010:836B:4179::836B:4179 ; IPv6 address per RFC 2373
+
+ are represented in the following example IPP URLs:
+
+ ipp://[::192.9.5.5]/prt1
+ ipp://[::FFFF:129.144.52.38]:631/printers/tiger
+ ipp://[2010:836B:4179::836B:4179]/printers/tiger/bob
+
+
+
+ 4.5.2. IPP URL Comparisons
+
+ When comparing two IPP URLs to decide if they match or not, an IPP
+ Client SHOULD use a case-sensitive octet-by-octet comparison of the
+ entire URLs, with these exceptions:
+
+ - A port that is empty or not given is equivalent to the well-known
+ port for that IPP URL (port 631);
+
+ - Comparisons of host names MUST be case-insensitive;
+
+ - Comparisons of scheme names MUST be case-insensitive;
+
+ - An empty 'abs_path' is equivalent to an 'abs_path' of "/".
+
+ Characters other than those in the "reserved" and "unsafe" sets (see
+ [RFC-2396] and [RFC-2732]) are equivalent to their ""%" HEX HEX"
+ encoding.
+
+ For example, the following three URIs are equivalent:
+
+ ipp://abc.com:631/~smith/printer
+ ipp://ABC.com/%7Esmith/printer
+ ipp://ABC.com:/%7esmith/printer
+
+
+
+
+
+
+Herriot, McDonald Expires 13 August 2001 [Page 9]
+
+Internet Draft IPP URL Scheme 13 February 2001
+
+
+
+5. Conformance Requirements
+
+
+
+ 5.1. Conformance Requirements for IPP Clients
+
+ IPP Clients that conform to this specification:
+
+ a) MUST send IPP URLs (e.g., in the "printer-uri" operation attribute
+ in 'Print-Job') that conform to the ABNF specified in section 4.5
+ of this document;
+
+ b) MUST send IPP operations via the port specified in the IPP URL (if
+ present) or otherwise via IANA assigned well-known port 631;
+
+ c) MUST convert IPP URLs to their corresponding HTTP URL forms
+ according to the rules in section 5 'IPP URL Scheme' in
+ [RFC-2910];
+
+ d) SHOULD interoperate with IPP/1.0 Printers according to the rules
+ in section 9 'Interoperability with IPP/1.0 Implementations' and
+ section 9.2 'Security and URL Schemes' in [RFC-2910].
+
+
+
+ 5.2. Conformance Requirements for IPP Printers
+
+ IPP Printers that conform to this specification:
+
+ a) SHOULD reject received IPP URLs in "application/ipp" request
+ bodies (e.g., in the "printer-uri" attribute in a 'Print-Job'
+ request) that do not conform to the ABNF for IPP URLs specified in
+ section 4.5 of this document;
+
+ b) SHOULD return IPP URLs in "application/ipp" response bodies (e.g.,
+ in the "job-uri" attribute in a 'Print-Job' response) that do
+ conform to the ABNF for IPP URLs specified in section 4.5 of this
+ document;
+
+ c) MUST listen for IPP operations on IANA-assigned well-known port
+ 631, unless explicitly configured by system administrators or site
+ policies;
+
+ d) SHOULD NOT listen for IPP operations on any other port, unless
+ explicitly configured by system administrators or site policies;
+
+ e) SHOULD interoperate with IPP/1.0 Clients according to the rules in
+ section 9 'Interoperability with IPP/1.0 Implementations' and
+ section 9.2 'Security and URL Schemes' in [RFC-2910].
+
+Herriot, McDonald Expires 13 August 2001 [Page 10]
+
+Internet Draft IPP URL Scheme 13 February 2001
+
+
+
+6. IANA Considerations
+
+ This document is intended for use in registering the "ipp" URL scheme
+ with IANA and fully conforms to the requirements in [RFC-2717]. This
+ document defines the "ipp" URL (Uniform Resource Locator) scheme for
+ specifying the location of an IPP Printer, IPP Job, or other IPP
+ object (defined in some future version of IPP) which implements the
+ IPP/1.1 Model [RFC-2911] and the IPP/1.1 Protocol encoding over HTTP
+ [RFC-2910] or any later version of IPP. The intended usage of the
+ "ipp" URL scheme is COMMON.
+
+ This IPP URL Scheme specification does not introduce any additional
+ IANA considerations, beyond those described in [RFC-2910] and
+ [RFC-2911].
+
+ See: Section 6 'IANA Considerations' in [RFC-2910]
+ See: Section 6 'IANA Considerations' in [RFC-2911].
+
+
+
+7. Internationalization Considerations
+
+ This IPP URL Scheme specification does not introduce any additional
+ internationalization considerations, beyond those described in
+ [RFC-2910] and [RFC-2911].
+
+ See: Section 7 'Internationalization Considerations' in [RFC-2910].
+ See: Section 7 'Internationalization Considerations' in [RFC-2911].
+
+
+
+8. Security Considerations
+
+ This IPP URL Scheme specification does not introduce any additional
+ security considerations, beyond those described in [RFC-2910] and
+ [RFC-2911].
+
+ See: Section 8 'Security Considerations' in [RFC-2910].
+ See: Section 8 'Security Considerations' in [RFC-2911].
+
+
+
+
+
+
+
+
+
+
+
+Herriot, McDonald Expires 13 August 2001 [Page 11]
+
+Internet Draft IPP URL Scheme 13 February 2001
+
+
+
+9. References
+
+ See: Section 10 'References' in [RFC-2910].
+ See: Section 9 'References' in [RFC-2911].
+
+ [IANA-CHARREG] IANA Charset Registry.
+ ftp://ftp.isi.edu/in-notes/iana/assignments/character-sets
+
+ [IANA-MIMEREG] IANA MIME Media Types Registry.
+ ftp://ftp.isi.edu/in-notes/iana/assignments/media-types/...
+
+ [IANA-PORTREG] IANA Port Numbers Registry.
+ ftp://ftp.isi.edu/in-notes/iana/assignments/port-numbers
+
+ [NET-SSL3] Netscape. The SSL Protocol, Version 3 (text version
+ 3.02), November 1996.
+
+ [RFC-1759] R. Smith, F. Wright, T. Hastings, S. Zilles,
+ J. Gyllenskog. Printer MIB, RFC 1759, March 1995.
+
+ [RFC-1900] B. Carpenter, Y. Rekhter. Renumbering Needs Work, RFC
+ 1900, February 1996.
+
+ [RFC-2046] N. Freed, N. Borenstein. MIME Part Two: Media Types, RFC
+ 2046, November 1996.
+
+ [RFC-2048] N. Freed, J. Klensin, J. Postel. MIME Part
+ Four: Registration Procedures, RFC 2048, November 1996.
+
+ [RFC-2234] D. Crocker, P. Overell. Augmented BNF for Syntax
+ Specifications: ABNF, RFC 2234, November 1997.
+
+ [RFC-2373] R. Hinden, S. Deering. IP Version 6 Addressing
+ Architecture, RFC 2373, July 1998.
+
+ [RFC-2396] T. Berners-Lee, R. Fielding, L. Masinter. Uniform
+ Resource Identifiers (URI): Generic Syntax, RFC 2396, August 1998.
+
+ [RFC-2246] T. Dierks, C. Allen. The TLS Protocol Version, RFC 2246,
+ January 1999.
+
+ [RFC-2277] H. Alvestrand. IETF Policy on Character Sets and
+ Languages, RFC 2277, January 1998.
+
+ [RFC-2279] F. Yergeau. UTF-8, a Transformation Format of ISO 10646,
+ RFC 2279, January 1998.
+
+ [RFC-2565] R. Herriot, S. Butler, P. Moore, R. Turner. IPP/1.0
+ Encoding and Transport, RFC 2565, April 1999 (Experimental).
+
+Herriot, McDonald Expires 13 August 2001 [Page 12]
+
+Internet Draft IPP URL Scheme 13 February 2001
+
+
+ [RFC-2566] R. deBry, T. Hastings, R. Herriot, S. Isaacson, P. Powell.
+ IPP/1.0 Model and Semantics, RFC 2566, April 1999 (Experimental).
+
+ [RFC-2579] K. McCloghrie, D. Perkins, J. Schoenwaelder. Textual
+ Conventions for SMIv2, RFC 2579, April 1999.
+
+ [RFC-2616] R. Fielding, J. Gettys, J. Mogul, H. Frystyk, L. Masinter,
+ P. Leach, T. Berners-Lee. Hypertext Transfer Protocol -- HTTP/1.1,
+ RFC 2616, June 1999.
+
+ [RFC-2617] J. Franks, P. Hallam-Baker, J. Hostetler, S. Lawrence,
+ P. Leach, A. Luotonen, L. Stewart. HTTP Authentication: Basic and
+ Digest Access Authentication, RFC 2617, June 1999.
+
+ [RFC-2717] R. Petke, I. King. Registration Procedures for URL Scheme
+ Names, RFC 2717, November 1999.
+
+ [RFC-2718] L. Masinter, H. Alvestrand, D. Zigmond, R. Petke.
+ Guidelines for new URL Scheme Names, RFC 2718, November 1999.
+
+ [RFC-2732] R. Hinden,B. Carpenter, L. Masinter. Format for Literal
+ IPv6 Addresses in URL's, RFC 2732, December 1999.
+
+ [RFC-2910] R. Herriot, S. Butler, P. Moore, R. Turner, J. Wenn.
+ IPP/1.1 Encoding and Transport, RFC 2910, September 2000.
+
+ [RFC-2911] T. Hastings, R. Herriot, R. deBry, S. Isaacson, P. Powell.
+ IPP/1.1 Model and Semantics, RFC 2911, September 2000.
+
+ [RFC-2978] N. Freed, J. Postel. IANA Charset Registration
+ Procedures, RFC 2978, October 2000.
+
+ [RFC-3066] H. Alvestrand. Tags for the Identification of Languages,
+ RFC 3066, January 2001.
+
+ [US-ASCII] Coded Character Set -- 7-bit American Standard Code for
+ Information Interchange, ANSI X3.4-1986.
+
+
+
+10. Acknowledgments
+
+ This document is a product of the Internet Printing Protocol Working
+ Group of the Internet Engineering Task Force (IETF). Comments should
+ be submitted to the ipp@pwg.org mailing list.
+
+ Thanks to Pat Fleming (IBM), Tom Hastings (Xerox), Harry Lewis (IBM),
+ and Hugo Parra (Novell).
+
+ Section 5 'IPP URL Scheme' in IPP/1.1 Encoding and Transport
+
+Herriot, McDonald Expires 13 August 2001 [Page 13]
+
+Internet Draft IPP URL Scheme 13 February 2001
+
+ [RFC-2910] was the primary input to this IPP URL Scheme
+ specification.
+
+
+
+11. Authors' Addresses
+
+ Robert Herriot
+ Xerox Corporation
+ 3400 Hill View Ave, Building 1
+ Palo Alto, CA 94304
+
+ Phone: +1 650-813-7696
+ Fax: +1 650-813-6860
+ Email: robert.herriot@pahv.xerox.com
+
+
+ Ira McDonald
+ High North Inc
+ 221 Ridge Ave
+ Grand Marais, MI 49839
+
+ Phone: +1 906-494-2434
+ Email: imcdonald@crt.xerox.com
+ Email: imcdonald@sharplabs.com
+
+
+
+12. Appendix X - Change History
+
+ [To be deleted before RFC publication]
+
+ 13 February 2001 - draft-ietf-ipp-url-scheme-02.txt
+ - revised section 3 'IPP Model for Printers and Jobs' and section 4.5
+ 'IPP URL Scheme Syntax in ABNF' to add notes stating that "IPP URL"
+ (in this document) is a synonym for "ipp-URL" in [RFC-2910], per
+ request of Bob Herriot;
+ - revised section 4.5 'IPP URL Scheme Syntax in ABNF' to correct typo
+ that showed "http:" rather than "ipp:" in the one-line ABNF, per
+ request of Tom Hastings;
+ - revised section 4.5.1 'IPP URL Examples' to add a note discouraging
+ the use of literal IP addresses in URLs, per [RFC-2616] and
+ [RFC-1900];
+
+ 5 February 2001 - draft-ietf-ipp-url-scheme-01.txt
+ - revised section 4.1 'IPP URL Applicability and Intended Usage' to
+ clarify that a given IPP URL MAY identify an IPP Printer object or
+ an IPP Job object, per request of Tom Hastings;
+ - revised section 4.5 'IPP URL Scheme Syntax in ABNF' to define IPP
+ URLs consistently with section 3.2.2 'http URL' of HTTP/1.1
+ [RFC-2616], per request of Tom Hastings;
+
+Herriot, McDonald Expires 13 August 2001 [Page 14]
+
+Internet Draft IPP URL Scheme 13 February 2001
+
+ - revised section 4.5 'IPP URL Scheme Syntax in ABNF' to clarify that
+ IPP URLs may reference IPP Printer objects, IPP Job objects, or
+ (possibly other future) IPP objects, per request of Bob Herriot;
+ - added section 4.5.1 'IPP URL Examples' to supply meaningful
+ examples of IPP URLs with host names, IPv4 addresses, and IPv6
+ addresses, per request of Tom Hastings;
+ - added section 4.5.2 'IPP URL Comparisons' to define IPP URL
+ comparisons consistently with section 3.3 'URI Comparison' of
+ HTTP/1.1 [RFC-2616], per request of Tom Hastings;
+ - revised section 5.1 'Conformance Requirements for IPP Clients' to
+ clarify that an IPP Client MUST convert IPP URLs to their
+ corresponding HTTP URL forms according to section 5 'IPP URL
+ Scheme' in [RFC-2910], per request of Tom Hastings and Bob Herriot;
+ - revised section 5.1 'Conformance Requirements for IPP Clients' and
+ section 5.2 'Conformance Requirements for IPP Printers' to clarify
+ that IPP Clients and IPP Printers SHOULD interoperate with IPP/1.0
+ systems according to section 9 'Interoperability with IPP/1.0
+ Implementations' in [RFC-2910], per request of Carl Kugler;
+ - revised section 5.2 'Conformance Requirements for IPP Printers' to
+ clarify that an IPP Printer MUST listen on (IANA assigned
+ well-known) port 631, unless explicitly configured, per request of
+ Michael Sweet;
+ - revised section 5.2 'Conformance Requirements for IPP Printers' to
+ clarify that an IPP Printer SHOULD NOT listen on ports other than
+ (IANA assigned well-known) port 631, unless explicitly configured,
+ per request of Don Wright;
+ - revised section 6 'IANA Considerations' to clarify that the sole
+ purpose of the entire document is IANA registration of the "ipp"
+ URL scheme;
+ - deleted Appendix A 'Registration of IPP Port' as unnecessary (port
+ is already registered);
+ - deleted Appendix B 'Registration of MIME "application/ipp" as
+ unnecessary (MIME registry has recently caught up to RFC 2910);
+
+ 11 January 2001 - draft-ietf-ipp-url-scheme-00.txt
+ - initial version - simple "ipp" URL scheme without parameters or
+ query part (consistent with existing and IPP/1.1 implementations);
+ - added Appendix A 'Registration of IPP Port' (placeholder) for
+ updated IANA registration of port 631 with references to IPP/1.1;
+ - added Appendix B 'Registration of MIME "application/ipp"' with
+ updated IANA registration for IPP MIME type with references to both
+ IPP/1.0 and IPP/1.1;
+
+
+
+
+13. Full Copyright Statement
+
+ Copyright (C) The Internet Society (2001). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+
+Herriot, McDonald Expires 13 August 2001 [Page 15]
+
+Internet Draft IPP URL Scheme 13 February 2001
+
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, McDonald Expires 13 August 2001 [Page 16]
diff --git a/standards/rfc1179.txt b/standards/rfc1179.txt
new file mode 100644
index 000000000..ef59411f7
--- /dev/null
+++ b/standards/rfc1179.txt
@@ -0,0 +1,787 @@
+
+
+
+
+
+
+Network Printing Working Group L. McLaughlin III, Editor
+Request for Comments: 1179 The Wollongong Group
+ August 1990
+
+
+ Line Printer Daemon Protocol
+
+Status of this Memo
+
+ This RFC describes an existing print server protocol widely used on
+ the Internet for communicating between line printer daemons (both
+ clients and servers). This memo is for informational purposes only,
+ and does not specify an Internet standard. Please refer to the
+ current edition of the "IAB Official Protocol Standards" for the
+ standardization state and status of this protocol. Distribution of
+ this memo is unlimited.
+
+1. Introduction
+
+ The Berkeley versions of the Unix(tm) operating system provide line
+ printer spooling with a collection of programs: lpr (assign to
+ queue), lpq (display the queue), lprm (remove from queue), and lpc
+ (control the queue). These programs interact with an autonomous
+ process called the line printer daemon. This RFC describes the
+ protocols with which a line printer daemon client may control
+ printing.
+
+ This memo is based almost entirely on the work of Robert Knight at
+ Princeton University. I gratefully acknowledge his efforts in
+ deciphering the UNIX lpr protocol and producing earlier versions of
+ this document.
+
+2. Model of Printing Environment
+
+ A group of hosts request services from a line printer daemon process
+ running on a host. The services provided by the process are related
+ to printing jobs. A printing job produces output from one file.
+ Each job will have a unique job number which is between 0 and 999,
+ inclusive. The jobs are requested by users which have names. These
+ user names may not start with a digit.
+
+3. Specification of the Protocol
+
+ The specification includes file formats for the control and data
+ files as well as messages used by the protocol.
+
+
+
+
+
+
+McLaughlin [Page 1]
+
+RFC 1179 LPR August 1990
+
+
+3.1 Message formats
+
+ LPR is a a TCP-based protocol. The port on which a line printer
+ daemon listens is 515. The source port must be in the range 721 to
+ 731, inclusive. A line printer daemon responds to commands send to
+ its port. All commands begin with a single octet code, which is a
+ binary number which represents the requested function. The code is
+ immediately followed by the ASCII name of the printer queue name on
+ which the function is to be performed. If there are other operands
+ to the command, they are separated from the printer queue name with
+ white space (ASCII space, horizontal tab, vertical tab, and form
+ feed). The end of the command is indicated with an ASCII line feed
+ character.
+
+4. Diagram Conventions
+
+ The diagrams in the rest of this RFC use these conventions. These
+ diagrams show the format of an octet stream sent to the server. The
+ outermost box represents this stream. Each box within the outermost
+ one shows one portion of the stream. If the contents of the box is
+ two decimal digits, this indicates that the binary 8 bit value is to
+ be used. If the contents is two uppercase letters, this indicates
+ that the corresponding ASCII control character is to be used. An
+ exception to this is that the character SP can be interpreted as
+ white space. (See the preceding section for a definition.) If the
+ contents is a single letter, the ASCII code for this letter must be
+ sent. Otherwise, the contents are intended to be mnemonic of the
+ contents of the field which is a sequence of octets.
+
+5. Daemon commands
+
+ The verbs in the command names should be interpreted as statements
+ made to the daemon. Thus, the command "Print any waiting jobs" is an
+ imperative to the line printer daemon to which it is sent. A new
+ connection must be made for each command to be given to the daemon.
+
+5.1 01 - Print any waiting jobs
+
+ +----+-------+----+
+ | 01 | Queue | LF |
+ +----+-------+----+
+ Command code - 1
+ Operand - Printer queue name
+
+ This command starts the printing process if it not already running.
+
+
+
+
+
+
+McLaughlin [Page 2]
+
+RFC 1179 LPR August 1990
+
+
+5.2 02 - Receive a printer job
+
+ +----+-------+----+
+ | 02 | Queue | LF |
+ +----+-------+----+
+ Command code - 2
+ Operand - Printer queue name
+
+ Receiving a job is controlled by a second level of commands. The
+ daemon is given commands by sending them over the same connection.
+ The commands are described in the next section (6).
+
+ After this command is sent, the client must read an acknowledgement
+ octet from the daemon. A positive acknowledgement is an octet of
+ zero bits. A negative acknowledgement is an octet of any other
+ pattern.
+
+5.3 03 - Send queue state (short)
+
+ +----+-------+----+------+----+
+ | 03 | Queue | SP | List | LF |
+ +----+-------+----+------+----+
+ Command code - 3
+ Operand 1 - Printer queue name
+ Other operands - User names or job numbers
+
+ If the user names or job numbers or both are supplied then only those
+ jobs for those users or with those numbers will be sent.
+
+ The response is an ASCII stream which describes the printer queue.
+ The stream continues until the connection closes. Ends of lines are
+ indicated with ASCII LF control characters. The lines may also
+ contain ASCII HT control characters.
+
+5.4 04 - Send queue state (long)
+
+ +----+-------+----+------+----+
+ | 04 | Queue | SP | List | LF |
+ +----+-------+----+------+----+
+ Command code - 4
+ Operand 1 - Printer queue name
+ Other operands - User names or job numbers
+
+ If the user names or job numbers or both are supplied then only those
+ jobs for those users or with those numbers will be sent.
+
+ The response is an ASCII stream which describes the printer queue.
+ The stream continues until the connection closes. Ends of lines are
+
+
+
+McLaughlin [Page 3]
+
+RFC 1179 LPR August 1990
+
+
+ indicated with ASCII LF control characters. The lines may also
+ contain ASCII HT control characters.
+
+5.5 05 - Remove jobs
+
+ +----+-------+----+-------+----+------+----+
+ | 05 | Queue | SP | Agent | SP | List | LF |
+ +----+-------+----+-------+----+------+----+
+ Command code - 5
+ Operand 1 - Printer queue name
+ Operand 2 - User name making request (the agent)
+ Other operands - User names or job numbers
+
+ This command deletes the print jobs from the specified queue which
+ are listed as the other operands. If only the agent is given, the
+ command is to delete the currently active job. Unless the agent is
+ "root", it is not possible to delete a job which is not owned by the
+ user. This is also the case for specifying user names instead of
+ numbers. That is, agent "root" can delete jobs by user name but no
+ other agents can.
+
+6. Receive job subcommands
+
+ These commands are processed when the line printer daemon has
+ been given the receive job command. The daemon will continue to
+ process commands until the connection is closed.
+
+ After a subcommand is sent, the client must wait for an
+ acknowledgement from the daemon. A positive acknowledgement is an
+ octet of zero bits. A negative acknowledgement is an octet of any
+ other pattern.
+
+ LPR clients SHOULD be able to sent the receive data file and receive
+ control file subcommands in either order. LPR servers MUST be able
+ to receive the control file subcommand first and SHOULD be able to
+ receive the data file subcommand first.
+
+6.1 01 - Abort job
+
+ Command code - 1
+ +----+----+
+ | 01 | LF |
+ +----+----+
+
+ No operands should be supplied. This subcommand will remove any
+ files which have been created during this "Receive job" command.
+
+
+
+
+
+McLaughlin [Page 4]
+
+RFC 1179 LPR August 1990
+
+
+6.2 02 - Receive control file
+
+ +----+-------+----+------+----+
+ | 02 | Count | SP | Name | LF |
+ +----+-------+----+------+----+
+ Command code - 2
+ Operand 1 - Number of bytes in control file
+ Operand 2 - Name of control file
+
+ The control file must be an ASCII stream with the ends of lines
+ indicated by ASCII LF. The total number of bytes in the stream is
+ sent as the first operand. The name of the control file is sent as
+ the second. It should start with ASCII "cfA", followed by a three
+ digit job number, followed by the host name which has constructed the
+ control file. Acknowledgement processing must occur as usual after
+ the command is sent.
+
+ The next "Operand 1" octets over the same TCP connection are the
+ intended contents of the control file. Once all of the contents have
+ been delivered, an octet of zero bits is sent as an indication that
+ the file being sent is complete. A second level of acknowledgement
+ processing must occur at this point.
+
+6.3 03 - Receive data file
+
+ +----+-------+----+------+----+
+ | 03 | Count | SP | Name | LF |
+ +----+-------+----+------+----+
+ Command code - 3
+ Operand 1 - Number of bytes in data file
+ Operand 2 - Name of data file
+
+ The data file may contain any 8 bit values at all. The total number
+ of bytes in the stream may be sent as the first operand, otherwise
+ the field should be cleared to 0. The name of the data file should
+ start with ASCII "dfA". This should be followed by a three digit job
+ number. The job number should be followed by the host name which has
+ constructed the data file. Interpretation of the contents of the
+ data file is determined by the contents of the corresponding control
+ file. If a data file length has been specified, the next "Operand 1"
+ octets over the same TCP connection are the intended contents of the
+ data file. In this case, once all of the contents have been
+ delivered, an octet of zero bits is sent as an indication that the
+ file being sent is complete. A second level of acknowledgement
+ processing must occur at this point.
+
+
+
+
+
+
+McLaughlin [Page 5]
+
+RFC 1179 LPR August 1990
+
+
+7. Control file lines
+
+ This section discusses the format of the lines in the control file
+ which is sent to the line printer daemon.
+
+ Each line of the control file consists of a single, printable ASCII
+ character which represents a function to be performed when the file
+ is printed. Interpretation of these command characters are case-
+ sensitive. The rest of the line after the command character is the
+ command's operand. No leading white space is permitted after the
+ command character. The line ends with an ASCII new line.
+
+ Those commands which have a lower case letter as a command code are
+ used to specify an actual printing request. The commands which use
+ upper case are used to describe parametric values or background
+ conditions.
+
+ Some commands must be included in every control file. These are 'H'
+ (responsible host) and 'P' (responsible user). Additionally, there
+ must be at least one lower case command to produce any output.
+
+7.1 C - Class for banner page
+
+ +---+-------+----+
+ | C | Class | LF |
+ +---+-------+----+
+ Command code - 'C'
+ Operand - Name of class for banner pages
+
+ This command sets the class name to be printed on the banner page.
+ The name must be 31 or fewer octets. The name can be omitted. If it
+ is, the name of the host on which the file is printed will be used.
+ The class is conventionally used to display the host from which the
+ printing job originated. It will be ignored unless the print banner
+ command ('L') is also used.
+
+7.2 H - Host name
+
+ +---+------+----+
+ | H | Host | LF |
+ +---+------+----+
+ Command code - 'H'
+ Operand - Name of host
+
+ This command specifies the name of the host which is to be treated as
+ the source of the print job. The command must be included in the
+ control file. The name of the host must be 31 or fewer octets.
+
+
+
+
+McLaughlin [Page 6]
+
+RFC 1179 LPR August 1990
+
+
+7.3 I - Indent Printing
+
+ +---+-------+----+
+ | I | count | LF |
+ +---+-------+----+
+ Command code - 'I'
+ Operand - Indenting count
+
+ This command specifies that, for files which are printed with the
+ 'f', of columns given. (It is ignored for other output generating
+ commands.) The identing count operand must be all decimal digits.
+
+7.4 J - Job name for banner page
+
+ +---+----------+----+
+ | J | Job name | LF |
+ +---+----------+----+
+ Command code - 'J'
+ Operand - Job name
+
+ This command sets the job name to be printed on the banner page. The
+ name of the job must be 99 or fewer octets. It can be omitted. The
+ job name is conventionally used to display the name of the file or
+ files which were "printed". It will be ignored unless the print
+ banner command ('L') is also used.
+
+7.5 L - Print banner page
+
+ +---+------+----+
+ | L | User | LF |
+ +---+------+----+
+ Command code - 'L'
+ Operand - Name of user for burst pages
+
+ This command causes the banner page to be printed. The user name can
+ be omitted. The class name for banner page and job name for banner
+ page commands must precede this command in the control file to be
+ effective.
+
+7.6 M - Mail When Printed
+
+ +---+------+----+
+ | M | user | LF |
+ +---+------+----+
+ Command code - 'M'
+ Operand - User name
+
+ This entry causes mail to be sent to the user given as the operand at
+
+
+
+McLaughlin [Page 7]
+
+RFC 1179 LPR August 1990
+
+
+ the host specified by the 'H' entry when the printing operation ends
+ (successfully or unsuccessfully).
+
+7.7 N - Name of source file
+
+ +---+------+----+
+ | N | Name | LF |
+ +---+------+----+
+ Command code - 'N'
+ Operand - File name
+
+ This command specifies the name of the file from which the data file
+ was constructed. It is returned on a query and used in printing with
+ the 'p' command when no title has been given. It must be 131 or
+ fewer octets.
+
+7.8 P - User identification
+
+ +---+------+----+
+ | P | Name | LF |
+ +---+------+----+
+ Command code - 'P'
+ Operand - User id
+
+ This command specifies the user identification of the entity
+ requesting the printing job. This command must be included in the
+ control file. The user identification must be 31 or fewer octets.
+
+7.9 S - Symbolic link data
+
+ +---+--------+----+-------+----+
+ | S | device | SP | inode | LF |
+ +---+--------+----+-------+----+
+ Command code - 'S'
+ Operand 1 - Device number
+ Operand 2 - Inode number
+
+ This command is used to record symbolic link data on a Unix system so
+ that changing a file's directory entry after a file is printed will
+ not print the new file. It is ignored if the data file is not
+ symbolically linked.
+
+
+
+
+
+
+
+
+
+
+McLaughlin [Page 8]
+
+RFC 1179 LPR August 1990
+
+
+7.10 T - Title for pr
+
+ +---+-------+----+
+ | T | title | LF |
+ +---+-------+----+
+ Command code - 'T'
+ Operand - Title text
+
+ This command provides a title for a file which is to be printed with
+ either the 'p' command. (It is ignored by all of the other printing
+ commands.) The title must be 79 or fewer octets.
+
+7.11 U - Unlink data file
+
+ +---+------+----+
+ | U | file | LF |
+ +---+------+----+
+ Command code - 'U'
+ Operand - File to unlink
+
+ This command indicates that the specified file is no longer needed.
+ This should only be used for data files.
+
+7.12 W - Width of output
+
+ +---+-------+----+
+ | W | width | LF |
+ +---+-------+----+
+ Command code - 'W'
+ Operand - Width count
+
+ This command limits the output to the specified number of columns for
+ the 'f', 'l', and 'p' commands. (It is ignored for other output
+ generating commands.) The width count operand must be all decimal
+ digits. It may be silently reduced to some lower value. The default
+ value for the width is 132.
+
+7.13 1 - troff R font
+
+ +---+------+----+
+ | 1 | file | LF |
+ +---+------+----+
+ Command code - '1'
+ Operand - File name
+
+ This command specifies the file name for the troff R font. [1] This
+ is the font which is printed using Times Roman by default.
+
+
+
+
+McLaughlin [Page 9]
+
+RFC 1179 LPR August 1990
+
+
+7.14 2 - troff I font
+
+ +---+------+----+
+ | 2 | file | LF |
+ +---+------+----+
+ Command code - '2'
+ Operand - File name
+
+ This command specifies the file name for the troff I font. [1] This
+ is the font which is printed using Times Italic by default.
+
+7.15 3 - troff B font
+
+ +---+------+----+
+ | 3 | file | LF |
+ +---+------+----+
+ Command code - '3'
+ Operand - File name
+
+ This command specifies the file name for the troff B font. [1] This
+ is the font which is printed using Times Bold by default.
+
+7.16 4 - troff S font
+
+ +---+------+----+
+ | 4 | file | LF |
+ +---+------+----+
+ Command code - '4'
+ Operand - File name
+
+ This command specifies the file name for the troff S font. [1] This
+ is the font which is printed using Special Mathematical Font by
+ default.
+
+7.17 c - Plot CIF file
+
+ +---+------+----+
+ | c | file | LF |
+ +---+------+----+
+ Command code - 'c'
+ Operand - File to plot
+
+ This command causes the data file to be plotted, treating the data as
+ CIF (CalTech Intermediate Form) graphics language. [2]
+
+
+
+
+
+
+
+McLaughlin [Page 10]
+
+RFC 1179 LPR August 1990
+
+
+7.18 d - Print DVI file
+
+ +---+------+----+
+ | d | file | LF |
+ +---+------+----+
+ Command code - 'd'
+ Operand - File to print
+
+ This command causes the data file to be printed, treating the data as
+ DVI (TeX output). [3]
+
+7.19 f - Print formatted file
+
+ +---+------+----+
+ | f | file | LF |
+ +---+------+----+
+ Command code - 'f'
+ Operand - File to print
+
+ This command cause the data file to be printed as a plain text file,
+ providing page breaks as necessary. Any ASCII control characters
+ which are not in the following list are discarded: HT, CR, FF, LF,
+ and BS.
+
+7.20 g - Plot file
+
+ +---+------+----+
+ | g | file | LF |
+ +---+------+----+
+ Command code - 'g'
+ Operand - File to plot
+
+ This command causes the data file to be plotted, treating the data as
+ output from the Berkeley Unix plot library. [1]
+
+7.21 k - Reserved for use by Kerberized LPR clients and servers.
+
+7.22 l - Print file leaving control characters
+
+ +---+------+----+
+ | l | file | LF |
+ +---+------+----+
+ Command code - 'l' (lower case L)
+ Operand - File to print
+
+ This command causes the specified data file to printed without
+ filtering the control characters (as is done with the 'f' command).
+
+
+
+
+McLaughlin [Page 11]
+
+RFC 1179 LPR August 1990
+
+
+7.23 n - Print ditroff output file
+
+ +---+------+----+
+ | n | file | LF |
+ +---+------+----+
+ Command code - 'n'
+ Operand - File to print
+
+ This command prints the data file to be printed, treating the data as
+ ditroff output. [4]
+
+7.24 o - Print Postscript output file
+
+ +---+------+----+
+ | o | file | LF |
+ +---+------+----+
+ Command code - 'o'
+ Operand - File to print
+
+ This command prints the data file to be printed, treating the data as
+ standard Postscript input.
+
+7.25 p - Print file with 'pr' format
+
+ +---+------+----+
+ | p | file | LF |
+ +---+------+----+
+ Command code - 'p'
+ Operand - File to print
+
+ This command causes the data file to be printed with a heading, page
+ numbers, and pagination. The heading should include the date and
+ time that printing was started, the title, and a page number
+ identifier followed by the page number. The title is the name of
+ file as specified by the 'N' command, unless the 'T' command (title)
+ has been given. After a page of text has been printed, a new page is
+ started with a new page number. (There is no way to specify the
+ length of the page.)
+
+7.26 r - File to print with FORTRAN carriage control
+
+ +---+------+----+
+ | r | file | LF |
+ +---+------+----+
+ Command code - 'r'
+ Operand - File to print
+
+ This command causes the data file to be printed, interpreting the
+
+
+
+McLaughlin [Page 12]
+
+RFC 1179 LPR August 1990
+
+
+ first column of each line as FORTRAN carriage control. The FORTRAN
+ standard limits this to blank, "1", "0", and "+" carriage controls.
+ Most FORTRAN programmers also expect "-" (triple space) to work as
+ well.
+
+7.27 t - Print troff output file
+
+ +---+------+----+
+ | t | file | LF |
+ +---+------+----+
+ Command code - 't'
+ Operand - File to print
+
+ This command prints the data file as Graphic Systems C/A/T
+ phototypesetter input. [5] This is the standard output of the Unix
+ "troff" command.
+
+7.28 v - Print raster file
+
+ +---+------+----+
+ | v | file | LF |
+ +---+------+----+
+ Command code - 'v'
+ Operand - File to print
+
+ This command prints a Sun raster format file. [6]
+
+7.29 z - Reserved for future use with the Palladium print system.
+
+REFERENCES and BIBLIOGRAPHY
+
+ [1] Computer Science Research Group, "UNIX Programmer's Reference
+ Manual", USENIX, 1986.
+
+ [2] Hon and Sequin, "A Guide to LSI Implementation", XEROX PARC,
+ 1980.
+
+ [3] Knuth, D., "TeX The Program".
+
+ [4] Kernighan, B., "A Typesetter-independent TROFF".
+
+ [5] "Model C/A/T Phototypesetter", Graphic Systems, Inc. Hudson, N.H.
+
+ [6] Sun Microsystems, "Pixrect Reference Manual", Sun Microsystems,
+ Mountain View, CA, 1988.
+
+
+
+
+
+
+McLaughlin [Page 13]
+
+RFC 1179 LPR August 1990
+
+
+Security Considerations
+
+ Security issues are not discussed in this memo.
+
+Author's Address
+
+ Leo J. McLaughlin III
+ The Wollongong Group
+ 1129 San Antonio Road
+ Palo Alto, CA 94303
+
+ Phone: 415-962-7100
+
+ EMail: ljm@twg.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+McLaughlin [Page 14]
+ \ No newline at end of file
diff --git a/standards/rfc1321.txt b/standards/rfc1321.txt
new file mode 100644
index 000000000..68af27d2b
--- /dev/null
+++ b/standards/rfc1321.txt
@@ -0,0 +1,1179 @@
+
+
+
+
+
+
+Network Working Group R. Rivest
+Request for Comments: 1321 MIT Laboratory for Computer Science
+ and RSA Data Security, Inc.
+ April 1992
+
+
+ The MD5 Message-Digest Algorithm
+
+Status of this Memo
+
+ This memo provides information for the Internet community. It does
+ not specify an Internet standard. Distribution of this memo is
+ unlimited.
+
+Acknowlegements
+
+ We would like to thank Don Coppersmith, Burt Kaliski, Ralph Merkle,
+ David Chaum, and Noam Nisan for numerous helpful comments and
+ suggestions.
+
+Table of Contents
+
+ 1. Executive Summary 1
+ 2. Terminology and Notation 2
+ 3. MD5 Algorithm Description 3
+ 4. Summary 6
+ 5. Differences Between MD4 and MD5 6
+ References 7
+ APPENDIX A - Reference Implementation 7
+ Security Considerations 21
+ Author's Address 21
+
+1. Executive Summary
+
+ This document describes the MD5 message-digest algorithm. The
+ algorithm takes as input a message of arbitrary length and produces
+ as output a 128-bit "fingerprint" or "message digest" of the input.
+ It is conjectured that it is computationally infeasible to produce
+ two messages having the same message digest, or to produce any
+ message having a given prespecified target message digest. The MD5
+ algorithm is intended for digital signature applications, where a
+ large file must be "compressed" in a secure manner before being
+ encrypted with a private (secret) key under a public-key cryptosystem
+ such as RSA.
+
+
+
+
+
+
+
+Rivest [Page 1]
+
+RFC 1321 MD5 Message-Digest Algorithm April 1992
+
+
+ The MD5 algorithm is designed to be quite fast on 32-bit machines. In
+ addition, the MD5 algorithm does not require any large substitution
+ tables; the algorithm can be coded quite compactly.
+
+ The MD5 algorithm is an extension of the MD4 message-digest algorithm
+ 1,2]. MD5 is slightly slower than MD4, but is more "conservative" in
+ design. MD5 was designed because it was felt that MD4 was perhaps
+ being adopted for use more quickly than justified by the existing
+ critical review; because MD4 was designed to be exceptionally fast,
+ it is "at the edge" in terms of risking successful cryptanalytic
+ attack. MD5 backs off a bit, giving up a little in speed for a much
+ greater likelihood of ultimate security. It incorporates some
+ suggestions made by various reviewers, and contains additional
+ optimizations. The MD5 algorithm is being placed in the public domain
+ for review and possible adoption as a standard.
+
+ For OSI-based applications, MD5's object identifier is
+
+ md5 OBJECT IDENTIFIER ::=
+ iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 5}
+
+ In the X.509 type AlgorithmIdentifier [3], the parameters for MD5
+ should have type NULL.
+
+2. Terminology and Notation
+
+ In this document a "word" is a 32-bit quantity and a "byte" is an
+ eight-bit quantity. A sequence of bits can be interpreted in a
+ natural manner as a sequence of bytes, where each consecutive group
+ of eight bits is interpreted as a byte with the high-order (most
+ significant) bit of each byte listed first. Similarly, a sequence of
+ bytes can be interpreted as a sequence of 32-bit words, where each
+ consecutive group of four bytes is interpreted as a word with the
+ low-order (least significant) byte given first.
+
+ Let x_i denote "x sub i". If the subscript is an expression, we
+ surround it in braces, as in x_{i+1}. Similarly, we use ^ for
+ superscripts (exponentiation), so that x^i denotes x to the i-th
+ power.
+
+ Let the symbol "+" denote addition of words (i.e., modulo-2^32
+ addition). Let X <<< s denote the 32-bit value obtained by circularly
+ shifting (rotating) X left by s bit positions. Let not(X) denote the
+ bit-wise complement of X, and let X v Y denote the bit-wise OR of X
+ and Y. Let X xor Y denote the bit-wise XOR of X and Y, and let XY
+ denote the bit-wise AND of X and Y.
+
+
+
+
+
+Rivest [Page 2]
+
+RFC 1321 MD5 Message-Digest Algorithm April 1992
+
+
+3. MD5 Algorithm Description
+
+ We begin by supposing that we have a b-bit message as input, and that
+ we wish to find its message digest. Here b is an arbitrary
+ nonnegative integer; b may be zero, it need not be a multiple of
+ eight, and it may be arbitrarily large. We imagine the bits of the
+ message written down as follows:
+
+ m_0 m_1 ... m_{b-1}
+
+ The following five steps are performed to compute the message digest
+ of the message.
+
+3.1 Step 1. Append Padding Bits
+
+ The message is "padded" (extended) so that its length (in bits) is
+ congruent to 448, modulo 512. That is, the message is extended so
+ that it is just 64 bits shy of being a multiple of 512 bits long.
+ Padding is always performed, even if the length of the message is
+ already congruent to 448, modulo 512.
+
+ Padding is performed as follows: a single "1" bit is appended to the
+ message, and then "0" bits are appended so that the length in bits of
+ the padded message becomes congruent to 448, modulo 512. In all, at
+ least one bit and at most 512 bits are appended.
+
+3.2 Step 2. Append Length
+
+ A 64-bit representation of b (the length of the message before the
+ padding bits were added) is appended to the result of the previous
+ step. In the unlikely event that b is greater than 2^64, then only
+ the low-order 64 bits of b are used. (These bits are appended as two
+ 32-bit words and appended low-order word first in accordance with the
+ previous conventions.)
+
+ At this point the resulting message (after padding with bits and with
+ b) has a length that is an exact multiple of 512 bits. Equivalently,
+ this message has a length that is an exact multiple of 16 (32-bit)
+ words. Let M[0 ... N-1] denote the words of the resulting message,
+ where N is a multiple of 16.
+
+3.3 Step 3. Initialize MD Buffer
+
+ A four-word buffer (A,B,C,D) is used to compute the message digest.
+ Here each of A, B, C, D is a 32-bit register. These registers are
+ initialized to the following values in hexadecimal, low-order bytes
+ first):
+
+
+
+
+Rivest [Page 3]
+
+RFC 1321 MD5 Message-Digest Algorithm April 1992
+
+
+ word A: 01 23 45 67
+ word B: 89 ab cd ef
+ word C: fe dc ba 98
+ word D: 76 54 32 10
+
+3.4 Step 4. Process Message in 16-Word Blocks
+
+ We first define four auxiliary functions that each take as input
+ three 32-bit words and produce as output one 32-bit word.
+
+ F(X,Y,Z) = XY v not(X) Z
+ G(X,Y,Z) = XZ v Y not(Z)
+ H(X,Y,Z) = X xor Y xor Z
+ I(X,Y,Z) = Y xor (X v not(Z))
+
+ In each bit position F acts as a conditional: if X then Y else Z.
+ The function F could have been defined using + instead of v since XY
+ and not(X)Z will never have 1's in the same bit position.) It is
+ interesting to note that if the bits of X, Y, and Z are independent
+ and unbiased, the each bit of F(X,Y,Z) will be independent and
+ unbiased.
+
+ The functions G, H, and I are similar to the function F, in that they
+ act in "bitwise parallel" to produce their output from the bits of X,
+ Y, and Z, in such a manner that if the corresponding bits of X, Y,
+ and Z are independent and unbiased, then each bit of G(X,Y,Z),
+ H(X,Y,Z), and I(X,Y,Z) will be independent and unbiased. Note that
+ the function H is the bit-wise "xor" or "parity" function of its
+ inputs.
+
+ This step uses a 64-element table T[1 ... 64] constructed from the
+ sine function. Let T[i] denote the i-th element of the table, which
+ is equal to the integer part of 4294967296 times abs(sin(i)), where i
+ is in radians. The elements of the table are given in the appendix.
+
+ Do the following:
+
+ /* Process each 16-word block. */
+ For i = 0 to N/16-1 do
+
+ /* Copy block i into X. */
+ For j = 0 to 15 do
+ Set X[j] to M[i*16+j].
+ end /* of loop on j */
+
+ /* Save A as AA, B as BB, C as CC, and D as DD. */
+ AA = A
+ BB = B
+
+
+
+Rivest [Page 4]
+
+RFC 1321 MD5 Message-Digest Algorithm April 1992
+
+
+ CC = C
+ DD = D
+
+ /* Round 1. */
+ /* Let [abcd k s i] denote the operation
+ a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
+ /* Do the following 16 operations. */
+ [ABCD 0 7 1] [DABC 1 12 2] [CDAB 2 17 3] [BCDA 3 22 4]
+ [ABCD 4 7 5] [DABC 5 12 6] [CDAB 6 17 7] [BCDA 7 22 8]
+ [ABCD 8 7 9] [DABC 9 12 10] [CDAB 10 17 11] [BCDA 11 22 12]
+ [ABCD 12 7 13] [DABC 13 12 14] [CDAB 14 17 15] [BCDA 15 22 16]
+
+ /* Round 2. */
+ /* Let [abcd k s i] denote the operation
+ a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
+ /* Do the following 16 operations. */
+ [ABCD 1 5 17] [DABC 6 9 18] [CDAB 11 14 19] [BCDA 0 20 20]
+ [ABCD 5 5 21] [DABC 10 9 22] [CDAB 15 14 23] [BCDA 4 20 24]
+ [ABCD 9 5 25] [DABC 14 9 26] [CDAB 3 14 27] [BCDA 8 20 28]
+ [ABCD 13 5 29] [DABC 2 9 30] [CDAB 7 14 31] [BCDA 12 20 32]
+
+ /* Round 3. */
+ /* Let [abcd k s t] denote the operation
+ a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
+ /* Do the following 16 operations. */
+ [ABCD 5 4 33] [DABC 8 11 34] [CDAB 11 16 35] [BCDA 14 23 36]
+ [ABCD 1 4 37] [DABC 4 11 38] [CDAB 7 16 39] [BCDA 10 23 40]
+ [ABCD 13 4 41] [DABC 0 11 42] [CDAB 3 16 43] [BCDA 6 23 44]
+ [ABCD 9 4 45] [DABC 12 11 46] [CDAB 15 16 47] [BCDA 2 23 48]
+
+ /* Round 4. */
+ /* Let [abcd k s t] denote the operation
+ a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
+ /* Do the following 16 operations. */
+ [ABCD 0 6 49] [DABC 7 10 50] [CDAB 14 15 51] [BCDA 5 21 52]
+ [ABCD 12 6 53] [DABC 3 10 54] [CDAB 10 15 55] [BCDA 1 21 56]
+ [ABCD 8 6 57] [DABC 15 10 58] [CDAB 6 15 59] [BCDA 13 21 60]
+ [ABCD 4 6 61] [DABC 11 10 62] [CDAB 2 15 63] [BCDA 9 21 64]
+
+ /* Then perform the following additions. (That is increment each
+ of the four registers by the value it had before this block
+ was started.) */
+ A = A + AA
+ B = B + BB
+ C = C + CC
+ D = D + DD
+
+ end /* of loop on i */
+
+
+
+Rivest [Page 5]
+
+RFC 1321 MD5 Message-Digest Algorithm April 1992
+
+
+3.5 Step 5. Output
+
+ The message digest produced as output is A, B, C, D. That is, we
+ begin with the low-order byte of A, and end with the high-order byte
+ of D.
+
+ This completes the description of MD5. A reference implementation in
+ C is given in the appendix.
+
+4. Summary
+
+ The MD5 message-digest algorithm is simple to implement, and provides
+ a "fingerprint" or message digest of a message of arbitrary length.
+ It is conjectured that the difficulty of coming up with two messages
+ having the same message digest is on the order of 2^64 operations,
+ and that the difficulty of coming up with any message having a given
+ message digest is on the order of 2^128 operations. The MD5 algorithm
+ has been carefully scrutinized for weaknesses. It is, however, a
+ relatively new algorithm and further security analysis is of course
+ justified, as is the case with any new proposal of this sort.
+
+5. Differences Between MD4 and MD5
+
+ The following are the differences between MD4 and MD5:
+
+ 1. A fourth round has been added.
+
+ 2. Each step now has a unique additive constant.
+
+ 3. The function g in round 2 was changed from (XY v XZ v YZ) to
+ (XZ v Y not(Z)) to make g less symmetric.
+
+ 4. Each step now adds in the result of the previous step. This
+ promotes a faster "avalanche effect".
+
+ 5. The order in which input words are accessed in rounds 2 and
+ 3 is changed, to make these patterns less like each other.
+
+ 6. The shift amounts in each round have been approximately
+ optimized, to yield a faster "avalanche effect." The shifts in
+ different rounds are distinct.
+
+
+
+
+
+
+
+
+
+
+Rivest [Page 6]
+
+RFC 1321 MD5 Message-Digest Algorithm April 1992
+
+
+References
+
+ [1] Rivest, R., "The MD4 Message Digest Algorithm", RFC 1320, MIT and
+ RSA Data Security, Inc., April 1992.
+
+ [2] Rivest, R., "The MD4 message digest algorithm", in A.J. Menezes
+ and S.A. Vanstone, editors, Advances in Cryptology - CRYPTO '90
+ Proceedings, pages 303-311, Springer-Verlag, 1991.
+
+ [3] CCITT Recommendation X.509 (1988), "The Directory -
+ Authentication Framework."
+
+APPENDIX A - Reference Implementation
+
+ This appendix contains the following files taken from RSAREF: A
+ Cryptographic Toolkit for Privacy-Enhanced Mail:
+
+ global.h -- global header file
+
+ md5.h -- header file for MD5
+
+ md5c.c -- source code for MD5
+
+ For more information on RSAREF, send email to <rsaref@rsa.com>.
+
+ The appendix also includes the following file:
+
+ mddriver.c -- test driver for MD2, MD4 and MD5
+
+ The driver compiles for MD5 by default but can compile for MD2 or MD4
+ if the symbol MD is defined on the C compiler command line as 2 or 4.
+
+ The implementation is portable and should work on many different
+ plaforms. However, it is not difficult to optimize the implementation
+ on particular platforms, an exercise left to the reader. For example,
+ on "little-endian" platforms where the lowest-addressed byte in a 32-
+ bit word is the least significant and there are no alignment
+ restrictions, the call to Decode in MD5Transform can be replaced with
+ a typecast.
+
+A.1 global.h
+
+/* GLOBAL.H - RSAREF types and constants
+ */
+
+/* PROTOTYPES should be set to one if and only if the compiler supports
+ function argument prototyping.
+The following makes PROTOTYPES default to 0 if it has not already
+
+
+
+Rivest [Page 7]
+
+RFC 1321 MD5 Message-Digest Algorithm April 1992
+
+
+ been defined with C compiler flags.
+ */
+#ifndef PROTOTYPES
+#define PROTOTYPES 0
+#endif
+
+/* POINTER defines a generic pointer type */
+typedef unsigned char *POINTER;
+
+/* UINT2 defines a two byte word */
+typedef unsigned short int UINT2;
+
+/* UINT4 defines a four byte word */
+typedef unsigned long int UINT4;
+
+/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
+If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
+ returns an empty list.
+ */
+#if PROTOTYPES
+#define PROTO_LIST(list) list
+#else
+#define PROTO_LIST(list) ()
+#endif
+
+A.2 md5.h
+
+/* MD5.H - header file for MD5C.C
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+
+
+
+Rivest [Page 8]
+
+RFC 1321 MD5 Message-Digest Algorithm April 1992
+
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+/* MD5 context. */
+typedef struct {
+ UINT4 state[4]; /* state (ABCD) */
+ UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
+ unsigned char buffer[64]; /* input buffer */
+} MD5_CTX;
+
+void MD5Init PROTO_LIST ((MD5_CTX *));
+void MD5Update PROTO_LIST
+ ((MD5_CTX *, unsigned char *, unsigned int));
+void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *));
+
+A.3 md5c.c
+
+/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+#include "global.h"
+#include "md5.h"
+
+/* Constants for MD5Transform routine.
+ */
+
+
+
+Rivest [Page 9]
+
+RFC 1321 MD5 Message-Digest Algorithm April 1992
+
+
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64]));
+static void Encode PROTO_LIST
+ ((unsigned char *, UINT4 *, unsigned int));
+static void Decode PROTO_LIST
+ ((UINT4 *, unsigned char *, unsigned int));
+static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int));
+static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int));
+
+static unsigned char PADDING[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
+};
+
+/* F, G, H and I are basic MD5 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits.
+ */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+Rotation is separate from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, x, s, ac) { \
+ (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+
+
+
+Rivest [Page 10]
+
+RFC 1321 MD5 Message-Digest Algorithm April 1992
+
+
+ (a) += (b); \
+ }
+#define GG(a, b, c, d, x, s, ac) { \
+ (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define HH(a, b, c, d, x, s, ac) { \
+ (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define II(a, b, c, d, x, s, ac) { \
+ (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+
+/* MD5 initialization. Begins an MD5 operation, writing a new context.
+ */
+void MD5Init (context)
+MD5_CTX *context; /* context */
+{
+ context->count[0] = context->count[1] = 0;
+ /* Load magic initialization constants.
+*/
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xefcdab89;
+ context->state[2] = 0x98badcfe;
+ context->state[3] = 0x10325476;
+}
+
+/* MD5 block update operation. Continues an MD5 message-digest
+ operation, processing another message block, and updating the
+ context.
+ */
+void MD5Update (context, input, inputLen)
+MD5_CTX *context; /* context */
+unsigned char *input; /* input block */
+unsigned int inputLen; /* length of input block */
+{
+ unsigned int i, index, partLen;
+
+ /* Compute number of bytes mod 64 */
+ index = (unsigned int)((context->count[0] >> 3) & 0x3F);
+
+ /* Update number of bits */
+ if ((context->count[0] += ((UINT4)inputLen << 3))
+
+
+
+Rivest [Page 11]
+
+RFC 1321 MD5 Message-Digest Algorithm April 1992
+
+
+ < ((UINT4)inputLen << 3))
+ context->count[1]++;
+ context->count[1] += ((UINT4)inputLen >> 29);
+
+ partLen = 64 - index;
+
+ /* Transform as many times as possible.
+*/
+ if (inputLen >= partLen) {
+ MD5_memcpy
+ ((POINTER)&context->buffer[index], (POINTER)input, partLen);
+ MD5Transform (context->state, context->buffer);
+
+ for (i = partLen; i + 63 < inputLen; i += 64)
+ MD5Transform (context->state, &input[i]);
+
+ index = 0;
+ }
+ else
+ i = 0;
+
+ /* Buffer remaining input */
+ MD5_memcpy
+ ((POINTER)&context->buffer[index], (POINTER)&input[i],
+ inputLen-i);
+}
+
+/* MD5 finalization. Ends an MD5 message-digest operation, writing the
+ the message digest and zeroizing the context.
+ */
+void MD5Final (digest, context)
+unsigned char digest[16]; /* message digest */
+MD5_CTX *context; /* context */
+{
+ unsigned char bits[8];
+ unsigned int index, padLen;
+
+ /* Save number of bits */
+ Encode (bits, context->count, 8);
+
+ /* Pad out to 56 mod 64.
+*/
+ index = (unsigned int)((context->count[0] >> 3) & 0x3f);
+ padLen = (index < 56) ? (56 - index) : (120 - index);
+ MD5Update (context, PADDING, padLen);
+
+ /* Append length (before padding) */
+ MD5Update (context, bits, 8);
+
+
+
+Rivest [Page 12]
+
+RFC 1321 MD5 Message-Digest Algorithm April 1992
+
+
+ /* Store state in digest */
+ Encode (digest, context->state, 16);
+
+ /* Zeroize sensitive information.
+*/
+ MD5_memset ((POINTER)context, 0, sizeof (*context));
+}
+
+/* MD5 basic transformation. Transforms state based on block.
+ */
+static void MD5Transform (state, block)
+UINT4 state[4];
+unsigned char block[64];
+{
+ UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+ Decode (x, block, 64);
+
+ /* Round 1 */
+ FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+ FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+ FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+ FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+ FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+ FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+ FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+ FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+ FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+ FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+ FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+ FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+ FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+ FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+ FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+ FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+ GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+ GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+ GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+ GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+ GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+ GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
+ GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+ GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+ GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+ GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+ GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+
+
+
+Rivest [Page 13]
+
+RFC 1321 MD5 Message-Digest Algorithm April 1992
+
+
+ GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+ GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+ GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+ GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+ GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+ /* Round 3 */
+ HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+ HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+ HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+ HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+ HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+ HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+ HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+ HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+ HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+ HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+ HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+ HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
+ HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+ HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+ HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+ HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+ /* Round 4 */
+ II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+ II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+ II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+ II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+ II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+ II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+ II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+ II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+ II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+ II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+ II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+ II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+ II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+ II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+ II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+ II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+
+ /* Zeroize sensitive information.
+
+
+
+Rivest [Page 14]
+
+RFC 1321 MD5 Message-Digest Algorithm April 1992
+
+
+*/
+ MD5_memset ((POINTER)x, 0, sizeof (x));
+}
+
+/* Encodes input (UINT4) into output (unsigned char). Assumes len is
+ a multiple of 4.
+ */
+static void Encode (output, input, len)
+unsigned char *output;
+UINT4 *input;
+unsigned int len;
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4) {
+ output[j] = (unsigned char)(input[i] & 0xff);
+ output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
+ output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
+ output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
+ }
+}
+
+/* Decodes input (unsigned char) into output (UINT4). Assumes len is
+ a multiple of 4.
+ */
+static void Decode (output, input, len)
+UINT4 *output;
+unsigned char *input;
+unsigned int len;
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4)
+ output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
+ (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
+}
+
+/* Note: Replace "for loop" with standard memcpy if possible.
+ */
+
+static void MD5_memcpy (output, input, len)
+POINTER output;
+POINTER input;
+unsigned int len;
+{
+ unsigned int i;
+
+ for (i = 0; i < len; i++)
+
+
+
+Rivest [Page 15]
+
+RFC 1321 MD5 Message-Digest Algorithm April 1992
+
+
+ output[i] = input[i];
+}
+
+/* Note: Replace "for loop" with standard memset if possible.
+ */
+static void MD5_memset (output, value, len)
+POINTER output;
+int value;
+unsigned int len;
+{
+ unsigned int i;
+
+ for (i = 0; i < len; i++)
+ ((char *)output)[i] = (char)value;
+}
+
+A.4 mddriver.c
+
+/* MDDRIVER.C - test driver for MD2, MD4 and MD5
+ */
+
+/* Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All
+rights reserved.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+/* The following makes MD default to MD5 if it has not already been
+ defined with C compiler flags.
+ */
+#ifndef MD
+#define MD MD5
+#endif
+
+#include <stdio.h>
+#include <time.h>
+#include <string.h>
+#include "global.h"
+#if MD == 2
+#include "md2.h"
+#endif
+#if MD == 4
+
+
+
+Rivest [Page 16]
+
+RFC 1321 MD5 Message-Digest Algorithm April 1992
+
+
+#include "md4.h"
+#endif
+#if MD == 5
+#include "md5.h"
+#endif
+
+/* Length of test block, number of test blocks.
+ */
+#define TEST_BLOCK_LEN 1000
+#define TEST_BLOCK_COUNT 1000
+
+static void MDString PROTO_LIST ((char *));
+static void MDTimeTrial PROTO_LIST ((void));
+static void MDTestSuite PROTO_LIST ((void));
+static void MDFile PROTO_LIST ((char *));
+static void MDFilter PROTO_LIST ((void));
+static void MDPrint PROTO_LIST ((unsigned char [16]));
+
+#if MD == 2
+#define MD_CTX MD2_CTX
+#define MDInit MD2Init
+#define MDUpdate MD2Update
+#define MDFinal MD2Final
+#endif
+#if MD == 4
+#define MD_CTX MD4_CTX
+#define MDInit MD4Init
+#define MDUpdate MD4Update
+#define MDFinal MD4Final
+#endif
+#if MD == 5
+#define MD_CTX MD5_CTX
+#define MDInit MD5Init
+#define MDUpdate MD5Update
+#define MDFinal MD5Final
+#endif
+
+/* Main driver.
+
+Arguments (may be any combination):
+ -sstring - digests string
+ -t - runs time trial
+ -x - runs test script
+ filename - digests file
+ (none) - digests standard input
+ */
+int main (argc, argv)
+int argc;
+
+
+
+Rivest [Page 17]
+
+RFC 1321 MD5 Message-Digest Algorithm April 1992
+
+
+char *argv[];
+{
+ int i;
+
+ if (argc > 1)
+ for (i = 1; i < argc; i++)
+ if (argv[i][0] == '-' && argv[i][1] == 's')
+ MDString (argv[i] + 2);
+ else if (strcmp (argv[i], "-t") == 0)
+ MDTimeTrial ();
+ else if (strcmp (argv[i], "-x") == 0)
+ MDTestSuite ();
+ else
+ MDFile (argv[i]);
+ else
+ MDFilter ();
+
+ return (0);
+}
+
+/* Digests a string and prints the result.
+ */
+static void MDString (string)
+char *string;
+{
+ MD_CTX context;
+ unsigned char digest[16];
+ unsigned int len = strlen (string);
+
+ MDInit (&context);
+ MDUpdate (&context, string, len);
+ MDFinal (digest, &context);
+
+ printf ("MD%d (\"%s\") = ", MD, string);
+ MDPrint (digest);
+ printf ("\n");
+}
+
+/* Measures the time to digest TEST_BLOCK_COUNT TEST_BLOCK_LEN-byte
+ blocks.
+ */
+static void MDTimeTrial ()
+{
+ MD_CTX context;
+ time_t endTime, startTime;
+ unsigned char block[TEST_BLOCK_LEN], digest[16];
+ unsigned int i;
+
+
+
+
+Rivest [Page 18]
+
+RFC 1321 MD5 Message-Digest Algorithm April 1992
+
+
+ printf
+ ("MD%d time trial. Digesting %d %d-byte blocks ...", MD,
+ TEST_BLOCK_LEN, TEST_BLOCK_COUNT);
+
+ /* Initialize block */
+ for (i = 0; i < TEST_BLOCK_LEN; i++)
+ block[i] = (unsigned char)(i & 0xff);
+
+ /* Start timer */
+ time (&startTime);
+
+ /* Digest blocks */
+ MDInit (&context);
+ for (i = 0; i < TEST_BLOCK_COUNT; i++)
+ MDUpdate (&context, block, TEST_BLOCK_LEN);
+ MDFinal (digest, &context);
+
+ /* Stop timer */
+ time (&endTime);
+
+ printf (" done\n");
+ printf ("Digest = ");
+ MDPrint (digest);
+ printf ("\nTime = %ld seconds\n", (long)(endTime-startTime));
+ printf
+ ("Speed = %ld bytes/second\n",
+ (long)TEST_BLOCK_LEN * (long)TEST_BLOCK_COUNT/(endTime-startTime));
+}
+
+/* Digests a reference suite of strings and prints the results.
+ */
+static void MDTestSuite ()
+{
+ printf ("MD%d test suite:\n", MD);
+
+ MDString ("");
+ MDString ("a");
+ MDString ("abc");
+ MDString ("message digest");
+ MDString ("abcdefghijklmnopqrstuvwxyz");
+ MDString
+ ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
+ MDString
+ ("1234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890");
+}
+
+/* Digests a file and prints the result.
+
+
+
+Rivest [Page 19]
+
+RFC 1321 MD5 Message-Digest Algorithm April 1992
+
+
+ */
+static void MDFile (filename)
+char *filename;
+{
+ FILE *file;
+ MD_CTX context;
+ int len;
+ unsigned char buffer[1024], digest[16];
+
+ if ((file = fopen (filename, "rb")) == NULL)
+ printf ("%s can't be opened\n", filename);
+
+ else {
+ MDInit (&context);
+ while (len = fread (buffer, 1, 1024, file))
+ MDUpdate (&context, buffer, len);
+ MDFinal (digest, &context);
+
+ fclose (file);
+
+ printf ("MD%d (%s) = ", MD, filename);
+ MDPrint (digest);
+ printf ("\n");
+ }
+}
+
+/* Digests the standard input and prints the result.
+ */
+static void MDFilter ()
+{
+ MD_CTX context;
+ int len;
+ unsigned char buffer[16], digest[16];
+
+ MDInit (&context);
+ while (len = fread (buffer, 1, 16, stdin))
+ MDUpdate (&context, buffer, len);
+ MDFinal (digest, &context);
+
+ MDPrint (digest);
+ printf ("\n");
+}
+
+/* Prints a message digest in hexadecimal.
+ */
+static void MDPrint (digest)
+unsigned char digest[16];
+{
+
+
+
+Rivest [Page 20]
+
+RFC 1321 MD5 Message-Digest Algorithm April 1992
+
+
+ unsigned int i;
+
+ for (i = 0; i < 16; i++)
+ printf ("%02x", digest[i]);
+}
+
+A.5 Test suite
+
+ The MD5 test suite (driver option "-x") should print the following
+ results:
+
+MD5 test suite:
+MD5 ("") = d41d8cd98f00b204e9800998ecf8427e
+MD5 ("a") = 0cc175b9c0f1b6a831c399e269772661
+MD5 ("abc") = 900150983cd24fb0d6963f7d28e17f72
+MD5 ("message digest") = f96b697d7cb7938d525a2f31aaf161d0
+MD5 ("abcdefghijklmnopqrstuvwxyz") = c3fcd3d76192e4007dfb496cca67e13b
+MD5 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") =
+d174ab98d277d9f5a5611c2c9f419d9f
+MD5 ("123456789012345678901234567890123456789012345678901234567890123456
+78901234567890") = 57edf4a22be3c955ac49da2e2107b67a
+
+Security Considerations
+
+ The level of security discussed in this memo is considered to be
+ sufficient for implementing very high security hybrid digital-
+ signature schemes based on MD5 and a public-key cryptosystem.
+
+Author's Address
+
+ Ronald L. Rivest
+ Massachusetts Institute of Technology
+ Laboratory for Computer Science
+ NE43-324
+ 545 Technology Square
+ Cambridge, MA 02139-1986
+
+ Phone: (617) 253-5880
+ EMail: rivest@theory.lcs.mit.edu
+
+
+
+
+
+
+
+
+
+
+
+
+Rivest [Page 21]
+ \ No newline at end of file
diff --git a/standards/rfc2246.txt b/standards/rfc2246.txt
new file mode 100644
index 000000000..2e838cf5d
--- /dev/null
+++ b/standards/rfc2246.txt
@@ -0,0 +1,4483 @@
+
+
+
+
+
+
+Network Working Group T. Dierks
+Request for Comments: 2246 Certicom
+Category: Standards Track C. Allen
+ Certicom
+ January 1999
+
+
+ The TLS Protocol
+ Version 1.0
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+Abstract
+
+ This document specifies Version 1.0 of the Transport Layer Security
+ (TLS) protocol. The TLS protocol provides communications privacy over
+ the Internet. The protocol allows client/server applications to
+ communicate in a way that is designed to prevent eavesdropping,
+ tampering, or message forgery.
+
+Table of Contents
+
+ 1. Introduction 3
+ 2. Goals 4
+ 3. Goals of this document 5
+ 4. Presentation language 5
+ 4.1. Basic block size 6
+ 4.2. Miscellaneous 6
+ 4.3. Vectors 6
+ 4.4. Numbers 7
+ 4.5. Enumerateds 7
+ 4.6. Constructed types 8
+ 4.6.1. Variants 9
+ 4.7. Cryptographic attributes 10
+ 4.8. Constants 11
+ 5. HMAC and the pseudorandom function 11
+ 6. The TLS Record Protocol 13
+ 6.1. Connection states 14
+
+
+
+Dierks & Allen Standards Track [Page 1]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ 6.2. Record layer 16
+ 6.2.1. Fragmentation 16
+ 6.2.2. Record compression and decompression 17
+ 6.2.3. Record payload protection 18
+ 6.2.3.1. Null or standard stream cipher 19
+ 6.2.3.2. CBC block cipher 19
+ 6.3. Key calculation 21
+ 6.3.1. Export key generation example 22
+ 7. The TLS Handshake Protocol 23
+ 7.1. Change cipher spec protocol 24
+ 7.2. Alert protocol 24
+ 7.2.1. Closure alerts 25
+ 7.2.2. Error alerts 26
+ 7.3. Handshake Protocol overview 29
+ 7.4. Handshake protocol 32
+ 7.4.1. Hello messages 33
+ 7.4.1.1. Hello request 33
+ 7.4.1.2. Client hello 34
+ 7.4.1.3. Server hello 36
+ 7.4.2. Server certificate 37
+ 7.4.3. Server key exchange message 39
+ 7.4.4. Certificate request 41
+ 7.4.5. Server hello done 42
+ 7.4.6. Client certificate 43
+ 7.4.7. Client key exchange message 43
+ 7.4.7.1. RSA encrypted premaster secret message 44
+ 7.4.7.2. Client Diffie-Hellman public value 45
+ 7.4.8. Certificate verify 45
+ 7.4.9. Finished 46
+ 8. Cryptographic computations 47
+ 8.1. Computing the master secret 47
+ 8.1.1. RSA 48
+ 8.1.2. Diffie-Hellman 48
+ 9. Mandatory Cipher Suites 48
+ 10. Application data protocol 48
+ A. Protocol constant values 49
+ A.1. Record layer 49
+ A.2. Change cipher specs message 50
+ A.3. Alert messages 50
+ A.4. Handshake protocol 51
+ A.4.1. Hello messages 51
+ A.4.2. Server authentication and key exchange messages 52
+ A.4.3. Client authentication and key exchange messages 53
+ A.4.4. Handshake finalization message 54
+ A.5. The CipherSuite 54
+ A.6. The Security Parameters 56
+ B. Glossary 57
+ C. CipherSuite definitions 61
+
+
+
+Dierks & Allen Standards Track [Page 2]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ D. Implementation Notes 64
+ D.1. Temporary RSA keys 64
+ D.2. Random Number Generation and Seeding 64
+ D.3. Certificates and authentication 65
+ D.4. CipherSuites 65
+ E. Backward Compatibility With SSL 66
+ E.1. Version 2 client hello 67
+ E.2. Avoiding man-in-the-middle version rollback 68
+ F. Security analysis 69
+ F.1. Handshake protocol 69
+ F.1.1. Authentication and key exchange 69
+ F.1.1.1. Anonymous key exchange 69
+ F.1.1.2. RSA key exchange and authentication 70
+ F.1.1.3. Diffie-Hellman key exchange with authentication 71
+ F.1.2. Version rollback attacks 71
+ F.1.3. Detecting attacks against the handshake protocol 72
+ F.1.4. Resuming sessions 72
+ F.1.5. MD5 and SHA 72
+ F.2. Protecting application data 72
+ F.3. Final notes 73
+ G. Patent Statement 74
+ Security Considerations 75
+ References 75
+ Credits 77
+ Comments 78
+ Full Copyright Statement 80
+
+1. Introduction
+
+ The primary goal of the TLS Protocol is to provide privacy and data
+ integrity between two communicating applications. The protocol is
+ composed of two layers: the TLS Record Protocol and the TLS Handshake
+ Protocol. At the lowest level, layered on top of some reliable
+ transport protocol (e.g., TCP[TCP]), is the TLS Record Protocol. The
+ TLS Record Protocol provides connection security that has two basic
+ properties:
+
+ - The connection is private. Symmetric cryptography is used for
+ data encryption (e.g., DES [DES], RC4 [RC4], etc.) The keys for
+ this symmetric encryption are generated uniquely for each
+ connection and are based on a secret negotiated by another
+ protocol (such as the TLS Handshake Protocol). The Record
+ Protocol can also be used without encryption.
+
+ - The connection is reliable. Message transport includes a message
+ integrity check using a keyed MAC. Secure hash functions (e.g.,
+ SHA, MD5, etc.) are used for MAC computations. The Record
+ Protocol can operate without a MAC, but is generally only used in
+
+
+
+Dierks & Allen Standards Track [Page 3]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ this mode while another protocol is using the Record Protocol as
+ a transport for negotiating security parameters.
+
+ The TLS Record Protocol is used for encapsulation of various higher
+ level protocols. One such encapsulated protocol, the TLS Handshake
+ Protocol, allows the server and client to authenticate each other and
+ to negotiate an encryption algorithm and cryptographic keys before
+ the application protocol transmits or receives its first byte of
+ data. The TLS Handshake Protocol provides connection security that
+ has three basic properties:
+
+ - The peer's identity can be authenticated using asymmetric, or
+ public key, cryptography (e.g., RSA [RSA], DSS [DSS], etc.). This
+ authentication can be made optional, but is generally required
+ for at least one of the peers.
+
+ - The negotiation of a shared secret is secure: the negotiated
+ secret is unavailable to eavesdroppers, and for any authenticated
+ connection the secret cannot be obtained, even by an attacker who
+ can place himself in the middle of the connection.
+
+ - The negotiation is reliable: no attacker can modify the
+ negotiation communication without being detected by the parties
+ to the communication.
+
+ One advantage of TLS is that it is application protocol independent.
+ Higher level protocols can layer on top of the TLS Protocol
+ transparently. The TLS standard, however, does not specify how
+ protocols add security with TLS; the decisions on how to initiate TLS
+ handshaking and how to interpret the authentication certificates
+ exchanged are left up to the judgment of the designers and
+ implementors of protocols which run on top of TLS.
+
+2. Goals
+
+ The goals of TLS Protocol, in order of their priority, are:
+
+ 1. Cryptographic security: TLS should be used to establish a secure
+ connection between two parties.
+
+ 2. Interoperability: Independent programmers should be able to
+ develop applications utilizing TLS that will then be able to
+ successfully exchange cryptographic parameters without knowledge
+ of one another's code.
+
+ 3. Extensibility: TLS seeks to provide a framework into which new
+ public key and bulk encryption methods can be incorporated as
+ necessary. This will also accomplish two sub-goals: to prevent
+
+
+
+Dierks & Allen Standards Track [Page 4]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ the need to create a new protocol (and risking the introduction
+ of possible new weaknesses) and to avoid the need to implement an
+ entire new security library.
+
+ 4. Relative efficiency: Cryptographic operations tend to be highly
+ CPU intensive, particularly public key operations. For this
+ reason, the TLS protocol has incorporated an optional session
+ caching scheme to reduce the number of connections that need to
+ be established from scratch. Additionally, care has been taken to
+ reduce network activity.
+
+3. Goals of this document
+
+ This document and the TLS protocol itself are based on the SSL 3.0
+ Protocol Specification as published by Netscape. The differences
+ between this protocol and SSL 3.0 are not dramatic, but they are
+ significant enough that TLS 1.0 and SSL 3.0 do not interoperate
+ (although TLS 1.0 does incorporate a mechanism by which a TLS
+ implementation can back down to SSL 3.0). This document is intended
+ primarily for readers who will be implementing the protocol and those
+ doing cryptographic analysis of it. The specification has been
+ written with this in mind, and it is intended to reflect the needs of
+ those two groups. For that reason, many of the algorithm-dependent
+ data structures and rules are included in the body of the text (as
+ opposed to in an appendix), providing easier access to them.
+
+ This document is not intended to supply any details of service
+ definition nor interface definition, although it does cover select
+ areas of policy as they are required for the maintenance of solid
+ security.
+
+4. Presentation language
+
+ This document deals with the formatting of data in an external
+ representation. The following very basic and somewhat casually
+ defined presentation syntax will be used. The syntax draws from
+ several sources in its structure. Although it resembles the
+ programming language "C" in its syntax and XDR [XDR] in both its
+ syntax and intent, it would be risky to draw too many parallels. The
+ purpose of this presentation language is to document TLS only, not to
+ have general application beyond that particular goal.
+
+
+
+
+
+
+
+
+
+
+Dierks & Allen Standards Track [Page 5]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+4.1. Basic block size
+
+ The representation of all data items is explicitly specified. The
+ basic data block size is one byte (i.e. 8 bits). Multiple byte data
+ items are concatenations of bytes, from left to right, from top to
+ bottom. From the bytestream a multi-byte item (a numeric in the
+ example) is formed (using C notation) by:
+
+ value = (byte[0] << 8*(n-1)) | (byte[1] << 8*(n-2)) |
+ ... | byte[n-1];
+
+ This byte ordering for multi-byte values is the commonplace network
+ byte order or big endian format.
+
+4.2. Miscellaneous
+
+ Comments begin with "/*" and end with "*/".
+
+ Optional components are denoted by enclosing them in "[[ ]]" double
+ brackets.
+
+ Single byte entities containing uninterpreted data are of type
+ opaque.
+
+4.3. Vectors
+
+ A vector (single dimensioned array) is a stream of homogeneous data
+ elements. The size of the vector may be specified at documentation
+ time or left unspecified until runtime. In either case the length
+ declares the number of bytes, not the number of elements, in the
+ vector. The syntax for specifying a new type T' that is a fixed
+ length vector of type T is
+
+ T T'[n];
+
+ Here T' occupies n bytes in the data stream, where n is a multiple of
+ the size of T. The length of the vector is not included in the
+ encoded stream.
+
+ In the following example, Datum is defined to be three consecutive
+ bytes that the protocol does not interpret, while Data is three
+ consecutive Datum, consuming a total of nine bytes.
+
+ opaque Datum[3]; /* three uninterpreted bytes */
+ Datum Data[9]; /* 3 consecutive 3 byte vectors */
+
+
+
+
+
+
+Dierks & Allen Standards Track [Page 6]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ Variable length vectors are defined by specifying a subrange of legal
+ lengths, inclusively, using the notation <floor..ceiling>. When
+ encoded, the actual length precedes the vector's contents in the byte
+ stream. The length will be in the form of a number consuming as many
+ bytes as required to hold the vector's specified maximum (ceiling)
+ length. A variable length vector with an actual length field of zero
+ is referred to as an empty vector.
+
+ T T'<floor..ceiling>;
+
+ In the following example, mandatory is a vector that must contain
+ between 300 and 400 bytes of type opaque. It can never be empty. The
+ actual length field consumes two bytes, a uint16, sufficient to
+ represent the value 400 (see Section 4.4). On the other hand, longer
+ can represent up to 800 bytes of data, or 400 uint16 elements, and it
+ may be empty. Its encoding will include a two byte actual length
+ field prepended to the vector. The length of an encoded vector must
+ be an even multiple of the length of a single element (for example, a
+ 17 byte vector of uint16 would be illegal).
+
+ opaque mandatory<300..400>;
+ /* length field is 2 bytes, cannot be empty */
+ uint16 longer<0..800>;
+ /* zero to 400 16-bit unsigned integers */
+
+4.4. Numbers
+
+ The basic numeric data type is an unsigned byte (uint8). All larger
+ numeric data types are formed from fixed length series of bytes
+ concatenated as described in Section 4.1 and are also unsigned. The
+ following numeric types are predefined.
+
+ uint8 uint16[2];
+ uint8 uint24[3];
+ uint8 uint32[4];
+ uint8 uint64[8];
+
+ All values, here and elsewhere in the specification, are stored in
+ "network" or "big-endian" order; the uint32 represented by the hex
+ bytes 01 02 03 04 is equivalent to the decimal value 16909060.
+
+4.5. Enumerateds
+
+ An additional sparse data type is available called enum. A field of
+ type enum can only assume the values declared in the definition.
+ Each definition is a different type. Only enumerateds of the same
+ type may be assigned or compared. Every element of an enumerated must
+
+
+
+
+Dierks & Allen Standards Track [Page 7]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ be assigned a value, as demonstrated in the following example. Since
+ the elements of the enumerated are not ordered, they can be assigned
+ any unique value, in any order.
+
+ enum { e1(v1), e2(v2), ... , en(vn) [[, (n)]] } Te;
+
+ Enumerateds occupy as much space in the byte stream as would its
+ maximal defined ordinal value. The following definition would cause
+ one byte to be used to carry fields of type Color.
+
+ enum { red(3), blue(5), white(7) } Color;
+
+ One may optionally specify a value without its associated tag to
+ force the width definition without defining a superfluous element.
+ In the following example, Taste will consume two bytes in the data
+ stream but can only assume the values 1, 2 or 4.
+
+ enum { sweet(1), sour(2), bitter(4), (32000) } Taste;
+
+ The names of the elements of an enumeration are scoped within the
+ defined type. In the first example, a fully qualified reference to
+ the second element of the enumeration would be Color.blue. Such
+ qualification is not required if the target of the assignment is well
+ specified.
+
+ Color color = Color.blue; /* overspecified, legal */
+ Color color = blue; /* correct, type implicit */
+
+ For enumerateds that are never converted to external representation,
+ the numerical information may be omitted.
+
+ enum { low, medium, high } Amount;
+
+4.6. Constructed types
+
+ Structure types may be constructed from primitive types for
+ convenience. Each specification declares a new, unique type. The
+ syntax for definition is much like that of C.
+
+ struct {
+ T1 f1;
+ T2 f2;
+ ...
+ Tn fn;
+ } [[T]];
+
+
+
+
+
+
+Dierks & Allen Standards Track [Page 8]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ The fields within a structure may be qualified using the type's name
+ using a syntax much like that available for enumerateds. For example,
+ T.f2 refers to the second field of the previous declaration.
+ Structure definitions may be embedded.
+
+4.6.1. Variants
+
+ Defined structures may have variants based on some knowledge that is
+ available within the environment. The selector must be an enumerated
+ type that defines the possible variants the structure defines. There
+ must be a case arm for every element of the enumeration declared in
+ the select. The body of the variant structure may be given a label
+ for reference. The mechanism by which the variant is selected at
+ runtime is not prescribed by the presentation language.
+
+ struct {
+ T1 f1;
+ T2 f2;
+ ....
+ Tn fn;
+ select (E) {
+ case e1: Te1;
+ case e2: Te2;
+ ....
+ case en: Ten;
+ } [[fv]];
+ } [[Tv]];
+
+ For example:
+
+ enum { apple, orange } VariantTag;
+ struct {
+ uint16 number;
+ opaque string<0..10>; /* variable length */
+ } V1;
+ struct {
+ uint32 number;
+ opaque string[10]; /* fixed length */
+ } V2;
+ struct {
+ select (VariantTag) { /* value of selector is implicit */
+ case apple: V1; /* VariantBody, tag = apple */
+ case orange: V2; /* VariantBody, tag = orange */
+ } variant_body; /* optional label on variant */
+ } VariantRecord;
+
+ Variant structures may be qualified (narrowed) by specifying a value
+ for the selector prior to the type. For example, a
+
+
+
+Dierks & Allen Standards Track [Page 9]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ orange VariantRecord
+
+ is a narrowed type of a VariantRecord containing a variant_body of
+ type V2.
+
+4.7. Cryptographic attributes
+
+ The four cryptographic operations digital signing, stream cipher
+ encryption, block cipher encryption, and public key encryption are
+ designated digitally-signed, stream-ciphered, block-ciphered, and
+ public-key-encrypted, respectively. A field's cryptographic
+ processing is specified by prepending an appropriate key word
+ designation before the field's type specification. Cryptographic keys
+ are implied by the current session state (see Section 6.1).
+
+ In digital signing, one-way hash functions are used as input for a
+ signing algorithm. A digitally-signed element is encoded as an opaque
+ vector <0..2^16-1>, where the length is specified by the signing
+ algorithm and key.
+
+ In RSA signing, a 36-byte structure of two hashes (one SHA and one
+ MD5) is signed (encrypted with the private key). It is encoded with
+ PKCS #1 block type 0 or type 1 as described in [PKCS1].
+
+ In DSS, the 20 bytes of the SHA hash are run directly through the
+ Digital Signing Algorithm with no additional hashing. This produces
+ two values, r and s. The DSS signature is an opaque vector, as above,
+ the contents of which are the DER encoding of:
+
+ Dss-Sig-Value ::= SEQUENCE {
+ r INTEGER,
+ s INTEGER
+ }
+
+ In stream cipher encryption, the plaintext is exclusive-ORed with an
+ identical amount of output generated from a cryptographically-secure
+ keyed pseudorandom number generator.
+
+ In block cipher encryption, every block of plaintext encrypts to a
+ block of ciphertext. All block cipher encryption is done in CBC
+ (Cipher Block Chaining) mode, and all items which are block-ciphered
+ will be an exact multiple of the cipher block length.
+
+ In public key encryption, a public key algorithm is used to encrypt
+ data in such a way that it can be decrypted only with the matching
+ private key. A public-key-encrypted element is encoded as an opaque
+ vector <0..2^16-1>, where the length is specified by the signing
+ algorithm and key.
+
+
+
+Dierks & Allen Standards Track [Page 10]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ An RSA encrypted value is encoded with PKCS #1 block type 2 as
+ described in [PKCS1].
+
+ In the following example:
+
+ stream-ciphered struct {
+ uint8 field1;
+ uint8 field2;
+ digitally-signed opaque hash[20];
+ } UserType;
+
+ The contents of hash are used as input for the signing algorithm,
+ then the entire structure is encrypted with a stream cipher. The
+ length of this structure, in bytes would be equal to 2 bytes for
+ field1 and field2, plus two bytes for the length of the signature,
+ plus the length of the output of the signing algorithm. This is known
+ due to the fact that the algorithm and key used for the signing are
+ known prior to encoding or decoding this structure.
+
+4.8. Constants
+
+ Typed constants can be defined for purposes of specification by
+ declaring a symbol of the desired type and assigning values to it.
+ Under-specified types (opaque, variable length vectors, and
+ structures that contain opaque) cannot be assigned values. No fields
+ of a multi-element structure or vector may be elided.
+
+ For example,
+
+ struct {
+ uint8 f1;
+ uint8 f2;
+ } Example1;
+
+ Example1 ex1 = {1, 4}; /* assigns f1 = 1, f2 = 4 */
+
+5. HMAC and the pseudorandom function
+
+ A number of operations in the TLS record and handshake layer required
+ a keyed MAC; this is a secure digest of some data protected by a
+ secret. Forging the MAC is infeasible without knowledge of the MAC
+ secret. The construction we use for this operation is known as HMAC,
+ described in [HMAC].
+
+ HMAC can be used with a variety of different hash algorithms. TLS
+ uses it in the handshake with two different algorithms: MD5 and SHA-
+ 1, denoting these as HMAC_MD5(secret, data) and HMAC_SHA(secret,
+
+
+
+
+Dierks & Allen Standards Track [Page 11]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ data). Additional hash algorithms can be defined by cipher suites and
+ used to protect record data, but MD5 and SHA-1 are hard coded into
+ the description of the handshaking for this version of the protocol.
+
+ In addition, a construction is required to do expansion of secrets
+ into blocks of data for the purposes of key generation or validation.
+ This pseudo-random function (PRF) takes as input a secret, a seed,
+ and an identifying label and produces an output of arbitrary length.
+
+ In order to make the PRF as secure as possible, it uses two hash
+ algorithms in a way which should guarantee its security if either
+ algorithm remains secure.
+
+ First, we define a data expansion function, P_hash(secret, data)
+ which uses a single hash function to expand a secret and seed into an
+ arbitrary quantity of output:
+
+ P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) +
+ HMAC_hash(secret, A(2) + seed) +
+ HMAC_hash(secret, A(3) + seed) + ...
+
+ Where + indicates concatenation.
+
+ A() is defined as:
+ A(0) = seed
+ A(i) = HMAC_hash(secret, A(i-1))
+
+ P_hash can be iterated as many times as is necessary to produce the
+ required quantity of data. For example, if P_SHA-1 was being used to
+ create 64 bytes of data, it would have to be iterated 4 times
+ (through A(4)), creating 80 bytes of output data; the last 16 bytes
+ of the final iteration would then be discarded, leaving 64 bytes of
+ output data.
+
+ TLS's PRF is created by splitting the secret into two halves and
+ using one half to generate data with P_MD5 and the other half to
+ generate data with P_SHA-1, then exclusive-or'ing the outputs of
+ these two expansion functions together.
+
+ S1 and S2 are the two halves of the secret and each is the same
+ length. S1 is taken from the first half of the secret, S2 from the
+ second half. Their length is created by rounding up the length of the
+ overall secret divided by two; thus, if the original secret is an odd
+ number of bytes long, the last byte of S1 will be the same as the
+ first byte of S2.
+
+ L_S = length in bytes of secret;
+ L_S1 = L_S2 = ceil(L_S / 2);
+
+
+
+Dierks & Allen Standards Track [Page 12]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ The secret is partitioned into two halves (with the possibility of
+ one shared byte) as described above, S1 taking the first L_S1 bytes
+ and S2 the last L_S2 bytes.
+
+ The PRF is then defined as the result of mixing the two pseudorandom
+ streams by exclusive-or'ing them together.
+
+ PRF(secret, label, seed) = P_MD5(S1, label + seed) XOR
+ P_SHA-1(S2, label + seed);
+
+ The label is an ASCII string. It should be included in the exact form
+ it is given without a length byte or trailing null character. For
+ example, the label "slithy toves" would be processed by hashing the
+ following bytes:
+
+ 73 6C 69 74 68 79 20 74 6F 76 65 73
+
+ Note that because MD5 produces 16 byte outputs and SHA-1 produces 20
+ byte outputs, the boundaries of their internal iterations will not be
+ aligned; to generate a 80 byte output will involve P_MD5 being
+ iterated through A(5), while P_SHA-1 will only iterate through A(4).
+
+6. The TLS Record Protocol
+
+ The TLS Record Protocol is a layered protocol. At each layer,
+ messages may include fields for length, description, and content.
+ The Record Protocol takes messages to be transmitted, fragments the
+ data into manageable blocks, optionally compresses the data, applies
+ a MAC, encrypts, and transmits the result. Received data is
+ decrypted, verified, decompressed, and reassembled, then delivered to
+ higher level clients.
+
+ Four record protocol clients are described in this document: the
+ handshake protocol, the alert protocol, the change cipher spec
+ protocol, and the application data protocol. In order to allow
+ extension of the TLS protocol, additional record types can be
+ supported by the record protocol. Any new record types should
+ allocate type values immediately beyond the ContentType values for
+ the four record types described here (see Appendix A.2). If a TLS
+ implementation receives a record type it does not understand, it
+ should just ignore it. Any protocol designed for use over TLS must be
+ carefully designed to deal with all possible attacks against it.
+ Note that because the type and length of a record are not protected
+ by encryption, care should be take to minimize the value of traffic
+ analysis of these values.
+
+
+
+
+
+
+Dierks & Allen Standards Track [Page 13]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+6.1. Connection states
+
+ A TLS connection state is the operating environment of the TLS Record
+ Protocol. It specifies a compression algorithm, encryption algorithm,
+ and MAC algorithm. In addition, the parameters for these algorithms
+ are known: the MAC secret and the bulk encryption keys and IVs for
+ the connection in both the read and the write directions. Logically,
+ there are always four connection states outstanding: the current read
+ and write states, and the pending read and write states. All records
+ are processed under the current read and write states. The security
+ parameters for the pending states can be set by the TLS Handshake
+ Protocol, and the Handshake Protocol can selectively make either of
+ the pending states current, in which case the appropriate current
+ state is disposed of and replaced with the pending state; the pending
+ state is then reinitialized to an empty state. It is illegal to make
+ a state which has not been initialized with security parameters a
+ current state. The initial current state always specifies that no
+ encryption, compression, or MAC will be used.
+
+ The security parameters for a TLS Connection read and write state are
+ set by providing the following values:
+
+ connection end
+ Whether this entity is considered the "client" or the "server" in
+ this connection.
+
+ bulk encryption algorithm
+ An algorithm to be used for bulk encryption. This specification
+ includes the key size of this algorithm, how much of that key is
+ secret, whether it is a block or stream cipher, the block size of
+ the cipher (if appropriate), and whether it is considered an
+ "export" cipher.
+
+ MAC algorithm
+ An algorithm to be used for message authentication. This
+ specification includes the size of the hash which is returned by
+ the MAC algorithm.
+
+ compression algorithm
+ An algorithm to be used for data compression. This specification
+ must include all information the algorithm requires to do
+ compression.
+
+ master secret
+ A 48 byte secret shared between the two peers in the connection.
+
+ client random
+ A 32 byte value provided by the client.
+
+
+
+Dierks & Allen Standards Track [Page 14]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ server random
+ A 32 byte value provided by the server.
+
+ These parameters are defined in the presentation language as:
+
+ enum { server, client } ConnectionEnd;
+
+ enum { null, rc4, rc2, des, 3des, des40 } BulkCipherAlgorithm;
+
+ enum { stream, block } CipherType;
+
+ enum { true, false } IsExportable;
+
+ enum { null, md5, sha } MACAlgorithm;
+
+ enum { null(0), (255) } CompressionMethod;
+
+ /* The algorithms specified in CompressionMethod,
+ BulkCipherAlgorithm, and MACAlgorithm may be added to. */
+
+ struct {
+ ConnectionEnd entity;
+ BulkCipherAlgorithm bulk_cipher_algorithm;
+ CipherType cipher_type;
+ uint8 key_size;
+ uint8 key_material_length;
+ IsExportable is_exportable;
+ MACAlgorithm mac_algorithm;
+ uint8 hash_size;
+ CompressionMethod compression_algorithm;
+ opaque master_secret[48];
+ opaque client_random[32];
+ opaque server_random[32];
+ } SecurityParameters;
+
+ The record layer will use the security parameters to generate the
+ following six items:
+
+ client write MAC secret
+ server write MAC secret
+ client write key
+ server write key
+ client write IV (for block ciphers only)
+ server write IV (for block ciphers only)
+
+ The client write parameters are used by the server when receiving and
+ processing records and vice-versa. The algorithm used for generating
+ these items from the security parameters is described in section 6.3.
+
+
+
+Dierks & Allen Standards Track [Page 15]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ Once the security parameters have been set and the keys have been
+ generated, the connection states can be instantiated by making them
+ the current states. These current states must be updated for each
+ record processed. Each connection state includes the following
+ elements:
+
+ compression state
+ The current state of the compression algorithm.
+
+ cipher state
+ The current state of the encryption algorithm. This will consist
+ of the scheduled key for that connection. In addition, for block
+ ciphers running in CBC mode (the only mode specified for TLS),
+ this will initially contain the IV for that connection state and
+ be updated to contain the ciphertext of the last block encrypted
+ or decrypted as records are processed. For stream ciphers, this
+ will contain whatever the necessary state information is to allow
+ the stream to continue to encrypt or decrypt data.
+
+ MAC secret
+ The MAC secret for this connection as generated above.
+
+ sequence number
+ Each connection state contains a sequence number, which is
+ maintained separately for read and write states. The sequence
+ number must be set to zero whenever a connection state is made
+ the active state. Sequence numbers are of type uint64 and may not
+ exceed 2^64-1. A sequence number is incremented after each
+ record: specifically, the first record which is transmitted under
+ a particular connection state should use sequence number 0.
+
+6.2. Record layer
+
+ The TLS Record Layer receives uninterpreted data from higher layers
+ in non-empty blocks of arbitrary size.
+
+6.2.1. Fragmentation
+
+ The record layer fragments information blocks into TLSPlaintext
+ records carrying data in chunks of 2^14 bytes or less. Client message
+ boundaries are not preserved in the record layer (i.e., multiple
+ client messages of the same ContentType may be coalesced into a
+ single TLSPlaintext record, or a single message may be fragmented
+ across several records).
+
+ struct {
+ uint8 major, minor;
+ } ProtocolVersion;
+
+
+
+Dierks & Allen Standards Track [Page 16]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ enum {
+ change_cipher_spec(20), alert(21), handshake(22),
+ application_data(23), (255)
+ } ContentType;
+
+ struct {
+ ContentType type;
+ ProtocolVersion version;
+ uint16 length;
+ opaque fragment[TLSPlaintext.length];
+ } TLSPlaintext;
+
+ type
+ The higher level protocol used to process the enclosed fragment.
+
+ version
+ The version of the protocol being employed. This document
+ describes TLS Version 1.0, which uses the version { 3, 1 }. The
+ version value 3.1 is historical: TLS version 1.0 is a minor
+ modification to the SSL 3.0 protocol, which bears the version
+ value 3.0. (See Appendix A.1).
+
+ length
+ The length (in bytes) of the following TLSPlaintext.fragment.
+ The length should not exceed 2^14.
+
+ fragment
+ The application data. This data is transparent and treated as an
+ independent block to be dealt with by the higher level protocol
+ specified by the type field.
+
+ Note: Data of different TLS Record layer content types may be
+ interleaved. Application data is generally of lower precedence
+ for transmission than other content types.
+
+6.2.2. Record compression and decompression
+
+ All records are compressed using the compression algorithm defined in
+ the current session state. There is always an active compression
+ algorithm; however, initially it is defined as
+ CompressionMethod.null. The compression algorithm translates a
+ TLSPlaintext structure into a TLSCompressed structure. Compression
+ functions are initialized with default state information whenever a
+ connection state is made active.
+
+
+
+
+
+
+
+Dierks & Allen Standards Track [Page 17]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ Compression must be lossless and may not increase the content length
+ by more than 1024 bytes. If the decompression function encounters a
+ TLSCompressed.fragment that would decompress to a length in excess of
+ 2^14 bytes, it should report a fatal decompression failure error.
+
+ struct {
+ ContentType type; /* same as TLSPlaintext.type */
+ ProtocolVersion version;/* same as TLSPlaintext.version */
+ uint16 length;
+ opaque fragment[TLSCompressed.length];
+ } TLSCompressed;
+
+ length
+ The length (in bytes) of the following TLSCompressed.fragment.
+ The length should not exceed 2^14 + 1024.
+
+ fragment
+ The compressed form of TLSPlaintext.fragment.
+
+ Note: A CompressionMethod.null operation is an identity operation; no
+ fields are altered.
+
+ Implementation note:
+ Decompression functions are responsible for ensuring that
+ messages cannot cause internal buffer overflows.
+
+6.2.3. Record payload protection
+
+ The encryption and MAC functions translate a TLSCompressed structure
+ into a TLSCiphertext. The decryption functions reverse the process.
+ The MAC of the record also includes a sequence number so that
+ missing, extra or repeated messages are detectable.
+
+ struct {
+ ContentType type;
+ ProtocolVersion version;
+ uint16 length;
+ select (CipherSpec.cipher_type) {
+ case stream: GenericStreamCipher;
+ case block: GenericBlockCipher;
+ } fragment;
+ } TLSCiphertext;
+
+ type
+ The type field is identical to TLSCompressed.type.
+
+ version
+ The version field is identical to TLSCompressed.version.
+
+
+
+Dierks & Allen Standards Track [Page 18]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ length
+ The length (in bytes) of the following TLSCiphertext.fragment.
+ The length may not exceed 2^14 + 2048.
+
+ fragment
+ The encrypted form of TLSCompressed.fragment, with the MAC.
+
+6.2.3.1. Null or standard stream cipher
+
+ Stream ciphers (including BulkCipherAlgorithm.null - see Appendix
+ A.6) convert TLSCompressed.fragment structures to and from stream
+ TLSCiphertext.fragment structures.
+
+ stream-ciphered struct {
+ opaque content[TLSCompressed.length];
+ opaque MAC[CipherSpec.hash_size];
+ } GenericStreamCipher;
+
+ The MAC is generated as:
+
+ HMAC_hash(MAC_write_secret, seq_num + TLSCompressed.type +
+ TLSCompressed.version + TLSCompressed.length +
+ TLSCompressed.fragment));
+
+ where "+" denotes concatenation.
+
+ seq_num
+ The sequence number for this record.
+
+ hash
+ The hashing algorithm specified by
+ SecurityParameters.mac_algorithm.
+
+ Note that the MAC is computed before encryption. The stream cipher
+ encrypts the entire block, including the MAC. For stream ciphers that
+ do not use a synchronization vector (such as RC4), the stream cipher
+ state from the end of one record is simply used on the subsequent
+ packet. If the CipherSuite is TLS_NULL_WITH_NULL_NULL, encryption
+ consists of the identity operation (i.e., the data is not encrypted
+ and the MAC size is zero implying that no MAC is used).
+ TLSCiphertext.length is TLSCompressed.length plus
+ CipherSpec.hash_size.
+
+6.2.3.2. CBC block cipher
+
+ For block ciphers (such as RC2 or DES), the encryption and MAC
+ functions convert TLSCompressed.fragment structures to and from block
+ TLSCiphertext.fragment structures.
+
+
+
+Dierks & Allen Standards Track [Page 19]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ block-ciphered struct {
+ opaque content[TLSCompressed.length];
+ opaque MAC[CipherSpec.hash_size];
+ uint8 padding[GenericBlockCipher.padding_length];
+ uint8 padding_length;
+ } GenericBlockCipher;
+
+ The MAC is generated as described in Section 6.2.3.1.
+
+ padding
+ Padding that is added to force the length of the plaintext to be
+ an integral multiple of the block cipher's block length. The
+ padding may be any length up to 255 bytes long, as long as it
+ results in the TLSCiphertext.length being an integral multiple of
+ the block length. Lengths longer than necessary might be
+ desirable to frustrate attacks on a protocol based on analysis of
+ the lengths of exchanged messages. Each uint8 in the padding data
+ vector must be filled with the padding length value.
+
+ padding_length
+ The padding length should be such that the total size of the
+ GenericBlockCipher structure is a multiple of the cipher's block
+ length. Legal values range from zero to 255, inclusive. This
+ length specifies the length of the padding field exclusive of the
+ padding_length field itself.
+
+ The encrypted data length (TLSCiphertext.length) is one more than the
+ sum of TLSCompressed.length, CipherSpec.hash_size, and
+ padding_length.
+
+ Example: If the block length is 8 bytes, the content length
+ (TLSCompressed.length) is 61 bytes, and the MAC length is 20
+ bytes, the length before padding is 82 bytes. Thus, the
+ padding length modulo 8 must be equal to 6 in order to make
+ the total length an even multiple of 8 bytes (the block
+ length). The padding length can be 6, 14, 22, and so on,
+ through 254. If the padding length were the minimum necessary,
+ 6, the padding would be 6 bytes, each containing the value 6.
+ Thus, the last 8 octets of the GenericBlockCipher before block
+ encryption would be xx 06 06 06 06 06 06 06, where xx is the
+ last octet of the MAC.
+
+ Note: With block ciphers in CBC mode (Cipher Block Chaining) the
+ initialization vector (IV) for the first record is generated with
+ the other keys and secrets when the security parameters are set.
+ The IV for subsequent records is the last ciphertext block from
+ the previous record.
+
+
+
+
+Dierks & Allen Standards Track [Page 20]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+6.3. Key calculation
+
+ The Record Protocol requires an algorithm to generate keys, IVs, and
+ MAC secrets from the security parameters provided by the handshake
+ protocol.
+
+ The master secret is hashed into a sequence of secure bytes, which
+ are assigned to the MAC secrets, keys, and non-export IVs required by
+ the current connection state (see Appendix A.6). CipherSpecs require
+ a client write MAC secret, a server write MAC secret, a client write
+ key, a server write key, a client write IV, and a server write IV,
+ which are generated from the master secret in that order. Unused
+ values are empty.
+
+ When generating keys and MAC secrets, the master secret is used as an
+ entropy source, and the random values provide unencrypted salt
+ material and IVs for exportable ciphers.
+
+ To generate the key material, compute
+
+ key_block = PRF(SecurityParameters.master_secret,
+ "key expansion",
+ SecurityParameters.server_random +
+ SecurityParameters.client_random);
+
+ until enough output has been generated. Then the key_block is
+ partitioned as follows:
+
+ client_write_MAC_secret[SecurityParameters.hash_size]
+ server_write_MAC_secret[SecurityParameters.hash_size]
+ client_write_key[SecurityParameters.key_material_length]
+ server_write_key[SecurityParameters.key_material_length]
+ client_write_IV[SecurityParameters.IV_size]
+ server_write_IV[SecurityParameters.IV_size]
+
+ The client_write_IV and server_write_IV are only generated for non-
+ export block ciphers. For exportable block ciphers, the
+ initialization vectors are generated later, as described below. Any
+ extra key_block material is discarded.
+
+ Implementation note:
+ The cipher spec which is defined in this document which requires
+ the most material is 3DES_EDE_CBC_SHA: it requires 2 x 24 byte
+ keys, 2 x 20 byte MAC secrets, and 2 x 8 byte IVs, for a total of
+ 104 bytes of key material.
+
+
+
+
+
+
+Dierks & Allen Standards Track [Page 21]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ Exportable encryption algorithms (for which CipherSpec.is_exportable
+ is true) require additional processing as follows to derive their
+ final write keys:
+
+ final_client_write_key =
+ PRF(SecurityParameters.client_write_key,
+ "client write key",
+ SecurityParameters.client_random +
+ SecurityParameters.server_random);
+ final_server_write_key =
+ PRF(SecurityParameters.server_write_key,
+ "server write key",
+ SecurityParameters.client_random +
+ SecurityParameters.server_random);
+
+ Exportable encryption algorithms derive their IVs solely from the
+ random values from the hello messages:
+
+ iv_block = PRF("", "IV block", SecurityParameters.client_random +
+ SecurityParameters.server_random);
+
+ The iv_block is partitioned into two initialization vectors as the
+ key_block was above:
+
+ client_write_IV[SecurityParameters.IV_size]
+ server_write_IV[SecurityParameters.IV_size]
+
+ Note that the PRF is used without a secret in this case: this just
+ means that the secret has a length of zero bytes and contributes
+ nothing to the hashing in the PRF.
+
+6.3.1. Export key generation example
+
+ TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 requires five random bytes for
+ each of the two encryption keys and 16 bytes for each of the MAC
+ keys, for a total of 42 bytes of key material. The PRF output is
+ stored in the key_block. The key_block is partitioned, and the write
+ keys are salted because this is an exportable encryption algorithm.
+
+ key_block = PRF(master_secret,
+ "key expansion",
+ server_random +
+ client_random)[0..41]
+ client_write_MAC_secret = key_block[0..15]
+ server_write_MAC_secret = key_block[16..31]
+ client_write_key = key_block[32..36]
+ server_write_key = key_block[37..41]
+
+
+
+
+Dierks & Allen Standards Track [Page 22]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ final_client_write_key = PRF(client_write_key,
+ "client write key",
+ client_random +
+ server_random)[0..15]
+ final_server_write_key = PRF(server_write_key,
+ "server write key",
+ client_random +
+ server_random)[0..15]
+
+ iv_block = PRF("", "IV block", client_random +
+ server_random)[0..15]
+ client_write_IV = iv_block[0..7]
+ server_write_IV = iv_block[8..15]
+
+7. The TLS Handshake Protocol
+
+ The TLS Handshake Protocol consists of a suite of three sub-protocols
+ which are used to allow peers to agree upon security parameters for
+ the record layer, authenticate themselves, instantiate negotiated
+ security parameters, and report error conditions to each other.
+
+ The Handshake Protocol is responsible for negotiating a session,
+ which consists of the following items:
+
+ session identifier
+ An arbitrary byte sequence chosen by the server to identify an
+ active or resumable session state.
+
+ peer certificate
+ X509v3 [X509] certificate of the peer. This element of the state
+ may be null.
+
+ compression method
+ The algorithm used to compress data prior to encryption.
+
+ cipher spec
+ Specifies the bulk data encryption algorithm (such as null, DES,
+ etc.) and a MAC algorithm (such as MD5 or SHA). It also defines
+ cryptographic attributes such as the hash_size. (See Appendix A.6
+ for formal definition)
+
+ master secret
+ 48-byte secret shared between the client and server.
+
+ is resumable
+ A flag indicating whether the session can be used to initiate new
+ connections.
+
+
+
+
+Dierks & Allen Standards Track [Page 23]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ These items are then used to create security parameters for use by
+ the Record Layer when protecting application data. Many connections
+ can be instantiated using the same session through the resumption
+ feature of the TLS Handshake Protocol.
+
+7.1. Change cipher spec protocol
+
+ The change cipher spec protocol exists to signal transitions in
+ ciphering strategies. The protocol consists of a single message,
+ which is encrypted and compressed under the current (not the pending)
+ connection state. The message consists of a single byte of value 1.
+
+ struct {
+ enum { change_cipher_spec(1), (255) } type;
+ } ChangeCipherSpec;
+
+ The change cipher spec message is sent by both the client and server
+ to notify the receiving party that subsequent records will be
+ protected under the newly negotiated CipherSpec and keys. Reception
+ of this message causes the receiver to instruct the Record Layer to
+ immediately copy the read pending state into the read current state.
+ Immediately after sending this message, the sender should instruct
+ the record layer to make the write pending state the write active
+ state. (See section 6.1.) The change cipher spec message is sent
+ during the handshake after the security parameters have been agreed
+ upon, but before the verifying finished message is sent (see section
+ 7.4.9).
+
+7.2. Alert protocol
+
+ One of the content types supported by the TLS Record layer is the
+ alert type. Alert messages convey the severity of the message and a
+ description of the alert. Alert messages with a level of fatal result
+ in the immediate termination of the connection. In this case, other
+ connections corresponding to the session may continue, but the
+ session identifier must be invalidated, preventing the failed session
+ from being used to establish new connections. Like other messages,
+ alert messages are encrypted and compressed, as specified by the
+ current connection state.
+
+ enum { warning(1), fatal(2), (255) } AlertLevel;
+
+ enum {
+ close_notify(0),
+ unexpected_message(10),
+ bad_record_mac(20),
+ decryption_failed(21),
+ record_overflow(22),
+
+
+
+Dierks & Allen Standards Track [Page 24]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ decompression_failure(30),
+ handshake_failure(40),
+ bad_certificate(42),
+ unsupported_certificate(43),
+ certificate_revoked(44),
+ certificate_expired(45),
+ certificate_unknown(46),
+ illegal_parameter(47),
+ unknown_ca(48),
+ access_denied(49),
+ decode_error(50),
+ decrypt_error(51),
+ export_restriction(60),
+ protocol_version(70),
+ insufficient_security(71),
+ internal_error(80),
+ user_canceled(90),
+ no_renegotiation(100),
+ (255)
+ } AlertDescription;
+
+ struct {
+ AlertLevel level;
+ AlertDescription description;
+ } Alert;
+
+7.2.1. Closure alerts
+
+ The client and the server must share knowledge that the connection is
+ ending in order to avoid a truncation attack. Either party may
+ initiate the exchange of closing messages.
+
+ close_notify
+ This message notifies the recipient that the sender will not send
+ any more messages on this connection. The session becomes
+ unresumable if any connection is terminated without proper
+ close_notify messages with level equal to warning.
+
+ Either party may initiate a close by sending a close_notify alert.
+ Any data received after a closure alert is ignored.
+
+ Each party is required to send a close_notify alert before closing
+ the write side of the connection. It is required that the other party
+ respond with a close_notify alert of its own and close down the
+ connection immediately, discarding any pending writes. It is not
+ required for the initiator of the close to wait for the responding
+ close_notify alert before closing the read side of the connection.
+
+
+
+
+Dierks & Allen Standards Track [Page 25]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ If the application protocol using TLS provides that any data may be
+ carried over the underlying transport after the TLS connection is
+ closed, the TLS implementation must receive the responding
+ close_notify alert before indicating to the application layer that
+ the TLS connection has ended. If the application protocol will not
+ transfer any additional data, but will only close the underlying
+ transport connection, then the implementation may choose to close the
+ transport without waiting for the responding close_notify. No part of
+ this standard should be taken to dictate the manner in which a usage
+ profile for TLS manages its data transport, including when
+ connections are opened or closed.
+
+ NB: It is assumed that closing a connection reliably delivers
+ pending data before destroying the transport.
+
+7.2.2. Error alerts
+
+ Error handling in the TLS Handshake protocol is very simple. When an
+ error is detected, the detecting party sends a message to the other
+ party. Upon transmission or receipt of an fatal alert message, both
+ parties immediately close the connection. Servers and clients are
+ required to forget any session-identifiers, keys, and secrets
+ associated with a failed connection. The following error alerts are
+ defined:
+
+ unexpected_message
+ An inappropriate message was received. This alert is always fatal
+ and should never be observed in communication between proper
+ implementations.
+
+ bad_record_mac
+ This alert is returned if a record is received with an incorrect
+ MAC. This message is always fatal.
+
+ decryption_failed
+ A TLSCiphertext decrypted in an invalid way: either it wasn`t an
+ even multiple of the block length or its padding values, when
+ checked, weren`t correct. This message is always fatal.
+
+ record_overflow
+ A TLSCiphertext record was received which had a length more than
+ 2^14+2048 bytes, or a record decrypted to a TLSCompressed record
+ with more than 2^14+1024 bytes. This message is always fatal.
+
+ decompression_failure
+ The decompression function received improper input (e.g. data
+ that would expand to excessive length). This message is always
+ fatal.
+
+
+
+Dierks & Allen Standards Track [Page 26]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ handshake_failure
+ Reception of a handshake_failure alert message indicates that the
+ sender was unable to negotiate an acceptable set of security
+ parameters given the options available. This is a fatal error.
+
+ bad_certificate
+ A certificate was corrupt, contained signatures that did not
+ verify correctly, etc.
+
+ unsupported_certificate
+ A certificate was of an unsupported type.
+
+ certificate_revoked
+ A certificate was revoked by its signer.
+
+ certificate_expired
+ A certificate has expired or is not currently valid.
+
+ certificate_unknown
+ Some other (unspecified) issue arose in processing the
+ certificate, rendering it unacceptable.
+
+ illegal_parameter
+ A field in the handshake was out of range or inconsistent with
+ other fields. This is always fatal.
+
+ unknown_ca
+ A valid certificate chain or partial chain was received, but the
+ certificate was not accepted because the CA certificate could not
+ be located or couldn`t be matched with a known, trusted CA. This
+ message is always fatal.
+
+ access_denied
+ A valid certificate was received, but when access control was
+ applied, the sender decided not to proceed with negotiation.
+ This message is always fatal.
+
+ decode_error
+ A message could not be decoded because some field was out of the
+ specified range or the length of the message was incorrect. This
+ message is always fatal.
+
+ decrypt_error
+ A handshake cryptographic operation failed, including being
+ unable to correctly verify a signature, decrypt a key exchange,
+ or validate a finished message.
+
+
+
+
+
+Dierks & Allen Standards Track [Page 27]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ export_restriction
+ A negotiation not in compliance with export restrictions was
+ detected; for example, attempting to transfer a 1024 bit
+ ephemeral RSA key for the RSA_EXPORT handshake method. This
+ message is always fatal.
+
+ protocol_version
+ The protocol version the client has attempted to negotiate is
+ recognized, but not supported. (For example, old protocol
+ versions might be avoided for security reasons). This message is
+ always fatal.
+
+ insufficient_security
+ Returned instead of handshake_failure when a negotiation has
+ failed specifically because the server requires ciphers more
+ secure than those supported by the client. This message is always
+ fatal.
+
+ internal_error
+ An internal error unrelated to the peer or the correctness of the
+ protocol makes it impossible to continue (such as a memory
+ allocation failure). This message is always fatal.
+
+ user_canceled
+ This handshake is being canceled for some reason unrelated to a
+ protocol failure. If the user cancels an operation after the
+ handshake is complete, just closing the connection by sending a
+ close_notify is more appropriate. This alert should be followed
+ by a close_notify. This message is generally a warning.
+
+ no_renegotiation
+ Sent by the client in response to a hello request or by the
+ server in response to a client hello after initial handshaking.
+ Either of these would normally lead to renegotiation; when that
+ is not appropriate, the recipient should respond with this alert;
+ at that point, the original requester can decide whether to
+ proceed with the connection. One case where this would be
+ appropriate would be where a server has spawned a process to
+ satisfy a request; the process might receive security parameters
+ (key length, authentication, etc.) at startup and it might be
+ difficult to communicate changes to these parameters after that
+ point. This message is always a warning.
+
+ For all errors where an alert level is not explicitly specified, the
+ sending party may determine at its discretion whether this is a fatal
+ error or not; if an alert with a level of warning is received, the
+
+
+
+
+
+Dierks & Allen Standards Track [Page 28]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ receiving party may decide at its discretion whether to treat this as
+ a fatal error or not. However, all messages which are transmitted
+ with a level of fatal must be treated as fatal messages.
+
+7.3. Handshake Protocol overview
+
+ The cryptographic parameters of the session state are produced by the
+ TLS Handshake Protocol, which operates on top of the TLS Record
+ Layer. When a TLS client and server first start communicating, they
+ agree on a protocol version, select cryptographic algorithms,
+ optionally authenticate each other, and use public-key encryption
+ techniques to generate shared secrets.
+
+ The TLS Handshake Protocol involves the following steps:
+
+ - Exchange hello messages to agree on algorithms, exchange random
+ values, and check for session resumption.
+
+ - Exchange the necessary cryptographic parameters to allow the
+ client and server to agree on a premaster secret.
+
+ - Exchange certificates and cryptographic information to allow the
+ client and server to authenticate themselves.
+
+ - Generate a master secret from the premaster secret and exchanged
+ random values.
+
+ - Provide security parameters to the record layer.
+
+ - Allow the client and server to verify that their peer has
+ calculated the same security parameters and that the handshake
+ occurred without tampering by an attacker.
+
+ Note that higher layers should not be overly reliant on TLS always
+ negotiating the strongest possible connection between two peers:
+ there are a number of ways a man in the middle attacker can attempt
+ to make two entities drop down to the least secure method they
+ support. The protocol has been designed to minimize this risk, but
+ there are still attacks available: for example, an attacker could
+ block access to the port a secure service runs on, or attempt to get
+ the peers to negotiate an unauthenticated connection. The fundamental
+ rule is that higher levels must be cognizant of what their security
+ requirements are and never transmit information over a channel less
+ secure than what they require. The TLS protocol is secure, in that
+ any cipher suite offers its promised level of security: if you
+ negotiate 3DES with a 1024 bit RSA key exchange with a host whose
+ certificate you have verified, you can expect to be that secure.
+
+
+
+
+Dierks & Allen Standards Track [Page 29]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ However, you should never send data over a link encrypted with 40 bit
+ security unless you feel that data is worth no more than the effort
+ required to break that encryption.
+
+ These goals are achieved by the handshake protocol, which can be
+ summarized as follows: The client sends a client hello message to
+ which the server must respond with a server hello message, or else a
+ fatal error will occur and the connection will fail. The client hello
+ and server hello are used to establish security enhancement
+ capabilities between client and server. The client hello and server
+ hello establish the following attributes: Protocol Version, Session
+ ID, Cipher Suite, and Compression Method. Additionally, two random
+ values are generated and exchanged: ClientHello.random and
+ ServerHello.random.
+
+ The actual key exchange uses up to four messages: the server
+ certificate, the server key exchange, the client certificate, and the
+ client key exchange. New key exchange methods can be created by
+ specifying a format for these messages and defining the use of the
+ messages to allow the client and server to agree upon a shared
+ secret. This secret should be quite long; currently defined key
+ exchange methods exchange secrets which range from 48 to 128 bytes in
+ length.
+
+ Following the hello messages, the server will send its certificate,
+ if it is to be authenticated. Additionally, a server key exchange
+ message may be sent, if it is required (e.g. if their server has no
+ certificate, or if its certificate is for signing only). If the
+ server is authenticated, it may request a certificate from the
+ client, if that is appropriate to the cipher suite selected. Now the
+ server will send the server hello done message, indicating that the
+ hello-message phase of the handshake is complete. The server will
+ then wait for a client response. If the server has sent a certificate
+ request message, the client must send the certificate message. The
+ client key exchange message is now sent, and the content of that
+ message will depend on the public key algorithm selected between the
+ client hello and the server hello. If the client has sent a
+ certificate with signing ability, a digitally-signed certificate
+ verify message is sent to explicitly verify the certificate.
+
+ At this point, a change cipher spec message is sent by the client,
+ and the client copies the pending Cipher Spec into the current Cipher
+ Spec. The client then immediately sends the finished message under
+ the new algorithms, keys, and secrets. In response, the server will
+ send its own change cipher spec message, transfer the pending to the
+ current Cipher Spec, and send its finished message under the new
+
+
+
+
+
+Dierks & Allen Standards Track [Page 30]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ Cipher Spec. At this point, the handshake is complete and the client
+ and server may begin to exchange application layer data. (See flow
+ chart below.)
+
+ Client Server
+
+ ClientHello -------->
+ ServerHello
+ Certificate*
+ ServerKeyExchange*
+ CertificateRequest*
+ <-------- ServerHelloDone
+ Certificate*
+ ClientKeyExchange
+ CertificateVerify*
+ [ChangeCipherSpec]
+ Finished -------->
+ [ChangeCipherSpec]
+ <-------- Finished
+ Application Data <-------> Application Data
+
+ Fig. 1 - Message flow for a full handshake
+
+ * Indicates optional or situation-dependent messages that are not
+ always sent.
+
+ Note: To help avoid pipeline stalls, ChangeCipherSpec is an
+ independent TLS Protocol content type, and is not actually a TLS
+ handshake message.
+
+ When the client and server decide to resume a previous session or
+ duplicate an existing session (instead of negotiating new security
+ parameters) the message flow is as follows:
+
+ The client sends a ClientHello using the Session ID of the session to
+ be resumed. The server then checks its session cache for a match. If
+ a match is found, and the server is willing to re-establish the
+ connection under the specified session state, it will send a
+ ServerHello with the same Session ID value. At this point, both
+ client and server must send change cipher spec messages and proceed
+ directly to finished messages. Once the re-establishment is complete,
+ the client and server may begin to exchange application layer data.
+ (See flow chart below.) If a Session ID match is not found, the
+ server generates a new session ID and the TLS client and server
+ perform a full handshake.
+
+
+
+
+
+
+Dierks & Allen Standards Track [Page 31]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ Client Server
+
+ ClientHello -------->
+ ServerHello
+ [ChangeCipherSpec]
+ <-------- Finished
+ [ChangeCipherSpec]
+ Finished -------->
+ Application Data <-------> Application Data
+
+ Fig. 2 - Message flow for an abbreviated handshake
+
+ The contents and significance of each message will be presented in
+ detail in the following sections.
+
+7.4. Handshake protocol
+
+ The TLS Handshake Protocol is one of the defined higher level clients
+ of the TLS Record Protocol. This protocol is used to negotiate the
+ secure attributes of a session. Handshake messages are supplied to
+ the TLS Record Layer, where they are encapsulated within one or more
+ TLSPlaintext structures, which are processed and transmitted as
+ specified by the current active session state.
+
+ enum {
+ hello_request(0), client_hello(1), server_hello(2),
+ certificate(11), server_key_exchange (12),
+ certificate_request(13), server_hello_done(14),
+ certificate_verify(15), client_key_exchange(16),
+ finished(20), (255)
+ } HandshakeType;
+
+ struct {
+ HandshakeType msg_type; /* handshake type */
+ uint24 length; /* bytes in message */
+ select (HandshakeType) {
+ case hello_request: HelloRequest;
+ case client_hello: ClientHello;
+ case server_hello: ServerHello;
+ case certificate: Certificate;
+ case server_key_exchange: ServerKeyExchange;
+ case certificate_request: CertificateRequest;
+ case server_hello_done: ServerHelloDone;
+ case certificate_verify: CertificateVerify;
+ case client_key_exchange: ClientKeyExchange;
+ case finished: Finished;
+ } body;
+ } Handshake;
+
+
+
+Dierks & Allen Standards Track [Page 32]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ The handshake protocol messages are presented below in the order they
+ must be sent; sending handshake messages in an unexpected order
+ results in a fatal error. Unneeded handshake messages can be omitted,
+ however. Note one exception to the ordering: the Certificate message
+ is used twice in the handshake (from server to client, then from
+ client to server), but described only in its first position. The one
+ message which is not bound by these ordering rules in the Hello
+ Request message, which can be sent at any time, but which should be
+ ignored by the client if it arrives in the middle of a handshake.
+
+7.4.1. Hello messages
+
+ The hello phase messages are used to exchange security enhancement
+ capabilities between the client and server. When a new session
+ begins, the Record Layer's connection state encryption, hash, and
+ compression algorithms are initialized to null. The current
+ connection state is used for renegotiation messages.
+
+7.4.1.1. Hello request
+
+ When this message will be sent:
+ The hello request message may be sent by the server at any time.
+
+ Meaning of this message:
+ Hello request is a simple notification that the client should
+ begin the negotiation process anew by sending a client hello
+ message when convenient. This message will be ignored by the
+ client if the client is currently negotiating a session. This
+ message may be ignored by the client if it does not wish to
+ renegotiate a session, or the client may, if it wishes, respond
+ with a no_renegotiation alert. Since handshake messages are
+ intended to have transmission precedence over application data,
+ it is expected that the negotiation will begin before no more
+ than a few records are received from the client. If the server
+ sends a hello request but does not receive a client hello in
+ response, it may close the connection with a fatal alert.
+
+ After sending a hello request, servers should not repeat the request
+ until the subsequent handshake negotiation is complete.
+
+ Structure of this message:
+ struct { } HelloRequest;
+
+ Note: This message should never be included in the message hashes which
+ are maintained throughout the handshake and used in the finished
+ messages and the certificate verify message.
+
+
+
+
+
+Dierks & Allen Standards Track [Page 33]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+7.4.1.2. Client hello
+
+ When this message will be sent:
+ When a client first connects to a server it is required to send
+ the client hello as its first message. The client can also send a
+ client hello in response to a hello request or on its own
+ initiative in order to renegotiate the security parameters in an
+ existing connection.
+
+ Structure of this message:
+ The client hello message includes a random structure, which is
+ used later in the protocol.
+
+ struct {
+ uint32 gmt_unix_time;
+ opaque random_bytes[28];
+ } Random;
+
+ gmt_unix_time
+ The current time and date in standard UNIX 32-bit format (seconds
+ since the midnight starting Jan 1, 1970, GMT) according to the
+ sender's internal clock. Clocks are not required to be set
+ correctly by the basic TLS Protocol; higher level or application
+ protocols may define additional requirements.
+
+ random_bytes
+ 28 bytes generated by a secure random number generator.
+
+ The client hello message includes a variable length session
+ identifier. If not empty, the value identifies a session between the
+ same client and server whose security parameters the client wishes to
+ reuse. The session identifier may be from an earlier connection, this
+ connection, or another currently active connection. The second option
+ is useful if the client only wishes to update the random structures
+ and derived values of a connection, while the third option makes it
+ possible to establish several independent secure connections without
+ repeating the full handshake protocol. These independent connections
+ may occur sequentially or simultaneously; a SessionID becomes valid
+ when the handshake negotiating it completes with the exchange of
+ Finished messages and persists until removed due to aging or because
+ a fatal error was encountered on a connection associated with the
+ session. The actual contents of the SessionID are defined by the
+ server.
+
+ opaque SessionID<0..32>;
+
+
+
+
+
+
+Dierks & Allen Standards Track [Page 34]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ Warning:
+ Because the SessionID is transmitted without encryption or
+ immediate MAC protection, servers must not place confidential
+ information in session identifiers or let the contents of fake
+ session identifiers cause any breach of security. (Note that the
+ content of the handshake as a whole, including the SessionID, is
+ protected by the Finished messages exchanged at the end of the
+ handshake.)
+
+ The CipherSuite list, passed from the client to the server in the
+ client hello message, contains the combinations of cryptographic
+ algorithms supported by the client in order of the client's
+ preference (favorite choice first). Each CipherSuite defines a key
+ exchange algorithm, a bulk encryption algorithm (including secret key
+ length) and a MAC algorithm. The server will select a cipher suite
+ or, if no acceptable choices are presented, return a handshake
+ failure alert and close the connection.
+
+ uint8 CipherSuite[2]; /* Cryptographic suite selector */
+
+ The client hello includes a list of compression algorithms supported
+ by the client, ordered according to the client's preference.
+
+ enum { null(0), (255) } CompressionMethod;
+
+ struct {
+ ProtocolVersion client_version;
+ Random random;
+ SessionID session_id;
+ CipherSuite cipher_suites<2..2^16-1>;
+ CompressionMethod compression_methods<1..2^8-1>;
+ } ClientHello;
+
+ client_version
+ The version of the TLS protocol by which the client wishes to
+ communicate during this session. This should be the latest
+ (highest valued) version supported by the client. For this
+ version of the specification, the version will be 3.1 (See
+ Appendix E for details about backward compatibility).
+
+ random
+ A client-generated random structure.
+
+ session_id
+ The ID of a session the client wishes to use for this connection.
+ This field should be empty if no session_id is available or the
+ client wishes to generate new security parameters.
+
+
+
+
+Dierks & Allen Standards Track [Page 35]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ cipher_suites
+ This is a list of the cryptographic options supported by the
+ client, with the client's first preference first. If the
+ session_id field is not empty (implying a session resumption
+ request) this vector must include at least the cipher_suite from
+ that session. Values are defined in Appendix A.5.
+
+ compression_methods
+ This is a list of the compression methods supported by the
+ client, sorted by client preference. If the session_id field is
+ not empty (implying a session resumption request) it must include
+ the compression_method from that session. This vector must
+ contain, and all implementations must support,
+ CompressionMethod.null. Thus, a client and server will always be
+ able to agree on a compression method.
+
+ After sending the client hello message, the client waits for a server
+ hello message. Any other handshake message returned by the server
+ except for a hello request is treated as a fatal error.
+
+ Forward compatibility note:
+ In the interests of forward compatibility, it is permitted for a
+ client hello message to include extra data after the compression
+ methods. This data must be included in the handshake hashes, but
+ must otherwise be ignored. This is the only handshake message for
+ which this is legal; for all other messages, the amount of data
+ in the message must match the description of the message
+ precisely.
+
+7.4.1.3. Server hello
+
+ When this message will be sent:
+ The server will send this message in response to a client hello
+ message when it was able to find an acceptable set of algorithms.
+ If it cannot find such a match, it will respond with a handshake
+ failure alert.
+
+ Structure of this message:
+ struct {
+ ProtocolVersion server_version;
+ Random random;
+ SessionID session_id;
+ CipherSuite cipher_suite;
+ CompressionMethod compression_method;
+ } ServerHello;
+
+
+
+
+
+
+Dierks & Allen Standards Track [Page 36]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ server_version
+ This field will contain the lower of that suggested by the client
+ in the client hello and the highest supported by the server. For
+ this version of the specification, the version is 3.1 (See
+ Appendix E for details about backward compatibility).
+
+ random
+ This structure is generated by the server and must be different
+ from (and independent of) ClientHello.random.
+
+ session_id
+ This is the identity of the session corresponding to this
+ connection. If the ClientHello.session_id was non-empty, the
+ server will look in its session cache for a match. If a match is
+ found and the server is willing to establish the new connection
+ using the specified session state, the server will respond with
+ the same value as was supplied by the client. This indicates a
+ resumed session and dictates that the parties must proceed
+ directly to the finished messages. Otherwise this field will
+ contain a different value identifying the new session. The server
+ may return an empty session_id to indicate that the session will
+ not be cached and therefore cannot be resumed. If a session is
+ resumed, it must be resumed using the same cipher suite it was
+ originally negotiated with.
+
+ cipher_suite
+ The single cipher suite selected by the server from the list in
+ ClientHello.cipher_suites. For resumed sessions this field is the
+ value from the state of the session being resumed.
+
+ compression_method
+ The single compression algorithm selected by the server from the
+ list in ClientHello.compression_methods. For resumed sessions
+ this field is the value from the resumed session state.
+
+7.4.2. Server certificate
+
+ When this message will be sent:
+ The server must send a certificate whenever the agreed-upon key
+ exchange method is not an anonymous one. This message will always
+ immediately follow the server hello message.
+
+ Meaning of this message:
+ The certificate type must be appropriate for the selected cipher
+ suite's key exchange algorithm, and is generally an X.509v3
+ certificate. It must contain a key which matches the key exchange
+ method, as follows. Unless otherwise specified, the signing
+
+
+
+
+Dierks & Allen Standards Track [Page 37]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ algorithm for the certificate must be the same as the algorithm
+ for the certificate key. Unless otherwise specified, the public
+ key may be of any length.
+
+ Key Exchange Algorithm Certificate Key Type
+
+ RSA RSA public key; the certificate must
+ allow the key to be used for encryption.
+
+ RSA_EXPORT RSA public key of length greater than
+ 512 bits which can be used for signing,
+ or a key of 512 bits or shorter which
+ can be used for either encryption or
+ signing.
+
+ DHE_DSS DSS public key.
+
+ DHE_DSS_EXPORT DSS public key.
+
+ DHE_RSA RSA public key which can be used for
+ signing.
+
+ DHE_RSA_EXPORT RSA public key which can be used for
+ signing.
+
+ DH_DSS Diffie-Hellman key. The algorithm used
+ to sign the certificate should be DSS.
+
+ DH_RSA Diffie-Hellman key. The algorithm used
+ to sign the certificate should be RSA.
+
+ All certificate profiles, key and cryptographic formats are defined
+ by the IETF PKIX working group [PKIX]. When a key usage extension is
+ present, the digitalSignature bit must be set for the key to be
+ eligible for signing, as described above, and the keyEncipherment bit
+ must be present to allow encryption, as described above. The
+ keyAgreement bit must be set on Diffie-Hellman certificates.
+
+ As CipherSuites which specify new key exchange methods are specified
+ for the TLS Protocol, they will imply certificate format and the
+ required encoded keying information.
+
+ Structure of this message:
+ opaque ASN.1Cert<1..2^24-1>;
+
+ struct {
+ ASN.1Cert certificate_list<0..2^24-1>;
+ } Certificate;
+
+
+
+Dierks & Allen Standards Track [Page 38]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ certificate_list
+ This is a sequence (chain) of X.509v3 certificates. The sender's
+ certificate must come first in the list. Each following
+ certificate must directly certify the one preceding it. Because
+ certificate validation requires that root keys be distributed
+ independently, the self-signed certificate which specifies the
+ root certificate authority may optionally be omitted from the
+ chain, under the assumption that the remote end must already
+ possess it in order to validate it in any case.
+
+ The same message type and structure will be used for the client's
+ response to a certificate request message. Note that a client may
+ send no certificates if it does not have an appropriate certificate
+ to send in response to the server's authentication request.
+
+ Note: PKCS #7 [PKCS7] is not used as the format for the certificate
+ vector because PKCS #6 [PKCS6] extended certificates are not
+ used. Also PKCS #7 defines a SET rather than a SEQUENCE, making
+ the task of parsing the list more difficult.
+
+7.4.3. Server key exchange message
+
+ When this message will be sent:
+ This message will be sent immediately after the server
+ certificate message (or the server hello message, if this is an
+ anonymous negotiation).
+
+ The server key exchange message is sent by the server only when
+ the server certificate message (if sent) does not contain enough
+ data to allow the client to exchange a premaster secret. This is
+ true for the following key exchange methods:
+
+ RSA_EXPORT (if the public key in the server certificate is
+ longer than 512 bits)
+ DHE_DSS
+ DHE_DSS_EXPORT
+ DHE_RSA
+ DHE_RSA_EXPORT
+ DH_anon
+
+ It is not legal to send the server key exchange message for the
+ following key exchange methods:
+
+ RSA
+ RSA_EXPORT (when the public key in the server certificate is
+ less than or equal to 512 bits in length)
+ DH_DSS
+ DH_RSA
+
+
+
+Dierks & Allen Standards Track [Page 39]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ Meaning of this message:
+ This message conveys cryptographic information to allow the
+ client to communicate the premaster secret: either an RSA public
+ key to encrypt the premaster secret with, or a Diffie-Hellman
+ public key with which the client can complete a key exchange
+ (with the result being the premaster secret.)
+
+ As additional CipherSuites are defined for TLS which include new key
+ exchange algorithms, the server key exchange message will be sent if
+ and only if the certificate type associated with the key exchange
+ algorithm does not provide enough information for the client to
+ exchange a premaster secret.
+
+ Note: According to current US export law, RSA moduli larger than 512
+ bits may not be used for key exchange in software exported from
+ the US. With this message, the larger RSA keys encoded in
+ certificates may be used to sign temporary shorter RSA keys for
+ the RSA_EXPORT key exchange method.
+
+ Structure of this message:
+ enum { rsa, diffie_hellman } KeyExchangeAlgorithm;
+
+ struct {
+ opaque rsa_modulus<1..2^16-1>;
+ opaque rsa_exponent<1..2^16-1>;
+ } ServerRSAParams;
+
+ rsa_modulus
+ The modulus of the server's temporary RSA key.
+
+ rsa_exponent
+ The public exponent of the server's temporary RSA key.
+
+ struct {
+ opaque dh_p<1..2^16-1>;
+ opaque dh_g<1..2^16-1>;
+ opaque dh_Ys<1..2^16-1>;
+ } ServerDHParams; /* Ephemeral DH parameters */
+
+ dh_p
+ The prime modulus used for the Diffie-Hellman operation.
+
+ dh_g
+ The generator used for the Diffie-Hellman operation.
+
+ dh_Ys
+ The server's Diffie-Hellman public value (g^X mod p).
+
+
+
+
+Dierks & Allen Standards Track [Page 40]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ struct {
+ select (KeyExchangeAlgorithm) {
+ case diffie_hellman:
+ ServerDHParams params;
+ Signature signed_params;
+ case rsa:
+ ServerRSAParams params;
+ Signature signed_params;
+ };
+ } ServerKeyExchange;
+
+ params
+ The server's key exchange parameters.
+
+ signed_params
+ For non-anonymous key exchanges, a hash of the corresponding
+ params value, with the signature appropriate to that hash
+ applied.
+
+ md5_hash
+ MD5(ClientHello.random + ServerHello.random + ServerParams);
+
+ sha_hash
+ SHA(ClientHello.random + ServerHello.random + ServerParams);
+
+ enum { anonymous, rsa, dsa } SignatureAlgorithm;
+
+ select (SignatureAlgorithm)
+ { case anonymous: struct { };
+ case rsa:
+ digitally-signed struct {
+ opaque md5_hash[16];
+ opaque sha_hash[20];
+ };
+ case dsa:
+ digitally-signed struct {
+ opaque sha_hash[20];
+ };
+ } Signature;
+
+7.4.4. Certificate request
+
+ When this message will be sent:
+ A non-anonymous server can optionally request a certificate from
+ the client, if appropriate for the selected cipher suite. This
+ message, if sent, will immediately follow the Server Key Exchange
+ message (if it is sent; otherwise, the Server Certificate
+ message).
+
+
+
+Dierks & Allen Standards Track [Page 41]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ Structure of this message:
+ enum {
+ rsa_sign(1), dss_sign(2), rsa_fixed_dh(3), dss_fixed_dh(4),
+ (255)
+ } ClientCertificateType;
+
+ opaque DistinguishedName<1..2^16-1>;
+
+ struct {
+ ClientCertificateType certificate_types<1..2^8-1>;
+ DistinguishedName certificate_authorities<3..2^16-1>;
+ } CertificateRequest;
+
+ certificate_types
+ This field is a list of the types of certificates requested,
+ sorted in order of the server's preference.
+
+ certificate_authorities
+ A list of the distinguished names of acceptable certificate
+ authorities. These distinguished names may specify a desired
+ distinguished name for a root CA or for a subordinate CA;
+ thus, this message can be used both to describe known roots
+ and a desired authorization space.
+
+ Note: DistinguishedName is derived from [X509].
+
+ Note: It is a fatal handshake_failure alert for an anonymous server to
+ request client identification.
+
+7.4.5. Server hello done
+
+ When this message will be sent:
+ The server hello done message is sent by the server to indicate
+ the end of the server hello and associated messages. After
+ sending this message the server will wait for a client response.
+
+ Meaning of this message:
+ This message means that the server is done sending messages to
+ support the key exchange, and the client can proceed with its
+ phase of the key exchange.
+
+ Upon receipt of the server hello done message the client should
+ verify that the server provided a valid certificate if required
+ and check that the server hello parameters are acceptable.
+
+ Structure of this message:
+ struct { } ServerHelloDone;
+
+
+
+
+Dierks & Allen Standards Track [Page 42]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+7.4.6. Client certificate
+
+ When this message will be sent:
+ This is the first message the client can send after receiving a
+ server hello done message. This message is only sent if the
+ server requests a certificate. If no suitable certificate is
+ available, the client should send a certificate message
+ containing no certificates. If client authentication is required
+ by the server for the handshake to continue, it may respond with
+ a fatal handshake failure alert. Client certificates are sent
+ using the Certificate structure defined in Section 7.4.2.
+
+ Note: When using a static Diffie-Hellman based key exchange method
+ (DH_DSS or DH_RSA), if client authentication is requested, the
+ Diffie-Hellman group and generator encoded in the client's
+ certificate must match the server specified Diffie-Hellman
+ parameters if the client's parameters are to be used for the key
+ exchange.
+
+7.4.7. Client key exchange message
+
+ When this message will be sent:
+ This message is always sent by the client. It will immediately
+ follow the client certificate message, if it is sent. Otherwise
+ it will be the first message sent by the client after it receives
+ the server hello done message.
+
+ Meaning of this message:
+ With this message, the premaster secret is set, either though
+ direct transmission of the RSA-encrypted secret, or by the
+ transmission of Diffie-Hellman parameters which will allow each
+ side to agree upon the same premaster secret. When the key
+ exchange method is DH_RSA or DH_DSS, client certification has
+ been requested, and the client was able to respond with a
+ certificate which contained a Diffie-Hellman public key whose
+ parameters (group and generator) matched those specified by the
+ server in its certificate, this message will not contain any
+ data.
+
+ Structure of this message:
+ The choice of messages depends on which key exchange method has
+ been selected. See Section 7.4.3 for the KeyExchangeAlgorithm
+ definition.
+
+ struct {
+ select (KeyExchangeAlgorithm) {
+ case rsa: EncryptedPreMasterSecret;
+ case diffie_hellman: ClientDiffieHellmanPublic;
+
+
+
+Dierks & Allen Standards Track [Page 43]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ } exchange_keys;
+ } ClientKeyExchange;
+
+7.4.7.1. RSA encrypted premaster secret message
+
+ Meaning of this message:
+ If RSA is being used for key agreement and authentication, the
+ client generates a 48-byte premaster secret, encrypts it using
+ the public key from the server's certificate or the temporary RSA
+ key provided in a server key exchange message, and sends the
+ result in an encrypted premaster secret message. This structure
+ is a variant of the client key exchange message, not a message in
+ itself.
+
+ Structure of this message:
+ struct {
+ ProtocolVersion client_version;
+ opaque random[46];
+ } PreMasterSecret;
+
+ client_version
+ The latest (newest) version supported by the client. This is
+ used to detect version roll-back attacks. Upon receiving the
+ premaster secret, the server should check that this value
+ matches the value transmitted by the client in the client
+ hello message.
+
+ random
+ 46 securely-generated random bytes.
+
+ struct {
+ public-key-encrypted PreMasterSecret pre_master_secret;
+ } EncryptedPreMasterSecret;
+
+ Note: An attack discovered by Daniel Bleichenbacher [BLEI] can be used
+ to attack a TLS server which is using PKCS#1 encoded RSA. The
+ attack takes advantage of the fact that by failing in different
+ ways, a TLS server can be coerced into revealing whether a
+ particular message, when decrypted, is properly PKCS#1 formatted
+ or not.
+
+ The best way to avoid vulnerability to this attack is to treat
+ incorrectly formatted messages in a manner indistinguishable from
+ correctly formatted RSA blocks. Thus, when it receives an
+ incorrectly formatted RSA block, a server should generate a
+ random 48-byte value and proceed using it as the premaster
+ secret. Thus, the server will act identically whether the
+ received RSA block is correctly encoded or not.
+
+
+
+Dierks & Allen Standards Track [Page 44]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ pre_master_secret
+ This random value is generated by the client and is used to
+ generate the master secret, as specified in Section 8.1.
+
+7.4.7.2. Client Diffie-Hellman public value
+
+ Meaning of this message:
+ This structure conveys the client's Diffie-Hellman public value
+ (Yc) if it was not already included in the client's certificate.
+ The encoding used for Yc is determined by the enumerated
+ PublicValueEncoding. This structure is a variant of the client
+ key exchange message, not a message in itself.
+
+ Structure of this message:
+ enum { implicit, explicit } PublicValueEncoding;
+
+ implicit
+ If the client certificate already contains a suitable
+ Diffie-Hellman key, then Yc is implicit and does not need to
+ be sent again. In this case, the Client Key Exchange message
+ will be sent, but will be empty.
+
+ explicit
+ Yc needs to be sent.
+
+ struct {
+ select (PublicValueEncoding) {
+ case implicit: struct { };
+ case explicit: opaque dh_Yc<1..2^16-1>;
+ } dh_public;
+ } ClientDiffieHellmanPublic;
+
+ dh_Yc
+ The client's Diffie-Hellman public value (Yc).
+
+7.4.8. Certificate verify
+
+ When this message will be sent:
+ This message is used to provide explicit verification of a client
+ certificate. This message is only sent following a client
+ certificate that has signing capability (i.e. all certificates
+ except those containing fixed Diffie-Hellman parameters). When
+ sent, it will immediately follow the client key exchange message.
+
+ Structure of this message:
+ struct {
+ Signature signature;
+ } CertificateVerify;
+
+
+
+Dierks & Allen Standards Track [Page 45]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ The Signature type is defined in 7.4.3.
+
+ CertificateVerify.signature.md5_hash
+ MD5(handshake_messages);
+
+ Certificate.signature.sha_hash
+ SHA(handshake_messages);
+
+ Here handshake_messages refers to all handshake messages sent or
+ received starting at client hello up to but not including this
+ message, including the type and length fields of the handshake
+ messages. This is the concatenation of all the Handshake structures
+ as defined in 7.4 exchanged thus far.
+
+7.4.9. Finished
+
+ When this message will be sent:
+ A finished message is always sent immediately after a change
+ cipher spec message to verify that the key exchange and
+ authentication processes were successful. It is essential that a
+ change cipher spec message be received between the other
+ handshake messages and the Finished message.
+
+ Meaning of this message:
+ The finished message is the first protected with the just-
+ negotiated algorithms, keys, and secrets. Recipients of finished
+ messages must verify that the contents are correct. Once a side
+ has sent its Finished message and received and validated the
+ Finished message from its peer, it may begin to send and receive
+ application data over the connection.
+
+ struct {
+ opaque verify_data[12];
+ } Finished;
+
+ verify_data
+ PRF(master_secret, finished_label, MD5(handshake_messages) +
+ SHA-1(handshake_messages)) [0..11];
+
+ finished_label
+ For Finished messages sent by the client, the string "client
+ finished". For Finished messages sent by the server, the
+ string "server finished".
+
+ handshake_messages
+ All of the data from all handshake messages up to but not
+ including this message. This is only data visible at the
+ handshake layer and does not include record layer headers.
+
+
+
+Dierks & Allen Standards Track [Page 46]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ This is the concatenation of all the Handshake structures as
+ defined in 7.4 exchanged thus far.
+
+ It is a fatal error if a finished message is not preceded by a change
+ cipher spec message at the appropriate point in the handshake.
+
+ The hash contained in finished messages sent by the server
+ incorporate Sender.server; those sent by the client incorporate
+ Sender.client. The value handshake_messages includes all handshake
+ messages starting at client hello up to, but not including, this
+ finished message. This may be different from handshake_messages in
+ Section 7.4.8 because it would include the certificate verify message
+ (if sent). Also, the handshake_messages for the finished message sent
+ by the client will be different from that for the finished message
+ sent by the server, because the one which is sent second will include
+ the prior one.
+
+ Note: Change cipher spec messages, alerts and any other record types
+ are not handshake messages and are not included in the hash
+ computations. Also, Hello Request messages are omitted from
+ handshake hashes.
+
+8. Cryptographic computations
+
+ In order to begin connection protection, the TLS Record Protocol
+ requires specification of a suite of algorithms, a master secret, and
+ the client and server random values. The authentication, encryption,
+ and MAC algorithms are determined by the cipher_suite selected by the
+ server and revealed in the server hello message. The compression
+ algorithm is negotiated in the hello messages, and the random values
+ are exchanged in the hello messages. All that remains is to calculate
+ the master secret.
+
+8.1. Computing the master secret
+
+ For all key exchange methods, the same algorithm is used to convert
+ the pre_master_secret into the master_secret. The pre_master_secret
+ should be deleted from memory once the master_secret has been
+ computed.
+
+ master_secret = PRF(pre_master_secret, "master secret",
+ ClientHello.random + ServerHello.random)
+ [0..47];
+
+ The master secret is always exactly 48 bytes in length. The length of
+ the premaster secret will vary depending on key exchange method.
+
+
+
+
+
+Dierks & Allen Standards Track [Page 47]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+8.1.1. RSA
+
+ When RSA is used for server authentication and key exchange, a 48-
+ byte pre_master_secret is generated by the client, encrypted under
+ the server's public key, and sent to the server. The server uses its
+ private key to decrypt the pre_master_secret. Both parties then
+ convert the pre_master_secret into the master_secret, as specified
+ above.
+
+ RSA digital signatures are performed using PKCS #1 [PKCS1] block type
+ 1. RSA public key encryption is performed using PKCS #1 block type 2.
+
+8.1.2. Diffie-Hellman
+
+ A conventional Diffie-Hellman computation is performed. The
+ negotiated key (Z) is used as the pre_master_secret, and is converted
+ into the master_secret, as specified above.
+
+ Note: Diffie-Hellman parameters are specified by the server, and may
+ be either ephemeral or contained within the server's certificate.
+
+9. Mandatory Cipher Suites
+
+ In the absence of an application profile standard specifying
+ otherwise, a TLS compliant application MUST implement the cipher
+ suite TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA.
+
+10. Application data protocol
+
+ Application data messages are carried by the Record Layer and are
+ fragmented, compressed and encrypted based on the current connection
+ state. The messages are treated as transparent data to the record
+ layer.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Dierks & Allen Standards Track [Page 48]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+A. Protocol constant values
+
+ This section describes protocol types and constants.
+
+A.1. Record layer
+
+ struct {
+ uint8 major, minor;
+ } ProtocolVersion;
+
+ ProtocolVersion version = { 3, 1 }; /* TLS v1.0 */
+
+ enum {
+ change_cipher_spec(20), alert(21), handshake(22),
+ application_data(23), (255)
+ } ContentType;
+
+ struct {
+ ContentType type;
+ ProtocolVersion version;
+ uint16 length;
+ opaque fragment[TLSPlaintext.length];
+ } TLSPlaintext;
+
+ struct {
+ ContentType type;
+ ProtocolVersion version;
+ uint16 length;
+ opaque fragment[TLSCompressed.length];
+ } TLSCompressed;
+
+ struct {
+ ContentType type;
+ ProtocolVersion version;
+ uint16 length;
+ select (CipherSpec.cipher_type) {
+ case stream: GenericStreamCipher;
+ case block: GenericBlockCipher;
+ } fragment;
+ } TLSCiphertext;
+
+ stream-ciphered struct {
+ opaque content[TLSCompressed.length];
+ opaque MAC[CipherSpec.hash_size];
+ } GenericStreamCipher;
+
+ block-ciphered struct {
+ opaque content[TLSCompressed.length];
+
+
+
+Dierks & Allen Standards Track [Page 49]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ opaque MAC[CipherSpec.hash_size];
+ uint8 padding[GenericBlockCipher.padding_length];
+ uint8 padding_length;
+ } GenericBlockCipher;
+
+A.2. Change cipher specs message
+
+ struct {
+ enum { change_cipher_spec(1), (255) } type;
+ } ChangeCipherSpec;
+
+A.3. Alert messages
+
+ enum { warning(1), fatal(2), (255) } AlertLevel;
+
+ enum {
+ close_notify(0),
+ unexpected_message(10),
+ bad_record_mac(20),
+ decryption_failed(21),
+ record_overflow(22),
+ decompression_failure(30),
+ handshake_failure(40),
+ bad_certificate(42),
+ unsupported_certificate(43),
+ certificate_revoked(44),
+ certificate_expired(45),
+ certificate_unknown(46),
+ illegal_parameter(47),
+ unknown_ca(48),
+ access_denied(49),
+ decode_error(50),
+ decrypt_error(51),
+ export_restriction(60),
+ protocol_version(70),
+ insufficient_security(71),
+ internal_error(80),
+ user_canceled(90),
+ no_renegotiation(100),
+ (255)
+ } AlertDescription;
+
+ struct {
+ AlertLevel level;
+ AlertDescription description;
+ } Alert;
+
+
+
+
+
+Dierks & Allen Standards Track [Page 50]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+A.4. Handshake protocol
+
+ enum {
+ hello_request(0), client_hello(1), server_hello(2),
+ certificate(11), server_key_exchange (12),
+ certificate_request(13), server_hello_done(14),
+ certificate_verify(15), client_key_exchange(16),
+ finished(20), (255)
+ } HandshakeType;
+
+ struct {
+ HandshakeType msg_type;
+ uint24 length;
+ select (HandshakeType) {
+ case hello_request: HelloRequest;
+ case client_hello: ClientHello;
+ case server_hello: ServerHello;
+ case certificate: Certificate;
+ case server_key_exchange: ServerKeyExchange;
+ case certificate_request: CertificateRequest;
+ case server_hello_done: ServerHelloDone;
+ case certificate_verify: CertificateVerify;
+ case client_key_exchange: ClientKeyExchange;
+ case finished: Finished;
+ } body;
+ } Handshake;
+
+A.4.1. Hello messages
+
+ struct { } HelloRequest;
+
+ struct {
+ uint32 gmt_unix_time;
+ opaque random_bytes[28];
+ } Random;
+
+ opaque SessionID<0..32>;
+
+ uint8 CipherSuite[2];
+
+ enum { null(0), (255) } CompressionMethod;
+
+ struct {
+ ProtocolVersion client_version;
+ Random random;
+ SessionID session_id;
+ CipherSuite cipher_suites<2..2^16-1>;
+ CompressionMethod compression_methods<1..2^8-1>;
+
+
+
+Dierks & Allen Standards Track [Page 51]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ } ClientHello;
+
+ struct {
+ ProtocolVersion server_version;
+ Random random;
+ SessionID session_id;
+ CipherSuite cipher_suite;
+ CompressionMethod compression_method;
+ } ServerHello;
+
+A.4.2. Server authentication and key exchange messages
+
+ opaque ASN.1Cert<2^24-1>;
+
+ struct {
+ ASN.1Cert certificate_list<1..2^24-1>;
+ } Certificate;
+
+ enum { rsa, diffie_hellman } KeyExchangeAlgorithm;
+
+ struct {
+ opaque RSA_modulus<1..2^16-1>;
+ opaque RSA_exponent<1..2^16-1>;
+ } ServerRSAParams;
+
+ struct {
+ opaque DH_p<1..2^16-1>;
+ opaque DH_g<1..2^16-1>;
+ opaque DH_Ys<1..2^16-1>;
+ } ServerDHParams;
+
+ struct {
+ select (KeyExchangeAlgorithm) {
+ case diffie_hellman:
+ ServerDHParams params;
+ Signature signed_params;
+ case rsa:
+ ServerRSAParams params;
+ Signature signed_params;
+ };
+ } ServerKeyExchange;
+
+ enum { anonymous, rsa, dsa } SignatureAlgorithm;
+
+ select (SignatureAlgorithm)
+ { case anonymous: struct { };
+ case rsa:
+ digitally-signed struct {
+
+
+
+Dierks & Allen Standards Track [Page 52]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ opaque md5_hash[16];
+ opaque sha_hash[20];
+ };
+ case dsa:
+ digitally-signed struct {
+ opaque sha_hash[20];
+ };
+ } Signature;
+
+ enum {
+ rsa_sign(1), dss_sign(2), rsa_fixed_dh(3), dss_fixed_dh(4),
+ (255)
+ } ClientCertificateType;
+
+ opaque DistinguishedName<1..2^16-1>;
+
+ struct {
+ ClientCertificateType certificate_types<1..2^8-1>;
+ DistinguishedName certificate_authorities<3..2^16-1>;
+ } CertificateRequest;
+
+ struct { } ServerHelloDone;
+
+A.4.3. Client authentication and key exchange messages
+
+ struct {
+ select (KeyExchangeAlgorithm) {
+ case rsa: EncryptedPreMasterSecret;
+ case diffie_hellman: DiffieHellmanClientPublicValue;
+ } exchange_keys;
+ } ClientKeyExchange;
+
+ struct {
+ ProtocolVersion client_version;
+ opaque random[46];
+
+ } PreMasterSecret;
+
+ struct {
+ public-key-encrypted PreMasterSecret pre_master_secret;
+ } EncryptedPreMasterSecret;
+
+ enum { implicit, explicit } PublicValueEncoding;
+
+ struct {
+ select (PublicValueEncoding) {
+ case implicit: struct {};
+ case explicit: opaque DH_Yc<1..2^16-1>;
+
+
+
+Dierks & Allen Standards Track [Page 53]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ } dh_public;
+ } ClientDiffieHellmanPublic;
+
+ struct {
+ Signature signature;
+ } CertificateVerify;
+
+A.4.4. Handshake finalization message
+
+ struct {
+ opaque verify_data[12];
+ } Finished;
+
+A.5. The CipherSuite
+
+ The following values define the CipherSuite codes used in the client
+ hello and server hello messages.
+
+ A CipherSuite defines a cipher specification supported in TLS Version
+ 1.0.
+
+ TLS_NULL_WITH_NULL_NULL is specified and is the initial state of a
+ TLS connection during the first handshake on that channel, but must
+ not be negotiated, as it provides no more protection than an
+ unsecured connection.
+
+ CipherSuite TLS_NULL_WITH_NULL_NULL = { 0x00,0x00 };
+
+ The following CipherSuite definitions require that the server provide
+ an RSA certificate that can be used for key exchange. The server may
+ request either an RSA or a DSS signature-capable certificate in the
+ certificate request message.
+
+ CipherSuite TLS_RSA_WITH_NULL_MD5 = { 0x00,0x01 };
+ CipherSuite TLS_RSA_WITH_NULL_SHA = { 0x00,0x02 };
+ CipherSuite TLS_RSA_EXPORT_WITH_RC4_40_MD5 = { 0x00,0x03 };
+ CipherSuite TLS_RSA_WITH_RC4_128_MD5 = { 0x00,0x04 };
+ CipherSuite TLS_RSA_WITH_RC4_128_SHA = { 0x00,0x05 };
+ CipherSuite TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 = { 0x00,0x06 };
+ CipherSuite TLS_RSA_WITH_IDEA_CBC_SHA = { 0x00,0x07 };
+ CipherSuite TLS_RSA_EXPORT_WITH_DES40_CBC_SHA = { 0x00,0x08 };
+ CipherSuite TLS_RSA_WITH_DES_CBC_SHA = { 0x00,0x09 };
+ CipherSuite TLS_RSA_WITH_3DES_EDE_CBC_SHA = { 0x00,0x0A };
+
+ The following CipherSuite definitions are used for server-
+ authenticated (and optionally client-authenticated) Diffie-Hellman.
+ DH denotes cipher suites in which the server's certificate contains
+ the Diffie-Hellman parameters signed by the certificate authority
+
+
+
+Dierks & Allen Standards Track [Page 54]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ (CA). DHE denotes ephemeral Diffie-Hellman, where the Diffie-Hellman
+ parameters are signed by a DSS or RSA certificate, which has been
+ signed by the CA. The signing algorithm used is specified after the
+ DH or DHE parameter. The server can request an RSA or DSS signature-
+ capable certificate from the client for client authentication or it
+ may request a Diffie-Hellman certificate. Any Diffie-Hellman
+ certificate provided by the client must use the parameters (group and
+ generator) described by the server.
+
+ CipherSuite TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = { 0x00,0x0B };
+ CipherSuite TLS_DH_DSS_WITH_DES_CBC_SHA = { 0x00,0x0C };
+ CipherSuite TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA = { 0x00,0x0D };
+ CipherSuite TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA = { 0x00,0x0E };
+ CipherSuite TLS_DH_RSA_WITH_DES_CBC_SHA = { 0x00,0x0F };
+ CipherSuite TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA = { 0x00,0x10 };
+ CipherSuite TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = { 0x00,0x11 };
+ CipherSuite TLS_DHE_DSS_WITH_DES_CBC_SHA = { 0x00,0x12 };
+ CipherSuite TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = { 0x00,0x13 };
+ CipherSuite TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA = { 0x00,0x14 };
+ CipherSuite TLS_DHE_RSA_WITH_DES_CBC_SHA = { 0x00,0x15 };
+ CipherSuite TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = { 0x00,0x16 };
+
+ The following cipher suites are used for completely anonymous
+ Diffie-Hellman communications in which neither party is
+ authenticated. Note that this mode is vulnerable to man-in-the-middle
+ attacks and is therefore deprecated.
+
+ CipherSuite TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 = { 0x00,0x17 };
+ CipherSuite TLS_DH_anon_WITH_RC4_128_MD5 = { 0x00,0x18 };
+ CipherSuite TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA = { 0x00,0x19 };
+ CipherSuite TLS_DH_anon_WITH_DES_CBC_SHA = { 0x00,0x1A };
+ CipherSuite TLS_DH_anon_WITH_3DES_EDE_CBC_SHA = { 0x00,0x1B };
+
+ Note: All cipher suites whose first byte is 0xFF are considered
+ private and can be used for defining local/experimental
+ algorithms. Interoperability of such types is a local matter.
+
+ Note: Additional cipher suites can be registered by publishing an RFC
+ which specifies the cipher suites, including the necessary TLS
+ protocol information, including message encoding, premaster
+ secret derivation, symmetric encryption and MAC calculation and
+ appropriate reference information for the algorithms involved.
+ The RFC editor's office may, at its discretion, choose to publish
+ specifications for cipher suites which are not completely
+ described (e.g., for classified algorithms) if it finds the
+ specification to be of technical interest and completely
+ specified.
+
+
+
+
+Dierks & Allen Standards Track [Page 55]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ Note: The cipher suite values { 0x00, 0x1C } and { 0x00, 0x1D } are
+ reserved to avoid collision with Fortezza-based cipher suites in
+ SSL 3.
+
+A.6. The Security Parameters
+
+ These security parameters are determined by the TLS Handshake
+ Protocol and provided as parameters to the TLS Record Layer in order
+ to initialize a connection state. SecurityParameters includes:
+
+ enum { null(0), (255) } CompressionMethod;
+
+ enum { server, client } ConnectionEnd;
+
+ enum { null, rc4, rc2, des, 3des, des40, idea }
+ BulkCipherAlgorithm;
+
+ enum { stream, block } CipherType;
+
+ enum { true, false } IsExportable;
+
+ enum { null, md5, sha } MACAlgorithm;
+
+ /* The algorithms specified in CompressionMethod,
+ BulkCipherAlgorithm, and MACAlgorithm may be added to. */
+
+ struct {
+ ConnectionEnd entity;
+ BulkCipherAlgorithm bulk_cipher_algorithm;
+ CipherType cipher_type;
+ uint8 key_size;
+ uint8 key_material_length;
+ IsExportable is_exportable;
+ MACAlgorithm mac_algorithm;
+ uint8 hash_size;
+ CompressionMethod compression_algorithm;
+ opaque master_secret[48];
+ opaque client_random[32];
+ opaque server_random[32];
+ } SecurityParameters;
+
+
+
+
+
+
+
+
+
+
+
+Dierks & Allen Standards Track [Page 56]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+B. Glossary
+
+ application protocol
+ An application protocol is a protocol that normally layers
+ directly on top of the transport layer (e.g., TCP/IP). Examples
+ include HTTP, TELNET, FTP, and SMTP.
+
+ asymmetric cipher
+ See public key cryptography.
+
+ authentication
+ Authentication is the ability of one entity to determine the
+ identity of another entity.
+
+ block cipher
+ A block cipher is an algorithm that operates on plaintext in
+ groups of bits, called blocks. 64 bits is a common block size.
+
+ bulk cipher
+ A symmetric encryption algorithm used to encrypt large quantities
+ of data.
+
+ cipher block chaining (CBC)
+ CBC is a mode in which every plaintext block encrypted with a
+ block cipher is first exclusive-ORed with the previous ciphertext
+ block (or, in the case of the first block, with the
+ initialization vector). For decryption, every block is first
+ decrypted, then exclusive-ORed with the previous ciphertext block
+ (or IV).
+
+ certificate
+ As part of the X.509 protocol (a.k.a. ISO Authentication
+ framework), certificates are assigned by a trusted Certificate
+ Authority and provide a strong binding between a party's identity
+ or some other attributes and its public key.
+
+ client
+ The application entity that initiates a TLS connection to a
+ server. This may or may not imply that the client initiated the
+ underlying transport connection. The primary operational
+ difference between the server and client is that the server is
+ generally authenticated, while the client is only optionally
+ authenticated.
+
+ client write key
+ The key used to encrypt data written by the client.
+
+
+
+
+
+Dierks & Allen Standards Track [Page 57]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ client write MAC secret
+ The secret data used to authenticate data written by the client.
+
+ connection
+ A connection is a transport (in the OSI layering model
+ definition) that provides a suitable type of service. For TLS,
+ such connections are peer to peer relationships. The connections
+ are transient. Every connection is associated with one session.
+
+ Data Encryption Standard
+ DES is a very widely used symmetric encryption algorithm. DES is
+ a block cipher with a 56 bit key and an 8 byte block size. Note
+ that in TLS, for key generation purposes, DES is treated as
+ having an 8 byte key length (64 bits), but it still only provides
+ 56 bits of protection. (The low bit of each key byte is presumed
+ to be set to produce odd parity in that key byte.) DES can also
+ be operated in a mode where three independent keys and three
+ encryptions are used for each block of data; this uses 168 bits
+ of key (24 bytes in the TLS key generation method) and provides
+ the equivalent of 112 bits of security. [DES], [3DES]
+
+ Digital Signature Standard (DSS)
+ A standard for digital signing, including the Digital Signing
+ Algorithm, approved by the National Institute of Standards and
+ Technology, defined in NIST FIPS PUB 186, "Digital Signature
+ Standard," published May, 1994 by the U.S. Dept. of Commerce.
+ [DSS]
+
+ digital signatures
+ Digital signatures utilize public key cryptography and one-way
+ hash functions to produce a signature of the data that can be
+ authenticated, and is difficult to forge or repudiate.
+
+ handshake
+ An initial negotiation between client and server that establishes
+ the parameters of their transactions.
+
+ Initialization Vector (IV)
+ When a block cipher is used in CBC mode, the initialization
+ vector is exclusive-ORed with the first plaintext block prior to
+ encryption.
+
+ IDEA
+ A 64-bit block cipher designed by Xuejia Lai and James Massey.
+ [IDEA]
+
+
+
+
+
+
+Dierks & Allen Standards Track [Page 58]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ Message Authentication Code (MAC)
+ A Message Authentication Code is a one-way hash computed from a
+ message and some secret data. It is difficult to forge without
+ knowing the secret data. Its purpose is to detect if the message
+ has been altered.
+
+ master secret
+ Secure secret data used for generating encryption keys, MAC
+ secrets, and IVs.
+
+ MD5
+ MD5 is a secure hashing function that converts an arbitrarily
+ long data stream into a digest of fixed size (16 bytes). [MD5]
+
+ public key cryptography
+ A class of cryptographic techniques employing two-key ciphers.
+ Messages encrypted with the public key can only be decrypted with
+ the associated private key. Conversely, messages signed with the
+ private key can be verified with the public key.
+
+ one-way hash function
+ A one-way transformation that converts an arbitrary amount of
+ data into a fixed-length hash. It is computationally hard to
+ reverse the transformation or to find collisions. MD5 and SHA are
+ examples of one-way hash functions.
+
+ RC2
+ A block cipher developed by Ron Rivest at RSA Data Security, Inc.
+ [RSADSI] described in [RC2].
+
+ RC4
+ A stream cipher licensed by RSA Data Security [RSADSI]. A
+ compatible cipher is described in [RC4].
+
+ RSA
+ A very widely used public-key algorithm that can be used for
+ either encryption or digital signing. [RSA]
+
+ salt
+ Non-secret random data used to make export encryption keys resist
+ precomputation attacks.
+
+ server
+ The server is the application entity that responds to requests
+ for connections from clients. See also under client.
+
+
+
+
+
+
+Dierks & Allen Standards Track [Page 59]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ session
+ A TLS session is an association between a client and a server.
+ Sessions are created by the handshake protocol. Sessions define a
+ set of cryptographic security parameters, which can be shared
+ among multiple connections. Sessions are used to avoid the
+ expensive negotiation of new security parameters for each
+ connection.
+
+ session identifier
+ A session identifier is a value generated by a server that
+ identifies a particular session.
+
+ server write key
+ The key used to encrypt data written by the server.
+
+ server write MAC secret
+ The secret data used to authenticate data written by the server.
+
+ SHA
+ The Secure Hash Algorithm is defined in FIPS PUB 180-1. It
+ produces a 20-byte output. Note that all references to SHA
+ actually use the modified SHA-1 algorithm. [SHA]
+
+ SSL
+ Netscape's Secure Socket Layer protocol [SSL3]. TLS is based on
+ SSL Version 3.0
+
+ stream cipher
+ An encryption algorithm that converts a key into a
+ cryptographically-strong keystream, which is then exclusive-ORed
+ with the plaintext.
+
+ symmetric cipher
+ See bulk cipher.
+
+ Transport Layer Security (TLS)
+ This protocol; also, the Transport Layer Security working group
+ of the Internet Engineering Task Force (IETF). See "Comments" at
+ the end of this document.
+
+
+
+
+
+
+
+
+
+
+
+
+Dierks & Allen Standards Track [Page 60]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+C. CipherSuite definitions
+
+CipherSuite Is Key Cipher Hash
+ Exportable Exchange
+
+TLS_NULL_WITH_NULL_NULL * NULL NULL NULL
+TLS_RSA_WITH_NULL_MD5 * RSA NULL MD5
+TLS_RSA_WITH_NULL_SHA * RSA NULL SHA
+TLS_RSA_EXPORT_WITH_RC4_40_MD5 * RSA_EXPORT RC4_40 MD5
+TLS_RSA_WITH_RC4_128_MD5 RSA RC4_128 MD5
+TLS_RSA_WITH_RC4_128_SHA RSA RC4_128 SHA
+TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 * RSA_EXPORT RC2_CBC_40 MD5
+TLS_RSA_WITH_IDEA_CBC_SHA RSA IDEA_CBC SHA
+TLS_RSA_EXPORT_WITH_DES40_CBC_SHA * RSA_EXPORT DES40_CBC SHA
+TLS_RSA_WITH_DES_CBC_SHA RSA DES_CBC SHA
+TLS_RSA_WITH_3DES_EDE_CBC_SHA RSA 3DES_EDE_CBC SHA
+TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA * DH_DSS_EXPORT DES40_CBC SHA
+TLS_DH_DSS_WITH_DES_CBC_SHA DH_DSS DES_CBC SHA
+TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA DH_DSS 3DES_EDE_CBC SHA
+TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA * DH_RSA_EXPORT DES40_CBC SHA
+TLS_DH_RSA_WITH_DES_CBC_SHA DH_RSA DES_CBC SHA
+TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA DH_RSA 3DES_EDE_CBC SHA
+TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA * DHE_DSS_EXPORT DES40_CBC SHA
+TLS_DHE_DSS_WITH_DES_CBC_SHA DHE_DSS DES_CBC SHA
+TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA DHE_DSS 3DES_EDE_CBC SHA
+TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA * DHE_RSA_EXPORT DES40_CBC SHA
+TLS_DHE_RSA_WITH_DES_CBC_SHA DHE_RSA DES_CBC SHA
+TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA DHE_RSA 3DES_EDE_CBC SHA
+TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 * DH_anon_EXPORT RC4_40 MD5
+TLS_DH_anon_WITH_RC4_128_MD5 DH_anon RC4_128 MD5
+TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA DH_anon DES40_CBC SHA
+TLS_DH_anon_WITH_DES_CBC_SHA DH_anon DES_CBC SHA
+TLS_DH_anon_WITH_3DES_EDE_CBC_SHA DH_anon 3DES_EDE_CBC SHA
+
+
+ * Indicates IsExportable is True
+
+ Key
+ Exchange
+ Algorithm Description Key size limit
+
+ DHE_DSS Ephemeral DH with DSS signatures None
+ DHE_DSS_EXPORT Ephemeral DH with DSS signatures DH = 512 bits
+ DHE_RSA Ephemeral DH with RSA signatures None
+ DHE_RSA_EXPORT Ephemeral DH with RSA signatures DH = 512 bits,
+ RSA = none
+ DH_anon Anonymous DH, no signatures None
+ DH_anon_EXPORT Anonymous DH, no signatures DH = 512 bits
+
+
+
+Dierks & Allen Standards Track [Page 61]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ DH_DSS DH with DSS-based certificates None
+ DH_DSS_EXPORT DH with DSS-based certificates DH = 512 bits
+ DH_RSA DH with RSA-based certificates None
+ DH_RSA_EXPORT DH with RSA-based certificates DH = 512 bits,
+ RSA = none
+ NULL No key exchange N/A
+ RSA RSA key exchange None
+ RSA_EXPORT RSA key exchange RSA = 512 bits
+
+ Key size limit
+ The key size limit gives the size of the largest public key that
+ can be legally used for encryption in cipher suites that are
+ exportable.
+
+ Key Expanded Effective IV Block
+ Cipher Type Material Key Material Key Bits Size Size
+
+ NULL * Stream 0 0 0 0 N/A
+ IDEA_CBC Block 16 16 128 8 8
+ RC2_CBC_40 * Block 5 16 40 8 8
+ RC4_40 * Stream 5 16 40 0 N/A
+ RC4_128 Stream 16 16 128 0 N/A
+ DES40_CBC * Block 5 8 40 8 8
+ DES_CBC Block 8 8 56 8 8
+ 3DES_EDE_CBC Block 24 24 168 8 8
+
+ * Indicates IsExportable is true.
+
+ Type
+ Indicates whether this is a stream cipher or a block cipher
+ running in CBC mode.
+
+ Key Material
+ The number of bytes from the key_block that are used for
+ generating the write keys.
+
+ Expanded Key Material
+ The number of bytes actually fed into the encryption algorithm
+
+ Effective Key Bits
+ How much entropy material is in the key material being fed into
+ the encryption routines.
+
+ IV Size
+ How much data needs to be generated for the initialization
+ vector. Zero for stream ciphers; equal to the block size for
+ block ciphers.
+
+
+
+
+Dierks & Allen Standards Track [Page 62]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ Block Size
+ The amount of data a block cipher enciphers in one chunk; a
+ block cipher running in CBC mode can only encrypt an even
+ multiple of its block size.
+
+ Hash Hash Padding
+ function Size Size
+ NULL 0 0
+ MD5 16 48
+ SHA 20 40
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Dierks & Allen Standards Track [Page 63]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+D. Implementation Notes
+
+ The TLS protocol cannot prevent many common security mistakes. This
+ section provides several recommendations to assist implementors.
+
+D.1. Temporary RSA keys
+
+ US Export restrictions limit RSA keys used for encryption to 512
+ bits, but do not place any limit on lengths of RSA keys used for
+ signing operations. Certificates often need to be larger than 512
+ bits, since 512-bit RSA keys are not secure enough for high-value
+ transactions or for applications requiring long-term security. Some
+ certificates are also designated signing-only, in which case they
+ cannot be used for key exchange.
+
+ When the public key in the certificate cannot be used for encryption,
+ the server signs a temporary RSA key, which is then exchanged. In
+ exportable applications, the temporary RSA key should be the maximum
+ allowable length (i.e., 512 bits). Because 512-bit RSA keys are
+ relatively insecure, they should be changed often. For typical
+ electronic commerce applications, it is suggested that keys be
+ changed daily or every 500 transactions, and more often if possible.
+ Note that while it is acceptable to use the same temporary key for
+ multiple transactions, it must be signed each time it is used.
+
+ RSA key generation is a time-consuming process. In many cases, a
+ low-priority process can be assigned the task of key generation.
+
+ Whenever a new key is completed, the existing temporary key can be
+ replaced with the new one.
+
+D.2. Random Number Generation and Seeding
+
+ TLS requires a cryptographically-secure pseudorandom number generator
+ (PRNG). Care must be taken in designing and seeding PRNGs. PRNGs
+ based on secure hash operations, most notably MD5 and/or SHA, are
+ acceptable, but cannot provide more security than the size of the
+ random number generator state. (For example, MD5-based PRNGs usually
+ provide 128 bits of state.)
+
+ To estimate the amount of seed material being produced, add the
+ number of bits of unpredictable information in each seed byte. For
+ example, keystroke timing values taken from a PC compatible's 18.2 Hz
+ timer provide 1 or 2 secure bits each, even though the total size of
+ the counter value is 16 bits or more. To seed a 128-bit PRNG, one
+ would thus require approximately 100 such timer values.
+
+
+
+
+
+Dierks & Allen Standards Track [Page 64]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ Warning: The seeding functions in RSAREF and versions of BSAFE prior to
+ 3.0 are order-independent. For example, if 1000 seed bits are
+ supplied, one at a time, in 1000 separate calls to the seed
+ function, the PRNG will end up in a state which depends only
+ on the number of 0 or 1 seed bits in the seed data (i.e.,
+ there are 1001 possible final states). Applications using
+ BSAFE or RSAREF must take extra care to ensure proper seeding.
+ This may be accomplished by accumulating seed bits into a
+ buffer and processing them all at once or by processing an
+ incrementing counter with every seed bit; either method will
+ reintroduce order dependence into the seeding process.
+
+D.3. Certificates and authentication
+
+ Implementations are responsible for verifying the integrity of
+ certificates and should generally support certificate revocation
+ messages. Certificates should always be verified to ensure proper
+ signing by a trusted Certificate Authority (CA). The selection and
+ addition of trusted CAs should be done very carefully. Users should
+ be able to view information about the certificate and root CA.
+
+D.4. CipherSuites
+
+ TLS supports a range of key sizes and security levels, including some
+ which provide no or minimal security. A proper implementation will
+ probably not support many cipher suites. For example, 40-bit
+ encryption is easily broken, so implementations requiring strong
+ security should not allow 40-bit keys. Similarly, anonymous Diffie-
+ Hellman is strongly discouraged because it cannot prevent man-in-
+ the-middle attacks. Applications should also enforce minimum and
+ maximum key sizes. For example, certificate chains containing 512-bit
+ RSA keys or signatures are not appropriate for high-security
+ applications.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Dierks & Allen Standards Track [Page 65]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+E. Backward Compatibility With SSL
+
+ For historical reasons and in order to avoid a profligate consumption
+ of reserved port numbers, application protocols which are secured by
+ TLS 1.0, SSL 3.0, and SSL 2.0 all frequently share the same
+ connection port: for example, the https protocol (HTTP secured by SSL
+ or TLS) uses port 443 regardless of which security protocol it is
+ using. Thus, some mechanism must be determined to distinguish and
+ negotiate among the various protocols.
+
+ TLS version 1.0 and SSL 3.0 are very similar; thus, supporting both
+ is easy. TLS clients who wish to negotiate with SSL 3.0 servers
+ should send client hello messages using the SSL 3.0 record format and
+ client hello structure, sending {3, 1} for the version field to note
+ that they support TLS 1.0. If the server supports only SSL 3.0, it
+ will respond with an SSL 3.0 server hello; if it supports TLS, with a
+ TLS server hello. The negotiation then proceeds as appropriate for
+ the negotiated protocol.
+
+ Similarly, a TLS server which wishes to interoperate with SSL 3.0
+ clients should accept SSL 3.0 client hello messages and respond with
+ an SSL 3.0 server hello if an SSL 3.0 client hello is received which
+ has a version field of {3, 0}, denoting that this client does not
+ support TLS.
+
+ Whenever a client already knows the highest protocol known to a
+ server (for example, when resuming a session), it should initiate the
+ connection in that native protocol.
+
+ TLS 1.0 clients that support SSL Version 2.0 servers must send SSL
+ Version 2.0 client hello messages [SSL2]. TLS servers should accept
+ either client hello format if they wish to support SSL 2.0 clients on
+ the same connection port. The only deviations from the Version 2.0
+ specification are the ability to specify a version with a value of
+ three and the support for more ciphering types in the CipherSpec.
+
+ Warning: The ability to send Version 2.0 client hello messages will be
+ phased out with all due haste. Implementors should make every
+ effort to move forward as quickly as possible. Version 3.0
+ provides better mechanisms for moving to newer versions.
+
+ The following cipher specifications are carryovers from SSL Version
+ 2.0. These are assumed to use RSA for key exchange and
+ authentication.
+
+ V2CipherSpec TLS_RC4_128_WITH_MD5 = { 0x01,0x00,0x80 };
+ V2CipherSpec TLS_RC4_128_EXPORT40_WITH_MD5 = { 0x02,0x00,0x80 };
+ V2CipherSpec TLS_RC2_CBC_128_CBC_WITH_MD5 = { 0x03,0x00,0x80 };
+
+
+
+Dierks & Allen Standards Track [Page 66]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ V2CipherSpec TLS_RC2_CBC_128_CBC_EXPORT40_WITH_MD5
+ = { 0x04,0x00,0x80 };
+ V2CipherSpec TLS_IDEA_128_CBC_WITH_MD5 = { 0x05,0x00,0x80 };
+ V2CipherSpec TLS_DES_64_CBC_WITH_MD5 = { 0x06,0x00,0x40 };
+ V2CipherSpec TLS_DES_192_EDE3_CBC_WITH_MD5 = { 0x07,0x00,0xC0 };
+
+ Cipher specifications native to TLS can be included in Version 2.0
+ client hello messages using the syntax below. Any V2CipherSpec
+ element with its first byte equal to zero will be ignored by Version
+ 2.0 servers. Clients sending any of the above V2CipherSpecs should
+ also include the TLS equivalent (see Appendix A.5):
+
+ V2CipherSpec (see TLS name) = { 0x00, CipherSuite };
+
+E.1. Version 2 client hello
+
+ The Version 2.0 client hello message is presented below using this
+ document's presentation model. The true definition is still assumed
+ to be the SSL Version 2.0 specification.
+
+ uint8 V2CipherSpec[3];
+
+ struct {
+ uint8 msg_type;
+ Version version;
+ uint16 cipher_spec_length;
+ uint16 session_id_length;
+ uint16 challenge_length;
+ V2CipherSpec cipher_specs[V2ClientHello.cipher_spec_length];
+ opaque session_id[V2ClientHello.session_id_length];
+ Random challenge;
+ } V2ClientHello;
+
+ msg_type
+ This field, in conjunction with the version field, identifies a
+ version 2 client hello message. The value should be one (1).
+
+ version
+ The highest version of the protocol supported by the client
+ (equals ProtocolVersion.version, see Appendix A.1).
+
+ cipher_spec_length
+ This field is the total length of the field cipher_specs. It
+ cannot be zero and must be a multiple of the V2CipherSpec length
+ (3).
+
+
+
+
+
+
+Dierks & Allen Standards Track [Page 67]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ session_id_length
+ This field must have a value of either zero or 16. If zero, the
+ client is creating a new session. If 16, the session_id field
+ will contain the 16 bytes of session identification.
+
+ challenge_length
+ The length in bytes of the client's challenge to the server to
+ authenticate itself. This value must be 32.
+
+ cipher_specs
+ This is a list of all CipherSpecs the client is willing and able
+ to use. There must be at least one CipherSpec acceptable to the
+ server.
+
+ session_id
+ If this field's length is not zero, it will contain the
+ identification for a session that the client wishes to resume.
+
+ challenge
+ The client challenge to the server for the server to identify
+ itself is a (nearly) arbitrary length random. The TLS server will
+ right justify the challenge data to become the ClientHello.random
+ data (padded with leading zeroes, if necessary), as specified in
+ this protocol specification. If the length of the challenge is
+ greater than 32 bytes, only the last 32 bytes are used. It is
+ legitimate (but not necessary) for a V3 server to reject a V2
+ ClientHello that has fewer than 16 bytes of challenge data.
+
+ Note: Requests to resume a TLS session should use a TLS client hello.
+
+E.2. Avoiding man-in-the-middle version rollback
+
+ When TLS clients fall back to Version 2.0 compatibility mode, they
+ should use special PKCS #1 block formatting. This is done so that TLS
+ servers will reject Version 2.0 sessions with TLS-capable clients.
+
+ When TLS clients are in Version 2.0 compatibility mode, they set the
+ right-hand (least-significant) 8 random bytes of the PKCS padding
+ (not including the terminal null of the padding) for the RSA
+ encryption of the ENCRYPTED-KEY-DATA field of the CLIENT-MASTER-KEY
+ to 0x03 (the other padding bytes are random). After decrypting the
+ ENCRYPTED-KEY-DATA field, servers that support TLS should issue an
+ error if these eight padding bytes are 0x03. Version 2.0 servers
+ receiving blocks padded in this manner will proceed normally.
+
+
+
+
+
+
+
+Dierks & Allen Standards Track [Page 68]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+F. Security analysis
+
+ The TLS protocol is designed to establish a secure connection between
+ a client and a server communicating over an insecure channel. This
+ document makes several traditional assumptions, including that
+ attackers have substantial computational resources and cannot obtain
+ secret information from sources outside the protocol. Attackers are
+ assumed to have the ability to capture, modify, delete, replay, and
+ otherwise tamper with messages sent over the communication channel.
+ This appendix outlines how TLS has been designed to resist a variety
+ of attacks.
+
+F.1. Handshake protocol
+
+ The handshake protocol is responsible for selecting a CipherSpec and
+ generating a Master Secret, which together comprise the primary
+ cryptographic parameters associated with a secure session. The
+ handshake protocol can also optionally authenticate parties who have
+ certificates signed by a trusted certificate authority.
+
+F.1.1. Authentication and key exchange
+
+ TLS supports three authentication modes: authentication of both
+ parties, server authentication with an unauthenticated client, and
+ total anonymity. Whenever the server is authenticated, the channel is
+ secure against man-in-the-middle attacks, but completely anonymous
+ sessions are inherently vulnerable to such attacks. Anonymous
+ servers cannot authenticate clients. If the server is authenticated,
+ its certificate message must provide a valid certificate chain
+ leading to an acceptable certificate authority. Similarly,
+ authenticated clients must supply an acceptable certificate to the
+ server. Each party is responsible for verifying that the other's
+ certificate is valid and has not expired or been revoked.
+
+ The general goal of the key exchange process is to create a
+ pre_master_secret known to the communicating parties and not to
+ attackers. The pre_master_secret will be used to generate the
+ master_secret (see Section 8.1). The master_secret is required to
+ generate the certificate verify and finished messages, encryption
+ keys, and MAC secrets (see Sections 7.4.8, 7.4.9 and 6.3). By sending
+ a correct finished message, parties thus prove that they know the
+ correct pre_master_secret.
+
+F.1.1.1. Anonymous key exchange
+
+ Completely anonymous sessions can be established using RSA or
+ Diffie-Hellman for key exchange. With anonymous RSA, the client
+ encrypts a pre_master_secret with the server's uncertified public key
+
+
+
+Dierks & Allen Standards Track [Page 69]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ extracted from the server key exchange message. The result is sent in
+ a client key exchange message. Since eavesdroppers do not know the
+ server's private key, it will be infeasible for them to decode the
+ pre_master_secret. (Note that no anonymous RSA Cipher Suites are
+ defined in this document).
+
+ With Diffie-Hellman, the server's public parameters are contained in
+ the server key exchange message and the client's are sent in the
+ client key exchange message. Eavesdroppers who do not know the
+ private values should not be able to find the Diffie-Hellman result
+ (i.e. the pre_master_secret).
+
+ Warning: Completely anonymous connections only provide protection
+ against passive eavesdropping. Unless an independent tamper-
+ proof channel is used to verify that the finished messages
+ were not replaced by an attacker, server authentication is
+ required in environments where active man-in-the-middle
+ attacks are a concern.
+
+F.1.1.2. RSA key exchange and authentication
+
+ With RSA, key exchange and server authentication are combined. The
+ public key may be either contained in the server's certificate or may
+ be a temporary RSA key sent in a server key exchange message. When
+ temporary RSA keys are used, they are signed by the server's RSA or
+ DSS certificate. The signature includes the current
+ ClientHello.random, so old signatures and temporary keys cannot be
+ replayed. Servers may use a single temporary RSA key for multiple
+ negotiation sessions.
+
+ Note: The temporary RSA key option is useful if servers need large
+ certificates but must comply with government-imposed size limits
+ on keys used for key exchange.
+
+ After verifying the server's certificate, the client encrypts a
+ pre_master_secret with the server's public key. By successfully
+ decoding the pre_master_secret and producing a correct finished
+ message, the server demonstrates that it knows the private key
+ corresponding to the server certificate.
+
+ When RSA is used for key exchange, clients are authenticated using
+ the certificate verify message (see Section 7.4.8). The client signs
+ a value derived from the master_secret and all preceding handshake
+ messages. These handshake messages include the server certificate,
+ which binds the signature to the server, and ServerHello.random,
+ which binds the signature to the current handshake process.
+
+
+
+
+
+Dierks & Allen Standards Track [Page 70]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+F.1.1.3. Diffie-Hellman key exchange with authentication
+
+ When Diffie-Hellman key exchange is used, the server can either
+ supply a certificate containing fixed Diffie-Hellman parameters or
+ can use the server key exchange message to send a set of temporary
+ Diffie-Hellman parameters signed with a DSS or RSA certificate.
+ Temporary parameters are hashed with the hello.random values before
+ signing to ensure that attackers do not replay old parameters. In
+ either case, the client can verify the certificate or signature to
+ ensure that the parameters belong to the server.
+
+ If the client has a certificate containing fixed Diffie-Hellman
+ parameters, its certificate contains the information required to
+ complete the key exchange. Note that in this case the client and
+ server will generate the same Diffie-Hellman result (i.e.,
+ pre_master_secret) every time they communicate. To prevent the
+ pre_master_secret from staying in memory any longer than necessary,
+ it should be converted into the master_secret as soon as possible.
+ Client Diffie-Hellman parameters must be compatible with those
+ supplied by the server for the key exchange to work.
+
+ If the client has a standard DSS or RSA certificate or is
+ unauthenticated, it sends a set of temporary parameters to the server
+ in the client key exchange message, then optionally uses a
+ certificate verify message to authenticate itself.
+
+F.1.2. Version rollback attacks
+
+ Because TLS includes substantial improvements over SSL Version 2.0,
+ attackers may try to make TLS-capable clients and servers fall back
+ to Version 2.0. This attack can occur if (and only if) two TLS-
+ capable parties use an SSL 2.0 handshake.
+
+ Although the solution using non-random PKCS #1 block type 2 message
+ padding is inelegant, it provides a reasonably secure way for Version
+ 3.0 servers to detect the attack. This solution is not secure against
+ attackers who can brute force the key and substitute a new
+ ENCRYPTED-KEY-DATA message containing the same key (but with normal
+ padding) before the application specified wait threshold has expired.
+ Parties concerned about attacks of this scale should not be using
+ 40-bit encryption keys anyway. Altering the padding of the least-
+ significant 8 bytes of the PKCS padding does not impact security for
+ the size of the signed hashes and RSA key lengths used in the
+ protocol, since this is essentially equivalent to increasing the
+ input block size by 8 bytes.
+
+
+
+
+
+
+Dierks & Allen Standards Track [Page 71]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+F.1.3. Detecting attacks against the handshake protocol
+
+ An attacker might try to influence the handshake exchange to make the
+ parties select different encryption algorithms than they would
+ normally choose. Because many implementations will support 40-bit
+ exportable encryption and some may even support null encryption or
+ MAC algorithms, this attack is of particular concern.
+
+ For this attack, an attacker must actively change one or more
+ handshake messages. If this occurs, the client and server will
+ compute different values for the handshake message hashes. As a
+ result, the parties will not accept each others' finished messages.
+ Without the master_secret, the attacker cannot repair the finished
+ messages, so the attack will be discovered.
+
+F.1.4. Resuming sessions
+
+ When a connection is established by resuming a session, new
+ ClientHello.random and ServerHello.random values are hashed with the
+ session's master_secret. Provided that the master_secret has not been
+ compromised and that the secure hash operations used to produce the
+ encryption keys and MAC secrets are secure, the connection should be
+ secure and effectively independent from previous connections.
+ Attackers cannot use known encryption keys or MAC secrets to
+ compromise the master_secret without breaking the secure hash
+ operations (which use both SHA and MD5).
+
+ Sessions cannot be resumed unless both the client and server agree.
+ If either party suspects that the session may have been compromised,
+ or that certificates may have expired or been revoked, it should
+ force a full handshake. An upper limit of 24 hours is suggested for
+ session ID lifetimes, since an attacker who obtains a master_secret
+ may be able to impersonate the compromised party until the
+ corresponding session ID is retired. Applications that may be run in
+ relatively insecure environments should not write session IDs to
+ stable storage.
+
+F.1.5. MD5 and SHA
+
+ TLS uses hash functions very conservatively. Where possible, both MD5
+ and SHA are used in tandem to ensure that non-catastrophic flaws in
+ one algorithm will not break the overall protocol.
+
+F.2. Protecting application data
+
+ The master_secret is hashed with the ClientHello.random and
+ ServerHello.random to produce unique data encryption keys and MAC
+ secrets for each connection.
+
+
+
+Dierks & Allen Standards Track [Page 72]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ Outgoing data is protected with a MAC before transmission. To prevent
+ message replay or modification attacks, the MAC is computed from the
+ MAC secret, the sequence number, the message length, the message
+ contents, and two fixed character strings. The message type field is
+ necessary to ensure that messages intended for one TLS Record Layer
+ client are not redirected to another. The sequence number ensures
+ that attempts to delete or reorder messages will be detected. Since
+ sequence numbers are 64-bits long, they should never overflow.
+ Messages from one party cannot be inserted into the other's output,
+ since they use independent MAC secrets. Similarly, the server-write
+ and client-write keys are independent so stream cipher keys are used
+ only once.
+
+ If an attacker does break an encryption key, all messages encrypted
+ with it can be read. Similarly, compromise of a MAC key can make
+ message modification attacks possible. Because MACs are also
+ encrypted, message-alteration attacks generally require breaking the
+ encryption algorithm as well as the MAC.
+
+ Note: MAC secrets may be larger than encryption keys, so messages can
+ remain tamper resistant even if encryption keys are broken.
+
+F.3. Final notes
+
+ For TLS to be able to provide a secure connection, both the client
+ and server systems, keys, and applications must be secure. In
+ addition, the implementation must be free of security errors.
+
+ The system is only as strong as the weakest key exchange and
+ authentication algorithm supported, and only trustworthy
+ cryptographic functions should be used. Short public keys, 40-bit
+ bulk encryption keys, and anonymous servers should be used with great
+ caution. Implementations and users must be careful when deciding
+ which certificates and certificate authorities are acceptable; a
+ dishonest certificate authority can do tremendous damage.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Dierks & Allen Standards Track [Page 73]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+G. Patent Statement
+
+ Some of the cryptographic algorithms proposed for use in this
+ protocol have patent claims on them. In addition Netscape
+ Communications Corporation has a patent claim on the Secure Sockets
+ Layer (SSL) work that this standard is based on. The Internet
+ Standards Process as defined in RFC 2026 requests that a statement be
+ obtained from a Patent holder indicating that a license will be made
+ available to applicants under reasonable terms and conditions.
+
+ The Massachusetts Institute of Technology has granted RSA Data
+ Security, Inc., exclusive sub-licensing rights to the following
+ patent issued in the United States:
+
+ Cryptographic Communications System and Method ("RSA"), No.
+ 4,405,829
+
+ Netscape Communications Corporation has been issued the following
+ patent in the United States:
+
+ Secure Socket Layer Application Program Apparatus And Method
+ ("SSL"), No. 5,657,390
+
+ Netscape Communications has issued the following statement:
+
+ Intellectual Property Rights
+
+ Secure Sockets Layer
+
+ The United States Patent and Trademark Office ("the PTO")
+ recently issued U.S. Patent No. 5,657,390 ("the SSL Patent") to
+ Netscape for inventions described as Secure Sockets Layers
+ ("SSL"). The IETF is currently considering adopting SSL as a
+ transport protocol with security features. Netscape encourages
+ the royalty-free adoption and use of the SSL protocol upon the
+ following terms and conditions:
+
+ * If you already have a valid SSL Ref license today which
+ includes source code from Netscape, an additional patent
+ license under the SSL patent is not required.
+
+ * If you don't have an SSL Ref license, you may have a royalty
+ free license to build implementations covered by the SSL
+ Patent Claims or the IETF TLS specification provided that you
+ do not to assert any patent rights against Netscape or other
+ companies for the implementation of SSL or the IETF TLS
+ recommendation.
+
+
+
+
+Dierks & Allen Standards Track [Page 74]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ What are "Patent Claims":
+
+ Patent claims are claims in an issued foreign or domestic patent
+ that:
+
+ 1) must be infringed in order to implement methods or build
+ products according to the IETF TLS specification; or
+
+ 2) patent claims which require the elements of the SSL patent
+ claims and/or their equivalents to be infringed.
+
+ The Internet Society, Internet Architecture Board, Internet
+ Engineering Steering Group and the Corporation for National Research
+ Initiatives take no position on the validity or scope of the patents
+ and patent applications, nor on the appropriateness of the terms of
+ the assurance. The Internet Society and other groups mentioned above
+ have not made any determination as to any other intellectual property
+ rights which may apply to the practice of this standard. Any further
+ consideration of these matters is the user's own responsibility.
+
+Security Considerations
+
+ Security issues are discussed throughout this memo.
+
+References
+
+ [3DES] W. Tuchman, "Hellman Presents No Shortcut Solutions To DES,"
+ IEEE Spectrum, v. 16, n. 7, July 1979, pp40-41.
+
+ [BLEI] Bleichenbacher D., "Chosen Ciphertext Attacks against
+ Protocols Based on RSA Encryption Standard PKCS #1" in
+ Advances in Cryptology -- CRYPTO'98, LNCS vol. 1462, pages:
+ 1--12, 1998.
+
+ [DES] ANSI X3.106, "American National Standard for Information
+ Systems-Data Link Encryption," American National Standards
+ Institute, 1983.
+
+ [DH1] W. Diffie and M. E. Hellman, "New Directions in
+ Cryptography," IEEE Transactions on Information Theory, V.
+ IT-22, n. 6, Jun 1977, pp. 74-84.
+
+ [DSS] NIST FIPS PUB 186, "Digital Signature Standard," National
+ Institute of Standards and Technology, U.S. Department of
+ Commerce, May 18, 1994.
+
+ [FTP] Postel J., and J. Reynolds, "File Transfer Protocol", STD 9,
+ RFC 959, October 1985.
+
+
+
+Dierks & Allen Standards Track [Page 75]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ [HTTP] Berners-Lee, T., Fielding, R., and H. Frystyk, "Hypertext
+ Transfer Protocol -- HTTP/1.0", RFC 1945, May 1996.
+
+ [HMAC] Krawczyk, H., Bellare, M., and R. Canetti, "HMAC: Keyed-
+ Hashing for Message Authentication," RFC 2104, February
+ 1997.
+
+ [IDEA] X. Lai, "On the Design and Security of Block Ciphers," ETH
+ Series in Information Processing, v. 1, Konstanz: Hartung-
+ Gorre Verlag, 1992.
+
+ [MD2] Kaliski, B., "The MD2 Message Digest Algorithm", RFC 1319,
+ April 1992.
+
+ [MD5] Rivest, R., "The MD5 Message Digest Algorithm", RFC 1321,
+ April 1992.
+
+ [PKCS1] RSA Laboratories, "PKCS #1: RSA Encryption Standard,"
+ version 1.5, November 1993.
+
+ [PKCS6] RSA Laboratories, "PKCS #6: RSA Extended Certificate Syntax
+ Standard," version 1.5, November 1993.
+
+ [PKCS7] RSA Laboratories, "PKCS #7: RSA Cryptographic Message Syntax
+ Standard," version 1.5, November 1993.
+
+ [PKIX] Housley, R., Ford, W., Polk, W. and D. Solo, "Internet
+ Public Key Infrastructure: Part I: X.509 Certificate and CRL
+ Profile", RFC 2459, January 1999.
+
+ [RC2] Rivest, R., "A Description of the RC2(r) Encryption
+ Algorithm", RFC 2268, January 1998.
+
+ [RC4] Thayer, R. and K. Kaukonen, A Stream Cipher Encryption
+ Algorithm, Work in Progress.
+
+ [RSA] R. Rivest, A. Shamir, and L. M. Adleman, "A Method for
+ Obtaining Digital Signatures and Public-Key Cryptosystems,"
+ Communications of the ACM, v. 21, n. 2, Feb 1978, pp. 120-
+ 126.
+
+ [RSADSI] Contact RSA Data Security, Inc., Tel: 415-595-8782
+
+ [SCH] B. Schneier. Applied Cryptography: Protocols, Algorithms,
+ and Source Code in C, Published by John Wiley & Sons, Inc.
+ 1994.
+
+
+
+
+
+Dierks & Allen Standards Track [Page 76]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ [SHA] NIST FIPS PUB 180-1, "Secure Hash Standard," National
+ Institute of Standards and Technology, U.S. Department of
+ Commerce, Work in Progress, May 31, 1994.
+
+ [SSL2] Hickman, Kipp, "The SSL Protocol", Netscape Communications
+ Corp., Feb 9, 1995.
+
+ [SSL3] A. Frier, P. Karlton, and P. Kocher, "The SSL 3.0 Protocol",
+ Netscape Communications Corp., Nov 18, 1996.
+
+ [TCP] Postel, J., "Transmission Control Protocol," STD 7, RFC 793,
+ September 1981.
+
+ [TEL] Postel J., and J. Reynolds, "Telnet Protocol
+ Specifications", STD 8, RFC 854, May 1993.
+
+ [TEL] Postel J., and J. Reynolds, "Telnet Option Specifications",
+ STD 8, RFC 855, May 1993.
+
+ [X509] CCITT. Recommendation X.509: "The Directory - Authentication
+ Framework". 1988.
+
+ [XDR] R. Srinivansan, Sun Microsystems, RFC-1832: XDR: External
+ Data Representation Standard, August 1995.
+
+Credits
+
+ Win Treese
+ Open Market
+
+ EMail: treese@openmarket.com
+
+
+ Editors
+
+ Christopher Allen Tim Dierks
+ Certicom Certicom
+
+ EMail: callen@certicom.com EMail: tdierks@certicom.com
+
+
+ Authors' Addresses
+
+ Tim Dierks Philip L. Karlton
+ Certicom Netscape Communications
+
+ EMail: tdierks@certicom.com
+
+
+
+
+Dierks & Allen Standards Track [Page 77]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ Alan O. Freier Paul C. Kocher
+ Netscape Communications Independent Consultant
+
+ EMail: freier@netscape.com EMail: pck@netcom.com
+
+
+ Other contributors
+
+ Martin Abadi Robert Relyea
+ Digital Equipment Corporation Netscape Communications
+
+ EMail: ma@pa.dec.com EMail: relyea@netscape.com
+
+ Ran Canetti Jim Roskind
+ IBM Watson Research Center Netscape Communications
+
+ EMail: canetti@watson.ibm.com EMail: jar@netscape.com
+
+
+ Taher Elgamal Micheal J. Sabin, Ph. D.
+ Securify Consulting Engineer
+
+ EMail: elgamal@securify.com EMail: msabin@netcom.com
+
+
+ Anil R. Gangolli Dan Simon
+ Structured Arts Computing Corp. Microsoft
+
+ EMail: gangolli@structuredarts.com EMail: dansimon@microsoft.com
+
+
+ Kipp E.B. Hickman Tom Weinstein
+ Netscape Communications Netscape Communications
+
+ EMail: kipp@netscape.com EMail: tomw@netscape.com
+
+
+ Hugo Krawczyk
+ IBM Watson Research Center
+
+ EMail: hugo@watson.ibm.com
+
+Comments
+
+ The discussion list for the IETF TLS working group is located at the
+ e-mail address <ietf-tls@lists.consensus.com>. Information on the
+ group and information on how to subscribe to the list is at
+ <http://lists.consensus.com/>.
+
+
+
+Dierks & Allen Standards Track [Page 78]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ Archives of the list can be found at:
+ <http://www.imc.org/ietf-tls/mail-archive/>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Dierks & Allen Standards Track [Page 79]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Dierks & Allen Standards Track [Page 80]
+
diff --git a/standards/rfc2396.txt b/standards/rfc2396.txt
new file mode 100644
index 000000000..5bd52110a
--- /dev/null
+++ b/standards/rfc2396.txt
@@ -0,0 +1,2243 @@
+
+
+
+
+
+
+Network Working Group T. Berners-Lee
+Request for Comments: 2396 MIT/LCS
+Updates: 1808, 1738 R. Fielding
+Category: Standards Track U.C. Irvine
+ L. Masinter
+ Xerox Corporation
+ August 1998
+
+
+ Uniform Resource Identifiers (URI): Generic Syntax
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (1998). All Rights Reserved.
+
+IESG Note
+
+ This paper describes a "superset" of operations that can be applied
+ to URI. It consists of both a grammar and a description of basic
+ functionality for URI. To understand what is a valid URI, both the
+ grammar and the associated description have to be studied. Some of
+ the functionality described is not applicable to all URI schemes, and
+ some operations are only possible when certain media types are
+ retrieved using the URI, regardless of the scheme used.
+
+Abstract
+
+ A Uniform Resource Identifier (URI) is a compact string of characters
+ for identifying an abstract or physical resource. This document
+ defines the generic syntax of URI, including both absolute and
+ relative forms, and guidelines for their use; it revises and replaces
+ the generic definitions in RFC 1738 and RFC 1808.
+
+ This document defines a grammar that is a superset of all valid URI,
+ such that an implementation can parse the common components of a URI
+ reference without knowing the scheme-specific requirements of every
+ possible identifier type. This document does not define a generative
+ grammar for URI; that task will be performed by the individual
+ specifications of each URI scheme.
+
+
+
+
+Berners-Lee, et. al. Standards Track [Page 1]
+
+RFC 2396 URI Generic Syntax August 1998
+
+
+1. Introduction
+
+ Uniform Resource Identifiers (URI) provide a simple and extensible
+ means for identifying a resource. This specification of URI syntax
+ and semantics is derived from concepts introduced by the World Wide
+ Web global information initiative, whose use of such objects dates
+ from 1990 and is described in "Universal Resource Identifiers in WWW"
+ [RFC1630]. The specification of URI is designed to meet the
+ recommendations laid out in "Functional Recommendations for Internet
+ Resource Locators" [RFC1736] and "Functional Requirements for Uniform
+ Resource Names" [RFC1737].
+
+ This document updates and merges "Uniform Resource Locators"
+ [RFC1738] and "Relative Uniform Resource Locators" [RFC1808] in order
+ to define a single, generic syntax for all URI. It excludes those
+ portions of RFC 1738 that defined the specific syntax of individual
+ URL schemes; those portions will be updated as separate documents, as
+ will the process for registration of new URI schemes. This document
+ does not discuss the issues and recommendation for dealing with
+ characters outside of the US-ASCII character set [ASCII]; those
+ recommendations are discussed in a separate document.
+
+ All significant changes from the prior RFCs are noted in Appendix G.
+
+1.1 Overview of URI
+
+ URI are characterized by the following definitions:
+
+ Uniform
+ Uniformity provides several benefits: it allows different types
+ of resource identifiers to be used in the same context, even
+ when the mechanisms used to access those resources may differ;
+ it allows uniform semantic interpretation of common syntactic
+ conventions across different types of resource identifiers; it
+ allows introduction of new types of resource identifiers
+ without interfering with the way that existing identifiers are
+ used; and, it allows the identifiers to be reused in many
+ different contexts, thus permitting new applications or
+ protocols to leverage a pre-existing, large, and widely-used
+ set of resource identifiers.
+
+ Resource
+ A resource can be anything that has identity. Familiar
+ examples include an electronic document, an image, a service
+ (e.g., "today's weather report for Los Angeles"), and a
+ collection of other resources. Not all resources are network
+ "retrievable"; e.g., human beings, corporations, and bound
+ books in a library can also be considered resources.
+
+
+
+Berners-Lee, et. al. Standards Track [Page 2]
+
+RFC 2396 URI Generic Syntax August 1998
+
+
+ The resource is the conceptual mapping to an entity or set of
+ entities, not necessarily the entity which corresponds to that
+ mapping at any particular instance in time. Thus, a resource
+ can remain constant even when its content---the entities to
+ which it currently corresponds---changes over time, provided
+ that the conceptual mapping is not changed in the process.
+
+ Identifier
+ An identifier is an object that can act as a reference to
+ something that has identity. In the case of URI, the object is
+ a sequence of characters with a restricted syntax.
+
+ Having identified a resource, a system may perform a variety of
+ operations on the resource, as might be characterized by such words
+ as `access', `update', `replace', or `find attributes'.
+
+1.2. URI, URL, and URN
+
+ A URI can be further classified as a locator, a name, or both. The
+ term "Uniform Resource Locator" (URL) refers to the subset of URI
+ that identify resources via a representation of their primary access
+ mechanism (e.g., their network "location"), rather than identifying
+ the resource by name or by some other attribute(s) of that resource.
+ The term "Uniform Resource Name" (URN) refers to the subset of URI
+ that are required to remain globally unique and persistent even when
+ the resource ceases to exist or becomes unavailable.
+
+ The URI scheme (Section 3.1) defines the namespace of the URI, and
+ thus may further restrict the syntax and semantics of identifiers
+ using that scheme. This specification defines those elements of the
+ URI syntax that are either required of all URI schemes or are common
+ to many URI schemes. It thus defines the syntax and semantics that
+ are needed to implement a scheme-independent parsing mechanism for
+ URI references, such that the scheme-dependent handling of a URI can
+ be postponed until the scheme-dependent semantics are needed. We use
+ the term URL below when describing syntax or semantics that only
+ apply to locators.
+
+ Although many URL schemes are named after protocols, this does not
+ imply that the only way to access the URL's resource is via the named
+ protocol. Gateways, proxies, caches, and name resolution services
+ might be used to access some resources, independent of the protocol
+ of their origin, and the resolution of some URL may require the use
+ of more than one protocol (e.g., both DNS and HTTP are typically used
+ to access an "http" URL's resource when it can't be found in a local
+ cache).
+
+
+
+
+
+Berners-Lee, et. al. Standards Track [Page 3]
+
+RFC 2396 URI Generic Syntax August 1998
+
+
+ A URN differs from a URL in that it's primary purpose is persistent
+ labeling of a resource with an identifier. That identifier is drawn
+ from one of a set of defined namespaces, each of which has its own
+ set name structure and assignment procedures. The "urn" scheme has
+ been reserved to establish the requirements for a standardized URN
+ namespace, as defined in "URN Syntax" [RFC2141] and its related
+ specifications.
+
+ Most of the examples in this specification demonstrate URL, since
+ they allow the most varied use of the syntax and often have a
+ hierarchical namespace. A parser of the URI syntax is capable of
+ parsing both URL and URN references as a generic URI; once the scheme
+ is determined, the scheme-specific parsing can be performed on the
+ generic URI components. In other words, the URI syntax is a superset
+ of the syntax of all URI schemes.
+
+1.3. Example URI
+
+ The following examples illustrate URI that are in common use.
+
+ ftp://ftp.is.co.za/rfc/rfc1808.txt
+ -- ftp scheme for File Transfer Protocol services
+
+ gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles
+ -- gopher scheme for Gopher and Gopher+ Protocol services
+
+ http://www.math.uio.no/faq/compression-faq/part1.html
+ -- http scheme for Hypertext Transfer Protocol services
+
+ mailto:mduerst@ifi.unizh.ch
+ -- mailto scheme for electronic mail addresses
+
+ news:comp.infosystems.www.servers.unix
+ -- news scheme for USENET news groups and articles
+
+ telnet://melvyl.ucop.edu/
+ -- telnet scheme for interactive services via the TELNET Protocol
+
+1.4. Hierarchical URI and Relative Forms
+
+ An absolute identifier refers to a resource independent of the
+ context in which the identifier is used. In contrast, a relative
+ identifier refers to a resource by describing the difference within a
+ hierarchical namespace between the current context and an absolute
+ identifier of the resource.
+
+
+
+
+
+
+Berners-Lee, et. al. Standards Track [Page 4]
+
+RFC 2396 URI Generic Syntax August 1998
+
+
+ Some URI schemes support a hierarchical naming system, where the
+ hierarchy of the name is denoted by a "/" delimiter separating the
+ components in the scheme. This document defines a scheme-independent
+ `relative' form of URI reference that can be used in conjunction with
+ a `base' URI (of a hierarchical scheme) to produce another URI. The
+ syntax of hierarchical URI is described in Section 3; the relative
+ URI calculation is described in Section 5.
+
+1.5. URI Transcribability
+
+ The URI syntax was designed with global transcribability as one of
+ its main concerns. A URI is a sequence of characters from a very
+ limited set, i.e. the letters of the basic Latin alphabet, digits,
+ and a few special characters. A URI may be represented in a variety
+ of ways: e.g., ink on paper, pixels on a screen, or a sequence of
+ octets in a coded character set. The interpretation of a URI depends
+ only on the characters used and not how those characters are
+ represented in a network protocol.
+
+ The goal of transcribability can be described by a simple scenario.
+ Imagine two colleagues, Sam and Kim, sitting in a pub at an
+ international conference and exchanging research ideas. Sam asks Kim
+ for a location to get more information, so Kim writes the URI for the
+ research site on a napkin. Upon returning home, Sam takes out the
+ napkin and types the URI into a computer, which then retrieves the
+ information to which Kim referred.
+
+ There are several design concerns revealed by the scenario:
+
+ o A URI is a sequence of characters, which is not always
+ represented as a sequence of octets.
+
+ o A URI may be transcribed from a non-network source, and thus
+ should consist of characters that are most likely to be able to
+ be typed into a computer, within the constraints imposed by
+ keyboards (and related input devices) across languages and
+ locales.
+
+ o A URI often needs to be remembered by people, and it is easier
+ for people to remember a URI when it consists of meaningful
+ components.
+
+ These design concerns are not always in alignment. For example, it
+ is often the case that the most meaningful name for a URI component
+ would require characters that cannot be typed into some systems. The
+ ability to transcribe the resource identifier from one medium to
+ another was considered more important than having its URI consist of
+ the most meaningful of components. In local and regional contexts
+
+
+
+Berners-Lee, et. al. Standards Track [Page 5]
+
+RFC 2396 URI Generic Syntax August 1998
+
+
+ and with improving technology, users might benefit from being able to
+ use a wider range of characters; such use is not defined in this
+ document.
+
+1.6. Syntax Notation and Common Elements
+
+ This document uses two conventions to describe and define the syntax
+ for URI. The first, called the layout form, is a general description
+ of the order of components and component separators, as in
+
+ <first>/<second>;<third>?<fourth>
+
+ The component names are enclosed in angle-brackets and any characters
+ outside angle-brackets are literal separators. Whitespace should be
+ ignored. These descriptions are used informally and do not define
+ the syntax requirements.
+
+ The second convention is a BNF-like grammar, used to define the
+ formal URI syntax. The grammar is that of [RFC822], except that "|"
+ is used to designate alternatives. Briefly, rules are separated from
+ definitions by an equal "=", indentation is used to continue a rule
+ definition over more than one line, literals are quoted with "",
+ parentheses "(" and ")" are used to group elements, optional elements
+ are enclosed in "[" and "]" brackets, and elements may be preceded
+ with <n>* to designate n or more repetitions of the following
+ element; n defaults to 0.
+
+ Unlike many specifications that use a BNF-like grammar to define the
+ bytes (octets) allowed by a protocol, the URI grammar is defined in
+ terms of characters. Each literal in the grammar corresponds to the
+ character it represents, rather than to the octet encoding of that
+ character in any particular coded character set. How a URI is
+ represented in terms of bits and bytes on the wire is dependent upon
+ the character encoding of the protocol used to transport it, or the
+ charset of the document which contains it.
+
+ The following definitions are common to many elements:
+
+ alpha = lowalpha | upalpha
+
+ lowalpha = "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"
+
+ upalpha = "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"
+
+
+
+
+Berners-Lee, et. al. Standards Track [Page 6]
+
+RFC 2396 URI Generic Syntax August 1998
+
+
+ digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" |
+ "8" | "9"
+
+ alphanum = alpha | digit
+
+ The complete URI syntax is collected in Appendix A.
+
+2. URI Characters and Escape Sequences
+
+ URI consist of a restricted set of characters, primarily chosen to
+ aid transcribability and usability both in computer systems and in
+ non-computer communications. Characters used conventionally as
+ delimiters around URI were excluded. The restricted set of
+ characters consists of digits, letters, and a few graphic symbols
+ were chosen from those common to most of the character encodings and
+ input facilities available to Internet users.
+
+ uric = reserved | unreserved | escaped
+
+ Within a URI, characters are either used as delimiters, or to
+ represent strings of data (octets) within the delimited portions.
+ Octets are either represented directly by a character (using the US-
+ ASCII character for that octet [ASCII]) or by an escape encoding.
+ This representation is elaborated below.
+
+2.1 URI and non-ASCII characters
+
+ The relationship between URI and characters has been a source of
+ confusion for characters that are not part of US-ASCII. To describe
+ the relationship, it is useful to distinguish between a "character"
+ (as a distinguishable semantic entity) and an "octet" (an 8-bit
+ byte). There are two mappings, one from URI characters to octets, and
+ a second from octets to original characters:
+
+ URI character sequence->octet sequence->original character sequence
+
+ A URI is represented as a sequence of characters, not as a sequence
+ of octets. That is because URI might be "transported" by means that
+ are not through a computer network, e.g., printed on paper, read over
+ the radio, etc.
+
+ A URI scheme may define a mapping from URI characters to octets;
+ whether this is done depends on the scheme. Commonly, within a
+ delimited component of a URI, a sequence of characters may be used to
+ represent a sequence of octets. For example, the character "a"
+ represents the octet 97 (decimal), while the character sequence "%",
+ "0", "a" represents the octet 10 (decimal).
+
+
+
+
+Berners-Lee, et. al. Standards Track [Page 7]
+
+RFC 2396 URI Generic Syntax August 1998
+
+
+ There is a second translation for some resources: the sequence of
+ octets defined by a component of the URI is subsequently used to
+ represent a sequence of characters. A 'charset' defines this mapping.
+ There are many charsets in use in Internet protocols. For example,
+ UTF-8 [UTF-8] defines a mapping from sequences of octets to sequences
+ of characters in the repertoire of ISO 10646.
+
+ In the simplest case, the original character sequence contains only
+ characters that are defined in US-ASCII, and the two levels of
+ mapping are simple and easily invertible: each 'original character'
+ is represented as the octet for the US-ASCII code for it, which is,
+ in turn, represented as either the US-ASCII character, or else the
+ "%" escape sequence for that octet.
+
+ For original character sequences that contain non-ASCII characters,
+ however, the situation is more difficult. Internet protocols that
+ transmit octet sequences intended to represent character sequences
+ are expected to provide some way of identifying the charset used, if
+ there might be more than one [RFC2277]. However, there is currently
+ no provision within the generic URI syntax to accomplish this
+ identification. An individual URI scheme may require a single
+ charset, define a default charset, or provide a way to indicate the
+ charset used.
+
+ It is expected that a systematic treatment of character encoding
+ within URI will be developed as a future modification of this
+ specification.
+
+2.2. Reserved Characters
+
+ Many URI include components consisting of or delimited by, certain
+ special characters. These characters are called "reserved", since
+ their usage within the URI component is limited to their reserved
+ purpose. If the data for a URI component would conflict with the
+ reserved purpose, then the conflicting data must be escaped before
+ forming the URI.
+
+ reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
+ "$" | ","
+
+ The "reserved" syntax class above refers to those characters that are
+ allowed within a URI, but which may not be allowed within a
+ particular component of the generic URI syntax; they are used as
+ delimiters of the components described in Section 3.
+
+
+
+
+
+
+
+Berners-Lee, et. al. Standards Track [Page 8]
+
+RFC 2396 URI Generic Syntax August 1998
+
+
+ Characters in the "reserved" set are not reserved in all contexts.
+ The set of characters actually reserved within any given URI
+ component is defined by that component. In general, a character is
+ reserved if the semantics of the URI changes if the character is
+ replaced with its escaped US-ASCII encoding.
+
+2.3. Unreserved Characters
+
+ Data characters that are allowed in a URI but do not have a reserved
+ purpose are called unreserved. These include upper and lower case
+ letters, decimal digits, and a limited set of punctuation marks and
+ symbols.
+
+ unreserved = alphanum | mark
+
+ mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
+
+ Unreserved characters can be escaped without changing the semantics
+ of the URI, but this should not be done unless the URI is being used
+ in a context that does not allow the unescaped character to appear.
+
+2.4. Escape Sequences
+
+ Data must be escaped if it does not have a representation using an
+ unreserved character; this includes data that does not correspond to
+ a printable character of the US-ASCII coded character set, or that
+ corresponds to any US-ASCII character that is disallowed, as
+ explained below.
+
+2.4.1. Escaped Encoding
+
+ An escaped octet is encoded as a character triplet, consisting of the
+ percent character "%" followed by the two hexadecimal digits
+ representing the octet code. For example, "%20" is the escaped
+ encoding for the US-ASCII space character.
+
+ escaped = "%" hex hex
+ hex = digit | "A" | "B" | "C" | "D" | "E" | "F" |
+ "a" | "b" | "c" | "d" | "e" | "f"
+
+2.4.2. When to Escape and Unescape
+
+ A URI is always in an "escaped" form, since escaping or unescaping a
+ completed URI might change its semantics. Normally, the only time
+ escape encodings can safely be made is when the URI is being created
+ from its component parts; each component may have its own set of
+ characters that are reserved, so only the mechanism responsible for
+ generating or interpreting that component can determine whether or
+
+
+
+Berners-Lee, et. al. Standards Track [Page 9]
+
+RFC 2396 URI Generic Syntax August 1998
+
+
+ not escaping a character will change its semantics. Likewise, a URI
+ must be separated into its components before the escaped characters
+ within those components can be safely decoded.
+
+ In some cases, data that could be represented by an unreserved
+ character may appear escaped; for example, some of the unreserved
+ "mark" characters are automatically escaped by some systems. If the
+ given URI scheme defines a canonicalization algorithm, then
+ unreserved characters may be unescaped according to that algorithm.
+ For example, "%7e" is sometimes used instead of "~" in an http URL
+ path, but the two are equivalent for an http URL.
+
+ Because the percent "%" character always has the reserved purpose of
+ being the escape indicator, it must be escaped as "%25" in order to
+ be used as data within a URI. Implementers should be careful not to
+ escape or unescape the same string more than once, since unescaping
+ an already unescaped string might lead to misinterpreting a percent
+ data character as another escaped character, or vice versa in the
+ case of escaping an already escaped string.
+
+2.4.3. Excluded US-ASCII Characters
+
+ Although they are disallowed within the URI syntax, we include here a
+ description of those US-ASCII characters that have been excluded and
+ the reasons for their exclusion.
+
+ The control characters in the US-ASCII coded character set are not
+ used within a URI, both because they are non-printable and because
+ they are likely to be misinterpreted by some control mechanisms.
+
+ control = <US-ASCII coded characters 00-1F and 7F hexadecimal>
+
+ The space character is excluded because significant spaces may
+ disappear and insignificant spaces may be introduced when URI are
+ transcribed or typeset or subjected to the treatment of word-
+ processing programs. Whitespace is also used to delimit URI in many
+ contexts.
+
+ space = <US-ASCII coded character 20 hexadecimal>
+
+ The angle-bracket "<" and ">" and double-quote (") characters are
+ excluded because they are often used as the delimiters around URI in
+ text documents and protocol fields. The character "#" is excluded
+ because it is used to delimit a URI from a fragment identifier in URI
+ references (Section 4). The percent character "%" is excluded because
+ it is used for the encoding of escaped characters.
+
+ delims = "<" | ">" | "#" | "%" | <">
+
+
+
+Berners-Lee, et. al. Standards Track [Page 10]
+
+RFC 2396 URI Generic Syntax August 1998
+
+
+ Other characters are excluded because gateways and other transport
+ agents are known to sometimes modify such characters, or they are
+ used as delimiters.
+
+ unwise = "{" | "}" | "|" | "\" | "^" | "[" | "]" | "`"
+
+ Data corresponding to excluded characters must be escaped in order to
+ be properly represented within a URI.
+
+3. URI Syntactic Components
+
+ The URI syntax is dependent upon the scheme. In general, absolute
+ URI are written as follows:
+
+ <scheme>:<scheme-specific-part>
+
+ An absolute URI contains the name of the scheme being used (<scheme>)
+ followed by a colon (":") and then a string (the <scheme-specific-
+ part>) whose interpretation depends on the scheme.
+
+ The URI syntax does not require that the scheme-specific-part have
+ any general structure or set of semantics which is common among all
+ URI. However, a subset of URI do share a common syntax for
+ representing hierarchical relationships within the namespace. This
+ "generic URI" syntax consists of a sequence of four main components:
+
+ <scheme>://<authority><path>?<query>
+
+ each of which, except <scheme>, may be absent from a particular URI.
+ For example, some URI schemes do not allow an <authority> component,
+ and others do not use a <query> component.
+
+ absoluteURI = scheme ":" ( hier_part | opaque_part )
+
+ URI that are hierarchical in nature use the slash "/" character for
+ separating hierarchical components. For some file systems, a "/"
+ character (used to denote the hierarchical structure of a URI) is the
+ delimiter used to construct a file name hierarchy, and thus the URI
+ path will look similar to a file pathname. This does NOT imply that
+ the resource is a file or that the URI maps to an actual filesystem
+ pathname.
+
+ hier_part = ( net_path | abs_path ) [ "?" query ]
+
+ net_path = "//" authority [ abs_path ]
+
+ abs_path = "/" path_segments
+
+
+
+
+Berners-Lee, et. al. Standards Track [Page 11]
+
+RFC 2396 URI Generic Syntax August 1998
+
+
+ URI that do not make use of the slash "/" character for separating
+ hierarchical components are considered opaque by the generic URI
+ parser.
+
+ opaque_part = uric_no_slash *uric
+
+ uric_no_slash = unreserved | escaped | ";" | "?" | ":" | "@" |
+ "&" | "=" | "+" | "$" | ","
+
+ We use the term <path> to refer to both the <abs_path> and
+ <opaque_part> constructs, since they are mutually exclusive for any
+ given URI and can be parsed as a single component.
+
+3.1. Scheme Component
+
+ Just as there are many different methods of access to resources,
+ there are a variety of schemes for identifying such resources. The
+ URI syntax consists of a sequence of components separated by reserved
+ characters, with the first component defining the semantics for the
+ remainder of the URI string.
+
+ Scheme names consist of a sequence of characters beginning with a
+ lower case letter and followed by any combination of lower case
+ letters, digits, plus ("+"), period ("."), or hyphen ("-"). For
+ resiliency, programs interpreting URI should treat upper case letters
+ as equivalent to lower case in scheme names (e.g., allow "HTTP" as
+ well as "http").
+
+ scheme = alpha *( alpha | digit | "+" | "-" | "." )
+
+ Relative URI references are distinguished from absolute URI in that
+ they do not begin with a scheme name. Instead, the scheme is
+ inherited from the base URI, as described in Section 5.2.
+
+3.2. Authority Component
+
+ Many URI schemes include a top hierarchical element for a naming
+ authority, such that the namespace defined by the remainder of the
+ URI is governed by that authority. This authority component is
+ typically defined by an Internet-based server or a scheme-specific
+ registry of naming authorities.
+
+ authority = server | reg_name
+
+ The authority component is preceded by a double slash "//" and is
+ terminated by the next slash "/", question-mark "?", or by the end of
+ the URI. Within the authority component, the characters ";", ":",
+ "@", "?", and "/" are reserved.
+
+
+
+Berners-Lee, et. al. Standards Track [Page 12]
+
+RFC 2396 URI Generic Syntax August 1998
+
+
+ An authority component is not required for a URI scheme to make use
+ of relative references. A base URI without an authority component
+ implies that any relative reference will also be without an authority
+ component.
+
+3.2.1. Registry-based Naming Authority
+
+ The structure of a registry-based naming authority is specific to the
+ URI scheme, but constrained to the allowed characters for an
+ authority component.
+
+ reg_name = 1*( unreserved | escaped | "$" | "," |
+ ";" | ":" | "@" | "&" | "=" | "+" )
+
+3.2.2. Server-based Naming Authority
+
+ URL schemes that involve the direct use of an IP-based protocol to a
+ specified server on the Internet use a common syntax for the server
+ component of the URI's scheme-specific data:
+
+ <userinfo>@<host>:<port>
+
+ where <userinfo> may consist of a user name and, optionally, scheme-
+ specific information about how to gain authorization to access the
+ server. The parts "<userinfo>@" and ":<port>" may be omitted.
+
+ server = [ [ userinfo "@" ] hostport ]
+
+ The user information, if present, is followed by a commercial at-sign
+ "@".
+
+ userinfo = *( unreserved | escaped |
+ ";" | ":" | "&" | "=" | "+" | "$" | "," )
+
+ Some URL schemes use the format "user:password" in the userinfo
+ field. This practice is NOT RECOMMENDED, because the passing of
+ authentication information in clear text (such as URI) has proven to
+ be a security risk in almost every case where it has been used.
+
+ The host is a domain name of a network host, or its IPv4 address as a
+ set of four decimal digit groups separated by ".". Literal IPv6
+ addresses are not supported.
+
+ hostport = host [ ":" port ]
+ host = hostname | IPv4address
+ hostname = *( domainlabel "." ) toplabel [ "." ]
+ domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum
+ toplabel = alpha | alpha *( alphanum | "-" ) alphanum
+
+
+
+Berners-Lee, et. al. Standards Track [Page 13]
+
+RFC 2396 URI Generic Syntax August 1998
+
+
+ IPv4address = 1*digit "." 1*digit "." 1*digit "." 1*digit
+ port = *digit
+
+ Hostnames take the form described in Section 3 of [RFC1034] and
+ Section 2.1 of [RFC1123]: a sequence of domain labels separated by
+ ".", each domain label starting and ending with an alphanumeric
+ character and possibly also containing "-" characters. The rightmost
+ domain label of a fully qualified domain name will never start with a
+ digit, thus syntactically distinguishing domain names from IPv4
+ addresses, and may be followed by a single "." if it is necessary to
+ distinguish between the complete domain name and any local domain.
+ To actually be "Uniform" as a resource locator, a URL hostname should
+ be a fully qualified domain name. In practice, however, the host
+ component may be a local domain literal.
+
+ Note: A suitable representation for including a literal IPv6
+ address as the host part of a URL is desired, but has not yet been
+ determined or implemented in practice.
+
+ The port is the network port number for the server. Most schemes
+ designate protocols that have a default port number. Another port
+ number may optionally be supplied, in decimal, separated from the
+ host by a colon. If the port is omitted, the default port number is
+ assumed.
+
+3.3. Path Component
+
+ The path component contains data, specific to the authority (or the
+ scheme if there is no authority component), identifying the resource
+ within the scope of that scheme and authority.
+
+ path = [ abs_path | opaque_part ]
+
+ path_segments = segment *( "/" segment )
+ segment = *pchar *( ";" param )
+ param = *pchar
+
+ pchar = unreserved | escaped |
+ ":" | "@" | "&" | "=" | "+" | "$" | ","
+
+ The path may consist of a sequence of path segments separated by a
+ single slash "/" character. Within a path segment, the characters
+ "/", ";", "=", and "?" are reserved. Each path segment may include a
+ sequence of parameters, indicated by the semicolon ";" character.
+ The parameters are not significant to the parsing of relative
+ references.
+
+
+
+
+
+Berners-Lee, et. al. Standards Track [Page 14]
+
+RFC 2396 URI Generic Syntax August 1998
+
+
+3.4. Query Component
+
+ The query component is a string of information to be interpreted by
+ the resource.
+
+ query = *uric
+
+ Within a query component, the characters ";", "/", "?", ":", "@",
+ "&", "=", "+", ",", and "$" are reserved.
+
+4. URI References
+
+ The term "URI-reference" is used here to denote the common usage of a
+ resource identifier. A URI reference may be absolute or relative,
+ and may have additional information attached in the form of a
+ fragment identifier. However, "the URI" that results from such a
+ reference includes only the absolute URI after the fragment
+ identifier (if any) is removed and after any relative URI is resolved
+ to its absolute form. Although it is possible to limit the
+ discussion of URI syntax and semantics to that of the absolute
+ result, most usage of URI is within general URI references, and it is
+ impossible to obtain the URI from such a reference without also
+ parsing the fragment and resolving the relative form.
+
+ URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
+
+ The syntax for relative URI is a shortened form of that for absolute
+ URI, where some prefix of the URI is missing and certain path
+ components ("." and "..") have a special meaning when, and only when,
+ interpreting a relative path. The relative URI syntax is defined in
+ Section 5.
+
+4.1. Fragment Identifier
+
+ When a URI reference is used to perform a retrieval action on the
+ identified resource, the optional fragment identifier, separated from
+ the URI by a crosshatch ("#") character, consists of additional
+ reference information to be interpreted by the user agent after the
+ retrieval action has been successfully completed. As such, it is not
+ part of a URI, but is often used in conjunction with a URI.
+
+ fragment = *uric
+
+ The semantics of a fragment identifier is a property of the data
+ resulting from a retrieval action, regardless of the type of URI used
+ in the reference. Therefore, the format and interpretation of
+ fragment identifiers is dependent on the media type [RFC2046] of the
+ retrieval result. The character restrictions described in Section 2
+
+
+
+Berners-Lee, et. al. Standards Track [Page 15]
+
+RFC 2396 URI Generic Syntax August 1998
+
+
+ for URI also apply to the fragment in a URI-reference. Individual
+ media types may define additional restrictions or structure within
+ the fragment for specifying different types of "partial views" that
+ can be identified within that media type.
+
+ A fragment identifier is only meaningful when a URI reference is
+ intended for retrieval and the result of that retrieval is a document
+ for which the identified fragment is consistently defined.
+
+4.2. Same-document References
+
+ A URI reference that does not contain a URI is a reference to the
+ current document. In other words, an empty URI reference within a
+ document is interpreted as a reference to the start of that document,
+ and a reference containing only a fragment identifier is a reference
+ to the identified fragment of that document. Traversal of such a
+ reference should not result in an additional retrieval action.
+ However, if the URI reference occurs in a context that is always
+ intended to result in a new request, as in the case of HTML's FORM
+ element, then an empty URI reference represents the base URI of the
+ current document and should be replaced by that URI when transformed
+ into a request.
+
+4.3. Parsing a URI Reference
+
+ A URI reference is typically parsed according to the four main
+ components and fragment identifier in order to determine what
+ components are present and whether the reference is relative or
+ absolute. The individual components are then parsed for their
+ subparts and, if not opaque, to verify their validity.
+
+ Although the BNF defines what is allowed in each component, it is
+ ambiguous in terms of differentiating between an authority component
+ and a path component that begins with two slash characters. The
+ greedy algorithm is used for disambiguation: the left-most matching
+ rule soaks up as much of the URI reference string as it is capable of
+ matching. In other words, the authority component wins.
+
+ Readers familiar with regular expressions should see Appendix B for a
+ concrete parsing example and test oracle.
+
+5. Relative URI References
+
+ It is often the case that a group or "tree" of documents has been
+ constructed to serve a common purpose; the vast majority of URI in
+ these documents point to resources within the tree rather than
+
+
+
+
+
+Berners-Lee, et. al. Standards Track [Page 16]
+
+RFC 2396 URI Generic Syntax August 1998
+
+
+ outside of it. Similarly, documents located at a particular site are
+ much more likely to refer to other resources at that site than to
+ resources at remote sites.
+
+ Relative addressing of URI allows document trees to be partially
+ independent of their location and access scheme. For instance, it is
+ possible for a single set of hypertext documents to be simultaneously
+ accessible and traversable via each of the "file", "http", and "ftp"
+ schemes if the documents refer to each other using relative URI.
+ Furthermore, such document trees can be moved, as a whole, without
+ changing any of the relative references. Experience within the WWW
+ has demonstrated that the ability to perform relative referencing is
+ necessary for the long-term usability of embedded URI.
+
+ The syntax for relative URI takes advantage of the <hier_part> syntax
+ of <absoluteURI> (Section 3) in order to express a reference that is
+ relative to the namespace of another hierarchical URI.
+
+ relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ]
+
+ A relative reference beginning with two slash characters is termed a
+ network-path reference, as defined by <net_path> in Section 3. Such
+ references are rarely used.
+
+ A relative reference beginning with a single slash character is
+ termed an absolute-path reference, as defined by <abs_path> in
+ Section 3.
+
+ A relative reference that does not begin with a scheme name or a
+ slash character is termed a relative-path reference.
+
+ rel_path = rel_segment [ abs_path ]
+
+ rel_segment = 1*( unreserved | escaped |
+ ";" | "@" | "&" | "=" | "+" | "$" | "," )
+
+ Within a relative-path reference, the complete path segments "." and
+ ".." have special meanings: "the current hierarchy level" and "the
+ level above this hierarchy level", respectively. Although this is
+ very similar to their use within Unix-based filesystems to indicate
+ directory levels, these path components are only considered special
+ when resolving a relative-path reference to its absolute form
+ (Section 5.2).
+
+ Authors should be aware that a path segment which contains a colon
+ character cannot be used as the first segment of a relative URI path
+ (e.g., "this:that"), because it would be mistaken for a scheme name.
+
+
+
+
+Berners-Lee, et. al. Standards Track [Page 17]
+
+RFC 2396 URI Generic Syntax August 1998
+
+
+ It is therefore necessary to precede such segments with other
+ segments (e.g., "./this:that") in order for them to be referenced as
+ a relative path.
+
+ It is not necessary for all URI within a given scheme to be
+ restricted to the <hier_part> syntax, since the hierarchical
+ properties of that syntax are only necessary when relative URI are
+ used within a particular document. Documents can only make use of
+ relative URI when their base URI fits within the <hier_part> syntax.
+ It is assumed that any document which contains a relative reference
+ will also have a base URI that obeys the syntax. In other words,
+ relative URI cannot be used within a document that has an unsuitable
+ base URI.
+
+ Some URI schemes do not allow a hierarchical syntax matching the
+ <hier_part> syntax, and thus cannot use relative references.
+
+5.1. Establishing a Base URI
+
+ The term "relative URI" implies that there exists some absolute "base
+ URI" against which the relative reference is applied. Indeed, the
+ base URI is necessary to define the semantics of any relative URI
+ reference; without it, a relative reference is meaningless. In order
+ for relative URI to be usable within a document, the base URI of that
+ document must be known to the parser.
+
+ The base URI of a document can be established in one of four ways,
+ listed below in order of precedence. The order of precedence can be
+ thought of in terms of layers, where the innermost defined base URI
+ has the highest precedence. This can be visualized graphically as:
+
+ .----------------------------------------------------------.
+ | .----------------------------------------------------. |
+ | | .----------------------------------------------. | |
+ | | | .----------------------------------------. | | |
+ | | | | .----------------------------------. | | | |
+ | | | | | <relative_reference> | | | | |
+ | | | | `----------------------------------' | | | |
+ | | | | (5.1.1) Base URI embedded in the | | | |
+ | | | | document's content | | | |
+ | | | `----------------------------------------' | | |
+ | | | (5.1.2) Base URI of the encapsulating entity | | |
+ | | | (message, document, or none). | | |
+ | | `----------------------------------------------' | |
+ | | (5.1.3) URI used to retrieve the entity | |
+ | `----------------------------------------------------' |
+ | (5.1.4) Default Base URI is application-dependent |
+ `----------------------------------------------------------'
+
+
+
+Berners-Lee, et. al. Standards Track [Page 18]
+
+RFC 2396 URI Generic Syntax August 1998
+
+
+5.1.1. Base URI within Document Content
+
+ Within certain document media types, the base URI of the document can
+ be embedded within the content itself such that it can be readily
+ obtained by a parser. This can be useful for descriptive documents,
+ such as tables of content, which may be transmitted to others through
+ protocols other than their usual retrieval context (e.g., E-Mail or
+ USENET news).
+
+ It is beyond the scope of this document to specify how, for each
+ media type, the base URI can be embedded. It is assumed that user
+ agents manipulating such media types will be able to obtain the
+ appropriate syntax from that media type's specification. An example
+ of how the base URI can be embedded in the Hypertext Markup Language
+ (HTML) [RFC1866] is provided in Appendix D.
+
+ A mechanism for embedding the base URI within MIME container types
+ (e.g., the message and multipart types) is defined by MHTML
+ [RFC2110]. Protocols that do not use the MIME message header syntax,
+ but which do allow some form of tagged metainformation to be included
+ within messages, may define their own syntax for defining the base
+ URI as part of a message.
+
+5.1.2. Base URI from the Encapsulating Entity
+
+ If no base URI is embedded, the base URI of a document is defined by
+ the document's retrieval context. For a document that is enclosed
+ within another entity (such as a message or another document), the
+ retrieval context is that entity; thus, the default base URI of the
+ document is the base URI of the entity in which the document is
+ encapsulated.
+
+5.1.3. Base URI from the Retrieval URI
+
+ If no base URI is embedded and the document is not encapsulated
+ within some other entity (e.g., the top level of a composite entity),
+ then, if a URI was used to retrieve the base document, that URI shall
+ be considered the base URI. Note that if the retrieval was the
+ result of a redirected request, the last URI used (i.e., that which
+ resulted in the actual retrieval of the document) is the base URI.
+
+5.1.4. Default Base URI
+
+ If none of the conditions described in Sections 5.1.1--5.1.3 apply,
+ then the base URI is defined by the context of the application.
+ Since this definition is necessarily application-dependent, failing
+
+
+
+
+
+Berners-Lee, et. al. Standards Track [Page 19]
+
+RFC 2396 URI Generic Syntax August 1998
+
+
+ to define the base URI using one of the other methods may result in
+ the same content being interpreted differently by different types of
+ application.
+
+ It is the responsibility of the distributor(s) of a document
+ containing relative URI to ensure that the base URI for that document
+ can be established. It must be emphasized that relative URI cannot
+ be used reliably in situations where the document's base URI is not
+ well-defined.
+
+5.2. Resolving Relative References to Absolute Form
+
+ This section describes an example algorithm for resolving URI
+ references that might be relative to a given base URI.
+
+ The base URI is established according to the rules of Section 5.1 and
+ parsed into the four main components as described in Section 3. Note
+ that only the scheme component is required to be present in the base
+ URI; the other components may be empty or undefined. A component is
+ undefined if its preceding separator does not appear in the URI
+ reference; the path component is never undefined, though it may be
+ empty. The base URI's query component is not used by the resolution
+ algorithm and may be discarded.
+
+ For each URI reference, the following steps are performed in order:
+
+ 1) The URI reference is parsed into the potential four components and
+ fragment identifier, as described in Section 4.3.
+
+ 2) If the path component is empty and the scheme, authority, and
+ query components are undefined, then it is a reference to the
+ current document and we are done. Otherwise, the reference URI's
+ query and fragment components are defined as found (or not found)
+ within the URI reference and not inherited from the base URI.
+
+ 3) If the scheme component is defined, indicating that the reference
+ starts with a scheme name, then the reference is interpreted as an
+ absolute URI and we are done. Otherwise, the reference URI's
+ scheme is inherited from the base URI's scheme component.
+
+ Due to a loophole in prior specifications [RFC1630], some parsers
+ allow the scheme name to be present in a relative URI if it is the
+ same as the base URI scheme. Unfortunately, this can conflict
+ with the correct parsing of non-hierarchical URI. For backwards
+ compatibility, an implementation may work around such references
+ by removing the scheme if it matches that of the base URI and the
+ scheme is known to always use the <hier_part> syntax. The parser
+
+
+
+
+Berners-Lee, et. al. Standards Track [Page 20]
+
+RFC 2396 URI Generic Syntax August 1998
+
+
+ can then continue with the steps below for the remainder of the
+ reference components. Validating parsers should mark such a
+ misformed relative reference as an error.
+
+ 4) If the authority component is defined, then the reference is a
+ network-path and we skip to step 7. Otherwise, the reference
+ URI's authority is inherited from the base URI's authority
+ component, which will also be undefined if the URI scheme does not
+ use an authority component.
+
+ 5) If the path component begins with a slash character ("/"), then
+ the reference is an absolute-path and we skip to step 7.
+
+ 6) If this step is reached, then we are resolving a relative-path
+ reference. The relative path needs to be merged with the base
+ URI's path. Although there are many ways to do this, we will
+ describe a simple method using a separate string buffer.
+
+ a) All but the last segment of the base URI's path component is
+ copied to the buffer. In other words, any characters after the
+ last (right-most) slash character, if any, are excluded.
+
+ b) The reference's path component is appended to the buffer
+ string.
+
+ c) All occurrences of "./", where "." is a complete path segment,
+ are removed from the buffer string.
+
+ d) If the buffer string ends with "." as a complete path segment,
+ that "." is removed.
+
+ e) All occurrences of "<segment>/../", where <segment> is a
+ complete path segment not equal to "..", are removed from the
+ buffer string. Removal of these path segments is performed
+ iteratively, removing the leftmost matching pattern on each
+ iteration, until no matching pattern remains.
+
+ f) If the buffer string ends with "<segment>/..", where <segment>
+ is a complete path segment not equal to "..", that
+ "<segment>/.." is removed.
+
+ g) If the resulting buffer string still begins with one or more
+ complete path segments of "..", then the reference is
+ considered to be in error. Implementations may handle this
+ error by retaining these components in the resolved path (i.e.,
+ treating them as part of the final URI), by removing them from
+ the resolved path (i.e., discarding relative levels above the
+ root), or by avoiding traversal of the reference.
+
+
+
+Berners-Lee, et. al. Standards Track [Page 21]
+
+RFC 2396 URI Generic Syntax August 1998
+
+
+ h) The remaining buffer string is the reference URI's new path
+ component.
+
+ 7) The resulting URI components, including any inherited from the
+ base URI, are recombined to give the absolute form of the URI
+ reference. Using pseudocode, this would be
+
+ result = ""
+
+ if scheme is defined then
+ append scheme to result
+ append ":" to result
+
+ if authority is defined then
+ append "//" to result
+ append authority to result
+
+ append path to result
+
+ if query is defined then
+ append "?" to result
+ append query to result
+
+ if fragment is defined then
+ append "#" to result
+ append fragment to result
+
+ return result
+
+ Note that we must be careful to preserve the distinction between a
+ component that is undefined, meaning that its separator was not
+ present in the reference, and a component that is empty, meaning
+ that the separator was present and was immediately followed by the
+ next component separator or the end of the reference.
+
+ The above algorithm is intended to provide an example by which the
+ output of implementations can be tested -- implementation of the
+ algorithm itself is not required. For example, some systems may find
+ it more efficient to implement step 6 as a pair of segment stacks
+ being merged, rather than as a series of string pattern replacements.
+
+ Note: Some WWW client applications will fail to separate the
+ reference's query component from its path component before merging
+ the base and reference paths in step 6 above. This may result in
+ a loss of information if the query component contains the strings
+ "/../" or "/./".
+
+ Resolution examples are provided in Appendix C.
+
+
+
+Berners-Lee, et. al. Standards Track [Page 22]
+
+RFC 2396 URI Generic Syntax August 1998
+
+
+6. URI Normalization and Equivalence
+
+ In many cases, different URI strings may actually identify the
+ identical resource. For example, the host names used in URL are
+ actually case insensitive, and the URL <http://www.XEROX.com> is
+ equivalent to <http://www.xerox.com>. In general, the rules for
+ equivalence and definition of a normal form, if any, are scheme
+ dependent. When a scheme uses elements of the common syntax, it will
+ also use the common syntax equivalence rules, namely that the scheme
+ and hostname are case insensitive and a URL with an explicit ":port",
+ where the port is the default for the scheme, is equivalent to one
+ where the port is elided.
+
+7. Security Considerations
+
+ A URI does not in itself pose a security threat. Users should beware
+ that there is no general guarantee that a URL, which at one time
+ located a given resource, will continue to do so. Nor is there any
+ guarantee that a URL will not locate a different resource at some
+ later point in time, due to the lack of any constraint on how a given
+ authority apportions its namespace. Such a guarantee can only be
+ obtained from the person(s) controlling that namespace and the
+ resource in question. A specific URI scheme may include additional
+ semantics, such as name persistence, if those semantics are required
+ of all naming authorities for that scheme.
+
+ It is sometimes possible to construct a URL such that an attempt to
+ perform a seemingly harmless, idempotent operation, such as the
+ retrieval of an entity associated with the resource, will in fact
+ cause a possibly damaging remote operation to occur. The unsafe URL
+ is typically constructed by specifying a port number other than that
+ reserved for the network protocol in question. The client
+ unwittingly contacts a site that is in fact running a different
+ protocol. The content of the URL contains instructions that, when
+ interpreted according to this other protocol, cause an unexpected
+ operation. An example has been the use of a gopher URL to cause an
+ unintended or impersonating message to be sent via a SMTP server.
+
+ Caution should be used when using any URL that specifies a port
+ number other than the default for the protocol, especially when it is
+ a number within the reserved space.
+
+ Care should be taken when a URL contains escaped delimiters for a
+ given protocol (for example, CR and LF characters for telnet
+ protocols) that these are not unescaped before transmission. This
+ might violate the protocol, but avoids the potential for such
+
+
+
+
+
+Berners-Lee, et. al. Standards Track [Page 23]
+
+RFC 2396 URI Generic Syntax August 1998
+
+
+ characters to be used to simulate an extra operation or parameter in
+ that protocol, which might lead to an unexpected and possibly harmful
+ remote operation to be performed.
+
+ It is clearly unwise to use a URL that contains a password which is
+ intended to be secret. In particular, the use of a password within
+ the 'userinfo' component of a URL is strongly disrecommended except
+ in those rare cases where the 'password' parameter is intended to be
+ public.
+
+8. Acknowledgements
+
+ This document was derived from RFC 1738 [RFC1738] and RFC 1808
+ [RFC1808]; the acknowledgements in those specifications still apply.
+ In addition, contributions by Gisle Aas, Martin Beet, Martin Duerst,
+ Jim Gettys, Martijn Koster, Dave Kristol, Daniel LaLiberte, Foteos
+ Macrides, James Marshall, Ryan Moats, Keith Moore, and Lauren Wood
+ are gratefully acknowledged.
+
+9. References
+
+ [RFC2277] Alvestrand, H., "IETF Policy on Character Sets and
+ Languages", BCP 18, RFC 2277, January 1998.
+
+ [RFC1630] Berners-Lee, T., "Universal Resource Identifiers in WWW: A
+ Unifying Syntax for the Expression of Names and Addresses
+ of Objects on the Network as used in the World-Wide Web",
+ RFC 1630, June 1994.
+
+ [RFC1738] Berners-Lee, T., Masinter, L., and M. McCahill, Editors,
+ "Uniform Resource Locators (URL)", RFC 1738, December 1994.
+
+ [RFC1866] Berners-Lee T., and D. Connolly, "HyperText Markup Language
+ Specification -- 2.0", RFC 1866, November 1995.
+
+ [RFC1123] Braden, R., Editor, "Requirements for Internet Hosts --
+ Application and Support", STD 3, RFC 1123, October 1989.
+
+ [RFC822] Crocker, D., "Standard for the Format of ARPA Internet Text
+ Messages", STD 11, RFC 822, August 1982.
+
+ [RFC1808] Fielding, R., "Relative Uniform Resource Locators", RFC
+ 1808, June 1995.
+
+ [RFC2046] Freed, N., and N. Borenstein, "Multipurpose Internet Mail
+ Extensions (MIME) Part Two: Media Types", RFC 2046,
+ November 1996.
+
+
+
+
+Berners-Lee, et. al. Standards Track [Page 24]
+
+RFC 2396 URI Generic Syntax August 1998
+
+
+ [RFC1736] Kunze, J., "Functional Recommendations for Internet
+ Resource Locators", RFC 1736, February 1995.
+
+ [RFC2141] Moats, R., "URN Syntax", RFC 2141, May 1997.
+
+ [RFC1034] Mockapetris, P., "Domain Names - Concepts and Facilities",
+ STD 13, RFC 1034, November 1987.
+
+ [RFC2110] Palme, J., and A. Hopmann, "MIME E-mail Encapsulation of
+ Aggregate Documents, such as HTML (MHTML)", RFC 2110, March
+ 1997.
+
+ [RFC1737] Sollins, K., and L. Masinter, "Functional Requirements for
+ Uniform Resource Names", RFC 1737, December 1994.
+
+ [ASCII] US-ASCII. "Coded Character Set -- 7-bit American Standard
+ Code for Information Interchange", ANSI X3.4-1986.
+
+ [UTF-8] Yergeau, F., "UTF-8, a transformation format of ISO 10646",
+ RFC 2279, January 1998.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Berners-Lee, et. al. Standards Track [Page 25]
+
+RFC 2396 URI Generic Syntax August 1998
+
+
+10. Authors' Addresses
+
+ Tim Berners-Lee
+ World Wide Web Consortium
+ MIT Laboratory for Computer Science, NE43-356
+ 545 Technology Square
+ Cambridge, MA 02139
+
+ Fax: +1(617)258-8682
+ EMail: timbl@w3.org
+
+
+ Roy T. Fielding
+ Department of Information and Computer Science
+ University of California, Irvine
+ Irvine, CA 92697-3425
+
+ Fax: +1(949)824-1715
+ EMail: fielding@ics.uci.edu
+
+
+ Larry Masinter
+ Xerox PARC
+ 3333 Coyote Hill Road
+ Palo Alto, CA 94034
+
+ Fax: +1(415)812-4333
+ EMail: masinter@parc.xerox.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Berners-Lee, et. al. Standards Track [Page 26]
+
+RFC 2396 URI Generic Syntax August 1998
+
+
+A. Collected BNF for URI
+
+ URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
+ absoluteURI = scheme ":" ( hier_part | opaque_part )
+ relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ]
+
+ hier_part = ( net_path | abs_path ) [ "?" query ]
+ opaque_part = uric_no_slash *uric
+
+ uric_no_slash = unreserved | escaped | ";" | "?" | ":" | "@" |
+ "&" | "=" | "+" | "$" | ","
+
+ net_path = "//" authority [ abs_path ]
+ abs_path = "/" path_segments
+ rel_path = rel_segment [ abs_path ]
+
+ rel_segment = 1*( unreserved | escaped |
+ ";" | "@" | "&" | "=" | "+" | "$" | "," )
+
+ scheme = alpha *( alpha | digit | "+" | "-" | "." )
+
+ authority = server | reg_name
+
+ reg_name = 1*( unreserved | escaped | "$" | "," |
+ ";" | ":" | "@" | "&" | "=" | "+" )
+
+ server = [ [ userinfo "@" ] hostport ]
+ userinfo = *( unreserved | escaped |
+ ";" | ":" | "&" | "=" | "+" | "$" | "," )
+
+ hostport = host [ ":" port ]
+ host = hostname | IPv4address
+ hostname = *( domainlabel "." ) toplabel [ "." ]
+ domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum
+ toplabel = alpha | alpha *( alphanum | "-" ) alphanum
+ IPv4address = 1*digit "." 1*digit "." 1*digit "." 1*digit
+ port = *digit
+
+ path = [ abs_path | opaque_part ]
+ path_segments = segment *( "/" segment )
+ segment = *pchar *( ";" param )
+ param = *pchar
+ pchar = unreserved | escaped |
+ ":" | "@" | "&" | "=" | "+" | "$" | ","
+
+ query = *uric
+
+ fragment = *uric
+
+
+
+Berners-Lee, et. al. Standards Track [Page 27]
+
+RFC 2396 URI Generic Syntax August 1998
+
+
+ uric = reserved | unreserved | escaped
+ reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
+ "$" | ","
+ unreserved = alphanum | mark
+ mark = "-" | "_" | "." | "!" | "~" | "*" | "'" |
+ "(" | ")"
+
+ escaped = "%" hex hex
+ hex = digit | "A" | "B" | "C" | "D" | "E" | "F" |
+ "a" | "b" | "c" | "d" | "e" | "f"
+
+ alphanum = alpha | digit
+ alpha = lowalpha | upalpha
+
+ lowalpha = "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"
+ upalpha = "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"
+ digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" |
+ "8" | "9"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Berners-Lee, et. al. Standards Track [Page 28]
+
+RFC 2396 URI Generic Syntax August 1998
+
+
+B. Parsing a URI Reference with a Regular Expression
+
+ As described in Section 4.3, the generic URI syntax is not sufficient
+ to disambiguate the components of some forms of URI. Since the
+ "greedy algorithm" described in that section is identical to the
+ disambiguation method used by POSIX regular expressions, it is
+ natural and commonplace to use a regular expression for parsing the
+ potential four components and fragment identifier of a URI reference.
+
+ The following line is the regular expression for breaking-down a URI
+ reference into its components.
+
+ ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
+ 12 3 4 5 6 7 8 9
+
+ The numbers in the second line above are only to assist readability;
+ they indicate the reference points for each subexpression (i.e., each
+ paired parenthesis). We refer to the value matched for subexpression
+ <n> as $<n>. For example, matching the above expression to
+
+ http://www.ics.uci.edu/pub/ietf/uri/#Related
+
+ results in the following subexpression matches:
+
+ $1 = http:
+ $2 = http
+ $3 = //www.ics.uci.edu
+ $4 = www.ics.uci.edu
+ $5 = /pub/ietf/uri/
+ $6 = <undefined>
+ $7 = <undefined>
+ $8 = #Related
+ $9 = Related
+
+ where <undefined> indicates that the component is not present, as is
+ the case for the query component in the above example. Therefore, we
+ can determine the value of the four components and fragment as
+
+ scheme = $2
+ authority = $4
+ path = $5
+ query = $7
+ fragment = $9
+
+ and, going in the opposite direction, we can recreate a URI reference
+ from its components using the algorithm in step 7 of Section 5.2.
+
+
+
+
+
+Berners-Lee, et. al. Standards Track [Page 29]
+
+RFC 2396 URI Generic Syntax August 1998
+
+
+C. Examples of Resolving Relative URI References
+
+ Within an object with a well-defined base URI of
+
+ http://a/b/c/d;p?q
+
+ the relative URI would be resolved as follows:
+
+C.1. Normal Examples
+
+ g:h = g:h
+ g = http://a/b/c/g
+ ./g = http://a/b/c/g
+ g/ = http://a/b/c/g/
+ /g = http://a/g
+ //g = http://g
+ ?y = http://a/b/c/?y
+ g?y = http://a/b/c/g?y
+ #s = (current document)#s
+ g#s = http://a/b/c/g#s
+ g?y#s = http://a/b/c/g?y#s
+ ;x = http://a/b/c/;x
+ g;x = http://a/b/c/g;x
+ g;x?y#s = http://a/b/c/g;x?y#s
+ . = http://a/b/c/
+ ./ = http://a/b/c/
+ .. = http://a/b/
+ ../ = http://a/b/
+ ../g = http://a/b/g
+ ../.. = http://a/
+ ../../ = http://a/
+ ../../g = http://a/g
+
+C.2. Abnormal Examples
+
+ Although the following abnormal examples are unlikely to occur in
+ normal practice, all URI parsers should be capable of resolving them
+ consistently. Each example uses the same base as above.
+
+ An empty reference refers to the start of the current document.
+
+ <> = (current document)
+
+ Parsers must be careful in handling the case where there are more
+ relative path ".." segments than there are hierarchical levels in the
+ base URI's path. Note that the ".." syntax cannot be used to change
+ the authority component of a URI.
+
+
+
+
+Berners-Lee, et. al. Standards Track [Page 30]
+
+RFC 2396 URI Generic Syntax August 1998
+
+
+ ../../../g = http://a/../g
+ ../../../../g = http://a/../../g
+
+ In practice, some implementations strip leading relative symbolic
+ elements (".", "..") after applying a relative URI calculation, based
+ on the theory that compensating for obvious author errors is better
+ than allowing the request to fail. Thus, the above two references
+ will be interpreted as "http://a/g" by some implementations.
+
+ Similarly, parsers must avoid treating "." and ".." as special when
+ they are not complete components of a relative path.
+
+ /./g = http://a/./g
+ /../g = http://a/../g
+ g. = http://a/b/c/g.
+ .g = http://a/b/c/.g
+ g.. = http://a/b/c/g..
+ ..g = http://a/b/c/..g
+
+ Less likely are cases where the relative URI uses unnecessary or
+ nonsensical forms of the "." and ".." complete path segments.
+
+ ./../g = http://a/b/g
+ ./g/. = http://a/b/c/g/
+ g/./h = http://a/b/c/g/h
+ g/../h = http://a/b/c/h
+ g;x=1/./y = http://a/b/c/g;x=1/y
+ g;x=1/../y = http://a/b/c/y
+
+ All client applications remove the query component from the base URI
+ before resolving relative URI. However, some applications fail to
+ separate the reference's query and/or fragment components from a
+ relative path before merging it with the base path. This error is
+ rarely noticed, since typical usage of a fragment never includes the
+ hierarchy ("/") character, and the query component is not normally
+ used within relative references.
+
+ g?y/./x = http://a/b/c/g?y/./x
+ g?y/../x = http://a/b/c/g?y/../x
+ g#s/./x = http://a/b/c/g#s/./x
+ g#s/../x = http://a/b/c/g#s/../x
+
+
+
+
+
+
+
+
+
+
+Berners-Lee, et. al. Standards Track [Page 31]
+
+RFC 2396 URI Generic Syntax August 1998
+
+
+ Some parsers allow the scheme name to be present in a relative URI if
+ it is the same as the base URI scheme. This is considered to be a
+ loophole in prior specifications of partial URI [RFC1630]. Its use
+ should be avoided.
+
+ http:g = http:g ; for validating parsers
+ | http://a/b/c/g ; for backwards compatibility
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Berners-Lee, et. al. Standards Track [Page 32]
+
+RFC 2396 URI Generic Syntax August 1998
+
+
+D. Embedding the Base URI in HTML documents
+
+ It is useful to consider an example of how the base URI of a document
+ can be embedded within the document's content. In this appendix, we
+ describe how documents written in the Hypertext Markup Language
+ (HTML) [RFC1866] can include an embedded base URI. This appendix
+ does not form a part of the URI specification and should not be
+ considered as anything more than a descriptive example.
+
+ HTML defines a special element "BASE" which, when present in the
+ "HEAD" portion of a document, signals that the parser should use the
+ BASE element's "HREF" attribute as the base URI for resolving any
+ relative URI. The "HREF" attribute must be an absolute URI. Note
+ that, in HTML, element and attribute names are case-insensitive. For
+ example:
+
+ <!doctype html public "-//IETF//DTD HTML//EN">
+ <HTML><HEAD>
+ <TITLE>An example HTML document</TITLE>
+ <BASE href="http://www.ics.uci.edu/Test/a/b/c">
+ </HEAD><BODY>
+ ... <A href="../x">a hypertext anchor</A> ...
+ </BODY></HTML>
+
+ A parser reading the example document should interpret the given
+ relative URI "../x" as representing the absolute URI
+
+ <http://www.ics.uci.edu/Test/a/x>
+
+ regardless of the context in which the example document was obtained.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Berners-Lee, et. al. Standards Track [Page 33]
+
+RFC 2396 URI Generic Syntax August 1998
+
+
+E. Recommendations for Delimiting URI in Context
+
+ URI are often transmitted through formats that do not provide a clear
+ context for their interpretation. For example, there are many
+ occasions when URI are included in plain text; examples include text
+ sent in electronic mail, USENET news messages, and, most importantly,
+ printed on paper. In such cases, it is important to be able to
+ delimit the URI from the rest of the text, and in particular from
+ punctuation marks that might be mistaken for part of the URI.
+
+ In practice, URI are delimited in a variety of ways, but usually
+ within double-quotes "http://test.com/", angle brackets
+ <http://test.com/>, or just using whitespace
+
+ http://test.com/
+
+ These wrappers do not form part of the URI.
+
+ In the case where a fragment identifier is associated with a URI
+ reference, the fragment would be placed within the brackets as well
+ (separated from the URI with a "#" character).
+
+ In some cases, extra whitespace (spaces, linebreaks, tabs, etc.) may
+ need to be added to break long URI across lines. The whitespace
+ should be ignored when extracting the URI.
+
+ No whitespace should be introduced after a hyphen ("-") character.
+ Because some typesetters and printers may (erroneously) introduce a
+ hyphen at the end of line when breaking a line, the interpreter of a
+ URI containing a line break immediately after a hyphen should ignore
+ all unescaped whitespace around the line break, and should be aware
+ that the hyphen may or may not actually be part of the URI.
+
+ Using <> angle brackets around each URI is especially recommended as
+ a delimiting style for URI that contain whitespace.
+
+ The prefix "URL:" (with or without a trailing space) was recommended
+ as a way to used to help distinguish a URL from other bracketed
+ designators, although this is not common in practice.
+
+ For robustness, software that accepts user-typed URI should attempt
+ to recognize and strip both delimiters and embedded whitespace.
+
+ For example, the text:
+
+
+
+
+
+
+
+Berners-Lee, et. al. Standards Track [Page 34]
+
+RFC 2396 URI Generic Syntax August 1998
+
+
+ Yes, Jim, I found it under "http://www.w3.org/Addressing/",
+ but you can probably pick it up from <ftp://ds.internic.
+ net/rfc/>. Note the warning in <http://www.ics.uci.edu/pub/
+ ietf/uri/historical.html#WARNING>.
+
+ contains the URI references
+
+ http://www.w3.org/Addressing/
+ ftp://ds.internic.net/rfc/
+ http://www.ics.uci.edu/pub/ietf/uri/historical.html#WARNING
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Berners-Lee, et. al. Standards Track [Page 35]
+
+RFC 2396 URI Generic Syntax August 1998
+
+
+F. Abbreviated URLs
+
+ The URL syntax was designed for unambiguous reference to network
+ resources and extensibility via the URL scheme. However, as URL
+ identification and usage have become commonplace, traditional media
+ (television, radio, newspapers, billboards, etc.) have increasingly
+ used abbreviated URL references. That is, a reference consisting of
+ only the authority and path portions of the identified resource, such
+ as
+
+ www.w3.org/Addressing/
+
+ or simply the DNS hostname on its own. Such references are primarily
+ intended for human interpretation rather than machine, with the
+ assumption that context-based heuristics are sufficient to complete
+ the URL (e.g., most hostnames beginning with "www" are likely to have
+ a URL prefix of "http://"). Although there is no standard set of
+ heuristics for disambiguating abbreviated URL references, many client
+ implementations allow them to be entered by the user and
+ heuristically resolved. It should be noted that such heuristics may
+ change over time, particularly when new URL schemes are introduced.
+
+ Since an abbreviated URL has the same syntax as a relative URL path,
+ abbreviated URL references cannot be used in contexts where relative
+ URLs are expected. This limits the use of abbreviated URLs to places
+ where there is no defined base URL, such as dialog boxes and off-line
+ advertisements.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Berners-Lee, et. al. Standards Track [Page 36]
+
+RFC 2396 URI Generic Syntax August 1998
+
+
+G. Summary of Non-editorial Changes
+
+G.1. Additions
+
+ Section 4 (URI References) was added to stem the confusion regarding
+ "what is a URI" and how to describe fragment identifiers given that
+ they are not part of the URI, but are part of the URI syntax and
+ parsing concerns. In addition, it provides a reference definition
+ for use by other IETF specifications (HTML, HTTP, etc.) that have
+ previously attempted to redefine the URI syntax in order to account
+ for the presence of fragment identifiers in URI references.
+
+ Section 2.4 was rewritten to clarify a number of misinterpretations
+ and to leave room for fully internationalized URI.
+
+ Appendix F on abbreviated URLs was added to describe the shortened
+ references often seen on television and magazine advertisements and
+ explain why they are not used in other contexts.
+
+G.2. Modifications from both RFC 1738 and RFC 1808
+
+ Changed to URI syntax instead of just URL.
+
+ Confusion regarding the terms "character encoding", the URI
+ "character set", and the escaping of characters with %<hex><hex>
+ equivalents has (hopefully) been reduced. Many of the BNF rule names
+ regarding the character sets have been changed to more accurately
+ describe their purpose and to encompass all "characters" rather than
+ just US-ASCII octets. Unless otherwise noted here, these
+ modifications do not affect the URI syntax.
+
+ Both RFC 1738 and RFC 1808 refer to the "reserved" set of characters
+ as if URI-interpreting software were limited to a single set of
+ characters with a reserved purpose (i.e., as meaning something other
+ than the data to which the characters correspond), and that this set
+ was fixed by the URI scheme. However, this has not been true in
+ practice; any character that is interpreted differently when it is
+ escaped is, in effect, reserved. Furthermore, the interpreting
+ engine on a HTTP server is often dependent on the resource, not just
+ the URI scheme. The description of reserved characters has been
+ changed accordingly.
+
+ The plus "+", dollar "$", and comma "," characters have been added to
+ those in the "reserved" set, since they are treated as reserved
+ within the query component.
+
+
+
+
+
+
+Berners-Lee, et. al. Standards Track [Page 37]
+
+RFC 2396 URI Generic Syntax August 1998
+
+
+ The tilde "~" character was added to those in the "unreserved" set,
+ since it is extensively used on the Internet in spite of the
+ difficulty to transcribe it with some keyboards.
+
+ The syntax for URI scheme has been changed to require that all
+ schemes begin with an alpha character.
+
+ The "user:password" form in the previous BNF was changed to a
+ "userinfo" token, and the possibility that it might be
+ "user:password" made scheme specific. In particular, the use of
+ passwords in the clear is not even suggested by the syntax.
+
+ The question-mark "?" character was removed from the set of allowed
+ characters for the userinfo in the authority component, since testing
+ showed that many applications treat it as reserved for separating the
+ query component from the rest of the URI.
+
+ The semicolon ";" character was added to those stated as being
+ reserved within the authority component, since several new schemes
+ are using it as a separator within userinfo to indicate the type of
+ user authentication.
+
+ RFC 1738 specified that the path was separated from the authority
+ portion of a URI by a slash. RFC 1808 followed suit, but with a
+ fudge of carrying around the separator as a "prefix" in order to
+ describe the parsing algorithm. RFC 1630 never had this problem,
+ since it considered the slash to be part of the path. In writing
+ this specification, it was found to be impossible to accurately
+ describe and retain the difference between the two URI
+ <foo:/bar> and <foo:bar>
+ without either considering the slash to be part of the path (as
+ corresponds to actual practice) or creating a separate component just
+ to hold that slash. We chose the former.
+
+G.3. Modifications from RFC 1738
+
+ The definition of specific URL schemes and their scheme-specific
+ syntax and semantics has been moved to separate documents.
+
+ The URL host was defined as a fully-qualified domain name. However,
+ many URLs are used without fully-qualified domain names (in contexts
+ for which the full qualification is not necessary), without any host
+ (as in some file URLs), or with a host of "localhost".
+
+ The URL port is now *digit instead of 1*digit, since systems are
+ expected to handle the case where the ":" separator between host and
+ port is supplied without a port.
+
+
+
+
+Berners-Lee, et. al. Standards Track [Page 38]
+
+RFC 2396 URI Generic Syntax August 1998
+
+
+ The recommendations for delimiting URI in context (Appendix E) have
+ been adjusted to reflect current practice.
+
+G.4. Modifications from RFC 1808
+
+ RFC 1808 (Section 4) defined an empty URL reference (a reference
+ containing nothing aside from the fragment identifier) as being a
+ reference to the base URL. Unfortunately, that definition could be
+ interpreted, upon selection of such a reference, as a new retrieval
+ action on that resource. Since the normal intent of such references
+ is for the user agent to change its view of the current document to
+ the beginning of the specified fragment within that document, not to
+ make an additional request of the resource, a description of how to
+ correctly interpret an empty reference has been added in Section 4.
+
+ The description of the mythical Base header field has been replaced
+ with a reference to the Content-Location header field defined by
+ MHTML [RFC2110].
+
+ RFC 1808 described various schemes as either having or not having the
+ properties of the generic URI syntax. However, the only requirement
+ is that the particular document containing the relative references
+ have a base URI that abides by the generic URI syntax, regardless of
+ the URI scheme, so the associated description has been updated to
+ reflect that.
+
+ The BNF term <net_loc> has been replaced with <authority>, since the
+ latter more accurately describes its use and purpose. Likewise, the
+ authority is no longer restricted to the IP server syntax.
+
+ Extensive testing of current client applications demonstrated that
+ the majority of deployed systems do not use the ";" character to
+ indicate trailing parameter information, and that the presence of a
+ semicolon in a path segment does not affect the relative parsing of
+ that segment. Therefore, parameters have been removed as a separate
+ component and may now appear in any path segment. Their influence
+ has been removed from the algorithm for resolving a relative URI
+ reference. The resolution examples in Appendix C have been modified
+ to reflect this change.
+
+ Implementations are now allowed to work around misformed relative
+ references that are prefixed by the same scheme as the base URI, but
+ only for schemes known to use the <hier_part> syntax.
+
+
+
+
+
+
+
+
+Berners-Lee, et. al. Standards Track [Page 39]
+
+RFC 2396 URI Generic Syntax August 1998
+
+
+H. Full Copyright Statement
+
+ Copyright (C) The Internet Society (1998). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Berners-Lee, et. al. Standards Track [Page 40]
+
diff --git a/standards/rfc2487.txt b/standards/rfc2487.txt
new file mode 100644
index 000000000..fb1305f00
--- /dev/null
+++ b/standards/rfc2487.txt
@@ -0,0 +1,451 @@
+
+
+
+
+
+
+Network Working Group P. Hoffman
+Request for Comments: 2487 Internet Mail Consortium
+Category: Standards Track January 1999
+
+
+ SMTP Service Extension for Secure SMTP over TLS
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+1. Abstract
+
+ This document describes an extension to the SMTP service that allows
+ an SMTP server and client to use transport-layer security to provide
+ private, authenticated communication over the Internet. This gives
+ SMTP agents the ability to protect some or all of their
+ communications from eavesdroppers and attackers.
+
+2. Introduction
+
+ SMTP [RFC-821] servers and clients normally communicate in the clear
+ over the Internet. In many cases, this communication goes through one
+ or more router that is not controlled or trusted by either entity.
+ Such an untrusted router might allow a third party to monitor or
+ alter the communications between the server and client.
+
+ Further, there is often a desire for two SMTP agents to be able to
+ authenticate each others' identities. For example, a secure SMTP
+ server might only allow communications from other SMTP agents it
+ knows, or it might act differently for messages received from an
+ agent it knows than from one it doesn't know.
+
+ TLS [TLS], more commonly known as SSL, is a popular mechanism for
+ enhancing TCP communications with privacy and authentication. TLS is
+ in wide use with the HTTP protocol, and is also being used for adding
+ security to many other common protocols that run over TCP.
+
+
+
+
+
+
+Hoffman Standards Track [Page 1]
+
+RFC 2487 SMTP Service Extension January 1999
+
+
+2.1 Terminology
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+ document are to be interpreted as described in [RFC-2119].
+
+3. STARTTLS Extension
+
+ The STARTTLS extension to SMTP is laid out as follows:
+
+ (1) the name of the SMTP service defined here is STARTTLS;
+
+ (2) the EHLO keyword value associated with the extension is STARTTLS;
+
+ (3) the STARTTLS keyword has no parameters;
+
+ (4) a new SMTP verb, "STARTTLS", is defined;
+
+ (5) no additional parameters are added to any SMTP command.
+
+4. The STARTTLS Keyword
+
+ The STARTTLS keyword is used to tell the SMTP client that the SMTP
+ server allows use of TLS. It takes no parameters.
+
+5. The STARTTLS Command
+
+ The format for the STARTTLS command is:
+
+ STARTTLS
+
+ with no parameters.
+
+ After the client gives the STARTTLS command, the server responds with
+ one of the following reply codes:
+
+ 220 Ready to start TLS
+ 501 Syntax error (no parameters allowed)
+ 454 TLS not available due to temporary reason
+
+ A publicly-referenced SMTP server MUST NOT require use of the
+ STARTTLS extension in order to deliver mail locally. This rule
+ prevents the STARTTLS extension from damaging the interoperability of
+ the Internet's SMTP infrastructure. A publicly-referenced SMTP server
+ is an SMTP server which runs on port 25 of an Internet host listed in
+ the MX record (or A record if an MX record is not present) for the
+ domain name on the right hand side of an Internet mail address.
+
+
+
+
+Hoffman Standards Track [Page 2]
+
+RFC 2487 SMTP Service Extension January 1999
+
+
+ Any SMTP server may refuse to accept messages for relay based on
+ authentication supplied during the TLS negotiation. An SMTP server
+ that is not publicly referenced may refuse to accept any messages for
+ relay or local delivery based on authentication supplied during the
+ TLS negotiation.
+
+ A SMTP server that is not publicly referenced may choose to require
+ that the client perform a TLS negotiation before accepting any
+ commands. In this case, the server SHOULD return the reply code:
+
+ 530 Must issue a STARTTLS command first
+
+ to every command other than NOOP, EHLO, STARTTLS, or QUIT. If the
+ client and server are using the ENHANCEDSTATUSCODES ESMTP extension
+ [RFC-2034], the status code to be returned SHOULD be 5.7.0.
+
+ After receiving a 220 response to a STARTTLS command, the client
+ SHOULD start the TLS negotiation before giving any other SMTP
+ commands.
+
+ If the SMTP client is using pipelining as defined in RFC 1854, the
+ STARTTLS command must be the last command in a group.
+
+5.1 Processing After the STARTTLS Command
+
+ After the TLS handshake has been completed, both parties MUST
+ immediately decide whether or not to continue based on the
+ authentication and privacy achieved. The SMTP client and server may
+ decide to move ahead even if the TLS negotiation ended with no
+ authentication and/or no privacy because most SMTP services are
+ performed with no authentication and no privacy, but some SMTP
+ clients or servers may want to continue only if a particular level of
+ authentication and/or privacy was achieved.
+
+ If the SMTP client decides that the level of authentication or
+ privacy is not high enough for it to continue, it SHOULD issue an
+ SMTP QUIT command immediately after the TLS negotiation is complete.
+ If the SMTP server decides that the level of authentication or
+ privacy is not high enough for it to continue, it SHOULD reply to
+ every SMTP command from the client (other than a QUIT command) with
+ the 554 reply code (with a possible text string such as "Command
+ refused due to lack of security").
+
+ The decision of whether or not to believe the authenticity of the
+ other party in a TLS negotiation is a local matter. However, some
+ general rules for the decisions are:
+
+
+
+
+
+Hoffman Standards Track [Page 3]
+
+RFC 2487 SMTP Service Extension January 1999
+
+
+ - A SMTP client would probably only want to authenticate an SMTP
+ server whose server certificate has a domain name that is the
+ domain name that the client thought it was connecting to.
+ - A publicly-referenced SMTP server would probably want to accept
+ any certificate from an SMTP client, and would possibly want to
+ put distinguishing information about the certificate in the
+ Received header of messages that were relayed or submitted from
+ the client.
+
+5.2 Result of the STARTTLS Command
+
+ Upon completion of the TLS handshake, the SMTP protocol is reset to
+ the initial state (the state in SMTP after a server issues a 220
+ service ready greeting). The server MUST discard any knowledge
+ obtained from the client, such as the argument to the EHLO command,
+ which was not obtained from the TLS negotiation itself. The client
+ MUST discard any knowledge obtained from the server, such as the list
+ of SMTP service extensions, which was not obtained from the TLS
+ negotiation itself. The client SHOULD send an EHLO command as the
+ first command after a successful TLS negotiation.
+
+ The list of SMTP service extensions returned in response to an EHLO
+ command received after the TLS handshake MAY be different than the
+ list returned before the TLS handshake. For example, an SMTP server
+ might not want to advertise support for a particular SASL mechanism
+ [SASL] unless a client has sent an appropriate client certificate
+ during a TLS handshake.
+
+ Both the client and the server MUST know if there is a TLS session
+ active. A client MUST NOT attempt to start a TLS session if a TLS
+ session is already active. A server MUST NOT return the TLS extension
+ in response to an EHLO command received after a TLS handshake has
+ completed.
+
+6. Usage Example
+
+ The following dialog illustrates how a client and server can start a
+ TLS session:
+
+ S: <waits for connection on TCP port 25>
+ C: <opens connection>
+ S: 220 mail.imc.org SMTP service ready
+ C: EHLO mail.ietf.org
+ S: 250-mail.imc.org offers a warm hug of welcome
+ S: 250 STARTTLS
+ C: STARTTLS
+ S: 220 Go ahead
+ C: <starts TLS negotiation>
+
+
+
+Hoffman Standards Track [Page 4]
+
+RFC 2487 SMTP Service Extension January 1999
+
+
+ C & S: <negotiate a TLS session>
+ C & S: <check result of negotiation>
+ C: <continues by sending an SMTP command>
+ . . .
+
+7. Security Considerations
+
+ It should be noted that SMTP is not an end-to-end mechanism. Thus, if
+ an SMTP client/server pair decide to add TLS privacy, they are not
+ securing the transport from the originating mail user agent to the
+ recipient. Further, because delivery of a single piece of mail may
+ go between more than two SMTP servers, adding TLS privacy to one pair
+ of servers does not mean that the entire SMTP chain has been made
+ private. Further, just because an SMTP server can authenticate an
+ SMTP client, it does not mean that the mail from the SMTP client was
+ authenticated by the SMTP client when the client received it.
+
+ Both the STMP client and server must check the result of the TLS
+ negotiation to see whether acceptable authentication or privacy was
+ achieved. Ignoring this step completely invalidates using TLS for
+ security. The decision about whether acceptable authentication or
+ privacy was achieved is made locally, is implementation-dependant,
+ and is beyond the scope of this document.
+
+ The SMTP client and server should note carefully the result of the
+ TLS negotiation. If the negotiation results in no privacy, or if it
+ results in privacy using algorithms or key lengths that are deemed
+ not strong enough, or if the authentication is not good enough for
+ either party, the client may choose to end the SMTP session with an
+ immediate QUIT command, or the server may choose to not accept any
+ more SMTP commands.
+
+ A server announcing in an EHLO response that it uses a particular TLS
+ protocol should not pose any security issues, since any use of TLS
+ will be at least as secure as no use of TLS.
+
+ A man-in-the-middle attack can be launched by deleting the "250
+ STARTTLS" response from the server. This would cause the client not
+ to try to start a TLS session. An SMTP client can protect against
+ this attack by recording the fact that a particular SMTP server
+ offers TLS during one session and generating an alarm if it does not
+ appear in the EHLO response for a later session. The lack of TLS
+ during a session SHOULD NOT result in the bouncing of email, although
+ it could result in delayed processing.
+
+
+
+
+
+
+
+Hoffman Standards Track [Page 5]
+
+RFC 2487 SMTP Service Extension January 1999
+
+
+ Before the TLS handshake has begun, any protocol interactions are
+ performed in the clear and may be modified by an active attacker. For
+ this reason, clients and servers MUST discard any knowledge obtained
+ prior to the start of the TLS handshake upon completion of the TLS
+ handshake.
+
+ The STARTTLS extension is not suitable for authenticating the author
+ of an email message unless every hop in the delivery chain, including
+ the submission to the first SMTP server, is authenticated. Another
+ proposal [SMTP-AUTH] can be used to authenticate delivery and MIME
+ security multiparts [MIME-SEC] can be used to authenticate the author
+ of an email message. In addition, the [SMTP-AUTH] proposal offers
+ simpler and more flexible options to authenticate an SMTP client and
+ the SASL EXTERNAL mechanism [SASL] MAY be used in conjunction with
+ the STARTTLS command to provide an authorization identity.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hoffman Standards Track [Page 6]
+
+RFC 2487 SMTP Service Extension January 1999
+
+
+A. References
+
+ [RFC-821] Postel, J., "Simple Mail Transfer Protocol", RFC 821,
+ August 1982.
+
+ [RFC-1869] Klensin, J., Freed, N, Rose, M, Stefferud, E. and D.
+ Crocker, "SMTP Service Extensions", STD 10, RFC 1869,
+ November 1995.
+
+ [RFC-2034] Freed, N., "SMTP Service Extension for Returning Enhanced
+ Error Codes", RFC 2034, October 1996.
+
+ [RFC-2119] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+ [SASL] Myers, J., "Simple Authentication and Security Layer
+ (SASL)", RFC 2222, October 1997.
+
+ [SMTP-AUTH] "SMTP Service Extension for Authentication", Work in
+ Progress.
+
+ [TLS] Dierks, T. and C. Allen, "The TLS Protocol Version 1.0",
+ RFC 2246, January 1999.
+
+B. Author's Address
+
+ Paul Hoffman
+ Internet Mail Consortium
+ 127 Segre Place
+ Santa Cruz, CA 95060
+
+ Phone: (831) 426-9827
+ EMail: phoffman@imc.org
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hoffman Standards Track [Page 7]
+
+RFC 2487 SMTP Service Extension January 1999
+
+
+C. Full Copyright Statement
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hoffman Standards Track [Page 8]
+
diff --git a/standards/rfc2565.txt b/standards/rfc2565.txt
new file mode 100644
index 000000000..56511d478
--- /dev/null
+++ b/standards/rfc2565.txt
@@ -0,0 +1,2075 @@
+
+
+
+
+
+
+Network Working Group R. Herriot, Ed.
+Request for Comments: 2565 Xerox Corporation
+Category: Experimental S. Butler
+ Hewlett-Packard
+ P. Moore
+ Microsoft
+ R. Turner
+ Sharp Labs
+ April 1999
+
+
+ Internet Printing Protocol/1.0: Encoding and Transport
+
+Status of this Memo
+
+ This memo defines an Experimental Protocol for the Internet
+ community. It does not specify an Internet standard of any kind.
+ Discussion and suggestions for improvement are requested.
+ Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+IESG Note
+
+ This document defines an Experimental protocol for the Internet
+ community. The IESG expects that a revised version of this protocol
+ will be published as Proposed Standard protocol. The Proposed
+ Standard, when published, is expected to change from the protocol
+ defined in this memo. In particular, it is expected that the
+ standards-track version of the protocol will incorporate strong
+ authentication and privacy features, and that an "ipp:" URL type will
+ be defined which supports those security measures. Other changes to
+ the protocol are also possible. Implementors are warned that future
+ versions of this protocol may not interoperate with the version of
+ IPP defined in this document, or if they do interoperate, that some
+ protocol features may not be available.
+
+ The IESG encourages experimentation with this protocol, especially in
+ combination with Transport Layer Security (TLS) [RFC 2246], to help
+ determine how TLS may effectively be used as a security layer for
+ IPP.
+
+
+
+
+
+
+
+
+Herriot, et al. Experimental [Page 1]
+
+RFC 2565 IPP/1.0: Encoding and Transport April 1999
+
+
+Abstract
+
+ This document is one of a set of documents, which together describe
+ all aspects of a new Internet Printing Protocol (IPP). IPP is an
+ application level protocol that can be used for distributed printing
+ using Internet tools and technologies. This document defines the
+ rules for encoding IPP operations and IPP attributes into a new
+ Internet mime media type called "application/ipp". This document
+ also defines the rules for transporting over HTTP a message body
+ whose Content-Type is "application/ipp".
+
+ The full set of IPP documents includes:
+
+ Design Goals for an Internet Printing Protocol [RFC2567]
+ Rationale for the Structure and Model and Protocol for the
+ Internet Printing Protocol [RFC2568]
+ Internet Printing Protocol/1.0: Model and Semantics [RFC2566]
+ Internet Printing Protocol/1.0: Encoding and Transport (this
+ document)
+ Internet Printing Protocol/1.0: Implementer's Guide [ipp-iig]
+ Mapping between LPD and IPP Protocols [RFC2569]
+
+ The document, "Design Goals for an Internet Printing Protocol", takes
+ a broad look at distributed printing functionality, and it enumerates
+ real-life scenarios that help to clarify the features that need to be
+ included in a printing protocol for the Internet. It identifies
+ requirements for three types of users: end users, operators, and
+ administrators. It calls out a subset of end user requirements that
+ are satisfied in IPP/1.0. Operator and administrator requirements are
+ out of scope for version 1.0.
+
+ The document, "Rationale for the Structure and Model and Protocol for
+ the Internet Printing Protocol", describes IPP from a high level
+ view, defines a roadmap for the various documents that form the suite
+ of IPP specifications, and gives background and rationale for the
+ IETF working group's major decisions.
+
+ The document, "Internet Printing Protocol/1.0: Model and Semantics",
+ describes a simplified model with abstract objects, their attributes,
+ and their operations that are independent of encoding and transport.
+ It introduces a Printer and a Job object. The Job object optionally
+ supports multiple documents per Job. It also addresses security,
+ internationalization, and directory issues.
+
+ This document "Internet Printing Protocol/1.0: Implementer's Guide",
+ gives advice to implementers of IPP clients and IPP objects.
+
+
+
+
+
+Herriot, et al. Experimental [Page 2]
+
+RFC 2565 IPP/1.0: Encoding and Transport April 1999
+
+
+ The document "Mapping between LPD and IPP Protocols" gives some
+ advice to implementers of gateways between IPP and LPD (Line Printer
+ Daemon) implementations.
+
+Table of Contents
+
+ 1. Introduction.....................................................4
+ 2. Conformance Terminology..........................................4
+ 3. Encoding of the Operation Layer.................................4
+ 3.1 Picture of the Encoding.....................................5
+ 3.2 Syntax of Encoding..........................................7
+ 3.3 Version-number..............................................9
+ 3.4 Operation-id................................................9
+ 3.5 Status-code.................................................9
+ 3.6 Request-id..................................................9
+ 3.7 Tags.......................................................10
+ 3.7.1 Delimiter Tags.........................................10
+ 3.7.2 Value Tags.............................................11
+ 3.8 Name-Length................................................13
+ 3.9 (Attribute) Name...........................................13
+ 3.10 Value Length...............................................16
+ 3.11 (Attribute) Value..........................................16
+ 3.12 Data.......................................................18
+ 4. Encoding of Transport Layer.....................................18
+ 5. Security Considerations.........................................19
+ 5.1 Using IPP with SSL3........................................19
+ 6. References......................................................20
+ 7. Authors' Addresses..............................................22
+ 8. Other Participants:.............................................24
+ 9. Appendix A: Protocol Examples...................................25
+ 9.1 Print-Job Request..........................................25
+ 9.2 Print-Job Response (successful)............................26
+ 9.3 Print-Job Response (failure)...............................27
+ 9.4 Print-Job Response (success with attributes ignored).......28
+ 9.5 Print-URI Request..........................................30
+ 9.6 Create-Job Request.........................................31
+ 9.7 Get-Jobs Request...........................................31
+ 9.8 Get-Jobs Response..........................................32
+ 10. Appendix C: Registration of MIME Media Type Information for
+ "application/ipp"..............................................35
+ 11. Full Copyright Statement.......................................37
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Experimental [Page 3]
+
+RFC 2565 IPP/1.0: Encoding and Transport April 1999
+
+
+1. Introduction
+
+ This document contains the rules for encoding IPP operations and
+ describes two layers: the transport layer and the operation layer.
+
+ The transport layer consists of an HTTP/1.1 request or response. RFC
+ 2068 [RFC2068] describes HTTP/1.1. This document specifies the HTTP
+ headers that an IPP implementation supports.
+
+ The operation layer consists of a message body in an HTTP request or
+ response. The document "Internet Printing Protocol/1.0: Model and
+ Semantics" [RFC2566] defines the semantics of such a message body and
+ the supported values. This document specifies the encoding of an IPP
+ operation. The aforementioned document [RFC2566] is henceforth
+ referred to as the "IPP model document"
+
+2. Conformance Terminology
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHOULD", "SHOULD NOT",
+ "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be
+ interpreted as described in RFC 2119 [RFC2119].
+
+3. Encoding of the Operation Layer
+
+ The operation layer MUST contain a single operation request or
+ operation response. Each request or response consists of a sequence
+ of values and attribute groups. Attribute groups consist of a
+ sequence of attributes each of which is a name and value. Names and
+ values are ultimately sequences of octets
+
+ The encoding consists of octets as the most primitive type. There are
+ several types built from octets, but three important types are
+ integers, character strings and octet strings, on which most other
+ data types are built. Every character string in this encoding MUST be
+ a sequence of characters where the characters are associated with
+ some charset and some natural language. A character string MUST be in
+ "reading order" with the first character in the value (according to
+ reading order) being the first character in the encoding. A character
+ string whose associated charset is US-ASCII whose associated natural
+ language is US English is henceforth called a US-ASCII-STRING. A
+ character string whose associated charset and natural language are
+ specified in a request or response as described in the model document
+ is henceforth called a LOCALIZED-STRING. An octet string MUST be in
+ "IPP model document order" with the first octet in the value
+ (according to the IPP model document order) being the first octet in
+ the encoding Every integer in this encoding MUST be encoded as a
+ signed integer using two's-complement binary encoding with big-endian
+ format (also known as "network order" and "most significant byte
+
+
+
+Herriot, et al. Experimental [Page 4]
+
+RFC 2565 IPP/1.0: Encoding and Transport April 1999
+
+
+ first"). The number of octets for an integer MUST be 1, 2 or 4,
+ depending on usage in the protocol. Such one-octet integers,
+ henceforth called SIGNED-BYTE, are used for the version-number and
+ tag fields. Such two-byte integers, henceforth called SIGNED-SHORT
+ are used for the operation-id, status-code and length fields. Four
+ byte integers, henceforth called SIGNED-INTEGER, are used for values
+ fields and the sequence number.
+
+ The following two sections present the operation layer in two ways
+
+ - informally through pictures and description
+ - formally through Augmented Backus-Naur Form (ABNF), as specified
+ by RFC 2234 [RFC2234]
+
+3.1 Picture of the Encoding
+
+ The encoding for an operation request or response consists of:
+
+ -----------------------------------------------
+ | version-number | 2 bytes - required
+ -----------------------------------------------
+ | operation-id (request) |
+ | or | 2 bytes - required
+ | status-code (response) |
+ -----------------------------------------------
+ | request-id | 4 bytes - required
+ -----------------------------------------------------------
+ | xxx-attributes-tag | 1 byte |
+ ----------------------------------------------- |-0 or more
+ | xxx-attribute-sequence | n bytes |
+ -----------------------------------------------------------
+ | end-of-attributes-tag | 1 byte - required
+ -----------------------------------------------
+ | data | q bytes - optional
+ -----------------------------------------------
+
+ The xxx-attributes-tag and xxx-attribute-sequence represents four
+ different values of "xxx", namely, operation, job, printer and
+ unsupported. The xxx-attributes-tag and an xxx-attribute-sequence
+ represent attribute groups in the model document. The xxx-
+ attributes-tag identifies the attribute group and the xxx-attribute-
+ sequence contains the attributes.
+
+ The expected sequence of xxx-attributes-tag and xxx-attribute-
+ sequence is specified in the IPP model document for each operation
+ request and operation response.
+
+
+
+
+
+Herriot, et al. Experimental [Page 5]
+
+RFC 2565 IPP/1.0: Encoding and Transport April 1999
+
+
+ A request or response SHOULD contain each xxx-attributes-tag defined
+ for that request or response even if there are no attributes except
+ for the unsupported-attributes-tag which SHOULD be present only if
+ the unsupported-attribute-sequence is non-empty. A receiver of a
+ request MUST be able to process as equivalent empty attribute groups:
+
+ a) an xxx-attributes-tag with an empty xxx-attribute-sequence,
+ b) an expected but missing xxx-attributes-tag.
+
+ The data is omitted from some operations, but the end-of-attributes-
+ tag is present even when the data is omitted. Note, the xxx-
+ attributes-tags and end-of-attributes-tag are called 'delimiter-
+ tags'. Note: the xxx-attribute-sequence, shown above may consist of 0
+ bytes, according to the rule below.
+
+ An xxx-attributes-sequence consists of zero or more compound-
+ attributes.
+
+ -----------------------------------------------
+ | compound-attribute | s bytes - 0 or more
+ -----------------------------------------------
+
+ A compound-attribute consists of an attribute with a single value
+ followed by zero or more additional values.
+
+ Note: a 'compound-attribute' represents a single attribute in the
+ model document. The 'additional value' syntax is for attributes with
+ 2 or more values.
+
+ Each attribute consists of:
+
+ -----------------------------------------------
+ | value-tag | 1 byte
+ -----------------------------------------------
+ | name-length (value is u) | 2 bytes
+ -----------------------------------------------
+ | name | u bytes
+ -----------------------------------------------
+ | value-length (value is v) | 2 bytes
+ -----------------------------------------------
+ | value | v bytes
+ -----------------------------------------------
+
+
+
+
+
+
+
+
+
+Herriot, et al. Experimental [Page 6]
+
+RFC 2565 IPP/1.0: Encoding and Transport April 1999
+
+
+ An additional value consists of:
+
+ -----------------------------------------------------------
+ | value-tag | 1 byte |
+ ----------------------------------------------- |
+ | name-length (value is 0x0000) | 2 bytes |
+ ----------------------------------------------- |-0 or more
+ | value-length (value is w) | 2 bytes |
+ ----------------------------------------------- |
+ | value | w bytes |
+ -----------------------------------------------------------
+
+ Note: an additional value is like an attribute whose name-length is 0.
+
+ From the standpoint of a parsing loop, the encoding consists of:
+
+ -----------------------------------------------
+ | version-number | 2 bytes - required
+ -----------------------------------------------
+ | operation-id (request) |
+ | or | 2 bytes - required
+ | status-code (response) |
+ -----------------------------------------------
+ | request-id | 4 bytes - required
+ -----------------------------------------------------------
+ | tag (delimiter-tag or value-tag) | 1 byte |
+ ----------------------------------------------- |-0 or more
+ | empty or rest of attribute | x bytes |
+ -----------------------------------------------------------
+ | end-of-attributes-tag | 2 bytes - required
+ -----------------------------------------------
+ | data | y bytes - optional
+ -----------------------------------------------
+
+ The value of the tag determines whether the bytes following the
+ tag are:
+
+ - attributes
+ - data
+ - the remainder of a single attribute where the tag specifies the
+ type of the value.
+
+3.2 Syntax of Encoding
+
+ The syntax below is ABNF [RFC2234] except 'strings of literals' MUST
+ be case sensitive. For example 'a' means lower case 'a' and not
+ upper case 'A'. In addition, SIGNED-BYTE and SIGNED-SHORT fields
+ are represented as '%x' values which show their range of values.
+
+
+
+Herriot, et al. Experimental [Page 7]
+
+RFC 2565 IPP/1.0: Encoding and Transport April 1999
+
+
+ ipp-message = ipp-request / ipp-response
+ ipp-request = version-number operation-id request-id
+ *(xxx-attributes-tag xxx-attribute-sequence)
+ end-of-attributes-tag data
+ ipp-response = version-number status-code request-id
+ *(xxx-attributes-tag xxx-attribute-sequence)
+ end-of-attributes-tag data
+ xxx-attribute-sequence = *compound-attribute
+
+ xxx-attributes-tag = operation-attributes-tag / job-attributes-tag /
+ printer-attributes-tag / unsupported-attributes-tag
+
+ version-number = major-version-number minor-version-number
+ major-version-number = SIGNED-BYTE ; initially %d1
+ minor-version-number = SIGNED-BYTE ; initially %d0
+
+ operation-id = SIGNED-SHORT ; mapping from model defined below
+ status-code = SIGNED-SHORT ; mapping from model defined below
+ request-id = SIGNED-INTEGER ; whose value is > 0
+
+ compound-attribute = attribute *additional-values
+ attribute = value-tag name-length name value-length value
+ additional-values = value-tag zero-name-length value-length value
+
+ name-length = SIGNED-SHORT ; number of octets of 'name'
+ name = LALPHA *( LALPHA / DIGIT / "-" / "_" / "." )
+ value-length = SIGNED-SHORT ; number of octets of 'value'
+ value = OCTET-STRING
+
+ data = OCTET-STRING
+
+ zero-name-length = %x00.00 ; name-length of 0
+ operation-attributes-tag = %x01 ; tag of 1
+ job-attributes-tag = %x02 ; tag of 2
+ printer-attributes-tag = %x04 ; tag of 4
+ unsupported-attributes-tag = %x05 ; tag of 5
+ end-of-attributes-tag = %x03 ; tag of 3
+ value-tag = %x10-FF
+
+ SIGNED-BYTE = BYTE
+ SIGNED-SHORT = 2BYTE
+ SIGNED-INTEGER = 4BYTE
+ DIGIT = %x30-39 ; "0" to "9"
+ LALPHA = %x61-7A ; "a" to "z"
+ BYTE = %x00-FF
+ OCTET-STRING = *BYTE
+
+
+
+
+
+Herriot, et al. Experimental [Page 8]
+
+RFC 2565 IPP/1.0: Encoding and Transport April 1999
+
+
+ The syntax allows an xxx-attributes-tag to be present when the xxx-
+ attribute-sequence that follows is empty. The syntax is defined this
+ way to allow for the response of Get-Jobs where no attributes are
+ returned for some job-objects. Although it is RECOMMENDED that the
+ sender not send an xxx-attributes-tag if there are no attributes
+ (except in the Get-Jobs response just mentioned), the receiver MUST
+ be able to decode such syntax.
+
+3.3 Version-number
+
+ The version-number MUST consist of a major and minor version-number,
+ each of which MUST be represented by a SIGNED-BYTE. The protocol
+ described in this document MUST have a major version-number of 1
+ (0x01) and a minor version-number of 0 (0x00). The ABNF for these
+ two bytes MUST be %x01.00.
+
+3.4 Operation-id
+
+ Operation-ids are defined as enums in the model document. An
+ operation-ids enum value MUST be encoded as a SIGNED-SHORT.
+
+ Note: the values 0x4000 to 0xFFFF are reserved for private
+ extensions.
+
+3.5 Status-code
+
+ Status-codes are defined as enums in the model document. A status-
+ code enum value MUST be encoded as a SIGNED-SHORT.
+
+ The status-code is an operation attribute in the model document. In
+ the protocol, the status-code is in a special position, outside of
+ the operation attributes.
+
+ If an IPP status-code is returned, then the HTTP Status-Code MUST be
+ 200 (successful-ok). With any other HTTP Status-Code value, the HTTP
+ response MUST NOT contain an IPP message-body, and thus no IPP
+ status-code is returned.
+
+3.6 Request-id
+
+ The request-id allows a client to match a response with a request.
+ This mechanism is unnecessary in HTTP, but may be useful when
+ application/ipp entity bodies are used in another context.
+
+ The request-id in a response MUST be the value of the request-id
+ received in the corresponding request. A client can set the
+ request-id in each request to a unique value or a constant value,
+ such as 1, depending on what the client does with the request-id
+
+
+
+Herriot, et al. Experimental [Page 9]
+
+RFC 2565 IPP/1.0: Encoding and Transport April 1999
+
+
+ returned in the response. The value of the request-id MUST be greater
+ than zero.
+
+3.7 Tags
+
+ There are two kinds of tags:
+
+ - delimiter tags: delimit major sections of the protocol, namely
+ attributes and data
+ - value tags: specify the type of each attribute value
+
+3.7.1 Delimiter Tags
+
+ The following table specifies the values for the delimiter tags:
+
+ Tag Value (Hex) Delimiter
+
+ 0x00 reserved
+ 0x01 operation-attributes-tag
+ 0x02 job-attributes-tag
+ 0x03 end-of-attributes-tag
+ 0x04 printer-attributes-tag
+ 0x05 unsupported-attributes-tag
+ 0x06-0x0e reserved for future delimiters
+ 0x0F reserved for future chunking-end-of-attributes-
+ tag
+
+ When an xxx-attributes-tag occurs in the protocol, it MUST mean that
+ zero or more following attributes up to the next delimiter tag are
+ attributes belonging to group xxx as defined in the model document,
+ where xxx is operation, job, printer, unsupported.
+
+ Doing substitution for xxx in the above paragraph, this means the
+ following. When an operation-attributes-tag occurs in the protocol,
+ it MUST mean that the zero or more following attributes up to the
+ next delimiter tag are operation attributes as defined in the model
+ document. When an job-attributes-tag occurs in the protocol, it MUST
+ mean that the zero or more following attributes up to the next
+ delimiter tag are job attributes or job template attributes as
+ defined in the model document. When a printer-attributes-tag occurs
+ in the protocol, it MUST mean that the zero or more following
+ attributes up to the next delimiter tag are printer attributes as
+ defined in the model document. When an unsupported-attributes-tag
+ occurs in the protocol, it MUST mean that the zero or more following
+ attributes up to the next delimiter tag are unsupported attributes as
+ defined in the model document.
+
+
+
+
+
+Herriot, et al. Experimental [Page 10]
+
+RFC 2565 IPP/1.0: Encoding and Transport April 1999
+
+
+ The operation-attributes-tag and end-of-attributes-tag MUST each
+ occur exactly once in an operation. The operation-attributes-tag MUST
+ be the first tag delimiter, and the end-of-attributes-tag MUST be the
+ last tag delimiter. If the operation has a document-content group,
+ the document data in that group MUST follow the end-of-attributes-
+ tag.
+
+ Each of the other three xxx-attributes-tags defined above is
+ OPTIONAL in an operation and each MUST occur at most once in an
+ operation, except for job-attributes-tag in a Get-Jobs response which
+ may occur zero or more times.
+
+ The order and presence of delimiter tags for each operation request
+ and each operation response MUST be that defined in the model
+ document. For further details, see section 3.9 "(Attribute) Name" and
+ section 9 "Appendix A: Protocol Examples".
+
+ A Printer MUST treat the reserved delimiter tags differently from
+ reserved value tags so that the Printer knows that there is an entire
+ attribute group that it doesn't understand as opposed to a single
+ value that it doesn't understand.
+
+3.7.2 Value Tags
+
+ The remaining tables show values for the value-tag, which is the
+ first octet of an attribute. The value-tag specifies the type of the
+ value of the attribute. The following table specifies the "out-of-
+ band" values for the value-tag.
+
+ Tag Value (Hex) Meaning
+
+ 0x10 unsupported
+ 0x11 reserved for future 'default'
+ 0x12 unknown
+ 0x13 no-value
+
+ Tag Value (Hex) Meaning
+
+ 0x14-0x1F reserved for future "out-of-band" values.
+
+ The "unsupported" value MUST be used in the attribute-sequence of an
+ error response for those attributes which the printer does not
+ support. The "default" value is reserved for future use of setting
+ value back to their default value. The "unknown" value is used for
+ the value of a supported attribute when its value is temporarily
+ unknown. The "no-value" value is used for a supported attribute to
+ which
+
+
+
+
+Herriot, et al. Experimental [Page 11]
+
+RFC 2565 IPP/1.0: Encoding and Transport April 1999
+
+
+ no value has been assigned, e.g. "job-k-octets-supported" has no
+ value if an implementation supports this attribute, but an
+ administrator has not configured the printer to have a limit.
+
+ The following table specifies the integer values for the value-tag:
+
+ Tag Value (Hex) Meaning
+
+ 0x20 reserved
+ 0x21 integer
+ 0x22 boolean
+ 0x23 enum
+ 0x24-0x2F reserved for future integer types
+
+ NOTE: 0x20 is reserved for "generic integer" if it should ever be
+ needed.
+
+ The following table specifies the octetString values for the value-
+ tag:
+
+ Tag Value (Hex) Meaning
+
+ 0x30 octetString with an unspecified format
+ 0x31 dateTime
+ 0x32 resolution
+ 0x33 rangeOfInteger
+ 0x34 reserved for collection (in the future)
+ 0x35 textWithLanguage
+ 0x36 nameWithLanguage
+ 0x37-0x3F reserved for future octetString types
+
+ The following table specifies the character-string values for the
+ value-tag:
+
+ Tag Value (Hex) Meaning
+
+ 0x40 reserved
+ 0x41 textWithoutLanguage
+ 0x42 nameWithoutLanguage
+ 0x43 reserved
+ 0x44 keyword
+ 0x45 uri
+ 0x46 uriScheme
+ 0x47 charset
+ 0x48 naturalLanguage
+
+
+
+
+
+
+Herriot, et al. Experimental [Page 12]
+
+RFC 2565 IPP/1.0: Encoding and Transport April 1999
+
+
+ Tag Value (Hex) Meaning
+
+ 0x49 mimeMediaType
+ 0x4A-0x5F reserved for future character string types
+
+ NOTE: 0x40 is reserved for "generic character-string" if it should
+ ever be needed.
+
+ NOTE: an attribute value always has a type, which is explicitly
+ specified by its tag; one such tag value is "nameWithoutLanguage".
+ An attribute's name has an implicit type, which is keyword.
+
+ The values 0x60-0xFF are reserved for future types. There are no
+ values allocated for private extensions. A new type MUST be
+ registered via the type 2 registration process [RFC2566].
+
+ The tag 0x7F is reserved for extending types beyond the 255 values
+ available with a single byte. A tag value of 0x7F MUST signify that
+ the first 4 bytes of the value field are interpreted as the tag
+ value. Note, this future extension doesn't affect parsers that are
+ unaware of this special tag. The tag is like any other unknown tag,
+ and the value length specifies the length of a value which contains a
+ value that the parser treats atomically. All these 4 byte tag values
+ are currently unallocated except that the values 0x40000000-
+ 0x7FFFFFFF are reserved for experimental use.
+
+3.8 Name-Length
+
+ The name-length field MUST consist of a SIGNED-SHORT. This field MUST
+ specify the number of octets in the name field which follows the
+ name-length field, excluding the two bytes of the name-length field.
+
+ If a name-length field has a value of zero, the following name field
+ MUST be empty, and the following value MUST be treated as an
+ additional value for the preceding attribute. Within an attribute-
+ sequence, if two attributes have the same name, the first occurrence
+ MUST be ignored. The zero-length name is the only mechanism for
+ multi-valued attributes.
+
+3.9 (Attribute) Name
+
+ Some operation elements are called parameters in the model document
+ [RFC2566]. They MUST be encoded in a special position and they MUST
+ NOT appear as an operation attributes. These parameters are:
+
+ - "version-number": The parameter named "version-number" in the
+ IPP model document MUST become the "version-number" field in the
+ operation layer request or response.
+
+
+
+Herriot, et al. Experimental [Page 13]
+
+RFC 2565 IPP/1.0: Encoding and Transport April 1999
+
+
+ - "operation-id": The parameter named "operation-id" in the IPP
+ model document MUST become the "operation-id" field in the
+ operation layer request.
+ - "status-code": The parameter named "status-code" in the IPP
+ model document MUST become the "status-code" field in the
+ operation layer response.
+ - "request-id": The parameter named "request-id" in the IPP model
+ document MUST become the "request-id" field in the operation
+ layer request or response.
+
+ All Printer and Job objects are identified by a Uniform Resource
+ Identifier (URI) [RFC2396] so that they can be persistently and
+ unambiguously referenced. The notion of a URI is a useful concept,
+ however, until the notion of URI is more stable (i.e., defined more
+ completely and deployed more widely), it is expected that the URIs
+ used for IPP objects will actually be URLs [RFC1738] [RFC1808].
+ Since every URL is a specialized form of a URI, even though the more
+ generic term URI is used throughout the rest of this document, its
+ usage is intended to cover the more specific notion of URL as well.
+
+ Some operation elements are encoded twice, once as the request-URI on
+ the HTTP Request-Line and a second time as a REQUIRED operation
+ attribute in the application/ipp entity. These attributes are the
+ target URI for the operation:
+
+ - "printer-uri": When the target is a printer and the transport is
+ HTTP or HTTPS (for SSL3 [ssl]), the target printer-uri defined
+ in each operation in the IPP model document MUST be an operation
+ attribute called "printer-uri" and it MUST also be specified
+ outside of the operation layer as the request-URI on the
+ Request-Line at the HTTP level.
+ - "job-uri": When the target is a job and the transport is HTTP or
+ HTTPS (for SSL3), the target job-uri of each operation in the
+ IPP model document MUST be an operation attribute called "job-
+ uri" and it MUST also be specified outside of the operation
+ layer as the request-URI on the Request-Line at the HTTP level.
+
+ Note: The target URI is included twice in an operation referencing
+ the same IPP object, but the two URIs NEED NOT be literally
+ identical. One can be a relative URI and the other can be an absolute
+ URI. HTTP/1.1 allows clients to generate and send a relative URI
+ rather than an absolute URI. A relative URI identifies a resource
+ with the scope of the HTTP server, but does not include scheme, host
+ or port. The following statements characterize how URLs should be
+ used in the mapping of IPP onto HTTP/1.1:
+
+
+
+
+
+
+Herriot, et al. Experimental [Page 14]
+
+RFC 2565 IPP/1.0: Encoding and Transport April 1999
+
+
+ 1. Although potentially redundant, a client MUST supply the target
+ of the operation both as an operation attribute and as a URI at
+ the HTTP layer. The rationale for this decision is to maintain
+ a consistent set of rules for mapping application/ipp to
+ possibly many communication layers, even where URLs are not
+ used as the addressing mechanism in the transport layer.
+ 2. Even though these two URLs might not be literally identical
+ (one being relative and the other being absolute), they MUST
+ both reference the same IPP object.
+ 3. The URI in the HTTP layer is either relative or absolute and is
+ used by the HTTP server to route the HTTP request to the
+ correct resource relative to that HTTP server. The HTTP server
+ need not be aware of the URI within the operation request.
+ 4. Once the HTTP server resource begins to process the HTTP
+ request, it might get the reference to the appropriate IPP
+ Printer object from either the HTTP URI (using to the context
+ of the HTTP server for relative URLs) or from the URI within
+ the operation request; the choice is up to the implementation.
+ 5. HTTP URIs can be relative or absolute, but the target URI in
+ the operation MUST be an absolute URI.
+
+ The model document arranges the remaining attributes into groups for
+ each operation request and response. Each such group MUST be
+ represented in the protocol by an xxx-attribute-sequence preceded by
+ the appropriate xxx-attributes-tag (See the table below and section 9
+ "Appendix A: Protocol Examples"). In addition, the order of these
+ xxx-attributes-tags and xxx-attribute-sequences in the protocol MUST
+ be the same as in the model document, but the order of attributes
+ within each xxx-attribute-sequence MUST be unspecified. The table
+ below maps the model document group name to xxx-attributes-sequence:
+
+ Model Document Group xxx-attributes-sequence
+
+ Operation Attributes operations-attributes-sequence
+ Job Template Attributes job-attributes-sequence
+ Job Object Attributes job-attributes-sequence
+ Unsupported Attributes unsupported-attributes-sequence
+ Requested Attributes job-attributes-sequence
+ Get-Job-Attributes)
+ Requested Attributes printer-attributes-sequence
+ Get-Printer-Attributes)
+ Document Content in a special position as described
+ above
+
+ If an operation contains attributes from more than one job object
+ (e.g. Get-Jobs response), the attributes from each job object MUST
+ be in a separate job-attribute-sequence, such that the attributes
+
+
+
+
+Herriot, et al. Experimental [Page 15]
+
+RFC 2565 IPP/1.0: Encoding and Transport April 1999
+
+
+ from the ith job object are in the ith job-attribute-sequence. See
+ Section 9 "Appendix A: Protocol Examples" for table showing the
+ application of the rules above.
+
+3.10 Value Length
+
+ Each attribute value MUST be preceded by a SIGNED-SHORT, which MUST
+ specify the number of octets in the value which follows this length,
+ exclusive of the two bytes specifying the length.
+
+ For any of the types represented by binary signed integers, the
+ sender MUST encode the value in exactly four octets.
+
+ For any of the types represented by character-strings, the sender
+ MUST encode the value with all the characters of the string and
+ without any padding characters.
+
+ If a value-tag contains an "out-of-band" value, such as
+ "unsupported", the value-length MUST be 0 and the value empty. The
+ value has no meaning when the value-tag has an "out-of-band" value.
+ If a client receives a response with a nonzero value-length in this
+ case, it MUST ignore the value field. If a printer receives a request
+ with a nonzero value-length in this case, it MUST reject the request.
+
+3.11 (Attribute) Value
+
+ The syntax types and most of the details of their representation are
+ defined in the IPP model document. The table below augments the
+ information in the model document, and defines the syntax types from
+ the model document in terms of the 5 basic types defined in section 3
+ "Encoding of the Operation Layer". The 5 types are US-ASCII-STRING,
+ LOCALIZED-STRING, SIGNED-INTEGER, SIGNED-SHORT, SIGNED-BYTE, and
+ OCTET-STRING.
+
+Syntax of Attribute Encoding
+Value
+
+textWithoutLanguage, LOCALIZED-STRING.
+nameWithoutLanguage
+
+textWithLanguage OCTET_STRING consisting of 4 fields:
+ a) a SIGNED-SHORT which is the number of octets
+ in the following field
+ b) a value of type natural-language,
+ c) a SIGNED-SHORT which is the number of octets
+ in the following field,
+ d) a value of type textWithoutLanguage.
+
+
+
+
+Herriot, et al. Experimental [Page 16]
+
+RFC 2565 IPP/1.0: Encoding and Transport April 1999
+
+
+ The length of a textWithLanguage value MUST be 4
+ + the value of field a + the value of field c.
+
+nameWithLanguage OCTET_STRING consisting of 4 fields:
+ a) a SIGNED-SHORT which is the number of octets
+ in the following field
+ b) a value of type natural-language,
+ c) a SIGNED-SHORT which is the number of octets
+ in the following field
+ d) a value of type nameWithoutLanguage.
+
+ The length of a nameWithLanguage value MUST be 4
+ + the value of field a + the value of field c.
+
+charset, US-ASCII-STRING.
+naturalLanguage,
+mimeMediaType,
+keyword, uri, and
+uriScheme
+
+boolean SIGNED-BYTE where 0x00 is 'false' and 0x01 is
+ 'true'.
+
+Syntax of Attribute Encoding
+Value
+
+
+integer and enum a SIGNED-INTEGER.
+
+dateTime OCTET-STRING consisting of eleven octets whose
+ contents are defined by "DateAndTime" in RFC
+ 2579 [RFC2579].
+
+resolution OCTET_STRING consisting of nine octets of 2
+ SIGNED-INTEGERs followed by a SIGNED-BYTE. The
+ first SIGNED-INTEGER contains the value of cross
+ feed direction resolution. The second SIGNED-
+ INTEGER contains the value of feed direction
+ resolution. The SIGNED-BYTE contains the units
+ value.
+
+rangeOfInteger Eight octets consisting of 2 SIGNED-INTEGERs.
+ The first SIGNED-INTEGER contains the lower
+ bound and the second SIGNED-INTEGER contains the
+ upper bound.
+
+
+
+
+
+
+Herriot, et al. Experimental [Page 17]
+
+RFC 2565 IPP/1.0: Encoding and Transport April 1999
+
+
+1setOf X Encoding according to the rules for an attribute
+ with more than 1 value. Each value X is encoded
+ according to the rules for encoding its type.
+
+octetString OCTET-STRING
+
+ The type of the value in the model document determines the encoding
+ in the value and the value of the value-tag.
+
+3.12 Data
+
+ The data part MUST include any data required by the operation
+
+4. Encoding of Transport Layer
+
+ HTTP/1.1 [RFC2068] is the transport layer for this protocol.
+
+ The operation layer has been designed with the assumption that the
+ transport layer contains the following information:
+
+ - the URI of the target job or printer operation
+ - the total length of the data in the operation layer, either as a
+ single length or as a sequence of chunks each with a length.
+
+ It is REQUIRED that a printer implementation support HTTP over the
+ IANA assigned Well Known Port 631 (the IPP default port), though a
+ printer implementation may support HTTP over some other port as well.
+ In addition, a printer may have to support another port for privacy
+ (See Section 5 "Security Considerations").
+
+ Note: even though port 631 is the IPP default, port 80 remains the
+ default for an HTTP URI. Thus a URI for a printer using port 631
+ MUST contain an explicit port, e.g. "http://forest:631/pinetree". An
+ HTTP URI for IPP with no explicit port implicitly reference port 80,
+ which is consistent with the rules for HTTP/1.1. Each HTTP operation
+ MUST use the POST method where the request-URI is the object target
+ of the operation, and where the "Content-Type" of the message-body in
+ each request and response MUST be "application/ipp". The message-body
+ MUST contain the operation layer and MUST have the syntax described
+ in section 3.2 "Syntax of Encoding". A client implementation MUST
+ adhere to the rules for a client described for HTTP1.1 [RFC2068]. A
+ printer (server) implementation MUST adhere the rules for an origin
+ server described for HTTP1.1 [RFC2068].
+
+ An IPP server sends a response for each request that it receives. If
+ an IPP server detects an error, it MAY send a response before it has
+ read the entire request. If the HTTP layer of the IPP server
+ completes processing the HTTP headers successfully, it MAY send an
+
+
+
+Herriot, et al. Experimental [Page 18]
+
+RFC 2565 IPP/1.0: Encoding and Transport April 1999
+
+
+ intermediate response, such as "100 Continue", with no IPP data
+ before sending the IPP response. A client MUST expect such a variety
+ of responses from an IPP server. For further information on HTTP/1.1,
+ consult the HTTP documents [RFC2068].
+
+5. Security Considerations
+
+ The IPP Model document defines an IPP implementation with "privacy"
+ as one that implements Secure Socket Layer Version 3 (SSL3). Note:
+ SSL3 is not an IETF standards track specification. SSL3 meets the
+ requirements for IPP security with regards to features such as mutual
+ authentication and privacy (via encryption). The IPP Model document
+ also outlines IPP-specific security considerations and should be the
+ primary reference for security implications with regards to the IPP
+ protocol itself.
+
+ The IPP Model document defines an IPP implementation with
+ "authentication" as one that implements the standard way for
+ transporting IPP messages within HTTP 1.1. These include the security
+ considerations outlined in the HTTP 1.1 standard document [RFC2068]
+ and Digest Access Authentication extension [RFC2069].
+
+ The current HTTP infrastructure supports HTTP over TCP port 80. IPP
+ server implementations MUST offer IPP services using HTTP over the
+ IANA assigned Well Known Port 631 (the IPP default port). IPP server
+ implementations may support other ports, in addition to this port.
+
+ See further discussion of IPP security concepts in the model document
+ [RFC2566].
+
+5.1 Using IPP with SSL3
+
+ An assumption is that the URI for a secure IPP Printer object has
+ been found by means outside the IPP printing protocol, via a
+ directory service, web site or other means.
+
+ IPP provides a transparent connection to SSL by calling the
+ corresponding URL (a https URI connects by default to port 443).
+ However, the following functions can be provided to ease the
+ integration of IPP with SSL during implementation:
+
+ connect (URI), returns a status
+
+ "connect" makes an https call and returns the immediate status
+ of the connection as returned by SSL to the user. The status
+ values are explained in section 5.4.2 of the SSL document
+ [ssl].
+
+
+
+
+Herriot, et al. Experimental [Page 19]
+
+RFC 2565 IPP/1.0: Encoding and Transport April 1999
+
+
+ A session-id may also be retained to later resume a session.
+ The SSL handshake protocol may also require the cipher
+ specifications supported by the client, key length of the
+ ciphers, compression methods, certificates, etc. These should
+ be sent to the server and hence should be available to the IPP
+ client (although as part of administration features).
+
+ disconnect (session)
+
+ to disconnect a particular session.
+
+ The session-id available from the "connect" could be used.
+
+ resume (session)
+
+ to reconnect using a previous session-id.
+
+ The availability of this information as administration features are
+ left for implementers, and need not be specified at this time.
+
+6. References
+
+ [RFC2278] Freed, N. and J. Postel, "IANA Charset Registration
+ Procedures", BCP 19, RFC 2278, January 1998.
+
+ [dpa] ISO/IEC 10175 Document Printing Application (DPA), June
+ 1996.
+
+ [iana] IANA Registry of Coded Character Sets:
+ ftp://ftp.isi.edu/in-notes/iana/assignments/character-sets.
+
+ [ipp-iig] Hastings, Tom, et al., "Internet Printing Protocol/1.0:
+ Implementer's Guide", Work in Progress.
+
+ [RFC2569] Herriot, R., Hastings, T., Jacobs, N. and J. Martin,
+ "Mapping between LPD and IPP Protocols", RFC 2569, April
+ 1999.
+
+ [RFC2566] deBry, R., Hastings, T., Herriot, R., Isaacson, S. and P.
+ Powell, "Internet Printing Protocol/1.0: Model and
+ Semantics", RFC 2566, April 1999.
+
+ [RFC2565] Herriot, R., Butler, S., Moore, P., Tuner, R., "Internet
+ Printing Protocol/1.0: Encoding and Transport", RFC 2565,
+ April 1999.
+
+
+
+
+
+
+Herriot, et al. Experimental [Page 20]
+
+RFC 2565 IPP/1.0: Encoding and Transport April 1999
+
+
+ [RFC2568] Zilles, S., "Rationale for the Structure and Model and
+ Protocol for the Internet Printing Protocol", RFC 2568,
+ April 1999.
+
+ [RFC2567] Wright, D., "Design Goals for an Internet Printing
+ Protocol", RFC 2567, April 1999.
+
+ [RFC822] Crocker, D., "Standard for the Format of ARPA Internet Text
+ Messages", STD 11, RFC 822, August 1982.
+
+ [RFC1123] Braden, R., "Requirements for Internet Hosts - Application
+ and Support", STD 3, RFC 1123, October 1989.
+
+ [RFC1179] McLaughlin, L. III, (editor), "Line Printer Daemon
+ Protocol" RFC 1179, August 1990.
+
+ [RFC2223] Postel, J. and J. Reynolds, "Instructions to RFC Authors",
+ RFC 2223, October 1997.
+
+ [RFC1738] Berners-Lee, T., Masinter, L. and M. McCahill, "Uniform
+ Resource Locators (URL)", RFC 1738, December 1994.
+
+ [RFC1759] Smith, R., Wright, F., Hastings, T., Zilles, S. and J.
+ Gyllenskog, "Printer MIB", RFC 1759, March 1995.
+
+ [RFC1766] Alvestrand, H., " Tags for the Identification of
+ Languages", RFC 1766, March 1995.
+
+ [RFC1808] Fielding, R., "Relative Uniform Resource Locators", RFC
+ 1808, June 1995.
+
+ [RFC2579] McCloghrie, K., Perkins, D. and J. Schoenwaelder, "Textual
+ Conventions for SMIv2", STD 58, RFC 2579, April 1999.
+
+ [RFC2046] Freed, N. and N. Borenstein, Multipurpose Internet Mail
+ Extensions (MIME) Part Two: Media Types", RFC 2046,
+ November 1996.
+
+ [RFC2048] Freed, N., Klensin J. and J. Postel. Multipurpose Internet
+ Mail Extension (MIME) Part Four: Registration Procedures",
+ BCP 13, RFC 2048, November 1996.
+
+ [RFC2068] Fielding, R., Gettys, J., Mogul, J., Frystyk, H. and T.
+ Berners-Lee, "Hypertext Transfer Protocol -- HTTP/1.1", RFC
+ 2068, January 1997.
+
+
+
+
+
+
+Herriot, et al. Experimental [Page 21]
+
+RFC 2565 IPP/1.0: Encoding and Transport April 1999
+
+
+ [RFC2069] Franks, J., Hallam-Baker, P., Hostetler, J., Leach, P.,
+ Luotonen, A., Sink, E. and L. Stewart, "An Extension to
+ HTTP: Digest Access Authentication", RFC 2069, January
+ 1997.
+
+ [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+ [RFC2184] Freed, N. and K. Moore, "MIME Parameter Value and Encoded
+ Word Extensions: Character Sets, Languages, and
+ Continuations", RFC 2184, August 1997.
+
+ [RFC2234] Crocker, D. and P. Overell, "Augmented BNF for Syntax
+ Specifications: ABNF", RFC 2234. November 1997.
+
+ [RFC2396] Berners-Lee, T., Fielding, R. and L. Masinter, "Uniform
+ Resource Identifiers (URI): Generic Syntax", RFC 2396,
+ August 1998.
+
+7. Authors' Addresses
+
+ Robert Herriot (Editor)
+ Xerox Corporation
+ 3400 Hillview Ave., Bldg #1
+ Palo Alto, CA 94304
+
+ Phone: 650-813-7696
+ Fax: 650-813-6860
+ EMail: rherriot@pahv.xerox.com
+
+
+ Sylvan Butler
+ Hewlett-Packard
+ 11311 Chinden Blvd.
+ Boise, ID 83714
+
+ Phone: 208-396-6000
+ Fax: 208-396-3457
+ EMail: sbutler@boi.hp.com
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Experimental [Page 22]
+
+RFC 2565 IPP/1.0: Encoding and Transport April 1999
+
+
+ Paul Moore
+ Microsoft
+ One Microsoft Way
+ Redmond, WA 98053
+
+ Phone: 425-936-0908
+ Fax: 425-93MS-FAX
+ EMail: paulmo@microsoft.com
+
+
+ Randy Turner
+ Sharp Laboratories
+ 5750 NW Pacific Rim Blvd
+ Camas, WA 98607
+
+ Phone: 360-817-8456
+ Fax: 360-817-8436
+ EMail: rturner@sharplabs.com
+
+
+ IPP Mailing List: ipp@pwg.org
+ IPP Mailing List Subscription: ipp-request@pwg.org
+ IPP Web Page: http://www.pwg.org/ipp/
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Experimental [Page 23]
+
+RFC 2565 IPP/1.0: Encoding and Transport April 1999
+
+
+8. Other Participants:
+
+ Chuck Adams - Tektronix Harry Lewis - IBM
+ Ron Bergman - Dataproducts Tony Liao - Vivid Image
+ Keith Carter - IBM David Manchala - Xerox
+ Angelo Caruso - Xerox Carl-Uno Manros - Xerox
+ Jeff Copeland - QMS Jay Martin - Underscore
+ Roger deBry - IBM Larry Masinter - Xerox
+ Lee Farrell - Canon Ira McDonald - High North Inc.
+ Sue Gleeson - Digital Bob Pentecost - Hewlett-Packard
+ Charles Gordon - Osicom Patrick Powell - Astart
+ Technologies
+ Brian Grimshaw - Apple Jeff Rackowitz - Intermec
+ Jerry Hadsell - IBM Xavier Riley - Xerox
+ Richard Hart - Digital Gary Roberts - Ricoh
+ Tom Hastings - Xerox Stuart Rowley - Kyocera
+ Stephen Holmstead Richard Schneider - Epson
+ Zhi-Hong Huang - Zenographics Shigern Ueda - Canon
+ Scott Isaacson - Novell Bob Von Andel - Allegro Software
+ Rich Lomicka - Digital William Wagner - Digital Products
+ David Kellerman - Northlake Jasper Wong - Xionics
+ Software
+ Robert Kline - TrueSpectra Don Wright - Lexmark
+ Dave Kuntz - Hewlett-Packard Rick Yardumian - Xerox
+ Takami Kurono - Brother Lloyd Young - Lexmark
+ Rich Landau - Digital Peter Zehler - Xerox
+ Greg LeClair - Epson Frank Zhao - Panasonic
+ Steve Zilles - Adobe
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Experimental [Page 24]
+
+RFC 2565 IPP/1.0: Encoding and Transport April 1999
+
+
+9. Appendix A: Protocol Examples
+
+9.1 Print-Job Request
+
+ The following is an example of a Print-Job request with job-name,
+ copies, and sides specified. The "ipp-attribute-fidelity" attribute
+ is set to 'true' so that the print request will fail if the "copies"
+ or the "sides" attribute are not supported or their values are not
+ supported.
+
+ Octets Symbolic Value Protocol field
+
+ 0x0100 1.0 version-number
+ 0x0002 Print-Job operation-id
+ 0x00000001 1 request-id
+ 0x01 start operation-attributes operation-attributes-tag
+ 0x47 charset type value-tag
+ 0x0012 name-length
+ attributes- attributes-charset name
+ charset
+ 0x0008 value-length
+ us-ascii US-ASCII value
+ 0x48 natural-language type value-tag
+ 0x001B name-length
+ attributes- attributes-natural-language name
+ natural-
+ language
+ 0x0005 value-length
+ en-us en-US value
+ 0x45 uri type value-tag
+ 0x000B name-length
+ printer-uri printer-uri name
+ 0x001A value-length
+ http://forest: printer pinetree value
+ 631/pinetree
+ 0x42 nameWithoutLanguage type value-tag
+ 0x0008 name-length
+ job-name job-name name
+ 0x0006 value-length
+ foobar foobar value
+ 0x22 boolean type value-tag
+ 0x16 name-length
+ ipp-attribute- ipp-attribute-fidelity name
+ fidelity
+ 0x01 value-length
+ 0x01 true value
+ 0x02 start job-attributes job-attributes-tag
+ 0x21 integer type value-tag
+
+
+
+Herriot, et al. Experimental [Page 25]
+
+RFC 2565 IPP/1.0: Encoding and Transport April 1999
+
+
+ 0x0006 name-length
+ copies copies name
+ 0x0004 value-length
+ 0x00000014 20 value
+ 0x44 keyword type value-tag
+ 0x0005 name-length
+ sides sides name
+ 0x0013 value-length
+ two-sided- two-sided-long-edge value
+ long-edge
+ 0x03 end-of-attributes end-of-attributes-tag
+ %!PS... <PostScript> data
+
+9.2 Print-Job Response (successful)
+
+ Here is an example of a successful Print-Job response to the previous
+ Print-Job request. The printer supported the "copies" and "sides"
+ attributes and their supplied values. The status code returned is '
+ successful-ok'.
+
+ Octets Symbolic Value Protocol field
+
+ 0x0100 1.0 version-number
+ 0x0000 successful-ok status-code
+ 0x00000001 1 request-id
+ 0x01 start operation-attributes operation-attributes-tag
+ 0x47 charset type value-tag
+ 0x0012 name-length
+ attributes- attributes-charset name
+ charset
+ 0x0008 value-length
+ us-ascii US-ASCII value
+ 0x48 natural-language type value-tag
+ 0x001B name-length
+ attributes- attributes-natural- name
+ natural-language language
+ 0x0005 value-length
+ en-us en-US value
+ 0x41 textWithoutLanguage type value-tag
+ 0x000E name-length
+ status-message status-message name
+ 0x000D value-length
+ successful-ok successful-ok value
+ 0x02 start job-attributes job-attributes-tag
+ 0x21 integer value-tag
+ 0x0006 name-length
+
+
+
+
+
+Herriot, et al. Experimental [Page 26]
+
+RFC 2565 IPP/1.0: Encoding and Transport April 1999
+
+
+ Octets Symbolic Value Protocol field
+
+ job-id job-id name
+ 0x0004 value-length
+ 147 147 value
+ 0x45 uri type value-tag
+ 0x0007 name-length
+ job-uri job-uri name
+ 0x001E value-length
+ http://forest:63 job 123 on pinetree value
+ 1/pinetree/123
+ 0x42 nameWithoutLanguage type value-tag
+ 0x0009 name-length
+ job-state job-state name
+ 0x0004 value-length
+ 0x0003 pending value
+ 0x03 end-of-attributes end-of-attributes-tag
+
+9.3 Print-Job Response (failure)
+
+ Here is an example of an unsuccessful Print-Job response to the
+ previous Print-Job request. It fails because, in this case, the
+ printer does not support the "sides" attribute and because the value
+ '20' for the "copies" attribute is not supported. Therefore, no job
+ is created, and neither a "job-id" nor a "job-uri" operation
+ attribute is returned. The error code returned is 'client-error-
+ attributes-or-values-not-supported' (0x040B).
+
+ Octets Symbolic Value Protocol field
+
+ 0x0100 1.0 version-number
+ 0x040B client-error-attributes-or- status-code
+ values-not-supported
+ 0x00000001 1 request-id
+ 0x01 start operation-attributes operation-attribute tag
+ 0x47 charset type value-tag
+ 0x0012 name-length
+ attributes- attributes-charset name
+ charset
+ 0x0008 value-length
+ us-ascii US-ASCII value
+ 0x48 natural-language type value-tag
+ 0x001B name-length
+ attributes- attributes-natural-language name
+ natural-
+ language
+ 0x0005 value-length
+
+
+
+
+Herriot, et al. Experimental [Page 27]
+
+RFC 2565 IPP/1.0: Encoding and Transport April 1999
+
+
+ Octets Symbolic Value Protocol field
+
+ en-us en-US value
+ 0x41 textWithoutLanguage type value-tag
+ 0x000E name-length
+ status- status-message name
+ message
+ 0x002F value-length
+ client-error- client-error-attributes-or- value
+ attributes- values-not-supported
+ or-values-
+ not-supported
+ 0x05 start unsupported-attributes unsupported-attributes tag
+ 0x21 integer type value-tag
+ 0x0006 name-length
+ copies copies name
+ 0x0004 value-length
+ 0x00000014 20 value
+ 0x10 unsupported (type) value-tag
+ 0x0005 name-length
+ sides sides name
+ 0x0000 value-length
+ 0x03 end-of-attributes end-of-attributes-tag
+
+9.4 Print-Job Response (success with attributes ignored)
+
+ Here is an example of a successful Print-Job response to a Print-Job
+ request like the previous Print-Job request, except that the value of
+ 'ipp-attribute-fidelity' is false. The print request succeeds, even
+ though, in this case, the printer supports neither the "sides"
+ attribute nor the value '20' for the "copies" attribute. Therefore, a
+ job is created, and both a "job-id" and a "job-uri" operation
+ attribute are returned. The unsupported attributes are also returned
+ in an Unsupported Attributes Group. The error code returned is '
+ successful-ok-ignored-or-substituted-attributes' (0x0001).
+
+ Octets Symbolic Value Protocol field
+
+ 0x0100 1.0 version-number
+ 0x0001 successful-ok-ignored-or- status-code
+ substituted-attributes
+ 0x00000001 1 request-id
+ 0x01 start operation-attributes operation-attributes-tag
+ 0x47 charset type value-tag
+ 0x0012 name-length
+ attributes- attributes-charset name
+ charset
+ 0x0008 value-length
+
+
+
+Herriot, et al. Experimental [Page 28]
+
+RFC 2565 IPP/1.0: Encoding and Transport April 1999
+
+
+ Octets Symbolic Value Protocol field
+
+ us-ascii US-ASCII value
+ 0x48 natural-language type value-tag
+ 0x001B name-length
+ attributes- attributes-natural- name
+ natural-language language
+ 0x0005 value-length
+ en-us en-US value
+ 0x41 textWithoutLanguage type value-tag
+ 0x000E name-length
+ status-message status-message name
+ 0x002F value-length
+ successful-ok- successful-ok-ignored-or- value
+ ignored-or- substituted-attributes
+ substituted-
+ attributes
+ 0x05 start unsupported- unsupported-attributes
+ attributes tag
+ 0x21 integer type value-tag
+ 0x0006 name-length
+ copies copies name
+ 0x0004 value-length
+ 0x00000014 20 value
+ 0x10 unsupported (type) value-tag
+ 0x0005 name-length
+ sides sides name
+ 0x0000 value-length
+ 0x02 start job-attributes job-attributes-tag
+ 0x21 integer value-tag
+ 0x0006 name-length
+ job-id job-id name
+ 0x0004 value-length
+ 147 147 value
+ 0x45 uri type value-tag
+ 0x0007 name-length
+ job-uri job-uri name
+ 0x001E value-length
+ http://forest:63 job 123 on pinetree value
+ 1/pinetree/123
+ 0x42 nameWithoutLanguage type value-tag
+ 0x0009 name-length
+ job-state job-state name
+ 0x0004 value-length
+ 0x0003 pending value
+ 0x03 end-of-attributes end-of-attributes-tag
+
+
+
+
+
+Herriot, et al. Experimental [Page 29]
+
+RFC 2565 IPP/1.0: Encoding and Transport April 1999
+
+
+9.5 Print-URI Request
+
+ The following is an example of Print-URI request with copies and
+ job-name parameters:
+
+ Octets Symbolic Value Protocol field
+
+ 0x0100 1.0 version-number
+
+ Octets Symbolic Value Protocol field
+ 0x0003 Print-URI operation-id
+ 0x00000001 1 request-id
+ 0x01 start operation-attributes operation-attributes-tag
+ 0x47 charset type value-tag
+ 0x0012 name-length
+ attributes- attributes-charset name
+ charset
+ 0x0008 value-length
+ us-ascii US-ASCII value
+ 0x48 natural-language type value-tag
+ 0x001B name-length
+ attributes- attributes-natural-language name
+ natural-
+ language
+ 0x0005 value-length
+ en-us en-US value
+ 0x45 uri type value-tag
+ 0x000B name-length
+ printer-uri printer-uri name
+ 0x001A value-length
+ http://forest printer pinetree value
+ :631/pinetree
+ 0x45 uri type value-tag
+ 0x000C name-length
+ document-uri document-uri name
+ 0x11 value-length
+ ftp://foo.com ftp://foo.com/foo value
+ /foo
+ 0x42 nameWithoutLanguage type value-tag
+ 0x0008 name-length
+ job-name job-name name
+ 0x0006 value-length
+ foobar foobar value
+ 0x02 start job-attributes job-attributes-tag
+ 0x21 integer type value-tag
+ 0x0006 name-length
+ copies copies name
+ 0x0004 value-length
+
+
+
+Herriot, et al. Experimental [Page 30]
+
+RFC 2565 IPP/1.0: Encoding and Transport April 1999
+
+
+ 0x00000001 1 value
+ 0x03 end-of-attributes end-of-attributes-tag
+
+9.6 Create-Job Request
+
+ The following is an example of Create-Job request with no parameters
+ and no attributes:
+
+ Octets Symbolic Value Protocol field
+ 0x0100 1.0 version-number
+ 0x0005 Create-Job operation-id
+ 0x00000001 1 request-id
+ 0x01 start operation-attributes operation-attributes-tag
+ 0x47 charset type value-tag
+ 0x0012 name-length
+
+ Octets Symbolic Value Protocol field
+ attributes- attributes-charset name
+ charset
+ 0x0008 value-length
+ us-ascii US-ASCII value
+ 0x48 natural-language type value-tag
+ 0x001B name-length
+ attributes- attributes-natural-language name
+ natural-
+ language
+ 0x0005 value-length
+ en-us en-US value
+ 0x45 uri type value-tag
+ 0x000B name-length
+ printer-uri printer-uri name
+ 0x001A value-length
+ http://forest: printer pinetree value
+ 631/pinetree
+ 0x03 end-of-attributes end-of-attributes-tag
+
+9.7 Get-Jobs Request
+
+ The following is an example of Get-Jobs request with parameters but
+ no attributes:
+
+ Octets Symbolic Value Protocol field
+
+ 0x0100 1.0 version-number
+ 0x000A Get-Jobs operation-id
+ 0x00000123 0x123 request-id
+ 0x01 start operation-attributes operation-attributes-tag
+ 0x47 charset type value-tag
+
+
+
+Herriot, et al. Experimental [Page 31]
+
+RFC 2565 IPP/1.0: Encoding and Transport April 1999
+
+
+ Octets Symbolic Value Protocol field
+
+ 0x0012 name-length
+ attributes- attributes-charset name
+ charset
+ 0x0008 value-length
+ us-ascii US-ASCII value
+ 0x48 natural-language type value-tag
+ 0x001B name-length
+ attributes- attributes-natural-language name
+ natural-
+ language
+ 0x0005 value-length
+ en-us en-US value
+ 0x45 uri type value-tag
+ 0x000B name-length
+ printer-uri printer-uri name
+ 0x001A value-length
+ http://forest:6 printer pinetree value
+ 31/pinetree
+ 0x21 integer type value-tag
+ 0x0005 name-length
+ limit limit name
+ 0x0004 value-length
+ 0x00000032 50 value
+ 0x44 keyword type value-tag
+ 0x0014 name-length
+ requested- requested-attributes name
+ attributes
+ 0x0006 value-length
+ job-id job-id value
+ 0x44 keyword type value-tag
+ 0x0000 additional value name-length
+ 0x0008 value-length
+ job-name job-name value
+ 0x44 keyword type value-tag
+ 0x0000 additional value name-length
+ 0x000F value-length
+ document-format document-format value
+ 0x03 end-of-attributes end-of-attributes-tag
+
+9.8 Get-Jobs Response
+
+ The following is an of Get-Jobs response from previous request with 3
+ jobs. The Printer returns no information about the second job
+ (because of security reasons):
+
+
+
+
+
+Herriot, et al. Experimental [Page 32]
+
+RFC 2565 IPP/1.0: Encoding and Transport April 1999
+
+
+ Octets Symbolic Value Protocol field
+
+ 0x0100 1.0 version-number
+ 0x0000 successful-ok status-code
+ 0x00000123 0x123 request-id (echoed
+ back)
+ 0x01 start operation-attributes operation-attribute-tag
+ 0x47 charset type value-tag
+ 0x0012 name-length
+ attributes- attributes-charset name
+ charset
+ 0x000A value-length
+ ISO-8859-1 ISO-8859-1 value
+ 0x48 natural-language type value-tag
+ 0x001B name-length
+ attributes- attributes-natural-language name
+ natural-
+ language
+ 0x0005 value-length
+ en-us en-US value
+ 0x41 textWithoutLanguage type value-tag
+ 0x000E name-length
+ status-message status-message name
+ 0x000D value-length
+ successful-ok successful-ok value
+ 0x02 start job-attributes (1st job-attributes-tag
+ object)
+ 0x21 integer type value-tag
+ 0x0006 name-length
+ job-id job-id name
+ 0x0004 value-length
+ 147 147 value
+ 0x36 nameWithLanguage value-tag
+ 0x0008 name-length
+ job-name job-name name
+ 0x000C value-length
+ 0x0005 sub-value-length
+ fr-ca fr-CA value
+ 0x0003 sub-value-length
+ fou fou name
+ 0x02 start job-attributes (2nd job-attributes-tag
+ object)
+ 0x02 start job-attributes (3rd job-attributes-tag
+ object)
+ 0x21 integer type value-tag
+ 0x0006 name-length
+ job-id job-id name
+ 0x0004 value-length
+
+
+
+Herriot, et al. Experimental [Page 33]
+
+RFC 2565 IPP/1.0: Encoding and Transport April 1999
+
+
+ Octets Symbolic Value Protocol field
+
+ 148 148 value
+ 0x36 nameWithLanguage value-tag
+ 0x0008 name-length
+ job-name job-name name
+ 0x0012 value-length
+ 0x0005 sub-value-length
+ de-CH de-CH value
+ 0x0009 sub-value-length
+ isch guet isch guet name
+ 0x03 end-of-attributes end-of-attributes-tag
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Experimental [Page 34]
+
+RFC 2565 IPP/1.0: Encoding and Transport April 1999
+
+
+10. Appendix C: Registration of MIME Media Type Information for
+ "application/ipp"
+
+ This appendix contains the information that IANA requires for
+ registering a MIME media type. The information following this
+ paragraph will be forwarded to IANA to register application/ipp whose
+ contents are defined in Section 3 "Encoding of the Operation Layer"
+ in this document:
+
+ MIME type name: application
+
+ MIME subtype name: ipp
+
+ A Content-Type of "application/ipp" indicates an Internet Printing
+ Protocol message body (request or response). Currently there is one
+ version: IPP/1.0, whose syntax is described in Section 3 "Encoding of
+ the Operation Layer" of [RFC2565], and whose semantics are described
+ in [RFC2566].
+
+ Required parameters: none
+
+ Optional parameters: none
+
+ Encoding considerations:
+
+ IPP/1.0 protocol requests/responses MAY contain long lines and ALWAYS
+ contain binary data (for example attribute value lengths).
+
+ Security considerations:
+
+ IPP/1.0 protocol requests/responses do not introduce any security
+ risks not already inherent in the underlying transport protocols.
+ Protocol mixed-version interworking rules in [RFC2566] as well as
+ protocol encoding rules in [RFC2565] are complete and unambiguous.
+
+ Interoperability considerations:
+
+ IPP/1.0 requests (generated by clients) and responses (generated by
+ servers) MUST comply with all conformance requirements imposed by the
+ normative specifications [RFC2566] and [RFC2565]. Protocol encoding
+ rules specified in [RFC2565] are comprehensive, so that
+ interoperability between conforming implementations is guaranteed
+ (although support for specific optional features is not ensured).
+ Both the "charset" and "natural-language" of all IPP/1.0 attribute
+ values which are a LOCALIZED-STRING are explicit within IPP protocol
+ requests/responses (without recourse to any external information in
+ HTTP, SMTP, or other message transport headers).
+
+
+
+
+Herriot, et al. Experimental [Page 35]
+
+RFC 2565 IPP/1.0: Encoding and Transport April 1999
+
+
+ Published specification:
+
+ [RFC2566] Isaacson, S., deBry, R., Hastings, T., Herriot, R. and P.
+ Powell, "Internet Printing Protocol/1.0: Model and
+ Semantics" RFC 2566, April 1999.
+
+ [RFC2565] Herriot, R., Butler, S., Moore, P., Tuner, R., "Internet
+ Printing Protocol/1.0: Encoding and Transport", RFC 2565,
+ April 1999.
+
+ Applications which use this media type:
+
+ Internet Printing Protocol (IPP) print clients and print servers,
+ communicating using HTTP/1.1 (see [RFC2565]), SMTP/ESMTP, FTP, or
+ other transport protocol. Messages of type "application/ipp" are
+ self-contained and transport-independent, including "charset" and
+ "natural-language" context for any LOCALIZED-STRING value.
+
+ Person & email address to contact for further information:
+
+ Scott A. Isaacson
+ Novell, Inc.
+ 122 E 1700 S
+ Provo, UT 84606
+
+ Phone: 801-861-7366
+ Fax: 801-861-4025
+ Email: sisaacson@novell.com
+
+ or
+
+ Robert Herriot (Editor)
+ Xerox Corporation
+ 3400 Hillview Ave., Bldg #1
+ Palo Alto, CA 94304
+
+ Phone: 650-813-7696
+ Fax: 650-813-6860
+ EMail: rherriot@pahv.xerox.com
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Experimental [Page 36]
+
+RFC 2565 IPP/1.0: Encoding and Transport April 1999
+
+
+11. Full Copyright Statement
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Experimental [Page 37]
+
diff --git a/standards/rfc2566.txt b/standards/rfc2566.txt
new file mode 100644
index 000000000..f373d6a0f
--- /dev/null
+++ b/standards/rfc2566.txt
@@ -0,0 +1,9691 @@
+
+
+
+
+
+
+Network Working Group R. deBry
+Request for Comments: 2566 Utah Valley State College
+Category: Experimental T. Hastings
+ Xerox Corporation
+ R. Herriot
+ Xerox Corporation
+ S. Isaacson
+ Novell, Inc.
+ P. Powell
+ Astart Technologies
+ April 1999
+
+
+ Internet Printing Protocol/1.0: Model and Semantics
+
+Status of this Memo
+
+ This memo defines an Experimental Protocol for the Internet
+ community. It does not specify an Internet standard of any kind.
+ Discussion and suggestions for improvement are requested.
+ Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+IESG Note
+
+ This document defines an Experimental protocol for the Internet
+ community. The IESG expects that a revised version of this protocol
+ will be published as Proposed Standard protocol. The Proposed
+ Standard, when published, is expected to change from the protocol
+ defined in this memo. In particular, it is expected that the
+ standards-track version of the protocol will incorporate strong
+ authentication and privacy features, and that an "ipp:" URL type will
+ be defined which supports those security measures. Other changes to
+ the protocol are also possible. Implementors are warned that future
+ versions of this protocol may not interoperate with the version of
+ IPP defined in this document, or if they do interoperate, that some
+ protocol features may not be available.
+
+ The IESG encourages experimentation with this protocol, especially in
+ combination with Transport Layer Security (TLS) [RFC 2246], to help
+ determine how TLS may effectively be used as a security layer for
+ IPP.
+
+
+
+
+
+
+deBry, et al. Experimental [Page 1]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+Abstract
+
+ This document is one of a set of documents, which together describe
+ all aspects of a new Internet Printing Protocol (IPP). IPP is an
+ application level protocol that can be used for distributed printing
+ using Internet tools and technologies. This document describes a
+ simplified model consisting of abstract objects, their attributes,
+ and their operations that is independent of encoding and transport.
+ The model consists of a Printer and a Job object. A Job optionally
+ supports multiple documents. IPP 1.0 semantics allow end-users and
+ operators to query printer capabilities, submit print jobs, inquire
+ about the status of print jobs and printers, and cancel print jobs.
+ This document also addresses security, internationalization, and
+ directory issues.
+
+ The full set of IPP documents includes:
+
+ Design Goals for an Internet Printing Protocol [RFC2567]
+ Rationale for the Structure and Model and Protocol for the Internet
+ Printing Protocol [RFC2568]
+ Internet Printing Protocol/1.0: Model and Semantics (this document)
+ Internet Printing Protocol/1.0: Encoding and Transport [RFC2565]
+ Internet Printing Protocol/1.0: Implementer's Guide [ipp-iig]
+ Mapping between LPD and IPP Protocols [RFC2569]
+
+ The "Design Goals for an Internet Printing Protocol" document takes a
+ broad look at distributed printing functionality, and it enumerates
+ real-life scenarios that help to clarify the features that need to be
+ included in a printing protocol for the Internet. It identifies
+ requirements for three types of users: end users, operators, and
+ administrators. It calls out a subset of end user requirements that
+ are satisfied in IPP/1.0. Operator and administrator requirements
+ are out of scope for version 1.0.
+
+ The "Rationale for the Structure and Model and Protocol for the
+ Internet Printing Protocol" document describes IPP from a high level
+ view, defines a roadmap for the various documents that form the suite
+ of IPP specifications, and gives background and rationale for the
+ IETF working group's major decisions.
+
+ The "Internet Printing Protocol/1.0: Encoding and Transport" document
+ is a formal mapping of the abstract operations and attributes defined
+ in the model document onto HTTP/1.1. It defines the encoding rules
+ for a new Internet media type called "application/ipp".
+
+ The "Internet Printing Protocol/1.0: Implementer's Guide" document
+ gives insight and advice to implementers of IPP clients and IPP
+ objects. It is intended to help them understand IPP/1.0 and some of
+
+
+
+deBry, et al. Experimental [Page 2]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ the considerations that may assist them in the design of their client
+ and/or IPP object implementations. For example, a typical order of
+ processing requests is given, including error checking. Motivation
+ for some of the specification decisions is also included.
+
+ The "Mapping between LPD and IPP Protocols" document gives some
+ advice to implementers of gateways between IPP and LPD (Line Printer
+ Daemon) implementations.
+
+Table of Contents
+
+1. Introduction 8
+ 1.1 Simplified Printing Model 9
+2. IPP Objects 11
+ 2.1 Printer Object 12
+ 2.2 Job Object 14
+ 2.3 Object Relationships 14
+ 2.4 Object Identity 15
+3. IPP Operations 18
+ 3.1 Common Semantics 19
+ 3.1.1 Required Parameters 19
+ 3.1.2 Operation IDs and Request IDs 20
+ 3.1.3 Attributes 20
+ 3.1.4 Character Set and Natural Language Operation Attributes 22
+ 3.1.4.1 Request Operation Attributes 22
+ 3.1.4.2 Response Operation Attributes 26
+ 3.1.5 Operation Targets 28
+ 3.1.6 Operation Status Codes and Messages 29
+ 3.1.7 Versions 30
+ 3.1.8 Job Creation Operations 32
+ 3.2 Printer Operations 34
+ 3.2.1 Print-Job Operation 34
+ 3.2.1.1 Print-Job Request 34
+ 3.2.1.2 Print-Job Response 38
+ 3.2.2 Print-URI Operation 41
+ 3.2.3 Validate-Job Operation 42
+ 3.2.4 Create-Job Operation 42
+ 3.2.5 Get-Printer-Attributes Operation 43
+ 3.2.5.1 Get-Printer-Attributes Request 44
+ 3.2.5.2 Get-Printer-Attributes Response 46
+ 3.2.6 Get-Jobs Operation 47
+ 3.2.6.1 Get-Jobs Request 47
+ 3.2.6.2 Get-Jobs Response 49
+ 3.3 Job Operations 50
+ 3.3.1 Send-Document Operation 50
+ 3.3.1.1 Send-Document Request 51
+ 3.3.1.2 Send-Document Response 53
+ 3.3.2 Send-URI Operation 54
+
+
+
+deBry, et al. Experimental [Page 3]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ 3.3.3 Cancel-Job Operation 54
+ 3.3.3.1 Cancel-Job Request 54
+ 3.3.3.2 Cancel-Job Response 55
+ 3.3.4 Get-Job-Attributes Operation 56
+ 3.3.4.1 Get-Job-Attributes Request 57
+ 3.3.4.2 Get-Job-Attributes Response 57
+4. Object Attributes 58
+ 4.1 Attribute Syntaxes 59
+ 4.1.1 'text' 60
+ 4.1.1.1 'textWithoutLanguage' 61
+ 4.1.1.2 'textWithLanguage' 61
+ 4.1.2 'name' 62
+ 4.1.2.1 'nameWithoutLanguage' 62
+ 4.1.2.2 'nameWithLanguage' 63
+ 4.1.2.3 Matching 'name' attribute values 63
+ 4.1.3 'keyword' 64
+ 4.1.4 'enum' 65
+ 4.1.5 'uri' 65
+ 4.1.6 'uriScheme' 65
+ 4.1.7 'charset' 66
+ 4.1.8 'naturalLanguage' 67
+ 4.1.9 'mimeMediaType' 67
+ 4.1.10 'octetString' 69
+ 4.1.11 'boolean' 69
+ 4.1.12 'integer' 69
+ 4.1.13 'rangeOfInteger' 69
+ 4.1.14 'dateTime' 69
+ 4.1.15 'resolution' 69
+ 4.1.16 '1setOf X' 70
+ 4.2 Job Template Attributes 70
+ 4.2.1 job-priority (integer(1:100)) 74
+ 4.2.2 job-hold-until (type3 keyword | name (MAX)) 75
+ 4.2.3 job-sheets (type3 keyword | name(MAX)) 75
+ 4.2.4 multiple-document-handling (type2 keyword) 76
+ 4.2.5 copies (integer(1:MAX)) 77
+ 4.2.6 finishings (1setOf type2 enum) 78
+ 4.2.7 page-ranges (1setOf rangeOfInteger (1:MAX)) 79
+ 4.2.8 sides (type2 keyword) 80
+ 4.2.9 number-up (integer(1:MAX)) 80
+ 4.2.10 orientation-requested (type2 enum) 81
+ 4.2.11 media (type3 keyword | name(MAX)) 82
+ 4.2.12 printer-resolution (resolution) 83
+ 4.2.13 print-quality (type2 enum) 83
+ 4.3 Job Description Attributes 84
+ 4.3.1 job-uri (uri) 85
+ 4.3.2 job-id (integer(1:MAX)) 85
+ 4.3.3 job-printer-uri (uri) 86
+ 4.3.4 job-more-info (uri) 86
+
+
+
+deBry, et al. Experimental [Page 4]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ 4.3.5 job-name (name(MAX)) 86
+ 4.3.6 job-originating-user-name (name(MAX)) 86
+ 4.3.7 job-state (type1 enum) 87
+ 4.3.8 job-state-reasons (1setOf type2 keyword) 90
+ 4.3.9 job-state-message (text(MAX)) 92
+ 4.3.10 number-of-documents (integer(0:MAX)) 93
+ 4.3.11 output-device-assigned (name(127)) 93
+ 4.3.12 time-at-creation (integer(0:MAX)) 93
+ 4.3.13 time-at-processing (integer(0:MAX)) 93
+ 4.3.14 time-at-completed (integer(0:MAX)) 94
+ 4.3.15 number-of-intervening-jobs (integer(0:MAX)) 94
+ 4.3.16 job-message-from-operator (text(127)) 94
+ 4.3.17 job-k-octets (integer(0:MAX)) 94
+ 4.3.18 job-impressions (integer(0:MAX)) 95
+ 4.3.19 job-media-sheets (integer(0:MAX)) 95
+ 4.3.20 job-k-octets-processed (integer(0:MAX)) 96
+ 4.3.21 job-impressions-completed (integer(0:MAX)) 96
+ 4.3.22 job-media-sheets-completed (integer(0:MAX)) 96
+ 4.3.23 attributes-charset (charset) 97
+ 4.3.24 attributes-natural-language (naturalLanguage) 97
+ 4.4 Printer Description Attributes 97
+ 4.4.1 printer-uri-supported (1setOf uri) 99
+ 4.4.2 uri-security-supported (1setOf type2 keyword) 100
+ 4.4.3 printer-name (name(127)) 101
+ 4.4.4 printer-location (text(127)) 101
+ 4.4.5 printer-info (text(127)) 101
+ 4.4.6 printer-more-info (uri) 101
+ 4.4.7 printer-driver-installer (uri) 102
+ 4.4.8 printer-make-and-model (text(127)) 102
+ 4.4.9 printer-more-info-manufacturer (uri) 102
+ 4.4.10 printer-state (type1 enum) 102
+ 4.4.11 printer-state-reasons (1setOf type2 keyword) 103
+ 4.4.12 printer-state-message (text(MAX)) 106
+ 4.4.13 operations-supported (1setOf type2 enum) 106
+ 4.4.14 charset-configured (charset) 107
+ 4.4.15 charset-supported (1setOf charset) 107
+ 4.4.16 natural-language-configured (naturalLanguage) 107
+ 4.4.17 generated-natural-language-supported(1setOf naturalLanguage108
+ 4.4.18 document-format-default (mimeMediaType) 108
+ 4.4.19 document-format-supported (1setOf mimeMediaType) 108
+ 4.4.20 printer-is-accepting-jobs (boolean) 109
+ 4.4.21 queued-job-count (integer(0:MAX)) 109
+ 4.4.22 printer-message-from-operator (text(127)) 109
+ 4.4.23 color-supported (boolean) 109
+ 4.4.24 reference-uri-schemes-supported (1setOf uriScheme) 109
+ 4.4.25 pdl-override-supported (type2 keyword) 110
+ 4.4.26 printer-up-time (integer(1:MAX)) 110
+ 4.4.27 printer-current-time (dateTime) 111
+
+
+
+deBry, et al. Experimental [Page 5]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ 4.4.28 multiple-operation-time-out (integer(1:MAX)) 111
+ 4.4.29 compression-supported (1setOf type3 keyword) 111
+ 4.4.30 job-k-octets-supported (rangeOfInteger(0:MAX)) 112
+ 4.4.31 job-impressions-supported (rangeOfInteger(0:MAX)) 112
+ 4.4.32 job-media-sheets-supported (rangeOfInteger(0:MAX)) 112
+5. Conformance 112
+ 5.1 Client Conformance Requirements 112
+ 5.2 IPP Object Conformance Requirements 113
+ 5.2.1 Objects 113
+ 5.2.2 Operations 113
+ 5.2.3 IPP Object Attributes 114
+ 5.2.4 Extensions 114
+ 5.2.5 Attribute Syntaxes 115
+ 5.3 Charset and Natural Language Requirements 115
+ 5.4 Security Conformance Requirements 115
+6. IANA Considerations (registered and private extensions) 116
+ 6.1 Typed 'keyword' and 'enum' Extensions 116
+ 6.2 Attribute Extensibility 119
+ 6.3 Attribute Syntax Extensibility 119
+ 6.4 Operation Extensibility 120
+ 6.5 Attribute Groups 120
+ 6.6 Status Code Extensibility 120
+ 6.7 Registration of MIME types/sub-types for document-formats 121
+ 6.8 Registration of charsets for use in 'charset' attribute values121
+7. Internationalization Considerations 121
+8. Security Considerations 125
+ 8.1 Security Scenarios 126
+ 8.1.1 Client and Server in the Same Security Domain 126
+ 8.1.2 Client and Server in Different Security Domains 126
+ 8.1.3 Print by Reference 127
+ 8.2 URIs for SSL3 and non-SSL3 Access 127
+ 8.3 The "requesting-user-name" (name(MAX)) Operation Attribute 127
+ 8.4 Restricted Queries 129
+ 8.5 Queries on jobs submitted using non-IPP protocols 129
+ 8.6 IPP Security Application Profile for SSL3 130
+9. References 131
+10. Authors' Addresses 134
+11. Formats for IPP Registration Proposals 136
+ 11.1 Type2 keyword attribute values registration 136
+ 11.2 Type3 keyword attribute values registration 137
+ 11.3 Type2 enum attribute values registration 137
+ 11.4 Type3 enum attribute values registration 137
+ 11.5 Attribute registration 138
+ 11.6 Attribute Syntax registration 138
+ 11.7 Operation registration 139
+ 11.8 Attribute Group registration 139
+ 11.9 Status code registration 139
+12.APPENDIX A: Terminology 141
+
+
+
+deBry, et al. Experimental [Page 6]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ 12.1 Conformance Terminology 141
+ 12.1.1 NEED NOT 141
+ 12.2 Model Terminology 141
+ 12.2.1 Keyword 141
+ 12.2.2 Attributes 141
+ 12.2.2.1 Attribute Name 141
+ 12.2.2.2 Attribute Group Name 142
+ 12.2.2.3 Attribute Value 142
+ 12.2.2.4 Attribute Syntax 142
+ 12.2.3 Supports 142
+ 12.2.4 print-stream page 144
+ 12.2.5 impression 144
+13.APPENDIX B: Status Codes and Suggested Status Code Messages 145
+ 13.1 Status Codes 146
+ 13.1.1 Informational 146
+ 13.1.2 Successful Status Codes 146
+ 13.1.2.1 successful-ok (0x0000) 146
+ 13.1.2.2 successful-ok-ignored-or-substituted-attributes (0x0001) 146
+ 13.1.2.3 successful-ok-conflicting-attributes (0x0002) 147
+ 13.1.3 Redirection Status Codes 147
+ 13.1.4 Client Error Status Codes 147
+ 13.1.4.1 client-error-bad-request (0x0400) 147
+ 13.1.4.2 client-error-forbidden (0x0401) 147
+ 13.1.4.3 client-error-not-authenticated (0x0402) 148
+ 13.1.4.4 client-error-not-authorized (0x0403) 148
+ 13.1.4.5 client-error-not-possible (0x0404) 148
+ 13.1.4.6 client-error-timeout (0x0405) 148
+ 13.1.4.7 client-error-not-found (0x0406) 149
+ 13.1.4.8 client-error-gone (0x0407) 149
+ 13.1.4.9 client-error-request-entity-too-large (0x0408) 149
+ 13.1.4.10client-error-request-value-too-long (0x0409) 150
+ 13.1.4.11client-error-document-format-not-supported (0x040A) 150
+ 13.1.4.12client-error-attributes-or-values-not-supported (0x040B) 150
+ 13.1.4.13client-error-uri-scheme-not-supported (0x040C) 151
+ 13.1.4.14client-error-charset-not-supported (0x040D) 151
+ 13.1.4.15client-error-conflicting-attributes (0x040E) 151
+ 13.1.5 Server Error Status Codes 151
+ 13.1.5.1 server-error-internal-error (0x0500) 151
+ 13.1.5.2 server-error-operation-not-supported (0x0501) 152
+ 13.1.5.3 server-error-service-unavailable (0x0502) 152
+ 13.1.5.4 server-error-version-not-supported (0x0503) 152
+ 13.1.5.5 server-error-device-error (0x0504) 152
+ 13.1.5.6 server-error-temporary-error (0x0505) 153
+ 13.1.5.7 server-error-not-accepting-jobs (0x0506) 153
+ 13.1.5.8 server-error-busy (0x0507) 153
+ 13.1.5.9 server-error-job-canceled (0x0508) 153
+ 13.2 Status Codes for IPP Operations 153
+14.APPENDIX C: "media" keyword values 155
+
+
+
+deBry, et al. Experimental [Page 7]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+15.APPENDIX D: Processing IPP Attributes 160
+ 15.1 Fidelity 160
+ 15.2 Page Description Language (PDL) Override 161
+ 15.3 Using Job Template Attributes During Document Processing. 163
+16.APPENDIX E: Generic Directory Schema 166
+17.APPENDIX F: Change History for the Model and Semantics document 168
+18.FULL COPYRIGHT STATEMENT 173
+
+1. Introduction
+
+ The Internet Printing Protocol (IPP) is an application level protocol
+ that can be used for distributed printing using Internet tools and
+ technologies. IPP version 1.0 (IPP/1.0) focuses only on end user
+ functionality. This document is just one of a suite of documents
+ that fully define IPP. The full set of IPP documents includes:
+
+ Design Goals for an Internet Printing Protocol [RFC2567]
+ Rationale for the Structure and Model and Protocol for the Internet
+ Printing Protocol [RFC2568]
+ Internet Printing Protocol/1.0: Model and Semantics (this document)
+ Internet Printing Protocol/1.0: Encoding and Transport [RFC2565]
+ Internet Printing Protocol/1.0: Implementer's Guide [ipp-iig]
+ Mapping between LPD and IPP Protocols [RFC2569]
+
+ Anyone reading these documents for the first time is strongly
+ encouraged to read the IPP documents in the above order.
+
+ This document is laid out as follows:
+
+ - The rest of Section 1 is an introduction to the IPP simplified
+ model for distributed printing.
+ - Section 2 introduces the object types covered in the model with
+ their basic behaviors, attributes, and interactions.
+ - Section 3 defines the operations included in IPP/1.0. IPP
+ operations are synchronous, therefore, for each operation, there
+ is a both request and a response.
+ - Section 4 defines the attributes (and their syntaxes) that are
+ used in the model.
+ - Sections 5 - 6 summarizes the implementation conformance
+ requirements for objects that support the protocol and IANA
+ considerations, respectively.
+ - Sections 7 - 11 cover the Internationalization and Security
+ considerations as well as References, Author contact information,
+ and Formats for Registration Proposals.
+ - Sections 12 - 14 are appendices that cover Terminology, Status
+ Codes and Messages, and "media" keyword values.
+
+
+
+
+
+deBry, et al. Experimental [Page 8]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ Note: This document uses terms such as "attributes",
+ "keywords", and "support". These terms have special
+ meaning and are defined in the model terminology section
+ 12.2. Capitalized terms, such as MUST, MUST NOT, REQUIRED,
+ SHOULD, SHOULD NOT, MAY, NEED NOT, and OPTIONAL, have
+ special meaning relating to conformance. These terms are
+ defined in section 12.1 on conformance terminology, most of
+ which is taken from RFC 2119 [RFC2119].
+
+ - Section 15 is an appendix that helps to clarify the effects of
+ interactions between related attributes and their values.
+ - Section 16 is an appendix that enumerates the subset of Printer
+ attributes that form a generic directory schema. These
+ attributes are useful when registering a Printer so that a
+ client can find the Printer not just by name, but by filtered
+ searches as well.
+ - Section 17 is an appendix that provides a Change History
+ summarizing the clarification and changes that might affect an
+ implementation since the June 30, 1998 draft.
+
+1.1 Simplified Printing Model
+
+ In order to achieve its goal of realizing a workable printing
+ protocol for the Internet, the Internet Printing Protocol (IPP) is
+ based on a simplified printing model that abstracts the many
+ components of real world printing solutions. The Internet is a
+ distributed computing environment where requesters of print services
+ (clients, applications, printer drivers, etc.) cooperate and interact
+ with print service providers. This model and semantics document
+ describes a simple, abstract model for IPP even though the underlying
+ configurations may be complex "n-tier" client/server systems. An
+ important simplifying step in the IPP model is to expose only the key
+ objects and interfaces required for printing. The model described in
+ this model document does not include features, interfaces, and
+ relationships that are beyond the scope of the first version of IPP
+ (IPP/1.0). IPP/1.0 incorporates many of the relevant ideas and
+ lessons learned from other specification and development efforts
+ [HTPP] [ISO10175] [LDPA] [P1387.4] [PSIS] [RFC1179] [SWP]. IPP is
+ heavily influenced by the printing model introduced in the Document
+ Printing Application (DPA) [ISO10175] standard. Although DPA
+ specifies both end user and administrative features, IPP version 1.0
+ (IPP/1.0) focuses only on end user functionality.
+
+ The IPP/1.0 model encapsulates the important components of
+ distributed printing into two object types:
+
+ - Printer (Section 2.1)
+ - Job (Section 2.2)
+
+
+
+deBry, et al. Experimental [Page 9]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ Each object type has an associated set of operations (see section 3)
+ and attributes (see section 4).
+
+ It is important, however, to understand that in real system
+ implementations (which lie underneath the abstracted IPP/1.0 model),
+ there are other components of a print service which are not
+ explicitly defined in the IPP/1.0 model. The following figure
+ illustrates where IPP/1.0 fits with respect to these other
+ components.
+
+ +--------------+
+ | Application |
+ o +. . . . . . . |
+ \|/ | Spooler |
+ / \ +. . . . . . . | +---------+
+ End-User | Print Driver |---| File |
+ +-----------+ +-----+ +------+-------+ +----+----+
+ | Browser | | GUI | | |
+ +-----+-----+ +--+--+ | |
+ | | | |
+ | +---+------------+---+ |
+ N D S | | IPP Client |------------+
+ O I E | +---------+----------+
+ T R C | |
+ I E U |
+ F C R -------------- Transport ------------------
+ I T I
+ C O T | --+
+ A R Y +--------+--------+ |
+ T Y | IPP Server | |
+ I +--------+--------+ |
+ O | |
+ N +-----------------+ | IPP Printer
+ | Print Service | |
+ +-----------------+ |
+ | --+
+ +-----------------+
+ | Output Device(s)|
+ +-----------------+
+
+ An IPP Printer object encapsulates the functions normally associated
+ with physical output devices along with the spooling, scheduling and
+ multiple device management functions often associated with a print
+ server. Printer objects are optionally registered as entries in a
+ directory where end users find and select them based on some sort of
+ filtered and context based searching mechanism (see section 16). The
+ directory is used to store relatively static information about the
+ Printer, allowing end users to search for and find Printers that
+
+
+
+deBry, et al. Experimental [Page 10]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ match their search criteria, for example: name, context, printer
+ capabilities, etc. The more dynamic information, such as state,
+ currently loaded and ready media, number of jobs at the Printer,
+ errors, warnings, and so forth, is directly associated with the
+ Printer object itself rather than with the entry in the directory
+ which only represents the Printer object.
+
+ IPP clients implement the IPP protocol on the client side and give
+ end users (or programs running on behalf of end users) the ability to
+ query Printer objects and submit and manage print jobs. An IPP
+ server is just that part of the Printer object that implements the
+ server-side protocol. The rest of the Printer object implements (or
+ gateways into) the application semantics of the print service itself.
+ The Printer objects may be embedded in an output device or may be
+ implemented on a host on the network that communicates with an output
+ device.
+
+ When a job is submitted to the Printer object and the Printer object
+ validates the attributes in the submission request, the Printer
+ object creates a new Job object. The end user then interacts with
+ this new Job object to query its status and monitor the progress of
+ the job. End users may also cancel the print job by using the Job
+ object's Cancel-Job operation. The notification service is out of
+ scope for IPP/1.0, but using such a notification service, the end
+ user is able to register for and receive Printer specific and Job
+ specific events. An end user can query the status of Printer objects
+ and can follow the progress of Job objects by polling using the Get-
+ Printer-Attributes, Get-Jobs, and Get-Job-Attributes operations.
+
+2. IPP Objects
+
+ The IPP/1.0 model introduces objects of type Printer and Job. Each
+ type of object models relevant aspects of a real-world entity such as
+ a real printer or real print job. Each object type is defined as a
+ set of possible attributes that may be supported by instances of that
+ object type. For each object (instance), the actual set of supported
+ attributes and values describe a specific implementation. The
+ object's attributes and values describe its state, capabilities,
+ realizable features, job processing functions, and default behaviors
+ and characteristics. For example, the Printer object type is defined
+ as a set of attributes that each Printer object potentially supports.
+ In the same manner, the Job object type is defined as a set of
+ attributes that are potentially supported by each Job object.
+
+ Each attribute included in the set of attributes defining an object
+ type is labeled as:
+
+
+
+
+
+deBry, et al. Experimental [Page 11]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ - "REQUIRED": each object MUST support the attribute.
+ - "OPTIONAL": each object MAY support the attribute.
+
+ There is no such similar labeling of attribute values. However, if
+ an implementation supports an attribute, it MUST support at least one
+ of the possible values for that attribute.
+
+2.1 Printer Object
+
+ The major component of the IPP/1.0 model is the Printer object. A
+ Printer object implements the server-side of the IPP/1.0 protocol.
+ Using the protocol, end users may query the attributes of the Printer
+ object and submit print jobs to the Printer object. The actual
+ implementation components behind the Printer abstraction may take on
+ different forms and different configurations. However, the model
+ abstraction allows the details of the configuration of real
+ components to remain opaque to the end user. Section 3 describes
+ each of the Printer operations in detail.
+
+ The capabilities and state of a Printer object are described by its
+ attributes. Printer attributes are divided into two groups:
+
+ - "job-template" attributes: These attributes describe supported
+ job processing capabilities and defaults for the Printer object.
+ (See section 4.2)
+ - "printer-description" attributes: These attributes describe the
+ Printer object's identification, state, location, references to
+ other sources of information about the Printer object, etc. (see
+ section 4.4)
+
+ Since a Printer object is an abstraction of a generic document output
+ device and print service provider, a Printer object could be used to
+ represent any real or virtual device with semantics consistent with
+ the Printer object, such as a fax device, an imager, or even a CD
+ writer.
+
+ Some examples of configurations supporting a Printer object include:
+
+ 1) An output device with no spooling capabilities
+ 2) An output device with a built-in spooler
+ 3) A print server supporting IPP with one or more associated output
+ devices
+ 3a) The associated output devices may or may not be capable of
+ spooling jobs
+ 3b) The associated output devices may or may not support IPP
+
+
+
+
+
+
+deBry, et al. Experimental [Page 12]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ The following figures show some examples of how Printer objects can
+ be realized on top of various distributed printing configurations.
+ The embedded case below represents configurations 1 and 2. The hosted
+ and fan-out figures below represent configurations 3a and 3b.
+
+ Legend:
+
+ ##### indicates a Printer object which is
+ either embedded in an output device or is
+ hosted in a server. The Printer object
+ might or might not be capable of queuing/spooling.
+
+ any indicates any network protocol or direct
+ connect, including IPP
+
+
+ embedded printer:
+ output device
+ +---------------+
+ O +--------+ | ########### |
+ /|\ | client |------------IPP------------># Printer # |
+ / \ +--------+ | # Object # |
+ | ########### |
+ +---------------+
+
+
+ hosted printer:
+ +---------------+
+ O +--------+ ########### | |
+ /|\ | client |--IPP--># Printer #-any->| output device |
+ / \ +--------+ # Object # | |
+ ########### +---------------+
+
+
+
+ +---------------+
+ fan out: | |
+ +-->| output device |
+ any/ | |
+ O +--------+ ########### / +---------------+
+ /|\ | client |-IPP-># Printer #--*
+ / \ +--------+ # Object # \ +---------------+
+ ########### any\ | |
+ +-->| output device |
+ | |
+ +---------------+
+
+
+
+
+
+deBry, et al. Experimental [Page 13]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+2.2 Job Object
+
+ A Job object is used to model a print job. A Job object contains
+ documents. The information required to create a Job object is sent
+ in a create request from the end user via an IPP Client to the
+ Printer object. The Printer object validates the create request, and
+ if the Printer object accepts the request, the Printer object creates
+ the new Job object. Section 3 describes each of the Job operations
+ in detail.
+
+ The characteristics and state of a Job object are described by its
+ attributes. Job attributes are grouped into two groups as follows:
+
+ - "job-template" attributes: These attributes can be supplied by
+ the client or end user and include job processing instructions
+ which are intended to override any Printer object defaults and/or
+ instructions embedded within the document data. (See section 4.2)
+ - "job-description" attributes: These attributes describe the Job
+ object's identification, state, size, etc. The client supplies
+ some of these attributes, and the Printer object generates others.
+ (See section 4.3)
+
+ An implementation MUST support at least one document per Job object.
+ An implementation MAY support multiple documents per Job object. A
+ document is either:
+
+ - a stream of document data in a format supported by the Printer
+ object (typically a Page Description Language - PDL), or
+ - a reference to such a stream of document data
+
+ In IPP/1.0, a document is not modeled as an IPP object, therefore it
+ has no object identifier or associated attributes. All job
+ processing instructions are modeled as Job object attributes. These
+ attributes are called Job Template attributes and they apply equally
+ to all documents within a Job object.
+
+2.3 Object Relationships
+
+ IPP objects have relationships that are maintained persistently along
+ with the persistent storage of the object attributes.
+
+ A Printer object can represent either one or more physical output
+ devices or a logical device which "processes" jobs but never actually
+ uses a physical output device to put marks on paper. Examples of
+ logical devices include a Web page publisher or a gateway into an
+ online document archive or repository. A Printer object contains
+ zero or more Job objects.
+
+
+
+
+deBry, et al. Experimental [Page 14]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ A Job object is contained by exactly one Printer object, however the
+ identical document data associated with a Job object could be sent to
+ either the same or a different Printer object. In this case, a
+ second Job object would be created which would be almost identical to
+ the first Job object, however it would have new (different) Job
+ object identifiers (see section 2.4).
+
+ A Job object is either empty (before any documents have been added)
+ or contains one or more documents. If the contained document is a
+ stream of document data, that stream can be contained in only one
+ document. However, there can be identical copies of the stream in
+ other documents in the same or different Job objects. If the
+ contained document is just a reference to a stream of document data,
+ other documents (in the same or different Job object(s)) may contain
+ the same reference.
+
+2.4 Object Identity
+
+ All Printer and Job objects are identified by a Uniform Resource
+ Identifier (URI) [RFC2396] so that they can be persistently and
+ unambiguously referenced. The notion of a URI is a useful concept,
+ however, until the notion of URI is more stable (i.e., defined more
+ completely and deployed more widely), it is expected that the URIs
+ used for IPP objects will actually be URLs [RFC2396]. Since every
+ URL is a specialized form of a URI, even though the more generic term
+ URI is used throughout the rest of this document, its usage is
+ intended to cover the more specific notion of URL as well.
+
+ An administrator configures Printer objects to either support or not
+ support authentication and/or message privacy using SSL3 [SSL] (the
+ mechanism for security configuration is outside the scope of
+ IPP/1.0). In some situations, both types of connections (both
+ authenticated and unauthenticated) can be established using a single
+ communication channel that has some sort of negotiation mechanism.
+ In other situations, multiple communication channels are used, one
+ for each type of security configuration. Section 8 provides a full
+ description of all security considerations and configurations.
+
+ If a Printer object supports more than one communication channel,
+ some or all of those channels might support and/or require different
+ security mechanisms. In such cases, an administrator could expose
+ the simultaneous support for these multiple communication channels as
+ multiple URIs for a single Printer object where each URI represents
+ one of the communication channels to the Printer object. To support
+ this flexibility, the IPP Printer object type defines a multi-valued
+ identification attribute called the "printer-uri-supported"
+ attribute. It MUST contain at least one URI. It MAY contain more
+ than one URI. That is, every Printer object will have at least one
+
+
+
+deBry, et al. Experimental [Page 15]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ URI that identifies at least one communication channel to the Printer
+ object, but it may have more than one URI where each URI identifies a
+ different communication channel to the Printer object. The
+ "printer-uri-supported" attribute has a companion attribute, the
+ "uri-security-supported" attribute, that has the same cardinality as
+ "printer-uri-supported". The purpose of the "uri-security-supported"
+ attribute is to indicate the security mechanisms (if any) used for
+ each URI listed in "printer-uri-supported". These two attributes are
+ fully described in sections 4.4.1 and 4.4.2.
+
+ When a job is submitted to the Printer object via a create request,
+ the client supplies only a single Printer object URI. The client
+ supplied Printer object URI MUST be one of the values in the
+ "printer-uri-supported" Printer attribute.
+
+ Note: IPP/1.0 does not specify how the client obtains the client
+ supplied URI, but it is RECOMMENDED that a Printer object be
+ registered as an entry in a directory service. End-users and
+ programs can then interrogate the directory searching for Printers.
+ Section 16 defines a generic schema for Printer object entries in the
+ directory service and describes how the entry acts as a bridge to the
+ actual IPP Printer object. The entry in the directory that
+ represents the IPP Printer object includes the possibly many URIs for
+ that Printer object as values in one its attributes.
+
+ When a client submits a create request to the Printer object, the
+ Printer object validates the request and creates a new Job object.
+ The Printer object assigns the new Job object a URI which is stored
+ in the "job-uri" Job attribute. This URI is then used by clients as
+ the target for subsequent Job operations. The Printer object
+ generates a Job URI based on its configured security policy and the
+ URI used by the client in the create request.
+
+ For example, consider a Printer object that supports both a
+ communication channel secured by the use of SSL3 (using HTTP over
+ SSL3 with an "https" schemed URI) and another open communication
+ channel that is not secured with SSL3 (using a simple "http" schemed
+ URI). If a client were to submit a job using the secure URI, the
+ Printer object would assign the new Job object a secure URI as well.
+ If a client were to submit a job using the open-channel URI, the
+ Printer would assign the new Job object an open-channel URI.
+
+ In addition, the Printer object also populates the Job object's
+ "job-printer-uri" attribute. This is a reference back to the Printer
+ object that created the Job object. If a client only has access to a
+ Job object's "job-uri" identifier, the client can query the Job's
+ "job-printer-uri" attribute in order to determine which Printer
+ object created the Job object. If the Printer object supports more
+
+
+
+deBry, et al. Experimental [Page 16]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ than one URI, the Printer object picks the one URI supplied by the
+ client when creating the job to build the value for and to populate
+ the Job's "job-printer-uri" attribute.
+
+ Allowing Job objects to have URIs allows for flexibility and
+ scalability. For example, in some implementations, the Printer
+ object might create Jobs that are processed in the same local
+ environment as the Printer object itself. In this case, the Job URI
+ might just be a composition of the Printer's URI and some unique
+ component for the Job object, such as the unique 32-bit positive
+ integer mentioned later in this paragraph. In other implementations,
+ the Printer object might be a central clearing-house for validating
+ all Job object creation requests, but the Job object itself might be
+ created in some environment that is remote from the Printer object.
+ In this case, the Job object's URI may have no physical-location
+ relationship at all to the Printer object's URI. Again, the fact
+ that Job objects have URIs allows for flexibility and scalability,
+ however, many existing printing systems have local models or
+ interface constraints that force print jobs to be identified using
+ only a 32-bit positive integer rather than an independent URI. This
+ numeric Job ID is only unique within the context of the Printer
+ object to which the create request was originally submitted.
+ Therefore, in order to allow both types of client access to IPP Job
+ objects (either by Job URI or by numeric Job ID), when the Printer
+ object successfully processes a create request and creates a new Job
+ object, the Printer object MUST generate both a Job URI and a Job ID.
+ The Job ID (stored in the "job-id" attribute) only has meaning in the
+ context of the Printer object to which the create request was
+ originally submitted. This requirement to support both Job URIs and
+ Job IDs allows all types of clients to access Printer objects and Job
+ objects no matter the local constraints imposed on the client
+ implementation.
+
+ In addition to identifiers, Printer objects and Job objects have
+ names ("printer-name" and "job-name"). An object name NEED NOT be
+ unique across all instances of all objects. A Printer object's name
+ is chosen and set by an administrator through some mechanism outside
+ the scope of IPP/1.0. A Job object's name is optionally chosen and
+ supplied by the IPP client submitting the job. If the client does
+ not supply a Job object name, the Printer object generates a name for
+ the new Job object. In all cases, the name only has local meaning.
+
+ To summarize:
+
+ - Each Printer object is identified with one or more URIs. The
+ Printer's "printer-uri-supported" attribute contains the URI(s).
+
+
+
+
+
+deBry, et al. Experimental [Page 17]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ - The Printer object's "uri-security-supported" attribute
+ identifies the communication channel security protocols that may
+ or may not have been configured for the various Printer object
+ URIs (e.g., 'ssl3' or 'none').
+ - Each Job object is identified with a Job URI. The Job's "job-uri"
+ attribute contains the URI.
+ - Each Job object is also identified with Job ID which is a 32-bit,
+ positive integer. The Job's "job-id" attribute contains the Job
+ ID. The Job ID is only unique within the context of the Printer
+ object which created the Job object.
+ - Each Job object has a "job-printer-uri" attribute which contains
+ the URI of the Printer object that was used to create the Job
+ object. This attribute is used to determine the Printer object
+ that created a Job object when given only the URI for the Job
+ object. This linkage is necessary to determine the languages,
+ charsets, and operations which are supported on that Job (the
+ basis for such support comes from the creating Printer object).
+ - Each Printer object has a name (which is not necessarily unique).
+ The administrator chooses and sets this name through some
+ mechanism outside the scope of IPP/1.0 itself. The Printer
+ object's "printer-name" attribute contains the name.
+ - Each Job object has a name (which is not necessarily unique). The
+ client optionally supplies this name in the create request. If
+ the client does not supply this name, the Printer object generates
+ a name for the Job object. The Job object's "job-name" attribute
+ contains the name.
+
+3. IPP Operations
+
+ IPP objects support operations. An operation consists of a request
+ and a response. When a client communicates with an IPP object, the
+ client issues an operation request to the URI for that object.
+ Operation requests and responses have parameters that identify the
+ operation. Operations also have attributes that affect the run-time
+ characteristics of the operation (the intended target, localization
+ information, etc.). These operation-specific attributes are called
+ operation attributes (as compared to object attributes such as
+ Printer object attributes or Job object attributes). Each request
+ carries along with it any operation attributes, object attributes,
+ and/or document data required to perform the operation. Each request
+ requires a response from the object. Each response indicates success
+ or failure of the operation with a status code as a response
+ parameter. The response contains any operation attributes, object
+ attributes, and/or status messages generated during the execution of
+ the operation request.
+
+
+
+
+
+
+deBry, et al. Experimental [Page 18]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ This section describes the semantics of the IPP operations, both
+ requests and responses, in terms of the parameters, attributes, and
+ other data associated with each operation.
+
+ The IPP/1.0 Printer operations are:
+
+ Print-Job (section 3.2.1)
+ Print-URI (section 3.2.2)
+ Validate-Job (section 3.2.3)
+ Create-Job (section 3.2.4)
+ Get-Printer-Attributes (section 3.2.5)
+ Get-Jobs (section 3.2.6)
+
+ The Job operations are:
+
+ Send-Document (section 3.3.1)
+ Send-URI (section 3.3.2)
+ Cancel-Job (section 3.3.3)
+ Get-Job-Attributes (section 3.3.4)
+
+ The Send-Document and Send-URI Job operations are used to add a new
+ document to an existing multi-document Job object created using the
+ Create-Job operation.
+
+3.1 Common Semantics
+
+ All IPP operations require some common parameters and operation
+ attributes. These common elements and their semantic characteristics
+ are defined and described in more detail in the following sections.
+
+3.1.1 Required Parameters
+
+ Every operation request contains the following REQUIRED parameters:
+
+ - a "version-number",
+ - an "operation-id",
+ - a "request-id", and
+ - the attributes that are REQUIRED for that type of request.
+
+ Every operation response contains the following REQUIRED parameters:
+
+ - a "version-number",
+ - a "status-code",
+ - the "request-id" that was supplied in the corresponding request,
+ and
+ - the attributes that are REQUIRED for that type of response.
+
+
+
+
+
+deBry, et al. Experimental [Page 19]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ The encoding and transport document [RFC2565] defines special rules
+ for the encoding of these parameters. All other operation elements
+ are represented using the more generic encoding rules for attributes
+ and groups of attributes.
+
+3.1.2 Operation IDs and Request IDs
+
+ Each IPP operation request includes an identifying "operation-id"
+ value. Valid values are defined in the "operations-supported"
+ Printer attribute section (see section 4.4.13). The client specifies
+ which operation is being requested by supplying the correct
+ "operation-id" value.
+
+ In addition, every invocation of an operation is identified by a
+ "request-id" value. For each request, the client chooses the
+ "request-id" which MUST be an integer (possibly unique depending on
+ client requirements) in the range from 1 to 2**31 - 1 (inclusive).
+ This "request-id" allows clients to manage multiple outstanding
+ requests. The receiving IPP object copies all 32-bits of the client-
+ supplied "request-id" attribute into the response so that the client
+ can match the response with the correct outstanding request, even if
+ the "request-id" is out of range. If the request is terminated
+ before the complete "request-id" is received, the IPP object rejects
+ the request and returns a response with a "request-id" of 0.
+
+ Note: In some cases, the transport protocol underneath IPP might be a
+ connection oriented protocol that would make it impossible for a
+ client to receive responses in any order other than the order in
+ which the corresponding requests were sent. In such cases, the
+ "request-id" attribute would not be essential for correct protocol
+ operation. However, in other mappings, the operation responses can
+ come back in any order. In these cases, the "request-id" would be
+ essential.
+
+3.1.3 Attributes
+
+ Operation requests and responses are both composed of groups of
+ attributes and/or document data. The attributes groups are:
+
+ - Operation Attributes: These attributes are passed in the
+ operation and affect the IPP object's behavior while processing
+ the operation request and may affect other attributes or groups
+ of attributes. Some operation attributes describe the document
+ data associated with the print job and are associated with new
+ Job objects, however most operation attributes do not persist
+ beyond the life of the operation. The description of each
+ operation attribute includes conformance statements indicating
+ which operation attributes are REQUIRED and which are OPTIONAL
+
+
+
+deBry, et al. Experimental [Page 20]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ for an IPP object to support and which attributes a client MUST
+ supply in a request and an IPP object MUST supply in a response.
+ - Job Template Attributes: These attributes affect the processing
+ of a job. A client OPTIONALLY supplies Job Template Attributes
+ in a create request, and the receiving object MUST be prepared to
+ receive all supported attributes. The Job object can later be
+ queried to find out what Job Template attributes were originally
+ requested in the create request, and such attributes are returned
+ in the response as Job Object Attributes. The Printer object can
+ be queried about its Job Template attributes to find out what
+ type of job processing capabilities are supported and/or what the
+ default job processing behaviors are, though such attributes are
+ returned in the response as Printer Object Attributes. The
+ "ipp-attribute-fidelity" operation attribute affects processing
+ of all client-supplied Job Template attributes (see section 15
+ for a full description of "ipp-attribute-fidelity" and its
+ relationship to other attributes).
+ - Job Object Attributes: These attributes are returned in response
+ to a query operation directed at a Job object.
+ - Printer Object Attributes: These attributes are returned in
+ response to a query operation directed at a Printer object.
+ - Unsupported Attributes: In a create request, the client supplies
+ a set of Operation and Job Template attributes. If any of these
+ attributes or their values is unsupported by the Printer object,
+ the Printer object returns the set of unsupported attributes in
+ the response. Section 15 gives a full description of how Job
+ Template attributes supplied by the client in a create request
+ are processed by the Printer object and how unsupported
+ attributes are returned to the client. Because of extensibility,
+ any IPP object might receive a request that contains new or
+ unknown attributes or values for which it has no support. In such
+ cases, the IPP object processes what it can and returns the
+ unsupported attributes in the response.
+
+ Later in this section, each operation is formally defined by
+ identifying the allowed and expected groups of attributes for each
+ request and response. The model identifies a specific order for each
+ group in each request or response, but the attributes within each
+ group may be in any order, unless specified otherwise.
+
+ Each attribute specification includes the attribute's name followed
+ by the name of its attribute syntax(es) in parenthesizes. In
+ addition, each 'integer' attribute is followed by the allowed range
+ in parentheses, (m:n), for values of that attribute. Each 'text' or
+ 'name' attribute is followed by the maximum size in octets in
+ parentheses, (size), for values of that attribute. For more details
+ on attribute syntax notation, see the descriptions of these
+ attributes syntaxes in section 4.1.
+
+
+
+deBry, et al. Experimental [Page 21]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ Note: Document data included in the operation is not strictly an
+ attribute, but it is treated as a special attribute group for
+ ordering purposes. The only operations that support supplying the
+ document data within an operation request are Print-Job and Send-
+ Document. There are no operation responses that include document
+ data.
+
+ Note: Some operations are REQUIRED for IPP objects to support; the
+ others are OPTIONAL (see section 5.2.2). Therefore, before using an
+ OPTIONAL operation, a client SHOULD first use the REQUIRED Get-
+ Printer-Attributes operation to query the Printer's "operations-
+ supported" attribute in order to determine which OPTIONAL Printer and
+ Job operations are actually supported. The client SHOULD NOT use an
+ OPTIONAL operation that is not supported. When an IPP object
+ receives a request to perform an operation it does not support, it
+ returns the 'server-error-operation-not-supported' status code (see
+ section 13.1.5.2). An IPP object is non-conformant if it does not
+ support a REQUIRED operation.
+
+3.1.4 Character Set and Natural Language Operation Attributes
+
+ Some Job and Printer attributes have values that are text strings and
+ names intended for human understanding rather than machine
+ understanding (see the 'text' and 'name' attribute syntax
+ descriptions in section 4.1). The following sections describe two
+ special Operation Attributes called "attributes-charset" and
+ "attributes-natural-language". These attributes are always part of
+ the Operation Attributes group. For most attribute groups, the order
+ of the attributes within the group is not important. However, for
+ these two attributes within the Operation Attributes group, the order
+ is critical. The "attributes-charset" attribute MUST be the first
+ attribute in the group and the "attributes-natural-language"
+ attribute MUST be the second attribute in the group. In other words,
+ these attributes MUST be supplied in every IPP request and response,
+ they MUST come first in the group, and MUST come in the specified
+ order. For job creation operations, the IPP Printer implementation
+ saves these two attributes with the new Job object as Job Description
+ attributes. For the sake of brevity in this document, these
+ operation attribute descriptions are not repeated with every
+ operation request and response, but have a reference back to this
+ section instead.
+
+3.1.4.1 Request Operation Attributes
+
+ The client MUST supply and the Printer object MUST support the
+ following REQUIRED operation attributes in every IPP/1.0 operation
+ request:
+
+
+
+
+deBry, et al. Experimental [Page 22]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ "attributes-charset" (charset):
+ This operation attribute identifies the charset (coded character
+ set and encoding method) used by any 'text' and 'name'
+ attributes that the client is supplying in this request. It
+ also identifies the charset that the Printer object MUST use (if
+ supported) for all 'text' and 'name' attributes and status
+ messages that the Printer object returns in the response to this
+ request. See Sections 4.1.1 and 4.1.2 for the specification of
+ the 'text' and 'name' attribute syntaxes.
+
+ All clients and IPP objects MUST support the 'utf-8' charset
+ [RFC2279] and MAY support additional charsets provided that they
+ are registered with IANA [IANA-CS]. If the Printer object does
+ not support the client supplied charset value, the Printer
+ object MUST reject the request, set the "attributes-charset" to
+ 'utf-8' in the response, and return the 'client-error-charset-
+ not-supported' status code and any 'text' or 'name' attributes
+ using the 'utf-8' charset. The Printer object MUST indicate the
+ charset(s) supported as the values of the "charset-supported"
+ Printer attribute (see Section 4.4.15), so that the client can
+ query to determine which charset(s) are supported.
+
+ Note to client implementers: Since IPP objects are only required
+ to support the 'utf-8' charset, in order to maximize
+ interoperability with multiple IPP object implementations, a
+ client may want to supply 'utf-8' in the "attributes-charset"
+ operation attribute, even though the client is only passing and
+ able to present a simpler charset, such as US-ASCII or ISO-
+ 8859-1. Then the client will have to filter out (or charset
+ convert) those characters that are returned in the response that
+ it cannot present to its user. On the other hand, if both the
+ client and the IPP objects also support a charset in common
+ besides utf-8, the client may want to use that charset in order
+ to avoid charset conversion or data loss.
+
+ See the 'charset' attribute syntax description in Section 4.1.7
+ for the syntax and semantic interpretation of the values of this
+ attribute and for example values.
+
+ "attributes-natural-language" (naturalLanguage):
+ This operation attribute identifies the natural language used by
+ any 'text' and 'name' attributes that the client is supplying in
+ this request. This attribute also identifies the natural
+ language that the Printer object SHOULD use for all 'text' and '
+ name' attributes and status messages that the Printer object
+ returns in the response to this request.
+
+
+
+
+
+deBry, et al. Experimental [Page 23]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ There are no REQUIRED natural languages required for the Printer
+ object to support. However, the Printer object's "generated-
+ natural-language-supported" attribute identifies the natural
+ languages supported by the Printer object and any contained Job
+ objects for all text strings generated by the IPP object. A
+ client MAY query this attribute to determine which natural
+ language(s) are supported for generated messages.
+
+ For any of the attributes for which the Printer object generates
+ text, i.e., for the "job-state-message", "printer-state-
+ message", and status messages (see Section 3.1.6), the Printer
+ object MUST be able to generate these text strings in any of its
+ supported natural languages. If the client requests a natural
+ language that is not supported, the Printer object MUST return
+ these generated messages in the Printer's configured natural
+ language as specified by the Printer's "natural-language-
+ configured" attribute" (see Section 4.4.16).
+
+ For other 'text' and 'name' attributes supplied by the client,
+ authentication system, operator, system administrator, or
+ manufacturer (i.e., for "job-originating-user-name", "printer-
+ name" (name), "printer-location" (text), "printer-info" (text),
+ and "printer-make-and-model" (text)), the Printer object is only
+ required to support the configured natural language of the
+ Printer identified by the Printer object's "natural-language-
+ configured" attribute, though support of additional natural
+ languages for these attributes is permitted.
+
+ For any 'text' or 'name' attribute in the request that is in a
+ different natural language than the value supplied in the
+ "attributes-natural-language" operation attribute, the client
+ MUST use the Natural Language Override mechanism (see sections
+ 4.1.1.2 and 4.1.2.2) for each such attribute value supplied.
+ The client MAY use the Natural Language Override mechanism
+ redundantly, i.e., use it even when the value is in the same
+ natural language as the value supplied in the "attributes-
+ natural-language" operation attribute of the request.
+
+ The IPP object MUST accept any natural language and any Natural
+ Language Override, whether the IPP object supports that natural
+ language or not (and independent of the value of the "ipp-
+ attribute-fidelity" Operation attribute). That is the IPP
+ object accepts all client supplied values no matter what the
+ values are in the Printer object's "generated-natural-language-
+ supported" attribute. That attribute, "generated-natural-
+ language-supported", only applies to generated messages,
+
+
+
+
+
+deBry, et al. Experimental [Page 24]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ not client supplied messages. The IPP object MUST remember that
+ natural language for all client-supplied attributes, and when
+ returning those attributes in response to a query, the IPP
+ object MUST indicate that natural language.
+
+ Each value whose attribute syntax type is 'text' or 'name' (see
+ sections 4.1.1 and 4.1.2) has an Associated Natural-Language.
+ This document does not specify how this association is stored in
+ a Printer or Job object. When such a value is encoded in a
+ request or response, the natural language is either implicit or
+ explicit:
+
+ - In the implicit case, the value contains only the
+ text/name value, and the language is specified by the
+ "attributes-natural-language" operation attribute in the
+ request or response (see sections 4.1.1.1
+ textWithoutLanguage and 4.1.2.1 nameWithoutLanguage).
+
+ - In the explicit case (also known as the Natural-Language
+ Override case), the value contains both the language and
+ the text/name value (see sections 4.1.1.2
+ textWithLanguage and 4.1.2.2 nameWithLanguage).
+
+ For example, the "job-name" attribute MAY be supplied by the
+ client in a create request. The text value for this attribute
+ will be in the natural language identified by the "attribute-
+ natural-language" attribute, or if different, as identified by
+ the Natural Language Override mechanism. If supplied, the IPP
+ object will use the value of the "job-name" attribute to
+ populate the Job object's "job-name" attribute. Whenever any
+ client queries the Job object's "job-name" attribute, the IPP
+ object returns the attribute as stored and uses the Natural
+ Language Override mechanism to specify the natural language, if
+ it is different from that reported in the "attributes-natural-
+ language" operation attribute of the response. The IPP object
+ MAY use the Natural Language Override mechanism redundantly,
+ i.e., use it even when the value is in the same natural language
+ as the value supplied in the "attributes-natural-language"
+ operation attribute of the response.
+
+ An IPP object MUST NOT reject a request based on a supplied
+ natural language in an "attributes-natural-language" Operation
+ attribute or in any attribute that uses the Natural Language
+ Override.
+
+ See the 'naturalLanguage' attribute syntax description in
+ section 4.1.8 for the syntax and semantic interpretation of the
+ values of this attribute and for example values.
+
+
+
+deBry, et al. Experimental [Page 25]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ Clients SHOULD NOT supply 'text' or 'name' attributes that use an
+ illegal combination of natural language and charset. For example,
+ suppose a Printer object supports charsets 'utf-8', 'iso-8859-1', and
+ 'iso-8859-7'. Suppose also, that it supports natural languages 'en'
+ (English), 'fr' (French), and 'el' (Greek). Although the Printer
+ object supports the charset 'iso-8859-1' and natural language 'el',
+ it probably does not support the combination of Greek text strings
+ using the 'iso-8859-1' charset. The Printer object handles this
+ apparent incompatibility differently depending on the context in
+ which it occurs:
+
+ - In a create request: If the client supplies a text or name
+ attribute (for example, the "job-name" operation attribute) that
+ uses an apparently incompatible combination, it is a client
+ choice that does not affect the Printer object or its correct
+ operation. Therefore, the Printer object simply accepts the
+ client supplied value, stores it with the Job object, and
+ responds back with the same combination whenever the client (or
+ any client) queries for that attribute.
+ - In a query-type operation, like Get-Printer-Attributes: If the
+ client requests an apparently incompatible combination, the
+ Printer object responds (as described in section 3.1.4.2) using
+ the Printer's configured natural language rather than the natural
+ language requested by the client.
+
+ In either case, the Printer object does not reject the request
+ because of the apparent incompatibility. The potential incompatible
+ combination of charset and natural language can occur either at the
+ global operation level or at the Natural Language Override
+ attribute-by-attribute level. In addition, since the response always
+ includes explicit charset and natural language information, there is
+ never any question or ambiguity in how the client interprets the
+ response.
+
+3.1.4.2 Response Operation Attributes
+
+ The Printer object MUST supply and the client MUST support the
+ following REQUIRED operation attributes in every IPP/1.0 operation
+ response:
+
+ "attributes-charset" (charset):
+ This operation attribute identifies the charset used by any '
+ text' and 'name' attributes that the Printer object is returning
+ in this response. The value in this response MUST be the same
+ value as the "attributes-charset" operation attribute supplied
+ by the client in the request. If this is not possible
+
+
+
+
+
+deBry, et al. Experimental [Page 26]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ (i.e., the charset requested is not supported), the request
+ would have been rejected. See "attributes-charset" described in
+ Section 3.1.4.1 above.
+
+ If the Printer object supports more than just the 'utf-8'
+ charset, the Printer object MUST be able to code convert between
+ each of the charsets supported on a highest fidelity possible
+ basis in order to return the 'text' and 'name' attributes in the
+ charset requested by the client. However, some information loss
+ MAY occur during the charset conversion depending on the
+ charsets involved. For example, the Printer object may convert
+ from a UTF-8 'a' to a US-ASCII 'a' (with no loss of
+ information), from an ISO Latin 1 CAPITAL LETTER A WITH ACUTE
+ ACCENT to US-ASCII 'A' (losing the accent), or from a UTF-8
+ Japanese Kanji character to some ISO Latin 1 error character
+ indication such as '?', decimal code equivalent, or to the
+ absence of a character, depending on implementation.
+
+ Note: Whether an implementation that supports more than one
+ charset stores the data in the charset supplied by the client or
+ code converts to one of the other supported charsets, depends on
+ implementation. The strategy should try to minimize loss of
+ information during code conversion. On each response, such an
+ implementation converts from its internal charset to that
+ requested.
+
+ "attributes-natural-language" (naturalLanguage):
+ This operation attribute identifies the natural language used by
+ any 'text' and 'name' attributes that the IPP object is
+ returning in this response. Unlike the "attributes-charset"
+ operation attribute, the IPP object NEED NOT return the same
+ value as that supplied by the client in the request. The IPP
+ object MAY return the natural language of the Job object or the
+ Printer's configured natural language as identified by the
+ Printer object's "natural-language-configured" attribute, rather
+ than the natural language supplied by the client. For any '
+ text' or 'name' attribute or status message in the response that
+ is in a different natural language than the value returned in
+ the "attributes-natural-language" operation attribute, the IPP
+ object MUST use the Natural Language Override mechanism (see
+ sections 4.1.1.2 and 4.1.2.2) on each attribute value returned.
+ The IPP object MAY use the Natural Language Override mechanism
+ redundantly, i.e., use it even when the value is in the same
+ natural language as the value supplied in the "attributes-
+ natural-language" operation attribute of the response.
+
+
+
+
+
+
+deBry, et al. Experimental [Page 27]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+3.1.5 Operation Targets
+
+ All IPP operations are directed at IPP objects. For Printer
+ operations, the operation is always directed at a Printer object
+ using one of its URIs (i.e., one of the values in the Printer
+ object's "printer-uri-supported" attribute). Even if the Printer
+ object supports more than one URI, the client supplies only one URI
+ as the target of the operation. The client identifies the target
+ object by supplying the correct URI in the "printer-uri (uri)"
+ operation attribute.
+
+ For Job operations, the operation is directed at either:
+
+ - The Job object itself using the Job object's URI. In this case,
+ the client identifies the target object by supplying the correct
+ URI in the "job-uri (uri)" operation attribute.
+ - The Printer object that created the Job object using both the
+ Printer objects URI and the Job object's Job ID. Since the
+ Printer object that created the Job object generated the Job ID,
+ it MUST be able to correctly associate the client supplied Job ID
+ with the correct Job object. The client supplies the Printer
+ object's URI in the "printer-uri (uri)" operation attribute and
+ the Job object's Job ID in the "job-id (integer(1:MAX))"
+ operation attribute.
+
+ If the operation is directed at the Job object directly using the Job
+ object's URI, the client MUST NOT include the redundant "job-id"
+ operation attribute.
+
+ The operation target attributes are REQUIRED operation attributes
+ that MUST be included in every operation request. Like the charset
+ and natural language attributes (see section 3.1.4), the operation
+ target attributes are specially ordered operation attributes. In all
+ cases, the operation target attributes immediately follow the
+ "attributes-charset" and "attributes-natural-language" attributes
+ within the operation attribute group, however the specific ordering
+ rules are:
+
+ - In the case where there is only one operation target attribute
+ (i.e., either only the "printer-uri" attribute or only the "job-
+ uri" attribute), that attribute MUST be the third attribute in
+ the operation attributes group.
+ - In the case where Job operations use two operation target
+ attributes (i.e., the "printer-uri" and "job-id" attributes), the
+ "printer-uri" attribute MUST be the third attribute and the
+ "job-id" attribute MUST be the fourth attribute.
+
+
+
+
+
+deBry, et al. Experimental [Page 28]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ In all cases, the target URIs contained within the body of IPP
+ operation requests and responses must be in absolute format rather
+ than relative format (a relative URL identifies a resource with the
+ scope of the HTTP server, but does not include scheme, host or port).
+
+ The following rules apply to the use of port numbers in URIs that
+ identify IPP objects:
+
+ 1. If the URI scheme allows the port number to be explicitly
+ included in the URI string, and a port number is specified
+ within the URI, then that port number MUST be used by the client
+ to contact the IPP object.
+
+ 2. If the URI scheme allows the port number to be explicitly
+ included in the URI string, and a port number is not specified
+ within the URI, then default port number implied by that URI
+ scheme MUST be used by the client to contact the IPP object.
+
+ 3. If the URI scheme does not allow an explicit port number to be
+ specified within the URI, then the default port number implied
+ by that URI MUST be used by the client to contact the IPP
+ object.
+
+ Note: The IPP encoding and transport document [RFC2565] shows a
+ mapping of IPP onto HTTP/1.1 and defines a new default port number
+ for using IPP over HTTP/1.1.
+
+3.1.6 Operation Status Codes and Messages
+
+ Every operation response includes a REQUIRED "status-code" parameter
+ and an OPTIONAL "status-message" operation attribute. The "status-
+ code" provides information on the processing of a request. A
+ "status-message" attribute provides a short textual description of
+ the status of the operation. The status code is intended for use by
+ automata, and the status message is intended for the human end user.
+ If a response does include a "status-message" attribute, an IPP
+ client NEED NOT examine or display the message, however it SHOULD do
+ so in some implementation specific manner.
+
+ The "status-code" value is a numeric value that has semantic meaning.
+ The "status-code" syntax is similar to a "type2 enum" (see section
+ 4.1 on "Attribute Syntaxes") except that values can range only from
+ 0x0000 to 0x7FFF. Section 13 describes the status codes, assigns the
+ numeric values, and suggests a corresponding status message for each
+ status code. The "status-message" attribute's syntax is "text(255)".
+ A client implementation of IPP SHOULD convert status code values into
+ any localized message that has semantic meaning to the end user.
+
+
+
+
+deBry, et al. Experimental [Page 29]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ If the Printer object supports the "status-message" operation
+ attribute, the Printer object MUST be able to generate this message
+ in any of the natural languages identified by the Printer object's
+ "generated-natural-language-supported" attribute (see the
+ "attributes-natural-language" operation attribute specified in
+ section 3.1.4.1). As described in section 3.1.4.1 for any returned '
+ text' attribute, if there is a choice for generating this message,
+ the Printer object uses the natural language indicated by the value
+ of the "attributes-natural-language" in the client request if
+ supported, otherwise the Printer object uses the value in the Printer
+ object's own "natural-language-configured" attribute. If the Printer
+ object supports the "status-message" operation attribute, it SHOULD
+ use the REQUIRED 'utf-8' charset to return a status message for the
+ following error status codes (see section 13): 'client-error-bad-
+ request', 'client-error-charset-not-supported', 'server-error-
+ internal-error', 'server-error-operation-not-supported', and '
+ server-error-version-not-supported'. In this case, it MUST set the
+ value of the "attributes-charset" operation attribute to 'utf-8' in
+ the error response.
+
+3.1.7 Versions
+
+ Each operation request and response carries with it a "version-
+ number" parameter. Each value of the "version-number" is in the form
+ "X.Y" where X is the major version number and Y is the minor version
+ number. By including a version number in the client request, it
+ allows the client to identify which version of IPP it is interested
+ in using. If the IPP object does not support that version, the
+ object responds with a status code of 'server-error-version-not-
+ supported' along with the closest version number that is supported
+ (see section 13.1.5.4).
+
+ There is no version negotiation per se. However, if after receiving
+ a 'server-error-version-not-supported' status code from an IPP
+ object, there is nothing that prevents a client from trying again
+ with a different version number. In order to conform to IPP/1.0, an
+ implementation MUST support at least version '1.0'.
+
+ There is only one notion of "version number" that covers both IPP
+ Model and IPP Protocol changes. Thus the version number MUST change
+ when introducing a new version of the Model and Semantics document
+ [RFC2566] or a new version of the Encoding and Transport document
+ [RFC2565].
+
+ Changes to the major version number indicate structural or syntactic
+ changes that make it impossible for older version of IPP clients and
+ Printer objects to correctly parse and process the new or changed
+ attributes, operations and responses. If the major version number
+
+
+
+deBry, et al. Experimental [Page 30]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ changes, the minor version numbers is set to zero. As an example,
+ adding the "ipp-attribute-fidelity" attribute (if it had not been
+ part of version '1.0'), would have required a change to the major
+ version number. Items that might affect the changing of the major
+ version number include any changes to the Model and Semantics
+ document [RFC2566] or the Encoding and Transport [RFC2565] itself,
+ such as:
+
+ - reordering of ordered attributes or attribute sets
+ - changes to the syntax of existing attributes
+ - changing Operation or Job Template attributes from OPTIONAL to
+ REQUIRED and vice versa
+ - adding REQUIRED (for an IPP object to support) operation
+ attributes
+ - adding REQUIRED (for an IPP object to support) operation
+ attribute groups
+ - adding values to existing operation attributes
+ - adding REQUIRED operations
+
+ Changes to the minor version number indicate the addition of new
+ features, attributes and attribute values that may not be understood
+ by all IPP objects, but which can be ignored if not understood.
+ Items that might affect the changing of the minor version number
+ include any changes to the model objects and attributes but not the
+ encoding and transport rules [RFC2565] (except adding attribute
+ syntaxes). Examples of such changes are:
+
+ - grouping all extensions not included in a previous version into
+ a new version
+ - adding new attribute values
+ - adding new object attributes
+ - adding OPTIONAL (for an IPP object to support) operation
+ attributes (i.e., those attributes that an IPP object can ignore
+ without confusing clients)
+ - adding OPTIONAL (for an IPP object to support) operation
+ attribute groups (i.e., those attributes that an IPP object can
+ ignore without confusing clients)
+ - adding new attribute syntaxes
+ - adding OPTIONAL operations
+ - changing Job Description attributes or Printer Description
+ attributes from OPTIONAL to REQUIRED or vice versa.
+
+ The encoding of the "operation-id", the "version-number", the
+ "status-code", and the "request-id" MUST NOT change over any version
+ number (either major or minor). This rule guarantees that all future
+ versions will be backwards compatible with all previous versions (at
+ least for checking the "operation-id", the "version-number", and the
+ "request-id"). In addition, any protocol elements (attributes, error
+
+
+
+deBry, et al. Experimental [Page 31]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ codes, tags, etc.) that are not carried forward from one version to
+ the next are deprecated so that they can never be reused with new
+ semantics.
+
+ Implementations that support a certain major version NEED NOT support
+ ALL previous versions. As each new major version is defined (through
+ the release of a new specification), that major version will specify
+ which previous major versions MUST be supported in compliant
+ implementations.
+
+3.1.8 Job Creation Operations
+
+ In order to "submit a print job" and create a new Job object, a
+ client issues a create request. A create request is any one of
+ following three operation requests:
+
+ - The Print-Job Request: A client that wants to submit a print job
+ with only a single document uses the Print-Job operation. The
+ operation allows for the client to "push" the document data to
+ the Printer object by including the document data in the request
+ itself.
+
+ - The Print-URI Request: A client that wants to submit a print job
+ with only a single document (where the Printer object "pulls" the
+ document data instead of the client "pushing" the data to the
+ Printer object) uses the Print-URI operation. In this case, the
+ client includes in the request only a URI reference to the
+ document data (not the document data itself).
+
+ - The Create-Job Request: A client that wants to submit a print job
+ with multiple documents uses the Create-Job operation. This
+ operation is followed by an arbitrary number of Send-Document
+ and/or Send-URI operations (each creating another document for
+ the newly create Job object). The Send-Document operation
+ includes the document data in the request (the client "pushes"
+ the document data to the printer), and the Send-URI operation
+ includes only a URI reference to the document data in the request
+ (the Printer "pulls" the document data from the referenced
+ location). The last Send-Document or Send-URI request for a
+ given Job object includes a "last-document" operation attribute
+ set to 'true' indicating that this is the last request.
+
+ Throughout this model specification, the term "create request" is
+ used to refer to any of these three operation requests.
+
+ A Create-Job operation followed by only one Send-Document operation
+ is semantically equivalent to a Print-Job operation, however, for
+ performance reasons, the client SHOULD use the Print-Job operation
+
+
+
+deBry, et al. Experimental [Page 32]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ for all single document jobs. Also, Print-Job is a REQUIRED
+ operation (all implementations MUST support it) whereas Create-Job is
+ an OPTIONAL operation, hence some implementations might not support
+ it.
+
+ Job submission time is the point in time when a client issues a
+ create request. The initial state of every Job object is the '
+ pending' or 'pending-held' state. Later, the Printer object begins
+ processing the print job. At this point in time, the Job object's
+ state moves to 'processing'. This is known as job processing time.
+ There are validation checks that must be done at job submission time
+ and others that must be performed at job processing time.
+
+ At job submission time and at the time a Validate-Job operation is
+ received, the Printer MUST do the following:
+
+ 1. Process the client supplied attributes and either accept or
+ reject the request
+ 2. Validate the syntax of and support for the scheme of any client
+ supplied URI
+
+ At job submission time the Printer object MUST validate whether or
+ not the supplied attributes, attribute syntaxes, and values are
+ supported by matching them with the Printer object's corresponding
+ "xxx-supported" attributes. See section 3.2.1.2 for details. [ipp-
+ iig] presents suggested steps for an IPP object to either accept or
+ reject any request and additional steps for processing create
+ requests.
+
+ At job submission time the Printer object NEED NOT perform the
+ validation checks reserved for job processing time such as:
+
+ 1. Validating the document data
+ 2. Validating the actual contents of any client supplied URI
+ (resolve the reference and follow the link to the document data)
+
+ At job submission time, these additional job processing time
+ validation checks are essentially useless, since they require
+ actually parsing and interpreting the document data, are not
+ guaranteed to be 100% accurate, and MUST be done, yet again, at job
+ processing time. Also, in the case of a URI, checking for
+ availability at job submission time does not guarantee availability
+ at job processing time. In addition, at job processing time, the
+ Printer object might discover any of the following conditions that
+ were not detectable at job submission time:
+
+ - runtime errors in the document data,
+ - nested document data that is in an unsupported format,
+
+
+
+deBry, et al. Experimental [Page 33]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ - the URI reference is no longer valid (i.e., the server hosting
+ the document might be down), or
+ - any other job processing error
+
+ At job processing time, since the Printer object has already
+ responded with a successful status code in the response to the create
+ request, if the Printer object detects an error, the Printer object
+ is unable to inform the end user of the error with an operation
+ status code. In this case, the Printer, depending on the error, can
+ set the "job-state", "job-state-reasons", or "job-state-message"
+ attributes to the appropriate value(s) so that later queries can
+ report the correct job status.
+
+ Note: Asynchronous notification of events is outside the scope of
+ IPP/1.0.
+
+3.2 Printer Operations
+
+ All Printer operations are directed at Printer objects. A client
+ MUST always supply the "printer-uri" operation attribute in order to
+ identify the correct target of the operation.
+
+3.2.1 Print-Job Operation
+
+ This REQUIRED operation allows a client to submit a print job with
+ only one document and supply the document data (rather than just a
+ reference to the data). See Section 15 for the suggested steps for
+ processing create operations and their Operation and Job Template
+ attributes.
+
+3.2.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. The Printer object
+ MUST copy these values to the corresponding Job Description
+ attributes described in sections 4.3.23 and 4.3.24.
+
+ Target:
+ The "printer-uri" (uri) operation attribute which is the target
+ for this operation as described in section 3.1.5.
+
+
+
+
+
+deBry, et al. Experimental [Page 34]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ Requesting User Name:
+ The "requesting-user-name" (name(MAX)) attribute SHOULD be
+ supplied by the client as described in section 8.3.
+
+ "job-name" (name(MAX)):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object MUST support this attribute. It contains the client
+ supplied Job name. If this attribute is supplied by the client,
+ its value is used for the "job-name" attribute of the newly
+ created Job object. The client MAY automatically include any
+ information that will help the end-user distinguish amongst
+ his/her jobs, such as the name of the application program along
+ with information from the document, such as the document name,
+ document subject, or source file name. If this attribute is not
+ supplied by the client, the Printer generates a name to use in
+ the "job-name" attribute of the newly created Job object (see
+ Section 4.3.5).
+
+ "ipp-attribute-fidelity" (boolean):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object MUST support this attribute. The value 'true' indicates
+ that total fidelity to client supplied Job Template attributes
+ and values is required, else the Printer object MUST reject the
+ Print-Job request. The value 'false' indicates that a
+ reasonable attempt to print the Job object is acceptable and the
+ Printer object MUST accept the Print-job request. If not
+ supplied, the Printer object assumes the value is 'false'. All
+ Printer objects MUST support both types of job processing. See
+ section 15 for a full description of "ipp-attribute-fidelity"
+ and its relationship to other attributes, especially the Printer
+ object's "pdl-override-supported" attribute.
+
+ "document-name" (name(MAX)):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object MUST support this attribute. It contains the client
+ supplied document name. The document name MAY be different than
+ the Job name. Typically, the client software automatically
+ supplies the document name on behalf of the end user by using a
+ file name or an application generated name. If this attribute
+ is supplied, its value can be used in a manner defined by each
+ implementation. Examples include: printed along with the Job
+ (job start sheet, page adornments, etc.), used by accounting or
+ resource tracking management tools, or even stored along with
+ the document as a document level attribute. IPP/1.0 does not
+ support the concept of document level attributes.
+
+
+
+
+
+
+deBry, et al. Experimental [Page 35]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ "document-format" (mimeMediaType) :
+ The client OPTIONALLY supplies this attribute. The Printer
+ object MUST support this attribute. The value of this attribute
+ identifies the format of the supplied document data. If the
+ client does not supply this attribute, the Printer object
+ assumes that the document data is in the format defined by the
+ Printer object's "document-format-default" attribute. If the
+ client supplies this attribute, but the value is not supported
+ by the Printer object, i.e., the value is not one of the values
+ of the Printer object's "document-format-supported" attribute,
+ the Printer object MUST reject the request and return the '
+ client-error-document-format-not-supported' status code.
+
+ "document-natural-language" (naturalLanguage):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object OPTIONALLY supports this attribute. This attribute
+ specifies the natural language of the document for those
+ document-formats that require a specification of the natural
+ language in order to image the document unambiguously. There are
+ no particular values required for the Printer object to support.
+
+ "compression" (type3 keyword)
+ The client OPTIONALLY supplies this attribute. The Printer
+ object OPTIONALLY supports this attribute and the "compression-
+ supported" attribute (see section 4.4.29). The client supplied
+ "compression" operation attribute identifies the compression
+ algorithm used on the document data. If the client omits this
+ attribute, the Printer object MUST assume that the data is not
+ compressed. If the client supplies the attribute and the
+ Printer object supports the attribute, the Printer object uses
+ the corresponding decompression algorithm on the document data.
+ If the client supplies this attribute, but the value is not
+ supported by the Printer object, i.e., the value is not one of
+ the values of the Printer object's "compression-supported"
+ attribute, the Printer object MUST copy the attribute and its
+ value to the Unsupported Attributes response group, reject the
+ request, and return the 'client-error-attributes-or-values-not-
+ supported' status code.
+
+ "job-k-octets" (integer(0:MAX))
+ The client OPTIONALLY supplies this attribute. The Printer
+ object OPTIONALLY supports this attribute and the "job-k-
+ octets-supported" attribute (see section 4.4.30). The client
+ supplied "job-k-octets" operation attribute identifies the total
+ size of the document(s) in K octets being submitted (see section
+ 4.3.17 for the complete semantics). If the client supplies the
+
+
+
+
+
+deBry, et al. Experimental [Page 36]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ attribute and the Printer object supports the attribute, the
+ value of the attribute is used to populate the Job object's
+ "job-k-octets" Job Description attribute.
+
+ Note: For this attribute and the following two attributes
+ ("job-impressions", and "job-media-sheets"), if the client
+ supplies the attribute, but the Printer object does not support
+ the attribute, the Printer object ignores the client-supplied
+ value. If the client supplies the attribute and the Printer
+ supports the attribute, and the value is within the range of the
+ corresponding Printer object's "xxx-supported" attribute, the
+ Printer object MUST use the value to populate the Job object's
+ "xxx" attribute. If the client supplies the attribute and the
+ Printer supports the attribute, but the value is outside the
+ range of the corresponding Printer object's "xxx-supported"
+ attribute, the Printer object MUST copy the attribute and its
+ value to the Unsupported Attributes response group, reject the
+ request, and return the 'client-error-attributes-or-values-not-
+ supported' status code. If the client does not supply the
+ attribute, the Printer object MAY choose to populate the
+ corresponding Job object attribute depending on whether the
+ Printer object supports the attribute and is able to calculate
+ or discern the correct value.
+
+ "job-impressions" (integer(0:MAX))
+ The client OPTIONALLY supplies this attribute. The Printer
+ object OPTIONALLY supports this attribute and the "job-
+ impressions-supported" attribute (see section 4.4.31). The
+ client supplied "job-impressions" operation attribute identifies
+ the total size in number of impressions of the document(s) being
+ submitted (see section 4.3.18 for the complete semantics).
+
+ See note under "job-k-octets".
+
+ "job-media-sheets" (integer(0:MAX))
+ The client OPTIONALLY supplies this attribute. The Printer
+ object OPTIONALLY supports this attribute and the "job-media-
+ sheets-supported" attribute (see section 4.4.32). The client
+ supplied "job-media-sheets" operation attribute identifies the
+ total number of media sheets to be produced for this job (see
+ section 4.3.19 for the complete semantics).
+
+ See note under "job-k-octets".
+
+
+
+
+
+
+
+
+deBry, et al. Experimental [Page 37]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ Group 2: Job Template Attributes
+
+ The client OPTIONALLY supplies a set of Job Template attributes
+ as defined in section 4.2. If the client is not supplying any
+ Job Template attributes in the request, the client SHOULD omit
+ Group 2 rather than sending an empty group. However, a Printer
+ object MUST be able to accept an empty group.
+
+ Group 3: Document Content
+
+ The client MUST supply the document data to be processed.
+
+ Note: In addition to the MANDATORY parameters required for every
+ operation request, the simplest Print-Job Request consists of just
+ the "attributes-charset" and "attributes-natural-language" operation
+ attributes; the "printer-uri" target operation attribute; the
+ Document Content and nothing else. In this simple case, the Printer
+ object:
+
+ - creates a new Job object (the Job object contains a single
+ document),
+ - stores a generated Job name in the "job-name" attribute in the
+ natural language and charset requested (see Section 3.1.4.1) (if
+ those are supported, otherwise using the Printer object's default
+ natural language and charset), and
+ - at job processing time, uses its corresponding default value
+ attributes for the supported Job Template attributes that were
+ not supplied by the client as IPP attribute or embedded
+ instructions in the document data.
+
+3.2.1.2 Print-Job Response
+
+ The Printer object MUST return to the client the following sets
+ of attributes as part of the Print-Job Response:
+
+ Group 1: Operation Attributes
+
+ Status Message:
+ In addition to the REQUIRED status code returned in every
+ response, the response OPTIONALLY includes a "status-message"
+ (text) operation attribute as described in sections 14 and
+ 3.1.6. If the client supplies unsupported or conflicting Job
+ Template attributes or values, the Printer object MUST reject or
+ accept the Print-Job request depending on the whether the client
+ supplied a 'true' or 'false' value for the "ipp-attribute-
+ fidelity" operation attribute. See the Implementer's Guide
+ [ipp-iig] for a complete description of the suggested steps for
+ processing a create request.
+
+
+
+deBry, et al. Experimental [Page 38]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2.
+
+ Group 2: Unsupported Attributes
+
+ This is a set of Operation and Job Template attributes supplied
+ by the client (in the request) that are not supported by the
+ Printer object or that conflict with one another (see the
+ Implementer's Guide [ipp-iig]). If the Printer object is not
+ returning any Unsupported Attributes in the response, the
+ Printer object SHOULD omit Group 2 rather than sending an empty
+ group. However, a client MUST be able to accept an empty group.
+
+ Unsupported attributes fall into three categories:
+
+ 1. The Printer object does not support the supplied attribute
+ (no matter what the attribute syntax or value).
+ 2. The Printer object does support the attribute, but does not
+ support some or all of the particular attribute syntaxes or
+ values supplied by the client (i.e., the Printer object does
+ not have those attribute syntaxes or values in its
+ corresponding "xxx-supported" attribute).
+ 3. The Printer object does support the attributes and values
+ supplied, but the particular values are in conflict with one
+ another, because they violate a constraint, such as not being
+ able to staple transparencies.
+
+ In the case of an unsupported attribute name, the Printer object
+ returns the client-supplied attribute with a substituted "out-
+ of-band" value of 'unsupported' indicating no support for the
+ attribute itself (see the beginning of section 4.1).
+
+ In the case of a supported attribute with one or more
+ unsupported attribute syntaxes or values, the Printer object
+ simply returns the client-supplied attribute with the
+ unsupported attribute syntaxes or values as supplied by the
+ client. This indicates support for the attribute, but no
+ support for that particular attribute syntax or value. If the
+ client supplies a multi-valued attribute with more than one
+ value and the Printer object supports the attribute but only
+ supports a subset of the client-supplied attribute syntaxes or
+ values, the Printer object MUST return only those attribute
+ syntaxes or values that are unsupported.
+
+ In the case of two (or more) supported attribute values that are
+ in conflict with one another (although each is supported
+ independently, the values conflict when requested together
+
+
+
+deBry, et al. Experimental [Page 39]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ within the same job), the Printer object MUST return all the
+ values that it ignores or substitutes to resolve the conflict,
+ but not any of the values that it is still using. The choice
+ for exactly how to resolve the conflict is implementation
+ dependent. See The Implementer's Guide [ipp-iig] for an
+ example.
+
+ In these three cases, the value of the "ipp-attribute-fidelity"
+ supplied by the client does not affect what the Printer object
+ returns. The value of "ipp-attribute-fidelity" only affects
+ whether the Print-Job operation is accepted or rejected. If the
+ job is accepted, the client may query the job using the Get-
+ Job-Attributes operation requesting the unsupported attributes
+ that were returned in the create response to see which
+ attributes were ignored (not stored on the Job object) and which
+ attributes were stored with other (substituted) values.
+
+ Group 3: Job Object Attributes
+
+ "job-uri" (uri):
+ The Printer object MUST return the Job object's URI by returning
+ the contents of the REQUIRED "job-uri" Job object attribute.
+ The client uses the Job object's URI when directing operations
+ at the Job object. The Printer object always uses its
+ configured security policy when creating the new URI. However,
+ if the Printer object supports more than one URI, the Printer
+ object also uses information about which URI was used in the
+ Print-Job Request to generated the new URI so that the new URI
+ references the correct access channel. In other words, if the
+ Print-Job Request comes in over a secure channel, the Printer
+ object MUST generate a Job URI that uses the secure channel as
+ well.
+
+ "job-id" (integer(1:MAX)):
+ The Printer object MUST return the Job object's Job ID by
+ returning the REQUIRED "job-id" Job object attribute. The
+ client uses this "job-id" attribute in conjunction with the
+ "printer-uri" attribute used in the Print-Job Request when
+ directing Job operations at the Printer object.
+
+ "job-state":
+ The Printer object MUST return the Job object's REQUIRED "job-
+ state" attribute. The value of this attribute (along with the
+ value of the next attribute "job-state-reasons") is taken from a
+ "snapshot" of the new Job object at some meaningful point in
+ time (implementation defined) between when the Printer object
+ receives the Print-Job Request and when the Printer object
+ returns the response.
+
+
+
+deBry, et al. Experimental [Page 40]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ "job-state-reasons":
+ The Printer object OPTIONALLY returns the Job object's OPTIONAL
+ "job-state-reasons" attribute. If the Printer object supports
+ this attribute then it MUST be returned in the response. If
+ this attribute is not returned in the response, the client can
+ assume that the "job-state-reasons" attribute is not supported
+ and will not be returned in a subsequent Job object query.
+
+ "job-state-message":
+ The Printer object OPTIONALLY returns the Job object's OPTIONAL
+ "job-state-message" attribute. If the Printer object supports
+ this attribute then it MUST be returned in the response. If
+ this attribute is not returned in the response, the client can
+ assume that the "job-state-message" attribute is not supported
+ and will not be returned in a subsequent Job object query.
+
+ "number-of-intervening-jobs":
+ The Printer object OPTIONALLY returns the Job object's OPTIONAL
+ "number-of-intervening-jobs" attribute. If the Printer object
+ supports this attribute then it MUST be returned in the
+ response. If this attribute is not returned in the response,
+ the client can assume that the "number-of-intervening-jobs"
+ attribute is not supported and will not be returned in a
+ subsequent Job object query.
+
+ Note: Since any printer state information which affects a job's
+ state is reflected in the "job-state" and "job-state-reasons"
+ attributes, it is sufficient to return only these attributes and
+ no specific printer status attributes.
+
+ Note: In addition to the MANDATORY parameters required for every
+ operation response, the simplest response consists of the just the
+ "attributes-charset" and "attributes-natural-language" operation
+ attributes and the "job-uri", "job-id", and "job-state" Job Object
+ Attributes. In this simplest case, the status code is "successful-
+ ok" and there is no "status-message" operation attribute.
+
+3.2.2 Print-URI Operation
+
+ This OPTIONAL operation is identical to the Print-Job operation
+ (section 3.2.1) except that a client supplies a URI reference to the
+ document data using the "document-uri" (uri) operation attribute (in
+ Group 1) rather than including the document data itself. Before
+ returning the response, the Printer MUST validate that the Printer
+ supports the retrieval method (e.g., http, ftp, etc.) implied by the
+ URI, and MUST check for valid URI syntax. If the client-supplied URI
+ scheme is not supported, i.e. the value is not in the Printer
+ object's "referenced-uri-scheme-supported" attribute, the Printer
+
+
+
+deBry, et al. Experimental [Page 41]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ object MUST reject the request and return the 'client-error-uri-
+ scheme-not-supported' status code. See The Implementer's Guide
+ [ipp-iig] for suggested additional checks. The Printer NEED NOT
+ follow the reference and validate the contents of the reference.
+
+ If the Printer object supports this operation, it MUST support the
+ "reference-uri-schemes-supported" Printer attribute (see section
+ 4.4.24).
+
+ It is up to the IPP object to interpret the URI and subsequently
+ "pull" the document from the source referenced by the URI string.
+
+3.2.3 Validate-Job Operation
+
+ This REQUIRED operation is similar to the Print-Job operation
+ (section 3.2.1) except that a client supplies no document data and
+ the Printer allocates no resources (i.e., it does not create a new
+ Job object). This operation is used only to verify capabilities of a
+ printer object against whatever attributes are supplied by the client
+ in the Validate-Job request. By using the Validate-Job operation a
+ client can validate that an identical Print-Job operation (with the
+ document data) would be accepted. The Validate-Job operation also
+ performs the same security negotiation as the Print-Job operation
+ (see section 8), so that a client can check that the client and
+ Printer object security requirements can be met before performing a
+ Print-Job operation.
+
+ Note: The Validate-Job operation does not accept a "document-uri"
+ attribute in order to allow a client to check that the same Print-URI
+ operation will be accepted, since the client doesn't send the data
+ with the Print-URI operation. The client SHOULD just issue the
+ Print-URI request.
+
+ The Printer object returns the same status codes, Operation
+ Attributes (Group 1) and Unsupported Attributes (Group 2) as the
+ Print-Job operation. However, no Job Object Attributes (Group 3) are
+ returned, since no Job object is created.
+
+3.2.4 Create-Job Operation
+
+ This OPTIONAL operation is similar to the Print-Job operation
+ (section 3.2.1) except that in the Create-Job request, a client does
+ not supply document data or any reference to document data. Also,
+ the client does not supply any of the "document-name", "document-
+ format", "compression", or "document-natural-language" operation
+ attributes. This operation is followed by one or more Send-Document
+ or Send-URI operations. In each of those operation requests, the
+
+
+
+
+deBry, et al. Experimental [Page 42]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ client OPTIONALLY supplies the "document-name", "document-format",
+ and "document-natural-language" attributes for each document in the
+ multi-document Job object.
+
+ If a Printer object supports the Create-Job operation, it MUST also
+ support the Send-Document operation and also MAY support the Send-URI
+ operation.
+
+ If the Printer object supports this operation, it MUST support the
+ "multiple-operation-time-out" Printer attribute (see section 4.4.28).
+
+
+3.2.5 Get-Printer-Attributes Operation
+
+ This REQUIRED operation allows a client to request the values of the
+ attributes of a Printer object. In the request, the client supplies
+ the set of Printer attribute names and/or attribute group names in
+ which the requester is interested. In the response, the Printer
+ object returns a corresponding attribute set with the appropriate
+ attribute values filled in.
+
+ For Printer objects, the possible names of attribute groups are:
+
+ - 'job-template': all of the Job Template attributes that apply to
+ a Printer object (the last two columns of the table in Section
+ 4.2).
+ - 'printer-description': the attributes specified in Section 4.4.
+ - 'all': the special group 'all' that includes all supported
+ attributes.
+
+ Since a client MAY request specific attributes or named groups, there
+ is a potential that there is some overlap. For example, if a client
+ requests, 'printer-name' and 'all', the client is actually requesting
+ the "printer-name" attribute twice: once by naming it explicitly, and
+ once by inclusion in the 'all' group. In such cases, the Printer
+ object NEED NOT return each attribute only once in the response even
+ if it is requested multiple times. The client SHOULD NOT request the
+ same attribute in multiple ways.
+
+ It is NOT REQUIRED that a Printer object support all attributes
+ belonging to a group (since some attributes are OPTIONAL). However,
+ it is REQUIRED that each Printer object support all group names.
+
+
+
+
+
+
+
+
+
+deBry, et al. Experimental [Page 43]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+3.2.5.1 Get-Printer-Attributes Request
+
+ The following sets of attributes are part of the Get-Printer-
+ Attributes Request:
+
+ Group 1: Operation Attributes
+
+ Natural Language and Character Set:
+ attributes-charset" and "attributes-natural-language" butes as
+ described in section 3.1.4.1.
+
+ Target:
+ The "printer-uri" (uri) operation attribute which is the target
+ for this operation as described in section 3.1.5.
+
+ Requesting User Name:
+ The "requesting-user-name" (name(MAX)) attribute SHOULD be
+ supplied by the client as described in section 8.3.
+
+ "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. The Printer object MUST support this attribute. If
+ the client omits this attribute, the Printer MUST respond as if
+ this attribute had been supplied with a value of 'all'.
+
+ "document-format" (mimeMediaType) :
+ The client OPTIONALLY supplies this attribute. The Printer
+ object MUST support this attribute. This attribute is useful
+ for a Printer object to determine the set of supported attribute
+ values that relate to the requested document format. The
+ Printer object MUST return the attributes and values that it
+ uses to validate a job on a create or Validate-Job operation in
+ which this document format is supplied. The Printer object
+ SHOULD return only (1) those attributes that are supported for
+ the specified format and (2) the attribute values that are
+ supported for the specified document format. By specifying the
+ document format, the client can get the Printer object to
+ eliminate the attributes and values that are not supported for a
+ specific document format. For example, a Printer object might
+ have multiple interpreters to support both '
+ application/postscript' (for PostScript) and 'text/plain' (for
+ text) documents. However, for only one of those interpreters
+ might the Printer object be able to support "number-up" with
+ values of '1', '2', and '4'. For the other interpreter it might
+ be able to only support "number-up" with a value of '1'. Thus a
+
+
+
+
+
+deBry, et al. Experimental [Page 44]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ client can use the Get-Printer-Attributes operation to obtain
+ the attributes and values that will be used to accept/reject a
+ create job operation.
+
+ If the Printer object does not distinguish between different
+ sets of supported values for each different document format when
+ validating jobs in the create and Validate-Job operations, it
+ MUST NOT distinguish between different document formats in the
+ Get-Printer-Attributes operation. If the Printer object does
+ distinguish between different sets of supported values for each
+ different document format specified by the client, this
+ specialization applies only to the following Printer object
+ attributes:
+
+ - Printer attributes that are Job Template attributes ("xxx-
+ default" "xxx-supported", and "xxx-ready" in the Table in
+ Section 4.2),
+ - "pdl-override-supported",
+ - "compression-supported",
+ - "job-k-octets-supported",
+ - "job-impressions-supported,
+ - "job-media-sheets-supported"
+ - "printer-driver-installer",
+ - "color-supported", and
+ - "reference-uri-schemes-supported"
+
+ The values of all other Printer object attributes (including
+ "document-format-supported") remain invariant with respect to
+ the client supplied document format (except for new Printer
+ description attribute as registered according to section 6.2).
+
+ If the client omits this "document-format" operation attribute,
+ the Printer object MUST respond as if the attribute had been
+ supplied with the value of the Printer object's "document-
+ format-default" attribute. It is recommended that the client
+ always supply a value for "document-format", since the Printer
+ object's "document-format-default" may be 'application/octet-
+ stream', in which case the returned attributes and values are
+ for the union of the document formats that the Printer can
+ automatically sense. For more details, see the description of
+ the 'mimeMediaType' attribute syntax in section 4.1.9.
+
+ If the client supplies a value for the "document-format"
+ Operation attribute that is not supported by the Printer, i.e.,
+ is not among the values of the Printer object's "document-
+ format-supported" attribute, the Printer object MUST reject the
+ operation and return the 'client-error-document-format-not-
+ supported' status code.
+
+
+
+deBry, et al. Experimental [Page 45]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+3.2.5.2 Get-Printer-Attributes Response
+
+ The Printer object returns the following sets of attributes as part
+ of the Get-Printer-Attributes Response:
+
+ Group 1: Operation Attributes
+
+ Status Message:
+ In addition to the REQUIRED status code returned in every
+ response, the response OPTIONALLY includes a "status-message"
+ (text) operation attribute as described in section 3.1.6.
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2.
+
+ Group 2: Unsupported Attributes
+
+ This is a set of Operation attributes supplied by the client (in
+ the request) that are not supported by the Printer object or
+ that conflict with one another (see sections 3.2.1.2 and 16).
+ The response NEED NOT contain the "requested-attributes"
+ operation attribute with any supplied values (attribute
+ keywords) that were requested by the client but are not
+ supported by the IPP object. If the Printer object is not
+ returning any Unsupported Attributes in the response, the
+ Printer object SHOULD omit Group 2 rather than sending an empty
+ group. However, a client MUST be able to accept an empty group.
+
+ Group 3: Printer Object Attributes
+
+ This is the set of requested attributes and their current
+ values. The Printer object ignores (does not respond with) any
+ requested attribute which is not supported. The Printer object
+ MAY respond with a subset of the supported attributes and
+ values, depending on the security policy in force. However, the
+ Printer object MUST respond with the 'unknown' value for any
+ supported attribute (including all REQUIRED attributes) for
+ which the Printer object does not know the value. Also the
+ Printer object MUST respond with the 'no-value' for any
+ supported attribute (including all REQUIRED attributes) for
+ which the system administrator has not configured a value. See
+ the description of the "out-of-band" values in the beginning of
+ Section 4.1.
+
+
+
+
+
+
+
+deBry, et al. Experimental [Page 46]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+3.2.6 Get-Jobs Operation
+
+ This REQUIRED operation allows a client to retrieve the list of Job
+ objects belonging to the target Printer object. The client may also
+ supply a list of Job attribute names and/or attribute group names. A
+ group of Job object attributes will be returned for each Job object
+ that is returned.
+
+ This operation is similar to the Get-Job-Attributes operation, except
+ that this Get-Jobs operation returns attributes from possibly more
+ than one object (see the description of Job attribute group names in
+ section 3.3.4).
+
+3.2.6.1 Get-Jobs Request
+
+ The client submits the Get-Jobs request to a Printer object.
+
+ The following groups of attributes are part of the Get-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.
+
+ Target:
+ The "printer-uri" (uri) operation attribute which is the target
+ for this operation as described in section 3.1.5.
+
+ Requesting User Name:
+ The "requesting-user-name" (name(MAX)) attribute SHOULD be
+ supplied by the client as described in section 8.3.
+
+ "limit" (integer(1:MAX)):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object MUST support this attribute. It is an integer value that
+ indicates a limit to the number of Job objects returned. The
+ limit is a "stateless limit" in that if the value supplied by
+ the client is 'N', then only the first 'N' jobs are returned in
+ the Get-Jobs Response. There is no mechanism to allow for the
+ next 'M' jobs after the first 'N' jobs. If the client does not
+ supply this attribute, the Printer object responds with all
+ applicable jobs.
+
+ "requested-attributes" (1setOf keyword):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object MUST support this attribute. It is a set of Job
+ attribute names and/or attribute groups names in whose values
+
+
+
+deBry, et al. Experimental [Page 47]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ the requester is interested. This set of attributes is returned
+ for each Job object that is returned. The allowed attribute
+ group names are the same as those defined in the Get-Job-
+ Attributes operation in section 3.3.4. If the client does not
+ supply this attribute, the Printer MUST respond as if the client
+ had supplied this attribute with two values: 'job-uri' and '
+ job-id'.
+
+ "which-jobs" (type2 keyword):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object MUST support this attribute. It indicates which Job
+ objects MUST be returned by the Printer object. The values for
+ this attribute are:
+
+ 'completed': This includes any Job object whose state is
+ 'completed', 'canceled', or 'aborted'.
+ 'not-completed': This includes any Job object whose state is '
+ pending', 'processing', 'processing-stopped', or 'pending-
+ held'.
+
+ A Printer object MUST support both values. However, if the
+ mentation does not keep jobs in the 'completed', 'canceled', '
+ aborted' states, then it returns no jobs when the 'completed'
+ value is supplied.
+
+ If a client supplies some other value, the Printer object MUST
+ copy the attribute and the unsupported value to the Unsupported
+ Attributes response group, reject the request, and return the '
+ client-error-attributes-or-values-not-supported' status code.
+
+ If the client does not supply this attribute, the Printer object
+ MUST respond as if the client had supplied the attribute with a
+ value of 'not-completed'.
+
+ "my-jobs" (boolean):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object MUST support this attribute. It indicates whether all
+ jobs or just the jobs submitted by the requesting user of this
+ request MUST be returned by the Printer object. If the client
+ does not supply this attribute, the Printer object MUST respond
+ as if the client had supplied the attribute with a value of '
+ false', i.e., all jobs. The means for authenticating the
+ requesting user and matching the jobs is described in section 8.
+
+
+
+
+
+
+
+
+deBry, et al. Experimental [Page 48]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+3.2.6.2 Get-Jobs Response
+
+ The Printer object returns all of the Job objects that match the
+ criteria as defined by the attribute values supplied by the client in
+ the request. It is possible that no Job objects are returned since
+ there may literally be no Job objects at the Printer, or there may be
+ no Job objects that match the criteria supplied by the client. If
+ the client requests any Job attributes at all, there is a set of Job
+ Object Attributes returned for each Job object.
+
+ Group 1: Operation Attributes
+
+ Status Message:
+ In addition to the REQUIRED status code returned in every
+ response, the response OPTIONALLY includes a "status-message"
+ (text) operation attribute as described in sections 14 and
+ 3.1.6.
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2.
+
+ Group 2: Unsupported Attributes
+
+ This is a set of Operation attributes supplied by the client (in
+ the request) that are not supported by the Printer object or
+ that conflict with one another (see sections 3.2.1.2 and the
+ Implementer's Guide [ipp-iig]). The response NEED NOT contain
+ the "requested-attributes" operation attribute with any supplied
+ values (attribute keywords) that were requested by the client
+ but are not supported by the IPP object. If the Printer object
+ is not returning any Unsupported Attributes in the response, the
+ Printer object SHOULD omit Group 2 rather than sending an empty
+ group. However, a client MUST be able to accept an empty group.
+
+ Groups 3 to N: Job Object Attributes
+
+ The Printer object responds with one set of Job Object
+ Attributes for each returned Job object. The Printer object
+ ignores (does not respond with) any requested attribute or value
+ which is not supported or which is restricted by the security
+ policy in force, including whether the requesting user is the
+ user that submitted the job (job originating user) or not (see
+ section 8). However, the Printer object MUST respond with the '
+ unknown' value for any supported attribute (including all
+ REQUIRED attributes) for which the Printer object does not know
+
+
+
+
+
+deBry, et al. Experimental [Page 49]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ the value, unless it would violate the security policy. See the
+ description of the "out-of-band" values in the beginning of
+ Section 4.1.
+
+ Jobs are returned in the following order:
+
+ - If the client requests all 'completed' Jobs (Jobs in the '
+ completed', 'aborted', or 'canceled' states), then the Jobs
+ are returned newest to oldest (with respect to actual
+ completion time)
+ - If the client requests all 'not-completed' Jobs (Jobs in the
+ 'pending', 'processing', 'pending-held', and 'processing-
+ stopped' states), then Jobs are returned in relative
+ chronological order of expected time to complete (based on
+ whatever scheduling algorithm is configured for the Printer
+ object).
+
+3.3 Job Operations
+
+ All Job operations are directed at Job objects. A client MUST always
+ supply some means of identifying the Job object in order to identify
+ the correct target of the operation. That job identification MAY
+ either be a single Job URI or a combination of a Printer URI with a
+ Job ID. The IPP object implementation MUST support both forms of
+ identification for every job.
+
+3.3.1 Send-Document Operation
+
+ This OPTIONAL operation allows a client to create a multi-document
+ Job object that is initially "empty" (contains no documents). In the
+ Create-Job response, the Printer object returns the Job object's URI
+ (the "job-uri" attribute) and the Job object's 32-bit identifier (the
+ "job-id" attribute). For each new document that the client desires
+ to add, the client uses a Send-Document operation. Each Send-
+ Document Request contains the entire stream of document data for one
+ document.
+
+ Since the Create-Job and the send operations (Send-Document or Send-
+ URI operations) that follow could occur over an arbitrarily long
+ period of time for a particular job, a client MUST send another send
+ operation within an IPP Printer defined minimum time interval after
+ the receipt of the previous request for the job. If a Printer object
+ supports multiple document jobs, the Printer object MUST support the
+ "multiple-operation-time-out" attribute (see section 4.4.28). This
+ attribute indicates the minimum number of seconds the Printer object
+ will wait for the next send operation before taking some recovery
+ action.
+
+
+
+
+deBry, et al. Experimental [Page 50]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ An IPP object MUST recover from an errant client that does not supply
+ a send operation, sometime after the minimum time interval specified
+ by the Printer object's "multiple-operation-time-out" attribute.
+ Such recovery MAY include any of the following or other recovery
+ actions:
+
+ 1. Assume that the Job is an invalid job, start the process of
+ changing the job state to 'aborted', add the 'aborted-by-system'
+ value to the job's "job-state-reasons" attribute (see section
+ 4.3.8), if supported, and clean up all resources associated with
+ the Job. In this case, if another send operation is finally
+ received, the Printer responds with an "client-error-not-
+ possible" or "client-error-not-found" depending on whether or
+ not the Job object is still around when the send operation
+ finally arrives.
+ 2. Assume that the last send operation received was in fact the
+ last document (as if the "last-document" flag had been set to '
+ true'), close the Job object, and proceed to process it (i.e.,
+ move the Job's state to 'pending').
+ 3. Assume that the last send operation received was in fact the
+ last document, close the Job, but move it to the 'pending-held'
+ and add the 'submission-interrupted' value to the job's "job-
+ state-reasons" attribute (see section 4.3.8), if supported.
+ This action allows the user or an operator to determine whether
+ to continue processing the Job by moving it back to the '
+ pending' state or to cancel the job.
+
+ Each implementation is free to decide the "best" action to take
+ depending on local policy, whether any documents have been added,
+ whether the implementation spools jobs or not, and/or any other piece
+ of information available to it. If the choice is to abort the Job
+ object, it is possible that the Job object may already have been
+ processed to the point that some media sheet pages have been printed.
+
+3.3.1.1 Send-Document Request
+
+ The following attribute sets are part of the Send-Document 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.
+
+
+
+
+
+
+
+
+deBry, et al. Experimental [Page 51]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ Target:
+ Either (1) the "printer-uri" (uri) plus "job-id"
+ (integer(1:MAX))or (2) the "job-uri" (uri) operation
+ attribute(s) which define the target for this operation as
+ described in section 3.1.5.
+
+ Requesting User Name:
+ "requesting-user-name" (name(MAX)) attribute SHOULD be supplied
+ by the client as described in section 8.3.
+
+ "document-name" (name(MAX)):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object MUST support this attribute. It contains the client
+ supplied document name. The document name MAY be different than
+ the Job name. It might be helpful, but NEED NOT be unique
+ across multiple documents in the same Job. Typically, the
+ client software automatically supplies the document name on
+ behalf of the end user by using a file name or an application
+ generated name. See the description of the "document-name"
+ operation attribute in the Print-Job Request (section 3.2.1.1)
+ for more information about this attribute
+
+ "document-format" (mimeMediaType):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object MUST support this attribute. The value of this attribute
+ identifies the format of the supplied document data. If the
+ client does not supply this attribute, the Printer object
+ assumes that the document data is in the format defined by the
+ Printer object's "document-format-default" attribute. If the
+ client supplies this attribute, but the value is not supported
+ by the Printer object, i.e., the value is not one of the values
+ of the Printer object's "document-format-supported" attribute,
+ the Printer object MUST reject the request and return the '
+ client-error-document-format-not-supported' status code.
+
+ "document-natural-language" (naturalLanguage):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object OPTIONALLY supports this attribute. This attribute
+ specifies the natural language of the document for those
+ document-formats that require a specification of the natural
+ language in order to image the document unambiguously. There
+ are no particular values required for the Printer object to
+ support.
+
+ "compression" (type3 keyword)
+ The client OPTIONALLY supplies this attribute. The Printer
+ object OPTIONALLY supports this attribute and the "compression-
+ supported" attribute (see section 4.4.29). The client supplied
+
+
+
+deBry, et al. Experimental [Page 52]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ "compression" operation attribute identifies the compression
+ algorithm used on the document data. If the client omits this
+ attribute, the Printer object MUST assume that the data is not
+ compressed. If the client supplies the attribute and the
+ Printer object supports the attribute, the Printer object MUST
+ use the corresponding decompression algorithm on the document
+ data. If the client supplies this attribute, but the value is
+ not supported by the Printer object, i.e., the value is not one
+ of the values of the Printer object's "compression-supported"
+ attribute, the Printer object MUST copy the attribute and its
+ value to the Unsupported Attributes response group, reject the
+ request, and return the 'client-error-attributes-or-values-not-
+ supported' status code.
+
+ "last-document" (boolean):
+ The client MUST supply this attribute. The Printer object MUST
+ support this attribute. It is a boolean flag that is set to '
+ true' if this is the last document for the Job, 'false'
+ otherwise.
+
+ Group 2: Document Content
+
+ The client MUST supply the document data if the "last-document"
+ flag is set to 'false'. However, since a client might not know
+ that the previous document sent with a Send-Document (or Send-
+ URI) operation was the last document (i.e., the "last-document"
+ attribute was set to 'false'), it is legal to send a Send-
+ Document request with no document data where the "last-document"
+ flag is set to 'true'. Such a request MUST NOT increment the
+ value of the Job object's "number-of-documents" attribute, since
+ no real document was added to the job.
+
+3.3.1.2 Send-Document Response
+
+ The following sets of attributes are part of the Send-Document
+ Response:
+
+ Group 1: Operation Attributes
+
+ Status Message:
+ In addition to the REQUIRED status code returned in every
+ response, the response OPTIONALLY includes a "status-message"
+ (text) operation attribute as described in sections 14 and
+ 3.1.6.
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2.
+
+
+
+deBry, et al. Experimental [Page 53]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ Group 2: Unsupported Attributes
+
+ This is a set of Operation attributes supplied by the client (in
+ the request) that are not supported by the Printer object or
+ that conflict with one another (see sections 3.2.1.2 and the
+ Implementer's Guide [ipp-iig]). If the Printer object is not
+ returning any Unsupported Attributes in the response, the
+ Printer object SHOULD omit Group 2 rather than sending an empty
+ group. However, a client MUST be able to accept an empty group.
+
+ Group 3: Job Object Attributes
+
+ This is the same set of attributes as described in the Print-Job
+ response (see section 3.2.1.2).
+
+3.3.2 Send-URI Operation
+
+ This OPTIONAL operation is identical to the Send-Document operation
+ (see section 3.3.1) except that a client MUST supply a URI reference
+ ("document-uri" operation attribute) rather than the document data
+ itself. If a Printer object supports this operation, clients can use
+ both Send-URI or Send-Document operations to add new documents to an
+ existing multi-document Job object. However, if a client needs to
+ indicate that the previous Send-URI or Send-Document was the last
+ document, the client MUST use the Send-Document operation with no
+ document data and the "last-document" flag set to 'true' (rather than
+ using a Send-URI operation with no "document-uri" operation
+ attribute).
+
+ If a Printer object supports this operation, it MUST also support the
+ Print-URI operation (see section 3.2.2).
+
+ The Printer object MUST validate the syntax and URI scheme of the
+ supplied URI before returning a response, just as in the Print-URI
+ operation.
+
+3.3.3 Cancel-Job Operation
+
+ This REQUIRED operation allows a client to cancel a Print Job from
+ the time the job is created up to the time it is completed, canceled,
+ or aborted. Since a Job might already be printing by the time a
+ Cancel-Job is received, some media sheet pages might be printed
+ before the job is actually terminated.
+
+3.3.3.1 Cancel-Job Request
+
+ The following groups of attributes are part of the Cancel-Job
+ Request:
+
+
+
+deBry, et al. Experimental [Page 54]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ 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.
+
+ Target:
+ Either (1) the "printer-uri" (uri) plus "job-id"
+ (integer(1:MAX))or (2) the "job-uri" (uri) operation
+ attribute(s) which define the target for this operation as
+ described in section 3.1.5.
+
+ Requesting User Name:
+ The "requesting-user-name" (name(MAX)) attribute SHOULD be
+ supplied by the client as described in section 8.3.
+
+ "message" (text(127)):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object OPTIONALLY supports this attribute. It is a message to
+ the operator. This "message" attribute is not the same as the
+ "job-message-from-operator" attribute. That attribute is used
+ to report a message from the operator to the end user that
+ queries that attribute. This "message" operation attribute is
+ used to send a message from the client to the operator along
+ with the operation request. It is an implementation decision of
+ how or where to display this message to the operator (if at
+ all).
+
+3.3.3.2 Cancel-Job Response
+
+ The following sets of attributes are part of the Cancel-Job Response:
+
+ Group 1: Operation Attributes
+
+ Status Message:
+ In addition to the REQUIRED status code returned in every
+ response, the response OPTIONALLY includes a "status-message"
+ (text) operation attribute as described in sections 14 and
+ 3.1.6.
+
+ If the job is already in the 'completed', 'aborted', or '
+ canceled' state, or the 'process-to-stop-point' value is set in
+ the Job's "job-state-reasons" attribute, the Printer object MUST
+ reject the request and return the 'client-error-not-possible'
+ error status code.
+
+
+
+
+
+
+deBry, et al. Experimental [Page 55]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2.
+
+ Group 2: Unsupported Attributes
+
+ This is a set of Operation attributes supplied by the client (in
+ the request) that are not supported by the Printer object or
+ that conflict with one another (see section 3.2.1.2 and the
+ Implementer's Guide [ipp-iig]). If the Printer object is not
+ returning any Unsupported Attributes in the response, the
+ Printer object SHOULD omit Group 2 rather than sending an empty
+ group. However, a client MUST be able to accept an empty group.
+
+ Once a successful response has been sent, the implementation
+ guarantees that the Job will eventually end up in the 'canceled'
+ state. Between the time of the Cancel-Job operation is accepted and
+ when the job enters the 'canceled' job-state (see section 4.3.7), the
+ "job-state-reasons" attribute SHOULD contain the 'processing-to-
+ stop-point' value which indicates to later queries that although the
+ Job might still be 'processing', it will eventually end up in the '
+ canceled' state, not the 'completed' state.
+
+3.3.4 Get-Job-Attributes Operation
+
+ This REQUIRED operation allows a client to request the values of
+ attributes of a Job object and it is almost identical to the Get-
+ Printer-Attributes operation (see section 3.2.5). The only
+ differences are that the operation is directed at a Job object rather
+ than a Printer object, there is no "document-format" operation
+ attribute used when querying a Job object, and the returned attribute
+ group is a set of Job object attributes rather than a set of Printer
+ object attributes.
+
+ For Jobs, the possible names of attribute groups are:
+
+ - 'job-template': all of the Job Template attributes that apply to a
+ Job object (the first column of the table in Section 4.2).
+ - 'job-description': all of the Job Description attributes specified
+ in Section 4.3.
+ - 'all': the special group 'all' that includes all supported
+ attributes.
+
+ Since a client MAY request specific attributes or named groups, there
+ is a potential that there is some overlap. For example, if a client
+ requests, 'job-name' and 'job-description', the client is actually
+ requesting the "job-name" attribute once by naming it explicitly, and
+ once by inclusion in the 'job-description' group. In such cases, the
+
+
+
+deBry, et al. Experimental [Page 56]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ Printer object NEED NOT return the attribute only once in the
+ response even if it is requested multiple times. The client SHOULD
+ NOT request the same attribute in multiple ways.
+
+ It is NOT REQUIRED that a Job object support all attributes belonging
+ to a group (since some attributes are OPTIONAL). However it is
+ REQUIRED that each Job object support all group names.
+
+3.3.4.1 Get-Job-Attributes Request
+
+ The following groups of attributes are part of the Get-Job-Attributes
+ Request when the request is directed at a Job object:
+
+ 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.
+
+ Target:
+ Either (1) the "printer-uri" (uri) plus "job-id"
+ (integer(1:MAX)) or (2) the "job-uri" (uri) operation
+ attribute(s) which define the target for this operation as
+ described in section 3.1.5.
+
+ Requesting User Name:
+ The "requesting-user-name" (name(MAX)) attribute SHOULD be
+ supplied by the client as described in section 8.3.
+
+ "requested-attributes" (1setOf keyword) :
+ The client OPTIONALLY supplies this attribute. The IPP object
+ MUST support this attribute. It is a set of attribute names
+ and/or attribute group names in whose values the requester is
+ interested. If the client omits this attribute, the IPP object
+ MUST respond as if this attribute had been supplied with a value
+ of 'all'.
+
+3.3.4.2 Get-Job-Attributes Response
+
+ The Printer object returns the following sets of attributes as part
+ of the Get-Job-Attributes Response:
+
+
+
+
+
+
+
+
+
+
+deBry, et al. Experimental [Page 57]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ Group 1: Operation Attributes
+
+ Status Message:
+ In addition to the REQUIRED status code returned in every
+ response, the response OPTIONALLY includes a "status-message"
+ (text) operation attribute as described in sections 14 and
+ 3.1.6.
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2. The "attributes-
+ natural-language" MAY be the natural language of the Job object,
+ rather than the one requested.
+
+ Group 2: Unsupported Attributes
+
+ This is a set of Operation attributes supplied by the client (in
+ the request) that are not supported by the Printer object or
+ that conflict with one another (see sections 3.2.1.2 and the
+ Implementer's Guide [ipp-iig]). The response NEED NOT contain
+ the "requested-attributes" operation attribute with any supplied
+ values (attribute keywords) that were requested by the client
+ but are not supported by the IPP object. If the Printer object
+ is not returning any Unsupported Attributes in the response, the
+ Printer object SHOULD omit Group 2 rather than sending an empty
+ group. However, a client MUST be able to accept an empty group.
+
+ Group 3: Job Object Attributes
+
+ This is the set of requested attributes and their current
+ values. The IPP object ignores (does not respond with) any
+ requested attribute or value which is not supported or which is
+ restricted by the security policy in force, including whether
+ the requesting user is the user that submitted the job (job
+ originating user) or not (see section 8). However, the IPP
+ object MUST respond with the 'unknown' value for any supported
+ attribute (including all RED butes) for which the IPP object
+ does not know the value, s it would violate the security policy.
+ See the description e "out-of-band" values in the beginning of
+ Section 4.1.
+
+4. Object Attributes
+
+ This section describes the attributes with their corresponding
+ attribute syntaxes and values that are part of the IPP model. The
+ sections below show the objects and their associated attributes which
+ are included within the scope of this protocol. Many of these
+ attributes are derived from other relevant specifications:
+
+
+
+deBry, et al. Experimental [Page 58]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ - Document Printing Application (DPA) [ISO10175]
+ - RFC 1759 Printer MIB [RFC1759]
+
+ Each attribute is uniquely identified in this document using a
+ "keyword" (see section 12.2.1) which is the name of the attribute.
+ The keyword is included in the section header describing that
+ attribute.
+
+ Note: Not only are keywords used to identify attributes, but one of
+ the attribute syntaxes described below is "keyword" so that some
+ attributes have keyword values. Therefore, these attributes are
+ defined as having an attribute syntax that is a set of keywords.
+
+4.1 Attribute Syntaxes
+
+ This section defines the basic attribute syntax types that all clients
+ and IPP objects MUST be able to accept in responses and accept in
+ requests, respectively. Each attribute description in sections 3 and
+ 4 includes the name of attribute syntax(es) in the heading (in
+ parentheses). A conforming implementation of an attribute MUST
+ include the semantics of the attribute syntax(es) so identified.
+ Section 6.3 describes how the protocol can be extended with new
+ attribute syntaxes.
+
+ The attribute syntaxes are specified in the following sub-sections,
+ where the sub-section heading is the keyword name of the attribute
+ syntax inside the single quotes. In operation requests and responses
+ each attribute value MUST be represented as one of the attribute
+ syntaxes specified in the sub-section heading for the attribute. In
+ addition, the value of an attribute in a response (but not in a
+ request) MAY be one of the "out-of-band" values. Standard
+ "out-of-band" values are:
+
+ 'unknown': The attribute is supported by the IPP object, but the
+ value is unknown to the IPP object for some reason.
+ 'unsupported': The attribute is unsupported by the IPP object. This
+ value MUST be returned only as the value of an attribute in the
+ Unsupported Attributes Group.
+ 'no-value': The attribute is supported by the Printer object, but
+ the system administrator has not yet configured a value.
+
+ The Encoding and Transport specification [RFC2565] defines mechanisms
+ for passing "out-of-band" values. All attributes in a request MUST
+ have one or more values as defined in Sections 4.2 to 4.4. Thus
+ clients MUST NOT supply attributes with "out-of-band" values. All
+ attribute in a response MUST have one or more values as defined in
+ Sections 4.2 to 4.4 or a single "out-of-band" value.
+
+
+
+
+deBry, et al. Experimental [Page 59]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ Most attributes are defined to have a single attribute syntax.
+ However, a few attributes (e.g., "job-sheet", "media", "job-hold-
+ until") are defined to have several attribute syntaxes, depending on
+ the value. These multiple attribute syntaxes are separated by the
+ "|" character in the sub-section heading to indicate the choice.
+ Since each value MUST be tagged as to its attribute syntax in the
+
+ protocol, a single-valued attribute instance may have any one of its
+ attribute syntaxes and a multi-valued attribute instance may have a
+ mixture of its defined attribute syntaxes.
+
+4.1.1 'text'
+
+ A text attribute is an attribute whose value is a sequence of zero or
+ more characters encoded in a maximum of 1023 ('MAX') octets. MAX is
+ the maximum length for each value of any text attribute. However, if
+ an attribute will always contain values whose maximum length is much
+ less than MAX, the definition of that attribute will include a
+ qualifier that defines the maximum length for values of that
+ attribute. For example: the "printer-location" attribute is
+ specified as "printer-location (text(127))". In this case, text
+ values for "printer-location" MUST NOT exceed 127 octets; if supplied
+ with a longer text string via some external interface (other than the
+ protocol), implementations are free to truncate to this shorter
+ length limitation.
+
+ In this specification, all text attributes are defined using the '
+ text' syntax. However, 'text' is used only for brevity; the formal
+ interpretation of 'text' is: 'textWithoutLanguage |
+ textWithLanguage'. That is, for any attribute defined in this
+ specification using the 'text' attribute syntax, all IPP objects and
+ clients MUST support both the 'textWithoutLanguage' and '
+ textWithLanguage' attribute syntaxes. However, in actual usage and
+ protocol execution, objects and clients accept and return only one of
+ the two syntax per attribute. The syntax 'text' never appears "on-
+ the-wire".
+
+ Both 'textWithoutLanguage' and 'textWithLanguage' are needed to
+ support the real world needs of interoperability between sites and
+ systems that use different natural languages as the basis for human
+ communication. Generally, one natural language applies to all text
+ attributes in a given request or response. The language is indicated
+ by the "attributes-natural-language" operation attribute defined in
+ section 3.1.4 or "attributes-natural-language" job attribute defined
+ in section 4.3.24, and there is no need to identify the natural
+ language for each text string on a value-by-value basis. In these
+ cases, the attribute syntax 'textWithoutLanguage' is used for text
+ attributes. In other cases, the client needs to supply or the
+
+
+
+deBry, et al. Experimental [Page 60]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ Printer object needs to return a text value in a natural language
+ that is different from the rest of the text values in the request or
+ response. In these cases, the client or Printer object uses the
+ attribute syntax 'textWithLanguage' for text attributes (this is the
+ Natural Language Override mechanism described in section 3.1.4).
+
+ The 'textWithoutLanguage' and 'textWithLanguage' attribute syntaxes
+ are described in more detail in the following sections.
+
+4.1.1.1 'textWithoutLanguage'
+
+ The 'textWithoutLanguage' syntax indicates a value that is sequence
+ of zero or more characters. Text strings are encoded using the rules
+ of some charset. The Printer object MUST support the UTF-8 charset
+ [RFC2279] and MAY support additional charsets to represent 'text'
+ values, provided that the charsets are registered with IANA [IANA-
+ CS]. See Section 4.1.7 for the specification of the 'charset'
+ attribute syntax, including restricted semantics and examples of
+ charsets.
+
+4.1.1.2 'textWithLanguage'
+
+ The 'textWithLanguage' attribute syntax is a compound attribute
+ syntax consisting of two parts: a 'textWithoutLanguage' part plus an
+ additional 'naturalLanguage' (see section 4.1.8) part that overrides
+ the natural language in force. The 'naturalLanguage' part explicitly
+ identifies the natural language that applies to the text part of that
+ value and that value alone. For any give text attribute, the '
+ textWithoutLanguage' part is limited to the maximum length defined
+ for that attribute, but the 'naturalLanguage' part is always limited
+ to 63 octets. Using the 'textWithLanguage' attribute syntax rather
+ than the normal 'textWithoutLanguage' syntax is the so-called Natural
+ Language Override mechanism and MUST be supported by all IPP objects
+ and clients.
+
+ If the attribute is multi-valued (1setOf text), then the '
+ textWithLanguage' attribute syntax MUST be used to explicitly specify
+ each attribute value whose natural language needs to be overridden.
+ Other values in a multi-valued 'text' attribute in a request or a
+ response revert to the natural language of the operation attribute.
+
+ In a create request, the Printer object MUST accept and store with
+ the Job object any natural language in the "attributes-natural-
+ language" operation attribute, whether the Printer object supports
+ that natural language or not. Furthermore, the Printer object MUST
+ accept and store any 'textWithLanguage' attribute value, whether the
+
+
+
+
+
+deBry, et al. Experimental [Page 61]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ Printer object supports that natural language or not. These
+ requirements are independent of the value of the "ipp-attribute-
+ fidelity" operation attribute that the client MAY supply.
+
+ Example: If the client supplies the "attributes-natural-language"
+ operation attribute with the value: 'en' indicating English, but the
+ value of the "job-name" attribute is in French, the client MUST use
+ the 'textWithLanguage' attribute syntax with the following two
+ values:
+
+ 'fr': Natural Language Override indicating French
+ 'Rapport Mensuel': the job name in French
+
+ See the Encoding and Transport document [RFC2565] for a detailed
+ example of the 'textWithLanguage' attribute syntax.
+
+4.1.2 'name'
+
+ This syntax type is used for user-friendly strings, such as a Printer
+ name, that, for humans, are more meaningful than identifiers. Names
+ are never translated from one natural language to another. The '
+ name' attribute syntax is essentially the same as 'text', including
+ the REQUIRED support of UTF-8 except that the sequence of characters
+ is limited so that its encoded form MUST NOT exceed 255 (MAX) octets.
+
+ Also like 'text', 'name' is really an abbreviated notation for either
+ 'nameWithoutLanguage' or 'nameWithLanguage'. That is, all IPP
+ objects and clients MUST support both the 'nameWithoutLanguage' and '
+ nameWithLanguage' attribute syntaxes. However, in actual usage and
+ protocol execution, objects and clients accept and return only one of
+ the two syntax per attribute. The syntax 'name' never appears "on-
+ the-wire".
+
+ Note: Only the 'text' and 'name' attribute syntaxes permit the
+ Natural Language Override mechanism.
+
+ Some attributes are defined as 'type3 keyword | name'. These
+ attributes support values that are either type3 keywords or names.
+ This dual-syntax mechanism enables a site administrator to extend
+ these attributes to legally include values that are locally defined
+ by the site administrator. Such names are not registered with IANA.
+
+4.1.2.1 'nameWithoutLanguage'
+
+ The 'nameWithoutLanguage' syntax indicates a value that is sequence
+ of zero or more characters so that its encoded form does not exceed
+ MAX octets.
+
+
+
+
+deBry, et al. Experimental [Page 62]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+4.1.2.2 'nameWithLanguage'
+
+ The 'nameWithLanguage' attribute syntax is a compound attribute
+ syntax consisting of two parts: a 'nameWithoutLanguage' part plus an
+ additional 'naturalLanguage' (see section 4.1.8) part that overrides
+ the natural language in force. The 'naturalLanguage' part explicitly
+ identifies the natural language that applies to that name value and
+ that name value alone.
+
+ The 'nameWithLanguage' attribute syntax behaves the same as the '
+ textWithLanguage' syntax. If a name is in a language that is
+ different than the rest of the object or operation, then this '
+ nameWithLanguage' syntax is used rather than the generic '
+ nameWithoutLanguage' syntax.
+
+ Example: If the client supplies the "attributes-natural-language"
+ operation attribute with the value: 'en' indicating English, but the
+ "printer-name" attribute is in German, the client MUST use the '
+ nameWithLanguage' attribute syntax as follows:
+
+ 'de': Natural Language Override indicating German
+ 'Farbdrucker': the Printer name in German
+
+4.1.2.3 Matching 'name' attribute values
+
+ For purposes of matching two 'name' attribute values for equality,
+ such as in job validation (where a client-supplied value for
+ attribute "xxx" is checked to see if the value is among the values of
+ the Printer object's corresponding "xxx-supported" attribute), the
+ following match rules apply:
+
+ 1. 'keyword' values never match 'name' values.
+
+ 2. 'name' (nameWithoutLanguage and nameWithLanguage) values
+ match if (1) the name parts match and (2) the Associated
+ Natural-Language parts (see section 3.1.4.1) match. The
+ matching rules are:
+
+ a. the name parts match if the two names are identical
+ character by character, except it is RECOMMENDED that case
+ be ignored. For example: 'Ajax-letter-head-white' MUST
+ match 'Ajax-letter-head-white' and SHOULD match 'ajax-
+ letter-head-white' and 'AJAX-LETTER-HEAD-WHITE'.
+
+ b. the Associated Natural-Language parts match if the
+ shorter of the two meets the syntactic requirements of RFC
+ 1766 [RFC1766] and matches byte for byte with the longer.
+ For example, 'en' matches 'en', 'en-us' and 'en-gb', but
+
+
+
+deBry, et al. Experimental [Page 63]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ matches neither 'fr' nor 'e'.
+
+4.1.3 'keyword'
+
+ The 'keyword' attribute syntax is a sequence of characters, length: 1
+ to 255, containing only the US-ASCII [ASCII] encoded values for
+ lowercase letters ("a" - "z"), digits ("0" - "9"), hyphen ("-"), dot
+ ("."), and underscore ("_"). The first character MUST be a lowercase
+ letter. Furthermore, keywords MUST be in U.S. English.
+
+ This syntax type is used for enumerating semantic identifiers of
+ entities in the abstract protocol, i.e., entities identified in this
+ document. Keywords are used as attribute names or values of
+ attributes. Unlike 'text' and 'name' attribute values, 'keyword'
+ values MUST NOT use the Natural Language Override mechanism, since
+ they MUST always be US-ASCII and U.S. English.
+
+ Keywords are for use in the protocol. A user interface will likely
+ provide a mapping between protocol keywords and displayable user-
+ friendly words and phrases which are localized to the natural
+ language of the user. While the keywords specified in this document
+ MAY be displayed to users whose natural language is U.S. English,
+ they MAY be mapped to other U.S. English words for U.S. English
+ users, since the user interface is outside the scope of this
+ document.
+
+ In the definition for each attribute of this syntax type, the full
+ set of defined keyword values for that attribute are listed.
+
+ When a keyword is used to represent an attribute (its name), it MUST
+ be unique within the full scope of all IPP objects and attributes.
+ When a keyword is used to represent a value of an attribute, it MUST
+ be unique just within the scope of that attribute. That is, the same
+ keyword MUST NOT be used for two different values within the same
+ attribute to mean two different semantic ideas. However, the same
+ keyword MAY be used across two or more attributes, representing
+ different semantic ideas for each attribute. Section 6.1 describes
+ how the protocol can be extended with new keyword values. Examples
+ of attribute name keywords:
+
+ "job-name"
+ "attributes-charset"
+
+ Note: This document uses "type1", "type2", and "type3" prefixes to
+ the "keyword" basic syntax to indicate different levels of review for
+ extensions (see section 6.1).
+
+
+
+
+
+deBry, et al. Experimental [Page 64]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+4.1.4 'enum'
+
+ The 'enum' attribute syntax is an enumerated integer value that is in
+ the range from 1 to 2**31 - 1 (MAX). Each value has an associated '
+ keyword' name. In the definition for each attribute of this syntax
+ type, the full set of possible values for that attribute are listed.
+ This syntax type is used for attributes for which there are enum
+ values assigned by other standards, such as SNMP MIBs. A number of
+ attribute enum values in this specification are also used for
+ corresponding attributes in other standards [RFC1759]. This syntax
+ type is not used for attributes to which the system administrator may
+ assign values. Section 6.1 describes how the protocol can be
+ extended with new enum values.
+
+ Enum values are for use in the protocol. A user interface will
+ provide a mapping between protocol enum values and displayable user-
+ friendly words and phrases which are localized to the natural
+ language of the user. While the enum symbols specified in this
+ document MAY be displayed to users whose natural language is U.S.
+ English, they MAY be mapped to other U.S. English words for U.S.
+ English users, since the user interface is outside the scope of this
+ document.
+
+ Note: SNMP MIBs use '2' for 'unknown' which corresponds to the IPP
+ "out-of-band" value 'unknown'. See the description of the "out-of-
+ band" values at the beginning of Section 4.1. Therefore, attributes
+ of type 'enum' start at '3'.
+
+ Note: This document uses "type1", "type2", and "type3" prefixes to
+ the "enum" basic syntax to indicate different levels of review for
+ extensions (see section 6.1).
+
+4.1.5 'uri'
+
+ The 'uri' attribute syntax is any valid Uniform Resource Identifier
+ or URI [RFC2396]. Most often, URIs are simply Uniform Resource
+ Locators or URLs. The maximum length of URIs used as values of IPP
+ attributes is 1023 octets. Although most other IPP attribute syntax
+ types allow for only lower-cased values, this attribute syntax type
+ conforms to the case-sensitive and case-insensitive rules specified
+ in [RFC2396].
+
+4.1.6 'uriScheme'
+
+ The 'uriScheme' attribute syntax is a sequence of characters
+ representing a URI scheme according to RFC 2396 [RFC2396]. Though
+ RFC 2396 requires that the values be case-insensitive, IPP requires
+
+
+
+
+deBry, et al. Experimental [Page 65]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ all lower case values in IPP attributes to simplify comparing by IPP
+ clients and Printer objects. Standard values for this syntax type
+ are the following keywords:
+
+ 'http': for HTTP schemed URIs (e.g., "http:...")
+ 'https': for use with HTTPS schemed URIs (e.g., "https:...")
+ (not on IETF standards track)
+ 'ftp': for FTP schemed URIs (e.g., "ftp:...")
+ 'mailto': for SMTP schemed URIs (e.g., "mailto:...")
+ 'file': for file schemed URIs (e.g., "file:...")
+
+ A Printer object MAY support any URI 'scheme' that has been
+ registered with IANA [IANA-MT]. The maximum length of URI 'scheme'
+ values used to represent IPP attribute values is 63 octets.
+
+4.1.7 'charset'
+
+ The 'charset' attribute syntax is a standard identifier for a
+ charset. A charset is a coded character set and encoding scheme.
+ Charsets are used for labeling certain document contents and 'text'
+ and 'name' attribute values. The syntax and semantics of this
+ attribute syntax are specified in RFC 2046 [RFC2046] and contained in
+ the IANA character-set Registry [IANA-CS] according to the IANA
+ procedures [RFC2278]. Though RFC 2046 requires that the values be
+ case-insensitive US-ASCII, IPP requires all lower case values in IPP
+ attributes to simplify comparing by IPP clients and Printer objects.
+ When a character-set in the IANA registry has more than one name
+ (alias), the name labeled as "(preferred MIME name)", if present,
+ MUST be used.
+
+ The maximum length of 'charset' values used to represent IPP
+ attribute values is 63 octets.
+
+ Some examples are:
+
+ 'utf-8': ISO 10646 Universal Multiple-Octet Coded Character Set
+ (UCS) represented as the UTF-8 [RFC2279] transfer encoding
+ scheme in which US-ASCII is a subset charset.
+ 'us-ascii': 7-bit American Standard Code for Information
+ Interchange (ASCII), ANSI X3.4-1986 [ASCII]. That standard
+ defines US-ASCII, but RFC 2045 [RFC2045] eliminates most of the
+ control characters from conformant usage in MIME and IPP.
+ 'iso-8859-1': 8-bit One-Byte Coded Character Set, Latin Alphabet
+ Nr 1 [ISO8859-1]. That standard defines a coded character set
+ that is used by Latin languages in the Western Hemisphere and
+ Western Europe. US-ASCII is a subset charset.
+
+
+
+
+
+deBry, et al. Experimental [Page 66]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ 'iso-10646-ucs-2': ISO 10646 Universal Multiple-Octet Coded
+ Character Set (UCS) represented as two octets (UCS-2), with the
+ high order octet of each pair coming first (so-called Big Endian
+ integer).
+
+ Some attribute descriptions MAY place additional requirements on
+ charset values that may be used, such as REQUIRED values that MUST be
+ supported or additional restrictions, such as requiring that the
+ charset have US-ASCII as a subset charset.
+
+4.1.8 'naturalLanguage'
+
+ The 'naturalLanguage' attribute syntax is a standard identifier for a
+ natural language and optionally a country. The values for this
+ syntax type are defined by RFC 1766 [RFC1766]. Though RFC 1766
+ requires that the values be case-insensitive US-ASCII, IPP requires
+ all lower case to simplify comparing by IPP clients and Printer
+ objects. Examples include:
+
+ 'en': for English
+ 'en-us': for US English
+ 'fr': for French
+ 'de': for German
+
+ The maximum length of 'naturalLanguage' values used to represent IPP
+ attribute values is 63 octets.
+
+4.1.9 'mimeMediaType'
+
+ The 'mimeMediaType' attribute syntax is the Internet Media Type
+ (sometimes called MIME type) as defined by RFC 2046 [RFC2046] and
+ registered according to the procedures of RFC 2048 [RFC2048] for
+ identifying a document format. The value MAY include a charset
+ parameter, depending on the specification of the Media Type in the
+ IANA Registry [IANA-MT]. Although most other IPP syntax types allow
+ for only lower-cased values, this syntax type allows for mixed-case
+ values which are case-insensitive.
+
+ Examples are:
+
+ 'text/html': An HTML document
+ 'text/plain': A plain text document in US-ASCII (RFC 2046 indicates
+ that in the absence of the charset parameter MUST mean US-ASCII
+ rather than simply unspecified) [RFC2046].
+ 'text/plain; charset=US-ASCII': A plain text document in US-ASCII
+ [52, 56].
+ 'text/plain; charset=ISO-8859-1': A plain text document in ISO
+ 8859-1 (Latin 1) [ISO8859-1].
+
+
+
+deBry, et al. Experimental [Page 67]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ 'text/plain; charset=utf-8': A plain text document in ISO 10646
+ represented as UTF-8 [RFC2279]
+ 'text/plain, charset=iso-10646-ucs-2': A plain text document in
+ ISO 10646 represented in two octets (UCS-2) [ISO10646-1]
+ 'application/postscript': A PostScript document [RFC2046]
+ 'application/vnd.hp-PCL': A PCL document [IANA-MT] (charset escape
+ sequence embedded in the document data)
+ 'application/octet-stream': Auto-sense - see below
+
+ One special type is 'application/octet-stream'. If the Printer
+ object supports this value, the Printer object MUST be capable of
+ auto-sensing the format of the document data. If the Printer
+ object's default value attribute "document-format-default" is set to
+ 'application/octet-stream', the Printer object not only supports
+ auto-sensing of the document format, but will depend on the result of
+ applying its auto-sensing when the client does not supply the
+ "document-format" attribute. If the client supplies a document
+ format value, the Printer MUST rely on the supplied attribute, rather
+ than trust its auto-sensing algorithm. To summarize:
+
+ 1. If the client does not supply a document format value, the
+ Printer MUST rely on its default value setting (which may be '
+ application/octet-stream' indicating an auto-sensing mechanism).
+ 2. If the client supplies a value other than 'application/octet-
+ stream', the client is supplying valid information about the
+ format of the document data and the Printer object MUST trust
+ the client supplied value more than the outcome of applying an
+ automatic format detection mechanism. For example, the client
+ may be requesting the printing of a PostScript file as a '
+ text/plain' document. The Printer object MUST print a text
+ representation of the PostScript commands rather than interpret
+ the stream of PostScript commands and print the result.
+ 3. If the client supplies a value of 'application/octet-stream',
+ the client is indicating that the Printer object MUST use its
+ auto-sensing mechanism on the client supplied document data
+ whether auto-sensing is the Printer object's default or not.
+
+ Note: Since the auto-sensing algorithm is probabilistic, if the
+ client requests both auto-sensing ("document-format" set to '
+ application/octet-stream') and true fidelity ("ipp-attribute-
+ fidelity" set to 'true'), the Printer object might not be able to
+ guarantee exactly what the end user intended (the auto-sensing
+ algorithm might mistake one document format for another ), but it is
+ able to guarantee that its auto-sensing mechanism be used.
+
+ The maximum length of a 'mimeMediaType' value to represent IPP
+ attribute values is 255 octets.
+
+
+
+
+deBry, et al. Experimental [Page 68]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+4.1.10 'octetString'
+
+ The 'octetString' attribute syntax is a sequence of octets encoded in
+ a maximum of 1023 octets which is indicated in sub-section headers
+ using the notation: octetString(MAX). This syntax type is used for
+ opaque data.
+
+4.1.11 'boolean'
+
+ The 'boolean' attribute syntax has only two values: 'true' and '
+ false'.
+
+4.1.12 'integer'
+
+ The 'integer' attribute syntax is an integer value that is in the
+ range from -2**31 (MIN) to 2**31 - 1 (MAX). Each individual
+ attribute may specify the range constraint explicitly in sub-section
+ headers if the range is different from the full range of possible
+ integer values. For example: job-priority (integer(1:100)) for the
+ "job-priority" attribute. However, the enforcement of that
+ additional constraint is up to the IPP objects, not the protocol.
+
+4.1.13 'rangeOfInteger'
+
+ The 'rangeOfInteger' attribute syntax is an ordered pair of integers
+ that defines an inclusive range of integer values. The first integer
+ specifies the lower bound and the second specifies the upper bound.
+ If a range constraint is specified in the header description for an
+ attribute in this document whose attribute syntax is 'rangeOfInteger'
+ (i.e., 'X:Y' indicating X as a minimum value and Y as a maximum
+ value), then the constraint applies to both integers.
+
+4.1.14 'dateTime'
+
+ The 'dateTime' attribute syntax is a standard, fixed length, 11 octet
+ representation of the "DateAndTime" syntax as defined in RFC 2579
+ [RFC2579]. RFC 2579 also identifies an 8 octet representation of a
+ "DateAndTime" value, but IPP objects MUST use the 11 octet
+ representation. A user interface will provide a mapping between
+ protocol dateTime values and displayable user-friendly words or
+ presentation values and phrases which are localized to the natural
+ language and date format of the user.
+
+4.1.15 'resolution'
+
+ The 'resolution' attribute syntax specifies a two-dimensional
+ resolution in the indicated units. It consists of 3 values: a cross
+ feed direction resolution (positive integer value), a feed direction
+
+
+
+deBry, et al. Experimental [Page 69]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ resolution (positive integer value), and a units value. The
+ semantics of these three components are taken from the Printer MIB
+ [RFC1759] suggested values. That is, the cross feed direction
+ component resolution component is the same as the
+ prtMarkerAddressabilityXFeedDir object in the Printer MIB, the feed
+ direction component resolution component is the same as the
+ prtMarkerAddressabilityFeedDir in the Printer MIB, and the units
+ component is the same as the prtMarkerAddressabilityUnit object in
+ the Printer MIB (namely, '3' indicates dots per inch and '4'
+ indicates dots per centimeter). All three values MUST be present
+ even if the first two values are the same. Example: '300', '600', '
+ 3' indicates a 300 dpi cross-feed direction resolution, a 600 dpi
+ feed direction resolution, since a '3' indicates dots per inch (dpi).
+
+4.1.16 '1setOf X'
+
+ The '1setOf X' attribute syntax is 1 or more values of attribute
+ syntax type X. This syntax type is used for multi-valued attributes.
+ The syntax type is called '1setOf' rather than just 'setOf' as a
+ reminder that the set of values MUST NOT be empty (i.e., a set of
+ size 0). Sets are normally unordered. However each attribute
+ description of this type may specify that the values MUST be in a
+ certain order for that attribute.
+
+4.2 Job Template Attributes
+
+ Job Template attributes describe job processing behavior. Support
+ for Job Template attributes by a Printer object is OPTIONAL (see
+ section 13.2.3 for a description of support for OPTIONAL attributes).
+ Also, clients OPTIONALLY supply Job Template attributes in create
+ requests.
+
+ Job Template attributes conform to the following rules. For each Job
+ Template attribute called "xxx":
+
+ 1. If the Printer object supports "xxx" then it MUST support both a
+ "xxx-default" attribute (unless there is a "No" in the table
+ below) and a "xxx-supported" attribute. If the Printer object
+ doesn't support "xxx", then it MUST support neither an "xxx-
+ default" attribute nor an "xxx-supported" attribute, and it MUST
+ treat an attribute "xxx" supplied by a client as unsupported.
+ An attribute "xxx" may be supported for some document formats
+ and not supported for other document formats. For example, it
+ is expected that a Printer object would only support
+ "orientation-requested" for some document formats (such as '
+ text/plain' or 'text/html') but not others (such as '
+ application/postscript').
+
+
+
+
+deBry, et al. Experimental [Page 70]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ 2. "xxx" is OPTIONALLY supplied by the client in a create request.
+ If "xxx" is supplied, the client is indicating a desired job
+ processing behavior for this Job. When "xxx" is not supplied,
+ the client is indicating that the Printer object apply its
+ default job processing behavior at job processing time if the
+ document content does not contain an embedded instruction
+ indicating an xxx-related behavior.
+
+ Note: Since an administrator MAY change the default value
+ attribute after a Job object has been submitted but before it
+ has been processed, the default value used by the Printer object
+ at job processing time may be different that the default value
+ in effect at job submission time.
+
+ 3. The "xxx-supported" attribute is a Printer object attribute that
+ describes which job processing behaviors are supported by that
+ Printer object. A client can query the Printer object to find
+ out what xxx-related behaviors are supported by inspecting the
+ returned values of the "xxx-supported" attribute.
+
+ Note: The "xxx" in each "xxx-supported" attribute name is
+ singular, even though an "xxx-supported" attribute usually has
+ more than one value, such as "job-sheet-supported", unless the
+ "xxx" Job Template attribute is plural, such as "finishings" or
+ "sides". In such cases the "xxx-supported" attribute names are:
+ "finishings-supported" and "sides-supported".
+
+ 4. The "xxx-default" default value attribute describes what will be
+ done at job processing time when no other job processing
+ information is supplied by the client (either explicitly as an
+ IPP attribute in the create request or implicitly as an embedded
+ instruction within the document data).
+
+ If an application wishes to present an end user with a list of
+ supported values from which to choose, the application SHOULD query
+ the Printer object for its supported value attributes. The
+ application SHOULD also query the default value attributes. If the
+ application then limits selectable values to only those value that
+ are supported, the application can guarantee that the values supplied
+ by the client in the create request all fall within the set of
+ supported values at the Printer. When querying the Printer, the
+ client MAY enumerate each attribute by name in the Get-Printer-
+ Attributes Request, or the client MAY just name the "job-template"
+ group in order to get the complete set of supported attributes (both
+ supported and default attributes).
+
+
+
+
+
+
+deBry, et al. Experimental [Page 71]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ The "finishings" attribute is an example of a Job Template attribute.
+ It can take on a set of values such as 'staple', 'punch', and/or '
+ cover'. A client can query the Printer object for the "finishings-
+ supported" attribute and the "finishings-default" attribute. The
+ supported attribute contains a set of supported values. The default
+ value attribute contains the finishing value(s) that will be used for
+ a new Job if the client does not supply a "finishings" attribute in
+ the create request and the document data does not contain any
+ corresponding finishing instructions. If the client does supply the
+ "finishings" attribute in the create request, the IPP object
+ validates the value or values to make sure that they are a subset of
+ the supported values identified in the Printer object's "finishings-
+ supported" attribute. See section 3.2.1.2.
+
+ The table below summarizes the names and relationships for all Job
+ Template attributes. The first column of the table (labeled "Job
+ Attribute") shows the name and syntax for each Job Template attribute
+ in the Job object. These are the attributes that can optionally be
+ supplied by the client in a create request. The last two columns
+ (labeled "Printer: Default Value Attribute" and "Printer: Supported
+ Values Attribute") shows the name and syntax for each Job Template
+ attribute in the Printer object (the default value attribute and the
+ supported values attribute). A "No" in the table means the Printer
+ MUST NOT support the attribute (that is, the attribute is simply not
+ applicable). For brevity in the table, the 'text' and 'name' entries
+ do not show the maximum length for each attribute.
+
+ +===================+======================+======================+
+ | Job Attribute |Printer: Default Value| Printer: Supported |
+ | | Attribute | Values Attribute |
+ +===================+======================+======================+
+ | job-priority | job-priority-default |job-priority-supported|
+ | (integer 1:100) | (integer 1:100) |(integer 1:100) |
+ +-------------------+----------------------+----------------------+
+ | job-hold-until | job-hold-until- |job-hold-until- |
+ | (type3 keyword | | default | supported |
+ | name) | (type3 keyword | |(1setOf |
+ | | name) | type3 keyword | name)|
+ +-------------------+----------------------+----------------------+
+ | job-sheets | job-sheets-default |job-sheets-supported |
+ | (type3 keyword | | (type3 keyword | |(1setOf |
+ | name) | name) | type3 keyword | name)|
+ +-------------------+----------------------+----------------------+
+ |multiple-document- |multiple-document- |multiple-document- |
+ | handling | handling-default |handling-supported |
+ | (type2 keyword) | (type2 keyword) |(1setOf type2 keyword)|
+ +-------------------+----------------------+----------------------+
+
+
+
+
+deBry, et al. Experimental [Page 72]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ +===================+======================+======================+
+ | Job Attribute |Printer: Default Value| Printer: Supported |
+ | | Attribute | Values Attribute |
+ +===================+======================+======================+
+ | copies | copies-default | copies-supported |
+ | (integer (1:MAX)) | (integer (1:MAX)) | (rangeOfInteger |
+ | | | (1:MAX)) |
+ +-------------------+----------------------+----------------------+
+ | finishings | finishings-default | finishings-supported |
+ |(1setOf type2 enum)|(1setOf type2 enum) |(1setOf type2 enum) |
+ +-------------------+----------------------+----------------------+
+ | page-ranges | No | page-ranges- |
+ | (1setOf | | supported (boolean) |
+ | rangeOfInteger | | |
+ | (1:MAX)) | | |
+ +-------------------+----------------------+----------------------+
+ | sides | sides-default | sides-supported |
+ | (type2 keyword) | (type2 keyword) |(1setOf type2 keyword)|
+ +-------------------+----------------------+----------------------+
+ | number-up | number-up-default | number-up-supported |
+ | (integer (1:MAX)) | (integer (1:MAX)) |(1setOf integer |
+ | | | (1:MAX) | |
+ | | | rangeOfInteger |
+ | | | (1:MAX)) |
+ +-------------------+----------------------+----------------------+
+ | orientation- |orientation-requested-|orientation-requested-|
+ | requested | default | supported |
+ | (type2 enum) | (type2 enum) | (1setOf type2 enum) |
+ +-------------------+----------------------+----------------------+
+ | media | media-default | media-supported |
+ | (type3 keyword | | (type3 keyword | |(1setOf |
+ | name) | name) | type3 keyword | name)|
+ | | | |
+ | | | media-ready |
+ | | |(1setOf |
+ | | | type3 keyword | name)|
+ +-------------------+----------------------+----------------------+
+ | printer-resolution| printer-resolution- | printer-resolution- |
+ | (resolution) | default | supported |
+ | | (resolution) |(1setOf resolution) |
+ +-------------------+----------------------+----------------------+
+ | print-quality | print-quality-default| print-quality- |
+ | (type2 enum) | (type2 enum) | supported |
+ | | |(1setOf type2 enum) |
+ +-------------------+----------------------+----------------------+
+
+
+
+
+
+
+deBry, et al. Experimental [Page 73]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+4.2.1 job-priority (integer(1:100))
+
+ This attribute specifies a priority for scheduling the Job. A higher
+ value specifies a higher priority. The value 1 indicates the lowest
+ possible priority. The value 100 indicates the highest possible
+ priority. Among those jobs that are ready to print, a Printer MUST
+ print all jobs with a priority value of n before printing those with
+ a priority value of n-1 for all n.
+
+ If the Printer object supports this attribute, it MUST always support
+ the full range from 1 to 100. No administrative restrictions are
+ permitted. This way an end-user can always make full use of the
+ entire range with any Printer object. If privileged jobs are
+ implemented outside IPP/1.0, they MUST have priorities higher than
+ 100, rather than restricting the range available to end-users.
+
+ If the client does not supply this attribute and this attribute is
+ supported by the Printer object, the Printer object MUST use the
+ value of the Printer object's "job-priority-default" at job
+ submission time (unlike most Job Template attributes that are used if
+ necessary at job processing time).
+
+ The syntax for the "job-priority-supported" is also integer(1:100).
+ This single integer value indicates the number of priority levels
+ supported. The Printer object MUST take the value supplied by the
+ client and map it to the closest integer in a sequence of n integers
+ values that are evenly distributed over the range from 1 to 100 using
+ the formula:
+
+ roundToNearestInt((100x+50)/n)
+
+ where n is the value of "job-priority-supported" and x ranges from 0
+ through n-1.
+
+ For example, if n=1 the sequence of values is 50; if n=2, the
+ sequence of values is: 25 and 75; if n = 3, the sequence of values
+ is: 17, 50 and 83; if n = 10, the sequence of values is: 5, 15, 25,
+ 35, 45, 55, 65, 75, 85, and 95; if n = 100, the sequence of values
+ is: 1, 2, 3, . 100.
+
+ If the value of the Printer object's "job-priority-supported" is 10
+ and the client supplies values in the range 1 to 10, the Printer
+ object maps them to 5, in the range 11 to 20, the Printer object maps
+ them to 15, etc.
+
+
+
+
+
+
+
+deBry, et al. Experimental [Page 74]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+4.2.2 job-hold-until (type3 keyword | name (MAX))
+
+ This attribute specifies the named time period during which the Job
+ MUST become a candidate for printing.
+
+ Standard keyword values for named time periods are:
+
+ 'no-hold': immediately, if there are not other reasons to hold the
+ job
+ 'day-time': during the day
+ 'evening': evening
+ 'night': night
+ 'weekend': weekend
+ 'second-shift': second-shift (after close of business)
+ 'third-shift': third-shift (after midnight)
+
+ An administrator MUST associate allowable print times with a named
+ time period (by means outside IPP/1.0). An administrator is
+ encouraged to pick names that suggest the type of time period. An
+ administrator MAY define additional values using the 'name' or '
+ keyword' attribute syntax, depending on implementation.
+
+ If the value of this attribute specifies a time period that is in the
+ future, the Printer MUST add the 'job-hold-until-specified' value to
+ the job's "job-state-reasons" attribute, move the job to the '
+ pending-held' state, and MUST NOT schedule the job for printing until
+ the specified time-period arrives. When the specified time period
+ arrives, the Printer MUST remove the 'job-hold-until-specified' value
+ from the job's "job-state-reason" attribute and, if there are no
+ other job state reasons that keep the job in the 'pending-held'
+ state, the Printer MUST consider the job as a candidate for
+ processing by moving the job to the 'pending' state.
+
+ If this job attribute value is the named value 'no-hold', or the
+ specified time period has already started, the job MUST be a
+ candidate for processing immediately.
+
+ If the client does not supply this attribute and this attribute is
+ supported by the Printer object, the Printer object MUST use the
+ value of the Printer object's "job-hold-until-default" at job
+ submission time (unlike most Job Template attributes that are used if
+ necessary at job processing time).
+
+4.2.3 job-sheets (type3 keyword | name(MAX))
+
+ This attribute determines which job start/end sheet(s), if any, MUST
+ be printed with a job.
+
+
+
+
+deBry, et al. Experimental [Page 75]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ Standard keyword values are:
+
+ 'none': no job sheet is printed
+ 'standard': one or more site specific standard job sheets are
+ printed, e.g. a single start sheet or both start and end sheet
+ is printed
+
+ An administrator MAY define additional values using the 'name' or '
+ keyword' attribute syntax, depending on implementation.
+
+ Note: The effect of this attribute on jobs with multiple documents
+ MAY be affected by the "multiple-document-handling" job attribute
+ (section 4.2.4), depending on the job sheet semantics.
+
+4.2.4 multiple-document-handling (type2 keyword)
+
+ This attribute is relevant only if a job consists of two or more
+ documents. The attribute controls finishing operations and the
+ placement of one or more print-stream pages into impressions and onto
+ media sheets. When the value of the "copies" attribute exceeds 1, it
+ also controls the order in which the copies that result from
+ processing the documents are produced. For the purposes of this
+ explanations, if "a" represents an instance of document data, then
+ the result of processing the data in document "a" is a sequence of
+ media sheets represented by "a(*)".
+
+ Standard keyword values are:
+
+ 'single-document': If a Job object has multiple documents, say, the
+ document data is called a and b, then the result of processing
+ all the document data (a and then b) MUST be treated as a single
+ sequence of media sheets for finishing operations; that is,
+ finishing would be performed on the concatenation of the
+ sequences a(*),b(*). The Printer object MUST NOT force the data
+ in each document instance to be formatted onto a new print-
+ stream page, nor to start a new impression on a new media sheet.
+ If more than one copy is made, the ordering of the sets of media
+ sheets resulting from processing the document data MUST be a(*),
+ b(*), a(*), b(*), ..., and the Printer object MUST force each
+ copy (a(*),b(*)) to start on a new media sheet.
+ 'separate-documents-uncollated-copies': If a Job object has
+ multiple documents, say, the document data is called a and b,
+ then the result of processing the data in each document instance
+ MUST be treated as a single sequence of media sheets for
+ finishing operations; that is, the sets a(*) and b(*) would each
+ be finished separately. The Printer object MUST force each copy
+ of the result of processing the data in a single document to
+ start on a new media sheet. If more than one copy is made, the
+
+
+
+deBry, et al. Experimental [Page 76]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ ordering of the sets of media sheets resulting from processing
+ the document data MUST be a(*), a(*), ..., b(*), b(*) ... .
+ 'separate-documents-collated-copies': If a Job object has multiple
+ documents, say, the document data is called a and b, then the
+ result of processing the data in each document instance MUST be
+ treated as a single sequence of media sheets for finishing
+ operations; that is, the sets a(*) and b(*) would each be
+ finished separately. The Printer object MUST force each copy of
+ the result of processing the data in a single document to start
+ on a new media sheet. If more than one copy is made, the
+ ordering of the sets of media sheets resulting from processing
+ the document data MUST be a(*), b(*), a(*), b(*), ... .
+ 'single-document-new-sheet': Same as 'single-document', except
+ that the Printer object MUST ensure that the first impression of
+ each document instance in the job is placed on a new media
+ sheet. This value allows multiple documents to be stapled
+ together with a single staple where each document starts on a
+ new sheet.
+
+ The 'single-document' value is the same as 'separate-documents-
+ collated-copies' with respect to ordering of print-stream pages, but
+ not media sheet generation, since 'single-document' will put the
+ first page of the next document on the back side of a sheet if an odd
+ number of pages have been produced so far for the job, while '
+ separate-documents-collated-copies' always forces the next document
+ or document copy on to a new sheet. In addition, if the "finishings"
+ attribute specifies 'staple', then with 'single-document', documents
+ a and b are stapled together as a single document with no regard to
+ new sheets, with 'single-document-new-sheet', documents a and b are
+ stapled together as a single document, but document b starts on a new
+ sheet, but with 'separate-documents-uncollated-copies' and '
+ separate-documents-collated-copies', documents a and b are stapled
+ separately.
+
+ Note: None of these values provide means to produce uncollated sheets
+ within a document, i.e., where multiple copies of sheet n are
+ produced before sheet n+1 of the same document.
+
+ The relationship of this attribute and the other attributes that
+ control document processing is described in section 15.3.
+
+4.2.5 copies (integer(1:MAX))
+
+ This attribute specifies the number of copies to be printed.
+
+ On many devices the supported number of collated copies will be
+ limited by the number of physical output bins on the device, and may
+ be different from the number of uncollated copies which can be
+
+
+
+deBry, et al. Experimental [Page 77]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ supported.
+
+ Note: The effect of this attribute on jobs with multiple documents is
+ controlled by the "multiple-document-handling" job attribute (section
+ 4.2.4) and the relationship of this attribute and the other
+ attributes that control document processing is described in section
+ 15.3.
+
+4.2.6 finishings (1setOf type2 enum)
+
+ This attribute identifies the finishing operations that the Printer
+ uses for each copy of each printed document in the Job. For Jobs with
+ multiple documents, the "multiple-document-handling" attribute
+ determines what constitutes a "copy" for purposes of finishing.
+
+ Standard enum values are:
+
+ Value Symbolic Name and Description
+
+ '3' 'none': Perform no finishing
+ '4' 'staple': Bind the document(s) with one or more staples.
+ The exact number and placement of the staples is
+ site-defined.
+ '5' 'punch': This value indicates that holes are required in
+ the finished document. The exact number and placement
+ of the holes is site-defined The punch specification
+ MAY be satisfied (in a site- and implementation-
+ specific manner) either by drilling/punching, or by
+ substituting pre-drilled media.
+ '6' 'cover': This value is specified when it is desired to
+ select a non-printed (or pre-printed) cover for the
+ document. This does not supplant the specification of
+ a printed cover (on cover stock medium) by the
+ document itself.
+ '7' 'bind': This value indicates that a binding is to be
+ applied to the document; the type and placement of the
+ binding is site-defined."
+
+ Note: The effect of this attribute on jobs with multiple documents is
+ controlled by the "multiple-document-handling" job attribute (section
+ 4.2.4) and the relationship of this attribute and the other
+ attributes that control document processing is described in section
+ 15.3.
+
+ If the client supplies a value of 'none' along with any other
+ combination of values, it is the same as if only that other
+ combination of values had been supplied (that is the 'none' value has
+ no effect).
+
+
+
+deBry, et al. Experimental [Page 78]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+4.2.7 page-ranges (1setOf rangeOfInteger (1:MAX))
+
+ This attribute identifies the range(s) of print-stream pages that the
+ Printer object uses for each copy of each document which are to be
+ printed. Nothing is printed for any pages identified that do not
+ exist in the document(s). Ranges MUST be in ascending order, for
+ example: 1-3, 5-7, 15-19 and MUST NOT overlap, so that a non-spooling
+ Printer object can process the job in a single pass. If the ranges
+ are not ascending or are overlapping, the IPP object MUST reject the
+ request and return the 'client-error-bad-request' status code. The
+ attribute is associated with print-stream pages not application-
+ numbered pages (for example, the page numbers found in the headers
+ and or footers for certain word processing applications).
+
+ For Jobs with multiple documents, the "multiple-document-handling"
+ attribute determines what constitutes a "copy" for purposes of the
+ specified page range(s). When "multiple-document-handling" is '
+ single-document', the Printer object MUST apply each supplied page
+ range once to the concatenation of the print-stream pages. For
+ example, if there are 8 documents of 10 pages each, the page-range '
+ 41:60' prints the pages in the 5th and 6th documents as a single
+ document and none of the pages of the other documents are printed.
+ When "multiple-document-handling" is 'separate-documents-uncollated-
+ copies' or 'separate-documents-collated-copies', the Printer object
+ MUST apply each supplied page range repeatedly to each document copy.
+ For the same job, the page-range '1:3, 10:10' would print the first 3
+ pages and the 10th page of each of the 8 documents in the Job, as 8
+ separate documents.
+
+ In most cases, the exact pages to be printed will be generated by a
+ device driver and this attribute would not be required. However,
+ when printing an archived document which has already been formatted,
+ the end user may elect to print just a subset of the pages contained
+ in the document. In this case, if page-range = n.m is specified, the
+ first page to be printed will be page n. All subsequent pages of the
+ document will be printed through and including page m.
+
+ "page-ranges-supported" is a boolean value indicating whether or not
+ the printer is capable of supporting the printing of page ranges.
+ This capability may differ from one PDL to another. There is no
+ "page-ranges-default" attribute. If the "page-ranges" attribute is
+ not supplied by the client, all pages of the document will be
+ printed.
+
+
+
+
+
+
+
+
+deBry, et al. Experimental [Page 79]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ Note: The effect of this attribute on jobs with multiple documents is
+ controlled by the "multiple-document-handling" job attribute (section
+ 4.2.4) and the relationship of this attribute and the other
+ attributes that control document processing is described in section
+ 15.3.
+
+4.2.8 sides (type2 keyword)
+
+ This attribute specifies how print-stream pages are to be imposed
+ upon the sides of an instance of a selected medium, i.e., an
+ impression.
+
+ The standard keyword values are:
+
+ 'one-sided': imposes each consecutive print-stream page upon the
+ same side of consecutive media sheets.
+ 'two-sided-long-edge': imposes each consecutive pair of print-
+ stream pages upon front and back sides of consecutive media
+ sheets, such that the orientation of each pair of print-stream
+ pages on the medium would be correct for the reader as if for
+ binding on the long edge. This imposition is sometimes called '
+ duplex' or 'head-to-head'.
+ 'two-sided-short-edge': imposes each consecutive pair of print-
+ stream pages upon front and back sides of consecutive media
+ sheets, such that the orientation of each pair of print-stream
+ pages on the medium would be correct for the reader as if for
+ binding on the short edge. This imposition is sometimes called
+ 'tumble' or 'head-to-toe'.
+
+ 'two-sided-long-edge', 'two-sided-short-edge', 'tumble', and 'duplex'
+ all work the same for portrait or landscape. However 'head-to-toe'
+ is 'tumble' in portrait but 'duplex' in landscape. 'head-to-head'
+ also switches between 'duplex' and 'tumble' when using portrait and
+ landscape modes.
+
+ Note: The effect of this attribute on jobs with multiple documents is
+ controlled by the "multiple-document-handling" job attribute (section
+ 4.2.4) and the relationship of this attribute and the other
+ attributes that control document processing is described in section
+ 15.3.
+
+4.2.9 number-up (integer(1:MAX))
+
+ This attribute specifies the number of print-stream pages to impose
+ upon a single side of an instance of a selected medium. For example,
+ if the value is:
+
+
+
+
+
+deBry, et al. Experimental [Page 80]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ Value Description
+
+ '1' the Printer MUST place one print-stream page on a single
+ side of an instance of the selected medium (MAY add
+ some sort of translation, scaling, or rotation).
+ '2' the Printer MUST place two print-stream pages on a single
+ side of an instance of the selected medium (MAY add
+ some sort of translation, scaling, or rotation).
+ '4' the Printer MUST place four print-stream pages on a single
+ side of an instance of the selected medium (MAY add
+ some sort of translation, scaling, or rotation).
+
+ This attribute primarily controls the translation, scaling and
+ rotation of print-stream pages.
+
+ Note: The effect of this attribute on jobs with multiple documents is
+ controlled by the "multiple-document-handling" job attribute (section
+ 4.2.4) and the relationship of this attribute and the other
+ attributes that control document processing is described in section
+ 15.3.
+
+4.2.10 orientation-requested (type2 enum)
+
+ This attribute indicates the desired orientation for printed print-
+ stream pages; it does not describe the orientation of the client-
+ supplied print-stream pages.
+
+ For some document formats (such as 'application/postscript'), the
+ desired orientation of the print-stream pages is specified within the
+ document data. This information is generated by a device driver
+ prior to the submission of the print job. Other document formats
+ (such as 'text/plain') do not include the notion of desired
+ orientation within the document data. In the latter case it is
+ possible for the Printer object to bind the desired orientation to
+ the document data after it has been submitted. It is expected that a
+ Printer object would only support "orientations-requested" for some
+ document formats (e.g., 'text/plain' or 'text/html') but not others
+ (e.g., 'application/postscript'). This is no different than any
+ other Job Template attribute since section 4.2, item 1, points out
+ that a Printer object may support or not support any Job Template
+ attribute based on the document format supplied by the client.
+ However, a special mention is made here since it is very likely that
+ a Printer object will support "orientation-requested" for only a
+ subset of the supported document formats.
+
+
+
+
+
+
+
+deBry, et al. Experimental [Page 81]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ Standard enum values are:
+
+ Value Symbolic Name and Description
+
+ '3' 'portrait': The content will be imaged across the short
+ edge of the medium.
+ '4' 'landscape': The content will be imaged across the long
+ edge of the medium. Landscape is defined to be a
+ rotation of the print-stream page to be imaged by +90
+ degrees with respect to the medium (i.e. anti-
+ clockwise) from the portrait orientation. Note: The
+ +90 direction was chosen because simple finishing on
+ the long edge is the same edge whether portrait or
+ landscape
+ '5' 'reverse-landscape': The content will be imaged across the
+ long edge of the medium. Reverse-landscape is defined
+ to be a rotation of the print-stream page to be imaged
+ by - 90 degrees with respect to the medium (i.e.
+ clockwise) from the portrait orientation. Note: The '
+ reverse-landscape' value was added because some
+ applications rotate landscape -90 degrees from
+ portrait, rather than +90 degrees.
+ '6' 'reverse-portrait': The content will be imaged across the
+ short edge of the medium. Reverse-portrait is defined
+ to be a rotation of the print-stream page to be imaged
+ by 180 degrees with respect to the medium from the
+ portrait orientation. Note: The 'reverse-portrait'
+ value was added for use with the "finishings"
+ attribute in cases where the opposite edge is desired
+ for finishing a portrait document on simple finishing
+ devices that have only one finishing position. Thus a
+ 'text'/plain' portrait document can be stapled "on the
+ right" by a simple finishing device as is common use
+ with some middle eastern languages such as Hebrew.
+
+ Note: The effect of this attribute on jobs with multiple documents is
+ controlled by the "multiple-document-handling" job attribute (section
+ 4.2.4) and the relationship of this attribute and the other
+ attributes that control document processing is described in section
+ 15.3.
+
+4.2.11 media (type3 keyword | name(MAX))
+
+ This attribute identifies the medium that the Printer uses for all
+ impressions of the Job.
+
+ The values for "media" include medium-names, medium-sizes, input-
+ trays and electronic forms so that one attribute specifies the media.
+
+
+
+deBry, et al. Experimental [Page 82]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ If a Printer object supports a medium name as a value of this
+ attribute, such a medium name implicitly selects an input-tray that
+ contains the specified medium. If a Printer object supports a medium
+ size as a value of this attribute, such a medium size implicitly
+ selects a medium name that in turn implicitly selects an input-tray
+ that contains the medium with the specified size. If a Printer
+ object supports an input-tray as the value of this attribute, such an
+ input-tray implicitly selects the medium that is in that input-tray
+ at the time the job prints. This case includes manual-feed input-
+ trays. If a Printer object supports an electronic form as the value
+ of this attribute, such an electronic form implicitly selects a
+ medium-name that in turn implicitly selects an input-tray that
+ contains the medium specified by the electronic form. The electronic
+ form also implicitly selects an image that the Printer MUST merge
+ with the document data as its prints each page.
+
+ Standard keyword values are (taken from ISO DPA and the Printer MIB)
+ and are listed in section 14. An administrator MAY define additional
+ values using the 'name' or 'keyword' attribute syntax, depending on
+ implementation.
+
+ There is also an additional Printer attribute named "media-ready"
+ which differs from "media-supported" in that legal values only
+ include the subset of "media-supported" values that are physically
+ loaded and ready for printing with no operator intervention required.
+ If an IPP object supports "media-supported", it NEED NOT support
+ "media-ready".
+
+ The relationship of this attribute and the other attributes that
+ control document processing is described in section 15.3.
+
+4.2.12 printer-resolution (resolution)
+
+ This attribute identifies the resolution that Printer uses for the
+ Job.
+
+4.2.13 print-quality (type2 enum)
+
+ This attribute specifies the print quality that the Printer uses for
+ the Job.
+
+ The standard enum values are:
+
+ Value Symbolic Name and Description
+
+ '3' 'draft': lowest quality available on the printer
+ '4' 'normal': normal or intermediate quality on the printer
+ '5' 'high': highest quality available on the printer
+
+
+
+deBry, et al. Experimental [Page 83]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+4.3 Job Description Attributes
+
+ The attributes in this section form the attribute group called "job-
+ description". The following table summarizes these attributes. The
+ third column indicates whether the attribute is a REQUIRED attribute
+ that MUST be supported by Printer objects. If it is not indicated as
+ REQUIRED, then it is OPTIONAL. The maximum size in octets for 'text'
+ and 'name' attributes is indicated in parenthesizes.
+
+ +----------------------------+----------------------+----------------+
+ | Attribute | Syntax | REQUIRED? |
+ +----------------------------+----------------------+----------------+
+ | job-uri | uri | REQUIRED |
+ +----------------------------+----------------------+----------------+
+ | job-id | integer(1:MAX) | REQUIRED |
+ +----------------------------+----------------------+----------------+
+ | job-printer-uri | uri | REQUIRED |
+ +----------------------------+----------------------+----------------+
+ | job-more-info | uri | |
+ +----------------------------+----------------------+----------------+
+ | job-name | name (MAX) | REQUIRED |
+ +----------------------------+----------------------+----------------+
+ | job-originating-user-name | name (MAX) | REQUIRED |
+ +----------------------------+----------------------+----------------+
+ | job-state | type1 enum | REQUIRED |
+ +----------------------------+----------------------+----------------+
+ | job-state-reasons | 1setOf type2 keyword | |
+ +----------------------------+----------------------+----------------+
+ | job-state-message | text (MAX) | |
+ +----------------------------+----------------------+----------------+
+ | number-of-documents | integer (0:MAX) | |
+ +----------------------------+----------------------+----------------+
+ | output-device-assigned | name (127) | |
+ +----------------------------+----------------------+----------------+
+ | time-at-creation | integer (0:MAX) | |
+ +----------------------------+----------------------+----------------+
+ | time-at-processing | integer (0:MAX) | |
+ +----------------------------+----------------------+----------------+
+ | time-at-completed | integer (0:MAX) | |
+ +----------------------------+----------------------+----------------+
+ | number-of-intervening-jobs | integer (0:MAX) | |
+ +----------------------------+----------------------+----------------+
+ | job-message-from-operator | text (127) | |
+ +----------------------------+----------------------+----------------+
+ | job-k-octets | integer (0:MAX) | |
+ +----------------------------+----------------------+----------------+
+ | job-impressions | integer (0:MAX) | |
+ +----------------------------+----------------------+----------------+
+
+
+
+deBry, et al. Experimental [Page 84]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ +----------------------------+----------------------+----------------+
+ | Attribute | Syntax | REQUIRED? |
+ +----------------------------+----------------------+----------------+
+ | job-media-sheets | integer (0:MAX) | |
+ +----------------------------+----------------------+----------------+
+ | job-k-octets-processed | integer (0:MAX) | |
+ +----------------------------+----------------------+----------------+
+ | job-impressions-completed | integer (0:MAX) | |
+ +----------------------------+----------------------+----------------+
+ | job-media-sheets-completed | integer (0:MAX) | |
+ +----------------------------+----------------------+----------------+
+ | attributes-charset | charset | REQUIRED |
+ +----------------------------+----------------------+----------------+
+ | attributes-natural-language| naturalLanguage | REQUIRED |
+ +----------------------------+----------------------+----------------+
+
+
+4.3.1 job-uri (uri)
+
+ This REQUIRED attribute contains the URI for the job. The Printer
+ object, on receipt of a new job, generates a URI which identifies the
+ new Job. The Printer object returns the value of the "job-uri"
+ attribute as part of the response to a create request. The precise
+ format of a Job URI is implementation dependent. If the Printer
+ object supports more than one URI and there is some relationship
+ between the newly formed Job URI and the Printer object's URI, the
+ Printer object uses the Printer URI supplied by the client in the
+ create request. For example, if the create request comes in over a
+ secure channel, the new Job URI MUST use the same secure channel.
+ This can be guaranteed because the Printer object is responsible for
+ generating the Job URI and the Printer object is aware of its
+ security configuration and policy as well as the Printer URI used in
+ the create request.
+
+ For a description of this attribute and its relationship to "job-id"
+ and "job-printer-uri" attribute, see the discussion in section 2.4 on
+ "Object Identity".
+
+4.3.2 job-id (integer(1:MAX))
+
+ This REQUIRED attribute contains the ID of the job. The Printer, on
+ receipt of a new job, generates an ID which identifies the new Job on
+ that Printer. The Printer returns the value of the "job-id"
+ attribute as part of the response to a create request. The 0 value
+ is not included to allow for compatibility with SNMP index values
+ which also cannot be 0.
+
+
+
+
+
+deBry, et al. Experimental [Page 85]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ For a description of this attribute and its relationship to "job-uri"
+ and "job-printer-uri" attribute, see the discussion in section 2.4 on
+ "Object Identity".
+
+4.3.3 job-printer-uri (uri)
+
+ This REQUIRED attribute identifies the Printer object that created
+ this Job object. When a Printer object creates a Job object, it
+ populates this attribute with the Printer object URI that was used in
+ the create request. This attribute permits a client to identify the
+ Printer object that created this Job object when only the Job
+ object's URI is available to the client. The client queries the
+ creating Printer object to determine which languages, charsets,
+ operations, are supported for this Job.
+
+ For a description of this attribute and its relationship to "job-uri"
+ and "job-id" attribute, see the discussion in section 2.4 on "Object
+ Identity".
+
+4.3.4 job-more-info (uri)
+
+ Similar to "printer-more-info", this attribute contains the URI
+ referencing some resource with more information about this Job
+ object, perhaps an HTML page containing information about the Job.
+
+4.3.5 job-name (name(MAX))
+
+ This REQUIRED attribute is the name of the job. It is a name that is
+ more user friendly than the "job-uri" attribute value. It does not
+ need to be unique between Jobs. The Job's "job-name" attribute is
+ set to the value supplied by the client in the "job-name" operation
+ attribute in the create request (see Section 3.2.1.1). If, however,
+ the "job-name" operation attribute is not supplied by the client in
+ the create request, the Printer object, on creation of the Job, MUST
+ generate a name. The printer SHOULD generate the value of the Job's
+ "job-name" attribute from the first of the following sources that
+ produces a value: 1) the "document-name" operation attribute of the
+ first (or only) document, 2) the "document-URI" attribute of the
+ first (or only) document, or 3) any other piece of Job specific
+ and/or Document Content information.
+
+4.3.6 job-originating-user-name (name(MAX))
+
+ This REQUIRED attribute contains the name of the end user that
+ submitted the print job. The Printer object sets this attribute to
+ the most authenticated printable name that it can obtain from the
+ authentication service over which the IPP operation was received.
+
+
+
+
+deBry, et al. Experimental [Page 86]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ Only if such is not available, does the Printer object use the value
+ supplied by the client in the "requesting-user-name" operation
+ attribute of the create operation (see Section 8).
+
+ Note: The Printer object needs to keep an internal originating user
+ id of some form, typically as a credential of a principal, with the
+ Job object. Since such an internal attribute is implementation-
+ dependent and not of interest to clients, it is not specified as a
+ Job Description attribute. This originating user id is used for
+ authorization checks (if any) on all subsequent operation.
+
+4.3.7 job-state (type1 enum)
+
+ This REQUIRED attribute identifies the current state of the job.
+ Even though the IPP protocol defines eight values for job states,
+ implementations only need to support those states which are
+ appropriate for the particular implementation. In other words, a
+ Printer supports only those job states implemented by the output
+ device and available to the Printer object implementation.
+
+ Standard enum values are:
+
+ Values Symbolic Name and Description
+
+ '3' 'pending': The job is a candidate to start processing, but
+ is not yet processing.
+
+ '4' 'pending-held': The job is not a candidate for processing
+ for any number of reasons but will return to the '
+ pending' state as soon as the reasons are no longer
+ present. The job's "job-state-reason" attribute MUST
+ indicate why the job is no longer a candidate for
+ processing.
+
+ '5' 'processing': One or more of:
+
+ 1. the job is using, or is attempting to use, one or
+ more purely software processes that are analyzing,
+ creating, or interpreting a PDL, etc.,
+ 2. the job is using, or is attempting to use, one or
+ more hardware devices that are interpreting a PDL,
+ making marks on a medium, and/or performing finishing,
+ such as stapling, etc.,
+ 3. the Printer object has made the job ready for
+ printing, but the output device is not yet printing
+ it, either because the job hasn't reached the output
+
+
+
+
+
+deBry, et al. Experimental [Page 87]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ device or because the job is queued in the output
+ device or some other spooler, awaiting the output
+ device to print it.
+
+ When the job is in the 'processing' state, the entire
+ job state includes the detailed status represented in
+ the printer's "printer-state", "printer-state-
+ reasons", and "printer-state-message" attributes.
+
+ Implementations MAY, though they NEED NOT, include
+ additional values in the job's "job-state-reasons"
+ attribute to indicate the progress of the job, such as
+ adding the 'job-printing' value to indicate when the
+ output device is actually making marks on paper and/or
+ the 'processing-to-stop-point' value to indicate that
+ the IPP object is in the process of canceling or
+ aborting the job. Most implementations won't bother
+ with this nuance.
+
+ '6' 'processing-stopped': The job has stopped while processing
+ for any number of reasons and will return to the '
+ processing' state as soon as the reasons are no longer
+ present.
+
+ The job's "job-state-reason" attribute MAY indicate
+ why the job has stopped processing. For example, if
+ the output device is stopped, the 'printer-stopped'
+ value MAY be included in the job's "job-state-reasons"
+ attribute.
+
+ Note: When an output device is stopped, the device
+ usually indicates its condition in human readable form
+ locally at the device. A client can obtain more
+ complete device status remotely by querying the
+ Printer object's "printer-state", "printer-state-
+ reasons" and "printer-state-message" attributes.
+
+ '7' 'canceled': The job has been canceled by a Cancel-Job
+ operation and the Printer object has completed
+ canceling the job and all job status attributes have
+ reached their final values for the job. While the
+ Printer object is canceling the job, the job remains
+ in its current state, but the job's "job-state-
+ reasons" attribute SHOULD contain the 'processing-to-
+ stop-point' value and one of the 'canceled-by-user', '
+ canceled-by-operator', or 'canceled-at-device' value.
+
+
+
+
+
+deBry, et al. Experimental [Page 88]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ When the job moves to the 'canceled' state, the '
+ processing-to-stop-point' value, if present, MUST be
+ removed, but the 'canceled-by-xxx', if present, MUST
+ remain.
+
+ '8' 'aborted': The job has been aborted by the system, usually
+ while the job was in the 'processing' or 'processing-
+ stopped' state and the Printer has completed aborting
+ the job and all job status attributes have reached
+ their final values for the job. While the Printer
+ object is aborting the job, the job remains in its
+ current state, but the job's "job-state-reasons"
+ attribute SHOULD contain the 'processing-to-stop-
+ point' and 'aborted-by-system' values. When the job
+ moves to the 'aborted' state, the 'processing-to-
+ stop-point' value, if present, MUST be removed, but
+ the 'aborted-by-system' value, if present, MUST
+ remain.
+
+ '9' 'completed': The job has completed successfully or with
+ warnings or errors after processing and all of the job
+ media sheets have been successfully stacked in the
+ appropriate output bin(s) and all job status
+ attributes have reached their final values for the
+ job. The job's "job-state-reasons" attribute SHOULD
+ contain one of: 'completed-successfully', '
+ completed-with-warnings', or 'completed-with-errors'
+ values.
+
+ The final value for this attribute MUST be one of: 'completed', '
+ canceled', or 'aborted' before the Printer removes the job
+ altogether. The length of time that jobs remain in the 'canceled', '
+ aborted', and 'completed' states depends on implementation.
+
+ The following figure shows the normal job state transitions.
+
+ +----> canceled
+ /
+ +----> pending --------> processing ---------+------> completed
+ | ^ ^ \
+ --->+ | | +----> aborted
+ | v v /
+ +----> pending-held processing-stopped ---+
+
+ Normally a job progresses from left to right. Other state
+ transitions are unlikely, but are not forbidden. Not shown are the
+ transitions to the 'canceled' state from the 'pending', 'pending-
+ held', and 'processing-stopped' states.
+
+
+
+deBry, et al. Experimental [Page 89]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ Jobs reach one of the three terminal states: 'completed', 'canceled',
+ or 'aborted', after the jobs have completed all activity, including
+ stacking output media, after the jobs have completed all activity,
+ and all job status attributes have reached their final values for the
+ job.
+
+ Note: As with all other IPP attributes, if the implementation can not
+ determine the correct value for this attribute, it SHOULD respond
+ with the out-of-band value 'unknown' (see section 4.1) rather than
+ try to guess at some possibly incorrect value and give the end user
+ the wrong impression about the state of the Job object. For example,
+ if the implementation is just a gateway into some printing system
+ that does not provide detailed status about the print job, the IPP
+ Job object's state might literally be 'unknown'.
+
+4.3.8 job-state-reasons (1setOf type2 keyword)
+
+ This attribute provides additional information about the job's
+ current state, i.e., information that augments the value of the job's
+ "job-state" attribute.
+
+ Implementation of these values is OPTIONAL, i.e., a Printer NEED NOT
+ implement them, even if (1) the output device supports the
+ functionality represented by the reason and (2) is available to the
+ Printer object implementation. These values MAY be used with any job
+ state or states for which the reason makes sense. Furthermore, when
+ implemented, the Printer MUST return these values when the reason
+ applies and MUST NOT return them when the reason no longer applies
+ whether the value of the Job's "job-state" attribute changed or not.
+ When the Job does not have any reasons for being in its current
+ state, the value of the Job's "job-state-reasons" attribute MUST be '
+ none'.
+
+ Note: While values cannot be added to the 'job-state' attribute
+ without impacting deployed clients that take actions upon receiving
+ "job-state" values, it is the intent that additional "job-state-
+ reasons" values can be defined and registered without impacting such
+ deployed clients. In other words, the "job-state-reasons" attribute
+ is intended to be extensible.
+
+ The following standard keyword values are defined. For ease of
+ understanding, the values are presented in the order in which the
+ reasons are likely to occur (if implemented), starting with the '
+ job-incoming' value:
+
+ 'none': There are no reasons for the job's current state.
+ 'job-incoming': The Create-Job operation has been accepted by the
+ Printer, but the Printer is expecting additional Send-Document
+
+
+
+deBry, et al. Experimental [Page 90]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ and/or Send-URI operations and/or is accessing/accepting
+ document data.
+ 'submission-interrupted': The job was not completely submitted for
+ some unforeseen reason, such as: (1) the Printer has crashed
+ before the job was closed by the client, (2) the Printer or the
+ document transfer method has crashed in some non-recoverable way
+ before the document data was entirely transferred to the
+ Printer, (3) the client crashed or failed to close the job
+ before the time-out period. See section 4.4.28.
+ 'job-outgoing': The Printer is transmitting the job to the output
+ device.
+ 'job-hold-until-specified': The value of the job's "job-hold-
+ until" attribute was specified with a time period that is still
+ in the future. The job MUST NOT be a candidate for processing
+ until this reason is removed and there are no other reasons to
+ hold the job.
+ 'resources-are-not-ready': At least one of the resources needed by
+ the job, such as media, fonts, resource objects, etc., is not
+ ready on any of the physical printer's for which the job is a
+ candidate. This condition MAY be detected when the job is
+ accepted, or subsequently while the job is pending or
+ processing, depending on implementation. The job may remain in
+ its current state or be moved to the 'pending-held' state,
+ depending on implementation and/or job scheduling policy.
+ 'printer-stopped-partly': The value of the Printer's "printer-
+ state-reasons" attribute contains the value 'stopped-partly'.
+ 'printer-stopped': The value of the Printer's "printer-state"
+ attribute is 'stopped'.
+ 'job-interpreting': Job is in the 'processing' state, but more
+ specifically, the Printer is interpreting the document data.
+ 'job-queued': Job is in the 'processing' state, but more
+ specifically, the Printer has queued the document data.
+ 'job-transforming': Job is in the 'processing' state, but more
+ specifically, the Printer is interpreting document data and
+ producing another electronic representation.
+ 'job-printing': The output device is marking media. This value is
+ useful for Printers which spend a great deal of time processing
+ (1) when no marking is happening and then want to show that
+ marking is now happening or (2) when the job is in the process
+ of being canceled or aborted while the job remains in the '
+ processing' state, but the marking has not yet stopped so that
+ impression or sheet counts are still increasing for the job.
+ 'job-canceled-by-user': The job was canceled by the owner of the
+ job using the Cancel-Job request, i.e., by a user whose
+ authenticated identity is the same as the value of the
+ originating user that created the Job object, or by some other
+ authorized end-user, such as a member of the job owner's
+ security group.
+
+
+
+deBry, et al. Experimental [Page 91]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ 'job-canceled-by-operator': The job was canceled by the operator
+ using the Cancel-Job request, i.e., by a user who has been
+ authenticated as having operator privileges (whether local or
+ remote). If the security policy is to allow anyone to cancel
+ anyone's job, then this value may be used when the job is
+ canceled by other than the owner of the job. For such a
+ security policy, in effect, everyone is an operator as far as
+ canceling jobs with IPP is concerned.
+ 'job-canceled-at-device': The job was canceled by an unidentified
+ local user, i.e., a user at a console at the device.
+ 'aborted-by-system': The job (1) is in the process of being
+ aborted, (2) has been aborted by the system and placed in the '
+ aborted' state, or (3) has been aborted by the system and placed
+ in the 'pending-held' state, so that a user or operator can
+ manually try the job again.
+ 'processing-to-stop-point': The requester has issued a Cancel-Job
+ operation or the Printer object has aborted the job, but is
+ still performing some actions on the job until a specified stop
+ point occurs or job termination/cleanup is completed.
+
+ This reason is recommended to be used in conjunction with the '
+ processing' job state to indicate that the Printer object is
+ still performing some actions on the job while the job remains
+ in the 'processing' state. After all the job's job description
+ attributes have stopped incrementing, the Printer object moves
+ the job from the 'processing' state to the 'canceled' or '
+ aborted' job states.
+
+ 'service-off-line': The Printer is off-line and accepting no jobs.
+ All 'pending' jobs are put into the 'pending-held' state. This
+ situation could be true if the service's or document transform's
+ input is impaired or broken.
+ 'job-completed-successfully': The job completed successfully.
+ 'job-completed-with-warnings': The job completed with warnings.
+ 'job-completed-with-errors': The job completed with errors (and
+ possibly warnings too).
+
+4.3.9 job-state-message (text(MAX))
+
+ This attribute specifies information about the "job-state" and "job-
+ state-reasons" attributes in human readable text. If the Printer
+ object supports this attribute, the Printer object MUST be able to
+ generate this message in any of the natural languages identified by
+ the Printer's "generated-natural-language-supported" attribute (see
+ the "attributes-natural-language" operation attribute specified in
+ Section 3.1.4.1).
+
+
+
+
+
+deBry, et al. Experimental [Page 92]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ Note: the value SHOULD NOT contain additional information not
+ contained in the values of the "job-state" and "job-states-reasons"
+ attributes, such as interpreter error information. Otherwise,
+ application programs might attempt to parse the (localized text).
+ For such additional information such as interpreter errors for
+ application program consumption, a new attribute with keyword values,
+ needs to be developed and registered.
+
+4.3.10 number-of-documents (integer(0:MAX))
+
+ This attribute indicates the number of documents in the job, i.e.,
+ the number of Send-Document, Send-URI, Print-Job, or Print-URI
+ operations that the Printer has accepted for this job, regardless of
+ whether the document data has reached the Printer object or not.
+
+ Implementations supporting the OPTIONAL Create-Job/Send-
+ Document/Send-URI operations SHOULD support this attribute so that
+ clients can query the number of documents in each job.
+
+4.3.11 output-device-assigned (name(127))
+
+ This attribute identifies the output device to which the Printer
+ object has assigned this job. If an output device implements an
+ embedded Printer object, the Printer object NEED NOT set this
+ attribute. If a print server implements a Printer object, the value
+ MAY be empty (zero-length string) or not returned until the Printer
+ object assigns an output device to the job. This attribute is
+ particularly useful when a single Printer object support multiple
+ devices (so called "fan-out").
+
+4.3.12 time-at-creation (integer(0:MAX))
+
+ This attribute indicates the point in time at which the Job object
+ was created. In order to populate this attribute, the Printer object
+ uses the value in its "printer-up-time" attribute at the time the Job
+ object is created.
+
+4.3.13 time-at-processing (integer(0:MAX))
+
+ This attribute indicates the point in time at which the Job object
+ began processing. In order to populate this attribute, the Printer
+ object uses the value in its "printer-up-time" attribute at the time
+ the Job object is moved into the 'processing' state for the first
+ time.
+
+
+
+
+
+
+
+deBry, et al. Experimental [Page 93]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+4.3.14 time-at-completed (integer(0:MAX))
+
+ This attribute indicates the point in time at which the Job object
+ completed (or was cancelled or aborted). In order to populate this
+ attribute, the Printer object uses the value in its "printer-up-time"
+ attribute at the time the Job object is moved into the 'completed' or
+ 'canceled' or 'aborted' state.
+
+4.3.15 number-of-intervening-jobs (integer(0:MAX))
+
+ This attribute indicates the number of jobs that are "ahead" of this
+ job in the relative chronological order of expected time to complete
+ (i.e., the current scheduled order). For efficiency, it is only
+ necessary to calculate this value when an operation is performed that
+ requests this attribute.
+
+4.3.16 job-message-from-operator (text(127))
+
+ This attribute provides a message from an operator, system
+ administrator or "intelligent" process to indicate to the end user
+ the reasons for modification or other management action taken on a
+ job.
+
+4.3.17 job-k-octets (integer(0:MAX))
+
+ This attribute specifies the total size of the document(s) in K
+ octets, i.e., in units of 1024 octets requested to be processed in
+ the job. The value MUST be rounded up, so that a job between 1 and
+ 1024 octets MUST be indicated as being 1, 1025 to 2048 MUST be 2,
+ etc.
+
+ This value MUST NOT include the multiplicative factors contributed by
+ the number of copies specified by the "copies" attribute, independent
+ of whether the device can process multiple copies without making
+ multiple passes over the job or document data and independent of
+ whether the output is collated or not. Thus the value is independent
+ of the implementation and indicates the size of the document(s)
+ measured in K octets independent of the number of copies.
+
+ This value MUST also not include the multiplicative factor due to a
+ copies instruction embedded in the document data. If the document
+ data actually includes replications of the document data, this value
+ will include such replication. In other words, this value is always
+ the size of the source document data, rather than a measure of the
+ hardcopy output to be produced.
+
+
+
+
+
+
+deBry, et al. Experimental [Page 94]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ Note: This attribute and the following two attributes ("job-
+ impressions" and "job-media-sheets") are not intended to be counters;
+ they are intended to be useful routing and scheduling information if
+ known. For these three attributes, the Printer object may try to
+ compute the value if it is not supplied in the create request. Even
+ if the client does supply a value for these three attributes in the
+ create request, the Printer object MAY choose to change the value if
+ the Printer object is able to compute a value which is more accurate
+ than the client supplied value. The Printer object may be able to
+ determine the correct value for these three attributes either right
+ at job submission time or at any later point in time.
+
+4.3.18 job-impressions (integer(0:MAX))
+
+ This attribute specifies the total size in number of impressions of
+ the document(s) being submitted (see the definition of impression in
+ section 13.2.5).
+
+ As with "job-k-octets", this value MUST NOT include the
+ multiplicative factors contributed by the number of copies specified
+ by the "copies" attribute, independent of whether the device can
+ process multiple copies without making multiple passes over the job
+ or document data and independent of whether the output is collated or
+ not. Thus the value is independent of the implementation and
+ reflects the size of the document(s) measured in impressions
+ independent of the number of copies.
+
+ As with "job-k-octets", this value MUST also not include the
+ multiplicative factor due to a copies instruction embedded in the
+ document data. If the document data actually includes replications
+ of the document data, this value will include such replication. In
+ other words, this value is always the number of impressions in the
+ source document data, rather than a measure of the number of
+ impressions to be produced by the job.
+
+ See the Note in the "job-k-octets" attribute that also applies to
+ this attribute.
+
+4.3.19 job-media-sheets (integer(0:MAX))
+
+ This attribute specifies the total number of media sheets to be
+ produced for this job.
+
+ Unlike the "job-k-octets" and the "job-impressions" attributes, this
+ value MUST include the multiplicative factors contributed by the
+ number of copies specified by the "copies" attribute and a 'number of
+ copies' instruction embedded in the document data, if any. This
+ difference allows the system administrator to control the lower and
+
+
+
+deBry, et al. Experimental [Page 95]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ upper bounds of both (1) the size of the document(s) with "job-k-
+ octets-supported" and "job-impressions-supported" and (2) the size of
+ the job with "job-media-sheets-supported".
+
+ See the Note in the "job-k-octets" attribute that also applies to
+ this attribute.
+
+4.3.20 job-k-octets-processed (integer(0:MAX))
+
+ This attribute specifies the total number of octets processed in K
+ octets, i.e., in units of 1024 octets so far. The value MUST be
+ rounded up, so that a job between 1 and 1024 octets inclusive MUST be
+ indicated as being 1, 1025 to 2048 inclusive MUST be 2, etc.
+
+ For implementations where multiple copies are produced by the
+ interpreter with only a single pass over the data, the final value
+ MUST be equal to the value of the "job-k-octets" attribute. For
+ implementations where multiple copies are produced by the interpreter
+ by processing the data for each copy, the final value MUST be a
+ multiple of the value of the "job-k-octets" attribute.
+
+ Note: This attribute and the following two attributes ("job-
+ impressions-completed" and "job-sheets-completed") are intended to be
+ counters. That is, the value for a job that has not started
+ processing MUST be 0. When the job's "job-state" is 'processing' or
+ 'processing-stopped', this value is intended to contain the amount of
+ the job that has been processed to the time at which the attributes
+ are requested.
+
+4.3.21 job-impressions-completed (integer(0:MAX))
+
+ This job attribute specifies the number of impressions completed for
+ the job so far. For printing devices, the impressions completed
+ includes interpreting, marking, and stacking the output.
+
+ See the note in "job-k-octets-processed" which also applies to this
+ attribute.
+
+4.3.22 job-media-sheets-completed (integer(0:MAX))
+
+ This job attribute specifies the media-sheets completed marking and
+ stacking for the entire job so far whether those sheets have been
+ processed on one side or on both.
+
+ See the note in "job-k-octets-processed" which also applies to this
+ attribute.
+
+
+
+
+
+deBry, et al. Experimental [Page 96]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+4.3.23 attributes-charset (charset)
+
+ This REQUIRED attribute is populated using the value in the client
+ supplied "attributes-charset" attribute in the create request. It
+ identifies the charset (coded character set and encoding method) used
+ by any Job attributes with attribute syntax 'text' and 'name' that
+ were supplied by the client in the create request. See Section 3.1.4
+ for a complete description of the "attributes-charset" operation
+ attribute.
+
+ This attribute does not indicate the charset in which the 'text' and
+ 'name' values are stored internally in the Job object. The internal
+ charset is implementation-defined. The IPP object MUST convert from
+ whatever the internal charset is to that being requested in an
+ operation as specified in Section 3.1.4.
+
+4.3.24 attributes-natural-language (naturalLanguage)
+
+ This REQUIRED attribute is populated using the value in the client
+ supplied "attributes-natural-language" attribute in the create
+ request. It identifies the natural language used for any Job
+ attributes with attribute syntax 'text' and 'name' that were supplied
+ by the client in the create request. See Section 3.1.4 for a
+ complete description of the "attributes-natural-language" operation
+ attribute. See Sections 4.1.1.2 and 4.1.2.2 for how a Natural
+ Language Override may be supplied explicitly for each 'text' and '
+ name' attribute value that differs from the value identified by the
+ "attributes-natural-language" attribute.
+
+4.4 Printer Description Attributes
+
+ These attributes form the attribute group called "printer-
+ description". The following table summarizes these attributes, their
+ syntax, and whether or not they are REQUIRED for a Printer object to
+ support. If they are not indicated as REQUIRED, they are OPTIONAL.
+ The maximum size in octets for 'text' and 'name' attributes is
+ indicated in parenthesizes.
+
+ Note: How these attributes are set by an Administrator is outside the
+ scope of this specification.
+
+
+
+
+
+
+
+
+
+
+
+deBry, et al. Experimental [Page 97]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ +----------------------------+----------------------+----------------+
+ | Attribute | Syntax | REQUIRED? |
+ +----------------------------+----------------------+----------------+
+ | printer-uri-supported | 1setOf uri | REQUIRED |
+ +----------------------------+----------------------+----------------+
+ | uri-security-supported | 1setOf type2 keyword | REQUIRED |
+ +----------------------------+----------------------+----------------+
+ | printer-name | name (127) | REQUIRED |
+ +----------------------------+----------------------+----------------+
+ | printer-location | text (127) | |
+ +----------------------------+----------------------+----------------+
+ | printer-info | text (127) | |
+ +----------------------------+----------------------+----------------+
+ | printer-more-info | uri | |
+ +----------------------------+----------------------+----------------+
+ | printer-driver-installer | uri | |
+ +----------------------------+----------------------+----------------+
+ | printer-make-and-model | text (127) | |
+ +----------------------------+----------------------+----------------+
+ | printer-more-info- | uri | |
+ | manufacturer | | |
+ +----------------------------+----------------------+----------------+
+ | printer-state | type1 enum | REQUIRED |
+ +----------------------------+----------------------+----------------+
+ | printer-state-reasons | 1setOf type2 keyword | |
+ +----------------------------+----------------------+----------------+
+ | printer-state-message | text (MAX) | |
+ +----------------------------+----------------------+----------------+
+ | operations-supported | 1setOf type2 enum | REQUIRED |
+ +----------------------------+----------------------+----------------+
+ | charset-configured | charset | REQUIRED |
+ +----------------------------+----------------------+----------------+
+ | charset-supported | 1setOf charset | REQUIRED |
+ +----------------------------+----------------------+----------------+
+ | natural-language-configured| naturalLanguage | REQUIRED |
+ +----------------------------+----------------------+----------------+
+ | generated-natural-language-| 1setOf | REQUIRED |
+ | supported | naturalLanguage | |
+ +----------------------------+----------------------+----------------+
+ | document-format-default | mimeMediaType | REQUIRED |
+ +----------------------------+----------------------+----------------+
+ | document-format- | 1setOf | REQUIRED |
+ | supported | mimeMediaType | |
+ +----------------------------+----------------------+----------------+
+ | printer-is-accepting-jobs | boolean | REQUIRED |
+ +----------------------------+----------------------+----------------+
+ | queued-job-count | integer (0:MAX) | RECOMMENDED |
+ +----------------------------+----------------------+----------------+
+
+
+
+deBry, et al. Experimental [Page 98]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ +----------------------------+----------------------+----------------+
+ | Attribute | Syntax | REQUIRED? |
+ +----------------------------+----------------------+----------------+
+ | printer-message-from- | text (127) | |
+ | operator | | |
+ +----------------------------+----------------------+----------------+
+ | color-supported | boolean | |
+ +----------------------------+----------------------+----------------+
+ | reference-uri-schemes- | 1setOf uriScheme | |
+ | supported | | |
+ +----------------------------+----------------------+----------------+
+ | pdl-override-supported | type2 keyword | REQUIRED |
+ +----------------------------+----------------------+----------------+
+ | printer-up-time | integer (1:MAX) | REQUIRED |
+ +----------------------------+----------------------+----------------+
+ | printer-current-time | dateTime | |
+ +----------------------------+----------------------+----------------+
+ | multiple-operation-time-out| integer (1:MAX) | |
+ +----------------------------+----------------------+----------------+
+ | compression-supported | 1setOf type3 keyword | |
+ +----------------------------+----------------------+----------------+
+ | job-k-octets-supported | rangeOfInteger | |
+ | | (0:MAX) | |
+ +----------------------------+----------------------+----------------+
+ | job-impressions-supported | rangeOfInteger | |
+ | | (0:MAX) | |
+ +----------------------------+----------------------+----------------+
+ | job-media-sheets-supported | rangeOfInteger | |
+ | | (0:MAX) | |
+ +----------------------------+----------------------+----------------+
+
+4.4.1 printer-uri-supported (1setOf uri)
+
+ This REQUIRED Printer attribute contains at least one URI for the
+ Printer object. It OPTIONALLY contains more than one URI for the
+ Printer object. An administrator determines a Printer object's
+ URI(s) and configures this attribute to contain those URIs by some
+ means outside the scope of IPP/1.0. The precise format of this URI
+ is implementation dependent and depends on the protocol. See the
+ next section for a description "uri-security-supported" which is the
+ REQUIRED companion attribute to this "printer-uri-supported"
+ attribute. See section 2.4 on Printer object identity and section
+ 8.2 on security and URIs for more information.
+
+
+
+
+
+
+
+
+deBry, et al. Experimental [Page 99]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+4.4.2 uri-security-supported (1setOf type2 keyword)
+
+ This REQUIRED Printer attribute MUST have the same cardinality
+ (contain the same number of values) as the "printer-uri-supported"
+ attribute. This attribute identifies the security mechanisms used
+ for each URI listed in the "printer-uri-supported" attribute. The "i
+ th" value in "uri-security-supported" corresponds to the "i th" value
+ in "printer-uri-supported" and it describes the security mechanisms
+ used for accessing the Printer object via that URI. The following
+ standard values are defined:
+
+ 'none': There are no secure communication channel protocols in use
+ for the given URI.
+
+ 'ssl3': SSL3 [SSL] is the secure communications channel protocol in
+ use for the given URI.
+
+ Consider the following example. For a single Printer object, an
+ administrator configures the "printer-uri-supported" and "uri-
+ security-supported" attributes as follows:
+
+ "printer-uri-supported": 'http://acme.com/open-use-printer', '
+ http://acme.com/restricted-use-printer', '
+ http://acme.com/private-printer'
+ "uri-security-supported": 'none', 'none', 'ssl3'
+
+ In this case, one Printer object has three URIs.
+
+ - For the first URI, 'http://acme.com/open-use-printer', the value
+ 'none' in "uri-security-supported" indicates that there is no
+ secure channel protocol configured to run under HTTP. The name
+ implies that there is no Basic or Digest authentication being
+ used, but it is up to the client to determine that while using
+ HTTP underneath the IPP application protocol.
+ - For the second URI, 'http://acme.com/restricted-use-printer', the
+ value 'none' in "uri-security-supported" indicates that there is
+ no secure channel protocol configured to run under HTTP. In
+ this case, although the name does imply that there is some sort
+ of Basic or Digest authentication being used within HTTP, it is
+ up to the client to determine that while using HTTP and by
+ processing any '401 Unauthorized' HTTP error messages.
+ - For the third URI, 'http://acme.com/private-printer', the value '
+ ssl3' in "uri-security-supported" indicates that SSL3 is being
+ used to secure the channel. The client SHOULD be prepared to
+ use SSL3 framing to negotiate an acceptable ciphersuite to use
+ while communicating with the Printer object. In this case, the
+ name implies the use of a secure communications channel, but the
+ fact is made explicit by the presence of the 'ssl3' value in
+
+
+
+deBry, et al. Experimental [Page 100]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ "uri-security-supported". The client does not need to resort to
+ understanding which security it must use by following naming
+ conventions or by parsing the URI to determine which security
+ mechanisms are implied.
+
+ It is expected that many IPP Printer objects will be configured to
+ support only one channel (either configured to use SSL3 access or
+ not), and will therefore only ever have one URI listed in the
+ "printer-uri-supported" attribute. No matter the configuration of
+ the Printer object (whether it has only one URI or more than one
+ URI), a client MUST supply only one URI in the target "printer-uri"
+ operation attribute.
+
+4.4.3 printer-name (name(127))
+
+ This REQUIRED Printer attribute contains the name of the Printer
+ object. It is a name that is more end-user friendly than a URI. An
+ administrator determines a printer's name and sets this attribute to
+ that name. This name may be the last part of the printer's URI or it
+ may be unrelated. In non-US-English locales, a name may contain
+ characters that are not allowed in a URI.
+
+4.4.4 printer-location (text(127))
+
+ This Printer attribute identifies the location of the device. This
+ could include things like: "in Room 123A, second floor of building
+ XYZ".
+
+4.4.5 printer-info (text(127))
+
+ This Printer attribute identifies the descriptive information about
+ this Printer object. This could include things like: "This printer
+ can be used for printing color transparencies for HR presentations",
+ or "Out of courtesy for others, please print only small (1-5 page)
+ jobs at this printer", or even "This printer is going away on July 1,
+ 1997, please find a new printer".
+
+4.4.6 printer-more-info (uri)
+
+ This Printer attribute contains a URI used to obtain more information
+ about this specific Printer object. For example, this could be an
+ HTTP type URI referencing an HTML page accessible to a Web Browser.
+ The information obtained from this URI is intended for end user
+ consumption. Features outside the scope of IPP can be accessed from
+ this URI. The information is intended to be specific to this printer
+ instance and site specific services (e.g. job pricing, services
+ offered, end user assistance). The device manufacturer may initially
+ populate this attribute.
+
+
+
+deBry, et al. Experimental [Page 101]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+4.4.7 printer-driver-installer (uri)
+
+ This Printer attribute contains a URI to use to locate the driver
+ installer for this Printer object. This attribute is intended for
+ consumption by automata. The mechanics of print driver installation
+ is outside the scope of IPP. The device manufacturer may initially
+ populate this attribute.
+
+4.4.8 printer-make-and-model (text(127))
+
+ This Printer attribute identifies the make and model of the device.
+ The device manufacturer may initially populate this attribute.
+
+4.4.9 printer-more-info-manufacturer (uri)
+
+ This Printer attribute contains a URI used to obtain more information
+ about this type of device. The information obtained from this URI is
+ intended for end user consumption. Features outside the scope of IPP
+ can be accessed from this URI (e.g., latest firmware, upgrades, print
+ drivers, optional features available, details on color support). The
+ information is intended to be germane to this printer without regard
+ to site specific modifications or services. The device manufacturer
+ may initially populate this attribute.
+
+4.4.10 printer-state (type1 enum)
+
+ This REQUIRED Printer attribute identifies the current state of the
+ device. The "printer-state reasons" attribute augments the
+ "printer-state" attribute to give more detailed information about the
+ Printer in the given printer state.
+
+ A Printer object need only update this attribute before responding to
+ an operation which requests the attribute; the Printer object NEED
+ NOT update this attribute continually, since asynchronous event
+ notification is not part of IPP/1.0. A Printer NEED NOT implement
+ all values if they are not applicable to a given implementation.
+
+ The following standard enum values are defined:
+
+ Value Symbolic Name and Description
+
+ '3' 'idle': If a Printer receives a job (whose required
+ resources are ready) while in this state, such a job
+ MUST transit into the 'processing' state immediately.
+ If the "printer-state-reasons" attribute contains any
+ reasons, they MUST be reasons that would not prevent a
+ job from transiting into the 'processing' state
+ immediately, e.g., 'toner-low'. Note: if a Printer
+
+
+
+deBry, et al. Experimental [Page 102]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ controls more than one output device, the above
+ definition implies that a Printer is 'idle' if at
+ least one output device is idle.
+
+ '4' 'processing': If a Printer receives a job (whose required
+ resources are ready) while in this state, such a job
+ MUST transit into the 'pending' state immediately.
+ Such a job MUST transit into the 'processing' state
+ only after jobs ahead of it complete. If the
+ "printer-state-reasons" attribute contains any
+ reasons, they MUST be reasons that do not prevent the
+ current job from printing, e.g. 'toner-low'. Note:
+ if a Printer controls more than one output device, the
+ above definition implies that a Printer is '
+ processing' if at least one output device is
+ processing, and none is idle.
+
+ '5' 'stopped': If a Printer receives a job (whose required
+ resources are ready) while in this state, such a job
+ MUST transit into the 'pending' state immediately.
+ Such a job MUST transit into the 'processing' state
+ only after some human fixes the problem that stopped
+ the printer and after jobs ahead of it complete
+ processing. If supported, the "printer-state-reasons"
+ attribute MUST contain at least one reason, e.g. '
+ media-jam', which prevents it from either processing
+ the current job or transitioning a 'pending' job to
+ the 'processing' state.
+
+ Note: if a Printer controls more than one output
+ device, the above definition implies that a Printer is
+ 'stopped' only if all output devices are stopped.
+ Also, it is tempting to define 'stopped' as when a
+ sufficient number of output devices are stopped and
+ leave it to an implementation to define the sufficient
+ number. But such a rule complicates the definition of
+ 'stopped' and 'processing'. For example, with this
+ alternate definition of 'stopped', a job can move from
+ 'pending' to 'processing' without human intervention,
+ even though the Printer is stopped.
+
+4.4.11 printer-state-reasons (1setOf type2 keyword)
+
+ This Printer attribute supplies additional detail about the device's
+ state.
+
+
+
+
+
+
+deBry, et al. Experimental [Page 103]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ Each keyword value MAY have a suffix to indicate its level of
+ severity. The three levels are: report (least severe), warning, and
+ error (most severe).
+
+ - '-report': This suffix indicates that the reason is a "report".
+ An implementation may choose to omit some or all reports. Some
+ reports specify finer granularity about the printer state;
+ others serve as a precursor to a warning. A report MUST contain
+ nothing that could affect the printed output.
+ - '-warning': This suffix indicates that the reason is a "warning".
+ An implementation may choose to omit some or all warnings.
+ Warnings serve as a precursor to an error. A warning MUST
+ contain nothing that prevents a job from completing, though in
+ some cases the output may be of lower quality.
+ - '-error': This suffix indicates that the reason is an "error".
+ An implementation MUST include all errors. If this attribute
+ contains one or more errors, printer MUST be in the stopped
+ state.
+
+ If the implementation does not add any one of the three suffixes, all
+ parties MUST assume that the reason is an "error".
+
+ If a Printer object controls more than one output device, each value
+ of this attribute MAY apply to one or more of the output devices. An
+ error on one output device that does not stop the Printer object as a
+ whole MAY appear as a warning in the Printer's "printer-state-reasons
+ attribute". If the "printer-state" for such a Printer has a value of
+ 'stopped', then there MUST be an error reason among the values in the
+ "printer-state-reasons" attribute.
+
+ The following standard keyword values are defined:
+
+ 'other': The device has detected an error other than one listed in
+ this document.
+ 'none': There are not reasons. This state reason is semantically
+ equivalent to "printer-state-reasons" without any value.
+ 'media-needed': A tray has run out of media.
+ 'media-jam': The device has a media jam.
+ 'paused': Someone has paused the Printer object. In this state, a
+ Printer MUST NOT produce printed output, but it MUST perform
+ other operations requested by a client. If a Printer had been
+ printing a job when the Printer was paused, the Printer MUST
+ resume printing that job when the Printer is no longer paused
+ and leave no evidence in the printed output of such a pause.
+ 'shutdown': Someone has removed a Printer object from service, and
+ the device may be powered down or physically removed. In this
+ state, a Printer object MUST NOT produce printed output, and
+ unless the Printer object is realized by a print server that is
+
+
+
+deBry, et al. Experimental [Page 104]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ still active, the Printer object MUST perform no other
+ operations requested by a client, including returning this
+ value. If a Printer object had been printing a job when it was
+ shutdown, the Printer NEED NOT resume printing that job when the
+ Printer is no longer shutdown. If the Printer resumes printing
+ such a job, it may leave evidence in the printed output of such
+ a shutdown, e.g. the part printed before the shutdown may be
+ printed a second time after the shutdown.
+ 'connecting-to-device': The Printer object has scheduled a job on
+ the output device and is in the process of connecting to a
+ shared network output device (and might not be able to actually
+ start printing the job for an arbitrarily long time depending on
+ the usage of the output device by other servers on the network).
+ 'timed-out': The server was able to connect to the output device
+ (or is always connected), but was unable to get a response from
+ the output device.
+ 'stopping': The Printer object is in the process of stopping the
+ device and will be stopped in a while. When the device is
+ stopped, the Printer object will change the Printer object's
+ state to 'stopped'. The 'stopping-warning' reason is never an
+ error, even for a Printer with a single output device. When an
+ output-device ceases accepting jobs, the Printer will have this
+ reason while the output device completes printing.
+ 'stopped-partly': When a Printer object controls more than one
+ output device, this reason indicates that one or more output
+ devices are stopped. If the reason is a report, fewer than half
+ of the output devices are stopped. If the reason is a warning,
+ fewer than all of the output devices are stopped.
+ 'toner-low': The device is low on toner.
+ 'toner-empty': The device is out of toner.
+ 'spool-area-full': The limit of persistent storage allocated for
+ spooling has been reached.
+ 'cover-open': One or more covers on the device are open.
+ 'interlock-open': One or more interlock devices on the printer are
+ unlocked.
+ 'door-open': One or more doors on the device are open.
+ 'input-tray-missing': One or more input trays are not in the
+ device.
+ 'media-low': At least one input tray is low on media.
+ 'media-empty': At least one input tray is empty.
+ 'output-tray-missing': One or more output trays are not in the
+ device
+ 'output-area-almost-full': One or more output area is almost full
+ (e.g. tray, stacker, collator).
+ 'output-area-full': One or more output area is full. (e.g. tray,
+ stacker, collator)
+ 'marker-supply-low': The device is low on at least one marker
+ supply. (e.g. toner, ink, ribbon)
+
+
+
+deBry, et al. Experimental [Page 105]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ 'marker-supply-empty: The device is out of at least one marker
+ supply. (e.g. toner, ink, ribbon)
+ 'marker-waste-almost-full': The device marker supply waste
+ receptacle is almost full.
+ 'marker-waste-full': The device marker supply waste receptacle is
+ full.
+ 'fuser-over-temp': The fuser temperature is above normal.
+ 'fuser-under-temp': The fuser temperature is below normal.
+ 'opc-near-eol': The optical photo conductor is near end of life.
+ 'opc-life-over': The optical photo conductor is no longer
+ functioning.
+ 'developer-low': The device is low on developer.
+ 'developer-empty: The device is out of developer.
+ 'interpreter-resource-unavailable': An interpreter resource is
+ unavailable (i.e. font, form)
+
+4.4.12 printer-state-message (text(MAX))
+
+ This Printer attribute specifies the additional information about the
+ printer state and printer state reasons in human readable text. If
+ the Printer object supports this attribute, the Printer object MUST
+ be able to generate this message in any of the natural languages
+ identified by the Printer's "generated-natural-language-supported"
+ attribute (see the "attributes-natural-language" operation attribute
+ specified in Section 3.1.4.1).
+
+4.4.13 operations-supported (1setOf type2 enum)
+
+ This REQUIRED Printer attribute specifies the set of supported
+ operations for this Printer object and contained Job objects. All
+ 32-bit enum values for this attribute MUST NOT exceed 0x8FFF, since
+ these values are passed in two octets in each Protocol request
+ [RFC2565].
+
+ The following standard enum and "operation-id" (see section 3.1.2)
+ values are defined:
+
+ Value Operation Name
+ ----------------- -------------------------------------
+
+ 0x0000 reserved, not used
+ 0x0001 reserved, not used
+ 0x0002 Print-Job
+ 0x0003 Print-URI
+ 0x0004 Validate-Job
+ 0x0005 Create-Job
+ 0x0006 Send-Document
+ 0x0007 Send-URI
+
+
+
+deBry, et al. Experimental [Page 106]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ 0x0008 Cancel-Job
+ 0x0009 Get-Job-Attributes
+ 0x000A Get-Jobs
+ 0x000B Get-Printer-Attributes
+ 0x000C-0x3FFF reserved for future operations
+ 0x4000-0x8FFF reserved for private extensions
+
+ This allows for certain vendors to implement private extensions that
+ are guaranteed to not conflict with future registered extensions.
+ However, there is no guarantee that two or more private extensions
+ will not conflict.
+
+4.4.14 charset-configured (charset)
+
+ This REQUIRED Printer attribute identifies the charset that the
+ Printer object has been configured to represent 'text' and 'name'
+ Printer attributes that are set by the operator, system
+ administrator, or manufacturer, i.e., for "printer-name" (name),
+ "printer-location" (text), "printer-info" (text), and "printer-make-
+ and-model" (text). Therefore, the value of the Printer object's
+ "charset-configured" attribute MUST also be among the values of the
+ Printer object's "charset-supported" attribute.
+
+4.4.15 charset-supported (1setOf charset)
+
+ This REQUIRED Printer attribute identifies the set of charsets that
+ the Printer and contained Job objects support in attributes with
+ attribute syntax 'text' and 'name'. At least the value 'utf-8' MUST
+ be present, since IPP objects MUST support the UTF-8 [RFC2279]
+ charset. If a Printer object supports a charset, it means that for
+ all attributes of syntax 'text' and 'name' the IPP object MUST (1)
+ accept the charset in requests and return the charset in responses as
+ needed.
+
+ If more charsets than UTF-8 are supported, the IPP object MUST
+ perform charset conversion between the charsets as described in
+ Section 3.2.1.2.
+
+4.4.16 natural-language-configured (naturalLanguage)
+
+ This REQUIRED Printer attribute identifies the natural language that
+ the Printer object has been configured to represent 'text' and 'name'
+ Printer attributes that are set by the operator, system
+ administrator, or manufacturer, i.e., for "printer-name" (name),
+ "printer-location" (text), "printer-info" (text), and "printer-make-
+ and-model" (text). When returning these Printer attributes, the
+ Printer object MAY return them in the configured natural language
+ specified by this attribute, instead of the natural language
+
+
+
+deBry, et al. Experimental [Page 107]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ requested by the client in the "attributes-natural-language"
+ operation attribute. See Section 3.1.4.1 for the specification of
+ the OPTIONAL multiple natural language support. Therefore, the value
+ of the Printer object's "natural-language-configured" attribute MUST
+ also be among the values of the Printer object's "generated-natural-
+ language-supported" attribute.
+
+4.4.17 generated-natural-language-supported (1setOf naturalLanguage)
+
+ This REQUIRED Printer attribute identifies the natural language(s)
+ that the Printer object and contained Job objects support in
+ attributes with attribute syntax 'text' and 'name'. The natural
+ language(s) supported depends on implementation and/or configuration.
+ Unlike charsets, IPP objects MUST accept requests with any natural
+ language or any Natural Language Override whether the natural
+ language is supported or not.
+
+ If a Printer object supports a natural language, it means that for
+ any of the attributes for which the Printer or Job object generates
+ messages, i.e., for the "job-state-message" and "printer-state-
+ message" attributes and Operation Messages (see Section 3.1.5) in
+ operation responses, the Printer and Job objects MUST be able to
+ generate messages in any of the Printer's supported natural
+ languages. See section 3.1.4 for the specification of 'text' and '
+ name' attributes in operation requests and responses.
+
+ Note: A Printer object that supports multiple natural languages,
+ often has separate catalogs of messages, one for each natural
+ language supported.
+
+4.4.18 document-format-default (mimeMediaType)
+
+ This REQUIRED Printer attribute identifies the document format that
+ the Printer object has been configured to assume if the client does
+ not supply a "document-format" operation attribute in any of the
+ operation requests that supply document data. The standard values
+ for this attribute are Internet Media types (sometimes called MIME
+ types). For further details see the description of the '
+ mimeMediaType' attribute syntax in Section 4.1.9.
+
+4.4.19 document-format-supported (1setOf mimeMediaType)
+
+ This REQUIRED Printer attribute identifies the set of document
+ formats that the Printer object and contained Job objects can
+ support. For further details see the description of the '
+ mimeMediaType' attribute syntax in Section 4.1.9.
+
+4.4.20 printer-is-accepting-jobs (boolean)
+
+
+
+deBry, et al. Experimental [Page 108]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ This REQUIRED Printer attribute indicates whether the printer is
+ currently able to accept jobs, i.e., is accepting Print-Job, Print-
+ URI, and Create-Job requests. If the value is 'true', the printer is
+ accepting jobs. If the value is 'false', the Printer object is
+ currently rejecting any jobs submitted to it. In this case, the
+ Printer object returns the 'server-error-not-accepting-jobs' status
+ code.
+
+ Note: This value is independent of the "printer-state" and "printer-
+ state-reasons" attributes because its value does not affect the
+ current job; rather it affects future jobs. This attribute may cause
+ the Printer to reject jobs when the "printer-state" is 'idle' or it
+ may cause the Printer object to accepts jobs when the "printer-state"
+ is 'stopped'.
+
+4.4.21 queued-job-count (integer(0:MAX))
+
+ This RECOMMENDED Printer attribute contains a count of the number of
+ jobs that are either 'pending', 'processing', 'pending-held', or '
+ processing-stopped' and is set by the Printer object.
+
+4.4.22 printer-message-from-operator (text(127))
+
+ This Printer attribute provides a message from an operator, system
+ administrator or "intelligent" process to indicate to the end user
+ information or status of the printer, such as why it is unavailable
+ or when it is expected to be available.
+
+4.4.23 color-supported (boolean)
+
+ This Printer attribute identifies whether the device is capable of
+ any type of color printing at all, including highlight color. All
+ document instructions having to do with color are embedded within the
+ document PDL (none are external IPP attributes in IPP/1.0).
+
+ Note: end-users are able to determine the nature and details of the
+ color support by querying the "printer-more-info-manufacturer"
+ Printer attribute.
+
+4.4.24 reference-uri-schemes-supported (1setOf uriScheme)
+
+ This Printer attribute specifies which URI schemes are supported for
+ use in the "document-uri" operation attribute of the Print-URI or
+ Send-URI operation. If a Printer object supports these optional
+ operations, it MUST support the "reference-uri-schemes-supported"
+ Printer attribute with at least the following schemed URI value:
+
+ 'ftp': The Printer object will use an FTP 'get' operation as
+
+
+
+deBry, et al. Experimental [Page 109]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ defined in RFC 2228 [RFC2228] using FTP URLs as defined by
+ [RFC2396] and[RFC2316].
+
+ The Printer object MAY OPTIONALLY support other URI schemes (see
+ section 4.1.6).
+
+4.4.25 pdl-override-supported (type2 keyword)
+
+ This REQUIRED Printer attribute expresses the ability for a
+ particular Printer implementation to either attempt to override
+ document data instructions with IPP attributes or not.
+
+ This attribute takes on the following values:
+
+ - 'attempted': This value indicates that the Printer object
+ attempts to make the IPP attribute values take precedence over
+ embedded instructions in the document data, however there is no
+ guarantee.
+
+ - 'not-attempted': This value indicates that the Printer object
+ makes no attempt to make the IPP attribute values take precedence
+ over embedded instructions in the document data.
+
+ Section 15 contains a full description of how this attribute
+ interacts with and affects other IPP attributes, especially the
+ "ipp-attribute-fidelity" attribute.
+
+4.4.26 printer-up-time (integer(1:MAX))
+
+ This REQUIRED Printer attribute indicates the amount of time (in
+ seconds) that this instance of this Printer implementation has been
+ up and running. This value is used to populate the Job attributes
+ "time-at-creation", "time-at-processing", and "time-at-completed".
+ These time values are all measured in seconds and all have meaning
+ only relative to this attribute, "printer-up-time". The value is a
+ monotonically increasing value starting from 1 when the Printer
+ object is started-up (initialized, booted, etc.).
+
+ If the Printer object goes down at some value 'n', and comes back up,
+ the implementation MAY:
+
+ 1. Know how long it has been down, and resume at some value greater
+ than 'n', or
+ 2. Restart from 1.
+
+ In the first case, the Printer SHOULD not tweak any existing related
+ Job attributes ("time-at-creation", "time-at-processing", and "time-
+ at-completed"). In the second case, the Printer object SHOULD reset
+
+
+
+deBry, et al. Experimental [Page 110]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ those attributes to 0. If a client queries a time-related Job
+ attribute and finds the value to be 0, the client MUST assume that
+ the Job was submitted in some life other than the Printer's current
+ life.
+
+4.4.27 printer-current-time (dateTime)
+
+ This Printer attribute indicates the current absolute wall-clock
+ time. If an implementation supports this attribute, then a client
+ could calculate the absolute wall-clock time each Job's "time-at-
+ creation", "time-at-processing", and "time-at-completed" attributes
+ by using both "printer-up-time" and this attribute, "printer-
+ current-time". If an implementation does not support this attribute,
+ a client can only calculate the relative time of certain events based
+ on the REQUIRED "printer-up-time" attribute.
+
+4.4.28 multiple-operation-time-out (integer(1:MAX))
+
+ This Printer attributes identifies the minimum time (in seconds) that
+ the Printer object waits for additional Send-Document or Send-URI
+ operations to follow a still-open multi-document Job object before
+ taking any recovery actions, such as the ones indicated in section
+ 3.3.1.
+
+ It is RECOMMENDED that vendors supply a value for this attribute that
+ is between 60 and 240 seconds. An implementation MAY allow a system
+ administrator to set this attribute. If so, the system administrator
+ MAY be able to set values outside this range.
+
+4.4.29 compression-supported (1setOf type3 keyword)
+
+ This Printer attribute identifies the set of supported compression
+ algorithms for document data. Compression only applies to the
+ document data; compression does not apply to the encoding of the IPP
+ operation itself. The supported values are used to validate the
+ client supplied "compression" operation attributes in Print-Job,
+ Send-Document, and Send-URI requests.
+
+ Standard values are :
+
+ 'none': no compression is used.
+ 'deflate': ZIP public domain inflate/deflate) compression
+ technology
+ 'gzip' GNU zip compression technology described in RFC 1952
+ [RFC1952].
+ 'compress': UNIX compression technology
+
+4.4.30 job-k-octets-supported (rangeOfInteger(0:MAX))
+
+
+
+deBry, et al. Experimental [Page 111]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ This Printer attribute specifies the upper and lower bounds of total
+ sizes of jobs in K octets, i.e., in units of 1024 octets. The
+ supported values are used to validate the client supplied "job-k-
+ octets" operation attributes in create requests. The corresponding
+ job description attribute "job-k-octets" is defined in section
+ 4.3.17.
+
+ 4.4.31 job-impressions-supported (rangeOfInteger(0:MAX))
+
+ This Printer attribute specifies the upper and lower bounds for the
+ number of impressions per job. The supported values are used to
+ validate the client supplied "job-impressions" operation attributes
+ in create requests. The corresponding job description attribute
+ "job-impressions" is defined in section 4.3.18.
+
+4.4.32 job-media-sheets-supported (rangeOfInteger(0:MAX))
+
+ This Printer attribute specifies the upper and lower bounds for the
+ number of media sheets per job. The supported values are used to
+ validate the client supplied "job-media-sheets" operation attributes
+ in create requests. The corresponding Job attribute "job-media-
+ sheets" is defined in section 4.3.19.
+
+5. Conformance
+
+ This section describes conformance issues and requirements. This
+ document introduces model entities such as objects, operations,
+ attributes, attribute syntaxes, and attribute values. These
+ conformance sections describe the conformance requirements which
+ apply to these model entities.
+
+5.1 Client Conformance Requirements
+
+ A conforming client MUST support all REQUIRED operations as defined
+ in this document. For each attribute included in an operation
+ request, a conforming client MUST supply a value whose type and value
+ syntax conforms to the requirements of the Model document as
+ specified in Sections 3 and 4. A conforming client MAY supply any
+ registered extensions and/or private extensions in an operation
+ request, as long as they meet the requirements in Section 6.
+
+ Otherwise, there are no conformance requirements placed on the user
+ interfaces provided by IPP clients or their applications. For
+ example, one application might not allow an end user to submit
+ multiple documents per job, while another does. One application
+ might first query a Printer object in order to supply a graphical
+ user interface (GUI) dialogue box with supported and default values
+ whereas a different implementation might not.
+
+
+
+deBry, et al. Experimental [Page 112]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ When sending a request, an IPP client NEED NOT supply any attributes
+ that are indicated as OPTIONALLY supplied by the client.
+
+ A client MUST be able to accept any of the attribute syntaxes defined
+ in Section 4.1, including their full range, that may be returned to
+ it in a response from a Printer object. In particular for each
+ attribute that the client supports whose attribute syntax is 'text',
+ the client MUST accept and process both the 'textWithoutLanguage' and
+ 'textWithLanguage' forms. Similarly, for each attribute that the
+ client supports whose attribute syntax is 'name', the client MUST
+ accept and process both the 'nameWithoutLanguage' and '
+ nameWithLanguage' forms. For presentation purposes, truncation of
+ long attribute values is not recommended. A recommended approach
+ would be for the client implementation to allow the user to scroll
+ through long attribute values.
+
+ A query response may contain attribute groups, attributes, and values
+ that the client does not expect. Therefore, a client implementation
+ MUST gracefully handle such responses and not refuse to inter-operate
+ with a conforming Printer that is returning extended registered or
+ private attributes and/or attribute values that conform to Section 6.
+ Clients may choose to ignore any parameters, attributes, or values
+ that they do not understand.
+
+5.2 IPP Object Conformance Requirements
+
+ This section specifies the conformance requirements for conforming
+ implementations with respect to objects, operations, and attributes.
+
+5.2.1 Objects
+
+ Conforming implementations MUST implement all of the model objects as
+ defined in this specification in the indicated sections:
+
+ Section 2.1 - Printer Object
+ Section 2.2 - Job Object
+
+5.2.2 Operations
+
+ Conforming IPP object implementations MUST implement all of the
+ REQUIRED model operations, including REQUIRED responses, as defined
+ in this specification in the indicated sections:
+
+ For a Printer object:
+ Print-Job (section 3.2.1) REQUIRED
+ Print-URI (section 3.2.2) OPTIONAL
+ Validate-Job (section 3.2.3) REQUIRED
+ Create-Job (section 3.2.4) OPTIONAL
+
+
+
+deBry, et al. Experimental [Page 113]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ Get-Printer-Attributes (section 3.2.5) REQUIRED
+ Get-Jobs (section 3.2.6) REQUIRED
+
+ For a Job object:
+ Send-Document (section 3.3.1) OPTIONAL
+ Send-URI (section 3.3.2) OPTIONAL
+ Cancel-Job (section 3.3.3) REQUIRED
+ Get-Job-Attributes (section 3.3.4) REQUIRED
+
+ Conforming IPP objects MUST support all REQUIRED operation attributes
+ and all values of such attributes if so indicated in the description.
+ Conforming IPP objects MUST ignore all unsupported or unknown
+ operation attributes or operation attribute groups received in a
+ request, but MUST reject a request that contains a supported
+ operation attribute that contains an unsupported value.
+
+ The following section on object attributes specifies the support
+ required for object attributes.
+
+5.2.3 IPP Object Attributes
+
+ Conforming IPP objects MUST support all of the REQUIRED object
+ attributes, as defined in this specification in the indicated
+ sections.
+
+ If an object supports an attribute, it MUST support only those values
+ specified in this document or through the extension mechanism
+ described in section 5.2.4. It MAY support any non-empty subset of
+ these values. That is, it MUST support at least one of the specified
+ values and at most all of them.
+
+5.2.4 Extensions
+
+ A conforming IPP object MAY support registered extensions and private
+ extensions, as long as they meet the requirements specified in
+ Section 6.
+
+ For each attribute included in an operation response, a conforming
+ IPP object MUST return a value whose type and value syntax conforms
+ to the requirement of the Model document as specified in Sections 3
+ and 4.
+
+
+
+
+
+
+
+
+
+
+deBry, et al. Experimental [Page 114]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+5.2.5 Attribute Syntaxes
+
+ An IPP object MUST be able to accept any of the attribute syntaxes
+ defined in Section 4.1, including their full range, in any operation
+ in which a client may supply attributes or the system administrator
+ may configure attributes (by means outside the scope of IPP/1.0). In
+ particular for each attribute that the IPP object supports whose
+ attribute syntax is 'text', the IPP object MUST accept and process
+ both the 'textWithoutLanguage' and 'textWithLanguage' forms.
+ Similarly, for each attribute that the IPP object supports whose
+ attribute syntax is 'name', the IPP object MUST accept and process
+ both the 'nameWithoutLanguage' and 'nameWithLanguage' forms.
+ Furthermore, an IPP object MUST return attributes to the client in
+ operation responses that conform to the syntax specified in Section
+ 4.1, including their full range if supplied previously by a client.
+
+5.3 Charset and Natural Language Requirements
+
+ All clients and IPP objects MUST support the 'utf-8' charset as
+ defined in section 4.1.7.
+
+ IPP objects MUST be able to accept any client request which correctly
+ uses the "attributes-natural-language" operation attribute or the
+ Natural Language Override mechanism on any individual attribute
+ whether or not the natural language is supported by the IPP object.
+ If an IPP object supports a natural language, then it MUST be able to
+ translate (perhaps by table lookup) all generated 'text' or 'name'
+ attribute values into one of the supported languages (see section
+ 3.1.4). That is, the IPP object that supports a natural language
+ NEED NOT be a general purpose translator of any arbitrary 'text' or '
+ name' value supplied by the client into that natural language.
+ However, the object MUST be able to translate (automatically
+ generate) any of its own attribute values and messages into that
+ natural language.
+
+5.4 Security Conformance Requirements
+
+ Conforming IPP Printer objects MAY support Secure Socket Layer
+ Version 3 (SSL3) [SSL] access, support access without SSL3 or support
+ both means of access.
+
+ Conforming IPP clients SHOULD support SSL3 access and non-SSL3
+ access. Note: This client requirement to support both means that
+ conforming IPP clients will be able to inter-operate with any IPP
+ Printer object.
+
+
+
+
+
+
+deBry, et al. Experimental [Page 115]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ For a detailed discussion of security considerations and the IPP
+ application security profile required for SSL3 support, see section
+ 8.
+
+6. IANA Considerations (registered and private extensions)
+
+ This section describes how IPP can be extended to allow the following
+ registered and private extensions to IPP:
+
+ 1. keyword attribute values
+ 2. enum attribute values
+ 3. attributes
+ 4. attribute syntaxes
+ 5. operations
+ 6. attribute groups
+ 7. status codes
+
+ Extensions registered for use with IPP/1.0 are OPTIONAL for client
+ and IPP object conformance to the IPP/1.0 Model specification.
+
+ These extension procedures are aligned with the guidelines as set
+ forth by the IESG [RFC2434]. Section 11 describes how to propose new
+ registrations for consideration. IANA will reject registration
+ proposals that leave out required information or do not follow the
+ appropriate format described in Section 11. IPP/1.0 may also be
+ extended by an appropriate RFC that specifies any of the above
+ extensions.
+
+6.1 Typed 'keyword' and 'enum' Extensions
+
+ IPP allows for 'keyword' and 'enum' extensions (see sections 4.1.2.3
+ and 4.1.4). This document uses prefixes to the 'keyword' and 'enum'
+ basic attribute syntax type in order to communicate extra information
+ to the reader through its name. This extra information is not
+ represented in the protocol because it is unimportant to a client or
+ Printer object. The list below describes the prefixes and their
+ meaning.
+
+ "type1": The IPP specification must be revised to add a new
+ keyword or a new enum. No private keywords or enums are
+ allowed.
+
+ "type2": Implementers can, at any time, add new keyword or enum
+ values by proposing the complete specification to IANA:
+
+ iana@iana.org
+
+
+
+
+
+deBry, et al. Experimental [Page 116]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ IANA will forward the registration proposal to the IPP
+ Designated Expert who will review the proposal with a mailing
+ list that the Designated Expert keeps for this purpose.
+ Initially, that list will be the mailing list used by the IPP
+ WG:
+
+ ipp@pwg.org
+
+ even after the IPP WG is disbanded as permitted by [RFC2434].
+ The IPP Designated Expert is appointed by the IESG Area Director
+ responsible for IPP, according to [RFC2434].
+
+ When a type2 keyword or enum is approved, the IPP Designated
+ Expert becomes the point of contact for any future maintenance
+ that might be required for that registration.
+
+ "type3": Implementers can, at any time, add new keyword and enum
+ values by submitting the complete specification to IANA as for
+ type2 who will forward the proposal to the IPP Designated
+ Expert. While no additional technical review is required, the
+ IPP Designated Expert may, at his/her discretion, forward the
+ proposal to the same mailing list as for type2 registrations for
+ advice and comment.
+
+ When a type3 keyword or enum is approved by the IPP Designated
+ Expert, the original proposer becomes the point of contact for
+ any future maintenance that might be required for that
+ registration.
+
+ For type2 and type3 keywords, the proposer includes the name of the
+ keyword in the registration proposal and the name is part of the
+ technical review.
+
+ After type2 and type3 enums specifications are approved, the IPP
+ Designated Expert in consultation with IANA assigns the next
+ available enum number for each enum value.
+
+ IANA will publish approved type2 and type3 keyword and enum
+ attributes value registration specifications in:
+
+ ftp.isi.edu/iana/assignments/ipp/attribute-values/xxx/yyy.txt
+
+ where xxx is the attribute name that specifies the initial values and
+ yyy.txt is a descriptive file name that contains one or more enums or
+ keywords approved at the same time. For example, if several
+ additional enums for stapling are approved for use with the
+
+
+
+
+
+deBry, et al. Experimental [Page 117]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ "finishings" attribute (and "finishings-default" and "finishings-
+ supported" attributes), IANA will publish the additional values in
+ the file:
+
+ ftp.isi.edu/iana/assignments/ipp/attribute-
+ values/finishings/stapling.txt
+
+ Note: Some attributes are defined to be: 'type3 keywords' | 'name'
+ which allows for attribute values to be extended by a site
+ administrator with administrator defined names. Such names are not
+ registered with IANA.
+
+ By definition, each of the three types above assert some sort of
+ registry or review process in order for extensions to be considered
+ valid. Each higher numbered level (1, 2, 3) tends to be decreasingly
+ less stringent than the previous level. Therefore, any typeN value
+ MAY be registered using a process for some typeM where M is less than
+ N, however such registration is NOT REQUIRED. For example, a type3
+ value MAY be registered in a type 1 manner (by being included in a
+ future version of an IPP specification), however, it is NOT REQUIRED.
+
+ This specification defines keyword and enum values for all of the
+ above types, including type3 keywords.
+
+ For private (unregistered) keyword extensions, implementers SHOULD
+ use keywords with a suitable distinguishing prefix, such as "xxx-"
+ where xxx is the (lowercase) fully qualified company name registered
+ with IANA for use in domain names [RFC1035]. For example, if the
+ company XYZ Corp. had obtained the domain name "XYZ.com", then a
+ private keyword 'abc' would be: 'xyz.com-abc'.
+
+ Note: RFC 1035 [RFC1035] indicates that while upper and lower case
+ letters are allowed in domain names, no significance is attached to
+ the case. That is, two names with the same spelling but different
+ case are to be treated as if identical. Also, the labels in a domain
+ name must follow the rules for ARPANET host names: They must start
+ with a letter, end with a letter or digit, and have as interior
+ characters only letters, digits, and hyphen. Labels must be 63
+ characters or less. Labels are separated by the "." character.
+
+ For private (unregistered) enum extension, implementers MUST use
+ values in the reserved integer range which is 2**30 to 2**31-1.
+
+
+
+
+
+
+
+
+
+deBry, et al. Experimental [Page 118]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+6.2 Attribute Extensibility
+
+ Attribute names are type2 keywords. Therefore, new attributes may be
+ registered and have the same status as attributes in this document by
+ following the type2 extension rules. For private (unregistered)
+ attribute extensions, implementers SHOULD use keywords with a
+ suitable distinguishing prefix as described in Section 6.1.
+
+ IANA will publish approved attribute registration specifications as
+ separate files:
+
+ ftp.isi.edu/iana/assignments/ipp/attributes/xxx-yyy.txt
+
+ where "xxx-yyy" is the new attribute name.
+
+ If a new Printer object attribute is defined and its values can be
+ affected by a specific document format, its specification needs to
+ contain the following sentence:
+
+ "The value of this attribute returned in a Get-Printer-Attributes
+ response MAY depend on the "document-format" attribute supplied
+ (see Section 3.2.5.1)."
+
+ If the specification does not, then its value in the Get-Printer-
+ Attributes response MUST NOT depend on the "document-format" supplied
+ in the request. When a new Job Template attribute is registered, the
+ value of the Printer attributes MAY vary with "document-format"
+ supplied in the request without the specification having to indicate
+ so.
+
+6.3 Attribute Syntax Extensibility
+
+ Attribute syntaxes are like type2 enums. Therefore, new attribute
+ syntaxes may be registered and have the same status as attribute
+ syntaxes in this document by following the type2 extension rules
+ described in Section 6.1. The value codes that identify each of the
+ attribute syntaxes are assigned in the Encoding and Transport
+ specification [RFC2565], including a designated range for private,
+ experimental use.
+
+ For attribute syntaxes, the IPP Designated Expert in consultation
+ with IANA assigns the next attribute syntax code in the appropriate
+ range as specified in [RFC2565]. IANA will publish approved
+ attribute syntax registration specifications as separate files:
+
+ ftp.isi.edu/iana/assignments/ipp/attribute-syntaxes/xxx-yyy.txt
+
+ where 'xxx-yyy' is the new attribute syntax name.
+
+
+
+deBry, et al. Experimental [Page 119]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+6.4 Operation Extensibility
+
+ Operations may also be registered following the type2 procedures
+ described in Section 6.1, though major new operations will usually be
+ done by a new standards track RFC that augments this document. For
+ private (unregistered) operation extensions, implementers MUST use
+ the range for the "operation-id" in requests specified in Section
+ 4.4.13 "operations-supported" Printer attribute.
+
+ For operations, the IPP Designated Expert in consultation with IANA
+ assigns the next operation-id code as specified in Section 4.4.13.
+ IANA will publish approved operation registration specifications as
+ separate files:
+
+ ftp.isi.edu/iana/assignments/ipp/operations/Xxx-Yyy.txt
+
+ where "Xxx-Yyy" is the new operation name.
+
+6.5 Attribute Groups
+
+ Attribute groups passed in requests and responses may be registered
+ following the type2 procedures described in Section 6.1. The tags
+ that identify each of the attribute groups are assigned in [RFC2565].
+
+ For attribute groups, the IPP Designated Expert in consultation with
+ IANA assigns the next attribute group tag code in the appropriate
+ range as specified in [RFC2565]. IANA will publish approved
+ attribute group registration specifications as separate files:
+
+ ftp.isi.edu/iana/assignments/ipp/attribute-group-tags/xxx-yyy-
+ tag.txt
+
+ where 'xxx-yyy-tag' is the new attribute group tag name.
+
+6.6 Status Code Extensibility
+
+ Operation status codes may also be registered following the type2
+ procedures described in Section 6.1. The values for status codes are
+ allocated in ranges as specified in Section 13 for each status code
+ class:
+
+ "informational" - Request received, continuing process
+ "successful" - The action was successfully received, understood,
+ and accepted
+ "redirection" - Further action must be taken in order to complete
+ the request
+ "client-error" - The request contains bad syntax or cannot be
+ fulfilled
+
+
+
+deBry, et al. Experimental [Page 120]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ "server-error" - The IPP object failed to fulfill an apparently
+ valid request
+
+ For private (unregistered) operation status code extensions,
+ implementers MUST use the top of each range as specified in Section
+ 13.
+
+ For operation status codes, the IPP Designated Expert in consultation
+ with IANA assigns the next status code in the appropriate class range
+ as specified in Section 13. IANA will publish approved status code
+ registration specifications as separate files:
+
+ ftp.isi.edu/iana/assignments/ipp/status-codes/xxx-yyy.txt
+
+ where "xxx-yyy" is the new operation status code keyword.
+
+6.7 Registration of MIME types/sub-types for document-formats
+
+ The "document-format" attribute's syntax is 'mimeMediaType'. This
+ means that valid values are Internet Media Types (see Section 4.1.9).
+ RFC 2045 [RFC2045] defines the syntax for valid Internet media types.
+ IANA is the registry for all Internet media types.
+
+6.8 Registration of charsets for use in 'charset' attribute values
+
+ The "attributes-charset" attribute's syntax is 'charset'. This means
+ that valid values are charsets names. When a charset in the IANA
+ registry has more than one name (alias), the name labeled as
+ "(preferred MIME name)", if present, MUST be used (see Section
+ 4.1.7). IANA is the registry for charsets following the procedures
+ of [RFC2278].
+
+7. Internationalization Considerations
+
+ Some of the attributes have values that are text strings and names
+ which are intended for human understanding rather than machine
+ understanding (see the 'text' and 'name' attribute syntaxes in
+ Sections 4.1.1 and 4.1.2).
+
+ In each operation request, the client
+
+ - identifies the charset and natural language of the request which
+ affects each supplied 'text' and 'name' attribute value, and
+ - requests the charset and natural language for attributes returned
+ by the IPP object in operation responses (as described in Section
+ 3.1.4.1).
+
+
+
+
+
+deBry, et al. Experimental [Page 121]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ In addition, the client MAY separately and individually identify the
+ Natural Language Override of a supplied 'text' or 'name' attribute
+ using the 'textWithLanguage' and 'nameWithLanguage' technique
+ described section 4.1.1.2 and 4.1.2.2 respectively.
+
+ All IPP objects MUST support the UTF-8 [RFC2279] charset in all '
+ text' and 'name' attributes supported. If an IPP object supports
+ more than the UTF-8 charset, the object MUST convert between them in
+ order to return the requested charset to the client according to
+ Section 3.1.4.2. If an IPP object supports more than one natural
+ language, the object SHOULD return 'text' and 'name' values in the
+ natural language requested where those values are generated by the
+ Printer (see Section 3.1.4.1).
+
+ For Printers that support multiple charsets and/or multiple natural
+ languages in 'text' and 'name' attributes, different jobs may have
+ been submitted in differing charsets and/or natural languages. All
+ responses MUST be returned in the charset requested by the client.
+ However, the Get-Jobs operation uses the 'textWithLanguage' and '
+ nameWithLanguage' mechanism to identify the differing natural
+ languages with each job attribute returned.
+
+ The Printer object also has configured charset and natural language
+ attributes. The client can query the Printer object to determine
+ the list of charsets and natural languages supported by the Printer
+ object and what the Printer object's configured values are. See the
+ "charset-configured", "charset-supported", "natural-language-
+ configured", and "generated-natural-language-supported" Printer
+ description attributes for more details.
+
+ The "charset-supported" attributed identifies the supported charsets.
+ If a charset is supported, the IPP object MUST be capable of
+ converting to and from that charset into any other supported charset.
+ In many cases, an IPP object will support only one charset and it
+ MUST be the UTF-8 charset.
+
+ The "charset-configured" attribute identifies the one supported
+ charset which is the native charset given the current configuration
+ of the IPP object (administrator defined).
+
+ The "generated-natural-language-supported" attribute identifies the
+ set of supported natural languages for generated messages; it is not
+ related to the set of natural languages that must be accepted for
+ client supplied 'text' and 'name' attributes. For client supplied '
+ text' and 'name' attributes, an IPP object MUST accept ALL supplied
+ natural languages. Just because a Printer object is currently
+
+
+
+
+
+deBry, et al. Experimental [Page 122]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ configured to support 'en-us' natural language does not mean that the
+ Printer object should reject a job if the client supplies a job name
+ that is in 'fr-ca'.
+
+ The "natural-language-configured" attribute identifies the one
+ supported natural language for generated messages which is the native
+ natural language given the current configuration of the IPP object
+ (administrator defined).
+
+ Attributes of type 'text' and 'name' are populated from different
+ sources. These attributes can be categorized into following groups
+ (depending on the source of the attribute):
+
+ 1. Some attributes are supplied by the client (e.g., the client
+ supplied "job-name", "document-name", and "requesting-user-name"
+ operation attributes along with the corresponding Job object's
+ "job-name" and "job-originating-user-name" attributes). The IPP
+ object MUST accept these attributes in any natural language no
+ matter what the set of supported languages for generated
+ messages
+ 2. Some attributes are supplied by the system administrator (e.g.,
+ the Printer object's "printer-name" and "printer-location"
+ attributes). These too can be in any natural language. If the
+ natural language for these attributes is different than what a
+ client requests, then they must be reported using the Natural
+ Language Override mechanism.
+ 3. Some attributes are supplied by the device manufacturer (e.g.,
+ the Printer object's "printer-make-and-model" attribute). These
+ too can be in any natural language. If the natural language for
+ these attributes is different than what a client requests, then
+ they must be reported using the Natural Language Override
+ mechanism.
+ 4. Some attributes are supplied by the operator (e.g., the Job
+ object's "job-message-from-operator" attribute). These too can
+ be in any natural language. If the natural language for these
+ attributes is different than what a client requests, then they
+ must be reported using the Natural Language Override mechanism.
+ 5. Some attributes are generated by the IPP object (e.g., the Job
+ object's "job-state-message" attribute, the Printer object's
+ "printer-state-message" attribute, and the "status-message"
+ operation attribute). These attributes can only be in one of
+ the "generated-natural-language-supported" natural languages.
+ If a client requests some natural language for these attributes
+ other than one of the supported values, the IPP object SHOULD
+ respond using the value of the "natural-language-configured"
+ attribute (using the Natural Language Override mechanism if
+ needed).
+
+
+
+
+deBry, et al. Experimental [Page 123]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ The 'text' and 'name' attributes specified in this version of this
+ document (additional ones will be registered according to the
+ procedures in Section 6) are:
+
+ Attributes Source
+ -------------------------- ----------
+ Operation Attributes
+ job-name (name) client
+ document-name (name) client
+ requesting-user-name (name) client
+ status-message Job or Printer object
+
+ Job Template Attributes:
+ job-hold-until) client matches administrator-configured
+ (keyword | name
+ job-hold-until-default client matches administrator-configured
+ (keyword | name)
+ job-hold-until-supported client matches administrator-configured
+ (keyword | name)
+ job-sheets client matches administrator-configured
+ (keyword | name)
+ job-sheets-default client matches administrator-configured
+ (keyword | name)
+ job-sheets-supported client matches administrator-configured
+ (keyword | name)
+ media client matches administrator-configured
+ (keyword | name)
+ media-default client matches administrator-configured
+ (keyword | name)
+ media-supported client matches administrator-configured
+ (keyword | name)
+ media-ready client matches administrator-configured
+ (keyword | name)
+
+ Job Description Attributes:
+ job-name (name) client or Printer object
+ job-originating-user-name (name) Printer object
+ job-state-message (text) Job or Printer object
+ output-device-assigned (name(127)) administrator
+ job-message-from-operator (text(127)) operator
+
+ Printer Description Attributes:
+ printer-name (name(127)) administrator
+ printer-location (text(127)) administrator
+ printer-info (text(127)) administrator
+ printer-make-and-model (text(127)) administrator or manufacturer
+ printer-state-message (text) Printer object
+ printer-message-from-operator (text(127)) operator
+
+
+
+deBry, et al. Experimental [Page 124]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+8. Security Considerations
+
+ Some IPP objects MAY be deployed over protocol stacks that support
+ Secure Socket Layer Version 3 (SSL3) [SSL]. Note: SSL3 is not an
+ IETF standards track specification. Other IPP objects MAY be
+ deployed over protocol stacks that do not support SSL3. Some IPP
+ objects MAY be deployed over both types of protocol stacks. Those
+ IPP objects that support SSL3, are capable of supporting mutual
+ authentication as well as privacy of messages via multiple encryption
+ schemes. An important point about security related information for
+ SSL3 access to an IPP object, is that the security-related parameters
+ (authentication, encryption keys, etc.) are "out-of-band" to the
+ actual IPP protocol.
+
+ An IPP object that does not support SSL3 MAY elect to support a
+ transport layer that provides other security mechanisms. For
+ example, in a mapping of IPP over HTTP/1.1 [RFC2565], if the IPP
+ object does not support SSL3, HTTP still allows for client
+ authentication using Digest Access Authentication (DAA) [RFC2069].
+
+ It is difficult to anticipate the security risks that might exist in
+ any given IPP environment. For example, if IPP is used within a given
+ corporation over a private network, the risks of exposing document
+ data may be low enough that the corporation will choose not to use
+ encryption on that data. However, if the connection between the
+ client and the IPP object is over a public network, the client may
+ wish to protect the content of the information during transmission
+ through the network with encryption.
+
+ Furthermore, the value of the information being printed may vary from
+ one IPP environment to the next. Printing payroll checks, for
+ example, would have a different value than printing public
+ information from a file. There is also the possibly of denial-of-
+ service attacks, but denial-of-service attacks against printing
+ resources are not well understood and there is no published
+ precedents regarding this scenario.
+
+ Once the authenticated identity of the requester has been supplied to
+ the IPP object, the object uses that identity to enforce any
+ authorization policy that might be in place. For example, one site's
+ policy might be that only the job owner is allowed to cancel a job.
+ The details and mechanisms to set up a particular access control
+ policy are not part of IPP/1.0, and must be established via some
+ other type of administrative or access control framework. However,
+ there are operation status codes that allow an IPP server to return
+ information back to a client about any potential access control
+ violations for an IPP object.
+
+
+
+
+deBry, et al. Experimental [Page 125]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ During a create operation, the client's identity is recorded in the
+ Job object in an implementation-defined attribute. This information
+ can be used to verify a client's identity for subsequent operations
+ on that Job object in order to enforce any access control policy that
+ might be in effect. See section 8.3 below for more details.
+
+ Since the security levels or the specific threats that any given IPP
+ system administrator may be concerned with cannot be anticipated, IPP
+ MUST be capable of operating with different security mechanisms and
+ security policies as required by the individual installation.
+ Security policies might vary from very strong, to very weak, to none
+ at all, and corresponding security mechanisms will be required. SSL3
+ supports the type of negotiated levels of security required by most,
+ if not all, potential IPP environments. IPP environments that require
+ no security can elect to deploy IPP objects that do not utilize the
+ optional SSL3 security mechanisms.
+
+8.1 Security Scenarios
+
+ The following sections describe specific security attacks for IPP
+ environments. Where examples are provided they should be considered
+ illustrative of the environment and not an exhaustive set. Not all of
+ these environments will necessarily be addressed in initial
+ implementations of IPP.
+
+8.1.1 Client and Server in the Same Security Domain
+
+ This environment is typical of internal networks where traditional
+ office workers print the output of personal productivity applications
+ on shared work-group printers, or where batch applications print
+ their output on large production printers. Although the identity of
+ the user may be trusted in this environment, a user might want to
+ protect the content of a document against such attacks as
+ eavesdropping, replaying or tampering.
+
+8.1.2 Client and Server in Different Security Domains
+
+ Examples of this environment include printing a document created by
+ the client on a publicly available printer, such as at a commercial
+ print shop; or printing a document remotely on a business associate's
+ printer. This latter operation is functionally equivalent to sending
+ the document to the business associate as a facsimile. Printing
+ sensitive information on a Printer in a different security domain
+ requires strong security measures. In this environment authentication
+ of the printer is required as well as protection against unauthorized
+ use of print resources. Since the document crosses security domains,
+
+
+
+
+
+deBry, et al. Experimental [Page 126]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ protection against eavesdropping and document tampering are also
+ required. It will also be important in this environment to protect
+ Printers against "spamming" and malicious document content.
+
+8.1.3 Print by Reference
+
+ When the document is not stored on the client, printing can be done
+ by reference. That is, the print request can contain a reference, or
+ pointer, to the document instead of the actual document itself.
+ Standard methods currently do not exist for remote entities to
+ "assume" the credentials of a client for forwarding requests to a 3rd
+ party. It is anticipated that Print-By-Reference will be used to
+ access "public" documents and that sophisticated methods for
+ authenticating "proxies" will not be specified for version 1 of IPP.
+
+8.2 URIs for SSL3 and non-SSL3 Access
+
+ As described earlier, an IPP object can support SSL3 access, non-SSL3
+ access, or both. The "printer-uri-supported" attribute contains the
+ Printer object's URI(s). Its companion attribute, "uri-security-
+ supported", identifies the security mechanism used for each URI
+ listed in the "printer-uri-supported" attribute. For each Printer
+ operation request, a client MUST supply only one URI in the
+ "printer-uri" operation attribute. In other words, even though the
+ Printer supports more than one URI, the client only interacts with
+ the Printer object using one if its URIs. This duality is not needed
+ for Job objects, since the Printer objects is the factory for Job
+ objects, and the Printer object will generate the correct URI for new
+ Job objects depending on the Printer object's security configuration.
+
+8.3 The "requesting-user-name" (name(MAX)) Operation Attribute
+
+ Each operation MUST specify the user who is performing the operation
+ in both of the following two ways:
+
+ 1) via the REQUIRED "requesting-user-name" operation attribute that
+ a client SHOULD supply in all operations. The client MUST obtain
+ the value for this attribute from an environmental or network
+ login name for the user, rather than allowing the user to supply
+ any value. If the client does not supply a value for
+ "requesting-user-name", the printer MUST assume that the client
+ is supplying some anonymous name, such as "anonymous".
+ 2) via an authentication mechanism of the underlying transport
+ which may be configured to give no authentication information.
+
+
+
+
+
+
+
+deBry, et al. Experimental [Page 127]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ There are six cases to consider:
+
+ a) the authentication mechanism gives no information, and the
+ client doesn't specify "requesting-user-name".
+ b) the authentication mechanism gives no information, but the
+ client specifies "requesting-user-name".
+ c) the authentication mechanism specifies a user which has no human
+ readable representation, and the client doesn't specify
+ "requesting-user-name".
+ d) the authentication mechanism specifies a user which has no human
+ readable representation, but the client specifies "requesting-
+ user-name".
+ e) the authentication mechanism specifies a user which has a human
+ readable representation. The Printer object ignores the
+ "requesting-user-name".
+ f) the authentication mechanism specifies a user who is trusted and
+ whose name means that the value of the "requesting-user-name",
+ which MUST be present, is treated as the authenticated name.
+
+ Note: Case "f" is intended for a tightly coupled gateway and server
+ to work together so that the "user" name is able to be that of the
+ gateway client and not that of the gateway. Because most, if not
+ all, system vendors will initially implement IPP via a gateway into
+ their existing print system, this mechanism is necessary unless the
+ authentication mechanism allows a gateway (client) to act on behalf
+ of some other client.
+
+ The user-name has two forms:
+
+ - one that is human readable: it is held in the REQUIRED "job-
+ originating-user-name" Job Description attribute which is set
+ during the job creation operations. It is used for presentation
+ only, such as returning in queries or printing on start sheets
+ - one for authorization: it is held in an undefined (by IPP) Job
+ object attribute which is set by the job creation operation. It
+ is used to authorize other operations, such as Send-Document,
+ Send-URI, Cancel-Job, to determine the user when the "my-jobs"
+ attribute is specified with Get-Jobs, and to limit what
+ attributes and values to return with Get-Job-Attributes and Get-
+ Jobs.
+
+ The human readable user name:
+
+ - is the value of the "requesting-user-name" for cases b, d and f.
+ - comes from the authentication mechanism for case e
+ - is some anonymous name, such as "anonymous" for cases a and c.
+
+ The user name used for authorization:
+
+
+
+deBry, et al. Experimental [Page 128]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ - is the value of the "requesting-user-name" for cases b and f.
+ - comes from the authentication mechanism for cases c, d and e
+ - is some anonymous name, such as "anonymous" for case a.
+
+ The essence of these rules for resolving conflicting sources of
+ user-names is that a printer implementation is free to pick either
+ source as long as it achieves consistent results. That is, if a user
+ uses the same path for a series of requests, the requests MUST appear
+ to come from the same user from the standpoint of both the human-
+ readable user name and the user name for authorization. This rule
+ MUST continue to apply even if a request could be authenticated by
+ two or more mechanisms. It doesn't matter which of several
+ authentication mechanisms a Printer uses as long as it achieves
+ consistent results. If a client uses more than one authentication
+ mechanism, it is recommended that an administrator make all
+ credentials resolve to the same user and user-name as much as
+ possible.
+
+8.4 Restricted Queries
+
+ In many IPP operations, a client supplies a list of attributes to be
+ returned in the response. For security reasons, an IPP object may be
+ configured not to return all attributes (or all values) that a client
+ requests. The job attributes returned MAY depend on whether the
+ requesting user is the same as the user that submitted the job. The
+ IPP object MAY even return none of the requested attributes. In such
+ cases, the status returned is the same as if the object had returned
+ all requested attributes. The client cannot tell by such a response
+ whether the requested attribute was present or absent on the object.
+
+8.5 Queries on jobs submitted using non-IPP protocols
+
+ If the device that an IPP Printer is representing is able to accept
+ jobs using other job submission protocols in addition to IPP, it is
+ RECOMMENDED that such an implementation at least allow such "foreign"
+ jobs to be queried using Get-Jobs returning "job-id" and "job-uri" as
+ 'unknown'. Such an implementation NEED NOT support all of the same
+ IPP job attributes as for IPP jobs. The IPP object returns the '
+ unknown' out-of-band value for any requested attribute of a foreign
+ job that is supported for IPP jobs, but not for foreign jobs.
+
+ It is further RECOMMENDED, that the IPP Printer generate "job-id" and
+ "job-uri" values for such "foreign jobs", if possible, so that they
+ may be targets of other IPP operations, such as Get-Job-Attributes
+ and Cancel-Job. Such an implementation also needs to deal with the
+ problem of authentication of such foreign jobs. One approach would
+ be to treat all such foreign jobs as belonging to users other than
+ the user of the IPP client. Another approach would be for the
+
+
+
+deBry, et al. Experimental [Page 129]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ foreign job to belong to 'anonymous'. Only if the IPP client has
+ been authenticated as an operator or administrator of the IPP Printer
+ object, could the foreign jobs be queried by an IPP request.
+ Alternatively, if the security policy is to allow users to query
+ other users' jobs, then the foreign jobs would also be visible to an
+ end-user IPP client using Get-Jobs and Get-Job-Attributes.
+
+8.6 IPP Security Application Profile for SSL3
+
+ The IPP application profile for SSL3 follows the "Secure Socket
+ Layer" requirement as documented in the SSL3 specification [SSL].
+ For interoperability, the SSL3 cipher suites are:
+
+ SSL_RSA_WITH_RC4_128_MD5
+ SSL_RSA_WITH_3DES_EDE_CBC_SHA
+ SSL_RSA_WITH_DES_CBC_SHA
+ SSL_RSA_EXPORT_WITH_RC4_40_MD5
+ SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5
+ SSL_RSA_WITH_NULL_MD5
+
+ Client implementations MUST NOT assume any other cipher suites are
+ supported by an IPP Printer object.
+
+ If a conforming IPP object supports SSL3, it MUST implement and
+ support the cipher suites listed above and MAY support additional
+ cipher suites.
+
+ A conforming IPP client SHOULD support SSL3 including the cipher
+ suites listed above. A conforming IPP client MAY support additional
+ cipher suites.
+
+ It is possible that due to certain government export restrictions
+ some non-compliant versions of this extension could be deployed.
+ Implementations wishing to inter-operate with such non-compliant
+ versions MAY offer the SSL_RSA_EXPORT_WITH_RC4_40_MD5 and
+ SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5 mechanisms. However, since 40 bit
+ ciphers are known to be vulnerable to attack by current technology,
+ any client which actives a 40 bit cipher MUST NOT indicate to the
+ user that the connection is completely secure from eavesdropping.
+
+
+
+
+
+
+
+
+
+
+
+
+deBry, et al. Experimental [Page 130]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+9. References
+
+ [ASCII] Coded Character Set - 7-bit American Standard Code for
+ Information Interchange (ASCII), ANSI X3.4-1986. This
+ standard is the specification of the US-ASCII charset.
+
+ [HTPP] J. Barnett, K. Carter, R. DeBry, "Initial Draft -
+ Hypertext Printing Protocol - HTPP/1.0", October 1996.
+ ftp://ftp.pwg.org/pub/pwg/ipp/historic/htpp/
+ overview.ps.gz
+
+ [IANA-CS] IANA Registry of Coded Character Sets:
+ ftp://ftp.isi.edu/in-notes/iana/assignments/character-
+ sets
+
+ [IANA-MT] IANA Registry of Media Types: ftp://ftp.isi.edu/in-
+ notes/iana/assignments/media-types/
+
+ [ipp-iig] Hastings, T. and C. Manros, "Internet Printing
+ Protocol/1.0: Implementer's Guide", Work in Progress.
+
+ [ISO10646-1] ISO/IEC 10646-1:1993, "Information technology --
+ Universal Multiple-Octet Coded Character Set (UCS) -
+ Part 1: Architecture and Basic Multilingual Plane,
+ JTC1/SC2."
+
+ [ISO8859-1] ISO/IEC 8859-1:1987, "Information technology -- 8-bit
+ One-Byte Coded Character Set - Part 1: Latin Alphabet Nr
+ 1", 1987, JTC1/SC2.
+
+ [ISO10175] ISO/IEC 10175 Document Printing Application (DPA), June
+ 1996.
+
+ [LDPA] T. Hastings, S. Isaacson, M. MacKay, C. Manros, D. Taylor, P.
+ Zehler, "LDPA - Lightweight Document Printing
+ Application", October 1996,
+ ftp://ftp.pwg.org/pub/pwg/ipp/historic/ldpa/ldpa8.pdf.gz
+
+ [P1387.4] Kirk, M. (Editor), POSIX System Administration - Part 4:
+ Printing Interfaces, POSIX 1387.4 D8, 1994.
+
+ [PSIS] Herriot, R. (editor), X/Open A Printing System
+ Interoperability Specification (PSIS), August 1995.
+
+ [PWG] Printer Working Group, http://www.pwg.org.
+
+ [RFC1035] Mockapetris, P., "DOMAIN NAMES - IMPLEMENTATION AND
+ SPECIFICATION", STD 13, RFC 1035, November 1987.
+
+
+
+deBry, et al. Experimental [Page 131]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ [RFC1759] Smith, R., Wright, F., Hastings, T., Zilles, S. and J.
+ Gyllenskog, "Printer MIB", RFC 1759, March 1995.
+
+ [RFC1766] Alvestrand, H., "Tags for the Identification of
+ Languages", RFC 1766, March 1995.
+
+ [RFC1179] McLaughlin, L. (Editor), "Line Printer Daemon Protocol",
+ RFC 1179, August 1990.
+
+ [RFC1952] Deutsch, P., "GZIP file format specification version
+ 4.3", RFC 1952, May 1996.
+
+ [RFC2045] Freed, N. and N. Borenstein, " Multipurpose Internet
+ Mail Extensions (MIME) Part One: Format of Internet
+ Message Bodies", RFC 2045, November 1996.
+
+ [RFC2046] Freed, N. and N. Borenstein, "Multipurpose Internet Mail
+ Extensions (MIME) Part Two: Media Types", RFC 2046,
+ November 1996.
+
+ [RFC2048] Freed, N., Klensin, J. and J. Postel, "Multipurpose
+ Internet Mail Extension (MIME) Part Four: Registration
+ Procedures", RFC 2048, November 1996.
+
+ [RFC2068] Fielding, R., Gettys, J., Mogul, J., Frystyk, H. AND T.
+ Berners-Lee, "Hypertext Transfer Protocol - HTTP/1.1",
+ RFC 2068, January 1997.
+
+ [RFC2069] Franks, J., Hallam-Baker, P., Hostetler, J., Leach, P.,
+ Luotonen, A., Sink, E. and L. Stewart, "An Extension to
+ HTTP: Digest Access Authentication", RFC 2069, January
+ 1997.
+
+ [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+ [RFC2228] Horowitz, M. and S. Lunt, "FTP Security Extensions", RFC
+ 2228, October 1997.
+
+ [RFC2277] Alvestrand, H., "IETF Policy on Character Sets and
+ Languages" RFC 2277, January 1998.
+
+ [RFC2278] Freed, N. and J. Postel: "IANA Charset Registration
+ Procedures", BCP 19, RFC 2278, January 1998.
+
+ [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO
+ 10646", RFC 2279, January 1998.
+
+
+
+
+deBry, et al. Experimental [Page 132]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ [RFC2316] Bellovin, S., "Report of the IAB Security Architecture
+ Workshop", RFC 2316, April 1998.
+
+ [RFC2396] Berners-Lee, T., Fielding, R. and L. Masinter, "Uniform
+ Resource Identifiers (URI): Generic Syntax", RFC 2396,
+ August 1998.
+
+ [RFC2434] Narten, T. and H. Alvestrand, "Guidelines for Writing an
+ IANA Considerations Section in RFCs", BCP 26, RFC 2434,
+ October 1998.
+
+ [RFC2565] Herriot, R., Butler, S., Moore, P. and R. Tuner
+ "Internet Printing Protocol/1.0: Encoding and
+ Transport", RFC 2565, April 1999.
+
+ [RFC2567] Wright, D., "Design Goals for an Internet Printing
+ Protocol", RFC 2567, April 1999.
+
+ [RFC2568] Zilles, S., "Rationale for the Structure and Model and
+ Protocol for the Internet Printing Protocol", RFC 2568,
+ April 1999.
+
+ [RFC2569] Herriot, R., Hastings, T., Jacobs, N. and J. Martin,
+ "Mapping between LPD and IPP Protocols", RFC 2569, April
+ 1999.
+
+ [RFC2579] McCloghrie, K., Perkins, D. and J. Schoenwaelder,
+ "Textual Conventions for SMIv2", STD 58, RFC 2579, April
+ 1999.
+
+ [SSL] Netscape, The SSL Protocol, Version 3, (Text version
+ 3.02), November 1996.
+
+ [SWP] P. Moore, B. Jahromi, S. Butler, "Simple Web Printing
+ SWP/1.0", May 7, 1997,
+ ftp://ftp.pwg.org/pub/pwg/ipp/new_PRO/swp9705.pdf
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+deBry, et al. Experimental [Page 133]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+10. Authors' Addresses
+
+ Scott A. Isaacson (Editor)
+ Novell, Inc.
+ 122 E 1700 S
+ Provo, UT 84606
+
+ Phone: 801-861-7366
+ Fax: 801-861-2517
+ EMail: sisaacson@novell.com
+
+
+ Tom Hastings
+ Xerox Corporation
+ 737 Hawaii St.
+ El Segundo, CA 90245
+
+ Phone: 310-333-6413
+ Fax: 310-333-5514
+ EMail: hastings@cp10.es.xerox.com
+
+
+ Robert Herriot
+ Xerox Corporation
+ 3400 Hillview Ave., Bldg #1
+ Palo Alto, CA 94304
+
+ Phone: 650-813-7696
+ Fax: 650-813-6860
+ EMail: robert.herriot@pahv.xerox.com
+
+
+ Roger deBry
+ Utah Valley State College
+ Orem, UT 84058
+
+ Phone: (801) 222-8000
+ EMail: debryro@uvsc.edu
+
+
+
+
+
+
+
+
+
+
+
+
+
+deBry, et al. Experimental [Page 134]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ Patrick Powell
+ Astart Technologies
+ 9475 Chesapeake Dr., Suite D
+ San Diego, CA 95123
+
+ Phone: (619) 874-6543
+ Fax: (619) 279-8424
+ EMail: papowell@astart.com
+
+ IPP Mailing List: ipp@pwg.org
+ IPP Mailing List Subscription: ipp-request@pwg.org
+ IPP Web Page: http://www.pwg.org/ipp/
+
+ Implementers of this specification are encouraged to join IPP Mailing
+ List in order to participate in any discussions of clarification
+ issues and review of registration proposals for additional attributes
+ and values.
+
+ Other Participants:
+
+ Chuck Adams - Tektronix
+ Jeff Barnett - IBM
+ Ron Bergman - Dataproducts Corp.
+ Sylvan Butler - HP
+ Keith Carter - IBM Corporation
+ Jeff Copeland - QMS
+ Andy Davidson - Tektronix
+ Mabry Dozier - QMS
+ Lee Farrell - Canon Information Systems
+ Steve Gebert - IBM
+ Babek Jahromi - Microsoft
+ David Kellerman - Northlake Software
+ Rick Landau - Digital
+ Greg LeClair - Epson
+ Harry Lewis - IBM
+ Pete Loya - HP
+ Ray Lutz - Cognisys
+ Mike MacKay - Novell, Inc.
+ Daniel Manchala - Xerox
+ Carl-Uno Manros - Xerox
+ Jay Martin - Underscore
+ Larry Masinter - Xerox
+ Stan McConnell - Xerox
+ Ira McDonald - High North Inc.
+ Paul Moore - Microsoft
+ Tetsuya Morita - Ricoh
+ Yuichi Niwa - Ricoh
+ Pat Nogay - IBM
+
+
+
+deBry, et al. Experimental [Page 135]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ Ron Norton - Printronics
+ Bob Pentecost - HP
+ Rob Rhoads - Intel
+ Xavier Riley - Xerox
+ David Roach - Unisys
+ Stuart Rowley - Kyocera
+ Hiroyuki Sato - Canon
+ Bob Setterbo - Adobe
+ Devon Taylor - Novell, Inc.
+ Mike Timperman - Lexmark
+ Randy Turner - Sharp
+ Atsushi Yuki - Kyocera
+ Rick Yardumian - Xerox
+ Lloyd Young - Lexmark
+ Bill Wagner - DPI
+ Jim Walker - DAZEL
+ Chris Wellens - Interworking Labs
+ Rob Whittle - Novell, Inc.
+ Don Wright - Lexmark
+ Peter Zehler - Xerox
+ Steve Zilles - Adobe
+
+11. Formats for IPP Registration Proposals
+
+ In order to propose an IPP extension for registration, the proposer
+ must submit an application to IANA by email to "iana@iana.org" or by
+ filling out the appropriate form on the IANA web pages
+ (http://www.iana.org). This section specifies the required
+ information and the formats for proposing registrations of extensions
+ to IPP as provided in Section 6 for:
+
+ 1. type2 'keyword' attribute values
+ 2. type3 'keyword' attribute values
+ 3. type2 'enum' attribute values
+ 4. type3 'enum' attribute values
+ 5. attributes
+ 6. attribute syntaxes
+ 7. operations
+ 8. status codes
+
+11.1 Type2 keyword attribute values registration
+
+ Type of registration: type2 keyword attribute value
+ Name of attribute to which this keyword specification is to be added:
+ Proposed keyword name of this keyword value:
+ Specification of this keyword value (follow the style of IPP Model
+ Section 4.1.2.3):
+ Name of proposer:
+
+
+
+deBry, et al. Experimental [Page 136]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ Address of proposer:
+ Email address of proposer:
+
+ Note: For type2 keywords, the Designated Expert will be the point of
+ contact for the approved registration specification, if any
+ maintenance of the registration specification is needed.
+
+11.2 Type3 keyword attribute values registration
+
+ Type of registration: type3 keyword attribute value
+ Name of attribute to which this keyword specification is to be added:
+ Proposed keyword name of this keyword value:
+ Specification of this keyword value (follow the style of IPP Model
+ Section 4.1.2.3):
+ Name of proposer:
+ Address of proposer:
+ Email address of proposer:
+
+ Note: For type3 keywords, the proposer will be the point of contact
+ for the approved registration specification, if any maintenance of
+ the registration specification is needed.
+
+11.3 Type2 enum attribute values registration
+
+ Type of registration: type2 enum attribute value
+ Name of attribute to which this enum specification is to be added:
+ Keyword symbolic name of this enum value:
+ Numeric value (to be assigned by the IPP Designated Expert in
+ consultation with IANA):
+ Specification of this enum value (follow the style of IPP Model
+ Section 4.1.4):
+ Name of proposer:
+ Address of proposer:
+ Email address of proposer:
+
+ Note: For type2 enums, the Designated Expert will be the point of
+ contact for the approved registration specification, if any
+ maintenance of the registration specification is needed.
+
+11.4 Type3 enum attribute values registration
+
+ Type of registration: type3 enum attribute value
+ Name of attribute to which this enum specification is to be added:
+ Keyword symbolic name of this enum value:
+ Numeric value (to be assigned by the IPP Designated Expert in
+ consultation with IANA):
+ Specification of this enum value (follow the style of IPP Model
+ Section 4.1.4):
+
+
+
+deBry, et al. Experimental [Page 137]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ Name of proposer:
+ Address of proposer:
+ Email address of proposer:
+
+ Note: For type3 enums, the proposer will be the point of contact for
+ the approved registration specification, if any maintenance of the
+ registration specification is needed.
+
+11.5 Attribute registration
+
+ Type of registration: attribute
+ Proposed keyword name of this attribute:
+ Types of attribute (Operation, Job Template, Job Description,
+ Printer Description):
+ Operations to be used with if the attribute is an operation
+ attribute:
+ Object (Job, Printer, etc. if bound to an object):
+ Attribute syntax(es) (include 1setOf and range as in Section 4.2):
+ If attribute syntax is 'keyword' or 'enum', is it type2 or type3:
+ If this is a Printer attribute, MAY the value returned depend on
+ "document-format" (See Section 6.2):
+ If this is a Job Template attribute, how does its specification
+ depend on the value of the "multiple-document-handling" attribute:
+ Specification of this attribute (follow the style of IPP Model
+ Section 4.2):
+ Name of proposer:
+ Address of proposer:
+ Email address of proposer:
+
+ Note: For attributes, the IPP Designated Expert will be the point of
+ contact for the approved registration specification, if any
+ maintenance of the registration specification is needed.
+
+11.6 Attribute Syntax registration
+
+ Type of registration: attribute syntax
+ Proposed name of this attribute syntax:
+ Type of attribute syntax (integer, octetString, character-string,
+ see [RFC2565]):
+ Numeric value (to be assigned by the IPP Designated Expert in
+ consultation with IANA):
+ Specification of this attribute (follow the style of IPP Model
+ Section 4.1):
+ Name of proposer:
+ Address of proposer:
+ Email address of proposer:
+
+
+
+
+
+deBry, et al. Experimental [Page 138]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ Note: For attribute syntaxes, the IPP Designated Expert will be the
+ point of contact for the approved registration specification, if any
+ maintenance of the registration specification is needed.
+
+11.7 Operation registration
+
+ Type of registration: operation
+ Proposed name of this operation:
+ Numeric operation-id value (to be assigned by the IPP Designated
+ Expert in consultation with IANA):
+ Object Target (Job, Printer, etc. that operation is upon):
+ Specification of this attribute (follow the style of IPP Model
+ Section 3):
+ Name of proposer:
+ Address of proposer:
+ Email address of proposer:
+
+ Note: For operations, the IPP Designated Expert will be the point of
+ contact for the approved registration specification, if any
+ maintenance of the registration specification is needed.
+
+11.8 Attribute Group registration
+
+ Type of registration: attribute group
+ Proposed name of this attribute group:
+ Numeric tag according to [RFC2565] (to be assigned by the IPP
+ Designated Expert in consultation with IANA):
+ Operation requests and group number for each operation in which the
+ attribute group occurs:
+ Operation responses and group number for each operation in which the
+ attribute group occurs:
+ Specification of this attribute group (follow the style of IPP Model
+ Section 3):
+ Name of proposer:
+ Address of proposer:
+ Email address of proposer:
+
+ Note: For attribute groups, the IPP Designated Expert will be the
+ point of contact for the approved registration specification, if any
+ maintenance of the registration specification is needed.
+
+11.9 Status code registration
+
+ Type of registration: status code
+ Keyword symbolic name of this status code value:
+ Numeric value (to be assigned by the IPP Designated Expert in
+ consultation with IANA):
+ Operations that this status code may be used with:
+
+
+
+deBry, et al. Experimental [Page 139]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ Specification of this status code (follow the style of IPP Model
+ Section 14 APPENDIX B: Status Codes and Suggested Status Code
+ Messages):
+ Name of proposer:
+ Address of proposer:
+ Email address of proposer:
+
+ Note: For status codes, the Designated Expert will be the point of
+ contact for the approved registration specification, if any
+ maintenance of the registration specification is needed.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+deBry, et al. Experimental [Page 140]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+12. APPENDIX A: Terminology
+
+ This specification uses the terminology defined in this section.
+
+12.1 Conformance Terminology
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHOULD", "SHOULD NOT",
+ "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be
+ interpreted as described in RFC 2119 [RFC2119].
+
+12.1.1 NEED NOT
+
+ This term is not included in RFC 2119. The verb "NEED NOT" indicates
+ an action that the subject of the sentence does not have to implement
+ in order to claim conformance to the standard. The verb "NEED NOT"
+ is used instead of "MAY NOT" since "MAY NOT" sounds like a
+ prohibition.
+
+12.2 Model Terminology
+
+12.2.1 Keyword
+
+ Keywords are used within this document as identifiers of semantic
+ entities within the abstract model (see section 4.1.2.3). Attribute
+ names, some attribute values, attribute syntaxes, and attribute group
+ names are represented as keywords.
+
+12.2.2 Attributes
+
+ An attribute is an item of information that is associated with an
+ instance of an IPP object. An attribute consists of an attribute
+ name and one or more attribute values. Each attribute has a specific
+ attribute syntax. All object attributes are defined in section 4 and
+ all operation attributes are defined in section 3.
+
+ Job Template Attributes are described in section 4.2. The client
+ optionally supplies Job Template attributes in a create request
+ (operation requests that create Job objects). The Printer object has
+ associated attributes which define supported and default values for
+ the Printer.
+
+12.2.2.1 Attribute Name
+
+ Each attribute is uniquely identified in this document by its
+ attribute name. An attribute name is a keyword. The keyword
+ attribute name is given in the section header describing that
+
+
+
+
+
+deBry, et al. Experimental [Page 141]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ attribute. In running text in this document, attribute names are
+ indicated inside double quotation marks (") where the quotation marks
+ are not part of the keyword itself.
+
+12.2.2.2 Attribute Group Name
+
+ Related attributes are grouped into named groups. The name of the
+ group is a keyword. The group name may be used in place of naming
+ all the attributes in the group explicitly. Attribute groups are
+ defined in section 3.
+
+12.2.2.3 Attribute Value
+
+ Each attribute has one or more values. Attribute values are
+ represented in the syntax type specified for that attribute. In
+ running text in this document, attribute values are indicated inside
+ single quotation marks ('), whether their attribute syntax is
+ keyword, integer, text, etc. where the quotation marks are not part
+ of the value itself.
+
+12.2.2.4 Attribute Syntax
+
+ Each attribute is defined using an explicit syntax type. In this
+ document, each syntax type is defined as a keyword with specific
+ meaning. The Encoding and Transport document [RFC2565] indicates the
+ actual "on-the-wire" encoding rules for each syntax type. Attribute
+ syntax types are defined in section 4.1.
+
+12.2.3 Supports
+
+ By definition, a Printer object supports an attribute only if that
+ Printer object responds with the corresponding attribute populated
+ with some value(s) in a response to a query for that attribute. A
+ Printer object supports an attribute value if the value is one of the
+ Printer object's "supported values" attributes. The device behind a
+ Printer object may exhibit a behavior that corresponds to some IPP
+ attribute, but if the Printer object, when queried for that
+ attribute, doesn't respond with the attribute, then as far as IPP is
+ concerned, that implementation does not support that feature. If the
+ Printer object's "xxx-supported" attribute is not populated with a
+ particular value (even if that value is a legal value for that
+ attribute), then that Printer object does not support that particular
+ value.
+
+ A conforming implementation MUST support all REQUIRED attributes.
+ However, even for REQUIRED attributes, conformance to IPP does not
+ mandate that all implementations support all possible values
+ representing all possible job processing behaviors and features. For
+
+
+
+deBry, et al. Experimental [Page 142]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ example, if a given instance of a Printer supports only certain
+ document formats, then that Printer responds with the "document-
+ format-supported" attribute populated with a set of values, possibly
+ only one, taken from the entire set of possible values defined for
+ that attribute. This limited set of values represents the Printer's
+ set of supported document formats. Supporting an attribute and some
+ set of values for that attribute enables IPP end users to be aware of
+ and make use of those features associated with that attribute and
+ those values. If an implementation chooses to not support an
+ attribute or some specific value, then IPP end users would have no
+ ability to make use of that feature within the context of IPP itself.
+ However, due to existing practice and legacy systems which are not
+ IPP aware, there might be some other mechanism outside the scope of
+ IPP to control or request the "unsupported" feature (such as embedded
+ instructions within the document data itself).
+
+ For example, consider the "finishings-supported" attribute.
+
+ 1) If a Printer object is not physically capable of stapling, the
+ "finishings-supported" attribute MUST NOT be populated with the
+ value of 'staple'.
+ 2) A Printer object is physically capable of stapling, however an
+ implementation chooses not to support stapling in the IPP
+ "finishings" attribute. In this case, 'staple' MUST NOT be a
+ value in the "finishings-supported" Printer object attribute.
+ Without support for the value 'staple', an IPP end user would
+ have no means within the protocol itself to request that a Job
+ be stapled. However, an existing document data formatter might
+ be able to request that the document be stapled directly with an
+ embedded instruction within the document data. In this case,
+ the IPP implementation does not "support" stapling, however the
+ end user is still able to have some control over the stapling of
+ the completed job.
+ 3) A Printer object is physically capable of stapling, and an
+ implementation chooses to support stapling in the IPP
+ "finishings" attribute. In this case, 'staple' MUST be a value
+ in the "finishings-supported" Printer object attribute. Doing
+ so, would enable end users to be aware of and make use of the
+ stapling feature using IPP attributes.
+
+ Even though support for Job Template attributes by a Printer object
+ is OPTIONAL, it is RECOMMENDED that if the device behind a Printer
+ object is capable of realizing any feature or function that
+ corresponds to an IPP attribute and some associated value, then that
+ implementation SHOULD support that IPP attribute and value.
+
+
+
+
+
+
+deBry, et al. Experimental [Page 143]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ The set of values in any of the supported value attributes is set
+ (populated) by some administrative process or automatic sensing
+ mechanism that is outside the scope of IPP. For administrative
+ policy and control reasons, an administrator may choose to make only
+ a subset of possible values visible to the end user. In this case,
+ the real output device behind the IPP Printer abstraction may be
+ capable of a certain feature, however an administrator is specifying
+ that access to that feature not be exposed to the end user through
+ the IPP protocol. Also, since a Printer object may represent a
+ logical print device (not just a physical device) the actual process
+ for supporting a value is undefined and left up to the
+ implementation. However, if a Printer object supports a value, some
+ manual human action may be needed to realize the semantic action
+ associated with the value, but no end user action is required.
+
+ For example, if one of the values in the "finishings-supported"
+ attribute is 'staple', the actual process might be an automatic
+ staple action by a physical device controlled by some command sent to
+ the device. Or, the actual process of stapling might be a manual
+ action by an operator at an operator attended Printer object.
+
+ For another example of how supported attributes function, consider a
+ system administrator who desires to control all print jobs so that no
+ job sheets are printed in order to conserve paper. To force no job
+ sheets, the system administrator sets the only supported value for
+ the "job-sheets-supported" attribute to 'none'. In this case, if a
+ client requests anything except 'none', the create request is
+ rejected or the "job-sheets" value is ignored (depending on the value
+ of "ipp-attribute-fidelity"). To force the use of job start/end
+ sheets on all jobs, the administrator does not include the value '
+ none' in the "job-sheets-supported" attribute. In this case, if a
+ client requests 'none', the create request is rejected or the "job-
+ sheets" value is ignored (again depending on the value of "ipp-
+ attribute-fidelity").
+
+12.2.4 print-stream page
+
+ A "print-stream page" is a page according to the definition of pages
+ in the language used to express the document data.
+
+12.2.5 impression
+
+ An "impression" is the image (possibly many print-stream pages in
+ different configurations) imposed onto a single media page.
+
+
+
+
+
+
+
+deBry, et al. Experimental [Page 144]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+13. APPENDIX B: Status Codes and Suggested Status Code Messages
+
+ This section defines status code enum keywords and values that are
+ used to provide semantic information on the results of an operation
+ request. Each operation response MUST include a status code. The
+ response MAY also contain a status message that provides a short
+ textual description of the status. The status code is intended for
+ use by automata, and the status message is intended for the human end
+ user. Since the status message is an OPTIONAL component of the
+ operation response, an IPP application (i.e., a browser, GUI, print
+ driver or gateway) is NOT REQUIRED to examine or display the status
+ message, since it MAY not be returned to the application.
+
+ The prefix of the status keyword defines the class of response as
+ follows:
+
+ "informational" - Request received, continuing process
+ "successful" - The action was successfully received, understood,
+ and accepted
+ "redirection" - Further action must be taken in order to complete
+ the request
+ "client-error" - The request contains bad syntax or cannot be
+ fulfilled
+ "server-error" - The IPP object failed to fulfill an apparently
+ valid request
+
+ As with type2 enums, IPP status codes are extensible. IPP clients
+ are NOT REQUIRED to understand the meaning of all registered status
+ codes, though such understanding is obviously desirable. However,
+ IPP clients MUST understand the class of any status code, as
+ indicated by the prefix, and treat any unrecognized response as being
+ equivalent to the first status code of that class, with the exception
+ that an unrecognized response MUST NOT be cached. For example, if an
+ unrecognized status code of "client-error-xxx-yyy" is received by the
+ client, it can safely assume that there was something wrong with its
+ request and treat the response as if it had received a "client-
+ error-bad-request" status code. In such cases, IPP applications
+ SHOULD present the OPTIONAL message (if present) to the end user
+ since the message is likely to contain human readable information
+ which will help to explain the unusual status. The name of the enum
+ is the suggested status message for US English.
+
+ The status code values range from 0x0000 to 0x7FFF. The value ranges
+ for each status code class are as follows:
+
+ "successful" - 0x0000 to 0x00FF
+ "informational" - 0x0100 to 0x01FF
+ "redirection" - 0x0200 to 0x02FF
+
+
+
+deBry, et al. Experimental [Page 145]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ "client-error" - 0x0400 to 0x04FF
+ "server-error" - 0x0500 to 0x05FF
+
+ The top half (128 values) of each range (0x0n40 to 0x0nFF, for n = 0
+ to 5) is reserved for private use within each status code class.
+ Values 0x0600 to 0x7FFF are reserved for future assignment and MUST
+ NOT be used.
+
+13.1 Status Codes
+
+ Each status code is described below. Section 13.1.5.9 contains a
+ table that indicates which status codes apply to which operations.
+ The Implementer's Guide [ipp-iig] describe the suggested steps for
+ processing IPP attributes for all operations, including returning
+ status codes.
+
+13.1.1 Informational
+
+ This class of status code indicates a provisional response and is to
+ be used for informational purposes only.
+
+ There are no status codes defined in IPP/1.0 for this class of status
+ code.
+
+13.1.2 Successful Status Codes
+
+ This class of status code indicates that the client's request was
+ successfully received, understood, and accepted.
+
+13.1.2.1 successful-ok (0x0000)
+
+ The request has succeeded and no request attributes were substituted
+ or ignored. In the case of a response to a create request, the '
+ successful-ok' status code indicates that the request was
+ successfully received and validated, and that the Job object has been
+ created; it does not indicate that the job has been processed. The
+ transition of the Job object into the 'completed' state is the only
+ indicator that the job has been printed.
+
+13.1.2.2 successful-ok-ignored-or-substituted-attributes (0x0001)
+
+ The request has succeeded, but some supplied (1) attributes were
+ ignored or (2) unsupported values were substituted with supported
+ values or were ignored in order to perform the operation without
+ rejecting it. Unsupported attributes, attribute syntaxes, or values
+ MUST be returned in the Unsupported Attributes group of the response
+ for all operations. There is an exception to this rule for the query
+ operations: Get-Printer-Attributes, Get-Jobs, and Get-Job-Attributes
+
+
+
+deBry, et al. Experimental [Page 146]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ for the "requested-attributes" operation attribute only. When the
+ supplied values of the "requested-attributes" operation attribute are
+ requesting attributes that are not supported, the IPP object MAY, but
+ is NOT REQUIRED to, return the "requested-attributes" attribute in
+ the Unsupported Attribute response group (with the unsupported values
+ only). See section 3.2.1.2.
+
+13.1.2.3 successful-ok-conflicting-attributes (0x0002)
+
+ The request has succeeded, but some supplied attribute values
+ conflicted with the values of other supplied attributes. These
+ conflicting values were either (1) substituted with (supported)
+ values or (2) the attributes were removed in order to process the job
+ without rejecting it. Attributes or values which conflict with other
+ attributes and have been substituted or ignored MUST be returned in
+ the Unsupported Attributes group of the response for all operations
+ as supplied by the client. See section 3.2.1.2.
+
+13.1.3 Redirection Status Codes
+
+ This class of status code indicates that further action needs to be
+ taken to fulfill the request.
+
+ There are no status codes defined in IPP/1.0 for this class of status
+ code.
+
+13.1.4 Client Error Status Codes
+
+ This class of status code is intended for cases in which the client
+ seems to have erred. The IPP object SHOULD return a message
+ containing an explanation of the error situation and whether it is a
+ temporary or permanent condition.
+
+13.1.4.1 client-error-bad-request (0x0400)
+
+ The request could not be understood by the IPP object due to
+ malformed syntax (such as the value of a fixed length attribute whose
+ length does not match the prescribed length for that attribute - see
+ the Implementer's Guide [ipp-iig] ). The IPP application SHOULD NOT
+ repeat the request without modifications.
+
+13.1.4.2 client-error-forbidden (0x0401)
+
+ The IPP object understood the request, but is refusing to fulfill it.
+ Additional authentication information or authorization credentials
+ will not help and the request SHOULD NOT be repeated. This status
+
+
+
+
+
+deBry, et al. Experimental [Page 147]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ code is commonly used when the IPP object does not wish to reveal
+ exactly why the request has been refused or when no other response is
+ applicable.
+
+13.1.4.3 client-error-not-authenticated (0x0402)
+
+ The request requires user authentication. The IPP client may repeat
+ the request with suitable authentication information. If the request
+ already included authentication information, then this status code
+ indicates that authorization has been refused for those credentials.
+ If this response contains the same challenge as the prior response,
+ and the user agent has already attempted authentication at least
+ once, then the response message may contain relevant diagnostic
+ information. This status codes reveals more information than
+ "client-error-forbidden".
+
+13.1.4.4 client-error-not-authorized (0x0403)
+
+ The requester is not authorized to perform the request. Additional
+ authentication information or authorization credentials will not help
+ and the request SHOULD NOT be repeated. This status code is used
+ when the IPP object wishes to reveal that the authentication
+ information is understandable, however, the requester is explicitly
+ not authorized to perform the request. This status codes reveals
+ more information than "client-error-forbidden" and "client-error-
+ not-authenticated".
+
+13.1.4.5 client-error-not-possible (0x0404)
+
+ This status code is used when the request is for something that can
+ not happen. For example, there might be a request to cancel a job
+ that has already been canceled or aborted by the system. The IPP
+ client SHOULD NOT repeat the request.
+
+13.1.4.6 client-error-timeout (0x0405)
+
+ The client did not produce a request within the time that the IPP
+ object was prepared to wait. For example, a client issued a Create-
+ Job operation and then, after a long period of time, issued a Send-
+ Document operation and this error status code was returned in
+ response to the Send-Document request (see section 3.3.1). The IPP
+ object might have been forced to clean up resources that had been
+ held for the waiting additional Documents. The IPP object was forced
+ to close the Job since the client took too long. The client SHOULD
+ NOT repeat the request without modifications.
+
+
+
+
+
+
+deBry, et al. Experimental [Page 148]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+13.1.4.7 client-error-not-found (0x0406)
+
+ The IPP object has not found anything matching the request URI. No
+ indication is given of whether the condition is temporary or
+ permanent. For example, a client with an old reference to a Job (a
+ URI) tries to cancel the Job, however in the mean time the Job might
+ have been completed and all record of it at the Printer has been
+ deleted. This status code, 'client-error-not-found' is returned
+ indicating that the referenced Job can not be found. This error
+ status code is also used when a client supplies a URI as a reference
+ to the document data in either a Print-URI or Send-URI operation, but
+ the document can not be found.
+
+ In practice, an IPP application should avoid a not found situation by
+ first querying and presenting a list of valid Printer URIs and Job
+ URIs to the end-user.
+
+13.1.4.8 client-error-gone (0x0407)
+
+ The requested object is no longer available and no forwarding address
+ is known. This condition should be considered permanent. Clients
+ with link editing capabilities should delete references to the
+ request URI after user approval. If the IPP object does not know or
+ has no facility to determine, whether or not the condition is
+ permanent, the status code "client-error-not-found" should be used
+ instead.
+
+ This response is primarily intended to assist the task of maintenance
+ by notifying the recipient that the resource is intentionally
+ unavailable and that the IPP object administrator desires that remote
+ links to that resource be removed. It is not necessary to mark all
+ permanently unavailable resources as "gone" or to keep the mark for
+ any length of time -- that is left to the discretion of the IPP
+ object administrator.
+
+13.1.4.9 client-error-request-entity-too-large (0x0408)
+
+ The IPP object is refusing to process a request because the request
+ entity is larger than the IPP object is willing or able to process.
+ An IPP Printer returns this status code when it limits the size of
+ print jobs and it receives a print job that exceeds that limit or
+ when the attributes are so many that their encoding causes the
+ request entity to exceed IPP object capacity.
+
+
+
+
+
+
+
+
+deBry, et al. Experimental [Page 149]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+13.1.4.10 client-error-request-value-too-long (0x0409)
+
+ The IPP object is refusing to service the request because one or more
+ of the client-supplied attributes has a variable length value that is
+ longer than the maximum length specified for that attribute. The IPP
+ object might not have sufficient resources (memory, buffers, etc.) to
+ process (even temporarily), interpret, and/or ignore a value larger
+ than the maximum length. Another use of this error code is when the
+ IPP object supports the processing of a large value that is less than
+ the maximum length, but during the processing of the request as a
+ whole, the object may pass the value onto some other system component
+ which is not able to accept the large value. For more details, see
+ the Implementer's Guide [ipp-iig] .
+
+ Note: For attribute values that are URIs, this rare condition is
+ only likely to occur when a client has improperly submitted a request
+ with long query information (e.g. an IPP application allows an end-
+ user to enter an invalid URI), when the client has descended into a
+ URI "black hole" of redirection (e.g., a redirected URI prefix that
+ points to a suffix of itself), or when the IPP object is under attack
+ by a client attempting to exploit security holes present in some IPP
+ objects using fixed-length buffers for reading or manipulating the
+ Request-URI.
+
+13.1.4.11 client-error-document-format-not-supported (0x040A)
+
+ The IPP object is refusing to service the request because the
+ document data is in a format, as specified in the "document-format"
+ operation attribute, that is not supported by the Printer object.
+ This error is returned independent of the client-supplied "ipp-
+ attribute-fidelity". The Printer object MUST return this status
+ code, even if there are other attributes that are not supported as
+ well, since this error is a bigger problem than with Job Template
+ attributes.
+
+13.1.4.12 client-error-attributes-or-values-not-supported (0x040B)
+
+ In a create request, if the Printer object does not support one or
+ more attributes, attribute syntaxes, or attribute values supplied in
+ the request and the client supplied the "ipp-attributes-fidelity"
+ operation attribute with the 'true' value, the Printer object MUST
+ return this status code. For example, if the request indicates '
+ iso-a4' media, but that media type is not supported by the Printer
+ object. Or, if the client supplies an optional attribute and the
+ attribute itself is not even supported by the Printer. If the "ipp-
+ attribute-fidelity" attribute is 'false', the Printer MUST ignore or
+ substitute values for unsupported attributes and values rather than
+ reject the request and return this status code.
+
+
+
+deBry, et al. Experimental [Page 150]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ For any operation where a client requests attributes (such as a Get-
+ Jobs, Get-Printer-Attributes, or Get-Job-Attributes operation), if
+ the IPP object does not support one or more of the requested
+ attributes, the IPP object simply ignores the unsupported requested
+ attributes and processes the request as if they had not been
+ supplied, rather than returning this status code. In this case, the
+ IPP object MUST return the 'successful-ok-ignored-or-substituted-
+ attributes' status code and MAY return the unsupported attributes as
+ values of the "requested-attributes" in the Unsupported Attributes
+ Group (see section 13.1.2.2).
+
+13.1.4.13 client-error-uri-scheme-not-supported (0x040C)
+
+ The type of the client supplied URI in a Print-URI or a Send-URI
+ operation is not supported.
+
+13.1.4.14 client-error-charset-not-supported (0x040D)
+
+ For any operation, if the IPP Printer does not support the charset
+ supplied by the client in the "attributes-charset" operation
+ attribute, the Printer MUST reject the operation and return this
+ status and any 'text' or 'name' attributes using the 'utf-8' charset
+ (see Section 3.1.4.1).
+
+13.1.4.15 client-error-conflicting-attributes (0x040E)
+
+ The request is rejected because some attribute values conflicted with
+ the values of other attributes which this specification does not
+ permit to be substituted or ignored.
+
+13.1.5 Server Error Status Codes
+
+ This class of status codes indicates cases in which the IPP object is
+ aware that it has erred or is incapable of performing the request.
+ The IPP object SHOULD include a message containing an explanation of
+ the error situation, and whether it is a temporary or permanent
+ condition.
+
+13.1.5.1 server-error-internal-error (0x0500)
+
+ The IPP object encountered an unexpected condition that prevented it
+ from fulfilling the request. This error status code differs from
+ "server-error-temporary-error" in that it implies a more permanent
+ type of internal error. It also differs from "server-error-device-
+ error" in that it implies an unexpected condition (unlike a paper-jam
+ or out-of-toner problem which is undesirable but expected). This
+ error status code indicates that probably some knowledgeable human
+ intervention is required.
+
+
+
+deBry, et al. Experimental [Page 151]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+13.1.5.2 server-error-operation-not-supported (0x0501)
+
+ The IPP object does not support the functionality required to fulfill
+ the request. This is the appropriate response when the IPP object
+ does not recognize an operation or is not capable of supporting it.
+
+13.1.5.3 server-error-service-unavailable (0x0502)
+
+ The IPP object is currently unable to handle the request due to a
+ temporary overloading or maintenance of the IPP object. The
+ implication is that this is a temporary condition which will be
+ alleviated after some delay. If known, the length of the delay may be
+ indicated in the message. If no delay is given, the IPP application
+ should handle the response as it would for a "server-error-
+ temporary-error" response. If the condition is more permanent, the
+ error status codes "client-error-gone" or "client-error-not-found"
+ could be used.
+
+13.1.5.4 server-error-version-not-supported (0x0503)
+
+ The IPP object does not support, or refuses to support, the IPP
+ protocol version that was used in the request message. The IPP
+ object is indicating that it is unable or unwilling to complete the
+ request using the same version as supplied in the request other than
+ with this error message. The response should contain a Message
+ describing why that version is not supported and what other versions
+ are supported by that IPP object.
+
+ A conforming IPP/1.0 client MUST specify the valid version ('1.0') on
+ each request. A conforming IPP/1.0 object MUST NOT return this
+ status code to a conforming IPP/1.0 client. An IPP object MUST
+ return this status code to a non-conforming IPP client. The response
+ MUST identify in the "version-number" operation attribute the closest
+ version number that the IPP object does support.
+
+13.1.5.5 server-error-device-error (0x0504)
+
+ A printer error, such as a paper jam, occurs while the IPP object
+ processes a Print or Send operation. The response contains the true
+ Job Status (the values of the "job-state" and "job-state-reasons"
+ attributes). Additional information can be returned in the optional
+ "job-state-message" attribute value or in the OPTIONAL status message
+ that describes the error in more detail. This error status code is
+ only returned in situations where the Printer is unable to accept the
+ create request because of such a device error. For example, if the
+ Printer is unable to spool, and can only accept one job at a time,
+ the reason it might reject a create request is that the printer
+ currently has a paper jam. In many cases however, where the Printer
+
+
+
+deBry, et al. Experimental [Page 152]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ object can accept the request even though the Printer has some error
+ condition, the 'successful-ok' status code will be returned. In such
+ a case, the client would look at the returned Job Object Attributes
+ or later query the Printer to determine its state and state reasons.
+
+13.1.5.6 server-error-temporary-error (0x0505)
+
+ A temporary error such as a buffer full write error, a memory
+ overflow (i.e. the document data exceeds the memory of the Printer),
+ or a disk full condition, occurs while the IPP Printer processes an
+ operation. The client MAY try the unmodified request again at some
+ later point in time with an expectation that the temporary internal
+ error condition may have been cleared. Alternatively, as an
+ implementation option, a Printer object MAY delay the response until
+ the temporary condition is cleared so that no error is returned.
+
+13.1.5.7 server-error-not-accepting-jobs (0x0506)
+
+ A temporary error indicating that the Printer is not currently
+ accepting jobs, because the administrator has set the value of the
+ Printer's "printer-is-not-accepting-jobs" attribute to 'false' (by
+ means outside of IPP/1.0).
+
+13.1.5.8 server-error-busy (0x0507)
+
+ A temporary error indicating that the Printer is too busy processing
+ jobs and/or other requests. The client SHOULD try the unmodified
+ request again at some later point in time with an expectation that
+ the temporary busy condition will have been cleared.
+
+13.1.5.9 server-error-job-canceled (0x0508)
+
+ An error indicating that the job has been canceled by an operator or
+ the system while the client was transmitting the data to the IPP
+ Printer. If a job-id and job-uri had been created, then they are
+ returned in the Print-Job, Send-Document, or Send-URI response as
+ usual; otherwise, no job-id and job-uri are returned in the response.
+
+13.2 Status Codes for IPP Operations
+
+ PJ = Print-Job, PU = Print-URI, CJ = Create-Job, SD = Send-Document
+ SU = Send-URI, V = Validate-Job, GA = Get-Job-Attributes and
+ Get-Printer-Attributes, GJ = Get-Jobs, C = Cancel-Job
+
+
+
+
+
+
+
+
+deBry, et al. Experimental [Page 153]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ IPP Operations
+ IPP Status Keyword PJ PU CJ SD SU V GA GJ C
+ ------------------ -- -- -- -- -- - -- -- -
+ successful-ok x x x x x x x x x
+ successful-ok-ignored-or-substituted- x x x x x x x x x
+ attributes
+ successful-ok-conflicting-attributes x x x x x x x x x
+ client-error-bad-request x x x x x x x x x
+ client-error-forbidden x x x x x x x x x
+ client-error-not-authenticated x x x x x x x x x
+ client-error-not-authorized x x x x x x x x x
+ client-error-not-possible x x x x x x x x x
+ client-error-timeout x x
+ client-error-not-found x x x x x x x x x
+ client-error-gone x x x x x x x x x
+ client-error-request-entity-too-large x x x x x x x x x
+ client-error-request-value-too-long x x x x x x x x x
+ client-error-document-format-not- x x x x x x
+ supported
+ client-error-attributes-or-values-not- x x x x x x x x x
+ supported
+ client-error-uri-scheme-not-supported x x
+ client-error-charset-not-supported x x x x x x x x x
+ client-error-conflicting-attributes x x x x x x x x x
+ server-error-internal-error x x x x x x x x x
+ server-error-operation-not-supported x x x x
+ server-error-service-unavailable x x x x x x x x x
+ server-error-version-not-supported x x x x x x x x x
+ server-error-device-error x x x x x
+ server-error-temporary-error x x x x x
+ server-error-not-accepting-jobs x x x x
+ server-error-busy x x x x x x x x x
+ server-error-job-canceled x x
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+deBry, et al. Experimental [Page 154]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+14. APPENDIX C: "media" keyword values
+
+ Standard keyword values are taken from several sources.
+
+ Standard values are defined (taken from DPA[ISO10175] and the Printer
+ MIB[RFC1759]):
+
+ 'default': The default medium for the output device
+ 'iso-a4-white': Specifies the ISO A4 white medium
+ 'iso-a4-colored': Specifies the ISO A4 colored medium
+ 'iso-a4-transparent' Specifies the ISO A4 transparent medium
+ 'iso-a3-white': Specifies the ISO A3 white medium
+ 'iso-a3-colored': Specifies the ISO A3 colored medium
+ 'iso-a5-white': Specifies the ISO A5 white medium
+ 'iso-a5-colored': Specifies the ISO A5 colored medium
+ 'iso-b4-white': Specifies the ISO B4 white medium
+ 'iso-b4-colored': Specifies the ISO B4 colored medium
+ 'iso-b5-white': Specifies the ISO B5 white medium
+ 'iso-b5-colored': Specifies the ISO B5 colored medium
+ 'jis-b4-white': Specifies the JIS B4 white medium
+ 'jis-b4-colored': Specifies the JIS B4 colored medium
+ 'jis-b5-white': Specifies the JIS B5 white medium
+ 'jis-b5-colored': Specifies the JIS B5 colored medium
+
+ The following standard values are defined for North American media:
+
+ 'na-letter-white': Specifies the North American letter white medium
+ 'na-letter-colored': Specifies the North American letter colored
+ medium
+ 'na-letter-transparent': Specifies the North American letter
+ transparent medium
+ 'na-legal-white': Specifies the North American legal white medium
+ 'na-legal-colored': Specifies the North American legal colored
+ medium
+
+ The following standard values are defined for envelopes:
+
+ 'iso-b4-envelope': Specifies the ISO B4 envelope medium
+ 'iso-b5-envelope': Specifies the ISO B5 envelope medium
+ 'iso-c3-envelope': Specifies the ISO C3 envelope medium
+ 'iso-c4-envelope': Specifies the ISO C4 envelope medium
+ 'iso-c5-envelope': Specifies the ISO C5 envelope medium
+ 'iso-c6-envelope': Specifies the ISO C6 envelope medium
+ 'iso-designated-long-envelope': Specifies the ISO Designated Long
+ envelope medium
+ 'na-10x13-envelope': Specifies the North American 10x13 envelope
+ medium
+
+
+
+
+deBry, et al. Experimental [Page 155]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ 'na-9x12-envelope': Specifies the North American 9x12 envelope
+ medium
+ 'monarch-envelope': Specifies the Monarch envelope
+ 'na-number-10-envelope': Specifies the North American number 10
+ business envelope medium
+ 'na-7x9-envelope': Specifies the North American 7x9 inch envelope
+ 'na-9x11-envelope': Specifies the North American 9x11 inch envelope
+ 'na-10x14-envelope': Specifies the North American 10x14 inch
+ envelope
+ 'na-number-9-envelope': Specifies the North American number 9
+ business envelope
+ 'na-6x9-envelope': Specifies the North American 6x9 inch envelope
+ 'na-10x15-envelope': Specifies the North American 10x15 inch
+ envelope
+
+ The following standard values are defined for the less commonly used
+ media (white-only):
+
+ 'executive-white': Specifies the white executive medium
+ 'folio-white': Specifies the folio white medium
+ 'invoice-white': Specifies the white invoice medium
+ 'ledger-white': Specifies the white ledger medium
+ 'quarto-white': Specified the white quarto medium
+ 'iso-a0-white': Specifies the ISO A0 white medium
+ 'iso-a1-white': Specifies the ISO A1 white medium
+ 'iso-a2-white': Specifies the ISO A2 white medium
+ 'iso-a6-white': Specifies the ISO A6 white medium
+ 'iso-a7-white': Specifies the ISO A7 white medium
+ 'iso-a8-white': Specifies the ISO A8 white medium
+ 'iso-a9-white': Specifies the ISO A9 white medium
+ 'iso-10-white': Specifies the ISO A10 white medium
+ 'iso-b0-white': Specifies the ISO B0 white medium
+ 'iso-b1-white': Specifies the ISO B1 white medium
+ 'iso-b2-white': Specifies the ISO B2 white medium
+ 'iso-b3-white': Specifies the ISO B3 white medium
+ 'iso-b6-white': Specifies the ISO B6 white medium
+ 'iso-b7-white': Specifies the ISO B7 white medium
+ 'iso-b8-white': Specifies the ISO B8 white medium
+ 'iso-b9-white': Specifies the ISO B9 white medium
+ 'iso-b10-white': Specifies the ISO B10 white medium
+ 'jis-b0-white': Specifies the JIS B0 white medium
+ 'jis-b1-white': Specifies the JIS B1 white medium
+ 'jis-b2-white': Specifies the JIS B2 white medium
+ 'jis-b3-white': Specifies the JIS B3 white medium
+ 'jis-b6-white': Specifies the JIS B6 white medium
+ 'jis-b7-white': Specifies the JIS B7 white medium
+
+
+
+
+
+deBry, et al. Experimental [Page 156]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ 'jis-b8-white': Specifies the JIS B8 white medium
+ 'jis-b9-white': Specifies the JIS B9 white medium
+ 'jis-b10-white': Specifies the JIS B10 white medium
+
+
+ The following standard values are defined for engineering media:
+
+ 'a': Specifies the engineering A size medium
+ 'b': Specifies the engineering B size medium
+ 'c': Specifies the engineering C size medium
+ 'd': Specifies the engineering D size medium
+ 'e': Specifies the engineering E size medium
+
+
+ The following standard values are defined for input-trays (from ISO
+ DPA and the Printer MIB):
+
+ 'top': The top input tray in the printer.
+ 'middle': The middle input tray in the printer.
+ 'bottom': The bottom input tray in the printer.
+ 'envelope': The envelope input tray in the printer.
+ 'manual': The manual feed input tray in the printer.
+ 'large-capacity': The large capacity input tray in the printer.
+ 'main': The main input tray
+ 'side': The side input tray
+
+
+ The following standard values are defined for media sizes (from ISO
+ DPA):
+
+ 'iso-a0': Specifies the ISO A0 size: 841 mm by 1189 mm as defined
+ in ISO 216
+ 'iso-a1': Specifies the ISO A1 size: 594 mm by 841 mm as defined in
+ ISO 216
+ 'iso-a2': Specifies the ISO A2 size: 420 mm by 594 mm as defined in
+ ISO 216
+ 'iso-a3': Specifies the ISO A3 size: 297 mm by 420 mm as defined in
+ ISO 216
+ 'iso-a4': Specifies the ISO A4 size: 210 mm by 297 mm as defined in
+ ISO 216
+ 'iso-a5': Specifies the ISO A5 size: 148 mm by 210 mm as defined in
+ ISO 216
+ 'iso-a6': Specifies the ISO A6 size: 105 mm by 148 mm as defined in
+ ISO 216
+ 'iso-a7': Specifies the ISO A7 size: 74 mm by 105 mm as defined in
+ ISO 216
+ 'iso-a8': Specifies the ISO A8 size: 52 mm by 74 mm as defined in
+ ISO 216
+
+
+
+deBry, et al. Experimental [Page 157]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ 'iso-a9': Specifies the ISO A9 size: 37 mm by 52 mm as defined in
+ ISO 216
+ 'iso-a10': Specifies the ISO A10 size: 26 mm by 37 mm as defined in
+ ISO 216
+ 'iso-b0': Specifies the ISO B0 size: 1000 mm by 1414 mm as defined
+ in ISO 216
+ 'iso-b1': Specifies the ISO B1 size: 707 mm by 1000 mm as defined
+ in ISO 216
+ 'iso-b2': Specifies the ISO B2 size: 500 mm by 707 mm as defined in
+ ISO 216
+ 'iso-b3': Specifies the ISO B3 size: 353 mm by 500 mm as defined in
+ ISO 216
+ 'iso-b4': Specifies the ISO B4 size: 250 mm by 353 mm as defined in
+ ISO 216
+ 'iso-b5': Specifies the ISO B5 size: 176 mm by 250 mm as defined in
+ ISO 216
+ 'iso-b6': Specifies the ISO B6 size: 125 mm by 176 mm as defined in
+ ISO 216
+ 'iso-b7': Specifies the ISO B7 size: 88 mm by 125 mm as defined in
+ ISO 216
+ 'iso-b8': Specifies the ISO B8 size: 62 mm by 88 mm as defined in
+ ISO 216
+ 'iso-b9': Specifies the ISO B9 size: 44 mm by 62 mm as defined in
+ ISO 216
+ 'iso-b10': Specifies the ISO B10 size: 31 mm by 44 mm as defined in
+ ISO 216
+ 'na-letter': Specifies the North American letter size: 8.5 inches by
+ 11 inches
+ 'na-legal': Specifies the North American legal size: 8.5 inches by
+ 14 inches
+ 'executive': Specifies the executive size (7.25 X 10.5 in)
+ 'folio': Specifies the folio size (8.5 X 13 in)
+ 'invoice': Specifies the invoice size (5.5 X 8.5 in)
+ 'ledger': Specifies the ledger size (11 X 17 in)
+ 'quarto': Specifies the quarto size (8.5 X 10.83 in)
+ 'iso-c3': Specifies the ISO C3 size: 324 mm by 458 mm as defined in
+ ISO 269
+ 'iso-c4': Specifies the ISO C4 size: 229 mm by 324 mm as defined in
+ ISO 269
+ 'iso-c5': Specifies the ISO C5 size: 162 mm by 229 mm as defined in
+ ISO 269
+ 'iso-c6': Specifies the ISO C6 size: 114 mm by 162 mm as defined in
+ ISO 269
+ 'iso-designated-long': Specifies the ISO Designated Long size: 110
+ mm by 220 mm as defined in ISO 269
+ 'na-10x13-envelope': Specifies the North American 10x13 size: 10
+ inches by 13 inches
+
+
+
+
+deBry, et al. Experimental [Page 158]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ 'na-9x12-envelope': Specifies the North American 9x12 size: 9
+ inches by 12 inches
+ 'na-number-10-envelope': Specifies the North American number 10
+ business envelope size: 4.125 inches by 9.5 inches
+ 'na-7x9-envelope': Specifies the North American 7x9 inch envelope
+ size
+ 'na-9x11-envelope': Specifies the North American 9x11 inch envelope
+ size
+ 'na-10x14-envelope': Specifies the North American 10x14 inch
+ envelope size
+ 'na-number-9-envelope': Specifies the North American number 9
+ business envelope size
+ 'na-6x9-envelope': Specifies the North American 6x9 envelope size
+ 'na-10x15-envelope': Specifies the North American 10x15 envelope
+ size
+ 'monarch-envelope': Specifies the Monarch envelope size (3.87 x 7.5
+ in)
+ 'jis-b0': Specifies the JIS B0 size: 1030mm x 1456mm
+ 'jis-b1': Specifies the JIS B1 size: 728mm x 1030mm
+ 'jis-b2': Specifies the JIS B2 size: 515mm x 728mm
+ 'jis-b3': Specifies the JIS B3 size: 364mm x 515mm
+ 'jis-b4': Specifies the JIS B4 size: 257mm x 364mm
+ 'jis-b5': Specifies the JIS B5 size: 182mm x 257mm
+ 'jis-b6': Specifies the JIS B6 size: 128mm x 182mm
+ 'jis-b7': Specifies the JIS B7 size: 91mm x 128mm
+ 'jis-b8': Specifies the JIS B8 size: 64mm x 91mm
+ 'jis-b9': Specifies the JIS B9 size: 45mm x 64mm
+ 'jis-b10': Specifies the JIS B10 size: 32mm x 45mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+deBry, et al. Experimental [Page 159]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+15. APPENDIX D: Processing IPP Attributes
+
+ When submitting a print job to a Printer object, the IPP model allows
+ a client to supply operation and Job Template attributes along with
+ the document data. These Job Template attributes in the create
+ request affect the rendering, production and finishing of the
+ documents in the job. Similar types of instructions may also be
+ contained in the document to be printed, that is, embedded within the
+ print data itself. In addition, the Printer has a set of attributes
+ that describe what rendering and finishing options which are
+ supported by that Printer. This model, which allows for flexibility
+ and power, also introduces the potential that at job submission time,
+ these client-supplied attributes may conflict with either:
+
+ - what the implementation is capable of realizing (i.e., what the
+ Printer supports), as well as
+ - the instructions embedded within the print data itself.
+
+ The following sections describe how these two types of conflicts are
+ handled in the IPP model.
+
+15.1 Fidelity
+
+ If there is a conflict between what the client requests and what a
+ Printer object supports, the client may request one of two possible
+ conflict handling mechanisms:
+
+ 1) either reject the job since the job can not be processed exactly
+ as specified, or
+ 2) allow the Printer to make any changes necessary to proceed with
+ processing the Job the best it can.
+
+ In the first case the client is indicating to the Printer object:
+ "Print the job exactly as specified with no exceptions, and if that
+ can't be done, don't even bother printing the job at all." In the
+ second case, the client is indicating to the Printer object: "It is
+ more important to make sure the job is printed rather than be
+ processed exactly as specified; just make sure the job is printed
+ even if client supplied attributes need to be changed or ignored."
+
+ The IPP model accounts for this situation by introducing an "ipp-
+ attribute-fidelity" attribute.
+
+ In a create request, "ipp-attribute-fidelity" is a boolean operation
+ attribute that is OPTIONALLY supplied by the client. The value '
+ true' indicates that total fidelity to client supplied Job Template
+ attributes and values is required. The client is requesting that the
+ Job be printed exactly as specified, and if that is not possible then
+
+
+
+deBry, et al. Experimental [Page 160]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ the job MUST be rejected rather than processed incorrectly. The
+ value 'false' indicates that a reasonable attempt to print the Job is
+ acceptable. If a Printer does not support some of the client
+ supplied Job Template attributes or values, the Printer MUST ignore
+ them or substitute any supported value for unsupported values,
+ respectively. The Printer may choose to substitute the default value
+ associated with that attribute, or use some other supported value
+ that is similar to the unsupported requested value. For example, if
+ a client supplies a "media" value of 'na-letter', the Printer may
+ choose to substitute 'iso-a4' rather than a default value of '
+ envelope'. If the client does not supply the "ipp-attribute-fidelity"
+ attribute, the Printer assumes a value of 'false'.
+
+ Each Printer implementation MUST support both types of "fidelity"
+ printing (that is whether the client supplies a value of 'true' or '
+ false'):
+
+ - If the client supplies 'false' or does not supply the attribute,
+ the Printer object MUST always accept the request by ignoring
+ unsupported Job Template attributes and by substituting
+ unsupported values of supported Job Template attributes with
+ supported values.
+ - If the client supplies 'true', the Printer object MUST reject the
+ request if the client supplies unsupported Job Template
+ attributes.
+
+ Since a client can always query a Printer to find out exactly what is
+ and is not supported, "ipp-attribute-fidelity" set to 'false' is
+ useful when:
+
+ 1) The End-User uses a command line interface to request attributes
+ that might not be supported.
+ 2) In a GUI context, if the End User expects the job might be moved
+ to another printer and prefers a sub-optimal result to nothing
+ at all.
+ 3) The End User just wants something reasonable in lieu of nothing
+ at all.
+
+15.2 Page Description Language (PDL) Override
+
+ If there is a conflict between the value of an IPP Job Template
+ attribute and a corresponding instruction in the document data, the
+ value of the IPP attribute SHOULD take precedence over the document
+ instruction. Consider the case where a previously formatted file of
+ document data is sent to an IPP Printer. In this case, if the client
+ supplies any attributes at job submission time, the client desires
+ that those attributes override the embedded instructions. Consider
+ the case were a previously formatted document has embedded in it
+
+
+
+deBry, et al. Experimental [Page 161]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ commands to load 'iso-a4' media. However, the document is passed to
+ an end user that only has access to a printer with 'na-letter' media
+ loaded. That end user most likely wants to submit that document to
+ an IPP Printer with the "media" Job Template attribute set to 'na-
+ letter'. The job submission attribute should take precedence over
+ the embedded PDL instruction. However, until companies that supply
+ document data interpreters allow a way for external IPP attributes to
+ take precedence over embedded job production instructions, a Printer
+ might not be able to support the semantics that IPP attributes
+ override the embedded instructions.
+
+ The IPP model accounts for this situation by introducing a "pdl-
+ override-supported" attribute that describes the Printer objects
+ capabilities to override instructions embedded in the PDL data
+ stream. The value of the "pdl-override-supported" attribute is
+ configured by means outside IPP/1.0.
+
+ This REQUIRED Printer attribute takes on the following values:
+
+ - 'attempted': This value indicates that the Printer object
+ attempts to make the IPP attribute values take precedence over
+ embedded instructions in the document data, however there is no
+ guarantee.
+ - 'not-attempted': This value indicates that the Printer object
+ makes no attempt to make the IPP attribute values take precedence
+ over embedded instructions in the document data.
+
+ At job processing time, an implementation that supports the value of
+ 'attempted' might do one of several different actions:
+
+ 1) Generate an output device specific command sequence to realize
+ the feature represented by the IPP attribute value.
+ 2) Parse the document data itself and replace the conflicting
+ embedded instruction with a new embedded instruction that
+ matches the intent of the IPP attribute value.
+ 3) Indicate to the Printer that external supplied attributes take
+ precedence over embedded instructions and then pass the external
+ IPP attribute values to the document data interpreter.
+ 4) Anything else that allows for the semantics that IPP attributes
+ override embedded document data instructions.
+
+ Since 'attempted' does not offer any type of guarantee, even though a
+ given Printer object might not do a very "good" job of attempting to
+ ensure that IPP attributes take a higher precedence over instructions
+ embedded in the document data, it would still be a conforming
+ implementation.
+
+
+
+
+
+deBry, et al. Experimental [Page 162]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ At job processing time, an implementation that supports the value of
+ 'not-attempted' might do one of the following actions:
+
+ 1) Simply pre-pend the document data with the PDL instruction that
+ corresponds to the client-supplied PDL attribute, such that if
+ the document data also has the same PDL instruction, it will
+ override what the Printer object pre-pended. In other words,
+ this implementation is using the same implementation semantics
+ for the client-supplied IPP attributes as for the Printer object
+ defaults.
+ 2) Parse the document data and replace the conflicting embedded
+ instruction with a new embedded instruction that approximates,
+ but does not match, the semantic intent of the IPP attribute
+ value.
+
+ Note: The "ipp-attribute-fidelity" attribute applies to the
+ Printer's ability to either accept or reject other unsupported Job
+ Template attributes. In other words, if "ipp-attribute-fidelity" is
+ set to 'true', a Job is accepted if and only if the client supplied
+ Job Template attributes and values are supported by the Printer.
+ Whether these attributes actually affect the processing of the Job
+ when the document data contains embedded instructions depends on the
+ ability of the Printer to override the instructions embedded in the
+ document data with the semantics of the IPP attributes. If the
+ document data attributes can be overridden ("pdl-override-supported"
+ set to 'attempted'), the Printer makes an attempt to use the IPP
+ attributes when processing the Job. If the document data attributes
+ can not be overridden ("pdl-override-supported" set to 'not-
+ attempted'), the Printer makes no attempt to override the embedded
+ document data instructions with the IPP attributes when processing
+ the Job, and hence, the IPP attributes may fail to affect the Job
+ processing and output when the corresponding instruction is embedded
+ in the document data.
+
+15.3 Using Job Template Attributes During Document Processing.
+
+ The Printer object uses some of the Job object's Job Template
+ attributes during the processing of the document data associated with
+ that job. These include, but are not limited to, "orientation",
+ "number-up", "sides", "media", and "copies". The processing of each
+ document in a Job Object MUST follow the steps below. These steps are
+ intended only to identify when and how attributes are to be used in
+ processing document data and any alternative steps that accomplishes
+ the same effect can be used to implement this specification.
+
+ 1. Using the client supplied "document-format" attribute or some
+ form of document format detection algorithm (if the value of
+ "document- format" is not specific enough), determine whether or
+
+
+
+deBry, et al. Experimental [Page 163]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ not the document data has already been formatted for printing.
+ If the document data has been formatted, then go to step 2.
+ Otherwise, the document data MUST be formatted. The formatting
+ detection algorithm is implementation defined and is not
+ specified by this specification. The formatting of the document
+ data uses the "orientation-requested" attribute to determine how
+ the formatted print data should be placed on a print-stream
+ page, see section 4.2.10 for the details.
+
+ 2. The document data is in the form of a print-stream in a known
+ media type. The "page-ranges" attribute is used to select, as
+ specified in section 4.2.7, a sub-sequence of the pages in the
+ print-stream that are to be processed and images.
+
+ 3. The input to this step is a sequence of print-stream pages. This
+ step is controlled by the "number-up" attribute. If the value of
+ "number-up" is N, then during the processing of the print-stream
+ pages, each N print-stream pages are positioned, as specified in
+ section 4.2.9, to create a single impression. If a given
+ document does not have N more print-stream pages, then the
+ completion of the impression is controlled by the "multiple-
+ document-handling" attribute as described in section 4.2.4; when
+ the value of this attribute is 'single-document' or 'single-
+ document-new-sheet', the print-stream pages of document data
+ from subsequent documents is used to complete the impression.
+
+ The size(scaling), position(translation) and rotation of the
+ print-stream pages on the impression is implementation defined.
+ Note that during this process the print-stream pages may be
+ rendered to a form suitable for placing on the impression; this
+ rendering is controlled by the values of the "printer-
+ resolution" and "print- quality" attributes as described in
+ sections 4.2.12 and 4.2.13. In the case N=1, the impression is
+ nearly the same as the print-stream page; the differences would
+ only be in the size, position and rotation of the print-stream
+ page and/or any decoration, such as a frame to the page, that is
+ added by the implementation.
+
+ 4. The collection of impressions is placed, in sequence, onto sides
+ of the media sheets. This placement is controlled by the "sides"
+ attribute and the orientation of the print-stream page, as
+ described in section 4.2.8. The orientation of the print-stream
+ pages affects the orientation of the impression; for example, if
+ "number-up" equals 2, then, typically, two portrait print-stream
+ pages become one landscape impression. Note that the placement
+ of impressions onto media sheets is also controlled by the
+ "multiple-document-handling" attribute as described in section
+ 4.2.4.
+
+
+
+deBry, et al. Experimental [Page 164]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ 5. The "copies" and "multiple-document-handling" attributes are
+ used to determine how many copies of each media instance are
+ created and in what order. See sections 4.2.5 and 4.2.4 for the
+ details.
+
+ 6. When the correct number of copies are created, the media
+ instances are finished according to the values of the
+ "finishings" attribute as described in 4.2.6. Note that
+ sometimes finishing operations may require manual intervention
+ to perform the finishing operations on the copies, especially
+ uncollated copies. This specification allows any or all of the
+ processing steps to be performed automatically or manually at
+ the discretion of the Printer object.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+deBry, et al. Experimental [Page 165]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+16. APPENDIX E: Generic Directory Schema
+
+ This section defines a generic schema for an entry in a directory
+ service. A directory service is a means by which service users can
+ locate service providers. In IPP environments, this means that IPP
+ Printers can be registered (either automatically or with the help of
+ an administrator) as entries of type printer in the directory using
+ an implementation specific mechanism such as entry attributes, entry
+ type fields, specific branches, etc. IPP clients can search or
+ browse for entries of type printer. Clients use the directory
+ service to find entries based on naming, organizational contexts, or
+ filtered searches on attribute values of entries. For example, a
+ client can find all printers in the "Local Department" context.
+ Authentication and authorization are also often part of a directory
+ service so that an administrator can place limits on end users so
+ that they are only allowed to find entries to which they have certain
+ access rights. IPP itself does not require any specific directory
+ service protocol or provider.
+
+ Note: Some directory implementations allow for the notion of
+ "aliasing". That is, one directory entry object can appear as
+ multiple directory entry object with different names for each object.
+ In each case, each alias refers to the same directory entry object
+ which refers to a single IPP Printer object.
+
+ The generic schema is a subset of IPP Printer Job Template and
+ Printer Description attributes (sections 4.2 and 4.4). These
+ attributes are identified as either RECOMMENDED or OPTIONAL for the
+ directory entry itself. This conformance labeling is NOT the same
+ conformance labeling applied to the attributes of IPP Printers
+ objects. The conformance labeling in this Appendix is intended to
+ apply to directory templates and to IPP Printer implementations that
+ subscribe by adding one or more entries to a directory. RECOMMENDED
+ attributes SHOULD be associated with each directory entry. OPTIONAL
+ attributes MAY be associated with the directory entry (if known or
+ supported). In addition, all directory entry attributes SHOULD
+ reflect the current attribute values for the corresponding Printer
+ object.
+
+ The names of attributes in directory schema and entries SHOULD be the
+ same as the IPP Printer attribute names as shown.
+
+ In order to bridge between the directory service and the IPP Printer
+ object, one of the RECOMMENDED directory entry attributes is the
+ Printer object's "printer-uri-supported" attribute. The IPP client
+ queries the "printer-uri-supported" attribute in the directory entry
+
+
+
+
+
+deBry, et al. Experimental [Page 166]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ and then addresses the IPP Printer object using one of its URIs. The
+ "uri-security-supported" attribute identifies the protocol (if any)
+ used to secure a channel.
+
+ The following attributes define the generic schema for directory
+ entries of type PRINTER:
+
+ printer-uri-supported RECOMMENDED Section 4.4.1
+ uri-security-supported RECOMMENDED Section 4.4.2
+ printer-name RECOMMENDED Section 4.4.3
+ printer-location RECOMMENDED Section 4.4.4
+ printer-info OPTIONAL Section 4.4.5
+ printer-more-info OPTIONAL Section 4.4.6
+ printer-make-and-model RECOMMENDED Section 4.4.8
+ charset-supported OPTIONAL Section 4.4.15
+ generated-natural-language-
+ supported OPTIONAL Section 4.4.17
+ document-format-supported RECOMMENDED Section 4.4.19
+ color-supported RECOMMENDED Section 4.4.23
+ finishings-supported OPTIONAL Section 4.2.6
+ number-up-supported OPTIONAL Section 4.2.7
+ sides-supported RECOMMENDED Section 4.2.8
+ media-supported RECOMMENDED Section 4.2.11
+ printer-resolution-supported OPTIONAL Section 4.2.12
+ print-quality-supported OPTIONAL Section 4.2.13
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+deBry, et al. Experimental [Page 167]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+17. APPENDIX F: Change History for the IPP Model and Semantics document
+
+ The following substantive changes and major clarifications have been
+ made to this document from the June 30, 1998 version based on the
+ interoperability testing that took place September 23-25 1998 and
+ subsequent mailing list and meeting discussions. They are listed in
+ the order of occurrence in the document. These changes are the ones
+ that might affect implementations. Clarifications that are unlikely
+ to affect implementations are not listed. The issue numbers refer to
+ the IPP Issues List which is available in the following directory:
+
+ ftp://ftp.pwg.org/pub/pwg/ipp/approved-clarifications/
+
+ Section Description
+
+ global Replaced TLS references with SSL3 references as agreed with
+ our Area Director on 11/12/1998.
+
+ global Removed the indications that some of these IPP documents
+ are informational, since the intent is now to publish all
+ IPP/1.0 documents as informational as agreed with our Area
+ Director on 11/12/1998.
+
+ 3.1.2, Clarify that the IPP object SHOULD NOT validate the
+ 16.3.3 range of the request-id being 1 to 2**31-1, but accepts
+ [now ipp- and returns any value. Clients MUST still keep in the
+ iig] range 1 to 2**31 though. If the request is terminated
+ before the complete "request-id" is received, the IPP
+ object rejects the request and returns a response with a
+ "request-id" of 0 (Issue 1.36).
+
+ 3.1.4.1, Clarified that when a client submits a request in a
+ 13.1.4.14 charset that is not supported, the IPP object SHOULD
+ return any 'text' or 'name' attributes in the 'utf-8'
+ charset, if it returns any, since clients and IPP
+ objects MUST support 'utf-8'. (Issue 1.19)
+
+ 3.1.4.1 Clarified Section 3.1.4.1 Request Operation Attributes
+ that a client MAY use the attribute level natural
+ language override (text/nameWithLanguage) redundantly in
+ a request. (Issue 1.46)
+
+ 3.1.4.2 Clarified Section 3.1.4.2 Response Operation Attributes
+ that an IPP object MAY use the attribute level natural
+ language override (text/nameWithLanguage) redundantly in
+ a response. (Issue 1.46)
+
+
+
+
+
+deBry, et al. Experimental [Page 168]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ 3.1.6 Clarified section 3.1.6: If the Printer object supports
+ the "status-message" operation attribute, it NEED NOT
+ return a status message for the following error status
+ codes: 'client-error-bad-request', 'client-error-
+ charset-not-supported', 'server-error-internal-error',
+ 'server-error-operation-not-supported', and 'server-
+ error-version-not-supported'.
+
+ 3.2.1.1 Clarified that if a client is not supplying any Job
+ Template attributes in a request, the client SHOULD omit
+ Group 2 rather than sending an empty group. However, a
+ Printer object MUST be able to accept an empty group.
+ This makes [RFC2566] agree with [RFC2565]. (Issue 1.16)
+
+ 3.2.1.2, Clarified that if an IPP object is not returning any
+ 3.2.5.2, Unsupported Attributes in a response, the IPP object
+ 3.2.6.2, SHOULD omit Group 2 rather than sending an empty group.
+ 3.3.1.2, However, a client MUST be able to accept an empty group.
+ 3.3.3.2, This makes [RFC2566] agree with [RFC2565]. (Issue 1.17)
+ 3.3.4.2
+
+ 3.2.1.2, Clarified that an IPP object MUST treat an unsupported
+ 13.1.2.2, attribute syntax supplied in a request in the same way
+ 13.1.4.12 as an unsupported value. The IPP object MUST return the
+ attribute, the attribute syntax, and the value in the
+ Unsupported Attributes group. (Issue 1.26)
+
+ 3.2.5.2, Clarified for Get-Printer-Attributes, Get-Jobs, and Get-
+ 3.2.6.2, Job-Attributes that an IPP object MUST return
+ 3.3.4.2, 'successful-ok-ignored-or-substituted-attributes' (0x1),
+
+ 13.1.2.1, rather than 'successful-ok' (0x0), when a client
+ 13.1.2.2, supplies unsupported attributes as values of the
+ 13.1.4.12 'requested-attributes' operation attribute. (Issue
+ 1.24)
+ Also clarified that the response NEED NOT contain the
+ "requested-attributes" operation attribute with any
+ supplied values (attribute keywords) that were requested
+ by the client but are not supported by the IPP object.
+ (Issue 1.18)
+
+ 3.2.6.2 Deleted the job-level natural language override (NLO)
+ 4.1.1.2 from Section 3.2.6.2 Get-Jobs Response so that all
+ 4.3.24 operation responses are the same with respect to NLO.
+ (Issue 1.47)
+
+
+
+
+
+
+deBry, et al. Experimental [Page 169]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ 3.3.1 Clarified that an IPP Printer that supports the Create-
+ Job operation MUST handle the situation when a client
+ does not supply Send-Document or Send-URI operations
+ within a one- to four-minute time period. Also
+ clarified that a client MUST send documents in a multi-
+ document job without undue or unbounded delay. (Issue
+ 1.28)
+
+ 3.3.3 Clarified that the IPP object MUST reject a Cancel-Job
+ request if the job is in 'completed', 'canceled', or
+ 'aborted' job states. (Issue 1.12)
+
+ 4.1.2.3 Added this new sub-section: it specifies that
+ nameWithoutLanguage plus the implicit natural language
+ matches nameWithLanguage, if the values and natural
+ languages are the same. Also added that keyword never
+ matches nameWithLanguage or nameWithoutLanguage.
+ Clarified that if both have countries, that the
+ countries SHOULD match as well. If either do not, then
+ the country field SHOULD be ignored. (Issues 1.33 and
+ 1.34)
+
+ 4.1.5 Clarified regarding the case-insensitivity of URLs to
+ refer only to the RFCs that define them. (Issue 1.10)
+
+ 4.1.11 Clarified that 'boolean' is not a full-sized integer.
+ (Issue 1.38)
+
+ 4.1.15 Clarified that 'resolution' is not three full-sized
+ integers. (Issue 1.20)
+
+ 4.2.* Clarified that standard values are keywords or enums,
+ not names. (Issue 1.49).
+
+ 4.2.4 Added the 'single-document-new-sheet' value to Section
+ 4.2.4 multiple-document-handling. (Issue 1.54)
+
+ 4.4.18, Clarified that the "document-format-default" and
+ 4.4.19 "document-format-supported" Printer Description
+ attributes are REQUIRED to agree with the table. (Issue
+ 1.4)
+
+ 4.4.21 Changed "queued-job-count" from OPTIONAL to RECOMMENDED.
+ (Issue 1.14)
+
+
+
+
+
+
+
+deBry, et al. Experimental [Page 170]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ 4.4.28 Clarified that the implementation supplied value for the
+ "multiple-operation-time-out" attribute SHOULD be
+ between 30 and 240 seconds, though the implementation
+ MAY allow the administrator to set values, and MAY allow
+ values outside this range. (Issue 1.28)
+
+ 5.1, Clarified Client Conformance that if a client supports
+ 5.2.5 an attribute of 'text' attribute syntax, that it MUST
+ support both the textWithoutLanguage and the
+ textWithLanguage forms. Same for 'name' attribute
+ syntax. Same for an IPP object (Issue 1.48)
+
+ 6.5, Added new section to allow Attribute Groups to be
+ 12.8 registered as extensions for being passed in operation
+ requests and responses. (Issue 1.25)
+
+ 7. Updated the table of text and name attributes to agree
+ with Section 4.2.
+
+ 8.5 Added a new section RECOMMENDING that the Get-Jobs
+ SHOULD return non-IPP jobs whether or not assigning them
+ a job-id and job-uri. Also RECOMMENDED generating, if
+ possible, job-id and job-uri and supporting other IPP
+ operations on foreign jobs as an implementer option.
+ (Issue 1.32)
+
+ 9. Updated document references.
+
+ 13.1.4.14 Clarified 'client-error-charset-not-supported' that
+ 'utf-8' must be used for any 'text' or 'name' attributes
+ returned in the error response (Issue 1.19).
+
+ 13.1.5.9 Added a new error code 'server-error-job-canceled'
+ (0x0508) to be returned if a job is canceled by another
+ client or aborted by the IPP object while the first
+ client is still sending the document data. (Issue 1.29)
+
+ 15.3, Moved these sections recommending operation processing
+ 15.4 steps to the new Implementer's Guide (informational).
+ There indicated that all of the error checks are not
+ required, so an IPP object MAY be forgiving and accept
+ non-conforming requests. However, a conforming client
+ MUST supply requests that would pass all of the error
+ checks indicated. (Issue 1.21)
+
+
+
+
+
+
+
+deBry, et al. Experimental [Page 171]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+ 16 Changed directory schema attributes from REQUIRED to
+ RECOMMENDED. Changed some of the OPTIONAL to
+ RECOMMENDED to agree with the SLP template. Changed the
+ "charset-supported" and "natural-language-supported"
+ from REQUIRED to OPTIONAL. Recommended that the names
+ be the same in a directory entry as the IPP attribute
+ names. (Issue 1.53)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+deBry, et al. Experimental [Page 172]
+
+RFC 2566 IPP/1.0: Model and Semantics April 1999
+
+
+18. Full Copyright Statement
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+deBry, et al. Experimental [Page 173]
+
diff --git a/standards/rfc2567.txt b/standards/rfc2567.txt
new file mode 100644
index 000000000..d5ef440be
--- /dev/null
+++ b/standards/rfc2567.txt
@@ -0,0 +1,2411 @@
+
+
+
+
+
+
+Network Working Group F.D. Wright
+Request for Comments: 2567 Lexmark International
+Category: Experimental April 1999
+
+
+ Design Goals for an Internet Printing Protocol
+
+Status of this Memo
+
+ This memo defines an Experimental Protocol for the Internet
+ community. It does not specify an Internet standard of any kind.
+ Discussion and suggestions for improvement are requested.
+ Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+IESG Note
+
+ This document defines an Experimental protocol for the Internet
+ community. The IESG expects that a revised version of this protocol
+ will be published as Proposed Standard protocol. The Proposed
+ Standard, when published, is expected to change from the protocol
+ defined in this memo. In particular, it is expected that the
+ standards-track version of the protocol will incorporate strong
+ authentication and privacy features, and that an "ipp:" URL type will
+ be defined which supports those security measures. Other changes to
+ the protocol are also possible. Implementers are warned that future
+ versions of this protocol may not interoperate with the version of
+ IPP defined in this document, or if they do interoperate, that some
+ protocol features may not be available.
+
+ The IESG encourages experimentation with this protocol, especially in
+ combination with Transport Layer Security (TLS) [RFC2246], to help
+ determine how TLS may effectively be used as a security layer for
+ IPP.
+
+Abstract
+
+ This document is one of a set of documents, which together describe
+ all aspects of a new Internet Printing Protocol (IPP). IPP is an
+ application level protocol that can be used for distributed printing
+ using Internet tools and technologies. This document takes a broad
+ look at distributed printing functionality, and it enumerates real-
+ life scenarios that help to clarify the features that need to be
+ included in a printing protocol for the Internet. It identifies
+ requirements for three types of users: end users, operators, and
+
+
+
+Wright Experimental [Page 1]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ administrators. The design goals document calls out a subset of end
+ user requirements that are satisfied in IPP/1.0. Operator and
+ administrator requirements are out of scope for version 1.0.
+
+ The full set of IPP documents includes:
+
+ Design Goals for an Internet Printing Protocol (this document)
+ Rationale for the Structure and Model and Protocol for the
+ Internet Printing Protocol [RFC2568]
+ Internet Printing Protocol/1.0: Model and Semantics [RFC2568]
+ Internet Printing Protocol/1.0: Encoding and Transport [RFC2565]
+ Internet Printing Protocol/1.0: Implementer's Guide [ipp-iig]
+ Mapping between LPD and IPP Protocols [RFC2569]
+
+ The "Rationale for the Structure and Model and Protocol for the
+ Internet Printing Protocol" document describes IPP from a high level
+ view, defines a roadmap for the various documents that form the suite
+ of IPP specifications, and gives background and rationale for the
+ IETF working group's major decisions.
+
+ The "Internet Printing Protocol/1.0: Model and Semantics" document
+ describes a simplified model consisting of abstract objects, their
+ attributes, and their operations that is independent of encoding and
+ transport. The model consists of a Printer and a Job object. The
+ Job optionally supports multiple documents. IPP 1.0 semantics allow
+ end-users and operators to query printer capabilities, submit print
+ jobs, inquire about the status of print jobs and printers, and cancel
+ print jobs. This document also addresses security,
+ internationalization, and directory issues.
+
+ The "Internet Printing Protocol/1.0: Encoding and Transport" document
+ is a formal mapping of the abstract operations and attributes defined
+ in the model document onto HTTP/1.1. It defines the encoding rules
+ for a new Internet media type called "application/ipp".
+
+ The "Internet Printing Protocol/1.0: Implementer's Guide" document
+ gives insight and advice to implementers of IPP clients and IPP
+ objects. It is intended to help them understand IPP/1.0 and some of
+ the considerations that may assist them in the design of their client
+ and/or IPP object implementations. For example, a typical order of
+ processing requests is given, including error checking. Motivation
+ for some of the specification decisions is also included.
+
+ The "Mapping between LPD and IPP Protocols" document gives some
+ advice to implementers of gateways between IPP and LPD (Line Printer
+ Daemon) implementations.
+
+
+
+
+
+Wright Experimental [Page 2]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+TABLE OF CONTENTS
+
+ 1. INTRODUCTION.....................................................4
+ 2. TERMINOLOGY......................................................4
+ 3. DESIGN GOALS.....................................................6
+ 3.1. End-user.......................................................6
+ 3.1.1. Finding or locating a printer................................6
+ 3.1.2. Create an instance of the printer............................7
+ 3.1.3. Viewing the status and capabilities of a printer.............7
+ 3.1.4. Submitting a print job.......................................8
+ 3.1.5. Viewing the status of a submitted print job..................9
+ 3.1.6. Canceling a Print Job........................................9
+ 3.2. Operator (NOT REQUIRED FOR V1.0)...............................9
+ 3.2.1. Alerting.....................................................9
+ 3.2.2. Changing Print and Job Status...............................10
+ 3.3. Administrator (NOT REQUIRED FOR v1.0).........................10
+ 4. OBJECTIVES OF THE PROTOCOL......................................10
+ 4.1. SECURITY CONSIDERATIONS.......................................11
+ 4.2. Interaction with LPD (RFC1179)................................12
+ 4.3. Extensibility.................................................12
+ 4.4. Firewalls.....................................................13
+ 4.5. Internationalization..........................................13
+ 5. IPP SCENARIOS...................................................13
+ 5.1. Printer Discovery.............................................14
+ 5.2. Driver Installation...........................................15
+ 5.3. Submitting a Print Job........................................15
+ 5.4. Getting Status/Capabilities...................................16
+ 5.5. Asynchronous Notification.....................................17
+ 5.6. Job Canceling.................................................17
+ 6. Security Considerations.........................................18
+ 7. REFERENCES......................................................18
+ 8. ACKNOWLEDGMENTS.................................................19
+ 9. AUTHOR'S ADDRESS................................................19
+ 10. APPENDIX - DETAILED SCENARIOS..................................20
+ 10.1. Printer discovery within an enterprise.......................20
+ 10.2. Printer discovery across enterprises.........................21
+ 10.3. Printer discovery on the Internet -logical operations........21
+ 10.4. Printer discovery on the Internet - authentication...........22
+ 10.5. Driver Download..............................................23
+ 10.6. Submitting a print job as a file.............................24
+ 10.7. Submitting a print job with two documents....................24
+ 10.8. Submitting a print job as a file, printing fails.............25
+ 10.9. Submitting a print job with authentication, PRIVACY and
+ payment......................................................26
+ 10.10. Submitting a print job with decryption error................27
+ 10.11. Submitting a print job with authentication..................28
+ 10.12. Submitting a print job generated dynamically................29
+ 10.13. Submitting a print job with a Printer jam - CANCELED........29
+
+
+
+Wright Experimental [Page 3]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ 10.14. Submitting a print job with a Printer jam - recovered.......30
+ 10.15. Submitting a print job with server pull.....................31
+ 10.16. Submitting a print job with referenced resources............32
+ 10.17. Getting Capabilities........................................33
+ 10.17.1. Submission Attributes.....................................33
+ 10.17.2. Printer Capabilities......................................33
+ 10.18. Getting Status..............................................34
+ 10.18.1. Printer State/Status......................................34
+ 10.18.2. Job Status................................................34
+ 10.18.3. Status of All My Jobs.....................................34
+ 10.19. Asynchronous Notification...................................35
+ 10.19.1. Job Completion............................................35
+ 10.19.2. Job Complete with Data....................................35
+ 10.19.3. Print Job Fails...........................................35
+ 10.20. Cancel a job................................................36
+ 10.21. End to end Scenario - within an enterprise..................36
+ 10.22. End to end Scenario - across enterprises....................37
+ 10.23. End to End Scenario - on the internet.......................40
+ 11. Full Copyright Statement.......................................43
+
+1. INTRODUCTION
+
+ The IPP protocol is heavily influenced by the printing model
+ introduced in the Document Printing Application (DPA) [ISO10175]
+ standard. Although DPA specifies both end user and administrative
+ features, IPP version 1.0 (IPP/1.0) focuses only on end user
+ functionality.
+
+2. TERMINOLOGY
+
+ Internet Printing for the purposes of this document is the
+ application of Internet tools, programs, servers and networks to
+ allow end-users to print to a remote printer using, after initial
+ setup or configuration, the same methods, operations and paradigms as
+ would be used for a locally attached or a local area network attached
+ printer. This could include the use of HTTP servers and browsers and
+ other applications for providing static, dynamic and interactive
+ printer locating services, user installation, selection,
+ configuration, print job submission, printer capability inquiry and
+ status inquiry of remote printers and jobs.
+
+ For the purposes of this document, a WEB Browser is software
+ available from a number of sources including but not limited to the
+ following: Microsoft Internet Explorer, NCSA Mosaic, Netscape
+ Navigator, Sun Hot Java!. The major task of these products is to use
+ the Hypertext Transport Protocol (HTTP) to retrieve, interpret and
+ display Hypertext Markup Language (HTML). These products are often a
+ part of a complete Internet Printing system because they are often
+
+
+
+Wright Experimental [Page 4]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ used as a means of obtaining the status of or more information about
+ the printing system; however, they may not be present in all
+ implementations.
+
+ Throughout this document, 'printer' shall be interpreted to include
+ any device which is capable of marking on a piece of media using any
+ available technology. These design goals do not include support for
+ multi-tiered printing solutions involving servers (single or
+ multiple) logically in front of the actual printing device yet all
+ such configurations shall be supported but shall appear to the end-
+ user as only a single device.
+
+ Throughout this document 'driver' refers to the code installed in
+ some client operating system to generate the print data stream for
+ the intended printer. Some computing environments may not include a
+ separate printer driver. Rather, the generation of the proper print
+ data stream is accomplished in an application on that computer. How
+ such a computer environment or application is updated to support a
+ new printer now made available using IPP is outside the scope of IPP.
+ The actual details for installing a printer driver are operating
+ system dependent and are also outside the scope of IPP. See also
+ section 4.1 (SECURITY CONSIDERATIONS) for security implications of
+ driver download and installation.
+
+ The IPP protocol will support the following physical configurations:
+
+ - An IPP client talking to an IPP Printer object imbedded in a
+ single, physical output device.
+ - An IPP Client talking to a server containing one or more IPP
+ Printer objects. Each Printer object is associated with exactly one
+ physical output device supported by the server. The protocol
+ between the server and the output devices is undefined.
+ - An IPP Client talking to an IPP Printer object in a server. The
+ Printer object is associated with one or more physical output
+ devices, but the client only sees the Printer object, which is an
+ abstraction and represents all of the associated physical output
+ devices. The protocol between the server and the physical output
+ devices is undefined.
+
+ Throughout this document, certain design goals will be identified as
+ not being a part of version 1.0 (or V1.0) of the protocol or as being
+ satisfied by means outside of IPP. IPP is assumed to be one part, an
+ enabler, of a complete Internet Printing solution. For example
+ printer instance creation is not performed by but is enabled by the
+ protocol. Globally, none of the operator or administrators wants and
+ needs are included in the design goals for version 1.0. Some of the
+ end-user wants and needs may also be excluded from version 1.0 and
+ will be so noted in the description of them. Subsequent versions of
+
+
+
+Wright Experimental [Page 5]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ the protocol (e.g. V2.0) may include support for these initially
+ excluded wants and needs.
+
+3. DESIGN GOALS
+
+ The next three sections identify the design goals for an Internet
+ printing protocol from three roles assumed by humans: end-user,
+ operator, and administrator. The goals defined here are only those
+ that need to be addressed by an Internet printing protocol. Other
+ wants and needs, such as that the operator needs physical access to
+ the printer (e.g. to be able to load paper or clear jams) are not
+ covered by this document. Section 5 contains scenarios which provide
+ more detailed examples of the entire process including discovery,
+ status, printing and end-of-job reporting.
+
+3.1. END-USER
+
+ An end-user of a printer accepting jobs through the Internet is one
+ of the roles in which humans act. The end-user is the person that
+ will submit a job to be printed on the printer.
+
+ The wants and needs of the end-user are broken down into six
+ categories: finding/locating a printer, creating a local instance of
+ a printer, viewing printer status, viewing printer capabilities,
+ submitting a print job, viewing print job status, altering the
+ attributes of a print job.
+
+3.1.1. Finding or locating a printer.
+
+ End-users want to be able to find and locate printers to which they
+ are authorized to print. They want to be able to perform this
+ function using a standard WEB browser or other application. Multiple
+ criteria can be applied to find the printers needed. These criteria
+ include but are not limited to:
+
+ - by name (Printer 1, Joes-color-printer, etc.)
+ - by geographic location (bldg 1, Kentucky, etc.)
+ - by capability or attribute (color, duplex, legal paper, etc.)
+
+ Additionally, while it is outside of scope of IPP, end-users want to
+ be able to limit the scope of their searching to:
+
+ - inside a functional sub-domain
+ - include only a particular domain (lexmark.com)
+ - exclude specified domains
+
+
+
+
+
+
+Wright Experimental [Page 6]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ While an Internet printing protocol may not of itself include this
+ function, IPP must define and enable a directory schema which will
+ provide the necessary information for a directory service
+ implementation to consistently represent printers by their IPP
+ attributes.
+
+3.1.2. Create an instance of the printer.
+
+ After finding the desired printer, an end-user needs to be able to
+ create a local instance of that printer within the end-user operating
+ system or desktop. This local instance will vary depending upon the
+ printing paradigm of the operating system. For example, some UNIX
+ users will only want a queue or a reference to a remote printer
+ created on their machine while other UNIX users and Windows NT users
+ will want the queue and also the necessary icons and registry entries
+ to be created and initialized. Where required, drivers may need to
+ be downloaded from some repository and installed on the computer.
+ All necessary decompressing, unpacking, and other installation
+ actions should occur without end-user interaction or intervention
+ excepting initial approval by the end-user. Once the local instance
+ of the printer has been installed, it shall appear to the end-user of
+ the operating system and to the applications running there as any
+ other printer (local, local area network connected, or network
+ operating system connected) on the end-user desktop or environment.
+ IPP's role in this goal is simply to enable the creation of the
+ printer instance providing information such as where to locate a
+ printer driver for this printer, as an attribute of an IPP Printer.
+
+3.1.3. Viewing the status and capabilities of a printer.
+
+ Before using a selected printer or, in fact at any time, the end-user
+ needs the ability to verify the characteristics and status of both
+ printers and jobs queued for that printer. When checking the
+ characteristics of a printer, the end-user typically wants to be able
+ to determine the capability of the device, e.g.:
+
+ - supported media, commonly paper, by size and type
+ - paper handling capability, e.g. duplex, collating, finishing
+ - color capability
+
+ When checking the status of the printer and its print jobs, the end-
+ user typically wants to be able to determine:
+
+ - is the printer on-line?
+ - what are the defaults to be used for printing?
+ - how many jobs are queued for the printer?
+ - how are job priorities assigned? (outside the scope of IPP)
+
+
+
+
+Wright Experimental [Page 7]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+3.1.4. Submitting a print job.
+
+ Once the desired printer has been located and installed, the end-user
+ wants to print to that printer from normal applications using
+ standard methods. These normal applications include such programs as
+ word processors, spreadsheets, data-base applications, WEB browsers,
+ production printing applications, etc. Additionally, the end-user
+ may want to print a file already existing on the end-user's computer
+ -- "simple push". In addition to printing from an application and
+ simple push, the end-user needs to have the ability to submit a print
+ job by reference. Printing by reference is defined to mean as
+ submitting a job by providing a reference to an existing document.
+ The reference, a URI, will be resolved before the actual print
+ process occurs. Submitting a job by reference relieves the user from
+ downloading the document from the remote server and then sending it
+ via IPP to the printer. This saves both time and network bandwidth.
+
+ Some means shall be provided to determine if the format of a job
+ matches the capability of the printer. This can be done by one of
+ the following (all of which are outside of scope of the IPP
+ protocol):
+
+ - the end-user selects the correct printer driver
+ - the printer automatically selects the proper interpreter
+ - the end-user uses some other manual procedure.
+
+ A standard action shall be defined should the job's requirements not
+ match the capabilities of the printer.
+
+ Because the end-user does not want to know the details of the
+ underlying printing process, the protocol must support job-to-printer
+ capability matching (all implementations are not necessarily required
+ to implement this function.) This matching capability requires
+ knowing both the printer's capabilities and attributes and those
+ capabilities and attributes required by the job. Actions taken when
+ a print job requires capabilities or attributes that are not
+ available on the printer vary and can include but are not limited to:
+
+ - rejecting the print job
+ - redirecting the print job to another printer (Not in V1.0)
+ - printing the job, accepting differences in the appearance
+
+ Print jobs will also be submitted by background or batch applications
+ without human intervention.
+
+ End-users need the ability to set certain print job parameters at the
+ time the job is submitted. These parameters include but are not
+ limited to:
+
+
+
+Wright Experimental [Page 8]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ - number of copies
+ - single or two sided printing
+ - finishing
+ - job priority
+
+3.1.5. Viewing the status of a submitted print job.
+
+ After a job has been submitted to a printer, the end-user needs a way
+ to view the status of that job (i.e. job waiting, job printing, job
+ done) and to determine where the job is in the print queue.
+
+ In addition to the need to inquire about the status of a print job,
+ automatic notification of the completion of that job is also
+ required.
+
+ Notification means are not defined by the protocol but the protocol
+ must provide a means of enabling and disabling the notification.
+
+3.1.6. Canceling a Print Job
+
+ While a job is waiting to be printed or has been started but not yet
+ completed, the original creator/submitter of the print job (i.e. the
+ end-user) shall be able to cancel the job entirely (job is waiting)
+ or the remaining portion of it (job is printing.) Altering the print
+ job itself is not a V1.0 design goal.
+
+3.2. OPERATOR (NOT REQUIRED FOR V1.0)
+
+ An operator of a printer accepting jobs through the Internet is one
+ of the roles in which humans act. The operator has the
+ responsibility of monitoring the status of the printer as well as
+ managing and controlling the jobs at the device. These
+ responsibilities include but are not limited to the replenishing of
+ supplies (ink, toner, paper, etc.), the clearing of minor errors
+ (paper jams, etc.) and the re-prioritization of end-user jobs.
+ Operator wants and needs will not be addressed by V1.0 of the
+ protocol.
+
+ The wants and needs of the operator include all those of the end-user
+ but may include additional privileges. For example, an operator may
+ be able to view all print jobs on a printer while the end-user might
+ only be able to see his own jobs.
+
+3.2.1. Alerting.
+
+ One of the required operator functions is having the ability to
+ discover or to be alerted to changes in the status of a printer
+ particularly those changes that cause a printer to stop printing and
+
+
+
+Wright Experimental [Page 9]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ to be able to correct those problems. As such, an Internet printing
+ protocol shall be able to alert a designated operator or operators to
+ these conditions such as 'out of paper', 'out of ink', etc.
+ Additionally. the operator shall be able to, asynchronous to other
+ printer activity, inquire as to a printer's or a job's status.
+
+3.2.2. Changing Print and Job Status.
+
+ Another of the required operator functions is the ability to affect
+ changes to printer and job status remotely. For example, the
+ operator will need to be able to re-prioritize or cancel any print
+ jobs on a printer to which the operator has authority.
+
+3.3. ADMINISTRATOR (NOT REQUIRED FOR V1.0)
+
+ An administrator of a printer accepting jobs through the Internet is
+ one of the roles in which humans act. The administrator has the
+ responsibility of creating the printer instances and controlling the
+ authorization of other end-users and operators. Administrator wants
+ and needs will not be addressed by V1.0 of the protocol.
+
+ The wants and needs of the administrator include all those of the
+ end-user and, in some environments, some or all of those of the
+ operator. Minimally, the administrator must also have the tools,
+ programs, utilities and supporting protocols available to be able to:
+
+ - create an instance of a printer
+ - create, edit and maintain the list of authorized end-users
+ - create, edit and maintain the list of authorized operators
+ - create, edit and maintain the list of authorized
+ administrators
+ - create, customize, change or otherwise alter the manner in
+ which the status capabilities and other information about printers
+ and jobs are presented
+ - create, customize, or change other printer or job features
+ - administrate billing or other charge-back mechanisms
+ - create sets of defaults
+ - create sets of capabilities
+
+ The administrator must have the capability to perform all the above
+ tasks locally or remotely to the printer.
+
+4. OBJECTIVES OF THE PROTOCOL
+
+ The protocol to be defined by an Internet printing working group will
+ address the wants and needs of the end-user (V1.0). It will not, at
+ least initially, address the operator or administrator wants and
+ needs (V2.0).
+
+
+
+Wright Experimental [Page 10]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ The protocol defined shall be independent of the operating system of
+ both the client and the server. Generally, any platform capable of
+ supporting a WEB Browser should be capable of being a client.
+ Generally, any platform providing a WEB/HTTP server and printing
+ services should be capable of being a server. Usage of the WEB
+ Browser and Server is not required for IPP; the operating system,
+ operating system extensions or other applications may provide IPP
+ functionality directly.
+
+ In many environments such as Windows 95, Windows NT and OS/2, the
+ print data is created and transmitted to the printer on the fly
+ rather than being created, spooled and then transmitted to the
+ printer (a typical UNIX method.) The Internet Printing Protocol must
+ properly handle either methodology and make this transparent to the
+ end-user.
+
+4.1. SECURITY CONSIDERATIONS
+
+ It is required that the Internet Printing Protocol be able to operate
+ within a secure environment. Wherever reasonable, IPP ought to make
+ use of existing security protocols and services. IPP will not invent
+ new security features when the design goals described in this
+ document can be met by existing protocols and services. Examples of
+ such services include Secure Socket Layer Version 3 (SSL3) [SSL] and
+ HTTP Digest Access Authentication [RFC2069]. Note: SSL3 is not on
+ the IETF standards track.
+
+ Since we cannot anticipate the security levels or the specific
+ threats that any given IPP print administrator may be concerned with,
+ IPP must be capable of operating with different security mechanisms
+ and policies as required by the individual installation. The initial
+ security needs of IPP are derived from two primary considerations.
+ First, the printing environments described in this document take into
+ account that the client, the Printer, and the document to be printed
+ may each exist in different security domains. When objects are in
+ different security domains the design goals for authentication and
+ message protection may be much stronger than when they are all in the
+ same domain.
+
+ Secondly, the sensitivity and value of the content being printed will
+ vary from one instance of a print job to another. For example, a
+ publicly available document does not need the same level of
+ protection as a payroll document does. Message protection design
+ goals include data origin authentication, privacy, integrity, and
+ non-repudiation.
+
+
+
+
+
+
+Wright Experimental [Page 11]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ In many environments (e.g. Windows, OS/2) a printer driver may be
+ needed to create the proper datastream for printer. This document
+ discusses downloading such a new driver from a variety of sources.
+ Downloading and installing any software, including drivers) on a
+ computer exposes that computer to a number of security risks
+ including but not limited to:
+
+ - defective software
+ - malicious software (e.g. Trojan horses)
+ - inappropriate software (i.e. software doing something
+ deemed unreasonable by the user.)
+
+ As such, proper security considerations and actions need to be taken
+ by the user and/or a system administrator to prevent the compromising
+ of the computer. Administrators should configure downloading
+ mechanism for printer drivers in such a way as to be able to verify
+ the source of driver software and encrypt or otherwise protect that
+ software during download.
+
+ Examples including security considerations can be found in sections 5
+ (IPP SCENARIOS) and 10 (APPENDIX - DETAILED SCENARIOS) later in this
+ document.
+
+4.2. INTERACTION WITH LPD (RFC1179)
+
+ Many versions of UNIX and in fact other operating systems provide a
+ means of printing as described in [RFC1179] (Line Printer Daemon
+ Protocol.) This document describes the file formats for the control
+ and data files as well as the messages used by the protocol. Because
+ of the simplistic approach taken by this protocol, many manufacturers
+ have include proprietary enhancements and extensions to 'lpd.'
+ Because of this divergence and due to other design goals described in
+ this document, there is no requirement for backward compatibility or
+ interoperability with 'lpd'. However, a mapping of LPD functionality
+ and IPP functionality shall be provided so as to enable a gateway
+ between LPD and IPP.
+
+4.3. EXTENSIBILITY
+
+ The Internet Printing Protocol shall be extensible by several means
+ that facilitate interoperability and prevent implementation
+ collisions:
+
+ - by providing a process whereby implementers can submit proposals
+ for registration of new attributes and new enumerated values for
+ existing attributes.
+
+
+
+
+
+Wright Experimental [Page 12]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ * that require review and approval. The Internet Assigned
+ Number Authority (IANA) will be the repository for such
+ accepted registration proposals after review.
+
+ * that do not require review and approval. IANA will be the
+ repository for such registrations.
+
+ - by providing syntax in the protocol so that implementers may add
+ private (i.e. unregistered) attributes and enumerated attribute
+ values.
+
+ - by providing versioning and negotiation so as to enable future
+ implementations of IPP to interoperate with implementations of
+ version 1.0 of IPP.
+
+4.4. FIREWALLS
+
+ As stated in section 3 Design Goals, Internet printing shall, by
+ definition, support printing from one enterprise to another. As
+ such, the Internet printing protocol must be capable of passing
+ through firewalls and/or proxy servers (where enabled by the firewall
+ administrator) preferably without modification to the existing
+ firewall technology.
+
+4.5. INTERNATIONALIZATION
+
+ Users of Internet printing will come from all over the world. As
+ such, where appropriate, internationalization and localization will
+ be enabled for the protocol.
+
+5. IPP SCENARIOS
+
+ Each of the scenarios in this section describes a specific IPP
+ operation, such as submitting a print job. Section 10 contains
+ several detailed flows for each scenario to provide additional
+ detail. The examples should not be considered exhaustive, but
+ illustrative of the functions and features required in the protocol.
+ Flows are intended to be protocol neutral. It is not assumed that all
+ of the functions and features described in these scenarios will
+ necessarily be supported directly by IPP or in version 1.0 of IPP.
+
+ See the IPP Model and Semantics document for details on
+ configurations of clients, servers and firewalls.
+
+
+
+
+
+
+
+
+Wright Experimental [Page 13]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+5.1. PRINTER DISCOVERY
+
+ Client Directory Service
+ Service
+
+ +----------------------------------------------------------- >
+ give me information on printers with these characteristics
+
+
+ < -----------------------------------------------------------+
+ Information on Printers matching these characteristics
+
+ The objective of printer discovery is to locate printers that meet
+ the client's wants and needs. The Directory Service should provide
+ enough information for the client to make an initial choice. The
+ client may have to connect to each individual Printer offered to get
+ more detail. Not all information available from the Directory
+ Service is obtained using IPP; some information may be
+ administratively provided.
+
+ The actual protocol used between client and Directory or Name Service
+ is considered outside the scope of IPP. Printer Discover is included
+ in the scenarios to provide design goals for the directory schema for
+ IPP Printers and to further define Printer attributes.
+
+ Characteristics that might be considered when locating a Printer
+ include:
+
+ - capabilities of the Printer, e.g. PDLs supported
+ - physical location, e.g. in building 010
+ - driver required and location
+ - cost per page to print (outside the scope of IPP)
+ - whether or not printer is access controlled
+ - whether or not usage requires client authentication
+ - whether or not Printer can be authenticated
+ - whether or not payment is required for printing (outside the scope
+ of IPP)
+ - maximum job size (spool size) (outside the scope of IPP)
+ - whether or not Printer support compression (outside the scope of
+ IPP)
+ - whether or not Printer supports encryption
+ - administrative limits on this Printer
+ - maximum number of copies per job
+ - maximum number of pages per job
+
+
+
+
+
+
+
+Wright Experimental [Page 14]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ Responses could additionally include:
+
+ - how to get more information
+ - web page
+ - telephone number
+ - help desk
+
+5.2. DRIVER INSTALLATION
+
+ Client Printer
+
+ +----------------------------------------------------------- >
+ Where can I find a driver & software to install it?
+
+
+ < -----------------------------------------------------------+
+ URIs for drivers and install software
+
+ Driver here refers to the code installed in some client operating
+ system to generate the print data stream for the intended printer.
+ The actual details for installing a printer driver are operating
+ system dependent and are also outside the scope of IPP. However, an
+ IPP printer or a directory service advertising an IPP Printer should
+ be capable of telling a client what drivers are available and/or
+ required, where they can be found, and provide pointers to
+ installation instructions, installation code or initialization
+ strings required to install the driver. See section 4.1 (SECURITY
+ CONSIDERATIONS) for security implications of driver download and
+ installation.
+
+5.3. SUBMITTING A PRINT JOB
+
+ Client IPP Printer
+
+ +----------------------------------------------------------- >
+ Here is a Print Job
+ - Job attributes
+ - Print data
+
+
+ < -----------------------------------------------------------+
+ Response
+
+ The protocol must support these sources of client data:
+
+ - Print data is a file submitted with the job
+ - Print data is generated on the fly by an application
+ - Print data is a file referenced by a URI
+
+
+
+Wright Experimental [Page 15]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ The protocol must handle overrun conditions in the printer and must
+ support overlapped printing and downloading of the file in devices
+ that are unable to spool files before printing them.
+
+ Every print request will have a response. Responses will indicate
+ success or failure of the request and provide information on failures
+ when they occur. Responses would include things like:
+
+ - Got the print job and queued it
+ - Got the print job and am printing it
+ - Got the print job, started to print it, but printing failed
+ - why it failed (e.g. unrecoverable PostScript error)
+ - state of the printer
+ - how much printed
+ - Got the print job but couldn't print it
+ - why it can't be printed
+ - state of the printer
+ - Got the print job but don't know what to do with it
+ - Didn't get a complete print job (e.g. communication failure)
+
+5.4. GETTING STATUS/CAPABILITIES
+
+ Client IPP Printer
+
+ +----------------------------------------------------------- >
+ Get status and/or capabilities of Printer
+
+
+ < -----------------------------------------------------------+
+ Status/Capabilities
+
+ Clients will need to get information about
+
+ - Static capabilities of the device
+ - Dynamic state of the Printer (e.g. out of paper)
+ - State of a specific job owned by this client
+ - State of all jobs owned by this client
+ - queued
+ - printing
+ - completed
+
+
+
+
+
+
+
+
+
+
+
+Wright Experimental [Page 16]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ - Job submission attributes supported/required
+ - scheduling attributes (e.g. priority)
+ - production attributes (e.g. number of copies)
+
+5.5. ASYNCHRONOUS NOTIFICATION
+
+ Client IPP Printer
+
+ +----------------------------------------------------------- >
+ Use the following method to notify me of Printer events
+
+ .
+ .
+ .
+ < -----------------------------------------------------------+
+ Asynchronous notification of Printer event
+
+ Clients must be able to request asynchronous notification for Printer
+ events such as
+
+ - job completion
+ - a fatal error that requires the job to be resubmitted
+ - a condition that severely impacts a queued job for this client
+ e.g. printer is out of paper
+
+ Note: end-user notification is a V1.0 design goal while operator
+ notification is for V2.0.
+
+5.6. JOB CANCELING
+
+ Client IPP Printer
+
+ +----------------------------------------------------------- >
+ Cancel the named job as indicated
+
+
+ < -----------------------------------------------------------+
+ Response (did it or not)
+
+ Similarly clients must be able to make changes to jobs which have
+ been submitted and are queued for printing. Changing of job
+ attributes should also be supported. Job modifications, holding and
+ releasing of jobs are not included in the design goals for IPP v1.0.
+
+
+
+
+
+
+
+
+Wright Experimental [Page 17]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+6. SECURITY CONSIDERATIONS
+
+ The security considerations for IPP are described in Section 4.1
+ above.
+
+7. REFERENCES
+
+ [ipp-iig] Hastings, T. and C. Manros, "Internet Printing
+ Protocol/1.0: Implementer's Guide", Work in Progress.
+
+ [RFC2569] Herriot, R., Hastings, T., Jacobs, N. and J. Martin,
+ "Mapping between LPD and IPP Protocols", RFC 2569, April
+ 1999.
+
+ [RFC2566] deBry, R., Hastings, T., Herriot, R., Isaacson, S. and P.
+ Powell, "Internet Printing Protocol/1.0: Model and
+ Semantics", RFC 2568, April 1999.
+
+ [RFC2565] Herriot, R., Butler, S., Moore, P. and R. Tuner, "Internet
+ Printing Protocol/1.0: Encoding and Transport", RFC 2565,
+ April 1999.
+
+ [RFC2568] Zilles, S., "Rationale for the Structure and Model and
+ Protocol for the Internet Printing Protocol", RFC 2568,
+ April 1999.
+
+ [ISO10175] ISO/IEC 10175, Document Printing Application, June 1996.
+
+ [RFC1179] McLaughlin, L., "Line Printer Daemon Protocol" RFC 1179,
+ August 1990.
+
+ [SSL] Netscape, The SSL Protocol, Version 3, (Text version
+ 3.02), November 1996.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Wright Experimental [Page 18]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+8. ACKNOWLEDGMENTS
+
+ This document draws heavily from preliminary work done by others
+ especially in the Printer Working Group (PWG). The author gratefully
+ acknowledges the specific contributions of:
+
+ Scott Isaacson Roger deBry
+ Novell Utah Valley State College
+ sisaacson@novell.com debryro@uvsc.edu
+
+ Carl-Uno Manros Robert Herriot
+ Xerox Sun
+ manros@cp10.es.xerox.com Robert.Herrior@pahv.xerox.xom
+
+ Tom Hastings Peter Zehler
+ Xerox Xerox
+ hastings@cp10.es.xerox.com Peter.Zehler@usa.xerox.com
+
+9. AUTHOR'S ADDRESS
+
+ F.D. (Don) Wright
+ Lexmark International
+ C14/035-3
+ 740 New Circle Rd
+ Lexington, KY 40550
+
+ Phone: 606-232-4808
+ Fax: 606-232-6740
+ EMail: don@lexmark.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Wright Experimental [Page 19]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+10. APPENDIX - DETAILED SCENARIOS
+
+ The following are more detailed scenarios illustrating how the
+ Internet Printing Protocol is expected to be used as a part of a
+ complete Internet Printing system. Some parts of the scenarios
+ include concepts, functions and information that may be outside of
+ the scope of version 1.0 of IPP (e.g. cost per page, payments means
+ available, etc.) The information contained herein is meant to be
+ generic. There may not be an exact wording or terminology match
+ between these scenarios and the implementation documents.
+
+10.1. PRINTER DISCOVERY WITHIN AN ENTERPRISE
+
+ A user wants to find a color Postscript printer in his/her enterprise
+ which will print transparencies. The client, directory service, and
+ printer are all behind the same corporate firewall. Because color
+ foils are expensive, printers of this type are access controlled and
+ require an account to be established so that printing can be billed
+ back to the using department. Note the request to find a printer
+ usable by Dept. J15. Drivers for all supported printers are
+ available from the server they are associated with. A help desk is
+ provided for end user support. The printer is unattended.
+
+ Client Directory Service
+
+ +---------------------------------------------------------- >
+ Find a printer with these characteristics
+ - prints color, prints transparencies
+ - prints Postscript
+ - is in building 003
+ - accessible by the client
+
+ < ----------------------------------------------------------+
+ Printer "Color-A"
+ - prints color, prints transparencies
+ - prints Postscript
+ - in room H-6, building 003
+ - driver ABC-Postscript-V1.3 required, here is URI
+ - cost is $.45 per page for color transparencies
+ - limit is 10 pages per job
+ - authentication required to use printer
+ - printer is unattended
+ - help desk at x5001
+
+ Printer "Color-B"
+ - prints color, prints transparencies
+ - prints Postscript
+ - in room J-10, building 003
+
+
+
+Wright Experimental [Page 20]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ - driver XYZ-Postscript-V2.4 required, here is URI
+ - cost is $1.25 page for color transparencies
+ - limit is 5 pages per job
+ - authentication is required to use printer
+ - printer is unattended
+ - help desk at x5001
+
+10.2. PRINTER DISCOVERY ACROSS ENTERPRISES
+
+ A user in Company A wants to find a public printer in a business
+ partner's enterprise (Company B) on which to print a purchase order.
+ The client is behind one corporate firewall and the directory service
+ and the printer are behind a different corporate firewall. Drivers
+ for all supported printers are available from the server they are
+ associated with. A web page is provided for end user support for
+ public printers.
+
+ Client Company B Directory Service
+
+ +---------------------------------------------------------- >
+ Find a printer with these characteristics
+ - prints black and white
+ - is in El Segundo, building A
+ - is a public printer
+
+ < ----------------------------------------------------------+
+ Printer "Public-A"
+ - prints black and white
+ - prints Postscript
+ - in El Segundo, room H-6, building A
+ - driver ABC-Postscript-V1.3 required, here is URI
+ - printer is public
+ - help available at http://xerox/elSegundo/publicPrinters
+
+ Printer "Public-B"
+ - prints black and white
+ - prints PCL/5e
+ - is in El Segundo, room J-10, building A
+ - driver XYZ-PCL-V2.4 required, here is URI
+ - printer is public
+ - help available at http://xerox/elSegundo/publicPrinters
+
+10.3. PRINTER DISCOVERY ON THE INTERNET -LOGICAL OPERATIONS
+
+ A student wants to print a paper on a printer at his neighborhood
+ Ink-o's print shop. The report was written using Microsoft Word. The
+ student is interested in the cost of printing since his budget is
+ limited. Note the use of logical operators to find this information.
+
+
+
+Wright Experimental [Page 21]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ Client Ink-o's Directory Service
+
+ +---------------------------------------------------------- >
+ Find a Printer with these characteristics
+ - prints color or black and white
+ - costs less than $.50 per page
+ - tell me about resolution and marking technology
+
+ < ----------------------------------------------------------+
+ Printer "Color-A"
+ - prints color
+ - 600 dpi laser printer
+ - prints Postscript
+ - driver ABC-Postscript-V1.3 required, here is URI
+ - cost is $.50 per page for color
+ - payment required prior to submitting print job
+ - here is URI for more information on Ink-o's
+
+ Printer "Mono-B"
+ - prints black and white
+ - 300 dpi inkjet printer
+ - prints Postscript
+ - driver XYZ-Postscript-V2.4 required, here is URI
+ - cost is $0.35 page for black and white
+ - payment required prior to submitting print job
+ - here is URI for more information on Ink-o's
+
+10.4. PRINTER DISCOVERY ON THE INTERNET - AUTHENTICATION
+
+ An executive in her hotel room is finishing an important presentation
+ on her laptop computer. She connects to a local print shop through
+ the web to get a copy of her charts printed for tomorrow's
+ presentation. She must find a print shop that is convenient to her
+ hotel and can print color transparencies. She wants to be sure that
+ the printer can be authenticated and can accept encrypted data.
+
+ Client SirZippy Directory Service
+
+ +---------------------------------------------------------- >
+ Find a Printer with these characteristics
+ - prints color transparencies
+ - is in Boulder, Colorado
+ - Printer can be authenticated
+ - Printer supports encryption
+
+
+
+
+
+
+
+Wright Experimental [Page 22]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ Tell me when you are open for business
+
+ < ----------------------------------------------------------+
+ Printer "Color-A"
+ - prints color transparencies
+ - prints Postscript
+ - driver ABC-Postscript-V1.3 required, here is URI
+ - payment required prior to submitting print job
+ - Printer can be authenticated
+ - Data can be encrypted
+ - Located at 1670 Pearl Street, Boulder, CO
+ - This Branch is open 24 hours a day
+
+
+ Printer "Color-B"
+ - prints color transparencies
+ - prints Postscript
+ - driver ABC-Postscript-V1.3 required, here is URI
+ - payment required prior to submitting print job
+ - Printer can be authenticated
+ - Data can be encrypted
+ - Located at 1220 Arapahoe, Boulder, CO
+ - This Branch is open from 9:00 am to 6:30 pm
+
+10.5. DRIVER DOWNLOAD
+
+ An end user in an enterprise wants to print a lengthy report on a
+ newly installed high speed PostScript printer. Since she will likely
+ use this printer often, she would like to download a driver and
+ install it on her workstation. She is running Windows 95. Note:
+ Driver download is not a V1.0 design goal.
+
+ Client IPP Printer
+
+ +---------------------------------------------------------- >
+ Tell me where to find print drivers for you
+
+
+
+ < ----------------------------------------------------------+
+ Driver install file is at
+ http://www.ibm.com/drivers/NP12a/Win95
+
+
+
+
+
+
+
+
+
+Wright Experimental [Page 23]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+10.6. SUBMITTING A PRINT JOB AS A FILE
+
+ An end-user wants to submit a print job. The print file already
+ exists on his workstation. The client and printer are behind the same
+ corporate firewall. The printer is available to anyone behind the
+ firewall and no authorization or authentication is required. The data
+ is pushed to the printer. The printer is capable of spooling the
+ output. No errors occur.
+
+ Client IPP Printer
+
+ +---------------------------------------------------------- >
+ Here is a print job
+ - job name = MyJob
+ - notify me by email when done printing
+ - print on iso-a4-white paper
+ - print on both sides of the paper
+ - return status of the printer in response
+ - document is in Postscript format
+ - here is the document to print
+
+ < ----------------------------------------------------------+
+ Print job accepted and spooled
+ - job id = #12345
+ - current state of print job = spooled
+ - submission time = 02/12/97, 15:35
+ - printer state = printing
+
+10.7. SUBMITTING A PRINT JOB WITH TWO DOCUMENTS
+
+ An end-user wants to submit a print job. The print file already
+ exists on his workstation. The client and printer are behind the same
+ corporate firewall. The printer is available to anyone behind the
+ firewall and no authorization or authentication is required. The data
+ is pushed to the printer. The job consists of two separate documents.
+ The printer is capable of spooling the output. No errors occur.
+
+ Client IPP Printer
+
+ +---------------------------------------------------------- >
+ Here is a print job
+ - job name = MyJob
+ - notify me by email when done printing
+ - print on iso-a4-white paper
+ - print on both sides of the paper
+ - return status of the printer in response
+
+ < ----------------------------------------------------------+
+
+
+
+Wright Experimental [Page 24]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ Print job accepted and spooled
+ - job id = #12345
+ - submission time = 02/12/97, 15:35
+ +---------------------------------------------------------- >
+ - here is the document to print
+
+ < ----------------------------------------------------------+
+ - OK
+
+ +---------------------------------------------------------- >
+ - here is the document to print, it is the last document.
+
+ < ----------------------------------------------------------+
+ - OK
+
+10.8. SUBMITTING A PRINT JOB AS A FILE, PRINTING FAILS
+
+ An end-user wants to submit a print job. The print file already
+ exists on his workstation. The client and printer are behind the same
+ corporate firewall. The printer is available to anyone behind the
+ firewall and no authorization or authentication is required. The data
+ is pushed to the printer. The printer is not capable of spooling the
+ output so it begins printing while still receiving the file. An error
+ occurs and the printer cannot complete printing (in this case the
+ user requires A4 paper and that paper size is not available on the
+ printer.)
+
+ Client IPP Printer
+
+ +---------------------------------------------------------- >
+ Here is a print job
+ - job name = MyJob
+ - notify me by email when done printing
+ - print on iso-a4-white paper
+ - print on both sides of the paper
+ - return status of the printer in response
+ - document is in Postscript format
+ - here is the document to print
+
+ < ----------------------------------------------------------+
+ Print job accepted
+
+ - printing failed
+ - current state of print job = canceled (A4 not available)
+ - submission time = 02/12/97, 15:35
+ - printer state = ready
+
+
+
+
+
+Wright Experimental [Page 25]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+10.9. SUBMITTING A PRINT JOB WITH AUTHENTICATION, PRIVACY AND PAYMENT
+
+ A traveling executive needs to print a set of transparencies for an
+ important business meeting. The charts are in Lotus Freelance format
+ on his notebook computer. He has located a SirZippy print shop near
+ his hotel that will print color transparencies. Because the
+ information on the charts is sensitive, he wants to be sure that his
+ data is sent to the Printer in an encrypted format. He also wants to
+ authenticate the Printer. The Printer also authenticates the user.
+ Payment occurs across the Internet.
+
+ Client IPP Printer
+
+ +---------------------------------------------------------- >
+ < ----------------------------------------------------------+
+
+ Mutual authentication and exchange of secret keys
+
+ +---------------------------------------------------------- >
+ Here is a print job (encrypted)
+ - job name = MyJob
+ - notify me by email when done printing
+ - print on iso-a4-white paper
+ - print on both sides of the paper
+ - return status of the printer in response
+ - tell me where to pick up output
+ - document is in Postscript format
+ - here is the document to print
+
+ < ----------------------------------------------------------+
+ Print job accepted and spooled (encrypted)
+ - job id = #12345
+ - current state of print job = spooled
+ - submission time = 02/12/97, 15:35
+ - printer state = printing
+ - payment required to proceed with job
+ - pick up at 230 East Main after 3:30 pm today
+
+ +---------------------------------------------------------- >
+ < ----------------------------------------------------------+
+ Payment transaction
+
+
+
+
+
+
+
+
+
+
+Wright Experimental [Page 26]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+10.10. SUBMITTING A PRINT JOB WITH DECRYPTION ERROR
+
+ A traveling executive needs to print a set of transparencies for an
+ important business meeting. The charts are in Lotus Freelance format
+ on his notebook computer. He has located a SirZippy print shop near
+ his hotel that will print color transparencies. Because the
+ information on the charts is sensitive, he wants to be sure that his
+ data is sent to the printer in an encrypted format. He also wants to
+ authenticate the printer. The printer also authenticates the user.
+ Payment occurs across the Internet. An error occurs during
+ decryption.
+
+ Client IPP Printer
+
+ +---------------------------------------------------------- >
+ < ----------------------------------------------------------+
+ Mutual authentication and exchange of secret keys
+
+
+ +---------------------------------------------------------- >
+ Here is a print job (encrypted)
+ - job name = MyJob
+ - notify me by email when done printing
+ - print on iso-a4-white paper
+ - print on both sides of the paper
+ - return status of the printer in response
+ - tell me where to pick up output
+ - document is in Postscript format
+ - here is the document to print
+
+ < ----------------------------------------------------------+
+ Print job accepted and spooled (encrypted)
+ - job id = #12345
+ - current state of print job = spooled
+ - submission time = 02/12/97, 15:35
+ - printer state = printing
+ - payment required to proceed with job
+ - pick up at 230 East Main after 3:30 pm today
+
+ +---------------------------------------------------------- >
+ < ----------------------------------------------------------+
+ Payment transaction
+ .
+ .
+ .
+ < ----------------------------------------------------------+
+ Asynchronous response (email in this case)
+ - decryption failed on job #12345
+
+
+
+Wright Experimental [Page 27]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ - no pages printed
+ - current state of job = aborted
+
+10.11. SUBMITTING A PRINT JOB WITH AUTHENTICATION
+
+ An end-user wants to submit a print job. The print file already
+ exists on his workstation. The client and printer are behind the same
+ corporate firewall. The printer is available to anyone behind the
+ firewall but authentication and authorization is required.
+ Authorization takes place using the authenticated end-user's name.
+ The data is pushed to the printer. The printer is capable of spooling
+ the output.
+
+ Client IPP Printer
+
+ +---------------------------------------------------------- >
+ < ----------------------------------------------------------+
+ Authentication
+
+ Note: An authentication failure would end the transaction at
+ this point.
+
+ +---------------------------------------------------------- >
+ Here is a print job
+ - job name = MyJob
+ - notify me by email when done printing
+ - print on iso-a4-white paper
+ - print on both sides of the paper
+ - return status of the printer in response
+ - tell me where to pick up output
+ - document is in Postscript format
+ - here is the document to print
+
+ < ----------------------------------------------------------+
+ Print job accepted and spooled
+ - job id = #12345
+ - current state of print job = spooled
+ - submission time = 02/12/97, 15:35
+ - printer state = printing
+
+
+
+
+
+
+
+
+
+
+
+
+Wright Experimental [Page 28]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+10.12. SUBMITTING A PRINT JOB GENERATED DYNAMICALLY
+
+ An end-user wants to submit a print job. The print data is generated
+ dynamically and is being transmitted by a printer driver on the
+ client workstation as available. The client and printer are behind
+ the same corporate firewall. The printer is available to anyone
+ behind the firewall and no authentication and authorization is
+ required. The data is pushed to the printer. The printer is capable
+ of spooling the output. No error occurs.
+
+ Client IPP Printer
+
+ +---------------------------------------------------------- >
+ Here is a print job
+ - job name = MyJob
+ - notify me by email when done printing
+ - print on iso-a4-white paper
+ - print on both sides of the paper
+ - return status of the printer in response
+ - document is in Postscript format
+ - here is the print job
+
+
+ < ----------------------------------------------------------+
+ Print data accepted and spooling started
+ - job id = #12345
+ - current job state = spooled
+ - submission time = 02/12/97, 15:35
+ - printer state = printing
+
+10.13. SUBMITTING A PRINT JOB WITH A PRINTER JAM - CANCELED
+
+ An end-user wants to submit a print job. The print data is generated
+ dynamically and is being transmitted by a printer driver on the
+ client workstation as available. The client and printer are behind
+ the same corporate firewall. The printer is available to anyone
+ behind the firewall and no authentication and authorization is
+ required. The data is pushed to the printer. The printer is not
+ capable of spooling the output. The printer jams notifies the user
+ and the user chooses to cancel the job.
+
+ Client IPP Printer
+ +---------------------------------------------------------- >
+ Here is a print job
+ - job name = MyJob
+ - notify me by email when done printing
+ - print on iso-a4-white paper
+ - print on both sides of the paper
+
+
+
+Wright Experimental [Page 29]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ - return status of the printer in response
+ - document is in Postscript format
+ - here is the document to print
+
+ < ----------------------------------------------------------+
+ Print data accepted and printing started
+ - job id = #12345
+
+ +---------------------------------------------------------- >
+ - What is the status of print job #12345?
+
+ < --------------------------------------------------------- +
+ - Job #12345 accepted but printer jammed, cannot continue
+
+ +---------------------------------------------------------- >
+ - Cancel job #12345
+
+ * Printer flushes remaining data
+ < ----------------------------------------------------------+
+ Print job terminated
+ - current job state = canceled
+ - submission time = 02/12/97, 15:35
+ - printer state = jammed
+
+10.14. SUBMITTING A PRINT JOB WITH A PRINTER JAM - RECOVERED
+
+ An end-user wants to submit a print job. The print data is generated
+ dynamically and is being transmitted by a printer driver on the
+ client workstation as available. The client and printer are behind
+ the same corporate firewall. The printer is available to anyone
+ behind the firewall and no authentication and authorization is
+ required. The data is pushed to the printer. The printer is not
+ capable of spooling the output. The printer jams, notifies the user
+ and the user clears the jam and elects to continue.
+
+ Client IPP Printer
+
+ +---------------------------------------------------------- >
+ Here is a print job
+ - job name = MyJob
+ - notify me by email when done printing
+ - print on iso-a4-white paper
+ - print on both sides of the paper
+ - return status of the printer in response
+ - document is in Postscript format
+ - here is the document to print
+
+ < ----------------------------------------------------------+
+
+
+
+Wright Experimental [Page 30]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ Print data accepted and printing started
+ - job id = #12345
+
+ < --------------------------------------------------------- +
+ - Notification: printer jammed, cannot continue
+
+ * Jam is clear by human intervention, printing continues
+
+ +---------------------------------------------------------- >
+ Here is the last part of the document to print
+
+ < ----------------------------------------------------------+
+ Print job received
+ - current job state = printing
+ - submission time = 02/12/97, 15:35
+ - printer state = printing
+
+10.15. SUBMITTING A PRINT JOB WITH SERVER PULL
+
+ An end-user wants to submit a print job. The print data is in a file
+ and is publicly available. It is pulled by the printer. The client
+ and printer are behind the same corporate firewall. The printer is
+ available to anyone behind the firewall and no authentication and
+ authorization is required. The printer is capable of spooling the
+ output. Printing may start before the entire job has been pulled.
+
+ Client IPP Printer
+
+ +---------------------------------------------------------- >
+ Here is a print job
+
+ - job name = MyJob
+ - notify me by email when done printing
+ - print on iso-a4-white paper
+ - print on both sides of the paper
+ - return status of the printer in response
+ - here is a reference to the data to be printed
+
+ < ----------------------------------------------------------+
+ Print data accepted and printing started
+ - job id = #12345
+ - current state of job = spooled
+ - submission time = 02/12/97, 13:15
+ - printer state = printing
+
+ .
+ .
+ < ----------------------------------------------------------+
+
+
+
+Wright Experimental [Page 31]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ Get the file to be printed
+
+ +---------------------------------------------------------- >
+ Here it is
+
+ Note: Failure to find the file, would end the transaction
+ with an error at this point and an asynchronous
+ notification would be send to the Client.
+
+ < ----------------------------------------------------------+
+ Data received
+
+10.16. SUBMITTING A PRINT JOB WITH REFERENCED RESOURCES
+
+ An end-user wants to submit a print job. Part of the print data is
+ on a file on the user's workstation. It is pushed by the client, but
+ the print job requires some resource not included in the print file.
+ The client and printer are behind the same corporate firewall. The
+ printer is available to anyone behind the firewall and no
+ authentication and authorization is required. The printer is capable
+ of spooling the output. No errors occur.
+
+ Client IPP Printer
+
+ +---------------------------------------------------------- >
+ Here is a print job
+ - job name = MyJob
+ - notify me by email when done printing
+ - print on iso-a4-white paper
+ - print on both sides of the paper
+ - return status of the printer in response
+
+ < ----------------------------------------------------------+
+ Print job accepted and spooled
+ - job id = #12345
+ - submission time = 02/12/97, 15:35
+
+ +---------------------------------------------------------- >
+ - here is the document to print
+
+ < ----------------------------------------------------------+
+ - OK
+
+ +---------------------------------------------------------- >
+ - here is the URI to print, it is the last document.
+
+ < ----------------------------------------------------------+
+ - OK
+
+
+
+Wright Experimental [Page 32]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ < ----------------------------------------------------------+
+ Get the external resource
+
+ +---------------------------------------------------------- >
+ Here it is
+
+10.17. GETTING CAPABILITIES
+
+10.17.1. Submission Attributes
+
+ An end-user wants to get the production and scheduling attributes
+ that are supported or required when submitting jobs to this printer.
+ The client will use these attributes when forming the subsequent
+ print request.
+
+ Client IPP Printer
+ +---------------------------------------------------------- >
+ I'm going to submit a Postscript job
+ give me your job submission attributes
+
+ < ----------------------------------------------------------+
+ Postscript production attributes for this Printer are:
+ - medium-select = us-letter-white, us-legal-white
+ - default is us-letter-white
+ - copies = 1,2,3,4,5
+ - default is 1
+ - print-quality = draft, normal, high
+ - default is draft
+ - sides = 1-sided, 2-sided-long-edge
+ - default is 2-sided-long-edge
+ - Job scheduling attributes for this Printer are:
+ - job-priority = 1,2,3
+ - default = 3
+
+10.17.2. Printer Capabilities
+
+ An end-user wants to determine the resolution, marking technology,
+ and PDLs supported by the printer.
+
+ Client IPP Printer
+ +---------------------------------------------------------- >
+ Please tell me the
+ - resolution of the printer
+ - the marking technology of the printer
+ - PDLs supported
+ < ----------------------------------------------------------+
+ Printer resolution = 600 dpi
+ Marking Technology = laser
+
+
+
+Wright Experimental [Page 33]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ PDLs supported = Postscript level 2, PCL/6
+
+10.18. GETTING STATUS
+
+10.18.1. Printer State/Status
+
+ An end-user wants to determine the state or status of the printer.
+
+ Client IPP Printer
+
+ +---------------------------------------------------------- >
+ What is the state of the printer?
+
+ < ----------------------------------------------------------+
+ Printer state = out-of-paper
+
+10.18.2. Job Status
+
+ An end user wants to get the status of a job he has submitted.
+
+ Client IPP Printer
+
+ +---------------------------------------------------------- >
+ Please tell me the status of job #12345
+
+ < ----------------------------------------------------------+
+ Job #12345 is queued
+ it is number 3 in the queue
+ printer state = printing
+
+10.18.3. Status of All My Jobs
+
+ An end user wants to get a list of all of the jobs he has submitted
+ to this Printer.
+
+ Client IPP Printer
+
+ +---------------------------------------------------------- >
+ Please tell me the status of my jobs
+
+ < ----------------------------------------------------------+
+ Job #00012 is complete
+ Printed at 12:35 on 01/23/97
+
+ Job #09876 is printing
+
+ Job #12345 is queued
+ it is number 3 in the queue
+
+
+
+Wright Experimental [Page 34]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ Job #34567 is queued
+ it is number 7 in the queue
+
+10.19. ASYNCHRONOUS NOTIFICATION
+
+10.19.1. Job Completion
+
+ An end-user wants to get notification of events that affect his print
+ jobs. Print job completes without error.
+
+ Client IPP Printer
+
+ < ----------------------------------------------------------+
+ Print job #123 completed
+
+10.19.2. Job Complete with Data
+
+ An end-user wants to get notification of events that affect his print
+ jobs. Print job completes, users asked for all end of job
+ information.
+
+ Client IPP Printer
+
+ < ----------------------------------------------------------+
+ Print job #123 completed
+ - total pages printed = 15
+ - number of copies printed = 3
+ - total cost to print = $7.45
+ - pick up copies in room H-6, building 005
+
+10.19.3. Print Job Fails
+
+ An end-user wants to get notification of events that affect his print
+ jobs. Print job fails. Printer is unattended.
+
+ Client IPP Printer
+
+ < ----------------------------------------------------------+
+ Print job #123 failed
+ - total pages printed = 15
+ - number of pages submitted = 25
+ - printer-state = jammed
+
+
+
+
+
+
+
+
+
+Wright Experimental [Page 35]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+10.20. CANCEL A JOB
+
+ The end-user submits a print job and later decides to cancel it.
+
+ Client IPP Printer
+
+ +---------------------------------------------------------- >
+ < ----------------------------------------------------------+
+ Authentication.
+
+
+ +---------------------------------------------------------- >
+ Cancel job #1234
+
+ < ----------------------------------------------------------+
+ Job #1234 Canceled
+
+
+10.21. END TO END SCENARIO - WITHIN AN ENTERPRISE
+
+ An office worker prints on shared departmental printers. All printers
+ in the office are public, that is, no authentication or authorization
+ is required. Printers are protected from external access by a
+ firewall. No billing or accounting is required. Most printing is done
+ from desktop applications. A help desk is provided for printing
+ problems. Standard operating systems and applications are used.
+ Drivers are available, but are installed manually by support
+ personnel. This scenario assumes that drivers have been installed and
+ that drivers are not IPP aware, that is, they cannot communicate
+ across an IPP connection to obtain status and capabilities. IPP
+ printers appear in application pull-down menus. Printer
+ configuration data is hard wired into the driver.
+
+ End-user selects print from the application pull down menu. An IPP
+ printer is selected from the list of Printers offered
+
+ The driver puts up a dialogue with hard-wired set of options for this
+ printer. The end-user makes choices and submits job.
+
+ Client IPP Printer
+ +---------------------------------------------------------- >
+ Here is a print job
+ - job-name = memo-to-boss
+ - notify me by email when job is complete
+ - print on us-letter-white paper
+ - print 1 copy
+ - print at normal quality
+ - print on 1 side
+
+
+
+Wright Experimental [Page 36]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ - give me the state of the printer in response
+
+ The driver generates the print data and passes it to the IPP driver a
+ piece at a time as it is generated.
+
+ +---------------------------------------------------------- >
+ Here is the print data
+
+
+ < ----------------------------------------------------------+
+ Print data received, file is spooled
+ - printer state = printing
+ - time submitted = 2/12/97, 15:35
+ - current job state = spooled
+
+ Client adds this job to list of current jobs. List of jobs and state
+ of each is available on a pull-down menu on the client.
+
+ End-user selects job #1234 from list and clicks on it to see its
+ status.
+
+ +---------------------------------------------------------- >
+ Give me the state of job #1234
+ and the state of the Printer
+
+ < ----------------------------------------------------------+
+ Job #1234 state = spooled
+ - it is number 3 in the queue
+ - printer state = printing
+
+ The job completes without error
+
+ < ----------------------------------------------------------+
+ Job #1234 completed
+ 12 of 12 pages printed
+
+10.22. END TO END SCENARIO - ACROSS ENTERPRISES
+
+ An office worker in Company A needs to print an office document on a
+ "public" printer at Company B, a business partner. Both companies
+ have corporate firewalls so the print request must flow out of A's
+ firewall and into B's firewall. The office worker can look at public
+ printers in Company B's directory service. The document is generated
+ by a desktop application. Since the printer is "public" no
+ authentication or authorization is required. A driver is downloaded.
+ The driver is IPP aware, that is, it can communicate dynamically
+ through the IPP protocol layer to obtain information about the
+ printer.
+
+
+
+Wright Experimental [Page 37]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ Client Company B's Directory Service
+
+ End user connects to B's Directory service
+
+ +---------------------------------------------------------- >
+ Find a Printer with these characteristics
+ - public (no authorization or authentication required)
+ - is in Lexington, building 004
+ - prints black and white
+
+ < ----------------------------------------------------------+
+ Printer "Public-A"
+ - http://www.lexmark.com/pubprinter/a
+
+ Printer "Public-B"
+ - http://www.lexmark.com/pubprinter/b
+
+ End user selects Public-A
+
+ Client Public-A
+
+ +---------------------------------------------------------- >
+ Where can I find a driver for you?
+
+ < ----------------------------------------------------------+
+ Drivers at http://www.lexmark.com/pubprinters/a/os245
+
+ End user gets driver and installs it on his PC.
+
+ End-user selects print from the application pull down menu. "Public-
+ A" is selected from the list of Printers offered
+
+ +---------------------------------------------------------- >
+ I'm going to submit a print job
+ give me your job submission attributes
+
+ < ----------------------------------------------------------+
+
+ Production attributes for this Printer are:
+ - medium-select = us-letter-white, us-legal-white
+ - default is us-letter-white
+ - copies = 1,2,3,4,5
+ - default is 1
+ - print-quality = draft, normal, high
+ - default is draft
+ - sides = 1-sided, 2-sided-long-edge
+ - default is 2-sided-long-edge
+
+
+
+
+Wright Experimental [Page 38]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ Job scheduling attributes for this Printer are:
+ - job-priority = 1,2,3
+ default = 3
+
+ Driver puts up dialogue with available options and fills in the
+ defaults.
+
+ End-user makes choices and submits job
+
+ +---------------------------------------------------------- >
+ Here is a print job
+ - job-name = memo-to-Don-Wright
+ - notify me by email when job is complete
+ - print on us-letter-white paper
+ - print 1 copy
+ - print at normal quality
+ - print on 1 side
+ - give me the state of the printer in response
+
+
+ The driver generates the print data and passes it to the IPP driver a
+ piece at a time.
+
+ +---------------------------------------------------------- >
+ Here is the print data
+
+ < ----------------------------------------------------------+
+ Print data received, and spooling started
+ print job id = #1234
+
+ Print data received, file is spooled
+
+ - printer state = printing
+ - time submitted = 2/12/97, 15:35
+ - current job state = spooled
+
+ Client adds this job to list of current jobs. List of jobs and state
+ of each is available on a pull-down menu on the client.
+
+ End-user selects job #1234 from list and clicks on it to see its
+ status.
+
+ +---------------------------------------------------------- >
+ Give me the state of job #1234
+ and the state of the Printer
+
+ < ----------------------------------------------------------+
+ Job #1234 state = spooled
+
+
+
+Wright Experimental [Page 39]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ - it is number 3 in the queue
+ - printer state = printing
+
+ * The job completes without error
+ < ----------------------------------------------------------+
+ Job #1234 completed
+ 12 of 12 pages printed
+
+10.23. END TO END SCENARIO - ON THE INTERNET
+
+ An executive in her hotel room is finishing an important presentation
+ on her laptop computer. She connects to a local print shop through
+ the web to get a copy of her charts printed for tomorrow's
+ presentation. She must find a print shop that is convenient and can
+ print color transparencies. She must download and temporarily install
+ a driver in order to generate the PDL required by the print shop.
+ Mutual authentication is required by the print shop and payment must
+ be made in advance. The job is encrypted on the wire to prevent
+ eavesdropping.
+
+ End-user completes presentation. She goes to the web and connects to
+ the SirZippy home page.
+
+ Client SirZippy Directory Service
+ +---------------------------------------------------------- >
+
+ Find me a printer with these characteristics
+ - Near Market Street in San Jose
+ - Prints color transparencies
+ - drivers can be downloaded
+ - supports privacy (encryption)
+ -
+
+ Available Printers matching these characteristics are looked up in the
+ Directory Service
+
+ < ----------------------------------------------------------+
+
+ Printer "Color-A"
+ - located at 123 First Street in San Jose
+ - URI is http://www.SirZippy.com/FirstStreet/Color-A
+ - prints color transparencies
+ - 600 dpi laser
+ - driver ABC-Postscript-V1.3 available at this URI
+ - cost = $.75 per page
+ - authentication required to use printer
+ - payment required prior to printing
+
+
+
+
+Wright Experimental [Page 40]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ Printer "Color-B"
+ - located at 67 San Carlos Street, San Jose
+ - URI is http://www.SirZippy.com/SanCarlos/Color-B
+ - prints color transparencies
+ - 1200 dpi laser
+ - driver XYZ-PostScript-V4.3 available at this URI
+ - cost = $1.25 per page
+ - authentication required to use printer
+ - payment required prior to printing
+ - more information at this URI
+
+ The user decides to use the first printer because it is closer. She
+ connects to the URI given to get a driver.
+
+ Client Driver URI
+
+ +---------------------------------------------------------- >
+ I need a driver for "Color-A"
+
+
+ < ----------------------------------------------------------+
+ Driver installer is at http://www.xerox.com/prtdrvrs
+
+ Driver is installed
+
+ User connects to
+ "Color-A"
+
+ Client IPP Printer "Color-A"
+
+ +---------------------------------------------------------- >
+ < ----------------------------------------------------------+
+ Mutual authentication and exchange of secret keys
+
+ +---------------------------------------------------------- >
+ I'm going to submit a print job
+ give me your job submission attributes
+
+ < ----------------------------------------------------------+
+ Production attributes for this Printer are:
+ - medium-select = us-letter-white, us-legal-white
+ - default is us-letter-white
+ - copies = 1,2,3,4,5
+ - default is 1
+ - print-quality = draft, normal, high
+ - default is draft
+ - sides = 1-sided, 2-sided-long-edge
+ - default is 2-sided-long-edge
+
+
+
+Wright Experimental [Page 41]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ Job scheduling attributes for this Printer are:
+ - job-priority = 1,2,3
+ default = 3
+
+ Driver puts up dialogue with available options and fills in the
+ defaults.
+
+ End-user makes choices and submits job
+
+ +---------------------------------------------------------- >
+ Here is a print job
+
+ - job-name = presentation
+ - notify me by email when job is complete
+ - print on us-letter-transparency
+ - print 1 copy
+ - print at high quality
+ - print by 9:00 am tomorrow morning
+ - give me the state of the printer in response
+
+ The driver generates the print data and passes it to the IPP driver a
+ piece at a time.
+
+ +---------------------------------------------------------- >
+ Here is the print data
+
+ < ---------------------------------------------------------+
+ Print data received, and spooling started
+ print job id = #1234
+
+ Print data received, file is spooled
+ - printer state = printing
+ - time submitted = 2/12/97, 15:35
+ - current job state = held, waiting for payment
+
+ +---------------------------------------------------------- >
+ < ----------------------------------------------------------+
+ Payment transaction
+
+ < ----------------------------------------------------------+
+ Job is scheduled to print, pick up after 9:00am tomorrow
+ Thank you for using SirZippy
+
+
+
+
+
+
+
+
+
+Wright Experimental [Page 42]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+11. Full Copyright Statement
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Wright Experimental [Page 43]
+
diff --git a/standards/rfc2568.txt b/standards/rfc2568.txt
new file mode 100644
index 000000000..2d3ae4905
--- /dev/null
+++ b/standards/rfc2568.txt
@@ -0,0 +1,563 @@
+
+
+
+
+
+
+Network Working Group S. Zilles
+Request for Comments: 2568 Adobe Systems Inc.
+Category: Experimental April 1999
+
+
+ Rationale for the Structure of the Model and Protocol
+ for the Internet Printing Protocol
+
+Status of this Memo
+
+ This memo defines an Experimental Protocol for the Internet
+ community. It does not specify an Internet standard of any kind.
+ Discussion and suggestions for improvement are requested.
+ Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+IESG Note
+
+ This document defines an Experimental protocol for the Internet
+ community. The IESG expects that a revised version of this protocol
+ will be published as Proposed Standard protocol. The Proposed
+ Standard, when published, is expected to change from the protocol
+ defined in this memo. In particular, it is expected that the
+ standards-track version of the protocol will incorporate strong
+ authentication and privacy features, and that an "ipp:" URL type will
+ be defined which supports those security measures. Other changes to
+ the protocol are also possible. Implementors are warned that future
+ versions of this protocol may not interoperate with the version of
+ IPP defined in this document, or if they do interoperate, that some
+ protocol features may not be available.
+
+ The IESG encourages experimentation with this protocol, especially in
+ combination with Transport Layer Security (TLS) [RFC2246], to help
+ determine how TLS may effectively be used as a security layer for
+ IPP.
+
+ABSTRACT
+
+ This document is one of a set of documents, which together describe
+ all aspects of a new Internet Printing Protocol (IPP). IPP is an
+ application level protocol that can be used for distributed printing
+ using Internet tools and technologies. This document describes IPP
+ from a high level view, defines a roadmap for the various documents
+ that form the suite of IPP specifications, and gives background and
+ rationale for the IETF working group's major decisions.
+
+
+
+Zilles Experimental [Page 1]
+
+RFC 2568 Rationale for IPP April 1999
+
+
+ The full set of IPP documents includes:
+
+ Design Goals for an Internet Printing Protocol [RFC2567]
+ Rationale for the Structure and Model and Protocol for the
+ Internet Printing Protocol (this document)
+ Internet Printing Protocol/1.0: Model and Semantics [RFC2566]
+ Internet Printing Protocol/1.0: Encoding and Transport [RFC2565]
+ Internet Printing Protocol/1.0: Implementer's Guide [ipp-iig]
+ Mapping between LPD and IPP Protocols [RFC2569]
+
+ The "Design Goals for an Internet Printing Protocol" document takes a
+ broad look at distributed printing functionality, and it enumerates
+ real-life scenarios that help to clarify the features that need to be
+ included in a printing protocol for the Internet. It identifies
+ requirements for three types of users: end users, operators, and
+ administrators. The Design Goals document calls out a subset of end
+ user requirements that are satisfied in IPP/1.0. Operator and
+ administrator requirements are out of scope for version 1.0.
+
+ The "Internet Printing Protocol/1.0: Model and Semantics" document
+ describes a simplified model consisting of abstract objects, their
+ attributes, and their operations that is independent of encoding and
+ transport. The model consists of a Printer and a Job object. The
+ Job optionally supports multiple documents. This document also
+ addresses security, internationalization, and directory issues.
+
+ The "Internet Printing Protocol/1.0: Encoding and Transport" document
+ is a formal mapping of the abstract operations and attributes defined
+ in the model document onto HTTP/1.1. It defines the encoding rules
+ for a new Internet media type called "application/ipp".
+
+ The "Internet Printing Protocol/1.0: Implementer's Guide" document
+ gives insight and advice to implementers of IPP clients and IPP
+ objects. It is intended to help them understand IPP/1.0 and some of
+ the considerations that may assist them in the design of their client
+ and/or IPP object implementations. For example, a typical order of
+ processing requests is given, including error checking. Motivation
+ for some of the specification decisions is also included.
+
+ The "Mapping between LPD and IPP Protocols" document gives some
+ advice to implementers of gateways between IPP and LPD (Line Printer
+ Daemon) implementations.
+
+1. ARCHITECTURAL OVERVIEW
+
+ The Internet Printing Protocol (IPP) is an application level protocol
+ that can be used for distributed printing on the Internet. This
+ protocol defines interactions between a client and a server. The
+
+
+
+Zilles Experimental [Page 2]
+
+RFC 2568 Rationale for IPP April 1999
+
+
+ protocol allows a client to inquire about capabilities of a printer,
+ to submit print jobs and to inquire about and cancel print jobs. The
+ server for these requests is the Printer; the Printer is an
+ abstraction of a generic document output device and/or a print
+ service provider. Thus, the Printer could be a real printing device,
+ such as a computer printer or fax output device, or it could be a
+ service that interfaced with output devices.
+
+ The protocol is heavily influenced by the printing model introduced
+ in the Document Printing Application (DPA) [ISO10175] standard.
+ Although DPA specifies both end user and administrative features, IPP
+ version 1.0 (IPP/1.0) focuses only on end user functionality.
+
+ The architecture for IPP defines (in the Model and Semantics document
+ [RFC2566]) an abstract Model for the data which is used to control
+ the printing process and to provide information about the process and
+ the capabilities of the Printer. This abstract Model is hierarchical
+ in nature and reflects the structure of the Printer and the Jobs that
+ may be being processed by the Printer.
+
+ The Internet provides a channel between the client and the
+ server/Printer. Use of this channel requires flattening and
+ sequencing the hierarchical Model data. Therefore, the IPP also
+ defines (in the Encoding and Transport document [RFC2565]) an
+ encoding of the data in the model for transfer between the client and
+ server. This transfer of data may be either a request or the
+ response to a request.
+
+ Finally, the IPP defines (in the Encoding and Transport document
+ [RFC2565]) a protocol for transferring the encoded request and
+ response data between the client and the server/Printer.
+
+ An example of a typical interaction would be a request from the
+ client to create a print job. The client would assemble the Model
+ data to be associated with that job, such as the name of the job, the
+ media to use, the number of pages to place on each media instance,
+ etc. This data would then be encoded according to the Protocol and
+ would be transmitted according to the Protocol. The server/Printer
+ would receive the encoded Model data, decode it into a form
+ understood by the server/Printer and, based on that data, do one of
+ two things: (1) accept the job or (2) reject the job. In either case,
+ the server must construct a response in terms of the Model data,
+ encode that response according to the Protocol and transmit that
+ encoded Model data as the response to the request using the Protocol.
+
+ Another part of the IPP architecture is the Directory Schema
+ described in the model document. The role of a Directory Schema is to
+ provide a standard set of attributes which might be used to query a
+
+
+
+Zilles Experimental [Page 3]
+
+RFC 2568 Rationale for IPP April 1999
+
+
+ directory service for the URI of a Printer that is likely to meet the
+ needs of the client. The IPP architecture also addresses security
+ issues such as control of access to server/Printers and secure
+ transmissions of requests, response and the data to be printed.
+
+2. THE PRINTER
+
+ Because the (abstract) server/Printer encompasses a wide range of
+ implementations, it is necessary to make some assumptions about a
+ minimal implementation. The most likely minimal implementation is one
+ that is embedded in an output device running a specialized real time
+ operating system and with limited processing, memory and storage
+ capabilities. This printer will be connected to the Internet and will
+ have at least a TCP/IP capability with (likely) SNMP [RFC1905,
+ RFC1906] support for the Internet connection. In addition, it is
+ likely the the Printer will be an HTML/HTTP server to allow direct
+ user access to information about the printer.
+
+3. RATIONALE FOR THE MODEL
+
+ The Model [RFC2566] is defined independently of any encoding of the
+ Model data both to support the likely uses of IPP and to be robust
+ with respect to the possibility of alternate encoding.
+
+ It is expected that a client or server/Printer would represent the
+ Model data in some data structure within the applications/servers
+ that support IPP. Therefore, the Model was designed to make that
+ representation straightforward. Typically a parser or formatter would
+ be used to convert from or to the encoded data format. Once in an
+ internal form suitable to a product, the data can be manipulated by
+ the product. For example, the data sent with a Print Job can be used
+ to control the processing of that Print Job.
+
+ The semantics of IPP are attached to the (abstract) Model.
+ Therefore, the application/server is not dependent on the encoding of
+ the Model data, and it is possible to consider alternative mechanisms
+ and formats by which the data could be transmitted from a client to a
+ server; for example, a server could have a direct, client-less GUI
+ interface that might be used to accept some kinds of Print Jobs. This
+ independence would also allow a different encoding and/or
+ transmission mechanism to be used if the ones adopted here were shown
+ to be overly limiting in the future. Such a change could be migrated
+ into new products as an alternate protocol stack/parser for the Model
+ data.
+
+
+
+
+
+
+
+Zilles Experimental [Page 4]
+
+RFC 2568 Rationale for IPP April 1999
+
+
+ Having an abstract Model also allows the Model data to be aligned
+ with the (abstract) model used in the Printer [RFC1759], Job and Host
+ Resources MIBs. This provides consistency in interpretation of the
+ data obtained independently of how the data is accessed, whether via
+ IPP or via SNMP [RFC1905, RFC1906] and the Printer/Job MIBs.
+
+ There is one aspect of the Model that deserves some extra
+ explanation. There are two ways for identifying a Job object: (a)
+ with a Job URI and (b) using a combination of the Printer URI and a
+ Job ID (a 32 bit positive integer). Allowing Job objects to have URIs
+ allows for flexibility and scalability. For example a job could be
+ moved from a printer with a large backlog to one with a smaller load
+ and the job identification, the Job object URI, need not change.
+ However, many existing printing systems have local models or
+ interface constraints that force Job objects to be identified using
+ only a 32-bit positive integer rather than a URI. This numeric Job
+ ID is only unique within the context of the Printer object to which
+ the create request was originally submitted. In order to allow both
+ types of client access to Jobs (either by Job URI or by numeric Job
+ ID), when the Printer object successfully processes a create request
+ and creates a new Job, the Printer object generates both a Job URI
+ and a Job ID for the new Job object. This requirement allows all
+ clients to access Printer objects and Job objects independent of any
+ local constraints imposed on the client implementation.
+
+4. RATIONALE FOR THE PROTOCOL
+
+ There are two parts to the Protocol: (1) the encoding of the Model
+ data and (2) the mechanism for transmitting the model data between
+ client and server.
+
+4.1 The Encoding
+
+ To make it simpler to develop embedded printers, a very simple binary
+ encoding has been chosen. This encoding is adequate to represent the
+ kinds of data that occur within the Model. It has a simple structure
+ consisting of sequences of attributes. Each attribute has a name,
+ prefixed by a name length, and a value. The names are strings
+ constrained to characters from a subset of ASCII. The values are
+ either scalars or a sequence of scalars. Each scalar value has a
+ length specification and a value tag which indicates the type of the
+ value. The value type has two parts: a major class part, such as
+ integer or string, and a minor class part which distinguishes the
+ usage of the major class, such as dateTime string. Tagging of the
+ values with type information allows for introducing new value types
+ at some future time.
+
+
+
+
+
+Zilles Experimental [Page 5]
+
+RFC 2568 Rationale for IPP April 1999
+
+
+ A fully encoded request/response has a version number, an operation
+ (for a request) or a status and optionally a status message (for a
+ response), associated parameters and attributes which are encoded
+ Model data and, optionally (for a request), print data following the
+ Model data.
+
+4.2 The Transmission Mechanism
+
+ The chosen mechanism for transmitting the encoded Model data is HTTP
+ 1.1 Post (and associated response). No modifications to HTTP 1.1 are
+ proposed or required. The sole role of the Transmission Mechanism is
+ to provide a transfer of encoded Model data from/to the client
+ to/from the server. This could be done using any data delivery
+ mechanism. The key reasons why HTTP 1.1 Post is used are given below.
+ The most important of these is the first. With perhaps this
+ exception, these reasons could be satisfied by other mechanisms.
+ There is no claim that this list uniquely determines a choice of
+ mechanism.
+
+ 1. HTTP 1.0 is already widely deployed and, based on the recent
+ evidence, HTTP 1.1 is being widely deployed as the manufacturers
+ release new products. The performance benefits of HTTP 1.1 have
+ been shown and manufactures are reacting positively.
+
+ Wide deployment has meant that many of the problems of making a
+ protocol work in a wide range of environments from local net to
+ Intranet to Internet have been solved and will stay solved with
+ HTTP 1.1 deployment.
+
+ 2. HTTP 1.1 solves most of the problems that might have required a
+ new protocol to be developed. HTTP 1.1 allows persistent
+ connections that make a multi-message protocol be more efficient;
+ for example it is practical to have separate Create-Job and Send-
+ Document messages. Chunking allows the transmission of large print
+ files without having to pre-scan the file to determine the file
+ length. The accept headers allow the client's protocol and
+ localization desires to be transmitted with the IPP operations and
+ data. If the Model were to provide for the redirection of Job
+ requests, such as Cancel-Job, when a Job is moved, the HTTP
+ redirect response allows a client to be informed when a Job he is
+ interested in is moved to another server/Printer for any reason.
+
+ 3. Most network Printers will be implementing HTTP servers for
+ reasons other than IPP. These network attached Printers want to
+ provide information on how to use the printer, its current state,
+ HELP information, etc. in HTML. This requires having an HTTP
+ server which would be available to do IPP functions as well.
+
+
+
+
+Zilles Experimental [Page 6]
+
+RFC 2568 Rationale for IPP April 1999
+
+
+ 4. Most of the complexity of HTTP 1.1 is concerned with the
+ implementation of HTTP proxies and not the implementation of HTTP
+ clients and/or servers. Work is proceeding in the HTTP Working
+ Group to help identify what must be done by a server. As the
+ Encoding and Transport document shows, that is not very much.
+
+ 5. HTTP implementations provide support for handling URLs that
+ would have to be provided if a new protocol were defined.
+
+ 6. An HTTP based solution fits well with the Internet security
+ mechanisms that are currently deployed or being deployed. HTTP
+ will run over SSL3. The digest access authentication mechanism of
+ HTTP 1.1 provides an adequate level of access control. These
+ solutions are deployed and in practical use; a new solution would
+ require extensive use to have the same degree of confidence in its
+ security. Note: SSL3 is not on the IETF standards track.
+
+ 7. HTTP provides an extensibility model that a new protocol would
+ have to develop independently. In particular, the headers,
+ intent-types (via Internet Media Types) and error codes have wide
+ acceptance and a useful set of definitions and methods for
+ extension.
+
+ 8. Although not strictly a reason why IPP should use HTTP as the
+ transmission protocol, it is extremely helpful that there are many
+ prototyping tools that work with HTTP and that CGI scripts can be
+ used to test and debug parts of the protocol.
+
+ 9. Finally, the POST method was chosen to carry the print data
+ because its usage for data transmission has been established, it
+ works and the results are available via CGI scripts or servlets.
+ Creating a new method would have better identified the intended
+ use of the POSTed data, but a new method would be more difficult
+ to deploy. Assigning a new default port for IPP provided the
+ necessary identification with minimal impact to installed
+ infrastructure, so was chosen instead.
+
+5. RATIONALE FOR THE DIRECTORY SCHEMA
+
+ Successful use of IPP depends on the client finding a suitable IPP
+ enabled Printer to which to send a IPP requests, such as print a
+ job. This task is simplified if there is a Directory Service which
+ can be queried for a suitable Printer. The purpose of the
+ Directory Schema is to have a standard description of Printer
+ attributes that can be associated the URI for the printer. These
+ attributes are a subset of the Model attributes and can be encoded
+ in the appropriate query syntax for the Directory Service being
+ used by the client.
+
+
+
+Zilles Experimental [Page 7]
+
+RFC 2568 Rationale for IPP April 1999
+
+
+6. SECURITY CONSIDERATIONS - RATIONALE FOR SECURITY
+
+ Security is an area of active work on the Internet. Complete
+ solutions to a wide range of security concerns are not yet
+ available. Therefore, in the design of IPP, the focus has been on
+ identifying a set of security protocols/features that are
+ implemented (or currently implementable) and solve real problems
+ with distributed printing. The two areas that seem appropriate to
+ support are: (1) authorization to use a Printer and (2) secure
+ interaction with a printer. The chosen mechanisms are the digest
+ authentication mechanism of HTTP 1.1 and SSL3 [SSL] secure
+ communication mechanism.
+
+7. REFERENCES
+
+ [ipp-iig] Hastings, T. and C. Manros, "Internet Printing
+ Protocol/1.0:Implementer's Guide", Work in Progress.
+
+ [RFC2569] Herriot, R., Hastings, T., Jacobs, N. and J. Martin,
+ "Mapping between LPD and IPP Protocols", RFC 2569, April
+ 1999.
+
+ [RFC2566] deBry, R., Isaacson, S., Hastings, T., Herriot, R. and P.
+ Powell, "Internet Printing Protocol/1.0: Model and
+ Semantics", RFC 2566, April 1999.
+
+ [RFC2565] Herriot, R., Butler, S., Moore, P. and R. Tuner, "Internet
+ Printing Protocol/1.0: Encoding and Transport", RFC 2565,
+ April 1999.
+
+ [RFC2567] Wright, D., "Design Goals for an Internet Printing
+ Protocol", RFC 2567, April 1999.
+
+ [ISO10175] ISO/IEC 10175 "Document Printing Application (DPA)", June
+ 1996.
+
+ [RFC1759] Smith, R., Wright, F., Hastings, T., Zilles, S. and J.
+ Gyllenskog, "Printer MIB", RFC 1759, March 1995.
+
+ [RFC1905] Case, J., McCloghrie, K., Rose, M. and S. Waldbusser,
+ "Protocol Operations for Version 2 of the Simple Network
+ Management Protocol (SNMPv2)", RFC 1905, January 1996.
+
+ [RFC1906] Case, J., McCloghrie, K., Rose, M. and S. Waldbusser,
+ "Transport Mappings for Version 2 of the Simple Network
+ Management Protocol (SNMPv2)", RFC 1906, January 1996.
+
+
+
+
+
+Zilles Experimental [Page 8]
+
+RFC 2568 Rationale for IPP April 1999
+
+
+ [SSL] Netscape, The SSL Protocol, Version 3, (Text version
+ 3.02), November 1996.
+
+8. AUTHOR'S ADDRESS
+
+ Stephen Zilles
+ Adobe Systems Incorporated
+ 345 Park Avenue
+ MailStop W14
+ San Jose, CA 95110-2704
+
+ Phone: +1 408 536-4766
+ Fax: +1 408 537-4042
+ EMail: szilles@adobe.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Zilles Experimental [Page 9]
+
+RFC 2568 Rationale for IPP April 1999
+
+
+9. Full Copyright Statement
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Zilles Experimental [Page 10]
+
diff --git a/standards/rfc2569.txt b/standards/rfc2569.txt
new file mode 100644
index 000000000..767857c34
--- /dev/null
+++ b/standards/rfc2569.txt
@@ -0,0 +1,1571 @@
+
+
+
+
+
+
+Network Working Group R. Herriot
+Request For Comments: 2569 Xerox Corporation
+Category: Experimental N. Jacobs
+ Sun Microsystems, Inc.
+ T. Hastings
+ Xerox Corporation
+ J. Martin
+ Underscore, Inc.
+ April 1999
+
+
+ Mapping between LPD and IPP Protocols
+
+Status of this Memo
+
+ This memo defines an Experimental Protocol for the Internet
+ community. It does not specify an Internet standard of any kind.
+ Discussion and suggestions for improvement are requested.
+ Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+IESG Note
+
+ This document defines an Experimental protocol for the Internet
+ community. The IESG expects that a revised version of this protocol
+ will be published as Proposed Standard protocol. The Proposed
+ Standard, when published, is expected to change from the protocol
+ defined in this memo. In particular, it is expected that the
+ standards-track version of the protocol will incorporate strong
+ authentication and privacy features, and that an "ipp:" URL type will
+ be defined which supports those security measures. Other changes to
+ the protocol are also possible. Implementors are warned that future
+ versions of this protocol may not interoperate with the version of
+ IPP defined in this document, or if they do interoperate, that some
+ protocol features may not be available.
+
+ The IESG encourages experimentation with this protocol, especially in
+ combination with Transport Layer Security (TLS) [RFC 2246], to help
+ determine how TLS may effectively be used as a security layer for
+ IPP.
+
+
+
+
+
+
+
+
+Herriot, et al. Experimental [Page 1]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+Abstract
+
+ This document is one of a set of documents, which together describe
+ all aspects of a new Internet Printing Protocol (IPP). IPP is an
+ application level protocol that can be used for distributed printing
+ using Internet tools and technologies. This document gives some
+ advice to implementers of gateways between IPP and LPD (Line Printer
+ Daemon). This document describes the mapping between (1) the commands
+ and operands of the 'Line Printer Daemon (LPD) Protocol' specified in
+ RFC 1179 and (2) the operations, operation attributes and job
+ template attributes of the Internet Printing Protocol/1.0 (IPP). One
+ of the purposes of this document is to compare the functionality of
+ the two protocols. Another purpose is to facilitate implementation
+ of gateways between LPD and IPP.
+
+ WARNING: RFC 1179 was not on the IETF standards track. While RFC
+ 1179 was intended to record existing practice, it fell short in some
+ areas. However, this specification maps between (1) the actual
+ current practice of RFC 1179 and (2) IPP. This document does not
+ attempt to map the numerous divergent extensions to the LPD protocol
+ that have been made by many implementers.
+
+ The full set of IPP documents includes:
+
+ Design Goals for an Internet Printing Protocol [RFC2567]
+ Rationale for the Structure and Model and Protocol for the
+ Internet Printing Protocol [RFC2568]
+ Internet Printing Protocol/1.0: Model and Semantics [RFC2566]
+ Internet Printing Protocol/1.0: Encoding and Transport [RFC2565]
+ Internet Printing Protocol/1.0: Implementors Guide [ipp-iig]
+ Mapping between LPD and IPP Protocols (this document)
+
+ The document, "Design Goals for an Internet Printing Protocol", takes
+ a broad look at distributed printing functionality, and it enumerates
+ real-life scenarios that help to clarify the features that need to be
+ included in a printing protocol for the Internet. It identifies
+ requirements for three types of users: end users, operators, and
+ administrators. It calls out a subset of end user requirements that
+ are satisfied in IPP/1.0. Operator and administrator requirements are
+ out of scope for version 1.0.
+
+ The document, "Rationale for the Structure and Model and Protocol for
+ the Internet Printing Protocol", describes IPP from a high level
+ view, defines a roadmap for the various documents that form the suite
+ of IPP specifications, and gives background and rationale for the
+ IETF working group's major decisions.
+
+
+
+
+
+Herriot, et al. Experimental [Page 2]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+ The document, "Internet Printing Protocol/1.0: Model and Semantics",
+ describes a simplified model with abstract objects, their attributes,
+ and their operations. It introduces a Printer and a Job object. The
+ Job object supports multiple documents per Job. It also addresses
+ security, internationalization, and directory issues.
+
+ The document, "Internet Printing Protocol/1.0: Encoding and
+ Transport", is a formal mapping of the abstract operations and
+ attributes defined in the model document onto HTTP/1.1. It defines
+ the encoding rules for a new Internet media type called '
+ application/ipp'.
+
+ This document "Internet Printing Protocol/1.0: Implementer's Guide",
+ gives advice to implementers of IPP clients and IPP objects.
+
+TABLE OF CONTENTS
+
+ 1. Introduction.....................................................4
+ 2. Terminology......................................................5
+ 3. Mapping from LPD Commands to IPP Operations......................5
+ 3.1 Print any waiting jobs..........................................6
+ 3.2 Receive a printer job...........................................6
+ 3.2.1 Abort job.....................................................7
+ 3.2.2 Receive control file..........................................7
+ 3.2.3 Receive data file.............................................8
+ 3.3 Send queue state (short)........................................8
+ 3.4 Send queue state (long)........................................10
+ 3.5 Remove jobs....................................................12
+ 4. Mapping of LPD Control File Lines to IPP Operation and Job
+ Template Attributes.............................................13
+ 4.1 Required Job Functions.........................................13
+ 4.2 Optional Job Functions.........................................14
+ 4.3 Required Document Functions....................................14
+ 4.4 Recommended Document Functions.................................16
+ 5. Mapping from IPP operations to LPD commands.....................16
+ 5.1 Print-Job......................................................16
+ 5.2 Print-URI......................................................18
+ 5.3 Validate-Job...................................................18
+ 5.4 Create-Job.....................................................18
+ 5.5 Send-Document..................................................18
+ 5.6 Send-URI.......................................................18
+ 5.7 Cancel-Job.....................................................18
+ 5.8 Get-Printer-Attributes.........................................19
+ 5.9 Get-Job-Attributes.............................................19
+ 5.10 Get-Jobs......................................................20
+ 6. Mapping of IPP Attributes to LPD Control File Lines.............20
+ 6.1 Required Job Functions.........................................21
+ 6.2 Optional Job Functions.........................................21
+
+
+
+Herriot, et al. Experimental [Page 3]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+ 6.3 Required Document Functions....................................22
+ 7. Security Considerations.........................................23
+ 8. References......................................................23
+ 9. Authors' Addresses..............................................24
+ 10.Appendix A: ABNF Syntax for response of Send-queue-state (short)25
+ 11.Appendix B: ABNF Syntax for response of Send-queue-state (long) 26
+ 12.Appendix C: Unsupported LPD functions...........................27
+ 13.Full Copyright Statement........................................28
+
+1. Introduction
+
+ The reader of this specification is expected to be familiar with the
+ IPP Model and Semantics specification [RFC2566], the IPP Encoding and
+ Transport [RF2565], and the Line Printer Daemon (LPD) protocol
+ specification [RFC1179] as described in RFC 1179.
+
+ RFC 1179 was written in 1990 in an attempt to document existing LPD
+ protocol implementations. Since then, a number of undocumented
+ extensions have been made by vendors to support functionality
+ specific to their printing solutions. All of these extensions
+ consist of additional control file commands. This document does not
+ address any of these vendor extensions. Rather it addresses existing
+ practice within the context of the features described by RFC 1179.
+ Deviations of existing practice from RFC 1179 are so indicated.
+
+ Other LPD control file commands in RFC 1179 are obsolete. They are
+ intended to work on "text" only formats and are inappropriate for
+ many contemporary document formats that completely specify each page.
+ This document does not address the support of these obsolete
+ features.
+
+ In the area of document formats, also known as page description
+ languages (PDL), RFC 1179 defines a fixed set with no capability for
+ extension. Consequently, some new PDL's are not supported, and some
+ of those that are supported are sufficiently unimportant now that
+ they have not been registered for use with the Printer MIB [RFC1759]
+ and IPP [RFC2566] [RFC2565], though they could be registered if
+ desired. See the Printer MIB specification [RFC1759] and/or the IPP
+ Model specification [RFC2566] for instructions for registration of
+ document-formats with IANA. IANA lists the registered document-
+ formats as "printer languages".
+
+ This document addresses the protocol mapping for both directions:
+ mapping of the LPD protocol to the IPP protocol and mapping of the
+ IPP protocol to the LPD protocol. The former is called the "LPD-to-
+ IPP mapper" and the latter is called the "IPP-to-LPD mapper".
+
+
+
+
+
+Herriot, et al. Experimental [Page 4]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+ This document is an informational document that is not on the
+ standards track. It is intended to help implementers of gateways
+ between IPP and LPD. It also provides an example, which gives
+ additional insight into IPP.
+
+2. Terminology
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+ document are to be interpreted as described in RFC 2119 [RFC2119].
+
+ RFC 1179 uses the word "command" in two contexts: for over-the-wire
+ operations and for command file functions. This document SHALL use
+ the word "command" for the former and the phrase "functions" for the
+ latter. The syntax of the LPD commands is given using ABNF
+ [RFC2234].
+
+ The following tokens are used in order to make the syntax more
+ readable:
+
+ LF stands for %x0A (linefeed)
+ SP stands for %x20. (space)
+ DIGIT stands for %x30-39 ("0" to "9")
+
+3. Mapping from LPD Commands to IPP Operations
+
+ This section describes the mapping from LPD commands to IPP
+ operations. Each of the following sub-sections appear as sub-
+ sections of section 5 of RFC 1179.
+
+ The following table summarizes the IPP operation that the mapper uses
+ when it receives an LPD command. Each section below gives more
+ detail:
+
+ LPD command IPP operation
+
+
+ print-any-waiting-jobs ignore
+ receive-a-printer-job Print-Job or Create-Job/Send-Document
+ send queue state Get-Printer-Attributes and Get-Jobs
+ (short or long)
+ remove-jobs Cancel-Job
+
+
+
+
+
+
+
+
+
+Herriot, et al. Experimental [Page 5]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+3.1 Print any waiting jobs
+
+ Command syntax:
+
+ print-waiting-jobs = %x01 printer-name LF
+
+ This command causes the LPD daemon check its queue and print any
+ waiting jobs. An IPP printer handles waiting jobs without such a
+ nudge.
+
+ If the mapper receives this LPD command, it SHALL ignore it and send
+ no IPP operation.
+
+3.2 Receive a printer job
+
+ Command syntax:
+
+ receive-job = %x02 printer-name LF
+
+ The control file and data files mentioned in the following paragraphs
+ are received via LPD sub-commands that follow this command. Their
+ mapping to IPP commands and attributes is described later in this
+ section.
+
+ The mapper maps the 'Receive a printer job' command to either:
+
+ - the Print-Job operation which includes a single data file or
+ - the Create-Job operation followed by one Send-Document operation
+ for each data file.
+
+ If the IPP printer supports both Create-Job and Send-Document, and if
+ a job consists of:
+
+ - a single data file, the mapper SHOULD use the Print-Job
+ operation, but MAY use the Create-Job and Send-Document
+ operations.
+ - more than one data file, the mapper SHALL use Create-Job
+ followed by one Send-Document for each received LPD data file.
+
+ If the IPP printer does not support both Create-Job and Send-
+ Document, and if a job consists of:
+
+ - a single data file, the mapper SHALL use the PrintJob
+ operation.
+ - more than one data file, the mapper SHALL submit each received
+ LPD data file as a separate Print-Job operation (thereby
+ converting a single LPD job into multiple IPP jobs).
+
+
+
+
+Herriot, et al. Experimental [Page 6]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+ If the mapper uses Create-Job and Send-Document, it MUST send the
+ Create-Job operation before it sends any Send-Document operations
+ whether the LPD control file, which supplies attributes for Create-
+ Job, arrives before or after all LPD data files.
+
+ NOTE: This specification does not specify how the mapper maps: the
+ LPD Printer-name operand to the IPP "printer-uri" operation
+ attribute.
+
+ The following three sub-sections gives further details about the
+ mapping from LPD receive-a-printer-job sub-commands. Each of the
+ following subsections appear as sub-sections of section 6 of RFC
+ 1179.
+
+3.2.1 Abort job
+
+ Sub-command syntax:
+
+ abort-job = %x1 LF
+
+ This sub-command of receive-a-printer-job is intended to abort any
+ job transfer in process.
+
+ If the mapper receives this sub-command, it SHALL cancel the job that
+ it is in the process of transmitting.
+
+ If the mapper is in the process of sending a Print-Job or Create-Job
+ operation, it terminates the job either by closing the connection, or
+ performing the Cancel-Job operation with the job-uri that it received
+ from the Print-Job or Create-Job operation.
+
+ NOTE: This sub-command is implied if at any time the connection
+ between the LPD client and server is terminated before an entire
+ print job has been transferred via an LPD Receive-a-printer-job
+ request.
+
+3.2.2 Receive control file
+
+ Sub-command syntax:
+
+ receive-control-file = %x2 number-of-bytes SP name-of-control-file LF
+ number-of-bytes = 1*DIGIT
+ name-of-control-file = "cfA" job-number client-host-name
+ ; e.g. "cfA123woden"
+ job-number = 3DIGIT
+ client-host-name = <a host name>
+
+
+
+
+
+Herriot, et al. Experimental [Page 7]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+ This sub-command is roughly equivalent to the IPP Create-Job
+ operation.
+
+ The mapper SHALL use the contents of the received LPD control file to
+ create IPP operation attribute and job template attribute values to
+ transmit with the Print-Job or Create-Job operation.
+
+3.2.3 Receive data file
+
+Sub-command syntax: %x3 number-of-bytes-in-data-file Name-of-data-file
+
+ receive-data-file = %x03 number-of-bytes SP name-of-data-file LF
+ number-of-bytes = 1*DIGIT
+ name-of-data-file = "df" letter job-number client-host-name
+ ; e.g. "dfA123woden for the first file
+ letter = %x41-5A / %x61-7A ; "A" to "Z", "a" to "z"
+ ; first file is "A",
+ ; second "B", and 52nd file is "z"
+ job-number = 3DIGIT
+ client-host-name = <a host name>
+
+ This sub-command is roughly equivalent to the IPP Send-Document
+ operation.
+
+ The mapper SHALL use the contents of the received LPD data file as
+ the data to transmit with the IPP Print-Job or Send-Document
+ operation.
+
+ Although RFC 1179 alludes to a method for passing an unspecified
+ length data file by using an octet-count of zero, no implementations
+ support this feature. The mapper SHALL reject a job that has a value
+ of 0 in the number-of-bytes field.
+
+3.3 Send queue state (short)
+
+ Command syntax:
+
+send-queue-short = %x03 printer-name *(SP(user-name / job-number)) LF
+
+ The mapper's response to this command includes information about the
+ printer and its jobs. RFC 1179 specifies neither the information nor
+ the format of its response. This document requires the mapper to
+ follow existing practice as specified in this document.
+
+ The mapper SHALL produce a response in the following format which
+ consists of a printer-status line optionally followed by a heading
+ line, and a list of jobs. This format is defined by examples below.
+ Appendix A contains the ABNF syntax.
+
+
+
+Herriot, et al. Experimental [Page 8]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+ For an printer with no jobs, the response starts in column 1 and is:
+
+ no entries
+
+ For a printer with jobs, an example of the response is:
+
+ killtree is ready and printing
+ Rank Owner Job Files Total Size
+ active fred 123 stuff 1204 bytes
+ 1st smith 124 resume, foo 34576 bytes
+ 2nd fred 125 more 99 bytes
+ 3rd mary 126 mydoc 378 bytes
+ 4th jones 127 statistics.ps 4567 bytes
+ 5th fred 128 data.txt 9 bytes
+
+ The column numbers of above headings and job entries are:
+
+ | | | | |
+ 01 08 19 35 63
+
+ The mapper SHALL produce each field above from the following IPP
+ attribute:
+
+ LPD field IPP attribute special conversion details
+
+ printer- printer-state and For a printer-state of idle or
+ status printer-state-reasons processing, the mapper SHALL use
+ the formats above. For stopped,
+ the mapper SHALL use printer-
+ state-reasons to produce an
+ unspecified format for the error.
+ rank number-of- the mapper SHALL the format above
+ intervening-jobs
+ owner job-originating-user- unspecified conversion; job-
+ name originating-user-name may be the
+ mapper's user-name
+ job job-id the mapper shall use the job-id
+ files document-name the mapper shall create a comma
+ separated list of the document-
+ names and then truncate this list
+ to the first 24 characters
+ total- job-k- the mapper shall multiple the
+ size octets*copies*1024 value of job-k-octets by 1024 and
+ by the value of the "copies"
+ attribute.
+
+
+
+
+
+
+Herriot, et al. Experimental [Page 9]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+ A mapper SHOULD use the job attribute number-of-intervening-jobs
+ rather than the job's position in a list of jobs to determine 'rank'
+ because a Printer may omit jobs that it wants to keep secret. If a
+ printer doesn't support the job attribute number-of-intervening-jobs,
+ a mapper MAY use the job's position.
+
+ Note: a Printer may set the value of job-originating-user-name to the
+ authenticated user or to the value of "requesting-user-name",
+ depending on the implementation and configuration. For a gateway, the
+ authenticated user is the user-id of the gateway, but the
+ "requesting-user-name" may contain the name of the user who is the
+ gateway's client.
+
+ In order to obtain the information specified above, The LPD-to-IPP
+ mapper SHALL use the Get-Printer-Attributes operation to get
+ printer-status and SHOULD use the Get-Jobs operation to get
+ information about all of the jobs. If the LPD command contains job-
+ numbers or user-names, the mapper MAY handle the filtering of the
+ response. If the LPD command contains job-numbers but no user-names,
+ the mapper MAY use Get-Job-Attributes on each converted job-number
+ rather than Get-Jobs. If the LPD command contains a single user-name
+ but no job-numbers, the mapper MAY use Get-Jobs with the my-jobs
+ option if the server supports this option and if the server allows
+ the client to be a proxy for the LPD user.
+
+ NOTE: This specification does not define how the mapper maps the LPD
+ Printer-name operand to the IPP "printer-uri" operation attribute.
+
+3.4 Send queue state (long)
+
+ Command syntax:
+
+ send-queue-long = %x04 printer-name *(SP(user-name / job-number)) LF
+
+ The mapper's response to this command includes information about the
+ printer and its jobs. RFC 1179 specifies neither the information nor
+ the format of its response. This document requires the mapper to
+ follow existing practice as specified in this document.
+
+ The mapper SHALL produce a response in the following format which
+ consists of a printer-status line optionally followed a list of jobs,
+ where each job consists of a blank line, a description line, and one
+ line for each file. The description line contains the user-name,
+ rank, job-number and host. This format is defined by examples below.
+ Appendix B contain the ABNF syntax.
+
+
+
+
+
+
+Herriot, et al. Experimental [Page 10]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+ For an printer with no jobs the response is:
+
+ no entries
+
+ For a printer with jobs, an example of the response is:
+
+ killtree is ready and printing
+
+ fred: active [job 123 tiger]
+ 2 copies of stuff 602 bytes
+
+ smith: 1st [job 124 snail]
+ 2 copies of resume 7088 bytes
+ 2 copies of foo 10200 bytes
+
+ fred: 2nd [job 125 tiger]
+ more 99 bytes
+
+ The column numbers of above headings and job entries are:
+
+ | | |
+ 01 09 41
+
+ Although the format of the long form is different from the format of
+ the short form, their fields are identical except for a) the copies
+ and host fields which are only in the long form, and b) the "size"
+ field contains the single copy size of each file. Thus the sum of
+ the file sizes in the "size" field times the value of the "copies"
+ field produces the value for the "Total Size" field in the short
+ form. For fields other than the host and copies fields, see the
+ preceding section. For the host field see the table below.
+
+ LPD field IPP attribute special conversion details
+
+ host unspecified conversion; job-
+ originating-host may be the
+ mapper's host
+ copies copies the mapper shall assume the
+ value of copies precedes the
+ string "copies of "; otherwise,
+ the value of copies is 1.
+
+ NOTE: This specification does not define how the mapper maps the LPD
+ Printer-name operand to the IPP printer-uri operation attribute.
+
+
+
+
+
+
+
+Herriot, et al. Experimental [Page 11]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+3.5 Remove jobs
+
+ Command syntax:
+
+ remove-jobs = %x05 printer-name SP agent
+ *(SP(user-name / job-number)) LF
+
+ The agent operand is the user-name of the user initiating the
+ remove-jobs command. The special user-name 'root' indicates a
+ privileged user who can remove jobs whose user-name differs from the
+ agent.
+
+ The mapper SHALL issue one Cancel-Job operation for each job
+ referenced by the remove-jobs command. Each job-number in the
+ remove-jobs command references a single job. Each user-name in the
+ remove-jobs command implicitly references all jobs owned by the
+ specified user. The active job is implicitly referenced when the
+ remove-jobs command contains neither job-numbers nor user-names. The
+ mapper MAY use Get-Jobs to determine the job-uri of implicitly
+ referenced jobs.
+
+ The mapper SHALL not use the agent name of 'root' when end-users
+ cancel their own jobs. Violation of this rule creates a potential
+ security violation, and it may cause the printer to issue a
+ notification that misleads a user into thinking that some other
+ person canceled the job.
+
+ If the agent of a remove-jobs command for a job J is the same as the
+ user name specified with the 'P' function in the control file for job
+ J, then the mapper SHALL ensure that the initiator of the Cancel-Job
+ command for job J is the same as job-originating-user for job J.
+
+ Note: This requirement means that a mapper must be consistent in who
+ the receiver perceives as the initiator of IPP operations. The mapper
+ either acts as itself or acts on behalf of another user. The latter
+ is preferable if it is possible. This consistency is necessary
+ between Print-Job/Create-Job and Cancel-Job in order for Cancel-Job
+ to work, but it is also desirable for other operations. For example,
+ Get-Jobs may give more information about job submitted by the
+ initiator of this operation.
+
+ NOTE: This specification does not define how the mapper maps: (1) the
+ LPD printer-name to the IPP "printer-uri" or (2) the LPD job-number
+ to the IPP "job-uri".
+
+ NOTE: This specification does not specify how the mapper maps the LPD
+ user-name to the IPP job-originating-user because the mapper may use
+ its own user-name with jobs.
+
+
+
+Herriot, et al. Experimental [Page 12]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+4. Mapping of LPD Control File Lines to IPP Operation and Job Template
+ Attributes
+
+ This section describes the mapping from LPD control file lines
+ (called 'functions') to IPP operation attributes and job template
+ attributes. The mapper receives the control file lines via the LPD
+ receive-control-file sub-command. Each of the LPD functions appear
+ as sub-sections of section 7 of RFC 1179.
+
+ In LPD control file lines, the text operands have a maximum length of
+ 31 or 99 while IPP operation attribute and job template attribute
+ values have a maximum of 255 or 1023 octets, depending on the
+ attribute syntax. Therefore, no data is lost.
+
+ The mapper converts each supported LPD function to its corresponding
+ IPP operation or job template attribute as defined by tables in the
+ subsections that follow. These subsections group functions according
+ to whether they are:
+
+ - required with a job,
+ - optional with a job
+ - required with each document.
+
+ In the tables below, each LPD value is given a name, such as 'h'. If
+ an IPP value uses the LPD value, then the IPP value column contains
+ the LPD name, such as 'h' to denote this. Otherwise, the IPP value
+ column specifies the literal value.
+
+4.1 Required Job Functions
+
+ The following LPD functions MUST be in a received LPD job. The mapper
+ SHALL receive each of the following LPD functions and SHALL include
+ the information as a operation or job template attribute with each
+ IPP job. The functions SHOULD be in the order 'H', 'P' and they
+ SHOULD be the first two functions in the control file, but they MAY
+ be anywhere in the control file and in any order:
+
+ LPD function IPP
+ name value description name value
+
+ H h Originating Host h (in security layer)
+ P u User identification requesting- u (and in security
+ user-name layer)
+ none ipp- 'true'
+ attribute-
+ fidelity
+
+
+
+
+
+Herriot, et al. Experimental [Page 13]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+ A mapper MAY send its own host rather than the client's host, and a
+ mapper MAY send its own user-name as user identification rather than
+ the client user. But in any case, the values sent SHALL be compatible
+ with the Cancel-Job operation. The IPP operation MAY have no way to
+ specify an originating host-name.
+
+ The mapper SHALL include ipp-attribute-fidelity = true so that it
+ doesn't have to determine which attributes a printer supports.
+
+4.2 Optional Job Functions
+
+ The following LPD functions MAY be present in a received job. These
+ functions SHOULD follow the required job functions and precede the
+ document functions, but they MAY be anywhere in the control file.
+
+ If the mapper receives such an LPD function, the mapper SHALL include
+ the corresponding IPP attribute with the value converted as specified
+ in the table below. If the mapper does not receive such an LPD
+ attribute, the mapper SHALL NOT include the corresponding IPP
+ attribute, except the 'L' LPD function whose absence has a special
+ meaning as noted in the table.
+
+ LPD function IPP
+ name value description name value
+
+ J j Job name for job-name j
+ banner page
+ L l Print banner page job-sheets 'standard' if 'L' is
+ present
+ 'none' if 'L' is present
+ M m Mail When Printed IPP has no notification
+ mechanism. To support
+ this LPD feature, the
+ gateway must poll using
+ the Get-Job-Attributes
+ operation.
+
+4.3 Required Document Functions
+
+ The mapper SHALL receive one set of the required document functions
+ with each copy of a document, and SHALL include the converted
+ information as operation or job template attributes with each IPP
+ document.
+
+ If the control file contains required and recommended document
+ functions, the required functions SHOULD precede the recommended ones
+ and if the job contains multiple documents, all the functions for
+
+
+
+
+Herriot, et al. Experimental [Page 14]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+ each document are grouped together as shown in the example of section
+ 6.3 "Required Document Functions". However, the document functions
+ MAY be in any order.
+
+ LPD function IPP
+ name value description name value
+
+ f fff Print formatted document-format 'application/octet-
+ file stream'
+ l fff Print file leaving document-format 'application/octet-
+ control characters stream'
+ o fff Print Postscript document-format 'application/PostScri
+ output file pt'
+ copies see note
+
+ Note: In practice, the 'f' LPD function is often overloaded. It is
+ often used with any format of document data including PostScript and
+ PCL data.
+
+ Note: In practice, the 'l' LPD function is often used as a rough
+ equivalent to the 'f' function.
+
+ Note: When RFC 1179 was written, no implementation supported the 'o'
+ function; instead 'f' was used for PostScript. Windows NT now sends '
+ o' function for a PostScript file.
+
+ Note: the value 'fff' of the 'f', 'l' and 'o' functions is the name
+ of the data file as transferred, e.g. "dfA123woden".
+
+ If the mapper receives any other lower case letter, the mapper SHALL
+ reject the job because the document contains a format that the mapper
+ does not support.
+
+ The mapper determines the number of copies by counting the number of
+ occurrences of each 'fff' file with one of the lower-case functions
+ above. For example, if 'f dfA123woden' occurs 4 times, then copies
+ has a value of 4. Although the LPD protocol allows the value of
+ copies to be different for each document, the commands and the
+ receiving print systems don't support this.
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Experimental [Page 15]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+4.4 Recommended Document Functions
+
+ The mapper SHOULD receive one set of the recommended document
+ functions with each document, and SHOULD include the converted
+ information as an operation or job template attribute with each IPP
+ document. The functions SHOULD be received in the order 'U' and 'N',
+ but they MAY arrive in any order.
+
+ LPD function IPP
+ name value description name value
+
+ U fff ignored
+ N n Name of source file document-name n
+
+ Note: the value 'fff' of the 'U' function is the name of the data
+ file as transferred, e.g. "dfA123woden".
+
+5. Mapping from IPP operations to LPD commands
+
+ If the IPP-to-LPD mapper receives an IPP operation, the following
+ table summarizes the LPD command that it uses. Each section below
+ gives the detail. Each of the following sub-sections appear as sub-
+ sections of section 3 in the document "Internet Printing
+ Protocol/1.0: Model and Semantics" [RFC2566].
+
+ IPP operation LPD command
+
+ Print-Job or Print-URI or receive-a-printer-job
+ Create-Job/Send-Document/Send-URI and then print-any-waiting-jobs
+ Validate-Job implemented by the mapper
+ Cancel-Job remove-jobs
+ Get-Printer-Attributes, Get-Job- send queue state (short or long)
+ Attributes or Get-Jobs
+
+5.1 Print-Job
+
+ The mapper SHALL send the following commands in the order listed
+ below:
+
+ - receive-a-printer-job command
+ - both receive-control-file sub-command and receive-data-file
+ sub-command (unspecified order, see Note below)
+ - print-any-waiting-jobs command, except that if the mapper is
+ sending a sequence of receive a printer-job commands, it MAY
+ omit sending print-any-waiting-jobs after any receive a
+ printer-job command that is neither the first nor last command
+ in this sequence
+
+
+
+
+Herriot, et al. Experimental [Page 16]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+ Note: it is recommended that the order of the receive-control-file
+ subcommand and the receive-data-file sub-command be configurable
+ because either order fails for some print systems. Some print systems
+ assume that the control file follows all data files and start
+ printing immediately on receipt of the control file. When such a
+ print system tries to print a data file that has not arrived, it
+ produces an error. Other print systems assume that the control file
+ arrives before the data files and start printing when the first data
+ file arrives. Such a system ignores the control information, such as
+ banner page or copies.
+
+ NOTE: This specification does not define the mapping between the IPP
+ printer-uri and the LPD printer-name.
+
+ The mapper SHALL send the IPP operation attributes and job template
+ attributes received from the operation to the LPD printer by using
+ the LPD receive-control-file sub-command. The mapper SHALL create the
+ LPD job-number for use in the control file name, but the receiving
+ printer MAY, in some circumstances, assign a different job-number to
+ the job. The mapper SHALL create the IPP job-id and IPP job-uri
+ returned in the Print-Job response.
+
+ NOTE: This specification does not specify how the mapper determines
+ the LPD job-number, the IPP job-id or the IPP job-uri of a job that
+ it creates nor does it specify the relationship between the IPP job-
+ uri, IPP the job-id and the LPD job-number, both of which the mapper
+ creates. However, it is likely that the mapper will use the same
+ integer value for both the LPD job-number and the IPP job-id, and
+ that the IPP Job-uri is the printer's URI with the job-id
+ concatenated on the end.
+
+ The mapper SHALL send data received in the IPP operation to the LPD
+ printer by using the LPD receive-data-file sub-command. The mapper
+ SHALL specify the exact number of bytes being transmitted in the
+ number-of-bytes field of the receive-data-file sub-command. It SHALL
+ NOT use a value of 0 in this field.
+
+ If the mapper, while it is transmitting a receive-a-printer-job
+ command or sub-command, either detects that its IPP connection has
+ closed or receives a Cancel-Job operation, the mapper SHALL terminate
+ the LPD job either with the abort sub-command or the remove-jobs
+ command.
+
+ This document does not address error code conversion.
+
+
+
+
+
+
+
+Herriot, et al. Experimental [Page 17]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+5.2 Print-URI
+
+ The mapper SHALL handle this operation in the same way as a Print-Job
+ operation except that it SHALL obtain data referenced by the
+ "document-uri" operation attribute and SHALL then treat that data as
+ if it had been received via a Print-Job operation.
+
+5.3 Validate-Job
+
+ The mapper SHALL perform this operation directly. Because LPD
+ supports very few attributes, this operation doesn't have much to
+ check.
+
+5.4 Create-Job
+
+ The mapper SHALL handle this operation like Print-Job, except:
+
+ - the mapper SHALL send the control file after it has received the
+ last Send-Document or Send-URI operation because the control
+ file contains all the document-name and document-format values
+ specified in the Send-Document and Send-URI operations.
+ - the mapper SHALL perform one receive-data-file sub-command for
+ each Send-Document or Send-URI operation received and in the
+ same order received.
+ - the mapper SHALL send the control file either before all data
+ files or after all data files. (See the note in the section on
+ Print-Job about the dilemma of sending the control file either
+ before or after the data files.
+
+5.5 Send-Document
+
+ The mapper performs a receive-data-file sub-command on the received
+ data. See the preceding section 5.4 "Create-Job" for the details.
+
+5.6 Send-URI
+
+ The mapper SHALL obtain the data referenced by the "document-uri"
+ operation attribute, and SHALL then treat that data as if it had been
+ received via a Send-Document operation. See the preceding section 5.5
+ "Send-Document" for the details.
+
+5.7 Cancel-Job
+
+ The mapper SHALL perform a remove-jobs command with the following
+ operation attributes:
+
+
+
+
+
+
+Herriot, et al. Experimental [Page 18]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+ - the printer is the one to which the job was submitted, that is
+ the IPP printer-uri is mapped to an LPD printer-name by the same
+ mechanism as for all commands
+ - the agent is the authenticated user-name of the IPP client
+ - the job-number is the job-id returned by the Print-Job command,
+ that is, the LPD job-number has the same value as the IPP job-id
+ for likely implementations
+
+5.8 Get-Printer-Attributes
+
+ LPD severely limits the set of attributes that the mapper is able to
+ return in its response for this operation. The mapper SHALL support,
+ at most, the following printer attributes:
+
+ - printer-state
+ - printer-state-reasons
+
+ The mapper uses either the long or short form of the "send queue
+ state" command.
+
+ The mapper SHALL assume that the LPD response that it receives has
+ the format and information specified in section 3.3 "Send queue state
+ (short)" and section 3.4 "Send queue state (long)". The mapper SHALL
+ determine the value of each requested attribute by using the inverse
+ of the mapping specified in the two aforementioned sections.
+
+ Note: the mapper can determine the response from the printer-status
+ line without examining the rest of the LPD response.
+
+5.9 Get-Job-Attributes
+
+ LPD severely limits the set of attributes that the mapper is able to
+ return in its response for this operation. The mapper SHALL support,
+ at most, the following job attributes:
+
+ - number-of-intervening-jobs
+ - job-originating-user-name
+ - job-id
+ - document-name
+ - job-k-octets
+ - copies
+
+ The mapper uses either the long or short form of the "send queue
+ state" command. If it receives a request for the "job-k-octets" or
+ "copies" and supports the attribute it SHALL use the long form;
+ otherwise, it SHALL use the short form.
+
+
+
+
+
+Herriot, et al. Experimental [Page 19]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+ Note: the value of job-k-octets is the value in the short form
+ divided by the number of "copies" which is on the long form only. Its
+ value can also be determined by adding the "size" field values for
+ each document in the job in the long form.
+
+ The mapper SHALL assume that the LPD response that it receives has
+ the format and information specified in section 3.3 "Send queue state
+ (short)" and section 3.4 "Send queue state (long)". The mapper SHALL
+ determine the value of each requested attribute by using the inverse
+ of the mapping specified in the two aforementioned sections.
+
+ Note: when the mapper uses the LPD short form, it can determine the
+ response from the single LPD line that pertains to the job specified
+ by the Get-Job-Attributes operation.
+
+ Note: the mapper can use its correspondence between the IPP job-id,
+ job-uri and the LPD job-number.
+
+5.10 Get-Jobs
+
+ The mapper SHALL perform this operation in the same way as Get-Job-
+ Attributes except that the mapper converts all the LPD job-lines, and
+ the IPP response contains one job object for each job-line in the LPD
+ response.
+
+6. Mapping of IPP Attributes to LPD Control File Lines
+
+ This section describes the mapping from IPP operation attributes and
+ job template attributes to LPD control file lines (called '
+ functions'). The mapper receives the IPP operation attributes and job
+ template atributes via the IPP operation. Each of the IPP operation
+ attributes and job template attributes appear as sub-sections of
+ section 3 and 4.2 in the IPP model document [RFC2566].
+
+ In the context of LPD control file lines, the text operands have a
+ maximum length of 31 or 99 while IPP operation attributes and job
+ template attributes have a maximum of 255 or 1023 octets, depending
+ on the attribute syntax. Therefore, there may be some data loss if
+ the IPP operation attribute and job template attribute values exceed
+ the maximum length of the LPD equivalent operands.
+
+ The mapper converts each supported IPP operation attribute and job
+ template attribute to its corresponding LPD function as defined by
+ tables in the subsections that follow. These subsections group
+ functions according to whether they are:
+
+
+
+
+
+
+Herriot, et al. Experimental [Page 20]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+ - required with a job,
+ - optional with a job
+ - required with each document.
+
+ In the tables below, each IPP value is given a name, such as 'h'. If
+ an LPD value uses the IPP value, then the LPD value column contains
+ the IPP name, such as 'h' to denote this. Otherwise, the LPD value
+ column specifies the literal value.
+
+6.1 Required Job Functions
+
+ The mapper SHALL include the following LPD functions with each job,
+ and they SHALL have the specified value. They SHALL be the first
+ functions in the control file and they SHALL be in the order "H" and
+ then "P".
+
+ IPP LPD function
+ name value name value description
+
+ (perhaps in security h H gateway host Originating Host
+ layer)
+ requesting-user-name u P u User identification
+ and in the security
+ layer
+
+ A mapper SHALL sends its own host rather than the client's host,
+ because some LPD systems require that it be the same as the host from
+ which the remove-jobs command comes. A mapper MAY send its own user
+ name as user identification rather than the client user. But in any
+ case, the values sent SHALL be compatible with the LPD remove-jobs
+ operation.
+
+6.2 Optional Job Functions
+
+ The mapper MAY include the following LPD functions with each job.
+ They SHALL have the specified value if they are sent. These
+ functions, if present, SHALL follow the require job functions, and
+ they SHALL precede the required document functions.
+
+ IPP attribute LPD function
+ name value name value description
+
+ job-name j J j Job name for banner
+ page
+ job-sheets 'standard' L u Print banner page
+ job-sheets 'none' omit 'L' function
+
+
+
+
+
+Herriot, et al. Experimental [Page 21]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+ Note: 'L' has special meaning when it is omitted. If 'J' is omitted,
+ some undefined behavior occurs with respect to the banner page.
+
+6.3 Required Document Functions
+
+ The mapper SHALL include one set of the following LPD functions with
+ each document, and they SHALL have the specified values. For each
+ document, the order of the functions SHALL be 'f', 'U' and then 'N',
+ where 'f' is replicated once for each copy.
+
+ IPP attribute LPD function
+
+ name value name value description
+
+ document- 'application/octet- f fff Print formatted file
+ format stream' or
+ 'application/PostScript'
+ copies c replicate 'f' 'c'
+ times
+ none U fff Unlink data file
+ document- n N n Name of source file
+ name
+
+ Note: the value 'fff' of the 'f' and 'U' functions is the name of the
+ data file as transferred, e.g. "dfA123woden".
+
+ Note: the mapper SHALL not send the 'o' function
+
+ ISSUE: should we register DVI, troff or ditroff?
+
+ If the mapper receives no "ipp-attribute-fidelitybest-effort" or it
+ has a value of false, then the mapper SHALL reject the job if it
+ specifies attributes or attribute values that are not among those
+ supported in the above tables.
+
+ Below is an example of the minimal control file for a job with three
+ copies of two files 'foo' and 'bar':
+
+ H tiger
+ P jones
+ f dfA123woden
+ f dfA123woden
+ f dfA123woden
+ U dfA123woden
+ N foo
+ f dfB123woden
+ f dfB123woden
+ f dfB123woden
+
+
+
+Herriot, et al. Experimental [Page 22]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+ U dfB123woden
+ N bar
+
+7. Security Considerations
+
+ There are no security issues beyond those covered in the IPP Encoding
+ and Transport document [RFC2565], the IPP model document [RFC2566]
+ and the LPD document [RFC1179].
+
+8. References
+
+ [ipp-iig] Hasting, T., et al., "Internet Printing Protocol/1.0:
+ Implementer's Guide", Work in Progress.
+
+ [RFC1759] Smith, R., Wright, F., Hastings, T., Zilles, S., and J.
+ Gyllenskog, "Printer MIB", RFC 1759, March 1995.
+
+ [RFC1179] McLaughlin, L., "Line Printer Daemon Protocol", RFC 1179,
+ August 1990.
+
+ [RFC2119] Bradner, S. "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+ [RFC2234] D. Crocker et al., "Augmented BNF for Syntax
+ Specifications: ABNF", RFC 2234, November 1997.
+
+ [RFC2565] Herriot, R., Butler, S., Moore, P. and R. Tuner, "Internet
+ Printing Protocol/1.0: Encoding and Transport", RFC 2565,
+ April 1999.
+
+ [RFC2566] deBry, R., Hastings, T., Herriot, R., Isaacson, S., and P.
+ Powell, "Internet Printing Protocol/1.0: Model and
+ Semantics", RFC 2566, April 1999.
+
+ [RFC2567] Wright, D., "Design Goals for an Internet Printing
+ Protocol", RFC 2567, April 1999.
+
+ [RFC2568] Zilles, S., "Rationale for the Structure and Model and
+ Protocol for the Internet Printing Protocol", RFC 2568,
+ April 1999.
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Experimental [Page 23]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+9. Authors' Addresses
+
+ Robert Herriot (Editor)
+ Xerox Corporation
+ 3400 Hillview Ave., Bldg #1
+ Palo Alto, CA 94304
+
+ Phone: 650-813-7696
+ Fax: 650-813-6860
+ EMail: rherriot@pahv.xerox.com
+
+
+ Norm Jacobs
+ Sun Microsystems Inc.
+ 1430 Owl Ridge Rd.
+ Colorado Springs, CO 80919
+
+ Phone: 719-532-9927
+ Fax: 719-535-0956
+ EMail: Norm.Jacobs@Central.sun.com
+
+
+ Thomas N. Hastings
+ Xerox Corporation
+ 701 S. Aviation Blvd., ESAE-231
+ El Segundo, CA 90245
+
+ Phone: 310-333-6413
+ Fax: 310-333-5514
+ EMail: hastings@cp10.es.xerox.com
+
+
+ Jay Martin
+ Underscore, Inc.
+ 41-C Sagamore Park Road
+ Hudson, NH 03051-4915
+
+ Phone: 603-889-7000
+ Fax: 603-889-2699
+ EMail: jkm@underscore.com
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Experimental [Page 24]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+10. Appendix A: ABNF Syntax for response of Send-queue-state (short)
+
+ The syntax in ABNF for the response to the LPD command 'send-queue-
+ state (long)' is:
+
+ status-response = empty-queue / nonempty-queue
+ empty-queue = "no-entries" LF
+ nonempty-queue = printer-status LF heading LF *(job LF)
+ printer-status = OK-status / error-status
+ OK-status = printer-name SP "ready and printing" LF
+ error-status = < implementation dependent status information >
+ heading = "Rank" 3SP "Owner" 6SP "Job" 13SP "Files"
+ 23SP "Total Size" LF
+ ; the column headings and their values below begin
+ at the columns
+ ; 1, 8, 19, 35 and 63
+ job = rank *SP owner *SP job *SP files *SP total-size "bytes"
+ ; jobs are in order of oldest to newest
+ rank = "active" / "1st" / "2nd" / "3rd" / integer "th"
+ ; job that is printing is "active"
+ ; other values show position in the queue
+ owner = <user name of person who submitted the job>
+ job = 1*3DIGIT ; job-number
+ files = <file name> *( "," <file name>) ; truncated to 24 characters
+ total-size = 1*DIGIT ; combined size in bytes of all documents
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Experimental [Page 25]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+11. Appendix B: ABNF Syntax for response of Send-queue-state (long)
+
+ The syntax in ABNF for the response to the LPD command 'send-queue-
+ state (long)' is:
+
+ status-response = empty-queue / nonempty-queue
+ empty-queue = "no-entries" LF
+ nonempty-queue = printer-status LF *job
+ printer-status = OK-status / error-status
+ OK-status = printer-name SP "ready and printing" LF
+ error-status = < implementation dependent status information >
+ job = LF line-1 LF line-2 LF
+ line-1 = owner ":" SP rank 1*SP "[job" job SP host "]"
+ line-2 = file-name 1*SP document-size "bytes"
+ ; jobs are in order of oldest to newest
+ rank = "active" / "1st" / "2nd" / "3rd" / integer "th"
+ ; job that is printing is "active"
+ ; other values show position in the queue
+ owner = <user name of person who submitted the job>
+ job = 1*3DIGIT
+ file-name = [ 1*DIGIT "copies of" SP ] <file name>
+ ; truncated to 24 characters
+ document-size = 1*DIGIT ;size of single copy of the document.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Experimental [Page 26]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+12. Appendix C: Unsupported LPD functions
+
+ The follow LPD functions have no IPP equivalent. The LPD-to-IPP
+ mapper ignores them and the IPP-to-LPD mapper does not send them.
+
+ LPD command
+ name description
+
+ C Class for banner page
+ I Indent Printing
+ H Host of client
+ M Mail when printed
+ S Symbolic link data
+ T Title for pr
+ W Width of output
+ 1 troff R font
+ 2 troff I font
+ 3 troff B font
+ 4 troff S font
+
+ The follow LPD functions specify document-formats which have no IPP
+ equivalent, unless someone registers them. The LPD-to-IPP mapper
+ rejects jobs that request such a document format, and the IPP-to-LPD
+ mapper does not send them.
+
+ LPD command
+ name description
+
+ c Plot CIF file
+ d Print DVI file
+ g Plot file
+ k reserved for Kerberized clients and servers
+ n Print ditroff output file
+ p Print file with 'pr' format
+ r File to print with FORTRAN carriage control
+ t Print troff output file
+ v Print raster file
+ z reserved for future use with the Palladium
+ print system
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Experimental [Page 27]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+13. Full Copyright Statement
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Experimental [Page 28]
+
diff --git a/standards/rfc2595.txt b/standards/rfc2595.txt
new file mode 100644
index 000000000..66897cd6c
--- /dev/null
+++ b/standards/rfc2595.txt
@@ -0,0 +1,843 @@
+
+
+
+
+
+
+Network Working Group C. Newman
+Request for Comments: 2595 Innosoft
+Category: Standards Track June 1999
+
+
+ Using TLS with IMAP, POP3 and ACAP
+
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+1. Motivation
+
+ The TLS protocol (formerly known as SSL) provides a way to secure an
+ application protocol from tampering and eavesdropping. The option of
+ using such security is desirable for IMAP, POP and ACAP due to common
+ connection eavesdropping and hijacking attacks [AUTH]. Although
+ advanced SASL authentication mechanisms can provide a lightweight
+ version of this service, TLS is complimentary to simple
+ authentication-only SASL mechanisms or deployed clear-text password
+ login commands.
+
+ Many sites have a high investment in authentication infrastructure
+ (e.g., a large database of a one-way-function applied to user
+ passwords), so a privacy layer which is not tightly bound to user
+ authentication can protect against network eavesdropping attacks
+ without requiring a new authentication infrastructure and/or forcing
+ all users to change their password. Recognizing that such sites will
+ desire simple password authentication in combination with TLS
+ encryption, this specification defines the PLAIN SASL mechanism for
+ use with protocols which lack a simple password authentication
+ command such as ACAP and SMTP. (Note there is a separate RFC for the
+ STARTTLS command in SMTP [SMTPTLS].)
+
+ There is a strong desire in the IETF to eliminate the transmission of
+ clear-text passwords over unencrypted channels. While SASL can be
+ used for this purpose, TLS provides an additional tool with different
+ deployability characteristics. A server supporting both TLS with
+
+
+
+
+Newman Standards Track [Page 1]
+
+RFC 2595 Using TLS with IMAP, POP3 and ACAP June 1999
+
+
+ simple passwords and a challenge/response SASL mechanism is likely to
+ interoperate with a wide variety of clients without resorting to
+ unencrypted clear-text passwords.
+
+ The STARTTLS command rectifies a number of the problems with using a
+ separate port for a "secure" protocol variant. Some of these are
+ mentioned in section 7.
+
+1.1. Conventions Used in this Document
+
+ The key words "REQUIRED", "MUST", "MUST NOT", "SHOULD", "SHOULD NOT",
+ "MAY", and "OPTIONAL" in this document are to be interpreted as
+ described in "Key words for use in RFCs to Indicate Requirement
+ Levels" [KEYWORDS].
+
+ Terms related to authentication are defined in "On Internet
+ Authentication" [AUTH].
+
+ Formal syntax is defined using ABNF [ABNF].
+
+ In examples, "C:" and "S:" indicate lines sent by the client and
+ server respectively.
+
+2. Basic Interoperability and Security Requirements
+
+ The following requirements apply to all implementations of the
+ STARTTLS extension for IMAP, POP3 and ACAP.
+
+2.1. Cipher Suite Requirements
+
+ Implementation of the TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA [TLS] cipher
+ suite is REQUIRED. This is important as it assures that any two
+ compliant implementations can be configured to interoperate.
+
+ All other cipher suites are OPTIONAL.
+
+2.2. Privacy Operational Mode Security Requirements
+
+ Both clients and servers SHOULD have a privacy operational mode which
+ refuses authentication unless successful activation of an encryption
+ layer (such as that provided by TLS) occurs prior to or at the time
+ of authentication and which will terminate the connection if that
+ encryption layer is deactivated. Implementations are encouraged to
+ have flexability with respect to the minimal encryption strength or
+ cipher suites permitted. A minimalist approach to this
+ recommendation would be an operational mode where the
+ TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA cipher suite is mandatory prior to
+ permitting authentication.
+
+
+
+Newman Standards Track [Page 2]
+
+RFC 2595 Using TLS with IMAP, POP3 and ACAP June 1999
+
+
+ Clients MAY have an operational mode which uses encryption only when
+ it is advertised by the server, but authentication continues
+ regardless. For backwards compatibility, servers SHOULD have an
+ operational mode where only the authentication mechanisms required by
+ the relevant base protocol specification are needed to successfully
+ authenticate.
+
+2.3. Clear-Text Password Requirements
+
+ Clients and servers which implement STARTTLS MUST be configurable to
+ refuse all clear-text login commands or mechanisms (including both
+ standards-track and nonstandard mechanisms) unless an encryption
+ layer of adequate strength is active. Servers which allow
+ unencrypted clear-text logins SHOULD be configurable to refuse
+ clear-text logins both for the entire server, and on a per-user
+ basis.
+
+2.4. Server Identity Check
+
+ During the TLS negotiation, the client MUST check its understanding
+ of the server hostname against the server's identity as presented in
+ the server Certificate message, in order to prevent man-in-the-middle
+ attacks. Matching is performed according to these rules:
+
+ - The client MUST use the server hostname it used to open the
+ connection as the value to compare against the server name as
+ expressed in the server certificate. The client MUST NOT use any
+ form of the server hostname derived from an insecure remote source
+ (e.g., insecure DNS lookup). CNAME canonicalization is not done.
+
+ - If a subjectAltName extension of type dNSName is present in the
+ certificate, it SHOULD be used as the source of the server's
+ identity.
+
+ - Matching is case-insensitive.
+
+ - A "*" wildcard character MAY be used as the left-most name
+ component in the certificate. For example, *.example.com would
+ match a.example.com, foo.example.com, etc. but would not match
+ example.com.
+
+ - If the certificate contains multiple names (e.g. more than one
+ dNSName field), then a match with any one of the fields is
+ considered acceptable.
+
+ If the match fails, the client SHOULD either ask for explicit user
+ confirmation, or terminate the connection and indicate the server's
+ identity is suspect.
+
+
+
+Newman Standards Track [Page 3]
+
+RFC 2595 Using TLS with IMAP, POP3 and ACAP June 1999
+
+
+2.5. TLS Security Policy Check
+
+ Both the client and server MUST check the result of the STARTTLS
+ command and subsequent TLS negotiation to see whether acceptable
+ authentication or privacy was achieved. Ignoring this step
+ completely invalidates using TLS for security. The decision about
+ whether acceptable authentication or privacy was achieved is made
+ locally, is implementation-dependent, and is beyond the scope of this
+ document.
+
+3. IMAP STARTTLS extension
+
+ When the TLS extension is present in IMAP, "STARTTLS" is listed as a
+ capability in response to the CAPABILITY command. This extension
+ adds a single command, "STARTTLS" to the IMAP protocol which is used
+ to begin a TLS negotiation.
+
+3.1. STARTTLS Command
+
+ Arguments: none
+
+ Responses: no specific responses for this command
+
+ Result: OK - begin TLS negotiation
+ BAD - command unknown or arguments invalid
+
+ A TLS negotiation begins immediately after the CRLF at the end of
+ the tagged OK response from the server. Once a client issues a
+ STARTTLS command, it MUST NOT issue further commands until a
+ server response is seen and the TLS negotiation is complete.
+
+ The STARTTLS command is only valid in non-authenticated state.
+ The server remains in non-authenticated state, even if client
+ credentials are supplied during the TLS negotiation. The SASL
+ [SASL] EXTERNAL mechanism MAY be used to authenticate once TLS
+ client credentials are successfully exchanged, but servers
+ supporting the STARTTLS command are not required to support the
+ EXTERNAL mechanism.
+
+ Once TLS has been started, the client MUST discard cached
+ information about server capabilities and SHOULD re-issue the
+ CAPABILITY command. This is necessary to protect against
+ man-in-the-middle attacks which alter the capabilities list prior
+ to STARTTLS. The server MAY advertise different capabilities
+ after STARTTLS.
+
+ The formal syntax for IMAP is amended as follows:
+
+
+
+
+Newman Standards Track [Page 4]
+
+RFC 2595 Using TLS with IMAP, POP3 and ACAP June 1999
+
+
+ command_any =/ "STARTTLS"
+
+ Example: C: a001 CAPABILITY
+ S: * CAPABILITY IMAP4rev1 STARTTLS LOGINDISABLED
+ S: a001 OK CAPABILITY completed
+ C: a002 STARTTLS
+ S: a002 OK Begin TLS negotiation now
+ <TLS negotiation, further commands are under TLS layer>
+ C: a003 CAPABILITY
+ S: * CAPABILITY IMAP4rev1 AUTH=EXTERNAL
+ S: a003 OK CAPABILITY completed
+ C: a004 LOGIN joe password
+ S: a004 OK LOGIN completed
+
+3.2. IMAP LOGINDISABLED capability
+
+ The current IMAP protocol specification (RFC 2060) requires the
+ implementation of the LOGIN command which uses clear-text passwords.
+ Many sites may choose to disable this command unless encryption is
+ active for security reasons. An IMAP server MAY advertise that the
+ LOGIN command is disabled by including the LOGINDISABLED capability
+ in the capability response. Such a server will respond with a tagged
+ "NO" response to any attempt to use the LOGIN command.
+
+ An IMAP server which implements STARTTLS MUST implement support for
+ the LOGINDISABLED capability on unencrypted connections.
+
+ An IMAP client which complies with this specification MUST NOT issue
+ the LOGIN command if this capability is present.
+
+ This capability is useful to prevent clients compliant with this
+ specification from sending an unencrypted password in an environment
+ subject to passive attacks. It has no impact on an environment
+ subject to active attacks as a man-in-the-middle attacker can remove
+ this capability. Therefore this does not relieve clients of the need
+ to follow the privacy mode recommendation in section 2.2.
+
+ Servers advertising this capability will fail to interoperate with
+ many existing compliant IMAP clients and will be unable to prevent
+ those clients from disclosing the user's password.
+
+4. POP3 STARTTLS extension
+
+ The POP3 STARTTLS extension adds the STLS command to POP3 servers.
+ If this is implemented, the POP3 extension mechanism [POP3EXT] MUST
+ also be implemented to avoid the need for client probing of multiple
+ commands. The capability name "STLS" indicates this command is
+ present and permitted in the current state.
+
+
+
+Newman Standards Track [Page 5]
+
+RFC 2595 Using TLS with IMAP, POP3 and ACAP June 1999
+
+
+ STLS
+
+ Arguments: none
+
+ Restrictions:
+ Only permitted in AUTHORIZATION state.
+
+ Discussion:
+ A TLS negotiation begins immediately after the CRLF at the
+ end of the +OK response from the server. A -ERR response
+ MAY result if a security layer is already active. Once a
+ client issues a STLS command, it MUST NOT issue further
+ commands until a server response is seen and the TLS
+ negotiation is complete.
+
+ The STLS command is only permitted in AUTHORIZATION state
+ and the server remains in AUTHORIZATION state, even if
+ client credentials are supplied during the TLS negotiation.
+ The AUTH command [POP-AUTH] with the EXTERNAL mechanism
+ [SASL] MAY be used to authenticate once TLS client
+ credentials are successfully exchanged, but servers
+ supporting the STLS command are not required to support the
+ EXTERNAL mechanism.
+
+ Once TLS has been started, the client MUST discard cached
+ information about server capabilities and SHOULD re-issue
+ the CAPA command. This is necessary to protect against
+ man-in-the-middle attacks which alter the capabilities list
+ prior to STLS. The server MAY advertise different
+ capabilities after STLS.
+
+ Possible Responses:
+ +OK -ERR
+
+ Examples:
+ C: STLS
+ S: +OK Begin TLS negotiation
+ <TLS negotiation, further commands are under TLS layer>
+ ...
+ C: STLS
+ S: -ERR Command not permitted when TLS active
+
+
+
+
+
+
+
+
+
+
+Newman Standards Track [Page 6]
+
+RFC 2595 Using TLS with IMAP, POP3 and ACAP June 1999
+
+
+5. ACAP STARTTLS extension
+
+ When the TLS extension is present in ACAP, "STARTTLS" is listed as a
+ capability in the ACAP greeting. No arguments to this capability are
+ defined at this time. This extension adds a single command,
+ "STARTTLS" to the ACAP protocol which is used to begin a TLS
+ negotiation.
+
+5.1. STARTTLS Command
+
+ Arguments: none
+
+ Responses: no specific responses for this command
+
+ Result: OK - begin TLS negotiation
+ BAD - command unknown or arguments invalid
+
+ A TLS negotiation begins immediately after the CRLF at the end of
+ the tagged OK response from the server. Once a client issues a
+ STARTTLS command, it MUST NOT issue further commands until a
+ server response is seen and the TLS negotiation is complete.
+
+ The STARTTLS command is only valid in non-authenticated state.
+ The server remains in non-authenticated state, even if client
+ credentials are supplied during the TLS negotiation. The SASL
+ [SASL] EXTERNAL mechanism MAY be used to authenticate once TLS
+ client credentials are successfully exchanged, but servers
+ supporting the STARTTLS command are not required to support the
+ EXTERNAL mechanism.
+
+ After the TLS layer is established, the server MUST re-issue an
+ untagged ACAP greeting. This is necessary to protect against
+ man-in-the-middle attacks which alter the capabilities list prior
+ to STARTTLS. The client MUST discard cached capability
+ information and replace it with the information from the new ACAP
+ greeting. The server MAY advertise different capabilities after
+ STARTTLS.
+
+ The formal syntax for ACAP is amended as follows:
+
+ command_any =/ "STARTTLS"
+
+ Example: S: * ACAP (SASL "CRAM-MD5") (STARTTLS)
+ C: a002 STARTTLS
+ S: a002 OK "Begin TLS negotiation now"
+ <TLS negotiation, further commands are under TLS layer>
+ S: * ACAP (SASL "CRAM-MD5" "PLAIN" "EXTERNAL")
+
+
+
+
+Newman Standards Track [Page 7]
+
+RFC 2595 Using TLS with IMAP, POP3 and ACAP June 1999
+
+
+6. PLAIN SASL mechanism
+
+ Clear-text passwords are simple, interoperate with almost all
+ existing operating system authentication databases, and are useful
+ for a smooth transition to a more secure password-based
+ authentication mechanism. The drawback is that they are unacceptable
+ for use over an unencrypted network connection.
+
+ This defines the "PLAIN" SASL mechanism for use with ACAP and other
+ protocols with no clear-text login command. The PLAIN SASL mechanism
+ MUST NOT be advertised or used unless a strong encryption layer (such
+ as the provided by TLS) is active or backwards compatibility dictates
+ otherwise.
+
+ The mechanism consists of a single message from the client to the
+ server. The client sends the authorization identity (identity to
+ login as), followed by a US-ASCII NUL character, followed by the
+ authentication identity (identity whose password will be used),
+ followed by a US-ASCII NUL character, followed by the clear-text
+ password. The client may leave the authorization identity empty to
+ indicate that it is the same as the authentication identity.
+
+ The server will verify the authentication identity and password with
+ the system authentication database and verify that the authentication
+ credentials permit the client to login as the authorization identity.
+ If both steps succeed, the user is logged in.
+
+ The server MAY also use the password to initialize any new
+ authentication database, such as one suitable for CRAM-MD5
+ [CRAM-MD5].
+
+ Non-US-ASCII characters are permitted as long as they are represented
+ in UTF-8 [UTF-8]. Use of non-visible characters or characters which
+ a user may be unable to enter on some keyboards is discouraged.
+
+ The formal grammar for the client message using Augmented BNF [ABNF]
+ follows.
+
+ message = [authorize-id] NUL authenticate-id NUL password
+ authenticate-id = 1*UTF8-SAFE ; MUST accept up to 255 octets
+ authorize-id = 1*UTF8-SAFE ; MUST accept up to 255 octets
+ password = 1*UTF8-SAFE ; MUST accept up to 255 octets
+ NUL = %x00
+ UTF8-SAFE = %x01-09 / %x0B-0C / %x0E-7F / UTF8-2 /
+ UTF8-3 / UTF8-4 / UTF8-5 / UTF8-6
+ UTF8-1 = %x80-BF
+ UTF8-2 = %xC0-DF UTF8-1
+ UTF8-3 = %xE0-EF 2UTF8-1
+
+
+
+Newman Standards Track [Page 8]
+
+RFC 2595 Using TLS with IMAP, POP3 and ACAP June 1999
+
+
+ UTF8-4 = %xF0-F7 3UTF8-1
+ UTF8-5 = %xF8-FB 4UTF8-1
+ UTF8-6 = %xFC-FD 5UTF8-1
+
+ Here is an example of how this might be used to initialize a CRAM-MD5
+ authentication database for ACAP:
+
+ Example: S: * ACAP (SASL "CRAM-MD5") (STARTTLS)
+ C: a001 AUTHENTICATE "CRAM-MD5"
+ S: + "<1896.697170952@postoffice.reston.mci.net>"
+ C: "tim b913a602c7eda7a495b4e6e7334d3890"
+ S: a001 NO (TRANSITION-NEEDED)
+ "Please change your password, or use TLS to login"
+ C: a002 STARTTLS
+ S: a002 OK "Begin TLS negotiation now"
+ <TLS negotiation, further commands are under TLS layer>
+ S: * ACAP (SASL "CRAM-MD5" "PLAIN" "EXTERNAL")
+ C: a003 AUTHENTICATE "PLAIN" {21+}
+ C: <NUL>tim<NUL>tanstaaftanstaaf
+ S: a003 OK CRAM-MD5 password initialized
+
+ Note: In this example, <NUL> represents a single ASCII NUL octet.
+
+7. imaps and pop3s ports
+
+ Separate "imaps" and "pop3s" ports were registered for use with SSL.
+ Use of these ports is discouraged in favor of the STARTTLS or STLS
+ commands.
+
+ A number of problems have been observed with separate ports for
+ "secure" variants of protocols. This is an attempt to enumerate some
+ of those problems.
+
+ - Separate ports lead to a separate URL scheme which intrudes into
+ the user interface in inappropriate ways. For example, many web
+ pages use language like "click here if your browser supports SSL."
+ This is a decision the browser is often more capable of making than
+ the user.
+
+ - Separate ports imply a model of either "secure" or "not secure."
+ This can be misleading in a number of ways. First, the "secure"
+ port may not in fact be acceptably secure as an export-crippled
+ cipher suite might be in use. This can mislead users into a false
+ sense of security. Second, the normal port might in fact be
+ secured by using a SASL mechanism which includes a security layer.
+ Thus the separate port distinction makes the complex topic of
+ security policy even more confusing. One common result of this
+ confusion is that firewall administrators are often misled into
+
+
+
+Newman Standards Track [Page 9]
+
+RFC 2595 Using TLS with IMAP, POP3 and ACAP June 1999
+
+
+ permitting the "secure" port and blocking the standard port. This
+ could be a poor choice given the common use of SSL with a 40-bit
+ key encryption layer and plain-text password authentication is less
+ secure than strong SASL mechanisms such as GSSAPI with Kerberos 5.
+
+ - Use of separate ports for SSL has caused clients to implement only
+ two security policies: use SSL or don't use SSL. The desirable
+ security policy "use TLS when available" would be cumbersome with
+ the separate port model, but is simple with STARTTLS.
+
+ - Port numbers are a limited resource. While they are not yet in
+ short supply, it is unwise to set a precedent that could double (or
+ worse) the speed of their consumption.
+
+
+8. IANA Considerations
+
+ This constitutes registration of the "STARTTLS" and "LOGINDISABLED"
+ IMAP capabilities as required by section 7.2.1 of RFC 2060 [IMAP].
+
+ The registration for the POP3 "STLS" capability follows:
+
+ CAPA tag: STLS
+ Arguments: none
+ Added commands: STLS
+ Standard commands affected: May enable USER/PASS as a side-effect.
+ CAPA command SHOULD be re-issued after successful completion.
+ Announced states/Valid states: AUTHORIZATION state only.
+ Specification reference: this memo
+
+ The registration for the ACAP "STARTTLS" capability follows:
+
+ Capability name: STARTTLS
+ Capability keyword: STARTTLS
+ Capability arguments: none
+ Published Specification(s): this memo
+ Person and email address for further information:
+ see author's address section below
+
+ The registration for the PLAIN SASL mechanism follows:
+
+ SASL mechanism name: PLAIN
+ Security Considerations: See section 9 of this memo
+ Published specification: this memo
+ Person & email address to contact for further information:
+ see author's address section below
+ Intended usage: COMMON
+ Author/Change controller: see author's address section below
+
+
+
+Newman Standards Track [Page 10]
+
+RFC 2595 Using TLS with IMAP, POP3 and ACAP June 1999
+
+
+9. Security Considerations
+
+ TLS only provides protection for data sent over a network connection.
+ Messages transferred over IMAP or POP3 are still available to server
+ administrators and usually subject to eavesdropping, tampering and
+ forgery when transmitted through SMTP or NNTP. TLS is no substitute
+ for an end-to-end message security mechanism using MIME security
+ multiparts [MIME-SEC].
+
+ A man-in-the-middle attacker can remove STARTTLS from the capability
+ list or generate a failure response to the STARTTLS command. In
+ order to detect such an attack, clients SHOULD warn the user when
+ session privacy is not active and/or be configurable to refuse to
+ proceed without an acceptable level of security.
+
+ A man-in-the-middle attacker can always cause a down-negotiation to
+ the weakest authentication mechanism or cipher suite available. For
+ this reason, implementations SHOULD be configurable to refuse weak
+ mechanisms or cipher suites.
+
+ Any protocol interactions prior to the TLS handshake are performed in
+ the clear and can be modified by a man-in-the-middle attacker. For
+ this reason, clients MUST discard cached information about server
+ capabilities advertised prior to the start of the TLS handshake.
+
+ Clients are encouraged to clearly indicate when the level of
+ encryption active is known to be vulnerable to attack using modern
+ hardware (such as encryption keys with 56 bits of entropy or less).
+
+ The LOGINDISABLED IMAP capability (discussed in section 3.2) only
+ reduces the potential for passive attacks, it provides no protection
+ against active attacks. The responsibility remains with the client
+ to avoid sending a password over a vulnerable channel.
+
+ The PLAIN mechanism relies on the TLS encryption layer for security.
+ When used without TLS, it is vulnerable to a common network
+ eavesdropping attack. Therefore PLAIN MUST NOT be advertised or used
+ unless a suitable TLS encryption layer is active or backwards
+ compatibility dictates otherwise.
+
+ When the PLAIN mechanism is used, the server gains the ability to
+ impersonate the user to all services with the same password
+ regardless of any encryption provided by TLS or other network privacy
+ mechanisms. While many other authentication mechanisms have similar
+ weaknesses, stronger SASL mechanisms such as Kerberos address this
+ issue. Clients are encouraged to have an operational mode where all
+ mechanisms which are likely to reveal the user's password to the
+ server are disabled.
+
+
+
+Newman Standards Track [Page 11]
+
+RFC 2595 Using TLS with IMAP, POP3 and ACAP June 1999
+
+
+ The security considerations for TLS apply to STARTTLS and the
+ security considerations for SASL apply to the PLAIN mechanism.
+ Additional security requirements are discussed in section 2.
+
+10. References
+
+ [ABNF] Crocker, D. and P. Overell, "Augmented BNF for Syntax
+ Specifications: ABNF", RFC 2234, November 1997.
+
+ [ACAP] Newman, C. and J. Myers, "ACAP -- Application
+ Configuration Access Protocol", RFC 2244, November 1997.
+
+ [AUTH] Haller, N. and R. Atkinson, "On Internet Authentication",
+ RFC 1704, October 1994.
+
+ [CRAM-MD5] Klensin, J., Catoe, R. and P. Krumviede, "IMAP/POP
+ AUTHorize Extension for Simple Challenge/Response", RFC
+ 2195, September 1997.
+
+ [IMAP] Crispin, M., "Internet Message Access Protocol - Version
+ 4rev1", RFC 2060, December 1996.
+
+ [KEYWORDS] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+ [MIME-SEC] Galvin, J., Murphy, S., Crocker, S. and N. Freed,
+ "Security Multiparts for MIME: Multipart/Signed and
+ Multipart/Encrypted", RFC 1847, October 1995.
+
+ [POP3] Myers, J. and M. Rose, "Post Office Protocol - Version 3",
+ STD 53, RFC 1939, May 1996.
+
+ [POP3EXT] Gellens, R., Newman, C. and L. Lundblade, "POP3 Extension
+ Mechanism", RFC 2449, November 1998.
+
+ [POP-AUTH] Myers, J., "POP3 AUTHentication command", RFC 1734,
+ December 1994.
+
+ [SASL] Myers, J., "Simple Authentication and Security Layer
+ (SASL)", RFC 2222, October 1997.
+
+ [SMTPTLS] Hoffman, P., "SMTP Service Extension for Secure SMTP over
+ TLS", RFC 2487, January 1999.
+
+ [TLS] Dierks, T. and C. Allen, "The TLS Protocol Version 1.0",
+ RFC 2246, January 1999.
+
+
+
+
+
+Newman Standards Track [Page 12]
+
+RFC 2595 Using TLS with IMAP, POP3 and ACAP June 1999
+
+
+ [UTF-8] Yergeau, F., "UTF-8, a transformation format of ISO
+ 10646", RFC 2279, January 1998.
+
+
+11. Author's Address
+
+ Chris Newman
+ Innosoft International, Inc.
+ 1050 Lakes Drive
+ West Covina, CA 91790 USA
+
+ EMail: chris.newman@innosoft.com
+
+
+A. Appendix -- Compliance Checklist
+
+ An implementation is not compliant if it fails to satisfy one or more
+ of the MUST requirements for the protocols it implements. An
+ implementation that satisfies all the MUST and all the SHOULD
+ requirements for its protocols is said to be "unconditionally
+ compliant"; one that satisfies all the MUST requirements but not all
+ the SHOULD requirements for its protocols is said to be
+ "conditionally compliant".
+
+ Rules Section
+ ----- -------
+ Mandatory-to-implement Cipher Suite 2.1
+ SHOULD have mode where encryption required 2.2
+ server SHOULD have mode where TLS not required 2.2
+ MUST be configurable to refuse all clear-text login
+ commands or mechanisms 2.3
+ server SHOULD be configurable to refuse clear-text
+ login commands on entire server and on per-user basis 2.3
+ client MUST check server identity 2.4
+ client MUST use hostname used to open connection 2.4
+ client MUST NOT use hostname from insecure remote lookup 2.4
+ client SHOULD support subjectAltName of dNSName type 2.4
+ client SHOULD ask for confirmation or terminate on fail 2.4
+ MUST check result of STARTTLS for acceptable privacy 2.5
+ client MUST NOT issue commands after STARTTLS
+ until server response and negotiation done 3.1,4,5.1
+ client MUST discard cached information 3.1,4,5.1,9
+ client SHOULD re-issue CAPABILITY/CAPA command 3.1,4
+ IMAP server with STARTTLS MUST implement LOGINDISABLED 3.2
+ IMAP client MUST NOT issue LOGIN if LOGINDISABLED 3.2
+ POP server MUST implement POP3 extensions 4
+ ACAP server MUST re-issue ACAP greeting 5.1
+
+
+
+
+Newman Standards Track [Page 13]
+
+RFC 2595 Using TLS with IMAP, POP3 and ACAP June 1999
+
+
+ client SHOULD warn when session privacy not active and/or
+ refuse to proceed without acceptable security level 9
+ SHOULD be configurable to refuse weak mechanisms or
+ cipher suites 9
+
+ The PLAIN mechanism is an optional part of this specification.
+ However if it is implemented the following rules apply:
+
+ Rules Section
+ ----- -------
+ MUST NOT use PLAIN unless strong encryption active
+ or backwards compatibility dictates otherwise 6,9
+ MUST use UTF-8 encoding for characters in PLAIN 6
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Newman Standards Track [Page 14]
+
+RFC 2595 Using TLS with IMAP, POP3 and ACAP June 1999
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Newman Standards Track [Page 15]
+
diff --git a/standards/rfc2616.txt b/standards/rfc2616.txt
new file mode 100644
index 000000000..45d7d08b8
--- /dev/null
+++ b/standards/rfc2616.txt
@@ -0,0 +1,9859 @@
+
+
+
+
+
+
+Network Working Group R. Fielding
+Request for Comments: 2616 UC Irvine
+Obsoletes: 2068 J. Gettys
+Category: Standards Track Compaq/W3C
+ J. Mogul
+ Compaq
+ H. Frystyk
+ W3C/MIT
+ L. Masinter
+ Xerox
+ P. Leach
+ Microsoft
+ T. Berners-Lee
+ W3C/MIT
+ June 1999
+
+
+ Hypertext Transfer Protocol -- HTTP/1.1
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+Abstract
+
+ The Hypertext Transfer Protocol (HTTP) is an application-level
+ protocol for distributed, collaborative, hypermedia information
+ systems. It is a generic, stateless, protocol which can be used for
+ many tasks beyond its use for hypertext, such as name servers and
+ distributed object management systems, through extension of its
+ request methods, error codes and headers [47]. A feature of HTTP is
+ the typing and negotiation of data representation, allowing systems
+ to be built independently of the data being transferred.
+
+ HTTP has been in use by the World-Wide Web global information
+ initiative since 1990. This specification defines the protocol
+ referred to as "HTTP/1.1", and is an update to RFC 2068 [33].
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 1]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+Table of Contents
+
+ 1 Introduction ...................................................7
+ 1.1 Purpose......................................................7
+ 1.2 Requirements .................................................8
+ 1.3 Terminology ..................................................8
+ 1.4 Overall Operation ...........................................12
+ 2 Notational Conventions and Generic Grammar ....................14
+ 2.1 Augmented BNF ...............................................14
+ 2.2 Basic Rules .................................................15
+ 3 Protocol Parameters ...........................................17
+ 3.1 HTTP Version ................................................17
+ 3.2 Uniform Resource Identifiers ................................18
+ 3.2.1 General Syntax ...........................................19
+ 3.2.2 http URL .................................................19
+ 3.2.3 URI Comparison ...........................................20
+ 3.3 Date/Time Formats ...........................................20
+ 3.3.1 Full Date ................................................20
+ 3.3.2 Delta Seconds ............................................21
+ 3.4 Character Sets ..............................................21
+ 3.4.1 Missing Charset ..........................................22
+ 3.5 Content Codings .............................................23
+ 3.6 Transfer Codings ............................................24
+ 3.6.1 Chunked Transfer Coding ..................................25
+ 3.7 Media Types .................................................26
+ 3.7.1 Canonicalization and Text Defaults .......................27
+ 3.7.2 Multipart Types ..........................................27
+ 3.8 Product Tokens ..............................................28
+ 3.9 Quality Values ..............................................29
+ 3.10 Language Tags ...............................................29
+ 3.11 Entity Tags .................................................30
+ 3.12 Range Units .................................................30
+ 4 HTTP Message ..................................................31
+ 4.1 Message Types ...............................................31
+ 4.2 Message Headers .............................................31
+ 4.3 Message Body ................................................32
+ 4.4 Message Length ..............................................33
+ 4.5 General Header Fields .......................................34
+ 5 Request .......................................................35
+ 5.1 Request-Line ................................................35
+ 5.1.1 Method ...................................................36
+ 5.1.2 Request-URI ..............................................36
+ 5.2 The Resource Identified by a Request ........................38
+ 5.3 Request Header Fields .......................................38
+ 6 Response ......................................................39
+ 6.1 Status-Line .................................................39
+ 6.1.1 Status Code and Reason Phrase ............................39
+ 6.2 Response Header Fields ......................................41
+
+
+
+Fielding, et al. Standards Track [Page 2]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ 7 Entity ........................................................42
+ 7.1 Entity Header Fields ........................................42
+ 7.2 Entity Body .................................................43
+ 7.2.1 Type .....................................................43
+ 7.2.2 Entity Length ............................................43
+ 8 Connections ...................................................44
+ 8.1 Persistent Connections ......................................44
+ 8.1.1 Purpose ..................................................44
+ 8.1.2 Overall Operation ........................................45
+ 8.1.3 Proxy Servers ............................................46
+ 8.1.4 Practical Considerations .................................46
+ 8.2 Message Transmission Requirements ...........................47
+ 8.2.1 Persistent Connections and Flow Control ..................47
+ 8.2.2 Monitoring Connections for Error Status Messages .........48
+ 8.2.3 Use of the 100 (Continue) Status .........................48
+ 8.2.4 Client Behavior if Server Prematurely Closes Connection ..50
+ 9 Method Definitions ............................................51
+ 9.1 Safe and Idempotent Methods .................................51
+ 9.1.1 Safe Methods .............................................51
+ 9.1.2 Idempotent Methods .......................................51
+ 9.2 OPTIONS .....................................................52
+ 9.3 GET .........................................................53
+ 9.4 HEAD ........................................................54
+ 9.5 POST ........................................................54
+ 9.6 PUT .........................................................55
+ 9.7 DELETE ......................................................56
+ 9.8 TRACE .......................................................56
+ 9.9 CONNECT .....................................................57
+ 10 Status Code Definitions ......................................57
+ 10.1 Informational 1xx ...........................................57
+ 10.1.1 100 Continue .............................................58
+ 10.1.2 101 Switching Protocols ..................................58
+ 10.2 Successful 2xx ..............................................58
+ 10.2.1 200 OK ...................................................58
+ 10.2.2 201 Created ..............................................59
+ 10.2.3 202 Accepted .............................................59
+ 10.2.4 203 Non-Authoritative Information ........................59
+ 10.2.5 204 No Content ...........................................60
+ 10.2.6 205 Reset Content ........................................60
+ 10.2.7 206 Partial Content ......................................60
+ 10.3 Redirection 3xx .............................................61
+ 10.3.1 300 Multiple Choices .....................................61
+ 10.3.2 301 Moved Permanently ....................................62
+ 10.3.3 302 Found ................................................62
+ 10.3.4 303 See Other ............................................63
+ 10.3.5 304 Not Modified .........................................63
+ 10.3.6 305 Use Proxy ............................................64
+ 10.3.7 306 (Unused) .............................................64
+
+
+
+Fielding, et al. Standards Track [Page 3]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ 10.3.8 307 Temporary Redirect ...................................65
+ 10.4 Client Error 4xx ............................................65
+ 10.4.1 400 Bad Request .........................................65
+ 10.4.2 401 Unauthorized ........................................66
+ 10.4.3 402 Payment Required ....................................66
+ 10.4.4 403 Forbidden ...........................................66
+ 10.4.5 404 Not Found ...........................................66
+ 10.4.6 405 Method Not Allowed ..................................66
+ 10.4.7 406 Not Acceptable ......................................67
+ 10.4.8 407 Proxy Authentication Required .......................67
+ 10.4.9 408 Request Timeout .....................................67
+ 10.4.10 409 Conflict ............................................67
+ 10.4.11 410 Gone ................................................68
+ 10.4.12 411 Length Required .....................................68
+ 10.4.13 412 Precondition Failed .................................68
+ 10.4.14 413 Request Entity Too Large ............................69
+ 10.4.15 414 Request-URI Too Long ................................69
+ 10.4.16 415 Unsupported Media Type ..............................69
+ 10.4.17 416 Requested Range Not Satisfiable .....................69
+ 10.4.18 417 Expectation Failed ..................................70
+ 10.5 Server Error 5xx ............................................70
+ 10.5.1 500 Internal Server Error ................................70
+ 10.5.2 501 Not Implemented ......................................70
+ 10.5.3 502 Bad Gateway ..........................................70
+ 10.5.4 503 Service Unavailable ..................................70
+ 10.5.5 504 Gateway Timeout ......................................71
+ 10.5.6 505 HTTP Version Not Supported ...........................71
+ 11 Access Authentication ........................................71
+ 12 Content Negotiation ..........................................71
+ 12.1 Server-driven Negotiation ...................................72
+ 12.2 Agent-driven Negotiation ....................................73
+ 12.3 Transparent Negotiation .....................................74
+ 13 Caching in HTTP ..............................................74
+ 13.1.1 Cache Correctness ........................................75
+ 13.1.2 Warnings .................................................76
+ 13.1.3 Cache-control Mechanisms .................................77
+ 13.1.4 Explicit User Agent Warnings .............................78
+ 13.1.5 Exceptions to the Rules and Warnings .....................78
+ 13.1.6 Client-controlled Behavior ...............................79
+ 13.2 Expiration Model ............................................79
+ 13.2.1 Server-Specified Expiration ..............................79
+ 13.2.2 Heuristic Expiration .....................................80
+ 13.2.3 Age Calculations .........................................80
+ 13.2.4 Expiration Calculations ..................................83
+ 13.2.5 Disambiguating Expiration Values .........................84
+ 13.2.6 Disambiguating Multiple Responses ........................84
+ 13.3 Validation Model ............................................85
+ 13.3.1 Last-Modified Dates ......................................86
+
+
+
+Fielding, et al. Standards Track [Page 4]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ 13.3.2 Entity Tag Cache Validators ..............................86
+ 13.3.3 Weak and Strong Validators ...............................86
+ 13.3.4 Rules for When to Use Entity Tags and Last-Modified Dates.89
+ 13.3.5 Non-validating Conditionals ..............................90
+ 13.4 Response Cacheability .......................................91
+ 13.5 Constructing Responses From Caches ..........................92
+ 13.5.1 End-to-end and Hop-by-hop Headers ........................92
+ 13.5.2 Non-modifiable Headers ...................................92
+ 13.5.3 Combining Headers ........................................94
+ 13.5.4 Combining Byte Ranges ....................................95
+ 13.6 Caching Negotiated Responses ................................95
+ 13.7 Shared and Non-Shared Caches ................................96
+ 13.8 Errors or Incomplete Response Cache Behavior ................97
+ 13.9 Side Effects of GET and HEAD ................................97
+ 13.10 Invalidation After Updates or Deletions ...................97
+ 13.11 Write-Through Mandatory ...................................98
+ 13.12 Cache Replacement .........................................99
+ 13.13 History Lists .............................................99
+ 14 Header Field Definitions ....................................100
+ 14.1 Accept .....................................................100
+ 14.2 Accept-Charset .............................................102
+ 14.3 Accept-Encoding ............................................102
+ 14.4 Accept-Language ............................................104
+ 14.5 Accept-Ranges ..............................................105
+ 14.6 Age ........................................................106
+ 14.7 Allow ......................................................106
+ 14.8 Authorization ..............................................107
+ 14.9 Cache-Control ..............................................108
+ 14.9.1 What is Cacheable .......................................109
+ 14.9.2 What May be Stored by Caches ............................110
+ 14.9.3 Modifications of the Basic Expiration Mechanism .........111
+ 14.9.4 Cache Revalidation and Reload Controls ..................113
+ 14.9.5 No-Transform Directive ..................................115
+ 14.9.6 Cache Control Extensions ................................116
+ 14.10 Connection ...............................................117
+ 14.11 Content-Encoding .........................................118
+ 14.12 Content-Language .........................................118
+ 14.13 Content-Length ...........................................119
+ 14.14 Content-Location .........................................120
+ 14.15 Content-MD5 ..............................................121
+ 14.16 Content-Range ............................................122
+ 14.17 Content-Type .............................................124
+ 14.18 Date .....................................................124
+ 14.18.1 Clockless Origin Server Operation ......................125
+ 14.19 ETag .....................................................126
+ 14.20 Expect ...................................................126
+ 14.21 Expires ..................................................127
+ 14.22 From .....................................................128
+
+
+
+Fielding, et al. Standards Track [Page 5]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ 14.23 Host .....................................................128
+ 14.24 If-Match .................................................129
+ 14.25 If-Modified-Since ........................................130
+ 14.26 If-None-Match ............................................132
+ 14.27 If-Range .................................................133
+ 14.28 If-Unmodified-Since ......................................134
+ 14.29 Last-Modified ............................................134
+ 14.30 Location .................................................135
+ 14.31 Max-Forwards .............................................136
+ 14.32 Pragma ...................................................136
+ 14.33 Proxy-Authenticate .......................................137
+ 14.34 Proxy-Authorization ......................................137
+ 14.35 Range ....................................................138
+ 14.35.1 Byte Ranges ...........................................138
+ 14.35.2 Range Retrieval Requests ..............................139
+ 14.36 Referer ..................................................140
+ 14.37 Retry-After ..............................................141
+ 14.38 Server ...................................................141
+ 14.39 TE .......................................................142
+ 14.40 Trailer ..................................................143
+ 14.41 Transfer-Encoding..........................................143
+ 14.42 Upgrade ..................................................144
+ 14.43 User-Agent ...............................................145
+ 14.44 Vary .....................................................145
+ 14.45 Via ......................................................146
+ 14.46 Warning ..................................................148
+ 14.47 WWW-Authenticate .........................................150
+ 15 Security Considerations .......................................150
+ 15.1 Personal Information....................................151
+ 15.1.1 Abuse of Server Log Information .........................151
+ 15.1.2 Transfer of Sensitive Information .......................151
+ 15.1.3 Encoding Sensitive Information in URI's .................152
+ 15.1.4 Privacy Issues Connected to Accept Headers ..............152
+ 15.2 Attacks Based On File and Path Names .......................153
+ 15.3 DNS Spoofing ...............................................154
+ 15.4 Location Headers and Spoofing ..............................154
+ 15.5 Content-Disposition Issues .................................154
+ 15.6 Authentication Credentials and Idle Clients ................155
+ 15.7 Proxies and Caching ........................................155
+ 15.7.1 Denial of Service Attacks on Proxies....................156
+ 16 Acknowledgments .............................................156
+ 17 References ..................................................158
+ 18 Authors' Addresses ..........................................162
+ 19 Appendices ..................................................164
+ 19.1 Internet Media Type message/http and application/http ......164
+ 19.2 Internet Media Type multipart/byteranges ...................165
+ 19.3 Tolerant Applications ......................................166
+ 19.4 Differences Between HTTP Entities and RFC 2045 Entities ....167
+
+
+
+Fielding, et al. Standards Track [Page 6]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ 19.4.1 MIME-Version ............................................167
+ 19.4.2 Conversion to Canonical Form ............................167
+ 19.4.3 Conversion of Date Formats ..............................168
+ 19.4.4 Introduction of Content-Encoding ........................168
+ 19.4.5 No Content-Transfer-Encoding ............................168
+ 19.4.6 Introduction of Transfer-Encoding .......................169
+ 19.4.7 MHTML and Line Length Limitations .......................169
+ 19.5 Additional Features ........................................169
+ 19.5.1 Content-Disposition .....................................170
+ 19.6 Compatibility with Previous Versions .......................170
+ 19.6.1 Changes from HTTP/1.0 ...................................171
+ 19.6.2 Compatibility with HTTP/1.0 Persistent Connections ......172
+ 19.6.3 Changes from RFC 2068 ...................................172
+ 20 Index .......................................................175
+ 21 Full Copyright Statement ....................................176
+
+1 Introduction
+
+1.1 Purpose
+
+ The Hypertext Transfer Protocol (HTTP) is an application-level
+ protocol for distributed, collaborative, hypermedia information
+ systems. HTTP has been in use by the World-Wide Web global
+ information initiative since 1990. The first version of HTTP,
+ referred to as HTTP/0.9, was a simple protocol for raw data transfer
+ across the Internet. HTTP/1.0, as defined by RFC 1945 [6], improved
+ the protocol by allowing messages to be in the format of MIME-like
+ messages, containing metainformation about the data transferred and
+ modifiers on the request/response semantics. However, HTTP/1.0 does
+ not sufficiently take into consideration the effects of hierarchical
+ proxies, caching, the need for persistent connections, or virtual
+ hosts. In addition, the proliferation of incompletely-implemented
+ applications calling themselves "HTTP/1.0" has necessitated a
+ protocol version change in order for two communicating applications
+ to determine each other's true capabilities.
+
+ This specification defines the protocol referred to as "HTTP/1.1".
+ This protocol includes more stringent requirements than HTTP/1.0 in
+ order to ensure reliable implementation of its features.
+
+ Practical information systems require more functionality than simple
+ retrieval, including search, front-end update, and annotation. HTTP
+ allows an open-ended set of methods and headers that indicate the
+ purpose of a request [47]. It builds on the discipline of reference
+ provided by the Uniform Resource Identifier (URI) [3], as a location
+ (URL) [4] or name (URN) [20], for indicating the resource to which a
+
+
+
+
+
+Fielding, et al. Standards Track [Page 7]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ method is to be applied. Messages are passed in a format similar to
+ that used by Internet mail [9] as defined by the Multipurpose
+ Internet Mail Extensions (MIME) [7].
+
+ HTTP is also used as a generic protocol for communication between
+ user agents and proxies/gateways to other Internet systems, including
+ those supported by the SMTP [16], NNTP [13], FTP [18], Gopher [2],
+ and WAIS [10] protocols. In this way, HTTP allows basic hypermedia
+ access to resources available from diverse applications.
+
+1.2 Requirements
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+ document are to be interpreted as described in RFC 2119 [34].
+
+ An implementation is not compliant if it fails to satisfy one or more
+ of the MUST or REQUIRED level requirements for the protocols it
+ implements. An implementation that satisfies all the MUST or REQUIRED
+ level and all the SHOULD level requirements for its protocols is said
+ to be "unconditionally compliant"; one that satisfies all the MUST
+ level requirements but not all the SHOULD level requirements for its
+ protocols is said to be "conditionally compliant."
+
+1.3 Terminology
+
+ This specification uses a number of terms to refer to the roles
+ played by participants in, and objects of, the HTTP communication.
+
+ connection
+ A transport layer virtual circuit established between two programs
+ for the purpose of communication.
+
+ message
+ The basic unit of HTTP communication, consisting of a structured
+ sequence of octets matching the syntax defined in section 4 and
+ transmitted via the connection.
+
+ request
+ An HTTP request message, as defined in section 5.
+
+ response
+ An HTTP response message, as defined in section 6.
+
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 8]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ resource
+ A network data object or service that can be identified by a URI,
+ as defined in section 3.2. Resources may be available in multiple
+ representations (e.g. multiple languages, data formats, size, and
+ resolutions) or vary in other ways.
+
+ entity
+ The information transferred as the payload of a request or
+ response. An entity consists of metainformation in the form of
+ entity-header fields and content in the form of an entity-body, as
+ described in section 7.
+
+ representation
+ An entity included with a response that is subject to content
+ negotiation, as described in section 12. There may exist multiple
+ representations associated with a particular response status.
+
+ content negotiation
+ The mechanism for selecting the appropriate representation when
+ servicing a request, as described in section 12. The
+ representation of entities in any response can be negotiated
+ (including error responses).
+
+ variant
+ A resource may have one, or more than one, representation(s)
+ associated with it at any given instant. Each of these
+ representations is termed a `varriant'. Use of the term `variant'
+ does not necessarily imply that the resource is subject to content
+ negotiation.
+
+ client
+ A program that establishes connections for the purpose of sending
+ requests.
+
+ user agent
+ The client which initiates a request. These are often browsers,
+ editors, spiders (web-traversing robots), or other end user tools.
+
+ server
+ An application program that accepts connections in order to
+ service requests by sending back responses. Any given program may
+ be capable of being both a client and a server; our use of these
+ terms refers only to the role being performed by the program for a
+ particular connection, rather than to the program's capabilities
+ in general. Likewise, any server may act as an origin server,
+ proxy, gateway, or tunnel, switching behavior based on the nature
+ of each request.
+
+
+
+
+Fielding, et al. Standards Track [Page 9]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ origin server
+ The server on which a given resource resides or is to be created.
+
+ proxy
+ An intermediary program which acts as both a server and a client
+ for the purpose of making requests on behalf of other clients.
+ Requests are serviced internally or by passing them on, with
+ possible translation, to other servers. A proxy MUST implement
+ both the client and server requirements of this specification. A
+ "transparent proxy" is a proxy that does not modify the request or
+ response beyond what is required for proxy authentication and
+ identification. A "non-transparent proxy" is a proxy that modifies
+ the request or response in order to provide some added service to
+ the user agent, such as group annotation services, media type
+ transformation, protocol reduction, or anonymity filtering. Except
+ where either transparent or non-transparent behavior is explicitly
+ stated, the HTTP proxy requirements apply to both types of
+ proxies.
+
+ gateway
+ A server which acts as an intermediary for some other server.
+ Unlike a proxy, a gateway receives requests as if it were the
+ origin server for the requested resource; the requesting client
+ may not be aware that it is communicating with a gateway.
+
+ tunnel
+ An intermediary program which is acting as a blind relay between
+ two connections. Once active, a tunnel is not considered a party
+ to the HTTP communication, though the tunnel may have been
+ initiated by an HTTP request. The tunnel ceases to exist when both
+ ends of the relayed connections are closed.
+
+ cache
+ A program's local store of response messages and the subsystem
+ that controls its message storage, retrieval, and deletion. A
+ cache stores cacheable responses in order to reduce the response
+ time and network bandwidth consumption on future, equivalent
+ requests. Any client or server may include a cache, though a cache
+ cannot be used by a server that is acting as a tunnel.
+
+ cacheable
+ A response is cacheable if a cache is allowed to store a copy of
+ the response message for use in answering subsequent requests. The
+ rules for determining the cacheability of HTTP responses are
+ defined in section 13. Even if a resource is cacheable, there may
+ be additional constraints on whether a cache can use the cached
+ copy for a particular request.
+
+
+
+
+Fielding, et al. Standards Track [Page 10]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ first-hand
+ A response is first-hand if it comes directly and without
+ unnecessary delay from the origin server, perhaps via one or more
+ proxies. A response is also first-hand if its validity has just
+ been checked directly with the origin server.
+
+ explicit expiration time
+ The time at which the origin server intends that an entity should
+ no longer be returned by a cache without further validation.
+
+ heuristic expiration time
+ An expiration time assigned by a cache when no explicit expiration
+ time is available.
+
+ age
+ The age of a response is the time since it was sent by, or
+ successfully validated with, the origin server.
+
+ freshness lifetime
+ The length of time between the generation of a response and its
+ expiration time.
+
+ fresh
+ A response is fresh if its age has not yet exceeded its freshness
+ lifetime.
+
+ stale
+ A response is stale if its age has passed its freshness lifetime.
+
+ semantically transparent
+ A cache behaves in a "semantically transparent" manner, with
+ respect to a particular response, when its use affects neither the
+ requesting client nor the origin server, except to improve
+ performance. When a cache is semantically transparent, the client
+ receives exactly the same response (except for hop-by-hop headers)
+ that it would have received had its request been handled directly
+ by the origin server.
+
+ validator
+ A protocol element (e.g., an entity tag or a Last-Modified time)
+ that is used to find out whether a cache entry is an equivalent
+ copy of an entity.
+
+ upstream/downstream
+ Upstream and downstream describe the flow of a message: all
+ messages flow from upstream to downstream.
+
+
+
+
+
+Fielding, et al. Standards Track [Page 11]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ inbound/outbound
+ Inbound and outbound refer to the request and response paths for
+ messages: "inbound" means "traveling toward the origin server",
+ and "outbound" means "traveling toward the user agent"
+
+1.4 Overall Operation
+
+ The HTTP protocol is a request/response protocol. A client sends a
+ request to the server in the form of a request method, URI, and
+ protocol version, followed by a MIME-like message containing request
+ modifiers, client information, and possible body content over a
+ connection with a server. The server responds with a status line,
+ including the message's protocol version and a success or error code,
+ followed by a MIME-like message containing server information, entity
+ metainformation, and possible entity-body content. The relationship
+ between HTTP and MIME is described in appendix 19.4.
+
+ Most HTTP communication is initiated by a user agent and consists of
+ a request to be applied to a resource on some origin server. In the
+ simplest case, this may be accomplished via a single connection (v)
+ between the user agent (UA) and the origin server (O).
+
+ request chain ------------------------>
+ UA -------------------v------------------- O
+ <----------------------- response chain
+
+ A more complicated situation occurs when one or more intermediaries
+ are present in the request/response chain. There are three common
+ forms of intermediary: proxy, gateway, and tunnel. A proxy is a
+ forwarding agent, receiving requests for a URI in its absolute form,
+ rewriting all or part of the message, and forwarding the reformatted
+ request toward the server identified by the URI. A gateway is a
+ receiving agent, acting as a layer above some other server(s) and, if
+ necessary, translating the requests to the underlying server's
+ protocol. A tunnel acts as a relay point between two connections
+ without changing the messages; tunnels are used when the
+ communication needs to pass through an intermediary (such as a
+ firewall) even when the intermediary cannot understand the contents
+ of the messages.
+
+ request chain -------------------------------------->
+ UA -----v----- A -----v----- B -----v----- C -----v----- O
+ <------------------------------------- response chain
+
+ The figure above shows three intermediaries (A, B, and C) between the
+ user agent and origin server. A request or response message that
+ travels the whole chain will pass through four separate connections.
+ This distinction is important because some HTTP communication options
+
+
+
+Fielding, et al. Standards Track [Page 12]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ may apply only to the connection with the nearest, non-tunnel
+ neighbor, only to the end-points of the chain, or to all connections
+ along the chain. Although the diagram is linear, each participant may
+ be engaged in multiple, simultaneous communications. For example, B
+ may be receiving requests from many clients other than A, and/or
+ forwarding requests to servers other than C, at the same time that it
+ is handling A's request.
+
+ Any party to the communication which is not acting as a tunnel may
+ employ an internal cache for handling requests. The effect of a cache
+ is that the request/response chain is shortened if one of the
+ participants along the chain has a cached response applicable to that
+ request. The following illustrates the resulting chain if B has a
+ cached copy of an earlier response from O (via C) for a request which
+ has not been cached by UA or A.
+
+ request chain ---------->
+ UA -----v----- A -----v----- B - - - - - - C - - - - - - O
+ <--------- response chain
+
+ Not all responses are usefully cacheable, and some requests may
+ contain modifiers which place special requirements on cache behavior.
+ HTTP requirements for cache behavior and cacheable responses are
+ defined in section 13.
+
+ In fact, there are a wide variety of architectures and configurations
+ of caches and proxies currently being experimented with or deployed
+ across the World Wide Web. These systems include national hierarchies
+ of proxy caches to save transoceanic bandwidth, systems that
+ broadcast or multicast cache entries, organizations that distribute
+ subsets of cached data via CD-ROM, and so on. HTTP systems are used
+ in corporate intranets over high-bandwidth links, and for access via
+ PDAs with low-power radio links and intermittent connectivity. The
+ goal of HTTP/1.1 is to support the wide diversity of configurations
+ already deployed while introducing protocol constructs that meet the
+ needs of those who build web applications that require high
+ reliability and, failing that, at least reliable indications of
+ failure.
+
+ HTTP communication usually takes place over TCP/IP connections. The
+ default port is TCP 80 [19], but other ports can be used. This does
+ not preclude HTTP from being implemented on top of any other protocol
+ on the Internet, or on other networks. HTTP only presumes a reliable
+ transport; any protocol that provides such guarantees can be used;
+ the mapping of the HTTP/1.1 request and response structures onto the
+ transport data units of the protocol in question is outside the scope
+ of this specification.
+
+
+
+
+Fielding, et al. Standards Track [Page 13]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ In HTTP/1.0, most implementations used a new connection for each
+ request/response exchange. In HTTP/1.1, a connection may be used for
+ one or more request/response exchanges, although connections may be
+ closed for a variety of reasons (see section 8.1).
+
+2 Notational Conventions and Generic Grammar
+
+2.1 Augmented BNF
+
+ All of the mechanisms specified in this document are described in
+ both prose and an augmented Backus-Naur Form (BNF) similar to that
+ used by RFC 822 [9]. Implementors will need to be familiar with the
+ notation in order to understand this specification. The augmented BNF
+ includes the following constructs:
+
+ name = definition
+ The name of a rule is simply the name itself (without any
+ enclosing "<" and ">") and is separated from its definition by the
+ equal "=" character. White space is only significant in that
+ indentation of continuation lines is used to indicate a rule
+ definition that spans more than one line. Certain basic rules are
+ in uppercase, such as SP, LWS, HT, CRLF, DIGIT, ALPHA, etc. Angle
+ brackets are used within definitions whenever their presence will
+ facilitate discerning the use of rule names.
+
+ "literal"
+ Quotation marks surround literal text. Unless stated otherwise,
+ the text is case-insensitive.
+
+ rule1 | rule2
+ Elements separated by a bar ("|") are alternatives, e.g., "yes |
+ no" will accept yes or no.
+
+ (rule1 rule2)
+ Elements enclosed in parentheses are treated as a single element.
+ Thus, "(elem (foo | bar) elem)" allows the token sequences "elem
+ foo elem" and "elem bar elem".
+
+ *rule
+ The character "*" preceding an element indicates repetition. The
+ full form is "<n>*<m>element" indicating at least <n> and at most
+ <m> occurrences of element. Default values are 0 and infinity so
+ that "*(element)" allows any number, including zero; "1*element"
+ requires at least one; and "1*2element" allows one or two.
+
+ [rule]
+ Square brackets enclose optional elements; "[foo bar]" is
+ equivalent to "*1(foo bar)".
+
+
+
+Fielding, et al. Standards Track [Page 14]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ N rule
+ Specific repetition: "<n>(element)" is equivalent to
+ "<n>*<n>(element)"; that is, exactly <n> occurrences of (element).
+ Thus 2DIGIT is a 2-digit number, and 3ALPHA is a string of three
+ alphabetic characters.
+
+ #rule
+ A construct "#" is defined, similar to "*", for defining lists of
+ elements. The full form is "<n>#<m>element" indicating at least
+ <n> and at most <m> elements, each separated by one or more commas
+ (",") and OPTIONAL linear white space (LWS). This makes the usual
+ form of lists very easy; a rule such as
+ ( *LWS element *( *LWS "," *LWS element ))
+ can be shown as
+ 1#element
+ Wherever this construct is used, null elements are allowed, but do
+ not contribute to the count of elements present. That is,
+ "(element), , (element) " is permitted, but counts as only two
+ elements. Therefore, where at least one element is required, at
+ least one non-null element MUST be present. Default values are 0
+ and infinity so that "#element" allows any number, including zero;
+ "1#element" requires at least one; and "1#2element" allows one or
+ two.
+
+ ; comment
+ A semi-colon, set off some distance to the right of rule text,
+ starts a comment that continues to the end of line. This is a
+ simple way of including useful notes in parallel with the
+ specifications.
+
+ implied *LWS
+ The grammar described by this specification is word-based. Except
+ where noted otherwise, linear white space (LWS) can be included
+ between any two adjacent words (token or quoted-string), and
+ between adjacent words and separators, without changing the
+ interpretation of a field. At least one delimiter (LWS and/or
+
+ separators) MUST exist between any two tokens (for the definition
+ of "token" below), since they would otherwise be interpreted as a
+ single token.
+
+2.2 Basic Rules
+
+ The following rules are used throughout this specification to
+ describe basic parsing constructs. The US-ASCII coded character set
+ is defined by ANSI X3.4-1986 [21].
+
+
+
+
+
+Fielding, et al. Standards Track [Page 15]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ OCTET = <any 8-bit sequence of data>
+ CHAR = <any US-ASCII character (octets 0 - 127)>
+ UPALPHA = <any US-ASCII uppercase letter "A".."Z">
+ LOALPHA = <any US-ASCII lowercase letter "a".."z">
+ ALPHA = UPALPHA | LOALPHA
+ DIGIT = <any US-ASCII digit "0".."9">
+ CTL = <any US-ASCII control character
+ (octets 0 - 31) and DEL (127)>
+ CR = <US-ASCII CR, carriage return (13)>
+ LF = <US-ASCII LF, linefeed (10)>
+ SP = <US-ASCII SP, space (32)>
+ HT = <US-ASCII HT, horizontal-tab (9)>
+ <"> = <US-ASCII double-quote mark (34)>
+
+ HTTP/1.1 defines the sequence CR LF as the end-of-line marker for all
+ protocol elements except the entity-body (see appendix 19.3 for
+ tolerant applications). The end-of-line marker within an entity-body
+ is defined by its associated media type, as described in section 3.7.
+
+ CRLF = CR LF
+
+ HTTP/1.1 header field values can be folded onto multiple lines if the
+ continuation line begins with a space or horizontal tab. All linear
+ white space, including folding, has the same semantics as SP. A
+ recipient MAY replace any linear white space with a single SP before
+ interpreting the field value or forwarding the message downstream.
+
+ LWS = [CRLF] 1*( SP | HT )
+
+ The TEXT rule is only used for descriptive field contents and values
+ that are not intended to be interpreted by the message parser. Words
+ of *TEXT MAY contain characters from character sets other than ISO-
+ 8859-1 [22] only when encoded according to the rules of RFC 2047
+ [14].
+
+ TEXT = <any OCTET except CTLs,
+ but including LWS>
+
+ A CRLF is allowed in the definition of TEXT only as part of a header
+ field continuation. It is expected that the folding LWS will be
+ replaced with a single SP before interpretation of the TEXT value.
+
+ Hexadecimal numeric characters are used in several protocol elements.
+
+ HEX = "A" | "B" | "C" | "D" | "E" | "F"
+ | "a" | "b" | "c" | "d" | "e" | "f" | DIGIT
+
+
+
+
+
+Fielding, et al. Standards Track [Page 16]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ Many HTTP/1.1 header field values consist of words separated by LWS
+ or special characters. These special characters MUST be in a quoted
+ string to be used within a parameter value (as defined in section
+ 3.6).
+
+ token = 1*<any CHAR except CTLs or separators>
+ separators = "(" | ")" | "<" | ">" | "@"
+ | "," | ";" | ":" | "\" | <">
+ | "/" | "[" | "]" | "?" | "="
+ | "{" | "}" | SP | HT
+
+ Comments can be included in some HTTP header fields by surrounding
+ the comment text with parentheses. Comments are only allowed in
+ fields containing "comment" as part of their field value definition.
+ In all other fields, parentheses are considered part of the field
+ value.
+
+ comment = "(" *( ctext | quoted-pair | comment ) ")"
+ ctext = <any TEXT excluding "(" and ")">
+
+ A string of text is parsed as a single word if it is quoted using
+ double-quote marks.
+
+ quoted-string = ( <"> *(qdtext | quoted-pair ) <"> )
+ qdtext = <any TEXT except <">>
+
+ The backslash character ("\") MAY be used as a single-character
+ quoting mechanism only within quoted-string and comment constructs.
+
+ quoted-pair = "\" CHAR
+
+3 Protocol Parameters
+
+3.1 HTTP Version
+
+ HTTP uses a "<major>.<minor>" numbering scheme to indicate versions
+ of the protocol. The protocol versioning policy is intended to allow
+ the sender to indicate the format of a message and its capacity for
+ understanding further HTTP communication, rather than the features
+ obtained via that communication. No change is made to the version
+ number for the addition of message components which do not affect
+ communication behavior or which only add to extensible field values.
+ The <minor> number is incremented when the changes made to the
+ protocol add features which do not change the general message parsing
+ algorithm, but which may add to the message semantics and imply
+ additional capabilities of the sender. The <major> number is
+ incremented when the format of a message within the protocol is
+ changed. See RFC 2145 [36] for a fuller explanation.
+
+
+
+Fielding, et al. Standards Track [Page 17]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ The version of an HTTP message is indicated by an HTTP-Version field
+ in the first line of the message.
+
+ HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT
+
+ Note that the major and minor numbers MUST be treated as separate
+ integers and that each MAY be incremented higher than a single digit.
+ Thus, HTTP/2.4 is a lower version than HTTP/2.13, which in turn is
+ lower than HTTP/12.3. Leading zeros MUST be ignored by recipients and
+ MUST NOT be sent.
+
+ An application that sends a request or response message that includes
+ HTTP-Version of "HTTP/1.1" MUST be at least conditionally compliant
+ with this specification. Applications that are at least conditionally
+ compliant with this specification SHOULD use an HTTP-Version of
+ "HTTP/1.1" in their messages, and MUST do so for any message that is
+ not compatible with HTTP/1.0. For more details on when to send
+ specific HTTP-Version values, see RFC 2145 [36].
+
+ The HTTP version of an application is the highest HTTP version for
+ which the application is at least conditionally compliant.
+
+ Proxy and gateway applications need to be careful when forwarding
+ messages in protocol versions different from that of the application.
+ Since the protocol version indicates the protocol capability of the
+ sender, a proxy/gateway MUST NOT send a message with a version
+ indicator which is greater than its actual version. If a higher
+ version request is received, the proxy/gateway MUST either downgrade
+ the request version, or respond with an error, or switch to tunnel
+ behavior.
+
+ Due to interoperability problems with HTTP/1.0 proxies discovered
+ since the publication of RFC 2068[33], caching proxies MUST, gateways
+ MAY, and tunnels MUST NOT upgrade the request to the highest version
+ they support. The proxy/gateway's response to that request MUST be in
+ the same major version as the request.
+
+ Note: Converting between versions of HTTP may involve modification
+ of header fields required or forbidden by the versions involved.
+
+3.2 Uniform Resource Identifiers
+
+ URIs have been known by many names: WWW addresses, Universal Document
+ Identifiers, Universal Resource Identifiers [3], and finally the
+ combination of Uniform Resource Locators (URL) [4] and Names (URN)
+ [20]. As far as HTTP is concerned, Uniform Resource Identifiers are
+ simply formatted strings which identify--via name, location, or any
+ other characteristic--a resource.
+
+
+
+Fielding, et al. Standards Track [Page 18]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+3.2.1 General Syntax
+
+ URIs in HTTP can be represented in absolute form or relative to some
+ known base URI [11], depending upon the context of their use. The two
+ forms are differentiated by the fact that absolute URIs always begin
+ with a scheme name followed by a colon. For definitive information on
+ URL syntax and semantics, see "Uniform Resource Identifiers (URI):
+ Generic Syntax and Semantics," RFC 2396 [42] (which replaces RFCs
+ 1738 [4] and RFC 1808 [11]). This specification adopts the
+ definitions of "URI-reference", "absoluteURI", "relativeURI", "port",
+ "host","abs_path", "rel_path", and "authority" from that
+ specification.
+
+ The HTTP protocol does not place any a priori limit on the length of
+ a URI. Servers MUST be able to handle the URI of any resource they
+ serve, and SHOULD be able to handle URIs of unbounded length if they
+ provide GET-based forms that could generate such URIs. A server
+ SHOULD return 414 (Request-URI Too Long) status if a URI is longer
+ than the server can handle (see section 10.4.15).
+
+ Note: Servers ought to be cautious about depending on URI lengths
+ above 255 bytes, because some older client or proxy
+ implementations might not properly support these lengths.
+
+3.2.2 http URL
+
+ The "http" scheme is used to locate network resources via the HTTP
+ protocol. This section defines the scheme-specific syntax and
+ semantics for http URLs.
+
+ http_URL = "http:" "//" host [ ":" port ] [ abs_path [ "?" query ]]
+
+ If the port is empty or not given, port 80 is assumed. The semantics
+ are that the identified resource is located at the server listening
+ for TCP connections on that port of that host, and the Request-URI
+ for the resource is abs_path (section 5.1.2). The use of IP addresses
+ in URLs SHOULD be avoided whenever possible (see RFC 1900 [24]). If
+ the abs_path is not present in the URL, it MUST be given as "/" when
+ used as a Request-URI for a resource (section 5.1.2). If a proxy
+ receives a host name which is not a fully qualified domain name, it
+ MAY add its domain to the host name it received. If a proxy receives
+ a fully qualified domain name, the proxy MUST NOT change the host
+ name.
+
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 19]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+3.2.3 URI Comparison
+
+ When comparing two URIs to decide if they match or not, a client
+ SHOULD use a case-sensitive octet-by-octet comparison of the entire
+ URIs, with these exceptions:
+
+ - A port that is empty or not given is equivalent to the default
+ port for that URI-reference;
+
+ - Comparisons of host names MUST be case-insensitive;
+
+ - Comparisons of scheme names MUST be case-insensitive;
+
+ - An empty abs_path is equivalent to an abs_path of "/".
+
+ Characters other than those in the "reserved" and "unsafe" sets (see
+ RFC 2396 [42]) are equivalent to their ""%" HEX HEX" encoding.
+
+ For example, the following three URIs are equivalent:
+
+ http://abc.com:80/~smith/home.html
+ http://ABC.com/%7Esmith/home.html
+ http://ABC.com:/%7esmith/home.html
+
+3.3 Date/Time Formats
+
+3.3.1 Full Date
+
+ HTTP applications have historically allowed three different formats
+ for the representation of date/time stamps:
+
+ Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123
+ Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
+ Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format
+
+ The first format is preferred as an Internet standard and represents
+ a fixed-length subset of that defined by RFC 1123 [8] (an update to
+ RFC 822 [9]). The second format is in common use, but is based on the
+ obsolete RFC 850 [12] date format and lacks a four-digit year.
+ HTTP/1.1 clients and servers that parse the date value MUST accept
+ all three formats (for compatibility with HTTP/1.0), though they MUST
+ only generate the RFC 1123 format for representing HTTP-date values
+ in header fields. See section 19.3 for further information.
+
+ Note: Recipients of date values are encouraged to be robust in
+ accepting date values that may have been sent by non-HTTP
+ applications, as is sometimes the case when retrieving or posting
+ messages via proxies/gateways to SMTP or NNTP.
+
+
+
+Fielding, et al. Standards Track [Page 20]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ All HTTP date/time stamps MUST be represented in Greenwich Mean Time
+ (GMT), without exception. For the purposes of HTTP, GMT is exactly
+ equal to UTC (Coordinated Universal Time). This is indicated in the
+ first two formats by the inclusion of "GMT" as the three-letter
+ abbreviation for time zone, and MUST be assumed when reading the
+ asctime format. HTTP-date is case sensitive and MUST NOT include
+ additional LWS beyond that specifically included as SP in the
+ grammar.
+
+ HTTP-date = rfc1123-date | rfc850-date | asctime-date
+ rfc1123-date = wkday "," SP date1 SP time SP "GMT"
+ rfc850-date = weekday "," SP date2 SP time SP "GMT"
+ asctime-date = wkday SP date3 SP time SP 4DIGIT
+ date1 = 2DIGIT SP month SP 4DIGIT
+ ; day month year (e.g., 02 Jun 1982)
+ date2 = 2DIGIT "-" month "-" 2DIGIT
+ ; day-month-year (e.g., 02-Jun-82)
+ date3 = month SP ( 2DIGIT | ( SP 1DIGIT ))
+ ; month day (e.g., Jun 2)
+ time = 2DIGIT ":" 2DIGIT ":" 2DIGIT
+ ; 00:00:00 - 23:59:59
+ wkday = "Mon" | "Tue" | "Wed"
+ | "Thu" | "Fri" | "Sat" | "Sun"
+ weekday = "Monday" | "Tuesday" | "Wednesday"
+ | "Thursday" | "Friday" | "Saturday" | "Sunday"
+ month = "Jan" | "Feb" | "Mar" | "Apr"
+ | "May" | "Jun" | "Jul" | "Aug"
+ | "Sep" | "Oct" | "Nov" | "Dec"
+
+ Note: HTTP requirements for the date/time stamp format apply only
+ to their usage within the protocol stream. Clients and servers are
+ not required to use these formats for user presentation, request
+ logging, etc.
+
+3.3.2 Delta Seconds
+
+ Some HTTP header fields allow a time value to be specified as an
+ integer number of seconds, represented in decimal, after the time
+ that the message was received.
+
+ delta-seconds = 1*DIGIT
+
+3.4 Character Sets
+
+ HTTP uses the same definition of the term "character set" as that
+ described for MIME:
+
+
+
+
+
+Fielding, et al. Standards Track [Page 21]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ The term "character set" is used in this document to refer to a
+ method used with one or more tables to convert a sequence of octets
+ into a sequence of characters. Note that unconditional conversion in
+ the other direction is not required, in that not all characters may
+ be available in a given character set and a character set may provide
+ more than one sequence of octets to represent a particular character.
+ This definition is intended to allow various kinds of character
+ encoding, from simple single-table mappings such as US-ASCII to
+ complex table switching methods such as those that use ISO-2022's
+ techniques. However, the definition associated with a MIME character
+ set name MUST fully specify the mapping to be performed from octets
+ to characters. In particular, use of external profiling information
+ to determine the exact mapping is not permitted.
+
+ Note: This use of the term "character set" is more commonly
+ referred to as a "character encoding." However, since HTTP and
+ MIME share the same registry, it is important that the terminology
+ also be shared.
+
+ HTTP character sets are identified by case-insensitive tokens. The
+ complete set of tokens is defined by the IANA Character Set registry
+ [19].
+
+ charset = token
+
+ Although HTTP allows an arbitrary token to be used as a charset
+ value, any token that has a predefined value within the IANA
+ Character Set registry [19] MUST represent the character set defined
+ by that registry. Applications SHOULD limit their use of character
+ sets to those defined by the IANA registry.
+
+ Implementors should be aware of IETF character set requirements [38]
+ [41].
+
+3.4.1 Missing Charset
+
+ Some HTTP/1.0 software has interpreted a Content-Type header without
+ charset parameter incorrectly to mean "recipient should guess."
+ Senders wishing to defeat this behavior MAY include a charset
+ parameter even when the charset is ISO-8859-1 and SHOULD do so when
+ it is known that it will not confuse the recipient.
+
+ Unfortunately, some older HTTP/1.0 clients did not deal properly with
+ an explicit charset parameter. HTTP/1.1 recipients MUST respect the
+ charset label provided by the sender; and those user agents that have
+ a provision to "guess" a charset MUST use the charset from the
+
+
+
+
+
+Fielding, et al. Standards Track [Page 22]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ content-type field if they support that charset, rather than the
+ recipient's preference, when initially displaying a document. See
+ section 3.7.1.
+
+3.5 Content Codings
+
+ Content coding values indicate an encoding transformation that has
+ been or can be applied to an entity. Content codings are primarily
+ used to allow a document to be compressed or otherwise usefully
+ transformed without losing the identity of its underlying media type
+ and without loss of information. Frequently, the entity is stored in
+ coded form, transmitted directly, and only decoded by the recipient.
+
+ content-coding = token
+
+ All content-coding values are case-insensitive. HTTP/1.1 uses
+ content-coding values in the Accept-Encoding (section 14.3) and
+ Content-Encoding (section 14.11) header fields. Although the value
+ describes the content-coding, what is more important is that it
+ indicates what decoding mechanism will be required to remove the
+ encoding.
+
+ The Internet Assigned Numbers Authority (IANA) acts as a registry for
+ content-coding value tokens. Initially, the registry contains the
+ following tokens:
+
+ gzip An encoding format produced by the file compression program
+ "gzip" (GNU zip) as described in RFC 1952 [25]. This format is a
+ Lempel-Ziv coding (LZ77) with a 32 bit CRC.
+
+ compress
+ The encoding format produced by the common UNIX file compression
+ program "compress". This format is an adaptive Lempel-Ziv-Welch
+ coding (LZW).
+
+ Use of program names for the identification of encoding formats
+ is not desirable and is discouraged for future encodings. Their
+ use here is representative of historical practice, not good
+ design. For compatibility with previous implementations of HTTP,
+ applications SHOULD consider "x-gzip" and "x-compress" to be
+ equivalent to "gzip" and "compress" respectively.
+
+ deflate
+ The "zlib" format defined in RFC 1950 [31] in combination with
+ the "deflate" compression mechanism described in RFC 1951 [29].
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 23]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ identity
+ The default (identity) encoding; the use of no transformation
+ whatsoever. This content-coding is used only in the Accept-
+ Encoding header, and SHOULD NOT be used in the Content-Encoding
+ header.
+
+ New content-coding value tokens SHOULD be registered; to allow
+ interoperability between clients and servers, specifications of the
+ content coding algorithms needed to implement a new value SHOULD be
+ publicly available and adequate for independent implementation, and
+ conform to the purpose of content coding defined in this section.
+
+3.6 Transfer Codings
+
+ Transfer-coding values are used to indicate an encoding
+ transformation that has been, can be, or may need to be applied to an
+ entity-body in order to ensure "safe transport" through the network.
+ This differs from a content coding in that the transfer-coding is a
+ property of the message, not of the original entity.
+
+ transfer-coding = "chunked" | transfer-extension
+ transfer-extension = token *( ";" parameter )
+
+ Parameters are in the form of attribute/value pairs.
+
+ parameter = attribute "=" value
+ attribute = token
+ value = token | quoted-string
+
+ All transfer-coding values are case-insensitive. HTTP/1.1 uses
+ transfer-coding values in the TE header field (section 14.39) and in
+ the Transfer-Encoding header field (section 14.41).
+
+ Whenever a transfer-coding is applied to a message-body, the set of
+ transfer-codings MUST include "chunked", unless the message is
+ terminated by closing the connection. When the "chunked" transfer-
+ coding is used, it MUST be the last transfer-coding applied to the
+ message-body. The "chunked" transfer-coding MUST NOT be applied more
+ than once to a message-body. These rules allow the recipient to
+ determine the transfer-length of the message (section 4.4).
+
+ Transfer-codings are analogous to the Content-Transfer-Encoding
+ values of MIME [7], which were designed to enable safe transport of
+ binary data over a 7-bit transport service. However, safe transport
+ has a different focus for an 8bit-clean transfer protocol. In HTTP,
+ the only unsafe characteristic of message-bodies is the difficulty in
+ determining the exact body length (section 7.2.2), or the desire to
+ encrypt data over a shared transport.
+
+
+
+Fielding, et al. Standards Track [Page 24]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ The Internet Assigned Numbers Authority (IANA) acts as a registry for
+ transfer-coding value tokens. Initially, the registry contains the
+ following tokens: "chunked" (section 3.6.1), "identity" (section
+ 3.6.2), "gzip" (section 3.5), "compress" (section 3.5), and "deflate"
+ (section 3.5).
+
+ New transfer-coding value tokens SHOULD be registered in the same way
+ as new content-coding value tokens (section 3.5).
+
+ A server which receives an entity-body with a transfer-coding it does
+ not understand SHOULD return 501 (Unimplemented), and close the
+ connection. A server MUST NOT send transfer-codings to an HTTP/1.0
+ client.
+
+3.6.1 Chunked Transfer Coding
+
+ The chunked encoding modifies the body of a message in order to
+ transfer it as a series of chunks, each with its own size indicator,
+ followed by an OPTIONAL trailer containing entity-header fields. This
+ allows dynamically produced content to be transferred along with the
+ information necessary for the recipient to verify that it has
+ received the full message.
+
+ Chunked-Body = *chunk
+ last-chunk
+ trailer
+ CRLF
+
+ chunk = chunk-size [ chunk-extension ] CRLF
+ chunk-data CRLF
+ chunk-size = 1*HEX
+ last-chunk = 1*("0") [ chunk-extension ] CRLF
+
+ chunk-extension= *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
+ chunk-ext-name = token
+ chunk-ext-val = token | quoted-string
+ chunk-data = chunk-size(OCTET)
+ trailer = *(entity-header CRLF)
+
+ The chunk-size field is a string of hex digits indicating the size of
+ the chunk. The chunked encoding is ended by any chunk whose size is
+ zero, followed by the trailer, which is terminated by an empty line.
+
+ The trailer allows the sender to include additional HTTP header
+ fields at the end of the message. The Trailer header field can be
+ used to indicate which header fields are included in a trailer (see
+ section 14.40).
+
+
+
+
+Fielding, et al. Standards Track [Page 25]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ A server using chunked transfer-coding in a response MUST NOT use the
+ trailer for any header fields unless at least one of the following is
+ true:
+
+ a)the request included a TE header field that indicates "trailers" is
+ acceptable in the transfer-coding of the response, as described in
+ section 14.39; or,
+
+ b)the server is the origin server for the response, the trailer
+ fields consist entirely of optional metadata, and the recipient
+ could use the message (in a manner acceptable to the origin server)
+ without receiving this metadata. In other words, the origin server
+ is willing to accept the possibility that the trailer fields might
+ be silently discarded along the path to the client.
+
+ This requirement prevents an interoperability failure when the
+ message is being received by an HTTP/1.1 (or later) proxy and
+ forwarded to an HTTP/1.0 recipient. It avoids a situation where
+ compliance with the protocol would have necessitated a possibly
+ infinite buffer on the proxy.
+
+ An example process for decoding a Chunked-Body is presented in
+ appendix 19.4.6.
+
+ All HTTP/1.1 applications MUST be able to receive and decode the
+ "chunked" transfer-coding, and MUST ignore chunk-extension extensions
+ they do not understand.
+
+3.7 Media Types
+
+ HTTP uses Internet Media Types [17] in the Content-Type (section
+ 14.17) and Accept (section 14.1) header fields in order to provide
+ open and extensible data typing and type negotiation.
+
+ media-type = type "/" subtype *( ";" parameter )
+ type = token
+ subtype = token
+
+ Parameters MAY follow the type/subtype in the form of attribute/value
+ pairs (as defined in section 3.6).
+
+ The type, subtype, and parameter attribute names are case-
+ insensitive. Parameter values might or might not be case-sensitive,
+ depending on the semantics of the parameter name. Linear white space
+ (LWS) MUST NOT be used between the type and subtype, nor between an
+ attribute and its value. The presence or absence of a parameter might
+ be significant to the processing of a media-type, depending on its
+ definition within the media type registry.
+
+
+
+Fielding, et al. Standards Track [Page 26]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ Note that some older HTTP applications do not recognize media type
+ parameters. When sending data to older HTTP applications,
+ implementations SHOULD only use media type parameters when they are
+ required by that type/subtype definition.
+
+ Media-type values are registered with the Internet Assigned Number
+ Authority (IANA [19]). The media type registration process is
+ outlined in RFC 1590 [17]. Use of non-registered media types is
+ discouraged.
+
+3.7.1 Canonicalization and Text Defaults
+
+ Internet media types are registered with a canonical form. An
+ entity-body transferred via HTTP messages MUST be represented in the
+ appropriate canonical form prior to its transmission except for
+ "text" types, as defined in the next paragraph.
+
+ When in canonical form, media subtypes of the "text" type use CRLF as
+ the text line break. HTTP relaxes this requirement and allows the
+ transport of text media with plain CR or LF alone representing a line
+ break when it is done consistently for an entire entity-body. HTTP
+ applications MUST accept CRLF, bare CR, and bare LF as being
+ representative of a line break in text media received via HTTP. In
+ addition, if the text is represented in a character set that does not
+ use octets 13 and 10 for CR and LF respectively, as is the case for
+ some multi-byte character sets, HTTP allows the use of whatever octet
+ sequences are defined by that character set to represent the
+ equivalent of CR and LF for line breaks. This flexibility regarding
+ line breaks applies only to text media in the entity-body; a bare CR
+ or LF MUST NOT be substituted for CRLF within any of the HTTP control
+ structures (such as header fields and multipart boundaries).
+
+ If an entity-body is encoded with a content-coding, the underlying
+ data MUST be in a form defined above prior to being encoded.
+
+ The "charset" parameter is used with some media types to define the
+ character set (section 3.4) of the data. When no explicit charset
+ parameter is provided by the sender, media subtypes of the "text"
+ type are defined to have a default charset value of "ISO-8859-1" when
+ received via HTTP. Data in character sets other than "ISO-8859-1" or
+ its subsets MUST be labeled with an appropriate charset value. See
+ section 3.4.1 for compatibility problems.
+
+3.7.2 Multipart Types
+
+ MIME provides for a number of "multipart" types -- encapsulations of
+ one or more entities within a single message-body. All multipart
+ types share a common syntax, as defined in section 5.1.1 of RFC 2046
+
+
+
+Fielding, et al. Standards Track [Page 27]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ [40], and MUST include a boundary parameter as part of the media type
+ value. The message body is itself a protocol element and MUST
+ therefore use only CRLF to represent line breaks between body-parts.
+ Unlike in RFC 2046, the epilogue of any multipart message MUST be
+ empty; HTTP applications MUST NOT transmit the epilogue (even if the
+ original multipart contains an epilogue). These restrictions exist in
+ order to preserve the self-delimiting nature of a multipart message-
+ body, wherein the "end" of the message-body is indicated by the
+ ending multipart boundary.
+
+ In general, HTTP treats a multipart message-body no differently than
+ any other media type: strictly as payload. The one exception is the
+ "multipart/byteranges" type (appendix 19.2) when it appears in a 206
+ (Partial Content) response, which will be interpreted by some HTTP
+ caching mechanisms as described in sections 13.5.4 and 14.16. In all
+ other cases, an HTTP user agent SHOULD follow the same or similar
+ behavior as a MIME user agent would upon receipt of a multipart type.
+ The MIME header fields within each body-part of a multipart message-
+ body do not have any significance to HTTP beyond that defined by
+ their MIME semantics.
+
+ In general, an HTTP user agent SHOULD follow the same or similar
+ behavior as a MIME user agent would upon receipt of a multipart type.
+ If an application receives an unrecognized multipart subtype, the
+ application MUST treat it as being equivalent to "multipart/mixed".
+
+ Note: The "multipart/form-data" type has been specifically defined
+ for carrying form data suitable for processing via the POST
+ request method, as described in RFC 1867 [15].
+
+3.8 Product Tokens
+
+ Product tokens are used to allow communicating applications to
+ identify themselves by software name and version. Most fields using
+ product tokens also allow sub-products which form a significant part
+ of the application to be listed, separated by white space. By
+ convention, the products are listed in order of their significance
+ for identifying the application.
+
+ product = token ["/" product-version]
+ product-version = token
+
+ Examples:
+
+ User-Agent: CERN-LineMode/2.15 libwww/2.17b3
+ Server: Apache/0.8.4
+
+
+
+
+
+Fielding, et al. Standards Track [Page 28]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ Product tokens SHOULD be short and to the point. They MUST NOT be
+ used for advertising or other non-essential information. Although any
+ token character MAY appear in a product-version, this token SHOULD
+ only be used for a version identifier (i.e., successive versions of
+ the same product SHOULD only differ in the product-version portion of
+ the product value).
+
+3.9 Quality Values
+
+ HTTP content negotiation (section 12) uses short "floating point"
+ numbers to indicate the relative importance ("weight") of various
+ negotiable parameters. A weight is normalized to a real number in
+ the range 0 through 1, where 0 is the minimum and 1 the maximum
+ value. If a parameter has a quality value of 0, then content with
+ this parameter is `not acceptable' for the client. HTTP/1.1
+ applications MUST NOT generate more than three digits after the
+ decimal point. User configuration of these values SHOULD also be
+ limited in this fashion.
+
+ qvalue = ( "0" [ "." 0*3DIGIT ] )
+ | ( "1" [ "." 0*3("0") ] )
+
+ "Quality values" is a misnomer, since these values merely represent
+ relative degradation in desired quality.
+
+3.10 Language Tags
+
+ A language tag identifies a natural language spoken, written, or
+ otherwise conveyed by human beings for communication of information
+ to other human beings. Computer languages are explicitly excluded.
+ HTTP uses language tags within the Accept-Language and Content-
+ Language fields.
+
+ The syntax and registry of HTTP language tags is the same as that
+ defined by RFC 1766 [1]. In summary, a language tag is composed of 1
+ or more parts: A primary language tag and a possibly empty series of
+ subtags:
+
+ language-tag = primary-tag *( "-" subtag )
+ primary-tag = 1*8ALPHA
+ subtag = 1*8ALPHA
+
+ White space is not allowed within the tag and all tags are case-
+ insensitive. The name space of language tags is administered by the
+ IANA. Example tags include:
+
+ en, en-US, en-cockney, i-cherokee, x-pig-latin
+
+
+
+
+Fielding, et al. Standards Track [Page 29]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ where any two-letter primary-tag is an ISO-639 language abbreviation
+ and any two-letter initial subtag is an ISO-3166 country code. (The
+ last three tags above are not registered tags; all but the last are
+ examples of tags which could be registered in future.)
+
+3.11 Entity Tags
+
+ Entity tags are used for comparing two or more entities from the same
+ requested resource. HTTP/1.1 uses entity tags in the ETag (section
+ 14.19), If-Match (section 14.24), If-None-Match (section 14.26), and
+ If-Range (section 14.27) header fields. The definition of how they
+ are used and compared as cache validators is in section 13.3.3. An
+ entity tag consists of an opaque quoted string, possibly prefixed by
+ a weakness indicator.
+
+ entity-tag = [ weak ] opaque-tag
+ weak = "W/"
+ opaque-tag = quoted-string
+
+ A "strong entity tag" MAY be shared by two entities of a resource
+ only if they are equivalent by octet equality.
+
+ A "weak entity tag," indicated by the "W/" prefix, MAY be shared by
+ two entities of a resource only if the entities are equivalent and
+ could be substituted for each other with no significant change in
+ semantics. A weak entity tag can only be used for weak comparison.
+
+ An entity tag MUST be unique across all versions of all entities
+ associated with a particular resource. A given entity tag value MAY
+ be used for entities obtained by requests on different URIs. The use
+ of the same entity tag value in conjunction with entities obtained by
+ requests on different URIs does not imply the equivalence of those
+ entities.
+
+3.12 Range Units
+
+ HTTP/1.1 allows a client to request that only part (a range of) the
+ response entity be included within the response. HTTP/1.1 uses range
+ units in the Range (section 14.35) and Content-Range (section 14.16)
+ header fields. An entity can be broken down into subranges according
+ to various structural units.
+
+ range-unit = bytes-unit | other-range-unit
+ bytes-unit = "bytes"
+ other-range-unit = token
+
+ The only range unit defined by HTTP/1.1 is "bytes". HTTP/1.1
+ implementations MAY ignore ranges specified using other units.
+
+
+
+Fielding, et al. Standards Track [Page 30]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ HTTP/1.1 has been designed to allow implementations of applications
+ that do not depend on knowledge of ranges.
+
+4 HTTP Message
+
+4.1 Message Types
+
+ HTTP messages consist of requests from client to server and responses
+ from server to client.
+
+ HTTP-message = Request | Response ; HTTP/1.1 messages
+
+ Request (section 5) and Response (section 6) messages use the generic
+ message format of RFC 822 [9] for transferring entities (the payload
+ of the message). Both types of message consist of a start-line, zero
+ or more header fields (also known as "headers"), an empty line (i.e.,
+ a line with nothing preceding the CRLF) indicating the end of the
+ header fields, and possibly a message-body.
+
+ generic-message = start-line
+ *(message-header CRLF)
+ CRLF
+ [ message-body ]
+ start-line = Request-Line | Status-Line
+
+ In the interest of robustness, servers SHOULD ignore any empty
+ line(s) received where a Request-Line is expected. In other words, if
+ the server is reading the protocol stream at the beginning of a
+ message and receives a CRLF first, it should ignore the CRLF.
+
+ Certain buggy HTTP/1.0 client implementations generate extra CRLF's
+ after a POST request. To restate what is explicitly forbidden by the
+ BNF, an HTTP/1.1 client MUST NOT preface or follow a request with an
+ extra CRLF.
+
+4.2 Message Headers
+
+ HTTP header fields, which include general-header (section 4.5),
+ request-header (section 5.3), response-header (section 6.2), and
+ entity-header (section 7.1) fields, follow the same generic format as
+ that given in Section 3.1 of RFC 822 [9]. Each header field consists
+ of a name followed by a colon (":") and the field value. Field names
+ are case-insensitive. The field value MAY be preceded by any amount
+ of LWS, though a single SP is preferred. Header fields can be
+ extended over multiple lines by preceding each extra line with at
+ least one SP or HT. Applications ought to follow "common form", where
+ one is known or indicated, when generating HTTP constructs, since
+ there might exist some implementations that fail to accept anything
+
+
+
+Fielding, et al. Standards Track [Page 31]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ beyond the common forms.
+
+ message-header = field-name ":" [ field-value ]
+ field-name = token
+ field-value = *( field-content | LWS )
+ field-content = <the OCTETs making up the field-value
+ and consisting of either *TEXT or combinations
+ of token, separators, and quoted-string>
+
+ The field-content does not include any leading or trailing LWS:
+ linear white space occurring before the first non-whitespace
+ character of the field-value or after the last non-whitespace
+ character of the field-value. Such leading or trailing LWS MAY be
+ removed without changing the semantics of the field value. Any LWS
+ that occurs between field-content MAY be replaced with a single SP
+ before interpreting the field value or forwarding the message
+ downstream.
+
+ The order in which header fields with differing field names are
+ received is not significant. However, it is "good practice" to send
+ general-header fields first, followed by request-header or response-
+ header fields, and ending with the entity-header fields.
+
+ Multiple message-header fields with the same field-name MAY be
+ present in a message if and only if the entire field-value for that
+ header field is defined as a comma-separated list [i.e., #(values)].
+ It MUST be possible to combine the multiple header fields into one
+ "field-name: field-value" pair, without changing the semantics of the
+ message, by appending each subsequent field-value to the first, each
+ separated by a comma. The order in which header fields with the same
+ field-name are received is therefore significant to the
+ interpretation of the combined field value, and thus a proxy MUST NOT
+ change the order of these field values when a message is forwarded.
+
+4.3 Message Body
+
+ The message-body (if any) of an HTTP message is used to carry the
+ entity-body associated with the request or response. The message-body
+ differs from the entity-body only when a transfer-coding has been
+ applied, as indicated by the Transfer-Encoding header field (section
+ 14.41).
+
+ message-body = entity-body
+ | <entity-body encoded as per Transfer-Encoding>
+
+ Transfer-Encoding MUST be used to indicate any transfer-codings
+ applied by an application to ensure safe and proper transfer of the
+ message. Transfer-Encoding is a property of the message, not of the
+
+
+
+Fielding, et al. Standards Track [Page 32]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ entity, and thus MAY be added or removed by any application along the
+ request/response chain. (However, section 3.6 places restrictions on
+ when certain transfer-codings may be used.)
+
+ The rules for when a message-body is allowed in a message differ for
+ requests and responses.
+
+ The presence of a message-body in a request is signaled by the
+ inclusion of a Content-Length or Transfer-Encoding header field in
+ the request's message-headers. A message-body MUST NOT be included in
+ a request if the specification of the request method (section 5.1.1)
+ does not allow sending an entity-body in requests. A server SHOULD
+ read and forward a message-body on any request; if the request method
+ does not include defined semantics for an entity-body, then the
+ message-body SHOULD be ignored when handling the request.
+
+ For response messages, whether or not a message-body is included with
+ a message is dependent on both the request method and the response
+ status code (section 6.1.1). All responses to the HEAD request method
+ MUST NOT include a message-body, even though the presence of entity-
+ header fields might lead one to believe they do. All 1xx
+ (informational), 204 (no content), and 304 (not modified) responses
+ MUST NOT include a message-body. All other responses do include a
+ message-body, although it MAY be of zero length.
+
+4.4 Message Length
+
+ The transfer-length of a message is the length of the message-body as
+ it appears in the message; that is, after any transfer-codings have
+ been applied. When a message-body is included with a message, the
+ transfer-length of that body is determined by one of the following
+ (in order of precedence):
+
+ 1.Any response message which "MUST NOT" include a message-body (such
+ as the 1xx, 204, and 304 responses and any response to a HEAD
+ request) is always terminated by the first empty line after the
+ header fields, regardless of the entity-header fields present in
+ the message.
+
+ 2.If a Transfer-Encoding header field (section 14.41) is present and
+ has any value other than "identity", then the transfer-length is
+ defined by use of the "chunked" transfer-coding (section 3.6),
+ unless the message is terminated by closing the connection.
+
+ 3.If a Content-Length header field (section 14.13) is present, its
+ decimal value in OCTETs represents both the entity-length and the
+ transfer-length. The Content-Length header field MUST NOT be sent
+ if these two lengths are different (i.e., if a Transfer-Encoding
+
+
+
+Fielding, et al. Standards Track [Page 33]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ header field is present). If a message is received with both a
+ Transfer-Encoding header field and a Content-Length header field,
+ the latter MUST be ignored.
+
+ 4.If the message uses the media type "multipart/byteranges", and the
+ ransfer-length is not otherwise specified, then this self-
+ elimiting media type defines the transfer-length. This media type
+ UST NOT be used unless the sender knows that the recipient can arse
+ it; the presence in a request of a Range header with ultiple byte-
+ range specifiers from a 1.1 client implies that the lient can parse
+ multipart/byteranges responses.
+
+ A range header might be forwarded by a 1.0 proxy that does not
+ understand multipart/byteranges; in this case the server MUST
+ delimit the message using methods defined in items 1,3 or 5 of
+ this section.
+
+ 5.By the server closing the connection. (Closing the connection
+ cannot be used to indicate the end of a request body, since that
+ would leave no possibility for the server to send back a response.)
+
+ For compatibility with HTTP/1.0 applications, HTTP/1.1 requests
+ containing a message-body MUST include a valid Content-Length header
+ field unless the server is known to be HTTP/1.1 compliant. If a
+ request contains a message-body and a Content-Length is not given,
+ the server SHOULD respond with 400 (bad request) if it cannot
+ determine the length of the message, or with 411 (length required) if
+ it wishes to insist on receiving a valid Content-Length.
+
+ All HTTP/1.1 applications that receive entities MUST accept the
+ "chunked" transfer-coding (section 3.6), thus allowing this mechanism
+ to be used for messages when the message length cannot be determined
+ in advance.
+
+ Messages MUST NOT include both a Content-Length header field and a
+ non-identity transfer-coding. If the message does include a non-
+ identity transfer-coding, the Content-Length MUST be ignored.
+
+ When a Content-Length is given in a message where a message-body is
+ allowed, its field value MUST exactly match the number of OCTETs in
+ the message-body. HTTP/1.1 user agents MUST notify the user when an
+ invalid length is received and detected.
+
+4.5 General Header Fields
+
+ There are a few header fields which have general applicability for
+ both request and response messages, but which do not apply to the
+ entity being transferred. These header fields apply only to the
+
+
+
+Fielding, et al. Standards Track [Page 34]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ message being transmitted.
+
+ general-header = Cache-Control ; Section 14.9
+ | Connection ; Section 14.10
+ | Date ; Section 14.18
+ | Pragma ; Section 14.32
+ | Trailer ; Section 14.40
+ | Transfer-Encoding ; Section 14.41
+ | Upgrade ; Section 14.42
+ | Via ; Section 14.45
+ | Warning ; Section 14.46
+
+ General-header field names can be extended reliably only in
+ combination with a change in the protocol version. However, new or
+ experimental header fields may be given the semantics of general
+ header fields if all parties in the communication recognize them to
+ be general-header fields. Unrecognized header fields are treated as
+ entity-header fields.
+
+5 Request
+
+ A request message from a client to a server includes, within the
+ first line of that message, the method to be applied to the resource,
+ the identifier of the resource, and the protocol version in use.
+
+ Request = Request-Line ; Section 5.1
+ *(( general-header ; Section 4.5
+ | request-header ; Section 5.3
+ | entity-header ) CRLF) ; Section 7.1
+ CRLF
+ [ message-body ] ; Section 4.3
+
+5.1 Request-Line
+
+ The Request-Line begins with a method token, followed by the
+ Request-URI and the protocol version, and ending with CRLF. The
+ elements are separated by SP characters. No CR or LF is allowed
+ except in the final CRLF sequence.
+
+ Request-Line = Method SP Request-URI SP HTTP-Version CRLF
+
+
+
+
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 35]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+5.1.1 Method
+
+ The Method token indicates the method to be performed on the
+ resource identified by the Request-URI. The method is case-sensitive.
+
+ Method = "OPTIONS" ; Section 9.2
+ | "GET" ; Section 9.3
+ | "HEAD" ; Section 9.4
+ | "POST" ; Section 9.5
+ | "PUT" ; Section 9.6
+ | "DELETE" ; Section 9.7
+ | "TRACE" ; Section 9.8
+ | "CONNECT" ; Section 9.9
+ | extension-method
+ extension-method = token
+
+ The list of methods allowed by a resource can be specified in an
+ Allow header field (section 14.7). The return code of the response
+ always notifies the client whether a method is currently allowed on a
+ resource, since the set of allowed methods can change dynamically. An
+ origin server SHOULD return the status code 405 (Method Not Allowed)
+ if the method is known by the origin server but not allowed for the
+ requested resource, and 501 (Not Implemented) if the method is
+ unrecognized or not implemented by the origin server. The methods GET
+ and HEAD MUST be supported by all general-purpose servers. All other
+ methods are OPTIONAL; however, if the above methods are implemented,
+ they MUST be implemented with the same semantics as those specified
+ in section 9.
+
+5.1.2 Request-URI
+
+ The Request-URI is a Uniform Resource Identifier (section 3.2) and
+ identifies the resource upon which to apply the request.
+
+ Request-URI = "*" | absoluteURI | abs_path | authority
+
+ The four options for Request-URI are dependent on the nature of the
+ request. The asterisk "*" means that the request does not apply to a
+ particular resource, but to the server itself, and is only allowed
+ when the method used does not necessarily apply to a resource. One
+ example would be
+
+ OPTIONS * HTTP/1.1
+
+ The absoluteURI form is REQUIRED when the request is being made to a
+ proxy. The proxy is requested to forward the request or service it
+ from a valid cache, and return the response. Note that the proxy MAY
+ forward the request on to another proxy or directly to the server
+
+
+
+Fielding, et al. Standards Track [Page 36]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ specified by the absoluteURI. In order to avoid request loops, a
+ proxy MUST be able to recognize all of its server names, including
+ any aliases, local variations, and the numeric IP address. An example
+ Request-Line would be:
+
+ GET http://www.w3.org/pub/WWW/TheProject.html HTTP/1.1
+
+ To allow for transition to absoluteURIs in all requests in future
+ versions of HTTP, all HTTP/1.1 servers MUST accept the absoluteURI
+ form in requests, even though HTTP/1.1 clients will only generate
+ them in requests to proxies.
+
+ The authority form is only used by the CONNECT method (section 9.9).
+
+ The most common form of Request-URI is that used to identify a
+ resource on an origin server or gateway. In this case the absolute
+ path of the URI MUST be transmitted (see section 3.2.1, abs_path) as
+ the Request-URI, and the network location of the URI (authority) MUST
+ be transmitted in a Host header field. For example, a client wishing
+ to retrieve the resource above directly from the origin server would
+ create a TCP connection to port 80 of the host "www.w3.org" and send
+ the lines:
+
+ GET /pub/WWW/TheProject.html HTTP/1.1
+ Host: www.w3.org
+
+ followed by the remainder of the Request. Note that the absolute path
+ cannot be empty; if none is present in the original URI, it MUST be
+ given as "/" (the server root).
+
+ The Request-URI is transmitted in the format specified in section
+ 3.2.1. If the Request-URI is encoded using the "% HEX HEX" encoding
+ [42], the origin server MUST decode the Request-URI in order to
+ properly interpret the request. Servers SHOULD respond to invalid
+ Request-URIs with an appropriate status code.
+
+ A transparent proxy MUST NOT rewrite the "abs_path" part of the
+ received Request-URI when forwarding it to the next inbound server,
+ except as noted above to replace a null abs_path with "/".
+
+ Note: The "no rewrite" rule prevents the proxy from changing the
+ meaning of the request when the origin server is improperly using
+ a non-reserved URI character for a reserved purpose. Implementors
+ should be aware that some pre-HTTP/1.1 proxies have been known to
+ rewrite the Request-URI.
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 37]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+5.2 The Resource Identified by a Request
+
+ The exact resource identified by an Internet request is determined by
+ examining both the Request-URI and the Host header field.
+
+ An origin server that does not allow resources to differ by the
+ requested host MAY ignore the Host header field value when
+ determining the resource identified by an HTTP/1.1 request. (But see
+ section 19.6.1.1 for other requirements on Host support in HTTP/1.1.)
+
+ An origin server that does differentiate resources based on the host
+ requested (sometimes referred to as virtual hosts or vanity host
+ names) MUST use the following rules for determining the requested
+ resource on an HTTP/1.1 request:
+
+ 1. If Request-URI is an absoluteURI, the host is part of the
+ Request-URI. Any Host header field value in the request MUST be
+ ignored.
+
+ 2. If the Request-URI is not an absoluteURI, and the request includes
+ a Host header field, the host is determined by the Host header
+ field value.
+
+ 3. If the host as determined by rule 1 or 2 is not a valid host on
+ the server, the response MUST be a 400 (Bad Request) error message.
+
+ Recipients of an HTTP/1.0 request that lacks a Host header field MAY
+ attempt to use heuristics (e.g., examination of the URI path for
+ something unique to a particular host) in order to determine what
+ exact resource is being requested.
+
+5.3 Request Header Fields
+
+ The request-header fields allow the client to pass additional
+ information about the request, and about the client itself, to the
+ server. These fields act as request modifiers, with semantics
+ equivalent to the parameters on a programming language method
+ invocation.
+
+ request-header = Accept ; Section 14.1
+ | Accept-Charset ; Section 14.2
+ | Accept-Encoding ; Section 14.3
+ | Accept-Language ; Section 14.4
+ | Authorization ; Section 14.8
+ | Expect ; Section 14.20
+ | From ; Section 14.22
+ | Host ; Section 14.23
+ | If-Match ; Section 14.24
+
+
+
+Fielding, et al. Standards Track [Page 38]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ | If-Modified-Since ; Section 14.25
+ | If-None-Match ; Section 14.26
+ | If-Range ; Section 14.27
+ | If-Unmodified-Since ; Section 14.28
+ | Max-Forwards ; Section 14.31
+ | Proxy-Authorization ; Section 14.34
+ | Range ; Section 14.35
+ | Referer ; Section 14.36
+ | TE ; Section 14.39
+ | User-Agent ; Section 14.43
+
+ Request-header field names can be extended reliably only in
+ combination with a change in the protocol version. However, new or
+ experimental header fields MAY be given the semantics of request-
+ header fields if all parties in the communication recognize them to
+ be request-header fields. Unrecognized header fields are treated as
+ entity-header fields.
+
+6 Response
+
+ After receiving and interpreting a request message, a server responds
+ with an HTTP response message.
+
+ Response = Status-Line ; Section 6.1
+ *(( general-header ; Section 4.5
+ | response-header ; Section 6.2
+ | entity-header ) CRLF) ; Section 7.1
+ CRLF
+ [ message-body ] ; Section 7.2
+
+6.1 Status-Line
+
+ The first line of a Response message is the Status-Line, consisting
+ of the protocol version followed by a numeric status code and its
+ associated textual phrase, with each element separated by SP
+ characters. No CR or LF is allowed except in the final CRLF sequence.
+
+ Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
+
+6.1.1 Status Code and Reason Phrase
+
+ The Status-Code element is a 3-digit integer result code of the
+ attempt to understand and satisfy the request. These codes are fully
+ defined in section 10. The Reason-Phrase is intended to give a short
+ textual description of the Status-Code. The Status-Code is intended
+ for use by automata and the Reason-Phrase is intended for the human
+ user. The client is not required to examine or display the Reason-
+ Phrase.
+
+
+
+Fielding, et al. Standards Track [Page 39]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ The first digit of the Status-Code defines the class of response. The
+ last two digits do not have any categorization role. There are 5
+ values for the first digit:
+
+ - 1xx: Informational - Request received, continuing process
+
+ - 2xx: Success - The action was successfully received,
+ understood, and accepted
+
+ - 3xx: Redirection - Further action must be taken in order to
+ complete the request
+
+ - 4xx: Client Error - The request contains bad syntax or cannot
+ be fulfilled
+
+ - 5xx: Server Error - The server failed to fulfill an apparently
+ valid request
+
+ The individual values of the numeric status codes defined for
+ HTTP/1.1, and an example set of corresponding Reason-Phrase's, are
+ presented below. The reason phrases listed here are only
+ recommendations -- they MAY be replaced by local equivalents without
+ affecting the protocol.
+
+ Status-Code =
+ "100" ; Section 10.1.1: Continue
+ | "101" ; Section 10.1.2: Switching Protocols
+ | "200" ; Section 10.2.1: OK
+ | "201" ; Section 10.2.2: Created
+ | "202" ; Section 10.2.3: Accepted
+ | "203" ; Section 10.2.4: Non-Authoritative Information
+ | "204" ; Section 10.2.5: No Content
+ | "205" ; Section 10.2.6: Reset Content
+ | "206" ; Section 10.2.7: Partial Content
+ | "300" ; Section 10.3.1: Multiple Choices
+ | "301" ; Section 10.3.2: Moved Permanently
+ | "302" ; Section 10.3.3: Found
+ | "303" ; Section 10.3.4: See Other
+ | "304" ; Section 10.3.5: Not Modified
+ | "305" ; Section 10.3.6: Use Proxy
+ | "307" ; Section 10.3.8: Temporary Redirect
+ | "400" ; Section 10.4.1: Bad Request
+ | "401" ; Section 10.4.2: Unauthorized
+ | "402" ; Section 10.4.3: Payment Required
+ | "403" ; Section 10.4.4: Forbidden
+ | "404" ; Section 10.4.5: Not Found
+ | "405" ; Section 10.4.6: Method Not Allowed
+ | "406" ; Section 10.4.7: Not Acceptable
+
+
+
+Fielding, et al. Standards Track [Page 40]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ | "407" ; Section 10.4.8: Proxy Authentication Required
+ | "408" ; Section 10.4.9: Request Time-out
+ | "409" ; Section 10.4.10: Conflict
+ | "410" ; Section 10.4.11: Gone
+ | "411" ; Section 10.4.12: Length Required
+ | "412" ; Section 10.4.13: Precondition Failed
+ | "413" ; Section 10.4.14: Request Entity Too Large
+ | "414" ; Section 10.4.15: Request-URI Too Large
+ | "415" ; Section 10.4.16: Unsupported Media Type
+ | "416" ; Section 10.4.17: Requested range not satisfiable
+ | "417" ; Section 10.4.18: Expectation Failed
+ | "500" ; Section 10.5.1: Internal Server Error
+ | "501" ; Section 10.5.2: Not Implemented
+ | "502" ; Section 10.5.3: Bad Gateway
+ | "503" ; Section 10.5.4: Service Unavailable
+ | "504" ; Section 10.5.5: Gateway Time-out
+ | "505" ; Section 10.5.6: HTTP Version not supported
+ | extension-code
+
+ extension-code = 3DIGIT
+ Reason-Phrase = *<TEXT, excluding CR, LF>
+
+ HTTP status codes are extensible. HTTP applications are not required
+ to understand the meaning of all registered status codes, though such
+ understanding is obviously desirable. However, applications MUST
+ understand the class of any status code, as indicated by the first
+ digit, and treat any unrecognized response as being equivalent to the
+ x00 status code of that class, with the exception that an
+ unrecognized response MUST NOT be cached. For example, if an
+ unrecognized status code of 431 is received by the client, it can
+ safely assume that there was something wrong with its request and
+ treat the response as if it had received a 400 status code. In such
+ cases, user agents SHOULD present to the user the entity returned
+ with the response, since that entity is likely to include human-
+ readable information which will explain the unusual status.
+
+6.2 Response Header Fields
+
+ The response-header fields allow the server to pass additional
+ information about the response which cannot be placed in the Status-
+ Line. These header fields give information about the server and about
+ further access to the resource identified by the Request-URI.
+
+ response-header = Accept-Ranges ; Section 14.5
+ | Age ; Section 14.6
+ | ETag ; Section 14.19
+ | Location ; Section 14.30
+ | Proxy-Authenticate ; Section 14.33
+
+
+
+Fielding, et al. Standards Track [Page 41]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ | Retry-After ; Section 14.37
+ | Server ; Section 14.38
+ | Vary ; Section 14.44
+ | WWW-Authenticate ; Section 14.47
+
+ Response-header field names can be extended reliably only in
+ combination with a change in the protocol version. However, new or
+ experimental header fields MAY be given the semantics of response-
+ header fields if all parties in the communication recognize them to
+ be response-header fields. Unrecognized header fields are treated as
+ entity-header fields.
+
+7 Entity
+
+ Request and Response messages MAY transfer an entity if not otherwise
+ restricted by the request method or response status code. An entity
+ consists of entity-header fields and an entity-body, although some
+ responses will only include the entity-headers.
+
+ In this section, both sender and recipient refer to either the client
+ or the server, depending on who sends and who receives the entity.
+
+7.1 Entity Header Fields
+
+ Entity-header fields define metainformation about the entity-body or,
+ if no body is present, about the resource identified by the request.
+ Some of this metainformation is OPTIONAL; some might be REQUIRED by
+ portions of this specification.
+
+ entity-header = Allow ; Section 14.7
+ | Content-Encoding ; Section 14.11
+ | Content-Language ; Section 14.12
+ | Content-Length ; Section 14.13
+ | Content-Location ; Section 14.14
+ | Content-MD5 ; Section 14.15
+ | Content-Range ; Section 14.16
+ | Content-Type ; Section 14.17
+ | Expires ; Section 14.21
+ | Last-Modified ; Section 14.29
+ | extension-header
+
+ extension-header = message-header
+
+ The extension-header mechanism allows additional entity-header fields
+ to be defined without changing the protocol, but these fields cannot
+ be assumed to be recognizable by the recipient. Unrecognized header
+ fields SHOULD be ignored by the recipient and MUST be forwarded by
+ transparent proxies.
+
+
+
+Fielding, et al. Standards Track [Page 42]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+7.2 Entity Body
+
+ The entity-body (if any) sent with an HTTP request or response is in
+ a format and encoding defined by the entity-header fields.
+
+ entity-body = *OCTET
+
+ An entity-body is only present in a message when a message-body is
+ present, as described in section 4.3. The entity-body is obtained
+ from the message-body by decoding any Transfer-Encoding that might
+ have been applied to ensure safe and proper transfer of the message.
+
+7.2.1 Type
+
+ When an entity-body is included with a message, the data type of that
+ body is determined via the header fields Content-Type and Content-
+ Encoding. These define a two-layer, ordered encoding model:
+
+ entity-body := Content-Encoding( Content-Type( data ) )
+
+ Content-Type specifies the media type of the underlying data.
+ Content-Encoding may be used to indicate any additional content
+ codings applied to the data, usually for the purpose of data
+ compression, that are a property of the requested resource. There is
+ no default encoding.
+
+ Any HTTP/1.1 message containing an entity-body SHOULD include a
+ Content-Type header field defining the media type of that body. If
+ and only if the media type is not given by a Content-Type field, the
+ recipient MAY attempt to guess the media type via inspection of its
+ content and/or the name extension(s) of the URI used to identify the
+ resource. If the media type remains unknown, the recipient SHOULD
+ treat it as type "application/octet-stream".
+
+7.2.2 Entity Length
+
+ The entity-length of a message is the length of the message-body
+ before any transfer-codings have been applied. Section 4.4 defines
+ how the transfer-length of a message-body is determined.
+
+
+
+
+
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 43]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+8 Connections
+
+8.1 Persistent Connections
+
+8.1.1 Purpose
+
+ Prior to persistent connections, a separate TCP connection was
+ established to fetch each URL, increasing the load on HTTP servers
+ and causing congestion on the Internet. The use of inline images and
+ other associated data often require a client to make multiple
+ requests of the same server in a short amount of time. Analysis of
+ these performance problems and results from a prototype
+ implementation are available [26] [30]. Implementation experience and
+ measurements of actual HTTP/1.1 (RFC 2068) implementations show good
+ results [39]. Alternatives have also been explored, for example,
+ T/TCP [27].
+
+ Persistent HTTP connections have a number of advantages:
+
+ - By opening and closing fewer TCP connections, CPU time is saved
+ in routers and hosts (clients, servers, proxies, gateways,
+ tunnels, or caches), and memory used for TCP protocol control
+ blocks can be saved in hosts.
+
+ - HTTP requests and responses can be pipelined on a connection.
+ Pipelining allows a client to make multiple requests without
+ waiting for each response, allowing a single TCP connection to
+ be used much more efficiently, with much lower elapsed time.
+
+ - Network congestion is reduced by reducing the number of packets
+ caused by TCP opens, and by allowing TCP sufficient time to
+ determine the congestion state of the network.
+
+ - Latency on subsequent requests is reduced since there is no time
+ spent in TCP's connection opening handshake.
+
+ - HTTP can evolve more gracefully, since errors can be reported
+ without the penalty of closing the TCP connection. Clients using
+ future versions of HTTP might optimistically try a new feature,
+ but if communicating with an older server, retry with old
+ semantics after an error is reported.
+
+ HTTP implementations SHOULD implement persistent connections.
+
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 44]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+8.1.2 Overall Operation
+
+ A significant difference between HTTP/1.1 and earlier versions of
+ HTTP is that persistent connections are the default behavior of any
+ HTTP connection. That is, unless otherwise indicated, the client
+ SHOULD assume that the server will maintain a persistent connection,
+ even after error responses from the server.
+
+ Persistent connections provide a mechanism by which a client and a
+ server can signal the close of a TCP connection. This signaling takes
+ place using the Connection header field (section 14.10). Once a close
+ has been signaled, the client MUST NOT send any more requests on that
+ connection.
+
+8.1.2.1 Negotiation
+
+ An HTTP/1.1 server MAY assume that a HTTP/1.1 client intends to
+ maintain a persistent connection unless a Connection header including
+ the connection-token "close" was sent in the request. If the server
+ chooses to close the connection immediately after sending the
+ response, it SHOULD send a Connection header including the
+ connection-token close.
+
+ An HTTP/1.1 client MAY expect a connection to remain open, but would
+ decide to keep it open based on whether the response from a server
+ contains a Connection header with the connection-token close. In case
+ the client does not want to maintain a connection for more than that
+ request, it SHOULD send a Connection header including the
+ connection-token close.
+
+ If either the client or the server sends the close token in the
+ Connection header, that request becomes the last one for the
+ connection.
+
+ Clients and servers SHOULD NOT assume that a persistent connection is
+ maintained for HTTP versions less than 1.1 unless it is explicitly
+ signaled. See section 19.6.2 for more information on backward
+ compatibility with HTTP/1.0 clients.
+
+ In order to remain persistent, all messages on the connection MUST
+ have a self-defined message length (i.e., one not defined by closure
+ of the connection), as described in section 4.4.
+
+
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 45]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+8.1.2.2 Pipelining
+
+ A client that supports persistent connections MAY "pipeline" its
+ requests (i.e., send multiple requests without waiting for each
+ response). A server MUST send its responses to those requests in the
+ same order that the requests were received.
+
+ Clients which assume persistent connections and pipeline immediately
+ after connection establishment SHOULD be prepared to retry their
+ connection if the first pipelined attempt fails. If a client does
+ such a retry, it MUST NOT pipeline before it knows the connection is
+ persistent. Clients MUST also be prepared to resend their requests if
+ the server closes the connection before sending all of the
+ corresponding responses.
+
+ Clients SHOULD NOT pipeline requests using non-idempotent methods or
+ non-idempotent sequences of methods (see section 9.1.2). Otherwise, a
+ premature termination of the transport connection could lead to
+ indeterminate results. A client wishing to send a non-idempotent
+ request SHOULD wait to send that request until it has received the
+ response status for the previous request.
+
+8.1.3 Proxy Servers
+
+ It is especially important that proxies correctly implement the
+ properties of the Connection header field as specified in section
+ 14.10.
+
+ The proxy server MUST signal persistent connections separately with
+ its clients and the origin servers (or other proxy servers) that it
+ connects to. Each persistent connection applies to only one transport
+ link.
+
+ A proxy server MUST NOT establish a HTTP/1.1 persistent connection
+ with an HTTP/1.0 client (but see RFC 2068 [33] for information and
+ discussion of the problems with the Keep-Alive header implemented by
+ many HTTP/1.0 clients).
+
+8.1.4 Practical Considerations
+
+ Servers will usually have some time-out value beyond which they will
+ no longer maintain an inactive connection. Proxy servers might make
+ this a higher value since it is likely that the client will be making
+ more connections through the same server. The use of persistent
+ connections places no requirements on the length (or existence) of
+ this time-out for either the client or the server.
+
+
+
+
+
+Fielding, et al. Standards Track [Page 46]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ When a client or server wishes to time-out it SHOULD issue a graceful
+ close on the transport connection. Clients and servers SHOULD both
+ constantly watch for the other side of the transport close, and
+ respond to it as appropriate. If a client or server does not detect
+ the other side's close promptly it could cause unnecessary resource
+ drain on the network.
+
+ A client, server, or proxy MAY close the transport connection at any
+ time. For example, a client might have started to send a new request
+ at the same time that the server has decided to close the "idle"
+ connection. From the server's point of view, the connection is being
+ closed while it was idle, but from the client's point of view, a
+ request is in progress.
+
+ This means that clients, servers, and proxies MUST be able to recover
+ from asynchronous close events. Client software SHOULD reopen the
+ transport connection and retransmit the aborted sequence of requests
+ without user interaction so long as the request sequence is
+ idempotent (see section 9.1.2). Non-idempotent methods or sequences
+ MUST NOT be automatically retried, although user agents MAY offer a
+ human operator the choice of retrying the request(s). Confirmation by
+ user-agent software with semantic understanding of the application
+ MAY substitute for user confirmation. The automatic retry SHOULD NOT
+ be repeated if the second sequence of requests fails.
+
+ Servers SHOULD always respond to at least one request per connection,
+ if at all possible. Servers SHOULD NOT close a connection in the
+ middle of transmitting a response, unless a network or client failure
+ is suspected.
+
+ Clients that use persistent connections SHOULD limit the number of
+ simultaneous connections that they maintain to a given server. A
+ single-user client SHOULD NOT maintain more than 2 connections with
+ any server or proxy. A proxy SHOULD use up to 2*N connections to
+ another server or proxy, where N is the number of simultaneously
+ active users. These guidelines are intended to improve HTTP response
+ times and avoid congestion.
+
+8.2 Message Transmission Requirements
+
+8.2.1 Persistent Connections and Flow Control
+
+ HTTP/1.1 servers SHOULD maintain persistent connections and use TCP's
+ flow control mechanisms to resolve temporary overloads, rather than
+ terminating connections with the expectation that clients will retry.
+ The latter technique can exacerbate network congestion.
+
+
+
+
+
+Fielding, et al. Standards Track [Page 47]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+8.2.2 Monitoring Connections for Error Status Messages
+
+ An HTTP/1.1 (or later) client sending a message-body SHOULD monitor
+ the network connection for an error status while it is transmitting
+ the request. If the client sees an error status, it SHOULD
+ immediately cease transmitting the body. If the body is being sent
+ using a "chunked" encoding (section 3.6), a zero length chunk and
+ empty trailer MAY be used to prematurely mark the end of the message.
+ If the body was preceded by a Content-Length header, the client MUST
+ close the connection.
+
+8.2.3 Use of the 100 (Continue) Status
+
+ The purpose of the 100 (Continue) status (see section 10.1.1) is to
+ allow a client that is sending a request message with a request body
+ to determine if the origin server is willing to accept the request
+ (based on the request headers) before the client sends the request
+ body. In some cases, it might either be inappropriate or highly
+ inefficient for the client to send the body if the server will reject
+ the message without looking at the body.
+
+ Requirements for HTTP/1.1 clients:
+
+ - If a client will wait for a 100 (Continue) response before
+ sending the request body, it MUST send an Expect request-header
+ field (section 14.20) with the "100-continue" expectation.
+
+ - A client MUST NOT send an Expect request-header field (section
+ 14.20) with the "100-continue" expectation if it does not intend
+ to send a request body.
+
+ Because of the presence of older implementations, the protocol allows
+ ambiguous situations in which a client may send "Expect: 100-
+ continue" without receiving either a 417 (Expectation Failed) status
+ or a 100 (Continue) status. Therefore, when a client sends this
+ header field to an origin server (possibly via a proxy) from which it
+ has never seen a 100 (Continue) status, the client SHOULD NOT wait
+ for an indefinite period before sending the request body.
+
+ Requirements for HTTP/1.1 origin servers:
+
+ - Upon receiving a request which includes an Expect request-header
+ field with the "100-continue" expectation, an origin server MUST
+ either respond with 100 (Continue) status and continue to read
+ from the input stream, or respond with a final status code. The
+ origin server MUST NOT wait for the request body before sending
+ the 100 (Continue) response. If it responds with a final status
+ code, it MAY close the transport connection or it MAY continue
+
+
+
+Fielding, et al. Standards Track [Page 48]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ to read and discard the rest of the request. It MUST NOT
+ perform the requested method if it returns a final status code.
+
+ - An origin server SHOULD NOT send a 100 (Continue) response if
+ the request message does not include an Expect request-header
+ field with the "100-continue" expectation, and MUST NOT send a
+ 100 (Continue) response if such a request comes from an HTTP/1.0
+ (or earlier) client. There is an exception to this rule: for
+ compatibility with RFC 2068, a server MAY send a 100 (Continue)
+ status in response to an HTTP/1.1 PUT or POST request that does
+ not include an Expect request-header field with the "100-
+ continue" expectation. This exception, the purpose of which is
+ to minimize any client processing delays associated with an
+ undeclared wait for 100 (Continue) status, applies only to
+ HTTP/1.1 requests, and not to requests with any other HTTP-
+ version value.
+
+ - An origin server MAY omit a 100 (Continue) response if it has
+ already received some or all of the request body for the
+ corresponding request.
+
+ - An origin server that sends a 100 (Continue) response MUST
+ ultimately send a final status code, once the request body is
+ received and processed, unless it terminates the transport
+ connection prematurely.
+
+ - If an origin server receives a request that does not include an
+ Expect request-header field with the "100-continue" expectation,
+ the request includes a request body, and the server responds
+ with a final status code before reading the entire request body
+ from the transport connection, then the server SHOULD NOT close
+ the transport connection until it has read the entire request,
+ or until the client closes the connection. Otherwise, the client
+ might not reliably receive the response message. However, this
+ requirement is not be construed as preventing a server from
+ defending itself against denial-of-service attacks, or from
+ badly broken client implementations.
+
+ Requirements for HTTP/1.1 proxies:
+
+ - If a proxy receives a request that includes an Expect request-
+ header field with the "100-continue" expectation, and the proxy
+ either knows that the next-hop server complies with HTTP/1.1 or
+ higher, or does not know the HTTP version of the next-hop
+ server, it MUST forward the request, including the Expect header
+ field.
+
+
+
+
+
+Fielding, et al. Standards Track [Page 49]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ - If the proxy knows that the version of the next-hop server is
+ HTTP/1.0 or lower, it MUST NOT forward the request, and it MUST
+ respond with a 417 (Expectation Failed) status.
+
+ - Proxies SHOULD maintain a cache recording the HTTP version
+ numbers received from recently-referenced next-hop servers.
+
+ - A proxy MUST NOT forward a 100 (Continue) response if the
+ request message was received from an HTTP/1.0 (or earlier)
+ client and did not include an Expect request-header field with
+ the "100-continue" expectation. This requirement overrides the
+ general rule for forwarding of 1xx responses (see section 10.1).
+
+8.2.4 Client Behavior if Server Prematurely Closes Connection
+
+ If an HTTP/1.1 client sends a request which includes a request body,
+ but which does not include an Expect request-header field with the
+ "100-continue" expectation, and if the client is not directly
+ connected to an HTTP/1.1 origin server, and if the client sees the
+ connection close before receiving any status from the server, the
+ client SHOULD retry the request. If the client does retry this
+ request, it MAY use the following "binary exponential backoff"
+ algorithm to be assured of obtaining a reliable response:
+
+ 1. Initiate a new connection to the server
+
+ 2. Transmit the request-headers
+
+ 3. Initialize a variable R to the estimated round-trip time to the
+ server (e.g., based on the time it took to establish the
+ connection), or to a constant value of 5 seconds if the round-
+ trip time is not available.
+
+ 4. Compute T = R * (2**N), where N is the number of previous
+ retries of this request.
+
+ 5. Wait either for an error response from the server, or for T
+ seconds (whichever comes first)
+
+ 6. If no error response is received, after T seconds transmit the
+ body of the request.
+
+ 7. If client sees that the connection is closed prematurely,
+ repeat from step 1 until the request is accepted, an error
+ response is received, or the user becomes impatient and
+ terminates the retry process.
+
+
+
+
+
+Fielding, et al. Standards Track [Page 50]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ If at any point an error status is received, the client
+
+ - SHOULD NOT continue and
+
+ - SHOULD close the connection if it has not completed sending the
+ request message.
+
+9 Method Definitions
+
+ The set of common methods for HTTP/1.1 is defined below. Although
+ this set can be expanded, additional methods cannot be assumed to
+ share the same semantics for separately extended clients and servers.
+
+ The Host request-header field (section 14.23) MUST accompany all
+ HTTP/1.1 requests.
+
+9.1 Safe and Idempotent Methods
+
+9.1.1 Safe Methods
+
+ Implementors should be aware that the software represents the user in
+ their interactions over the Internet, and should be careful to allow
+ the user to be aware of any actions they might take which may have an
+ unexpected significance to themselves or others.
+
+ In particular, the convention has been established that the GET and
+ HEAD methods SHOULD NOT have the significance of taking an action
+ other than retrieval. These methods ought to be considered "safe".
+ This allows user agents to represent other methods, such as POST, PUT
+ and DELETE, in a special way, so that the user is made aware of the
+ fact that a possibly unsafe action is being requested.
+
+ Naturally, it is not possible to ensure that the server does not
+ generate side-effects as a result of performing a GET request; in
+ fact, some dynamic resources consider that a feature. The important
+ distinction here is that the user did not request the side-effects,
+ so therefore cannot be held accountable for them.
+
+9.1.2 Idempotent Methods
+
+ Methods can also have the property of "idempotence" in that (aside
+ from error or expiration issues) the side-effects of N > 0 identical
+ requests is the same as for a single request. The methods GET, HEAD,
+ PUT and DELETE share this property. Also, the methods OPTIONS and
+ TRACE SHOULD NOT have side effects, and so are inherently idempotent.
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 51]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ However, it is possible that a sequence of several requests is non-
+ idempotent, even if all of the methods executed in that sequence are
+ idempotent. (A sequence is idempotent if a single execution of the
+ entire sequence always yields a result that is not changed by a
+ reexecution of all, or part, of that sequence.) For example, a
+ sequence is non-idempotent if its result depends on a value that is
+ later modified in the same sequence.
+
+ A sequence that never has side effects is idempotent, by definition
+ (provided that no concurrent operations are being executed on the
+ same set of resources).
+
+9.2 OPTIONS
+
+ The OPTIONS method represents a request for information about the
+ communication options available on the request/response chain
+ identified by the Request-URI. This method allows the client to
+ determine the options and/or requirements associated with a resource,
+ or the capabilities of a server, without implying a resource action
+ or initiating a resource retrieval.
+
+ Responses to this method are not cacheable.
+
+ If the OPTIONS request includes an entity-body (as indicated by the
+ presence of Content-Length or Transfer-Encoding), then the media type
+ MUST be indicated by a Content-Type field. Although this
+ specification does not define any use for such a body, future
+ extensions to HTTP might use the OPTIONS body to make more detailed
+ queries on the server. A server that does not support such an
+ extension MAY discard the request body.
+
+ If the Request-URI is an asterisk ("*"), the OPTIONS request is
+ intended to apply to the server in general rather than to a specific
+ resource. Since a server's communication options typically depend on
+ the resource, the "*" request is only useful as a "ping" or "no-op"
+ type of method; it does nothing beyond allowing the client to test
+ the capabilities of the server. For example, this can be used to test
+ a proxy for HTTP/1.1 compliance (or lack thereof).
+
+ If the Request-URI is not an asterisk, the OPTIONS request applies
+ only to the options that are available when communicating with that
+ resource.
+
+ A 200 response SHOULD include any header fields that indicate
+ optional features implemented by the server and applicable to that
+ resource (e.g., Allow), possibly including extensions not defined by
+ this specification. The response body, if any, SHOULD also include
+ information about the communication options. The format for such a
+
+
+
+Fielding, et al. Standards Track [Page 52]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ body is not defined by this specification, but might be defined by
+ future extensions to HTTP. Content negotiation MAY be used to select
+ the appropriate response format. If no response body is included, the
+ response MUST include a Content-Length field with a field-value of
+ "0".
+
+ The Max-Forwards request-header field MAY be used to target a
+ specific proxy in the request chain. When a proxy receives an OPTIONS
+ request on an absoluteURI for which request forwarding is permitted,
+ the proxy MUST check for a Max-Forwards field. If the Max-Forwards
+ field-value is zero ("0"), the proxy MUST NOT forward the message;
+ instead, the proxy SHOULD respond with its own communication options.
+ If the Max-Forwards field-value is an integer greater than zero, the
+ proxy MUST decrement the field-value when it forwards the request. If
+ no Max-Forwards field is present in the request, then the forwarded
+ request MUST NOT include a Max-Forwards field.
+
+9.3 GET
+
+ The GET method means retrieve whatever information (in the form of an
+ entity) is identified by the Request-URI. If the Request-URI refers
+ to a data-producing process, it is the produced data which shall be
+ returned as the entity in the response and not the source text of the
+ process, unless that text happens to be the output of the process.
+
+ The semantics of the GET method change to a "conditional GET" if the
+ request message includes an If-Modified-Since, If-Unmodified-Since,
+ If-Match, If-None-Match, or If-Range header field. A conditional GET
+ method requests that the entity be transferred only under the
+ circumstances described by the conditional header field(s). The
+ conditional GET method is intended to reduce unnecessary network
+ usage by allowing cached entities to be refreshed without requiring
+ multiple requests or transferring data already held by the client.
+
+ The semantics of the GET method change to a "partial GET" if the
+ request message includes a Range header field. A partial GET requests
+ that only part of the entity be transferred, as described in section
+ 14.35. The partial GET method is intended to reduce unnecessary
+ network usage by allowing partially-retrieved entities to be
+ completed without transferring data already held by the client.
+
+ The response to a GET request is cacheable if and only if it meets
+ the requirements for HTTP caching described in section 13.
+
+ See section 15.1.3 for security considerations when used for forms.
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 53]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+9.4 HEAD
+
+ The HEAD method is identical to GET except that the server MUST NOT
+ return a message-body in the response. The metainformation contained
+ in the HTTP headers in response to a HEAD request SHOULD be identical
+ to the information sent in response to a GET request. This method can
+ be used for obtaining metainformation about the entity implied by the
+ request without transferring the entity-body itself. This method is
+ often used for testing hypertext links for validity, accessibility,
+ and recent modification.
+
+ The response to a HEAD request MAY be cacheable in the sense that the
+ information contained in the response MAY be used to update a
+ previously cached entity from that resource. If the new field values
+ indicate that the cached entity differs from the current entity (as
+ would be indicated by a change in Content-Length, Content-MD5, ETag
+ or Last-Modified), then the cache MUST treat the cache entry as
+ stale.
+
+9.5 POST
+
+ The POST method is used to request that the origin server accept the
+ entity enclosed in the request as a new subordinate of the resource
+ identified by the Request-URI in the Request-Line. POST is designed
+ to allow a uniform method to cover the following functions:
+
+ - Annotation of existing resources;
+
+ - Posting a message to a bulletin board, newsgroup, mailing list,
+ or similar group of articles;
+
+ - Providing a block of data, such as the result of submitting a
+ form, to a data-handling process;
+
+ - Extending a database through an append operation.
+
+ The actual function performed by the POST method is determined by the
+ server and is usually dependent on the Request-URI. The posted entity
+ is subordinate to that URI in the same way that a file is subordinate
+ to a directory containing it, a news article is subordinate to a
+ newsgroup to which it is posted, or a record is subordinate to a
+ database.
+
+ The action performed by the POST method might not result in a
+ resource that can be identified by a URI. In this case, either 200
+ (OK) or 204 (No Content) is the appropriate response status,
+ depending on whether or not the response includes an entity that
+ describes the result.
+
+
+
+Fielding, et al. Standards Track [Page 54]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ If a resource has been created on the origin server, the response
+ SHOULD be 201 (Created) and contain an entity which describes the
+ status of the request and refers to the new resource, and a Location
+ header (see section 14.30).
+
+ Responses to this method are not cacheable, unless the response
+ includes appropriate Cache-Control or Expires header fields. However,
+ the 303 (See Other) response can be used to direct the user agent to
+ retrieve a cacheable resource.
+
+ POST requests MUST obey the message transmission requirements set out
+ in section 8.2.
+
+ See section 15.1.3 for security considerations.
+
+9.6 PUT
+
+ The PUT method requests that the enclosed entity be stored under the
+ supplied Request-URI. If the Request-URI refers to an already
+ existing resource, the enclosed entity SHOULD be considered as a
+ modified version of the one residing on the origin server. If the
+ Request-URI does not point to an existing resource, and that URI is
+ capable of being defined as a new resource by the requesting user
+ agent, the origin server can create the resource with that URI. If a
+ new resource is created, the origin server MUST inform the user agent
+ via the 201 (Created) response. If an existing resource is modified,
+ either the 200 (OK) or 204 (No Content) response codes SHOULD be sent
+ to indicate successful completion of the request. If the resource
+ could not be created or modified with the Request-URI, an appropriate
+ error response SHOULD be given that reflects the nature of the
+ problem. The recipient of the entity MUST NOT ignore any Content-*
+ (e.g. Content-Range) headers that it does not understand or implement
+ and MUST return a 501 (Not Implemented) response in such cases.
+
+ If the request passes through a cache and the Request-URI identifies
+ one or more currently cached entities, those entries SHOULD be
+ treated as stale. Responses to this method are not cacheable.
+
+ The fundamental difference between the POST and PUT requests is
+ reflected in the different meaning of the Request-URI. The URI in a
+ POST request identifies the resource that will handle the enclosed
+ entity. That resource might be a data-accepting process, a gateway to
+ some other protocol, or a separate entity that accepts annotations.
+ In contrast, the URI in a PUT request identifies the entity enclosed
+ with the request -- the user agent knows what URI is intended and the
+ server MUST NOT attempt to apply the request to some other resource.
+ If the server desires that the request be applied to a different URI,
+
+
+
+
+Fielding, et al. Standards Track [Page 55]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ it MUST send a 301 (Moved Permanently) response; the user agent MAY
+ then make its own decision regarding whether or not to redirect the
+ request.
+
+ A single resource MAY be identified by many different URIs. For
+ example, an article might have a URI for identifying "the current
+ version" which is separate from the URI identifying each particular
+ version. In this case, a PUT request on a general URI might result in
+ several other URIs being defined by the origin server.
+
+ HTTP/1.1 does not define how a PUT method affects the state of an
+ origin server.
+
+ PUT requests MUST obey the message transmission requirements set out
+ in section 8.2.
+
+ Unless otherwise specified for a particular entity-header, the
+ entity-headers in the PUT request SHOULD be applied to the resource
+ created or modified by the PUT.
+
+9.7 DELETE
+
+ The DELETE method requests that the origin server delete the resource
+ identified by the Request-URI. This method MAY be overridden by human
+ intervention (or other means) on the origin server. The client cannot
+ be guaranteed that the operation has been carried out, even if the
+ status code returned from the origin server indicates that the action
+ has been completed successfully. However, the server SHOULD NOT
+ indicate success unless, at the time the response is given, it
+ intends to delete the resource or move it to an inaccessible
+ location.
+
+ A successful response SHOULD be 200 (OK) if the response includes an
+ entity describing the status, 202 (Accepted) if the action has not
+ yet been enacted, or 204 (No Content) if the action has been enacted
+ but the response does not include an entity.
+
+ If the request passes through a cache and the Request-URI identifies
+ one or more currently cached entities, those entries SHOULD be
+ treated as stale. Responses to this method are not cacheable.
+
+9.8 TRACE
+
+ The TRACE method is used to invoke a remote, application-layer loop-
+ back of the request message. The final recipient of the request
+ SHOULD reflect the message received back to the client as the
+ entity-body of a 200 (OK) response. The final recipient is either the
+
+
+
+
+Fielding, et al. Standards Track [Page 56]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ origin server or the first proxy or gateway to receive a Max-Forwards
+ value of zero (0) in the request (see section 14.31). A TRACE request
+ MUST NOT include an entity.
+
+ TRACE allows the client to see what is being received at the other
+ end of the request chain and use that data for testing or diagnostic
+ information. The value of the Via header field (section 14.45) is of
+ particular interest, since it acts as a trace of the request chain.
+ Use of the Max-Forwards header field allows the client to limit the
+ length of the request chain, which is useful for testing a chain of
+ proxies forwarding messages in an infinite loop.
+
+ If the request is valid, the response SHOULD contain the entire
+ request message in the entity-body, with a Content-Type of
+ "message/http". Responses to this method MUST NOT be cached.
+
+9.9 CONNECT
+
+ This specification reserves the method name CONNECT for use with a
+ proxy that can dynamically switch to being a tunnel (e.g. SSL
+ tunneling [44]).
+
+10 Status Code Definitions
+
+ Each Status-Code is described below, including a description of which
+ method(s) it can follow and any metainformation required in the
+ response.
+
+10.1 Informational 1xx
+
+ This class of status code indicates a provisional response,
+ consisting only of the Status-Line and optional headers, and is
+ terminated by an empty line. There are no required headers for this
+ class of status code. Since HTTP/1.0 did not define any 1xx status
+ codes, servers MUST NOT send a 1xx response to an HTTP/1.0 client
+ except under experimental conditions.
+
+ A client MUST be prepared to accept one or more 1xx status responses
+ prior to a regular response, even if the client does not expect a 100
+ (Continue) status message. Unexpected 1xx status responses MAY be
+ ignored by a user agent.
+
+ Proxies MUST forward 1xx responses, unless the connection between the
+ proxy and its client has been closed, or unless the proxy itself
+ requested the generation of the 1xx response. (For example, if a
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 57]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ proxy adds a "Expect: 100-continue" field when it forwards a request,
+ then it need not forward the corresponding 100 (Continue)
+ response(s).)
+
+10.1.1 100 Continue
+
+ The client SHOULD continue with its request. This interim response is
+ used to inform the client that the initial part of the request has
+ been received and has not yet been rejected by the server. The client
+ SHOULD continue by sending the remainder of the request or, if the
+ request has already been completed, ignore this response. The server
+ MUST send a final response after the request has been completed. See
+ section 8.2.3 for detailed discussion of the use and handling of this
+ status code.
+
+10.1.2 101 Switching Protocols
+
+ The server understands and is willing to comply with the client's
+ request, via the Upgrade message header field (section 14.42), for a
+ change in the application protocol being used on this connection. The
+ server will switch protocols to those defined by the response's
+ Upgrade header field immediately after the empty line which
+ terminates the 101 response.
+
+ The protocol SHOULD be switched only when it is advantageous to do
+ so. For example, switching to a newer version of HTTP is advantageous
+ over older versions, and switching to a real-time, synchronous
+ protocol might be advantageous when delivering resources that use
+ such features.
+
+10.2 Successful 2xx
+
+ This class of status code indicates that the client's request was
+ successfully received, understood, and accepted.
+
+10.2.1 200 OK
+
+ The request has succeeded. The information returned with the response
+ is dependent on the method used in the request, for example:
+
+ GET an entity corresponding to the requested resource is sent in
+ the response;
+
+ HEAD the entity-header fields corresponding to the requested
+ resource are sent in the response without any message-body;
+
+ POST an entity describing or containing the result of the action;
+
+
+
+
+Fielding, et al. Standards Track [Page 58]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ TRACE an entity containing the request message as received by the
+ end server.
+
+10.2.2 201 Created
+
+ The request has been fulfilled and resulted in a new resource being
+ created. The newly created resource can be referenced by the URI(s)
+ returned in the entity of the response, with the most specific URI
+ for the resource given by a Location header field. The response
+ SHOULD include an entity containing a list of resource
+ characteristics and location(s) from which the user or user agent can
+ choose the one most appropriate. The entity format is specified by
+ the media type given in the Content-Type header field. The origin
+ server MUST create the resource before returning the 201 status code.
+ If the action cannot be carried out immediately, the server SHOULD
+ respond with 202 (Accepted) response instead.
+
+ A 201 response MAY contain an ETag response header field indicating
+ the current value of the entity tag for the requested variant just
+ created, see section 14.19.
+
+10.2.3 202 Accepted
+
+ The request has been accepted for processing, but the processing has
+ not been completed. The request might or might not eventually be
+ acted upon, as it might be disallowed when processing actually takes
+ place. There is no facility for re-sending a status code from an
+ asynchronous operation such as this.
+
+ The 202 response is intentionally non-committal. Its purpose is to
+ allow a server to accept a request for some other process (perhaps a
+ batch-oriented process that is only run once per day) without
+ requiring that the user agent's connection to the server persist
+ until the process is completed. The entity returned with this
+ response SHOULD include an indication of the request's current status
+ and either a pointer to a status monitor or some estimate of when the
+ user can expect the request to be fulfilled.
+
+10.2.4 203 Non-Authoritative Information
+
+ The returned metainformation in the entity-header is not the
+ definitive set as available from the origin server, but is gathered
+ from a local or a third-party copy. The set presented MAY be a subset
+ or superset of the original version. For example, including local
+ annotation information about the resource might result in a superset
+ of the metainformation known by the origin server. Use of this
+ response code is not required and is only appropriate when the
+ response would otherwise be 200 (OK).
+
+
+
+Fielding, et al. Standards Track [Page 59]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+10.2.5 204 No Content
+
+ The server has fulfilled the request but does not need to return an
+ entity-body, and might want to return updated metainformation. The
+ response MAY include new or updated metainformation in the form of
+ entity-headers, which if present SHOULD be associated with the
+ requested variant.
+
+ If the client is a user agent, it SHOULD NOT change its document view
+ from that which caused the request to be sent. This response is
+ primarily intended to allow input for actions to take place without
+ causing a change to the user agent's active document view, although
+ any new or updated metainformation SHOULD be applied to the document
+ currently in the user agent's active view.
+
+ The 204 response MUST NOT include a message-body, and thus is always
+ terminated by the first empty line after the header fields.
+
+10.2.6 205 Reset Content
+
+ The server has fulfilled the request and the user agent SHOULD reset
+ the document view which caused the request to be sent. This response
+ is primarily intended to allow input for actions to take place via
+ user input, followed by a clearing of the form in which the input is
+ given so that the user can easily initiate another input action. The
+ response MUST NOT include an entity.
+
+10.2.7 206 Partial Content
+
+ The server has fulfilled the partial GET request for the resource.
+ The request MUST have included a Range header field (section 14.35)
+ indicating the desired range, and MAY have included an If-Range
+ header field (section 14.27) to make the request conditional.
+
+ The response MUST include the following header fields:
+
+ - Either a Content-Range header field (section 14.16) indicating
+ the range included with this response, or a multipart/byteranges
+ Content-Type including Content-Range fields for each part. If a
+ Content-Length header field is present in the response, its
+ value MUST match the actual number of OCTETs transmitted in the
+ message-body.
+
+ - Date
+
+ - ETag and/or Content-Location, if the header would have been sent
+ in a 200 response to the same request
+
+
+
+
+Fielding, et al. Standards Track [Page 60]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ - Expires, Cache-Control, and/or Vary, if the field-value might
+ differ from that sent in any previous response for the same
+ variant
+
+ If the 206 response is the result of an If-Range request that used a
+ strong cache validator (see section 13.3.3), the response SHOULD NOT
+ include other entity-headers. If the response is the result of an
+ If-Range request that used a weak validator, the response MUST NOT
+ include other entity-headers; this prevents inconsistencies between
+ cached entity-bodies and updated headers. Otherwise, the response
+ MUST include all of the entity-headers that would have been returned
+ with a 200 (OK) response to the same request.
+
+ A cache MUST NOT combine a 206 response with other previously cached
+ content if the ETag or Last-Modified headers do not match exactly,
+ see 13.5.4.
+
+ A cache that does not support the Range and Content-Range headers
+ MUST NOT cache 206 (Partial) responses.
+
+10.3 Redirection 3xx
+
+ This class of status code indicates that further action needs to be
+ taken by the user agent in order to fulfill the request. The action
+ required MAY be carried out by the user agent without interaction
+ with the user if and only if the method used in the second request is
+ GET or HEAD. A client SHOULD detect infinite redirection loops, since
+ such loops generate network traffic for each redirection.
+
+ Note: previous versions of this specification recommended a
+ maximum of five redirections. Content developers should be aware
+ that there might be clients that implement such a fixed
+ limitation.
+
+10.3.1 300 Multiple Choices
+
+ The requested resource corresponds to any one of a set of
+ representations, each with its own specific location, and agent-
+ driven negotiation information (section 12) is being provided so that
+ the user (or user agent) can select a preferred representation and
+ redirect its request to that location.
+
+ Unless it was a HEAD request, the response SHOULD include an entity
+ containing a list of resource characteristics and location(s) from
+ which the user or user agent can choose the one most appropriate. The
+ entity format is specified by the media type given in the Content-
+ Type header field. Depending upon the format and the capabilities of
+
+
+
+
+Fielding, et al. Standards Track [Page 61]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ the user agent, selection of the most appropriate choice MAY be
+ performed automatically. However, this specification does not define
+ any standard for such automatic selection.
+
+ If the server has a preferred choice of representation, it SHOULD
+ include the specific URI for that representation in the Location
+ field; user agents MAY use the Location field value for automatic
+ redirection. This response is cacheable unless indicated otherwise.
+
+10.3.2 301 Moved Permanently
+
+ The requested resource has been assigned a new permanent URI and any
+ future references to this resource SHOULD use one of the returned
+ URIs. Clients with link editing capabilities ought to automatically
+ re-link references to the Request-URI to one or more of the new
+ references returned by the server, where possible. This response is
+ cacheable unless indicated otherwise.
+
+ The new permanent URI SHOULD be given by the Location field in the
+ response. Unless the request method was HEAD, the entity of the
+ response SHOULD contain a short hypertext note with a hyperlink to
+ the new URI(s).
+
+ If the 301 status code is received in response to a request other
+ than GET or HEAD, the user agent MUST NOT automatically redirect the
+ request unless it can be confirmed by the user, since this might
+ change the conditions under which the request was issued.
+
+ Note: When automatically redirecting a POST request after
+ receiving a 301 status code, some existing HTTP/1.0 user agents
+ will erroneously change it into a GET request.
+
+10.3.3 302 Found
+
+ The requested resource resides temporarily under a different URI.
+ Since the redirection might be altered on occasion, the client SHOULD
+ continue to use the Request-URI for future requests. This response
+ is only cacheable if indicated by a Cache-Control or Expires header
+ field.
+
+ The temporary URI SHOULD be given by the Location field in the
+ response. Unless the request method was HEAD, the entity of the
+ response SHOULD contain a short hypertext note with a hyperlink to
+ the new URI(s).
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 62]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ If the 302 status code is received in response to a request other
+ than GET or HEAD, the user agent MUST NOT automatically redirect the
+ request unless it can be confirmed by the user, since this might
+ change the conditions under which the request was issued.
+
+ Note: RFC 1945 and RFC 2068 specify that the client is not allowed
+ to change the method on the redirected request. However, most
+ existing user agent implementations treat 302 as if it were a 303
+ response, performing a GET on the Location field-value regardless
+ of the original request method. The status codes 303 and 307 have
+ been added for servers that wish to make unambiguously clear which
+ kind of reaction is expected of the client.
+
+10.3.4 303 See Other
+
+ The response to the request can be found under a different URI and
+ SHOULD be retrieved using a GET method on that resource. This method
+ exists primarily to allow the output of a POST-activated script to
+ redirect the user agent to a selected resource. The new URI is not a
+ substitute reference for the originally requested resource. The 303
+ response MUST NOT be cached, but the response to the second
+ (redirected) request might be cacheable.
+
+ The different URI SHOULD be given by the Location field in the
+ response. Unless the request method was HEAD, the entity of the
+ response SHOULD contain a short hypertext note with a hyperlink to
+ the new URI(s).
+
+ Note: Many pre-HTTP/1.1 user agents do not understand the 303
+ status. When interoperability with such clients is a concern, the
+ 302 status code may be used instead, since most user agents react
+ to a 302 response as described here for 303.
+
+10.3.5 304 Not Modified
+
+ If the client has performed a conditional GET request and access is
+ allowed, but the document has not been modified, the server SHOULD
+ respond with this status code. The 304 response MUST NOT contain a
+ message-body, and thus is always terminated by the first empty line
+ after the header fields.
+
+ The response MUST include the following header fields:
+
+ - Date, unless its omission is required by section 14.18.1
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 63]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ If a clockless origin server obeys these rules, and proxies and
+ clients add their own Date to any response received without one (as
+ already specified by [RFC 2068], section 14.19), caches will operate
+ correctly.
+
+ - ETag and/or Content-Location, if the header would have been sent
+ in a 200 response to the same request
+
+ - Expires, Cache-Control, and/or Vary, if the field-value might
+ differ from that sent in any previous response for the same
+ variant
+
+ If the conditional GET used a strong cache validator (see section
+ 13.3.3), the response SHOULD NOT include other entity-headers.
+ Otherwise (i.e., the conditional GET used a weak validator), the
+ response MUST NOT include other entity-headers; this prevents
+ inconsistencies between cached entity-bodies and updated headers.
+
+ If a 304 response indicates an entity not currently cached, then the
+ cache MUST disregard the response and repeat the request without the
+ conditional.
+
+ If a cache uses a received 304 response to update a cache entry, the
+ cache MUST update the entry to reflect any new field values given in
+ the response.
+
+10.3.6 305 Use Proxy
+
+ The requested resource MUST be accessed through the proxy given by
+ the Location field. The Location field gives the URI of the proxy.
+ The recipient is expected to repeat this single request via the
+ proxy. 305 responses MUST only be generated by origin servers.
+
+ Note: RFC 2068 was not clear that 305 was intended to redirect a
+ single request, and to be generated by origin servers only. Not
+ observing these limitations has significant security consequences.
+
+10.3.7 306 (Unused)
+
+ The 306 status code was used in a previous version of the
+ specification, is no longer used, and the code is reserved.
+
+
+
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 64]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+10.3.8 307 Temporary Redirect
+
+ The requested resource resides temporarily under a different URI.
+ Since the redirection MAY be altered on occasion, the client SHOULD
+ continue to use the Request-URI for future requests. This response
+ is only cacheable if indicated by a Cache-Control or Expires header
+ field.
+
+ The temporary URI SHOULD be given by the Location field in the
+ response. Unless the request method was HEAD, the entity of the
+ response SHOULD contain a short hypertext note with a hyperlink to
+ the new URI(s) , since many pre-HTTP/1.1 user agents do not
+ understand the 307 status. Therefore, the note SHOULD contain the
+ information necessary for a user to repeat the original request on
+ the new URI.
+
+ If the 307 status code is received in response to a request other
+ than GET or HEAD, the user agent MUST NOT automatically redirect the
+ request unless it can be confirmed by the user, since this might
+ change the conditions under which the request was issued.
+
+10.4 Client Error 4xx
+
+ The 4xx class of status code is intended for cases in which the
+ client seems to have erred. Except when responding to a HEAD request,
+ the server SHOULD include an entity containing an explanation of the
+ error situation, and whether it is a temporary or permanent
+ condition. These status codes are applicable to any request method.
+ User agents SHOULD display any included entity to the user.
+
+ If the client is sending data, a server implementation using TCP
+ SHOULD be careful to ensure that the client acknowledges receipt of
+ the packet(s) containing the response, before the server closes the
+ input connection. If the client continues sending data to the server
+ after the close, the server's TCP stack will send a reset packet to
+ the client, which may erase the client's unacknowledged input buffers
+ before they can be read and interpreted by the HTTP application.
+
+10.4.1 400 Bad Request
+
+ The request could not be understood by the server due to malformed
+ syntax. The client SHOULD NOT repeat the request without
+ modifications.
+
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 65]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+10.4.2 401 Unauthorized
+
+ The request requires user authentication. The response MUST include a
+ WWW-Authenticate header field (section 14.47) containing a challenge
+ applicable to the requested resource. The client MAY repeat the
+ request with a suitable Authorization header field (section 14.8). If
+ the request already included Authorization credentials, then the 401
+ response indicates that authorization has been refused for those
+ credentials. If the 401 response contains the same challenge as the
+ prior response, and the user agent has already attempted
+ authentication at least once, then the user SHOULD be presented the
+ entity that was given in the response, since that entity might
+ include relevant diagnostic information. HTTP access authentication
+ is explained in "HTTP Authentication: Basic and Digest Access
+ Authentication" [43].
+
+10.4.3 402 Payment Required
+
+ This code is reserved for future use.
+
+10.4.4 403 Forbidden
+
+ The server understood the request, but is refusing to fulfill it.
+ Authorization will not help and the request SHOULD NOT be repeated.
+ If the request method was not HEAD and the server wishes to make
+ public why the request has not been fulfilled, it SHOULD describe the
+ reason for the refusal in the entity. If the server does not wish to
+ make this information available to the client, the status code 404
+ (Not Found) can be used instead.
+
+10.4.5 404 Not Found
+
+ The server has not found anything matching the Request-URI. No
+ indication is given of whether the condition is temporary or
+ permanent. The 410 (Gone) status code SHOULD be used if the server
+ knows, through some internally configurable mechanism, that an old
+ resource is permanently unavailable and has no forwarding address.
+ This status code is commonly used when the server does not wish to
+ reveal exactly why the request has been refused, or when no other
+ response is applicable.
+
+10.4.6 405 Method Not Allowed
+
+ The method specified in the Request-Line is not allowed for the
+ resource identified by the Request-URI. The response MUST include an
+ Allow header containing a list of valid methods for the requested
+ resource.
+
+
+
+
+Fielding, et al. Standards Track [Page 66]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+10.4.7 406 Not Acceptable
+
+ The resource identified by the request is only capable of generating
+ response entities which have content characteristics not acceptable
+ according to the accept headers sent in the request.
+
+ Unless it was a HEAD request, the response SHOULD include an entity
+ containing a list of available entity characteristics and location(s)
+ from which the user or user agent can choose the one most
+ appropriate. The entity format is specified by the media type given
+ in the Content-Type header field. Depending upon the format and the
+ capabilities of the user agent, selection of the most appropriate
+ choice MAY be performed automatically. However, this specification
+ does not define any standard for such automatic selection.
+
+ Note: HTTP/1.1 servers are allowed to return responses which are
+ not acceptable according to the accept headers sent in the
+ request. In some cases, this may even be preferable to sending a
+ 406 response. User agents are encouraged to inspect the headers of
+ an incoming response to determine if it is acceptable.
+
+ If the response could be unacceptable, a user agent SHOULD
+ temporarily stop receipt of more data and query the user for a
+ decision on further actions.
+
+10.4.8 407 Proxy Authentication Required
+
+ This code is similar to 401 (Unauthorized), but indicates that the
+ client must first authenticate itself with the proxy. The proxy MUST
+ return a Proxy-Authenticate header field (section 14.33) containing a
+ challenge applicable to the proxy for the requested resource. The
+ client MAY repeat the request with a suitable Proxy-Authorization
+ header field (section 14.34). HTTP access authentication is explained
+ in "HTTP Authentication: Basic and Digest Access Authentication"
+ [43].
+
+10.4.9 408 Request Timeout
+
+ The client did not produce a request within the time that the server
+ was prepared to wait. The client MAY repeat the request without
+ modifications at any later time.
+
+10.4.10 409 Conflict
+
+ The request could not be completed due to a conflict with the current
+ state of the resource. This code is only allowed in situations where
+ it is expected that the user might be able to resolve the conflict
+ and resubmit the request. The response body SHOULD include enough
+
+
+
+Fielding, et al. Standards Track [Page 67]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ information for the user to recognize the source of the conflict.
+ Ideally, the response entity would include enough information for the
+ user or user agent to fix the problem; however, that might not be
+ possible and is not required.
+
+ Conflicts are most likely to occur in response to a PUT request. For
+ example, if versioning were being used and the entity being PUT
+ included changes to a resource which conflict with those made by an
+ earlier (third-party) request, the server might use the 409 response
+ to indicate that it can't complete the request. In this case, the
+ response entity would likely contain a list of the differences
+ between the two versions in a format defined by the response
+ Content-Type.
+
+10.4.11 410 Gone
+
+ The requested resource is no longer available at the server and no
+ forwarding address is known. This condition is expected to be
+ considered permanent. Clients with link editing capabilities SHOULD
+ delete references to the Request-URI after user approval. If the
+ server does not know, or has no facility to determine, whether or not
+ the condition is permanent, the status code 404 (Not Found) SHOULD be
+ used instead. This response is cacheable unless indicated otherwise.
+
+ The 410 response is primarily intended to assist the task of web
+ maintenance by notifying the recipient that the resource is
+ intentionally unavailable and that the server owners desire that
+ remote links to that resource be removed. Such an event is common for
+ limited-time, promotional services and for resources belonging to
+ individuals no longer working at the server's site. It is not
+ necessary to mark all permanently unavailable resources as "gone" or
+ to keep the mark for any length of time -- that is left to the
+ discretion of the server owner.
+
+10.4.12 411 Length Required
+
+ The server refuses to accept the request without a defined Content-
+ Length. The client MAY repeat the request if it adds a valid
+ Content-Length header field containing the length of the message-body
+ in the request message.
+
+10.4.13 412 Precondition Failed
+
+ The precondition given in one or more of the request-header fields
+ evaluated to false when it was tested on the server. This response
+ code allows the client to place preconditions on the current resource
+ metainformation (header field data) and thus prevent the requested
+ method from being applied to a resource other than the one intended.
+
+
+
+Fielding, et al. Standards Track [Page 68]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+10.4.14 413 Request Entity Too Large
+
+ The server is refusing to process a request because the request
+ entity is larger than the server is willing or able to process. The
+ server MAY close the connection to prevent the client from continuing
+ the request.
+
+ If the condition is temporary, the server SHOULD include a Retry-
+ After header field to indicate that it is temporary and after what
+ time the client MAY try again.
+
+10.4.15 414 Request-URI Too Long
+
+ The server is refusing to service the request because the Request-URI
+ is longer than the server is willing to interpret. This rare
+ condition is only likely to occur when a client has improperly
+ converted a POST request to a GET request with long query
+ information, when the client has descended into a URI "black hole" of
+ redirection (e.g., a redirected URI prefix that points to a suffix of
+ itself), or when the server is under attack by a client attempting to
+ exploit security holes present in some servers using fixed-length
+ buffers for reading or manipulating the Request-URI.
+
+10.4.16 415 Unsupported Media Type
+
+ The server is refusing to service the request because the entity of
+ the request is in a format not supported by the requested resource
+ for the requested method.
+
+10.4.17 416 Requested Range Not Satisfiable
+
+ A server SHOULD return a response with this status code if a request
+ included a Range request-header field (section 14.35), and none of
+ the range-specifier values in this field overlap the current extent
+ of the selected resource, and the request did not include an If-Range
+ request-header field. (For byte-ranges, this means that the first-
+ byte-pos of all of the byte-range-spec values were greater than the
+ current length of the selected resource.)
+
+ When this status code is returned for a byte-range request, the
+ response SHOULD include a Content-Range entity-header field
+ specifying the current length of the selected resource (see section
+ 14.16). This response MUST NOT use the multipart/byteranges content-
+ type.
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 69]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+10.4.18 417 Expectation Failed
+
+ The expectation given in an Expect request-header field (see section
+ 14.20) could not be met by this server, or, if the server is a proxy,
+ the server has unambiguous evidence that the request could not be met
+ by the next-hop server.
+
+10.5 Server Error 5xx
+
+ Response status codes beginning with the digit "5" indicate cases in
+ which the server is aware that it has erred or is incapable of
+ performing the request. Except when responding to a HEAD request, the
+ server SHOULD include an entity containing an explanation of the
+ error situation, and whether it is a temporary or permanent
+ condition. User agents SHOULD display any included entity to the
+ user. These response codes are applicable to any request method.
+
+10.5.1 500 Internal Server Error
+
+ The server encountered an unexpected condition which prevented it
+ from fulfilling the request.
+
+10.5.2 501 Not Implemented
+
+ The server does not support the functionality required to fulfill the
+ request. This is the appropriate response when the server does not
+ recognize the request method and is not capable of supporting it for
+ any resource.
+
+10.5.3 502 Bad Gateway
+
+ The server, while acting as a gateway or proxy, received an invalid
+ response from the upstream server it accessed in attempting to
+ fulfill the request.
+
+10.5.4 503 Service Unavailable
+
+ The server is currently unable to handle the request due to a
+ temporary overloading or maintenance of the server. The implication
+ is that this is a temporary condition which will be alleviated after
+ some delay. If known, the length of the delay MAY be indicated in a
+ Retry-After header. If no Retry-After is given, the client SHOULD
+ handle the response as it would for a 500 response.
+
+ Note: The existence of the 503 status code does not imply that a
+ server must use it when becoming overloaded. Some servers may wish
+ to simply refuse the connection.
+
+
+
+
+Fielding, et al. Standards Track [Page 70]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+10.5.5 504 Gateway Timeout
+
+ The server, while acting as a gateway or proxy, did not receive a
+ timely response from the upstream server specified by the URI (e.g.
+ HTTP, FTP, LDAP) or some other auxiliary server (e.g. DNS) it needed
+ to access in attempting to complete the request.
+
+ Note: Note to implementors: some deployed proxies are known to
+ return 400 or 500 when DNS lookups time out.
+
+10.5.6 505 HTTP Version Not Supported
+
+ The server does not support, or refuses to support, the HTTP protocol
+ version that was used in the request message. The server is
+ indicating that it is unable or unwilling to complete the request
+ using the same major version as the client, as described in section
+ 3.1, other than with this error message. The response SHOULD contain
+ an entity describing why that version is not supported and what other
+ protocols are supported by that server.
+
+11 Access Authentication
+
+ HTTP provides several OPTIONAL challenge-response authentication
+ mechanisms which can be used by a server to challenge a client
+ request and by a client to provide authentication information. The
+ general framework for access authentication, and the specification of
+ "basic" and "digest" authentication, are specified in "HTTP
+ Authentication: Basic and Digest Access Authentication" [43]. This
+ specification adopts the definitions of "challenge" and "credentials"
+ from that specification.
+
+12 Content Negotiation
+
+ Most HTTP responses include an entity which contains information for
+ interpretation by a human user. Naturally, it is desirable to supply
+ the user with the "best available" entity corresponding to the
+ request. Unfortunately for servers and caches, not all users have the
+ same preferences for what is "best," and not all user agents are
+ equally capable of rendering all entity types. For that reason, HTTP
+ has provisions for several mechanisms for "content negotiation" --
+ the process of selecting the best representation for a given response
+ when there are multiple representations available.
+
+ Note: This is not called "format negotiation" because the
+ alternate representations may be of the same media type, but use
+ different capabilities of that type, be in different languages,
+ etc.
+
+
+
+
+Fielding, et al. Standards Track [Page 71]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ Any response containing an entity-body MAY be subject to negotiation,
+ including error responses.
+
+ There are two kinds of content negotiation which are possible in
+ HTTP: server-driven and agent-driven negotiation. These two kinds of
+ negotiation are orthogonal and thus may be used separately or in
+ combination. One method of combination, referred to as transparent
+ negotiation, occurs when a cache uses the agent-driven negotiation
+ information provided by the origin server in order to provide
+ server-driven negotiation for subsequent requests.
+
+12.1 Server-driven Negotiation
+
+ If the selection of the best representation for a response is made by
+ an algorithm located at the server, it is called server-driven
+ negotiation. Selection is based on the available representations of
+ the response (the dimensions over which it can vary; e.g. language,
+ content-coding, etc.) and the contents of particular header fields in
+ the request message or on other information pertaining to the request
+ (such as the network address of the client).
+
+ Server-driven negotiation is advantageous when the algorithm for
+ selecting from among the available representations is difficult to
+ describe to the user agent, or when the server desires to send its
+ "best guess" to the client along with the first response (hoping to
+ avoid the round-trip delay of a subsequent request if the "best
+ guess" is good enough for the user). In order to improve the server's
+ guess, the user agent MAY include request header fields (Accept,
+ Accept-Language, Accept-Encoding, etc.) which describe its
+ preferences for such a response.
+
+ Server-driven negotiation has disadvantages:
+
+ 1. It is impossible for the server to accurately determine what
+ might be "best" for any given user, since that would require
+ complete knowledge of both the capabilities of the user agent
+ and the intended use for the response (e.g., does the user want
+ to view it on screen or print it on paper?).
+
+ 2. Having the user agent describe its capabilities in every
+ request can be both very inefficient (given that only a small
+ percentage of responses have multiple representations) and a
+ potential violation of the user's privacy.
+
+ 3. It complicates the implementation of an origin server and the
+ algorithms for generating responses to a request.
+
+
+
+
+
+Fielding, et al. Standards Track [Page 72]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ 4. It may limit a public cache's ability to use the same response
+ for multiple user's requests.
+
+ HTTP/1.1 includes the following request-header fields for enabling
+ server-driven negotiation through description of user agent
+ capabilities and user preferences: Accept (section 14.1), Accept-
+ Charset (section 14.2), Accept-Encoding (section 14.3), Accept-
+ Language (section 14.4), and User-Agent (section 14.43). However, an
+ origin server is not limited to these dimensions and MAY vary the
+ response based on any aspect of the request, including information
+ outside the request-header fields or within extension header fields
+ not defined by this specification.
+
+ The Vary header field can be used to express the parameters the
+ server uses to select a representation that is subject to server-
+ driven negotiation. See section 13.6 for use of the Vary header field
+ by caches and section 14.44 for use of the Vary header field by
+ servers.
+
+12.2 Agent-driven Negotiation
+
+ With agent-driven negotiation, selection of the best representation
+ for a response is performed by the user agent after receiving an
+ initial response from the origin server. Selection is based on a list
+ of the available representations of the response included within the
+ header fields or entity-body of the initial response, with each
+ representation identified by its own URI. Selection from among the
+ representations may be performed automatically (if the user agent is
+ capable of doing so) or manually by the user selecting from a
+ generated (possibly hypertext) menu.
+
+ Agent-driven negotiation is advantageous when the response would vary
+ over commonly-used dimensions (such as type, language, or encoding),
+ when the origin server is unable to determine a user agent's
+ capabilities from examining the request, and generally when public
+ caches are used to distribute server load and reduce network usage.
+
+ Agent-driven negotiation suffers from the disadvantage of needing a
+ second request to obtain the best alternate representation. This
+ second request is only efficient when caching is used. In addition,
+ this specification does not define any mechanism for supporting
+ automatic selection, though it also does not prevent any such
+ mechanism from being developed as an extension and used within
+ HTTP/1.1.
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 73]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ HTTP/1.1 defines the 300 (Multiple Choices) and 406 (Not Acceptable)
+ status codes for enabling agent-driven negotiation when the server is
+ unwilling or unable to provide a varying response using server-driven
+ negotiation.
+
+12.3 Transparent Negotiation
+
+ Transparent negotiation is a combination of both server-driven and
+ agent-driven negotiation. When a cache is supplied with a form of the
+ list of available representations of the response (as in agent-driven
+ negotiation) and the dimensions of variance are completely understood
+ by the cache, then the cache becomes capable of performing server-
+ driven negotiation on behalf of the origin server for subsequent
+ requests on that resource.
+
+ Transparent negotiation has the advantage of distributing the
+ negotiation work that would otherwise be required of the origin
+ server and also removing the second request delay of agent-driven
+ negotiation when the cache is able to correctly guess the right
+ response.
+
+ This specification does not define any mechanism for transparent
+ negotiation, though it also does not prevent any such mechanism from
+ being developed as an extension that could be used within HTTP/1.1.
+
+13 Caching in HTTP
+
+ HTTP is typically used for distributed information systems, where
+ performance can be improved by the use of response caches. The
+ HTTP/1.1 protocol includes a number of elements intended to make
+ caching work as well as possible. Because these elements are
+ inextricable from other aspects of the protocol, and because they
+ interact with each other, it is useful to describe the basic caching
+ design of HTTP separately from the detailed descriptions of methods,
+ headers, response codes, etc.
+
+ Caching would be useless if it did not significantly improve
+ performance. The goal of caching in HTTP/1.1 is to eliminate the need
+ to send requests in many cases, and to eliminate the need to send
+ full responses in many other cases. The former reduces the number of
+ network round-trips required for many operations; we use an
+ "expiration" mechanism for this purpose (see section 13.2). The
+ latter reduces network bandwidth requirements; we use a "validation"
+ mechanism for this purpose (see section 13.3).
+
+ Requirements for performance, availability, and disconnected
+ operation require us to be able to relax the goal of semantic
+ transparency. The HTTP/1.1 protocol allows origin servers, caches,
+
+
+
+Fielding, et al. Standards Track [Page 74]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ and clients to explicitly reduce transparency when necessary.
+ However, because non-transparent operation may confuse non-expert
+ users, and might be incompatible with certain server applications
+ (such as those for ordering merchandise), the protocol requires that
+ transparency be relaxed
+
+ - only by an explicit protocol-level request when relaxed by
+ client or origin server
+
+ - only with an explicit warning to the end user when relaxed by
+ cache or client
+
+ Therefore, the HTTP/1.1 protocol provides these important elements:
+
+ 1. Protocol features that provide full semantic transparency when
+ this is required by all parties.
+
+ 2. Protocol features that allow an origin server or user agent to
+ explicitly request and control non-transparent operation.
+
+ 3. Protocol features that allow a cache to attach warnings to
+ responses that do not preserve the requested approximation of
+ semantic transparency.
+
+ A basic principle is that it must be possible for the clients to
+ detect any potential relaxation of semantic transparency.
+
+ Note: The server, cache, or client implementor might be faced with
+ design decisions not explicitly discussed in this specification.
+ If a decision might affect semantic transparency, the implementor
+ ought to err on the side of maintaining transparency unless a
+ careful and complete analysis shows significant benefits in
+ breaking transparency.
+
+13.1.1 Cache Correctness
+
+ A correct cache MUST respond to a request with the most up-to-date
+ response held by the cache that is appropriate to the request (see
+ sections 13.2.5, 13.2.6, and 13.12) which meets one of the following
+ conditions:
+
+ 1. It has been checked for equivalence with what the origin server
+ would have returned by revalidating the response with the
+ origin server (section 13.3);
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 75]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ 2. It is "fresh enough" (see section 13.2). In the default case,
+ this means it meets the least restrictive freshness requirement
+ of the client, origin server, and cache (see section 14.9); if
+ the origin server so specifies, it is the freshness requirement
+ of the origin server alone.
+
+ If a stored response is not "fresh enough" by the most
+ restrictive freshness requirement of both the client and the
+ origin server, in carefully considered circumstances the cache
+ MAY still return the response with the appropriate Warning
+ header (see section 13.1.5 and 14.46), unless such a response
+ is prohibited (e.g., by a "no-store" cache-directive, or by a
+ "no-cache" cache-request-directive; see section 14.9).
+
+ 3. It is an appropriate 304 (Not Modified), 305 (Proxy Redirect),
+ or error (4xx or 5xx) response message.
+
+ If the cache can not communicate with the origin server, then a
+ correct cache SHOULD respond as above if the response can be
+ correctly served from the cache; if not it MUST return an error or
+ warning indicating that there was a communication failure.
+
+ If a cache receives a response (either an entire response, or a 304
+ (Not Modified) response) that it would normally forward to the
+ requesting client, and the received response is no longer fresh, the
+ cache SHOULD forward it to the requesting client without adding a new
+ Warning (but without removing any existing Warning headers). A cache
+ SHOULD NOT attempt to revalidate a response simply because that
+ response became stale in transit; this might lead to an infinite
+ loop. A user agent that receives a stale response without a Warning
+ MAY display a warning indication to the user.
+
+13.1.2 Warnings
+
+ Whenever a cache returns a response that is neither first-hand nor
+ "fresh enough" (in the sense of condition 2 in section 13.1.1), it
+ MUST attach a warning to that effect, using a Warning general-header.
+ The Warning header and the currently defined warnings are described
+ in section 14.46. The warning allows clients to take appropriate
+ action.
+
+ Warnings MAY be used for other purposes, both cache-related and
+ otherwise. The use of a warning, rather than an error status code,
+ distinguish these responses from true failures.
+
+ Warnings are assigned three digit warn-codes. The first digit
+ indicates whether the Warning MUST or MUST NOT be deleted from a
+ stored cache entry after a successful revalidation:
+
+
+
+Fielding, et al. Standards Track [Page 76]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ 1xx Warnings that describe the freshness or revalidation status of
+ the response, and so MUST be deleted after a successful
+ revalidation. 1XX warn-codes MAY be generated by a cache only when
+ validating a cached entry. It MUST NOT be generated by clients.
+
+ 2xx Warnings that describe some aspect of the entity body or entity
+ headers that is not rectified by a revalidation (for example, a
+ lossy compression of the entity bodies) and which MUST NOT be
+ deleted after a successful revalidation.
+
+ See section 14.46 for the definitions of the codes themselves.
+
+ HTTP/1.0 caches will cache all Warnings in responses, without
+ deleting the ones in the first category. Warnings in responses that
+ are passed to HTTP/1.0 caches carry an extra warning-date field,
+ which prevents a future HTTP/1.1 recipient from believing an
+ erroneously cached Warning.
+
+ Warnings also carry a warning text. The text MAY be in any
+ appropriate natural language (perhaps based on the client's Accept
+ headers), and include an OPTIONAL indication of what character set is
+ used.
+
+ Multiple warnings MAY be attached to a response (either by the origin
+ server or by a cache), including multiple warnings with the same code
+ number. For example, a server might provide the same warning with
+ texts in both English and Basque.
+
+ When multiple warnings are attached to a response, it might not be
+ practical or reasonable to display all of them to the user. This
+ version of HTTP does not specify strict priority rules for deciding
+ which warnings to display and in what order, but does suggest some
+ heuristics.
+
+13.1.3 Cache-control Mechanisms
+
+ The basic cache mechanisms in HTTP/1.1 (server-specified expiration
+ times and validators) are implicit directives to caches. In some
+ cases, a server or client might need to provide explicit directives
+ to the HTTP caches. We use the Cache-Control header for this purpose.
+
+ The Cache-Control header allows a client or server to transmit a
+ variety of directives in either requests or responses. These
+ directives typically override the default caching algorithms. As a
+ general rule, if there is any apparent conflict between header
+ values, the most restrictive interpretation is applied (that is, the
+ one that is most likely to preserve semantic transparency). However,
+
+
+
+
+Fielding, et al. Standards Track [Page 77]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ in some cases, cache-control directives are explicitly specified as
+ weakening the approximation of semantic transparency (for example,
+ "max-stale" or "public").
+
+ The cache-control directives are described in detail in section 14.9.
+
+13.1.4 Explicit User Agent Warnings
+
+ Many user agents make it possible for users to override the basic
+ caching mechanisms. For example, the user agent might allow the user
+ to specify that cached entities (even explicitly stale ones) are
+ never validated. Or the user agent might habitually add "Cache-
+ Control: max-stale=3600" to every request. The user agent SHOULD NOT
+ default to either non-transparent behavior, or behavior that results
+ in abnormally ineffective caching, but MAY be explicitly configured
+ to do so by an explicit action of the user.
+
+ If the user has overridden the basic caching mechanisms, the user
+ agent SHOULD explicitly indicate to the user whenever this results in
+ the display of information that might not meet the server's
+ transparency requirements (in particular, if the displayed entity is
+ known to be stale). Since the protocol normally allows the user agent
+ to determine if responses are stale or not, this indication need only
+ be displayed when this actually happens. The indication need not be a
+ dialog box; it could be an icon (for example, a picture of a rotting
+ fish) or some other indicator.
+
+ If the user has overridden the caching mechanisms in a way that would
+ abnormally reduce the effectiveness of caches, the user agent SHOULD
+ continually indicate this state to the user (for example, by a
+ display of a picture of currency in flames) so that the user does not
+ inadvertently consume excess resources or suffer from excessive
+ latency.
+
+13.1.5 Exceptions to the Rules and Warnings
+
+ In some cases, the operator of a cache MAY choose to configure it to
+ return stale responses even when not requested by clients. This
+ decision ought not be made lightly, but may be necessary for reasons
+ of availability or performance, especially when the cache is poorly
+ connected to the origin server. Whenever a cache returns a stale
+ response, it MUST mark it as such (using a Warning header) enabling
+ the client software to alert the user that there might be a potential
+ problem.
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 78]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ It also allows the user agent to take steps to obtain a first-hand or
+ fresh response. For this reason, a cache SHOULD NOT return a stale
+ response if the client explicitly requests a first-hand or fresh one,
+ unless it is impossible to comply for technical or policy reasons.
+
+13.1.6 Client-controlled Behavior
+
+ While the origin server (and to a lesser extent, intermediate caches,
+ by their contribution to the age of a response) are the primary
+ source of expiration information, in some cases the client might need
+ to control a cache's decision about whether to return a cached
+ response without validating it. Clients do this using several
+ directives of the Cache-Control header.
+
+ A client's request MAY specify the maximum age it is willing to
+ accept of an unvalidated response; specifying a value of zero forces
+ the cache(s) to revalidate all responses. A client MAY also specify
+ the minimum time remaining before a response expires. Both of these
+ options increase constraints on the behavior of caches, and so cannot
+ further relax the cache's approximation of semantic transparency.
+
+ A client MAY also specify that it will accept stale responses, up to
+ some maximum amount of staleness. This loosens the constraints on the
+ caches, and so might violate the origin server's specified
+ constraints on semantic transparency, but might be necessary to
+ support disconnected operation, or high availability in the face of
+ poor connectivity.
+
+13.2 Expiration Model
+
+13.2.1 Server-Specified Expiration
+
+ HTTP caching works best when caches can entirely avoid making
+ requests to the origin server. The primary mechanism for avoiding
+ requests is for an origin server to provide an explicit expiration
+ time in the future, indicating that a response MAY be used to satisfy
+ subsequent requests. In other words, a cache can return a fresh
+ response without first contacting the server.
+
+ Our expectation is that servers will assign future explicit
+ expiration times to responses in the belief that the entity is not
+ likely to change, in a semantically significant way, before the
+ expiration time is reached. This normally preserves semantic
+ transparency, as long as the server's expiration times are carefully
+ chosen.
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 79]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ The expiration mechanism applies only to responses taken from a cache
+ and not to first-hand responses forwarded immediately to the
+ requesting client.
+
+ If an origin server wishes to force a semantically transparent cache
+ to validate every request, it MAY assign an explicit expiration time
+ in the past. This means that the response is always stale, and so the
+ cache SHOULD validate it before using it for subsequent requests. See
+ section 14.9.4 for a more restrictive way to force revalidation.
+
+ If an origin server wishes to force any HTTP/1.1 cache, no matter how
+ it is configured, to validate every request, it SHOULD use the "must-
+ revalidate" cache-control directive (see section 14.9).
+
+ Servers specify explicit expiration times using either the Expires
+ header, or the max-age directive of the Cache-Control header.
+
+ An expiration time cannot be used to force a user agent to refresh
+ its display or reload a resource; its semantics apply only to caching
+ mechanisms, and such mechanisms need only check a resource's
+ expiration status when a new request for that resource is initiated.
+ See section 13.13 for an explanation of the difference between caches
+ and history mechanisms.
+
+13.2.2 Heuristic Expiration
+
+ Since origin servers do not always provide explicit expiration times,
+ HTTP caches typically assign heuristic expiration times, employing
+ algorithms that use other header values (such as the Last-Modified
+ time) to estimate a plausible expiration time. The HTTP/1.1
+ specification does not provide specific algorithms, but does impose
+ worst-case constraints on their results. Since heuristic expiration
+ times might compromise semantic transparency, they ought to used
+ cautiously, and we encourage origin servers to provide explicit
+ expiration times as much as possible.
+
+13.2.3 Age Calculations
+
+ In order to know if a cached entry is fresh, a cache needs to know if
+ its age exceeds its freshness lifetime. We discuss how to calculate
+ the latter in section 13.2.4; this section describes how to calculate
+ the age of a response or cache entry.
+
+ In this discussion, we use the term "now" to mean "the current value
+ of the clock at the host performing the calculation." Hosts that use
+ HTTP, but especially hosts running origin servers and caches, SHOULD
+ use NTP [28] or some similar protocol to synchronize their clocks to
+ a globally accurate time standard.
+
+
+
+Fielding, et al. Standards Track [Page 80]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ HTTP/1.1 requires origin servers to send a Date header, if possible,
+ with every response, giving the time at which the response was
+ generated (see section 14.18). We use the term "date_value" to denote
+ the value of the Date header, in a form appropriate for arithmetic
+ operations.
+
+ HTTP/1.1 uses the Age response-header to convey the estimated age of
+ the response message when obtained from a cache. The Age field value
+ is the cache's estimate of the amount of time since the response was
+ generated or revalidated by the origin server.
+
+ In essence, the Age value is the sum of the time that the response
+ has been resident in each of the caches along the path from the
+ origin server, plus the amount of time it has been in transit along
+ network paths.
+
+ We use the term "age_value" to denote the value of the Age header, in
+ a form appropriate for arithmetic operations.
+
+ A response's age can be calculated in two entirely independent ways:
+
+ 1. now minus date_value, if the local clock is reasonably well
+ synchronized to the origin server's clock. If the result is
+ negative, the result is replaced by zero.
+
+ 2. age_value, if all of the caches along the response path
+ implement HTTP/1.1.
+
+ Given that we have two independent ways to compute the age of a
+ response when it is received, we can combine these as
+
+ corrected_received_age = max(now - date_value, age_value)
+
+ and as long as we have either nearly synchronized clocks or all-
+ HTTP/1.1 paths, one gets a reliable (conservative) result.
+
+ Because of network-imposed delays, some significant interval might
+ pass between the time that a server generates a response and the time
+ it is received at the next outbound cache or client. If uncorrected,
+ this delay could result in improperly low ages.
+
+ Because the request that resulted in the returned Age value must have
+ been initiated prior to that Age value's generation, we can correct
+ for delays imposed by the network by recording the time at which the
+ request was initiated. Then, when an Age value is received, it MUST
+ be interpreted relative to the time the request was initiated, not
+
+
+
+
+
+Fielding, et al. Standards Track [Page 81]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ the time that the response was received. This algorithm results in
+ conservative behavior no matter how much delay is experienced. So, we
+ compute:
+
+ corrected_initial_age = corrected_received_age
+ + (now - request_time)
+
+ where "request_time" is the time (according to the local clock) when
+ the request that elicited this response was sent.
+
+ Summary of age calculation algorithm, when a cache receives a
+ response:
+
+ /*
+ * age_value
+ * is the value of Age: header received by the cache with
+ * this response.
+ * date_value
+ * is the value of the origin server's Date: header
+ * request_time
+ * is the (local) time when the cache made the request
+ * that resulted in this cached response
+ * response_time
+ * is the (local) time when the cache received the
+ * response
+ * now
+ * is the current (local) time
+ */
+
+ apparent_age = max(0, response_time - date_value);
+ corrected_received_age = max(apparent_age, age_value);
+ response_delay = response_time - request_time;
+ corrected_initial_age = corrected_received_age + response_delay;
+ resident_time = now - response_time;
+ current_age = corrected_initial_age + resident_time;
+
+ The current_age of a cache entry is calculated by adding the amount
+ of time (in seconds) since the cache entry was last validated by the
+ origin server to the corrected_initial_age. When a response is
+ generated from a cache entry, the cache MUST include a single Age
+ header field in the response with a value equal to the cache entry's
+ current_age.
+
+ The presence of an Age header field in a response implies that a
+ response is not first-hand. However, the converse is not true, since
+ the lack of an Age header field in a response does not imply that the
+
+
+
+
+
+Fielding, et al. Standards Track [Page 82]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ response is first-hand unless all caches along the request path are
+ compliant with HTTP/1.1 (i.e., older HTTP caches did not implement
+ the Age header field).
+
+13.2.4 Expiration Calculations
+
+ In order to decide whether a response is fresh or stale, we need to
+ compare its freshness lifetime to its age. The age is calculated as
+ described in section 13.2.3; this section describes how to calculate
+ the freshness lifetime, and to determine if a response has expired.
+ In the discussion below, the values can be represented in any form
+ appropriate for arithmetic operations.
+
+ We use the term "expires_value" to denote the value of the Expires
+ header. We use the term "max_age_value" to denote an appropriate
+ value of the number of seconds carried by the "max-age" directive of
+ the Cache-Control header in a response (see section 14.9.3).
+
+ The max-age directive takes priority over Expires, so if max-age is
+ present in a response, the calculation is simply:
+
+ freshness_lifetime = max_age_value
+
+ Otherwise, if Expires is present in the response, the calculation is:
+
+ freshness_lifetime = expires_value - date_value
+
+ Note that neither of these calculations is vulnerable to clock skew,
+ since all of the information comes from the origin server.
+
+ If none of Expires, Cache-Control: max-age, or Cache-Control: s-
+ maxage (see section 14.9.3) appears in the response, and the response
+ does not include other restrictions on caching, the cache MAY compute
+ a freshness lifetime using a heuristic. The cache MUST attach Warning
+ 113 to any response whose age is more than 24 hours if such warning
+ has not already been added.
+
+ Also, if the response does have a Last-Modified time, the heuristic
+ expiration value SHOULD be no more than some fraction of the interval
+ since that time. A typical setting of this fraction might be 10%.
+
+ The calculation to determine if a response has expired is quite
+ simple:
+
+ response_is_fresh = (freshness_lifetime > current_age)
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 83]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+13.2.5 Disambiguating Expiration Values
+
+ Because expiration values are assigned optimistically, it is possible
+ for two caches to contain fresh values for the same resource that are
+ different.
+
+ If a client performing a retrieval receives a non-first-hand response
+ for a request that was already fresh in its own cache, and the Date
+ header in its existing cache entry is newer than the Date on the new
+ response, then the client MAY ignore the response. If so, it MAY
+ retry the request with a "Cache-Control: max-age=0" directive (see
+ section 14.9), to force a check with the origin server.
+
+ If a cache has two fresh responses for the same representation with
+ different validators, it MUST use the one with the more recent Date
+ header. This situation might arise because the cache is pooling
+ responses from other caches, or because a client has asked for a
+ reload or a revalidation of an apparently fresh cache entry.
+
+13.2.6 Disambiguating Multiple Responses
+
+ Because a client might be receiving responses via multiple paths, so
+ that some responses flow through one set of caches and other
+ responses flow through a different set of caches, a client might
+ receive responses in an order different from that in which the origin
+ server sent them. We would like the client to use the most recently
+ generated response, even if older responses are still apparently
+ fresh.
+
+ Neither the entity tag nor the expiration value can impose an
+ ordering on responses, since it is possible that a later response
+ intentionally carries an earlier expiration time. The Date values are
+ ordered to a granularity of one second.
+
+ When a client tries to revalidate a cache entry, and the response it
+ receives contains a Date header that appears to be older than the one
+ for the existing entry, then the client SHOULD repeat the request
+ unconditionally, and include
+
+ Cache-Control: max-age=0
+
+ to force any intermediate caches to validate their copies directly
+ with the origin server, or
+
+ Cache-Control: no-cache
+
+ to force any intermediate caches to obtain a new copy from the origin
+ server.
+
+
+
+Fielding, et al. Standards Track [Page 84]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ If the Date values are equal, then the client MAY use either response
+ (or MAY, if it is being extremely prudent, request a new response).
+ Servers MUST NOT depend on clients being able to choose
+ deterministically between responses generated during the same second,
+ if their expiration times overlap.
+
+13.3 Validation Model
+
+ When a cache has a stale entry that it would like to use as a
+ response to a client's request, it first has to check with the origin
+ server (or possibly an intermediate cache with a fresh response) to
+ see if its cached entry is still usable. We call this "validating"
+ the cache entry. Since we do not want to have to pay the overhead of
+ retransmitting the full response if the cached entry is good, and we
+ do not want to pay the overhead of an extra round trip if the cached
+ entry is invalid, the HTTP/1.1 protocol supports the use of
+ conditional methods.
+
+ The key protocol features for supporting conditional methods are
+ those concerned with "cache validators." When an origin server
+ generates a full response, it attaches some sort of validator to it,
+ which is kept with the cache entry. When a client (user agent or
+ proxy cache) makes a conditional request for a resource for which it
+ has a cache entry, it includes the associated validator in the
+ request.
+
+ The server then checks that validator against the current validator
+ for the entity, and, if they match (see section 13.3.3), it responds
+ with a special status code (usually, 304 (Not Modified)) and no
+ entity-body. Otherwise, it returns a full response (including
+ entity-body). Thus, we avoid transmitting the full response if the
+ validator matches, and we avoid an extra round trip if it does not
+ match.
+
+ In HTTP/1.1, a conditional request looks exactly the same as a normal
+ request for the same resource, except that it carries a special
+ header (which includes the validator) that implicitly turns the
+ method (usually, GET) into a conditional.
+
+ The protocol includes both positive and negative senses of cache-
+ validating conditions. That is, it is possible to request either that
+ a method be performed if and only if a validator matches or if and
+ only if no validators match.
+
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 85]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ Note: a response that lacks a validator may still be cached, and
+ served from cache until it expires, unless this is explicitly
+ prohibited by a cache-control directive. However, a cache cannot
+ do a conditional retrieval if it does not have a validator for the
+ entity, which means it will not be refreshable after it expires.
+
+13.3.1 Last-Modified Dates
+
+ The Last-Modified entity-header field value is often used as a cache
+ validator. In simple terms, a cache entry is considered to be valid
+ if the entity has not been modified since the Last-Modified value.
+
+13.3.2 Entity Tag Cache Validators
+
+ The ETag response-header field value, an entity tag, provides for an
+ "opaque" cache validator. This might allow more reliable validation
+ in situations where it is inconvenient to store modification dates,
+ where the one-second resolution of HTTP date values is not
+ sufficient, or where the origin server wishes to avoid certain
+ paradoxes that might arise from the use of modification dates.
+
+ Entity Tags are described in section 3.11. The headers used with
+ entity tags are described in sections 14.19, 14.24, 14.26 and 14.44.
+
+13.3.3 Weak and Strong Validators
+
+ Since both origin servers and caches will compare two validators to
+ decide if they represent the same or different entities, one normally
+ would expect that if the entity (the entity-body or any entity-
+ headers) changes in any way, then the associated validator would
+ change as well. If this is true, then we call this validator a
+ "strong validator."
+
+ However, there might be cases when a server prefers to change the
+ validator only on semantically significant changes, and not when
+ insignificant aspects of the entity change. A validator that does not
+ always change when the resource changes is a "weak validator."
+
+ Entity tags are normally "strong validators," but the protocol
+ provides a mechanism to tag an entity tag as "weak." One can think of
+ a strong validator as one that changes whenever the bits of an entity
+ changes, while a weak value changes whenever the meaning of an entity
+ changes. Alternatively, one can think of a strong validator as part
+ of an identifier for a specific entity, while a weak validator is
+ part of an identifier for a set of semantically equivalent entities.
+
+ Note: One example of a strong validator is an integer that is
+ incremented in stable storage every time an entity is changed.
+
+
+
+Fielding, et al. Standards Track [Page 86]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ An entity's modification time, if represented with one-second
+ resolution, could be a weak validator, since it is possible that
+ the resource might be modified twice during a single second.
+
+ Support for weak validators is optional. However, weak validators
+ allow for more efficient caching of equivalent objects; for
+ example, a hit counter on a site is probably good enough if it is
+ updated every few days or weeks, and any value during that period
+ is likely "good enough" to be equivalent.
+
+ A "use" of a validator is either when a client generates a request
+ and includes the validator in a validating header field, or when a
+ server compares two validators.
+
+ Strong validators are usable in any context. Weak validators are only
+ usable in contexts that do not depend on exact equality of an entity.
+ For example, either kind is usable for a conditional GET of a full
+ entity. However, only a strong validator is usable for a sub-range
+ retrieval, since otherwise the client might end up with an internally
+ inconsistent entity.
+
+ Clients MAY issue simple (non-subrange) GET requests with either weak
+ validators or strong validators. Clients MUST NOT use weak validators
+ in other forms of request.
+
+ The only function that the HTTP/1.1 protocol defines on validators is
+ comparison. There are two validator comparison functions, depending
+ on whether the comparison context allows the use of weak validators
+ or not:
+
+ - The strong comparison function: in order to be considered equal,
+ both validators MUST be identical in every way, and both MUST
+ NOT be weak.
+
+ - The weak comparison function: in order to be considered equal,
+ both validators MUST be identical in every way, but either or
+ both of them MAY be tagged as "weak" without affecting the
+ result.
+
+ An entity tag is strong unless it is explicitly tagged as weak.
+ Section 3.11 gives the syntax for entity tags.
+
+ A Last-Modified time, when used as a validator in a request, is
+ implicitly weak unless it is possible to deduce that it is strong,
+ using the following rules:
+
+ - The validator is being compared by an origin server to the
+ actual current validator for the entity and,
+
+
+
+Fielding, et al. Standards Track [Page 87]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ - That origin server reliably knows that the associated entity did
+ not change twice during the second covered by the presented
+ validator.
+
+ or
+
+ - The validator is about to be used by a client in an If-
+ Modified-Since or If-Unmodified-Since header, because the client
+ has a cache entry for the associated entity, and
+
+ - That cache entry includes a Date value, which gives the time
+ when the origin server sent the original response, and
+
+ - The presented Last-Modified time is at least 60 seconds before
+ the Date value.
+
+ or
+
+ - The validator is being compared by an intermediate cache to the
+ validator stored in its cache entry for the entity, and
+
+ - That cache entry includes a Date value, which gives the time
+ when the origin server sent the original response, and
+
+ - The presented Last-Modified time is at least 60 seconds before
+ the Date value.
+
+ This method relies on the fact that if two different responses were
+ sent by the origin server during the same second, but both had the
+ same Last-Modified time, then at least one of those responses would
+ have a Date value equal to its Last-Modified time. The arbitrary 60-
+ second limit guards against the possibility that the Date and Last-
+ Modified values are generated from different clocks, or at somewhat
+ different times during the preparation of the response. An
+ implementation MAY use a value larger than 60 seconds, if it is
+ believed that 60 seconds is too short.
+
+ If a client wishes to perform a sub-range retrieval on a value for
+ which it has only a Last-Modified time and no opaque validator, it
+ MAY do this only if the Last-Modified time is strong in the sense
+ described here.
+
+ A cache or origin server receiving a conditional request, other than
+ a full-body GET request, MUST use the strong comparison function to
+ evaluate the condition.
+
+ These rules allow HTTP/1.1 caches and clients to safely perform sub-
+ range retrievals on values that have been obtained from HTTP/1.0
+
+
+
+Fielding, et al. Standards Track [Page 88]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ servers.
+
+13.3.4 Rules for When to Use Entity Tags and Last-Modified Dates
+
+ We adopt a set of rules and recommendations for origin servers,
+ clients, and caches regarding when various validator types ought to
+ be used, and for what purposes.
+
+ HTTP/1.1 origin servers:
+
+ - SHOULD send an entity tag validator unless it is not feasible to
+ generate one.
+
+ - MAY send a weak entity tag instead of a strong entity tag, if
+ performance considerations support the use of weak entity tags,
+ or if it is unfeasible to send a strong entity tag.
+
+ - SHOULD send a Last-Modified value if it is feasible to send one,
+ unless the risk of a breakdown in semantic transparency that
+ could result from using this date in an If-Modified-Since header
+ would lead to serious problems.
+
+ In other words, the preferred behavior for an HTTP/1.1 origin server
+ is to send both a strong entity tag and a Last-Modified value.
+
+ In order to be legal, a strong entity tag MUST change whenever the
+ associated entity value changes in any way. A weak entity tag SHOULD
+ change whenever the associated entity changes in a semantically
+ significant way.
+
+ Note: in order to provide semantically transparent caching, an
+ origin server must avoid reusing a specific strong entity tag
+ value for two different entities, or reusing a specific weak
+ entity tag value for two semantically different entities. Cache
+ entries might persist for arbitrarily long periods, regardless of
+ expiration times, so it might be inappropriate to expect that a
+ cache will never again attempt to validate an entry using a
+ validator that it obtained at some point in the past.
+
+ HTTP/1.1 clients:
+
+ - If an entity tag has been provided by the origin server, MUST
+ use that entity tag in any cache-conditional request (using If-
+ Match or If-None-Match).
+
+ - If only a Last-Modified value has been provided by the origin
+ server, SHOULD use that value in non-subrange cache-conditional
+ requests (using If-Modified-Since).
+
+
+
+Fielding, et al. Standards Track [Page 89]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ - If only a Last-Modified value has been provided by an HTTP/1.0
+ origin server, MAY use that value in subrange cache-conditional
+ requests (using If-Unmodified-Since:). The user agent SHOULD
+ provide a way to disable this, in case of difficulty.
+
+ - If both an entity tag and a Last-Modified value have been
+ provided by the origin server, SHOULD use both validators in
+ cache-conditional requests. This allows both HTTP/1.0 and
+ HTTP/1.1 caches to respond appropriately.
+
+ An HTTP/1.1 origin server, upon receiving a conditional request that
+ includes both a Last-Modified date (e.g., in an If-Modified-Since or
+ If-Unmodified-Since header field) and one or more entity tags (e.g.,
+ in an If-Match, If-None-Match, or If-Range header field) as cache
+ validators, MUST NOT return a response status of 304 (Not Modified)
+ unless doing so is consistent with all of the conditional header
+ fields in the request.
+
+ An HTTP/1.1 caching proxy, upon receiving a conditional request that
+ includes both a Last-Modified date and one or more entity tags as
+ cache validators, MUST NOT return a locally cached response to the
+ client unless that cached response is consistent with all of the
+ conditional header fields in the request.
+
+ Note: The general principle behind these rules is that HTTP/1.1
+ servers and clients should transmit as much non-redundant
+ information as is available in their responses and requests.
+ HTTP/1.1 systems receiving this information will make the most
+ conservative assumptions about the validators they receive.
+
+ HTTP/1.0 clients and caches will ignore entity tags. Generally,
+ last-modified values received or used by these systems will
+ support transparent and efficient caching, and so HTTP/1.1 origin
+ servers should provide Last-Modified values. In those rare cases
+ where the use of a Last-Modified value as a validator by an
+ HTTP/1.0 system could result in a serious problem, then HTTP/1.1
+ origin servers should not provide one.
+
+13.3.5 Non-validating Conditionals
+
+ The principle behind entity tags is that only the service author
+ knows the semantics of a resource well enough to select an
+ appropriate cache validation mechanism, and the specification of any
+ validator comparison function more complex than byte-equality would
+ open up a can of worms. Thus, comparisons of any other headers
+ (except Last-Modified, for compatibility with HTTP/1.0) are never
+ used for purposes of validating a cache entry.
+
+
+
+
+Fielding, et al. Standards Track [Page 90]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+13.4 Response Cacheability
+
+ Unless specifically constrained by a cache-control (section 14.9)
+ directive, a caching system MAY always store a successful response
+ (see section 13.8) as a cache entry, MAY return it without validation
+ if it is fresh, and MAY return it after successful validation. If
+ there is neither a cache validator nor an explicit expiration time
+ associated with a response, we do not expect it to be cached, but
+ certain caches MAY violate this expectation (for example, when little
+ or no network connectivity is available). A client can usually detect
+ that such a response was taken from a cache by comparing the Date
+ header to the current time.
+
+ Note: some HTTP/1.0 caches are known to violate this expectation
+ without providing any Warning.
+
+ However, in some cases it might be inappropriate for a cache to
+ retain an entity, or to return it in response to a subsequent
+ request. This might be because absolute semantic transparency is
+ deemed necessary by the service author, or because of security or
+ privacy considerations. Certain cache-control directives are
+ therefore provided so that the server can indicate that certain
+ resource entities, or portions thereof, are not to be cached
+ regardless of other considerations.
+
+ Note that section 14.8 normally prevents a shared cache from saving
+ and returning a response to a previous request if that request
+ included an Authorization header.
+
+ A response received with a status code of 200, 203, 206, 300, 301 or
+ 410 MAY be stored by a cache and used in reply to a subsequent
+ request, subject to the expiration mechanism, unless a cache-control
+ directive prohibits caching. However, a cache that does not support
+ the Range and Content-Range headers MUST NOT cache 206 (Partial
+ Content) responses.
+
+ A response received with any other status code (e.g. status codes 302
+ and 307) MUST NOT be returned in a reply to a subsequent request
+ unless there are cache-control directives or another header(s) that
+ explicitly allow it. For example, these include the following: an
+ Expires header (section 14.21); a "max-age", "s-maxage", "must-
+ revalidate", "proxy-revalidate", "public" or "private" cache-control
+ directive (section 14.9).
+
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 91]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+13.5 Constructing Responses From Caches
+
+ The purpose of an HTTP cache is to store information received in
+ response to requests for use in responding to future requests. In
+ many cases, a cache simply returns the appropriate parts of a
+ response to the requester. However, if the cache holds a cache entry
+ based on a previous response, it might have to combine parts of a new
+ response with what is held in the cache entry.
+
+13.5.1 End-to-end and Hop-by-hop Headers
+
+ For the purpose of defining the behavior of caches and non-caching
+ proxies, we divide HTTP headers into two categories:
+
+ - End-to-end headers, which are transmitted to the ultimate
+ recipient of a request or response. End-to-end headers in
+ responses MUST be stored as part of a cache entry and MUST be
+ transmitted in any response formed from a cache entry.
+
+ - Hop-by-hop headers, which are meaningful only for a single
+ transport-level connection, and are not stored by caches or
+ forwarded by proxies.
+
+ The following HTTP/1.1 headers are hop-by-hop headers:
+
+ - Connection
+ - Keep-Alive
+ - Proxy-Authenticate
+ - Proxy-Authorization
+ - TE
+ - Trailers
+ - Transfer-Encoding
+ - Upgrade
+
+ All other headers defined by HTTP/1.1 are end-to-end headers.
+
+ Other hop-by-hop headers MUST be listed in a Connection header,
+ (section 14.10) to be introduced into HTTP/1.1 (or later).
+
+13.5.2 Non-modifiable Headers
+
+ Some features of the HTTP/1.1 protocol, such as Digest
+ Authentication, depend on the value of certain end-to-end headers. A
+ transparent proxy SHOULD NOT modify an end-to-end header unless the
+ definition of that header requires or specifically allows that.
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 92]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ A transparent proxy MUST NOT modify any of the following fields in a
+ request or response, and it MUST NOT add any of these fields if not
+ already present:
+
+ - Content-Location
+
+ - Content-MD5
+
+ - ETag
+
+ - Last-Modified
+
+ A transparent proxy MUST NOT modify any of the following fields in a
+ response:
+
+ - Expires
+
+ but it MAY add any of these fields if not already present. If an
+ Expires header is added, it MUST be given a field-value identical to
+ that of the Date header in that response.
+
+ A proxy MUST NOT modify or add any of the following fields in a
+ message that contains the no-transform cache-control directive, or in
+ any request:
+
+ - Content-Encoding
+
+ - Content-Range
+
+ - Content-Type
+
+ A non-transparent proxy MAY modify or add these fields to a message
+ that does not include no-transform, but if it does so, it MUST add a
+ Warning 214 (Transformation applied) if one does not already appear
+ in the message (see section 14.46).
+
+ Warning: unnecessary modification of end-to-end headers might
+ cause authentication failures if stronger authentication
+ mechanisms are introduced in later versions of HTTP. Such
+ authentication mechanisms MAY rely on the values of header fields
+ not listed here.
+
+ The Content-Length field of a request or response is added or deleted
+ according to the rules in section 4.4. A transparent proxy MUST
+ preserve the entity-length (section 7.2.2) of the entity-body,
+ although it MAY change the transfer-length (section 4.4).
+
+
+
+
+
+Fielding, et al. Standards Track [Page 93]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+13.5.3 Combining Headers
+
+ When a cache makes a validating request to a server, and the server
+ provides a 304 (Not Modified) response or a 206 (Partial Content)
+ response, the cache then constructs a response to send to the
+ requesting client.
+
+ If the status code is 304 (Not Modified), the cache uses the entity-
+ body stored in the cache entry as the entity-body of this outgoing
+ response. If the status code is 206 (Partial Content) and the ETag or
+ Last-Modified headers match exactly, the cache MAY combine the
+ contents stored in the cache entry with the new contents received in
+ the response and use the result as the entity-body of this outgoing
+ response, (see 13.5.4).
+
+ The end-to-end headers stored in the cache entry are used for the
+ constructed response, except that
+
+ - any stored Warning headers with warn-code 1xx (see section
+ 14.46) MUST be deleted from the cache entry and the forwarded
+ response.
+
+ - any stored Warning headers with warn-code 2xx MUST be retained
+ in the cache entry and the forwarded response.
+
+ - any end-to-end headers provided in the 304 or 206 response MUST
+ replace the corresponding headers from the cache entry.
+
+ Unless the cache decides to remove the cache entry, it MUST also
+ replace the end-to-end headers stored with the cache entry with
+ corresponding headers received in the incoming response, except for
+ Warning headers as described immediately above. If a header field-
+ name in the incoming response matches more than one header in the
+ cache entry, all such old headers MUST be replaced.
+
+ In other words, the set of end-to-end headers received in the
+ incoming response overrides all corresponding end-to-end headers
+ stored with the cache entry (except for stored Warning headers with
+ warn-code 1xx, which are deleted even if not overridden).
+
+ Note: this rule allows an origin server to use a 304 (Not
+ Modified) or a 206 (Partial Content) response to update any header
+ associated with a previous response for the same entity or sub-
+ ranges thereof, although it might not always be meaningful or
+ correct to do so. This rule does not allow an origin server to use
+ a 304 (Not Modified) or a 206 (Partial Content) response to
+ entirely delete a header that it had provided with a previous
+ response.
+
+
+
+Fielding, et al. Standards Track [Page 94]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+13.5.4 Combining Byte Ranges
+
+ A response might transfer only a subrange of the bytes of an entity-
+ body, either because the request included one or more Range
+ specifications, or because a connection was broken prematurely. After
+ several such transfers, a cache might have received several ranges of
+ the same entity-body.
+
+ If a cache has a stored non-empty set of subranges for an entity, and
+ an incoming response transfers another subrange, the cache MAY
+ combine the new subrange with the existing set if both the following
+ conditions are met:
+
+ - Both the incoming response and the cache entry have a cache
+ validator.
+
+ - The two cache validators match using the strong comparison
+ function (see section 13.3.3).
+
+ If either requirement is not met, the cache MUST use only the most
+ recent partial response (based on the Date values transmitted with
+ every response, and using the incoming response if these values are
+ equal or missing), and MUST discard the other partial information.
+
+13.6 Caching Negotiated Responses
+
+ Use of server-driven content negotiation (section 12.1), as indicated
+ by the presence of a Vary header field in a response, alters the
+ conditions and procedure by which a cache can use the response for
+ subsequent requests. See section 14.44 for use of the Vary header
+ field by servers.
+
+ A server SHOULD use the Vary header field to inform a cache of what
+ request-header fields were used to select among multiple
+ representations of a cacheable response subject to server-driven
+ negotiation. The set of header fields named by the Vary field value
+ is known as the "selecting" request-headers.
+
+ When the cache receives a subsequent request whose Request-URI
+ specifies one or more cache entries including a Vary header field,
+ the cache MUST NOT use such a cache entry to construct a response to
+ the new request unless all of the selecting request-headers present
+ in the new request match the corresponding stored request-headers in
+ the original request.
+
+ The selecting request-headers from two requests are defined to match
+ if and only if the selecting request-headers in the first request can
+ be transformed to the selecting request-headers in the second request
+
+
+
+Fielding, et al. Standards Track [Page 95]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ by adding or removing linear white space (LWS) at places where this
+ is allowed by the corresponding BNF, and/or combining multiple
+ message-header fields with the same field name following the rules
+ about message headers in section 4.2.
+
+ A Vary header field-value of "*" always fails to match and subsequent
+ requests on that resource can only be properly interpreted by the
+ origin server.
+
+ If the selecting request header fields for the cached entry do not
+ match the selecting request header fields of the new request, then
+ the cache MUST NOT use a cached entry to satisfy the request unless
+ it first relays the new request to the origin server in a conditional
+ request and the server responds with 304 (Not Modified), including an
+ entity tag or Content-Location that indicates the entity to be used.
+
+ If an entity tag was assigned to a cached representation, the
+ forwarded request SHOULD be conditional and include the entity tags
+ in an If-None-Match header field from all its cache entries for the
+ resource. This conveys to the server the set of entities currently
+ held by the cache, so that if any one of these entities matches the
+ requested entity, the server can use the ETag header field in its 304
+ (Not Modified) response to tell the cache which entry is appropriate.
+ If the entity-tag of the new response matches that of an existing
+ entry, the new response SHOULD be used to update the header fields of
+ the existing entry, and the result MUST be returned to the client.
+
+ If any of the existing cache entries contains only partial content
+ for the associated entity, its entity-tag SHOULD NOT be included in
+ the If-None-Match header field unless the request is for a range that
+ would be fully satisfied by that entry.
+
+ If a cache receives a successful response whose Content-Location
+ field matches that of an existing cache entry for the same Request-
+ ]URI, whose entity-tag differs from that of the existing entry, and
+ whose Date is more recent than that of the existing entry, the
+ existing entry SHOULD NOT be returned in response to future requests
+ and SHOULD be deleted from the cache.
+
+13.7 Shared and Non-Shared Caches
+
+ For reasons of security and privacy, it is necessary to make a
+ distinction between "shared" and "non-shared" caches. A non-shared
+ cache is one that is accessible only to a single user. Accessibility
+ in this case SHOULD be enforced by appropriate security mechanisms.
+ All other caches are considered to be "shared." Other sections of
+
+
+
+
+
+Fielding, et al. Standards Track [Page 96]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ this specification place certain constraints on the operation of
+ shared caches in order to prevent loss of privacy or failure of
+ access controls.
+
+13.8 Errors or Incomplete Response Cache Behavior
+
+ A cache that receives an incomplete response (for example, with fewer
+ bytes of data than specified in a Content-Length header) MAY store
+ the response. However, the cache MUST treat this as a partial
+ response. Partial responses MAY be combined as described in section
+ 13.5.4; the result might be a full response or might still be
+ partial. A cache MUST NOT return a partial response to a client
+ without explicitly marking it as such, using the 206 (Partial
+ Content) status code. A cache MUST NOT return a partial response
+ using a status code of 200 (OK).
+
+ If a cache receives a 5xx response while attempting to revalidate an
+ entry, it MAY either forward this response to the requesting client,
+ or act as if the server failed to respond. In the latter case, it MAY
+ return a previously received response unless the cached entry
+ includes the "must-revalidate" cache-control directive (see section
+ 14.9).
+
+13.9 Side Effects of GET and HEAD
+
+ Unless the origin server explicitly prohibits the caching of their
+ responses, the application of GET and HEAD methods to any resources
+ SHOULD NOT have side effects that would lead to erroneous behavior if
+ these responses are taken from a cache. They MAY still have side
+ effects, but a cache is not required to consider such side effects in
+ its caching decisions. Caches are always expected to observe an
+ origin server's explicit restrictions on caching.
+
+ We note one exception to this rule: since some applications have
+ traditionally used GETs and HEADs with query URLs (those containing a
+ "?" in the rel_path part) to perform operations with significant side
+ effects, caches MUST NOT treat responses to such URIs as fresh unless
+ the server provides an explicit expiration time. This specifically
+ means that responses from HTTP/1.0 servers for such URIs SHOULD NOT
+ be taken from a cache. See section 9.1.1 for related information.
+
+13.10 Invalidation After Updates or Deletions
+
+ The effect of certain methods performed on a resource at the origin
+ server might cause one or more existing cache entries to become non-
+ transparently invalid. That is, although they might continue to be
+ "fresh," they do not accurately reflect what the origin server would
+ return for a new request on that resource.
+
+
+
+Fielding, et al. Standards Track [Page 97]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ There is no way for the HTTP protocol to guarantee that all such
+ cache entries are marked invalid. For example, the request that
+ caused the change at the origin server might not have gone through
+ the proxy where a cache entry is stored. However, several rules help
+ reduce the likelihood of erroneous behavior.
+
+ In this section, the phrase "invalidate an entity" means that the
+ cache will either remove all instances of that entity from its
+ storage, or will mark these as "invalid" and in need of a mandatory
+ revalidation before they can be returned in response to a subsequent
+ request.
+
+ Some HTTP methods MUST cause a cache to invalidate an entity. This is
+ either the entity referred to by the Request-URI, or by the Location
+ or Content-Location headers (if present). These methods are:
+
+ - PUT
+
+ - DELETE
+
+ - POST
+
+ In order to prevent denial of service attacks, an invalidation based
+ on the URI in a Location or Content-Location header MUST only be
+ performed if the host part is the same as in the Request-URI.
+
+ A cache that passes through requests for methods it does not
+ understand SHOULD invalidate any entities referred to by the
+ Request-URI.
+
+13.11 Write-Through Mandatory
+
+ All methods that might be expected to cause modifications to the
+ origin server's resources MUST be written through to the origin
+ server. This currently includes all methods except for GET and HEAD.
+ A cache MUST NOT reply to such a request from a client before having
+ transmitted the request to the inbound server, and having received a
+ corresponding response from the inbound server. This does not prevent
+ a proxy cache from sending a 100 (Continue) response before the
+ inbound server has sent its final reply.
+
+ The alternative (known as "write-back" or "copy-back" caching) is not
+ allowed in HTTP/1.1, due to the difficulty of providing consistent
+ updates and the problems arising from server, cache, or network
+ failure prior to write-back.
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 98]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+13.12 Cache Replacement
+
+ If a new cacheable (see sections 14.9.2, 13.2.5, 13.2.6 and 13.8)
+ response is received from a resource while any existing responses for
+ the same resource are cached, the cache SHOULD use the new response
+ to reply to the current request. It MAY insert it into cache storage
+ and MAY, if it meets all other requirements, use it to respond to any
+ future requests that would previously have caused the old response to
+ be returned. If it inserts the new response into cache storage the
+ rules in section 13.5.3 apply.
+
+ Note: a new response that has an older Date header value than
+ existing cached responses is not cacheable.
+
+13.13 History Lists
+
+ User agents often have history mechanisms, such as "Back" buttons and
+ history lists, which can be used to redisplay an entity retrieved
+ earlier in a session.
+
+ History mechanisms and caches are different. In particular history
+ mechanisms SHOULD NOT try to show a semantically transparent view of
+ the current state of a resource. Rather, a history mechanism is meant
+ to show exactly what the user saw at the time when the resource was
+ retrieved.
+
+ By default, an expiration time does not apply to history mechanisms.
+ If the entity is still in storage, a history mechanism SHOULD display
+ it even if the entity has expired, unless the user has specifically
+ configured the agent to refresh expired history documents.
+
+ This is not to be construed to prohibit the history mechanism from
+ telling the user that a view might be stale.
+
+ Note: if history list mechanisms unnecessarily prevent users from
+ viewing stale resources, this will tend to force service authors
+ to avoid using HTTP expiration controls and cache controls when
+ they would otherwise like to. Service authors may consider it
+ important that users not be presented with error messages or
+ warning messages when they use navigation controls (such as BACK)
+ to view previously fetched resources. Even though sometimes such
+ resources ought not to cached, or ought to expire quickly, user
+ interface considerations may force service authors to resort to
+ other means of preventing caching (e.g. "once-only" URLs) in order
+ not to suffer the effects of improperly functioning history
+ mechanisms.
+
+
+
+
+
+Fielding, et al. Standards Track [Page 99]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+14 Header Field Definitions
+
+ This section defines the syntax and semantics of all standard
+ HTTP/1.1 header fields. For entity-header fields, both sender and
+ recipient refer to either the client or the server, depending on who
+ sends and who receives the entity.
+
+14.1 Accept
+
+ The Accept request-header field can be used to specify certain media
+ types which are acceptable for the response. Accept headers can be
+ used to indicate that the request is specifically limited to a small
+ set of desired types, as in the case of a request for an in-line
+ image.
+
+ Accept = "Accept" ":"
+ #( media-range [ accept-params ] )
+
+ media-range = ( "*/*"
+ | ( type "/" "*" )
+ | ( type "/" subtype )
+ ) *( ";" parameter )
+ accept-params = ";" "q" "=" qvalue *( accept-extension )
+ accept-extension = ";" token [ "=" ( token | quoted-string ) ]
+
+ The asterisk "*" character is used to group media types into ranges,
+ with "*/*" indicating all media types and "type/*" indicating all
+ subtypes of that type. The media-range MAY include media type
+ parameters that are applicable to that range.
+
+ Each media-range MAY be followed by one or more accept-params,
+ beginning with the "q" parameter for indicating a relative quality
+ factor. The first "q" parameter (if any) separates the media-range
+ parameter(s) from the accept-params. Quality factors allow the user
+ or user agent to indicate the relative degree of preference for that
+ media-range, using the qvalue scale from 0 to 1 (section 3.9). The
+ default value is q=1.
+
+ Note: Use of the "q" parameter name to separate media type
+ parameters from Accept extension parameters is due to historical
+ practice. Although this prevents any media type parameter named
+ "q" from being used with a media range, such an event is believed
+ to be unlikely given the lack of any "q" parameters in the IANA
+ media type registry and the rare usage of any media type
+ parameters in Accept. Future media types are discouraged from
+ registering any parameter named "q".
+
+
+
+
+
+Fielding, et al. Standards Track [Page 100]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ The example
+
+ Accept: audio/*; q=0.2, audio/basic
+
+ SHOULD be interpreted as "I prefer audio/basic, but send me any audio
+ type if it is the best available after an 80% mark-down in quality."
+
+ If no Accept header field is present, then it is assumed that the
+ client accepts all media types. If an Accept header field is present,
+ and if the server cannot send a response which is acceptable
+ according to the combined Accept field value, then the server SHOULD
+ send a 406 (not acceptable) response.
+
+ A more elaborate example is
+
+ Accept: text/plain; q=0.5, text/html,
+ text/x-dvi; q=0.8, text/x-c
+
+ Verbally, this would be interpreted as "text/html and text/x-c are
+ the preferred media types, but if they do not exist, then send the
+ text/x-dvi entity, and if that does not exist, send the text/plain
+ entity."
+
+ Media ranges can be overridden by more specific media ranges or
+ specific media types. If more than one media range applies to a given
+ type, the most specific reference has precedence. For example,
+
+ Accept: text/*, text/html, text/html;level=1, */*
+
+ have the following precedence:
+
+ 1) text/html;level=1
+ 2) text/html
+ 3) text/*
+ 4) */*
+
+ The media type quality factor associated with a given type is
+ determined by finding the media range with the highest precedence
+ which matches that type. For example,
+
+ Accept: text/*;q=0.3, text/html;q=0.7, text/html;level=1,
+ text/html;level=2;q=0.4, */*;q=0.5
+
+ would cause the following values to be associated:
+
+ text/html;level=1 = 1
+ text/html = 0.7
+ text/plain = 0.3
+
+
+
+Fielding, et al. Standards Track [Page 101]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ image/jpeg = 0.5
+ text/html;level=2 = 0.4
+ text/html;level=3 = 0.7
+
+ Note: A user agent might be provided with a default set of quality
+ values for certain media ranges. However, unless the user agent is
+ a closed system which cannot interact with other rendering agents,
+ this default set ought to be configurable by the user.
+
+14.2 Accept-Charset
+
+ The Accept-Charset request-header field can be used to indicate what
+ character sets are acceptable for the response. This field allows
+ clients capable of understanding more comprehensive or special-
+ purpose character sets to signal that capability to a server which is
+ capable of representing documents in those character sets.
+
+ Accept-Charset = "Accept-Charset" ":"
+ 1#( ( charset | "*" )[ ";" "q" "=" qvalue ] )
+
+
+ Character set values are described in section 3.4. Each charset MAY
+ be given an associated quality value which represents the user's
+ preference for that charset. The default value is q=1. An example is
+
+ Accept-Charset: iso-8859-5, unicode-1-1;q=0.8
+
+ The special value "*", if present in the Accept-Charset field,
+ matches every character set (including ISO-8859-1) which is not
+ mentioned elsewhere in the Accept-Charset field. If no "*" is present
+ in an Accept-Charset field, then all character sets not explicitly
+ mentioned get a quality value of 0, except for ISO-8859-1, which gets
+ a quality value of 1 if not explicitly mentioned.
+
+ If no Accept-Charset header is present, the default is that any
+ character set is acceptable. If an Accept-Charset header is present,
+ and if the server cannot send a response which is acceptable
+ according to the Accept-Charset header, then the server SHOULD send
+ an error response with the 406 (not acceptable) status code, though
+ the sending of an unacceptable response is also allowed.
+
+14.3 Accept-Encoding
+
+ The Accept-Encoding request-header field is similar to Accept, but
+ restricts the content-codings (section 3.5) that are acceptable in
+ the response.
+
+ Accept-Encoding = "Accept-Encoding" ":"
+
+
+
+Fielding, et al. Standards Track [Page 102]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ 1#( codings [ ";" "q" "=" qvalue ] )
+ codings = ( content-coding | "*" )
+
+ Examples of its use are:
+
+ Accept-Encoding: compress, gzip
+ Accept-Encoding:
+ Accept-Encoding: *
+ Accept-Encoding: compress;q=0.5, gzip;q=1.0
+ Accept-Encoding: gzip;q=1.0, identity; q=0.5, *;q=0
+
+ A server tests whether a content-coding is acceptable, according to
+ an Accept-Encoding field, using these rules:
+
+ 1. If the content-coding is one of the content-codings listed in
+ the Accept-Encoding field, then it is acceptable, unless it is
+ accompanied by a qvalue of 0. (As defined in section 3.9, a
+ qvalue of 0 means "not acceptable.")
+
+ 2. The special "*" symbol in an Accept-Encoding field matches any
+ available content-coding not explicitly listed in the header
+ field.
+
+ 3. If multiple content-codings are acceptable, then the acceptable
+ content-coding with the highest non-zero qvalue is preferred.
+
+ 4. The "identity" content-coding is always acceptable, unless
+ specifically refused because the Accept-Encoding field includes
+ "identity;q=0", or because the field includes "*;q=0" and does
+ not explicitly include the "identity" content-coding. If the
+ Accept-Encoding field-value is empty, then only the "identity"
+ encoding is acceptable.
+
+ If an Accept-Encoding field is present in a request, and if the
+ server cannot send a response which is acceptable according to the
+ Accept-Encoding header, then the server SHOULD send an error response
+ with the 406 (Not Acceptable) status code.
+
+ If no Accept-Encoding field is present in a request, the server MAY
+ assume that the client will accept any content coding. In this case,
+ if "identity" is one of the available content-codings, then the
+ server SHOULD use the "identity" content-coding, unless it has
+ additional information that a different content-coding is meaningful
+ to the client.
+
+ Note: If the request does not include an Accept-Encoding field,
+ and if the "identity" content-coding is unavailable, then
+ content-codings commonly understood by HTTP/1.0 clients (i.e.,
+
+
+
+Fielding, et al. Standards Track [Page 103]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ "gzip" and "compress") are preferred; some older clients
+ improperly display messages sent with other content-codings. The
+ server might also make this decision based on information about
+ the particular user-agent or client.
+
+ Note: Most HTTP/1.0 applications do not recognize or obey qvalues
+ associated with content-codings. This means that qvalues will not
+ work and are not permitted with x-gzip or x-compress.
+
+14.4 Accept-Language
+
+ The Accept-Language request-header field is similar to Accept, but
+ restricts the set of natural languages that are preferred as a
+ response to the request. Language tags are defined in section 3.10.
+
+ Accept-Language = "Accept-Language" ":"
+ 1#( language-range [ ";" "q" "=" qvalue ] )
+ language-range = ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) | "*" )
+
+ Each language-range MAY be given an associated quality value which
+ represents an estimate of the user's preference for the languages
+ specified by that range. The quality value defaults to "q=1". For
+ example,
+
+ Accept-Language: da, en-gb;q=0.8, en;q=0.7
+
+ would mean: "I prefer Danish, but will accept British English and
+ other types of English." A language-range matches a language-tag if
+ it exactly equals the tag, or if it exactly equals a prefix of the
+ tag such that the first tag character following the prefix is "-".
+ The special range "*", if present in the Accept-Language field,
+ matches every tag not matched by any other range present in the
+ Accept-Language field.
+
+ Note: This use of a prefix matching rule does not imply that
+ language tags are assigned to languages in such a way that it is
+ always true that if a user understands a language with a certain
+ tag, then this user will also understand all languages with tags
+ for which this tag is a prefix. The prefix rule simply allows the
+ use of prefix tags if this is the case.
+
+ The language quality factor assigned to a language-tag by the
+ Accept-Language field is the quality value of the longest language-
+ range in the field that matches the language-tag. If no language-
+ range in the field matches the tag, the language quality factor
+ assigned is 0. If no Accept-Language header is present in the
+ request, the server
+
+
+
+
+Fielding, et al. Standards Track [Page 104]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ SHOULD assume that all languages are equally acceptable. If an
+ Accept-Language header is present, then all languages which are
+ assigned a quality factor greater than 0 are acceptable.
+
+ It might be contrary to the privacy expectations of the user to send
+ an Accept-Language header with the complete linguistic preferences of
+ the user in every request. For a discussion of this issue, see
+ section 15.1.4.
+
+ As intelligibility is highly dependent on the individual user, it is
+ recommended that client applications make the choice of linguistic
+ preference available to the user. If the choice is not made
+ available, then the Accept-Language header field MUST NOT be given in
+ the request.
+
+ Note: When making the choice of linguistic preference available to
+ the user, we remind implementors of the fact that users are not
+ familiar with the details of language matching as described above,
+ and should provide appropriate guidance. As an example, users
+ might assume that on selecting "en-gb", they will be served any
+ kind of English document if British English is not available. A
+ user agent might suggest in such a case to add "en" to get the
+ best matching behavior.
+
+14.5 Accept-Ranges
+
+ The Accept-Ranges response-header field allows the server to
+ indicate its acceptance of range requests for a resource:
+
+ Accept-Ranges = "Accept-Ranges" ":" acceptable-ranges
+ acceptable-ranges = 1#range-unit | "none"
+
+ Origin servers that accept byte-range requests MAY send
+
+ Accept-Ranges: bytes
+
+ but are not required to do so. Clients MAY generate byte-range
+ requests without having received this header for the resource
+ involved. Range units are defined in section 3.12.
+
+ Servers that do not accept any kind of range request for a
+ resource MAY send
+
+ Accept-Ranges: none
+
+ to advise the client not to attempt a range request.
+
+
+
+
+
+Fielding, et al. Standards Track [Page 105]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+14.6 Age
+
+ The Age response-header field conveys the sender's estimate of the
+ amount of time since the response (or its revalidation) was
+ generated at the origin server. A cached response is "fresh" if
+ its age does not exceed its freshness lifetime. Age values are
+ calculated as specified in section 13.2.3.
+
+ Age = "Age" ":" age-value
+ age-value = delta-seconds
+
+ Age values are non-negative decimal integers, representing time in
+ seconds.
+
+ If a cache receives a value larger than the largest positive
+ integer it can represent, or if any of its age calculations
+ overflows, it MUST transmit an Age header with a value of
+ 2147483648 (2^31). An HTTP/1.1 server that includes a cache MUST
+ include an Age header field in every response generated from its
+ own cache. Caches SHOULD use an arithmetic type of at least 31
+ bits of range.
+
+14.7 Allow
+
+ The Allow entity-header field lists the set of methods supported
+ by the resource identified by the Request-URI. The purpose of this
+ field is strictly to inform the recipient of valid methods
+ associated with the resource. An Allow header field MUST be
+ present in a 405 (Method Not Allowed) response.
+
+ Allow = "Allow" ":" #Method
+
+ Example of use:
+
+ Allow: GET, HEAD, PUT
+
+ This field cannot prevent a client from trying other methods.
+ However, the indications given by the Allow header field value
+ SHOULD be followed. The actual set of allowed methods is defined
+ by the origin server at the time of each request.
+
+ The Allow header field MAY be provided with a PUT request to
+ recommend the methods to be supported by the new or modified
+ resource. The server is not required to support these methods and
+ SHOULD include an Allow header in the response giving the actual
+ supported methods.
+
+
+
+
+
+Fielding, et al. Standards Track [Page 106]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ A proxy MUST NOT modify the Allow header field even if it does not
+ understand all the methods specified, since the user agent might
+ have other means of communicating with the origin server.
+
+14.8 Authorization
+
+ A user agent that wishes to authenticate itself with a server--
+ usually, but not necessarily, after receiving a 401 response--does
+ so by including an Authorization request-header field with the
+ request. The Authorization field value consists of credentials
+ containing the authentication information of the user agent for
+ the realm of the resource being requested.
+
+ Authorization = "Authorization" ":" credentials
+
+ HTTP access authentication is described in "HTTP Authentication:
+ Basic and Digest Access Authentication" [43]. If a request is
+ authenticated and a realm specified, the same credentials SHOULD
+ be valid for all other requests within this realm (assuming that
+ the authentication scheme itself does not require otherwise, such
+ as credentials that vary according to a challenge value or using
+ synchronized clocks).
+
+ When a shared cache (see section 13.7) receives a request
+ containing an Authorization field, it MUST NOT return the
+ corresponding response as a reply to any other request, unless one
+ of the following specific exceptions holds:
+
+ 1. If the response includes the "s-maxage" cache-control
+ directive, the cache MAY use that response in replying to a
+ subsequent request. But (if the specified maximum age has
+ passed) a proxy cache MUST first revalidate it with the origin
+ server, using the request-headers from the new request to allow
+ the origin server to authenticate the new request. (This is the
+ defined behavior for s-maxage.) If the response includes "s-
+ maxage=0", the proxy MUST always revalidate it before re-using
+ it.
+
+ 2. If the response includes the "must-revalidate" cache-control
+ directive, the cache MAY use that response in replying to a
+ subsequent request. But if the response is stale, all caches
+ MUST first revalidate it with the origin server, using the
+ request-headers from the new request to allow the origin server
+ to authenticate the new request.
+
+ 3. If the response includes the "public" cache-control directive,
+ it MAY be returned in reply to any subsequent request.
+
+
+
+
+Fielding, et al. Standards Track [Page 107]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+14.9 Cache-Control
+
+ The Cache-Control general-header field is used to specify directives
+ that MUST be obeyed by all caching mechanisms along the
+ request/response chain. The directives specify behavior intended to
+ prevent caches from adversely interfering with the request or
+ response. These directives typically override the default caching
+ algorithms. Cache directives are unidirectional in that the presence
+ of a directive in a request does not imply that the same directive is
+ to be given in the response.
+
+ Note that HTTP/1.0 caches might not implement Cache-Control and
+ might only implement Pragma: no-cache (see section 14.32).
+
+ Cache directives MUST be passed through by a proxy or gateway
+ application, regardless of their significance to that application,
+ since the directives might be applicable to all recipients along the
+ request/response chain. It is not possible to specify a cache-
+ directive for a specific cache.
+
+ Cache-Control = "Cache-Control" ":" 1#cache-directive
+
+ cache-directive = cache-request-directive
+ | cache-response-directive
+
+ cache-request-directive =
+ "no-cache" ; Section 14.9.1
+ | "no-store" ; Section 14.9.2
+ | "max-age" "=" delta-seconds ; Section 14.9.3, 14.9.4
+ | "max-stale" [ "=" delta-seconds ] ; Section 14.9.3
+ | "min-fresh" "=" delta-seconds ; Section 14.9.3
+ | "no-transform" ; Section 14.9.5
+ | "only-if-cached" ; Section 14.9.4
+ | cache-extension ; Section 14.9.6
+
+ cache-response-directive =
+ "public" ; Section 14.9.1
+ | "private" [ "=" <"> 1#field-name <"> ] ; Section 14.9.1
+ | "no-cache" [ "=" <"> 1#field-name <"> ]; Section 14.9.1
+ | "no-store" ; Section 14.9.2
+ | "no-transform" ; Section 14.9.5
+ | "must-revalidate" ; Section 14.9.4
+ | "proxy-revalidate" ; Section 14.9.4
+ | "max-age" "=" delta-seconds ; Section 14.9.3
+ | "s-maxage" "=" delta-seconds ; Section 14.9.3
+ | cache-extension ; Section 14.9.6
+
+ cache-extension = token [ "=" ( token | quoted-string ) ]
+
+
+
+Fielding, et al. Standards Track [Page 108]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ When a directive appears without any 1#field-name parameter, the
+ directive applies to the entire request or response. When such a
+ directive appears with a 1#field-name parameter, it applies only to
+ the named field or fields, and not to the rest of the request or
+ response. This mechanism supports extensibility; implementations of
+ future versions of the HTTP protocol might apply these directives to
+ header fields not defined in HTTP/1.1.
+
+ The cache-control directives can be broken down into these general
+ categories:
+
+ - Restrictions on what are cacheable; these may only be imposed by
+ the origin server.
+
+ - Restrictions on what may be stored by a cache; these may be
+ imposed by either the origin server or the user agent.
+
+ - Modifications of the basic expiration mechanism; these may be
+ imposed by either the origin server or the user agent.
+
+ - Controls over cache revalidation and reload; these may only be
+ imposed by a user agent.
+
+ - Control over transformation of entities.
+
+ - Extensions to the caching system.
+
+14.9.1 What is Cacheable
+
+ By default, a response is cacheable if the requirements of the
+ request method, request header fields, and the response status
+ indicate that it is cacheable. Section 13.4 summarizes these defaults
+ for cacheability. The following Cache-Control response directives
+ allow an origin server to override the default cacheability of a
+ response:
+
+ public
+ Indicates that the response MAY be cached by any cache, even if it
+ would normally be non-cacheable or cacheable only within a non-
+ shared cache. (See also Authorization, section 14.8, for
+ additional details.)
+
+ private
+ Indicates that all or part of the response message is intended for
+ a single user and MUST NOT be cached by a shared cache. This
+ allows an origin server to state that the specified parts of the
+
+
+
+
+
+Fielding, et al. Standards Track [Page 109]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ response are intended for only one user and are not a valid
+ response for requests by other users. A private (non-shared) cache
+ MAY cache the response.
+
+ Note: This usage of the word private only controls where the
+ response may be cached, and cannot ensure the privacy of the
+ message content.
+
+ no-cache
+ If the no-cache directive does not specify a field-name, then a
+ cache MUST NOT use the response to satisfy a subsequent request
+ without successful revalidation with the origin server. This
+ allows an origin server to prevent caching even by caches that
+ have been configured to return stale responses to client requests.
+
+ If the no-cache directive does specify one or more field-names,
+ then a cache MAY use the response to satisfy a subsequent request,
+ subject to any other restrictions on caching. However, the
+ specified field-name(s) MUST NOT be sent in the response to a
+ subsequent request without successful revalidation with the origin
+ server. This allows an origin server to prevent the re-use of
+ certain header fields in a response, while still allowing caching
+ of the rest of the response.
+
+ Note: Most HTTP/1.0 caches will not recognize or obey this
+ directive.
+
+14.9.2 What May be Stored by Caches
+
+ no-store
+ The purpose of the no-store directive is to prevent the
+ inadvertent release or retention of sensitive information (for
+ example, on backup tapes). The no-store directive applies to the
+ entire message, and MAY be sent either in a response or in a
+ request. If sent in a request, a cache MUST NOT store any part of
+ either this request or any response to it. If sent in a response,
+ a cache MUST NOT store any part of either this response or the
+ request that elicited it. This directive applies to both non-
+ shared and shared caches. "MUST NOT store" in this context means
+ that the cache MUST NOT intentionally store the information in
+ non-volatile storage, and MUST make a best-effort attempt to
+ remove the information from volatile storage as promptly as
+ possible after forwarding it.
+
+ Even when this directive is associated with a response, users
+ might explicitly store such a response outside of the caching
+ system (e.g., with a "Save As" dialog). History buffers MAY store
+ such responses as part of their normal operation.
+
+
+
+Fielding, et al. Standards Track [Page 110]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ The purpose of this directive is to meet the stated requirements
+ of certain users and service authors who are concerned about
+ accidental releases of information via unanticipated accesses to
+ cache data structures. While the use of this directive might
+ improve privacy in some cases, we caution that it is NOT in any
+ way a reliable or sufficient mechanism for ensuring privacy. In
+ particular, malicious or compromised caches might not recognize or
+ obey this directive, and communications networks might be
+ vulnerable to eavesdropping.
+
+14.9.3 Modifications of the Basic Expiration Mechanism
+
+ The expiration time of an entity MAY be specified by the origin
+ server using the Expires header (see section 14.21). Alternatively,
+ it MAY be specified using the max-age directive in a response. When
+ the max-age cache-control directive is present in a cached response,
+ the response is stale if its current age is greater than the age
+ value given (in seconds) at the time of a new request for that
+ resource. The max-age directive on a response implies that the
+ response is cacheable (i.e., "public") unless some other, more
+ restrictive cache directive is also present.
+
+ If a response includes both an Expires header and a max-age
+ directive, the max-age directive overrides the Expires header, even
+ if the Expires header is more restrictive. This rule allows an origin
+ server to provide, for a given response, a longer expiration time to
+ an HTTP/1.1 (or later) cache than to an HTTP/1.0 cache. This might be
+ useful if certain HTTP/1.0 caches improperly calculate ages or
+ expiration times, perhaps due to desynchronized clocks.
+
+ Many HTTP/1.0 cache implementations will treat an Expires value that
+ is less than or equal to the response Date value as being equivalent
+ to the Cache-Control response directive "no-cache". If an HTTP/1.1
+ cache receives such a response, and the response does not include a
+ Cache-Control header field, it SHOULD consider the response to be
+ non-cacheable in order to retain compatibility with HTTP/1.0 servers.
+
+ Note: An origin server might wish to use a relatively new HTTP
+ cache control feature, such as the "private" directive, on a
+ network including older caches that do not understand that
+ feature. The origin server will need to combine the new feature
+ with an Expires field whose value is less than or equal to the
+ Date value. This will prevent older caches from improperly
+ caching the response.
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 111]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ s-maxage
+ If a response includes an s-maxage directive, then for a shared
+ cache (but not for a private cache), the maximum age specified by
+ this directive overrides the maximum age specified by either the
+ max-age directive or the Expires header. The s-maxage directive
+ also implies the semantics of the proxy-revalidate directive (see
+ section 14.9.4), i.e., that the shared cache must not use the
+ entry after it becomes stale to respond to a subsequent request
+ without first revalidating it with the origin server. The s-
+ maxage directive is always ignored by a private cache.
+
+ Note that most older caches, not compliant with this specification,
+ do not implement any cache-control directives. An origin server
+ wishing to use a cache-control directive that restricts, but does not
+ prevent, caching by an HTTP/1.1-compliant cache MAY exploit the
+ requirement that the max-age directive overrides the Expires header,
+ and the fact that pre-HTTP/1.1-compliant caches do not observe the
+ max-age directive.
+
+ Other directives allow a user agent to modify the basic expiration
+ mechanism. These directives MAY be specified on a request:
+
+ max-age
+ Indicates that the client is willing to accept a response whose
+ age is no greater than the specified time in seconds. Unless max-
+ stale directive is also included, the client is not willing to
+ accept a stale response.
+
+ min-fresh
+ Indicates that the client is willing to accept a response whose
+ freshness lifetime is no less than its current age plus the
+ specified time in seconds. That is, the client wants a response
+ that will still be fresh for at least the specified number of
+ seconds.
+
+ max-stale
+ Indicates that the client is willing to accept a response that has
+ exceeded its expiration time. If max-stale is assigned a value,
+ then the client is willing to accept a response that has exceeded
+ its expiration time by no more than the specified number of
+ seconds. If no value is assigned to max-stale, then the client is
+ willing to accept a stale response of any age.
+
+ If a cache returns a stale response, either because of a max-stale
+ directive on a request, or because the cache is configured to
+ override the expiration time of a response, the cache MUST attach a
+ Warning header to the stale response, using Warning 110 (Response is
+ stale).
+
+
+
+Fielding, et al. Standards Track [Page 112]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ A cache MAY be configured to return stale responses without
+ validation, but only if this does not conflict with any "MUST"-level
+ requirements concerning cache validation (e.g., a "must-revalidate"
+ cache-control directive).
+
+ If both the new request and the cached entry include "max-age"
+ directives, then the lesser of the two values is used for determining
+ the freshness of the cached entry for that request.
+
+14.9.4 Cache Revalidation and Reload Controls
+
+ Sometimes a user agent might want or need to insist that a cache
+ revalidate its cache entry with the origin server (and not just with
+ the next cache along the path to the origin server), or to reload its
+ cache entry from the origin server. End-to-end revalidation might be
+ necessary if either the cache or the origin server has overestimated
+ the expiration time of the cached response. End-to-end reload may be
+ necessary if the cache entry has become corrupted for some reason.
+
+ End-to-end revalidation may be requested either when the client does
+ not have its own local cached copy, in which case we call it
+ "unspecified end-to-end revalidation", or when the client does have a
+ local cached copy, in which case we call it "specific end-to-end
+ revalidation."
+
+ The client can specify these three kinds of action using Cache-
+ Control request directives:
+
+ End-to-end reload
+ The request includes a "no-cache" cache-control directive or, for
+ compatibility with HTTP/1.0 clients, "Pragma: no-cache". Field
+ names MUST NOT be included with the no-cache directive in a
+ request. The server MUST NOT use a cached copy when responding to
+ such a request.
+
+ Specific end-to-end revalidation
+ The request includes a "max-age=0" cache-control directive, which
+ forces each cache along the path to the origin server to
+ revalidate its own entry, if any, with the next cache or server.
+ The initial request includes a cache-validating conditional with
+ the client's current validator.
+
+ Unspecified end-to-end revalidation
+ The request includes "max-age=0" cache-control directive, which
+ forces each cache along the path to the origin server to
+ revalidate its own entry, if any, with the next cache or server.
+ The initial request does not include a cache-validating
+
+
+
+
+Fielding, et al. Standards Track [Page 113]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ conditional; the first cache along the path (if any) that holds a
+ cache entry for this resource includes a cache-validating
+ conditional with its current validator.
+
+ max-age
+ When an intermediate cache is forced, by means of a max-age=0
+ directive, to revalidate its own cache entry, and the client has
+ supplied its own validator in the request, the supplied validator
+ might differ from the validator currently stored with the cache
+ entry. In this case, the cache MAY use either validator in making
+ its own request without affecting semantic transparency.
+
+ However, the choice of validator might affect performance. The
+ best approach is for the intermediate cache to use its own
+ validator when making its request. If the server replies with 304
+ (Not Modified), then the cache can return its now validated copy
+ to the client with a 200 (OK) response. If the server replies with
+ a new entity and cache validator, however, the intermediate cache
+ can compare the returned validator with the one provided in the
+ client's request, using the strong comparison function. If the
+ client's validator is equal to the origin server's, then the
+ intermediate cache simply returns 304 (Not Modified). Otherwise,
+ it returns the new entity with a 200 (OK) response.
+
+ If a request includes the no-cache directive, it SHOULD NOT
+ include min-fresh, max-stale, or max-age.
+
+ only-if-cached
+ In some cases, such as times of extremely poor network
+ connectivity, a client may want a cache to return only those
+ responses that it currently has stored, and not to reload or
+ revalidate with the origin server. To do this, the client may
+ include the only-if-cached directive in a request. If it receives
+ this directive, a cache SHOULD either respond using a cached entry
+ that is consistent with the other constraints of the request, or
+ respond with a 504 (Gateway Timeout) status. However, if a group
+ of caches is being operated as a unified system with good internal
+ connectivity, such a request MAY be forwarded within that group of
+ caches.
+
+ must-revalidate
+ Because a cache MAY be configured to ignore a server's specified
+ expiration time, and because a client request MAY include a max-
+ stale directive (which has a similar effect), the protocol also
+ includes a mechanism for the origin server to require revalidation
+ of a cache entry on any subsequent use. When the must-revalidate
+ directive is present in a response received by a cache, that cache
+ MUST NOT use the entry after it becomes stale to respond to a
+
+
+
+Fielding, et al. Standards Track [Page 114]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ subsequent request without first revalidating it with the origin
+ server. (I.e., the cache MUST do an end-to-end revalidation every
+ time, if, based solely on the origin server's Expires or max-age
+ value, the cached response is stale.)
+
+ The must-revalidate directive is necessary to support reliable
+ operation for certain protocol features. In all circumstances an
+ HTTP/1.1 cache MUST obey the must-revalidate directive; in
+ particular, if the cache cannot reach the origin server for any
+ reason, it MUST generate a 504 (Gateway Timeout) response.
+
+ Servers SHOULD send the must-revalidate directive if and only if
+ failure to revalidate a request on the entity could result in
+ incorrect operation, such as a silently unexecuted financial
+ transaction. Recipients MUST NOT take any automated action that
+ violates this directive, and MUST NOT automatically provide an
+ unvalidated copy of the entity if revalidation fails.
+
+ Although this is not recommended, user agents operating under
+ severe connectivity constraints MAY violate this directive but, if
+ so, MUST explicitly warn the user that an unvalidated response has
+ been provided. The warning MUST be provided on each unvalidated
+ access, and SHOULD require explicit user confirmation.
+
+ proxy-revalidate
+ The proxy-revalidate directive has the same meaning as the must-
+ revalidate directive, except that it does not apply to non-shared
+ user agent caches. It can be used on a response to an
+ authenticated request to permit the user's cache to store and
+ later return the response without needing to revalidate it (since
+ it has already been authenticated once by that user), while still
+ requiring proxies that service many users to revalidate each time
+ (in order to make sure that each user has been authenticated).
+ Note that such authenticated responses also need the public cache
+ control directive in order to allow them to be cached at all.
+
+14.9.5 No-Transform Directive
+
+ no-transform
+ Implementors of intermediate caches (proxies) have found it useful
+ to convert the media type of certain entity bodies. A non-
+ transparent proxy might, for example, convert between image
+ formats in order to save cache space or to reduce the amount of
+ traffic on a slow link.
+
+ Serious operational problems occur, however, when these
+ transformations are applied to entity bodies intended for certain
+ kinds of applications. For example, applications for medical
+
+
+
+Fielding, et al. Standards Track [Page 115]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ imaging, scientific data analysis and those using end-to-end
+ authentication, all depend on receiving an entity body that is bit
+ for bit identical to the original entity-body.
+
+ Therefore, if a message includes the no-transform directive, an
+ intermediate cache or proxy MUST NOT change those headers that are
+ listed in section 13.5.2 as being subject to the no-transform
+ directive. This implies that the cache or proxy MUST NOT change
+ any aspect of the entity-body that is specified by these headers,
+ including the value of the entity-body itself.
+
+14.9.6 Cache Control Extensions
+
+ The Cache-Control header field can be extended through the use of one
+ or more cache-extension tokens, each with an optional assigned value.
+ Informational extensions (those which do not require a change in
+ cache behavior) MAY be added without changing the semantics of other
+ directives. Behavioral extensions are designed to work by acting as
+ modifiers to the existing base of cache directives. Both the new
+ directive and the standard directive are supplied, such that
+ applications which do not understand the new directive will default
+ to the behavior specified by the standard directive, and those that
+ understand the new directive will recognize it as modifying the
+ requirements associated with the standard directive. In this way,
+ extensions to the cache-control directives can be made without
+ requiring changes to the base protocol.
+
+ This extension mechanism depends on an HTTP cache obeying all of the
+ cache-control directives defined for its native HTTP-version, obeying
+ certain extensions, and ignoring all directives that it does not
+ understand.
+
+ For example, consider a hypothetical new response directive called
+ community which acts as a modifier to the private directive. We
+ define this new directive to mean that, in addition to any non-shared
+ cache, any cache which is shared only by members of the community
+ named within its value may cache the response. An origin server
+ wishing to allow the UCI community to use an otherwise private
+ response in their shared cache(s) could do so by including
+
+ Cache-Control: private, community="UCI"
+
+ A cache seeing this header field will act correctly even if the cache
+ does not understand the community cache-extension, since it will also
+ see and understand the private directive and thus default to the safe
+ behavior.
+
+
+
+
+
+Fielding, et al. Standards Track [Page 116]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ Unrecognized cache-directives MUST be ignored; it is assumed that any
+ cache-directive likely to be unrecognized by an HTTP/1.1 cache will
+ be combined with standard directives (or the response's default
+ cacheability) such that the cache behavior will remain minimally
+ correct even if the cache does not understand the extension(s).
+
+14.10 Connection
+
+ The Connection general-header field allows the sender to specify
+ options that are desired for that particular connection and MUST NOT
+ be communicated by proxies over further connections.
+
+ The Connection header has the following grammar:
+
+ Connection = "Connection" ":" 1#(connection-token)
+ connection-token = token
+
+ HTTP/1.1 proxies MUST parse the Connection header field before a
+ message is forwarded and, for each connection-token in this field,
+ remove any header field(s) from the message with the same name as the
+ connection-token. Connection options are signaled by the presence of
+ a connection-token in the Connection header field, not by any
+ corresponding additional header field(s), since the additional header
+ field may not be sent if there are no parameters associated with that
+ connection option.
+
+ Message headers listed in the Connection header MUST NOT include
+ end-to-end headers, such as Cache-Control.
+
+ HTTP/1.1 defines the "close" connection option for the sender to
+ signal that the connection will be closed after completion of the
+ response. For example,
+
+ Connection: close
+
+ in either the request or the response header fields indicates that
+ the connection SHOULD NOT be considered `persistent' (section 8.1)
+ after the current request/response is complete.
+
+ HTTP/1.1 applications that do not support persistent connections MUST
+ include the "close" connection option in every message.
+
+ A system receiving an HTTP/1.0 (or lower-version) message that
+ includes a Connection header MUST, for each connection-token in this
+ field, remove and ignore any header field(s) from the message with
+ the same name as the connection-token. This protects against mistaken
+ forwarding of such header fields by pre-HTTP/1.1 proxies. See section
+ 19.6.2.
+
+
+
+Fielding, et al. Standards Track [Page 117]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+14.11 Content-Encoding
+
+ The Content-Encoding entity-header field is used as a modifier to the
+ media-type. When present, its value indicates what additional content
+ codings have been applied to the entity-body, and thus what decoding
+ mechanisms must be applied in order to obtain the media-type
+ referenced by the Content-Type header field. Content-Encoding is
+ primarily used to allow a document to be compressed without losing
+ the identity of its underlying media type.
+
+ Content-Encoding = "Content-Encoding" ":" 1#content-coding
+
+ Content codings are defined in section 3.5. An example of its use is
+
+ Content-Encoding: gzip
+
+ The content-coding is a characteristic of the entity identified by
+ the Request-URI. Typically, the entity-body is stored with this
+ encoding and is only decoded before rendering or analogous usage.
+ However, a non-transparent proxy MAY modify the content-coding if the
+ new coding is known to be acceptable to the recipient, unless the
+ "no-transform" cache-control directive is present in the message.
+
+ If the content-coding of an entity is not "identity", then the
+ response MUST include a Content-Encoding entity-header (section
+ 14.11) that lists the non-identity content-coding(s) used.
+
+ If the content-coding of an entity in a request message is not
+ acceptable to the origin server, the server SHOULD respond with a
+ status code of 415 (Unsupported Media Type).
+
+ If multiple encodings have been applied to an entity, the content
+ codings MUST be listed in the order in which they were applied.
+ Additional information about the encoding parameters MAY be provided
+ by other entity-header fields not defined by this specification.
+
+14.12 Content-Language
+
+ The Content-Language entity-header field describes the natural
+ language(s) of the intended audience for the enclosed entity. Note
+ that this might not be equivalent to all the languages used within
+ the entity-body.
+
+ Content-Language = "Content-Language" ":" 1#language-tag
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 118]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ Language tags are defined in section 3.10. The primary purpose of
+ Content-Language is to allow a user to identify and differentiate
+ entities according to the user's own preferred language. Thus, if the
+ body content is intended only for a Danish-literate audience, the
+ appropriate field is
+
+ Content-Language: da
+
+ If no Content-Language is specified, the default is that the content
+ is intended for all language audiences. This might mean that the
+ sender does not consider it to be specific to any natural language,
+ or that the sender does not know for which language it is intended.
+
+ Multiple languages MAY be listed for content that is intended for
+ multiple audiences. For example, a rendition of the "Treaty of
+ Waitangi," presented simultaneously in the original Maori and English
+ versions, would call for
+
+ Content-Language: mi, en
+
+ However, just because multiple languages are present within an entity
+ does not mean that it is intended for multiple linguistic audiences.
+ An example would be a beginner's language primer, such as "A First
+ Lesson in Latin," which is clearly intended to be used by an
+ English-literate audience. In this case, the Content-Language would
+ properly only include "en".
+
+ Content-Language MAY be applied to any media type -- it is not
+ limited to textual documents.
+
+14.13 Content-Length
+
+ The Content-Length entity-header field indicates the size of the
+ entity-body, in decimal number of OCTETs, sent to the recipient or,
+ in the case of the HEAD method, the size of the entity-body that
+ would have been sent had the request been a GET.
+
+ Content-Length = "Content-Length" ":" 1*DIGIT
+
+ An example is
+
+ Content-Length: 3495
+
+ Applications SHOULD use this field to indicate the transfer-length of
+ the message-body, unless this is prohibited by the rules in section
+ 4.4.
+
+
+
+
+
+Fielding, et al. Standards Track [Page 119]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ Any Content-Length greater than or equal to zero is a valid value.
+ Section 4.4 describes how to determine the length of a message-body
+ if a Content-Length is not given.
+
+ Note that the meaning of this field is significantly different from
+ the corresponding definition in MIME, where it is an optional field
+ used within the "message/external-body" content-type. In HTTP, it
+ SHOULD be sent whenever the message's length can be determined prior
+ to being transferred, unless this is prohibited by the rules in
+ section 4.4.
+
+14.14 Content-Location
+
+ The Content-Location entity-header field MAY be used to supply the
+ resource location for the entity enclosed in the message when that
+ entity is accessible from a location separate from the requested
+ resource's URI. A server SHOULD provide a Content-Location for the
+ variant corresponding to the response entity; especially in the case
+ where a resource has multiple entities associated with it, and those
+ entities actually have separate locations by which they might be
+ individually accessed, the server SHOULD provide a Content-Location
+ for the particular variant which is returned.
+
+ Content-Location = "Content-Location" ":"
+ ( absoluteURI | relativeURI )
+
+ The value of Content-Location also defines the base URI for the
+ entity.
+
+ The Content-Location value is not a replacement for the original
+ requested URI; it is only a statement of the location of the resource
+ corresponding to this particular entity at the time of the request.
+ Future requests MAY specify the Content-Location URI as the request-
+ URI if the desire is to identify the source of that particular
+ entity.
+
+ A cache cannot assume that an entity with a Content-Location
+ different from the URI used to retrieve it can be used to respond to
+ later requests on that Content-Location URI. However, the Content-
+ Location can be used to differentiate between multiple entities
+ retrieved from a single requested resource, as described in section
+ 13.6.
+
+ If the Content-Location is a relative URI, the relative URI is
+ interpreted relative to the Request-URI.
+
+ The meaning of the Content-Location header in PUT or POST requests is
+ undefined; servers are free to ignore it in those cases.
+
+
+
+Fielding, et al. Standards Track [Page 120]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+14.15 Content-MD5
+
+ The Content-MD5 entity-header field, as defined in RFC 1864 [23], is
+ an MD5 digest of the entity-body for the purpose of providing an
+ end-to-end message integrity check (MIC) of the entity-body. (Note: a
+ MIC is good for detecting accidental modification of the entity-body
+ in transit, but is not proof against malicious attacks.)
+
+ Content-MD5 = "Content-MD5" ":" md5-digest
+ md5-digest = <base64 of 128 bit MD5 digest as per RFC 1864>
+
+ The Content-MD5 header field MAY be generated by an origin server or
+ client to function as an integrity check of the entity-body. Only
+ origin servers or clients MAY generate the Content-MD5 header field;
+ proxies and gateways MUST NOT generate it, as this would defeat its
+ value as an end-to-end integrity check. Any recipient of the entity-
+ body, including gateways and proxies, MAY check that the digest value
+ in this header field matches that of the entity-body as received.
+
+ The MD5 digest is computed based on the content of the entity-body,
+ including any content-coding that has been applied, but not including
+ any transfer-encoding applied to the message-body. If the message is
+ received with a transfer-encoding, that encoding MUST be removed
+ prior to checking the Content-MD5 value against the received entity.
+
+ This has the result that the digest is computed on the octets of the
+ entity-body exactly as, and in the order that, they would be sent if
+ no transfer-encoding were being applied.
+
+ HTTP extends RFC 1864 to permit the digest to be computed for MIME
+ composite media-types (e.g., multipart/* and message/rfc822), but
+ this does not change how the digest is computed as defined in the
+ preceding paragraph.
+
+ There are several consequences of this. The entity-body for composite
+ types MAY contain many body-parts, each with its own MIME and HTTP
+ headers (including Content-MD5, Content-Transfer-Encoding, and
+ Content-Encoding headers). If a body-part has a Content-Transfer-
+ Encoding or Content-Encoding header, it is assumed that the content
+ of the body-part has had the encoding applied, and the body-part is
+ included in the Content-MD5 digest as is -- i.e., after the
+ application. The Transfer-Encoding header field is not allowed within
+ body-parts.
+
+ Conversion of all line breaks to CRLF MUST NOT be done before
+ computing or checking the digest: the line break convention used in
+ the text actually transmitted MUST be left unaltered when computing
+ the digest.
+
+
+
+Fielding, et al. Standards Track [Page 121]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ Note: while the definition of Content-MD5 is exactly the same for
+ HTTP as in RFC 1864 for MIME entity-bodies, there are several ways
+ in which the application of Content-MD5 to HTTP entity-bodies
+ differs from its application to MIME entity-bodies. One is that
+ HTTP, unlike MIME, does not use Content-Transfer-Encoding, and
+ does use Transfer-Encoding and Content-Encoding. Another is that
+ HTTP more frequently uses binary content types than MIME, so it is
+ worth noting that, in such cases, the byte order used to compute
+ the digest is the transmission byte order defined for the type.
+ Lastly, HTTP allows transmission of text types with any of several
+ line break conventions and not just the canonical form using CRLF.
+
+14.16 Content-Range
+
+ The Content-Range entity-header is sent with a partial entity-body to
+ specify where in the full entity-body the partial body should be
+ applied. Range units are defined in section 3.12.
+
+ Content-Range = "Content-Range" ":" content-range-spec
+
+ content-range-spec = byte-content-range-spec
+ byte-content-range-spec = bytes-unit SP
+ byte-range-resp-spec "/"
+ ( instance-length | "*" )
+
+ byte-range-resp-spec = (first-byte-pos "-" last-byte-pos)
+ | "*"
+ instance-length = 1*DIGIT
+
+ The header SHOULD indicate the total length of the full entity-body,
+ unless this length is unknown or difficult to determine. The asterisk
+ "*" character means that the instance-length is unknown at the time
+ when the response was generated.
+
+ Unlike byte-ranges-specifier values (see section 14.35.1), a byte-
+ range-resp-spec MUST only specify one range, and MUST contain
+ absolute byte positions for both the first and last byte of the
+ range.
+
+ A byte-content-range-spec with a byte-range-resp-spec whose last-
+ byte-pos value is less than its first-byte-pos value, or whose
+ instance-length value is less than or equal to its last-byte-pos
+ value, is invalid. The recipient of an invalid byte-content-range-
+ spec MUST ignore it and any content transferred along with it.
+
+ A server sending a response with status code 416 (Requested range not
+ satisfiable) SHOULD include a Content-Range field with a byte-range-
+ resp-spec of "*". The instance-length specifies the current length of
+
+
+
+Fielding, et al. Standards Track [Page 122]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ the selected resource. A response with status code 206 (Partial
+ Content) MUST NOT include a Content-Range field with a byte-range-
+ resp-spec of "*".
+
+ Examples of byte-content-range-spec values, assuming that the entity
+ contains a total of 1234 bytes:
+
+ . The first 500 bytes:
+ bytes 0-499/1234
+
+ . The second 500 bytes:
+ bytes 500-999/1234
+
+ . All except for the first 500 bytes:
+ bytes 500-1233/1234
+
+ . The last 500 bytes:
+ bytes 734-1233/1234
+
+ When an HTTP message includes the content of a single range (for
+ example, a response to a request for a single range, or to a request
+ for a set of ranges that overlap without any holes), this content is
+ transmitted with a Content-Range header, and a Content-Length header
+ showing the number of bytes actually transferred. For example,
+
+ HTTP/1.1 206 Partial content
+ Date: Wed, 15 Nov 1995 06:25:24 GMT
+ Last-Modified: Wed, 15 Nov 1995 04:58:08 GMT
+ Content-Range: bytes 21010-47021/47022
+ Content-Length: 26012
+ Content-Type: image/gif
+
+ When an HTTP message includes the content of multiple ranges (for
+ example, a response to a request for multiple non-overlapping
+ ranges), these are transmitted as a multipart message. The multipart
+ media type used for this purpose is "multipart/byteranges" as defined
+ in appendix 19.2. See appendix 19.6.3 for a compatibility issue.
+
+ A response to a request for a single range MUST NOT be sent using the
+ multipart/byteranges media type. A response to a request for
+ multiple ranges, whose result is a single range, MAY be sent as a
+ multipart/byteranges media type with one part. A client that cannot
+ decode a multipart/byteranges message MUST NOT ask for multiple
+ byte-ranges in a single request.
+
+ When a client requests multiple byte-ranges in one request, the
+ server SHOULD return them in the order that they appeared in the
+ request.
+
+
+
+Fielding, et al. Standards Track [Page 123]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ If the server ignores a byte-range-spec because it is syntactically
+ invalid, the server SHOULD treat the request as if the invalid Range
+ header field did not exist. (Normally, this means return a 200
+ response containing the full entity).
+
+ If the server receives a request (other than one including an If-
+ Range request-header field) with an unsatisfiable Range request-
+ header field (that is, all of whose byte-range-spec values have a
+ first-byte-pos value greater than the current length of the selected
+ resource), it SHOULD return a response code of 416 (Requested range
+ not satisfiable) (section 10.4.17).
+
+ Note: clients cannot depend on servers to send a 416 (Requested
+ range not satisfiable) response instead of a 200 (OK) response for
+ an unsatisfiable Range request-header, since not all servers
+ implement this request-header.
+
+14.17 Content-Type
+
+ The Content-Type entity-header field indicates the media type of the
+ entity-body sent to the recipient or, in the case of the HEAD method,
+ the media type that would have been sent had the request been a GET.
+
+ Content-Type = "Content-Type" ":" media-type
+
+ Media types are defined in section 3.7. An example of the field is
+
+ Content-Type: text/html; charset=ISO-8859-4
+
+ Further discussion of methods for identifying the media type of an
+ entity is provided in section 7.2.1.
+
+14.18 Date
+
+ The Date general-header field represents the date and time at which
+ the message was originated, having the same semantics as orig-date in
+ RFC 822. The field value is an HTTP-date, as described in section
+ 3.3.1; it MUST be sent in RFC 1123 [8]-date format.
+
+ Date = "Date" ":" HTTP-date
+
+ An example is
+
+ Date: Tue, 15 Nov 1994 08:12:31 GMT
+
+ Origin servers MUST include a Date header field in all responses,
+ except in these cases:
+
+
+
+
+Fielding, et al. Standards Track [Page 124]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ 1. If the response status code is 100 (Continue) or 101 (Switching
+ Protocols), the response MAY include a Date header field, at
+ the server's option.
+
+ 2. If the response status code conveys a server error, e.g. 500
+ (Internal Server Error) or 503 (Service Unavailable), and it is
+ inconvenient or impossible to generate a valid Date.
+
+ 3. If the server does not have a clock that can provide a
+ reasonable approximation of the current time, its responses
+ MUST NOT include a Date header field. In this case, the rules
+ in section 14.18.1 MUST be followed.
+
+ A received message that does not have a Date header field MUST be
+ assigned one by the recipient if the message will be cached by that
+ recipient or gatewayed via a protocol which requires a Date. An HTTP
+ implementation without a clock MUST NOT cache responses without
+ revalidating them on every use. An HTTP cache, especially a shared
+ cache, SHOULD use a mechanism, such as NTP [28], to synchronize its
+ clock with a reliable external standard.
+
+ Clients SHOULD only send a Date header field in messages that include
+ an entity-body, as in the case of the PUT and POST requests, and even
+ then it is optional. A client without a clock MUST NOT send a Date
+ header field in a request.
+
+ The HTTP-date sent in a Date header SHOULD NOT represent a date and
+ time subsequent to the generation of the message. It SHOULD represent
+ the best available approximation of the date and time of message
+ generation, unless the implementation has no means of generating a
+ reasonably accurate date and time. In theory, the date ought to
+ represent the moment just before the entity is generated. In
+ practice, the date can be generated at any time during the message
+ origination without affecting its semantic value.
+
+14.18.1 Clockless Origin Server Operation
+
+ Some origin server implementations might not have a clock available.
+ An origin server without a clock MUST NOT assign Expires or Last-
+ Modified values to a response, unless these values were associated
+ with the resource by a system or user with a reliable clock. It MAY
+ assign an Expires value that is known, at or before server
+ configuration time, to be in the past (this allows "pre-expiration"
+ of responses without storing separate Expires values for each
+ resource).
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 125]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+14.19 ETag
+
+ The ETag response-header field provides the current value of the
+ entity tag for the requested variant. The headers used with entity
+ tags are described in sections 14.24, 14.26 and 14.44. The entity tag
+ MAY be used for comparison with other entities from the same resource
+ (see section 13.3.3).
+
+ ETag = "ETag" ":" entity-tag
+
+ Examples:
+
+ ETag: "xyzzy"
+ ETag: W/"xyzzy"
+ ETag: ""
+
+14.20 Expect
+
+ The Expect request-header field is used to indicate that particular
+ server behaviors are required by the client.
+
+ Expect = "Expect" ":" 1#expectation
+
+ expectation = "100-continue" | expectation-extension
+ expectation-extension = token [ "=" ( token | quoted-string )
+ *expect-params ]
+ expect-params = ";" token [ "=" ( token | quoted-string ) ]
+
+
+ A server that does not understand or is unable to comply with any of
+ the expectation values in the Expect field of a request MUST respond
+ with appropriate error status. The server MUST respond with a 417
+ (Expectation Failed) status if any of the expectations cannot be met
+ or, if there are other problems with the request, some other 4xx
+ status.
+
+ This header field is defined with extensible syntax to allow for
+ future extensions. If a server receives a request containing an
+ Expect field that includes an expectation-extension that it does not
+ support, it MUST respond with a 417 (Expectation Failed) status.
+
+ Comparison of expectation values is case-insensitive for unquoted
+ tokens (including the 100-continue token), and is case-sensitive for
+ quoted-string expectation-extensions.
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 126]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ The Expect mechanism is hop-by-hop: that is, an HTTP/1.1 proxy MUST
+ return a 417 (Expectation Failed) status if it receives a request
+ with an expectation that it cannot meet. However, the Expect
+ request-header itself is end-to-end; it MUST be forwarded if the
+ request is forwarded.
+
+ Many older HTTP/1.0 and HTTP/1.1 applications do not understand the
+ Expect header.
+
+ See section 8.2.3 for the use of the 100 (continue) status.
+
+14.21 Expires
+
+ The Expires entity-header field gives the date/time after which the
+ response is considered stale. A stale cache entry may not normally be
+ returned by a cache (either a proxy cache or a user agent cache)
+ unless it is first validated with the origin server (or with an
+ intermediate cache that has a fresh copy of the entity). See section
+ 13.2 for further discussion of the expiration model.
+
+ The presence of an Expires field does not imply that the original
+ resource will change or cease to exist at, before, or after that
+ time.
+
+ The format is an absolute date and time as defined by HTTP-date in
+ section 3.3.1; it MUST be in RFC 1123 date format:
+
+ Expires = "Expires" ":" HTTP-date
+
+ An example of its use is
+
+ Expires: Thu, 01 Dec 1994 16:00:00 GMT
+
+ Note: if a response includes a Cache-Control field with the max-
+ age directive (see section 14.9.3), that directive overrides the
+ Expires field.
+
+ HTTP/1.1 clients and caches MUST treat other invalid date formats,
+ especially including the value "0", as in the past (i.e., "already
+ expired").
+
+ To mark a response as "already expired," an origin server sends an
+ Expires date that is equal to the Date header value. (See the rules
+ for expiration calculations in section 13.2.4.)
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 127]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ To mark a response as "never expires," an origin server sends an
+ Expires date approximately one year from the time the response is
+ sent. HTTP/1.1 servers SHOULD NOT send Expires dates more than one
+ year in the future.
+
+ The presence of an Expires header field with a date value of some
+ time in the future on a response that otherwise would by default be
+ non-cacheable indicates that the response is cacheable, unless
+ indicated otherwise by a Cache-Control header field (section 14.9).
+
+14.22 From
+
+ The From request-header field, if given, SHOULD contain an Internet
+ e-mail address for the human user who controls the requesting user
+ agent. The address SHOULD be machine-usable, as defined by "mailbox"
+ in RFC 822 [9] as updated by RFC 1123 [8]:
+
+ From = "From" ":" mailbox
+
+ An example is:
+
+ From: webmaster@w3.org
+
+ This header field MAY be used for logging purposes and as a means for
+ identifying the source of invalid or unwanted requests. It SHOULD NOT
+ be used as an insecure form of access protection. The interpretation
+ of this field is that the request is being performed on behalf of the
+ person given, who accepts responsibility for the method performed. In
+ particular, robot agents SHOULD include this header so that the
+ person responsible for running the robot can be contacted if problems
+ occur on the receiving end.
+
+ The Internet e-mail address in this field MAY be separate from the
+ Internet host which issued the request. For example, when a request
+ is passed through a proxy the original issuer's address SHOULD be
+ used.
+
+ The client SHOULD NOT send the From header field without the user's
+ approval, as it might conflict with the user's privacy interests or
+ their site's security policy. It is strongly recommended that the
+ user be able to disable, enable, and modify the value of this field
+ at any time prior to a request.
+
+14.23 Host
+
+ The Host request-header field specifies the Internet host and port
+ number of the resource being requested, as obtained from the original
+ URI given by the user or referring resource (generally an HTTP URL,
+
+
+
+Fielding, et al. Standards Track [Page 128]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ as described in section 3.2.2). The Host field value MUST represent
+ the naming authority of the origin server or gateway given by the
+ original URL. This allows the origin server or gateway to
+ differentiate between internally-ambiguous URLs, such as the root "/"
+ URL of a server for multiple host names on a single IP address.
+
+ Host = "Host" ":" host [ ":" port ] ; Section 3.2.2
+
+ A "host" without any trailing port information implies the default
+ port for the service requested (e.g., "80" for an HTTP URL). For
+ example, a request on the origin server for
+ <http://www.w3.org/pub/WWW/> would properly include:
+
+ GET /pub/WWW/ HTTP/1.1
+ Host: www.w3.org
+
+ A client MUST include a Host header field in all HTTP/1.1 request
+ messages . If the requested URI does not include an Internet host
+ name for the service being requested, then the Host header field MUST
+ be given with an empty value. An HTTP/1.1 proxy MUST ensure that any
+ request message it forwards does contain an appropriate Host header
+ field that identifies the service being requested by the proxy. All
+ Internet-based HTTP/1.1 servers MUST respond with a 400 (Bad Request)
+ status code to any HTTP/1.1 request message which lacks a Host header
+ field.
+
+ See sections 5.2 and 19.6.1.1 for other requirements relating to
+ Host.
+
+14.24 If-Match
+
+ The If-Match request-header field is used with a method to make it
+ conditional. A client that has one or more entities previously
+ obtained from the resource can verify that one of those entities is
+ current by including a list of their associated entity tags in the
+ If-Match header field. Entity tags are defined in section 3.11. The
+ purpose of this feature is to allow efficient updates of cached
+ information with a minimum amount of transaction overhead. It is also
+ used, on updating requests, to prevent inadvertent modification of
+ the wrong version of a resource. As a special case, the value "*"
+ matches any current entity of the resource.
+
+ If-Match = "If-Match" ":" ( "*" | 1#entity-tag )
+
+ If any of the entity tags match the entity tag of the entity that
+ would have been returned in the response to a similar GET request
+ (without the If-Match header) on that resource, or if "*" is given
+
+
+
+
+Fielding, et al. Standards Track [Page 129]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ and any current entity exists for that resource, then the server MAY
+ perform the requested method as if the If-Match header field did not
+ exist.
+
+ A server MUST use the strong comparison function (see section 13.3.3)
+ to compare the entity tags in If-Match.
+
+ If none of the entity tags match, or if "*" is given and no current
+ entity exists, the server MUST NOT perform the requested method, and
+ MUST return a 412 (Precondition Failed) response. This behavior is
+ most useful when the client wants to prevent an updating method, such
+ as PUT, from modifying a resource that has changed since the client
+ last retrieved it.
+
+ If the request would, without the If-Match header field, result in
+ anything other than a 2xx or 412 status, then the If-Match header
+ MUST be ignored.
+
+ The meaning of "If-Match: *" is that the method SHOULD be performed
+ if the representation selected by the origin server (or by a cache,
+ possibly using the Vary mechanism, see section 14.44) exists, and
+ MUST NOT be performed if the representation does not exist.
+
+ A request intended to update a resource (e.g., a PUT) MAY include an
+ If-Match header field to signal that the request method MUST NOT be
+ applied if the entity corresponding to the If-Match value (a single
+ entity tag) is no longer a representation of that resource. This
+ allows the user to indicate that they do not wish the request to be
+ successful if the resource has been changed without their knowledge.
+ Examples:
+
+ If-Match: "xyzzy"
+ If-Match: "xyzzy", "r2d2xxxx", "c3piozzzz"
+ If-Match: *
+
+ The result of a request having both an If-Match header field and
+ either an If-None-Match or an If-Modified-Since header fields is
+ undefined by this specification.
+
+14.25 If-Modified-Since
+
+ The If-Modified-Since request-header field is used with a method to
+ make it conditional: if the requested variant has not been modified
+ since the time specified in this field, an entity will not be
+ returned from the server; instead, a 304 (not modified) response will
+ be returned without any message-body.
+
+ If-Modified-Since = "If-Modified-Since" ":" HTTP-date
+
+
+
+Fielding, et al. Standards Track [Page 130]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ An example of the field is:
+
+ If-Modified-Since: Sat, 29 Oct 1994 19:43:31 GMT
+
+ A GET method with an If-Modified-Since header and no Range header
+ requests that the identified entity be transferred only if it has
+ been modified since the date given by the If-Modified-Since header.
+ The algorithm for determining this includes the following cases:
+
+ a) If the request would normally result in anything other than a
+ 200 (OK) status, or if the passed If-Modified-Since date is
+ invalid, the response is exactly the same as for a normal GET.
+ A date which is later than the server's current time is
+ invalid.
+
+ b) If the variant has been modified since the If-Modified-Since
+ date, the response is exactly the same as for a normal GET.
+
+ c) If the variant has not been modified since a valid If-
+ Modified-Since date, the server SHOULD return a 304 (Not
+ Modified) response.
+
+ The purpose of this feature is to allow efficient updates of cached
+ information with a minimum amount of transaction overhead.
+
+ Note: The Range request-header field modifies the meaning of If-
+ Modified-Since; see section 14.35 for full details.
+
+ Note: If-Modified-Since times are interpreted by the server, whose
+ clock might not be synchronized with the client.
+
+ Note: When handling an If-Modified-Since header field, some
+ servers will use an exact date comparison function, rather than a
+ less-than function, for deciding whether to send a 304 (Not
+ Modified) response. To get best results when sending an If-
+ Modified-Since header field for cache validation, clients are
+ advised to use the exact date string received in a previous Last-
+ Modified header field whenever possible.
+
+ Note: If a client uses an arbitrary date in the If-Modified-Since
+ header instead of a date taken from the Last-Modified header for
+ the same request, the client should be aware of the fact that this
+ date is interpreted in the server's understanding of time. The
+ client should consider unsynchronized clocks and rounding problems
+ due to the different encodings of time between the client and
+ server. This includes the possibility of race conditions if the
+ document has changed between the time it was first requested and
+ the If-Modified-Since date of a subsequent request, and the
+
+
+
+Fielding, et al. Standards Track [Page 131]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ possibility of clock-skew-related problems if the If-Modified-
+ Since date is derived from the client's clock without correction
+ to the server's clock. Corrections for different time bases
+ between client and server are at best approximate due to network
+ latency.
+
+ The result of a request having both an If-Modified-Since header field
+ and either an If-Match or an If-Unmodified-Since header fields is
+ undefined by this specification.
+
+14.26 If-None-Match
+
+ The If-None-Match request-header field is used with a method to make
+ it conditional. A client that has one or more entities previously
+ obtained from the resource can verify that none of those entities is
+ current by including a list of their associated entity tags in the
+ If-None-Match header field. The purpose of this feature is to allow
+ efficient updates of cached information with a minimum amount of
+ transaction overhead. It is also used to prevent a method (e.g. PUT)
+ from inadvertently modifying an existing resource when the client
+ believes that the resource does not exist.
+
+ As a special case, the value "*" matches any current entity of the
+ resource.
+
+ If-None-Match = "If-None-Match" ":" ( "*" | 1#entity-tag )
+
+ If any of the entity tags match the entity tag of the entity that
+ would have been returned in the response to a similar GET request
+ (without the If-None-Match header) on that resource, or if "*" is
+ given and any current entity exists for that resource, then the
+ server MUST NOT perform the requested method, unless required to do
+ so because the resource's modification date fails to match that
+ supplied in an If-Modified-Since header field in the request.
+ Instead, if the request method was GET or HEAD, the server SHOULD
+ respond with a 304 (Not Modified) response, including the cache-
+ related header fields (particularly ETag) of one of the entities that
+ matched. For all other request methods, the server MUST respond with
+ a status of 412 (Precondition Failed).
+
+ See section 13.3.3 for rules on how to determine if two entities tags
+ match. The weak comparison function can only be used with GET or HEAD
+ requests.
+
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 132]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ If none of the entity tags match, then the server MAY perform the
+ requested method as if the If-None-Match header field did not exist,
+ but MUST also ignore any If-Modified-Since header field(s) in the
+ request. That is, if no entity tags match, then the server MUST NOT
+ return a 304 (Not Modified) response.
+
+ If the request would, without the If-None-Match header field, result
+ in anything other than a 2xx or 304 status, then the If-None-Match
+ header MUST be ignored. (See section 13.3.4 for a discussion of
+ server behavior when both If-Modified-Since and If-None-Match appear
+ in the same request.)
+
+ The meaning of "If-None-Match: *" is that the method MUST NOT be
+ performed if the representation selected by the origin server (or by
+ a cache, possibly using the Vary mechanism, see section 14.44)
+ exists, and SHOULD be performed if the representation does not exist.
+ This feature is intended to be useful in preventing races between PUT
+ operations.
+
+ Examples:
+
+ If-None-Match: "xyzzy"
+ If-None-Match: W/"xyzzy"
+ If-None-Match: "xyzzy", "r2d2xxxx", "c3piozzzz"
+ If-None-Match: W/"xyzzy", W/"r2d2xxxx", W/"c3piozzzz"
+ If-None-Match: *
+
+ The result of a request having both an If-None-Match header field and
+ either an If-Match or an If-Unmodified-Since header fields is
+ undefined by this specification.
+
+14.27 If-Range
+
+ If a client has a partial copy of an entity in its cache, and wishes
+ to have an up-to-date copy of the entire entity in its cache, it
+ could use the Range request-header with a conditional GET (using
+ either or both of If-Unmodified-Since and If-Match.) However, if the
+ condition fails because the entity has been modified, the client
+ would then have to make a second request to obtain the entire current
+ entity-body.
+
+ The If-Range header allows a client to "short-circuit" the second
+ request. Informally, its meaning is `if the entity is unchanged, send
+ me the part(s) that I am missing; otherwise, send me the entire new
+ entity'.
+
+ If-Range = "If-Range" ":" ( entity-tag | HTTP-date )
+
+
+
+
+Fielding, et al. Standards Track [Page 133]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ If the client has no entity tag for an entity, but does have a Last-
+ Modified date, it MAY use that date in an If-Range header. (The
+ server can distinguish between a valid HTTP-date and any form of
+ entity-tag by examining no more than two characters.) The If-Range
+ header SHOULD only be used together with a Range header, and MUST be
+ ignored if the request does not include a Range header, or if the
+ server does not support the sub-range operation.
+
+ If the entity tag given in the If-Range header matches the current
+ entity tag for the entity, then the server SHOULD provide the
+ specified sub-range of the entity using a 206 (Partial content)
+ response. If the entity tag does not match, then the server SHOULD
+ return the entire entity using a 200 (OK) response.
+
+14.28 If-Unmodified-Since
+
+ The If-Unmodified-Since request-header field is used with a method to
+ make it conditional. If the requested resource has not been modified
+ since the time specified in this field, the server SHOULD perform the
+ requested operation as if the If-Unmodified-Since header were not
+ present.
+
+ If the requested variant has been modified since the specified time,
+ the server MUST NOT perform the requested operation, and MUST return
+ a 412 (Precondition Failed).
+
+ If-Unmodified-Since = "If-Unmodified-Since" ":" HTTP-date
+
+ An example of the field is:
+
+ If-Unmodified-Since: Sat, 29 Oct 1994 19:43:31 GMT
+
+ If the request normally (i.e., without the If-Unmodified-Since
+ header) would result in anything other than a 2xx or 412 status, the
+ If-Unmodified-Since header SHOULD be ignored.
+
+ If the specified date is invalid, the header is ignored.
+
+ The result of a request having both an If-Unmodified-Since header
+ field and either an If-None-Match or an If-Modified-Since header
+ fields is undefined by this specification.
+
+14.29 Last-Modified
+
+ The Last-Modified entity-header field indicates the date and time at
+ which the origin server believes the variant was last modified.
+
+ Last-Modified = "Last-Modified" ":" HTTP-date
+
+
+
+Fielding, et al. Standards Track [Page 134]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ An example of its use is
+
+ Last-Modified: Tue, 15 Nov 1994 12:45:26 GMT
+
+ The exact meaning of this header field depends on the implementation
+ of the origin server and the nature of the original resource. For
+ files, it may be just the file system last-modified time. For
+ entities with dynamically included parts, it may be the most recent
+ of the set of last-modify times for its component parts. For database
+ gateways, it may be the last-update time stamp of the record. For
+ virtual objects, it may be the last time the internal state changed.
+
+ An origin server MUST NOT send a Last-Modified date which is later
+ than the server's time of message origination. In such cases, where
+ the resource's last modification would indicate some time in the
+ future, the server MUST replace that date with the message
+ origination date.
+
+ An origin server SHOULD obtain the Last-Modified value of the entity
+ as close as possible to the time that it generates the Date value of
+ its response. This allows a recipient to make an accurate assessment
+ of the entity's modification time, especially if the entity changes
+ near the time that the response is generated.
+
+ HTTP/1.1 servers SHOULD send Last-Modified whenever feasible.
+
+14.30 Location
+
+ The Location response-header field is used to redirect the recipient
+ to a location other than the Request-URI for completion of the
+ request or identification of a new resource. For 201 (Created)
+ responses, the Location is that of the new resource which was created
+ by the request. For 3xx responses, the location SHOULD indicate the
+ server's preferred URI for automatic redirection to the resource. The
+ field value consists of a single absolute URI.
+
+ Location = "Location" ":" absoluteURI
+
+ An example is:
+
+ Location: http://www.w3.org/pub/WWW/People.html
+
+ Note: The Content-Location header field (section 14.14) differs
+ from Location in that the Content-Location identifies the original
+ location of the entity enclosed in the request. It is therefore
+ possible for a response to contain header fields for both Location
+ and Content-Location. Also see section 13.10 for cache
+ requirements of some methods.
+
+
+
+Fielding, et al. Standards Track [Page 135]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+14.31 Max-Forwards
+
+ The Max-Forwards request-header field provides a mechanism with the
+ TRACE (section 9.8) and OPTIONS (section 9.2) methods to limit the
+ number of proxies or gateways that can forward the request to the
+ next inbound server. This can be useful when the client is attempting
+ to trace a request chain which appears to be failing or looping in
+ mid-chain.
+
+ Max-Forwards = "Max-Forwards" ":" 1*DIGIT
+
+ The Max-Forwards value is a decimal integer indicating the remaining
+ number of times this request message may be forwarded.
+
+ Each proxy or gateway recipient of a TRACE or OPTIONS request
+ containing a Max-Forwards header field MUST check and update its
+ value prior to forwarding the request. If the received value is zero
+ (0), the recipient MUST NOT forward the request; instead, it MUST
+ respond as the final recipient. If the received Max-Forwards value is
+ greater than zero, then the forwarded message MUST contain an updated
+ Max-Forwards field with a value decremented by one (1).
+
+ The Max-Forwards header field MAY be ignored for all other methods
+ defined by this specification and for any extension methods for which
+ it is not explicitly referred to as part of that method definition.
+
+14.32 Pragma
+
+ The Pragma general-header field is used to include implementation-
+ specific directives that might apply to any recipient along the
+ request/response chain. All pragma directives specify optional
+ behavior from the viewpoint of the protocol; however, some systems
+ MAY require that behavior be consistent with the directives.
+
+ Pragma = "Pragma" ":" 1#pragma-directive
+ pragma-directive = "no-cache" | extension-pragma
+ extension-pragma = token [ "=" ( token | quoted-string ) ]
+
+ When the no-cache directive is present in a request message, an
+ application SHOULD forward the request toward the origin server even
+ if it has a cached copy of what is being requested. This pragma
+ directive has the same semantics as the no-cache cache-directive (see
+ section 14.9) and is defined here for backward compatibility with
+ HTTP/1.0. Clients SHOULD include both header fields when a no-cache
+ request is sent to a server not known to be HTTP/1.1 compliant.
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 136]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ Pragma directives MUST be passed through by a proxy or gateway
+ application, regardless of their significance to that application,
+ since the directives might be applicable to all recipients along the
+ request/response chain. It is not possible to specify a pragma for a
+ specific recipient; however, any pragma directive not relevant to a
+ recipient SHOULD be ignored by that recipient.
+
+ HTTP/1.1 caches SHOULD treat "Pragma: no-cache" as if the client had
+ sent "Cache-Control: no-cache". No new Pragma directives will be
+ defined in HTTP.
+
+ Note: because the meaning of "Pragma: no-cache as a response
+ header field is not actually specified, it does not provide a
+ reliable replacement for "Cache-Control: no-cache" in a response
+
+14.33 Proxy-Authenticate
+
+ The Proxy-Authenticate response-header field MUST be included as part
+ of a 407 (Proxy Authentication Required) response. The field value
+ consists of a challenge that indicates the authentication scheme and
+ parameters applicable to the proxy for this Request-URI.
+
+ Proxy-Authenticate = "Proxy-Authenticate" ":" 1#challenge
+
+ The HTTP access authentication process is described in "HTTP
+ Authentication: Basic and Digest Access Authentication" [43]. Unlike
+ WWW-Authenticate, the Proxy-Authenticate header field applies only to
+ the current connection and SHOULD NOT be passed on to downstream
+ clients. However, an intermediate proxy might need to obtain its own
+ credentials by requesting them from the downstream client, which in
+ some circumstances will appear as if the proxy is forwarding the
+ Proxy-Authenticate header field.
+
+14.34 Proxy-Authorization
+
+ The Proxy-Authorization request-header field allows the client to
+ identify itself (or its user) to a proxy which requires
+ authentication. The Proxy-Authorization field value consists of
+ credentials containing the authentication information of the user
+ agent for the proxy and/or realm of the resource being requested.
+
+ Proxy-Authorization = "Proxy-Authorization" ":" credentials
+
+ The HTTP access authentication process is described in "HTTP
+ Authentication: Basic and Digest Access Authentication" [43] . Unlike
+ Authorization, the Proxy-Authorization header field applies only to
+ the next outbound proxy that demanded authentication using the Proxy-
+ Authenticate field. When multiple proxies are used in a chain, the
+
+
+
+Fielding, et al. Standards Track [Page 137]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ Proxy-Authorization header field is consumed by the first outbound
+ proxy that was expecting to receive credentials. A proxy MAY relay
+ the credentials from the client request to the next proxy if that is
+ the mechanism by which the proxies cooperatively authenticate a given
+ request.
+
+14.35 Range
+
+14.35.1 Byte Ranges
+
+ Since all HTTP entities are represented in HTTP messages as sequences
+ of bytes, the concept of a byte range is meaningful for any HTTP
+ entity. (However, not all clients and servers need to support byte-
+ range operations.)
+
+ Byte range specifications in HTTP apply to the sequence of bytes in
+ the entity-body (not necessarily the same as the message-body).
+
+ A byte range operation MAY specify a single range of bytes, or a set
+ of ranges within a single entity.
+
+ ranges-specifier = byte-ranges-specifier
+ byte-ranges-specifier = bytes-unit "=" byte-range-set
+ byte-range-set = 1#( byte-range-spec | suffix-byte-range-spec )
+ byte-range-spec = first-byte-pos "-" [last-byte-pos]
+ first-byte-pos = 1*DIGIT
+ last-byte-pos = 1*DIGIT
+
+ The first-byte-pos value in a byte-range-spec gives the byte-offset
+ of the first byte in a range. The last-byte-pos value gives the
+ byte-offset of the last byte in the range; that is, the byte
+ positions specified are inclusive. Byte offsets start at zero.
+
+ If the last-byte-pos value is present, it MUST be greater than or
+ equal to the first-byte-pos in that byte-range-spec, or the byte-
+ range-spec is syntactically invalid. The recipient of a byte-range-
+ set that includes one or more syntactically invalid byte-range-spec
+ values MUST ignore the header field that includes that byte-range-
+ set.
+
+ If the last-byte-pos value is absent, or if the value is greater than
+ or equal to the current length of the entity-body, last-byte-pos is
+ taken to be equal to one less than the current length of the entity-
+ body in bytes.
+
+ By its choice of last-byte-pos, a client can limit the number of
+ bytes retrieved without knowing the size of the entity.
+
+
+
+
+Fielding, et al. Standards Track [Page 138]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ suffix-byte-range-spec = "-" suffix-length
+ suffix-length = 1*DIGIT
+
+ A suffix-byte-range-spec is used to specify the suffix of the
+ entity-body, of a length given by the suffix-length value. (That is,
+ this form specifies the last N bytes of an entity-body.) If the
+ entity is shorter than the specified suffix-length, the entire
+ entity-body is used.
+
+ If a syntactically valid byte-range-set includes at least one byte-
+ range-spec whose first-byte-pos is less than the current length of
+ the entity-body, or at least one suffix-byte-range-spec with a non-
+ zero suffix-length, then the byte-range-set is satisfiable.
+ Otherwise, the byte-range-set is unsatisfiable. If the byte-range-set
+ is unsatisfiable, the server SHOULD return a response with a status
+ of 416 (Requested range not satisfiable). Otherwise, the server
+ SHOULD return a response with a status of 206 (Partial Content)
+ containing the satisfiable ranges of the entity-body.
+
+ Examples of byte-ranges-specifier values (assuming an entity-body of
+ length 10000):
+
+ - The first 500 bytes (byte offsets 0-499, inclusive): bytes=0-
+ 499
+
+ - The second 500 bytes (byte offsets 500-999, inclusive):
+ bytes=500-999
+
+ - The final 500 bytes (byte offsets 9500-9999, inclusive):
+ bytes=-500
+
+ - Or bytes=9500-
+
+ - The first and last bytes only (bytes 0 and 9999): bytes=0-0,-1
+
+ - Several legal but not canonical specifications of the second 500
+ bytes (byte offsets 500-999, inclusive):
+ bytes=500-600,601-999
+ bytes=500-700,601-999
+
+14.35.2 Range Retrieval Requests
+
+ HTTP retrieval requests using conditional or unconditional GET
+ methods MAY request one or more sub-ranges of the entity, instead of
+ the entire entity, using the Range request header, which applies to
+ the entity returned as the result of the request:
+
+ Range = "Range" ":" ranges-specifier
+
+
+
+Fielding, et al. Standards Track [Page 139]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ A server MAY ignore the Range header. However, HTTP/1.1 origin
+ servers and intermediate caches ought to support byte ranges when
+ possible, since Range supports efficient recovery from partially
+ failed transfers, and supports efficient partial retrieval of large
+ entities.
+
+ If the server supports the Range header and the specified range or
+ ranges are appropriate for the entity:
+
+ - The presence of a Range header in an unconditional GET modifies
+ what is returned if the GET is otherwise successful. In other
+ words, the response carries a status code of 206 (Partial
+ Content) instead of 200 (OK).
+
+ - The presence of a Range header in a conditional GET (a request
+ using one or both of If-Modified-Since and If-None-Match, or
+ one or both of If-Unmodified-Since and If-Match) modifies what
+ is returned if the GET is otherwise successful and the
+ condition is true. It does not affect the 304 (Not Modified)
+ response returned if the conditional is false.
+
+ In some cases, it might be more appropriate to use the If-Range
+ header (see section 14.27) in addition to the Range header.
+
+ If a proxy that supports ranges receives a Range request, forwards
+ the request to an inbound server, and receives an entire entity in
+ reply, it SHOULD only return the requested range to its client. It
+ SHOULD store the entire received response in its cache if that is
+ consistent with its cache allocation policies.
+
+14.36 Referer
+
+ The Referer[sic] request-header field allows the client to specify,
+ for the server's benefit, the address (URI) of the resource from
+ which the Request-URI was obtained (the "referrer", although the
+ header field is misspelled.) The Referer request-header allows a
+ server to generate lists of back-links to resources for interest,
+ logging, optimized caching, etc. It also allows obsolete or mistyped
+ links to be traced for maintenance. The Referer field MUST NOT be
+ sent if the Request-URI was obtained from a source that does not have
+ its own URI, such as input from the user keyboard.
+
+ Referer = "Referer" ":" ( absoluteURI | relativeURI )
+
+ Example:
+
+ Referer: http://www.w3.org/hypertext/DataSources/Overview.html
+
+
+
+
+Fielding, et al. Standards Track [Page 140]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ If the field value is a relative URI, it SHOULD be interpreted
+ relative to the Request-URI. The URI MUST NOT include a fragment. See
+ section 15.1.3 for security considerations.
+
+14.37 Retry-After
+
+ The Retry-After response-header field can be used with a 503 (Service
+ Unavailable) response to indicate how long the service is expected to
+ be unavailable to the requesting client. This field MAY also be used
+ with any 3xx (Redirection) response to indicate the minimum time the
+ user-agent is asked wait before issuing the redirected request. The
+ value of this field can be either an HTTP-date or an integer number
+ of seconds (in decimal) after the time of the response.
+
+ Retry-After = "Retry-After" ":" ( HTTP-date | delta-seconds )
+
+ Two examples of its use are
+
+ Retry-After: Fri, 31 Dec 1999 23:59:59 GMT
+ Retry-After: 120
+
+ In the latter example, the delay is 2 minutes.
+
+14.38 Server
+
+ The Server response-header field contains information about the
+ software used by the origin server to handle the request. The field
+ can contain multiple product tokens (section 3.8) and comments
+ identifying the server and any significant subproducts. The product
+ tokens are listed in order of their significance for identifying the
+ application.
+
+ Server = "Server" ":" 1*( product | comment )
+
+ Example:
+
+ Server: CERN/3.0 libwww/2.17
+
+ If the response is being forwarded through a proxy, the proxy
+ application MUST NOT modify the Server response-header. Instead, it
+ SHOULD include a Via field (as described in section 14.45).
+
+ Note: Revealing the specific software version of the server might
+ allow the server machine to become more vulnerable to attacks
+ against software that is known to contain security holes. Server
+ implementors are encouraged to make this field a configurable
+ option.
+
+
+
+
+Fielding, et al. Standards Track [Page 141]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+14.39 TE
+
+ The TE request-header field indicates what extension transfer-codings
+ it is willing to accept in the response and whether or not it is
+ willing to accept trailer fields in a chunked transfer-coding. Its
+ value may consist of the keyword "trailers" and/or a comma-separated
+ list of extension transfer-coding names with optional accept
+ parameters (as described in section 3.6).
+
+ TE = "TE" ":" #( t-codings )
+ t-codings = "trailers" | ( transfer-extension [ accept-params ] )
+
+ The presence of the keyword "trailers" indicates that the client is
+ willing to accept trailer fields in a chunked transfer-coding, as
+ defined in section 3.6.1. This keyword is reserved for use with
+ transfer-coding values even though it does not itself represent a
+ transfer-coding.
+
+ Examples of its use are:
+
+ TE: deflate
+ TE:
+ TE: trailers, deflate;q=0.5
+
+ The TE header field only applies to the immediate connection.
+ Therefore, the keyword MUST be supplied within a Connection header
+ field (section 14.10) whenever TE is present in an HTTP/1.1 message.
+
+ A server tests whether a transfer-coding is acceptable, according to
+ a TE field, using these rules:
+
+ 1. The "chunked" transfer-coding is always acceptable. If the
+ keyword "trailers" is listed, the client indicates that it is
+ willing to accept trailer fields in the chunked response on
+ behalf of itself and any downstream clients. The implication is
+ that, if given, the client is stating that either all
+ downstream clients are willing to accept trailer fields in the
+ forwarded response, or that it will attempt to buffer the
+ response on behalf of downstream recipients.
+
+ Note: HTTP/1.1 does not define any means to limit the size of a
+ chunked response such that a client can be assured of buffering
+ the entire response.
+
+ 2. If the transfer-coding being tested is one of the transfer-
+ codings listed in the TE field, then it is acceptable unless it
+ is accompanied by a qvalue of 0. (As defined in section 3.9, a
+ qvalue of 0 means "not acceptable.")
+
+
+
+Fielding, et al. Standards Track [Page 142]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ 3. If multiple transfer-codings are acceptable, then the
+ acceptable transfer-coding with the highest non-zero qvalue is
+ preferred. The "chunked" transfer-coding always has a qvalue
+ of 1.
+
+ If the TE field-value is empty or if no TE field is present, the only
+ transfer-coding is "chunked". A message with no transfer-coding is
+ always acceptable.
+
+14.40 Trailer
+
+ The Trailer general field value indicates that the given set of
+ header fields is present in the trailer of a message encoded with
+ chunked transfer-coding.
+
+ Trailer = "Trailer" ":" 1#field-name
+
+ An HTTP/1.1 message SHOULD include a Trailer header field in a
+ message using chunked transfer-coding with a non-empty trailer. Doing
+ so allows the recipient to know which header fields to expect in the
+ trailer.
+
+ If no Trailer header field is present, the trailer SHOULD NOT include
+ any header fields. See section 3.6.1 for restrictions on the use of
+ trailer fields in a "chunked" transfer-coding.
+
+ Message header fields listed in the Trailer header field MUST NOT
+ include the following header fields:
+
+ . Transfer-Encoding
+
+ . Content-Length
+
+ . Trailer
+
+14.41 Transfer-Encoding
+
+ The Transfer-Encoding general-header field indicates what (if any)
+ type of transformation has been applied to the message body in order
+ to safely transfer it between the sender and the recipient. This
+ differs from the content-coding in that the transfer-coding is a
+ property of the message, not of the entity.
+
+ Transfer-Encoding = "Transfer-Encoding" ":" 1#transfer-coding
+
+ Transfer-codings are defined in section 3.6. An example is:
+
+ Transfer-Encoding: chunked
+
+
+
+Fielding, et al. Standards Track [Page 143]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ If multiple encodings have been applied to an entity, the transfer-
+ codings MUST be listed in the order in which they were applied.
+ Additional information about the encoding parameters MAY be provided
+ by other entity-header fields not defined by this specification.
+
+ Many older HTTP/1.0 applications do not understand the Transfer-
+ Encoding header.
+
+14.42 Upgrade
+
+ The Upgrade general-header allows the client to specify what
+ additional communication protocols it supports and would like to use
+ if the server finds it appropriate to switch protocols. The server
+ MUST use the Upgrade header field within a 101 (Switching Protocols)
+ response to indicate which protocol(s) are being switched.
+
+ Upgrade = "Upgrade" ":" 1#product
+
+ For example,
+
+ Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11
+
+ The Upgrade header field is intended to provide a simple mechanism
+ for transition from HTTP/1.1 to some other, incompatible protocol. It
+ does so by allowing the client to advertise its desire to use another
+ protocol, such as a later version of HTTP with a higher major version
+ number, even though the current request has been made using HTTP/1.1.
+ This eases the difficult transition between incompatible protocols by
+ allowing the client to initiate a request in the more commonly
+ supported protocol while indicating to the server that it would like
+ to use a "better" protocol if available (where "better" is determined
+ by the server, possibly according to the nature of the method and/or
+ resource being requested).
+
+ The Upgrade header field only applies to switching application-layer
+ protocols upon the existing transport-layer connection. Upgrade
+ cannot be used to insist on a protocol change; its acceptance and use
+ by the server is optional. The capabilities and nature of the
+ application-layer communication after the protocol change is entirely
+ dependent upon the new protocol chosen, although the first action
+ after changing the protocol MUST be a response to the initial HTTP
+ request containing the Upgrade header field.
+
+ The Upgrade header field only applies to the immediate connection.
+ Therefore, the upgrade keyword MUST be supplied within a Connection
+ header field (section 14.10) whenever Upgrade is present in an
+ HTTP/1.1 message.
+
+
+
+
+Fielding, et al. Standards Track [Page 144]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ The Upgrade header field cannot be used to indicate a switch to a
+ protocol on a different connection. For that purpose, it is more
+ appropriate to use a 301, 302, 303, or 305 redirection response.
+
+ This specification only defines the protocol name "HTTP" for use by
+ the family of Hypertext Transfer Protocols, as defined by the HTTP
+ version rules of section 3.1 and future updates to this
+ specification. Any token can be used as a protocol name; however, it
+ will only be useful if both the client and server associate the name
+ with the same protocol.
+
+14.43 User-Agent
+
+ The User-Agent request-header field contains information about the
+ user agent originating the request. This is for statistical purposes,
+ the tracing of protocol violations, and automated recognition of user
+ agents for the sake of tailoring responses to avoid particular user
+ agent limitations. User agents SHOULD include this field with
+ requests. The field can contain multiple product tokens (section 3.8)
+ and comments identifying the agent and any subproducts which form a
+ significant part of the user agent. By convention, the product tokens
+ are listed in order of their significance for identifying the
+ application.
+
+ User-Agent = "User-Agent" ":" 1*( product | comment )
+
+ Example:
+
+ User-Agent: CERN-LineMode/2.15 libwww/2.17b3
+
+14.44 Vary
+
+ The Vary field value indicates the set of request-header fields that
+ fully determines, while the response is fresh, whether a cache is
+ permitted to use the response to reply to a subsequent request
+ without revalidation. For uncacheable or stale responses, the Vary
+ field value advises the user agent about the criteria that were used
+ to select the representation. A Vary field value of "*" implies that
+ a cache cannot determine from the request headers of a subsequent
+ request whether this response is the appropriate representation. See
+ section 13.6 for use of the Vary header field by caches.
+
+ Vary = "Vary" ":" ( "*" | 1#field-name )
+
+ An HTTP/1.1 server SHOULD include a Vary header field with any
+ cacheable response that is subject to server-driven negotiation.
+ Doing so allows a cache to properly interpret future requests on that
+ resource and informs the user agent about the presence of negotiation
+
+
+
+Fielding, et al. Standards Track [Page 145]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ on that resource. A server MAY include a Vary header field with a
+ non-cacheable response that is subject to server-driven negotiation,
+ since this might provide the user agent with useful information about
+ the dimensions over which the response varies at the time of the
+ response.
+
+ A Vary field value consisting of a list of field-names signals that
+ the representation selected for the response is based on a selection
+ algorithm which considers ONLY the listed request-header field values
+ in selecting the most appropriate representation. A cache MAY assume
+ that the same selection will be made for future requests with the
+ same values for the listed field names, for the duration of time for
+ which the response is fresh.
+
+ The field-names given are not limited to the set of standard
+ request-header fields defined by this specification. Field names are
+ case-insensitive.
+
+ A Vary field value of "*" signals that unspecified parameters not
+ limited to the request-headers (e.g., the network address of the
+ client), play a role in the selection of the response representation.
+ The "*" value MUST NOT be generated by a proxy server; it may only be
+ generated by an origin server.
+
+14.45 Via
+
+ The Via general-header field MUST be used by gateways and proxies to
+ indicate the intermediate protocols and recipients between the user
+ agent and the server on requests, and between the origin server and
+ the client on responses. It is analogous to the "Received" field of
+ RFC 822 [9] and is intended to be used for tracking message forwards,
+ avoiding request loops, and identifying the protocol capabilities of
+ all senders along the request/response chain.
+
+ Via = "Via" ":" 1#( received-protocol received-by [ comment ] )
+ received-protocol = [ protocol-name "/" ] protocol-version
+ protocol-name = token
+ protocol-version = token
+ received-by = ( host [ ":" port ] ) | pseudonym
+ pseudonym = token
+
+ The received-protocol indicates the protocol version of the message
+ received by the server or client along each segment of the
+ request/response chain. The received-protocol version is appended to
+ the Via field value when the message is forwarded so that information
+ about the protocol capabilities of upstream applications remains
+ visible to all recipients.
+
+
+
+
+Fielding, et al. Standards Track [Page 146]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ The protocol-name is optional if and only if it would be "HTTP". The
+ received-by field is normally the host and optional port number of a
+ recipient server or client that subsequently forwarded the message.
+ However, if the real host is considered to be sensitive information,
+ it MAY be replaced by a pseudonym. If the port is not given, it MAY
+ be assumed to be the default port of the received-protocol.
+
+ Multiple Via field values represents each proxy or gateway that has
+ forwarded the message. Each recipient MUST append its information
+ such that the end result is ordered according to the sequence of
+ forwarding applications.
+
+ Comments MAY be used in the Via header field to identify the software
+ of the recipient proxy or gateway, analogous to the User-Agent and
+ Server header fields. However, all comments in the Via field are
+ optional and MAY be removed by any recipient prior to forwarding the
+ message.
+
+ For example, a request message could be sent from an HTTP/1.0 user
+ agent to an internal proxy code-named "fred", which uses HTTP/1.1 to
+ forward the request to a public proxy at nowhere.com, which completes
+ the request by forwarding it to the origin server at www.ics.uci.edu.
+ The request received by www.ics.uci.edu would then have the following
+ Via header field:
+
+ Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1)
+
+ Proxies and gateways used as a portal through a network firewall
+ SHOULD NOT, by default, forward the names and ports of hosts within
+ the firewall region. This information SHOULD only be propagated if
+ explicitly enabled. If not enabled, the received-by host of any host
+ behind the firewall SHOULD be replaced by an appropriate pseudonym
+ for that host.
+
+ For organizations that have strong privacy requirements for hiding
+ internal structures, a proxy MAY combine an ordered subsequence of
+ Via header field entries with identical received-protocol values into
+ a single such entry. For example,
+
+ Via: 1.0 ricky, 1.1 ethel, 1.1 fred, 1.0 lucy
+
+ could be collapsed to
+
+ Via: 1.0 ricky, 1.1 mertz, 1.0 lucy
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 147]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ Applications SHOULD NOT combine multiple entries unless they are all
+ under the same organizational control and the hosts have already been
+ replaced by pseudonyms. Applications MUST NOT combine entries which
+ have different received-protocol values.
+
+14.46 Warning
+
+ The Warning general-header field is used to carry additional
+ information about the status or transformation of a message which
+ might not be reflected in the message. This information is typically
+ used to warn about a possible lack of semantic transparency from
+ caching operations or transformations applied to the entity body of
+ the message.
+
+ Warning headers are sent with responses using:
+
+ Warning = "Warning" ":" 1#warning-value
+
+ warning-value = warn-code SP warn-agent SP warn-text
+ [SP warn-date]
+
+ warn-code = 3DIGIT
+ warn-agent = ( host [ ":" port ] ) | pseudonym
+ ; the name or pseudonym of the server adding
+ ; the Warning header, for use in debugging
+ warn-text = quoted-string
+ warn-date = <"> HTTP-date <">
+
+ A response MAY carry more than one Warning header.
+
+ The warn-text SHOULD be in a natural language and character set that
+ is most likely to be intelligible to the human user receiving the
+ response. This decision MAY be based on any available knowledge, such
+ as the location of the cache or user, the Accept-Language field in a
+ request, the Content-Language field in a response, etc. The default
+ language is English and the default character set is ISO-8859-1.
+
+ If a character set other than ISO-8859-1 is used, it MUST be encoded
+ in the warn-text using the method described in RFC 2047 [14].
+
+ Warning headers can in general be applied to any message, however
+ some specific warn-codes are specific to caches and can only be
+ applied to response messages. New Warning headers SHOULD be added
+ after any existing Warning headers. A cache MUST NOT delete any
+ Warning header that it received with a message. However, if a cache
+ successfully validates a cache entry, it SHOULD remove any Warning
+ headers previously attached to that entry except as specified for
+
+
+
+
+Fielding, et al. Standards Track [Page 148]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ specific Warning codes. It MUST then add any Warning headers received
+ in the validating response. In other words, Warning headers are those
+ that would be attached to the most recent relevant response.
+
+ When multiple Warning headers are attached to a response, the user
+ agent ought to inform the user of as many of them as possible, in the
+ order that they appear in the response. If it is not possible to
+ inform the user of all of the warnings, the user agent SHOULD follow
+ these heuristics:
+
+ - Warnings that appear early in the response take priority over
+ those appearing later in the response.
+
+ - Warnings in the user's preferred character set take priority
+ over warnings in other character sets but with identical warn-
+ codes and warn-agents.
+
+ Systems that generate multiple Warning headers SHOULD order them with
+ this user agent behavior in mind.
+
+ Requirements for the behavior of caches with respect to Warnings are
+ stated in section 13.1.2.
+
+ This is a list of the currently-defined warn-codes, each with a
+ recommended warn-text in English, and a description of its meaning.
+
+ 110 Response is stale
+ MUST be included whenever the returned response is stale.
+
+ 111 Revalidation failed
+ MUST be included if a cache returns a stale response because an
+ attempt to revalidate the response failed, due to an inability to
+ reach the server.
+
+ 112 Disconnected operation
+ SHOULD be included if the cache is intentionally disconnected from
+ the rest of the network for a period of time.
+
+ 113 Heuristic expiration
+ MUST be included if the cache heuristically chose a freshness
+ lifetime greater than 24 hours and the response's age is greater
+ than 24 hours.
+
+ 199 Miscellaneous warning
+ The warning text MAY include arbitrary information to be presented
+ to a human user, or logged. A system receiving this warning MUST
+ NOT take any automated action, besides presenting the warning to
+ the user.
+
+
+
+Fielding, et al. Standards Track [Page 149]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ 214 Transformation applied
+ MUST be added by an intermediate cache or proxy if it applies any
+ transformation changing the content-coding (as specified in the
+ Content-Encoding header) or media-type (as specified in the
+ Content-Type header) of the response, or the entity-body of the
+ response, unless this Warning code already appears in the response.
+
+ 299 Miscellaneous persistent warning
+ The warning text MAY include arbitrary information to be presented
+ to a human user, or logged. A system receiving this warning MUST
+ NOT take any automated action.
+
+ If an implementation sends a message with one or more Warning headers
+ whose version is HTTP/1.0 or lower, then the sender MUST include in
+ each warning-value a warn-date that matches the date in the response.
+
+ If an implementation receives a message with a warning-value that
+ includes a warn-date, and that warn-date is different from the Date
+ value in the response, then that warning-value MUST be deleted from
+ the message before storing, forwarding, or using it. (This prevents
+ bad consequences of naive caching of Warning header fields.) If all
+ of the warning-values are deleted for this reason, the Warning header
+ MUST be deleted as well.
+
+14.47 WWW-Authenticate
+
+ The WWW-Authenticate response-header field MUST be included in 401
+ (Unauthorized) response messages. The field value consists of at
+ least one challenge that indicates the authentication scheme(s) and
+ parameters applicable to the Request-URI.
+
+ WWW-Authenticate = "WWW-Authenticate" ":" 1#challenge
+
+ The HTTP access authentication process is described in "HTTP
+ Authentication: Basic and Digest Access Authentication" [43]. User
+ agents are advised to take special care in parsing the WWW-
+ Authenticate field value as it might contain more than one challenge,
+ or if more than one WWW-Authenticate header field is provided, the
+ contents of a challenge itself can contain a comma-separated list of
+ authentication parameters.
+
+15 Security Considerations
+
+ This section is meant to inform application developers, information
+ providers, and users of the security limitations in HTTP/1.1 as
+ described by this document. The discussion does not include
+ definitive solutions to the problems revealed, though it does make
+ some suggestions for reducing security risks.
+
+
+
+Fielding, et al. Standards Track [Page 150]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+15.1 Personal Information
+
+ HTTP clients are often privy to large amounts of personal information
+ (e.g. the user's name, location, mail address, passwords, encryption
+ keys, etc.), and SHOULD be very careful to prevent unintentional
+ leakage of this information via the HTTP protocol to other sources.
+ We very strongly recommend that a convenient interface be provided
+ for the user to control dissemination of such information, and that
+ designers and implementors be particularly careful in this area.
+ History shows that errors in this area often create serious security
+ and/or privacy problems and generate highly adverse publicity for the
+ implementor's company.
+
+15.1.1 Abuse of Server Log Information
+
+ A server is in the position to save personal data about a user's
+ requests which might identify their reading patterns or subjects of
+ interest. This information is clearly confidential in nature and its
+ handling can be constrained by law in certain countries. People using
+ the HTTP protocol to provide data are responsible for ensuring that
+ such material is not distributed without the permission of any
+ individuals that are identifiable by the published results.
+
+15.1.2 Transfer of Sensitive Information
+
+ Like any generic data transfer protocol, HTTP cannot regulate the
+ content of the data that is transferred, nor is there any a priori
+ method of determining the sensitivity of any particular piece of
+ information within the context of any given request. Therefore,
+ applications SHOULD supply as much control over this information as
+ possible to the provider of that information. Four header fields are
+ worth special mention in this context: Server, Via, Referer and From.
+
+ Revealing the specific software version of the server might allow the
+ server machine to become more vulnerable to attacks against software
+ that is known to contain security holes. Implementors SHOULD make the
+ Server header field a configurable option.
+
+ Proxies which serve as a portal through a network firewall SHOULD
+ take special precautions regarding the transfer of header information
+ that identifies the hosts behind the firewall. In particular, they
+ SHOULD remove, or replace with sanitized versions, any Via fields
+ generated behind the firewall.
+
+ The Referer header allows reading patterns to be studied and reverse
+ links drawn. Although it can be very useful, its power can be abused
+ if user details are not separated from the information contained in
+
+
+
+
+Fielding, et al. Standards Track [Page 151]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ the Referer. Even when the personal information has been removed, the
+ Referer header might indicate a private document's URI whose
+ publication would be inappropriate.
+
+ The information sent in the From field might conflict with the user's
+ privacy interests or their site's security policy, and hence it
+ SHOULD NOT be transmitted without the user being able to disable,
+ enable, and modify the contents of the field. The user MUST be able
+ to set the contents of this field within a user preference or
+ application defaults configuration.
+
+ We suggest, though do not require, that a convenient toggle interface
+ be provided for the user to enable or disable the sending of From and
+ Referer information.
+
+ The User-Agent (section 14.43) or Server (section 14.38) header
+ fields can sometimes be used to determine that a specific client or
+ server have a particular security hole which might be exploited.
+ Unfortunately, this same information is often used for other valuable
+ purposes for which HTTP currently has no better mechanism.
+
+15.1.3 Encoding Sensitive Information in URI's
+
+ Because the source of a link might be private information or might
+ reveal an otherwise private information source, it is strongly
+ recommended that the user be able to select whether or not the
+ Referer field is sent. For example, a browser client could have a
+ toggle switch for browsing openly/anonymously, which would
+ respectively enable/disable the sending of Referer and From
+ information.
+
+ Clients SHOULD NOT include a Referer header field in a (non-secure)
+ HTTP request if the referring page was transferred with a secure
+ protocol.
+
+ Authors of services which use the HTTP protocol SHOULD NOT use GET
+ based forms for the submission of sensitive data, because this will
+ cause this data to be encoded in the Request-URI. Many existing
+ servers, proxies, and user agents will log the request URI in some
+ place where it might be visible to third parties. Servers can use
+ POST-based form submission instead
+
+15.1.4 Privacy Issues Connected to Accept Headers
+
+ Accept request-headers can reveal information about the user to all
+ servers which are accessed. The Accept-Language header in particular
+ can reveal information the user would consider to be of a private
+ nature, because the understanding of particular languages is often
+
+
+
+Fielding, et al. Standards Track [Page 152]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ strongly correlated to the membership of a particular ethnic group.
+ User agents which offer the option to configure the contents of an
+ Accept-Language header to be sent in every request are strongly
+ encouraged to let the configuration process include a message which
+ makes the user aware of the loss of privacy involved.
+
+ An approach that limits the loss of privacy would be for a user agent
+ to omit the sending of Accept-Language headers by default, and to ask
+ the user whether or not to start sending Accept-Language headers to a
+ server if it detects, by looking for any Vary response-header fields
+ generated by the server, that such sending could improve the quality
+ of service.
+
+ Elaborate user-customized accept header fields sent in every request,
+ in particular if these include quality values, can be used by servers
+ as relatively reliable and long-lived user identifiers. Such user
+ identifiers would allow content providers to do click-trail tracking,
+ and would allow collaborating content providers to match cross-server
+ click-trails or form submissions of individual users. Note that for
+ many users not behind a proxy, the network address of the host
+ running the user agent will also serve as a long-lived user
+ identifier. In environments where proxies are used to enhance
+ privacy, user agents ought to be conservative in offering accept
+ header configuration options to end users. As an extreme privacy
+ measure, proxies could filter the accept headers in relayed requests.
+ General purpose user agents which provide a high degree of header
+ configurability SHOULD warn users about the loss of privacy which can
+ be involved.
+
+15.2 Attacks Based On File and Path Names
+
+ Implementations of HTTP origin servers SHOULD be careful to restrict
+ the documents returned by HTTP requests to be only those that were
+ intended by the server administrators. If an HTTP server translates
+ HTTP URIs directly into file system calls, the server MUST take
+ special care not to serve files that were not intended to be
+ delivered to HTTP clients. For example, UNIX, Microsoft Windows, and
+ other operating systems use ".." as a path component to indicate a
+ directory level above the current one. On such a system, an HTTP
+ server MUST disallow any such construct in the Request-URI if it
+ would otherwise allow access to a resource outside those intended to
+ be accessible via the HTTP server. Similarly, files intended for
+ reference only internally to the server (such as access control
+ files, configuration files, and script code) MUST be protected from
+ inappropriate retrieval, since they might contain sensitive
+ information. Experience has shown that minor bugs in such HTTP server
+ implementations have turned into security risks.
+
+
+
+
+Fielding, et al. Standards Track [Page 153]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+15.3 DNS Spoofing
+
+ Clients using HTTP rely heavily on the Domain Name Service, and are
+ thus generally prone to security attacks based on the deliberate
+ mis-association of IP addresses and DNS names. Clients need to be
+ cautious in assuming the continuing validity of an IP number/DNS name
+ association.
+
+ In particular, HTTP clients SHOULD rely on their name resolver for
+ confirmation of an IP number/DNS name association, rather than
+ caching the result of previous host name lookups. Many platforms
+ already can cache host name lookups locally when appropriate, and
+ they SHOULD be configured to do so. It is proper for these lookups to
+ be cached, however, only when the TTL (Time To Live) information
+ reported by the name server makes it likely that the cached
+ information will remain useful.
+
+ If HTTP clients cache the results of host name lookups in order to
+ achieve a performance improvement, they MUST observe the TTL
+ information reported by DNS.
+
+ If HTTP clients do not observe this rule, they could be spoofed when
+ a previously-accessed server's IP address changes. As network
+ renumbering is expected to become increasingly common [24], the
+ possibility of this form of attack will grow. Observing this
+ requirement thus reduces this potential security vulnerability.
+
+ This requirement also improves the load-balancing behavior of clients
+ for replicated servers using the same DNS name and reduces the
+ likelihood of a user's experiencing failure in accessing sites which
+ use that strategy.
+
+15.4 Location Headers and Spoofing
+
+ If a single server supports multiple organizations that do not trust
+ one another, then it MUST check the values of Location and Content-
+ Location headers in responses that are generated under control of
+ said organizations to make sure that they do not attempt to
+ invalidate resources over which they have no authority.
+
+15.5 Content-Disposition Issues
+
+ RFC 1806 [35], from which the often implemented Content-Disposition
+ (see section 19.5.1) header in HTTP is derived, has a number of very
+ serious security considerations. Content-Disposition is not part of
+ the HTTP standard, but since it is widely implemented, we are
+ documenting its use and risks for implementors. See RFC 2183 [49]
+ (which updates RFC 1806) for details.
+
+
+
+Fielding, et al. Standards Track [Page 154]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+15.6 Authentication Credentials and Idle Clients
+
+ Existing HTTP clients and user agents typically retain authentication
+ information indefinitely. HTTP/1.1. does not provide a method for a
+ server to direct clients to discard these cached credentials. This is
+ a significant defect that requires further extensions to HTTP.
+ Circumstances under which credential caching can interfere with the
+ application's security model include but are not limited to:
+
+ - Clients which have been idle for an extended period following
+ which the server might wish to cause the client to reprompt the
+ user for credentials.
+
+ - Applications which include a session termination indication
+ (such as a `logout' or `commit' button on a page) after which
+ the server side of the application `knows' that there is no
+ further reason for the client to retain the credentials.
+
+ This is currently under separate study. There are a number of work-
+ arounds to parts of this problem, and we encourage the use of
+ password protection in screen savers, idle time-outs, and other
+ methods which mitigate the security problems inherent in this
+ problem. In particular, user agents which cache credentials are
+ encouraged to provide a readily accessible mechanism for discarding
+ cached credentials under user control.
+
+15.7 Proxies and Caching
+
+ By their very nature, HTTP proxies are men-in-the-middle, and
+ represent an opportunity for man-in-the-middle attacks. Compromise of
+ the systems on which the proxies run can result in serious security
+ and privacy problems. Proxies have access to security-related
+ information, personal information about individual users and
+ organizations, and proprietary information belonging to users and
+ content providers. A compromised proxy, or a proxy implemented or
+ configured without regard to security and privacy considerations,
+ might be used in the commission of a wide range of potential attacks.
+
+ Proxy operators should protect the systems on which proxies run as
+ they would protect any system that contains or transports sensitive
+ information. In particular, log information gathered at proxies often
+ contains highly sensitive personal information, and/or information
+ about organizations. Log information should be carefully guarded, and
+ appropriate guidelines for use developed and followed. (Section
+ 15.1.1).
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 155]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ Caching proxies provide additional potential vulnerabilities, since
+ the contents of the cache represent an attractive target for
+ malicious exploitation. Because cache contents persist after an HTTP
+ request is complete, an attack on the cache can reveal information
+ long after a user believes that the information has been removed from
+ the network. Therefore, cache contents should be protected as
+ sensitive information.
+
+ Proxy implementors should consider the privacy and security
+ implications of their design and coding decisions, and of the
+ configuration options they provide to proxy operators (especially the
+ default configuration).
+
+ Users of a proxy need to be aware that they are no trustworthier than
+ the people who run the proxy; HTTP itself cannot solve this problem.
+
+ The judicious use of cryptography, when appropriate, may suffice to
+ protect against a broad range of security and privacy attacks. Such
+ cryptography is beyond the scope of the HTTP/1.1 specification.
+
+15.7.1 Denial of Service Attacks on Proxies
+
+ They exist. They are hard to defend against. Research continues.
+ Beware.
+
+16 Acknowledgments
+
+ This specification makes heavy use of the augmented BNF and generic
+ constructs defined by David H. Crocker for RFC 822 [9]. Similarly, it
+ reuses many of the definitions provided by Nathaniel Borenstein and
+ Ned Freed for MIME [7]. We hope that their inclusion in this
+ specification will help reduce past confusion over the relationship
+ between HTTP and Internet mail message formats.
+
+ The HTTP protocol has evolved considerably over the years. It has
+ benefited from a large and active developer community--the many
+ people who have participated on the www-talk mailing list--and it is
+ that community which has been most responsible for the success of
+ HTTP and of the World-Wide Web in general. Marc Andreessen, Robert
+ Cailliau, Daniel W. Connolly, Bob Denny, John Franks, Jean-Francois
+ Groff, Phillip M. Hallam-Baker, Hakon W. Lie, Ari Luotonen, Rob
+ McCool, Lou Montulli, Dave Raggett, Tony Sanders, and Marc
+ VanHeyningen deserve special recognition for their efforts in
+ defining early aspects of the protocol.
+
+ This document has benefited greatly from the comments of all those
+ participating in the HTTP-WG. In addition to those already mentioned,
+ the following individuals have contributed to this specification:
+
+
+
+Fielding, et al. Standards Track [Page 156]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ Gary Adams Ross Patterson
+ Harald Tveit Alvestrand Albert Lunde
+ Keith Ball John C. Mallery
+ Brian Behlendorf Jean-Philippe Martin-Flatin
+ Paul Burchard Mitra
+ Maurizio Codogno David Morris
+ Mike Cowlishaw Gavin Nicol
+ Roman Czyborra Bill Perry
+ Michael A. Dolan Jeffrey Perry
+ David J. Fiander Scott Powers
+ Alan Freier Owen Rees
+ Marc Hedlund Luigi Rizzo
+ Greg Herlihy David Robinson
+ Koen Holtman Marc Salomon
+ Alex Hopmann Rich Salz
+ Bob Jernigan Allan M. Schiffman
+ Shel Kaphan Jim Seidman
+ Rohit Khare Chuck Shotton
+ John Klensin Eric W. Sink
+ Martijn Koster Simon E. Spero
+ Alexei Kosut Richard N. Taylor
+ David M. Kristol Robert S. Thau
+ Daniel LaLiberte Bill (BearHeart) Weinman
+ Ben Laurie Francois Yergeau
+ Paul J. Leach Mary Ellen Zurko
+ Daniel DuBois Josh Cohen
+
+
+ Much of the content and presentation of the caching design is due to
+ suggestions and comments from individuals including: Shel Kaphan,
+ Paul Leach, Koen Holtman, David Morris, and Larry Masinter.
+
+ Most of the specification of ranges is based on work originally done
+ by Ari Luotonen and John Franks, with additional input from Steve
+ Zilles.
+
+ Thanks to the "cave men" of Palo Alto. You know who you are.
+
+ Jim Gettys (the current editor of this document) wishes particularly
+ to thank Roy Fielding, the previous editor of this document, along
+ with John Klensin, Jeff Mogul, Paul Leach, Dave Kristol, Koen
+ Holtman, John Franks, Josh Cohen, Alex Hopmann, Scott Lawrence, and
+ Larry Masinter for their help. And thanks go particularly to Jeff
+ Mogul and Scott Lawrence for performing the "MUST/MAY/SHOULD" audit.
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 157]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ The Apache Group, Anselm Baird-Smith, author of Jigsaw, and Henrik
+ Frystyk implemented RFC 2068 early, and we wish to thank them for the
+ discovery of many of the problems that this document attempts to
+ rectify.
+
+17 References
+
+ [1] Alvestrand, H., "Tags for the Identification of Languages", RFC
+ 1766, March 1995.
+
+ [2] Anklesaria, F., McCahill, M., Lindner, P., Johnson, D., Torrey,
+ D. and B. Alberti, "The Internet Gopher Protocol (a distributed
+ document search and retrieval protocol)", RFC 1436, March 1993.
+
+ [3] Berners-Lee, T., "Universal Resource Identifiers in WWW", RFC
+ 1630, June 1994.
+
+ [4] Berners-Lee, T., Masinter, L. and M. McCahill, "Uniform Resource
+ Locators (URL)", RFC 1738, December 1994.
+
+ [5] Berners-Lee, T. and D. Connolly, "Hypertext Markup Language -
+ 2.0", RFC 1866, November 1995.
+
+ [6] Berners-Lee, T., Fielding, R. and H. Frystyk, "Hypertext Transfer
+ Protocol -- HTTP/1.0", RFC 1945, May 1996.
+
+ [7] Freed, N. and N. Borenstein, "Multipurpose Internet Mail
+ Extensions (MIME) Part One: Format of Internet Message Bodies",
+ RFC 2045, November 1996.
+
+ [8] Braden, R., "Requirements for Internet Hosts -- Communication
+ Layers", STD 3, RFC 1123, October 1989.
+
+ [9] Crocker, D., "Standard for The Format of ARPA Internet Text
+ Messages", STD 11, RFC 822, August 1982.
+
+ [10] Davis, F., Kahle, B., Morris, H., Salem, J., Shen, T., Wang, R.,
+ Sui, J., and M. Grinbaum, "WAIS Interface Protocol Prototype
+ Functional Specification," (v1.5), Thinking Machines
+ Corporation, April 1990.
+
+ [11] Fielding, R., "Relative Uniform Resource Locators", RFC 1808,
+ June 1995.
+
+ [12] Horton, M. and R. Adams, "Standard for Interchange of USENET
+ Messages", RFC 1036, December 1987.
+
+
+
+
+
+Fielding, et al. Standards Track [Page 158]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ [13] Kantor, B. and P. Lapsley, "Network News Transfer Protocol", RFC
+ 977, February 1986.
+
+ [14] Moore, K., "MIME (Multipurpose Internet Mail Extensions) Part
+ Three: Message Header Extensions for Non-ASCII Text", RFC 2047,
+ November 1996.
+
+ [15] Nebel, E. and L. Masinter, "Form-based File Upload in HTML", RFC
+ 1867, November 1995.
+
+ [16] Postel, J., "Simple Mail Transfer Protocol", STD 10, RFC 821,
+ August 1982.
+
+ [17] Postel, J., "Media Type Registration Procedure", RFC 1590,
+ November 1996.
+
+ [18] Postel, J. and J. Reynolds, "File Transfer Protocol", STD 9, RFC
+ 959, October 1985.
+
+ [19] Reynolds, J. and J. Postel, "Assigned Numbers", STD 2, RFC 1700,
+ October 1994.
+
+ [20] Sollins, K. and L. Masinter, "Functional Requirements for
+ Uniform Resource Names", RFC 1737, December 1994.
+
+ [21] US-ASCII. Coded Character Set - 7-Bit American Standard Code for
+ Information Interchange. Standard ANSI X3.4-1986, ANSI, 1986.
+
+ [22] ISO-8859. International Standard -- Information Processing --
+ 8-bit Single-Byte Coded Graphic Character Sets --
+ Part 1: Latin alphabet No. 1, ISO-8859-1:1987.
+ Part 2: Latin alphabet No. 2, ISO-8859-2, 1987.
+ Part 3: Latin alphabet No. 3, ISO-8859-3, 1988.
+ Part 4: Latin alphabet No. 4, ISO-8859-4, 1988.
+ Part 5: Latin/Cyrillic alphabet, ISO-8859-5, 1988.
+ Part 6: Latin/Arabic alphabet, ISO-8859-6, 1987.
+ Part 7: Latin/Greek alphabet, ISO-8859-7, 1987.
+ Part 8: Latin/Hebrew alphabet, ISO-8859-8, 1988.
+ Part 9: Latin alphabet No. 5, ISO-8859-9, 1990.
+
+ [23] Meyers, J. and M. Rose, "The Content-MD5 Header Field", RFC
+ 1864, October 1995.
+
+ [24] Carpenter, B. and Y. Rekhter, "Renumbering Needs Work", RFC
+ 1900, February 1996.
+
+ [25] Deutsch, P., "GZIP file format specification version 4.3", RFC
+ 1952, May 1996.
+
+
+
+Fielding, et al. Standards Track [Page 159]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ [26] Venkata N. Padmanabhan, and Jeffrey C. Mogul. "Improving HTTP
+ Latency", Computer Networks and ISDN Systems, v. 28, pp. 25-35,
+ Dec. 1995. Slightly revised version of paper in Proc. 2nd
+ International WWW Conference '94: Mosaic and the Web, Oct. 1994,
+ which is available at
+ http://www.ncsa.uiuc.edu/SDG/IT94/Proceedings/DDay/mogul/HTTPLat
+ ency.html.
+
+ [27] Joe Touch, John Heidemann, and Katia Obraczka. "Analysis of HTTP
+ Performance", <URL: http://www.isi.edu/touch/pubs/http-perf96/>,
+ ISI Research Report ISI/RR-98-463, (original report dated Aug.
+ 1996), USC/Information Sciences Institute, August 1998.
+
+ [28] Mills, D., "Network Time Protocol (Version 3) Specification,
+ Implementation and Analysis", RFC 1305, March 1992.
+
+ [29] Deutsch, P., "DEFLATE Compressed Data Format Specification
+ version 1.3", RFC 1951, May 1996.
+
+ [30] S. Spero, "Analysis of HTTP Performance Problems,"
+ http://sunsite.unc.edu/mdma-release/http-prob.html.
+
+ [31] Deutsch, P. and J. Gailly, "ZLIB Compressed Data Format
+ Specification version 3.3", RFC 1950, May 1996.
+
+ [32] Franks, J., Hallam-Baker, P., Hostetler, J., Leach, P.,
+ Luotonen, A., Sink, E. and L. Stewart, "An Extension to HTTP:
+ Digest Access Authentication", RFC 2069, January 1997.
+
+ [33] Fielding, R., Gettys, J., Mogul, J., Frystyk, H. and T.
+ Berners-Lee, "Hypertext Transfer Protocol -- HTTP/1.1", RFC
+ 2068, January 1997.
+
+ [34] Bradner, S., "Key words for use in RFCs to Indicate Requirement
+ Levels", BCP 14, RFC 2119, March 1997.
+
+ [35] Troost, R. and Dorner, S., "Communicating Presentation
+ Information in Internet Messages: The Content-Disposition
+ Header", RFC 1806, June 1995.
+
+ [36] Mogul, J., Fielding, R., Gettys, J. and H. Frystyk, "Use and
+ Interpretation of HTTP Version Numbers", RFC 2145, May 1997.
+ [jg639]
+
+ [37] Palme, J., "Common Internet Message Headers", RFC 2076, February
+ 1997. [jg640]
+
+
+
+
+
+Fielding, et al. Standards Track [Page 160]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ [38] Yergeau, F., "UTF-8, a transformation format of Unicode and
+ ISO-10646", RFC 2279, January 1998. [jg641]
+
+ [39] Nielsen, H.F., Gettys, J., Baird-Smith, A., Prud'hommeaux, E.,
+ Lie, H., and C. Lilley. "Network Performance Effects of
+ HTTP/1.1, CSS1, and PNG," Proceedings of ACM SIGCOMM '97, Cannes
+ France, September 1997.[jg642]
+
+ [40] Freed, N. and N. Borenstein, "Multipurpose Internet Mail
+ Extensions (MIME) Part Two: Media Types", RFC 2046, November
+ 1996. [jg643]
+
+ [41] Alvestrand, H., "IETF Policy on Character Sets and Languages",
+ BCP 18, RFC 2277, January 1998. [jg644]
+
+ [42] Berners-Lee, T., Fielding, R. and L. Masinter, "Uniform Resource
+ Identifiers (URI): Generic Syntax and Semantics", RFC 2396,
+ August 1998. [jg645]
+
+ [43] Franks, J., Hallam-Baker, P., Hostetler, J., Lawrence, S.,
+ Leach, P., Luotonen, A., Sink, E. and L. Stewart, "HTTP
+ Authentication: Basic and Digest Access Authentication", RFC
+ 2617, June 1999. [jg646]
+
+ [44] Luotonen, A., "Tunneling TCP based protocols through Web proxy
+ servers," Work in Progress. [jg647]
+
+ [45] Palme, J. and A. Hopmann, "MIME E-mail Encapsulation of
+ Aggregate Documents, such as HTML (MHTML)", RFC 2110, March
+ 1997.
+
+ [46] Bradner, S., "The Internet Standards Process -- Revision 3", BCP
+ 9, RFC 2026, October 1996.
+
+ [47] Masinter, L., "Hyper Text Coffee Pot Control Protocol
+ (HTCPCP/1.0)", RFC 2324, 1 April 1998.
+
+ [48] Freed, N. and N. Borenstein, "Multipurpose Internet Mail
+ Extensions (MIME) Part Five: Conformance Criteria and Examples",
+ RFC 2049, November 1996.
+
+ [49] Troost, R., Dorner, S. and K. Moore, "Communicating Presentation
+ Information in Internet Messages: The Content-Disposition Header
+ Field", RFC 2183, August 1997.
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 161]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+18 Authors' Addresses
+
+ Roy T. Fielding
+ Information and Computer Science
+ University of California, Irvine
+ Irvine, CA 92697-3425, USA
+
+ Fax: +1 (949) 824-1715
+ EMail: fielding@ics.uci.edu
+
+
+ James Gettys
+ World Wide Web Consortium
+ MIT Laboratory for Computer Science
+ 545 Technology Square
+ Cambridge, MA 02139, USA
+
+ Fax: +1 (617) 258 8682
+ EMail: jg@w3.org
+
+
+ Jeffrey C. Mogul
+ Western Research Laboratory
+ Compaq Computer Corporation
+ 250 University Avenue
+ Palo Alto, California, 94305, USA
+
+ EMail: mogul@wrl.dec.com
+
+
+ Henrik Frystyk Nielsen
+ World Wide Web Consortium
+ MIT Laboratory for Computer Science
+ 545 Technology Square
+ Cambridge, MA 02139, USA
+
+ Fax: +1 (617) 258 8682
+ EMail: frystyk@w3.org
+
+
+ Larry Masinter
+ Xerox Corporation
+ 3333 Coyote Hill Road
+ Palo Alto, CA 94034, USA
+
+ EMail: masinter@parc.xerox.com
+
+
+
+
+
+Fielding, et al. Standards Track [Page 162]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ Paul J. Leach
+ Microsoft Corporation
+ 1 Microsoft Way
+ Redmond, WA 98052, USA
+
+ EMail: paulle@microsoft.com
+
+
+ Tim Berners-Lee
+ Director, World Wide Web Consortium
+ MIT Laboratory for Computer Science
+ 545 Technology Square
+ Cambridge, MA 02139, USA
+
+ Fax: +1 (617) 258 8682
+ EMail: timbl@w3.org
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 163]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+19 Appendices
+
+19.1 Internet Media Type message/http and application/http
+
+ In addition to defining the HTTP/1.1 protocol, this document serves
+ as the specification for the Internet media type "message/http" and
+ "application/http". The message/http type can be used to enclose a
+ single HTTP request or response message, provided that it obeys the
+ MIME restrictions for all "message" types regarding line length and
+ encodings. The application/http type can be used to enclose a
+ pipeline of one or more HTTP request or response messages (not
+ intermixed). The following is to be registered with IANA [17].
+
+ Media Type name: message
+ Media subtype name: http
+ Required parameters: none
+ Optional parameters: version, msgtype
+ version: The HTTP-Version number of the enclosed message
+ (e.g., "1.1"). If not present, the version can be
+ determined from the first line of the body.
+ msgtype: The message type -- "request" or "response". If not
+ present, the type can be determined from the first
+ line of the body.
+ Encoding considerations: only "7bit", "8bit", or "binary" are
+ permitted
+ Security considerations: none
+
+ Media Type name: application
+ Media subtype name: http
+ Required parameters: none
+ Optional parameters: version, msgtype
+ version: The HTTP-Version number of the enclosed messages
+ (e.g., "1.1"). If not present, the version can be
+ determined from the first line of the body.
+ msgtype: The message type -- "request" or "response". If not
+ present, the type can be determined from the first
+ line of the body.
+ Encoding considerations: HTTP messages enclosed by this type
+ are in "binary" format; use of an appropriate
+ Content-Transfer-Encoding is required when
+ transmitted via E-mail.
+ Security considerations: none
+
+
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 164]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+19.2 Internet Media Type multipart/byteranges
+
+ When an HTTP 206 (Partial Content) response message includes the
+ content of multiple ranges (a response to a request for multiple
+ non-overlapping ranges), these are transmitted as a multipart
+ message-body. The media type for this purpose is called
+ "multipart/byteranges".
+
+ The multipart/byteranges media type includes two or more parts, each
+ with its own Content-Type and Content-Range fields. The required
+ boundary parameter specifies the boundary string used to separate
+ each body-part.
+
+ Media Type name: multipart
+ Media subtype name: byteranges
+ Required parameters: boundary
+ Optional parameters: none
+ Encoding considerations: only "7bit", "8bit", or "binary" are
+ permitted
+ Security considerations: none
+
+
+ For example:
+
+ HTTP/1.1 206 Partial Content
+ Date: Wed, 15 Nov 1995 06:25:24 GMT
+ Last-Modified: Wed, 15 Nov 1995 04:58:08 GMT
+ Content-type: multipart/byteranges; boundary=THIS_STRING_SEPARATES
+
+ --THIS_STRING_SEPARATES
+ Content-type: application/pdf
+ Content-range: bytes 500-999/8000
+
+ ...the first range...
+ --THIS_STRING_SEPARATES
+ Content-type: application/pdf
+ Content-range: bytes 7000-7999/8000
+
+ ...the second range
+ --THIS_STRING_SEPARATES--
+
+ Notes:
+
+ 1) Additional CRLFs may precede the first boundary string in the
+ entity.
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 165]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ 2) Although RFC 2046 [40] permits the boundary string to be
+ quoted, some existing implementations handle a quoted boundary
+ string incorrectly.
+
+ 3) A number of browsers and servers were coded to an early draft
+ of the byteranges specification to use a media type of
+ multipart/x-byteranges, which is almost, but not quite
+ compatible with the version documented in HTTP/1.1.
+
+19.3 Tolerant Applications
+
+ Although this document specifies the requirements for the generation
+ of HTTP/1.1 messages, not all applications will be correct in their
+ implementation. We therefore recommend that operational applications
+ be tolerant of deviations whenever those deviations can be
+ interpreted unambiguously.
+
+ Clients SHOULD be tolerant in parsing the Status-Line and servers
+ tolerant when parsing the Request-Line. In particular, they SHOULD
+ accept any amount of SP or HT characters between fields, even though
+ only a single SP is required.
+
+ The line terminator for message-header fields is the sequence CRLF.
+ However, we recommend that applications, when parsing such headers,
+ recognize a single LF as a line terminator and ignore the leading CR.
+
+ The character set of an entity-body SHOULD be labeled as the lowest
+ common denominator of the character codes used within that body, with
+ the exception that not labeling the entity is preferred over labeling
+ the entity with the labels US-ASCII or ISO-8859-1. See section 3.7.1
+ and 3.4.1.
+
+ Additional rules for requirements on parsing and encoding of dates
+ and other potential problems with date encodings include:
+
+ - HTTP/1.1 clients and caches SHOULD assume that an RFC-850 date
+ which appears to be more than 50 years in the future is in fact
+ in the past (this helps solve the "year 2000" problem).
+
+ - An HTTP/1.1 implementation MAY internally represent a parsed
+ Expires date as earlier than the proper value, but MUST NOT
+ internally represent a parsed Expires date as later than the
+ proper value.
+
+ - All expiration-related calculations MUST be done in GMT. The
+ local time zone MUST NOT influence the calculation or comparison
+ of an age or expiration time.
+
+
+
+
+Fielding, et al. Standards Track [Page 166]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ - If an HTTP header incorrectly carries a date value with a time
+ zone other than GMT, it MUST be converted into GMT using the
+ most conservative possible conversion.
+
+19.4 Differences Between HTTP Entities and RFC 2045 Entities
+
+ HTTP/1.1 uses many of the constructs defined for Internet Mail (RFC
+ 822 [9]) and the Multipurpose Internet Mail Extensions (MIME [7]) to
+ allow entities to be transmitted in an open variety of
+ representations and with extensible mechanisms. However, RFC 2045
+ discusses mail, and HTTP has a few features that are different from
+ those described in RFC 2045. These differences were carefully chosen
+ to optimize performance over binary connections, to allow greater
+ freedom in the use of new media types, to make date comparisons
+ easier, and to acknowledge the practice of some early HTTP servers
+ and clients.
+
+ This appendix describes specific areas where HTTP differs from RFC
+ 2045. Proxies and gateways to strict MIME environments SHOULD be
+ aware of these differences and provide the appropriate conversions
+ where necessary. Proxies and gateways from MIME environments to HTTP
+ also need to be aware of the differences because some conversions
+ might be required.
+
+19.4.1 MIME-Version
+
+ HTTP is not a MIME-compliant protocol. However, HTTP/1.1 messages MAY
+ include a single MIME-Version general-header field to indicate what
+ version of the MIME protocol was used to construct the message. Use
+ of the MIME-Version header field indicates that the message is in
+ full compliance with the MIME protocol (as defined in RFC 2045[7]).
+ Proxies/gateways are responsible for ensuring full compliance (where
+ possible) when exporting HTTP messages to strict MIME environments.
+
+ MIME-Version = "MIME-Version" ":" 1*DIGIT "." 1*DIGIT
+
+ MIME version "1.0" is the default for use in HTTP/1.1. However,
+ HTTP/1.1 message parsing and semantics are defined by this document
+ and not the MIME specification.
+
+19.4.2 Conversion to Canonical Form
+
+ RFC 2045 [7] requires that an Internet mail entity be converted to
+ canonical form prior to being transferred, as described in section 4
+ of RFC 2049 [48]. Section 3.7.1 of this document describes the forms
+ allowed for subtypes of the "text" media type when transmitted over
+ HTTP. RFC 2046 requires that content with a type of "text" represent
+ line breaks as CRLF and forbids the use of CR or LF outside of line
+
+
+
+Fielding, et al. Standards Track [Page 167]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ break sequences. HTTP allows CRLF, bare CR, and bare LF to indicate a
+ line break within text content when a message is transmitted over
+ HTTP.
+
+ Where it is possible, a proxy or gateway from HTTP to a strict MIME
+ environment SHOULD translate all line breaks within the text media
+ types described in section 3.7.1 of this document to the RFC 2049
+ canonical form of CRLF. Note, however, that this might be complicated
+ by the presence of a Content-Encoding and by the fact that HTTP
+ allows the use of some character sets which do not use octets 13 and
+ 10 to represent CR and LF, as is the case for some multi-byte
+ character sets.
+
+ Implementors should note that conversion will break any cryptographic
+ checksums applied to the original content unless the original content
+ is already in canonical form. Therefore, the canonical form is
+ recommended for any content that uses such checksums in HTTP.
+
+19.4.3 Conversion of Date Formats
+
+ HTTP/1.1 uses a restricted set of date formats (section 3.3.1) to
+ simplify the process of date comparison. Proxies and gateways from
+ other protocols SHOULD ensure that any Date header field present in a
+ message conforms to one of the HTTP/1.1 formats and rewrite the date
+ if necessary.
+
+19.4.4 Introduction of Content-Encoding
+
+ RFC 2045 does not include any concept equivalent to HTTP/1.1's
+ Content-Encoding header field. Since this acts as a modifier on the
+ media type, proxies and gateways from HTTP to MIME-compliant
+ protocols MUST either change the value of the Content-Type header
+ field or decode the entity-body before forwarding the message. (Some
+ experimental applications of Content-Type for Internet mail have used
+ a media-type parameter of ";conversions=<content-coding>" to perform
+ a function equivalent to Content-Encoding. However, this parameter is
+ not part of RFC 2045.)
+
+19.4.5 No Content-Transfer-Encoding
+
+ HTTP does not use the Content-Transfer-Encoding (CTE) field of RFC
+ 2045. Proxies and gateways from MIME-compliant protocols to HTTP MUST
+ remove any non-identity CTE ("quoted-printable" or "base64") encoding
+ prior to delivering the response message to an HTTP client.
+
+ Proxies and gateways from HTTP to MIME-compliant protocols are
+ responsible for ensuring that the message is in the correct format
+ and encoding for safe transport on that protocol, where "safe
+
+
+
+Fielding, et al. Standards Track [Page 168]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ transport" is defined by the limitations of the protocol being used.
+ Such a proxy or gateway SHOULD label the data with an appropriate
+ Content-Transfer-Encoding if doing so will improve the likelihood of
+ safe transport over the destination protocol.
+
+19.4.6 Introduction of Transfer-Encoding
+
+ HTTP/1.1 introduces the Transfer-Encoding header field (section
+ 14.41). Proxies/gateways MUST remove any transfer-coding prior to
+ forwarding a message via a MIME-compliant protocol.
+
+ A process for decoding the "chunked" transfer-coding (section 3.6)
+ can be represented in pseudo-code as:
+
+ length := 0
+ read chunk-size, chunk-extension (if any) and CRLF
+ while (chunk-size > 0) {
+ read chunk-data and CRLF
+ append chunk-data to entity-body
+ length := length + chunk-size
+ read chunk-size and CRLF
+ }
+ read entity-header
+ while (entity-header not empty) {
+ append entity-header to existing header fields
+ read entity-header
+ }
+ Content-Length := length
+ Remove "chunked" from Transfer-Encoding
+
+19.4.7 MHTML and Line Length Limitations
+
+ HTTP implementations which share code with MHTML [45] implementations
+ need to be aware of MIME line length limitations. Since HTTP does not
+ have this limitation, HTTP does not fold long lines. MHTML messages
+ being transported by HTTP follow all conventions of MHTML, including
+ line length limitations and folding, canonicalization, etc., since
+ HTTP transports all message-bodies as payload (see section 3.7.2) and
+ does not interpret the content or any MIME header lines that might be
+ contained therein.
+
+19.5 Additional Features
+
+ RFC 1945 and RFC 2068 document protocol elements used by some
+ existing HTTP implementations, but not consistently and correctly
+ across most HTTP/1.1 applications. Implementors are advised to be
+ aware of these features, but cannot rely upon their presence in, or
+ interoperability with, other HTTP/1.1 applications. Some of these
+
+
+
+Fielding, et al. Standards Track [Page 169]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ describe proposed experimental features, and some describe features
+ that experimental deployment found lacking that are now addressed in
+ the base HTTP/1.1 specification.
+
+ A number of other headers, such as Content-Disposition and Title,
+ from SMTP and MIME are also often implemented (see RFC 2076 [37]).
+
+19.5.1 Content-Disposition
+
+ The Content-Disposition response-header field has been proposed as a
+ means for the origin server to suggest a default filename if the user
+ requests that the content is saved to a file. This usage is derived
+ from the definition of Content-Disposition in RFC 1806 [35].
+
+ content-disposition = "Content-Disposition" ":"
+ disposition-type *( ";" disposition-parm )
+ disposition-type = "attachment" | disp-extension-token
+ disposition-parm = filename-parm | disp-extension-parm
+ filename-parm = "filename" "=" quoted-string
+ disp-extension-token = token
+ disp-extension-parm = token "=" ( token | quoted-string )
+
+ An example is
+
+ Content-Disposition: attachment; filename="fname.ext"
+
+ The receiving user agent SHOULD NOT respect any directory path
+ information present in the filename-parm parameter, which is the only
+ parameter believed to apply to HTTP implementations at this time. The
+ filename SHOULD be treated as a terminal component only.
+
+ If this header is used in a response with the application/octet-
+ stream content-type, the implied suggestion is that the user agent
+ should not display the response, but directly enter a `save response
+ as...' dialog.
+
+ See section 15.5 for Content-Disposition security issues.
+
+19.6 Compatibility with Previous Versions
+
+ It is beyond the scope of a protocol specification to mandate
+ compliance with previous versions. HTTP/1.1 was deliberately
+ designed, however, to make supporting previous versions easy. It is
+ worth noting that, at the time of composing this specification
+ (1996), we would expect commercial HTTP/1.1 servers to:
+
+ - recognize the format of the Request-Line for HTTP/0.9, 1.0, and
+ 1.1 requests;
+
+
+
+Fielding, et al. Standards Track [Page 170]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ - understand any valid request in the format of HTTP/0.9, 1.0, or
+ 1.1;
+
+ - respond appropriately with a message in the same major version
+ used by the client.
+
+ And we would expect HTTP/1.1 clients to:
+
+ - recognize the format of the Status-Line for HTTP/1.0 and 1.1
+ responses;
+
+ - understand any valid response in the format of HTTP/0.9, 1.0, or
+ 1.1.
+
+ For most implementations of HTTP/1.0, each connection is established
+ by the client prior to the request and closed by the server after
+ sending the response. Some implementations implement the Keep-Alive
+ version of persistent connections described in section 19.7.1 of RFC
+ 2068 [33].
+
+19.6.1 Changes from HTTP/1.0
+
+ This section summarizes major differences between versions HTTP/1.0
+ and HTTP/1.1.
+
+19.6.1.1 Changes to Simplify Multi-homed Web Servers and Conserve IP
+ Addresses
+
+ The requirements that clients and servers support the Host request-
+ header, report an error if the Host request-header (section 14.23) is
+ missing from an HTTP/1.1 request, and accept absolute URIs (section
+ 5.1.2) are among the most important changes defined by this
+ specification.
+
+ Older HTTP/1.0 clients assumed a one-to-one relationship of IP
+ addresses and servers; there was no other established mechanism for
+ distinguishing the intended server of a request than the IP address
+ to which that request was directed. The changes outlined above will
+ allow the Internet, once older HTTP clients are no longer common, to
+ support multiple Web sites from a single IP address, greatly
+ simplifying large operational Web servers, where allocation of many
+ IP addresses to a single host has created serious problems. The
+ Internet will also be able to recover the IP addresses that have been
+ allocated for the sole purpose of allowing special-purpose domain
+ names to be used in root-level HTTP URLs. Given the rate of growth of
+ the Web, and the number of servers already deployed, it is extremely
+
+
+
+
+
+Fielding, et al. Standards Track [Page 171]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ important that all implementations of HTTP (including updates to
+ existing HTTP/1.0 applications) correctly implement these
+ requirements:
+
+ - Both clients and servers MUST support the Host request-header.
+
+ - A client that sends an HTTP/1.1 request MUST send a Host header.
+
+ - Servers MUST report a 400 (Bad Request) error if an HTTP/1.1
+ request does not include a Host request-header.
+
+ - Servers MUST accept absolute URIs.
+
+19.6.2 Compatibility with HTTP/1.0 Persistent Connections
+
+ Some clients and servers might wish to be compatible with some
+ previous implementations of persistent connections in HTTP/1.0
+ clients and servers. Persistent connections in HTTP/1.0 are
+ explicitly negotiated as they are not the default behavior. HTTP/1.0
+ experimental implementations of persistent connections are faulty,
+ and the new facilities in HTTP/1.1 are designed to rectify these
+ problems. The problem was that some existing 1.0 clients may be
+ sending Keep-Alive to a proxy server that doesn't understand
+ Connection, which would then erroneously forward it to the next
+ inbound server, which would establish the Keep-Alive connection and
+ result in a hung HTTP/1.0 proxy waiting for the close on the
+ response. The result is that HTTP/1.0 clients must be prevented from
+ using Keep-Alive when talking to proxies.
+
+ However, talking to proxies is the most important use of persistent
+ connections, so that prohibition is clearly unacceptable. Therefore,
+ we need some other mechanism for indicating a persistent connection
+ is desired, which is safe to use even when talking to an old proxy
+ that ignores Connection. Persistent connections are the default for
+ HTTP/1.1 messages; we introduce a new keyword (Connection: close) for
+ declaring non-persistence. See section 14.10.
+
+ The original HTTP/1.0 form of persistent connections (the Connection:
+ Keep-Alive and Keep-Alive header) is documented in RFC 2068. [33]
+
+19.6.3 Changes from RFC 2068
+
+ This specification has been carefully audited to correct and
+ disambiguate key word usage; RFC 2068 had many problems in respect to
+ the conventions laid out in RFC 2119 [34].
+
+ Clarified which error code should be used for inbound server failures
+ (e.g. DNS failures). (Section 10.5.5).
+
+
+
+Fielding, et al. Standards Track [Page 172]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ CREATE had a race that required an Etag be sent when a resource is
+ first created. (Section 10.2.2).
+
+ Content-Base was deleted from the specification: it was not
+ implemented widely, and there is no simple, safe way to introduce it
+ without a robust extension mechanism. In addition, it is used in a
+ similar, but not identical fashion in MHTML [45].
+
+ Transfer-coding and message lengths all interact in ways that
+ required fixing exactly when chunked encoding is used (to allow for
+ transfer encoding that may not be self delimiting); it was important
+ to straighten out exactly how message lengths are computed. (Sections
+ 3.6, 4.4, 7.2.2, 13.5.2, 14.13, 14.16)
+
+ A content-coding of "identity" was introduced, to solve problems
+ discovered in caching. (section 3.5)
+
+ Quality Values of zero should indicate that "I don't want something"
+ to allow clients to refuse a representation. (Section 3.9)
+
+ The use and interpretation of HTTP version numbers has been clarified
+ by RFC 2145. Require proxies to upgrade requests to highest protocol
+ version they support to deal with problems discovered in HTTP/1.0
+ implementations (Section 3.1)
+
+ Charset wildcarding is introduced to avoid explosion of character set
+ names in accept headers. (Section 14.2)
+
+ A case was missed in the Cache-Control model of HTTP/1.1; s-maxage
+ was introduced to add this missing case. (Sections 13.4, 14.8, 14.9,
+ 14.9.3)
+
+ The Cache-Control: max-age directive was not properly defined for
+ responses. (Section 14.9.3)
+
+ There are situations where a server (especially a proxy) does not
+ know the full length of a response but is capable of serving a
+ byterange request. We therefore need a mechanism to allow byteranges
+ with a content-range not indicating the full length of the message.
+ (Section 14.16)
+
+ Range request responses would become very verbose if all meta-data
+ were always returned; by allowing the server to only send needed
+ headers in a 206 response, this problem can be avoided. (Section
+ 10.2.7, 13.5.3, and 14.27)
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 173]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ Fix problem with unsatisfiable range requests; there are two cases:
+ syntactic problems, and range doesn't exist in the document. The 416
+ status code was needed to resolve this ambiguity needed to indicate
+ an error for a byte range request that falls outside of the actual
+ contents of a document. (Section 10.4.17, 14.16)
+
+ Rewrite of message transmission requirements to make it much harder
+ for implementors to get it wrong, as the consequences of errors here
+ can have significant impact on the Internet, and to deal with the
+ following problems:
+
+ 1. Changing "HTTP/1.1 or later" to "HTTP/1.1", in contexts where
+ this was incorrectly placing a requirement on the behavior of
+ an implementation of a future version of HTTP/1.x
+
+ 2. Made it clear that user-agents should retry requests, not
+ "clients" in general.
+
+ 3. Converted requirements for clients to ignore unexpected 100
+ (Continue) responses, and for proxies to forward 100 responses,
+ into a general requirement for 1xx responses.
+
+ 4. Modified some TCP-specific language, to make it clearer that
+ non-TCP transports are possible for HTTP.
+
+ 5. Require that the origin server MUST NOT wait for the request
+ body before it sends a required 100 (Continue) response.
+
+ 6. Allow, rather than require, a server to omit 100 (Continue) if
+ it has already seen some of the request body.
+
+ 7. Allow servers to defend against denial-of-service attacks and
+ broken clients.
+
+ This change adds the Expect header and 417 status code. The message
+ transmission requirements fixes are in sections 8.2, 10.4.18,
+ 8.1.2.2, 13.11, and 14.20.
+
+ Proxies should be able to add Content-Length when appropriate.
+ (Section 13.5.2)
+
+ Clean up confusion between 403 and 404 responses. (Section 10.4.4,
+ 10.4.5, and 10.4.11)
+
+ Warnings could be cached incorrectly, or not updated appropriately.
+ (Section 13.1.2, 13.2.4, 13.5.2, 13.5.3, 14.9.3, and 14.46) Warning
+ also needed to be a general header, as PUT or other methods may have
+ need for it in requests.
+
+
+
+Fielding, et al. Standards Track [Page 174]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ Transfer-coding had significant problems, particularly with
+ interactions with chunked encoding. The solution is that transfer-
+ codings become as full fledged as content-codings. This involves
+ adding an IANA registry for transfer-codings (separate from content
+ codings), a new header field (TE) and enabling trailer headers in the
+ future. Transfer encoding is a major performance benefit, so it was
+ worth fixing [39]. TE also solves another, obscure, downward
+ interoperability problem that could have occurred due to interactions
+ between authentication trailers, chunked encoding and HTTP/1.0
+ clients.(Section 3.6, 3.6.1, and 14.39)
+
+ The PATCH, LINK, UNLINK methods were defined but not commonly
+ implemented in previous versions of this specification. See RFC 2068
+ [33].
+
+ The Alternates, Content-Version, Derived-From, Link, URI, Public and
+ Content-Base header fields were defined in previous versions of this
+ specification, but not commonly implemented. See RFC 2068 [33].
+
+20 Index
+
+ Please see the PostScript version of this RFC for the INDEX.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 175]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+21. Full Copyright Statement
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 176]
+
diff --git a/standards/rfc2617.txt b/standards/rfc2617.txt
new file mode 100644
index 000000000..771aa924a
--- /dev/null
+++ b/standards/rfc2617.txt
@@ -0,0 +1,1907 @@
+
+
+
+
+
+
+Network Working Group J. Franks
+Request for Comments: 2617 Northwestern University
+Obsoletes: 2069 P. Hallam-Baker
+Category: Standards Track Verisign, Inc.
+ J. Hostetler
+ AbiSource, Inc.
+ S. Lawrence
+ Agranat Systems, Inc.
+ P. Leach
+ Microsoft Corporation
+ A. Luotonen
+ Netscape Communications Corporation
+ L. Stewart
+ Open Market, Inc.
+ June 1999
+
+
+ HTTP Authentication: Basic and Digest Access Authentication
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+Abstract
+
+ "HTTP/1.0", includes the specification for a Basic Access
+ Authentication scheme. This scheme is not considered to be a secure
+ method of user authentication (unless used in conjunction with some
+ external secure system such as SSL [5]), as the user name and
+ password are passed over the network as cleartext.
+
+ This document also provides the specification for HTTP's
+ authentication framework, the original Basic authentication scheme
+ and a scheme based on cryptographic hashes, referred to as "Digest
+ Access Authentication". It is therefore also intended to serve as a
+ replacement for RFC 2069 [6]. Some optional elements specified by
+ RFC 2069 have been removed from this specification due to problems
+ found since its publication; other new elements have been added for
+ compatibility, those new elements have been made optional, but are
+ strongly recommended.
+
+
+
+Franks, et al. Standards Track [Page 1]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ Like Basic, Digest access authentication verifies that both parties
+ to a communication know a shared secret (a password); unlike Basic,
+ this verification can be done without sending the password in the
+ clear, which is Basic's biggest weakness. As with most other
+ authentication protocols, the greatest sources of risks are usually
+ found not in the core protocol itself but in policies and procedures
+ surrounding its use.
+
+Table of Contents
+
+ 1 Access Authentication................................ 3
+ 1.1 Reliance on the HTTP/1.1 Specification............ 3
+ 1.2 Access Authentication Framework................... 3
+ 2 Basic Authentication Scheme.......................... 5
+ 3 Digest Access Authentication Scheme.................. 6
+ 3.1 Introduction...................................... 6
+ 3.1.1 Purpose......................................... 6
+ 3.1.2 Overall Operation............................... 6
+ 3.1.3 Representation of digest values................. 7
+ 3.1.4 Limitations..................................... 7
+ 3.2 Specification of Digest Headers................... 7
+ 3.2.1 The WWW-Authenticate Response Header............ 8
+ 3.2.2 The Authorization Request Header................ 11
+ 3.2.3 The Authentication-Info Header.................. 15
+ 3.3 Digest Operation.................................. 17
+ 3.4 Security Protocol Negotiation..................... 18
+ 3.5 Example........................................... 18
+ 3.6 Proxy-Authentication and Proxy-Authorization...... 19
+ 4 Security Considerations.............................. 19
+ 4.1 Authentication of Clients using Basic
+ Authentication.................................... 19
+ 4.2 Authentication of Clients using Digest
+ Authentication.................................... 20
+ 4.3 Limited Use Nonce Values.......................... 21
+ 4.4 Comparison of Digest with Basic Authentication.... 22
+ 4.5 Replay Attacks.................................... 22
+ 4.6 Weakness Created by Multiple Authentication
+ Schemes........................................... 23
+ 4.7 Online dictionary attacks......................... 23
+ 4.8 Man in the Middle................................. 24
+ 4.9 Chosen plaintext attacks.......................... 24
+ 4.10 Precomputed dictionary attacks.................... 25
+ 4.11 Batch brute force attacks......................... 25
+ 4.12 Spoofing by Counterfeit Servers................... 25
+ 4.13 Storing passwords................................. 26
+ 4.14 Summary........................................... 26
+ 5 Sample implementation................................ 27
+ 6 Acknowledgments...................................... 31
+
+
+
+Franks, et al. Standards Track [Page 2]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ 7 References........................................... 31
+ 8 Authors' Addresses................................... 32
+ 9 Full Copyright Statement............................. 34
+
+1 Access Authentication
+
+1.1 Reliance on the HTTP/1.1 Specification
+
+ This specification is a companion to the HTTP/1.1 specification [2].
+ It uses the augmented BNF section 2.1 of that document, and relies on
+ both the non-terminals defined in that document and other aspects of
+ the HTTP/1.1 specification.
+
+1.2 Access Authentication Framework
+
+ HTTP provides a simple challenge-response authentication mechanism
+ that MAY be used by a server to challenge a client request and by a
+ client to provide authentication information. It uses an extensible,
+ case-insensitive token to identify the authentication scheme,
+ followed by a comma-separated list of attribute-value pairs which
+ carry the parameters necessary for achieving authentication via that
+ scheme.
+
+ auth-scheme = token
+ auth-param = token "=" ( token | quoted-string )
+
+ The 401 (Unauthorized) response message is used by an origin server
+ to challenge the authorization of a user agent. This response MUST
+ include a WWW-Authenticate header field containing at least one
+ challenge applicable to the requested resource. The 407 (Proxy
+ Authentication Required) response message is used by a proxy to
+ challenge the authorization of a client and MUST include a Proxy-
+ Authenticate header field containing at least one challenge
+ applicable to the proxy for the requested resource.
+
+ challenge = auth-scheme 1*SP 1#auth-param
+
+ Note: User agents will need to take special care in parsing the WWW-
+ Authenticate or Proxy-Authenticate header field value if it contains
+ more than one challenge, or if more than one WWW-Authenticate header
+ field is provided, since the contents of a challenge may itself
+ contain a comma-separated list of authentication parameters.
+
+ The authentication parameter realm is defined for all authentication
+ schemes:
+
+ realm = "realm" "=" realm-value
+ realm-value = quoted-string
+
+
+
+Franks, et al. Standards Track [Page 3]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ The realm directive (case-insensitive) is required for all
+ authentication schemes that issue a challenge. The realm value
+ (case-sensitive), in combination with the canonical root URL (the
+ absoluteURI for the server whose abs_path is empty; see section 5.1.2
+ of [2]) of the server being accessed, defines the protection space.
+ These realms allow the protected resources on a server to be
+ partitioned into a set of protection spaces, each with its own
+ authentication scheme and/or authorization database. The realm value
+ is a string, generally assigned by the origin server, which may have
+ additional semantics specific to the authentication scheme. Note that
+ there may be multiple challenges with the same auth-scheme but
+ different realms.
+
+ A user agent that wishes to authenticate itself with an origin
+ server--usually, but not necessarily, after receiving a 401
+ (Unauthorized)--MAY do so by including an Authorization header field
+ with the request. A client that wishes to authenticate itself with a
+ proxy--usually, but not necessarily, after receiving a 407 (Proxy
+ Authentication Required)--MAY do so by including a Proxy-
+ Authorization header field with the request. Both the Authorization
+ field value and the Proxy-Authorization field value consist of
+ credentials containing the authentication information of the client
+ for the realm of the resource being requested. The user agent MUST
+ choose to use one of the challenges with the strongest auth-scheme it
+ understands and request credentials from the user based upon that
+ challenge.
+
+ credentials = auth-scheme #auth-param
+
+ Note that many browsers will only recognize Basic and will require
+ that it be the first auth-scheme presented. Servers should only
+ include Basic if it is minimally acceptable.
+
+ The protection space determines the domain over which credentials can
+ be automatically applied. If a prior request has been authorized, the
+ same credentials MAY be reused for all other requests within that
+ protection space for a period of time determined by the
+ authentication scheme, parameters, and/or user preference. Unless
+ otherwise defined by the authentication scheme, a single protection
+ space cannot extend outside the scope of its server.
+
+ If the origin server does not wish to accept the credentials sent
+ with a request, it SHOULD return a 401 (Unauthorized) response. The
+ response MUST include a WWW-Authenticate header field containing at
+ least one (possibly new) challenge applicable to the requested
+ resource. If a proxy does not accept the credentials sent with a
+ request, it SHOULD return a 407 (Proxy Authentication Required). The
+ response MUST include a Proxy-Authenticate header field containing a
+
+
+
+Franks, et al. Standards Track [Page 4]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ (possibly new) challenge applicable to the proxy for the requested
+ resource.
+
+ The HTTP protocol does not restrict applications to this simple
+ challenge-response mechanism for access authentication. Additional
+ mechanisms MAY be used, such as encryption at the transport level or
+ via message encapsulation, and with additional header fields
+ specifying authentication information. However, these additional
+ mechanisms are not defined by this specification.
+
+ Proxies MUST be completely transparent regarding user agent
+ authentication by origin servers. That is, they must forward the
+ WWW-Authenticate and Authorization headers untouched, and follow the
+ rules found in section 14.8 of [2]. Both the Proxy-Authenticate and
+ the Proxy-Authorization header fields are hop-by-hop headers (see
+ section 13.5.1 of [2]).
+
+2 Basic Authentication Scheme
+
+ The "basic" authentication scheme is based on the model that the
+ client must authenticate itself with a user-ID and a password for
+ each realm. The realm value should be considered an opaque string
+ which can only be compared for equality with other realms on that
+ server. The server will service the request only if it can validate
+ the user-ID and password for the protection space of the Request-URI.
+ There are no optional authentication parameters.
+
+ For Basic, the framework above is utilized as follows:
+
+ challenge = "Basic" realm
+ credentials = "Basic" basic-credentials
+
+ Upon receipt of an unauthorized request for a URI within the
+ protection space, the origin server MAY respond with a challenge like
+ the following:
+
+ WWW-Authenticate: Basic realm="WallyWorld"
+
+ where "WallyWorld" is the string assigned by the server to identify
+ the protection space of the Request-URI. A proxy may respond with the
+ same challenge using the Proxy-Authenticate header field.
+
+ To receive authorization, the client sends the userid and password,
+ separated by a single colon (":") character, within a base64 [7]
+ encoded string in the credentials.
+
+ basic-credentials = base64-user-pass
+ base64-user-pass = <base64 [4] encoding of user-pass,
+
+
+
+Franks, et al. Standards Track [Page 5]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ except not limited to 76 char/line>
+ user-pass = userid ":" password
+ userid = *<TEXT excluding ":">
+ password = *TEXT
+
+ Userids might be case sensitive.
+
+ If the user agent wishes to send the userid "Aladdin" and password
+ "open sesame", it would use the following header field:
+
+ Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
+
+ A client SHOULD assume that all paths at or deeper than the depth of
+ the last symbolic element in the path field of the Request-URI also
+ are within the protection space specified by the Basic realm value of
+ the current challenge. A client MAY preemptively send the
+ corresponding Authorization header with requests for resources in
+ that space without receipt of another challenge from the server.
+ Similarly, when a client sends a request to a proxy, it may reuse a
+ userid and password in the Proxy-Authorization header field without
+ receiving another challenge from the proxy server. See section 4 for
+ security considerations associated with Basic authentication.
+
+3 Digest Access Authentication Scheme
+
+3.1 Introduction
+
+3.1.1 Purpose
+
+ The protocol referred to as "HTTP/1.0" includes the specification for
+ a Basic Access Authentication scheme[1]. That scheme is not
+ considered to be a secure method of user authentication, as the user
+ name and password are passed over the network in an unencrypted form.
+ This section provides the specification for a scheme that does not
+ send the password in cleartext, referred to as "Digest Access
+ Authentication".
+
+ The Digest Access Authentication scheme is not intended to be a
+ complete answer to the need for security in the World Wide Web. This
+ scheme provides no encryption of message content. The intent is
+ simply to create an access authentication method that avoids the most
+ serious flaws of Basic authentication.
+
+3.1.2 Overall Operation
+
+ Like Basic Access Authentication, the Digest scheme is based on a
+ simple challenge-response paradigm. The Digest scheme challenges
+ using a nonce value. A valid response contains a checksum (by
+
+
+
+Franks, et al. Standards Track [Page 6]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ default, the MD5 checksum) of the username, the password, the given
+ nonce value, the HTTP method, and the requested URI. In this way, the
+ password is never sent in the clear. Just as with the Basic scheme,
+ the username and password must be prearranged in some fashion not
+ addressed by this document.
+
+3.1.3 Representation of digest values
+
+ An optional header allows the server to specify the algorithm used to
+ create the checksum or digest. By default the MD5 algorithm is used
+ and that is the only algorithm described in this document.
+
+ For the purposes of this document, an MD5 digest of 128 bits is
+ represented as 32 ASCII printable characters. The bits in the 128 bit
+ digest are converted from most significant to least significant bit,
+ four bits at a time to their ASCII presentation as follows. Each four
+ bits is represented by its familiar hexadecimal notation from the
+ characters 0123456789abcdef. That is, binary 0000 gets represented by
+ the character '0', 0001, by '1', and so on up to the representation
+ of 1111 as 'f'.
+
+3.1.4 Limitations
+
+ The Digest authentication scheme described in this document suffers
+ from many known limitations. It is intended as a replacement for
+ Basic authentication and nothing more. It is a password-based system
+ and (on the server side) suffers from all the same problems of any
+ password system. In particular, no provision is made in this protocol
+ for the initial secure arrangement between user and server to
+ establish the user's password.
+
+ Users and implementors should be aware that this protocol is not as
+ secure as Kerberos, and not as secure as any client-side private-key
+ scheme. Nevertheless it is better than nothing, better than what is
+ commonly used with telnet and ftp, and better than Basic
+ authentication.
+
+3.2 Specification of Digest Headers
+
+ The Digest Access Authentication scheme is conceptually similar to
+ the Basic scheme. The formats of the modified WWW-Authenticate header
+ line and the Authorization header line are specified below. In
+ addition, a new header, Authentication-Info, is specified.
+
+
+
+
+
+
+
+
+Franks, et al. Standards Track [Page 7]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+3.2.1 The WWW-Authenticate Response Header
+
+ If a server receives a request for an access-protected object, and an
+ acceptable Authorization header is not sent, the server responds with
+ a "401 Unauthorized" status code, and a WWW-Authenticate header as
+ per the framework defined above, which for the digest scheme is
+ utilized as follows:
+
+ challenge = "Digest" digest-challenge
+
+ digest-challenge = 1#( realm | [ domain ] | nonce |
+ [ opaque ] |[ stale ] | [ algorithm ] |
+ [ qop-options ] | [auth-param] )
+
+
+ domain = "domain" "=" <"> URI ( 1*SP URI ) <">
+ URI = absoluteURI | abs_path
+ nonce = "nonce" "=" nonce-value
+ nonce-value = quoted-string
+ opaque = "opaque" "=" quoted-string
+ stale = "stale" "=" ( "true" | "false" )
+ algorithm = "algorithm" "=" ( "MD5" | "MD5-sess" |
+ token )
+ qop-options = "qop" "=" <"> 1#qop-value <">
+ qop-value = "auth" | "auth-int" | token
+
+ The meanings of the values of the directives used above are as
+ follows:
+
+ realm
+ A string to be displayed to users so they know which username and
+ password to use. This string should contain at least the name of
+ the host performing the authentication and might additionally
+ indicate the collection of users who might have access. An example
+ might be "registered_users@gotham.news.com".
+
+ domain
+ A quoted, space-separated list of URIs, as specified in RFC XURI
+ [7], that define the protection space. If a URI is an abs_path, it
+ is relative to the canonical root URL (see section 1.2 above) of
+ the server being accessed. An absoluteURI in this list may refer to
+ a different server than the one being accessed. The client can use
+ this list to determine the set of URIs for which the same
+ authentication information may be sent: any URI that has a URI in
+ this list as a prefix (after both have been made absolute) may be
+ assumed to be in the same protection space. If this directive is
+ omitted or its value is empty, the client should assume that the
+ protection space consists of all URIs on the responding server.
+
+
+
+Franks, et al. Standards Track [Page 8]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ This directive is not meaningful in Proxy-Authenticate headers, for
+ which the protection space is always the entire proxy; if present
+ it should be ignored.
+
+ nonce
+ A server-specified data string which should be uniquely generated
+ each time a 401 response is made. It is recommended that this
+ string be base64 or hexadecimal data. Specifically, since the
+ string is passed in the header lines as a quoted string, the
+ double-quote character is not allowed.
+
+ The contents of the nonce are implementation dependent. The quality
+ of the implementation depends on a good choice. A nonce might, for
+ example, be constructed as the base 64 encoding of
+
+ time-stamp H(time-stamp ":" ETag ":" private-key)
+
+ where time-stamp is a server-generated time or other non-repeating
+ value, ETag is the value of the HTTP ETag header associated with
+ the requested entity, and private-key is data known only to the
+ server. With a nonce of this form a server would recalculate the
+ hash portion after receiving the client authentication header and
+ reject the request if it did not match the nonce from that header
+ or if the time-stamp value is not recent enough. In this way the
+ server can limit the time of the nonce's validity. The inclusion of
+ the ETag prevents a replay request for an updated version of the
+ resource. (Note: including the IP address of the client in the
+ nonce would appear to offer the server the ability to limit the
+ reuse of the nonce to the same client that originally got it.
+ However, that would break proxy farms, where requests from a single
+ user often go through different proxies in the farm. Also, IP
+ address spoofing is not that hard.)
+
+ An implementation might choose not to accept a previously used
+ nonce or a previously used digest, in order to protect against a
+ replay attack. Or, an implementation might choose to use one-time
+ nonces or digests for POST or PUT requests and a time-stamp for GET
+ requests. For more details on the issues involved see section 4.
+ of this document.
+
+ The nonce is opaque to the client.
+
+ opaque
+ A string of data, specified by the server, which should be returned
+ by the client unchanged in the Authorization header of subsequent
+ requests with URIs in the same protection space. It is recommended
+ that this string be base64 or hexadecimal data.
+
+
+
+
+Franks, et al. Standards Track [Page 9]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ stale
+ A flag, indicating that the previous request from the client was
+ rejected because the nonce value was stale. If stale is TRUE
+ (case-insensitive), the client may wish to simply retry the request
+ with a new encrypted response, without reprompting the user for a
+ new username and password. The server should only set stale to TRUE
+ if it receives a request for which the nonce is invalid but with a
+ valid digest for that nonce (indicating that the client knows the
+ correct username/password). If stale is FALSE, or anything other
+ than TRUE, or the stale directive is not present, the username
+ and/or password are invalid, and new values must be obtained.
+
+ algorithm
+ A string indicating a pair of algorithms used to produce the digest
+ and a checksum. If this is not present it is assumed to be "MD5".
+ If the algorithm is not understood, the challenge should be ignored
+ (and a different one used, if there is more than one).
+
+ In this document the string obtained by applying the digest
+ algorithm to the data "data" with secret "secret" will be denoted
+ by KD(secret, data), and the string obtained by applying the
+ checksum algorithm to the data "data" will be denoted H(data). The
+ notation unq(X) means the value of the quoted-string X without the
+ surrounding quotes.
+
+ For the "MD5" and "MD5-sess" algorithms
+
+ H(data) = MD5(data)
+
+ and
+
+ KD(secret, data) = H(concat(secret, ":", data))
+
+ i.e., the digest is the MD5 of the secret concatenated with a colon
+ concatenated with the data. The "MD5-sess" algorithm is intended to
+ allow efficient 3rd party authentication servers; for the
+ difference in usage, see the description in section 3.2.2.2.
+
+ qop-options
+ This directive is optional, but is made so only for backward
+ compatibility with RFC 2069 [6]; it SHOULD be used by all
+ implementations compliant with this version of the Digest scheme.
+ If present, it is a quoted string of one or more tokens indicating
+ the "quality of protection" values supported by the server. The
+ value "auth" indicates authentication; the value "auth-int"
+ indicates authentication with integrity protection; see the
+
+
+
+
+
+Franks, et al. Standards Track [Page 10]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ descriptions below for calculating the response directive value for
+ the application of this choice. Unrecognized options MUST be
+ ignored.
+
+ auth-param
+ This directive allows for future extensions. Any unrecognized
+ directive MUST be ignored.
+
+3.2.2 The Authorization Request Header
+
+ The client is expected to retry the request, passing an Authorization
+ header line, which is defined according to the framework above,
+ utilized as follows.
+
+ credentials = "Digest" digest-response
+ digest-response = 1#( username | realm | nonce | digest-uri
+ | response | [ algorithm ] | [cnonce] |
+ [opaque] | [message-qop] |
+ [nonce-count] | [auth-param] )
+
+ username = "username" "=" username-value
+ username-value = quoted-string
+ digest-uri = "uri" "=" digest-uri-value
+ digest-uri-value = request-uri ; As specified by HTTP/1.1
+ message-qop = "qop" "=" qop-value
+ cnonce = "cnonce" "=" cnonce-value
+ cnonce-value = nonce-value
+ nonce-count = "nc" "=" nc-value
+ nc-value = 8LHEX
+ response = "response" "=" request-digest
+ request-digest = <"> 32LHEX <">
+ LHEX = "0" | "1" | "2" | "3" |
+ "4" | "5" | "6" | "7" |
+ "8" | "9" | "a" | "b" |
+ "c" | "d" | "e" | "f"
+
+ The values of the opaque and algorithm fields must be those supplied
+ in the WWW-Authenticate response header for the entity being
+ requested.
+
+ response
+ A string of 32 hex digits computed as defined below, which proves
+ that the user knows a password
+
+ username
+ The user's name in the specified realm.
+
+
+
+
+
+Franks, et al. Standards Track [Page 11]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ digest-uri
+ The URI from Request-URI of the Request-Line; duplicated here
+ because proxies are allowed to change the Request-Line in transit.
+
+ qop
+ Indicates what "quality of protection" the client has applied to
+ the message. If present, its value MUST be one of the alternatives
+ the server indicated it supports in the WWW-Authenticate header.
+ These values affect the computation of the request-digest. Note
+ that this is a single token, not a quoted list of alternatives as
+ in WWW- Authenticate. This directive is optional in order to
+ preserve backward compatibility with a minimal implementation of
+ RFC 2069 [6], but SHOULD be used if the server indicated that qop
+ is supported by providing a qop directive in the WWW-Authenticate
+ header field.
+
+ cnonce
+ This MUST be specified if a qop directive is sent (see above), and
+ MUST NOT be specified if the server did not send a qop directive in
+ the WWW-Authenticate header field. The cnonce-value is an opaque
+ quoted string value provided by the client and used by both client
+ and server to avoid chosen plaintext attacks, to provide mutual
+ authentication, and to provide some message integrity protection.
+ See the descriptions below of the calculation of the response-
+ digest and request-digest values.
+
+ nonce-count
+ This MUST be specified if a qop directive is sent (see above), and
+ MUST NOT be specified if the server did not send a qop directive in
+ the WWW-Authenticate header field. The nc-value is the hexadecimal
+ count of the number of requests (including the current request)
+ that the client has sent with the nonce value in this request. For
+ example, in the first request sent in response to a given nonce
+ value, the client sends "nc=00000001". The purpose of this
+ directive is to allow the server to detect request replays by
+ maintaining its own copy of this count - if the same nc-value is
+ seen twice, then the request is a replay. See the description
+ below of the construction of the request-digest value.
+
+ auth-param
+ This directive allows for future extensions. Any unrecognized
+ directive MUST be ignored.
+
+ If a directive or its value is improper, or required directives are
+ missing, the proper response is 400 Bad Request. If the request-
+ digest is invalid, then a login failure should be logged, since
+ repeated login failures from a single client may indicate an attacker
+ attempting to guess passwords.
+
+
+
+Franks, et al. Standards Track [Page 12]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ The definition of request-digest above indicates the encoding for its
+ value. The following definitions show how the value is computed.
+
+3.2.2.1 Request-Digest
+
+ If the "qop" value is "auth" or "auth-int":
+
+ request-digest = <"> < KD ( H(A1), unq(nonce-value)
+ ":" nc-value
+ ":" unq(cnonce-value)
+ ":" unq(qop-value)
+ ":" H(A2)
+ ) <">
+
+ If the "qop" directive is not present (this construction is for
+ compatibility with RFC 2069):
+
+ request-digest =
+ <"> < KD ( H(A1), unq(nonce-value) ":" H(A2) ) >
+ <">
+
+ See below for the definitions for A1 and A2.
+
+3.2.2.2 A1
+
+ If the "algorithm" directive's value is "MD5" or is unspecified, then
+ A1 is:
+
+ A1 = unq(username-value) ":" unq(realm-value) ":" passwd
+
+ where
+
+ passwd = < user's password >
+
+ If the "algorithm" directive's value is "MD5-sess", then A1 is
+ calculated only once - on the first request by the client following
+ receipt of a WWW-Authenticate challenge from the server. It uses the
+ server nonce from that challenge, and the first client nonce value to
+ construct A1 as follows:
+
+ A1 = H( unq(username-value) ":" unq(realm-value)
+ ":" passwd )
+ ":" unq(nonce-value) ":" unq(cnonce-value)
+
+ This creates a 'session key' for the authentication of subsequent
+ requests and responses which is different for each "authentication
+ session", thus limiting the amount of material hashed with any one
+ key. (Note: see further discussion of the authentication session in
+
+
+
+Franks, et al. Standards Track [Page 13]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ section 3.3.) Because the server need only use the hash of the user
+ credentials in order to create the A1 value, this construction could
+ be used in conjunction with a third party authentication service so
+ that the web server would not need the actual password value. The
+ specification of such a protocol is beyond the scope of this
+ specification.
+
+3.2.2.3 A2
+
+ If the "qop" directive's value is "auth" or is unspecified, then A2
+ is:
+
+ A2 = Method ":" digest-uri-value
+
+ If the "qop" value is "auth-int", then A2 is:
+
+ A2 = Method ":" digest-uri-value ":" H(entity-body)
+
+3.2.2.4 Directive values and quoted-string
+
+ Note that the value of many of the directives, such as "username-
+ value", are defined as a "quoted-string". However, the "unq" notation
+ indicates that surrounding quotation marks are removed in forming the
+ string A1. Thus if the Authorization header includes the fields
+
+ username="Mufasa", realm=myhost@testrealm.com
+
+ and the user Mufasa has password "Circle Of Life" then H(A1) would be
+ H(Mufasa:myhost@testrealm.com:Circle Of Life) with no quotation marks
+ in the digested string.
+
+ No white space is allowed in any of the strings to which the digest
+ function H() is applied unless that white space exists in the quoted
+ strings or entity body whose contents make up the string to be
+ digested. For example, the string A1 illustrated above must be
+
+ Mufasa:myhost@testrealm.com:Circle Of Life
+
+ with no white space on either side of the colons, but with the white
+ space between the words used in the password value. Likewise, the
+ other strings digested by H() must not have white space on either
+ side of the colons which delimit their fields unless that white space
+ was in the quoted strings or entity body being digested.
+
+ Also note that if integrity protection is applied (qop=auth-int), the
+ H(entity-body) is the hash of the entity body, not the message body -
+ it is computed before any transfer encoding is applied by the sender
+
+
+
+
+Franks, et al. Standards Track [Page 14]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ and after it has been removed by the recipient. Note that this
+ includes multipart boundaries and embedded headers in each part of
+ any multipart content-type.
+
+3.2.2.5 Various considerations
+
+ The "Method" value is the HTTP request method as specified in section
+ 5.1.1 of [2]. The "request-uri" value is the Request-URI from the
+ request line as specified in section 5.1.2 of [2]. This may be "*",
+ an "absoluteURL" or an "abs_path" as specified in section 5.1.2 of
+ [2], but it MUST agree with the Request-URI. In particular, it MUST
+ be an "absoluteURL" if the Request-URI is an "absoluteURL". The
+ "cnonce-value" is an optional client-chosen value whose purpose is
+ to foil chosen plaintext attacks.
+
+ The authenticating server must assure that the resource designated by
+ the "uri" directive is the same as the resource specified in the
+ Request-Line; if they are not, the server SHOULD return a 400 Bad
+ Request error. (Since this may be a symptom of an attack, server
+ implementers may want to consider logging such errors.) The purpose
+ of duplicating information from the request URL in this field is to
+ deal with the possibility that an intermediate proxy may alter the
+ client's Request-Line. This altered (but presumably semantically
+ equivalent) request would not result in the same digest as that
+ calculated by the client.
+
+ Implementers should be aware of how authenticated transactions
+ interact with shared caches. The HTTP/1.1 protocol specifies that
+ when a shared cache (see section 13.7 of [2]) has received a request
+ containing an Authorization header and a response from relaying that
+ request, it MUST NOT return that response as a reply to any other
+ request, unless one of two Cache-Control (see section 14.9 of [2])
+ directives was present in the response. If the original response
+ included the "must-revalidate" Cache-Control directive, the cache MAY
+ use the entity of that response in replying to a subsequent request,
+ but MUST first revalidate it with the origin server, using the
+ request headers from the new request to allow the origin server to
+ authenticate the new request. Alternatively, if the original response
+ included the "public" Cache-Control directive, the response entity
+ MAY be returned in reply to any subsequent request.
+
+3.2.3 The Authentication-Info Header
+
+ The Authentication-Info header is used by the server to communicate
+ some information regarding the successful authentication in the
+ response.
+
+
+
+
+
+Franks, et al. Standards Track [Page 15]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ AuthenticationInfo = "Authentication-Info" ":" auth-info
+ auth-info = 1#(nextnonce | [ message-qop ]
+ | [ response-auth ] | [ cnonce ]
+ | [nonce-count] )
+ nextnonce = "nextnonce" "=" nonce-value
+ response-auth = "rspauth" "=" response-digest
+ response-digest = <"> *LHEX <">
+
+ The value of the nextnonce directive is the nonce the server wishes
+ the client to use for a future authentication response. The server
+ may send the Authentication-Info header with a nextnonce field as a
+ means of implementing one-time or otherwise changing nonces. If the
+ nextnonce field is present the client SHOULD use it when constructing
+ the Authorization header for its next request. Failure of the client
+ to do so may result in a request to re-authenticate from the server
+ with the "stale=TRUE".
+
+ Server implementations should carefully consider the performance
+ implications of the use of this mechanism; pipelined requests will
+ not be possible if every response includes a nextnonce directive
+ that must be used on the next request received by the server.
+ Consideration should be given to the performance vs. security
+ tradeoffs of allowing an old nonce value to be used for a limited
+ time to permit request pipelining. Use of the nonce-count can
+ retain most of the security advantages of a new server nonce
+ without the deleterious affects on pipelining.
+
+ message-qop
+ Indicates the "quality of protection" options applied to the
+ response by the server. The value "auth" indicates authentication;
+ the value "auth-int" indicates authentication with integrity
+ protection. The server SHOULD use the same value for the message-
+ qop directive in the response as was sent by the client in the
+ corresponding request.
+
+ The optional response digest in the "response-auth" directive
+ supports mutual authentication -- the server proves that it knows the
+ user's secret, and with qop=auth-int also provides limited integrity
+ protection of the response. The "response-digest" value is calculated
+ as for the "request-digest" in the Authorization header, except that
+ if "qop=auth" or is not specified in the Authorization header for the
+ request, A2 is
+
+ A2 = ":" digest-uri-value
+
+ and if "qop=auth-int", then A2 is
+
+ A2 = ":" digest-uri-value ":" H(entity-body)
+
+
+
+Franks, et al. Standards Track [Page 16]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ where "digest-uri-value" is the value of the "uri" directive on the
+ Authorization header in the request. The "cnonce-value" and "nc-
+ value" MUST be the ones for the client request to which this message
+ is the response. The "response-auth", "cnonce", and "nonce-count"
+ directives MUST BE present if "qop=auth" or "qop=auth-int" is
+ specified.
+
+ The Authentication-Info header is allowed in the trailer of an HTTP
+ message transferred via chunked transfer-coding.
+
+3.3 Digest Operation
+
+ Upon receiving the Authorization header, the server may check its
+ validity by looking up the password that corresponds to the submitted
+ username. Then, the server must perform the same digest operation
+ (e.g., MD5) performed by the client, and compare the result to the
+ given request-digest value.
+
+ Note that the HTTP server does not actually need to know the user's
+ cleartext password. As long as H(A1) is available to the server, the
+ validity of an Authorization header may be verified.
+
+ The client response to a WWW-Authenticate challenge for a protection
+ space starts an authentication session with that protection space.
+ The authentication session lasts until the client receives another
+ WWW-Authenticate challenge from any server in the protection space. A
+ client should remember the username, password, nonce, nonce count and
+ opaque values associated with an authentication session to use to
+ construct the Authorization header in future requests within that
+ protection space. The Authorization header may be included
+ preemptively; doing so improves server efficiency and avoids extra
+ round trips for authentication challenges. The server may choose to
+ accept the old Authorization header information, even though the
+ nonce value included might not be fresh. Alternatively, the server
+ may return a 401 response with a new nonce value, causing the client
+ to retry the request; by specifying stale=TRUE with this response,
+ the server tells the client to retry with the new nonce, but without
+ prompting for a new username and password.
+
+ Because the client is required to return the value of the opaque
+ directive given to it by the server for the duration of a session,
+ the opaque data may be used to transport authentication session state
+ information. (Note that any such use can also be accomplished more
+ easily and safely by including the state in the nonce.) For example,
+ a server could be responsible for authenticating content that
+ actually sits on another server. It would achieve this by having the
+ first 401 response include a domain directive whose value includes a
+ URI on the second server, and an opaque directive whose value
+
+
+
+Franks, et al. Standards Track [Page 17]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ contains the state information. The client will retry the request, at
+ which time the server might respond with a 301/302 redirection,
+ pointing to the URI on the second server. The client will follow the
+ redirection, and pass an Authorization header , including the
+ <opaque> data.
+
+ As with the basic scheme, proxies must be completely transparent in
+ the Digest access authentication scheme. That is, they must forward
+ the WWW-Authenticate, Authentication-Info and Authorization headers
+ untouched. If a proxy wants to authenticate a client before a request
+ is forwarded to the server, it can be done using the Proxy-
+ Authenticate and Proxy-Authorization headers described in section 3.6
+ below.
+
+3.4 Security Protocol Negotiation
+
+ It is useful for a server to be able to know which security schemes a
+ client is capable of handling.
+
+ It is possible that a server may want to require Digest as its
+ authentication method, even if the server does not know that the
+ client supports it. A client is encouraged to fail gracefully if the
+ server specifies only authentication schemes it cannot handle.
+
+3.5 Example
+
+ The following example assumes that an access-protected document is
+ being requested from the server via a GET request. The URI of the
+ document is "http://www.nowhere.org/dir/index.html". Both client and
+ server know that the username for this document is "Mufasa", and the
+ password is "Circle Of Life" (with one space between each of the
+ three words).
+
+ The first time the client requests the document, no Authorization
+ header is sent, so the server responds with:
+
+ HTTP/1.1 401 Unauthorized
+ WWW-Authenticate: Digest
+ realm="testrealm@host.com",
+ qop="auth,auth-int",
+ nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
+ opaque="5ccc069c403ebaf9f0171e9517f40e41"
+
+ The client may prompt the user for the username and password, after
+ which it will respond with a new request, including the following
+ Authorization header:
+
+
+
+
+
+Franks, et al. Standards Track [Page 18]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ Authorization: Digest username="Mufasa",
+ realm="testrealm@host.com",
+ nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
+ uri="/dir/index.html",
+ qop=auth,
+ nc=00000001,
+ cnonce="0a4f113b",
+ response="6629fae49393a05397450978507c4ef1",
+ opaque="5ccc069c403ebaf9f0171e9517f40e41"
+
+3.6 Proxy-Authentication and Proxy-Authorization
+
+ The digest authentication scheme may also be used for authenticating
+ users to proxies, proxies to proxies, or proxies to origin servers by
+ use of the Proxy-Authenticate and Proxy-Authorization headers. These
+ headers are instances of the Proxy-Authenticate and Proxy-
+ Authorization headers specified in sections 10.33 and 10.34 of the
+ HTTP/1.1 specification [2] and their behavior is subject to
+ restrictions described there. The transactions for proxy
+ authentication are very similar to those already described. Upon
+ receiving a request which requires authentication, the proxy/server
+ must issue the "407 Proxy Authentication Required" response with a
+ "Proxy-Authenticate" header. The digest-challenge used in the
+ Proxy-Authenticate header is the same as that for the WWW-
+ Authenticate header as defined above in section 3.2.1.
+
+ The client/proxy must then re-issue the request with a Proxy-
+ Authorization header, with directives as specified for the
+ Authorization header in section 3.2.2 above.
+
+ On subsequent responses, the server sends Proxy-Authentication-Info
+ with directives the same as those for the Authentication-Info header
+ field.
+
+ Note that in principle a client could be asked to authenticate itself
+ to both a proxy and an end-server, but never in the same response.
+
+4 Security Considerations
+
+4.1 Authentication of Clients using Basic Authentication
+
+ The Basic authentication scheme is not a secure method of user
+ authentication, nor does it in any way protect the entity, which is
+ transmitted in cleartext across the physical network used as the
+ carrier. HTTP does not prevent additional authentication schemes and
+ encryption mechanisms from being employed to increase security or the
+ addition of enhancements (such as schemes to use one-time passwords)
+ to Basic authentication.
+
+
+
+Franks, et al. Standards Track [Page 19]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ The most serious flaw in Basic authentication is that it results in
+ the essentially cleartext transmission of the user's password over
+ the physical network. It is this problem which Digest Authentication
+ attempts to address.
+
+ Because Basic authentication involves the cleartext transmission of
+ passwords it SHOULD NOT be used (without enhancements) to protect
+ sensitive or valuable information.
+
+ A common use of Basic authentication is for identification purposes
+ -- requiring the user to provide a user name and password as a means
+ of identification, for example, for purposes of gathering accurate
+ usage statistics on a server. When used in this way it is tempting to
+ think that there is no danger in its use if illicit access to the
+ protected documents is not a major concern. This is only correct if
+ the server issues both user name and password to the users and in
+ particular does not allow the user to choose his or her own password.
+ The danger arises because naive users frequently reuse a single
+ password to avoid the task of maintaining multiple passwords.
+
+ If a server permits users to select their own passwords, then the
+ threat is not only unauthorized access to documents on the server but
+ also unauthorized access to any other resources on other systems that
+ the user protects with the same password. Furthermore, in the
+ server's password database, many of the passwords may also be users'
+ passwords for other sites. The owner or administrator of such a
+ system could therefore expose all users of the system to the risk of
+ unauthorized access to all those sites if this information is not
+ maintained in a secure fashion.
+
+ Basic Authentication is also vulnerable to spoofing by counterfeit
+ servers. If a user can be led to believe that he is connecting to a
+ host containing information protected by Basic authentication when,
+ in fact, he is connecting to a hostile server or gateway, then the
+ attacker can request a password, store it for later use, and feign an
+ error. This type of attack is not possible with Digest
+ Authentication. Server implementers SHOULD guard against the
+ possibility of this sort of counterfeiting by gateways or CGI
+ scripts. In particular it is very dangerous for a server to simply
+ turn over a connection to a gateway. That gateway can then use the
+ persistent connection mechanism to engage in multiple transactions
+ with the client while impersonating the original server in a way that
+ is not detectable by the client.
+
+4.2 Authentication of Clients using Digest Authentication
+
+ Digest Authentication does not provide a strong authentication
+ mechanism, when compared to public key based mechanisms, for example.
+
+
+
+Franks, et al. Standards Track [Page 20]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ However, it is significantly stronger than (e.g.) CRAM-MD5, which has
+ been proposed for use with LDAP [10], POP and IMAP (see RFC 2195
+ [9]). It is intended to replace the much weaker and even more
+ dangerous Basic mechanism.
+
+ Digest Authentication offers no confidentiality protection beyond
+ protecting the actual password. All of the rest of the request and
+ response are available to an eavesdropper.
+
+ Digest Authentication offers only limited integrity protection for
+ the messages in either direction. If qop=auth-int mechanism is used,
+ those parts of the message used in the calculation of the WWW-
+ Authenticate and Authorization header field response directive values
+ (see section 3.2 above) are protected. Most header fields and their
+ values could be modified as a part of a man-in-the-middle attack.
+
+ Many needs for secure HTTP transactions cannot be met by Digest
+ Authentication. For those needs TLS or SHTTP are more appropriate
+ protocols. In particular Digest authentication cannot be used for any
+ transaction requiring confidentiality protection. Nevertheless many
+ functions remain for which Digest authentication is both useful and
+ appropriate. Any service in present use that uses Basic should be
+ switched to Digest as soon as practical.
+
+4.3 Limited Use Nonce Values
+
+ The Digest scheme uses a server-specified nonce to seed the
+ generation of the request-digest value (as specified in section
+ 3.2.2.1 above). As shown in the example nonce in section 3.2.1, the
+ server is free to construct the nonce such that it may only be used
+ from a particular client, for a particular resource, for a limited
+ period of time or number of uses, or any other restrictions. Doing
+ so strengthens the protection provided against, for example, replay
+ attacks (see 4.5). However, it should be noted that the method
+ chosen for generating and checking the nonce also has performance and
+ resource implications. For example, a server may choose to allow
+ each nonce value to be used only once by maintaining a record of
+ whether or not each recently issued nonce has been returned and
+ sending a next-nonce directive in the Authentication-Info header
+ field of every response. This protects against even an immediate
+ replay attack, but has a high cost checking nonce values, and perhaps
+ more important will cause authentication failures for any pipelined
+ requests (presumably returning a stale nonce indication). Similarly,
+ incorporating a request-specific element such as the Etag value for a
+ resource limits the use of the nonce to that version of the resource
+ and also defeats pipelining. Thus it may be useful to do so for
+ methods with side effects but have unacceptable performance for those
+ that do not.
+
+
+
+Franks, et al. Standards Track [Page 21]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+4.4 Comparison of Digest with Basic Authentication
+
+ Both Digest and Basic Authentication are very much on the weak end of
+ the security strength spectrum. But a comparison between the two
+ points out the utility, even necessity, of replacing Basic by Digest.
+
+ The greatest threat to the type of transactions for which these
+ protocols are used is network snooping. This kind of transaction
+ might involve, for example, online access to a database whose use is
+ restricted to paying subscribers. With Basic authentication an
+ eavesdropper can obtain the password of the user. This not only
+ permits him to access anything in the database, but, often worse,
+ will permit access to anything else the user protects with the same
+ password.
+
+ By contrast, with Digest Authentication the eavesdropper only gets
+ access to the transaction in question and not to the user's password.
+ The information gained by the eavesdropper would permit a replay
+ attack, but only with a request for the same document, and even that
+ may be limited by the server's choice of nonce.
+
+4.5 Replay Attacks
+
+ A replay attack against Digest authentication would usually be
+ pointless for a simple GET request since an eavesdropper would
+ already have seen the only document he could obtain with a replay.
+ This is because the URI of the requested document is digested in the
+ client request and the server will only deliver that document. By
+ contrast under Basic Authentication once the eavesdropper has the
+ user's password, any document protected by that password is open to
+ him.
+
+ Thus, for some purposes, it is necessary to protect against replay
+ attacks. A good Digest implementation can do this in various ways.
+ The server created "nonce" value is implementation dependent, but if
+ it contains a digest of the client IP, a time-stamp, the resource
+ ETag, and a private server key (as recommended above) then a replay
+ attack is not simple. An attacker must convince the server that the
+ request is coming from a false IP address and must cause the server
+ to deliver the document to an IP address different from the address
+ to which it believes it is sending the document. An attack can only
+ succeed in the period before the time-stamp expires. Digesting the
+ client IP and time-stamp in the nonce permits an implementation which
+ does not maintain state between transactions.
+
+ For applications where no possibility of replay attack can be
+ tolerated the server can use one-time nonce values which will not be
+ honored for a second use. This requires the overhead of the server
+
+
+
+Franks, et al. Standards Track [Page 22]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ remembering which nonce values have been used until the nonce time-
+ stamp (and hence the digest built with it) has expired, but it
+ effectively protects against replay attacks.
+
+ An implementation must give special attention to the possibility of
+ replay attacks with POST and PUT requests. Unless the server employs
+ one-time or otherwise limited-use nonces and/or insists on the use of
+ the integrity protection of qop=auth-int, an attacker could replay
+ valid credentials from a successful request with counterfeit form
+ data or other message body. Even with the use of integrity protection
+ most metadata in header fields is not protected. Proper nonce
+ generation and checking provides some protection against replay of
+ previously used valid credentials, but see 4.8.
+
+4.6 Weakness Created by Multiple Authentication Schemes
+
+ An HTTP/1.1 server may return multiple challenges with a 401
+ (Authenticate) response, and each challenge may use a different
+ auth-scheme. A user agent MUST choose to use the strongest auth-
+ scheme it understands and request credentials from the user based
+ upon that challenge.
+
+ Note that many browsers will only recognize Basic and will require
+ that it be the first auth-scheme presented. Servers should only
+ include Basic if it is minimally acceptable.
+
+ When the server offers choices of authentication schemes using the
+ WWW-Authenticate header, the strength of the resulting authentication
+ is only as good as that of the of the weakest of the authentication
+ schemes. See section 4.8 below for discussion of particular attack
+ scenarios that exploit multiple authentication schemes.
+
+4.7 Online dictionary attacks
+
+ If the attacker can eavesdrop, then it can test any overheard
+ nonce/response pairs against a list of common words. Such a list is
+ usually much smaller than the total number of possible passwords. The
+ cost of computing the response for each password on the list is paid
+ once for each challenge.
+
+ The server can mitigate this attack by not allowing users to select
+ passwords that are in a dictionary.
+
+
+
+
+
+
+
+
+
+Franks, et al. Standards Track [Page 23]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+4.8 Man in the Middle
+
+ Both Basic and Digest authentication are vulnerable to "man in the
+ middle" (MITM) attacks, for example, from a hostile or compromised
+ proxy. Clearly, this would present all the problems of eavesdropping.
+ But it also offers some additional opportunities to the attacker.
+
+ A possible man-in-the-middle attack would be to add a weak
+ authentication scheme to the set of choices, hoping that the client
+ will use one that exposes the user's credentials (e.g. password). For
+ this reason, the client should always use the strongest scheme that
+ it understands from the choices offered.
+
+ An even better MITM attack would be to remove all offered choices,
+ replacing them with a challenge that requests only Basic
+ authentication, then uses the cleartext credentials from the Basic
+ authentication to authenticate to the origin server using the
+ stronger scheme it requested. A particularly insidious way to mount
+ such a MITM attack would be to offer a "free" proxy caching service
+ to gullible users.
+
+ User agents should consider measures such as presenting a visual
+ indication at the time of the credentials request of what
+ authentication scheme is to be used, or remembering the strongest
+ authentication scheme ever requested by a server and produce a
+ warning message before using a weaker one. It might also be a good
+ idea for the user agent to be configured to demand Digest
+ authentication in general, or from specific sites.
+
+ Or, a hostile proxy might spoof the client into making a request the
+ attacker wanted rather than one the client wanted. Of course, this is
+ still much harder than a comparable attack against Basic
+ Authentication.
+
+4.9 Chosen plaintext attacks
+
+ With Digest authentication, a MITM or a malicious server can
+ arbitrarily choose the nonce that the client will use to compute the
+ response. This is called a "chosen plaintext" attack. The ability to
+ choose the nonce is known to make cryptanalysis much easier [8].
+
+ However, no way to analyze the MD5 one-way function used by Digest
+ using chosen plaintext is currently known.
+
+ The countermeasure against this attack is for clients to be
+ configured to require the use of the optional "cnonce" directive;
+ this allows the client to vary the input to the hash in a way not
+ chosen by the attacker.
+
+
+
+Franks, et al. Standards Track [Page 24]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+4.10 Precomputed dictionary attacks
+
+ With Digest authentication, if the attacker can execute a chosen
+ plaintext attack, the attacker can precompute the response for many
+ common words to a nonce of its choice, and store a dictionary of
+ (response, password) pairs. Such precomputation can often be done in
+ parallel on many machines. It can then use the chosen plaintext
+ attack to acquire a response corresponding to that challenge, and
+ just look up the password in the dictionary. Even if most passwords
+ are not in the dictionary, some might be. Since the attacker gets to
+ pick the challenge, the cost of computing the response for each
+ password on the list can be amortized over finding many passwords. A
+ dictionary with 100 million password/response pairs would take about
+ 3.2 gigabytes of disk storage.
+
+ The countermeasure against this attack is to for clients to be
+ configured to require the use of the optional "cnonce" directive.
+
+4.11 Batch brute force attacks
+
+ With Digest authentication, a MITM can execute a chosen plaintext
+ attack, and can gather responses from many users to the same nonce.
+ It can then find all the passwords within any subset of password
+ space that would generate one of the nonce/response pairs in a single
+ pass over that space. It also reduces the time to find the first
+ password by a factor equal to the number of nonce/response pairs
+ gathered. This search of the password space can often be done in
+ parallel on many machines, and even a single machine can search large
+ subsets of the password space very quickly -- reports exist of
+ searching all passwords with six or fewer letters in a few hours.
+
+ The countermeasure against this attack is to for clients to be
+ configured to require the use of the optional "cnonce" directive.
+
+4.12 Spoofing by Counterfeit Servers
+
+ Basic Authentication is vulnerable to spoofing by counterfeit
+ servers. If a user can be led to believe that she is connecting to a
+ host containing information protected by a password she knows, when
+ in fact she is connecting to a hostile server, then the hostile
+ server can request a password, store it away for later use, and feign
+ an error. This type of attack is more difficult with Digest
+ Authentication -- but the client must know to demand that Digest
+ authentication be used, perhaps using some of the techniques
+ described above to counter "man-in-the-middle" attacks. Again, the
+ user can be helped in detecting this attack by a visual indication of
+ the authentication mechanism in use with appropriate guidance in
+ interpreting the implications of each scheme.
+
+
+
+Franks, et al. Standards Track [Page 25]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+4.13 Storing passwords
+
+ Digest authentication requires that the authenticating agent (usually
+ the server) store some data derived from the user's name and password
+ in a "password file" associated with a given realm. Normally this
+ might contain pairs consisting of username and H(A1), where H(A1) is
+ the digested value of the username, realm, and password as described
+ above.
+
+ The security implications of this are that if this password file is
+ compromised, then an attacker gains immediate access to documents on
+ the server using this realm. Unlike, say a standard UNIX password
+ file, this information need not be decrypted in order to access
+ documents in the server realm associated with this file. On the other
+ hand, decryption, or more likely a brute force attack, would be
+ necessary to obtain the user's password. This is the reason that the
+ realm is part of the digested data stored in the password file. It
+ means that if one Digest authentication password file is compromised,
+ it does not automatically compromise others with the same username
+ and password (though it does expose them to brute force attack).
+
+ There are two important security consequences of this. First the
+ password file must be protected as if it contained unencrypted
+ passwords, because for the purpose of accessing documents in its
+ realm, it effectively does.
+
+ A second consequence of this is that the realm string should be
+ unique among all realms which any single user is likely to use. In
+ particular a realm string should include the name of the host doing
+ the authentication. The inability of the client to authenticate the
+ server is a weakness of Digest Authentication.
+
+4.14 Summary
+
+ By modern cryptographic standards Digest Authentication is weak. But
+ for a large range of purposes it is valuable as a replacement for
+ Basic Authentication. It remedies some, but not all, weaknesses of
+ Basic Authentication. Its strength may vary depending on the
+ implementation. In particular the structure of the nonce (which is
+ dependent on the server implementation) may affect the ease of
+ mounting a replay attack. A range of server options is appropriate
+ since, for example, some implementations may be willing to accept the
+ server overhead of one-time nonces or digests to eliminate the
+ possibility of replay. Others may satisfied with a nonce like the one
+ recommended above restricted to a single IP address and a single ETag
+ or with a limited lifetime.
+
+
+
+
+
+Franks, et al. Standards Track [Page 26]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ The bottom line is that *any* compliant implementation will be
+ relatively weak by cryptographic standards, but *any* compliant
+ implementation will be far superior to Basic Authentication.
+
+5 Sample implementation
+
+ The following code implements the calculations of H(A1), H(A2),
+ request-digest and response-digest, and a test program which computes
+ the values used in the example of section 3.5. It uses the MD5
+ implementation from RFC 1321.
+
+ File "digcalc.h":
+
+#define HASHLEN 16
+typedef char HASH[HASHLEN];
+#define HASHHEXLEN 32
+typedef char HASHHEX[HASHHEXLEN+1];
+#define IN
+#define OUT
+
+/* calculate H(A1) as per HTTP Digest spec */
+void DigestCalcHA1(
+ IN char * pszAlg,
+ IN char * pszUserName,
+ IN char * pszRealm,
+ IN char * pszPassword,
+ IN char * pszNonce,
+ IN char * pszCNonce,
+ OUT HASHHEX SessionKey
+ );
+
+/* calculate request-digest/response-digest as per HTTP Digest spec */
+void DigestCalcResponse(
+ IN HASHHEX HA1, /* H(A1) */
+ IN char * pszNonce, /* nonce from server */
+ IN char * pszNonceCount, /* 8 hex digits */
+ IN char * pszCNonce, /* client nonce */
+ IN char * pszQop, /* qop-value: "", "auth", "auth-int" */
+ IN char * pszMethod, /* method from the request */
+ IN char * pszDigestUri, /* requested URL */
+ IN HASHHEX HEntity, /* H(entity body) if qop="auth-int" */
+ OUT HASHHEX Response /* request-digest or response-digest */
+ );
+
+File "digcalc.c":
+
+#include <global.h>
+#include <md5.h>
+
+
+
+Franks, et al. Standards Track [Page 27]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+#include <string.h>
+#include "digcalc.h"
+
+void CvtHex(
+ IN HASH Bin,
+ OUT HASHHEX Hex
+ )
+{
+ unsigned short i;
+ unsigned char j;
+
+ for (i = 0; i < HASHLEN; i++) {
+ j = (Bin[i] >> 4) & 0xf;
+ if (j <= 9)
+ Hex[i*2] = (j + '0');
+ else
+ Hex[i*2] = (j + 'a' - 10);
+ j = Bin[i] & 0xf;
+ if (j <= 9)
+ Hex[i*2+1] = (j + '0');
+ else
+ Hex[i*2+1] = (j + 'a' - 10);
+ };
+ Hex[HASHHEXLEN] = '\0';
+};
+
+/* calculate H(A1) as per spec */
+void DigestCalcHA1(
+ IN char * pszAlg,
+ IN char * pszUserName,
+ IN char * pszRealm,
+ IN char * pszPassword,
+ IN char * pszNonce,
+ IN char * pszCNonce,
+ OUT HASHHEX SessionKey
+ )
+{
+ MD5_CTX Md5Ctx;
+ HASH HA1;
+
+ MD5Init(&Md5Ctx);
+ MD5Update(&Md5Ctx, pszUserName, strlen(pszUserName));
+ MD5Update(&Md5Ctx, ":", 1);
+ MD5Update(&Md5Ctx, pszRealm, strlen(pszRealm));
+ MD5Update(&Md5Ctx, ":", 1);
+ MD5Update(&Md5Ctx, pszPassword, strlen(pszPassword));
+ MD5Final(HA1, &Md5Ctx);
+ if (stricmp(pszAlg, "md5-sess") == 0) {
+
+
+
+Franks, et al. Standards Track [Page 28]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ MD5Init(&Md5Ctx);
+ MD5Update(&Md5Ctx, HA1, HASHLEN);
+ MD5Update(&Md5Ctx, ":", 1);
+ MD5Update(&Md5Ctx, pszNonce, strlen(pszNonce));
+ MD5Update(&Md5Ctx, ":", 1);
+ MD5Update(&Md5Ctx, pszCNonce, strlen(pszCNonce));
+ MD5Final(HA1, &Md5Ctx);
+ };
+ CvtHex(HA1, SessionKey);
+};
+
+/* calculate request-digest/response-digest as per HTTP Digest spec */
+void DigestCalcResponse(
+ IN HASHHEX HA1, /* H(A1) */
+ IN char * pszNonce, /* nonce from server */
+ IN char * pszNonceCount, /* 8 hex digits */
+ IN char * pszCNonce, /* client nonce */
+ IN char * pszQop, /* qop-value: "", "auth", "auth-int" */
+ IN char * pszMethod, /* method from the request */
+ IN char * pszDigestUri, /* requested URL */
+ IN HASHHEX HEntity, /* H(entity body) if qop="auth-int" */
+ OUT HASHHEX Response /* request-digest or response-digest */
+ )
+{
+ MD5_CTX Md5Ctx;
+ HASH HA2;
+ HASH RespHash;
+ HASHHEX HA2Hex;
+
+ // calculate H(A2)
+ MD5Init(&Md5Ctx);
+ MD5Update(&Md5Ctx, pszMethod, strlen(pszMethod));
+ MD5Update(&Md5Ctx, ":", 1);
+ MD5Update(&Md5Ctx, pszDigestUri, strlen(pszDigestUri));
+ if (stricmp(pszQop, "auth-int") == 0) {
+ MD5Update(&Md5Ctx, ":", 1);
+ MD5Update(&Md5Ctx, HEntity, HASHHEXLEN);
+ };
+ MD5Final(HA2, &Md5Ctx);
+ CvtHex(HA2, HA2Hex);
+
+ // calculate response
+ MD5Init(&Md5Ctx);
+ MD5Update(&Md5Ctx, HA1, HASHHEXLEN);
+ MD5Update(&Md5Ctx, ":", 1);
+ MD5Update(&Md5Ctx, pszNonce, strlen(pszNonce));
+ MD5Update(&Md5Ctx, ":", 1);
+ if (*pszQop) {
+
+
+
+Franks, et al. Standards Track [Page 29]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ MD5Update(&Md5Ctx, pszNonceCount, strlen(pszNonceCount));
+ MD5Update(&Md5Ctx, ":", 1);
+ MD5Update(&Md5Ctx, pszCNonce, strlen(pszCNonce));
+ MD5Update(&Md5Ctx, ":", 1);
+ MD5Update(&Md5Ctx, pszQop, strlen(pszQop));
+ MD5Update(&Md5Ctx, ":", 1);
+ };
+ MD5Update(&Md5Ctx, HA2Hex, HASHHEXLEN);
+ MD5Final(RespHash, &Md5Ctx);
+ CvtHex(RespHash, Response);
+};
+
+File "digtest.c":
+
+
+#include <stdio.h>
+#include "digcalc.h"
+
+void main(int argc, char ** argv) {
+
+ char * pszNonce = "dcd98b7102dd2f0e8b11d0f600bfb0c093";
+ char * pszCNonce = "0a4f113b";
+ char * pszUser = "Mufasa";
+ char * pszRealm = "testrealm@host.com";
+ char * pszPass = "Circle Of Life";
+ char * pszAlg = "md5";
+ char szNonceCount[9] = "00000001";
+ char * pszMethod = "GET";
+ char * pszQop = "auth";
+ char * pszURI = "/dir/index.html";
+ HASHHEX HA1;
+ HASHHEX HA2 = "";
+ HASHHEX Response;
+
+ DigestCalcHA1(pszAlg, pszUser, pszRealm, pszPass, pszNonce,
+pszCNonce, HA1);
+ DigestCalcResponse(HA1, pszNonce, szNonceCount, pszCNonce, pszQop,
+ pszMethod, pszURI, HA2, Response);
+ printf("Response = %s\n", Response);
+};
+
+
+
+
+
+
+
+
+
+
+
+Franks, et al. Standards Track [Page 30]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+6 Acknowledgments
+
+ Eric W. Sink, of AbiSource, Inc., was one of the original authors
+ before the specification underwent substantial revision.
+
+ In addition to the authors, valuable discussion instrumental in
+ creating this document has come from Peter J. Churchyard, Ned Freed,
+ and David M. Kristol.
+
+ Jim Gettys and Larry Masinter edited this document for update.
+
+7 References
+
+ [1] Berners-Lee, T., Fielding, R. and H. Frystyk, "Hypertext
+ Transfer Protocol -- HTTP/1.0", RFC 1945, May 1996.
+
+ [2] Fielding, R., Gettys, J., Mogul, J., Frysyk, H., Masinter, L.,
+ Leach, P. and T. Berners-Lee, "Hypertext Transfer Protocol --
+ HTTP/1.1", RFC 2616, June 1999.
+
+ [3] Rivest, R., "The MD5 Message-Digest Algorithm", RFC 1321, April
+ 1992.
+
+ [4] Freed, N. and N. Borenstein. "Multipurpose Internet Mail
+ Extensions (MIME) Part One: Format of Internet Message Bodies",
+ RFC 2045, November 1996.
+
+ [5] Dierks, T. and C. Allen "The TLS Protocol, Version 1.0", RFC
+ 2246, January 1999.
+
+ [6] Franks, J., Hallam-Baker, P., Hostetler, J., Leach, P.,
+ Luotonen, A., Sink, E. and L. Stewart, "An Extension to HTTP :
+ Digest Access Authentication", RFC 2069, January 1997.
+
+ [7] Berners Lee, T, Fielding, R. and L. Masinter, "Uniform Resource
+ Identifiers (URI): Generic Syntax", RFC 2396, August 1998.
+
+ [8] Kaliski, B.,Robshaw, M., "Message Authentication with MD5",
+ CryptoBytes, Sping 1995, RSA Inc,
+ (http://www.rsa.com/rsalabs/pubs/cryptobytes/spring95/md5.htm)
+
+ [9] Klensin, J., Catoe, R. and P. Krumviede, "IMAP/POP AUTHorize
+ Extension for Simple Challenge/Response", RFC 2195, September
+ 1997.
+
+ [10] Morgan, B., Alvestrand, H., Hodges, J., Wahl, M.,
+ "Authentication Methods for LDAP", Work in Progress.
+
+
+
+
+Franks, et al. Standards Track [Page 31]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+8 Authors' Addresses
+
+ John Franks
+ Professor of Mathematics
+ Department of Mathematics
+ Northwestern University
+ Evanston, IL 60208-2730, USA
+
+ EMail: john@math.nwu.edu
+
+
+ Phillip M. Hallam-Baker
+ Principal Consultant
+ Verisign Inc.
+ 301 Edgewater Place
+ Suite 210
+ Wakefield MA 01880, USA
+
+ EMail: pbaker@verisign.com
+
+
+ Jeffery L. Hostetler
+ Software Craftsman
+ AbiSource, Inc.
+ 6 Dunlap Court
+ Savoy, IL 61874
+
+ EMail: jeff@AbiSource.com
+
+
+ Scott D. Lawrence
+ Agranat Systems, Inc.
+ 5 Clocktower Place, Suite 400
+ Maynard, MA 01754, USA
+
+ EMail: lawrence@agranat.com
+
+
+ Paul J. Leach
+ Microsoft Corporation
+ 1 Microsoft Way
+ Redmond, WA 98052, USA
+
+ EMail: paulle@microsoft.com
+
+
+
+
+
+
+
+Franks, et al. Standards Track [Page 32]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ Ari Luotonen
+ Member of Technical Staff
+ Netscape Communications Corporation
+ 501 East Middlefield Road
+ Mountain View, CA 94043, USA
+
+
+ Lawrence C. Stewart
+ Open Market, Inc.
+ 215 First Street
+ Cambridge, MA 02142, USA
+
+ EMail: stewart@OpenMarket.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Franks, et al. Standards Track [Page 33]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+9. Full Copyright Statement
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Franks, et al. Standards Track [Page 34]
+
diff --git a/standards/rfc2639.txt b/standards/rfc2639.txt
new file mode 100644
index 000000000..e3ab71684
--- /dev/null
+++ b/standards/rfc2639.txt
@@ -0,0 +1,3587 @@
+
+
+
+
+
+
+Network Working Group T. Hastings
+Request for Comments: 2639 C. Manros
+Category: Informational Xerox Corporation
+ July 1999
+
+
+ Internet Printing Protocol/1.0: Implementer's Guide
+
+Status of this Memo
+
+ This memo provides information for the Internet community. It does
+ not specify an Internet standard of any kind. Distribution of this
+ memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+Abstract
+
+ This document is one of a set of documents, which together describe
+ all aspects of a new Internet Printing Protocol (IPP). IPP is an
+ application level protocol that can be used for distributed printing
+ using Internet tools and technologies. This document contains
+ information that supplements the IPP Model and Semantics [RFC2566]
+ and the IPP Transport and Encoding [RFC2565] documents. It is
+ intended to help implementers understand IPP/1.0 and some of the
+ considerations that may assist them in the design of their client
+ and/or IPP object implementations. For example, a typical order of
+ processing requests is given, including error checking. Motivation
+ for some of the specification decisions is also included.
+
+ The full set of IPP documents includes:
+
+ Design Goals for an Internet Printing Protocol [RFC2567]
+ Rationale for the Structure and Model and Protocol for the Internet
+ Printing Protocol [RFC2568]
+ Internet Printing Protocol/1.0: Model and Semantics [RFC2566]
+ Internet Printing Protocol/1.0: Encoding and Transport [RFC2565]
+ Mapping between LPD and IPP Protocols [RFC2569]
+
+ The document, "Design Goals for an Internet Printing Protocol", takes
+ a broad look at distributed printing functionality, and it enumerates
+ real-life scenarios that help to clarify the features that need to be
+ included in a printing protocol for the Internet. It identifies
+ requirements for three types of users: end users, operators, and
+
+
+
+
+
+Hastings & Manros Informational [Page 1]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ administrators. The design goals document calls out a subset of end
+ user requirements that are satisfied in IPP/1.0. Operator and
+ administrator requirements are out of scope for version 1.0.
+
+ The document, "Rationale for the Structure and Model and Protocol for
+ the Internet Printing Protocol", describes IPP from a high level
+ view, defines a roadmap for the various documents that form the suite
+ of IPP specifications, and gives background and rationale for the
+ IETF working group's major decisions.
+
+ The document, "Internet Printing Protocol/1.0: Model and Semantics",
+ describes a simplified model with abstract objects, their attributes,
+ and their operations. The model introduces a Printer and a Job. The
+ Job supports multiple documents per Job. The model document also
+ addresses how security, internationalization, and directory issues
+ are addressed.
+
+ The document, "Internet Printing Protocol/1.0: Encoding and
+ Transport", is a formal mapping of the abstract operations and
+ attributes defined in the model document onto HTTP/1.1. It also
+ defines the encoding rules for a new Internet media type called
+ "application/ipp".
+
+ The document, "Mapping between LPD and IPP Protocols", gives some
+ advice to implementers of gateways between IPP and LPD (Line Printer
+ Daemon) implementations.
+
+Table of Contents
+
+ 1 Introduction......................................................4
+ 1.1 Conformance language............................................4
+ 1.2 Other terminology...............................................5
+ 2 Model and Semantics...............................................5
+ 2.1 Summary of Operation Attributes.................................5
+ 2.2 Suggested Operation Processing Steps for IPP Objects ..........10
+ 2.2.1 Suggested Operation Processing Steps for all Operations..11
+ 2.2.1.1 Validate version number...............................11
+ 2.2.1.2 Validate operation identifier.........................11
+ 2.2.1.3 Validate the request identifier.......................11
+ 2.2.1.4 Validate attribute group and attribute presence and
+ order.................................................12
+ 2.2.1.5 Validate the values of the REQUIRED Operation
+ attributes............................................19
+ 2.2.1.6 Validate the values of the OPTIONAL Operation
+ attributes............................................23
+ 2.2.2 Suggested Additional Processing Steps for Operations that
+ Create/Validate Jobs and Add Documents.....................26
+ 2.2.2.1 Default "ipp-attribute-fidelity" if not supplied......26
+
+
+
+Hastings & Manros Informational [Page 2]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ 2.2.2.2 Check that the Printer object is accepting jobs.......26
+ 2.2.2.3 Validate the values of the Job Template attributes....26
+ 2.2.3 Algorithm for job validation...............................27
+ 2.2.3.1 Check for conflicting Job Template attributes values..33
+ 2.2.3.2 Decide whether to REJECT the request..................33
+ 2.2.3.3 For the Validate-Job operation, RETURN one of the
+ success status codes..................................34
+ 2.2.3.4 Create the Job object with attributes to support......34
+ 2.2.3.5 Return one of the success status codes................36
+ 2.2.3.6 Accept appended Document Content......................36
+ 2.2.3.7 Scheduling and Starting to Process the Job............36
+ 2.2.3.8 Completing the Job....................................37
+ 2.2.3.9 Destroying the Job after completion...................37
+ 2.2.3.10 Interaction with "ipp-attribute-fidelity".............37
+ 2.3 Status codes returned by operation ............................37
+ 2.3.1 Printer Operations.........................................38
+ 2.3.1.1 Print-Job.............................................38
+ 2.3.1.2 Print-URI.............................................40
+ 2.3.1.3 Validate-Job..........................................40
+ 2.3.1.4 Create-Job............................................41
+ 2.3.1.5 Get-Printer-Attributes................................41
+ 2.3.1.6 Get-Jobs..............................................42
+ 2.3.2 Job Operations.............................................43
+ 2.3.2.1 Send-Document.........................................43
+ 2.3.2.2 Send-URI..............................................44
+ 2.3.2.3 Cancel-Job............................................44
+ 2.3.2.4 Get-Job-Attributes....................................45
+ 2.4 Validate-Job...................................................46
+ 2.5 Case Sensitivity in URIs ......................................46
+ 2.6 Character Sets, natural languages, and internationalization....46
+ 2.6.1 Character set code conversion support .....................46
+ 2.6.2 What charset to return when an unsupported charset is
+ requested?.................................................48
+ 2.6.3 Natural Language Override (NLO) ...........................48
+ 2.7 The "queued-job-count" Printer Description attribute...........50
+ 2.7.1 Why is "queued-job-count" RECOMMENDED?.....................50
+ 2.7.2 Is "queued-job-count" a good measure of how busy a printer
+ is?........................................................50
+ 2.8 Sending empty attribute groups ................................50
+ 2.9 Returning unsupported attributes in Get-Xxxx responses ........51
+ 2.10 Returning job-state in Print-Job response ....................51
+ 2.11 Flow controlling the data portion of a Print-Job request .....52
+ 2.12 Multi-valued attributes ......................................53
+ 2.13 Querying jobs with IPP that were submitted using other job
+ submission protocols .........................................53
+ 2.14 The 'none' value for empty sets ..............................54
+ 2.15 Get-Jobs, my-jobs='true', and 'requesting-user-name'?.........54
+
+
+
+
+Hastings & Manros Informational [Page 3]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ 2.16 The "multiple-document-handling" Job Template attribute and
+ support of multiple document jobs.............................54
+ 3 Encoding and Transport...........................................55
+ 3.1 General Headers................................................56
+ 3.2 Request Headers...............................................57
+ 3.3 Response Headers...............................................58
+ 3.4 Entity Headers................................................59
+ 3.5 Optional support for HTTP/1.0..................................60
+ 3.6 HTTP/1.1 Chunking..............................................60
+ 3.6.1 Disabling IPP Server Response Chunking.....................60
+ 3.6.2 Warning About the Support of Chunked Requests..............60
+ 4 References.......................................................61
+ 4.1 Authors' Addresses.............................................62
+ 5 Security Considerations..........................................62
+ 6 Notices..........................................................62
+ Full Copyright Statement............................................65
+
+1 Introduction
+
+ This document contains information that supplements the IPP Model and
+ Semantics [RFC2566] and the IPP Transport and Encoding [RFC2565]
+ documents. As such this information is not part of the formal
+ specifications. Instead information is presented to help implementers
+ understand the specification, including some of the motivation for
+ decisions taken by the committee in developing the specification.
+ Some of the implementation considerations are intended to help
+ implementers design their client and/or IPP object implementations.
+ If there are any contradictions between this document and [RFC2566] or
+ [RFC2565], those documents take precedence over this document.
+
+1.1 Conformance language
+
+ Usually, this document does not contain the terminology MUST, MUST
+ NOT, MAY, NEED NOT, SHOULD, SHOULD NOT, REQUIRED, and OPTIONAL.
+ However, when those terms do appear in this document, their intent is
+ to repeat what the [RFC2566] and [RFC2565] documents require and
+ allow, rather than specifying additional conformance requirements.
+ These terms are defined in section 13 on conformance terminology in
+ [RFC2566], most of which is taken from RFC 2119 [RFC2119].
+
+ Implementers should read section 13 in [RFC2566] in order to
+ understand these capitalized words. The words MUST, MUST NOT, and
+ REQUIRED indicate what implementations are required to support in a
+ client or IPP object in order to be conformant to [RFC2566] and
+ [RFC2565]. MAY, NEED NOT, and OPTIONAL indicate was is merely allowed
+ as an implementer option. The verbs SHOULD and SHOULD NOT indicate
+ suggested behavior, but which is not required or disallowed,
+ respectively, in order to conform to the specification.
+
+
+
+Hastings & Manros Informational [Page 4]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+1.2 Other terminology
+
+ The term "sender" refers to the client that sends a request or an IPP
+ object that returns a response. The term "receiver" refers to the IPP
+ object that receives a request and to a client that receives a
+ response.
+
+2 Model and Semantics
+
+ This section discusses various aspects of IPP/1.0 Model and Semantics
+ [RFC2566].
+
+2.1 Summary of Operation Attributes
+
+ Legend for the following table:
+
+ R indicates a REQUIRED operation or attribute for an
+ implementation to support
+
+ O indicates an OPTIONAL operation or attribute for an
+ implementation to support
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings & Manros Informational [Page 5]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ Table 1. Summary of operation attributes for Printer operations
+
+ Printer Operations
+
+ Requests Responses
+
+ Operation Print- Pri Crea Get- Get- All
+ Attributes Job, nt- te- Printer- Jobs Opera-
+ Validate URI Job Attribut tions
+ -Job (O) (O) es
+
+ Operation parameters--REQUIRED to be supplied by the sender
+
+ operation-id R R R R R
+
+ status-code R
+
+ request-id R R R R R R
+
+ version-number R R R R R R
+
+ Operation attributes-REQUIRED to be supplied by the sender
+
+ attributes-charset R R R R R R
+
+ attributes- R R R R R R
+ natural-language
+
+ document-uri R
+
+ job-id*
+
+ job-uri*
+
+ last-document
+
+ printer-uri R R R R R
+
+ Operation attributes-RECOMMENDED to be supplied by the sender
+
+ job-name R R R
+
+ requesting-user- R R R R R
+ name
+
+
+
+
+
+
+
+Hastings & Manros Informational [Page 6]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ Printer Operations
+
+ Requests Responses
+
+ Operation Print- Pri Crea Get- Get- All
+ Attributes Job, nt- te- Printer Jobs Opera-
+ Vali- URI Job Attri- tions
+ date-Job (O) (O) butes
+
+ Operation attributes-OPTIONAL to be supplied by the sender
+
+ status-message O
+
+ compression O O
+
+ document-format R R O
+
+ document-name O O
+
+ document-natural- O O
+ language
+
+ ipp-attribute- R R R
+ fidelity
+
+ job-impressions O O O
+
+ job-k-octets O O O
+
+ job-media-sheets O O O
+
+ limit R
+
+ message
+
+ my-jobs R
+
+ requested- R R
+ attributes
+
+ which-jobs R
+
+ * "job-id" is REQUIRED only if used together with
+ "printer-uri" to identify the target job; otherwise, "job-
+ uri" is REQUIRED.
+
+
+
+
+
+
+Hastings & Manros Informational [Page 7]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ Table 2. Summary of operation attributes for Job operations
+
+
+ Requests Responses
+
+ Operation Send- Send- Cancel Get- All
+ Attributes Document URI -Job Job- Opera-
+ (O) (O) Attri- tions
+ butes
+
+ Operation parameters--REQUIRED to be supplied by the sender
+
+ operation-id R R R R
+
+ status-code R
+
+ request-id R R R R R
+
+ version-number R R R R R
+
+ Operation attributes-REQUIRED to be supplied by the sender
+
+ attributes- R R R R R
+ charset
+
+ attributes- R R R R R
+ natural-language
+
+ document-uri R
+
+ job-id* R R R R
+
+ job-uri* R R R R
+
+ last-document R R
+
+ printer-uri R R R R
+
+ Operation attributes-RECOMMENDED to be supplied by the
+ sender
+
+ job-name
+
+ requesting-user- R R R R
+ name
+
+
+
+
+
+
+Hastings & Manros Informational [Page 8]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ Job Operations
+
+ Requests Responses
+
+ Operation Attributes Send- Send- Cance Get- All
+ Document URI l-Job Job- Opera-
+ (O) (O) Attri- tions
+ butes
+
+ Operation attributes.OPTIONAL to be supplied by the sender
+
+ status-message O
+
+ compression O O
+
+ document-format R R
+
+ document-name O O
+
+ document-natural- O O
+ language
+
+ ipp-attribute-
+ fidelity
+
+ job-impressions
+
+ job-k-octets
+
+ job-media-sheets
+
+ limit
+
+ message O
+
+ my-jobs
+
+ requested-attributes R
+
+ which-jobs
+
+ * "job-id" is REQUIRED only if used together with "printer-
+ uri" to identify the target job; otherwise, "job-uri" is
+ REQUIRED.
+
+
+
+
+
+
+
+Hastings & Manros Informational [Page 9]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+2.2 Suggested Operation Processing Steps for IPP Objects
+
+ This section suggests the steps and error checks that an IPP object
+ MAY perform when processing requests and returning responses. An IPP
+ object MAY perform some or all of the error checks. However, some
+ implementations MAY choose to be more forgiving than the error checks
+ shown here, in order to be able to accept requests from non-
+ conforming clients. Not performing all of these error checks is a
+ so-called "forgiving" implementation. On the other hand, clients
+ that successfully submit requests to IPP objects that do perform all
+ the error checks will be more likely to be able to interoperate with
+ other IPP object implementations. Thus an implementer of an IPP
+ object needs to decide whether to be a "forgiving" or a "strict"
+ implementation. Therefore, the error status codes returned may
+ differ between implementations. Consequentially, client SHOULD NOT
+ expect exactly the error code processing described in this section.
+
+ When an IPP object receives a request, the IPP object either accepts
+ or rejects the request. In order to determine whether or not to
+ accept or reject the request, the IPP object SHOULD execute the
+ following steps. The order of the steps may be rearranged and/or
+ combined, including making one or multiple passes over the request.
+
+ A client MUST supply requests that would pass all of the error checks
+ indicated here in order to be a conforming client. Therefore, a
+ client SHOULD supply requests that are conforming, in order to avoid
+ being rejected by some IPP object implementations and/or risking
+ different semantics by different implementations of forgiving
+ implementations. For example, a forgiving implementation that
+ accepts multiple occurrences of the same attribute, rather than
+ rejecting the request might use the first occurrences, while another
+ might use the last occurrence. Thus such a non-conforming client
+ would get different results from the two forgiving implementations.
+
+ In the following, processing continues step by step until a "RETURNS
+ the xxx status code ." statement is encountered. Error returns are
+ indicated by the verb: "REJECTS". Since clients have difficulty
+ getting the status code before sending all of the document data in a
+ Print-Job request, clients SHOULD use the Validate-Job operation
+ before sending large documents to be printed, in order to validate
+ whether the IPP Printer will accept the job or not.
+
+ It is assumed that security authentication and authorization has
+ already taken place at a lower layer.
+
+
+
+
+
+
+
+Hastings & Manros Informational [Page 10]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+2.2.1 Suggested Operation Processing Steps for all Operations
+
+ This section is intended to apply to all operations. The next
+ section contains the additional steps for the Print-Job, Validate-
+ Job, Print-URI, Create-Job, Send-Document, and Send-URI operations
+ that create jobs, adds documents, and validates jobs.
+
+2.2.1.1 Validate version number
+
+ Every request and every response contains the "version-number"
+ attribute. The value of this attribute is the major and minor
+ version number of the syntax and semantics that the client and IPP
+ object is using, respectively. The "version-number" attribute
+ remains in a fixed position across all future versions so that all
+ clients and IPP object that support future versions can determine
+ which version is being used. The IPP object checks to see if the
+ major version number supplied in the request is supported. If not,
+ the Printer object REJECTS the request and RETURNS the 'server-
+ error-version-not-supported' status code in the response. The IPP
+ object returns in the "version-number" response attribute the major
+ and minor version for the error response. Thus the client can learn
+ at least one major and minor version that the IPP object supports.
+ The IPP object is encouraged to return the closest version number to
+ the one supplied by the client.
+
+ The checking of the minor version number is implementation dependent,
+ however if the client supplied minor version is explicitly supported,
+ the IPP object MUST respond using that identical minor version
+ number. If the requested minor version is not supported (the
+ requested minor version is either higher or lower) than a supported
+ minor version, the IPP object SHOULD return the closest supported
+ minor version.
+
+2.2.1.2 Validate operation identifier
+
+ The Printer object checks to see if the "operation-id" attribute
+ supplied by the client is supported as indicated in the Printer
+ object's "operations-supported" attribute. If not, the Printer
+ REJECTS the request and returns the 'server-error-operation-not-
+ supported' status code in the response.
+
+2.2.1.3 Validate the request identifier
+
+ The Printer object SHOULD NOT check to see if the "request-id"
+ attribute supplied by the client is in range: between 1 and 2**31 - 1
+ (inclusive), but copies all 32 bits.
+
+
+
+
+
+Hastings & Manros Informational [Page 11]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ Note: The "version-number", "operation-id", and the "request-id"
+ parameters are in fixed octet positions in the IPP/1.0 encoding. The
+ "version-number" parameter will be the same fixed octet position in
+ all versions of the protocol. These fields are validated before
+ proceeding with the rest of the validation.
+
+2.2.1.4 Validate attribute group and attribute presence and order
+
+ The order of the following validation steps depends on
+ implementation.
+
+2.2.1.4.1 Validate the presence and order of attribute groups
+
+ Client requests and IPP object responses contain attribute groups
+ that Section 3 requires to be present and in a specified order. An
+ IPP object verifies that the attribute groups are present and in the
+ correct order in requests supplied by clients (attribute groups
+ without an * in the following tables).
+
+ If an IPP object receives a request with (1) required attribute
+ groups missing, or (2) the attributes groups are out of order, or (3)
+ the groups are repeated, the IPP object REJECTS the request and
+ RETURNS the 'client-error-bad-request' status code. For example, it
+ is an error for the Job Template Attributes group to occur before the
+ Operation Attributes group, for the Operation Attributes group to be
+ omitted, or for an attribute group to occur more than once, except in
+ the Get-Jobs response.
+
+ Since this kind of attribute group error is most likely to be an
+ error detected by a client developer rather than by a customer, the
+ IPP object NEED NOT return an indication of which attribute group was
+ in error in either the Unsupported Attributes group or the Status
+ Message. Also, the IPP object NEED NOT find all attribute group
+ errors before returning this error.
+
+2.2.1.4.2 Ignore unknown attribute groups in the expected position
+
+ Future attribute groups may be added to the specification at the end
+ of requests just before the Document Content and at the end of
+ response, except for the Get-Jobs response, where it maybe there or
+ before the first job attributes returned. If an IPP object receives
+ an unknown attribute group in these positions, it ignores the entire
+ group, rather than returning an error, since that group may be a new
+ group in a later minor version of the protocol that can be ignored.
+ (If the new attribute group cannot be ignored without confusing the
+ client, the major version number would have been increased in the
+
+
+
+
+
+Hastings & Manros Informational [Page 12]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ protocol document and in the request). If the unknown group occurs
+ in a different position, the IPP object REJECTS the request and
+ RETURNS the 'client-error-bad-request' status code.
+
+ Clients also ignore unknown attribute groups returned in a response.
+
+ Note: By validating that requests are in the proper form, IPP
+ objects force clients to use the proper form which, in turn,
+ increases the chances that customers will be able to use such clients
+ from multiple vendors with IPP objects from other vendors.
+
+2.2.1.4.3 Validate the presence of a single occurrence of required
+ Operation attributes
+
+ Client requests and IPP object responses contain Operation attributes
+ that [RFC2566] Section 3 requires to be present. Attributes within a
+ group may be in any order, except for the ordering of target,
+ charset, and natural languages attributes. These attributes MUST be
+ first, and MUST be supplied in the following order: charset, natural
+ language, and then target. An IPP object verifies that the attributes
+ that Section 4 requires to be supplied by the client have been
+ supplied in the request (attributes without an * in the following
+ tables). An asterisk (*) indicates groups and Operation attributes
+ that the client may omit in a request or an IPP object may omit in a
+ response.
+
+ If an IPP object receives a request with required attributes missing
+ or repeated from a group or in the wrong position, the behavior of
+ the IPP object is IMPLEMENTATION DEPENDENT. Some of the possible
+ implementations are:
+
+ 1.REJECTS the request and RETURNS the 'client-error-bad-request'
+ status code
+
+ 2.accepts the request and uses the first occurrence of the
+ attribute no matter where it is
+
+ 3.accepts the request and uses the last occurrence of the
+ attribute no matter where it is
+
+ 4.accept the request and assume some default value for the missing
+ attribute
+
+ Therefore, client MUST send conforming requests, if they want to
+ receive the same behavior from all IPP object implementations. For
+ example, it is an error for the "attributes-charset" or "attributes-
+ natural-language" attribute to be omitted in any operation request,
+ or for an Operation attribute to be supplied in a Job Template group
+
+
+
+Hastings & Manros Informational [Page 13]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ or a Job Template attribute to be supplied in an Operation Attribute
+ group in a create request. It is also an error to supply the
+ "attributes-charset" attribute twice.
+
+ Since these kinds of attribute errors are most likely to be detected
+ by a client developer rather than by a customer, the IPP object NEED
+ NOT return an indication of which attribute was in error in either
+ the Unsupported Attributes group or the Status Message. Also, the
+ IPP object NEED NOT find all attribute errors before returning this
+ error.
+
+ The following tables list all the attributes for all the operations
+ by attribute group in each request and each response. The order of
+ the groups is the order that the client supplies the groups as
+ specified in [RFC2566] Section 3. The order of the attributes within
+ a group is arbitrary, except as noted for some of the special
+ operation attributes (charset, natural language, and target). The
+ tables below use the following notation:
+
+ R indicates a REQUIRED attribute that an IPP object MUST support
+ O indicates an OPTIONAL attribute that an IPP object NEED NOT
+ support
+ * indicates that a client MAY omit the attribute in a request
+ and that an IPP object MAY omit the attribute in a
+ response. The absence of an * means that a client MUST
+ supply the attribute in a request and an IPP object MUST
+ supply the attribute in a response.
+
+ Operation Requests
+
+ The tables below show the attributes in their proper attribute groups
+ for operation requests:
+
+ Note: All operation requests contain "version-number", "operation-
+ id", and "request-id" parameters.
+
+ Print-Job Request:
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ printer-uri (R)
+ requesting-user-name (R*)
+ job-name (R*)
+ ipp-attribute-fidelity (R*)
+ document-name (R*)
+ document-format (R*)
+ document-natural-language (O*)
+ compression (O*)
+
+
+
+Hastings & Manros Informational [Page 14]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ job-k-octets (O*)
+ job-impressions (O*)
+ job-media-sheets (O*)
+ Group 2: Job Template Attributes (R*)
+ <Job Template attributes> (O*)
+ (see [RFC2566] Section 4.2)
+ Group 3: Document Content (R)
+ <document content>
+
+ Validate-Job Request:
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ printer-uri (R)
+ requesting-user-name (R*)
+ job-name (R*)
+ ipp-attribute-fidelity (R*)
+ document-name (R*)
+ document-format (R*)
+ document-natural-language (O*)
+ compression (O*)
+ job-k-octets (O*)
+ job-impressions (O*)
+ job-media-sheets (O*)
+ Group 2: Job Template Attributes (R*)
+ <Job Template attributes> (O*)
+ (see [RFC2566] Section 4.2)
+
+ Create-Job Request:
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ printer-uri (R)
+ requesting-user-name (R*)
+ job-name (R*)
+ ipp-attribute-fidelity (R*)
+ job-k-octets (O*)
+ job-impressions (O*)
+ job-media-sheets (O*)
+ Group 2: Job Template Attributes (R*)
+ <Job Template attributes> (O*) (see
+ (see [RFC2566] Section 4.2)
+
+ Print-URI Request:
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ printer-uri (R)
+
+
+
+Hastings & Manros Informational [Page 15]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ document-uri (R)
+ requesting-user-name (R*)
+ job-name (R*)
+ ipp-attribute-fidelity (R*)
+ document-name (R*)
+ document-format (R*)
+ document-natural-language (O*)
+ compression (O*)
+ job-k-octets (O*)
+ job-impressions (O*)
+ job-media-sheets (O*)
+ Group 2: Job Template Attributes (R*)
+ <Job Template attributes> (O*) (see
+ (see [RFC2566] Section 4.2)
+
+ Send-Document Request:
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ (printer-uri & job-id) | job-uri (R)
+ last-document (R)
+ requesting-user-name (R*)
+ document-name (R*)
+ document-format (R*)
+ document-natural-language (O*)
+ compression (O*)
+ Group 2: Document Content (R*)
+ <document content>
+
+ Send-URI Request:
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ (printer-uri & job-id) | job-uri (R)
+ last-document (R)
+ document-uri (R)
+ requesting-user-name (R*)
+ document-name (R*)
+ document-format (R*)
+ document-natural-language (O*)
+ compression (O*)
+
+
+
+
+
+
+
+
+
+
+Hastings & Manros Informational [Page 16]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ Cancel-Job Request:
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ (printer-uri & job-id) | job-uri (R)
+ requesting-user-name (R*)
+ message (O*)
+
+ Get-Printer-Attributes Request:
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ printer-uri (R)
+ requesting-user-name (R*)
+ requested-attributes (R*)
+ document-format (R*)
+
+ Get-Job-Attributes Request:
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ (printer-uri & job-id) | job-uri (R)
+ requesting-user-name (R*)
+ requested-attributes (R*)
+
+ Get-Jobs Request:
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ printer-uri (R)
+ requesting-user-name (R*)
+ limit (R*)
+ requested-attributes (R*)
+ which-jobs (R*)
+ my-jobs (R*)
+
+
+ Operation Responses
+
+ The tables below show the response attributes in their proper
+ attribute groups for responses.
+
+ Note: All operation responses contain "version-number", "status-
+ code", and "request-id" parameters.
+
+ Print-Job Response:
+ Print-URI Response:
+ Create-Job Response:
+
+
+
+Hastings & Manros Informational [Page 17]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ Send-Document Response:
+ Send-URI Response:
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ status-message (O*)
+ Group 2: Unsupported Attributes (R*) (see Note 3)
+ <unsupported attributes> (R*)
+ Group 3: Job Object Attributes(R*) (see Note 2)
+ job-uri (R)
+ job-id (R)
+ job-state (R)
+ job-state-reasons (O*)
+ job-state-message (O*)
+ number-of-intervening-jobs (O*)
+
+ Validate-Job Response:
+ Cancel-Job Response:
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ status-message (O*)
+ Group 2: Unsupported Attributes (R*) (see Note 3)
+ <unsupported attributes> (R*)
+
+ Note 2 - the Job Object Attributes and Printer Object Attributes are
+ returned only if the IPP object returns one of the success status
+ codes.
+
+ Note 3 - the Unsupported Attributes Group is present only if the
+ client included some Operation and/or Job Template attributes or
+ values that the Printer doesn't support whether a success or an error
+ return.
+
+ Get-Printer-Attributes Response:
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ status-message (O*)
+ Group 2: Unsupported Attributes (R*) (see Note 4)
+ <unsupported attributes> (R*)
+ Group 3: Printer Object Attributes(R*) (see Note 2)
+ <requested attributes> (R*)
+
+ Note 4 - the Unsupported Attributes Group is present only if the
+ client included some Operation attributes that the Printer doesn't
+ support whether a success or an error return.
+
+
+
+
+Hastings & Manros Informational [Page 18]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ Get-Job-Attributes Response:
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ status-message (O*)
+ Group 2: Unsupported Attributes (R*) (see Note 4)
+ <unsupported attributes> (R*)
+ Group 3: Job Object Attributes(R*) (see Note 2)
+ <requested attributes> (R*)
+
+ Get-Jobs Response:
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ status-message (O*)
+ Group 2: Unsupported Attributes (R*) (see Note 4)
+ <unsupported attributes> (R*)
+ Group 3: Job Object Attributes(R*) (see Note 2, 5)
+ <requested attributes> (R*)
+
+ Note 5: for the Get-Jobs operation the response contains a separate
+ Job Object Attributes group 3 to N containing requested-attributes
+ for each job object in the response.
+
+2.2.1.5 Validate the values of the REQUIRED Operation attributes
+
+ An IPP object validates the values supplied by the client of the
+ REQUIRED Operation attribute that the IPP object MUST support. The
+ next section specifies the validation of the values of the OPTIONAL
+ Operation attributes that IPP objects MAY support.
+
+ The IPP object performs the following syntactic validation checks of
+ each Operation attribute value:
+
+ a)that the length of each Operation attribute value is correct for
+ the attribute syntax tag supplied by the client according to
+ [RFC2566] Section 4.1,
+
+ b)that the attribute syntax tag is correct for that Operation
+ attribute according to [RFC2566] Section 3,
+
+ c)that the value is in the range specified for that Operation
+ attribute according to [RFC2566] Section 3,
+
+ d)that multiple values are supplied by the client only for
+ operation attributes that are multi-valued, i.e., that are
+ 1setOf X according to [RFC2566] Section 3.
+
+
+
+
+Hastings & Manros Informational [Page 19]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ If any of these checks fail, the IPP object REJECTS the request and
+ RETURNS the 'client-error-bad-request' or the 'client-error-request-
+ value-too-long' status code. Since such an error is most likely to
+ be an error detected by a client developer, rather than by an end-
+ user, the IPP object NEED NOT return an indication of which attribute
+ had the error in either the Unsupported Attributes Group or the
+
+ Status Message. The description for each of these syntactic checks
+ is explicitly expressed in the first IF statement in the following
+ table.
+
+ In addition, the IPP object checks each Operation attribute value
+ against some Printer object attribute or some hard-coded value if
+ there is no "xxx-supported" Printer object attribute defined. If its
+ value is not among those supported or is not in the range supported,
+ then the IPP object REJECTS the request and RETURNS the error status
+ code indicated in the table by the second IF statement. If the value
+ of the Printer object's "xxx-supported" attribute is 'no-value'
+ (because the system administrator hasn't configured a value), the
+ check always fails.
+
+ attributes-charset (charset)
+
+ IF NOT a single non-empty 'charset' value, REJECT/RETURN 'client-
+ error-bad-request'.
+
+ IF the value length is greater than 63 octets, REJECT/RETURN '
+ client-error-request-value-too-long'.
+ IF NOT in the Printer object's "charset-supported" attribute,
+ REJECT/RETURN "client-error-charset-not-supported".
+
+
+ attributes-natural-language(naturalLanguage)
+
+ IF NOT a single non-empty 'naturalLanguage' value, REJECT/RETURN
+ 'client-error-bad-request'.
+ IF the value length is greater than 63 octets, REJECT/RETURN '
+ client-error-request-value-too-long'.
+ ACCEPT the request even if not a member of the set in the Printer
+ object's "generated-natural-language-supported" attribute. If
+ the supplied value is not a member of the Printer object's
+ "generated-natural-language-supported" attribute, use the
+ Printer object's "natural-language-configured" value.
+
+
+
+
+
+
+
+
+Hastings & Manros Informational [Page 20]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ requesting-user-name
+
+ IF NOT a single 'name' value, REJECT/RETURN 'client-error-bad-
+ request'.
+ IF the value length is greater than 255 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+ IF the IPP object can obtain a better authenticated name, use it
+ instead.
+
+
+ job-name(name)
+
+ IF NOT a single 'name' value, REJECT/RETURN 'client-error-bad-
+ request'.
+ IF the value length is greater than 255 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+ IF NOT supplied by the client, the Printer object creates a name
+ from the document-name or document-uri.
+
+
+ document-name (name)
+
+ IF NOT a single 'name' value, REJECT/RETURN 'client-error-bad-
+ request'.
+ IF the value length is greater than 255 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+
+
+ ipp-attribute-fidelity (boolean)
+
+ IF NEITHER a single 'true' NOR a single 'false' 'boolean' value,
+ REJECT/RETURN 'client-error-bad-request'.
+ IF the value length is NOT equal to 1 octet, REJECT/RETURN '
+ client-error-request-value-too-long'
+ IF NOT supplied by the client, the IPP object assumes the value
+ 'false'.
+
+
+ document-format (mimeMediaType)
+
+ IF NOT a single non-empty 'mimeMediaType' value, REJECT/RETURN
+ 'client-error-bad-request'.
+ IF the value length is greater than 255 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+ IF NOT in the Printer object's "document-format-supported"
+ attribute, REJECT/RETURN 'client-error-document-format-not-
+ supported'
+
+
+
+
+Hastings & Manros Informational [Page 21]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ IF NOT supplied by the client, the IPP object assumes the value of
+ the Printer object's "document-format-default" attribute.
+
+
+ document-uri (uri)
+
+ IF NOT a single non-empty 'uri' value, REJECT/RETURN 'client-
+ error-bad-request'.
+ IF the value length is greater than 1023 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+ IF the URI syntax is not valid, REJECT/RETURN 'client-error-bad-
+ request'.
+ IF scheme is NOT in the Printer object's "reference-uri-schemes-
+ supported" attribute, REJECT/RETURN 'client-error-uri-scheme-
+ not-supported'.
+ The Printer object MAY check to see if the document exists and is
+ accessible. If the document is not found or is not accessible,
+ REJECT/RETURN 'client-error-not found'.
+
+
+ last-document (boolean)
+
+ IF NEITHER a single 'true' NOR a single 'false' 'boolean' value,
+ REJECT/RETURN 'client-error-bad-request'.
+ IF the value length is NOT equal to 1 octet, REJECT/RETURN '
+ client-error-request-value-too-long'
+
+
+ job-id (integer(1:MAX))
+
+ IF NOT an single 'integer' value equal to 4 octets AND in the
+ range 1 to MAX, REJECT/RETURN 'client-error-bad-request'.
+
+ IF NOT a job-id of an existing Job object, REJECT/RETURN 'client-
+ error-not-found' or 'client-error-gone' status code, if keep
+ track of recently deleted jobs.
+
+
+ requested-attributes (1setOf keyword)
+
+ IF NOT one or more 'keyword' values, REJECT/RETURN 'client-error-
+ bad-request'.
+ IF the value length is greater than 255 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+ Ignore unsupported values which are the keyword names of
+ unsupported attributes. Don't bother to copy such requested
+ (unsupported) attributes to the Unsupported Attribute response
+ group since the response will not return them.
+
+
+
+Hastings & Manros Informational [Page 22]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ which-jobs (type2 keyword)
+
+ IF NOT a single 'keyword' value, REJECT/RETURN 'client-error-bad-
+ request'.
+ IF the value length is greater than 255 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+ IF NEITHER 'completed' NOR 'not-completed', copy the attribute and
+ the unsupported value to the Unsupported Attributes response
+ group and REJECT/RETURN 'client-error-attributes-or-values-
+ not-supported'.
+ Note: a Printer still supports the 'completed' value even if it
+ keeps no completed/canceled/aborted jobs: by returning no jobs
+ when so queried.
+ IF NOT supplied by the client, the IPP object assumes the 'not-
+ completed' value.
+
+
+ my-jobs (boolean)
+
+ IF NEITHER a single 'true' NOR a single 'false' 'boolean' value,
+ REJECT/RETURN 'client-error-bad-request'.
+ IF the value length is NOT equal to 1 octet, REJECT/RETURN '
+ client-error-request-value-too-long'
+ IF NOT supplied by the client, the IPP object assumes the 'false'
+ value.
+
+
+ limit (integer(1:MAX))
+
+ IF NOT a single 'integer' value equal to 4 octets AND in the range
+ 1 to MAX, REJECT/RETURN 'client-error-bad-request'.
+ IF NOT supplied by the client, the IPP object returns all jobs, no
+ matter how many.
+
+2.2.1.6 Validate the values of the OPTIONAL Operation attributes
+
+ OPTIONAL Operation attributes are those that an IPP object MAY or MAY
+ NOT support. An IPP object validates the values of the OPTIONAL
+ attributes supplied by the client. The IPP object performs the same
+ syntactic validation checks for each OPTIONAL attribute value as in
+ Section 2.2.1.5. As in Section 2.2.1.5, if any fail, the IPP object
+ REJECTS the request and RETURNS the 'client-error-bad-request' or the
+ 'client-error-request-value-too-long' status code.
+
+ In addition, the IPP object checks each Operation attribute value
+ against some Printer attribute or some hard-coded value if there is
+ no "xxx-supported" Printer attribute defined. If its value is not
+ among those supported or is not in the range supported, then the IPP
+
+
+
+Hastings & Manros Informational [Page 23]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ object REJECTS the request and RETURNS the error status code
+ indicated in the table. If the value of the Printer object's "xxx-
+ supported" attribute is 'no-value' (because the system administrator
+ hasn't configured a value), the check always fails.
+
+ If the IPP object doesn't recognize/support an attribute, the IPP
+ object treats the attribute as an unknown or unsupported attribute
+ (see the last row in the table below).
+
+ document-natural-language (naturalLanguage)
+
+ IF NOT a single non-empty 'naturalLanguage' value, REJECT/RETURN '
+ client-error-bad-request'.
+ IF the value length is greater than 63 octets, REJECT/RETURN '
+ client-error-request-value-too-long'.
+ IF NOT a value that the Printer object supports in document
+ formats, (no corresponding "xxx-supported" Printer attribute),
+ REJECT/RETURN 'client-error-natural-language-not-supported'.
+
+
+ compression (type3 keyword)
+
+ IF NOT a single 'keyword' value, REJECT/RETURN 'client-error-bad-
+ request'.
+ IF the value length is greater than 255 octets, REJECT/RETURN '
+ client-error-request-value-too-long'.
+ IF NOT in the Printer object's "compression-supported" attribute,
+ copy the attribute and the unsupported value to the Unsupported
+ Attributes response group and REJECT/RETURN 'client-error-
+ attributes-or-values-not-supported'.
+
+
+ job-k-octets (integer(0:MAX))
+
+ IF NOT a single 'integer' value equal to 4 octets,
+ REJECT/RETURN 'client-error-bad-request'.
+ IF NOT in the range of the Printer object's "job-k-octets-
+ supported" attribute, copy the attribute and the unsupported
+ value to the Unsupported Attributes response group and
+ REJECT/RETURN 'client-error-attributes-or-values-not-
+ supported'.
+
+
+ job-impressions (integer(0:MAX))
+
+ IF NOT a single 'integer' value equal to 4 octets,
+ REJECT/RETURN 'client-error-bad-request'.
+
+
+
+
+Hastings & Manros Informational [Page 24]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ IF NOT in the range of the Printer object's "job-impressions-
+ supported" attribute, copy the attribute and the unsupported
+ value to the Unsupported Attributes response group and
+ REJECT/RETURN 'client-error-attributes-or-values-not-
+ supported'.
+
+
+ job-media-sheets (integer(0:MAX))
+
+ IF NOT a single 'integer' value equal to 4 octets,
+ REJECT/RETURN 'client-error-bad-request'.
+ IF NOT in the range of the Printer object's "job-media-sheets-
+ supported" attribute, copy the attribute and the unsupported
+ value to the Unsupported Attributes response group and
+ REJECT/RETURN 'client-error-attributes-or-values-not-
+ supported'.
+
+
+ message (text(127))
+
+ IF NOT a single 'text' value, REJECT/RETURN 'client-error-bad-
+ request'.
+ IF the value length is greater than 127 octets,
+ REJECT/RETURN 'client-error-request-value-too-long'.
+
+
+ unknown or unsupported attribute
+
+ IF the attribute syntax supplied by the client is supported but
+ the length is not legal for that attribute syntax,
+ REJECT/RETURN 'client-error-request-value-too-long'.
+ ELSE copy the attribute and value to the Unsupported Attributes
+ response group and change the attribute value to the "out-of-
+ band" 'unsupported' value, but otherwise ignore the attribute.
+
+ Note: Future Operation attributes may be added to the protocol
+ specification that may occur anywhere in the specified group.
+ When the operation is otherwise successful, the IPP object returns
+ the 'successful-ok-ignored-or-substituted-attributes' status code.
+ Ignoring unsupported Operation attributes in all operations is
+ analogous to the handling of unsupported Job Template attributes
+ in the create and Validate-Job operations when the client supplies
+ the "ipp-attribute-fidelity" Operation attribute with the 'false'
+ value. This last rule is so that we can add OPTIONAL Operation
+ attributes to future versions of IPP so that older clients can
+ inter-work with new IPP objects and newer clients can inter-work
+ with older IPP objects. (If the new attribute cannot be ignored
+ without performing unexpectedly, the major version number would
+
+
+
+Hastings & Manros Informational [Page 25]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ have been increased in the protocol document and in the request).
+ This rule for Operation attributes is independent of the value of
+ the "ipp-attribute-fidelity" attribute. For example, if an IPP
+ object doesn't support the OPTIONAL "job-k-octets" attribute', the
+ IPP object treats "job-k-octets" as an unknown attribute and only
+ checks the length for the 'integer' attribute syntax supplied by
+ the client. If it is not four octets, the IPP object REJECTS the
+ request and RETURNS the 'client-error-bad-request' status code,
+ else the IPP object copies the attribute to the Unsupported
+ Attribute response group, setting the value to the "out-of-band" '
+ unsupported' value, but otherwise ignores the attribute.
+
+2.2.2 Suggested Additional Processing Steps for Operations that
+ Create/Validate Jobs and Add Documents
+
+ This section in combination with the previous section recommends the
+ processing steps for the Print-Job, Validate-Job, Print-URI, Create-
+ Job, Send-Document, and Send-URI operations that IPP objects SHOULD
+ use. These are the operations that create jobs, validate a Print-Job
+ request, and add documents to a job.
+
+2.2.2.1 Default "ipp-attribute-fidelity" if not supplied
+
+ The Printer object checks to see if the client supplied an "ipp-
+ attribute-fidelity" Operation attribute. If the attribute is not
+ supplied by the client, the IPP object assumes that the value is
+ 'false'.
+
+2.2.2.2 Check that the Printer object is accepting jobs
+
+ If the value of the Printer object's "printer-is-accepting-jobs" is
+ 'false', the Printer object REJECTS the request and RETURNS the
+ 'server-error-not-accepting-jobs' status code.
+
+2.2.2.3 Validate the values of the Job Template attributes
+
+ An IPP object validates the values of all Job Template attribute
+ supplied by the client. The IPP object performs the analogous
+ syntactic validation checks of each Job Template attribute value that
+ it performs for Operation attributes (see Section 2.2.1.5.):
+
+ a)that the length of each value is correct for the attribute
+ syntax tag supplied by the client according to [RFC2566] Section
+ 4.1.
+
+ b)that the attribute syntax tag is correct for that attribute
+ according to [RFC2566] Sections 4.2 to 4.4.
+
+
+
+
+Hastings & Manros Informational [Page 26]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ c)that multiple values are supplied only for multi-valued
+ attributes, i.e., that are 1setOf X according to [RFC2566]
+ Sections 4.2 to 4.4.
+
+ As in Section 2.2.1.5, if any of these syntactic checks fail, the IPP
+ object REJECTS the request and RETURNS the 'client-error-bad-request'
+ or 'client-error-request-value-too-long' status code as appropriate,
+ independent of the value of the "ipp-attribute-fidelity". Since such
+ an error is most likely to be an error detected by a client
+ developer, rather than by an end-user, the IPP object NEED NOT return
+ an indication of which attribute had the error in either the
+ Unsupported Attributes Group or the Status Message. The description
+ for each of these syntactic checks is explicitly expressed in the
+ first IF statement in the following table.
+
+ Each Job Template attribute MUST occur no more than once. If an IPP
+ Printer receives a create request with multiple occurrences of a Job
+ Template attribute, it MAY:
+
+ 1.reject the operation and return the 'client-error-bad syntax'
+ error status code
+
+ 2.accept the operation and use the first occurrence of the
+ attribute
+
+ 3.accept the operation and use the last occurrence of the
+ attribute
+
+ depending on implementation. Therefore, clients MUST NOT supply
+ multiple occurrences of the same Job Template attribute in the Job
+ Attributes group in the request.
+
+2.2.3 Algorithm for job validation
+
+ The process of validating a Job-Template attribute "xxx" against a
+ Printer attribute "xxx-supported" can use the following validation
+ algorithm (see section 3.2.1.2 in [RFC2566]).
+
+ To validate the value U of Job-Template attribute "xxx" against the
+ value V of Printer "xxx-supported", perform the following algorithm:
+
+ 1.If U is multi-valued, validate each value X of U by performing
+ the algorithm in Table 3 with each value X. Each validation is
+ separate from the standpoint of returning unsupported values.
+
+ Example: If U is "finishings" that the client supplies with
+ 'staple', 'bind' values, then X takes on the successive values:
+ 'staple', then 'bind'
+
+
+
+Hastings & Manros Informational [Page 27]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ 2.If V is multi-valued, validate X against each Z of V by
+ performing the algorithm in Table 3 with each value Z. If a
+ value Z validates, the validation for the attribute value X
+ succeeds. If it fails, the algorithm is applied to the next
+ value Z of V. If there are no more values Z of V, validation
+ fails.
+
+ Example: If V is "sides-supported" with values: 'one-sided',
+ 'two-sided-long', and 'two-sided-short', then Z takes on the
+ successive values: 'one-sided', 'two-sided-long', and
+ 'two-sided-short'. If the client supplies "sides" with 'two-
+ sided-long', the first comparison fails ('one-sided' is not
+ equal to 'two-sided-long'), the second comparison succeeds
+ ('two-sided-long' is equal to 'two-sided-long"), and the third
+ comparison ('two-sided-short' with 'two-sided-long') is not even
+ performed.
+
+ 3.If both U and V are single-valued, let X be U and Z be V and use
+ the validation rules in Table 3.
+
+ Table 3 - Rules for validating single values X against Z
+
+ attribute attribute validated if:
+ syntax of X syntax of Z
+
+ integer rangeOfInteger X is within the range of
+ Z
+
+ uri uriScheme the uri scheme in X is
+ equal to Z
+
+ any boolean the value of Z is TRUE
+
+ any any X and Z are of the same
+ type and are equal.
+
+ If the value of the Printer object's "xxx-supported" attribute is '
+ no-value' (because the system administrator hasn't configured a
+ value), the check always fails. If the check fails, the IPP object
+ copies the attribute to the Unsupported Attributes response group
+ with its unsupported value. If the attribute contains more than one
+ value, each value is checked and each unsupported value is separately
+ copied, while supported values are not copied. If an IPP object
+ doesn't recognize/support a Job Template attribute, i.e., there is no
+ corresponding Printer object "xxx-supported" attribute, the IPP
+ object treats the attribute as an unknown or unsupported attribute
+ (see the last row in the table below).
+
+
+
+
+Hastings & Manros Informational [Page 28]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ If some Job Template attributes are supported for some document
+ formats and not for others or the values are different for different
+ document formats, the IPP object SHOULD take that into account in
+ this validation using the value of the "document-format" supplied by
+ the client (or defaulted to the value of the Printer's "document-
+ format-default" attribute, if not supplied by the client). For
+ example, if "number-up" is supported for the 'text/plain' document
+ format, but not for the 'application/postscript' document format, the
+ check SHOULD (though it NEED NOT) depend on the value of the
+ "document-format" operation attribute. See "document-format" in
+ [RFC2566] section 3.2.1.1 and 3.2.5.1.
+
+ Note: whether the request is accepted or rejected is determined by
+ the value of the "ipp-attribute-fidelity" attribute in a subsequent
+ step, so that all Job Template attribute supplied are examined and
+ all unsupported attributes and/or values are copied to the
+ Unsupported Attributes response group.
+
+ job-priority (integer(1:100))
+
+ IF NOT a single 'integer' value with a length equal to 4 octets,
+ REJECT/RETURN 'client-error-bad-request'.
+ IF NOT supplied by the client, use the value of the Printer
+ object's "job-priority-default" attribute at job submission
+ time.
+ IF NOT in the range 1 to 100, inclusive, copy the attribute and
+ the unsupported value to the Unsupported Attributes response
+ group.
+ Map the value to the nearest supported value in the range 1:100 as
+ specified by the number of discrete values indicated by the
+ value of the Printer's "job-priority-supported" attribute. See
+ the formula in [RFC2566] Section 4.2.1.
+
+ job-hold-until (type3 keyword | name)
+
+ IF NOT a single 'keyword' or 'name' value, REJECT/RETURN 'client-
+ error-bad-request'.
+ IF the value length is greater than 255 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+ IF NOT supplied by the client, use the value of the Printer
+ object's "job-hold-until" attribute at job submission time.
+ IF NOT in the Printer object's "job-hold-until-supported"
+ attribute, copy the attribute and the unsupported value to the
+ Unsupported Attributes response group.
+
+
+
+
+
+
+
+Hastings & Manros Informational [Page 29]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ job-sheets (type3 keyword | name)
+
+ IF NOT a single 'keyword' or 'name' value, REJECT/RETURN 'client-
+ error-bad-request'.
+ IF the value length is greater than 255 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+ IF NOT in the Printer object's "job-sheets-supported" attribute,
+ copy the attribute and the unsupported value to the Unsupported
+ Attributes response group.
+
+ multiple-document-handling (type2 keyword)
+
+ IF NOT a single 'keyword' value, REJECT/RETURN 'client-error-bad-
+ request'.
+ IF the value length is greater than 255 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+ IF NOT in the Printer object's "multiple-document-handling-
+ supported" attribute, copy the attribute and the unsupported
+ value to the Unsupported Attributes response group.
+
+ copies (integer(1:MAX))
+
+ IF NOT a single 'integer' value with a length equal to 4 octets,
+ REJECT/RETURN 'client-error-bad-request'.
+ IF NOT in range of the Printer object's "copies-supported"
+ attribute copy the attribute and the unsupported value to the
+ Unsupported
+ Attributes response group.
+
+ finishings (1setOf type2 enum)
+
+ IF NOT an 'enum' value(s) each with a length equal to 4 octets,
+ REJECT/RETURN 'client-error-bad-request'.
+ IF NOT in the Printer object's "finishings-supported" attribute,
+ copy the attribute and the unsupported value(s), but not any
+ supported values, to the Unsupported Attributes response group.
+
+ page-ranges (1setOf rangeOfInteger(1:MAX))
+
+ IF NOT a 'rangeOfInteger' value(s) each with a length equal to 8
+ octets, REJECT/RETURN 'client-error-bad-request'.
+ IF first value is greater than second value in any range, the
+ ranges are not in ascending order, or ranges overlap,
+ REJECT/RETURN 'client-error-bad-request'.
+ IF the value of the Printer object's "page-ranges-supported"
+ attribute is 'false', copy the attribute to the Unsupported
+ Attributes response group and set the value to the "out-of-
+ band" 'unsupported' value.
+
+
+
+Hastings & Manros Informational [Page 30]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ sides (type2 keyword)
+
+ IF NOT a single 'keyword' value, REJECT/RETURN 'client-error-bad-
+ request'.
+ IF the value length is greater than 255 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+ IF NOT in the Printer object's "sides-supported" attribute, copy
+ the attribute and the unsupported value to the Unsupported
+ Attributes response group.
+
+ number-up (integer(1:MAX))
+
+ IF NOT a single 'integer' value with a length equal to 4 octets,
+ REJECT/RETURN 'client-error-bad-request'.
+ IF NOT a value or in the range of one of the values of the Printer
+ object's "number-up-supported" attribute, copy the attribute
+ and value to the Unsupported Attribute response group.
+
+ orientation-requested (type2 enum)
+
+ IF NOT a single 'enum' value with a length equal to 4 octets,
+ REJECT/RETURN 'client-error-bad-request'.
+ IF NOT in the Printer object's "orientation-requested-supported"
+ attribute, copy the attribute and the unsupported value to the
+ Unsupported Attributes response group.
+
+ media (type3 keyword | name)
+
+ IF NOT a single 'keyword' or 'name' value, REJECT/RETURN 'client-
+ error-bad-request'.
+ IF the value length is greater than 255 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+ IF NOT in the Printer object's "media-supported" attribute, copy
+ the attribute and the unsupported value to the Unsupported
+ Attributes response group.
+
+ printer-resolution (resolution)
+
+ IF NOT a single 'resolution' value with a length equal to 9
+ octets,
+ REJECT/RETURN 'client-error-bad-request'.
+ IF NOT in the Printer object's "printer-resolution-supported"
+ attribute, copy the attribute and the unsupported value to the
+ Unsupported Attributes response group.
+
+
+
+
+
+
+
+Hastings & Manros Informational [Page 31]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ print-quality (type2 enum)
+
+ IF NOT a single 'enum' value with a length equal to 4 octets,
+ REJECT/RETURN 'client-error-bad-request'.
+ IF NOT in the Printer object's "print-quality-supported"
+ attribute, copy the attribute and the unsupported value to the
+ Unsupported Attributes response group.
+
+ unknown or unsupported attribute (i.e., there is no corresponding
+ Printer object "xxx-supported" attribute)
+
+ IF the attribute syntax supplied by the client is supported but
+ the length is not legal for that attribute syntax,
+ REJECT/RETURN 'client-error-bad-request' if the length of the
+ attribute syntax is fixed or 'client-error-request-value-too-
+ long' if the length of the attribute syntax is variable.
+ ELSE copy the attribute and value to the Unsupported Attributes
+ response group and change the attribute value to the "out-of-
+ band" 'unsupported' value. Any remaining Job Template
+ Attributes are either unknown or unsupported Job Template
+ attributes and are validated algorithmically according to their
+ attribute syntax for proper length (see below).
+
+ If the attribute syntax is supported AND the length check
+ fails, the IPP object REJECTS the request and RETURNS the '
+ client-error-bad-request' if the length of the attribute syntax
+ is fixed or the 'client-error-request-value-too-long' status
+ code if the length of the attribute syntax is variable.
+ Otherwise, the IPP object copies the unsupported Job Template
+ attribute to the Unsupported Attributes response group and
+ changes the attribute value to the "out-of-band" 'unsupported'
+ value. The following table shows the length checks for all
+ attribute syntaxes. In the following table: "<=" means less
+ than or equal, "=" means equal to:
+
+ Name Octet length check for read-write attributes
+ ----------- --------------------------------------------
+ 'textWithLanguage <= 1023 AND 'naturalLanguage' <= 63
+ 'textWithoutLanguage' <= 1023
+ 'nameWithLanguage' <= 255 AND 'naturalLanguage' <= 63
+ 'nameWithoutLanguage' <= 255
+ 'keyword' <= 255
+ 'enum' = 4
+ 'uri' <= 1023
+ 'uriScheme' <= 63
+ 'charset' <= 63
+ 'naturalLanguage' <= 63
+ 'mimeMediaType' <= 255
+
+
+
+Hastings & Manros Informational [Page 32]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ 'octetString' <= 1023
+ 'boolean' = 1
+ 'integer' = 4
+ 'rangeOfInteger' = 8
+ 'dateTime' = 11
+ 'resolution' = 9
+ '1setOf X'
+
+2.2.3.1 Check for conflicting Job Template attributes values
+
+ Once all the Operation and Job Template attributes have been checked
+ individually, the Printer object SHOULD check for any conflicting
+ values among all the supported values supplied by the client. For
+ example, a Printer object might be able to staple and to print on
+ transparencies, however due to physical stapling constraints, the
+ Printer object might not be able to staple transparencies. The IPP
+ object copies the supported attributes and their conflicting
+ attribute values to the Unsupported Attributes response group. The
+ Printer object only copies over those attributes that the Printer
+ object either ignores or substitutes in order to resolve the
+ conflict, and it returns the original values which were supplied by
+ the client. For example suppose the client supplies "finishings"
+ equals 'staple' and "media" equals 'transparency', but the Printer
+ object does not support stapling transparencies. If the Printer
+ chooses to ignore the stapling request in order to resolve the
+ conflict, the Printer objects returns "finishings" equal to 'staple'
+ in the Unsupported Attributes response group. If any attributes are
+ multi-valued, only the conflicting values of the attributes are
+ copied.
+
+ Note: The decisions made to resolve the conflict (if there is a
+ choice) is implementation dependent.
+
+2.2.3.2 Decide whether to REJECT the request
+
+ If there were any unsupported Job Template attributes or
+ unsupported/conflicting Job Template attribute values and the client
+ supplied the "ipp-attribute-fidelity" attribute with the 'true'
+ value, the Printer object REJECTS the request and return the status
+ code:
+
+ (1) 'client-error-conflicting-attributes' status code, if there
+ were any conflicts between attributes supplied by the client.
+ (2) 'client-error-attributes-or-values-not-supported' status code,
+ otherwise.
+
+
+
+
+
+
+Hastings & Manros Informational [Page 33]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ Note: Unsupported Operation attributes or values that are returned
+ do not affect the status returned in this step. If the unsupported
+ Operation attribute was a serious error, the above already rejected
+ the request in a previous step. If control gets to this step with
+ unsupported Operation attributes being returned, they are not serious
+ errors.
+
+2.2.3.3 For the Validate-Job operation, RETURN one of the success
+ status codes
+
+ If the requested operation is the Validate-Job operation, the Printer
+ object returns:
+
+ (1) the "successful-ok" status code, if there are no unsupported
+ or conflicting Job Template attributes or values.
+ (2) the "successful-ok-conflicting-attributes, if there are any
+ conflicting Job Template attribute or values.
+ (3) the "successful-ok-ignored-or-substituted-attributes, if there
+ are only unsupported Job Template attributes or values.
+
+ Note: Unsupported Operation attributes or values that are returned
+ do not affect the status returned in this step. If the unsupported
+ Operation attribute was a serious error, the above already rejected
+ the request in a previous step. If control gets to this step with
+ unsupported Operation attributes being returned, they are not serious
+ errors.
+
+2.2.3.4 Create the Job object with attributes to support
+
+ If "ipp-attribute-fidelity" is set to 'false' (or it was not supplied
+ by the client), the Printer object:
+
+ (1) creates a Job object, assigns a unique value to the job's
+ "job-uri" and "job-id" attributes, and initializes all of the
+ job's other supported Job Description attributes.
+ (2) removes all unsupported attributes from the Job object.
+ (3) for each unsupported value, removes either the unsupported
+ value or substitutes the unsupported attribute value with some
+ supported value. If an attribute has no values after removing
+ unsupported values from it, the attribute is removed from the
+ Job object (so that the normal default behavior at job
+ processing time will take place for that attribute).
+ (4) for each conflicting value, removes either the conflicting
+ value or substitutes the conflicting attribute value with some
+ other supported value. If an attribute has no values after
+ removing conflicting values from it, the attribute is removed
+ from the Job object (so that the normal default behavior at
+ job processing time will take place for that attribute).
+
+
+
+Hastings & Manros Informational [Page 34]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ If there were no attributes or values flagged as unsupported, or the
+ value of 'ipp-attribute-fidelity" was 'false', the Printer object is
+ able to accept the create request and create a new Job object. If
+ the "ipp-attribute-fidelity" attribute is set to 'true', the Job
+ Template attributes that populate the new Job object are necessarily
+ all the Job Template attributes supplied in the create request. If
+ the "ipp-attribute-fidelity" attribute is set to 'false', the Job
+ Template attributes that populate the new Job object are all the
+ client supplied Job Template attributes that are supported or that
+ have value substitution. Thus, some of the requested Job Template
+ attributes may not appear in the Job object because the Printer
+ object did not support those attributes. The attributes that
+ populate the Job object are persistently stored with the Job object
+ for that Job. A Get-Job-Attributes operation on that Job object will
+ return only those attributes that are persistently stored with the
+ Job object.
+
+ Note: All Job Template attributes that are persistently stored with
+ the Job object are intended to be "override values"; that is, they
+ that take precedence over whatever other embedded instructions might
+ be in the document data itself. However, it is not possible for all
+ Printer objects to realize the semantics of "override". End users
+ may query the Printer's "pdl-override-supported" attribute to
+ determine if the Printer either attempts or does not attempt to
+ override document data instructions with IPP attributes.
+
+ There are some cases, where a Printer supports a Job Template
+ attribute and has an associated default value set for that attribute.
+ In the case where a client does not supply the corresponding
+ attribute, the Printer does not use its default values to populate
+ Job attributes when creating the new Job object; only Job Template
+ attributes actually in the create request are used to populate the
+ Job object. The Printer's default values are only used later at Job
+ processing time if no other IPP attribute or instruction embedded in
+ the document data is present.
+
+ Note: If the default values associated with Job Template attributes
+ that the client did not supply were to be used to populate the Job
+ object, then these values would become "override values" rather than
+ defaults. If the Printer supports the 'attempted' value of the
+ "pdl-override-supported" attribute, then these override values could
+ replace values specified within the document data. This is not the
+ intent of the default value mechanism. A default value for an
+ attribute is used only if the create request did not specify that
+ attribute (or it was ignored when allowed by "ipp-attribute-fidelity"
+ being 'false') and no value was provided within the content of the
+ document data.
+
+
+
+
+Hastings & Manros Informational [Page 35]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ If the client does not supply a value for some Job Template
+ attribute, and the Printer does not support that attribute, as far as
+ IPP is concerned, the result of processing that Job (with respect to
+ the missing attribute) is undefined.
+
+2.2.3.5 Return one of the success status codes
+
+ Once the Job object has been created, the Printer object accepts the
+ request and returns to the client:
+
+ (1) the 'successful-ok' status code, if there are no unsupported
+ or conflicting Job Template attributes or values.
+ (2) the 'successful-ok-conflicting-attributes' status code, if
+ there are any conflicting Job Template attribute or values.
+ (3) the 'successful-ok-ignored-or-substituted-attributes' status
+ code, if there are only unsupported Job Template attributes or
+ values.
+
+ Note: Unsupported Operation attributes or values that are returned
+ do not affect the status returned in this step. If the unsupported
+ Operation attribute was a serious error, the above already rejected
+ the request in a previous step. If control gets to this step with
+ unsupported Operation attributes being returned, they are not serious
+ errors.
+
+ The Printer object also returns Job status attributes that indicate
+ the initial state of the Job ('pending', 'pending-held', '
+ processing', etc.), etc. See Print-Job Response, [RFC2566] section
+ 3.2.1.2.
+
+2.2.3.6 Accept appended Document Content
+
+ The Printer object accepts the appended Document Content data and
+ either starts it printing, or spools it for later processing.
+
+2.2.3.7 Scheduling and Starting to Process the Job
+
+ The Printer object uses its own configuration and implementation
+ specific algorithms for scheduling the Job in the correct processing
+ order. Once the Printer object begins processing the Job, the
+ Printer changes the Job's state to 'processing'. If the Printer
+ object supports PDL override (the "pdl-override-supported" attribute
+ set to 'attempted'), the implementation does its best to see that IPP
+ attributes take precedence over embedded instructions in the document
+ data.
+
+
+
+
+
+
+Hastings & Manros Informational [Page 36]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+2.2.3.8 Completing the Job
+
+ The Printer object continues to process the Job until it can move the
+ Job into the 'completed' state. If an Cancel-Job operation is
+ received, the implementation eventually moves the Job into the '
+ canceled' state. If the system encounters errors during processing
+ that do not allow it to progress the Job into a completed state, the
+ implementation halts all processing, cleans up any resources, and
+ moves the Job into the 'aborted' state.
+
+2.2.3.9 Destroying the Job after completion
+
+ Once the Job moves to the 'completed', 'aborted', or 'canceled'
+ state, it is an implementation decision as to when to destroy the Job
+ object and release all associated resources. Once the Job has been
+ destroyed, the Printer would return either the "client-error-not-
+ found" or "client-error-gone" status codes for operations directed at
+ that Job.
+
+ Note: the Printer object SHOULD NOT re-use a "job-uri" or "job-id"
+ value for a sufficiently long time after a job has been destroyed, so
+ that stale references kept by clients are less likely to access the
+ wrong (newer) job.
+
+2.2.3.10 Interaction with "ipp-attribute-fidelity"
+
+ Some Printer object implementations may support "ipp-attribute-
+ fidelity" set to 'true' and "pdl-override-supported" set to '
+ attempted' and yet still not be able to realize exactly what the
+ client specifies in the create request. This is due to legacy
+ decisions and assumptions that have been made about the role of job
+ instructions embedded within the document data and external job
+ instructions that accompany the document data and how to handle
+ conflicts between such instructions. The inability to be 100%
+ precise about how a given implementation will behave is also
+ compounded by the fact that the two special attributes, "ipp-
+ attribute-fidelity" and "pdl-override-supported", apply to the whole
+ job rather than specific values for each attribute. For example, some
+ implementations may be able to override almost all Job Template
+ attributes except for "number-up".
+
+2.3 Status codes returned by operation
+
+ This section lists all status codes once in the first operation
+ (Print-Job). Then it lists the status codes that are different or
+ specialized for subsequent operations under each operation.
+
+
+
+
+
+Hastings & Manros Informational [Page 37]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+2.3.1 Printer Operations
+
+2.3.1.1 Print-Job
+
+ The Printer object MUST return one of the following "status-code"
+ values for the indicated reason. Whether all of the document data
+ has been accepted or not before returning the success or error
+ response depends on implementation. See Section 14 for a more
+ complete description of each status code.
+
+ For the following success status codes, the Job object has been
+ created and the "job-id", and "job-uri" assigned and returned in the
+ response:
+
+ successful-ok: no request attributes were substituted or ignored.
+ successful-ok-ignored-or-substituted-attributes: some supplied
+ (1) attributes were ignored or (2) unsupported attribute
+ syntaxes or values were substituted with supported values or
+ were ignored. Unsupported attributes, attribute syntaxes, or
+ values MUST be returned in the Unsupported Attributes group of
+ the response.
+ successful-ok-conflicting-attributes: some supplied attribute
+ values conflicted with the values of other supplied attributes
+ and were either substituted or ignored. Attributes or values
+ which conflict with other attributes and have been substituted
+ or ignored MUST be returned in the Unsupported Attributes group
+ of the response as supplied by the client.
+
+ [RFC2566] section 3.1.6 Operation Status Codes and Messages states:
+
+ If the Printer object supports the "status-message" operation
+ attribute, it SHOULD use the REQUIRED 'utf-8' charset to return
+ a status message for the following error status codes (see
+ section 14): 'client-error-bad-request', 'client-error-
+ charset-not-supported', 'server-error-internal-error', '
+ server-error-operation-not-supported', and 'server-error-
+ version-not-supported'. In this case, it MUST set the value of
+ the "attributes-charset" operation attribute to 'utf-8' in the
+ error response.
+
+ For the following error status codes, no job is created and no "job-
+ id" or "job-uri" is returned:
+
+ client-error-bad-request: The request syntax does not conform to
+ the specification.
+
+
+
+
+
+
+Hastings & Manros Informational [Page 38]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ client-error-forbidden: The request is being refused for
+ authorization or authentication reasons. The implementation
+ security policy is to not reveal whether the failure is one of
+ authentication or authorization.
+ client-error-not-authenticated: Either the request requires
+ authentication information to be supplied or the authentication
+ information is not sufficient for authorization.
+ client-error-not-authorized: The requester is not authorized to
+ perform the request on the target object.
+ client-error-not-possible: The request cannot be carried out
+ because of the state of the system. See also 'server-error-
+ not-accepting-jobs' status code which MUST take precedence if
+ the Printer object's "printer-accepting-jobs" attribute is '
+ false'.
+ client-error-timeout: not applicable.
+ client-error-not-found: the target object does not exist.
+ client-error-gone: the target object no longer exists and no
+ forwarding address is known.
+ client-error-request-entity-too-large: the size of the request
+ and/or print data exceeds the capacity of the IPP Printer to
+ process it.
+ client-error-request-value-too-long: the size of request variable
+ length attribute values, such as 'text' and 'name' attribute
+ syntaxes, exceed the maximum length specified in [RFC2566] for
+ the attribute and MUST be returned in the Unsupported
+ Attributes Group.
+ client-error-document-format-not-supported: the document format
+ supplied is not supported. The "document-format" attribute
+ with the unsupported value MUST be returned in the Unsupported
+ Attributes Group. This error SHOULD take precedence over any
+ other 'xxx-not-supported' error, except 'client-error-charset-
+ not-supported'.
+ client-error-attributes-or-values-not-supported: one or more
+ supplied attributes, attribute syntaxes, or values are not
+ supported and the client supplied the "ipp-attributes-fidelity"
+ operation attribute with a 'true' value. They MUST be returned
+ in the Unsupported Attributes Group as explained below.
+ client-error-uri-scheme-not-supported: not applicable.
+ client-error-charset-not-supported: the charset supplied in the
+ "attributes-charset" operation attribute is not supported. The
+ Printer's "configured-charset" MUST be returned in the response
+ as the value of the "attributes-charset" operation attribute
+ and used for any 'text' and 'name' attributes returned in the
+ error response. This error SHOULD take precedence over any
+ other error, unless the request syntax is so bad that the
+ client's supplied "attributes-charset" cannot be determined.
+
+
+
+
+
+Hastings & Manros Informational [Page 39]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ client-error-conflicting-attributes: one or more supplied
+ attribute va attribute values conflicted with each other and
+ the client supplied the "ipp-attributes-fidelity" operation
+ attribute with a 'true' value. They MUST be returned in the
+ Unsupported Attributes Group as explained below.
+ server-error-internal-error: an unexpected condition prevents the
+ request from being fulfilled.
+ server-error-operation-not-supported: not applicable (since
+ Print-Job is REQUIRED).
+ server-error-service-unavailable: the service is temporarily
+ overloaded.
+ server-error-version-not-supported: the version in the request is
+ not supported. The "closest" version number supported MUST be
+ returned in the response.
+ server-error-device-error: a device error occurred while
+ receiving or spooling the request or document data or the IPP
+ Printer object can only accept one job at a time.
+ server-error-temporary-error: a temporary error such as a buffer
+ full write error, a memory overflow, or a disk full condition
+ occurred while receiving the request and/or the document data.
+ server-error-not-accepting-jobs: the Printer object's "printer-
+ is-not-accepting-jobs" attribute is 'false'.
+ server-error-busy: the Printer is too busy processing jobs to
+ accept another job at this time.
+ server-error-job-canceled: the job has been canceled by an
+ operator or the system while the client was transmitting the
+ document data.
+
+2.3.1.2 Print-URI
+
+ All of the Print-Job status codes described in Section 3.2.1.2
+ Print-Job Response are applicable to Print-URI with the following
+ specializations and differences. See Section 14 for a more complete
+ description of each status code.
+
+ server-error-uri-scheme-not-supported: the URI scheme supplied in
+ the "document-uri" operation attribute is not supported and is
+ returned in the Unsupported Attributes group.
+
+2.3.1.3 Validate-Job
+
+ All of the Print-Job status codes described in Section 3.2.1.2
+ Print-Job Response are applicable to Validate-Job. See Section 14
+ for a more complete description of each status code.
+
+
+
+
+
+
+
+Hastings & Manros Informational [Page 40]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+2.3.1.4 Create-Job
+
+ All of the Print-Job status codes described in Section 3.2.1.2
+ Print-Job Response are applicable to Create-Job with the following
+ specializations and differences. See Section 14 for a more complete
+ description of each status code.
+
+ server-error-operation-not-supported: the Create-Job operation is
+ not supported.
+
+2.3.1.5 Get-Printer-Attributes
+
+ All of the Print-Job status codes described in Section 3.2.1.2
+ Print-Job Response are applicable to the Get-Printer-Attributes
+ operation with the following specializations and differences. See
+ Section 14 for a more complete description of each status code.
+
+ For the following success status codes, the requested attributes are
+ returned in Group 3 in the response:
+
+ successful-ok: no request attributes were substituted or ignored
+ (same as Print-Job) and no requested attributes were
+ unsupported.
+ successful-ok-ignored-or-substituted-attributes: same as Print-
+ Job, except the "requested-attributes" operation attribute MAY,
+ but NEED NOT, be returned with the unsupported values.
+ successful-ok-conflicting-attributes: same as Print-Job.
+
+ For the error status codes, Group 3 is returned containing no
+ attributes or is not returned at all:
+
+ client-error-not-possible: Same as Print-Job, in addition the
+ Printer object is not accepting any requests.
+ client-error-request-entity-too-large: same as Print-job, except
+ that no print data is involved.
+ client-error-attributes-or-values-not-supported: not applicable,
+ since unsupported operation attributes MUST be ignored and '
+ successful-ok-ignored-or-substituted-attributes' returned.
+ client-error-conflicting-attributes: same as Print-Job, except
+ that "ipp-attribute-fidelity" is not involved.
+ server-error-operation-not-supported: not applicable (since Get-
+ Printer-Attributes is REQUIRED).
+ server-error-device-error: same as Print-Job, except that no
+ document data is involved.
+ server-error-temporary-error: same as Print-Job, except that no
+ document data is involved.
+ server-error-not-accepting-jobs: not applicable.
+
+
+
+
+Hastings & Manros Informational [Page 41]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ server-error-busy: same as Print-Job, except the IPP object is
+ too busy to accept even query requests.
+ server-error-job-canceled: not applicable.
+
+2.3.1.6 Get-Jobs
+
+ All of the Print-Job status codes described in Section 3.2.1.2
+ Print-Job Response are applicable to the Get-Jobs operation with the
+ following specializations and differences. See Section 14 for a
+ more complete description of each status code.
+
+ For the following success status codes, the requested attributes are
+ returned in Group 3 in the response:
+
+ successful-ok: no request attributes were substituted or ignored
+ (same as Print-Job) and no requested attributes were
+ unsupported.
+ successful-ok-ignored-or-substituted-attributes: same as Print-
+ Job, except the "requested-attributes" operation attribute MAY,
+ but NEED NOT, be returned with the unsupported values.
+ successful-ok-conflicting-attributes: same as Print-Job.
+
+ For any error status codes, Group 3 is returned containing no
+ attributes or is not returned at all. The following brief error
+ status code descriptions contain unique information for use with
+ Get-Jobs operation. See section 14 for the other error status codes
+ that apply uniformly to all operations:
+
+ client-error-not-possible: Same as Print-Job, in addition the
+ Printer object is not accepting any requests.
+ client-error-request-entity-too-large: same as Print-job, except
+ that no print data is involved.
+ client-error-document-format-not-supported: not applicable.
+ client-error-attributes-or-values-not-supported: not applicable,
+ since unsupported operation attributes MUST be ignored and '
+ successful-ok-ignored-or-substituted-attributes' returned.
+ client-error-conflicting-attributes: same as Print-Job, except
+ that "ipp-attribute-fidelity" is not involved.
+ server-error-operation-not-supported: not applicable (since Get-
+ Jobs is REQUIRED).
+ server-error-device-error: same as Print-Job, except that no
+ document data is involved.
+ server-error-temporary-error: same as Print-Job, except that no
+ document data is involved.
+ server-error-not-accepting-jobs: not applicable.
+ server-error-job-canceled: not applicable.
+
+
+
+
+
+Hastings & Manros Informational [Page 42]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+2.3.2 Job Operations
+
+2.3.2.1 Send-Document
+
+ All of the Print-Job status codes described in Section 3.2.1.2
+ Print-Job Response are applicable to the Get-Printer-Attributes
+ operation with the following specializations and differences. See
+ Section 14 for a more complete description of each status code.
+
+ For the following success status codes, the document has been added
+ to the specified Job object and the job's "number-of-documents"
+ attribute has been incremented:
+
+ successful-ok: no request attributes were substituted or ignored
+ (same as Print-Job).
+ successful-ok-ignored-or-substituted-attributes: same as Print-
+ Job.
+ successful-ok-conflicting-attributes: same as Print-Job.
+
+ For the error status codes, no document has been added to the Job
+ object and the job's "number-of-documents" attribute has not been
+ incremented:
+
+ client-error-not-possible: Same as Print-Job, except that the
+ Printer's "printer-is-accepting-jobs" attribute is not
+ involved, so that the client is able to finish submitting a
+ multi-document job after this attribute has been set to 'true'.
+ Another condition is that the state of the job precludes Send-
+ Document, i.e., the job has already been closed out by the
+ client. However, if the IPP Printer closed out the job due to
+ timeout, the 'client-error-timeout' error status SHOULD be
+ returned instead.
+ client-error-timeout: This request was sent after the Printer
+ closed the job, because it has not received a Send-Document or
+ Send-URI operation within the Printer's "multiple-operation-
+ time-out" period.
+ client-error-request-entity-too-large: same as Print-Job.
+ client-error-conflicting-attributes: same as Print-Job, except
+ that "ipp-attributes-fidelity" operation attribute is not
+ involved.
+ server-error-operation-not-supported: the Send-Document request
+ is not supported.
+ server-error-not-accepting-jobs: not applicable.
+ server-error-job-canceled: the job has been canceled by an
+ operator or the system while the client was transmitting the
+ data.
+
+
+
+
+
+Hastings & Manros Informational [Page 43]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+2.3.2.2 Send-URI
+
+ All of the Print-Job status code descriptions in Section 3.2.1.2
+ Print-Job Response with the specializations described for Send-
+ Document are applicable to Send-URI. See Section 14 for a more
+ complete description of each status code.
+
+ server-error-uri-scheme-not-supported: the URI scheme supplied in
+ the "document-uri" operation attribute is not supported and the
+ "document-uri" attribute MUST be returned in the Unsupported
+ Attributes group.
+
+2.3.2.3 Cancel-Job
+
+ All of the Print-Job status codes described in Section 3.2.1.2
+ Print-Job Response are applicable to Cancel-Job with the following
+ specializations and differences. See Section 14 for a more complete
+ description of each status code.
+
+ For the following success status codes, the Job object is being
+ canceled or has been canceled:
+
+ successful-ok: no request attributes were substituted or ignored
+ (same as Print-Job).
+ successful-ok-ignored-or-substituted-attributes: same as Print-
+ Job.
+ successful-ok-conflicting-attributes: same as Print-Job.
+
+ For any of the error status codes, the Job object has not been
+ canceled or was previously canceled.
+
+ client-error-not-possible: The request cannot be carried out
+ because of the state of the Job object ('completed', '
+ canceled', or 'aborted') or the state of the system.
+ client-error-not-found: the target Printer and/or Job object does
+ not exist.
+ client-error-gone: the target Printer and/or Job object no longer
+ exists and no forwarding address is known.
+ client-error-request-entity-too-large: same as Print-Job, except
+ no document data is involved.
+ client-error-document-format-not-supported: not applicable.
+ client-error-attributes-or-values-not-supported: not applicable,
+ since unsupported operation attributes and values MUST be
+ ignored.
+ client-error-conflicting-attributes: same as Print-Job, except
+ that the Printer's "printer-is-accepting-jobs" attribute is not
+ involved.
+
+
+
+
+Hastings & Manros Informational [Page 44]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ server-error-operation-not-supported: not applicable (Cancel-Job
+ is REQUIRED).
+ server-error-device-error: same as Print-Job, except no document
+ data is involved.
+ server-error-temporary-error: same as Print-Job, except no
+ document data is involved.
+ server-error-not-accepting-jobs: not applicable.
+ server-error-job-canceled: not applicable.
+
+2.3.2.4 Get-Job-Attributes
+
+ All of the Print-Job status codes described in Section 3.2.1.2
+ Print-Job Response are applicable to Get-Job-Attributes with the
+ following specializations and differences. See Section 14 for a more
+ complete description of each status code.
+
+ For the following success status codes, the requested attributes are
+ returned in Group 3 in the response:
+
+ successful-ok: no request attributes were substituted or ignored
+ (same as Print-Job) and no requested attributes were
+ unsupported.
+ successful-ok-ignored-or-substituted-attributes: same as Print-
+ Job, except the "requested-attributes" operation attribute MAY,
+ but NEED NOT, be returned with the unsupported values.
+ successful-ok-conflicting-attributes: same as Print-Job.
+
+ For the error status codes, Group 3 is returned containing no
+ attributes or is not returned at all.
+
+ client-error-not-possible: Same as Print-Job, in addition the
+ Printer object is not accepting any requests.
+ client-error-document-format-not-supported: not applicable.
+ client-error-attributes-or-values-not-supported: not applicable.
+ client-error-uri-scheme-not-supported: not applicable.
+ client-error-conflicting-attributes: not applicable
+ server-error-operation-not-supported: not applicable (since Get-
+ Job-Attributes is REQUIRED).
+ server-error-device-error: same as Print-Job, except no document
+ data is involved.
+ server-error-temporary-error: sane as Print-Job, except no
+ document data is involved.
+ server-error-not-accepting-jobs: not applicable. server-error-
+ job-canceled: not applicable.
+
+
+
+
+
+
+
+Hastings & Manros Informational [Page 45]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+2.4 Validate-Job
+
+ The Validate-Job operation has been designed so that its
+ implementation may be a part of the Print-Job operation. Therefore,
+ requiring Validate-Job is not a burden on implementers. Also it is
+ useful for client's to be able to count on its presence in all
+ conformance implementations, so that the client can determine before
+ sending a long document, whether the job will be accepted by the IPP
+ Printer or not.
+
+2.5 Case Sensitivity in URIs
+
+ IPP client and server implementations must be aware of the diverse
+ uppercase/lowercase nature of URIs. RFC 2396 defines URL schemes and
+ Host names as case insensitive but reminds us that the rest of the
+ URL may well demonstrate case sensitivity. When creating URL's for
+ fields where the choice is completely arbitrary, it is probably best
+ to select lower case. However, this cannot be guaranteed and
+ implementations MUST NOT rely on any fields being case-sensitive or
+ case-insensitive in the URL beyond the URL scheme and host name
+ fields.
+
+ The reason that the IPP specification does not make any restrictions
+ on URIs, is so that implementations of IPP may use off-the-shelf
+ components that conform to the standards that define URIs, such as
+ RFC 2396 and the HTTP/1.1 specifications [RFC2068]. See these
+ specifications for rules of matching, comparison, and case-
+ sensitivity.
+
+ It is also recommended that System Administrators and implementations
+ avoid creating URLs for different printers that differ only in their
+ case. For example, don't have Printer1 and printer1 as two different
+ IPP Printers.
+
+ The HTTP/1.1 specification [RFC2068] contains more details on
+ comparing URLs.
+
+2.6 Character Sets, natural languages, and internationalization
+
+ This section discusses character set support, natural language
+ support and internationalization.
+
+2.6.1 Character set code conversion support
+
+ IPP clients and IPP objects are REQUIRED to support UTF-8. They MAY
+ support additional charsets. It is RECOMMENDED that an IPP object
+ also support US-ASCII, since many clients support US-ASCII, and
+ indicate that UTF-8 and US-ASCII are supported by populating the
+
+
+
+Hastings & Manros Informational [Page 46]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ Printer's "charset-supported" with 'utf-8' and 'us-ascii' values. An
+ IPP object is required to code covert with as little loss as possible
+ between the charsets that it supports, as indicated in the Printer's
+ "charsets-supported" attribute.
+
+ How should the server handle the situation where the "attributes-
+ charset" of the response itself is "us-ascii", but one or more
+ attributes in that response is in the "utf-8" format?
+
+ Example: Consider a case where a client sends a Print-Job request
+ with "utf-8" as the value of "attributes-charset" and with the "job-
+ name" attribute supplied. Later another client submits a Get-Job-
+ Attribute or Get-Jobs request. This second request contains the
+ "attributes-charset" with value "us-ascii" and "requested-attributes"
+ attribute with exactly one value "job-name".
+
+ According to the RFC2566 document (section 3.1.4.2), the value of the
+ "attributes-charset" for the response of the second request must be
+ "us-ascii" since that is the charset specified in the request. The
+ "job-name" value, however, is in "utf-8" format. Should the request
+ be rejected even though both "utf-8" and "us-ascii" charsets are
+ supported by the server? or should the "job-name" value be converted
+ to "us-ascii" and return "successful-ok-conflicting-attributes"
+ (0x0002) as the status code?
+
+ Answer: An IPP object that supports both utf-8 (REQUIRED) and us-
+ ascii, the second paragraph of section 3.1.4.2 applies so that the
+ IPP object MUST accept the request, perform code set conversion
+ between these two charsets with "the highest fidelity possible" and
+ return 'successful-ok', rather than a warning 'successful-ok-
+ conflicting-attributes, or an error. The printer will do the best it
+ can to convert between each of the character sets that it supports--
+ even if that means providing a string of question marks because none
+ of the characters are representable in US ASCII. If it can't perform
+ such conversion, it MUST NOT advertise us-ascii as a value of its
+ "attributes-charset-supported" and MUST reject any request that
+ requests 'us-ascii'.
+
+ One IPP object implementation strategy is to convert all request text
+ and name values to a Unicode internal representation. This is 16-bit
+ and virtually universal. Then convert to the specified operation
+ attributes-charset on output.
+
+ Also it would be smarter for a client to ask for 'utf-8', rather than
+ 'us-ascii' and throw away characters that it doesn't understand,
+ rather than depending on the code conversion of the IPP object.
+
+
+
+
+
+Hastings & Manros Informational [Page 47]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+2.6.2 What charset to return when an unsupported charset is requested?
+
+ Section 3.1.4.1 Request Operation attributes was clarified in
+ November 1998 as follows:
+
+ All clients and IPP objects MUST support the 'utf-8' charset
+ [RFC2044] and MAY support additional charsets provided that they
+ are registered with IANA [IANA-CS]. If the Printer object does
+ not support the client supplied charset value, the Printer object
+ MUST reject the request, set the "attributes-charset" to 'utf-8'
+ in the response, and return the 'client-error-charset-not-
+ supported' status code and any 'text' or 'name' attributes using
+ the 'utf-8' charset.
+
+ Since the client and IPP object MUST support UTF-8, returning any
+ text or name attributes in UTF-8 when the client requests a charset
+ that is not supported should allow the client to display the text or
+ name.
+
+ Since such an error is a client error, rather than a user error, the
+ client should check the status code first so that it can avoid
+ displaying any other returned 'text' and 'name' attributes that are
+ not in the charset requested.
+
+ Furthermore, [RFC2566] section 14.1.4.14 client-error-charset-not-
+ supported (0x040D) was clarified in November 1998 as follows:
+
+ For any operation, if the IPP Printer does not support the charset
+ supplied by the client in the "attributes-charset" operation
+ attribute, the Printer MUST reject the operation and return this
+ status and any 'text' or 'name' attributes using the 'utf-8'
+ charset (see Section 3.1.4.1).
+
+2.6.3 Natural Language Override (NLO)
+
+ The 'text' and 'name' attributes each have two forms. One has an
+ implicit natural language, and the other has an explicit natural
+ language. The 'textWithoutLanguage' and 'textWithoutLanguage' are
+ the two 'text' forms. The 'nameWithoutLanguage" and '
+ nameWithLanguage are the two 'name' forms. If a receiver (IPP object
+ or IPP client) supports an attribute with attribute syntax 'text', it
+ MUST support both forms in a request and a response. A sender (IPP
+ client or IPP object) MAY send either form for any such attribute.
+ When a sender sends a WithoutLanguage form, the implicit natural
+ language is specified in the "attributes-natural-language" operation
+ attribute which all senders MUST include in every request and
+ response.
+
+
+
+
+Hastings & Manros Informational [Page 48]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ When a sender sends a WithLanguage form, it MAY be different from the
+ implicit natural language supplied by the sender or it MAY be the
+ same. The receiver MUST treat either form equivalently.
+
+ There is an implementation decision for senders, whether to always
+ send the WithLanguage forms or use the WithoutLanguage form when the
+ attribute's natural language is the same as the request or response.
+ The former approach makes the sender implementation simpler. The
+ latter approach is more efficient on the wire and allows inter-
+ working with non-conforming receivers that fail to support the
+ WithLanguage forms. As each approach have advantages, the choice is
+ completely up to the implementer of the sender.
+
+ Furthermore, when a client receives a 'text' or 'name' job attribute
+ that it had previously supplied, that client MUST NOT expect to see
+ the attribute in the same form, i.e., in the same WithoutLanguage or
+ WithLanguage form as the client supplied when it created the job.
+ The IPP object is free to transform the attribute from the
+ WithLanguage form to the WithoutLanguage form and vice versa, as long
+ as the natural language is preserved. However, in order to meet this
+ latter requirement, it is usually simpler for the IPP object
+ implementation to store the natural language explicitly with the
+ attribute value, i.e., to store using an internal representation that
+ resembles the WithLanguage form.
+
+ The IPP Printer MUST copy the natural language of a job, i.e., the
+ value of the "attributes-natural-language" operation attribute
+ supplied by the client in the create operation, to the Job object as
+ a Job Description attribute, so that a client is able to query it.
+ In returning a Get-Job-Attributes response, the IPP object MAY return
+ one of three natural language values in the response's "attributes-
+ natural-language" operation attribute: (1) that requested by the
+ requester, (2) the natural language of the job, or (3) the configured
+ natural language of the IPP Printer, if the requested language is not
+ supported by the IPP Printer.
+
+ This "attributes-natural-language" Job Description attribute is
+ useful for an IPP object implementation that prints start sheets in
+ the language of the user who submitted the job. This same Job
+ Description attribute is useful to a multi-lingual operator who has
+ to communicate with different job submitters in different natural
+ languages. This same Job Description attribute is expected to be
+ used in the future to generate notification messages in the natural
+ language of the job submitter.
+
+ Early drafts of [RFC2566] contained a job-level natural language
+ override (NLO) for the Get-Jobs response. A job-level (NLO) is an
+ (unrequested) Job Attribute which then specified the implicit natural
+
+
+
+Hastings & Manros Informational [Page 49]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ language for any other WithoutLanguage job attributes returned in the
+ response for that job. Interoperability testing of early
+ implementations showed that no one was implementing the job-level NLO
+ in Get-Job responses. So the job-level NLO was eliminated from the
+ Get- Jobs response. This simplification makes all requests and
+ responses consistent in that the implicit natural language for any
+ WithoutLanguage 'text' or 'name' form is always supplied in the
+ request's or response's "attributes-natural-language" operation
+ attribute.
+
+2.7 The "queued-job-count" Printer Description attribute
+
+2.7.1 Why is "queued-job-count" RECOMMENDED?
+
+ The reason that "queued-job-count" is RECOMMENDED, is that some
+ clients look at that attribute alone when summarizing the status of a
+ list of printers, instead of doing a Get-Jobs to determine the number
+ of jobs in the queue. Implementations that fail to support the
+ "queued-job-count" will cause that client to display 0 jobs when
+ there are actually queued jobs.
+
+ We would have made it a REQUIRED Printer attribute, but some
+ implementations had already been completed before the issue was
+ raised, so making it a SHOULD was a compromise.
+
+2.7.2 Is "queued-job-count" a good measure of how busy a printer is?
+
+ The "queued-job-count" is not a good measure of how busy the printer
+ is when there are held jobs. A future registration could be to add a
+ "held-job-count" (or an "active-job-count") Printer Description
+ attribute if experience shows that such an attribute (combination) is
+ needed to quickly indicate how busy a printer really is.
+
+2.8 Sending empty attribute groups
+
+ The [RFC2566] and [RFC2565] specifications RECOMMEND that a sender
+ not send an empty attribute group in a request or a response.
+ However, they REQUIRE a receiver to accept an empty attribute group
+ as equivalent to the omission of that group. So a client SHOULD omit
+ the Job Template Attributes group entirely in a create operation that
+ is not supplying any Job Template attributes. Similarly, an IPP
+ object SHOULD omit an empty Unsupported Attributes group if there are
+ no unsupported attributes to be returned in a response.
+
+
+
+
+
+
+
+
+Hastings & Manros Informational [Page 50]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ The [RFC2565] specification REQUIRES a receiver to be able to receive
+ either an empty attribute group or an omitted attribute group and
+ treat them equivalently. The term "receiver" means an IPP object for
+ a request and a client for a response. The term "sender' means a
+ client for a request and an IPP object for a response.
+
+ There is an exception to the rule for Get-Jobs when there are no
+ attributes to be returned. [RFC2565] contains the following
+ paragraph:
+
+ The syntax allows an xxx-attributes-tag to be present when the
+ xxx-attribute-sequence that follows is empty. The syntax is
+ defined this way to allow for the response of Get-Jobs where no
+ attributes are returned for some job-objects. Although it is
+ RECOMMENDED that the sender not send an xxx-attributes-tag if
+ there are no attributes (except in the Get-Jobs response just
+ mentioned), the receiver MUST be able to decode such syntax.
+
+2.9 Returning unsupported attributes in Get-Xxxx responses
+
+ In the Get-Printer-Attributes, Get-Jobs, or Get-Job-Attributes
+ responses, the client cannot depend on getting unsupported attributes
+ returned in the Unsupported Attributes group that the client
+ requested, but are not supported by the IPP object. However, such
+ unsupported requested attributes will not be returned in the Job
+ Attributes or Printer Attributes group (since they are unsupported).
+ Furthermore, the IPP object is REQUIRED to return the 'successful-
+ ok-ignored-or-substituted-attributes' status code, so that the client
+ knows that not all that was requested has been returned.
+
+2.10 Returning job-state in Print-Job response
+
+ An IPP client submits a small job via Print-Job. By the time the IPP
+ printer/print server is putting together a response to the operation,
+ the job has finished printing and been removed as an object from the
+ print system. What should the job-state be in the response?
+
+ The Model suggests that the Printer return a response before it even
+ accepts the document content. The Job Object Attributes are returned
+ only if the IPP object returns one of the success status codes. Then
+ the job-state would always be "pending" or "pending-held".
+
+ This issue comes up for the implementation of an IPP Printer object
+ as a server that forwards jobs to devices that do not provide job
+ status back to the server. If the server is reasonably certain that
+ the job completed successfully, then it should return the job-state
+ as 'completed'. Also the server can keep the job in its "job
+ history" long after the job is no longer in the device. Then a user
+
+
+
+Hastings & Manros Informational [Page 51]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ could query the server and see that the job was in the 'completed'
+ state and completed as specified by the job's "time-at-completed"
+ time which would be the same as the server submitted the job to the
+ device.
+
+ An alternative is for the server to respond to the client before or
+ while sending the job to the device, instead of waiting until the
+ server has finished sending the job to the device. In this case, the
+ server can return the job's state as 'pending' with the 'job-
+ outgoing' value in the job's "job-state-reasons" attribute.
+
+ If the server doesn't know for sure whether the job completed
+ successfully (or at all), it could return the (out-of-band) 'unknown'
+ value.
+
+ On the other hand, if the server is able to query the device and/or
+ setup some sort of event notification that the device initiates when
+ the job makes state transitions, then the server can return the
+ current job state in the Print-Job response and in subsequent queries
+ because the server knows what the job state is in the device (or can
+ query the device).
+
+ All of these alternatives depend on implementation of the server and
+ the device.
+
+2.11 Flow controlling the data portion of a Print-Job request
+
+ A paused printer (or one that is stopped due to paper out or jam or
+ spool space full or buffer space full, may flow control the data of a
+ Print-Job operation (at the TCP/IP layer), so that the client is not
+ able to send all the document data. Consequently, the Printer will
+ not return a response until the condition is changed.
+
+ The Printer should not return a Print-Job response with an error code
+ in any of these conditions, since either the printer will be resumed
+ and/or the condition will be freed either by human intervention or as
+ jobs print.
+
+ In writing test scripts to test IPP Printers, the script must also be
+ written not to expect a response, if the printer has been paused,
+ until the printer is resumed, in order to work with all possible
+ implementations.
+
+2.12 Multi-valued attributes
+
+ What is the attribute syntax for a multi-valued attribute? Since
+ some attributes support values in more than one data type, such as
+ "media", "job-hold-until", and "job-sheets", IPP semantics associate
+
+
+
+Hastings & Manros Informational [Page 52]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ the attribute syntax with each value, not with the attribute as a
+ whole. The protocol associates the attribute syntax tag with each
+ value. Don't be fooled, just because the attribute syntax tag comes
+ before the attribute keyword. All attribute values after the first
+ have a zero length attribute keyword as the indication of a
+ subsequent value of the same attribute.
+
+2.13 Querying jobs with IPP that were submitted using other job
+ submission protocols
+
+ The following clarification was added to [RFC2566] section 8.5:
+
+ 8.5 Queries on jobs submitted using non-IPP protocols
+
+ If the device that an IPP Printer is representing is able to
+ accept jobs using other job submission protocols in addition to
+ IPP, it is RECOMMEND that such an implementation at least allow
+ such "foreign" jobs to be queried using Get-Jobs returning "job-
+ id" and "job-uri" as 'unknown'. Such an implementation NEED NOT
+ support all of the same IPP job attributes as for IPP jobs. The
+ IPP object returns the 'unknown' out-of-band value for any
+ requested attribute of a foreign job that is supported for IPP
+ jobs, but not for foreign jobs.
+
+ It is further RECOMMENDED, that the IPP Printer generate "job-id"
+ and "job-uri" values for such "foreign jobs", if possible, so that
+ they may be targets of other IPP operations, such as Get-Job-
+ Attributes and Cancel-Job. Such an implementation also needs to
+ deal with the problem of authentication of such foreign jobs. One
+ approach would be to treat all such foreign jobs as belonging to
+ users other than the user of the IPP client. Another approach
+ would be for the foreign job to belong to 'anonymous'. Only if
+ the IPP client has been authenticated as an operator or
+ administrator of the IPP Printer object, could the foreign jobs be
+ queried by an IPP request. Alternatively, if the security policy
+ is to allow users to query other users' jobs, then the foreign
+ jobs would also be visible to an end-user IPP client using Get-
+ Jobs and Get-Job-Attributes.
+
+ Thus IPP MAY be implemented as a "universal" protocol that provides
+ access to jobs submitted with any job submission protocol. As IPP
+ becomes widely implemented, providing a more universal access makes
+ sense.
+
+
+
+
+
+
+
+
+Hastings & Manros Informational [Page 53]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+2.14 The 'none' value for empty sets
+
+ [RFC2566] states that the 'none' value should be used as the value of
+ a 1SetOf when the set is empty. In most cases, sets that are
+ potentially empty contain keywords so the keyword 'none' is used, but
+ for the 3 finishings attributes, the values are enums and thus the
+ empty set is represented by the enum 3. Currently there are no other
+ attributes with 1SetOf values which can be empty and can contain
+ values that are not keywords. This exception requires special code
+ and is a potential place for bugs. It would have been better if we
+ had chosen an out-of-band value, either "no-value" or some new value,
+ such as 'none'. Since we didn't, implementations have to deal with
+ the different representations of 'none', depending on the attribute
+ syntax.
+
+2.15 Get-Jobs, my-jobs='true', and 'requesting-user-name'?
+
+ In [RFC2566] section 3.2.6.1 'Get-Jobs Request', if the attribute '
+ my-jobs' is present and set to TRUE, MUST the 'requesting-user-name'
+ attribute be there to, and if it's not present what should the IPP
+ printer do?
+
+ [RFC2566] Section 8.3 describes the various cases of "requesting-
+ user-name" being present or not for any operation. If the client
+ does not supply a value for "requesting-user-name", the printer MUST
+ assume that the client is supplying some anonymous name, such as
+ "anonymous".
+
+2.16 The "multiple-document-handling" Job Template attribute and support
+ of multiple document jobs
+
+ ISSUE: IPP/1.0 is silent on which of the four effects an
+ implementation would perform if it supports Create-Job, but does not
+ support "multiple-document-handling".
+
+ A fix to IPP/1.0 would be to require implementing all four values of
+ "multiple-document-handling" if Create-Job is supported at all. Or
+ at least 'single-document-new-sheet' and 'separate-documents-
+ uncollated-copies'. In any case, an implementation that supports
+ Create-Job SHOULD also support "multiple-document-handling". Support
+ for all four values is RECOMMENDED, but at least the 'single-
+ document-new-sheet' and 'separate-documents-uncollated-copies'
+ values, along with the "multiple-document-handling-default"
+ indicating the default behavior and "multiple-document-handling-
+ supported" values. If an implementation spools the data, it should
+ also support the 'separate-documents-collated-copies' value as well.
+
+
+
+
+
+Hastings & Manros Informational [Page 54]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+3 Encoding and Transport
+
+ This section discusses various aspects of IPP/1.0 Encoding and
+ Transport [RFC2565].
+
+ A server is not required to send a response until after it has
+ received the client.s entire request. Hence, a client must not
+ expect a response until after it has sent the entire request.
+ However, we recommend that the server return a response as soon as
+ possible if an error is detected while the client is still sending
+ the data, rather than waiting until all of the data is received.
+ Therefore, we also recommend that a client listen for an error
+ response that an IPP server MAY send before it receives all the data.
+ In this case a client, if chunking the data, can send a premature
+ zero-length chunk to end the request before sending all the data (and
+ so the client can keep the connection open for other requests, rather
+ than closing it). If the request is blocked for some reason, a client
+ MAY determine the reason by opening another connection to query the
+ server using Get-Printer-Attributes.
+
+ In the following sections, there are a tables of all HTTP headers
+ which describe their use in an IPP client or server. The following
+ is an explanation of each column in these tables.
+
+ - the .header. column contains the name of a header.
+ - the .request/client. column indicates whether a client sends the
+ header.
+ - the .request/ server. column indicates whether a server supports
+ the header when received.
+ - the .response/ server. column indicates whether a server sends
+ the header.
+ - the .response /client. column indicates whether a client
+ supports the header when received.
+ - the .values and conditions. column specifies the allowed header
+ values and the conditions for the header to be present in a
+ request/response.
+
+ The table for .request headers. does not have columns for responses,
+ and the table for .response headers. does not have columns for
+ requests.
+
+ The following is an explanation of the values in the .request/client.
+ and .response/ server. columns.
+
+ - must: the client or server MUST send the header,
+ - must-if: the client or server MUST send the header when the
+ condition described in the .values and conditions. column is
+ met,
+
+
+
+Hastings & Manros Informational [Page 55]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ - may: the client or server MAY send the header
+ - not: the client or server SHOULD NOT send the header. It is not
+ relevant to an IPP implementation.
+
+ The following is an explanation of the values in the
+ .response/client. and .request/ server. columns.
+
+ - must: the client or server MUST support the header,
+ - may: the client or server MAY support the header
+ - not: the client or server SHOULD NOT support the header. It is
+ not relevant to an IPP implementation.
+
+3.1 General Headers
+
+
+ The following is a table for the general headers.
+
+
+ General- Request Response Values and Conditions
+ Header
+
+ Client Server Server Client
+
+ Cache- must not must not .no-cache. only
+ Control
+
+ Connection must-if must must- must .close. only. Both
+ if client and server
+ SHOULD keep a
+ connection for the
+ duration of a sequence
+ of operations. The
+ client and server MUST
+ include this header
+ for the last operation
+ in such a sequence.
+
+ Date may may must may per RFC 1123 [RFC1123]
+ from RFC 2068
+ [RFC2068]
+
+ Pragma must not must not .no-cache. only
+
+ Transfer- must-if must must- must .chunked. only .
+ Encoding if Header MUST be present
+ if Content-Length is
+ absent.
+
+
+
+
+Hastings & Manros Informational [Page 56]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ Upgrade not not not not
+
+ Via not not not not
+
+3.2 Request Headers
+
+
+ The following is a table for the request headers.
+
+
+ Request-Header Client Server Request Values and Conditions
+
+ Accept may must .application/ipp. only. This
+ value is the default if the
+
+ Request-Header Client Server Request Values and Conditions
+
+ client omits it
+
+ Accept-Charset not not Charset information is within
+ the application/ipp entity
+
+ Accept-Encoding may must empty and per RFC 2068 [RFC2068]
+ and IANA registry for content-
+ codings
+
+ Accept-Language not not language information is within
+ the application/ipp entity
+
+ Authorization must-if must per RFC 2068. A client MUST send
+ this header when it receives a
+ 401 .Unauthorized. response and
+ does not receive a .Proxy-
+ Authenticate. header.
+
+ From not not per RFC 2068. Because RFC
+ recommends sending this header
+ only with the user.s approval, it
+ is not very useful
+
+ Host must must per RFC 2068
+
+ If-Match not not
+
+ If-Modified- not not
+ Since
+
+ If-None-Match not not
+
+
+
+Hastings & Manros Informational [Page 57]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ If-Range not not
+
+ If-Unmodified- not not
+ Since
+
+ Max-Forwards not not
+
+ Proxy- must-if not per RFC 2068. A client MUST send
+ Authorization this header when it receives a
+ 401 .Unauthorized. response and a
+ .Proxy-Authenticate. header.
+
+ Range not not
+
+ Referer not not
+
+ User-Agent not not
+
+
+3.3 Response Headers
+
+
+ The following is a table for the request headers.
+
+
+ Response- Server Client Response Values and Conditions
+ Header
+
+ Accept-Ranges not not
+
+ Age not not
+
+ Location must-if may per RFC 2068. When URI needs
+ redirection.
+
+ Proxy- not must per RFC 2068
+ Authenticate
+
+ Public may may per RFC 2068
+
+ Retry-After may may per RFC 2068
+
+ Server not not
+
+ Vary not not
+
+ Warning may may per RFC 2068
+
+
+
+
+Hastings & Manros Informational [Page 58]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ WWW- must-if must per RFC 2068. When a server needs to
+ Authenticate authenticate a client.
+
+3.4 Entity Headers
+
+
+ The following is a table for the entity headers.
+
+
+ Entity-Header Request Response Values and Conditions
+
+ Client Server Server Client
+
+ Allow not not not not
+
+ Content-Base not not not not
+
+ Content- may must must must per RFC 2068 and IANA
+ Encoding registry for content
+ codings.
+
+ Content- not not not not Application/ipp
+ Language handles language
+
+ Content- must-if must must-if must the length of the
+ Length message-body per RFC
+ 2068. Header MUST be
+ present if Transfer-
+
+ Entity-Header Request Response Values and Conditions
+
+ Client Server Server Client
+
+ Encoding is absent.
+
+ Content- not not not not
+ Location
+
+ Content-MD5 may may may may per RFC 2068
+
+ Content-Range not not not not
+
+ Content-Type must must must must .application/ipp.
+ only
+
+ ETag not not not not
+
+ Expires not not not not
+
+
+
+Hastings & Manros Informational [Page 59]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ Last-Modified not not not not
+
+
+3.5 Optional support for HTTP/1.0
+
+ IPP implementations consist of an HTTP layer and an IPP layer. In
+ the following discussion, the term "client" refers to the HTTP client
+ layer and the term "server" refers to the HTTP server layer. The
+ Encoding and Transport document [RFC2565] requires that HTTP 1.1 MUST
+ be supported by all clients and all servers. However, a client
+ and/or a server implementation may choose to also support HTTP 1.0.
+
+ - This option means that a server may choose to communicate with a
+ (non-conforming) client that only supports HTTP 1.0. In such cases
+ the server should not use any HTTP 1.1 specific parameters or
+ features and should respond using HTTP version number 1.0.
+
+ - This option also means that a client may choose to communicate with
+ a (non-conforming) server that only supports HTTP 1.0. In such
+ cases, if the server responds with an HTTP .unsupported version
+ number. to an HTTP 1.1 request, the client should retry using HTTP
+ version number 1.0.
+
+3.6 HTTP/1.1 Chunking
+
+3.6.1 Disabling IPP Server Response Chunking
+
+ Clients MUST anticipate that the HTTP/1.1 server may chunk responses
+ and MUST accept them in responses. However, a (non-conforming) HTTP
+ client that is unable to accept chunked responses may attempt to
+ request an HTTP 1.1 server not to use chunking in its response to an
+ operation by using the following HTTP header:
+
+ TE: identity
+
+ This mechanism should not be used by a server to disable a client
+ from chunking a request, since chunking of document data is an
+ important feature for clients to send long documents.
+
+3.6.2 Warning About the Support of Chunked Requests
+
+ This section describes some problems with the use of chunked requests
+ and HTTP/1.1 servers.
+
+ The HTTP/1.1 standard [HTTP] requires that conforming servers support
+ chunked requests for any method. However, in spite of this
+ requirement, some HTTP/1.1 implementations support chunked responses
+ in the GET method, but do not support chunked POST method requests.
+
+
+
+Hastings & Manros Informational [Page 60]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ Some HTTP/1.1 implementations that support CGI scripts [CGI] and/or
+ servlets [Servlet] require that the client supply a Content-Length.
+ These implementations might reject a chunked POST method and return a
+ 411 status code (Length Required), might attempt to buffer the
+ request and run out of room returning a 413 status code (Request
+ Entity Too Large), or might successfully accept the chunked request.
+
+ Because of this lack of conformance of HTTP servers to the HTTP/1.1
+ standard, the IPP standard [RFC2565] REQUIRES that a conforming IPP
+ Printer object implementation support chunked requests and that
+ conforming clients accept chunked responses. Therefore, IPP object
+ implementers are warned to seek HTTP server implementations that
+ support chunked POST requests in order to conform to the IPP standard
+ and/or use implementation techniques that support chunked POST
+ requests.
+
+4 References
+
+ [CGI] Coar, K. and D. Robinson, "The WWW Common Gateway Interface
+ Version 1.1 (CGI/1.1)", Work in Progress.
+
+ [HTTP] Fielding, R., Gettys,J., Mogul, J., Frystyk,, H., Masinter,
+ L., Leach, P. and T. Berners-Lee, "Hypertext Transfer
+ Protocol -- HTTP/1.1", RFC 2616, June 1999.
+
+ [RFC2569] Herriot, R., Hastings, T., Jacobs, N. and J. Martin,
+ "Mapping between LPD and IPP Protocols", RFC 2569, April
+ 1999.
+
+ [RFC2566] deBry, R., Hastings, T., Herriot, R., Isaacson, S. and P.
+ Powell, "Internet Printing Protocol/1.0: Model and
+ Semantics", RFC 2566, April 1999.
+
+ [RFC2565] Herriot, R., Butler, S., Moore, P. and R. Tuner, "Internet
+ Printing Protocol/1.0: Encoding and Transport", RFC 2565,
+ April 1999.
+
+ [RFC2568] Zilles, S., "Rationale for the Structure and Model and
+ Protocol for the Internet Printing Protocol", RFC 2568,
+ April 1999.
+
+ [RFC2567] Wright, D., "Design Goals for an Internet Printing
+ Protocol", RFC 2567, April 1999.
+
+ [RFC1123] Braden, S., "Requirements for Internet Hosts - Application
+ and Support", STD 3, RFC 1123, October 1989.
+
+
+
+
+
+Hastings & Manros Informational [Page 61]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ [RFC2026] Bradner, S., "The Internet Standards Process -- Revision
+ 3", BCP 9, RFC 2026, October 1996.
+
+ [RFC2068] Fielding, R., Gettys, J., Mogul, J., Frystyk, H. and T.
+ Berners-Lee, "Hypertext Transfer Protocol -- HTTP/1.1", RFC
+ 2068, January 1997.
+
+ [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+ [RFC2396] Berners-Lee, T., Fielding, R. and L. Masinter, "Uniform
+ Resource Identifiers (URI): Generic Syntax", RFC 2396,
+ August 1998.
+
+ [Servlet] Servlet Specification Version 2.1
+ (http://java.sun.com/products/servlet/2.1/index.html).
+
+ [SSL] Netscape, The SSL Protocol, Version 3, (Text version 3.02),
+ November 1996.
+
+4.1 Authors' Addresses
+
+ Thomas N. Hastings
+ Xerox Corporation
+ 701 Aviation Blvd.
+ El Segundo, CA 90245
+
+ EMail: hastings@cp10.es.xerox.com
+
+
+ Carl-Uno Manros
+ Xerox Corporation
+ 701 Aviation Blvd.
+ El Segundo, CA 90245
+
+ EMail: manros@cp10.es.xerox.com
+
+5 Security Considerations
+
+ Security issues are discussed in sections 2.2, 2.3.1, and 8.5.
+
+6 Notices
+
+ The IETF takes no position regarding the validity or scope of any
+ intellectual property or other rights that might be claimed to
+ pertain to the implementation or use of the technology described in
+ this document or the extent to which any license under such rights
+ might or might not be available; neither does it represent that it
+
+
+
+Hastings & Manros Informational [Page 62]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+ has made any effort to identify any such rights. Information on the
+ IETF's procedures with respect to rights in standards-track and
+ standards-related documentation can be found in BCP-11 [BCP-11].
+ Copies of claims of rights made available for publication and any
+ assurances of licenses to be made available, or the result of an
+ attempt made to obtain a general license or permission for the use of
+ such proprietary rights by implementers or users of this
+ specification can be obtained from the IETF Secretariat.
+
+ The IETF invites any interested party to bring to its attention any
+ copyrights, patents or patent applications, or other proprietary
+ rights which may cover technology that may be required to practice
+ this standard. Please address the information to the IETF Executive
+ Director.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings & Manros Informational [Page 63]
+
+RFC 2639 IPP/1.0: Implementer's Guide July 1999
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings & Manros Informational [Page 64]
+
diff --git a/standards/rfc2712.txt b/standards/rfc2712.txt
new file mode 100644
index 000000000..4888e2e2d
--- /dev/null
+++ b/standards/rfc2712.txt
@@ -0,0 +1,395 @@
+
+
+
+
+
+
+Network Working Group A. Medvinsky
+Request for Comments: 2712 Excite
+Category: Standards Track M. Hur
+ CyberSafe Corporation
+ October 1999
+
+
+ Addition of Kerberos Cipher Suites to Transport Layer Security (TLS)
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+IESG Note:
+
+ The 40-bit ciphersuites defined in this memo are included only for
+ the purpose of documenting the fact that those ciphersuite codes have
+ already been assigned. 40-bit ciphersuites were designed to comply
+ with US-centric, and now obsolete, export restrictions. They were
+ never secure, and nowadays are inadequate even for casual
+ applications. Implementation and use of the 40-bit ciphersuites
+ defined in this document, and elsewhere, is strongly discouraged.
+
+1. Abstract
+
+ This document proposes the addition of new cipher suites to the TLS
+ protocol [1] to support Kerberos-based authentication. Kerberos
+ credentials are used to achieve mutual authentication and to
+ establish a master secret which is subsequently used to secure
+ client-server communication.
+
+2. Introduction
+
+ Flexibility is one of the main strengths of the TLS protocol.
+ Clients and servers can negotiate cipher suites to meet specific
+ security and administrative policies. However, to date,
+ authentication in TLS is limited only to public key solutions. As a
+ result, TLS does not fully support organizations with heterogeneous
+ security deployments that include authentication systems based on
+ symmetric cryptography. Kerberos, originally developed at MIT, is
+
+
+
+Medvinsky & Hur Standards Track [Page 1]
+
+RFC 2712 Addition of Kerberos Cipher Suites to TLS October 1999
+
+
+ based on an open standard [2] and is the most widely deployed
+ symmetric key authentication system. This document proposes a new
+ option for negotiating Kerberos authentication within the TLS
+ framework. This achieves mutual authentication and the establishment
+ of a master secret using Kerberos credentials. The proposed changes
+ are minimal and, in fact, no different from adding a new public key
+ algorithm to the TLS framework.
+
+3. Kerberos Authentication Option In TLS
+
+ This section describes the addition of the Kerberos authentication
+ option to the TLS protocol. Throughout this document, we refer to
+ the basic SSL handshake shown in Figure 1. For a review of the TLS
+ handshake see [1].
+
+ CLIENT SERVER
+ ------ ------
+ ClientHello
+ -------------------------------->
+ ServerHello
+ Certificate *
+ ServerKeyExchange*
+ CertificateRequest*
+ ServerHelloDone
+ <-------------------------------
+ Certificate*
+ ClientKeyExchange
+ CertificateVerify*
+ change cipher spec
+ Finished
+ | -------------------------------->
+ | change cipher spec
+ | Finished
+ | |
+ | |
+ Application Data <------------------------------->Application Data
+
+ FIGURE 1: The TLS protocol. All messages followed by a star are
+ optional. Note: This figure was taken from an IETF document
+ [1].
+
+ The TLS security context is negotiated in the client and server hello
+ messages. For example: TLS_RSA_WITH_RC4_MD5 means the initial
+ authentication will be done using the RSA public key algorithm, RC4
+ will be used for the session key, and MACs will be based on the MD5
+ algorithm. Thus, to facilitate the Kerberos authentication option,
+ we must start by defining new cipher suites including (but not
+ limited to):
+
+
+
+Medvinsky & Hur Standards Track [Page 2]
+
+RFC 2712 Addition of Kerberos Cipher Suites to TLS October 1999
+
+
+ CipherSuite TLS_KRB5_WITH_DES_CBC_SHA = { 0x00,0x1E };
+ CipherSuite TLS_KRB5_WITH_3DES_EDE_CBC_SHA = { 0x00,0x1F };
+ CipherSuite TLS_KRB5_WITH_RC4_128_SHA = { 0x00,0x20 };
+ CipherSuite TLS_KRB5_WITH_IDEA_CBC_SHA = { 0x00,0x21 };
+ CipherSuite TLS_KRB5_WITH_DES_CBC_MD5 = { 0x00,0x22 };
+ CipherSuite TLS_KRB5_WITH_3DES_EDE_CBC_MD5 = { 0x00,0x23 };
+ CipherSuite TLS_KRB5_WITH_RC4_128_MD5 = { 0x00,0x24 };
+ CipherSuite TLS_KRB5_WITH_IDEA_CBC_MD5 = { 0x00,0x25 };
+
+ CipherSuite TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA = { 0x00,0x26 };
+ CipherSuite TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA = { 0x00,0x27 };
+ CipherSuite TLS_KRB5_EXPORT_WITH_RC4_40_SHA = { 0x00,0x28 };
+ CipherSuite TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5 = { 0x00,0x29 };
+ CipherSuite TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5 = { 0x00,0x2A };
+ CipherSuite TLS_KRB5_EXPORT_WITH_RC4_40_MD5 = { 0x00,0x2B };
+
+ To establish a Kerberos-based security context, one or more of the
+ above cipher suites must be specified in the client hello message.
+ If the TLS server supports the Kerberos authentication option, the
+ server hello message, sent to the client, will confirm the Kerberos
+ cipher suite selected by the server. The server's certificate, the
+ client
+
+ CertificateRequest, and the ServerKeyExchange shown in Figure 1 will
+ be omitted since authentication and the establishment of a master
+ secret will be done using the client's Kerberos credentials for the
+ TLS server. The client's certificate will be omitted for the same
+ reason. Note that these messages are specified as optional in the
+ TLS protocol; therefore, omitting them is permissible.
+
+ The Kerberos option must be added to the ClientKeyExchange message as
+ shown in Figure 2.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Medvinsky & Hur Standards Track [Page 3]
+
+RFC 2712 Addition of Kerberos Cipher Suites to TLS October 1999
+
+
+ struct
+ {
+ select (KeyExchangeAlgorithm)
+ {
+ case krb5: KerberosWrapper; /* new addition */
+ case rsa: EncryptedPreMasterSecret;
+ case diffie_hellman: ClientDiffieHellmanPublic;
+ } Exchange_keys;
+
+ } ClientKeyExchange;
+
+ struct
+ {
+ opaque Ticket;
+ opaque authenticator; /* optional */
+ opaque EncryptedPreMasterSecret; /* encrypted with the session key
+ which is sealed in the ticket */
+ } KerberosWrapper; /* new addition */
+
+ FIGURE 2: The Kerberos option in the ClientKeyExchange.
+
+ To use the Kerberos authentication option, the TLS client must obtain
+ a service ticket for the TLS server. In TLS, the ClientKeyExchange
+ message is used to pass a random 48-byte pre-master secret to the
+ server.
+
+ The client and server then use the pre-master secret to independently
+ derive the master secret, which in turn is used for generating
+ session keys and for MAC computations. Thus, if the Kerberos option
+ is selected, the pre-master secret structure is the same as that used
+ in the RSA case; it is encrypted under the Kerberos session key and
+ sent to the TLS server along with the Kerberos credentials (see
+ Figure 2). The ticket and authenticator are encoded per RFC 1510
+ (ASN.1 encoding). Once the ClientKeyExchange message is received,
+ the server's secret key is used to unwrap the credentials and extract
+ the pre-master secret.
+
+ Note that a Kerberos authenticator is not required, since the master
+ secret derived by the client and server is seeded with a random value
+ passed in the server hello message, thus foiling replay attacks.
+ However, the authenticator may still prove useful for passing
+ authorization information and is thus allotted an optional field (see
+ Figure 2).
+
+ Lastly, the client and server exchange the finished messages to
+ complete the handshake. At this point we have achieved the
+ following:
+
+
+
+
+Medvinsky & Hur Standards Track [Page 4]
+
+RFC 2712 Addition of Kerberos Cipher Suites to TLS October 1999
+
+
+ 1) A master secret, used to protect all subsequent communication, is
+ securely established.
+
+ 2) Mutual client-server authentication is achieved, since the TLS
+ server proves knowledge of the master secret in the finished
+ message.
+
+ Note that the Kerberos option fits in seamlessly, without adding any
+ new messages.
+
+4. Naming Conventions:
+
+ To obtain an appropriate service ticket, the TLS client must
+ determine the principal name of the TLS server. The Kerberos service
+ naming convention is used for this purpose, as follows:
+
+ host/MachineName@Realm
+ where:
+ - The literal, "host", follows the Kerberos convention when not
+ concerned about the protection domain on a particular machine.
+ - "MachineName" is the particular instance of the service.
+ - The Kerberos "Realm" is the domain name of the machine.
+
+5. Summary
+
+ The proposed Kerberos authentication option is added in exactly the
+ same manner as a new public key algorithm would be added to TLS.
+ Furthermore, it establishes the master secret in exactly the same
+ manner.
+
+6. Security Considerations
+
+ Kerberos ciphersuites are subject to the same security considerations
+ as the TLS protocol. In addition, just as a public key
+ implementation must take care to protect the private key (for example
+ the PIN for a smartcard), a Kerberos implementation must take care to
+ protect the long lived secret that is shared between the principal
+ and the KDC. In particular, a weak password may be subject to a
+ dictionary attack. In order to strengthen the initial authentication
+ to a KDC, an implementor may choose to utilize secondary
+ authentication via a token card, or one may utilize initial
+ authentication to the KDC based on public key cryptography (commonly
+ known as PKINIT - a product of the Common Authentication Technology
+ working group of the IETF).
+
+
+
+
+
+
+
+Medvinsky & Hur Standards Track [Page 5]
+
+RFC 2712 Addition of Kerberos Cipher Suites to TLS October 1999
+
+
+7. Acknowledgements
+
+ We would like to thank Clifford Neuman for his invaluable comments on
+ earlier versions of this document.
+
+8. References
+
+ [1] Dierks, T. and C. Allen, "The TLS Protocol, Version 1.0", RFC
+ 2246, January 1999.
+
+ [2] Kohl J. and C. Neuman, "The Kerberos Network Authentication
+ Service (V5)", RFC 1510, September 1993.
+
+9. Authors' Addresses
+
+ Ari Medvinsky
+ Excite
+ 555 Broadway
+ Redwood City, CA 94063
+
+ Phone: +1 650 569 2119
+ EMail: amedvins@excitecorp.com
+ http://www.excite.com
+
+
+ Matthew Hur
+ CyberSafe Corporation
+ 1605 NW Sammamish Road
+ Issaquah WA 98027-5378
+
+ Phone: +1 425 391 6000
+ EMail: matt.hur@cybersafe.com
+ http://www.cybersafe.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Medvinsky & Hur Standards Track [Page 6]
+
+RFC 2712 Addition of Kerberos Cipher Suites to TLS October 1999
+
+
+10. Full Copyright Statement
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Medvinsky & Hur Standards Track [Page 7]
+
diff --git a/standards/rfc2817.txt b/standards/rfc2817.txt
new file mode 100644
index 000000000..d7b7e703b
--- /dev/null
+++ b/standards/rfc2817.txt
@@ -0,0 +1,731 @@
+
+
+
+
+
+
+Network Working Group R. Khare
+Request for Comments: 2817 4K Associates / UC Irvine
+Updates: 2616 S. Lawrence
+Category: Standards Track Agranat Systems, Inc.
+ May 2000
+
+
+ Upgrading to TLS Within HTTP/1.1
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2000). All Rights Reserved.
+
+Abstract
+
+ This memo explains how to use the Upgrade mechanism in HTTP/1.1 to
+ initiate Transport Layer Security (TLS) over an existing TCP
+ connection. This allows unsecured and secured HTTP traffic to share
+ the same well known port (in this case, http: at 80 rather than
+ https: at 443). It also enables "virtual hosting", so a single HTTP +
+ TLS server can disambiguate traffic intended for several hostnames at
+ a single IP address.
+
+ Since HTTP/1.1 [1] defines Upgrade as a hop-by-hop mechanism, this
+ memo also documents the HTTP CONNECT method for establishing end-to-
+ end tunnels across HTTP proxies. Finally, this memo establishes new
+ IANA registries for public HTTP status codes, as well as public or
+ private Upgrade product tokens.
+
+ This memo does NOT affect the current definition of the 'https' URI
+ scheme, which already defines a separate namespace
+ (http://example.org/ and https://example.org/ are not equivalent).
+
+
+
+
+
+
+
+
+
+
+
+Khare & Lawrence Standards Track [Page 1]
+
+RFC 2817 HTTP Upgrade to TLS May 2000
+
+
+Table of Contents
+
+ 1. Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . 2
+ 2. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 3
+ 2.1 Requirements Terminology . . . . . . . . . . . . . . . . . . . 4
+ 3. Client Requested Upgrade to HTTP over TLS . . . . . . . . . . 4
+ 3.1 Optional Upgrade . . . . . . . . . . . . . . . . . . . . . . . 4
+ 3.2 Mandatory Upgrade . . . . . . . . . . . . . . . . . . . . . . 4
+ 3.3 Server Acceptance of Upgrade Request . . . . . . . . . . . . . 4
+ 4. Server Requested Upgrade to HTTP over TLS . . . . . . . . . . 5
+ 4.1 Optional Advertisement . . . . . . . . . . . . . . . . . . . . 5
+ 4.2 Mandatory Advertisement . . . . . . . . . . . . . . . . . . . 5
+ 5. Upgrade across Proxies . . . . . . . . . . . . . . . . . . . . 6
+ 5.1 Implications of Hop By Hop Upgrade . . . . . . . . . . . . . . 6
+ 5.2 Requesting a Tunnel with CONNECT . . . . . . . . . . . . . . . 6
+ 5.3 Establishing a Tunnel with CONNECT . . . . . . . . . . . . . . 7
+ 6. Rationale for the use of a 4xx (client error) Status Code . . 7
+ 7. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 8
+ 7.1 HTTP Status Code Registry . . . . . . . . . . . . . . . . . . 8
+ 7.2 HTTP Upgrade Token Registry . . . . . . . . . . . . . . . . . 8
+ 8. Security Considerations . . . . . . . . . . . . . . . . . . . 9
+ 8.1 Implications for the https: URI Scheme . . . . . . . . . . . . 10
+ 8.2 Security Considerations for CONNECT . . . . . . . . . . . . . 10
+ References . . . . . . . . . . . . . . . . . . . . . . . . . . 10
+ Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . 11
+ A. Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . 12
+ Full Copyright Statement . . . . . . . . . . . . . . . . . . . 13
+
+1. Motivation
+
+ The historical practice of deploying HTTP over SSL3 [3] has
+ distinguished the combination from HTTP alone by a unique URI scheme
+ and the TCP port number. The scheme 'http' meant the HTTP protocol
+ alone on port 80, while 'https' meant the HTTP protocol over SSL on
+ port 443. Parallel well-known port numbers have similarly been
+ requested -- and in some cases, granted -- to distinguish between
+ secured and unsecured use of other application protocols (e.g.
+ snews, ftps). This approach effectively halves the number of
+ available well known ports.
+
+ At the Washington DC IETF meeting in December 1997, the Applications
+ Area Directors and the IESG reaffirmed that the practice of issuing
+ parallel "secure" port numbers should be deprecated. The HTTP/1.1
+ Upgrade mechanism can apply Transport Layer Security [6] to an open
+ HTTP connection.
+
+
+
+
+
+
+Khare & Lawrence Standards Track [Page 2]
+
+RFC 2817 HTTP Upgrade to TLS May 2000
+
+
+ In the nearly two years since, there has been broad acceptance of the
+ concept behind this proposal, but little interest in implementing
+ alternatives to port 443 for generic Web browsing. In fact, nothing
+ in this memo affects the current interpretation of https: URIs.
+ However, new application protocols built atop HTTP, such as the
+ Internet Printing Protocol [7], call for just such a mechanism in
+ order to move ahead in the IETF standards process.
+
+ The Upgrade mechanism also solves the "virtual hosting" problem.
+ Rather than allocating multiple IP addresses to a single host, an
+ HTTP/1.1 server will use the Host: header to disambiguate the
+ intended web service. As HTTP/1.1 usage has grown more prevalent,
+ more ISPs are offering name-based virtual hosting, thus delaying IP
+ address space exhaustion.
+
+ TLS (and SSL) have been hobbled by the same limitation as earlier
+ versions of HTTP: the initial handshake does not specify the intended
+ hostname, relying exclusively on the IP address. Using a cleartext
+ HTTP/1.1 Upgrade: preamble to the TLS handshake -- choosing the
+ certificates based on the initial Host: header -- will allow ISPs to
+ provide secure name-based virtual hosting as well.
+
+2. Introduction
+
+ TLS, a.k.a., SSL (Secure Sockets Layer), establishes a private end-
+ to-end connection, optionally including strong mutual authentication,
+ using a variety of cryptosystems. Initially, a handshake phase uses
+ three subprotocols to set up a record layer, authenticate endpoints,
+ set parameters, as well as report errors. Then, there is an ongoing
+ layered record protocol that handles encryption, compression, and
+ reassembly for the remainder of the connection. The latter is
+ intended to be completely transparent. For example, there is no
+ dependency between TLS's record markers and or certificates and
+ HTTP/1.1's chunked encoding or authentication.
+
+ Either the client or server can use the HTTP/1.1 [1] Upgrade
+ mechanism (Section 14.42) to indicate that a TLS-secured connection
+ is desired or necessary. This memo defines the "TLS/1.0" Upgrade
+ token, and a new HTTP Status Code, "426 Upgrade Required".
+
+ Section 3 and Section 4 describe the operation of a directly
+ connected client and server. Intermediate proxies must establish an
+ end-to-end tunnel before applying those operations, as explained in
+ Section 5.
+
+
+
+
+
+
+
+Khare & Lawrence Standards Track [Page 3]
+
+RFC 2817 HTTP Upgrade to TLS May 2000
+
+
+2.1 Requirements Terminology
+
+ Keywords "MUST", "MUST NOT", "REQUIRED", "SHOULD", "SHOULD NOT" and
+ "MAY" that appear in this document are to be interpreted as described
+ in RFC 2119 [11].
+
+3. Client Requested Upgrade to HTTP over TLS
+
+ When the client sends an HTTP/1.1 request with an Upgrade header
+ field containing the token "TLS/1.0", it is requesting the server to
+ complete the current HTTP/1.1 request after switching to TLS/1.0.
+
+3.1 Optional Upgrade
+
+ A client MAY offer to switch to secured operation during any clear
+ HTTP request when an unsecured response would be acceptable:
+
+ GET http://example.bank.com/acct_stat.html?749394889300 HTTP/1.1
+ Host: example.bank.com
+ Upgrade: TLS/1.0
+ Connection: Upgrade
+
+ In this case, the server MAY respond to the clear HTTP operation
+ normally, OR switch to secured operation (as detailed in the next
+ section).
+
+ Note that HTTP/1.1 [1] specifies "the upgrade keyword MUST be
+ supplied within a Connection header field (section 14.10) whenever
+ Upgrade is present in an HTTP/1.1 message".
+
+3.2 Mandatory Upgrade
+
+ If an unsecured response would be unacceptable, a client MUST send an
+ OPTIONS request first to complete the switch to TLS/1.0 (if
+ possible).
+
+ OPTIONS * HTTP/1.1
+ Host: example.bank.com
+ Upgrade: TLS/1.0
+ Connection: Upgrade
+
+3.3 Server Acceptance of Upgrade Request
+
+ As specified in HTTP/1.1 [1], if the server is prepared to initiate
+ the TLS handshake, it MUST send the intermediate "101 Switching
+ Protocol" and MUST include an Upgrade response header specifying the
+ tokens of the protocol stack it is switching to:
+
+
+
+
+Khare & Lawrence Standards Track [Page 4]
+
+RFC 2817 HTTP Upgrade to TLS May 2000
+
+
+ HTTP/1.1 101 Switching Protocols
+ Upgrade: TLS/1.0, HTTP/1.1
+ Connection: Upgrade
+
+ Note that the protocol tokens listed in the Upgrade header of a 101
+ Switching Protocols response specify an ordered 'bottom-up' stack.
+
+ As specified in HTTP/1.1 [1], Section 10.1.2: "The server will
+ switch protocols to those defined by the response's Upgrade header
+ field immediately after the empty line which terminates the 101
+ response".
+
+ Once the TLS handshake completes successfully, the server MUST
+ continue with the response to the original request. Any TLS handshake
+ failure MUST lead to disconnection, per the TLS error alert
+ specification.
+
+4. Server Requested Upgrade to HTTP over TLS
+
+ The Upgrade response header field advertises possible protocol
+ upgrades a server MAY accept. In conjunction with the "426 Upgrade
+ Required" status code, a server can advertise the exact protocol
+ upgrade(s) that a client MUST accept to complete the request.
+
+4.1 Optional Advertisement
+
+ As specified in HTTP/1.1 [1], the server MAY include an Upgrade
+ header in any response other than 101 or 426 to indicate a
+ willingness to switch to any (combination) of the protocols listed.
+
+4.2 Mandatory Advertisement
+
+ A server MAY indicate that a client request can not be completed
+ without TLS using the "426 Upgrade Required" status code, which MUST
+ include an an Upgrade header field specifying the token of the
+ required TLS version.
+
+ HTTP/1.1 426 Upgrade Required
+ Upgrade: TLS/1.0, HTTP/1.1
+ Connection: Upgrade
+
+ The server SHOULD include a message body in the 426 response which
+ indicates in human readable form the reason for the error and
+ describes any alternative courses which may be available to the user.
+
+ Note that even if a client is willing to use TLS, it must use the
+ operations in Section 3 to proceed; the TLS handshake cannot begin
+ immediately after the 426 response.
+
+
+
+Khare & Lawrence Standards Track [Page 5]
+
+RFC 2817 HTTP Upgrade to TLS May 2000
+
+
+5. Upgrade across Proxies
+
+ As a hop-by-hop header, Upgrade is negotiated between each pair of
+ HTTP counterparties. If a User Agent sends a request with an Upgrade
+ header to a proxy, it is requesting a change to the protocol between
+ itself and the proxy, not an end-to-end change.
+
+ Since TLS, in particular, requires end-to-end connectivity to provide
+ authentication and prevent man-in-the-middle attacks, this memo
+ specifies the CONNECT method to establish a tunnel across proxies.
+
+ Once a tunnel is established, any of the operations in Section 3 can
+ be used to establish a TLS connection.
+
+5.1 Implications of Hop By Hop Upgrade
+
+ If an origin server receives an Upgrade header from a proxy and
+ responds with a 101 Switching Protocols response, it is changing the
+ protocol only on the connection between the proxy and itself.
+ Similarly, a proxy might return a 101 response to its client to
+ change the protocol on that connection independently of the protocols
+ it is using to communicate toward the origin server.
+
+ These scenarios also complicate diagnosis of a 426 response. Since
+ Upgrade is a hop-by-hop header, a proxy that does not recognize 426
+ might remove the accompanying Upgrade header and prevent the client
+ from determining the required protocol switch. If a client receives
+ a 426 status without an accompanying Upgrade header, it will need to
+ request an end to end tunnel connection as described in Section 5.2
+ and repeat the request in order to obtain the required upgrade
+ information.
+
+ This hop-by-hop definition of Upgrade was a deliberate choice. It
+ allows for incremental deployment on either side of proxies, and for
+ optimized protocols between cascaded proxies without the knowledge of
+ the parties that are not a part of the change.
+
+5.2 Requesting a Tunnel with CONNECT
+
+ A CONNECT method requests that a proxy establish a tunnel connection
+ on its behalf. The Request-URI portion of the Request-Line is always
+ an 'authority' as defined by URI Generic Syntax [2], which is to say
+ the host name and port number destination of the requested connection
+ separated by a colon:
+
+ CONNECT server.example.com:80 HTTP/1.1
+ Host: server.example.com:80
+
+
+
+
+Khare & Lawrence Standards Track [Page 6]
+
+RFC 2817 HTTP Upgrade to TLS May 2000
+
+
+ Other HTTP mechanisms can be used normally with the CONNECT method --
+ except end-to-end protocol Upgrade requests, of course, since the
+ tunnel must be established first.
+
+ For example, proxy authentication might be used to establish the
+ authority to create a tunnel:
+
+ CONNECT server.example.com:80 HTTP/1.1
+ Host: server.example.com:80
+ Proxy-Authorization: basic aGVsbG86d29ybGQ=
+
+ Like any other pipelined HTTP/1.1 request, data to be tunneled may be
+ sent immediately after the blank line. The usual caveats also apply:
+ data may be discarded if the eventual response is negative, and the
+ connection may be reset with no response if more than one TCP segment
+ is outstanding.
+
+5.3 Establishing a Tunnel with CONNECT
+
+ Any successful (2xx) response to a CONNECT request indicates that the
+ proxy has established a connection to the requested host and port,
+ and has switched to tunneling the current connection to that server
+ connection.
+
+ It may be the case that the proxy itself can only reach the requested
+ origin server through another proxy. In this case, the first proxy
+ SHOULD make a CONNECT request of that next proxy, requesting a tunnel
+ to the authority. A proxy MUST NOT respond with any 2xx status code
+ unless it has either a direct or tunnel connection established to the
+ authority.
+
+ An origin server which receives a CONNECT request for itself MAY
+ respond with a 2xx status code to indicate that a connection is
+ established.
+
+ If at any point either one of the peers gets disconnected, any
+ outstanding data that came from that peer will be passed to the other
+ one, and after that also the other connection will be terminated by
+ the proxy. If there is outstanding data to that peer undelivered,
+ that data will be discarded.
+
+6. Rationale for the use of a 4xx (client error) Status Code
+
+ Reliable, interoperable negotiation of Upgrade features requires an
+ unambiguous failure signal. The 426 Upgrade Required status code
+ allows a server to definitively state the precise protocol extensions
+ a given resource must be served with.
+
+
+
+
+Khare & Lawrence Standards Track [Page 7]
+
+RFC 2817 HTTP Upgrade to TLS May 2000
+
+
+ It might at first appear that the response should have been some form
+ of redirection (a 3xx code), by analogy to an old-style redirection
+ to an https: URI. User agents that do not understand Upgrade:
+ preclude this.
+
+ Suppose that a 3xx code had been assigned for "Upgrade Required"; a
+ user agent that did not recognize it would treat it as 300. It would
+ then properly look for a "Location" header in the response and
+ attempt to repeat the request at the URL in that header field. Since
+ it did not know to Upgrade to incorporate the TLS layer, it would at
+ best fail again at the new URL.
+
+7. IANA Considerations
+
+ IANA shall create registries for two name spaces, as described in BCP
+ 26 [10]:
+
+ o HTTP Status Codes
+ o HTTP Upgrade Tokens
+
+7.1 HTTP Status Code Registry
+
+ The HTTP Status Code Registry defines the name space for the Status-
+ Code token in the Status line of an HTTP response. The initial
+ values for this name space are those specified by:
+
+ 1. Draft Standard for HTTP/1.1 [1]
+ 2. Web Distributed Authoring and Versioning [4] [defines 420-424]
+ 3. WebDAV Advanced Collections [5] (Work in Progress) [defines 425]
+ 4. Section 6 [defines 426]
+
+ Values to be added to this name space SHOULD be subject to review in
+ the form of a standards track document within the IETF Applications
+ Area. Any such document SHOULD be traceable through statuses of
+ either 'Obsoletes' or 'Updates' to the Draft Standard for
+ HTTP/1.1 [1].
+
+7.2 HTTP Upgrade Token Registry
+
+ The HTTP Upgrade Token Registry defines the name space for product
+ tokens used to identify protocols in the Upgrade HTTP header field.
+ Each registered token should be associated with one or a set of
+ specifications, and with contact information.
+
+ The Draft Standard for HTTP/1.1 [1] specifies that these tokens obey
+ the production for 'product':
+
+
+
+
+
+Khare & Lawrence Standards Track [Page 8]
+
+RFC 2817 HTTP Upgrade to TLS May 2000
+
+
+ product = token ["/" product-version]
+ product-version = token
+
+ Registrations should be allowed on a First Come First Served basis as
+ described in BCP 26 [10]. These specifications need not be IETF
+ documents or be subject to IESG review, but should obey the following
+ rules:
+
+ 1. A token, once registered, stays registered forever.
+ 2. The registration MUST name a responsible party for the
+ registration.
+ 3. The registration MUST name a point of contact.
+ 4. The registration MAY name the documentation required for the
+ token.
+ 5. The responsible party MAY change the registration at any time.
+ The IANA will keep a record of all such changes, and make them
+ available upon request.
+ 6. The responsible party for the first registration of a "product"
+ token MUST approve later registrations of a "version" token
+ together with that "product" token before they can be registered.
+ 7. If absolutely required, the IESG MAY reassign the responsibility
+ for a token. This will normally only be used in the case when a
+ responsible party cannot be contacted.
+
+ This specification defines the protocol token "TLS/1.0" as the
+ identifier for the protocol specified by The TLS Protocol [6].
+
+ It is NOT required that specifications for upgrade tokens be made
+ publicly available, but the contact information for the registration
+ SHOULD be.
+
+8. Security Considerations
+
+ The potential for a man-in-the-middle attack (deleting the Upgrade
+ header) remains the same as current, mixed http/https practice:
+
+ o Removing the Upgrade header is similar to rewriting web pages to
+ change https:// links to http:// links.
+ o The risk is only present if the server is willing to vend such
+ information over both a secure and an insecure channel in the
+ first place.
+ o If the client knows for a fact that a server is TLS-compliant, it
+ can insist on it by only sending an Upgrade request with a no-op
+ method like OPTIONS.
+ o Finally, as the https: specification warns, "users should
+ carefully examine the certificate presented by the server to
+ determine if it meets their expectations".
+
+
+
+
+Khare & Lawrence Standards Track [Page 9]
+
+RFC 2817 HTTP Upgrade to TLS May 2000
+
+
+ Furthermore, for clients that do not explicitly try to invoke TLS,
+ servers can use the Upgrade header in any response other than 101 or
+ 426 to advertise TLS compliance. Since TLS compliance should be
+ considered a feature of the server and not the resource at hand, it
+ should be sufficient to send it once, and let clients cache that
+ fact.
+
+8.1 Implications for the https: URI Scheme
+
+ While nothing in this memo affects the definition of the 'https' URI
+ scheme, widespread adoption of this mechanism for HyperText content
+ could use 'http' to identify both secure and non-secure resources.
+
+ The choice of what security characteristics are required on the
+ connection is left to the client and server. This allows either
+ party to use any information available in making this determination.
+ For example, user agents may rely on user preference settings or
+ information about the security of the network such as 'TLS required
+ on all POST operations not on my local net', or servers may apply
+ resource access rules such as 'the FORM on this page must be served
+ and submitted using TLS'.
+
+8.2 Security Considerations for CONNECT
+
+ A generic TCP tunnel is fraught with security risks. First, such
+ authorization should be limited to a small number of known ports.
+ The Upgrade: mechanism defined here only requires onward tunneling at
+ port 80. Second, since tunneled data is opaque to the proxy, there
+ are additional risks to tunneling to other well-known or reserved
+ ports. A putative HTTP client CONNECTing to port 25 could relay spam
+ via SMTP, for example.
+
+References
+
+ [1] Fielding, R., Gettys, J., Mogul, J., Frystyk, H., Masinter, L.,
+ Leach, P. and T. Berners-Lee, "Hypertext Transfer Protocol --
+ HTTP/1.1", RFC 2616, June 1999.
+
+ [2] Berners-Lee, T., Fielding, R. and L. Masinter, "URI Generic
+ Syntax", RFC 2396, August 1998.
+
+ [3] Rescorla, E., "HTTP Over TLS", RFC 2818, May 2000.
+
+ [4] Goland, Y., Whitehead, E., Faizi, A., Carter, S. and D. Jensen,
+ "Web Distributed Authoring and Versioning", RFC 2518, February
+ 1999.
+
+
+
+
+
+Khare & Lawrence Standards Track [Page 10]
+
+RFC 2817 HTTP Upgrade to TLS May 2000
+
+
+ [5] Slein, J., Whitehead, E.J., et al., "WebDAV Advanced Collections
+ Protocol", Work In Progress.
+
+ [6] Dierks, T. and C. Allen, "The TLS Protocol", RFC 2246, January
+ 1999.
+
+ [7] Herriot, R., Butler, S., Moore, P. and R. Turner, "Internet
+ Printing Protocol/1.0: Encoding and Transport", RFC 2565, April
+ 1999.
+
+ [8] Luotonen, A., "Tunneling TCP based protocols through Web proxy
+ servers", Work In Progress. (Also available in: Luotonen, Ari.
+ Web Proxy Servers, Prentice-Hall, 1997 ISBN:0136806120.)
+
+ [9] Rose, M., "Writing I-Ds and RFCs using XML", RFC 2629, June
+ 1999.
+
+ [10] Narten, T. and H. Alvestrand, "Guidelines for Writing an IANA
+ Considerations Section in RFCs", BCP 26, RFC 2434, October 1998.
+
+ [11] Bradner, S., "Key words for use in RFCs to Indicate Requirement
+ Levels", BCP 14, RFC 2119, March 1997.
+
+Authors' Addresses
+
+ Rohit Khare
+ 4K Associates / UC Irvine
+ 3207 Palo Verde
+ Irvine, CA 92612
+ US
+
+ Phone: +1 626 806 7574
+ EMail: rohit@4K-associates.com
+ URI: http://www.4K-associates.com/
+
+
+ Scott Lawrence
+ Agranat Systems, Inc.
+ 5 Clocktower Place
+ Suite 400
+ Maynard, MA 01754
+ US
+
+ Phone: +1 978 461 0888
+ EMail: lawrence@agranat.com
+ URI: http://www.agranat.com/
+
+
+
+
+
+Khare & Lawrence Standards Track [Page 11]
+
+RFC 2817 HTTP Upgrade to TLS May 2000
+
+
+Appendix A. Acknowledgments
+
+ The CONNECT method was originally described in a Work in Progress
+ titled, "Tunneling TCP based protocols through Web proxy servers",
+ [8] by Ari Luotonen of Netscape Communications Corporation. It was
+ widely implemented by HTTP proxies, but was never made a part of any
+ IETF Standards Track document. The method name CONNECT was reserved,
+ but not defined in [1].
+
+ The definition provided here is derived directly from that earlier
+ memo, with some editorial changes and conformance to the stylistic
+ conventions since established in other HTTP specifications.
+
+ Additional Thanks to:
+
+ o Paul Hoffman for his work on the STARTTLS command extension for
+ ESMTP.
+ o Roy Fielding for assistance with the rationale behind Upgrade:
+ and its interaction with OPTIONS.
+ o Eric Rescorla for his work on standardizing the existing https:
+ practice to compare with.
+ o Marshall Rose, for the xml2rfc document type description and tools
+ [9].
+ o Jim Whitehead, for sorting out the current range of available HTTP
+ status codes.
+ o Henrik Frystyk Nielsen, whose work on the Mandatory extension
+ mechanism pointed out a hop-by-hop Upgrade still requires
+ tunneling.
+ o Harald Alvestrand for improvements to the token registration
+ rules.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Khare & Lawrence Standards Track [Page 12]
+
+RFC 2817 HTTP Upgrade to TLS May 2000
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (2000). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Khare & Lawrence Standards Track [Page 13]
+
diff --git a/standards/rfc2818.txt b/standards/rfc2818.txt
new file mode 100644
index 000000000..219a1c427
--- /dev/null
+++ b/standards/rfc2818.txt
@@ -0,0 +1,395 @@
+
+
+
+
+
+
+Network Working Group E. Rescorla
+Request for Comments: 2818 RTFM, Inc.
+Category: Informational May 2000
+
+
+ HTTP Over TLS
+
+Status of this Memo
+
+ This memo provides information for the Internet community. It does
+ not specify an Internet standard of any kind. Distribution of this
+ memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2000). All Rights Reserved.
+
+Abstract
+
+ This memo describes how to use TLS to secure HTTP connections over
+ the Internet. Current practice is to layer HTTP over SSL (the
+ predecessor to TLS), distinguishing secured traffic from insecure
+ traffic by the use of a different server port. This document
+ documents that practice using TLS. A companion document describes a
+ method for using HTTP/TLS over the same port as normal HTTP
+ [RFC2817].
+
+Table of Contents
+
+ 1. Introduction . . . . . . . . . . . . . . . . . . . . . . 2
+ 1.1. Requirements Terminology . . . . . . . . . . . . . . . 2
+ 2. HTTP Over TLS . . . . . . . . . . . . . . . . . . . . . . 2
+ 2.1. Connection Initiation . . . . . . . . . . . . . . . . . 2
+ 2.2. Connection Closure . . . . . . . . . . . . . . . . . . 2
+ 2.2.1. Client Behavior . . . . . . . . . . . . . . . . . . . 3
+ 2.2.2. Server Behavior . . . . . . . . . . . . . . . . . . . 3
+ 2.3. Port Number . . . . . . . . . . . . . . . . . . . . . . 4
+ 2.4. URI Format . . . . . . . . . . . . . . . . . . . . . . 4
+ 3. Endpoint Identification . . . . . . . . . . . . . . . . . 4
+ 3.1. Server Identity . . . . . . . . . . . . . . . . . . . . 4
+ 3.2. Client Identity . . . . . . . . . . . . . . . . . . . . 5
+ References . . . . . . . . . . . . . . . . . . . . . . . . . 6
+ Security Considerations . . . . . . . . . . . . . . . . . . 6
+ Author's Address . . . . . . . . . . . . . . . . . . . . . . 6
+ Full Copyright Statement . . . . . . . . . . . . . . . . . . 7
+
+
+
+
+
+
+Rescorla Informational [Page 1]
+
+RFC 2818 HTTP Over TLS May 2000
+
+
+1. Introduction
+
+ HTTP [RFC2616] was originally used in the clear on the Internet.
+ However, increased use of HTTP for sensitive applications has
+ required security measures. SSL, and its successor TLS [RFC2246] were
+ designed to provide channel-oriented security. This document
+ describes how to use HTTP over TLS.
+
+1.1. Requirements Terminology
+
+ Keywords "MUST", "MUST NOT", "REQUIRED", "SHOULD", "SHOULD NOT" and
+ "MAY" that appear in this document are to be interpreted as described
+ in [RFC2119].
+
+2. HTTP Over TLS
+
+ Conceptually, HTTP/TLS is very simple. Simply use HTTP over TLS
+ precisely as you would use HTTP over TCP.
+
+2.1. Connection Initiation
+
+ The agent acting as the HTTP client should also act as the TLS
+ client. It should initiate a connection to the server on the
+ appropriate port and then send the TLS ClientHello to begin the TLS
+ handshake. When the TLS handshake has finished. The client may then
+ initiate the first HTTP request. All HTTP data MUST be sent as TLS
+ "application data". Normal HTTP behavior, including retained
+ connections should be followed.
+
+2.2. Connection Closure
+
+ TLS provides a facility for secure connection closure. When a valid
+ closure alert is received, an implementation can be assured that no
+ further data will be received on that connection. TLS
+ implementations MUST initiate an exchange of closure alerts before
+ closing a connection. A TLS implementation MAY, after sending a
+ closure alert, close the connection without waiting for the peer to
+ send its closure alert, generating an "incomplete close". Note that
+ an implementation which does this MAY choose to reuse the session.
+ This SHOULD only be done when the application knows (typically
+ through detecting HTTP message boundaries) that it has received all
+ the message data that it cares about.
+
+ As specified in [RFC2246], any implementation which receives a
+ connection close without first receiving a valid closure alert (a
+ "premature close") MUST NOT reuse that session. Note that a
+ premature close does not call into question the security of the data
+ already received, but simply indicates that subsequent data might
+
+
+
+Rescorla Informational [Page 2]
+
+RFC 2818 HTTP Over TLS May 2000
+
+
+ have been truncated. Because TLS is oblivious to HTTP
+ request/response boundaries, it is necessary to examine the HTTP data
+ itself (specifically the Content-Length header) to determine whether
+ the truncation occurred inside a message or between messages.
+
+2.2.1. Client Behavior
+
+ Because HTTP uses connection closure to signal end of server data,
+ client implementations MUST treat any premature closes as errors and
+ the data received as potentially truncated. While in some cases the
+ HTTP protocol allows the client to find out whether truncation took
+ place so that, if it received the complete reply, it may tolerate
+ such errors following the principle to "[be] strict when sending and
+ tolerant when receiving" [RFC1958], often truncation does not show in
+ the HTTP protocol data; two cases in particular deserve special note:
+
+ A HTTP response without a Content-Length header. Since data length
+ in this situation is signalled by connection close a premature
+ close generated by the server cannot be distinguished from a
+ spurious close generated by an attacker.
+
+ A HTTP response with a valid Content-Length header closed before
+ all data has been read. Because TLS does not provide document
+ oriented protection, it is impossible to determine whether the
+ server has miscomputed the Content-Length or an attacker has
+ truncated the connection.
+
+ There is one exception to the above rule. When encountering a
+ premature close, a client SHOULD treat as completed all requests for
+ which it has received as much data as specified in the Content-Length
+ header.
+
+ A client detecting an incomplete close SHOULD recover gracefully. It
+ MAY resume a TLS session closed in this fashion.
+
+ Clients MUST send a closure alert before closing the connection.
+ Clients which are unprepared to receive any more data MAY choose not
+ to wait for the server's closure alert and simply close the
+ connection, thus generating an incomplete close on the server side.
+
+2.2.2. Server Behavior
+
+ RFC 2616 permits an HTTP client to close the connection at any time,
+ and requires servers to recover gracefully. In particular, servers
+ SHOULD be prepared to receive an incomplete close from the client,
+ since the client can often determine when the end of server data is.
+ Servers SHOULD be willing to resume TLS sessions closed in this
+ fashion.
+
+
+
+Rescorla Informational [Page 3]
+
+RFC 2818 HTTP Over TLS May 2000
+
+
+ Implementation note: In HTTP implementations which do not use
+ persistent connections, the server ordinarily expects to be able to
+ signal end of data by closing the connection. When Content-Length is
+ used, however, the client may have already sent the closure alert and
+ dropped the connection.
+
+ Servers MUST attempt to initiate an exchange of closure alerts with
+ the client before closing the connection. Servers MAY close the
+ connection after sending the closure alert, thus generating an
+ incomplete close on the client side.
+
+2.3. Port Number
+
+ The first data that an HTTP server expects to receive from the client
+ is the Request-Line production. The first data that a TLS server (and
+ hence an HTTP/TLS server) expects to receive is the ClientHello.
+ Consequently, common practice has been to run HTTP/TLS over a
+ separate port in order to distinguish which protocol is being used.
+ When HTTP/TLS is being run over a TCP/IP connection, the default port
+ is 443. This does not preclude HTTP/TLS from being run over another
+ transport. TLS only presumes a reliable connection-oriented data
+ stream.
+
+2.4. URI Format
+
+ HTTP/TLS is differentiated from HTTP URIs by using the 'https'
+ protocol identifier in place of the 'http' protocol identifier. An
+ example URI specifying HTTP/TLS is:
+
+ https://www.example.com/~smith/home.html
+
+3. Endpoint Identification
+
+3.1. Server Identity
+
+ In general, HTTP/TLS requests are generated by dereferencing a URI.
+ As a consequence, the hostname for the server is known to the client.
+ If the hostname is available, the client MUST check it against the
+ server's identity as presented in the server's Certificate message,
+ in order to prevent man-in-the-middle attacks.
+
+ If the client has external information as to the expected identity of
+ the server, the hostname check MAY be omitted. (For instance, a
+ client may be connecting to a machine whose address and hostname are
+ dynamic but the client knows the certificate that the server will
+ present.) In such cases, it is important to narrow the scope of
+ acceptable certificates as much as possible in order to prevent man
+
+
+
+
+Rescorla Informational [Page 4]
+
+RFC 2818 HTTP Over TLS May 2000
+
+
+ in the middle attacks. In special cases, it may be appropriate for
+ the client to simply ignore the server's identity, but it must be
+ understood that this leaves the connection open to active attack.
+
+ If a subjectAltName extension of type dNSName is present, that MUST
+ be used as the identity. Otherwise, the (most specific) Common Name
+ field in the Subject field of the certificate MUST be used. Although
+ the use of the Common Name is existing practice, it is deprecated and
+ Certification Authorities are encouraged to use the dNSName instead.
+
+ Matching is performed using the matching rules specified by
+ [RFC2459]. If more than one identity of a given type is present in
+ the certificate (e.g., more than one dNSName name, a match in any one
+ of the set is considered acceptable.) Names may contain the wildcard
+ character * which is considered to match any single domain name
+ component or component fragment. E.g., *.a.com matches foo.a.com but
+ not bar.foo.a.com. f*.com matches foo.com but not bar.com.
+
+ In some cases, the URI is specified as an IP address rather than a
+ hostname. In this case, the iPAddress subjectAltName must be present
+ in the certificate and must exactly match the IP in the URI.
+
+ If the hostname does not match the identity in the certificate, user
+ oriented clients MUST either notify the user (clients MAY give the
+ user the opportunity to continue with the connection in any case) or
+ terminate the connection with a bad certificate error. Automated
+ clients MUST log the error to an appropriate audit log (if available)
+ and SHOULD terminate the connection (with a bad certificate error).
+ Automated clients MAY provide a configuration setting that disables
+ this check, but MUST provide a setting which enables it.
+
+ Note that in many cases the URI itself comes from an untrusted
+ source. The above-described check provides no protection against
+ attacks where this source is compromised. For example, if the URI was
+ obtained by clicking on an HTML page which was itself obtained
+ without using HTTP/TLS, a man in the middle could have replaced the
+ URI. In order to prevent this form of attack, users should carefully
+ examine the certificate presented by the server to determine if it
+ meets their expectations.
+
+3.2. Client Identity
+
+ Typically, the server has no external knowledge of what the client's
+ identity ought to be and so checks (other than that the client has a
+ certificate chain rooted in an appropriate CA) are not possible. If a
+ server has such knowledge (typically from some source external to
+ HTTP or TLS) it SHOULD check the identity as described above.
+
+
+
+
+Rescorla Informational [Page 5]
+
+RFC 2818 HTTP Over TLS May 2000
+
+
+References
+
+ [RFC2459] Housley, R., Ford, W., Polk, W. and D. Solo, "Internet
+ Public Key Infrastructure: Part I: X.509 Certificate and
+ CRL Profile", RFC 2459, January 1999.
+
+ [RFC2616] Fielding, R., Gettys, J., Mogul, J., Frystyk, H., Masinter,
+ L., Leach, P. and T. Berners-Lee, "Hypertext Transfer
+ Protocol, HTTP/1.1", RFC 2616, June 1999.
+
+ [RFC2119] Bradner, S., "Key Words for use in RFCs to indicate
+ Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+ [RFC2246] Dierks, T. and C. Allen, "The TLS Protocol", RFC 2246,
+ January 1999.
+
+ [RFC2817] Khare, R. and S. Lawrence, "Upgrading to TLS Within
+ HTTP/1.1", RFC 2817, May 2000.
+
+Security Considerations
+
+ This entire document is about security.
+
+Author's Address
+
+ Eric Rescorla
+ RTFM, Inc.
+ 30 Newell Road, #16
+ East Palo Alto, CA 94303
+
+ Phone: (650) 328-8631
+ EMail: ekr@rtfm.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Rescorla Informational [Page 6]
+
+RFC 2818 HTTP Over TLS May 2000
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (2000). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Rescorla Informational [Page 7]
+
diff --git a/standards/rfc2821.txt b/standards/rfc2821.txt
new file mode 100644
index 000000000..0eac91188
--- /dev/null
+++ b/standards/rfc2821.txt
@@ -0,0 +1,4427 @@
+
+
+
+
+
+
+Network Working Group J. Klensin, Editor
+Request for Comments: 2821 AT&T Laboratories
+Obsoletes: 821, 974, 1869 April 2001
+Updates: 1123
+Category: Standards Track
+
+
+ Simple Mail Transfer Protocol
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2001). All Rights Reserved.
+
+Abstract
+
+ This document is a self-contained specification of the basic protocol
+ for the Internet electronic mail transport. It consolidates, updates
+ and clarifies, but doesn't add new or change existing functionality
+ of the following:
+
+ - the original SMTP (Simple Mail Transfer Protocol) specification of
+ RFC 821 [30],
+
+ - domain name system requirements and implications for mail
+ transport from RFC 1035 [22] and RFC 974 [27],
+
+ - the clarifications and applicability statements in RFC 1123 [2],
+ and
+
+ - material drawn from the SMTP Extension mechanisms [19].
+
+ It obsoletes RFC 821, RFC 974, and updates RFC 1123 (replaces the
+ mail transport materials of RFC 1123). However, RFC 821 specifies
+ some features that were not in significant use in the Internet by the
+ mid-1990s and (in appendices) some additional transport models.
+ Those sections are omitted here in the interest of clarity and
+ brevity; readers needing them should refer to RFC 821.
+
+
+
+
+
+
+Klensin Standards Track [Page 1]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ It also includes some additional material from RFC 1123 that required
+ amplification. This material has been identified in multiple ways,
+ mostly by tracking flaming on various lists and newsgroups and
+ problems of unusual readings or interpretations that have appeared as
+ the SMTP extensions have been deployed. Where this specification
+ moves beyond consolidation and actually differs from earlier
+ documents, it supersedes them technically as well as textually.
+
+ Although SMTP was designed as a mail transport and delivery protocol,
+ this specification also contains information that is important to its
+ use as a 'mail submission' protocol, as recommended for POP [3, 26]
+ and IMAP [6]. Additional submission issues are discussed in RFC 2476
+ [15].
+
+ Section 2.3 provides definitions of terms specific to this document.
+ Except when the historical terminology is necessary for clarity, this
+ document uses the current 'client' and 'server' terminology to
+ identify the sending and receiving SMTP processes, respectively.
+
+ A companion document [32] discusses message headers, message bodies
+ and formats and structures for them, and their relationship.
+
+Table of Contents
+
+ 1. Introduction .................................................. 4
+ 2. The SMTP Model ................................................ 5
+ 2.1 Basic Structure .............................................. 5
+ 2.2 The Extension Model .......................................... 7
+ 2.2.1 Background ................................................. 7
+ 2.2.2 Definition and Registration of Extensions .................. 8
+ 2.3 Terminology .................................................. 9
+ 2.3.1 Mail Objects ............................................... 10
+ 2.3.2 Senders and Receivers ...................................... 10
+ 2.3.3 Mail Agents and Message Stores ............................. 10
+ 2.3.4 Host ....................................................... 11
+ 2.3.5 Domain ..................................................... 11
+ 2.3.6 Buffer and State Table ..................................... 11
+ 2.3.7 Lines ...................................................... 12
+ 2.3.8 Originator, Delivery, Relay, and Gateway Systems ........... 12
+ 2.3.9 Message Content and Mail Data .............................. 13
+ 2.3.10 Mailbox and Address ....................................... 13
+ 2.3.11 Reply ..................................................... 13
+ 2.4 General Syntax Principles and Transaction Model .............. 13
+ 3. The SMTP Procedures: An Overview .............................. 15
+ 3.1 Session Initiation ........................................... 15
+ 3.2 Client Initiation ............................................ 16
+ 3.3 Mail Transactions ............................................ 16
+ 3.4 Forwarding for Address Correction or Updating ................ 19
+
+
+
+Klensin Standards Track [Page 2]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ 3.5 Commands for Debugging Addresses ............................. 20
+ 3.5.1 Overview ................................................... 20
+ 3.5.2 VRFY Normal Response ....................................... 22
+ 3.5.3 Meaning of VRFY or EXPN Success Response ................... 22
+ 3.5.4 Semantics and Applications of EXPN ......................... 23
+ 3.6 Domains ...................................................... 23
+ 3.7 Relaying ..................................................... 24
+ 3.8 Mail Gatewaying .............................................. 25
+ 3.8.1 Header Fields in Gatewaying ................................ 26
+ 3.8.2 Received Lines in Gatewaying ............................... 26
+ 3.8.3 Addresses in Gatewaying .................................... 26
+ 3.8.4 Other Header Fields in Gatewaying .......................... 27
+ 3.8.5 Envelopes in Gatewaying .................................... 27
+ 3.9 Terminating Sessions and Connections ......................... 27
+ 3.10 Mailing Lists and Aliases ................................... 28
+ 3.10.1 Alias ..................................................... 28
+ 3.10.2 List ...................................................... 28
+ 4. The SMTP Specifications ....................................... 29
+ 4.1 SMTP Commands ................................................ 29
+ 4.1.1 Command Semantics and Syntax ............................... 29
+ 4.1.1.1 Extended HELLO (EHLO) or HELLO (HELO) ................... 29
+ 4.1.1.2 MAIL (MAIL) .............................................. 31
+ 4.1.1.3 RECIPIENT (RCPT) ......................................... 31
+ 4.1.1.4 DATA (DATA) .............................................. 33
+ 4.1.1.5 RESET (RSET) ............................................. 34
+ 4.1.1.6 VERIFY (VRFY) ............................................ 35
+ 4.1.1.7 EXPAND (EXPN) ............................................ 35
+ 4.1.1.8 HELP (HELP) .............................................. 35
+ 4.1.1.9 NOOP (NOOP) .............................................. 35
+ 4.1.1.10 QUIT (QUIT) ............................................. 36
+ 4.1.2 Command Argument Syntax .................................... 36
+ 4.1.3 Address Literals ........................................... 38
+ 4.1.4 Order of Commands .......................................... 39
+ 4.1.5 Private-use Commands ....................................... 40
+ 4.2 SMTP Replies ................................................ 40
+ 4.2.1 Reply Code Severities and Theory ........................... 42
+ 4.2.2 Reply Codes by Function Groups ............................. 44
+ 4.2.3 Reply Codes in Numeric Order .............................. 45
+ 4.2.4 Reply Code 502 ............................................. 46
+ 4.2.5 Reply Codes After DATA and the Subsequent <CRLF>.<CRLF> .... 46
+ 4.3 Sequencing of Commands and Replies ........................... 47
+ 4.3.1 Sequencing Overview ........................................ 47
+ 4.3.2 Command-Reply Sequences .................................... 48
+ 4.4 Trace Information ............................................ 49
+ 4.5 Additional Implementation Issues ............................. 53
+ 4.5.1 Minimum Implementation ..................................... 53
+ 4.5.2 Transparency ............................................... 53
+ 4.5.3 Sizes and Timeouts ......................................... 54
+
+
+
+Klensin Standards Track [Page 3]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ 4.5.3.1 Size limits and minimums ................................. 54
+ 4.5.3.2 Timeouts ................................................. 56
+ 4.5.4 Retry Strategies ........................................... 57
+ 4.5.4.1 Sending Strategy ......................................... 58
+ 4.5.4.2 Receiving Strategy ....................................... 59
+ 4.5.5 Messages with a null reverse-path .......................... 59
+ 5. Address Resolution and Mail Handling .......................... 60
+ 6. Problem Detection and Handling ................................ 62
+ 6.1 Reliable Delivery and Replies by Email ....................... 62
+ 6.2 Loop Detection ............................................... 63
+ 6.3 Compensating for Irregularities .............................. 63
+ 7. Security Considerations ....................................... 64
+ 7.1 Mail Security and Spoofing ................................... 64
+ 7.2 "Blind" Copies ............................................... 65
+ 7.3 VRFY, EXPN, and Security ..................................... 65
+ 7.4 Information Disclosure in Announcements ...................... 66
+ 7.5 Information Disclosure in Trace Fields ....................... 66
+ 7.6 Information Disclosure in Message Forwarding ................. 67
+ 7.7 Scope of Operation of SMTP Servers ........................... 67
+ 8. IANA Considerations ........................................... 67
+ 9. References .................................................... 68
+ 10. Editor's Address ............................................. 70
+ 11. Acknowledgments .............................................. 70
+ Appendices ....................................................... 71
+ A. TCP Transport Service ......................................... 71
+ B. Generating SMTP Commands from RFC 822 Headers ................. 71
+ C. Source Routes ................................................. 72
+ D. Scenarios ..................................................... 73
+ E. Other Gateway Issues .......................................... 76
+ F. Deprecated Features of RFC 821 ................................ 76
+ Full Copyright Statement ......................................... 79
+
+1. Introduction
+
+ The objective of the Simple Mail Transfer Protocol (SMTP) is to
+ transfer mail reliably and efficiently.
+
+ SMTP is independent of the particular transmission subsystem and
+ requires only a reliable ordered data stream channel. While this
+ document specifically discusses transport over TCP, other transports
+ are possible. Appendices to RFC 821 describe some of them.
+
+ An important feature of SMTP is its capability to transport mail
+ across networks, usually referred to as "SMTP mail relaying" (see
+ section 3.8). A network consists of the mutually-TCP-accessible
+ hosts on the public Internet, the mutually-TCP-accessible hosts on a
+ firewall-isolated TCP/IP Intranet, or hosts in some other LAN or WAN
+ environment utilizing a non-TCP transport-level protocol. Using
+
+
+
+Klensin Standards Track [Page 4]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ SMTP, a process can transfer mail to another process on the same
+ network or to some other network via a relay or gateway process
+ accessible to both networks.
+
+ In this way, a mail message may pass through a number of intermediate
+ relay or gateway hosts on its path from sender to ultimate recipient.
+ The Mail eXchanger mechanisms of the domain name system [22, 27] (and
+ section 5 of this document) are used to identify the appropriate
+ next-hop destination for a message being transported.
+
+2. The SMTP Model
+
+2.1 Basic Structure
+
+ The SMTP design can be pictured as:
+
+ +----------+ +----------+
+ +------+ | | | |
+ | User |<-->| | SMTP | |
+ +------+ | Client- |Commands/Replies| Server- |
+ +------+ | SMTP |<-------------->| SMTP | +------+
+ | File |<-->| | and Mail | |<-->| File |
+ |System| | | | | |System|
+ +------+ +----------+ +----------+ +------+
+ SMTP client SMTP server
+
+ When an SMTP client has a message to transmit, it establishes a two-
+ way transmission channel to an SMTP server. The responsibility of an
+ SMTP client is to transfer mail messages to one or more SMTP servers,
+ or report its failure to do so.
+
+ The means by which a mail message is presented to an SMTP client, and
+ how that client determines the domain name(s) to which mail messages
+ are to be transferred is a local matter, and is not addressed by this
+ document. In some cases, the domain name(s) transferred to, or
+ determined by, an SMTP client will identify the final destination(s)
+ of the mail message. In other cases, common with SMTP clients
+ associated with implementations of the POP [3, 26] or IMAP [6]
+ protocols, or when the SMTP client is inside an isolated transport
+ service environment, the domain name determined will identify an
+ intermediate destination through which all mail messages are to be
+ relayed. SMTP clients that transfer all traffic, regardless of the
+ target domain names associated with the individual messages, or that
+ do not maintain queues for retrying message transmissions that
+ initially cannot be completed, may otherwise conform to this
+ specification but are not considered fully-capable. Fully-capable
+ SMTP implementations, including the relays used by these less capable
+
+
+
+
+Klensin Standards Track [Page 5]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ ones, and their destinations, are expected to support all of the
+ queuing, retrying, and alternate address functions discussed in this
+ specification.
+
+ The means by which an SMTP client, once it has determined a target
+ domain name, determines the identity of an SMTP server to which a
+ copy of a message is to be transferred, and then performs that
+ transfer, is covered by this document. To effect a mail transfer to
+ an SMTP server, an SMTP client establishes a two-way transmission
+ channel to that SMTP server. An SMTP client determines the address
+ of an appropriate host running an SMTP server by resolving a
+ destination domain name to either an intermediate Mail eXchanger host
+ or a final target host.
+
+ An SMTP server may be either the ultimate destination or an
+ intermediate "relay" (that is, it may assume the role of an SMTP
+ client after receiving the message) or "gateway" (that is, it may
+ transport the message further using some protocol other than SMTP).
+ SMTP commands are generated by the SMTP client and sent to the SMTP
+ server. SMTP replies are sent from the SMTP server to the SMTP
+ client in response to the commands.
+
+ In other words, message transfer can occur in a single connection
+ between the original SMTP-sender and the final SMTP-recipient, or can
+ occur in a series of hops through intermediary systems. In either
+ case, a formal handoff of responsibility for the message occurs: the
+ protocol requires that a server accept responsibility for either
+ delivering a message or properly reporting the failure to do so.
+
+ Once the transmission channel is established and initial handshaking
+ completed, the SMTP client normally initiates a mail transaction.
+ Such a transaction consists of a series of commands to specify the
+ originator and destination of the mail and transmission of the
+ message content (including any headers or other structure) itself.
+ When the same message is sent to multiple recipients, this protocol
+ encourages the transmission of only one copy of the data for all
+ recipients at the same destination (or intermediate relay) host.
+
+ The server responds to each command with a reply; replies may
+ indicate that the command was accepted, that additional commands are
+ expected, or that a temporary or permanent error condition exists.
+ Commands specifying the sender or recipients may include server-
+ permitted SMTP service extension requests as discussed in section
+ 2.2. The dialog is purposely lock-step, one-at-a-time, although this
+ can be modified by mutually-agreed extension requests such as command
+ pipelining [13].
+
+
+
+
+
+Klensin Standards Track [Page 6]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ Once a given mail message has been transmitted, the client may either
+ request that the connection be shut down or may initiate other mail
+ transactions. In addition, an SMTP client may use a connection to an
+ SMTP server for ancillary services such as verification of email
+ addresses or retrieval of mailing list subscriber addresses.
+
+ As suggested above, this protocol provides mechanisms for the
+ transmission of mail. This transmission normally occurs directly
+ from the sending user's host to the receiving user's host when the
+ two hosts are connected to the same transport service. When they are
+ not connected to the same transport service, transmission occurs via
+ one or more relay SMTP servers. An intermediate host that acts as
+ either an SMTP relay or as a gateway into some other transmission
+ environment is usually selected through the use of the domain name
+ service (DNS) Mail eXchanger mechanism.
+
+ Usually, intermediate hosts are determined via the DNS MX record, not
+ by explicit "source" routing (see section 5 and appendices C and
+ F.2).
+
+2.2 The Extension Model
+
+2.2.1 Background
+
+ In an effort that started in 1990, approximately a decade after RFC
+ 821 was completed, the protocol was modified with a "service
+ extensions" model that permits the client and server to agree to
+ utilize shared functionality beyond the original SMTP requirements.
+ The SMTP extension mechanism defines a means whereby an extended SMTP
+ client and server may recognize each other, and the server can inform
+ the client as to the service extensions that it supports.
+
+ Contemporary SMTP implementations MUST support the basic extension
+ mechanisms. For instance, servers MUST support the EHLO command even
+ if they do not implement any specific extensions and clients SHOULD
+ preferentially utilize EHLO rather than HELO. (However, for
+ compatibility with older conforming implementations, SMTP clients and
+ servers MUST support the original HELO mechanisms as a fallback.)
+ Unless the different characteristics of HELO must be identified for
+ interoperability purposes, this document discusses only EHLO.
+
+ SMTP is widely deployed and high-quality implementations have proven
+ to be very robust. However, the Internet community now considers
+ some services to be important that were not anticipated when the
+ protocol was first designed. If support for those services is to be
+ added, it must be done in a way that permits older implementations to
+ continue working acceptably. The extension framework consists of:
+
+
+
+
+Klensin Standards Track [Page 7]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ - The SMTP command EHLO, superseding the earlier HELO,
+
+ - a registry of SMTP service extensions,
+
+ - additional parameters to the SMTP MAIL and RCPT commands, and
+
+ - optional replacements for commands defined in this protocol, such
+ as for DATA in non-ASCII transmissions [33].
+
+ SMTP's strength comes primarily from its simplicity. Experience with
+ many protocols has shown that protocols with few options tend towards
+ ubiquity, whereas protocols with many options tend towards obscurity.
+
+ Each and every extension, regardless of its benefits, must be
+ carefully scrutinized with respect to its implementation, deployment,
+ and interoperability costs. In many cases, the cost of extending the
+ SMTP service will likely outweigh the benefit.
+
+2.2.2 Definition and Registration of Extensions
+
+ The IANA maintains a registry of SMTP service extensions. A
+ corresponding EHLO keyword value is associated with each extension.
+ Each service extension registered with the IANA must be defined in a
+ formal standards-track or IESG-approved experimental protocol
+ document. The definition must include:
+
+ - the textual name of the SMTP service extension;
+
+ - the EHLO keyword value associated with the extension;
+
+ - the syntax and possible values of parameters associated with the
+ EHLO keyword value;
+
+ - any additional SMTP verbs associated with the extension
+ (additional verbs will usually be, but are not required to be, the
+ same as the EHLO keyword value);
+
+ - any new parameters the extension associates with the MAIL or RCPT
+ verbs;
+
+ - a description of how support for the extension affects the
+ behavior of a server and client SMTP; and,
+
+ - the increment by which the extension is increasing the maximum
+ length of the commands MAIL and/or RCPT, over that specified in
+ this standard.
+
+
+
+
+
+Klensin Standards Track [Page 8]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ In addition, any EHLO keyword value starting with an upper or lower
+ case "X" refers to a local SMTP service extension used exclusively
+ through bilateral agreement. Keywords beginning with "X" MUST NOT be
+ used in a registered service extension. Conversely, keyword values
+ presented in the EHLO response that do not begin with "X" MUST
+ correspond to a standard, standards-track, or IESG-approved
+ experimental SMTP service extension registered with IANA. A
+ conforming server MUST NOT offer non-"X"-prefixed keyword values that
+ are not described in a registered extension.
+
+ Additional verbs and parameter names are bound by the same rules as
+ EHLO keywords; specifically, verbs beginning with "X" are local
+ extensions that may not be registered or standardized. Conversely,
+ verbs not beginning with "X" must always be registered.
+
+2.3 Terminology
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+ document are to be interpreted as described below.
+
+ 1. MUST This word, or the terms "REQUIRED" or "SHALL", mean that
+ the definition is an absolute requirement of the specification.
+
+ 2. MUST NOT This phrase, or the phrase "SHALL NOT", mean that the
+ definition is an absolute prohibition of the specification.
+
+ 3. SHOULD This word, or the adjective "RECOMMENDED", mean that
+ there may exist valid reasons in particular circumstances to
+ ignore a particular item, but the full implications must be
+ understood and carefully weighed before choosing a different
+ course.
+
+ 4. SHOULD NOT This phrase, or the phrase "NOT RECOMMENDED" mean
+ that there may exist valid reasons in particular circumstances
+ when the particular behavior is acceptable or even useful, but the
+ full implications should be understood and the case carefully
+ weighed before implementing any behavior described with this
+ label.
+
+ 5. MAY This word, or the adjective "OPTIONAL", mean that an item is
+ truly optional. One vendor may choose to include the item because
+ a particular marketplace requires it or because the vendor feels
+ that it enhances the product while another vendor may omit the
+ same item. An implementation which does not include a particular
+ option MUST be prepared to interoperate with another
+ implementation which does include the option, though perhaps with
+ reduced functionality. In the same vein an implementation which
+
+
+
+Klensin Standards Track [Page 9]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ does include a particular option MUST be prepared to interoperate
+ with another implementation which does not include the option
+ (except, of course, for the feature the option provides.)
+
+2.3.1 Mail Objects
+
+ SMTP transports a mail object. A mail object contains an envelope
+ and content.
+
+ The SMTP envelope is sent as a series of SMTP protocol units
+ (described in section 3). It consists of an originator address (to
+ which error reports should be directed); one or more recipient
+ addresses; and optional protocol extension material. Historically,
+ variations on the recipient address specification command (RCPT TO)
+ could be used to specify alternate delivery modes, such as immediate
+ display; those variations have now been deprecated (see appendix F,
+ section F.6).
+
+ The SMTP content is sent in the SMTP DATA protocol unit and has two
+ parts: the headers and the body. If the content conforms to other
+ contemporary standards, the headers form a collection of field/value
+ pairs structured as in the message format specification [32]; the
+ body, if structured, is defined according to MIME [12]. The content
+ is textual in nature, expressed using the US-ASCII repertoire [1].
+ Although SMTP extensions (such as "8BITMIME" [20]) may relax this
+ restriction for the content body, the content headers are always
+ encoded using the US-ASCII repertoire. A MIME extension [23] defines
+ an algorithm for representing header values outside the US-ASCII
+ repertoire, while still encoding them using the US-ASCII repertoire.
+
+2.3.2 Senders and Receivers
+
+ In RFC 821, the two hosts participating in an SMTP transaction were
+ described as the "SMTP-sender" and "SMTP-receiver". This document
+ has been changed to reflect current industry terminology and hence
+ refers to them as the "SMTP client" (or sometimes just "the client")
+ and "SMTP server" (or just "the server"), respectively. Since a
+ given host may act both as server and client in a relay situation,
+ "receiver" and "sender" terminology is still used where needed for
+ clarity.
+
+2.3.3 Mail Agents and Message Stores
+
+ Additional mail system terminology became common after RFC 821 was
+ published and, where convenient, is used in this specification. In
+ particular, SMTP servers and clients provide a mail transport service
+ and therefore act as "Mail Transfer Agents" (MTAs). "Mail User
+ Agents" (MUAs or UAs) are normally thought of as the sources and
+
+
+
+Klensin Standards Track [Page 10]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ targets of mail. At the source, an MUA might collect mail to be
+ transmitted from a user and hand it off to an MTA; the final
+ ("delivery") MTA would be thought of as handing the mail off to an
+ MUA (or at least transferring responsibility to it, e.g., by
+ depositing the message in a "message store"). However, while these
+ terms are used with at least the appearance of great precision in
+ other environments, the implied boundaries between MUAs and MTAs
+ often do not accurately match common, and conforming, practices with
+ Internet mail. Hence, the reader should be cautious about inferring
+ the strong relationships and responsibilities that might be implied
+ if these terms were used elsewhere.
+
+2.3.4 Host
+
+ For the purposes of this specification, a host is a computer system
+ attached to the Internet (or, in some cases, to a private TCP/IP
+ network) and supporting the SMTP protocol. Hosts are known by names
+ (see "domain"); identifying them by numerical address is discouraged.
+
+2.3.5 Domain
+
+ A domain (or domain name) consists of one or more dot-separated
+ components. These components ("labels" in DNS terminology [22]) are
+ restricted for SMTP purposes to consist of a sequence of letters,
+ digits, and hyphens drawn from the ASCII character set [1]. Domain
+ names are used as names of hosts and of other entities in the domain
+ name hierarchy. For example, a domain may refer to an alias (label
+ of a CNAME RR) or the label of Mail eXchanger records to be used to
+ deliver mail instead of representing a host name. See [22] and
+ section 5 of this specification.
+
+ The domain name, as described in this document and in [22], is the
+ entire, fully-qualified name (often referred to as an "FQDN"). A
+ domain name that is not in FQDN form is no more than a local alias.
+ Local aliases MUST NOT appear in any SMTP transaction.
+
+2.3.6 Buffer and State Table
+
+ SMTP sessions are stateful, with both parties carefully maintaining a
+ common view of the current state. In this document we model this
+ state by a virtual "buffer" and a "state table" on the server which
+ may be used by the client to, for example, "clear the buffer" or
+ "reset the state table," causing the information in the buffer to be
+ discarded and the state to be returned to some previous state.
+
+
+
+
+
+
+
+Klensin Standards Track [Page 11]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+2.3.7 Lines
+
+ SMTP commands and, unless altered by a service extension, message
+ data, are transmitted in "lines". Lines consist of zero or more data
+ characters terminated by the sequence ASCII character "CR" (hex value
+ 0D) followed immediately by ASCII character "LF" (hex value 0A).
+ This termination sequence is denoted as <CRLF> in this document.
+ Conforming implementations MUST NOT recognize or generate any other
+ character or character sequence as a line terminator. Limits MAY be
+ imposed on line lengths by servers (see section 4.5.3).
+
+ In addition, the appearance of "bare" "CR" or "LF" characters in text
+ (i.e., either without the other) has a long history of causing
+ problems in mail implementations and applications that use the mail
+ system as a tool. SMTP client implementations MUST NOT transmit
+ these characters except when they are intended as line terminators
+ and then MUST, as indicated above, transmit them only as a <CRLF>
+ sequence.
+
+2.3.8 Originator, Delivery, Relay, and Gateway Systems
+
+ This specification makes a distinction among four types of SMTP
+ systems, based on the role those systems play in transmitting
+ electronic mail. An "originating" system (sometimes called an SMTP
+ originator) introduces mail into the Internet or, more generally,
+ into a transport service environment. A "delivery" SMTP system is
+ one that receives mail from a transport service environment and
+ passes it to a mail user agent or deposits it in a message store
+ which a mail user agent is expected to subsequently access. A
+ "relay" SMTP system (usually referred to just as a "relay") receives
+ mail from an SMTP client and transmits it, without modification to
+ the message data other than adding trace information, to another SMTP
+ server for further relaying or for delivery.
+
+ A "gateway" SMTP system (usually referred to just as a "gateway")
+ receives mail from a client system in one transport environment and
+ transmits it to a server system in another transport environment.
+ Differences in protocols or message semantics between the transport
+ environments on either side of a gateway may require that the gateway
+ system perform transformations to the message that are not permitted
+ to SMTP relay systems. For the purposes of this specification,
+ firewalls that rewrite addresses should be considered as gateways,
+ even if SMTP is used on both sides of them (see [11]).
+
+
+
+
+
+
+
+
+Klensin Standards Track [Page 12]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+2.3.9 Message Content and Mail Data
+
+ The terms "message content" and "mail data" are used interchangeably
+ in this document to describe the material transmitted after the DATA
+ command is accepted and before the end of data indication is
+ transmitted. Message content includes message headers and the
+ possibly-structured message body. The MIME specification [12]
+ provides the standard mechanisms for structured message bodies.
+
+2.3.10 Mailbox and Address
+
+ As used in this specification, an "address" is a character string
+ that identifies a user to whom mail will be sent or a location into
+ which mail will be deposited. The term "mailbox" refers to that
+ depository. The two terms are typically used interchangeably unless
+ the distinction between the location in which mail is placed (the
+ mailbox) and a reference to it (the address) is important. An
+ address normally consists of user and domain specifications. The
+ standard mailbox naming convention is defined to be "local-
+ part@domain": contemporary usage permits a much broader set of
+ applications than simple "user names". Consequently, and due to a
+ long history of problems when intermediate hosts have attempted to
+ optimize transport by modifying them, the local-part MUST be
+ interpreted and assigned semantics only by the host specified in the
+ domain part of the address.
+
+2.3.11 Reply
+
+ An SMTP reply is an acknowledgment (positive or negative) sent from
+ receiver to sender via the transmission channel in response to a
+ command. The general form of a reply is a numeric completion code
+ (indicating failure or success) usually followed by a text string.
+ The codes are for use by programs and the text is usually intended
+ for human users. Recent work [34] has specified further structuring
+ of the reply strings, including the use of supplemental and more
+ specific completion codes.
+
+2.4 General Syntax Principles and Transaction Model
+
+ SMTP commands and replies have a rigid syntax. All commands begin
+ with a command verb. All Replies begin with a three digit numeric
+ code. In some commands and replies, arguments MUST follow the verb
+ or reply code. Some commands do not accept arguments (after the
+ verb), and some reply codes are followed, sometimes optionally, by
+ free form text. In both cases, where text appears, it is separated
+ from the verb or reply code by a space character. Complete
+ definitions of commands and replies appear in section 4.
+
+
+
+
+Klensin Standards Track [Page 13]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ Verbs and argument values (e.g., "TO:" or "to:" in the RCPT command
+ and extension name keywords) are not case sensitive, with the sole
+ exception in this specification of a mailbox local-part (SMTP
+ Extensions may explicitly specify case-sensitive elements). That is,
+ a command verb, an argument value other than a mailbox local-part,
+ and free form text MAY be encoded in upper case, lower case, or any
+ mixture of upper and lower case with no impact on its meaning. This
+ is NOT true of a mailbox local-part. The local-part of a mailbox
+ MUST BE treated as case sensitive. Therefore, SMTP implementations
+ MUST take care to preserve the case of mailbox local-parts. Mailbox
+ domains are not case sensitive. In particular, for some hosts the
+ user "smith" is different from the user "Smith". However, exploiting
+ the case sensitivity of mailbox local-parts impedes interoperability
+ and is discouraged.
+
+ A few SMTP servers, in violation of this specification (and RFC 821)
+ require that command verbs be encoded by clients in upper case.
+ Implementations MAY wish to employ this encoding to accommodate those
+ servers.
+
+ The argument field consists of a variable length character string
+ ending with the end of the line, i.e., with the character sequence
+ <CRLF>. The receiver will take no action until this sequence is
+ received.
+
+ The syntax for each command is shown with the discussion of that
+ command. Common elements and parameters are shown in section 4.1.2.
+
+ Commands and replies are composed of characters from the ASCII
+ character set [1]. When the transport service provides an 8-bit byte
+ (octet) transmission channel, each 7-bit character is transmitted
+ right justified in an octet with the high order bit cleared to zero.
+ More specifically, the unextended SMTP service provides seven bit
+ transport only. An originating SMTP client which has not
+ successfully negotiated an appropriate extension with a particular
+ server MUST NOT transmit messages with information in the high-order
+ bit of octets. If such messages are transmitted in violation of this
+ rule, receiving SMTP servers MAY clear the high-order bit or reject
+ the message as invalid. In general, a relay SMTP SHOULD assume that
+ the message content it has received is valid and, assuming that the
+ envelope permits doing so, relay it without inspecting that content.
+ Of course, if the content is mislabeled and the data path cannot
+ accept the actual content, this may result in ultimate delivery of a
+ severely garbled message to the recipient. Delivery SMTP systems MAY
+ reject ("bounce") such messages rather than deliver them. No sending
+ SMTP system is permitted to send envelope commands in any character
+
+
+
+
+
+Klensin Standards Track [Page 14]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ set other than US-ASCII; receiving systems SHOULD reject such
+ commands, normally using "500 syntax error - invalid character"
+ replies.
+
+ Eight-bit message content transmission MAY be requested of the server
+ by a client using extended SMTP facilities, notably the "8BITMIME"
+ extension [20]. 8BITMIME SHOULD be supported by SMTP servers.
+ However, it MUST not be construed as authorization to transmit
+ unrestricted eight bit material. 8BITMIME MUST NOT be requested by
+ senders for material with the high bit on that is not in MIME format
+ with an appropriate content-transfer encoding; servers MAY reject
+ such messages.
+
+ The metalinguistic notation used in this document corresponds to the
+ "Augmented BNF" used in other Internet mail system documents. The
+ reader who is not familiar with that syntax should consult the ABNF
+ specification [8]. Metalanguage terms used in running text are
+ surrounded by pointed brackets (e.g., <CRLF>) for clarity.
+
+3. The SMTP Procedures: An Overview
+
+ This section contains descriptions of the procedures used in SMTP:
+ session initiation, the mail transaction, forwarding mail, verifying
+ mailbox names and expanding mailing lists, and the opening and
+ closing exchanges. Comments on relaying, a note on mail domains, and
+ a discussion of changing roles are included at the end of this
+ section. Several complete scenarios are presented in appendix D.
+
+3.1 Session Initiation
+
+ An SMTP session is initiated when a client opens a connection to a
+ server and the server responds with an opening message.
+
+ SMTP server implementations MAY include identification of their
+ software and version information in the connection greeting reply
+ after the 220 code, a practice that permits more efficient isolation
+ and repair of any problems. Implementations MAY make provision for
+ SMTP servers to disable the software and version announcement where
+ it causes security concerns. While some systems also identify their
+ contact point for mail problems, this is not a substitute for
+ maintaining the required "postmaster" address (see section 4.5.1).
+
+ The SMTP protocol allows a server to formally reject a transaction
+ while still allowing the initial connection as follows: a 554
+ response MAY be given in the initial connection opening message
+ instead of the 220. A server taking this approach MUST still wait
+ for the client to send a QUIT (see section 4.1.1.10) before closing
+ the connection and SHOULD respond to any intervening commands with
+
+
+
+Klensin Standards Track [Page 15]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ "503 bad sequence of commands". Since an attempt to make an SMTP
+ connection to such a system is probably in error, a server returning
+ a 554 response on connection opening SHOULD provide enough
+ information in the reply text to facilitate debugging of the sending
+ system.
+
+3.2 Client Initiation
+
+ Once the server has sent the welcoming message and the client has
+ received it, the client normally sends the EHLO command to the
+ server, indicating the client's identity. In addition to opening the
+ session, use of EHLO indicates that the client is able to process
+ service extensions and requests that the server provide a list of the
+ extensions it supports. Older SMTP systems which are unable to
+ support service extensions and contemporary clients which do not
+ require service extensions in the mail session being initiated, MAY
+ use HELO instead of EHLO. Servers MUST NOT return the extended
+ EHLO-style response to a HELO command. For a particular connection
+ attempt, if the server returns a "command not recognized" response to
+ EHLO, the client SHOULD be able to fall back and send HELO.
+
+ In the EHLO command the host sending the command identifies itself;
+ the command may be interpreted as saying "Hello, I am <domain>" (and,
+ in the case of EHLO, "and I support service extension requests").
+
+3.3 Mail Transactions
+
+ There are three steps to SMTP mail transactions. The transaction
+ starts with a MAIL command which gives the sender identification.
+ (In general, the MAIL command may be sent only when no mail
+ transaction is in progress; see section 4.1.4.) A series of one or
+ more RCPT commands follows giving the receiver information. Then a
+ DATA command initiates transfer of the mail data and is terminated by
+ the "end of mail" data indicator, which also confirms the
+ transaction.
+
+ The first step in the procedure is the MAIL command.
+
+ MAIL FROM:<reverse-path> [SP <mail-parameters> ] <CRLF>
+
+ This command tells the SMTP-receiver that a new mail transaction is
+ starting and to reset all its state tables and buffers, including any
+ recipients or mail data. The <reverse-path> portion of the first or
+ only argument contains the source mailbox (between "<" and ">"
+ brackets), which can be used to report errors (see section 4.2 for a
+ discussion of error reporting). If accepted, the SMTP server returns
+ a 250 OK reply. If the mailbox specification is not acceptable for
+ some reason, the server MUST return a reply indicating whether the
+
+
+
+Klensin Standards Track [Page 16]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ failure is permanent (i.e., will occur again if the client tries to
+ send the same address again) or temporary (i.e., the address might be
+ accepted if the client tries again later). Despite the apparent
+ scope of this requirement, there are circumstances in which the
+ acceptability of the reverse-path may not be determined until one or
+ more forward-paths (in RCPT commands) can be examined. In those
+ cases, the server MAY reasonably accept the reverse-path (with a 250
+ reply) and then report problems after the forward-paths are received
+ and examined. Normally, failures produce 550 or 553 replies.
+
+ Historically, the <reverse-path> can contain more than just a
+ mailbox, however, contemporary systems SHOULD NOT use source routing
+ (see appendix C).
+
+ The optional <mail-parameters> are associated with negotiated SMTP
+ service extensions (see section 2.2).
+
+ The second step in the procedure is the RCPT command.
+
+ RCPT TO:<forward-path> [ SP <rcpt-parameters> ] <CRLF>
+
+ The first or only argument to this command includes a forward-path
+ (normally a mailbox and domain, always surrounded by "<" and ">"
+ brackets) identifying one recipient. If accepted, the SMTP server
+ returns a 250 OK reply and stores the forward-path. If the recipient
+ is known not to be a deliverable address, the SMTP server returns a
+ 550 reply, typically with a string such as "no such user - " and the
+ mailbox name (other circumstances and reply codes are possible).
+ This step of the procedure can be repeated any number of times.
+
+ The <forward-path> can contain more than just a mailbox.
+ Historically, the <forward-path> can be a source routing list of
+ hosts and the destination mailbox, however, contemporary SMTP clients
+ SHOULD NOT utilize source routes (see appendix C). Servers MUST be
+ prepared to encounter a list of source routes in the forward path,
+ but SHOULD ignore the routes or MAY decline to support the relaying
+ they imply. Similarly, servers MAY decline to accept mail that is
+ destined for other hosts or systems. These restrictions make a
+ server useless as a relay for clients that do not support full SMTP
+ functionality. Consequently, restricted-capability clients MUST NOT
+ assume that any SMTP server on the Internet can be used as their mail
+ processing (relaying) site. If a RCPT command appears without a
+ previous MAIL command, the server MUST return a 503 "Bad sequence of
+ commands" response. The optional <rcpt-parameters> are associated
+ with negotiated SMTP service extensions (see section 2.2).
+
+ The third step in the procedure is the DATA command (or some
+ alternative specified in a service extension).
+
+
+
+Klensin Standards Track [Page 17]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ DATA <CRLF>
+
+ If accepted, the SMTP server returns a 354 Intermediate reply and
+ considers all succeeding lines up to but not including the end of
+ mail data indicator to be the message text. When the end of text is
+ successfully received and stored the SMTP-receiver sends a 250 OK
+ reply.
+
+ Since the mail data is sent on the transmission channel, the end of
+ mail data must be indicated so that the command and reply dialog can
+ be resumed. SMTP indicates the end of the mail data by sending a
+ line containing only a "." (period or full stop). A transparency
+ procedure is used to prevent this from interfering with the user's
+ text (see section 4.5.2).
+
+ The end of mail data indicator also confirms the mail transaction and
+ tells the SMTP server to now process the stored recipients and mail
+ data. If accepted, the SMTP server returns a 250 OK reply. The DATA
+ command can fail at only two points in the protocol exchange:
+
+ - If there was no MAIL, or no RCPT, command, or all such commands
+ were rejected, the server MAY return a "command out of sequence"
+ (503) or "no valid recipients" (554) reply in response to the DATA
+ command. If one of those replies (or any other 5yz reply) is
+ received, the client MUST NOT send the message data; more
+ generally, message data MUST NOT be sent unless a 354 reply is
+ received.
+
+ - If the verb is initially accepted and the 354 reply issued, the
+ DATA command should fail only if the mail transaction was
+ incomplete (for example, no recipients), or if resources were
+ unavailable (including, of course, the server unexpectedly
+ becoming unavailable), or if the server determines that the
+ message should be rejected for policy or other reasons.
+
+ However, in practice, some servers do not perform recipient
+ verification until after the message text is received. These servers
+ SHOULD treat a failure for one or more recipients as a "subsequent
+ failure" and return a mail message as discussed in section 6. Using
+ a "550 mailbox not found" (or equivalent) reply code after the data
+ are accepted makes it difficult or impossible for the client to
+ determine which recipients failed.
+
+ When RFC 822 format [7, 32] is being used, the mail data include the
+ memo header items such as Date, Subject, To, Cc, From. Server SMTP
+ systems SHOULD NOT reject messages based on perceived defects in the
+ RFC 822 or MIME [12] message header or message body. In particular,
+
+
+
+
+Klensin Standards Track [Page 18]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ they MUST NOT reject messages in which the numbers of Resent-fields
+ do not match or Resent-to appears without Resent-from and/or Resent-
+ date.
+
+ Mail transaction commands MUST be used in the order discussed above.
+
+3.4 Forwarding for Address Correction or Updating
+
+ Forwarding support is most often required to consolidate and simplify
+ addresses within, or relative to, some enterprise and less frequently
+ to establish addresses to link a person's prior address with current
+ one. Silent forwarding of messages (without server notification to
+ the sender), for security or non-disclosure purposes, is common in
+ the contemporary Internet.
+
+ In both the enterprise and the "new address" cases, information
+ hiding (and sometimes security) considerations argue against exposure
+ of the "final" address through the SMTP protocol as a side-effect of
+ the forwarding activity. This may be especially important when the
+ final address may not even be reachable by the sender. Consequently,
+ the "forwarding" mechanisms described in section 3.2 of RFC 821, and
+ especially the 251 (corrected destination) and 551 reply codes from
+ RCPT must be evaluated carefully by implementers and, when they are
+ available, by those configuring systems.
+
+ In particular:
+
+ * Servers MAY forward messages when they are aware of an address
+ change. When they do so, they MAY either provide address-updating
+ information with a 251 code, or may forward "silently" and return
+ a 250 code. But, if a 251 code is used, they MUST NOT assume that
+ the client will actually update address information or even return
+ that information to the user.
+
+ Alternately,
+
+ * Servers MAY reject or bounce messages when they are not
+ deliverable when addressed. When they do so, they MAY either
+ provide address-updating information with a 551 code, or may
+ reject the message as undeliverable with a 550 code and no
+ address-specific information. But, if a 551 code is used, they
+ MUST NOT assume that the client will actually update address
+ information or even return that information to the user.
+
+ SMTP server implementations that support the 251 and/or 551 reply
+ codes are strongly encouraged to provide configuration mechanisms so
+ that sites which conclude that they would undesirably disclose
+ information can disable or restrict their use.
+
+
+
+Klensin Standards Track [Page 19]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+3.5 Commands for Debugging Addresses
+
+3.5.1 Overview
+
+ SMTP provides commands to verify a user name or obtain the content of
+ a mailing list. This is done with the VRFY and EXPN commands, which
+ have character string arguments. Implementations SHOULD support VRFY
+ and EXPN (however, see section 3.5.2 and 7.3).
+
+ For the VRFY command, the string is a user name or a user name and
+ domain (see below). If a normal (i.e., 250) response is returned,
+ the response MAY include the full name of the user and MUST include
+ the mailbox of the user. It MUST be in either of the following
+ forms:
+
+ User Name <local-part@domain>
+ local-part@domain
+
+ When a name that is the argument to VRFY could identify more than one
+ mailbox, the server MAY either note the ambiguity or identify the
+ alternatives. In other words, any of the following are legitimate
+ response to VRFY:
+
+ 553 User ambiguous
+
+ or
+
+ 553- Ambiguous; Possibilities are
+ 553-Joe Smith <jsmith@foo.com>
+ 553-Harry Smith <hsmith@foo.com>
+ 553 Melvin Smith <dweep@foo.com>
+
+ or
+
+ 553-Ambiguous; Possibilities
+ 553- <jsmith@foo.com>
+ 553- <hsmith@foo.com>
+ 553 <dweep@foo.com>
+
+ Under normal circumstances, a client receiving a 553 reply would be
+ expected to expose the result to the user. Use of exactly the forms
+ given, and the "user ambiguous" or "ambiguous" keywords, possibly
+ supplemented by extended reply codes such as those described in [34],
+ will facilitate automated translation into other languages as needed.
+ Of course, a client that was highly automated or that was operating
+ in another language than English, might choose to try to translate
+ the response, to return some other indication to the user than the
+
+
+
+
+Klensin Standards Track [Page 20]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ literal text of the reply, or to take some automated action such as
+ consulting a directory service for additional information before
+ reporting to the user.
+
+ For the EXPN command, the string identifies a mailing list, and the
+ successful (i.e., 250) multiline response MAY include the full name
+ of the users and MUST give the mailboxes on the mailing list.
+
+ In some hosts the distinction between a mailing list and an alias for
+ a single mailbox is a bit fuzzy, since a common data structure may
+ hold both types of entries, and it is possible to have mailing lists
+ containing only one mailbox. If a request is made to apply VRFY to a
+ mailing list, a positive response MAY be given if a message so
+ addressed would be delivered to everyone on the list, otherwise an
+ error SHOULD be reported (e.g., "550 That is a mailing list, not a
+ user" or "252 Unable to verify members of mailing list"). If a
+ request is made to expand a user name, the server MAY return a
+ positive response consisting of a list containing one name, or an
+ error MAY be reported (e.g., "550 That is a user name, not a mailing
+ list").
+
+ In the case of a successful multiline reply (normal for EXPN) exactly
+ one mailbox is to be specified on each line of the reply. The case
+ of an ambiguous request is discussed above.
+
+ "User name" is a fuzzy term and has been used deliberately. An
+ implementation of the VRFY or EXPN commands MUST include at least
+ recognition of local mailboxes as "user names". However, since
+ current Internet practice often results in a single host handling
+ mail for multiple domains, hosts, especially hosts that provide this
+ functionality, SHOULD accept the "local-part@domain" form as a "user
+ name"; hosts MAY also choose to recognize other strings as "user
+ names".
+
+ The case of expanding a mailbox list requires a multiline reply, such
+ as:
+
+ C: EXPN Example-People
+ S: 250-Jon Postel <Postel@isi.edu>
+ S: 250-Fred Fonebone <Fonebone@physics.foo-u.edu>
+ S: 250 Sam Q. Smith <SQSmith@specific.generic.com>
+
+ or
+
+ C: EXPN Executive-Washroom-List
+ S: 550 Access Denied to You.
+
+
+
+
+
+Klensin Standards Track [Page 21]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ The character string arguments of the VRFY and EXPN commands cannot
+ be further restricted due to the variety of implementations of the
+ user name and mailbox list concepts. On some systems it may be
+ appropriate for the argument of the EXPN command to be a file name
+ for a file containing a mailing list, but again there are a variety
+ of file naming conventions in the Internet. Similarly, historical
+ variations in what is returned by these commands are such that the
+ response SHOULD be interpreted very carefully, if at all, and SHOULD
+ generally only be used for diagnostic purposes.
+
+3.5.2 VRFY Normal Response
+
+ When normal (2yz or 551) responses are returned from a VRFY or EXPN
+ request, the reply normally includes the mailbox name, i.e.,
+ "<local-part@domain>", where "domain" is a fully qualified domain
+ name, MUST appear in the syntax. In circumstances exceptional enough
+ to justify violating the intent of this specification, free-form text
+ MAY be returned. In order to facilitate parsing by both computers
+ and people, addresses SHOULD appear in pointed brackets. When
+ addresses, rather than free-form debugging information, are returned,
+ EXPN and VRFY MUST return only valid domain addresses that are usable
+ in SMTP RCPT commands. Consequently, if an address implies delivery
+ to a program or other system, the mailbox name used to reach that
+ target MUST be given. Paths (explicit source routes) MUST NOT be
+ returned by VRFY or EXPN.
+
+ Server implementations SHOULD support both VRFY and EXPN. For
+ security reasons, implementations MAY provide local installations a
+ way to disable either or both of these commands through configuration
+ options or the equivalent. When these commands are supported, they
+ are not required to work across relays when relaying is supported.
+ Since they were both optional in RFC 821, they MUST be listed as
+ service extensions in an EHLO response, if they are supported.
+
+3.5.3 Meaning of VRFY or EXPN Success Response
+
+ A server MUST NOT return a 250 code in response to a VRFY or EXPN
+ command unless it has actually verified the address. In particular,
+ a server MUST NOT return 250 if all it has done is to verify that the
+ syntax given is valid. In that case, 502 (Command not implemented)
+ or 500 (Syntax error, command unrecognized) SHOULD be returned. As
+ stated elsewhere, implementation (in the sense of actually validating
+ addresses and returning information) of VRFY and EXPN are strongly
+ recommended. Hence, implementations that return 500 or 502 for VRFY
+ are not in full compliance with this specification.
+
+
+
+
+
+
+Klensin Standards Track [Page 22]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ There may be circumstances where an address appears to be valid but
+ cannot reasonably be verified in real time, particularly when a
+ server is acting as a mail exchanger for another server or domain.
+ "Apparent validity" in this case would normally involve at least
+ syntax checking and might involve verification that any domains
+ specified were ones to which the host expected to be able to relay
+ mail. In these situations, reply code 252 SHOULD be returned. These
+ cases parallel the discussion of RCPT verification discussed in
+ section 2.1. Similarly, the discussion in section 3.4 applies to the
+ use of reply codes 251 and 551 with VRFY (and EXPN) to indicate
+ addresses that are recognized but that would be forwarded or bounced
+ were mail received for them. Implementations generally SHOULD be
+ more aggressive about address verification in the case of VRFY than
+ in the case of RCPT, even if it takes a little longer to do so.
+
+3.5.4 Semantics and Applications of EXPN
+
+ EXPN is often very useful in debugging and understanding problems
+ with mailing lists and multiple-target-address aliases. Some systems
+ have attempted to use source expansion of mailing lists as a means of
+ eliminating duplicates. The propagation of aliasing systems with
+ mail on the Internet, for hosts (typically with MX and CNAME DNS
+ records), for mailboxes (various types of local host aliases), and in
+ various proxying arrangements, has made it nearly impossible for
+ these strategies to work consistently, and mail systems SHOULD NOT
+ attempt them.
+
+3.6 Domains
+
+ Only resolvable, fully-qualified, domain names (FQDNs) are permitted
+ when domain names are used in SMTP. In other words, names that can
+ be resolved to MX RRs or A RRs (as discussed in section 5) are
+ permitted, as are CNAME RRs whose targets can be resolved, in turn,
+ to MX or A RRs. Local nicknames or unqualified names MUST NOT be
+ used. There are two exceptions to the rule requiring FQDNs:
+
+ - The domain name given in the EHLO command MUST BE either a primary
+ host name (a domain name that resolves to an A RR) or, if the host
+ has no name, an address literal as described in section 4.1.1.1.
+
+ - The reserved mailbox name "postmaster" may be used in a RCPT
+ command without domain qualification (see section 4.1.1.3) and
+ MUST be accepted if so used.
+
+
+
+
+
+
+
+
+Klensin Standards Track [Page 23]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+3.7 Relaying
+
+ In general, the availability of Mail eXchanger records in the domain
+ name system [22, 27] makes the use of explicit source routes in the
+ Internet mail system unnecessary. Many historical problems with
+ their interpretation have made their use undesirable. SMTP clients
+ SHOULD NOT generate explicit source routes except under unusual
+ circumstances. SMTP servers MAY decline to act as mail relays or to
+ accept addresses that specify source routes. When route information
+ is encountered, SMTP servers are also permitted to ignore the route
+ information and simply send to the final destination specified as the
+ last element in the route and SHOULD do so. There has been an
+ invalid practice of using names that do not appear in the DNS as
+ destination names, with the senders counting on the intermediate
+ hosts specified in source routing to resolve any problems. If source
+ routes are stripped, this practice will cause failures. This is one
+ of several reasons why SMTP clients MUST NOT generate invalid source
+ routes or depend on serial resolution of names.
+
+ When source routes are not used, the process described in RFC 821 for
+ constructing a reverse-path from the forward-path is not applicable
+ and the reverse-path at the time of delivery will simply be the
+ address that appeared in the MAIL command.
+
+ A relay SMTP server is usually the target of a DNS MX record that
+ designates it, rather than the final delivery system. The relay
+ server may accept or reject the task of relaying the mail in the same
+ way it accepts or rejects mail for a local user. If it accepts the
+ task, it then becomes an SMTP client, establishes a transmission
+ channel to the next SMTP server specified in the DNS (according to
+ the rules in section 5), and sends it the mail. If it declines to
+ relay mail to a particular address for policy reasons, a 550 response
+ SHOULD be returned.
+
+ Many mail-sending clients exist, especially in conjunction with
+ facilities that receive mail via POP3 or IMAP, that have limited
+ capability to support some of the requirements of this specification,
+ such as the ability to queue messages for subsequent delivery
+ attempts. For these clients, it is common practice to make private
+ arrangements to send all messages to a single server for processing
+ and subsequent distribution. SMTP, as specified here, is not ideally
+ suited for this role, and work is underway on standardized mail
+ submission protocols that might eventually supercede the current
+ practices. In any event, because these arrangements are private and
+ fall outside the scope of this specification, they are not described
+ here.
+
+
+
+
+
+Klensin Standards Track [Page 24]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ It is important to note that MX records can point to SMTP servers
+ which act as gateways into other environments, not just SMTP relays
+ and final delivery systems; see sections 3.8 and 5.
+
+ If an SMTP server has accepted the task of relaying the mail and
+ later finds that the destination is incorrect or that the mail cannot
+ be delivered for some other reason, then it MUST construct an
+ "undeliverable mail" notification message and send it to the
+ originator of the undeliverable mail (as indicated by the reverse-
+ path). Formats specified for non-delivery reports by other standards
+ (see, for example, [24, 25]) SHOULD be used if possible.
+
+ This notification message must be from the SMTP server at the relay
+ host or the host that first determines that delivery cannot be
+ accomplished. Of course, SMTP servers MUST NOT send notification
+ messages about problems transporting notification messages. One way
+ to prevent loops in error reporting is to specify a null reverse-path
+ in the MAIL command of a notification message. When such a message
+ is transmitted the reverse-path MUST be set to null (see section
+ 4.5.5 for additional discussion). A MAIL command with a null
+ reverse-path appears as follows:
+
+ MAIL FROM:<>
+
+ As discussed in section 2.4.1, a relay SMTP has no need to inspect or
+ act upon the headers or body of the message data and MUST NOT do so
+ except to add its own "Received:" header (section 4.4) and,
+ optionally, to attempt to detect looping in the mail system (see
+ section 6.2).
+
+3.8 Mail Gatewaying
+
+ While the relay function discussed above operates within the Internet
+ SMTP transport service environment, MX records or various forms of
+ explicit routing may require that an intermediate SMTP server perform
+ a translation function between one transport service and another. As
+ discussed in section 2.3.8, when such a system is at the boundary
+ between two transport service environments, we refer to it as a
+ "gateway" or "gateway SMTP".
+
+ Gatewaying mail between different mail environments, such as
+ different mail formats and protocols, is complex and does not easily
+ yield to standardization. However, some general requirements may be
+ given for a gateway between the Internet and another mail
+ environment.
+
+
+
+
+
+
+Klensin Standards Track [Page 25]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+3.8.1 Header Fields in Gatewaying
+
+ Header fields MAY be rewritten when necessary as messages are
+ gatewayed across mail environment boundaries. This may involve
+ inspecting the message body or interpreting the local-part of the
+ destination address in spite of the prohibitions in section 2.4.1.
+
+ Other mail systems gatewayed to the Internet often use a subset of
+ RFC 822 headers or provide similar functionality with a different
+ syntax, but some of these mail systems do not have an equivalent to
+ the SMTP envelope. Therefore, when a message leaves the Internet
+ environment, it may be necessary to fold the SMTP envelope
+ information into the message header. A possible solution would be to
+ create new header fields to carry the envelope information (e.g.,
+ "X-SMTP-MAIL:" and "X-SMTP-RCPT:"); however, this would require
+ changes in mail programs in foreign environments and might risk
+ disclosure of private information (see section 7.2).
+
+3.8.2 Received Lines in Gatewaying
+
+ When forwarding a message into or out of the Internet environment, a
+ gateway MUST prepend a Received: line, but it MUST NOT alter in any
+ way a Received: line that is already in the header.
+
+ "Received:" fields of messages originating from other environments
+ may not conform exactly to this specification. However, the most
+ important use of Received: lines is for debugging mail faults, and
+ this debugging can be severely hampered by well-meaning gateways that
+ try to "fix" a Received: line. As another consequence of trace
+ fields arising in non-SMTP environments, receiving systems MUST NOT
+ reject mail based on the format of a trace field and SHOULD be
+ extremely robust in the light of unexpected information or formats in
+ those fields.
+
+ The gateway SHOULD indicate the environment and protocol in the "via"
+ clauses of Received field(s) that it supplies.
+
+3.8.3 Addresses in Gatewaying
+
+ From the Internet side, the gateway SHOULD accept all valid address
+ formats in SMTP commands and in RFC 822 headers, and all valid RFC
+ 822 messages. Addresses and headers generated by gateways MUST
+ conform to applicable Internet standards (including this one and RFC
+ 822). Gateways are, of course, subject to the same rules for
+ handling source routes as those described for other SMTP systems in
+ section 3.3.
+
+
+
+
+
+Klensin Standards Track [Page 26]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+3.8.4 Other Header Fields in Gatewaying
+
+ The gateway MUST ensure that all header fields of a message that it
+ forwards into the Internet mail environment meet the requirements for
+ Internet mail. In particular, all addresses in "From:", "To:",
+ "Cc:", etc., fields MUST be transformed (if necessary) to satisfy RFC
+ 822 syntax, MUST reference only fully-qualified domain names, and
+ MUST be effective and useful for sending replies. The translation
+ algorithm used to convert mail from the Internet protocols to another
+ environment's protocol SHOULD ensure that error messages from the
+ foreign mail environment are delivered to the return path from the
+ SMTP envelope, not to the sender listed in the "From:" field (or
+ other fields) of the RFC 822 message.
+
+3.8.5 Envelopes in Gatewaying
+
+ Similarly, when forwarding a message from another environment into
+ the Internet, the gateway SHOULD set the envelope return path in
+ accordance with an error message return address, if supplied by the
+ foreign environment. If the foreign environment has no equivalent
+ concept, the gateway must select and use a best approximation, with
+ the message originator's address as the default of last resort.
+
+3.9 Terminating Sessions and Connections
+
+ An SMTP connection is terminated when the client sends a QUIT
+ command. The server responds with a positive reply code, after which
+ it closes the connection.
+
+ An SMTP server MUST NOT intentionally close the connection except:
+
+ - After receiving a QUIT command and responding with a 221 reply.
+
+ - After detecting the need to shut down the SMTP service and
+ returning a 421 response code. This response code can be issued
+ after the server receives any command or, if necessary,
+ asynchronously from command receipt (on the assumption that the
+ client will receive it after the next command is issued).
+
+ In particular, a server that closes connections in response to
+ commands that are not understood is in violation of this
+ specification. Servers are expected to be tolerant of unknown
+ commands, issuing a 500 reply and awaiting further instructions from
+ the client.
+
+
+
+
+
+
+
+Klensin Standards Track [Page 27]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ An SMTP server which is forcibly shut down via external means SHOULD
+ attempt to send a line containing a 421 response code to the SMTP
+ client before exiting. The SMTP client will normally read the 421
+ response code after sending its next command.
+
+ SMTP clients that experience a connection close, reset, or other
+ communications failure due to circumstances not under their control
+ (in violation of the intent of this specification but sometimes
+ unavoidable) SHOULD, to maintain the robustness of the mail system,
+ treat the mail transaction as if a 451 response had been received and
+ act accordingly.
+
+3.10 Mailing Lists and Aliases
+
+ An SMTP-capable host SHOULD support both the alias and the list
+ models of address expansion for multiple delivery. When a message is
+ delivered or forwarded to each address of an expanded list form, the
+ return address in the envelope ("MAIL FROM:") MUST be changed to be
+ the address of a person or other entity who administers the list.
+ However, in this case, the message header [32] MUST be left
+ unchanged; in particular, the "From" field of the message header is
+ unaffected.
+
+ An important mail facility is a mechanism for multi-destination
+ delivery of a single message, by transforming (or "expanding" or
+ "exploding") a pseudo-mailbox address into a list of destination
+ mailbox addresses. When a message is sent to such a pseudo-mailbox
+ (sometimes called an "exploder"), copies are forwarded or
+ redistributed to each mailbox in the expanded list. Servers SHOULD
+ simply utilize the addresses on the list; application of heuristics
+ or other matching rules to eliminate some addresses, such as that of
+ the originator, is strongly discouraged. We classify such a pseudo-
+ mailbox as an "alias" or a "list", depending upon the expansion
+ rules.
+
+3.10.1 Alias
+
+ To expand an alias, the recipient mailer simply replaces the pseudo-
+ mailbox address in the envelope with each of the expanded addresses
+ in turn; the rest of the envelope and the message body are left
+ unchanged. The message is then delivered or forwarded to each
+ expanded address.
+
+3.10.2 List
+
+ A mailing list may be said to operate by "redistribution" rather than
+ by "forwarding". To expand a list, the recipient mailer replaces the
+ pseudo-mailbox address in the envelope with all of the expanded
+
+
+
+Klensin Standards Track [Page 28]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ addresses. The return address in the envelope is changed so that all
+ error messages generated by the final deliveries will be returned to
+ a list administrator, not to the message originator, who generally
+ has no control over the contents of the list and will typically find
+ error messages annoying.
+
+4. The SMTP Specifications
+
+4.1 SMTP Commands
+
+4.1.1 Command Semantics and Syntax
+
+ The SMTP commands define the mail transfer or the mail system
+ function requested by the user. SMTP commands are character strings
+ terminated by <CRLF>. The commands themselves are alphabetic
+ characters terminated by <SP> if parameters follow and <CRLF>
+ otherwise. (In the interest of improved interoperability, SMTP
+ receivers are encouraged to tolerate trailing white space before the
+ terminating <CRLF>.) The syntax of the local part of a mailbox must
+ conform to receiver site conventions and the syntax specified in
+ section 4.1.2. The SMTP commands are discussed below. The SMTP
+ replies are discussed in section 4.2.
+
+ A mail transaction involves several data objects which are
+ communicated as arguments to different commands. The reverse-path is
+ the argument of the MAIL command, the forward-path is the argument of
+ the RCPT command, and the mail data is the argument of the DATA
+ command. These arguments or data objects must be transmitted and
+ held pending the confirmation communicated by the end of mail data
+ indication which finalizes the transaction. The model for this is
+ that distinct buffers are provided to hold the types of data objects,
+ that is, there is a reverse-path buffer, a forward-path buffer, and a
+ mail data buffer. Specific commands cause information to be appended
+ to a specific buffer, or cause one or more buffers to be cleared.
+
+ Several commands (RSET, DATA, QUIT) are specified as not permitting
+ parameters. In the absence of specific extensions offered by the
+ server and accepted by the client, clients MUST NOT send such
+ parameters and servers SHOULD reject commands containing them as
+ having invalid syntax.
+
+4.1.1.1 Extended HELLO (EHLO) or HELLO (HELO)
+
+ These commands are used to identify the SMTP client to the SMTP
+ server. The argument field contains the fully-qualified domain name
+ of the SMTP client if one is available. In situations in which the
+ SMTP client system does not have a meaningful domain name (e.g., when
+ its address is dynamically allocated and no reverse mapping record is
+
+
+
+Klensin Standards Track [Page 29]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ available), the client SHOULD send an address literal (see section
+ 4.1.3), optionally followed by information that will help to identify
+ the client system. y The SMTP server identifies itself to the SMTP
+ client in the connection greeting reply and in the response to this
+ command.
+
+ A client SMTP SHOULD start an SMTP session by issuing the EHLO
+ command. If the SMTP server supports the SMTP service extensions it
+ will give a successful response, a failure response, or an error
+ response. If the SMTP server, in violation of this specification,
+ does not support any SMTP service extensions it will generate an
+ error response. Older client SMTP systems MAY, as discussed above,
+ use HELO (as specified in RFC 821) instead of EHLO, and servers MUST
+ support the HELO command and reply properly to it. In any event, a
+ client MUST issue HELO or EHLO before starting a mail transaction.
+
+ These commands, and a "250 OK" reply to one of them, confirm that
+ both the SMTP client and the SMTP server are in the initial state,
+ that is, there is no transaction in progress and all state tables and
+ buffers are cleared.
+
+ Syntax:
+
+ ehlo = "EHLO" SP Domain CRLF
+ helo = "HELO" SP Domain CRLF
+
+ Normally, the response to EHLO will be a multiline reply. Each line
+ of the response contains a keyword and, optionally, one or more
+ parameters. Following the normal syntax for multiline replies, these
+ keyworks follow the code (250) and a hyphen for all but the last
+ line, and the code and a space for the last line. The syntax for a
+ positive response, using the ABNF notation and terminal symbols of
+ [8], is:
+
+ ehlo-ok-rsp = ( "250" domain [ SP ehlo-greet ] CRLF )
+ / ( "250-" domain [ SP ehlo-greet ] CRLF
+ *( "250-" ehlo-line CRLF )
+ "250" SP ehlo-line CRLF )
+
+ ehlo-greet = 1*(%d0-9 / %d11-12 / %d14-127)
+ ; string of any characters other than CR or LF
+
+ ehlo-line = ehlo-keyword *( SP ehlo-param )
+
+ ehlo-keyword = (ALPHA / DIGIT) *(ALPHA / DIGIT / "-")
+ ; additional syntax of ehlo-params depends on
+ ; ehlo-keyword
+
+
+
+
+Klensin Standards Track [Page 30]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ ehlo-param = 1*(%d33-127)
+ ; any CHAR excluding <SP> and all
+ ; control characters (US-ASCII 0-31 inclusive)
+
+ Although EHLO keywords may be specified in upper, lower, or mixed
+ case, they MUST always be recognized and processed in a case-
+ insensitive manner. This is simply an extension of practices
+ specified in RFC 821 and section 2.4.1.
+
+4.1.1.2 MAIL (MAIL)
+
+ This command is used to initiate a mail transaction in which the mail
+ data is delivered to an SMTP server which may, in turn, deliver it to
+ one or more mailboxes or pass it on to another system (possibly using
+ SMTP). The argument field contains a reverse-path and may contain
+ optional parameters. In general, the MAIL command may be sent only
+ when no mail transaction is in progress, see section 4.1.4.
+
+ The reverse-path consists of the sender mailbox. Historically, that
+ mailbox might optionally have been preceded by a list of hosts, but
+ that behavior is now deprecated (see appendix C). In some types of
+ reporting messages for which a reply is likely to cause a mail loop
+ (for example, mail delivery and nondelivery notifications), the
+ reverse-path may be null (see section 3.7).
+
+ This command clears the reverse-path buffer, the forward-path buffer,
+ and the mail data buffer; and inserts the reverse-path information
+ from this command into the reverse-path buffer.
+
+ If service extensions were negotiated, the MAIL command may also
+ carry parameters associated with a particular service extension.
+
+ Syntax:
+
+ "MAIL FROM:" ("<>" / Reverse-Path)
+ [SP Mail-parameters] CRLF
+
+4.1.1.3 RECIPIENT (RCPT)
+
+ This command is used to identify an individual recipient of the mail
+ data; multiple recipients are specified by multiple use of this
+ command. The argument field contains a forward-path and may contain
+ optional parameters.
+
+ The forward-path normally consists of the required destination
+ mailbox. Sending systems SHOULD not generate the optional list of
+ hosts known as a source route. Receiving systems MUST recognize
+
+
+
+
+Klensin Standards Track [Page 31]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ source route syntax but SHOULD strip off the source route
+ specification and utilize the domain name associated with the mailbox
+ as if the source route had not been provided.
+
+ Similarly, relay hosts SHOULD strip or ignore source routes, and
+ names MUST NOT be copied into the reverse-path. When mail reaches
+ its ultimate destination (the forward-path contains only a
+ destination mailbox), the SMTP server inserts it into the destination
+ mailbox in accordance with its host mail conventions.
+
+ For example, mail received at relay host xyz.com with envelope
+ commands
+
+ MAIL FROM:<userx@y.foo.org>
+ RCPT TO:<@hosta.int,@jkl.org:userc@d.bar.org>
+
+ will normally be sent directly on to host d.bar.org with envelope
+ commands
+
+ MAIL FROM:<userx@y.foo.org>
+ RCPT TO:<userc@d.bar.org>
+
+ As provided in appendix C, xyz.com MAY also choose to relay the
+ message to hosta.int, using the envelope commands
+
+ MAIL FROM:<userx@y.foo.org>
+ RCPT TO:<@hosta.int,@jkl.org:userc@d.bar.org>
+
+ or to jkl.org, using the envelope commands
+
+ MAIL FROM:<userx@y.foo.org>
+ RCPT TO:<@jkl.org:userc@d.bar.org>
+
+ Of course, since hosts are not required to relay mail at all, xyz.com
+ may also reject the message entirely when the RCPT command is
+ received, using a 550 code (since this is a "policy reason").
+
+ If service extensions were negotiated, the RCPT command may also
+ carry parameters associated with a particular service extension
+ offered by the server. The client MUST NOT transmit parameters other
+ than those associated with a service extension offered by the server
+ in its EHLO response.
+
+Syntax:
+ "RCPT TO:" ("<Postmaster@" domain ">" / "<Postmaster>" / Forward-Path)
+ [SP Rcpt-parameters] CRLF
+
+
+
+
+
+Klensin Standards Track [Page 32]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+4.1.1.4 DATA (DATA)
+
+ The receiver normally sends a 354 response to DATA, and then treats
+ the lines (strings ending in <CRLF> sequences, as described in
+ section 2.3.7) following the command as mail data from the sender.
+ This command causes the mail data to be appended to the mail data
+ buffer. The mail data may contain any of the 128 ASCII character
+ codes, although experience has indicated that use of control
+ characters other than SP, HT, CR, and LF may cause problems and
+ SHOULD be avoided when possible.
+
+ The mail data is terminated by a line containing only a period, that
+ is, the character sequence "<CRLF>.<CRLF>" (see section 4.5.2). This
+ is the end of mail data indication. Note that the first <CRLF> of
+ this terminating sequence is also the <CRLF> that ends the final line
+ of the data (message text) or, if there was no data, ends the DATA
+ command itself. An extra <CRLF> MUST NOT be added, as that would
+ cause an empty line to be added to the message. The only exception
+ to this rule would arise if the message body were passed to the
+ originating SMTP-sender with a final "line" that did not end in
+ <CRLF>; in that case, the originating SMTP system MUST either reject
+ the message as invalid or add <CRLF> in order to have the receiving
+ SMTP server recognize the "end of data" condition.
+
+ The custom of accepting lines ending only in <LF>, as a concession to
+ non-conforming behavior on the part of some UNIX systems, has proven
+ to cause more interoperability problems than it solves, and SMTP
+ server systems MUST NOT do this, even in the name of improved
+ robustness. In particular, the sequence "<LF>.<LF>" (bare line
+ feeds, without carriage returns) MUST NOT be treated as equivalent to
+ <CRLF>.<CRLF> as the end of mail data indication.
+
+ Receipt of the end of mail data indication requires the server to
+ process the stored mail transaction information. This processing
+ consumes the information in the reverse-path buffer, the forward-path
+ buffer, and the mail data buffer, and on the completion of this
+ command these buffers are cleared. If the processing is successful,
+ the receiver MUST send an OK reply. If the processing fails the
+ receiver MUST send a failure reply. The SMTP model does not allow
+ for partial failures at this point: either the message is accepted by
+ the server for delivery and a positive response is returned or it is
+ not accepted and a failure reply is returned. In sending a positive
+ completion reply to the end of data indication, the receiver takes
+ full responsibility for the message (see section 6.1). Errors that
+ are diagnosed subsequently MUST be reported in a mail message, as
+ discussed in section 4.4.
+
+
+
+
+
+Klensin Standards Track [Page 33]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ When the SMTP server accepts a message either for relaying or for
+ final delivery, it inserts a trace record (also referred to
+ interchangeably as a "time stamp line" or "Received" line) at the top
+ of the mail data. This trace record indicates the identity of the
+ host that sent the message, the identity of the host that received
+ the message (and is inserting this time stamp), and the date and time
+ the message was received. Relayed messages will have multiple time
+ stamp lines. Details for formation of these lines, including their
+ syntax, is specified in section 4.4.
+
+ Additional discussion about the operation of the DATA command appears
+ in section 3.3.
+
+ Syntax:
+ "DATA" CRLF
+
+4.1.1.5 RESET (RSET)
+
+ This command specifies that the current mail transaction will be
+ aborted. Any stored sender, recipients, and mail data MUST be
+ discarded, and all buffers and state tables cleared. The receiver
+ MUST send a "250 OK" reply to a RSET command with no arguments. A
+ reset command may be issued by the client at any time. It is
+ effectively equivalent to a NOOP (i.e., if has no effect) if issued
+ immediately after EHLO, before EHLO is issued in the session, after
+ an end-of-data indicator has been sent and acknowledged, or
+ immediately before a QUIT. An SMTP server MUST NOT close the
+ connection as the result of receiving a RSET; that action is reserved
+ for QUIT (see section 4.1.1.10).
+
+ Since EHLO implies some additional processing and response by the
+ server, RSET will normally be more efficient than reissuing that
+ command, even though the formal semantics are the same.
+
+ There are circumstances, contrary to the intent of this
+ specification, in which an SMTP server may receive an indication that
+ the underlying TCP connection has been closed or reset. To preserve
+ the robustness of the mail system, SMTP servers SHOULD be prepared
+ for this condition and SHOULD treat it as if a QUIT had been received
+ before the connection disappeared.
+
+ Syntax:
+ "RSET" CRLF
+
+
+
+
+
+
+
+
+Klensin Standards Track [Page 34]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+4.1.1.6 VERIFY (VRFY)
+
+ This command asks the receiver to confirm that the argument
+ identifies a user or mailbox. If it is a user name, information is
+ returned as specified in section 3.5.
+
+ This command has no effect on the reverse-path buffer, the forward-
+ path buffer, or the mail data buffer.
+
+ Syntax:
+ "VRFY" SP String CRLF
+
+4.1.1.7 EXPAND (EXPN)
+
+ This command asks the receiver to confirm that the argument
+ identifies a mailing list, and if so, to return the membership of
+ that list. If the command is successful, a reply is returned
+ containing information as described in section 3.5. This reply will
+ have multiple lines except in the trivial case of a one-member list.
+
+ This command has no effect on the reverse-path buffer, the forward-
+ path buffer, or the mail data buffer and may be issued at any time.
+
+ Syntax:
+ "EXPN" SP String CRLF
+
+4.1.1.8 HELP (HELP)
+
+ This command causes the server to send helpful information to the
+ client. The command MAY take an argument (e.g., any command name)
+ and return more specific information as a response.
+
+ This command has no effect on the reverse-path buffer, the forward-
+ path buffer, or the mail data buffer and may be issued at any time.
+
+ SMTP servers SHOULD support HELP without arguments and MAY support it
+ with arguments.
+
+ Syntax:
+ "HELP" [ SP String ] CRLF
+
+4.1.1.9 NOOP (NOOP)
+
+ This command does not affect any parameters or previously entered
+ commands. It specifies no action other than that the receiver send
+ an OK reply.
+
+
+
+
+
+Klensin Standards Track [Page 35]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ This command has no effect on the reverse-path buffer, the forward-
+ path buffer, or the mail data buffer and may be issued at any time.
+ If a parameter string is specified, servers SHOULD ignore it.
+
+ Syntax:
+ "NOOP" [ SP String ] CRLF
+
+4.1.1.10 QUIT (QUIT)
+
+ This command specifies that the receiver MUST send an OK reply, and
+ then close the transmission channel.
+
+ The receiver MUST NOT intentionally close the transmission channel
+ until it receives and replies to a QUIT command (even if there was an
+ error). The sender MUST NOT intentionally close the transmission
+ channel until it sends a QUIT command and SHOULD wait until it
+ receives the reply (even if there was an error response to a previous
+ command). If the connection is closed prematurely due to violations
+ of the above or system or network failure, the server MUST cancel any
+ pending transaction, but not undo any previously completed
+ transaction, and generally MUST act as if the command or transaction
+ in progress had received a temporary error (i.e., a 4yz response).
+
+ The QUIT command may be issued at any time.
+
+ Syntax:
+ "QUIT" CRLF
+
+4.1.2 Command Argument Syntax
+
+ The syntax of the argument fields of the above commands (using the
+ syntax specified in [8] where applicable) is given below. Some of
+ the productions given below are used only in conjunction with source
+ routes as described in appendix C. Terminals not defined in this
+ document, such as ALPHA, DIGIT, SP, CR, LF, CRLF, are as defined in
+ the "core" syntax [8 (section 6)] or in the message format syntax
+ [32].
+
+ Reverse-path = Path
+ Forward-path = Path
+ Path = "<" [ A-d-l ":" ] Mailbox ">"
+ A-d-l = At-domain *( "," A-d-l )
+ ; Note that this form, the so-called "source route",
+ ; MUST BE accepted, SHOULD NOT be generated, and SHOULD be
+ ; ignored.
+ At-domain = "@" domain
+ Mail-parameters = esmtp-param *(SP esmtp-param)
+ Rcpt-parameters = esmtp-param *(SP esmtp-param)
+
+
+
+Klensin Standards Track [Page 36]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ esmtp-param = esmtp-keyword ["=" esmtp-value]
+ esmtp-keyword = (ALPHA / DIGIT) *(ALPHA / DIGIT / "-")
+ esmtp-value = 1*(%d33-60 / %d62-127)
+ ; any CHAR excluding "=", SP, and control characters
+ Keyword = Ldh-str
+ Argument = Atom
+ Domain = (sub-domain 1*("." sub-domain)) / address-literal
+ sub-domain = Let-dig [Ldh-str]
+
+ address-literal = "[" IPv4-address-literal /
+ IPv6-address-literal /
+ General-address-literal "]"
+ ; See section 4.1.3
+
+ Mailbox = Local-part "@" Domain
+
+ Local-part = Dot-string / Quoted-string
+ ; MAY be case-sensitive
+
+ Dot-string = Atom *("." Atom)
+
+ Atom = 1*atext
+
+ Quoted-string = DQUOTE *qcontent DQUOTE
+
+ String = Atom / Quoted-string
+
+ While the above definition for Local-part is relatively permissive,
+ for maximum interoperability, a host that expects to receive mail
+ SHOULD avoid defining mailboxes where the Local-part requires (or
+ uses) the Quoted-string form or where the Local-part is case-
+ sensitive. For any purposes that require generating or comparing
+ Local-parts (e.g., to specific mailbox names), all quoted forms MUST
+ be treated as equivalent and the sending system SHOULD transmit the
+ form that uses the minimum quoting possible.
+
+ Systems MUST NOT define mailboxes in such a way as to require the use
+ in SMTP of non-ASCII characters (octets with the high order bit set
+ to one) or ASCII "control characters" (decimal value 0-31 and 127).
+ These characters MUST NOT be used in MAIL or RCPT commands or other
+ commands that require mailbox names.
+
+ Note that the backslash, "\", is a quote character, which is used to
+ indicate that the next character is to be used literally (instead of
+ its normal interpretation). For example, "Joe\,Smith" indicates a
+ single nine character user field with the comma being the fourth
+ character of the field.
+
+
+
+
+Klensin Standards Track [Page 37]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ To promote interoperability and consistent with long-standing
+ guidance about conservative use of the DNS in naming and applications
+ (e.g., see section 2.3.1 of the base DNS document, RFC1035 [22]),
+ characters outside the set of alphas, digits, and hyphen MUST NOT
+ appear in domain name labels for SMTP clients or servers. In
+ particular, the underscore character is not permitted. SMTP servers
+ that receive a command in which invalid character codes have been
+ employed, and for which there are no other reasons for rejection,
+ MUST reject that command with a 501 response.
+
+4.1.3 Address Literals
+
+ Sometimes a host is not known to the domain name system and
+ communication (and, in particular, communication to report and repair
+ the error) is blocked. To bypass this barrier a special literal form
+ of the address is allowed as an alternative to a domain name. For
+ IPv4 addresses, this form uses four small decimal integers separated
+ by dots and enclosed by brackets such as [123.255.37.2], which
+ indicates an (IPv4) Internet Address in sequence-of-octets form. For
+ IPv6 and other forms of addressing that might eventually be
+ standardized, the form consists of a standardized "tag" that
+ identifies the address syntax, a colon, and the address itself, in a
+ format specified as part of the IPv6 standards [17].
+
+ Specifically:
+
+ IPv4-address-literal = Snum 3("." Snum)
+ IPv6-address-literal = "IPv6:" IPv6-addr
+ General-address-literal = Standardized-tag ":" 1*dcontent
+ Standardized-tag = Ldh-str
+ ; MUST be specified in a standards-track RFC
+ ; and registered with IANA
+
+ Snum = 1*3DIGIT ; representing a decimal integer
+ ; value in the range 0 through 255
+ Let-dig = ALPHA / DIGIT
+ Ldh-str = *( ALPHA / DIGIT / "-" ) Let-dig
+
+ IPv6-addr = IPv6-full / IPv6-comp / IPv6v4-full / IPv6v4-comp
+ IPv6-hex = 1*4HEXDIG
+ IPv6-full = IPv6-hex 7(":" IPv6-hex)
+ IPv6-comp = [IPv6-hex *5(":" IPv6-hex)] "::" [IPv6-hex *5(":"
+ IPv6-hex)]
+ ; The "::" represents at least 2 16-bit groups of zeros
+ ; No more than 6 groups in addition to the "::" may be
+ ; present
+ IPv6v4-full = IPv6-hex 5(":" IPv6-hex) ":" IPv4-address-literal
+ IPv6v4-comp = [IPv6-hex *3(":" IPv6-hex)] "::"
+
+
+
+Klensin Standards Track [Page 38]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ [IPv6-hex *3(":" IPv6-hex) ":"] IPv4-address-literal
+ ; The "::" represents at least 2 16-bit groups of zeros
+ ; No more than 4 groups in addition to the "::" and
+ ; IPv4-address-literal may be present
+
+4.1.4 Order of Commands
+
+ There are restrictions on the order in which these commands may be
+ used.
+
+ A session that will contain mail transactions MUST first be
+ initialized by the use of the EHLO command. An SMTP server SHOULD
+ accept commands for non-mail transactions (e.g., VRFY or EXPN)
+ without this initialization.
+
+ An EHLO command MAY be issued by a client later in the session. If
+ it is issued after the session begins, the SMTP server MUST clear all
+ buffers and reset the state exactly as if a RSET command had been
+ issued. In other words, the sequence of RSET followed immediately by
+ EHLO is redundant, but not harmful other than in the performance cost
+ of executing unnecessary commands.
+
+ If the EHLO command is not acceptable to the SMTP server, 501, 500,
+ or 502 failure replies MUST be returned as appropriate. The SMTP
+ server MUST stay in the same state after transmitting these replies
+ that it was in before the EHLO was received.
+
+ The SMTP client MUST, if possible, ensure that the domain parameter
+ to the EHLO command is a valid principal host name (not a CNAME or MX
+ name) for its host. If this is not possible (e.g., when the client's
+ address is dynamically assigned and the client does not have an
+ obvious name), an address literal SHOULD be substituted for the
+ domain name and supplemental information provided that will assist in
+ identifying the client.
+
+ An SMTP server MAY verify that the domain name parameter in the EHLO
+ command actually corresponds to the IP address of the client.
+ However, the server MUST NOT refuse to accept a message for this
+ reason if the verification fails: the information about verification
+ failure is for logging and tracing only.
+
+ The NOOP, HELP, EXPN, VRFY, and RSET commands can be used at any time
+ during a session, or without previously initializing a session. SMTP
+ servers SHOULD process these normally (that is, not return a 503
+ code) even if no EHLO command has yet been received; clients SHOULD
+ open a session with EHLO before sending these commands.
+
+
+
+
+
+Klensin Standards Track [Page 39]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ If these rules are followed, the example in RFC 821 that shows "550
+ access denied to you" in response to an EXPN command is incorrect
+ unless an EHLO command precedes the EXPN or the denial of access is
+ based on the client's IP address or other authentication or
+ authorization-determining mechanisms.
+
+ The MAIL command (or the obsolete SEND, SOML, or SAML commands)
+ begins a mail transaction. Once started, a mail transaction consists
+ of a transaction beginning command, one or more RCPT commands, and a
+ DATA command, in that order. A mail transaction may be aborted by
+ the RSET (or a new EHLO) command. There may be zero or more
+ transactions in a session. MAIL (or SEND, SOML, or SAML) MUST NOT be
+ sent if a mail transaction is already open, i.e., it should be sent
+ only if no mail transaction had been started in the session, or it
+ the previous one successfully concluded with a successful DATA
+ command, or if the previous one was aborted with a RSET.
+
+ If the transaction beginning command argument is not acceptable, a
+ 501 failure reply MUST be returned and the SMTP server MUST stay in
+ the same state. If the commands in a transaction are out of order to
+ the degree that they cannot be processed by the server, a 503 failure
+ reply MUST be returned and the SMTP server MUST stay in the same
+ state.
+
+ The last command in a session MUST be the QUIT command. The QUIT
+ command cannot be used at any other time in a session, but SHOULD be
+ used by the client SMTP to request connection closure, even when no
+ session opening command was sent and accepted.
+
+4.1.5 Private-use Commands
+
+ As specified in section 2.2.2, commands starting in "X" may be used
+ by bilateral agreement between the client (sending) and server
+ (receiving) SMTP agents. An SMTP server that does not recognize such
+ a command is expected to reply with "500 Command not recognized". An
+ extended SMTP server MAY list the feature names associated with these
+ private commands in the response to the EHLO command.
+
+ Commands sent or accepted by SMTP systems that do not start with "X"
+ MUST conform to the requirements of section 2.2.2.
+
+4.2 SMTP Replies
+
+ Replies to SMTP commands serve to ensure the synchronization of
+ requests and actions in the process of mail transfer and to guarantee
+ that the SMTP client always knows the state of the SMTP server.
+ Every command MUST generate exactly one reply.
+
+
+
+
+Klensin Standards Track [Page 40]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ The details of the command-reply sequence are described in section
+ 4.3.
+
+ An SMTP reply consists of a three digit number (transmitted as three
+ numeric characters) followed by some text unless specified otherwise
+ in this document. The number is for use by automata to determine
+ what state to enter next; the text is for the human user. The three
+ digits contain enough encoded information that the SMTP client need
+ not examine the text and may either discard it or pass it on to the
+ user, as appropriate. Exceptions are as noted elsewhere in this
+ document. In particular, the 220, 221, 251, 421, and 551 reply codes
+ are associated with message text that must be parsed and interpreted
+ by machines. In the general case, the text may be receiver dependent
+ and context dependent, so there are likely to be varying texts for
+ each reply code. A discussion of the theory of reply codes is given
+ in section 4.2.1. Formally, a reply is defined to be the sequence: a
+ three-digit code, <SP>, one line of text, and <CRLF>, or a multiline
+ reply (as defined in section 4.2.1). Since, in violation of this
+ specification, the text is sometimes not sent, clients which do not
+ receive it SHOULD be prepared to process the code alone (with or
+ without a trailing space character). Only the EHLO, EXPN, and HELP
+ commands are expected to result in multiline replies in normal
+ circumstances, however, multiline replies are allowed for any
+ command.
+
+ In ABNF, server responses are:
+
+ Greeting = "220 " Domain [ SP text ] CRLF
+ Reply-line = Reply-code [ SP text ] CRLF
+
+ where "Greeting" appears only in the 220 response that announces that
+ the server is opening its part of the connection.
+
+ An SMTP server SHOULD send only the reply codes listed in this
+ document. An SMTP server SHOULD use the text shown in the examples
+ whenever appropriate.
+
+ An SMTP client MUST determine its actions only by the reply code, not
+ by the text (except for the "change of address" 251 and 551 and, if
+ necessary, 220, 221, and 421 replies); in the general case, any text,
+ including no text at all (although senders SHOULD NOT send bare
+ codes), MUST be acceptable. The space (blank) following the reply
+ code is considered part of the text. Whenever possible, a receiver-
+ SMTP SHOULD test the first digit (severity indication) of the reply
+ code.
+
+
+
+
+
+
+Klensin Standards Track [Page 41]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ The list of codes that appears below MUST NOT be construed as
+ permanent. While the addition of new codes should be a rare and
+ significant activity, with supplemental information in the textual
+ part of the response being preferred, new codes may be added as the
+ result of new Standards or Standards-track specifications.
+ Consequently, a sender-SMTP MUST be prepared to handle codes not
+ specified in this document and MUST do so by interpreting the first
+ digit only.
+
+4.2.1 Reply Code Severities and Theory
+
+ The three digits of the reply each have a special significance. The
+ first digit denotes whether the response is good, bad or incomplete.
+ An unsophisticated SMTP client, or one that receives an unexpected
+ code, will be able to determine its next action (proceed as planned,
+ redo, retrench, etc.) by examining this first digit. An SMTP client
+ that wants to know approximately what kind of error occurred (e.g.,
+ mail system error, command syntax error) may examine the second
+ digit. The third digit and any supplemental information that may be
+ present is reserved for the finest gradation of information.
+
+ There are five values for the first digit of the reply code:
+
+ 1yz Positive Preliminary reply
+ The command has been accepted, but the requested action is being
+ held in abeyance, pending confirmation of the information in this
+ reply. The SMTP client should send another command specifying
+ whether to continue or abort the action. Note: unextended SMTP
+ does not have any commands that allow this type of reply, and so
+ does not have continue or abort commands.
+
+ 2yz Positive Completion reply
+ The requested action has been successfully completed. A new
+ request may be initiated.
+
+ 3yz Positive Intermediate reply
+ The command has been accepted, but the requested action is being
+ held in abeyance, pending receipt of further information. The
+ SMTP client should send another command specifying this
+ information. This reply is used in command sequence groups (i.e.,
+ in DATA).
+
+ 4yz Transient Negative Completion reply
+ The command was not accepted, and the requested action did not
+ occur. However, the error condition is temporary and the action
+ may be requested again. The sender should return to the beginning
+ of the command sequence (if any). It is difficult to assign a
+ meaning to "transient" when two different sites (receiver- and
+
+
+
+Klensin Standards Track [Page 42]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ sender-SMTP agents) must agree on the interpretation. Each reply
+ in this category might have a different time value, but the SMTP
+ client is encouraged to try again. A rule of thumb to determine
+ whether a reply fits into the 4yz or the 5yz category (see below)
+ is that replies are 4yz if they can be successful if repeated
+ without any change in command form or in properties of the sender
+ or receiver (that is, the command is repeated identically and the
+ receiver does not put up a new implementation.)
+
+ 5yz Permanent Negative Completion reply
+ The command was not accepted and the requested action did not
+ occur. The SMTP client is discouraged from repeating the exact
+ request (in the same sequence). Even some "permanent" error
+ conditions can be corrected, so the human user may want to direct
+ the SMTP client to reinitiate the command sequence by direct
+ action at some point in the future (e.g., after the spelling has
+ been changed, or the user has altered the account status).
+
+ The second digit encodes responses in specific categories:
+
+ x0z Syntax: These replies refer to syntax errors, syntactically
+ correct commands that do not fit any functional category, and
+ unimplemented or superfluous commands.
+
+ x1z Information: These are replies to requests for information,
+ such as status or help.
+
+ x2z Connections: These are replies referring to the transmission
+ channel.
+
+ x3z Unspecified.
+
+ x4z Unspecified.
+
+ x5z Mail system: These replies indicate the status of the receiver
+ mail system vis-a-vis the requested transfer or other mail system
+ action.
+
+ The third digit gives a finer gradation of meaning in each category
+ specified by the second digit. The list of replies illustrates this.
+ Each reply text is recommended rather than mandatory, and may even
+ change according to the command with which it is associated. On the
+ other hand, the reply codes must strictly follow the specifications
+ in this section. Receiver implementations should not invent new
+ codes for slightly different situations from the ones described here,
+ but rather adapt codes already defined.
+
+
+
+
+
+Klensin Standards Track [Page 43]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ For example, a command such as NOOP, whose successful execution does
+ not offer the SMTP client any new information, will return a 250
+ reply. The reply is 502 when the command requests an unimplemented
+ non-site-specific action. A refinement of that is the 504 reply for
+ a command that is implemented, but that requests an unimplemented
+ parameter.
+
+ The reply text may be longer than a single line; in these cases the
+ complete text must be marked so the SMTP client knows when it can
+ stop reading the reply. This requires a special format to indicate a
+ multiple line reply.
+
+ The format for multiline replies requires that every line, except the
+ last, begin with the reply code, followed immediately by a hyphen,
+ "-" (also known as minus), followed by text. The last line will
+ begin with the reply code, followed immediately by <SP>, optionally
+ some text, and <CRLF>. As noted above, servers SHOULD send the <SP>
+ if subsequent text is not sent, but clients MUST be prepared for it
+ to be omitted.
+
+ For example:
+
+ 123-First line
+ 123-Second line
+ 123-234 text beginning with numbers
+ 123 The last line
+
+ In many cases the SMTP client then simply needs to search for a line
+ beginning with the reply code followed by <SP> or <CRLF> and ignore
+ all preceding lines. In a few cases, there is important data for the
+ client in the reply "text". The client will be able to identify
+ these cases from the current context.
+
+4.2.2 Reply Codes by Function Groups
+
+ 500 Syntax error, command unrecognized
+ (This may include errors such as command line too long)
+ 501 Syntax error in parameters or arguments
+ 502 Command not implemented (see section 4.2.4)
+ 503 Bad sequence of commands
+ 504 Command parameter not implemented
+
+ 211 System status, or system help reply
+ 214 Help message
+ (Information on how to use the receiver or the meaning of a
+ particular non-standard command; this reply is useful only
+ to the human user)
+
+
+
+
+Klensin Standards Track [Page 44]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ 220 <domain> Service ready
+ 221 <domain> Service closing transmission channel
+ 421 <domain> Service not available, closing transmission channel
+ (This may be a reply to any command if the service knows it
+ must shut down)
+
+ 250 Requested mail action okay, completed
+ 251 User not local; will forward to <forward-path>
+ (See section 3.4)
+ 252 Cannot VRFY user, but will accept message and attempt
+ delivery
+ (See section 3.5.3)
+ 450 Requested mail action not taken: mailbox unavailable
+ (e.g., mailbox busy)
+ 550 Requested action not taken: mailbox unavailable
+ (e.g., mailbox not found, no access, or command rejected
+ for policy reasons)
+ 451 Requested action aborted: error in processing
+ 551 User not local; please try <forward-path>
+ (See section 3.4)
+ 452 Requested action not taken: insufficient system storage
+ 552 Requested mail action aborted: exceeded storage allocation
+ 553 Requested action not taken: mailbox name not allowed
+ (e.g., mailbox syntax incorrect)
+ 354 Start mail input; end with <CRLF>.<CRLF>
+ 554 Transaction failed (Or, in the case of a connection-opening
+ response, "No SMTP service here")
+
+4.2.3 Reply Codes in Numeric Order
+
+ 211 System status, or system help reply
+ 214 Help message
+ (Information on how to use the receiver or the meaning of a
+ particular non-standard command; this reply is useful only
+ to the human user)
+ 220 <domain> Service ready
+ 221 <domain> Service closing transmission channel
+ 250 Requested mail action okay, completed
+ 251 User not local; will forward to <forward-path>
+ (See section 3.4)
+ 252 Cannot VRFY user, but will accept message and attempt
+ delivery
+ (See section 3.5.3)
+
+ 354 Start mail input; end with <CRLF>.<CRLF>
+
+
+
+
+
+
+Klensin Standards Track [Page 45]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ 421 <domain> Service not available, closing transmission channel
+ (This may be a reply to any command if the service knows it
+ must shut down)
+ 450 Requested mail action not taken: mailbox unavailable
+ (e.g., mailbox busy)
+ 451 Requested action aborted: local error in processing
+ 452 Requested action not taken: insufficient system storage
+ 500 Syntax error, command unrecognized
+ (This may include errors such as command line too long)
+ 501 Syntax error in parameters or arguments
+ 502 Command not implemented (see section 4.2.4)
+ 503 Bad sequence of commands
+ 504 Command parameter not implemented
+ 550 Requested action not taken: mailbox unavailable
+ (e.g., mailbox not found, no access, or command rejected
+ for policy reasons)
+ 551 User not local; please try <forward-path>
+ (See section 3.4)
+ 552 Requested mail action aborted: exceeded storage allocation
+ 553 Requested action not taken: mailbox name not allowed
+ (e.g., mailbox syntax incorrect)
+ 554 Transaction failed (Or, in the case of a connection-opening
+ response, "No SMTP service here")
+
+4.2.4 Reply Code 502
+
+ Questions have been raised as to when reply code 502 (Command not
+ implemented) SHOULD be returned in preference to other codes. 502
+ SHOULD be used when the command is actually recognized by the SMTP
+ server, but not implemented. If the command is not recognized, code
+ 500 SHOULD be returned. Extended SMTP systems MUST NOT list
+ capabilities in response to EHLO for which they will return 502 (or
+ 500) replies.
+
+4.2.5 Reply Codes After DATA and the Subsequent <CRLF>.<CRLF>
+
+ When an SMTP server returns a positive completion status (2yz code)
+ after the DATA command is completed with <CRLF>.<CRLF>, it accepts
+ responsibility for:
+
+ - delivering the message (if the recipient mailbox exists), or
+
+ - if attempts to deliver the message fail due to transient
+ conditions, retrying delivery some reasonable number of times at
+ intervals as specified in section 4.5.4.
+
+
+
+
+
+
+Klensin Standards Track [Page 46]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ - if attempts to deliver the message fail due to permanent
+ conditions, or if repeated attempts to deliver the message fail
+ due to transient conditions, returning appropriate notification to
+ the sender of the original message (using the address in the SMTP
+ MAIL command).
+
+ When an SMTP server returns a permanent error status (5yz) code after
+ the DATA command is completed with <CRLF>.<CRLF>, it MUST NOT make
+ any subsequent attempt to deliver that message. The SMTP client
+ retains responsibility for delivery of that message and may either
+ return it to the user or requeue it for a subsequent attempt (see
+ section 4.5.4.1).
+
+ The user who originated the message SHOULD be able to interpret the
+ return of a transient failure status (by mail message or otherwise)
+ as a non-delivery indication, just as a permanent failure would be
+ interpreted. I.e., if the client SMTP successfully handles these
+ conditions, the user will not receive such a reply.
+
+ When an SMTP server returns a permanent error status (5yz) code after
+ the DATA command is completely with <CRLF>.<CRLF>, it MUST NOT make
+ any subsequent attempt to deliver the message. As with temporary
+ error status codes, the SMTP client retains responsibility for the
+ message, but SHOULD not again attempt delivery to the same server
+ without user review and intervention of the message.
+
+4.3 Sequencing of Commands and Replies
+
+4.3.1 Sequencing Overview
+
+ The communication between the sender and receiver is an alternating
+ dialogue, controlled by the sender. As such, the sender issues a
+ command and the receiver responds with a reply. Unless other
+ arrangements are negotiated through service extensions, the sender
+ MUST wait for this response before sending further commands.
+
+ One important reply is the connection greeting. Normally, a receiver
+ will send a 220 "Service ready" reply when the connection is
+ completed. The sender SHOULD wait for this greeting message before
+ sending any commands.
+
+ Note: all the greeting-type replies have the official name (the
+ fully-qualified primary domain name) of the server host as the first
+ word following the reply code. Sometimes the host will have no
+ meaningful name. See 4.1.3 for a discussion of alternatives in these
+ situations.
+
+
+
+
+
+Klensin Standards Track [Page 47]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ For example,
+
+ 220 ISIF.USC.EDU Service ready
+ or
+ 220 mail.foo.com SuperSMTP v 6.1.2 Service ready
+ or
+ 220 [10.0.0.1] Clueless host service ready
+
+ The table below lists alternative success and failure replies for
+ each command. These SHOULD be strictly adhered to: a receiver may
+ substitute text in the replies, but the meaning and action implied by
+ the code numbers and by the specific command reply sequence cannot be
+ altered.
+
+4.3.2 Command-Reply Sequences
+
+ Each command is listed with its usual possible replies. The prefixes
+ used before the possible replies are "I" for intermediate, "S" for
+ success, and "E" for error. Since some servers may generate other
+ replies under special circumstances, and to allow for future
+ extension, SMTP clients SHOULD, when possible, interpret only the
+ first digit of the reply and MUST be prepared to deal with
+ unrecognized reply codes by interpreting the first digit only.
+ Unless extended using the mechanisms described in section 2.2, SMTP
+ servers MUST NOT transmit reply codes to an SMTP client that are
+ other than three digits or that do not start in a digit between 2 and
+ 5 inclusive.
+
+ These sequencing rules and, in principle, the codes themselves, can
+ be extended or modified by SMTP extensions offered by the server and
+ accepted (requested) by the client.
+
+ In addition to the codes listed below, any SMTP command can return
+ any of the following codes if the corresponding unusual circumstances
+ are encountered:
+
+ 500 For the "command line too long" case or if the command name was
+ not recognized. Note that producing a "command not recognized"
+ error in response to the required subset of these commands is a
+ violation of this specification.
+
+ 501 Syntax error in command or arguments. In order to provide for
+ future extensions, commands that are specified in this document as
+ not accepting arguments (DATA, RSET, QUIT) SHOULD return a 501
+ message if arguments are supplied in the absence of EHLO-
+ advertised extensions.
+
+ 421 Service shutting down and closing transmission channel
+
+
+
+Klensin Standards Track [Page 48]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ Specific sequences are:
+
+ CONNECTION ESTABLISHMENT
+ S: 220
+ E: 554
+ EHLO or HELO
+ S: 250
+ E: 504, 550
+ MAIL
+ S: 250
+ E: 552, 451, 452, 550, 553, 503
+ RCPT
+ S: 250, 251 (but see section 3.4 for discussion of 251 and 551)
+ E: 550, 551, 552, 553, 450, 451, 452, 503, 550
+ DATA
+ I: 354 -> data -> S: 250
+ E: 552, 554, 451, 452
+ E: 451, 554, 503
+ RSET
+ S: 250
+ VRFY
+ S: 250, 251, 252
+ E: 550, 551, 553, 502, 504
+ EXPN
+ S: 250, 252
+ E: 550, 500, 502, 504
+ HELP
+ S: 211, 214
+ E: 502, 504
+ NOOP
+ S: 250
+ QUIT
+ S: 221
+
+4.4 Trace Information
+
+ When an SMTP server receives a message for delivery or further
+ processing, it MUST insert trace ("time stamp" or "Received")
+ information at the beginning of the message content, as discussed in
+ section 4.1.1.4.
+
+ This line MUST be structured as follows:
+
+ - The FROM field, which MUST be supplied in an SMTP environment,
+ SHOULD contain both (1) the name of the source host as presented
+ in the EHLO command and (2) an address literal containing the IP
+ address of the source, determined from the TCP connection.
+
+
+
+
+Klensin Standards Track [Page 49]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ - The ID field MAY contain an "@" as suggested in RFC 822, but this
+ is not required.
+
+ - The FOR field MAY contain a list of <path> entries when multiple
+ RCPT commands have been given. This may raise some security
+ issues and is usually not desirable; see section 7.2.
+
+ An Internet mail program MUST NOT change a Received: line that was
+ previously added to the message header. SMTP servers MUST prepend
+ Received lines to messages; they MUST NOT change the order of
+ existing lines or insert Received lines in any other location.
+
+ As the Internet grows, comparability of Received fields is important
+ for detecting problems, especially slow relays. SMTP servers that
+ create Received fields SHOULD use explicit offsets in the dates
+ (e.g., -0800), rather than time zone names of any type. Local time
+ (with an offset) is preferred to UT when feasible. This formulation
+ allows slightly more information about local circumstances to be
+ specified. If UT is needed, the receiver need merely do some simple
+ arithmetic to convert the values. Use of UT loses information about
+ the time zone-location of the server. If it is desired to supply a
+ time zone name, it SHOULD be included in a comment.
+
+ When the delivery SMTP server makes the "final delivery" of a
+ message, it inserts a return-path line at the beginning of the mail
+ data. This use of return-path is required; mail systems MUST support
+ it. The return-path line preserves the information in the <reverse-
+ path> from the MAIL command. Here, final delivery means the message
+ has left the SMTP environment. Normally, this would mean it had been
+ delivered to the destination user or an associated mail drop, but in
+ some cases it may be further processed and transmitted by another
+ mail system.
+
+ It is possible for the mailbox in the return path to be different
+ from the actual sender's mailbox, for example, if error responses are
+ to be delivered to a special error handling mailbox rather than to
+ the message sender. When mailing lists are involved, this
+ arrangement is common and useful as a means of directing errors to
+ the list maintainer rather than the message originator.
+
+ The text above implies that the final mail data will begin with a
+ return path line, followed by one or more time stamp lines. These
+ lines will be followed by the mail data headers and body [32].
+
+ It is sometimes difficult for an SMTP server to determine whether or
+ not it is making final delivery since forwarding or other operations
+ may occur after the message is accepted for delivery. Consequently,
+
+
+
+
+Klensin Standards Track [Page 50]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ any further (forwarding, gateway, or relay) systems MAY remove the
+ return path and rebuild the MAIL command as needed to ensure that
+ exactly one such line appears in a delivered message.
+
+ A message-originating SMTP system SHOULD NOT send a message that
+ already contains a Return-path header. SMTP servers performing a
+ relay function MUST NOT inspect the message data, and especially not
+ to the extent needed to determine if Return-path headers are present.
+ SMTP servers making final delivery MAY remove Return-path headers
+ before adding their own.
+
+ The primary purpose of the Return-path is to designate the address to
+ which messages indicating non-delivery or other mail system failures
+ are to be sent. For this to be unambiguous, exactly one return path
+ SHOULD be present when the message is delivered. Systems using RFC
+ 822 syntax with non-SMTP transports SHOULD designate an unambiguous
+ address, associated with the transport envelope, to which error
+ reports (e.g., non-delivery messages) should be sent.
+
+ Historical note: Text in RFC 822 that appears to contradict the use
+ of the Return-path header (or the envelope reverse path address from
+ the MAIL command) as the destination for error messages is not
+ applicable on the Internet. The reverse path address (as copied into
+ the Return-path) MUST be used as the target of any mail containing
+ delivery error messages.
+
+ In particular:
+
+ - a gateway from SMTP->elsewhere SHOULD insert a return-path header,
+ unless it is known that the "elsewhere" transport also uses
+ Internet domain addresses and maintains the envelope sender
+ address separately.
+
+ - a gateway from elsewhere->SMTP SHOULD delete any return-path
+ header present in the message, and either copy that information to
+ the SMTP envelope or combine it with information present in the
+ envelope of the other transport system to construct the reverse
+ path argument to the MAIL command in the SMTP envelope.
+
+ The server must give special treatment to cases in which the
+ processing following the end of mail data indication is only
+ partially successful. This could happen if, after accepting several
+ recipients and the mail data, the SMTP server finds that the mail
+ data could be successfully delivered to some, but not all, of the
+ recipients. In such cases, the response to the DATA command MUST be
+ an OK reply. However, the SMTP server MUST compose and send an
+ "undeliverable mail" notification message to the originator of the
+ message.
+
+
+
+Klensin Standards Track [Page 51]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ A single notification listing all of the failed recipients or
+ separate notification messages MUST be sent for each failed
+ recipient. For economy of processing by the sender, the former is
+ preferred when possible. All undeliverable mail notification
+ messages are sent using the MAIL command (even if they result from
+ processing the obsolete SEND, SOML, or SAML commands) and use a null
+ return path as discussed in section 3.7.
+
+ The time stamp line and the return path line are formally defined as
+ follows:
+
+Return-path-line = "Return-Path:" FWS Reverse-path <CRLF>
+
+Time-stamp-line = "Received:" FWS Stamp <CRLF>
+
+Stamp = From-domain By-domain Opt-info ";" FWS date-time
+
+ ; where "date-time" is as defined in [32]
+ ; but the "obs-" forms, especially two-digit
+ ; years, are prohibited in SMTP and MUST NOT be used.
+
+From-domain = "FROM" FWS Extended-Domain CFWS
+
+By-domain = "BY" FWS Extended-Domain CFWS
+
+Extended-Domain = Domain /
+ ( Domain FWS "(" TCP-info ")" ) /
+ ( Address-literal FWS "(" TCP-info ")" )
+
+TCP-info = Address-literal / ( Domain FWS Address-literal )
+ ; Information derived by server from TCP connection
+ ; not client EHLO.
+
+Opt-info = [Via] [With] [ID] [For]
+
+Via = "VIA" FWS Link CFWS
+
+With = "WITH" FWS Protocol CFWS
+
+ID = "ID" FWS String / msg-id CFWS
+
+For = "FOR" FWS 1*( Path / Mailbox ) CFWS
+
+Link = "TCP" / Addtl-Link
+Addtl-Link = Atom
+ ; Additional standard names for links are registered with the
+ ; Internet Assigned Numbers Authority (IANA). "Via" is
+ ; primarily of value with non-Internet transports. SMTP
+
+
+
+Klensin Standards Track [Page 52]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ ; servers SHOULD NOT use unregistered names.
+Protocol = "ESMTP" / "SMTP" / Attdl-Protocol
+Attdl-Protocol = Atom
+ ; Additional standard names for protocols are registered with the
+ ; Internet Assigned Numbers Authority (IANA). SMTP servers
+ ; SHOULD NOT use unregistered names.
+
+4.5 Additional Implementation Issues
+
+4.5.1 Minimum Implementation
+
+ In order to make SMTP workable, the following minimum implementation
+ is required for all receivers. The following commands MUST be
+ supported to conform to this specification:
+
+ EHLO
+ HELO
+ MAIL
+ RCPT
+ DATA
+ RSET
+ NOOP
+ QUIT
+ VRFY
+
+ Any system that includes an SMTP server supporting mail relaying or
+ delivery MUST support the reserved mailbox "postmaster" as a case-
+ insensitive local name. This postmaster address is not strictly
+ necessary if the server always returns 554 on connection opening (as
+ described in section 3.1). The requirement to accept mail for
+ postmaster implies that RCPT commands which specify a mailbox for
+ postmaster at any of the domains for which the SMTP server provides
+ mail service, as well as the special case of "RCPT TO:<Postmaster>"
+ (with no domain specification), MUST be supported.
+
+ SMTP systems are expected to make every reasonable effort to accept
+ mail directed to Postmaster from any other system on the Internet.
+ In extreme cases --such as to contain a denial of service attack or
+ other breach of security-- an SMTP server may block mail directed to
+ Postmaster. However, such arrangements SHOULD be narrowly tailored
+ so as to avoid blocking messages which are not part of such attacks.
+
+4.5.2 Transparency
+
+ Without some provision for data transparency, the character sequence
+ "<CRLF>.<CRLF>" ends the mail text and cannot be sent by the user.
+ In general, users are not aware of such "forbidden" sequences. To
+
+
+
+
+Klensin Standards Track [Page 53]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ allow all user composed text to be transmitted transparently, the
+ following procedures are used:
+
+ - Before sending a line of mail text, the SMTP client checks the
+ first character of the line. If it is a period, one additional
+ period is inserted at the beginning of the line.
+
+ - When a line of mail text is received by the SMTP server, it checks
+ the line. If the line is composed of a single period, it is
+ treated as the end of mail indicator. If the first character is a
+ period and there are other characters on the line, the first
+ character is deleted.
+
+ The mail data may contain any of the 128 ASCII characters. All
+ characters are to be delivered to the recipient's mailbox, including
+ spaces, vertical and horizontal tabs, and other control characters.
+ If the transmission channel provides an 8-bit byte (octet) data
+ stream, the 7-bit ASCII codes are transmitted right justified in the
+ octets, with the high order bits cleared to zero. See 3.7 for
+ special treatment of these conditions in SMTP systems serving a relay
+ function.
+
+ In some systems it may be necessary to transform the data as it is
+ received and stored. This may be necessary for hosts that use a
+ different character set than ASCII as their local character set, that
+ store data in records rather than strings, or which use special
+ character sequences as delimiters inside mailboxes. If such
+ transformations are necessary, they MUST be reversible, especially if
+ they are applied to mail being relayed.
+
+4.5.3 Sizes and Timeouts
+
+4.5.3.1 Size limits and minimums
+
+ There are several objects that have required minimum/maximum sizes.
+ Every implementation MUST be able to receive objects of at least
+ these sizes. Objects larger than these sizes SHOULD be avoided when
+ possible. However, some Internet mail constructs such as encoded
+ X.400 addresses [16] will often require larger objects: clients MAY
+ attempt to transmit these, but MUST be prepared for a server to
+ reject them if they cannot be handled by it. To the maximum extent
+ possible, implementation techniques which impose no limits on the
+ length of these objects should be used.
+
+ local-part
+ The maximum total length of a user name or other local-part is 64
+ characters.
+
+
+
+
+Klensin Standards Track [Page 54]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ domain
+ The maximum total length of a domain name or number is 255
+ characters.
+
+ path
+ The maximum total length of a reverse-path or forward-path is 256
+ characters (including the punctuation and element separators).
+
+ command line
+ The maximum total length of a command line including the command
+ word and the <CRLF> is 512 characters. SMTP extensions may be
+ used to increase this limit.
+
+ reply line
+ The maximum total length of a reply line including the reply code
+ and the <CRLF> is 512 characters. More information may be
+ conveyed through multiple-line replies.
+
+ text line
+ The maximum total length of a text line including the <CRLF> is
+ 1000 characters (not counting the leading dot duplicated for
+ transparency). This number may be increased by the use of SMTP
+ Service Extensions.
+
+ message content
+ The maximum total length of a message content (including any
+ message headers as well as the message body) MUST BE at least 64K
+ octets. Since the introduction of Internet standards for
+ multimedia mail [12], message lengths on the Internet have grown
+ dramatically, and message size restrictions should be avoided if
+ at all possible. SMTP server systems that must impose
+ restrictions SHOULD implement the "SIZE" service extension [18],
+ and SMTP client systems that will send large messages SHOULD
+ utilize it when possible.
+
+ recipients buffer
+ The minimum total number of recipients that must be buffered is
+ 100 recipients. Rejection of messages (for excessive recipients)
+ with fewer than 100 RCPT commands is a violation of this
+ specification. The general principle that relaying SMTP servers
+ MUST NOT, and delivery SMTP servers SHOULD NOT, perform validation
+ tests on message headers suggests that rejecting a message based
+ on the total number of recipients shown in header fields is to be
+ discouraged. A server which imposes a limit on the number of
+ recipients MUST behave in an orderly fashion, such as to reject
+ additional addresses over its limit rather than silently
+ discarding addresses previously accepted. A client that needs to
+
+
+
+
+Klensin Standards Track [Page 55]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ deliver a message containing over 100 RCPT commands SHOULD be
+ prepared to transmit in 100-recipient "chunks" if the server
+ declines to accept more than 100 recipients in a single message.
+
+ Errors due to exceeding these limits may be reported by using the
+ reply codes. Some examples of reply codes are:
+
+ 500 Line too long.
+ or
+ 501 Path too long
+ or
+ 452 Too many recipients (see below)
+ or
+ 552 Too much mail data.
+
+ RFC 821 [30] incorrectly listed the error where an SMTP server
+ exhausts its implementation limit on the number of RCPT commands
+ ("too many recipients") as having reply code 552. The correct reply
+ code for this condition is 452. Clients SHOULD treat a 552 code in
+ this case as a temporary, rather than permanent, failure so the logic
+ below works.
+
+ When a conforming SMTP server encounters this condition, it has at
+ least 100 successful RCPT commands in its recipients buffer. If the
+ server is able to accept the message, then at least these 100
+ addresses will be removed from the SMTP client's queue. When the
+ client attempts retransmission of those addresses which received 452
+ responses, at least 100 of these will be able to fit in the SMTP
+ server's recipients buffer. Each retransmission attempt which is
+ able to deliver anything will be able to dispose of at least 100 of
+ these recipients.
+
+ If an SMTP server has an implementation limit on the number of RCPT
+ commands and this limit is exhausted, it MUST use a response code of
+ 452 (but the client SHOULD also be prepared for a 552, as noted
+ above). If the server has a configured site-policy limitation on the
+ number of RCPT commands, it MAY instead use a 5XX response code.
+ This would be most appropriate if the policy limitation was intended
+ to apply if the total recipient count for a particular message body
+ were enforced even if that message body was sent in multiple mail
+ transactions.
+
+4.5.3.2 Timeouts
+
+ An SMTP client MUST provide a timeout mechanism. It MUST use per-
+ command timeouts rather than somehow trying to time the entire mail
+ transaction. Timeouts SHOULD be easily reconfigurable, preferably
+ without recompiling the SMTP code. To implement this, a timer is set
+
+
+
+Klensin Standards Track [Page 56]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ for each SMTP command and for each buffer of the data transfer. The
+ latter means that the overall timeout is inherently proportional to
+ the size of the message.
+
+ Based on extensive experience with busy mail-relay hosts, the minimum
+ per-command timeout values SHOULD be as follows:
+
+ Initial 220 Message: 5 minutes
+ An SMTP client process needs to distinguish between a failed TCP
+ connection and a delay in receiving the initial 220 greeting
+ message. Many SMTP servers accept a TCP connection but delay
+ delivery of the 220 message until their system load permits more
+ mail to be processed.
+
+ MAIL Command: 5 minutes
+
+ RCPT Command: 5 minutes
+ A longer timeout is required if processing of mailing lists and
+ aliases is not deferred until after the message was accepted.
+
+ DATA Initiation: 2 minutes
+ This is while awaiting the "354 Start Input" reply to a DATA
+ command.
+
+ Data Block: 3 minutes
+ This is while awaiting the completion of each TCP SEND call
+ transmitting a chunk of data.
+
+ DATA Termination: 10 minutes.
+ This is while awaiting the "250 OK" reply. When the receiver gets
+ the final period terminating the message data, it typically
+ performs processing to deliver the message to a user mailbox. A
+ spurious timeout at this point would be very wasteful and would
+ typically result in delivery of multiple copies of the message,
+ since it has been successfully sent and the server has accepted
+ responsibility for delivery. See section 6.1 for additional
+ discussion.
+
+ An SMTP server SHOULD have a timeout of at least 5 minutes while it
+ is awaiting the next command from the sender.
+
+4.5.4 Retry Strategies
+
+ The common structure of a host SMTP implementation includes user
+ mailboxes, one or more areas for queuing messages in transit, and one
+ or more daemon processes for sending and receiving mail. The exact
+ structure will vary depending on the needs of the users on the host
+
+
+
+
+Klensin Standards Track [Page 57]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ and the number and size of mailing lists supported by the host. We
+ describe several optimizations that have proved helpful, particularly
+ for mailers supporting high traffic levels.
+
+ Any queuing strategy MUST include timeouts on all activities on a
+ per-command basis. A queuing strategy MUST NOT send error messages
+ in response to error messages under any circumstances.
+
+4.5.4.1 Sending Strategy
+
+ The general model for an SMTP client is one or more processes that
+ periodically attempt to transmit outgoing mail. In a typical system,
+ the program that composes a message has some method for requesting
+ immediate attention for a new piece of outgoing mail, while mail that
+ cannot be transmitted immediately MUST be queued and periodically
+ retried by the sender. A mail queue entry will include not only the
+ message itself but also the envelope information.
+
+ The sender MUST delay retrying a particular destination after one
+ attempt has failed. In general, the retry interval SHOULD be at
+ least 30 minutes; however, more sophisticated and variable strategies
+ will be beneficial when the SMTP client can determine the reason for
+ non-delivery.
+
+ Retries continue until the message is transmitted or the sender gives
+ up; the give-up time generally needs to be at least 4-5 days. The
+ parameters to the retry algorithm MUST be configurable.
+
+ A client SHOULD keep a list of hosts it cannot reach and
+ corresponding connection timeouts, rather than just retrying queued
+ mail items.
+
+ Experience suggests that failures are typically transient (the target
+ system or its connection has crashed), favoring a policy of two
+ connection attempts in the first hour the message is in the queue,
+ and then backing off to one every two or three hours.
+
+ The SMTP client can shorten the queuing delay in cooperation with the
+ SMTP server. For example, if mail is received from a particular
+ address, it is likely that mail queued for that host can now be sent.
+ Application of this principle may, in many cases, eliminate the
+ requirement for an explicit "send queues now" function such as ETRN
+ [9].
+
+ The strategy may be further modified as a result of multiple
+ addresses per host (see below) to optimize delivery time vs. resource
+ usage.
+
+
+
+
+Klensin Standards Track [Page 58]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ An SMTP client may have a large queue of messages for each
+ unavailable destination host. If all of these messages were retried
+ in every retry cycle, there would be excessive Internet overhead and
+ the sending system would be blocked for a long period. Note that an
+ SMTP client can generally determine that a delivery attempt has
+ failed only after a timeout of several minutes and even a one-minute
+ timeout per connection will result in a very large delay if retries
+ are repeated for dozens, or even hundreds, of queued messages to the
+ same host.
+
+ At the same time, SMTP clients SHOULD use great care in caching
+ negative responses from servers. In an extreme case, if EHLO is
+ issued multiple times during the same SMTP connection, different
+ answers may be returned by the server. More significantly, 5yz
+ responses to the MAIL command MUST NOT be cached.
+
+ When a mail message is to be delivered to multiple recipients, and
+ the SMTP server to which a copy of the message is to be sent is the
+ same for multiple recipients, then only one copy of the message
+ SHOULD be transmitted. That is, the SMTP client SHOULD use the
+ command sequence: MAIL, RCPT, RCPT,... RCPT, DATA instead of the
+ sequence: MAIL, RCPT, DATA, ..., MAIL, RCPT, DATA. However, if there
+ are very many addresses, a limit on the number of RCPT commands per
+ MAIL command MAY be imposed. Implementation of this efficiency
+ feature is strongly encouraged.
+
+ Similarly, to achieve timely delivery, the SMTP client MAY support
+ multiple concurrent outgoing mail transactions. However, some limit
+ may be appropriate to protect the host from devoting all its
+ resources to mail.
+
+4.5.4.2 Receiving Strategy
+
+ The SMTP server SHOULD attempt to keep a pending listen on the SMTP
+ port at all times. This requires the support of multiple incoming
+ TCP connections for SMTP. Some limit MAY be imposed but servers that
+ cannot handle more than one SMTP transaction at a time are not in
+ conformance with the intent of this specification.
+
+ As discussed above, when the SMTP server receives mail from a
+ particular host address, it could activate its own SMTP queuing
+ mechanisms to retry any mail pending for that host address.
+
+4.5.5 Messages with a null reverse-path
+
+ There are several types of notification messages which are required
+ by existing and proposed standards to be sent with a null reverse
+ path, namely non-delivery notifications as discussed in section 3.7,
+
+
+
+Klensin Standards Track [Page 59]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ other kinds of Delivery Status Notifications (DSNs) [24], and also
+ Message Disposition Notifications (MDNs) [10]. All of these kinds of
+ messages are notifications about a previous message, and they are
+ sent to the reverse-path of the previous mail message. (If the
+ delivery of such a notification message fails, that usually indicates
+ a problem with the mail system of the host to which the notification
+ message is addressed. For this reason, at some hosts the MTA is set
+ up to forward such failed notification messages to someone who is
+ able to fix problems with the mail system, e.g., via the postmaster
+ alias.)
+
+ All other types of messages (i.e., any message which is not required
+ by a standards-track RFC to have a null reverse-path) SHOULD be sent
+ with with a valid, non-null reverse-path.
+
+ Implementors of automated email processors should be careful to make
+ sure that the various kinds of messages with null reverse-path are
+ handled correctly, in particular such systems SHOULD NOT reply to
+ messages with null reverse-path.
+
+5. Address Resolution and Mail Handling
+
+ Once an SMTP client lexically identifies a domain to which mail will
+ be delivered for processing (as described in sections 3.6 and 3.7), a
+ DNS lookup MUST be performed to resolve the domain name [22]. The
+ names are expected to be fully-qualified domain names (FQDNs):
+ mechanisms for inferring FQDNs from partial names or local aliases
+ are outside of this specification and, due to a history of problems,
+ are generally discouraged. The lookup first attempts to locate an MX
+ record associated with the name. If a CNAME record is found instead,
+ the resulting name is processed as if it were the initial name. If
+ no MX records are found, but an A RR is found, the A RR is treated as
+ if it was associated with an implicit MX RR, with a preference of 0,
+ pointing to that host. If one or more MX RRs are found for a given
+ name, SMTP systems MUST NOT utilize any A RRs associated with that
+ name unless they are located using the MX RRs; the "implicit MX" rule
+ above applies only if there are no MX records present. If MX records
+ are present, but none of them are usable, this situation MUST be
+ reported as an error.
+
+ When the lookup succeeds, the mapping can result in a list of
+ alternative delivery addresses rather than a single address, because
+ of multiple MX records, multihoming, or both. To provide reliable
+ mail transmission, the SMTP client MUST be able to try (and retry)
+ each of the relevant addresses in this list in order, until a
+ delivery attempt succeeds. However, there MAY also be a configurable
+ limit on the number of alternate addresses that can be tried. In any
+ case, the SMTP client SHOULD try at least two addresses.
+
+
+
+Klensin Standards Track [Page 60]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ Two types of information is used to rank the host addresses: multiple
+ MX records, and multihomed hosts.
+
+ Multiple MX records contain a preference indication that MUST be used
+ in sorting (see below). Lower numbers are more preferred than higher
+ ones. If there are multiple destinations with the same preference
+ and there is no clear reason to favor one (e.g., by recognition of an
+ easily-reached address), then the sender-SMTP MUST randomize them to
+ spread the load across multiple mail exchangers for a specific
+ organization.
+
+ The destination host (perhaps taken from the preferred MX record) may
+ be multihomed, in which case the domain name resolver will return a
+ list of alternative IP addresses. It is the responsibility of the
+ domain name resolver interface to have ordered this list by
+ decreasing preference if necessary, and SMTP MUST try them in the
+ order presented.
+
+ Although the capability to try multiple alternative addresses is
+ required, specific installations may want to limit or disable the use
+ of alternative addresses. The question of whether a sender should
+ attempt retries using the different addresses of a multihomed host
+ has been controversial. The main argument for using the multiple
+ addresses is that it maximizes the probability of timely delivery,
+ and indeed sometimes the probability of any delivery; the counter-
+ argument is that it may result in unnecessary resource use. Note
+ that resource use is also strongly determined by the sending strategy
+ discussed in section 4.5.4.1.
+
+ If an SMTP server receives a message with a destination for which it
+ is a designated Mail eXchanger, it MAY relay the message (potentially
+ after having rewritten the MAIL FROM and/or RCPT TO addresses), make
+ final delivery of the message, or hand it off using some mechanism
+ outside the SMTP-provided transport environment. Of course, neither
+ of the latter require that the list of MX records be examined
+ further.
+
+ If it determines that it should relay the message without rewriting
+ the address, it MUST sort the MX records to determine candidates for
+ delivery. The records are first ordered by preference, with the
+ lowest-numbered records being most preferred. The relay host MUST
+ then inspect the list for any of the names or addresses by which it
+ might be known in mail transactions. If a matching record is found,
+ all records at that preference level and higher-numbered ones MUST be
+ discarded from consideration. If there are no records left at that
+ point, it is an error condition, and the message MUST be returned as
+ undeliverable. If records do remain, they SHOULD be tried, best
+ preference first, as described above.
+
+
+
+Klensin Standards Track [Page 61]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+6. Problem Detection and Handling
+
+6.1 Reliable Delivery and Replies by Email
+
+ When the receiver-SMTP accepts a piece of mail (by sending a "250 OK"
+ message in response to DATA), it is accepting responsibility for
+ delivering or relaying the message. It must take this responsibility
+ seriously. It MUST NOT lose the message for frivolous reasons, such
+ as because the host later crashes or because of a predictable
+ resource shortage.
+
+ If there is a delivery failure after acceptance of a message, the
+ receiver-SMTP MUST formulate and mail a notification message. This
+ notification MUST be sent using a null ("<>") reverse path in the
+ envelope. The recipient of this notification MUST be the address
+ from the envelope return path (or the Return-Path: line). However,
+ if this address is null ("<>"), the receiver-SMTP MUST NOT send a
+ notification. Obviously, nothing in this section can or should
+ prohibit local decisions (i.e., as part of the same system
+ environment as the receiver-SMTP) to log or otherwise transmit
+ information about null address events locally if that is desired. If
+ the address is an explicit source route, it MUST be stripped down to
+ its final hop.
+
+ For example, suppose that an error notification must be sent for a
+ message that arrived with:
+
+ MAIL FROM:<@a,@b:user@d>
+
+ The notification message MUST be sent using:
+
+ RCPT TO:<user@d>
+
+ Some delivery failures after the message is accepted by SMTP will be
+ unavoidable. For example, it may be impossible for the receiving
+ SMTP server to validate all the delivery addresses in RCPT command(s)
+ due to a "soft" domain system error, because the target is a mailing
+ list (see earlier discussion of RCPT), or because the server is
+ acting as a relay and has no immediate access to the delivering
+ system.
+
+ To avoid receiving duplicate messages as the result of timeouts, a
+ receiver-SMTP MUST seek to minimize the time required to respond to
+ the final <CRLF>.<CRLF> end of data indicator. See RFC 1047 [28] for
+ a discussion of this problem.
+
+
+
+
+
+
+Klensin Standards Track [Page 62]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+6.2 Loop Detection
+
+ Simple counting of the number of "Received:" headers in a message has
+ proven to be an effective, although rarely optimal, method of
+ detecting loops in mail systems. SMTP servers using this technique
+ SHOULD use a large rejection threshold, normally at least 100
+ Received entries. Whatever mechanisms are used, servers MUST contain
+ provisions for detecting and stopping trivial loops.
+
+6.3 Compensating for Irregularities
+
+ Unfortunately, variations, creative interpretations, and outright
+ violations of Internet mail protocols do occur; some would suggest
+ that they occur quite frequently. The debate as to whether a well-
+ behaved SMTP receiver or relay should reject a malformed message,
+ attempt to pass it on unchanged, or attempt to repair it to increase
+ the odds of successful delivery (or subsequent reply) began almost
+ with the dawn of structured network mail and shows no signs of
+ abating. Advocates of rejection claim that attempted repairs are
+ rarely completely adequate and that rejection of bad messages is the
+ only way to get the offending software repaired. Advocates of
+ "repair" or "deliver no matter what" argue that users prefer that
+ mail go through it if at all possible and that there are significant
+ market pressures in that direction. In practice, these market
+ pressures may be more important to particular vendors than strict
+ conformance to the standards, regardless of the preference of the
+ actual developers.
+
+ The problems associated with ill-formed messages were exacerbated by
+ the introduction of the split-UA mail reading protocols [3, 26, 5,
+ 21]. These protocols have encouraged the use of SMTP as a posting
+ protocol, and SMTP servers as relay systems for these client hosts
+ (which are often only intermittently connected to the Internet).
+ Historically, many of those client machines lacked some of the
+ mechanisms and information assumed by SMTP (and indeed, by the mail
+ format protocol [7]). Some could not keep adequate track of time;
+ others had no concept of time zones; still others could not identify
+ their own names or addresses; and, of course, none could satisfy the
+ assumptions that underlay RFC 822's conception of authenticated
+ addresses.
+
+ In response to these weak SMTP clients, many SMTP systems now
+ complete messages that are delivered to them in incomplete or
+ incorrect form. This strategy is generally considered appropriate
+ when the server can identify or authenticate the client, and there
+ are prior agreements between them. By contrast, there is at best
+ great concern about fixes applied by a relay or delivery SMTP server
+ that has little or no knowledge of the user or client machine.
+
+
+
+Klensin Standards Track [Page 63]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ The following changes to a message being processed MAY be applied
+ when necessary by an originating SMTP server, or one used as the
+ target of SMTP as an initial posting protocol:
+
+ - Addition of a message-id field when none appears
+
+ - Addition of a date, time or time zone when none appears
+
+ - Correction of addresses to proper FQDN format
+
+ The less information the server has about the client, the less likely
+ these changes are to be correct and the more caution and conservatism
+ should be applied when considering whether or not to perform fixes
+ and how. These changes MUST NOT be applied by an SMTP server that
+ provides an intermediate relay function.
+
+ In all cases, properly-operating clients supplying correct
+ information are preferred to corrections by the SMTP server. In all
+ cases, documentation of actions performed by the servers (in trace
+ fields and/or header comments) is strongly encouraged.
+
+7. Security Considerations
+
+7.1 Mail Security and Spoofing
+
+ SMTP mail is inherently insecure in that it is feasible for even
+ fairly casual users to negotiate directly with receiving and relaying
+ SMTP servers and create messages that will trick a naive recipient
+ into believing that they came from somewhere else. Constructing such
+ a message so that the "spoofed" behavior cannot be detected by an
+ expert is somewhat more difficult, but not sufficiently so as to be a
+ deterrent to someone who is determined and knowledgeable.
+ Consequently, as knowledge of Internet mail increases, so does the
+ knowledge that SMTP mail inherently cannot be authenticated, or
+ integrity checks provided, at the transport level. Real mail
+ security lies only in end-to-end methods involving the message
+ bodies, such as those which use digital signatures (see [14] and,
+ e.g., PGP [4] or S/MIME [31]).
+
+ Various protocol extensions and configuration options that provide
+ authentication at the transport level (e.g., from an SMTP client to
+ an SMTP server) improve somewhat on the traditional situation
+ described above. However, unless they are accompanied by careful
+ handoffs of responsibility in a carefully-designed trust environment,
+ they remain inherently weaker than end-to-end mechanisms which use
+ digitally signed messages rather than depending on the integrity of
+ the transport system.
+
+
+
+
+Klensin Standards Track [Page 64]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ Efforts to make it more difficult for users to set envelope return
+ path and header "From" fields to point to valid addresses other than
+ their own are largely misguided: they frustrate legitimate
+ applications in which mail is sent by one user on behalf of another
+ or in which error (or normal) replies should be directed to a special
+ address. (Systems that provide convenient ways for users to alter
+ these fields on a per-message basis should attempt to establish a
+ primary and permanent mailbox address for the user so that Sender
+ fields within the message data can be generated sensibly.)
+
+ This specification does not further address the authentication issues
+ associated with SMTP other than to advocate that useful functionality
+ not be disabled in the hope of providing some small margin of
+ protection against an ignorant user who is trying to fake mail.
+
+7.2 "Blind" Copies
+
+ Addresses that do not appear in the message headers may appear in the
+ RCPT commands to an SMTP server for a number of reasons. The two
+ most common involve the use of a mailing address as a "list exploder"
+ (a single address that resolves into multiple addresses) and the
+ appearance of "blind copies". Especially when more than one RCPT
+ command is present, and in order to avoid defeating some of the
+ purpose of these mechanisms, SMTP clients and servers SHOULD NOT copy
+ the full set of RCPT command arguments into the headers, either as
+ part of trace headers or as informational or private-extension
+ headers. Since this rule is often violated in practice, and cannot
+ be enforced, sending SMTP systems that are aware of "bcc" use MAY
+ find it helpful to send each blind copy as a separate message
+ transaction containing only a single RCPT command.
+
+ There is no inherent relationship between either "reverse" (from
+ MAIL, SAML, etc., commands) or "forward" (RCPT) addresses in the SMTP
+ transaction ("envelope") and the addresses in the headers. Receiving
+ systems SHOULD NOT attempt to deduce such relationships and use them
+ to alter the headers of the message for delivery. The popular
+ "Apparently-to" header is a violation of this principle as well as a
+ common source of unintended information disclosure and SHOULD NOT be
+ used.
+
+7.3 VRFY, EXPN, and Security
+
+ As discussed in section 3.5, individual sites may want to disable
+ either or both of VRFY or EXPN for security reasons. As a corollary
+ to the above, implementations that permit this MUST NOT appear to
+ have verified addresses that are not, in fact, verified. If a site
+
+
+
+
+
+Klensin Standards Track [Page 65]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ disables these commands for security reasons, the SMTP server MUST
+ return a 252 response, rather than a code that could be confused with
+ successful or unsuccessful verification.
+
+ Returning a 250 reply code with the address listed in the VRFY
+ command after having checked it only for syntax violates this rule.
+ Of course, an implementation that "supports" VRFY by always returning
+ 550 whether or not the address is valid is equally not in
+ conformance.
+
+ Within the last few years, the contents of mailing lists have become
+ popular as an address information source for so-called "spammers."
+ The use of EXPN to "harvest" addresses has increased as list
+ administrators have installed protections against inappropriate uses
+ of the lists themselves. Implementations SHOULD still provide
+ support for EXPN, but sites SHOULD carefully evaluate the tradeoffs.
+ As authentication mechanisms are introduced into SMTP, some sites may
+ choose to make EXPN available only to authenticated requestors.
+
+7.4 Information Disclosure in Announcements
+
+ There has been an ongoing debate about the tradeoffs between the
+ debugging advantages of announcing server type and version (and,
+ sometimes, even server domain name) in the greeting response or in
+ response to the HELP command and the disadvantages of exposing
+ information that might be useful in a potential hostile attack. The
+ utility of the debugging information is beyond doubt. Those who
+ argue for making it available point out that it is far better to
+ actually secure an SMTP server rather than hope that trying to
+ conceal known vulnerabilities by hiding the server's precise identity
+ will provide more protection. Sites are encouraged to evaluate the
+ tradeoff with that issue in mind; implementations are strongly
+ encouraged to minimally provide for making type and version
+ information available in some way to other network hosts.
+
+7.5 Information Disclosure in Trace Fields
+
+ In some circumstances, such as when mail originates from within a LAN
+ whose hosts are not directly on the public Internet, trace
+ ("Received") fields produced in conformance with this specification
+ may disclose host names and similar information that would not
+ normally be available. This ordinarily does not pose a problem, but
+ sites with special concerns about name disclosure should be aware of
+ it. Also, the optional FOR clause should be supplied with caution or
+ not at all when multiple recipients are involved lest it
+ inadvertently disclose the identities of "blind copy" recipients to
+ others.
+
+
+
+
+Klensin Standards Track [Page 66]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+7.6 Information Disclosure in Message Forwarding
+
+ As discussed in section 3.4, use of the 251 or 551 reply codes to
+ identify the replacement address associated with a mailbox may
+ inadvertently disclose sensitive information. Sites that are
+ concerned about those issues should ensure that they select and
+ configure servers appropriately.
+
+7.7 Scope of Operation of SMTP Servers
+
+ It is a well-established principle that an SMTP server may refuse to
+ accept mail for any operational or technical reason that makes sense
+ to the site providing the server. However, cooperation among sites
+ and installations makes the Internet possible. If sites take
+ excessive advantage of the right to reject traffic, the ubiquity of
+ email availability (one of the strengths of the Internet) will be
+ threatened; considerable care should be taken and balance maintained
+ if a site decides to be selective about the traffic it will accept
+ and process.
+
+ In recent years, use of the relay function through arbitrary sites
+ has been used as part of hostile efforts to hide the actual origins
+ of mail. Some sites have decided to limit the use of the relay
+ function to known or identifiable sources, and implementations SHOULD
+ provide the capability to perform this type of filtering. When mail
+ is rejected for these or other policy reasons, a 550 code SHOULD be
+ used in response to EHLO, MAIL, or RCPT as appropriate.
+
+8. IANA Considerations
+
+ IANA will maintain three registries in support of this specification.
+ The first consists of SMTP service extensions with the associated
+ keywords, and, as needed, parameters and verbs. As specified in
+ section 2.2.2, no entry may be made in this registry that starts in
+ an "X". Entries may be made only for service extensions (and
+ associated keywords, parameters, or verbs) that are defined in
+ standards-track or experimental RFCs specifically approved by the
+ IESG for this purpose.
+
+ The second registry consists of "tags" that identify forms of domain
+ literals other than those for IPv4 addresses (specified in RFC 821
+ and in this document) and IPv6 addresses (specified in this
+ document). Additional literal types require standardization before
+ being used; none are anticipated at this time.
+
+ The third, established by RFC 821 and renewed by this specification,
+ is a registry of link and protocol identifiers to be used with the
+ "via" and "with" subclauses of the time stamp ("Received: header")
+
+
+
+Klensin Standards Track [Page 67]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ described in section 4.4. Link and protocol identifiers in addition
+ to those specified in this document may be registered only by
+ standardization or by way of an RFC-documented, IESG-approved,
+ Experimental protocol extension.
+
+9. References
+
+ [1] American National Standards Institute (formerly United States of
+ America Standards Institute), X3.4, 1968, "USA Code for
+ Information Interchange". ANSI X3.4-1968 has been replaced by
+ newer versions with slight modifications, but the 1968 version
+ remains definitive for the Internet.
+
+ [2] Braden, R., "Requirements for Internet hosts - application and
+ support", STD 3, RFC 1123, October 1989.
+
+ [3] Butler, M., Chase, D., Goldberger, J., Postel, J. and J.
+ Reynolds, "Post Office Protocol - version 2", RFC 937, February
+ 1985.
+
+ [4] Callas, J., Donnerhacke, L., Finney, H. and R. Thayer, "OpenPGP
+ Message Format", RFC 2440, November 1998.
+
+ [5] Crispin, M., "Interactive Mail Access Protocol - Version 2", RFC
+ 1176, August 1990.
+
+ [6] Crispin, M., "Internet Message Access Protocol - Version 4", RFC
+ 2060, December 1996.
+
+ [7] Crocker, D., "Standard for the Format of ARPA Internet Text
+ Messages", RFC 822, August 1982.
+
+ [8] Crocker, D. and P. Overell, Eds., "Augmented BNF for Syntax
+ Specifications: ABNF", RFC 2234, November 1997.
+
+ [9] De Winter, J., "SMTP Service Extension for Remote Message Queue
+ Starting", RFC 1985, August 1996.
+
+ [10] Fajman, R., "An Extensible Message Format for Message
+ Disposition Notifications", RFC 2298, March 1998.
+
+ [11] Freed, N, "Behavior of and Requirements for Internet Firewalls",
+ RFC 2979, October 2000.
+
+ [12] Freed, N. and N. Borenstein, "Multipurpose Internet Mail
+ Extensions (MIME) Part One: Format of Internet Message Bodies",
+ RFC 2045, December 1996.
+
+
+
+
+Klensin Standards Track [Page 68]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ [13] Freed, N., "SMTP Service Extension for Command Pipelining", RFC
+ 2920, September 2000.
+
+ [14] Galvin, J., Murphy, S., Crocker, S. and N. Freed, "Security
+ Multiparts for MIME: Multipart/Signed and Multipart/Encrypted",
+ RFC 1847, October 1995.
+
+ [15] Gellens, R. and J. Klensin, "Message Submission", RFC 2476,
+ December 1998.
+
+ [16] Kille, S., "Mapping between X.400 and RFC822/MIME", RFC 2156,
+ January 1998.
+
+ [17] Hinden, R and S. Deering, Eds. "IP Version 6 Addressing
+ Architecture", RFC 2373, July 1998.
+
+ [18] Klensin, J., Freed, N. and K. Moore, "SMTP Service Extension for
+ Message Size Declaration", STD 10, RFC 1870, November 1995.
+
+ [19] Klensin, J., Freed, N., Rose, M., Stefferud, E. and D. Crocker,
+ "SMTP Service Extensions", STD 10, RFC 1869, November 1995.
+
+ [20] Klensin, J., Freed, N., Rose, M., Stefferud, E. and D. Crocker,
+ "SMTP Service Extension for 8bit-MIMEtransport", RFC 1652, July
+ 1994.
+
+ [21] Lambert, M., "PCMAIL: A distributed mail system for personal
+ computers", RFC 1056, July 1988.
+
+ [22] Mockapetris, P., "Domain names - implementation and
+ specification", STD 13, RFC 1035, November 1987.
+
+ Mockapetris, P., "Domain names - concepts and facilities", STD
+ 13, RFC 1034, November 1987.
+
+ [23] Moore, K., "MIME (Multipurpose Internet Mail Extensions) Part
+ Three: Message Header Extensions for Non-ASCII Text", RFC 2047,
+ December 1996.
+
+ [24] Moore, K., "SMTP Service Extension for Delivery Status
+ Notifications", RFC 1891, January 1996.
+
+ [25] Moore, K., and G. Vaudreuil, "An Extensible Message Format for
+ Delivery Status Notifications", RFC 1894, January 1996.
+
+ [26] Myers, J. and M. Rose, "Post Office Protocol - Version 3", STD
+ 53, RFC 1939, May 1996.
+
+
+
+
+Klensin Standards Track [Page 69]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ [27] Partridge, C., "Mail routing and the domain system", RFC 974,
+ January 1986.
+
+ [28] Partridge, C., "Duplicate messages and SMTP", RFC 1047, February
+ 1988.
+
+ [29] Postel, J., ed., "Transmission Control Protocol - DARPA Internet
+ Program Protocol Specification", STD 7, RFC 793, September 1981.
+
+ [30] Postel, J., "Simple Mail Transfer Protocol", RFC 821, August
+ 1982.
+
+ [31] Ramsdell, B., Ed., "S/MIME Version 3 Message Specification", RFC
+ 2633, June 1999.
+
+ [32] Resnick, P., Ed., "Internet Message Format", RFC 2822, April
+ 2001.
+
+ [33] Vaudreuil, G., "SMTP Service Extensions for Transmission of
+ Large and Binary MIME Messages", RFC 1830, August 1995.
+
+ [34] Vaudreuil, G., "Enhanced Mail System Status Codes", RFC 1893,
+ January 1996.
+
+10. Editor's Address
+
+ John C. Klensin
+ AT&T Laboratories
+ 99 Bedford St
+ Boston, MA 02111 USA
+
+ Phone: 617-574-3076
+ EMail: klensin@research.att.com
+
+11. Acknowledgments
+
+ Many people worked long and hard on the many iterations of this
+ document. There was wide-ranging debate in the IETF DRUMS Working
+ Group, both on its mailing list and in face to face discussions,
+ about many technical issues and the role of a revised standard for
+ Internet mail transport, and many contributors helped form the
+ wording in this specification. The hundreds of participants in the
+ many discussions since RFC 821 was produced are too numerous to
+ mention, but they all helped this document become what it is.
+
+
+
+
+
+
+
+Klensin Standards Track [Page 70]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+APPENDICES
+
+A. TCP Transport Service
+
+ The TCP connection supports the transmission of 8-bit bytes. The
+ SMTP data is 7-bit ASCII characters. Each character is transmitted
+ as an 8-bit byte with the high-order bit cleared to zero. Service
+ extensions may modify this rule to permit transmission of full 8-bit
+ data bytes as part of the message body, but not in SMTP commands or
+ responses.
+
+B. Generating SMTP Commands from RFC 822 Headers
+
+ Some systems use RFC 822 headers (only) in a mail submission
+ protocol, or otherwise generate SMTP commands from RFC 822 headers
+ when such a message is handed to an MTA from a UA. While the MTA-UA
+ protocol is a private matter, not covered by any Internet Standard,
+ there are problems with this approach. For example, there have been
+ repeated problems with proper handling of "bcc" copies and
+ redistribution lists when information that conceptually belongs to a
+ mail envelopes is not separated early in processing from header
+ information (and kept separate).
+
+ It is recommended that the UA provide its initial ("submission
+ client") MTA with an envelope separate from the message itself.
+ However, if the envelope is not supplied, SMTP commands SHOULD be
+ generated as follows:
+
+ 1. Each recipient address from a TO, CC, or BCC header field SHOULD
+ be copied to a RCPT command (generating multiple message copies if
+ that is required for queuing or delivery). This includes any
+ addresses listed in a RFC 822 "group". Any BCC fields SHOULD then
+ be removed from the headers. Once this process is completed, the
+ remaining headers SHOULD be checked to verify that at least one
+ To:, Cc:, or Bcc: header remains. If none do, then a bcc: header
+ with no additional information SHOULD be inserted as specified in
+ [32].
+
+ 2. The return address in the MAIL command SHOULD, if possible, be
+ derived from the system's identity for the submitting (local)
+ user, and the "From:" header field otherwise. If there is a
+ system identity available, it SHOULD also be copied to the Sender
+ header field if it is different from the address in the From
+ header field. (Any Sender field that was already there SHOULD be
+ removed.) Systems may provide a way for submitters to override
+ the envelope return address, but may want to restrict its use to
+ privileged users. This will not prevent mail forgery, but may
+ lessen its incidence; see section 7.1.
+
+
+
+Klensin Standards Track [Page 71]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ When an MTA is being used in this way, it bears responsibility for
+ ensuring that the message being transmitted is valid. The mechanisms
+ for checking that validity, and for handling (or returning) messages
+ that are not valid at the time of arrival, are part of the MUA-MTA
+ interface and not covered by this specification.
+
+ A submission protocol based on Standard RFC 822 information alone
+ MUST NOT be used to gateway a message from a foreign (non-SMTP) mail
+ system into an SMTP environment. Additional information to construct
+ an envelope must come from some source in the other environment,
+ whether supplemental headers or the foreign system's envelope.
+
+ Attempts to gateway messages using only their header "to" and "cc"
+ fields have repeatedly caused mail loops and other behavior adverse
+ to the proper functioning of the Internet mail environment. These
+ problems have been especially common when the message originates from
+ an Internet mailing list and is distributed into the foreign
+ environment using envelope information. When these messages are then
+ processed by a header-only remailer, loops back to the Internet
+ environment (and the mailing list) are almost inevitable.
+
+C. Source Routes
+
+ Historically, the <reverse-path> was a reverse source routing list of
+ hosts and a source mailbox. The first host in the <reverse-path>
+ SHOULD be the host sending the MAIL command. Similarly, the
+ <forward-path> may be a source routing lists of hosts and a
+ destination mailbox. However, in general, the <forward-path> SHOULD
+ contain only a mailbox and domain name, relying on the domain name
+ system to supply routing information if required. The use of source
+ routes is deprecated; while servers MUST be prepared to receive and
+ handle them as discussed in section 3.3 and F.2, clients SHOULD NOT
+ transmit them and this section was included only to provide context.
+
+ For relay purposes, the forward-path may be a source route of the
+ form "@ONE,@TWO:JOE@THREE", where ONE, TWO, and THREE MUST BE fully-
+ qualified domain names. This form is used to emphasize the
+ distinction between an address and a route. The mailbox is an
+ absolute address, and the route is information about how to get
+ there. The two concepts should not be confused.
+
+ If source routes are used, RFC 821 and the text below should be
+ consulted for the mechanisms for constructing and updating the
+ forward- and reverse-paths.
+
+
+
+
+
+
+
+Klensin Standards Track [Page 72]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ The SMTP server transforms the command arguments by moving its own
+ identifier (its domain name or that of any domain for which it is
+ acting as a mail exchanger), if it appears, from the forward-path to
+ the beginning of the reverse-path.
+
+ Notice that the forward-path and reverse-path appear in the SMTP
+ commands and replies, but not necessarily in the message. That is,
+ there is no need for these paths and especially this syntax to appear
+ in the "To:" , "From:", "CC:", etc. fields of the message header.
+ Conversely, SMTP servers MUST NOT derive final message delivery
+ information from message header fields.
+
+ When the list of hosts is present, it is a "reverse" source route and
+ indicates that the mail was relayed through each host on the list
+ (the first host in the list was the most recent relay). This list is
+ used as a source route to return non-delivery notices to the sender.
+ As each relay host adds itself to the beginning of the list, it MUST
+ use its name as known in the transport environment to which it is
+ relaying the mail rather than that of the transport environment from
+ which the mail came (if they are different).
+
+D. Scenarios
+
+ This section presents complete scenarios of several types of SMTP
+ sessions. In the examples, "C:" indicates what is said by the SMTP
+ client, and "S:" indicates what is said by the SMTP server.
+
+D.1 A Typical SMTP Transaction Scenario
+
+ This SMTP example shows mail sent by Smith at host bar.com, to Jones,
+ Green, and Brown at host foo.com. Here we assume that host bar.com
+ contacts host foo.com directly. The mail is accepted for Jones and
+ Brown. Green does not have a mailbox at host foo.com.
+
+ S: 220 foo.com Simple Mail Transfer Service Ready
+ C: EHLO bar.com
+ S: 250-foo.com greets bar.com
+ S: 250-8BITMIME
+ S: 250-SIZE
+ S: 250-DSN
+ S: 250 HELP
+ C: MAIL FROM:<Smith@bar.com>
+ S: 250 OK
+ C: RCPT TO:<Jones@foo.com>
+ S: 250 OK
+ C: RCPT TO:<Green@foo.com>
+ S: 550 No such user here
+ C: RCPT TO:<Brown@foo.com>
+
+
+
+Klensin Standards Track [Page 73]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ S: 250 OK
+ C: DATA
+ S: 354 Start mail input; end with <CRLF>.<CRLF>
+ C: Blah blah blah...
+ C: ...etc. etc. etc.
+ C: .
+ S: 250 OK
+ C: QUIT
+ S: 221 foo.com Service closing transmission channel
+
+D.2 Aborted SMTP Transaction Scenario
+
+ S: 220 foo.com Simple Mail Transfer Service Ready
+ C: EHLO bar.com
+ S: 250-foo.com greets bar.com
+ S: 250-8BITMIME
+ S: 250-SIZE
+ S: 250-DSN
+ S: 250 HELP
+ C: MAIL FROM:<Smith@bar.com>
+ S: 250 OK
+ C: RCPT TO:<Jones@foo.com>
+ S: 250 OK
+ C: RCPT TO:<Green@foo.com>
+ S: 550 No such user here
+ C: RSET
+ S: 250 OK
+ C: QUIT
+ S: 221 foo.com Service closing transmission channel
+
+D.3 Relayed Mail Scenario
+
+ Step 1 -- Source Host to Relay Host
+
+ S: 220 foo.com Simple Mail Transfer Service Ready
+ C: EHLO bar.com
+ S: 250-foo.com greets bar.com
+ S: 250-8BITMIME
+ S: 250-SIZE
+ S: 250-DSN
+ S: 250 HELP
+ C: MAIL FROM:<JQP@bar.com>
+ S: 250 OK
+ C: RCPT TO:<@foo.com:Jones@XYZ.COM>
+ S: 250 OK
+ C: DATA
+ S: 354 Start mail input; end with <CRLF>.<CRLF>
+ C: Date: Thu, 21 May 1998 05:33:29 -0700
+
+
+
+Klensin Standards Track [Page 74]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ C: From: John Q. Public <JQP@bar.com>
+ C: Subject: The Next Meeting of the Board
+ C: To: Jones@xyz.com
+ C:
+ C: Bill:
+ C: The next meeting of the board of directors will be
+ C: on Tuesday.
+ C: John.
+ C: .
+ S: 250 OK
+ C: QUIT
+ S: 221 foo.com Service closing transmission channel
+
+ Step 2 -- Relay Host to Destination Host
+
+ S: 220 xyz.com Simple Mail Transfer Service Ready
+ C: EHLO foo.com
+ S: 250 xyz.com is on the air
+ C: MAIL FROM:<@foo.com:JQP@bar.com>
+ S: 250 OK
+ C: RCPT TO:<Jones@XYZ.COM>
+ S: 250 OK
+ C: DATA
+ S: 354 Start mail input; end with <CRLF>.<CRLF>
+ C: Received: from bar.com by foo.com ; Thu, 21 May 1998
+ C: 05:33:29 -0700
+ C: Date: Thu, 21 May 1998 05:33:22 -0700
+ C: From: John Q. Public <JQP@bar.com>
+ C: Subject: The Next Meeting of the Board
+ C: To: Jones@xyz.com
+ C:
+ C: Bill:
+ C: The next meeting of the board of directors will be
+ C: on Tuesday.
+ C: John.
+ C: .
+ S: 250 OK
+ C: QUIT
+ S: 221 foo.com Service closing transmission channel
+
+D.4 Verifying and Sending Scenario
+
+ S: 220 foo.com Simple Mail Transfer Service Ready
+ C: EHLO bar.com
+ S: 250-foo.com greets bar.com
+ S: 250-8BITMIME
+ S: 250-SIZE
+ S: 250-DSN
+
+
+
+Klensin Standards Track [Page 75]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ S: 250-VRFY
+ S: 250 HELP
+ C: VRFY Crispin
+ S: 250 Mark Crispin <Admin.MRC@foo.com>
+ C: SEND FROM:<EAK@bar.com>
+ S: 250 OK
+ C: RCPT TO:<Admin.MRC@foo.com>
+ S: 250 OK
+ C: DATA
+ S: 354 Start mail input; end with <CRLF>.<CRLF>
+ C: Blah blah blah...
+ C: ...etc. etc. etc.
+ C: .
+ S: 250 OK
+ C: QUIT
+ S: 221 foo.com Service closing transmission channel
+
+E. Other Gateway Issues
+
+ In general, gateways between the Internet and other mail systems
+ SHOULD attempt to preserve any layering semantics across the
+ boundaries between the two mail systems involved. Gateway-
+ translation approaches that attempt to take shortcuts by mapping,
+ (such as envelope information from one system to the message headers
+ or body of another) have generally proven to be inadequate in
+ important ways. Systems translating between environments that do not
+ support both envelopes and headers and Internet mail must be written
+ with the understanding that some information loss is almost
+ inevitable.
+
+F. Deprecated Features of RFC 821
+
+ A few features of RFC 821 have proven to be problematic and SHOULD
+ NOT be used in Internet mail.
+
+F.1 TURN
+
+ This command, described in RFC 821, raises important security issues
+ since, in the absence of strong authentication of the host requesting
+ that the client and server switch roles, it can easily be used to
+ divert mail from its correct destination. Its use is deprecated;
+ SMTP systems SHOULD NOT use it unless the server can authenticate the
+ client.
+
+
+
+
+
+
+
+
+Klensin Standards Track [Page 76]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+F.2 Source Routing
+
+ RFC 821 utilized the concept of explicit source routing to get mail
+ from one host to another via a series of relays. The requirement to
+ utilize source routes in regular mail traffic was eliminated by the
+ introduction of the domain name system "MX" record and the last
+ significant justification for them was eliminated by the
+ introduction, in RFC 1123, of a clear requirement that addresses
+ following an "@" must all be fully-qualified domain names.
+ Consequently, the only remaining justifications for the use of source
+ routes are support for very old SMTP clients or MUAs and in mail
+ system debugging. They can, however, still be useful in the latter
+ circumstance and for routing mail around serious, but temporary,
+ problems such as problems with the relevant DNS records.
+
+ SMTP servers MUST continue to accept source route syntax as specified
+ in the main body of this document and in RFC 1123. They MAY, if
+ necessary, ignore the routes and utilize only the target domain in
+ the address. If they do utilize the source route, the message MUST
+ be sent to the first domain shown in the address. In particular, a
+ server MUST NOT guess at shortcuts within the source route.
+
+ Clients SHOULD NOT utilize explicit source routing except under
+ unusual circumstances, such as debugging or potentially relaying
+ around firewall or mail system configuration errors.
+
+F.3 HELO
+
+ As discussed in sections 3.1 and 4.1.1, EHLO is strongly preferred to
+ HELO when the server will accept the former. Servers must continue
+ to accept and process HELO in order to support older clients.
+
+F.4 #-literals
+
+ RFC 821 provided for specifying an Internet address as a decimal
+ integer host number prefixed by a pound sign, "#". In practice, that
+ form has been obsolete since the introduction of TCP/IP. It is
+ deprecated and MUST NOT be used.
+
+F.5 Dates and Years
+
+ When dates are inserted into messages by SMTP clients or servers
+ (e.g., in trace fields), four-digit years MUST BE used. Two-digit
+ years are deprecated; three-digit years were never permitted in the
+ Internet mail system.
+
+
+
+
+
+
+Klensin Standards Track [Page 77]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+F.6 Sending versus Mailing
+
+ In addition to specifying a mechanism for delivering messages to
+ user's mailboxes, RFC 821 provided additional, optional, commands to
+ deliver messages directly to the user's terminal screen. These
+ commands (SEND, SAML, SOML) were rarely implemented, and changes in
+ workstation technology and the introduction of other protocols may
+ have rendered them obsolete even where they are implemented.
+
+ Clients SHOULD NOT provide SEND, SAML, or SOML as services. Servers
+ MAY implement them. If they are implemented by servers, the
+ implementation model specified in RFC 821 MUST be used and the
+ command names MUST be published in the response to the EHLO command.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Klensin Standards Track [Page 78]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (2001). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Klensin Standards Track [Page 79]
+
diff --git a/standards/rfc2822.txt b/standards/rfc2822.txt
new file mode 100644
index 000000000..9f698f77d
--- /dev/null
+++ b/standards/rfc2822.txt
@@ -0,0 +1,2859 @@
+
+
+
+
+
+
+Network Working Group P. Resnick, Editor
+Request for Comments: 2822 QUALCOMM Incorporated
+Obsoletes: 822 April 2001
+Category: Standards Track
+
+
+ Internet Message Format
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2001). All Rights Reserved.
+
+Abstract
+
+ This standard specifies a syntax for text messages that are sent
+ between computer users, within the framework of "electronic mail"
+ messages. This standard supersedes the one specified in Request For
+ Comments (RFC) 822, "Standard for the Format of ARPA Internet Text
+ Messages", updating it to reflect current practice and incorporating
+ incremental changes that were specified in other RFCs.
+
+Table of Contents
+
+ 1. Introduction ............................................... 3
+ 1.1. Scope .................................................... 3
+ 1.2. Notational conventions ................................... 4
+ 1.2.1. Requirements notation .................................. 4
+ 1.2.2. Syntactic notation ..................................... 4
+ 1.3. Structure of this document ............................... 4
+ 2. Lexical Analysis of Messages ............................... 5
+ 2.1. General Description ...................................... 5
+ 2.1.1. Line Length Limits ..................................... 6
+ 2.2. Header Fields ............................................ 7
+ 2.2.1. Unstructured Header Field Bodies ....................... 7
+ 2.2.2. Structured Header Field Bodies ......................... 7
+ 2.2.3. Long Header Fields ..................................... 7
+ 2.3. Body ..................................................... 8
+ 3. Syntax ..................................................... 9
+ 3.1. Introduction ............................................. 9
+ 3.2. Lexical Tokens ........................................... 9
+
+
+
+Resnick Standards Track [Page 1]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ 3.2.1. Primitive Tokens ....................................... 9
+ 3.2.2. Quoted characters ......................................10
+ 3.2.3. Folding white space and comments .......................11
+ 3.2.4. Atom ...................................................12
+ 3.2.5. Quoted strings .........................................13
+ 3.2.6. Miscellaneous tokens ...................................13
+ 3.3. Date and Time Specification ..............................14
+ 3.4. Address Specification ....................................15
+ 3.4.1. Addr-spec specification ................................16
+ 3.5 Overall message syntax ....................................17
+ 3.6. Field definitions ........................................18
+ 3.6.1. The origination date field .............................20
+ 3.6.2. Originator fields ......................................21
+ 3.6.3. Destination address fields .............................22
+ 3.6.4. Identification fields ..................................23
+ 3.6.5. Informational fields ...................................26
+ 3.6.6. Resent fields ..........................................26
+ 3.6.7. Trace fields ...........................................28
+ 3.6.8. Optional fields ........................................29
+ 4. Obsolete Syntax ............................................29
+ 4.1. Miscellaneous obsolete tokens ............................30
+ 4.2. Obsolete folding white space .............................31
+ 4.3. Obsolete Date and Time ...................................31
+ 4.4. Obsolete Addressing ......................................33
+ 4.5. Obsolete header fields ...................................33
+ 4.5.1. Obsolete origination date field ........................34
+ 4.5.2. Obsolete originator fields .............................34
+ 4.5.3. Obsolete destination address fields ....................34
+ 4.5.4. Obsolete identification fields .........................35
+ 4.5.5. Obsolete informational fields ..........................35
+ 4.5.6. Obsolete resent fields .................................35
+ 4.5.7. Obsolete trace fields ..................................36
+ 4.5.8. Obsolete optional fields ...............................36
+ 5. Security Considerations ....................................36
+ 6. Bibliography ...............................................37
+ 7. Editor's Address ...........................................38
+ 8. Acknowledgements ...........................................39
+ Appendix A. Example messages ..................................41
+ A.1. Addressing examples ......................................41
+ A.1.1. A message from one person to another with simple
+ addressing .............................................41
+ A.1.2. Different types of mailboxes ...........................42
+ A.1.3. Group addresses ........................................43
+ A.2. Reply messages ...........................................43
+ A.3. Resent messages ..........................................44
+ A.4. Messages with trace fields ...............................46
+ A.5. White space, comments, and other oddities ................47
+ A.6. Obsoleted forms ..........................................47
+
+
+
+Resnick Standards Track [Page 2]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ A.6.1. Obsolete addressing ....................................48
+ A.6.2. Obsolete dates .........................................48
+ A.6.3. Obsolete white space and comments ......................48
+ Appendix B. Differences from earlier standards ................49
+ Appendix C. Notices ...........................................50
+ Full Copyright Statement ......................................51
+
+1. Introduction
+
+1.1. Scope
+
+ This standard specifies a syntax for text messages that are sent
+ between computer users, within the framework of "electronic mail"
+ messages. This standard supersedes the one specified in Request For
+ Comments (RFC) 822, "Standard for the Format of ARPA Internet Text
+ Messages" [RFC822], updating it to reflect current practice and
+ incorporating incremental changes that were specified in other RFCs
+ [STD3].
+
+ This standard specifies a syntax only for text messages. In
+ particular, it makes no provision for the transmission of images,
+ audio, or other sorts of structured data in electronic mail messages.
+ There are several extensions published, such as the MIME document
+ series [RFC2045, RFC2046, RFC2049], which describe mechanisms for the
+ transmission of such data through electronic mail, either by
+ extending the syntax provided here or by structuring such messages to
+ conform to this syntax. Those mechanisms are outside of the scope of
+ this standard.
+
+ In the context of electronic mail, messages are viewed as having an
+ envelope and contents. The envelope contains whatever information is
+ needed to accomplish transmission and delivery. (See [RFC2821] for a
+ discussion of the envelope.) The contents comprise the object to be
+ delivered to the recipient. This standard applies only to the format
+ and some of the semantics of message contents. It contains no
+ specification of the information in the envelope.
+
+ However, some message systems may use information from the contents
+ to create the envelope. It is intended that this standard facilitate
+ the acquisition of such information by programs.
+
+ This specification is intended as a definition of what message
+ content format is to be passed between systems. Though some message
+ systems locally store messages in this format (which eliminates the
+ need for translation between formats) and others use formats that
+ differ from the one specified in this standard, local storage is
+ outside of the scope of this standard.
+
+
+
+
+Resnick Standards Track [Page 3]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ Note: This standard is not intended to dictate the internal formats
+ used by sites, the specific message system features that they are
+ expected to support, or any of the characteristics of user interface
+ programs that create or read messages. In addition, this standard
+ does not specify an encoding of the characters for either transport
+ or storage; that is, it does not specify the number of bits used or
+ how those bits are specifically transferred over the wire or stored
+ on disk.
+
+1.2. Notational conventions
+
+1.2.1. Requirements notation
+
+ This document occasionally uses terms that appear in capital letters.
+ When the terms "MUST", "SHOULD", "RECOMMENDED", "MUST NOT", "SHOULD
+ NOT", and "MAY" appear capitalized, they are being used to indicate
+ particular requirements of this specification. A discussion of the
+ meanings of these terms appears in [RFC2119].
+
+1.2.2. Syntactic notation
+
+ This standard uses the Augmented Backus-Naur Form (ABNF) notation
+ specified in [RFC2234] for the formal definitions of the syntax of
+ messages. Characters will be specified either by a decimal value
+ (e.g., the value %d65 for uppercase A and %d97 for lowercase A) or by
+ a case-insensitive literal value enclosed in quotation marks (e.g.,
+ "A" for either uppercase or lowercase A). See [RFC2234] for the full
+ description of the notation.
+
+1.3. Structure of this document
+
+ This document is divided into several sections.
+
+ This section, section 1, is a short introduction to the document.
+
+ Section 2 lays out the general description of a message and its
+ constituent parts. This is an overview to help the reader understand
+ some of the general principles used in the later portions of this
+ document. Any examples in this section MUST NOT be taken as
+ specification of the formal syntax of any part of a message.
+
+ Section 3 specifies formal ABNF rules for the structure of each part
+ of a message (the syntax) and describes the relationship between
+ those parts and their meaning in the context of a message (the
+ semantics). That is, it describes the actual rules for the structure
+ of each part of a message (the syntax) as well as a description of
+ the parts and instructions on how they ought to be interpreted (the
+ semantics). This includes analysis of the syntax and semantics of
+
+
+
+Resnick Standards Track [Page 4]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ subparts of messages that have specific structure. The syntax
+ included in section 3 represents messages as they MUST be created.
+ There are also notes in section 3 to indicate if any of the options
+ specified in the syntax SHOULD be used over any of the others.
+
+ Both sections 2 and 3 describe messages that are legal to generate
+ for purposes of this standard.
+
+ Section 4 of this document specifies an "obsolete" syntax. There are
+ references in section 3 to these obsolete syntactic elements. The
+ rules of the obsolete syntax are elements that have appeared in
+ earlier revisions of this standard or have previously been widely
+ used in Internet messages. As such, these elements MUST be
+ interpreted by parsers of messages in order to be conformant to this
+ standard. However, since items in this syntax have been determined
+ to be non-interoperable or to cause significant problems for
+ recipients of messages, they MUST NOT be generated by creators of
+ conformant messages.
+
+ Section 5 details security considerations to take into account when
+ implementing this standard.
+
+ Section 6 is a bibliography of references in this document.
+
+ Section 7 contains the editor's address.
+
+ Section 8 contains acknowledgements.
+
+ Appendix A lists examples of different sorts of messages. These
+ examples are not exhaustive of the types of messages that appear on
+ the Internet, but give a broad overview of certain syntactic forms.
+
+ Appendix B lists the differences between this standard and earlier
+ standards for Internet messages.
+
+ Appendix C has copyright and intellectual property notices.
+
+2. Lexical Analysis of Messages
+
+2.1. General Description
+
+ At the most basic level, a message is a series of characters. A
+ message that is conformant with this standard is comprised of
+ characters with values in the range 1 through 127 and interpreted as
+ US-ASCII characters [ASCII]. For brevity, this document sometimes
+ refers to this range of characters as simply "US-ASCII characters".
+
+
+
+
+
+Resnick Standards Track [Page 5]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ Note: This standard specifies that messages are made up of characters
+ in the US-ASCII range of 1 through 127. There are other documents,
+ specifically the MIME document series [RFC2045, RFC2046, RFC2047,
+ RFC2048, RFC2049], that extend this standard to allow for values
+ outside of that range. Discussion of those mechanisms is not within
+ the scope of this standard.
+
+ Messages are divided into lines of characters. A line is a series of
+ characters that is delimited with the two characters carriage-return
+ and line-feed; that is, the carriage return (CR) character (ASCII
+ value 13) followed immediately by the line feed (LF) character (ASCII
+ value 10). (The carriage-return/line-feed pair is usually written in
+ this document as "CRLF".)
+
+ A message consists of header fields (collectively called "the header
+ of the message") followed, optionally, by a body. The header is a
+ sequence of lines of characters with special syntax as defined in
+ this standard. The body is simply a sequence of characters that
+ follows the header and is separated from the header by an empty line
+ (i.e., a line with nothing preceding the CRLF).
+
+2.1.1. Line Length Limits
+
+ There are two limits that this standard places on the number of
+ characters in a line. Each line of characters MUST be no more than
+ 998 characters, and SHOULD be no more than 78 characters, excluding
+ the CRLF.
+
+ The 998 character limit is due to limitations in many implementations
+ which send, receive, or store Internet Message Format messages that
+ simply cannot handle more than 998 characters on a line. Receiving
+ implementations would do well to handle an arbitrarily large number
+ of characters in a line for robustness sake. However, there are so
+ many implementations which (in compliance with the transport
+ requirements of [RFC2821]) do not accept messages containing more
+ than 1000 character including the CR and LF per line, it is important
+ for implementations not to create such messages.
+
+ The more conservative 78 character recommendation is to accommodate
+ the many implementations of user interfaces that display these
+ messages which may truncate, or disastrously wrap, the display of
+ more than 78 characters per line, in spite of the fact that such
+ implementations are non-conformant to the intent of this
+ specification (and that of [RFC2821] if they actually cause
+ information to be lost). Again, even though this limitation is put on
+ messages, it is encumbant upon implementations which display messages
+
+
+
+
+
+Resnick Standards Track [Page 6]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ to handle an arbitrarily large number of characters in a line
+ (certainly at least up to the 998 character limit) for the sake of
+ robustness.
+
+2.2. Header Fields
+
+ Header fields are lines composed of a field name, followed by a colon
+ (":"), followed by a field body, and terminated by CRLF. A field
+ name MUST be composed of printable US-ASCII characters (i.e.,
+ characters that have values between 33 and 126, inclusive), except
+ colon. A field body may be composed of any US-ASCII characters,
+ except for CR and LF. However, a field body may contain CRLF when
+ used in header "folding" and "unfolding" as described in section
+ 2.2.3. All field bodies MUST conform to the syntax described in
+ sections 3 and 4 of this standard.
+
+2.2.1. Unstructured Header Field Bodies
+
+ Some field bodies in this standard are defined simply as
+ "unstructured" (which is specified below as any US-ASCII characters,
+ except for CR and LF) with no further restrictions. These are
+ referred to as unstructured field bodies. Semantically, unstructured
+ field bodies are simply to be treated as a single line of characters
+ with no further processing (except for header "folding" and
+ "unfolding" as described in section 2.2.3).
+
+2.2.2. Structured Header Field Bodies
+
+ Some field bodies in this standard have specific syntactical
+ structure more restrictive than the unstructured field bodies
+ described above. These are referred to as "structured" field bodies.
+ Structured field bodies are sequences of specific lexical tokens as
+ described in sections 3 and 4 of this standard. Many of these tokens
+ are allowed (according to their syntax) to be introduced or end with
+ comments (as described in section 3.2.3) as well as the space (SP,
+ ASCII value 32) and horizontal tab (HTAB, ASCII value 9) characters
+ (together known as the white space characters, WSP), and those WSP
+ characters are subject to header "folding" and "unfolding" as
+ described in section 2.2.3. Semantic analysis of structured field
+ bodies is given along with their syntax.
+
+2.2.3. Long Header Fields
+
+ Each header field is logically a single line of characters comprising
+ the field name, the colon, and the field body. For convenience
+ however, and to deal with the 998/78 character limitations per line,
+ the field body portion of a header field can be split into a multiple
+ line representation; this is called "folding". The general rule is
+
+
+
+Resnick Standards Track [Page 7]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ that wherever this standard allows for folding white space (not
+ simply WSP characters), a CRLF may be inserted before any WSP. For
+ example, the header field:
+
+ Subject: This is a test
+
+ can be represented as:
+
+ Subject: This
+ is a test
+
+ Note: Though structured field bodies are defined in such a way that
+ folding can take place between many of the lexical tokens (and even
+ within some of the lexical tokens), folding SHOULD be limited to
+ placing the CRLF at higher-level syntactic breaks. For instance, if
+ a field body is defined as comma-separated values, it is recommended
+ that folding occur after the comma separating the structured items in
+ preference to other places where the field could be folded, even if
+ it is allowed elsewhere.
+
+ The process of moving from this folded multiple-line representation
+ of a header field to its single line representation is called
+ "unfolding". Unfolding is accomplished by simply removing any CRLF
+ that is immediately followed by WSP. Each header field should be
+ treated in its unfolded form for further syntactic and semantic
+ evaluation.
+
+2.3. Body
+
+ The body of a message is simply lines of US-ASCII characters. The
+ only two limitations on the body are as follows:
+
+ - CR and LF MUST only occur together as CRLF; they MUST NOT appear
+ independently in the body.
+
+ - Lines of characters in the body MUST be limited to 998 characters,
+ and SHOULD be limited to 78 characters, excluding the CRLF.
+
+ Note: As was stated earlier, there are other standards documents,
+ specifically the MIME documents [RFC2045, RFC2046, RFC2048, RFC2049]
+ that extend this standard to allow for different sorts of message
+ bodies. Again, these mechanisms are beyond the scope of this
+ document.
+
+
+
+
+
+
+
+
+Resnick Standards Track [Page 8]
+
+RFC 2822 Internet Message Format April 2001
+
+
+3. Syntax
+
+3.1. Introduction
+
+ The syntax as given in this section defines the legal syntax of
+ Internet messages. Messages that are conformant to this standard
+ MUST conform to the syntax in this section. If there are options in
+ this section where one option SHOULD be generated, that is indicated
+ either in the prose or in a comment next to the syntax.
+
+ For the defined expressions, a short description of the syntax and
+ use is given, followed by the syntax in ABNF, followed by a semantic
+ analysis. Primitive tokens that are used but otherwise unspecified
+ come from [RFC2234].
+
+ In some of the definitions, there will be nonterminals whose names
+ start with "obs-". These "obs-" elements refer to tokens defined in
+ the obsolete syntax in section 4. In all cases, these productions
+ are to be ignored for the purposes of generating legal Internet
+ messages and MUST NOT be used as part of such a message. However,
+ when interpreting messages, these tokens MUST be honored as part of
+ the legal syntax. In this sense, section 3 defines a grammar for
+ generation of messages, with "obs-" elements that are to be ignored,
+ while section 4 adds grammar for interpretation of messages.
+
+3.2. Lexical Tokens
+
+ The following rules are used to define an underlying lexical
+ analyzer, which feeds tokens to the higher-level parsers. This
+ section defines the tokens used in structured header field bodies.
+
+ Note: Readers of this standard need to pay special attention to how
+ these lexical tokens are used in both the lower-level and
+ higher-level syntax later in the document. Particularly, the white
+ space tokens and the comment tokens defined in section 3.2.3 get used
+ in the lower-level tokens defined here, and those lower-level tokens
+ are in turn used as parts of the higher-level tokens defined later.
+ Therefore, the white space and comments may be allowed in the
+ higher-level tokens even though they may not explicitly appear in a
+ particular definition.
+
+3.2.1. Primitive Tokens
+
+ The following are primitive tokens referred to elsewhere in this
+ standard, but not otherwise defined in [RFC2234]. Some of them will
+ not appear anywhere else in the syntax, but they are convenient to
+ refer to in other parts of this document.
+
+
+
+
+Resnick Standards Track [Page 9]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ Note: The "specials" below are just such an example. Though the
+ specials token does not appear anywhere else in this standard, it is
+ useful for implementers who use tools that lexically analyze
+ messages. Each of the characters in specials can be used to indicate
+ a tokenization point in lexical analysis.
+
+NO-WS-CTL = %d1-8 / ; US-ASCII control characters
+ %d11 / ; that do not include the
+ %d12 / ; carriage return, line feed,
+ %d14-31 / ; and white space characters
+ %d127
+
+text = %d1-9 / ; Characters excluding CR and LF
+ %d11 /
+ %d12 /
+ %d14-127 /
+ obs-text
+
+specials = "(" / ")" / ; Special characters used in
+ "<" / ">" / ; other parts of the syntax
+ "[" / "]" /
+ ":" / ";" /
+ "@" / "\" /
+ "," / "." /
+ DQUOTE
+
+ No special semantics are attached to these tokens. They are simply
+ single characters.
+
+3.2.2. Quoted characters
+
+ Some characters are reserved for special interpretation, such as
+ delimiting lexical tokens. To permit use of these characters as
+ uninterpreted data, a quoting mechanism is provided.
+
+quoted-pair = ("\" text) / obs-qp
+
+ Where any quoted-pair appears, it is to be interpreted as the text
+ character alone. That is to say, the "\" character that appears as
+ part of a quoted-pair is semantically "invisible".
+
+ Note: The "\" character may appear in a message where it is not part
+ of a quoted-pair. A "\" character that does not appear in a
+ quoted-pair is not semantically invisible. The only places in this
+ standard where quoted-pair currently appears are ccontent, qcontent,
+ dcontent, no-fold-quote, and no-fold-literal.
+
+
+
+
+
+Resnick Standards Track [Page 10]
+
+RFC 2822 Internet Message Format April 2001
+
+
+3.2.3. Folding white space and comments
+
+ White space characters, including white space used in folding
+ (described in section 2.2.3), may appear between many elements in
+ header field bodies. Also, strings of characters that are treated as
+ comments may be included in structured field bodies as characters
+ enclosed in parentheses. The following defines the folding white
+ space (FWS) and comment constructs.
+
+ Strings of characters enclosed in parentheses are considered comments
+ so long as they do not appear within a "quoted-string", as defined in
+ section 3.2.5. Comments may nest.
+
+ There are several places in this standard where comments and FWS may
+ be freely inserted. To accommodate that syntax, an additional token
+ for "CFWS" is defined for places where comments and/or FWS can occur.
+ However, where CFWS occurs in this standard, it MUST NOT be inserted
+ in such a way that any line of a folded header field is made up
+ entirely of WSP characters and nothing else.
+
+FWS = ([*WSP CRLF] 1*WSP) / ; Folding white space
+ obs-FWS
+
+ctext = NO-WS-CTL / ; Non white space controls
+
+ %d33-39 / ; The rest of the US-ASCII
+ %d42-91 / ; characters not including "(",
+ %d93-126 ; ")", or "\"
+
+ccontent = ctext / quoted-pair / comment
+
+comment = "(" *([FWS] ccontent) [FWS] ")"
+
+CFWS = *([FWS] comment) (([FWS] comment) / FWS)
+
+ Throughout this standard, where FWS (the folding white space token)
+ appears, it indicates a place where header folding, as discussed in
+ section 2.2.3, may take place. Wherever header folding appears in a
+ message (that is, a header field body containing a CRLF followed by
+ any WSP), header unfolding (removal of the CRLF) is performed before
+ any further lexical analysis is performed on that header field
+ according to this standard. That is to say, any CRLF that appears in
+ FWS is semantically "invisible."
+
+ A comment is normally used in a structured field body to provide some
+ human readable informational text. Since a comment is allowed to
+ contain FWS, folding is permitted within the comment. Also note that
+ since quoted-pair is allowed in a comment, the parentheses and
+
+
+
+Resnick Standards Track [Page 11]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ backslash characters may appear in a comment so long as they appear
+ as a quoted-pair. Semantically, the enclosing parentheses are not
+ part of the comment; the comment is what is contained between the two
+ parentheses. As stated earlier, the "\" in any quoted-pair and the
+ CRLF in any FWS that appears within the comment are semantically
+ "invisible" and therefore not part of the comment either.
+
+ Runs of FWS, comment or CFWS that occur between lexical tokens in a
+ structured field header are semantically interpreted as a single
+ space character.
+
+3.2.4. Atom
+
+ Several productions in structured header field bodies are simply
+ strings of certain basic characters. Such productions are called
+ atoms.
+
+ Some of the structured header field bodies also allow the period
+ character (".", ASCII value 46) within runs of atext. An additional
+ "dot-atom" token is defined for those purposes.
+
+atext = ALPHA / DIGIT / ; Any character except controls,
+ "!" / "#" / ; SP, and specials.
+ "$" / "%" / ; Used for atoms
+ "&" / "'" /
+ "*" / "+" /
+ "-" / "/" /
+ "=" / "?" /
+ "^" / "_" /
+ "`" / "{" /
+ "|" / "}" /
+ "~"
+
+atom = [CFWS] 1*atext [CFWS]
+
+dot-atom = [CFWS] dot-atom-text [CFWS]
+
+dot-atom-text = 1*atext *("." 1*atext)
+
+ Both atom and dot-atom are interpreted as a single unit, comprised of
+ the string of characters that make it up. Semantically, the optional
+ comments and FWS surrounding the rest of the characters are not part
+ of the atom; the atom is only the run of atext characters in an atom,
+ or the atext and "." characters in a dot-atom.
+
+
+
+
+
+
+
+Resnick Standards Track [Page 12]
+
+RFC 2822 Internet Message Format April 2001
+
+
+3.2.5. Quoted strings
+
+ Strings of characters that include characters other than those
+ allowed in atoms may be represented in a quoted string format, where
+ the characters are surrounded by quote (DQUOTE, ASCII value 34)
+ characters.
+
+qtext = NO-WS-CTL / ; Non white space controls
+
+ %d33 / ; The rest of the US-ASCII
+ %d35-91 / ; characters not including "\"
+ %d93-126 ; or the quote character
+
+qcontent = qtext / quoted-pair
+
+quoted-string = [CFWS]
+ DQUOTE *([FWS] qcontent) [FWS] DQUOTE
+ [CFWS]
+
+ A quoted-string is treated as a unit. That is, quoted-string is
+ identical to atom, semantically. Since a quoted-string is allowed to
+ contain FWS, folding is permitted. Also note that since quoted-pair
+ is allowed in a quoted-string, the quote and backslash characters may
+ appear in a quoted-string so long as they appear as a quoted-pair.
+
+ Semantically, neither the optional CFWS outside of the quote
+ characters nor the quote characters themselves are part of the
+ quoted-string; the quoted-string is what is contained between the two
+ quote characters. As stated earlier, the "\" in any quoted-pair and
+ the CRLF in any FWS/CFWS that appears within the quoted-string are
+ semantically "invisible" and therefore not part of the quoted-string
+ either.
+
+3.2.6. Miscellaneous tokens
+
+ Three additional tokens are defined, word and phrase for combinations
+ of atoms and/or quoted-strings, and unstructured for use in
+ unstructured header fields and in some places within structured
+ header fields.
+
+word = atom / quoted-string
+
+phrase = 1*word / obs-phrase
+
+
+
+
+
+
+
+
+Resnick Standards Track [Page 13]
+
+RFC 2822 Internet Message Format April 2001
+
+
+utext = NO-WS-CTL / ; Non white space controls
+ %d33-126 / ; The rest of US-ASCII
+ obs-utext
+
+unstructured = *([FWS] utext) [FWS]
+
+3.3. Date and Time Specification
+
+ Date and time occur in several header fields. This section specifies
+ the syntax for a full date and time specification. Though folding
+ white space is permitted throughout the date-time specification, it
+ is RECOMMENDED that a single space be used in each place that FWS
+ appears (whether it is required or optional); some older
+ implementations may not interpret other occurrences of folding white
+ space correctly.
+
+date-time = [ day-of-week "," ] date FWS time [CFWS]
+
+day-of-week = ([FWS] day-name) / obs-day-of-week
+
+day-name = "Mon" / "Tue" / "Wed" / "Thu" /
+ "Fri" / "Sat" / "Sun"
+
+date = day month year
+
+year = 4*DIGIT / obs-year
+
+month = (FWS month-name FWS) / obs-month
+
+month-name = "Jan" / "Feb" / "Mar" / "Apr" /
+ "May" / "Jun" / "Jul" / "Aug" /
+ "Sep" / "Oct" / "Nov" / "Dec"
+
+day = ([FWS] 1*2DIGIT) / obs-day
+
+time = time-of-day FWS zone
+
+time-of-day = hour ":" minute [ ":" second ]
+
+hour = 2DIGIT / obs-hour
+
+minute = 2DIGIT / obs-minute
+
+second = 2DIGIT / obs-second
+
+zone = (( "+" / "-" ) 4DIGIT) / obs-zone
+
+
+
+
+
+Resnick Standards Track [Page 14]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ The day is the numeric day of the month. The year is any numeric
+ year 1900 or later.
+
+ The time-of-day specifies the number of hours, minutes, and
+ optionally seconds since midnight of the date indicated.
+
+ The date and time-of-day SHOULD express local time.
+
+ The zone specifies the offset from Coordinated Universal Time (UTC,
+ formerly referred to as "Greenwich Mean Time") that the date and
+ time-of-day represent. The "+" or "-" indicates whether the
+ time-of-day is ahead of (i.e., east of) or behind (i.e., west of)
+ Universal Time. The first two digits indicate the number of hours
+ difference from Universal Time, and the last two digits indicate the
+ number of minutes difference from Universal Time. (Hence, +hhmm
+ means +(hh * 60 + mm) minutes, and -hhmm means -(hh * 60 + mm)
+ minutes). The form "+0000" SHOULD be used to indicate a time zone at
+ Universal Time. Though "-0000" also indicates Universal Time, it is
+ used to indicate that the time was generated on a system that may be
+ in a local time zone other than Universal Time and therefore
+ indicates that the date-time contains no information about the local
+ time zone.
+
+ A date-time specification MUST be semantically valid. That is, the
+ day-of-the-week (if included) MUST be the day implied by the date,
+ the numeric day-of-month MUST be between 1 and the number of days
+ allowed for the specified month (in the specified year), the
+ time-of-day MUST be in the range 00:00:00 through 23:59:60 (the
+ number of seconds allowing for a leap second; see [STD12]), and the
+ zone MUST be within the range -9959 through +9959.
+
+3.4. Address Specification
+
+ Addresses occur in several message header fields to indicate senders
+ and recipients of messages. An address may either be an individual
+ mailbox, or a group of mailboxes.
+
+address = mailbox / group
+
+mailbox = name-addr / addr-spec
+
+name-addr = [display-name] angle-addr
+
+angle-addr = [CFWS] "<" addr-spec ">" [CFWS] / obs-angle-addr
+
+group = display-name ":" [mailbox-list / CFWS] ";"
+ [CFWS]
+
+
+
+
+Resnick Standards Track [Page 15]
+
+RFC 2822 Internet Message Format April 2001
+
+
+display-name = phrase
+
+mailbox-list = (mailbox *("," mailbox)) / obs-mbox-list
+
+address-list = (address *("," address)) / obs-addr-list
+
+ A mailbox receives mail. It is a conceptual entity which does not
+ necessarily pertain to file storage. For example, some sites may
+ choose to print mail on a printer and deliver the output to the
+ addressee's desk. Normally, a mailbox is comprised of two parts: (1)
+ an optional display name that indicates the name of the recipient
+ (which could be a person or a system) that could be displayed to the
+ user of a mail application, and (2) an addr-spec address enclosed in
+ angle brackets ("<" and ">"). There is also an alternate simple form
+ of a mailbox where the addr-spec address appears alone, without the
+ recipient's name or the angle brackets. The Internet addr-spec
+ address is described in section 3.4.1.
+
+ Note: Some legacy implementations used the simple form where the
+ addr-spec appears without the angle brackets, but included the name
+ of the recipient in parentheses as a comment following the addr-spec.
+ Since the meaning of the information in a comment is unspecified,
+ implementations SHOULD use the full name-addr form of the mailbox,
+ instead of the legacy form, to specify the display name associated
+ with a mailbox. Also, because some legacy implementations interpret
+ the comment, comments generally SHOULD NOT be used in address fields
+ to avoid confusing such implementations.
+
+ When it is desirable to treat several mailboxes as a single unit
+ (i.e., in a distribution list), the group construct can be used. The
+ group construct allows the sender to indicate a named group of
+ recipients. This is done by giving a display name for the group,
+ followed by a colon, followed by a comma separated list of any number
+ of mailboxes (including zero and one), and ending with a semicolon.
+ Because the list of mailboxes can be empty, using the group construct
+ is also a simple way to communicate to recipients that the message
+ was sent to one or more named sets of recipients, without actually
+ providing the individual mailbox address for each of those
+ recipients.
+
+3.4.1. Addr-spec specification
+
+ An addr-spec is a specific Internet identifier that contains a
+ locally interpreted string followed by the at-sign character ("@",
+ ASCII value 64) followed by an Internet domain. The locally
+ interpreted string is either a quoted-string or a dot-atom. If the
+ string can be represented as a dot-atom (that is, it contains no
+ characters other than atext characters or "." surrounded by atext
+
+
+
+Resnick Standards Track [Page 16]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ characters), then the dot-atom form SHOULD be used and the
+ quoted-string form SHOULD NOT be used. Comments and folding white
+ space SHOULD NOT be used around the "@" in the addr-spec.
+
+addr-spec = local-part "@" domain
+
+local-part = dot-atom / quoted-string / obs-local-part
+
+domain = dot-atom / domain-literal / obs-domain
+
+domain-literal = [CFWS] "[" *([FWS] dcontent) [FWS] "]" [CFWS]
+
+dcontent = dtext / quoted-pair
+
+dtext = NO-WS-CTL / ; Non white space controls
+
+ %d33-90 / ; The rest of the US-ASCII
+ %d94-126 ; characters not including "[",
+ ; "]", or "\"
+
+ The domain portion identifies the point to which the mail is
+ delivered. In the dot-atom form, this is interpreted as an Internet
+ domain name (either a host name or a mail exchanger name) as
+ described in [STD3, STD13, STD14]. In the domain-literal form, the
+ domain is interpreted as the literal Internet address of the
+ particular host. In both cases, how addressing is used and how
+ messages are transported to a particular host is covered in the mail
+ transport document [RFC2821]. These mechanisms are outside of the
+ scope of this document.
+
+ The local-part portion is a domain dependent string. In addresses,
+ it is simply interpreted on the particular host as a name of a
+ particular mailbox.
+
+3.5 Overall message syntax
+
+ A message consists of header fields, optionally followed by a message
+ body. Lines in a message MUST be a maximum of 998 characters
+ excluding the CRLF, but it is RECOMMENDED that lines be limited to 78
+ characters excluding the CRLF. (See section 2.1.1 for explanation.)
+ In a message body, though all of the characters listed in the text
+ rule MAY be used, the use of US-ASCII control characters (values 1
+ through 8, 11, 12, and 14 through 31) is discouraged since their
+ interpretation by receivers for display is not guaranteed.
+
+
+
+
+
+
+
+Resnick Standards Track [Page 17]
+
+RFC 2822 Internet Message Format April 2001
+
+
+message = (fields / obs-fields)
+ [CRLF body]
+
+body = *(*998text CRLF) *998text
+
+ The header fields carry most of the semantic information and are
+ defined in section 3.6. The body is simply a series of lines of text
+ which are uninterpreted for the purposes of this standard.
+
+3.6. Field definitions
+
+ The header fields of a message are defined here. All header fields
+ have the same general syntactic structure: A field name, followed by
+ a colon, followed by the field body. The specific syntax for each
+ header field is defined in the subsequent sections.
+
+ Note: In the ABNF syntax for each field in subsequent sections, each
+ field name is followed by the required colon. However, for brevity
+ sometimes the colon is not referred to in the textual description of
+ the syntax. It is, nonetheless, required.
+
+ It is important to note that the header fields are not guaranteed to
+ be in a particular order. They may appear in any order, and they
+ have been known to be reordered occasionally when transported over
+ the Internet. However, for the purposes of this standard, header
+ fields SHOULD NOT be reordered when a message is transported or
+ transformed. More importantly, the trace header fields and resent
+ header fields MUST NOT be reordered, and SHOULD be kept in blocks
+ prepended to the message. See sections 3.6.6 and 3.6.7 for more
+ information.
+
+ The only required header fields are the origination date field and
+ the originator address field(s). All other header fields are
+ syntactically optional. More information is contained in the table
+ following this definition.
+
+fields = *(trace
+ *(resent-date /
+ resent-from /
+ resent-sender /
+ resent-to /
+ resent-cc /
+ resent-bcc /
+ resent-msg-id))
+ *(orig-date /
+ from /
+ sender /
+ reply-to /
+
+
+
+Resnick Standards Track [Page 18]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ to /
+ cc /
+ bcc /
+ message-id /
+ in-reply-to /
+ references /
+ subject /
+ comments /
+ keywords /
+ optional-field)
+
+ The following table indicates limits on the number of times each
+ field may occur in a message header as well as any special
+ limitations on the use of those fields. An asterisk next to a value
+ in the minimum or maximum column indicates that a special restriction
+ appears in the Notes column.
+
+Field Min number Max number Notes
+
+trace 0 unlimited Block prepended - see
+ 3.6.7
+
+resent-date 0* unlimited* One per block, required
+ if other resent fields
+ present - see 3.6.6
+
+resent-from 0 unlimited* One per block - see
+ 3.6.6
+
+resent-sender 0* unlimited* One per block, MUST
+ occur with multi-address
+ resent-from - see 3.6.6
+
+resent-to 0 unlimited* One per block - see
+ 3.6.6
+
+resent-cc 0 unlimited* One per block - see
+ 3.6.6
+
+resent-bcc 0 unlimited* One per block - see
+ 3.6.6
+
+resent-msg-id 0 unlimited* One per block - see
+ 3.6.6
+
+orig-date 1 1
+
+from 1 1 See sender and 3.6.2
+
+
+
+Resnick Standards Track [Page 19]
+
+RFC 2822 Internet Message Format April 2001
+
+
+sender 0* 1 MUST occur with multi-
+ address from - see 3.6.2
+
+reply-to 0 1
+
+to 0 1
+
+cc 0 1
+
+bcc 0 1
+
+message-id 0* 1 SHOULD be present - see
+ 3.6.4
+
+in-reply-to 0* 1 SHOULD occur in some
+ replies - see 3.6.4
+
+references 0* 1 SHOULD occur in some
+ replies - see 3.6.4
+
+subject 0 1
+
+comments 0 unlimited
+
+keywords 0 unlimited
+
+optional-field 0 unlimited
+
+ The exact interpretation of each field is described in subsequent
+ sections.
+
+3.6.1. The origination date field
+
+ The origination date field consists of the field name "Date" followed
+ by a date-time specification.
+
+orig-date = "Date:" date-time CRLF
+
+ The origination date specifies the date and time at which the creator
+ of the message indicated that the message was complete and ready to
+ enter the mail delivery system. For instance, this might be the time
+ that a user pushes the "send" or "submit" button in an application
+ program. In any case, it is specifically not intended to convey the
+ time that the message is actually transported, but rather the time at
+ which the human or other creator of the message has put the message
+ into its final form, ready for transport. (For example, a portable
+ computer user who is not connected to a network might queue a message
+
+
+
+
+Resnick Standards Track [Page 20]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ for delivery. The origination date is intended to contain the date
+ and time that the user queued the message, not the time when the user
+ connected to the network to send the message.)
+
+3.6.2. Originator fields
+
+ The originator fields of a message consist of the from field, the
+ sender field (when applicable), and optionally the reply-to field.
+ The from field consists of the field name "From" and a
+ comma-separated list of one or more mailbox specifications. If the
+ from field contains more than one mailbox specification in the
+ mailbox-list, then the sender field, containing the field name
+ "Sender" and a single mailbox specification, MUST appear in the
+ message. In either case, an optional reply-to field MAY also be
+ included, which contains the field name "Reply-To" and a
+ comma-separated list of one or more addresses.
+
+from = "From:" mailbox-list CRLF
+
+sender = "Sender:" mailbox CRLF
+
+reply-to = "Reply-To:" address-list CRLF
+
+ The originator fields indicate the mailbox(es) of the source of the
+ message. The "From:" field specifies the author(s) of the message,
+ that is, the mailbox(es) of the person(s) or system(s) responsible
+ for the writing of the message. The "Sender:" field specifies the
+ mailbox of the agent responsible for the actual transmission of the
+ message. For example, if a secretary were to send a message for
+ another person, the mailbox of the secretary would appear in the
+ "Sender:" field and the mailbox of the actual author would appear in
+ the "From:" field. If the originator of the message can be indicated
+ by a single mailbox and the author and transmitter are identical, the
+ "Sender:" field SHOULD NOT be used. Otherwise, both fields SHOULD
+ appear.
+
+ The originator fields also provide the information required when
+ replying to a message. When the "Reply-To:" field is present, it
+ indicates the mailbox(es) to which the author of the message suggests
+ that replies be sent. In the absence of the "Reply-To:" field,
+ replies SHOULD by default be sent to the mailbox(es) specified in the
+ "From:" field unless otherwise specified by the person composing the
+ reply.
+
+ In all cases, the "From:" field SHOULD NOT contain any mailbox that
+ does not belong to the author(s) of the message. See also section
+ 3.6.3 for more information on forming the destination addresses for a
+ reply.
+
+
+
+Resnick Standards Track [Page 21]
+
+RFC 2822 Internet Message Format April 2001
+
+
+3.6.3. Destination address fields
+
+ The destination fields of a message consist of three possible fields,
+ each of the same form: The field name, which is either "To", "Cc", or
+ "Bcc", followed by a comma-separated list of one or more addresses
+ (either mailbox or group syntax).
+
+to = "To:" address-list CRLF
+
+cc = "Cc:" address-list CRLF
+
+bcc = "Bcc:" (address-list / [CFWS]) CRLF
+
+ The destination fields specify the recipients of the message. Each
+ destination field may have one or more addresses, and each of the
+ addresses indicate the intended recipients of the message. The only
+ difference between the three fields is how each is used.
+
+ The "To:" field contains the address(es) of the primary recipient(s)
+ of the message.
+
+ The "Cc:" field (where the "Cc" means "Carbon Copy" in the sense of
+ making a copy on a typewriter using carbon paper) contains the
+ addresses of others who are to receive the message, though the
+ content of the message may not be directed at them.
+
+ The "Bcc:" field (where the "Bcc" means "Blind Carbon Copy") contains
+ addresses of recipients of the message whose addresses are not to be
+ revealed to other recipients of the message. There are three ways in
+ which the "Bcc:" field is used. In the first case, when a message
+ containing a "Bcc:" field is prepared to be sent, the "Bcc:" line is
+ removed even though all of the recipients (including those specified
+ in the "Bcc:" field) are sent a copy of the message. In the second
+ case, recipients specified in the "To:" and "Cc:" lines each are sent
+ a copy of the message with the "Bcc:" line removed as above, but the
+ recipients on the "Bcc:" line get a separate copy of the message
+ containing a "Bcc:" line. (When there are multiple recipient
+ addresses in the "Bcc:" field, some implementations actually send a
+ separate copy of the message to each recipient with a "Bcc:"
+ containing only the address of that particular recipient.) Finally,
+ since a "Bcc:" field may contain no addresses, a "Bcc:" field can be
+ sent without any addresses indicating to the recipients that blind
+ copies were sent to someone. Which method to use with "Bcc:" fields
+ is implementation dependent, but refer to the "Security
+ Considerations" section of this document for a discussion of each.
+
+
+
+
+
+
+Resnick Standards Track [Page 22]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ When a message is a reply to another message, the mailboxes of the
+ authors of the original message (the mailboxes in the "From:" field)
+ or mailboxes specified in the "Reply-To:" field (if it exists) MAY
+ appear in the "To:" field of the reply since these would normally be
+ the primary recipients of the reply. If a reply is sent to a message
+ that has destination fields, it is often desirable to send a copy of
+ the reply to all of the recipients of the message, in addition to the
+ author. When such a reply is formed, addresses in the "To:" and
+ "Cc:" fields of the original message MAY appear in the "Cc:" field of
+ the reply, since these are normally secondary recipients of the
+ reply. If a "Bcc:" field is present in the original message,
+ addresses in that field MAY appear in the "Bcc:" field of the reply,
+ but SHOULD NOT appear in the "To:" or "Cc:" fields.
+
+ Note: Some mail applications have automatic reply commands that
+ include the destination addresses of the original message in the
+ destination addresses of the reply. How those reply commands behave
+ is implementation dependent and is beyond the scope of this document.
+ In particular, whether or not to include the original destination
+ addresses when the original message had a "Reply-To:" field is not
+ addressed here.
+
+3.6.4. Identification fields
+
+ Though optional, every message SHOULD have a "Message-ID:" field.
+ Furthermore, reply messages SHOULD have "In-Reply-To:" and
+ "References:" fields as appropriate, as described below.
+
+ The "Message-ID:" field contains a single unique message identifier.
+ The "References:" and "In-Reply-To:" field each contain one or more
+ unique message identifiers, optionally separated by CFWS.
+
+ The message identifier (msg-id) is similar in syntax to an angle-addr
+ construct without the internal CFWS.
+
+message-id = "Message-ID:" msg-id CRLF
+
+in-reply-to = "In-Reply-To:" 1*msg-id CRLF
+
+references = "References:" 1*msg-id CRLF
+
+msg-id = [CFWS] "<" id-left "@" id-right ">" [CFWS]
+
+id-left = dot-atom-text / no-fold-quote / obs-id-left
+
+id-right = dot-atom-text / no-fold-literal / obs-id-right
+
+no-fold-quote = DQUOTE *(qtext / quoted-pair) DQUOTE
+
+
+
+Resnick Standards Track [Page 23]
+
+RFC 2822 Internet Message Format April 2001
+
+
+no-fold-literal = "[" *(dtext / quoted-pair) "]"
+
+ The "Message-ID:" field provides a unique message identifier that
+ refers to a particular version of a particular message. The
+ uniqueness of the message identifier is guaranteed by the host that
+ generates it (see below). This message identifier is intended to be
+ machine readable and not necessarily meaningful to humans. A message
+ identifier pertains to exactly one instantiation of a particular
+ message; subsequent revisions to the message each receive new message
+ identifiers.
+
+ Note: There are many instances when messages are "changed", but those
+ changes do not constitute a new instantiation of that message, and
+ therefore the message would not get a new message identifier. For
+ example, when messages are introduced into the transport system, they
+ are often prepended with additional header fields such as trace
+ fields (described in section 3.6.7) and resent fields (described in
+ section 3.6.6). The addition of such header fields does not change
+ the identity of the message and therefore the original "Message-ID:"
+ field is retained. In all cases, it is the meaning that the sender
+ of the message wishes to convey (i.e., whether this is the same
+ message or a different message) that determines whether or not the
+ "Message-ID:" field changes, not any particular syntactic difference
+ that appears (or does not appear) in the message.
+
+ The "In-Reply-To:" and "References:" fields are used when creating a
+ reply to a message. They hold the message identifier of the original
+ message and the message identifiers of other messages (for example,
+ in the case of a reply to a message which was itself a reply). The
+ "In-Reply-To:" field may be used to identify the message (or
+ messages) to which the new message is a reply, while the
+ "References:" field may be used to identify a "thread" of
+ conversation.
+
+ When creating a reply to a message, the "In-Reply-To:" and
+ "References:" fields of the resultant message are constructed as
+ follows:
+
+ The "In-Reply-To:" field will contain the contents of the "Message-
+ ID:" field of the message to which this one is a reply (the "parent
+ message"). If there is more than one parent message, then the "In-
+ Reply-To:" field will contain the contents of all of the parents'
+ "Message-ID:" fields. If there is no "Message-ID:" field in any of
+ the parent messages, then the new message will have no "In-Reply-To:"
+ field.
+
+
+
+
+
+
+Resnick Standards Track [Page 24]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ The "References:" field will contain the contents of the parent's
+ "References:" field (if any) followed by the contents of the parent's
+ "Message-ID:" field (if any). If the parent message does not contain
+ a "References:" field but does have an "In-Reply-To:" field
+ containing a single message identifier, then the "References:" field
+ will contain the contents of the parent's "In-Reply-To:" field
+ followed by the contents of the parent's "Message-ID:" field (if
+ any). If the parent has none of the "References:", "In-Reply-To:",
+ or "Message-ID:" fields, then the new message will have no
+ "References:" field.
+
+ Note: Some implementations parse the "References:" field to display
+ the "thread of the discussion". These implementations assume that
+ each new message is a reply to a single parent and hence that they
+ can walk backwards through the "References:" field to find the parent
+ of each message listed there. Therefore, trying to form a
+ "References:" field for a reply that has multiple parents is
+ discouraged and how to do so is not defined in this document.
+
+ The message identifier (msg-id) itself MUST be a globally unique
+ identifier for a message. The generator of the message identifier
+ MUST guarantee that the msg-id is unique. There are several
+ algorithms that can be used to accomplish this. Since the msg-id has
+ a similar syntax to angle-addr (identical except that comments and
+ folding white space are not allowed), a good method is to put the
+ domain name (or a domain literal IP address) of the host on which the
+ message identifier was created on the right hand side of the "@", and
+ put a combination of the current absolute date and time along with
+ some other currently unique (perhaps sequential) identifier available
+ on the system (for example, a process id number) on the left hand
+ side. Using a date on the left hand side and a domain name or domain
+ literal on the right hand side makes it possible to guarantee
+ uniqueness since no two hosts use the same domain name or IP address
+ at the same time. Though other algorithms will work, it is
+ RECOMMENDED that the right hand side contain some domain identifier
+ (either of the host itself or otherwise) such that the generator of
+ the message identifier can guarantee the uniqueness of the left hand
+ side within the scope of that domain.
+
+ Semantically, the angle bracket characters are not part of the
+ msg-id; the msg-id is what is contained between the two angle bracket
+ characters.
+
+
+
+
+
+
+
+
+
+Resnick Standards Track [Page 25]
+
+RFC 2822 Internet Message Format April 2001
+
+
+3.6.5. Informational fields
+
+ The informational fields are all optional. The "Keywords:" field
+ contains a comma-separated list of one or more words or
+ quoted-strings. The "Subject:" and "Comments:" fields are
+ unstructured fields as defined in section 2.2.1, and therefore may
+ contain text or folding white space.
+
+subject = "Subject:" unstructured CRLF
+
+comments = "Comments:" unstructured CRLF
+
+keywords = "Keywords:" phrase *("," phrase) CRLF
+
+ These three fields are intended to have only human-readable content
+ with information about the message. The "Subject:" field is the most
+ common and contains a short string identifying the topic of the
+ message. When used in a reply, the field body MAY start with the
+ string "Re: " (from the Latin "res", in the matter of) followed by
+ the contents of the "Subject:" field body of the original message.
+ If this is done, only one instance of the literal string "Re: " ought
+ to be used since use of other strings or more than one instance can
+ lead to undesirable consequences. The "Comments:" field contains any
+ additional comments on the text of the body of the message. The
+ "Keywords:" field contains a comma-separated list of important words
+ and phrases that might be useful for the recipient.
+
+3.6.6. Resent fields
+
+ Resent fields SHOULD be added to any message that is reintroduced by
+ a user into the transport system. A separate set of resent fields
+ SHOULD be added each time this is done. All of the resent fields
+ corresponding to a particular resending of the message SHOULD be
+ together. Each new set of resent fields is prepended to the message;
+ that is, the most recent set of resent fields appear earlier in the
+ message. No other fields in the message are changed when resent
+ fields are added.
+
+ Each of the resent fields corresponds to a particular field elsewhere
+ in the syntax. For instance, the "Resent-Date:" field corresponds to
+ the "Date:" field and the "Resent-To:" field corresponds to the "To:"
+ field. In each case, the syntax for the field body is identical to
+ the syntax given previously for the corresponding field.
+
+ When resent fields are used, the "Resent-From:" and "Resent-Date:"
+ fields MUST be sent. The "Resent-Message-ID:" field SHOULD be sent.
+ "Resent-Sender:" SHOULD NOT be used if "Resent-Sender:" would be
+ identical to "Resent-From:".
+
+
+
+Resnick Standards Track [Page 26]
+
+RFC 2822 Internet Message Format April 2001
+
+
+resent-date = "Resent-Date:" date-time CRLF
+
+resent-from = "Resent-From:" mailbox-list CRLF
+
+resent-sender = "Resent-Sender:" mailbox CRLF
+
+resent-to = "Resent-To:" address-list CRLF
+
+resent-cc = "Resent-Cc:" address-list CRLF
+
+resent-bcc = "Resent-Bcc:" (address-list / [CFWS]) CRLF
+
+resent-msg-id = "Resent-Message-ID:" msg-id CRLF
+
+ Resent fields are used to identify a message as having been
+ reintroduced into the transport system by a user. The purpose of
+ using resent fields is to have the message appear to the final
+ recipient as if it were sent directly by the original sender, with
+ all of the original fields remaining the same. Each set of resent
+ fields correspond to a particular resending event. That is, if a
+ message is resent multiple times, each set of resent fields gives
+ identifying information for each individual time. Resent fields are
+ strictly informational. They MUST NOT be used in the normal
+ processing of replies or other such automatic actions on messages.
+
+ Note: Reintroducing a message into the transport system and using
+ resent fields is a different operation from "forwarding".
+ "Forwarding" has two meanings: One sense of forwarding is that a mail
+ reading program can be told by a user to forward a copy of a message
+ to another person, making the forwarded message the body of the new
+ message. A forwarded message in this sense does not appear to have
+ come from the original sender, but is an entirely new message from
+ the forwarder of the message. On the other hand, forwarding is also
+ used to mean when a mail transport program gets a message and
+ forwards it on to a different destination for final delivery. Resent
+ header fields are not intended for use with either type of
+ forwarding.
+
+ The resent originator fields indicate the mailbox of the person(s) or
+ system(s) that resent the message. As with the regular originator
+ fields, there are two forms: a simple "Resent-From:" form which
+ contains the mailbox of the individual doing the resending, and the
+ more complex form, when one individual (identified in the
+ "Resent-Sender:" field) resends a message on behalf of one or more
+ others (identified in the "Resent-From:" field).
+
+ Note: When replying to a resent message, replies behave just as they
+ would with any other message, using the original "From:",
+
+
+
+Resnick Standards Track [Page 27]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ "Reply-To:", "Message-ID:", and other fields. The resent fields are
+ only informational and MUST NOT be used in the normal processing of
+ replies.
+
+ The "Resent-Date:" indicates the date and time at which the resent
+ message is dispatched by the resender of the message. Like the
+ "Date:" field, it is not the date and time that the message was
+ actually transported.
+
+ The "Resent-To:", "Resent-Cc:", and "Resent-Bcc:" fields function
+ identically to the "To:", "Cc:", and "Bcc:" fields respectively,
+ except that they indicate the recipients of the resent message, not
+ the recipients of the original message.
+
+ The "Resent-Message-ID:" field provides a unique identifier for the
+ resent message.
+
+3.6.7. Trace fields
+
+ The trace fields are a group of header fields consisting of an
+ optional "Return-Path:" field, and one or more "Received:" fields.
+ The "Return-Path:" header field contains a pair of angle brackets
+ that enclose an optional addr-spec. The "Received:" field contains a
+ (possibly empty) list of name/value pairs followed by a semicolon and
+ a date-time specification. The first item of the name/value pair is
+ defined by item-name, and the second item is either an addr-spec, an
+ atom, a domain, or a msg-id. Further restrictions may be applied to
+ the syntax of the trace fields by standards that provide for their
+ use, such as [RFC2821].
+
+trace = [return]
+ 1*received
+
+return = "Return-Path:" path CRLF
+
+path = ([CFWS] "<" ([CFWS] / addr-spec) ">" [CFWS]) /
+ obs-path
+
+received = "Received:" name-val-list ";" date-time CRLF
+
+name-val-list = [CFWS] [name-val-pair *(CFWS name-val-pair)]
+
+name-val-pair = item-name CFWS item-value
+
+item-name = ALPHA *(["-"] (ALPHA / DIGIT))
+
+item-value = 1*angle-addr / addr-spec /
+ atom / domain / msg-id
+
+
+
+Resnick Standards Track [Page 28]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ A full discussion of the Internet mail use of trace fields is
+ contained in [RFC2821]. For the purposes of this standard, the trace
+ fields are strictly informational, and any formal interpretation of
+ them is outside of the scope of this document.
+
+3.6.8. Optional fields
+
+ Fields may appear in messages that are otherwise unspecified in this
+ standard. They MUST conform to the syntax of an optional-field.
+ This is a field name, made up of the printable US-ASCII characters
+ except SP and colon, followed by a colon, followed by any text which
+ conforms to unstructured.
+
+ The field names of any optional-field MUST NOT be identical to any
+ field name specified elsewhere in this standard.
+
+optional-field = field-name ":" unstructured CRLF
+
+field-name = 1*ftext
+
+ftext = %d33-57 / ; Any character except
+ %d59-126 ; controls, SP, and
+ ; ":".
+
+ For the purposes of this standard, any optional field is
+ uninterpreted.
+
+4. Obsolete Syntax
+
+ Earlier versions of this standard allowed for different (usually more
+ liberal) syntax than is allowed in this version. Also, there have
+ been syntactic elements used in messages on the Internet whose
+ interpretation have never been documented. Though some of these
+ syntactic forms MUST NOT be generated according to the grammar in
+ section 3, they MUST be accepted and parsed by a conformant receiver.
+ This section documents many of these syntactic elements. Taking the
+ grammar in section 3 and adding the definitions presented in this
+ section will result in the grammar to use for interpretation of
+ messages.
+
+ Note: This section identifies syntactic forms that any implementation
+ MUST reasonably interpret. However, there are certainly Internet
+ messages which do not conform to even the additional syntax given in
+ this section. The fact that a particular form does not appear in any
+ section of this document is not justification for computer programs
+ to crash or for malformed data to be irretrievably lost by any
+ implementation. To repeat an example, though this document requires
+ lines in messages to be no longer than 998 characters, silently
+
+
+
+Resnick Standards Track [Page 29]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ discarding the 999th and subsequent characters in a line without
+ warning would still be bad behavior for an implementation. It is up
+ to the implementation to deal with messages robustly.
+
+ One important difference between the obsolete (interpreting) and the
+ current (generating) syntax is that in structured header field bodies
+ (i.e., between the colon and the CRLF of any structured header
+ field), white space characters, including folding white space, and
+ comments can be freely inserted between any syntactic tokens. This
+ allows many complex forms that have proven difficult for some
+ implementations to parse.
+
+ Another key difference between the obsolete and the current syntax is
+ that the rule in section 3.2.3 regarding lines composed entirely of
+ white space in comments and folding white space does not apply. See
+ the discussion of folding white space in section 4.2 below.
+
+ Finally, certain characters that were formerly allowed in messages
+ appear in this section. The NUL character (ASCII value 0) was once
+ allowed, but is no longer for compatibility reasons. CR and LF were
+ allowed to appear in messages other than as CRLF; this use is also
+ shown here.
+
+ Other differences in syntax and semantics are noted in the following
+ sections.
+
+4.1. Miscellaneous obsolete tokens
+
+ These syntactic elements are used elsewhere in the obsolete syntax or
+ in the main syntax. The obs-char and obs-qp elements each add ASCII
+ value 0. Bare CR and bare LF are added to obs-text and obs-utext.
+ The period character is added to obs-phrase. The obs-phrase-list
+ provides for "empty" elements in a comma-separated list of phrases.
+
+ Note: The "period" (or "full stop") character (".") in obs-phrase is
+ not a form that was allowed in earlier versions of this or any other
+ standard. Period (nor any other character from specials) was not
+ allowed in phrase because it introduced a parsing difficulty
+ distinguishing between phrases and portions of an addr-spec (see
+ section 4.4). It appears here because the period character is
+ currently used in many messages in the display-name portion of
+ addresses, especially for initials in names, and therefore must be
+ interpreted properly. In the future, period may appear in the
+ regular syntax of phrase.
+
+obs-qp = "\" (%d0-127)
+
+obs-text = *LF *CR *(obs-char *LF *CR)
+
+
+
+Resnick Standards Track [Page 30]
+
+RFC 2822 Internet Message Format April 2001
+
+
+obs-char = %d0-9 / %d11 / ; %d0-127 except CR and
+ %d12 / %d14-127 ; LF
+
+obs-utext = obs-text
+
+obs-phrase = word *(word / "." / CFWS)
+
+obs-phrase-list = phrase / 1*([phrase] [CFWS] "," [CFWS]) [phrase]
+
+ Bare CR and bare LF appear in messages with two different meanings.
+ In many cases, bare CR or bare LF are used improperly instead of CRLF
+ to indicate line separators. In other cases, bare CR and bare LF are
+ used simply as ASCII control characters with their traditional ASCII
+ meanings.
+
+4.2. Obsolete folding white space
+
+ In the obsolete syntax, any amount of folding white space MAY be
+ inserted where the obs-FWS rule is allowed. This creates the
+ possibility of having two consecutive "folds" in a line, and
+ therefore the possibility that a line which makes up a folded header
+ field could be composed entirely of white space.
+
+ obs-FWS = 1*WSP *(CRLF 1*WSP)
+
+4.3. Obsolete Date and Time
+
+ The syntax for the obsolete date format allows a 2 digit year in the
+ date field and allows for a list of alphabetic time zone
+ specifications that were used in earlier versions of this standard.
+ It also permits comments and folding white space between many of the
+ tokens.
+
+obs-day-of-week = [CFWS] day-name [CFWS]
+
+obs-year = [CFWS] 2*DIGIT [CFWS]
+
+obs-month = CFWS month-name CFWS
+
+obs-day = [CFWS] 1*2DIGIT [CFWS]
+
+obs-hour = [CFWS] 2DIGIT [CFWS]
+
+obs-minute = [CFWS] 2DIGIT [CFWS]
+
+obs-second = [CFWS] 2DIGIT [CFWS]
+
+obs-zone = "UT" / "GMT" / ; Universal Time
+
+
+
+Resnick Standards Track [Page 31]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ ; North American UT
+ ; offsets
+ "EST" / "EDT" / ; Eastern: - 5/ - 4
+ "CST" / "CDT" / ; Central: - 6/ - 5
+ "MST" / "MDT" / ; Mountain: - 7/ - 6
+ "PST" / "PDT" / ; Pacific: - 8/ - 7
+
+ %d65-73 / ; Military zones - "A"
+ %d75-90 / ; through "I" and "K"
+ %d97-105 / ; through "Z", both
+ %d107-122 ; upper and lower case
+
+ Where a two or three digit year occurs in a date, the year is to be
+ interpreted as follows: If a two digit year is encountered whose
+ value is between 00 and 49, the year is interpreted by adding 2000,
+ ending up with a value between 2000 and 2049. If a two digit year is
+ encountered with a value between 50 and 99, or any three digit year
+ is encountered, the year is interpreted by adding 1900.
+
+ In the obsolete time zone, "UT" and "GMT" are indications of
+ "Universal Time" and "Greenwich Mean Time" respectively and are both
+ semantically identical to "+0000".
+
+ The remaining three character zones are the US time zones. The first
+ letter, "E", "C", "M", or "P" stands for "Eastern", "Central",
+ "Mountain" and "Pacific". The second letter is either "S" for
+ "Standard" time, or "D" for "Daylight" (or summer) time. Their
+ interpretations are as follows:
+
+ EDT is semantically equivalent to -0400
+ EST is semantically equivalent to -0500
+ CDT is semantically equivalent to -0500
+ CST is semantically equivalent to -0600
+ MDT is semantically equivalent to -0600
+ MST is semantically equivalent to -0700
+ PDT is semantically equivalent to -0700
+ PST is semantically equivalent to -0800
+
+ The 1 character military time zones were defined in a non-standard
+ way in [RFC822] and are therefore unpredictable in their meaning.
+ The original definitions of the military zones "A" through "I" are
+ equivalent to "+0100" through "+0900" respectively; "K", "L", and "M"
+ are equivalent to "+1000", "+1100", and "+1200" respectively; "N"
+ through "Y" are equivalent to "-0100" through "-1200" respectively;
+ and "Z" is equivalent to "+0000". However, because of the error in
+ [RFC822], they SHOULD all be considered equivalent to "-0000" unless
+ there is out-of-band information confirming their meaning.
+
+
+
+
+Resnick Standards Track [Page 32]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ Other multi-character (usually between 3 and 5) alphabetic time zones
+ have been used in Internet messages. Any such time zone whose
+ meaning is not known SHOULD be considered equivalent to "-0000"
+ unless there is out-of-band information confirming their meaning.
+
+4.4. Obsolete Addressing
+
+ There are three primary differences in addressing. First, mailbox
+ addresses were allowed to have a route portion before the addr-spec
+ when enclosed in "<" and ">". The route is simply a comma-separated
+ list of domain names, each preceded by "@", and the list terminated
+ by a colon. Second, CFWS were allowed between the period-separated
+ elements of local-part and domain (i.e., dot-atom was not used). In
+ addition, local-part is allowed to contain quoted-string in addition
+ to just atom. Finally, mailbox-list and address-list were allowed to
+ have "null" members. That is, there could be two or more commas in
+ such a list with nothing in between them.
+
+obs-angle-addr = [CFWS] "<" [obs-route] addr-spec ">" [CFWS]
+
+obs-route = [CFWS] obs-domain-list ":" [CFWS]
+
+obs-domain-list = "@" domain *(*(CFWS / "," ) [CFWS] "@" domain)
+
+obs-local-part = word *("." word)
+
+obs-domain = atom *("." atom)
+
+obs-mbox-list = 1*([mailbox] [CFWS] "," [CFWS]) [mailbox]
+
+obs-addr-list = 1*([address] [CFWS] "," [CFWS]) [address]
+
+ When interpreting addresses, the route portion SHOULD be ignored.
+
+4.5. Obsolete header fields
+
+ Syntactically, the primary difference in the obsolete field syntax is
+ that it allows multiple occurrences of any of the fields and they may
+ occur in any order. Also, any amount of white space is allowed
+ before the ":" at the end of the field name.
+
+obs-fields = *(obs-return /
+ obs-received /
+ obs-orig-date /
+ obs-from /
+ obs-sender /
+ obs-reply-to /
+ obs-to /
+
+
+
+Resnick Standards Track [Page 33]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ obs-cc /
+ obs-bcc /
+ obs-message-id /
+ obs-in-reply-to /
+ obs-references /
+ obs-subject /
+ obs-comments /
+ obs-keywords /
+ obs-resent-date /
+ obs-resent-from /
+ obs-resent-send /
+ obs-resent-rply /
+ obs-resent-to /
+ obs-resent-cc /
+ obs-resent-bcc /
+ obs-resent-mid /
+ obs-optional)
+
+ Except for destination address fields (described in section 4.5.3),
+ the interpretation of multiple occurrences of fields is unspecified.
+ Also, the interpretation of trace fields and resent fields which do
+ not occur in blocks prepended to the message is unspecified as well.
+ Unless otherwise noted in the following sections, interpretation of
+ other fields is identical to the interpretation of their non-obsolete
+ counterparts in section 3.
+
+4.5.1. Obsolete origination date field
+
+obs-orig-date = "Date" *WSP ":" date-time CRLF
+
+4.5.2. Obsolete originator fields
+
+obs-from = "From" *WSP ":" mailbox-list CRLF
+
+obs-sender = "Sender" *WSP ":" mailbox CRLF
+
+obs-reply-to = "Reply-To" *WSP ":" mailbox-list CRLF
+
+4.5.3. Obsolete destination address fields
+
+obs-to = "To" *WSP ":" address-list CRLF
+
+obs-cc = "Cc" *WSP ":" address-list CRLF
+
+obs-bcc = "Bcc" *WSP ":" (address-list / [CFWS]) CRLF
+
+
+
+
+
+
+Resnick Standards Track [Page 34]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ When multiple occurrences of destination address fields occur in a
+ message, they SHOULD be treated as if the address-list in the first
+ occurrence of the field is combined with the address lists of the
+ subsequent occurrences by adding a comma and concatenating.
+
+4.5.4. Obsolete identification fields
+
+ The obsolete "In-Reply-To:" and "References:" fields differ from the
+ current syntax in that they allow phrase (words or quoted strings) to
+ appear. The obsolete forms of the left and right sides of msg-id
+ allow interspersed CFWS, making them syntactically identical to
+ local-part and domain respectively.
+
+obs-message-id = "Message-ID" *WSP ":" msg-id CRLF
+
+obs-in-reply-to = "In-Reply-To" *WSP ":" *(phrase / msg-id) CRLF
+
+obs-references = "References" *WSP ":" *(phrase / msg-id) CRLF
+
+obs-id-left = local-part
+
+obs-id-right = domain
+
+ For purposes of interpretation, the phrases in the "In-Reply-To:" and
+ "References:" fields are ignored.
+
+ Semantically, none of the optional CFWS surrounding the local-part
+ and the domain are part of the obs-id-left and obs-id-right
+ respectively.
+
+4.5.5. Obsolete informational fields
+
+obs-subject = "Subject" *WSP ":" unstructured CRLF
+
+obs-comments = "Comments" *WSP ":" unstructured CRLF
+
+obs-keywords = "Keywords" *WSP ":" obs-phrase-list CRLF
+
+4.5.6. Obsolete resent fields
+
+ The obsolete syntax adds a "Resent-Reply-To:" field, which consists
+ of the field name, the optional comments and folding white space, the
+ colon, and a comma separated list of addresses.
+
+obs-resent-from = "Resent-From" *WSP ":" mailbox-list CRLF
+
+obs-resent-send = "Resent-Sender" *WSP ":" mailbox CRLF
+
+
+
+
+Resnick Standards Track [Page 35]
+
+RFC 2822 Internet Message Format April 2001
+
+
+obs-resent-date = "Resent-Date" *WSP ":" date-time CRLF
+
+obs-resent-to = "Resent-To" *WSP ":" address-list CRLF
+
+obs-resent-cc = "Resent-Cc" *WSP ":" address-list CRLF
+
+obs-resent-bcc = "Resent-Bcc" *WSP ":"
+ (address-list / [CFWS]) CRLF
+
+obs-resent-mid = "Resent-Message-ID" *WSP ":" msg-id CRLF
+
+obs-resent-rply = "Resent-Reply-To" *WSP ":" address-list CRLF
+
+ As with other resent fields, the "Resent-Reply-To:" field is to be
+ treated as trace information only.
+
+4.5.7. Obsolete trace fields
+
+ The obs-return and obs-received are again given here as template
+ definitions, just as return and received are in section 3. Their
+ full syntax is given in [RFC2821].
+
+obs-return = "Return-Path" *WSP ":" path CRLF
+
+obs-received = "Received" *WSP ":" name-val-list CRLF
+
+obs-path = obs-angle-addr
+
+4.5.8. Obsolete optional fields
+
+obs-optional = field-name *WSP ":" unstructured CRLF
+
+5. Security Considerations
+
+ Care needs to be taken when displaying messages on a terminal or
+ terminal emulator. Powerful terminals may act on escape sequences
+ and other combinations of ASCII control characters with a variety of
+ consequences. They can remap the keyboard or permit other
+ modifications to the terminal which could lead to denial of service
+ or even damaged data. They can trigger (sometimes programmable)
+ answerback messages which can allow a message to cause commands to be
+ issued on the recipient's behalf. They can also effect the operation
+ of terminal attached devices such as printers. Message viewers may
+ wish to strip potentially dangerous terminal escape sequences from
+ the message prior to display. However, other escape sequences appear
+ in messages for useful purposes (cf. [RFC2045, RFC2046, RFC2047,
+ RFC2048, RFC2049, ISO2022]) and therefore should not be stripped
+ indiscriminately.
+
+
+
+Resnick Standards Track [Page 36]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ Transmission of non-text objects in messages raises additional
+ security issues. These issues are discussed in [RFC2045, RFC2046,
+ RFC2047, RFC2048, RFC2049].
+
+ Many implementations use the "Bcc:" (blind carbon copy) field
+ described in section 3.6.3 to facilitate sending messages to
+ recipients without revealing the addresses of one or more of the
+ addressees to the other recipients. Mishandling this use of "Bcc:"
+ has implications for confidential information that might be revealed,
+ which could eventually lead to security problems through knowledge of
+ even the existence of a particular mail address. For example, if
+ using the first method described in section 3.6.3, where the "Bcc:"
+ line is removed from the message, blind recipients have no explicit
+ indication that they have been sent a blind copy, except insofar as
+ their address does not appear in the message header. Because of
+ this, one of the blind addressees could potentially send a reply to
+ all of the shown recipients and accidentally reveal that the message
+ went to the blind recipient. When the second method from section
+ 3.6.3 is used, the blind recipient's address appears in the "Bcc:"
+ field of a separate copy of the message. If the "Bcc:" field sent
+ contains all of the blind addressees, all of the "Bcc:" recipients
+ will be seen by each "Bcc:" recipient. Even if a separate message is
+ sent to each "Bcc:" recipient with only the individual's address,
+ implementations still need to be careful to process replies to the
+ message as per section 3.6.3 so as not to accidentally reveal the
+ blind recipient to other recipients.
+
+6. Bibliography
+
+ [ASCII] American National Standards Institute (ANSI), Coded
+ Character Set - 7-Bit American National Standard Code for
+ Information Interchange, ANSI X3.4, 1986.
+
+ [ISO2022] International Organization for Standardization (ISO),
+ Information processing - ISO 7-bit and 8-bit coded
+ character sets - Code extension techniques, Third edition
+ - 1986-05-01, ISO 2022, 1986.
+
+ [RFC822] Crocker, D., "Standard for the Format of ARPA Internet
+ Text Messages", RFC 822, August 1982.
+
+ [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail
+ Extensions (MIME) Part One: Format of Internet Message
+ Bodies", RFC 2045, November 1996.
+
+ [RFC2046] Freed, N. and N. Borenstein, "Multipurpose Internet Mail
+ Extensions (MIME) Part Two: Media Types", RFC 2046,
+ November 1996.
+
+
+
+Resnick Standards Track [Page 37]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ [RFC2047] Moore, K., "Multipurpose Internet Mail Extensions (MIME)
+ Part Three: Message Header Extensions for Non-ASCII Text",
+ RFC 2047, November 1996.
+
+ [RFC2048] Freed, N., Klensin, J. and J. Postel, "Multipurpose
+ Internet Mail Extensions (MIME) Part Four: Format of
+ Internet Message Bodies", RFC 2048, November 1996.
+
+ [RFC2049] Freed, N. and N. Borenstein, "Multipurpose Internet Mail
+ Extensions (MIME) Part Five: Conformance Criteria and
+ Examples", RFC 2049, November 1996.
+
+ [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+ [RFC2234] Crocker, D., Editor, and P. Overell, "Augmented BNF for
+ Syntax Specifications: ABNF", RFC 2234, November 1997.
+
+ [RFC2821] Klensin, J., Editor, "Simple Mail Transfer Protocol", RFC
+ 2821, March 2001.
+
+ [STD3] Braden, R., "Host Requirements", STD 3, RFC 1122 and RFC
+ 1123, October 1989.
+
+ [STD12] Mills, D., "Network Time Protocol", STD 12, RFC 1119,
+ September 1989.
+
+ [STD13] Mockapetris, P., "Domain Name System", STD 13, RFC 1034
+ and RFC 1035, November 1987.
+
+ [STD14] Partridge, C., "Mail Routing and the Domain System", STD
+ 14, RFC 974, January 1986.
+
+7. Editor's Address
+
+ Peter W. Resnick
+ QUALCOMM Incorporated
+ 5775 Morehouse Drive
+ San Diego, CA 92121-1714
+ USA
+
+ Phone: +1 858 651 4478
+ Fax: +1 858 651 1102
+ EMail: presnick@qualcomm.com
+
+
+
+
+
+
+
+Resnick Standards Track [Page 38]
+
+RFC 2822 Internet Message Format April 2001
+
+
+8. Acknowledgements
+
+ Many people contributed to this document. They included folks who
+ participated in the Detailed Revision and Update of Messaging
+ Standards (DRUMS) Working Group of the Internet Engineering Task
+ Force (IETF), the chair of DRUMS, the Area Directors of the IETF, and
+ people who simply sent their comments in via e-mail. The editor is
+ deeply indebted to them all and thanks them sincerely. The below
+ list includes everyone who sent e-mail concerning this document.
+ Hopefully, everyone who contributed is named here:
+
+ Matti Aarnio Barry Finkel Larry Masinter
+ Tanaka Akira Erik Forsberg Denis McKeon
+ Russ Allbery Chuck Foster William P McQuillan
+ Eric Allman Paul Fox Alexey Melnikov
+ Harald Tveit Alvestrand Klaus M. Frank Perry E. Metzger
+ Ran Atkinson Ned Freed Steven Miller
+ Jos Backus Jochen Friedrich Keith Moore
+ Bruce Balden Randall C. Gellens John Gardiner Myers
+ Dave Barr Sukvinder Singh Gill Chris Newman
+ Alan Barrett Tim Goodwin John W. Noerenberg
+ John Beck Philip Guenther Eric Norman
+ J. Robert von Behren Tony Hansen Mike O'Dell
+ Jos den Bekker John Hawkinson Larry Osterman
+ D. J. Bernstein Philip Hazel Paul Overell
+ James Berriman Kai Henningsen Jacob Palme
+ Norbert Bollow Robert Herriot Michael A. Patton
+ Raj Bose Paul Hethmon Uzi Paz
+ Antony Bowesman Jim Hill Michael A. Quinlan
+ Scott Bradner Paul E. Hoffman Eric S. Raymond
+ Randy Bush Steve Hole Sam Roberts
+ Tom Byrer Kari Hurtta Hugh Sasse
+ Bruce Campbell Marco S. Hyman Bart Schaefer
+ Larry Campbell Ofer Inbar Tom Scola
+ W. J. Carpenter Olle Jarnefors Wolfgang Segmuller
+ Michael Chapman Kevin Johnson Nick Shelness
+ Richard Clayton Sudish Joseph John Stanley
+ Maurizio Codogno Maynard Kang Einar Stefferud
+ Jim Conklin Prabhat Keni Jeff Stephenson
+ R. Kelley Cook John C. Klensin Bernard Stern
+ Steve Coya Graham Klyne Peter Sylvester
+ Mark Crispin Brad Knowles Mark Symons
+ Dave Crocker Shuhei Kobayashi Eric Thomas
+ Matt Curtin Peter Koch Lee Thompson
+ Michael D'Errico Dan Kohn Karel De Vriendt
+ Cyrus Daboo Christian Kuhtz Matthew Wall
+ Jutta Degener Anand Kumria Rolf Weber
+ Mark Delany Steen Larsen Brent B. Welch
+
+
+
+Resnick Standards Track [Page 39]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ Steve Dorner Eliot Lear Dan Wing
+ Harold A. Driscoll Barry Leiba Jack De Winter
+ Michael Elkins Jay Levitt Gregory J. Woodhouse
+ Robert Elz Lars-Johan Liman Greg A. Woods
+ Johnny Eriksson Charles Lindsey Kazu Yamamoto
+ Erik E. Fair Pete Loshin Alain Zahm
+ Roger Fajman Simon Lyall Jamie Zawinski
+ Patrik Faltstrom Bill Manning Timothy S. Zurcher
+ Claus Andre Farber John Martin
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Resnick Standards Track [Page 40]
+
+RFC 2822 Internet Message Format April 2001
+
+
+Appendix A. Example messages
+
+ This section presents a selection of messages. These are intended to
+ assist in the implementation of this standard, but should not be
+ taken as normative; that is to say, although the examples in this
+ section were carefully reviewed, if there happens to be a conflict
+ between these examples and the syntax described in sections 3 and 4
+ of this document, the syntax in those sections is to be taken as
+ correct.
+
+ Messages are delimited in this section between lines of "----". The
+ "----" lines are not part of the message itself.
+
+A.1. Addressing examples
+
+ The following are examples of messages that might be sent between two
+ individuals.
+
+A.1.1. A message from one person to another with simple addressing
+
+ This could be called a canonical message. It has a single author,
+ John Doe, a single recipient, Mary Smith, a subject, the date, a
+ message identifier, and a textual message in the body.
+
+----
+From: John Doe <jdoe@machine.example>
+To: Mary Smith <mary@example.net>
+Subject: Saying Hello
+Date: Fri, 21 Nov 1997 09:55:06 -0600
+Message-ID: <1234@local.machine.example>
+
+This is a message just to say hello.
+So, "Hello".
+----
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Resnick Standards Track [Page 41]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ If John's secretary Michael actually sent the message, though John
+ was the author and replies to this message should go back to him, the
+ sender field would be used:
+
+----
+From: John Doe <jdoe@machine.example>
+Sender: Michael Jones <mjones@machine.example>
+To: Mary Smith <mary@example.net>
+Subject: Saying Hello
+Date: Fri, 21 Nov 1997 09:55:06 -0600
+Message-ID: <1234@local.machine.example>
+
+This is a message just to say hello.
+So, "Hello".
+----
+
+A.1.2. Different types of mailboxes
+
+ This message includes multiple addresses in the destination fields
+ and also uses several different forms of addresses.
+
+----
+From: "Joe Q. Public" <john.q.public@example.com>
+To: Mary Smith <mary@x.test>, jdoe@example.org, Who? <one@y.test>
+Cc: <boss@nil.test>, "Giant; \"Big\" Box" <sysservices@example.net>
+Date: Tue, 1 Jul 2003 10:52:37 +0200
+Message-ID: <5678.21-Nov-1997@example.com>
+
+Hi everyone.
+----
+
+ Note that the display names for Joe Q. Public and Giant; "Big" Box
+ needed to be enclosed in double-quotes because the former contains
+ the period and the latter contains both semicolon and double-quote
+ characters (the double-quote characters appearing as quoted-pair
+ construct). Conversely, the display name for Who? could appear
+ without them because the question mark is legal in an atom. Notice
+ also that jdoe@example.org and boss@nil.test have no display names
+ associated with them at all, and jdoe@example.org uses the simpler
+ address form without the angle brackets.
+
+
+
+
+
+
+
+
+
+
+
+Resnick Standards Track [Page 42]
+
+RFC 2822 Internet Message Format April 2001
+
+
+A.1.3. Group addresses
+
+----
+From: Pete <pete@silly.example>
+To: A Group:Chris Jones <c@a.test>,joe@where.test,John <jdoe@one.test>;
+Cc: Undisclosed recipients:;
+Date: Thu, 13 Feb 1969 23:32:54 -0330
+Message-ID: <testabcd.1234@silly.example>
+
+Testing.
+----
+
+ In this message, the "To:" field has a single group recipient named A
+ Group which contains 3 addresses, and a "Cc:" field with an empty
+ group recipient named Undisclosed recipients.
+
+A.2. Reply messages
+
+ The following is a series of three messages that make up a
+ conversation thread between John and Mary. John firsts sends a
+ message to Mary, Mary then replies to John's message, and then John
+ replies to Mary's reply message.
+
+ Note especially the "Message-ID:", "References:", and "In-Reply-To:"
+ fields in each message.
+
+----
+From: John Doe <jdoe@machine.example>
+To: Mary Smith <mary@example.net>
+Subject: Saying Hello
+Date: Fri, 21 Nov 1997 09:55:06 -0600
+Message-ID: <1234@local.machine.example>
+
+This is a message just to say hello.
+So, "Hello".
+----
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Resnick Standards Track [Page 43]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ When sending replies, the Subject field is often retained, though
+ prepended with "Re: " as described in section 3.6.5.
+
+----
+From: Mary Smith <mary@example.net>
+To: John Doe <jdoe@machine.example>
+Reply-To: "Mary Smith: Personal Account" <smith@home.example>
+Subject: Re: Saying Hello
+Date: Fri, 21 Nov 1997 10:01:10 -0600
+Message-ID: <3456@example.net>
+In-Reply-To: <1234@local.machine.example>
+References: <1234@local.machine.example>
+
+This is a reply to your hello.
+----
+
+ Note the "Reply-To:" field in the above message. When John replies
+ to Mary's message above, the reply should go to the address in the
+ "Reply-To:" field instead of the address in the "From:" field.
+
+----
+To: "Mary Smith: Personal Account" <smith@home.example>
+From: John Doe <jdoe@machine.example>
+Subject: Re: Saying Hello
+Date: Fri, 21 Nov 1997 11:00:00 -0600
+Message-ID: <abcd.1234@local.machine.tld>
+In-Reply-To: <3456@example.net>
+References: <1234@local.machine.example> <3456@example.net>
+
+This is a reply to your reply.
+----
+
+A.3. Resent messages
+
+ Start with the message that has been used as an example several
+ times:
+
+----
+From: John Doe <jdoe@machine.example>
+To: Mary Smith <mary@example.net>
+Subject: Saying Hello
+Date: Fri, 21 Nov 1997 09:55:06 -0600
+Message-ID: <1234@local.machine.example>
+
+This is a message just to say hello.
+So, "Hello".
+----
+
+
+
+
+Resnick Standards Track [Page 44]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ Say that Mary, upon receiving this message, wishes to send a copy of
+ the message to Jane such that (a) the message would appear to have
+ come straight from John; (b) if Jane replies to the message, the
+ reply should go back to John; and (c) all of the original
+ information, like the date the message was originally sent to Mary,
+ the message identifier, and the original addressee, is preserved. In
+ this case, resent fields are prepended to the message:
+
+----
+Resent-From: Mary Smith <mary@example.net>
+Resent-To: Jane Brown <j-brown@other.example>
+Resent-Date: Mon, 24 Nov 1997 14:22:01 -0800
+Resent-Message-ID: <78910@example.net>
+From: John Doe <jdoe@machine.example>
+To: Mary Smith <mary@example.net>
+Subject: Saying Hello
+Date: Fri, 21 Nov 1997 09:55:06 -0600
+Message-ID: <1234@local.machine.example>
+
+This is a message just to say hello.
+So, "Hello".
+----
+
+ If Jane, in turn, wished to resend this message to another person,
+ she would prepend her own set of resent header fields to the above
+ and send that.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Resnick Standards Track [Page 45]
+
+RFC 2822 Internet Message Format April 2001
+
+
+A.4. Messages with trace fields
+
+ As messages are sent through the transport system as described in
+ [RFC2821], trace fields are prepended to the message. The following
+ is an example of what those trace fields might look like. Note that
+ there is some folding white space in the first one since these lines
+ can be long.
+
+----
+Received: from x.y.test
+ by example.net
+ via TCP
+ with ESMTP
+ id ABC12345
+ for <mary@example.net>; 21 Nov 1997 10:05:43 -0600
+Received: from machine.example by x.y.test; 21 Nov 1997 10:01:22 -0600
+From: John Doe <jdoe@machine.example>
+To: Mary Smith <mary@example.net>
+Subject: Saying Hello
+Date: Fri, 21 Nov 1997 09:55:06 -0600
+Message-ID: <1234@local.machine.example>
+
+This is a message just to say hello.
+So, "Hello".
+----
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Resnick Standards Track [Page 46]
+
+RFC 2822 Internet Message Format April 2001
+
+
+A.5. White space, comments, and other oddities
+
+ White space, including folding white space, and comments can be
+ inserted between many of the tokens of fields. Taking the example
+ from A.1.3, white space and comments can be inserted into all of the
+ fields.
+
+----
+From: Pete(A wonderful \) chap) <pete(his account)@silly.test(his host)>
+To:A Group(Some people)
+ :Chris Jones <c@(Chris's host.)public.example>,
+ joe@example.org,
+ John <jdoe@one.test> (my dear friend); (the end of the group)
+Cc:(Empty list)(start)Undisclosed recipients :(nobody(that I know)) ;
+Date: Thu,
+ 13
+ Feb
+ 1969
+ 23:32
+ -0330 (Newfoundland Time)
+Message-ID: <testabcd.1234@silly.test>
+
+Testing.
+----
+
+ The above example is aesthetically displeasing, but perfectly legal.
+ Note particularly (1) the comments in the "From:" field (including
+ one that has a ")" character appearing as part of a quoted-pair); (2)
+ the white space absent after the ":" in the "To:" field as well as
+ the comment and folding white space after the group name, the special
+ character (".") in the comment in Chris Jones's address, and the
+ folding white space before and after "joe@example.org,"; (3) the
+ multiple and nested comments in the "Cc:" field as well as the
+ comment immediately following the ":" after "Cc"; (4) the folding
+ white space (but no comments except at the end) and the missing
+ seconds in the time of the date field; and (5) the white space before
+ (but not within) the identifier in the "Message-ID:" field.
+
+A.6. Obsoleted forms
+
+ The following are examples of obsolete (that is, the "MUST NOT
+ generate") syntactic elements described in section 4 of this
+ document.
+
+
+
+
+
+
+
+
+Resnick Standards Track [Page 47]
+
+RFC 2822 Internet Message Format April 2001
+
+
+A.6.1. Obsolete addressing
+
+ Note in the below example the lack of quotes around Joe Q. Public,
+ the route that appears in the address for Mary Smith, the two commas
+ that appear in the "To:" field, and the spaces that appear around the
+ "." in the jdoe address.
+
+----
+From: Joe Q. Public <john.q.public@example.com>
+To: Mary Smith <@machine.tld:mary@example.net>, , jdoe@test . example
+Date: Tue, 1 Jul 2003 10:52:37 +0200
+Message-ID: <5678.21-Nov-1997@example.com>
+
+Hi everyone.
+----
+
+A.6.2. Obsolete dates
+
+ The following message uses an obsolete date format, including a non-
+ numeric time zone and a two digit year. Note that although the
+ day-of-week is missing, that is not specific to the obsolete syntax;
+ it is optional in the current syntax as well.
+
+----
+From: John Doe <jdoe@machine.example>
+To: Mary Smith <mary@example.net>
+Subject: Saying Hello
+Date: 21 Nov 97 09:55:06 GMT
+Message-ID: <1234@local.machine.example>
+
+This is a message just to say hello.
+So, "Hello".
+----
+
+A.6.3. Obsolete white space and comments
+
+ White space and comments can appear between many more elements than
+ in the current syntax. Also, folding lines that are made up entirely
+ of white space are legal.
+
+
+
+
+
+
+
+
+
+
+
+
+Resnick Standards Track [Page 48]
+
+RFC 2822 Internet Message Format April 2001
+
+
+----
+From : John Doe <jdoe@machine(comment). example>
+To : Mary Smith
+__
+ <mary@example.net>
+Subject : Saying Hello
+Date : Fri, 21 Nov 1997 09(comment): 55 : 06 -0600
+Message-ID : <1234 @ local(blah) .machine .example>
+
+This is a message just to say hello.
+So, "Hello".
+----
+
+ Note especially the second line of the "To:" field. It starts with
+ two space characters. (Note that "__" represent blank spaces.)
+ Therefore, it is considered part of the folding as described in
+ section 4.2. Also, the comments and white space throughout
+ addresses, dates, and message identifiers are all part of the
+ obsolete syntax.
+
+Appendix B. Differences from earlier standards
+
+ This appendix contains a list of changes that have been made in the
+ Internet Message Format from earlier standards, specifically [RFC822]
+ and [STD3]. Items marked with an asterisk (*) below are items which
+ appear in section 4 of this document and therefore can no longer be
+ generated.
+
+ 1. Period allowed in obsolete form of phrase.
+ 2. ABNF moved out of document to [RFC2234].
+ 3. Four or more digits allowed for year.
+ 4. Header field ordering (and lack thereof) made explicit.
+ 5. Encrypted header field removed.
+ 6. Received syntax loosened to allow any token/value pair.
+ 7. Specifically allow and give meaning to "-0000" time zone.
+ 8. Folding white space is not allowed between every token.
+ 9. Requirement for destinations removed.
+ 10. Forwarding and resending redefined.
+ 11. Extension header fields no longer specifically called out.
+ 12. ASCII 0 (null) removed.*
+ 13. Folding continuation lines cannot contain only white space.*
+ 14. Free insertion of comments not allowed in date.*
+ 15. Non-numeric time zones not allowed.*
+ 16. Two digit years not allowed.*
+ 17. Three digit years interpreted, but not allowed for generation.
+ 18. Routes in addresses not allowed.*
+ 19. CFWS within local-parts and domains not allowed.*
+ 20. Empty members of address lists not allowed.*
+
+
+
+Resnick Standards Track [Page 49]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ 21. Folding white space between field name and colon not allowed.*
+ 22. Comments between field name and colon not allowed.
+ 23. Tightened syntax of in-reply-to and references.*
+ 24. CFWS within msg-id not allowed.*
+ 25. Tightened semantics of resent fields as informational only.
+ 26. Resent-Reply-To not allowed.*
+ 27. No multiple occurrences of fields (except resent and received).*
+ 28. Free CR and LF not allowed.*
+ 29. Routes in return path not allowed.*
+ 30. Line length limits specified.
+ 31. Bcc more clearly specified.
+
+Appendix C. Notices
+
+ Intellectual Property
+
+ The IETF takes no position regarding the validity or scope of any
+ intellectual property or other rights that might be claimed to
+ pertain to the implementation or use of the technology described in
+ this document or the extent to which any license under such rights
+ might or might not be available; neither does it represent that it
+ has made any effort to identify any such rights. Information on the
+ IETF's procedures with respect to rights in standards-track and
+ standards-related documentation can be found in BCP-11. Copies of
+ claims of rights made available for publication and any assurances of
+ licenses to be made available, or the result of an attempt made to
+ obtain a general license or permission for the use of such
+ proprietary rights by implementors or users of this specification can
+ be obtained from the IETF Secretariat.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Resnick Standards Track [Page 50]
+
+RFC 2822 Internet Message Format April 2001
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (2001). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Resnick Standards Track [Page 51]
+
diff --git a/standards/rfc2910.txt b/standards/rfc2910.txt
new file mode 100644
index 000000000..e13631c2a
--- /dev/null
+++ b/standards/rfc2910.txt
@@ -0,0 +1,2579 @@
+
+
+
+
+
+
+Network Working Group R. Herriot, Editor
+Request for Comments: 2910 Xerox Corporation
+Obsoletes: 2565 S. Butler
+Category: Standards Track Hewlett-Packard
+ P. Moore
+ Peerless Systems Networking
+ R. Turner
+ 2wire.com
+ J. Wenn
+ Xerox Corporation
+ September 2000
+
+
+ Internet Printing Protocol/1.1: Encoding and Transport
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2000). All Rights Reserved.
+
+Abstract
+
+ This document is one of a set of documents, which together describe
+ all aspects of a new Internet Printing Protocol (IPP). IPP is an
+ application level protocol that can be used for distributed printing
+ using Internet tools and technologies. This document defines the
+ rules for encoding IPP operations and IPP attributes into a new
+ Internet mime media type called "application/ipp". This document
+ also defines the rules for transporting over Hypertext Transfer
+ Protocol (HTTP) a message body whose Content-Type is
+ "application/ipp". This document defines a new scheme named 'ipp' for
+ identifying IPP printers and jobs.
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 1]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ The full set of IPP documents includes:
+
+ Design Goals for an Internet Printing Protocol [RFC2567]
+ Rationale for the Structure and Model and Protocol for the Internet
+ Printing Protocol [RFC2568]
+ Internet Printing Protocol/1.1: Model and Semantics [RFC2911]
+ Internet Printing Protocol/1.1: Encoding and Transport (this
+ document)
+ Internet Printing Protocol/1.1: Implementer's Guide [ipp-iig]
+ Mapping between LPD and IPP Protocols [RFC2569]
+
+ The document, "Design Goals for an Internet Printing Protocol", takes
+ a broad look at distributed printing functionality, and it enumerates
+ real-life scenarios that help to clarify the features that need to be
+ included in a printing protocol for the Internet. It identifies
+ requirements for three types of users: end users, operators, and
+ administrators. It calls out a subset of end user requirements that
+ are satisfied in IPP/1.1. A few OPTIONAL operator operations have
+ been added to IPP/1.1.
+
+ The document, "Rationale for the Structure and Model and Protocol for
+ the Internet Printing Protocol", describes IPP from a high level
+ view, defines a roadmap for the various documents that form the suite
+ of IPP specification documents, and gives background and rationale
+ for the IETF working group's major decisions.
+
+ The document, "Internet Printing Protocol/1.1: Model and Semantics",
+ describes a simplified model with abstract objects, their attributes,
+ and their operations that are independent of encoding and transport.
+ It introduces a Printer and a Job object. The Job object optionally
+ supports multiple documents per Job. It also addresses security,
+ internationalization, and directory issues.
+
+ The document "Internet Printing Protocol/1.1: Implementer's Guide",
+ gives advice to implementers of IPP clients and IPP objects.
+
+ The document "Mapping between LPD and IPP Protocols", gives some
+ advice to implementers of gateways between IPP and LPD (Line Printer
+ Daemon) implementations.
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 2]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+Table of Contents
+
+ 1. Introduction ...................................................4
+ 2. Conformance Terminology ........................................4
+ 3. Encoding of the Operation Layer ...............................4
+ 3.1 Picture of the Encoding ...................................6
+ 3.1.1 Request and Response...................................6
+ 3.1.2 Attribute Group........................................6
+ 3.1.3 Attribute..............................................7
+ 3.1.4 Picture of the Encoding of an Attribute-with-one-value.7
+ 3.1.5 Additional-value.......................................8
+ 3.1.6 Alternative Picture of the Encoding of a Request Or a
+ Response...............................................9
+ 3.2 Syntax of Encoding ........................................9
+ 3.3 Attribute-group ..........................................11
+ 3.4 Required Parameters ......................................12
+ 3.4.1 Version-number........................................12
+ 3.4.2 Operation-id..........................................12
+ 3.4.3 Status-code...........................................12
+ 3.4.4 Request-id............................................13
+ 3.5 Tags .....................................................13
+ 3.5.1 Delimiter Tags........................................13
+ 3.5.2 Value Tags............................................14
+ 3.6 Name-Length ..............................................16
+ 3.7 (Attribute) Name .........................................16
+ 3.8 Value Length .............................................16
+ 3.9 (Attribute) Value ........................................17
+ 3.10 Data .....................................................18
+ 4. Encoding of Transport Layer ...................................18
+ 4.1 Printer-uri and job-uri ..................................19
+ 5. IPP URL Scheme ................................................20
+ 6. IANA Considerations ...........................................22
+ 7. Internationalization Considerations ...........................23
+ 8. Security Considerations .......................................23
+ 8.1 Security Conformance Requirements ........................23
+ 8.1.1 Digest Authentication.................................23
+ 8.1.2 Transport Layer Security (TLS)........................24
+ 8.2 Using IPP with TLS .......................................25
+ 9. Interoperability with IPP/1.0 Implementations .................25
+ 9.1 The "version-number" Parameter ...........................25
+ 9.2 Security and URL Schemes .................................26
+ 10. References ...................................................27
+ 11. Authors' Addresses ...........................................29
+ 12. Other Participants: ..........................................31
+ 13. Appendix A: Protocol Examples ................................33
+ 13.1 Print-Job Request ........................................33
+ 13.2 Print-Job Response (successful) ..........................34
+ 13.3 Print-Job Response (failure) .............................35
+
+
+
+Herriot, et al. Standards Track [Page 3]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ 13.4 Print-Job Response (success with attributes ignored) .....36
+ 13.5 Print-URI Request ........................................38
+ 13.6 Create-Job Request .......................................39
+ 13.7 Get-Jobs Request .........................................40
+ 13.8 Get-Jobs Response ........................................41
+ 14. Appendix B: Registration of MIME Media Type Information for
+ "application/ipp".............................................42
+ 15. Appendix C: Changes from IPP/1.0 .............................44
+ 16. Full Copyright Statement .....................................45
+
+1. Introduction
+
+ This document contains the rules for encoding IPP operations and
+ describes two layers: the transport layer and the operation layer.
+
+ The transport layer consists of an HTTP/1.1 request or response. RFC
+ 2616 [RFC2616] describes HTTP/1.1. This document specifies the HTTP
+ headers that an IPP implementation supports.
+
+ The operation layer consists of a message body in an HTTP request or
+ response. The document "Internet Printing Protocol/1.1: Model and
+ Semantics" [RFC2911] defines the semantics of such a message body and
+ the supported values. This document specifies the encoding of an IPP
+ operation. The aforementioned document [RFC2911] is henceforth
+ referred to as the "IPP model document" or simply "model document".
+
+ Note: the version number of IPP (1.1) and HTTP (1.1) are not linked.
+ They both just happen to be 1.1.
+
+2. Conformance Terminology
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHOULD", "SHOULD NOT",
+ "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be
+ interpreted as described in RFC 2119 [RFC2119].
+
+3. Encoding of the Operation Layer
+
+ The operation layer is the message body part of the HTTP request or
+ response and it MUST contain a single IPP operation request or IPP
+ operation response. Each request or response consists of a sequence
+ of values and attribute groups. Attribute groups consist of a
+ sequence of attributes each of which is a name and value. Names and
+ values are ultimately sequences of octets.
+
+ The encoding consists of octets as the most primitive type. There are
+ several types built from octets, but three important types are
+ integers, character strings and octet strings, on which most other
+ data types are built. Every character string in this encoding MUST be
+
+
+
+Herriot, et al. Standards Track [Page 4]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ a sequence of characters where the characters are associated with
+ some charset and some natural language. A character string MUST be in
+ "reading order" with the first character in the value (according to
+ reading order) being the first character in the encoding. A character
+ string whose associated charset is US-ASCII whose associated natural
+ language is US English is henceforth called a US-ASCII-STRING. A
+ character string whose associated charset and natural language are
+ specified in a request or response as described in the model document
+ is henceforth called a LOCALIZED-STRING. An octet string MUST be in
+ "IPP model document order" with the first octet in the value
+ (according to the IPP model document order) being the first octet in
+ the encoding. Every integer in this encoding MUST be encoded as a
+ signed integer using two's-complement binary encoding with big-endian
+ format (also known as "network order" and "most significant byte
+ first"). The number of octets for an integer MUST be 1, 2 or 4,
+ depending on usage in the protocol. Such one-octet integers,
+ henceforth called SIGNED-BYTE, are used for the version-number and
+ tag fields. Such two-byte integers, henceforth called SIGNED-SHORT
+ are used for the operation-id, status-code and length fields. Four
+ byte integers, henceforth called SIGNED-INTEGER, are used for value
+ fields and the request-id.
+
+ The following two sections present the encoding of the operation
+ layer in two ways:
+
+ - informally through pictures and description
+ - formally through Augmented Backus-Naur Form (ABNF), as
+ specified by RFC 2234 [RFC2234]
+
+ An operation request or response MUST use the encoding described in
+ these two sections.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 5]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+3.1 Picture of the Encoding
+
+3.1.1 Request and Response
+
+ An operation request or response is encoded as follows:
+
+ -----------------------------------------------
+ | version-number | 2 bytes - required
+ -----------------------------------------------
+ | operation-id (request) |
+ | or | 2 bytes - required
+ | status-code (response) |
+ -----------------------------------------------
+ | request-id | 4 bytes - required
+ -----------------------------------------------
+ | attribute-group | n bytes - 0 or more
+ -----------------------------------------------
+ | end-of-attributes-tag | 1 byte - required
+ -----------------------------------------------
+ | data | q bytes - optional
+ -----------------------------------------------
+
+ The first three fields in the above diagram contain the value of
+ attributes described in section 3.1.1 of the Model document.
+
+ The fourth field is the "attribute-group" field, and it occurs 0 or
+ more times. Each "attribute-group" field represents a single group of
+ attributes, such as an Operation Attributes group or a Job Attributes
+ group (see the Model document). The IPP model document specifies the
+ required attribute groups and their order for each operation request
+ and response.
+
+ The "end-of-attributes-tag" field is always present, even when the
+ "data" is not present. The Model document specifies for each
+ operation request and response whether the "data" field is present or
+ absent.
+
+3.1.2 Attribute Group
+
+ Each "attribute-group" field is encoded as follows:
+
+ -----------------------------------------------
+ | begin-attribute-group-tag | 1 byte
+ ----------------------------------------------------------
+ | attribute | p bytes |- 0 or more
+ ----------------------------------------------------------
+
+
+
+
+
+Herriot, et al. Standards Track [Page 6]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ The "begin-attribute-group-tag" field marks the beginning of an
+ "attribute-group" field and its value identifies the type of
+ attribute group, e.g. Operations Attributes group versus a Job
+ Attributes group. The "begin-attribute-group-tag" field also marks
+ the end of the previous attribute group except for the "begin-
+ attribute-group-tag" field in the first "attribute-group" field of a
+ request or response. The "begin-attribute-group-tag" field acts as
+ an "attribute-group" terminator because an "attribute-group" field
+ cannot nest inside another "attribute-group" field.
+
+ An "attribute-group" field contains zero or more "attribute" fields.
+
+ Note, the values of the "begin-attribute-group-tag" field and the
+ "end-of-attributes-tag" field are called "delimiter-tags".
+
+3.1.3 Attribute
+
+ An "attribute" field is encoded as follows:
+
+ -----------------------------------------------
+ | attribute-with-one-value | q bytes
+ ----------------------------------------------------------
+ | additional-value | r bytes |- 0 or more
+ ----------------------------------------------------------
+
+ When an attribute is single valued (e.g. "copies" with value of 10)
+ or multi-valued with one value (e.g. "sides-supported" with just the
+ value 'one-sided') it is encoded with just an "attribute-with-one-
+ value" field. When an attribute is multi-valued with n values (e.g.
+ "sides-supported" with the values 'one-sided' and 'two-sided-long-
+ edge'), it is encoded with an "attribute-with-one-value" field
+ followed by n-1 "additional-value" fields.
+
+3.1.4 Picture of the Encoding of an Attribute-with-one-value
+
+ Each "attribute-with-one-value" field is encoded as follows:
+
+ -----------------------------------------------
+ | value-tag | 1 byte
+ -----------------------------------------------
+ | name-length (value is u) | 2 bytes
+ -----------------------------------------------
+ | name | u bytes
+ -----------------------------------------------
+ | value-length (value is v) | 2 bytes
+ -----------------------------------------------
+ | value | v bytes
+ -----------------------------------------------
+
+
+
+Herriot, et al. Standards Track [Page 7]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ An "attribute-with-one-value" field is encoded with five subfields:
+
+ The "value-tag" field specifies the attribute syntax, e.g. 0x44
+ for the attribute syntax 'keyword'.
+
+ The "name-length" field specifies the length of the "name" field
+ in bytes, e.g. u in the above diagram or 15 for the name "sides-
+ supported".
+
+ The "name" field contains the textual name of the attribute, e.g.
+ "sides-supported".
+
+ The "value-length" field specifies the length of the "value" field
+ in bytes, e.g. v in the above diagram or 9 for the (keyword) value
+ 'one-sided'.
+
+ The "value" field contains the value of the attribute, e.g. the
+ textual value 'one-sided'.
+
+3.1.5 Additional-value
+
+ Each "additional-value" field is encoded as follows:
+
+ -----------------------------------------------
+ | value-tag | 1 byte
+ -----------------------------------------------
+ | name-length (value is 0x0000) | 2 bytes
+ -----------------------------------------------
+ | value-length (value is w) | 2 bytes
+ -----------------------------------------------
+ | value | w bytes
+ -----------------------------------------------
+
+ An "additional-value" is encoded with four subfields:
+
+ The "value-tag" field specifies the attribute syntax, e.g. 0x44
+ for the attribute syntax 'keyword'.
+
+ The "name-length" field has the value of 0 in order to signify
+ that it is an "additional-value". The value of the "name-length"
+ field distinguishes an "additional-value" field ("name-length" is
+ 0) from an "attribute-with-one-value" field ("name-length" is not
+ 0).
+
+ The "value-length" field specifies the length of the "value" field
+ in bytes, e.g. w in the above diagram or 19 for the (keyword)
+ value 'two-sided-long-edge'.
+
+
+
+
+Herriot, et al. Standards Track [Page 8]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ The "value" field contains the value of the attribute, e.g. the
+ textual value 'two-sided-long-edge'.
+
+3.1.6 Alternative Picture of the Encoding of a Request Or a Response
+
+ From the standpoint of a parser that performs an action based on a
+ "tag" value, the encoding consists of:
+
+ -----------------------------------------------
+ | version-number | 2 bytes - required
+ -----------------------------------------------
+ | operation-id (request) |
+ | or | 2 bytes - required
+ | status-code (response) |
+ -----------------------------------------------
+ | request-id | 4 bytes - required
+ -----------------------------------------------------------
+ | tag (delimiter-tag or value-tag) | 1 byte |
+ ----------------------------------------------- |-0 or more
+ | empty or rest of attribute | x bytes |
+ -----------------------------------------------------------
+ | end-of-attributes-tag | 1 byte - required
+ -----------------------------------------------
+ | data | y bytes - optional
+ -----------------------------------------------
+
+ The following show what fields the parser would expect after each
+ type of "tag":
+
+ - "begin-attribute-group-tag": expect zero or more "attribute"
+ fields
+ - "value-tag": expect the remainder of an "attribute-with-one-
+ value" or an "additional-value".
+ - "end-of-attributes-tag": expect that "attribute" fields are
+ complete and there is optional "data"
+
+3.2 Syntax of Encoding
+
+ The syntax below is ABNF [RFC2234] except 'strings of literals' MUST
+ be case sensitive. For example 'a' means lower case 'a' and not
+ upper case 'A'. In addition, SIGNED-BYTE and SIGNED-SHORT fields
+ are represented as '%x' values which show their range of values.
+
+ ipp-message = ipp-request / ipp-response
+ ipp-request = version-number operation-id request-id
+ *attribute-group end-of-attributes-tag data
+ ipp-response = version-number status-code request-id
+ *attribute-group end-of-attributes-tag data
+
+
+
+Herriot, et al. Standards Track [Page 9]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ attribute-group = begin-attribute-group-tag *attribute
+
+ version-number = major-version-number minor-version-number
+ major-version-number = SIGNED-BYTE
+ minor-version-number = SIGNED-BYTE
+
+ operation-id = SIGNED-SHORT ; mapping from model defined below
+ status-code = SIGNED-SHORT ; mapping from model defined below
+ request-id = SIGNED-INTEGER ; whose value is > 0
+
+ attribute = attribute-with-one-value *additional-value
+
+ attribute-with-one-value = value-tag name-length name
+ value-length value
+ additional-value = value-tag zero-name-length value-length value
+
+ name-length = SIGNED-SHORT ; number of octets of 'name'
+ name = LALPHA *( LALPHA / DIGIT / "-" / "_" / "." )
+ value-length = SIGNED-SHORT ; number of octets of 'value'
+ value = OCTET-STRING
+
+ data = OCTET-STRING
+
+ zero-name-length = %x00.00 ; name-length of 0
+ value-tag = %x10-FF ;see section 3.7.2
+ begin-attribute-group-tag = %x00-02 / %04-0F ; see section 3.7.1
+ end-of-attributes-tag = %x03 ; tag of 3
+ ; see section 3.7.1
+ SIGNED-BYTE = BYTE
+ SIGNED-SHORT = 2BYTE
+ SIGNED-INTEGER = 4BYTE
+ DIGIT = %x30-39 ; "0" to "9"
+ LALPHA = %x61-7A ; "a" to "z"
+ BYTE = %x00-FF
+ OCTET-STRING = *BYTE
+
+ The syntax below defines additional terms that are referenced in this
+ document. This syntax provides an alternate grouping of the delimiter
+ tags.
+
+ delimiter-tag = begin-attribute-group-tag / ; see section 3.7.1
+ end-of-attributes-tag
+ delimiter-tag = %x00-0F ; see section 3.7.1
+
+ begin-attribute-group-tag = %x00 / operation-attributes-tag /
+ job-attributes-tag / printer-attributes-tag /
+ unsupported-attributes-tag / %x06-0F
+ operation-attributes-tag = %x01 ; tag of 1
+
+
+
+Herriot, et al. Standards Track [Page 10]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ job-attributes-tag = %x02 ; tag of 2
+ printer-attributes-tag = %x04 ; tag of 4
+ unsupported-attributes-tag = %x05 ; tag of 5
+
+3.3 Attribute-group
+
+ Each "attribute-group" field MUST be encoded with the "begin-
+ attribute-group-tag" field followed by zero or more "attribute" sub-
+ fields.
+
+ The table below maps the model document group name to value of the
+ "begin-attribute-group-tag" field:
+
+ Model Document Group "begin-attribute-group-tag" field
+ values
+
+ Operation Attributes "operations-attributes-tag"
+ Job Template Attributes "job-attributes-tag"
+ Job Object Attributes "job-attributes-tag"
+ Unsupported Attributes "unsupported-attributes-tag"
+ Requested Attributes "job-attributes-tag"
+ (Get-Job-Attributes)
+ Requested Attributes "printer-attributes-tag"
+ (Get-Printer-Attributes)
+ Document Content in a special position as
+ described above
+
+ For each operation request and response, the model document
+ prescribes the required and optional attribute groups, along with
+ their order. Within each attribute group, the model document
+ prescribes the required and optional attributes, along with their
+ order.
+
+ When the Model document requires an attribute group in a request or
+ response and the attribute group contains zero attributes, a request
+ or response SHOULD encode the attribute group with the "begin-
+ attribute-group-tag" field followed by zero "attribute" fields. For
+ example, if the client requests a single unsupported attribute with
+ the Get-Printer-Attributes operation, the Printer MUST return no
+ "attribute" fields, and it SHOULD return a "begin-attribute-group-
+ tag" field for the Printer Attributes Group. The Unsupported
+ Attributes group is not such an example. According to the model
+ document, the Unsupported Attributes Group SHOULD be present only if
+ the unsupported attributes group contains at least one attribute.
+
+ A receiver of a request MUST be able to process the following as
+ equivalent empty attribute groups:
+
+
+
+
+Herriot, et al. Standards Track [Page 11]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ a) A "begin-attribute-group-tag" field with zero following
+ "attribute" fields.
+
+ b) An expected but missing "begin-attribute-group-tag" field.
+
+ When the Model document requires a sequence of an unknown number of
+ attribute groups, each of the same type, the encoding MUST contain
+ one "begin-attribute-group-tag" field for each attribute group even
+ when an "attribute-group" field contains zero "attribute" sub-fields.
+ For example, for the Get-Jobs operation may return zero attributes
+ for some jobs and not others. The "begin-attribute-group-tag" field
+ followed by zero "attribute" fields tells the recipient that there is
+ a job in queue for which no information is available except that it
+ is in the queue.
+
+3.4 Required Parameters
+
+ Some operation elements are called parameters in the model document
+ [RFC2911]. They MUST be encoded in a special position and they MUST
+ NOT appear as operation attributes. These parameters are described
+ in the subsections below.
+
+3.4.1 Version-number
+
+ The "version-number" field MUST consist of a major and minor
+ version-number, each of which MUST be represented by a SIGNED-BYTE.
+ The major version-number MUST be the first byte of the encoding and
+ the minor version-number MUST be the second byte of the encoding. The
+ protocol described in this document MUST have a major version-number
+ of 1 (0x01) and a minor version-number of 1 (0x01). The ABNF for
+ these two bytes MUST be %x01.01.
+
+3.4.2 Operation-id
+
+ The "operation-id" field MUST contain an operation-id value defined
+ in the model document. The value MUST be encoded as a SIGNED-SHORT
+ and it MUST be in the third and fourth bytes of the encoding of an
+ operation request.
+
+3.4.3 Status-code
+
+ The "status-code" field MUST contain a status-code value defined in
+ the model document. The value MUST be encoded as a SIGNED-SHORT and
+ it MUST be in the third and fourth bytes of the encoding of an
+ operation response.
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 12]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ The status-code is an operation attribute in the model document. In
+ the protocol, the status-code is in a special position, outside of
+ the operation attributes.
+
+ If an IPP status-code is returned, then the HTTP Status-Code MUST be
+ 200 (successful-ok). With any other HTTP Status-Code value, the HTTP
+ response MUST NOT contain an IPP message-body, and thus no IPP
+ status-code is returned.
+
+3.4.4 Request-id
+
+ The "request-id" field MUST contain a request-id value as defined in
+ the model document. The value MUST be encoded as a SIGNED-INTEGER and
+ it MUST be in the fifth through eighth bytes of the encoding.
+
+3.5 Tags
+
+ There are two kinds of tags:
+
+ - delimiter tags: delimit major sections of the protocol, namely
+ attributes and data
+ - value tags: specify the type of each attribute value
+
+3.5.1 Delimiter Tags
+
+ The following table specifies the values for the delimiter tags:
+
+ Tag Value (Hex) Meaning
+
+ 0x00 reserved for definition in a future IETF
+ standards track document
+ 0x01 "operation-attributes-tag"
+ 0x02 "job-attributes-tag"
+ 0x03 "end-of-attributes-tag"
+ 0x04 "printer-attributes-tag"
+ 0x05 "unsupported-attributes-tag"
+ 0x06-0x0f reserved for future delimiters in IETF
+ standards track documents
+
+ When a "begin-attribute-group-tag" field occurs in the protocol, it
+ means that zero or more following attributes up to the next delimiter
+ tag MUST be attributes belonging to the attribute group specified by
+ the value of the "begin-attribute-group-tag". For example, if the
+ value of "begin-attribute-group-tag" is 0x01, the following
+ attributes MUST be members of the Operations Attributes group.
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 13]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ The "end-of-attributes-tag" (value 0x03) MUST occur exactly once in
+ an operation. It MUST be the last "delimiter-tag". If the operation
+ has a document-content group, the document data in that group MUST
+ follow the "end-of-attributes-tag".
+
+ The order and presence of "attribute-group" fields (whose beginning
+ is marked by the "begin-attribute-group-tag" subfield) for each
+ operation request and each operation response MUST be that defined in
+ the model document. For further details, see section 3.7 "(Attribute)
+ Name" and 13 "Appendix A: Protocol Examples".
+
+ A Printer MUST treat a "delimiter-tag" (values from 0x00 through
+ 0x0F) differently from a "value-tag" (values from 0x10 through 0xFF)
+ so that the Printer knows that there is an entire attribute group
+ that it doesn't understand as opposed to a single value that it
+ doesn't understand.
+
+3.5.2 Value Tags
+
+ The remaining tables show values for the "value-tag" field, which is
+ the first octet of an attribute. The "value-tag" field specifies the
+ type of the value of the attribute.
+
+ The following table specifies the "out-of-band" values for the
+ "value-tag" field.
+
+ Tag Value (Hex) Meaning
+
+ 0x10 unsupported
+ 0x11 reserved for 'default' for definition in a future
+ IETF standards track document
+ 0x12 unknown
+ 0x13 no-value
+ 0x14-0x1F reserved for "out-of-band" values in future IETF
+ standards track documents.
+
+ The following table specifies the integer values for the "value-tag"
+ field:
+
+ Tag Value (Hex) Meaning
+
+ 0x20 reserved for definition in a future IETF
+ standards track document
+ 0x21 integer
+ 0x22 boolean
+ 0x23 enum
+ 0x24-0x2F reserved for integer types for definition in
+ future IETF standards track documents
+
+
+
+Herriot, et al. Standards Track [Page 14]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ NOTE: 0x20 is reserved for "generic integer" if it should ever be
+ needed.
+
+ The following table specifies the octetString values for the "value-
+ tag" field:
+
+ Tag Value (Hex) Meaning
+
+ 0x30 octetString with an unspecified format
+ 0x31 dateTime
+ 0x32 resolution
+ 0x33 rangeOfInteger
+ 0x34 reserved for definition in a future IETF
+ standards track document
+ 0x35 textWithLanguage
+ 0x36 nameWithLanguage
+ 0x37-0x3F reserved for octetString type definitions in
+ future IETF standards track documents
+
+ The following table specifies the character-string values for the
+ "value-tag" field:
+
+ Tag Value (Hex) Meaning
+
+ 0x40 reserved for definition in a future IETF
+ standards track document
+ 0x41 textWithoutLanguage
+ 0x42 nameWithoutLanguage
+ 0x43 reserved for definition in a future IETF
+ standards track document
+ 0x44 keyword
+ 0x45 uri
+ 0x46 uriScheme
+ 0x47 charset
+ 0x48 naturalLanguage
+ 0x49 mimeMediaType
+ 0x4A-0x5F reserved for character string type definitions
+ in future IETF standards track documents
+
+ NOTE: 0x40 is reserved for "generic character-string" if it should
+ ever be needed.
+
+ NOTE: an attribute value always has a type, which is explicitly
+ specified by its tag; one such tag value is "nameWithoutLanguage".
+ An attribute's name has an implicit type, which is keyword.
+
+ The values 0x60-0xFF are reserved for future type definitions in IETF
+ standards track documents.
+
+
+
+Herriot, et al. Standards Track [Page 15]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ The tag 0x7F is reserved for extending types beyond the 255 values
+ available with a single byte. A tag value of 0x7F MUST signify that
+ the first 4 bytes of the value field are interpreted as the tag
+ value. Note this future extension doesn't affect parsers that are
+ unaware of this special tag. The tag is like any other unknown tag,
+ and the value length specifies the length of a value, which contains
+ a value that the parser treats atomically. Values from 0x00 to
+ 0x37777777 are reserved for definition in future IETF standard track
+ documents. The values 0x40000000 to 0x7FFFFFFF are reserved for
+ vendor extensions.
+
+3.6 Name-Length
+
+ The "name-length" field MUST consist of a SIGNED-SHORT. This field
+ MUST specify the number of octets in the immediately following "name"
+ field. The value of this field excludes the two bytes of the "name-
+ length" field. For example, if the "name" field contains "sides", the
+ value of this field is 5.
+
+ If a "name-length" field has a value of zero, the following "name"
+ field MUST be empty, and the following value MUST be treated as an
+ additional value for the attribute encoded in the nearest preceding
+ "attribute-with-one-value" field. Within an attribute group, if two
+ or more attributes have the same name, the attribute group is mal-
+ formed (see [RFC2911] section 3.1.3). The zero-length name is the
+ only mechanism for multi-valued attributes.
+
+3.7 (Attribute) Name
+
+ The "name" field MUST contain the name of an attribute. The model
+ document [RFC2911] specifies such names.
+
+3.8 Value Length
+
+ The "value-length" field MUST consist of a SIGNED-SHORT. This field
+ MUST specify the number of octets in the immediately following
+ "value" field. The value of this field excludes the two bytes of the
+ "value-length" field. For example, if the "value" field contains the
+ keyword (text) value 'one-sided', the value of this field is 9.
+
+ For any of the types represented by binary signed integers, the
+ sender MUST encode the value in exactly four octets.
+
+ For any of the types represented by character-strings, the sender
+ MUST encode the value with all the characters of the string and
+ without any padding characters.
+
+
+
+
+
+Herriot, et al. Standards Track [Page 16]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ For "out-of-band" "value-tag" fields defined in this document, such
+ as "unsupported", the "value-length" MUST be 0 and the "value" empty;
+ the "value" has no meaning when the "value-tag" has one of these
+ "out-of-band" values. For future "out-of-band" "value-tag" fields,
+ the same rule holds unless the definition explicitly states that the
+ "value-length" MAY be non-zero and the "value" non-empty.
+
+3.9 (Attribute) Value
+
+ The syntax types (specified by the "value-tag" field) and most of the
+ details of the representation of attribute values are defined in the
+ IPP model document. The table below augments the information in the
+ model document, and defines the syntax types from the model document
+ in terms of the 5 basic types defined in section 3, "Encoding of the
+ Operation Layer". The 5 types are US-ASCII-STRING, LOCALIZED-STRING,
+ SIGNED-INTEGER, SIGNED-SHORT, SIGNED-BYTE, and OCTET-STRING.
+
+ Syntax of Attribute Encoding
+ Value
+
+ textWithoutLanguage, LOCALIZED-STRING.
+ nameWithoutLanguage
+
+ textWithLanguage OCTET-STRING consisting of 4 fields:
+ a. a SIGNED-SHORT which is the number of
+ octets in the following field
+ b. a value of type natural-language,
+ c. a SIGNED-SHORT which is the number of
+ octets in the following field,
+ d. a value of type textWithoutLanguage.
+ The length of a textWithLanguage value MUST be
+ 4 + the value of field a + the value of field c.
+
+ nameWithLanguage OCTET-STRING consisting of 4 fields:
+ a. a SIGNED-SHORT which is the number of
+ octets in the following field
+ b. a value of type natural-language,
+ c. a SIGNED-SHORT which is the number of
+ octets in the following field
+ d. a value of type nameWithoutLanguage.
+ The length of a nameWithLanguage value MUST be
+ 4 + the value of field a + the value of field c.
+
+ charset, US-ASCII-STRING.
+ naturalLanguage,
+ mimeMediaType,
+ keyword, uri, and
+ uriScheme
+
+
+
+Herriot, et al. Standards Track [Page 17]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ Syntax of Attribute Encoding
+ Value
+
+ boolean SIGNED-BYTE where 0x00 is 'false' and 0x01 is
+ 'true'.
+
+ integer and enum a SIGNED-INTEGER.
+
+ dateTime OCTET-STRING consisting of eleven octets whose
+ contents are defined by "DateAndTime" in RFC
+ 1903 [RFC1903].
+
+ resolution OCTET-STRING consisting of nine octets of 2
+ SIGNED-INTEGERs followed by a SIGNED-BYTE. The
+ first SIGNED-INTEGER contains the value of
+ cross feed direction resolution. The second
+ SIGNED-INTEGER contains the value of feed
+ direction resolution. The SIGNED-BYTE contains
+ the units
+
+ rangeOfInteger Eight octets consisting of 2 SIGNED-INTEGERs.
+ The first SIGNED-INTEGER contains the lower
+ bound and the second SIGNED-INTEGER contains
+ the upper bound.
+
+ 1setOf X Encoding according to the rules for an
+ attribute with more than 1 value. Each value
+ X is encoded according to the rules for
+ encoding its type.
+
+ octetString OCTET-STRING
+
+
+ The attribute syntax type of the value determines its encoding and
+ the value of its "value-tag".
+
+3.10 Data
+
+ The "data" field MUST include any data required by the operation
+
+4. Encoding of Transport Layer
+
+ HTTP/1.1 [RFC2616] is the transport layer for this protocol.
+
+ The operation layer has been designed with the assumption that the
+ transport layer contains the following information:
+
+
+
+
+
+Herriot, et al. Standards Track [Page 18]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ - the URI of the target job or printer operation
+ - the total length of the data in the operation layer, either as
+ a single length or as a sequence of chunks each with a length.
+
+ It is REQUIRED that a printer implementation support HTTP over the
+ IANA assigned Well Known Port 631 (the IPP default port), though a
+ printer implementation may support HTTP over some other port as well.
+
+ Each HTTP operation MUST use the POST method where the request-URI is
+ the object target of the operation, and where the "Content-Type" of
+ the message-body in each request and response MUST be
+ "application/ipp". The message-body MUST contain the operation layer
+ and MUST have the syntax described in section 3.2 "Syntax of
+ Encoding". A client implementation MUST adhere to the rules for a
+ client described for HTTP1.1 [RFC2616]. A printer (server)
+ implementation MUST adhere the rules for an origin server described
+ for HTTP1.1 [RFC2616].
+
+ An IPP server sends a response for each request that it receives. If
+ an IPP server detects an error, it MAY send a response before it has
+ read the entire request. If the HTTP layer of the IPP server
+ completes processing the HTTP headers successfully, it MAY send an
+ intermediate response, such as "100 Continue", with no IPP data
+ before sending the IPP response. A client MUST expect such a variety
+ of responses from an IPP server. For further information on HTTP/1.1,
+ consult the HTTP documents [RFC2616].
+
+ An HTTP server MUST support chunking for IPP requests, and an IPP
+ client MUST support chunking for IPP responses according to HTTP/1.1
+ [RFC2616]. Note: this rule causes a conflict with non-compliant
+ implementations of HTTP/1.1 that don't support chunking for POST
+ methods, and this rule may cause a conflict with non-compliant
+ implementations of HTTP/1.1 that don't support chunking for CGI
+ scripts.
+
+4.1 Printer-uri and job-uri
+
+ All Printer and Job objects are identified by a Uniform Resource
+ Identifier (URI) [RFC2396] so that they can be persistently and
+ unambiguously referenced. Since every URL is a specialized form of a
+ URI, even though the more generic term URI is used throughout the
+ rest of this document, its usage is intended to cover the more
+ specific notion of URL as well.
+
+
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 19]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ Some operation elements are encoded twice, once as the request-URI on
+ the HTTP Request-Line and a second time as a REQUIRED operation
+ attribute in the application/ipp entity. These attributes are the
+ target URI for the operation and are called printer-uri and job-uri.
+ Note: The target URI is included twice in an operation referencing
+ the same IPP object, but the two URIs NEED NOT be literally
+ identical. One can be a relative URI and the other can be an absolute
+ URI. HTTP/1.1 allows clients to generate and send a relative URI
+ rather than an absolute URI. A relative URI identifies a resource
+ with the scope of the HTTP server, but does not include scheme, host
+ or port. The following statements characterize how URLs should be
+ used in the mapping of IPP onto HTTP/1.1:
+
+ 1. Although potentially redundant, a client MUST supply the target
+ of the operation both as an operation attribute and as a URI at
+ the HTTP layer. The rationale for this decision is to maintain
+ a consistent set of rules for mapping application/ipp to
+ possibly many communication layers, even where URLs are not
+ used as the addressing mechanism in the transport layer.
+ 2. Even though these two URLs might not be literally identical
+ (one being relative and the other being absolute), they MUST
+ both reference the same IPP object. However, a Printer NEED NOT
+ verify that the two URLs reference the same IPP object, and
+ NEED NOT take any action if it determines the two URLs to be
+ different.
+ 3. The URI in the HTTP layer is either relative or absolute and is
+ used by the HTTP server to route the HTTP request to the
+ correct resource relative to that HTTP server. The HTTP server
+ need not be aware of the URI within the operation request.
+ 4. Once the HTTP server resource begins to process the HTTP
+ request, it might get the reference to the appropriate IPP
+ Printer object from either the HTTP URI (using to the context
+ of the HTTP server for relative URLs) or from the URI within
+ the operation request; the choice is up to the implementation.
+ 5. HTTP URIs can be relative or absolute, but the target URI in
+ the operation MUST be an absolute URI.
+
+5. IPP URL Scheme
+
+ The IPP/1.1 document defines a new scheme 'ipp' as the value of a URL
+ that identifies either an IPP printer object or an IPP job object.
+ The IPP attributes using the 'ipp' scheme are specified below.
+ Because the HTTP layer does not support the 'ipp' scheme, a client
+ MUST map 'ipp' URLs to 'http' URLs, and then follows the HTTP
+ [RFC2616][RFC2617] rules for constructing a Request-Line and HTTP
+ headers. The mapping is simple because the 'ipp' scheme implies all
+ of the same protocol semantics as that of the 'http' scheme
+
+
+
+
+Herriot, et al. Standards Track [Page 20]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ [RFC2616], except that it represents a print service and the implicit
+ (default) port number that clients use to connect to a server is port
+ 631.
+
+ In the remainder of this section the term 'ipp-URL' means a URL whose
+ scheme is 'ipp' and whose implicit (default) port is 631. The term
+ 'http-URL' means a URL whose scheme is 'http', and the term 'https-
+ URL' means a URL whose scheme is 'https',
+
+ A client and an IPP object (i.e. the server) MUST support the ipp-URL
+ value in the following IPP attributes.
+ job attributes:
+ job-uri
+ job-printer-uri
+ printer attributes:
+ printer-uri-supported
+ operation attributes:
+ job-uri
+ printer-uri
+ Each of the above attributes identifies a printer or job object. The
+ ipp-URL is intended as the value of the attributes in this list, and
+ for no other attributes. All of these attributes have a syntax type
+ of 'uri', but there are attributes with a syntax type of 'uri' that
+ do not use the 'ipp' scheme, e.g. 'job-more-info'.
+
+ If a printer registers its URL with a directory service, the printer
+ MUST register an ipp-URL.
+
+ User interfaces are beyond the scope of this document. But if
+ software exposes the ipp-URL values of any of the above five
+ attributes to a human user, it is REQUIRED that the human see the
+ ipp-URL as is.
+
+ When a client sends a request, it MUST convert a target ipp-URL to a
+ target http-URL for the HTTP layer according to the following rules:
+
+ 1. change the 'ipp' scheme to 'http'
+ 2. add an explicit port 631 if the URL does not contain an
+ explicit port. Note: port 631 is the IANA assigned Well Known
+ Port for the 'ipp' scheme.
+
+ The client MUST use the target http-URL in both the HTTP Request-
+ Line and HTTP headers, as specified by HTTP [RFC2616] [RFC2617] .
+ However, the client MUST use the target ipp-URL for the value of the
+ "printer-uri" or "job-uri" operation attribute within the
+ application/ipp body of the request. The server MUST use the ipp-URL
+
+
+
+
+
+Herriot, et al. Standards Track [Page 21]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ for the value of the "printer-uri", "job-uri" or "printer-uri-
+ supported" attributes within the application/ipp body of the
+ response.
+
+ For example, when an IPP client sends a request directly (i.e. no
+ proxy) to an ipp-URL "ipp://myhost.com/myprinter/myqueue", it opens a
+ TCP connection to port 631 (the ipp implicit port) on the host
+ "myhost.com" and sends the following data:
+
+ POST /myprinter/myqueue HTTP/1.1
+ Host: myhost.com:631
+ Content-type: application/ipp
+ Transfer-Encoding: chunked
+ ...
+ "printer-uri" "ipp://myhost.com/myprinter/myqueue"
+ (encoded in application/ipp message body)
+ ...
+
+ As another example, when an IPP client sends the same request as
+ above via a proxy "myproxy.com", it opens a TCP connection to the
+ proxy port 8080 on the proxy host "myproxy.com" and sends the
+ following data:
+
+ POST http://myhost.com:631/myprinter/myqueue HTTP/1.1
+ Host: myhost.com:631
+ Content-type: application/ipp
+ Transfer-Encoding: chunked
+ ...
+ "printer-uri" "ipp://myhost.com/myprinter/myqueue"
+ (encoded in application/ipp message body)
+ ...
+
+ The proxy then connects to the IPP origin server with headers that
+ are the same as the "no-proxy" example above.
+
+6. IANA Considerations
+
+ This section describes the procedures for allocating encoding for the
+ following IETF standards track extensions and vendor extensions to
+ the IPP/1.1 Encoding and Transport document:
+
+ 1. attribute syntaxes - see [RFC2911] section 6.3
+ 2. attribute groups - see [RFC2911] section 6.5
+ 3. out-of-band attribute values - see [RFC2911] section 6.7
+
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 22]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ These extensions follow the "type2" registration procedures defined
+ in [RFC2911] section 6. Extensions registered for use with IPP/1.1
+ are OPTIONAL for client and IPP object conformance to the IPP/1.1
+ Encoding and Transport document.
+
+ These extension procedures are aligned with the guidelines as set
+ forth by the IESG [IANA-CON]. The [RFC2911] Section 11 describes how
+ to propose new registrations for consideration. IANA will reject
+ registration proposals that leave out required information or do not
+ follow the appropriate format described in [RFC2911] Section 11. The
+ IPP/1.1 Encoding and Transport document may also be extended by an
+ appropriate RFC that specifies any of the above extensions.
+
+7. Internationalization Considerations
+
+ See the section on "Internationalization Considerations" in the
+ document "Internet Printing Protocol/1.1: Model and Semantics"
+ [RFC2911] for information on internationalization. This document adds
+ no additional issues.
+
+8. Security Considerations
+
+ The IPP Model and Semantics document [RFC2911] discusses high level
+ security requirements (Client Authentication, Server Authentication
+ and Operation Privacy). Client Authentication is the mechanism by
+ which the client proves its identity to the server in a secure
+ manner. Server Authentication is the mechanism by which the server
+ proves its identity to the client in a secure manner. Operation
+ Privacy is defined as a mechanism for protecting operations from
+ eavesdropping.
+
+8.1 Security Conformance Requirements
+
+ This section defines the security requirements for IPP clients and
+ IPP objects.
+
+8.1.1 Digest Authentication
+
+ IPP clients MUST support:
+
+ Digest Authentication [RFC2617].
+
+ MD5 and MD5-sess MUST be implemented and supported.
+
+ The Message Integrity feature NEED NOT be used.
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 23]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ IPP Printers SHOULD support:
+
+ Digest Authentication [RFC2617].
+
+ MD5 and MD5-sess MUST be implemented and supported.
+
+ The Message Integrity feature NEED NOT be used.
+
+ The reasons that IPP Printers SHOULD (rather than MUST) support
+ Digest Authentication are:
+
+ 1. While Client Authentication is important, there is a certain class
+ of printer devices where it does not make sense. Specifically, a
+ low-end device with limited ROM space and low paper throughput may
+ not need Client Authentication. This class of device typically
+ requires firmware designers to make trade-offs between protocols
+ and functionality to arrive at the lowest-cost solution possible.
+ Factored into the designer's decisions is not just the size of the
+ code, but also the testing, maintenance, usefulness, and time-to-
+ market impact for each feature delivered to the customer. Forcing
+ such low-end devices to provide security in order to claim IPP/1.1
+ conformance would not make business sense and could potentially
+ stall the adoption of the standard.
+
+ 2. Print devices that have high-volume throughput and have available
+ ROM space have a compelling argument to provide support for Client
+ Authentication that safeguards the device from unauthorized
+ access. These devices are prone to a high loss of consumables and
+ paper if unauthorized access should occur.
+
+8.1.2 Transport Layer Security (TLS)
+
+ IPP Printers SHOULD support Transport Layer Security (TLS) [RFC2246]
+ for Server Authentication and Operation Privacy. IPP Printers MAY
+ also support TLS for Client Authentication. If an IPP Printer
+ supports TLS, it MUST support the TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA
+ cipher suite as mandated by RFC 2246 [RFC2246]. All other cipher
+ suites are OPTIONAL. An IPP Printer MAY support Basic Authentication
+ (described in HTTP/1.1 [RFC2617]) for Client Authentication if the
+ channel is secure. TLS with the above mandated cipher suite can
+ provide such a secure channel.
+
+ If a IPP client supports TLS, it MUST support the
+ TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA cipher suite as mandated by RFC
+ 2246 [RFC2246]. All other cipher suites are OPTIONAL.
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 24]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ The IPP Model and Semantics document defines two printer attributes
+ ("uri-authentication-supported" and "uri-security-supported") that
+ the client can use to discover the security policy of a printer. That
+ document also outlines IPP-specific security considerations and
+ should be the primary reference for security implications with regard
+ to the IPP protocol itself. For backward compatibility with IPP
+ version 1.0, IPP clients and printers may also support SSL3 [ssl].
+ This is in addition to the security required in this document.
+
+8.2 Using IPP with TLS
+
+ IPP/1.1 uses the "Upgrading to TLS Within HTTP/1.1" mechanism
+ [RFC2817]. An initial IPP request never uses TLS. The client
+ requests a secure TLS connection by using the HTTP "Upgrade" header,
+ while the server agrees in the HTTP response. The switch to TLS
+ occurs either because the server grants the client's request to
+ upgrade to TLS, or a server asks to switch to TLS in its response.
+ Secure communication begins with a server's response to switch to
+ TLS.
+
+9. Interoperability with IPP/1.0 Implementations
+
+ It is beyond the scope of this specification to mandate conformance
+ with previous versions. IPP/1.1 was deliberately designed, however,
+ to make supporting previous versions easy. It is worth noting that,
+ at the time of composing this specification (1999), we would expect
+ IPP/1.1 Printer implementations to:
+
+ understand any valid request in the format of IPP/1.0, or 1.1;
+
+ respond appropriately with a response containing the same
+ "version-number" parameter value used by the client in the
+ request.
+
+ And we would expect IPP/1.1 clients to:
+
+ understand any valid response in the format of IPP/1.0, or 1.1.
+
+9.1 The "version-number" Parameter
+
+ The following are rules regarding the "version-number" parameter (see
+ section 3.3):
+
+ 1. Clients MUST send requests containing a "version-number"
+ parameter with a '1.1' value and SHOULD try supplying alternate
+ version numbers if they receive a 'server-error-version-not-
+ supported' error return in a response.
+
+
+
+
+Herriot, et al. Standards Track [Page 25]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ 2. IPP objects MUST accept requests containing a "version-number"
+ parameter with a '1.1' value (or reject the request for reasons
+ other than 'server-error-version-not-supported').
+
+ 3. It is recommended that IPP objects accept any request with the
+ major version '1' (or reject the request for reasons other than
+ 'server-error-version-not-supported'). See [RFC2911]
+ "versions" sub-section.
+
+ 4. In any case, security MUST NOT be compromised when a client
+ supplies a lower "version-number" parameter in a request. For
+ example, if an IPP/1.1 conforming Printer object accepts
+ version '1.0' requests and is configured to enforce Digest
+ Authentication, it MUST do the same for a version '1.0'
+ request.
+
+9.2 Security and URL Schemes
+
+ The following are rules regarding security, the "version-number"
+ parameter, and the URL scheme supplied in target attributes and
+ responses:
+
+ 1. When a client supplies a request, the "printer-uri" or "job-
+ uri" target operation attribute MUST have the same scheme as
+ that indicated in one of the values of the "printer-uri-
+ supported" Printer attribute.
+
+ 2. When the server returns the "job-printer-uri" or "job-uri" Job
+ Description attributes, it SHOULD return the same scheme
+ ('ipp', 'https', 'http', etc.) that the client supplied in the
+ "printer-uri" or "job-uri" target operation attributes in the
+ Get-Job-Attributes or Get-Jobs request, rather than the scheme
+ used when the job was created. However, when a client requests
+ job attributes using the Get-Job-Attributes or Get-Jobs
+ operations, the jobs and job attributes that the server returns
+ depends on: (1) the security in effect when the job was
+ created, (2) the security in effect in the query request, and
+ (3) the security policy in force.
+
+ 3. It is recommended that if a server registers a non-secure ipp-
+ URL with a directory service (see [RFC2911] "Generic Directory
+ Schema" Appendix), then it also register an http-URL for
+ interoperability with IPP/1.0 clients (see section 9).
+
+ 4. In any case, security MUST NOT be compromised when a client
+ supplies an 'http' or other non-secure URL scheme in the target
+ "printer-uri" and "job-uri" operation attributes in a request.
+
+
+
+
+Herriot, et al. Standards Track [Page 26]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+10. References
+
+ [dpa] ISO/IEC 10175 Document Printing Application (DPA), June
+ 1996.
+
+ [iana] IANA Registry of Coded Character Sets:
+ ftp://ftp.isi.edu/in-notes/iana/assignments/character-
+ sets.
+
+ [IANA-CON] Narten, T. and H. Alvestrand, "Guidelines for Writing an
+ IANA Considerations Section in RFCs", BCP 26, RFC 2434,
+ October 1998.
+
+ [ipp-iig] Hastings, Tom, et al., "Internet Printing Protocol/1.1:
+ Implementer's Guide", Work in Progress.
+
+ [RFC822] Crocker, D., "Standard for the Format of ARPA Internet
+ Text Messages", STD 11, RFC 822, August 1982.
+
+ [RFC1123] Braden, S., "Requirements for Internet Hosts - Application
+ and Support", STD 3, RFC 1123, October, 1989.
+
+ [RFC1179] McLaughlin, L. III, (editor), "Line Printer Daemon
+ Protocol", RFC 1179, August 1990.
+
+ [RFC2223] Postel, J. and J. Reynolds, "Instructions to RFC Authors",
+ RFC 2223, October 1997.
+
+ [RFC1738] Berners-Lee, T., Masinter, L. and M. McCahill, "Uniform
+ Resource Locators (URL)", RFC 1738, December 1994.
+
+ [RFC1759] Smith, R., Wright, F., Hastings, T., Zilles, S. and J.
+ Gyllenskog, "Printer MIB", RFC 1759, March 1995.
+
+ [RFC1766] Alvestrand, H., "Tags for the Identification of
+ Languages", RFC 1766, March 1995.
+
+ [RFC1808] Fielding, R., "Relative Uniform Resource Locators", RFC
+ 1808, June 1995.
+
+ [RFC1903] Case, J., McCloghrie, K., Rose, M. and S. Waldbusser,
+ "Textual Conventions for Version 2 of the Simple Network
+ Management Protocol (SNMPv2)", RFC 1903, January 1996.
+
+ [RFC2046] Freed, N. and N. Borenstein, "Multipurpose Internet Mail
+ Extensions (MIME) Part Two: Media Types", RFC 2046,
+ November 1996.
+
+
+
+
+Herriot, et al. Standards Track [Page 27]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ [RFC2048] Freed, N., Klensin, J. and J. Postel, "Multipurpose
+ Internet Mail Extension (MIME) Part Four: Registration
+ Procedures", BCP 13, RFC 2048, November 1996.
+
+ [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+ [RFC2184] Freed, N. and K. Moore, "MIME Parameter Value and Encoded
+ Word Extensions: Character Sets, Languages, and
+ Continuations", RFC 2184, August 1997.
+
+ [RFC2234] Crocker, D. and P. Overall, "Augmented BNF for Syntax
+ Specifications: ABNF", RFC 2234, November 1997.
+
+ [RFC2246] Dierks, T. and C. Allen, "The TLS Protocol", RFC 2246.
+ January 1999.
+
+ [RFC2396] Berners-Lee, T., Fielding, R. and L. Masinter, "Uniform
+ Resource Identifiers (URI): Generic Syntax", RFC 2396,
+ August 1998.
+
+ [RFC2565] Herriot, R., Butler, S., Moore, P. and R. Turner,
+ "Internet Printing Protocol/1.0: Encoding and Transport",
+ RFC 2565, April 1999.
+
+ [RFC2566] deBry, R., Hastings, T., Herriot, R., Isaacson, S. and P.
+ Powell, "Internet Printing Protocol/1.0: Model and
+ Semantics", RFC 2566, April 1999.
+
+ [RFC2567] Wright, D., "Design Goals for an Internet Printing
+ Protocol", RFC2567, April 1999.
+
+ [RFC2568] Zilles, S., "Rationale for the Structure and Model and
+ Protocol for the Internet Printing Protocol", RFC 2568,
+ April 1999.
+
+ [RFC2569] Herriot, R., Hastings, T., Jacobs, N. and J. Martin,
+ "Mapping between LPD and IPP Protocols", RFC 2569, April
+ 1999.
+
+ [RFC2616] Fielding, R., Gettys, J., Mogul, J., Frystyk, H.,
+ Masinter, L., Leach, P. and T. Berners-Lee, "Hypertext
+ Transfer Protocol - HTTP/1.1", RFC 2616, June 1999.
+
+ [RFC2617] Franks, J., Hallam-Baker, P., Hostetler, J., Lawrence, S.,
+ Leach, P., Luotonen, A. and L. Stewart, "HTTP
+ Authentication: Basic and Digest Access Authentication",
+ RFC 2617, June 1999.
+
+
+
+Herriot, et al. Standards Track [Page 28]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ [RFC2817] Khare, R. and S. Lawrence, "Upgrading to TLS Within
+ HTTP/1.1", RFC 2817, May 2000.
+
+ [RFC2910] Herriot, R., Butler, S., Moore, P., Turner, R. and J.
+ Wenn, "Internet Printing Protocol/1.1: Encoding and
+ Transport", RFC 2910, September 2000.
+
+ [RFC2911] Hastings, T., Herriot, R., deBry, R., Isaacson, S. and P.
+ Powell, "Internet Printing Protocol/1.1: Model and
+ Semantics", RFC 2911, September 2000.
+
+ [SSL] Netscape, The SSL Protocol, Version 3, (Text version
+ 3.02), November 1996.
+
+11. Authors' Addresses
+
+ Robert Herriot, Editor
+ Xerox Corporation
+ 3400 Hillview Ave., Bldg #1
+ Palo Alto, CA 94304
+
+ Phone: 650-813-7696
+ Fax: 650-813-6860
+ EMail: robert.herriot@pahv.xerox.com
+
+
+ Sylvan Butler
+ Hewlett-Packard
+ 11311 Chinden Blvd.
+ Boise, ID 83714
+
+ Phone: 208-396-6000
+ Fax: 208-396-3457
+ EMail: sbutler@boi.hp.com
+
+
+ Paul Moore
+ Peerless Systems Networking
+ 10900 NE 8th St #900
+ Bellevue, WA 98004
+
+ Phone: 425-462-5852
+ EMail: pmoore@peerless.com
+
+
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 29]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ Randy Turner
+ 2Wire, Inc.
+ 694 Tasman Dr.
+ Milpitas, CA 95035
+
+ Phone: 408-546-1273
+
+
+ John Wenn
+ Xerox Corporation
+ 737 Hawaii St
+ El Segundo, CA 90245
+
+ Phone: 310-333-5764
+ Fax: 310-333-5514
+ EMail: jwenn@cp10.es.xerox.com
+
+
+ IPP Web Page: http://www.pwg.org/ipp/
+ IPP Mailing List: ipp@pwg.org
+
+ To subscribe to the ipp mailing list, send the following email:
+ 1) send it to majordomo@pwg.org
+ 2) leave the subject line blank
+ 3) put the following two lines in the message body:
+ subscribe ipp
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 30]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+12. Other Participants:
+
+ Chuck Adams - Tektronix Shivaun Albright - HP
+ Stefan Andersson - Axis Jeff Barnett - IBM
+ Ron Bergman - Hitachi Koki Imaging Dennis Carney - IBM
+ Systems
+ Keith Carter - IBM Angelo Caruso - Xerox
+ Rajesh Chawla - TR Computing Nancy Chen - Okidata
+ Solutions
+ Josh Cohen - Microsoft Jeff Copeland - QMS
+ Andy Davidson - Tektronix Roger deBry - IBM
+ Maulik Desai - Auco Mabry Dozier - QMS
+ Lee Farrell - Canon Information Satoshi Fujitami - Ricoh
+ Systems
+ Steve Gebert - IBM Sue Gleeson - Digital
+ Charles Gordon - Osicom Brian Grimshaw - Apple
+ Jerry Hadsell - IBM Richard Hart - Digital
+ Tom Hastings - Xerox Henrik Holst - I-data
+ Stephen Holmstead Zhi-Hong Huang - Zenographics
+ Scott Isaacson - Novell Babek Jahromi - Microsoft
+ Swen Johnson - Xerox David Kellerman - Northlake
+ Software
+ Robert Kline - TrueSpectra Charles Kong - Panasonic
+ Carl Kugler - IBM Dave Kuntz - Hewlett-Packard
+ Takami Kurono - Brother Rick Landau - Digital
+ Scott Lawrence - Agranot Systems Greg LeClair - Epson
+ Dwight Lewis - Lexmark Harry Lewis - IBM
+ Tony Liao - Vivid Image Roy Lomicka - Digital
+ Pete Loya - HP Ray Lutz - Cognisys
+ Mike MacKay - Novell, Inc. David Manchala - Xerox
+ Carl-Uno Manros - Xerox Jay Martin - Underscore
+ Stan McConnell - Xerox Larry Masinter - Xerox
+ Sandra Matts - Hewlett Packard Peter Michalek - Shinesoft
+ Ira McDonald - High North Inc. Mike Moldovan - G3 Nova
+ Tetsuya Morita - Ricoh Yuichi Niwa - Ricoh
+ Pat Nogay - IBM Ron Norton - Printronics
+ Hugo Parra, Novell Bob Pentecost - Hewlett-Packard
+ Patrick Powell - Astart Jeff Rackowitz - Intermec
+ Technologies
+ Eric Random - Peerless Rob Rhoads - Intel
+ Xavier Riley - Xerox Gary Roberts - Ricoh
+ David Roach - Unisys Stuart Rowley - Kyocera
+ Yuji Sasaki - Japan Computer Richard Schneider - Epson
+ Industry
+ Kris Schoff - HP Katsuaki Sekiguchi - Canon
+ Information Systems
+
+
+
+
+
+Herriot, et al. Standards Track [Page 31]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ Bob Setterbo - Adobe Gail Songer - Peerless
+ Hideki Tanaka - Cannon Information Devon Taylor - Novell, Inc.
+ Systems
+ Mike Timperman - Lexmark Atsushi Uchino - Epson
+ Shigeru Ueda - Canon Bob Von Andel - Allegro Software
+ William Wagner - NetSilicon/DPI Jim Walker - DAZEL
+ Chris Wellens - Interworking Labs Trevor Wells - Hewlett Packard
+ Craig Whittle - Sharp Labs Rob Whittle - Novell, Inc.
+ Jasper Wong - Xionics Don Wright - Lexmark
+ Michael Wu - Heidelberg Digital Rick Yardumian - Xerox
+ Michael Yeung - Canon Information Lloyd Young - Lexmark
+ Systems
+ Atsushi Yuki - Kyocera Peter Zehler - Xerox
+ William Zhang - Canon Information Frank Zhao - Panasonic
+ Systems
+ Steve Zilles - Adobe Rob Zirnstein - Canon Information
+ Systems
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 32]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+13. Appendix A: Protocol Examples
+
+13.1 Print-Job Request
+
+ The following is an example of a Print-Job request with job-name,
+ copies, and sides specified. The "ipp-attribute-fidelity" attribute
+ is set to 'true' so that the print request will fail if the "copies"
+ or the "sides" attribute are not supported or their values are not
+ supported.
+
+ Octets Symbolic Value Protocol field
+
+ 0x0101 1.1 version-number
+ 0x0002 Print-Job operation-id
+ 0x00000001 1 request-id
+ 0x01 start operation-attributes operation-attributes-tag
+ 0x47 charset type value-tag
+ 0x0012 name-length
+ attributes- attributes-charset name
+ charset
+ 0x0008 value-length
+ us-ascii US-ASCII value
+ 0x48 natural-language type value-tag
+ 0x001B name-length
+ attributes- name
+ natural- attributes-natural-language
+ language
+ 0x0005 value-length
+ en-us en-US value
+ 0x45 uri type value-tag
+ 0x000B name-length
+ printer-uri printer-uri name
+ 0x0015 value-length
+ ipp://forest/ printer pinetree value
+ pinetree
+ 0x42 nameWithoutLanguage type value-tag
+ 0x0008 name-length
+ job-name job-name name
+ 0x0006 value-length
+ foobar foobar value
+ 0x22 boolean type value-tag
+ 0x0016 name-length
+ ipp-attribute- ipp-attribute-fidelity name
+ fidelity
+ 0x0001 value-length
+ 0x01 true value
+
+
+
+
+
+Herriot, et al. Standards Track [Page 33]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ Octets Symbolic Value Protocol field
+
+ 0x02 start job-attributes job-attributes-tag
+ 0x21 integer type value-tag
+ 0x0006 name-length
+ copies copies name
+ 0x0004 value-length
+ 0x00000014 20 value
+ 0x44 keyword type value-tag
+ 0x0005 name-length
+ sides sides name
+ 0x0013 value-length
+ two-sided- two-sided-long-edge value
+ long-edge
+ 0x03 end-of-attributes end-of-attributes-tag
+ %!PS... <PostScript> data
+
+13.2 Print-Job Response (successful)
+
+ Here is an example of a successful Print-Job response to the previous
+ Print-Job request. The printer supported the "copies" and "sides"
+ attributes and their supplied values. The status code returned is
+ 'successful-ok'.
+
+ Octets Symbolic Value Protocol field
+
+ 0x0101 1.1 version-number
+ 0x0000 successful-ok status-code
+ 0x00000001 1 request-id
+ 0x01 start operation-attributes operation-attributes-tag
+ 0x47 charset type value-tag
+ 0x0012 name-length
+ attributes- attributes-charset name
+ charset
+ 0x0008 value-length
+ us-ascii US-ASCII value
+ 0x48 natural-language type value-tag
+ 0x001B name-length
+ attributes- attributes-natural- name
+ natural-language language
+ 0x0005 value-length
+ en-us en-US value
+ 0x41 textWithoutLanguage type value-tag
+ 0x000E name-length
+ status-message status-message name
+ 0x000D value-length
+
+
+
+
+
+Herriot, et al. Standards Track [Page 34]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ Octets Symbolic Value Protocol field
+
+ successful-ok successful-ok value
+ 0x02 start job-attributes job-attributes-tag
+ 0x21 integer value-tag
+ 0x0006 name-length
+ job-id job-id name
+ 0x0004 value-length
+ 147 147 value
+ 0x45 uri type value-tag
+ 0x0007 name-length
+ job-uri job-uri name
+ 0x0019 value-length
+ ipp://forest/ job 123 on pinetree value
+ pinetree/123
+ 0x23 enum type value-tag
+ 0x0009 name-length
+ job-state job-state name
+ 0x0004 value-length
+ 0x0003 pending value
+ 0x03 end-of-attributes end-of-attributes-tag
+
+13.3 Print-Job Response (failure)
+
+ Here is an example of an unsuccessful Print-Job response to the
+ previous Print-Job request. It fails because, in this case, the
+ printer does not support the "sides" attribute and because the value
+ '20' for the "copies" attribute is not supported. Therefore, no job
+ is created, and neither a "job-id" nor a "job-uri" operation
+ attribute is returned. The error code returned is 'client-error-
+ attributes-or-values-not-supported' (0x040B).
+
+ 0x0101 1.1 version-number
+ 0x040B client-error-attributes-or- status-code
+ values-not-supported
+ 0x00000001 1 request-id
+ 0x01 start operation-attributes operation-attributes tag
+ 0x47 charset type value-tag
+ 0x0012 name-length
+ attributes- attributes-charset name
+ charset
+ 0x0008 value-length
+ us-ascii US-ASCII value
+
+
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 35]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ Octets Symbolic Value Protocol field
+
+ 0x48 natural-language type value-tag
+ 0x001B name-length
+ attributes- attributes-natural-language name
+ natural-
+ language
+ 0x0005 value-length
+ en-us en-US value
+ 0x41 textWithoutLanguage type value-tag
+ 0x000E name-length
+ status- status-message name
+ message
+ 0x002F value-length
+ client-error- value
+ attributes- values-not-supported
+ or-values- client-error-attributes-or-
+ not-supported
+ 0x05 start unsupported-attributes unsupported-attributes tag
+ 0x21 integer type value-tag
+ 0x0006 name-length
+ copies copies name
+ 0x0004 value-length
+ 0x00000014 20 value
+ 0x10 unsupported (type) value-tag
+ 0x0005 name-length
+ sides sides name
+ 0x0000 value-length
+ 0x03 end-of-attributes end-of-attributes-tag
+
+13.4 Print-Job Response (success with attributes ignored)
+
+ Here is an example of a successful Print-Job response to a Print-Job
+ request like the previous Print-Job request, except that the value of
+ 'ipp-attribute-fidelity' is false. The print request succeeds, even
+ though, in this case, the printer supports neither the "sides"
+ attribute nor the value '20' for the "copies" attribute. Therefore, a
+ job is created, and both a "job-id" and a "job-uri" operation
+ attribute are returned. The unsupported attributes are also returned
+ in an Unsupported Attributes Group. The error code returned is
+ 'successful-ok-ignored-or-substituted-attributes' (0x0001).
+
+ Octets Symbolic Value Protocol field
+
+ 0x0101 1.1 version-number
+ 0x0001 successful-ok-ignored-or- status-code
+
+
+
+
+
+Herriot, et al. Standards Track [Page 36]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ Octets Symbolic Value Protocol field
+
+ substituted-attributes
+ 0x00000001 1 request-id
+ 0x01 start operation-attributes operation-attributes-tag
+ 0x47 charset type value-tag
+ 0x0012 name-length
+ attributes- attributes-charset name
+ charset
+ 0x0008 value-length
+ us-ascii US-ASCII value
+ 0x48 natural-language type value-tag
+ 0x001B name-length
+ attributes- attributes-natural- name
+ natural-language language
+ 0x0005 value-length
+ en-us en-US value
+ 0x41 textWithoutLanguage type value-tag
+ 0x000E name-length
+ status-message status-message name
+ 0x002F value-length
+ successful-ok- successful-ok-ignored-or- value
+ ignored-or- substituted-attributes
+ substituted-
+ attributes
+ 0x05 start unsupported- unsupported-attributes
+ attributes tag
+ 0x21 integer type value-tag
+ 0x0006 name-length
+ copies copies name
+ 0x0004 value-length
+ 0x00000014 20 value
+ 0x10 unsupported (type) value-tag
+ 0x0005 name-length
+ sides sides name
+ 0x0000 value-length
+ 0x02 start job-attributes job-attributes-tag
+ 0x21 integer value-tag
+ 0x0006 name-length
+ job-id job-id name
+ 0x0004 value-length
+ 147 147 value
+ 0x45 uri type value-tag
+ 0x0007 name-length
+ job-uri job-uri name
+ 0x0019 value-length
+ ipp://forest/ job 123 on pinetree value
+ pinetree/123
+
+
+
+Herriot, et al. Standards Track [Page 37]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ Octets Symbolic Value Protocol field
+
+ 0x23 enum type value-tag
+ 0x0009 name-length
+ job-state job-state name
+ 0x0004 value-length
+ 0x0003 pending value
+ 0x03 end-of-attributes end-of-attributes-tag
+
+13.5 Print-URI Request
+
+ The following is an example of Print-URI request with copies and
+ job-name parameters:
+
+ Octets Symbolic Value Protocol field
+
+ 0x0101 1.1 version-number
+ 0x0003 Print-URI operation-id
+ 0x00000001 1 request-id
+ 0x01 start operation-attributes operation-attributes-tag
+ 0x47 charset type value-tag
+ 0x0012 name-length
+ attributes- attributes-charset name
+ charset
+ 0x0008 value-length
+ us-ascii US-ASCII value
+ 0x48 natural-language type value-tag
+ 0x001B name-length
+ attributes- attributes-natural-language name
+ natural-
+ language
+ 0x0005 value-length
+ en-us en-US value
+ 0x45 uri type value-tag
+ 0x000B name-length
+ printer-uri printer-uri name
+ 0x0015 value-length
+ ipp://forest/ printer pinetree value
+ pinetree
+ 0x45 uri type value-tag
+ 0x000C name-length
+ document-uri document-uri name
+ 0x0011 value-length
+ ftp://foo.com ftp://foo.com/foo value
+
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 38]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ Octets Symbolic Value Protocol field
+
+ /foo
+ 0x42 nameWithoutLanguage type value-tag
+ 0x0008 name-length
+ job-name job-name name
+ 0x0006 value-length
+ foobar foobar value
+ 0x02 start job-attributes job-attributes-tag
+ 0x21 integer type value-tag
+ 0x0006 name-length
+ copies copies name
+ 0x0004 value-length
+ 0x00000001 1 value
+ 0x03 end-of-attributes end-of-attributes-tag
+
+13.6 Create-Job Request
+
+ The following is an example of Create-Job request with no parameters
+ and no attributes:
+
+ Octets Symbolic Value Protocol field
+
+ 0x0101 1.1 version-number
+ 0x0005 Create-Job operation-id
+ 0x00000001 1 request-id
+ 0x01 start operation-attributes operation-attributes-tag
+ 0x47 charset type value-tag
+ 0x0012 name-length
+ attributes- attributes-charset name
+ charset
+ 0x0008 value-length
+ us-ascii US-ASCII value
+ 0x48 natural-language type value-tag
+ 0x001B name-length
+ attributes- attributes-natural-language name
+ natural-
+ language
+ 0x0005 value-length
+ en-us en-US value
+ 0x45 uri type value-tag
+ 0x000B name-length
+ printer-uri printer-uri name
+ 0x0015 value-length
+ ipp://forest/ printer pinetree value
+ pinetree
+
+
+
+
+
+Herriot, et al. Standards Track [Page 39]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ Octets Symbolic Value Protocol field
+
+ inetree
+ 0x03 end-of-attributes end-of-attributes-tag
+
+13.7 Get-Jobs Request
+
+ The following is an example of Get-Jobs request with parameters but
+ no attributes:
+
+ Octets Symbolic Value Protocol field
+
+ 0x0101 1.1 version-number
+ 0x000A Get-Jobs operation-id
+ 0x00000123 0x123 request-id
+ 0x01 start operation-attributes operation-attributes-tag
+ 0x47 charset type value-tag
+ 0x0012 name-length
+ attributes- attributes-charset name
+ charset
+ 0x0008 value-length
+ us-ascii US-ASCII value
+ 0x48 natural-language type value-tag
+ 0x001B name-length
+ attributes- attributes-natural-language name
+ natural-
+ language
+ 0x0005 value-length
+ en-us en-US value
+ 0x45 uri type value-tag
+ 0x000B name-length
+ printer-uri printer-uri name
+ 0x0015 value-length
+ ipp://forest/ printer pinetree value
+ pinetree
+ 0x21 integer type value-tag
+ 0x0005 name-length
+ limit limit name
+ 0x0004 value-length
+ 0x00000032 50 value
+ 0x44 keyword type value-tag
+ 0x0014 name-length
+ requested- requested-attributes name
+ attributes
+ 0x0006 value-length
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 40]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ Octets Symbolic Value Protocol field
+
+ job-id job-id value
+ 0x44 keyword type value-tag
+ 0x0000 additional value name-length
+ 0x0008 value-length
+ job-name job-name value
+ 0x44 keyword type value-tag
+ 0x0000 additional value name-length
+ 0x000F value-length
+ document-format document-format value
+ 0x03 end-of-attributes end-of-attributes-tag
+
+13.8 Get-Jobs Response
+
+ The following is an of Get-Jobs response from previous request with 3
+ jobs. The Printer returns no information about the second job
+ (because of security reasons):
+
+ Octets Symbolic Value Protocol field
+
+ 0x0101 1.1 version-number
+ 0x0000 successful-ok status-code
+ 0x00000123 0x123 request-id (echoed
+ back)
+ 0x01 start operation-attributes operation-attributes-tag
+ 0x47 charset type value-tag
+ 0x0012 name-length
+ attributes- attributes-charset name
+ charset
+ 0x000A value-length
+ ISO-8859-1 ISO-8859-1 value
+ 0x48 natural-language type value-tag
+ 0x001B name-length
+ attributes- attributes-natural-language name
+ natural-
+ language
+ 0x0005 value-length
+ en-us en-US value
+ 0x41 textWithoutLanguage type value-tag
+ 0x000E name-length
+ status-message status-message name
+ 0x000D value-length
+ successful-ok successful-ok value
+ 0x02 start job-attributes (1st job-attributes-tag
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 41]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ Octets Symbolic Value Protocol field
+
+ object)
+ 0x21 integer type value-tag
+ 0x0006 name-length
+ job-id job-id name
+ 0x0004 value-length
+ 147 147 value
+ 0x36 nameWithLanguage value-tag
+ 0x0008 name-length
+ job-name job-name name
+ 0x000C value-length
+ 0x0005 sub-value-length
+ fr-ca fr-CA value
+ 0x0003 sub-value-length
+ fou fou name
+ 0x02 start job-attributes (2nd job-attributes-tag
+ object)
+ 0x02 start job-attributes (3rd job-attributes-tag
+ object)
+ 0x21 integer type value-tag
+ 0x0006 name-length
+ job-id job-id name
+ 0x0004 value-length
+ 148 149 value
+ 0x36 nameWithLanguage value-tag
+ 0x0008 name-length
+ job-name job-name name
+ 0x0012 value-length
+ 0x0005 sub-value-length
+ de-CH de-CH value
+ 0x0009 sub-value-length
+ isch guet isch guet name
+ 0x03 end-of-attributes end-of-attributes-tag
+
+14. Appendix B: Registration of MIME Media Type Information for
+ "application/ipp"
+
+ This appendix contains the information that IANA requires for
+ registering a MIME media type. The information following this
+ paragraph will be forwarded to IANA to register application/ipp whose
+ contents are defined in Section 3 "Encoding of the Operation Layer"
+ in this document:
+
+ MIME type name: application
+
+ MIME subtype name: ipp
+
+
+
+
+Herriot, et al. Standards Track [Page 42]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ A Content-Type of "application/ipp" indicates an Internet Printing
+ Protocol message body (request or response). Currently there is one
+ version: IPP/1.1, whose syntax is described in Section 3 "Encoding of
+ the Operation Layer" of [RFC2910], and whose semantics are described
+ in [RFC2911].
+
+ Required parameters: none
+
+ Optional parameters: none
+
+ Encoding considerations:
+
+ IPP/1.1 protocol requests/responses MAY contain long lines and ALWAYS
+ contain binary data (for example attribute value lengths).
+
+ Security considerations:
+
+ IPP/1.1 protocol requests/responses do not introduce any security
+ risks not already inherent in the underlying transport protocols.
+ Protocol mixed-version interworking rules in [RFC2911] as well as
+ protocol encoding rules in [RFC2910] are complete and unambiguous.
+
+ Interoperability considerations:
+
+ IPP/1.1 requests (generated by clients) and responses (generated by
+ servers) MUST comply with all conformance requirements imposed by the
+ normative specifications [RFC2911] and [RFC2910]. Protocol encoding
+ rules specified in [RFC2910] are comprehensive, so that
+ interoperability between conforming implementations is guaranteed
+ (although support for specific optional features is not ensured).
+ Both the "charset" and "natural-language" of all IPP/1.1 attribute
+ values which are a LOCALIZED-STRING are explicit within IPP protocol
+ requests/responses (without recourse to any external information in
+ HTTP, SMTP, or other message transport headers).
+
+ Published specifications:
+
+ [RFC2911] Hastings, T., Herriot, R., deBry, R., Isaacson, S. and P.
+ Powell, "Internet Printing Protocol/1.1: Model and
+ Semantics", RFC 2911, September 2000.
+
+ [RFC2910] Herriot, R., Butler, S., Moore, P., Turner, R. and J.
+ Wenn, "Internet Printing Protocol/1.1: Encoding and
+ Transport", RFC 2910, September 2000.
+
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 43]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ Applications which use this media type:
+
+ Internet Printing Protocol (IPP) print clients and print servers,
+ communicating using HTTP/1.1 (see [RFC2910]), SMTP/ESMTP, FTP, or
+ other transport protocol. Messages of type "application/ipp" are
+ self-contained and transport-independent, including "charset" and
+ "natural-language" context for any LOCALIZED-STRING value.
+
+ Person & email address to contact for further information:
+
+ Tom Hastings
+ Xerox Corporation
+ 737 Hawaii St. ESAE-231
+ El Segundo, CA
+
+ Phone: 310-333-6413
+ Fax: 310-333-5514
+ EMail: hastings@cp10.es.xerox.com
+
+ or
+
+ Robert Herriot
+ Xerox Corporation
+ 3400 Hillview Ave., Bldg #1
+ Palo Alto, CA 94304
+
+ Phone: 650-813-7696
+ Fax: 650-813-6860
+ EMail: robert.herriot@pahv.xerox.com
+
+ Intended usage:
+
+ COMMON
+
+15. Appendix C: Changes from IPP/1.0
+
+ IPP/1.1 is identical to IPP/1.0 [RFC2565] with the follow changes:
+
+ 1. Attributes values that identify a printer or job object use a new
+ 'ipp' scheme. The 'http' and 'https' schemes are supported only
+ for backward compatibility. See section 5.
+
+ 2. Clients MUST support of Digest Authentication, IPP Printers SHOULD
+ support Digest Authentication. See Section 8.1.1
+
+ 3. TLS is recommended for channel security. In addition, SSL3 may be
+ supported for backward compatibility. See Section 8.1.2
+
+
+
+
+Herriot, et al. Standards Track [Page 44]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ 4. It is recommended that IPP/1.1 objects accept any request with
+ major version number '1'. See section 9.1.
+
+ 5. IPP objects SHOULD return the URL scheme requested for "job-
+ printer-uri" and "job-uri" Job Attributes, rather than the URL
+ scheme used to create the job. See section 9.2.
+
+ 6. The IANA and Internationalization sections have been added. The
+ terms "private use" and "experimental" have been changed to
+ "vendor extension". The reserved allocations for attribute group
+ tags, attribute syntax tags, and out-of-band attribute values have
+ been clarified as to which are reserved to future IETF standards
+ track documents and which are reserved to vendor extension. Both
+ kinds of extensions use the type2 registration procedures as
+ defined in [RFC2911].
+
+ 7. Clarified that future "out-of-band" value definitions may use the
+ value field if additional information is needed.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 45]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (2000). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 46]
+
diff --git a/standards/rfc2911.txt b/standards/rfc2911.txt
new file mode 100644
index 000000000..29c85a426
--- /dev/null
+++ b/standards/rfc2911.txt
@@ -0,0 +1,12547 @@
+
+
+
+
+
+
+Network Working Group T. Hastings, Editor
+Request for Comments: 2911 R. Herriot
+Obsoletes: 2566 Xerox Corporation
+Category: Standards Track R. deBry
+ Utah Valley State College
+ S. Isaacson
+ Novell, Inc.
+ P. Powell
+ Astart Technologies
+ September 2000
+
+
+ Internet Printing Protocol/1.1: Model and Semantics
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2000). All Rights Reserved.
+
+Abstract
+
+ This document is one of a set of documents, which together describe
+ all aspects of a new Internet Printing Protocol (IPP). IPP is an
+ application level protocol that can be used for distributed printing
+ using Internet tools and technologies. This document describes a
+ simplified model consisting of abstract objects, their attributes,
+ and their operations that is independent of encoding and transport.
+ The model consists of a Printer and a Job object. A Job optionally
+ supports multiple documents. IPP 1.1 semantics allow end-users and
+ operators to query printer capabilities, submit print jobs, inquire
+ about the status of print jobs and printers, cancel, hold, release,
+ and restart print jobs. IPP 1.1 semantics allow operators to pause,
+ resume, and purge (jobs from) Printer objects. This document also
+ addresses security, internationalization, and directory issues.
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 1]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ The full set of IPP documents includes:
+
+ Design Goals for an Internet Printing Protocol [RFC2567]
+ Rationale for the Structure and Model and Protocol for the Internet
+ Printing Protocol [RFC2568]
+ Internet Printing Protocol/1.1: Model and Semantics (this document)
+ Internet Printing Protocol/1.1: Encoding and Transport [RFC2910]
+ Internet Printing Protocol/1.1: Implementer's Guide [IPP-IIG]
+ Mapping between LPD and IPP Protocols [RFC2569]
+
+ The "Design Goals for an Internet Printing Protocol" document takes a
+ broad look at distributed printing functionality, and it enumerates
+ real-life scenarios that help to clarify the features that need to be
+ included in a printing protocol for the Internet. It identifies
+ requirements for three types of users: end users, operators, and
+ administrators. It calls out a subset of end user requirements that
+ are satisfied in IPP/1.0. A few OPTIONAL operator operations have
+ been added to IPP/1.1.
+
+ The "Rationale for the Structure and Model and Protocol for the
+ Internet Printing Protocol" document describes IPP from a high level
+ view, defines a roadmap for the various documents that form the suite
+ of IPP specification documents, and gives background and rationale
+ for the IETF working group's major decisions.
+
+ The "Internet Printing Protocol/1.1: Encoding and Transport" document
+ is a formal mapping of the abstract operations and attributes defined
+ in the model document onto HTTP/1.1 [RFC2616]. It defines the
+ encoding rules for a new Internet MIME media type called
+ "application/ipp". This document also defines the rules for
+ transporting over HTTP a message body whose Content-Type is
+ "application/ipp". This document defines a new scheme named 'ipp'
+ for identifying IPP printers and jobs.
+
+ The "Internet Printing Protocol/1.1: Implementer's Guide" document
+ gives insight and advice to implementers of IPP clients and IPP
+ objects. It is intended to help them understand IPP/1.1 and some of
+ the considerations that may assist them in the design of their client
+ and/or IPP object implementations. For example, a typical order of
+ processing requests is given, including error checking. Motivation
+ for some of the specification decisions is also included.
+
+ The "Mapping between LPD and IPP Protocols" document gives some
+ advice to implementers of gateways between IPP and LPD (Line Printer
+ Daemon) implementations.
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 2]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+Table of Contents
+
+ 1. Introduction 9
+ 1.1 Simplified Printing Model 10
+ 2. IPP Objects 12
+ 2.1 Printer Object 13
+ 2.2 Job Object 15
+ 2.3 Object Relationships 16
+ 2.4 Object Identity 17
+ 3. IPP Operations 20
+ 3.1 Common Semantics 21
+ 3.1.1 Required Parameters 21
+ 3.1.2 Operation IDs and Request IDs 22
+ 3.1.3 Attributes 22
+ 3.1.4 Character Set and Natural Language Operation Attribute 24
+ 3.1.4.1 Request Operation Attributes 25
+ 3.1.4.2 Response Operation Attributes 29
+ 3.1.5 Operation Targets 30
+ 3.1.6 Operation Response Status Codes and Status Messages 32
+ 3.1.6.1 "status-code" (type2 enum) 32
+ 3.1.6.2 "status-message" (text(255)) 33
+ 3.1.6.3 "detailed-status-message" (text(MAX)) 33
+ 3.1.6.4 "document-access-error" (text(MAX)) 34
+ 3.1.7 Unsupported Attributes 34
+ 3.1.8 Versions 36
+ 3.1.9 Job Creation Operations 38
+ 3.2 Printer Operations 41
+ 3.2.1 Print-Job Operation 41
+ 3.2.1.1 Print-Job Request 41
+ 3.2.1.2 Print-Job Response 46
+ 3.2.2 Print-URI Operation 48
+ 3.2.3 Validate-Job Operation 49
+ 3.2.4 Create-Job Operation 49
+ 3.2.5 Get-Printer-Attributes Operation 50
+ 3.2.5.1 Get-Printer-Attributes Request 51
+ 3.2.5.2 Get-Printer-Attributes Response 53
+ 3.2.6 Get-Jobs Operation 54
+ 3.2.6.1 Get-Jobs Request 54
+ 3.2.6.2 Get-Jobs Response 56
+ 3.2.7 Pause-Printer Operation 57
+ 3.2.7.1 Pause-Printer Request 59
+ 3.2.7.2 Pause-Printer Response 60
+ 3.2.8 Resume-Printer Operation 60
+ 3.2.9 Purge-Jobs Operation 61
+ 3.3 Job Operations 62
+ 3.3.1 Send-Document Operation 62
+ 3.3.1.1 Send-Document Request 64
+ 3.3.1.2 Send-Document Response 65
+
+
+
+Hastings, et al. Standards Track [Page 3]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 3.3.2 Send-URI Operation 66
+ 3.3.3 Cancel-Job Operation 66
+ 3.3.3.1 Cancel-Job Request 67
+ 3.3.3.2 Cancel-Job Response 68
+ 3.3.4 Get-Job-Attributes Operation 69
+ 3.3.4.1 Get-Job-Attributes Request 69
+ 3.3.4.2 Get-Job-Attributes Response 70
+ 3.3.5 Hold-Job Operation 71
+ 3.3.5.1 Hold-Job Request 72
+ 3.3.5.2 Hold-Job Response 73
+ 3.3.6 Release-Job Operation 74
+ 3.3.7 Restart-Job Operation 75
+ 3.3.7.1 Restart-Job Request 76
+ 3.3.7.2 Restart-Job Response 78
+ 4. Object Attributes 78
+ 4.1 Attribute Syntaxes 78
+ 4.1.1 'text' 79
+ 4.1.1.1 'textWithoutLanguage' 80
+ 4.1.1.2 'textWithLanguage' 80
+ 4.1.2 'name' 81
+ 4.1.2.1 'nameWithoutLanguage' 82
+ 4.1.2.2 'nameWithLanguage' 82
+ 4.1.2.3 Matching 'name' attribute values 83
+ 4.1.3 'keyword' 84
+ 4.1.4 'enum' 85
+ 4.1.5 'uri' 85
+ 4.1.6 'uriScheme' 86
+ 4.1.7 'charset' 86
+ 4.1.8 'naturalLanguage' 87
+ 4.1.9 'mimeMediaType' 87
+ 4.1.9.1 Application/octet-stream -- Auto-Sensing 88
+ the document format
+ 4.1.10 'octetString' 89
+ 4.1.11 'boolean' 89
+ 4.1.12 'integer' 89
+ 4.1.13 'rangeOfInteger' 90
+ 4.1.14 'dateTime' 90
+ 4.1.15 'resolution' 90
+ 4.1.16 '1setOf X' 90
+ 4.2 Job Template Attributes 91
+ 4.2.1 job-priority (integer(1:100)) 94
+ 4.2.2 job-hold-until (type3 keyword | name (MAX)) 95
+ 4.2.3 job-sheets (type3 keyword | name(MAX)) 96
+ 4.2.4 multiple-document-handling (type2 keyword) 96
+ 4.2.5 copies (integer(1:MAX)) 98
+ 4.2.6 finishings (1setOf type2 enum) 98
+ 4.2.7 page-ranges (1setOf rangeOfInteger (1:MAX)) 101
+ 4.2.8 sides (type2 keyword) 102
+
+
+
+Hastings, et al. Standards Track [Page 4]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 4.2.9 number-up (integer(1:MAX)) 102
+ 4.2.10 orientation-requested (type2 enum) 103
+ 4.2.11 media (type3 keyword | name(MAX)) 104
+ 4.2.12 printer-resolution (resolution) 105
+ 4.2.13 print-quality (type2 enum) 105
+ 4.3 Job Description Attributes 106
+ 4.3.1 job-uri (uri) 107
+ 4.3.2 job-id (integer(1:MAX)) 108
+ 4.3.3 job-printer-uri (uri) 108
+ 4.3.4 job-more-info (uri) 108
+ 4.3.5 job-name (name(MAX)) 108
+ 4.3.6 job-originating-user-name (name(MAX)) 109
+ 4.3.7 job-state (type1 enum) 109
+ 4.3.7.1 Forwarding Servers 112
+ 4.3.7.2 Partitioning of Job States 112
+ 4.3.8 job-state-reasons (1setOf type2 keyword) 113
+ 4.3.9 job-state-message (text(MAX)) 118
+ 4.3.10 job-detailed-status-messages (1setOf text(MAX)) 118
+ 4.3.11 job-document-access-errors (1setOf text(MAX)) 118
+ 4.3.12 number-of-documents (integer(0:MAX)) 119
+ 4.3.13 output-device-assigned (name(127)) 119
+ 4.3.14 Event Time Job Description Attributes 119
+ 4.3.14.1 time-at-creation (integer(MIN:MAX)) 120
+ 4.3.14.2 time-at-processing (integer(MIN:MAX)) 120
+ 4.3.14.3 time-at-completed (integer(MIN:MAX)) 120
+ 4.3.14.4 job-printer-up-time (integer(1:MAX)) 120
+ 4.3.14.5 date-time-at-creation (dateTime) 121
+ 4.3.14.6 date-time-at-processing (dateTime) 121
+ 4.3.14.7 date-time-at-completed (dateTime) 121
+ 4.3.15 number-of-intervening-jobs (integer(0:MAX)) 121
+ 4.3.16 job-message-from-operator (text(127)) 121
+ 4.3.17 Job Size Attributes 121
+ 4.3.17.1 job-k-octets (integer(0:MAX)) 122
+ 4.3.17.2 job-impressions (integer(0:MAX)) 122
+ 4.3.17.3 job-media-sheets (integer(0:MAX)) 123
+ 4.3.18 Job Progress Attributes 123
+ 4.3.18.1 job-k-octets-processed (integer(0:MAX)) 123
+ 4.3.18.2 job-impressions-completed (integer(0:MAX)) 123
+ 4.3.18.3 job-media-sheets-completed (integer(0:MAX)) 124
+ 4.3.19 attributes-charset (charset) 124
+ 4.3.20 attributes-natural-language (naturalLanguage) 124
+ 4.4 Printer Description Attributes 124
+ 4.4.1 printer-uri-supported (1setOf uri) 126
+ 4.4.2 uri-authentication-supported (1setOf type2 keyword) 127
+ 4.4.3 uri-security-supported (1setOf type2 keyword) 128
+ 4.4.4 printer-name (name(127)) 129
+ 4.4.5 printer-location (text(127)) 129
+ 4.4.6 printer-info (text(127)) 130
+
+
+
+Hastings, et al. Standards Track [Page 5]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 4.4.7 printer-more-info (uri) 130
+ 4.4.8 printer-driver-installer (uri) 130
+ 4.4.9 printer-make-and-model (text(127)) 130
+ 4.4.10 printer-more-info-manufacturer (uri) 130
+ 4.4.11 printer-state (type1 enum) 131
+ 4.4.12 printer-state-reasons (1setOf type2 keyword) 131
+ 4.4.13 printer-state-message (text(MAX)) 134
+ 4.4.14 ipp-versions-supported (1setOf type2 keyword) 134
+ 4.4.15 operations-supported (1setOf type2 enum) 135
+ 4.4.16 multiple-document-jobs-supported (boolean) 136
+ 4.4.17 charset-configured (charset) 136
+ 4.4.18 charset-supported (1setOf charset) 137
+ 4.4.19 natural-language-configured (naturalLanguage) 137
+ 4.4.20 generated-natural-language-supported
+ (1setOf naturalLanguage) 137
+ 4.4.21 document-format-default (mimeMediaType) 138
+ 4.4.22 document-format-supported (1setOf mimeMediaType) 138
+ 4.4.23 printer-is-accepting-jobs (boolean) 138
+ 4.4.24 queued-job-count (integer(0:MAX)) 138
+ 4.4.25 printer-message-from-operator (text(127)) 139
+ 4.4.26 color-supported (boolean) 139
+ 4.4.27 reference-uri-schemes-supported (1setOf uriScheme) 139
+ 4.4.28 pdl-override-supported (type2 keyword) 139
+ 4.4.29 printer-up-time (integer(1:MAX)) 140
+ 4.4.30 printer-current-time (dateTime) 140
+ 4.4.31 multiple-operation-time-out (integer(1:MAX)) 141
+ 4.4.32 compression-supported (1setOf type3 keyword) 141
+ 4.4.33 job-k-octets-supported (rangeOfInteger(0:MAX)) 142
+ 4.4.34 job-impressions-supported (rangeOfInteger(0:MAX)) 142
+ 4.4.35 job-media-sheets-supported (rangeOfInteger(0:MAX)) 142
+ 4.4.36 pages-per-minute (integer(0:MAX)) 142
+ 4.4.37 pages-per-minute-color (integer(0:MAX)) 142
+ 5. Conformance 143
+ 5.1 Client Conformance Requirements 143
+ 5.2 IPP Object Conformance Requirements 145
+ 5.2.1 Objects 145
+ 5.2.2 Operations 145
+ 5.2.3 IPP Object Attributes 146
+ 5.2.4 Versions 146
+ 5.2.5 Extensions 147
+ 5.2.6 Attribute Syntaxes 147
+ 5.2.7 Security 148
+ 5.3 Charset and Natural Language Requirements 148
+ 6. IANA Considerations 148
+ 6.1 Typed 'keyword' and 'enum' Extensions 149
+ 6.2 Attribute Extensibility 151
+ 6.3 Attribute Syntax Extensibility 152
+ 6.4 Operation Extensibility 152
+
+
+
+Hastings, et al. Standards Track [Page 6]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 6.5 Attribute Group Extensibility 153
+ 6.6 Status Code Extensibility 153
+ 6.7 Out-of-band Attribute Value Extensibility 154
+ 6.8 Registration of MIME types/sub-types for document-formats 154
+ 6.9 Registration of charsets for use in 'charset'
+ attribute values 154
+ 7. Internationalization Considerations 154
+ 8. Security Considerations 158
+ 8.1 Security Scenarios 159
+ 8.1.1 Client and Server in the Same Security Domain 159
+ 8.1.2 Client and Server in Different Security Domains 159
+ 8.1.3 Print by Reference 160
+ 8.2 URIs in Operation, Job, and Printer attributes 160
+ 8.3 URIs for each authentication mechanisms 160
+ 8.4 Restricted Queries 161
+ 8.5 Operations performed by operators and system
+ administrators 161
+ 8.6 Queries on jobs submitted using non-IPP protocols 162
+ 9. References 162
+ 10. Authors' Addresses 166
+ 11. Formats for IPP Registration Proposals 168
+ 11.1 Type2 keyword attribute values registration 169
+ 11.2 Type3 keyword attribute values registration 169
+ 11.3 Type2 enum attribute values registration 169
+ 11.4 Type3 enum attribute values registration 170
+ 11.5 Attribute registration 170
+ 11.6 Attribute Syntax registration 171
+ 11.7 Operation registration 171
+ 11.8 Attribute Group registration 171
+ 11.9 Status code registration 172
+ 11.10 Out-of-band Attribute Value registration 172
+ 12. APPENDIX A: Terminology 173
+ 12.1 Conformance Terminology 173
+ 12.1.1 NEED NOT 173
+ 12.2 Model Terminology 173
+ 12.2.1 Keyword 173
+ 12.2.2 Attributes 173
+ 12.2.2.1 Attribute Name 173
+ 12.2.2.2 Attribute Group Name 174
+ 12.2.2.3 Attribute Value 174
+ 12.2.2.4 Attribute Syntax 174
+ 12.2.3 Supports 174
+ 12.2.4 print-stream page 176
+ 12.2.5 impression 177
+ 13. APPENDIX B: Status Codes and Suggested Status Code Messages 177
+ 13.1 Status Codes 178
+ 13.1.1 Informational 178
+ 13.1.2 Successful Status Codes 178
+
+
+
+Hastings, et al. Standards Track [Page 7]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 13.1.2.1 successful-ok (0x0000) 178
+ 13.1.2.2 successful-ok-ignored-or-substituted-attributes
+ (0x0001) 179
+ 13.1.2.3 successful-ok-conflicting-attributes (0x0002) 179
+ 13.1.3 Redirection Status Codes 179
+ 13.1.4 Client Error Status Codes 179
+ 13.1.4.1 client-error-bad-request (0x0400) 180
+ 13.1.4.2 client-error-forbidden (0x0401) 180
+ 13.1.4.3 client-error-not-authenticated (0x0402) 180
+ 13.1.4.4 client-error-not-authorized (0x0403) 180
+ 13.1.4.5 client-error-not-possible (0x0404) 180
+ 13.1.4.6 client-error-timeout (0x0405) 181
+ 13.1.4.7 client-error-not-found (0x0406) 181
+ 13.1.4.8 client-error-gone (0x0407) 181
+ 13.1.4.9 client-error-request-entity-too-large (0x0408) 182
+ 13.1.4.10 client-error-request-value-too-long (0x0409) 182
+ 13.1.4.11 client-error-document-format-not-supported (0x040A) 182
+ 13.1.4.12 client-error-attributes-or-values-not-supported
+ (0x040B) 183
+ 13.1.4.13 client-error-uri-scheme-not-supported (0x040C) 183
+ 13.1.4.14 client-error-charset-not-supported (0x040D) 183
+ 13.1.4.15 client-error-conflicting-attributes (0x040E) 183
+ 13.1.4.16 client-error-compression-not-supported (0x040F) 184
+ 13.1.4.17 client-error-compression-error (0x0410) 184
+ 13.1.4.18 client-error-document-format-error (0x0411) 184
+ 13.1.4.19 client-error-document-access-error (0x0412) 184
+ 13.1.5 Server Error Status Codes 185
+ 13.1.5.1 server-error-internal-error (0x0500) 185
+ 13.1.5.2 server-error-operation-not-supported (0x0501) 185
+ 13.1.5.3 server-error-service-unavailable (0x0502) 185
+ 13.1.5.4 server-error-version-not-supported (0x0503) 185
+ 13.1.5.5 server-error-device-error (0x0504) 186
+ 13.1.5.6 server-error-temporary-error (0x0505) 186
+ 13.1.5.7 server-error-not-accepting-jobs (0x0506) 187
+ 13.1.5.8 server-error-busy (0x0507) 187
+ 13.1.5.9 server-error-job-canceled (0x0508) 187
+ 13.1.5.10 server-error-multiple-document-jobs-not-supported
+ (0x0509) 187
+ 13.2 Status Codes for IPP Operations 187
+ 14. APPENDIX C: "media" keyword values 190
+ 15. APPENDIX D: Processing IPP Attributes 208
+ 15.1 Fidelity 209
+ 15.2 Page Description Language (PDL) Override 210
+ 15.3 Using Job Template Attributes During Document Processing 212
+ 16. APPENDIX E: Generic Directory Schema 214
+ 17. APPENDIX F: Differences between the IPP/1.0 and IPP/1.1
+ "Model and Semantics" Documents 215
+ 18. Full Copyright Statement 224
+
+
+
+Hastings, et al. Standards Track [Page 8]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+1. Introduction
+
+ The Internet Printing Protocol (IPP) is an application level protocol
+ that can be used for distributed printing using Internet tools and
+ technologies. IPP version 1.1 (IPP/1.1) focuses primarily on end
+ user functionality with a few administrative operations included.
+ This document is just one of a suite of documents that fully define
+ IPP. The full set of IPP documents includes:
+
+ Design Goals for an Internet Printing Protocol [RFC2567]
+ Rationale for the Structure and Model and Protocol for the Internet
+ Printing Protocol [RFC2568]
+ Internet Printing Protocol/1.1: Model and Semantics (this document)
+ Internet Printing Protocol/1.1: Encoding and Transport [RFC2910]
+ Internet Printing Protocol/1.1: Implementer's Guide [IPP-IIG]
+ Mapping between LPD and IPP Protocols [RFC2569]
+
+ Anyone reading these documents for the first time is strongly
+ encouraged to read the IPP documents in the above order.
+
+ This document is laid out as follows:
+
+ - The rest of Section 1 is an introduction to the IPP simplified
+ model for distributed printing.
+ - Section 2 introduces the object types covered in the model with
+ their basic behaviors, attributes, and interactions.
+ - Section 3 defines the operations included in IPP/1.1. IPP
+ operations are synchronous, therefore, for each operation, there is
+ a both request and a response.
+ - Section 4 defines the attributes (and their syntaxes) that are used
+ in the model.
+ - Sections 5 - 6 summarizes the implementation conformance
+ requirements for objects that support the protocol and IANA
+ considerations, respectively.
+ - Sections 7 - 11 cover the Internationalization and Security
+ considerations as well as References, Author contact information,
+ and Formats for Registration Proposals.
+ - Sections 12 - 14 are appendices that cover Terminology, Status
+ Codes and Messages, and "media" keyword values.
+
+ Note: This document uses terms such as "attributes", "keywords",
+ and "support". These terms have special meaning and are defined
+ in the model terminology section 12.2. Capitalized terms, such
+ as MUST, MUST NOT, REQUIRED, SHOULD, SHOULD NOT, MAY, NEED NOT,
+ and OPTIONAL, have special meaning relating to conformance.
+ These terms are defined in section 12.1 on conformance
+ terminology, most of which is taken from RFC 2119 [RFC2119].
+
+
+
+
+Hastings, et al. Standards Track [Page 9]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ - Section 15 is an appendix that helps to clarify the effects of
+ interactions between related attributes and their values.
+ - Section 16 is an appendix that enumerates the subset of Printer
+ attributes that form a generic directory schema. These attributes
+ are useful when registering a Printer so that a client can find the
+ Printer not just by name, but by filtered searches as well.
+ - Section 17 is an appendix summarizing the additions and changes
+ from the IPP/1.0 "Model and Semantics" document [RFC2566] to make
+ this IPP/1.1 document.
+ - Section 18 is the full copyright notice.
+
+1.1 Simplified Printing Model
+
+ In order to achieve its goal of realizing a workable printing
+ protocol for the Internet, the Internet Printing Protocol (IPP) is
+ based on a simplified printing model that abstracts the many
+ components of real world printing solutions. The Internet is a
+ distributed computing environment where requesters of print services
+ (clients, applications, printer drivers, etc.) cooperate and interact
+ with print service providers. This model and semantics document
+ describes a simple, abstract model for IPP even though the underlying
+ configurations may be complex "n-tier" client/server systems. An
+ important simplifying step in the IPP model is to expose only the key
+ objects and interfaces required for printing. The model described in
+ this model document does not include features, interfaces, and
+ relationships that are beyond the scope of the first version of IPP
+ (IPP/1.1). IPP/1.1 incorporates many of the relevant ideas and
+ lessons learned from other specification and development efforts
+ [HTPP] [ISO10175] [LDPA] [P1387.4] [PSIS] [RFC1179] [SWP]. IPP is
+ heavily influenced by the printing model introduced in the Document
+ Printing Application (DPA) [ISO10175] standard. Although DPA
+ specifies both end user and administrative features, IPP version 1.1
+ (IPP/1.1) focuses primarily on end user functionality with a few
+ additional OPTIONAL operator operations.
+
+ The IPP/1.1 model encapsulates the important components of
+ distributed printing into two object types:
+
+ - Printer (Section 2.1)
+ - Job (Section 2.2)
+
+ Each object type has an associated set of operations (see section 3)
+ and attributes (see section 4).
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 10]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ It is important, however, to understand that in real system
+ implementations (which lie underneath the abstracted IPP/1.1 model),
+ there are other components of a print service which are not
+ explicitly defined in the IPP/1.1 model. The following figure
+ illustrates where IPP/1.1 fits with respect to these other
+ components.
+
+ +--------------+
+ | Application |
+ o +. . . . . . . |
+ \|/ | Spooler |
+ / \ +. . . . . . . | +---------+
+ End-User | Print Driver |---| File |
+ +-----------+ +-----+ +------+-------+ +----+----+
+ | Browser | | GUI | | |
+ +-----+-----+ +--+--+ | |
+ | | | |
+ | +---+------------+---+ |
+ N D S | | IPP Client |------------+
+ O I E | +---------+----------+
+ T R C | |
+ I E U |
+ F C R -------------- Transport ------------------
+ I T I
+ C O T | --+
+ A R Y +--------+--------+ |
+ T Y | IPP Server | |
+ I +--------+--------+ |
+ O | |
+ N +-----------------+ | IPP Printer
+ | Print Service | |
+ +-----------------+ |
+ | --+
+ +-----------------+
+ | Output Device(s)|
+ +-----------------+
+
+ An IPP Printer object encapsulates the functions normally associated
+ with physical output devices along with the spooling, scheduling and
+ multiple device management functions often associated with a print
+ server. Printer objects are optionally registered as entries in a
+ directory where end users find and select them based on some sort of
+ filtered and context based searching mechanism (see section 16). The
+ directory is used to store relatively static information about the
+ Printer, allowing end users to search for and find Printers that
+ match their search criteria, for example: name, context, printer
+ capabilities, etc. The more dynamic information, such as state,
+ currently loaded and ready media, number of jobs at the Printer,
+
+
+
+Hastings, et al. Standards Track [Page 11]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ errors, warnings, and so forth, is directly associated with the
+ Printer object itself rather than with the entry in the directory
+ which only represents the Printer object.
+
+ IPP clients implement the IPP protocol on the client side and give
+ end users (or programs running on behalf of end users) the ability to
+ query Printer objects and submit and manage print jobs. An IPP
+ server is just that part of the Printer object that implements the
+ server-side protocol. The rest of the Printer object implements (or
+ gateways into) the application semantics of the print service itself.
+ The Printer objects may be embedded in an output device or may be
+ implemented on a host on the network that communicates with an output
+ device.
+
+ When a job is submitted to the Printer object and the Printer object
+ validates the attributes in the submission request, the Printer
+ object creates a new Job object. The end user then interacts with
+ this new Job object to query its status and monitor the progress of
+ the job. An end user can also cancel their print jobs by using the
+ Job object's Cancel-Job operation. An end-user can also hold,
+ release, and restart their print jobs using the Job object's OPTIONAL
+ Hold-Job, Release-Job, and Restart-Job operations, if implemented.
+
+ A privileged operator or administrator of a Printer object can
+ cancel, hold, release, and restart any user's job using the REQUIRED
+ Cancel-Job and the OPTIONAL Hold-Job, Release-Job, and Restart-Job
+ operations. In additional privileged operator or administrator of a
+ Printer object can pause, resume, or purge (jobs from) a Printer
+ object using the OPTIONAL Pause-Printer, Resume-Printer, and Purge-
+ Jobs operations, if implemented.
+
+ The notification service is out of scope for this IPP/1.1 document,
+ but using such a notification service, the end user is able to
+ register for and receive Printer specific and Job specific events.
+ An end user can query the status of Printer objects and can follow
+ the progress of Job objects by polling using the Get-Printer-
+ Attributes, Get-Jobs, and Get-Job-Attributes operations.
+
+2. IPP Objects
+
+ The IPP/1.1 model introduces objects of type Printer and Job. Each
+ type of object models relevant aspects of a real-world entity such as
+ a real printer or real print job. Each object type is defined as a
+ set of possible attributes that may be supported by instances of that
+ object type. For each object (instance), the actual set of supported
+ attributes and values describe a specific implementation. The
+ object's attributes and values describe its state, capabilities,
+ realizable features, job processing functions, and default behaviors
+
+
+
+Hastings, et al. Standards Track [Page 12]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ and characteristics. For example, the Printer object type is defined
+ as a set of attributes that each Printer object potentially supports.
+ In the same manner, the Job object type is defined as a set of
+ attributes that are potentially supported by each Job object.
+
+ Each attribute included in the set of attributes defining an object
+ type is labeled as:
+
+ - "REQUIRED": each object MUST support the attribute.
+ - "RECOMMENDED": each object SHOULD support the attribute.
+ - "OPTIONAL": each object MAY support the attribute.
+
+ Some definitions of attribute values indicate that an object MUST or
+ SHOULD support the value; otherwise, support of the value is
+ OPTIONAL.
+
+ However, if an implementation supports an attribute, it MUST support
+ at least one of the possible values for that attribute.
+
+2.1 Printer Object
+
+ The major component of the IPP/1.1 model is the Printer object. A
+ Printer object implements the server-side of the IPP/1.1 protocol.
+ Using the protocol, end users may query the attributes of the Printer
+ object and submit print jobs to the Printer object. The actual
+ implementation components behind the Printer abstraction may take on
+ different forms and different configurations. However, the model
+ abstraction allows the details of the configuration of real
+ components to remain opaque to the end user. Section 3 describes
+ each of the Printer operations in detail.
+
+ The capabilities and state of a Printer object are described by its
+ attributes. Printer attributes are divided into two groups:
+
+ - "job-template" attributes: These attributes describe supported job
+ processing capabilities and defaults for the Printer object. (See
+ section 4.2)
+ - "printer-description" attributes: These attributes describe the
+ Printer object's identification, state, location, references to
+ other sources of information about the Printer object, etc. (see
+ section 4.4)
+
+ Since a Printer object is an abstraction of a generic document output
+ device and print service provider, a Printer object could be used to
+ represent any real or virtual device with semantics consistent with
+ the Printer object, such as a fax device, an imager, or even a CD
+ writer.
+
+
+
+
+Hastings, et al. Standards Track [Page 13]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Some examples of configurations supporting a Printer object include:
+
+ 1) An output device with no spooling capabilities
+ 2) An output device with a built-in spooler
+ 3) A print server supporting IPP with one or more associated
+ output devices
+ 3a) The associated output devices may or may not be capable of
+ spooling jobs
+ 3b) The associated output devices may or may not support IPP
+
+ The following figures show some examples of how Printer objects can
+ be realized on top of various distributed printing configurations.
+ The embedded case below represents configurations 1 and 2. The hosted
+ and fan-out figures below represent configurations 3a and 3b.
+
+ In this document the term "client" refers to a software entity that
+ sends IPP operation requests to an IPP Printer object and accepts IPP
+ operation responses. A client MAY be:
+
+ 1. contained within software controlled by an end user, e.g.
+ activated by the "Print" menu item in an application or
+
+ 2. the print server component that sends IPP requests to either an
+ output device or another "downstream" print server.
+
+ The term "IPP Printer" is a network entity that accepts IPP operation
+ requests and returns IPP operation responses. As such, an IPP object
+ MAY be:
+
+ 1. an (embedded) device component that accepts IPP requests and
+ controls the device or
+
+ 2. a component of a print server that accepts IPP requests (where
+ the print server controls one or more networked devices using
+ IPP or other protocols).
+
+ Legend:
+
+ ##### indicates a Printer object which is
+ either embedded in an output device or is
+ hosted in a server. The Printer object
+ might or might not be capable of queuing/spooling.
+
+ any indicates any network protocol or direct
+ connect, including IPP
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 14]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ embedded printer:
+ output device
+ +---------------+
+ O +--------+ | ########### |
+ /|\ | client |------------IPP------------># Printer # |
+ / \ +--------+ | # Object # |
+ | ########### |
+ +---------------+
+
+ hosted printer:
+ +---------------+
+ O +--------+ ########### | |
+ /|\ | client |--IPP--># Printer #-any->| output device |
+ / \ +--------+ # Object # | |
+ ########### +---------------+
+
+
+ +---------------+
+ fan out: | |
+ +-->| output device |
+ any/ | |
+ O +--------+ ########### / +---------------+
+ /|\ | client |-IPP-># Printer #--*
+ / \ +--------+ # Object # \ +---------------+
+ ########### any\ | |
+ +-->| output device |
+ | |
+ +---------------+
+
+2.2 Job Object
+
+ A Job object is used to model a print job. A Job object contains
+ documents. The information required to create a Job object is sent
+ in a create request from the end user via an IPP Client to the
+ Printer object. The Printer object validates the create request, and
+ if the Printer object accepts the request, the Printer object creates
+ the new Job object. Section 3 describes each of the Job operations
+ in detail.
+
+ The characteristics and state of a Job object are described by its
+ attributes. Job attributes are grouped into two groups as follows:
+
+ - "job-template" attributes: These attributes can be supplied by
+ the client or end user and include job processing instructions
+ which are intended to override any Printer object defaults
+ and/or instructions embedded within the document data. (See
+ section 4.2)
+
+
+
+
+Hastings, et al. Standards Track [Page 15]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ - "job-description" attributes: These attributes describe the Job
+ object's identification, state, size, etc. The client supplies
+ some of these attributes, and the Printer object generates
+ others. (See section 4.3)
+
+ An implementation MUST support at least one document per Job object.
+ An implementation MAY support multiple documents per Job object. A
+ document is either:
+
+ - a stream of document data in a format supported by the Printer
+ object (typically a Page Description Language - PDL), or
+ - a reference to such a stream of document data
+
+ In IPP/1.1, a document is not modeled as an IPP object, therefore it
+ has no object identifier or associated attributes. All job
+ processing instructions are modeled as Job object attributes. These
+ attributes are called Job Template attributes and they apply equally
+ to all documents within a Job object.
+
+2.3 Object Relationships
+
+ IPP objects have relationships that are maintained persistently along
+ with the persistent storage of the object attributes.
+
+ A Printer object can represent either one or more physical output
+ devices or a logical device which "processes" jobs but never actually
+ uses a physical output device to put marks on paper. Examples of
+ logical devices include a Web page publisher or a gateway into an
+ online document archive or repository. A Printer object contains
+ zero or more Job objects.
+
+ A Job object is contained by exactly one Printer object, however the
+ identical document data associated with a Job object could be sent to
+ either the same or a different Printer object. In this case, a
+ second Job object would be created which would be almost identical to
+ the first Job object, however it would have new (different) Job
+ object identifiers (see section 2.4).
+
+ A Job object is either empty (before any documents have been added)
+ or contains one or more documents. If the contained document is a
+ stream of document data, that stream can be contained in only one
+ document. However, there can be identical copies of the stream in
+ other documents in the same or different Job objects. If the
+ contained document is just a reference to a stream of document data,
+ other documents (in the same or different Job object(s)) may contain
+ the same reference.
+
+
+
+
+
+Hastings, et al. Standards Track [Page 16]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+2.4 Object Identity
+
+ All Printer and Job objects are identified by a Uniform Resource
+ Identifier (URI) [RFC2396] so that they can be persistently and
+ unambiguously referenced. Since every URL is a specialized form of a
+ URI, even though the more generic term URI is used throughout the
+ rest of this document, its usage is intended to cover the more
+ specific notion of URL as well.
+
+ An administrator configures Printer objects to either support or not
+ support authentication and/or message privacy using Transport Layer
+ Security (TLS) [RFC2246] (the mechanism for security configuration is
+ outside the scope of this IPP/1.1 document). In some situations,
+ both types of connections (both authenticated and unauthenticated)
+ can be established using a single communication channel that has some
+ sort of negotiation mechanism. In other situations, multiple
+ communication channels are used, one for each type of security
+ configuration. Section 8 provides a full description of all security
+ considerations and configurations.
+
+ If a Printer object supports more than one communication channel,
+ some or all of those channels might support and/or require different
+ security mechanisms. In such cases, an administrator could expose
+ the simultaneous support for these multiple communication channels as
+ multiple URIs for a single Printer object where each URI represents
+ one of the communication channels to the Printer object. To support
+ this flexibility, the IPP Printer object type defines a multi-valued
+ identification attribute called the "printer-uri-supported"
+ attribute. It MUST contain at least one URI. It MAY contain more
+ than one URI. That is, every Printer object will have at least one
+ URI that identifies at least one communication channel to the Printer
+ object, but it may have more than one URI where each URI identifies a
+ different communication channel to the Printer object. The
+ "printer-uri-supported" attribute has two companion attributes, the
+ "uri-security-supported" attribute and the "uri-authentication-
+ supported". Both have the same cardinality as "printer-uri-
+ supported". The purpose of the "uri-security-supported" attribute is
+ to indicate the security mechanisms (if any) used for each URI listed
+ in "printer-uri-supported". The purpose of the "uri-authentication-
+ supported" attribute is to indicate the authentication mechanisms (if
+ any) used for each URI listed in "printer-uri-supported". These
+ three attributes are fully described in sections 4.4.1, 4.4.2, and
+ 4.4.3.
+
+ When a job is submitted to the Printer object via a create request,
+ the client supplies only a single Printer object URI. The client
+ supplied Printer object URI MUST be one of the values in the
+ "printer-uri-supported" Printer attribute.
+
+
+
+Hastings, et al. Standards Track [Page 17]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ IPP/1.1 does not specify how the client obtains the client supplied
+ URI, but it is RECOMMENDED that a Printer object be registered as an
+ entry in a directory service. End-users and programs can then
+ interrogate the directory searching for Printers. Section 16 defines
+ a generic schema for Printer object entries in the directory service
+ and describes how the entry acts as a bridge to the actual IPP
+ Printer object. The entry in the directory that represents the IPP
+ Printer object includes the possibly many URIs for that Printer
+ object as values in one its attributes.
+
+ When a client submits a create request to the Printer object, the
+ Printer object validates the request and creates a new Job object.
+ The Printer object assigns the new Job object a URI which is stored
+ in the "job-uri" Job attribute. This URI is then used by clients as
+ the target for subsequent Job operations. The Printer object
+ generates a Job URI based on its configured security policy and the
+ URI used by the client in the create request.
+
+ For example, consider a Printer object that supports both a
+ communication channel secured by the use of SSL3 (using HTTP over
+ SSL3 with an "https" schemed URI) and another open communication
+ channel that is not secured with SSL3 (using a simple "http" schemed
+ URI). If a client were to submit a job using the secure URI, the
+ Printer object would assign the new Job object a secure URI as well.
+ If a client were to submit a job using the open-channel URI, the
+ Printer would assign the new Job object an open-channel URI.
+
+ In addition, the Printer object also populates the Job object's
+ "job-printer-uri" attribute. This is a reference back to the Printer
+ object that created the Job object. If a client only has access to a
+ Job object's "job-uri" identifier, the client can query the Job's
+ "job-printer-uri" attribute in order to determine which Printer
+ object created the Job object. If the Printer object supports more
+ than one URI, the Printer object picks the one URI supplied by the
+ client when creating the job to build the value for and to populate
+ the Job's "job-printer-uri" attribute.
+
+ Allowing Job objects to have URIs allows for flexibility and
+ scalability. For example, in some implementations, the Printer
+ object might create Jobs that are processed in the same local
+ environment as the Printer object itself. In this case, the Job URI
+ might just be a composition of the Printer's URI and some unique
+ component for the Job object, such as the unique 32-bit positive
+ integer mentioned later in this paragraph. In other implementations,
+ the Printer object might be a central clearing-house for validating
+ all Job object creation requests, but the Job object itself might be
+ created in some environment that is remote from the Printer object.
+ In this case, the Job object's URI may have no physical-location
+
+
+
+Hastings, et al. Standards Track [Page 18]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ relationship at all to the Printer object's URI. Again, the fact
+ that Job objects have URIs allows for flexibility and scalability,
+ however, many existing printing systems have local models or
+ interface constraints that force print jobs to be identified using
+ only a 32-bit positive integer rather than an independent URI. This
+ numeric Job ID is only unique within the context of the Printer
+ object to which the create request was originally submitted.
+ Therefore, in order to allow both types of client access to IPP Job
+ objects (either by Job URI or by numeric Job ID), when the Printer
+ object successfully processes a create request and creates a new Job
+ object, the Printer object MUST generate both a Job URI and a Job ID.
+ The Job ID (stored in the "job-id" attribute) only has meaning in the
+ context of the Printer object to which the create request was
+ originally submitted. This requirement to support both Job URIs and
+ Job IDs allows all types of clients to access Printer objects and Job
+ objects no matter the local constraints imposed on the client
+ implementation.
+
+ In addition to identifiers, Printer objects and Job objects have
+ names ("printer-name" and "job-name"). An object name NEED NOT be
+ unique across all instances of all objects. A Printer object's name
+ is chosen and set by an administrator through some mechanism outside
+ the scope of this IPP/1.1 document. A Job object's name is
+ optionally chosen and supplied by the IPP client submitting the job.
+ If the client does not supply a Job object name, the Printer object
+ generates a name for the new Job object. In all cases, the name only
+ has local meaning.
+
+ To summarize:
+
+ - Each Printer object is identified with one or more URIs. The
+ Printer's "printer-uri-supported" attribute contains the URI(s).
+ - The Printer object's "uri-security-supported" attribute
+ identifies the communication channel security protocols that may
+ or may not have been configured for the various Printer object
+ URIs (e.g., 'tls' or 'none').
+ - The Printer object's "uri-authentication-supported" attribute
+ identifies the authentication mechanisms that may or may not
+ have been configured for the various Printer object URIs (e.g.,
+ 'digest' or 'none').
+ - Each Job object is identified with a Job URI. The Job's "job-
+ uri" attribute contains the URI.
+ - Each Job object is also identified with Job ID which is a 32-
+ bit, positive integer. The Job's "job-id" attribute contains
+ the Job ID. The Job ID is only unique within the context of the
+ Printer object which created the Job object.
+
+
+
+
+
+Hastings, et al. Standards Track [Page 19]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ - Each Job object has a "job-printer-uri" attribute which contains
+ the URI of the Printer object that was used to create the Job
+ object. This attribute is used to determine the Printer object
+ that created a Job object when given only the URI for the Job
+ object. This linkage is necessary to determine the languages,
+ charsets, and operations which are supported on that Job (the
+ basis for such support comes from the creating Printer object).
+ - Each Printer object has a name (which is not necessarily
+ unique). The administrator chooses and sets this name through
+ some mechanism outside the scope of this IPP/1.1 document. The
+ Printer object's "printer-name" attribute contains the name.
+ - Each Job object has a name (which is not necessarily unique).
+ The client optionally supplies this name in the create request.
+ If the client does not supply this name, the Printer object
+ generates a name for the Job object. The Job object's "job-name"
+ attribute contains the name.
+
+3. IPP Operations
+
+ IPP objects support operations. An operation consists of a request
+ and a response. When a client communicates with an IPP object, the
+ client issues an operation request to the URI for that object.
+ Operation requests and responses have parameters that identify the
+ operation. Operations also have attributes that affect the run-time
+ characteristics of the operation (the intended target, localization
+ information, etc.). These operation-specific attributes are called
+ operation attributes (as compared to object attributes such as
+ Printer object attributes or Job object attributes). Each request
+ carries along with it any operation attributes, object attributes,
+ and/or document data required to perform the operation. Each request
+ requires a response from the object. Each response indicates success
+ or failure of the operation with a status code as a response
+ parameter. The response contains any operation attributes, object
+ attributes, and/or status messages generated during the execution of
+ the operation request.
+
+ This section describes the semantics of the IPP operations, both
+ requests and responses, in terms of the parameters, attributes, and
+ other data associated with each operation.
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 20]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ The IPP/1.1 Printer operations are:
+
+ Print-Job (section 3.2.1)
+ Print-URI (section 3.2.2)
+ Validate-Job (section 3.2.3)
+ Create-Job (section 3.2.4)
+ Get-Printer-Attributes (section 3.2.5)
+ Get-Jobs (section 3.2.6)
+ Pause-Printer (section 3.3.5)
+ Resume-Printer (section 3.3.6)
+ Purge-Jobs (section 3.3.7)
+
+ The Job operations are:
+
+ Send-Document (section 3.3.1)
+ Send-URI (section 3.3.2)
+ Cancel-Job (section 3.3.3)
+ Get-Job-Attributes (section 3.3.4)
+ Hold-Job (section 3.3.5)
+ Release-Job (section 3.3.6)
+ Restart-Job (section 3.3.7)
+
+ The Send-Document and Send-URI Job operations are used to add a new
+ document to an existing multi-document Job object created using the
+ Create-Job operation.
+
+3.1 Common Semantics
+
+ All IPP operations require some common parameters and operation
+ attributes. These common elements and their semantic characteristics
+ are defined and described in more detail in the following sections.
+
+3.1.1 Required Parameters
+
+ Every operation request contains the following REQUIRED parameters:
+
+ - a "version-number",
+ - an "operation-id",
+ - a "request-id", and
+ - the attributes that are REQUIRED for that type of request.
+
+ Every operation response contains the following REQUIRED parameters:
+
+ - a "version-number",
+ - a "status-code",
+ - the "request-id" that was supplied in the corresponding request,
+ and
+ - the attributes that are REQUIRED for that type of response.
+
+
+
+Hastings, et al. Standards Track [Page 21]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ The "Encoding and Transport" document [RFC2910] defines special rules
+ for the encoding of these parameters. All other operation elements
+ are represented using the more generic encoding rules for attributes
+ and groups of attributes.
+
+3.1.2 Operation IDs and Request IDs
+
+ Each IPP operation request includes an identifying "operation-id"
+ value. Valid values are defined in the "operations-supported"
+ Printer attribute section (see section 4.4.15). The client specifies
+ which operation is being requested by supplying the correct
+ "operation-id" value.
+
+ In addition, every invocation of an operation is identified by a
+ "request-id" value. For each request, the client chooses the
+ "request-id" which MUST be an integer (possibly unique depending on
+ client requirements) in the range from 1 to 2**31 - 1 (inclusive).
+ This "request-id" allows clients to manage multiple outstanding
+ requests. The receiving IPP object copies all 32-bits of the client-
+ supplied "request-id" attribute into the response so that the client
+ can match the response with the correct outstanding request, even if
+ the "request-id" is out of range. If the request is terminated
+ before the complete "request-id" is received, the IPP object rejects
+ the request and returns a response with a "request-id" of 0.
+
+ Note: In some cases, the transport protocol underneath IPP might be a
+ connection oriented protocol that would make it impossible for a
+ client to receive responses in any order other than the order in
+ which the corresponding requests were sent. In such cases, the
+ "request-id" attribute would not be essential for correct protocol
+ operation. However, in other mappings, the operation responses can
+ come back in any order. In these cases, the "request-id" would be
+ essential.
+
+3.1.3 Attributes
+
+ Operation requests and responses are both composed of groups of
+ attributes and/or document data. The attributes groups are:
+
+ - Operation Attributes: These attributes are passed in the
+ operation and affect the IPP object's behavior while processing
+ the operation request and may affect other attributes or groups
+ of attributes. Some operation attributes describe the document
+ data associated with the print job and are associated with new
+ Job objects, however most operation attributes do not persist
+ beyond the life of the operation. The description of each
+ operation attribute includes conformance statements indicating
+ which operation attributes are REQUIRED and which are OPTIONAL
+
+
+
+Hastings, et al. Standards Track [Page 22]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ for an IPP object to support and which attributes a client MUST
+ supply in a request and an IPP object MUST supply in a response.
+ - Job Template Attributes: These attributes affect the processing
+ of a job. A client OPTIONALLY supplies Job Template Attributes
+ in a create request, and the receiving object MUST be prepared
+ to receive all supported attributes. The Job object can later
+ be queried to find out what Job Template attributes were
+ originally requested in the create request, and such attributes
+ are returned in the response as Job Object Attributes. The
+ Printer object can be queried about its Job Template attributes
+ to find out what type of job processing capabilities are
+ supported and/or what the default job processing behaviors are,
+ though such attributes are returned in the response as Printer
+ Object Attributes. The "ipp-attribute-fidelity" operation
+ attribute affects processing of all client-supplied Job Template
+ attributes (see sections 3.2.1.2 and 15 for a full description
+ of "ipp-attribute-fidelity" and its relationship to other
+ attributes).
+ - Job Object Attributes: These attributes are returned in response
+ to a query operation directed at a Job object.
+ - Printer Object Attributes: These attributes are returned in
+ response to a query operation directed at a Printer object.
+ - Unsupported Attributes: In a create request, the client supplies
+ a set of Operation and Job Template attributes. If any of these
+ attributes or their values is unsupported by the Printer object,
+ the Printer object returns the set of unsupported attributes in
+ the response. Sections 3.1.7, 3.2.1.2, and 15 give a full
+ description of how Job Template attributes supplied by the
+ client in a create request are processed by the Printer object
+ and how unsupported attributes are returned to the client.
+ Because of extensibility, any IPP object might receive a request
+ that contains new or unknown attributes or values for which it
+ has no support. In such cases, the IPP object processes what it
+ can and returns the unsupported attributes in the response. The
+ Unsupported Attribute group is defined for all operation
+ responses for returning unsupported attributes that the client
+ supplied in the request.
+
+ Later in this section, each operation is formally defined by
+ identifying the allowed and expected groups of attributes for each
+ request and response. The model identifies a specific order for each
+ group in each request or response, but the attributes within each
+ group may be in any order, unless specified otherwise.
+
+ The attributes within a group MUST be unique; if an attribute with
+ the same name occurs more than once, the group is mal-formed.
+ Clients MUST NOT submit such malformed requests and Printers MUST NOT
+ return such malformed responses. If such a malformed request is
+
+
+
+Hastings, et al. Standards Track [Page 23]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ submitted to a Printer, the Printer MUST either (1) reject the
+ request with the 'client-error-bad-request' status code (see section
+ 13.1.4.1) or (2) process the request normally after selecting only
+ one of the attribute instances, depending on implementation. Which
+ attribute is selected when there are duplicate attributes depends on
+ implementation. The IPP Printer MUST NOT use the values from more
+ than one such duplicate attribute instance.
+
+ Each attribute definition includes the attribute's name followed by
+ the name of its attribute syntax(es) in parenthesizes. In addition,
+ each 'integer' attribute is followed by the allowed range in
+ parentheses, (m:n), for values of that attribute. Each 'text' or
+ 'name' attribute is followed by the maximum size in octets in
+ parentheses, (size), for values of that attribute. For more details
+ on attribute syntax notation, see the descriptions of these
+ attributes syntaxes in section 4.1.
+
+ Note: Document data included in the operation is not strictly an
+ attribute, but it is treated as a special attribute group for
+ ordering purposes. The only operations that support supplying the
+ document data within an operation request are Print-Job and Send-
+ Document. There are no operation responses that include document
+ data.
+
+ Some operations are REQUIRED for IPP objects to support; the others
+ are OPTIONAL (see section 5.2.2). Therefore, before using an
+ OPTIONAL operation, a client SHOULD first use the REQUIRED Get-
+ Printer-Attributes operation to query the Printer's "operations-
+ supported" attribute in order to determine which OPTIONAL Printer and
+ Job operations are actually supported. The client SHOULD NOT use an
+ OPTIONAL operation that is not supported. When an IPP object
+ receives a request to perform an operation it does not support, it
+ returns the 'server-error-operation-not-supported' status code (see
+ section 13.1.5.2). An IPP object is non-conformant if it does not
+ support a REQUIRED operation.
+
+3.1.4 Character Set and Natural Language Operation Attributes
+
+ Some Job and Printer attributes have values that are text strings and
+ names intended for human understanding rather than machine
+ understanding (see the 'text' and 'name' attribute syntax
+ descriptions in section 4.1). The following sections describe two
+ special Operation Attributes called "attributes-charset" and
+ "attributes-natural-language". These attributes are always part of
+ the Operation Attributes group. For most attribute groups, the order
+ of the attributes within the group is not important. However, for
+ these two attributes within the Operation Attributes group, the order
+ is critical. The "attributes-charset" attribute MUST be the first
+
+
+
+Hastings, et al. Standards Track [Page 24]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ attribute in the group and the "attributes-natural-language"
+ attribute MUST be the second attribute in the group. In other words,
+ these attributes MUST be supplied in every IPP request and response,
+ they MUST come first in the group, and MUST come in the specified
+ order. For job creation operations, the IPP Printer implementation
+ saves these two attributes with the new Job object as Job Description
+ attributes. For the sake of brevity in this document, these
+ operation attribute descriptions are not repeated with every
+ operation request and response, but have a reference back to this
+ section instead.
+
+3.1.4.1 Request Operation Attributes
+
+ The client MUST supply and the Printer object MUST support the
+ following REQUIRED operation attributes in every IPP/1.1 operation
+ request:
+
+ "attributes-charset" (charset):
+ This operation attribute identifies the charset (coded
+ character set and encoding method) used by any 'text' and
+ 'name' attributes that the client is supplying in this request.
+ It also identifies the charset that the Printer object MUST use
+ (if supported) for all 'text' and 'name' attributes and status
+ messages that the Printer object returns in the response to
+ this request. See Sections 4.1.1 and 4.1.2 for the definition
+ of the 'text' and 'name' attribute syntaxes.
+
+ All clients and IPP objects MUST support the 'utf-8' charset
+ [RFC2279] and MAY support additional charsets provided that
+ they are registered with IANA [IANA-CS]. If the Printer object
+ does not support the client supplied charset value, the Printer
+ object MUST reject the request, set the "attributes-charset" to
+ 'utf-8' in the response, and return the 'client-error-charset-
+ not-supported' status code and any 'text' or 'name' attributes
+ using the 'utf-8' charset. The Printer NEED NOT return any
+ attributes in the Unsupported Attributes Group (See sections
+ 3.1.7 and 3.2.1.2). The Printer object MUST indicate the
+ charset(s) supported as the values of the "charset-supported"
+ Printer attribute (see Section 4.4.18), so that the client can
+ query to determine which charset(s) are supported.
+
+ Note to client implementers: Since IPP objects are only
+ required to support the 'utf-8' charset, in order to maximize
+ interoperability with multiple IPP object implementations, a
+ client may want to supply 'utf-8' in the "attributes-charset"
+ operation attribute, even though the client is only passing and
+ able to present a simpler charset, such as US-ASCII [ASCII] or
+ ISO-8859-1 [ISO8859-1]. Then the client will have to filter
+
+
+
+Hastings, et al. Standards Track [Page 25]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ out (or charset convert) those characters that are returned in
+ the response that it cannot present to its user. On the other
+ hand, if both the client and the IPP objects also support a
+ charset in common besides utf-8, the client may want to use
+ that charset in order to avoid charset conversion or data loss.
+
+ See the 'charset' attribute syntax description in Section 4.1.7
+ for the syntax and semantic interpretation of the values of
+ this attribute and for example values.
+
+ "attributes-natural-language" (naturalLanguage):
+ This operation attribute identifies the natural language used
+ by any 'text' and 'name' attributes that the client is
+ supplying in this request. This attribute also identifies the
+ natural language that the Printer object SHOULD use for all
+ 'text' and 'name' attributes and status messages that the
+ Printer object returns in the response to this request. See
+ the 'naturalLanguage' attribute syntax description in section
+ 4.1.8 for the syntax and semantic interpretation of the values
+ of this attribute and for example values.
+
+ There are no REQUIRED natural languages required for the
+ Printer object to support. However, the Printer object's
+ "generated-natural-language-supported" attribute identifies the
+ natural languages supported by the Printer object and any
+ contained Job objects for all text strings generated by the IPP
+ object. A client MAY query this attribute to determine which
+ natural language(s) are supported for generated messages.
+
+ For any of the attributes for which the Printer object
+ generates text, i.e., for the "job-state-message", "printer-
+ state-message", and status messages (see Section 3.1.6), the
+ Printer object MUST be able to generate these text strings in
+ any of its supported natural languages. If the client requests
+ a natural language that is not supported, the Printer object
+ MUST return these generated messages in the Printer's
+ configured natural language as specified by the Printer's
+ "natural-language-configured" attribute" (see Section 4.4.19).
+
+ For other 'text' and 'name' attributes supplied by the client,
+ authentication system, operator, system administrator, or
+ manufacturer (i.e., for "job-originating-user-name", "printer-
+ name" (name), "printer-location" (text), "printer-info" (text),
+ and "printer-make-and-model" (text)), the Printer object is
+ only required to support the configured natural language of the
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 26]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Printer identified by the Printer object's "natural-language-
+ configured" attribute, though support of additional natural
+ languages for these attributes is permitted.
+
+ For any 'text' or 'name' attribute in the request that is in a
+ different natural language than the value supplied in the
+ "attributes-natural-language" operation attribute, the client
+ MUST use the Natural Language Override mechanism (see sections
+ 4.1.1.2 and 4.1.2.2) for each such attribute value supplied.
+ The client MAY use the Natural Language Override mechanism
+ redundantly, i.e., use it even when the value is in the same
+ natural language as the value supplied in the "attributes-
+ natural-language" operation attribute of the request.
+
+ The IPP object MUST accept any natural language and any Natural
+ Language Override, whether the IPP object supports that natural
+ language or not (and independent of the value of the "ipp-
+ attribute-fidelity" Operation attribute). That is the IPP
+ object accepts all client supplied values no matter what the
+ values are in the Printer object's "generated-natural-
+ language-supported" attribute. That attribute, "generated-
+ natural-language-supported", only applies to generated
+ messages, not client supplied messages. The IPP object MUST
+ remember that natural language for all client-supplied
+ attributes, and when returning those attributes in response to
+ a query, the IPP object MUST indicate that natural language.
+
+ Each value whose attribute syntax type is 'text' or 'name' (see
+ sections 4.1.1 and 4.1.2) has an Associated Natural-Language.
+ This document does not specify how this association is stored
+ in a Printer or Job object. When such a value is encoded in a
+ request or response, the natural language is either implicit or
+ explicit:
+
+ - In the implicit case, the value contains only the text/name
+ value, and the language is specified by the "attributes-
+ natural-language" operation attribute in the request or
+ response (see sections 4.1.1.1 textWithoutLanguage and
+ 4.1.2.1 nameWithoutLanguage).
+
+ - In the explicit case (also known as the Natural-Language
+ Override case), the value contains both the language and the
+ text/name value (see sections 4.1.1.2 textWithLanguage and
+ 4.1.2.2 nameWithLanguage).
+
+ For example, the "job-name" attribute MAY be supplied by the
+ client in a create request. The text value for this attribute
+ will be in the natural language identified by the "attribute-
+
+
+
+Hastings, et al. Standards Track [Page 27]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ natural-language" attribute, or if different, as identified by
+ the Natural Language Override mechanism. If supplied, the IPP
+ object will use the value of the "job-name" attribute to
+ populate the Job object's "job-name" attribute. Whenever any
+ client queries the Job object's "job-name" attribute, the IPP
+ object returns the attribute as stored and uses the Natural
+ Language Override mechanism to specify the natural language, if
+ it is different from that reported in the "attributes-natural-
+ language" operation attribute of the response. The IPP object
+ MAY use the Natural Language Override mechanism redundantly,
+ i.e., use it even when the value is in the same natural
+ language as the value supplied in the "attributes-natural-
+ language" operation attribute of the response.
+
+ An IPP object MUST NOT reject a request based on a supplied
+ natural language in an "attributes-natural-language" Operation
+ attribute or in any attribute that uses the Natural Language
+ Override.
+
+ Clients SHOULD NOT supply 'text' or 'name' attributes that use an
+ illegal combination of natural language and charset. For example,
+ suppose a Printer object supports charsets 'utf-8', 'iso-8859-1', and
+ 'iso-8859-7'. Suppose also, that it supports natural languages 'en'
+ (English), 'fr' (French), and 'el' (Greek). Although the Printer
+ object supports the charset 'iso-8859-1' and natural language 'el',
+ it probably does not support the combination of Greek text strings
+ using the 'iso-8859-1' charset. The Printer object handles this
+ apparent incompatibility differently depending on the context in
+ which it occurs:
+
+ - In a create request: If the client supplies a text or name
+ attribute (for example, the "job-name" operation attribute) that
+ uses an apparently incompatible combination, it is a client
+ choice that does not affect the Printer object or its correct
+ operation. Therefore, the Printer object simply accepts the
+ client supplied value, stores it with the Job object, and
+ responds back with the same combination whenever the client (or
+ any client) queries for that attribute.
+ - In a query-type operation, like Get-Printer-Attributes: If the
+ client requests an apparently incompatible combination, the
+ Printer object responds (as described in section 3.1.4.2) using
+ the Printer's configured natural language rather than the
+ natural language requested by the client.
+
+ In either case, the Printer object does not reject the request
+ because of the apparent incompatibility. The potential incompatible
+ combination of charset and natural language can occur either at the
+ global operation level or at the Natural Language Override
+
+
+
+Hastings, et al. Standards Track [Page 28]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ attribute-by-attribute level. In addition, since the response always
+ includes explicit charset and natural language information, there is
+ never any question or ambiguity in how the client interprets the
+ response.
+
+3.1.4.2 Response Operation Attributes
+
+ The Printer object MUST supply and the client MUST support the
+ following REQUIRED operation attributes in every IPP/1.1 operation
+ response:
+
+ "attributes-charset" (charset):
+ This operation attribute identifies the charset used by any
+ 'text' and 'name' attributes that the Printer object is
+ returning in this response. The value in this response MUST be
+ the same value as the "attributes-charset" operation attribute
+ supplied by the client in the request. If this is not possible
+ (i.e., the charset requested is not supported), the request
+ would have been rejected. See "attributes-charset" described
+ in Section 3.1.4.1 above.
+
+ If the Printer object supports more than just the 'utf-8'
+ charset, the Printer object MUST be able to code convert
+ between each of the charsets supported on a highest fidelity
+ possible basis in order to return the 'text' and 'name'
+ attributes in the charset requested by the client. However,
+ some information loss MAY occur during the charset conversion
+ depending on the charsets involved. For example, the Printer
+ object may convert from a UTF-8 'a' to a US-ASCII 'a' (with no
+ loss of information), from an ISO Latin 1 CAPITAL LETTER A WITH
+ ACUTE ACCENT to US-ASCII 'A' (losing the accent), or from a
+ UTF-8 Japanese Kanji character to some ISO Latin 1 error
+ character indication such as '?', decimal code equivalent, or
+ to the absence of a character, depending on implementation.
+
+ Whether an implementation that supports more than one charset
+ stores the data in the charset supplied by the client or code
+ converts to one of the other supported charsets, depends on
+ implementation. The strategy should try to minimize loss of
+ information during code conversion. On each response, such an
+ implementation converts from its internal charset to that
+ requested.
+
+ "attributes-natural-language" (naturalLanguage):
+ This operation attribute identifies the natural language used
+ by any 'text' and 'name' attributes that the IPP object is
+ returning in this response. Unlike the "attributes-charset"
+ operation attribute, the IPP object NEED NOT return the same
+
+
+
+Hastings, et al. Standards Track [Page 29]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ value as that supplied by the client in the request. The IPP
+ object MAY return the natural language of the Job object or the
+ Printer's configured natural language as identified by the
+ Printer object's "natural-language-configured" attribute,
+ rather than the natural language supplied by the client. For
+ any 'text' or 'name' attribute or status message in the
+ response that is in a different natural language than the value
+ returned in the "attributes-natural-language" operation
+ attribute, the IPP object MUST use the Natural Language
+ Override mechanism (see sections 4.1.1.2 and 4.1.2.2) on each
+ attribute value returned. The IPP object MAY use the Natural
+ Language Override mechanism redundantly, i.e., use it even when
+ the value is in the same natural language as the value supplied
+ in the "attributes-natural-language" operation attribute of the
+ response.
+
+3.1.5 Operation Targets
+
+ All IPP operations are directed at IPP objects. For Printer
+ operations, the operation is always directed at a Printer object
+ using one of its URIs (i.e., one of the values in the Printer
+ object's "printer-uri-supported" attribute). Even if the Printer
+ object supports more than one URI, the client supplies only one URI
+ as the target of the operation. The client identifies the target
+ object by supplying the correct URI in the "printer-uri (uri)"
+ operation attribute.
+
+ For Job operations, the operation is directed at either:
+
+ - The Job object itself using the Job object's URI. In this case,
+ the client identifies the target object by supplying the correct
+ URI in the "job-uri (uri)" operation attribute.
+ - The Printer object that created the Job object using both the
+ Printer objects URI and the Job object's Job ID. Since the
+ Printer object that created the Job object generated the Job ID,
+ it MUST be able to correctly associate the client supplied Job
+ ID with the correct Job object. The client supplies the Printer
+ object's URI in the "printer-uri (uri)" operation attribute and
+ the Job object's Job ID in the "job-id (integer(1:MAX))"
+ operation attribute.
+
+ If the operation is directed at the Job object directly using the Job
+ object's URI, the client MUST NOT include the redundant "job-id"
+ operation attribute.
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 30]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ The operation target attributes are REQUIRED operation attributes
+ that MUST be included in every operation request. Like the charset
+ and natural language attributes (see section 3.1.4), the operation
+ target attributes are specially ordered operation attributes. In all
+ cases, the operation target attributes immediately follow the
+ "attributes-charset" and "attributes-natural-language" attributes
+ within the operation attribute group, however the specific ordering
+ rules are:
+
+ - In the case where there is only one operation target attribute
+ (i.e., either only the "printer-uri" attribute or only the
+ "job-uri" attribute), that attribute MUST be the third attribute
+ in the operation attributes group.
+ - In the case where Job operations use two operation target
+ attributes (i.e., the "printer-uri" and "job-id" attributes),
+ the "printer-uri" attribute MUST be the third attribute and the
+ "job-id" attribute MUST be the fourth attribute.
+
+ In all cases, the target URIs contained within the body of IPP
+ operation requests and responses must be in absolute format rather
+ than relative format (a relative URL identifies a resource with the
+ scope of the HTTP server, but does not include scheme, host or port).
+
+ The following rules apply to the use of port numbers in URIs that
+ identify IPP objects:
+
+ 1. If the URI scheme allows the port number to be explicitly
+ included in the URI string, and a port number is specified
+ within the URI, then that port number MUST be used by the
+ client to contact the IPP object.
+
+ 2. If the URI scheme allows the port number to be explicitly
+ included in the URI string, and a port number is not specified
+ within the URI, then default port number implied by that URI
+ scheme MUST be used by the client to contact the IPP object.
+
+ 3. If the URI scheme does not allow an explicit port number to be
+ specified within the URI, then the default port number implied
+ by that URI MUST be used by the client to contact the IPP
+ object.
+
+ Note: The IPP "Encoding and Transport document [RFC2910] shows a
+ mapping of IPP onto HTTP/1.1 [RFC2616] and defines a new default port
+ number for using IPP over HTTP/1.1.
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 31]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+3.1.6 Operation Response Status Codes and Status Messages
+
+ Every operation response includes a REQUIRED "status-code" parameter
+ and an OPTIONAL "status-message" operation attribute, and an OPTIONAL
+ "detailed-status-message" operation attribute. The Print-URI and
+ Send-URI response MAY include an OPTIONAL "document-access-error"
+ operation attribute.
+
+3.1.6.1 "status-code" (type2 enum)
+
+ The REQUIRED "status-code" parameter provides information on the
+ processing of a request.
+
+ The status code is intended for use by automata. A client
+ implementation of IPP SHOULD convert status code values into any
+ localized message that has semantic meaning to the end user.
+
+ The "status-code" value is a numeric value that has semantic meaning.
+ The "status-code" syntax is similar to a "type2 enum" (see section
+ 4.1 on "Attribute Syntaxes") except that values can range only from
+ 0x0000 to 0x7FFF. Section 13 describes the status codes, assigns the
+ numeric values, and suggests a corresponding status message for each
+ status code for use by the client when the user's natural language is
+ English.
+
+ If the Printer performs an operation with no errors and it encounters
+ no problems, it MUST return the status code 'successful-ok' in the
+ response. See section 13.
+
+ If the client supplies unsupported values for the following
+ parameters or Operation attributes, the Printer object MUST reject
+ the operation, NEED NOT return the unsupported attribute value in the
+ Unsupported Attributes group, and MUST return the indicated status
+ code:
+
+ Parameter/Attribute Status code
+
+ version-number server-error-version-not-supported
+ operation-id server-error-operation-not-supported
+ attributes-charset client-error-charset-not-supported
+ compression client-error-compression-not-supported
+ document-format client-error-document-format-not-supported
+ document-uri client-error-uri-scheme-not-supported,
+ client-error-document-access-error
+
+ If the client supplies unsupported values for other attributes, or
+ unsupported attributes, the Printer returns the status code defined
+ in section 3.1.7 on Unsupported Attributes.
+
+
+
+Hastings, et al. Standards Track [Page 32]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+3.1.6.2 "status-message" (text(255))
+
+ The OPTIONAL "status-message" operation attribute provides a short
+ textual description of the status of the operation. The "status-
+ message" attribute's syntax is "text(255)", so the maximum length is
+ 255 octets (see section 4.1.1). The status message is intended for
+ the human end user. If a response does include a "status-message"
+ attribute, an IPP client NEED NOT examine or display the messages,
+ however it SHOULD do so in some implementation specific manner. The
+ "status-message" is especially useful for a later version of a
+ Printer object to return as supplemental information for the human
+ user to accompany a status code that an earlier version of a client
+ might not understand.
+
+ If the Printer object supports the "status-message" operation
+ attribute, the Printer object MUST be able to generate this message
+ in any of the natural languages identified by the Printer object's
+ "generated-natural-language-supported" attribute (see the
+ "attributes-natural-language" operation attribute specified in
+ section 3.1.4.1. Section 13 suggests the text for the status message
+ returned by the Printer for use with the English natural language.
+
+ As described in section 3.1.4.1 for any returned 'text' attribute, if
+ there is a choice for generating this message, the Printer object
+ uses the natural language indicated by the value of the "attributes-
+ natural-language" in the client request if supported, otherwise the
+ Printer object uses the value in the Printer object's own "natural-
+ language-configured" attribute.
+
+ If the Printer object supports the "status-message" operation
+ attribute, it SHOULD use the REQUIRED 'utf-8' charset to return a
+ status message for the following error status codes (see section 13):
+ 'client-error-bad-request', 'client-error-charset-not-supported',
+ 'server-error-internal-error', 'server-error-operation-not-
+ supported', and 'server-error-version-not-supported'. In this case,
+ it MUST set the value of the "attributes-charset" operation attribute
+ to 'utf-8' in the error response.
+
+3.1.6.3 "detailed-status-message" (text(MAX))
+
+ The OPTIONAL "detailed-status-message" operation attribute provides
+ additional more detailed technical and implementation-specific
+ information about the operation. The "detailed-status-message"
+ attribute's syntax is "text(MAX)", so the maximum length is 1023
+ octets (see section 4.1.1). If the Printer objects supports the
+ "detailed-status-message" operation attribute, the Printer NEED NOT
+ localize the message, since it is intended for use by the system
+ administrator or other experienced technical persons. Localization
+
+
+
+Hastings, et al. Standards Track [Page 33]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ might obscure the technical meaning of such messages. Clients MUST
+ NOT attempt to parse the value of this attribute. See the
+ "document-access-error" operation attribute (section 3.1.6.4) for
+ additional errors that a program can process.
+
+3.1.6.4 "document-access-error" (text(MAX))
+
+ This OPTIONAL operation attribute provides additional information
+ about any document access errors encountered by the Printer before it
+ returned a response to the Print-URI (section 3.2.2) or Send-URI
+ (section 3.3.1) operation. For errors in the protocol identified by
+ the URI scheme in the "document-uri" operation attribute, such as
+ 'http:' or 'ftp:', the error code is returned in parentheses,
+ followed by the URI. For example:
+
+ (404) http://ftp.pwg.org/pub/pwg/ipp/new_MOD/ipp-model-v11.pdf
+
+ Most Internet protocols use decimal error codes (unlike IPP), so the
+ ASCII error code representation is in decimal.
+
+3.1.7 Unsupported Attributes
+
+ The Unsupported Attributes group contains attributes that are not
+ supported by the operation. This group is primarily for the job
+ creation operations, but all operations can return this group.
+
+ A Printer object MUST include an Unsupported Attributes group in a
+ response if the status code is one of the following: 'successful-
+ ok-ignored-or-substituted-attributes', 'successful-ok-conflicting-
+ attributes', 'client-error-attributes-or-values-not-supported' or
+ 'client-error-conflicting-attributes'.
+
+ If the status code is one of the four specified in the preceding
+ paragraph, the Unsupported Attributes group MUST contain all of those
+ attributes and only those attributes that are:
+
+ a. an Operation or Job Template attribute supplied in the request,
+ and
+
+ b. unsupported by the printer. See below for details on the three
+ categories "unsupported" attributes.
+
+ If the status code is one of those in the table in section 3.1.6.1,
+ the Unsupported Attributes group NEED NOT contain the unsupported
+ parameter or attribute indicated in that table.
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 34]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ If the Printer object is not returning any Unsupported Attributes in
+ the response, the Printer object SHOULD omit Group 2 rather than
+ sending an empty group. However, a client MUST be able to accept an
+ empty group.
+
+ Unsupported attributes fall into three categories:
+
+ 1. The Printer object does not support the supplied attribute (no
+ matter what the attribute syntax or value).
+
+ 2. The Printer object does support the attribute, but does not
+ support some or all of the particular attribute syntaxes or
+ values supplied by the client (i.e., the Printer object does
+ not have those attribute syntaxes or values in its
+ corresponding "xxx-supported" attribute).
+
+ 3. The Printer object does support the attributes and values
+ supplied, but the particular values are in conflict with one
+ another, because they violate a constraint, such as not being
+ able to staple transparencies.
+
+ In the case of an unsupported attribute name, the Printer object
+ returns the client-supplied attribute with a substituted value of
+ 'unsupported'. This value's syntax type is "out-of-band" and its
+ encoding is defined by special rules for "out-of-band" values in the
+ "Encoding and Transport" document [RFC2910]. Its value indicates no
+ support for the attribute itself (see the beginning of section 4.1).
+
+ In the case of a supported attribute with one or more unsupported
+ attribute syntaxes or values, the Printer object simply returns the
+ client-supplied attribute with the unsupported attribute syntaxes or
+ values as supplied by the client. This indicates support for the
+ attribute, but no support for that particular attribute syntax or
+ value. If the client supplies a multi-valued attribute with more
+ than one value and the Printer object supports the attribute but only
+ supports a subset of the client-supplied attribute syntaxes or
+ values, the Printer object
+
+ MUST return only those attribute syntaxes or values that are
+ unsupported.
+
+ In the case of two (or more) supported attribute values that are in
+ conflict with one another (although each is supported independently,
+ the values conflict when requested together within the same job), the
+ Printer object MUST return all the values that it ignores or
+ substitutes to resolve the conflict, but not any of the values that
+
+
+
+
+
+Hastings, et al. Standards Track [Page 35]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ it is still using. The choice for exactly how to resolve the
+ conflict is implementation dependent. See sections 3.2.1.2 and 15.
+ See The Implementer's Guide [IPP-IIG] for an example.
+
+3.1.8 Versions
+
+ Each operation request and response carries with it a "version-
+ number" parameter. Each value of the "version-number" is in the form
+ "X.Y" where X is the major version number and Y is the minor version
+ number. By including a version number in the client request, it
+ allows the client to identify which version of IPP it is interested
+ in using, i.e., the version whose conformance requirements the client
+ may be depending upon the Printer to meet.
+
+ If the IPP object does not support that major version number supplied
+ by the client, i.e., the major version field of the "version-number"
+ parameter does not match any of the values of the Printer's "ipp-
+ versions-supported" (see section 4.4.14), the object MUST respond
+ with a status code of 'server-error-version-not-supported' along with
+ the closest version number that is supported (see section 13.1.5.4).
+ If the major version number is supported, but the minor version
+ number is not, the IPP object SHOULD accept and attempt to perform
+ the request (or reject the request if the operation is not
+ supported), else it rejects the request and returns the 'server-
+ error-version-not-supported' status code. In all cases, the IPP
+ object MUST return the "version-number" that it supports that is
+ closest to the version number supplied by the client in the request.
+
+ There is no version negotiation per se. However, if after receiving
+ a 'server-error-version-not-supported' status code from an IPP
+ object, a client SHOULD try again with a different version number. A
+ client MAY also determine the versions supported either from a
+ directory that conforms to Appendix E (see section 16) or by querying
+ the Printer object's "ipp-versions-supported" attribute (see section
+ 4.4.14) to determine which versions are supported.
+
+ An IPP object implementation MUST support version '1.1', i.e., meet
+ the conformance requirements for IPP/1.1 as specified in this
+ document and [RFC2910]. It is recommended that IPP object
+ implementations accept any request with the major version '1' (or
+ reject the request if the operation is not supported).
+
+ There is only one notion of "version number" that covers both IPP
+ Model and IPP Protocol changes. Thus the version number MUST change
+ when introducing a new version of the Model and Semantics document
+ (this document) or a new version of the "Encoding and Transport"
+ document [RFC2910].
+
+
+
+
+Hastings, et al. Standards Track [Page 36]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Changes to the major version number of the Model and Semantics
+ document indicate structural or syntactic changes that make it
+ impossible for older version of IPP clients and Printer objects to
+ correctly parse and correctly process the new or changed attributes,
+ operations and responses. If the major version number changes, the
+ minor version numbers is set to zero. As an example, adding the
+ REQUIRED "ipp-attribute-fidelity" attribute to version '1.1' (if it
+ had not been part of version '1.0'), would have required a change to
+ the major version number, since an IPP/1.0 Printer would not have
+ processed a request with the correct semantics that contained the
+ "ipp-attribute-fidelity" attribute that it did not know about. Items
+ that might affect the changing of the major version number include
+ any changes to the Model and Semantics document (this document) or
+ the "Encoding and Transport" document [RFC2910] itself, such as:
+
+ - reordering of ordered attributes or attribute sets
+ - changes to the syntax of existing attributes
+ - adding REQUIRED (for an IPP object to support) operation
+ attribute groups
+ - adding values to existing REQUIRED operation attributes
+ - adding REQUIRED operations
+
+ Changes to the minor version number indicate the addition of new
+ features, attributes and attribute values that may not be understood
+ by all IPP objects, but which can be ignored if not understood.
+ Items that might affect the changing of the minor version number
+ include any changes to the model objects and attributes but not the
+ encoding and transport rules [RFC2910] (except adding attribute
+ syntaxes). Examples of such changes are:
+
+ - grouping all extensions not included in a previous version into
+ a new version
+ - adding new attribute values
+ - adding new object attributes
+ - adding OPTIONAL (for an IPP object to support) operation
+ attributes (i.e., those attributes that an IPP object can ignore
+ without confusing clients)
+ - adding OPTIONAL (for an IPP object to support) operation
+ attribute groups (i.e., those attributes that an IPP object can
+ ignore without confusing clients)
+ - adding new attribute syntaxes
+ - adding OPTIONAL operations
+ - changing Job Description attributes or Printer Description
+ attributes from OPTIONAL to REQUIRED or vice versa.
+ - adding OPTIONAL attribute syntaxes to an existing attribute.
+
+ The encoding of the "version-number" MUST NOT change over any version
+ number (either major or minor). This rule guarantees that all future
+
+
+
+Hastings, et al. Standards Track [Page 37]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ versions will be backwards compatible with all previous versions (at
+ least for checking the "version-number"). In addition, any protocol
+ elements (attributes, error codes, tags, etc.) that are not carried
+ forward from one version to the next are deprecated so that they can
+ never be reused with new semantics.
+
+ Implementations that support a certain version NEED NOT support ALL
+ previous versions. As each new version is defined (through the
+ release of a new IPP specification document), that version will
+ specify which previous versions MUST and which versions SHOULD be
+ supported in compliant implementations.
+
+3.1.9 Job Creation Operations
+
+ In order to "submit a print job" and create a new Job object, a
+ client issues a create request. A create request is any one of
+ following three operation requests:
+
+ - The Print-Job Request: A client that wants to submit a print job
+ with only a single document uses the Print-Job operation. The
+ operation allows for the client to "push" the document data to
+ the Printer object by including the document data in the request
+ itself.
+
+ - The Print-URI Request: A client that wants to submit a print job
+ with only a single document (where the Printer object "pulls"
+ the document data instead of the client "pushing" the data to
+ the Printer object) uses the Print-URI operation. In this
+ case, the client includes in the request only a URI reference to
+ the document data (not the document data itself).
+
+ - The Create-Job Request: A client that wants to submit a print
+ job with multiple documents uses the Create-Job operation. This
+ operation is followed by an arbitrary number (one or more) of
+ Send-Document and/or Send-URI operations (each creating another
+ document for the newly create Job object). The Send-Document
+ operation includes the document data in the request (the client
+ "pushes" the document data to the printer), and the Send-URI
+ operation includes only a URI reference to the document data in
+ the request (the Printer "pulls" the document data from the
+ referenced location). The last Send-Document or Send-URI
+ request for a given Job object includes a "last-document"
+ operation attribute set to 'true' indicating that this is the
+ last request.
+
+ Throughout this model document, the term "create request" is used to
+ refer to any of these three operation requests.
+
+
+
+
+Hastings, et al. Standards Track [Page 38]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ A Create-Job operation followed by only one Send-Document operation
+ is semantically equivalent to a Print-Job operation, however, for
+ performance reasons, the client SHOULD use the Print-Job operation
+ for all single document jobs. Also, Print-Job is a REQUIRED
+ operation (all implementations MUST support it) whereas Create-Job is
+ an OPTIONAL operation, hence some implementations might not support
+ it.
+
+ Job submission time is the point in time when a client issues a
+ create request. The initial state of every Job object is the
+ 'pending', 'pending-held', or 'processing' state (see section 4.3.7).
+ When the Printer object begins processing the print job, the Job
+ object's state moves to 'processing'. This is known as job
+ processing time. There are validation checks that must be done at
+ job submission time and others that must be performed at job
+ processing time.
+
+ At job submission time and at the time a Validate-Job operation is
+ received, the Printer MUST do the following:
+
+ 1. Process the client supplied attributes and either accept or
+ reject the request
+ 2. Validate the syntax of and support for the scheme of any client
+ supplied URI
+
+ At job submission time the Printer object MUST validate whether or
+ not the supplied attributes, attribute syntaxes, and values are
+ supported by matching them with the Printer object's corresponding
+ "xxx-supported" attributes. See section 3.1.7 for details. [IPP-
+ IIG] presents suggested steps for an IPP object to either accept or
+ reject any request and additional steps for processing create
+ requests.
+
+ At job submission time the Printer object NEED NOT perform the
+ validation checks reserved for job processing time such as:
+
+ 1. Validating the document data
+ 2. Validating the actual contents of any client supplied URI
+ (resolve the reference and follow the link to the document
+ data)
+
+ At job submission time, these additional job processing time
+ validation checks are essentially useless, since they require
+ actually parsing and interpreting the document data, are not
+ guaranteed to be 100% accurate, and MUST be done, yet again, at job
+ processing time. Also, in the case of a URI, checking for
+ availability at job submission time does not guarantee availability
+
+
+
+
+Hastings, et al. Standards Track [Page 39]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ at job processing time. In addition, at job processing time, the
+ Printer object might discover any of the following conditions that
+ were not detectable at job submission time:
+
+ - runtime errors in the document data,
+ - nested document data that is in an unsupported format,
+ - the URI reference is no longer valid (i.e., the server hosting
+ the document might be down), or
+ - any other job processing error
+
+ At job submission time, a Printer object, especially a non-spooling
+ Printer, MAY accept jobs that it does not have enough space for. In
+ such a situation, a Printer object MAY stop reading data from a
+ client for an indefinite period of time. A client MUST be prepared
+ for a write operation to block for an indefinite period of time (see
+ section 5.1 on client conformance).
+
+ When a Printer object has too little space for starting a new job, it
+ MAY reject a new create request. In this case, a Printer object MUST
+ return a response (in reply to the rejected request) with a status-
+ code of 'server-error-busy' (see section 14.1.5.8) and it MAY close
+ the connection before receiving all bytes of the operation. A
+ Printer SHOULD indicate that it is temporarily unable to accept jobs
+ by setting the 'spool-space-full' value in its "printer-state-
+ reasons" attribute and removing the value when it can accept another
+ job (see section 4.4.12).
+
+ When receiving a 'server-error-busy' status-code in an operation
+ response, a client MUST be prepared for the Printer object to close
+ the connection before the client has sent all of the data (especially
+ for the Print-Job operation). A client MUST be prepared to keep
+ submitting a create request until the IPP Printer object accepts the
+ create request.
+
+ At job processing time, since the Printer object has already
+ responded with a successful status code in the response to the create
+ request, if the Printer object detects an error, the Printer object
+ is unable to inform the end user of the error with an operation
+ status code. In this case, the Printer, depending on the error, can
+ set the job object's "job-state", "job-state-reasons", or "job-
+ state-message" attributes to the appropriate value(s) so that later
+ queries can report the correct job status.
+
+ Note: Asynchronous notification of events is outside the scope of
+ this IPP/1.1 document.
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 40]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+3.2 Printer Operations
+
+ All Printer operations are directed at Printer objects. A client
+ MUST always supply the "printer-uri" operation attribute in order to
+ identify the correct target of the operation.
+
+3.2.1 Print-Job Operation
+
+ This REQUIRED operation allows a client to submit a print job with
+ only one document and supply the document data (rather than just a
+ reference to the data). See Section 15 for the suggested steps for
+ processing create operations and their Operation and Job Template
+ attributes.
+
+3.2.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. The Printer object
+ MUST copy these values to the corresponding Job Description
+ attributes described in sections 4.3.19 and 4.3.20.
+
+ Target:
+ The "printer-uri" (uri) operation attribute which is the target
+ for this operation as described in section 3.1.5.
+
+ Requesting User Name:
+ The "requesting-user-name" (name(MAX)) attribute SHOULD be
+ supplied by the client as described in section 8.3.
+
+ "job-name" (name(MAX)):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object MUST support this attribute. It contains the client
+ supplied Job name. If this attribute is supplied by the
+ client, its value is used for the "job-name" attribute of the
+ newly created Job object. The client MAY automatically include
+ any information that will help the end-user distinguish amongst
+ his/her jobs, such as the name of the application program along
+ with information from the document, such as the document name,
+ document subject, or source file name. If this attribute is
+ not supplied by the client, the Printer generates a name to use
+ in the "job-name" attribute of the newly created Job object
+ (see Section 4.3.5).
+
+
+
+Hastings, et al. Standards Track [Page 41]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ "ipp-attribute-fidelity" (boolean):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object MUST support this attribute. The value 'true' indicates
+ that total fidelity to client supplied Job Template attributes
+ and values is required, else the Printer object MUST reject the
+ Print-Job request. The value 'false' indicates that a
+ reasonable attempt to print the Job object is acceptable and
+ the Printer object MUST accept the Print-Job request. If not
+ supplied, the Printer object assumes the value is 'false'. All
+ Printer objects MUST support both types of job processing. See
+ section 15 for a full description of "ipp-attribute-fidelity"
+ and its relationship to other attributes, especially the
+ Printer object's "pdl-override-supported" attribute.
+
+ "document-name" (name(MAX)):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object MUST support this attribute. It contains the client
+ supplied document name. The document name MAY be different
+ than the Job name. Typically, the client software
+ automatically supplies the document name on behalf of the end
+ user by using a file name or an application generated name. If
+ this attribute is supplied, its value can be used in a manner
+ defined by each implementation. Examples include: printed
+ along with the Job (job start sheet, page adornments, etc.),
+ used by accounting or resource tracking management tools, or
+ even stored along with the document as a document level
+ attribute. IPP/1.1 does not support the concept of document
+ level attributes.
+
+ "compression" (type3 keyword):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object MUST support this attribute and the "compression-
+ supported" attribute (see section 4.4.32). The client supplied
+ "compression" operation attribute identifies the compression
+ algorithm used on the document data. The following cases exist:
+
+ a) If the client omits this attribute, the Printer object MUST
+ assume that the data is not compressed (i.e. the Printer
+ follows the rules below as if the client supplied the
+ "compression" attribute with a value of 'none').
+ b) If the client supplies this attribute, but the value is not
+ supported by the Printer object, i.e., the value is not one
+ of the values of the Printer object's "compression-
+ supported" attribute, the Printer object MUST reject the
+ request, and return the 'client-error-compression-not-
+ supported' status code. See section 3.1.7 for returning
+ unsupported attributes and values.
+
+
+
+
+Hastings, et al. Standards Track [Page 42]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ c) If the client supplies the attribute and the Printer object
+ supports the attribute value, the Printer object uses the
+ corresponding decompression algorithm on the document data.
+ d) If the decompression algorithm fails before the Printer
+ returns an operation response, the Printer object MUST
+ reject the request and return the 'client-error-
+ compression-error' status code.
+ e) If the decompression algorithm fails after the Printer
+ returns an operation response, the Printer object MUST abort
+ the job and add the 'compression-error' value to the job's
+ "job-state-reasons" attribute.
+ f) If the decompression algorithm succeeds, the document data
+ MUST then have the format specified by the job's "document-
+ format" attribute, if supplied (see "document-format"
+ operation attribute definition below).
+
+ "document-format" (mimeMediaType):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object MUST support this attribute. The value of this
+ attribute identifies the format of the supplied document data.
+ The following cases exist:
+
+ a) If the client does not supply this attribute, the Printer
+ object assumes that the document data is in the format
+ defined by the Printer object's "document-format-default"
+ attribute. (i.e. the Printer follows the rules below as if
+ the client supplied the "document-format" attribute with a
+ value equal to the printer's default value).
+ b) If the client supplies this attribute, but the value is not
+ supported by the Printer object, i.e., the value is not one
+ of the values of the Printer object's "document-format-
+ supported" attribute, the Printer object MUST reject the
+ request and return the 'client-error-document-format-not-
+ supported' status code.
+ c) If the client supplies this attribute and its value is
+ 'application/octet-stream' (i.e. to be auto-sensed, see
+ Section 4.1.9.1), and the format is not one of the
+ document-formats that the Printer can auto-sense, and this
+ check occurs before the Printer returns an operation
+ response, then the Printer MUST reject the request and
+ return the 'client-error-document-format-not-supported'
+ status code.
+ d) If the client supplies this attribute, and the value is
+ supported by the Printer object, the Printer is capable of
+ interpreting the document data.
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 43]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ e) If interpreting of the document data fails before the
+ Printer returns an operation response, the Printer object
+ MUST reject the request and return the 'client-error-
+ document-format-error' status code.
+ f) If interpreting of the document data fails after the Printer
+ returns an operation response, the Printer object MUST abort
+ the job and add the 'document-format-error' value to the
+ job's "job-state-reasons" attribute.
+
+ "document-natural-language" (naturalLanguage):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object OPTIONALLY supports this attribute. This attribute
+ specifies the natural language of the document for those
+ document-formats that require a specification of the natural
+ language in order to image the document unambiguously. There
+ are no particular values required for the Printer object to
+ support.
+
+ "job-k-octets" (integer(0:MAX)):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object OPTIONALLY supports this attribute and the "job-k-
+ octets-supported" attribute (see section 4.4.33). The client
+ supplied "job-k-octets" operation attribute identifies the
+ total size of the document(s) in K octets being submitted (see
+ section 4.3.17.1 for the complete semantics). If the client
+ supplies the attribute and the Printer object supports the
+ attribute, the value of the attribute is used to populate the
+ Job object's "job-k-octets" Job Description attribute.
+
+ For this attribute and the following two attributes ("job-
+ impressions", and "job-media-sheets"), if the client supplies
+ the attribute, but the Printer object does not support the
+ attribute, the Printer object ignores the client-supplied
+ value. If the client supplies the attribute and the Printer
+ supports the attribute, and the value is within the range of
+ the corresponding Printer object's "xxx-supported" attribute,
+ the Printer object MUST use the value to populate the Job
+ object's "xxx" attribute. If the client supplies the attribute
+ and the Printer supports the attribute, but the value is
+ outside the range of the corresponding Printer object's "xxx-
+ supported" attribute, the Printer object MUST copy the
+ attribute and its value to the Unsupported Attributes response
+ group, reject the request, and return the 'client-error-
+ attributes-or-values-not-supported' status code. If the client
+ does not supply the attribute, the Printer object MAY choose to
+ populate the corresponding Job object attribute depending on
+ whether the Printer object supports the attribute and is able
+ to calculate or discern the correct value.
+
+
+
+Hastings, et al. Standards Track [Page 44]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ "job-impressions" (integer(0:MAX)):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object OPTIONALLY supports this attribute and the "job-
+ impressions-supported" attribute (see section 4.4.34). The
+ client supplied "job-impressions" operation attribute
+ identifies the total size in number of impressions of the
+ document(s) being submitted (see section 4.3.17.2 for the
+ complete semantics).
+
+ See last paragraph under "job-k-octets".
+
+ "job-media-sheets" (integer(0:MAX)):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object OPTIONALLY supports this attribute and the "job-media-
+ sheets-supported" attribute (see section 4.4.35). The client
+ supplied "job-media-sheets" operation attribute identifies the
+ total number of media sheets to be produced for this job (see
+ section 4.3.17.3 for the complete semantics).
+
+ See last paragraph under "job-k-octets".
+
+ Group 2: Job Template Attributes
+
+ The client OPTIONALLY supplies a set of Job Template attributes as
+ defined in section 4.2. If the client is not supplying any Job
+ Template attributes in the request, the client SHOULD omit Group 2
+ rather than sending an empty group. However, a Printer object
+ MUST be able to accept an empty group.
+
+ Group 3: Document Content
+
+ The client MUST supply the document data to be processed.
+
+ In addition to the MANDATORY parameters required for every
+ operation request, the simplest Print-Job Request consists of just
+ the "attributes-charset" and "attributes-natural-language"
+ operation attributes; the "printer-uri" target operation
+ attribute; the Document Content and nothing else. In this simple
+ case, the Printer object:
+
+ - creates a new Job object (the Job object contains a single
+ document),
+ - stores a generated Job name in the "job-name" attribute in the
+ natural language and charset requested (see Section 3.1.4.1) (if
+ those are supported, otherwise using the Printer object's
+ default natural language and charset), and
+
+
+
+
+
+Hastings, et al. Standards Track [Page 45]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ - at job processing time, uses its corresponding default value
+ attributes for the supported Job Template attributes that were
+ not supplied by the client as IPP attribute or embedded
+ instructions in the document data.
+
+3.2.1.2 Print-Job Response
+
+ The Printer object MUST return to the client the following sets of
+ attributes as part of the Print-Job Response:
+
+ Group 1: Operation Attributes
+
+ Status Message:
+ In addition to the REQUIRED status code returned in every
+ response, the response OPTIONALLY includes a "status-message"
+ (text(255)) and/or a "detailed-status-message" (text(MAX))
+ operation attribute as described in sections 13 and 3.1.6. If
+ the client supplies unsupported or conflicting Job Template
+ attributes or values, the Printer object MUST reject or accept
+ the Print-Job request depending on the whether the client
+ supplied a 'true' or 'false' value for the "ipp-attribute-
+ fidelity" operation attribute. See the Implementer's Guide
+ [IPP-IIG] for a complete description of the suggested steps for
+ processing a create request.
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2.
+
+ Group 2: Unsupported Attributes
+
+ See section 3.1.7 for details on returning Unsupported Attributes.
+
+ The value of the "ipp-attribute-fidelity" supplied by the client
+ does not affect what attributes the Printer object returns in this
+ group. The value of "ipp-attribute-fidelity" only affects whether
+ the Print-Job operation is accepted or rejected. If the job is
+ accepted, the client may query the job using the Get-Job-
+ Attributes operation requesting the unsupported attributes that
+ were returned in the create response to see which attributes were
+ ignored (not stored on the Job object) and which attributes were
+ stored with other (substituted) values.
+
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 46]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Group 3: Job Object Attributes
+
+ "job-uri" (uri):
+ The Printer object MUST return the Job object's URI by
+ returning the contents of the REQUIRED "job-uri" Job object
+ attribute. The client uses the Job object's URI when directing
+ operations at the Job object. The Printer object always uses
+ its configured security policy when creating the new URI.
+ However, if the Printer object supports more than one URI, the
+ Printer object also uses information about which URI was used
+ in the Print-Job Request to generated the new URI so that the
+ new URI references the correct access channel. In other words,
+ if the Print-Job Request comes in over a secure channel, the
+ Printer object MUST generate a Job URI that uses the secure
+ channel as well.
+
+ "job-id" (integer(1:MAX)):
+ The Printer object MUST return the Job object's Job ID by
+ returning the REQUIRED "job-id" Job object attribute. The
+ client uses this "job-id" attribute in conjunction with the
+ "printer-uri" attribute used in the Print-Job Request when
+ directing Job operations at the Printer object.
+
+ "job-state" (type1 enum):
+ The Printer object MUST return the Job object's REQUIRED "job-
+ state" attribute. The value of this attribute (along with the
+ value of the next attribute: "job-state-reasons") is taken
+ from a "snapshot" of the new Job object at some meaningful
+ point in time (implementation defined) between when the Printer
+ object receives the Print-Job Request and when the Printer
+ object returns the response.
+
+ "job-state-reasons" (1setOf type2 keyword):
+ The Printer object MUST return the Job object's REQUIRED "job-
+ state-reasons" attribute.
+
+ "job-state-message" (text(MAX)):
+ The Printer object OPTIONALLY returns the Job object's OPTIONAL
+ "job-state-message" attribute. If the Printer object supports
+ this attribute then it MUST be returned in the response. If
+ this attribute is not returned in the response, the client can
+ assume that the "job-state-message" attribute is not supported
+ and will not be returned in a subsequent Job object query.
+
+ "number-of-intervening-jobs" (integer(0:MAX)):
+ The Printer object OPTIONALLY returns the Job object's OPTIONAL
+ "number-of-intervening-jobs" attribute. If the Printer object
+ supports this attribute then it MUST be returned in the
+
+
+
+Hastings, et al. Standards Track [Page 47]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ response. If this attribute is not returned in the response,
+ the client can assume that the "number-of-intervening-jobs"
+ attribute is not supported and will not be returned in a
+ subsequent Job object query.
+
+ Note: Since any printer state information which affects a job's
+ state is reflected in the "job-state" and "job-state-reasons"
+ attributes, it is sufficient to return only these attributes
+ and no specific printer status attributes.
+
+ Note: In addition to the MANDATORY parameters required for every
+ operation response, the simplest response consists of the just the
+ "attributes-charset" and "attributes-natural-language" operation
+ attributes and the "job-uri", "job-id", and "job-state" Job Object
+ Attributes. In this simplest case, the status code is 'successful-
+ ok' and there is no "status-message" or "detailed-status-message"
+ operation attribute.
+
+3.2.2 Print-URI Operation
+
+ This OPTIONAL operation is identical to the Print-Job operation
+ (section 3.2.1) except that a client supplies a URI reference to the
+ document data using the "document-uri" (uri) operation attribute (in
+ Group 1) rather than including the document data itself. Before
+ returning the response, the Printer MUST validate that the Printer
+ supports the retrieval method (e.g., http, ftp, etc.) implied by the
+ URI, and MUST check for valid URI syntax. If the client-supplied URI
+ scheme is not supported, i.e. the value is not in the Printer
+ object's "referenced-uri-scheme-supported" attribute, the Printer
+ object MUST reject the request and return the 'client-error-uri-
+ scheme-not-supported' status code.
+
+ The IPP Printer MAY validate the accessibility of the document as
+ part of the operation or subsequently. If the Printer determines an
+ accessibility problem before returning an operation response, it
+ rejects the request and returns the 'client-error-document-access-
+ error' status code. The Printer MAY also return a specific document
+ access error code using the "document-access-error" operation
+ attribute (see section 3.1.6.4).
+
+ If the Printer determines this document accessibility problem after
+ accepting the request and returning an operation response with one of
+ the successful status codes, the Printer adds the 'document-access-
+ error' value to the job's "job-state-reasons" attribute and MAY
+ populate the job's "job-document-access-errors" Job Description
+ attribute (see section 4.3.11). See The Implementer's Guide [IPP-
+ IIG] for suggested additional checks.
+
+
+
+
+Hastings, et al. Standards Track [Page 48]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ If the Printer object supports this operation, it MUST support the
+ "reference-uri-schemes-supported" Printer attribute (see section
+ 4.4.27).
+
+ It is up to the IPP object to interpret the URI and subsequently
+ "pull" the document from the source referenced by the URI string.
+
+3.2.3 Validate-Job Operation
+
+ This REQUIRED operation is similar to the Print-Job operation
+ (section 3.2.1) except that a client supplies no document data and
+ the Printer allocates no resources (i.e., it does not create a new
+ Job object). This operation is used only to verify capabilities of a
+ printer object against whatever attributes are supplied by the client
+ in the Validate-Job request. By using the Validate-Job operation a
+ client can validate that an identical Print-Job operation (with the
+ document data) would be accepted. The Validate-Job operation also
+ performs the same security negotiation as the Print-Job operation
+ (see section 8), so that a client can check that the client and
+ Printer object security requirements can be met before performing a
+ Print-Job operation.
+
+ The Validate-Job operation does not accept a "document-uri" attribute
+ in order to allow a client to check that the same Print-URI operation
+ will be accepted, since the client doesn't send the data with the
+ Print-URI operation. The client SHOULD just issue the Print-URI
+ request.
+
+ The Printer object returns the same status codes, Operation
+ Attributes (Group 1) and Unsupported Attributes (Group 2) as the
+ Print-Job operation. However, no Job Object Attributes (Group 3) are
+ returned, since no Job object is created.
+
+3.2.4 Create-Job Operation
+
+ This OPTIONAL operation is similar to the Print-Job operation
+ (section 3.2.1) except that in the Create-Job request, a client does
+ not supply document data or any reference to document data. Also,
+ the client does not supply any of the "document-name", "document-
+ format", "compression", or "document-natural-language" operation
+ attributes. This operation is followed by one or more Send-Document
+ or Send-URI operations. In each of those operation requests, the
+ client OPTIONALLY supplies the "document-name", "document-format",
+ and "document-natural-language" attributes for each document in the
+ multi-document Job object.
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 49]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ If a Printer object supports the Create-Job operation, it MUST also
+ support the Send-Document operation and also MAY support the Send-URI
+ operation.
+
+ If the Printer object supports this operation, it MUST support the
+ "multiple-operation-time-out" Printer attribute (see section 4.4.31).
+
+ If the Printer object supports this operation, then it MUST support
+ the "multiple-document-jobs-supported" Printer Description attribute
+ (see section 4.4.16) and indicate whether or not it supports
+ multiple-document jobs.
+
+ If the Printer object supports this operation and supports multiple
+ documents in a job, then it MUST support the "multiple-document-
+ handling" Job Template job attribute with at least one value (see
+ section 4.2.4) and the associated "multiple-document-handling-
+ default" and "multiple-document-handling-supported" Job Template
+ Printer attributes (see section 4.2).
+
+ After the Create-Job operation has completed, the value of the "job-
+ state" attribute is similar to the "job-state" after a Print-Job,
+ even though no document-data has arrived. A Printer MAY set the
+ 'job-data-insufficient' value of the job's "job-state-reason"
+ attribute to indicate that processing cannot begin until sufficient
+ data has arrived and set the "job-state" to either 'pending' or
+ 'pending-held'. A non-spooling printer that doesn't implement the
+ 'pending' job state may even set the "job-state" to 'processing',
+ even though there is not yet any data to process. See sections 4.3.7
+ and 4.3.8.
+
+3.2.5 Get-Printer-Attributes Operation
+
+ This REQUIRED operation allows a client to request the values of the
+ attributes of a Printer object. In the request, the client supplies
+ the set of Printer attribute names and/or attribute group names in
+ which the requester is interested. In the response, the Printer
+ object returns a corresponding attribute set with the appropriate
+ attribute values filled in.
+
+ For Printer objects, the possible names of attribute groups are:
+
+ - 'job-template': the subset of the Job Template attributes that
+ apply to a Printer object (the last two columns of the table in
+ Section 4.2) that the implementation supports for Printer
+ objects.
+ - 'printer-description': the subset of the attributes specified in
+ Section 4.4 that the implementation supports for Printer
+ objects.
+
+
+
+Hastings, et al. Standards Track [Page 50]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ - 'all': the special group 'all' that includes all attributes that
+ the implementation supports for Printer objects.
+
+ Since a client MAY request specific attributes or named groups, there
+ is a potential that there is some overlap. For example, if a client
+ requests, 'printer-name' and 'all', the client is actually requesting
+ the "printer-name" attribute twice: once by naming it explicitly, and
+ once by inclusion in the 'all' group. In such cases, the Printer
+ object NEED NOT return each attribute only once in the response even
+ if it is requested multiple times. The client SHOULD NOT request the
+ same attribute in multiple ways.
+
+ It is NOT REQUIRED that a Printer object support all attributes
+ belonging to a group (since some attributes are OPTIONAL). However,
+ it is REQUIRED that each Printer object support all group names.
+
+3.2.5.1 Get-Printer-Attributes Request
+
+ The following sets of attributes are part of the Get-Printer-
+ 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.
+
+ Target:
+ The "printer-uri" (uri) operation attribute which is the target
+ for this operation as described in section 3.1.5.
+
+ Requesting User Name:
+ The "requesting-user-name" (name(MAX)) attribute SHOULD be
+ supplied by the client as described in section 8.3.
+
+ "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. The Printer object MUST support this attribute.
+ If the client omits this attribute, the Printer MUST respond as
+ if this attribute had been supplied with a value of 'all'.
+
+ "document-format" (mimeMediaType):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object MUST support this attribute. This attribute is useful
+ for a Printer object to determine the set of supported
+ attribute values that relate to the requested document format.
+ The Printer object MUST return the attributes and values that
+
+
+
+Hastings, et al. Standards Track [Page 51]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ it uses to validate a job on a create or Validate-Job operation
+ in which this document format is supplied. The Printer object
+ SHOULD return only (1) those attributes that are supported for
+ the specified format and (2) the attribute values that are
+ supported for the specified document format. By specifying the
+ document format, the client can get the Printer object to
+ eliminate the attributes and values that are not supported for
+ a specific document format. For example, a Printer object
+ might have multiple interpreters to support both
+ 'application/postscript' (for PostScript) and 'text/plain' (for
+ text) documents. However, for only one of those interpreters
+ might the Printer object be able to support "number-up" with
+ values of '1', '2', and '4'. For the other interpreter it
+ might be able to only support "number-up" with a value of '1'.
+ Thus a client can use the Get-Printer-Attributes operation to
+ obtain the attributes and values that will be used to
+ accept/reject a create job operation.
+
+ If the Printer object does not distinguish between different
+ sets of supported values for each different document format
+ when validating jobs in the create and Validate-Job operations,
+ it MUST NOT distinguish between different document formats in
+ the Get-Printer-Attributes operation. If the Printer object
+ does distinguish between different sets of supported values for
+ each different document format specified by the client, this
+ specialization applies only to the following Printer object
+ attributes:
+
+ - Printer attributes that are Job Template attributes ("xxx-
+ default" "xxx-supported", and "xxx-ready" in the Table in
+ Section 4.2),
+ - "pdl-override-supported",
+ - "compression-supported",
+ - "job-k-octets-supported",
+ - "job-impressions-supported",
+ - "job-media-sheets-supported",
+ - "printer-driver-installer",
+ - "color-supported", and
+ - "reference-uri-schemes-supported"
+
+ The values of all other Printer object attributes (including
+ "document-format-supported") remain invariant with respect to the
+ client supplied document format (except for new Printer
+ description attribute as registered according to section 6.2).
+
+ If the client omits this "document-format" operation attribute,
+ the Printer object MUST respond as if the attribute had been
+ supplied with the value of the Printer object's "document-format-
+
+
+
+Hastings, et al. Standards Track [Page 52]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ default" attribute. It is RECOMMENDED that the client always
+ supply a value for "document-format", since the Printer object's
+ "document-format-default" may be 'application/octet-stream', in
+ which case the returned attributes and values are for the union of
+ the document formats that the Printer can automatically sense.
+ For more details, see the description of the 'mimeMediaType'
+ attribute syntax in section 4.1.9.
+
+ If the client supplies a value for the "document-format" Operation
+ attribute that is not supported by the Printer, i.e., is not among
+ the values of the Printer object's "document-format-supported"
+ attribute, the Printer object MUST reject the operation and return
+ the 'client-error-document-format-not-supported' status code.
+
+3.2.5.2 Get-Printer-Attributes Response
+
+ The Printer object returns the following sets of attributes as part
+ of the Get-Printer-Attributes Response:
+
+ Group 1: Operation Attributes
+
+ Status Message:
+ In addition to the REQUIRED status code returned in every
+ response, the response OPTIONALLY includes a "status-message"
+ (text(255)) and/or a "detailed-status-message" (text(MAX))
+ operation attribute as described in sections 13 and 3.1.6.
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2.
+
+ Group 2: Unsupported Attributes
+
+ See section 3.1.7 for details on returning Unsupported Attributes.
+
+ The response NEED NOT contain the "requested-attributes" operation
+ attribute with any supplied values (attribute keywords) that were
+ requested by the client but are not supported by the IPP object.
+ If the Printer object does return unsupported attributes
+ referenced in the "requested-attributes" operation attribute and
+ that attribute included group names, such as 'all', the
+ unsupported attributes MUST NOT include attributes described in
+ the standard but not supported by the implementation.
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 53]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Group 3: Printer Object Attributes
+
+ This is the set of requested attributes and their current values.
+ The Printer object ignores (does not respond with) any requested
+ attribute which is not supported. The Printer object MAY respond
+ with a subset of the supported attributes and values, depending on
+ the security policy in force. However, the Printer object MUST
+ respond with the 'unknown' value for any supported attribute
+ (including all REQUIRED attributes) for which the Printer object
+ does not know the value. Also the Printer object MUST respond
+ with the 'no-value' for any supported attribute (including all
+ REQUIRED attributes) for which the system administrator has not
+ configured a value. See the description of the "out-of-band"
+ values in the beginning of Section 4.1.
+
+3.2.6 Get-Jobs Operation
+
+ This REQUIRED operation allows a client to retrieve the list of Job
+ objects belonging to the target Printer object. The client may also
+ supply a list of Job attribute names and/or attribute group names. A
+ group of Job object attributes will be returned for each Job object
+ that is returned.
+
+ This operation is similar to the Get-Job-Attributes operation, except
+ that this Get-Jobs operation returns attributes from possibly more
+ than one object.
+
+3.2.6.1 Get-Jobs Request
+
+ The client submits the Get-Jobs request to a Printer object.
+
+ The following groups of attributes are part of the Get-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.
+
+ Target:
+ The "printer-uri" (uri) operation attribute which is the target
+ for this operation as described in section 3.1.5.
+
+ Requesting User Name:
+ The "requesting-user-name" (name(MAX)) attribute SHOULD be
+ supplied by the client as described in section 8.3.
+
+
+
+
+
+Hastings, et al. Standards Track [Page 54]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ "limit" (integer(1:MAX)):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object MUST support this attribute. It is an integer value that
+ determines the maximum number of jobs that a client will
+ receive from the Printer even if "which-jobs" or "my-jobs"
+ constrain which jobs are returned. The limit is a "stateless
+ limit" in that if the value supplied by the client is 'N', then
+ only the first 'N' jobs are returned in the Get-Jobs Response.
+ There is no mechanism to allow for the next 'M' jobs after the
+ first 'N' jobs. If the client does not supply this attribute,
+ the Printer object responds with all applicable jobs.
+
+ "requested-attributes" (1setOf type2 keyword):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object MUST support this attribute. It is a set of Job
+ attribute names and/or attribute groups names in whose values
+ the requester is interested. This set of attributes is
+ returned for each Job object that is returned. The allowed
+ attribute group names are the same as those defined in the
+ Get-Job-Attributes operation in section 3.3.4. If the client
+ does not supply this attribute, the Printer MUST respond as if
+ the client had supplied this attribute with two values: 'job-
+ uri' and 'job-id'.
+
+ "which-jobs" (type2 keyword):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object MUST support this attribute. It indicates which Job
+ objects MUST be returned by the Printer object. The values for
+ this attribute are:
+
+ 'completed': This includes any Job object whose state is
+ 'completed', 'canceled', or 'aborted'.
+ 'not-completed': This includes any Job object whose state is
+ 'pending', 'processing', 'processing-stopped', or 'pending-
+ held'.
+
+ A Printer object MUST support both values. However, if the
+ implementation does not keep jobs in the 'completed',
+ 'canceled', and 'aborted' states, then it returns no jobs when
+ the 'completed' value is supplied.
+
+ If a client supplies some other value, the Printer object MUST
+ copy the attribute and the unsupported value to the Unsupported
+ Attributes response group, reject the request, and return the
+ 'client-error-attributes-or-values-not-supported' status code.
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 55]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ If the client does not supply this attribute, the Printer
+ object MUST respond as if the client had supplied the attribute
+ with a value of 'not-completed'.
+
+ "my-jobs" (boolean):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object MUST support this attribute. It indicates whether jobs
+ from all users or just the jobs submitted by the requesting
+ user of this request MUST be considered as candidate jobs to be
+ returned by the Printer object. If the client does not supply
+ this attribute, the Printer object MUST respond as if the
+ client had supplied the attribute with a value of 'false',
+ i.e., jobs from all users. The means for authenticating the
+ requesting user and matching the jobs is described in section
+ 8.
+
+3.2.6.2 Get-Jobs Response
+
+ The Printer object returns all of the Job objects up to the number
+ specified by the "limit" attribute that match the criteria as defined
+ by the attribute values supplied by the client in the request. It is
+ possible that no Job objects are returned since there may literally
+ be no Job objects at the Printer, or there may be no Job objects that
+ match the criteria supplied by the client. If the client requests
+ any Job attributes at all, there is a set of Job Object Attributes
+ returned for each Job object.
+
+ It is not an error for the Printer to return 0 jobs. If the response
+ returns 0 jobs because there are no jobs matching the criteria, and
+ the request would have returned 1 or more jobs with a status code of
+ 'successful-ok' if there had been jobs matching the criteria, then
+ the status code for 0 jobs MUST be 'successful-ok'.
+
+ Group 1: Operation Attributes
+
+ Status Message:
+ In addition to the REQUIRED status code returned in every
+ response, the response OPTIONALLY includes a "status-message"
+ (text(255)) and/or a "detailed-status-message" (text(MAX))
+ operation attribute as described in sections 13 and 3.1.6.
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2.
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 56]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Group 2: Unsupported Attributes
+
+ See section 3.1.7 for details on returning Unsupported Attributes.
+
+ The response NEED NOT contain the "requested-attributes" operation
+ attribute with any supplied values (attribute keywords) that were
+ requested by the client but are not supported by the IPP object.
+ If the Printer object does return unsupported attributes
+ referenced in the "requested-attributes" operation attribute and
+ that attribute included group names, such as 'all', the
+ unsupported attributes MUST NOT include attributes described in
+ the standard but not supported by the implementation.
+
+ Groups 3 to N: Job Object Attributes
+
+ The Printer object responds with one set of Job Object Attributes
+ for each returned Job object. The Printer object ignores (does
+ not respond with) any requested attribute or value which is not
+ supported or which is restricted by the security policy in force,
+ including whether the requesting user is the user that submitted
+ the job (job originating user) or not (see section 8). However,
+ the Printer object MUST respond with the 'unknown' value for any
+ supported attribute (including all REQUIRED attributes) for which
+ the Printer object does not know the value, unless it would
+ violate the security policy. See the description of the "out-of-
+ band" values in the beginning of Section 4.1.
+
+ Jobs are returned in the following order:
+
+ - If the client requests all 'completed' Jobs (Jobs in the
+ 'completed', 'aborted', or 'canceled' states), then the Jobs are
+ returned newest to oldest (with respect to actual completion
+ time)
+ - If the client requests all 'not-completed' Jobs (Jobs in the
+ 'pending', 'processing', 'pending-held', and 'processing-
+ stopped' states), then Jobs are returned in relative
+ chronological order of expected time to complete (based on
+ whatever scheduling algorithm is configured for the Printer
+ object).
+
+3.2.7 Pause-Printer Operation
+
+ This OPTIONAL operation allows a client to stop the Printer object
+ from scheduling jobs on all its devices. Depending on
+ implementation, the Pause-Printer operation MAY also stop the Printer
+ from processing the current job or jobs. Any job that is currently
+ being printed is either stopped as soon as the implementation permits
+
+
+
+
+Hastings, et al. Standards Track [Page 57]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ or is completed, depending on implementation. The Printer object
+ MUST still accept create operations to create new jobs, but MUST
+ prevent any jobs from entering the 'processing' state.
+
+ If the Pause-Printer operation is supported, then the Resume-Printer
+ operation MUST be supported, and vice-versa.
+
+ The IPP Printer stops the current job(s) on its device(s) that were
+ in the 'processing' or 'processing-stopped' states as soon as the
+ implementation permits. If the implementation will take appreciable
+ time to stop, the IPP Printer adds the 'moving-to-paused' value to
+ the Printer object's "printer-state-reasons" attribute (see section
+ 4.4.12). When the device(s) have all stopped, the IPP Printer
+ transitions the Printer object to the 'stopped' state, removes the
+ 'moving-to-paused' value, if present, and adds the 'paused' value to
+ the Printer object's "printer-state-reasons" attribute.
+
+ When the current job(s) complete that were in the 'processing' state,
+ the IPP Printer transitions them to the 'completed' state. When the
+ current job(s) stop in mid processing that were in the 'processing'
+ state, the IPP Printer transitions them to the 'processing-stopped'
+ state and adds the 'printer-stopped' value to the job's "job-state-
+ reasons" attribute.
+
+ For any jobs that are 'pending' or 'pending-held', the 'printer-
+ stopped' value of the jobs' "job-state-reasons" attribute also
+ applies. However, the IPP Printer NEED NOT update those jobs' "job-
+ state-reasons" attributes and only need return the 'printer-stopped'
+ value when those jobs are queried (so-called "lazy evaluation").
+
+ Whether the Pause-Printer operation affects jobs that were submitted
+ to the device from other sources than the IPP Printer object in the
+ same way that the Pause-Printer operation affects jobs that were
+ submitted to the IPP Printer object using IPP, depends on
+ implementation, i.e., on whether the IPP protocol is being used as a
+ universal management protocol or just to manage IPP jobs,
+ respectively.
+
+ The IPP Printer MUST accept the request in any state and transition
+ the Printer to the indicated new "printer-state" before returning as
+ follows:
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 58]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Current New "printer IPP Printer's response status
+ "printer- "printer- -state- code and action:
+ state" state" reasons"
+
+ 'idle' 'stopped' 'paused' 'successful-ok'
+ 'processing' 'processing' 'moving- OPTION 1: 'successful-ok';
+ to- Later, when all output has
+ paused' stopped, the "printer-state"
+ becomes 'stopped', and the
+ 'paused' value replaces the
+ 'moving-to-paused' value in the
+ "printer-state-reasons"
+ attribute
+ 'processing' 'stopped' 'paused' OPTION 2: 'successful-ok';
+ all device output stopped
+ immediately
+ 'stopped' 'stopped' 'paused' 'successful-ok'
+
+ Access Rights: The authenticated user (see section 8.3) performing
+ this operation must be an operator or administrator of the Printer
+ object (see Sections 1 and 8.5). Otherwise, the IPP Printer MUST
+ reject the operation and return: 'client-error-forbidden', 'client-
+ error-not-authenticated', or 'client-error-not-authorized' as
+ appropriate.
+
+3.2.7.1 Pause-Printer Request
+
+ The following groups of attributes are part of the Pause-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.
+
+ Target:
+ The "printer-uri" (uri) operation attribute which is the target
+ for this operation as described in section 3.1.5.
+
+ Requesting User Name:
+ The "requesting-user-name" (name(MAX)) attribute SHOULD be
+ supplied by the client as described in section 8.3.
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 59]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+3.2.7.2 Pause-Printer Response
+
+ The following groups of attributes are part of the Pause-Printer
+ Response:
+
+ Group 1: Operation Attributes
+
+ Status Message:
+ In addition to the REQUIRED status code returned in every
+ response, the response OPTIONALLY includes a "status-message"
+ (text(255)) and/or a "detailed-status-message" (text(MAX))
+ operation attribute as described in sections 13 and 3.1.6.
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2.
+
+ Group 2: Unsupported Attributes
+
+ See section 3.1.7 for details on returning Unsupported Attributes.
+
+3.2.8 Resume-Printer Operation
+
+ This operation allows a client to resume the Printer object
+ scheduling jobs on all its devices. The Printer object MUST remove
+ the 'paused' and 'moving-to-paused' values from the Printer object's
+ "printer-state-reasons" attribute, if present. If there are no other
+ reasons to keep a device paused (such as media-jam), the IPP Printer
+ is free to transition itself to the 'processing' or 'idle' states,
+ depending on whether there are jobs to be processed or not,
+ respectively, and the device(s) resume processing jobs.
+
+ If the Pause-Printer operation is supported, then the Resume-Printer
+ operation MUST be supported, and vice-versa.
+
+ The IPP Printer removes the 'printer-stopped' value from any job's
+ "job-state-reasons" attributes contained in that Printer.
+
+ The IPP Printer MUST accept the request in any state, transition the
+ Printer object to the indicated new state as follows:
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 60]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Current New "printer- IPP Printer's response status code and
+ "printer- state" action:
+ state"
+
+ 'idle' 'idle' 'successful-ok'
+ 'processing' 'processing' 'successful-ok'
+
+ 'stopped' 'processing' 'successful-ok';
+ when there are jobs to be processed
+ 'stopped' 'idle' 'successful-ok';
+ when there are no jobs to be processed.
+
+ Access Rights: The authenticated user (see section 8.3) performing
+ this operation must be an operator or administrator of the Printer
+ object (see Sections 1 and 8.5). Otherwise, the IPP Printer MUST
+ reject the operation and return: 'client-error-forbidden', 'client-
+ error-not-authenticated', or 'client-error-not-authorized' as
+ appropriate.
+
+ The Resume-Printer Request and Resume-Printer Response have the same
+ attribute groups and attributes as the Pause-Printer operation (see
+ sections 3.2.7.1 and 3.2.7.2).
+
+3.2.9 Purge-Jobs Operation
+
+ This OPTIONAL operation allows a client to remove all jobs from an
+ IPP Printer object, regardless of their job states, including jobs in
+ the Printer object's Job History (see Section 4.3.7.2). After a
+ Purge-Jobs operation has been performed, a Printer object MUST return
+ no jobs in subsequent Get-Job-Attributes and Get-Jobs responses
+ (until new jobs are submitted).
+
+ Whether the Purge-Jobs (and Get-Jobs) operation affects jobs that
+ were submitted to the device from other sources than the IPP Printer
+ object in the same way that the Purge-Jobs operation affects jobs
+ that were submitted to the IPP Printer object using IPP, depends on
+ implementation, i.e., on whether the IPP protocol is being used as a
+ universal management protocol or just to manage IPP jobs,
+ respectively.
+
+ Note: if an operator wants to cancel all jobs without clearing out
+ the Job History, the operator uses the Cancel-Job operation on each
+ job instead of using the Purge-Jobs operation.
+
+ The Printer object MUST accept this operation in any state and
+ transition the Printer object to the 'idle' state.
+
+
+
+
+
+Hastings, et al. Standards Track [Page 61]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Access Rights: The authenticated user (see section 8.3) performing
+ this operation must be an operator or administrator of the Printer
+ object (see Sections 1 and 8.5). Otherwise, the IPP object MUST
+ reject the operation and return: client-error-forbidden, client-
+ error-not-authenticated, and client-error-not-authorized as
+ appropriate.
+
+ The Purge-Jobs Request and Purge-Jobs Response have the same
+ attribute groups and attributes as the Pause-Printer operation (see
+ sections 3.2.7.1 and 3.2.7.2).
+
+3.3 Job Operations
+
+ All Job operations are directed at Job objects. A client MUST always
+ supply some means of identifying the Job object in order to identify
+ the correct target of the operation. That job identification MAY
+ either be a single Job URI or a combination of a Printer URI with a
+ Job ID. The IPP object implementation MUST support both forms of
+ identification for every job.
+
+3.3.1 Send-Document Operation
+
+ This OPTIONAL operation allows a client to create a multi-document
+ Job object that is initially "empty" (contains no documents). In the
+ Create-Job response, the Printer object returns the Job object's URI
+ (the "job-uri" attribute) and the Job object's 32-bit identifier (the
+ "job-id" attribute). For each new document that the client desires
+ to add, the client uses a Send-Document operation. Each Send-
+ Document Request contains the entire stream of document data for one
+ document.
+
+ If the Printer supports this operation but does not support multiple
+ documents per job, the Printer MUST reject subsequent Send-Document
+ operations supplied with data and return the 'server-error-multiple-
+ document-jobs-not-supported'. However, the Printer MUST accept the
+ first document with a 'true' or 'false' value for the "last-document"
+ operation attribute (see below), so that clients MAY always submit
+ one document jobs with a 'false' value for "last-document" in the
+ first Send-Document and a 'true' for "last-document" in the second
+ Send-Document (with no data).
+
+ Since the Create-Job and the send operations (Send-Document or Send-
+ URI operations) that follow could occur over an arbitrarily long
+ period of time for a particular job, a client MUST send another send
+ operation within an IPP Printer defined minimum time interval after
+ the receipt of the previous request for the job. If a Printer object
+ supports the Create-Job and Send-Document operations, the Printer
+ object MUST support the "multiple-operation-time-out" attribute (see
+
+
+
+Hastings, et al. Standards Track [Page 62]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ section 4.4.31). This attribute indicates the minimum number of
+ seconds the Printer object will wait for the next send operation
+ before taking some recovery action.
+
+ An IPP object MUST recover from an errant client that does not supply
+ a send operation, sometime after the minimum time interval specified
+ by the Printer object's "multiple-operation-time-out" attribute.
+ Such recovery MAY include any of the following or other recovery
+ actions:
+
+ 1. Assume that the Job is an invalid job, start the process of
+ changing the job state to 'aborted', add the 'aborted-by-
+ system' value to the job's "job-state-reasons" attribute (see
+ section 4.3.8), and clean up all resources associated with the
+ Job. In this case, if another send operation is finally
+ received, the Printer responds with an "client-error-not-
+ possible" or "client-error-not-found" depending on whether or
+ not the Job object is still around when the send operation
+ finally arrives.
+ 2. Assume that the last send operation received was in fact the
+ last document (as if the "last-document" flag had been set to
+ 'true'), close the Job object, and proceed to process it (i.e.,
+ move the Job's state to 'pending').
+ 3. Assume that the last send operation received was in fact the
+ last document, close the Job, but move it to the 'pending-held'
+ and add the 'submission-interrupted' value to the job's "job-
+ state-reasons" attribute (see section 4.3.8). This action
+ allows the user or an operator to determine whether to continue
+ processing the Job by moving it back to the 'pending' state
+ using the Release-Job operation (see section 3.3.6) or to
+ cancel the job using the Cancel-Job operation (see section
+ 3.3.3).
+
+ Each implementation is free to decide the "best" action to take
+ depending on local policy, whether any documents have been added,
+ whether the implementation spools jobs or not, and/or any other
+ piece of information available to it. If the choice is to abort the
+ Job object, it is possible that the Job object may already have been
+ processed to the point that some media sheet pages have been printed.
+
+ Access Rights: The authenticated user (see section 8.3) performing
+ this operation must either be the job owner (as determined in the
+ Create-Job operation) or an operator or administrator of the Printer
+ object (see Sections 1 and 8.5). Otherwise, the IPP object MUST
+ reject the operation and return: 'client-error-forbidden', 'client-
+ error-not-authenticated', or 'client-error-not-authorized' as
+ appropriate.
+
+
+
+
+Hastings, et al. Standards Track [Page 63]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+3.3.1.1 Send-Document Request
+
+ The following attribute sets are part of the Send-Document 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.
+
+ Target:
+ Either (1) the "printer-uri" (uri) plus "job-id"
+ (integer(1:MAX))or (2) the "job-uri" (uri) operation
+ attribute(s) which define the target for this operation as
+ described in section 3.1.5.
+
+ Requesting User Name:
+ The "requesting-user-name" (name(MAX)) attribute SHOULD be
+ supplied by the client as described in section 8.3.
+
+ "document-name" (name(MAX)):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object MUST support this attribute. It contains the client
+ supplied document name. The document name MAY be different than
+ the Job name. It might be helpful, but NEED NOT be unique
+ across multiple documents in the same Job. Typically, the
+ client software automatically supplies the document name on
+ behalf of the end user by using a file name or an application
+ generated name. See the description of the "document-name"
+ operation attribute in the Print-Job Request (section 3.2.1.1)
+ for more information about this attribute.
+
+ "compression" (type3 keyword):
+ See the description of "compression" for the Print-Job operation
+ in Section 3.2.1.1.
+
+ "document-format" (mimeMediaType):
+ See the description of "document-format" for the Print-Job
+ operation in Section 3.2.1.1.
+
+ "document-natural-language" (naturalLanguage):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object OPTIONALLY supports this attribute. This attribute
+ specifies the natural language of the document for those
+ document-formats that require a specification of the natural
+ language in order to image the document unambiguously. There
+ are no particular values required for the Printer object to
+ support.
+
+
+
+Hastings, et al. Standards Track [Page 64]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ "last-document" (boolean):
+ The client MUST supply this attribute. The Printer object MUST
+ support this attribute. It is a boolean flag that is set to
+ 'true' if this is the last document for the Job, 'false'
+ otherwise.
+
+ Group 2: Document Content
+
+ The client MUST supply the document data if the "last-document"
+ flag is set to 'false'. However, since a client might not know
+ that the previous document sent with a Send-Document (or Send-URI)
+ operation was the last document (i.e., the "last-document"
+ attribute was set to 'false'), it is legal to send a Send-Document
+ request with no document data where the "last-document" flag is
+ set to 'true'. Such a request MUST NOT increment the value of the
+ Job object's "number-of-documents" attribute, since no real
+ document was added to the job. It is not an error for a client to
+ submit a job with no actual document data, i.e., only a single
+ Create-Job and Send-Document request with a "last-document"
+ operation attribute set to 'true' with no document data.
+
+3.3.1.2 Send-Document Response
+
+ The following sets of attributes are part of the Send-Document
+ Response:
+
+ Group 1: Operation Attributes
+
+ Status Message:
+ In addition to the REQUIRED status code returned in every
+ response, the response OPTIONALLY includes a "status-message"
+ (text(255)) and/or a "detailed-status-message" (text(MAX))
+ operation attribute as described in sections 13 and 3.1.6.
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2.
+
+ Group 2: Unsupported Attributes
+
+ See section 3.1.7 for details on returning Unsupported Attributes.
+
+ Group 3: Job Object Attributes
+
+ This is the same set of attributes as described in the Print-Job
+ response (see section 3.2.1.2).
+
+
+
+
+
+Hastings, et al. Standards Track [Page 65]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+3.3.2 Send-URI Operation
+
+ This OPTIONAL operation is identical to the Send-Document operation
+ (see section 3.3.1) except that a client MUST supply a URI reference
+ ("document-uri" operation attribute) rather than the document data
+ itself. If a Printer object supports this operation, clients can use
+ both Send-URI or Send-Document operations to add new documents to an
+ existing multi-document Job object. However, if a client needs to
+ indicate that the previous Send-URI or Send-Document was the last
+ document, the client MUST use the Send-Document operation with no
+ document data and the "last-document" flag set to 'true' (rather than
+ using a Send-URI operation with no "document-uri" operation
+ attribute).
+
+ If a Printer object supports this operation, it MUST also support the
+ Print-URI operation (see section 3.2.2).
+
+ The Printer object MUST validate the syntax and URI scheme of the
+ supplied URI before returning a response, just as in the Print-URI
+ operation. The IPP Printer MAY validate the accessibility of the
+ document as part of the operation or subsequently (see section
+ 3.2.2).
+
+3.3.3 Cancel-Job Operation
+
+ This REQUIRED operation allows a client to cancel a Print Job from
+ the time the job is created up to the time it is completed, canceled,
+ or aborted. Since a Job might already be printing by the time a
+ Cancel-Job is received, some media sheet pages might be printed
+ before the job is actually terminated.
+
+ The IPP object MUST accept or reject the request based on the job's
+ current state and transition the job to the indicated new state as
+ follows:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 66]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Current "job- New "job- IPP object's response status
+ state" state" code and action:
+
+ 'pending' 'canceled' 'successful-ok'
+ 'pending-held' 'canceled' 'successful-ok'
+ 'processing' 'canceled' 'successful-ok'
+ 'processing' 'processing' 'successful-ok' See Rule 1
+ 'processing' 'processing' 'client-error-not-possible'
+ See Rule 2
+ 'processing- 'canceled' 'successful-ok'
+ stopped'
+ 'processing- 'processing- 'successful-ok' See Rule 1
+ stopped' stopped'
+ 'processing- 'processing- 'client-error-not-possible'
+ stopped' stopped' See Rule 2
+ 'completed' 'completed' 'client-error-not-possible'
+ 'canceled' 'canceled' 'client-error-not-possible'
+ 'aborted' 'aborted' 'client-error-not-possible'
+
+ Rule 1: If the implementation requires some measurable time to
+ cancel the job in the 'processing' or 'processing-stopped' job
+ states, the IPP object MUST add the 'processing-to-stop-point' value
+ to the job's "job-state-reasons" attribute and then transition the
+ job to the 'canceled' state when the processing ceases (see section
+ 4.3.8).
+
+ Rule 2: If the Job object already has the 'processing-to-stop-point'
+ value in its "job-state-reasons" attribute, then the Printer object
+ MUST reject a Cancel-Job operation.
+
+ Access Rights: The authenticated user (see section 8.3) performing
+ this operation must either be the job owner or an operator or
+ administrator of the Printer object (see Sections 1 and 8.5).
+ Otherwise, the IPP object MUST reject the operation and return:
+ 'client-error-forbidden', 'client-error-not-authenticated', or
+ 'client-error-not-authorized' as appropriate.
+
+3.3.3.1 Cancel-Job Request
+
+ The following groups of attributes are part of the Cancel-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.
+
+
+
+
+Hastings, et al. Standards Track [Page 67]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Target:
+ Either (1) the "printer-uri" (uri) plus "job-id"
+ (integer(1:MAX))or (2) the "job-uri" (uri) operation
+ attribute(s) which define the target for this operation as
+ described in section 3.1.5.
+
+ Requesting User Name:
+ The "requesting-user-name" (name(MAX)) attribute SHOULD be
+ supplied by the client as described in section 8.3.
+
+ "message" (text(127)):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object OPTIONALLY supports this attribute. It is a message to
+ the operator. This "message" attribute is not the same as the
+ "job-message-from-operator" attribute. That attribute is used
+ to report a message from the operator to the end user that
+ queries that attribute. This "message" operation attribute is
+ used to send a message from the client to the operator along
+ with the operation request. It is an implementation decision
+ of how or where to display this message to the operator (if at
+ all).
+
+3.3.3.2 Cancel-Job Response
+
+ The following sets of attributes are part of the Cancel-Job Response:
+
+ Group 1: Operation Attributes
+
+ Status Message:
+ In addition to the REQUIRED status code returned in every
+ response, the response OPTIONALLY includes a "status-message"
+ (text(255)) and/or a "detailed-status-message" (text(MAX))
+ operation attribute as described in sections 13 and 3.1.6.
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2.
+
+ Group 2: Unsupported Attributes
+
+ See section 3.1.7 for details on returning Unsupported Attributes.
+
+ Once a successful response has been sent, the implementation
+ guarantees that the Job will eventually end up in the 'canceled'
+ state. Between the time of the Cancel-Job operation is accepted and
+ when the job enters the 'canceled' job-state (see section 4.3.7), the
+ "job-state-reasons" attribute SHOULD contain the 'processing-to-
+ stop-point'
+
+
+
+Hastings, et al. Standards Track [Page 68]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ value which indicates to later queries that although the Job might
+ still be 'processing', it will eventually end up in the
+ 'canceled' state, not the 'completed' state.
+
+3.3.4 Get-Job-Attributes Operation
+
+ This REQUIRED operation allows a client to request the values of
+ attributes of a Job object and it is almost identical to the Get-
+ Printer-Attributes operation (see section 3.2.5). The only
+ differences are that the operation is directed at a Job object rather
+ than a Printer object, there is no "document-format" operation
+ attribute used when querying a Job object, and the returned attribute
+ group is a set of Job object attributes rather than a set of Printer
+ object attributes.
+
+ For Jobs, the possible names of attribute groups are:
+
+ - 'job-template': the subset of the Job Template attributes that
+ apply to a Job object (the first column of the table in Section
+ 4.2) that the implementation supports for Job objects.
+ - 'job-description': the subset of the Job Description attributes
+ specified in Section 4.3 that the implementation supports for
+ Job objects.
+ - 'all': the special group 'all' that includes all attributes that
+ the implementation supports for Job objects.
+
+ Since a client MAY request specific attributes or named groups, there
+ is a potential that there is some overlap. For example, if a client
+ requests, 'job-name' and 'job-description', the client is actually
+ requesting the "job-name" attribute once by naming it explicitly, and
+ once by inclusion in the 'job-description' group. In such cases, the
+ Printer object NEED NOT return the attribute only once in the
+ response even if it is requested multiple times. The client SHOULD
+ NOT request the same attribute in multiple ways.
+
+ It is NOT REQUIRED that a Job object support all attributes belonging
+ to a group (since some attributes are OPTIONAL). However it is
+ REQUIRED that each Job object support all these group names.
+
+3.3.4.1 Get-Job-Attributes Request
+
+ The following groups of attributes are part of the Get-Job-Attributes
+ Request when the request is directed at a Job object:
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 69]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 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.
+
+ Target:
+ Either (1) the "printer-uri" (uri) plus "job-id"
+ (integer(1:MAX)) or (2) the "job-uri" (uri) operation
+ attribute(s) which define the target for this operation as
+ described in section 3.1.5.
+
+ Requesting User Name:
+ The "requesting-user-name" (name(MAX)) attribute SHOULD be
+ supplied by the client as described in section 8.3.
+
+ "requested-attributes" (1setOf keyword):
+ The client OPTIONALLY supplies this attribute. The IPP object
+ MUST support this attribute. It is a set of attribute names
+ and/or attribute group names in whose values the requester is
+ interested. If the client omits this attribute, the IPP object
+ MUST respond as if this attribute had been supplied with a value
+ of 'all'.
+
+3.3.4.2 Get-Job-Attributes Response
+
+ The Printer object returns the following sets of attributes as part
+ of the Get-Job-Attributes Response:
+
+ Group 1: Operation Attributes
+
+ Status Message:
+ In addition to the REQUIRED status code returned in every
+ response, the response OPTIONALLY includes a "status-message"
+ (text(255)) and/or a "detailed-status-message" (text(MAX))
+ operation attribute as described in sections 13 and 3.1.6.
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2. The "attributes-
+ natural-language" MAY be the natural language of the Job
+ object, rather than the one requested.
+
+ Group 2: Unsupported Attributes
+
+ See section 3.1.7 for details on returning Unsupported Attributes.
+
+
+
+
+
+Hastings, et al. Standards Track [Page 70]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ The response NEED NOT contain the "requested-attributes" operation
+ attribute with any supplied values (attribute keywords) that were
+ requested by the client but are not supported by the IPP object.
+ If the Printer object does return unsupported attributes
+ referenced in the "requested-attributes" operation attribute and
+ that attribute included group names, such as 'all', the
+ unsupported attributes MUST NOT include attributes described in
+ the standard but not supported by the implementation.
+
+ Group 3: Job Object Attributes
+
+ This is the set of requested attributes and their current values.
+ The IPP object ignores (does not respond with) any requested
+ attribute or value which is not supported or which is restricted
+ by the security policy in force, including whether the requesting
+ user is the user that submitted the job (job originating user) or
+ not (see section 8). However, the IPP object MUST respond with
+ the 'unknown' value for any supported attribute (including all
+ REQUIRED attributes) for which the IPP object does not know the
+ value, unless it would violate the security policy. See the
+ description of the "out-of-band" values in the beginning of
+ Section 4.1.
+
+3.3.5 Hold-Job Operation
+
+ This OPTIONAL operation allows a client to hold a pending job in the
+ queue so that it is not eligible for scheduling. If the Hold-Job
+ operation is supported, then the Release-Job operation MUST be
+ supported, and vice-versa. The OPTIONAL "job-hold-until" operation
+ attribute allows a client to specify whether to hold the job
+ indefinitely or until a specified time period, if supported.
+
+ The IPP object MUST accept or reject the request based on the job's
+ current state and transition the job to the indicated new state as
+ follows:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 71]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Current "job- New "job-state" IPP object's response status
+ state" code and action:
+
+ 'pending' 'pending-held' 'successful-ok' See Rule 1
+ 'pending' 'pending' 'successful-ok' See Rule 2
+ 'pending-held' 'pending-held' 'successful-ok' See Rule 1
+ 'pending-held' 'pending' 'successful-ok' See Rule 2
+ 'processing' 'processing' 'client-error-not-possible'
+ 'processing- 'processing- 'client-error-not-possible'
+ stopped' stopped'
+ 'completed' 'completed' 'client-error-not-possible'
+ 'canceled' 'canceled' 'client-error-not-possible'
+ 'aborted' 'aborted' 'client-error-not-possible'
+
+ Rule 1: If the implementation supports multiple reasons for a job to
+ be in the 'pending-held' state, the IPP object MUST add the 'job-
+ hold-until-specified' value to the job's "job-state-reasons"
+ attribute.
+
+ Rule 2: If the IPP object supports the "job-hold-until" operation
+ attribute, but the specified time period has already started (or is
+ the 'no-hold' value) and there are no other reasons to hold the job,
+ the IPP object MUST make the job be a candidate for processing
+ immediately (see Section 4.2.2) by putting the job in the 'pending'
+ state.
+
+ Note: In order to keep the Hold-Job operation simple, such a request
+ is rejected when the job is in the 'processing' or 'processing-
+ stopped' states. If an operation is needed to hold jobs while in
+ these states, it will be added as an additional operation, rather
+ than overloading the Hold-Job operation. Then it is clear to clients
+ by querying the Printer object's "operations-supported" (see Section
+ 4.4.15) and the Job object's "job-state" (see Section 4.3.7)
+ attributes which operations are possible.
+
+ Access Rights: The authenticated user (see section 8.3) performing
+ this operation must either be the job owner or an operator or
+ administrator of the Printer object (see Sections 1 and 8.5).
+ Otherwise, the IPP object MUST reject the operation and return:
+ 'client-error-forbidden', 'client-error-not-authenticated', or
+ 'client-error-not-authorized' as appropriate.
+
+3.3.5.1 Hold-Job Request
+
+ The groups and operation attributes are the same as for a Cancel-Job
+ request (see section 3.3.3.1), with the addition of the following
+ Group 1 Operation attribute:
+
+
+
+
+Hastings, et al. Standards Track [Page 72]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ "job-hold-until" (type3 keyword | name(MAX)):
+ The client OPTIONALLY supplies this Operation attribute. The
+ IPP object MUST support this operation attribute in a Hold-Job
+ request, if it supports the "job-hold-until" Job template
+ attribute in create operations. See section 4.2.2. The IPP
+ object SHOULD support the "job-hold-until" Job Template
+ attribute for use in job create operations with at least the
+ 'indefinite' value, if it supports the Hold-Job operation.
+ Otherwise, a client cannot create a job and hold it immediately
+ (without picking some supported time period in the future).
+
+ If supplied and supported as specified in the Printer's "job-
+ hold-until-supported" attribute, the IPP object copies the
+ supplied operation attribute to the Job object, replacing the
+ job's previous "job-hold-until" attribute, if present, and
+ makes the job a candidate for scheduling during the supplied
+ named time period.
+
+ If supplied, but either the "job-hold-until" Operation
+ attribute itself or the value supplied is not supported, the
+ IPP object accepts the request, returns the unsupported
+ attribute or value in the Unsupported Attributes Group
+ according to section 3.1.7, returns the 'successful-ok-
+ ignored-or-substituted-attributes, and holds the job
+ indefinitely until a client performs a subsequent Release-Job
+ operation.
+
+ If the client (1) supplies a value that specifies a time period
+ that has already started or the 'no-hold' value (meaning don't
+ hold the job) and (2) the IPP object supports the "job-hold-
+ until" operation attribute and there are no other reasons to
+ hold the job, the IPP object MUST accept the operation and make
+ the job be a candidate for processing immediately (see Section
+ 4.2.2).
+
+ If the client does not supply a "job-hold-until" Operation
+ attribute in the request, the IPP object MUST populate the job
+ object with a "job-hold-until" attribute with the 'indefinite'
+ value (if IPP object supports the "job-hold-until" attribute)
+ and hold the job indefinitely, until a client performs a
+ Release-Job operation.
+
+3.3.5.2 Hold-Job Response
+
+ The groups and attributes are the same as for a Cancel-Job response
+ (see section 3.3.3.2).
+
+
+
+
+
+Hastings, et al. Standards Track [Page 73]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+3.3.6 Release-Job Operation
+
+ This OPTIONAL operation allows a client to release a previously held
+ job so that it is again eligible for scheduling. If the Hold-Job
+ operation is supported, then the Release-Job operation MUST be
+ supported, and vice-versa.
+
+ This operation removes the "job-hold-until" job attribute, if
+ present, from the job object that had been supplied in the create or
+ most recent Hold-Job or Restart-Job operation and removes its effect
+ on the job. The IPP object MUST remove the 'job-hold-until-
+ specified' value from the job's "job-state-reasons" attribute, if
+ present. See section 4.3.8.
+
+ The IPP object MUST accept or reject the request based on the job's
+ current state and transition the job to the indicated new state as
+ follows:
+
+ Current "job- New "job-state" IPP object's response status
+ state" code and action:
+
+ 'pending' 'pending' 'successful-ok'
+ No effect on the job.
+ 'pending-held' 'pending-held' 'successful-ok' See Rule 1
+ 'pending-held' 'pending' 'successful-ok'
+ 'processing' 'processing' 'successful-ok'
+ No effect on the job.
+ 'processing- 'processing- 'successful-ok'
+ stopped' stopped' No effect on the job.
+ 'completed' 'completed' 'client-error-not-possible'
+ 'canceled' 'canceled' 'client-error-not-possible'
+ 'aborted' 'aborted' 'client-error-not-possible'
+
+ Rule 1: If there are other reasons to keep the job in the 'pending-
+ held' state, such as 'resources-are-not-ready', the job remains in
+ the 'pending-held' state. Thus the 'pending-held' state is not just
+ for jobs that have the 'job-hold-until' applied to them, but are for
+ any reason to keep the job from being a candidate for scheduling and
+ processing, such as 'resources-are-not-ready'. See the "job-hold-
+ until" attribute (section 4.2.2).
+
+ Access Rights: The authenticated user (see section 8.3) performing
+ this operation must either be the job owner or an operator or
+ administrator of the Printer object (see Sections 1 and 8.5).
+ Otherwise, the IPP object MUST reject the operation and return:
+ 'client-error-forbidden', 'client-error-not-authenticated', or
+ 'client-error-not-authorized' as appropriate.
+
+
+
+
+Hastings, et al. Standards Track [Page 74]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ The Release-Job Request and Release-Job Response have the same
+ attribute groups and attributes as the Cancel-Job operation (see
+ section 3.3.3.1 and 3.3.3.2).
+
+3.3.7 Restart-Job Operation
+
+ This OPTIONAL operation allows a client to restart a job that is
+ retained in the queue after processing has completed (see section
+ 4.3.7.2).
+
+ The job is moved to the 'pending' or 'pending-held' job state and
+ restarts at the beginning on the same IPP Printer object with the
+ same attribute values. If any of the documents in the job were
+ passed by reference (Print-URI or Send-URI), the Printer MUST re-
+ fetch the data, since the semantics of Restart-Job are to repeat all
+ Job processing. The Job Description attributes that accumulate job
+ progress, such as "job-impressions-completed", "job-media-sheets-
+ completed", and "job-k-octets-processed", MUST be reset to 0 so that
+ they give an accurate record of the job from its restart point. The
+ job object MUST continue to use the same "job-uri" and "job-id"
+ attribute values.
+
+ Note: If in the future an operation is needed that does not reset
+ the job progress attributes, then a new operation will be defined
+ which makes a copy of the job, assigns a new "job-uri" and "job-id"
+ to the copy and resets the job progress attributes in the new copy
+ only.
+
+ The IPP object MUST accept or reject the request based on the job's
+ current state, transition the job to the indicated new state as
+ follows:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 75]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Current "job- New "job-state" IPP object's response status
+ state" code and action:
+
+ 'pending' 'pending' 'client-error-not-possible'
+ 'pending-held' 'pending-held' 'client-error-not-possible'
+ 'processing' 'processing' 'client-error-not-possible'
+ 'processing- 'processing- 'client-error-not-possible'
+ stopped' stopped'
+ 'completed' 'pending' or 'successful-ok' - job is started
+ 'pending-held' over.
+ 'completed' 'completed' 'client-error-not-possible' -
+ see Rule 1
+ 'canceled' 'pending' or 'successful-ok' - job is started
+ 'pending-held' over.
+ 'canceled' 'canceled' 'client-error-not-possible' -
+ see Rule 1
+ 'aborted' 'pending' or 'successful-ok' - job is started
+ 'pending-held' over.
+ 'aborted' 'aborted' 'client-error-not-possible' -
+ see Rule 1
+
+ Rule 1: If the Job Retention Period has expired for the job in this
+ state, then the IPP object rejects the operation. See section
+ 4.3.7.2.
+
+ Note: In order to prevent a user from inadvertently restarting a job
+ in the middle, the Restart-Job request is rejected when the job is in
+ the 'processing' or 'processing-stopped' states. If in the future an
+ operation is needed to hold or restart jobs while in these states, it
+ will be added as an additional operation, rather than overloading the
+ Restart-Job operation, so that it is clear that the user intended
+ that the current job not be completed.
+
+ Access Rights: The authenticated user (see section 8.3) performing
+ this operation must either be the job owner or an operator or
+ administrator of the Printer object (see Sections 1 and 8.5).
+ Otherwise, the IPP object MUST reject the operation and return:
+ 'client-error-forbidden', 'client-error-not-authenticated', or
+ 'client-error-not-authorized' as appropriate.
+
+3.3.7.1 Restart-Job Request
+
+ The groups and attributes are the same as for a Cancel-Job request
+ (see section 3.3.3.1), with the addition of the following Group 1
+ Operation attribute:
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 76]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ "job-hold-until" (type3 keyword | name(MAX)):
+ The client OPTIONALLY supplies this attribute. The IPP object
+ MUST support this Operation attribute in a Restart-Job request,
+ if it supports the "job-hold-until" Job Template attribute in
+ create operations. See section 4.2.2. Otherwise, the IPP
+ object NEED NOT support the "job-hold-until" Operation
+ attribute in a Restart-Job request.
+
+ If supplied and supported as specified in the Printer's "job-
+ hold-until-supported" attribute, the IPP object copies the
+ supplied Operation attribute to the Job object, replacing the
+ job's previous "job-hold-until" attribute, if present, and
+ makes the job a candidate for scheduling during the supplied
+ named time period. See section 4.2.2.
+
+ If supplied, but the value is not supported, the IPP object
+ accepts the request, returns the unsupported attribute or value
+ in the Unsupported Attributes Group according to section 3.1.7,
+ returns the 'successful-ok-ignored-or-substituted-attributes'
+ status code, and holds the job indefinitely until a client
+ performs a subsequent Release-Job operation.
+
+ If supplied, but the "job-hold-until" Operation attribute
+ itself is not supported, the IPP object accepts the request,
+ returns the unsupported attribute with the out-of-band
+ 'unsupported' value in the Unsupported Attributes Group
+ according to section 3.1.7, returns the 'successful-ok-
+ ignored-or-substituted-attributes' status code, and restarts
+ the job, i.e., ignores the "job-hold-until" attribute.
+
+ If the client (1) supplies a value that specifies a time period
+ that has already started or the 'no-hold' value (meaning don't
+ hold the job) and (2) the IPP object supports the "job-hold-
+ until" operation attribute and there are no other reasons to
+ hold the job, the IPP object makes the job a candidate for
+ processing immediately (see Section 4.2.2).
+
+ If the client does not supply a "job-hold-until" operation
+ attribute in the request, the IPP object removes the "job-
+ hold-until" attribute, if present, from the job. If there are
+ no other reasons to hold the job, the Restart-Job operation
+ makes the job a candidate for processing immediately (see
+ Section 4.2.2).
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 77]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+3.3.7.2 Restart-Job Response
+
+ The groups and attributes are the same as for a Cancel-Job response
+ (see section 3.3.3.2).
+
+ Note: In the future an OPTIONAL Modify-Job or Set-Job-Attributes
+ operation may be specified that allows the client to modify other
+ attributes before releasing the restarted job.
+
+4. Object Attributes
+
+ This section describes the attributes with their corresponding
+ attribute syntaxes and values that are part of the IPP model. The
+ sections below show the objects and their associated attributes which
+ are included within the scope of this protocol. Many of these
+ attributes are derived from other relevant documents:
+
+ - Document Printing Application (DPA) [ISO10175]
+ - RFC 1759 Printer MIB [RFC1759]
+
+ Each attribute is uniquely identified in this document using a
+ "keyword" (see section 12.2.1) which is the name of the attribute.
+ The keyword is included in the section header describing that
+ attribute.
+
+ Note: Not only are keywords used to identify attributes, but one of
+ the attribute syntaxes described below is "keyword" so that some
+ attributes have keyword values. Therefore, these attributes are
+ defined as having an attribute syntax that is a set of keywords.
+
+4.1 Attribute Syntaxes
+
+ This section defines the basic attribute syntax types that all
+ clients and IPP objects MUST be able to accept in responses and
+ accept in requests, respectively. Each attribute description in
+ sections 3 and 4 includes the name of attribute syntax(es) in the
+ heading (in parentheses). A conforming implementation of an
+ attribute MUST include the semantics of the attribute syntax(es) so
+ identified. Section 6.3 describes how the protocol can be extended
+ with new attribute syntaxes.
+
+ The attribute syntaxes are specified in the following sub-sections,
+ where the sub-section heading is the keyword name of the attribute
+ syntax inside the single quotes. In operation requests and responses
+ each attribute value MUST be represented as one of the attribute
+ syntaxes specified in the sub-section heading for the attribute. In
+ addition, the value of an attribute in a response (but not in a
+
+
+
+
+Hastings, et al. Standards Track [Page 78]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ request) MAY be one of the "out-of-band" values whose special
+ encoding rules are defined in the "Encoding and Transport" document
+ [RFC2910]. Standard "out-of-band" values are:
+
+ 'unknown': The attribute is supported by the IPP object, but the
+ value is unknown to the IPP object for some reason.
+ 'unsupported': The attribute is unsupported by the IPP object.
+ This value MUST be returned only as the value of an attribute
+ in the Unsupported Attributes Group.
+ 'no-value': The attribute is supported by the Printer object, but
+ the administrator has not yet configured a value.
+
+ All attributes in a request MUST have one or more values as defined
+ in Sections 4.2 to 4.4. Thus clients MUST NOT supply attributes with
+ "out-of-band" values for operations defined in this document. All
+ attributes in a response MUST have one or more values as defined in
+ Sections 4.2 to 4.4 or a single "out-of-band" value.
+
+ Most attributes are defined to have a single attribute syntax.
+ However, a few attributes (e.g., "job-sheet", "media", "job-hold-
+ until") are defined to have several attribute syntaxes, depending on
+ the value. These multiple attribute syntaxes are separated by the
+ "|" character in the sub-section heading to indicate the choice.
+ Since each value MUST be tagged as to its attribute syntax in the
+ protocol, a single-valued attribute instance may have any one of its
+ attribute syntaxes and a multi-valued attribute instance may have a
+ mixture of its defined attribute syntaxes.
+
+4.1.1 'text'
+
+ A text attribute is an attribute whose value is a sequence of zero or
+ more characters encoded in a maximum of 1023 ('MAX') octets. MAX is
+ the maximum length for each value of any text attribute. However, if
+ an attribute will always contain values whose maximum length is much
+ less than MAX, the definition of that attribute will include a
+ qualifier that defines the maximum length for values of that
+ attribute. For example: the "printer-location" attribute is
+ specified as "printer-location (text(127))". In this case, text
+ values for "printer-location" MUST NOT exceed 127 octets; if supplied
+ with a longer text string via some external interface (other than the
+ protocol), implementations are free to truncate to this shorter
+ length limitation.
+
+ In this document, all text attributes are defined using the 'text'
+ syntax. However, 'text' is used only for brevity; the formal
+ interpretation of 'text' is: 'textWithoutLanguage |
+ textWithLanguage'. That is, for any attribute defined in this
+ document using the 'text' attribute syntax, all IPP objects and
+
+
+
+Hastings, et al. Standards Track [Page 79]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ clients MUST support both the 'textWithoutLanguage' and
+ 'textWithLanguage' attribute syntaxes. However, in actual usage and
+ protocol execution, objects and clients accept and return only one of
+ the two syntax per attribute. The syntax 'text' never appears "on-
+ the-wire".
+
+ Both 'textWithoutLanguage' and 'textWithLanguage' are needed to
+ support the real world needs of interoperability between sites and
+ systems that use different natural languages as the basis for human
+ communication. Generally, one natural language applies to all text
+ attributes in a given request or response. The language is indicated
+ by the "attributes-natural-language" operation attribute defined in
+ section 3.1.4 or "attributes-natural-language" job attribute defined
+ in section 4.3.20, and there is no need to identify the natural
+ language for each text string on a value-by-value basis. In these
+ cases, the attribute syntax 'textWithoutLanguage' is used for text
+ attributes. In other cases, the client needs to supply or the
+ Printer object needs to return a text value in a natural language
+ that is different from the rest of the text values in the request or
+ response. In these cases, the client or Printer object uses the
+ attribute syntax 'textWithLanguage' for text attributes (this is the
+ Natural Language Override mechanism described in section 3.1.4).
+
+ The 'textWithoutLanguage' and 'textWithLanguage' attribute syntaxes
+ are described in more detail in the following sections.
+
+4.1.1.1 'textWithoutLanguage'
+
+ The 'textWithoutLanguage' syntax indicates a value that is sequence
+ of zero or more characters encoded in a maximum of 1023 (MAX) octets.
+ Text strings are encoded using the rules of some charset. The
+ Printer object MUST support the UTF-8 charset [RFC2279] and MAY
+ support additional charsets to represent 'text' values, provided that
+ the charsets are registered with IANA [IANA-CS]. See Section 4.1.7
+ for the definition of the 'charset' attribute syntax, including
+ restricted semantics and examples of charsets.
+
+4.1.1.2 'textWithLanguage'
+
+ The 'textWithLanguage' attribute syntax is a compound attribute
+ syntax consisting of two parts: a 'textWithoutLanguage' part encoded
+ in a maximum of 1023 (MAX) octets plus an additional
+ 'naturalLanguage' (see section 4.1.8) part that overrides the natural
+ language in force. The 'naturalLanguage' part explicitly identifies
+ the natural language that applies to the text part of that value and
+ that value alone. For any give text attribute, the
+ 'textWithoutLanguage' part is limited to the maximum length defined
+ for that 'text' attribute, and the 'naturalLanguage' part is always
+
+
+
+Hastings, et al. Standards Track [Page 80]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ limited to 63 (additional) octets. Using the 'textWithLanguage'
+ attribute syntax rather than the normal 'textWithoutLanguage' syntax
+ is the so-called Natural Language Override mechanism and MUST be
+ supported by all IPP objects and clients.
+
+ If the attribute is multi-valued (1setOf text), then the
+ 'textWithLanguage' attribute syntax MUST be used to explicitly
+ specify each attribute value whose natural language needs to be
+ overridden. Other values in a multi-valued 'text' attribute in a
+ request or a response revert to the natural language of the operation
+ attribute.
+
+ In a create request, the Printer object MUST accept and store with
+ the Job object any natural language in the "attributes-natural-
+ language" operation attribute, whether the Printer object supports
+ that natural language or not. Furthermore, the Printer object MUST
+ accept and store any 'textWithLanguage' attribute value, whether the
+ Printer object supports that natural language or not. These
+ requirements are independent of the value of the "ipp-attribute-
+ fidelity" operation attribute that the client MAY supply.
+
+ Example: If the client supplies the "attributes-natural-language"
+ operation attribute with the value: 'en' indicating English, but the
+ value of the "job-name" attribute is in French, the client MUST use
+ the 'textWithLanguage' attribute syntax with the following two
+ values:
+
+ 'fr': Natural Language Override indicating French
+ 'Rapport Mensuel': the job name in French
+
+ See the "Encoding and Transport" document [RFC2910] section 3.9 for
+ the encoding of the two parts and Appendix A for a detailed example
+ of the 'textWithLanguage' attribute syntax.
+
+4.1.2 'name'
+
+ This syntax type is used for user-friendly strings, such as a Printer
+ name, that, for humans, are more meaningful than identifiers. Names
+ are never translated from one natural language to another. The
+ 'name' attribute syntax is essentially the same as 'text', including
+ the REQUIRED support of UTF-8 except that the sequence of characters
+ is limited so that its encoded form MUST NOT exceed 255 (MAX) octets.
+
+ Also like 'text', 'name' is really an abbreviated notation for either
+ 'nameWithoutLanguage' or 'nameWithLanguage'. That is, all IPP
+ objects and clients MUST support both the 'nameWithoutLanguage' and
+ 'nameWithLanguage' attribute syntaxes. However, in actual usage and
+
+
+
+
+Hastings, et al. Standards Track [Page 81]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ protocol execution, objects and clients accept and return only one of
+ the two syntax per attribute. The syntax 'name' never appears "on-
+ the-wire".
+
+ Only the 'text' and 'name' attribute syntaxes permit the Natural
+ Language Override mechanism.
+
+ Some attributes are defined as 'type3 keyword | name'. These
+ attributes support values that are either type3 keywords or names.
+ This dual-syntax mechanism enables a site administrator to extend
+ these attributes to legally include values that are locally defined
+ by the site administrator. Such names are not registered with IANA.
+
+4.1.2.1 'nameWithoutLanguage'
+
+ The 'nameWithoutLanguage' syntax indicates a value that is sequence
+ of zero or more characters encoded in a maximum of 255 (MAX) octets.
+
+4.1.2.2 'nameWithLanguage'
+
+ The 'nameWithLanguage' attribute syntax is a compound attribute
+ syntax consisting of two parts: a 'nameWithoutLanguage' part encoded
+ in a maximum of 1023 (MAX) octets plus an additional
+ 'naturalLanguage' (see section 4.1.8) part that overrides the natural
+ language in force. The 'naturalLanguage' part explicitly identifies
+ the natural language that applies to that name value and that name
+ value alone. For any give text attribute, the 'textWithoutLanguage'
+ part is limited to the maximum length defined for that 'text'
+ attribute, and the 'naturalLanguage' part is always limited to 63
+ (additional) octets. Using the 'textWithLanguage' attribute syntax
+ rather than the normal 'textWithoutLanguage' syntax is the so-called
+ Natural Language Override mechanism and MUST be supported by all IPP
+ objects and clients.
+
+ The 'nameWithLanguage' attribute syntax behaves the same as the
+ 'textWithLanguage' syntax. Using the 'textWithLanguage' attribute
+ syntax rather than the normal 'textWithoutLanguage' syntax is the
+ so-called Natural Language Override mechanism and MUST be supported
+ by all IPP objects and clients. If a name is in a language that is
+ different than the rest of the object or operation, then this
+ 'nameWithLanguage' syntax is used rather than the generic
+ 'nameWithoutLanguage' syntax.
+
+ If the attribute is multi-valued (1setOf text), then the
+ 'nameWithLanguage' attribute syntax MUST be used to explicitly
+ specify each attribute value whose natural language needs to be
+ overridden.
+
+
+
+
+Hastings, et al. Standards Track [Page 82]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Other values in a multi-valued 'name' attribute in a request or a
+ response revert to the natural language of the operation attribute.
+
+ In a create request, the Printer object MUST accept and store with
+ the Job object any natural language in the "attributes-natural-
+ language" operation attribute, whether the Printer object supports
+ that natural language or not. Furthermore, the Printer object MUST
+ accept and store any 'nameWithLanguage' attribute value, whether the
+ Printer object supports that natural language or not. These
+ requirements are independent of the value of the "ipp-attribute-
+ fidelity" operation attribute that the client MAY supply.
+
+ Example: If the client supplies the "attributes-natural-language"
+ operation attribute with the value: 'en' indicating English, but the
+ "printer-name" attribute is in German, the client MUST use the
+ 'nameWithLanguage' attribute syntax as follows:
+
+ 'de': Natural Language Override indicating German
+ 'Farbdrucker': the Printer name in German
+
+ See the "Encoding and Transport" document [RFC2910] section 3.9 for
+ the encoding of the two parts and Appendix A for a detailed example
+ of the 'nameWithLanguage' attribute syntax.
+
+4.1.2.3 Matching 'name' attribute values
+
+ For purposes of matching two 'name' attribute values for equality,
+ such as in job validation (where a client-supplied value for
+ attribute "xxx" is checked to see if the value is among the values of
+ the Printer object's corresponding "xxx-supported" attribute), the
+ following match rules apply:
+
+ 1. 'keyword' values never match 'name' values.
+
+ 2. 'name' (nameWithoutLanguage and nameWithLanguage) values match
+ if (1) the name parts match and (2) the Associated Natural-
+ Language parts (see section 3.1.4.1) match. The matching rules
+ are:
+
+ a. the name parts match if the two names are identical
+ character by character, except it is RECOMMENDED that case
+ be ignored. For example: 'Ajax-letter-head-white' MUST
+ match 'Ajax-letter-head-white' and SHOULD match 'ajax-
+ letter-head-white' and 'AJAX-LETTER-HEAD-WHITE'.
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 83]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ b. the Associated Natural-Language parts match if the shorter
+ of the two meets the syntactic requirements of RFC 1766
+ [RFC1766] and matches byte for byte with the longer. For
+ example, 'en' matches 'en', 'en-us' and 'en-gb', but matches
+ neither 'fr' nor 'e'.
+
+4.1.3 'keyword'
+
+ The 'keyword' attribute syntax is a sequence of characters, length: 1
+ to 255, containing only the US-ASCII [ASCII] encoded values for
+ lowercase letters ("a" - "z"), digits ("0" - "9"), hyphen ("-"), dot
+ ("."), and underscore ("_"). The first character MUST be a lowercase
+ letter. Furthermore, keywords MUST be in U.S. English.
+
+ This syntax type is used for enumerating semantic identifiers of
+ entities in the abstract protocol, i.e., entities identified in this
+ document. Keywords are used as attribute names or values of
+ attributes. Unlike 'text' and 'name' attribute values, 'keyword'
+ values MUST NOT use the Natural Language Override mechanism, since
+ they MUST always be US-ASCII and U.S. English.
+
+ Keywords are for use in the protocol. A user interface will likely
+ provide a mapping between protocol keywords and displayable user-
+ friendly words and phrases which are localized to the natural
+ language of the user. While the keywords specified in this document
+ MAY be displayed to users whose natural language is U.S. English,
+ they MAY be mapped to other U.S. English words for U.S. English
+ users, since the user interface is outside the scope of this
+ document.
+
+ In the definition for each attribute of this syntax type, the full
+ set of defined keyword values for that attribute are listed.
+
+ When a keyword is used to represent an attribute (its name), it MUST
+ be unique within the full scope of all IPP objects and attributes.
+ When a keyword is used to represent a value of an attribute, it MUST
+ be unique just within the scope of that attribute. That is, the same
+ keyword MUST NOT be used for two different values within the same
+ attribute to mean two different semantic ideas. However, the same
+ keyword MAY be used across two or more attributes, representing
+ different semantic ideas for each attribute. Section 6.1 describes
+ how the protocol can be extended with new keyword values. Examples
+ of attribute name keywords:
+
+ "job-name"
+ "attributes-charset"
+
+
+
+
+
+Hastings, et al. Standards Track [Page 84]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Note: This document uses "type1", "type2", and "type3" prefixes to
+ the "keyword" basic syntax to indicate different levels of review for
+ extensions (see section 6.1).
+
+4.1.4 'enum'
+
+ The 'enum' attribute syntax is an enumerated integer value that is in
+ the range from 1 to 2**31 - 1 (MAX). Each value has an associated
+ 'keyword' name. In the definition for each attribute of this syntax
+ type, the full set of possible values for that attribute are listed.
+ This syntax type is used for attributes for which there are enum
+ values assigned by other standards, such as SNMP MIBs. A number of
+ attribute enum values in this document are also used for
+ corresponding attributes in other standards [RFC1759]. This syntax
+ type is not used for attributes to which the administrator may assign
+ values. Section 6.1 describes how the protocol can be extended with
+ new enum values.
+
+ Enum values are for use in the protocol. A user interface will
+ provide a mapping between protocol enum values and displayable user-
+ friendly words and phrases which are localized to the natural
+ language of the user. While the enum symbols specified in this
+ document MAY be displayed to users whose natural language is U.S.
+ English, they MAY be mapped to other U.S. English words for U.S.
+ English users, since the user interface is outside the scope of this
+ document.
+
+ Note: SNMP MIBs use '2' for 'unknown' which corresponds to the IPP
+ "out-of-band" value 'unknown'. See the description of the "out-of-
+ band" values at the beginning of Section 4.1. Therefore, attributes
+ of type 'enum' start at '3'.
+
+ Note: This document uses "type1", "type2", and "type3" prefixes to
+ the "enum" basic syntax to indicate different levels of review for
+ extensions (see section 6.1).
+
+4.1.5 'uri'
+
+ The 'uri' attribute syntax is any valid Uniform Resource Identifier
+ or URI [RFC2396]. Most often, URIs are simply Uniform Resource
+ Locators or URLs. The maximum length of URIs used as values of IPP
+ attributes is 1023 octets. Although most other IPP attribute syntax
+ types allow for only lower-cased values, this attribute syntax type
+ conforms to the case-sensitive and case-insensitive rules specified
+ in [RFC2396]. See also [IPP-IIG] for a discussion of case in URIs.
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 85]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+4.1.6 'uriScheme'
+
+ The 'uriScheme' attribute syntax is a sequence of characters
+ representing a URI scheme according to RFC 2396 [RFC2396]. Though
+ RFC 2396 requires that the values be case-insensitive, IPP requires
+ all lower case values in IPP attributes to simplify comparing by IPP
+ clients and Printer objects.
+
+ Standard values for this syntax type are the following keywords:
+
+ 'ipp': for IPP schemed URIs (e.g., "ipp:...")
+ 'http': for HTTP schemed URIs (e.g., "http:...")
+ 'https': for use with HTTPS schemed URIs (e.g., "https:...") (not
+ on IETF standards track)
+ 'ftp': for FTP schemed URIs (e.g., "ftp:...")
+ 'mailto': for SMTP schemed URIs (e.g., "mailto:...")
+ 'file': for file schemed URIs (e.g., "file:...")
+
+ A Printer object MAY support any URI 'scheme' that has been
+ registered with IANA [IANA-MT]. The maximum length of URI 'scheme'
+ values used to represent IPP attribute values is 63 octets.
+
+4.1.7 'charset'
+
+ The 'charset' attribute syntax is a standard identifier for a
+ charset. A charset is a coded character set and encoding scheme.
+ Charsets are used for labeling certain document contents and 'text'
+ and 'name' attribute values. The syntax and semantics of this
+ attribute syntax are specified in RFC 2046 [RFC2046] and contained in
+ the IANA character-set Registry [IANA-CS] according to the IANA
+ procedures [RFC2278]. Though RFC 2046 requires that the values be
+ case-insensitive US-ASCII [ASCII], IPP requires all lower case values
+ in IPP attributes to simplify comparing by IPP clients and Printer
+ objects. When a character-set in the IANA registry has more than one
+ name (alias), the name labeled as "(preferred MIME name)", if
+ present, MUST be used.
+
+ The maximum length of 'charset' values used to represent IPP
+ attribute values is 63 octets.
+
+ Some examples are:
+
+ 'utf-8': ISO 10646 Universal Multiple-Octet Coded Character Set
+ (UCS) represented as the UTF-8 [RFC2279] transfer encoding
+ scheme in which US-ASCII is a subset charset.
+ 'us-ascii': 7-bit American Standard Code for Information
+ Interchange (ASCII), ANSI X3.4-1986 [ASCII]. That standard
+
+
+
+
+Hastings, et al. Standards Track [Page 86]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ defines US-ASCII, but RFC 2045 [RFC2045] eliminates most of the
+ control characters from conformant usage in MIME and IPP.
+ 'iso-8859-1': 8-bit One-Byte Coded Character Set, Latin Alphabet
+ Nr 1 [ISO8859-1]. That standard defines a coded character set
+ that is used by Latin languages in the Western Hemisphere and
+ Western Europe. US-ASCII is a subset charset.
+
+ Some attribute descriptions MAY place additional requirements on
+ charset values that may be used, such as REQUIRED values that MUST be
+ supported or additional restrictions, such as requiring that the
+ charset have US- ASCII as a subset charset.
+
+4.1.8 'naturalLanguage'
+
+ The 'naturalLanguage' attribute syntax is a standard identifier for a
+ natural language and optionally a country. The values for this
+ syntax type are defined by RFC 1766 [RFC1766]. Though RFC 1766
+ requires that the values be case-insensitive US-ASCII [ASCII], IPP
+ requires all lower case to simplify comparing by IPP clients and
+ Printer objects. Examples include:
+
+ 'en': for English
+ 'en-us': for US English
+ 'fr': for French
+ 'de': for German
+
+ The maximum length of 'naturalLanguage' values used to represent IPP
+ attribute values is 63 octets.
+
+4.1.9 'mimeMediaType'
+
+ The 'mimeMediaType' attribute syntax is the Internet Media Type
+ (sometimes called MIME type) as defined by RFC 2046 [RFC2046] and
+ registered according to the procedures of RFC 2048 [RFC2048] for
+ identifying a document format. The value MAY include a charset, or
+ other, parameter, depending on the specification of the Media Type in
+ the IANA Registry [IANA-MT]. Although most other IPP syntax types
+ allow for only lower-cased values, this syntax type allows for
+ mixed-case values which are case-insensitive.
+
+ Examples are:
+ 'text/html': An HTML document
+ 'text/plain': A plain text document in US-ASCII (RFC 2046
+ indicates that in the absence of the charset parameter MUST
+ mean US-ASCII rather than simply unspecified) [RFC2046].
+ 'text/plain; charset=US-ASCII': A plain text document in US-ASCII
+ [52, 56].
+
+
+
+
+Hastings, et al. Standards Track [Page 87]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 'text/plain; charset=ISO-8859-1': A plain text document in ISO
+ 8859-1 (Latin 1) [ISO8859-1].
+ 'text/plain; charset=utf-8': A plain text document in ISO 10646
+ represented as UTF-8 [RFC2279]
+ 'application/postscript': A PostScript document [RFC2046]
+ 'application/vnd.hp-PCL': A PCL document [IANA-MT] (charset
+ escape sequence embedded in the document data)
+ 'application/pdf': Portable Document Format - see IANA MIME Media
+ Type registry
+ 'application/octet-stream': Auto-sense - see section 4.1.9.1
+
+ The maximum length of a 'mimeMediaType' value to represent IPP
+ attribute values is 255 octets.
+
+4.1.9.1 Application/octet-stream -- Auto-Sensing the document format
+
+ One special type is 'application/octet-stream'. If the Printer
+ object supports this value, the Printer object MUST be capable of
+ auto-sensing the format of the document data using an
+ implementation-dependent method that examines some number of octets
+ of the document data, either as part of the create operation and/or
+ at document processing time. During auto-sensing, a Printer may
+ determine that the document-data has a format that the Printer
+ doesn't recognize. If the Printer determines this problem before
+ returning an operation response, it rejects the request and returns
+ the 'client-error-document-format-not-supported' status code. If the
+ Printer determines this problem after accepting the request and
+ returning an operation response with one of the successful status
+ codes, the Printer adds the 'unsupported-document-format' value to
+ the job's "job-state-reasons" attribute.
+
+ If the Printer object's default value attribute "document-format-
+ default" is set to 'application/octet-stream', the Printer object not
+ only supports auto-sensing of the document format, but will depend on
+ the result of applying its auto-sensing when the client does not
+ supply the "document-format" attribute. If the client supplies a
+ document format value, the Printer MUST rely on the supplied
+ attribute, rather than trust its auto-sensing algorithm. To
+ summarize:
+
+ 1. If the client does not supply a document format value, the
+ Printer MUST rely on its default value setting (which may be
+ 'application/octet-stream' indicating an auto-sensing
+ mechanism).
+ 2. If the client supplies a value other than 'application/octet-
+ stream', the client is supplying valid information about the
+ format of the document data and the Printer object MUST trust
+ the client supplied value more than the outcome of applying an
+
+
+
+Hastings, et al. Standards Track [Page 88]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ automatic format detection mechanism. For example, the client
+ may be requesting the printing of a PostScript file as a
+ 'text/plain' document. The Printer object MUST print a text
+ representation of the PostScript commands rather than interpret
+ the stream of PostScript commands and print the result.
+ 3. If the client supplies a value of 'application/octet-stream',
+ the client is indicating that the Printer object MUST use its
+ auto-sensing mechanism on the client supplied document data
+ whether auto-sensing is the Printer object's default or not.
+
+ Note: Since the auto-sensing algorithm is probabilistic, if the
+ client requests both auto-sensing ("document-format" set to
+ 'application/octet-stream') and true fidelity ("ipp-attribute-
+ fidelity" set to 'true'), the Printer object might not be able to
+ guarantee exactly what the end user intended (the auto-sensing
+ algorithm might mistake one document format for another), but it is
+ able to guarantee that its auto-sensing mechanism be used.
+
+ When a Printer performs auto-sensing of a document in a submitted
+ job, it is RECOMMENDED that the Printer indicate to the user that
+ such auto-sensing has occurred and which document-format was auto-
+ sensed by printing that information on the job's job-start-sheet.
+
+4.1.10 'octetString'
+
+ The 'octetString' attribute syntax is a sequence of octets encoded in
+ a maximum of 1023 octets which is indicated in sub-section headers
+ using the notation: octetString(MAX). This syntax type is used for
+ opaque data.
+
+4.1.11 'boolean'
+
+ The 'boolean' attribute syntax has only two values: 'true' and
+ 'false'.
+
+4.1.12 'integer'
+
+ The 'integer' attribute syntax is an integer value that is in the
+ range from -2**31 (MIN) to 2**31 - 1 (MAX). Each individual
+ attribute may specify the range constraint explicitly in sub-section
+ headers if the range is different from the full range of possible
+ integer values. For example: job-priority (integer(1:100)) for the
+ "job-priority" attribute. However, the enforcement of that
+ additional constraint is up to the IPP objects, not the protocol.
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 89]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+4.1.13 'rangeOfInteger'
+
+ The 'rangeOfInteger' attribute syntax is an ordered pair of integers
+ that defines an inclusive range of integer values. The first integer
+ specifies the lower bound and the second specifies the upper bound.
+ If a range constraint is specified in the header description for an
+ attribute in this document whose attribute syntax is 'rangeOfInteger'
+ (i.e., 'X:Y' indicating X as a minimum value and Y as a maximum
+ value), then the constraint applies to both integers.
+
+4.1.14 'dateTime'
+
+ The 'dateTime' attribute syntax is a standard, fixed length, 11 octet
+ representation of the "DateAndTime" syntax as defined in RFC 2579
+ [RFC2579]. RFC 2579 also identifies an 8 octet representation of a
+ "DateAndTime" value, but IPP objects MUST use the 11 octet
+ representation. A user interface will provide a mapping between
+ protocol dateTime values and displayable user-friendly words or
+ presentation values and phrases which are localized to the natural
+ language and date format of the user, including time zone.
+
+4.1.15 'resolution'
+
+ The 'resolution' attribute syntax specifies a two-dimensional
+ resolution in the indicated units. It consists of 3 values: a cross
+ feed direction resolution (positive integer value), a feed direction
+ resolution (positive integer value), and a units value. The
+ semantics of these three components are taken from the Printer MIB
+ [RFC1759] suggested values. That is, the cross feed direction
+ component resolution component is the same as the
+ prtMarkerAddressabilityXFeedDir object in the Printer MIB, the feed
+ direction component resolution component is the same as the
+ prtMarkerAddressabilityFeedDir in the Printer MIB, and the units
+ component is the same as the prtMarkerAddressabilityUnit object in
+ the Printer MIB (namely, '3' indicates dots per inch and '4'
+ indicates dots per centimeter). All three values MUST be present
+ even if the first two values are the same. Example: '300', '600',
+ '3' indicates a 300 dpi cross-feed direction resolution, a 600 dpi
+ feed direction resolution, since a '3' indicates dots per inch (dpi).
+
+4.1.16 '1setOf X'
+
+ The '1setOf X' attribute syntax is 1 or more values of attribute
+ syntax type X. This syntax type is used for multi-valued attributes.
+ The syntax type is called '1setOf' rather than just 'setOf' as a
+ reminder that the set of values MUST NOT be empty (i.e., a set of
+
+
+
+
+
+Hastings, et al. Standards Track [Page 90]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ size 0). Sets are normally unordered. However each attribute
+ description of this type may specify that the values MUST be in a
+ certain order for that attribute.
+
+4.2 Job Template Attributes
+
+ Job Template attributes describe job processing behavior. Support
+ for Job Template attributes by a Printer object is OPTIONAL (see
+ section 12.2.3 for a description of support for OPTIONAL attributes).
+ Also, clients OPTIONALLY supply Job Template attributes in create
+ requests.
+
+ Job Template attributes conform to the following rules. For each Job
+ Template attribute called "xxx":
+
+ 1. If the Printer object supports "xxx" then it MUST support both
+ a "xxx-default" attribute (unless there is a "No" in the table
+ below) and a "xxx-supported" attribute. If the Printer object
+ doesn't support "xxx", then it MUST support neither an "xxx-
+ default" attribute nor an "xxx-supported" attribute, and it
+ MUST treat an attribute "xxx" supplied by a client as
+ unsupported. An attribute "xxx" may be supported for some
+ document formats and not supported for other document formats.
+ For example, it is expected that a Printer object would only
+ support "orientation-requested" for some document formats (such
+ as 'text/plain' or 'text/html') but not others (such as
+ 'application/postscript').
+
+ 2. "xxx" is OPTIONALLY supplied by the client in a create request.
+ If "xxx" is supplied, the client is indicating a desired job
+ processing behavior for this Job. When "xxx" is not supplied,
+ the client is indicating that the Printer object apply its
+ default job processing behavior at job processing time if the
+ document content does not contain an embedded instruction
+ indicating an xxx-related behavior.
+
+ Since an administrator MAY change the default value attribute
+ after a Job object has been submitted but before it has been
+ processed, the default value used by the Printer object at job
+ processing time may be different that the default value in
+ effect at job submission time.
+
+ 3. The "xxx-supported" attribute is a Printer object attribute
+ that describes which job processing behaviors are supported by
+ that Printer object. A client can query the Printer object to
+ find out what xxx-related behaviors are supported by inspecting
+ the returned values of the "xxx-supported" attribute.
+
+
+
+
+Hastings, et al. Standards Track [Page 91]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Note: The "xxx" in each "xxx-supported" attribute name is
+ singular, even though an "xxx-supported" attribute usually has
+ more than one value, such as "job-sheet-supported", unless the
+ "xxx" Job Template attribute is plural, such as "finishings" or
+ "sides". In such cases the "xxx-supported" attribute names
+ are: "finishings- supported" and "sides-supported".
+
+ 4. The "xxx-default" default value attribute describes what will
+ be done at job processing time when no other job processing
+ information is supplied by the client (either explicitly as an
+ IPP attribute in the create request or implicitly as an
+ embedded instruction within the document data).
+
+ If an application wishes to present an end user with a list of
+ supported values from which to choose, the application SHOULD query
+ the Printer object for its supported value attributes. The
+ application SHOULD also query the default value attributes. If the
+ application then limits selectable values to only those value that
+ are supported, the application can guarantee that the values supplied
+ by the client in the create request all fall within the set of
+ supported values at the Printer. When querying the Printer, the
+ client MAY enumerate each attribute by name in the Get-Printer-
+ Attributes Request, or the client MAY just name the "job-template"
+ group in order to get the complete set of supported attributes (both
+ supported and default attributes).
+
+ The "finishings" attribute is an example of a Job Template attribute.
+ It can take on a set of values such as 'staple', 'punch', and/or
+ 'cover'. A client can query the Printer object for the "finishings-
+ supported" attribute and the "finishings-default" attribute. The
+ supported attribute contains a set of supported values. The default
+ value attribute contains the finishing value(s) that will be used for
+ a new Job if the client does not supply a "finishings" attribute in
+ the create request and the document data does not contain any
+ corresponding finishing instructions. If the client does supply the
+ "finishings" attribute in the create request, the IPP object
+ validates the value or values to make sure that they are a subset of
+ the supported values identified in the Printer object's "finishings-
+ supported" attribute. See section 3.1.7.
+
+ The table below summarizes the names and relationships for all Job
+ Template attributes. The first column of the table (labeled "Job
+ Attribute") shows the name and syntax for each Job Template attribute
+ in the Job object. These are the attributes that can optionally be
+ supplied by the client in a create request. The last two columns
+ (labeled "Printer: Default Value Attribute" and "Printer: Supported
+ Values Attribute") show the name and syntax for each Job Template
+ attribute in the Printer object (the default value attribute and the
+
+
+
+Hastings, et al. Standards Track [Page 92]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ supported values attribute). A "No" in the table means the Printer
+ MUST NOT support the attribute (that is, the attribute is simply not
+ applicable). For brevity in the table, the 'text' and 'name' entries
+ do not show the maximum length for each attribute.
+
+ +===================+======================+======================+
+ | Job Attribute |Printer: Default Value| Printer: Supported |
+ | | Attribute | Values Attribute |
+ +===================+======================+======================+
+ | job-priority | job-priority-default |job-priority-supported|
+ | (integer 1:100) | (integer 1:100) |(integer 1:100) |
+ +-------------------+----------------------+----------------------+
+ | job-hold-until | job-hold-until- |job-hold-until- |
+ | (type3 keyword | | default | supported |
+ | name) | (type3 keyword | |(1setOf ( |
+ | | name) |type3 keyword | name))|
+ +-------------------+----------------------+----------------------+
+ | job-sheets | job-sheets-default |job-sheets-supported |
+ | (type3 keyword | | (type3 keyword | |(1setOf ( |
+ | name) | name) |type3 keyword | name))|
+ +-------------------+----------------------+----------------------+
+ |multiple-document- |multiple-document- |multiple-document- |
+ | handling | handling-default |handling-supported |
+ | (type2 keyword) | (type2 keyword) |(1setOf type2 keyword)|
+ +-------------------+----------------------+----------------------+
+ | copies | copies-default | copies-supported |
+ | (integer (1:MAX)) | (integer (1:MAX)) | (rangeOfInteger |
+ | | | (1:MAX)) |
+ +-------------------+----------------------+----------------------+
+ | finishings | finishings-default | finishings-supported |
+ |(1setOf type2 enum)|(1setOf type2 enum) |(1setOf type2 enum) |
+ +-------------------+----------------------+----------------------+
+ | page-ranges | No | page-ranges- |
+ | (1setOf | | supported (boolean) |
+ | rangeOfInteger | | |
+ | (1:MAX)) | | |
+ +-------------------+----------------------+----------------------+
+ | sides | sides-default | sides-supported |
+ | (type2 keyword) | (type2 keyword) |(1setOf type2 keyword)|
+ +-------------------+----------------------+----------------------+
+ | number-up | number-up-default | number-up-supported |
+ | (integer (1:MAX)) | (integer (1:MAX)) |(1setOf (integer |
+ | | | (1:MAX) | |
+ | | | rangeOfInteger |
+ | | | (1:MAX))) |
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 93]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ +-------------------+----------------------+----------------------+
+ | orientation- |orientation-requested-|orientation-requested-|
+ | requested | default | supported |
+ | (type2 enum) | (type2 enum) | (1setOf type2 enum) |
+ +-------------------+----------------------+----------------------+
+ | media | media-default | media-supported |
+ | (type3 keyword | | (type3 keyword | |(1setOf ( |
+ | name) | name) |type3 keyword | name))|
+ | | | |
+ | | | media-ready |
+ | | |(1setOf ( |
+ | | |type3 keyword | name))|
+ +-------------------+----------------------+----------------------+
+ | printer-resolution| printer-resolution- | printer-resolution- |
+ | (resolution) | default | supported |
+ | | (resolution) |(1setOf resolution) |
+ +-------------------+----------------------+----------------------+
+ | print-quality | print-quality-default| print-quality- |
+ | (type2 enum) | (type2 enum) | supported |
+ | | |(1setOf type2 enum) |
+ +-------------------+----------------------+----------------------+
+
+4.2.1 job-priority (integer(1:100))
+
+ This attribute specifies a priority for scheduling the Job. A higher
+ value specifies a higher priority. The value 1 indicates the lowest
+ possible priority. The value 100 indicates the highest possible
+ priority. Among those jobs that are ready to print, a Printer MUST
+ print all jobs with a priority value of n before printing those with
+ a priority value of n-1 for all n.
+
+ If the Printer object supports this attribute, it MUST always support
+ the full range from 1 to 100. No administrative restrictions are
+ permitted. This way an end-user can always make full use of the
+ entire range with any Printer object. If privileged jobs are
+ implemented outside IPP/1.1, they MUST have priorities higher than
+ 100, rather than restricting the range available to end-users.
+
+ If the client does not supply this attribute and this attribute is
+ supported by the Printer object, the Printer object MUST use the
+ value of the Printer object's "job-priority-default" at job
+ submission time (unlike most Job Template attributes that are used if
+ necessary at job processing time).
+
+ The syntax for the "job-priority-supported" is also integer(1:100).
+ This single integer value indicates the number of priority levels
+ supported. The Printer object MUST take the value supplied by the
+ client and map it to the closest integer in a sequence of n integers
+
+
+
+Hastings, et al. Standards Track [Page 94]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ values that are evenly distributed over the range from 1 to 100 using
+ the formula:
+
+ roundToNearestInt((100x+50)/n)
+
+ where n is the value of "job-priority-supported" and x ranges from 0
+ through n-1.
+
+ For example, if n=1 the sequence of values is 50; if n=2, the
+ sequence of values is: 25 and 75; if n = 3, the sequence of values
+ is: 17, 50 and 83; if n = 10, the sequence of values is: 5, 15, 25,
+ 35, 45, 55, 65, 75, 85, and 95; if n = 100, the sequence of values
+ is: 1, 2, 3, ... 100.
+
+ If the value of the Printer object's "job-priority-supported" is 10
+ and the client supplies values in the range 1 to 10, the Printer
+ object maps them to 5, in the range 11 to 20, the Printer object maps
+ them to 15, etc.
+
+4.2.2 job-hold-until (type3 keyword | name (MAX))
+
+ This attribute specifies the named time period during which the Job
+ MUST become a candidate for printing.
+
+ Standard keyword values for named time periods are:
+
+ 'no-hold': immediately, if there are not other reasons to hold the
+ job
+ 'indefinite': - the job is held indefinitely, until a client
+ performs a Release-Job (section 3.3.6)
+ 'day-time': during the day
+ 'evening': evening
+ 'night': night
+ 'weekend': weekend
+ 'second-shift': second-shift (after close of business)
+ 'third-shift': third-shift (after midnight)
+
+ An administrator MUST associate allowable print times with a named
+ time period (by means outside the scope of this IPP/1.1 document).
+ An administrator is encouraged to pick names that suggest the type of
+ time period. An administrator MAY define additional values using the
+ 'name' or 'keyword' attribute syntax, depending on implementation.
+
+ If the value of this attribute specifies a time period that is in the
+ future, the Printer SHOULD add the 'job-hold-until-specified' value
+ to the job's "job-state-reasons" attribute, MUST move the job to the
+
+
+
+
+
+Hastings, et al. Standards Track [Page 95]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 'pending-held' state, and MUST NOT schedule the job for printing
+ until the specified time-period arrives.
+
+ When the specified time period arrives, the Printer MUST remove the
+ 'job-hold-until-specified' value from the job's "job-state-reason"
+ attribute, if present. If there are no other job state reasons that
+ keep the job in the 'pending-held' state, the Printer MUST consider
+ the job as a candidate for processing by moving the job to the
+ 'pending' state.
+
+ If this job attribute value is the named value 'no-hold', or the
+ specified time period has already started, the job MUST be a
+ candidate for processing immediately.
+
+ If the client does not supply this attribute and this attribute is
+ supported by the Printer object, the Printer object MUST use the
+ value of the Printer object's "job-hold-until-default" at job
+ submission time (unlike most Job Template attributes that are used if
+ necessary at job processing time).
+
+4.2.3 job-sheets (type3 keyword | name(MAX))
+
+ This attribute determines which job start/end sheet(s), if any, MUST
+ be printed with a job.
+
+ Standard keyword values are:
+
+ 'none': no job sheet is printed
+ 'standard': one or more site specific standard job sheets are
+ printed, e.g. a single start sheet or both start and end sheet is
+ printed
+
+ An administrator MAY define additional values using the 'name' or
+ 'keyword' attribute syntax, depending on implementation.
+
+ The effect of this attribute on jobs with multiple documents MAY be
+ affected by the "multiple-document-handling" job attribute (section
+ 4.2.4), depending on the job sheet semantics.
+
+4.2.4 multiple-document-handling (type2 keyword)
+
+ This attribute is relevant only if a job consists of two or more
+ documents. This attribute MUST be supported with at least one value
+ if the Printer supports multiple documents per job (see sections
+ 3.2.4 and 3.3.1). The attribute controls finishing operations and
+ the placement of one or more print-stream pages into impressions and
+ onto media sheets. When the value of the "copies" attribute exceeds
+ 1, it also controls the order in which the copies that result from
+
+
+
+Hastings, et al. Standards Track [Page 96]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ processing the documents are produced. For the purposes of this
+ explanations, if "a" represents an instance of document data, then
+ the result of processing the data in document "a" is a sequence of
+ media sheets represented by "a(*)".
+
+ Standard keyword values are:
+
+ 'single-document': If a Job object has multiple documents, say,
+ the document data is called a and b, then the result of
+ processing all the document data (a and then b) MUST be treated
+ as a single sequence of media sheets for finishing operations;
+ that is, finishing would be performed on the concatenation of
+ the sequences a(*),b(*). The Printer object MUST NOT force the
+ data in each document instance to be formatted onto a new
+ print-stream page, nor to start a new impression on a new media
+ sheet. If more than one copy is made, the ordering of the sets
+ of media sheets resulting from processing the document data
+ MUST be a(*), b(*), a(*), b(*), start on a new media sheet.
+ 'separate-documents-uncollated-copies': If a Job object has
+ multiple documents, say, the document data is called a and b,
+ then the result of processing the data in each document
+ instance MUST be treated as a single sequence of media sheets
+ for finishing operations; that is, the sets a(*) and b(*) would
+ each be finished separately. The Printer object MUST force each
+ copy of the result of processing the data in a single document
+ to start on a new media sheet. If more than one copy is made,
+ the ordering of the sets of media sheets resulting from
+ processing the document data MUST be a(*), a(*), ..., b(*),
+ b(*) ... .
+ 'separate-documents-collated-copies': If a Job object has multiple
+ documents, say, the document data is called a and b, then the
+ result of processing the data in each document instance MUST be
+ treated as a single sequence of media sheets for finishing
+ operations; that is, the sets a(*) and b(*) would each be
+ finished separately. The Printer object MUST force each copy of
+ the result of processing the data in a single document to start
+ on a new media sheet. If more than one copy is made, the
+ ordering of the sets of media sheets resulting from processing
+ the document data MUST be a(*), b(*), a(*), b(*), ... .
+ 'single-document-new-sheet': Same as 'single-document', except
+ that the Printer object MUST ensure that the first impression
+ of each document instance in the job is placed on a new media
+ sheet. This value allows multiple documents to be stapled
+ together with a single staple where each document starts on a
+ new sheet.
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 97]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ The 'single-document' value is the same as 'separate-documents-
+ collated-copies' with respect to ordering of print-stream pages, but
+ not media sheet generation, since 'single-document' will put the
+ first page of the next document on the back side of a sheet if an odd
+ number of pages have been produced so far for the job, while
+ 'separate-documents-collated- copies' always forces the next document
+ or document copy on to a new sheet. In addition, if the "finishings"
+ attribute specifies 'staple', then with 'single-document', documents
+ a and b are stapled together as a single document with no regard to
+ new sheets, with 'single-document-new-sheet', documents a and b are
+ stapled together as a single document, but document b starts on a new
+ sheet, but with 'separate-documents-uncollated-copies' and
+ 'separate-documents-collated-copies', documents a and b are stapled
+ separately.
+
+ Note: None of these values provide means to produce uncollated sheets
+ within a document, i.e., where multiple copies of sheet n are
+ produced before sheet n+1 of the same document.
+
+ The relationship of this attribute and the other attributes that
+ control document processing is described in section 15.3.
+
+4.2.5 copies (integer(1:MAX))
+
+ This attribute specifies the number of copies to be printed.
+
+ On many devices the supported number of collated copies will be
+ limited by the number of physical output bins on the device, and may
+ be different from the number of uncollated copies which can be
+ supported.
+
+ Note: The effect of this attribute on jobs with multiple documents is
+ controlled by the "multiple-document-handling" job attribute (section
+ 4.2.4) and the relationship of this attribute and the other
+ attributes that control document processing is described in section
+ 15.3.
+
+4.2.6 finishings (1setOf type2 enum)
+
+ This attribute identifies the finishing operations that the Printer
+ uses for each copy of each printed document in the Job. For Jobs with
+ multiple documents, the "multiple-document-handling" attribute
+ determines what constitutes a "copy" for purposes of finishing.
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 98]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Standard enum values are:
+
+ Value Symbolic Name and Description
+
+ '3' 'none': Perform no finishing
+ '4' 'staple': Bind the document(s) with one or more staples. The
+ exact number and placement of the staples is site-
+ defined.
+ '5' 'punch': This value indicates that holes are required in the
+ finished document. The exact number and placement of the
+ holes is site-defined The punch specification MAY be
+ satisfied (in a site- and implementation-specific manner)
+ either by drilling/punching, or by substituting pre-
+ drilled media.
+ '6' 'cover': This value is specified when it is desired to select
+ a non-printed (or pre-printed) cover for the document.
+ This does not supplant the specification of a printed
+ cover (on cover stock medium) by the document itself.
+ '7' 'bind': This value indicates that a binding is to be applied
+ to the document; the type and placement of the binding is
+ site-defined.
+ '8' 'saddle-stitch': Bind the document(s) with one or more
+ staples (wire stitches) along the middle fold. The exact
+ number and placement of the staples and the middle fold
+ is implementation and/or site-defined.
+ '9' 'edge-stitch': Bind the document(s) with one or more staples
+ (wire stitches) along one edge. The exact number and
+ placement of the staples is implementation and/or site-
+ defined.
+ '10'-'19' reserved for future generic finishing enum values.
+
+ The following values are more specific; they indicate a corner or an
+ edge as if the document were a portrait document (see below):
+
+ '20' 'staple-top-left': Bind the document(s) with one or more
+ staples in the top left corner.
+ '21' 'staple-bottom-left': Bind the document(s) with one or more
+ staples in the bottom left corner.
+ '22' 'staple-top-right': Bind the document(s) with one or more
+ staples in the top right corner.
+ '23' 'staple-bottom-right': Bind the document(s) with one or more
+ staples in the bottom right corner.
+ '24' 'edge-stitch-left': Bind the document(s) with one or more
+ staples (wire stitches) along the left edge. The exact
+ number and placement of the staples is implementation
+ and/or site-defined.
+
+
+
+
+
+Hastings, et al. Standards Track [Page 99]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ '25' 'edge-stitch-top': Bind the document(s) with one or more
+ staples (wire stitches) along the top edge. The exact
+ number and placement of the staples is implementation
+ and/or site-defined.
+ '26' 'edge-stitch-right': Bind the document(s) with one or more
+ staples (wire stitches) along the right edge. The exact
+ number and placement of the staples is implementation
+ and/or site-defined.
+ '27' 'edge-stitch-bottom': Bind the document(s) with one or more
+ staples (wire stitches) along the bottom edge. The exact
+ number and placement of the staples is implementation
+ and/or site-defined.
+ '28' 'staple-dual-left': Bind the document(s) with two staples
+ (wire stitches) along the left edge assuming a portrait
+ document (see above).
+ '29' 'staple-dual-top': Bind the document(s) with two staples
+ (wire stitches) along the top edge assuming a portrait
+ document (see above).
+ '30' 'staple-dual-right': Bind the document(s) with two staples
+ (wire stitches) along the right edge assuming a portrait
+ document (see above).
+ '31' 'staple-dual-bottom': Bind the document(s) with two staples
+ (wire stitches) along the bottom edge assuming a portrait
+ document (see above).
+
+ The 'staple-xxx' values are specified with respect to the document as
+ if the document were a portrait document. If the document is
+ actually a landscape or a reverse-landscape document, the client
+ supplies the appropriate transformed value. For example, to position
+ a staple in the upper left hand corner of a landscape document when
+ held for reading, the client supplies the 'staple-bottom-left' value
+ (since landscape is defined as a +90 degree rotation of the image
+ with respect to the media from portrait, i.e., anti-clockwise). On
+ the other hand, to position a staple in the upper left hand corner of
+ a reverse-landscape document when held for reading, the client
+ supplies the 'staple-top-right' value (since reverse-landscape is
+ defined as a -90 degree rotation of the image with respect to the
+ media from portrait, i.e., clockwise).
+
+ The angle (vertical, horizontal, angled) of each staple with respect
+ to the document depends on the implementation which may in turn
+ depend on the value of the attribute.
+
+ Note: The effect of this attribute on jobs with multiple documents is
+ controlled by the "multiple-document-handling" job attribute (section
+ 4.2.4) and the relationship of this attribute and the other
+ attributes that control document processing is described in section
+ 15.3.
+
+
+
+Hastings, et al. Standards Track [Page 100]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ If the client supplies a value of 'none' along with any other
+ combination of values, it is the same as if only that other
+ combination of values had been supplied (that is the 'none' value has
+ no effect).
+
+4.2.7 page-ranges (1setOf rangeOfInteger (1:MAX))
+
+ This attribute identifies the range(s) of print-stream pages that the
+ Printer object uses for each copy of each document which are to be
+ printed. Nothing is printed for any pages identified that do not
+ exist in the document(s). Ranges MUST be in ascending order, for
+ example: 1-3, 5-7, 15-19 and MUST NOT overlap, so that a non-spooling
+ Printer object can process the job in a single pass. If the ranges
+ are not ascending or are overlapping, the IPP object MUST reject the
+ request and return the 'client-error-bad-request' status code. The
+ attribute is associated with print-stream pages not application-
+ numbered pages (for example, the page numbers found in the headers
+ and or footers for certain word processing applications).
+
+ For Jobs with multiple documents, the "multiple-document-handling"
+ attribute determines what constitutes a "copy" for purposes of the
+ specified page range(s). When "multiple-document-handling" is
+ 'single-document', the Printer object MUST apply each supplied page
+ range once to the concatenation of the print-stream pages. For
+ example, if there are 8 documents of 10 pages each, the page-range
+ '41:60' prints the pages in the 5th and 6th documents as a single
+ document and none of the pages of the other documents are printed.
+ When "multiple-document- handling" is 'separate-documents-
+ uncollated-copies' or 'separate-documents-collated-copies', the
+ Printer object MUST apply each supplied page range repeatedly to each
+ document copy. For the same job, the page-range '1:3, 10:10' would
+ print the first 3 pages and the 10th page of each of the 8 documents
+ in the Job, as 8 separate documents.
+
+ In most cases, the exact pages to be printed will be generated by a
+ device driver and this attribute would not be required. However,
+ when printing an archived document which has already been formatted,
+ the end user may elect to print just a subset of the pages contained
+ in the document. In this case, if page-range = n.m is specified, the
+ first page to be printed will be page n. All subsequent pages of the
+ document will be printed through and including page m.
+
+ "page-ranges-supported" is a boolean value indicating whether or not
+ the printer is capable of supporting the printing of page ranges.
+ This capability may differ from one PDL to another. There is no
+ "page-ranges-default" attribute. If the "page-ranges" attribute is
+ not supplied by the client, all pages of the document will be
+ printed.
+
+
+
+Hastings, et al. Standards Track [Page 101]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Note: The effect of this attribute on jobs with multiple documents is
+ controlled by the "multiple-document-handling" job attribute (section
+ 4.2.4) and the relationship of this attribute and the other
+ attributes that control document processing is described in section
+ 15.3.
+
+4.2.8 sides (type2 keyword)
+
+ This attribute specifies how print-stream pages are to be imposed
+ upon the sides of an instance of a selected medium, i.e., an
+ impression.
+
+ The standard keyword values are:
+
+ 'one-sided': imposes each consecutive print-stream page upon the
+ same side of consecutive media sheets.
+ 'two-sided-long-edge': imposes each consecutive pair of print-
+ stream pages upon front and back sides of consecutive media
+ sheets, such that the orientation of each pair of print-stream
+ pages on the medium would be correct for the reader as if for
+ binding on the long edge. This imposition is sometimes called
+ 'duplex' or 'head-to-head'.
+ 'two-sided-short-edge': imposes each consecutive pair of print-
+ stream pages upon front and back sides of consecutive media
+ sheets, such that the orientation of each pair of print-stream
+ pages on the medium would be correct for the reader as if for
+ binding on the short edge. This imposition is sometimes called
+ 'tumble' or 'head-to-toe'.
+ 'two-sided-long-edge', 'two-sided-short-edge',
+ 'tumble', and 'duplex' all work the same for portrait or
+ landscape. However
+ 'head-to-toe' is
+ 'tumble' in portrait but 'duplex' in landscape. 'head-to-head'
+ also switches between 'duplex' and 'tumble' when using portrait
+ and landscape modes.
+
+ Note: The effect of this attribute on jobs with multiple documents is
+ controlled by the "multiple-document-handling" job attribute (section
+ 4.2.4) and the relationship of this attribute and the other
+ attributes that control document processing is described in section
+ 15.3.
+
+4.2.9 number-up (integer(1:MAX))
+
+ This attribute specifies the number of print-stream pages to impose
+ upon a single side of an instance of a selected medium. For example,
+ if the value is:
+
+
+
+
+Hastings, et al. Standards Track [Page 102]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Value Description
+
+ '1' the Printer MUST place one print-stream page on a single side
+ of an instance of the selected medium (MAY add some sort
+ of translation, scaling, or rotation).
+ '2' the Printer MUST place two print-stream pages on a single side
+ of an instance of the selected medium (MAY add some sort
+ of translation, scaling, or rotation).
+ '4' the Printer MUST place four print-stream pages on a single
+ side of an instance of the selected medium (MAY add some
+ sort of translation, scaling, or rotation).
+
+ This attribute primarily controls the translation, scaling and
+ rotation of print-stream pages.
+
+ Note: The effect of this attribute on jobs with multiple documents is
+ controlled by the "multiple-document-handling" job attribute (section
+ 4.2.4) and the relationship of this attribute and the other
+ attributes that control document processing is described in section
+ 15.3.
+
+4.2.10 orientation-requested (type2 enum)
+
+ This attribute indicates the desired orientation for printed print-
+ stream pages; it does not describe the orientation of the client-
+ supplied print-stream pages.
+
+ For some document formats (such as 'application/postscript'), the
+ desired orientation of the print-stream pages is specified within the
+ document data. This information is generated by a device driver
+ prior to the submission of the print job. Other document formats
+ (such as 'text/plain') do not include the notion of desired
+ orientation within the document data. In the latter case it is
+ possible for the Printer object to bind the desired orientation to
+ the document data after it has been submitted. It is expected that a
+ Printer object would only support "orientations-requested" for some
+ document formats (e.g., 'text/plain' or 'text/html') but not others
+ (e.g., 'application/postscript'). This is no different than any
+ other Job Template attribute since section 4.2, item 1, points out
+ that a Printer object may support or not support any Job Template
+ attribute based on the document format supplied by the client.
+ However, a special mention is made here since it is very likely that
+ a Printer object will support "orientation-requested" for only a
+ subset of the supported document formats.
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 103]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Standard enum values are:
+
+ Value Symbolic Name and Description
+
+ '3' 'portrait': The content will be imaged across the short edge
+ of the medium.
+ '4' 'landscape': The content will be imaged across the long edge
+ of the medium. Landscape is defined to be a rotation of
+ the print-stream page to be imaged by +90 degrees with
+ respect to the medium (i.e. anti-clockwise) from the
+ portrait orientation. Note: The +90 direction was
+ chosen because simple finishing on the long edge is the
+ same edge whether portrait or landscape
+ '5' 'reverse-landscape': The content will be imaged across the
+ long edge of the medium. Reverse-landscape is defined to
+ be a rotation of the print-stream page to be imaged by -
+ 90 degrees with respect to the medium (i.e. clockwise)
+ from the portrait orientation. Note: The 'reverse-
+ landscape' value was added because some applications
+ rotate landscape -90 degrees from portrait, rather than
+ +90 degrees.
+ '6' 'reverse-portrait': The content will be imaged across the
+ short edge of the medium. Reverse-portrait is defined to
+ be a rotation of the print-stream page to be imaged by
+ 180 degrees with respect to the medium from the portrait
+ orientation. Note: The 'reverse-portrait' value was
+ added for use with the "finishings" attribute in cases
+ where the opposite edge is desired for finishing a
+ portrait document on simple finishing devices that have
+ only one finishing position. Thus a 'text'/plain'
+ portrait document can be stapled "on the right" by a
+ simple finishing device as is common use with some middle
+ eastern languages such as Hebrew.
+
+ Note: The effect of this attribute on jobs with multiple documents is
+ controlled by the "multiple-document-handling" job attribute (section
+ 4.2.4) and the relationship of this attribute and the other
+ attributes that control document processing is described in section
+ 15.3.
+
+4.2.11 media (type3 keyword | name(MAX))
+
+ This attribute identifies the medium that the Printer uses for all
+ impressions of the Job.
+
+ The values for "media" include medium-names, medium-sizes, input-
+ trays and electronic forms so that one attribute specifies the media.
+ If a Printer object supports a medium name as a value of this
+
+
+
+Hastings, et al. Standards Track [Page 104]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ attribute, such a medium name implicitly selects an input-tray that
+ contains the specified medium. If a Printer object supports a medium
+ size as a value of this attribute, such a medium size implicitly
+ selects a medium name that in turn implicitly selects an input-tray
+ that contains the medium with the specified size. If a Printer
+ object supports an input-tray as the value of this attribute, such an
+ input-tray implicitly selects the medium that is in that input-tray
+ at the time the job prints. This case includes manual-feed input-
+ trays. If a Printer object supports an electronic form as the value
+ of this attribute, such an electronic form implicitly selects a
+ medium-name that in turn implicitly selects an input-tray that
+ contains the medium specified by the electronic form. The electronic
+ form also implicitly selects an image that the Printer MUST merge
+ with the document data as its prints each page.
+
+ Standard keyword values are taken from ISO DPA [ISO10175], the
+ Printer MIB [RFC1759], and ASME-Y14.1M [ASME-Y14.1M] and are listed
+ in section 14. An administrator MAY define additional values using
+ the 'name' or 'keyword' attribute syntax, depending on
+ implementation.
+
+ There is also an additional Printer attribute named "media-ready"
+ which differs from "media-supported" in that legal values only
+ include the subset of "media-supported" values that are physically
+ loaded and ready for printing with no operator intervention required.
+ If an IPP object supports "media-supported", it NEED NOT support
+ "media-ready".
+
+ The relationship of this attribute and the other attributes that
+ control document processing is described in section 15.3.
+
+4.2.12 printer-resolution (resolution)
+
+ This attribute identifies the resolution that Printer uses for the
+ Job.
+
+4.2.13 print-quality (type2 enum)
+
+ This attribute specifies the print quality that the Printer uses for
+ the Job.
+
+ The standard enum values are:
+
+ Value Symbolic Name and Description
+
+ '3' 'draft': lowest quality available on the printer
+ '4' 'normal': normal or intermediate quality on the printer
+ '5' 'high': highest quality available on the printer
+
+
+
+Hastings, et al. Standards Track [Page 105]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+4.3 Job Description Attributes
+
+ The attributes in this section form the attribute group called "job-
+ description". The following table summarizes these attributes. The
+ third column indicates whether the attribute is a REQUIRED attribute
+ that MUST be supported by Printer objects. If it is not indicated as
+ REQUIRED, then it is OPTIONAL. The maximum size in octets for 'text'
+ and 'name' attributes is indicated in parenthesizes.
+
+ +----------------------------+----------------------+--------------+
+ | Attribute | Syntax | REQUIRED? |
+ +----------------------------+----------------------+--------------+
+ | job-uri | uri | REQUIRED |
+ +----------------------------+----------------------+--------------+
+ | job-id | integer(1:MAX) | REQUIRED |
+ +----------------------------+----------------------+--------------+
+ | job-printer-uri | uri | REQUIRED |
+ +----------------------------+----------------------+--------------+
+ | job-more-info | uri | |
+ +----------------------------+----------------------+--------------+
+ | job-name | name (MAX) | REQUIRED |
+ +----------------------------+----------------------+--------------+
+ | job-originating-user-name | name (MAX) | REQUIRED |
+ +----------------------------+----------------------+--------------+
+ | job-state | type1 enum | REQUIRED |
+ +----------------------------+----------------------+--------------+
+ | job-state-reasons | 1setOf type2 keyword | REQUIRED |
+ +----------------------------+----------------------+--------------+
+ | job-state-message | text (MAX) | |
+ +----------------------------+----------------------+--------------+
+ | job-detailed-status- | 1setOf text (MAX) | |
+ | messages | | |
+ +----------------------------+----------------------+--------------+
+ | job-document-access-errors | 1setOf text (MAX) | |
+ +----------------------------+----------------------+--------------+
+ | number-of-documents | integer (0:MAX) | |
+ +----------------------------+----------------------+--------------+
+ | output-device-assigned | name (127) | |
+ +----------------------------+----------------------+--------------+
+ | time-at-creation | integer (MIN:MAX) | REQUIRED |
+ +----------------------------+----------------------+--------------+
+ | time-at-processing | integer (MIN:MAX) | REQUIRED |
+ +----------------------------+----------------------+--------------+
+ | time-at-completed | integer (MIN:MAX) | REQUIRED |
+ +----------------------------+----------------------+--------------+
+ | job-printer-up-time | integer (1:MAX) | REQUIRED |
+ +----------------------------+----------------------+--------------+
+ | date-time-at-creation | dateTime | |
+
+
+
+Hastings, et al. Standards Track [Page 106]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ +----------------------------+----------------------+--------------+
+ | date-time-at-processing | dateTime | |
+ +----------------------------+----------------------+--------------+
+ | date-time-at-completed | dateTime | |
+ +----------------------------+----------------------+--------------+
+ | number-of-intervening-jobs | integer (0:MAX) | |
+ +----------------------------+----------------------+--------------+
+ | job-message-from-operator | text (127) | |
+ +----------------------------+----------------------+--------------+
+ | job-k-octets | integer (0:MAX) | |
+ +----------------------------+----------------------+--------------+
+ | job-impressions | integer (0:MAX) | |
+ +----------------------------+----------------------+--------------+
+ | job-media-sheets | integer (0:MAX) | |
+ +----------------------------+----------------------+--------------+
+ | job-k-octets-processed | integer (0:MAX) | |
+ +----------------------------+----------------------+--------------+
+ | job-impressions-completed | integer (0:MAX) | |
+ +----------------------------+----------------------+--------------+
+ | job-media-sheets-completed | integer (0:MAX) | |
+ +----------------------------+----------------------+--------------+
+ | attributes-charset | charset | REQUIRED |
+ +----------------------------+----------------------+--------------+
+ | attributes-natural-language| naturalLanguage | REQUIRED |
+ +----------------------------+----------------------+--------------+
+
+4.3.1 job-uri (uri)
+
+ This REQUIRED attribute contains the URI for the job. The Printer
+ object, on receipt of a new job, generates a URI which identifies the
+ new Job. The Printer object returns the value of the "job-uri"
+ attribute as part of the response to a create request. The precise
+ format of a Job URI is implementation dependent. If the Printer
+ object supports more than one URI and there is some relationship
+ between the newly formed Job URI and the Printer object's URI, the
+ Printer object uses the Printer URI supplied by the client in the
+ create request. For example, if the create request comes in over a
+ secure channel, the new Job URI MUST use the same secure channel.
+ This can be guaranteed because the Printer object is responsible for
+ generating the Job URI and the Printer object is aware of its
+ security configuration and policy as well as the Printer URI used in
+ the create request.
+
+ For a description of this attribute and its relationship to "job-id"
+ and "job-printer-uri" attribute, see the discussion in section 2.4 on
+ "Object Identity".
+
+
+
+
+
+Hastings, et al. Standards Track [Page 107]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+4.3.2 job-id (integer(1:MAX))
+
+ This REQUIRED attribute contains the ID of the job. The Printer, on
+ receipt of a new job, generates an ID which identifies the new Job on
+ that Printer. The Printer returns the value of the "job-id"
+ attribute as part of the response to a create request. The 0 value
+ is not included to allow for compatibility with SNMP index values
+ which also cannot be 0.
+
+ For a description of this attribute and its relationship to "job-uri"
+ and "job-printer-uri" attribute, see the discussion in section 2.4 on
+ "Object Identity".
+
+4.3.3 job-printer-uri (uri)
+
+ This REQUIRED attribute identifies the Printer object that created
+ this Job object. When a Printer object creates a Job object, it
+ populates this attribute with the Printer object URI that was used in
+ the create request. This attribute permits a client to identify the
+ Printer object that created this Job object when only the Job
+ object's URI is available to the client. The client queries the
+ creating Printer object to determine which languages, charsets,
+ operations, are supported for this Job.
+
+ For a description of this attribute and its relationship to "job-uri"
+ and "job-id" attribute, see the discussion in section 2.4 on "Object
+ Identity".
+
+4.3.4 job-more-info (uri)
+
+ Similar to "printer-more-info", this attribute contains the URI
+ referencing some resource with more information about this Job
+ object, perhaps an HTML page containing information about the Job.
+
+4.3.5 job-name (name(MAX))
+
+ This REQUIRED attribute is the name of the job. It is a name that is
+ more user friendly than the "job-uri" attribute value. It does not
+ need to be unique between Jobs. The Job's "job-name" attribute is
+ set to the value supplied by the client in the "job-name" operation
+ attribute in the create request (see Section 3.2.1.1). If, however,
+ the "job-name" operation attribute is not supplied by the client in
+ the create request, the Printer object, on creation of the Job, MUST
+ generate a name. The printer SHOULD generate the value of the Job's
+ "job-name" attribute from the first of the following sources that
+ produces a value: 1) the "document-name" operation attribute of the
+
+
+
+
+
+Hastings, et al. Standards Track [Page 108]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ first (or only) document, 2) the "document-URI" attribute of the
+ first (or only) document, or 3) any other piece of Job specific
+ and/or Document Content information.
+
+4.3.6 job-originating-user-name (name(MAX))
+
+ This REQUIRED attribute contains the name of the end user that
+ submitted the print job. The Printer object sets this attribute to
+ the most authenticated printable name that it can obtain from the
+ authentication service over which the IPP operation was received.
+ Only if such is not available, does the Printer object use the value
+ supplied by the client in the "requesting-user-name" operation
+ attribute of the create operation (see Sections 4.4.2, 4.4.3, and 8).
+
+ Note: The Printer object needs to keep an internal originating user
+ id of some form, typically as a credential of a principal, with the
+ Job object. Since such an internal attribute is implementation-
+ dependent and not of interest to clients, it is not specified as a
+ Job Description attribute. This originating user id is used for
+ authorization checks (if any) on all subsequent operations.
+
+4.3.7 job-state (type1 enum)
+
+ This REQUIRED attribute identifies the current state of the job.
+ Even though the IPP protocol defines seven values for job states
+ (plus the out-of-band 'unknown' value - see Section 4.1),
+ implementations only need to support those states which are
+ appropriate for the particular implementation. In other words, a
+ Printer supports only those job states implemented by the output
+ device and available to the Printer object implementation.
+
+ Standard enum values are:
+
+ Values Symbolic Name and Description
+
+ '3' 'pending': The job is a candidate to start processing, but is
+ not yet processing.
+
+ '4' 'pending-held': The job is not a candidate for processing for
+ any number of reasons but will return to the 'pending'
+ state as soon as the reasons are no longer present. The
+ job's "job-state-reason" attribute MUST indicate why the
+ job is no longer a candidate for processing.
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 109]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ '5' 'processing': One or more of:
+
+ 1. the job is using, or is attempting to use, one or
+ more purely software processes that are analyzing,
+ creating, or interpreting a PDL, etc.,
+ 2. the job is using, or is attempting to use, one or
+ more hardware devices that are interpreting a PDL, making
+ marks on a medium, and/or performing finishing, such as
+ stapling, etc.,
+ 3. the Printer object has made the job ready for
+ printing, but the output device is not yet printing it,
+ either because the job hasn't reached the output device
+ or because the job is queued in the output device or some
+ other spooler, awaiting the output device to print it.
+
+ When the job is in the 'processing' state, the entire job
+ state includes the detailed status represented in the
+ Printer object's "printer-state", "printer-state-
+ reasons", and "printer-state-message" attributes.
+
+ Implementations MAY, though they NEED NOT, include
+ additional values in the job's "job-state-reasons"
+ attribute to indicate the progress of the job, such as
+ adding the 'job-printing' value to indicate when the
+ output device is actually making marks on paper and/or
+ the 'processing-to-stop-point' value to indicate that the
+ IPP object is in the process of canceling or aborting the
+ job. Most implementations won't bother with this nuance.
+
+ '6' 'processing-stopped': The job has stopped while processing
+ for any number of reasons and will return to the
+ 'processing' state as soon as the reasons are no longer
+ present.
+
+ The job's "job-state-reason" attribute MAY indicate why
+ the job has stopped processing. For example, if the
+ output device is stopped, the 'printer-stopped' value MAY
+ be included in the job's "job-state-reasons" attribute.
+
+ Note: When an output device is stopped, the device
+ usually indicates its condition in human readable form
+ locally at the device. A client can obtain more complete
+ device status remotely by querying the Printer object's
+ "printer-state", "printer-state-reasons" and "printer-
+ state-message" attributes.
+
+ '7' 'canceled': The job has been canceled by a Cancel-Job
+ operation and the Printer object has completed canceling
+
+
+
+Hastings, et al. Standards Track [Page 110]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ the job and all job status attributes have reached their
+ final values for the job. While the Printer object is
+ canceling the job, the job remains in its current state,
+ but the job's "job-state-reasons" attribute SHOULD
+ contain the 'processing-to-stop-point' value and one of
+ the 'canceled-by-user', 'canceled-by-operator', or
+ 'canceled-at-device' value. When the job moves to the
+ 'canceled' state, the 'processing-to-stop-point' value,
+ if present, MUST be removed, but the 'canceled-by-xxx',
+ if present, MUST remain.
+
+ '8' 'aborted': The job has been aborted by the system, usually
+ while the job was in the 'processing' or 'processing-
+ stopped' state and the Printer has completed aborting the
+ job and all job status attributes have reached their
+ final values for the job. While the Printer object is
+ aborting the job, the job remains in its current state,
+ but the job's "job-state-reasons" attribute SHOULD
+ contain the 'processing-to-stop-point' and 'aborted-by-
+ system' values. When the job moves to the 'aborted'
+ state, the 'processing-to-stop-point' value, if present,
+ MUST be removed, but the 'aborted-by-system' value, if
+ present, MUST remain.
+
+ '9' 'completed': The job has completed successfully or with
+ warnings or errors after processing and all of the job
+ media sheets have been successfully stacked in the
+ appropriate output bin(s) and all job status attributes
+ have reached their final values for the job. The job's
+ "job-state-reasons" attribute SHOULD contain one of:
+ 'completed-successfully', 'completed-with-warnings', or
+ 'completed-with-errors' values.
+
+ The final value for this attribute MUST be one of: 'completed',
+ 'canceled', or 'aborted' before the Printer removes the job
+ altogether. The length of time that jobs remain in the 'canceled',
+ 'aborted', and 'completed' states depends on implementation. See
+ section 4.3.7.2.
+
+ The following figure shows the normal job state transitions.
+
+ +----> canceled
+ /
+ +----> pending --------> processing ---------+------> completed
+ | ^ ^ \
+ --->+ | | +----> aborted
+ | v v /
+ +----> pending-held processing-stopped ---+
+
+
+
+Hastings, et al. Standards Track [Page 111]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Normally a job progresses from left to right. Other state
+ transitions are unlikely, but are not forbidden. Not shown are the
+ transitions to the 'canceled' state from the 'pending', 'pending-
+ held', and 'processing-stopped' states.
+
+ Jobs reach one of the three terminal states: 'completed', 'canceled',
+ or 'aborted', after the jobs have completed all activity, including
+ stacking output media, after the jobs have completed all activity,
+ and all job status attributes have reached their final values for the
+ job.
+
+4.3.7.1 Forwarding Servers
+
+ As with all other IPP attributes, if the implementation cannot
+ determine the correct value for this attribute, it SHOULD respond
+ with the out-of-band value 'unknown' (see section 4.1) rather than
+ try to guess at some possibly incorrect value and give the end user
+ the wrong impression about the state of the Job object. For example,
+ if the implementation is just a gateway into some printing system
+ from which it can normally get status, but temporarily is unable,
+ then the implementation should return the 'unknown' value. However,
+ if the implementation is a gateway to a printing system that never
+ provides detailed status about the print job, the implementation MAY
+ set the IPP Job object's state to 'completed', provided that it also
+ sets the 'queued-in-device' value in the job's "job-state-reasons"
+ attribute (see section 4.3.8).
+
+4.3.7.2 Partitioning of Job States
+
+ This section partitions the 7 job states into phases: Job Not
+ Completed, Job Retention, Job History, and Job Removal. This section
+ also explains the 'job-restartable' value of the "job-state-reasons"
+ Job Description attribute for use with the Restart-Job operation.
+
+ Job Not Completed: When a job is in the 'pending', 'pending-held',
+ 'processing', or 'processing-stopped' states, the job is not
+ completed.
+
+ Job Retention: When a job enters one of the three terminal job
+ states: 'completed', 'canceled', or 'aborted', the IPP Printer
+ object MAY "retain" the job in a restartable condition for an
+ implementation-defined time period. This time period MAY be zero
+ seconds and MAY depend on the terminal job state. This phase is
+ called Job Retention. While in the Job Retention phase, the job's
+ document data is retained and a client may restart the job using the
+ Restart-Job operation. If the IPP object supports the Restart-Job
+
+
+
+
+
+Hastings, et al. Standards Track [Page 112]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ operation, then it SHOULD indicate that the job is restartable by
+ adding the 'job-restartable' value to the job's "job-state-reasons"
+ attribute (see Section 4.3.8) during the Job Retention phase.
+
+ Job History: After the Job Retention phase expires for a job, the
+ Printer object deletes the document data for the job and the job
+ becomes part of the Job History. The Printer object MAY also delete
+ any number of the job attributes. Since the job is no longer
+ restartable, the Printer object MUST remove the 'job-restartable'
+ value from the job's "job-state-reasons" attribute, if present.
+
+ Job Removal: After the job has remained in the Job History for an
+ implementation-defined time, such as when the number of jobs exceeds
+ a fixed number or after a fixed time period (which MAY be zero
+ seconds), the IPP Printer removes the job from the system.
+
+ Using the Get-Jobs operation and supplying the 'not-completed' value
+ for the "which-jobs" operation attribute, a client is requesting jobs
+ in the Job Not Completed phase. Using the Get-Jobs operation and
+ supplying the 'completed' value for the "which-jobs" operation
+ attribute, a client is requesting jobs in the Job Retention and Job
+ History phases. Using the Get-Job-Attributes operation, a client is
+ requesting a job in any phase except Job Removal. After Job Removal,
+ the Get-Job-Attributes and Get-Jobs operations no longer are capable
+ of returning any information about a job.
+
+4.3.8 job-state-reasons (1setOf type2 keyword)
+
+ This REQUIRED attribute provides additional information about the
+ job's current state, i.e., information that augments the value of the
+ job's "job-state" attribute.
+
+ These values MAY be used with any job state or states for which the
+ reason makes sense. Some of these value definitions indicate
+ conformance requirements; the rest are OPTIONAL. Furthermore, when
+ implemented, the Printer MUST return these values when the reason
+ applies and MUST NOT return them when the reason no longer applies
+ whether the value of the Job's "job-state" attribute changed or not.
+ When the Job does not have any reasons for being in its current
+ state, the value of the Job's "job-state-reasons" attribute MUST be
+ 'none'.
+
+ Note: While values cannot be added to the 'job-state' attribute
+ without impacting deployed clients that take actions upon receiving
+ "job-state" values, it is the intent that additional "job-state-
+ reasons" values can be defined and registered without impacting such
+ deployed clients. In other words, the "job-state-reasons" attribute
+ is intended to be extensible.
+
+
+
+Hastings, et al. Standards Track [Page 113]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ The following standard keyword values are defined. For ease of
+ understanding, the values are presented in the order in which the
+ reasons are likely to occur (if implemented), starting with the
+ 'job-incoming' value:
+
+ 'none': There are no reasons for the job's current state. This
+ state reason is semantically equivalent to "job-state-reasons"
+ without any value and MUST be used when there is no other
+ value, since the 1setOf attribute syntax requires at least one
+ value.
+ 'job-incoming': Either (1) the Printer has accepted the Create-
+ Job operation and is expecting additional Send-Document and/or
+ Send-URI operations, or (2) the Printer is retrieving/accepting
+ document data as a result of a Print-Job, Print-URI, Send-
+ Document or Send-URI operation.
+ 'job-data-insufficient': The Create-Job operation has been
+ accepted by the Printer, but the Printer is expecting
+ additional document data before it can move the job into the
+ 'processing' state. If a Printer starts processing before it
+ has received all data, the Printer removes the 'job-data-
+ insufficient' reason, but the 'job-incoming' remains. If a
+ Printer starts processing after it has received all data, the
+ Printer removes the 'job-data-insufficient' reason and the
+ 'job-incoming' at the same time.
+ 'document-access-error': After accepting a Print-URI or Send-URI
+ request, the Printer could not access one or more documents
+ passed by reference. This reason is intended to cover any file
+ access problem, including file does not exist and access denied
+ because of an access control problem. The Printer MAY also
+ indicate the document access error using the "job-document-
+ access-errors" Job Description attribute (see section 4.3.11).
+ Whether the Printer aborts the job and moves the job to the
+ 'aborted' job state or prints all documents that are accessible
+ and moves the job to the 'completed' job state and adds the
+ 'completed-with-errors' value in the job's "job-state-reasons"
+ attribute depends on implementation and/or site policy. This
+ value SHOULD be supported if the Print-URI or Send-URI
+ operations are supported.
+ 'submission-interrupted': The job was not completely submitted
+ for some unforeseen reason, such as: (1) the Printer has
+ crashed before the job was closed by the client, (2) the
+ Printer or the document transfer method has crashed in some
+ non-recoverable way before the document data was entirely
+ transferred to the Printer, (3) the client crashed or failed to
+ close the job before the time-out period. See section 4.4.31.
+ 'job-outgoing': The Printer is transmitting the job to the output
+ device.
+
+
+
+
+Hastings, et al. Standards Track [Page 114]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 'job-hold-until-specified': The value of the job's "job-hold-
+ until" attribute was specified with a time period that is still
+ in the future. The job MUST NOT be a candidate for processing
+ until this reason is removed and there are no other reasons to
+ hold the job. This value SHOULD be supported if the "job-
+ hold-until" Job Template attribute is supported.
+ 'resources-are-not-ready': At least one of the resources needed
+ by the job, such as media, fonts, resource objects, etc., is
+ not ready on any of the physical printer's for which the job is
+ a candidate. This condition MAY be detected when the job is
+ accepted, or subsequently while the job is pending or
+ processing, depending on implementation. The job may remain in
+ its current state or be moved to the 'pending-held' state,
+ depending on implementation and/or job scheduling policy.
+ 'printer-stopped-partly': The value of the Printer's "printer-
+ state-reasons" attribute contains the value 'stopped-partly'.
+ 'printer-stopped': The value of the Printer's "printer-state"
+ attribute is 'stopped'.
+ 'job-interpreting': Job is in the 'processing' state, but more
+ specifically, the Printer is interpreting the document data.
+ 'job-queued': Job is in the 'processing' state, but more
+ specifically, the Printer has queued the document data.
+ 'job-transforming': Job is in the 'processing' state, but more
+ specifically, the Printer is interpreting document data and
+ producing another electronic representation.
+ 'job-queued-for-marker': Job is in any of the 'pending-held',
+ 'pending', or 'processing' states, but more specifically, the
+ Printer has completed enough processing of the document to be
+ able to start marking and the job is waiting for the marker.
+ Systems that require human intervention to release jobs using
+ the Release-Job operation, put the job into the 'pending-held'
+ job state. Systems that automatically select a job to use the
+ marker put the job into the 'pending' job state or keep the
+ job in the 'processing' job state while waiting for the marker,
+ depending on implementation. All implementations put the job
+ into (or back into) the 'processing' state when marking does
+ begin.
+ 'job-printing': The output device is marking media. This value is
+ useful for Printers which spend a great deal of time processing
+ (1) when no marking is happening and then want to show that
+ marking is now happening or (2) when the job is in the process
+ of being canceled or aborted while the job remains in the
+ 'processing' state, but the marking has not yet stopped so that
+ impression or sheet counts are still increasing for the job.
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 115]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 'job-canceled-by-user': The job was canceled by the owner of the
+ job using the Cancel-Job request, i.e., by a user whose
+ authenticated identity is the same as the value of the
+ originating user that created the Job object, or by some other
+ authorized end-user, such as a member of the job owner's
+ security group. This value SHOULD be supported.
+ 'job-canceled-by-operator': The job was canceled by the operator
+ using the Cancel-Job request, i.e., by a user who has been
+ authenticated as having operator privileges (whether local or
+ remote). If the security policy is to allow anyone to cancel
+ anyone's job, then this value may be used when the job is
+ canceled by other than the owner of the job. For such a
+ security policy, in effect, everyone is an operator as far as
+ canceling jobs with IPP is concerned. This value SHOULD be
+ supported if the implementation permits canceling by other than
+ the owner of the job.
+ 'job-canceled-at-device': The job was canceled by an unidentified
+ local user, i.e., a user at a console at the device. This
+ value SHOULD be supported if the implementation supports
+ canceling jobs at the console.
+ 'aborted-by-system': The job (1) is in the process of being
+ aborted, (2) has been aborted by the system and placed in the
+ 'aborted' state, or (3) has been aborted by the system and
+ placed in the 'pending-held' state, so that a user or operator
+ can manually try the job again. This value SHOULD be
+ supported.
+ 'unsupported-compression': The job was aborted by the system
+ because the Printer determined while attempting to decompress
+ the document-data's that the compression is actually not among
+ those supported by the Printer. This value MUST be supported,
+ since "compressions is a REQUIRED operation attribute.
+ 'compression-error': The job was aborted by the system because the
+ Printer encountered an error in the document-data while
+ decompressing it. If the Printer posts this reason, the
+ document-data has already passed any tests that would have led
+ to the 'unsupported-compression' job-state-reason.
+ 'unsupported-document-format': The job was aborted by the system
+ because the document-data's document-format is not among those
+ supported by the Printer. If the client specifies the
+ document-format as 'application/octet-stream', the printer MAY
+ abort the job and post this reason even though the format is a
+ member of the "document-format-supported" printer attribute,
+ but not among the auto-sensed document-formats. This value
+ MUST be supported, since "document-format" is a REQUIRED
+ operation attribute.
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 116]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 'document-format-error': The job was aborted by the system because
+ the Printer encountered an error in the document-data while
+ processing it. If the Printer posts this reason, the
+ document-data has already passed any tests that would have led
+ to the 'unsupported-document-format' job-state-reason.
+ 'processing-to-stop-point': The requester has issued a Cancel-Job
+ operation or the Printer object has aborted the job, but is
+ still performing some actions on the job until a specified stop
+ point occurs or job termination/cleanup is completed.
+
+ If the implementation requires some measurable time to cancel
+ the job in the 'processing' or 'processing-stopped' job states,
+ the IPP object MUST use this value to indicate that the Printer
+ object is still performing some actions on the job while the
+ job remains in the 'processing' or 'processing-stopped' state.
+ After all the job's job description attributes have stopped
+ incrementing, the Printer object moves the job from the
+ 'processing' state to the 'canceled' or
+ 'aborted' job states.
+
+ 'service-off-line': The Printer is off-line and accepting no
+ jobs. All 'pending' jobs are put into the 'pending-held'
+ state. This situation could be true if the service's or
+ document transform's input is impaired or broken.
+ 'job-completed-successfully': The job completed successfully.
+ This value SHOULD be supported.
+ 'job-completed-with-warnings': The job completed with warnings.
+ This value SHOULD be supported if the implementation detects
+ warnings.
+ 'job-completed-with-errors': The job completed with errors (and
+ possibly warnings too). This value SHOULD be supported if the
+ implementation detects errors.
+ 'job-restartable' - This job is retained (see section 4.3.7.2) and
+ is currently able to be restarted using the Restart-Job
+ operation (see section 3.3.7). If 'job-restartable' is a value
+ of the job's 'job-state-reasons' attribute, then the IPP object
+ MUST accept a Restart-Job operation for that job. This value
+ SHOULD be supported if the Restart-Job operation is supported.
+ 'queued-in-device': The job has been forwarded to a device or
+ print system that is unable to send back status. The Printer
+ sets the job's "job-state " attribute to 'completed' and adds
+ the 'queued-in-device' value to the job's "job-state-reasons"
+ attribute to indicate that the Printer has no additional
+ information about the job and never will have any better
+ information. See section 4.3.7.1.
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 117]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+4.3.9 job-state-message (text(MAX))
+
+ This attribute specifies information about the "job-state" and "job-
+ state-reasons" attributes in human readable text. If the Printer
+ object supports this attribute, the Printer object MUST be able to
+ generate this message in any of the natural languages identified by
+ the Printer's "generated-natural-language-supported" attribute (see
+ the "attributes-natural-language" operation attribute specified in
+ Section 3.1.4.1).
+
+ The value SHOULD NOT contain additional information not contained in
+ the values of the "job-state" and "job-states-reasons" attributes,
+ such as interpreter error information. Otherwise, application
+ programs might attempt to parse the (localized text). For such
+ additional information such as interpreter errors for application
+ program consumption or specific document access errors, new
+ attributes with keyword values, needs to be developed and registered.
+
+4.3.10 job-detailed-status-messages (1setOf text(MAX))
+
+ This attribute specifies additional detailed and technical
+ information about the job. The Printer NEED NOT localize the
+ message(s), since they are intended for use by the system
+ administrator or other experienced technical persons. Localization
+ might obscure the technical meaning of such messages. Clients MUST
+ NOT attempt to parse the value of this attribute. See "job-
+ document-access-errors" (section 4.3.11) for additional errors that a
+ program can process.
+
+4.3.11 job-document-access-errors (1setOf text(MAX))
+
+ This attribute provides additional information about each document
+ access error for this job encountered by the Printer after it
+ returned a response to the Print-URI or Send-URI operation and
+ subsequently attempted to access document(s) supplied in the Print-
+ URI or Send-URI operation. For errors in the protocol that is
+ identified by the URI scheme in the "document-uri" operation
+ attribute, such as 'http:' or 'ftp:', the error code is returned in
+ parentheses, followed by the URI. For example:
+
+ (404) http://ftp.pwg.org/pub/pwg/ipp/new_MOD/ipp-model-v11.pdf
+
+ Most Internet protocols use decimal error codes (unlike IPP), so the
+ ASCII error code representation is in decimal.
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 118]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+4.3.12 number-of-documents (integer(0:MAX))
+
+ This attribute indicates the number of documents in the job, i.e.,
+ the number of Send-Document, Send-URI, Print-Job, or Print-URI
+ operations that the Printer has accepted for this job, regardless of
+ whether the document data has reached the Printer object or not.
+
+ Implementations supporting the OPTIONAL Create-Job/Send-
+ Document/Send-URI operations SHOULD support this attribute so that
+ clients can query the number of documents in each job.
+
+4.3.13 output-device-assigned (name(127))
+
+ This attribute identifies the output device to which the Printer
+ object has assigned this job. If an output device implements an
+ embedded Printer object, the Printer object NEED NOT set this
+ attribute. If a print server implements a Printer object, the value
+ MAY be empty (zero- length string) or not returned until the Printer
+ object assigns an output device to the job. This attribute is
+ particularly useful when a single Printer object supports multiple
+ devices (so called "fan-out" - see section 2.1).
+
+4.3.14 Event Time Job Description Attributes
+
+ This section defines the Job Description attributes that indicate the
+ time at which certain events occur for a job. If the job event has
+ not yet occurred, then the IPP object MUST return the 'no-value'
+ out-of-band value (see the beginning of Section 4.1). The "time-at-
+ xxx(integer)" attributes represent time as an 'integer' representing
+ the number of seconds since the device was powered up (informally
+ called "time ticks"). The "date-time-at-xxx(dateTime)" attributes
+ represent time as 'dateTime' representing date and time (including an
+ offset from UTC).
+
+ In order to populate these attributes, the Printer object copies the
+ value(s) of the following Printer Description attributes at the time
+ the event occurs:
+
+ 1. the value in the Printer's "printer-up-time" attribute for the
+ "time-at-xxx(integer)" attributes
+
+ 2. the value in the Printer's "printer-current-time" attribute for
+ the "date-time-at-xxx(dateTime)" attributes.
+
+ If the Printer resets its "printer-up-time" attribute to 1 on power-
+ up (see section 4.4.29) and has persistent jobs, then it MUST change
+ all of jobs' "time-at-xxx(integer)" (time tick) job attributes whose
+ events have occurred either to:
+
+
+
+Hastings, et al. Standards Track [Page 119]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 1. 0 to indicate that the event happened before the most recent
+ power up OR
+
+ 2. the negative of the number of seconds before the most recent
+ power-up that the event took place, though the negative number
+ NEED NOT reflect the exact number of seconds.
+
+ If a client queries a "time-at-xxx(integer)" time tick Job attribute
+ and finds the value to be 0 or negative, the client MUST assume that
+ the event occurred in some life other than the Printer's current
+ life.
+
+ Note: A Printer does not change the values of any "date-time-at-
+ xxx(dateTime)" job attributes on power-up.
+
+4.3.14.1 time-at-creation (integer(MIN:MAX))
+
+ This REQUIRED attribute indicates the time at which the Job object
+ was created.
+
+4.3.14.2 time-at-processing (integer(MIN:MAX))
+
+ This REQUIRED attribute indicates the time at which the Job object
+ first began processing after the create operation or the most recent
+ Restart-Job operation. The out-of-band 'no-value' value is returned
+ if the job has not yet been in the 'processing' state (see the
+ beginning of Section 4.1).
+
+4.3.14.3 time-at-completed (integer(MIN:MAX))
+
+ This REQUIRED attribute indicates the time at which the Job object
+ completed (or was canceled or aborted). The out-of-band 'no-value'
+ value is returned if the job has not yet completed, been canceled, or
+ aborted (see the beginning of Section 4.1).
+
+4.3.14.4 job-printer-up-time (integer(1:MAX))
+
+ This REQUIRED Job Description attribute indicates the amount of time
+ (in seconds) that the Printer implementation has been up and running.
+ This attribute is an alias for the "printer-up-time" Printer
+ Description attribute (see Section 4.4.29).
+
+ A client MAY request this attribute in a Get-Job-Attributes or Get-
+ Jobs request and use the value returned in combination with other
+ requested Event Time Job Description Attributes in order to display
+ time attributes to a user. The difference between this attribute and
+ the 'integer' value of a "time-at-xxx" attribute is the number of
+
+
+
+
+Hastings, et al. Standards Track [Page 120]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ seconds ago that the "time-at-xxx" event occurred. A client can
+ compute the wall-clock time at which the "time-at-xxx" event occurred
+ by subtracting this difference from the client's wall-clock time.
+
+4.3.14.5 date-time-at-creation (dateTime)
+
+ This attribute indicates the date and time at which the Job object
+ was created.
+
+4.3.14.6 date-time-at-processing (dateTime)
+
+ This attribute indicates the date and time at which the Job object
+ first began processing after the create operation or the most recent
+ Restart-Job operation.
+
+4.3.14.7 date-time-at-completed (dateTime)
+
+ This attribute indicates the date and time at which the Job object
+ completed (or was canceled or aborted).
+
+4.3.15 number-of-intervening-jobs (integer(0:MAX))
+
+ This attribute indicates the number of jobs that are "ahead" of this
+ job in the relative chronological order of expected time to complete
+ (i.e., the current scheduled order). For efficiency, it is only
+ necessary to calculate this value when an operation is performed that
+ requests this attribute.
+
+4.3.16 job-message-from-operator (text(127))
+
+ This attribute provides a message from an operator, system
+ administrator or "intelligent" process to indicate to the end user
+ the reasons for modification or other management action taken on a
+ job.
+
+4.3.17 Job Size Attributes
+
+ This sub-section defines job attributes that describe the size of the
+ job. These attributes are not intended to be counters; they are
+ intended to be useful routing and scheduling information if known.
+ For these attributes, the Printer object may try to compute the value
+ if it is not supplied in the create request. Even if the client does
+ supply a value for these three attributes in the create request, the
+ Printer object MAY choose to change the value if the Printer object
+ is able to compute a value which is more accurate than the client
+ supplied value. The Printer object may be able to determine the
+ correct value for these attributes either right at job submission
+ time or at any later point in time.
+
+
+
+Hastings, et al. Standards Track [Page 121]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+4.3.17.1 job-k-octets (integer(0:MAX))
+
+ This attribute specifies the total size of the document(s) in K
+ octets, i.e., in units of 1024 octets requested to be processed in
+ the job. The value MUST be rounded up, so that a job between 1 and
+ 1024 octets MUST be indicated as being 1, 1025 to 2048 MUST be 2,
+ etc.
+
+ This value MUST NOT include the multiplicative factors contributed by
+ the number of copies specified by the "copies" attribute, independent
+ of whether the device can process multiple copies without making
+ multiple passes over the job or document data and independent of
+ whether the output is collated or not. Thus the value is independent
+ of the implementation and indicates the size of the document(s)
+ measured in K octets independent of the number of copies.
+
+ This value MUST also not include the multiplicative factor due to a
+ copies instruction embedded in the document data. If the document
+ data actually includes replications of the document data, this value
+ will include such replication. In other words, this value is always
+ the size of the source document data, rather than a measure of the
+ hardcopy output to be produced.
+
+4.3.17.2 job-impressions (integer(0:MAX))
+
+ This attribute specifies the total size in number of impressions of
+ the document(s) being submitted (see the definition of impression in
+ section 12.2.5).
+
+ As with "job-k-octets", this value MUST NOT include the
+ multiplicative factors contributed by the number of copies specified
+ by the "copies" attribute, independent of whether the device can
+ process multiple copies without making multiple passes over the job
+ or document data and independent of whether the output is collated or
+ not. Thus the value is independent of the implementation and
+ reflects the size of the document(s) measured in impressions
+ independent of the number of copies.
+
+ As with "job-k-octets", this value MUST also not include the
+ multiplicative factor due to a copies instruction embedded in the
+ document data. If the document data actually includes replications
+ of the document data, this value will include such replication. In
+ other words, this value is always the number of impressions in the
+ source document data, rather than a measure of the number of
+ impressions to be produced by the job.
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 122]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+4.3.17.3 job-media-sheets (integer(0:MAX))
+
+ This attribute specifies the total number of media sheets to be
+ produced for this job.
+
+ Unlike the "job-k-octets" and the "job-impressions" attributes, this
+ value MUST include the multiplicative factors contributed by the
+ number of copies specified by the "copies" attribute and a 'number of
+ copies' instruction embedded in the document data, if any. This
+ difference allows the system administrator to control the lower and
+ upper bounds of both (1) the size of the document(s) with "job-k-
+ octets-supported" and "job-impressions-supported" and (2) the size of
+ the job with "job-media-sheets-supported".
+
+4.3.18 Job Progress Attributes
+
+ This sub-section defines job attributes that describe the progress of
+ the job. These attributes are intended to be counters. That is, the
+ value for a job that has not started processing MUST be 0. When the
+ job's "job-state" is 'processing' or 'processing-stopped', this value
+ is intended to contain the amount of the job that has been processed
+ to the time at which the attributes are requested. When the job
+ enters the 'completed', 'canceled', or 'aborted' states, these values
+ are the final values for the job.
+
+4.3.18.1 job-k-octets-processed (integer(0:MAX))
+
+ This attribute specifies the total number of octets processed in K
+ octets, i.e., in units of 1024 octets so far. The value MUST be
+ rounded up, so that a job between 1 and 1024 octets inclusive MUST be
+ indicated as being 1, 1025 to 2048 inclusive MUST be 2, etc.
+
+ For implementations where multiple copies are produced by the
+ interpreter with only a single pass over the data, the final value
+ MUST be equal to the value of the "job-k-octets" attribute. For
+ implementations where multiple copies are produced by the interpreter
+ by processing the data for each copy, the final value MUST be a
+ multiple of the value of the "job-k-octets" attribute.
+
+4.3.18.2 job-impressions-completed (integer(0:MAX))
+
+ This job attribute specifies the number of impressions completed for
+ the job so far. For printing devices, the impressions completed
+ includes interpreting, marking, and stacking the output.
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 123]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+4.3.18.3 job-media-sheets-completed (integer(0:MAX))
+
+ This job attribute specifies the media-sheets completed marking and
+ stacking for the entire job so far whether those sheets have been
+ processed on one side or on both.
+
+4.3.19 attributes-charset (charset)
+
+ This REQUIRED attribute is populated using the value in the client
+ supplied "attributes-charset" attribute in the create request. It
+ identifies the charset (coded character set and encoding method) used
+ by any Job attributes with attribute syntax 'text' and 'name' that
+ were supplied by the client in the create request. See Section 3.1.4
+ for a complete description of the "attributes-charset" operation
+ attribute.
+
+ This attribute does not indicate the charset in which the 'text' and
+ 'name' values are stored internally in the Job object. The internal
+ charset is implementation-defined. The IPP object MUST convert from
+ whatever the internal charset is to that being requested in an
+ operation as specified in Section 3.1.4.
+
+4.3.20 attributes-natural-language (naturalLanguage)
+
+ This REQUIRED attribute is populated using the value in the client
+ supplied "attributes-natural-language" attribute in the create
+ request. It identifies the natural language used for any Job
+ attributes with attribute syntax 'text' and 'name' that were supplied
+ by the client in the create request. See Section 3.1.4 for a
+ complete description of the "attributes-natural-language" operation
+ attribute. See Sections 4.1.1.2 and 4.1.2.2 for how a Natural
+ Language Override may be supplied explicitly for each 'text' and
+ 'name' attribute value that differs from the value identified by the
+ "attributes-natural-language" attribute.
+
+4.4 Printer Description Attributes
+
+ These attributes form the attribute group called "printer-
+ description". The following table summarizes these attributes, their
+ syntax, and whether or not they are REQUIRED for a Printer object to
+ support. If they are not indicated as REQUIRED, they are OPTIONAL.
+ The maximum size in octets for 'text' and 'name' attributes is
+ indicated in parenthesizes.
+
+ Note: How these attributes are set by an Administrator is outside the
+ scope of this IPP/1.1 document.
+
+
+
+
+
+Hastings, et al. Standards Track [Page 124]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ +----------------------------+---------------------------+-----------+
+ | Attribute | Syntax | REQUIRED? |
+ +----------------------------+---------------------------+-----------+
+ | printer-uri-supported | 1setOf uri | REQUIRED |
+ +----------------------------+---------------------------+-----------+
+ | uri-security-supported | 1setOf type2 keyword | REQUIRED |
+ +----------------------------+---------------------------+-----------+
+ | uri-authentication- | 1setOf type2 keyword | REQUIRED |
+ | supported | | |
+ +----------------------------+---------------------------+-----------+
+ | printer-name | name (127) | REQUIRED |
+ +----------------------------+---------------------------+-----------+
+ | printer-location | text (127) | |
+ +----------------------------+---------------------------+-----------+
+ | printer-info | text (127) | |
+ +----------------------------+---------------------------+-----------+
+ | printer-more-info | uri | |
+ +----------------------------+---------------------------+-----------+
+ | printer-driver-installer | uri | |
+ +----------------------------+---------------------------+-----------+
+ | printer-make-and-model | text (127) | |
+ +----------------------------+---------------------------+-----------+
+ | printer-more-info- | uri | |
+ | manufacturer | | |
+ +----------------------------+---------------------------+-----------+
+ | printer-state | type1 enum | REQUIRED |
+ +----------------------------+---------------------------+-----------+
+ | printer-state-reasons | 1setOf type2 keyword | REQUIRED |
+ +----------------------------+---------------------------+-----------+
+ | printer-state-message | text (MAX) | |
+ +----------------------------+---------------------------+-----------+
+ | ipp-versions-supported | 1setOf type2 keyword | REQUIRED |
+ +----------------------------+---------------------------+-----------+
+ | operations-supported | 1setOf type2 enum | REQUIRED |
+ +----------------------------+---------------------------+-----------+
+ | multiple-document-jobs- | boolean | |
+ | supported | | |
+ +----------------------------+---------------------------+-----------+
+ | charset-configured | charset | REQUIRED |
+ +----------------------------+---------------------------+-----------+
+ | charset-supported | 1setOf charset | REQUIRED |
+ +----------------------------+---------------------------+-----------+
+ | natural-language-configured| naturalLanguage | REQUIRED |
+ +----------------------------+---------------------------+-----------+
+ | generated-natural-language-| 1setOf naturalLanguage | REQUIRED |
+ | supported | | |
+ +----------------------------+---------------------------+-----------+
+ | document-format-default | mimeMediaType | REQUIRED |
+
+
+
+Hastings, et al. Standards Track [Page 125]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ +----------------------------+---------------------------+-----------+
+ | document-format-supported | 1setOf mimeMediaType | REQUIRED |
+ +----------------------------+---------------------------+-----------+
+ | printer-is-accepting-jobs | boolean | REQUIRED |
+ +----------------------------+---------------------------+-----------+
+ | queued-job-count | integer (0:MAX) | REQUIRED |
+ +----------------------------+---------------------------+-----------+
+ | printer-message-from- | text (127) | |
+ | operator | | |
+ +----------------------------+---------------------------+-----------+
+ | color-supported | boolean | |
+ +----------------------------+---------------------------+-----------+
+ | reference-uri-schemes- | 1setOf uriScheme | |
+ | supported | | |
+ +----------------------------+---------------------------+-----------+
+ | pdl-override-supported | type2 keyword | REQUIRED |
+ +----------------------------+---------------------------+-----------+
+ | printer-up-time | integer (1:MAX) | REQUIRED |
+ +----------------------------+---------------------------+-----------+
+ | printer-current-time | dateTime | |
+ +----------------------------+---------------------------+-----------+
+ | multiple-operation-time-out| integer (1:MAX) | |
+ +----------------------------+---------------------------+-----------+
+ | compression-supported | 1setOf type3 keyword | REQUIRED |
+ +----------------------------+---------------------------+-----------+
+ | job-k-octets-supported | rangeOfInteger (0:MAX) | |
+ +----------------------------+---------------------------+-----------+
+ | job-impressions-supported | rangeOfInteger (0:MAX) | |
+ +----------------------------+---------------------------+-----------+
+ | job-media-sheets-supported | rangeOfInteger (0:MAX) | |
+ +----------------------------+---------------------------+-----------+
+ | pages-per-minute | integer(0:MAX) | |
+ +----------------------------+---------------------------+-----------+
+ | pages-per-minute-color | integer(0:MAX) | |
+ +----------------------------+---------------------------+-----------+
+
+4.4.1 printer-uri-supported (1setOf uri)
+
+ This REQUIRED Printer attribute contains at least one URI for the
+ Printer object. It OPTIONALLY contains more than one URI for the
+ Printer object. An administrator determines a Printer object's
+ URI(s) and configures this attribute to contain those URIs by some
+ means outside the scope of this IPP/1.1 document. The precise format
+ of this URI is implementation dependent and depends on the protocol.
+ See the next two sections for a description of the "uri-security-
+ supported" and "uri-authentication-supported" attributes, both of
+
+
+
+
+
+Hastings, et al. Standards Track [Page 126]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ which are the REQUIRED companion attributes to this "printer-uri-
+ supported" attribute. See section 2.4 on Printer object identity and
+ section 8.2 on security and URIs for more information.
+
+4.4.2 uri-authentication-supported (1setOf type2 keyword)
+
+ This REQUIRED Printer attribute MUST have the same cardinality
+ (contain the same number of values) as the "printer-uri-supported"
+ attribute. This attribute identifies the Client Authentication
+ mechanism associated with each URI listed in the "printer-uri-
+ supported" attribute. The Printer object uses the specified mechanism
+ to identify the authenticated user (see section 8.3). The "i th"
+ value in "uri-authentication-supported" corresponds to the "i th"
+ value in "printer-uri-supported" and it describes the authentication
+ mechanisms used by the Printer when accessed via that URI. See
+ [RFC2910] for more details on Client Authentication.
+
+ The following standard keyword values are defined:
+
+ 'none': There is no authentication mechanism associated with the
+ URI. The Printer object assumes that the authenticated user is
+ "anonymous".
+ 'requesting-user-name': When a client performs an operation whose
+ target is the associated URI, the Printer object assumes that
+ the authenticated user is specified by the "requesting-user-
+ name" Operation attribute (see section 8.3). If the
+ "requesting-user-name" attribute is absent in a request, the
+ Printer object assumes that the authenticated user is
+ "anonymous".
+ 'basic': When a client performs an operation whose target is the
+ associated URI, the Printer object challenges the client with
+ HTTP basic authentication [RFC2617]. The Printer object assumes
+ that the authenticated user is the name received via the basic
+ authentication mechanism.
+ 'digest': When a client performs an operation whose target is the
+ associated URI, the Printer object challenges the client with
+ HTTP digest authentication [RFC2617]. The Printer object
+ assumes that the authenticated user is the name received via
+ the digest authentication mechanism.
+ 'certificate': When a client performs an operation whose target is
+ the associated URI, the Printer object expects the client to
+ provide a certificate. The Printer object assumes that the
+ authenticated user is the textual name contained within the
+ certificate.
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 127]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+4.4.3 uri-security-supported (1setOf type2 keyword)
+
+ This REQUIRED Printer attribute MUST have the same cardinality
+ (contain the same number of values) as the "printer-uri-supported"
+ attribute. This attribute identifies the security mechanisms used
+ for each URI listed in the "printer-uri-supported" attribute. The "i
+ th" value in "uri-security-supported" corresponds to the "i th" value
+ in "printer-uri-supported" and it describes the security mechanisms
+ used for accessing the Printer object via that URI. See [RFC2910]
+ for more details on security mechanisms.
+
+ The following standard keyword values are defined:
+
+ 'none': There are no secure communication channel protocols in use
+ for the given URI.
+ 'ssl3': SSL3 [SSL] is the secure communications channel protocol
+ in use for the given URI.
+ 'tls': TLS [RFC2246] is the secure communications channel
+ protocol in use for the given URI.
+
+ This attribute is orthogonal to the definition of a Client
+ Authentication mechanism. Specifically, 'none' does not exclude
+ Client Authentication. See section 4.4.2.
+
+ Consider the following example. For a single Printer object, an
+ administrator configures the "printer-uri-supported", "uri-
+ authentication-supported" and "uri-security-supported" attributes as
+ follows:
+
+ "printer-uri-supported": 'xxx://acme.com/open-use-printer',
+ 'xxx://acme.com/restricted-use-printer',
+ 'xxx://acme.com/private-printer'
+ "uri-authentication-supported": 'none', 'digest', 'basic'
+ "uri-security-supported": 'none', 'none', 'tls'
+
+ Note: 'xxx' is not a valid scheme. See the IPP/1.1 "Transport and
+ Encoding" document [RFC2910] for the actual URI schemes to be used in
+ object target attributes.
+
+ In this case, one Printer object has three URIs.
+
+ - For the first URI, 'xxx://acme.com/open-use-printer', the value
+ 'none' in "uri-security-supported" indicates that there is no
+ secure channel protocol configured to run under HTTP. The value
+ of 'none' in "uri-authentication-supported" indicates that all
+ users are 'anonymous'. There will be no challenge and the
+ Printer will ignore "requesting-user-name".
+
+
+
+
+Hastings, et al. Standards Track [Page 128]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ - For the second URI, 'xxx://acme.com/restricted-use-printer', the
+ value 'none' in "uri-security-supported" indicates that there is
+ no secure channel protocol configured to run under HTTP. The
+ value of 'digest' in "uri-authentication-supported" indicates
+ that the Printer will issue a challenge and that the Printer
+ will use the name supplied by the digest mechanism to determine
+ the authenticated user (see section 8.3).
+ - For the third URI, 'xxx://acme.com/private-printer', the value
+ 'tls' in "uri-security-supported" indicates that TLS is being
+ used to secure the channel. The client SHOULD be prepared to
+ use TLS framing to negotiate an acceptable ciphersuite to use
+ while communicating with the Printer object. In this case, the
+ name implies the use of a secure communications channel, but the
+ fact is made explicit by the presence of the 'tls' value in
+ "uri-security-supported". The client does not need to resort to
+ understanding which security it must use by following naming
+ conventions or by parsing the URI to determine which security
+ mechanisms are implied. The value of 'basic' in "uri-
+ authentication-supported" indicates that the Printer will issue
+ a challenge and that the Printer will use the name supplied by
+ the digest mechanism to determine the authenticated user (see
+ section 8.3). Because this challenge occurs in a tls session,
+ the channel is secure.
+
+ It is expected that many IPP Printer objects will be configured to
+ support only one channel (either configured to use TLS access or not)
+ and only one authentication mechanism. Such Printer objects only have
+ one URI listed in the "printer-uri-supported" attribute. No matter
+ the configuration of the Printer object (whether it has only one URI
+ or more than one URI), a client MUST supply only one URI in the
+ target "printer-uri" operation attribute.
+
+4.4.4 printer-name (name(127))
+
+ This REQUIRED Printer attribute contains the name of the Printer
+ object. It is a name that is more end-user friendly than a URI. An
+ administrator determines a printer's name and sets this attribute to
+ that name. This name may be the last part of the printer's URI or it
+ may be unrelated. In non-US-English locales, a name may contain
+ characters that are not allowed in a URI.
+
+4.4.5 printer-location (text(127))
+
+ This Printer attribute identifies the location of the device. This
+ could include things like: "in Room 123A, second floor of building
+ XYZ".
+
+
+
+
+
+Hastings, et al. Standards Track [Page 129]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+4.4.6 printer-info (text(127))
+
+ This Printer attribute identifies the descriptive information about
+ this Printer object. This could include things like: "This printer
+ can be used for printing color transparencies for HR presentations",
+ or "Out of courtesy for others, please print only small (1-5 page)
+ jobs at this printer", or even "This printer is going away on July 1,
+ 1997, please find a new printer".
+
+4.4.7 printer-more-info (uri)
+
+ This Printer attribute contains a URI used to obtain more information
+ about this specific Printer object. For example, this could be an
+ HTTP type URI referencing an HTML page accessible to a Web Browser.
+ The information obtained from this URI is intended for end user
+ consumption. Features outside the scope of IPP can be accessed from
+ this URI. The information is intended to be specific to this printer
+ instance and site specific services (e.g. job pricing, services
+ offered, end user assistance). The device manufacturer may initially
+ populate this attribute.
+
+4.4.8 printer-driver-installer (uri)
+
+ This Printer attribute contains a URI to use to locate the driver
+ installer for this Printer object. This attribute is intended for
+ consumption by automata. The mechanics of print driver installation
+ is outside the scope of this IPP/1.1 document. The device
+ manufacturer may initially populate this attribute.
+
+4.4.9 printer-make-and-model (text(127))
+
+ This Printer attribute identifies the make and model of the device.
+ The device manufacturer may initially populate this attribute.
+
+4.4.10 printer-more-info-manufacturer (uri)
+
+ This Printer attribute contains a URI used to obtain more information
+ about this type of device. The information obtained from this URI is
+ intended for end user consumption. Features outside the scope of IPP
+ can be accessed from this URI (e.g., latest firmware, upgrades, print
+ drivers, optional features available, details on color support). The
+ information is intended to be germane to this printer without regard
+ to site specific modifications or services. The device manufacturer
+ may initially populate this attribute.
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 130]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+4.4.11 printer-state (type1 enum)
+
+ This REQUIRED Printer attribute identifies the current state of the
+ device. The "printer-state reasons" attribute augments the
+ "printer-state" attribute to give more detailed information about the
+ Printer in the given printer state.
+
+ A Printer object need only update this attribute before responding to
+ an operation which requests the attribute; the Printer object NEED
+ NOT update this attribute continually, since asynchronous event
+ notification is not part of IPP/1.1. A Printer NEED NOT implement
+ all values if they are not applicable to a given implementation.
+
+ The following standard enum values are defined:
+
+ Value Symbolic Name and Description
+
+ '3' 'idle': Indicates that new jobs can start processing without
+ waiting.
+ '4' 'processing': Indicates that jobs are processing; new jobs
+ will wait before processing.
+ '5' 'stopped': Indicates that no jobs can be processed and
+ intervention is required.
+
+ Values of "printer-state-reasons", such as 'spool-area-full' and
+ 'stopped-partly', MAY be used to provide further information.
+
+4.4.12 printer-state-reasons (1setOf type2 keyword)
+
+ This REQUIRED Printer attribute supplies additional detail about the
+ device's state. Some of the these value definitions indicate
+ conformance requirements; the rest are OPTIONAL.
+
+ Each keyword value MAY have a suffix to indicate its level of
+ severity. The three levels are: report (least severe), warning, and
+ error (most severe).
+
+ - '-report': This suffix indicates that the reason is a "report".
+ An implementation may choose to omit some or all reports. Some
+ reports specify finer granularity about the printer state;
+ others serve as a precursor to a warning. A report MUST contain
+ nothing that could affect the printed output.
+ - '-warning': This suffix indicates that the reason is a
+ "warning". An implementation may choose to omit some or all
+ warnings. Warnings serve as a precursor to an error. A warning
+ MUST contain nothing that prevents a job from completing, though
+ in some cases the output may be of lower quality.
+
+
+
+
+Hastings, et al. Standards Track [Page 131]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ - '-error': This suffix indicates that the reason is an "error".
+ An implementation MUST include all errors. If this attribute
+ contains one or more errors, printer MUST be in the stopped
+ state.
+
+ If the implementation does not add any one of the three suffixes, all
+ parties MUST assume that the reason is an "error".
+
+ If a Printer object controls more than one output device, each value
+ of this attribute MAY apply to one or more of the output devices. An
+ error on one output device that does not stop the Printer object as a
+ whole MAY appear as a warning in the Printer's "printer-state-reasons
+ attribute". If the "printer-state" for such a Printer has a value of
+ 'stopped', then there MUST be an error reason among the values in the
+ "printer-state-reasons" attribute.
+
+ The following standard keyword values are defined:
+
+ 'other': The device has detected an error other than one listed in
+ this document.
+ 'none': There are not reasons. This state reason is semantically
+ equivalent to "printer-state-reasons" without any value and
+ MUST be used, since the 1setOf attribute syntax requires at
+ least one value.
+ 'media-needed': A tray has run out of media.
+ 'media-jam': The device has a media jam.
+ 'moving-to-paused': Someone has paused the Printer object using
+ the Pause-Printer operation (see section 3.2.7) or other means,
+ but the device(s) are taking an appreciable time to stop.
+ Later, when all output has stopped, the "printer-state" becomes
+ 'stopped', and the 'paused' value replaces the 'moving-to-
+ paused' value in the "printer-state-reasons" attribute. This
+ value MUST be supported, if the Pause-Printer operation is
+ supported and the implementation takes significant time to
+ pause a device in certain circumstances.
+ 'paused': Someone has paused the Printer object using the Pause-
+ Printer operation (see section 3.2.7) or other means and the
+ Printer object's "printer-state" is 'stopped'. In this state,
+ a Printer MUST NOT produce printed output, but it MUST perform
+ other operations requested by a client. If a Printer had been
+ printing a job when the Printer was paused, the Printer MUST
+ resume printing that job when the Printer is no longer paused
+ and leave no evidence in the printed output of such a pause.
+ This value MUST be supported, if the Pause-Printer operation is
+ supported.
+ 'shutdown': Someone has removed a Printer object from service, and
+ the device may be powered down or physically removed. In this
+ state, a Printer object MUST NOT produce printed output, and
+
+
+
+Hastings, et al. Standards Track [Page 132]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ unless the Printer object is realized by a print server that is
+ still active, the Printer object MUST perform no other
+ operations requested by a client, including returning this
+ value. If a Printer object had been printing a job when it was
+ shutdown, the Printer NEED NOT resume printing that job when
+ the Printer is no longer shutdown. If the Printer resumes
+ printing such a job, it may leave evidence in the printed
+ output of such a shutdown, e.g. the part printed before the
+ shutdown may be printed a second time after the shutdown.
+ 'connecting-to-device': The Printer object has scheduled a job on
+ the output device and is in the process of connecting to a
+ shared network output device (and might not be able to actually
+ start printing the job for an arbitrarily long time depending
+ on the usage of the output device by other servers on the
+ network).
+ 'timed-out': The server was able to connect to the output device
+ (or is always connected), but was unable to get a response from
+ the output device.
+ 'stopping': The Printer object is in the process of stopping the
+ device and will be stopped in a while. When the device is
+ stopped, the Printer object will change the Printer object's
+ state to 'stopped'. The 'stopping-warning' reason is never an
+ error, even for a Printer with a single output device. When an
+ output-device ceases accepting jobs, the Printer will have this
+ reason while the output device completes printing.
+ 'stopped-partly': When a Printer object controls more than one
+ output device, this reason indicates that one or more output
+ devices are stopped. If the reason is a report, fewer than
+ half of the output devices are stopped. If the reason is a
+ warning, fewer than all of the output devices are stopped.
+ 'toner-low': The device is low on toner.
+ 'toner-empty': The device is out of toner.
+ 'spool-area-full': The limit of persistent storage allocated for
+ spooling has been reached. The Printer is temporarily unable
+ to accept more jobs. The Printer will remove this value when
+ it is able to accept more jobs. This value SHOULD be used by a
+ non-spooling Printer that only accepts one or a small number
+ jobs at a time or a spooling Printer that has filled the spool
+ space.
+ 'cover-open': One or more covers on the device are open.
+ 'interlock-open': One or more interlock devices on the printer are
+ unlocked.
+ 'door-open': One or more doors on the device are open.
+ 'input-tray-missing': One or more input trays are not in the
+ device.
+ 'media-low': At least one input tray is low on media.
+ 'media-empty': At least one input tray is empty.
+
+
+
+
+Hastings, et al. Standards Track [Page 133]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 'output-tray-missing': One or more output trays are not in the
+ device
+ 'output-area-almost-full': One or more output area is almost full
+ (e.g. tray, stacker, collator).
+ 'output-area-full': One or more output area is full. (e.g. tray,
+ stacker, collator)
+ 'marker-supply-low': The device is low on at least one marker
+ supply. (e.g. toner, ink, ribbon)
+ 'marker-supply-empty: The device is out of at least one marker
+ supply. (e.g. toner, ink, ribbon)
+ 'marker-waste-almost-full': The device marker supply waste
+ receptacle is almost full.
+ 'marker-waste-full': The device marker supply waste receptacle is
+ full.
+ 'fuser-over-temp': The fuser temperature is above normal.
+ 'fuser-under-temp': The fuser temperature is below normal.
+ 'opc-near-eol': The optical photo conductor is near end of life.
+ 'opc-life-over': The optical photo conductor is no longer
+ functioning.
+ 'developer-low': The device is low on developer.
+ 'developer-empty: The device is out of developer.
+ 'interpreter-resource-unavailable': An interpreter resource is
+ unavailable (i.e. font, form)
+
+4.4.13 printer-state-message (text(MAX))
+
+ This Printer attribute specifies information about the "printer-
+ state" and "printer-state-reasons" attributes in human readable text.
+ If the Printer object supports this attribute, the Printer object
+ MUST be able to generate this message in any of the natural languages
+ identified by the Printer's "generated-natural-language-supported"
+ attribute (see the "attributes-natural-language" operation attribute
+ specified in Section 3.1.4.1).
+
+4.4.14 ipp-versions-supported (1setOf type2 keyword)
+
+ This REQUIRED attribute identifies the IPP protocol version(s) that
+ this Printer supports, including major and minor versions, i.e., the
+ version numbers for which this Printer implementation meets the
+ conformance requirements. For version number validation, the Printer
+ matches the (two-octet binary) "version-number" parameter supplied by
+ the client in each request (see sections 3.1.1 and 3.1.8) with the
+ (US-ASCII) keyword values of this attribute.
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 134]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ The following standard keyword values are defined:
+
+ '1.0': Meets the conformance requirement of IPP version 1.0 as
+ specified in RFC 2566 [RFC2566] and RFC 2565 [RFC2565]
+ including any extensions registered according to Section 6 and
+ any extension defined in this version or any future version of
+ the IPP "Model and Semantics" document or the IPP "Encoding and
+ Transport" document following the rules, if any, when the
+ "version-number" parameter is '1.0'.
+ '1.1': Meets the conformance requirement of IPP version 1.1 as
+ specified in this document and [RFC2910] including any
+ extensions registered according to Section 6 and any extension
+ defined in any future versions of the IPP "Model and Semantics"
+ document or the IPP Encoding and Transport document following
+ the rules, if any, when the "version-number" parameter is
+ '1.1'.
+
+4.4.15 operations-supported (1setOf type2 enum)
+
+ This REQUIRED Printer attribute specifies the set of supported
+ operations for this Printer object and contained Job objects.
+
+ This attribute is encoded as any other enum attribute syntax
+ according to [RFC2910] as 32-bits. However, all 32-bit enum values
+ for this attribute MUST NOT exceed 0x00008FFF, since these same
+ values are also passed in two octets in the "operation-id" parameter
+ (see section 3.1.1) in each Protocol request with the two high order
+ octets omitted in order to indicate the operation being performed
+ [RFC2910].
+
+ The following standard enum and "operation-id" (see section 3.1.2)
+ values are defined:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 135]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Value Operation Name
+ ----------------- -------------------------------------
+
+ 0x0000 reserved, not used
+ 0x0001 reserved, not used
+ 0x0002 Print-Job
+ 0x0003 Print-URI
+ 0x0004 Validate-Job
+ 0x0005 Create-Job
+ 0x0006 Send-Document
+ 0x0007 Send-URI
+ 0x0008 Cancel-Job
+ 0x0009 Get-Job-Attributes
+ 0x000A Get-Jobs
+ 0x000B Get-Printer-Attributes
+ 0x000C Hold-Job
+ 0x000D Release-Job
+ 0x000E Restart-Job
+ 0x000F reserved for a future operation
+ 0x0010 Pause-Printer
+ 0x0011 Resume-Printer
+ 0x0012 Purge-Jobs
+ 0x0013-0x3FFF reserved for future IETF standards track
+ operations (see section 6.4)
+ 0x4000-0x8FFF reserved for vendor extensions (see section 6.4)
+
+4.4.16 multiple-document-jobs-supported (boolean)
+
+ This Printer attribute indicates whether or not the Printer supports
+ more than one document per job, i.e., more than one Send-Document or
+ Send-Data operation with document data. If the Printer supports the
+ Create-Job and Send-Document operations (see section 3.2.4 and
+ 3.3.1), it MUST support this attribute.
+
+4.4.17 charset-configured (charset)
+
+ This REQUIRED Printer attribute identifies the charset that the
+ Printer object has been configured to represent 'text' and 'name'
+ Printer attributes that are set by the operator, system
+ administrator, or manufacturer, i.e., for "printer-name" (name),
+ "printer-location" (text), "printer-info" (text), and "printer-make-
+ and-model" (text). Therefore, the value of the Printer object's
+ "charset-configured" attribute MUST also be among the values of the
+ Printer object's "charset-supported" attribute.
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 136]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+4.4.18 charset-supported (1setOf charset)
+
+ This REQUIRED Printer attribute identifies the set of charsets that
+ the Printer and contained Job objects support in attributes with
+ attribute syntax 'text' and 'name'. At least the value 'utf-8' MUST
+ be present, since IPP objects MUST support the UTF-8 [RFC2279]
+ charset. If a Printer object supports a charset, it means that for
+ all attributes of syntax 'text' and 'name' the IPP object MUST (1)
+ accept the charset in requests and return the charset in responses as
+ needed.
+
+ If more charsets than UTF-8 are supported, the IPP object MUST
+ perform charset conversion between the charsets as described in
+ Section 3.1.4.2.
+
+4.4.19 natural-language-configured (naturalLanguage)
+
+ This REQUIRED Printer attribute identifies the natural language that
+ the Printer object has been configured to represent 'text' and 'name'
+ Printer attributes that are set by the operator, system
+ administrator, or manufacturer, i.e., for "printer-name" (name),
+ "printer-location" (text), "printer-info" (text), and "printer-make-
+ and-model" (text). When returning these Printer attributes, the
+ Printer object MAY return them in the configured natural language
+ specified by this attribute, instead of the natural language
+ requested by the client in the "attributes-natural-language"
+ operation attribute. See Section 3.1.4.1 for the specification of
+ the OPTIONAL multiple natural language support. Therefore, the value
+ of the Printer object's "natural-language-configured" attribute MUST
+ also be among the values of the Printer object's "generated-natural-
+ language-supported" attribute.
+
+4.4.20 generated-natural-language-supported (1setOf naturalLanguage)
+
+ This REQUIRED Printer attribute identifies the natural language(s)
+ that the Printer object and contained Job objects support in
+ attributes with attribute syntax 'text' and 'name'. The natural
+ language(s) supported depends on implementation and/or configuration.
+ Unlike charsets, IPP objects MUST accept requests with any natural
+ language or any Natural Language Override whether the natural
+ language is supported or not.
+
+ If a Printer object supports a natural language, it means that for
+ any of the attributes for which the Printer or Job object generates
+ messages, i.e., for the "job-state-message" and "printer-state-
+ message" attributes and Operation Messages (see Section 3.1.5) in
+ operation responses, the Printer and Job objects MUST be able to
+
+
+
+
+Hastings, et al. Standards Track [Page 137]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ generate messages in any of the Printer's supported natural
+ languages. See section 3.1.4 for the definition of 'text' and 'name'
+ attributes in operation requests and responses.
+
+ Note: A Printer object that supports multiple natural languages,
+ often has separate catalogs of messages, one for each natural
+ language supported.
+
+4.4.21 document-format-default (mimeMediaType)
+
+ This REQUIRED Printer attribute identifies the document format that
+ the Printer object has been configured to assume if the client does
+ not supply a "document-format" operation attribute in any of the
+ operation requests that supply document data. The standard values
+ for this attribute are Internet Media types (sometimes called MIME
+ types). For further details see the description of the
+ 'mimeMediaType' attribute syntax in Section 4.1.9.
+
+4.4.22 document-format-supported (1setOf mimeMediaType)
+
+ This REQUIRED Printer attribute identifies the set of document
+ formats that the Printer object and contained Job objects can
+ support. For further details see the description of the
+ 'mimeMediaType' attribute syntax in Section 4.1.9.
+
+4.4.23 printer-is-accepting-jobs (boolean)
+
+ This REQUIRED Printer attribute indicates whether the printer is
+ currently able to accept jobs, i.e., is accepting Print-Job, Print-
+ URI, and Create-Job requests. If the value is 'true', the printer is
+ accepting jobs. If the value is 'false', the Printer object is
+ currently rejecting any jobs submitted to it. In this case, the
+ Printer object returns the 'server-error-not-accepting-jobs' status
+ code.
+
+ This value is independent of the "printer-state" and "printer-state-
+ reasons" attributes because its value does not affect the current
+ job; rather it affects future jobs. This attribute, when 'false',
+ causes the Printer to reject jobs even when the "printer-state" is
+ 'idle' or, when 'true', causes the Printer object to accepts jobs
+ even when the "printer-state" is 'stopped'.
+
+4.4.24 queued-job-count (integer(0:MAX))
+
+ This REQUIRED Printer attribute contains a count of the number of
+ jobs that are either 'pending', 'processing', 'pending-held', or
+ 'processing-stopped' and is set by the Printer object.
+
+
+
+
+Hastings, et al. Standards Track [Page 138]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+4.4.25 printer-message-from-operator (text(127))
+
+ This Printer attribute provides a message from an operator, system
+ administrator or "intelligent" process to indicate to the end user
+ information or status of the printer, such as why it is unavailable
+ or when it is expected to be available.
+
+4.4.26 color-supported (boolean)
+
+ This Printer attribute identifies whether the device is capable of
+ any type of color printing at all, including highlight color. All
+ document instructions having to do with color are embedded within the
+ document PDL (none are external IPP attributes in IPP/1.1).
+
+ Note: end-users are able to determine the nature and details of the
+ color support by querying the "printer-more-info-manufacturer"
+ Printer attribute.
+
+4.4.27 reference-uri-schemes-supported (1setOf uriScheme)
+
+ This Printer attribute specifies which URI schemes are supported for
+ use in the "document-uri" operation attribute of the Print-URI or
+ Send-URI operation. If a Printer object supports these optional
+ operations, it MUST support the "reference-uri-schemes-supported"
+ Printer attribute with at least the following schemed URI value:
+
+ 'ftp': The Printer object will use an FTP 'get' operation as
+ defined in RFC 2228 [RFC2228] using FTP URLs as defined by
+ [RFC2396] and [RFC2316].
+
+ The Printer object MAY OPTIONALLY support other URI schemes (see
+ section 4.1.6).
+
+4.4.28 pdl-override-supported (type2 keyword)
+
+ This REQUIRED Printer attribute expresses the ability for a
+ particular Printer implementation to either attempt to override
+ document data instructions with IPP attributes or not.
+
+ This attribute takes on the following keyword values:
+
+ - 'attempted': This value indicates that the Printer object
+ attempts to make the IPP attribute values take precedence over
+ embedded instructions in the document data, however there is no
+ guarantee.
+ - 'not-attempted': This value indicates that the Printer object
+ makes no attempt to make the IPP attribute values take
+ precedence over embedded instructions in the document data.
+
+
+
+Hastings, et al. Standards Track [Page 139]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Section 15 contains a full description of how this attribute
+ interacts with and affects other IPP attributes, especially the
+ "ipp-attribute-fidelity" attribute.
+
+4.4.29 printer-up-time (integer(1:MAX))
+
+ This REQUIRED Printer attribute indicates the amount of time (in
+ seconds) that this Printer instance has been up and running. The
+ value is a monotonically increasing value starting from 1 when the
+ Printer object is started-up (initialized, booted, etc.). This value
+ is used to populate the Event Time Job Description Job attributes
+ "time-at-creation", "time-at-processing", and "time-at-completed"
+ (see section 4.3.14).
+
+ If the Printer object goes down at some value 'n', and comes back up,
+ the implementation MAY:
+
+ 1. Know how long it has been down, and resume at some value
+ greater than 'n', or
+ 2. Restart from 1.
+
+ In other words, if the device or devices that the Printer object is
+ representing are restarted or power cycled, the Printer object MAY
+ continue counting this value or MAY reset this value to 1 depending
+ on implementation. However, if the Printer object software ceases
+ running, and restarts without knowing the last value for "printer-
+ up-time", the implementation MUST reset this value to 1. If this
+ value is reset and the Printer has persistent jobs, the Printer MUST
+ reset the "time-at-xxx(integer) Event Time Job Description attributes
+ according to Section 4.3.14. An implementation MAY use both
+ implementation alternatives, depending on warm versus cold start,
+ respectively.
+
+4.4.30 printer-current-time (dateTime)
+
+ This Printer attribute indicates the current date and time. This
+ value is used to populate the Event Time Job Description attributes:
+ "date-time-at-creation", "date-time-at-processing", and "date-time-
+ at-completed" (see Section 4.3.14).
+
+ The date and time is obtained on a "best efforts basis" and does not
+ have to be that precise in order to work in practice. A Printer
+ implementation sets the value of this attribute by obtaining the date
+ and time via some implementation-dependent means, such as getting the
+ value from a network time server, initialization at time of
+ manufacture, or setting by an administrator. See [IPP-IIG] for
+ examples. If an implementation supports this attribute and the
+ implementation knows that it has not yet been set, then the
+
+
+
+Hastings, et al. Standards Track [Page 140]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ implementation MUST return the value of this attribute using the
+ out-of-band 'no-value' meaning not configured. See the beginning of
+ section 4.1.
+
+ The time zone of this attribute NEED NOT be the time zone used by
+ people located near the Printer object or device. The client MUST
+ NOT expect that the time zone of any received 'dateTime' value to be
+ in the time zone of the client or in the time zone of the people
+ located near the printer.
+
+ The client SHOULD display any dateTime attributes to the user in
+ client local time by converting the 'dateTime' value returned by the
+ server to the time zone of the client, rather than using the time
+ zone returned by the Printer in attributes that use the 'dateTime'
+ attribute syntax.
+
+4.4.31 multiple-operation-time-out (integer(1:MAX))
+
+ This Printer attributes identifies the minimum time (in seconds) that
+ the Printer object waits for additional Send-Document or Send-URI
+ operations to follow a still-open Job object before taking any
+ recovery actions, such as the ones indicated in section 3.3.1. If
+ the Printer object supports the Create-Job and Send-Document
+ operations (see section 3.2.4 and 3.3.1), it MUST support this
+ attribute.
+
+ It is RECOMMENDED that vendors supply a value for this attribute that
+ is between 60 and 240 seconds. An implementation MAY allow a system
+ administrator to set this attribute (by means outside this IPP/1.1
+ document). If so, the system administrator MAY be able to set values
+ outside this range.
+
+4.4.32 compression-supported (1setOf type3 keyword)
+
+ This REQUIRED Printer attribute identifies the set of supported
+ compression algorithms for document data. Compression only applies
+ to the document data; compression does not apply to the encoding of
+ the IPP operation itself. The supported values are used to validate
+ the client supplied "compression" operation attributes in Print-Job,
+ Send-Document, and Send-URI requests.
+
+ Standard keyword values are :
+
+ 'none': no compression is used.
+ 'deflate': ZIP public domain inflate/deflate) compression technology
+ in RFC 1951 [RFC1951]
+ 'gzip' GNU zip compression technology described in RFC 1952
+ [RFC1952].
+
+
+
+Hastings, et al. Standards Track [Page 141]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 'compress': UNIX compression technology in RFC 1977 [RFC1977]
+
+4.4.33 job-k-octets-supported (rangeOfInteger(0:MAX))
+
+ This Printer attribute specifies the upper and lower bounds of total
+ sizes of jobs in K octets, i.e., in units of 1024 octets. The
+ supported values are used to validate the client supplied "job-k-
+ octets" operation attributes in create requests. The corresponding
+ job description attribute "job-k-octets" is defined in section
+ 4.3.17.1.
+
+4.4.34 job-impressions-supported (rangeOfInteger(0:MAX))
+
+ This Printer attribute specifies the upper and lower bounds for the
+ number of impressions per job. The supported values are used to
+ validate the client supplied "job-impressions" operation attributes
+ in create requests. The corresponding job description attribute
+ "job-impressions" is defined in section 4.3.17.2.
+
+4.4.35 job-media-sheets-supported (rangeOfInteger(0:MAX))
+
+ This Printer attribute specifies the upper and lower bounds for the
+ number of media sheets per job. The supported values are used to
+ validate the client supplied "job-media-sheets" operation attributes
+ in create requests. The corresponding Job attribute "job-media-
+ sheets" is defined in section 4.3.17.3.
+
+4.4.36 pages-per-minute (integer(0:MAX))
+
+ This Printer attributes specifies the nominal number of pages per
+ minute to the nearest whole number which may be generated by this
+ printer (e.g., simplex, black-and-white). This attribute is
+ informative, not a service guarantee. Generally, it is the value
+ used in the marketing literature to describe the device.
+
+ A value of 0 indicates a device that takes more than two minutes to
+ process a page.
+
+4.4.37 pages-per-minute-color (integer(0:MAX))
+
+ This Printer attributes specifies the nominal number of pages per
+ minute to the nearest whole number which may be generated by this
+ printer when printing color (e.g., simplex, color). For purposes of
+ this attribute, "color" means the same as for the "color-supported"
+ attribute, namely, the device is capable of any type of color
+ printing at all, including highlight color. This attribute is
+
+
+
+
+
+Hastings, et al. Standards Track [Page 142]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ informative, not a service guarantee. Generally, it is the value
+ used in the marketing literature to describe the color capabilities
+ of this device.
+
+ A value of 0 indicates a device that takes more than two minutes to
+ process a page.
+
+ If a color device has several color modes, it MAY use the pages-per-
+ minute value for this attribute that corresponds to the mode that
+ produces the highest number.
+
+ Black and white only printers MUST NOT support this attribute. If
+ this attribute is present, then the "color-supported" Printer
+ description attribute MUST be present and have a 'true' value.
+
+ The values of these two attributes returned by the Get-Printer-
+ Attributes operation MAY be affected by the "document-format"
+ attribute supplied by the client in the Get-Printer-Attributes
+ request. In other words, the implementation MAY have different
+ speeds depending on the document format being processed. See section
+ 3.2.5.1 Get-Printer-Attributes.
+
+5. Conformance
+
+ This section describes conformance issues and requirements. This
+ document introduces model entities such as objects, operations,
+ attributes, attribute syntaxes, and attribute values. These
+ conformance sections describe the conformance requirements which
+ apply to these model entities.
+
+5.1 Client Conformance Requirements
+
+ This section describes the conformance requirements for a client (see
+ section 2.1), whether it be:
+
+ 1. contained within software controlled by an end user, e.g.
+ activated by the "Print" menu item in an application that sends
+ IPP requests or
+
+ 2. the print server component that sends IPP requests to either an
+ output device or another "downstream" print server.
+
+ A conforming client MUST support all REQUIRED operations as defined
+ in this document. For each attribute included in an operation
+ request, a conforming client MUST supply a value whose type and value
+ syntax conforms to the requirements of the Model document as
+ specified in Sections 3 and 4. A conforming client MAY supply any
+
+
+
+
+Hastings, et al. Standards Track [Page 143]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ IETF standards track extensions and/or vendor extensions in an
+ operation request, as long as the extensions meet the requirements in
+ Section 6.
+
+ Otherwise, there are no conformance requirements placed on the user
+ interfaces provided by IPP clients or their applications. For
+ example, one application might not allow an end user to submit
+ multiple documents per job, while another does. One application
+ might first query a Printer object in order to supply a graphical
+ user interface (GUI) dialogue box with supported and default values
+ whereas a different implementation might not.
+
+ When sending a request, an IPP client NEED NOT supply any attributes
+ that are indicated as OPTIONALLY supplied by the client.
+
+ A client MUST be able to accept any of the attribute syntaxes defined
+ in Section 4.1, including their full range, that may be returned to
+ it in a response from a Printer object. In particular for each
+ attribute that the client supports whose attribute syntax is 'text',
+ the client MUST accept and process both the 'textWithoutLanguage' and
+ 'textWithLanguage' forms. Similarly, for each attribute that the
+ client supports whose attribute syntax is 'name', the client MUST
+ accept and process both the 'nameWithoutLanguage' and
+ 'nameWithLanguage' forms. For presentation purposes, truncation of
+ long attribute values is not recommended. A recommended approach
+ would be for the client implementation to allow the user to scroll
+ through long attribute values.
+
+ A response MAY contain attribute groups, attributes, attribute
+ syntaxes, values, and status codes that the client does not expect.
+ Therefore, a client implementation MUST gracefully handle such
+ responses and not refuse to inter-operate with a conforming Printer
+ that is returning IETF standards track extension or vendor
+ extensions, including attribute groups, attributes, attribute
+ syntaxes, attribute values, status codes, and out-of-band attribute
+ values that conform to Section 6. Clients may choose to ignore any
+ parameters, attribute groups, attributes, attribute syntaxes, or
+ values that they do not understand.
+
+ While a client is sending data to a printer, it SHOULD do its best to
+ prevent a channel from being closed by a lower layer when the channel
+ is blocked (i.e. flow-controlled off) for whatever reason, e.g. 'out
+ of paper' or 'job ahead hasn't freed up enough memory'. However, the
+ layer that launched the print submission (e.g. an end user) MAY close
+ the channel in order to cancel the job. When a client closes a
+ channel, a Printer MAY print all or part of the received portion of
+ the document. See the "Encoding and Transport" document [RFC2910]
+ for more details.
+
+
+
+Hastings, et al. Standards Track [Page 144]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ A client MUST support Client Authentication as defined in the IPP/1.1
+ Encoding and Transport document [RFC2910]. A client SHOULD support
+ Operation Privacy and Server Authentication as defined in the IPP/1.1
+ Encoding and Transport document [RFC2910]. See also section 8 of
+ this document.
+
+5.2 IPP Object Conformance Requirements
+
+ This section specifies the conformance requirements for conforming
+ implementations of IPP objects (see section 2). These requirements
+ apply to an IPP object whether it is:
+
+ (1) an (embedded) device component that accepts IPP requests and
+ controls the device or
+
+ (2) a component of a print server that accepts IPP requests (where
+ the print server control one or more networked devices using IPP or
+ other protocols).
+
+5.2.1 Objects
+
+ Conforming implementations MUST implement all of the model objects as
+ defined in this document in the indicated sections:
+
+ Section 2.1 - Printer Object
+ Section 2.2 - Job Object
+
+5.2.2 Operations
+
+ Conforming IPP object implementations MUST implement all of the
+ REQUIRED model operations, including REQUIRED responses, as defined
+ in this document in the indicated sections:
+
+ For a Printer object:
+ Print-Job (section 3.2.1) REQUIRED
+ Print-URI (section 3.2.2) OPTIONAL
+ Validate-Job (section 3.2.3) REQUIRED
+ Create-Job (section 3.2.4) OPTIONAL
+ Get-Printer-Attributes (section 3.2.5) REQUIRED
+ Get-Jobs (section 3.2.6) REQUIRED
+ Pause-Printer (section 3.2.7) OPTIONAL
+ Resume-Printer (section 3.2.8) OPTIONAL
+ Purge-Jobs (section 3.2.9) OPTIONAL
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 145]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ For a Job object:
+ Send-Document (section 3.3.1) OPTIONAL
+ Send-URI (section 3.3.2) OPTIONAL
+ Cancel-Job (section 3.3.3) REQUIRED
+ Get-Job-Attributes (section 3.3.4) REQUIRED
+ Hold-Job (section 3.3.5) OPTIONAL
+ Release-Job (section 3.3.6) OPTIONAL
+ Restart-Job (section 3.3.7) OPTIONAL
+
+ Conforming IPP objects MUST support all REQUIRED operation attributes
+ and all values of such attributes if so indicated in the description.
+ Conforming IPP objects MUST ignore all unsupported or unknown
+ operation attributes or operation attribute groups received in a
+ request, but MUST reject a request that contains a supported
+ operation attribute that contains an unsupported value.
+
+ Conforming IPP objects MAY return operation responses that contain
+ attributes groups, attributes names, attribute syntaxes, attribute
+ values, and status codes that are extensions to this standard. The
+ additional attribute groups MAY occur in any order.
+
+ The following section on object attributes specifies the support
+ required for object attributes.
+
+5.2.3 IPP Object Attributes
+
+ Conforming IPP objects MUST support all of the REQUIRED object
+ attributes, as defined in this document in the indicated sections.
+
+ If an object supports an attribute, it MUST support only those values
+ specified in this document or through the extension mechanism
+ described in section 5.2.4. It MAY support any non-empty subset of
+ these values. That is, it MUST support at least one of the specified
+ values and at most all of them.
+
+5.2.4 Versions
+
+ IPP/1.1 clients MUST meet the conformance requirements for clients
+ specified in this document and [RFC2910]. IPP/1.1 clients MUST send
+ requests containing a "version-number" parameter with a '1.1' value.
+
+ IPP/1.1 Printer and Job objects MUST meet the conformance
+ requirements for IPP objects specified in this document and
+ [RFC2910]. IPP/1.1 objects MUST accept requests containing a
+ "version-number" parameter with a '1.1' value (or reject the request
+ if the operation is not supported).
+
+
+
+
+
+Hastings, et al. Standards Track [Page 146]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ It is beyond the scope of this specification to mandate conformance
+ with previous versions. IPP/1.1 was deliberately designed, however,
+ to make supporting previous versions easy. It is worth noting that,
+ at the time of composing this specification (1999), we would expect
+ IPP/1.1 Printer implementations to:
+
+ understand any valid request in the format of IPP/1.0, or 1.1;
+
+ respond appropriately with a response containing the same
+ "version-number" parameter value used by the client in the request.
+
+ And we would expect IPP/1.1 clients to:
+
+ understand any valid response in the format of IPP/1.0, or 1.1.
+
+ It is recommended that IPP/1.1 clients try supplying alternate
+ version numbers if they receive a 'server-error-version-not-
+ supported' error return in a response.
+
+5.2.5 Extensions
+
+ A conforming IPP object MAY support IETF standards track extensions
+ and vendor extensions, as long as the extensions meet the
+ requirements specified in Section 6.
+
+ For each attribute included in an operation response, a conforming
+ IPP object MUST return a value whose type and value syntax conforms
+ to the requirement of the Model document as specified in Sections 3
+ and 4.
+
+5.2.6 Attribute Syntaxes
+
+ An IPP object MUST be able to accept any of the attribute syntaxes
+ defined in Section 4.1, including their full range, in any operation
+ in which a client may supply attributes or the system administrator
+ may configure attributes (by means outside the scope of this IPP/1.1
+ document). In particular for each attribute that the IPP object
+ supports whose attribute syntax is 'text', the IPP object MUST accept
+ and process both the 'textWithoutLanguage' and 'textWithLanguage'
+ forms. Similarly, for each attribute that the IPP object supports
+ whose attribute syntax is 'name', the IPP object MUST accept and
+ process both the 'nameWithoutLanguage' and 'nameWithLanguage' forms.
+ Furthermore, an IPP object MUST return attributes to the client in
+ operation responses that conform to the syntax specified in Section
+ 4.1, including their full range if supplied previously by a client.
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 147]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+5.2.7 Security
+
+ An IPP Printer implementation SHOULD contain support for Client
+ Authentication as defined in the IPP/1.1 Encoding and Transport
+ document [RFC2910]. A Printer implementation MAY allow an
+ administrator to configure the Printer so that all, some, or none of
+ the users are authenticated. See also section 8 of this document.
+
+ An IPP Printer implementation SHOULD contain support for Operation
+ Privacy and Server Authentication as defined in the IPP/1.1 Encoding
+ and Transport document [RFC2910]. A Printer implementation MAY allow
+ an administrator to configure the degree of support for Operation
+ Privacy and Server Authentication. See also section 8 of this
+ document.
+
+ Security MUST NOT be compromised when a client supplies a lower
+ "version-number" parameter in a request. For example, if an IPP/1.1
+ conforming Printer object accepts version '1.0' requests and is
+ configured to enforce Digest Authentication, it MUST do the same for
+ a version '1.0' request.
+
+5.3 Charset and Natural Language Requirements
+
+ All clients and IPP objects MUST support the 'utf-8' charset as
+ defined in section 4.1.7.
+
+ IPP objects MUST be able to accept any client request which correctly
+ uses the "attributes-natural-language" operation attribute or the
+ Natural Language Override mechanism on any individual attribute
+ whether or not the natural language is supported by the IPP object.
+ If an IPP object supports a natural language, then it MUST be able to
+ translate (perhaps by table lookup) all generated 'text' or 'name'
+ attribute values into one of the supported languages (see section
+ 3.1.4). That is, the IPP object that supports a natural language
+ NEED NOT be a general purpose translator of any arbitrary 'text' or
+ 'name' value supplied by the client into that natural language.
+ However, the object MUST be able to translate (automatically
+ generate) any of its own attribute values and messages into that
+ natural language.
+
+6. IANA Considerations
+
+ This section describes the procedures for defining semantics for the
+ following IETF standards track extensions and vendor extensions to
+ the IPP/1.1 Model and Semantics document:
+
+ 1. keyword attribute values
+ 2. enum attribute values
+
+
+
+Hastings, et al. Standards Track [Page 148]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 3. attributes
+ 4. attribute syntaxes
+ 5. operations
+ 6. attribute groups
+ 7. status codes
+ 8. out-of-band attribute values
+
+ Extensions registered for use with IPP/1.1 are OPTIONAL for client
+ and IPP object conformance to the IPP/1.1 "Model and Semantics"
+ document (this document).
+
+ These extension procedures are aligned with the guidelines as set
+ forth by the IESG [IANA-CON]. Section 11 describes how to propose
+ new registrations for consideration. IANA will reject registration
+ proposals that leave out required information or do not follow the
+ appropriate format described in Section 11. The IPP/1.1 Model and
+ Semantics document may also be extended by an appropriate RFC that
+ specifies any of the above extensions.
+
+6.1 Typed 'keyword' and 'enum' Extensions
+
+ IPP allows for 'keyword' and 'enum' extensions (see sections 4.1.2.3
+ and 4.1.4). This document uses prefixes to the 'keyword' and 'enum'
+ basic attribute syntax type in order to communicate extra information
+ to the reader through its name. This extra information is not
+ represented in the protocol because it is unimportant to a client or
+ Printer object. The list below describes the prefixes and their
+ meaning.
+
+ "type1": This IPP specification document must be revised (or
+ another IETF standards track document which augments this
+ document) to add a new keyword or a new enum. No vendor
+ defined keywords or enums are allowed.
+
+ "type2": Implementers can, at any time, add new keyword or enum
+ values by proposing the complete specification to IANA:
+
+ iana@iana.org
+
+ IANA will forward the registration proposal to the IPP
+ Designated Expert who will review the proposal with a mailing
+ list that the Designated Expert keeps for this purpose.
+ Initially, that list will be the mailing list used by the IPP
+ WG:
+
+ ipp@pwg.org
+
+ even after the IPP WG is disbanded as permitted by [IANA-CON].
+
+
+
+Hastings, et al. Standards Track [Page 149]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ The IPP Designated Expert is appointed by the IESG Area
+ Director responsible for IPP, according to [IANA-CON].
+
+ When a type2 keyword or enum is approved, the IPP Designated
+ Expert becomes the point of contact for any future maintenance
+ that might be required for that registration.
+
+ "type3": Implementers can, at any time, add new keyword and enum
+ values by submitting the complete specification to IANA as for
+ type2 who will forward the proposal to the IPP Designated
+ Expert. While no additional technical review is required, the
+ IPP Designated Expert may, at his/her discretion, forward the
+ proposal to the same mailing list as for type2 registrations
+ for advice and comment.
+
+ When a type3 keyword or enum is approved by the IPP Designated
+ Expert, the original proposer becomes the point of contact for
+ any future maintenance that might be required for that
+ registration.
+
+ For type2 and type3 keywords, the proposer includes the name of the
+ keyword in the registration proposal and the name is part of the
+ technical review.
+
+ After type2 and type3 enums specifications are approved, the IPP
+ Designated Expert in consultation with IANA assigns the next
+ available enum number for each enum value.
+
+ IANA will publish approved type2 and type3 keyword and enum
+ attributes value registration specifications in:
+
+ ftp.isi.edu/iana/assignments/ipp/attribute-values/xxx/yyy.txt
+
+ where xxx is the attribute name that specifies the initial values and
+ yyy.txt is a descriptive file name that contains one or more enums or
+ keywords approved at the same time. For example, if several
+ additional enums for stapling are approved for use with the
+ "finishings" attribute (and "finishings-default" and "finishings-
+ supported" attributes), IANA will publish the additional values in
+ the file:
+
+ ftp.isi.edu/iana/assignments/ipp/attribute-
+ values/finishings/stapling.txt
+
+ Note: Some attributes are defined to be: 'type3 keywords' | 'name'
+ which allows for attribute values to be extended by a site
+ administrator with administrator defined names. Such names are not
+ registered with IANA.
+
+
+
+Hastings, et al. Standards Track [Page 150]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ By definition, each of the three types above assert some sort of
+ registry or review process in order for extensions to be considered
+ valid. Each higher numbered level (1, 2, 3) tends to be decreasingly
+ less stringent than the previous level. Therefore, any typeN value
+ MAY be registered using a process for some typeM where M is less than
+ N, however such registration is NOT REQUIRED. For example, a type3
+ value MAY be registered in a type 1 manner (by being included in a
+ future version of an IPP specification), however, it is NOT REQUIRED.
+
+ This document defines keyword and enum values for all of the above
+ types, including type3 keywords.
+
+ For vendor keyword extensions, implementers SHOULD use keywords with
+ a suitable distinguishing prefix, such as "xxx-" where xxx follows
+ the syntax rules for keywords (see section 4.1.3) and is the
+ (lowercase) fully qualified company name registered with IANA for use
+ in domain names [RFC1035]. For example, if the company XYZ Corp. had
+ obtained the domain name "XYZ.com", then a vendor keyword 'abc' would
+ be: 'xyz.com-abc'.
+
+ Note: RFC 1035 [RFC1035] indicates that while upper and lower case
+ letters are allowed in domain names, no significance is attached to
+ the case. That is, two names with the same spelling but different
+ case are to be treated as if identical. Also, the labels in a domain
+ name must follow the rules for ARPANET host names: They must start
+ with a letter, end with a letter or digit, and have as interior
+ characters only letters, digits, and hyphen. Labels must be 63
+ characters or less. Labels are separated by the "." character.
+
+ For vendor enum extensions, implementers MUST use values in the
+ reserved integer range which is 2**30 to 2**31-1.
+
+6.2 Attribute Extensibility
+
+ Attribute names (see section 4.1.3) are type2 keywords. Therefore,
+ new attributes may be registered and have the same status as
+ attributes in this document by following the type2 extension rules.
+ For vendor attribute extensions, implementers SHOULD use keywords
+ with a suitable distinguishing prefix as described in Section 6.1.
+
+ IANA will publish approved attribute registration specifications as
+ separate files:
+
+ ftp.isi.edu/iana/assignments/ipp/attributes/xxx-yyy.txt
+
+ where "xxx-yyy" is the new attribute name.
+
+
+
+
+
+Hastings, et al. Standards Track [Page 151]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ If a new Printer object attribute is defined and its values can be
+ affected by a specific document format, its specification needs to
+ contain the following sentence:
+
+ "The value of this attribute returned in a Get-Printer-
+ Attributes response MAY depend on the "document-format"
+ attribute supplied (see Section 3.2.5.1)."
+
+ If the specification does not, then its value in the Get-Printer-
+ Attributes response MUST NOT depend on the "document-format" supplied
+ in the request. When a new Job Template attribute is registered, the
+ value of the Printer attributes MAY vary with "document-format"
+ supplied in the request without the specification having to indicate
+ so.
+
+6.3 Attribute Syntax Extensibility
+
+ Attribute syntaxes (see section 4.1) are like type2 enums.
+ Therefore, new attribute syntaxes may be registered and have the same
+ status as attribute syntaxes in this document by following the type2
+ extension rules described in Section 6.1. The initial set of value
+ codes that identify each of the attribute syntaxes have been assigned
+ in the "Encoding and Transport" document [RFC2910], including a
+ designated range for vendor extension.
+
+ For attribute syntaxes, the IPP Designated Expert in consultation
+ with IANA assigns the next attribute syntax code in the appropriate
+ range as specified in [RFC2910]. IANA will publish approved
+ attribute syntax registration specifications as separate files:
+
+ ftp.isi.edu/iana/assignments/ipp/attribute-syntaxes/xxx-yyy.txt
+
+ where 'xxx-yyy' is the new attribute syntax name.
+
+6.4 Operation Extensibility
+
+ Operations (see section 3) may also be registered following the type2
+ procedures described in Section 6.1, though major new operations will
+ usually be done by a new standards track RFC that augments this
+ document. For vendor operation extensions, implementers MUST use the
+ range for the "operation-id" in requests specified in Section 4.4.15
+ "operations-supported" Printer attribute.
+
+ For operations, the IPP Designated Expert in consultation with IANA
+ assigns the next operation-id code as specified in Section 4.4.15.
+ IANA will publish approved operation registration specifications as
+ separate files:
+
+
+
+
+Hastings, et al. Standards Track [Page 152]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ ftp.isi.edu/iana/assignments/ipp/operations/Xxx-Yyy.txt
+
+ where "Xxx-Yyy" is the new operation name.
+
+6.5 Attribute Group Extensibility
+
+ Attribute groups (see section 3.1.3) passed in requests and responses
+ may be registered following the type2 procedures described in Section
+ 6.1. The initial set of attribute group tags have been assigned in
+ the "Encoding and Transport" document [RFC2910], including a
+ designated range for vendor extension.
+
+ For attribute groups, the IPP Designated Expert in consultation with
+ IANA assigns the next attribute group tag code in the appropriate
+ range as specified in [RFC2910]. IANA will publish approved
+ attribute group registration specifications as separate files:
+
+ ftp.isi.edu/iana/assignments/ipp/attribute-group-tags/xxx-yyy-
+ tag.txt
+
+ where 'xxx-yyy-tag' is the new attribute group tag name.
+
+6.6 Status Code Extensibility
+
+ Operation status codes (see section 3.1.6.1) may also be registered
+ following the type2 procedures described in Section 6.1. The values
+ for status codes are allocated in ranges as specified in Section 14
+ for each status code class:
+
+ "informational" - Request received, continuing process
+ "successful" - The action was successfully received, understood, and
+ accepted
+ "redirection" - Further action must be taken in order to complete the
+ request
+ "client-error" - The request contains bad syntax or cannot be
+ fulfilled
+ "server-error" - The IPP object failed to fulfill an apparently
+ valid request
+
+ For vendor operation status code extensions, implementers MUST use
+ the top of each range as specified in Section 13.
+
+ For operation status codes, the IPP Designated Expert in consultation
+ with IANA assigns the next status code in the appropriate class range
+ as specified in Section 13. IANA will publish approved status code
+ registration specifications as separate files:
+
+ ftp.isi.edu/iana/assignments/ipp/status-codes/xxx-yyy.txt
+
+
+
+Hastings, et al. Standards Track [Page 153]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ where "xxx-yyy" is the new operation status code keyword.
+
+6.7 Out-of-band Attribute Value Extensibility
+
+ Out-of-band attribute values (see the beginning of section 4.1)
+ passed in requests and responses may be registered following the
+ type2 procedures described in Section 6.1. The initial set of out-
+ of-band attribute value tags have been assigned in the "Encoding and
+ Transport" document [RFC2910].
+
+ For out-of-band attribute value tags, the IPP Designated Expert in
+ consultation with IANA assigns the next out-of-band attribute value
+ tag code in the appropriate range as specified in [RFC2910]. IANA
+ will publish approved out-of-band attribute value tags registration
+ specifications as separate files:
+
+ ftp.isi.edu/iana/assignments/ipp/out-of-band-attribute-value-
+ tags/xxx-yyy-tag.txt
+
+ where 'xxx-yyy-tag' is the new out-of-band attribute value tag name.
+
+6.8 Registration of MIME types/sub-types for document-formats
+
+ The "document-format" attribute's syntax is 'mimeMediaType'. This
+ means that valid values are Internet Media Types (see Section 4.1.9).
+ RFC 2045 [RFC2045] defines the syntax for valid Internet media types.
+ IANA is the registry for all Internet media types.
+
+6.9 Registration of charsets for use in 'charset' attribute values
+
+ The "attributes-charset" attribute's syntax is 'charset'. This means
+ that valid values are charsets names. When a charset in the IANA
+ registry has more than one name (alias), the name labeled as
+ "(preferred MIME name)", if present, MUST be used (see Section
+ 4.1.7). IANA is the registry for charsets following the procedures
+ of [RFC2278].
+
+7. Internationalization Considerations
+
+ Some of the attributes have values that are text strings and names
+ which are intended for human understanding rather than machine
+ understanding (see the 'text' and 'name' attribute syntaxes in
+ Sections 4.1.1 and 4.1.2).
+
+ In each operation request, the client
+
+ - identifies the charset and natural language of the request which
+ affects each supplied 'text' and 'name' attribute value, and
+
+
+
+Hastings, et al. Standards Track [Page 154]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ - requests the charset and natural language for attributes
+ returned by the IPP object in operation responses (as described
+ in Section 3.1.4.1).
+
+ In addition, the client MAY separately and individually identify the
+ Natural Language Override of a supplied 'text' or 'name' attribute
+ using the 'textWithLanguage' and 'nameWithLanguage' technique
+ described section 4.1.1.2 and 4.1.2.2 respectively.
+
+ All IPP objects MUST support the UTF-8 [RFC2279] charset in all
+ 'text' and 'name' attributes supported. If an IPP object supports
+ more than the UTF-8 charset, the object MUST convert between them in
+ order to return the requested charset to the client according to
+ Section 3.1.4.2. If an IPP object supports more than one natural
+ language, the object SHOULD return 'text' and 'name' values in the
+ natural language requested where those values are generated by the
+ Printer (see Section 3.1.4.1).
+
+ For Printers that support multiple charsets and/or multiple natural
+ languages in 'text' and 'name' attributes, different jobs may have
+ been submitted in differing charsets and/or natural languages. All
+ responses MUST be returned in the charset requested by the client.
+ However, the Get-Jobs operation uses the 'textWithLanguage' and
+ 'nameWithLanguage' mechanism to identify the differing natural
+ languages with each job attribute returned.
+
+ The Printer object also has configured charset and natural language
+ attributes. The client can query the Printer object to determine
+ the list of charsets and natural languages supported by the Printer
+ object and what the Printer object's configured values are. See the
+ "charset-configured", "charset-supported", "natural-language-
+ configured", and "generated-natural-language-supported" Printer
+ description attributes for more details.
+
+ The "charset-supported" attributed identifies the supported charsets.
+ If a charset is supported, the IPP object MUST be capable of
+ converting to and from that charset into any other supported charset.
+ In many cases, an IPP object will support only one charset and it
+ MUST be the UTF-8 charset.
+
+ The "charset-configured" attribute identifies the one supported
+ charset which is the native charset given the current configuration
+ of the IPP object (administrator defined).
+
+ The "generated-natural-language-supported" attribute identifies the
+ set of supported natural languages for generated messages; it is not
+ related to the set of natural languages that must be accepted for
+ client supplied 'text' and 'name' attributes. For client supplied
+
+
+
+Hastings, et al. Standards Track [Page 155]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 'text' and 'name' attributes, an IPP object MUST accept ALL supplied
+ natural languages. Just because a Printer object is currently
+ configured to support 'en-us' natural language does not mean that the
+ Printer object should reject a job if the client supplies a job name
+ that is in 'fr-ca'.
+
+ The "natural-language-configured" attribute identifies the one
+ supported natural language for generated messages which is the native
+ natural language given the current configuration of the IPP object
+ (administrator defined).
+
+ Attributes of type 'text' and 'name' are populated from different
+ sources. These attributes can be categorized into following groups
+ (depending on the source of the attribute):
+
+ 1. Some attributes are supplied by the client (e.g., the client
+ supplied "job-name", "document-name", and "requesting-user-
+ name" operation attributes along with the corresponding Job
+ object's "job-name" and "job-originating-user-name"
+ attributes). The IPP object MUST accept these attributes in
+ any natural language no matter what the set of supported
+ languages for generated messages
+ 2. Some attributes are supplied by the system administrator (e.g.,
+ the Printer object's "printer-name" and "printer-location"
+ attributes). These too can be in any natural language. If the
+ natural language for these attributes is different than what a
+ client requests, then they must be reported using the Natural
+ Language Override mechanism.
+ 3. Some attributes are supplied by the device manufacturer (e.g.,
+ the Printer object's "printer-make-and-model" attribute).
+ These too can be in any natural language. If the natural
+ language for these attributes is different than what a client
+ requests, then they must be reported using the Natural Language
+ Override mechanism.
+ 4. Some attributes are supplied by the operator (e.g., the Job
+ object's "job-message-from-operator" attribute). These too can
+ be in any natural language. If the natural language for these
+ attributes is different than what a client requests, then they
+ must be reported using the Natural Language Override mechanism.
+ 5. Some attributes are generated by the IPP object (e.g., the Job
+ object's "job-state-message" attribute, the Printer object's
+ "printer-state-message" attribute, and the "status-message"
+ operation attribute). These attributes can only be in one of
+ the "generated-natural-language-supported" natural languages.
+ If a client requests some natural language for these attributes
+ other than one of the supported values, the IPP object SHOULD
+
+
+
+
+
+Hastings, et al. Standards Track [Page 156]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ respond using the value of the "natural-language-configured"
+ attribute (using the Natural Language Override mechanism if
+ needed).
+
+ The 'text' and 'name' attributes specified in this version of this
+ document (additional ones will be registered according to the
+ procedures in Section 6) are:
+
+ Attributes Source
+
+ Operation Attributes:
+ job-name (name) client
+ document-name (name) client
+ requesting-user-name (name) client
+ status-message (text) Job or Printer object
+ detailed-status-message (text) Job or Printer object -
+ see rule 1
+ document-access-error (text) Job or Printer object -
+ see rule 1
+
+ Job Template Attributes:
+ job-hold-until (keyword | name) client matches
+ administrator-configured
+ job-hold-until-default (keyword | name) client matches
+ administrator-configured
+ job-hold-until-supported (keyword | client matches
+ name) administrator-configured
+ job-sheets (keyword | name) client matches
+ administrator-configured
+ job-sheets-default (keyword | name) client matches
+ administrator-configured
+ job-sheets-supported (keyword | name) client matches
+ administrator-configured
+ media (keyword | name) client matches
+ administrator-configured
+ media-default (keyword | name) client matches
+ administrator-configured
+ media-supported (keyword | name) client matches
+ administrator-configured
+ media-ready (keyword | name) client matches
+ administrator-configured
+
+ Job Description Attributes:
+ job-name (name) client or Printer object
+ job-originating-user-name (name) Printer object
+ job-state-message (text) Job or Printer object
+ output-device-assigned (name(127)) administrator
+ job-message-from-operator (text(127)) operator
+
+
+
+Hastings, et al. Standards Track [Page 157]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ job-detailed-status-messages (1setOf Job or Printer object -
+ text) see rule 1
+ job-document-access-errors (1setOf Job or Printer object -
+ text) see rule 1
+
+ Printer Description Attributes:
+ printer-name (name(127)) administrator
+ printer-location (text(127)) administrator
+ printer-info (text(127)) administrator
+ printer-make-and-model (text(127)) administrator or
+ manufacturer
+ printer-state-message (text) Printer object
+ printer-message-from-operator operator
+ (text(127))
+
+ Rule 1 - Neither the Printer nor the client localizes these message
+ attributes, since they are intended for use by the system
+ administrator or other experienced technical persons.
+
+8. Security Considerations
+
+ It is difficult to anticipate the security risks that might exist in
+ any given IPP environment. For example, if IPP is used within a given
+ corporation over a private network, the risks of exposing document
+ data may be low enough that the corporation will choose not to use
+ encryption on that data. However, if the connection between the
+ client and the IPP object is over a public network, the client may
+ wish to protect the content of the information during transmission
+ through the network with encryption.
+
+ Furthermore, the value of the information being printed may vary from
+ one IPP environment to the next. Printing payroll checks, for
+ example, would have a different value than printing public
+ information from a file. There is also the possibly of denial-of-
+ service attacks, but denial-of-service attacks against printing
+ resources are not well understood and there is no published
+ precedents regarding this scenario.
+
+ Once the authenticated identity of the requester has been supplied to
+ the IPP object, the object uses that identity to enforce any
+ authorization policy that might be in place. For example, one site's
+ policy might be that only the job owner is allowed to cancel a job.
+ The details and mechanisms to set up a particular access control
+ policy are not part of IPP/1.1, and must be established via some
+ other type of administrative or access control framework. However,
+ there are operation status codes that allow an IPP server to return
+ information back to a client about any potential access control
+ violations for an IPP object.
+
+
+
+Hastings, et al. Standards Track [Page 158]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ During a create operation, the client's identity is recorded in the
+ Job object in an implementation-defined attribute. This information
+ can be used to verify a client's identity for subsequent operations
+ on that Job object in order to enforce any access control policy that
+ might be in effect. See section 8.3 below for more details.
+
+ Since the security levels or the specific threats that an IPP system
+ administrator may be concerned with cannot be anticipated, IPP MUST
+ be capable of operating with different security mechanisms and
+ security policies as required by the individual installation.
+ Security policies might vary from very strong, to very weak, to none
+ at all, and corresponding security mechanisms will be required.
+
+8.1 Security Scenarios
+
+ The following sections describe specific security attacks for IPP
+ environments. Where examples are provided they should be considered
+ illustrative of the environment and not an exhaustive set. Not all of
+ these environments will necessarily be addressed in initial
+ implementations of IPP.
+
+8.1.1 Client and Server in the Same Security Domain
+
+ This environment is typical of internal networks where traditional
+ office workers print the output of personal productivity applications
+ on shared work-group printers, or where batch applications print
+ their output on large production printers. Although the identity of
+ the user may be trusted in this environment, a user might want to
+ protect the content of a document against such attacks as
+ eavesdropping, replaying or tampering.
+
+8.1.2 Client and Server in Different Security Domains
+
+ Examples of this environment include printing a document created by
+ the client on a publicly available printer, such as at a commercial
+ print shop; or printing a document remotely on a business associate's
+ printer. This latter operation is functionally equivalent to sending
+ the document to the business associate as a facsimile. Printing
+ sensitive information on a Printer in a different security domain
+ requires strong security measures. In this environment authentication
+ of the printer is required as well as protection against unauthorized
+ use of print resources. Since the document crosses security domains,
+ protection against eavesdropping and document tampering are also
+ required. It will also be important in this environment to protect
+ Printers against "spamming" and malicious document content.
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 159]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+8.1.3 Print by Reference
+
+ When the document is not stored on the client, printing can be done
+ by reference. That is, the print request can contain a reference, or
+ pointer, to the document instead of the actual document itself (see
+ sections 3.2.2 and 3.3.2). Standard methods currently do not exist
+ for remote entities to "assume" the credentials of a client for
+ forwarding requests to a 3rd party. It is anticipated that Print-By-
+ Reference will be used to access "public" documents and that
+ sophisticated methods for authenticating "proxies" is not specified
+ in this document.
+
+8.2 URIs in Operation, Job, and Printer attributes
+
+ The "printer-uri-supported" attribute contains the Printer object's
+ URI(s). Its companion attribute, "uri-security-supported",
+ identifies the security mechanism used for each URI listed in the
+ "printer-uri-supported" attribute. For each Printer operation
+ request, a client MUST supply only one URI in the "printer-uri"
+ operation attribute. In other words, even though the Printer
+ supports more than one URI, the client only interacts with the
+ Printer object using one if its URIs. This duality is not needed for
+ Job objects, since the Printer objects is the factory for Job
+ objects, and the Printer object will generate the correct URI for new
+ Job objects depending on the Printer object's security configuration.
+
+8.3 URIs for each authentication mechanisms
+
+ Each URI has an authentication mechanism associated with it. If the
+ URI is the i'th element of "printer-uri-supported", then
+ authentication mechanism is the "i th" element of "uri-
+ authentication-supported". For a list of possible authentication
+ mechanisms, see section 4.4.2.
+
+ The Printer object uses an authentication mechanism to determine the
+ name of the user performing an operation. This user is called the
+ "authenticated user". The credibility of authentication depends on
+ the mechanism that the Printer uses to obtain the user's name. When
+ the authentication mechanism is 'none', all authenticated users are
+ "anonymous".
+
+ During job creation operations, the Printer initializes the value of
+ the "job-originating-user-name" attribute (see section 4.3.6) to be
+ the authenticated user. The authenticated user is this case is called
+ the "job owner".
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 160]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ If an implementation can be configured to support more than one
+ authentication mechanism (see section 4.4.2), then it MUST implement
+ rules for determining equality of authenticated user names which have
+ been authenticated via different authentication mechanisms. One
+ possible policy is that identical names that are authenticated via
+ different mechanisms are different. For example, a user can cancel
+ his job only if he uses the same authentication mechanism for both
+ Cancel-Job and Print-Job. Another policy is that identical names
+ that are authenticated via different mechanism are the same if the
+ authentication mechanism for the later operation is not less strong
+ than the authentication mechanism for the earlier job creation
+ operation. For example, a user can cancel his job only if he uses
+ the same or stronger authentication mechanism for Cancel-Job and
+ Print-Job. With this second policy a job submitted via 'requesting-
+ user-name' authentication could be canceled via 'digest'
+ authentication. With the first policy, the job could not be canceled
+ in this way.
+
+ A client is able to determine the authentication mechanism used to
+ create a job. It is the i'th value of the Printer's "uri-
+ authentication-supported" attribute (see section 4.4.2), where i is
+ the index of the element of the Printer's "printer-uri-supported"
+ attribute (see section 4.4.1) equal to the job's "job-printer-uri"
+ attribute (see section 4.3.3).
+
+8.4 Restricted Queries
+
+ In many IPP operations, a client supplies a list of attributes to be
+ returned in the response. For security reasons, an IPP object may be
+ configured not to return all attributes (or all values) that a client
+ requests. The job attributes returned MAY depend on whether the
+ requesting user is the same as the user that submitted the job. The
+ IPP object MAY even return none of the requested attributes. In such
+ cases, the status returned is the same as if the object had returned
+ all requested attributes. The client cannot tell by such a response
+ whether the requested attribute was present or absent on the object.
+
+8.5 Operations performed by operators and system administrators
+
+ For the three printer operations Pause-Printer, Resume-Printer, and
+ Purge-Jobs (see sections 3.2.7, 3.2.8 and 3.2.9), the requesting user
+ is intended to be an operator or administrator of the Printer object
+ (see section 1). Otherwise, the IPP Printer MUST reject the
+ operation and return: 'client-error-forbidden', 'client-error-not-
+ authenticated', or 'client-error-not-authorized' as appropriate. For
+ operations on jobs, the requesting user is intended to be the job
+
+
+
+
+
+Hastings, et al. Standards Track [Page 161]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ owner or may be an operator or administrator of the Printer object.
+ The means for authorizing an operator or administrator of the Printer
+ object are not specified in this document.
+
+8.6 Queries on jobs submitted using non-IPP protocols
+
+ If the device that an IPP Printer is representing is able to accept
+ jobs using other job submission protocols in addition to IPP, it is
+ RECOMMENDED that such an implementation at least allow such "foreign"
+ jobs to be queried using Get-Jobs returning "job-id" and "job-uri" as
+ 'unknown'. Such an implementation NEED NOT support all of the same
+ IPP job attributes as for IPP jobs. The IPP object returns the
+ 'unknown' out-of-band value for any requested attribute of a foreign
+ job that is supported for IPP jobs, but not for foreign jobs.
+
+ It is further RECOMMENDED, that the IPP Printer generate "job-id" and
+ "job-uri" values for such "foreign jobs", if possible, so that they
+ may be targets of other IPP operations, such as Get-Job-Attributes
+ and Cancel-Job. Such an implementation also needs to deal with the
+ problem of authentication of such foreign jobs. One approach would
+ be to treat all such foreign jobs as belonging to users other than
+ the user of the IPP client. Another approach would be for the
+ foreign job to belong to 'anonymous'. Only if the IPP client has
+ been authenticated as an operator or administrator of the IPP Printer
+ object, could the foreign jobs be queried by an IPP request.
+ Alternatively, if the security policy is to allow users to query
+ other users' jobs, then the foreign jobs would also be visible to an
+ end-user IPP client using Get-Jobs and Get-Job-Attributes.
+
+9. References
+
+ [ASME-Y14.1M] Metric Drawing Sheet Size and Format, ASME Y14.1M-1995.
+ This standard defines metric sheet sizes and formats
+ for engineering drawings.
+
+ [ASCII] Coded Character Set - 7-bit American Standard Code for
+ Information Interchange (ASCII), ANSI X3.4-1986. This
+ standard is the specification of the US-ASCII charset.
+
+ [BCP-11] Bradner S. and R. Hovey, "The Organizations Involved in
+ the IETF Standards Process", BCP 11, RFC 2028, October
+ 1996.
+
+ [HTPP] J. Barnett, K. Carter, R. DeBry, "Initial Draft -
+ Hypertext Printing Protocol - HTPP/1.0", October 1996,
+ ftp://ftp.pwg.org/pub/pwg/ipp/historic/htpp/overview.ps.gz
+
+
+
+
+
+Hastings, et al. Standards Track [Page 162]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ [IANA-CON] Narten, T. and H. Alvestrand, "Guidelines for Writing
+ an IANA Considerations Section in RFCs", BCP 26, RFC
+ 2434, October 1998.
+
+ [IANA-CS] IANA Registry of Coded Character Sets:
+ ftp://ftp.isi.edu/in-notes/iana/assignments/character-
+ sets
+
+ [IANA-MT] IANA Registry of Media Types: ftp://ftp.isi.edu/in-
+ notes/iana/assignments/media-types/
+
+ [IPP-IIG] Hastings, T., Manros, C., Kugler, C., Holst, H., and P.
+ Zehler, "Internet Printing Protocol/1.1: draft-ietf-
+ ipp-implementers-guide-v11-01.txt, work in progress,
+ May 30, 2000.
+
+ [ISO10646-1] ISO/IEC 10646-1:1993, "Information technology --
+ Universal Multiple-Octet Coded Character Set (UCS) -
+ Part 1: Architecture and Basic Multilingual Plane,
+ JTC1/SC2."
+
+ [ISO8859-1] ISO/IEC 8859-1:1987, "Information technology -- 8-bit
+ One-Byte Coded Character Set - Part 1: Latin Alphabet
+ Nr 1", 1987, JTC1/SC2.
+
+ [ISO10175] ISO/IEC 10175 Document Printing Application (DPA), June
+ 1996.
+
+ [LDPA] T. Hastings, S. Isaacson, M. MacKay, C. Manros, D.
+ Taylor, P. Zehler, "LDPA - Lightweight Document
+ Printing Application", October 1996,
+ ftp://ftp.pwg.org/pub/pwg/ipp/historic/ldpa/ldpa8.pdf.gz
+
+ [P1387.4] Kirk, M. (editor), POSIX System Administration - Part
+ 4: Printing Interfaces, POSIX 1387.4 D8, 1994.
+
+ [PSIS] Herriot, R. (editor), X/Open A Printing System
+ Interoperability Specification (PSIS), August 1995.
+
+ [PWG] Printer Working Group, http://www.pwg.org.
+
+ [RFC1035] Mockapetris, P., "Domain Names - Implementation and
+ Specification", STD 13, RFC 1035, November 1987.
+
+ [RFC1179] McLaughlin, L., "Line Printer Daemon Protocol", RFC
+ 1179, August 1990.
+
+
+
+
+
+Hastings, et al. Standards Track [Page 163]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ [RFC1759] Smith, R., Wright, F., Hastings, T., Zilles, S. and J.
+ Gyllenskog, "Printer MIB", RFC 1759, March 1995.
+
+ [RFC1766] Alvestrand, H., "Tags for the Identification of
+ Languages", RFC 1766, March 1995.
+
+ [RFC1951] Deutsch, P., "DEFLATE Compressed Data Format
+ Specification version 1.3 ", RFC 1951, May 1996.
+
+ [RFC1952] Deutsch, P., "GZIP file format specification version
+ 4.3", RFC 1952, May 1996.
+
+ [RFC1977] Schryver, V., "PPP BSD Compression Protocol", RFC 1977,
+ August 1996.
+
+ [RFC2026] Bradner, S., "The Internet Standards Process --
+ Revision 3", BCP 9, RFC 2026, October 1996.
+
+ [RFC2045] Freed, N. and N. Borenstein, ", Multipurpose Internet
+ Mail Extensions (MIME) Part One: Format of Internet
+ Message Bodies", RFC 2045, November 1996.
+
+ [RFC2046] Freed, N. and N. Borenstein, "Multipurpose Internet
+ Mail Extensions (MIME) Part Two: Media Types", RFC
+ 2046, November 1996.
+
+ [RFC2048] Freed, N., Klensin, J. and J. Postel, "Multipurpose
+ Internet Mail Extension (MIME) Part Four: Registration
+ Procedures", RFC 2048, November 1996.
+
+ [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+ [RFC2228] Horowitz, M. and S. Lunt, "FTP Security Extensions",
+ RFC 2228, October 1997.
+
+ [RFC2246] Dierks, T. and C. Allen, "The TLS Protocol Version
+ 1.0", RFC 2246, January 1999.
+
+ [RFC2277] Alvestrand, H., "IETF Policy on Character Sets and
+ Languages" BCP 18, RFC 2277, January 1998.
+
+ [RFC2278] Freed, N. and J. Postel: "IANA CharSet Registration
+ Procedures", BCP 19, RFC 2278, January 1998.
+
+ [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO
+ 10646", RFC 2279, January 1998.
+
+
+
+
+Hastings, et al. Standards Track [Page 164]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ [RFC2316] Bellovin, S., "Report of the IAB Security Architecture
+ Workshop", RFC 2316, April 1998.
+
+ [RFC2396] Berners-Lee, T., Fielding, R. and L. Masinter, "Uniform
+ Resource Identifiers (URI): Generic Syntax", RFC 2396,
+ August 1998.
+
+ [RFC2565] Herriot, R., Butler, S., Moore, P. and R. Turner,
+ "Internet Printing Protocol/1.0: Encoding and
+ Transport", RFC 2565, April 1999.
+
+ [RFC2566] deBry, R., Hastings, T., Herriot, R., Isaacson, S. and
+ P. Powell, "Internet Printing Protocol/1.0: Model and
+ Semantics", RFC 2566, April 1999.
+
+ [RFC2567] Wright, D., "Design Goals for an Internet Printing
+ Protocol", RFC 2567, April 1999.
+
+ [RFC2568] Zilles, S., "Rationale for the Structure and Model and
+ Protocol for the Internet Printing Protocol", RFC 2568,
+ April 1999.
+
+ [RFC2569] Herriot, R., Hastings, T., Jacobs, N. and J. Martin,
+ "Mapping between LPD and IPP Protocols", RFC 2569,
+ April 1999.
+
+ [RFC2579] McCloghrie, K., Perkins, D. and J. Schoenwaelder,
+ "Textual Conventions for SMIv2", STD 58, RFC 2579,
+ April 1999.
+
+ [RFC2616] Fielding, R., Gettys, J., Mogul, J., Frystyk, H.,
+ Masinter, L., Leach, P. and T. Berners-Lee, "Hypertext
+ Transfer Protocol - HTTP/1.1", RFC 2616, June 1999.
+
+ [RFC2617] Franks, J., Hallam-Baker, P., Hostetler, J., Lawrence,
+ S., Leach, P., Luotonen, A. and L. Stewart, "HTTP
+ Authentication: Basic and Digest Access
+ Authentication", RFC 2617, June 1999.
+
+ [RFC2639] Hastings, T. and C. Manros, "Internet Printing
+ Protocol/1.0: Encoding and Transport", RFC 2639, July
+ 1999.
+
+ [RFC2910] Herriot, R., Butler, S., Moore, P., Turner, R. and J.
+ Wenn, "Internet Printing Protocol/1.1: Encoding and
+ Transport", RFC 2910, September 2000.
+
+
+
+
+
+Hastings, et al. Standards Track [Page 165]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ [SSL] Netscape, The SSL Protocol, Version 3, (Text version
+ 3.02), November 1996.
+
+ [SWP] P. Moore, B. Jahromi, S. Butler, "Simple Web Printing
+ SWP/1.0", May 7, 1997,
+ ftp://ftp.pwg.org/pub/pwg/ipp/new_PRO/swp9705.pdf
+
+10. Authors' Addresses
+
+ Scott A. Isaacson, Editor
+ Novell, Inc.
+ 122 E 1700 S
+ Provo, UT 84606
+
+ Phone: 801-861-7366
+ Fax: 801-861-2517
+ EMail: sisaacson@novell.com
+
+
+ Tom Hastings
+ Xerox Corporation
+ 737 Hawaii St. ESAE 231
+ El Segundo, CA 90245
+
+ Phone: 310-333-6413
+ Fax: 310-333-5514
+ EMail: hastings@cp10.es.xerox.com
+
+
+ Robert Herriot
+ Xerox Corp.
+ 3400 Hill View Ave, Building 1
+ Palo Alto, CA 94304
+
+ Phone: 650-813-7696
+ Fax: 650-813-6860
+ EMail: robert.herriot@pahv.xerox.com
+
+
+ Roger deBry
+ Utah Valley State College
+ Orem, UT 84058
+
+ Phone: (801) 222-8000
+ EMail: debryro@uvsc.edu
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 166]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Patrick Powell
+ Astart Technologies
+ 9475 Chesapeake Dr., Suite D
+ San Diego, CA 95123
+
+ Phone: (619) 874-6543
+ Fax: (619) 279-8424
+ EMail: papowell@astart.com
+
+ IPP Web Page: http://www.pwg.org/ipp/
+ IPP Mailing List: ipp@pwg.org
+
+ To subscribe to the ipp mailing list, send the following email:
+ 1) send it to majordomo@pwg.org
+ 2) leave the subject line blank
+ 3) put the following two lines in the message body:
+ subscribe ipp
+ end
+
+ Implementers of this specification document are encouraged to join
+ IPP Mailing List in order to participate in any discussions of
+ clarification issues and review of registration proposals for
+ additional attributes and values.
+
+ Other Participants:
+
+ Chuck Adams - Tektronix Shivaun Albright - HP
+ Stefan Andersson - Axis Jeff Barnett - IBM
+ Ron Bergman - Hitachi Koki Imaging Dennis Carney - IBM
+ Systems
+ Keith Carter - IBM Angelo Caruso - Xerox
+ Rajesh Chawla - TR Computing Nancy Chen - Okidata
+ Solutions
+ Josh Cohen - Microsoft Jeff Copeland - QMS
+ Andy Davidson - Tektronix Roger deBry - IBM
+ Maulik Desai - Auco Mabry Dozier - QMS
+ Lee Farrell - Canon Information Satoshi Fujitami - Ricoh
+ Systems
+ Steve Gebert - IBM Sue Gleeson - Digital
+ Charles Gordon - Osicom Brian Grimshaw - Apple
+ Jerry Hadsell - IBM Richard Hart - Digital
+ Tom Hastings - Xerox Henrik Holst - I-data
+ Stephen Holmstead Zhi-Hong Huang - Zenographics
+ Scott Isaacson - Novell Babek Jahromi - Microsoft
+ Swen Johnson - Xerox David Kellerman - Northlake
+ Software
+ Robert Kline - TrueSpectra Charles Kong - Panasonic
+ Carl Kugler - IBM Dave Kuntz - Hewlett-Packard
+
+
+
+Hastings, et al. Standards Track [Page 167]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Takami Kurono - Brother Rick Landau - Digital
+ Scott Lawrence - Agranot Systems Greg LeClair - Epson
+ Dwight Lewis - Lexmark Harry Lewis - IBM
+ Tony Liao - Vivid Image Roy Lomicka - Digital
+ Pete Loya - HP Ray Lutz - Cognisys
+ Mike MacKay - Novell, Inc. David Manchala - Xerox
+ Carl-Uno Manros - Xerox Jay Martin - Underscore
+ Stan McConnell - Xerox Larry Masinter - Xerox
+ Sandra Matts - Hewlett Packard Peter Michalek - Shinesoft
+ Ira McDonald - High North Inc. Mike Moldovan - G3 Nova
+ Tetsuya Morita - Ricoh Yuichi Niwa - Ricoh
+ Pat Nogay - IBM Ron Norton - Printronics
+ Hugo Parra, Novell Bob Pentecost - Hewlett-Packard
+ Patrick Powell - Astart Jeff Rackowitz - Intermec
+ Technologies
+ Eric Random - Peerless Rob Rhoads - Intel
+ Xavier Riley - Xerox Gary Roberts - Ricoh
+ David Roach - Unisys Stuart Rowley - Kyocera
+ Yuji Sasaki - Japan Computer Richard Schneider - Epson
+ Industry
+ Kris Schoff - HP Katsuaki Sekiguchi - Canon
+ Bob Setterbo - Adobe Gail Songer - Peerless
+ Hideki Tanaka - Cannon Devon Taylor - Novell
+ Mike Timperman - Lexmark Atsushi Uchino - Epson
+ Shigeru Ueda - Canon Bob Von Andel - Allegro Software
+ William Wagner - NetSilicon/DPI Jim Walker - DAZEL
+ Chris Wellens - Interworking Labs Trevor Wells - Hewlett Packard
+ Craig Whittle - Sharp Labs Rob Whittle - Novell, Inc.
+ Jasper Wong - Xionics Don Wright - Lexmark
+ Michael Wu - Heidelberg Digital Rick Yardumian - Xerox
+ Michael Yeung - Toshiba Lloyd Young - Lexmark
+ Atsushi Yuki - Kyocera Peter Zehler - Xerox
+ William Zhang- Canon Information Frank Zhao - Panasonic
+ Systems
+ Steve Zilles - Adobe Rob Zirnstein - Canon Information
+ Systems
+
+11. Formats for IPP Registration Proposals
+
+ In order to propose an IPP extension for registration, the proposer
+ must submit an application to IANA by email to "iana@iana.org" or by
+ filling out the appropriate form on the IANA web pages
+ (http://www.iana.org). This section specifies the required
+ information and the formats for proposing registrations of extensions
+ to IPP as provided in Section 6 for:
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 168]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 1. type2 'keyword' attribute values
+ 2. type3 'keyword' attribute values
+ 3. type2 'enum' attribute values
+ 4. type3 'enum' attribute values
+ 5. attributes
+ 6. attribute syntaxes
+ 7. operations
+ 8. status codes
+ 9. out-of-band attribute values
+
+11.1 Type2 keyword attribute values registration,
+
+ Type of registration: type2 keyword attribute value
+ Name of attribute to which this keyword specification is to be added:
+ Proposed keyword name of this keyword value:
+ Specification of this keyword value (follow the style of IPP Model
+ Section 4.1.2.3):
+ Name of proposer:
+ Address of proposer:
+ Email address of proposer:
+
+ Note: For type2 keywords, the Designated Expert will be the point of
+ contact for the approved registration specification, if any
+ maintenance of the registration specification is needed.
+
+11.2 Type3 keyword attribute values registration
+
+ Type of registration: type3 keyword attribute value
+ Name of attribute to which this keyword specification is to be added:
+ Proposed keyword name of this keyword value:
+ Specification of this keyword value (follow the style of IPP Model
+ Section 4.1.2.3):
+ Name of proposer:
+ Address of proposer:
+ Email address of proposer:
+
+ Note: For type3 keywords, the proposer will be the point of contact
+ for the approved registration specification, if any maintenance of
+ the registration specification is needed.
+
+11.3 Type2 enum attribute values registration
+
+ Type of registration: type2 enum attribute value
+ Name of attribute to which this enum specification is to be added:
+ Keyword symbolic name of this enum value:
+ Numeric value (to be assigned by the IPP Designated Expert in
+ consultation with IANA):
+
+
+
+
+Hastings, et al. Standards Track [Page 169]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Specification of this enum value (follow the style of IPP Model
+ Section 4.1.4):
+ Name of proposer:
+ Address of proposer:
+ Email address of proposer:
+
+ Note: For type2 enums, the Designated Expert will be the point of
+ contact for the approved registration specification, if any
+ maintenance of the registration specification is needed.
+
+11.4 Type3 enum attribute values registration
+
+ Type of registration: type3 enum attribute value
+ Name of attribute to which this enum specification is to be added:
+ Keyword symbolic name of this enum value:
+ Numeric value (to be assigned by the IPP Designated Expert in
+ consultation with IANA):
+ Specification of this enum value (follow the style of IPP Model
+ Section 4.1.4):
+ Name of proposer:
+ Address of proposer:
+ Email address of proposer:
+
+ Note: For type3 enums, the proposer will be the point of contact for
+ the approved registration specification, if any maintenance of the
+ registration specification is needed.
+
+11.5 Attribute registration
+
+ Type of registration: attribute
+ Proposed keyword name of this attribute:
+ Types of attribute (Operation, Job Template, Job Description, Printer
+ Description):
+ Operations to be used with if the attribute is an operation attribute:
+ Object (Job, Printer, etc. if bound to an object):
+ Attribute syntax(es) (include 1setOf and range as in Section 4.2):
+ If attribute syntax is 'keyword' or 'enum', is it type2 or type3:
+ If this is a Printer attribute, MAY the value returned depend on
+ "document-format" (See Section 6.2):
+ If this is a Job Template attribute, how does its specification depend
+ on the value of the "multiple-document-handling" attribute:
+ Specification of this attribute (follow the style of IPP Model Section
+ 4.2):
+ Name of proposer:
+ Address of proposer:
+ Email address of proposer:
+
+
+
+
+
+Hastings, et al. Standards Track [Page 170]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Note: For attributes, the IPP Designated Expert will be the point of
+ contact for the approved registration specification, if any
+ maintenance of the registration specification is needed.
+
+11.6 Attribute Syntax registration
+
+ Type of registration: attribute syntax
+ Proposed name of this attribute syntax:
+ Type of attribute syntax (integer, octetString, character-string, see
+ [RFC2910]):
+ Numeric tag according to [RFC2910] (to be assigned by the IPP
+ Designated Expert in consultation with IANA):
+ Specification of this attribute (follow the style of IPP Model Section
+ 4.1):
+ Name of proposer:
+ Address of proposer:
+ Email address of proposer:
+
+ Note: For attribute syntaxes, the IPP Designated Expert will be the
+ point of contact for the approved registration specification, if any
+ maintenance of the registration specification is needed.
+
+11.7 Operation registration
+
+ Type of registration: operation
+ Proposed name of this operation:
+ Numeric operation-id value according to section 4.4.15 (to be assigned
+ by the IPP Designated Expert in consultation with IANA):
+ Object Target (Job, Printer, etc. that operation is upon):
+ Specification of this operation (follow the style of IPP Model Section
+ 3):
+ Name of proposer:
+ Address of proposer:
+ Email address of proposer:
+
+ Note: For operations, the IPP Designated Expert will be the point of
+ contact for the approved registration specification, if any
+ maintenance of the registration specification is needed.
+
+11.8 Attribute Group registration
+
+ Type of registration: attribute group
+ Proposed name of this attribute group:
+ Numeric tag according to [RFC2910] (to be assigned by the IPP
+ Designated Expert in consultation with IANA):
+ Operation requests and group number for each operation in which the
+ attribute group occurs:
+
+
+
+
+Hastings, et al. Standards Track [Page 171]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Operation responses and group number for each operation in which the
+ attribute group occurs:
+ Specification of this attribute group (follow the style of IPP Model
+ Section 3):
+ Name of proposer:
+ Address of proposer:
+ Email address of proposer:
+
+ Note: For attribute groups, the IPP Designated Expert will be the
+ point of contact for the approved registration specification, if any
+ maintenance of the registration specification is needed.
+
+11.9 Status code registration
+
+ Type of registration: status code
+ Keyword symbolic name of this status code value:
+ Numeric value (to be assigned by the IPP Designated Expert in
+ consultation with IANA):
+ Operations that this status code may be used with:
+ Specification of this status code (follow the style of IPP Model
+ Section 13 APPENDIX B: Status Codes and Suggested Status Code
+ Messages):
+ Name of proposer:
+ Address of proposer:
+ Email address of proposer:
+
+ Note: For status codes, the Designated Expert will be the point of
+ contact for the approved registration specification, if any
+ maintenance of the registration specification is needed.
+
+11.10 Out-of-band Attribute Value registration
+
+ Type of registration: out-of-band attribute value
+ Proposed name of this out-of-band attribute value:
+ Numeric tag according to [RFC2910] (to be assigned by the IPP Designated
+ Expert in consultation with IANA):
+ Operations that this out-of-band attribute value may be used with:
+ Attributes that this out-of-band attribute value may be used with:
+ Specification of this out-of-band attribute value (follow the style of
+ the beginning of IPP Model Section 4.1):
+ Name of proposer:
+ Address of proposer:
+ Email address of proposer:
+
+ Note: For out-of-band attribute values, the IPP Designated Expert
+ will be the point of contact for the approved registration
+ specification, if any maintenance of the registration specification
+ is needed.
+
+
+
+Hastings, et al. Standards Track [Page 172]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+12. APPENDIX A: Terminology
+
+ This specification document uses the terminology defined in this
+ section.
+
+12.1 Conformance Terminology
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHOULD", "SHOULD NOT",
+ "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be
+ interpreted as described in RFC 2119 [RFC2119].
+
+12.1.1 NEED NOT
+
+ This term is not included in RFC 2119. The verb "NEED NOT" indicates
+ an action that the subject of the sentence does not have to implement
+ in order to claim conformance to the standard. The verb "NEED NOT"
+ is used instead of "MAY NOT" since "MAY NOT" sounds like a
+ prohibition.
+
+12.2 Model Terminology
+
+12.2.1 Keyword
+
+ Keywords are used within this document as identifiers of semantic
+ entities within the abstract model (see section 4.1.2.3). Attribute
+ names, some attribute values, attribute syntaxes, and attribute group
+ names are represented as keywords.
+
+12.2.2 Attributes
+
+ An attribute is an item of information that is associated with an
+ instance of an IPP object. An attribute consists of an attribute
+ name and one or more attribute values. Each attribute has a specific
+ attribute syntax. All object attributes are defined in section 4 and
+ all operation attributes are defined in section 3.
+
+ Job Template Attributes are described in section 4.2. The client
+ optionally supplies Job Template attributes in a create request
+ (operation requests that create Job objects). The Printer object has
+ associated attributes which define supported and default values for
+ the Printer.
+
+12.2.2.1 Attribute Name
+
+ Each attribute is uniquely identified in this document by its
+ attribute name. An attribute name is a keyword. The keyword
+ attribute name is given in the section header describing that
+
+
+
+
+Hastings, et al. Standards Track [Page 173]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ attribute. In running text in this document, attribute names are
+ indicated inside double quotation marks (") where the quotation marks
+ are not part of the keyword itself.
+
+12.2.2.2 Attribute Group Name
+
+ Related attributes are grouped into named groups. The name of the
+ group is a keyword. The group name may be used in place of naming
+ all the attributes in the group explicitly. Attribute groups are
+ defined in section 3.
+
+12.2.2.3 Attribute Value
+
+ Each attribute has one or more values. Attribute values are
+ represented in the syntax type specified for that attribute. In
+ running text in this document, attribute values are indicated inside
+ single quotation marks ('), whether their attribute syntax is
+ keyword, integer, text, etc. where the quotation marks are not part
+ of the value itself.
+
+12.2.2.4 Attribute Syntax
+
+ Each attribute is defined using an explicit syntax type. In this
+ document, each syntax type is defined as a keyword with specific
+ meaning. The "Encoding and Transport" document [RFC2910] indicates
+ the actual "on-the-wire" encoding rules for each syntax type.
+ Attribute syntax types are defined in section 4.1.
+
+12.2.3 Supports
+
+ By definition, a Printer object supports an attribute only if that
+ Printer object responds with the corresponding attribute populated
+ with some value(s) in a response to a query for that attribute. A
+ Printer object supports an attribute value if the value is one of the
+ Printer object's "supported values" attributes. The device behind a
+ Printer object may exhibit a behavior that corresponds to some IPP
+ attribute, but if the Printer object, when queried for that
+ attribute, doesn't respond with the attribute, then as far as IPP is
+ concerned, that implementation does not support that feature. If the
+ Printer object's "xxx-supported" attribute is not populated with a
+ particular value (even if that value is a legal value for that
+ attribute), then that Printer object does not support that particular
+ value.
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 174]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ A conforming implementation MUST support all REQUIRED attributes.
+ However, even for REQUIRED attributes, conformance to IPP does not
+ mandate that all implementations support all possible values
+ representing all possible job processing behaviors and features. For
+ example, if a given instance of a Printer supports only certain
+ document formats, then that Printer responds with the "document-
+ format-supported" attribute populated with a set of values, possibly
+ only one, taken from the entire set of possible values defined for
+ that attribute. This limited set of values represents the Printer's
+ set of supported document formats. Supporting an attribute and some
+ set of values for that attribute enables IPP end users to be aware of
+ and make use of those features associated with that attribute and
+ those values. If an implementation chooses to not support an
+ attribute or some specific value, then IPP end users would have no
+ ability to make use of that feature within the context of IPP itself.
+ However, due to existing practice and legacy systems which are not
+ IPP aware, there might be some other mechanism outside the scope of
+ IPP to control or request the "unsupported" feature (such as embedded
+ instructions within the document data itself).
+
+ For example, consider the "finishings-supported" attribute.
+
+ 1) If a Printer object is not physically capable of stapling, the
+ "finishings-supported" attribute MUST NOT be populated with the
+ value of 'staple'.
+ 2) A Printer object is physically capable of stapling, however an
+ implementation chooses not to support stapling in the IPP
+ "finishings" attribute. In this case, 'staple' MUST NOT be a
+ value in the "finishings-supported" Printer object attribute.
+ Without support for the value 'staple', an IPP end user would
+ have no means within the protocol itself to request that a Job
+ be stapled. However, an existing document data formatter might
+ be able to request that the document be stapled directly with
+ an embedded instruction within the document data. In this
+ case, the IPP implementation does not "support" stapling,
+ however the end user is still able to have some control over
+ the stapling of the completed job.
+ 3) A Printer object is physically capable of stapling, and an
+ implementation chooses to support stapling in the IPP
+ "finishings" attribute. In this case, 'staple' MUST be a value
+ in the "finishings-supported" Printer object attribute. Doing
+ so, would enable end users to be aware of and make use of the
+ stapling feature using IPP attributes.
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 175]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Even though support for Job Template attributes by a Printer object
+ is OPTIONAL, it is RECOMMENDED that if the device behind a Printer
+ object is capable of realizing any feature or function that
+ corresponds to an IPP attribute and some associated value, then that
+ implementation SHOULD support that IPP attribute and value.
+
+ The set of values in any of the supported value attributes is set
+ (populated) by some administrative process or automatic sensing
+ mechanism that is outside the scope of this IPP/1.1 document. For
+ administrative policy and control reasons, an administrator may
+ choose to make only a subset of possible values visible to the end
+ user. In this case, the real output device behind the IPP Printer
+ abstraction may be capable of a certain feature, however an
+ administrator is specifying that access to that feature not be
+ exposed to the end user through the IPP protocol. Also, since a
+ Printer object may represent a logical print device (not just a
+ physical device) the actual process for supporting a value is
+ undefined and left up to the implementation. However, if a Printer
+ object supports a value, some manual human action may be needed to
+ realize the semantic action associated with the value, but no end
+ user action is required.
+
+ For example, if one of the values in the "finishings-supported"
+ attribute is 'staple', the actual process might be an automatic
+ staple action by a physical device controlled by some command sent to
+ the device. Or, the actual process of stapling might be a manual
+ action by an operator at an operator attended Printer object.
+
+ For another example of how supported attributes function, consider a
+ system administrator who desires to control all print jobs so that no
+ job sheets are printed in order to conserve paper. To force no job
+ sheets, the system administrator sets the only supported value for
+ the "job-sheets-supported" attribute to 'none'. In this case, if a
+ client requests anything except 'none', the create request is
+ rejected or the "job-sheets" value is ignored (depending on the value
+ of "ipp-attribute-fidelity"). To force the use of job start/end
+ sheets on all jobs, the administrator does not include the value
+ 'none' in the "job-sheets- supported" attribute. In this case, if a
+ client requests 'none', the create request is rejected or the "job-
+ sheets" value is ignored (again depending on the value of "ipp-
+ attribute-fidelity").
+
+12.2.4 print-stream page
+
+ A "print-stream page" is a page according to the definition of pages
+ in the language used to express the document data.
+
+
+
+
+
+Hastings, et al. Standards Track [Page 176]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+12.2.5 impression
+
+ An "impression" is the image (possibly many print-stream pages in
+ different configurations) imposed onto a single media page.
+
+13. APPENDIX B: Status Codes and Suggested Status Code Messages
+
+ This section defines status code enum keywords and values that are
+ used to provide semantic information on the results of an operation
+ request. Each operation response MUST include a status code. The
+ response MAY also contain a status message that provides a short
+ textual description of the status. The status code is intended for
+ use by automata, and the status message is intended for the human end
+ user. Since the status message is an OPTIONAL component of the
+ operation response, an IPP application (i.e., a browser, GUI, print
+ driver or gateway) is NOT REQUIRED to examine or display the status
+ message, since it MAY not be returned to the application.
+
+ The prefix of the status keyword defines the class of response as
+ follows:
+
+ "informational" - Request received, continuing process
+ "successful" - The action was successfully received, understood,
+ and accepted
+ "redirection" - Further action must be taken in order to complete
+ the request
+ "client-error" - The request contains bad syntax or cannot be
+ fulfilled
+ "server-error" - The IPP object failed to fulfill an apparently
+ valid request
+
+ As with type2 enums, IPP status codes are extensible. IPP clients
+ are NOT REQUIRED to understand the meaning of all registered status
+ codes, though such understanding is obviously desirable. However,
+ IPP clients MUST understand the class of any status code, as
+ indicated by the prefix, and treat any unrecognized response as being
+ equivalent to the first status code of that class, with the exception
+ that an unrecognized response MUST NOT be cached. For example, if an
+ unrecognized status code of "client-error-xxx-yyy" is received by the
+ client, it can safely assume that there was something wrong with its
+ request and treat the response as if it had received a "client-
+ error-bad-request" status code. In such cases, IPP applications
+ SHOULD present the OPTIONAL message (if present) to the end user
+ since the message is likely to contain human readable information
+ which will help to explain the unusual status. The name of the enum
+ is the suggested status message for US English.
+
+
+
+
+
+Hastings, et al. Standards Track [Page 177]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ The status code values range from 0x0000 to 0x7FFF. The value ranges
+ for each status code class are as follows:
+
+ "successful" - 0x0000 to 0x00FF
+ "informational" - 0x0100 to 0x01FF
+ "redirection" - 0x0200 to 0x02FF
+ "client-error" - 0x0400 to 0x04FF
+ "server-error" - 0x0500 to 0x05FF
+
+ The top half (128 values) of each range (0x0n40 to 0x0nFF, for n = 0
+ to 5) is reserved for vendor use within each status code class.
+ Values 0x0600 to 0x7FFF are reserved for future assignment by IETF
+ standards track documents and MUST NOT be used.
+
+13.1 Status Codes
+
+ Each status code is described below. Section 13.1.5.9 contains a
+ table that indicates which status codes apply to which operations.
+ The Implementer's Guide [IPP-IIG] describe the suggested steps for
+ processing IPP attributes for all operations, including returning
+ status codes.
+
+13.1.1 Informational
+
+ This class of status code indicates a provisional response and is to
+ be used for informational purposes only.
+
+ There are no status codes defined in IPP/1.1 for this class of status
+ code.
+
+13.1.2 Successful Status Codes
+
+ This class of status code indicates that the client's request was
+ successfully received, understood, and accepted.
+
+13.1.2.1 successful-ok (0x0000)
+
+ The request has succeeded and no request attributes were substituted
+ or ignored. In the case of a response to a create request, the
+ 'successful-ok' status code indicates that the request was
+ successfully received and validated, and that the Job object has been
+ created; it does not indicate that the job has been processed. The
+ transition of the Job object into the 'completed' state is the only
+ indicator that the job has been printed.
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 178]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+13.1.2.2 successful-ok-ignored-or-substituted-attributes (0x0001)
+
+ The request has succeeded, but some supplied (1) attributes were
+ ignored or (2) unsupported values were substituted with supported
+ values or were ignored in order to perform the operation without
+ rejecting it. Unsupported attributes, attribute syntaxes, or values
+ MUST be returned in the Unsupported Attributes group of the response
+ for all operations. There is an exception to this rule for the query
+ operations: Get-Printer-Attributes, Get-Jobs, and Get-Job-Attributes
+ for the "requested-attributes" operation attribute only. When the
+ supplied values of the "requested-attributes" operation attribute are
+ requesting attributes that are not supported, the IPP object MAY, but
+ is NOT REQUIRED to, return the "requested-attributes" attribute in
+ the Unsupported Attribute response group (with the unsupported values
+ only). See sections 3.1.7 and 3.2.1.2.
+
+13.1.2.3 successful-ok-conflicting-attributes (0x0002)
+
+ The request has succeeded, but some supplied attribute values
+ conflicted with the values of other supplied attributes. These
+ conflicting values were either (1) substituted with (supported)
+ values or (2) the attributes were removed in order to process the job
+ without rejecting it. Attributes or values which conflict with other
+ attributes and have been substituted or ignored MUST be returned in
+ the Unsupported Attributes group of the response for all operations
+ as supplied by the client. See sections 3.1.7 and 3.2.1.2.
+
+13.1.3 Redirection Status Codes
+
+ This class of status code indicates that further action needs to be
+ taken to fulfill the request.
+
+ There are no status codes defined in IPP/1.1 for this class of status
+ code.
+
+13.1.4 Client Error Status Codes
+
+ This class of status code is intended for cases in which the client
+ seems to have erred. The IPP object SHOULD return a message
+ containing an explanation of the error situation and whether it is a
+ temporary or permanent condition.
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 179]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+13.1.4.1 client-error-bad-request (0x0400)
+
+ The request could not be understood by the IPP object due to
+ malformed syntax (such as the value of a fixed length attribute whose
+ length does not match the prescribed length for that attribute - see
+ the Implementer's Guide [IPP-IIG] ). The IPP application SHOULD NOT
+ repeat the request without modifications.
+
+13.1.4.2 client-error-forbidden (0x0401)
+
+ The IPP object understood the request, but is refusing to fulfill it.
+ Additional authentication information or authorization credentials
+ will not help and the request SHOULD NOT be repeated. This status
+ code is commonly used when the IPP object does not wish to reveal
+ exactly why the request has been refused or when no other response is
+ applicable.
+
+13.1.4.3 client-error-not-authenticated (0x0402)
+
+ The request requires user authentication. The IPP client may repeat
+ the request with suitable authentication information. If the request
+ already included authentication information, then this status code
+ indicates that authorization has been refused for those credentials.
+ If this response contains the same challenge as the prior response,
+ and the user agent has already attempted authentication at least
+ once, then the response message may contain relevant diagnostic
+ information. This status codes reveals more information than
+ "client-error-forbidden".
+
+13.1.4.4 client-error-not-authorized (0x0403)
+
+ The requester is not authorized to perform the request. Additional
+ authentication information or authorization credentials will not help
+ and the request SHOULD NOT be repeated. This status code is used
+ when the IPP object wishes to reveal that the authentication
+ information is understandable, however, the requester is explicitly
+ not authorized to perform the request. This status codes reveals
+ more information than "client-error-forbidden" and "client-error-
+ not-authenticated".
+
+13.1.4.5 client-error-not-possible (0x0404)
+
+ This status code is used when the request is for something that can
+ not happen. For example, there might be a request to cancel a job
+ that has already been canceled or aborted by the system. The IPP
+ client SHOULD NOT repeat the request.
+
+
+
+
+
+Hastings, et al. Standards Track [Page 180]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+13.1.4.6 client-error-timeout (0x0405)
+
+ The client did not produce a request within the time that the IPP
+ object was prepared to wait. For example, a client issued a Create-
+ Job operation and then, after a long period of time, issued a Send-
+ Document operation and this error status code was returned in
+ response to the Send-Document request (see section 3.3.1). The IPP
+ object might have been forced to clean up resources that had been
+ held for the waiting additional Documents. The IPP object was forced
+ to close the Job since the client took too long. The client SHOULD
+ NOT repeat the request without modifications.
+
+13.1.4.7 client-error-not-found (0x0406)
+
+ The IPP object has not found anything matching the request URI. No
+ indication is given of whether the condition is temporary or
+ permanent. For example, a client with an old reference to a Job (a
+ URI) tries to cancel the Job, however in the mean time the Job might
+ have been completed and all record of it at the Printer has been
+ deleted. This status code, 'client-error-not-found' is returned
+ indicating that the referenced Job can not be found. This error
+ status code is also used when a client supplies a URI as a reference
+ to the document data in either a Print-URI or Send-URI operation, but
+ the document can not be found.
+
+ In practice, an IPP application should avoid a not found situation by
+ first querying and presenting a list of valid Printer URIs and Job
+ URIs to the end-user.
+
+13.1.4.8 client-error-gone (0x0407)
+
+ The requested object is no longer available and no forwarding address
+ is known. This condition should be considered permanent. Clients
+ with link editing capabilities should delete references to the
+ request URI after user approval. If the IPP object does not know or
+ has no facility to determine, whether or not the condition is
+ permanent, the status code "client-error-not-found" should be used
+ instead.
+
+ This response is primarily intended to assist the task of maintenance
+ by notifying the recipient that the resource is intentionally
+ unavailable and that the IPP object administrator desires that remote
+ links to that resource be removed. It is not necessary to mark all
+ permanently unavailable resources as "gone" or to keep the mark for
+ any length of time -- that is left to the discretion of the IPP
+ object administrator and/or Printer implementation.
+
+
+
+
+
+Hastings, et al. Standards Track [Page 181]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+13.1.4.9 client-error-request-entity-too-large (0x0408)
+
+ The IPP object is refusing to process a request because the request
+ entity is larger than the IPP object is willing or able to process.
+ An IPP Printer returns this status code when it limits the size of
+ print jobs and it receives a print job that exceeds that limit or
+ when the attributes are so many that their encoding causes the
+ request entity to exceed IPP object capacity.
+
+13.1.4.10 client-error-request-value-too-long (0x0409)
+
+ The IPP object is refusing to service the request because one or more
+ of the client-supplied attributes has a variable length value that is
+ longer than the maximum length specified for that attribute. The IPP
+ object might not have sufficient resources (memory, buffers, etc.) to
+ process (even temporarily), interpret, and/or ignore a value larger
+ than the maximum length. Another use of this error code is when the
+ IPP object supports the processing of a large value that is less than
+ the maximum length, but during the processing of the request as a
+ whole, the object may pass the value onto some other system component
+ which is not able to accept the large value. For more details, see
+ the Implementer's Guide [IPP-IIG] .
+
+ Note: For attribute values that are URIs, this rare condition is
+ only likely to occur when a client has improperly submitted a request
+ with long query information (e.g. an IPP application allows an end-
+ user to enter an invalid URI), when the client has descended into a
+ URI "black hole" of redirection (e.g., a redirected URI prefix that
+ points to a suffix of itself), or when the IPP object is under attack
+ by a client attempting to exploit security holes present in some IPP
+ objects using fixed-length buffers for reading or manipulating the
+ Request-URI.
+
+13.1.4.11 client-error-document-format-not-supported (0x040A)
+
+ The IPP object is refusing to service the request because the
+ document data is in a format, as specified in the "document-format"
+ operation attribute, that is not supported by the Printer object.
+ This error is returned independent of the client-supplied "ipp-
+ attribute-fidelity". The Printer object MUST return this status
+ code, even if there are other Job Template attributes that are not
+ supported as well, since this error is a bigger problem than with Job
+ Template attributes. See sections 3.1.6.1, 3.1.7, and 3.2.1.1.
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 182]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+13.1.4.12 client-error-attributes-or-values-not-supported (0x040B)
+
+ In a create request, if the Printer object does not support one or
+ more attributes, attribute syntaxes, or attribute values supplied in
+ the request and the client supplied the "ipp-attribute-fidelity"
+ operation attribute with the 'true' value, the Printer object MUST
+ return this status code. The Printer object MUST also return in the
+ Unsupported Attributes Group all the attributes and/or values
+ supplied by the client that are not supported. See section 3.1.7.
+ For example, if the request indicates 'iso-a4' media, but that media
+ type is not supported by the Printer object. Or, if the client
+ supplies a Job Template attribute and the attribute itself is not
+ even supported by the Printer. If the "ipp-attribute-fidelity"
+ attribute is 'false', the Printer MUST ignore or substitute values
+ for unsupported Job Template attributes and values rather than reject
+ the request and return this status code.
+
+ For any operation where a client requests attributes (such as a Get-
+ Jobs, Get-Printer-Attributes, or Get-Job-Attributes operation), if
+ the IPP object does not support one or more of the requested
+ attributes, the IPP object simply ignores the unsupported requested
+ attributes and processes the request as if they had not been
+ supplied, rather than returning this status code. In this case, the
+ IPP object MUST return the 'successful-ok-ignored-or-substituted-
+ attributes' status code and MAY return the unsupported attributes as
+ values of the "requested-attributes" in the Unsupported Attributes
+ Group (see section 13.1.2.2).
+
+13.1.4.13 client-error-uri-scheme-not-supported (0x040C)
+
+ The scheme of the client-supplied URI in a Print-URI or a Send-URI
+ operation is not supported. See sections 3.1.6.1 and 3.1.7.
+
+13.1.4.14 client-error-charset-not-supported (0x040D)
+
+ For any operation, if the IPP Printer does not support the charset
+ supplied by the client in the "attributes-charset" operation
+ attribute, the Printer MUST reject the operation and return this
+ status and any 'text' or 'name' attributes using the 'utf-8' charset
+ (see Section 3.1.4.1). See sections 3.1.6.1 and 3.1.7.
+
+13.1.4.15 client-error-conflicting-attributes (0x040E)
+
+ The request is rejected because some attribute values conflicted with
+ the values of other attributes which this document does not permit to
+ be substituted or ignored. The Printer object MUST also return in
+ the Unsupported Attributes Group the conflicting attributes supplied
+ by the client. See sections 3.1.7 and 3.2.1.2.
+
+
+
+Hastings, et al. Standards Track [Page 183]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+13.1.4.16 client-error-compression-not-supported (0x040F)
+
+ The IPP object is refusing to service the request because the
+ document data, as specified in the "compression" operation attribute,
+ is compressed in a way that is not supported by the Printer object.
+ This error is returned independent of the client-supplied "ipp-
+ attribute-fidelity". The Printer object MUST return this status
+ code, even if there are other Job Template attributes that are not
+ supported as well, since this error is a bigger problem than with Job
+ Template attributes. See sections 3.1.6.1, 3.1.7, and 3.2.1.1.
+
+13.1.4.17 client-error-compression-error (0x0410)
+
+ The IPP object is refusing to service the request because the
+ document data cannot be decompressed when using the algorithm
+ specified by the "compression" operation attribute. This error is
+ returned independent of the client-supplied "ipp-attribute-fidelity".
+ The Printer object MUST return this status code, even if there are
+ Job Template attributes that are not supported as well, since this
+ error is a bigger problem than with Job Template attributes. See
+ sections 3.1.7 and 3.2.1.1.
+
+13.1.4.18 client-error-document-format-error (0x0411)
+
+ The IPP object is refusing to service the request because Printer
+ encountered an error in the document data while interpreting it.
+ This error is returned independent of the client-supplied "ipp-
+ attribute-fidelity". The Printer object MUST return this status
+ code, even if there are Job Template attributes that are not
+ supported as well, since this error is a bigger problem than with Job
+ Template attributes. See sections 3.1.7 and 3.2.1.1.
+
+13.1.4.19 client-error-document-access-error (0x0412)
+
+ The IPP object is refusing to service the Print-URI or Send-URI
+ request because Printer encountered an access error while attempting
+ to validate the accessibility or access the document data specified
+ in the "document-uri" operation attribute. The Printer MAY also
+ return a specific document access error code using the "document-
+ access-error" operation attribute (see section 3.1.6.4). This error
+ is returned independent of the client-supplied "ipp-attribute-
+ fidelity". The Printer object MUST return this status code, even if
+ there are Job Template attributes that are not supported as well,
+ since this error is a bigger problem than with Job Template
+ attributes. See sections 3.1.6.1 and 3.1.7.
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 184]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+13.1.5 Server Error Status Codes
+
+ This class of status codes indicates cases in which the IPP object is
+ aware that it has erred or is incapable of performing the request.
+ The IPP object SHOULD include a message containing an explanation of
+ the error situation, and whether it is a temporary or permanent
+ condition.
+
+13.1.5.1 server-error-internal-error (0x0500)
+
+ The IPP object encountered an unexpected condition that prevented it
+ from fulfilling the request. This error status code differs from
+ "server-error-temporary-error" in that it implies a more permanent
+ type of internal error. It also differs from "server-error-device-
+ error" in that it implies an unexpected condition (unlike a paper-jam
+ or out-of-toner problem which is undesirable but expected). This
+ error status code indicates that probably some knowledgeable human
+ intervention is required.
+
+13.1.5.2 server-error-operation-not-supported (0x0501)
+
+ The IPP object does not support the functionality required to fulfill
+ the request. This is the appropriate response when the IPP object
+ does not recognize an operation or is not capable of supporting it.
+ See sections 3.1.6.1 and 3.1.7.
+
+13.1.5.3 server-error-service-unavailable (0x0502)
+
+ The IPP object is currently unable to handle the request due to a
+ temporary overloading or maintenance of the IPP object. The
+ implication is that this is a temporary condition which will be
+ alleviated after some delay. If known, the length of the delay may be
+ indicated in the message. If no delay is given, the IPP application
+ should handle the response as it would for a "server-error-
+ temporary-error" response. If the condition is more permanent, the
+ error status codes "client-error-gone" or "client-error-not-found"
+ could be used.
+
+13.1.5.4 server-error-version-not-supported (0x0503)
+
+ The IPP object does not support, or refuses to support, the IPP
+ protocol version that was supplied as the value of the "version-
+ number" operation parameter in the request. The IPP object is
+ indicating that it is unable or unwilling to complete the request
+ using the same major and minor version number as supplied in the
+ request other than with this error message. The error response SHOULD
+ contain a "status-message" attribute (see section 3.1.6.2) describing
+
+
+
+
+Hastings, et al. Standards Track [Page 185]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ why that version is not supported and what other versions are
+ supported by that IPP object. See sections 3.1.6.1, 3.1.7, and
+ 3.1.8.
+
+ The error response MUST identify in the "version-number" operation
+ parameter the closest version number that the IPP object does
+ support. For example, if a client supplies version '1.0' and an
+ IPP/1.1 object supports version '1.0', then it responds with version
+ '1.0' in all responses to such a request. If the IPP/1.1 object does
+ not support version '1.0', then it should accept the request and
+ respond with version '1.1' or may reject the request and respond with
+ this error code and version
+ '1.1'. If a client supplies a version '1.2', the IPP/1.1 object
+ should accept the request and return version '1.1' or may reject the
+ request and respond with this error code and version '1.1'. See
+ sections 3.1.8 and 4.4.14.
+
+13.1.5.5 server-error-device-error (0x0504)
+
+ A printer error, such as a paper jam, occurs while the IPP object
+ processes a Print or Send operation. The response contains the true
+ Job Status (the values of the "job-state" and "job-state-reasons"
+ attributes). Additional information can be returned in the OPTIONAL
+ "job-state-message" attribute value or in the OPTIONAL status message
+ that describes the error in more detail. This error status code is
+ only returned in situations where the Printer is unable to accept the
+ create request because of such a device error. For example, if the
+ Printer is unable to spool, and can only accept one job at a time,
+ the reason it might reject a create request is that the printer
+ currently has a paper jam. In many cases however, where the Printer
+ object can accept the request even though the Printer has some error
+ condition, the 'successful-ok' status code will be returned. In such
+ a case, the client would look at the returned Job Object Attributes
+ or later query the Printer to determine its state and state reasons.
+
+13.1.5.6 server-error-temporary-error (0x0505)
+
+ A temporary error such as a buffer full write error, a memory
+ overflow (i.e. the document data exceeds the memory of the Printer),
+ or a disk full condition, occurs while the IPP Printer processes an
+ operation. The client MAY try the unmodified request again at some
+ later point in time with an expectation that the temporary internal
+ error condition may have been cleared. Alternatively, as an
+ implementation option, a Printer object MAY delay the response until
+ the temporary condition is cleared so that no error is returned.
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 186]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+13.1.5.7 server-error-not-accepting-jobs (0x0506)
+
+ A temporary error indicating that the Printer is not currently
+ accepting jobs, because the administrator has set the value of the
+ Printer's "printer-is-accepting-jobs" attribute to 'false' (by means
+ outside the scope of this IPP/1.1 document).
+
+13.1.5.8 server-error-busy (0x0507)
+
+ A temporary error indicating that the Printer is too busy processing
+ jobs and/or other requests. The client SHOULD try the unmodified
+ request again at some later point in time with an expectation that
+ the temporary busy condition will have been cleared.
+
+13.1.5.9 server-error-job-canceled (0x0508)
+
+ An error indicating that the job has been canceled by an operator or
+ the system while the client was transmitting the data to the IPP
+ Printer. If a job-id and job-uri had been created, then they are
+ returned in the Print-Job, Send-Document, or Send-URI response as
+ usual; otherwise, no job-id and job-uri are returned in the response.
+
+13.1.5.10 server-error-multiple-document-jobs-not-supported (0x0509)
+
+ The IPP object does not support multiple documents per job and a
+ client attempted to supply document data with a second Send-Document
+ or Send-URI operation.
+
+13.2 Status Codes for IPP Operations
+
+ PJ = Print-Job, PU = Print-URI, CJ = Create-Job, SD = Send-Document
+ SU = Send-URI, V = Validate-Job, GA = Get-Job-Attributes and
+ Get-Printer-Attributes, GJ = Get-Jobs, C = Cancel-Job
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 187]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ IPP Operations
+ IPP Status Keyword PJ PU CJ SD SU V GA GJ C
+ ------------------ -- -- -- -- -- - -- -- -
+ successful-ok x x x x x x x x x
+ successful-ok-ignored-or-substituted- x x x x x x x x x
+ attributes
+ successful-ok-conflicting-attributes x x x x x x x x x
+ client-error-bad-request x x x x x x x x x
+ client-error-forbidden x x x x x x x x x
+ client-error-not-authenticated x x x x x x x x x
+ client-error-not-authorized x x x x x x x x x
+ client-error-not-possible x x x x x x x x x
+ client-error-timeout x x
+ client-error-not-found x x x x x x x x x
+ client-error-gone x x x x x x x x x
+ client-error-request-entity-too-large x x x x x x x x x
+ client-error-request-value-too-long x x x x x x x x x
+ client-error-document-format-not- x x x x x x
+ supported
+ client-error-attributes-or-values-not- x x x x x x x x x
+ supported
+ client-error-uri-scheme-not-supported x x
+ client-error-charset-not-supported x x x x x x x x x
+ client-error-conflicting-attributes x x x x x x x x x
+ client-error-compression-not-supported x x x x x
+ client-error-compression-error x x x x
+ client-error-document-format-error x x x x
+ client-error-document-access-error x x
+ server-error-internal-error x x x x x x x x x
+ server-error-operation-not-supported x x x x
+ server-error-service-unavailable x x x x x x x x x
+ server-error-version-not-supported x x x x x x x x x
+ server-error-device-error x x x x x
+ server-error-temporary-error x x x x x
+ server-error-not-accepting-jobs x x x x
+ server-error-busy x x x x x x x x x
+ server-error-job-canceled x x x
+ server-error-multiple-document-jobs- x x
+ not-supported
+
+ HJ = Hold-Job, RJ = Release-Job, RS = Restart-Job
+ PP = Pause-Printer, RP = Resume-Printer, PJ = Purge-Jobs
+
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 188]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ IPP Operations (cont.)
+ IPP Status Keyword HJ RJ RS PP RP PJ
+ ------------------ -- -- -- -- -- --
+ successful-ok x x x x x x
+ successful-ok-ignored-or-substituted- x x x x x x
+ attributes
+ successful-ok-conflicting-attributes x x x x x x
+ client-error-bad-request x x x x x x
+ client-error-forbidden x x x x x x
+ client-error-not-authenticated x x x x x x
+ client-error-not-authorized x x x x x x
+ client-error-not-possible x x x x x x
+ client-error-timeout
+ client-error-not-found x x x x x x
+ client-error-gone x x x x x x
+ client-error-request-entity-too-large x x x x x x
+ client-error-request-value-too-long x x x x x x
+ client-error-document-format-not-
+ supported
+ client-error-attributes-or-values-not- x x x x x x
+ supported
+ client-error-uri-scheme-not-supported
+ client-error-charset-not-supported x x x x x x
+ client-error-conflicting-attributes x x x x x x
+ client-error-compression-not-supported
+ client-error-compression-error
+ client-error-document-format-error
+ client-error-document-access-error
+ server-error-internal-error x x x x x x
+ server-error-operation-not-supported x x x x x x
+ server-error-service-unavailable x x x x x x
+ server-error-version-not-supported x x x x x x
+ server-error-device-error
+ server-error-temporary-error x x x x x x
+ server-error-not-accepting-jobs
+ server-error-busy x x x x x x
+ server-error-job-canceled
+ server-error-multiple-document-jobs-
+ not-supported
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 189]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+14. APPENDIX C: "media" keyword values
+
+ Standard keyword values are taken from several sources.
+
+ Standard values are defined (taken from DPA[ISO10175] and the Printer
+ MIB[RFC1759]):
+
+ 'default': The default medium for the output device
+ 'iso-a4-white': Specifies the ISO A4 white medium: 210 mm x 297 mm
+ 'iso-a4-colored': Specifies the ISO A4 colored medium: 210 mm x 297
+ mm
+ 'iso-a4-transparent' Specifies the ISO A4 transparent medium: 210 mm
+ x 297 mm
+ 'iso-a3-white': Specifies the ISO A3 white medium: 297 mm x 420 mm
+ 'iso-a3-colored': Specifies the ISO A3 colored medium: 297 mm x 420
+ mm
+ 'iso-a5-white': Specifies the ISO A5 white medium: 148 mm x 210 mm
+ 'iso-a5-colored': Specifies the ISO A5 colored medium: 148 mm x 210
+ mm
+ 'iso-b4-white': Specifies the ISO B4 white medium: 250 mm x 353 mm
+ 'iso-b4-colored': Specifies the ISO B4 colored medium: 250 mm x 353
+ mm
+ 'iso-b5-white': Specifies the ISO B5 white medium: 176 mm x 250 mm
+ 'iso-b5-colored': Specifies the ISO B5 colored medium: 176 mm x 250
+ mm
+ 'jis-b4-white': Specifies the JIS B4 white medium: 257 mm x 364 mm
+ 'jis-b4-colored': Specifies the JIS B4 colored medium: 257 mm x 364
+ mm
+ 'jis-b5-white': Specifies the JIS B5 white medium: 182 mm x 257 mm
+ 'jis-b5-colored': Specifies the JIS B5 colored medium: 182 mm x 257
+ mm
+
+ The following standard values are defined for North American media:
+
+ 'na-letter-white': Specifies the North American letter white medium
+ 'na-letter-colored': Specifies the North American letter colored
+ medium
+ 'na-letter-transparent': Specifies the North American letter
+ transparent medium
+ 'na-legal-white': Specifies the North American legal white medium
+ 'na-legal-colored': Specifies the North American legal colored
+ medium
+
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 190]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ The following standard values are defined for envelopes:
+
+ 'iso-b4-envelope': Specifies the ISO B4 envelope medium
+ 'iso-b5-envelope': Specifies the ISO B5 envelope medium
+ 'iso-c3-envelope': Specifies the ISO C3 envelope medium
+ 'iso-c4-envelope': Specifies the ISO C4 envelope medium
+ 'iso-c5-envelope': Specifies the ISO C5 envelope medium
+ 'iso-c6-envelope': Specifies the ISO C6 envelope medium
+ 'iso-designated-long-envelope': Specifies the ISO Designated Long
+ envelope medium
+ 'na-10x13-envelope': Specifies the North American 10x13 envelope
+ medium
+ 'na-9x12-envelope': Specifies the North American 9x12 envelope
+ medium
+ 'monarch-envelope': Specifies the Monarch envelope
+ 'na-number-10-envelope': Specifies the North American number 10
+ business envelope medium
+ 'na-7x9-envelope': Specifies the North American 7x9 inch envelope
+ 'na-9x11-envelope': Specifies the North American 9x11 inch
+ envelope
+ 'na-10x14-envelope': Specifies the North American 10x14 inch
+ envelope
+ 'na-number-9-envelope': Specifies the North American number 9
+ business envelope
+ 'na-6x9-envelope': Specifies the North American 6x9 inch envelope
+ 'na-10x15-envelope': Specifies the North American 10x15 inch
+ envelope
+
+ The following standard values are defined for the less commonly used
+ media:
+
+ 'executive-white': Specifies the white executive medium
+ 'folio-white': Specifies the folio white medium
+ 'invoice-white': Specifies the white invoice medium
+ 'ledger-white': Specifies the white ledger medium
+ 'quarto-white': Specified the white quarto medium
+ 'iso-a0-white': Specifies the ISO A0 white medium: 841 mm x 1189 mm
+ 'iso-a0-transparent': Specifies the ISO A0 transparent medium: 841 mm
+ x 1189 mm
+ 'iso-a0-translucent': Specifies the ISO A0 translucent medium: 841 mm
+ x 1189 mm
+ 'iso-a1-white': Specifies the ISO A1 white medium: 594 mm x 841 mm
+ 'iso-a1-transparent': Specifies the ISO A1 transparent medium: 594 mm
+ x 841 mm
+ 'iso-a1-translucent': Specifies the ISO A1 translucent medium: 594 mm
+ x 841 mm
+ 'iso-a2-white': Specifies the ISO A2 white medium: 420 mm x 594 mm
+
+
+
+
+Hastings, et al. Standards Track [Page 191]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 'iso-a2-transparent': Specifies the ISO A2 transparent medium: 420 mm
+ x 594 mm
+ 'iso-a2-translucent': Specifies the ISO A2 translucent medium: 420 mm
+ x 594 mm
+ 'iso-a3-transparent': Specifies the ISO A3 transparent medium: 297 mm
+ x 420 mm
+ 'iso-a3-translucent': Specifies the ISO A3 translucent medium: 297 mm
+ x 420 mm
+ 'iso-a4-translucent': Specifies the ISO A4 translucent medium: 210 mm
+ x 297 mm
+ 'iso-a5-transparent': Specifies the ISO A5 transparent medium: 148 mm
+ x 210 mm
+ 'iso-a5-translucent': Specifies the ISO A5 translucent medium: 148 mm
+ x 210 mm
+ 'iso-a6-white': Specifies the ISO A6 white medium: 105 mm x 148 mm
+ 'iso-a7-white': Specifies the ISO A7 white medium: 74 mm x 105 mm
+ 'iso-a8-white': Specifies the ISO A8 white medium: 52 mm x 74 mm
+ 'iso-a9-white': Specifies the ISO A9 white medium: 37 mm x 52 mm
+ 'iso-a10-white': Specifies the ISO A10 white medium: 26 mm x 37 mm
+ 'iso-b0-white': Specifies the ISO B0 white medium: 1000 mm x 1414 mm
+ 'iso-b1-white': Specifies the ISO B1 white medium: 707 mm x 1000 mm
+ 'iso-b2-white': Specifies the ISO B2 white medium: 500 mm x 707 mm
+ 'iso-b3-white': Specifies the ISO B3 white medium: 353 mm x 500 mm
+ 'iso-b6-white': Specifies the ISO B6 white medium: 125 mm x 176 mm
+ 'iso-b7-white': Specifies the ISO B7 white medium: 88 mm x 125 mm
+ 'iso-b8-white': Specifies the ISO B8 white medium: 62 mm x 88 mm
+ 'iso-b9-white': Specifies the ISO B9 white medium: 44 mm x 62 mm
+ 'iso-b10-white': Specifies the ISO B10 white medium: 31 mm x 44 mm
+ 'jis-b0-white': Specifies the JIS B0 white medium: 1030 mm x 1456 mm
+ 'jis-b0-transparent': Specifies the JIS B0 transparent medium: 1030
+ mm x 1456 mm
+ 'jis-b0-translucent': Specifies the JIS B0 translucent medium: 1030
+ mm x 1456 mm
+ 'jis-b1-white': Specifies the JIS B1 white medium: 728 mm x 1030 mm
+ 'jis-b1-transparent': Specifies the JIS B1 transparent medium: 728 mm
+ x 1030 mm
+ 'jis-b1-translucent': Specifies the JIS B1 translucent medium: 728 mm
+ x 1030 mm
+ 'jis-b2-white': Specifies the JIS B2 white medium: 515 mm x 728 mm
+ 'jis-b2-transparent': Specifies the JIS B2 transparent medium: 515 mm
+ x 728 mm
+ 'jis-b2-translucent': Specifies the JIS B2 translucent medium: 515 mm
+ x 728 mm
+ 'jis-b3-white': Specifies the JIS B3 white medium: 364 mm x 515 mm
+ 'jis-b3-transparent': Specifies the JIS B3 transparent medium: 364 mm
+ x 515 mm
+ 'jis-b3-translucent': Specifies the JIS B3 translucent medium: 364 mm
+ x 515 mm
+
+
+
+Hastings, et al. Standards Track [Page 192]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 'jis-b4-transparent': Specifies the JIS B4 transparent medium: 257 mm
+ x 364 mm
+ 'jis-b4-translucent': Specifies the JIS B4 translucent medium: 257 mm
+ x 364 mm
+ 'jis-b5-transparent': Specifies the JIS B5 transparent medium: 182 mm
+ x 257 mm
+ 'jis-b5-translucent': Specifies the JIS B5 translucent medium: 182 mm
+ x 257 mm
+ 'jis-b6-white': Specifies the JIS B6 white medium: 128 mm x 182 mm
+ 'jis-b7-white': Specifies the JIS B7 white medium: 91 mm x 128 mm
+ 'jis-b8-white': Specifies the JIS B8 white medium: 64 mm x 91 mm
+ 'jis-b9-white': Specifies the JIS B9 white medium: 45 mm x 64 mm
+ 'jis-b10-white': Specifies the JIS B10 white medium: 32 mm x 45 mm
+
+ The following standard values are defined for American Standard (i.e.
+ ANSI) engineering media:
+
+ 'a-white': Specifies the engineering ANSI A size white medium: 8.5
+ inches x 11 inches
+ 'a-transparent': Specifies the engineering ANSI A size transparent
+ medium: 8.5 inches x 11 inches
+ 'a-translucent': Specifies the engineering ANSI A size translucent
+ medium: 8.5 inches x 11 inches
+ 'b-white': Specifies the engineering ANSI B size white medium: 11
+ inches x 17 inches
+ 'b-transparent': Specifies the engineering ANSI B size transparent
+ medium: 11 inches x 17 inches)
+ 'b-translucent': Specifies the engineering ANSI B size translucent
+ medium: 11 inches x 17 inches
+ 'c-white': Specifies the engineering ANSI C size white medium: 17
+ inches x 22 inches
+ 'c-transparent': Specifies the engineering ANSI C size transparent
+ medium: 17 inches x 22 inches
+ 'c-translucent': Specifies the engineering ANSI C size translucent
+ medium: 17 inches x 22 inches
+ 'd-white': Specifies the engineering ANSI D size white medium: 22
+ inches x 34 inches
+ 'd-transparent': Specifies the engineering ANSI D size transparent
+ medium: 22 inches x 34 inches
+ 'd-translucent': Specifies the engineering ANSI D size translucent
+ medium: 22 inches x 34 inches
+ 'e-white': Specifies the engineering ANSI E size white medium: 34
+ inches x 44 inches
+ 'e-transparent': Specifies the engineering ANSI E size transparent
+ medium: 34 inches x 44 inches
+ 'e-translucent': Specifies the engineering ANSI E size translucent
+ medium: 34 inches x 44 inches
+
+
+
+
+Hastings, et al. Standards Track [Page 193]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ The following standard values are defined for American Standard (i.e.
+ ANSI) engineering media for devices that provide the "synchro-cut"
+ feature (see section 14.1):
+
+ 'axsynchro-white': Specifies the roll paper having the width of the
+ longer edge (11 inches) of the engineering ANSI A size white medium
+ and cuts synchronizing with data.
+ 'axsynchro-transparent': Specifies the roll paper having the width of
+ the longer edge (11 inches) of the engineering ANSI A size
+ transparent medium and cuts synchronizing with data.
+ 'axsynchro-translucent': Specifies the roll paper having the width of
+ the longer edge (11 inches) of the engineering ANSI A size
+ translucent medium and cuts synchronizing with data.
+ 'bxsynchro-white': Specifies the roll paper having the width of the
+ longer edge (17 inches) of the engineering ANSI B size white medium
+ and cuts synchronizing with data.
+ 'bxsynchro-transparent': Specifies the roll paper having the width of
+ the longer edge (17 inches) of the engineering ANSI B size
+ transparent medium and cuts synchronizing with data.
+ 'bxsynchro-translucent': Specifies the roll paper having the width of
+ the longer edge (17 inches) of the engineering ANSI B size
+ translucent medium and cuts synchronizing with data.
+ 'cxsynchro-white': Specifies the roll paper having the width of the
+ longer edge (22 inches) of the engineering ANSI C size white medium
+ and cuts synchronizing with data.
+ 'cxsynchro-transparent': Specifies the roll paper having the width of
+ the longer edge (22 inches) of the engineering ANSI C size
+ transparent medium and cuts synchronizing with data.
+ 'cxsynchro-translucent': Specifies the roll paper having the width of
+ the longer edge (22 inches) of the engineering ANSI C size
+ translucent medium and cuts synchronizing with data.
+ 'dxsynchro-white': Specifies the roll paper having the width of the
+ longer edge (34 inches) of the engineering ANSI D size white medium
+ and cuts synchronizing with data.
+ 'dxsynchro-transparent': Specifies the roll paper having the width of
+ the longer edge (34 inches) of the engineering ANSI D size
+ transparent medium and cuts synchronizing with data.
+ 'dxsynchro-translucent': Specifies the roll paper having the width of
+ the longer edge (34 inches) of the engineering ANSI D size
+ translucent medium and cuts synchronizing with data.
+ 'exsynchro-white': Specifies the roll paper having the width of the
+ longer edge (44 inches) of the engineering ANSI E size white medium
+ and cuts synchronizing with data.
+ 'exsynchro-transparent': Specifies the roll paper having the width of
+ the longer edge (44 inches) of the engineering ANSI E size
+ transparent medium and cuts synchronizing with data.
+
+
+
+
+
+Hastings, et al. Standards Track [Page 194]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 'exsynchro-translucent': Specifies the roll paper having the width of
+ the longer edge (44 inches) of the engineering ANSI E size
+ translucent medium and cuts synchronizing with data.
+
+ The following standard values are defined for American Architectural
+ engineering media:
+
+ 'arch-a-white': Specifies the Architectural A size white medium: 9
+ inches x 12 inches
+ 'arch-a-transparent': Specifies the Architectural A size transparent
+ medium: 9 inches x 12 inches
+ 'arch-a-translucent': Specifies the Architectural A size translucent
+ medium: 9 inches x 12 inches
+ 'arch-b-white': Specifies the Architectural B size white medium: 12
+ inches x 18 inches
+ 'arch-b-transparent': Specifies the Architectural B size transparent
+ medium: 12 inches x 18 inches
+ 'arch-b-translucent': Specifies the Architectural B size translucent
+ medium: 12 inches x 18 inches
+ 'arch-c-white': Specifies the Architectural C size white medium: 18
+ inches x 24 inches
+ 'arch-c-transparent': Specifies the Architectural C size transparent
+ medium: 18 inches x 24 inches
+ 'arch-c-translucent': Specifies the Architectural C size translucent
+ medium: 18 inches x 24 inches
+ 'arch-d-white': Specifies the Architectural D size white medium: 24
+ inches x 36 inches
+ 'arch-d-transparent': Specifies the Architectural D size transparent
+ medium: 24 inches x 36 inches
+ 'arch-d-translucent': Specifies the Architectural D size translucent
+ medium: 24 inches x 36 inches
+ 'arch-e-white': Specifies the Architectural E size white medium: 36
+ inches x 48 inches
+ 'arch-e-transparent': Specifies the Architectural E size transparent
+ medium: 36 inches x 48 inches
+ 'arch-e-translucent': Specifies the Architectural E size translucent
+ medium: 36 inches x 48 inches
+
+ The following standard values are defined for American Architectural
+ engineering media for devices that provide the "synchro-cut" feature
+ (see section 14.1):
+
+ 'arch-axsynchro-white': Specifies the roll paper having the width of
+ the longer edge (12 inches) of the Architectural A size white
+ medium and cuts synchronizing with data.
+ 'arch-axsynchro-transparent': Specifies the roll paper having the
+ width of the longer edge (12 inches) of the Architectural A size
+ transparent medium and cuts synchronizing with data.
+
+
+
+Hastings, et al. Standards Track [Page 195]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 'arch-axsynchro-translucent': Specifies the roll paper having the
+ width of the longer edge (12 inches) of the Architectural A size
+ translucent medium and cuts synchronizing with data.
+ 'arch-bxsynchro-white': Specifies the roll paper having the width of
+ the longer edge (18 inches) of the Architectural B size white
+ medium and cuts synchronizing with data.
+ 'arch-bxsynchro-transparent': Specifies the roll paper having the
+ width of the longer edge (18 inches) of the Architectural B size
+ transparent medium and cuts synchronizing with data.
+ 'arch-bxsynchro-translucent': Specifies the roll paper having the
+ width of the longer edge (18 inches) of the Architectural B size
+ translucent medium and cuts synchronizing with data.
+ 'arch-cxsynchro-white': Specifies the roll paper having the width of
+ the longer edge (24 inches) of the Architectural C size white
+ medium and cuts synchronizing with data.
+ 'arch-cxsynchro-transparent': Specifies the roll paper having the
+ width of the longer edge (24 inches) of the Architectural C size
+ transparent medium and cuts synchronizing with data.
+ 'arch-cxsynchro-translucent': Specifies the roll paper having the
+ width of the longer edge (24 inches) of the Architectural C size
+ translucent medium and cuts synchronizing with data.
+ 'arch-dxsynchro-white': Specifies the roll paper having the width of
+ the longer edge (36 inches) of the Architectural D size white
+ medium and cuts synchronizing with data.
+ 'arch-dxsynchro-transparent': Specifies the roll paper having the
+ width of the longer edge (36 inches) of the Architectural D size
+ transparent medium and cuts synchronizing with data.
+ 'arch-dxsynchro-translucent': Specifies the roll paper having the
+ width of the longer edge (36 inches) of the Architectural D size
+ translucent medium and cuts synchronizing with data.
+ 'arch-exsynchro-white': Specifies the roll paper having the width of
+ the longer edge (48 inches) of the Architectural E size white
+ medium and cuts synchronizing with data.
+ 'arch-exsynchro-transparent': Specifies the roll paper having the
+ width of the longer edge (48 inches) of the Architectural E size
+ transparent medium and cuts synchronizing with data.
+ 'arch-exsynchro-translucent': Specifies the roll paper having the
+ width of the longer edge (48 inches) of the Architectural E size
+ translucent medium and cuts synchronizing with data.
+
+ The following standard values are defined for Japanese and European
+ Standard (i.e. ISO) engineering media, which are of a long fixed size
+ [ASME-Y14.1M]:
+
+ 'iso-a1x3-white': Specifies the ISO A1X3 white medium having the
+ width of the longer edge (841 mm) of the ISO A1 medium
+
+
+
+
+
+Hastings, et al. Standards Track [Page 196]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 'iso-a1x3-transparent': Specifies the ISO A1X3 transparent medium
+ having the width of the longer edge (841 mm) of the ISO A1
+ medium
+ 'iso-a1x3-translucent': Specifies the ISO A1X3 translucent medium
+ having the width of the longer edge (841 mm) of the ISO A1
+ medium
+ 'iso-a1x4-white': Specifies the ISO A1X4 white medium having the
+ width of the longer edge (841 mm) of the ISO A1 medium
+ 'iso-a1x4-transparent': Specifies the ISO A1X4 transparent medium
+ having the width of the longer edge (841 mm) of the ISO A1
+ medium
+ 'iso-a1x4- translucent': Specifies the ISO A1X4 translucent medium
+ having the width of the longer edge (841 mm) of the ISO A1
+ medium
+ 'iso-a2x3-white': Specifies the ISO A2X3 white medium having the
+ width of the longer edge (594 mm) of the ISO A2 medium
+ 'iso-a2x3-transparent': Specifies the ISO A2X3 transparent medium
+ having the width of the longer edge (594 mm) of the ISO A2
+ medium
+ 'iso-a2x3-translucent': Specifies the ISO A2X3 translucent medium
+ having the width of the longer edge (594 mm) of the ISO A2
+ medium
+ 'iso-a2x4-white': Specifies the ISO A2X4 white medium having the
+ width of the longer edge (594 mm) of the ISO A2 medium
+ 'iso-a2x4-transparent': Specifies the ISO A2X4 transparent medium
+ having the width of the longer edge (594 mm) of the ISO A2
+ medium
+ 'iso-a2x4-translucent': Specifies the ISO A2X4 translucent medium
+ having the width of the longer edge (594 mm) of the ISO A2
+ medium
+ 'iso-a2x5-white': Specifies the ISO A2X5 white medium having the
+ width of the longer edge (594 mm) of the ISO A2 medium
+ 'iso-a2x5-transparent': Specifies the ISO A2X5 transparent medium
+ having the width of the longer edge (594 mm) of the ISO A2
+ medium
+ 'iso-a2x5-translucent': Specifies the ISO A2X5 translucent medium
+ having the width of the longer edge (594 mm) of the ISO A2
+ medium
+ 'iso-a3x3-white': Specifies the ISO A3X3 white medium having the
+ width of the longer edge (420 mm) of the ISO A3 medium
+ 'iso-a3x3-transparent': Specifies the ISO A3X3 transparent medium
+ having the width of the longer edge (420 mm) of the ISO A3
+ medium
+ 'iso-a3x3-translucent': Specifies the ISO A3X3 translucent medium
+ having the width of the longer edge (420 mm) of the ISO A3
+ medium
+ 'iso-a3x4-white': Specifies the ISO A3X4 white medium having the
+ width of the longer edge (420 mm) of the ISO A3 medium
+
+
+
+Hastings, et al. Standards Track [Page 197]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 'iso-a3x4-transparent': Specifies the ISO A3X4 transparent medium
+ having the width of the longer edge (420 mm) of the ISO A3
+ medium
+ 'iso-a3x4-translucent': Specifies the ISO A3X4 translucent medium
+ having the width of the longer edge (420 mm) of the ISO A3
+ medium
+ 'iso-a3x5-white': Specifies the ISO A3X5 white medium having the
+ width of the longer edge (420 mm) of the ISO A3 medium
+ 'iso-a3x5-transparent': Specifies the ISO A3X5 transparent medium
+ having the width of the longer edge (420 mm) of the ISO A3
+ medium
+ 'iso-a3x5-translucent': Specifies the ISO A3X5 translucent medium
+ having the width of the longer edge (420 mm) of the ISO A3
+ medium
+ 'iso-a3x6-white': Specifies the ISO A3X6 white medium having the
+ width of the longer edge (420 mm) of the ISO A3 medium
+ 'iso-a3x6-transparent': Specifies the ISO A3X6 transparent medium
+ having the width of the longer edge (420 mm) of the ISO A3
+ medium
+ 'iso-a3x6-translucent': Specifies the ISO A3X6 translucent medium
+ having the width of the longer edge (420 mm) of the ISO A3
+ medium
+ 'iso-a3x7-white': Specifies the ISO A3X7 white medium having the
+ width of the longer edge (420 mm) of the ISO A3 medium
+ 'iso-a3x7-transparent': Specifies the ISO A3X7 transparent medium
+ having the width of the longer edge (420 mm) of the ISO A3
+ medium
+ 'iso-a3x7-translucent'': Specifies the ISO A3X7 translucent' medium
+ having the width of the longer edge (420 mm) of the ISO A3
+ medium
+ 'iso-a4x3-white': Specifies the ISO A4X3 white medium having the
+ width of the longer edge (297 mm) of the ISO A4 medium
+ 'iso-a4x3-transparent': Specifies the ISO A4X3 transparent medium
+ having the width of the longer edge (297 mm) of the ISO A4
+ medium
+ 'iso-a4x3-translucent'': Specifies the ISO A4X3 translucent' medium
+ having the width of the longer edge (297 mm) of the ISO A4
+ medium
+ 'iso-a4x4-white': Specifies the ISO A4X4 white medium having the
+ width of the longer edge (297 mm) of the ISO A4 medium
+ 'iso-a4x4-transparent': Specifies the ISO A4X4 transparent medium
+ having the width of the longer edge (297 mm) of the ISO A4
+ medium
+ 'iso-a4x4-translucent': Specifies the ISO A4X4 translucent medium
+ having the width of the longer edge (297 mm) of the ISO A4
+ medium
+ 'iso-a4x5-white': Specifies the ISO A4X5 white medium having the
+ width of the longer edge (297 mm) of the ISO A4 medium
+
+
+
+Hastings, et al. Standards Track [Page 198]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 'iso-a4x5-transparent': Specifies the ISO A4X5 transparent medium
+ having the width of the longer edge (297 mm) of the ISO A4
+ medium
+ 'iso-a4x5-translucent': Specifies the ISO A4X5 translucent medium
+ having the width of the longer edge (297 mm) of the ISO A4
+ medium
+ 'iso-a4x6-white': Specifies the ISO A4X6 white medium having the
+ width of the longer edge (297 mm) of the ISO A4 medium
+ 'iso-a4x6-transparent': Specifies the ISO A4X6 transparent medium
+ having the width of the longer edge (297 mm) of the ISO A4
+ medium
+ 'iso-a4x6-translucent': Specifies the ISO A4X6 translucent medium
+ having the width of the longer edge (297 mm) of the ISO A4
+ medium
+ 'iso-a4x7-white': Specifies the ISO A4X7 white medium having the
+ width of the longer edge (297 mm) of the ISO A4 medium
+ 'iso-a4x7-transparent': Specifies the ISO A4X7 transparent medium
+ having the width of the longer edge (297 mm) of the ISO A4
+ medium
+ 'iso-a4x7-translucent': Specifies the ISO A4X7 translucent medium
+ having the width of the longer edge (297 mm) of the ISO A4
+ medium
+ 'iso-a4x8-white': Specifies the ISO A4X8 white medium having the
+ width of the longer edge (297 mm) of the ISO A4 medium
+ 'iso-a4x8-transparent': Specifies the ISO A4X8 transparent medium
+ having the width of the longer edge (297 mm) of the ISO A4
+ medium
+ 'iso-a4x8-translucent': Specifies the ISO A4X8 translucent medium
+ having the width of the longer edge (297 mm) of the ISO A4
+ medium
+ 'iso-a4x9-white': Specifies the ISO A4X9 white medium having the
+ width of the longer edge (297 mm) of the ISO A4 medium
+ 'iso-a4x9-transparent': Specifies the ISO A4X9 transparent medium
+ having the width of the longer edge (297 mm) of the ISO A4
+ medium
+ 'iso-a4x9-translucent': Specifies the ISO A4X9 translucent medium
+ having the width of the longer edge (297 mm) of the ISO A4
+ medium
+
+ The following standard values are defined for Japanese and European
+ Standard (i.e. ISO) engineering media, which are either a long fixed
+ size [ASME-Y14.1M] or roll feed, for devices that provide the
+ "synchro-cut" feature (see section 14.1):
+
+ 'iso-a0xsynchro-white': Specifies the paper having the width of the
+ longer edge (1189 mm) of the ISO A0 white medium and cuts
+ synchronizing with data.
+
+
+
+
+Hastings, et al. Standards Track [Page 199]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 'iso-a0xsynchro-transparent': Specifies the paper having the width of
+ the longer edge (1189 mm) of the ISO A0 transparent medium and
+ cuts synchronizing with data.
+ 'iso-a0xsynchro-translucent': Specifies the paper having the width of
+ the longer edge (1189 mm) of the ISO A0 translucent medium and
+ cuts synchronizing with data.
+ 'iso-a1xsynchro-white': Specifies the paper having the width of the
+ longer edge (841 mm) of the ISO A1 white medium and cuts
+ synchronizing with data.
+ 'iso-a1xsynchro-transparent': Specifies the paper having the width of
+ the longer edge (841 mm) of the ISO A1 transparent medium and
+ cuts synchronizing with data.
+ 'iso-a1xsynchro-translucent': Specifies the paper having the width of
+ the longer edge (841 mm) of the ISO A1 translucent medium and
+ cuts synchronizing with data.
+ 'iso-a2xsynchro-white': Specifies the paper having the width of the
+ longer edge (594 mm) of the ISO A2 white medium and cuts
+ synchronizing with data.
+ 'iso-a2xsynchro-transparent': Specifies the paper having the width of
+ the longer edge (594 mm) of the ISO A2 transparent medium and
+ cuts synchronizing with data.
+ 'iso-a2xsynchro-translucent': Specifies the paper having the width of
+ the longer edge (594 mm) of the ISO A2 translucent medium and
+ cuts synchronizing with data.
+ 'iso-a3xsynchro-white': Specifies the paper having the width of the
+ longer edge (420 mm) of the ISO A3 white medium and cuts
+ synchronizing with data.
+ 'iso-a3xsynchro-transparent': Specifies the paper having the width of
+ the longer edge (420 mm) of the ISO A3 transparent medium and
+ cuts synchronizing with data.
+ 'iso-a3xsynchro-translucent': Specifies the paper having the width of
+ the longer edge (420 mm) of the ISO A3 translucent medium and
+ cuts synchronizing with data.
+ 'iso-a4xsynchro-white': Specifies the paper having the width of the
+ longer edge (297 mm) of the ISO A4 white medium and cuts
+ synchronizing with data.
+ 'iso-a4xsynchro-transparent': Specifies the paper having the width of
+ the longer edge (297 mm) of the ISO A4 transparent medium and
+ cuts synchronizing with data.
+ 'iso-a4xsynchro-translucent': Specifies the paper having the width of
+ the longer edge (297 mm) of the ISO A4 transparent medium and
+ cuts synchronizing with data.
+
+ The following standard values are defined for American Standard (i.e.
+ ANSI) engineering media, American Architectural engineering media,
+ and Japanese and European Standard (i.e. ISO) engineering media,
+
+
+
+
+
+Hastings, et al. Standards Track [Page 200]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ which are either a long fixed size [ASME-Y14.1M] or roll feed, for
+ devices that provide the "synchro-cut" feature and/or the "auto-
+ select" feature (see section 14.1):
+
+ 'auto-white': Specifies that the printer selects the white medium
+ with the appropriate fixed size (e.g. a1, a2, etc.) or data-
+ synchro size, and the selection is implementation-defined.
+ 'auto-transparent': Specifies that the printer selects the
+ transparent medium with the appropriate fixed size (e.g. a1, a2,
+ etc.) or data-synchro size, and the selection is implementation-
+ defined.
+ 'auto-translucent': Specifies that the printer selects the
+ translucent medium with the appropriate fixed size (e.g. a1, a2,
+ etc.) or data-synchro size, and the selection is implementation-
+ defined.
+ 'auto-fixed-size-white': Specifies that the printer selects the white
+ medium with the appropriate fixed size (e.g. a1, a2, etc.) or
+ the appropriate long fixed size listed above.
+ 'auto-fixed-size-transparent': Specifies that the printer selects the
+ transparent medium with the appropriate fixed size (e.g. a1, a2,
+ etc.) or the appropriate long fixed size listed above.
+ 'auto-fixed-size-translucent': Specifies that the printer selects the
+ translucent medium with the appropriate fixed size (e.g. a1, a2,
+ etc.) or the appropriate long fixed size listed above.
+ 'auto-synchro-white': Specifies that the printer selects the white
+ paper with the appropriate width and cuts it synchronizing with
+ data.
+ 'auto-synchro-transparent': Specifies that the printer selects the
+ transparent paper with the appropriate width and cuts it
+ synchronizing with data.
+ 'auto-synchro-translucent': Specifies that the printer selects the
+ translucent paper with the appropriate width and cuts it
+ synchronizing with data.
+
+ The following standard values are defined for input-trays (from ISO
+ DPA and the Printer MIB):
+
+ 'top': The top input tray in the printer.
+ 'middle': The middle input tray in the printer.
+ 'bottom': The bottom input tray in the printer.
+ 'envelope': The envelope input tray in the printer.
+ 'manual': The manual feed input tray in the printer.
+ 'large-capacity': The large capacity input tray in the printer.
+ 'main': The main input tray
+ 'side': The side input tray
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 201]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ The following standard values are defined for media sizes (from ISO
+ DPA):
+
+ 'iso-a0': Specifies the ISO A0 size: 841 mm by 1189 mm as defined in
+ ISO 216
+ 'iso-a1': Specifies the ISO A1 size: 594 mm by 841 mm as defined in
+ ISO 216
+ 'iso-a2': Specifies the ISO A2 size: 420 mm by 594 mm as defined in
+ ISO 216
+ 'iso-a3': Specifies the ISO A3 size: 297 mm by 420 mm as defined in
+ ISO 216
+ 'iso-a4': Specifies the ISO A4 size: 210 mm by 297 mm as defined in
+ ISO 216
+ 'iso-a5': Specifies the ISO A5 size: 148 mm by 210 mm as defined in
+ ISO 216
+ 'iso-a6': Specifies the ISO A6 size: 105 mm by 148 mm as defined in
+ ISO 216
+ 'iso-a7': Specifies the ISO A7 size: 74 mm by 105 mm as defined in
+ ISO 216
+ 'iso-a8': Specifies the ISO A8 size: 52 mm by 74 mm as defined in ISO
+ 216
+ 'iso-a9': Specifies the ISO A9 size: 37 mm by 52 mm as defined in ISO
+ 216
+ 'iso-a10': Specifies the ISO A10 size: 26 mm by 37 mm as defined in
+ ISO 216
+ 'iso-b0': Specifies the ISO B0 size: 1000 mm by 1414 mm as defined in
+ ISO 216
+ 'iso-b1': Specifies the ISO B1 size: 707 mm by 1000 mm as defined in
+ ISO 216
+ 'iso-b2': Specifies the ISO B2 size: 500 mm by 707 mm as defined in
+ ISO 216
+ 'iso-b3': Specifies the ISO B3 size: 353 mm by 500 mm as defined in
+ ISO 216
+ 'iso-b4': Specifies the ISO B4 size: 250 mm by 353 mm as defined in
+ ISO 216
+ 'iso-b5': Specifies the ISO B5 size: 176 mm by 250 mm as defined in
+ ISO 216
+ 'iso-b6': Specifies the ISO B6 size: 125 mm by 176 mm as defined in
+ ISO 216
+ 'iso-b7': Specifies the ISO B7 size: 88 mm by 125 mm as defined in
+ ISO 216
+ 'iso-b8': Specifies the ISO B8 size: 62 mm by 88 mm as defined in ISO
+ 216
+ 'iso-b9': Specifies the ISO B9 size: 44 mm by 62 mm as defined in ISO
+ 216
+ 'iso-b10': Specifies the ISO B10 size: 31 mm by 44 mm as defined in
+ ISO 216
+
+
+
+
+Hastings, et al. Standards Track [Page 202]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 'na-letter': Specifies the North American letter size: 8.5 inches by
+ 11 inches
+ 'na-legal': Specifies the North American legal size: 8.5 inches by 14
+ inches
+ 'na-8x10': Specifies the North American 8 inches by 10 inches
+ 'na-5x7': Specifies the North American 5 inches by 7 inches
+ 'executive': Specifies the executive size (7.25 X 10.5 in)
+ 'folio': Specifies the folio size (8.5 X 13 in)
+ 'invoice': Specifies the invoice size (5.5 X 8.5 in)
+ 'ledger': Specifies the ledger size (11 X 17 in)
+ 'quarto': Specifies the quarto size (8.5 X 10.83 in)
+ 'iso-c3': Specifies the ISO C3 size: 324 mm by 458 mm as defined in
+ ISO 269
+ 'iso-c4': Specifies the ISO C4 size: 229 mm by 324 mm as defined in
+ ISO 269
+ 'iso-c5': Specifies the ISO C5 size: 162 mm by 229 mm as defined in
+ ISO 269
+ 'iso-c6': Specifies the ISO C6 size: 114 mm by 162 mm as defined in
+ ISO 269
+ 'iso-designated-long': Specifies the ISO Designated Long size: 110 mm
+ by 220 mm as defined in ISO 269
+ 'na-10x13-envelope': Specifies the North American 10x13 size: 10
+ inches by 13 inches
+ 'na-9x12-envelope': Specifies the North American 9x12 size: 9 inches
+ by 12 inches
+ 'na-number-10-envelope': Specifies the North American number 10
+ business envelope size: 4.125 inches by 9.5 inches
+ 'na-7x9-envelope': Specifies the North American 7x9 inch envelope
+ size
+ 'na-9x11-envelope': Specifies the North American 9x11 inch envelope
+ size
+ 'na-10x14-envelope': Specifies the North American 10x14 inch envelope
+ size
+ 'na-number-9-envelope': Specifies the North American number 9
+ business envelope size
+ 'na-6x9-envelope': Specifies the North American 6x9 envelope size
+ 'na-10x15-envelope': Specifies the North American 10x15 envelope size
+ 'monarch-envelope': Specifies the Monarch envelope size (3.87 x 7.5
+ in)
+ 'jis-b0': Specifies the JIS B0 size: 1030mm x 1456mm
+ 'jis-b1': Specifies the JIS B1 size: 728mm x 1030mm
+ 'jis-b2': Specifies the JIS B2 size: 515mm x 728mm
+ 'jis-b3': Specifies the JIS B3 size: 364mm x 515mm
+ 'jis-b4': Specifies the JIS B4 size: 257mm x 364mm
+ 'jis-b5': Specifies the JIS B5 size: 182mm x 257mm
+ 'jis-b6': Specifies the JIS B6 size: 128mm x 182mm
+ 'jis-b7': Specifies the JIS B7 size: 91mm x 128mm
+ 'jis-b8': Specifies the JIS B8 size: 64mm x 91mm
+
+
+
+Hastings, et al. Standards Track [Page 203]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 'jis-b9': Specifies the JIS B9 size: 45mm x 64mm
+ 'jis-b10': Specifies the JIS B10 size: 32mm x 45mm
+
+ The following standard values are defined for American Standard (i.e.
+ ANSI) engineering media sizes:
+
+ 'a': Specifies the engineering ANSI A size medium: 8.5 inches x 11
+ inches
+ 'b': Specifies the engineering ANSI B size medium: 11 inches x 17
+ inches
+ 'c': Specifies the engineering ANSI C size medium: 17 inches x 22
+ inches
+ 'd': Specifies the engineering ANSI D size medium: 22 inches x 34
+ inches
+ 'e': Specifies the engineering ANSI E size medium: 34 inches x 44
+ inches
+
+ The following standard values are defined for American Architectural
+ engineering media sizes:
+
+ 'arch-a': Specifies the Architectural A size medium: 9 inches x 12
+ inches
+ 'arch-b': Specifies the Architectural B size medium: 12 inches x 18
+ inches
+ 'arch-c': Specifies the Architectural C size medium: 18 inches x 24
+ inches
+ 'arch-d': Specifies the Architectural D size medium: 24 inches x 36
+ inches
+ 'arch-e': Specifies the Architectural E size medium: 36 inches x 48
+ inches
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 204]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+14.1. Examples
+
+ Below are examples to supplement the engineering media value
+ definitions.
+
+ Example 1: "Synchro-Cut", a device cutting the roll paper in
+ synchronization with the data
+
+ data height: A1 height
+ data width (shaded): A1 width < data width < (A1 width) x 2
+ specified value: 'iso-a1xsynchro-white'
+
+ | |
+ |<--- data width --->|
+ | |
+ | | | |
+ |<- A1 width ->|<- A1 width ->|
+ | | | |
+ cross ^ | | | |
+ feed | +--------------------------------------------/
+ direction | |//////////////|/////| | ^ /
+ | |//////////////|/////| | | /
+ | |//////////////|/////| | | /
+ | |//////////////|/////| | | \
+<-----------+- |//////////////|/////| | A1 \ roll
+feed | |//////////////|/////| | height \ paper
+direction |//////////////|/////| | | \
+ |//////////////|/////| | | /
+ |//////////////|/////| | v /
+ +------------------------------------------/
+ |
+ |
+ |<------ CUT HERE (to synchronize
+ | with data width)
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 205]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Example 2: "Auto-Cut", a device cutting the roll paper at multiples
+ of fixed-size media width
+
+ data height: A1 height
+ data width (shaded): A1 width < data width < (A1 width) x 2
+ specified value: 'auto-fixed-size-white'
+
+ | |
+ |<--- data width --->|
+ | |
+ | | | |
+ |<- A1 width ->|<- A1 width ->|
+ | | | |
+ cross ^ | | | |
+ feed | +--------------------------------------------/
+ direction | |//////////////|/////| | ^ /
+ | |//////////////|/////| | | /
+ | |//////////////|/////| | | /
+ | |//////////////|/////| | | \
+<-----------+- |//////////////|/////| | A1 \ roll
+feed | |//////////////|/////| | height \ paper
+direction |//////////////|/////| | | \
+ |//////////////|/////| | | /
+ |//////////////|/////| | v /
+ +------------------------------------------/
+ |
+ |
+ |<--- CUT HERE
+ | (to synchronize
+ | with data width)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 206]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Example 3: the 'iso-a4x4-white' fixed size paper
+
+ paper height: A4 height
+ paper width: (A4 width) x 4
+ specified value: 'iso-a4x4-white'
+
+ | | | | |
+ |<- A4 width ->|<- A4 width ->|<- A4 width ->|<- A4 width ->|
+ | | | | |
+ | | | | |
+ +-----------------------------------------------------------+
+ | ^ | | | |
+ | | | | | |
+ | | | | | |
+ | A4 | | | |
+ | height | | | |
+ | | | | | |
+ | | | | | |
+ | | | | | |
+ | v | | | |
+ +-----------------------------------------------------------+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 207]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Example 4: "Synchro-Cut", a device cutting the fixed size paper in
+ synchronization with the data
+
+ data height: A4 height
+ data width (shaded): (A4 width) x 2 < data width < (A4 width) x 3
+ specified value: 'iso-a4xsynchro-white'
+
+ | |
+ |<---------- data width ----------->|
+ | |
+ | | | | |
+ |<- A4 width ->|<- A4 width ->|<- A4 width ->|
+ | | | | |
+ cross ^ | | | | |
+ feed | +--------------------------------------------+
+ direction | |//////////////|//////////////|/////| ^ |
+ | |//////////////|//////////////|/////| | |
+ | |//////////////|//////////////|/////| | |
+ | |//////////////|//////////////|/////| | |
+ <-----------+- |//////////////|//////////////|/////| A4 |
+ feed | |//////////////|//////////////|/////| height |
+ direction |//////////////|//////////////|/////| | |
+ |//////////////|//////////////|/////| | |
+ |//////////////|//////////////|/////| v |
+ +--------------------------------------------+
+ |
+ CUT HERE ---->|
+ (to synchronize |
+ with data width) |
+
+15. APPENDIX D: Processing IPP Attributes
+
+ When submitting a print job to a Printer object, the IPP model allows
+ a client to supply operation and Job Template attributes along with
+ the document data. These Job Template attributes in the create
+ request affect the rendering, production and finishing of the
+ documents in the job. Similar types of instructions may also be
+ contained in the document to be printed, that is, embedded within the
+ print data itself. In addition, the Printer has a set of attributes
+ that describe what rendering and finishing options which are
+ supported by that Printer. This model, which allows for flexibility
+ and power, also introduces the potential that at job submission time,
+ these client-supplied attributes may conflict with either:
+
+ - what the implementation is capable of realizing (i.e., what the
+ Printer supports), as well as
+ - the instructions embedded within the print data itself.
+
+
+
+
+Hastings, et al. Standards Track [Page 208]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ The following sections describe how these two types of conflicts are
+ handled in the IPP model.
+
+15.1 Fidelity
+
+ If there is a conflict between what the client requests and what a
+ Printer object supports, the client may request one of two possible
+ conflict handling mechanisms:
+
+ 1) either reject the job since the job can not be processed
+ exactly as specified, or
+ 2) allow the Printer to make any changes necessary to proceed with
+ processing the Job the best it can.
+
+ In the first case the client is indicating to the Printer object:
+ "Print the job exactly as specified with no exceptions, and if that
+ can't be done, don't even bother printing the job at all." In the
+ second case, the client is indicating to the Printer object: "It is
+ more important to make sure the job is printed rather than be
+ processed exactly as specified; just make sure the job is printed
+ even if some client-supplied attributes need to be changed or
+ ignored."
+
+ The IPP model accounts for this situation by introducing an "ipp-
+ attribute-fidelity" attribute.
+
+ In a create request, "ipp-attribute-fidelity" is a boolean operation
+ attribute that is OPTIONALLY supplied by the client. The value
+ 'true' indicates that total fidelity to client supplied Job Template
+ attributes and values is required. The client is requesting that the
+ Job be printed exactly as specified, and if that is not possible then
+ the job MUST be rejected rather than processed incorrectly. The
+ value 'false' indicates that a reasonable attempt to print the Job is
+ acceptable. If a Printer does not support some of the client
+ supplied Job Template attributes or values, the Printer MUST ignore
+ them or substitute any supported value for unsupported values,
+ respectively. The Printer may choose to substitute the default value
+ associated with that attribute, or use some other supported value
+ that is similar to the unsupported requested value. For example, if
+ a client supplies a "media" value of 'na-letter', the Printer may
+ choose to substitute 'iso-a4' rather than a default value of
+ 'envelope'. If the client does not supply the "ipp-attribute-
+ fidelity" attribute, the Printer assumes a value of 'false'.
+
+ Each Printer implementation MUST support both types of "fidelity"
+ printing (that is whether the client supplies a value of 'true' or
+ 'false'):
+
+
+
+
+Hastings, et al. Standards Track [Page 209]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ - If the client supplies 'false' or does not supply the attribute,
+ the Printer object MUST always accept the request by ignoring
+ unsupported Job Template attributes and by substituting
+ unsupported values of supported Job Template attributes with
+ supported values.
+ - If the client supplies 'true', the Printer object MUST reject
+ the request if the client supplies unsupported Job Template
+ attributes.
+
+ Since a client can always query a Printer to find out exactly what is
+ and is not supported, "ipp-attribute-fidelity" set to 'false' is
+ useful when:
+
+ 1) The End-User uses a command line interface to request
+ attributes that might not be supported.
+ 2) In a GUI context, if the End User expects the job might be
+ moved to another printer and prefers a sub-optimal result to
+ nothing at all.
+ 3) The End User just wants something reasonable in lieu of nothing
+ at all.
+
+15.2 Page Description Language (PDL) Override
+
+ If there is a conflict between the value of an IPP Job Template
+ attribute and a corresponding instruction in the document data, the
+ value of the IPP attribute SHOULD take precedence over the document
+ instruction. Consider the case where a previously formatted file of
+ document data is sent to an IPP Printer. In this case, if the client
+ supplies any attributes at job submission time, the client desires
+ that those attributes override the embedded instructions. Consider
+ the case were a previously formatted document has embedded in it
+ commands to load 'iso-a4' media. However, the document is passed to
+ an end user that only has access to a printer with 'na-letter' media
+ loaded. That end user most likely wants to submit that document to
+ an IPP Printer with the "media" Job Template attribute set to 'na-
+ letter'. The job submission attribute should take precedence over
+ the embedded PDL instruction. However, until companies that supply
+ document data interpreters allow a way for external IPP attributes to
+ take precedence over embedded job production instructions, a Printer
+ might not be able to support the semantics that IPP attributes
+ override the embedded instructions.
+
+ The IPP model accounts for this situation by introducing a "pdl-
+ override-supported" attribute that describes the Printer objects
+ capabilities to override instructions embedded in the PDL data
+ stream. The value of the "pdl-override-supported" attribute is
+ configured by means outside the scope of this IPP/1.1 document.
+
+
+
+
+Hastings, et al. Standards Track [Page 210]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ This REQUIRED Printer attribute takes on the following values:
+
+ - 'attempted': This value indicates that the Printer object
+ attempts to make the IPP attribute values take precedence over
+ embedded instructions in the document data, however there is no
+ guarantee.
+ - 'not-attempted': This value indicates that the Printer object
+ makes no attempt to make the IPP attribute values take
+ precedence over embedded instructions in the document data.
+
+ At job processing time, an implementation that supports the value of
+ 'attempted' might do one of several different actions:
+
+ 1) Generate an output device specific command sequence to realize
+ the feature represented by the IPP attribute value.
+ 2) Parse the document data itself and replace the conflicting
+ embedded instruction with a new embedded instruction that
+ matches the intent of the IPP attribute value.
+ 3) Indicate to the Printer that external supplied attributes take
+ precedence over embedded instructions and then pass the
+ external IPP attribute values to the document data interpreter.
+ 4) Anything else that allows for the semantics that IPP attributes
+ override embedded document data instructions.
+
+ Since 'attempted' does not offer any type of guarantee, even though a
+ given Printer object might not do a very "good" job of attempting to
+ ensure that IPP attributes take a higher precedence over instructions
+ embedded in the document data, it would still be a conforming
+ implementation.
+
+ At job processing time, an implementation that supports the value of
+ 'not-attempted' might do one of the following actions:
+
+ 1) Simply pre-pend the document data with the PDL instruction that
+ corresponds to the client-supplied PDL attribute, such that if
+ the document data also has the same PDL instruction, it will
+ override what the Printer object pre-pended. In other words,
+ this implementation is using the same implementation semantics
+ for the client-supplied IPP attributes as for the Printer
+ object defaults.
+
+ 2) Parse the document data and replace the conflicting embedded
+ instruction with a new embedded instruction that approximates,
+ but does not match, the semantic intent of the IPP attribute
+ value.
+
+ Note: The "ipp-attribute-fidelity" attribute applies to the
+ Printer's ability to either accept or reject other unsupported Job
+
+
+
+Hastings, et al. Standards Track [Page 211]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Template attributes. In other words, if "ipp-attribute-fidelity" is
+ set to 'true', a Job is accepted if and only if the client supplied
+ Job Template attributes and values are supported by the Printer.
+ Whether these attributes actually affect the processing of the Job
+ when the document data contains embedded instructions depends on the
+ ability of the Printer to override the instructions embedded in the
+ document data with the semantics of the IPP attributes. If the
+ document data attributes can be overridden ("pdl-override-supported"
+ set to 'attempted'), the Printer makes an attempt to use the IPP
+ attributes when processing the Job. If the document data attributes
+ can not be overridden ("pdl-override-supported" set to 'not-
+ attempted'), the Printer makes no attempt to override the embedded
+ document data instructions with the IPP attributes when processing
+ the Job, and hence, the IPP attributes may fail to affect the Job
+ processing and output when the corresponding instruction is embedded
+ in the document data.
+
+15.3 Using Job Template Attributes During Document Processing.
+
+ The Printer object uses some of the Job object's Job Template
+ attributes during the processing of the document data associated with
+ that job. These include, but are not limited to, "orientation-
+ requested", "number-up", "sides", "media", and "copies". The
+ processing of each document in a Job Object MUST follow the steps
+ below. These steps are intended only to identify when and how
+ attributes are to be used in processing document data and any
+ alternative steps that accomplishes the same effect can be used to
+ implement this specification document.
+
+ 1. Using the client supplied "document-format" attribute or some
+ form of document format detection algorithm (if the value of
+ "document-format" is not specific enough), determine whether or
+ not the document data has already been formatted for printing.
+ If the document data has been formatted, then go to step 2.
+ Otherwise, the document data MUST be formatted. The formatting
+ detection algorithm is implementation defined and is not
+ specified by this document. The formatting of the document
+ data uses the "orientation-requested" attribute to determine
+ how the formatted print data should be placed on a print-stream
+ page, see section 4.2.10 for the details.
+
+ 2. The document data is in the form of a print-stream in a known
+ media type. The "page-ranges" attribute is used to select, as
+ specified in section 4.2.7, a sub-sequence of the pages in the
+ print-stream that are to be processed and images.
+
+ 3. The input to this step is a sequence of print-stream pages.
+ This step is controlled by the "number-up" attribute. If the
+
+
+
+Hastings, et al. Standards Track [Page 212]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ value of "number-up" is N, then during the processing of the
+ print-stream pages, each N print-stream pages are positioned,
+ as specified in section 4.2.9, to create a single impression.
+ If a given document does not have N more print-stream pages,
+ then the completion of the impression is controlled by the
+ "multiple-document-handling" attribute as described in section
+ 4.2.4; when the value of this attribute is 'single-document' or
+ 'single-document-new-sheet', the print-stream pages of document
+ data from subsequent documents is used to complete the
+ impression.
+
+ The size(scaling), position(translation) and rotation of the
+ print-stream pages on the impression is implementation defined.
+ Note that during this process the print-stream pages may be
+ rendered to a form suitable for placing on the impression; this
+ rendering is controlled by the values of the "printer-
+ resolution" and "print-quality" attributes as described in
+ sections 4.2.12 and 4.2.13. In the case N=1, the impression is
+ nearly the same as the print-stream page; the differences would
+ only be in the size, position and rotation of the print-stream
+ page and/or any decoration, such as a frame to the page, that
+ is added by the implementation.
+
+ 4. The collection of impressions is placed, in sequence, onto
+ sides of the media sheets. This placement is controlled by the
+ "sides" attribute and the orientation of the print-stream page,
+ as described in section 4.2.8. The orientation of the print-
+ stream pages affects the orientation of the impression; for
+ example, if "number-up" equals 2, then, typically, two portrait
+ print-stream pages become one landscape impression. Note that
+ the placement of impressions onto media sheets is also
+ controlled by the "multiple-document-handling" attribute as
+ described in section 4.2.4.
+
+ 5. The "copies" and "multiple-document-handling" attributes are
+ used to determine how many copies of each media instance are
+ created and in what order. See sections 4.2.5 and 4.2.4 for the
+ details.
+
+ 6. When the correct number of copies are created, the media
+ instances are finished according to the values of the
+ "finishings" attribute as described in 4.2.6. Note that
+ sometimes finishing operations may require manual intervention
+ to perform the finishing operations on the copies, especially
+ uncollated copies. This document allows any or all of the
+ processing steps to be performed automatically or manually at
+ the discretion of the Printer object.
+
+
+
+
+Hastings, et al. Standards Track [Page 213]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+16. APPENDIX E: Generic Directory Schema
+
+ This section defines a generic schema for an entry in a directory
+ service. A directory service is a means by which service users can
+ locate service providers. In IPP environments, this means that IPP
+ Printers can be registered (either automatically or with the help of
+ an administrator) as entries of type printer in the directory using
+ an implementation specific mechanism such as entry attributes, entry
+ type fields, specific branches, etc. Directory clients can search or
+ browse for entries of type printer. Clients use the directory
+ service to find entries based on naming, organizational contexts, or
+ filtered searches on attribute values of entries. For example, a
+ client can find all printers in the "Local Department" context.
+ Authentication and authorization are also often part of a directory
+ service so that an administrator can place limits on end users so
+ that they are only allowed to find entries to which they have certain
+ access rights. IPP itself does not require any specific directory
+ service protocol or provider.
+
+ Note: Some directory implementations allow for the notion of
+ "aliasing". That is, one directory entry object can appear as
+ multiple directory entry object with different names for each object.
+ In each case, each alias refers to the same directory entry object
+ which refers to a single IPP Printer object.
+
+ The generic schema is a subset of IPP Printer Job Template and
+ Printer Description attributes (sections 4.2 and 4.4). These
+ attributes are identified as either RECOMMENDED or OPTIONAL for the
+ directory entry itself. This conformance labeling is NOT the same
+ conformance labeling applied to the attributes of IPP Printers
+ objects. The conformance labeling in this Appendix is intended to
+ apply to directory templates and to IPP Printer implementations that
+ subscribe by adding one or more entries to a directory. RECOMMENDED
+ attributes SHOULD be associated with each directory entry. OPTIONAL
+ attributes MAY be associated with the directory entry (if known or
+ supported). In addition, all directory entry attributes SHOULD
+ reflect the current attribute values for the corresponding Printer
+ object.
+
+ The names of attributes in directory schema and entries SHOULD be the
+ same as the IPP Printer attribute names as shown, as much as
+ possible.
+
+ In order to bridge between the directory service and the IPP Printer
+ object, one of the RECOMMENDED directory entry attributes is the
+ Printer object's "printer-uri-supported" attribute. The directory
+ client queries the "printer-uri-supported" attribute (or its
+ equivalent) in the directory entry and then the IPP client addresses
+
+
+
+Hastings, et al. Standards Track [Page 214]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ the IPP Printer object using one of its URIs. The "uri-security-
+ supported" attribute identifies the protocol (if any) used to secure
+ a channel.
+
+ The following attributes define the generic schema for directory
+ entries of type PRINTER:
+
+ printer-uri-supported RECOMMENDED Section 4.4.1
+ uri-authentication-supported RECOMMENDED Section 4.4.2
+ uri-security-supported RECOMMENDED Section 4.4.3
+ printer-name RECOMMENDED Section 4.4.4
+ printer-location RECOMMENDED Section 4.4.5
+ printer-info OPTIONAL Section 4.4.6
+ printer-more-info OPTIONAL Section 4.4.7
+ printer-make-and-model RECOMMENDED Section 4.4.9
+ ipp-versions-supported RECOMMENDED Section 4.4.14
+ multiple-document-jobs-supported OPTIONAL Section 4.4.16
+ charset-supported OPTIONAL Section 4.4.18
+
+ generated-natural-language-
+ supported OPTIONAL Section 4.4.20
+ document-format-supported RECOMMENDED Section 4.4.22
+ color-supported RECOMMENDED Section 4.4.26
+ compression-supported RECOMMENDED Section 4.4.32
+ pages-per-minute OPTIONAL Section 4.4.36
+ pages-per-minute-color OPTIONAL Section 4.4.37
+
+ finishings-supported OPTIONAL Section 4.2.6
+ number-up-supported OPTIONAL Section 4.2.7
+ sides-supported RECOMMENDED Section 4.2.8
+ media-supported RECOMMENDED Section 4.2.11
+ printer-resolution-supported OPTIONAL Section 4.2.12
+ print-quality-supported OPTIONAL Section 4.2.13
+
+17. APPENDIX F: Differences between the IPP/1.0 and IPP/1.1 "Model and
+ Semantics" Documents
+
+ This Appendix is divided into two lists that summarize the
+ differences between IPP/1.1 (this document) and IPP/1.0 [RFC2566].
+ The section numbers refer to the numbers in this document which in
+ some cases have changed from RFC 2566. When a change affects
+ multiple sections, the item is listed once in the order of the first
+ section affected and the remaining affected section numbers are
+ indicated.
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 215]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ The first list contains extensions and clarifications and the second
+ list contains changes in semantics or conformance. However, client
+ and IPP object implementations of IPP/1.0 MAY implement any of the
+ extensions and clarifications in this document.
+
+ The following extensions and clarifications have been incorporated
+ into this document:
+
+ 1. Section 2.1 - clarified that the term "client" can be either
+ contained in software controlled by an end user or a part of a
+ print server that controls devices.
+ 2. Section 2 - clarified that the term "IPP object" and "Printer
+ object" can either be embedded in a device object or part of a
+ print server that accepts IPP requests.
+ 3. Section 2.4 - added the description of the new "uri-
+ authentication-supported" Printer Description attribute.
+ 4. Section 3.1.3, 3.1.6, 3.2.5.2, and 3.2.6.2 - clarified the
+ error handling for operation attributes that have their own
+ status code.
+ 5. Section 3.1.3 - clarified that multiple occurrences of the
+ same attribute in an attribute group is mal-formed. An IPP
+ Printer MAY reject the request or choose one of the
+ attributes.
+ 6. Section 3.1.6 - reorganized this section into sub-sections to
+ separately describe "status-code", "status-message",
+ "detailed-status-message", and "document-access-error"
+ attributes.
+ 7. Section 3.1.6.1 - clarified the error status codes and their
+ relationship to operation attributes.
+ 8. Section 3.1.6.3 - Added the OPTIONAL "detailed-status-message
+ (text(MAX))" operation attribute to provide additional more
+ detailed information about a response.
+ 9. Section 3.1.6.4 and 3.2.2 - Added the OPTIONAL "document-
+ access-error (text(MAX))" operation attribute for use with
+ Print-URI and Send-URI responses.
+ 10. Sections 3.1.7 - Added this new section to clarify returning
+ Unsupported Attributes for all operations, including only
+ returning attributes that were in the request. Moved the text
+ from section 3.2.1.2 Unsupported Attributes to this section.
+ 11. Sections 3.1.7 and 4.1 - clarified the encoding of the "out-
+ of-band" 'unsupported' and 'unknown' values.
+ 12. Section 3.1.8 - clarified that only the version number
+ parameter will be carried forward into future major or minor
+ versions of the protocol.
+ 13. Section 3.1.8 - relaxed the requirements to increment the
+ major version number in future versions of the Model and
+ Semantics document.
+
+
+
+
+Hastings, et al. Standards Track [Page 216]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 14. Section 3.1.9, and 3.2.5 - added the 'processing' state to the
+ list of job states that a job can be in after a Create-Job
+ operation.
+ 15. Section 3.1.9 - clarified that a non-spooling Printer MAY
+ accept zero or more subsequent jobs while processing a job and
+ flow control them down. Subsequent create requests are
+ rejected with the 'server-error-busy' error status.
+ 16. Section 3.2.1.1 - clarified the validation of the
+ "compression" operation attribute and its relationship to the
+ validation of the "document-format" attribute and returning
+ Unsupported Attributes.
+ 17. Sections 3.2.1.1, 4.3.8, 13.1.4.16, and 13.1.4.17 - added the
+ 'client-error-compression-not-supported', 'client-error-
+ compression-error' status codes and the 'unsupported-
+ compression' and 'compression-error' job-state-reasons.
+ 18. Sections 3.2.1.1 and 4.3.8 - added 'unsupported-document-
+ format' and 'document-format-error' job-state-reasons.
+ 19. Sections 3.2.2, 4.3.8 and 13.1.4.19 - added 'client-error-
+ document-access-error' status code and 'document-access-error'
+ job state reason.
+ 20. Section 3.2.5.2 and 3.2.6.2 - clarified that the Unsupported
+ Attributes group MUST NOT include attributes not requested in
+ the Get-Printer-Attributes request.
+ 21. Section 3.2.6 - clarified that "limit" takes precedence over
+ "which-jobs" and "my-jobs'.
+ 22. Section 3.2.6.2 - clarified that Get-Jobs returns
+ 'successful-ok' when no jobs to return.
+ 23. Sections 3.2.7, 3.2.8, and 3.2.9 - added the OPTIONAL Pause-
+ Printer, Resume-Printer, and Purge-Jobs operations
+ 24. Section 3.3.1 - clarified that the authorization required for
+ a Send-Document request MUST be the same user as the Create-
+ Job or an operator.
+ 25. Section 3.3.1.1 - clarified that a Create-Job Send-Document
+ with "last-document" = 'true' and no data is not an error; its
+ a job with no documents.
+ 26. Sections 3.3.5, 3.3.6, and 3.3.7 - added the OPTIONAL Hold-
+ Job, Release-Job, and Restart-Job operations. Clarified the
+ Restart-Job operation so that the Printer MUST re-fetch any
+ documents passed by-reference (Print-URI or Send-URI).
+ 27. Section 4.1 - clarified that the encoding of the out-of-band
+ values are specified in the Encoding and Transport" document.
+ 28. Section 4.1 - Clarified that the requirement that clients MUST
+ NOT send "out-of-band" values in requests applies only to
+ operations defined in this document. Other operations are
+ allowed to define "out-of-band" values that clients can
+ supply.
+
+
+
+
+
+Hastings, et al. Standards Track [Page 217]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 29. Sections 4.1.1 and 4.1.2 - clarified that the maximum 'text'
+ and 'name' values of 1023 and 255 are for the
+ 'textWithoutLanguage' portion of the 'textWithLanguage' form,
+ so that the maximum number of octets for the actual text and
+ name data is the same for the without and with language forms;
+ the 'naturalLanguage' part is in addition.
+ 30. Section 4.1.9 - clarified that 'mimeMediaType' values can
+ include any parameters from the IANA Registry, not just
+ charset parameters.
+ 31. Section 4.1.9.1 - clarified that 'application/octet-stream'
+ auto-sensing can happen at create request time and/or
+ job/document processing time.
+ 32. Section 4.1.9.1 - clarified that auto-sensing involves the
+ Printer examining some number of octets of document data using
+ an implementation-dependent method.
+ 33. Section 4.1.14 - clarified that the localization of dateTime
+ by the client includes the time zone.
+ 34. Section 4.2 - clarified that xxx-supported have multiple
+ keywords and/or names by adding parentheses to the table to
+ give: (1setOf (type3 keyword | name))
+ 35. Section 4.2.2 - added the 'indefinite' keyword value to the
+ "job-hold-until" attribute for use with the create operations
+ and Hold-Job and Restart-Job operations.
+ 36. Section 4.2.6 - added more enum values to the "finishings" Job
+ Template attribute.
+ 37. Section 4.2.6 - clarified that the landscape definition is a
+ rotation of the image with respect to the medium.
+ 38. Section 4.3.7 - added that a forwarding server that cannot get
+ any job state MAY return the job's state as 'completed',
+ provided that it also return the new 'queued-in-device' job
+ state reason.
+ 39. Section 4.3.7.2 - added the Partitioning of Job States section
+ to clarify the concepts of Job Retention, Job History, and Job
+ Removal.
+ 40. Section 4.3.8 - added 'job-data-insufficient' job state reason
+ to indicate whether sufficient data has arrived for the
+ document to start to be processed.
+ 41. Section 4.3.8 - added 'document-access-error' job state reason
+ to indicate an access error of any kind.
+ 42. Section 4.3.8 - added 'job-queued-for-marker' job state reason
+ to indicate whether the job has completed some processing and
+ is waiting for the marker.
+ 43. Section 4.3.8 - added 'unsupported-compression' and
+ 'compression-error' job state reasons to indicate compression
+ not supported or compression processing error after the create
+ has been accepted.
+
+
+
+
+
+Hastings, et al. Standards Track [Page 218]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 44. Section 4.3.8 - added 'unsupported-document-format' and
+ 'document-format-error' job state reasons to indicate document
+ not supported or document format processing error after the
+ create has been accepted.
+ 45. Section 4.3.8 - added 'queued-in-device' job state reason to
+ indicate that a job as been forwarded to a print system or
+ device that does not provide any job status.
+ 46. Section 4.3.10 - added "job-detailed-status-messages (1setOf
+ text(MAX)) for returning detailed error messages.
+ 47. Section 4.3.11 - added the "job-document-access-errors (1setOf
+ text(MAX))
+ 48. Section 4.3.14.2 - clarified that the time recorded is the
+ first time processing since the create operation or the
+ Restart-Job operation.
+ 49. Section 4.3.14.2 and 4.3.14.3 - clarified that the out-of-band
+ value 'no-value' is returned if the job has not started
+ processing or has not completed, respectively.
+ 50. Section 4.3.14 - Added the OPTIONAL "date-time-at-creation",
+ "date-time-at-processing", and "date-time-at-completed" Event
+ Time Job Description attributes
+ 51. Section 4.4.3 - added the 'tls' value to "uri-security-
+ supported" attribute.
+ 52. Section 4.4.3 - clarified "uri-security-supported" is
+ orthogonal to Client Authentication so that 'none' does not
+ exclude Client Authentication.
+ 53. Section 4.4.11 - simplified the "printer-state" descriptions
+ while generalizing to allow high end devices that interpret
+ one or more jobs while marking another. Indicated that
+ 'spool-area-full' and 'stopped-partly' "printer-state-reasons"
+ may be used to provide further state information.
+ 54. Section 4.4.12 - added the 'moving-to-paused' keyword value to
+ the "printer-state-reasons" attribute for use with the Pause-
+ Printer operation.
+ 55. Section 4.4.12 - replaced the duplicate 'marker-supply-low'
+ keyword with the missing 'toner-empty' keyword for the
+ "printer-state-reasons" attribute. (This correction was also
+ made before RFC 2566 was published).
+ 56. Section 4.4.12 - clarified 'spool-area-full' "printer-state-
+ reasons" to include non-spooling printers to indicate when it
+ can and cannot accept another job.
+ 57. Section 4.4.15 - added the enum values to the "operations-
+ supported" attribute for the new operations. Clarified that
+ the values of this attribute are encoded as any enum, namely
+ 32-bit values.
+ 58. Section 4.4.30 - clarified that the dateTime value of
+ "printer-current-time" is on a "best efforts basis". If a
+ proper date-time cannot be obtained, the implementation
+ returns the 'no-value' out-of-band value. Also clarified that
+
+
+
+Hastings, et al. Standards Track [Page 219]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ the time zone NEED NOT be the time zone that the people near
+ the device use and that the client SHOULD display the dateTime
+ attributes in the user's local time.
+ 59. Sections 4.4.36 and 4.4.37 - added the OPTIONAL "pages-per-
+ minute" and "pages-per-minute-color" Printer Description
+ attributes.
+ 60. Section 5.1 - clarified that the client conformance
+ requirements apply to clients controlled by an end user and
+ clients in servers.
+ 61. Section 5.1 - clarified that any response MAY contain
+ additional attribute groups, attributes, attribute syntaxes,
+ or attribute values.
+ 62. Section 5.1 - clarified that a client SHOULD do its best to
+ prevent a channel from being closed by a lower layer when the
+ channel is flow controlled off by the IPP Printer.
+ 63. Section 5.2 - clarified that the IPP object requirements apply
+ to objects embedded in devices or that are parts of servers.
+ 64. Section 5.2.2 - clarified that IPP objects MAY return
+ operation responses that contain attribute groups, attribute
+ names, attribute syntaxes, attribute values, and status codes
+ that are extensions to this standard.
+ 65. Section 6 - changed the terminology of "private extensions" to
+ "vendor extensions" and indicated that they are registered
+ with IANA along with IETF standards track extensions.
+ 66. Section 6.7 - inserted this section on registering out-of-band
+ attribute values with IANA as extensions.
+ 67. Section 8.3 - clarified the use of URIs for each Client
+ Authentication mechanism.
+ 68. Section 8.5 - added the security discussion around the new
+ operator/administrator operations.
+ 69. Section 13.1.4.16 - added client-error-compression-not-
+ supported (0x040F)
+ 70. Section 13.1.4.17 - added client-error-compression-error
+ (0x0410)
+ 71. Section 13.1.4.18 - added client-error-document-format-error
+ (0x0411)
+ 72. Section 13.1.4.19 - added client-error-document-access-error
+ (0x0412)
+ 73. Section 13.1.5.10 - added server-error-multiple-document-
+ jobs-not-supported (0x0509)
+ 74. Section 14 - added 'a-white', 'b-white', 'c-white', 'd-white',
+ and 'e-white' and clarified that the existing 'a', 'b', 'c',
+ 'd', and 'e' values are size values. Added American,
+ Japanese, and European Engineering sizes, filled out
+ -transparent and - translucent media names and drawings for
+ the synchro cut sizes.
+
+
+
+
+
+Hastings, et al. Standards Track [Page 220]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 75. Section 16 - softened the RECOMMENDATION for IPP Printer
+ attributes in a Directory schema so that they can have
+ equivalents.
+ 76. Section 16 - added the OPTIONAL "pages-per-minute" and
+ "pages-per-minute-color" Printer attributes to the Directory
+ schema.
+ 77. Section 16 - added OPTIONAL "multiple-document-jobs-supported"
+ to the Directory schema.
+ 78. Section 16 - added RECOMMENDED "uri-authentication-supported",
+ "ipp-versions-supported", and "compression-supported" to the
+ Directory schema.
+
+ The following changes in semantics and/or conformance have been
+ incorporated into this document:
+
+ 1. Section 3.1.6.3 - allowed a Printer to localize the
+ "detailed-status-message" operation response attribute, but
+ indicated that such localization might obscure the technical
+ meaning of such messages.
+ 2. Section 3.1.8, 5.2.4, and 13.1.5.4 - Clients and IPP objects
+ MUST support version 1.1 conformance requirements. It is
+ recommended that they interoperate with 1.0. Also clarified
+ that IPP Printers MUST accept '1.1' requests. It is
+ recommended that they also accept '1.x' requests.
+
+ 3. Section 3.2.1.1 and section 4.4.32 - changed the "compression"
+ operation and the "compression-supported" Printer Description
+ attribute from OPTIONAL to REQUIRED.
+ 4. Sections 3.2.1.2 and 4.3.8 - changed "job-state-reasons" from
+ RECOMMENDED to REQUIRED, so that "job-state-reasons" MUST be
+ returned in create operation responses.
+ 5. Sections 3.2.4, 3.3.1, 4.4.16, and 16 - changed Create-
+ Job/Send-Document so that they MAY be implemented while only
+ supporting one document jobs. Added the "multiple-document-
+ jobs-supported" boolean Printer Description attribute to
+ indicate whether Create-Job/Send-Document support multiple
+ document jobs or not. Added to the Directory schema.
+ 6. Section 4.1.9 - deleted 'text/plain; charset=iso-10646-ucs-2',
+ since binary is not legal with the 'text' type.
+ 7. Section 4.1.9.1 - added the RECOMMENDATION that a Printer
+ indicate by printing on the job's job-start-sheet that auto-
+ sensing has occurred and what document format was auto-sensed.
+ 8. Section 4.2.4 - indicated that the "multiple-document-
+ handling" Job Template attribute MUST be supported with at
+ least one value if the Printer supports multiple documents per
+ job
+
+
+
+
+
+Hastings, et al. Standards Track [Page 221]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 9. Section 4.3.7.2 - indicated that the 'job-restartable' job
+ state reason SHOULD be supported if the Restart-Job operation
+ is supported.
+ 10. Section 4.3.8 - changed "job-state-reasons" from RECOMMENDED
+ to REQUIRED.
+ 11. Section 4.3.8 - clarified the conformance of the values of the
+ "job-state-reasons" attribute by copying conformance
+ requirements from other sections of the document so that it is
+ clear from reading the definition of "job-state-reasons" which
+ values MUST or SHOULD be supported. The 'none',
+ 'unsupported-compression', and 'unsupported-document-format'
+ values MUST be supported. The 'job-hold-until-specified'
+ SHOULD be specified if the "job-hold-until" Job Template is
+ supported. The following values SHOULD be supported: 'job-
+ canceled-by-user', 'aborted-by-system', and 'job-completed-
+ successfully'. The
+ 'job-canceled-by-operator' SHOULD be supported if the
+ implementation permits canceling by other than the job owner.
+ The 'job-canceled-at-device' SHOULD be supported if the device
+ supports canceling jobs at the console. The 'job-completed-
+ with-warnings' SHOULD be supported, if the implementation
+ detects warnings. The 'job-completed-with-errors' SHOULD be
+ supported if the implementation detects errors. The 'job-
+ restartable' SHOULD be supported if the Restart-Job operation
+ is supported.
+ 12. Section 4.3.10 - allowed a Printer to localize the "job-
+ detailed-status-message" Job Description attribute, but
+ indicated that such localization might obscure the technical
+ meaning of such messages.
+ 13. Section 4.3.14 - changed the "time-at-creation", "time-at-
+ processing", and "time-at-completed" Event Time Job
+ Description attributes from OPTIONAL to REQUIRED.
+ 14. Section 4.3.14.4 - added the REQUIRED "job-printer-up-time
+ (integer(1:MAX))" Job Description attribute as an alias for
+ "printer-up-time" to reduce number of operations to get job
+ times.
+ 15. Section 4.4.2 - added the REQUIRED "uri-authentication-
+ supported (1setOf type2 keyword)" Printer Description
+ attribute to describe the Client Authentication used by each
+ Printer URI.
+ 16. Section 4.4.12 - changed "printer-state-reasons" Printer
+ Description attribute from OPTIONAL to REQUIRED.
+ 17. Section 4.4.12 - changed 'paused' value of "printer-state-
+ reasons" to MUST if Pause-Printer operation is supported.
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 222]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 18. Section 4.4.14 - added the REQUIRED "ipp-versions-supported
+ (1setOf keyword)" Printer Description attribute, since IPP/1.1
+ Printers do not have to support version '1.0' conformance
+ requirements. Section 4.4.16 - added the "multiple-document-
+ jobs-supported (boolean)" Printer Description attribute so
+ that a client can tell whether a Printer that supports
+ Create-Job/Send-Document supports multiple document jobs or
+ not. This attribute is REQUIRED if the Create-Job operation
+ is supported.
+ 19. Section 4.4.24 - changed the "queued-job-count" Printer
+ Description attribute from RECOMMENDED to REQUIRED.
+ 20. Section 4.4.32 - changed "compression-supported (1setOf type3
+ keyword)" Printer Description attribute from OPTIONAL to
+ REQUIRED.
+ 21. Section 5.1 - changed the client security requirements from
+ RECOMMENDED non-standards track SSL3 to MUST support Client
+ Authentication as defined in the IPP/1.1 Encoding and
+ Transport document [RFC2910]. A client SHOULD support
+ Operation Privacy and Server Authentication as defined in the
+ IPP/1.1 Encoding and Transport document [RFC2910].
+ 22. Section 5.2.7 - changed the IPP object security requirements
+ from OPTIONAL non-standards track SSL3 to SHOULD contain
+ support for Client Authentication as defined in the IPP/1.1
+ Encoding and Transport document [RFC2910]. A Printer
+ implementation MAY allow an administrator to configure the
+ Printer so that all, some, or none of the users are
+ authenticated. An IPP Printer implementation SHOULD contain
+ support for Operation Privacy and Server Authentication as
+ defined in the IPP/1.1 Encoding and Transport document
+ [RFC2910]. A Printer implementation MAY allow an
+ administrator to configure the degree of support for Operation
+ Privacy and Server Authentication. Security MUST NOT be
+ compromised when the client supplies a lower version-number in
+ a request.
+ 23. Section 14 (Appendix C): Corrected typo, changing the keyword
+ 'iso-10-white' to 'iso-a10-white'.
+
+ See also the "IPP/1.1 Encoding and Transport" [RFC2910] document for
+ differences between IPP/1.0 [RFC2565] and IPP/1.1 [RFC2910].
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 223]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+18. Full Copyright Statement
+
+ Copyright (C) The Internet Society (2000). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 224]
+
diff --git a/systemv/.cvsignore b/systemv/.cvsignore
new file mode 100644
index 000000000..9d86f74cb
--- /dev/null
+++ b/systemv/.cvsignore
@@ -0,0 +1,10 @@
+lp
+cupsaddsmb
+lppasswd
+lpoptions
+lpadmin
+accept
+cancel
+lpinfo
+lpmove
+lpstat
diff --git a/systemv/Makefile b/systemv/Makefile
new file mode 100644
index 000000000..e8929ed84
--- /dev/null
+++ b/systemv/Makefile
@@ -0,0 +1,190 @@
+#
+# "$Id$"
+#
+# System V commands makefile for the Common UNIX Printing System (CUPS).
+#
+# Copyright 1997-2002 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 = accept cancel cupsaddsmb lp lpadmin lpinfo lpmove \
+ lpoptions lppasswd lpstat
+OBJS = accept.o cancel.o cupsaddsmb.o lp.o lpadmin.o \
+ lpinfo.o lpmove.o lpoptions.o lppasswd.o lpstat.o
+
+
+#
+# Make all targets...
+#
+
+all: $(TARGETS)
+
+
+#
+# Clean all object files...
+#
+
+clean:
+ $(RM) $(OBJS) $(TARGETS)
+
+
+#
+# Install all targets...
+#
+
+install:
+ $(INSTALL_DIR) $(BINDIR)
+ $(INSTALL_BIN) accept $(SBINDIR)
+ $(RM) $(SBINDIR)/reject
+ $(LN) accept $(SBINDIR)/reject
+ $(INSTALL_BIN) cupsaddsmb $(SBINDIR)
+ $(INSTALL_BIN) lpadmin $(SBINDIR)
+ $(INSTALL_BIN) lpinfo $(SBINDIR)
+ $(INSTALL_BIN) lpmove $(SBINDIR)
+ $(INSTALL_BIN) cancel $(BINDIR)
+ $(RM) $(BINDIR)/disable
+ $(LN) ../sbin/accept $(BINDIR)/disable
+ $(RM) $(BINDIR)/enable
+ $(LN) ../sbin/accept $(BINDIR)/enable
+ $(INSTALL_BIN) lp $(BINDIR)
+ $(INSTALL_BIN) lpoptions $(BINDIR)
+ $(INSTALL_BIN) lpstat $(BINDIR)
+ $(INSTALL_BIN) -m 4755 -o $(CUPS_USER) -g $(CUPS_GROUP) lppasswd $(BINDIR)
+
+
+#
+# accept
+#
+
+accept: accept.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o accept accept.o $(LIBS)
+ $(RM) reject enable disable
+ $(LN) accept reject
+ $(LN) accept enable
+ $(LN) accept disable
+
+accept.o: ../cups/cups.h
+
+
+#
+# cancel
+#
+
+cancel: cancel.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o cancel cancel.o $(LIBS)
+
+cancel.o: ../cups/cups.h
+
+
+#
+# cupsaddsmb
+#
+
+cupsaddsmb: cupsaddsmb.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o cupsaddsmb cupsaddsmb.o $(LIBS)
+
+cupsaddsmb.o: ../cups/cups.h ../cups/string.h
+
+
+#
+# lp
+#
+
+lp: lp.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o lp lp.o $(LIBS)
+
+lp.o: ../cups/cups.h
+
+
+#
+# lpadmin
+#
+
+lpadmin: lpadmin.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o lpadmin lpadmin.o $(LIBZ) $(LIBS)
+
+lpadmin.o: ../cups/cups.h
+
+
+#
+# lpinfo
+#
+
+lpinfo: lpinfo.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o lpinfo lpinfo.o $(LIBS)
+
+lpinfo.o: ../cups/cups.h
+
+
+#
+# lpmove
+#
+
+lpmove: lpmove.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o lpmove lpmove.o $(LIBS)
+
+lpmove.o: ../cups/cups.h
+
+
+#
+# lpoptions
+#
+
+lpoptions: lpoptions.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o lpoptions lpoptions.o $(LIBZ) $(LIBS)
+
+lpoptions.o: ../cups/cups.h
+
+
+#
+# lppasswd
+#
+
+lppasswd: lppasswd.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o lppasswd lppasswd.o $(LIBZ) $(LIBS)
+
+lppasswd.o: ../cups/cups.h ../cups/md5.h ../cups/string.h ../config.h
+
+
+#
+# lpstat
+#
+
+lpstat: lpstat.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o lpstat lpstat.o $(LIBS)
+
+lpstat.o: ../cups/cups.h
+
+
+$(OBJS): ../Makedefs
+
+#
+# End of "$Id$".
+#
diff --git a/systemv/accept.c b/systemv/accept.c
new file mode 100644
index 000000000..bdb5e9adb
--- /dev/null
+++ b/systemv/accept.c
@@ -0,0 +1,316 @@
+/*
+ * "$Id$"
+ *
+ * "accept", "disable", "enable", and "reject" commands for the Common
+ * UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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 accept/reject jobs or disable/enable printers.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include <config.h>
+#include <cups/cups.h>
+#include <cups/string.h>
+#include <cups/language.h>
+
+
+/*
+ * 'main()' - Parse options and accept/reject jobs or disable/enable printers.
+ */
+
+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 */
+ char *command, /* Command to do */
+ hostname[HTTP_MAX_URI],
+ /* Name of host */
+ printer[HTTP_MAX_URI],
+ /* Name of printer or class */
+ uri[1024], /* Printer URI */
+ *reason; /* Reason for reject/disable */
+ const char *server; /* Server name */
+ ipp_t *request; /* IPP request */
+ ipp_t *response; /* IPP response */
+ ipp_op_t op; /* Operation */
+ cups_lang_t *language; /* Language */
+ int cancel; /* Cancel jobs? */
+ http_encryption_t encryption; /* Encryption? */
+
+
+ /*
+ * See what operation we're supposed to do...
+ */
+
+ if ((command = strrchr(argv[0], '/')) != NULL)
+ command ++;
+ else
+ command = argv[0];
+
+ cancel = 0;
+
+ if (strcmp(command, "accept") == 0)
+ op = CUPS_ACCEPT_JOBS;
+ else if (strcmp(command, "reject") == 0)
+ op = CUPS_REJECT_JOBS;
+ else if (strcmp(command, "disable") == 0)
+ op = IPP_PAUSE_PRINTER;
+ else if (strcmp(command, "enable") == 0)
+ op = IPP_RESUME_PRINTER;
+ else
+ {
+ fprintf(stderr, "%s: Don't know what to do!\n", command);
+ return (1);
+ }
+
+ server = cupsServer();
+ http = NULL;
+ reason = NULL;
+ encryption = cupsEncryption();
+
+ /*
+ * Process command-line arguments...
+ */
+
+ for (i = 1; i < argc; i ++)
+ if (argv[i][0] == '-')
+ switch (argv[i][1])
+ {
+ case 'E' : /* Encrypt */
+#ifdef HAVE_LIBSSL
+ encryption = HTTP_ENCRYPT_REQUIRED;
+
+ if (http)
+ httpEncryption(http, encryption);
+#else
+ fprintf(stderr, "%s: Sorry, no encryption support compiled in!\n",
+ argv[0]);
+#endif /* HAVE_LIBSSL */
+ break;
+
+ case 'c' : /* Cancel jobs */
+ cancel = 1;
+ break;
+
+ case 'h' : /* Connect to host */
+ if (http != NULL)
+ httpClose(http);
+
+ if (argv[i][2] != '\0')
+ server = argv[i] + 2;
+ else
+ {
+ i ++;
+ if (i >= argc)
+ {
+ fprintf(stderr, "%s: Expected server name after -h!\n",
+ command);
+ return (1);
+ }
+
+ server = argv[i];
+ }
+
+ http = httpConnectEncrypt(server, ippPort(), encryption);
+
+ if (http == NULL)
+ {
+ fputs(argv[0], stderr);
+ perror(": Unable to connect to server");
+ return (1);
+ }
+ break;
+
+ case 'r' : /* Reason for cancellation */
+ if (argv[i][2] != '\0')
+ reason = argv[i] + 2;
+ else
+ {
+ i ++;
+ if (i >= argc)
+ {
+ fprintf(stderr, "%s: Expected reason text after -r!\n", command);
+ return (1);
+ }
+
+ reason = argv[i];
+ }
+ break;
+
+ default :
+ fprintf(stderr, "%s: Unknown option \'%c\'!\n", command,
+ argv[i][1]);
+ return (1);
+ }
+ else
+ {
+ /*
+ * Accept/disable/enable/reject a destination...
+ */
+
+ if (sscanf(argv[i], "%1023[^@]@%1023s", printer, hostname) == 1)
+ {
+ strncpy(hostname, server, sizeof(hostname) - 1);
+ hostname[sizeof(hostname) - 1] = '\0';
+ }
+
+ if (http != NULL && strcasecmp(http->hostname, hostname) != 0)
+ {
+ httpClose(http);
+ http = NULL;
+ }
+
+ if (http == NULL)
+ http = httpConnectEncrypt(hostname, ippPort(), encryption);
+
+ if (http == NULL)
+ {
+ fputs(argv[0], stderr);
+ perror(": Unable to connect to server");
+ return (1);
+ }
+
+ /*
+ * Build an IPP request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * printer-state-message [optional]
+ */
+
+ 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);
+
+ snprintf(uri, sizeof(uri), "ipp://%s:%d/printers/%s", hostname, ippPort(), printer);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, uri);
+
+ if (reason != NULL)
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT,
+ "printer-state-message", NULL, reason);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/admin/")) != NULL)
+ {
+ if (response->request.status.status_code > IPP_OK_CONFLICT)
+ {
+ fprintf(stderr, "%s: Operation failed: %s\n", command,
+ ippErrorString(cupsLastError()));
+ return (1);
+ }
+
+ ippDelete(response);
+ }
+ else
+ {
+ fprintf(stderr, "%s: Operation failed: %s\n", command,
+ ippErrorString(cupsLastError()));
+ return (1);
+ }
+
+ /*
+ * Cancel all jobs if requested...
+ */
+
+ if (cancel)
+ {
+ /*
+ * Build an IPP_PURGE_JOBS request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ */
+
+ request = ippNew();
+
+ request->request.op.operation_id = IPP_PURGE_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(uri, sizeof(uri), "ipp://%s:%d/printers/%s", hostname, ippPort(), printer);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, uri);
+
+ if ((response = cupsDoRequest(http, request, "/admin/")) != NULL)
+ {
+ if (response->request.status.status_code > IPP_OK_CONFLICT)
+ {
+ fprintf(stderr, "%s: Operation failed: %s\n", command,
+ ippErrorString(cupsLastError()));
+ return (1);
+ }
+
+ ippDelete(response);
+ }
+ else
+ {
+ fprintf(stderr, "%s: Operation failed: %s\n", command,
+ ippErrorString(cupsLastError()));
+ return (1);
+ }
+ }
+ }
+
+ if (http != NULL)
+ httpClose(http);
+
+ return (0);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/systemv/cancel.c b/systemv/cancel.c
new file mode 100644
index 000000000..1592afe99
--- /dev/null
+++ b/systemv/cancel.c
@@ -0,0 +1,286 @@
+/*
+ * "$Id$"
+ *
+ * "cancel" command for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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 <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include <config.h>
+#include <cups/cups.h>
+#include <cups/string.h>
+#include <cups/language.h>
+
+
+/*
+ * '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 */
+ char *dest, /* Destination printer */
+ *host, /* Host name */
+ *job; /* Job ID pointer */
+ char name[255]; /* Printer name */
+ 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 */
+ http_encryption_t encryption; /* Encryption? */
+
+
+ /*
+ * Setup to cancel individual print jobs...
+ */
+
+ op = IPP_CANCEL_JOB;
+ job_id = 0;
+ dest = NULL;
+ http = NULL;
+ encryption = cupsEncryption();
+
+ /*
+ * Process command-line arguments...
+ */
+
+ for (i = 1; i < argc; i ++)
+ if (argv[i][0] == '-' && argv[i][1])
+ switch (argv[i][1])
+ {
+ case 'E' : /* Encrypt */
+#ifdef HAVE_LIBSSL
+ encryption = HTTP_ENCRYPT_REQUIRED;
+
+ if (http)
+ httpEncryption(http, encryption);
+#else
+ fprintf(stderr, "%s: Sorry, no encryption support compiled in!\n",
+ argv[0]);
+#endif /* HAVE_LIBSSL */
+ break;
+
+ case 'a' : /* Cancel all jobs */
+ op = IPP_PURGE_JOBS;
+ break;
+
+ case 'h' : /* Connect to host */
+ if (http != NULL)
+ httpClose(http);
+
+ if (argv[i][2] != '\0')
+ http = httpConnectEncrypt(argv[i] + 2, ippPort(), encryption);
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ fputs("cancel: Error - expected hostname after \'-h\' option!\n", stderr);
+ return (1);
+ }
+ else
+ http = httpConnectEncrypt(argv[i], ippPort(), encryption);
+ }
+
+ if (http == NULL)
+ {
+ perror("cancel: Unable to connect to server");
+ return (1);
+ }
+ break;
+
+ case 'u' : /* Username */
+ if (argv[i][2] != '\0')
+ cupsSetUser(argv[i] + 2);
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ fputs("cancel: Error - expected username after \'-u\' option!\n", stderr);
+ return (1);
+ }
+ else
+ cupsSetUser(argv[i]);
+ }
+ break;
+
+ default :
+ fprintf(stderr, "cancel: 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 (argv[i][0] == '-')
+ {
+ dest = "";
+ job_id = 0;
+ }
+ else
+ {
+ strncpy(name, argv[i], sizeof(name) - 1);
+ name[sizeof(name) - 1] = '\0';
+
+ dest = name;
+ job_id = 0;
+
+ if ((job = strrchr(name, '-')) != NULL)
+ if (isdigit(job[1]))
+ {
+ *job++ = '\0';
+ job_id = atoi(job);
+ }
+
+ if (job_id)
+ op = IPP_CANCEL_JOB;
+
+ if ((host = strchr(name, '@')) != NULL)
+ {
+ /*
+ * Reconnect to the named host...
+ */
+
+ if (http != NULL)
+ httpClose(http);
+
+ *host++ = '\0';
+
+ if ((http = httpConnectEncrypt(host, ippPort(), encryption)) == NULL)
+ {
+ perror("cancel: Unable to connect to server");
+ return (1);
+ }
+ }
+ }
+
+ /*
+ * Open a connection to the server...
+ */
+
+ if (http == NULL)
+ if ((http = httpConnectEncrypt(cupsServer(), ippPort(),
+ encryption)) == NULL)
+ {
+ fputs("cancel: Unable to contact server!\n", stderr);
+ return (1);
+ }
+
+ /*
+ * 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 ||
+ response->request.status.status_code > IPP_OK_CONFLICT)
+ {
+ fprintf(stderr, "cancel: %s failed: %s\n",
+ op == IPP_PURGE_JOBS ? "purge-jobs" : "cancel-job",
+ response ? ippErrorString(response->request.status.status_code) :
+ ippErrorString(cupsLastError()));
+
+ if (response)
+ ippDelete(response);
+
+ return (1);
+ }
+
+ ippDelete(response);
+ }
+
+ return (0);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/systemv/cupsaddsmb.c b/systemv/cupsaddsmb.c
new file mode 100644
index 000000000..cce4a3e2c
--- /dev/null
+++ b/systemv/cupsaddsmb.c
@@ -0,0 +1,286 @@
+/*
+ * "$Id$"
+ *
+ * "cupsaddsmb" command for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 2001 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() - Export printers on the command-line.
+ * do_samba_command() - Do a SAMBA command, asking for a password as needed.
+ * export_dest() - Export a destination to SAMBA.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <cups/cups.h>
+#include <cups/string.h>
+#include <errno.h>
+
+
+/*
+ * Local globals...
+ */
+
+int Verbosity = 0;
+
+
+/*
+ * Local functions...
+ */
+
+int do_samba_command(const char *, const char *, const char *);
+int export_dest(const char *);
+
+
+/*
+ * 'main()' - Export printers on the command-line.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i, j; /* Looping vars */
+ int status; /* Status from export_dest() */
+ int num_printers; /* Number of printers */
+ char **printers; /* Printers */
+
+
+ for (i = 1; i < argc; i ++)
+ if (strcmp(argv[i], "-a") == 0)
+ {
+ num_printers = cupsGetPrinters(&printers);
+
+ for (j = 0, status = 0; j < num_printers; j ++)
+ if ((status = export_dest(printers[j])) != 0)
+ break;
+
+ for (j = 0; j < num_printers; j ++)
+ free(printers[j]);
+
+ if (num_printers)
+ free(printers);
+
+ if (status)
+ return (status);
+ }
+ else if (strcmp(argv[i], "-U") == 0)
+ {
+ i ++;
+ if (i >= argc)
+ {
+ puts("Usage: cupsaddsmb [-a] [-U user] [-v] [printer1 ... printerN]");
+ return (1);
+ }
+
+ cupsSetUser(argv[i]);
+ }
+ else if (strcmp(argv[i], "-v") == 0)
+ Verbosity = 1;
+ else if (argv[i][0] != '-')
+ {
+ if ((status = export_dest(argv[i])) != 0)
+ return (status);
+ }
+ else
+ {
+ puts("Usage: cupsaddsmb [-a] [-U user] [-v] [printer1 ... printerN]");
+ return (1);
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'do_samba_command()' - Do a SAMBA command, asking for
+ * a password as needed.
+ */
+
+int /* O - Status of command */
+do_samba_command(const char *command, /* I - Command to run */
+ const char *args, /* I - Argument(s) for command */
+ const char *subcmd) /* I - Sub-command */
+{
+ int status; /* Status of command */
+ char temp[4096]; /* Command/prompt string */
+ static const char *p = NULL; /* Password data */
+
+
+ for (status = 1;;)
+ {
+ if (p)
+ snprintf(temp, sizeof(temp), "%s -N -U\'%s%%%s\' %s -c \'%s\'",
+ command, cupsUser(), p, args, subcmd);
+ else
+ snprintf(temp, sizeof(temp), "%s -N -U\'%s\' %s -c \'%s\'",
+ command, cupsUser(), args, subcmd);
+
+ if (Verbosity)
+ printf("Running command: %s\n", temp);
+ else
+ {
+ strncat(temp, " </dev/null >/dev/null 2>/dev/null", sizeof(temp) - 1);
+ temp[sizeof(temp) - 1] = '\0';
+ }
+
+ if (Verbosity)
+ printf("Running the following command:\n\n %s\n", temp);
+ else
+ {
+ strncat(temp, " >/dev/null 2>/dev/null", sizeof(temp) - 1);
+ temp[sizeof(temp) - 1] = '\0';
+ }
+
+ if ((status = system(temp)) != 0)
+ {
+ if (Verbosity)
+ puts("");
+
+ snprintf(temp, sizeof(temp),
+ "Password for %s required to access %s via SAMBA: ",
+ cupsUser(), cupsServer());
+
+ if ((p = cupsGetPassword(temp)) == NULL)
+ break;
+ }
+ else
+ {
+ if (Verbosity)
+ puts("");
+
+ break;
+ }
+ }
+
+ return (status);
+}
+
+
+/*
+ * 'export_dest()' - Export a destination to SAMBA.
+ */
+
+int /* O - 0 on success, non-zero on error */
+export_dest(const char *dest) /* I - Destination to export */
+{
+ int status; /* Status of smbclient/rpcclient commands */
+ const char *ppdfile; /* PPD file for printer drivers */
+ char command[1024], /* Command to run */
+ subcmd[1024]; /* Sub-command */
+ const char *datadir; /* CUPS_DATADIR */
+
+
+ if ((datadir = getenv("CUPS_DATADIR")) == NULL)
+ datadir = CUPS_DATADIR;
+
+ /* Get the PPD file... */
+ if ((ppdfile = cupsGetPPD(dest)) == NULL)
+ {
+ fprintf(stderr, "Warning: No PPD file for printer \"%s\"!\n", dest);
+ return (1);
+ }
+
+ /* Do the smbclient commands needed for the Windows drivers... */
+ snprintf(command, sizeof(command), "smbclient //%s/print\\$", cupsServer());
+
+ snprintf(subcmd, sizeof(subcmd),
+ "mkdir W32X86;"
+ "put %s W32X86/%s.PPD;"
+ "put %s/drivers/ADOBEPS5.DLL W32X86/ADOBEPS5.DLL;"
+ "put %s/drivers/ADOBEPSU.DLL W32X86/ADOBEPSU.DLL;"
+ "put %s/drivers/ADOBEPSU.HLP W32X86/ADOBEPSU.HLP",
+ ppdfile, dest, datadir, datadir, datadir);
+
+ if ((status = do_samba_command(command, "", subcmd)) != 0)
+ {
+ fprintf(stderr, "ERROR: Unable to copy Windows printer driver files (%d)!\n",
+ status);
+ unlink(ppdfile);
+ return (3);
+ }
+
+ snprintf(subcmd, sizeof(subcmd),
+ "mkdir WIN40;"
+ "put %s WIN40/%s.PPD;"
+ "put %s/drivers/ADFONTS.MFM WIN40/ADFONTS.MFM;"
+ "put %s/drivers/ADOBEPS4.DRV WIN40/ADOBEPS4.DRV;"
+ "put %s/drivers/ADOBEPS4.HLP WIN40/ADOBEPS4.HLP;"
+ "put %s/drivers/DEFPRTR2.PPD WIN40/DEFPRTR2.PPD;"
+ "put %s/drivers/ICONLIB.DLL WIN40/ICONLIB.DLL;"
+ "put %s/drivers/PSMON.DLL WIN40/PSMON.DLL;",
+ ppdfile, dest, datadir, datadir, datadir,
+ datadir, datadir, datadir);
+
+ if ((status = do_samba_command(command, "", subcmd)) != 0)
+ {
+ fprintf(stderr, "ERROR: Unable to copy Windows printer driver files (%d)!\n",
+ status);
+ unlink(ppdfile);
+ return (3);
+ }
+
+ unlink(ppdfile);
+
+ /* Do the rpcclient commands needed for the Windows drivers... */
+ snprintf(subcmd, sizeof(subcmd),
+ "adddriver \"Windows NT x86\" \"%s:ADOBEPS5.DLL:%s.PPD:ADOBEPSU.DLL:ADOBEPSU.HLP:NULL:RAW:NULL\"",
+ dest, dest);
+
+ if ((status = do_samba_command("rpcclient", cupsServer(), subcmd)) != 0)
+ {
+ fprintf(stderr, "ERROR: Unable to install Windows printer driver files (%d)!\n",
+ status);
+ return (5);
+ }
+
+ snprintf(subcmd, sizeof(subcmd), "addprinter %s %s \"%s\" \"\"",
+ dest, dest, dest);
+
+ if ((status = do_samba_command("rpcclient", cupsServer(), subcmd)) != 0)
+ {
+ fprintf(stderr, "ERROR: Unable to install Windows printer driver files (%d)!\n",
+ status);
+ return (5);
+ }
+
+ snprintf(subcmd, sizeof(subcmd),
+ "adddriver \"Windows 4.0\" \"%s:ADOBEPS4.DRV:%s.PPD:NULL:ADOBEPS4.HLP:PSMON.DLL:RAW:ADFONTS.MFM,DEFPRTR2.PPD,ICONLIB.DLL\"",
+ dest, dest);
+
+ if ((status = do_samba_command("rpcclient", cupsServer(), subcmd)) != 0)
+ {
+ fprintf(stderr, "ERROR: Unable to install Windows printer driver files (%d)!\n",
+ status);
+ return (5);
+ }
+
+ return (0);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/systemv/lp.c b/systemv/lp.c
new file mode 100644
index 000000000..7faed77b9
--- /dev/null
+++ b/systemv/lp.c
@@ -0,0 +1,654 @@
+/*
+ * "$Id$"
+ *
+ * "lp" command for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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 <stdio.h>
+#include <stdlib.h>
+#include <cups/cups.h>
+#include <cups/string.h>
+#include <cups/language.h>
+
+
+#ifndef WIN32
+# include <signal.h>
+
+
+/*
+ * Local functions.
+ */
+
+void sighandler(int);
+#endif /* !WIN32 */
+int set_job_attrs(int job_id, int num_options, cups_option_t *options);
+
+
+/*
+ * 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, j; /* Looping vars */
+ int job_id; /* Job ID */
+ char *printer, /* Printer name */
+ *instance, /* Instance name */
+ *val, /* Option value */
+ *title; /* Job title */
+ int priority; /* Job priority (1-100) */
+ int num_copies; /* Number of copies per file */
+ int num_files; /* Number of files to print */
+ const char *files[1000]; /* Files to print */
+ int num_dests; /* Number of destinations */
+ cups_dest_t *dests, /* Destinations */
+ *dest; /* Selected destination */
+ int num_options; /* Number of options */
+ cups_option_t *options; /* Options */
+ int silent; /* Silent or verbose output? */
+ char buffer[8192]; /* Copy buffer */
+ int temp; /* Temporary file descriptor */
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ struct sigaction action; /* Signal action */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET*/
+
+
+#ifdef __sun
+ /*
+ * Solaris does some rather strange things to re-queue remote print
+ * jobs. On bootup, the "lp" command is run as "printd" to re-spool
+ * any remote jobs in /var/spool/print. Since CUPS doesn't need this
+ * nonsense, we just need to add the necessary check here to prevent
+ * lp from causing boot problems...
+ */
+
+ if ((val = strrchr(argv[0], '/')) != NULL)
+ val ++;
+ else
+ val = argv[0];
+
+ if (strcmp(val, "printd") == 0)
+ return (0);
+#endif /* __sun */
+
+ silent = 0;
+ printer = NULL;
+ num_dests = 0;
+ dests = NULL;
+ num_options = 0;
+ options = NULL;
+ num_files = 0;
+ title = NULL;
+ job_id = 0;
+
+ for (i = 1; i < argc; i ++)
+ if (argv[i][0] == '-')
+ switch (argv[i][1])
+ {
+ case 'E' : /* Encrypt */
+#ifdef HAVE_LIBSSL
+ cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
+#else
+ fprintf(stderr, "%s: Sorry, no encryption support compiled in!\n",
+ argv[0]);
+#endif /* HAVE_LIBSSL */
+ break;
+
+ case 'c' : /* Copy to spool dir (always enabled) */
+ break;
+
+ case 'd' : /* Destination printer or class */
+ if (argv[i][2] != '\0')
+ printer = argv[i] + 2;
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ fputs("lp: Expected destination after -d option!\n", stderr);
+ return (1);
+ }
+
+ printer = argv[i];
+ }
+
+ if ((instance = strrchr(printer, '/')) != NULL)
+ *instance++ = '\0';
+
+ if (num_dests == 0)
+ num_dests = cupsGetDests(&dests);
+
+ if ((dest = cupsGetDest(printer, instance, num_dests, dests)) != NULL)
+ {
+ for (j = 0; j < dest->num_options; j ++)
+ if (cupsGetOption(dest->options[j].name, num_options, options) == NULL)
+ num_options = cupsAddOption(dest->options[j].name,
+ dest->options[j].value,
+ num_options, &options);
+ }
+ break;
+
+ case 'f' : /* Form */
+ if (!argv[i][2])
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ fputs("lp: Expected form after -f option!\n", stderr);
+ return (1);
+ }
+ }
+
+ fputs("lp: Warning - form option ignored!\n", stderr);
+ break;
+
+ case 'h' : /* Destination host */
+ if (argv[i][2] != '\0')
+ cupsSetServer(argv[i] + 2);
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ fputs("lp: Expected hostname after -h option!\n", stderr);
+ return (1);
+ }
+
+ cupsSetServer(argv[i]);
+ }
+ break;
+
+ case 'i' : /* Change job */
+ if (argv[i][2])
+ val = argv[i] + 2;
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ fputs("lp: Expected job ID after -i option!\n", stderr);
+ return (1);
+ }
+
+ val = argv[i];
+ }
+
+ if (num_files > 0)
+ {
+ fputs("lp: Error - cannot print files and alter jobs simultaneously!\n", stderr);
+ return (1);
+ }
+
+ if (strrchr(val, '-') != NULL)
+ job_id = atoi(strrchr(val, '-') + 1);
+ else
+ job_id = atoi(val);
+
+ if (job_id < 0)
+ {
+ fputs("lp: Error - bad job ID!\n", stderr);
+ break;
+ }
+ break;
+
+ case 'm' : /* Send email when job is done */
+#ifdef __sun
+ case 'p' : /* Notify on completion */
+#endif /* __sun */
+ case 'w' : /* Write to console or email */
+ break;
+
+ case 'n' : /* Number of copies */
+ if (argv[i][2] != '\0')
+ num_copies = atoi(argv[i] + 2);
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ fputs("lp: Expected copies after -n option!\n", stderr);
+ return (1);
+ }
+
+ num_copies = atoi(argv[i]);
+ }
+
+ if (num_copies < 1 || num_copies > 100)
+ {
+ fputs("lp: 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 'o' : /* Option */
+ if (argv[i][2] != '\0')
+ num_options = cupsParseOptions(argv[i] + 2, num_options, &options);
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ fputs("lp: Expected option string after -o option!\n", stderr);
+ return (1);
+ }
+
+ num_options = cupsParseOptions(argv[i], num_options, &options);
+ }
+ break;
+
+#ifndef __sun
+ case 'p' : /* Queue priority */
+#endif /* !__sun */
+ case 'q' : /* Queue priority */
+ if (argv[i][2] != '\0')
+ priority = atoi(argv[i] + 2);
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ fprintf(stderr, "lp: Expected priority after -%c option!\n",
+ argv[i][1]);
+ return (1);
+ }
+
+ priority = atoi(argv[i]);
+ }
+
+ /*
+ * For 100% Solaris compatibility, need to add:
+ *
+ * priority = 99 * (39 - priority) / 39 + 1;
+ *
+ * However, to keep CUPS lp the same across all platforms
+ * we will break compatibility this far...
+ */
+
+ if (priority < 1 || priority > 100)
+ {
+ fputs("lp: Priority must be between 1 and 100.\n", stderr);
+ return (1);
+ }
+
+ sprintf(buffer, "%d", priority);
+ num_options = cupsAddOption("job-priority", buffer, num_options, &options);
+ break;
+
+ case 's' : /* Silent */
+ silent = 1;
+ break;
+
+ case 't' : /* Title */
+ if (argv[i][2] != '\0')
+ title = argv[i] + 2;
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ fputs("lp: Expected title after -t option!\n", stderr);
+ return (1);
+ }
+
+ title = argv[i];
+ }
+ break;
+
+ case 'y' : /* mode-list */
+ if (!argv[i][2])
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ fputs("lp: Expected mode list after -y option!\n", stderr);
+ return (1);
+ }
+ }
+
+ fputs("lp: Warning - mode option ignored!\n", stderr);
+ break;
+
+ case 'H' : /* Hold job */
+ if (argv[i][2])
+ val = argv[i] + 2;
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ fputs("lp: Expected hold name after -H option!\n", stderr);
+ return (1);
+ }
+
+ val = argv[i];
+ }
+
+ if (strcmp(val, "hold") == 0)
+ num_options = cupsAddOption("job-hold-until", "indefinite",
+ num_options, &options);
+ else if (strcmp(val, "resume") == 0 ||
+ strcmp(val, "release") == 0)
+ num_options = cupsAddOption("job-hold-until", "no-hold",
+ num_options, &options);
+ else if (strcmp(val, "immediate") == 0)
+ num_options = cupsAddOption("job-priority", "100",
+ num_options, &options);
+ else
+ num_options = cupsAddOption("job-hold-until", val,
+ num_options, &options);
+ break;
+
+ case 'P' : /* Page list */
+ if (argv[i][2])
+ val = argv[i] + 2;
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ fputs("lp: Expected page list after -P option!\n", stderr);
+ return (1);
+ }
+
+ val = argv[i];
+ }
+
+ num_options = cupsAddOption("page-ranges", val, num_options,
+ &options);
+ break;
+
+ case 'S' : /* character set */
+ if (!argv[i][2])
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ fputs("lp: Expected character set after -S option!\n", stderr);
+ return (1);
+ }
+ }
+
+ fputs("lp: Warning - character set option ignored!\n", stderr);
+ break;
+
+ case 'T' : /* Content-Type */
+ if (!argv[i][2])
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ fputs("lp: Expected content type after -T option!\n", stderr);
+ return (1);
+ }
+ }
+
+ fputs("lp: Warning - content type option ignored!\n", stderr);
+ break;
+
+ default :
+ fprintf(stderr, "lp: Unknown option \'%c\'!\n", argv[i][1]);
+ return (1);
+ }
+ else if (num_files < 1000 && job_id == 0)
+ {
+ /*
+ * Print a file...
+ */
+
+ files[num_files] = argv[i];
+ num_files ++;
+
+ if (title == NULL)
+ {
+ if ((title = strrchr(argv[i], '/')) != NULL)
+ title ++;
+ else
+ title = argv[i];
+ }
+ }
+ else
+ fprintf(stderr, "lp: Too many files - \"%s\"\n", argv[i]);
+
+ /*
+ * See if we are altering an existing job...
+ */
+
+ if (job_id)
+ return (set_job_attrs(job_id, num_options, options));
+
+ /*
+ * See if we have any files to print; if not, print from stdin...
+ */
+
+ if (printer == NULL)
+ {
+ if (num_dests == 0)
+ num_dests = cupsGetDests(&dests);
+
+ for (j = 0, dest = dests; j < num_dests; j ++, dest ++)
+ if (dest->is_default)
+ {
+ printer = dests[j].name;
+
+ for (j = 0; j < dest->num_options; j ++)
+ if (cupsGetOption(dest->options[j].name, num_options, options) == NULL)
+ num_options = cupsAddOption(dest->options[j].name,
+ dest->options[j].value,
+ num_options, &options);
+ break;
+ }
+ }
+
+ if (printer == NULL)
+ {
+ fputs("lp: error - no default destination available.\n", stderr);
+ return (1);
+ }
+
+ if (num_files > 0)
+ job_id = cupsPrintFiles(printer, num_files, files, title, num_options, options);
+ else
+ {
+ num_files = 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 = cupsTempFd(tempfile, sizeof(tempfile));
+
+ if (temp < 0)
+ {
+ fputs("lp: unable to create temporary file.\n", stderr);
+ return (1);
+ }
+
+ while ((i = read(0, buffer, sizeof(buffer))) > 0)
+ write(temp, buffer, i);
+
+ i = lseek(temp, 0, SEEK_CUR);
+ close(temp);
+
+ if (i == 0)
+ {
+ fputs("lp: stdin is empty, so no job has been sent.\n", stderr);
+ return (1);
+ }
+
+ if (title)
+ job_id = cupsPrintFile(printer, tempfile, title, num_options, options);
+ else
+ job_id = cupsPrintFile(printer, tempfile, "(stdin)", num_options, options);
+
+ unlink(tempfile);
+ }
+
+ if (job_id < 1)
+ {
+ fprintf(stderr, "lp: unable to print file: %s\n",
+ ippErrorString(cupsLastError()));
+ return (1);
+ }
+ else if (!silent)
+ printf("request id is %s-%d (%d file(s))\n", printer, job_id, num_files);
+
+ return (0);
+}
+
+
+/*
+ * 'set_job_attrs()' - Set job attributes.
+ */
+
+int /* O - Exit status */
+set_job_attrs(int job_id, /* I - Job ID */
+ int num_options,/* I - Number of options */
+ cups_option_t *options) /* I - Options */
+{
+ http_t *http; /* HTTP connection to server */
+ ipp_t *request, /* IPP request */
+ *response; /* IPP response */
+ cups_lang_t *language; /* Language for request */
+ char uri[HTTP_MAX_URI]; /* URI for job */
+
+
+ http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
+
+ language = cupsLangDefault();
+
+ request = ippNew();
+ request->request.op.operation_id = IPP_SET_JOB_ATTRIBUTES;
+ request->request.op.request_id = 1;
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, cupsLangEncoding(language));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ sprintf(uri, "ipp://localhost/jobs/%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());
+
+ cupsEncodeOptions(request, num_options, options);
+
+ if ((response = cupsDoRequest(http, request, "/jobs")) != NULL)
+ {
+ if (response->request.status.status_code > IPP_OK_CONFLICT)
+ {
+ fprintf(stderr, "lp: set-job-attributes failed: %s\n",
+ ippErrorString(response->request.status.status_code));
+ ippDelete(response);
+ return (1);
+ }
+
+ ippDelete(response);
+ }
+ else
+ {
+ fprintf(stderr, "lp: set-job-attributes failed: %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/systemv/lpadmin.c b/systemv/lpadmin.c
new file mode 100644
index 000000000..458b4ec7d
--- /dev/null
+++ b/systemv/lpadmin.c
@@ -0,0 +1,1856 @@
+/*
+ * "$Id$"
+ *
+ * "lpadmin" command for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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 configure the scheduler.
+ * add_printer_to_class() - Add a printer to a class.
+ * default_printer() - Set the default printing destination.
+ * delete_printer() - Delete a printer from the system...
+ * delete_printer_from_class() - Delete a printer from a class.
+ * enable_printer() - Enable a printer...
+ * set_printer_device() - Set the device-uri attribute.
+ * set_printer_file() - Set the interface script or PPD file.
+ * set_printer_info() - Set the printer description string.
+ * set_printer_location() - Set the printer location string.
+ * set_printer_model() - Set the driver model file.
+ * set_printer_options() - Set the printer options.
+ * validate_name() - Make sure the printer name only contains
+ * letters, numbers, and the underscore...
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <cups/cups.h>
+#include <cups/string.h>
+#include <cups/language.h>
+#include <cups/debug.h>
+#include <config.h>
+#ifdef HAVE_LIBZ
+# include <zlib.h>
+#endif /* HAVE_LIBZ */
+
+
+/*
+ * Local functions...
+ */
+
+static void add_printer_to_class(http_t *, char *, char *);
+static void default_printer(http_t *, char *);
+static void delete_printer(http_t *, char *);
+static void delete_printer_from_class(http_t *, char *, char *);
+static void enable_printer(http_t *, char *);
+static char *get_line(char *, int, FILE *fp);
+static void set_printer_device(http_t *, char *, char *);
+static void set_printer_file(http_t *, char *, char *);
+static void set_printer_info(http_t *, char *, char *);
+static void set_printer_location(http_t *, char *, char *);
+static void set_printer_model(http_t *, char *, char *);
+static void set_printer_options(http_t *, char *, int, cups_option_t *);
+static int validate_name(const char *);
+
+
+/*
+ * 'main()' - Parse options and configure the scheduler.
+ */
+
+int
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i; /* Looping var */
+ http_t *http; /* Connection to server */
+ char *printer, /* Destination printer */
+ *pclass, /* Printer class name */
+ *val; /* Pointer to allow/deny value */
+ int num_options; /* Number of options */
+ cups_option_t *options; /* Options */
+ http_encryption_t encryption; /* Encryption? */
+
+
+ http = NULL;
+ printer = NULL;
+ num_options = 0;
+ options = NULL;
+ encryption = cupsEncryption();
+
+ for (i = 1; i < argc; i ++)
+ if (argv[i][0] == '-')
+ switch (argv[i][1])
+ {
+ case 'c' : /* Add printer to class */
+ if (!http)
+ {
+ http = httpConnectEncrypt(cupsServer(), ippPort(), encryption);
+
+ if (http == NULL)
+ {
+ perror("lpadmin: Unable to connect to server");
+ return (1);
+ }
+ }
+
+ if (printer == NULL)
+ {
+ fputs("lpadmin: Unable to add a printer to the class:\n", stderr);
+ fputs(" You must specify a printer name first!\n", stderr);
+ return (1);
+ }
+
+ if (argv[i][2])
+ pclass = argv[i] + 2;
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ fputs("lpadmin: Expected class name after \'-c\' option!\n", stderr);
+ return (1);
+ }
+
+ pclass = argv[i];
+ }
+
+ if (!validate_name(pclass))
+ {
+ fputs("lpadmin: Class name can only contain letters, numbers, and the underscore!\n", stderr);
+ return (1);
+ }
+
+ add_printer_to_class(http, printer, pclass);
+ break;
+
+ case 'd' : /* Set as default destination */
+ if (!http)
+ {
+ http = httpConnectEncrypt(cupsServer(), ippPort(), encryption);
+
+ if (http == NULL)
+ {
+ perror("lpadmin: Unable to connect to server");
+ return (1);
+ }
+ }
+
+ if (argv[i][2])
+ printer = argv[i] + 2;
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ fputs("lpadmin: Expected printer name after \'-d\' option!\n", stderr);
+ return (1);
+ }
+
+ printer = argv[i];
+ }
+
+ if (!validate_name(printer))
+ {
+ fputs("lpadmin: Printer name can only contain letters, numbers, and the underscore!\n", stderr);
+ return (1);
+ }
+
+ default_printer(http, printer);
+ i = argc;
+ break;
+
+ case 'h' : /* Connect to host */
+ if (http)
+ httpClose(http);
+
+ if (argv[i][2] != '\0')
+ http = httpConnectEncrypt(argv[i] + 2, ippPort(), encryption);
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ fputs("lpadmin: Expected hostname after \'-h\' option!\n", stderr);
+ return (1);
+ }
+ else
+ http = httpConnectEncrypt(argv[i], ippPort(), encryption);
+ }
+
+ if (http == NULL)
+ {
+ perror("lpadmin: Unable to connect to server");
+ return (1);
+ }
+ else
+ cupsSetServer(http->hostname);
+ break;
+
+ case 'i' : /* Use the specified interface script */
+ if (!http)
+ {
+ http = httpConnectEncrypt(cupsServer(), ippPort(), encryption);
+
+ if (http == NULL)
+ {
+ perror("lpadmin: Unable to connect to server");
+ return (1);
+ }
+ }
+
+ if (printer == NULL)
+ {
+ fputs("lpadmin: Unable to set the interface script:\n", stderr);
+ fputs(" You must specify a printer name first!\n", stderr);
+ return (1);
+ }
+
+ if (argv[i][2])
+ set_printer_file(http, printer, argv[i] + 2);
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ fputs("lpadmin: Expected interface after \'-i\' option!\n", stderr);
+ return (1);
+ }
+
+ set_printer_file(http, printer, argv[i]);
+ }
+ break;
+
+ case 'E' : /* Enable the printer */
+ if (printer == NULL)
+ {
+#ifdef HAVE_LIBSSL
+ cupsSetEncryption(encryption = HTTP_ENCRYPT_REQUIRED);
+
+ if (http)
+ httpEncryption(http, encryption);
+#else
+ fprintf(stderr, "%s: Sorry, no encryption support compiled in!\n",
+ argv[0]);
+#endif /* HAVE_LIBSSL */
+ break;
+ }
+
+ if (!http)
+ {
+ http = httpConnectEncrypt(cupsServer(), ippPort(), encryption);
+
+ if (http == NULL)
+ {
+ perror("lpadmin: Unable to connect to server");
+ return (1);
+ }
+ }
+
+ enable_printer(http, printer);
+ break;
+
+ case 'm' : /* Use the specified standard script/PPD file */
+ if (!http)
+ {
+ http = httpConnectEncrypt(cupsServer(), ippPort(), encryption);
+
+ if (http == NULL)
+ {
+ perror("lpadmin: Unable to connect to server");
+ return (1);
+ }
+ }
+
+ if (printer == NULL)
+ {
+ fputs("lpadmin: Unable to set the interface script or PPD file:\n", stderr);
+ fputs(" You must specify a printer name first!\n", stderr);
+ return (1);
+ }
+
+ if (argv[i][2])
+ set_printer_model(http, printer, argv[i] + 2);
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ fputs("lpadmin: Expected model after \'-m\' option!\n", stderr);
+ return (1);
+ }
+
+ set_printer_model(http, printer, argv[i]);
+ }
+ break;
+
+ case 'o' : /* Set option */
+ if (argv[i][2])
+ num_options = cupsParseOptions(argv[i] + 2, num_options, &options);
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ fputs("lpadmin: Expected name=value after \'-o\' option!\n", stderr);
+ return (1);
+ }
+
+ num_options = cupsParseOptions(argv[i], num_options, &options);
+ }
+ break;
+
+ case 'p' : /* Add/modify a printer */
+ if (!http)
+ {
+ http = httpConnectEncrypt(cupsServer(), ippPort(), encryption);
+
+ if (http == NULL)
+ {
+ perror("lpadmin: Unable to connect to server");
+ return (1);
+ }
+ }
+
+ if (argv[i][2])
+ printer = argv[i] + 2;
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ fputs("lpadmin: Expected printer after \'-p\' option!\n", stderr);
+ return (1);
+ }
+
+ printer = argv[i];
+ }
+
+ if (!validate_name(printer))
+ {
+ fputs("lpadmin: Printer name can only contain letters, numbers, and the underscore!\n", stderr);
+ return (1);
+ }
+ break;
+
+ case 'r' : /* Remove printer from class */
+ if (!http)
+ {
+ http = httpConnectEncrypt(cupsServer(), ippPort(), encryption);
+
+ if (http == NULL)
+ {
+ perror("lpadmin: Unable to connect to server");
+ return (1);
+ }
+ }
+
+ if (printer == NULL)
+ {
+ fputs("lpadmin: Unable to remove a printer from the class:\n", stderr);
+ fputs(" You must specify a printer name first!\n", stderr);
+ return (1);
+ }
+
+ if (argv[i][2])
+ pclass = argv[i] + 2;
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ fputs("lpadmin: Expected class after \'-r\' option!\n", stderr);
+ return (1);
+ }
+
+ pclass = argv[i];
+ }
+
+ if (!validate_name(pclass))
+ {
+ fputs("lpadmin: Class name can only contain letters, numbers, and the underscore!\n", stderr);
+ return (1);
+ }
+
+ delete_printer_from_class(http, printer, pclass);
+ break;
+
+ case 'u' : /* Allow/deny users */
+ if (argv[i][2])
+ val = argv[i] + 2;
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ fputs("lpadmin: Expected name=value after \'-o\' option!\n", stderr);
+ return (1);
+ }
+
+ val = argv[i];
+ }
+
+ if (strncasecmp(val, "allow:", 6) == 0)
+ num_options = cupsAddOption("requesting-user-name-allowed",
+ val + 6, num_options, &options);
+ else if (strncasecmp(val, "deny:", 5) == 0)
+ num_options = cupsAddOption("requesting-user-name-denied",
+ val + 5, num_options, &options);
+ else
+ {
+ fprintf(stderr, "lpadmin: Unknown allow/deny option \"%s\"!\n",
+ val);
+ return (1);
+ }
+ break;
+
+ case 'v' : /* Set the device-uri attribute */
+ if (!http)
+ {
+ http = httpConnectEncrypt(cupsServer(), ippPort(), encryption);
+
+ if (http == NULL)
+ {
+ perror("lpadmin: Unable to connect to server");
+ return (1);
+ }
+ }
+
+ if (printer == NULL)
+ {
+ fputs("lpadmin: Unable to set the device URI:\n", stderr);
+ fputs(" You must specify a printer name first!\n", stderr);
+ return (1);
+ }
+
+ if (argv[i][2])
+ set_printer_device(http, printer, argv[i] + 2);
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ fputs("lpadmin: Expected device URI after \'-v\' option!\n", stderr);
+ return (1);
+ }
+
+ set_printer_device(http, printer, argv[i]);
+ }
+ break;
+
+ case 'x' : /* Delete a printer */
+ if (!http)
+ {
+ http = httpConnectEncrypt(cupsServer(), ippPort(), encryption);
+
+ if (http == NULL)
+ {
+ perror("lpadmin: Unable to connect to server");
+ return (1);
+ }
+ }
+
+ if (argv[i][2])
+ printer = argv[i] + 2;
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ fputs("lpadmin: Expected printer or class after \'-x\' option!\n", stderr);
+ return (1);
+ }
+
+ printer = argv[i];
+ }
+
+ if (!validate_name(printer))
+ {
+ fputs("lpadmin: Printer name can only contain letters, numbers, and the underscore!\n", stderr);
+ return (1);
+ }
+
+ delete_printer(http, printer);
+ i = argc;
+ break;
+
+ case 'D' : /* Set the printer-info attribute */
+ if (!http)
+ {
+ http = httpConnectEncrypt(cupsServer(), ippPort(), encryption);
+
+ if (http == NULL)
+ {
+ perror("lpadmin: Unable to connect to server");
+ return (1);
+ }
+ }
+
+ if (printer == NULL)
+ {
+ fputs("lpadmin: Unable to set the printer description:\n", stderr);
+ fputs(" You must specify a printer name first!\n", stderr);
+ return (1);
+ }
+
+ if (argv[i][2])
+ set_printer_info(http, printer, argv[i] + 2);
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ fputs("lpadmin: Expected description after \'-D\' option!\n", stderr);
+ return (1);
+ }
+
+ set_printer_info(http, printer, argv[i]);
+ }
+ break;
+
+ case 'L' : /* Set the printer-location attribute */
+ if (!http)
+ {
+ http = httpConnectEncrypt(cupsServer(), ippPort(), encryption);
+
+ if (http == NULL)
+ {
+ perror("lpadmin: Unable to connect to server");
+ return (1);
+ }
+ }
+
+ if (printer == NULL)
+ {
+ fputs("lpadmin: Unable to set the printer location:\n", stderr);
+ fputs(" You must specify a printer name first!\n", stderr);
+ return (1);
+ }
+
+ if (argv[i][2])
+ set_printer_location(http, printer, argv[i] + 2);
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ fputs("lpadmin: Expected location after \'-L\' option!\n", stderr);
+ return (1);
+ }
+
+ set_printer_location(http, printer, argv[i]);
+ }
+ break;
+
+ case 'P' : /* Use the specified PPD file */
+ if (!http)
+ {
+ http = httpConnectEncrypt(cupsServer(), ippPort(), encryption);
+
+ if (http == NULL)
+ {
+ perror("lpadmin: Unable to connect to server");
+ return (1);
+ }
+ }
+
+ if (printer == NULL)
+ {
+ fputs("lpadmin: Unable to set the PPD file:\n", stderr);
+ fputs(" You must specify a printer name first!\n", stderr);
+ return (1);
+ }
+
+ if (argv[i][2])
+ set_printer_file(http, printer, argv[i] + 2);
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ fputs("lpadmin: Expected PPD after \'-P\' option!\n", stderr);
+ return (1);
+ }
+
+ set_printer_file(http, printer, argv[i]);
+ }
+ break;
+
+ default :
+ fprintf(stderr, "lpadmin: Unknown option \'%c\'!\n", argv[i][1]);
+ return (1);
+ }
+ else
+ {
+ fprintf(stderr, "lpadmin: Unknown argument \'%s\'!\n", argv[i]);
+ return (1);
+ }
+
+ /*
+ * Set options as needed...
+ */
+
+ if (num_options)
+ {
+ if (!http)
+ {
+ http = httpConnectEncrypt(cupsServer(), ippPort(), encryption);
+
+ if (http == NULL)
+ {
+ perror("lpadmin: Unable to connect to server");
+ return (1);
+ }
+ }
+
+ if (printer == NULL)
+ {
+ fputs("lpadmin: Unable to set the printer options:\n", stderr);
+ fputs(" You must specify a printer name first!\n", stderr);
+ return (1);
+ }
+
+ set_printer_options(http, printer, num_options, options);
+ }
+
+ if (printer == NULL)
+ {
+ puts("Usage:");
+ puts("");
+ puts(" lpadmin [-h server] -d destination");
+ puts(" lpadmin [-h server] -x destination");
+ puts(" lpadmin [-h server] -p printer [-c add-class] [-i interface] [-m model]");
+ puts(" [-r remove-class] [-v device] [-D description]");
+ puts(" [-P ppd-file] [-o name=value]");
+ puts(" [-u allow:user,user] [-u deny:user,user]");
+ puts("");
+ }
+
+ if (http)
+ httpClose(http);
+
+ return (0);
+}
+
+
+/*
+ * 'add_printer_to_class()' - Add a printer to a class.
+ */
+
+static void
+add_printer_to_class(http_t *http, /* I - Server connection */
+ char *printer, /* I - Printer to add */
+ char *pclass) /* I - Class to add to */
+{
+ int i; /* Looping var */
+ ipp_t *request, /* IPP Request */
+ *response; /* IPP Response */
+ ipp_attribute_t *attr, /* Current attribute */
+ *members; /* Members in class */
+ cups_lang_t *language; /* Default language */
+ char uri[HTTP_MAX_URI]; /* URI for printer/class */
+
+
+ DEBUG_printf(("add_printer_to_class(%p, \"%s\", \"%s\")\n", http,
+ printer, pclass));
+
+ /*
+ * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ */
+
+ snprintf(uri, sizeof(uri), "ipp://localhost/classes/%s", pclass);
+
+ 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);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, uri);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ response = cupsDoRequest(http, request, "/");
+
+ /*
+ * Build a CUPS_ADD_CLASS request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * member-uris
+ */
+
+ request = ippNew();
+
+ request->request.op.operation_id = CUPS_ADD_CLASS;
+ request->request.op.request_id = 1;
+
+ language = cupsLangDefault();
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, cupsLangEncoding(language));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, uri);
+
+ /*
+ * See if the printer is already in the class...
+ */
+
+ if (response != NULL &&
+ (members = ippFindAttribute(response, "member-names", IPP_TAG_NAME)) != NULL)
+ for (i = 0; i < members->num_values; i ++)
+ if (strcasecmp(printer, members->values[i].string.text) == 0)
+ {
+ fprintf(stderr, "lpadmin: Printer %s is already a member of class %s.\n",
+ printer, pclass);
+ ippDelete(request);
+ ippDelete(response);
+ return;
+ }
+
+ /*
+ * OK, the printer isn't part of the class, so add it...
+ */
+
+ snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", printer);
+
+ if (response != NULL &&
+ (members = ippFindAttribute(response, "member-uris", IPP_TAG_URI)) != NULL)
+ {
+ /*
+ * Add the printer to the existing list...
+ */
+
+ attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_URI,
+ "member-uris", members->num_values + 1, NULL, NULL);
+ for (i = 0; i < members->num_values; i ++)
+ attr->values[i].string.text = strdup(members->values[i].string.text);
+
+ attr->values[i].string.text = strdup(uri);
+ }
+ else
+ attr = ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_URI, "member-uris", NULL, uri);
+
+ /*
+ * Then send the request...
+ */
+
+ ippDelete(response);
+
+ if ((response = cupsDoRequest(http, request, "/admin/")) == NULL)
+ fprintf(stderr, "lpadmin: add-class failed: %s\n",
+ ippErrorString(cupsLastError()));
+ else
+ {
+ if (response->request.status.status_code > IPP_OK_CONFLICT)
+ fprintf(stderr, "lpadmin: add-class failed: %s\n",
+ ippErrorString(response->request.status.status_code));
+
+ ippDelete(response);
+ }
+}
+
+
+/*
+ * 'default_printer()' - Set the default printing destination.
+ */
+
+static void
+default_printer(http_t *http, /* I - Server connection */
+ char *printer) /* I - Printer name */
+{
+ ipp_t *request, /* IPP Request */
+ *response; /* IPP Response */
+ cups_lang_t *language; /* Default language */
+ char uri[HTTP_MAX_URI]; /* URI for printer/class */
+
+
+ DEBUG_printf(("default_printer(%p, \"%s\")\n", http, printer));
+
+ /*
+ * Build a CUPS_SET_DEFAULT request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ */
+
+ snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", printer);
+
+ request = ippNew();
+
+ request->request.op.operation_id = CUPS_SET_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);
+
+ 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)
+ fprintf(stderr, "lpadmin: set-default failed: %s\n",
+ ippErrorString(cupsLastError()));
+ else
+ {
+ if (response->request.status.status_code > IPP_OK_CONFLICT)
+ fprintf(stderr, "lpadmin: set-default failed: %s\n",
+ ippErrorString(response->request.status.status_code));
+
+ ippDelete(response);
+ }
+}
+
+
+/*
+ * 'delete_printer()' - Delete a printer from the system...
+ */
+
+static void
+delete_printer(http_t *http, /* I - Server connection */
+ char *printer) /* I - Printer to delete */
+{
+ ipp_t *request, /* IPP Request */
+ *response; /* IPP Response */
+ cups_lang_t *language; /* Default language */
+ char uri[HTTP_MAX_URI]; /* URI for printer/class */
+
+
+ DEBUG_printf(("delete_printer(%p, \"%s\")\n", http, printer));
+
+ /*
+ * Build a CUPS_DELETE_PRINTER request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ */
+
+ snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", printer);
+
+ request = ippNew();
+
+ request->request.op.operation_id = CUPS_DELETE_PRINTER;
+ request->request.op.request_id = 1;
+
+ language = cupsLangDefault();
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, cupsLangEncoding(language));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, uri);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/admin/")) == NULL)
+ fprintf(stderr, "lpadmin: delete-printer failed: %s\n",
+ ippErrorString(cupsLastError()));
+ else
+ {
+ if (response->request.status.status_code > IPP_OK_CONFLICT)
+ fprintf(stderr, "lpadmin: delete-printer failed: %s\n",
+ ippErrorString(response->request.status.status_code));
+
+ ippDelete(response);
+ }
+}
+
+
+/*
+ * 'delete_printer_from_class()' - Delete a printer from a class.
+ */
+
+static void
+delete_printer_from_class(http_t *http, /* I - Server connection */
+ char *printer, /* I - Printer to remove */
+ char *pclass) /* I - Class to remove from */
+{
+ int i, j, k; /* Looping vars */
+ ipp_t *request, /* IPP Request */
+ *response; /* IPP Response */
+ ipp_attribute_t *attr, /* Current attribute */
+ *members; /* Members in class */
+ cups_lang_t *language; /* Default language */
+ char uri[HTTP_MAX_URI]; /* URI for printer/class */
+
+
+ DEBUG_printf(("delete_printer_from_class(%p, \"%s\", \"%s\")\n", http,
+ printer, pclass));
+
+ /*
+ * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ */
+
+ snprintf(uri, sizeof(uri), "ipp://localhost/classes/%s", pclass);
+
+ 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);
+
+ 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, "/classes/")) == NULL ||
+ response->request.status.status_code == IPP_NOT_FOUND)
+ {
+ ippDelete(response);
+ fprintf(stderr, "lpadmin: Class %s does not exist!\n", pclass);
+ return;
+ }
+
+ /*
+ * See if the printer is already in the class...
+ */
+
+ if ((members = ippFindAttribute(response, "member-names", IPP_TAG_NAME)) == NULL)
+ {
+ ippDelete(response);
+ fputs("lpadmin: No member names were seen!\n", stderr);
+ return;
+ }
+
+ for (i = 0; i < members->num_values; i ++)
+ if (strcasecmp(printer, members->values[i].string.text) == 0)
+ break;
+
+ if (i >= members->num_values)
+ {
+ fprintf(stderr, "lpadmin: Printer %s is not a member of class %s.\n",
+ printer, pclass);
+ ippDelete(response);
+ return;
+ }
+
+ if (members->num_values == 1)
+ {
+ /*
+ * 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;
+
+ language = cupsLangDefault();
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, cupsLangEncoding(language));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, uri);
+ }
+ else
+ {
+ /*
+ * Build a CUPS_ADD_CLASS request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * member-uris
+ */
+
+ request = ippNew();
+
+ request->request.op.operation_id = CUPS_ADD_CLASS;
+ request->request.op.request_id = 1;
+
+ language = cupsLangDefault();
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, cupsLangEncoding(language));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, uri);
+
+ /*
+ * Delete the printer from the class...
+ */
+
+ members = ippFindAttribute(response, "member-uris", IPP_TAG_URI);
+ attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_URI,
+ "member-uris", members->num_values - 1, NULL, NULL);
+
+ for (j = 0, k = 0; j < members->num_values; j ++)
+ if (j != i)
+ attr->values[k ++].string.text = strdup(members->values[j].string.text);
+ }
+
+ /*
+ * Then send the request...
+ */
+
+ ippDelete(response);
+
+ if ((response = cupsDoRequest(http, request, "/admin/")) == NULL)
+ fprintf(stderr, "lpadmin: add/delete-class failed: %s\n",
+ ippErrorString(cupsLastError()));
+ else
+ {
+ if (response->request.status.status_code > IPP_OK_CONFLICT)
+ fprintf(stderr, "lpadmin: add/delete-class failed: %s\n",
+ ippErrorString(response->request.status.status_code));
+
+ ippDelete(response);
+ }
+}
+
+
+/*
+ * 'enable_printer()' - Enable a printer...
+ */
+
+static void
+enable_printer(http_t *http, /* I - Server connection */
+ char *printer) /* I - Printer to enable */
+{
+ ipp_t *request, /* IPP Request */
+ *response; /* IPP Response */
+ cups_lang_t *language; /* Default language */
+ char uri[HTTP_MAX_URI]; /* URI for printer/class */
+
+
+ DEBUG_printf(("enable_printer(%p, \"%s\")\n", http, printer));
+
+ /*
+ * Build a CUPS_ADD_PRINTER request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * printer-state
+ * printer-is-accepting-jobs
+ */
+
+ snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", printer);
+
+ request = ippNew();
+
+ request->request.op.operation_id = CUPS_ADD_PRINTER;
+ request->request.op.request_id = 1;
+
+ language = cupsLangDefault();
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, cupsLangEncoding(language));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, uri);
+
+ ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state",
+ IPP_PRINTER_IDLE);
+
+ ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/admin/")) == NULL)
+ fprintf(stderr, "lpadmin: add-printer failed: %s\n",
+ ippErrorString(cupsLastError()));
+ else
+ {
+ if (response->request.status.status_code > IPP_OK_CONFLICT)
+ fprintf(stderr, "lpadmin: add-printer failed: %s\n",
+ ippErrorString(response->request.status.status_code));
+
+ ippDelete(response);
+ }
+}
+
+
+/*
+ * 'get_line()' - Get a line that is terminated by a LF, CR, or CR LF.
+ */
+
+static char * /* O - Pointer to buf or NULL on EOF */
+get_line(char *buf, /* I - Line buffer */
+ int length, /* I - Length of buffer */
+ FILE *fp) /* I - File to read from */
+{
+ char *bufptr; /* Pointer into buffer */
+ int ch; /* Character from file */
+
+
+ length --;
+ bufptr = buf;
+
+ while ((ch = getc(fp)) != EOF)
+ {
+ if (ch == '\n')
+ break;
+ else if (ch == '\r')
+ {
+ /*
+ * Look for LF...
+ */
+
+ ch = getc(fp);
+ if (ch != '\n' && ch != EOF)
+ ungetc(ch, fp);
+
+ break;
+ }
+
+ *bufptr++ = ch;
+ length --;
+ if (length == 0)
+ break;
+ }
+
+ *bufptr = '\0';
+
+ if (ch == EOF)
+ return (NULL);
+ else
+ return (buf);
+}
+
+
+/*
+ * 'set_printer_device()' - Set the device-uri attribute.
+ */
+
+static void
+set_printer_device(http_t *http, /* I - Server connection */
+ char *printer, /* I - Printer */
+ char *device) /* I - New device URI */
+{
+ ipp_t *request, /* IPP Request */
+ *response; /* IPP Response */
+ cups_lang_t *language; /* Default language */
+ char uri[HTTP_MAX_URI]; /* URI for printer/class */
+
+
+ DEBUG_printf(("set_printer_device(%p, \"%s\", \"%s\")\n", http, printer,
+ device));
+
+ /*
+ * Build a CUPS_ADD_PRINTER request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ */
+
+ snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", printer);
+
+ request = ippNew();
+
+ request->request.op.operation_id = CUPS_ADD_PRINTER;
+ request->request.op.request_id = 1;
+
+ language = cupsLangDefault();
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, cupsLangEncoding(language));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, uri);
+
+ /*
+ * Add the device URI...
+ */
+
+ if (device[0] == '/')
+ {
+ /*
+ * Convert filename to URI...
+ */
+
+ snprintf(uri, sizeof(uri), "file:%s", device);
+ ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL,
+ uri);
+ }
+ else
+ ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL,
+ device);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/admin/")) == NULL)
+ fprintf(stderr, "lpadmin: add-printer failed: %s\n",
+ ippErrorString(cupsLastError()));
+ else
+ {
+ if (response->request.status.status_code > IPP_OK_CONFLICT)
+ fprintf(stderr, "lpadmin: add-printer failed: %s\n",
+ ippErrorString(response->request.status.status_code));
+
+ ippDelete(response);
+ }
+}
+
+
+/*
+ * 'set_printer_file()' - Set the interface script or PPD file.
+ */
+
+static void
+set_printer_file(http_t *http, /* I - Server connection */
+ char *printer, /* I - Printer */
+ char *file) /* I - PPD file or interface script */
+{
+ ipp_t *request, /* IPP Request */
+ *response; /* IPP Response */
+ cups_lang_t *language; /* Default language */
+ char uri[HTTP_MAX_URI]; /* URI for printer/class */
+#ifdef HAVE_LIBZ
+ char tempfile[1024]; /* Temporary filename */
+ int fd; /* Temporary file */
+ gzFile *gz; /* GZIP'd file */
+ char buffer[8192]; /* Copy buffer */
+ int bytes; /* Bytes in buffer */
+
+
+ DEBUG_printf(("set_printer_file(%p, \"%s\", \"%s\")\n", http, printer,
+ file));
+
+ /*
+ * See if the file is gzip'd; if so, unzip it to a temporary file and
+ * send the uncompressed file.
+ */
+
+ if (strcmp(file + strlen(file) - 3, ".gz") == 0)
+ {
+ /*
+ * Yes, the file is compressed; uncompress to a temp file...
+ */
+
+ if ((fd = cupsTempFd(tempfile, sizeof(tempfile))) < 0)
+ {
+ perror("lpadmin: Unable to create temporary file");
+ return;
+ }
+
+ if ((gz = gzopen(file, "rb")) == NULL)
+ {
+ perror("lpadmin: Unable to open file");
+ close(fd);
+ unlink(tempfile);
+ return;
+ }
+
+ while ((bytes = gzread(gz, buffer, sizeof(buffer))) > 0)
+ write(fd, buffer, bytes);
+
+ close(fd);
+ gzclose(gz);
+
+ file = tempfile;
+ }
+#endif /* HAVE_LIBZ */
+
+ /*
+ * Build a CUPS_ADD_PRINTER request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ */
+
+ snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", printer);
+
+ request = ippNew();
+
+ request->request.op.operation_id = CUPS_ADD_PRINTER;
+ request->request.op.request_id = 1;
+
+ language = cupsLangDefault();
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, cupsLangEncoding(language));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, uri);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoFileRequest(http, request, "/admin/", file)) == NULL)
+ fprintf(stderr, "lpadmin: add-printer failed: %s\n",
+ ippErrorString(cupsLastError()));
+ else
+ {
+ if (response->request.status.status_code > IPP_OK_CONFLICT)
+ fprintf(stderr, "lpadmin: add-printer failed: %s\n",
+ ippErrorString(response->request.status.status_code));
+
+ ippDelete(response);
+ }
+
+#ifdef HAVE_LIBZ
+ /*
+ * Remove the temporary file as needed...
+ */
+
+ if (file == tempfile)
+ unlink(tempfile);
+#endif /* HAVE_LIBZ */
+}
+
+
+/*
+ * 'set_printer_info()' - Set the printer description string.
+ */
+
+static void
+set_printer_info(http_t *http, /* I - Server connection */
+ char *printer, /* I - Printer */
+ char *info) /* I - New description string */
+{
+ ipp_t *request, /* IPP Request */
+ *response; /* IPP Response */
+ cups_lang_t *language; /* Default language */
+ char uri[HTTP_MAX_URI]; /* URI for printer/class */
+
+
+ DEBUG_printf(("set_printer_info(%p, \"%s\", \"%s\")\n", http, printer,
+ info));
+
+ /*
+ * Build a CUPS_ADD_PRINTER request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ */
+
+ snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", printer);
+
+ request = ippNew();
+
+ request->request.op.operation_id = CUPS_ADD_PRINTER;
+ request->request.op.request_id = 1;
+
+ language = cupsLangDefault();
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, cupsLangEncoding(language));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, uri);
+
+ /*
+ * Add the info string...
+ */
+
+ ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info", NULL,
+ info);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/admin/")) == NULL)
+ fprintf(stderr, "lpadmin: add-printer failed: %s\n",
+ ippErrorString(cupsLastError()));
+ else
+ {
+ if (response->request.status.status_code > IPP_OK_CONFLICT)
+ fprintf(stderr, "lpadmin: add-printer failed: %s\n",
+ ippErrorString(response->request.status.status_code));
+
+ ippDelete(response);
+ }
+}
+
+
+/*
+ * 'set_printer_location()' - Set the printer location string.
+ */
+
+static void
+set_printer_location(http_t *http, /* I - Server connection */
+ char *printer, /* I - Printer */
+ char *location) /* I - New location string */
+{
+ ipp_t *request, /* IPP Request */
+ *response; /* IPP Response */
+ cups_lang_t *language; /* Default language */
+ char uri[HTTP_MAX_URI]; /* URI for printer/class */
+
+
+ DEBUG_printf(("set_printer_location(%p, \"%s\", \"%s\")\n", http, printer,
+ location));
+
+ /*
+ * Build a CUPS_ADD_PRINTER request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ */
+
+ snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", printer);
+
+ request = ippNew();
+
+ request->request.op.operation_id = CUPS_ADD_PRINTER;
+ request->request.op.request_id = 1;
+
+ language = cupsLangDefault();
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, cupsLangEncoding(language));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, uri);
+
+ /*
+ * Add the location string...
+ */
+
+ ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location", NULL,
+ location);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/admin/")) == NULL)
+ fprintf(stderr, "lpadmin: add-printer failed: %s\n",
+ ippErrorString(cupsLastError()));
+ else
+ {
+ if (response->request.status.status_code > IPP_OK_CONFLICT)
+ fprintf(stderr, "lpadmin: add-printer failed: %s\n",
+ ippErrorString(response->request.status.status_code));
+
+ ippDelete(response);
+ }
+}
+
+
+/*
+ * 'set_printer_model()' - Set the driver model file.
+ */
+
+static void
+set_printer_model(http_t *http, /* I - Server connection */
+ char *printer, /* I - Printer */
+ char *model) /* I - Driver model file */
+{
+ ipp_t *request, /* IPP Request */
+ *response; /* IPP Response */
+ cups_lang_t *language; /* Default language */
+ char uri[HTTP_MAX_URI]; /* URI for printer/class */
+
+
+ /*
+ * Build a CUPS_ADD_PRINTER request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * ppd-name
+ */
+
+ snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", printer);
+
+ request = ippNew();
+
+ request->request.op.operation_id = CUPS_ADD_PRINTER;
+ request->request.op.request_id = 1;
+
+ language = cupsLangDefault();
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, cupsLangEncoding(language));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, uri);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "ppd-name", NULL, model);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/admin/")) == NULL)
+ fprintf(stderr, "lpadmin: add-printer failed: %s\n",
+ ippErrorString(cupsLastError()));
+ else
+ {
+ if (response->request.status.status_code > IPP_OK_CONFLICT)
+ fprintf(stderr, "lpadmin: add-printer failed: %s\n",
+ ippErrorString(response->request.status.status_code));
+
+ ippDelete(response);
+ }
+}
+
+
+/*
+ * 'set_printer_options()' - Set the printer options.
+ */
+
+static void
+set_printer_options(http_t *http, /* I - Server connection */
+ char *printer, /* I - Printer */
+ int num_options, /* I - Number of options */
+ cups_option_t *options) /* I - Options */
+{
+ ipp_t *request, /* IPP Request */
+ *response; /* IPP Response */
+ ipp_attribute_t *attr; /* IPP attribute */
+ cups_lang_t *language; /* Default language */
+ ipp_op_t op; /* Operation to perform */
+ const char *val, /* Option value */
+ *ppdfile; /* PPD filename */
+ char uri[HTTP_MAX_URI], /* URI for printer/class */
+ line[1024], /* Line from PPD file */
+ keyword[1024], /* Keyword from Default line */
+ *keyptr, /* Pointer into keyword... */
+ tempfile[1024]; /* Temporary filename */
+ FILE *in, /* PPD file */
+ *out; /* Temporary file */
+ int outfd; /* Temporary file descriptor */
+
+
+ DEBUG_printf(("set_printer_options(%p, \"%s\", %d, %p)\n", http, printer,
+ num_options, options));
+
+ language = cupsLangDefault();
+
+ snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", printer);
+
+ /*
+ * Build a GET_PRINTER_ATTRIBUTES request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * requested-attributes
+ */
+
+ 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);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, uri);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes", NULL, "printer-type");
+
+ /*
+ * Do the request...
+ */
+
+ op = CUPS_ADD_PRINTER;
+
+ if ((response = cupsDoRequest(http, request, "/")) != NULL)
+ {
+ /*
+ * See what kind of printer or class it is...
+ */
+
+ if ((attr = ippFindAttribute(response, "printer-type", IPP_TAG_ENUM)) != NULL)
+ {
+ if (attr->values[0].integer & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))
+ op = CUPS_ADD_CLASS;
+ }
+
+ ippDelete(response);
+ }
+
+ /*
+ * Build a CUPS_ADD_PRINTER or CUPS_ADD_CLASS request, which requires
+ * the following attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * other options
+ */
+
+ 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);
+
+ /*
+ * Add the options...
+ */
+
+ cupsEncodeOptions(request, num_options, options);
+
+ if (op == CUPS_ADD_PRINTER)
+ ppdfile = cupsGetPPD(printer);
+ else
+ ppdfile = NULL;
+
+ if (ppdfile != NULL)
+ {
+ /*
+ * Set default options in the PPD file...
+ */
+
+ outfd = cupsTempFd(tempfile, sizeof(tempfile));
+
+ in = fopen(ppdfile, "rb");
+ out = fdopen(outfd, "wb");
+
+ while (get_line(line, sizeof(line), in) != NULL)
+ {
+ if (strncmp(line, "*Default", 8) != 0)
+ fprintf(out, "%s\n", line);
+ else
+ {
+ /*
+ * Get default option name...
+ */
+
+ strncpy(keyword, line + 8, sizeof(keyword) - 1);
+ keyword[sizeof(keyword) - 1] = '\0';
+
+ for (keyptr = keyword; *keyptr; keyptr ++)
+ if (*keyptr == ':' || isspace(*keyptr))
+ break;
+
+ *keyptr = '\0';
+
+ if (strcmp(keyword, "PageRegion") == 0)
+ val = cupsGetOption("PageSize", num_options, options);
+ else
+ val = cupsGetOption(keyword, num_options, options);
+
+ if (val != NULL)
+ fprintf(out, "*Default%s: %s\n", keyword, val);
+ else
+ fprintf(out, "%s\n", line);
+ }
+ }
+
+ fclose(in);
+ fclose(out);
+ close(outfd);
+
+ /*
+ * Do the request...
+ */
+
+ response = cupsDoFileRequest(http, request, "/admin/", tempfile);
+
+ /*
+ * Clean up temp files... (TODO: catch signals in case we CTRL-C during
+ * lpadmin)
+ */
+
+ unlink(ppdfile);
+ unlink(tempfile);
+ }
+ else
+ {
+ /*
+ * No PPD file - just set the options...
+ */
+
+ response = cupsDoRequest(http, request, "/admin/");
+ }
+
+ /*
+ * Check the response...
+ */
+
+ if (response == NULL)
+ fprintf(stderr, "lpadmin: %s failed: %s\n",
+ op == CUPS_ADD_PRINTER ? "add-printer" : "add-class",
+ ippErrorString(cupsLastError()));
+ else
+ {
+ if (response->request.status.status_code > IPP_OK_CONFLICT)
+ fprintf(stderr, "lpadmin: %s failed: %s\n",
+ op == CUPS_ADD_PRINTER ? "add-printer" : "add-class",
+ ippErrorString(response->request.status.status_code));
+
+ ippDelete(response);
+ }
+}
+
+
+/*
+ * 'validate_name()' - Make sure the printer name only contains letters,
+ * numbers, and the underscore...
+ */
+
+static int /* O - 0 if name is no good, 1 if name is good */
+validate_name(const char *name) /* I - Name to check */
+{
+ /*
+ * Don't allow names to start with a digit...
+ */
+
+ if (isdigit(*name))
+ return (0);
+
+ /*
+ * Scan the whole name...
+ */
+
+ while (*name)
+ if (*name == '@')
+ return (1);
+ else if (!isalnum(*name) && *name != '_')
+ return (0);
+ else
+ name ++;
+
+ return (1);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/systemv/lpinfo.c b/systemv/lpinfo.c
new file mode 100644
index 000000000..5acbfad92
--- /dev/null
+++ b/systemv/lpinfo.c
@@ -0,0 +1,457 @@
+/*
+ * "$Id$"
+ *
+ * "lpinfo" command for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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 show information.
+ * show_devices() - Show available devices.
+ * show_models() - Show available PPDs.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <cups/cups.h>
+#include <cups/language.h>
+#include <cups/debug.h>
+#include <cups/string.h>
+
+
+/*
+ * Local functions...
+ */
+
+static int show_devices(http_t *, int);
+static int show_models(http_t *, int);
+
+
+/*
+ * 'main()' - Parse options and show status information.
+ */
+
+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 */
+ int long_status; /* Long listing? */
+ http_encryption_t encryption; /* Encryption? */
+
+
+ http = NULL;
+ long_status = 0;
+ encryption = cupsEncryption();
+
+ for (i = 1; i < argc; i ++)
+ if (argv[i][0] == '-')
+ switch (argv[i][1])
+ {
+ case 'E' : /* Encrypt */
+#ifdef HAVE_LIBSSL
+ encryption = HTTP_ENCRYPT_REQUIRED;
+
+ if (http)
+ httpEncryption(http, encryption);
+#else
+ fprintf(stderr, "%s: Sorry, no encryption support compiled in!\n",
+ argv[0]);
+#endif /* HAVE_LIBSSL */
+ break;
+
+ case 'l' : /* Show long listing */
+ long_status = 1;
+ break;
+
+ case 'm' : /* Show models */
+ if (!http)
+ {
+ http = httpConnectEncrypt(cupsServer(), ippPort(), encryption);
+
+ if (http == NULL)
+ {
+ perror("lpinfo: Unable to connect to server");
+ return (1);
+ }
+ }
+
+ if (show_models(http, long_status))
+ return (1);
+ break;
+
+ case 'v' : /* Show available devices */
+ if (!http)
+ {
+ http = httpConnectEncrypt(cupsServer(), ippPort(), encryption);
+
+ if (http == NULL)
+ {
+ perror("lpinfo: Unable to connect to server");
+ return (1);
+ }
+ }
+
+ if (show_devices(http, long_status))
+ return (1);
+ break;
+
+ case 'h' : /* Connect to host */
+ if (http)
+ httpClose(http);
+
+ if (argv[i][2] != '\0')
+ http = httpConnectEncrypt(argv[i] + 2, ippPort(), encryption);
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ fputs("Error: need hostname after \'-h\' option!\n", stderr);
+ return (1);
+ }
+
+ http = httpConnectEncrypt(argv[i], ippPort(), encryption);
+ }
+
+ if (http == NULL)
+ {
+ perror("lpinfo: Unable to connect to server");
+ return (1);
+ }
+ break;
+
+ default :
+ fprintf(stderr, "lpinfo: Unknown option \'%c\'!\n", argv[i][1]);
+ return (1);
+ }
+ else
+ {
+ fprintf(stderr, "lpinfo: Unknown argument \'%s\'!\n", argv[i]);
+ return (1);
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'show_devices()' - Show available devices.
+ */
+
+static int /* O - 0 on success, 1 on failure */
+show_devices(http_t *http, /* I - HTTP connection to server */
+ int long_status)/* I - Long status report? */
+{
+ ipp_t *request, /* IPP Request */
+ *response; /* IPP Response */
+ ipp_attribute_t *attr; /* Current attribute */
+ cups_lang_t *language; /* Default language */
+ const char *device_class, /* Pointer into device-class */
+ *device_info, /* Pointer into device-info */
+ *device_make, /* Pointer into device-make-and-model */
+ *device_uri; /* Pointer into device-uri */
+
+
+ if (http == NULL)
+ return (1);
+
+ /*
+ * 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;
+
+ language = cupsLangDefault();
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, cupsLangEncoding(language));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, "ipp://localhost/printers/");
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/")) != NULL)
+ {
+ /*
+ * Loop through the device list and display them...
+ */
+
+ if (response->request.status.status_code > IPP_OK_CONFLICT)
+ {
+ fprintf(stderr, "lpinfo: cups-get-devices failed: %s\n",
+ ippErrorString(response->request.status.status_code));
+ ippDelete(response);
+ return (1);
+ }
+
+ for (attr = response->attrs; attr != NULL; attr = attr->next)
+ {
+ /*
+ * Skip leading attributes until we hit a device...
+ */
+
+ while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
+ attr = attr->next;
+
+ if (attr == NULL)
+ break;
+
+ /*
+ * Pull the needed attributes from this device...
+ */
+
+ device_class = NULL;
+ device_info = NULL;
+ device_make = NULL;
+ device_uri = NULL;
+
+ while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
+ {
+ if (strcmp(attr->name, "device-class") == 0 &&
+ attr->value_tag == IPP_TAG_KEYWORD)
+ device_class = attr->values[0].string.text;
+
+ if (strcmp(attr->name, "device-info") == 0 &&
+ attr->value_tag == IPP_TAG_TEXT)
+ device_info = attr->values[0].string.text;
+
+ if (strcmp(attr->name, "device-make-and-model") == 0 &&
+ attr->value_tag == IPP_TAG_TEXT)
+ device_make = attr->values[0].string.text;
+
+ if (strcmp(attr->name, "device-uri") == 0 &&
+ attr->value_tag == IPP_TAG_URI)
+ device_uri = attr->values[0].string.text;
+
+ attr = attr->next;
+ }
+
+ /*
+ * See if we have everything needed...
+ */
+
+ if (device_class == NULL || device_info == NULL ||
+ device_make == NULL || device_uri == NULL)
+ {
+ if (attr == NULL)
+ break;
+ else
+ continue;
+ }
+
+ /*
+ * Display the device...
+ */
+
+ if (long_status)
+ {
+ printf("Device: uri = %s\n", device_uri);
+ printf(" class = %s\n", device_class);
+ printf(" info = %s\n", device_info);
+ printf(" make-and-model = %s\n", device_make);
+ }
+ else
+ printf("%s %s\n", device_class, device_uri);
+
+ if (attr == NULL)
+ break;
+ }
+
+ ippDelete(response);
+ }
+ else
+ {
+ fprintf(stderr, "lpinfo: cups-get-devices failed: %s\n",
+ ippErrorString(cupsLastError()));
+ return (1);
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'show_models()' - Show available PPDs.
+ */
+
+static int /* O - 0 on success, 1 on failure */
+show_models(http_t *http, /* I - HTTP connection to server */
+ int long_status) /* I - Long status report? */
+{
+ ipp_t *request, /* IPP Request */
+ *response; /* IPP Response */
+ ipp_attribute_t *attr; /* Current attribute */
+ cups_lang_t *language; /* Default language */
+ const char *ppd_language, /* Pointer into ppd-natural-language */
+ *ppd_make, /* Pointer into ppd-make-and-model */
+ *ppd_name; /* Pointer into ppd-name */
+
+
+ if (http == NULL)
+ return (1);
+
+ /*
+ * 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;
+
+ language = cupsLangDefault();
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, cupsLangEncoding(language));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, "ipp://localhost/printers/");
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/")) != NULL)
+ {
+ /*
+ * Loop through the device list and display them...
+ */
+
+ if (response->request.status.status_code > IPP_OK_CONFLICT)
+ {
+ fprintf(stderr, "lpinfo: cups-get-ppds failed: %s\n",
+ ippErrorString(response->request.status.status_code));
+ ippDelete(response);
+ return (1);
+ }
+
+ for (attr = response->attrs; attr != NULL; attr = attr->next)
+ {
+ /*
+ * Skip leading attributes until we hit a PPD...
+ */
+
+ while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
+ attr = attr->next;
+
+ if (attr == NULL)
+ break;
+
+ /*
+ * Pull the needed attributes from this PPD...
+ */
+
+ ppd_language = NULL;
+ ppd_make = NULL;
+ ppd_name = NULL;
+
+ while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
+ {
+ if (strcmp(attr->name, "ppd-natural-language") == 0 &&
+ attr->value_tag == IPP_TAG_LANGUAGE)
+ ppd_language = attr->values[0].string.text;
+
+ if (strcmp(attr->name, "ppd-make-and-model") == 0 &&
+ attr->value_tag == IPP_TAG_TEXT)
+ ppd_make = attr->values[0].string.text;
+
+ if (strcmp(attr->name, "ppd-name") == 0 &&
+ attr->value_tag == IPP_TAG_NAME)
+ ppd_name = attr->values[0].string.text;
+
+ attr = attr->next;
+ }
+
+ /*
+ * See if we have everything needed...
+ */
+
+ if (ppd_language == NULL || ppd_make == NULL || ppd_name == NULL)
+ {
+ if (attr == NULL)
+ break;
+ else
+ continue;
+ }
+
+ /*
+ * Display the device...
+ */
+
+ if (long_status)
+ {
+ printf("Model: name = %s\n", ppd_name);
+ printf(" natural_language = %s\n", ppd_language);
+ printf(" make-and-model = %s\n", ppd_make);
+ }
+ else
+ printf("%s %s\n", ppd_name, ppd_make);
+
+ if (attr == NULL)
+ break;
+ }
+
+ ippDelete(response);
+ }
+ else
+ {
+ fprintf(stderr, "lpinfo: cups-get-ppds failed: %s\n",
+ ippErrorString(cupsLastError()));
+
+ return (1);
+ }
+
+ return (0);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/systemv/lpmove.c b/systemv/lpmove.c
new file mode 100644
index 000000000..24cd49c5f
--- /dev/null
+++ b/systemv/lpmove.c
@@ -0,0 +1,232 @@
+/*
+ * "$Id$"
+ *
+ * "lpmove" command for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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 move jobs.
+ * move_job() - Move a job.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <cups/cups.h>
+#include <cups/language.h>
+#include <cups/debug.h>
+#include <cups/string.h>
+
+
+/*
+ * Local functions...
+ */
+
+static void move_job(http_t *, int, const char *);
+
+
+/*
+ * 'main()' - Parse options and show status information.
+ */
+
+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 *job; /* Job name */
+ const char *dest; /* New destination */
+ http_encryption_t encryption; /* Encryption? */
+
+
+ http = NULL;
+ job = NULL;
+ dest = NULL;
+ encryption = cupsEncryption();
+
+ for (i = 1; i < argc; i ++)
+ if (argv[i][0] == '-')
+ switch (argv[i][1])
+ {
+ case 'E' : /* Encrypt */
+#ifdef HAVE_LIBSSL
+ encryption = HTTP_ENCRYPT_REQUIRED;
+
+ if (http)
+ httpEncryption(http, encryption);
+#else
+ fprintf(stderr, "%s: Sorry, no encryption support compiled in!\n",
+ argv[0]);
+#endif /* HAVE_LIBSSL */
+ break;
+
+ case 'h' : /* Connect to host */
+ if (http)
+ httpClose(http);
+
+ if (argv[i][2] != '\0')
+ http = httpConnectEncrypt(argv[i] + 2, ippPort(), encryption);
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ fputs("Error: need hostname after \'-h\' option!\n", stderr);
+ return (1);
+ }
+
+ http = httpConnectEncrypt(argv[i], ippPort(), encryption);
+ }
+
+ if (http == NULL)
+ {
+ perror("lpmove: Unable to connect to server");
+ return (1);
+ }
+ break;
+
+ default :
+ fprintf(stderr, "lpmove: Unknown option \'%c\'!\n", argv[i][1]);
+ return (1);
+ }
+ else if (job == NULL)
+ {
+ if ((job = strrchr(argv[i], '-')) != NULL)
+ job ++;
+ else
+ job = argv[i];
+ }
+ else if (dest == NULL)
+ dest = argv[i];
+ else
+ {
+ fprintf(stderr, "lpmove: Unknown argument \'%s\'!\n", argv[i]);
+ return (1);
+ }
+
+ if (job == NULL || dest == NULL)
+ {
+ puts("Usage: lpmove job dest");
+ return (1);
+ }
+
+ if (!http)
+ {
+ http = httpConnectEncrypt(cupsServer(), ippPort(), encryption);
+
+ if (http == NULL)
+ {
+ perror("lpmove: Unable to connect to server");
+ return (1);
+ }
+ }
+
+ move_job(http, atoi(job), dest);
+
+ return (0);
+}
+
+
+/*
+ * 'move_job()' - Move a job.
+ */
+
+static void
+move_job(http_t *http, /* I - HTTP connection to server */
+ int jobid, /* I - Job ID */
+ const char *dest) /* I - Destination */
+{
+ ipp_t *request, /* IPP Request */
+ *response; /* IPP Response */
+ cups_lang_t *language; /* Default language */
+ char job_uri[HTTP_MAX_URI],
+ /* job-uri */
+ printer_uri[HTTP_MAX_URI];
+ /* job-printer-uri */
+
+
+ if (http == NULL)
+ return;
+
+ /*
+ * Build a CUPS_MOVE_JOB request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * job-uri
+ * job-printer-uri
+ */
+
+ request = ippNew();
+
+ request->request.op.operation_id = CUPS_MOVE_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->language);
+
+ snprintf(job_uri, sizeof(job_uri), "ipp://localhost/jobs/%d", jobid);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, job_uri);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, cupsUser());
+
+ snprintf(printer_uri, sizeof(printer_uri), "ipp://localhost/printers/%s", dest);
+ ippAddString(request, IPP_TAG_JOB, IPP_TAG_URI, "job-printer-uri",
+ NULL, printer_uri);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/jobs")) != NULL)
+ {
+ if (response->request.status.status_code > IPP_OK_CONFLICT)
+ {
+ fprintf(stderr, "lpmove: move-job failed: %s\n",
+ ippErrorString(response->request.status.status_code));
+ ippDelete(response);
+ return;
+ }
+
+ ippDelete(response);
+ }
+ else
+ fprintf(stderr, "lpmove: move-job failed: %s\n",
+ ippErrorString(cupsLastError()));
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/systemv/lpoptions.c b/systemv/lpoptions.c
new file mode 100644
index 000000000..7335e1368
--- /dev/null
+++ b/systemv/lpoptions.c
@@ -0,0 +1,427 @@
+/*
+ * "$Id$"
+ *
+ * Printer option program for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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.
+ * list_group() - List printer-specific options from the PPD group.
+ * list_options() - List printer-specific options from the PPD file.
+ * usage() - Show program usage and exit.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups.h>
+#include <stdlib.h>
+
+
+/*
+ * Local functions...
+ */
+
+void list_group(ppd_group_t *group);
+void list_options(cups_dest_t *dest);
+void usage(void);
+
+
+/*
+ * 'main()' - Main entry.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i, j; /* Looping vars */
+ int changes; /* Did we make changes? */
+ int num_options; /* Number of options */
+ cups_option_t *options; /* Options */
+ int num_dests; /* Number of destinations */
+ cups_dest_t *dests; /* Destinations */
+ cups_dest_t *dest; /* Current destination */
+ char *printer, /* Printer name */
+ *instance, /* Instance name */
+ *option; /* Current option */
+
+
+ /*
+ * Loop through the command-line arguments...
+ */
+
+ dest = NULL;
+ num_dests = 0;
+ dests = NULL;
+ num_options = 0;
+ options = NULL;
+ changes = 0;
+
+ for (i = 1; i < argc; i ++)
+ if (argv[i][0] == '-')
+ {
+ switch (argv[i][1])
+ {
+ case 'd' : /* -d printer */
+ if (argv[i][2])
+ printer = argv[i] + 2;
+ else
+ {
+ i ++;
+ if (i >= argc)
+ usage();
+
+ printer = argv[i];
+ }
+
+ if ((instance = strrchr(printer, '/')) != NULL)
+ *instance++ = '\0';
+
+ if (num_dests == 0)
+ num_dests = cupsGetDests(&dests);
+
+ if ((dest = cupsGetDest(printer, instance, num_dests, dests)) == NULL)
+ {
+ fputs("lpoptions: Unknown printer or class!\n", stderr);
+ return (1);
+ }
+
+ /*
+ * Set the default destination...
+ */
+
+ for (j = 0; j < num_dests; j ++)
+ dests[j].is_default = 0;
+
+ dest->is_default = 1;
+
+ cupsSetDests(num_dests, dests);
+
+ for (j = 0; j < dest->num_options; j ++)
+ num_options = cupsAddOption(dest->options[j].name,
+ dest->options[j].value,
+ num_options, &options);
+ break;
+
+ case 'h' : /* -h server */
+ if (argv[i][2])
+ cupsSetServer(argv[i] + 2);
+ else
+ {
+ i ++;
+ if (i >= argc)
+ usage();
+
+ cupsSetServer(argv[i]);
+ }
+ break;
+
+ case 'l' : /* -l (list options) */
+ if (dest == NULL)
+ {
+ if (num_dests == 0)
+ num_dests = cupsGetDests(&dests);
+
+ for (i = num_dests, dest = dests; i > 0; i --, dest ++)
+ if (dest->is_default)
+ break;
+
+ if (i == 0)
+ dest = dests;
+ }
+
+ if (dest == NULL)
+ fputs("lpoptions: No printers!?!\n", stderr);
+ else
+ list_options(dest);
+
+ changes = -1;
+ break;
+
+ case 'o' : /* -o option[=value] */
+ if (argv[i][2])
+ num_options = cupsParseOptions(argv[i] + 2, num_options, &options);
+ else
+ {
+ i ++;
+ if (i >= argc)
+ usage();
+
+ num_options = cupsParseOptions(argv[i], num_options, &options);
+ }
+
+ changes = 1;
+ break;
+
+ case 'p' : /* -p printer */
+ if (argv[i][2])
+ printer = argv[i] + 2;
+ else
+ {
+ i ++;
+ if (i >= argc)
+ usage();
+
+ printer = argv[i];
+ }
+
+ if ((instance = strrchr(printer, '/')) != NULL)
+ *instance++ = '\0';
+
+ if (num_dests == 0)
+ num_dests = cupsGetDests(&dests);
+
+ if ((dest = cupsGetDest(printer, instance, num_dests, dests)) == NULL)
+ {
+ num_dests = cupsAddDest(printer, instance, num_dests, &dests);
+ dest = cupsGetDest(printer, instance, num_dests, dests);
+
+ if (dest == NULL)
+ {
+ perror("lpoptions: Unable to add printer or instance");
+ return (1);
+ }
+ }
+
+ for (j = 0; j < dest->num_options; j ++)
+ num_options = cupsAddOption(dest->options[j].name,
+ dest->options[j].value,
+ num_options, &options);
+ break;
+
+ case 'r' : /* -r option (remove) */
+ if (argv[i][2])
+ option = argv[i] + 2;
+ else
+ {
+ i ++;
+ if (i >= argc)
+ usage();
+
+ option = argv[i];
+ }
+
+ for (j = 0; j < num_options; j ++)
+ if (strcasecmp(options[j].name, option) == 0)
+ {
+ /*
+ * Remove this option...
+ */
+
+ num_options --;
+
+ if (j < num_options)
+ memcpy(options + j, options + j + 1,
+ sizeof(cups_option_t) * (num_options - j));
+ break;
+ }
+
+ changes = 1;
+ break;
+
+ case 'x' : /* -x printer */
+ if (argv[i][2])
+ printer = argv[i] + 2;
+ else
+ {
+ i ++;
+ if (i >= argc)
+ usage();
+
+ printer = argv[i];
+ }
+
+ if ((instance = strrchr(printer, '/')) != NULL)
+ *instance++ = '\0';
+
+ if (num_dests == 0)
+ num_dests = cupsGetDests(&dests);
+
+ if ((dest = cupsGetDest(printer, instance, num_dests, dests)) == NULL)
+ {
+ if (instance)
+ fprintf(stderr, "lpoptions: No such printer/instance: %s/%s\n",
+ printer, instance);
+ else
+ fprintf(stderr, "lpoptions: No such printer: %s\n", printer);
+
+ return (1);
+ }
+
+ cupsFreeOptions(dest->num_options, dest->options);
+ num_dests --;
+
+ j = dest - dests;
+ if (j < num_dests)
+ memcpy(dest, dest + 1, (num_dests - j) * sizeof(cups_dest_t));
+
+ cupsSetDests(num_dests, dests);
+ dest = NULL;
+ break;
+
+ default :
+ usage();
+ }
+ }
+ else
+ usage();
+
+ if (num_dests == 0)
+ num_dests = cupsGetDests(&dests);
+
+ if (dest == NULL)
+ for (i = 0; i < num_dests; i ++)
+ if (dests[i].is_default)
+ {
+ dest = dests + i;
+ break;
+ }
+
+ if (dest == NULL)
+ return (0);
+
+ if (changes > 0)
+ {
+ /*
+ * Set printer options...
+ */
+
+ cupsFreeOptions(dest->num_options, dest->options);
+
+ dest->num_options = num_options;
+ dest->options = options;
+
+ cupsSetDests(num_dests, dests);
+ }
+ else if (changes == 0)
+ {
+ num_options = dest->num_options;
+ options = dest->options;
+
+ for (i = 0; i < num_options; i ++)
+ {
+ if (i)
+ putchar(' ');
+
+ if (!options[i].value[0])
+ printf("%s", options[i].name);
+ else if (strchr(options[i].value, ' ') != NULL ||
+ strchr(options[i].value, '\t') != NULL)
+ printf("%s=\'%s\'", options[i].name, options[i].value);
+ else
+ printf("%s=%s", options[i].name, options[i].value);
+ }
+
+ putchar('\n');
+ }
+
+ return (0);
+}
+
+/*
+ * 'list_group()' - List printer-specific options from the PPD group.
+ */
+
+void
+list_group(ppd_group_t *group) /* I - Group to show */
+{
+ int i, j; /* Looping vars */
+ ppd_option_t *option; /* Current option */
+ ppd_choice_t *choice; /* Current choice */
+ ppd_group_t *subgroup; /* Current subgroup */
+
+
+ for (i = group->num_options, option = group->options; i > 0; i --, option ++)
+ {
+ printf("%s/%s:", option->keyword, option->text);
+
+ for (j = option->num_choices, choice = option->choices; j > 0; j --, choice ++)
+ if (choice->marked)
+ printf(" *%s", choice->choice);
+ else
+ printf(" %s", choice->choice);
+
+ putchar('\n');
+ }
+
+ for (i = group->num_subgroups, subgroup = group->subgroups; i > 0; i --, subgroup ++)
+ list_group(subgroup);
+}
+
+
+/*
+ * 'list_options()' - List printer-specific options from the PPD file.
+ */
+
+void
+list_options(cups_dest_t *dest) /* I - Destination to list */
+{
+ int i; /* Looping var */
+ const char *filename; /* PPD filename */
+ ppd_file_t *ppd; /* PPD data */
+ ppd_group_t *group; /* Current group */
+
+
+ if ((filename = cupsGetPPD(dest->name)) == NULL)
+ {
+ fprintf(stderr, "lpoptions: Destination %s has no PPD file!\n", dest->name);
+ return;
+ }
+
+ if ((ppd = ppdOpenFile(filename)) == NULL)
+ {
+ unlink(filename);
+ fprintf(stderr, "lpoptions: Unable to open PPD file for %s!\n", dest->name);
+ return;
+ }
+
+ ppdMarkDefaults(ppd);
+ cupsMarkOptions(ppd, dest->num_options, dest->options);
+
+ for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
+ list_group(group);
+
+ ppdClose(ppd);
+ unlink(filename);
+}
+
+
+/*
+ * 'usage()' - Show program usage and exit.
+ */
+
+void
+usage(void)
+{
+ puts("Usage: lpoptions -d printer");
+ puts(" lpoptions [-p printer] -l");
+ puts(" lpoptions -p printer -o option[=value] ...");
+ puts(" lpoptions -x printer");
+
+ exit(1);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/systemv/lppasswd.c b/systemv/lppasswd.c
new file mode 100644
index 000000000..3361f1cc9
--- /dev/null
+++ b/systemv/lppasswd.c
@@ -0,0 +1,405 @@
+/*
+ * "$Id$"
+ *
+ * MD5 password program for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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() - Add, change, or delete passwords from the MD5 password file.
+ * usage() - Show program usage.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <cups/cups.h>
+#include <cups/md5.h>
+#include <cups/string.h>
+
+
+/*
+ * Operations...
+ */
+
+#define ADD 0
+#define CHANGE 1
+#define DELETE 2
+
+
+/*
+ * Local functions...
+ */
+
+static void usage(FILE *fp);
+
+
+/*
+ * 'main()' - Add, change, or delete passwords from the MD5 password file.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i; /* Looping var */
+ char *opt; /* Option pointer */
+ const char *username; /* Pointer to username */
+ const char *groupname; /* Pointer to group name */
+ int op; /* Operation (add, change, delete) */
+ const char *passwd; /* Password string */
+ FILE *infile, /* Input file */
+ *outfile; /* Output file */
+ char line[256], /* Line from file */
+ userline[17], /* User from line */
+ groupline[17], /* Group from line */
+ md5line[33], /* MD5-sum from line */
+ md5new[33]; /* New MD5 sum */
+ const char *root; /* CUPS server root directory */
+ char passwdmd5[1024],/* passwd.md5 file */
+ passwdold[1024],/* passwd.old file */
+ passwdnew[1024];/* passwd.tmp file */
+ char *newpass, /* new password */
+ *oldpass; /* old password */
+ int flag; /* Password check flags... */
+ int fd; /* Password file descriptor */
+
+
+ /*
+ * Find the server directory...
+ *
+ * Don't use CUPS_SERVERROOT unless we're run by the
+ * super user.
+ */
+
+ if (!getuid() && (root = getenv("CUPS_SERVERROOT")) != NULL)
+ {
+ snprintf(passwdmd5, sizeof(passwdmd5), "%s/passwd.md5", root);
+ snprintf(passwdold, sizeof(passwdold), "%s/passwd.old", root);
+ snprintf(passwdnew, sizeof(passwdnew), "%s/passwd.new", root);
+ }
+ else
+ {
+ strcpy(passwdmd5, CUPS_SERVERROOT "/passwd.md5");
+ strcpy(passwdold, CUPS_SERVERROOT "/passwd.old");
+ strcpy(passwdnew, CUPS_SERVERROOT "/passwd.new");
+ }
+
+ /*
+ * Find the default system group: "sys", "system", or "root"...
+ */
+
+ if (getgrnam("sys"))
+ groupname = "sys";
+ else if (getgrnam("system"))
+ groupname = "system";
+ else if (getgrnam("root"))
+ groupname = "root";
+ else
+ groupname = "unknown";
+
+ endgrent();
+
+ username = NULL;
+ op = CHANGE;
+
+ /*
+ * Parse command-line options...
+ */
+
+ for (i = 1; i < argc; i ++)
+ if (argv[i][0] == '-')
+ for (opt = argv[i] + 1; *opt; opt ++)
+ switch (*opt)
+ {
+ case 'a' : /* Add */
+ op = ADD;
+ break;
+ case 'x' : /* Delete */
+ op = DELETE;
+ break;
+ case 'g' : /* Group */
+ i ++;
+ if (i >= argc)
+ usage(stderr);
+
+ groupname = argv[i];
+ break;
+ case 'h' : /* Help */
+ usage(stdout);
+ break;
+ default : /* Bad option */
+ usage(stderr);
+ break;
+ }
+ else if (!username)
+ username = argv[i];
+ else
+ usage(stderr);
+
+ /*
+ * See if we are trying to add or delete a password when we aren't logged in
+ * as root...
+ */
+
+ if (getuid() && (op != CHANGE || username))
+ {
+ fputs("lppasswd: Only root can add or delete passwords!\n", stderr);
+ return (1);
+ }
+
+ /*
+ * Fill in missing info...
+ */
+
+ if (!username)
+ username = cupsUser();
+
+ oldpass = newpass = NULL;
+
+ /*
+ * Obtain old and new password _before_ locking the database
+ * to keep users from locking the file indefinitely.
+ */
+
+ if (op == CHANGE && getuid())
+ {
+ if ((passwd = cupsGetPassword("Enter old password:")) == NULL)
+ return (1);
+
+ if ((oldpass = strdup(passwd)) == NULL)
+ {
+ perror("lppasswd: Unable to copy password string");
+ return (1);
+ }
+ }
+
+ /*
+ * Now get the new password, if necessary...
+ */
+
+ if (op != DELETE)
+ {
+ if ((passwd = cupsGetPassword("Enter password:")) == NULL)
+ return (1);
+
+ if ((newpass = strdup(passwd)) == NULL)
+ {
+ perror("lppasswd: Unable to copy password string!");
+ return (1);
+ }
+
+ if ((passwd = cupsGetPassword("Enter password again:")) == NULL)
+ return (1);
+
+ if (strcmp(passwd, newpass) != 0)
+ {
+ fputs("lppasswd: Sorry, passwords don't match!\n", stderr);
+ return (1);
+ }
+
+ /*
+ * Check that the password contains at least one letter and number.
+ */
+
+ flag = 0;
+
+ for (passwd = newpass; *passwd; passwd ++)
+ if (isdigit(*passwd))
+ flag |= 1;
+ else if (isalpha(*passwd))
+ flag |= 2;
+
+ /*
+ * Only allow passwords that are at least 6 chars, have a letter and
+ * a number, and don't contain the username.
+ */
+
+ if (strlen(newpass) < 6 || strstr(newpass, username) != NULL || flag != 3)
+ {
+ fputs("lppasswd: Sorry, password rejected.\n"
+ "Your password must be at least 6 characters long, cannot contain\n"
+ "your username, and must contain at least one letter and number.\n",
+ stderr);
+ return (1);
+ }
+ }
+
+ /*
+ * Open the output file.
+ */
+
+ if ((fd = open(passwdnew, O_WRONLY | O_CREAT | O_EXCL, 0400)) < 0)
+ {
+ if (errno == EEXIST)
+ fputs("lppasswd: Password file busy!\n", stderr);
+ else
+ perror("lppasswd: Unable to open passwd file");
+
+ return (1);
+ }
+
+ if ((outfile = fdopen(fd, "w")) == NULL)
+ {
+ perror("lppasswd: Unable to open passwd file");
+
+ unlink(passwdnew);
+
+ return (1);
+ }
+
+ /*
+ * Open the existing password file and create a new one...
+ */
+
+ infile = fopen(passwdmd5, "r");
+ if (infile == NULL && errno != ENOENT && op != ADD)
+ {
+ fputs("lppasswd: No password file to change or delete from!\n", stderr);
+
+ fclose(outfile);
+
+ unlink(passwdnew);
+
+ return (1);
+ }
+
+ /*
+ * Read lines from the password file; the format is:
+ *
+ * username:group:MD5-sum
+ */
+
+ if (infile)
+ {
+ while (fgets(line, sizeof(line), infile) != NULL)
+ {
+ if (sscanf(line, "%16[^:]:%16[^:]:%32s", userline, groupline, md5line) != 3)
+ continue;
+
+ if (strcmp(username, userline) == 0 &&
+ strcmp(groupname, groupline) == 0)
+ break;
+
+ fputs(line, outfile);
+ }
+
+ while (fgets(line, sizeof(line), infile) != NULL)
+ fputs(line, outfile);
+ }
+ else
+ {
+ userline[0] = '\0';
+ groupline[0] = '\0';
+ md5line[0] = '\0';
+ }
+
+ if (op == CHANGE &&
+ (strcmp(username, userline) != 0 ||
+ strcmp(groupname, groupline) != 0))
+ fprintf(stderr, "lppasswd: user \"%s\" and group \"%s\" do not exist.\n",
+ username, groupname);
+ else if (op != DELETE)
+ {
+ if (oldpass &&
+ strcmp(httpMD5(username, "CUPS", oldpass, md5new), md5line) != 0)
+ {
+ fputs("lppasswd: Sorry, password doesn't match!\n", stderr);
+
+ if (infile)
+ fclose(infile);
+
+ fclose(outfile);
+
+ unlink(passwdnew);
+
+ return (1);
+ }
+
+ fprintf(outfile, "%s:%s:%s\n", username, groupname,
+ httpMD5(username, "CUPS", newpass, md5new));
+ }
+
+ /*
+ * Close the files and remove the old password file...
+ */
+
+ if (infile)
+ fclose(infile);
+
+ fclose(outfile);
+
+ /*
+ * Save old passwd file
+ */
+
+ unlink(passwdold);
+ link(passwdmd5, passwdold);
+
+ /*
+ * Install new password file
+ */
+
+ if (rename(passwdnew, passwdmd5) < 0)
+ {
+ perror("lppasswd: failed to rename passwd file");
+ unlink(passwdnew);
+ return (1);
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'usage()' - Show program usage.
+ */
+
+static void
+usage(FILE *fp) /* I - File to send usage to */
+{
+ if (getuid())
+ {
+ fputs("Usage: lppasswd [-g groupname]\n", fp);
+ }
+ else
+ {
+ fputs("Usage: lppasswd [-g groupname] [username]\n", fp);
+ fputs(" lppasswd [-g groupname] -a [username]\n", fp);
+ fputs(" lppasswd [-g groupname] -x [username]\n", fp);
+ }
+
+ exit(1);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/systemv/lpstat.c b/systemv/lpstat.c
new file mode 100644
index 000000000..653e0fec2
--- /dev/null
+++ b/systemv/lpstat.c
@@ -0,0 +1,1924 @@
+/*
+ * "$Id$"
+ *
+ * "lpstat" command for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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 show status information.
+ * show_accepting() - Show acceptance status.
+ * show_classes() - Show printer classes.
+ * show_default() - Show default destination.
+ * show_devices() - Show printer devices.
+ * show_jobs() - Show active print jobs.
+ * show_printers() - Show printers.
+ * show_scheduler() - Show scheduler status.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <cups/cups.h>
+#include <cups/language.h>
+#include <cups/debug.h>
+#include <cups/string.h>
+
+
+/*
+ * Local functions...
+ */
+
+static void show_accepting(http_t *, const char *, int, cups_dest_t *);
+static void show_classes(http_t *, const char *);
+static void show_default(int, cups_dest_t *);
+static void show_devices(http_t *, const char *, int, cups_dest_t *);
+static void show_jobs(http_t *, const char *, const char *, int, int);
+static void show_printers(http_t *, const char *, int, cups_dest_t *, int);
+static void show_scheduler(http_t *);
+
+
+/*
+ * 'main()' - Parse options and show status information.
+ */
+
+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 */
+ int num_dests; /* Number of user destinations */
+ cups_dest_t *dests; /* User destinations */
+ int long_status; /* Long status report? */
+ int ranking; /* Show job ranking? */
+ http_encryption_t encryption; /* Encryption? */
+
+
+ http = NULL;
+ num_dests = 0;
+ dests = NULL;
+ long_status = 0;
+ ranking = 0;
+ encryption = cupsEncryption();
+
+ for (i = 1; i < argc; i ++)
+ if (argv[i][0] == '-')
+ switch (argv[i][1])
+ {
+ case 'D' : /* Show description */
+ long_status = 1;
+ break;
+
+ case 'E' : /* Encrypt */
+#ifdef HAVE_LIBSSL
+ encryption = HTTP_ENCRYPT_REQUIRED;
+
+ if (http)
+ httpEncryption(http, encryption);
+#else
+ fprintf(stderr, "%s: Sorry, no encryption support compiled in!\n",
+ argv[0]);
+#endif /* HAVE_LIBSSL */
+ break;
+
+ case 'P' : /* Show paper types */
+ break;
+
+ case 'R' : /* Show ranking */
+ ranking = 1;
+ break;
+
+ case 'S' : /* Show charsets */
+ if (!argv[i][2])
+ i ++;
+ break;
+
+ case 'a' : /* Show acceptance status */
+ if (!http)
+ {
+ http = httpConnectEncrypt(cupsServer(), ippPort(), encryption);
+
+ if (http == NULL)
+ {
+ perror("lpstat: Unable to connect to server");
+ return (1);
+ }
+ }
+
+ if (num_dests == 0)
+ num_dests = cupsGetDests(&dests);
+
+ if (argv[i][2] != '\0')
+ show_accepting(http, argv[i] + 2, num_dests, dests);
+ else if ((i + 1) < argc && argv[i + 1][0] != '-')
+ {
+ i ++;
+ show_accepting(http, argv[i], num_dests, dests);
+ }
+ else
+ show_accepting(http, NULL, num_dests, dests);
+ break;
+
+#ifdef __sgi
+ case 'b' : /* Show both the local and remote status */
+ if (!http)
+ {
+ http = httpConnectEncrypt(cupsServer(), ippPort(), encryption);
+
+ if (http == NULL)
+ {
+ perror("lpstat: Unable to connect to server");
+ return (1);
+ }
+ }
+
+ if (argv[i][2] != '\0')
+ {
+ /*
+ * The local and remote status are separated by a blank line;
+ * since all CUPS jobs are networked, we only output the
+ * second list for now... In the future, we might further
+ * emulate this by listing the remote server's queue, but
+ * for now this is enough to make the SGI printstatus program
+ * happy...
+ */
+
+ puts("");
+ show_jobs(http, argv[i] + 2, NULL, 3, ranking);
+ }
+ else
+ {
+ fputs("lpstat: The -b option requires a destination argument.\n",
+ stderr);
+
+ return (1);
+ }
+ break;
+#endif /* __sgi */
+
+ case 'c' : /* Show classes and members */
+ if (!http)
+ {
+ http = httpConnectEncrypt(cupsServer(), ippPort(), encryption);
+
+ if (http == NULL)
+ {
+ perror("lpstat: Unable to connect to server");
+ return (1);
+ }
+ }
+
+ if (argv[i][2] != '\0')
+ show_classes(http, argv[i] + 2);
+ else if ((i + 1) < argc && argv[i + 1][0] != '-')
+ {
+ i ++;
+ show_classes(http, argv[i]);
+ }
+ else
+ show_classes(http, NULL);
+ break;
+
+ case 'd' : /* Show default destination */
+ if (num_dests == 0)
+ num_dests = cupsGetDests(&dests);
+
+ show_default(num_dests, dests);
+ break;
+
+ case 'f' : /* Show forms */
+ if (!argv[i][2])
+ i ++;
+ break;
+
+ case 'h' : /* Connect to host */
+ if (http)
+ httpClose(http);
+
+ if (argv[i][2] != '\0')
+ {
+ http = httpConnectEncrypt(argv[i] + 2, ippPort(), encryption);
+ cupsSetServer(argv[i] + 2);
+ }
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ fputs("Error: need hostname after \'-h\' option!\n", stderr);
+ return (1);
+ }
+
+ http = httpConnectEncrypt(argv[i], ippPort(), encryption);
+ cupsSetServer(argv[i]);
+ }
+
+ if (http == NULL)
+ {
+ perror("lpstat: Unable to connect to server");
+ return (1);
+ }
+ break;
+
+ case 'l' : /* Long status or long job status */
+#ifdef __sgi
+ if (!http)
+ {
+ http = httpConnectEncrypt(cupsServer(), ippPort(), encryption);
+
+ if (http == NULL)
+ {
+ perror("lpstat: Unable to connect to server");
+ return (1);
+ }
+ }
+
+ if (argv[i][2] != '\0')
+ show_jobs(http, argv[i] + 2, NULL, 3, ranking);
+ else
+#endif /* __sgi */
+ long_status = 2;
+ break;
+
+ case 'o' : /* Show jobs by destination */
+ if (!http)
+ {
+ http = httpConnectEncrypt(cupsServer(), ippPort(), encryption);
+
+ if (http == NULL)
+ {
+ perror("lpstat: Unable to connect to server");
+ return (1);
+ }
+ }
+
+ if (argv[i][2] != '\0')
+ show_jobs(http, argv[i] + 2, NULL, long_status, ranking);
+ else if ((i + 1) < argc && argv[i + 1][0] != '-')
+ {
+ i ++;
+ show_jobs(http, argv[i], NULL, long_status, ranking);
+ }
+ else
+ show_jobs(http, NULL, NULL, long_status, ranking);
+ break;
+
+ case 'p' : /* Show printers */
+ if (!http)
+ {
+ http = httpConnectEncrypt(cupsServer(), ippPort(), encryption);
+
+ if (http == NULL)
+ {
+ perror("lpstat: Unable to connect to server");
+ return (1);
+ }
+ }
+
+ if (num_dests == 0)
+ num_dests = cupsGetDests(&dests);
+
+ if (argv[i][2] != '\0')
+ show_printers(http, argv[i] + 2, num_dests, dests, long_status);
+ else if ((i + 1) < argc && argv[i + 1][0] != '-')
+ {
+ i ++;
+ show_printers(http, argv[i], num_dests, dests, long_status);
+ }
+ else
+ show_printers(http, NULL, num_dests, dests, long_status);
+ break;
+
+ case 'r' : /* Show scheduler status */
+ if (!http)
+ {
+ http = httpConnectEncrypt(cupsServer(), ippPort(), encryption);
+
+ if (http == NULL)
+ {
+ perror("lpstat: Unable to connect to server");
+ return (1);
+ }
+ }
+
+ show_scheduler(http);
+ break;
+
+ case 's' : /* Show summary */
+ if (!http)
+ {
+ http = httpConnectEncrypt(cupsServer(), ippPort(), encryption);
+
+ if (http == NULL)
+ {
+ perror("lpstat: Unable to connect to server");
+ return (1);
+ }
+ }
+
+ if (num_dests == 0)
+ num_dests = cupsGetDests(&dests);
+
+ show_default(num_dests, dests);
+ show_classes(http, NULL);
+ show_devices(http, NULL, num_dests, dests);
+ break;
+
+ case 't' : /* Show all info */
+ if (!http)
+ {
+ http = httpConnectEncrypt(cupsServer(), ippPort(), encryption);
+
+ if (http == NULL)
+ {
+ perror("lpstat: Unable to connect to server");
+ return (1);
+ }
+ }
+
+ if (num_dests == 0)
+ num_dests = cupsGetDests(&dests);
+
+ show_scheduler(http);
+ show_default(num_dests, dests);
+ show_classes(http, NULL);
+ show_devices(http, NULL, num_dests, dests);
+ show_accepting(http, NULL, num_dests, dests);
+ show_printers(http, NULL, num_dests, dests, long_status);
+ show_jobs(http, NULL, NULL, long_status, ranking);
+ break;
+
+ case 'u' : /* Show jobs by user */
+ if (!http)
+ {
+ http = httpConnectEncrypt(cupsServer(), ippPort(), encryption);
+
+ if (http == NULL)
+ {
+ perror("lpstat: Unable to connect to server");
+ return (1);
+ }
+ }
+
+ if (argv[i][2] != '\0')
+ show_jobs(http, NULL, argv[i] + 2, long_status, ranking);
+ else if ((i + 1) < argc && argv[i + 1][0] != '-')
+ {
+ i ++;
+ show_jobs(http, NULL, argv[i], long_status, ranking);
+ }
+ else
+ show_jobs(http, NULL, NULL, long_status, ranking);
+ break;
+
+ case 'v' : /* Show printer devices */
+ if (!http)
+ {
+ http = httpConnectEncrypt(cupsServer(), ippPort(), encryption);
+
+ if (http == NULL)
+ {
+ perror("lpstat: Unable to connect to server");
+ return (1);
+ }
+ }
+
+ if (num_dests == 0)
+ num_dests = cupsGetDests(&dests);
+
+ if (argv[i][2] != '\0')
+ show_devices(http, argv[i] + 2, num_dests, dests);
+ else if ((i + 1) < argc && argv[i + 1][0] != '-')
+ {
+ i ++;
+ show_devices(http, argv[i], num_dests, dests);
+ }
+ else
+ show_devices(http, NULL, num_dests, dests);
+ break;
+
+
+ default :
+ fprintf(stderr, "lpstat: Unknown option \'%c\'!\n", argv[i][1]);
+ return (1);
+ }
+ else
+ {
+ if (!http)
+ {
+ http = httpConnectEncrypt(cupsServer(), ippPort(), encryption);
+
+ if (http == NULL)
+ {
+ perror("lpstat: Unable to connect to server");
+ return (1);
+ }
+ }
+
+ show_jobs(http, argv[i], NULL, long_status, ranking);
+ }
+
+ if (argc == 1)
+ {
+ if (!http)
+ {
+ http = httpConnectEncrypt(cupsServer(), ippPort(), encryption);
+
+ if (http == NULL)
+ {
+ perror("lpstat: Unable to connect to server");
+ return (1);
+ }
+ }
+
+ show_jobs(http, NULL, cupsUser(), long_status, ranking);
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'show_accepting()' - Show acceptance status.
+ */
+
+static void
+show_accepting(http_t *http, /* I - HTTP connection to server */
+ const char *printers, /* I - Destinations */
+ int num_dests, /* I - Number of user-defined dests */
+ cups_dest_t *dests) /* I - User-defined destinations */
+{
+ int i; /* Looping var */
+ ipp_t *request, /* IPP Request */
+ *response; /* IPP Response */
+ ipp_attribute_t *attr; /* Current attribute */
+ cups_lang_t *language; /* Default language */
+ const char *printer, /* Printer name */
+ *message; /* Printer device URI */
+ int accepting; /* Accepting requests? */
+ const char *dptr, /* Pointer into destination list */
+ *ptr; /* Pointer into printer name */
+ int match; /* Non-zero if this job matches */
+ static const char *pattrs[] = /* Attributes we need for printers... */
+ {
+ "printer-name",
+ "printer-state-message",
+ "printer-is-accepting-jobs"
+ };
+
+
+ DEBUG_printf(("show_accepting(%p, %p)\n", http, printers));
+
+ if (http == NULL)
+ return;
+
+ if (printers != NULL && strcmp(printers, "all") == 0)
+ printers = NULL;
+
+ /*
+ * Build a CUPS_GET_PRINTERS request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * requested-attributes
+ */
+
+ 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);
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]),
+ NULL, pattrs);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/")) != NULL)
+ {
+ DEBUG_puts("show_accepting: request succeeded...");
+
+ if (response->request.status.status_code > IPP_OK_CONFLICT)
+ {
+ fprintf(stderr, "lpstat: get-printers failed: %s\n",
+ ippErrorString(response->request.status.status_code));
+ ippDelete(response);
+ return;
+ }
+
+ /*
+ * Loop through the printers returned in the list and display
+ * their devices...
+ */
+
+ for (attr = response->attrs; attr != NULL; attr = attr->next)
+ {
+ /*
+ * Skip leading attributes until we hit a printer...
+ */
+
+ while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
+ attr = attr->next;
+
+ if (attr == NULL)
+ break;
+
+ /*
+ * Pull the needed attributes from this printer...
+ */
+
+ printer = NULL;
+ message = NULL;
+ 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, "printer-state-message") == 0 &&
+ attr->value_tag == IPP_TAG_TEXT)
+ message = attr->values[0].string.text;
+
+ 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 = printers == NULL;
+
+ if (printers != NULL)
+ {
+ for (dptr = printers; *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 (accepting)
+ printf("%s accepting requests since Jan 01 00:00\n", printer);
+ else
+ printf("%s not accepting requests since Jan 01 00:00 -\n\t%s\n", printer,
+ message == NULL ? "reason unknown" : message);
+
+ for (i = 0; i < num_dests; i ++)
+ if (strcasecmp(dests[i].name, printer) == 0 && dests[i].instance)
+ {
+ if (accepting)
+ printf("%s/%s accepting requests since Jan 01 00:00\n", printer, dests[i].instance);
+ else
+ printf("%s/%s not accepting requests since Jan 01 00:00 -\n\t%s\n", printer,
+ dests[i].instance,
+ message == NULL ? "reason unknown" : message);
+ }
+ }
+
+ if (attr == NULL)
+ break;
+ }
+
+ ippDelete(response);
+ }
+ else
+ fprintf(stderr, "lpstat: get-printers failed: %s\n",
+ ippErrorString(cupsLastError()));
+}
+
+
+/*
+ * 'show_classes()' - Show printer classes.
+ */
+
+static void
+show_classes(http_t *http, /* I - HTTP connection to server */
+ const char *dests) /* I - Destinations */
+{
+ int i; /* Looping var */
+ ipp_t *request, /* IPP Request */
+ *response, /* IPP Response */
+ *response2; /* IPP response from remote server */
+ http_t *http2; /* Remote server */
+ ipp_attribute_t *attr; /* Current attribute */
+ cups_lang_t *language; /* Default language */
+ const char *printer, /* Printer class name */
+ *printer_uri; /* Printer class URI */
+ ipp_attribute_t *members; /* Printer members */
+ char method[HTTP_MAX_URI],
+ /* Request method */
+ username[HTTP_MAX_URI],
+ /* Username:password */
+ server[HTTP_MAX_URI],
+ /* Server name */
+ resource[HTTP_MAX_URI];
+ /* Resource name */
+ int port; /* Port number */
+ const char *dptr, /* Pointer into destination list */
+ *ptr; /* Pointer into printer name */
+ int match; /* Non-zero if this job matches */
+ static const char *cattrs[] = /* Attributes we need for classes... */
+ {
+ "printer-name",
+ "printer-uri-supported",
+ "member-names"
+ };
+
+
+ DEBUG_printf(("show_classes(%p, %p)\n", http, dests));
+
+ if (http == NULL)
+ return;
+
+ if (dests != NULL && strcmp(dests, "all") == 0)
+ dests = NULL;
+
+ /*
+ * Build a CUPS_GET_CLASSES request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * requested-attributes
+ */
+
+ 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);
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes", sizeof(cattrs) / sizeof(cattrs[0]),
+ NULL, cattrs);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/")) != NULL)
+ {
+ DEBUG_puts("show_classes: request succeeded...");
+
+ if (response->request.status.status_code > IPP_OK_CONFLICT)
+ {
+ fprintf(stderr, "lpstat: get-classes failed: %s\n",
+ ippErrorString(response->request.status.status_code));
+ ippDelete(response);
+ return;
+ }
+
+ /*
+ * Loop through the printers returned in the list and display
+ * their devices...
+ */
+
+ for (attr = response->attrs; attr != NULL; attr = attr->next)
+ {
+ /*
+ * Skip leading attributes until we hit a job...
+ */
+
+ while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
+ attr = attr->next;
+
+ if (attr == NULL)
+ break;
+
+ /*
+ * Pull the needed attributes from this job...
+ */
+
+ printer = NULL;
+ printer_uri = NULL;
+ members = NULL;
+
+ 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, "printer-uri-supported") == 0 &&
+ attr->value_tag == IPP_TAG_URI)
+ printer_uri = attr->values[0].string.text;
+
+ if (strcmp(attr->name, "member-names") == 0 &&
+ attr->value_tag == IPP_TAG_NAME)
+ members = attr;
+
+ attr = attr->next;
+ }
+
+ /*
+ * If this is a remote class, grab the class info from the
+ * remote server...
+ */
+
+ response2 = NULL;
+ if (members == NULL && printer_uri != NULL)
+ {
+ httpSeparate(printer_uri, method, username, server, &port, resource);
+
+ if ((http2 = httpConnectEncrypt(server, port, cupsEncryption())) != NULL)
+ {
+ /*
+ * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
+ * following attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * requested-attributes
+ */
+
+ 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);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, printer_uri);
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes", sizeof(cattrs) / sizeof(cattrs[0]),
+ NULL, cattrs);
+
+ if ((response2 = cupsDoRequest(http2, request, "/")) != NULL)
+ members = ippFindAttribute(response2, "member-names", IPP_TAG_NAME);
+
+ httpClose(http2);
+ }
+ }
+
+ /*
+ * See if we have everything needed...
+ */
+
+ if (printer == NULL)
+ {
+ if (response2)
+ ippDelete(response2);
+
+ 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)
+ {
+ printf("members of class %s:\n", printer);
+
+ if (members)
+ {
+ for (i = 0; i < members->num_values; i ++)
+ printf("\t%s\n", members->values[i].string.text);
+ }
+ else
+ puts("\tunknown");
+ }
+
+ if (response2)
+ ippDelete(response2);
+
+ if (attr == NULL)
+ break;
+ }
+
+ ippDelete(response);
+ }
+ else
+ fprintf(stderr, "lpstat: get-classes failed: %s\n",
+ ippErrorString(cupsLastError()));
+}
+
+
+/*
+ * 'show_default()' - Show default destination.
+ */
+
+static void
+show_default(int num_dests, /* I - Number of user-defined dests */
+ cups_dest_t *dests) /* I - User-defined destinations */
+{
+ int i; /* Looping var */
+
+
+ for (i = 0; i < num_dests; i ++)
+ if (dests[i].is_default)
+ break;
+
+ if (i < num_dests)
+ {
+ if (dests[i].instance)
+ printf("system default destination: %s/%s\n", dests[i].name,
+ dests[i].instance);
+ else
+ printf("system default destination: %s\n", dests[i].name);
+ }
+ else
+ puts("no system default destination");
+}
+
+
+/*
+ * 'show_devices()' - Show printer devices.
+ */
+
+static void
+show_devices(http_t *http, /* I - HTTP connection to server */
+ const char *printers, /* I - Destinations */
+ int num_dests, /* I - Number of user-defined dests */
+ cups_dest_t *dests) /* I - User-defined destinations */
+{
+ int i; /* Looping var */
+ ipp_t *request, /* IPP Request */
+ *response; /* IPP Response */
+ ipp_attribute_t *attr; /* Current attribute */
+ cups_lang_t *language; /* Default language */
+ const char *printer, /* Printer name */
+ *uri, /* Printer URI */
+ *device, /* Printer device URI */
+ *dptr, /* Pointer into destination list */
+ *ptr; /* Pointer into printer name */
+ int match; /* Non-zero if this job matches */
+ static const char *pattrs[] = /* Attributes we need for printers... */
+ {
+ "printer-name",
+ "printer-uri-supported",
+ "device-uri"
+ };
+
+
+ DEBUG_printf(("show_devices(%p, %p)\n", http, dests));
+
+ if (http == NULL)
+ return;
+
+ if (printers != NULL && strcmp(printers, "all") == 0)
+ printers = NULL;
+
+ /*
+ * Build a CUPS_GET_PRINTERS request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * requested-attributes
+ */
+
+ 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);
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]),
+ NULL, pattrs);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/")) != NULL)
+ {
+ DEBUG_puts("show_devices: request succeeded...");
+
+ if (response->request.status.status_code > IPP_OK_CONFLICT)
+ {
+ fprintf(stderr, "lpstat: get-printers failed: %s\n",
+ ippErrorString(response->request.status.status_code));
+ ippDelete(response);
+ return;
+ }
+
+ /*
+ * Loop through the printers returned in the list and display
+ * their devices...
+ */
+
+ for (attr = response->attrs; attr != NULL; attr = attr->next)
+ {
+ /*
+ * Skip leading attributes until we hit a job...
+ */
+
+ while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
+ attr = attr->next;
+
+ if (attr == NULL)
+ break;
+
+ /*
+ * Pull the needed attributes from this job...
+ */
+
+ printer = NULL;
+ device = NULL;
+ uri = NULL;
+
+ 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, "printer-uri-supported") == 0 &&
+ attr->value_tag == IPP_TAG_URI)
+ uri = attr->values[0].string.text;
+
+ if (strcmp(attr->name, "device-uri") == 0 &&
+ attr->value_tag == IPP_TAG_URI)
+ device = attr->values[0].string.text;
+
+ 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 = printers == NULL;
+
+ if (printers != NULL)
+ {
+ for (dptr = printers; *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)
+ {
+#ifdef __osf__ /* Compaq/Digital like to do it their own way... */
+ char method[HTTP_MAX_URI], /* Components of printer URI */
+ username[HTTP_MAX_URI],
+ hostname[HTTP_MAX_URI],
+ resource[HTTP_MAX_URI];
+ int port;
+
+
+ if (device == NULL)
+ {
+ httpSeparate(uri, method, username, hostname, &port, resource);
+ printf("Output for printer %s is sent to remote printer %s on %s\n",
+ printer, strrchr(resource, '/') + 1, hostname);
+ }
+ else if (strncmp(device, "file:", 5) == 0)
+ printf("Output for printer %s is sent to %s\n", printer, device + 5);
+ else
+ printf("Output for printer %s is sent to %s\n", printer, device);
+
+ for (i = 0; i < num_dests; i ++)
+ if (strcasecmp(printer, dests[i].name) == 0 && dests[i].instance)
+ {
+ if (device == NULL)
+ printf("Output for printer %s/%s is sent to remote printer %s on %s\n",
+ printer, dests[i].instance, strrchr(resource, '/') + 1,
+ hostname);
+ else if (strncmp(device, "file:", 5) == 0)
+ printf("Output for printer %s/%s is sent to %s\n", printer, dests[i].instance, device + 5);
+ else
+ printf("Output for printer %s/%s is sent to %s\n", printer, dests[i].instance, device);
+ }
+#else
+ if (device == NULL)
+ printf("device for %s: %s\n", printer, uri);
+ else if (strncmp(device, "file:", 5) == 0)
+ printf("device for %s: %s\n", printer, device + 5);
+ else
+ printf("device for %s: %s\n", printer, device);
+
+ for (i = 0; i < num_dests; i ++)
+ if (strcasecmp(printer, dests[i].name) == 0 && dests[i].instance)
+ {
+ if (device == NULL)
+ printf("device for %s/%s: %s\n", printer, dests[i].instance, uri);
+ else if (strncmp(device, "file:", 5) == 0)
+ printf("device for %s/%s: %s\n", printer, dests[i].instance, device + 5);
+ else
+ printf("device for %s/%s: %s\n", printer, dests[i].instance, device);
+ }
+#endif /* __osf__ */
+ }
+
+ if (attr == NULL)
+ break;
+ }
+
+ ippDelete(response);
+ }
+ else
+ fprintf(stderr, "lpstat: get-printers failed: %s\n",
+ ippErrorString(cupsLastError()));
+}
+
+
+/*
+ * 'show_jobs()' - Show active print jobs.
+ */
+
+static void
+show_jobs(http_t *http, /* I - HTTP connection to server */
+ const char *dests, /* I - Destinations */
+ const char *users, /* I - Users */
+ int long_status,/* I - Show long status? */
+ int ranking) /* I - Show job ranking? */
+{
+ ipp_t *request, /* IPP Request */
+ *response; /* IPP Response */
+ ipp_attribute_t *attr; /* Current attribute */
+ cups_lang_t *language; /* Default language */
+ const char *dest, /* Pointer into job-printer-uri */
+ *username, /* Pointer to job-originating-user-name */
+ *title; /* Pointer to job-name */
+ int rank, /* Rank in queue */
+ jobid, /* job-id */
+ size; /* job-k-octets */
+ time_t jobtime; /* time-at-creation */
+ struct tm *jobdate; /* Date & time */
+ const char *dptr, /* Pointer into destination list */
+ *ptr; /* Pointer into printer name */
+ int match; /* Non-zero if this job matches */
+ char temp[22], /* Temporary buffer */
+ date[32]; /* Date buffer */
+ static const char *jattrs[] = /* Attributes we need for jobs... */
+ {
+ "job-id",
+ "job-k-octets",
+ "job-name",
+ "time-at-creation",
+ "job-printer-uri",
+ "job-originating-user-name"
+ };
+
+
+ DEBUG_printf(("show_jobs(%p, %p, %p)\n", http, dests, users));
+
+ if (http == NULL)
+ return;
+
+ if (dests != NULL && strcmp(dests, "all") == 0)
+ dests = NULL;
+
+ /*
+ * Build a IPP_GET_JOBS request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * job-uri
+ * requested-attributes
+ */
+
+ 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);
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes", sizeof(jattrs) / sizeof(jattrs[0]),
+ NULL, jattrs);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri",
+ NULL, "ipp://localhost/jobs/");
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/")) != NULL)
+ {
+ /*
+ * Loop through the job list and display them...
+ */
+
+ if (response->request.status.status_code > IPP_OK_CONFLICT)
+ {
+ fprintf(stderr, "lpstat: get-jobs failed: %s\n",
+ ippErrorString(response->request.status.status_code));
+ ippDelete(response);
+ return;
+ }
+
+ rank = -1;
+
+ 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;
+ size = 0;
+ username = NULL;
+ dest = NULL;
+ jobtime = 0;
+ title = "no title";
+
+ while (attr != NULL && attr->group_tag == IPP_TAG_JOB)
+ {
+ if (strcmp(attr->name, "job-id") == 0 &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ jobid = attr->values[0].integer;
+
+ if (strcmp(attr->name, "job-k-octets") == 0 &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ size = attr->values[0].integer * 1024;
+
+ if (strcmp(attr->name, "time-at-creation") == 0 &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ jobtime = attr->values[0].integer;
+
+ if (strcmp(attr->name, "job-printer-uri") == 0 &&
+ attr->value_tag == IPP_TAG_URI)
+ if ((dest = strrchr(attr->values[0].string.text, '/')) != NULL)
+ dest ++;
+
+ if (strcmp(attr->name, "job-originating-user-name") == 0 &&
+ attr->value_tag == IPP_TAG_NAME)
+ username = attr->values[0].string.text;
+
+ if (strcmp(attr->name, "job-name") == 0 &&
+ attr->value_tag == IPP_TAG_NAME)
+ title = attr->values[0].string.text;
+
+ attr = attr->next;
+ }
+
+ /*
+ * See if we have everything needed...
+ */
+
+ if (dest == NULL || jobid == 0)
+ {
+ if (attr == NULL)
+ break;
+ else
+ continue;
+ }
+
+ /*
+ * See if this is a job we're interested in...
+ */
+
+ match = (dests == NULL && users == NULL);
+ rank ++;
+
+ 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 = dest;
+ *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;
+ }
+ }
+
+ if (users != NULL && username != NULL)
+ {
+ for (dptr = users; *dptr != '\0';)
+ {
+ /*
+ * Skip leading whitespace and commas...
+ */
+
+ while (isspace(*dptr) || *dptr == ',')
+ dptr ++;
+
+ if (*dptr == '\0')
+ break;
+
+ /*
+ * Compare names...
+ */
+
+ for (ptr = username;
+ *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 job...
+ */
+
+ if (match)
+ {
+ jobdate = localtime(&jobtime);
+ snprintf(temp, sizeof(temp), "%s-%d", dest, jobid);
+
+ if (long_status == 3)
+ {
+ /*
+ * Show the consolidated output format for the SGI tools...
+ */
+
+ strftime(date, sizeof(date), "%b %d %H:%M", jobdate);
+
+ printf("%s;%s;%d;%s;%s\n", temp, username ? username : "unknown",
+ size, title ? title : "unknown", date);
+ }
+ else
+ {
+ strftime(date, sizeof(date), CUPS_STRFTIME_FORMAT, jobdate);
+
+ if (ranking)
+ printf("%3d %-21s %-13s %8d %s\n", rank, temp,
+ username ? username : "unknown", size, date);
+ else
+ printf("%-23s %-13s %8d %s\n", temp,
+ username ? username : "unknown", size, date);
+ if (long_status)
+ printf("\tqueued for %s\n", dest);
+ }
+ }
+
+ if (attr == NULL)
+ break;
+ }
+
+ ippDelete(response);
+ }
+ else
+ fprintf(stderr, "lpstat: get-jobs failed: %s\n",
+ ippErrorString(cupsLastError()));
+}
+
+
+/*
+ * 'show_printers()' - Show printers.
+ */
+
+static void
+show_printers(http_t *http, /* I - HTTP connection to server */
+ const char *printers, /* I - Destinations */
+ int num_dests, /* I - Number of user-defined dests */
+ cups_dest_t *dests, /* I - User-defined destinations */
+ int long_status) /* I - Show long status? */
+{
+ int i; /* Looping var */
+ ipp_t *request, /* IPP Request */
+ *response, /* IPP Response */
+ *jobs; /* IPP Get Jobs response */
+ ipp_attribute_t *attr; /* Current attribute */
+ ipp_attribute_t *jobattr; /* Job ID attribute */
+ cups_lang_t *language; /* Default language */
+ const char *printer, /* Printer name */
+ *message, /* Printer state message */
+ *description; /* Description of printer */
+ ipp_pstate_t pstate; /* Printer state */
+ cups_ptype_t ptype; /* Printer type */
+ int jobid; /* Job ID of current job */
+ const 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 */
+ const char *root; /* Server root directory... */
+ static const char *pattrs[] = /* Attributes we need for printers... */
+ {
+ "printer-name",
+ "printer-state",
+ "printer-state-message",
+ "printer-type",
+ "printer-info"
+ };
+ static const char *jattrs[] = /* Attributes we need for jobs... */
+ {
+ "job-id"
+ };
+
+
+ DEBUG_printf(("show_printers(%p, %p)\n", http, dests));
+
+ if (http == NULL)
+ return;
+
+ if ((root = getenv("CUPS_SERVERROOT")) == NULL)
+ root = CUPS_SERVERROOT;
+
+ if (printers != NULL && strcmp(printers, "all") == 0)
+ printers = NULL;
+
+ /*
+ * Build a CUPS_GET_PRINTERS request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * requested-attributes
+ */
+
+ 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);
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]),
+ NULL, pattrs);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/")) != NULL)
+ {
+ DEBUG_puts("show_printers: request succeeded...");
+
+ if (response->request.status.status_code > IPP_OK_CONFLICT)
+ {
+ fprintf(stderr, "lpstat: get-printers failed: %s\n",
+ ippErrorString(response->request.status.status_code));
+ ippDelete(response);
+ return;
+ }
+
+ /*
+ * 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;
+ ptype = CUPS_PRINTER_LOCAL;
+ pstate = IPP_PRINTER_IDLE;
+ message = NULL;
+ description = NULL;
+ jobid = 0;
+
+ 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, "printer-state") == 0 &&
+ attr->value_tag == IPP_TAG_ENUM)
+ pstate = (ipp_pstate_t)attr->values[0].integer;
+
+ if (strcmp(attr->name, "printer-type") == 0 &&
+ attr->value_tag == IPP_TAG_ENUM)
+ ptype = (cups_ptype_t)attr->values[0].integer;
+
+ if (strcmp(attr->name, "printer-state-message") == 0 &&
+ attr->value_tag == IPP_TAG_TEXT)
+ message = attr->values[0].string.text;
+
+ if (strcmp(attr->name, "printer-info") == 0 &&
+ attr->value_tag == IPP_TAG_TEXT)
+ description = attr->values[0].string.text;
+
+ 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 = printers == NULL;
+
+ if (printers != NULL)
+ {
+ for (dptr = printers; *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
+ * requested-attributes
+ */
+
+ 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);
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes",
+ sizeof(jattrs) / sizeof(jattrs[0]), NULL, jattrs);
+
+ snprintf(printer_uri, sizeof(printer_uri), "ipp://%s/printers/%s",
+ http->hostname, printer);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, printer_uri);
+
+ ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER,
+ "limit", 1);
+
+ if ((jobs = cupsDoRequest(http, request, "/")) != NULL)
+ {
+ if ((jobattr = ippFindAttribute(jobs, "job-id", IPP_TAG_INTEGER)) != NULL)
+ jobid = jobattr->values[0].integer;
+
+ ippDelete(jobs);
+ }
+ }
+
+ /*
+ * Display it...
+ */
+
+ switch (pstate)
+ {
+ case IPP_PRINTER_IDLE :
+ printf("printer %s is idle. enabled since Jan 01 00:00\n", printer);
+ break;
+ case IPP_PRINTER_PROCESSING :
+ printf("printer %s now printing %s-%d. enabled since Jan 01 00:00\n", printer, printer, jobid);
+ break;
+ case IPP_PRINTER_STOPPED :
+ printf("printer %s disabled since Jan 01 00:00 -\n\t%s\n", printer,
+ message == NULL ? "reason unknown" : message);
+ break;
+ }
+
+ if (long_status > 1)
+ {
+ puts("\tForm mounted:");
+ puts("\tContent types: any");
+ puts("\tPrinter types: unknown");
+ }
+ if (long_status)
+ printf("\tDescription: %s\n", description ? description : "");
+ if (long_status > 1)
+ {
+ printf("\tConnection: %s\n",
+ (ptype & CUPS_PRINTER_REMOTE) ? "remote" : "direct");
+ if (!(ptype & CUPS_PRINTER_REMOTE))
+ printf("\tInterface: %s/ppd/%s.ppd\n", root, printer);
+ puts("\tOn fault: no alert");
+ puts("\tAfter fault: continue");
+ puts("\tUsers allowed:");
+ puts("\t\t(all)");
+ puts("\tForms allowed:");
+ puts("\t\t(none)");
+ puts("\tBanner required");
+ puts("\tCharset sets:");
+ puts("\t\t(none)");
+ puts("\tDefault pitch:");
+ puts("\tDefault page size:");
+ puts("\tDefault port settings:");
+ }
+
+ for (i = 0; i < num_dests; i ++)
+ if (strcasecmp(printer, dests[i].name) == 0 && dests[i].instance)
+ {
+ switch (pstate)
+ {
+ case IPP_PRINTER_IDLE :
+ printf("printer %s/%s is idle. enabled since Jan 01 00:00\n", printer, dests[i].instance);
+ break;
+ case IPP_PRINTER_PROCESSING :
+ printf("printer %s/%s now printing %s-%d. enabled since Jan 01 00:00\n", printer,
+ dests[i].instance, printer, jobid);
+ break;
+ case IPP_PRINTER_STOPPED :
+ printf("printer %s/%s disabled since Jan 01 00:00 -\n\t%s\n", printer,
+ dests[i].instance,
+ message == NULL ? "reason unknown" : message);
+ break;
+ }
+
+ if (long_status > 1)
+ {
+ puts("\tForm mounted:");
+ puts("\tContent types: any");
+ puts("\tPrinter types: unknown");
+ }
+ if (long_status)
+ printf("\tDescription: %s\n", description ? description : "");
+ if (long_status > 1)
+ {
+ printf("\tConnection: %s\n",
+ (ptype & CUPS_PRINTER_REMOTE) ? "remote" : "direct");
+ if (!(ptype & CUPS_PRINTER_REMOTE))
+ printf("\tInterface: %s/ppd/%s.ppd\n", root, printer);
+ puts("\tOn fault: no alert");
+ puts("\tAfter fault: continue");
+ puts("\tUsers allowed:");
+ puts("\t\t(all)");
+ puts("\tForms allowed:");
+ puts("\t\t(none)");
+ puts("\tBanner required");
+ puts("\tCharset sets:");
+ puts("\t\t(none)");
+ puts("\tDefault pitch:");
+ puts("\tDefault page size:");
+ puts("\tDefault port settings:");
+ }
+ }
+ }
+
+ if (attr == NULL)
+ break;
+ }
+
+ ippDelete(response);
+ }
+ else
+ fprintf(stderr, "lpstat: get-printers failed: %s\n",
+ ippErrorString(cupsLastError()));
+}
+
+
+/*
+ * 'show_scheduler()' - Show scheduler status.
+ */
+
+static void
+show_scheduler(http_t *http) /* I - HTTP connection to server */
+{
+ printf("scheduler is %srunning\n", http == NULL ? "not " : "");
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/templates/Makefile b/templates/Makefile
new file mode 100644
index 000000000..31a9965c9
--- /dev/null
+++ b/templates/Makefile
@@ -0,0 +1,103 @@
+#
+# "$Id$"
+#
+# Template makefile for the Common UNIX Printing System (CUPS).
+#
+# Copyright 1993-2002 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
+
+#
+# Template files...
+#
+
+FILES = add-class.tmpl \
+ add-printer.tmpl \
+ admin-op.tmpl \
+ admin.tmpl \
+ choose-device.tmpl \
+ choose-make.tmpl \
+ choose-members.tmpl \
+ choose-model.tmpl \
+ choose-serial.tmpl \
+ choose-uri.tmpl \
+ class-added.tmpl \
+ class-confirm.tmpl \
+ class-deleted.tmpl \
+ class-modified.tmpl \
+ classes.tmpl \
+ config-printer.tmpl \
+ config-printer2.tmpl \
+ error.tmpl \
+ header.tmpl \
+ jobs.tmpl \
+ job-cancel.tmpl \
+ job-hold.tmpl \
+ job-release.tmpl \
+ job-restart.tmpl \
+ modify-class.tmpl \
+ modify-printer.tmpl \
+ option-boolean.tmpl \
+ option-header.tmpl \
+ option-pickmany.tmpl \
+ option-pickone.tmpl \
+ option-trailer.tmpl \
+ printers.tmpl \
+ printer-accept.tmpl \
+ printer-added.tmpl \
+ printer-configured.tmpl \
+ printer-confirm.tmpl \
+ printer-deleted.tmpl \
+ printer-modified.tmpl \
+ printer-reject.tmpl \
+ printer-start.tmpl \
+ printer-stop.tmpl \
+ test-page.tmpl \
+ trailer.tmpl
+
+
+#
+# Make everything...
+#
+
+all:
+
+
+#
+# Clean all config and object files...
+#
+
+clean:
+
+
+#
+# Install files...
+#
+
+install:
+ $(INSTALL_DIR) $(DATADIR)/templates
+ for file in $(FILES); do \
+ $(INSTALL_DATA) $$file $(DATADIR)/templates; \
+ done
+
+
+#
+# End of "$Id$".
+#
diff --git a/templates/add-class.tmpl b/templates/add-class.tmpl
new file mode 100644
index 000000000..019a3f9fc
--- /dev/null
+++ b/templates/add-class.tmpl
@@ -0,0 +1,33 @@
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+<TABLE CELLPADDING="0" CELLSPACING="0" BORDER="0" WIDTH="100%">
+<TR BGCOLOR="#999966">
+ <TH WIDTH="16"><IMG SRC="/images/left.gif" ALT=""></TH>
+ <TH COLSPAN="2">Add New Class</TH>
+ <TH BGCOLOR="#cccc99" WIDTH="16"><IMG SRC="/images/right.gif" ALT=""></TH>
+</TR>
+<TR>
+ <TD HEIGHT="4"></TD>
+</TR>
+<TR>
+ <TD></TD>
+ <TD ALIGN="RIGHT">Name:</TD>
+ <TD><INPUT TYPE="TEXT" NAME="PRINTER_NAME" SIZE="40" MAXLENGTH="127"></TD>
+</TR>
+<TR>
+ <TD></TD>
+ <TD ALIGN="RIGHT">Location:</TD>
+ <TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" SIZE="40" MAXLENGTH="127"></TD>
+</TR>
+<TR>
+ <TD></TD>
+ <TD ALIGN="RIGHT">Description:</TD>
+ <TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" SIZE="40" MAXLENGTH="127"></TD>
+</TR>
+<TR>
+ <TD></TD>
+ <TD></TD>
+ <TD><INPUT TYPE="IMAGE" SRC="/images/continue.gif" ALT="Continue" BORDER="0"></TD>
+</TR>
+</TABLE>
+</FORM>
diff --git a/templates/add-printer.tmpl b/templates/add-printer.tmpl
new file mode 100644
index 000000000..bf4a33d83
--- /dev/null
+++ b/templates/add-printer.tmpl
@@ -0,0 +1,33 @@
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+<TABLE CELLPADDING="0" CELLSPACING="0" BORDER="0" WIDTH="100%">
+<TR BGCOLOR="#999966">
+ <TH WIDTH="16"><IMG SRC="/images/left.gif" ALT=""></TH>
+ <TH COLSPAN="2">Add New Printer</TH>
+ <TH BGCOLOR="#cccc99" WIDTH="16"><IMG SRC="/images/right.gif" ALT=""></TH>
+</TR>
+<TR>
+ <TD HEIGHT="4"></TD>
+</TR>
+<TR>
+ <TD></TD>
+ <TD ALIGN="RIGHT">Name:</TD>
+ <TD><INPUT TYPE="TEXT" NAME="PRINTER_NAME" SIZE="40" MAXLENGTH="127"></TD>
+</TR>
+<TR>
+ <TD></TD>
+ <TD ALIGN="RIGHT">Location:</TD>
+ <TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" SIZE="40" MAXLENGTH="127"></TD>
+</TR>
+<TR>
+ <TD></TD>
+ <TD ALIGN="RIGHT">Description:</TD>
+ <TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" SIZE="40" MAXLENGTH="127"></TD>
+</TR>
+<TR>
+ <TD></TD>
+ <TD></TD>
+ <TD><INPUT TYPE="IMAGE" SRC="/images/continue.gif" ALT="Continue" BORDER="0"></TD>
+</TR>
+</TABLE>
+</FORM>
diff --git a/templates/admin-op.tmpl b/templates/admin-op.tmpl
new file mode 100644
index 000000000..16699f815
--- /dev/null
+++ b/templates/admin-op.tmpl
@@ -0,0 +1 @@
+<P>Unsupported administration operation "{op}".
diff --git a/templates/admin.tmpl b/templates/admin.tmpl
new file mode 100644
index 000000000..65a711fd7
--- /dev/null
+++ b/templates/admin.tmpl
@@ -0,0 +1,57 @@
+<TABLE CELLPADDING="0" CELLSPACING="0" BORDER="0" WIDTH="100%">
+<TR>
+ <TH BGCOLOR="#999966"><IMG SRC="/images/left.gif" ALT=""></TH>
+ <TH BGCOLOR="#999966">Classes</TH>
+ <TH WIDTH="16"><IMG SRC="/images/right.gif" ALT=""></TH>
+</TR>
+<TR>
+ <TD HEIGHT="4"></TD>
+</TR>
+<TR>
+ <TD></TD>
+ <TD><A HREF="/admin/?op=add-class">
+ <IMG SRC="/images/add-class.gif" ALT="Add a New Class" BORDER="0"></A>
+ <A HREF="/classes/">
+ <IMG SRC="/images/manage-classes.gif" ALT="Manage Available Classes" BORDER="0"></A>
+ </TD>
+</TR>
+<TR>
+ <TD>&nbsp;</TD>
+</TR>
+<TR>
+ <TH BGCOLOR="#999966"><IMG SRC="/images/left.gif" ALT=""></TH>
+ <TH BGCOLOR="#999966">Jobs</TH>
+ <TH WIDTH="16"><IMG SRC="/images/right.gif" ALT=""></TH>
+</TR>
+<TR>
+ <TD HEIGHT="4"></TD>
+</TR>
+<TR>
+ <TD></TD>
+ <TD><A HREF="/jobs/">
+ <IMG SRC="/images/manage-jobs.gif" ALT="Manage Jobs" BORDER="0"></A>
+ </TD>
+</TR>
+<TR>
+ <TD>&nbsp;</TD>
+</TR>
+<TR>
+ <TH BGCOLOR="#999966"><IMG SRC="/images/left.gif" ALT=""></TH>
+ <TH BGCOLOR="#999966">Printers</TH>
+ <TH WIDTH="16"><IMG SRC="/images/right.gif" ALT=""></TH>
+</TR>
+<TR>
+ <TD HEIGHT="4"></TD>
+</TR>
+<TR>
+ <TD></TD>
+ <TD><A HREF="/admin/?op=add-printer">
+ <IMG SRC="/images/add-printer.gif" ALT="Add a New Printer" BORDER="0"></A>
+ <A HREF="/printers/">
+ <IMG SRC="/images/manage-printers.gif" ALT="Manage Available Printers" BORDER="0"></A>
+ </TD>
+</TR>
+<TR>
+ <TD>&nbsp;</TD>
+</TR>
+</TABLE>
diff --git a/templates/choose-device.tmpl b/templates/choose-device.tmpl
new file mode 100644
index 000000000..f64810910
--- /dev/null
+++ b/templates/choose-device.tmpl
@@ -0,0 +1,32 @@
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="{?printer_location}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{?printer_info}">
+<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE_AND_MODEL" VALUE="{?current_make_and_model}">
+<TABLE CELLPADDING="0" CELLSPACING="0" BORDER="0" WIDTH="100%">
+<TR BGCOLOR="#999966">
+ <TH WIDTH="16"><IMG SRC="/images/left.gif" ALT=""></TH>
+ <TH COLSPAN="2">Device for {printer_name}</TH>
+ <TH BGCOLOR="#cccc99" WIDTH="16"><IMG SRC="/images/right.gif" ALT=""></TH>
+</TR>
+<TR>
+ <TD HEIGHT="4"></TD>
+</TR>
+<TR>
+ <TD></TD>
+ <TD ALIGN="RIGHT">Device:&nbsp;</TD>
+ <TD>
+ <SELECT NAME="DEVICE_URI">
+ {[device_uri]<OPTION VALUE="{device_uri}" {?current_device_uri={device_uri}?SELECTED:}>
+ {device_info} {?device_make_and_model!Unknown?({device_make_and_model}):}
+ }</SELECT>
+ </TD>
+</TR>
+<TR>
+ <TD></TD>
+ <TD></TD>
+ <TD><INPUT TYPE="IMAGE" SRC="/images/continue.gif" ALT="Continue" BORDER="0"></TD>
+</TR>
+</TABLE>
+</FORM>
diff --git a/templates/choose-make.tmpl b/templates/choose-make.tmpl
new file mode 100644
index 000000000..8392047c9
--- /dev/null
+++ b/templates/choose-make.tmpl
@@ -0,0 +1,35 @@
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="{?printer_location}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{?printer_info}">
+<INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">
+<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
+<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
+<INPUT TYPE="HIDDEN" NAME="PARITY" VALUE="{?parity}">
+<INPUT TYPE="HIDDEN" NAME="FLOW" VALUE="{?flow}">
+<TABLE CELLPADDING="0" CELLSPACING="0" BORDER="0" WIDTH="100%">
+<TR BGCOLOR="#999966">
+ <TH WIDTH="16"><IMG SRC="/images/left.gif" ALT=""></TH>
+ <TH COLSPAN="2">Model/Driver for {printer_name}</TH>
+ <TH BGCOLOR="#cccc99" WIDTH="16"><IMG SRC="/images/right.gif" ALT=""></TH>
+</TR>
+<TR>
+ <TD HEIGHT="4"></TD>
+</TR>
+<TR>
+ <TD></TD>
+ <TD ALIGN="RIGHT">Make:&nbsp;</TD>
+ <TD>
+ <SELECT NAME="PPD_MAKE" SIZE="10">
+ {[ppd_make]<OPTION VALUE="{ppd_make}" {?current_make={ppd_make}?SELECTED:}>{ppd_make}}
+ </SELECT>
+ </TD>
+</TR>
+<TR>
+ <TD></TD>
+ <TD></TD>
+ <TD><INPUT TYPE="IMAGE" SRC="/images/continue.gif" ALT="Continue" BORDER="0"></TD>
+</TR>
+</TABLE>
+</FORM>
diff --git a/templates/choose-members.tmpl b/templates/choose-members.tmpl
new file mode 100644
index 000000000..b83f13e74
--- /dev/null
+++ b/templates/choose-members.tmpl
@@ -0,0 +1,30 @@
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="{?printer_location}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{?printer_info}">
+<TABLE CELLPADDING="0" CELLSPACING="0" BORDER="0" WIDTH="100%">
+<TR BGCOLOR="#999966">
+ <TH WIDTH="16"><IMG SRC="/images/left.gif" ALT=""></TH>
+ <TH COLSPAN="2">Members for {printer_name}</TH>
+ <TH BGCOLOR="#cccc99" WIDTH="16"><IMG SRC="/images/right.gif" ALT=""></TH>
+</TR>
+<TR>
+ <TD HEIGHT="4"></TD>
+</TR>
+<TR>
+ <TD></TD>
+ <TD ALIGN="RIGHT">Members:&nbsp;</TD>
+ <TD>
+ <SELECT NAME="MEMBER_URIS" SIZE="10" MULTIPLE>
+ {[member_uris]<OPTION VALUE="{member_uris}" {?member_selected}>{member_names}}
+ </SELECT>
+ </TD>
+</TR>
+<TR>
+ <TD></TD>
+ <TD></TD>
+ <TD><INPUT TYPE="IMAGE" SRC="/images/continue.gif" ALT="Continue" BORDER="0"></TD>
+</TR>
+</TABLE>
+</FORM>
diff --git a/templates/choose-model.tmpl b/templates/choose-model.tmpl
new file mode 100644
index 000000000..60efb5634
--- /dev/null
+++ b/templates/choose-model.tmpl
@@ -0,0 +1,35 @@
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="{?printer_location}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{?printer_info}">
+<INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">
+<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
+<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
+<INPUT TYPE="HIDDEN" NAME="PARITY" VALUE="{?parity}">
+<INPUT TYPE="HIDDEN" NAME="FLOW" VALUE="{?flow}">
+<TABLE CELLPADDING="0" CELLSPACING="0" BORDER="0" WIDTH="100%">
+<TR BGCOLOR="#999966">
+ <TH WIDTH="16"><IMG SRC="/images/left.gif" ALT=""></TH>
+ <TH COLSPAN="2">Model/Driver for {printer_name}</TH>
+ <TH BGCOLOR="#cccc99" WIDTH="16"><IMG SRC="/images/right.gif" ALT=""></TH>
+</TR>
+<TR>
+ <TD HEIGHT="4"></TD>
+</TR>
+<TR>
+ <TD></TD>
+ <TD ALIGN="RIGHT">Model:&nbsp;</TD>
+ <TD>
+ <SELECT NAME="PPD_NAME" SIZE="10">
+ {[ppd_name]<OPTION VALUE="{ppd_name}" {?current_make_and_model={ppd_make_and_model}?SELECTED:}>{ppd_make_and_model} ({ppd_natural_language})
+ }</SELECT>
+ </TD>
+</TR>
+<TR>
+ <TD></TD>
+ <TD></TD>
+ <TD><INPUT TYPE="IMAGE" SRC="/images/continue.gif" ALT="Continue" BORDER="0"></TD>
+</TR>
+</TABLE>
+</FORM>
diff --git a/templates/choose-serial.tmpl b/templates/choose-serial.tmpl
new file mode 100644
index 000000000..a0ea5db2d
--- /dev/null
+++ b/templates/choose-serial.tmpl
@@ -0,0 +1,56 @@
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="{?printer_location}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{?printer_info}">
+<INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">
+<TABLE CELLPADDING="0" CELLSPACING="0" BORDER="0" WIDTH="100%">
+<TR BGCOLOR="#999966">
+ <TH WIDTH="16"><IMG SRC="/images/left.gif" ALT=""></TH>
+ <TH COLSPAN="2">Serial Port Settings for {printer_name}</TH>
+ <TH BGCOLOR="#cccc99" WIDTH="16"><IMG SRC="/images/right.gif" ALT=""></TH>
+</TR>
+<TR>
+ <TD HEIGHT="4"></TD>
+</TR>
+<TR>
+ <TD></TD>
+ <TD ALIGN="RIGHT">Baud Rate:&nbsp;</TD>
+ <TD><SELECT NAME="BAUDRATE">
+ {[baudrates]<OPTION {?baudrate={baudrates}?SELECTED:}>{baudrates}}
+ </SELECT></TD>
+</TR>
+<TR>
+ <TD></TD>
+ <TD ALIGN="RIGHT">Parity:&nbsp;</TD>
+ <TD><SELECT NAME="PARITY">
+ <OPTION VALUE="none" {?parity=none?SELECTED:}>None
+ <OPTION VALUE="even" {?parity=even?SELECTED:}>Even
+ <OPTION VALUE="odd" {?parity=odd?SELECTED:}>Odd
+ </SELECT></TD>
+</TR>
+<TR>
+ <TD></TD>
+ <TD ALIGN="RIGHT">Data Bits:&nbsp;</TD>
+ <TD><SELECT NAME="BITS">
+ <OPTION {?bits=8?SELECTED:}>8
+ <OPTION {?bits=7?SELECTED:}>7
+ </SELECT></TD>
+</TR>
+<TR>
+ <TD></TD>
+ <TD ALIGN="RIGHT">Flow Control:&nbsp;</TD>
+ <TD><SELECT NAME="FLOW">
+ <OPTION VALUE="none" {?flow=none?SELECTED:}>None
+ <OPTION VALUE="soft" {?flow=soft?SELECTED:}>XON/XOFF (Software)
+ <OPTION VALUE="hard" {?flow=hard?SELECTED:}>RTS/CTS (Hardware)
+ <OPTION VALUE="dtrdsr" {?flow=dtrdsr?SELECTED:}>DTR/DSR (Hardware)
+ </SELECT></TD>
+</TR>
+<TR>
+ <TD></TD>
+ <TD></TD>
+ <TD><INPUT TYPE="IMAGE" SRC="/images/continue.gif" ALT="Continue" BORDER="0"></TD>
+</TR>
+</TABLE>
+</FORM>
diff --git a/templates/choose-uri.tmpl b/templates/choose-uri.tmpl
new file mode 100644
index 000000000..63bee8529
--- /dev/null
+++ b/templates/choose-uri.tmpl
@@ -0,0 +1,41 @@
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="{?printer_location}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{?printer_info}">
+<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE_AND_MODEL" VALUE="{?current_make_and_model}">
+<TABLE CELLPADDING="0" CELLSPACING="0" BORDER="0" WIDTH="100%">
+<TR BGCOLOR="#999966">
+ <TH WIDTH="16"><IMG SRC="/images/left.gif" ALT=""></TH>
+ <TH COLSPAN="2">Device URI for {printer_name}</TH>
+ <TH BGCOLOR="#cccc99" WIDTH="16"><IMG SRC="/images/right.gif" ALT=""></TH>
+</TR>
+<TR>
+ <TD HEIGHT="4"></TD>
+</TR>
+<TR>
+ <TD></TD>
+ <TD ALIGN="RIGHT">Device URI:&nbsp;</TD>
+ <TD><INPUT TYPE="TEXT" SIZE="40" MAXLENGTH="1024" NAME="DEVICE_URI" VALUE="{device_uri}"></TD>
+</TR>
+<TR>
+ <TD></TD>
+ <TD></TD>
+ <TD>Examples:
+ <PRE>
+ file:/path/to/filename.prn
+ http://hostname:631/ipp/port1
+ ipp://hostname/ipp/port1
+ lpd://hostname/queue
+ socket://hostname
+ socket://hostname:9100
+ </PRE>
+ </TD>
+</TR>
+<TR>
+ <TD></TD>
+ <TD></TD>
+ <TD><INPUT TYPE="IMAGE" SRC="/images/continue.gif" ALT="Continue" BORDER="0"></TD>
+</TR>
+</TABLE>
+</FORM>
diff --git a/templates/class-added.tmpl b/templates/class-added.tmpl
new file mode 100644
index 000000000..f740581ad
--- /dev/null
+++ b/templates/class-added.tmpl
@@ -0,0 +1,2 @@
+<P>Class <A HREF="/classes/{printer_name}">{printer_name}</A> has been added
+successfully.
diff --git a/templates/class-confirm.tmpl b/templates/class-confirm.tmpl
new file mode 100644
index 000000000..0fbbd6d53
--- /dev/null
+++ b/templates/class-confirm.tmpl
@@ -0,0 +1,6 @@
+<P><B>Warning:</B> About to delete class {printer_name}! Do you wish to
+continue?
+
+<P ALIGN="CENTER">
+<A HREF="/admin/?op=delete-class&printer_name={printer_name}&confirm=yes">
+<IMG SRC="/images/continue.gif" ALT="Continue" BORDER="0"></A>
diff --git a/templates/class-deleted.tmpl b/templates/class-deleted.tmpl
new file mode 100644
index 000000000..269ddd87a
--- /dev/null
+++ b/templates/class-deleted.tmpl
@@ -0,0 +1 @@
+<P>Class {printer_name} has been deleted successfully.
diff --git a/templates/class-modified.tmpl b/templates/class-modified.tmpl
new file mode 100644
index 000000000..861790732
--- /dev/null
+++ b/templates/class-modified.tmpl
@@ -0,0 +1,2 @@
+<P>Class <A HREF="/classes/{printer_name}">{printer_name}</A> has been
+modified successfully.
diff --git a/templates/classes.tmpl b/templates/classes.tmpl
new file mode 100644
index 000000000..f7cc8d3a7
--- /dev/null
+++ b/templates/classes.tmpl
@@ -0,0 +1,51 @@
+{#printer_name=0?No classes:
+<P><B>Default Destination:</B> <A HREF="{default_uri}">{default_name}</A>
+<P><TABLE CELLPADDING="0" CELLSPACING="0" BORDER="0" WIDTH="100%">
+{[printer_name]
+<TR>
+ <TH BGCOLOR="#999966"><IMG SRC="/images/left.gif" ALT=""></TH>
+ <TH BGCOLOR="#999966"><A HREF="{printer_uri_supported}">{printer_name}</A></TH>
+ <TH BGCOLOR="#999966">Printer Class</TH>
+ <TH><IMG SRC="/images/right.gif" ALT=""></TH>
+</TR>
+<TR>
+ <TD HEIGHT="4"></TD>
+</TR>
+<TR>
+ <TD></TD>
+ <TD VALIGN=TOP><A HREF="{printer_uri_supported}">
+ <IMG SRC="../images/classes.gif" BORDER="0" ALT=""></A></TD>
+ <TD VALIGN=TOP>Description: {printer_info}<BR>
+ Location: {printer_location}<BR>
+ Class State: {printer_state=3?idle:{printer_state=4?processing:stopped}},
+ {printer_is_accepting_jobs=0?rejecting jobs:accepting jobs}.
+ {?printer_state_message=?:<BR><I>"{printer_state_message}"</I>}
+ {?member_names=?:<BR>Members: {member_names}}
+ <P>
+ <A HREF="{printer_uri_supported}?op=print-test-page">
+ <IMG SRC="/images/print-test-page.gif" ALT="Print Test Page" BORDER="0"></A>
+ {printer_state=5?
+ <A HREF="/admin/?op=start-printer&printer_name={printer_name}">
+ <IMG SRC="/images/start-class.gif" ALT="Start Class" BORDER="0"></A>
+ :
+ <A HREF="/admin/?op=stop-printer&printer_name={printer_name}">
+ <IMG SRC="/images/stop-class.gif" ALT="Stop Class" BORDER="0"></A>
+ }
+ {printer_is_accepting_jobs=0?
+ <A HREF="/admin/?op=accept-jobs&printer_name={printer_name}">
+ <IMG SRC="/images/accept-jobs.gif" ALT="Accept Jobs" BORDER="0"></A>
+ :
+ <A HREF="/admin/?op=reject-jobs&printer_name={printer_name}">
+ <IMG SRC="/images/reject-jobs.gif" ALT="Reject Jobs" BORDER="0"></A>
+ }
+ <A HREF="/admin/?op=modify-class&printer_name={printer_name}">
+ <IMG SRC="/images/modify-class.gif" ALT="Modify Class" BORDER="0"></A>
+ <A HREF="/admin/?op=delete-class&printer_name={printer_name}">
+ <IMG SRC="/images/delete-class.gif" ALT="Delete Class" BORDER="0"></A>
+ </TD>
+</TR>
+}
+</TABLE>
+}
+<P><A HREF="/admin/?op=add-class">
+<IMG SRC="/images/add-class.gif" ALT="Add Class" BORDER="0"></A>
diff --git a/templates/config-printer.tmpl b/templates/config-printer.tmpl
new file mode 100644
index 000000000..f24b08f12
--- /dev/null
+++ b/templates/config-printer.tmpl
@@ -0,0 +1,6 @@
+<P>Choose default options for {printer_name}.
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+<TABLE CELLPADDING="0" CELLSPACING="0" BORDER="0" WIDTH="100%">
diff --git a/templates/config-printer2.tmpl b/templates/config-printer2.tmpl
new file mode 100644
index 000000000..bfb42d69f
--- /dev/null
+++ b/templates/config-printer2.tmpl
@@ -0,0 +1,2 @@
+</TABLE>
+</FORM>
diff --git a/templates/error.tmpl b/templates/error.tmpl
new file mode 100644
index 000000000..eb15a06ff
--- /dev/null
+++ b/templates/error.tmpl
@@ -0,0 +1,3 @@
+<P>Error:
+
+<BLOCKQUOTE>{error}</BLOCKQUOTE>
diff --git a/templates/header.tmpl b/templates/header.tmpl
new file mode 100644
index 000000000..b22bc73f0
--- /dev/null
+++ b/templates/header.tmpl
@@ -0,0 +1,23 @@
+<HTML>
+<HEAD>
+ <TITLE>{title} on {server_name} - {cups_version}</TITLE>
+ <!-- Prevent caching of CGI content -->
+ <META HTTP-EQUIV="Expires" CONTENT="now">
+ <META HTTP-EQUIV="Pragma" CONTENT="no-cache">
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="/cups.css">
+ <MAP NAME="navbar">
+ <AREA SHAPE="RECT" COORDS="12,0,50,30" HREF="http://www.easysw.com" ALT="Easy Software Products Home Page">
+ <AREA SHAPE="RECT" COORDS="82,0,196,30" HREF="/admin" ALT="Do Administration Tasks">
+ <AREA SHAPE="RECT" COORDS="216,0,280,30" HREF="/classes" ALT="Manage Printer Classes Status">
+ <AREA SHAPE="RECT" COORDS="300,0,336,30" HREF="/documentation.html" ALT="On-Line Help">
+ <AREA SHAPE="RECT" COORDS="356,0,394,30" HREF="/jobs" ALT="Manage Jobs">
+ <AREA SHAPE="RECT" COORDS="414,0,476,30" HREF="/printers" ALT="Manage Printers">
+ <AREA SHAPE="RECT" COORDS="496,0,568,30" HREF="http://www.cups.org" ALT="Download the Current CUPS Software">
+ </MAP>
+</HEAD>
+<BODY BGCOLOR="#cccc99" TEXT="#000000" LINK="#0000FF" VLINK="#FF00FF">
+<CENTER>
+<IMG SRC="/images/navbar.gif" WIDTH="583" HEIGHT="30" USEMAP="#navbar" BORDER="0" ALT="Common UNIX Printing System">
+</CENTER>
+
+<H1>{title}</H1>
diff --git a/templates/job-cancel.tmpl b/templates/job-cancel.tmpl
new file mode 100644
index 000000000..52ba31137
--- /dev/null
+++ b/templates/job-cancel.tmpl
@@ -0,0 +1 @@
+<P>Job {job_id} has been cancelled.
diff --git a/templates/job-hold.tmpl b/templates/job-hold.tmpl
new file mode 100644
index 000000000..10fa6b369
--- /dev/null
+++ b/templates/job-hold.tmpl
@@ -0,0 +1 @@
+<P>Job {job_id} has been held from printing.
diff --git a/templates/job-release.tmpl b/templates/job-release.tmpl
new file mode 100644
index 000000000..8dd395b28
--- /dev/null
+++ b/templates/job-release.tmpl
@@ -0,0 +1 @@
+<P>Job {job_id} has been released for printing.
diff --git a/templates/job-restart.tmpl b/templates/job-restart.tmpl
new file mode 100644
index 000000000..f9d158222
--- /dev/null
+++ b/templates/job-restart.tmpl
@@ -0,0 +1 @@
+<P>Job {job_id} has been restarted.
diff --git a/templates/jobs.tmpl b/templates/jobs.tmpl
new file mode 100644
index 000000000..d168cc1ae
--- /dev/null
+++ b/templates/jobs.tmpl
@@ -0,0 +1,54 @@
+<P>{#job_id=0?No {?which_jobs=completed?Completed:Active} Jobs:
+<TABLE CELLPADDING="0" CELLSPACING="0" BORDER="0" WIDTH="100%">
+<TR BGCOLOR="#999966">
+ <TH WIDTH="16"><IMG SRC="/images/left.gif" ALT=""></TH>
+ <TH>ID&nbsp;</TH>
+ <TH>Name&nbsp;</TH>
+ <TH>User&nbsp;</TH>
+ <TH>Size&nbsp;</TH>
+ <TH>State&nbsp;</TH>
+ <TH>Control&nbsp;</TH>
+ <TH BGCOLOR="#cccc99" WIDTH="16"><IMG SRC="/images/right.gif" ALT=""></TH>
+</TR>
+<TR>
+ <TD HEIGHT="4"></TD>
+</TR>
+{[job_id]
+<TR VALIGN="TOP">
+ <TD HEIGHT="28"></TD>
+ <TD><A HREF="{job_printer_uri}">{job_printer_name}</A>-{job_id}&nbsp;</TD>
+ <TD>{?job_name=?Unknown:{job_name}}&nbsp;</TD>
+ <TD>{job_originating_user_name}&nbsp;</TD>
+ <TD>{job_k_octets}k&nbsp;</TD>
+ <TD>{job_state=3?pending since<BR>{time_at_creation}:{job_state=4?held since<BR>{time_at_creation}:
+ {job_state=5?processing since<BR>{time_at_processing}:{job_state=6?stopped at<BR>{time_at_completed}:
+ {job_state=7?cancelled at<BR>{time_at_completed}:{job_state=8?aborted:completed at<BR>{time_at_completed}}}}}}}&nbsp;</TD>
+ <TD>
+ {job_state>5?
+ {job_k_octets>0?
+ <A HREF="/admin/?op=restart-job&job_id={job_id}">
+ <IMG SRC="/images/restart-job.gif" ALT="Restart Job" BORDER="0"></A>
+ :}:}
+ {job_state>6?:
+ {job_state=4?
+ <A HREF="/admin/?op=release-job&job_id={job_id}">
+ <IMG SRC="/images/release-job.gif" ALT="Release Job" BORDER="0"></A>
+ :
+ <A HREF="/admin/?op=hold-job&job_id={job_id}">
+ <IMG SRC="/images/hold-job.gif" ALT="Hold Job" BORDER="0"></A>
+ }
+ <A HREF="/admin/?op=cancel-job&job_id={job_id}">
+ <IMG SRC="/images/cancel-job.gif" ALT="Cancel Job" BORDER="0"></A>
+ }
+ &nbsp;</TD>
+</TR>
+}
+</TABLE>
+}
+<P>{?which_jobs=?
+<A HREF="{?printer_name=?/jobs:/printers/{printer_name}}?which_jobs=completed">
+<IMG SRC="/images/show-completed.gif" BORDER="0" ALT="Show Completed Jobs"></A>
+:
+<A HREF="{?printer_name=?/jobs:/printers/{printer_name}}">
+<IMG SRC="/images/show-active.gif" BORDER="0" ALT="Show Active Jobs"></A>
+}
diff --git a/templates/modify-class.tmpl b/templates/modify-class.tmpl
new file mode 100644
index 000000000..17aeedbba
--- /dev/null
+++ b/templates/modify-class.tmpl
@@ -0,0 +1,34 @@
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+<TABLE CELLPADDING="0" CELLSPACING="0" BORDER="0" WIDTH="100%">
+<TR BGCOLOR="#999966">
+ <TH WIDTH="16"><IMG SRC="/images/left.gif" ALT=""></TH>
+ <TH COLSPAN="2">Modify Class {printer_name}</TH>
+ <TH BGCOLOR="#cccc99" WIDTH="16"><IMG SRC="/images/right.gif" ALT=""></TH>
+</TR>
+<TR>
+ <TD HEIGHT="4"></TD>
+</TR>
+<TR>
+ <TD></TD>
+ <TD ALIGN="RIGHT">Name:</TD>
+ <TD><INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+ {printer_name}</TD>
+</TR>
+<TR>
+ <TD></TD>
+ <TD ALIGN="RIGHT">Location:</TD>
+ <TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" VALUE="{?printer_location}" SIZE="40" MAXLENGTH="127"></TD>
+</TR>
+<TR>
+ <TD></TD>
+ <TD ALIGN="RIGHT">Description:</TD>
+ <TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" VALUE="{?printer_info}" SIZE="40" MAXLENGTH="127"></TD>
+</TR>
+<TR>
+ <TD></TD>
+ <TD></TD>
+ <TD><INPUT TYPE="IMAGE" SRC="/images/continue.gif" ALT="Continue" BORDER="0"></TD>
+</TR>
+</TABLE>
+</FORM>
diff --git a/templates/modify-printer.tmpl b/templates/modify-printer.tmpl
new file mode 100644
index 000000000..68e36cd8e
--- /dev/null
+++ b/templates/modify-printer.tmpl
@@ -0,0 +1,36 @@
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{?device_uri=?:<INPUT TYPE="HIDDEN" NAME="CURRENT_DEVICE_URI" VALUE="{device_uri}">}
+{?printer_make_and_model=?:<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE_AND_MODEL" VALUE="{printer_make_and_model}">}
+<TABLE CELLPADDING="0" CELLSPACING="0" BORDER="0" WIDTH="100%">
+<TR BGCOLOR="#999966">
+ <TH WIDTH="16"><IMG SRC="/images/left.gif" ALT=""></TH>
+ <TH COLSPAN="2">Modify Printer {printer_name}</TH>
+ <TH BGCOLOR="#cccc99" WIDTH="16"><IMG SRC="/images/right.gif" ALT=""></TH>
+</TR>
+<TR>
+ <TD HEIGHT="4"></TD>
+</TR>
+<TR>
+ <TD></TD>
+ <TD ALIGN="RIGHT">Name:</TD>
+ <TD><INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+ {printer_name}</TD>
+</TR>
+<TR>
+ <TD></TD>
+ <TD ALIGN="RIGHT">Location:</TD>
+ <TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" VALUE="{?printer_location}" SIZE="40" MAXLENGTH="127"></TD>
+</TR>
+<TR>
+ <TD></TD>
+ <TD ALIGN="RIGHT">Description:</TD>
+ <TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" VALUE="{?printer_info}" SIZE="40" MAXLENGTH="127"></TD>
+</TR>
+<TR>
+ <TD></TD>
+ <TD></TD>
+ <TD><INPUT TYPE="IMAGE" SRC="/images/continue.gif" ALT="Continue" BORDER="0"></TD>
+</TR>
+</TABLE>
+</FORM>
diff --git a/templates/option-boolean.tmpl b/templates/option-boolean.tmpl
new file mode 100644
index 000000000..a8360fc82
--- /dev/null
+++ b/templates/option-boolean.tmpl
@@ -0,0 +1,7 @@
+<TR>
+ <TD></TD>
+ <TD ALIGN="RIGHT">{keytext}:</TD>
+ <TD>
+ {[choices]<INPUT TYPE="RADIO" NAME="{keyword}" {choices={defchoice}?CHECKED:} VALUE="{choices}">{text}}
+ </TD>
+</TR>
diff --git a/templates/option-header.tmpl b/templates/option-header.tmpl
new file mode 100644
index 000000000..23a904178
--- /dev/null
+++ b/templates/option-header.tmpl
@@ -0,0 +1,8 @@
+<TR>
+ <TH BGCOLOR="#999966"><IMG SRC="/images/left.gif" ALT=""></TH>
+ <TH BGCOLOR="#999966" COLSPAN="2">{group}</TH>
+ <TH><IMG SRC="/images/right.gif" ALT=""></TH>
+</TR>
+<TR>
+ <TD HEIGHT="4"></TD>
+</TR>
diff --git a/templates/option-pickmany.tmpl b/templates/option-pickmany.tmpl
new file mode 100644
index 000000000..8340889b4
--- /dev/null
+++ b/templates/option-pickmany.tmpl
@@ -0,0 +1,7 @@
+<TR>
+ <TD></TD>
+ <TD ALIGN="RIGHT" VALIGN="TOP">{keytext}:</TD>
+ <TD><SELECT NAME="{keyword}" MULTIPLE SIZE="10">
+ {[choices]<OPTION {choices={defchoice}?SELECTED:} VALUE="{choices}">{text}}
+ </SELECT></TD>
+</TR>
diff --git a/templates/option-pickone.tmpl b/templates/option-pickone.tmpl
new file mode 100644
index 000000000..6880b968b
--- /dev/null
+++ b/templates/option-pickone.tmpl
@@ -0,0 +1,7 @@
+<TR>
+ <TD></TD>
+ <TD ALIGN="RIGHT">{keytext}:</TD>
+ <TD><SELECT NAME="{keyword}">
+ {[choices]<OPTION {choices={defchoice}?SELECTED:} VALUE="{choices}">{text}}
+ </SELECT></TD>
+</TR>
diff --git a/templates/option-trailer.tmpl b/templates/option-trailer.tmpl
new file mode 100644
index 000000000..803022837
--- /dev/null
+++ b/templates/option-trailer.tmpl
@@ -0,0 +1,8 @@
+<TR>
+ <TD></TD>
+ <TD></TD>
+ <TD><INPUT TYPE="IMAGE" SRC="/images/continue.gif" ALT="Continue" BORDER="0"></TD>
+</TR>
+<TR>
+ <TD HEIGHT="4"></TD>
+</TR>
diff --git a/templates/printer-accept.tmpl b/templates/printer-accept.tmpl
new file mode 100644
index 000000000..3a269eb0d
--- /dev/null
+++ b/templates/printer-accept.tmpl
@@ -0,0 +1 @@
+<P>Printer <A HREF="/printers/{printer_name}">{printer_name}</A> is now accepting jobs.
diff --git a/templates/printer-added.tmpl b/templates/printer-added.tmpl
new file mode 100644
index 000000000..ba5f550c2
--- /dev/null
+++ b/templates/printer-added.tmpl
@@ -0,0 +1,2 @@
+<P>Printer <A HREF="/printers/{printer_name}">{printer_name}</A> has been added
+successfully.
diff --git a/templates/printer-configured.tmpl b/templates/printer-configured.tmpl
new file mode 100644
index 000000000..7ec86879a
--- /dev/null
+++ b/templates/printer-configured.tmpl
@@ -0,0 +1,2 @@
+<P>Printer <A HREF="/printers/{printer_name}">{printer_name}</A> has
+been configured successfully.
diff --git a/templates/printer-confirm.tmpl b/templates/printer-confirm.tmpl
new file mode 100644
index 000000000..690c6479b
--- /dev/null
+++ b/templates/printer-confirm.tmpl
@@ -0,0 +1,6 @@
+<P><B>Warning:</B> About to delete printer {printer_name}! Do you wish to
+continue?
+
+<P ALIGN="CENTER">
+<A HREF="/admin/?op=delete-printer&printer_name={printer_name}&confirm=yes">
+<IMG SRC="/images/continue.gif" ALT="Continue" BORDER="0"></A>
diff --git a/templates/printer-deleted.tmpl b/templates/printer-deleted.tmpl
new file mode 100644
index 000000000..f1336b037
--- /dev/null
+++ b/templates/printer-deleted.tmpl
@@ -0,0 +1 @@
+<P>Printer {printer_name} has been deleted successfully.
diff --git a/templates/printer-modified.tmpl b/templates/printer-modified.tmpl
new file mode 100644
index 000000000..a16abd169
--- /dev/null
+++ b/templates/printer-modified.tmpl
@@ -0,0 +1,2 @@
+<P>Printer <A HREF="/printers/{printer_name}">{printer_name}</A> has been
+modified successfully.
diff --git a/templates/printer-reject.tmpl b/templates/printer-reject.tmpl
new file mode 100644
index 000000000..e73d87380
--- /dev/null
+++ b/templates/printer-reject.tmpl
@@ -0,0 +1 @@
+<P>Printer <A HREF="/printers/{printer_name}">{printer_name}</A> is no longer accepting jobs.
diff --git a/templates/printer-start.tmpl b/templates/printer-start.tmpl
new file mode 100644
index 000000000..e8d9f497f
--- /dev/null
+++ b/templates/printer-start.tmpl
@@ -0,0 +1,2 @@
+<P>Printer <A HREF="/printers/{printer_name}">{printer_name}</A> has been
+started.
diff --git a/templates/printer-stop.tmpl b/templates/printer-stop.tmpl
new file mode 100644
index 000000000..e01b82677
--- /dev/null
+++ b/templates/printer-stop.tmpl
@@ -0,0 +1,2 @@
+<P>Printer <A HREF="/printers/{printer_name}">{printer_name}</A> has been
+stopped.
diff --git a/templates/printers.tmpl b/templates/printers.tmpl
new file mode 100644
index 000000000..1505c36ba
--- /dev/null
+++ b/templates/printers.tmpl
@@ -0,0 +1,57 @@
+{#printer_name=0?No printers:
+<P><B>Default Destination:</B> <A HREF="{default_uri}">{default_name}</A>
+<P><TABLE CELLPADDING="0" CELLSPACING="0" BORDER="0" WIDTH="100%">
+{[printer_name]
+<TR>
+ <TH BGCOLOR="#999966"><IMG SRC="/images/left.gif" ALT=""></TH>
+ <TH BGCOLOR="#999966"><A HREF="{printer_uri_supported}">{printer_name}</A></TH>
+ <TH BGCOLOR="#999966">{printer_make_and_model}</TH>
+ <TH><IMG SRC="/images/right.gif" ALT=""></TH>
+</TR>
+<TR>
+ <TD HEIGHT="4"></TD>
+</TR>
+<TR>
+ <TD></TD>
+ <TD VALIGN="TOP"><A HREF="{printer_uri_supported}">
+ <IMG SRC="../images/printer-{printer_state=3?idle:{printer_state=4?processing:stopped}}.gif" BORDER="0" ALT=""></A>
+ </TD>
+ <TD VALIGN="TOP">Description: {printer_info}<BR>
+ Location: {printer_location}<BR>
+ Printer State: {printer_state=3?idle:{printer_state=4?processing:stopped}},
+ {printer_is_accepting_jobs=0?rejecting jobs:accepting jobs}.
+ {?printer_state_message=?:<BR><I>"{printer_state_message}"</I>}
+ {?device_uri=?:<BR>Device URI: {device_uri}}
+ <P>
+ <A HREF="{printer_uri_supported}?op=print-test-page">
+ <IMG SRC="/images/print-test-page.gif" ALT="Print Test Page" BORDER="0"></A>
+ {printer_state=5?
+ <A HREF="/admin/?op=start-printer&printer_name={printer_name}">
+ <IMG SRC="/images/start-printer.gif" ALT="Start Printer" BORDER="0"></A>
+ :
+ <A HREF="/admin/?op=stop-printer&printer_name={printer_name}">
+ <IMG SRC="/images/stop-printer.gif" ALT="Stop Printer" BORDER="0"></A>
+ }
+ {printer_is_accepting_jobs=0?
+ <A HREF="/admin/?op=accept-jobs&printer_name={printer_name}">
+ <IMG SRC="/images/accept-jobs.gif" ALT="Accept Jobs" BORDER="0"></A>
+ :
+ <A HREF="/admin/?op=reject-jobs&printer_name={printer_name}">
+ <IMG SRC="/images/reject-jobs.gif" ALT="Reject Jobs" BORDER="0"></A>
+ }
+ <A HREF="/admin/?op=modify-printer&printer_name={printer_name}">
+ <IMG SRC="/images/modify-printer.gif" ALT="Modify Printer" BORDER="0"></A>
+ <A HREF="/admin/?op=config-printer&printer_name={printer_name}">
+ <IMG SRC="/images/config-printer.gif" ALT="Configure Printer" BORDER="0"></A>
+ <A HREF="/admin/?op=delete-printer&printer_name={printer_name}">
+ <IMG SRC="/images/delete-printer.gif" ALT="Delete Printer" BORDER="0"></A>
+ </TD>
+</TR>
+<TR>
+ <TD>&nbsp;</TD>
+</TR>
+}
+</TABLE>
+}
+<P><A HREF="/admin/?op=add-printer">
+<IMG SRC="/images/add-printer.gif" ALT="Add Printer" BORDER="0"></A>
diff --git a/templates/test-page.tmpl b/templates/test-page.tmpl
new file mode 100644
index 000000000..5c5005438
--- /dev/null
+++ b/templates/test-page.tmpl
@@ -0,0 +1,2 @@
+<P>Test page sent; job ID is <A HREF="/printers/{printer_name}">
+{printer_name}-{job_id}</A>.
diff --git a/templates/trailer.tmpl b/templates/trailer.tmpl
new file mode 100644
index 000000000..bed0ed13c
--- /dev/null
+++ b/templates/trailer.tmpl
@@ -0,0 +1,7 @@
+<HR>
+<P>Copyright 1993-2002 Easy Software Products, All Rights Reserved.
+The Common UNIX Printing System, CUPS, and the CUPS logo
+are the trademark property of <A HREF="http://www.easysw.com">Easy Software Products</A>.
+All other trademarks are the property of their respective owners.
+</BODY>
+</HTML>
diff --git a/test/.cvsignore b/test/.cvsignore
new file mode 100644
index 000000000..07b5722d6
--- /dev/null
+++ b/test/.cvsignore
@@ -0,0 +1 @@
+ipptest
diff --git a/test/4.1-requests.test b/test/4.1-requests.test
new file mode 100644
index 000000000..ca0c8d326
--- /dev/null
+++ b/test/4.1-requests.test
@@ -0,0 +1,140 @@
+#
+# "$Id: 4.1-requests.test 1595 2001-03-01 20:40:17Z mike $"
+#
+# Verify that the server requires the following attributes:
+#
+# attributes-charset
+# attributes-natural-language
+# printer-uri/job-uri
+#
+{
+ # The name of the test...
+ NAME "No Attributes"
+
+ # The operation to use
+ OPERATION get-jobs
+
+ # What statuses are OK?
+ STATUS client-error-bad-request
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+}
+{
+ # The name of the test...
+ NAME "Charset Attribute"
+
+ # The operation to use
+ OPERATION get-jobs
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+
+ # What statuses are OK?
+ STATUS client-error-bad-request
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+}
+{
+ # The name of the test...
+ NAME "Language Attribute"
+
+ # The operation to use
+ OPERATION get-jobs
+
+ # The attributes to send
+ GROUP operation
+ ATTR language attributes-natural-language en
+
+ # What statuses are OK?
+ STATUS client-error-bad-request
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+}
+{
+ # The name of the test...
+ NAME "Language + Charset Attributes"
+
+ # The operation to use
+ OPERATION get-jobs
+
+ # The attributes to send
+ GROUP operation
+ ATTR language attributes-natural-language en
+ ATTR charset attributes-charset utf-8
+
+ # What statuses are OK?
+ STATUS client-error-bad-request
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+}
+{
+ # The name of the test...
+ NAME "Charset + Language Attributes"
+
+ # The operation to use
+ OPERATION get-jobs
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+
+ # What statuses are OK?
+ STATUS client-error-bad-request
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+}
+{
+ # The name of the test...
+ NAME "Charset + Language + Printer URI Attributes"
+
+ # The operation to use
+ OPERATION get-jobs
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+}
+{
+ # The name of the test...
+ NAME "Charset + Language + Job URI Attributes"
+
+ # The operation to use
+ OPERATION get-jobs
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri job-uri $method://$hostname:$port/jobs
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+}
+#
+# End of "$Id: 4.1-requests.test 1595 2001-03-01 20:40:17Z mike $"
+#
diff --git a/test/4.2-cups-printer-ops.test b/test/4.2-cups-printer-ops.test
new file mode 100644
index 000000000..8dfd724c5
--- /dev/null
+++ b/test/4.2-cups-printer-ops.test
@@ -0,0 +1,214 @@
+#
+# "$Id: 4.2-cups-printer-ops.test 1595 2001-03-01 20:40:17Z mike $"
+#
+# Verify that the CUPS printer operations work.
+#
+{
+ # The name of the test...
+ NAME "Add Printer Test1"
+
+ # The operation to use
+ OPERATION cups-add-printer
+ RESOURCE /admin/
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $method://$hostname:$port/printers/Test1
+
+ FILE testhp.ppd
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+}
+{
+ # The name of the test...
+ NAME "Verify Printer Test1 Added"
+
+ # The operation to use
+ OPERATION get-printer-attributes
+ RESOURCE /
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $method://$hostname:$port/printers/Test1
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+}
+{
+ # The name of the test...
+ NAME "Delete Printer Test1"
+
+ # The operation to use
+ OPERATION cups-delete-printer
+ RESOURCE /admin/
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $method://$hostname:$port/printers/Test1
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+}
+{
+ # The name of the test...
+ NAME "Verify Printer Test1 Deleted"
+
+ # The operation to use
+ OPERATION get-printer-attributes
+ RESOURCE /
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $method://$hostname:$port/printers/Test1
+
+ # What statuses are OK?
+ STATUS client-error-not-found
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+}
+{
+ # The name of the test...
+ NAME "Add Printer Test2"
+
+ # The operation to use
+ OPERATION cups-add-printer
+ RESOURCE /admin/
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $method://$hostname:$port/printers/Test2
+
+ FILE testps.ppd
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+}
+{
+ # The name of the test...
+ NAME "Verify Printer Test2 Added"
+
+ # The operation to use
+ OPERATION get-printer-attributes
+ RESOURCE /
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $method://$hostname:$port/printers/Test2
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+}
+{
+ # The name of the test...
+ NAME "Modify Printer Test2"
+
+ # The operation to use
+ OPERATION cups-add-printer
+ RESOURCE /admin/
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $method://$hostname:$port/printers/Test2
+
+ GROUP printer
+ ATTR uri device-uri file:/tmp/Test2
+ ATTR enum printer-state 3
+ ATTR boolean printer-is-accepting-jobs true
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+}
+{
+ # The name of the test...
+ NAME "Re-Add Printer Test1"
+
+ # The operation to use
+ OPERATION cups-add-printer
+ RESOURCE /admin/
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $method://$hostname:$port/printers/Test1
+
+ GROUP printer
+ ATTR uri device-uri file:/tmp/Test1
+ ATTR enum printer-state 3
+ ATTR boolean printer-is-accepting-jobs true
+
+ FILE testhp.ppd
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+}
+{
+ # The name of the test...
+ NAME "Verify Printer Test1 Re-Added"
+
+ # The operation to use
+ OPERATION get-printer-attributes
+ RESOURCE /
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $method://$hostname:$port/printers/Test1
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+}
+
+#
+# End of "$Id: 4.2-cups-printer-ops.test 1595 2001-03-01 20:40:17Z mike $"
+#
diff --git a/test/4.3-job-ops.test b/test/4.3-job-ops.test
new file mode 100644
index 000000000..831850ffe
--- /dev/null
+++ b/test/4.3-job-ops.test
@@ -0,0 +1,297 @@
+#
+# "$Id: 4.3-job-ops.test 1595 2001-03-01 20:40:17Z mike $"
+#
+# Verify that the IPP job operations work.
+#
+{
+ # The name of the test...
+ NAME "Print PostScript Job to Test1"
+
+ # The operation to use
+ OPERATION print-job
+ RESOURCE /printers/Test1
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $method://$hostname:$port/printers/Test1
+ ATTR name requesting-user-name $user
+
+ FILE testfile.ps
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+ EXPECT job-id
+}
+{
+ # The name of the test...
+ NAME "Get Job Attributes"
+
+ # The operation to use
+ OPERATION get-job-attributes
+ RESOURCE /jobs
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $method://$hostname:$port/printers/Test1
+ ATTR integer job-id $job-id
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+ EXPECT job-id
+ EXPECT job-uri
+ EXPECT job-state
+}
+{
+ # The name of the test...
+ NAME "Print PostScript Job to Test2"
+
+ # The operation to use
+ OPERATION print-job
+ RESOURCE /printers/Test2
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $method://$hostname:$port/printers/Test2
+ ATTR name requesting-user-name $user
+
+ FILE testfile.ps
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+ EXPECT job-id
+}
+{
+ # The name of the test...
+ NAME "Get Job Attributes"
+
+ # The operation to use
+ OPERATION get-job-attributes
+ RESOURCE /jobs
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $method://$hostname:$port/printers/Test2
+ ATTR integer job-id $job-id
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+ EXPECT job-id
+ EXPECT job-uri
+ EXPECT job-state
+}
+{
+ # The name of the test...
+ NAME "Print Text Job to Test1"
+
+ # The operation to use
+ OPERATION print-job
+ RESOURCE /printers/Test1
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $method://$hostname:$port/printers/Test1
+ ATTR name requesting-user-name $user
+
+ FILE testfile.txt
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+ EXPECT job-id
+}
+{
+ # The name of the test...
+ NAME "Print PDF Job to Test1"
+
+ # The operation to use
+ OPERATION print-job
+ RESOURCE /printers/Test1
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $method://$hostname:$port/printers/Test1
+ ATTR name requesting-user-name $user
+
+ FILE testfile.pdf
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+ EXPECT job-id
+}
+{
+ # The name of the test...
+ NAME "Print Image Job to Test1"
+
+ # The operation to use
+ OPERATION print-job
+ RESOURCE /printers/Test1
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $method://$hostname:$port/printers/Test1
+ ATTR name requesting-user-name $user
+
+ FILE testfile.jpg
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+ EXPECT job-id
+}
+{
+ # The name of the test...
+ NAME "Hold Job on Test1"
+
+ # The operation to use
+ OPERATION hold-job
+ RESOURCE /printers/Test1
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $method://$hostname:$port/printers/Test1
+ ATTR integer job-id $job-id
+ ATTR name requesting-user-name $user
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+}
+{
+ # The name of the test...
+ NAME "Release Job on Test1"
+
+ # The operation to use
+ OPERATION release-job
+ RESOURCE /printers/Test1
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $method://$hostname:$port/printers/Test1
+ ATTR integer job-id $job-id
+ ATTR name requesting-user-name $user
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+}
+{
+ # The name of the test...
+ NAME "Get Job List on Test1"
+
+ # The operation to use
+ OPERATION get-jobs
+ RESOURCE /printers/Test1
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $method://$hostname:$port/printers/Test1
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+}
+{
+ # The name of the test...
+ NAME "Get All Jobs"
+
+ # The operation to use
+ OPERATION get-jobs
+ RESOURCE /jobs
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri job-uri $method://$hostname:$port/jobs
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+ EXPECT job-uri
+ EXPECT job-id
+ EXPECT job-state
+}
+{
+ # The name of the test...
+ NAME "Cancel Job"
+
+ # The operation to use
+ OPERATION cancel-job
+ RESOURCE /jobs
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri job-uri $method://$hostname:$port/jobs/$job-id
+ ATTR name requesting-user-name $user
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+}
+
+#
+# End of "$Id: 4.3-job-ops.test 1595 2001-03-01 20:40:17Z mike $"
+#
diff --git a/test/5.1-lpadmin.sh b/test/5.1-lpadmin.sh
new file mode 100755
index 000000000..05036968e
--- /dev/null
+++ b/test/5.1-lpadmin.sh
@@ -0,0 +1,64 @@
+#!/bin/sh
+#
+# "$Id$"
+#
+# Test the lpadmin command.
+#
+# Copyright 1997-2002 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
+#
+
+echo "Add Printer Test"
+echo ""
+echo " lpadmin -p Test3 -v file:/dev/null -E -m deskjet.ppd"
+../systemv/lpadmin -p Test3 -v file:/dev/null -E -m deskjet.ppd 2>&1
+if test $? != 0; then
+ echo " FAILED"
+ exit 1
+else
+ echo " PASSED"
+fi
+echo ""
+
+echo "Modify Printer Test"
+echo ""
+echo " lpadmin -p Test3 -v file:/tmp/Test3 -o PageSize=A4"
+../systemv/lpadmin -p Test3 -v file:/tmp/Test3 -o PageSize=A4 2>&1
+if test $? != 0; then
+ echo " FAILED"
+ exit 1
+else
+ echo " PASSED"
+fi
+echo ""
+
+echo "Delete Printer Test"
+echo ""
+echo " lpadmin -x Test3"
+../systemv/lpadmin -x Test3 2>&1
+if test $? != 0; then
+ echo " FAILED"
+ exit 1
+else
+ echo " PASSED"
+fi
+echo ""
+
+#
+# End of "$Id$".
+#
diff --git a/test/5.2-lpc.sh b/test/5.2-lpc.sh
new file mode 100755
index 000000000..d7feb1aea
--- /dev/null
+++ b/test/5.2-lpc.sh
@@ -0,0 +1,40 @@
+#!/bin/sh
+#
+# "$Id$"
+#
+# Test the lpc command.
+#
+# Copyright 1997-2002 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
+#
+
+echo "LPC Test"
+echo ""
+echo " lpc status"
+../berkeley/lpc status 2>&1
+if test $? != 0; then
+ echo " FAILED"
+ exit 1
+else
+ echo " PASSED"
+fi
+echo ""
+
+#
+# End of "$Id$".
+#
diff --git a/test/5.3-lpq.sh b/test/5.3-lpq.sh
new file mode 100755
index 000000000..27f3d569c
--- /dev/null
+++ b/test/5.3-lpq.sh
@@ -0,0 +1,40 @@
+#!/bin/sh
+#
+# "$Id$"
+#
+# Test the lpq command.
+#
+# Copyright 1997-2002 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
+#
+
+echo "LPQ Test"
+echo ""
+echo " lpq"
+../berkeley/lpq 2>&1
+if test $? != 0; then
+ echo " FAILED"
+ exit 1
+else
+ echo " PASSED"
+fi
+echo ""
+
+#
+# End of "$Id$".
+#
diff --git a/test/5.4-lpstat.sh b/test/5.4-lpstat.sh
new file mode 100755
index 000000000..2153b28b1
--- /dev/null
+++ b/test/5.4-lpstat.sh
@@ -0,0 +1,40 @@
+#!/bin/sh
+#
+# "$Id$"
+#
+# Test the lpstat command.
+#
+# Copyright 1997-2002 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
+#
+
+echo "LPSTAT Test"
+echo ""
+echo " lpstat -t"
+../systemv/lpstat -t 2>&1
+if test $? != 0; then
+ echo " FAILED"
+ exit 1
+else
+ echo " PASSED"
+fi
+echo ""
+
+#
+# End of "$Id$".
+#
diff --git a/test/5.5-lp.sh b/test/5.5-lp.sh
new file mode 100755
index 000000000..32c12eb35
--- /dev/null
+++ b/test/5.5-lp.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+#
+# "$Id$"
+#
+# Test the lp command.
+#
+# Copyright 1997-2002 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
+#
+
+echo "LP Default Test"
+echo ""
+echo " lp testfile.jpg"
+../systemv/lp testfile.jpg 2>&1
+if test $? != 0; then
+ echo " FAILED"
+ exit 1
+else
+ echo " PASSED"
+fi
+echo ""
+
+echo "LP Destination Test"
+echo ""
+echo " lp -d Test1 testfile.jpg"
+../systemv/lp -d Test1 testfile.jpg 2>&1
+if test $? != 0; then
+ echo " FAILED"
+ exit 1
+else
+ echo " PASSED"
+fi
+echo ""
+
+#
+# End of "$Id$".
+#
diff --git a/test/5.6-lpr.sh b/test/5.6-lpr.sh
new file mode 100755
index 000000000..4b7efb627
--- /dev/null
+++ b/test/5.6-lpr.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+#
+# "$Id$"
+#
+# Test the lpr command.
+#
+# Copyright 1997-2002 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
+#
+
+echo "LPR Default Test"
+echo ""
+echo " lpr testfile.jpg"
+../berkeley/lpr testfile.jpg 2>&1
+if test $? != 0; then
+ echo " FAILED"
+ exit 1
+else
+ echo " PASSED"
+fi
+echo ""
+
+echo "LPR Destination Test"
+echo ""
+echo " lpr -P Test1 testfile.jpg"
+../berkeley/lpr -P Test1 testfile.jpg 2>&1
+if test $? != 0; then
+ echo " FAILED"
+ exit 1
+else
+ echo " PASSED"
+fi
+echo ""
+
+#
+# End of "$Id$".
+#
diff --git a/test/5.7-lprm.sh b/test/5.7-lprm.sh
new file mode 100755
index 000000000..81c26b5d4
--- /dev/null
+++ b/test/5.7-lprm.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+#
+# "$Id$"
+#
+# Test the lprm command.
+#
+# Copyright 1997-2002 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
+#
+
+echo "LPRM Current Test"
+echo ""
+echo " lprm"
+../berkeley/lprm 2>&1
+if test $? != 0; then
+ echo " FAILED"
+ exit 1
+else
+ echo " PASSED"
+fi
+echo ""
+
+echo "LPRM Destination Test"
+echo ""
+echo " lprm Test1"
+../berkeley/lprm Test1 2>&1
+if test $? != 0; then
+ echo " FAILED"
+ exit 1
+else
+ echo " PASSED"
+fi
+echo ""
+
+#
+# End of "$Id$".
+#
diff --git a/test/5.8-cancel.sh b/test/5.8-cancel.sh
new file mode 100755
index 000000000..fa1cf2b47
--- /dev/null
+++ b/test/5.8-cancel.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+#
+# "$Id$"
+#
+# Test the cancel command.
+#
+# Copyright 1997-2002 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
+#
+
+echo "Cancel Destination Test"
+echo ""
+echo " cancel Test1"
+../systemv/cancel Test1 2>&1
+if test $? != 0; then
+ echo " FAILED"
+ exit 1
+else
+ echo " PASSED"
+fi
+echo ""
+
+echo "Cancel All Test"
+echo ""
+echo " cancel -a -"
+../systemv/cancel -a - 2>&1
+if test $? != 0; then
+ echo " FAILED"
+ exit 1
+else
+ echo " PASSED"
+fi
+echo ""
+
+#
+# End of "$Id$".
+#
diff --git a/test/5.9-lpinfo.sh b/test/5.9-lpinfo.sh
new file mode 100755
index 000000000..bfeb9d668
--- /dev/null
+++ b/test/5.9-lpinfo.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+#
+# "$Id$"
+#
+# Test the lpinfo command.
+#
+# Copyright 1997-2002 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
+#
+
+echo "LPINFO Devices Test"
+echo ""
+echo " lpinfo -v"
+../systemv/lpinfo -v 2>&1
+if test $? != 0; then
+ echo " FAILED"
+ exit 1
+else
+ echo " PASSED"
+fi
+echo ""
+
+echo "LPINFO Drivers Test"
+echo ""
+echo " lpinfo -m"
+../systemv/lpinfo -m 2>&1
+if test $? != 0; then
+ echo " FAILED"
+ exit 1
+else
+ echo " PASSED"
+fi
+echo ""
+
+#
+# End of "$Id$".
+#
diff --git a/test/Makefile b/test/Makefile
new file mode 100644
index 000000000..21f07e1e6
--- /dev/null
+++ b/test/Makefile
@@ -0,0 +1,72 @@
+#
+# "$Id$"
+#
+# IPP test makefile for the Common UNIX Printing System (CUPS).
+#
+# Copyright 1997-2002 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
+
+
+#
+# Make all targets...
+#
+
+all: ipptest
+
+
+#
+# Clean all object files...
+#
+
+clean:
+ $(RM) ipptest ipptest.o
+
+
+#
+# Install all targets...
+#
+
+install:
+
+
+#
+# ipptest
+#
+
+ipptest: ipptest.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o ipptest ipptest.o $(LIBS)
+
+ipptest.o: ../cups/cups.h ../Makedefs
+
+
+#
+# purify target for doing tests on the CUPS API...
+#
+
+purify: ipptest.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ purify $(CC) $(LDFLAGS) -o ipptest.pure ipptest.o $(LIBS)
+
+
+#
+# End of "$Id$".
+#
diff --git a/test/create-job-format.test b/test/create-job-format.test
new file mode 100644
index 000000000..87d94a5b6
--- /dev/null
+++ b/test/create-job-format.test
@@ -0,0 +1,56 @@
+# Print a test page using create-job + send-document, specifying the
+# document format.
+{
+ # The name of the test...
+ NAME "Print test page using create-job"
+
+ # The resource to use for the POST
+ # RESOURCE /admin
+
+ # The operation to use
+ OPERATION create-job
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+
+ GROUP job
+ ATTR integer copies 1
+
+ # What statuses are OK?
+ STATUS ok
+ STATUS ok-subst
+
+ # What attributes do we expect?
+ EXPECT job-id
+ EXPECT job-uri
+}
+{
+ # The name of the test...
+ NAME "... and send-document"
+
+ # The resource to use for the POST
+ # RESOURCE /admin
+
+ # The operation to use
+ OPERATION send-document
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR integer job-id $job-id
+ ATTR name requesting-user-name $user
+ ATTR mimetype document-format application/postscript
+ ATTR boolean last-document true
+
+ FILE ../data/testprint.ps
+
+ # What statuses are OK?
+ STATUS ok
+ STATUS ok-subst
+}
diff --git a/test/create-job-sheets.test b/test/create-job-sheets.test
new file mode 100644
index 000000000..d15bb7d4b
--- /dev/null
+++ b/test/create-job-sheets.test
@@ -0,0 +1,55 @@
+# Test create-job + send-document with job-sheets attribute
+{
+ # The name of the test...
+ NAME "Print test page using create-job"
+
+ # The resource to use for the POST
+ # RESOURCE /admin
+
+ # The operation to use
+ OPERATION create-job
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+
+ GROUP job
+ ATTR integer copies 1
+ ATTR name job-sheets standard
+
+ # What statuses are OK?
+ STATUS ok
+ STATUS ok-subst
+
+ # What attributes do we expect?
+ EXPECT job-id
+ EXPECT job-uri
+}
+{
+ # The name of the test...
+ NAME "... and send-document"
+
+ # The resource to use for the POST
+ # RESOURCE /admin
+
+ # The operation to use
+ OPERATION send-document
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR integer job-id $job-id
+ ATTR name requesting-user-name $user
+ ATTR boolean last-document true
+
+ FILE ../data/testprint.ps
+
+ # What statuses are OK?
+ STATUS ok
+ STATUS ok-subst
+}
diff --git a/test/create-job-timeout.test b/test/create-job-timeout.test
new file mode 100644
index 000000000..b0e035797
--- /dev/null
+++ b/test/create-job-timeout.test
@@ -0,0 +1,55 @@
+# Print a test page using create-job + send-document, but don't send
+# last-document = true
+{
+ # The name of the test...
+ NAME "Print test page using create-job"
+
+ # The resource to use for the POST
+ # RESOURCE /admin
+
+ # The operation to use
+ OPERATION create-job
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+
+ GROUP job
+ ATTR integer copies 1
+
+ # What statuses are OK?
+ STATUS ok
+ STATUS ok-subst
+
+ # What attributes do we expect?
+ EXPECT job-id
+ EXPECT job-uri
+}
+{
+ # The name of the test...
+ NAME "... and send-document"
+
+ # The resource to use for the POST
+ # RESOURCE /admin
+
+ # The operation to use
+ OPERATION send-document
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR integer job-id $job-id
+ ATTR name requesting-user-name $user
+ ATTR mimetype document-format application/octet-stream
+
+ FILE ../data/testprint.ps
+
+ # What statuses are OK?
+ STATUS ok
+ STATUS ok-subst
+}
diff --git a/test/create-job.test b/test/create-job.test
new file mode 100644
index 000000000..3cfaac532
--- /dev/null
+++ b/test/create-job.test
@@ -0,0 +1,54 @@
+# Print a test page using create-job + send-document
+{
+ # The name of the test...
+ NAME "Print test page using create-job"
+
+ # The resource to use for the POST
+ # RESOURCE /admin
+
+ # The operation to use
+ OPERATION create-job
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+
+ GROUP job
+ ATTR integer copies 1
+
+ # What statuses are OK?
+ STATUS ok
+ STATUS ok-subst
+
+ # What attributes do we expect?
+ EXPECT job-id
+ EXPECT job-uri
+}
+{
+ # The name of the test...
+ NAME "... and send-document"
+
+ # The resource to use for the POST
+ # RESOURCE /admin
+
+ # The operation to use
+ OPERATION send-document
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR integer job-id $job-id
+ ATTR name requesting-user-name $user
+ ATTR boolean last-document true
+
+ FILE ../data/testprint.ps
+
+ # What statuses are OK?
+ STATUS ok
+ STATUS ok-subst
+}
diff --git a/test/get-devices.test b/test/get-devices.test
new file mode 100644
index 000000000..76bb5ec76
--- /dev/null
+++ b/test/get-devices.test
@@ -0,0 +1,21 @@
+# Get devices using CUPS-get-devices
+{
+ # The name of the test...
+ NAME "Get devices using CUPS-get-devices"
+
+ # The resource to use for the POST
+ # RESOURCE /admin
+
+ # The operation to use
+ OPERATION CUPS-get-devices
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+
+ # What statuses are OK?
+ STATUS ok
+ STATUS ok-subst
+}
diff --git a/test/get-job-attributes.test b/test/get-job-attributes.test
new file mode 100644
index 000000000..35b241b06
--- /dev/null
+++ b/test/get-job-attributes.test
@@ -0,0 +1,27 @@
+# Test get-job-attributes by sending a print job, getting the attributes,
+# and cancelling it.
+{
+ # The name of the test...
+ NAME "Get job info with get-job-attributes"
+
+ # The resource to use for the POST
+ # RESOURCE /admin
+
+ # The operation to use
+ OPERATION get-job-attributes
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri job-uri $uri
+
+ # What statuses are OK?
+ #STATUS ok
+ #STATUS ok-subst
+
+ # What attributes do we expect?
+ EXPECT job-uri
+ EXPECT job-state
+ EXPECT bogus-attribute
+}
diff --git a/test/get-job-attributes2.test b/test/get-job-attributes2.test
new file mode 100644
index 000000000..6a8673f88
--- /dev/null
+++ b/test/get-job-attributes2.test
@@ -0,0 +1,28 @@
+# Test get-job-attributes
+{
+ # The name of the test...
+ NAME "get-job-attributes"
+
+ # The resource to use for the POST
+ # RESOURCE /admin
+
+ # The operation to use
+ OPERATION get-job-attributes
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri job-uri $uri
+
+ # What statuses are OK?
+ STATUS ok
+ STATUS ok-subst
+
+ # What attributes do we expect?
+ EXPECT job-uri
+ EXPECT job-state
+ EXPECT time-at-creation
+ EXPECT time-at-completed
+ EXPECT time-at-processing
+}
diff --git a/test/get-ppds.test b/test/get-ppds.test
new file mode 100644
index 000000000..90f59eb6e
--- /dev/null
+++ b/test/get-ppds.test
@@ -0,0 +1,21 @@
+# Get PPD files using CUPS-get-ppds
+{
+ # The name of the test...
+ NAME "Get PPD files using CUPS-get-ppds"
+
+ # The resource to use for the POST
+ # RESOURCE /admin
+
+ # The operation to use
+ OPERATION CUPS-get-ppds
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+
+ # What statuses are OK?
+ STATUS ok
+ STATUS ok-subst
+}
diff --git a/test/get-printer-attributes.test b/test/get-printer-attributes.test
new file mode 100644
index 000000000..79d4dfffa
--- /dev/null
+++ b/test/get-printer-attributes.test
@@ -0,0 +1,44 @@
+# Get printer attributes using get-printer-attributes
+{
+ # The name of the test...
+ NAME "Get printer attributes using get-printer-attributes"
+
+ # The resource to use for the POST
+ # RESOURCE /admin
+
+ # The operation to use
+ OPERATION get-printer-attributes
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT charset-configured
+ EXPECT charset-supported
+ EXPECT compression-supported
+ EXPECT document-format-default
+ EXPECT document-format-supported
+ EXPECT generated-natural-language-supported
+ EXPECT ipp-versions-supported
+ EXPECT natural-language-configured
+ EXPECT operations-supported
+ EXPECT printer-info
+ EXPECT printer-is-accepting-jobs
+ EXPECT printer-location
+ EXPECT printer-make-and-model
+ EXPECT printer-more-info
+ EXPECT printer-name
+ EXPECT printer-state
+ EXPECT printer-state-reasons
+ EXPECT printer-up-time
+ EXPECT printer-uri-supported
+ EXPECT uri-authentication-supported
+ EXPECT uri-security-supported
+ EXPECT foo
+}
diff --git a/test/ipptest.c b/test/ipptest.c
new file mode 100644
index 000000000..14da08f69
--- /dev/null
+++ b/test/ipptest.c
@@ -0,0 +1,808 @@
+/*
+ * "$Id$"
+ *
+ * IPP test command for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2002 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 do tests.
+ * do_tests() - Do tests as specified in the test file.
+ * get_operation() - Get an IPP opcode from an operation name...
+ * get_status() - Get an IPP status from a status name...
+ * get_tag() - Get an IPP value or group tag from a name...
+ * get_token() - Get a token from a file.
+ * print_attr() - Print an attribute on the screen.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <cups/string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include <cups/cups.h>
+#include <cups/language.h>
+
+
+/*
+ * Local globals...
+ */
+
+
+/*
+ * Local functions...
+ */
+
+int do_tests(const char *, const char *);
+ipp_op_t get_operation(const char *);
+ipp_status_t get_status(const char *);
+ipp_tag_t get_tag(const char *);
+char *get_token(FILE *, char *, int);
+void print_attr(ipp_attribute_t *);
+
+
+/*
+ * 'main()' - Parse options and do tests.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i; /* Looping var */
+ int status; /* Status of tests... */
+
+
+ /*
+ * We need at least:
+ *
+ * testipp URL testfile
+ */
+
+ if (argc < 3)
+ {
+ fputs("Usage: testipp URL testfile [ ... testfileN ]\n", stderr);
+ return (1);
+ }
+
+ /*
+ * Run tests...
+ */
+
+ for (i = 2, status = 1; status && i < argc; i ++)
+ status = status && do_tests(argv[1], argv[i]);
+
+ /*
+ * Exit...
+ */
+
+ return (!status);
+}
+
+
+/*
+ * 'do_tests()' - Do tests as specified in the test file.
+ */
+
+int /* 1 = success, 0 = failure */
+do_tests(const char *uri, /* I - URI to connect on */
+ const char *testfile) /* I - Test file to use */
+{
+ int i; /* Looping var */
+ http_t *http; /* HTTP connection to server */
+ char method[HTTP_MAX_URI], /* URI method */
+ userpass[HTTP_MAX_URI], /* username:password */
+ server[HTTP_MAX_URI], /* Server */
+ resource[HTTP_MAX_URI]; /* Resource path */
+ int port; /* Port number */
+ FILE *fp; /* Test file */
+ char token[1024], /* Token from file */
+ *tokenptr, /* Pointer into token */
+ temp[1024], /* Temporary string */
+ *tempptr; /* Pointer into temp string */
+ ipp_t *request; /* IPP request */
+ ipp_t *response; /* IPP response */
+ ipp_op_t op; /* Operation */
+ ipp_tag_t group; /* Current group */
+ ipp_tag_t value; /* Current value type */
+ ipp_attribute_t *attrptr; /* Attribute pointer */
+ char attr[128]; /* Attribute name */
+ int num_statuses; /* Number of valid status codes */
+ ipp_status_t statuses[100]; /* Valid status codes */
+ int num_expects; /* Number of expected attributes */
+ char *expects[100]; /* Expected attributes */
+ char name[1024]; /* Name of test */
+ char filename[1024]; /* Filename */
+ int pass; /* Did we pass the test? */
+ int job_id; /* Job ID from last operation */
+
+
+ /*
+ * Open the test file...
+ */
+
+ if ((fp = fopen(testfile, "r")) == NULL)
+ {
+ printf("Unable to open test file %s - %s\n", testfile, strerror(errno));
+ return (0);
+ }
+
+ /*
+ * Connect to the server...
+ */
+
+ httpSeparate(uri, method, userpass, server, &port, resource);
+ if ((http = httpConnect(server, port)) == NULL)
+ {
+ printf("Unable to connect to %s on port %d - %s\n", server, port,
+ strerror(errno));
+ return (0);
+ }
+
+ /*
+ * Loop on tests...
+ */
+
+ printf("\"%s\":\n", testfile);
+ pass = 1;
+ job_id = 0;
+
+ while (get_token(fp, token, sizeof(token)) != NULL)
+ {
+ /*
+ * Expect an open brace...
+ */
+
+ if (strcmp(token, "{") != 0)
+ {
+ printf("Unexpected token %s seen - aborting test!\n", token);
+ httpClose(http);
+ return (0);
+ }
+
+ /*
+ * Initialize things...
+ */
+
+ httpSeparate(uri, method, userpass, server, &port, resource);
+
+ request = ippNew();
+ op = (ipp_op_t)0;
+ group = IPP_TAG_OPERATION;
+ value = IPP_TAG_ZERO;
+ num_statuses = 0;
+ num_expects = 0;
+ filename[0] = '\0';
+
+ strcpy(name, testfile);
+ if (strrchr(name, '.') != NULL)
+ *strrchr(name, '.') = '\0';
+
+ /*
+ * Parse until we see a close brace...
+ */
+
+ while (get_token(fp, token, sizeof(token)) != NULL)
+ {
+ if (strcmp(token, "}") == 0)
+ break;
+ else if (strcasecmp(token, "NAME") == 0)
+ {
+ /*
+ * Name of test...
+ */
+
+ get_token(fp, name, sizeof(name));
+ }
+ else if (strcasecmp(token, "RESOURCE") == 0)
+ {
+ /*
+ * Resource name...
+ */
+
+ get_token(fp, resource, sizeof(resource));
+ }
+ else if (strcasecmp(token, "OPERATION") == 0)
+ {
+ /*
+ * Operation...
+ */
+
+ get_token(fp, token, sizeof(token));
+ op = get_operation(token);
+ }
+ else if (strcasecmp(token, "GROUP") == 0)
+ {
+ /*
+ * Attribute group...
+ */
+
+ get_token(fp, token, sizeof(token));
+ group = get_tag(token);
+ }
+ else if (strcasecmp(token, "ATTR") == 0)
+ {
+ /*
+ * Attribute...
+ */
+
+ get_token(fp, token, sizeof(token));
+ value = get_tag(token);
+ get_token(fp, attr, sizeof(attr));
+ get_token(fp, temp, sizeof(temp));
+
+ token[sizeof(token) - 1] = '\0';
+
+ for (tempptr = temp, tokenptr = token;
+ *tempptr && tokenptr < (token + sizeof(token) - 1);)
+ if (*tempptr == '$')
+ {
+ /*
+ * Substitute a string/number...
+ */
+
+ if (strncasecmp(tempptr + 1, "uri", 3) == 0)
+ {
+ strncpy(tokenptr, uri, sizeof(token) - 1 - (tokenptr - token));
+ tempptr += 4;
+ }
+ else if (strncasecmp(tempptr + 1, "method", 6) == 0)
+ {
+ strncpy(tokenptr, method, sizeof(token) - 1 - (tokenptr - token));
+ tempptr += 7;
+ }
+ else if (strncasecmp(tempptr + 1, "username", 8) == 0)
+ {
+ strncpy(tokenptr, userpass, sizeof(token) - 1 - (tokenptr - token));
+ tempptr += 9;
+ }
+ else if (strncasecmp(tempptr + 1, "hostname", 8) == 0)
+ {
+ strncpy(tokenptr, server, sizeof(token) - 1 - (tokenptr - token));
+ tempptr += 9;
+ }
+ else if (strncasecmp(tempptr + 1, "port", 4) == 0)
+ {
+ snprintf(tokenptr, sizeof(token) - 1 - (tokenptr - token),
+ "%d", port);
+ tempptr += 5;
+ }
+ else if (strncasecmp(tempptr + 1, "resource", 8) == 0)
+ {
+ strncpy(tokenptr, resource, sizeof(token) - 1 - (tokenptr - token));
+ tempptr += 9;
+ }
+ else if (strncasecmp(tempptr + 1, "job-id", 6) == 0)
+ {
+ snprintf(tokenptr, sizeof(token) - 1 - (tokenptr - token),
+ "%d", job_id);
+ tempptr += 7;
+ }
+ else if (strncasecmp(tempptr + 1, "user", 4) == 0)
+ {
+ strncpy(tokenptr, cupsUser(), sizeof(token) - 1 - (tokenptr - token));
+ tempptr += 5;
+ }
+ else
+ {
+ *tokenptr++ = *tempptr ++;
+ *tokenptr = '\0';
+ }
+
+ tokenptr += strlen(tokenptr);
+ }
+ else
+ {
+ *tokenptr++ = *tempptr++;
+ *tokenptr = '\0';
+ }
+
+ switch (value)
+ {
+ case IPP_TAG_BOOLEAN :
+ if (strcasecmp(token, "true") == 0)
+ ippAddBoolean(request, group, attr, 1);
+ else
+ ippAddBoolean(request, group, attr, atoi(token));
+ break;
+
+ case IPP_TAG_INTEGER :
+ case IPP_TAG_ENUM :
+ ippAddInteger(request, group, value, attr, atoi(token));
+ break;
+
+ case IPP_TAG_RESOLUTION :
+ puts(" ERROR: resolution tag not yet supported!");
+ break;
+
+ case IPP_TAG_RANGE :
+ puts(" ERROR: range tag not yet supported!");
+ break;
+
+ default :
+ ippAddString(request, group, value, attr, NULL, token);
+ break;
+ }
+ }
+ else if (strcasecmp(token, "FILE") == 0)
+ {
+ /*
+ * File...
+ */
+
+ get_token(fp, filename, sizeof(filename));
+ }
+ else if (strcasecmp(token, "STATUS") == 0)
+ {
+ /*
+ * Status...
+ */
+
+ get_token(fp, token, sizeof(token));
+ statuses[num_statuses] = get_status(token);
+ num_statuses ++;
+ }
+ else if (strcasecmp(token, "EXPECT") == 0)
+ {
+ /*
+ * Status...
+ */
+
+ get_token(fp, token, sizeof(token));
+ expects[num_expects] = strdup(token);
+ num_expects ++;
+ }
+ else
+ {
+ printf("Unexpected token %s seen - aborting test!\n", token);
+ httpClose(http);
+ ippDelete(request);
+ return (0);
+ }
+ }
+
+ /*
+ * Submit the IPP request...
+ */
+
+ request->request.op.operation_id = op;
+ request->request.op.request_id = 1;
+
+ printf(" %-60.60s [ ]", name);
+ fflush(stdout);
+
+ if (filename[0])
+ response = cupsDoFileRequest(http, request, resource, filename);
+ else
+ response = cupsDoRequest(http, request, resource);
+
+ if (response == NULL)
+ {
+ time_t curtime;
+
+ curtime = time(NULL);
+
+ printf("\b\b\b\b\bFAIL]\n");
+ printf(" ERROR %x\n", cupsLastError());
+ printf(" (%s) @ %s\n",
+ ippErrorString(cupsLastError()), ctime(&curtime));
+ pass = 0;
+ }
+ else
+ {
+ if ((attrptr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER)) != NULL)
+ job_id = attrptr->values[0].integer;
+
+ for (i = 0; i < num_statuses; i ++)
+ if (response->request.status.status_code == statuses[i])
+ break;
+
+ if (i == num_statuses && num_statuses > 0)
+ {
+ printf("\b\b\b\b\bFAIL]\n");
+ printf(" STATUS %x\n", response->request.status.status_code);
+ printf(" (%s)\n",
+ ippErrorString(response->request.status.status_code));
+ printf(" (%d bytes in response)\n", ippLength(response));
+
+ pass = 0;
+ }
+ else
+ {
+ for (i = 0; i < num_expects; i ++)
+ if (ippFindAttribute(response, expects[i], IPP_TAG_ZERO) == NULL)
+ {
+ if (pass)
+ {
+ printf("\b\b\b\b\bFAIL]\n");
+ printf(" (%d bytes in response)\n", ippLength(response));
+ pass = 0;
+ }
+
+ printf(" EXPECTED %s\n", expects[i]);
+ }
+
+ if (pass)
+ {
+ printf("\b\b\b\b\bPASS]\n");
+ printf(" (%d bytes in response)\n", ippLength(response));
+ }
+ else
+ {
+ puts(" RECEIVED");
+ printf(" status-code = %04x\n",
+ response->request.status.status_code);
+
+ for (attrptr = response->attrs; attrptr != NULL; attrptr = attrptr->next)
+ print_attr(attrptr);
+ }
+ }
+
+ ippDelete(response);
+ }
+
+ for (i = 0; i < num_expects; i ++)
+ free(expects[i]);
+
+ if (!pass)
+ break;
+ }
+
+ fclose(fp);
+ httpClose(http);
+
+ return (pass);
+}
+
+
+/*
+ * 'get_operation()' - Get an IPP opcode from an operation name...
+ */
+
+ipp_op_t
+get_operation(const char *name)
+{
+ int i;
+ static char *ipp_ops[] =
+ {
+ "",
+ "",
+ "print-job",
+ "print-uri",
+ "validate-job",
+ "create-job",
+ "send-document",
+ "send-uri",
+ "cancel-job",
+ "get-job-attributes",
+ "get-jobs",
+ "get-printer-attributes",
+ "hold-job",
+ "release-job",
+ "restart-job",
+ "",
+ "pause-printer",
+ "resume-printer",
+ "purge-jobs",
+ "set-printer-attributes",
+ "set-job-attributes",
+ "get-printer-supported-values"
+ },
+ *cups_ops[] =
+ {
+ "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",
+ "cups-move-job"
+ };
+
+
+ for (i = 0; i < (sizeof(ipp_ops) / sizeof(ipp_ops[0])); i ++)
+ if (strcasecmp(name, ipp_ops[i]) == 0)
+ return ((ipp_op_t)i);
+
+ for (i = 0; i < (sizeof(cups_ops) / sizeof(cups_ops[0])); i ++)
+ if (strcasecmp(name, cups_ops[i]) == 0)
+ return ((ipp_op_t)(i + 0x4001));
+
+ return ((ipp_op_t)0);
+}
+
+
+/*
+ * 'get_status()' - Get an IPP status from a status name...
+ */
+
+ipp_status_t
+get_status(const char *name)
+{
+ int i;
+ static const char *status_oks[] = /* "OK" status codes */
+ {
+ "successful-ok",
+ "successful-ok-ignored-or-substituted-attributes",
+ "successful-ok-conflicting-attributes"
+ },
+ *status_400s[] = /* Client errors */
+ {
+ "client-error-bad-request",
+ "client-error-forbidden",
+ "client-error-not-authenticated",
+ "client-error-not-authorized",
+ "client-error-not-possible",
+ "client-error-timeout",
+ "client-error-not-found",
+ "client-error-gone",
+ "client-error-request-entity-too-large",
+ "client-error-request-value-too-long",
+ "client-error-document-format-not-supported",
+ "client-error-attributes-or-values-not-supported",
+ "client-error-uri-scheme-not-supported",
+ "client-error-charset-not-supported",
+ "client-error-conflicting-attributes",
+ "client-error-compression-not-supported",
+ "client-error-compression-error",
+ "client-error-document-format-error",
+ "client-error-document-access-error"
+ },
+ *status_500s[] = /* Server errors */
+ {
+ "server-error-internal-error",
+ "server-error-operation-not-supported",
+ "server-error-service-unavailable",
+ "server-error-version-not-supported",
+ "server-error-device-error",
+ "server-error-temporary-error",
+ "server-error-not-accepting-jobs",
+ "server-error-busy",
+ "server-error-job-canceled",
+ "server-error-multiple-document-jobs-not-supported"
+ };
+
+
+ for (i = 0; i < (sizeof(status_oks) / sizeof(status_oks[0])); i ++)
+ if (strcasecmp(name, status_oks[i]) == 0)
+ return ((ipp_status_t)i);
+
+ for (i = 0; i < (sizeof(status_400s) / sizeof(status_400s[0])); i ++)
+ if (strcasecmp(name, status_400s[i]) == 0)
+ return ((ipp_status_t)(i + 0x400));
+
+ for (i = 0; i < (sizeof(status_500s) / sizeof(status_500s[0])); i ++)
+ if (strcasecmp(name, status_500s[i]) == 0)
+ return ((ipp_status_t)(i + 0x500));
+
+ return ((ipp_status_t)-1);
+}
+
+
+/*
+ * 'get_tag()' - Get an IPP value or group tag from a name...
+ */
+
+ipp_tag_t
+get_tag(const char *name)
+{
+ int i;
+ static char *names[] =
+ {
+ "zero", "operation", "job", "end", "printer",
+ "unsupported-group", "", "", "", "", "", "", "",
+ "", "", "", "unsupported-value", "default",
+ "unknown", "novalue", "", "notsettable",
+ "deleteattr", "anyvalue", "", "", "", "", "", "",
+ "", "", "", "integer", "boolean", "enum", "", "",
+ "", "", "", "", "", "", "", "", "", "", "string",
+ "date", "resolution", "range", "collection",
+ "textlang", "namelang", "", "", "", "", "", "", "",
+ "", "", "", "text", "name", "", "keyword", "uri",
+ "urischeme", "charset", "language", "mimetype"
+ };
+
+
+ for (i = 0; i < (sizeof(names) / sizeof(names[0])); i ++)
+ if (strcasecmp(name, names[i]) == 0)
+ return ((ipp_tag_t)i);
+
+ return (IPP_TAG_ZERO);
+}
+
+
+/*
+ * 'get_token()' - Get a token from a file.
+ */
+
+char * /* O - Token from file or NULL on EOF */
+get_token(FILE *fp, /* I - File to read from */
+ char *buf, /* I - Buffer to read into */
+ int buflen) /* I - Length of buffer */
+{
+ int ch, /* Character from file */
+ quote; /* Quoting character */
+ char *bufptr, /* Pointer into buffer */
+ *bufend; /* End of buffer */
+
+
+ for (;;)
+ {
+ /*
+ * Skip whitespace...
+ */
+
+ while (isspace(ch = getc(fp)));
+
+ /*
+ * Read a token...
+ */
+
+ if (ch == EOF)
+ return (NULL);
+ else if (ch == '\'' || ch == '\"')
+ {
+ /*
+ * Quoted text...
+ */
+
+ quote = ch;
+ bufptr = buf;
+ bufend = buf + buflen - 1;
+
+ while ((ch = getc(fp)) != EOF)
+ if (ch == quote)
+ break;
+ else if (bufptr < bufend)
+ *bufptr++ = ch;
+
+ *bufptr = '\0';
+ return (buf);
+ }
+ else if (ch == '#')
+ {
+ /*
+ * Comment...
+ */
+
+ while ((ch = getc(fp)) != EOF)
+ if (ch == '\n')
+ break;
+ }
+ else
+ {
+ /*
+ * Whitespace delimited text...
+ */
+
+ ungetc(ch, fp);
+
+ bufptr = buf;
+ bufend = buf + buflen - 1;
+
+ while ((ch = getc(fp)) != EOF)
+ if (isspace(ch) || ch == '#')
+ break;
+ else if (bufptr < bufend)
+ *bufptr++ = ch;
+
+ if (ch == '#')
+ ungetc(ch, fp);
+
+ *bufptr = '\0';
+ return (buf);
+ }
+ }
+}
+
+
+/*
+ * 'print_attr()' - Print an attribute on the screen.
+ */
+
+void
+print_attr(ipp_attribute_t *attr) /* I - Attribute to print */
+{
+ int i; /* Looping var */
+
+
+ if (attr->name == NULL)
+ {
+ puts(" -- separator --");
+ return;
+ }
+
+ printf(" %s = ", attr->name);
+
+ switch (attr->value_tag)
+ {
+ case IPP_TAG_INTEGER :
+ case IPP_TAG_ENUM :
+ for (i = 0; i < attr->num_values; i ++)
+ printf("%d ", attr->values[i].integer);
+ break;
+
+ case IPP_TAG_BOOLEAN :
+ for (i = 0; i < attr->num_values; i ++)
+ if (attr->values[i].boolean)
+ printf("true ");
+ else
+ printf("false ");
+ break;
+
+ case IPP_TAG_NOVALUE :
+ printf("novalue");
+ break;
+
+ case IPP_TAG_RANGE :
+ for (i = 0; i < attr->num_values; i ++)
+ printf("%d-%d ", attr->values[i].range.lower,
+ attr->values[i].range.upper);
+ break;
+
+ case IPP_TAG_RESOLUTION :
+ for (i = 0; i < attr->num_values; i ++)
+ printf("%dx%d%s ", attr->values[i].resolution.xres,
+ attr->values[i].resolution.yres,
+ attr->values[i].resolution.units == IPP_RES_PER_INCH ?
+ "dpi" : "dpc");
+ break;
+
+ case IPP_TAG_STRING :
+ case IPP_TAG_TEXT :
+ case IPP_TAG_NAME :
+ case IPP_TAG_KEYWORD :
+ case IPP_TAG_CHARSET :
+ case IPP_TAG_URI :
+ case IPP_TAG_MIMETYPE :
+ case IPP_TAG_LANGUAGE :
+ for (i = 0; i < attr->num_values; i ++)
+ printf("\"%s\" ", attr->values[i].string.text);
+ break;
+
+ case IPP_TAG_TEXTLANG :
+ case IPP_TAG_NAMELANG :
+ for (i = 0; i < attr->num_values; i ++)
+ printf("\"%s\",%s ", attr->values[i].string.text,
+ attr->values[i].string.charset);
+ break;
+
+ default :
+ break; /* anti-compiler-warning-code */
+ }
+
+ putchar('\n');
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/test/print-job-hold.test b/test/print-job-hold.test
new file mode 100644
index 000000000..6bdaa8381
--- /dev/null
+++ b/test/print-job-hold.test
@@ -0,0 +1,33 @@
+# Test print-job and job-hold-until attribute
+{
+ # The name of the test...
+ NAME "Print with print-job + job-hold-until"
+
+ # The resource to use for the POST
+ # RESOURCE /admin
+
+ # The operation to use
+ OPERATION print-job
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+ ATTR mimetype document-format application/postscript
+ ATTR keyword job-hold-until indefinite
+
+ GROUP job
+ ATTR integer copies 1
+
+ FILE ../data/testprint.ps
+
+ # What statuses are OK?
+ STATUS ok
+ STATUS ok-subst
+
+ # What attributes do we expect?
+ EXPECT job-id
+ EXPECT job-uri
+}
diff --git a/test/print-job.test b/test/print-job.test
new file mode 100644
index 000000000..5bbc92c91
--- /dev/null
+++ b/test/print-job.test
@@ -0,0 +1,32 @@
+# Print a test page using print-job
+{
+ # The name of the test...
+ NAME "Print test page using print-job"
+
+ # The resource to use for the POST
+ # RESOURCE /admin
+
+ # The operation to use
+ OPERATION print-job
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+ ATTR mimetype document-format application/postscript
+
+ GROUP job
+ ATTR integer copies 1
+
+ FILE ../data/testprint.ps
+
+ # What statuses are OK?
+ STATUS ok
+ STATUS ok-subst
+
+ # What attributes do we expect?
+ EXPECT job-id
+ EXPECT job-uri
+}
diff --git a/test/run-stp-tests.sh b/test/run-stp-tests.sh
new file mode 100755
index 000000000..f45a6d96e
--- /dev/null
+++ b/test/run-stp-tests.sh
@@ -0,0 +1,327 @@
+#!/bin/sh
+#
+# "$Id$"
+#
+# Perform the complete set of IPP compliance tests specified in the
+# CUPS Software Test Plan.
+#
+# Copyright 1997-2002 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
+#
+
+#
+# Make the IPP test program...
+#
+
+make
+
+#
+# Information for the server/tests...
+#
+
+user=`whoami`
+port=8631
+cwd=`pwd`
+root=`dirname $cwd`
+
+#
+# Start by creating temporary directories for the tests...
+#
+
+rm -rf /tmp/$user
+mkdir /tmp/$user
+mkdir /tmp/$user/bin
+mkdir /tmp/$user/bin/backend
+mkdir /tmp/$user/bin/filter
+mkdir /tmp/$user/certs
+mkdir /tmp/$user/share
+mkdir /tmp/$user/share/banners
+mkdir /tmp/$user/share/model
+mkdir /tmp/$user/interfaces
+mkdir /tmp/$user/log
+mkdir /tmp/$user/ppd
+mkdir /tmp/$user/spool
+mkdir /tmp/$user/spool/temp
+mkdir /tmp/$user/ssl
+
+ln -s $root/backend/http /tmp/$user/bin/backend
+ln -s $root/backend/ipp /tmp/$user/bin/backend
+ln -s $root/backend/lpd /tmp/$user/bin/backend
+ln -s $root/backend/parallel /tmp/$user/bin/backend
+ln -s $root/backend/serial /tmp/$user/bin/backend
+ln -s $root/backend/socket /tmp/$user/bin/backend
+ln -s $root/backend/usb /tmp/$user/bin/backend
+ln -s $root/cgi-bin /tmp/$user/bin
+ln -s $root/filter/hpgltops /tmp/$user/bin/filter
+ln -s $root/filter/imagetops /tmp/$user/bin/filter
+ln -s $root/filter/imagetoraster /tmp/$user/bin/filter
+ln -s $root/filter/pstops /tmp/$user/bin/filter
+ln -s $root/filter/rastertoepson /tmp/$user/bin/filter
+ln -s $root/filter/rastertohp /tmp/$user/bin/filter
+ln -s $root/filter/texttops /tmp/$user/bin/filter
+ln -s $root/pdftops/pdftops /tmp/$user/bin/filter
+ln -s $root/pstoraster/pstoraster /tmp/$user/bin/filter
+
+ln -s $root/data/classified /tmp/$user/share/banners
+ln -s $root/data/confidential /tmp/$user/share/banners
+ln -s $root/data/secret /tmp/$user/share/banners
+ln -s $root/data/standard /tmp/$user/share/banners
+ln -s $root/data/topsecret /tmp/$user/share/banners
+ln -s $root/data/unclassified /tmp/$user/share/banners
+ln -s $root/data /tmp/$user/share/charsets
+ln -s $root/data /tmp/$user/share
+ln -s $root/fonts /tmp/$user/share
+ln -s $root/ppd/*.ppd /tmp/$user/share/model
+ln -s $root/pstoraster /tmp/$user/share
+ln -s $root/templates /tmp/$user/share
+
+#
+# Then create the necessary config files...
+#
+
+cat >/tmp/$user/cupsd.conf <<EOF
+Browsing Off
+Listen 127.0.0.1:$port
+User $user
+ServerRoot /tmp/$user
+ServerBin /tmp/$user/bin
+DataDir /tmp/$user/share
+FontPath /tmp/$user/share/fonts
+DocumentRoot $root/doc
+RequestRoot /tmp/$user/spool
+TempDir /tmp/$user/spool/temp
+AccessLog /tmp/$user/log/access_log
+ErrorLog /tmp/$user/log/error_log
+PageLog /tmp/$user/log/page_log
+LogLevel debug2
+PreserveJobHistory Yes
+<Location />
+Order deny,allow
+Deny from all
+Allow from 127.0.0.1
+</Location>
+<Location /admin>
+Order deny,allow
+Deny from all
+Allow from 127.0.0.1
+Require valid-user
+</Location>
+EOF
+
+touch /tmp/$user/classes.conf
+touch /tmp/$user/printers.conf
+
+cp $root/conf/mime.types /tmp/$user/mime.types
+cp $root/conf/mime.convs /tmp/$user/mime.convs
+
+#
+# Setup the paths...
+#
+
+if test "x$LD_LIBRARY_PATH" = x; then
+ LD_LIBRARY_PATH="$root/cups:$root/filter"
+else
+ LD_LIBRARY_PATH="$root/cups:$root/filter:$LD_LIBRARY_PATH"
+fi
+
+export LD_LIBRARY_PATH
+
+if test "x$DYLD_LIBRARY_PATH" = x; then
+ DYLD_LIBRARY_PATH="$root/cups:$root/filter"
+else
+ DYLD_LIBRARY_PATH="$root/cups:$root/filter:$DYLD_LIBRARY_PATH"
+fi
+
+export DYLD_LIBRARY_PATH
+
+CUPS_SERVERROOT=/tmp/$user; export CUPS_SERVERROOT
+CUPS_DATADIR=/tmp/$user/share; export CUPS_DATADIR
+
+#
+# Set a new home directory to avoid getting user options mixed in...
+#
+
+HOME=/tmp/$user
+export HOME
+
+#
+# Start the server; run as foreground daemon in the background...
+#
+
+echo "Starting scheduler..."
+
+../scheduler/cupsd -c /tmp/$user/cupsd.conf -f &
+cupsd=$!
+
+echo "Scheduler is PID $cupsd; run debugger now if you need to."
+echo ""
+echo "Press ENTER to continue..."
+read junk
+
+IPP_PORT=$port; export IPP_PORT
+
+while true; do
+ running=`../systemv/lpstat -r 2>/dev/null`
+ if test "x$running" = "xscheduler is running"; then
+ break
+ fi
+
+ echo "Waiting for scheduler to become ready..."
+ sleep 10
+done
+
+#
+# Create the test report source file...
+#
+
+strfile=cups-str-1.1-`date +%Y-%m-%d`-`whoami`.shtml
+
+rm -f $strfile
+cat str-header.html >$strfile
+
+#
+# Run the IPP tests...
+#
+
+echo "Running IPP compliance tests..."
+
+echo "<H1>IPP Compliance Tests</H1>" >>$strfile
+echo "<P>This section provides the results to the IPP compliance tests" >>$strfile
+echo "outlined in the CUPS Software Test Plan. These tests were run on" >>$strfile
+echo `date "+%Y-%m-%d"` by `whoami` on `hostname`. >>$strfile
+echo "<PRE>" >>$strfile
+
+fail=0
+for file in 4*.test; do
+ echo "Performing $file..."
+ echo "" >>$strfile
+
+ ./ipptest ipp://localhost:$port/printers $file >>$strfile
+ status=$?
+
+ if test $status != 0; then
+ echo Test failed.
+ fail=`expr $fail + 1`
+ fi
+done
+
+echo "</PRE>" >>$strfile
+
+#
+# Run the command tests...
+#
+
+echo "Running command tests..."
+
+echo "<H1>Command Tests</H1>" >>$strfile
+echo "<P>This section provides the results to the command tests" >>$strfile
+echo "outlined in the CUPS Software Test Plan. These tests were run on" >>$strfile
+echo `date "+%Y-%m-%d"` by `whoami` on `hostname`. >>$strfile
+echo "<PRE>" >>$strfile
+
+for file in 5*.sh; do
+ echo "Performing $file..."
+ echo "" >>$strfile
+ echo "\"$file\":" >>$strfile
+
+ sh $file >>$strfile
+ status=$?
+
+ if test $status != 0; then
+ echo Test failed.
+ fail=`expr $fail + 1`
+ fi
+done
+
+echo "</PRE>" >>$strfile
+
+#
+# Wait for jobs to complete...
+#
+
+while true; do
+ jobs=`../systemv/lpstat 2>/dev/null`
+ if test "x$jobs" = "x"; then
+ break
+ fi
+
+ echo "Waiting for jobs to complete..."
+ sleep 10
+done
+
+#
+# Stop the server...
+#
+
+kill $cupsd
+
+#
+# Append the log files for post-mortim...
+#
+
+echo "<H1>Log Files</H1>" >>$strfile
+
+echo "<H2>access_log</H2>" >>$strfile
+echo "<PRE>" >>$strfile
+cat /tmp/$user/log/access_log >>$strfile
+echo "</PRE>" >>$strfile
+
+echo "<H2>error_log</H2>" >>$strfile
+echo "<PRE>" >>$strfile
+cat /tmp/$user/log/error_log >>$strfile
+echo "</PRE>" >>$strfile
+
+echo "<H2>page_log</H2>" >>$strfile
+echo "<PRE>" >>$strfile
+cat /tmp/$user/log/page_log >>$strfile
+echo "</PRE>" >>$strfile
+
+#
+# Format the reports and tell the user where to find them...
+#
+
+echo "Formatting reports..."
+
+cat str-trailer.html >>$strfile
+
+htmlfile=`basename $strfile .shtml`.html
+pdffile=`basename $strfile .shtml`.pdf
+
+htmldoc --numbered --verbose --titleimage ../doc/images/cups-large.gif \
+ -f $htmlfile $strfile
+htmldoc --numbered --verbose --titleimage ../doc/images/cups-large.gif \
+ -f $pdffile $strfile
+
+echo ""
+
+if test $fail != 0; then
+ echo "$fail tests failed."
+else
+ echo "All tests were successful."
+fi
+
+echo ""
+echo "See the following files for details:"
+echo ""
+echo " $htmlfile"
+echo " $pdffile"
+echo ""
+
+#
+# End of "$Id$"
+#
diff --git a/test/set-attrs-hold.test b/test/set-attrs-hold.test
new file mode 100644
index 000000000..377819ae4
--- /dev/null
+++ b/test/set-attrs-hold.test
@@ -0,0 +1,180 @@
+# Test print-job and later job-hold-until attribute
+{
+ # The name of the test...
+ NAME "Disable printer..."
+
+ # The resource to use for the POST
+ RESOURCE /admin/
+
+ # The operation to use
+ OPERATION pause-printer
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+
+ # What statuses are OK?
+ STATUS ok
+ STATUS ok-subst
+}
+
+{
+ # The name of the test...
+ NAME "Print job"
+
+ # The resource to use for the POST
+ # RESOURCE /admin
+
+ # The operation to use
+ OPERATION print-job
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+ ATTR mimetype document-format application/postscript
+
+ GROUP job
+ ATTR integer copies 1
+
+ FILE ../data/testprint.ps
+
+ # What statuses are OK?
+ STATUS ok
+ STATUS ok-subst
+
+ # What attributes do we expect?
+ EXPECT job-id
+ EXPECT job-uri
+}
+
+{
+ # The name of the test...
+ NAME "Get job attrs"
+
+ # The resource to use for the POST
+ RESOURCE /
+
+ # The operation to use
+ OPERATION get-job-attributes
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR integer job-id $job-id
+
+ # What statuses are OK?
+ STATUS ok
+ STATUS ok-subst
+
+ # What attributes do we expect?
+ EXPECT job-state
+ EXPECT job-hold-until
+}
+
+{
+ # The name of the test...
+ NAME "Set job attrs with job-hold-until"
+
+ # The resource to use for the POST
+ # RESOURCE /admin
+
+ # The operation to use
+ OPERATION set-job-attributes
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR integer job-id $job-id
+ ATTR name requesting-user-name $user
+
+ GROUP job
+ ATTR name job-hold-until 00:30:00
+
+ # What statuses are OK?
+ STATUS ok
+ STATUS ok-subst
+}
+
+{
+ # The name of the test...
+ NAME "Get job attrs again"
+
+ # The resource to use for the POST
+ RESOURCE /
+
+ # The operation to use
+ OPERATION get-job-attributes
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR integer job-id $job-id
+
+ # What statuses are OK?
+ STATUS ok
+ STATUS ok-subst
+
+ # What attributes do we expect?
+ EXPECT job-state
+ EXPECT job-hold-until
+}
+
+{
+ # The name of the test...
+ NAME "Enable printer..."
+
+ # The resource to use for the POST
+ RESOURCE /admin/
+
+ # The operation to use
+ OPERATION resume-printer
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+
+ # What statuses are OK?
+ STATUS ok
+ STATUS ok-subst
+}
+
+{
+ # The name of the test...
+ NAME "Get job attrs (last time)"
+
+ # The resource to use for the POST
+ RESOURCE /
+
+ # The operation to use
+ OPERATION get-job-attributes
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR integer job-id $job-id
+
+ # What statuses are OK?
+ STATUS ok
+ STATUS ok-subst
+
+ # What attributes do we expect?
+ EXPECT job-state
+ EXPECT job-hold-until
+}
diff --git a/test/str-header.html b/test/str-header.html
new file mode 100644
index 000000000..a2e93e876
--- /dev/null
+++ b/test/str-header.html
@@ -0,0 +1,35 @@
+<HTML>
+<HEAD>
+ <META NAME="Description" CONTENT="Common UNIX Printing System Software Test Report">
+ <META NAME="COPYRIGHT" CONTENT="Copyright 1997-2001, All Rights Reserved">
+ <META NAME="DOCNUMBER" CONTENT="CUPS-STR-1.1">
+ <META NAME="Author" CONTENT="Easy Software Products">
+ <TITLE>CUPS Software Test Report</TITLE>
+</HEAD>
+<BODY>
+
+<H1>Scope</H1>
+
+<H2>Identification</H2>
+
+<P>This software test report provides detailed test results that
+are used to evaluate the stability and compliance of the Common
+UNIX Printing System ("CUPS") Version 1.1.
+
+<EMBED SRC="../doc/system-overview.shtml">
+
+<H2>Document Overview</H2>
+
+<P>This software test plan is organized into the following sections:
+
+<UL>
+ <LI>1 - Scope</LI>
+ <LI>2 - References</LI>
+ <LI>3 - IPP Compliance Tests</LI>
+ <LI>4 - Command Tests</LI>
+ <LI>5 - Log Files</LI>
+ <LI>A - Glossary</LI>
+</UL>
+
+<EMBED SRC="../doc/references.shtml">
+
diff --git a/test/str-trailer.html b/test/str-trailer.html
new file mode 100644
index 000000000..4c8ddd526
--- /dev/null
+++ b/test/str-trailer.html
@@ -0,0 +1,5 @@
+<EMBED SRC="../doc/glossary.shtml">
+
+
+</BODY>
+</HTML>
diff --git a/test/testfile.jpg b/test/testfile.jpg
new file mode 100644
index 000000000..9f4b39938
--- /dev/null
+++ b/test/testfile.jpg
Binary files differ
diff --git a/test/testfile.pdf b/test/testfile.pdf
new file mode 100644
index 000000000..8ae73cb58
--- /dev/null
+++ b/test/testfile.pdf
Binary files differ
diff --git a/test/testfile.ps b/test/testfile.ps
new file mode 100644
index 000000000..4610affff
--- /dev/null
+++ b/test/testfile.ps
@@ -0,0 +1,512 @@
+%!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-2002 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)
+
+ % Figure out the sizes of things...
+ /wheelSize % size of wheels
+ pageWidth pageHeight lt
+ { pageWidth 9 mul }
+ { pageHeight 7 mul }
+ ifelse def
+
+ % Create fonts...
+ /bigFont /Helvetica-Bold findfont % bigFont = Helvetica-Bold
+ pageHeight 3 mul scalefont def % size = pageHeight * 3 (nominally 33)
+
+ /mediumFont /Helvetica findfont % mediumFont = Helvetica
+ pageHeight 1.5 mul scalefont def % size = pageHeight * 1.5 (nominally 16.5)
+
+ /smallFont /Times-Roman findfont % smallFont = Times-Roman
+ pageHeight scalefont def % size = pageHeight (nominally 11)
+
+ % 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...
+ wheelSize
+
+ % 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...
+ wheelSize
+
+ % 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...
+ pageHeight 15 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
+ pageHeight -2 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
+ pageHeight sub % 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
+ pageHeight 2 mul sub % 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
+ pageHeight sub % 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
+ pageHeight 2 mul sub % 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
+ pageHeight sub % 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
+ pageHeight 2 mul sub % 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
+ pageHeight sub % 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...
+ pageHeight 15 mul % Height of interpreter information
+
+ 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
+ pageHeight 2 mul sub % 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
+ pageHeight 2 mul sub % Move down...
+ 2 copy moveto % Move to x & y
+ (Version: ) RIGHT % Label
+ version show % Version
+ ( \() show % " ("
+ 1 revision NUMBER % Revision
+ (\)) show % ")"
+
+ % Product
+ pageHeight 2 mul sub % Move down...
+ 2 copy moveto % Move to x & y
+ (Product: ) RIGHT % Label
+ product show % Product name
+
+ % Serial Number
+ pageHeight 2 mul sub % 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
+ pageHeight 10 mul % Bottom of page
+ 2 copy moveto % Position text
+ (Printed Using CUPS v1.1.x) CENTER % Show text centered
+
+ pageHeight 2 mul sub % Move down...
+ 2 copy moveto % Position text
+ smallFont setfont % Font
+ (Copyright 1993-2002 Easy Software Products, All Rights Reserved.) CENTER
+ pageHeight sub % Move down...
+ 2 copy moveto % Position text
+ (CUPS, and the CUPS logo are the trademark property of) CENTER
+ pageHeight sub % Move down...
+ 2 copy moveto % Position text
+ (Easy Software Products, 44141 Airport View Drive, Suite 204,) CENTER
+ pageHeight sub % Move down...
+ 2 copy moveto % Position text
+ (Hollywood, Maryland, 20636-3111, USA.) CENTER
+
+ % Then the CUPS logo....
+ gsave
+ pageWidth 4 mul
+ pageHeight 4 mul
+ translate
+ pageWidth 9 mul CUPSLOGO
+ grestore
+
+ % And the ESP logo....
+ gsave
+ pageWidth 59 mul
+ pageHeight 4 mul
+ translate
+ pageWidth 6 mul ESPLOGO
+ grestore
+% Show the page...
+grestore
+showpage
+%
+% End of "$Id: testfile.ps 2010 2002-01-02 17:59:21Z mike $".
+%
+%%EOF
diff --git a/test/testfile.txt b/test/testfile.txt
new file mode 100644
index 000000000..46bbf0848
--- /dev/null
+++ b/test/testfile.txt
@@ -0,0 +1,60 @@
+All work and no play makes Johhny a dull boy. All work and no
+play makes Johhny a dull boy. All work and no play makes Johhny
+a dull boy. All work and no play makes Johhny a dull boy. All
+work and no play makes Johhny a dull boy. All work and no play
+makes Johhny a dull boy. All work and no play makes Johhny a
+dull boy. All work and no play makes Johhny a dull boy. All
+work and no play makes Johhny a dull boy. All work and no play
+makes Johhny a dull boy. All work and no play makes Johhny a
+dull boy. All work and no play makes Johhny a dull boy. All
+work and no play makes Johhny a dull boy. All work and no play
+makes Johhny a dull boy. All work and no play makes Johhny a
+dull boy. All work and no play makes Johhny a dull boy. All
+work and no play makes Johhny a dull boy. All work and no play
+makes Johhny a dull boy. All work and no play makes Johhny a
+dull boy. All work and no play makes Johhny a dull boy. All
+work and no play makes Johhny a dull boy. All work and no play
+makes Johhny a dull boy. All work and no play makes Johhny a
+dull boy. All work and no play makes Johhny a dull boy. All
+work and no play makes Johhny a dull boy. All work and no play
+makes Johhny a dull boy. All work and no play makes Johhny a
+dull boy. All work and no play makes Johhny a dull boy. All
+work and no play makes Johhny a dull boy. All work and no play
+makes Johhny a dull boy. All work and no play makes Johhny a
+dull boy. All work and no play makes Johhny a dull boy. All
+work and no play makes Johhny a dull boy. All work and no play
+makes Johhny a dull boy. All work and no play makes Johhny a
+dull boy. All work and no play makes Johhny a dull boy. All
+work and no play makes Johhny a dull boy. All work and no play
+makes Johhny a dull boy. All work and no play makes Johhny a
+dull boy. All work and no play makes Johhny a dull boy. All
+work and no play makes Johhny a dull boy. All work and no play
+makes Johhny a dull boy. All work and no play makes Johhny a
+dull boy. All work and no play makes Johhny a dull boy. All
+work and no play makes Johhny a dull boy. All work and no play
+makes Johhny a dull boy. All work and no play makes Johhny a
+dull boy. All work and no play makes Johhny a dull boy. All
+work and no play makes Johhny a dull boy. All work and no play
+makes Johhny a dull boy. All work and no play makes Johhny a
+dull boy. All work and no play makes Johhny a dull boy. All
+work and no play makes Johhny a dull boy. All work and no play
+makes Johhny a dull boy. All work and no play makes Johhny a
+dull boy. All work and no play makes Johhny a dull boy. All
+work and no play makes Johhny a dull boy. All work and no play
+makes Johhny a dull boy. All work and no play makes Johhny a
+dull boy. All work and no play makes Johhny a dull boy. All
+work and no play makes Johhny a dull boy. All work and no play
+makes Johhny a dull boy. All work and no play makes Johhny a
+dull boy. All work and no play makes Johhny a dull boy. All
+work and no play makes Johhny a dull boy. All work and no play
+makes Johhny a dull boy. All work and no play makes Johhny a
+dull boy. All work and no play makes Johhny a dull boy. All
+work and no play makes Johhny a dull boy. All work and no play
+makes Johhny a dull boy. All work and no play makes Johhny a
+dull boy. All work and no play makes Johhny a dull boy. All
+work and no play makes Johhny a dull boy. All work and no play
+makes Johhny a dull boy. All work and no play makes Johhny a
+dull boy. All work and no play makes Johhny a dull boy. All
+work and no play makes Johhny a dull boy. All work and no play
+makes Johhny a dull boy. All work and no play makes Johhny a
+dull boy. All work and no play makes Johhny a dull boy.
diff --git a/test/testhp.ppd b/test/testhp.ppd
new file mode 100644
index 000000000..c77d22178
--- /dev/null
+++ b/test/testhp.ppd
@@ -0,0 +1,195 @@
+*PPD-Adobe: "4.3"
+*%
+*% "$Id$"
+*%
+*% Test HP PPD file for the Common UNIX Printing System (CUPS).
+*%
+*% Copyright 1997-2002 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: "TESTHP.PPD"
+*Manufacturer: "ESP"
+*Product: "(CUPS v1.1)"
+*cupsVersion: 1.1
+*cupsManualCopies: True
+*cupsFilter: "application/vnd.cups-raster 50 rastertohp"
+*ModelName: "Test HP Printer"
+*ShortNickName: "Test HP Printer"
+*NickName: "Test HP Printer CUPS v1.1"
+*PSVersion: "(3010.000) 550"
+*LanguageLevel: "3"
+*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 Tabloid *InputSlot Envelope
+*UIConstraints: *PageSize A3 *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/US Letter: "<</PageSize[612 792]/ImagingBBox null>>setpagedevice"
+*PageSize Legal/US Legal: "<</PageSize[612 1008]/ImagingBBox null>>setpagedevice"
+*PageSize Executive/US Executive: "<</PageSize[522 756]/ImagingBBox null>>setpagedevice"
+*PageSize Tabloid/US Tabloid: "<</PageSize[792 1224]/ImagingBBox null>>setpagedevice"
+*PageSize A3/A3: "<</PageSize[842 1191]/ImagingBBox null>>setpagedevice"
+*PageSize A4/A4: "<</PageSize[595 842]/ImagingBBox null>>setpagedevice"
+*PageSize A5/A5: "<</PageSize[421 595]/ImagingBBox null>>setpagedevice"
+*PageSize B5/B5 (JIS): "<</PageSize[516 729]/ImagingBBox null>>setpagedevice"
+*PageSize EnvISOB5/Envelope B5: "<</PageSize[499 709]/ImagingBBox null>>setpagedevice"
+*PageSize Env10/Envelope #10: "<</PageSize[297 684]/ImagingBBox null>>setpagedevice"
+*PageSize EnvC5/Envelope C5: "<</PageSize[459 649]/ImagingBBox null>>setpagedevice"
+*PageSize EnvDL/Envelope DL: "<</PageSize[312 624]/ImagingBBox null>>setpagedevice"
+*PageSize EnvMonarch/Envelope Monarch: "<</PageSize[279 540]/ImagingBBox null>>setpagedevice"
+*CloseUI: *PageSize
+
+*OpenUI *PageRegion: PickOne
+*OrderDependency: 10 AnySetup *PageRegion
+*DefaultPageRegion: Letter
+*PageRegion Letter/US Letter: "<</PageSize[612 792]/ImagingBBox null>>setpagedevice"
+*PageRegion Legal/US Legal: "<</PageSize[612 1008]/ImagingBBox null>>setpagedevice"
+*PageRegion Executive/US Executive: "<</PageSize[522 756]/ImagingBBox null>>setpagedevice"
+*PageRegion Tabloid/US Tabloid: "<</PageSize[792 1224]/ImagingBBox null>>setpagedevice"
+*PageRegion A3/A3: "<</PageSize[842 1191]/ImagingBBox null>>setpagedevice"
+*PageRegion A4/A4: "<</PageSize[595 842]/ImagingBBox null>>setpagedevice"
+*PageRegion A5/A5: "<</PageSize[421 595]/ImagingBBox null>>setpagedevice"
+*PageRegion B5/B5 (JIS): "<</PageSize[516 729]/ImagingBBox null>>setpagedevice"
+*PageRegion EnvISOB5/Envelope B5: "<</PageSize[499 709]/ImagingBBox null>>setpagedevice"
+*PageRegion Env10/Envelope #10: "<</PageSize[297 684]/ImagingBBox null>>setpagedevice"
+*PageRegion EnvC5/Envelope C5: "<</PageSize[459 649]/ImagingBBox null>>setpagedevice"
+*PageRegion EnvDL/Envelope DL: "<</PageSize[312 624]/ImagingBBox null>>setpagedevice"
+*PageRegion EnvMonarch/Envelope Monarch: "<</PageSize[279 540]/ImagingBBox null>>setpagedevice"
+*CloseUI: *PageRegion
+
+*DefaultImageableArea: Letter
+*ImageableArea Letter/US Letter: "18 36 594 756"
+*ImageableArea Legal/US Legal: "18 36 594 972"
+*ImageableArea Executive/US Executive: "18 36 504 684"
+*ImageableArea Tabloid/US Tabloid: "18 36 774 1188"
+*ImageableArea A3/A3: "18 36 824 1155"
+*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/US Letter: "612 792"
+*PaperDimension Legal/US Legal: "612 1008"
+*PaperDimension Executive/US Executive: "522 756"
+*PaperDimension Tabloid/US Tabloid: "792 1224"
+*PaperDimension A3/A3: "842 1191"
+*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: "<</MediaType(Plain)/cupsMediaType 0>>setpagedevice"
+*MediaType Bond/Bond Paper: "<</MediaType(Bond)/cupsMediaType 1>>setpagedevice"
+*MediaType Special/Special Paper: "<</MediaType(Special)/cupsMediaType 2>>setpagedevice"
+*MediaType Transparency/Transparency: "<</MediaType(Transparency)/cupsMediaType 3>>setpagedevice"
+*MediaType Glossy/Glossy Paper: "<</MediaType(Glossy)/cupsMediaType 4>>setpagedevice"
+*CloseUI: *MediaType
+
+*OpenUI *InputSlot/Media Source: PickOne
+*OrderDependency: 10 AnySetup *InputSlot
+*DefaultInputSlot: Tray
+*InputSlot Tray/Tray: "<</cupsMediaPosition 1>>setpagedevice"
+*InputSlot Manual/Manual Feed: "<</cupsMediaPosition 2>>setpagedevice"
+*InputSlot Envelope/Envelope Feed: "<</cupsMediaPosition 3>>setpagedevice"
+*CloseUI: *InputSlot
+
+*OpenUI *Resolution/Output Resolution: PickOne
+*OrderDependency: 20 AnySetup *Resolution
+*DefaultResolution: 100dpi
+*Resolution 75dpi/75 DPI: "<</HWResolution[75 75]>>setpagedevice"
+*Resolution 100dpi/100 DPI: "<</HWResolution[100 100]>>setpagedevice"
+*CloseUI: *Resolution
+
+*OpenUI *ColorModel/Output Mode: PickOne
+*OrderDependency: 10 AnySetup *ColorModel
+*DefaultColorModel: CMYK
+*ColorModel CMYK/CMYK Color: "<</cupsColorOrder 1/cupsColorSpace 8/cupsCompression 2>>setpagedevice"
+*ColorModel RGB/CMY Color: "<</cupsColorOrder 1/cupsColorSpace 4/cupsCompression 2>>setpagedevice"
+*ColorModel Gray/Grayscale: "<</cupsColorOrder 0/cupsColorSpace 3/cupsCompression 2>>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/test/testps.ppd b/test/testps.ppd
new file mode 100644
index 000000000..63d42adf5
--- /dev/null
+++ b/test/testps.ppd
@@ -0,0 +1,192 @@
+*PPD-Adobe: "4.3"
+*%
+*% "$Id$"
+*%
+*% Test PS PPD file for the Common UNIX Printing System (CUPS).
+*%
+*% Copyright 1997-2002 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: "TESTPS.PPD"
+*Manufacturer: "ESP"
+*Product: "(CUPS v1.1)"
+*ModelName: "Test PS Printer"
+*ShortNickName: "Test PS Printer"
+*NickName: "Test PS Printer CUPS v1.1"
+*PSVersion: "(3010.000) 550"
+*LanguageLevel: "3"
+*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 Tabloid *InputSlot Envelope
+*UIConstraints: *PageSize A3 *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/US Letter: "<</PageSize[612 792]/ImagingBBox null>>setpagedevice"
+*PageSize Legal/US Legal: "<</PageSize[612 1008]/ImagingBBox null>>setpagedevice"
+*PageSize Executive/US Executive: "<</PageSize[522 756]/ImagingBBox null>>setpagedevice"
+*PageSize Tabloid/US Tabloid: "<</PageSize[792 1224]/ImagingBBox null>>setpagedevice"
+*PageSize A3/A3: "<</PageSize[842 1191]/ImagingBBox null>>setpagedevice"
+*PageSize A4/A4: "<</PageSize[595 842]/ImagingBBox null>>setpagedevice"
+*PageSize A5/A5: "<</PageSize[421 595]/ImagingBBox null>>setpagedevice"
+*PageSize B5/B5 (JIS): "<</PageSize[516 729]/ImagingBBox null>>setpagedevice"
+*PageSize EnvISOB5/Envelope B5: "<</PageSize[499 709]/ImagingBBox null>>setpagedevice"
+*PageSize Env10/Envelope #10: "<</PageSize[297 684]/ImagingBBox null>>setpagedevice"
+*PageSize EnvC5/Envelope C5: "<</PageSize[459 649]/ImagingBBox null>>setpagedevice"
+*PageSize EnvDL/Envelope DL: "<</PageSize[312 624]/ImagingBBox null>>setpagedevice"
+*PageSize EnvMonarch/Envelope Monarch: "<</PageSize[279 540]/ImagingBBox null>>setpagedevice"
+*CloseUI: *PageSize
+
+*OpenUI *PageRegion: PickOne
+*OrderDependency: 10 AnySetup *PageRegion
+*DefaultPageRegion: Letter
+*PageRegion Letter/US Letter: "<</PageSize[612 792]/ImagingBBox null>>setpagedevice"
+*PageRegion Legal/US Legal: "<</PageSize[612 1008]/ImagingBBox null>>setpagedevice"
+*PageRegion Executive/US Executive: "<</PageSize[522 756]/ImagingBBox null>>setpagedevice"
+*PageRegion Tabloid/US Tabloid: "<</PageSize[792 1224]/ImagingBBox null>>setpagedevice"
+*PageRegion A3/A3: "<</PageSize[842 1191]/ImagingBBox null>>setpagedevice"
+*PageRegion A4/A4: "<</PageSize[595 842]/ImagingBBox null>>setpagedevice"
+*PageRegion A5/A5: "<</PageSize[421 595]/ImagingBBox null>>setpagedevice"
+*PageRegion B5/B5 (JIS): "<</PageSize[516 729]/ImagingBBox null>>setpagedevice"
+*PageRegion EnvISOB5/Envelope B5: "<</PageSize[499 709]/ImagingBBox null>>setpagedevice"
+*PageRegion Env10/Envelope #10: "<</PageSize[297 684]/ImagingBBox null>>setpagedevice"
+*PageRegion EnvC5/Envelope C5: "<</PageSize[459 649]/ImagingBBox null>>setpagedevice"
+*PageRegion EnvDL/Envelope DL: "<</PageSize[312 624]/ImagingBBox null>>setpagedevice"
+*PageRegion EnvMonarch/Envelope Monarch: "<</PageSize[279 540]/ImagingBBox null>>setpagedevice"
+*CloseUI: *PageRegion
+
+*DefaultImageableArea: Letter
+*ImageableArea Letter/US Letter: "18 36 594 756"
+*ImageableArea Legal/US Legal: "18 36 594 972"
+*ImageableArea Executive/US Executive: "18 36 504 684"
+*ImageableArea Tabloid/US Tabloid: "18 36 774 1188"
+*ImageableArea A3/A3: "18 36 824 1155"
+*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/US Letter: "612 792"
+*PaperDimension Legal/US Legal: "612 1008"
+*PaperDimension Executive/US Executive: "522 756"
+*PaperDimension Tabloid/US Tabloid: "792 1224"
+*PaperDimension A3/A3: "842 1191"
+*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: "<</MediaType(Plain)/cupsMediaType 0>>setpagedevice"
+*MediaType Bond/Bond Paper: "<</MediaType(Bond)/cupsMediaType 1>>setpagedevice"
+*MediaType Special/Special Paper: "<</MediaType(Special)/cupsMediaType 2>>setpagedevice"
+*MediaType Transparency/Transparency: "<</MediaType(Transparency)/cupsMediaType 3>>setpagedevice"
+*MediaType Glossy/Glossy Paper: "<</MediaType(Glossy)/cupsMediaType 4>>setpagedevice"
+*CloseUI: *MediaType
+
+*OpenUI *InputSlot/Media Source: PickOne
+*OrderDependency: 10 AnySetup *InputSlot
+*DefaultInputSlot: Tray
+*InputSlot Tray/Tray: "<</cupsMediaPosition 1>>setpagedevice"
+*InputSlot Manual/Manual Feed: "<</cupsMediaPosition 2>>setpagedevice"
+*InputSlot Envelope/Envelope Feed: "<</cupsMediaPosition 3>>setpagedevice"
+*CloseUI: *InputSlot
+
+*OpenUI *Resolution/Output Resolution: PickOne
+*OrderDependency: 20 AnySetup *Resolution
+*DefaultResolution: 100dpi
+*Resolution 75dpi/75 DPI: "<</HWResolution[75 75]>>setpagedevice"
+*Resolution 100dpi/100 DPI: "<</HWResolution[100 100]>>setpagedevice"
+*CloseUI: *Resolution
+
+*OpenUI *ColorModel/Output Mode: PickOne
+*OrderDependency: 10 AnySetup *ColorModel
+*DefaultColorModel: CMYK
+*ColorModel CMYK/CMYK Color: "<</cupsColorOrder 1/cupsColorSpace 8/cupsCompression 2>>setpagedevice"
+*ColorModel RGB/CMY Color: "<</cupsColorOrder 1/cupsColorSpace 4/cupsCompression 2>>setpagedevice"
+*ColorModel Gray/Grayscale: "<</cupsColorOrder 0/cupsColorSpace 3/cupsCompression 2>>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/visualc/config.h b/visualc/config.h
new file mode 100644
index 000000000..81f53b490
--- /dev/null
+++ b/visualc/config.h
@@ -0,0 +1,147 @@
+/*
+ * "$Id$"
+ *
+ * Configuration file for the Common UNIX Printing System (CUPS).
+ *
+ * @configure_input@
+ *
+ * Copyright 1997-2002 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.1.9"
+
+/*
+ * Where are files stored?
+ */
+
+#define CUPS_LOCALEDIR "C:/CUPS/locale"
+#define CUPS_SERVERROOT "C:/CUPS/etc"
+#define CUPS_SERVERBIN "C:/CUPS"
+#define CUPS_DOCROOT "C:/CUPS/share/doc"
+#define CUPS_REQUESTS "C:/CUPS/spool"
+#define CUPS_LOGDIR "C:/CUPS/logs"
+#define CUPS_DATADIR "C:/CUPS/share"
+#define CUPS_FONTPATH "C:/CUPS/share/fonts"
+
+/*
+ * What is the format string for strftime?
+ */
+
+#define CUPS_STRFTIME_FORMAT "%c"
+
+/*
+ * 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 <shadow.h>?
+ */
+
+#undef HAVE_SHADOW_H
+
+/*
+ * Do we have <crypt.h>?
+ */
+
+#undef HAVE_CRYPT_H
+
+/*
+ * Do we have the strXXX() functions?
+ */
+
+#define HAVE_STRDUP
+#define HAVE_STRCASECMP
+#define 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
+
+/*
+ * Do we have the mallinfo function and malloc.h?
+ */
+
+#undef HAVE_MALLINFO
+#undef HAVE_MALLOC_H
+
+/*
+ * Do we have the OpenSSL library?
+ */
+
+#undef HAVE_LIBSSL
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/visualc/jpeg.dsp b/visualc/jpeg.dsp
new file mode 100644
index 000000000..f4816d978
--- /dev/null
+++ b/visualc/jpeg.dsp
@@ -0,0 +1,284 @@
+# Microsoft Developer Studio Project File - Name="jpeg" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=jpeg - 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 "jpeg.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 "jpeg.mak" CFG="jpeg - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "jpeg - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "jpeg - 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)" == "jpeg - 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 "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /Ot /Op /Ob2 /I "../visualc" /I "../zlib" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "WIN32_LEAN_AND_MEAN" /D "VC_EXTRA_LEAN" /D "WIN32_EXTRA_LEAN" /YX /FD /c
+# SUBTRACT CPP /Os
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"jpeg.lib"
+
+!ELSEIF "$(CFG)" == "jpeg - 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 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /MTd /GX /Zi /Od /I "../visualc" /I "../zlib" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "WIN32_LEAN_AND_MEAN" /D "VC_EXTRA_LEAN" /D "WIN32_EXTRA_LEAN" /YX /FD /c
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"jpegd.lib"
+
+!ENDIF
+
+# Begin Target
+
+# Name "jpeg - Win32 Release"
+# Name "jpeg - Win32 Debug"
+# Begin Source File
+
+SOURCE=..\jpeg\jcapimin.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jcapistd.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jccoefct.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jccolor.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jcdctmgr.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jchuff.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jcinit.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jcmainct.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jcmarker.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jcmaster.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jcomapi.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jcparam.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jcphuff.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jcprepct.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jcsample.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jctrans.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jdapimin.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jdapistd.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jdatadst.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jdatasrc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jdcoefct.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jdcolor.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jddctmgr.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jdhuff.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jdinput.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jdmainct.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jdmarker.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jdmaster.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jdmerge.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jdphuff.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jdpostct.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jdsample.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jdtrans.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jerror.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jfdctflt.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jfdctfst.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jfdctint.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jidctflt.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jidctfst.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jidctint.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jidctred.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jmemmgr.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jmemnobs.c
+
+!IF "$(CFG)" == "jpeg - Win32 Release"
+
+# ADD CPP /MT
+
+!ELSEIF "$(CFG)" == "jpeg - Win32 Debug"
+
+# ADD CPP /MTd
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jpegtran.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jquant1.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jquant2.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\jpeg\jutils.c
+# End Source File
+# End Target
+# End Project
diff --git a/visualc/libpng.dsp b/visualc/libpng.dsp
new file mode 100644
index 000000000..e83faba7a
--- /dev/null
+++ b/visualc/libpng.dsp
@@ -0,0 +1,149 @@
+# Microsoft Developer Studio Project File - Name="libpng" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=libpng - 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 "libpng.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 "libpng.mak" CFG="libpng - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "libpng - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "libpng - 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)" == "libpng - 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 "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /Ot /Op /Ob2 /I "..\zlib-1.1.3" /I "../visualc" /I "../zlib" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "WIN32_LEAN_AND_MEAN" /D "VC_EXTRA_LEAN" /D "WIN32_EXTRA_LEAN" /YX /FD /c
+# SUBTRACT CPP /Os
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"png.lib"
+
+!ELSEIF "$(CFG)" == "libpng - 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 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /MTd /GX /Zi /Od /I "..\zlib-1.1.3" /I "../visualc" /I "../zlib" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "WIN32_LEAN_AND_MEAN" /D "VC_EXTRA_LEAN" /D "WIN32_EXTRA_LEAN" /YX /FD /c
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"pngd.lib"
+
+!ENDIF
+
+# Begin Target
+
+# Name "libpng - Win32 Release"
+# Name "libpng - Win32 Debug"
+# Begin Source File
+
+SOURCE=..\png\png.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\png\pngerror.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\png\pngget.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\png\pngmem.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\png\pngpread.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\png\pngread.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\png\pngrio.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\png\pngrtran.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\png\pngrutil.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\png\pngset.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\png\pngtest.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\png\pngtrans.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\png\pngwio.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\png\pngwrite.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\png\pngwtran.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\png\pngwutil.c
+# End Source File
+# End Target
+# End Project
diff --git a/visualc/zlib.dsp b/visualc/zlib.dsp
new file mode 100644
index 000000000..016b5b769
--- /dev/null
+++ b/visualc/zlib.dsp
@@ -0,0 +1,141 @@
+# Microsoft Developer Studio Project File - Name="zlib" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=zlib - 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 "zlib.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 "zlib.mak" CFG="zlib - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "zlib - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "zlib - 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)" == "zlib - 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 "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /MT /GX /Ot /Op /Ob2 /I "../visualc" /I "../zlib" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "WIN32_LEAN_AND_MEAN" /D "VC_EXTRA_LEAN" /D "WIN32_EXTRA_LEAN" /YX /FD /c
+# SUBTRACT CPP /Os
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"z.lib"
+
+!ELSEIF "$(CFG)" == "zlib - 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 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /MTd /GX /Zi /Od /I "../visualc" /I "../zlib" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "WIN32_LEAN_AND_MEAN" /D "VC_EXTRA_LEAN" /D "WIN32_EXTRA_LEAN" /YX /FD /c
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"zd.lib"
+
+!ENDIF
+
+# Begin Target
+
+# Name "zlib - Win32 Release"
+# Name "zlib - Win32 Debug"
+# Begin Source File
+
+SOURCE=..\zlib\adler32.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\zlib\compress.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\zlib\crc32.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\zlib\deflate.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\zlib\gzio.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\zlib\infblock.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\zlib\infcodes.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\zlib\inffast.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\zlib\inflate.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\zlib\inftrees.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\zlib\infutil.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\zlib\trees.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\zlib\uncompr.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\zlib\zutil.c
+# End Source File
+# End Target
+# End Project